Merge remote-tracking branch 'asoc/topic/rt5651' into asoc-next
authorMark Brown <broonie@kernel.org>
Mon, 11 Jan 2016 13:54:39 +0000 (13:54 +0000)
committerMark Brown <broonie@kernel.org>
Mon, 11 Jan 2016 13:54:39 +0000 (13:54 +0000)
1610 files changed:
Documentation/IPMI.txt
Documentation/arm/keystone/Overview.txt
Documentation/block/null_blk.txt
Documentation/devicetree/bindings/dma/ti-edma.txt
Documentation/devicetree/bindings/gpio/gpio-mpc8xxx.txt
Documentation/devicetree/bindings/input/sun4i-lradc-keys.txt
Documentation/devicetree/bindings/mtd/partition.txt
Documentation/devicetree/bindings/net/cpsw.txt
Documentation/devicetree/bindings/net/marvell-armada-370-neta.txt
Documentation/devicetree/bindings/sound/ak4613.txt
Documentation/devicetree/bindings/sound/atmel-classd.txt
Documentation/devicetree/bindings/sound/atmel-pdmic.txt [new file with mode: 0644]
Documentation/devicetree/bindings/sound/da7218.txt [new file with mode: 0644]
Documentation/devicetree/bindings/sound/da7219.txt
Documentation/devicetree/bindings/sound/fsl,asrc.txt
Documentation/devicetree/bindings/sound/fsl,esai.txt
Documentation/devicetree/bindings/sound/fsl,spdif.txt
Documentation/devicetree/bindings/sound/img,i2s-in.txt [new file with mode: 0644]
Documentation/devicetree/bindings/sound/img,i2s-out.txt [new file with mode: 0644]
Documentation/devicetree/bindings/sound/img,parallel-out.txt [new file with mode: 0644]
Documentation/devicetree/bindings/sound/img,pistachio-internal-dac.txt [new file with mode: 0644]
Documentation/devicetree/bindings/sound/img,spdif-in.txt [new file with mode: 0644]
Documentation/devicetree/bindings/sound/img,spdif-out.txt [new file with mode: 0644]
Documentation/devicetree/bindings/sound/inno-rk3036.txt [new file with mode: 0644]
Documentation/devicetree/bindings/sound/pcm179x.txt [moved from Documentation/devicetree/bindings/sound/pcm1792a.txt with 88% similarity]
Documentation/devicetree/bindings/sound/renesas,rsnd.txt
Documentation/devicetree/bindings/sound/renesas,rsrc-card.txt
Documentation/devicetree/bindings/sound/rockchip-i2s.txt
Documentation/devicetree/bindings/sound/rt5616.txt [new file with mode: 0644]
Documentation/devicetree/bindings/sound/rt5659.txt [new file with mode: 0644]
Documentation/devicetree/bindings/sound/rt5677.txt
Documentation/devicetree/bindings/sound/sun4i-codec.txt
Documentation/devicetree/bindings/sound/ti,pcm3168a.txt [new file with mode: 0644]
Documentation/devicetree/bindings/sound/wlf,wm8974.txt [new file with mode: 0644]
Documentation/devicetree/bindings/thermal/rockchip-thermal.txt
Documentation/i2c/busses/i2c-i801
Documentation/kernel-parameters.txt
Documentation/networking/e100.txt
Documentation/sound/alsa/img,spdif-in.txt [new file with mode: 0644]
MAINTAINERS
Makefile
arch/arc/Kconfig
arch/arc/Makefile
arch/arc/boot/dts/axs10x_mb.dtsi
arch/arc/boot/dts/nsim_hs.dts
arch/arc/configs/axs101_defconfig
arch/arc/configs/axs103_defconfig
arch/arc/configs/axs103_smp_defconfig
arch/arc/configs/nsim_hs_defconfig
arch/arc/configs/nsim_hs_smp_defconfig
arch/arc/configs/nsimosci_hs_defconfig
arch/arc/configs/nsimosci_hs_smp_defconfig
arch/arc/configs/vdk_hs38_defconfig
arch/arc/configs/vdk_hs38_smp_defconfig
arch/arc/include/asm/cache.h
arch/arc/include/asm/irqflags-arcv2.h
arch/arc/include/asm/irqflags-compact.h
arch/arc/include/asm/mach_desc.h
arch/arc/include/asm/smp.h
arch/arc/include/asm/unwind.h
arch/arc/kernel/ctx_sw.c
arch/arc/kernel/ctx_sw_asm.S
arch/arc/kernel/intc-arcv2.c
arch/arc/kernel/irq.c
arch/arc/kernel/mcip.c
arch/arc/kernel/perf_event.c
arch/arc/kernel/process.c
arch/arc/kernel/setup.c
arch/arc/kernel/smp.c
arch/arc/kernel/unwind.c
arch/arc/mm/highmem.c
arch/arc/mm/init.c
arch/arc/mm/tlb.c
arch/arm/Kconfig
arch/arm/boot/dts/am4372.dtsi
arch/arm/boot/dts/am43xx-clocks.dtsi
arch/arm/boot/dts/am57xx-beagle-x15.dts
arch/arm/boot/dts/animeo_ip.dts
arch/arm/boot/dts/armada-38x.dtsi
arch/arm/boot/dts/at91-foxg20.dts
arch/arm/boot/dts/at91-kizbox.dts
arch/arm/boot/dts/at91-kizbox2.dts
arch/arm/boot/dts/at91-kizboxmini.dts
arch/arm/boot/dts/at91-qil_a9260.dts
arch/arm/boot/dts/at91-sama5d2_xplained.dts
arch/arm/boot/dts/at91-sama5d3_xplained.dts
arch/arm/boot/dts/at91-sama5d4_xplained.dts
arch/arm/boot/dts/at91-sama5d4ek.dts
arch/arm/boot/dts/at91rm9200ek.dts
arch/arm/boot/dts/at91sam9261ek.dts
arch/arm/boot/dts/at91sam9263ek.dts
arch/arm/boot/dts/at91sam9g20ek_common.dtsi
arch/arm/boot/dts/at91sam9m10g45ek.dts
arch/arm/boot/dts/at91sam9n12ek.dts
arch/arm/boot/dts/at91sam9rlek.dts
arch/arm/boot/dts/at91sam9x5cm.dtsi
arch/arm/boot/dts/berlin2q.dtsi
arch/arm/boot/dts/dm816x.dtsi
arch/arm/boot/dts/dra7.dtsi
arch/arm/boot/dts/imx27.dtsi
arch/arm/boot/dts/imx6q-gw5400-a.dts
arch/arm/boot/dts/imx6qdl-gw51xx.dtsi
arch/arm/boot/dts/imx6qdl-gw52xx.dtsi
arch/arm/boot/dts/imx6qdl-gw53xx.dtsi
arch/arm/boot/dts/imx6qdl-gw54xx.dtsi
arch/arm/boot/dts/imx6qdl-sabreauto.dtsi
arch/arm/boot/dts/k2l-netcp.dtsi
arch/arm/boot/dts/kirkwood-ts219.dtsi
arch/arm/boot/dts/omap4-duovero-parlor.dts
arch/arm/boot/dts/rk3288-veyron-minnie.dts
arch/arm/boot/dts/rk3288.dtsi
arch/arm/boot/dts/sama5d35ek.dts
arch/arm/boot/dts/sama5d4.dtsi
arch/arm/boot/dts/sun6i-a31s-primo81.dts
arch/arm/boot/dts/tegra124-nyan.dtsi
arch/arm/boot/dts/usb_a9260_common.dtsi
arch/arm/boot/dts/usb_a9263.dts
arch/arm/boot/dts/vf610-colibri.dtsi
arch/arm/boot/dts/vf610.dtsi
arch/arm/boot/dts/vfxxx.dtsi
arch/arm/configs/at91_dt_defconfig
arch/arm/configs/sama5_defconfig
arch/arm/include/asm/arch_gicv3.h
arch/arm/include/asm/irq.h
arch/arm/include/asm/kvm_emulate.h
arch/arm/include/asm/uaccess.h
arch/arm/include/uapi/asm/unistd.h
arch/arm/kernel/bios32.c
arch/arm/kernel/calls.S
arch/arm/kernel/process.c
arch/arm/kernel/swp_emulate.c
arch/arm/kernel/sys_oabi-compat.c
arch/arm/kvm/arm.c
arch/arm/kvm/mmio.c
arch/arm/kvm/mmu.c
arch/arm/kvm/psci.c
arch/arm/lib/uaccess_with_memcpy.c
arch/arm/mach-at91/Kconfig
arch/arm/mach-at91/pm.c
arch/arm/mach-dove/include/mach/entry-macro.S
arch/arm/mach-exynos/pmu.c
arch/arm/mach-imx/gpc.c
arch/arm/mach-ixp4xx/include/mach/io.h
arch/arm/mach-omap2/Kconfig
arch/arm/mach-omap2/omap-smp.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/omap_hwmod_81xx_data.c
arch/arm/mach-omap2/pdata-quirks.c
arch/arm/mach-omap2/pm34xx.c
arch/arm/mach-omap2/timer.c
arch/arm/mach-orion5x/include/mach/entry-macro.S
arch/arm/mach-pxa/ezx.c
arch/arm/mach-pxa/palm27x.c
arch/arm/mach-pxa/palmtc.c
arch/arm/mach-s3c24xx/pll-s3c2440-12000000.c
arch/arm/mach-s3c24xx/pll-s3c2440-16934400.c
arch/arm/mach-s3c64xx/dev-audio.c
arch/arm/mach-s3c64xx/include/mach/dma.h
arch/arm/mach-shmobile/setup-r8a7793.c
arch/arm/mach-zx/Kconfig
arch/arm/mm/context.c
arch/arm/mm/dma-mapping.c
arch/arm/mm/init.c
arch/arm/mm/proc-v7.S
arch/arm/net/bpf_jit_32.c
arch/arm/plat-samsung/devs.c
arch/arm64/Kconfig
arch/arm64/boot/dts/freescale/fsl-ls2080a.dtsi
arch/arm64/crypto/aes-ce-cipher.c
arch/arm64/include/asm/arch_gicv3.h
arch/arm64/include/asm/barrier.h
arch/arm64/include/asm/compat.h
arch/arm64/include/asm/cpufeature.h
arch/arm64/include/asm/dma-mapping.h
arch/arm64/include/asm/hw_breakpoint.h
arch/arm64/include/asm/irq.h
arch/arm64/include/asm/kvm_emulate.h
arch/arm64/include/asm/mmu_context.h
arch/arm64/include/asm/pgtable.h
arch/arm64/kernel/cpu_errata.c
arch/arm64/kernel/cpufeature.c
arch/arm64/kernel/cpuinfo.c
arch/arm64/kernel/efi.c
arch/arm64/kernel/suspend.c
arch/arm64/kernel/vmlinux.lds.S
arch/arm64/kvm/handle_exit.c
arch/arm64/kvm/hyp.S
arch/arm64/kvm/inject_fault.c
arch/arm64/kvm/sys_regs.c
arch/arm64/kvm/sys_regs.h
arch/arm64/kvm/sys_regs_generic_v8.c
arch/arm64/mm/context.c
arch/arm64/mm/dma-mapping.c
arch/arm64/mm/fault.c
arch/arm64/mm/mmu.c
arch/arm64/net/bpf_jit_comp.c
arch/blackfin/kernel/perf_event.c
arch/ia64/include/asm/unistd.h
arch/ia64/include/uapi/asm/unistd.h
arch/ia64/kernel/entry.S
arch/m32r/include/asm/Kbuild
arch/m32r/include/asm/io.h
arch/m68k/coldfire/m54xx.c
arch/m68k/include/asm/unistd.h
arch/m68k/include/uapi/asm/unistd.h
arch/m68k/kernel/setup_no.c
arch/m68k/kernel/syscalltable.S
arch/m68k/mm/motorola.c
arch/m68k/sun3/config.c
arch/microblaze/kernel/dma.c
arch/mips/ath79/setup.c
arch/mips/boot/dts/qca/ar9132.dtsi
arch/mips/include/asm/page.h
arch/mips/include/asm/uaccess.h
arch/mips/kernel/cps-vec.S
arch/mips/kernel/mips_ksyms.c
arch/mips/kvm/emulate.c
arch/mips/kvm/locore.S
arch/mips/kvm/mips.c
arch/mips/lib/memset.S
arch/mips/mm/dma-default.c
arch/mips/pci/pci-rt2880.c
arch/mips/pmcs-msp71xx/msp_setup.c
arch/mips/sni/reset.c
arch/mips/vdso/Makefile
arch/mn10300/Kconfig
arch/nios2/mm/cacheflush.c
arch/parisc/Kconfig
arch/parisc/include/asm/hugetlb.h [new file with mode: 0644]
arch/parisc/include/asm/page.h
arch/parisc/include/asm/pgalloc.h
arch/parisc/include/asm/pgtable.h
arch/parisc/include/asm/processor.h
arch/parisc/include/uapi/asm/mman.h
arch/parisc/include/uapi/asm/unistd.h
arch/parisc/kernel/asm-offsets.c
arch/parisc/kernel/entry.S
arch/parisc/kernel/head.S
arch/parisc/kernel/pci.c
arch/parisc/kernel/setup.c
arch/parisc/kernel/signal.c
arch/parisc/kernel/syscall.S
arch/parisc/kernel/syscall_table.S
arch/parisc/kernel/traps.c
arch/parisc/kernel/vmlinux.lds.S
arch/parisc/mm/Makefile
arch/parisc/mm/hugetlbpage.c [new file with mode: 0644]
arch/parisc/mm/init.c
arch/powerpc/boot/dts/sbc8641d.dts
arch/powerpc/include/asm/reg.h
arch/powerpc/include/asm/systbl.h
arch/powerpc/include/asm/unistd.h
arch/powerpc/include/uapi/asm/unistd.h
arch/powerpc/kernel/eeh_driver.c
arch/powerpc/kernel/process.c
arch/powerpc/kernel/signal_32.c
arch/powerpc/kernel/signal_64.c
arch/powerpc/kvm/book3s_hv.c
arch/powerpc/platforms/powernv/opal-irqchip.c
arch/powerpc/platforms/powernv/opal.c
arch/s390/include/asm/cio.h
arch/s390/include/asm/elf.h
arch/s390/include/asm/ipl.h
arch/s390/include/asm/pci_dma.h
arch/s390/include/asm/trace/diag.h
arch/s390/include/uapi/asm/unistd.h
arch/s390/kernel/compat_wrapper.c
arch/s390/kernel/diag.c
arch/s390/kernel/dis.c
arch/s390/kernel/head.S
arch/s390/kernel/ipl.c
arch/s390/kernel/process.c
arch/s390/kernel/sclp.c
arch/s390/kernel/setup.c
arch/s390/kernel/syscalls.S
arch/s390/kernel/trace.c
arch/s390/kvm/interrupt.c
arch/s390/kvm/kvm-s390.c
arch/s390/kvm/priv.c
arch/s390/kvm/sigp.c
arch/s390/mm/init.c
arch/s390/mm/mmap.c
arch/s390/pci/pci_dma.c
arch/sh/include/uapi/asm/unistd_64.h
arch/sh/kernel/perf_event.c
arch/sparc/include/asm/elf_64.h
arch/sparc/include/uapi/asm/unistd.h
arch/sparc/kernel/head_64.S
arch/sparc/kernel/perf_event.c
arch/sparc/kernel/rtrap_64.S
arch/sparc/kernel/setup_64.c
arch/sparc/kernel/systbls_32.S
arch/sparc/kernel/systbls_64.S
arch/sparc/lib/NG2copy_from_user.S
arch/sparc/lib/NG2copy_to_user.S
arch/sparc/lib/NG2memcpy.S
arch/sparc/lib/NG4copy_from_user.S
arch/sparc/lib/NG4copy_to_user.S
arch/sparc/lib/NG4memcpy.S
arch/sparc/lib/U1copy_from_user.S
arch/sparc/lib/U1copy_to_user.S
arch/sparc/lib/U1memcpy.S
arch/sparc/lib/U3copy_from_user.S
arch/sparc/lib/U3copy_to_user.S
arch/sparc/lib/U3memcpy.S
arch/tile/kernel/perf_event.c
arch/um/Makefile
arch/um/drivers/net_user.c
arch/um/kernel/signal.c
arch/x86/boot/boot.h
arch/x86/boot/video-mode.c
arch/x86/boot/video.c
arch/x86/entry/entry_64.S
arch/x86/include/asm/msr-index.h
arch/x86/include/asm/page_types.h
arch/x86/include/asm/pgtable_types.h
arch/x86/include/asm/platform_sst_audio.h
arch/x86/include/asm/x86_init.h
arch/x86/kernel/cpu/common.c
arch/x86/kernel/cpu/microcode/core.c
arch/x86/kernel/cpu/perf_event.c
arch/x86/kernel/cpu/perf_event.h
arch/x86/kernel/cpu/perf_event_intel.c
arch/x86/kernel/cpu/perf_event_intel_cqm.c
arch/x86/kernel/cpu/perf_event_intel_lbr.c
arch/x86/kernel/fpu/signal.c
arch/x86/kernel/fpu/xstate.c
arch/x86/kernel/irq_work.c
arch/x86/kernel/mcount_64.S
arch/x86/kernel/pmem.c
arch/x86/kernel/setup.c
arch/x86/kernel/signal.c
arch/x86/kernel/smpboot.c
arch/x86/kvm/cpuid.h
arch/x86/kvm/mtrr.c
arch/x86/kvm/svm.c
arch/x86/kvm/vmx.c
arch/x86/kvm/x86.c
arch/x86/mm/dump_pagetables.c
arch/x86/mm/mpx.c
arch/x86/pci/bus_numa.c
arch/x86/um/signal.c
arch/x86/xen/mmu.c
arch/x86/xen/suspend.c
block/blk-cgroup.c
block/blk-core.c
block/blk-merge.c
block/blk-mq.c
block/blk-settings.c
block/blk-sysfs.c
block/blk-timeout.c
block/blk.h
block/noop-iosched.c
block/partition-generic.c
block/partitions/mac.c
crypto/ablkcipher.c
crypto/algif_aead.c
crypto/algif_skcipher.c
crypto/blkcipher.c
drivers/Makefile
drivers/acpi/Kconfig
drivers/acpi/cppc_acpi.c
drivers/acpi/ec.c
drivers/acpi/nfit.c
drivers/acpi/nfit.h
drivers/acpi/pci_root.c
drivers/acpi/processor_driver.c
drivers/acpi/sbshc.c
drivers/ata/ahci.c
drivers/ata/ahci_mvebu.c
drivers/ata/libahci.c
drivers/ata/libata-eh.c
drivers/ata/sata_fsl.c
drivers/ata/sata_sil.c
drivers/base/memory.c
drivers/base/power/domain.c
drivers/base/power/domain_governor.c
drivers/base/power/wakeirq.c
drivers/block/mtip32xx/mtip32xx.c
drivers/block/null_blk.c
drivers/block/rbd.c
drivers/block/xen-blkback/blkback.c
drivers/block/xen-blkback/common.h
drivers/bus/omap-ocp2scp.c
drivers/bus/sunxi-rsb.c
drivers/char/ipmi/ipmi_si_intf.c
drivers/char/ipmi/ipmi_watchdog.c
drivers/clk/clk-gpio.c
drivers/clk/clk-qoriq.c
drivers/clk/clk-scpi.c
drivers/clk/imx/clk-pllv1.c
drivers/clk/imx/clk-pllv2.c
drivers/clk/imx/clk-vf610.c
drivers/clk/mmp/clk-mmp2.c
drivers/clk/mmp/clk-pxa168.c
drivers/clk/mmp/clk-pxa910.c
drivers/clk/sunxi/clk-a10-pll2.c
drivers/clk/ti/clk-816x.c
drivers/clk/ti/clkt_dpll.c
drivers/clk/ti/divider.c
drivers/clk/ti/fapll.c
drivers/clk/ti/mux.c
drivers/clocksource/Kconfig
drivers/clocksource/fsl_ftm_timer.c
drivers/clocksource/mmio.c
drivers/cpufreq/Kconfig.arm
drivers/cpufreq/Kconfig.x86
drivers/cpufreq/cppc_cpufreq.c
drivers/cpufreq/cpufreq.c
drivers/cpufreq/intel_pstate.c
drivers/cpufreq/s3c24xx-cpufreq.c
drivers/cpufreq/scpi-cpufreq.c
drivers/crypto/nx/nx-aes-ccm.c
drivers/crypto/nx/nx-aes-gcm.c
drivers/crypto/qat/qat_common/adf_ctl_drv.c
drivers/crypto/talitos.c
drivers/dma/Kconfig
drivers/dma/at_hdmac.c
drivers/dma/at_hdmac_regs.h
drivers/dma/at_xdmac.c
drivers/dma/bcm2835-dma.c
drivers/dma/edma.c
drivers/dma/imx-sdma.c
drivers/dma/mic_x100_dma.c
drivers/dma/sh/usb-dmac.c
drivers/fpga/fpga-mgr.c
drivers/gpio/gpio-74xx-mmio.c
drivers/gpio/gpio-ath79.c
drivers/gpio/gpio-generic.c
drivers/gpio/gpio-omap.c
drivers/gpio/gpio-palmas.c
drivers/gpio/gpio-syscon.c
drivers/gpio/gpio-tegra.c
drivers/gpio/gpiolib.c
drivers/gpu/drm/amd/amdgpu/amdgpu.h
drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c
drivers/gpu/drm/amd/amdgpu/amdgpu_display.c
drivers/gpu/drm/amd/amdgpu/amdgpu_fence.c
drivers/gpu/drm/amd/amdgpu/amdgpu_gem.c
drivers/gpu/drm/amd/amdgpu/amdgpu_ib.c
drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c
drivers/gpu/drm/amd/amdgpu/amdgpu_mode.h
drivers/gpu/drm/amd/amdgpu/amdgpu_object.c
drivers/gpu/drm/amd/amdgpu/amdgpu_object.h
drivers/gpu/drm/amd/amdgpu/amdgpu_sa.c
drivers/gpu/drm/amd/amdgpu/amdgpu_sched.c
drivers/gpu/drm/amd/amdgpu/amdgpu_semaphore.c
drivers/gpu/drm/amd/amdgpu/amdgpu_sync.c
drivers/gpu/drm/amd/amdgpu/amdgpu_trace.h
drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c
drivers/gpu/drm/amd/amdgpu/amdgpu_vce.c
drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c
drivers/gpu/drm/amd/amdgpu/ci_dpm.c
drivers/gpu/drm/amd/amdgpu/dce_v10_0.c
drivers/gpu/drm/amd/amdgpu/dce_v11_0.c
drivers/gpu/drm/amd/amdgpu/dce_v8_0.c
drivers/gpu/drm/amd/amdgpu/gfx_v8_0.c
drivers/gpu/drm/amd/amdgpu/gmc_v7_0.c
drivers/gpu/drm/amd/amdgpu/gmc_v8_0.c
drivers/gpu/drm/amd/amdgpu/vce_v3_0.c
drivers/gpu/drm/amd/scheduler/gpu_sched_trace.h
drivers/gpu/drm/amd/scheduler/gpu_scheduler.c
drivers/gpu/drm/amd/scheduler/gpu_scheduler.h
drivers/gpu/drm/amd/scheduler/sched_fence.c
drivers/gpu/drm/drm_atomic.c
drivers/gpu/drm/drm_atomic_helper.c
drivers/gpu/drm/drm_drv.c
drivers/gpu/drm/drm_fb_helper.c
drivers/gpu/drm/drm_fops.c
drivers/gpu/drm/drm_irq.c
drivers/gpu/drm/drm_probe_helper.c
drivers/gpu/drm/exynos/exynos_drm_crtc.c
drivers/gpu/drm/i915/i915_debugfs.c
drivers/gpu/drm/i915/i915_drv.h
drivers/gpu/drm/i915/i915_gem.c
drivers/gpu/drm/i915/i915_gem_context.c
drivers/gpu/drm/i915/i915_gem_fence.c
drivers/gpu/drm/i915/i915_gem_gtt.c
drivers/gpu/drm/i915/i915_gem_stolen.c
drivers/gpu/drm/i915/i915_params.c
drivers/gpu/drm/i915/intel_crt.c
drivers/gpu/drm/i915/intel_ddi.c
drivers/gpu/drm/i915/intel_display.c
drivers/gpu/drm/i915/intel_dp.c
drivers/gpu/drm/i915/intel_drv.h
drivers/gpu/drm/i915/intel_hdmi.c
drivers/gpu/drm/i915/intel_i2c.c
drivers/gpu/drm/i915/intel_pm.c
drivers/gpu/drm/i915/intel_runtime_pm.c
drivers/gpu/drm/imx/imx-drm-core.c
drivers/gpu/drm/imx/imx-drm.h
drivers/gpu/drm/imx/imx-tve.c
drivers/gpu/drm/imx/ipuv3-crtc.c
drivers/gpu/drm/imx/ipuv3-plane.c
drivers/gpu/drm/imx/ipuv3-plane.h
drivers/gpu/drm/imx/parallel-display.c
drivers/gpu/drm/mgag200/mgag200_cursor.c
drivers/gpu/drm/nouveau/include/nvkm/core/device.h
drivers/gpu/drm/nouveau/include/nvkm/subdev/instmem.h
drivers/gpu/drm/nouveau/nouveau_acpi.c
drivers/gpu/drm/nouveau/nouveau_display.c
drivers/gpu/drm/nouveau/nouveau_drm.h
drivers/gpu/drm/nouveau/nouveau_usif.c
drivers/gpu/drm/nouveau/nvkm/engine/device/pci.c
drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgf117.c
drivers/gpu/drm/nouveau/nvkm/engine/gr/fuc/gpc.fuc
drivers/gpu/drm/nouveau/nvkm/engine/gr/fuc/gpcgf117.fuc3.h
drivers/gpu/drm/nouveau/nvkm/engine/gr/fuc/gpcgk104.fuc3.h
drivers/gpu/drm/nouveau/nvkm/engine/gr/fuc/gpcgk110.fuc3.h
drivers/gpu/drm/nouveau/nvkm/engine/gr/fuc/gpcgk208.fuc5.h
drivers/gpu/drm/nouveau/nvkm/engine/gr/fuc/gpcgm107.fuc5.h
drivers/gpu/drm/nouveau/nvkm/engine/gr/gf100.c
drivers/gpu/drm/nouveau/nvkm/engine/gr/gf100.h
drivers/gpu/drm/nouveau/nvkm/subdev/bios/fan.c
drivers/gpu/drm/nouveau/nvkm/subdev/instmem/base.c
drivers/gpu/drm/nouveau/nvkm/subdev/pmu/gk104.c
drivers/gpu/drm/nouveau/nvkm/subdev/volt/gk104.c
drivers/gpu/drm/omapdrm/omap_fbdev.c
drivers/gpu/drm/radeon/cik.c
drivers/gpu/drm/radeon/evergreen.c
drivers/gpu/drm/radeon/r100.c
drivers/gpu/drm/radeon/r600.c
drivers/gpu/drm/radeon/radeon.h
drivers/gpu/drm/radeon/radeon_agp.c
drivers/gpu/drm/radeon/radeon_connectors.c
drivers/gpu/drm/radeon/radeon_display.c
drivers/gpu/drm/radeon/radeon_irq_kms.c
drivers/gpu/drm/radeon/radeon_kms.c
drivers/gpu/drm/radeon/radeon_mode.h
drivers/gpu/drm/radeon/radeon_object.c
drivers/gpu/drm/radeon/radeon_pm.c
drivers/gpu/drm/radeon/radeon_vce.c
drivers/gpu/drm/radeon/rs600.c
drivers/gpu/drm/radeon/rs690.c
drivers/gpu/drm/radeon/rv730_dpm.c
drivers/gpu/drm/radeon/rv770_dpm.c
drivers/gpu/drm/radeon/si.c
drivers/gpu/drm/radeon/si_dpm.c
drivers/gpu/drm/rockchip/rockchip_drm_gem.c
drivers/gpu/drm/rockchip/rockchip_drm_vop.c
drivers/gpu/drm/ttm/ttm_lock.c
drivers/gpu/drm/vc4/vc4_crtc.c
drivers/gpu/drm/vc4/vc4_drv.c
drivers/gpu/drm/vc4/vc4_hvs.c
drivers/gpu/drm/vc4/vc4_plane.c
drivers/gpu/drm/virtio/virtgpu_display.c
drivers/gpu/drm/vmwgfx/vmwgfx_drv.c
drivers/gpu/drm/vmwgfx/vmwgfx_drv.h
drivers/gpu/drm/vmwgfx/vmwgfx_fifo.c
drivers/gpu/drm/vmwgfx/vmwgfx_kms.c
drivers/gpu/drm/vmwgfx/vmwgfx_kms.h
drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c
drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c
drivers/gpu/drm/vmwgfx/vmwgfx_stdu.c
drivers/gpu/ipu-v3/ipu-common.c
drivers/gpu/vga/vgaarb.c
drivers/hid/hid-ids.h
drivers/hid/hid-lg.c
drivers/hid/usbhid/hid-quirks.c
drivers/hid/wacom_wac.c
drivers/hwmon/Kconfig
drivers/hwmon/applesmc.c
drivers/hwmon/scpi-hwmon.c
drivers/hwmon/tmp102.c
drivers/i2c/busses/Kconfig
drivers/i2c/busses/i2c-davinci.c
drivers/i2c/busses/i2c-designware-core.c
drivers/i2c/busses/i2c-designware-core.h
drivers/i2c/busses/i2c-designware-platdrv.c
drivers/i2c/busses/i2c-i801.c
drivers/i2c/busses/i2c-imx.c
drivers/i2c/busses/i2c-mv64xxx.c
drivers/i2c/busses/i2c-rcar.c
drivers/i2c/busses/i2c-rk3x.c
drivers/i2c/busses/i2c-st.c
drivers/i2c/busses/i2c-xiic.c
drivers/i2c/i2c-core.c
drivers/iio/adc/ad7793.c
drivers/iio/adc/qcom-spmi-vadc.c
drivers/iio/adc/vf610_adc.c
drivers/iio/adc/xilinx-xadc-core.c
drivers/iio/dac/ad5064.c
drivers/iio/humidity/si7020.c
drivers/iio/industrialio-buffer.c
drivers/iio/industrialio-core.c
drivers/iio/light/apds9960.c
drivers/iio/proximity/pulsedlight-lidar-lite-v2.c
drivers/infiniband/core/cma.c
drivers/infiniband/core/mad.c
drivers/infiniband/core/sa_query.c
drivers/infiniband/core/uverbs_cmd.c
drivers/infiniband/core/verbs.c
drivers/infiniband/hw/mlx4/main.c
drivers/infiniband/hw/mlx4/qp.c
drivers/infiniband/hw/mlx4/srq.c
drivers/infiniband/hw/mlx5/mr.c
drivers/infiniband/hw/ocrdma/ocrdma.h
drivers/infiniband/hw/ocrdma/ocrdma_hw.c
drivers/infiniband/hw/ocrdma/ocrdma_hw.h
drivers/infiniband/hw/ocrdma/ocrdma_main.c
drivers/infiniband/hw/ocrdma/ocrdma_sli.h
drivers/infiniband/hw/ocrdma/ocrdma_verbs.c
drivers/infiniband/hw/qib/qib_qsfp.c
drivers/infiniband/hw/qib/qib_verbs.h
drivers/infiniband/ulp/iser/iser_verbs.c
drivers/infiniband/ulp/isert/ib_isert.c
drivers/infiniband/ulp/srp/ib_srp.c
drivers/infiniband/ulp/srp/ib_srp.h
drivers/input/joystick/db9.c
drivers/input/joystick/gamecon.c
drivers/input/joystick/turbografx.c
drivers/input/joystick/walkera0701.c
drivers/input/misc/arizona-haptics.c
drivers/input/mouse/elan_i2c_core.c
drivers/input/serio/parkbd.c
drivers/input/tablet/aiptek.c
drivers/input/touchscreen/atmel_mxt_ts.c
drivers/input/touchscreen/elants_i2c.c
drivers/iommu/amd_iommu_v2.c
drivers/iommu/intel-iommu.c
drivers/iommu/intel-svm.c
drivers/iommu/iommu.c
drivers/iommu/s390-iommu.c
drivers/irqchip/irq-gic-common.c
drivers/irqchip/irq-gic.c
drivers/irqchip/irq-versatile-fpga.c
drivers/isdn/gigaset/ser-gigaset.c
drivers/isdn/hardware/mISDN/mISDNipac.c
drivers/isdn/hisax/config.c
drivers/isdn/hisax/hfc_pci.c
drivers/isdn/hisax/hfc_sx.c
drivers/isdn/hisax/q931.c
drivers/lightnvm/Kconfig
drivers/lightnvm/core.c
drivers/lightnvm/gennvm.c
drivers/lightnvm/gennvm.h
drivers/lightnvm/rrpc.c
drivers/md/dm-crypt.c
drivers/md/dm-mpath.c
drivers/md/dm-thin-metadata.c
drivers/md/dm-thin.c
drivers/md/dm.c
drivers/md/md.c
drivers/md/md.h
drivers/md/persistent-data/dm-btree.c
drivers/md/persistent-data/dm-btree.h
drivers/md/persistent-data/dm-space-map-metadata.c
drivers/md/raid10.c
drivers/media/pci/cx23885/cx23885-core.c
drivers/media/pci/cx25821/cx25821-core.c
drivers/media/pci/cx88/cx88-alsa.c
drivers/media/pci/cx88/cx88-mpeg.c
drivers/media/pci/cx88/cx88-video.c
drivers/media/pci/ivtv/ivtv-driver.c
drivers/media/pci/netup_unidvb/netup_unidvb_core.c
drivers/media/pci/saa7134/saa7134-core.c
drivers/media/pci/saa7164/saa7164-core.c
drivers/media/pci/tw68/tw68-core.c
drivers/media/usb/airspy/airspy.c
drivers/media/usb/hackrf/hackrf.c
drivers/memory/fsl_ifc.c
drivers/misc/cxl/native.c
drivers/mmc/card/block.c
drivers/mmc/core/mmc.c
drivers/mmc/host/Kconfig
drivers/mmc/host/mtk-sd.c
drivers/mmc/host/pxamci.c
drivers/mtd/nand/jz4740_nand.c
drivers/mtd/nand/nand_base.c
drivers/mtd/ofpart.c
drivers/mtd/ubi/debug.c
drivers/mtd/ubi/io.c
drivers/mtd/ubi/wl.c
drivers/net/can/bfin_can.c
drivers/net/can/c_can/c_can.c
drivers/net/can/cc770/cc770.c
drivers/net/can/flexcan.c
drivers/net/can/janz-ican3.c
drivers/net/can/m_can/m_can.c
drivers/net/can/pch_can.c
drivers/net/can/rcar_can.c
drivers/net/can/sja1000/sja1000.c
drivers/net/can/sun4i_can.c
drivers/net/can/ti_hecc.c
drivers/net/can/usb/ems_usb.c
drivers/net/can/usb/esd_usb2.c
drivers/net/can/usb/kvaser_usb.c
drivers/net/can/usb/usb_8dev.c
drivers/net/can/xilinx_can.c
drivers/net/dsa/mv88e6060.c
drivers/net/dsa/mv88e6060.h [new file with mode: 0644]
drivers/net/ethernet/Kconfig
drivers/net/ethernet/Makefile
drivers/net/ethernet/amd/pcnet32.c
drivers/net/ethernet/amd/xgbe/xgbe-dev.c
drivers/net/ethernet/apm/xgene/xgene_enet_main.c
drivers/net/ethernet/apm/xgene/xgene_enet_main.h
drivers/net/ethernet/atheros/alx/main.c
drivers/net/ethernet/atheros/alx/reg.h
drivers/net/ethernet/atheros/atl1c/atl1c_main.c
drivers/net/ethernet/aurora/Kconfig [new file with mode: 0644]
drivers/net/ethernet/aurora/Makefile [new file with mode: 0644]
drivers/net/ethernet/aurora/nb8800.c [new file with mode: 0644]
drivers/net/ethernet/aurora/nb8800.h [new file with mode: 0644]
drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c
drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c
drivers/net/ethernet/broadcom/bnxt/bnxt.c
drivers/net/ethernet/broadcom/bnxt/bnxt.h
drivers/net/ethernet/broadcom/bnxt/bnxt_sriov.c
drivers/net/ethernet/cadence/macb.c
drivers/net/ethernet/cadence/macb.h
drivers/net/ethernet/cavium/liquidio/lio_main.c
drivers/net/ethernet/cavium/thunder/nic.h
drivers/net/ethernet/cavium/thunder/nic_main.c
drivers/net/ethernet/cavium/thunder/nicvf_ethtool.c
drivers/net/ethernet/cavium/thunder/nicvf_main.c
drivers/net/ethernet/cavium/thunder/nicvf_queues.c
drivers/net/ethernet/cavium/thunder/nicvf_queues.h
drivers/net/ethernet/cavium/thunder/thunder_bgx.c
drivers/net/ethernet/cavium/thunder/thunder_bgx.h
drivers/net/ethernet/dec/tulip/tulip_core.c
drivers/net/ethernet/dec/tulip/winbond-840.c
drivers/net/ethernet/dlink/Kconfig
drivers/net/ethernet/dlink/dl2k.c
drivers/net/ethernet/dlink/dl2k.h
drivers/net/ethernet/emulex/benet/be.h
drivers/net/ethernet/emulex/benet/be_ethtool.c
drivers/net/ethernet/emulex/benet/be_main.c
drivers/net/ethernet/emulex/benet/be_roce.c
drivers/net/ethernet/emulex/benet/be_roce.h
drivers/net/ethernet/ezchip/nps_enet.c
drivers/net/ethernet/freescale/Kconfig
drivers/net/ethernet/freescale/fs_enet/mac-fcc.c
drivers/net/ethernet/freescale/fsl_pq_mdio.c
drivers/net/ethernet/freescale/gianfar.c
drivers/net/ethernet/freescale/gianfar.h
drivers/net/ethernet/freescale/gianfar_ptp.c
drivers/net/ethernet/hisilicon/hns/hns_dsaf_main.c
drivers/net/ethernet/hisilicon/hns/hns_dsaf_reg.h
drivers/net/ethernet/icplus/Kconfig [deleted file]
drivers/net/ethernet/icplus/Makefile [deleted file]
drivers/net/ethernet/icplus/ipg.c [deleted file]
drivers/net/ethernet/icplus/ipg.h [deleted file]
drivers/net/ethernet/intel/fm10k/fm10k_netdev.c
drivers/net/ethernet/intel/i40e/i40e_adminq.c
drivers/net/ethernet/intel/i40e/i40e_main.c
drivers/net/ethernet/intel/i40evf/i40e_adminq.c
drivers/net/ethernet/intel/i40evf/i40evf_main.c
drivers/net/ethernet/intel/ixgbe/ixgbe_main.c
drivers/net/ethernet/marvell/mvneta.c
drivers/net/ethernet/marvell/mvpp2.c
drivers/net/ethernet/mellanox/mlx4/cmd.c
drivers/net/ethernet/mellanox/mlx4/en_clock.c
drivers/net/ethernet/mellanox/mlx4/en_main.c
drivers/net/ethernet/mellanox/mlx4/en_netdev.c
drivers/net/ethernet/mellanox/mlx4/main.c
drivers/net/ethernet/mellanox/mlx4/resource_tracker.c
drivers/net/ethernet/mellanox/mlx5/core/en.h
drivers/net/ethernet/mellanox/mlx5/core/en_main.c
drivers/net/ethernet/mellanox/mlx5/core/en_tx.c
drivers/net/ethernet/natsemi/natsemi.c
drivers/net/ethernet/nxp/lpc_eth.c
drivers/net/ethernet/qlogic/qed/qed.h
drivers/net/ethernet/qlogic/qed/qed_dev.c
drivers/net/ethernet/qlogic/qed/qed_int.c
drivers/net/ethernet/qlogic/qed/qed_int.h
drivers/net/ethernet/qlogic/qed/qed_main.c
drivers/net/ethernet/qlogic/qed/qed_reg_addr.h
drivers/net/ethernet/qlogic/qed/qed_sp.h
drivers/net/ethernet/qlogic/qed/qed_spq.c
drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_vnic.c
drivers/net/ethernet/qlogic/qlge/qlge_main.c
drivers/net/ethernet/qualcomm/qca_spi.c
drivers/net/ethernet/realtek/r8169.c
drivers/net/ethernet/renesas/ravb_main.c
drivers/net/ethernet/renesas/sh_eth.c
drivers/net/ethernet/renesas/sh_eth.h
drivers/net/ethernet/sfc/ef10.c
drivers/net/ethernet/sfc/efx.c
drivers/net/ethernet/sfc/efx.h
drivers/net/ethernet/sfc/farch.c
drivers/net/ethernet/sfc/txc43128_phy.c
drivers/net/ethernet/smsc/smsc911x.c
drivers/net/ethernet/stmicro/stmmac/dwmac-ipq806x.c
drivers/net/ethernet/stmicro/stmmac/dwmac-sti.c
drivers/net/ethernet/stmicro/stmmac/dwmac-sunxi.c
drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
drivers/net/ethernet/stmicro/stmmac/stmmac_mdio.c
drivers/net/ethernet/ti/cpsw-common.c
drivers/net/ethernet/ti/cpsw.c
drivers/net/ethernet/via/via-velocity.c
drivers/net/fjes/fjes_hw.c
drivers/net/geneve.c
drivers/net/hamradio/6pack.c
drivers/net/hamradio/mkiss.c
drivers/net/ipvlan/ipvlan_core.c
drivers/net/macvlan.c
drivers/net/macvtap.c
drivers/net/phy/at803x.c
drivers/net/phy/broadcom.c
drivers/net/phy/marvell.c
drivers/net/phy/mdio-mux.c
drivers/net/phy/micrel.c
drivers/net/phy/phy.c
drivers/net/phy/vitesse.c
drivers/net/ppp/pppoe.c
drivers/net/ppp/pptp.c
drivers/net/tun.c
drivers/net/usb/cdc_ether.c
drivers/net/usb/cdc_mbim.c
drivers/net/usb/cdc_ncm.c
drivers/net/usb/qmi_wwan.c
drivers/net/usb/r8152.c
drivers/net/veth.c
drivers/net/virtio_net.c
drivers/net/vmxnet3/vmxnet3_drv.c
drivers/net/vmxnet3/vmxnet3_int.h
drivers/net/vrf.c
drivers/net/vxlan.c
drivers/net/wan/hdlc_fr.c
drivers/net/wan/x25_asy.c
drivers/net/wireless/ath/ath10k/core.c
drivers/net/wireless/ath/ath10k/core.h
drivers/net/wireless/ath/ath10k/hw.h
drivers/net/wireless/ath/ath10k/mac.c
drivers/net/wireless/ath/ath10k/pci.c
drivers/net/wireless/iwlwifi/iwl-7000.c
drivers/net/wireless/iwlwifi/iwl-8000.c
drivers/net/wireless/iwlwifi/mvm/d3.c
drivers/net/wireless/iwlwifi/mvm/mac80211.c
drivers/net/wireless/iwlwifi/mvm/sta.c
drivers/net/wireless/iwlwifi/mvm/sta.h
drivers/net/wireless/iwlwifi/pcie/drv.c
drivers/net/wireless/realtek/rtlwifi/rtl8821ae/hw.c
drivers/net/wireless/realtek/rtlwifi/rtl8821ae/sw.c
drivers/net/xen-netback/netback.c
drivers/nvme/host/Makefile
drivers/nvme/host/lightnvm.c
drivers/nvme/host/nvme.h
drivers/nvme/host/pci.c
drivers/of/address.c
drivers/of/fdt.c
drivers/of/irq.c
drivers/of/of_reserved_mem.c
drivers/parisc/iommu-helpers.h
drivers/pci/host/pcie-altera.c
drivers/pci/host/pcie-designware.c
drivers/pci/host/pcie-hisi.c
drivers/pci/msi.c
drivers/pci/pci-driver.c
drivers/pci/pci-sysfs.c
drivers/pci/pci.h
drivers/pci/probe.c
drivers/phy/Kconfig
drivers/phy/phy-bcm-cygnus-pcie.c
drivers/phy/phy-berlin-sata.c
drivers/phy/phy-brcmstb-sata.c
drivers/phy/phy-core.c
drivers/phy/phy-miphy28lp.c
drivers/phy/phy-miphy365x.c
drivers/phy/phy-mt65xx-usb3.c
drivers/phy/phy-rockchip-usb.c
drivers/pinctrl/Kconfig
drivers/pinctrl/bcm/pinctrl-bcm2835.c
drivers/pinctrl/freescale/pinctrl-imx1-core.c
drivers/pinctrl/freescale/pinctrl-vf610.c
drivers/pinctrl/intel/pinctrl-broxton.c
drivers/pinctrl/intel/pinctrl-intel.c
drivers/pinctrl/intel/pinctrl-intel.h
drivers/pinctrl/intel/pinctrl-sunrisepoint.c
drivers/pinctrl/mediatek/pinctrl-mtk-common.c
drivers/pinctrl/qcom/pinctrl-ssbi-gpio.c
drivers/pinctrl/qcom/pinctrl-ssbi-mpp.c
drivers/pinctrl/sh-pfc/pfc-sh7734.c
drivers/powercap/intel_rapl.c
drivers/remoteproc/remoteproc_core.c
drivers/remoteproc/remoteproc_debugfs.c
drivers/rtc/rtc-da9063.c
drivers/rtc/rtc-ds1307.c
drivers/rtc/rtc-rk808.c
drivers/s390/cio/chsc.c
drivers/s390/cio/chsc.h
drivers/s390/cio/cio.c
drivers/s390/cio/css.c
drivers/s390/crypto/Makefile
drivers/s390/crypto/ap_bus.c
drivers/s390/crypto/zcrypt_api.c
drivers/s390/crypto/zcrypt_api.h
drivers/s390/crypto/zcrypt_msgtype50.c
drivers/s390/crypto/zcrypt_msgtype6.c
drivers/s390/virtio/virtio_ccw.c
drivers/scsi/Kconfig
drivers/scsi/advansys.c
drivers/scsi/hosts.c
drivers/scsi/hpsa.c
drivers/scsi/mpt3sas/Kconfig
drivers/scsi/mpt3sas/mpt3sas_scsih.c
drivers/scsi/mvsas/mv_init.c
drivers/scsi/qla2xxx/qla_nx.c
drivers/scsi/qla2xxx/tcm_qla2xxx.c
drivers/scsi/scsi_debug.c
drivers/scsi/scsi_pm.c
drivers/scsi/scsi_scan.c
drivers/scsi/scsi_sysfs.c
drivers/scsi/sd.c
drivers/scsi/sd.h
drivers/scsi/ses.c
drivers/scsi/st.c
drivers/sh/pm_runtime.c
drivers/soc/mediatek/Kconfig
drivers/soc/ti/knav_qmss_queue.c
drivers/spi/spi-bcm63xx.c
drivers/spi/spi-fsl-dspi.c
drivers/spi/spi-mt65xx.c
drivers/spi/spi-pl022.c
drivers/spi/spi.c
drivers/spi/spidev.c
drivers/staging/android/ion/ion_chunk_heap.c
drivers/staging/iio/Kconfig
drivers/staging/iio/adc/lpc32xx_adc.c
drivers/staging/iio/iio_simple_dummy_events.c
drivers/staging/lustre/include/linux/libcfs/libcfs_ioctl.h
drivers/staging/lustre/lustre/libcfs/module.c
drivers/staging/lustre/lustre/obdecho/echo_client.c
drivers/staging/wilc1000/coreconfigurator.c
drivers/target/iscsi/iscsi_target.c
drivers/target/iscsi/iscsi_target_nego.c
drivers/target/iscsi/iscsi_target_parameters.c
drivers/target/target_core_sbc.c
drivers/target/target_core_stat.c
drivers/target/target_core_tmr.c
drivers/target/target_core_transport.c
drivers/target/target_core_user.c
drivers/thermal/Kconfig
drivers/thermal/imx_thermal.c
drivers/thermal/of-thermal.c
drivers/thermal/power_allocator.c
drivers/thermal/rcar_thermal.c
drivers/thermal/rockchip_thermal.c
drivers/tty/n_tty.c
drivers/tty/serial/8250/8250_fsl.c
drivers/tty/serial/8250/8250_uniphier.c
drivers/tty/serial/8250/Kconfig
drivers/tty/serial/Kconfig
drivers/tty/serial/bcm63xx_uart.c
drivers/tty/serial/earlycon.c
drivers/tty/serial/etraxfs-uart.c
drivers/tty/serial/sh-sci.c
drivers/tty/serial/sunhv.c
drivers/tty/tty_audit.c
drivers/tty/tty_buffer.c
drivers/tty/tty_io.c
drivers/tty/tty_ioctl.c
drivers/tty/tty_ldisc.c
drivers/usb/chipidea/ci_hdrc_imx.c
drivers/usb/chipidea/debug.c
drivers/usb/chipidea/udc.c
drivers/usb/chipidea/usbmisc_imx.c
drivers/usb/class/cdc-acm.c
drivers/usb/class/usblp.c
drivers/usb/core/Kconfig
drivers/usb/core/config.c
drivers/usb/core/hub.c
drivers/usb/core/port.c
drivers/usb/core/quirks.c
drivers/usb/dwc2/hcd.c
drivers/usb/dwc2/platform.c
drivers/usb/dwc3/dwc3-pci.c
drivers/usb/dwc3/gadget.c
drivers/usb/gadget/function/f_fs.c
drivers/usb/gadget/function/f_loopback.c
drivers/usb/gadget/function/f_midi.c
drivers/usb/gadget/function/uvc_configfs.c
drivers/usb/gadget/udc/atmel_usba_udc.c
drivers/usb/gadget/udc/pxa27x_udc.c
drivers/usb/host/ohci-at91.c
drivers/usb/host/whci/qset.c
drivers/usb/host/xhci-hub.c
drivers/usb/host/xhci-pci.c
drivers/usb/host/xhci-ring.c
drivers/usb/host/xhci.c
drivers/usb/musb/Kconfig
drivers/usb/musb/musb_core.c
drivers/usb/musb/musb_host.c
drivers/usb/phy/Kconfig
drivers/usb/phy/phy-msm-usb.c
drivers/usb/phy/phy-mxs-usb.c
drivers/usb/phy/phy-omap-otg.c
drivers/usb/renesas_usbhs/mod_gadget.c
drivers/usb/serial/cp210x.c
drivers/usb/serial/ipaq.c
drivers/usb/serial/option.c
drivers/usb/serial/qcserial.c
drivers/usb/serial/ti_usb_3410_5052.c
drivers/usb/serial/ti_usb_3410_5052.h
drivers/usb/serial/usb-serial-simple.c
drivers/usb/storage/uas.c
drivers/usb/storage/unusual_devs.h
drivers/usb/storage/unusual_uas.h
drivers/vfio/Kconfig
drivers/vfio/pci/vfio_pci.c
drivers/vfio/platform/vfio_platform.c
drivers/vfio/platform/vfio_platform_common.c
drivers/vfio/vfio.c
drivers/vhost/vhost.c
drivers/video/fbdev/fsl-diu-fb.c
drivers/video/fbdev/omap2/dss/venc.c
drivers/virtio/virtio.c
drivers/virtio/virtio_ring.c
drivers/watchdog/Kconfig
drivers/watchdog/mtk_wdt.c
drivers/watchdog/omap_wdt.c
drivers/watchdog/pnx4008_wdt.c
drivers/watchdog/tegra_wdt.c
drivers/watchdog/w83977f_wdt.c
drivers/xen/events/events_base.c
drivers/xen/events/events_fifo.c
drivers/xen/evtchn.c
drivers/xen/gntdev.c
drivers/xen/xen-pciback/pciback.h
drivers/xen/xen-pciback/pciback_ops.c
drivers/xen/xen-pciback/xenbus.c
drivers/xen/xen-scsiback.c
fs/9p/vfs_inode.c
fs/Kconfig
fs/block_dev.c
fs/btrfs/backref.c
fs/btrfs/ctree.h
fs/btrfs/extent-tree.c
fs/btrfs/file.c
fs/btrfs/free-space-cache.c
fs/btrfs/inode.c
fs/btrfs/qgroup.c
fs/btrfs/scrub.c
fs/btrfs/tests/free-space-tests.c
fs/btrfs/transaction.c
fs/btrfs/transaction.h
fs/btrfs/volumes.c
fs/btrfs/volumes.h
fs/cachefiles/rdwr.c
fs/cifs/inode.c
fs/configfs/dir.c
fs/dax.c
fs/direct-io.c
fs/dlm/lowcomms.c
fs/exofs/inode.c
fs/ext2/super.c
fs/ext4/crypto.c
fs/ext4/ext4.h
fs/ext4/super.c
fs/ext4/symlink.c
fs/ext4/sysfs.c
fs/fat/dir.c
fs/fuse/cuse.c
fs/fuse/file.c
fs/hugetlbfs/inode.c
fs/jbd2/transaction.c
fs/namei.c
fs/ncpfs/ioctl.c
fs/nfs/inode.c
fs/nfs/internal.h
fs/nfs/nfs42proc.c
fs/nfs/nfs4client.c
fs/nfs/nfs4file.c
fs/nfs/nfs4proc.c
fs/nfs/nfs4xdr.c
fs/nfs/objlayout/objio_osd.c
fs/nfs/pagelist.c
fs/nfs/pnfs.c
fs/nfsd/nfs4layouts.c
fs/ocfs2/dlm/dlmmaster.c
fs/ocfs2/locks.c
fs/ocfs2/namei.c
fs/ocfs2/resize.c
fs/overlayfs/copy_up.c
fs/overlayfs/inode.c
fs/overlayfs/overlayfs.h
fs/proc/base.c
fs/splice.c
fs/sysv/inode.c
include/asm-generic/tlb.h
include/drm/drmP.h
include/drm/drm_atomic.h
include/kvm/arm_vgic.h
include/linux/acpi.h
include/linux/bitops.h
include/linux/blkdev.h
include/linux/bpf.h
include/linux/cgroup-defs.h
include/linux/cgroup.h
include/linux/configfs.h
include/linux/cpufreq.h
include/linux/dns_resolver.h
include/linux/enclosure.h
include/linux/gfp.h
include/linux/ipv6.h
include/linux/irqchip/arm-gic-v3.h
include/linux/jump_label.h
include/linux/kmemleak.h
include/linux/kref.h
include/linux/kvm_host.h
include/linux/libata.h
include/linux/lightnvm.h
include/linux/lockdep.h
include/linux/marvell_phy.h
include/linux/mlx4/device.h
include/linux/mlx5/mlx5_ifc.h
include/linux/mmdebug.h
include/linux/net.h
include/linux/netdevice.h
include/linux/netfilter/ipset/ip_set.h
include/linux/netfilter/nfnetlink.h
include/linux/netfilter_ingress.h
include/linux/nfs_xdr.h
include/linux/of_dma.h
include/linux/of_irq.h
include/linux/pci.h
include/linux/perf_event.h
include/linux/platform_data/asoc-s3c.h
include/linux/platform_data/edma.h
include/linux/proportions.h
include/linux/qed/common_hsi.h
include/linux/qed/qed_chain.h
include/linux/rhashtable.h
include/linux/scpi_protocol.h
include/linux/signal.h
include/linux/slab.h
include/linux/stop_machine.h
include/linux/syscalls.h
include/linux/thermal.h
include/linux/tty.h
include/linux/types.h
include/linux/uprobes.h
include/linux/usb/cdc_ncm.h
include/linux/usb/quirks.h
include/linux/vfio.h
include/linux/vmstat.h
include/linux/wait.h
include/net/af_unix.h
include/net/dst.h
include/net/inet_sock.h
include/net/inetpeer.h
include/net/ip6_fib.h
include/net/ip6_route.h
include/net/ip6_tunnel.h
include/net/ip_tunnels.h
include/net/ipv6.h
include/net/mac80211.h
include/net/ndisc.h
include/net/netfilter/nf_tables.h
include/net/sch_generic.h
include/net/sctp/structs.h
include/net/sock.h
include/net/switchdev.h
include/net/vxlan.h
include/net/xfrm.h
include/rdma/ib_mad.h
include/rdma/ib_verbs.h
include/scsi/scsi_host.h
include/sound/ac97_codec.h
include/sound/da7218.h [new file with mode: 0644]
include/sound/da7219.h
include/sound/designware_i2s.h
include/sound/hda_register.h
include/sound/hdaudio_ext.h
include/sound/rt5659.h [new file with mode: 0644]
include/sound/soc-dai.h
include/sound/soc-dapm.h
include/sound/soc-topology.h
include/sound/soc.h
include/target/target_core_base.h
include/uapi/linux/Kbuild
include/uapi/linux/nfs.h
include/uapi/linux/openvswitch.h
include/uapi/linux/vfio.h
include/uapi/sound/asoc.h
include/uapi/sound/compress_params.h
include/video/imx-ipu-v3.h
include/xen/interface/io/ring.h
init/Kconfig
kernel/bpf/arraymap.c
kernel/bpf/hashtab.c
kernel/bpf/inode.c
kernel/bpf/syscall.c
kernel/bpf/verifier.c
kernel/cgroup.c
kernel/cgroup_freezer.c
kernel/cgroup_pids.c
kernel/cpuset.c
kernel/events/callchain.c
kernel/events/core.c
kernel/events/ring_buffer.c
kernel/events/uprobes.c
kernel/fork.c
kernel/irq_work.c
kernel/jump_label.c
kernel/livepatch/core.c
kernel/locking/lockdep.c
kernel/locking/lockdep_proc.c
kernel/locking/osq_lock.c
kernel/panic.c
kernel/pid.c
kernel/sched/clock.c
kernel/sched/core.c
kernel/sched/cputime.c
kernel/sched/fair.c
kernel/sched/rt.c
kernel/sched/sched.h
kernel/sched/wait.c
kernel/signal.c
kernel/stop_machine.c
kernel/trace/ring_buffer.c
kernel/trace/trace_event_perf.c
kernel/trace/trace_events.c
lib/btree.c
lib/dma-debug.c
lib/proportions.c
lib/rhashtable.c
mm/backing-dev.c
mm/huge_memory.c
mm/hugetlb.c
mm/kasan/kasan.c
mm/memcontrol.c
mm/memory.c
mm/memory_hotplug.c
mm/oom_kill.c
mm/page-writeback.c
mm/page_alloc.c
mm/shmem.c
mm/slab.c
mm/slab.h
mm/slab_common.c
mm/slob.c
mm/slub.c
mm/vmalloc.c
mm/vmstat.c
mm/zswap.c
net/8021q/vlan_core.c
net/ax25/af_ax25.c
net/batman-adv/distributed-arp-table.c
net/batman-adv/routing.c
net/batman-adv/translation-table.c
net/bluetooth/af_bluetooth.c
net/bluetooth/sco.c
net/bluetooth/smp.c
net/bridge/br_stp.c
net/bridge/br_stp_if.c
net/caif/caif_socket.c
net/core/datagram.c
net/core/dev.c
net/core/neighbour.c
net/core/netclassid_cgroup.c
net/core/netprio_cgroup.c
net/core/rtnetlink.c
net/core/scm.c
net/core/skbuff.c
net/core/sock.c
net/core/stream.c
net/dccp/ipv6.c
net/dccp/proto.c
net/decnet/af_decnet.c
net/dns_resolver/dns_query.c
net/hsr/hsr_device.c
net/ipv4/af_inet.c
net/ipv4/fib_frontend.c
net/ipv4/fou.c
net/ipv4/igmp.c
net/ipv4/inet_connection_sock.c
net/ipv4/ipip.c
net/ipv4/ipmr.c
net/ipv4/netfilter/Kconfig
net/ipv4/netfilter/nf_nat_pptp.c
net/ipv4/raw.c
net/ipv4/tcp.c
net/ipv4/tcp_diag.c
net/ipv4/tcp_input.c
net/ipv4/tcp_ipv4.c
net/ipv4/tcp_output.c
net/ipv4/tcp_timer.c
net/ipv4/udp.c
net/ipv4/xfrm4_policy.c
net/ipv6/addrconf.c
net/ipv6/addrlabel.c
net/ipv6/af_inet6.c
net/ipv6/datagram.c
net/ipv6/exthdrs.c
net/ipv6/icmp.c
net/ipv6/inet6_connection_sock.c
net/ipv6/ip6_gre.c
net/ipv6/ip6_tunnel.c
net/ipv6/ip6mr.c
net/ipv6/ipv6_sockglue.c
net/ipv6/mcast.c
net/ipv6/ndisc.c
net/ipv6/netfilter/Kconfig
net/ipv6/netfilter/nf_conntrack_reasm.c
net/ipv6/raw.c
net/ipv6/reassembly.c
net/ipv6/route.c
net/ipv6/syncookies.c
net/ipv6/tcp_ipv6.c
net/ipv6/udp.c
net/ipv6/xfrm6_policy.c
net/irda/af_irda.c
net/iucv/af_iucv.c
net/l2tp/l2tp_ip6.c
net/mac80211/agg-tx.c
net/mac80211/cfg.c
net/mac80211/ieee80211_i.h
net/mac80211/iface.c
net/mac80211/main.c
net/mac80211/mesh_pathtbl.c
net/mac80211/mlme.c
net/mac80211/rx.c
net/mac80211/scan.c
net/mac80211/util.c
net/mac80211/vht.c
net/mpls/af_mpls.c
net/mpls/mpls_iptunnel.c
net/netfilter/Kconfig
net/netfilter/ipset/ip_set_bitmap_gen.h
net/netfilter/ipset/ip_set_bitmap_ip.c
net/netfilter/ipset/ip_set_bitmap_ipmac.c
net/netfilter/ipset/ip_set_bitmap_port.c
net/netfilter/ipset/ip_set_core.c
net/netfilter/ipset/ip_set_hash_gen.h
net/netfilter/ipset/ip_set_list_set.c
net/netfilter/ipvs/ip_vs_core.c
net/netfilter/nf_tables_api.c
net/netfilter/nf_tables_netdev.c
net/netfilter/nfnetlink.c
net/netfilter/nfnetlink_log.c
net/netfilter/nfnetlink_queue.c
net/netfilter/nft_counter.c
net/netfilter/nft_ct.c
net/netfilter/nft_dynset.c
net/nfc/llcp_sock.c
net/openvswitch/conntrack.c
net/openvswitch/dp_notify.c
net/openvswitch/flow_netlink.c
net/openvswitch/vport-geneve.c
net/openvswitch/vport-gre.c
net/openvswitch/vport-netdev.c
net/openvswitch/vport.c
net/openvswitch/vport.h
net/packet/af_packet.c
net/rds/connection.c
net/rds/send.c
net/rfkill/core.c
net/rxrpc/ar-ack.c
net/rxrpc/ar-output.c
net/sched/sch_api.c
net/sched/sch_generic.c
net/sched/sch_mq.c
net/sched/sch_mqprio.c
net/sctp/auth.c
net/sctp/ipv6.c
net/sctp/outqueue.c
net/sctp/sm_make_chunk.c
net/sctp/sm_statefuns.c
net/sctp/socket.c
net/socket.c
net/sunrpc/sched.c
net/sunrpc/svc.c
net/sunrpc/xprtsock.c
net/tipc/link.c
net/tipc/socket.c
net/tipc/udp_media.c
net/unix/af_unix.c
net/wireless/nl80211.c
net/wireless/reg.c
net/xfrm/xfrm_policy.c
samples/bpf/Makefile
scripts/kernel-doc
scripts/link-vmlinux.sh
scripts/recordmcount.c
security/keys/encrypted-keys/encrypted.c
security/keys/keyctl.c
security/keys/trusted.c
security/keys/user_defined.c
security/selinux/ss/conditional.c
sound/firewire/dice/dice.c
sound/hda/ext/hdac_ext_controller.c
sound/hda/ext/hdac_ext_stream.c
sound/pci/hda/hda_intel.c
sound/pci/hda/patch_ca0132.c
sound/pci/hda/patch_conexant.c
sound/pci/hda/patch_hdmi.c
sound/pci/hda/patch_realtek.c
sound/pci/hda/patch_sigmatel.c
sound/pci/rme96.c
sound/soc/Kconfig
sound/soc/Makefile
sound/soc/amd/Kconfig [new file with mode: 0644]
sound/soc/amd/Makefile [new file with mode: 0644]
sound/soc/amd/acp-pcm-dma.c [new file with mode: 0644]
sound/soc/amd/acp.h [new file with mode: 0644]
sound/soc/amd/include/acp_2_2_d.h [new file with mode: 0644]
sound/soc/amd/include/acp_2_2_enum.h [new file with mode: 0644]
sound/soc/amd/include/acp_2_2_sh_mask.h [new file with mode: 0644]
sound/soc/atmel/Kconfig
sound/soc/atmel/Makefile
sound/soc/atmel/atmel-classd.c
sound/soc/atmel/atmel-pdmic.c [new file with mode: 0644]
sound/soc/atmel/atmel-pdmic.h [new file with mode: 0644]
sound/soc/atmel/atmel_wm8904.c
sound/soc/bcm/bcm2835-i2s.c
sound/soc/codecs/Kconfig
sound/soc/codecs/Makefile
sound/soc/codecs/ak4613.c
sound/soc/codecs/arizona.c
sound/soc/codecs/arizona.h
sound/soc/codecs/cs47l24.c [new file with mode: 0644]
sound/soc/codecs/cs47l24.h [new file with mode: 0644]
sound/soc/codecs/da7218.c [new file with mode: 0644]
sound/soc/codecs/da7218.h [new file with mode: 0644]
sound/soc/codecs/da7219.c
sound/soc/codecs/da7219.h
sound/soc/codecs/es8328.c
sound/soc/codecs/es8328.h
sound/soc/codecs/hdac_hdmi.c [new file with mode: 0644]
sound/soc/codecs/inno_rk3036.c [new file with mode: 0644]
sound/soc/codecs/inno_rk3036.h [new file with mode: 0644]
sound/soc/codecs/max98357a.c
sound/soc/codecs/nau8825.c
sound/soc/codecs/pcm1792a.c [deleted file]
sound/soc/codecs/pcm179x.c [new file with mode: 0644]
sound/soc/codecs/pcm179x.h [moved from sound/soc/codecs/pcm1792a.h with 91% similarity]
sound/soc/codecs/pcm3168a-i2c.c [new file with mode: 0644]
sound/soc/codecs/pcm3168a-spi.c [new file with mode: 0644]
sound/soc/codecs/pcm3168a.c [new file with mode: 0644]
sound/soc/codecs/pcm3168a.h [new file with mode: 0644]
sound/soc/codecs/rl6231.c
sound/soc/codecs/rt286.c
sound/soc/codecs/rt298.c
sound/soc/codecs/rt5616.c [new file with mode: 0644]
sound/soc/codecs/rt5616.h [new file with mode: 0644]
sound/soc/codecs/rt5640.c
sound/soc/codecs/rt5640.h
sound/soc/codecs/rt5645.c
sound/soc/codecs/rt5645.h
sound/soc/codecs/rt5659.c [new file with mode: 0644]
sound/soc/codecs/rt5659.h [new file with mode: 0644]
sound/soc/codecs/rt5670.h
sound/soc/codecs/rt5677.c
sound/soc/codecs/sgtl5000.c
sound/soc/codecs/ssm2518.c
sound/soc/codecs/twl6040.c
sound/soc/codecs/wm5110.c
sound/soc/codecs/wm8903.c
sound/soc/codecs/wm8904.c
sound/soc/codecs/wm8960.c
sound/soc/codecs/wm8962.c
sound/soc/codecs/wm8974.c
sound/soc/codecs/wm8998.c
sound/soc/codecs/wm9713.c
sound/soc/codecs/wm_adsp.c
sound/soc/codecs/wm_adsp.h
sound/soc/davinci/davinci-mcasp.c
sound/soc/dwc/designware_i2s.c
sound/soc/fsl/Kconfig
sound/soc/fsl/fsl-asoc-card.c
sound/soc/fsl/fsl_asrc.c
sound/soc/fsl/fsl_asrc.h
sound/soc/fsl/fsl_esai.c
sound/soc/fsl/fsl_sai.c
sound/soc/fsl/fsl_sai.h
sound/soc/fsl/fsl_spdif.c
sound/soc/fsl/fsl_ssi.c
sound/soc/fsl/imx-pcm-dma.c
sound/soc/fsl/imx-pcm-fiq.c
sound/soc/fsl/imx-wm8962.c
sound/soc/fsl/mpc8610_hpcd.c
sound/soc/fsl/p1022_ds.c
sound/soc/fsl/p1022_rdk.c
sound/soc/generic/simple-card.c
sound/soc/img/Kconfig [new file with mode: 0644]
sound/soc/img/Makefile [new file with mode: 0644]
sound/soc/img/img-i2s-in.c [new file with mode: 0644]
sound/soc/img/img-i2s-out.c [new file with mode: 0644]
sound/soc/img/img-parallel-out.c [new file with mode: 0644]
sound/soc/img/img-spdif-in.c [new file with mode: 0644]
sound/soc/img/img-spdif-out.c [new file with mode: 0644]
sound/soc/img/pistachio-internal-dac.c [new file with mode: 0644]
sound/soc/intel/Kconfig
sound/soc/intel/atom/sst-atom-controls.c
sound/soc/intel/atom/sst-atom-controls.h
sound/soc/intel/atom/sst-mfld-platform-pcm.c
sound/soc/intel/atom/sst/sst_acpi.c
sound/soc/intel/atom/sst/sst_stream.c
sound/soc/intel/baytrail/sst-baytrail-pcm.c
sound/soc/intel/boards/Makefile
sound/soc/intel/boards/bytcr_rt5640.c
sound/soc/intel/boards/bytcr_rt5651.c [new file with mode: 0644]
sound/soc/intel/boards/cht_bsw_max98090_ti.c
sound/soc/intel/boards/cht_bsw_rt5645.c
sound/soc/intel/boards/cht_bsw_rt5672.c
sound/soc/intel/boards/skl_nau88l25_max98357a.c [new file with mode: 0644]
sound/soc/intel/boards/skl_nau88l25_ssm4567.c [new file with mode: 0644]
sound/soc/intel/boards/skl_rt286.c
sound/soc/intel/common/Makefile
sound/soc/intel/common/sst-acpi.c
sound/soc/intel/common/sst-acpi.h [new file with mode: 0644]
sound/soc/intel/common/sst-dsp-priv.h
sound/soc/intel/common/sst-dsp.c
sound/soc/intel/common/sst-dsp.h
sound/soc/intel/common/sst-firmware.c
sound/soc/intel/common/sst-match-acpi.c [new file with mode: 0644]
sound/soc/intel/haswell/sst-haswell-dsp.c
sound/soc/intel/haswell/sst-haswell-ipc.c
sound/soc/intel/skylake/skl-messages.c
sound/soc/intel/skylake/skl-nhlt.c
sound/soc/intel/skylake/skl-pcm.c
sound/soc/intel/skylake/skl-sst-cldma.c
sound/soc/intel/skylake/skl-sst-dsp.h
sound/soc/intel/skylake/skl-sst-ipc.c
sound/soc/intel/skylake/skl-sst-ipc.h
sound/soc/intel/skylake/skl-sst.c
sound/soc/intel/skylake/skl-topology.c
sound/soc/intel/skylake/skl-topology.h
sound/soc/intel/skylake/skl-tplg-interface.h
sound/soc/intel/skylake/skl.c
sound/soc/intel/skylake/skl.h
sound/soc/mediatek/mtk-afe-common.h
sound/soc/mediatek/mtk-afe-pcm.c
sound/soc/omap/omap-hdmi-audio.c
sound/soc/pxa/brownstone.c
sound/soc/pxa/mioa701_wm9713.c
sound/soc/qcom/lpass-cpu.c
sound/soc/rockchip/rockchip_i2s.c
sound/soc/rockchip/rockchip_max98090.c
sound/soc/rockchip/rockchip_rt5645.c
sound/soc/rockchip/rockchip_spdif.c
sound/soc/rockchip/rockchip_spdif.h
sound/soc/samsung/Kconfig
sound/soc/samsung/ac97.c
sound/soc/samsung/bells.c
sound/soc/samsung/dma.h
sound/soc/samsung/dmaengine.c
sound/soc/samsung/i2s.c
sound/soc/samsung/littlemill.c
sound/soc/samsung/odroidx2_max98090.c
sound/soc/samsung/pcm.c
sound/soc/samsung/s3c2412-i2s.c
sound/soc/samsung/s3c24xx-i2s.c
sound/soc/samsung/snow.c
sound/soc/samsung/spdif.c
sound/soc/samsung/speyside.c
sound/soc/samsung/tobermory.c
sound/soc/sh/Kconfig
sound/soc/sh/fsi.c
sound/soc/sh/rcar/Makefile
sound/soc/sh/rcar/adg.c
sound/soc/sh/rcar/cmd.c [new file with mode: 0644]
sound/soc/sh/rcar/core.c
sound/soc/sh/rcar/ctu.c
sound/soc/sh/rcar/dma.c
sound/soc/sh/rcar/dvc.c
sound/soc/sh/rcar/gen.c
sound/soc/sh/rcar/mix.c
sound/soc/sh/rcar/rcar_snd.h [deleted file]
sound/soc/sh/rcar/rsnd.h
sound/soc/sh/rcar/rsrc-card.c
sound/soc/sh/rcar/src.c
sound/soc/sh/rcar/ssi.c
sound/soc/sh/rcar/ssiu.c [new file with mode: 0644]
sound/soc/soc-ac97.c
sound/soc/soc-compress.c
sound/soc/soc-core.c
sound/soc/soc-dapm.c
sound/soc/soc-ops.c
sound/soc/soc-pcm.c
sound/soc/soc-topology.c
sound/soc/sti/uniperif_player.c
sound/soc/sti/uniperif_reader.c
sound/soc/sunxi/sun4i-codec.c
sound/soc/tegra/tegra_alc5632.c
sound/soc/tegra/tegra_wm8903.c
sound/usb/midi.c
sound/usb/mixer.c
sound/usb/mixer_maps.c
sound/usb/mixer_quirks.c
sound/usb/mixer_quirks.h
sound/usb/quirks-table.h
sound/usb/quirks.c
sound/usb/usbaudio.h
tools/Makefile
tools/net/Makefile
tools/perf/builtin-inject.c
tools/perf/builtin-report.c
tools/perf/ui/browsers/hists.c
tools/perf/util/build-id.c
tools/perf/util/dso.c
tools/perf/util/dso.h
tools/perf/util/machine.c
tools/perf/util/probe-finder.c
tools/perf/util/symbol.c
tools/perf/util/symbol.h
tools/power/x86/turbostat/turbostat.c
tools/testing/nvdimm/test/nfit.c
tools/testing/selftests/futex/README
tools/testing/selftests/seccomp/seccomp_bpf.c
tools/virtio/linux/kernel.h
tools/virtio/linux/virtio.h
tools/virtio/linux/virtio_config.h
tools/vm/page-types.c
virt/kvm/arm/arch_timer.c
virt/kvm/arm/vgic.c

index 31d1d658827f082f66c88c3147e99be3321635cf..c0d8788e75d3f1f2a335a27a883f161ad51128ac 100644 (file)
@@ -587,7 +587,7 @@ used to control it:
 
   modprobe ipmi_watchdog timeout=<t> pretimeout=<t> action=<action type>
       preaction=<preaction type> preop=<preop type> start_now=x
-      nowayout=x ifnum_to_use=n
+      nowayout=x ifnum_to_use=n panic_wdt_timeout=<t>
 
 ifnum_to_use specifies which interface the watchdog timer should use.
 The default is -1, which means to pick the first one registered.
@@ -597,7 +597,9 @@ is the amount of seconds before the reset that the pre-timeout panic will
 occur (if pretimeout is zero, then pretimeout will not be enabled).  Note
 that the pretimeout is the time before the final timeout.  So if the
 timeout is 50 seconds and the pretimeout is 10 seconds, then the pretimeout
-will occur in 40 second (10 seconds before the timeout).
+will occur in 40 second (10 seconds before the timeout). The panic_wdt_timeout
+is the value of timeout which is set on kernel panic, in order to let actions
+such as kdump to occur during panic.
 
 The action may be "reset", "power_cycle", or "power_off", and
 specifies what to do when the timer times out, and defaults to
@@ -634,6 +636,7 @@ for configuring the watchdog:
        ipmi_watchdog.preop=<preop type>
        ipmi_watchdog.start_now=x
        ipmi_watchdog.nowayout=x
+       ipmi_watchdog.panic_wdt_timeout=<t>
 
 The options are the same as the module parameter options.
 
index f17bc4c9dff9fa1334d518e0a6c0ffc8ac270e3a..400c0c270d2e8d935e55fc1396989e75abbad36d 100644 (file)
@@ -49,24 +49,6 @@ specified through DTS. Following are the DTS used:-
 The device tree documentation for the keystone machines are located at
         Documentation/devicetree/bindings/arm/keystone/keystone.txt
 
-Known issues & workaround
--------------------------
-
-Some of the device drivers used on keystone are re-used from that from
-DaVinci and other TI SoCs. These device drivers may use clock APIs directly.
-Some of the keystone specific drivers such as netcp uses run time power
-management API instead to enable clock. As this API has limitations on
-keystone, following workaround is needed to boot Linux.
-
-   Add 'clk_ignore_unused' to the bootargs env variable in u-boot. Otherwise
-   clock frameworks will try to disable clocks that are unused and disable
-   the hardware. This is because netcp related power domain and clock
-   domains are enabled in u-boot as run time power management API currently
-   doesn't enable clocks for netcp due to a limitation. This workaround is
-   expected to be removed in the future when proper API support becomes
-   available. Until then, this work around is needed.
-
-
 Document Author
 ---------------
 Murali Karicheri <m-karicheri2@ti.com>
index 2f6c6ff7161d4e77f3ec8ffee998b19f53b18cf7..d8880ca30af4c35d562c0f77b1b3a56c3ff6e1d7 100644 (file)
@@ -70,3 +70,6 @@ use_per_node_hctx=[0/1]: Default: 0
      parameter.
   1: The multi-queue block layer is instantiated with a hardware dispatch
      queue for each CPU node in the system.
+
+use_lightnvm=[0/1]: Default: 0
+  Register device with LightNVM. Requires blk-mq to be used.
index d3d0a4fb1c733b8288884869088fda088328546d..079b42a81d7cf3c5af086872fc86127023ab2c15 100644 (file)
@@ -22,8 +22,7 @@ Required properties:
 Optional properties:
 - ti,hwmods:   Name of the hwmods associated to the eDMA CC
 - ti,edma-memcpy-channels: List of channels allocated to be used for memcpy, iow
-               these channels will be SW triggered channels. The list must
-               contain 16 bits numbers, see example.
+               these channels will be SW triggered channels. See example.
 - ti,edma-reserved-slot-ranges: PaRAM slot ranges which should not be used by
                the driver, they are allocated to be used by for example the
                DSP. See example.
@@ -56,10 +55,9 @@ edma: edma@49000000 {
        ti,tptcs = <&edma_tptc0 7>, <&edma_tptc1 7>, <&edma_tptc2 0>;
 
        /* Channel 20 and 21 is allocated for memcpy */
-       ti,edma-memcpy-channels = /bits/ 16 <20 21>;
-       /* The following PaRAM slots are reserved: 35-45 and 100-110 */
-       ti,edma-reserved-slot-ranges = /bits/ 16 <35 10>,
-                                      /bits/ 16 <100 10>;
+       ti,edma-memcpy-channels = <20 21>;
+       /* The following PaRAM slots are reserved: 35-44 and 100-109 */
+       ti,edma-reserved-slot-ranges = <35 10>, <100 10>;
 };
 
 edma_tptc0: tptc@49800000 {
index f2455c50533d6c7388ebfacbe572d164e5d11314..120bc4971cf3ed92cf9590af16643645e5c89234 100644 (file)
@@ -11,6 +11,10 @@ Required properties:
       0 = active high
       1 = active low
 
+Optional properties:
+- little-endian : GPIO registers are used as little endian. If not
+                  present registers are used as big endian by default.
+
 Example:
 
 gpio0: gpio@1100 {
index b9c32f6fd687b04a3737c871bcf5c694665d3b84..4357e498ef0422d5fdc2715e3daf065ac80e41f4 100644 (file)
@@ -12,7 +12,7 @@ Each key is represented as a sub-node of "allwinner,sun4i-a10-lradc-keys":
 Required subnode-properties:
        - label: Descriptive name of the key.
        - linux,code: Keycode to emit.
-       - channel: Channel this key is attached to, mut be 0 or 1.
+       - channel: Channel this key is attached to, must be 0 or 1.
        - voltage: Voltage in ÂµV at lradc input when this key is pressed.
 
 Example:
index f1e2a02381a498a8f94e379870a8dcb1d2dec4ca..1c63e40659fcaada93e54ec81e8a12f62dca1f83 100644 (file)
@@ -6,7 +6,9 @@ used for what purposes, but which don't use an on-flash partition table such
 as RedBoot.
 
 The partition table should be a subnode of the mtd node and should be named
-'partitions'. Partitions are defined in subnodes of the partitions node.
+'partitions'. This node should have the following property:
+- compatible : (required) must be "fixed-partitions"
+Partitions are then defined in subnodes of the partitions node.
 
 For backwards compatibility partitions as direct subnodes of the mtd device are
 supported. This use is discouraged.
@@ -36,6 +38,7 @@ Examples:
 
 flash@0 {
        partitions {
+               compatible = "fixed-partitions";
                #address-cells = <1>;
                #size-cells = <1>;
 
@@ -53,6 +56,7 @@ flash@0 {
 
 flash@1 {
        partitions {
+               compatible = "fixed-partitions";
                #address-cells = <1>;
                #size-cells = <2>;
 
@@ -66,6 +70,7 @@ flash@1 {
 
 flash@2 {
        partitions {
+               compatible = "fixed-partitions";
                #address-cells = <2>;
                #size-cells = <2>;
 
index 9853f8e7096613e990c28cc545b39ab7f26afddc..28a4781ab6d7b9d6a1ab553ed96857f0f509e250 100644 (file)
@@ -40,18 +40,18 @@ Optional properties:
 
 Slave Properties:
 Required properties:
-- phy_id               : Specifies slave phy id
 - phy-mode             : See ethernet.txt file in the same directory
 
 Optional properties:
 - dual_emac_res_vlan   : Specifies VID to be used to segregate the ports
 - mac-address          : See ethernet.txt file in the same directory
+- phy_id               : Specifies slave phy id
 - phy-handle           : See ethernet.txt file in the same directory
 
 Slave sub-nodes:
 - fixed-link           : See fixed-link.txt file in the same directory
-                         Either the properties phy_id and phy-mode,
-                         or the sub-node fixed-link can be specified
+                         Either the property phy_id, or the sub-node
+                         fixed-link can be specified
 
 Note: "ti,hwmods" field is used to fetch the base address and irq
 resources from TI, omap hwmod data base during device registration.
index f5a8ca29aff06e84d49e3c75caf125b35c660055..aeea50c84e921fb301fc7fe9fd2cd6f295c7139c 100644 (file)
@@ -8,6 +8,11 @@ Required properties:
 - phy-mode: See ethernet.txt file in the same directory
 - clocks: a pointer to the reference clock for this device.
 
+Optional properties:
+- tx-csum-limit: maximum mtu supported by port that allow TX checksum.
+  Value is presented in bytes. If not used, by default 1600B is set for
+  "marvell,armada-370-neta" and 9800B for others.
+
 Example:
 
 ethernet@d0070000 {
@@ -15,6 +20,7 @@ ethernet@d0070000 {
        reg = <0xd0070000 0x2500>;
        interrupts = <8>;
        clocks = <&gate_clk 4>;
+       tx-csum-limit = <9800>
        status = "okay";
        phy = <&phy0>;
        phy-mode = "rgmii-id";
index 15a919522b4286e5bf8171cf86ace340f9e27faf..1783f9ef093096a0f06c1daf8ba854bba91e397d 100644 (file)
@@ -7,6 +7,16 @@ Required properties:
 - compatible : "asahi-kasei,ak4613"
 - reg : The chip select number on the I2C bus
 
+Optional properties:
+- asahi-kasei,in1-single-end   : Boolean. Indicate input / output pins are single-ended.
+- asahi-kasei,in2-single-end     rather than differential.
+- asahi-kasei,out1-single-end
+- asahi-kasei,out2-single-end
+- asahi-kasei,out3-single-end
+- asahi-kasei,out4-single-end
+- asahi-kasei,out5-single-end
+- asahi-kasei,out6-single-end
+
 Example:
 
 &i2c {
index 0018451c435148c4cd39b592e04c8e338d4ee3c9..549e701cb7a1c58620863fc0a5e5b08c313ff4ef 100644 (file)
@@ -16,6 +16,10 @@ Required properties:
        Required elements: "pclk", "gclk" and "aclk".
 - clocks
        Please refer to clock-bindings.txt.
+- assigned-clocks
+       Should be <&classd_gclk>.
+- assigned-clock-parents
+       Should be <&audio_pll_pmc>.
 
 Optional properties:
 - pinctrl-names, pinctrl-0
@@ -43,6 +47,8 @@ classd: classd@fc048000 {
                dma-names = "tx";
                clocks = <&classd_clk>, <&classd_gclk>, <&audio_pll_pmc>;
                clock-names = "pclk", "gclk", "aclk";
+               assigned-clocks = <&classd_gclk>;
+               assigned-clock-parents = <&audio_pll_pmc>;
 
                pinctrl-names = "default";
                pinctrl-0 = <&pinctrl_classd_default>;
diff --git a/Documentation/devicetree/bindings/sound/atmel-pdmic.txt b/Documentation/devicetree/bindings/sound/atmel-pdmic.txt
new file mode 100644 (file)
index 0000000..e0875f1
--- /dev/null
@@ -0,0 +1,55 @@
+* Atmel PDMIC driver under ALSA SoC architecture
+
+Required properties:
+- compatible
+       Should be "atmel,sama5d2-pdmic".
+- reg
+       Should contain PDMIC registers location and length.
+- interrupts
+       Should contain the IRQ line for the PDMIC.
+- dmas
+       One DMA specifiers as described in atmel-dma.txt and dma.txt files.
+- dma-names
+       Must be "rx".
+- clock-names
+       Required elements:
+       - "pclk"        peripheral clock
+       - "gclk"        generated clock
+- clocks
+       Must contain an entry for each required entry in clock-names.
+       Please refer to clock-bindings.txt.
+- atmel,mic-min-freq
+       The minimal frequency that the micphone supports.
+- atmel,mic-max-freq
+       The maximal frequency that the micphone supports.
+
+Optional properties:
+- pinctrl-names, pinctrl-0
+       Please refer to pinctrl-bindings.txt.
+- atmel,model
+       The user-visible name of this sound card.
+       The default value is "PDMIC".
+- atmel,mic-offset
+       The offset that should be added.
+       The range is from -32768 to 32767.
+       The default value is 0.
+
+Example:
+       pdmic@f8018000 {
+                               compatible = "atmel,sama5d2-pdmic";
+                               reg = <0xf8018000 0x124>;
+                               interrupts = <48 IRQ_TYPE_LEVEL_HIGH 7>;
+                               dmas = <&dma0
+                                       (AT91_XDMAC_DT_MEM_IF(0) | AT91_XDMAC_DT_PER_IF(1)
+                                       | AT91_XDMAC_DT_PERID(50))>;
+                               dma-names = "rx";
+                               clocks = <&pdmic_clk>, <&pdmic_gclk>;
+                               clock-names = "pclk", "gclk";
+
+                               pinctrl-names = "default";
+                               pinctrl-0 = <&pinctrl_pdmic_default>;
+                               atmel,model = "PDMIC @ sama5d2_xplained";
+                               atmel,mic-min-freq = <1000000>;
+                               atmel,mic-max-freq = <3246000>;
+                               atmel,mic-offset = <0x0>;
+       };
diff --git a/Documentation/devicetree/bindings/sound/da7218.txt b/Documentation/devicetree/bindings/sound/da7218.txt
new file mode 100644 (file)
index 0000000..5ca5a70
--- /dev/null
@@ -0,0 +1,104 @@
+Dialog Semiconductor DA7218 Audio Codec bindings
+
+DA7218 is an audio codec with HP detect feature.
+
+======
+
+Required properties:
+- compatible : Should be "dlg,da7217" or "dlg,da7218"
+- reg: Specifies the I2C slave address
+
+- VDD-supply: VDD power supply for the device
+- VDDMIC-supply: VDDMIC power supply for the device
+- VDDIO-supply: VDDIO power supply for the device
+  (See Documentation/devicetree/bindings/regulator/regulator.txt for further
+   information relating to regulators)
+
+Optional properties:
+- interrupt-parent: Specifies the phandle of the interrupt controller to which
+  the IRQs from DA7218 are delivered to.
+- interrupts: IRQ line info for DA7218 chip.
+  (See Documentation/devicetree/bindings/interrupt-controller/interrupts.txt for
+   further information relating to interrupt properties)
+- interrupt-names : Name associated with interrupt line. Should be "wakeup" if
+  interrupt is to be used to wake system, otherwise "irq" should be used.
+- wakeup-source: Flag to indicate this device can wake system (suspend/resume).
+
+- clocks : phandle and clock specifier for codec MCLK.
+- clock-names : Clock name string for 'clocks' attribute, should be "mclk".
+
+- dlg,micbias1-lvl-millivolt : Voltage (mV) for Mic Bias 1
+       [<1200>, <1600>, <1800>, <2000>, <2200>, <2400>, <2600>, <2800>, <3000>]
+- dlg,micbias2-lvl-millivolt : Voltage (mV) for Mic Bias 2
+       [<1200>, <1600>, <1800>, <2000>, <2200>, <2400>, <2600>, <2800>, <3000>]
+- dlg,mic1-amp-in-sel : Mic1 input source type
+       ["diff", "se_p", "se_n"]
+- dlg,mic2-amp-in-sel : Mic2 input source type
+       ["diff", "se_p", "se_n"]
+- dlg,dmic1-data-sel : DMIC1 channel select based on clock edge.
+       ["lrise_rfall", "lfall_rrise"]
+- dlg,dmic1-samplephase : When to sample audio from DMIC1.
+       ["on_clkedge", "between_clkedge"]
+- dlg,dmic1-clkrate-hz : DMic1 clock frequency (Hz).
+       [<1500000>, <3000000>]
+- dlg,dmic2-data-sel : DMic2 channel select based on clock edge.
+       ["lrise_rfall", "lfall_rrise"]
+- dlg,dmic2-samplephase : When to sample audio from DMic2.
+       ["on_clkedge", "between_clkedge"]
+- dlg,dmic2-clkrate-hz : DMic2 clock frequency (Hz).
+       [<1500000>, <3000000>]
+- dlg,hp-diff-single-supply : Boolean flag, use single supply for HP
+                             (DA7217 only)
+
+======
+
+Optional Child node - 'da7218_hpldet' (DA7218 only):
+
+Optional properties:
+- dlg,jack-rate-us : Time between jack detect measurements (us)
+       [<5>, <10>, <20>, <40>, <80>, <160>, <320>, <640>]
+- dlg,jack-debounce : Number of debounce measurements taken for jack detect
+       [<0>, <2>, <3>, <4>]
+- dlg,jack-threshold-pct : Threshold level for jack detection (% of VDD)
+       [<84>, <88>, <92>, <96>]
+- dlg,comp-inv : Boolean flag, invert comparator output
+- dlg,hyst : Boolean flag, enable hysteresis
+- dlg,discharge : Boolean flag, auto discharge of Mic Bias on jack removal
+
+======
+
+Example:
+
+       codec: da7218@1a {
+               compatible = "dlg,da7218";
+               reg = <0x1a>;
+               interrupt-parent = <&gpio6>;
+               interrupts = <11 IRQ_TYPE_LEVEL_HIGH>;
+               wakeup-source;
+
+               VDD-supply = <&reg_audio>;
+               VDDMIC-supply = <&reg_audio>;
+               VDDIO-supply = <&reg_audio>;
+
+               clocks = <&clks 201>;
+               clock-names = "mclk";
+
+               dlg,micbias1-lvl-millivolt = <2600>;
+               dlg,micbias2-lvl-millivolt = <2600>;
+               dlg,mic1-amp-in-sel = "diff";
+               dlg,mic2-amp-in-sel = "diff";
+
+               dlg,dmic1-data-sel = "lrise_rfall";
+               dlg,dmic1-samplephase = "on_clkedge";
+               dlg,dmic1-clkrate-hz = <3000000>;
+               dlg,dmic2-data-sel = "lrise_rfall";
+               dlg,dmic2-samplephase = "on_clkedge";
+               dlg,dmic2-clkrate-hz = <3000000>;
+
+               da7218_hpldet {
+                       dlg,jack-rate-us = <40>;
+                       dlg,jack-debounce = <2>;
+                       dlg,jack-threshold-pct = <84>;
+                       dlg,hyst;
+               };
+       };
index 1b7030911a3bfc8f13a276c00e5dc03d8ec7b5db..cf61681826b675ad984dc17f6c1dbcc2e1b6fc35 100644 (file)
@@ -28,13 +28,15 @@ Optional properties:
 - clocks : phandle and clock specifier for codec MCLK.
 - clock-names : Clock name string for 'clocks' attribute, should be "mclk".
 
-- dlg,ldo-lvl : Required internal LDO voltage (mV) level for digital engine
-       [<1050>, <1100>, <1200>, <1400>]
 - dlg,micbias-lvl : Voltage (mV) for Mic Bias
-       [<1800>, <2000>, <2200>, <2400>, <2600>]
+       [<1600>, <1800>, <2000>, <2200>, <2400>, <2600>]
 - dlg,mic-amp-in-sel : Mic input source type
        ["diff", "se_p", "se_n"]
 
+Deprecated properties:
+- dlg,ldo-lvl : Required internal LDO voltage (mV) level for digital engine
+  (LDO unavailable in production HW so property no longer required).
+
 ======
 
 Child node - 'da7219_aad':
index b93362a570be8aefeee64b5a16c01e37d7d92500..3e26a9478e570279eeaf461a7ed675c6f3f013ed 100644 (file)
@@ -25,6 +25,11 @@ Required properties:
        "mem"             Peripheral access clock to access registers.
        "ipg"             Peripheral clock to driver module.
        "asrck_<0-f>"     Clock sources for input and output clock.
+       "spba"            The spba clock is required when ASRC is placed as a
+                         bus slave of the Shared Peripheral Bus and when two
+                         or more bus masters (CPU, DMA or DSP) try to access
+                         it. This property is optional depending on the SoC
+                         design.
 
    - big-endian                : If this property is absent, the little endian mode
                          will be in use as default. Otherwise, the big endian
index d3b6b5f48010a9f12b8309f65ea7d517e0d392a8..cd3ee5d84f030f67df79de05b9561e1937dc6ce0 100644 (file)
@@ -27,6 +27,11 @@ Required properties:
                          derive HCK, SCK and FS.
        "fsys"            The system clock derived from ahb clock used to
                          derive HCK, SCK and FS.
+       "spba"            The spba clock is required when ESAI is placed as a
+                         bus slave of the Shared Peripheral Bus and when two
+                         or more bus masters (CPU, DMA or DSP) try to access
+                         it. This property is optional depending on the SoC
+                         design.
 
   - fsl,fifo-depth     : The number of elements in the transmit and receive
                          FIFOs. This number is the maximum allowed value for
index b5ee32ee370602bb9c56edf99f6d7df873aca538..4ca39ddc04172bcc4a56e41a193b7ea405ad82a7 100644 (file)
@@ -27,6 +27,11 @@ Required properties:
                          Transceiver Clock Diagram" of SoC reference manual.
                          It can also be referred to TxClk_Source bit of
                          register SPDIF_STC.
+       "spba"            The spba clock is required when SPDIF is placed as a
+                         bus slave of the Shared Peripheral Bus and when two
+                         or more bus masters (CPU, DMA or DSP) try to access
+                         it. This property is optional depending on the SoC
+                         design.
 
    - big-endian                : If this property is absent, the native endian mode
                          will be in use as default, or the big endian mode
diff --git a/Documentation/devicetree/bindings/sound/img,i2s-in.txt b/Documentation/devicetree/bindings/sound/img,i2s-in.txt
new file mode 100644 (file)
index 0000000..423265c
--- /dev/null
@@ -0,0 +1,47 @@
+Imagination Technologies I2S Input Controller
+
+Required Properties:
+
+  - compatible : Compatible list, must contain "img,i2s-in"
+
+  - #sound-dai-cells : Must be equal to 0
+
+  - reg : Offset and length of the register set for the device
+
+  - clocks : Contains an entry for each entry in clock-names
+
+  - clock-names : Must include the following entry:
+       "sys"   The system clock
+
+  - dmas: Contains an entry for each entry in dma-names.
+
+  - dma-names: Must include the following entry:
+       "rx"    Single DMA channel used by all active I2S channels
+
+  - img,i2s-channels : Number of I2S channels instantiated in the I2S in block
+
+Optional Properties:
+
+  - interrupts : Contains the I2S in interrupts. Depending on
+       the configuration, there may be no interrupts, one interrupt,
+       or an interrupt per I2S channel. For the case where there is
+       one interrupt per channel, the interrupts should be listed
+       in ascending channel order
+
+  - resets: Contains a phandle to the I2S in reset signal
+
+  - reset-names: Contains the reset signal name "rst"
+
+Example:
+
+i2s_in: i2s-in@18100800 {
+       compatible = "img,i2s-in";
+       reg = <0x18100800 0x200>;
+       interrupts = <GIC_SHARED 7 IRQ_TYPE_LEVEL_HIGH>;
+       dmas = <&mdc 30 0xffffffff 0>;
+       dma-names = "rx";
+       clocks = <&cr_periph SYS_CLK_I2S_IN>;
+       clock-names = "sys";
+       img,i2s-channels = <6>;
+       #sound-dai-cells = <0>;
+};
diff --git a/Documentation/devicetree/bindings/sound/img,i2s-out.txt b/Documentation/devicetree/bindings/sound/img,i2s-out.txt
new file mode 100644 (file)
index 0000000..0159415
--- /dev/null
@@ -0,0 +1,51 @@
+Imagination Technologies I2S Output Controller
+
+Required Properties:
+
+  - compatible : Compatible list, must contain "img,i2s-out"
+
+  - #sound-dai-cells : Must be equal to 0
+
+  - reg : Offset and length of the register set for the device
+
+  - clocks : Contains an entry for each entry in clock-names
+
+  - clock-names : Must include the following entries:
+       "sys"   The system clock
+       "ref"   The reference clock
+
+  - dmas: Contains an entry for each entry in dma-names.
+
+  - dma-names: Must include the following entry:
+       "tx"    Single DMA channel used by all active I2S channels
+
+  - img,i2s-channels : Number of I2S channels instantiated in the I2S out block
+
+  - resets: Contains a phandle to the I2S out reset signal
+
+  - reset-names: Contains the reset signal name "rst"
+
+Optional Properties:
+
+  - interrupts : Contains the I2S out interrupts. Depending on
+       the configuration, there may be no interrupts, one interrupt,
+       or an interrupt per I2S channel. For the case where there is
+       one interrupt per channel, the interrupts should be listed
+       in ascending channel order
+
+Example:
+
+i2s_out: i2s-out@18100A00 {
+       compatible = "img,i2s-out";
+       reg = <0x18100A00 0x200>;
+       interrupts = <GIC_SHARED 13 IRQ_TYPE_LEVEL_HIGH>;
+       dmas = <&mdc 23 0xffffffff 0>;
+       dma-names = "tx";
+       clocks = <&cr_periph SYS_CLK_I2S_OUT>,
+                <&clk_core CLK_I2S>;
+       clock-names = "sys", "ref";
+       img,i2s-channels = <6>;
+       resets = <&pistachio_reset PISTACHIO_RESET_I2S_OUT>;
+       reset-names = "rst";
+       #sound-dai-cells = <0>;
+};
diff --git a/Documentation/devicetree/bindings/sound/img,parallel-out.txt b/Documentation/devicetree/bindings/sound/img,parallel-out.txt
new file mode 100644 (file)
index 0000000..a3015d2
--- /dev/null
@@ -0,0 +1,44 @@
+Imagination Technologies Parallel Output Controller
+
+Required Properties:
+
+  - compatible : Compatible list, must contain "img,parallel-out".
+
+  - #sound-dai-cells : Must be equal to 0
+
+  - reg : Offset and length of the register set for the device.
+
+  - dmas: Contains an entry for each entry in dma-names.
+
+  - dma-names: Must include the following entry:
+       "tx"
+
+  - clocks : Contains an entry for each entry in clock-names.
+
+  - clock-names : Includes the following entries:
+       "sys"   The system clock
+       "ref"   The reference clock
+
+  - resets: Contains a phandle to the parallel out reset signal
+
+  - reset-names: Contains the reset signal name "rst"
+
+Optional Properties:
+
+  - interrupts : Contains the parallel out interrupt, if present
+
+Example:
+
+parallel_out: parallel-out@18100C00 {
+       compatible = "img,parallel-out";
+       reg = <0x18100C00 0x100>;
+       interrupts = <GIC_SHARED 19 IRQ_TYPE_LEVEL_HIGH>;
+       dmas = <&mdc 16 0xffffffff 0>;
+       dma-names = "tx";
+       clocks = <&cr_periph SYS_CLK_PAUD_OUT>,
+                <&clk_core CLK_AUDIO_DAC>;
+       clock-names = "sys", "ref";
+       resets = <&pistachio_reset PISTACHIO_RESET_PRL_OUT>;
+       reset-names = "rst";
+       #sound-dai-cells = <0>;
+};
diff --git a/Documentation/devicetree/bindings/sound/img,pistachio-internal-dac.txt b/Documentation/devicetree/bindings/sound/img,pistachio-internal-dac.txt
new file mode 100644 (file)
index 0000000..4cc18fc
--- /dev/null
@@ -0,0 +1,18 @@
+Pistachio internal DAC DT bindings
+
+Required properties:
+
+  - compatible: "img,pistachio-internal-dac"
+
+  - img,cr-top : Must contain a phandle to the top level control syscon
+                node which contains the internal dac control registers
+
+  - VDD-supply : Digital power supply regulator (+1.8V or +3.3V)
+
+Examples:
+
+internal_dac: internal-dac {
+       compatible = "img,pistachio-internal-dac";
+       img,cr-top = <&cr_top>;
+       VDD-supply = <&supply3v3>;
+};
diff --git a/Documentation/devicetree/bindings/sound/img,spdif-in.txt b/Documentation/devicetree/bindings/sound/img,spdif-in.txt
new file mode 100644 (file)
index 0000000..aab9a81
--- /dev/null
@@ -0,0 +1,41 @@
+Imagination Technologies SPDIF Input Controller
+
+Required Properties:
+
+  - compatible : Compatible list, must contain "img,spdif-in"
+
+  - #sound-dai-cells : Must be equal to 0
+
+  - reg : Offset and length of the register set for the device
+
+  - dmas: Contains an entry for each entry in dma-names.
+
+  - dma-names: Must include the following entry:
+       "rx"
+
+  - clocks : Contains an entry for each entry in clock-names
+
+  - clock-names : Includes the following entries:
+       "sys"   The system clock
+
+Optional Properties:
+
+  - resets: Should contain a phandle to the spdif in reset signal, if any
+
+  - reset-names: Should contain the reset signal name "rst", if a
+       reset phandle is given
+
+  - interrupts : Contains the spdif in interrupt, if present
+
+Example:
+
+spdif_in: spdif-in@18100E00 {
+       compatible = "img,spdif-in";
+       reg = <0x18100E00 0x100>;
+       interrupts = <GIC_SHARED 20 IRQ_TYPE_LEVEL_HIGH>;
+       dmas = <&mdc 15 0xffffffff 0>;
+       dma-names = "rx";
+       clocks = <&cr_periph SYS_CLK_SPDIF_IN>;
+       clock-names = "sys";
+       #sound-dai-cells = <0>;
+};
diff --git a/Documentation/devicetree/bindings/sound/img,spdif-out.txt b/Documentation/devicetree/bindings/sound/img,spdif-out.txt
new file mode 100644 (file)
index 0000000..470a519
--- /dev/null
@@ -0,0 +1,44 @@
+Imagination Technologies SPDIF Output Controller
+
+Required Properties:
+
+  - compatible : Compatible list, must contain "img,spdif-out"
+
+  - #sound-dai-cells : Must be equal to 0
+
+  - reg : Offset and length of the register set for the device
+
+  - dmas: Contains an entry for each entry in dma-names.
+
+  - dma-names: Must include the following entry:
+       "tx"
+
+  - clocks : Contains an entry for each entry in clock-names.
+
+  - clock-names : Includes the following entries:
+       "sys"   The system clock
+       "ref"   The reference clock
+
+  - resets: Contains a phandle to the spdif out reset signal
+
+  - reset-names: Contains the reset signal name "rst"
+
+Optional Properties:
+
+  - interrupts : Contains the parallel out interrupt, if present
+
+Example:
+
+spdif_out: spdif-out@18100D00 {
+       compatible = "img,spdif-out";
+       reg = <0x18100D00 0x100>;
+       interrupts = <GIC_SHARED 21 IRQ_TYPE_LEVEL_HIGH>;
+       dmas = <&mdc 14 0xffffffff 0>;
+       dma-names = "tx";
+       clocks = <&cr_periph SYS_CLK_SPDIF_OUT>,
+                <&clk_core CLK_SPDIF>;
+       clock-names = "sys", "ref";
+       resets = <&pistachio_reset PISTACHIO_RESET_SPDIF_OUT>;
+       reset-names = "rst";
+       #sound-dai-cells = <0>;
+};
diff --git a/Documentation/devicetree/bindings/sound/inno-rk3036.txt b/Documentation/devicetree/bindings/sound/inno-rk3036.txt
new file mode 100644 (file)
index 0000000..758de8e
--- /dev/null
@@ -0,0 +1,20 @@
+Inno audio codec for RK3036
+
+Inno audio codec is integrated inside RK3036 SoC.
+
+Required properties:
+- compatible : Should be "rockchip,rk3036-codec".
+- reg : The registers of codec.
+- clock-names : Should be "acodec_pclk".
+- clocks : The clock of codec.
+- rockchip,grf : The phandle of grf device node.
+
+Example:
+
+       acodec: acodec-ana@20030000 {
+               compatible = "rk3036-codec";
+               reg = <0x20030000 0x4000>;
+               rockchip,grf = <&grf>;
+               clock-names = "acodec_pclk";
+               clocks = <&cru ACLK_VCODEC>;
+       };
similarity index 88%
rename from Documentation/devicetree/bindings/sound/pcm1792a.txt
rename to Documentation/devicetree/bindings/sound/pcm179x.txt
index 970ba1ed576f24b9298dcf07754b5450cec2cc45..4ae70d3462d65e6539278f4036e3fe26dc73f0ca 100644 (file)
@@ -1,4 +1,4 @@
-Texas Instruments pcm1792a DT bindings
+Texas Instruments pcm179x DT bindings
 
 This driver supports the SPI bus.
 
index c57cbd65736cfaf4bd67c0801fcd86dca19ef106..8ee0fa91e4a067e622435d937378bee5288f6c53 100644 (file)
@@ -7,8 +7,11 @@ Required properties:
                                  "renesas,rcar_sound-gen3" if generation3
                                  Examples with soctypes are:
                                    - "renesas,rcar_sound-r8a7778" (R-Car M1A)
+                                   - "renesas,rcar_sound-r8a7779" (R-Car H1)
                                    - "renesas,rcar_sound-r8a7790" (R-Car H2)
                                    - "renesas,rcar_sound-r8a7791" (R-Car M2-W)
+                                   - "renesas,rcar_sound-r8a7793" (R-Car M2-N)
+                                   - "renesas,rcar_sound-r8a7794" (R-Car E2)
                                    - "renesas,rcar_sound-r8a7795" (R-Car H3)
 - reg                          : Should contain the register physical address.
                                  required register is
@@ -34,6 +37,8 @@ Required properties:
                                  see below for detail.
 - #sound-dai-cells             : it must be 0 if your system is using single DAI
                                  it must be 1 if your system is using multi  DAI
+
+Optional properties:
 - #clock-cells                 : it must be 0 if your system has audio_clkout
                                  it must be 1 if your system has audio_clkout0/1/2/3
 - clock-frequency              : for all audio_clkout0/1/2/3
@@ -244,3 +249,80 @@ rcar_sound: sound@ec500000 {
                };
        };
 };
+
+Example: simple sound card
+
+       rsnd_ak4643: sound {
+               compatible = "simple-audio-card";
+
+               simple-audio-card,format = "left_j";
+               simple-audio-card,bitclock-master = <&sndcodec>;
+               simple-audio-card,frame-master = <&sndcodec>;
+
+               sndcpu: simple-audio-card,cpu {
+                       sound-dai = <&rcar_sound>;
+               };
+
+               sndcodec: simple-audio-card,codec {
+                       sound-dai = <&ak4643>;
+                       clocks = <&audio_clock>;
+               };
+       };
+
+&rcar_sound {
+       pinctrl-0 = <&sound_pins &sound_clk_pins>;
+       pinctrl-names = "default";
+
+       /* Single DAI */
+       #sound-dai-cells = <0>;
+
+       status = "okay";
+
+       rcar_sound,dai {
+               dai0 {
+                       playback = <&ssi0 &src2 &dvc0>;
+                       capture  = <&ssi1 &src3 &dvc1>;
+               };
+       };
+};
+
+&ssi1 {
+       shared-pin;
+};
+
+Example: simple sound card for TDM
+
+       rsnd_tdm: sound {
+               compatible = "simple-audio-card";
+
+               simple-audio-card,format = "left_j";
+               simple-audio-card,bitclock-master = <&sndcodec>;
+               simple-audio-card,frame-master = <&sndcodec>;
+
+               sndcpu: simple-audio-card,cpu {
+                       sound-dai = <&rcar_sound>;
+                       dai-tdm-slot-num = <6>;
+               };
+
+               sndcodec: simple-audio-card,codec {
+                       sound-dai = <&xxx>;
+               };
+       };
+
+Example: simple sound card for Multi channel
+
+&rcar_sound {
+       pinctrl-0 = <&sound_pins &sound_clk_pins>;
+       pinctrl-names = "default";
+
+       /* Single DAI */
+       #sound-dai-cells = <0>;
+
+       status = "okay";
+
+       rcar_sound,dai {
+               dai0 {
+                       playback = <&ssi0 &ssi1 &ssi2 &src0 &dvc0>;
+               };
+       };
+};
index 962748a8d9194dee2101c681a80f18ed06825422..2b2caa281ce38abcb46f688318a3479efcf02cfa 100644 (file)
@@ -4,8 +4,8 @@ Renesas Sampling Rate Convert Sound Card specifies audio DAI connections of SoC
 
 Required properties:
 
-- compatible                           : "renesas,rsrc-card,<board>"
-                                         Examples with soctypes are:
+- compatible                           : "renesas,rsrc-card{,<board>}"
+                                         Examples with boards are:
                                            - "renesas,rsrc-card"
                                            - "renesas,rsrc-card,lager"
                                            - "renesas,rsrc-card,koelsch"
index 2267d249ca0ee20959b525d1d2075e9e09909d9e..b7f3a9325ebd564c9e455ced818acbe113b6182d 100644 (file)
@@ -19,6 +19,7 @@ Required properties:
 - clock-names: should contain followings:
    - "i2s_hclk": clock for I2S BUS
    - "i2s_clk" : clock for I2S controller
+- rockchip,playback-channels: max playback channels, if not set, 8 channels default.
 - rockchip,capture-channels: max capture channels, if not set, 2 channels default.
 
 Example for rk3288 I2S controller:
@@ -31,5 +32,6 @@ i2s@ff890000 {
        dma-names = "tx", "rx";
        clock-names = "i2s_hclk", "i2s_clk";
        clocks = <&cru HCLK_I2S0>, <&cru SCLK_I2S0>;
+       rockchip,playback-channels = <8>;
        rockchip,capture-channels = <2>;
 };
diff --git a/Documentation/devicetree/bindings/sound/rt5616.txt b/Documentation/devicetree/bindings/sound/rt5616.txt
new file mode 100644 (file)
index 0000000..efc48c6
--- /dev/null
@@ -0,0 +1,26 @@
+RT5616 audio CODEC
+
+This device supports I2C only.
+
+Required properties:
+
+- compatible : "realtek,rt5616".
+
+- reg : The I2C address of the device.
+
+Pins on the device (for linking into audio routes) for RT5616:
+
+  * IN1P
+  * IN2P
+  * IN2N
+  * LOUTL
+  * LOUTR
+  * HPOL
+  * HPOR
+
+Example:
+
+codec: rt5616@1b {
+       compatible = "realtek,rt5616";
+       reg = <0x1b>;
+};
diff --git a/Documentation/devicetree/bindings/sound/rt5659.txt b/Documentation/devicetree/bindings/sound/rt5659.txt
new file mode 100644 (file)
index 0000000..5f79e7f
--- /dev/null
@@ -0,0 +1,75 @@
+RT5659/RT5658 audio CODEC
+
+This device supports I2C only.
+
+Required properties:
+
+- compatible : One of "realtek,rt5659" or "realtek,rt5658".
+
+- reg : The I2C address of the device.
+
+- interrupts : The CODEC's interrupt output.
+
+Optional properties:
+
+- realtek,in1-differential
+- realtek,in3-differential
+- realtek,in4-differential
+  Boolean. Indicate MIC1/3/4 input are differential, rather than single-ended.
+
+- realtek,dmic1-data-pin
+  0: dmic1 is not used
+  1: using IN2N pin as dmic1 data pin
+  2: using GPIO5 pin as dmic1 data pin
+  3: using GPIO9 pin as dmic1 data pin
+  4: using GPIO11 pin as dmic1 data pin
+
+- realtek,dmic2-data-pin
+  0: dmic2 is not used
+  1: using IN2P pin as dmic2 data pin
+  2: using GPIO6 pin as dmic2 data pin
+  3: using GPIO10 pin as dmic2 data pin
+  4: using GPIO12 pin as dmic2 data pin
+
+- realtek,jd-src
+  0: No JD is used
+  1: using JD3 as JD source
+
+- realtek,ldo1-en-gpios : The GPIO that controls the CODEC's LDO1_EN pin.
+- realtek,reset-gpios : The GPIO that controls the CODEC's RESET pin.
+
+Pins on the device (for linking into audio routes) for RT5659/RT5658:
+
+  * DMIC L1
+  * DMIC R1
+  * DMIC L2
+  * DMIC R2
+  * IN1P
+  * IN1N
+  * IN2P
+  * IN2N
+  * IN3P
+  * IN3N
+  * IN4P
+  * IN4N
+  * HPOL
+  * HPOR
+  * SPOL
+  * SPOR
+  * LOUTL
+  * LOUTR
+  * MONOOUT
+  * PDML
+  * PDMR
+  * SPDIF
+
+Example:
+
+rt5659 {
+       compatible = "realtek,rt5659";
+       reg = <0x1b>;
+       interrupt-parent = <&gpio>;
+       interrupts = <TEGRA_GPIO(W, 3) GPIO_ACTIVE_HIGH>;
+       realtek,ldo1-en-gpios =
+               <&gpio TEGRA_GPIO(V, 3) GPIO_ACTIVE_HIGH>;
+};
index f07078997f87e0185cb3a2518893d97885ded472..1b3c13d206ffed5150ac78f0beefb159fc44eaba 100644 (file)
@@ -18,7 +18,7 @@ Required properties:
 Optional properties:
 
 - realtek,pow-ldo2-gpio : The GPIO that controls the CODEC's POW_LDO2 pin.
-- realtek,reset-gpio : The GPIO that controls the CODEC's RESET pin.
+- realtek,reset-gpio : The GPIO that controls the CODEC's RESET pin. Active low.
 
 - realtek,in1-differential
 - realtek,in2-differential
index c92966bd5488b8b8b3032b58228ba8542d9962cb..0dce690f78f543b767c939f76a2f44641530268b 100644 (file)
@@ -14,6 +14,9 @@ Required properties:
    - "apb": the parent APB clock for this controller
    - "codec": the parent module clock
 
+Optional properties:
+- allwinner,pa-gpios: gpio to enable external amplifier
+
 Example:
 codec: codec@01c22c00 {
        #sound-dai-cells = <0>;
diff --git a/Documentation/devicetree/bindings/sound/ti,pcm3168a.txt b/Documentation/devicetree/bindings/sound/ti,pcm3168a.txt
new file mode 100644 (file)
index 0000000..5d9cb84
--- /dev/null
@@ -0,0 +1,48 @@
+Texas Instruments pcm3168a DT bindings
+
+This driver supports both SPI and I2C bus access for this codec
+
+Required properties:
+
+  - compatible: "ti,pcm3168a"
+
+  - clocks : Contains an entry for each entry in clock-names
+
+  - clock-names : Includes the following entries:
+       "scki"  The system clock
+
+  - VDD1-supply : Digital power supply regulator 1 (+3.3V)
+
+  - VDD2-supply : Digital power supply regulator 2 (+3.3V)
+
+  - VCCAD1-supply : ADC power supply regulator 1 (+5V)
+
+  - VCCAD2-supply : ADC power supply regulator 2 (+5V)
+
+  - VCCDA1-supply : DAC power supply regulator 1 (+5V)
+
+  - VCCDA2-supply : DAC power supply regulator 2 (+5V)
+
+For required properties on SPI/I2C, consult SPI/I2C device tree documentation
+
+Examples:
+
+i2c0: i2c0@0 {
+
+       ...
+
+       pcm3168a: audio-codec@44 {
+               compatible = "ti,pcm3168a";
+               reg = <0x44>;
+               clocks = <&clk_core CLK_AUDIO>;
+               clock-names = "scki";
+               VDD1-supply = <&supply3v3>;
+               VDD2-supply = <&supply3v3>;
+               VCCAD1-supply = <&supply5v0>;
+               VCCAD2-supply = <&supply5v0>;
+               VCCDA1-supply = <&supply5v0>;
+               VCCDA2-supply = <&supply5v0>;
+               pinctrl-names = "default";
+               pinctrl-0 = <&dac_clk_pin>;
+       };
+};
diff --git a/Documentation/devicetree/bindings/sound/wlf,wm8974.txt b/Documentation/devicetree/bindings/sound/wlf,wm8974.txt
new file mode 100644 (file)
index 0000000..01d3a7c
--- /dev/null
@@ -0,0 +1,15 @@
+WM8974 audio CODEC
+
+This device supports both I2C and SPI (configured with pin strapping
+on the board).
+
+Required properties:
+  - compatible: "wlf,wm8974"
+  - reg: the I2C address or SPI chip select number of the device
+
+Examples:
+
+codec: wm8974@1a {
+       compatible = "wlf,wm8974";
+       reg = <0x1a>;
+};
index b38200d2583a5473ebe4c618aa09475128d31100..0dfa60d88dd3b4bb4ce2a42d2c0b3d15f4835e45 100644 (file)
@@ -1,7 +1,9 @@
 * Temperature Sensor ADC (TSADC) on rockchip SoCs
 
 Required properties:
-- compatible : "rockchip,rk3288-tsadc"
+- compatible : should be "rockchip,<name>-tsadc"
+   "rockchip,rk3288-tsadc": found on RK3288 SoCs
+   "rockchip,rk3368-tsadc": found on RK3368 SoCs
 - reg : physical base address of the controller and length of memory mapped
        region.
 - interrupts : The interrupt number to the cpu. The interrupt specifier format
index 6a4b1af724f8626c61f04bc2cb47a353f26a4826..1bba38dd263727cac57958e8f26a6ca75092c5e8 100644 (file)
@@ -32,6 +32,7 @@ Supported adapters:
   * Intel Sunrise Point-LP (PCH)
   * Intel DNV (SOC)
   * Intel Broxton (SOC)
+  * Intel Lewisburg (PCH)
    Datasheets: Publicly available at the Intel website
 
 On Intel Patsburg and later chipsets, both the normal host SMBus controller
index f8aae632f02f678000f9de7a8d507a5ea0bb9404..742f69d18fc8989ae28d9c0662d6bf334109dddd 100644 (file)
@@ -1583,9 +1583,6 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
                hwp_only
                        Only load intel_pstate on systems which support
                        hardware P state control (HWP) if available.
-               no_acpi
-                       Don't use ACPI processor performance control objects
-                       _PSS and _PPC specified limits.
 
        intremap=       [X86-64, Intel-IOMMU]
                        on      enable Interrupt Remapping (default)
index f862cf3aff3495d96f699cd666af6dbf3d18a453..42ddbd4b52a9d646a539ad154d7400c0a61c02c7 100644 (file)
@@ -181,17 +181,3 @@ For general information, go to the Intel support website at:
 If an issue is identified with the released source code on the supported
 kernel with a supported adapter, email the specific information related to the
 issue to e1000-devel@lists.sourceforge.net.
-
-
-License
-=======
-
-This software program is released under the terms of a license agreement
-between you ('Licensee') and Intel. Do not use or load this software or any
-associated materials (collectively, the 'Software') until you have carefully
-read the full terms and conditions of the file COPYING located in this software
-package. By loading or using the Software, you agree to the terms of this
-Agreement. If you do not agree with the terms of this Agreement, do not install
-or use the Software.
-
-* Other names and brands may be claimed as the property of others.
diff --git a/Documentation/sound/alsa/img,spdif-in.txt b/Documentation/sound/alsa/img,spdif-in.txt
new file mode 100644 (file)
index 0000000..8b75057
--- /dev/null
@@ -0,0 +1,49 @@
+The Imagination Technologies SPDIF Input controller contains the following
+controls:
+
+name='IEC958 Capture Mask',index=0
+
+This control returns a mask that shows which of the IEC958 status bits
+can be read using the 'IEC958 Capture Default' control.
+
+name='IEC958 Capture Default',index=0
+
+This control returns the status bits contained within the SPDIF stream that
+is being received. The 'IEC958 Capture Mask' shows which bits can be read
+from this control.
+
+name='SPDIF In Multi Frequency Acquire',index=0
+name='SPDIF In Multi Frequency Acquire',index=1
+name='SPDIF In Multi Frequency Acquire',index=2
+name='SPDIF In Multi Frequency Acquire',index=3
+
+This control is used to attempt acquisition of up to four different sample
+rates. The active rate can be obtained by reading the 'SPDIF In Lock Frequency'
+control.
+
+When the value of this control is set to {0,0,0,0}, the rate given to hw_params
+will determine the single rate the block will capture. Else, the rate given to
+hw_params will be ignored, and the block will attempt capture for each of the
+four sample rates set here.
+
+If less than four rates are required, the same rate can be specified more than
+once
+
+name='SPDIF In Lock Frequency',index=0
+
+This control returns the active capture rate, or 0 if a lock has not been
+acquired
+
+name='SPDIF In Lock TRK',index=0
+
+This control is used to modify the locking/jitter rejection characteristics
+of the block. Larger values increase the locking range, but reduce jitter
+rejection.
+
+name='SPDIF In Lock Acquire Threshold',index=0
+
+This control is used to change the threshold at which a lock is acquired.
+
+name='SPDIF In Lock Release Threshold',index=0
+
+This control is used to change the threshold at which a lock is released.
index e9caa4b288284b92a34681366a29223f691338b9..233f83464814f138c4c68f0815d2dbeace552ef6 100644 (file)
@@ -318,7 +318,7 @@ M:  Zhang Rui <rui.zhang@intel.com>
 L:     linux-acpi@vger.kernel.org
 W:     https://01.org/linux-acpi
 S:     Supported
-F:     drivers/acpi/video.c
+F:     drivers/acpi/acpi_video.c
 
 ACPI WMI DRIVER
 L:     platform-driver-x86@vger.kernel.org
@@ -1847,7 +1847,7 @@ S:        Supported
 F:     drivers/net/wireless/ath/ath6kl/
 
 WILOCITY WIL6210 WIRELESS DRIVER
-M:     Vladimir Kondratiev <qca_vkondrat@qca.qualcomm.com>
+M:     Maya Erez <qca_merez@qca.qualcomm.com>
 L:     linux-wireless@vger.kernel.org
 L:     wil6210@qca.qualcomm.com
 S:     Supported
@@ -1931,7 +1931,7 @@ S:        Supported
 F:     drivers/i2c/busses/i2c-at91.c
 
 ATMEL ISI DRIVER
-M:     Josh Wu <josh.wu@atmel.com>
+M:     Ludovic Desroches <ludovic.desroches@atmel.com>
 L:     linux-media@vger.kernel.org
 S:     Supported
 F:     drivers/media/platform/soc_camera/atmel-isi.c
@@ -1950,7 +1950,8 @@ S:        Supported
 F:     drivers/net/ethernet/cadence/
 
 ATMEL NAND DRIVER
-M:     Josh Wu <josh.wu@atmel.com>
+M:     Wenyou Yang <wenyou.yang@atmel.com>
+M:     Josh Wu <rainyfeeling@outlook.com>
 L:     linux-mtd@lists.infradead.org
 S:     Supported
 F:     drivers/mtd/nand/atmel_nand*
@@ -2449,7 +2450,9 @@ F:        drivers/firmware/broadcom/*
 
 BROADCOM STB NAND FLASH DRIVER
 M:     Brian Norris <computersforpeace@gmail.com>
+M:     Kamal Dasu <kdasu.kdev@gmail.com>
 L:     linux-mtd@lists.infradead.org
+L:     bcm-kernel-feedback-list@broadcom.com
 S:     Maintained
 F:     drivers/mtd/nand/brcmnand/
 
@@ -2546,7 +2549,7 @@ F:        arch/c6x/
 
 CACHEFILES: FS-CACHE BACKEND FOR CACHING ON MOUNTED FILESYSTEMS
 M:     David Howells <dhowells@redhat.com>
-L:     linux-cachefs@redhat.com
+L:     linux-cachefs@redhat.com (moderated for non-subscribers)
 S:     Supported
 F:     Documentation/filesystems/caching/cachefiles.txt
 F:     fs/cachefiles/
@@ -2929,10 +2932,9 @@ S:       Maintained
 F:     drivers/platform/x86/compal-laptop.c
 
 CONEXANT ACCESSRUNNER USB DRIVER
-M:     Simon Arlott <cxacru@fire.lp0.eu>
 L:     accessrunner-general@lists.sourceforge.net
 W:     http://accessrunner.sourceforge.net/
-S:     Maintained
+S:     Orphan
 F:     drivers/usb/atm/cxacru.c
 
 CONFIGFS
@@ -2973,6 +2975,7 @@ F:        kernel/cpuset.c
 CONTROL GROUP - MEMORY RESOURCE CONTROLLER (MEMCG)
 M:     Johannes Weiner <hannes@cmpxchg.org>
 M:     Michal Hocko <mhocko@kernel.org>
+M:     Vladimir Davydov <vdavydov@virtuozzo.com>
 L:     cgroups@vger.kernel.org
 L:     linux-mm@kvack.org
 S:     Maintained
@@ -4409,6 +4412,7 @@ K:        fmc_d.*register
 
 FPGA MANAGER FRAMEWORK
 M:     Alan Tull <atull@opensource.altera.com>
+R:     Moritz Fischer <moritz.fischer@ettus.com>
 S:     Maintained
 F:     drivers/fpga/
 F:     include/linux/fpga/fpga-mgr.h
@@ -4559,7 +4563,7 @@ F:        include/linux/frontswap.h
 
 FS-CACHE: LOCAL CACHING FOR NETWORK FILESYSTEMS
 M:     David Howells <dhowells@redhat.com>
-L:     linux-cachefs@redhat.com
+L:     linux-cachefs@redhat.com (moderated for non-subscribers)
 S:     Supported
 F:     Documentation/filesystems/caching/
 F:     fs/fscache/
@@ -5574,7 +5578,7 @@ 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:     Bruce Allan <bruce.w.allan@intel.com>
 R:     John Ronciak <john.ronciak@intel.com>
 R:     Mitch Williams <mitch.a.williams@intel.com>
 L:     intel-wired-lan@lists.osuosl.org
@@ -5711,13 +5715,6 @@ M:       Juanjo Ciarlante <jjciarla@raiz.uncu.edu.ar>
 S:     Maintained
 F:     net/ipv4/netfilter/ipt_MASQUERADE.c
 
-IP1000A 10/100/1000 GIGABIT ETHERNET DRIVER
-M:     Francois Romieu <romieu@fr.zoreil.com>
-M:     Sorbica Shieh <sorbica@icplus.com.tw>
-L:     netdev@vger.kernel.org
-S:     Maintained
-F:     drivers/net/ethernet/icplus/ipg.*
-
 IPATH DRIVER
 M:     Mike Marciniszyn <infinipath@intel.com>
 L:     linux-rdma@vger.kernel.org
@@ -6371,6 +6368,7 @@ F:        arch/*/include/asm/pmem.h
 LIGHTNVM PLATFORM SUPPORT
 M:     Matias Bjorling <mb@lightnvm.io>
 W:     http://github/OpenChannelSSD
+L:     linux-block@vger.kernel.org
 S:     Maintained
 F:     drivers/lightnvm/
 F:     include/linux/lightnvm.h
@@ -6923,13 +6921,21 @@ F:      drivers/scsi/megaraid.*
 F:     drivers/scsi/megaraid/
 
 MELLANOX ETHERNET DRIVER (mlx4_en)
-M:     Amir Vadai <amirv@mellanox.com>
+M:     Eugenia Emantayev <eugenia@mellanox.com>
 L:     netdev@vger.kernel.org
 S:     Supported
 W:     http://www.mellanox.com
 Q:     http://patchwork.ozlabs.org/project/netdev/list/
 F:     drivers/net/ethernet/mellanox/mlx4/en_*
 
+MELLANOX ETHERNET DRIVER (mlx5e)
+M:     Saeed Mahameed <saeedm@mellanox.com>
+L:     netdev@vger.kernel.org
+S:     Supported
+W:     http://www.mellanox.com
+Q:     http://patchwork.ozlabs.org/project/netdev/list/
+F:     drivers/net/ethernet/mellanox/mlx5/core/en_*
+
 MELLANOX ETHERNET SWITCH DRIVERS
 M:     Jiri Pirko <jiri@mellanox.com>
 M:     Ido Schimmel <idosch@mellanox.com>
@@ -7901,6 +7907,18 @@ S:       Maintained
 F:     net/openvswitch/
 F:     include/uapi/linux/openvswitch.h
 
+OPERATING PERFORMANCE POINTS (OPP)
+M:     Viresh Kumar <vireshk@kernel.org>
+M:     Nishanth Menon <nm@ti.com>
+M:     Stephen Boyd <sboyd@codeaurora.org>
+L:     linux-pm@vger.kernel.org
+S:     Maintained
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/vireshk/pm.git
+F:     drivers/base/power/opp/
+F:     include/linux/pm_opp.h
+F:     Documentation/power/opp.txt
+F:     Documentation/devicetree/bindings/opp/
+
 OPL4 DRIVER
 M:     Clemens Ladisch <clemens@ladisch.de>
 L:     alsa-devel@alsa-project.org (moderated for non-subscribers)
@@ -8269,7 +8287,7 @@ F:        include/linux/delayacct.h
 F:     kernel/delayacct.c
 
 PERFORMANCE EVENTS SUBSYSTEM
-M:     Peter Zijlstra <a.p.zijlstra@chello.nl>
+M:     Peter Zijlstra <peterz@infradead.org>
 M:     Ingo Molnar <mingo@redhat.com>
 M:     Arnaldo Carvalho de Melo <acme@kernel.org>
 L:     linux-kernel@vger.kernel.org
@@ -8362,6 +8380,14 @@ L:       linux-samsung-soc@vger.kernel.org (moderated for non-subscribers)
 S:     Maintained
 F:     drivers/pinctrl/samsung/
 
+PIN CONTROLLER - SINGLE
+M:     Tony Lindgren <tony@atomide.com>
+M:     Haojian Zhuang <haojian.zhuang@linaro.org>
+L:     linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
+L:     linux-omap@vger.kernel.org
+S:     Maintained
+F:     drivers/pinctrl/pinctrl-single.c
+
 PIN CONTROLLER - ST SPEAR
 M:     Viresh Kumar <vireshk@kernel.org>
 L:     spear-devel@list.st.com
@@ -8928,6 +8954,13 @@ F:       drivers/rpmsg/
 F:     Documentation/rpmsg.txt
 F:     include/linux/rpmsg.h
 
+RENESAS ETHERNET DRIVERS
+R:     Sergei Shtylyov <sergei.shtylyov@cogentembedded.com>
+L:     netdev@vger.kernel.org
+L:     linux-sh@vger.kernel.org
+F:     drivers/net/ethernet/renesas/
+F:     include/linux/sh_eth.h
+
 RESET CONTROLLER FRAMEWORK
 M:     Philipp Zabel <p.zabel@pengutronix.de>
 S:     Maintained
@@ -9314,7 +9347,6 @@ F:        drivers/i2c/busses/i2c-designware-*
 F:     include/linux/platform_data/i2c-designware.h
 
 SYNOPSYS DESIGNWARE MMC/SD/SDIO DRIVER
-M:     Seungwon Jeon <tgih.jun@samsung.com>
 M:     Jaehoon Chung <jh80.chung@samsung.com>
 L:     linux-mmc@vger.kernel.org
 S:     Maintained
@@ -9411,8 +9443,10 @@ F:       include/scsi/sg.h
 
 SCSI SUBSYSTEM
 M:     "James E.J. Bottomley" <JBottomley@odin.com>
-L:     linux-scsi@vger.kernel.org
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/jejb/scsi.git
+M:     "Martin K. Petersen" <martin.petersen@oracle.com>
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/mkp/scsi.git
+L:     linux-scsi@vger.kernel.org
 S:     Maintained
 F:     drivers/scsi/
 F:     include/scsi/
@@ -10887,9 +10921,9 @@ S:      Maintained
 F:     drivers/media/tuners/tua9001*
 
 TULIP NETWORK DRIVERS
-M:     Grant Grundler <grundler@parisc-linux.org>
 L:     netdev@vger.kernel.org
-S:     Maintained
+L:     linux-parisc@vger.kernel.org
+S:     Orphan
 F:     drivers/net/ethernet/dec/tulip/
 
 TUN/TAP driver
index 3a0234f50f36fb45461fe235c1a91addd4d6214b..9d94adeceab6d4343d87ad5fc08307641534301e 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -1,7 +1,7 @@
 VERSION = 4
 PATCHLEVEL = 4
 SUBLEVEL = 0
-EXTRAVERSION = -rc1
+EXTRAVERSION = -rc8
 NAME = Blurry Fish Butt
 
 # *DOCUMENTATION*
index 2c2ac3f3ff80370bd6bad9fffc9dfb8c8f6931e8..6312f607932fd2241782827cce2ec7968ea3c8b6 100644 (file)
@@ -445,6 +445,7 @@ config LINUX_LINK_BASE
          However some customers have peripherals mapped at this addr, so
          Linux needs to be scooted a bit.
          If you don't know what the above means, leave this setting alone.
+         This needs to match memory start address specified in Device Tree
 
 config HIGHMEM
        bool "High Memory Support"
index cf0cf34eeb24b14ef070735e83d25b0f7f6aecec..aeb19021099e315967ba95524e9528c48da0d159 100644 (file)
@@ -81,7 +81,7 @@ endif
 LIBGCC := $(shell $(CC) $(cflags-y) --print-libgcc-file-name)
 
 # Modules with short calls might break for calls into builtin-kernel
-KBUILD_CFLAGS_MODULE   += -mlong-calls
+KBUILD_CFLAGS_MODULE   += -mlong-calls -mno-millicode
 
 # Finally dump eveything into kernel build system
 KBUILD_CFLAGS  += $(cflags-y)
index f3db32154973718268c1998e9f16bb03d1af7e7f..44a578c10732cd1ab79558415e3c66f6825c98bd 100644 (file)
@@ -46,6 +46,7 @@
                        snps,pbl = < 32 >;
                        clocks = <&apbclk>;
                        clock-names = "stmmaceth";
+                       max-speed = <100>;
                };
 
                ehci@0x40000 {
index b0eb0e7fe21d8a66b1d0ef5267f24dd6a1f8f254..fc81879bc1f5800e5efe8eb43395eb2c5509f481 100644 (file)
@@ -17,7 +17,8 @@
 
        memory {
                device_type = "memory";
-               reg = <0x0 0x80000000 0x0 0x40000000    /* 1 GB low mem */
+               /* CONFIG_LINUX_LINK_BASE needs to match low mem start */
+               reg = <0x0 0x80000000 0x0 0x20000000    /* 512 MB low mem */
                       0x1 0x00000000 0x0 0x40000000>;  /* 1 GB highmem */
        };
 
index c92c0ef1e9d290b2db437001338cf477c1df9513..f1ac9818b751e1fab854f2c1a4440b9ca8af3e85 100644 (file)
@@ -1,4 +1,4 @@
-CONFIG_CROSS_COMPILE="arc-linux-uclibc-"
+CONFIG_CROSS_COMPILE="arc-linux-"
 CONFIG_DEFAULT_HOSTNAME="ARCLinux"
 # CONFIG_SWAP is not set
 CONFIG_SYSVIPC=y
index cfac24e0e7b6565a48c3a22f6251e8992fbb84bb..323486d6ee83419a9e50d5c53fa042f53e08ebed 100644 (file)
@@ -1,4 +1,4 @@
-CONFIG_CROSS_COMPILE="arc-linux-uclibc-"
+CONFIG_CROSS_COMPILE="arc-linux-"
 CONFIG_DEFAULT_HOSTNAME="ARCLinux"
 # CONFIG_SWAP is not set
 CONFIG_SYSVIPC=y
index 9922a118a15a3d28c99c85f1c67407142e75fb86..66191cd0447eaabc524a36ec497e7047043dc9a4 100644 (file)
@@ -1,4 +1,4 @@
-CONFIG_CROSS_COMPILE="arc-linux-uclibc-"
+CONFIG_CROSS_COMPILE="arc-linux-"
 CONFIG_DEFAULT_HOSTNAME="ARCLinux"
 # CONFIG_SWAP is not set
 CONFIG_SYSVIPC=y
index f761a7c70761862139ffeb7a2f89d2b159ffec71..f68838e8068af53eb2ebb29c83d88cb10dc0bfac 100644 (file)
@@ -1,4 +1,4 @@
-CONFIG_CROSS_COMPILE="arc-linux-uclibc-"
+CONFIG_CROSS_COMPILE="arc-linux-"
 # CONFIG_LOCALVERSION_AUTO is not set
 CONFIG_DEFAULT_HOSTNAME="ARCLinux"
 # CONFIG_SWAP is not set
index dc6f74f412837b51486634851a1e10ddc4341f10..96bd1c20fb0badeb5d3ebf41f2671f6558939c22 100644 (file)
@@ -1,4 +1,4 @@
-CONFIG_CROSS_COMPILE="arc-linux-uclibc-"
+CONFIG_CROSS_COMPILE="arc-linux-"
 # CONFIG_LOCALVERSION_AUTO is not set
 CONFIG_DEFAULT_HOSTNAME="ARCLinux"
 # CONFIG_SWAP is not set
index 3fef0a210c5654bda4e0bc085d3910d2b336a59c..fcae66683ca0bd5865924a88816a388e763604cd 100644 (file)
@@ -1,4 +1,4 @@
-CONFIG_CROSS_COMPILE="arc-linux-uclibc-"
+CONFIG_CROSS_COMPILE="arc-linux-"
 # CONFIG_LOCALVERSION_AUTO is not set
 CONFIG_DEFAULT_HOSTNAME="ARCLinux"
 # CONFIG_SWAP is not set
index 51784837daaec1e0b3fd0434b60e41b5b6e15610..b01b659168ea4a1c36ac85e0ee41c545aa697ec8 100644 (file)
@@ -1,4 +1,4 @@
-CONFIG_CROSS_COMPILE="arc-linux-uclibc-"
+CONFIG_CROSS_COMPILE="arc-linux-"
 CONFIG_DEFAULT_HOSTNAME="ARCLinux"
 # CONFIG_SWAP is not set
 CONFIG_SYSVIPC=y
index ef35ef3923ddca3a6fa84bd121b682681c861fc7..a07f20de221ba1f0b0963ca1f1d44053c6b1b89a 100644 (file)
@@ -1,4 +1,4 @@
-CONFIG_CROSS_COMPILE="arc-linux-uclibc-"
+CONFIG_CROSS_COMPILE="arc-linux-"
 # CONFIG_LOCALVERSION_AUTO is not set
 CONFIG_DEFAULT_HOSTNAME="ARCLinux"
 # CONFIG_CROSS_MEMORY_ATTACH is not set
index 634509e5e572ef02911e1a79906d54faf8523951..f36c047b33cad0c469bd2368bb3e5fa4260535e5 100644 (file)
@@ -1,4 +1,4 @@
-CONFIG_CROSS_COMPILE="arc-linux-uclibc-"
+CONFIG_CROSS_COMPILE="arc-linux-"
 # CONFIG_LOCALVERSION_AUTO is not set
 CONFIG_DEFAULT_HOSTNAME="ARCLinux"
 # CONFIG_CROSS_MEMORY_ATTACH is not set
index abf06e81c9290f6eafc441b563061e3389032922..210ef3e7233224b099bd40e85106d2d864e70987 100644 (file)
@@ -62,9 +62,7 @@ extern int ioc_exists;
 #define ARC_REG_IC_IVIC                0x10
 #define ARC_REG_IC_CTRL                0x11
 #define ARC_REG_IC_IVIL                0x19
-#if defined(CONFIG_ARC_MMU_V3) || defined(CONFIG_ARC_MMU_V4)
 #define ARC_REG_IC_PTAG                0x1E
-#endif
 #define ARC_REG_IC_PTAG_HI     0x1F
 
 /* Bit val in IC_CTRL */
index ad481c24070dd1f369fefab436160f6d60f9dc2c..258b0e5ad3329a614e59204df55d91873e969623 100644 (file)
@@ -37,6 +37,9 @@
 #define ISA_INIT_STATUS_BITS   (STATUS_IE_MASK | STATUS_AD_MASK | \
                                        (ARCV2_IRQ_DEF_PRIO << 1))
 
+/* SLEEP needs default irq priority (<=) which can interrupt the doze */
+#define ISA_SLEEP_ARG          (0x10 | ARCV2_IRQ_DEF_PRIO)
+
 #ifndef __ASSEMBLY__
 
 /*
index d8c608174617783496b8855bc6ed19de9b6f67cd..c1d36458bfb7aa665acb30a2234660034a19aecd 100644 (file)
@@ -43,6 +43,8 @@
 
 #define ISA_INIT_STATUS_BITS   STATUS_IE_MASK
 
+#define ISA_SLEEP_ARG          0x3
+
 #ifndef __ASSEMBLY__
 
 /******************************************************************
index 6ff657a904b61e700421b60423991273df93e1e1..c28e6c347b4900217ad48053c69679bb3da8b607 100644 (file)
@@ -23,7 +23,7 @@
  * @dt_compat:         Array of device tree 'compatible' strings
  *                     (XXX: although only 1st entry is looked at)
  * @init_early:                Very early callback [called from setup_arch()]
- * @init_cpu_smp:      for each CPU as it is coming up (SMP as well as UP)
+ * @init_per_cpu:      for each CPU as it is coming up (SMP as well as UP)
  *                     [(M):init_IRQ(), (o):start_kernel_secondary()]
  * @init_machine:      arch initcall level callback (e.g. populate static
  *                     platform devices or parse Devicetree)
@@ -35,7 +35,7 @@ struct machine_desc {
        const char              **dt_compat;
        void                    (*init_early)(void);
 #ifdef CONFIG_SMP
-       void                    (*init_cpu_smp)(unsigned int);
+       void                    (*init_per_cpu)(unsigned int);
 #endif
        void                    (*init_machine)(void);
        void                    (*init_late)(void);
index 133c867d15af0a627576d9faf89c0569220a6f47..991380438d6bfd6af03e6fff4748b8c5342b6a70 100644 (file)
@@ -48,7 +48,7 @@ extern int smp_ipi_irq_setup(int cpu, int irq);
  * @init_early_smp:    A SMP specific h/w block can init itself
  *                     Could be common across platforms so not covered by
  *                     mach_desc->init_early()
- * @init_irq_cpu:      Called for each core so SMP h/w block driver can do
+ * @init_per_cpu:      Called for each core so SMP h/w block driver can do
  *                     any needed setup per cpu (e.g. IPI request)
  * @cpu_kick:          For Master to kickstart a cpu (optionally at a PC)
  * @ipi_send:          To send IPI to a @cpu
@@ -57,7 +57,7 @@ extern int smp_ipi_irq_setup(int cpu, int irq);
 struct plat_smp_ops {
        const char      *info;
        void            (*init_early_smp)(void);
-       void            (*init_irq_cpu)(int cpu);
+       void            (*init_per_cpu)(int cpu);
        void            (*cpu_kick)(int cpu, unsigned long pc);
        void            (*ipi_send)(int cpu);
        void            (*ipi_clear)(int irq);
index 7ca628b6ee2aa6d1e02f6ad01363990439ec10b7..c11a25bb8158dee7f60a5f00ca8ec0addaf54b56 100644 (file)
@@ -112,7 +112,6 @@ struct unwind_frame_info {
 
 extern int arc_unwind(struct unwind_frame_info *frame);
 extern void arc_unwind_init(void);
-extern void arc_unwind_setup(void);
 extern void *unwind_add_table(struct module *module, const void *table_start,
                              unsigned long table_size);
 extern void unwind_remove_table(void *handle, int init_only);
@@ -152,9 +151,6 @@ static inline void arc_unwind_init(void)
 {
 }
 
-static inline void arc_unwind_setup(void)
-{
-}
 #define unwind_add_table(a, b, c)
 #define unwind_remove_table(a, b)
 
index c14a5bea0c76792ead17b42e1f548e38960cc194..5d446df2c41353a15edfc5a5f7b05abd24b16df3 100644 (file)
@@ -58,8 +58,6 @@ __switch_to(struct task_struct *prev_task, struct task_struct *next_task)
                "st      sp, [r24]       \n\t"
 #endif
 
-               "sync   \n\t"
-
                /*
                 * setup _current_task with incoming tsk.
                 * optionally, set r25 to that as well
index e248594097e7d69c66b2f46044dbfe4782008bd0..e6890b1f8650647774b48678c88e805f6b16de3a 100644 (file)
@@ -44,9 +44,6 @@ __switch_to:
        * don't need to do anything special to return it
        */
 
-       /* hardware memory barrier */
-       sync
-
        /*
         * switch to new task, contained in r1
         * Temp reg r3 is required to get the ptr to store val
index 26c15682747960d3b5b1c412f76dff3c2ebc7780..0394f9f61b466dea018af3ec371c65a8dbc17acb 100644 (file)
@@ -106,10 +106,21 @@ static struct irq_chip arcv2_irq_chip = {
 static int arcv2_irq_map(struct irq_domain *d, unsigned int irq,
                         irq_hw_number_t hw)
 {
-       if (irq == TIMER0_IRQ || irq == IPI_IRQ)
+       /*
+        * core intc IRQs [16, 23]:
+        * Statically assigned always private-per-core (Timers, WDT, IPI, PCT)
+        */
+       if (hw < 24) {
+               /*
+                * A subsequent request_percpu_irq() fails if percpu_devid is
+                * not set. That in turns sets NOAUTOEN, meaning each core needs
+                * to call enable_percpu_irq()
+                */
+               irq_set_percpu_devid(irq);
                irq_set_chip_and_handler(irq, &arcv2_irq_chip, handle_percpu_irq);
-       else
+       } else {
                irq_set_chip_and_handler(irq, &arcv2_irq_chip, handle_level_irq);
+       }
 
        return 0;
 }
index 2ee226546c6a821f739a079326ed92ad52fe16b8..ba17f85285cfe85c53ba6c93db08d620c7109fb9 100644 (file)
@@ -29,11 +29,11 @@ void __init init_IRQ(void)
 
 #ifdef CONFIG_SMP
        /* a SMP H/w block could do IPI IRQ request here */
-       if (plat_smp_ops.init_irq_cpu)
-               plat_smp_ops.init_irq_cpu(smp_processor_id());
+       if (plat_smp_ops.init_per_cpu)
+               plat_smp_ops.init_per_cpu(smp_processor_id());
 
-       if (machine_desc->init_cpu_smp)
-               machine_desc->init_cpu_smp(smp_processor_id());
+       if (machine_desc->init_per_cpu)
+               machine_desc->init_per_cpu(smp_processor_id());
 #endif
 }
 
@@ -51,6 +51,18 @@ void arch_do_IRQ(unsigned int irq, struct pt_regs *regs)
        set_irq_regs(old_regs);
 }
 
+/*
+ * API called for requesting percpu interrupts - called by each CPU
+ *  - For boot CPU, actually request the IRQ with genirq core + enables
+ *  - For subsequent callers only enable called locally
+ *
+ * Relies on being called by boot cpu first (i.e. request called ahead) of
+ * any enable as expected by genirq. Hence Suitable only for TIMER, IPI
+ * which are guaranteed to be setup on boot core first.
+ * Late probed peripherals such as perf can't use this as there no guarantee
+ * of being called on boot CPU first.
+ */
+
 void arc_request_percpu_irq(int irq, int cpu,
                             irqreturn_t (*isr)(int irq, void *dev),
                             const char *irq_nm,
@@ -60,14 +72,17 @@ void arc_request_percpu_irq(int irq, int cpu,
        if (!cpu) {
                int rc;
 
+#ifdef CONFIG_ISA_ARCOMPACT
                /*
-                * These 2 calls are essential to making percpu IRQ APIs work
-                * Ideally these details could be hidden in irq chip map function
-                * but the issue is IPIs IRQs being static (non-DT) and platform
-                * specific, so we can't identify them there.
+                * A subsequent request_percpu_irq() fails if percpu_devid is
+                * not set. That in turns sets NOAUTOEN, meaning each core needs
+                * to call enable_percpu_irq()
+                *
+                * For ARCv2, this is done in irq map function since we know
+                * which irqs are strictly per cpu
                 */
                irq_set_percpu_devid(irq);
-               irq_modify_status(irq, IRQ_NOAUTOEN, 0);  /* @irq, @clr, @set */
+#endif
 
                rc = request_percpu_irq(irq, isr, irq_nm, percpu_dev);
                if (rc)
index 74a9b074ac3e4e64d97ef8e069f73a9104531682..bd237acdf4f2f9601efbf4c25c45067ddd2b69d9 100644 (file)
@@ -132,7 +132,7 @@ static void mcip_probe_n_setup(void)
 struct plat_smp_ops plat_smp_ops = {
        .info           = smp_cpuinfo_buf,
        .init_early_smp = mcip_probe_n_setup,
-       .init_irq_cpu   = mcip_setup_per_cpu,
+       .init_per_cpu   = mcip_setup_per_cpu,
        .ipi_send       = mcip_ipi_send,
        .ipi_clear      = mcip_ipi_clear,
 };
index 0c08bb1ce15aab114c344609879eaa86bfa59a9d..8b134cfe5e1f11023b559639497f7e1a35d2ee79 100644 (file)
@@ -428,12 +428,11 @@ static irqreturn_t arc_pmu_intr(int irq, void *dev)
 
 #endif /* CONFIG_ISA_ARCV2 */
 
-void arc_cpu_pmu_irq_init(void)
+static void arc_cpu_pmu_irq_init(void *data)
 {
-       struct arc_pmu_cpu *pmu_cpu = this_cpu_ptr(&arc_pmu_cpu);
+       int irq = *(int *)data;
 
-       arc_request_percpu_irq(arc_pmu->irq, smp_processor_id(), arc_pmu_intr,
-                              "ARC perf counters", pmu_cpu);
+       enable_percpu_irq(irq, IRQ_TYPE_NONE);
 
        /* Clear all pending interrupt flags */
        write_aux_reg(ARC_REG_PCT_INT_ACT, 0xffffffff);
@@ -515,7 +514,6 @@ static int arc_pmu_device_probe(struct platform_device *pdev)
 
        if (has_interrupts) {
                int irq = platform_get_irq(pdev, 0);
-               unsigned long flags;
 
                if (irq < 0) {
                        pr_err("Cannot get IRQ number for the platform\n");
@@ -524,24 +522,12 @@ static int arc_pmu_device_probe(struct platform_device *pdev)
 
                arc_pmu->irq = irq;
 
-               /*
-                * arc_cpu_pmu_irq_init() needs to be called on all cores for
-                * their respective local PMU.
-                * However we use opencoded on_each_cpu() to ensure it is called
-                * on core0 first, so that arc_request_percpu_irq() sets up
-                * AUTOEN etc. Otherwise enable_percpu_irq() fails to enable
-                * perf IRQ on non master cores.
-                * see arc_request_percpu_irq()
-                */
-               preempt_disable();
-               local_irq_save(flags);
-               arc_cpu_pmu_irq_init();
-               local_irq_restore(flags);
-               smp_call_function((smp_call_func_t)arc_cpu_pmu_irq_init, 0, 1);
-               preempt_enable();
-
-               /* Clean all pending interrupt flags */
-               write_aux_reg(ARC_REG_PCT_INT_ACT, 0xffffffff);
+               /* intc map function ensures irq_set_percpu_devid() called */
+               request_percpu_irq(irq, arc_pmu_intr, "ARC perf counters",
+                                  this_cpu_ptr(&arc_pmu_cpu));
+
+               on_each_cpu(arc_cpu_pmu_irq_init, &irq, 1);
+
        } else
                arc_pmu->pmu.capabilities |= PERF_PMU_CAP_NO_INTERRUPT;
 
index 91d5a0f1f3f79cdd454e99e7781b2e3741caae76..a3f750e76b683dd25a45584b71014532214b20ac 100644 (file)
@@ -44,11 +44,10 @@ SYSCALL_DEFINE0(arc_gettls)
 void arch_cpu_idle(void)
 {
        /* sleep, but enable all interrupts before committing */
-       if (is_isa_arcompact()) {
-               __asm__("sleep 0x3");
-       } else {
-               __asm__("sleep 0x10");
-       }
+       __asm__ __volatile__(
+               "sleep %0       \n"
+               :
+               :"I"(ISA_SLEEP_ARG)); /* can't be "r" has to be embedded const */
 }
 
 asmlinkage void ret_from_fork(void);
index c33e77c0ad3e9eb60367b6c2510c4e35c60d3b52..e1b87444ea9a0740b9651ad6b68fd39f701121a0 100644 (file)
@@ -429,7 +429,6 @@ void __init setup_arch(char **cmdline_p)
 #endif
 
        arc_unwind_init();
-       arc_unwind_setup();
 }
 
 static int __init customize_machine(void)
index 580587805fa302d0d28f7adc89434b920b3be651..ef6e9e15b82abf72d946ab45c3e20096854605c5 100644 (file)
@@ -132,11 +132,11 @@ void start_kernel_secondary(void)
        pr_info("## CPU%u LIVE ##: Executing Code...\n", cpu);
 
        /* Some SMP H/w setup - for each cpu */
-       if (plat_smp_ops.init_irq_cpu)
-               plat_smp_ops.init_irq_cpu(cpu);
+       if (plat_smp_ops.init_per_cpu)
+               plat_smp_ops.init_per_cpu(cpu);
 
-       if (machine_desc->init_cpu_smp)
-               machine_desc->init_cpu_smp(cpu);
+       if (machine_desc->init_per_cpu)
+               machine_desc->init_per_cpu(cpu);
 
        arc_local_timer_setup();
 
index 93c6ea52b6719e4e238d6076fda6c3b981ac48fe..5eb707640e9c48c9939c3fcfd0022f8cfc897684 100644 (file)
@@ -170,6 +170,23 @@ static struct unwind_table *find_table(unsigned long pc)
 
 static unsigned long read_pointer(const u8 **pLoc,
                                  const void *end, signed ptrType);
+static void init_unwind_hdr(struct unwind_table *table,
+                           void *(*alloc) (unsigned long));
+
+/*
+ * wrappers for header alloc (vs. calling one vs. other at call site)
+ * to elide section mismatches warnings
+ */
+static void *__init unw_hdr_alloc_early(unsigned long sz)
+{
+       return __alloc_bootmem_nopanic(sz, sizeof(unsigned int),
+                                      MAX_DMA_ADDRESS);
+}
+
+static void *unw_hdr_alloc(unsigned long sz)
+{
+       return kmalloc(sz, GFP_KERNEL);
+}
 
 static void init_unwind_table(struct unwind_table *table, const char *name,
                              const void *core_start, unsigned long core_size,
@@ -209,6 +226,8 @@ void __init arc_unwind_init(void)
                          __start_unwind, __end_unwind - __start_unwind,
                          NULL, 0);
          /*__start_unwind_hdr, __end_unwind_hdr - __start_unwind_hdr);*/
+
+       init_unwind_hdr(&root_table, unw_hdr_alloc_early);
 }
 
 static const u32 bad_cie, not_fde;
@@ -241,8 +260,8 @@ static void swap_eh_frame_hdr_table_entries(void *p1, void *p2, int size)
        e2->fde = v;
 }
 
-static void __init setup_unwind_table(struct unwind_table *table,
-                                     void *(*alloc) (unsigned long))
+static void init_unwind_hdr(struct unwind_table *table,
+                           void *(*alloc) (unsigned long))
 {
        const u8 *ptr;
        unsigned long tableSize = table->size, hdrSize;
@@ -277,10 +296,10 @@ static void __init setup_unwind_table(struct unwind_table *table,
                if (cie == &not_fde)
                        continue;
                if (cie == NULL || cie == &bad_cie)
-                       return;
+                       goto ret_err;
                ptrType = fde_pointer_type(cie);
                if (ptrType < 0)
-                       return;
+                       goto ret_err;
 
                ptr = (const u8 *)(fde + 2);
                if (!read_pointer(&ptr, (const u8 *)(fde + 1) + *fde,
@@ -296,13 +315,15 @@ static void __init setup_unwind_table(struct unwind_table *table,
        }
 
        if (tableSize || !n)
-               return;
+               goto ret_err;
 
        hdrSize = 4 + sizeof(unsigned long) + sizeof(unsigned int)
            + 2 * n * sizeof(unsigned long);
+
        header = alloc(hdrSize);
        if (!header)
-               return;
+               goto ret_err;
+
        header->version = 1;
        header->eh_frame_ptr_enc = DW_EH_PE_abs | DW_EH_PE_native;
        header->fde_count_enc = DW_EH_PE_abs | DW_EH_PE_data4;
@@ -340,18 +361,10 @@ static void __init setup_unwind_table(struct unwind_table *table,
        table->hdrsz = hdrSize;
        smp_wmb();
        table->header = (const void *)header;
-}
-
-static void *__init balloc(unsigned long sz)
-{
-       return __alloc_bootmem_nopanic(sz,
-                                      sizeof(unsigned int),
-                                      __pa(MAX_DMA_ADDRESS));
-}
+       return;
 
-void __init arc_unwind_setup(void)
-{
-       setup_unwind_table(&root_table, balloc);
+ret_err:
+       panic("Attention !!! Dwarf FDE parsing errors\n");;
 }
 
 #ifdef CONFIG_MODULES
@@ -377,6 +390,8 @@ void *unwind_add_table(struct module *module, const void *table_start,
                          table_start, table_size,
                          NULL, 0);
 
+       init_unwind_hdr(table, unw_hdr_alloc);
+
 #ifdef UNWIND_DEBUG
        unw_debug("Table added for [%s] %lx %lx\n",
                module->name, table->core.pc, table->core.range);
@@ -439,6 +454,7 @@ void unwind_remove_table(void *handle, int init_only)
        info.init_only = init_only;
 
        unlink_table(&info); /* XXX: SMP */
+       kfree(table->header);
        kfree(table);
 }
 
@@ -588,9 +604,6 @@ static signed fde_pointer_type(const u32 *cie)
        const u8 *ptr = (const u8 *)(cie + 2);
        unsigned version = *ptr;
 
-       if (version != 1)
-               return -1;      /* unsupported */
-
        if (*++ptr) {
                const char *aug;
                const u8 *end = (const u8 *)(cie + 1) + *cie;
@@ -986,42 +999,13 @@ int arc_unwind(struct unwind_frame_info *frame)
                                                            (const u8 *)(fde +
                                                                         1) +
                                                            *fde, ptrType);
-                               if (pc >= endLoc)
+                               if (pc >= endLoc) {
                                        fde = NULL;
-                       } else
-                               fde = NULL;
-               }
-               if (fde == NULL) {
-                       for (fde = table->address, tableSize = table->size;
-                            cie = NULL, tableSize > sizeof(*fde)
-                            && tableSize - sizeof(*fde) >= *fde;
-                            tableSize -= sizeof(*fde) + *fde,
-                            fde += 1 + *fde / sizeof(*fde)) {
-                               cie = cie_for_fde(fde, table);
-                               if (cie == &bad_cie) {
                                        cie = NULL;
-                                       break;
                                }
-                               if (cie == NULL
-                                   || cie == &not_fde
-                                   || (ptrType = fde_pointer_type(cie)) < 0)
-                                       continue;
-                               ptr = (const u8 *)(fde + 2);
-                               startLoc = read_pointer(&ptr,
-                                                       (const u8 *)(fde + 1) +
-                                                       *fde, ptrType);
-                               if (!startLoc)
-                                       continue;
-                               if (!(ptrType & DW_EH_PE_indirect))
-                                       ptrType &=
-                                           DW_EH_PE_FORM | DW_EH_PE_signed;
-                               endLoc =
-                                   startLoc + read_pointer(&ptr,
-                                                           (const u8 *)(fde +
-                                                                        1) +
-                                                           *fde, ptrType);
-                               if (pc >= startLoc && pc < endLoc)
-                                       break;
+                       } else {
+                               fde = NULL;
+                               cie = NULL;
                        }
                }
        }
@@ -1031,9 +1015,7 @@ int arc_unwind(struct unwind_frame_info *frame)
                ptr = (const u8 *)(cie + 2);
                end = (const u8 *)(cie + 1) + *cie;
                frame->call_frame = 1;
-               if ((state.version = *ptr) != 1)
-                       cie = NULL;     /* unsupported version */
-               else if (*++ptr) {
+               if (*++ptr) {
                        /* check if augmentation size is first (thus present) */
                        if (*ptr == 'z') {
                                while (++ptr < end && *ptr) {
index 065ee6bfa82a2463ee60c790f08c5b60382715f3..92dd92cad7f92db32f9ecc1b73992e1ea0a5f74d 100644 (file)
@@ -111,7 +111,7 @@ void __kunmap_atomic(void *kv)
 }
 EXPORT_SYMBOL(__kunmap_atomic);
 
-noinline pte_t *alloc_kmap_pgtable(unsigned long kvaddr)
+static noinline pte_t * __init alloc_kmap_pgtable(unsigned long kvaddr)
 {
        pgd_t *pgd_k;
        pud_t *pud_k;
@@ -127,7 +127,7 @@ noinline pte_t *alloc_kmap_pgtable(unsigned long kvaddr)
        return pte_k;
 }
 
-void kmap_init(void)
+void __init kmap_init(void)
 {
        /* Due to recursive include hell, we can't do this in processor.h */
        BUILD_BUG_ON(PAGE_OFFSET < (VMALLOC_END + FIXMAP_SIZE + PKMAP_SIZE));
index a9305b5a2cd4ba091f7ae18914f6ef5e64d5236c..7d2c4fbf4f22eb1402bc666c077c652c40f38361 100644 (file)
@@ -51,7 +51,9 @@ void __init early_init_dt_add_memory_arch(u64 base, u64 size)
        int in_use = 0;
 
        if (!low_mem_sz) {
-               BUG_ON(base != low_mem_start);
+               if (base != low_mem_start)
+                       panic("CONFIG_LINUX_LINK_BASE != DT memory { }");
+
                low_mem_sz = size;
                in_use = 1;
        } else {
index 0ee7398468476f57b301bde2fa7c7e13735bb3fb..daf2bf52b984c6781dbb6831e22f013b04e58d0d 100644 (file)
@@ -619,10 +619,10 @@ void update_mmu_cache(struct vm_area_struct *vma, unsigned long vaddr_unaligned,
 
                int dirty = !test_and_set_bit(PG_dc_clean, &page->flags);
                if (dirty) {
-                       /* wback + inv dcache lines */
+                       /* wback + inv dcache lines (K-mapping) */
                        __flush_dcache_page(paddr, paddr);
 
-                       /* invalidate any existing icache lines */
+                       /* invalidate any existing icache lines (U-mapping) */
                        if (vma->vm_flags & VM_EXEC)
                                __inv_icache_page(paddr, vaddr);
                }
index 0365cbbc917989853d87b8a84c8409ae268d6e33..34e1569a11ee322a0a020bdfe0c9b801b6b58c12 100644 (file)
@@ -76,6 +76,8 @@ config ARM
        select IRQ_FORCED_THREADING
        select MODULES_USE_ELF_REL
        select NO_BOOTMEM
+       select OF_EARLY_FLATTREE if OF
+       select OF_RESERVED_MEM if OF
        select OLD_SIGACTION
        select OLD_SIGSUSPEND3
        select PERF_USE_VMALLOC
@@ -1822,8 +1824,6 @@ config USE_OF
        bool "Flattened Device Tree support"
        select IRQ_DOMAIN
        select OF
-       select OF_EARLY_FLATTREE
-       select OF_RESERVED_MEM
        help
          Include support for flattened device tree machine descriptions.
 
index d83ff9c9701e36d5d837c87ce292d89c421c4a70..de8791a4d1311883577f51e243769a3c6906a61a 100644 (file)
@@ -74,7 +74,7 @@
                reg = <0x48240200 0x100>;
                interrupts = <GIC_PPI 11 IRQ_TYPE_LEVEL_HIGH>;
                interrupt-parent = <&gic>;
-               clocks = <&dpll_mpu_m2_ck>;
+               clocks = <&mpu_periphclk>;
        };
 
        local_timer: timer@48240600 {
@@ -82,7 +82,7 @@
                reg = <0x48240600 0x100>;
                interrupts = <GIC_PPI 13 IRQ_TYPE_LEVEL_HIGH>;
                interrupt-parent = <&gic>;
-               clocks = <&dpll_mpu_m2_ck>;
+               clocks = <&mpu_periphclk>;
        };
 
        l2-cache-controller@48242000 {
index cc88728d751de587bcb86abbe179921c493779e9..a38af2bfbfcfbd51f223409e48231d04e73cd7e5 100644 (file)
                ti,invert-autoidle-bit;
        };
 
+       mpu_periphclk: mpu_periphclk {
+               #clock-cells = <0>;
+               compatible = "fixed-factor-clock";
+               clocks = <&dpll_mpu_m2_ck>;
+               clock-mult = <1>;
+               clock-div = <2>;
+       };
+
        dpll_ddr_ck: dpll_ddr_ck {
                #clock-cells = <0>;
                compatible = "ti,am3-dpll-clock";
index d9ba6b879fc1b25e25f8d006c8b57ab722310c7d..00352e761b8c036ce99dbe428ff0ecd7d4d60929 100644 (file)
                reg = <0x6f>;
                interrupts-extended = <&crossbar_mpu GIC_SPI 2 IRQ_TYPE_EDGE_RISING>,
                                      <&dra7_pmx_core 0x424>;
+               interrupt-names = "irq", "wakeup";
 
                pinctrl-names = "default";
                pinctrl-0 = <&mcp79410_pins_default>;
index 4e0ad3b827962831fe7d3e0d5a325d33b420381f..0962f2fa3f6e74d3f253593720689cf934dd56b0 100644 (file)
                        label = "keyswitch_in";
                        gpios = <&pioB 1 GPIO_ACTIVE_HIGH>;
                        linux,code = <28>;
-                       gpio-key,wakeup;
+                       wakeup-source;
                };
 
                error_in {
                        label = "error_in";
                        gpios = <&pioB 2 GPIO_ACTIVE_HIGH>;
                        linux,code = <29>;
-                       gpio-key,wakeup;
+                       wakeup-source;
                };
 
                btn {
                        label = "btn";
                        gpios = <&pioC 23 GPIO_ACTIVE_HIGH>;
                        linux,code = <31>;
-                       gpio-key,wakeup;
+                       wakeup-source;
                };
        };
 };
index c6a0e9d7f1a9bd0409b31bb4272bfbcb68f3b093..e8b7f67267723241730c8279902b82b8340d8118 100644 (file)
                                reg = <0x70000 0x4000>;
                                interrupts-extended = <&mpic 8>;
                                clocks = <&gateclk 4>;
+                               tx-csum-limit = <9800>;
                                status = "disabled";
                        };
 
index f89598af4c2b1ef24b1812b15fca28de2c5b4382..6bf873e7d96c226ac532658c62af2ca1e869046a 100644 (file)
                        label = "Button";
                        gpios = <&pioC 4 GPIO_ACTIVE_LOW>;
                        linux,code = <0x103>;
-                       gpio-key,wakeup;
+                       wakeup-source;
                };
        };
 };
index bf18ece0c02708c4d7b99ac543e2bc9045daf63b..229e989eb60df3305fb6a609e44e919a3696b143 100644 (file)
        };
 
        clocks {
-               #address-cells = <1>;
-               #size-cells = <1>;
-               ranges;
-
-               main_clock: clock@0 {
-                       compatible = "atmel,osc", "fixed-clock";
-                       clock-frequency = <18432000>;
-               };
-
                main_xtal {
                        clock-frequency = <18432000>;
                };
                        label = "PB_RST";
                        gpios = <&pioB 30 GPIO_ACTIVE_HIGH>;
                        linux,code = <0x100>;
-                       gpio-key,wakeup;
+                       wakeup-source;
                };
 
                user {
                        label = "PB_USER";
                        gpios = <&pioB 31 GPIO_ACTIVE_HIGH>;
                        linux,code = <0x101>;
-                       gpio-key,wakeup;
+                       wakeup-source;
                };
        };
 
index f0b1563cb3f164907c63a3ea3d94390a0cd863f9..50a14568f094a64cd5368851e2c39bd250e0cebe 100644 (file)
                        label = "PB_PROG";
                        gpios = <&pioE 27 GPIO_ACTIVE_LOW>;
                        linux,code = <0x102>;
-                       gpio-key,wakeup;
+                       wakeup-source;
                };
 
                reset {
                        label = "PB_RST";
                        gpios = <&pioE 29 GPIO_ACTIVE_LOW>;
                        linux,code = <0x100>;
-                       gpio-key,wakeup;
+                       wakeup-source;
                };
 
                user {
                        label = "PB_USER";
                        gpios = <&pioE 31 GPIO_ACTIVE_HIGH>;
                        linux,code = <0x101>;
-                       gpio-key,wakeup;
+                       wakeup-source;
                };
        };
 
index 9f72b49326344925b55d600a1a5c30173c5f7d48..9682d105d4d8317a4733412fbe4cde6241158e74 100644 (file)
                        label = "PB_PROG";
                        gpios = <&pioC 17 GPIO_ACTIVE_LOW>;
                        linux,code = <0x102>;
-                       gpio-key,wakeup;
+                       wakeup-source;
                };
 
                reset {
                        label = "PB_RST";
                        gpios = <&pioC 16 GPIO_ACTIVE_LOW>;
                        linux,code = <0x100>;
-                       gpio-key,wakeup;
+                       wakeup-source;
                };
        };
 
index a9aef53ab764202df553a058b73cd77a84c55dff..4f2eebf4a5603a5de81043fdefca99d13400c4cf 100644 (file)
                        label = "user_pb";
                        gpios = <&pioB 10 GPIO_ACTIVE_LOW>;
                        linux,code = <28>;
-                       gpio-key,wakeup;
+                       wakeup-source;
                };
        };
 
index e07c2b206beba18c8a139574aa8bc83f74c23545..e74df327cdd3b8d5776cb5d6deb269042f463bdb 100644 (file)
@@ -45,6 +45,7 @@
 /dts-v1/;
 #include "sama5d2.dtsi"
 #include "sama5d2-pinfunc.h"
+#include <dt-bindings/mfd/atmel-flexcom.h>
 
 / {
        model = "Atmel SAMA5D2 Xplained";
        };
 
        clocks {
-               #address-cells = <1>;
-               #size-cells = <1>;
-               ranges;
-
-               main_clock: clock@0 {
-                       compatible = "atmel,osc", "fixed-clock";
-                       clock-frequency = <12000000>;
-               };
-
                slow_xtal {
                        clock-frequency = <32768>;
                };
                        status = "okay";
                };
 
+               sdmmc0: sdio-host@a0000000 {
+                       bus-width = <8>;
+                       pinctrl-names = "default";
+                       pinctrl-0 = <&pinctrl_sdmmc0_default>;
+                       non-removable;
+                       mmc-ddr-1_8v;
+                       status = "okay";
+               };
+
+               sdmmc1: sdio-host@b0000000 {
+                       bus-width = <4>;
+                       pinctrl-names = "default";
+                       pinctrl-0 = <&pinctrl_sdmmc1_default>;
+                       status = "okay"; /* conflict with qspi0 */
+               };
+
                apb {
                        spi0: spi@f8000000 {
                                pinctrl-names = "default";
                                                        regulator-name = "VDD_SDHC_1V8";
                                                        regulator-min-microvolt = <1800000>;
                                                        regulator-max-microvolt = <1800000>;
+                                                       regulator-always-on;
                                                };
                                        };
                                };
                        };
 
+                       flx0: flexcom@f8034000 {
+                               atmel,flexcom-mode = <ATMEL_FLEXCOM_MODE_USART>;
+                               status = "disabled"; /* conflict with ISC_D2 & ISC_D3 data pins */
+
+                               uart5: serial@200 {
+                                       compatible = "atmel,at91sam9260-usart";
+                                       reg = <0x200 0x200>;
+                                       interrupts = <19 IRQ_TYPE_LEVEL_HIGH 7>;
+                                       clocks = <&flx0_clk>;
+                                       clock-names = "usart";
+                                       pinctrl-names = "default";
+                                       pinctrl-0 = <&pinctrl_flx0_default>;
+                                       atmel,fifo-size = <32>;
+                                       status = "okay";
+                               };
+                       };
+
                        uart3: serial@fc008000 {
                                pinctrl-names = "default";
                                pinctrl-0 = <&pinctrl_uart3_default>;
                                status = "okay";
                        };
 
+                       flx4: flexcom@fc018000 {
+                               atmel,flexcom-mode = <ATMEL_FLEXCOM_MODE_TWI>;
+                               status = "okay";
+
+                               i2c2: i2c@600 {
+                                       compatible = "atmel,sama5d2-i2c";
+                                       reg = <0x600 0x200>;
+                                       interrupts = <23 IRQ_TYPE_LEVEL_HIGH 7>;
+                                       dmas = <0>, <0>;
+                                       dma-names = "tx", "rx";
+                                       #address-cells = <1>;
+                                       #size-cells = <0>;
+                                       clocks = <&flx4_clk>;
+                                       pinctrl-names = "default";
+                                       pinctrl-0 = <&pinctrl_flx4_default>;
+                                       atmel,fifo-size = <16>;
+                                       status = "okay";
+                               };
+                       };
+
                        i2c1: i2c@fc028000 {
                                dmas = <0>, <0>;
                                pinctrl-names = "default";
                        };
 
                        pinctrl@fc038000 {
+                               pinctrl_flx0_default: flx0_default {
+                                       pinmux = <PIN_PB28__FLEXCOM0_IO0>,
+                                                <PIN_PB29__FLEXCOM0_IO1>;
+                                       bias-disable;
+                               };
+
+                               pinctrl_flx4_default: flx4_default {
+                                       pinmux = <PIN_PD12__FLEXCOM4_IO0>,
+                                                <PIN_PD13__FLEXCOM4_IO1>;
+                                       bias-disable;
+                               };
+
                                pinctrl_i2c0_default: i2c0_default {
                                        pinmux = <PIN_PD21__TWD0>,
                                                 <PIN_PD22__TWCK0>;
                                        bias-disable;
                                };
 
+                               pinctrl_sdmmc0_default: sdmmc0_default {
+                                       cmd_data {
+                                               pinmux = <PIN_PA1__SDMMC0_CMD>,
+                                                        <PIN_PA2__SDMMC0_DAT0>,
+                                                        <PIN_PA3__SDMMC0_DAT1>,
+                                                        <PIN_PA4__SDMMC0_DAT2>,
+                                                        <PIN_PA5__SDMMC0_DAT3>,
+                                                        <PIN_PA6__SDMMC0_DAT4>,
+                                                        <PIN_PA7__SDMMC0_DAT5>,
+                                                        <PIN_PA8__SDMMC0_DAT6>,
+                                                        <PIN_PA9__SDMMC0_DAT7>;
+                                               bias-pull-up;
+                                       };
+
+                                       ck_cd_rstn_vddsel {
+                                               pinmux = <PIN_PA0__SDMMC0_CK>,
+                                                        <PIN_PA10__SDMMC0_RSTN>,
+                                                        <PIN_PA11__SDMMC0_VDDSEL>,
+                                                        <PIN_PA13__SDMMC0_CD>;
+                                               bias-disable;
+                                       };
+                               };
+
+                               pinctrl_sdmmc1_default: sdmmc1_default {
+                                       cmd_data {
+                                               pinmux = <PIN_PA28__SDMMC1_CMD>,
+                                                        <PIN_PA18__SDMMC1_DAT0>,
+                                                        <PIN_PA19__SDMMC1_DAT1>,
+                                                        <PIN_PA20__SDMMC1_DAT2>,
+                                                        <PIN_PA21__SDMMC1_DAT3>;
+                                               bias-pull-up;
+                                       };
+
+                                       conf-ck_cd {
+                                               pinmux = <PIN_PA22__SDMMC1_CK>,
+                                                        <PIN_PA30__SDMMC1_CD>;
+                                               bias-disable;
+                                       };
+                               };
+
                                pinctrl_spi0_default: spi0_default {
                                        pinmux = <PIN_PA14__SPI0_SPCK>,
                                                 <PIN_PA15__SPI0_MOSI>,
index 8488ac53d22d3b4d6f0562ebd9018d3126ce5ee2..ff888d21c786a69b1f56c768ea6a2219056b98dc 100644 (file)
                        label = "PB_USER";
                        gpios = <&pioE 29 GPIO_ACTIVE_LOW>;
                        linux,code = <0x104>;
-                       gpio-key,wakeup;
+                       wakeup-source;
                };
        };
 
index 45371a1b61b398b6b939292649b20d0315cd399b..131614f28e758653e34cc2b993bb6a5a28f20bbb 100644 (file)
@@ -50,7 +50,6 @@
        compatible = "atmel,sama5d4-xplained", "atmel,sama5d4", "atmel,sama5";
 
        chosen {
-               bootargs = "ignore_loglevel earlyprintk";
                stdout-path = "serial0:115200n8";
        };
 
        };
 
        clocks {
-               #address-cells = <1>;
-               #size-cells = <1>;
-               ranges;
-
-               main_clock: clock@0 {
-                       compatible = "atmel,osc", "fixed-clock";
-                       clock-frequency = <12000000>;
-               };
-
                slow_xtal {
                        clock-frequency = <32768>;
                };
                        label = "pb_user1";
                        gpios = <&pioE 8 GPIO_ACTIVE_HIGH>;
                        linux,code = <0x100>;
-                       gpio-key,wakeup;
+                       wakeup-source;
                };
        };
 
index 6d272c0125e365b64aad7dadbeec309c51c60fc6..2d4a33100af6bdc4fcd4a3500467456673f54325 100644 (file)
@@ -50,7 +50,6 @@
        compatible = "atmel,sama5d4ek", "atmel,sama5d4", "atmel,sama5";
 
        chosen {
-               bootargs = "ignore_loglevel earlyprintk";
                stdout-path = "serial0:115200n8";
        };
 
        };
 
        clocks {
-               #address-cells = <1>;
-               #size-cells = <1>;
-               ranges;
-
-               main_clock: clock@0 {
-                       compatible = "atmel,osc", "fixed-clock";
-                       clock-frequency = <12000000>;
-               };
-
                slow_xtal {
                        clock-frequency = <32768>;
                };
                        label = "pb_user1";
                        gpios = <&pioE 13 GPIO_ACTIVE_HIGH>;
                        linux,code = <0x100>;
-                       gpio-key,wakeup;
+                       wakeup-source;
                };
        };
 
index 8dab4b75ca97cfed9beae29bf49224dc71a06bb9..f90e1c2d3caa2fc41485ba330bdcd691a379e6be 100644 (file)
        };
 
        clocks {
-               #address-cells = <1>;
-               #size-cells = <1>;
-               ranges;
-
-               main_clock: clock@0 {
-                       compatible = "atmel,osc", "fixed-clock";
-                       clock-frequency = <18432000>;
-               };
-
                slow_xtal {
                        clock-frequency = <32768>;
                };
index 2e92ac020f2383ef58c25a1836b22954834211be..55bd51f07fa601e709f7fc910e7fa757fe4f32ee 100644 (file)
        };
 
        clocks {
-               #address-cells = <1>;
-               #size-cells = <1>;
-               ranges;
-
-               main_clock: clock@0 {
-                       compatible = "atmel,osc", "fixed-clock";
-                       clock-frequency = <18432000>;
-               };
-
                slow_xtal {
                        clock-frequency = <32768>;
                };
                                        ti,debounce-tol = /bits/ 16 <65535>;
                                        ti,debounce-max = /bits/ 16 <1>;
 
-                                       linux,wakeup;
+                                       wakeup-source;
                                };
                        };
 
                        label = "button_0";
                        gpios = <&pioA 27 GPIO_ACTIVE_LOW>;
                        linux,code = <256>;
-                       gpio-key,wakeup;
+                       wakeup-source;
                };
 
                button_1 {
                        label = "button_1";
                        gpios = <&pioA 26 GPIO_ACTIVE_LOW>;
                        linux,code = <257>;
-                       gpio-key,wakeup;
+                       wakeup-source;
                };
 
                button_2 {
                        label = "button_2";
                        gpios = <&pioA 25 GPIO_ACTIVE_LOW>;
                        linux,code = <258>;
-                       gpio-key,wakeup;
+                       wakeup-source;
                };
 
                button_3 {
                        label = "button_3";
                        gpios = <&pioA 24 GPIO_ACTIVE_LOW>;
                        linux,code = <259>;
-                       gpio-key,wakeup;
+                       wakeup-source;
                };
        };
 };
index 23381276ffb8016b0dafc1237eb990bad1e775b1..59df9d73d27659d507d78d195fe3b1be7c499dd4 100644 (file)
        };
 
        clocks {
-               #address-cells = <1>;
-               #size-cells = <1>;
-               ranges;
-
-               main_clock: clock@0 {
-                       compatible = "atmel,osc", "fixed-clock";
-                       clock-frequency = <16367660>;
-               };
-
                slow_xtal {
                        clock-frequency = <32768>;
                };
                        label = "left_click";
                        gpios = <&pioC 5 GPIO_ACTIVE_LOW>;
                        linux,code = <272>;
-                       gpio-key,wakeup;
+                       wakeup-source;
                };
 
                right_click {
                        label = "right_click";
                        gpios = <&pioC 4 GPIO_ACTIVE_LOW>;
                        linux,code = <273>;
-                       gpio-key,wakeup;
+                       wakeup-source;
                };
        };
 
index 57548a2c5a1eb80b0701129f612bf3a785b65928..e9cc99b6353ad1e464bb0942c29e3cea6dc5d37e 100644 (file)
        };
 
        clocks {
-               #address-cells = <1>;
-               #size-cells = <1>;
-               ranges;
-
-               main_clock: clock@0 {
-                       compatible = "atmel,osc", "fixed-clock";
-                       clock-frequency = <18432000>;
-               };
-
                slow_xtal {
                        clock-frequency = <32768>;
                };
                        label = "Button 3";
                        gpios = <&pioA 30 GPIO_ACTIVE_LOW>;
                        linux,code = <0x103>;
-                       gpio-key,wakeup;
+                       wakeup-source;
                };
 
                btn4 {
                        label = "Button 4";
                        gpios = <&pioA 31 GPIO_ACTIVE_LOW>;
                        linux,code = <0x104>;
-                       gpio-key,wakeup;
+                       wakeup-source;
                };
        };
 
index 9d16ef8453c556f7ad69a21f65d9526a90325115..2400c99134f7f516e97af8234d89b8d3098196bd 100644 (file)
        };
 
        clocks {
-               #address-cells = <1>;
-               #size-cells = <1>;
-               ranges;
-
-               main_clock: clock@0 {
-                       compatible = "atmel,osc", "fixed-clock";
-                       clock-frequency = <12000000>;
-               };
-
                slow_xtal {
                      clock-frequency = <32768>;
                };
                        label = "left_click";
                        gpios = <&pioB 6 GPIO_ACTIVE_LOW>;
                        linux,code = <272>;
-                       gpio-key,wakeup;
+                       wakeup-source;
                };
 
                right_click {
                        label = "right_click";
                        gpios = <&pioB 7 GPIO_ACTIVE_LOW>;
                        linux,code = <273>;
-                       gpio-key,wakeup;
+                       wakeup-source;
                };
 
                left {
index acf3451a332da266f9a4e0ad5903a7ec11767587..ca4ddf86817ab64dc6a8a31193191460bfaf8d4b 100644 (file)
        };
 
        clocks {
-               #address-cells = <1>;
-               #size-cells = <1>;
-               ranges;
-
-               main_clock: clock@0 {
-                       compatible = "atmel,osc", "fixed-clock";
-                       clock-frequency = <16000000>;
-               };
-
                slow_xtal {
                        clock-frequency = <32768>;
                };
                        label = "Enter";
                        gpios = <&pioB 3 GPIO_ACTIVE_LOW>;
                        linux,code = <28>;
-                       gpio-key,wakeup;
+                       wakeup-source;
                };
        };
 
index 558c9f220bedef3c61ac0b78e3dad2eb76017573..f10566f759cdceba2bedb202365a8c30d979c2f5 100644 (file)
        };
 
        clocks {
-               #address-cells = <1>;
-               #size-cells = <1>;
-               ranges;
-
-               main_clock: clock {
-                       compatible = "atmel,osc", "fixed-clock";
-                       clock-frequency = <12000000>;
-               };
-
                slow_xtal {
                        clock-frequency = <32768>;
                };
                        label = "right_click";
                        gpios = <&pioB 0 GPIO_ACTIVE_LOW>;
                        linux,code = <273>;
-                       gpio-key,wakeup;
+                       wakeup-source;
                };
 
                left_click {
                        label = "left_click";
                        gpios = <&pioB 1 GPIO_ACTIVE_LOW>;
                        linux,code = <272>;
-                       gpio-key,wakeup;
+                       wakeup-source;
                };
        };
 
index 26112ebd15fc4e896d576932b330b846fc4cc397..b098ad8cd93a7622b02198ee4bf2b06422af941a 100644 (file)
                reg = <0x20000000 0x8000000>;
        };
 
-       clocks {
-               #address-cells = <1>;
-               #size-cells = <1>;
-               ranges;
-
-               main_clock: clock@0 {
-                       compatible = "atmel,osc", "fixed-clock";
-                       clock-frequency = <12000000>;
-               };
-       };
-
        clocks {
                slow_xtal {
                        clock-frequency = <32768>;
index 8ea177f375ddd652c98339ac2cc8ef8935396442..fb1da99996ea43f9c3492591e9faf800030d5989 100644 (file)
                sdhci0: sdhci@ab0000 {
                        compatible = "mrvl,pxav3-mmc";
                        reg = <0xab0000 0x200>;
-                       clocks = <&chip_clk CLKID_SDIO1XIN>;
+                       clocks = <&chip_clk CLKID_SDIO1XIN>, <&chip_clk CLKID_SDIO>;
+                       clock-names = "io", "core";
                        interrupts = <GIC_SPI 17 IRQ_TYPE_LEVEL_HIGH>;
                        status = "disabled";
                };
                sdhci1: sdhci@ab0800 {
                        compatible = "mrvl,pxav3-mmc";
                        reg = <0xab0800 0x200>;
-                       clocks = <&chip_clk CLKID_SDIO1XIN>;
+                       clocks = <&chip_clk CLKID_SDIO1XIN>, <&chip_clk CLKID_SDIO>;
+                       clock-names = "io", "core";
                        interrupts = <GIC_SPI 20 IRQ_TYPE_LEVEL_HIGH>;
                        status = "disabled";
                };
                        compatible = "mrvl,pxav3-mmc";
                        reg = <0xab1000 0x200>;
                        interrupts = <GIC_SPI 28 IRQ_TYPE_LEVEL_HIGH>;
-                       clocks = <&chip_clk CLKID_NFC_ECC>, <&chip_clk CLKID_NFC>;
+                       clocks = <&chip_clk CLKID_NFC_ECC>, <&chip_clk CLKID_SDIO>;
                        clock-names = "io", "core";
                        status = "disabled";
                };
index 3c99cfa1a8761604a409b9d0525f143c494571b0..eee636de4cd844237f5490b71c5f00d56dd9f06c 100644 (file)
                        reg = <0x480c8000 0x2000>;
                        interrupts = <77>;
                        ti,hwmods = "mailbox";
+                       #mbox-cells = <1>;
                        ti,mbox-num-users = <4>;
                        ti,mbox-num-fifos = <12>;
                        mbox_dsp: mbox_dsp {
                        ti,spi-num-cs = <4>;
                        ti,hwmods = "mcspi1";
                        dmas = <&edma 16 &edma 17
-                               &edma 18 &edma 19>;
-                       dma-names = "tx0", "rx0", "tx1", "rx1";
+                               &edma 18 &edma 19
+                               &edma 20 &edma 21
+                               &edma 22 &edma 23>;
+                       dma-names = "tx0", "rx0", "tx1", "rx1",
+                                   "tx2", "rx2", "tx3", "rx3";
                };
 
                mmc1: mmc@48060000 {
index bc672fb91466a5635a29c0811c202ef5c418aeeb..fe99231cbde5910bae9f768ead874effd33794c1 100644 (file)
                        interrupt-names = "tx", "rx";
                        dmas = <&sdma_xbar 133>, <&sdma_xbar 132>;
                        dma-names = "tx", "rx";
-                       clocks = <&mcasp3_ahclkx_mux>;
-                       clock-names = "fck";
+                       clocks = <&mcasp3_aux_gfclk_mux>, <&mcasp3_ahclkx_mux>;
+                       clock-names = "fck", "ahclkx";
                        status = "disabled";
                };
 
index feb9d34b239c8069450c1d4c1479ebaf207ef3ec..f818ea483aeb57ee804e34d07e4b8383fae2eb63 100644 (file)
                                compatible = "fsl,imx27-usb";
                                reg = <0x10024000 0x200>;
                                interrupts = <56>;
-                               clocks = <&clks IMX27_CLK_USB_IPG_GATE>;
+                               clocks = <&clks IMX27_CLK_USB_IPG_GATE>,
+                                       <&clks IMX27_CLK_USB_AHB_GATE>,
+                                       <&clks IMX27_CLK_USB_DIV>;
+                               clock-names = "ipg", "ahb", "per";
                                fsl,usbmisc = <&usbmisc 0>;
                                status = "disabled";
                        };
                                compatible = "fsl,imx27-usb";
                                reg = <0x10024200 0x200>;
                                interrupts = <54>;
-                               clocks = <&clks IMX27_CLK_USB_IPG_GATE>;
+                               clocks = <&clks IMX27_CLK_USB_IPG_GATE>,
+                                       <&clks IMX27_CLK_USB_AHB_GATE>,
+                                       <&clks IMX27_CLK_USB_DIV>;
+                               clock-names = "ipg", "ahb", "per";
                                fsl,usbmisc = <&usbmisc 1>;
                                dr_mode = "host";
                                status = "disabled";
                                compatible = "fsl,imx27-usb";
                                reg = <0x10024400 0x200>;
                                interrupts = <55>;
-                               clocks = <&clks IMX27_CLK_USB_IPG_GATE>;
+                               clocks = <&clks IMX27_CLK_USB_IPG_GATE>,
+                                       <&clks IMX27_CLK_USB_AHB_GATE>,
+                                       <&clks IMX27_CLK_USB_DIV>;
+                               clock-names = "ipg", "ahb", "per";
                                fsl,usbmisc = <&usbmisc 2>;
                                dr_mode = "host";
                                status = "disabled";
                                #index-cells = <1>;
                                compatible = "fsl,imx27-usbmisc";
                                reg = <0x10024600 0x200>;
-                               clocks = <&clks IMX27_CLK_USB_AHB_GATE>;
                        };
 
                        sahara2: sahara@10025000 {
index 58adf176425a69fc48d16731973f93827b080bab..a51834e1dd2789ed0bfeed69b2dbddc08aa946fc 100644 (file)
 &fec {
        pinctrl-names = "default";
        pinctrl-0 = <&pinctrl_enet>;
-       phy-mode = "rgmii";
+       phy-mode = "rgmii-id";
        phy-reset-gpios = <&gpio1 30 GPIO_ACTIVE_HIGH>;
        status = "okay";
 };
index 7b31fdb79ced5cbac2eecff792fa8d56b1a9a010..dc0cebfe22d7b9a8f0500e1313c67ede2718234d 100644 (file)
@@ -94,7 +94,7 @@
 &fec {
        pinctrl-names = "default";
        pinctrl-0 = <&pinctrl_enet>;
-       phy-mode = "rgmii";
+       phy-mode = "rgmii-id";
        phy-reset-gpios = <&gpio1 30 GPIO_ACTIVE_LOW>;
        status = "okay";
 };
index 1b66328a84987a1040b0406e1b4dfe29a87707ed..18cd4114a23e85a82f724c3b8773c04399826129 100644 (file)
 &fec {
        pinctrl-names = "default";
        pinctrl-0 = <&pinctrl_enet>;
-       phy-mode = "rgmii";
+       phy-mode = "rgmii-id";
        phy-reset-gpios = <&gpio1 30 GPIO_ACTIVE_LOW>;
        status = "okay";
 };
index 7c51839ff93467d209e0f3809b3ed9e8bc541c54..eea90f37bbb8c236ebc97e2e1c90b439e4aed2ed 100644 (file)
 &fec {
        pinctrl-names = "default";
        pinctrl-0 = <&pinctrl_enet>;
-       phy-mode = "rgmii";
+       phy-mode = "rgmii-id";
        phy-reset-gpios = <&gpio1 30 GPIO_ACTIVE_LOW>;
        status = "okay";
 };
index 929e0b37bd9e542e252be1159e6e588dd34b94e1..6c11a2ae35ef98b0f2adcb218d20543cead8f399 100644 (file)
 &fec {
        pinctrl-names = "default";
        pinctrl-0 = <&pinctrl_enet>;
-       phy-mode = "rgmii";
+       phy-mode = "rgmii-id";
        phy-reset-gpios = <&gpio1 30 GPIO_ACTIVE_LOW>;
        status = "okay";
 };
index 8263fc18a7d95ff88b470ae57fd5e2e89036f99f..d354d406954da437071db41de61e349a48644802 100644 (file)
 &clks {
        assigned-clocks = <&clks IMX6QDL_PLL4_BYPASS_SRC>,
                          <&clks IMX6QDL_PLL4_BYPASS>,
-                         <&clks IMX6QDL_CLK_PLL4_POST_DIV>,
                          <&clks IMX6QDL_CLK_LDB_DI0_SEL>,
-                         <&clks IMX6QDL_CLK_LDB_DI1_SEL>;
+                         <&clks IMX6QDL_CLK_LDB_DI1_SEL>,
+                         <&clks IMX6QDL_CLK_PLL4_POST_DIV>;
        assigned-clock-parents = <&clks IMX6QDL_CLK_LVDS2_IN>,
                                 <&clks IMX6QDL_PLL4_BYPASS_SRC>,
                                 <&clks IMX6QDL_CLK_PLL3_USB_OTG>,
                                 <&clks IMX6QDL_CLK_PLL3_USB_OTG>;
-       assigned-clock-rates = <0>, <0>, <24576000>;
+       assigned-clock-rates = <0>, <0>, <0>, <0>, <24576000>;
 };
 
 &ecspi1 {
index 01aef230773d4052e19ba13b5c4a95df9ea08787..5acbd0dcc2abd9d3ffd3ac09adeab6f2dc33dfad 100644 (file)
@@ -137,7 +137,7 @@ netcp: netcp@26000000 {
        /* NetCP address range */
        ranges = <0 0x26000000 0x1000000>;
 
-       clocks = <&papllclk>, <&clkcpgmac>, <&chipclk12>;
+       clocks = <&clkosr>, <&papllclk>, <&clkcpgmac>, <&chipclk12>;
        dma-coherent;
 
        ti,navigator-dmas = <&dma_gbe 0>,
index c56ab6bbfe3c3a1fa1b60f481840cbaa3292a7f2..0e46560551f44b5d5dba4a01dcd74d9eb91ec5b2 100644 (file)
@@ -40,7 +40,7 @@
                };
                poweroff@12100 {
                        compatible = "qnap,power-off";
-                       reg = <0x12000 0x100>;
+                       reg = <0x12100 0x100>;
                        clocks = <&gate_clk 7>;
                };
                spi@10600 {
index 1a78f013f37ab8e2ee4de5361dc16bdeec2b2516..b75f7b2b7c4ac9e0aca7c4c44e3f1b8e2bd09c28 100644 (file)
        };
 };
 
+&uart3 {
+       interrupts-extended = <&wakeupgen GIC_SPI 74 IRQ_TYPE_LEVEL_HIGH
+                              &omap4_pmx_core OMAP4_UART3_RX>;
+};
index 8fd8ef2c72dae55de1a1fa6004be38928b6f660f..85f0373df498f07b5b0c54658961bae18b535d7b 100644 (file)
        };
 };
 
+&emmc {
+       /delete-property/mmc-hs200-1_8v;
+};
+
 &gpio_keys {
        pinctrl-0 = <&pwr_key_l &ap_lid_int_l &volum_down_l &volum_up_l>;
 
index 6a79c9c526b8809d9ea201d087d680851653e990..04ea209f1737f9fb052f4efc8589e98aa027836e 100644 (file)
                clock-names = "tsadc", "apb_pclk";
                resets = <&cru SRST_TSADC>;
                reset-names = "tsadc-apb";
-               pinctrl-names = "default";
-               pinctrl-0 = <&otp_out>;
+               pinctrl-names = "init", "default", "sleep";
+               pinctrl-0 = <&otp_gpio>;
+               pinctrl-1 = <&otp_out>;
+               pinctrl-2 = <&otp_gpio>;
                #thermal-sensor-cells = <1>;
                rockchip,hw-tshut-temp = <95000>;
                status = "disabled";
                };
 
                tsadc {
+                       otp_gpio: otp-gpio {
+                               rockchip,pins = <0 10 RK_FUNC_GPIO &pcfg_pull_none>;
+                       };
+
                        otp_out: otp-out {
                                rockchip,pins = <0 10 RK_FUNC_1 &pcfg_pull_none>;
                        };
index d9a9aca1ccfdf6d5514b535241d7c5f2ae379e92..e812f5c1bf709db8edded907516c75e66e20c4b8 100644 (file)
@@ -49,7 +49,7 @@
                        label = "pb_user1";
                        gpios = <&pioE 27 GPIO_ACTIVE_HIGH>;
                        linux,code = <0x100>;
-                       gpio-key,wakeup;
+                       wakeup-source;
                };
        };
 };
index 15bbaf690047dfb9ab0082d31b83142b63228e09..2193637b9cd2bdb4a14a13e8e48218cc04cadf01 100644 (file)
                        };
 
                        watchdog@fc068640 {
-                               compatible = "atmel,at91sam9260-wdt";
+                               compatible = "atmel,sama5d4-wdt";
                                reg = <0xfc068640 0x10>;
                                clocks = <&clk32k>;
                                status = "disabled";
index 2d4250b1faf80040e3e6c3477fe64b7431141627..68b479b8772c6f3eadc16f2ad6c3d33e35d39c5f 100644 (file)
@@ -83,6 +83,7 @@
                reg = <0x5d>;
                interrupt-parent = <&pio>;
                interrupts = <0 3 IRQ_TYPE_LEVEL_HIGH>; /* PA3 */
+               touchscreen-swapped-x-y;
        };
 };
 
index 40c23a0b7cfc2adf8517e28ac51b0078423a0c61..ec1aa64ded681a1a4f834343b3fc45d0c4946819 100644 (file)
 
        /* CPU DFLL clock */
        clock@0,70110000 {
-               status = "okay";
+               status = "disabled";
                vdd-cpu-supply = <&vdd_cpu>;
                nvidia,i2c-fs-rate = <400000>;
        };
index 12edafefd44a3dfb17a5aae66a3fdeb3b8788679..9beea8976584e5067d68ec895c5b9ab1d8eb7929 100644 (file)
                        label = "user_pb";
                        gpios = <&pioB 10 GPIO_ACTIVE_LOW>;
                        linux,code = <28>;
-                       gpio-key,wakeup;
+                       wakeup-source;
                };
        };
 
index 68c0de36c339f7662b7545e072a60762b82627db..8cc6edb296942762772e5fb4e51cdc99ae219af7 100644 (file)
                        label = "user_pb";
                        gpios = <&pioB 10 GPIO_ACTIVE_LOW>;
                        linux,code = <28>;
-                       gpio-key,wakeup;
+                       wakeup-source;
                };
        };
 
index 19fe045b83342a6ee0f55a02b1490c291b9537dd..2d7eab7552100225efcf2cb5d52a5443459f6a58 100644 (file)
@@ -18,8 +18,3 @@
                reg = <0x80000000 0x10000000>;
        };
 };
-
-&L2 {
-       arm,data-latency = <2 1 2>;
-       arm,tag-latency = <3 2 3>;
-};
index 5f8eb1bd782bf01a6454aa7cb63682835c179650..58bc6e448be5601ed8d04106fbcc193793f040f1 100644 (file)
@@ -19,7 +19,7 @@
                reg = <0x40006000 0x1000>;
                cache-unified;
                cache-level = <2>;
-               arm,data-latency = <1 1 1>;
+               arm,data-latency = <3 3 3>;
                arm,tag-latency = <2 2 2>;
        };
 };
index 6736bae43a5b09280ec824146e6caee85f787cdd..3cd1b27f269780b99d1dbc4af64644bcaa45cce5 100644 (file)
                                interrupts = <67 IRQ_TYPE_LEVEL_HIGH>;
                                clocks = <&clks VF610_CLK_DSPI0>;
                                clock-names = "dspi";
-                               spi-num-chipselects = <5>;
+                               spi-num-chipselects = <6>;
                                status = "disabled";
                        };
 
                                interrupts = <68 IRQ_TYPE_LEVEL_HIGH>;
                                clocks = <&clks VF610_CLK_DSPI1>;
                                clock-names = "dspi";
-                               spi-num-chipselects = <5>;
+                               spi-num-chipselects = <4>;
                                status = "disabled";
                        };
 
                                compatible = "fsl,vf610-sai";
                                reg = <0x40031000 0x1000>;
                                interrupts = <86 IRQ_TYPE_LEVEL_HIGH>;
-                               clocks = <&clks VF610_CLK_SAI2>;
-                               clock-names = "sai";
+                               clocks = <&clks VF610_CLK_SAI2>,
+                                       <&clks VF610_CLK_SAI2_DIV>,
+                                       <&clks 0>, <&clks 0>;
+                               clock-names = "bus", "mclk1", "mclk2", "mclk3";
                                dma-names = "tx", "rx";
                                dmas = <&edma0 0 21>,
                                        <&edma0 0 20>;
                                clock-names = "adc";
                                #io-channel-cells = <1>;
                                status = "disabled";
+                               fsl,adck-max-frequency = <30000000>, <40000000>,
+                                                       <20000000>;
                        };
 
                        esdhc0: esdhc@400b1000 {
                                        <&clks VF610_CLK_ESDHC0>;
                                clock-names = "ipg", "ahb", "per";
                                status = "disabled";
-                               fsl,adck-max-frequency = <30000000>, <40000000>,
-                                                       <20000000>;
                        };
 
                        esdhc1: esdhc@400b2000 {
index 1b1e5acd76e2ebd8545f5da91397366b264a989f..e4b1be66b3f56a8d0ecb2590559902bb347b539b 100644 (file)
@@ -125,7 +125,6 @@ CONFIG_POWER_RESET=y
 # CONFIG_HWMON is not set
 CONFIG_WATCHDOG=y
 CONFIG_AT91SAM9X_WATCHDOG=y
-CONFIG_SSB=m
 CONFIG_MFD_ATMEL_HLCDC=y
 CONFIG_REGULATOR=y
 CONFIG_REGULATOR_FIXED_VOLTAGE=y
index a0c57ac88b2756c0a4cdf0b9758e4df65d975833..63f7e6ce649a8630e3f5471a7fea60ee483c5496 100644 (file)
@@ -129,7 +129,6 @@ CONFIG_GPIO_SYSFS=y
 CONFIG_POWER_SUPPLY=y
 CONFIG_POWER_RESET=y
 # CONFIG_HWMON is not set
-CONFIG_SSB=m
 CONFIG_MFD_ATMEL_FLEXCOM=y
 CONFIG_REGULATOR=y
 CONFIG_REGULATOR_FIXED_VOLTAGE=y
index 6607d976e07d0998639457745ca364cf1305da85..7da5503c0591411f43df6bc767fb8c4eef314789 100644 (file)
@@ -21,6 +21,7 @@
 #ifndef __ASSEMBLY__
 
 #include <linux/io.h>
+#include <asm/barrier.h>
 
 #define __ACCESS_CP15(CRn, Op1, CRm, Op2)      p15, Op1, %0, CRn, CRm, Op2
 #define __ACCESS_CP15_64(Op1, CRm)             p15, Op1, %Q0, %R0, CRm
index be1d07d59ee9784c7b3dd12a2150a009c7c742ba..1bd9510de1b9ced64b1947f2734ddbf4c8ce4f5d 100644 (file)
@@ -40,6 +40,11 @@ extern void arch_trigger_all_cpu_backtrace(bool);
 #define arch_trigger_all_cpu_backtrace(x) arch_trigger_all_cpu_backtrace(x)
 #endif
 
+static inline int nr_legacy_irqs(void)
+{
+       return NR_IRQS_LEGACY;
+}
+
 #endif
 
 #endif
index a9c80a2ea1a779ffdbcd5d56014b1b2fbbd0381b..3095df091ff8a571cf9b6b074c56beb69ad9243d 100644 (file)
 unsigned long *vcpu_reg(struct kvm_vcpu *vcpu, u8 reg_num);
 unsigned long *vcpu_spsr(struct kvm_vcpu *vcpu);
 
+static inline unsigned long vcpu_get_reg(struct kvm_vcpu *vcpu,
+                                        u8 reg_num)
+{
+       return *vcpu_reg(vcpu, reg_num);
+}
+
+static inline void vcpu_set_reg(struct kvm_vcpu *vcpu, u8 reg_num,
+                               unsigned long val)
+{
+       *vcpu_reg(vcpu, reg_num) = val;
+}
+
 bool kvm_condition_valid(struct kvm_vcpu *vcpu);
 void kvm_skip_instr(struct kvm_vcpu *vcpu, bool is_wide_instr);
 void kvm_inject_undefined(struct kvm_vcpu *vcpu);
index 8cc85a4ebec20a1223f966bb868e5def5f70928e..35c9db857ebe9c7d53715ec42518a6e9fbe1dc6e 100644 (file)
@@ -510,10 +510,14 @@ __copy_to_user_std(void __user *to, const void *from, unsigned long n);
 static inline unsigned long __must_check
 __copy_to_user(void __user *to, const void *from, unsigned long n)
 {
+#ifndef CONFIG_UACCESS_WITH_MEMCPY
        unsigned int __ua_flags = uaccess_save_and_enable();
        n = arm_copy_to_user(to, from, n);
        uaccess_restore(__ua_flags);
        return n;
+#else
+       return arm_copy_to_user(to, from, n);
+#endif
 }
 
 extern unsigned long __must_check
index 7a2a32a1d5a8c3fef87e995ac349435de1daeb6f..ede692ffa32ed14958f81eec0d7caac8f7efe853 100644 (file)
 #define __NR_execveat                  (__NR_SYSCALL_BASE+387)
 #define __NR_userfaultfd               (__NR_SYSCALL_BASE+388)
 #define __NR_membarrier                        (__NR_SYSCALL_BASE+389)
+#define __NR_mlock2                    (__NR_SYSCALL_BASE+390)
 
 /*
  * The following SWIs are ARM private.
index 6551d28c27e687068bc69af093a9a97805362d46..066f7f9ba411e09b5e492a84f03034b86305e38f 100644 (file)
 #include <asm/mach/pci.h>
 
 static int debug_pci;
-static resource_size_t (*align_resource)(struct pci_dev *dev,
-                 const struct resource *res,
-                 resource_size_t start,
-                 resource_size_t size,
-                 resource_size_t align) = NULL;
 
 /*
  * We can't use pci_get_device() here since we are
@@ -461,7 +456,6 @@ static void pcibios_init_hw(struct device *parent, struct hw_pci *hw,
                sys->busnr   = busnr;
                sys->swizzle = hw->swizzle;
                sys->map_irq = hw->map_irq;
-               align_resource = hw->align_resource;
                INIT_LIST_HEAD(&sys->resources);
 
                if (hw->private_data)
@@ -470,6 +464,8 @@ static void pcibios_init_hw(struct device *parent, struct hw_pci *hw,
                ret = hw->setup(nr, sys);
 
                if (ret > 0) {
+                       struct pci_host_bridge *host_bridge;
+
                        ret = pcibios_init_resources(nr, sys);
                        if (ret)  {
                                kfree(sys);
@@ -491,6 +487,9 @@ static void pcibios_init_hw(struct device *parent, struct hw_pci *hw,
                        busnr = sys->bus->busn_res.end + 1;
 
                        list_add(&sys->node, head);
+
+                       host_bridge = pci_find_host_bridge(sys->bus);
+                       host_bridge->align_resource = hw->align_resource;
                } else {
                        kfree(sys);
                        if (ret < 0)
@@ -578,14 +577,18 @@ resource_size_t pcibios_align_resource(void *data, const struct resource *res,
 {
        struct pci_dev *dev = data;
        resource_size_t start = res->start;
+       struct pci_host_bridge *host_bridge;
 
        if (res->flags & IORESOURCE_IO && start & 0x300)
                start = (start + 0x3ff) & ~0x3ff;
 
        start = (start + align - 1) & ~(align - 1);
 
-       if (align_resource)
-               return align_resource(dev, res, start, size, align);
+       host_bridge = pci_find_host_bridge(dev->bus);
+
+       if (host_bridge->align_resource)
+               return host_bridge->align_resource(dev, res,
+                               start, size, align);
 
        return start;
 }
index fde6c88d560cffcf8d1433fe486695e763704ca9..ac368bb068d1409af37a8e2585bb837b1ef1f02b 100644 (file)
                CALL(sys_execveat)
                CALL(sys_userfaultfd)
                CALL(sys_membarrier)
+               CALL(sys_mlock2)
 #ifndef syscalls_counted
 .equ syscalls_padding, ((NR_syscalls + 3) & ~3) - NR_syscalls
 #define syscalls_counted
index 7a7c4cea55231b1c793982ab63d6c5598004b14b..4adfb46e3ee93276ea506b723eb11e33c57459f4 100644 (file)
@@ -95,6 +95,22 @@ void __show_regs(struct pt_regs *regs)
 {
        unsigned long flags;
        char buf[64];
+#ifndef CONFIG_CPU_V7M
+       unsigned int domain;
+#ifdef CONFIG_CPU_SW_DOMAIN_PAN
+       /*
+        * Get the domain register for the parent context. In user
+        * mode, we don't save the DACR, so lets use what it should
+        * be. For other modes, we place it after the pt_regs struct.
+        */
+       if (user_mode(regs))
+               domain = DACR_UACCESS_ENABLE;
+       else
+               domain = *(unsigned int *)(regs + 1);
+#else
+       domain = get_domain();
+#endif
+#endif
 
        show_regs_print_info(KERN_DEFAULT);
 
@@ -123,21 +139,8 @@ void __show_regs(struct pt_regs *regs)
 
 #ifndef CONFIG_CPU_V7M
        {
-               unsigned int domain = get_domain();
                const char *segment;
 
-#ifdef CONFIG_CPU_SW_DOMAIN_PAN
-               /*
-                * Get the domain register for the parent context. In user
-                * mode, we don't save the DACR, so lets use what it should
-                * be. For other modes, we place it after the pt_regs struct.
-                */
-               if (user_mode(regs))
-                       domain = DACR_UACCESS_ENABLE;
-               else
-                       domain = *(unsigned int *)(regs + 1);
-#endif
-
                if ((domain & domain_mask(DOMAIN_USER)) ==
                    domain_val(DOMAIN_USER, DOMAIN_NOACCESS))
                        segment = "none";
@@ -163,11 +166,11 @@ void __show_regs(struct pt_regs *regs)
                buf[0] = '\0';
 #ifdef CONFIG_CPU_CP15_MMU
                {
-                       unsigned int transbase, dac = get_domain();
+                       unsigned int transbase;
                        asm("mrc p15, 0, %0, c2, c0\n\t"
                            : "=r" (transbase));
                        snprintf(buf, sizeof(buf), "  Table: %08x  DAC: %08x",
-                               transbase, dac);
+                               transbase, domain);
                }
 #endif
                asm("mrc p15, 0, %0, c1, c0\n" : "=r" (ctrl));
index 5b26e7efa9ea415967b63ede27ab1edf2bc8e888..c3fe769d75584c7248015b855bca904589f3e29f 100644 (file)
  */
 #define __user_swpX_asm(data, addr, res, temp, B)              \
        __asm__ __volatile__(                                   \
-       "       mov             %2, %1\n"                       \
-       "0:     ldrex"B"        %1, [%3]\n"                     \
-       "1:     strex"B"        %0, %2, [%3]\n"                 \
+       "0:     ldrex"B"        %2, [%3]\n"                     \
+       "1:     strex"B"        %0, %1, [%3]\n"                 \
        "       cmp             %0, #0\n"                       \
+       "       moveq           %1, %2\n"                       \
        "       movne           %0, %4\n"                       \
        "2:\n"                                                  \
        "       .section         .text.fixup,\"ax\"\n"          \
index b83f3b7737fb9dce2a18c66a086aac2430e98cf6..087acb569b63a4bd90982e0c9b15fc2313636c53 100644 (file)
@@ -193,15 +193,44 @@ struct oabi_flock64 {
        pid_t   l_pid;
 } __attribute__ ((packed,aligned(4)));
 
-asmlinkage long sys_oabi_fcntl64(unsigned int fd, unsigned int cmd,
+static long do_locks(unsigned int fd, unsigned int cmd,
                                 unsigned long arg)
 {
-       struct oabi_flock64 user;
        struct flock64 kernel;
-       mm_segment_t fs = USER_DS; /* initialized to kill a warning */
-       unsigned long local_arg = arg;
-       int ret;
+       struct oabi_flock64 user;
+       mm_segment_t fs;
+       long ret;
+
+       if (copy_from_user(&user, (struct oabi_flock64 __user *)arg,
+                          sizeof(user)))
+               return -EFAULT;
+       kernel.l_type   = user.l_type;
+       kernel.l_whence = user.l_whence;
+       kernel.l_start  = user.l_start;
+       kernel.l_len    = user.l_len;
+       kernel.l_pid    = user.l_pid;
+
+       fs = get_fs();
+       set_fs(KERNEL_DS);
+       ret = sys_fcntl64(fd, cmd, (unsigned long)&kernel);
+       set_fs(fs);
+
+       if (!ret && (cmd == F_GETLK64 || cmd == F_OFD_GETLK)) {
+               user.l_type     = kernel.l_type;
+               user.l_whence   = kernel.l_whence;
+               user.l_start    = kernel.l_start;
+               user.l_len      = kernel.l_len;
+               user.l_pid      = kernel.l_pid;
+               if (copy_to_user((struct oabi_flock64 __user *)arg,
+                                &user, sizeof(user)))
+                       ret = -EFAULT;
+       }
+       return ret;
+}
 
+asmlinkage long sys_oabi_fcntl64(unsigned int fd, unsigned int cmd,
+                                unsigned long arg)
+{
        switch (cmd) {
        case F_OFD_GETLK:
        case F_OFD_SETLK:
@@ -209,39 +238,11 @@ asmlinkage long sys_oabi_fcntl64(unsigned int fd, unsigned int cmd,
        case F_GETLK64:
        case F_SETLK64:
        case F_SETLKW64:
-               if (copy_from_user(&user, (struct oabi_flock64 __user *)arg,
-                                  sizeof(user)))
-                       return -EFAULT;
-               kernel.l_type   = user.l_type;
-               kernel.l_whence = user.l_whence;
-               kernel.l_start  = user.l_start;
-               kernel.l_len    = user.l_len;
-               kernel.l_pid    = user.l_pid;
-               local_arg = (unsigned long)&kernel;
-               fs = get_fs();
-               set_fs(KERNEL_DS);
-       }
-
-       ret = sys_fcntl64(fd, cmd, local_arg);
+               return do_locks(fd, cmd, arg);
 
-       switch (cmd) {
-       case F_GETLK64:
-               if (!ret) {
-                       user.l_type     = kernel.l_type;
-                       user.l_whence   = kernel.l_whence;
-                       user.l_start    = kernel.l_start;
-                       user.l_len      = kernel.l_len;
-                       user.l_pid      = kernel.l_pid;
-                       if (copy_to_user((struct oabi_flock64 __user *)arg,
-                                        &user, sizeof(user)))
-                               ret = -EFAULT;
-               }
-       case F_SETLK64:
-       case F_SETLKW64:
-               set_fs(fs);
+       default:
+               return sys_fcntl64(fd, cmd, arg);
        }
-
-       return ret;
 }
 
 struct oabi_epoll_event {
index eab83b2435b8b8ed2abc6342e3a22e19da80d623..e06fd299de0846b44b72cd037eacd05b0b2cb051 100644 (file)
@@ -563,18 +563,13 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu, struct kvm_run *run)
                if (vcpu->arch.power_off || vcpu->arch.pause)
                        vcpu_sleep(vcpu);
 
-               /*
-                * Disarming the background timer must be done in a
-                * preemptible context, as this call may sleep.
-                */
-               kvm_timer_flush_hwstate(vcpu);
-
                /*
                 * Preparing the interrupts to be injected also
                 * involves poking the GIC, which must be done in a
                 * non-preemptible context.
                 */
                preempt_disable();
+               kvm_timer_flush_hwstate(vcpu);
                kvm_vgic_flush_hwstate(vcpu);
 
                local_irq_disable();
index 974b1c606d044c239bfa14ffbdf66f0fc982c4fb..3a10c9f1d0a46b68b42d2e7c311a7dbd6ecd44a0 100644 (file)
@@ -115,7 +115,7 @@ int kvm_handle_mmio_return(struct kvm_vcpu *vcpu, struct kvm_run *run)
                trace_kvm_mmio(KVM_TRACE_MMIO_READ, len, run->mmio.phys_addr,
                               data);
                data = vcpu_data_host_to_guest(vcpu, data, len);
-               *vcpu_reg(vcpu, vcpu->arch.mmio_decode.rt) = data;
+               vcpu_set_reg(vcpu, vcpu->arch.mmio_decode.rt, data);
        }
 
        return 0;
@@ -186,7 +186,8 @@ int io_mem_abort(struct kvm_vcpu *vcpu, struct kvm_run *run,
        rt = vcpu->arch.mmio_decode.rt;
 
        if (is_write) {
-               data = vcpu_data_guest_to_host(vcpu, *vcpu_reg(vcpu, rt), len);
+               data = vcpu_data_guest_to_host(vcpu, vcpu_get_reg(vcpu, rt),
+                                              len);
 
                trace_kvm_mmio(KVM_TRACE_MMIO_WRITE, len, fault_ipa, data);
                mmio_write_buf(data_buf, len, data);
index 6984342da13d09fd0194563f4b598cfb913ec6c1..61d96a645ff38aa6e304eea5a198373958fe69cb 100644 (file)
@@ -98,6 +98,11 @@ static void kvm_flush_dcache_pud(pud_t pud)
        __kvm_flush_dcache_pud(pud);
 }
 
+static bool kvm_is_device_pfn(unsigned long pfn)
+{
+       return !pfn_valid(pfn);
+}
+
 /**
  * stage2_dissolve_pmd() - clear and flush huge PMD entry
  * @kvm:       pointer to kvm structure.
@@ -213,7 +218,7 @@ static void unmap_ptes(struct kvm *kvm, pmd_t *pmd,
                        kvm_tlb_flush_vmid_ipa(kvm, addr);
 
                        /* No need to invalidate the cache for device mappings */
-                       if ((pte_val(old_pte) & PAGE_S2_DEVICE) != PAGE_S2_DEVICE)
+                       if (!kvm_is_device_pfn(pte_pfn(old_pte)))
                                kvm_flush_dcache_pte(old_pte);
 
                        put_page(virt_to_page(pte));
@@ -305,8 +310,7 @@ static void stage2_flush_ptes(struct kvm *kvm, pmd_t *pmd,
 
        pte = pte_offset_kernel(pmd, addr);
        do {
-               if (!pte_none(*pte) &&
-                   (pte_val(*pte) & PAGE_S2_DEVICE) != PAGE_S2_DEVICE)
+               if (!pte_none(*pte) && !kvm_is_device_pfn(pte_pfn(*pte)))
                        kvm_flush_dcache_pte(*pte);
        } while (pte++, addr += PAGE_SIZE, addr != end);
 }
@@ -1037,11 +1041,6 @@ static bool kvm_is_write_fault(struct kvm_vcpu *vcpu)
        return kvm_vcpu_dabt_iswrite(vcpu);
 }
 
-static bool kvm_is_device_pfn(unsigned long pfn)
-{
-       return !pfn_valid(pfn);
-}
-
 /**
  * stage2_wp_ptes - write protect PMD range
  * @pmd:       pointer to pmd entry
index 0b556968a6da1e97e4b6232d1dd8e588a13bfa9e..a9b3b905e661dec55672e459f1119b3eb466b373 100644 (file)
@@ -75,7 +75,7 @@ static unsigned long kvm_psci_vcpu_on(struct kvm_vcpu *source_vcpu)
        unsigned long context_id;
        phys_addr_t target_pc;
 
-       cpu_id = *vcpu_reg(source_vcpu, 1) & MPIDR_HWID_BITMASK;
+       cpu_id = vcpu_get_reg(source_vcpu, 1) & MPIDR_HWID_BITMASK;
        if (vcpu_mode_is_32bit(source_vcpu))
                cpu_id &= ~((u32) 0);
 
@@ -94,8 +94,8 @@ static unsigned long kvm_psci_vcpu_on(struct kvm_vcpu *source_vcpu)
                        return PSCI_RET_INVALID_PARAMS;
        }
 
-       target_pc = *vcpu_reg(source_vcpu, 2);
-       context_id = *vcpu_reg(source_vcpu, 3);
+       target_pc = vcpu_get_reg(source_vcpu, 2);
+       context_id = vcpu_get_reg(source_vcpu, 3);
 
        kvm_reset_vcpu(vcpu);
 
@@ -114,7 +114,7 @@ static unsigned long kvm_psci_vcpu_on(struct kvm_vcpu *source_vcpu)
         * NOTE: We always update r0 (or x0) because for PSCI v0.1
         * the general puspose registers are undefined upon CPU_ON.
         */
-       *vcpu_reg(vcpu, 0) = context_id;
+       vcpu_set_reg(vcpu, 0, context_id);
        vcpu->arch.power_off = false;
        smp_mb();               /* Make sure the above is visible */
 
@@ -134,8 +134,8 @@ static unsigned long kvm_psci_vcpu_affinity_info(struct kvm_vcpu *vcpu)
        struct kvm *kvm = vcpu->kvm;
        struct kvm_vcpu *tmp;
 
-       target_affinity = *vcpu_reg(vcpu, 1);
-       lowest_affinity_level = *vcpu_reg(vcpu, 2);
+       target_affinity = vcpu_get_reg(vcpu, 1);
+       lowest_affinity_level = vcpu_get_reg(vcpu, 2);
 
        /* Determine target affinity mask */
        target_affinity_mask = psci_affinity_mask(lowest_affinity_level);
@@ -209,7 +209,7 @@ int kvm_psci_version(struct kvm_vcpu *vcpu)
 static int kvm_psci_0_2_call(struct kvm_vcpu *vcpu)
 {
        int ret = 1;
-       unsigned long psci_fn = *vcpu_reg(vcpu, 0) & ~((u32) 0);
+       unsigned long psci_fn = vcpu_get_reg(vcpu, 0) & ~((u32) 0);
        unsigned long val;
 
        switch (psci_fn) {
@@ -273,13 +273,13 @@ static int kvm_psci_0_2_call(struct kvm_vcpu *vcpu)
                break;
        }
 
-       *vcpu_reg(vcpu, 0) = val;
+       vcpu_set_reg(vcpu, 0, val);
        return ret;
 }
 
 static int kvm_psci_0_1_call(struct kvm_vcpu *vcpu)
 {
-       unsigned long psci_fn = *vcpu_reg(vcpu, 0) & ~((u32) 0);
+       unsigned long psci_fn = vcpu_get_reg(vcpu, 0) & ~((u32) 0);
        unsigned long val;
 
        switch (psci_fn) {
@@ -295,7 +295,7 @@ static int kvm_psci_0_1_call(struct kvm_vcpu *vcpu)
                break;
        }
 
-       *vcpu_reg(vcpu, 0) = val;
+       vcpu_set_reg(vcpu, 0, val);
        return 1;
 }
 
index d72b90905132487257220939a255ac7ed1d3754d..588bbc288396ae52fe0d801bc537906b3e5dbfce 100644 (file)
@@ -88,6 +88,7 @@ pin_page_for_write(const void __user *_addr, pte_t **ptep, spinlock_t **ptlp)
 static unsigned long noinline
 __copy_to_user_memcpy(void __user *to, const void *from, unsigned long n)
 {
+       unsigned long ua_flags;
        int atomic;
 
        if (unlikely(segment_eq(get_fs(), KERNEL_DS))) {
@@ -118,7 +119,9 @@ __copy_to_user_memcpy(void __user *to, const void *from, unsigned long n)
                if (tocopy > n)
                        tocopy = n;
 
+               ua_flags = uaccess_save_and_enable();
                memcpy((void *)to, from, tocopy);
+               uaccess_restore(ua_flags);
                to += tocopy;
                from += tocopy;
                n -= tocopy;
@@ -145,14 +148,21 @@ arm_copy_to_user(void __user *to, const void *from, unsigned long n)
         * With frame pointer disabled, tail call optimization kicks in
         * as well making this test almost invisible.
         */
-       if (n < 64)
-               return __copy_to_user_std(to, from, n);
-       return __copy_to_user_memcpy(to, from, n);
+       if (n < 64) {
+               unsigned long ua_flags = uaccess_save_and_enable();
+               n = __copy_to_user_std(to, from, n);
+               uaccess_restore(ua_flags);
+       } else {
+               n = __copy_to_user_memcpy(to, from, n);
+       }
+       return n;
 }
        
 static unsigned long noinline
 __clear_user_memset(void __user *addr, unsigned long n)
 {
+       unsigned long ua_flags;
+
        if (unlikely(segment_eq(get_fs(), KERNEL_DS))) {
                memset((void *)addr, 0, n);
                return 0;
@@ -175,7 +185,9 @@ __clear_user_memset(void __user *addr, unsigned long n)
                if (tocopy > n)
                        tocopy = n;
 
+               ua_flags = uaccess_save_and_enable();
                memset((void *)addr, 0, tocopy);
+               uaccess_restore(ua_flags);
                addr += tocopy;
                n -= tocopy;
 
@@ -193,9 +205,14 @@ out:
 unsigned long arm_clear_user(void __user *addr, unsigned long n)
 {
        /* See rational for this in __copy_to_user() above. */
-       if (n < 64)
-               return __clear_user_std(addr, n);
-       return __clear_user_memset(addr, n);
+       if (n < 64) {
+               unsigned long ua_flags = uaccess_save_and_enable();
+               n = __clear_user_std(addr, n);
+               uaccess_restore(ua_flags);
+       } else {
+               n = __clear_user_memset(addr, n);
+       }
+       return n;
 }
 
 #if 0
index 92673006e55c410ad27f60675c8e74bbf1433861..28656c2b54a0baadcc0aeaa6564cd1d91b592259 100644 (file)
@@ -4,7 +4,6 @@ menuconfig ARCH_AT91
        select ARCH_REQUIRE_GPIOLIB
        select COMMON_CLK_AT91
        select PINCTRL
-       select PINCTRL_AT91
        select SOC_BUS
 
 if ARCH_AT91
@@ -17,6 +16,7 @@ config SOC_SAMA5D2
        select HAVE_AT91_USB_CLK
        select HAVE_AT91_H32MX
        select HAVE_AT91_GENERATED_CLK
+       select PINCTRL_AT91PIO4
        help
          Select this if ou are using one of Atmel's SAMA5D2 family SoC.
 
@@ -27,6 +27,7 @@ config SOC_SAMA5D3
        select HAVE_AT91_UTMI
        select HAVE_AT91_SMD
        select HAVE_AT91_USB_CLK
+       select PINCTRL_AT91
        help
          Select this if you are using one of Atmel's SAMA5D3 family SoC.
          This support covers SAMA5D31, SAMA5D33, SAMA5D34, SAMA5D35, SAMA5D36.
@@ -40,6 +41,7 @@ config SOC_SAMA5D4
        select HAVE_AT91_SMD
        select HAVE_AT91_USB_CLK
        select HAVE_AT91_H32MX
+       select PINCTRL_AT91
        help
          Select this if you are using one of Atmel's SAMA5D4 family SoC.
 
@@ -50,6 +52,7 @@ config SOC_AT91RM9200
        select CPU_ARM920T
        select HAVE_AT91_USB_CLK
        select MIGHT_HAVE_PCI
+       select PINCTRL_AT91
        select SOC_SAM_V4_V5
        select SRAM if PM
        help
@@ -65,6 +68,7 @@ config SOC_AT91SAM9
        select HAVE_AT91_UTMI
        select HAVE_FB_ATMEL
        select MEMORY
+       select PINCTRL_AT91
        select SOC_SAM_V4_V5
        select SRAM if PM
        help
index 80e277cfcc8b6965d954473d877b66f91cdec52c..23726fb31741ea1479733ef91e88ac5585f7fe52 100644 (file)
  * implementation should be moved down into the pinctrl driver and get
  * called as part of the generic suspend/resume path.
  */
+#ifdef CONFIG_PINCTRL_AT91
 extern void at91_pinctrl_gpio_suspend(void);
 extern void at91_pinctrl_gpio_resume(void);
+#endif
 
 static struct {
        unsigned long uhp_udp_mask;
@@ -151,8 +153,9 @@ static void at91_pm_suspend(suspend_state_t state)
 
 static int at91_pm_enter(suspend_state_t state)
 {
+#ifdef CONFIG_PINCTRL_AT91
        at91_pinctrl_gpio_suspend();
-
+#endif
        switch (state) {
        /*
         * Suspend-to-RAM is like STANDBY plus slow clock mode, so
@@ -192,7 +195,9 @@ static int at91_pm_enter(suspend_state_t state)
 error:
        target_state = PM_SUSPEND_ON;
 
+#ifdef CONFIG_PINCTRL_AT91
        at91_pinctrl_gpio_resume();
+#endif
        return 0;
 }
 
index 72d622baaad3165ee3e920e6c5fc774e79cf26c5..df1d44bdc375b8c053ca258aa6e6027697e9fc98 100644 (file)
        @ check low interrupts
        ldr     \irqstat, [\base, #IRQ_CAUSE_LOW_OFF]
        ldr     \tmp, [\base, #IRQ_MASK_LOW_OFF]
-       mov     \irqnr, #31
+       mov     \irqnr, #32
        ands    \irqstat, \irqstat, \tmp
 
        @ if no low interrupts set, check high interrupts
        ldreq   \irqstat, [\base, #IRQ_CAUSE_HIGH_OFF]
        ldreq   \tmp, [\base, #IRQ_MASK_HIGH_OFF]
-       moveq   \irqnr, #63
+       moveq   \irqnr, #64
        andeqs  \irqstat, \irqstat, \tmp
 
        @ find first active interrupt source
index de68938ee6aa89a070c910c6de1cf1f5035cf0a4..c21e41dad19c14a66b83bcee65af4b504d8172c7 100644 (file)
@@ -748,8 +748,12 @@ static void exynos5_powerdown_conf(enum sys_powerdown mode)
 void exynos_sys_powerdown_conf(enum sys_powerdown mode)
 {
        unsigned int i;
+       const struct exynos_pmu_data *pmu_data;
+
+       if (!pmu_context)
+               return;
 
-       const struct exynos_pmu_data *pmu_data = pmu_context->pmu_data;
+       pmu_data = pmu_context->pmu_data;
 
        if (pmu_data->powerdown_conf)
                pmu_data->powerdown_conf(mode);
index 8e7976a4c3e723e1b27a08928700bac2b6cb9a09..cfc696b972f323e07b5e9a180755130e63e5e1b2 100644 (file)
@@ -177,6 +177,7 @@ static struct irq_chip imx_gpc_chip = {
        .irq_unmask             = imx_gpc_irq_unmask,
        .irq_retrigger          = irq_chip_retrigger_hierarchy,
        .irq_set_wake           = imx_gpc_irq_set_wake,
+       .irq_set_type           = irq_chip_set_type_parent,
 #ifdef CONFIG_SMP
        .irq_set_affinity       = irq_chip_set_affinity_parent,
 #endif
index b024390199639ca31201730ccdbcfceae577be2b..7a0c13bf42694b724e0fcb35439070eefde0a646 100644 (file)
@@ -143,7 +143,7 @@ static inline void __indirect_writesl(volatile void __iomem *bus_addr,
                writel(*vaddr++, bus_addr);
 }
 
-static inline unsigned char __indirect_readb(const volatile void __iomem *p)
+static inline u8 __indirect_readb(const volatile void __iomem *p)
 {
        u32 addr = (u32)p;
        u32 n, byte_enables, data;
@@ -166,7 +166,7 @@ static inline void __indirect_readsb(const volatile void __iomem *bus_addr,
                *vaddr++ = readb(bus_addr);
 }
 
-static inline unsigned short __indirect_readw(const volatile void __iomem *p)
+static inline u16 __indirect_readw(const volatile void __iomem *p)
 {
        u32 addr = (u32)p;
        u32 n, byte_enables, data;
@@ -189,7 +189,7 @@ static inline void __indirect_readsw(const volatile void __iomem *bus_addr,
                *vaddr++ = readw(bus_addr);
 }
 
-static inline unsigned long __indirect_readl(const volatile void __iomem *p)
+static inline u32 __indirect_readl(const volatile void __iomem *p)
 {
        u32 addr = (__force u32)p;
        u32 data;
@@ -350,7 +350,7 @@ static inline void insl(u32 io_addr, void *p, u32 count)
                                        ((unsigned long)p <= (PIO_MASK + PIO_OFFSET)))
 
 #define        ioread8(p)                      ioread8(p)
-static inline unsigned int ioread8(const void __iomem *addr)
+static inline u8 ioread8(const void __iomem *addr)
 {
        unsigned long port = (unsigned long __force)addr;
        if (__is_io_address(port))
@@ -378,7 +378,7 @@ static inline void ioread8_rep(const void __iomem *addr, void *vaddr, u32 count)
 }
 
 #define        ioread16(p)                     ioread16(p)
-static inline unsigned int ioread16(const void __iomem *addr)
+static inline u16 ioread16(const void __iomem *addr)
 {
        unsigned long port = (unsigned long __force)addr;
        if (__is_io_address(port))
@@ -407,7 +407,7 @@ static inline void ioread16_rep(const void __iomem *addr, void *vaddr,
 }
 
 #define        ioread32(p)                     ioread32(p)
-static inline unsigned int ioread32(const void __iomem *addr)
+static inline u32 ioread32(const void __iomem *addr)
 {
        unsigned long port = (unsigned long __force)addr;
        if (__is_io_address(port))
index 5076d3f334d28753e697b9e801b050c5807cadad..0517f0c1581a71091539c5c1abe47473f4b789ef 100644 (file)
@@ -65,6 +65,8 @@ config SOC_AM43XX
        select MACH_OMAP_GENERIC
        select MIGHT_HAVE_CACHE_L2X0
        select HAVE_ARM_SCU
+       select GENERIC_CLOCKEVENTS_BROADCAST
+       select HAVE_ARM_TWD
 
 config SOC_DRA7XX
        bool "TI DRA7XX"
@@ -121,6 +123,7 @@ config ARCH_OMAP2PLUS_TYPICAL
        select NEON if CPU_V7
        select PM
        select REGULATOR
+       select REGULATOR_FIXED_VOLTAGE
        select TWL4030_CORE if ARCH_OMAP3 || ARCH_OMAP4
        select TWL4030_POWER if ARCH_OMAP3 || ARCH_OMAP4
        select VFP
@@ -201,7 +204,6 @@ config MACH_OMAP3_PANDORA
        depends on ARCH_OMAP3
        default y
        select OMAP_PACKAGE_CBB
-       select REGULATOR_FIXED_VOLTAGE if REGULATOR
 
 config MACH_NOKIA_N810
        bool
index 5305ec7341eca5579398a10b72f263a2fbbe8e0e..79e1f876d1c9b9f28dc862e013e7bc657153fd4f 100644 (file)
@@ -143,9 +143,9 @@ static int omap4_boot_secondary(unsigned int cpu, struct task_struct *idle)
                 * Ensure that CPU power state is set to ON to avoid CPU
                 * powerdomain transition on wfi
                 */
-               clkdm_wakeup(cpu1_clkdm);
-               omap_set_pwrdm_state(cpu1_pwrdm, PWRDM_POWER_ON);
-               clkdm_allow_idle(cpu1_clkdm);
+               clkdm_wakeup_nolock(cpu1_clkdm);
+               pwrdm_set_next_pwrst(cpu1_pwrdm, PWRDM_POWER_ON);
+               clkdm_allow_idle_nolock(cpu1_clkdm);
 
                if (IS_PM44XX_ERRATUM(PM_OMAP4_ROM_SMP_BOOT_ERRATUM_GICD)) {
                        while (gic_dist_disabled()) {
index cc8a987149e2737db4bf255075d5baf3bc2b2bb0..48495ad82aba16775ff2108ead31ceb820a023b5 100644 (file)
@@ -890,6 +890,36 @@ static int _init_opt_clks(struct omap_hwmod *oh)
        return ret;
 }
 
+static void _enable_optional_clocks(struct omap_hwmod *oh)
+{
+       struct omap_hwmod_opt_clk *oc;
+       int i;
+
+       pr_debug("omap_hwmod: %s: enabling optional clocks\n", oh->name);
+
+       for (i = oh->opt_clks_cnt, oc = oh->opt_clks; i > 0; i--, oc++)
+               if (oc->_clk) {
+                       pr_debug("omap_hwmod: enable %s:%s\n", oc->role,
+                                __clk_get_name(oc->_clk));
+                       clk_enable(oc->_clk);
+               }
+}
+
+static void _disable_optional_clocks(struct omap_hwmod *oh)
+{
+       struct omap_hwmod_opt_clk *oc;
+       int i;
+
+       pr_debug("omap_hwmod: %s: disabling optional clocks\n", oh->name);
+
+       for (i = oh->opt_clks_cnt, oc = oh->opt_clks; i > 0; i--, oc++)
+               if (oc->_clk) {
+                       pr_debug("omap_hwmod: disable %s:%s\n", oc->role,
+                                __clk_get_name(oc->_clk));
+                       clk_disable(oc->_clk);
+               }
+}
+
 /**
  * _enable_clocks - enable hwmod main clock and interface clocks
  * @oh: struct omap_hwmod *
@@ -917,6 +947,9 @@ static int _enable_clocks(struct omap_hwmod *oh)
                        clk_enable(os->_clk);
        }
 
+       if (oh->flags & HWMOD_OPT_CLKS_NEEDED)
+               _enable_optional_clocks(oh);
+
        /* The opt clocks are controlled by the device driver. */
 
        return 0;
@@ -948,41 +981,14 @@ static int _disable_clocks(struct omap_hwmod *oh)
                        clk_disable(os->_clk);
        }
 
+       if (oh->flags & HWMOD_OPT_CLKS_NEEDED)
+               _disable_optional_clocks(oh);
+
        /* The opt clocks are controlled by the device driver. */
 
        return 0;
 }
 
-static void _enable_optional_clocks(struct omap_hwmod *oh)
-{
-       struct omap_hwmod_opt_clk *oc;
-       int i;
-
-       pr_debug("omap_hwmod: %s: enabling optional clocks\n", oh->name);
-
-       for (i = oh->opt_clks_cnt, oc = oh->opt_clks; i > 0; i--, oc++)
-               if (oc->_clk) {
-                       pr_debug("omap_hwmod: enable %s:%s\n", oc->role,
-                                __clk_get_name(oc->_clk));
-                       clk_enable(oc->_clk);
-               }
-}
-
-static void _disable_optional_clocks(struct omap_hwmod *oh)
-{
-       struct omap_hwmod_opt_clk *oc;
-       int i;
-
-       pr_debug("omap_hwmod: %s: disabling optional clocks\n", oh->name);
-
-       for (i = oh->opt_clks_cnt, oc = oh->opt_clks; i > 0; i--, oc++)
-               if (oc->_clk) {
-                       pr_debug("omap_hwmod: disable %s:%s\n", oc->role,
-                                __clk_get_name(oc->_clk));
-                       clk_disable(oc->_clk);
-               }
-}
-
 /**
  * _omap4_enable_module - enable CLKCTRL modulemode on OMAP4
  * @oh: struct omap_hwmod *
index ca6df1a734756fa6640067b9158dc1112e37b2a1..76bce11c85a40c477a5b87aab919d5b8dfded5e8 100644 (file)
@@ -523,6 +523,8 @@ struct omap_hwmod_omap4_prcm {
  * HWMOD_RECONFIG_IO_CHAIN: omap_hwmod code needs to reconfigure wake-up 
  *     events by calling _reconfigure_io_chain() when a device is enabled
  *     or idled.
+ * HWMOD_OPT_CLKS_NEEDED: The optional clocks are needed for the module to
+ *     operate and they need to be handled at the same time as the main_clk.
  */
 #define HWMOD_SWSUP_SIDLE                      (1 << 0)
 #define HWMOD_SWSUP_MSTANDBY                   (1 << 1)
@@ -538,6 +540,7 @@ struct omap_hwmod_omap4_prcm {
 #define HWMOD_FORCE_MSTANDBY                   (1 << 11)
 #define HWMOD_SWSUP_SIDLE_ACT                  (1 << 12)
 #define HWMOD_RECONFIG_IO_CHAIN                        (1 << 13)
+#define HWMOD_OPT_CLKS_NEEDED                  (1 << 14)
 
 /*
  * omap_hwmod._int_flags definitions
index 51d1ecb384bdddb95c1996258de93ee9ba9b85ec..ee4e04434a943ea573210fb2468ba29a36232f07 100644 (file)
@@ -1297,6 +1297,44 @@ static struct omap_hwmod dra7xx_mcspi4_hwmod = {
        .dev_attr       = &mcspi4_dev_attr,
 };
 
+/*
+ * 'mcasp' class
+ *
+ */
+static struct omap_hwmod_class_sysconfig dra7xx_mcasp_sysc = {
+       .sysc_offs      = 0x0004,
+       .sysc_flags     = SYSC_HAS_SIDLEMODE,
+       .idlemodes      = (SIDLE_FORCE | SIDLE_NO | SIDLE_SMART),
+       .sysc_fields    = &omap_hwmod_sysc_type3,
+};
+
+static struct omap_hwmod_class dra7xx_mcasp_hwmod_class = {
+       .name   = "mcasp",
+       .sysc   = &dra7xx_mcasp_sysc,
+};
+
+/* mcasp3 */
+static struct omap_hwmod_opt_clk mcasp3_opt_clks[] = {
+       { .role = "ahclkx", .clk = "mcasp3_ahclkx_mux" },
+};
+
+static struct omap_hwmod dra7xx_mcasp3_hwmod = {
+       .name           = "mcasp3",
+       .class          = &dra7xx_mcasp_hwmod_class,
+       .clkdm_name     = "l4per2_clkdm",
+       .main_clk       = "mcasp3_aux_gfclk_mux",
+       .flags          = HWMOD_OPT_CLKS_NEEDED,
+       .prcm = {
+               .omap4 = {
+                       .clkctrl_offs = DRA7XX_CM_L4PER2_MCASP3_CLKCTRL_OFFSET,
+                       .context_offs = DRA7XX_RM_L4PER2_MCASP3_CONTEXT_OFFSET,
+                       .modulemode   = MODULEMODE_SWCTRL,
+               },
+       },
+       .opt_clks       = mcasp3_opt_clks,
+       .opt_clks_cnt   = ARRAY_SIZE(mcasp3_opt_clks),
+};
+
 /*
  * 'mmc' class
  *
@@ -2566,6 +2604,22 @@ static struct omap_hwmod_ocp_if dra7xx_l3_main_1__hdmi = {
        .user           = OCP_USER_MPU | OCP_USER_SDMA,
 };
 
+/* l4_per2 -> mcasp3 */
+static struct omap_hwmod_ocp_if dra7xx_l4_per2__mcasp3 = {
+       .master         = &dra7xx_l4_per2_hwmod,
+       .slave          = &dra7xx_mcasp3_hwmod,
+       .clk            = "l4_root_clk_div",
+       .user           = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* l3_main_1 -> mcasp3 */
+static struct omap_hwmod_ocp_if dra7xx_l3_main_1__mcasp3 = {
+       .master         = &dra7xx_l3_main_1_hwmod,
+       .slave          = &dra7xx_mcasp3_hwmod,
+       .clk            = "l3_iclk_div",
+       .user           = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
 /* l4_per1 -> elm */
 static struct omap_hwmod_ocp_if dra7xx_l4_per1__elm = {
        .master         = &dra7xx_l4_per1_hwmod,
@@ -3308,6 +3362,8 @@ static struct omap_hwmod_ocp_if *dra7xx_hwmod_ocp_ifs[] __initdata = {
        &dra7xx_l4_wkup__dcan1,
        &dra7xx_l4_per2__dcan2,
        &dra7xx_l4_per2__cpgmac0,
+       &dra7xx_l4_per2__mcasp3,
+       &dra7xx_l3_main_1__mcasp3,
        &dra7xx_gmac__mdio,
        &dra7xx_l4_cfg__dma_system,
        &dra7xx_l3_main_1__dss,
index b1288f56d5095b4ad782e81b0453c9094ec47ac1..6256052893ec7b1453c3d0afb6e392c321040567 100644 (file)
@@ -144,6 +144,7 @@ static struct omap_hwmod dm81xx_l4_ls_hwmod = {
        .name           = "l4_ls",
        .clkdm_name     = "alwon_l3s_clkdm",
        .class          = &l4_hwmod_class,
+       .flags          = HWMOD_NO_IDLEST,
 };
 
 /*
@@ -155,6 +156,7 @@ static struct omap_hwmod dm81xx_l4_hs_hwmod = {
        .name           = "l4_hs",
        .clkdm_name     = "alwon_l3_med_clkdm",
        .class          = &l4_hwmod_class,
+       .flags          = HWMOD_NO_IDLEST,
 };
 
 /* L3 slow -> L4 ls peripheral interface running at 125MHz */
@@ -850,6 +852,7 @@ static struct omap_hwmod dm816x_emac0_hwmod = {
        .name           = "emac0",
        .clkdm_name     = "alwon_ethernet_clkdm",
        .class          = &dm816x_emac_hwmod_class,
+       .flags          = HWMOD_NO_IDLEST,
 };
 
 static struct omap_hwmod_ocp_if dm81xx_l4_hs__emac0 = {
index 1dfe34654c43a353a34ac2cb9b941ff9f951b275..58144779dec4c118aac35f60cab6f0c33a68929a 100644 (file)
@@ -24,9 +24,6 @@
 #include <linux/platform_data/iommu-omap.h>
 #include <linux/platform_data/wkup_m3.h>
 
-#include <asm/siginfo.h>
-#include <asm/signal.h>
-
 #include "common.h"
 #include "common-board-devices.h"
 #include "dss-common.h"
@@ -385,29 +382,6 @@ static void __init omap3_pandora_legacy_init(void)
 }
 #endif /* CONFIG_ARCH_OMAP3 */
 
-#ifdef CONFIG_SOC_TI81XX
-static int fault_fixed_up;
-
-static int t410_abort_handler(unsigned long addr, unsigned int fsr,
-                             struct pt_regs *regs)
-{
-       if ((fsr == 0x406 || fsr == 0xc06) && !fault_fixed_up) {
-               pr_warn("External imprecise Data abort at addr=%#lx, fsr=%#x ignored.\n",
-                       addr, fsr);
-               fault_fixed_up = 1;
-               return 0;
-       }
-
-       return 1;
-}
-
-static void __init t410_abort_init(void)
-{
-       hook_fault_code(16 + 6, t410_abort_handler, SIGBUS, BUS_OBJERR,
-                       "imprecise external abort");
-}
-#endif
-
 #if defined(CONFIG_ARCH_OMAP4) || defined(CONFIG_SOC_OMAP5)
 static struct iommu_platform_data omap4_iommu_pdata = {
        .reset_name = "mmu_cache",
@@ -536,9 +510,6 @@ static struct pdata_init pdata_quirks[] __initdata = {
        { "openpandora,omap3-pandora-600mhz", omap3_pandora_legacy_init, },
        { "openpandora,omap3-pandora-1ghz", omap3_pandora_legacy_init, },
 #endif
-#ifdef CONFIG_SOC_TI81XX
-       { "hp,t410", t410_abort_init, },
-#endif
 #ifdef CONFIG_SOC_OMAP5
        { "ti,omap5-uevm", omap5_uevm_legacy_init, },
 #endif
index 87b98bf92366f4f816ca4f53a32ecae305930016..2dbd3785ee6f0d00b4c3d88bada28d83c0203b2a 100644 (file)
@@ -301,11 +301,11 @@ static void omap3_pm_idle(void)
        if (omap_irq_pending())
                return;
 
-       trace_cpu_idle(1, smp_processor_id());
+       trace_cpu_idle_rcuidle(1, smp_processor_id());
 
        omap_sram_idle();
 
-       trace_cpu_idle(PWR_EVENT_EXIT, smp_processor_id());
+       trace_cpu_idle_rcuidle(PWR_EVENT_EXIT, smp_processor_id());
 }
 
 #ifdef CONFIG_SUSPEND
index b18ebbefae09577e20b19e53167aca5ef11b8d86..f86692dbcfd56efce7250b3a659891ad57a45725 100644 (file)
@@ -320,6 +320,12 @@ static int __init omap_dm_timer_init_one(struct omap_dm_timer *timer,
        return r;
 }
 
+#if !defined(CONFIG_SMP) && defined(CONFIG_GENERIC_CLOCKEVENTS_BROADCAST)
+void tick_broadcast(const struct cpumask *mask)
+{
+}
+#endif
+
 static void __init omap2_gp_clockevent_init(int gptimer_id,
                                                const char *fck_source,
                                                const char *property)
index 79eb502a1e64a67a7b716d0b31d7db0903aeab9f..73919a36b5775f1facd9cde91be9ef872ab7e18e 100644 (file)
@@ -21,5 +21,5 @@
        @ find cause bits that are unmasked
        ands    \irqstat, \irqstat, \tmp        @ clear Z flag if any
        clzne   \irqnr, \irqstat                @ calc irqnr
-       rsbne   \irqnr, \irqnr, #31
+       rsbne   \irqnr, \irqnr, #32
        .endm
index 9a9c15bfcd3451f02c115238813b2193db266844..7c0d5618be5e8b6f394cec5f4d797ad931675735 100644 (file)
@@ -889,6 +889,7 @@ static void __init e680_init(void)
 
        pxa_set_keypad_info(&e680_keypad_platform_data);
 
+       pwm_add_table(ezx_pwm_lookup, ARRAY_SIZE(ezx_pwm_lookup));
        platform_add_devices(ARRAY_AND_SIZE(ezx_devices));
        platform_add_devices(ARRAY_AND_SIZE(e680_devices));
 }
@@ -956,6 +957,7 @@ static void __init a1200_init(void)
 
        pxa_set_keypad_info(&a1200_keypad_platform_data);
 
+       pwm_add_table(ezx_pwm_lookup, ARRAY_SIZE(ezx_pwm_lookup));
        platform_add_devices(ARRAY_AND_SIZE(ezx_devices));
        platform_add_devices(ARRAY_AND_SIZE(a1200_devices));
 }
@@ -1148,6 +1150,7 @@ static void __init a910_init(void)
                platform_device_register(&a910_camera);
        }
 
+       pwm_add_table(ezx_pwm_lookup, ARRAY_SIZE(ezx_pwm_lookup));
        platform_add_devices(ARRAY_AND_SIZE(ezx_devices));
        platform_add_devices(ARRAY_AND_SIZE(a910_devices));
 }
@@ -1215,6 +1218,7 @@ static void __init e6_init(void)
 
        pxa_set_keypad_info(&e6_keypad_platform_data);
 
+       pwm_add_table(ezx_pwm_lookup, ARRAY_SIZE(ezx_pwm_lookup));
        platform_add_devices(ARRAY_AND_SIZE(ezx_devices));
        platform_add_devices(ARRAY_AND_SIZE(e6_devices));
 }
@@ -1256,6 +1260,7 @@ static void __init e2_init(void)
 
        pxa_set_keypad_info(&e2_keypad_platform_data);
 
+       pwm_add_table(ezx_pwm_lookup, ARRAY_SIZE(ezx_pwm_lookup));
        platform_add_devices(ARRAY_AND_SIZE(ezx_devices));
        platform_add_devices(ARRAY_AND_SIZE(e2_devices));
 }
index 13eba2b26e0aa478e7e26eb541855be091ac68e0..8fbfb10047ec30543b4ccf4c7e6787d9fd5ae5b0 100644 (file)
@@ -344,7 +344,7 @@ void __init palm27x_pwm_init(int bl, int lcd)
 {
        palm_bl_power   = bl;
        palm_lcd_power  = lcd;
-       pwm_add_lookup(palm27x_pwm_lookup, ARRAY_SIZE(palm27x_pwm_lookup));
+       pwm_add_table(palm27x_pwm_lookup, ARRAY_SIZE(palm27x_pwm_lookup));
        platform_device_register(&palm27x_backlight);
 }
 #endif
index aebf6de62468962b9398f6ee299c0539920cbba8..0b5c3876720cc3215949a6cbcf017bdf41f1eec8 100644 (file)
@@ -169,7 +169,7 @@ static inline void palmtc_keys_init(void) {}
 #if defined(CONFIG_BACKLIGHT_PWM) || defined(CONFIG_BACKLIGHT_PWM_MODULE)
 static struct pwm_lookup palmtc_pwm_lookup[] = {
        PWM_LOOKUP("pxa25x-pwm.1", 0, "pwm-backlight.0", NULL, PALMTC_PERIOD_NS,
-                  PWM_PERIOD_NORMAL),
+                  PWM_POLARITY_NORMAL),
 };
 
 static struct platform_pwm_backlight_data palmtc_backlight_data = {
index a19460e6e7b0ec9317e8db98ed9aea2cf6290421..b355fca6cc2efb1a3fccd3763c91430acb66fd69 100644 (file)
@@ -20,7 +20,7 @@
 #include <plat/cpu.h>
 #include <plat/cpu-freq-core.h>
 
-static struct cpufreq_frequency_table s3c2440_plls_12[] __initdata = {
+static struct cpufreq_frequency_table s3c2440_plls_12[] = {
        { .frequency = 75000000,        .driver_data = PLLVAL(0x75, 3, 3),  },  /* FVco 600.000000 */
        { .frequency = 80000000,        .driver_data = PLLVAL(0x98, 4, 3),  },  /* FVco 640.000000 */
        { .frequency = 90000000,        .driver_data = PLLVAL(0x70, 2, 3),  },  /* FVco 720.000000 */
index 1191b29056252e49eee5cc041e0757247dab1bdf..be9a248b5ce901b5eaed665ec4f5d75632775ebc 100644 (file)
@@ -20,7 +20,7 @@
 #include <plat/cpu.h>
 #include <plat/cpu-freq-core.h>
 
-static struct cpufreq_frequency_table s3c2440_plls_169344[] __initdata = {
+static struct cpufreq_frequency_table s3c2440_plls_169344[] = {
        { .frequency = 78019200,        .driver_data = PLLVAL(121, 5, 3),       },      /* FVco 624.153600 */
        { .frequency = 84067200,        .driver_data = PLLVAL(131, 5, 3),       },      /* FVco 672.537600 */
        { .frequency = 90115200,        .driver_data = PLLVAL(141, 5, 3),       },      /* FVco 720.921600 */
index ff780a8d8366fbe5463b665ea3d53c14d797a569..b57783371d525976946f3f47a2b37933308756f9 100644 (file)
@@ -54,12 +54,13 @@ static int s3c64xx_i2s_cfg_gpio(struct platform_device *pdev)
 
 static struct resource s3c64xx_iis0_resource[] = {
        [0] = DEFINE_RES_MEM(S3C64XX_PA_IIS0, SZ_256),
-       [1] = DEFINE_RES_DMA(DMACH_I2S0_OUT),
-       [2] = DEFINE_RES_DMA(DMACH_I2S0_IN),
 };
 
-static struct s3c_audio_pdata i2sv3_pdata = {
+static struct s3c_audio_pdata i2s0_pdata = {
        .cfg_gpio = s3c64xx_i2s_cfg_gpio,
+       .dma_filter = pl08x_filter_id,
+       .dma_playback = DMACH_I2S0_OUT,
+       .dma_capture = DMACH_I2S0_IN,
 };
 
 struct platform_device s3c64xx_device_iis0 = {
@@ -68,15 +69,20 @@ struct platform_device s3c64xx_device_iis0 = {
        .num_resources    = ARRAY_SIZE(s3c64xx_iis0_resource),
        .resource         = s3c64xx_iis0_resource,
        .dev = {
-               .platform_data = &i2sv3_pdata,
+               .platform_data = &i2s0_pdata,
        },
 };
 EXPORT_SYMBOL(s3c64xx_device_iis0);
 
 static struct resource s3c64xx_iis1_resource[] = {
        [0] = DEFINE_RES_MEM(S3C64XX_PA_IIS1, SZ_256),
-       [1] = DEFINE_RES_DMA(DMACH_I2S1_OUT),
-       [2] = DEFINE_RES_DMA(DMACH_I2S1_IN),
+};
+
+static struct s3c_audio_pdata i2s1_pdata = {
+       .cfg_gpio = s3c64xx_i2s_cfg_gpio,
+       .dma_filter = pl08x_filter_id,
+       .dma_playback = DMACH_I2S1_OUT,
+       .dma_capture = DMACH_I2S1_IN,
 };
 
 struct platform_device s3c64xx_device_iis1 = {
@@ -85,19 +91,20 @@ struct platform_device s3c64xx_device_iis1 = {
        .num_resources    = ARRAY_SIZE(s3c64xx_iis1_resource),
        .resource         = s3c64xx_iis1_resource,
        .dev = {
-               .platform_data = &i2sv3_pdata,
+               .platform_data = &i2s1_pdata,
        },
 };
 EXPORT_SYMBOL(s3c64xx_device_iis1);
 
 static struct resource s3c64xx_iisv4_resource[] = {
        [0] = DEFINE_RES_MEM(S3C64XX_PA_IISV4, SZ_256),
-       [1] = DEFINE_RES_DMA(DMACH_HSI_I2SV40_TX),
-       [2] = DEFINE_RES_DMA(DMACH_HSI_I2SV40_RX),
 };
 
 static struct s3c_audio_pdata i2sv4_pdata = {
        .cfg_gpio = s3c64xx_i2s_cfg_gpio,
+       .dma_filter = pl08x_filter_id,
+       .dma_playback = DMACH_HSI_I2SV40_TX,
+       .dma_capture = DMACH_HSI_I2SV40_RX,
        .type = {
                .i2s = {
                        .quirks = QUIRK_PRI_6CHAN,
@@ -142,12 +149,13 @@ static int s3c64xx_pcm_cfg_gpio(struct platform_device *pdev)
 
 static struct resource s3c64xx_pcm0_resource[] = {
        [0] = DEFINE_RES_MEM(S3C64XX_PA_PCM0, SZ_256),
-       [1] = DEFINE_RES_DMA(DMACH_PCM0_TX),
-       [2] = DEFINE_RES_DMA(DMACH_PCM0_RX),
 };
 
 static struct s3c_audio_pdata s3c_pcm0_pdata = {
        .cfg_gpio = s3c64xx_pcm_cfg_gpio,
+       .dma_filter = pl08x_filter_id,
+       .dma_capture = DMACH_PCM0_RX,
+       .dma_playback = DMACH_PCM0_TX,
 };
 
 struct platform_device s3c64xx_device_pcm0 = {
@@ -163,12 +171,13 @@ EXPORT_SYMBOL(s3c64xx_device_pcm0);
 
 static struct resource s3c64xx_pcm1_resource[] = {
        [0] = DEFINE_RES_MEM(S3C64XX_PA_PCM1, SZ_256),
-       [1] = DEFINE_RES_DMA(DMACH_PCM1_TX),
-       [2] = DEFINE_RES_DMA(DMACH_PCM1_RX),
 };
 
 static struct s3c_audio_pdata s3c_pcm1_pdata = {
        .cfg_gpio = s3c64xx_pcm_cfg_gpio,
+       .dma_filter = pl08x_filter_id,
+       .dma_playback = DMACH_PCM1_TX,
+       .dma_capture = DMACH_PCM1_RX,
 };
 
 struct platform_device s3c64xx_device_pcm1 = {
@@ -196,13 +205,15 @@ static int s3c64xx_ac97_cfg_gpe(struct platform_device *pdev)
 
 static struct resource s3c64xx_ac97_resource[] = {
        [0] = DEFINE_RES_MEM(S3C64XX_PA_AC97, SZ_256),
-       [1] = DEFINE_RES_DMA(DMACH_AC97_PCMOUT),
-       [2] = DEFINE_RES_DMA(DMACH_AC97_PCMIN),
-       [3] = DEFINE_RES_DMA(DMACH_AC97_MICIN),
-       [4] = DEFINE_RES_IRQ(IRQ_AC97),
+       [1] = DEFINE_RES_IRQ(IRQ_AC97),
 };
 
-static struct s3c_audio_pdata s3c_ac97_pdata;
+static struct s3c_audio_pdata s3c_ac97_pdata = {
+       .dma_playback = DMACH_AC97_PCMOUT,
+       .dma_filter = pl08x_filter_id,
+       .dma_capture = DMACH_AC97_PCMIN,
+       .dma_capture_mic = DMACH_AC97_MICIN,
+};
 
 static u64 s3c64xx_ac97_dmamask = DMA_BIT_MASK(32);
 
index 096e14073bd9225f9218550ee5a9ce13053f4717..9c739eafe95c48a111721e9539907ee8bd8b95a4 100644 (file)
 #define S3C64XX_DMA_CHAN(name)         ((unsigned long)(name))
 
 /* DMA0/SDMA0 */
-#define DMACH_UART0            S3C64XX_DMA_CHAN("uart0_tx")
-#define DMACH_UART0_SRC2       S3C64XX_DMA_CHAN("uart0_rx")
-#define DMACH_UART1            S3C64XX_DMA_CHAN("uart1_tx")
-#define DMACH_UART1_SRC2       S3C64XX_DMA_CHAN("uart1_rx")
-#define DMACH_UART2            S3C64XX_DMA_CHAN("uart2_tx")
-#define DMACH_UART2_SRC2       S3C64XX_DMA_CHAN("uart2_rx")
-#define DMACH_UART3            S3C64XX_DMA_CHAN("uart3_tx")
-#define DMACH_UART3_SRC2       S3C64XX_DMA_CHAN("uart3_rx")
-#define DMACH_PCM0_TX          S3C64XX_DMA_CHAN("pcm0_tx")
-#define DMACH_PCM0_RX          S3C64XX_DMA_CHAN("pcm0_rx")
-#define DMACH_I2S0_OUT         S3C64XX_DMA_CHAN("i2s0_tx")
-#define DMACH_I2S0_IN          S3C64XX_DMA_CHAN("i2s0_rx")
+#define DMACH_UART0            "uart0_tx"
+#define DMACH_UART0_SRC2       "uart0_rx"
+#define DMACH_UART1            "uart1_tx"
+#define DMACH_UART1_SRC2       "uart1_rx"
+#define DMACH_UART2            "uart2_tx"
+#define DMACH_UART2_SRC2       "uart2_rx"
+#define DMACH_UART3            "uart3_tx"
+#define DMACH_UART3_SRC2       "uart3_rx"
+#define DMACH_PCM0_TX          "pcm0_tx"
+#define DMACH_PCM0_RX          "pcm0_rx"
+#define DMACH_I2S0_OUT         "i2s0_tx"
+#define DMACH_I2S0_IN          "i2s0_rx"
 #define DMACH_SPI0_TX          S3C64XX_DMA_CHAN("spi0_tx")
 #define DMACH_SPI0_RX          S3C64XX_DMA_CHAN("spi0_rx")
-#define DMACH_HSI_I2SV40_TX    S3C64XX_DMA_CHAN("i2s2_tx")
-#define DMACH_HSI_I2SV40_RX    S3C64XX_DMA_CHAN("i2s2_rx")
+#define DMACH_HSI_I2SV40_TX    "i2s2_tx"
+#define DMACH_HSI_I2SV40_RX    "i2s2_rx"
 
 /* DMA1/SDMA1 */
-#define DMACH_PCM1_TX          S3C64XX_DMA_CHAN("pcm1_tx")
-#define DMACH_PCM1_RX          S3C64XX_DMA_CHAN("pcm1_rx")
-#define DMACH_I2S1_OUT         S3C64XX_DMA_CHAN("i2s1_tx")
-#define DMACH_I2S1_IN          S3C64XX_DMA_CHAN("i2s1_rx")
+#define DMACH_PCM1_TX          "pcm1_tx"
+#define DMACH_PCM1_RX          "pcm1_rx"
+#define DMACH_I2S1_OUT         "i2s1_tx"
+#define DMACH_I2S1_IN          "i2s1_rx"
 #define DMACH_SPI1_TX          S3C64XX_DMA_CHAN("spi1_tx")
 #define DMACH_SPI1_RX          S3C64XX_DMA_CHAN("spi1_rx")
-#define DMACH_AC97_PCMOUT      S3C64XX_DMA_CHAN("ac97_out")
-#define DMACH_AC97_PCMIN       S3C64XX_DMA_CHAN("ac97_in")
-#define DMACH_AC97_MICIN       S3C64XX_DMA_CHAN("ac97_mic")
-#define DMACH_PWM              S3C64XX_DMA_CHAN("pwm")
-#define DMACH_IRDA             S3C64XX_DMA_CHAN("irda")
-#define DMACH_EXTERNAL         S3C64XX_DMA_CHAN("external")
-#define DMACH_SECURITY_RX      S3C64XX_DMA_CHAN("sec_rx")
-#define DMACH_SECURITY_TX      S3C64XX_DMA_CHAN("sec_tx")
+#define DMACH_AC97_PCMOUT      "ac97_out"
+#define DMACH_AC97_PCMIN       "ac97_in"
+#define DMACH_AC97_MICIN       "ac97_mic"
+#define DMACH_PWM              "pwm"
+#define DMACH_IRDA             "irda"
+#define DMACH_EXTERNAL         "external"
+#define DMACH_SECURITY_RX      "sec_rx"
+#define DMACH_SECURITY_TX      "sec_tx"
 
 enum dma_ch {
        DMACH_MAX = 32
index 1d2825cb7a65050bc7b05bed4b200f3e8036349a..5fce87f7f254c2fa4b052c5ab91d11a91e2e3a15 100644 (file)
@@ -19,7 +19,7 @@
 #include "common.h"
 #include "rcar-gen2.h"
 
-static const char *r8a7793_boards_compat_dt[] __initconst = {
+static const char * const r8a7793_boards_compat_dt[] __initconst = {
        "renesas,r8a7793",
        NULL,
 };
index 7fdc5bf24f9b5c05d055f59932b285db4b85d465..446334a25cf5c6f0db61a9c10558e6c1e57b7823 100644 (file)
@@ -13,7 +13,7 @@ config SOC_ZX296702
        select ARM_GLOBAL_TIMER
        select HAVE_ARM_SCU if SMP
        select HAVE_ARM_TWD if SMP
-       select PM_GENERIC_DOMAINS
+       select PM_GENERIC_DOMAINS if PM
        help
          Support for ZTE ZX296702 SoC which is a dual core CortexA9MP
 endif
index 845769e413323120b6d7b4afed7640746413bc98..c8c8b9ed02e09b57a79bee1ab5db9c337be0d338 100644 (file)
@@ -165,13 +165,28 @@ static void flush_context(unsigned int cpu)
                __flush_icache_all();
 }
 
-static int is_reserved_asid(u64 asid)
+static bool check_update_reserved_asid(u64 asid, u64 newasid)
 {
        int cpu;
-       for_each_possible_cpu(cpu)
-               if (per_cpu(reserved_asids, cpu) == asid)
-                       return 1;
-       return 0;
+       bool hit = false;
+
+       /*
+        * Iterate over the set of reserved ASIDs looking for a match.
+        * If we find one, then we can update our mm to use newasid
+        * (i.e. the same ASID in the current generation) but we can't
+        * exit the loop early, since we need to ensure that all copies
+        * of the old ASID are updated to reflect the mm. Failure to do
+        * so could result in us missing the reserved ASID in a future
+        * generation.
+        */
+       for_each_possible_cpu(cpu) {
+               if (per_cpu(reserved_asids, cpu) == asid) {
+                       hit = true;
+                       per_cpu(reserved_asids, cpu) = newasid;
+               }
+       }
+
+       return hit;
 }
 
 static u64 new_context(struct mm_struct *mm, unsigned int cpu)
@@ -181,12 +196,14 @@ static u64 new_context(struct mm_struct *mm, unsigned int cpu)
        u64 generation = atomic64_read(&asid_generation);
 
        if (asid != 0) {
+               u64 newasid = generation | (asid & ~ASID_MASK);
+
                /*
                 * If our current ASID was active during a rollover, we
                 * can continue to use it and this was just a false alarm.
                 */
-               if (is_reserved_asid(asid))
-                       return generation | (asid & ~ASID_MASK);
+               if (check_update_reserved_asid(asid, newasid))
+                       return newasid;
 
                /*
                 * We had a valid ASID in a previous life, so try to re-use
@@ -194,7 +211,7 @@ static u64 new_context(struct mm_struct *mm, unsigned int cpu)
                 */
                asid &= ~ASID_MASK;
                if (!__test_and_set_bit(asid, asid_map))
-                       goto bump_gen;
+                       return newasid;
        }
 
        /*
@@ -216,11 +233,8 @@ static u64 new_context(struct mm_struct *mm, unsigned int cpu)
 
        __set_bit(asid, asid_map);
        cur_idx = asid;
-
-bump_gen:
-       asid |= generation;
        cpumask_clear(mm_cpumask(mm));
-       return asid;
+       return asid | generation;
 }
 
 void check_and_switch_context(struct mm_struct *mm, struct task_struct *tsk)
index e62400e5fb99fdbf864af966e718a98decf85e29..534a60ae282e702d3b06e8dad289d8f109cd80ef 100644 (file)
@@ -1521,7 +1521,7 @@ static int __map_sg_chunk(struct device *dev, struct scatterlist *sg,
                return -ENOMEM;
 
        for (count = 0, s = sg; count < (size >> PAGE_SHIFT); s = sg_next(s)) {
-               phys_addr_t phys = sg_phys(s) & PAGE_MASK;
+               phys_addr_t phys = page_to_phys(sg_page(s));
                unsigned int len = PAGE_ALIGN(s->offset + s->length);
 
                if (!is_coherent &&
index 8a63b4cdc0f27d0fa7cf69f0bb1ffa51b6289e39..7f8cd1b3557f071a64dafc05eba4c481ef82c79d 100644 (file)
@@ -22,6 +22,7 @@
 #include <linux/memblock.h>
 #include <linux/dma-contiguous.h>
 #include <linux/sizes.h>
+#include <linux/stop_machine.h>
 
 #include <asm/cp15.h>
 #include <asm/mach-types.h>
@@ -627,12 +628,10 @@ static struct section_perm ro_perms[] = {
  * safe to be called with preemption disabled, as under stop_machine().
  */
 static inline void section_update(unsigned long addr, pmdval_t mask,
-                                 pmdval_t prot)
+                                 pmdval_t prot, struct mm_struct *mm)
 {
-       struct mm_struct *mm;
        pmd_t *pmd;
 
-       mm = current->active_mm;
        pmd = pmd_offset(pud_offset(pgd_offset(mm, addr), addr), addr);
 
 #ifdef CONFIG_ARM_LPAE
@@ -656,49 +655,82 @@ static inline bool arch_has_strict_perms(void)
        return !!(get_cr() & CR_XP);
 }
 
-#define set_section_perms(perms, field)        {                               \
-       size_t i;                                                       \
-       unsigned long addr;                                             \
-                                                                       \
-       if (!arch_has_strict_perms())                                   \
-               return;                                                 \
-                                                                       \
-       for (i = 0; i < ARRAY_SIZE(perms); i++) {                       \
-               if (!IS_ALIGNED(perms[i].start, SECTION_SIZE) ||        \
-                   !IS_ALIGNED(perms[i].end, SECTION_SIZE)) {          \
-                       pr_err("BUG: section %lx-%lx not aligned to %lx\n", \
-                               perms[i].start, perms[i].end,           \
-                               SECTION_SIZE);                          \
-                       continue;                                       \
-               }                                                       \
-                                                                       \
-               for (addr = perms[i].start;                             \
-                    addr < perms[i].end;                               \
-                    addr += SECTION_SIZE)                              \
-                       section_update(addr, perms[i].mask,             \
-                                      perms[i].field);                 \
-       }                                                               \
+void set_section_perms(struct section_perm *perms, int n, bool set,
+                       struct mm_struct *mm)
+{
+       size_t i;
+       unsigned long addr;
+
+       if (!arch_has_strict_perms())
+               return;
+
+       for (i = 0; i < n; i++) {
+               if (!IS_ALIGNED(perms[i].start, SECTION_SIZE) ||
+                   !IS_ALIGNED(perms[i].end, SECTION_SIZE)) {
+                       pr_err("BUG: section %lx-%lx not aligned to %lx\n",
+                               perms[i].start, perms[i].end,
+                               SECTION_SIZE);
+                       continue;
+               }
+
+               for (addr = perms[i].start;
+                    addr < perms[i].end;
+                    addr += SECTION_SIZE)
+                       section_update(addr, perms[i].mask,
+                               set ? perms[i].prot : perms[i].clear, mm);
+       }
+
 }
 
-static inline void fix_kernmem_perms(void)
+static void update_sections_early(struct section_perm perms[], int n)
 {
-       set_section_perms(nx_perms, prot);
+       struct task_struct *t, *s;
+
+       read_lock(&tasklist_lock);
+       for_each_process(t) {
+               if (t->flags & PF_KTHREAD)
+                       continue;
+               for_each_thread(t, s)
+                       set_section_perms(perms, n, true, s->mm);
+       }
+       read_unlock(&tasklist_lock);
+       set_section_perms(perms, n, true, current->active_mm);
+       set_section_perms(perms, n, true, &init_mm);
+}
+
+int __fix_kernmem_perms(void *unused)
+{
+       update_sections_early(nx_perms, ARRAY_SIZE(nx_perms));
+       return 0;
+}
+
+void fix_kernmem_perms(void)
+{
+       stop_machine(__fix_kernmem_perms, NULL, NULL);
 }
 
 #ifdef CONFIG_DEBUG_RODATA
+int __mark_rodata_ro(void *unused)
+{
+       update_sections_early(ro_perms, ARRAY_SIZE(ro_perms));
+       return 0;
+}
+
 void mark_rodata_ro(void)
 {
-       set_section_perms(ro_perms, prot);
+       stop_machine(__mark_rodata_ro, NULL, NULL);
 }
 
 void set_kernel_text_rw(void)
 {
-       set_section_perms(ro_perms, clear);
+       set_section_perms(ro_perms, ARRAY_SIZE(ro_perms), false,
+                               current->active_mm);
 }
 
 void set_kernel_text_ro(void)
 {
-       set_section_perms(ro_perms, prot);
+       set_section_perms(ro_perms, ARRAY_SIZE(ro_perms), true,
+                               current->active_mm);
 }
 #endif /* CONFIG_DEBUG_RODATA */
 
index de2b246fed3808fce444b560a725ed4007464174..8e1ea433c3f1e321d7ed4e91fe582a5be4eb85be 100644 (file)
@@ -95,7 +95,7 @@ ENDPROC(cpu_v7_dcache_clean_area)
 .equ   cpu_v7_suspend_size, 4 * 9
 #ifdef CONFIG_ARM_CPU_SUSPEND
 ENTRY(cpu_v7_do_suspend)
-       stmfd   sp!, {r4 - r10, lr}
+       stmfd   sp!, {r4 - r11, lr}
        mrc     p15, 0, r4, c13, c0, 0  @ FCSE/PID
        mrc     p15, 0, r5, c13, c0, 3  @ User r/o thread ID
        stmia   r0!, {r4 - r5}
@@ -112,7 +112,7 @@ ENTRY(cpu_v7_do_suspend)
        mrc     p15, 0, r9, c1, c0, 1   @ Auxiliary control register
        mrc     p15, 0, r10, c1, c0, 2  @ Co-processor access control
        stmia   r0, {r5 - r11}
-       ldmfd   sp!, {r4 - r10, pc}
+       ldmfd   sp!, {r4 - r11, pc}
 ENDPROC(cpu_v7_do_suspend)
 
 ENTRY(cpu_v7_do_resume)
index 2f4b14cfddb4762e88818464dcd6c57d5eff2a5c..591f9db3bf4048a4d727f195e4e2fb95e4ca06c4 100644 (file)
@@ -1061,7 +1061,7 @@ void bpf_jit_compile(struct bpf_prog *fp)
        }
        build_epilogue(&ctx);
 
-       flush_icache_range((u32)ctx.target, (u32)(ctx.target + ctx.idx));
+       flush_icache_range((u32)header, (u32)(ctx.target + ctx.idx));
 
 #if __LINUX_ARM_ARCH__ < 7
        if (ctx.imm_count)
index 82074625de5cebfc7681f72c931c90d1b7e951ac..7263e95a6f354287533f2f13a702fcddae6fc260 100644 (file)
@@ -65,6 +65,7 @@
 #include <linux/platform_data/usb-ohci-s3c2410.h>
 #include <plat/usb-phy.h>
 #include <plat/regs-spi.h>
+#include <linux/platform_data/asoc-s3c.h>
 #include <linux/platform_data/spi-s3c64xx.h>
 
 static u64 samsung_device_dma_mask = DMA_BIT_MASK(32);
@@ -74,9 +75,15 @@ static u64 samsung_device_dma_mask = DMA_BIT_MASK(32);
 static struct resource s3c_ac97_resource[] = {
        [0] = DEFINE_RES_MEM(S3C2440_PA_AC97, S3C2440_SZ_AC97),
        [1] = DEFINE_RES_IRQ(IRQ_S3C244X_AC97),
-       [2] = DEFINE_RES_DMA_NAMED(DMACH_PCM_OUT, "PCM out"),
-       [3] = DEFINE_RES_DMA_NAMED(DMACH_PCM_IN, "PCM in"),
-       [4] = DEFINE_RES_DMA_NAMED(DMACH_MIC_IN, "Mic in"),
+};
+
+static struct s3c_audio_pdata s3c_ac97_pdata = {
+#ifdef CONFIG_S3C24XX_DMAC
+       .dma_filter = s3c24xx_dma_filter,
+#endif
+       .dma_playback = (void *)DMACH_PCM_OUT,
+       .dma_capture = (void *)DMACH_PCM_IN,
+       .dma_capture_mic = (void *)DMACH_MIC_IN,
 };
 
 struct platform_device s3c_device_ac97 = {
@@ -87,6 +94,7 @@ struct platform_device s3c_device_ac97 = {
        .dev            = {
                .dma_mask               = &samsung_device_dma_mask,
                .coherent_dma_mask      = DMA_BIT_MASK(32),
+               .platform_data          = &s3c_ac97_pdata,
        }
 };
 #endif /* CONFIG_CPU_S3C2440 */
@@ -566,6 +574,14 @@ static struct resource s3c_iis_resource[] = {
        [0] = DEFINE_RES_MEM(S3C24XX_PA_IIS, S3C24XX_SZ_IIS),
 };
 
+static struct s3c_audio_pdata s3c_iis_platdata = {
+#ifdef CONFIG_S3C24XX_DMAC
+       .dma_filter = s3c24xx_dma_filter,
+#endif
+       .dma_playback = (void *)DMACH_I2S_OUT,
+       .dma_capture = (void *)DMACH_I2S_IN,
+};
+
 struct platform_device s3c_device_iis = {
        .name           = "s3c24xx-iis",
        .id             = -1,
@@ -574,6 +590,7 @@ struct platform_device s3c_device_iis = {
        .dev            = {
                .dma_mask               = &samsung_device_dma_mask,
                .coherent_dma_mask      = DMA_BIT_MASK(32),
+               .platform_data          = &s3c_iis_platdata,
        }
 };
 #endif /* CONFIG_PLAT_S3C24XX */
index 9ac16a482ff1e690b9b6aa66a09225cec831966b..871f21783866d5fdb1557ec56e5f13b602ba331a 100644 (file)
@@ -49,7 +49,7 @@ config ARM64
        select HAVE_ARCH_AUDITSYSCALL
        select HAVE_ARCH_BITREVERSE
        select HAVE_ARCH_JUMP_LABEL
-       select HAVE_ARCH_KASAN if SPARSEMEM_VMEMMAP
+       select HAVE_ARCH_KASAN if SPARSEMEM_VMEMMAP && !(ARM64_16K_PAGES && ARM64_VA_BITS_48)
        select HAVE_ARCH_KGDB
        select HAVE_ARCH_SECCOMP_FILTER
        select HAVE_ARCH_TRACEHOOK
@@ -316,6 +316,27 @@ config ARM64_ERRATUM_832075
 
          If unsure, say Y.
 
+config ARM64_ERRATUM_834220
+       bool "Cortex-A57: 834220: Stage 2 translation fault might be incorrectly reported in presence of a Stage 1 fault"
+       depends on KVM
+       default y
+       help
+         This option adds an alternative code sequence to work around ARM
+         erratum 834220 on Cortex-A57 parts up to r1p2.
+
+         Affected Cortex-A57 parts might report a Stage 2 translation
+         fault as the result of a Stage 1 fault for load crossing a
+         page boundary when there is a permission or device memory
+         alignment fault at Stage 1 and a translation fault at Stage 2.
+
+         The workaround is to verify that the Stage 1 translation
+         doesn't generate a fault before handling the Stage 2 fault.
+         Please note that this does not necessarily enable the workaround,
+         as it depends on the alternative framework, which will only patch
+         the kernel if an affected CPU is detected.
+
+         If unsure, say Y.
+
 config ARM64_ERRATUM_845719
        bool "Cortex-A53: 845719: a load might read incorrect data"
        depends on COMPAT
index e81cd48d6245eace97978c58057a022d105d990d..925552e7b4f3eaf6ce23fc1e8dd2d77f50073121 100644 (file)
                        clock-frequency = <0>;  /* Updated by bootloader */
                        voltage-ranges = <1800 1800 3300 3300>;
                        sdhci,auto-cmd12;
+                       little-endian;
                        bus-width = <4>;
                };
 
                        reg = <0x0 0x2300000 0x0 0x10000>;
                        interrupts = <0 36 0x4>; /* Level high type */
                        gpio-controller;
+                       little-endian;
                        #gpio-cells = <2>;
                        interrupt-controller;
                        #interrupt-cells = <2>;
                        reg = <0x0 0x2310000 0x0 0x10000>;
                        interrupts = <0 36 0x4>; /* Level high type */
                        gpio-controller;
+                       little-endian;
                        #gpio-cells = <2>;
                        interrupt-controller;
                        #interrupt-cells = <2>;
                        reg = <0x0 0x2320000 0x0 0x10000>;
                        interrupts = <0 37 0x4>; /* Level high type */
                        gpio-controller;
+                       little-endian;
                        #gpio-cells = <2>;
                        interrupt-controller;
                        #interrupt-cells = <2>;
                        reg = <0x0 0x2330000 0x0 0x10000>;
                        interrupts = <0 37 0x4>; /* Level high type */
                        gpio-controller;
+                       little-endian;
                        #gpio-cells = <2>;
                        interrupt-controller;
                        #interrupt-cells = <2>;
index ce47792a983dda8b2909609502ef80d54c1215f8..f7bd9bf0bbb398bbb2a355c1b24d1f9c035bacf4 100644 (file)
@@ -237,7 +237,7 @@ EXPORT_SYMBOL(ce_aes_setkey);
 static struct crypto_alg aes_alg = {
        .cra_name               = "aes",
        .cra_driver_name        = "aes-ce",
-       .cra_priority           = 300,
+       .cra_priority           = 250,
        .cra_flags              = CRYPTO_ALG_TYPE_CIPHER,
        .cra_blocksize          = AES_BLOCK_SIZE,
        .cra_ctxsize            = sizeof(struct crypto_aes_ctx),
index 030cdcb46c6bdabd8bb49901ed231fcdbb5c25fd..2731d3b25ed2e338e76966b5efd86658b7e22263 100644 (file)
@@ -77,6 +77,7 @@
 #ifndef __ASSEMBLY__
 
 #include <linux/stringify.h>
+#include <asm/barrier.h>
 
 /*
  * Low-level accessors
index 624f9679f4b0abb3e41da2c7ec23c4a7625196e3..9622eb48f894db3fdb06db5441339babc2a1fdeb 100644 (file)
@@ -64,27 +64,31 @@ do {                                                                        \
 
 #define smp_load_acquire(p)                                            \
 ({                                                                     \
-       typeof(*p) ___p1;                                               \
+       union { typeof(*p) __val; char __c[1]; } __u;                   \
        compiletime_assert_atomic_type(*p);                             \
        switch (sizeof(*p)) {                                           \
        case 1:                                                         \
                asm volatile ("ldarb %w0, %1"                           \
-                       : "=r" (___p1) : "Q" (*p) : "memory");          \
+                       : "=r" (*(__u8 *)__u.__c)                       \
+                       : "Q" (*p) : "memory");                         \
                break;                                                  \
        case 2:                                                         \
                asm volatile ("ldarh %w0, %1"                           \
-                       : "=r" (___p1) : "Q" (*p) : "memory");          \
+                       : "=r" (*(__u16 *)__u.__c)                      \
+                       : "Q" (*p) : "memory");                         \
                break;                                                  \
        case 4:                                                         \
                asm volatile ("ldar %w0, %1"                            \
-                       : "=r" (___p1) : "Q" (*p) : "memory");          \
+                       : "=r" (*(__u32 *)__u.__c)                      \
+                       : "Q" (*p) : "memory");                         \
                break;                                                  \
        case 8:                                                         \
                asm volatile ("ldar %0, %1"                             \
-                       : "=r" (___p1) : "Q" (*p) : "memory");          \
+                       : "=r" (*(__u64 *)__u.__c)                      \
+                       : "Q" (*p) : "memory");                         \
                break;                                                  \
        }                                                               \
-       ___p1;                                                          \
+       __u.__val;                                                      \
 })
 
 #define read_barrier_depends()         do { } while(0)
index 7fbed6919b54041f8fd925f8661a72771e733461..eb8432bb82b8dd698c9bdd5723cc870b36158b25 100644 (file)
@@ -23,7 +23,6 @@
  */
 #include <linux/types.h>
 #include <linux/sched.h>
-#include <linux/ptrace.h>
 
 #define COMPAT_USER_HZ         100
 #ifdef __AARCH64EB__
@@ -234,7 +233,7 @@ static inline compat_uptr_t ptr_to_compat(void __user *uptr)
        return (u32)(unsigned long)uptr;
 }
 
-#define compat_user_stack_pointer() (user_stack_pointer(current_pt_regs()))
+#define compat_user_stack_pointer() (user_stack_pointer(task_pt_regs(current)))
 
 static inline void __user *arch_compat_alloc_user_space(long len)
 {
index 11d5bb0fdd541052b9cdd49197b2dc90e9ece737..8f271b83f9106c7c9753ce2601d3b59e1ffbdfc5 100644 (file)
@@ -29,8 +29,9 @@
 #define ARM64_HAS_PAN                          4
 #define ARM64_HAS_LSE_ATOMICS                  5
 #define ARM64_WORKAROUND_CAVIUM_23154          6
+#define ARM64_WORKAROUND_834220                        7
 
-#define ARM64_NCAPS                            7
+#define ARM64_NCAPS                            8
 
 #ifndef __ASSEMBLY__
 
@@ -46,8 +47,12 @@ enum ftr_type {
 #define FTR_STRICT     true    /* SANITY check strict matching required */
 #define FTR_NONSTRICT  false   /* SANITY check ignored */
 
+#define FTR_SIGNED     true    /* Value should be treated as signed */
+#define FTR_UNSIGNED   false   /* Value should be treated as unsigned */
+
 struct arm64_ftr_bits {
-       bool            strict;   /* CPU Sanity check: strict matching required ? */
+       bool            sign;   /* Value is signed ? */
+       bool            strict; /* CPU Sanity check: strict matching required ? */
        enum ftr_type   type;
        u8              shift;
        u8              width;
@@ -123,6 +128,18 @@ cpuid_feature_extract_field(u64 features, int field)
        return cpuid_feature_extract_field_width(features, field, 4);
 }
 
+static inline unsigned int __attribute_const__
+cpuid_feature_extract_unsigned_field_width(u64 features, int field, int width)
+{
+       return (u64)(features << (64 - width - field)) >> (64 - width);
+}
+
+static inline unsigned int __attribute_const__
+cpuid_feature_extract_unsigned_field(u64 features, int field)
+{
+       return cpuid_feature_extract_unsigned_field_width(features, field, 4);
+}
+
 static inline u64 arm64_ftr_mask(struct arm64_ftr_bits *ftrp)
 {
        return (u64)GENMASK(ftrp->shift + ftrp->width - 1, ftrp->shift);
@@ -130,7 +147,9 @@ static inline u64 arm64_ftr_mask(struct arm64_ftr_bits *ftrp)
 
 static inline s64 arm64_ftr_value(struct arm64_ftr_bits *ftrp, u64 val)
 {
-       return cpuid_feature_extract_field_width(val, ftrp->shift, ftrp->width);
+       return ftrp->sign ?
+               cpuid_feature_extract_field_width(val, ftrp->shift, ftrp->width) :
+               cpuid_feature_extract_unsigned_field_width(val, ftrp->shift, ftrp->width);
 }
 
 static inline bool id_aa64mmfr0_mixed_endian_el0(u64 mmfr0)
index 54d0ead41afc656e8b06a0850860b164a8b67eaa..61e08f360e31da1f92a38881cd2cf924d2f03c82 100644 (file)
@@ -18,7 +18,6 @@
 
 #ifdef __KERNEL__
 
-#include <linux/acpi.h>
 #include <linux/types.h>
 #include <linux/vmalloc.h>
 
 #include <asm/xen/hypervisor.h>
 
 #define DMA_ERROR_CODE (~(dma_addr_t)0)
-extern struct dma_map_ops *dma_ops;
 extern struct dma_map_ops dummy_dma_ops;
 
 static inline struct dma_map_ops *__generic_dma_ops(struct device *dev)
 {
-       if (unlikely(!dev))
-               return dma_ops;
-       else if (dev->archdata.dma_ops)
+       if (dev && dev->archdata.dma_ops)
                return dev->archdata.dma_ops;
-       else if (acpi_disabled)
-               return dma_ops;
 
        /*
-        * When ACPI is enabled, if arch_set_dma_ops is not called,
-        * we will disable device DMA capability by setting it
-        * to dummy_dma_ops.
+        * We expect no ISA devices, and all other DMA masters are expected to
+        * have someone call arch_setup_dma_ops at device creation time.
         */
        return &dummy_dma_ops;
 }
index e54415ec693571d1d4195d57b1928e2e58173353..9732908bfc8a54b546c4cab40802f70a56b36fce 100644 (file)
@@ -138,16 +138,18 @@ extern struct pmu perf_ops_bp;
 /* Determine number of BRP registers available. */
 static inline int get_num_brps(void)
 {
+       u64 dfr0 = read_system_reg(SYS_ID_AA64DFR0_EL1);
        return 1 +
-               cpuid_feature_extract_field(read_system_reg(SYS_ID_AA64DFR0_EL1),
+               cpuid_feature_extract_unsigned_field(dfr0,
                                                ID_AA64DFR0_BRPS_SHIFT);
 }
 
 /* Determine number of WRP registers available. */
 static inline int get_num_wrps(void)
 {
+       u64 dfr0 = read_system_reg(SYS_ID_AA64DFR0_EL1);
        return 1 +
-               cpuid_feature_extract_field(read_system_reg(SYS_ID_AA64DFR0_EL1),
+               cpuid_feature_extract_unsigned_field(dfr0,
                                                ID_AA64DFR0_WRPS_SHIFT);
 }
 
index 23eb450b820ba03ce83b737f308fcd3d6b33f9a8..8e8d30684392b1065b0c5d1f65e7715e4028331c 100644 (file)
@@ -7,4 +7,9 @@ struct pt_regs;
 
 extern void set_handle_irq(void (*handle_irq)(struct pt_regs *));
 
+static inline int nr_legacy_irqs(void)
+{
+       return 0;
+}
+
 #endif
index 17e92f05b1fe597ea1c4e833debf7541be0fde79..25a40213bd9b87cb6802ecfd4204dc66c41e5850 100644 (file)
@@ -99,12 +99,22 @@ static inline void vcpu_set_thumb(struct kvm_vcpu *vcpu)
        *vcpu_cpsr(vcpu) |= COMPAT_PSR_T_BIT;
 }
 
-static inline unsigned long *vcpu_reg(const struct kvm_vcpu *vcpu, u8 reg_num)
+/*
+ * vcpu_get_reg and vcpu_set_reg should always be passed a register number
+ * coming from a read of ESR_EL2. Otherwise, it may give the wrong result on
+ * AArch32 with banked registers.
+ */
+static inline unsigned long vcpu_get_reg(const struct kvm_vcpu *vcpu,
+                                        u8 reg_num)
 {
-       if (vcpu_mode_is_32bit(vcpu))
-               return vcpu_reg32(vcpu, reg_num);
+       return (reg_num == 31) ? 0 : vcpu_gp_regs(vcpu)->regs.regs[reg_num];
+}
 
-       return (unsigned long *)&vcpu_gp_regs(vcpu)->regs.regs[reg_num];
+static inline void vcpu_set_reg(struct kvm_vcpu *vcpu, u8 reg_num,
+                               unsigned long val)
+{
+       if (reg_num != 31)
+               vcpu_gp_regs(vcpu)->regs.regs[reg_num] = val;
 }
 
 /* Get vcpu SPSR for current mode */
index c0e87898ba96b04f2e5b847a0dacf01f4eb1dff1..24165784b8038b732ea568d1e74fd8c0a699b914 100644 (file)
@@ -101,7 +101,7 @@ static inline void cpu_set_default_tcr_t0sz(void)
 #define destroy_context(mm)            do { } while(0)
 void check_and_switch_context(struct mm_struct *mm, unsigned int cpu);
 
-#define init_new_context(tsk,mm)       ({ atomic64_set(&mm->context.id, 0); 0; })
+#define init_new_context(tsk,mm)       ({ atomic64_set(&(mm)->context.id, 0); 0; })
 
 /*
  * This is called when "tsk" is about to enter lazy TLB mode.
index 9819a9426b69a936017e508a6cab907040c9c67a..63f52b55defe1041a7913217db490528c441c6f3 100644 (file)
@@ -81,6 +81,7 @@ extern void __pgd_error(const char *file, int line, unsigned long val);
 
 #define PAGE_KERNEL            __pgprot(_PAGE_DEFAULT | PTE_PXN | PTE_UXN | PTE_DIRTY | PTE_WRITE)
 #define PAGE_KERNEL_RO         __pgprot(_PAGE_DEFAULT | PTE_PXN | PTE_UXN | PTE_DIRTY | PTE_RDONLY)
+#define PAGE_KERNEL_ROX        __pgprot(_PAGE_DEFAULT | PTE_UXN | PTE_DIRTY | PTE_RDONLY)
 #define PAGE_KERNEL_EXEC       __pgprot(_PAGE_DEFAULT | PTE_UXN | PTE_DIRTY | PTE_WRITE)
 #define PAGE_KERNEL_EXEC_CONT  __pgprot(_PAGE_DEFAULT | PTE_UXN | PTE_DIRTY | PTE_WRITE | PTE_CONT)
 
@@ -275,10 +276,14 @@ static inline void set_pte_at(struct mm_struct *mm, unsigned long addr,
         * hardware updates of the pte (ptep_set_access_flags safely changes
         * valid ptes without going through an invalid entry).
         */
-       if (IS_ENABLED(CONFIG_DEBUG_VM) && IS_ENABLED(CONFIG_ARM64_HW_AFDBM) &&
-           pte_valid(*ptep)) {
-               BUG_ON(!pte_young(pte));
-               BUG_ON(pte_write(*ptep) && !pte_dirty(pte));
+       if (IS_ENABLED(CONFIG_ARM64_HW_AFDBM) &&
+           pte_valid(*ptep) && pte_valid(pte)) {
+               VM_WARN_ONCE(!pte_young(pte),
+                            "%s: racy access flag clearing: 0x%016llx -> 0x%016llx",
+                            __func__, pte_val(*ptep), pte_val(pte));
+               VM_WARN_ONCE(pte_write(*ptep) && !pte_dirty(pte),
+                            "%s: racy dirty state clearing: 0x%016llx -> 0x%016llx",
+                            __func__, pte_val(*ptep), pte_val(pte));
        }
 
        set_pte(ptep, pte);
index 24926f2504f7aaf2e37a6f9ecf1692ce3fff422b..feb6b4efa6414846d5598ccb0913a544ba0cf441 100644 (file)
@@ -75,6 +75,15 @@ const struct arm64_cpu_capabilities arm64_errata[] = {
                           (1 << MIDR_VARIANT_SHIFT) | 2),
        },
 #endif
+#ifdef CONFIG_ARM64_ERRATUM_834220
+       {
+       /* Cortex-A57 r0p0 - r1p2 */
+               .desc = "ARM erratum 834220",
+               .capability = ARM64_WORKAROUND_834220,
+               MIDR_RANGE(MIDR_CORTEX_A57, 0x00,
+                          (1 << MIDR_VARIANT_SHIFT) | 2),
+       },
+#endif
 #ifdef CONFIG_ARM64_ERRATUM_845719
        {
        /* Cortex-A53 r0p[01234] */
index c8cf89223b5a8ceb3564e77cc5a6893e5c8eb99d..0669c63281ea01a93ef9794f9731b424b6afd28e 100644 (file)
@@ -44,8 +44,9 @@ unsigned int compat_elf_hwcap2 __read_mostly;
 
 DECLARE_BITMAP(cpu_hwcaps, ARM64_NCAPS);
 
-#define ARM64_FTR_BITS(STRICT, TYPE, SHIFT, WIDTH, SAFE_VAL) \
+#define __ARM64_FTR_BITS(SIGNED, STRICT, TYPE, SHIFT, WIDTH, SAFE_VAL) \
        {                                               \
+               .sign = SIGNED,                         \
                .strict = STRICT,                       \
                .type = TYPE,                           \
                .shift = SHIFT,                         \
@@ -53,6 +54,14 @@ DECLARE_BITMAP(cpu_hwcaps, ARM64_NCAPS);
                .safe_val = SAFE_VAL,                   \
        }
 
+/* Define a feature with signed values */
+#define ARM64_FTR_BITS(STRICT, TYPE, SHIFT, WIDTH, SAFE_VAL) \
+       __ARM64_FTR_BITS(FTR_SIGNED, STRICT, TYPE, SHIFT, WIDTH, SAFE_VAL)
+
+/* Define a feature with unsigned value */
+#define U_ARM64_FTR_BITS(STRICT, TYPE, SHIFT, WIDTH, SAFE_VAL) \
+       __ARM64_FTR_BITS(FTR_UNSIGNED, STRICT, TYPE, SHIFT, WIDTH, SAFE_VAL)
+
 #define ARM64_FTR_END                                  \
        {                                               \
                .width = 0,                             \
@@ -99,7 +108,7 @@ static struct arm64_ftr_bits ftr_id_aa64mmfr0[] = {
         * Differing PARange is fine as long as all peripherals and memory are mapped
         * within the minimum PARange of all CPUs
         */
-       ARM64_FTR_BITS(FTR_NONSTRICT, FTR_LOWER_SAFE, ID_AA64MMFR0_PARANGE_SHIFT, 4, 0),
+       U_ARM64_FTR_BITS(FTR_NONSTRICT, FTR_LOWER_SAFE, ID_AA64MMFR0_PARANGE_SHIFT, 4, 0),
        ARM64_FTR_END,
 };
 
@@ -115,18 +124,18 @@ static struct arm64_ftr_bits ftr_id_aa64mmfr1[] = {
 };
 
 static struct arm64_ftr_bits ftr_ctr[] = {
-       ARM64_FTR_BITS(FTR_STRICT, FTR_EXACT, 31, 1, 1),        /* RAO */
+       U_ARM64_FTR_BITS(FTR_STRICT, FTR_EXACT, 31, 1, 1),      /* RAO */
        ARM64_FTR_BITS(FTR_STRICT, FTR_EXACT, 28, 3, 0),
-       ARM64_FTR_BITS(FTR_STRICT, FTR_HIGHER_SAFE, 24, 4, 0),  /* CWG */
-       ARM64_FTR_BITS(FTR_STRICT, FTR_LOWER_SAFE, 20, 4, 0),   /* ERG */
-       ARM64_FTR_BITS(FTR_STRICT, FTR_LOWER_SAFE, 16, 4, 1),   /* DminLine */
+       U_ARM64_FTR_BITS(FTR_STRICT, FTR_HIGHER_SAFE, 24, 4, 0),        /* CWG */
+       U_ARM64_FTR_BITS(FTR_STRICT, FTR_LOWER_SAFE, 20, 4, 0), /* ERG */
+       U_ARM64_FTR_BITS(FTR_STRICT, FTR_LOWER_SAFE, 16, 4, 1), /* DminLine */
        /*
         * Linux can handle differing I-cache policies. Userspace JITs will
         * make use of *minLine
         */
-       ARM64_FTR_BITS(FTR_NONSTRICT, FTR_EXACT, 14, 2, 0),     /* L1Ip */
+       U_ARM64_FTR_BITS(FTR_NONSTRICT, FTR_EXACT, 14, 2, 0),   /* L1Ip */
        ARM64_FTR_BITS(FTR_STRICT, FTR_EXACT, 4, 10, 0),        /* RAZ */
-       ARM64_FTR_BITS(FTR_STRICT, FTR_LOWER_SAFE, 0, 4, 0),    /* IminLine */
+       U_ARM64_FTR_BITS(FTR_STRICT, FTR_LOWER_SAFE, 0, 4, 0),  /* IminLine */
        ARM64_FTR_END,
 };
 
@@ -144,12 +153,12 @@ static struct arm64_ftr_bits ftr_id_mmfr0[] = {
 
 static struct arm64_ftr_bits ftr_id_aa64dfr0[] = {
        ARM64_FTR_BITS(FTR_STRICT, FTR_EXACT, 32, 32, 0),
-       ARM64_FTR_BITS(FTR_STRICT, FTR_LOWER_SAFE, ID_AA64DFR0_CTX_CMPS_SHIFT, 4, 0),
-       ARM64_FTR_BITS(FTR_STRICT, FTR_LOWER_SAFE, ID_AA64DFR0_WRPS_SHIFT, 4, 0),
-       ARM64_FTR_BITS(FTR_STRICT, FTR_LOWER_SAFE, ID_AA64DFR0_BRPS_SHIFT, 4, 0),
-       ARM64_FTR_BITS(FTR_STRICT, FTR_EXACT, ID_AA64DFR0_PMUVER_SHIFT, 4, 0),
-       ARM64_FTR_BITS(FTR_STRICT, FTR_EXACT, ID_AA64DFR0_TRACEVER_SHIFT, 4, 0),
-       ARM64_FTR_BITS(FTR_STRICT, FTR_EXACT, ID_AA64DFR0_DEBUGVER_SHIFT, 4, 0x6),
+       U_ARM64_FTR_BITS(FTR_STRICT, FTR_LOWER_SAFE, ID_AA64DFR0_CTX_CMPS_SHIFT, 4, 0),
+       U_ARM64_FTR_BITS(FTR_STRICT, FTR_LOWER_SAFE, ID_AA64DFR0_WRPS_SHIFT, 4, 0),
+       U_ARM64_FTR_BITS(FTR_STRICT, FTR_LOWER_SAFE, ID_AA64DFR0_BRPS_SHIFT, 4, 0),
+       U_ARM64_FTR_BITS(FTR_STRICT, FTR_EXACT, ID_AA64DFR0_PMUVER_SHIFT, 4, 0),
+       U_ARM64_FTR_BITS(FTR_STRICT, FTR_EXACT, ID_AA64DFR0_TRACEVER_SHIFT, 4, 0),
+       U_ARM64_FTR_BITS(FTR_STRICT, FTR_EXACT, ID_AA64DFR0_DEBUGVER_SHIFT, 4, 0x6),
        ARM64_FTR_END,
 };
 
index 706679d0a0b4227c4a7267cd85142192576d7ab3..212ae6361d8be45d6d73d197284a1ca587599342 100644 (file)
@@ -30,6 +30,7 @@
 #include <linux/seq_file.h>
 #include <linux/sched.h>
 #include <linux/smp.h>
+#include <linux/delay.h>
 
 /*
  * In case the boot CPU is hotpluggable, we record its initial state and
@@ -112,6 +113,10 @@ static int c_show(struct seq_file *m, void *v)
                 */
                seq_printf(m, "processor\t: %d\n", i);
 
+               seq_printf(m, "BogoMIPS\t: %lu.%02lu\n",
+                          loops_per_jiffy / (500000UL/HZ),
+                          loops_per_jiffy / (5000UL/HZ) % 100);
+
                /*
                 * Dump out the common processor features in a single line.
                 * Userspace should read the hwcaps with getauxval(AT_HWCAP)
index de46b50f4cdf952087e77d473314e75728efeec0..4eeb17198cfaf598fd403b1e4040c77f5ee3068a 100644 (file)
@@ -127,7 +127,11 @@ static int __init uefi_init(void)
        table_size = sizeof(efi_config_table_64_t) * efi.systab->nr_tables;
        config_tables = early_memremap(efi_to_phys(efi.systab->tables),
                                       table_size);
-
+       if (config_tables == NULL) {
+               pr_warn("Unable to map EFI config table array.\n");
+               retval = -ENOMEM;
+               goto out;
+       }
        retval = efi_config_parse_tables(config_tables, efi.systab->nr_tables,
                                         sizeof(efi_config_table_64_t), NULL);
 
@@ -209,6 +213,14 @@ void __init efi_init(void)
                         PAGE_ALIGN(params.mmap_size + (params.mmap & ~PAGE_MASK)));
        memmap.phys_map = params.mmap;
        memmap.map = early_memremap(params.mmap, params.mmap_size);
+       if (memmap.map == NULL) {
+               /*
+               * If we are booting via UEFI, the UEFI memory map is the only
+               * description of memory we have, so there is little point in
+               * proceeding if we cannot access it.
+               */
+               panic("Unable to map EFI memory map.\n");
+       }
        memmap.map_end = memmap.map + params.mmap_size;
        memmap.desc_size = params.desc_size;
        memmap.desc_version = params.desc_ver;
@@ -224,8 +236,9 @@ static bool __init efi_virtmap_init(void)
 {
        efi_memory_desc_t *md;
 
+       init_new_context(NULL, &efi_mm);
+
        for_each_efi_memory_desc(&memmap, md) {
-               u64 paddr, npages, size;
                pgprot_t prot;
 
                if (!(md->attribute & EFI_MEMORY_RUNTIME))
@@ -233,11 +246,6 @@ static bool __init efi_virtmap_init(void)
                if (md->virt_addr == 0)
                        return false;
 
-               paddr = md->phys_addr;
-               npages = md->num_pages;
-               memrange_efi_to_native(&paddr, &npages);
-               size = npages << PAGE_SHIFT;
-
                pr_info("  EFI remap 0x%016llx => %p\n",
                        md->phys_addr, (void *)md->virt_addr);
 
@@ -254,7 +262,9 @@ static bool __init efi_virtmap_init(void)
                else
                        prot = PAGE_KERNEL;
 
-               create_pgd_mapping(&efi_mm, paddr, md->virt_addr, size, prot);
+               create_pgd_mapping(&efi_mm, md->phys_addr, md->virt_addr,
+                                  md->num_pages << EFI_PAGE_SHIFT, 
+                                  __pgprot(pgprot_val(prot) | PTE_NG));
        }
        return true;
 }
@@ -270,12 +280,12 @@ static int __init arm64_enable_runtime_services(void)
 
        if (!efi_enabled(EFI_BOOT)) {
                pr_info("EFI services will not be available.\n");
-               return -1;
+               return 0;
        }
 
        if (efi_runtime_disabled()) {
                pr_info("EFI runtime services will be disabled.\n");
-               return -1;
+               return 0;
        }
 
        pr_info("Remapping and enabling EFI services.\n");
@@ -285,7 +295,7 @@ static int __init arm64_enable_runtime_services(void)
                                                   mapsize);
        if (!memmap.map) {
                pr_err("Failed to remap EFI memory map\n");
-               return -1;
+               return -ENOMEM;
        }
        memmap.map_end = memmap.map + mapsize;
        efi.memmap = &memmap;
@@ -294,13 +304,13 @@ static int __init arm64_enable_runtime_services(void)
                                                   sizeof(efi_system_table_t));
        if (!efi.systab) {
                pr_err("Failed to remap EFI System Table\n");
-               return -1;
+               return -ENOMEM;
        }
        set_bit(EFI_SYSTEM_TABLES, &efi.flags);
 
        if (!efi_virtmap_init()) {
                pr_err("No UEFI virtual mapping was installed -- runtime services will not be available\n");
-               return -1;
+               return -ENOMEM;
        }
 
        /* Set up runtime services function pointers */
@@ -329,14 +339,7 @@ core_initcall(arm64_dmi_init);
 
 static void efi_set_pgd(struct mm_struct *mm)
 {
-       if (mm == &init_mm)
-               cpu_set_reserved_ttbr0();
-       else
-               cpu_switch_mm(mm->pgd, mm);
-
-       local_flush_tlb_all();
-       if (icache_is_aivivt())
-               __local_flush_icache_all();
+       switch_mm(NULL, mm, NULL);
 }
 
 void efi_virtmap_load(void)
index fce95e17cf7f268fdfc0dd5c2d91e00b1152fb3f..1095aa483a1c28e5387b23895c14d7a1746268a3 100644 (file)
@@ -1,3 +1,4 @@
+#include <linux/ftrace.h>
 #include <linux/percpu.h>
 #include <linux/slab.h>
 #include <asm/cacheflush.h>
@@ -70,6 +71,13 @@ int cpu_suspend(unsigned long arg, int (*fn)(unsigned long))
         */
        local_dbg_save(flags);
 
+       /*
+        * Function graph tracer state gets incosistent when the kernel
+        * calls functions that never return (aka suspend finishers) hence
+        * disable graph tracing during their execution.
+        */
+       pause_graph_tracing();
+
        /*
         * mm context saved on the stack, it will be restored when
         * the cpu comes out of reset through the identity mapped
@@ -111,6 +119,8 @@ int cpu_suspend(unsigned long arg, int (*fn)(unsigned long))
                        hw_breakpoint_restore(NULL);
        }
 
+       unpause_graph_tracing();
+
        /*
         * Restore pstate flags. OS lock and mdscr have been already
         * restored, so from this point onwards, debugging is fully
index 1ee2c3937d4e8badf3ccec9a816ad23f9814506f..71426a78db123d13e98acf8659d65155ff342a06 100644 (file)
@@ -5,6 +5,7 @@
  */
 
 #include <asm-generic/vmlinux.lds.h>
+#include <asm/cache.h>
 #include <asm/kernel-pgtable.h>
 #include <asm/thread_info.h>
 #include <asm/memory.h>
@@ -140,7 +141,7 @@ SECTIONS
                ARM_EXIT_KEEP(EXIT_DATA)
        }
 
-       PERCPU_SECTION(64)
+       PERCPU_SECTION(L1_CACHE_BYTES)
 
        . = ALIGN(PAGE_SIZE);
        __init_end = .;
@@ -158,7 +159,7 @@ SECTIONS
        . = ALIGN(PAGE_SIZE);
        _data = .;
        _sdata = .;
-       RW_DATA_SECTION(64, PAGE_SIZE, THREAD_SIZE)
+       RW_DATA_SECTION(L1_CACHE_BYTES, PAGE_SIZE, THREAD_SIZE)
        PECOFF_EDATA_PADDING
        _edata = .;
 
index 68a0759b1375e3d6824b55b0c0548ba21c434ca0..15f0477b0d2adc53d86573b1733d2fa7f368bbd9 100644 (file)
@@ -37,7 +37,7 @@ static int handle_hvc(struct kvm_vcpu *vcpu, struct kvm_run *run)
 {
        int ret;
 
-       trace_kvm_hvc_arm64(*vcpu_pc(vcpu), *vcpu_reg(vcpu, 0),
+       trace_kvm_hvc_arm64(*vcpu_pc(vcpu), vcpu_get_reg(vcpu, 0),
                            kvm_vcpu_hvc_get_imm(vcpu));
 
        ret = kvm_psci_call(vcpu);
index 1599701ef044b28b2534a3766dde1d255dba103a..86c289832272d71ba48786414bb6e4ecb9b9cb14 100644 (file)
@@ -864,6 +864,10 @@ ENTRY(__kvm_flush_vm_context)
 ENDPROC(__kvm_flush_vm_context)
 
 __kvm_hyp_panic:
+       // Stash PAR_EL1 before corrupting it in __restore_sysregs
+       mrs     x0, par_el1
+       push    x0, xzr
+
        // Guess the context by looking at VTTBR:
        // If zero, then we're already a host.
        // Otherwise restore a minimal host context before panicing.
@@ -898,7 +902,7 @@ __kvm_hyp_panic:
        mrs     x3, esr_el2
        mrs     x4, far_el2
        mrs     x5, hpfar_el2
-       mrs     x6, par_el1
+       pop     x6, xzr         // active context PAR_EL1
        mrs     x7, tpidr_el2
 
        mov     lr, #(PSR_F_BIT | PSR_I_BIT | PSR_A_BIT | PSR_D_BIT |\
@@ -914,7 +918,7 @@ __kvm_hyp_panic:
 ENDPROC(__kvm_hyp_panic)
 
 __hyp_panic_str:
-       .ascii  "HYP panic:\nPS:%08x PC:%p ESR:%p\nFAR:%p HPFAR:%p PAR:%p\nVCPU:%p\n\0"
+       .ascii  "HYP panic:\nPS:%08x PC:%016x ESR:%08x\nFAR:%016x HPFAR:%016x PAR:%016x\nVCPU:%p\n\0"
 
        .align  2
 
@@ -1015,9 +1019,15 @@ el1_trap:
        b.ne    1f              // Not an abort we care about
 
        /* This is an abort. Check for permission fault */
+alternative_if_not ARM64_WORKAROUND_834220
        and     x2, x1, #ESR_ELx_FSC_TYPE
        cmp     x2, #FSC_PERM
        b.ne    1f              // Not a permission fault
+alternative_else
+       nop                     // Use the permission fault path to
+       nop                     // check for a valid S1 translation,
+       nop                     // regardless of the ESR value.
+alternative_endif
 
        /*
         * Check for Stage-1 page table walk, which is guaranteed
index 85c57158dcd96a83d80ce99c2c557b371c275984..648112e90ed546d2d052ccf7d9f66866d2390d06 100644 (file)
@@ -48,7 +48,7 @@ static void prepare_fault32(struct kvm_vcpu *vcpu, u32 mode, u32 vect_offset)
 
        /* Note: These now point to the banked copies */
        *vcpu_spsr(vcpu) = new_spsr_value;
-       *vcpu_reg(vcpu, 14) = *vcpu_pc(vcpu) + return_offset;
+       *vcpu_reg32(vcpu, 14) = *vcpu_pc(vcpu) + return_offset;
 
        /* Branch to exception vector */
        if (sctlr & (1 << 13))
index 87a64e8db04c4dac07a5d289ad0c2dd22860f0e2..d2650e84faf2f53f2afbdbd15e1f54d217e3fdb8 100644 (file)
@@ -78,7 +78,7 @@ static u32 get_ccsidr(u32 csselr)
  * See note at ARMv7 ARM B1.14.4 (TL;DR: S/W ops are not easily virtualized).
  */
 static bool access_dcsw(struct kvm_vcpu *vcpu,
-                       const struct sys_reg_params *p,
+                       struct sys_reg_params *p,
                        const struct sys_reg_desc *r)
 {
        if (!p->is_write)
@@ -94,21 +94,19 @@ static bool access_dcsw(struct kvm_vcpu *vcpu,
  * sys_regs and leave it in complete control of the caches.
  */
 static bool access_vm_reg(struct kvm_vcpu *vcpu,
-                         const struct sys_reg_params *p,
+                         struct sys_reg_params *p,
                          const struct sys_reg_desc *r)
 {
-       unsigned long val;
        bool was_enabled = vcpu_has_cache_enabled(vcpu);
 
        BUG_ON(!p->is_write);
 
-       val = *vcpu_reg(vcpu, p->Rt);
        if (!p->is_aarch32) {
-               vcpu_sys_reg(vcpu, r->reg) = val;
+               vcpu_sys_reg(vcpu, r->reg) = p->regval;
        } else {
                if (!p->is_32bit)
-                       vcpu_cp15_64_high(vcpu, r->reg) = val >> 32;
-               vcpu_cp15_64_low(vcpu, r->reg) = val & 0xffffffffUL;
+                       vcpu_cp15_64_high(vcpu, r->reg) = upper_32_bits(p->regval);
+               vcpu_cp15_64_low(vcpu, r->reg) = lower_32_bits(p->regval);
        }
 
        kvm_toggle_cache(vcpu, was_enabled);
@@ -122,22 +120,19 @@ static bool access_vm_reg(struct kvm_vcpu *vcpu,
  * for both AArch64 and AArch32 accesses.
  */
 static bool access_gic_sgi(struct kvm_vcpu *vcpu,
-                          const struct sys_reg_params *p,
+                          struct sys_reg_params *p,
                           const struct sys_reg_desc *r)
 {
-       u64 val;
-
        if (!p->is_write)
                return read_from_write_only(vcpu, p);
 
-       val = *vcpu_reg(vcpu, p->Rt);
-       vgic_v3_dispatch_sgi(vcpu, val);
+       vgic_v3_dispatch_sgi(vcpu, p->regval);
 
        return true;
 }
 
 static bool trap_raz_wi(struct kvm_vcpu *vcpu,
-                       const struct sys_reg_params *p,
+                       struct sys_reg_params *p,
                        const struct sys_reg_desc *r)
 {
        if (p->is_write)
@@ -147,19 +142,19 @@ static bool trap_raz_wi(struct kvm_vcpu *vcpu,
 }
 
 static bool trap_oslsr_el1(struct kvm_vcpu *vcpu,
-                          const struct sys_reg_params *p,
+                          struct sys_reg_params *p,
                           const struct sys_reg_desc *r)
 {
        if (p->is_write) {
                return ignore_write(vcpu, p);
        } else {
-               *vcpu_reg(vcpu, p->Rt) = (1 << 3);
+               p->regval = (1 << 3);
                return true;
        }
 }
 
 static bool trap_dbgauthstatus_el1(struct kvm_vcpu *vcpu,
-                                  const struct sys_reg_params *p,
+                                  struct sys_reg_params *p,
                                   const struct sys_reg_desc *r)
 {
        if (p->is_write) {
@@ -167,7 +162,7 @@ static bool trap_dbgauthstatus_el1(struct kvm_vcpu *vcpu,
        } else {
                u32 val;
                asm volatile("mrs %0, dbgauthstatus_el1" : "=r" (val));
-               *vcpu_reg(vcpu, p->Rt) = val;
+               p->regval = val;
                return true;
        }
 }
@@ -200,17 +195,17 @@ static bool trap_dbgauthstatus_el1(struct kvm_vcpu *vcpu,
  *   now use the debug registers.
  */
 static bool trap_debug_regs(struct kvm_vcpu *vcpu,
-                           const struct sys_reg_params *p,
+                           struct sys_reg_params *p,
                            const struct sys_reg_desc *r)
 {
        if (p->is_write) {
-               vcpu_sys_reg(vcpu, r->reg) = *vcpu_reg(vcpu, p->Rt);
+               vcpu_sys_reg(vcpu, r->reg) = p->regval;
                vcpu->arch.debug_flags |= KVM_ARM64_DEBUG_DIRTY;
        } else {
-               *vcpu_reg(vcpu, p->Rt) = vcpu_sys_reg(vcpu, r->reg);
+               p->regval = vcpu_sys_reg(vcpu, r->reg);
        }
 
-       trace_trap_reg(__func__, r->reg, p->is_write, *vcpu_reg(vcpu, p->Rt));
+       trace_trap_reg(__func__, r->reg, p->is_write, p->regval);
 
        return true;
 }
@@ -225,10 +220,10 @@ static bool trap_debug_regs(struct kvm_vcpu *vcpu,
  * hyp.S code switches between host and guest values in future.
  */
 static inline void reg_to_dbg(struct kvm_vcpu *vcpu,
-                             const struct sys_reg_params *p,
+                             struct sys_reg_params *p,
                              u64 *dbg_reg)
 {
-       u64 val = *vcpu_reg(vcpu, p->Rt);
+       u64 val = p->regval;
 
        if (p->is_32bit) {
                val &= 0xffffffffUL;
@@ -240,19 +235,16 @@ static inline void reg_to_dbg(struct kvm_vcpu *vcpu,
 }
 
 static inline void dbg_to_reg(struct kvm_vcpu *vcpu,
-                             const struct sys_reg_params *p,
+                             struct sys_reg_params *p,
                              u64 *dbg_reg)
 {
-       u64 val = *dbg_reg;
-
+       p->regval = *dbg_reg;
        if (p->is_32bit)
-               val &= 0xffffffffUL;
-
-       *vcpu_reg(vcpu, p->Rt) = val;
+               p->regval &= 0xffffffffUL;
 }
 
 static inline bool trap_bvr(struct kvm_vcpu *vcpu,
-                           const struct sys_reg_params *p,
+                           struct sys_reg_params *p,
                            const struct sys_reg_desc *rd)
 {
        u64 *dbg_reg = &vcpu->arch.vcpu_debug_state.dbg_bvr[rd->reg];
@@ -294,7 +286,7 @@ static inline void reset_bvr(struct kvm_vcpu *vcpu,
 }
 
 static inline bool trap_bcr(struct kvm_vcpu *vcpu,
-                           const struct sys_reg_params *p,
+                           struct sys_reg_params *p,
                            const struct sys_reg_desc *rd)
 {
        u64 *dbg_reg = &vcpu->arch.vcpu_debug_state.dbg_bcr[rd->reg];
@@ -337,7 +329,7 @@ static inline void reset_bcr(struct kvm_vcpu *vcpu,
 }
 
 static inline bool trap_wvr(struct kvm_vcpu *vcpu,
-                           const struct sys_reg_params *p,
+                           struct sys_reg_params *p,
                            const struct sys_reg_desc *rd)
 {
        u64 *dbg_reg = &vcpu->arch.vcpu_debug_state.dbg_wvr[rd->reg];
@@ -380,7 +372,7 @@ static inline void reset_wvr(struct kvm_vcpu *vcpu,
 }
 
 static inline bool trap_wcr(struct kvm_vcpu *vcpu,
-                           const struct sys_reg_params *p,
+                           struct sys_reg_params *p,
                            const struct sys_reg_desc *rd)
 {
        u64 *dbg_reg = &vcpu->arch.vcpu_debug_state.dbg_wcr[rd->reg];
@@ -687,7 +679,7 @@ static const struct sys_reg_desc sys_reg_descs[] = {
 };
 
 static bool trap_dbgidr(struct kvm_vcpu *vcpu,
-                       const struct sys_reg_params *p,
+                       struct sys_reg_params *p,
                        const struct sys_reg_desc *r)
 {
        if (p->is_write) {
@@ -697,23 +689,23 @@ static bool trap_dbgidr(struct kvm_vcpu *vcpu,
                u64 pfr = read_system_reg(SYS_ID_AA64PFR0_EL1);
                u32 el3 = !!cpuid_feature_extract_field(pfr, ID_AA64PFR0_EL3_SHIFT);
 
-               *vcpu_reg(vcpu, p->Rt) = ((((dfr >> ID_AA64DFR0_WRPS_SHIFT) & 0xf) << 28) |
-                                         (((dfr >> ID_AA64DFR0_BRPS_SHIFT) & 0xf) << 24) |
-                                         (((dfr >> ID_AA64DFR0_CTX_CMPS_SHIFT) & 0xf) << 20) |
-                                         (6 << 16) | (el3 << 14) | (el3 << 12));
+               p->regval = ((((dfr >> ID_AA64DFR0_WRPS_SHIFT) & 0xf) << 28) |
+                            (((dfr >> ID_AA64DFR0_BRPS_SHIFT) & 0xf) << 24) |
+                            (((dfr >> ID_AA64DFR0_CTX_CMPS_SHIFT) & 0xf) << 20)
+                            | (6 << 16) | (el3 << 14) | (el3 << 12));
                return true;
        }
 }
 
 static bool trap_debug32(struct kvm_vcpu *vcpu,
-                        const struct sys_reg_params *p,
+                        struct sys_reg_params *p,
                         const struct sys_reg_desc *r)
 {
        if (p->is_write) {
-               vcpu_cp14(vcpu, r->reg) = *vcpu_reg(vcpu, p->Rt);
+               vcpu_cp14(vcpu, r->reg) = p->regval;
                vcpu->arch.debug_flags |= KVM_ARM64_DEBUG_DIRTY;
        } else {
-               *vcpu_reg(vcpu, p->Rt) = vcpu_cp14(vcpu, r->reg);
+               p->regval = vcpu_cp14(vcpu, r->reg);
        }
 
        return true;
@@ -731,7 +723,7 @@ static bool trap_debug32(struct kvm_vcpu *vcpu,
  */
 
 static inline bool trap_xvr(struct kvm_vcpu *vcpu,
-                           const struct sys_reg_params *p,
+                           struct sys_reg_params *p,
                            const struct sys_reg_desc *rd)
 {
        u64 *dbg_reg = &vcpu->arch.vcpu_debug_state.dbg_bvr[rd->reg];
@@ -740,12 +732,12 @@ static inline bool trap_xvr(struct kvm_vcpu *vcpu,
                u64 val = *dbg_reg;
 
                val &= 0xffffffffUL;
-               val |= *vcpu_reg(vcpu, p->Rt) << 32;
+               val |= p->regval << 32;
                *dbg_reg = val;
 
                vcpu->arch.debug_flags |= KVM_ARM64_DEBUG_DIRTY;
        } else {
-               *vcpu_reg(vcpu, p->Rt) = *dbg_reg >> 32;
+               p->regval = *dbg_reg >> 32;
        }
 
        trace_trap_reg(__func__, rd->reg, p->is_write, *dbg_reg);
@@ -991,7 +983,7 @@ int kvm_handle_cp14_load_store(struct kvm_vcpu *vcpu, struct kvm_run *run)
  * Return 0 if the access has been handled, and -1 if not.
  */
 static int emulate_cp(struct kvm_vcpu *vcpu,
-                     const struct sys_reg_params *params,
+                     struct sys_reg_params *params,
                      const struct sys_reg_desc *table,
                      size_t num)
 {
@@ -1062,12 +1054,12 @@ static int kvm_handle_cp_64(struct kvm_vcpu *vcpu,
 {
        struct sys_reg_params params;
        u32 hsr = kvm_vcpu_get_hsr(vcpu);
+       int Rt = (hsr >> 5) & 0xf;
        int Rt2 = (hsr >> 10) & 0xf;
 
        params.is_aarch32 = true;
        params.is_32bit = false;
        params.CRm = (hsr >> 1) & 0xf;
-       params.Rt = (hsr >> 5) & 0xf;
        params.is_write = ((hsr & 1) == 0);
 
        params.Op0 = 0;
@@ -1076,15 +1068,12 @@ static int kvm_handle_cp_64(struct kvm_vcpu *vcpu,
        params.CRn = 0;
 
        /*
-        * Massive hack here. Store Rt2 in the top 32bits so we only
-        * have one register to deal with. As we use the same trap
+        * Make a 64-bit value out of Rt and Rt2. As we use the same trap
         * backends between AArch32 and AArch64, we get away with it.
         */
        if (params.is_write) {
-               u64 val = *vcpu_reg(vcpu, params.Rt);
-               val &= 0xffffffff;
-               val |= *vcpu_reg(vcpu, Rt2) << 32;
-               *vcpu_reg(vcpu, params.Rt) = val;
+               params.regval = vcpu_get_reg(vcpu, Rt) & 0xffffffff;
+               params.regval |= vcpu_get_reg(vcpu, Rt2) << 32;
        }
 
        if (!emulate_cp(vcpu, &params, target_specific, nr_specific))
@@ -1095,11 +1084,10 @@ static int kvm_handle_cp_64(struct kvm_vcpu *vcpu,
        unhandled_cp_access(vcpu, &params);
 
 out:
-       /* Do the opposite hack for the read side */
+       /* Split up the value between registers for the read side */
        if (!params.is_write) {
-               u64 val = *vcpu_reg(vcpu, params.Rt);
-               val >>= 32;
-               *vcpu_reg(vcpu, Rt2) = val;
+               vcpu_set_reg(vcpu, Rt, lower_32_bits(params.regval));
+               vcpu_set_reg(vcpu, Rt2, upper_32_bits(params.regval));
        }
 
        return 1;
@@ -1118,21 +1106,24 @@ static int kvm_handle_cp_32(struct kvm_vcpu *vcpu,
 {
        struct sys_reg_params params;
        u32 hsr = kvm_vcpu_get_hsr(vcpu);
+       int Rt  = (hsr >> 5) & 0xf;
 
        params.is_aarch32 = true;
        params.is_32bit = true;
        params.CRm = (hsr >> 1) & 0xf;
-       params.Rt  = (hsr >> 5) & 0xf;
+       params.regval = vcpu_get_reg(vcpu, Rt);
        params.is_write = ((hsr & 1) == 0);
        params.CRn = (hsr >> 10) & 0xf;
        params.Op0 = 0;
        params.Op1 = (hsr >> 14) & 0x7;
        params.Op2 = (hsr >> 17) & 0x7;
 
-       if (!emulate_cp(vcpu, &params, target_specific, nr_specific))
-               return 1;
-       if (!emulate_cp(vcpu, &params, global, nr_global))
+       if (!emulate_cp(vcpu, &params, target_specific, nr_specific) ||
+           !emulate_cp(vcpu, &params, global, nr_global)) {
+               if (!params.is_write)
+                       vcpu_set_reg(vcpu, Rt, params.regval);
                return 1;
+       }
 
        unhandled_cp_access(vcpu, &params);
        return 1;
@@ -1175,7 +1166,7 @@ int kvm_handle_cp14_32(struct kvm_vcpu *vcpu, struct kvm_run *run)
 }
 
 static int emulate_sys_reg(struct kvm_vcpu *vcpu,
-                          const struct sys_reg_params *params)
+                          struct sys_reg_params *params)
 {
        size_t num;
        const struct sys_reg_desc *table, *r;
@@ -1230,6 +1221,8 @@ int kvm_handle_sys_reg(struct kvm_vcpu *vcpu, struct kvm_run *run)
 {
        struct sys_reg_params params;
        unsigned long esr = kvm_vcpu_get_hsr(vcpu);
+       int Rt = (esr >> 5) & 0x1f;
+       int ret;
 
        trace_kvm_handle_sys_reg(esr);
 
@@ -1240,10 +1233,14 @@ int kvm_handle_sys_reg(struct kvm_vcpu *vcpu, struct kvm_run *run)
        params.CRn = (esr >> 10) & 0xf;
        params.CRm = (esr >> 1) & 0xf;
        params.Op2 = (esr >> 17) & 0x7;
-       params.Rt = (esr >> 5) & 0x1f;
+       params.regval = vcpu_get_reg(vcpu, Rt);
        params.is_write = !(esr & 1);
 
-       return emulate_sys_reg(vcpu, &params);
+       ret = emulate_sys_reg(vcpu, &params);
+
+       if (!params.is_write)
+               vcpu_set_reg(vcpu, Rt, params.regval);
+       return ret;
 }
 
 /******************************************************************************
index eaa324e4db4da1149adfe7ae012b895353f05e91..dbbb01cfbee9c504980943921c841b61118837b8 100644 (file)
@@ -28,7 +28,7 @@ struct sys_reg_params {
        u8      CRn;
        u8      CRm;
        u8      Op2;
-       u8      Rt;
+       u64     regval;
        bool    is_write;
        bool    is_aarch32;
        bool    is_32bit;       /* Only valid if is_aarch32 is true */
@@ -44,7 +44,7 @@ struct sys_reg_desc {
 
        /* Trapped access from guest, if non-NULL. */
        bool (*access)(struct kvm_vcpu *,
-                      const struct sys_reg_params *,
+                      struct sys_reg_params *,
                       const struct sys_reg_desc *);
 
        /* Initialization for vcpu. */
@@ -77,9 +77,9 @@ static inline bool ignore_write(struct kvm_vcpu *vcpu,
 }
 
 static inline bool read_zero(struct kvm_vcpu *vcpu,
-                            const struct sys_reg_params *p)
+                            struct sys_reg_params *p)
 {
-       *vcpu_reg(vcpu, p->Rt) = 0;
+       p->regval = 0;
        return true;
 }
 
index 1e4576824165502d2a6d5a1caee9e0c1da10c3fa..ed90578fa120e50f5685ef51c82dd86efed6f837 100644 (file)
 #include "sys_regs.h"
 
 static bool access_actlr(struct kvm_vcpu *vcpu,
-                        const struct sys_reg_params *p,
+                        struct sys_reg_params *p,
                         const struct sys_reg_desc *r)
 {
        if (p->is_write)
                return ignore_write(vcpu, p);
 
-       *vcpu_reg(vcpu, p->Rt) = vcpu_sys_reg(vcpu, ACTLR_EL1);
+       p->regval = vcpu_sys_reg(vcpu, ACTLR_EL1);
        return true;
 }
 
index f636a2639f031dd03d0b5058ccf378721d67dbf4..e87f53ff5f583aeb47b3ec3187d229df380b2c50 100644 (file)
@@ -76,13 +76,28 @@ static void flush_context(unsigned int cpu)
                __flush_icache_all();
 }
 
-static int is_reserved_asid(u64 asid)
+static bool check_update_reserved_asid(u64 asid, u64 newasid)
 {
        int cpu;
-       for_each_possible_cpu(cpu)
-               if (per_cpu(reserved_asids, cpu) == asid)
-                       return 1;
-       return 0;
+       bool hit = false;
+
+       /*
+        * Iterate over the set of reserved ASIDs looking for a match.
+        * If we find one, then we can update our mm to use newasid
+        * (i.e. the same ASID in the current generation) but we can't
+        * exit the loop early, since we need to ensure that all copies
+        * of the old ASID are updated to reflect the mm. Failure to do
+        * so could result in us missing the reserved ASID in a future
+        * generation.
+        */
+       for_each_possible_cpu(cpu) {
+               if (per_cpu(reserved_asids, cpu) == asid) {
+                       hit = true;
+                       per_cpu(reserved_asids, cpu) = newasid;
+               }
+       }
+
+       return hit;
 }
 
 static u64 new_context(struct mm_struct *mm, unsigned int cpu)
@@ -92,12 +107,14 @@ static u64 new_context(struct mm_struct *mm, unsigned int cpu)
        u64 generation = atomic64_read(&asid_generation);
 
        if (asid != 0) {
+               u64 newasid = generation | (asid & ~ASID_MASK);
+
                /*
                 * If our current ASID was active during a rollover, we
                 * can continue to use it and this was just a false alarm.
                 */
-               if (is_reserved_asid(asid))
-                       return generation | (asid & ~ASID_MASK);
+               if (check_update_reserved_asid(asid, newasid))
+                       return newasid;
 
                /*
                 * We had a valid ASID in a previous life, so try to re-use
@@ -105,7 +122,7 @@ static u64 new_context(struct mm_struct *mm, unsigned int cpu)
                 */
                asid &= ~ASID_MASK;
                if (!__test_and_set_bit(asid, asid_map))
-                       goto bump_gen;
+                       return newasid;
        }
 
        /*
@@ -129,10 +146,7 @@ static u64 new_context(struct mm_struct *mm, unsigned int cpu)
 set_asid:
        __set_bit(asid, asid_map);
        cur_idx = asid;
-
-bump_gen:
-       asid |= generation;
-       return asid;
+       return asid | generation;
 }
 
 void check_and_switch_context(struct mm_struct *mm, unsigned int cpu)
index 131a199114b405e8403f05137e560a2b317f4941..7963aa4b5d2869b70dfd9a2f3d0ef501a033480b 100644 (file)
@@ -18,6 +18,7 @@
  */
 
 #include <linux/gfp.h>
+#include <linux/acpi.h>
 #include <linux/export.h>
 #include <linux/slab.h>
 #include <linux/genalloc.h>
@@ -28,9 +29,6 @@
 
 #include <asm/cacheflush.h>
 
-struct dma_map_ops *dma_ops;
-EXPORT_SYMBOL(dma_ops);
-
 static pgprot_t __get_dma_pgprot(struct dma_attrs *attrs, pgprot_t prot,
                                 bool coherent)
 {
@@ -515,13 +513,7 @@ EXPORT_SYMBOL(dummy_dma_ops);
 
 static int __init arm64_dma_init(void)
 {
-       int ret;
-
-       dma_ops = &swiotlb_dma_ops;
-
-       ret = atomic_pool_init();
-
-       return ret;
+       return atomic_pool_init();
 }
 arch_initcall(arm64_dma_init);
 
@@ -552,10 +544,14 @@ static void *__iommu_alloc_attrs(struct device *dev, size_t size,
 {
        bool coherent = is_device_dma_coherent(dev);
        int ioprot = dma_direction_to_prot(DMA_BIDIRECTIONAL, coherent);
+       size_t iosize = size;
        void *addr;
 
        if (WARN(!dev, "cannot create IOMMU mapping for unknown device\n"))
                return NULL;
+
+       size = PAGE_ALIGN(size);
+
        /*
         * Some drivers rely on this, and we probably don't want the
         * possibility of stale kernel data being read by devices anyway.
@@ -566,7 +562,7 @@ static void *__iommu_alloc_attrs(struct device *dev, size_t size,
                struct page **pages;
                pgprot_t prot = __get_dma_pgprot(attrs, PAGE_KERNEL, coherent);
 
-               pages = iommu_dma_alloc(dev, size, gfp, ioprot, handle,
+               pages = iommu_dma_alloc(dev, iosize, gfp, ioprot, handle,
                                        flush_page);
                if (!pages)
                        return NULL;
@@ -574,7 +570,7 @@ static void *__iommu_alloc_attrs(struct device *dev, size_t size,
                addr = dma_common_pages_remap(pages, size, VM_USERMAP, prot,
                                              __builtin_return_address(0));
                if (!addr)
-                       iommu_dma_free(dev, pages, size, handle);
+                       iommu_dma_free(dev, pages, iosize, handle);
        } else {
                struct page *page;
                /*
@@ -591,7 +587,7 @@ static void *__iommu_alloc_attrs(struct device *dev, size_t size,
                if (!addr)
                        return NULL;
 
-               *handle = iommu_dma_map_page(dev, page, 0, size, ioprot);
+               *handle = iommu_dma_map_page(dev, page, 0, iosize, ioprot);
                if (iommu_dma_mapping_error(dev, *handle)) {
                        if (coherent)
                                __free_pages(page, get_order(size));
@@ -606,6 +602,9 @@ static void *__iommu_alloc_attrs(struct device *dev, size_t size,
 static void __iommu_free_attrs(struct device *dev, size_t size, void *cpu_addr,
                               dma_addr_t handle, struct dma_attrs *attrs)
 {
+       size_t iosize = size;
+
+       size = PAGE_ALIGN(size);
        /*
         * @cpu_addr will be one of 3 things depending on how it was allocated:
         * - A remapped array of pages from iommu_dma_alloc(), for all
@@ -617,17 +616,17 @@ static void __iommu_free_attrs(struct device *dev, size_t size, void *cpu_addr,
         * Hence how dodgy the below logic looks...
         */
        if (__in_atomic_pool(cpu_addr, size)) {
-               iommu_dma_unmap_page(dev, handle, size, 0, NULL);
+               iommu_dma_unmap_page(dev, handle, iosize, 0, NULL);
                __free_from_pool(cpu_addr, size);
        } else if (is_vmalloc_addr(cpu_addr)){
                struct vm_struct *area = find_vm_area(cpu_addr);
 
                if (WARN_ON(!area || !area->pages))
                        return;
-               iommu_dma_free(dev, area->pages, size, &handle);
+               iommu_dma_free(dev, area->pages, iosize, &handle);
                dma_common_free_remap(cpu_addr, size, VM_USERMAP);
        } else {
-               iommu_dma_unmap_page(dev, handle, size, 0, NULL);
+               iommu_dma_unmap_page(dev, handle, iosize, 0, NULL);
                __free_pages(virt_to_page(cpu_addr), get_order(size));
        }
 }
@@ -984,8 +983,8 @@ static void __iommu_setup_dma_ops(struct device *dev, u64 dma_base, u64 size,
 void arch_setup_dma_ops(struct device *dev, u64 dma_base, u64 size,
                        struct iommu_ops *iommu, bool coherent)
 {
-       if (!acpi_disabled && !dev->archdata.dma_ops)
-               dev->archdata.dma_ops = dma_ops;
+       if (!dev->archdata.dma_ops)
+               dev->archdata.dma_ops = &swiotlb_dma_ops;
 
        dev->archdata.dma_coherent = coherent;
        __iommu_setup_dma_ops(dev, dma_base, size, iommu);
index 19211c4a891111cee301552a234821646f522ea6..92ddac1e8ca2f35b8f24028514bb761aed3591a4 100644 (file)
@@ -393,16 +393,16 @@ static struct fault_info {
        { do_translation_fault, SIGSEGV, SEGV_MAPERR,   "level 1 translation fault"     },
        { do_translation_fault, SIGSEGV, SEGV_MAPERR,   "level 2 translation fault"     },
        { do_page_fault,        SIGSEGV, SEGV_MAPERR,   "level 3 translation fault"     },
-       { do_bad,               SIGBUS,  0,             "reserved access flag fault"    },
+       { do_bad,               SIGBUS,  0,             "unknown 8"                     },
        { do_page_fault,        SIGSEGV, SEGV_ACCERR,   "level 1 access flag fault"     },
        { do_page_fault,        SIGSEGV, SEGV_ACCERR,   "level 2 access flag fault"     },
        { do_page_fault,        SIGSEGV, SEGV_ACCERR,   "level 3 access flag fault"     },
-       { do_bad,               SIGBUS,  0,             "reserved permission fault"     },
+       { do_bad,               SIGBUS,  0,             "unknown 12"                    },
        { do_page_fault,        SIGSEGV, SEGV_ACCERR,   "level 1 permission fault"      },
        { do_page_fault,        SIGSEGV, SEGV_ACCERR,   "level 2 permission fault"      },
        { do_page_fault,        SIGSEGV, SEGV_ACCERR,   "level 3 permission fault"      },
        { do_bad,               SIGBUS,  0,             "synchronous external abort"    },
-       { do_bad,               SIGBUS,  0,             "asynchronous external abort"   },
+       { do_bad,               SIGBUS,  0,             "unknown 17"                    },
        { do_bad,               SIGBUS,  0,             "unknown 18"                    },
        { do_bad,               SIGBUS,  0,             "unknown 19"                    },
        { do_bad,               SIGBUS,  0,             "synchronous abort (translation table walk)" },
@@ -410,16 +410,16 @@ static struct fault_info {
        { do_bad,               SIGBUS,  0,             "synchronous abort (translation table walk)" },
        { do_bad,               SIGBUS,  0,             "synchronous abort (translation table walk)" },
        { do_bad,               SIGBUS,  0,             "synchronous parity error"      },
-       { do_bad,               SIGBUS,  0,             "asynchronous parity error"     },
+       { do_bad,               SIGBUS,  0,             "unknown 25"                    },
        { do_bad,               SIGBUS,  0,             "unknown 26"                    },
        { do_bad,               SIGBUS,  0,             "unknown 27"                    },
-       { do_bad,               SIGBUS,  0,             "synchronous parity error (translation table walk" },
-       { do_bad,               SIGBUS,  0,             "synchronous parity error (translation table walk" },
-       { do_bad,               SIGBUS,  0,             "synchronous parity error (translation table walk" },
-       { do_bad,               SIGBUS,  0,             "synchronous parity error (translation table walk" },
+       { do_bad,               SIGBUS,  0,             "synchronous parity error (translation table walk)" },
+       { do_bad,               SIGBUS,  0,             "synchronous parity error (translation table walk)" },
+       { do_bad,               SIGBUS,  0,             "synchronous parity error (translation table walk)" },
+       { do_bad,               SIGBUS,  0,             "synchronous parity error (translation table walk)" },
        { do_bad,               SIGBUS,  0,             "unknown 32"                    },
        { do_bad,               SIGBUS,  BUS_ADRALN,    "alignment fault"               },
-       { do_bad,               SIGBUS,  0,             "debug event"                   },
+       { do_bad,               SIGBUS,  0,             "unknown 34"                    },
        { do_bad,               SIGBUS,  0,             "unknown 35"                    },
        { do_bad,               SIGBUS,  0,             "unknown 36"                    },
        { do_bad,               SIGBUS,  0,             "unknown 37"                    },
@@ -433,21 +433,21 @@ static struct fault_info {
        { do_bad,               SIGBUS,  0,             "unknown 45"                    },
        { do_bad,               SIGBUS,  0,             "unknown 46"                    },
        { do_bad,               SIGBUS,  0,             "unknown 47"                    },
-       { do_bad,               SIGBUS,  0,             "unknown 48"                    },
+       { do_bad,               SIGBUS,  0,             "TLB conflict abort"            },
        { do_bad,               SIGBUS,  0,             "unknown 49"                    },
        { do_bad,               SIGBUS,  0,             "unknown 50"                    },
        { do_bad,               SIGBUS,  0,             "unknown 51"                    },
        { do_bad,               SIGBUS,  0,             "implementation fault (lockdown abort)" },
-       { do_bad,               SIGBUS,  0,             "unknown 53"                    },
+       { do_bad,               SIGBUS,  0,             "implementation fault (unsupported exclusive)" },
        { do_bad,               SIGBUS,  0,             "unknown 54"                    },
        { do_bad,               SIGBUS,  0,             "unknown 55"                    },
        { do_bad,               SIGBUS,  0,             "unknown 56"                    },
        { do_bad,               SIGBUS,  0,             "unknown 57"                    },
-       { do_bad,               SIGBUS,  0,             "implementation fault (coprocessor abort)" },
+       { do_bad,               SIGBUS,  0,             "unknown 58"                    },
        { do_bad,               SIGBUS,  0,             "unknown 59"                    },
        { do_bad,               SIGBUS,  0,             "unknown 60"                    },
-       { do_bad,               SIGBUS,  0,             "unknown 61"                    },
-       { do_bad,               SIGBUS,  0,             "unknown 62"                    },
+       { do_bad,               SIGBUS,  0,             "section domain fault"          },
+       { do_bad,               SIGBUS,  0,             "page domain fault"             },
        { do_bad,               SIGBUS,  0,             "unknown 63"                    },
 };
 
index e3f563c81c4802c1f9c519fe2bfc7317f8ab5467..873e363048c6c661eda620bbd4f826ba568c5ba7 100644 (file)
@@ -64,8 +64,12 @@ EXPORT_SYMBOL(phys_mem_access_prot);
 
 static void __init *early_alloc(unsigned long sz)
 {
-       void *ptr = __va(memblock_alloc(sz, sz));
-       BUG_ON(!ptr);
+       phys_addr_t phys;
+       void *ptr;
+
+       phys = memblock_alloc(sz, sz);
+       BUG_ON(!phys);
+       ptr = __va(phys);
        memset(ptr, 0, sz);
        return ptr;
 }
@@ -81,55 +85,19 @@ static void split_pmd(pmd_t *pmd, pte_t *pte)
        do {
                /*
                 * Need to have the least restrictive permissions available
-                * permissions will be fixed up later. Default the new page
-                * range as contiguous ptes.
+                * permissions will be fixed up later
                 */
-               set_pte(pte, pfn_pte(pfn, PAGE_KERNEL_EXEC_CONT));
+               set_pte(pte, pfn_pte(pfn, PAGE_KERNEL_EXEC));
                pfn++;
        } while (pte++, i++, i < PTRS_PER_PTE);
 }
 
-/*
- * Given a PTE with the CONT bit set, determine where the CONT range
- * starts, and clear the entire range of PTE CONT bits.
- */
-static void clear_cont_pte_range(pte_t *pte, unsigned long addr)
-{
-       int i;
-
-       pte -= CONT_RANGE_OFFSET(addr);
-       for (i = 0; i < CONT_PTES; i++) {
-               set_pte(pte, pte_mknoncont(*pte));
-               pte++;
-       }
-       flush_tlb_all();
-}
-
-/*
- * Given a range of PTEs set the pfn and provided page protection flags
- */
-static void __populate_init_pte(pte_t *pte, unsigned long addr,
-                               unsigned long end, phys_addr_t phys,
-                               pgprot_t prot)
-{
-       unsigned long pfn = __phys_to_pfn(phys);
-
-       do {
-               /* clear all the bits except the pfn, then apply the prot */
-               set_pte(pte, pfn_pte(pfn, prot));
-               pte++;
-               pfn++;
-               addr += PAGE_SIZE;
-       } while (addr != end);
-}
-
 static void alloc_init_pte(pmd_t *pmd, unsigned long addr,
-                                 unsigned long end, phys_addr_t phys,
+                                 unsigned long end, unsigned long pfn,
                                  pgprot_t prot,
                                  void *(*alloc)(unsigned long size))
 {
        pte_t *pte;
-       unsigned long next;
 
        if (pmd_none(*pmd) || pmd_sect(*pmd)) {
                pte = alloc(PTRS_PER_PTE * sizeof(pte_t));
@@ -142,27 +110,9 @@ static void alloc_init_pte(pmd_t *pmd, unsigned long addr,
 
        pte = pte_offset_kernel(pmd, addr);
        do {
-               next = min(end, (addr + CONT_SIZE) & CONT_MASK);
-               if (((addr | next | phys) & ~CONT_MASK) == 0) {
-                       /* a block of CONT_PTES  */
-                       __populate_init_pte(pte, addr, next, phys,
-                                           __pgprot(pgprot_val(prot) | PTE_CONT));
-               } else {
-                       /*
-                        * If the range being split is already inside of a
-                        * contiguous range but this PTE isn't going to be
-                        * contiguous, then we want to unmark the adjacent
-                        * ranges, then update the portion of the range we
-                        * are interrested in.
-                        */
-                        clear_cont_pte_range(pte, addr);
-                        __populate_init_pte(pte, addr, next, phys, prot);
-               }
-
-               pte += (next - addr) >> PAGE_SHIFT;
-               phys += next - addr;
-               addr = next;
-       } while (addr != end);
+               set_pte(pte, pfn_pte(pfn, prot));
+               pfn++;
+       } while (pte++, addr += PAGE_SIZE, addr != end);
 }
 
 static void split_pud(pud_t *old_pud, pmd_t *pmd)
@@ -223,7 +173,8 @@ static void alloc_init_pmd(struct mm_struct *mm, pud_t *pud,
                                }
                        }
                } else {
-                       alloc_init_pte(pmd, addr, next, phys, prot, alloc);
+                       alloc_init_pte(pmd, addr, next, __phys_to_pfn(phys),
+                                      prot, alloc);
                }
                phys += next - addr;
        } while (pmd++, addr = next, addr != end);
@@ -362,8 +313,8 @@ static void __init __map_memblock(phys_addr_t start, phys_addr_t end)
         * for now. This will get more fine grained later once all memory
         * is mapped
         */
-       unsigned long kernel_x_start = round_down(__pa(_stext), SECTION_SIZE);
-       unsigned long kernel_x_end = round_up(__pa(__init_end), SECTION_SIZE);
+       unsigned long kernel_x_start = round_down(__pa(_stext), SWAPPER_BLOCK_SIZE);
+       unsigned long kernel_x_end = round_up(__pa(__init_end), SWAPPER_BLOCK_SIZE);
 
        if (end < kernel_x_start) {
                create_mapping(start, __phys_to_virt(start),
@@ -451,18 +402,18 @@ static void __init fixup_executable(void)
 {
 #ifdef CONFIG_DEBUG_RODATA
        /* now that we are actually fully mapped, make the start/end more fine grained */
-       if (!IS_ALIGNED((unsigned long)_stext, SECTION_SIZE)) {
+       if (!IS_ALIGNED((unsigned long)_stext, SWAPPER_BLOCK_SIZE)) {
                unsigned long aligned_start = round_down(__pa(_stext),
-                                                       SECTION_SIZE);
+                                                        SWAPPER_BLOCK_SIZE);
 
                create_mapping(aligned_start, __phys_to_virt(aligned_start),
                                __pa(_stext) - aligned_start,
                                PAGE_KERNEL);
        }
 
-       if (!IS_ALIGNED((unsigned long)__init_end, SECTION_SIZE)) {
+       if (!IS_ALIGNED((unsigned long)__init_end, SWAPPER_BLOCK_SIZE)) {
                unsigned long aligned_end = round_up(__pa(__init_end),
-                                                       SECTION_SIZE);
+                                                         SWAPPER_BLOCK_SIZE);
                create_mapping(__pa(__init_end), (unsigned long)__init_end,
                                aligned_end - __pa(__init_end),
                                PAGE_KERNEL);
@@ -475,7 +426,7 @@ void mark_rodata_ro(void)
 {
        create_mapping_late(__pa(_stext), (unsigned long)_stext,
                                (unsigned long)_etext - (unsigned long)_stext,
-                               PAGE_KERNEL_EXEC | PTE_RDONLY);
+                               PAGE_KERNEL_ROX);
 
 }
 #endif
index cf3c7d4a1b585a928d9b4451ee268141d95d7088..b162ad70effcfeacbc7a304d569b222717f495d7 100644 (file)
@@ -50,7 +50,7 @@ static const int bpf2a64[] = {
        [BPF_REG_8] = A64_R(21),
        [BPF_REG_9] = A64_R(22),
        /* read-only frame pointer to access stack */
-       [BPF_REG_FP] = A64_FP,
+       [BPF_REG_FP] = A64_R(25),
        /* temporary register for internal BPF JIT */
        [TMP_REG_1] = A64_R(23),
        [TMP_REG_2] = A64_R(24),
@@ -139,6 +139,12 @@ static inline int epilogue_offset(const struct jit_ctx *ctx)
 /* Stack must be multiples of 16B */
 #define STACK_ALIGN(sz) (((sz) + 15) & ~15)
 
+#define _STACK_SIZE \
+       (MAX_BPF_STACK \
+        + 4 /* extra for skb_copy_bits buffer */)
+
+#define STACK_SIZE STACK_ALIGN(_STACK_SIZE)
+
 static void build_prologue(struct jit_ctx *ctx)
 {
        const u8 r6 = bpf2a64[BPF_REG_6];
@@ -150,10 +156,35 @@ static void build_prologue(struct jit_ctx *ctx)
        const u8 rx = bpf2a64[BPF_REG_X];
        const u8 tmp1 = bpf2a64[TMP_REG_1];
        const u8 tmp2 = bpf2a64[TMP_REG_2];
-       int stack_size = MAX_BPF_STACK;
 
-       stack_size += 4; /* extra for skb_copy_bits buffer */
-       stack_size = STACK_ALIGN(stack_size);
+       /*
+        * BPF prog stack layout
+        *
+        *                         high
+        * original A64_SP =>   0:+-----+ BPF prologue
+        *                        |FP/LR|
+        * current A64_FP =>  -16:+-----+
+        *                        | ... | callee saved registers
+        *                        +-----+
+        *                        |     | x25/x26
+        * BPF fp register => -80:+-----+ <= (BPF_FP)
+        *                        |     |
+        *                        | ... | BPF prog stack
+        *                        |     |
+        *                        +-----+ <= (BPF_FP - MAX_BPF_STACK)
+        *                        |RSVD | JIT scratchpad
+        * current A64_SP =>      +-----+ <= (BPF_FP - STACK_SIZE)
+        *                        |     |
+        *                        | ... | Function call stack
+        *                        |     |
+        *                        +-----+
+        *                          low
+        *
+        */
+
+       /* Save FP and LR registers to stay align with ARM64 AAPCS */
+       emit(A64_PUSH(A64_FP, A64_LR, A64_SP), ctx);
+       emit(A64_MOV(1, A64_FP, A64_SP), ctx);
 
        /* Save callee-saved register */
        emit(A64_PUSH(r6, r7, A64_SP), ctx);
@@ -161,12 +192,15 @@ static void build_prologue(struct jit_ctx *ctx)
        if (ctx->tmp_used)
                emit(A64_PUSH(tmp1, tmp2, A64_SP), ctx);
 
-       /* Set up BPF stack */
-       emit(A64_SUB_I(1, A64_SP, A64_SP, stack_size), ctx);
+       /* Save fp (x25) and x26. SP requires 16 bytes alignment */
+       emit(A64_PUSH(fp, A64_R(26), A64_SP), ctx);
 
-       /* Set up frame pointer */
+       /* Set up BPF prog stack base register (x25) */
        emit(A64_MOV(1, fp, A64_SP), ctx);
 
+       /* Set up function call stack */
+       emit(A64_SUB_I(1, A64_SP, A64_SP, STACK_SIZE), ctx);
+
        /* Clear registers A and X */
        emit_a64_mov_i64(ra, 0, ctx);
        emit_a64_mov_i64(rx, 0, ctx);
@@ -182,13 +216,12 @@ static void build_epilogue(struct jit_ctx *ctx)
        const u8 fp = bpf2a64[BPF_REG_FP];
        const u8 tmp1 = bpf2a64[TMP_REG_1];
        const u8 tmp2 = bpf2a64[TMP_REG_2];
-       int stack_size = MAX_BPF_STACK;
-
-       stack_size += 4; /* extra for skb_copy_bits buffer */
-       stack_size = STACK_ALIGN(stack_size);
 
        /* We're done with BPF stack */
-       emit(A64_ADD_I(1, A64_SP, A64_SP, stack_size), ctx);
+       emit(A64_ADD_I(1, A64_SP, A64_SP, STACK_SIZE), ctx);
+
+       /* Restore fs (x25) and x26 */
+       emit(A64_POP(fp, A64_R(26), A64_SP), ctx);
 
        /* Restore callee-saved register */
        if (ctx->tmp_used)
@@ -196,8 +229,8 @@ static void build_epilogue(struct jit_ctx *ctx)
        emit(A64_POP(r8, r9, A64_SP), ctx);
        emit(A64_POP(r6, r7, A64_SP), ctx);
 
-       /* Restore frame pointer */
-       emit(A64_MOV(1, fp, A64_SP), ctx);
+       /* Restore FP/LR registers */
+       emit(A64_POP(A64_FP, A64_LR, A64_SP), ctx);
 
        /* Set return value */
        emit(A64_MOV(1, A64_R(0), r0), ctx);
@@ -557,7 +590,25 @@ emit_cond_jmp:
        case BPF_ST | BPF_MEM | BPF_H:
        case BPF_ST | BPF_MEM | BPF_B:
        case BPF_ST | BPF_MEM | BPF_DW:
-               goto notyet;
+               /* Load imm to a register then store it */
+               ctx->tmp_used = 1;
+               emit_a64_mov_i(1, tmp2, off, ctx);
+               emit_a64_mov_i(1, tmp, imm, ctx);
+               switch (BPF_SIZE(code)) {
+               case BPF_W:
+                       emit(A64_STR32(tmp, dst, tmp2), ctx);
+                       break;
+               case BPF_H:
+                       emit(A64_STRH(tmp, dst, tmp2), ctx);
+                       break;
+               case BPF_B:
+                       emit(A64_STRB(tmp, dst, tmp2), ctx);
+                       break;
+               case BPF_DW:
+                       emit(A64_STR64(tmp, dst, tmp2), ctx);
+                       break;
+               }
+               break;
 
        /* STX: *(size *)(dst + off) = src */
        case BPF_STX | BPF_MEM | BPF_W:
@@ -624,7 +675,7 @@ emit_cond_jmp:
                        return -EINVAL;
                }
                emit_a64_mov_i64(r3, size, ctx);
-               emit(A64_ADD_I(1, r4, fp, MAX_BPF_STACK), ctx);
+               emit(A64_SUB_I(1, r4, fp, STACK_SIZE), ctx);
                emit_a64_mov_i64(r5, (unsigned long)bpf_load_pointer, ctx);
                emit(A64_PUSH(A64_FP, A64_LR, A64_SP), ctx);
                emit(A64_MOV(1, A64_FP, A64_SP), ctx);
@@ -758,7 +809,7 @@ void bpf_int_jit_compile(struct bpf_prog *prog)
        if (bpf_jit_enable > 1)
                bpf_jit_dump(prog->len, image_size, 2, ctx.image);
 
-       bpf_flush_icache(ctx.image, ctx.image + ctx.idx);
+       bpf_flush_icache(header, ctx.image + ctx.idx);
 
        set_memory_ro((unsigned long)header, header->pages);
        prog->bpf_func = (void *)ctx.image;
index 1e9c8b0bf48666cfba1ee19d8731eb71cf68a77e..170d786807c460eda342f4383dc379e5279a215d 100644 (file)
@@ -14,7 +14,7 @@
  *  Copyright (C) 2008-2009 Red Hat, Inc., Ingo Molnar
  *  Copyright (C) 2009 Jaswinder Singh Rajput
  *  Copyright (C) 2009 Advanced Micro Devices, Inc., Robert Richter
- *  Copyright (C) 2008-2009 Red Hat, Inc., Peter Zijlstra <pzijlstr@redhat.com>
+ *  Copyright (C) 2008-2009 Red Hat, Inc., Peter Zijlstra
  *  Copyright (C) 2009 Intel Corporation, <markus.t.metzger@intel.com>
  *
  * ppc:
index db73390568c8dd873fc045cd35773714bd35f8e1..74c132d901bd290bcc803b7c0a0266428a2ec1cb 100644 (file)
@@ -11,7 +11,7 @@
 
 
 
-#define NR_syscalls                    322 /* length of syscall table */
+#define NR_syscalls                    323 /* length of syscall table */
 
 /*
  * The following defines stop scripts/checksyscalls.sh from complaining about
index 9038726e7d26777bf8f704f101ff86090e4d5059..762edce7572eb33f03a3402e4357de69626764c9 100644 (file)
 #define __NR_userfaultfd               1343
 #define __NR_membarrier                        1344
 #define __NR_kcmp                      1345
+#define __NR_mlock2                    1346
 
 #endif /* _UAPI_ASM_IA64_UNISTD_H */
index dcd97f84d065435a8eca5c041f33bb67c3912797..534a74acb849d736726b5f066675f0a3a4c87ed4 100644 (file)
@@ -1771,5 +1771,6 @@ sys_call_table:
        data8 sys_userfaultfd
        data8 sys_membarrier
        data8 sys_kcmp                          // 1345
+       data8 sys_mlock2
 
        .org sys_call_table + 8*NR_syscalls     // guard against failures to increase NR_syscalls
index fd104bd221ced1dff2c9485bdcb1be520171df7f..860e440611c98f7e0c2a9882c18dc73cf166f35e 100644 (file)
@@ -3,6 +3,7 @@ generic-y += clkdev.h
 generic-y += cputime.h
 generic-y += exec.h
 generic-y += irq_work.h
+generic-y += kvm_para.h
 generic-y += mcs_spinlock.h
 generic-y += mm-arch-hooks.h
 generic-y += module.h
index 61b8931bc19250df3af7b42b4e667749332b6be1..4b0f5e001d4d5ab2a545e62dcc276b9815df5821 100644 (file)
@@ -168,13 +168,21 @@ static inline void _writel(unsigned long l, unsigned long addr)
 #define writew_relaxed writew
 #define writel_relaxed writel
 
-#define ioread8 read
+#define ioread8 readb
 #define ioread16 readw
 #define ioread32 readl
 #define iowrite8 writeb
 #define iowrite16 writew
 #define iowrite32 writel
 
+#define ioread8_rep(p, dst, count) insb((unsigned long)(p), (dst), (count))
+#define ioread16_rep(p, dst, count) insw((unsigned long)(p), (dst), (count))
+#define ioread32_rep(p, dst, count) insl((unsigned long)(p), (dst), (count))
+
+#define iowrite8_rep(p, src, count) outsb((unsigned long)(p), (src), (count))
+#define iowrite16_rep(p, src, count) outsw((unsigned long)(p), (src), (count))
+#define iowrite32_rep(p, src, count) outsl((unsigned long)(p), (src), (count))
+
 #define ioread16be(addr)       be16_to_cpu(readw(addr))
 #define ioread32be(addr)       be32_to_cpu(readl(addr))
 #define iowrite16be(v, addr)   writew(cpu_to_be16(v), (addr))
index f7836c6a6b60eb24981a5f9f53207a96bff7a6dc..c32f76791f488ae12e7264960433c70d0fbd4315 100644 (file)
@@ -98,7 +98,7 @@ static void __init mcf54xx_bootmem_alloc(void)
        memstart = PAGE_ALIGN(_ramstart);
        min_low_pfn = PFN_DOWN(_rambase);
        start_pfn = PFN_DOWN(memstart);
-       max_low_pfn = PFN_DOWN(_ramend);
+       max_pfn = max_low_pfn = PFN_DOWN(_ramend);
        high_memory = (void *)_ramend;
 
        m68k_virt_to_node_shift = fls(_ramend - _rambase - 1) - 6;
index 0793a7f174176e6d590ca4d9567a9e3523c42c50..f9d96bf869109c028e5a9f1f12ad3e9fe8b933ba 100644 (file)
@@ -4,7 +4,7 @@
 #include <uapi/asm/unistd.h>
 
 
-#define NR_syscalls            375
+#define NR_syscalls            376
 
 #define __ARCH_WANT_OLD_READDIR
 #define __ARCH_WANT_OLD_STAT
index 5e6fae6c275f9b110464cb80bbb47187c2251dcd..36cf129de663a7ca22f1bf1bba5a6245b7b04c03 100644 (file)
 #define __NR_sendmmsg          372
 #define __NR_userfaultfd       373
 #define __NR_membarrier                374
+#define __NR_mlock2            375
 
 #endif /* _UAPI_ASM_M68K_UNISTD_H_ */
index 88c27d94a7214c959c6d75a3ac992a4c95b13b2e..76b9113f30922df74e8dac0d8dccca9d7c48fd6b 100644 (file)
@@ -238,11 +238,14 @@ void __init setup_arch(char **cmdline_p)
         * Give all the memory to the bootmap allocator, tell it to put the
         * boot mem_map at the start of memory.
         */
+       min_low_pfn = PFN_DOWN(memory_start);
+       max_pfn = max_low_pfn = PFN_DOWN(memory_end);
+
        bootmap_size = init_bootmem_node(
                        NODE_DATA(0),
-                       memory_start >> PAGE_SHIFT, /* map goes here */
-                       PAGE_OFFSET >> PAGE_SHIFT,      /* 0 on coldfire */
-                       memory_end >> PAGE_SHIFT);
+                       min_low_pfn,            /* map goes here */
+                       PFN_DOWN(PAGE_OFFSET),
+                       max_pfn);
        /*
         * Free the usable memory, we have to make sure we do not free
         * the bootmem bitmap so we then reserve it after freeing it :-)
index 5dd0e80042f51107e63e0fcd832f4c46c85b826c..282cd903f4c469197738eb9e840eaa75c77ec11a 100644 (file)
@@ -395,3 +395,4 @@ ENTRY(sys_call_table)
        .long sys_sendmmsg
        .long sys_userfaultfd
        .long sys_membarrier
+       .long sys_mlock2                /* 375 */
index b958916e5eac96b250ef08e556983e059d7d0850..8f37fdd80be9e9ccec99b1d4509f3c97a94f0899 100644 (file)
@@ -250,7 +250,7 @@ void __init paging_init(void)
        high_memory = phys_to_virt(max_addr);
 
        min_low_pfn = availmem >> PAGE_SHIFT;
-       max_low_pfn = max_addr >> PAGE_SHIFT;
+       max_pfn = max_low_pfn = max_addr >> PAGE_SHIFT;
 
        for (i = 0; i < m68k_num_memory; i++) {
                addr = m68k_memory[i].addr;
index a8b942bf71638c9778dd8fff05c63797202edd61..2a5f43a68ae3d73d22dd822a4da4996208543e7c 100644 (file)
@@ -118,13 +118,13 @@ static void __init sun3_bootmem_alloc(unsigned long memory_start,
        memory_end = memory_end & PAGE_MASK;
 
        start_page = __pa(memory_start) >> PAGE_SHIFT;
-       num_pages = __pa(memory_end) >> PAGE_SHIFT;
+       max_pfn = num_pages = __pa(memory_end) >> PAGE_SHIFT;
 
        high_memory = (void *)memory_end;
        availmem = memory_start;
 
        m68k_setup_node(0);
-       availmem += init_bootmem_node(NODE_DATA(0), start_page, 0, num_pages);
+       availmem += init_bootmem(start_page, num_pages);
        availmem = (availmem + (PAGE_SIZE-1)) & PAGE_MASK;
 
        free_bootmem(__pa(availmem), memory_end - (availmem));
index c89da63129545a9c300e61062e9d958d4c786790..bf4dec229437a836ee1829504be7bf603ce73b37 100644 (file)
@@ -61,7 +61,8 @@ static int dma_direct_map_sg(struct device *dev, struct scatterlist *sgl,
        /* FIXME this part of code is untested */
        for_each_sg(sgl, sg, nents, i) {
                sg->dma_address = sg_phys(sg);
-               __dma_sync(sg_phys(sg), sg->length, direction);
+               __dma_sync(page_to_phys(sg_page(sg)) + sg->offset,
+                                                       sg->length, direction);
        }
 
        return nents;
index 1ba21204ebe021ee164a9f8f4828dd3f3c836f84..8755d618e116ec32fd6fff90d0081b0bb2e4bb9c 100644 (file)
@@ -216,9 +216,9 @@ void __init plat_mem_setup(void)
                                           AR71XX_RESET_SIZE);
        ath79_pll_base = ioremap_nocache(AR71XX_PLL_BASE,
                                         AR71XX_PLL_SIZE);
+       ath79_detect_sys_type();
        ath79_ddr_ctrl_init();
 
-       ath79_detect_sys_type();
        if (mips_machtype != ATH79_MACH_GENERIC_OF)
                detect_memory_region(0, ATH79_MEM_SIZE_MIN, ATH79_MEM_SIZE_MAX);
 
@@ -281,3 +281,8 @@ MIPS_MACHINE(ATH79_MACH_GENERIC,
             "Generic",
             "Generic AR71XX/AR724X/AR913X based board",
             ath79_generic_init);
+
+MIPS_MACHINE(ATH79_MACH_GENERIC_OF,
+            "DTB",
+            "Generic AR71XX/AR724X/AR913X based board (DT)",
+            NULL);
index fb7734eadbf0e08faab7c6ab36b29851d3845e35..13d0439496a9d28d500b2d3e37b585e3f4541335 100644 (file)
                        miscintc: interrupt-controller@18060010 {
                                compatible = "qca,ar9132-misc-intc",
                                           "qca,ar7100-misc-intc";
-                               reg = <0x18060010 0x4>;
+                               reg = <0x18060010 0x8>;
 
                                interrupt-parent = <&cpuintc>;
                                interrupts = <6>;
index ad1fccdb8d13ee3d14e97efe3831bd266ba65a4b..2046c023022406d8a336197db13df1a75b1e8021 100644 (file)
@@ -200,8 +200,9 @@ static inline int pfn_valid(unsigned long pfn)
 {
        /* avoid <linux/mm.h> include hell */
        extern unsigned long max_mapnr;
+       unsigned long pfn_offset = ARCH_PFN_OFFSET;
 
-       return pfn >= ARCH_PFN_OFFSET && pfn < max_mapnr;
+       return pfn >= pfn_offset && pfn < max_mapnr;
 }
 
 #elif defined(CONFIG_SPARSEMEM)
index 5305d694ffe52010f19a110fd072341a44e4ae85..095ecafe6bd3525444c27812937e2d085bf69b2a 100644 (file)
@@ -599,7 +599,7 @@ extern void __put_user_unknown(void);
  * On error, the variable @x is set to zero.
  */
 #define __get_user_unaligned(x,ptr) \
-       __get_user__unalignednocheck((x),(ptr),sizeof(*(ptr)))
+       __get_user_unaligned_nocheck((x),(ptr),sizeof(*(ptr)))
 
 /*
  * Yuck.  We need two variants, one for 64bit operation and one
@@ -620,8 +620,8 @@ extern void __get_user_unaligned_unknown(void);
 do {                                                                   \
        switch (size) {                                                 \
        case 1: __get_data_asm(val, "lb", ptr); break;                  \
-       case 2: __get_user_unaligned_asm(val, "ulh", ptr); break;       \
-       case 4: __get_user_unaligned_asm(val, "ulw", ptr); break;       \
+       case 2: __get_data_unaligned_asm(val, "ulh", ptr); break;       \
+       case 4: __get_data_unaligned_asm(val, "ulw", ptr); break;       \
        case 8: __GET_USER_UNALIGNED_DW(val, ptr); break;               \
        default: __get_user_unaligned_unknown(); break;                 \
        }                                                               \
@@ -1122,9 +1122,15 @@ extern size_t __copy_in_user_eva(void *__to, const void *__from, size_t __n);
        __cu_to = (to);                                                 \
        __cu_from = (from);                                             \
        __cu_len = (n);                                                 \
-       might_fault();                                                  \
-       __cu_len = __invoke_copy_from_user(__cu_to, __cu_from,          \
-                                          __cu_len);                   \
+       if (eva_kernel_access()) {                                      \
+               __cu_len = __invoke_copy_from_kernel(__cu_to,           \
+                                                    __cu_from,         \
+                                                    __cu_len);         \
+       } else {                                                        \
+               might_fault();                                          \
+               __cu_len = __invoke_copy_from_user(__cu_to, __cu_from,  \
+                                                  __cu_len);           \
+       }                                                               \
        __cu_len;                                                       \
 })
 
@@ -1229,16 +1235,28 @@ __clear_user(void __user *addr, __kernel_size_t size)
 {
        __kernel_size_t res;
 
-       might_fault();
-       __asm__ __volatile__(
-               "move\t$4, %1\n\t"
-               "move\t$5, $0\n\t"
-               "move\t$6, %2\n\t"
-               __MODULE_JAL(__bzero)
-               "move\t%0, $6"
-               : "=r" (res)
-               : "r" (addr), "r" (size)
-               : "$4", "$5", "$6", __UA_t0, __UA_t1, "$31");
+       if (eva_kernel_access()) {
+               __asm__ __volatile__(
+                       "move\t$4, %1\n\t"
+                       "move\t$5, $0\n\t"
+                       "move\t$6, %2\n\t"
+                       __MODULE_JAL(__bzero_kernel)
+                       "move\t%0, $6"
+                       : "=r" (res)
+                       : "r" (addr), "r" (size)
+                       : "$4", "$5", "$6", __UA_t0, __UA_t1, "$31");
+       } else {
+               might_fault();
+               __asm__ __volatile__(
+                       "move\t$4, %1\n\t"
+                       "move\t$5, $0\n\t"
+                       "move\t$6, %2\n\t"
+                       __MODULE_JAL(__bzero)
+                       "move\t%0, $6"
+                       : "=r" (res)
+                       : "r" (addr), "r" (size)
+                       : "$4", "$5", "$6", __UA_t0, __UA_t1, "$31");
+       }
 
        return res;
 }
@@ -1384,7 +1402,7 @@ static inline long strlen_user(const char __user *s)
                might_fault();
                __asm__ __volatile__(
                        "move\t$4, %1\n\t"
-                       __MODULE_JAL(__strlen_kernel_asm)
+                       __MODULE_JAL(__strlen_user_asm)
                        "move\t%0, $2"
                        : "=r" (res)
                        : "r" (s)
index 8fd5a276cad23493f6500d0f4b01515ee20062f5..ac81edd44563119dbf6cf6fa0c9154afb9c47b98 100644 (file)
@@ -257,7 +257,6 @@ LEAF(mips_cps_core_init)
        has_mt  t0, 3f
 
        .set    push
-       .set    mips64r2
        .set    mt
 
        /* Only allow 1 TC per VPE to execute... */
@@ -376,7 +375,6 @@ LEAF(mips_cps_boot_vpes)
         nop
 
        .set    push
-       .set    mips64r2
        .set    mt
 
 1:     /* Enter VPE configuration state */
index 291af0b5c4828adaa22ff0fc065f37c6a094fd85..e2b6ab74643dba93b403dbba2dcfb4eced3e6d9e 100644 (file)
@@ -17,6 +17,7 @@
 #include <asm/fpu.h>
 #include <asm/msa.h>
 
+extern void *__bzero_kernel(void *__s, size_t __count);
 extern void *__bzero(void *__s, size_t __count);
 extern long __strncpy_from_kernel_nocheck_asm(char *__to,
                                              const char *__from, long __len);
@@ -64,6 +65,7 @@ EXPORT_SYMBOL(__copy_from_user_eva);
 EXPORT_SYMBOL(__copy_in_user_eva);
 EXPORT_SYMBOL(__copy_to_user_eva);
 EXPORT_SYMBOL(__copy_user_inatomic_eva);
+EXPORT_SYMBOL(__bzero_kernel);
 #endif
 EXPORT_SYMBOL(__bzero);
 EXPORT_SYMBOL(__strncpy_from_kernel_nocheck_asm);
index d5fa3eaf39a106546f52d82ec3e5391302ef8dec..41b1b090f56f6b73afc50240318634a4988ef427 100644 (file)
@@ -1581,7 +1581,7 @@ enum emulation_result kvm_mips_emulate_cache(uint32_t inst, uint32_t *opc,
 
        base = (inst >> 21) & 0x1f;
        op_inst = (inst >> 16) & 0x1f;
-       offset = inst & 0xffff;
+       offset = (int16_t)inst;
        cache = (inst >> 16) & 0x3;
        op = (inst >> 18) & 0x7;
 
index 7bab3a4e8f7d90b541b457f4f66138899db6db8a..7e2210846b8b9d1519f679e6a0950fcaf1e6dfd5 100644 (file)
@@ -157,9 +157,11 @@ FEXPORT(__kvm_mips_vcpu_run)
 
 FEXPORT(__kvm_mips_load_asid)
        /* Set the ASID for the Guest Kernel */
-       INT_SLL t0, t0, 1       /* with kseg0 @ 0x40000000, kernel */
-                               /* addresses shift to 0x80000000 */
-       bltz    t0, 1f          /* If kernel */
+       PTR_L   t0, VCPU_COP0(k1)
+       LONG_L  t0, COP0_STATUS(t0)
+       andi    t0, KSU_USER | ST0_ERL | ST0_EXL
+       xori    t0, KSU_USER
+       bnez    t0, 1f          /* If kernel */
         INT_ADDIU t1, k1, VCPU_GUEST_KERNEL_ASID  /* (BD)  */
        INT_ADDIU t1, k1, VCPU_GUEST_USER_ASID    /* else user */
 1:
@@ -474,9 +476,11 @@ __kvm_mips_return_to_guest:
        mtc0    t0, CP0_EPC
 
        /* Set the ASID for the Guest Kernel */
-       INT_SLL t0, t0, 1       /* with kseg0 @ 0x40000000, kernel */
-                               /* addresses shift to 0x80000000 */
-       bltz    t0, 1f          /* If kernel */
+       PTR_L   t0, VCPU_COP0(k1)
+       LONG_L  t0, COP0_STATUS(t0)
+       andi    t0, KSU_USER | ST0_ERL | ST0_EXL
+       xori    t0, KSU_USER
+       bnez    t0, 1f          /* If kernel */
         INT_ADDIU t1, k1, VCPU_GUEST_KERNEL_ASID  /* (BD)  */
        INT_ADDIU t1, k1, VCPU_GUEST_USER_ASID    /* else user */
 1:
index 49ff3bfc007e534529d0f61d21b6fddd6578d145..b9b803facdbf7594dc700ca828a2ced604e617aa 100644 (file)
@@ -279,7 +279,7 @@ struct kvm_vcpu *kvm_arch_vcpu_create(struct kvm *kvm, unsigned int id)
 
        if (!gebase) {
                err = -ENOMEM;
-               goto out_free_cpu;
+               goto out_uninit_cpu;
        }
        kvm_debug("Allocated %d bytes for KVM Exception Handlers @ %p\n",
                  ALIGN(size, PAGE_SIZE), gebase);
@@ -343,6 +343,9 @@ struct kvm_vcpu *kvm_arch_vcpu_create(struct kvm *kvm, unsigned int id)
 out_free_gebase:
        kfree(gebase);
 
+out_uninit_cpu:
+       kvm_vcpu_uninit(vcpu);
+
 out_free_cpu:
        kfree(vcpu);
 
index b8e63fd0037547cb9939907696da7ae55d699a95..8f0019a2e5c84bcd4f439559dad479b44903269a 100644 (file)
@@ -283,6 +283,8 @@ LEAF(memset)
 1:
 #ifndef CONFIG_EVA
 FEXPORT(__bzero)
+#else
+FEXPORT(__bzero_kernel)
 #endif
        __BUILD_BZERO LEGACY_MODE
 
index d8117be729a20ee26d2df8bb42a6f58b9670f513..730d394ce5f017991146084f9df53794242c970d 100644 (file)
@@ -145,7 +145,7 @@ static void *mips_dma_alloc_coherent(struct device *dev, size_t size,
 
        gfp = massage_gfp_flags(dev, gfp);
 
-       if (IS_ENABLED(CONFIG_DMA_CMA) && !(gfp & GFP_ATOMIC))
+       if (IS_ENABLED(CONFIG_DMA_CMA) && gfpflags_allow_blocking(gfp))
                page = dma_alloc_from_contiguous(dev,
                                        count, get_order(size));
        if (!page)
index 8a978022630b252fa0547dd137805d6b3c35ec3b..a245cad4372a4a84094b88eed05ba3080a146190 100644 (file)
@@ -11,6 +11,7 @@
  *  by the Free Software Foundation.
  */
 
+#include <linux/delay.h>
 #include <linux/types.h>
 #include <linux/pci.h>
 #include <linux/io.h>
@@ -220,7 +221,6 @@ int __init pcibios_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
 static int rt288x_pci_probe(struct platform_device *pdev)
 {
        void __iomem *io_map_base;
-       int i;
 
        rt2880_pci_base = ioremap_nocache(RT2880_PCI_BASE, PAGE_SIZE);
 
@@ -232,8 +232,7 @@ static int rt288x_pci_probe(struct platform_device *pdev)
        ioport_resource.end = RT2880_PCI_IO_BASE + RT2880_PCI_IO_SIZE - 1;
 
        rt2880_pci_reg_write(0, RT2880_PCI_REG_PCICFG_ADDR);
-       for (i = 0; i < 0xfffff; i++)
-               ;
+       udelay(1);
 
        rt2880_pci_reg_write(0x79, RT2880_PCI_REG_ARBCTL);
        rt2880_pci_reg_write(0x07FF0001, RT2880_PCI_REG_BAR0SETUP_ADDR);
index 4f925e06c414663023765630cd84211d62679e16..9d293b3e9130152af49f964e530ece27e482fd7b 100644 (file)
@@ -10,6 +10,8 @@
  * option) any later version.
  */
 
+#include <linux/delay.h>
+
 #include <asm/bootinfo.h>
 #include <asm/cacheflush.h>
 #include <asm/idle.h>
@@ -37,7 +39,6 @@ extern void msp_serial_setup(void);
 void msp7120_reset(void)
 {
        void *start, *end, *iptr;
-       register int i;
 
        /* Diasble all interrupts */
        local_irq_disable();
@@ -77,7 +78,7 @@ void msp7120_reset(void)
         */
 
        /* Wait a bit for the DDRC to settle */
-       for (i = 0; i < 100000000; i++);
+       mdelay(125);
 
 #if defined(CONFIG_PMC_MSP7120_GW)
        /*
index 244f9427625b5873003cc92132c96a32d99663eb..6afa34346b8148040a84e0a54ecd7af8d7ac608c 100644 (file)
@@ -3,6 +3,8 @@
  *
  *  Reset a SNI machine.
  */
+#include <linux/delay.h>
+
 #include <asm/io.h>
 #include <asm/reboot.h>
 #include <asm/sni.h>
@@ -24,7 +26,7 @@ static inline void kb_wait(void)
 /* XXX This ends up at the ARC firmware prompt ...  */
 void sni_machine_restart(char *command)
 {
-       int i, j;
+       int i;
 
        /* This does a normal via the keyboard controller like a PC.
           We can do that easier ...  */
@@ -32,9 +34,9 @@ void sni_machine_restart(char *command)
        for (;;) {
                for (i = 0; i < 100; i++) {
                        kb_wait();
-                       for (j = 0; j < 100000 ; j++)
-                               /* nothing */;
+                       udelay(50);
                        outb_p(0xfe, 0x64);      /* pulse reset low */
+                       udelay(50);
                }
        }
 }
index ef5f348f386a1ec4c5aef0a566a334a40e8f763b..14568900fc1d14ec2e0ff6b2d7152232c8b867bb 100644 (file)
@@ -26,8 +26,8 @@ aflags-vdso := $(ccflags-vdso) \
 # the comments on that file.
 #
 ifndef CONFIG_CPU_MIPSR6
-  ifeq ($(call ld-ifversion, -gt, 22400000, y),)
-    $(warning MIPS VDSO requires binutils > 2.24)
+  ifeq ($(call ld-ifversion, -lt, 22500000, y),y)
+    $(warning MIPS VDSO requires binutils >= 2.25)
     obj-vdso-y := $(filter-out gettimeofday.o, $(obj-vdso-y))
     ccflags-vdso += -DDISABLE_MIPS_VDSO
   endif
index 4434b54e1d87c4e10e705ff5b7641d4f52c9616c..78ae5552fdb89cca3c6a5ff4290a2581fbe95079 100644 (file)
@@ -1,6 +1,7 @@
 config MN10300
        def_bool y
        select HAVE_OPROFILE
+       select HAVE_UID16
        select GENERIC_IRQ_SHOW
        select ARCH_WANT_IPC_PARSE_VERSION
        select HAVE_ARCH_TRACEHOOK
@@ -37,9 +38,6 @@ config HIGHMEM
 config NUMA
        def_bool n
 
-config UID16
-       def_bool y
-
 config RWSEM_GENERIC_SPINLOCK
        def_bool y
 
index 223cdcc8203f566483c15051c1ce5cfdfe608791..87bf88ed04c6c0a13220e2b3588b7fedbb6145f3 100644 (file)
@@ -23,22 +23,6 @@ static void __flush_dcache(unsigned long start, unsigned long end)
        end += (cpuinfo.dcache_line_size - 1);
        end &= ~(cpuinfo.dcache_line_size - 1);
 
-       for (addr = start; addr < end; addr += cpuinfo.dcache_line_size) {
-               __asm__ __volatile__ ("   flushda 0(%0)\n"
-                                       : /* Outputs */
-                                       : /* Inputs  */ "r"(addr)
-                                       /* : No clobber */);
-       }
-}
-
-static void __flush_dcache_all(unsigned long start, unsigned long end)
-{
-       unsigned long addr;
-
-       start &= ~(cpuinfo.dcache_line_size - 1);
-       end += (cpuinfo.dcache_line_size - 1);
-       end &= ~(cpuinfo.dcache_line_size - 1);
-
        if (end > start + cpuinfo.dcache_size)
                end = start + cpuinfo.dcache_size;
 
@@ -112,7 +96,7 @@ static void flush_aliases(struct address_space *mapping, struct page *page)
 
 void flush_cache_all(void)
 {
-       __flush_dcache_all(0, cpuinfo.dcache_size);
+       __flush_dcache(0, cpuinfo.dcache_size);
        __flush_icache(0, cpuinfo.icache_size);
 }
 
@@ -182,7 +166,7 @@ void __flush_dcache_page(struct address_space *mapping, struct page *page)
         */
        unsigned long start = (unsigned long)page_address(page);
 
-       __flush_dcache_all(start, start + PAGE_SIZE);
+       __flush_dcache(start, start + PAGE_SIZE);
 }
 
 void flush_dcache_page(struct page *page)
@@ -268,7 +252,7 @@ void copy_from_user_page(struct vm_area_struct *vma, struct page *page,
 {
        flush_cache_page(vma, user_vaddr, page_to_pfn(page));
        memcpy(dst, src, len);
-       __flush_dcache_all((unsigned long)src, (unsigned long)src + len);
+       __flush_dcache((unsigned long)src, (unsigned long)src + len);
        if (vma->vm_flags & VM_EXEC)
                __flush_icache((unsigned long)src, (unsigned long)src + len);
 }
@@ -279,7 +263,7 @@ void copy_to_user_page(struct vm_area_struct *vma, struct page *page,
 {
        flush_cache_page(vma, user_vaddr, page_to_pfn(page));
        memcpy(dst, src, len);
-       __flush_dcache_all((unsigned long)dst, (unsigned long)dst + len);
+       __flush_dcache((unsigned long)dst, (unsigned long)dst + len);
        if (vma->vm_flags & VM_EXEC)
                __flush_icache((unsigned long)dst, (unsigned long)dst + len);
 }
index c36546959e86ff96f4b0a656d1562ee85e729904..729f89163bc32113dba77e309c8ce767ed3d15e8 100644 (file)
@@ -108,6 +108,9 @@ config PGTABLE_LEVELS
        default 3 if 64BIT && PARISC_PAGE_SIZE_4KB
        default 2
 
+config SYS_SUPPORTS_HUGETLBFS
+       def_bool y if PA20
+
 source "init/Kconfig"
 
 source "kernel/Kconfig.freezer"
diff --git a/arch/parisc/include/asm/hugetlb.h b/arch/parisc/include/asm/hugetlb.h
new file mode 100644 (file)
index 0000000..7d56a9c
--- /dev/null
@@ -0,0 +1,85 @@
+#ifndef _ASM_PARISC64_HUGETLB_H
+#define _ASM_PARISC64_HUGETLB_H
+
+#include <asm/page.h>
+#include <asm-generic/hugetlb.h>
+
+
+void set_huge_pte_at(struct mm_struct *mm, unsigned long addr,
+                    pte_t *ptep, pte_t pte);
+
+pte_t huge_ptep_get_and_clear(struct mm_struct *mm, unsigned long addr,
+                             pte_t *ptep);
+
+static inline int is_hugepage_only_range(struct mm_struct *mm,
+                                        unsigned long addr,
+                                        unsigned long len) {
+       return 0;
+}
+
+/*
+ * If the arch doesn't supply something else, assume that hugepage
+ * size aligned regions are ok without further preparation.
+ */
+static inline int prepare_hugepage_range(struct file *file,
+                       unsigned long addr, unsigned long len)
+{
+       if (len & ~HPAGE_MASK)
+               return -EINVAL;
+       if (addr & ~HPAGE_MASK)
+               return -EINVAL;
+       return 0;
+}
+
+static inline void hugetlb_free_pgd_range(struct mmu_gather *tlb,
+                                         unsigned long addr, unsigned long end,
+                                         unsigned long floor,
+                                         unsigned long ceiling)
+{
+       free_pgd_range(tlb, addr, end, floor, ceiling);
+}
+
+static inline void huge_ptep_clear_flush(struct vm_area_struct *vma,
+                                        unsigned long addr, pte_t *ptep)
+{
+}
+
+static inline int huge_pte_none(pte_t pte)
+{
+       return pte_none(pte);
+}
+
+static inline pte_t huge_pte_wrprotect(pte_t pte)
+{
+       return pte_wrprotect(pte);
+}
+
+static inline void huge_ptep_set_wrprotect(struct mm_struct *mm,
+                                          unsigned long addr, pte_t *ptep)
+{
+       pte_t old_pte = *ptep;
+       set_huge_pte_at(mm, addr, ptep, pte_wrprotect(old_pte));
+}
+
+static inline int huge_ptep_set_access_flags(struct vm_area_struct *vma,
+                                            unsigned long addr, pte_t *ptep,
+                                            pte_t pte, int dirty)
+{
+       int changed = !pte_same(*ptep, pte);
+       if (changed) {
+               set_huge_pte_at(vma->vm_mm, addr, ptep, pte);
+               flush_tlb_page(vma, addr);
+       }
+       return changed;
+}
+
+static inline pte_t huge_ptep_get(pte_t *ptep)
+{
+       return *ptep;
+}
+
+static inline void arch_clear_hugepage_flags(struct page *page)
+{
+}
+
+#endif /* _ASM_PARISC64_HUGETLB_H */
index 60d5d174dfe413e14cb5117a04536ce7948d937d..80e742a1c162fbd89b27a21bd4ff75eb169b9b38 100644 (file)
@@ -145,11 +145,22 @@ extern int npmem_ranges;
 #endif /* CONFIG_DISCONTIGMEM */
 
 #ifdef CONFIG_HUGETLB_PAGE
-#define HPAGE_SHIFT            22      /* 4MB (is this fixed?) */
+#define HPAGE_SHIFT            PMD_SHIFT /* fixed for transparent huge pages */
 #define HPAGE_SIZE             ((1UL) << HPAGE_SHIFT)
 #define HPAGE_MASK             (~(HPAGE_SIZE - 1))
 #define HUGETLB_PAGE_ORDER     (HPAGE_SHIFT - PAGE_SHIFT)
+
+#if defined(CONFIG_64BIT) && defined(CONFIG_PARISC_PAGE_SIZE_4KB)
+# define REAL_HPAGE_SHIFT      20 /* 20 = 1MB */
+# define _HUGE_PAGE_SIZE_ENCODING_DEFAULT _PAGE_SIZE_ENCODING_1M
+#elif !defined(CONFIG_64BIT) && defined(CONFIG_PARISC_PAGE_SIZE_4KB)
+# define REAL_HPAGE_SHIFT      22 /* 22 = 4MB */
+# define _HUGE_PAGE_SIZE_ENCODING_DEFAULT _PAGE_SIZE_ENCODING_4M
+#else
+# define REAL_HPAGE_SHIFT      24 /* 24 = 16MB */
+# define _HUGE_PAGE_SIZE_ENCODING_DEFAULT _PAGE_SIZE_ENCODING_16M
 #endif
+#endif /* CONFIG_HUGETLB_PAGE */
 
 #define virt_addr_valid(kaddr) pfn_valid(__pa(kaddr) >> PAGE_SHIFT)
 
index 3edbb9fc91b4e055307d3c7519592a00201d988a..f2fd327dce2edc14db5717211fe27943e957fcf0 100644 (file)
@@ -35,7 +35,7 @@ static inline pgd_t *pgd_alloc(struct mm_struct *mm)
                                        PxD_FLAG_VALID | 
                                        PxD_FLAG_ATTACHED) 
                        + (__u32)(__pa((unsigned long)pgd) >> PxD_VALUE_SHIFT));
-               /* The first pmd entry also is marked with _PAGE_GATEWAY as
+               /* The first pmd entry also is marked with PxD_FLAG_ATTACHED as
                 * a signal that this pmd may not be freed */
                __pgd_val_set(*pgd, PxD_FLAG_ATTACHED);
 #endif
index f93c4a4e6580300f347a4d69beccc5fe4810452b..291cee28ccb60da84576ba1d9e103a0dc6e78ba5 100644 (file)
@@ -83,7 +83,11 @@ static inline void purge_tlb_entries(struct mm_struct *mm, unsigned long addr)
        printk("%s:%d: bad pgd %08lx.\n", __FILE__, __LINE__, (unsigned long)pgd_val(e))
 
 /* This is the size of the initially mapped kernel memory */
-#define KERNEL_INITIAL_ORDER   24      /* 0 to 1<<24 = 16MB */
+#ifdef CONFIG_64BIT
+#define KERNEL_INITIAL_ORDER   25      /* 1<<25 = 32MB */
+#else
+#define KERNEL_INITIAL_ORDER   24      /* 1<<24 = 16MB */
+#endif
 #define KERNEL_INITIAL_SIZE    (1 << KERNEL_INITIAL_ORDER)
 
 #if CONFIG_PGTABLE_LEVELS == 3
@@ -167,7 +171,7 @@ static inline void purge_tlb_entries(struct mm_struct *mm, unsigned long addr)
 #define _PAGE_NO_CACHE_BIT 24   /* (0x080) Uncached Page (U bit) */
 #define _PAGE_ACCESSED_BIT 23   /* (0x100) Software: Page Accessed */
 #define _PAGE_PRESENT_BIT  22   /* (0x200) Software: translation valid */
-/* bit 21 was formerly the FLUSH bit but is now unused */
+#define _PAGE_HPAGE_BIT    21   /* (0x400) Software: Huge Page */
 #define _PAGE_USER_BIT     20   /* (0x800) Software: User accessible page */
 
 /* N.B. The bits are defined in terms of a 32 bit word above, so the */
@@ -194,6 +198,7 @@ static inline void purge_tlb_entries(struct mm_struct *mm, unsigned long addr)
 #define _PAGE_NO_CACHE (1 << xlate_pabit(_PAGE_NO_CACHE_BIT))
 #define _PAGE_ACCESSED (1 << xlate_pabit(_PAGE_ACCESSED_BIT))
 #define _PAGE_PRESENT  (1 << xlate_pabit(_PAGE_PRESENT_BIT))
+#define _PAGE_HUGE     (1 << xlate_pabit(_PAGE_HPAGE_BIT))
 #define _PAGE_USER     (1 << xlate_pabit(_PAGE_USER_BIT))
 
 #define _PAGE_TABLE    (_PAGE_PRESENT | _PAGE_READ | _PAGE_WRITE |  _PAGE_DIRTY | _PAGE_ACCESSED)
@@ -217,7 +222,7 @@ static inline void purge_tlb_entries(struct mm_struct *mm, unsigned long addr)
 #define PxD_FLAG_VALID    (1 << xlate_pabit(_PxD_VALID_BIT))
 #define PxD_FLAG_MASK     (0xf)
 #define PxD_FLAG_SHIFT    (4)
-#define PxD_VALUE_SHIFT   (8) /* (PAGE_SHIFT-PxD_FLAG_SHIFT) */
+#define PxD_VALUE_SHIFT   (PFN_PTE_SHIFT-PxD_FLAG_SHIFT)
 
 #ifndef __ASSEMBLY__
 
@@ -362,6 +367,19 @@ static inline pte_t pte_mkyoung(pte_t pte) { pte_val(pte) |= _PAGE_ACCESSED; ret
 static inline pte_t pte_mkwrite(pte_t pte)     { pte_val(pte) |= _PAGE_WRITE; return pte; }
 static inline pte_t pte_mkspecial(pte_t pte)   { return pte; }
 
+/*
+ * Huge pte definitions.
+ */
+#ifdef CONFIG_HUGETLB_PAGE
+#define pte_huge(pte)           (pte_val(pte) & _PAGE_HUGE)
+#define pte_mkhuge(pte)         (__pte(pte_val(pte) | \
+                                (parisc_requires_coherency() ? 0 : _PAGE_HUGE)))
+#else
+#define pte_huge(pte)           (0)
+#define pte_mkhuge(pte)         (pte)
+#endif
+
+
 /*
  * Conversion functions: convert a page and protection to a page entry,
  * and a page entry and page directory to the page they refer to.
@@ -410,8 +428,9 @@ static inline pte_t pte_modify(pte_t pte, pgprot_t newprot)
 /* Find an entry in the second-level page table.. */
 
 #if CONFIG_PGTABLE_LEVELS == 3
+#define pmd_index(addr)         (((addr) >> PMD_SHIFT) & (PTRS_PER_PMD - 1))
 #define pmd_offset(dir,address) \
-((pmd_t *) pgd_page_vaddr(*(dir)) + (((address)>>PMD_SHIFT) & (PTRS_PER_PMD-1)))
+((pmd_t *) pgd_page_vaddr(*(dir)) + pmd_index(address))
 #else
 #define pmd_offset(dir,addr) ((pmd_t *) dir)
 #endif
index 54adb60c0a42cca573abc1ca091328c9e6ca8b58..7e759ecb1343692a11a16526aaff04c5eb607cec 100644 (file)
@@ -192,33 +192,6 @@ void show_trace(struct task_struct *task, unsigned long *stack);
  */
 typedef unsigned int elf_caddr_t;
 
-#define start_thread_som(regs, new_pc, new_sp) do {    \
-       unsigned long *sp = (unsigned long *)new_sp;    \
-       __u32 spaceid = (__u32)current->mm->context;    \
-       unsigned long pc = (unsigned long)new_pc;       \
-       /* offset pc for priv. level */                 \
-       pc |= 3;                                        \
-                                                       \
-       regs->iasq[0] = spaceid;                        \
-       regs->iasq[1] = spaceid;                        \
-       regs->iaoq[0] = pc;                             \
-       regs->iaoq[1] = pc + 4;                         \
-       regs->sr[2] = LINUX_GATEWAY_SPACE;              \
-       regs->sr[3] = 0xffff;                           \
-       regs->sr[4] = spaceid;                          \
-       regs->sr[5] = spaceid;                          \
-       regs->sr[6] = spaceid;                          \
-       regs->sr[7] = spaceid;                          \
-       regs->gr[ 0] = USER_PSW;                        \
-       regs->gr[30] = ((new_sp)+63)&~63;               \
-       regs->gr[31] = pc;                              \
-                                                       \
-       get_user(regs->gr[26],&sp[0]);                  \
-       get_user(regs->gr[25],&sp[-1]);                 \
-       get_user(regs->gr[24],&sp[-2]);                 \
-       get_user(regs->gr[23],&sp[-3]);                 \
-} while(0)
-
 /* The ELF abi wants things done a "wee bit" differently than
  * som does.  Supporting this behavior here avoids
  * having our own version of create_elf_tables.
index ecc3ae1ca28e2d573f578709fa6c2c023159fa72..dd4d1876a020c1e0150cc87547e3f75f9940f16b 100644 (file)
 #define MADV_DONTFORK  10              /* don't inherit across fork */
 #define MADV_DOFORK    11              /* do inherit across fork */
 
-/* The range 12-64 is reserved for page size specification. */
-#define MADV_4K_PAGES   12              /* Use 4K pages  */
-#define MADV_16K_PAGES  14              /* Use 16K pages */
-#define MADV_64K_PAGES  16              /* Use 64K pages */
-#define MADV_256K_PAGES 18              /* Use 256K pages */
-#define MADV_1M_PAGES   20              /* Use 1 Megabyte pages */
-#define MADV_4M_PAGES   22              /* Use 4 Megabyte pages */
-#define MADV_16M_PAGES  24              /* Use 16 Megabyte pages */
-#define MADV_64M_PAGES  26              /* Use 64 Megabyte pages */
-
 #define MADV_MERGEABLE   65            /* KSM may merge identical pages */
 #define MADV_UNMERGEABLE 66            /* KSM may not merge identical pages */
 
index 33170384d3ac1a7fdd835c7b8f04484aaf1f244c..35bdccbb203622e116f288741ac4a9bc173034b0 100644 (file)
 #define __NR_execveat          (__NR_Linux + 342)
 #define __NR_membarrier                (__NR_Linux + 343)
 #define __NR_userfaultfd       (__NR_Linux + 344)
+#define __NR_mlock2            (__NR_Linux + 345)
 
-#define __NR_Linux_syscalls    (__NR_userfaultfd + 1)
+#define __NR_Linux_syscalls    (__NR_mlock2 + 1)
 
 
 #define __IGNORE_select                /* newselect */
index 59001cea13f9bea05c1071cc6aaaf1fad9ad3458..d2f62570a7b16d4f4c6321515d980f048cd278f2 100644 (file)
@@ -289,6 +289,14 @@ int main(void)
        DEFINE(ASM_PTE_ENTRY_SIZE, PTE_ENTRY_SIZE);
        DEFINE(ASM_PFN_PTE_SHIFT, PFN_PTE_SHIFT);
        DEFINE(ASM_PT_INITIAL, PT_INITIAL);
+       BLANK();
+       /* HUGEPAGE_SIZE is only used in vmlinux.lds.S to align kernel text
+        * and kernel data on physical huge pages */
+#ifdef CONFIG_HUGETLB_PAGE
+       DEFINE(HUGEPAGE_SIZE, 1UL << REAL_HPAGE_SHIFT);
+#else
+       DEFINE(HUGEPAGE_SIZE, PAGE_SIZE);
+#endif
        BLANK();
        DEFINE(EXCDATA_IP, offsetof(struct exception_data, fault_ip));
        DEFINE(EXCDATA_SPACE, offsetof(struct exception_data, fault_space));
index c5ef4081b01d2f0aee841a7f8f06b0be416a6fd8..623496c117564cdbc7f939dea4ff777e114212ac 100644 (file)
        STREG           \pte,0(\ptp)
        .endm
 
+       /* We have (depending on the page size):
+        * - 38 to 52-bit Physical Page Number
+        * - 12 to 26-bit page offset
+        */
        /* bitshift difference between a PFN (based on kernel's PAGE_SIZE)
         * to a CPU TLB 4k PFN (4k => 12 bits to shift) */
-       #define PAGE_ADD_SHIFT  (PAGE_SHIFT-12)
+       #define PAGE_ADD_SHIFT          (PAGE_SHIFT-12)
+       #define PAGE_ADD_HUGE_SHIFT     (REAL_HPAGE_SHIFT-12)
 
        /* Drop prot bits and convert to page addr for iitlbt and idtlbt */
-       .macro          convert_for_tlb_insert20 pte
+       .macro          convert_for_tlb_insert20 pte,tmp
+#ifdef CONFIG_HUGETLB_PAGE
+       copy            \pte,\tmp
+       extrd,u         \tmp,(63-ASM_PFN_PTE_SHIFT)+(63-58)+PAGE_ADD_SHIFT,\
+                               64-PAGE_SHIFT-PAGE_ADD_SHIFT,\pte
+
+       depdi           _PAGE_SIZE_ENCODING_DEFAULT,63,\
+                               (63-58)+PAGE_ADD_SHIFT,\pte
+       extrd,u,*=      \tmp,_PAGE_HPAGE_BIT+32,1,%r0
+       depdi           _HUGE_PAGE_SIZE_ENCODING_DEFAULT,63,\
+                               (63-58)+PAGE_ADD_HUGE_SHIFT,\pte
+#else /* Huge pages disabled */
        extrd,u         \pte,(63-ASM_PFN_PTE_SHIFT)+(63-58)+PAGE_ADD_SHIFT,\
                                64-PAGE_SHIFT-PAGE_ADD_SHIFT,\pte
        depdi           _PAGE_SIZE_ENCODING_DEFAULT,63,\
                                (63-58)+PAGE_ADD_SHIFT,\pte
+#endif
        .endm
 
        /* Convert the pte and prot to tlb insertion values.  How
         * this happens is quite subtle, read below */
-       .macro          make_insert_tlb spc,pte,prot
+       .macro          make_insert_tlb spc,pte,prot,tmp
        space_to_prot   \spc \prot        /* create prot id from space */
        /* The following is the real subtlety.  This is depositing
         * T <-> _PAGE_REFTRAP
        depdi           1,12,1,\prot
 
        /* Drop prot bits and convert to page addr for iitlbt and idtlbt */
-       convert_for_tlb_insert20 \pte
+       convert_for_tlb_insert20 \pte \tmp
        .endm
 
        /* Identical macro to make_insert_tlb above, except it
 
 
        /*
-        * Align fault_vector_20 on 4K boundary so that both
-        * fault_vector_11 and fault_vector_20 are on the
-        * same page. This is only necessary as long as we
-        * write protect the kernel text, which we may stop
-        * doing once we use large page translations to cover
-        * the static part of the kernel address space.
+        * Fault_vectors are architecturally required to be aligned on a 2K
+        * boundary
         */
 
        .text
-
-       .align 4096
+       .align 2048
 
 ENTRY(fault_vector_20)
        /* First vector is invalid (0) */
@@ -1147,7 +1159,7 @@ dtlb_miss_20w:
        tlb_lock        spc,ptp,pte,t0,t1,dtlb_check_alias_20w
        update_accessed ptp,pte,t0,t1
 
-       make_insert_tlb spc,pte,prot
+       make_insert_tlb spc,pte,prot,t1
        
        idtlbt          pte,prot
 
@@ -1173,7 +1185,7 @@ nadtlb_miss_20w:
        tlb_lock        spc,ptp,pte,t0,t1,nadtlb_check_alias_20w
        update_accessed ptp,pte,t0,t1
 
-       make_insert_tlb spc,pte,prot
+       make_insert_tlb spc,pte,prot,t1
 
        idtlbt          pte,prot
 
@@ -1267,7 +1279,7 @@ dtlb_miss_20:
        tlb_lock        spc,ptp,pte,t0,t1,dtlb_check_alias_20
        update_accessed ptp,pte,t0,t1
 
-       make_insert_tlb spc,pte,prot
+       make_insert_tlb spc,pte,prot,t1
 
        f_extend        pte,t1
 
@@ -1295,7 +1307,7 @@ nadtlb_miss_20:
        tlb_lock        spc,ptp,pte,t0,t1,nadtlb_check_alias_20
        update_accessed ptp,pte,t0,t1
 
-       make_insert_tlb spc,pte,prot
+       make_insert_tlb spc,pte,prot,t1
 
        f_extend        pte,t1
        
@@ -1404,7 +1416,7 @@ itlb_miss_20w:
        tlb_lock        spc,ptp,pte,t0,t1,itlb_fault
        update_accessed ptp,pte,t0,t1
 
-       make_insert_tlb spc,pte,prot
+       make_insert_tlb spc,pte,prot,t1
        
        iitlbt          pte,prot
 
@@ -1428,7 +1440,7 @@ naitlb_miss_20w:
        tlb_lock        spc,ptp,pte,t0,t1,naitlb_check_alias_20w
        update_accessed ptp,pte,t0,t1
 
-       make_insert_tlb spc,pte,prot
+       make_insert_tlb spc,pte,prot,t1
 
        iitlbt          pte,prot
 
@@ -1514,7 +1526,7 @@ itlb_miss_20:
        tlb_lock        spc,ptp,pte,t0,t1,itlb_fault
        update_accessed ptp,pte,t0,t1
 
-       make_insert_tlb spc,pte,prot
+       make_insert_tlb spc,pte,prot,t1
 
        f_extend        pte,t1
 
@@ -1534,7 +1546,7 @@ naitlb_miss_20:
        tlb_lock        spc,ptp,pte,t0,t1,naitlb_check_alias_20
        update_accessed ptp,pte,t0,t1
 
-       make_insert_tlb spc,pte,prot
+       make_insert_tlb spc,pte,prot,t1
 
        f_extend        pte,t1
 
@@ -1566,7 +1578,7 @@ dbit_trap_20w:
        tlb_lock        spc,ptp,pte,t0,t1,dbit_fault
        update_dirty    ptp,pte,t1
 
-       make_insert_tlb spc,pte,prot
+       make_insert_tlb spc,pte,prot,t1
                
        idtlbt          pte,prot
 
@@ -1610,7 +1622,7 @@ dbit_trap_20:
        tlb_lock        spc,ptp,pte,t0,t1,dbit_fault
        update_dirty    ptp,pte,t1
 
-       make_insert_tlb spc,pte,prot
+       make_insert_tlb spc,pte,prot,t1
 
        f_extend        pte,t1
        
index e7d64527aff94f69b019f7bde3aad63da47420ec..75aa0db9f69efe2fb3fa00d10d6fc66bd3f2b923 100644 (file)
@@ -69,7 +69,7 @@ $bss_loop:
        stw,ma          %arg2,4(%r1)
        stw,ma          %arg3,4(%r1)
 
-       /* Initialize startup VM. Just map first 8/16 MB of memory */
+       /* Initialize startup VM. Just map first 16/32 MB of memory */
        load32          PA(swapper_pg_dir),%r4
        mtctl           %r4,%cr24       /* Initialize kernel root pointer */
        mtctl           %r4,%cr25       /* Initialize user root pointer */
@@ -107,7 +107,7 @@ $bss_loop:
        /* Now initialize the PTEs themselves.  We use RWX for
         * everything ... it will get remapped correctly later */
        ldo             0+_PAGE_KERNEL_RWX(%r0),%r3 /* Hardwired 0 phys addr start */
-       ldi             (1<<(KERNEL_INITIAL_ORDER-PAGE_SHIFT)),%r11 /* PFN count */
+       load32          (1<<(KERNEL_INITIAL_ORDER-PAGE_SHIFT)),%r11 /* PFN count */
        load32          PA(pg0),%r1
 
 $pgt_fill_loop:
index 64f2764a8cef8778a0602262a5c5b10e4d68975d..c99f3dde455ce5979ee4e17830704710ba4683af 100644 (file)
@@ -171,24 +171,6 @@ void pcibios_set_master(struct pci_dev *dev)
 }
 
 
-void __init pcibios_init_bus(struct pci_bus *bus)
-{
-       struct pci_dev *dev = bus->self;
-       unsigned short bridge_ctl;
-
-       /* We deal only with pci controllers and pci-pci bridges. */
-       if (!dev || (dev->class >> 8) != PCI_CLASS_BRIDGE_PCI)
-               return;
-
-       /* PCI-PCI bridge - set the cache line and default latency
-          (32) for primary and secondary buses. */
-       pci_write_config_byte(dev, PCI_SEC_LATENCY_TIMER, 32);
-
-       pci_read_config_word(dev, PCI_BRIDGE_CONTROL, &bridge_ctl);
-       bridge_ctl |= PCI_BRIDGE_CTL_PARITY | PCI_BRIDGE_CTL_SERR;
-       pci_write_config_word(dev, PCI_BRIDGE_CONTROL, bridge_ctl);
-}
-
 /*
  * pcibios align resources() is called every time generic PCI code
  * wants to generate a new address. The process of looking for
index 72a3c658ad7bdbc3a0429f4c85f1d890b914e38c..f7ea626e29c9b3bce80d28062cbf802ab2313785 100644 (file)
@@ -130,7 +130,16 @@ void __init setup_arch(char **cmdline_p)
        printk(KERN_INFO "The 32-bit Kernel has started...\n");
 #endif
 
-       printk(KERN_INFO "Default page size is %dKB.\n", (int)(PAGE_SIZE / 1024));
+       printk(KERN_INFO "Kernel default page size is %d KB. Huge pages ",
+               (int)(PAGE_SIZE / 1024));
+#ifdef CONFIG_HUGETLB_PAGE
+       printk(KERN_CONT "enabled with %d MB physical and %d MB virtual size",
+                1 << (REAL_HPAGE_SHIFT - 20), 1 << (HPAGE_SHIFT - 20));
+#else
+       printk(KERN_CONT "disabled");
+#endif
+       printk(KERN_CONT ".\n");
+
 
        pdc_console_init();
 
@@ -377,6 +386,7 @@ arch_initcall(parisc_init);
 void start_parisc(void)
 {
        extern void start_kernel(void);
+       extern void early_trap_init(void);
 
        int ret, cpunum;
        struct pdc_coproc_cfg coproc_cfg;
@@ -397,6 +407,8 @@ void start_parisc(void)
                panic("must have an fpu to boot linux");
        }
 
+       early_trap_init(); /* initialize checksum of fault_vector */
+
        start_kernel();
        // not reached
 }
index dc1ea796fd605c257c7ce1196a63773a3e3e7987..2264f68f3c2f9716030cb8fab53487f6db22e667 100644 (file)
@@ -435,6 +435,55 @@ handle_signal(struct ksignal *ksig, struct pt_regs *regs, int in_syscall)
                regs->gr[28]);
 }
 
+/*
+ * Check how the syscall number gets loaded into %r20 within
+ * the delay branch in userspace and adjust as needed.
+ */
+
+static void check_syscallno_in_delay_branch(struct pt_regs *regs)
+{
+       u32 opcode, source_reg;
+       u32 __user *uaddr;
+       int err;
+
+       /* Usually we don't have to restore %r20 (the system call number)
+        * because it gets loaded in the delay slot of the branch external
+        * instruction via the ldi instruction.
+        * In some cases a register-to-register copy instruction might have
+        * been used instead, in which case we need to copy the syscall
+        * number into the source register before returning to userspace.
+        */
+
+       /* A syscall is just a branch, so all we have to do is fiddle the
+        * return pointer so that the ble instruction gets executed again.
+        */
+       regs->gr[31] -= 8; /* delayed branching */
+
+       /* Get assembler opcode of code in delay branch */
+       uaddr = (unsigned int *) ((regs->gr[31] & ~3) + 4);
+       err = get_user(opcode, uaddr);
+       if (err)
+               return;
+
+       /* Check if delay branch uses "ldi int,%r20" */
+       if ((opcode & 0xffff0000) == 0x34140000)
+               return; /* everything ok, just return */
+
+       /* Check if delay branch uses "nop" */
+       if (opcode == INSN_NOP)
+               return;
+
+       /* Check if delay branch uses "copy %rX,%r20" */
+       if ((opcode & 0xffe0ffff) == 0x08000254) {
+               source_reg = (opcode >> 16) & 31;
+               regs->gr[source_reg] = regs->gr[20];
+               return;
+       }
+
+       pr_warn("syscall restart: %s (pid %d): unexpected opcode 0x%08x\n",
+               current->comm, task_pid_nr(current), opcode);
+}
+
 static inline void
 syscall_restart(struct pt_regs *regs, struct k_sigaction *ka)
 {
@@ -457,10 +506,7 @@ syscall_restart(struct pt_regs *regs, struct k_sigaction *ka)
                }
                /* fallthrough */
        case -ERESTARTNOINTR:
-               /* A syscall is just a branch, so all
-                * we have to do is fiddle the return pointer.
-                */
-               regs->gr[31] -= 8; /* delayed branching */
+               check_syscallno_in_delay_branch(regs);
                break;
        }
 }
@@ -510,15 +556,9 @@ insert_restart_trampoline(struct pt_regs *regs)
        }
        case -ERESTARTNOHAND:
        case -ERESTARTSYS:
-       case -ERESTARTNOINTR: {
-               /* Hooray for delayed branching.  We don't
-                * have to restore %r20 (the system call
-                * number) because it gets loaded in the delay
-                * slot of the branch external instruction.
-                */
-               regs->gr[31] -= 8;
+       case -ERESTARTNOINTR:
+               check_syscallno_in_delay_branch(regs);
                return;
-       }
        default:
                break;
        }
index 0b8d26d3ba43be545308dc70075a4a224a8b8155..3fbd7252a4b27efd106250f5b21e98910f8af8bd 100644 (file)
@@ -369,7 +369,7 @@ tracesys_exit:
        ldo     -16(%r30),%r29                  /* Reference param save area */
 #endif
        ldo     TASK_REGS(%r1),%r26
-       bl      do_syscall_trace_exit,%r2
+       BL      do_syscall_trace_exit,%r2
        STREG   %r28,TASK_PT_GR28(%r1)          /* save return value now */
        ldo     -THREAD_SZ_ALGN-FRAME_SIZE(%r30),%r1      /* get task ptr */
        LDREG   TI_TASK(%r1), %r1
@@ -390,7 +390,7 @@ tracesys_sigexit:
 #ifdef CONFIG_64BIT
        ldo     -16(%r30),%r29                  /* Reference param save area */
 #endif
-       bl      do_syscall_trace_exit,%r2
+       BL      do_syscall_trace_exit,%r2
        ldo     TASK_REGS(%r1),%r26
 
        ldil    L%syscall_exit_rfi,%r1
index 78c3ef8c348d5cfdef2b50670a1da348ee49566e..d4ffcfbc98851e7c3f0707ec9d82470d918bed2e 100644 (file)
        ENTRY_COMP(execveat)
        ENTRY_SAME(membarrier)
        ENTRY_SAME(userfaultfd)
+       ENTRY_SAME(mlock2)              /* 345 */
 
 
 .ifne (. - 90b) - (__NR_Linux_syscalls * (91b - 90b))
index b99b39f1da02431865b94e6bfe720e9858163a0d..553b09855cfd8799acde0df3d9118afcfcf5cbb0 100644 (file)
@@ -807,7 +807,7 @@ void notrace handle_interruption(int code, struct pt_regs *regs)
 }
 
 
-int __init check_ivt(void *iva)
+void __init initialize_ivt(const void *iva)
 {
        extern u32 os_hpmc_size;
        extern const u32 os_hpmc[];
@@ -818,8 +818,8 @@ int __init check_ivt(void *iva)
        u32 *hpmcp;
        u32 length;
 
-       if (strcmp((char *)iva, "cows can fly"))
-               return -1;
+       if (strcmp((const char *)iva, "cows can fly"))
+               panic("IVT invalid");
 
        ivap = (u32 *)iva;
 
@@ -839,28 +839,23 @@ int __init check_ivt(void *iva)
            check += ivap[i];
 
        ivap[5] = -check;
-
-       return 0;
 }
        
-#ifndef CONFIG_64BIT
-extern const void fault_vector_11;
-#endif
-extern const void fault_vector_20;
 
-void __init trap_init(void)
+/* early_trap_init() is called before we set up kernel mappings and
+ * write-protect the kernel */
+void  __init early_trap_init(void)
 {
-       void *iva;
+       extern const void fault_vector_20;
 
-       if (boot_cpu_data.cpu_type >= pcxu)
-               iva = (void *) &fault_vector_20;
-       else
-#ifdef CONFIG_64BIT
-               panic("Can't boot 64-bit OS on PA1.1 processor!");
-#else
-               iva = (void *) &fault_vector_11;
+#ifndef CONFIG_64BIT
+       extern const void fault_vector_11;
+       initialize_ivt(&fault_vector_11);
 #endif
 
-       if (check_ivt(iva))
-               panic("IVT invalid");
+       initialize_ivt(&fault_vector_20);
+}
+
+void __init trap_init(void)
+{
 }
index 0dacc5ca555afe7643da970bf9f3ae75ebc88790..308f29081d461b0a9b0a0d8eec0d54e0a1936ff3 100644 (file)
@@ -60,7 +60,7 @@ SECTIONS
                EXIT_DATA
        }
        PERCPU_SECTION(8)
-       . = ALIGN(PAGE_SIZE);
+       . = ALIGN(HUGEPAGE_SIZE);
        __init_end = .;
        /* freed after init ends here */
 
@@ -116,7 +116,7 @@ SECTIONS
         * that we can properly leave these
         * as writable
         */
-       . = ALIGN(PAGE_SIZE);
+       . = ALIGN(HUGEPAGE_SIZE);
        data_start = .;
 
        EXCEPTION_TABLE(8)
@@ -135,8 +135,11 @@ SECTIONS
        _edata = .;
 
        /* BSS */
-       BSS_SECTION(PAGE_SIZE, PAGE_SIZE, 8)
+       BSS_SECTION(PAGE_SIZE, PAGE_SIZE, PAGE_SIZE)
+
+       /* bootmap is allocated in setup_bootmem() directly behind bss. */
 
+       . = ALIGN(HUGEPAGE_SIZE);
        _end = . ;
 
        STABS_DEBUG
index 758ceefb373aedaa0aaa86d57bccfe8fc6390887..134393de69d25e24101e5634d0b538bbf7fbc569 100644 (file)
@@ -3,3 +3,4 @@
 #
 
 obj-y   := init.o fault.o ioremap.o
+obj-$(CONFIG_HUGETLB_PAGE) += hugetlbpage.o
diff --git a/arch/parisc/mm/hugetlbpage.c b/arch/parisc/mm/hugetlbpage.c
new file mode 100644 (file)
index 0000000..f6fdc77
--- /dev/null
@@ -0,0 +1,161 @@
+/*
+ * PARISC64 Huge TLB page support.
+ *
+ * This parisc implementation is heavily based on the SPARC and x86 code.
+ *
+ * Copyright (C) 2015 Helge Deller <deller@gmx.de>
+ */
+
+#include <linux/fs.h>
+#include <linux/mm.h>
+#include <linux/hugetlb.h>
+#include <linux/pagemap.h>
+#include <linux/sysctl.h>
+
+#include <asm/mman.h>
+#include <asm/pgalloc.h>
+#include <asm/tlb.h>
+#include <asm/tlbflush.h>
+#include <asm/cacheflush.h>
+#include <asm/mmu_context.h>
+
+
+unsigned long
+hugetlb_get_unmapped_area(struct file *file, unsigned long addr,
+               unsigned long len, unsigned long pgoff, unsigned long flags)
+{
+       struct hstate *h = hstate_file(file);
+
+       if (len & ~huge_page_mask(h))
+               return -EINVAL;
+       if (len > TASK_SIZE)
+               return -ENOMEM;
+
+       if (flags & MAP_FIXED)
+               if (prepare_hugepage_range(file, addr, len))
+                       return -EINVAL;
+
+       if (addr)
+               addr = ALIGN(addr, huge_page_size(h));
+
+       /* we need to make sure the colouring is OK */
+       return arch_get_unmapped_area(file, addr, len, pgoff, flags);
+}
+
+
+pte_t *huge_pte_alloc(struct mm_struct *mm,
+                       unsigned long addr, unsigned long sz)
+{
+       pgd_t *pgd;
+       pud_t *pud;
+       pmd_t *pmd;
+       pte_t *pte = NULL;
+
+       /* We must align the address, because our caller will run
+        * set_huge_pte_at() on whatever we return, which writes out
+        * all of the sub-ptes for the hugepage range.  So we have
+        * to give it the first such sub-pte.
+        */
+       addr &= HPAGE_MASK;
+
+       pgd = pgd_offset(mm, addr);
+       pud = pud_alloc(mm, pgd, addr);
+       if (pud) {
+               pmd = pmd_alloc(mm, pud, addr);
+               if (pmd)
+                       pte = pte_alloc_map(mm, NULL, pmd, addr);
+       }
+       return pte;
+}
+
+pte_t *huge_pte_offset(struct mm_struct *mm, unsigned long addr)
+{
+       pgd_t *pgd;
+       pud_t *pud;
+       pmd_t *pmd;
+       pte_t *pte = NULL;
+
+       addr &= HPAGE_MASK;
+
+       pgd = pgd_offset(mm, addr);
+       if (!pgd_none(*pgd)) {
+               pud = pud_offset(pgd, addr);
+               if (!pud_none(*pud)) {
+                       pmd = pmd_offset(pud, addr);
+                       if (!pmd_none(*pmd))
+                               pte = pte_offset_map(pmd, addr);
+               }
+       }
+       return pte;
+}
+
+/* Purge data and instruction TLB entries.  Must be called holding
+ * the pa_tlb_lock.  The TLB purge instructions are slow on SMP
+ * machines since the purge must be broadcast to all CPUs.
+ */
+static inline void purge_tlb_entries_huge(struct mm_struct *mm, unsigned long addr)
+{
+       int i;
+
+       /* We may use multiple physical huge pages (e.g. 2x1 MB) to emulate
+        * Linux standard huge pages (e.g. 2 MB) */
+       BUILD_BUG_ON(REAL_HPAGE_SHIFT > HPAGE_SHIFT);
+
+       addr &= HPAGE_MASK;
+       addr |= _HUGE_PAGE_SIZE_ENCODING_DEFAULT;
+
+       for (i = 0; i < (1 << (HPAGE_SHIFT-REAL_HPAGE_SHIFT)); i++) {
+               mtsp(mm->context, 1);
+               pdtlb(addr);
+               if (unlikely(split_tlb))
+                       pitlb(addr);
+               addr += (1UL << REAL_HPAGE_SHIFT);
+       }
+}
+
+void set_huge_pte_at(struct mm_struct *mm, unsigned long addr,
+                    pte_t *ptep, pte_t entry)
+{
+       unsigned long addr_start;
+       int i;
+
+       addr &= HPAGE_MASK;
+       addr_start = addr;
+
+       for (i = 0; i < (1 << HUGETLB_PAGE_ORDER); i++) {
+               /* Directly write pte entry.  We could call set_pte_at(mm, addr, ptep, entry)
+                * instead, but then we get double locking on pa_tlb_lock. */
+               *ptep = entry;
+               ptep++;
+
+               /* Drop the PAGE_SIZE/non-huge tlb entry */
+               purge_tlb_entries(mm, addr);
+
+               addr += PAGE_SIZE;
+               pte_val(entry) += PAGE_SIZE;
+       }
+
+       purge_tlb_entries_huge(mm, addr_start);
+}
+
+
+pte_t huge_ptep_get_and_clear(struct mm_struct *mm, unsigned long addr,
+                             pte_t *ptep)
+{
+       pte_t entry;
+
+       entry = *ptep;
+       set_huge_pte_at(mm, addr, ptep, __pte(0));
+
+       return entry;
+}
+
+int pmd_huge(pmd_t pmd)
+{
+       return 0;
+}
+
+int pud_huge(pud_t pud)
+{
+       return 0;
+}
index c5fec4890fdf52fe459198ff7780f9e59af6d294..1b366c47768722081efe57a9db39eaba2a7dcde9 100644 (file)
@@ -409,15 +409,11 @@ static void __init map_pages(unsigned long start_vaddr,
        unsigned long vaddr;
        unsigned long ro_start;
        unsigned long ro_end;
-       unsigned long fv_addr;
-       unsigned long gw_addr;
-       extern const unsigned long fault_vector_20;
-       extern void * const linux_gateway_page;
+       unsigned long kernel_end;
 
        ro_start = __pa((unsigned long)_text);
        ro_end   = __pa((unsigned long)&data_start);
-       fv_addr  = __pa((unsigned long)&fault_vector_20) & PAGE_MASK;
-       gw_addr  = __pa((unsigned long)&linux_gateway_page) & PAGE_MASK;
+       kernel_end  = __pa((unsigned long)&_end);
 
        end_paddr = start_paddr + size;
 
@@ -475,24 +471,25 @@ static void __init map_pages(unsigned long start_vaddr,
                        for (tmp2 = start_pte; tmp2 < PTRS_PER_PTE; tmp2++, pg_table++) {
                                pte_t pte;
 
-                               /*
-                                * Map the fault vector writable so we can
-                                * write the HPMC checksum.
-                                */
                                if (force)
                                        pte =  __mk_pte(address, pgprot);
-                               else if (parisc_text_address(vaddr) &&
-                                        address != fv_addr)
+                               else if (parisc_text_address(vaddr)) {
                                        pte = __mk_pte(address, PAGE_KERNEL_EXEC);
+                                       if (address >= ro_start && address < kernel_end)
+                                               pte = pte_mkhuge(pte);
+                               }
                                else
 #if defined(CONFIG_PARISC_PAGE_SIZE_4KB)
-                               if (address >= ro_start && address < ro_end
-                                                       && address != fv_addr
-                                                       && address != gw_addr)
-                                       pte = __mk_pte(address, PAGE_KERNEL_RO);
-                               else
+                               if (address >= ro_start && address < ro_end) {
+                                       pte = __mk_pte(address, PAGE_KERNEL_EXEC);
+                                       pte = pte_mkhuge(pte);
+                               } else
 #endif
+                               {
                                        pte = __mk_pte(address, pgprot);
+                                       if (address >= ro_start && address < kernel_end)
+                                               pte = pte_mkhuge(pte);
+                               }
 
                                if (address >= end_paddr) {
                                        if (force)
@@ -536,15 +533,12 @@ void free_initmem(void)
 
        /* force the kernel to see the new TLB entries */
        __flush_tlb_range(0, init_begin, init_end);
-       /* Attempt to catch anyone trying to execute code here
-        * by filling the page with BRK insns.
-        */
-       memset((void *)init_begin, 0x00, init_end - init_begin);
+
        /* finally dump all the instructions which were cached, since the
         * pages are no-longer executable */
        flush_icache_range(init_begin, init_end);
        
-       free_initmem_default(-1);
+       free_initmem_default(POISON_FREE_INITMEM);
 
        /* set up a new led state on systems shipped LED State panel */
        pdc_chassis_send_status(PDC_CHASSIS_DIRECT_BCOMPLETE);
@@ -728,8 +722,8 @@ static void __init pagetable_init(void)
                unsigned long size;
 
                start_paddr = pmem_ranges[range].start_pfn << PAGE_SHIFT;
-               end_paddr = start_paddr + (pmem_ranges[range].pages << PAGE_SHIFT);
                size = pmem_ranges[range].pages << PAGE_SHIFT;
+               end_paddr = start_paddr + size;
 
                map_pages((unsigned long)__va(start_paddr), start_paddr,
                          size, PAGE_KERNEL, 0);
index 631ede72e226c31c8d9f610bc583fc9f93802191..68f0ed7626bd96252f768c7dcca12e8e0294ef69 100644 (file)
                                reg = <0x520 0x20>;
 
                                phy0: ethernet-phy@1f {
-                                       interrupt-parent = <&mpic>;
-                                       interrupts = <10 1>;
                                        reg = <0x1f>;
                                };
                                phy1: ethernet-phy@0 {
-                                       interrupt-parent = <&mpic>;
-                                       interrupts = <10 1>;
                                        reg = <0>;
                                };
                                phy2: ethernet-phy@1 {
-                                       interrupt-parent = <&mpic>;
-                                       interrupts = <10 1>;
                                        reg = <1>;
                                };
                                phy3: ethernet-phy@2 {
-                                       interrupt-parent = <&mpic>;
-                                       interrupts = <10 1>;
                                        reg = <2>;
                                };
                                tbi0: tbi-phy@11 {
index a908ada8e0a5353f5fce19af6ad3e59779ce2e0e..2220f7a60def314be5c8f23e18ceb8982061cb18 100644 (file)
 #define MSR_TS_T       __MASK(MSR_TS_T_LG)     /*  Transaction Transactional */
 #define MSR_TS_MASK    (MSR_TS_T | MSR_TS_S)   /* Transaction State bits */
 #define MSR_TM_ACTIVE(x) (((x) & MSR_TS_MASK) != 0) /* Transaction active? */
+#define MSR_TM_RESV(x) (((x) & MSR_TS_MASK) == MSR_TS_MASK) /* Reserved */
 #define MSR_TM_TRANSACTIONAL(x)        (((x) & MSR_TS_MASK) == MSR_TS_T)
 #define MSR_TM_SUSPENDED(x)    (((x) & MSR_TS_MASK) == MSR_TS_S)
 
index c9e26cb264f49dfff80114ddd97e1d10460157dd..5654ece02c0db5ee41da441c30d8a2c5f1cdcbc4 100644 (file)
@@ -370,15 +370,16 @@ COMPAT_SYS(execveat)
 PPC64ONLY(switch_endian)
 SYSCALL_SPU(userfaultfd)
 SYSCALL_SPU(membarrier)
-SYSCALL(semop)
-SYSCALL(semget)
-COMPAT_SYS(semctl)
-COMPAT_SYS(semtimedop)
-COMPAT_SYS(msgsnd)
-COMPAT_SYS(msgrcv)
-SYSCALL(msgget)
-COMPAT_SYS(msgctl)
-COMPAT_SYS(shmat)
-SYSCALL(shmdt)
-SYSCALL(shmget)
-COMPAT_SYS(shmctl)
+SYSCALL(ni_syscall)
+SYSCALL(ni_syscall)
+SYSCALL(ni_syscall)
+SYSCALL(ni_syscall)
+SYSCALL(ni_syscall)
+SYSCALL(ni_syscall)
+SYSCALL(ni_syscall)
+SYSCALL(ni_syscall)
+SYSCALL(ni_syscall)
+SYSCALL(ni_syscall)
+SYSCALL(ni_syscall)
+SYSCALL(ni_syscall)
+SYSCALL(mlock2)
index 6d8f8023ac27b1893bd4f6d329c6498b39fd949d..4b6b8ace18e086729932bd5635811167a6491a2b 100644 (file)
@@ -12,7 +12,7 @@
 #include <uapi/asm/unistd.h>
 
 
-#define __NR_syscalls          378
+#define __NR_syscalls          379
 
 #define __NR__exit __NR_exit
 #define NR_syscalls    __NR_syscalls
index 81579e93c65991b3dcb1e129aec6474a722d86cc..12a05652377a28799a89ae59e3d38a7ddeaade92 100644 (file)
 #define __NR_switch_endian     363
 #define __NR_userfaultfd       364
 #define __NR_membarrier                365
-#define __NR_semop             366
-#define __NR_semget            367
-#define __NR_semctl            368
-#define __NR_semtimedop                369
-#define __NR_msgsnd            370
-#define __NR_msgrcv            371
-#define __NR_msgget            372
-#define __NR_msgctl            373
-#define __NR_shmat             374
-#define __NR_shmdt             375
-#define __NR_shmget            376
-#define __NR_shmctl            377
+#define __NR_mlock2            378
 
 #endif /* _UAPI_ASM_POWERPC_UNISTD_H_ */
index 80dfe8965df9f7d49fc57a1f1d6773f0c5ffd736..8d14feb40f121129854a7760818e926f7b5b742c 100644 (file)
@@ -590,16 +590,10 @@ static int eeh_reset_device(struct eeh_pe *pe, struct pci_bus *bus)
        eeh_ops->configure_bridge(pe);
        eeh_pe_restore_bars(pe);
 
-       /*
-        * If it's PHB PE, the frozen state on all available PEs should have
-        * been cleared by the PHB reset. Otherwise, we unfreeze the PE and its
-        * child PEs because they might be in frozen state.
-        */
-       if (!(pe->type & EEH_PE_PHB)) {
-               rc = eeh_clear_pe_frozen_state(pe, false);
-               if (rc)
-                       return rc;
-       }
+       /* Clear frozen state */
+       rc = eeh_clear_pe_frozen_state(pe, false);
+       if (rc)
+               return rc;
 
        /* Give the system 5 seconds to finish running the user-space
         * hotplug shutdown scripts, e.g. ifdown for ethernet.  Yes,
index 75b6676c1a0b911b72b7af5a8dc7761173e638e8..646bf4d222c1caeda5c7851de74fbbe0ad0d65d9 100644 (file)
@@ -551,6 +551,24 @@ static void tm_reclaim_thread(struct thread_struct *thr,
                msr_diff &= MSR_FP | MSR_VEC | MSR_VSX | MSR_FE0 | MSR_FE1;
        }
 
+       /*
+        * Use the current MSR TM suspended bit to track if we have
+        * checkpointed state outstanding.
+        * On signal delivery, we'd normally reclaim the checkpointed
+        * state to obtain stack pointer (see:get_tm_stackpointer()).
+        * This will then directly return to userspace without going
+        * through __switch_to(). However, if the stack frame is bad,
+        * we need to exit this thread which calls __switch_to() which
+        * will again attempt to reclaim the already saved tm state.
+        * Hence we need to check that we've not already reclaimed
+        * this state.
+        * We do this using the current MSR, rather tracking it in
+        * some specific thread_struct bit, as it has the additional
+        * benifit of checking for a potential TM bad thing exception.
+        */
+       if (!MSR_TM_SUSPENDED(mfmsr()))
+               return;
+
        tm_reclaim(thr, thr->regs->msr, cause);
 
        /* Having done the reclaim, we now have the checkpointed
index 0dbee465af7a70e6c1ce0b7f1f667a577a7ebed0..ef7c24e84a623882c8f98dbc93aa7ab318a4ff68 100644 (file)
@@ -875,6 +875,15 @@ static long restore_tm_user_regs(struct pt_regs *regs,
                return 1;
 #endif /* CONFIG_SPE */
 
+       /* Get the top half of the MSR from the user context */
+       if (__get_user(msr_hi, &tm_sr->mc_gregs[PT_MSR]))
+               return 1;
+       msr_hi <<= 32;
+       /* If TM bits are set to the reserved value, it's an invalid context */
+       if (MSR_TM_RESV(msr_hi))
+               return 1;
+       /* Pull in the MSR TM bits from the user context */
+       regs->msr = (regs->msr & ~MSR_TS_MASK) | (msr_hi & MSR_TS_MASK);
        /* Now, recheckpoint.  This loads up all of the checkpointed (older)
         * registers, including FP and V[S]Rs.  After recheckpointing, the
         * transactional versions should be loaded.
@@ -884,11 +893,6 @@ static long restore_tm_user_regs(struct pt_regs *regs,
        current->thread.tm_texasr |= TEXASR_FS;
        /* This loads the checkpointed FP/VEC state, if used */
        tm_recheckpoint(&current->thread, msr);
-       /* Get the top half of the MSR */
-       if (__get_user(msr_hi, &tm_sr->mc_gregs[PT_MSR]))
-               return 1;
-       /* Pull in MSR TM from user context */
-       regs->msr = (regs->msr & ~MSR_TS_MASK) | ((msr_hi<<32) & MSR_TS_MASK);
 
        /* This loads the speculative FP/VEC state, if used */
        if (msr & MSR_FP) {
index 20756dfb9f34620ac254577458ac2aa8ff804835..c676ecec0869b26216e87483f54c2c6906ea6d01 100644 (file)
@@ -438,6 +438,10 @@ static long restore_tm_sigcontexts(struct pt_regs *regs,
 
        /* get MSR separately, transfer the LE bit if doing signal return */
        err |= __get_user(msr, &sc->gp_regs[PT_MSR]);
+       /* Don't allow reserved mode. */
+       if (MSR_TM_RESV(msr))
+               return -EINVAL;
+
        /* pull in MSR TM from user context */
        regs->msr = (regs->msr & ~MSR_TS_MASK) | (msr & MSR_TS_MASK);
 
index 54b45b73195f912688ec4afe8e9fb4c9c3d5723c..a7352b59e6f9b5c74f37556e6858c9ac9c5bb30b 100644 (file)
@@ -224,6 +224,12 @@ static void kvmppc_core_vcpu_put_hv(struct kvm_vcpu *vcpu)
 
 static void kvmppc_set_msr_hv(struct kvm_vcpu *vcpu, u64 msr)
 {
+       /*
+        * Check for illegal transactional state bit combination
+        * and if we find it, force the TS field to a safe state.
+        */
+       if ((msr & MSR_TS_MASK) == MSR_TS_MASK)
+               msr &= ~MSR_TS_MASK;
        vcpu->arch.shregs.msr = msr;
        kvmppc_end_cede(vcpu);
 }
index 6ccfb6c1c707b40e9fd6ba4cb202d70c1faf57cb..e505223b4ec5ed2d82bcb08b2e718a6b64601f18 100644 (file)
@@ -43,11 +43,34 @@ static unsigned int opal_irq_count;
 static unsigned int *opal_irqs;
 
 static void opal_handle_irq_work(struct irq_work *work);
-static __be64 last_outstanding_events;
+static u64 last_outstanding_events;
 static struct irq_work opal_event_irq_work = {
        .func = opal_handle_irq_work,
 };
 
+void opal_handle_events(uint64_t events)
+{
+       int virq, hwirq = 0;
+       u64 mask = opal_event_irqchip.mask;
+
+       if (!in_irq() && (events & mask)) {
+               last_outstanding_events = events;
+               irq_work_queue(&opal_event_irq_work);
+               return;
+       }
+
+       while (events & mask) {
+               hwirq = fls64(events) - 1;
+               if (BIT_ULL(hwirq) & mask) {
+                       virq = irq_find_mapping(opal_event_irqchip.domain,
+                                               hwirq);
+                       if (virq)
+                               generic_handle_irq(virq);
+               }
+               events &= ~BIT_ULL(hwirq);
+       }
+}
+
 static void opal_event_mask(struct irq_data *d)
 {
        clear_bit(d->hwirq, &opal_event_irqchip.mask);
@@ -55,9 +78,21 @@ static void opal_event_mask(struct irq_data *d)
 
 static void opal_event_unmask(struct irq_data *d)
 {
+       __be64 events;
+
        set_bit(d->hwirq, &opal_event_irqchip.mask);
 
-       opal_poll_events(&last_outstanding_events);
+       opal_poll_events(&events);
+       last_outstanding_events = be64_to_cpu(events);
+
+       /*
+        * We can't just handle the events now with opal_handle_events().
+        * If we did we would deadlock when opal_event_unmask() is called from
+        * handle_level_irq() with the irq descriptor lock held, because
+        * calling opal_handle_events() would call generic_handle_irq() and
+        * then handle_level_irq() which would try to take the descriptor lock
+        * again. Instead queue the events for later.
+        */
        if (last_outstanding_events & opal_event_irqchip.mask)
                /* Need to retrigger the interrupt */
                irq_work_queue(&opal_event_irq_work);
@@ -96,29 +131,6 @@ static int opal_event_map(struct irq_domain *d, unsigned int irq,
        return 0;
 }
 
-void opal_handle_events(uint64_t events)
-{
-       int virq, hwirq = 0;
-       u64 mask = opal_event_irqchip.mask;
-
-       if (!in_irq() && (events & mask)) {
-               last_outstanding_events = events;
-               irq_work_queue(&opal_event_irq_work);
-               return;
-       }
-
-       while (events & mask) {
-               hwirq = fls64(events) - 1;
-               if (BIT_ULL(hwirq) & mask) {
-                       virq = irq_find_mapping(opal_event_irqchip.domain,
-                                               hwirq);
-                       if (virq)
-                               generic_handle_irq(virq);
-               }
-               events &= ~BIT_ULL(hwirq);
-       }
-}
-
 static irqreturn_t opal_interrupt(int irq, void *data)
 {
        __be64 events;
@@ -131,7 +143,7 @@ static irqreturn_t opal_interrupt(int irq, void *data)
 
 static void opal_handle_irq_work(struct irq_work *work)
 {
-       opal_handle_events(be64_to_cpu(last_outstanding_events));
+       opal_handle_events(last_outstanding_events);
 }
 
 static int opal_event_match(struct irq_domain *h, struct device_node *node,
index 4296d55e88f30afa7cb91fd54d06e6b2a532d577..57cffb80bc36a85d975dc993235c02efda1d7be8 100644 (file)
@@ -278,7 +278,7 @@ static void opal_handle_message(void)
 
        /* Sanity check */
        if (type >= OPAL_MSG_TYPE_MAX) {
-               pr_warning("%s: Unknown message type: %u\n", __func__, type);
+               pr_warn_once("%s: Unknown message type: %u\n", __func__, type);
                return;
        }
        opal_message_do_notify(type, (void *)&msg);
index 0c5d8ee657f06ecf8537f11ed93e4ecd6e04ee82..d1e7b0a0feeb72649ae71ab8413c7693d022e24c 100644 (file)
@@ -312,6 +312,7 @@ extern void css_schedule_reprobe(void);
 extern void reipl_ccw_dev(struct ccw_dev_id *id);
 
 struct cio_iplinfo {
+       u8 ssid;
        u16 devno;
        int is_qdio;
 };
index 3ad48f22de78c2d846254035c815a3c547d9a595..bab6739a1154e1fd9827ff8dfb5c152ef52f3930 100644 (file)
@@ -206,9 +206,16 @@ do {                                                               \
 } while (0)
 #endif /* CONFIG_COMPAT */
 
-extern unsigned long mmap_rnd_mask;
-
-#define STACK_RND_MASK (test_thread_flag(TIF_31BIT) ? 0x7ff : mmap_rnd_mask)
+/*
+ * Cache aliasing on the latest machines calls for a mapping granularity
+ * of 512KB. For 64-bit processes use a 512KB alignment and a randomization
+ * of up to 1GB. For 31-bit processes the virtual address space is limited,
+ * use no alignment and limit the randomization to 8MB.
+ */
+#define BRK_RND_MASK   (is_32bit_task() ? 0x7ffUL : 0x3ffffUL)
+#define MMAP_RND_MASK  (is_32bit_task() ? 0x7ffUL : 0x3ff80UL)
+#define MMAP_ALIGN_MASK        (is_32bit_task() ? 0 : 0x7fUL)
+#define STACK_RND_MASK MMAP_RND_MASK
 
 #define ARCH_DLINFO                                                        \
 do {                                                                       \
index 39ae6a3597478117e1c6328382e034a59b527c77..86634e71b69f4ec880c9c237d51b1626a69148b0 100644 (file)
@@ -64,7 +64,8 @@ struct ipl_block_fcp {
 
 struct ipl_block_ccw {
        u8  reserved1[84];
-       u8  reserved2[2];
+       u16 reserved2 : 13;
+       u8  ssid : 3;
        u16 devno;
        u8  vm_flags;
        u8  reserved3[3];
index 7a7abf1a5537242746b079bfb57dfe555a1e6b33..1aac41e83ea197121c5dd178c587323f9b875aa1 100644 (file)
@@ -195,5 +195,7 @@ void zpci_dma_exit_device(struct zpci_dev *);
 void dma_free_seg_table(unsigned long);
 unsigned long *dma_alloc_cpu_table(void);
 void dma_cleanup_tables(unsigned long *);
-void dma_update_cpu_trans(unsigned long *, void *, dma_addr_t, int);
+unsigned long *dma_walk_cpu_trans(unsigned long *rto, dma_addr_t dma_addr);
+void dma_update_cpu_trans(unsigned long *entry, void *page_addr, int flags);
+
 #endif
index 776f307960cc877a80edda1e41f5ed6f1d94a6c4..cc6cfe7889da5351057c1f036b5ca293a0f8bffa 100644 (file)
@@ -19,7 +19,7 @@
 #define TRACE_INCLUDE_PATH asm/trace
 #define TRACE_INCLUDE_FILE diag
 
-TRACE_EVENT(diagnose,
+TRACE_EVENT(s390_diagnose,
        TP_PROTO(unsigned short nr),
        TP_ARGS(nr),
        TP_STRUCT__entry(
@@ -32,9 +32,9 @@ TRACE_EVENT(diagnose,
 );
 
 #ifdef CONFIG_TRACEPOINTS
-void trace_diagnose_norecursion(int diag_nr);
+void trace_s390_diagnose_norecursion(int diag_nr);
 #else
-static inline void trace_diagnose_norecursion(int diag_nr) { }
+static inline void trace_s390_diagnose_norecursion(int diag_nr) { }
 #endif
 
 #endif /* _TRACE_S390_DIAG_H */
index a848adba1504a1c9b758d55ef3b44ee07bc74471..34ec202472c6cadb5b973b54c6c995bb6d2e897c 100644 (file)
 #define __NR_set_tid_address   252
 #define __NR_fadvise64         253
 #define __NR_timer_create      254
-#define __NR_timer_settime     (__NR_timer_create+1)
-#define __NR_timer_gettime     (__NR_timer_create+2)
-#define __NR_timer_getoverrun  (__NR_timer_create+3)
-#define __NR_timer_delete      (__NR_timer_create+4)
-#define __NR_clock_settime     (__NR_timer_create+5)
-#define __NR_clock_gettime     (__NR_timer_create+6)
-#define __NR_clock_getres      (__NR_timer_create+7)
-#define __NR_clock_nanosleep   (__NR_timer_create+8)
+#define __NR_timer_settime     255
+#define __NR_timer_gettime     256
+#define __NR_timer_getoverrun  257
+#define __NR_timer_delete      258
+#define __NR_clock_settime     259
+#define __NR_clock_gettime     260
+#define __NR_clock_getres      261
+#define __NR_clock_nanosleep   262
 /* Number 263 is reserved for vserver */
 #define __NR_statfs64          265
 #define __NR_fstatfs64         266
 #define __NR_recvfrom          371
 #define __NR_recvmsg           372
 #define __NR_shutdown          373
-#define NR_syscalls 374
+#define __NR_mlock2            374
+#define NR_syscalls 375
 
 /* 
  * There are some system calls that are not present on 64 bit, some
index 09f194052df35f712cff3fe8f44639df9de6c9e1..fac4eeddef91fe3acb21e0108069f3f3a70ef72a 100644 (file)
@@ -176,3 +176,4 @@ COMPAT_SYSCALL_WRAP4(accept4, int, fd, struct sockaddr __user *, upeer_sockaddr,
 COMPAT_SYSCALL_WRAP3(getsockname, int, fd, struct sockaddr __user *, usockaddr, int __user *, usockaddr_len);
 COMPAT_SYSCALL_WRAP3(getpeername, int, fd, struct sockaddr __user *, usockaddr, int __user *, usockaddr_len);
 COMPAT_SYSCALL_WRAP6(sendto, int, fd, void __user *, buff, size_t, len, unsigned int, flags, struct sockaddr __user *, addr, int, addr_len);
+COMPAT_SYSCALL_WRAP3(mlock2, unsigned long, start, size_t, len, int, flags);
index f98766ede4e156e83dc222194ed677150b891c64..48b37b8357e6838dd213f230eaaf274027193b74 100644 (file)
@@ -121,14 +121,14 @@ device_initcall(show_diag_stat_init);
 void diag_stat_inc(enum diag_stat_enum nr)
 {
        this_cpu_inc(diag_stat.counter[nr]);
-       trace_diagnose(diag_map[nr].code);
+       trace_s390_diagnose(diag_map[nr].code);
 }
 EXPORT_SYMBOL(diag_stat_inc);
 
 void diag_stat_inc_norecursion(enum diag_stat_enum nr)
 {
        this_cpu_inc(diag_stat.counter[nr]);
-       trace_diagnose_norecursion(diag_map[nr].code);
+       trace_s390_diagnose_norecursion(diag_map[nr].code);
 }
 EXPORT_SYMBOL(diag_stat_inc_norecursion);
 
index 8140d10c67850902d9f60c967000dff7bdcd26a7..6e72961608f0d42f800a4f57b15d08c8456a38ab 100644 (file)
@@ -1920,16 +1920,23 @@ static int print_insn(char *buffer, unsigned char *code, unsigned long addr)
                        }
                        if (separator)
                                ptr += sprintf(ptr, "%c", separator);
+                       /*
+                        * Use four '%' characters below because of the
+                        * following two conversions:
+                        *
+                        *  1) sprintf: %%%%r -> %%r
+                        *  2) printk : %%r   -> %r
+                        */
                        if (operand->flags & OPERAND_GPR)
-                               ptr += sprintf(ptr, "%%r%i", value);
+                               ptr += sprintf(ptr, "%%%%r%i", value);
                        else if (operand->flags & OPERAND_FPR)
-                               ptr += sprintf(ptr, "%%f%i", value);
+                               ptr += sprintf(ptr, "%%%%f%i", value);
                        else if (operand->flags & OPERAND_AR)
-                               ptr += sprintf(ptr, "%%a%i", value);
+                               ptr += sprintf(ptr, "%%%%a%i", value);
                        else if (operand->flags & OPERAND_CR)
-                               ptr += sprintf(ptr, "%%c%i", value);
+                               ptr += sprintf(ptr, "%%%%c%i", value);
                        else if (operand->flags & OPERAND_VR)
-                               ptr += sprintf(ptr, "%%v%i", value);
+                               ptr += sprintf(ptr, "%%%%v%i", value);
                        else if (operand->flags & OPERAND_PCREL)
                                ptr += sprintf(ptr, "%lx", (signed int) value
                                                                      + addr);
index 1255c6c5353e2404f065545e557fe216e109b127..301ee9c70688b7ef35db09a62c9b8f3524ed5e68 100644 (file)
@@ -26,6 +26,7 @@
 #include <asm/asm-offsets.h>
 #include <asm/thread_info.h>
 #include <asm/page.h>
+#include <asm/ptrace.h>
 
 #define ARCH_OFFSET    4
 
@@ -59,19 +60,6 @@ __HEAD
        .long   0x020006e0,0x20000050
 
        .org    0x200
-#
-# subroutine to set architecture mode
-#
-.Lsetmode:
-       mvi     __LC_AR_MODE_ID,1       # set esame flag
-       slr     %r0,%r0                 # set cpuid to zero
-       lhi     %r1,2                   # mode 2 = esame (dump)
-       sigp    %r1,%r0,0x12            # switch to esame mode
-       bras    %r13,0f
-       .fill   16,4,0x0
-0:     lmh     %r0,%r15,0(%r13)        # clear high-order half of gprs
-       sam31                           # switch to 31 bit addressing mode
-       br      %r14
 
 #
 # subroutine to wait for end I/O
@@ -159,7 +147,14 @@ __HEAD
        .long   0x02200050,0x00000000
 
 iplstart:
-       bas     %r14,.Lsetmode          # Immediately switch to 64 bit mode
+       mvi     __LC_AR_MODE_ID,1       # set esame flag
+       slr     %r0,%r0                 # set cpuid to zero
+       lhi     %r1,2                   # mode 2 = esame (dump)
+       sigp    %r1,%r0,0x12            # switch to esame mode
+       bras    %r13,0f
+       .fill   16,4,0x0
+0:     lmh     %r0,%r15,0(%r13)        # clear high-order half of gprs
+       sam31                           # switch to 31 bit addressing mode
        lh      %r1,0xb8                # test if subchannel number
        bct     %r1,.Lnoload            #  is valid
        l       %r1,0xb8                # load ipl subchannel number
@@ -268,71 +263,6 @@ iplstart:
        .align  8
 .Lcpuid:.fill  8,1,0
 
-#
-# SALIPL loader support. Based on a patch by Rob van der Heij.
-# This entry point is called directly from the SALIPL loader and
-# doesn't need a builtin ipl record.
-#
-       .org    0x800
-ENTRY(start)
-       stm     %r0,%r15,0x07b0         # store registers
-       bas     %r14,.Lsetmode          # Immediately switch to 64 bit mode
-       basr    %r12,%r0
-.base:
-       l       %r11,.parm
-       l       %r8,.cmd                # pointer to command buffer
-
-       ltr     %r9,%r9                 # do we have SALIPL parameters?
-       bp      .sk8x8
-
-       mvc     0(64,%r8),0x00b0        # copy saved registers
-       xc      64(240-64,%r8),0(%r8)   # remainder of buffer
-       tr      0(64,%r8),.lowcase
-       b       .gotr
-.sk8x8:
-       mvc     0(240,%r8),0(%r9)       # copy iplparms into buffer
-.gotr:
-       slr     %r0,%r0
-       st      %r0,INITRD_SIZE+ARCH_OFFSET-PARMAREA(%r11)
-       st      %r0,INITRD_START+ARCH_OFFSET-PARMAREA(%r11)
-       j       startup                 # continue with startup
-.cmd:  .long   COMMAND_LINE            # address of command line buffer
-.parm: .long   PARMAREA
-.lowcase:
-       .byte 0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07
-       .byte 0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f
-       .byte 0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17
-       .byte 0x18,0x19,0x1a,0x1b,0x1c,0x1d,0x1e,0x1f
-       .byte 0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27
-       .byte 0x28,0x29,0x2a,0x2b,0x2c,0x2d,0x2e,0x2f
-       .byte 0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37
-       .byte 0x38,0x39,0x3a,0x3b,0x3c,0x3d,0x3e,0x3f
-       .byte 0x40,0x41,0x42,0x43,0x44,0x45,0x46,0x47
-       .byte 0x48,0x49,0x4a,0x4b,0x4c,0x4d,0x4e,0x4f
-       .byte 0x50,0x51,0x52,0x53,0x54,0x55,0x56,0x57
-       .byte 0x58,0x59,0x5a,0x5b,0x5c,0x5d,0x5e,0x5f
-       .byte 0x60,0x61,0x62,0x63,0x64,0x65,0x66,0x67
-       .byte 0x68,0x69,0x6a,0x6b,0x6c,0x6d,0x6e,0x6f
-       .byte 0x70,0x71,0x72,0x73,0x74,0x75,0x76,0x77
-       .byte 0x78,0x79,0x7a,0x7b,0x7c,0x7d,0x7e,0x7f
-
-       .byte 0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87
-       .byte 0x88,0x89,0x8a,0x8b,0x8c,0x8d,0x8e,0x8f
-       .byte 0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97
-       .byte 0x98,0x99,0x9a,0x9b,0x9c,0x9d,0x9e,0x9f
-       .byte 0xa0,0xa1,0xa2,0xa3,0xa4,0xa5,0xa6,0xa7
-       .byte 0xa8,0xa9,0xaa,0xab,0xac,0xad,0xae,0xaf
-       .byte 0xb0,0xb1,0xb2,0xb3,0xb4,0xb5,0xb6,0xb7
-       .byte 0xb8,0xb9,0xba,0xbb,0xbc,0xbd,0xbe,0xbf
-       .byte 0xc0,0x81,0x82,0x83,0x84,0x85,0x86,0x87   # .abcdefg
-       .byte 0x88,0x89,0xca,0xcb,0xcc,0xcd,0xce,0xcf   # hi
-       .byte 0xd0,0x91,0x92,0x93,0x94,0x95,0x96,0x97   # .jklmnop
-       .byte 0x98,0x99,0xda,0xdb,0xdc,0xdd,0xde,0xdf   # qr
-       .byte 0xe0,0xe1,0xa2,0xa3,0xa4,0xa5,0xa6,0xa7   # ..stuvwx
-       .byte 0xa8,0xa9,0xea,0xeb,0xec,0xed,0xee,0xef   # yz
-       .byte 0xf0,0xf1,0xf2,0xf3,0xf4,0xf5,0xf6,0xf7
-       .byte 0xf8,0xf9,0xfa,0xfb,0xfc,0xfd,0xfe,0xff
-
 #
 # startup-code at 0x10000, running in absolute addressing mode
 # this is called either by the ipl loader or directly by PSW restart
@@ -364,7 +294,7 @@ ENTRY(startup_kdump)
        bras    %r13,0f
        .fill   16,4,0x0
 0:     lmh     %r0,%r15,0(%r13)        # clear high-order half of gprs
-       sam31                           # switch to 31 bit addressing mode
+       sam64                           # switch to 64 bit addressing mode
        basr    %r13,0                  # get base
 .LPG0:
        xc      0x200(256),0x200        # partially clear lowcore
@@ -395,7 +325,7 @@ ENTRY(startup_kdump)
        jnz     1b
        j       4f
 2:     l       %r15,.Lstack-.LPG0(%r13)
-       ahi     %r15,-96
+       ahi     %r15,-STACK_FRAME_OVERHEAD
        la      %r2,.Lals_string-.LPG0(%r13)
        l       %r3,.Lsclp_print-.LPG0(%r13)
        basr    %r14,%r3
@@ -429,8 +359,7 @@ ENTRY(startup_kdump)
        .long 1, 0xc0000000
 #endif
 4:
-       /* Continue with 64bit startup code in head64.S */
-       sam64                           # switch to 64 bit mode
+       /* Continue with startup code in head64.S */
        jg      startup_continue
 
        .align  8
index f6d8acd7e13654c307a5d54e80bd6e084cf04a13..b1f0a90f933bbc95cc04c9e028d87865555909a9 100644 (file)
@@ -121,6 +121,7 @@ static char *dump_type_str(enum dump_type type)
  * Must be in data section since the bss section
  * is not cleared when these are accessed.
  */
+static u8 ipl_ssid __attribute__((__section__(".data"))) = 0;
 static u16 ipl_devno __attribute__((__section__(".data"))) = 0;
 u32 ipl_flags __attribute__((__section__(".data"))) = 0;
 
@@ -197,6 +198,33 @@ static ssize_t sys_##_prefix##_##_name##_show(struct kobject *kobj,        \
        return snprintf(page, PAGE_SIZE, _format, ##args);              \
 }
 
+#define IPL_ATTR_CCW_STORE_FN(_prefix, _name, _ipl_blk)                        \
+static ssize_t sys_##_prefix##_##_name##_store(struct kobject *kobj,   \
+               struct kobj_attribute *attr,                            \
+               const char *buf, size_t len)                            \
+{                                                                      \
+       unsigned long long ssid, devno;                                 \
+                                                                       \
+       if (sscanf(buf, "0.%llx.%llx\n", &ssid, &devno) != 2)           \
+               return -EINVAL;                                         \
+                                                                       \
+       if (ssid > __MAX_SSID || devno > __MAX_SUBCHANNEL)              \
+               return -EINVAL;                                         \
+                                                                       \
+       _ipl_blk.ssid = ssid;                                           \
+       _ipl_blk.devno = devno;                                         \
+       return len;                                                     \
+}
+
+#define DEFINE_IPL_CCW_ATTR_RW(_prefix, _name, _ipl_blk)               \
+IPL_ATTR_SHOW_FN(_prefix, _name, "0.%x.%04x\n",                                \
+                _ipl_blk.ssid, _ipl_blk.devno);                        \
+IPL_ATTR_CCW_STORE_FN(_prefix, _name, _ipl_blk);                       \
+static struct kobj_attribute sys_##_prefix##_##_name##_attr =          \
+       __ATTR(_name, (S_IRUGO | S_IWUSR),                              \
+              sys_##_prefix##_##_name##_show,                          \
+              sys_##_prefix##_##_name##_store)                         \
+
 #define DEFINE_IPL_ATTR_RO(_prefix, _name, _format, _value)            \
 IPL_ATTR_SHOW_FN(_prefix, _name, _format, _value)                      \
 static struct kobj_attribute sys_##_prefix##_##_name##_attr =          \
@@ -395,7 +423,7 @@ static ssize_t sys_ipl_device_show(struct kobject *kobj,
 
        switch (ipl_info.type) {
        case IPL_TYPE_CCW:
-               return sprintf(page, "0.0.%04x\n", ipl_devno);
+               return sprintf(page, "0.%x.%04x\n", ipl_ssid, ipl_devno);
        case IPL_TYPE_FCP:
        case IPL_TYPE_FCP_DUMP:
                return sprintf(page, "0.0.%04x\n", ipl->ipl_info.fcp.devno);
@@ -687,21 +715,14 @@ static ssize_t reipl_fcp_scpdata_write(struct file *filp, struct kobject *kobj,
                                       struct bin_attribute *attr,
                                       char *buf, loff_t off, size_t count)
 {
+       size_t scpdata_len = count;
        size_t padding;
-       size_t scpdata_len;
-
-       if (off < 0)
-               return -EINVAL;
 
-       if (off >= DIAG308_SCPDATA_SIZE)
-               return -ENOSPC;
 
-       if (count > DIAG308_SCPDATA_SIZE - off)
-               count = DIAG308_SCPDATA_SIZE - off;
-
-       memcpy(reipl_block_fcp->ipl_info.fcp.scp_data, buf + off, count);
-       scpdata_len = off + count;
+       if (off)
+               return -EINVAL;
 
+       memcpy(reipl_block_fcp->ipl_info.fcp.scp_data, buf, count);
        if (scpdata_len % 8) {
                padding = 8 - (scpdata_len % 8);
                memset(reipl_block_fcp->ipl_info.fcp.scp_data + scpdata_len,
@@ -717,7 +738,7 @@ static ssize_t reipl_fcp_scpdata_write(struct file *filp, struct kobject *kobj,
 }
 static struct bin_attribute sys_reipl_fcp_scp_data_attr =
        __BIN_ATTR(scp_data, (S_IRUGO | S_IWUSR), reipl_fcp_scpdata_read,
-                  reipl_fcp_scpdata_write, PAGE_SIZE);
+                  reipl_fcp_scpdata_write, DIAG308_SCPDATA_SIZE);
 
 static struct bin_attribute *reipl_fcp_bin_attrs[] = {
        &sys_reipl_fcp_scp_data_attr,
@@ -814,9 +835,7 @@ static struct attribute_group reipl_fcp_attr_group = {
 };
 
 /* CCW reipl device attributes */
-
-DEFINE_IPL_ATTR_RW(reipl_ccw, device, "0.0.%04llx\n", "0.0.%llx\n",
-       reipl_block_ccw->ipl_info.ccw.devno);
+DEFINE_IPL_CCW_ATTR_RW(reipl_ccw, device, reipl_block_ccw->ipl_info.ccw);
 
 /* NSS wrapper */
 static ssize_t reipl_nss_loadparm_show(struct kobject *kobj,
@@ -1056,8 +1075,8 @@ static void __reipl_run(void *unused)
 
        switch (reipl_method) {
        case REIPL_METHOD_CCW_CIO:
+               devid.ssid  = reipl_block_ccw->ipl_info.ccw.ssid;
                devid.devno = reipl_block_ccw->ipl_info.ccw.devno;
-               devid.ssid  = 0;
                reipl_ccw_dev(&devid);
                break;
        case REIPL_METHOD_CCW_VM:
@@ -1192,6 +1211,7 @@ static int __init reipl_ccw_init(void)
 
        reipl_block_ccw_init(reipl_block_ccw);
        if (ipl_info.type == IPL_TYPE_CCW) {
+               reipl_block_ccw->ipl_info.ccw.ssid = ipl_ssid;
                reipl_block_ccw->ipl_info.ccw.devno = ipl_devno;
                reipl_block_ccw_fill_parms(reipl_block_ccw);
        }
@@ -1336,9 +1356,7 @@ static struct attribute_group dump_fcp_attr_group = {
 };
 
 /* CCW dump device attributes */
-
-DEFINE_IPL_ATTR_RW(dump_ccw, device, "0.0.%04llx\n", "0.0.%llx\n",
-                  dump_block_ccw->ipl_info.ccw.devno);
+DEFINE_IPL_CCW_ATTR_RW(dump_ccw, device, dump_block_ccw->ipl_info.ccw);
 
 static struct attribute *dump_ccw_attrs[] = {
        &sys_dump_ccw_device_attr.attr,
@@ -1418,8 +1436,8 @@ static void __dump_run(void *unused)
 
        switch (dump_method) {
        case DUMP_METHOD_CCW_CIO:
+               devid.ssid  = dump_block_ccw->ipl_info.ccw.ssid;
                devid.devno = dump_block_ccw->ipl_info.ccw.devno;
-               devid.ssid  = 0;
                reipl_ccw_dev(&devid);
                break;
        case DUMP_METHOD_CCW_VM:
@@ -1939,14 +1957,14 @@ void __init setup_ipl(void)
        ipl_info.type = get_ipl_type();
        switch (ipl_info.type) {
        case IPL_TYPE_CCW:
+               ipl_info.data.ccw.dev_id.ssid = ipl_ssid;
                ipl_info.data.ccw.dev_id.devno = ipl_devno;
-               ipl_info.data.ccw.dev_id.ssid = 0;
                break;
        case IPL_TYPE_FCP:
        case IPL_TYPE_FCP_DUMP:
+               ipl_info.data.fcp.dev_id.ssid = 0;
                ipl_info.data.fcp.dev_id.devno =
                        IPL_PARMBLOCK_START->ipl_info.fcp.devno;
-               ipl_info.data.fcp.dev_id.ssid = 0;
                ipl_info.data.fcp.wwpn = IPL_PARMBLOCK_START->ipl_info.fcp.wwpn;
                ipl_info.data.fcp.lun = IPL_PARMBLOCK_START->ipl_info.fcp.lun;
                break;
@@ -1978,6 +1996,7 @@ void __init ipl_save_parameters(void)
        if (cio_get_iplinfo(&iplinfo))
                return;
 
+       ipl_ssid = iplinfo.ssid;
        ipl_devno = iplinfo.devno;
        ipl_flags |= IPL_DEVNO_VALID;
        if (!iplinfo.is_qdio)
index 688a3aad9c79d02a49702f729c3b418065c982e3..114ee8b96f17d31d5dba657c704bc34a2e1b9a9e 100644 (file)
@@ -243,11 +243,7 @@ unsigned long arch_align_stack(unsigned long sp)
 
 static inline unsigned long brk_rnd(void)
 {
-       /* 8MB for 32bit, 1GB for 64bit */
-       if (is_32bit_task())
-               return (get_random_int() & 0x7ffUL) << PAGE_SHIFT;
-       else
-               return (get_random_int() & 0x3ffffUL) << PAGE_SHIFT;
+       return (get_random_int() & BRK_RND_MASK) << PAGE_SHIFT;
 }
 
 unsigned long arch_randomize_brk(struct mm_struct *mm)
index fa0bdff1d41305cb61fdc160d381a509ec4a53b7..9fe7781a45cdd7717e4a65af365f1a24d69812da 100644 (file)
@@ -21,7 +21,7 @@ static void _sclp_wait_int(void)
        __ctl_load(cr0_new, 0, 0);
 
        psw_ext_save = S390_lowcore.external_new_psw;
-       psw_mask = __extract_psw() & (PSW_MASK_EA | PSW_MASK_BA);
+       psw_mask = __extract_psw();
        S390_lowcore.external_new_psw.mask = psw_mask;
        psw_wait.mask = psw_mask | PSW_MASK_EXT | PSW_MASK_WAIT;
        S390_lowcore.ext_int_code = 0;
index ce0cbd6ba7ca9e5a8ca4b0cf05b37ea2a1e5dcc0..c837bcacf2188460a50754f3a75d1b485c25f671 100644 (file)
@@ -764,9 +764,6 @@ static int __init setup_hwcaps(void)
        get_cpu_id(&cpu_id);
        add_device_randomness(&cpu_id, sizeof(cpu_id));
        switch (cpu_id.machine) {
-       case 0x9672:
-               strcpy(elf_platform, "g5");
-               break;
        case 0x2064:
        case 0x2066:
        default:        /* Use "z900" as default for 64 bit kernels. */
index 8c56929c8d826e09ccd3620454b813101cb319e7..5378c3ea1b984918ed3719c8a9cf8d1c8c86574a 100644 (file)
@@ -382,3 +382,4 @@ SYSCALL(sys_sendmsg,compat_sys_sendmsg)                     /* 370 */
 SYSCALL(sys_recvfrom,compat_sys_recvfrom)
 SYSCALL(sys_recvmsg,compat_sys_recvmsg)
 SYSCALL(sys_shutdown,sys_shutdown)
+SYSCALL(sys_mlock2,compat_sys_mlock2)
index 73239bb576c4ee8aaa69b232cdea0cbbd7f91fd0..21a5df99552bce6e4f84c872acdda43e6c5732c3 100644 (file)
@@ -9,11 +9,11 @@
 #define CREATE_TRACE_POINTS
 #include <asm/trace/diag.h>
 
-EXPORT_TRACEPOINT_SYMBOL(diagnose);
+EXPORT_TRACEPOINT_SYMBOL(s390_diagnose);
 
 static DEFINE_PER_CPU(unsigned int, diagnose_trace_depth);
 
-void trace_diagnose_norecursion(int diag_nr)
+void trace_s390_diagnose_norecursion(int diag_nr)
 {
        unsigned long flags;
        unsigned int *depth;
@@ -22,7 +22,7 @@ void trace_diagnose_norecursion(int diag_nr)
        depth = this_cpu_ptr(&diagnose_trace_depth);
        if (*depth == 0) {
                (*depth)++;
-               trace_diagnose(diag_nr);
+               trace_s390_diagnose(diag_nr);
                (*depth)--;
        }
        local_irq_restore(flags);
index 373e32346d68d6c3ae270ca39b96b09fe66b0a6e..6a75352f453c1a46775112c2749b8cff31d62ed1 100644 (file)
@@ -1030,8 +1030,7 @@ static int __inject_extcall(struct kvm_vcpu *vcpu, struct kvm_s390_irq *irq)
                                   src_id, 0);
 
        /* sending vcpu invalid */
-       if (src_id >= KVM_MAX_VCPUS ||
-           kvm_get_vcpu(vcpu->kvm, src_id) == NULL)
+       if (kvm_get_vcpu_by_id(vcpu->kvm, src_id) == NULL)
                return -EINVAL;
 
        if (sclp.has_sigpif)
@@ -1110,6 +1109,10 @@ static int __inject_sigp_emergency(struct kvm_vcpu *vcpu,
        trace_kvm_s390_inject_vcpu(vcpu->vcpu_id, KVM_S390_INT_EMERGENCY,
                                   irq->u.emerg.code, 0);
 
+       /* sending vcpu invalid */
+       if (kvm_get_vcpu_by_id(vcpu->kvm, irq->u.emerg.code) == NULL)
+               return -EINVAL;
+
        set_bit(irq->u.emerg.code, li->sigp_emerg_pending);
        set_bit(IRQ_PEND_EXT_EMERGENCY, &li->pending_irqs);
        atomic_or(CPUSTAT_EXT_INT, li->cpuflags);
index 8fe2f1c722dcabe22b3b3731bdce5e22092703db..846589281b046f414837cbd3f7ab9f4d0c675a51 100644 (file)
@@ -342,12 +342,16 @@ static int kvm_vm_ioctl_enable_cap(struct kvm *kvm, struct kvm_enable_cap *cap)
                r = 0;
                break;
        case KVM_CAP_S390_VECTOR_REGISTERS:
-               if (MACHINE_HAS_VX) {
+               mutex_lock(&kvm->lock);
+               if (atomic_read(&kvm->online_vcpus)) {
+                       r = -EBUSY;
+               } else if (MACHINE_HAS_VX) {
                        set_kvm_facility(kvm->arch.model.fac->mask, 129);
                        set_kvm_facility(kvm->arch.model.fac->list, 129);
                        r = 0;
                } else
                        r = -EINVAL;
+               mutex_unlock(&kvm->lock);
                VM_EVENT(kvm, 3, "ENABLE: CAP_S390_VECTOR_REGISTERS %s",
                         r ? "(not available)" : "(success)");
                break;
index 77191b85ea7af4dd96dc6a1ae819f27faa25233b..d76b51cb4b6207261e495bad832ec07444ec11a5 100644 (file)
@@ -660,7 +660,7 @@ static int handle_pfmf(struct kvm_vcpu *vcpu)
 
        kvm_s390_get_regs_rre(vcpu, &reg1, &reg2);
 
-       if (!MACHINE_HAS_PFMF)
+       if (!test_kvm_facility(vcpu->kvm, 8))
                return kvm_s390_inject_program_int(vcpu, PGM_OPERATION);
 
        if (vcpu->arch.sie_block->gpsw.mask & PSW_MASK_PSTATE)
index da690b69f9fe17a89c3f1dc3cd1b1119b832bd25..77c22d685c7a150a8ecfdccbfca1ec60f08698af 100644 (file)
@@ -291,12 +291,8 @@ static int handle_sigp_dst(struct kvm_vcpu *vcpu, u8 order_code,
                           u16 cpu_addr, u32 parameter, u64 *status_reg)
 {
        int rc;
-       struct kvm_vcpu *dst_vcpu;
+       struct kvm_vcpu *dst_vcpu = kvm_get_vcpu_by_id(vcpu->kvm, cpu_addr);
 
-       if (cpu_addr >= KVM_MAX_VCPUS)
-               return SIGP_CC_NOT_OPERATIONAL;
-
-       dst_vcpu = kvm_get_vcpu(vcpu->kvm, cpu_addr);
        if (!dst_vcpu)
                return SIGP_CC_NOT_OPERATIONAL;
 
@@ -478,7 +474,7 @@ int kvm_s390_handle_sigp_pei(struct kvm_vcpu *vcpu)
        trace_kvm_s390_handle_sigp_pei(vcpu, order_code, cpu_addr);
 
        if (order_code == SIGP_EXTERNAL_CALL) {
-               dest_vcpu = kvm_get_vcpu(vcpu->kvm, cpu_addr);
+               dest_vcpu = kvm_get_vcpu_by_id(vcpu->kvm, cpu_addr);
                BUG_ON(dest_vcpu == NULL);
 
                kvm_s390_vcpu_wakeup(dest_vcpu);
index c3c07d3505ba17ebe953d4310508abeb6b63fba1..c722400c769784d8df6f13507693e117ad942497 100644 (file)
@@ -48,37 +48,13 @@ EXPORT_SYMBOL(zero_page_mask);
 
 static void __init setup_zero_pages(void)
 {
-       struct cpuid cpu_id;
        unsigned int order;
        struct page *page;
        int i;
 
-       get_cpu_id(&cpu_id);
-       switch (cpu_id.machine) {
-       case 0x9672:    /* g5 */
-       case 0x2064:    /* z900 */
-       case 0x2066:    /* z900 */
-       case 0x2084:    /* z990 */
-       case 0x2086:    /* z990 */
-       case 0x2094:    /* z9-109 */
-       case 0x2096:    /* z9-109 */
-               order = 0;
-               break;
-       case 0x2097:    /* z10 */
-       case 0x2098:    /* z10 */
-       case 0x2817:    /* z196 */
-       case 0x2818:    /* z196 */
-               order = 2;
-               break;
-       case 0x2827:    /* zEC12 */
-       case 0x2828:    /* zEC12 */
-               order = 5;
-               break;
-       case 0x2964:    /* z13 */
-       default:
-               order = 7;
-               break;
-       }
+       /* Latest machines require a mapping granularity of 512KB */
+       order = 7;
+
        /* Limit number of empty zero pages for small memory sizes */
        while (order > 2 && (totalram_pages >> 10) < (1UL << order))
                order--;
index 6e552af08c76a61027c023f7305133ee1b4efe02..ea01477b4aa67155f87b88e8c6a87f5374eda247 100644 (file)
@@ -31,9 +31,6 @@
 #include <linux/security.h>
 #include <asm/pgalloc.h>
 
-unsigned long mmap_rnd_mask;
-static unsigned long mmap_align_mask;
-
 static unsigned long stack_maxrandom_size(void)
 {
        if (!(current->flags & PF_RANDOMIZE))
@@ -62,10 +59,7 @@ static inline int mmap_is_legacy(void)
 
 unsigned long arch_mmap_rnd(void)
 {
-       if (is_32bit_task())
-               return (get_random_int() & 0x7ff) << PAGE_SHIFT;
-       else
-               return (get_random_int() & mmap_rnd_mask) << PAGE_SHIFT;
+       return (get_random_int() & MMAP_RND_MASK) << PAGE_SHIFT;
 }
 
 static unsigned long mmap_base_legacy(unsigned long rnd)
@@ -92,7 +86,6 @@ arch_get_unmapped_area(struct file *filp, unsigned long addr,
        struct mm_struct *mm = current->mm;
        struct vm_area_struct *vma;
        struct vm_unmapped_area_info info;
-       int do_color_align;
 
        if (len > TASK_SIZE - mmap_min_addr)
                return -ENOMEM;
@@ -108,15 +101,14 @@ arch_get_unmapped_area(struct file *filp, unsigned long addr,
                        return addr;
        }
 
-       do_color_align = 0;
-       if (filp || (flags & MAP_SHARED))
-               do_color_align = !is_32bit_task();
-
        info.flags = 0;
        info.length = len;
        info.low_limit = mm->mmap_base;
        info.high_limit = TASK_SIZE;
-       info.align_mask = do_color_align ? (mmap_align_mask << PAGE_SHIFT) : 0;
+       if (filp || (flags & MAP_SHARED))
+               info.align_mask = MMAP_ALIGN_MASK << PAGE_SHIFT;
+       else
+               info.align_mask = 0;
        info.align_offset = pgoff << PAGE_SHIFT;
        return vm_unmapped_area(&info);
 }
@@ -130,7 +122,6 @@ arch_get_unmapped_area_topdown(struct file *filp, const unsigned long addr0,
        struct mm_struct *mm = current->mm;
        unsigned long addr = addr0;
        struct vm_unmapped_area_info info;
-       int do_color_align;
 
        /* requested length too big for entire address space */
        if (len > TASK_SIZE - mmap_min_addr)
@@ -148,15 +139,14 @@ arch_get_unmapped_area_topdown(struct file *filp, const unsigned long addr0,
                        return addr;
        }
 
-       do_color_align = 0;
-       if (filp || (flags & MAP_SHARED))
-               do_color_align = !is_32bit_task();
-
        info.flags = VM_UNMAPPED_AREA_TOPDOWN;
        info.length = len;
        info.low_limit = max(PAGE_SIZE, mmap_min_addr);
        info.high_limit = mm->mmap_base;
-       info.align_mask = do_color_align ? (mmap_align_mask << PAGE_SHIFT) : 0;
+       if (filp || (flags & MAP_SHARED))
+               info.align_mask = MMAP_ALIGN_MASK << PAGE_SHIFT;
+       else
+               info.align_mask = 0;
        info.align_offset = pgoff << PAGE_SHIFT;
        addr = vm_unmapped_area(&info);
 
@@ -254,35 +244,3 @@ void arch_pick_mmap_layout(struct mm_struct *mm)
                mm->get_unmapped_area = s390_get_unmapped_area_topdown;
        }
 }
-
-static int __init setup_mmap_rnd(void)
-{
-       struct cpuid cpu_id;
-
-       get_cpu_id(&cpu_id);
-       switch (cpu_id.machine) {
-       case 0x9672:
-       case 0x2064:
-       case 0x2066:
-       case 0x2084:
-       case 0x2086:
-       case 0x2094:
-       case 0x2096:
-       case 0x2097:
-       case 0x2098:
-       case 0x2817:
-       case 0x2818:
-       case 0x2827:
-       case 0x2828:
-               mmap_rnd_mask = 0x7ffUL;
-               mmap_align_mask = 0UL;
-               break;
-       case 0x2964:    /* z13 */
-       default:
-               mmap_rnd_mask = 0x3ff80UL;
-               mmap_align_mask = 0x7fUL;
-               break;
-       }
-       return 0;
-}
-early_initcall(setup_mmap_rnd);
index 37d10f74425a453202ae11e232d361404e9e68c2..d348f2c09a1eede659378cf4ae2686df008e4bd8 100644 (file)
@@ -33,7 +33,7 @@ unsigned long *dma_alloc_cpu_table(void)
                return NULL;
 
        for (entry = table; entry < table + ZPCI_TABLE_ENTRIES; entry++)
-               *entry = ZPCI_TABLE_INVALID | ZPCI_TABLE_PROTECTED;
+               *entry = ZPCI_TABLE_INVALID;
        return table;
 }
 
@@ -51,7 +51,7 @@ static unsigned long *dma_alloc_page_table(void)
                return NULL;
 
        for (entry = table; entry < table + ZPCI_PT_ENTRIES; entry++)
-               *entry = ZPCI_PTE_INVALID | ZPCI_TABLE_PROTECTED;
+               *entry = ZPCI_PTE_INVALID;
        return table;
 }
 
@@ -95,7 +95,7 @@ static unsigned long *dma_get_page_table_origin(unsigned long *entry)
        return pto;
 }
 
-static unsigned long *dma_walk_cpu_trans(unsigned long *rto, dma_addr_t dma_addr)
+unsigned long *dma_walk_cpu_trans(unsigned long *rto, dma_addr_t dma_addr)
 {
        unsigned long *sto, *pto;
        unsigned int rtx, sx, px;
@@ -114,20 +114,10 @@ static unsigned long *dma_walk_cpu_trans(unsigned long *rto, dma_addr_t dma_addr
        return &pto[px];
 }
 
-void dma_update_cpu_trans(unsigned long *dma_table, void *page_addr,
-                         dma_addr_t dma_addr, int flags)
+void dma_update_cpu_trans(unsigned long *entry, void *page_addr, int flags)
 {
-       unsigned long *entry;
-
-       entry = dma_walk_cpu_trans(dma_table, dma_addr);
-       if (!entry) {
-               WARN_ON_ONCE(1);
-               return;
-       }
-
        if (flags & ZPCI_PTE_INVALID) {
                invalidate_pt_entry(entry);
-               return;
        } else {
                set_pt_pfaa(entry, page_addr);
                validate_pt_entry(entry);
@@ -146,18 +136,25 @@ static int dma_update_trans(struct zpci_dev *zdev, unsigned long pa,
        u8 *page_addr = (u8 *) (pa & PAGE_MASK);
        dma_addr_t start_dma_addr = dma_addr;
        unsigned long irq_flags;
+       unsigned long *entry;
        int i, rc = 0;
 
        if (!nr_pages)
                return -EINVAL;
 
        spin_lock_irqsave(&zdev->dma_table_lock, irq_flags);
-       if (!zdev->dma_table)
+       if (!zdev->dma_table) {
+               rc = -EINVAL;
                goto no_refresh;
+       }
 
        for (i = 0; i < nr_pages; i++) {
-               dma_update_cpu_trans(zdev->dma_table, page_addr, dma_addr,
-                                    flags);
+               entry = dma_walk_cpu_trans(zdev->dma_table, dma_addr);
+               if (!entry) {
+                       rc = -ENOMEM;
+                       goto undo_cpu_trans;
+               }
+               dma_update_cpu_trans(entry, page_addr, flags);
                page_addr += PAGE_SIZE;
                dma_addr += PAGE_SIZE;
        }
@@ -176,6 +173,18 @@ static int dma_update_trans(struct zpci_dev *zdev, unsigned long pa,
 
        rc = zpci_refresh_trans((u64) zdev->fh << 32, start_dma_addr,
                                nr_pages * PAGE_SIZE);
+undo_cpu_trans:
+       if (rc && ((flags & ZPCI_PTE_VALID_MASK) == ZPCI_PTE_VALID)) {
+               flags = ZPCI_PTE_INVALID;
+               while (i-- > 0) {
+                       page_addr -= PAGE_SIZE;
+                       dma_addr -= PAGE_SIZE;
+                       entry = dma_walk_cpu_trans(zdev->dma_table, dma_addr);
+                       if (!entry)
+                               break;
+                       dma_update_cpu_trans(entry, page_addr, flags);
+               }
+       }
 
 no_refresh:
        spin_unlock_irqrestore(&zdev->dma_table_lock, irq_flags);
@@ -260,6 +269,16 @@ out:
        spin_unlock_irqrestore(&zdev->iommu_bitmap_lock, flags);
 }
 
+static inline void zpci_err_dma(unsigned long rc, unsigned long addr)
+{
+       struct {
+               unsigned long rc;
+               unsigned long addr;
+       } __packed data = {rc, addr};
+
+       zpci_err_hex(&data, sizeof(data));
+}
+
 static dma_addr_t s390_dma_map_pages(struct device *dev, struct page *page,
                                     unsigned long offset, size_t size,
                                     enum dma_data_direction direction,
@@ -270,33 +289,40 @@ static dma_addr_t s390_dma_map_pages(struct device *dev, struct page *page,
        unsigned long pa = page_to_phys(page) + offset;
        int flags = ZPCI_PTE_VALID;
        dma_addr_t dma_addr;
+       int ret;
 
        /* This rounds up number of pages based on size and offset */
        nr_pages = iommu_num_pages(pa, size, PAGE_SIZE);
        iommu_page_index = dma_alloc_iommu(zdev, nr_pages);
-       if (iommu_page_index == -1)
+       if (iommu_page_index == -1) {
+               ret = -ENOSPC;
                goto out_err;
+       }
 
        /* Use rounded up size */
        size = nr_pages * PAGE_SIZE;
 
        dma_addr = zdev->start_dma + iommu_page_index * PAGE_SIZE;
-       if (dma_addr + size > zdev->end_dma)
+       if (dma_addr + size > zdev->end_dma) {
+               ret = -ERANGE;
                goto out_free;
+       }
 
        if (direction == DMA_NONE || direction == DMA_TO_DEVICE)
                flags |= ZPCI_TABLE_PROTECTED;
 
-       if (!dma_update_trans(zdev, pa, dma_addr, size, flags)) {
-               atomic64_add(nr_pages, &zdev->mapped_pages);
-               return dma_addr + (offset & ~PAGE_MASK);
-       }
+       ret = dma_update_trans(zdev, pa, dma_addr, size, flags);
+       if (ret)
+               goto out_free;
+
+       atomic64_add(nr_pages, &zdev->mapped_pages);
+       return dma_addr + (offset & ~PAGE_MASK);
 
 out_free:
        dma_free_iommu(zdev, iommu_page_index, nr_pages);
 out_err:
        zpci_err("map error:\n");
-       zpci_err_hex(&pa, sizeof(pa));
+       zpci_err_dma(ret, pa);
        return DMA_ERROR_CODE;
 }
 
@@ -306,14 +332,16 @@ static void s390_dma_unmap_pages(struct device *dev, dma_addr_t dma_addr,
 {
        struct zpci_dev *zdev = to_zpci(to_pci_dev(dev));
        unsigned long iommu_page_index;
-       int npages;
+       int npages, ret;
 
        npages = iommu_num_pages(dma_addr, size, PAGE_SIZE);
        dma_addr = dma_addr & PAGE_MASK;
-       if (dma_update_trans(zdev, 0, dma_addr, npages * PAGE_SIZE,
-                            ZPCI_TABLE_PROTECTED | ZPCI_PTE_INVALID)) {
+       ret = dma_update_trans(zdev, 0, dma_addr, npages * PAGE_SIZE,
+                              ZPCI_PTE_INVALID);
+       if (ret) {
                zpci_err("unmap error:\n");
-               zpci_err_hex(&dma_addr, sizeof(dma_addr));
+               zpci_err_dma(ret, dma_addr);
+               return;
        }
 
        atomic64_add(npages, &zdev->unmapped_pages);
index e6820c86e8c7bc1c0daf34cd9a891c45b3a5775f..47ebd5b5ed55e018343e0c577eb2ca21e885bc17 100644 (file)
 #define __NR_fsetxattr         256
 #define __NR_getxattr          257
 #define __NR_lgetxattr         258
-#define __NR_fgetxattr         269
+#define __NR_fgetxattr         259
 #define __NR_listxattr         260
 #define __NR_llistxattr                261
 #define __NR_flistxattr                262
index 7cfd7f153966719c9201a66ff6043c3e48a47a93..4dca18347ee9a40949d55af11ae6adf07d05ca4b 100644 (file)
@@ -10,7 +10,7 @@
  *  Copyright (C) 2008-2009 Red Hat, Inc., Ingo Molnar
  *  Copyright (C) 2009 Jaswinder Singh Rajput
  *  Copyright (C) 2009 Advanced Micro Devices, Inc., Robert Richter
- *  Copyright (C) 2008-2009 Red Hat, Inc., Peter Zijlstra <pzijlstr@redhat.com>
+ *  Copyright (C) 2008-2009 Red Hat, Inc., Peter Zijlstra
  *  Copyright (C) 2009 Intel Corporation, <markus.t.metzger@intel.com>
  *
  * ppc:
index 370ca1e71ffbc8dc2fb4cd9567b44f95cf61eee6..93310837c2dfaa27ce384a32d2e7cec3c75c15fa 100644 (file)
@@ -95,6 +95,7 @@
  * really available.  So we simply advertise only "crypto" support.
  */
 #define HWCAP_SPARC_CRYPTO     0x04000000 /* CRYPTO insns available */
+#define HWCAP_SPARC_ADI                0x08000000 /* ADI available */
 
 #define CORE_DUMP_USE_REGSET
 
index efe9479f837bb50d289106cd22128292dd19ef5f..1c26d440d288dfb8d28579fda55e2a76ccf4c139 100644 (file)
 #define __NR_bpf               349
 #define __NR_execveat          350
 #define __NR_membarrier                351
+#define __NR_userfaultfd       352
+#define __NR_bind              353
+#define __NR_listen            354
+#define __NR_setsockopt                355
+#define __NR_mlock2            356
 
-#define NR_syscalls            352
+#define NR_syscalls            357
 
 /* Bitmask values returned from kern_features system call.  */
 #define KERN_FEATURE_MIXED_MODE_STACK  0x00000001
index 3d61fcae7ee38beaabe1b6f66bbdd781c43f1353..f2d30cab5b3f388fa9b446cf5b12afda92fa0a9d 100644 (file)
@@ -946,6 +946,12 @@ ENTRY(__retl_one)
         mov    1, %o0
 ENDPROC(__retl_one)
 
+ENTRY(__retl_one_fp)
+       VISExitHalf
+       retl
+        mov    1, %o0
+ENDPROC(__retl_one_fp)
+
 ENTRY(__ret_one_asi)
        wr      %g0, ASI_AIUS, %asi
        ret
@@ -958,6 +964,13 @@ ENTRY(__retl_one_asi)
         mov    1, %o0
 ENDPROC(__retl_one_asi)
 
+ENTRY(__retl_one_asi_fp)
+       wr      %g0, ASI_AIUS, %asi
+       VISExitHalf
+       retl
+        mov    1, %o0
+ENDPROC(__retl_one_asi_fp)
+
 ENTRY(__retl_o1)
        retl
         mov    %o1, %o0
index b0da5aedb336c643baf9163c010c6c679ce6bbdc..6596f66ce1126fa487b7ce8eec19ef17dc4912e7 100644 (file)
@@ -9,7 +9,7 @@
  *  Copyright (C) 2008-2009 Red Hat, Inc., Ingo Molnar
  *  Copyright (C) 2009 Jaswinder Singh Rajput
  *  Copyright (C) 2009 Advanced Micro Devices, Inc., Robert Richter
- *  Copyright (C) 2008-2009 Red Hat, Inc., Peter Zijlstra <pzijlstr@redhat.com>
+ *  Copyright (C) 2008-2009 Red Hat, Inc., Peter Zijlstra
  */
 
 #include <linux/perf_event.h>
@@ -1828,11 +1828,18 @@ static void perf_callchain_user_32(struct perf_callchain_entry *entry,
 void
 perf_callchain_user(struct perf_callchain_entry *entry, struct pt_regs *regs)
 {
+       u64 saved_fault_address = current_thread_info()->fault_address;
+       u8 saved_fault_code = get_thread_fault_code();
+       mm_segment_t old_fs;
+
        perf_callchain_store(entry, regs->tpc);
 
        if (!current->mm)
                return;
 
+       old_fs = get_fs();
+       set_fs(USER_DS);
+
        flushw_user();
 
        pagefault_disable();
@@ -1843,4 +1850,8 @@ perf_callchain_user(struct perf_callchain_entry *entry, struct pt_regs *regs)
                perf_callchain_user_64(entry, regs);
 
        pagefault_enable();
+
+       set_fs(old_fs);
+       set_thread_fault_code(saved_fault_code);
+       current_thread_info()->fault_address = saved_fault_address;
 }
index 39f0c662f4c81dcdf3050926a5a9525d352933a3..d08bdaffdbfccbafc9b3d67c30267fe397eb917f 100644 (file)
@@ -73,7 +73,13 @@ rtrap_nmi:   ldx                     [%sp + PTREGS_OFF + PT_V9_TSTATE], %l1
                andn                    %l1, %l4, %l1
                srl                     %l4, 20, %l4
                ba,pt                   %xcc, rtrap_no_irq_enable
-                wrpr                   %l4, %pil
+               nop
+               /* Do not actually set the %pil here.  We will do that
+                * below after we clear PSTATE_IE in the %pstate register.
+                * If we re-enable interrupts here, we can recurse down
+                * the hardirq stack potentially endlessly, causing a
+                * stack overflow.
+                */
 
                .align                  64
                .globl                  rtrap_irq, rtrap, irqsz_patchme, rtrap_xcall
index f7b261749383b4992300ba4418b1d16ef7251360..f3185e2b028b86886a2a185faee9d99fa5c5c47f 100644 (file)
@@ -380,7 +380,8 @@ static const char *hwcaps[] = {
         */
        "mul32", "div32", "fsmuld", "v8plus", "popc", "vis", "vis2",
        "ASIBlkInit", "fmaf", "vis3", "hpc", "random", "trans", "fjfmau",
-       "ima", "cspare", "pause", "cbcond",
+       "ima", "cspare", "pause", "cbcond", NULL /*reserved for crypto */,
+       "adp",
 };
 
 static const char *crypto_hwcaps[] = {
@@ -396,7 +397,7 @@ void cpucap_info(struct seq_file *m)
        seq_puts(m, "cpucaps\t\t: ");
        for (i = 0; i < ARRAY_SIZE(hwcaps); i++) {
                unsigned long bit = 1UL << i;
-               if (caps & bit) {
+               if (hwcaps[i] && (caps & bit)) {
                        seq_printf(m, "%s%s",
                                   printed ? "," : "", hwcaps[i]);
                        printed++;
@@ -450,7 +451,7 @@ static void __init report_hwcaps(unsigned long caps)
 
        for (i = 0; i < ARRAY_SIZE(hwcaps); i++) {
                unsigned long bit = 1UL << i;
-               if (caps & bit)
+               if (hwcaps[i] && (caps & bit))
                        report_one_hwcap(&printed, hwcaps[i]);
        }
        if (caps & HWCAP_SPARC_CRYPTO)
@@ -485,7 +486,7 @@ static unsigned long __init mdesc_cpu_hwcap_list(void)
                for (i = 0; i < ARRAY_SIZE(hwcaps); i++) {
                        unsigned long bit = 1UL << i;
 
-                       if (!strcmp(prop, hwcaps[i])) {
+                       if (hwcaps[i] && !strcmp(prop, hwcaps[i])) {
                                caps |= bit;
                                break;
                        }
index cc23b62b6e38a858c7e077c6b2c0757a63803b3d..e663b6c78de2e6498a5a458f1129504cae3ab2a8 100644 (file)
@@ -35,18 +35,18 @@ sys_call_table:
 /*80*/ .long sys_setgroups16, sys_getpgrp, sys_setgroups, sys_setitimer, sys_ftruncate64
 /*85*/ .long sys_swapon, sys_getitimer, sys_setuid, sys_sethostname, sys_setgid
 /*90*/ .long sys_dup2, sys_setfsuid, sys_fcntl, sys_select, sys_setfsgid
-/*95*/ .long sys_fsync, sys_setpriority, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall
+/*95*/ .long sys_fsync, sys_setpriority, sys_socket, sys_connect, sys_accept
 /*100*/        .long sys_getpriority, sys_rt_sigreturn, sys_rt_sigaction, sys_rt_sigprocmask, sys_rt_sigpending
 /*105*/        .long sys_rt_sigtimedwait, sys_rt_sigqueueinfo, sys_rt_sigsuspend, sys_setresuid, sys_getresuid
-/*110*/        .long sys_setresgid, sys_getresgid, sys_setregid, sys_nis_syscall, sys_nis_syscall
-/*115*/        .long sys_getgroups, sys_gettimeofday, sys_getrusage, sys_nis_syscall, sys_getcwd
+/*110*/        .long sys_setresgid, sys_getresgid, sys_setregid, sys_recvmsg, sys_sendmsg
+/*115*/        .long sys_getgroups, sys_gettimeofday, sys_getrusage, sys_getsockopt, sys_getcwd
 /*120*/        .long sys_readv, sys_writev, sys_settimeofday, sys_fchown16, sys_fchmod
-/*125*/        .long sys_nis_syscall, sys_setreuid16, sys_setregid16, sys_rename, sys_truncate
-/*130*/        .long sys_ftruncate, sys_flock, sys_lstat64, sys_nis_syscall, sys_nis_syscall
-/*135*/        .long sys_nis_syscall, sys_mkdir, sys_rmdir, sys_utimes, sys_stat64
-/*140*/        .long sys_sendfile64, sys_nis_syscall, sys_futex, sys_gettid, sys_getrlimit
+/*125*/        .long sys_recvfrom, sys_setreuid16, sys_setregid16, sys_rename, sys_truncate
+/*130*/        .long sys_ftruncate, sys_flock, sys_lstat64, sys_sendto, sys_shutdown
+/*135*/        .long sys_socketpair, sys_mkdir, sys_rmdir, sys_utimes, sys_stat64
+/*140*/        .long sys_sendfile64, sys_getpeername, sys_futex, sys_gettid, sys_getrlimit
 /*145*/        .long sys_setrlimit, sys_pivot_root, sys_prctl, sys_pciconfig_read, sys_pciconfig_write
-/*150*/        .long sys_nis_syscall, sys_inotify_init, sys_inotify_add_watch, sys_poll, sys_getdents64
+/*150*/        .long sys_getsockname, sys_inotify_init, sys_inotify_add_watch, sys_poll, sys_getdents64
 /*155*/        .long sys_fcntl64, sys_inotify_rm_watch, sys_statfs, sys_fstatfs, sys_oldumount
 /*160*/        .long sys_sched_setaffinity, sys_sched_getaffinity, sys_getdomainname, sys_setdomainname, sys_nis_syscall
 /*165*/        .long sys_quotactl, sys_set_tid_address, sys_mount, sys_ustat, sys_setxattr
@@ -87,4 +87,5 @@ sys_call_table:
 /*335*/        .long sys_syncfs, sys_sendmmsg, sys_setns, sys_process_vm_readv, sys_process_vm_writev
 /*340*/        .long sys_ni_syscall, sys_kcmp, sys_finit_module, sys_sched_setattr, sys_sched_getattr
 /*345*/        .long sys_renameat2, sys_seccomp, sys_getrandom, sys_memfd_create, sys_bpf
-/*350*/        .long sys_execveat, sys_membarrier
+/*350*/        .long sys_execveat, sys_membarrier, sys_userfaultfd, sys_bind, sys_listen
+/*355*/        .long sys_setsockopt, sys_mlock2
index f229468a747975ea7eb0dac89886747efb52f773..1557121f4cdce8a6ae21c31fb33e9aa2d7cbc443 100644 (file)
@@ -37,15 +37,15 @@ sys_call_table32:
 /*80*/ .word sys_setgroups16, sys_getpgrp, sys_setgroups, compat_sys_setitimer, sys32_ftruncate64
        .word sys_swapon, compat_sys_getitimer, sys_setuid, sys_sethostname, sys_setgid
 /*90*/ .word sys_dup2, sys_setfsuid, compat_sys_fcntl, sys32_select, sys_setfsgid
-       .word sys_fsync, sys_setpriority, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall
+       .word sys_fsync, sys_setpriority, sys_socket, sys_connect, sys_accept
 /*100*/ .word sys_getpriority, sys32_rt_sigreturn, compat_sys_rt_sigaction, compat_sys_rt_sigprocmask, compat_sys_rt_sigpending
        .word compat_sys_rt_sigtimedwait, compat_sys_rt_sigqueueinfo, compat_sys_rt_sigsuspend, sys_setresuid, sys_getresuid
-/*110*/        .word sys_setresgid, sys_getresgid, sys_setregid, sys_nis_syscall, sys_nis_syscall
-       .word sys_getgroups, compat_sys_gettimeofday, compat_sys_getrusage, sys_nis_syscall, sys_getcwd
+/*110*/        .word sys_setresgid, sys_getresgid, sys_setregid, compat_sys_recvmsg, compat_sys_sendmsg
+       .word sys_getgroups, compat_sys_gettimeofday, compat_sys_getrusage, compat_sys_getsockopt, sys_getcwd
 /*120*/        .word compat_sys_readv, compat_sys_writev, compat_sys_settimeofday, sys_fchown16, sys_fchmod
-       .word sys_nis_syscall, sys_setreuid16, sys_setregid16, sys_rename, compat_sys_truncate
-/*130*/        .word compat_sys_ftruncate, sys_flock, compat_sys_lstat64, sys_nis_syscall, sys_nis_syscall
-       .word sys_nis_syscall, sys_mkdir, sys_rmdir, compat_sys_utimes, compat_sys_stat64
+       .word sys_recvfrom, sys_setreuid16, sys_setregid16, sys_rename, compat_sys_truncate
+/*130*/        .word compat_sys_ftruncate, sys_flock, compat_sys_lstat64, sys_sendto, sys_shutdown
+       .word sys_socketpair, sys_mkdir, sys_rmdir, compat_sys_utimes, compat_sys_stat64
 /*140*/        .word sys_sendfile64, sys_nis_syscall, sys32_futex, sys_gettid, compat_sys_getrlimit
        .word compat_sys_setrlimit, sys_pivot_root, sys_prctl, sys_pciconfig_read, sys_pciconfig_write
 /*150*/        .word sys_nis_syscall, sys_inotify_init, sys_inotify_add_watch, sys_poll, sys_getdents64
@@ -88,7 +88,8 @@ sys_call_table32:
        .word sys_syncfs, compat_sys_sendmmsg, sys_setns, compat_sys_process_vm_readv, compat_sys_process_vm_writev
 /*340*/        .word sys_kern_features, sys_kcmp, sys_finit_module, sys_sched_setattr, sys_sched_getattr
        .word sys32_renameat2, sys_seccomp, sys_getrandom, sys_memfd_create, sys_bpf
-/*350*/        .word sys32_execveat, sys_membarrier
+/*350*/        .word sys32_execveat, sys_membarrier, sys_userfaultfd, sys_bind, sys_listen
+       .word compat_sys_setsockopt, sys_mlock2
 
 #endif /* CONFIG_COMPAT */
 
@@ -168,4 +169,5 @@ sys_call_table:
        .word sys_syncfs, sys_sendmmsg, sys_setns, sys_process_vm_readv, sys_process_vm_writev
 /*340*/        .word sys_kern_features, sys_kcmp, sys_finit_module, sys_sched_setattr, sys_sched_getattr
        .word sys_renameat2, sys_seccomp, sys_getrandom, sys_memfd_create, sys_bpf
-/*350*/        .word sys64_execveat, sys_membarrier
+/*350*/        .word sys64_execveat, sys_membarrier, sys_userfaultfd, sys_bind, sys_listen
+       .word sys_setsockopt, sys_mlock2
index 119ccb9a54f49e2ac2724650060eb7a1d70e8d9e..d5242b8c4f9495fe4241ee39de01255364e877af 100644 (file)
        .text;                  \
        .align 4;
 
+#define EX_LD_FP(x)            \
+98:    x;                      \
+       .section __ex_table,"a";\
+       .align 4;               \
+       .word 98b, __retl_one_asi_fp;\
+       .text;                  \
+       .align 4;
+
 #ifndef ASI_AIUS
 #define ASI_AIUS       0x11
 #endif
index 7fe1ccefd9d056a104407c8d1595095c7fc5add8..4e962d993b10cdff7677f8d51e61ad877901facc 100644 (file)
        .text;                  \
        .align 4;
 
+#define EX_ST_FP(x)            \
+98:    x;                      \
+       .section __ex_table,"a";\
+       .align 4;               \
+       .word 98b, __retl_one_asi_fp;\
+       .text;                  \
+       .align 4;
+
 #ifndef ASI_AIUS
 #define ASI_AIUS       0x11
 #endif
index 30eee6e8a81b2d45797aab304914b10571573b1a..d5f585df2f3fc345c87f04fb1a420fa766816cb5 100644 (file)
 #ifndef EX_LD
 #define EX_LD(x)       x
 #endif
+#ifndef EX_LD_FP
+#define EX_LD_FP(x)    x
+#endif
 
 #ifndef EX_ST
 #define EX_ST(x)       x
 #endif
+#ifndef EX_ST_FP
+#define EX_ST_FP(x)    x
+#endif
 
 #ifndef EX_RETVAL
 #define EX_RETVAL(x)   x
        fsrc2           %x6, %f12; \
        fsrc2           %x7, %f14;
 #define FREG_LOAD_1(base, x0) \
-       EX_LD(LOAD(ldd, base + 0x00, %x0))
+       EX_LD_FP(LOAD(ldd, base + 0x00, %x0))
 #define FREG_LOAD_2(base, x0, x1) \
-       EX_LD(LOAD(ldd, base + 0x00, %x0)); \
-       EX_LD(LOAD(ldd, base + 0x08, %x1));
+       EX_LD_FP(LOAD(ldd, base + 0x00, %x0)); \
+       EX_LD_FP(LOAD(ldd, base + 0x08, %x1));
 #define FREG_LOAD_3(base, x0, x1, x2) \
-       EX_LD(LOAD(ldd, base + 0x00, %x0)); \
-       EX_LD(LOAD(ldd, base + 0x08, %x1)); \
-       EX_LD(LOAD(ldd, base + 0x10, %x2));
+       EX_LD_FP(LOAD(ldd, base + 0x00, %x0)); \
+       EX_LD_FP(LOAD(ldd, base + 0x08, %x1)); \
+       EX_LD_FP(LOAD(ldd, base + 0x10, %x2));
 #define FREG_LOAD_4(base, x0, x1, x2, x3) \
-       EX_LD(LOAD(ldd, base + 0x00, %x0)); \
-       EX_LD(LOAD(ldd, base + 0x08, %x1)); \
-       EX_LD(LOAD(ldd, base + 0x10, %x2)); \
-       EX_LD(LOAD(ldd, base + 0x18, %x3));
+       EX_LD_FP(LOAD(ldd, base + 0x00, %x0)); \
+       EX_LD_FP(LOAD(ldd, base + 0x08, %x1)); \
+       EX_LD_FP(LOAD(ldd, base + 0x10, %x2)); \
+       EX_LD_FP(LOAD(ldd, base + 0x18, %x3));
 #define FREG_LOAD_5(base, x0, x1, x2, x3, x4) \
-       EX_LD(LOAD(ldd, base + 0x00, %x0)); \
-       EX_LD(LOAD(ldd, base + 0x08, %x1)); \
-       EX_LD(LOAD(ldd, base + 0x10, %x2)); \
-       EX_LD(LOAD(ldd, base + 0x18, %x3)); \
-       EX_LD(LOAD(ldd, base + 0x20, %x4));
+       EX_LD_FP(LOAD(ldd, base + 0x00, %x0)); \
+       EX_LD_FP(LOAD(ldd, base + 0x08, %x1)); \
+       EX_LD_FP(LOAD(ldd, base + 0x10, %x2)); \
+       EX_LD_FP(LOAD(ldd, base + 0x18, %x3)); \
+       EX_LD_FP(LOAD(ldd, base + 0x20, %x4));
 #define FREG_LOAD_6(base, x0, x1, x2, x3, x4, x5) \
-       EX_LD(LOAD(ldd, base + 0x00, %x0)); \
-       EX_LD(LOAD(ldd, base + 0x08, %x1)); \
-       EX_LD(LOAD(ldd, base + 0x10, %x2)); \
-       EX_LD(LOAD(ldd, base + 0x18, %x3)); \
-       EX_LD(LOAD(ldd, base + 0x20, %x4)); \
-       EX_LD(LOAD(ldd, base + 0x28, %x5));
+       EX_LD_FP(LOAD(ldd, base + 0x00, %x0)); \
+       EX_LD_FP(LOAD(ldd, base + 0x08, %x1)); \
+       EX_LD_FP(LOAD(ldd, base + 0x10, %x2)); \
+       EX_LD_FP(LOAD(ldd, base + 0x18, %x3)); \
+       EX_LD_FP(LOAD(ldd, base + 0x20, %x4)); \
+       EX_LD_FP(LOAD(ldd, base + 0x28, %x5));
 #define FREG_LOAD_7(base, x0, x1, x2, x3, x4, x5, x6) \
-       EX_LD(LOAD(ldd, base + 0x00, %x0)); \
-       EX_LD(LOAD(ldd, base + 0x08, %x1)); \
-       EX_LD(LOAD(ldd, base + 0x10, %x2)); \
-       EX_LD(LOAD(ldd, base + 0x18, %x3)); \
-       EX_LD(LOAD(ldd, base + 0x20, %x4)); \
-       EX_LD(LOAD(ldd, base + 0x28, %x5)); \
-       EX_LD(LOAD(ldd, base + 0x30, %x6));
+       EX_LD_FP(LOAD(ldd, base + 0x00, %x0)); \
+       EX_LD_FP(LOAD(ldd, base + 0x08, %x1)); \
+       EX_LD_FP(LOAD(ldd, base + 0x10, %x2)); \
+       EX_LD_FP(LOAD(ldd, base + 0x18, %x3)); \
+       EX_LD_FP(LOAD(ldd, base + 0x20, %x4)); \
+       EX_LD_FP(LOAD(ldd, base + 0x28, %x5)); \
+       EX_LD_FP(LOAD(ldd, base + 0x30, %x6));
 
        .register       %g2,#scratch
        .register       %g3,#scratch
@@ -275,11 +281,11 @@ FUNC_NAME:        /* %o0=dst, %o1=src, %o2=len */
         nop
        /* fall through for 0 < low bits < 8 */
 110:   sub             %o4, 64, %g2
-       EX_LD(LOAD_BLK(%g2, %f0))
-1:     EX_ST(STORE_INIT(%g0, %o4 + %g3))
-       EX_LD(LOAD_BLK(%o4, %f16))
+       EX_LD_FP(LOAD_BLK(%g2, %f0))
+1:     EX_ST_FP(STORE_INIT(%g0, %o4 + %g3))
+       EX_LD_FP(LOAD_BLK(%o4, %f16))
        FREG_FROB(f0, f2, f4, f6, f8, f10, f12, f14, f16)
-       EX_ST(STORE_BLK(%f0, %o4 + %g3))
+       EX_ST_FP(STORE_BLK(%f0, %o4 + %g3))
        FREG_MOVE_8(f16, f18, f20, f22, f24, f26, f28, f30)
        subcc           %g1, 64, %g1
        add             %o4, 64, %o4
@@ -290,10 +296,10 @@ FUNC_NAME:        /* %o0=dst, %o1=src, %o2=len */
 
 120:   sub             %o4, 56, %g2
        FREG_LOAD_7(%g2, f0, f2, f4, f6, f8, f10, f12)
-1:     EX_ST(STORE_INIT(%g0, %o4 + %g3))
-       EX_LD(LOAD_BLK(%o4, %f16))
+1:     EX_ST_FP(STORE_INIT(%g0, %o4 + %g3))
+       EX_LD_FP(LOAD_BLK(%o4, %f16))
        FREG_FROB(f0, f2, f4, f6, f8, f10, f12, f16, f18)
-       EX_ST(STORE_BLK(%f0, %o4 + %g3))
+       EX_ST_FP(STORE_BLK(%f0, %o4 + %g3))
        FREG_MOVE_7(f18, f20, f22, f24, f26, f28, f30)
        subcc           %g1, 64, %g1
        add             %o4, 64, %o4
@@ -304,10 +310,10 @@ FUNC_NAME:        /* %o0=dst, %o1=src, %o2=len */
 
 130:   sub             %o4, 48, %g2
        FREG_LOAD_6(%g2, f0, f2, f4, f6, f8, f10)
-1:     EX_ST(STORE_INIT(%g0, %o4 + %g3))
-       EX_LD(LOAD_BLK(%o4, %f16))
+1:     EX_ST_FP(STORE_INIT(%g0, %o4 + %g3))
+       EX_LD_FP(LOAD_BLK(%o4, %f16))
        FREG_FROB(f0, f2, f4, f6, f8, f10, f16, f18, f20)
-       EX_ST(STORE_BLK(%f0, %o4 + %g3))
+       EX_ST_FP(STORE_BLK(%f0, %o4 + %g3))
        FREG_MOVE_6(f20, f22, f24, f26, f28, f30)
        subcc           %g1, 64, %g1
        add             %o4, 64, %o4
@@ -318,10 +324,10 @@ FUNC_NAME:        /* %o0=dst, %o1=src, %o2=len */
 
 140:   sub             %o4, 40, %g2
        FREG_LOAD_5(%g2, f0, f2, f4, f6, f8)
-1:     EX_ST(STORE_INIT(%g0, %o4 + %g3))
-       EX_LD(LOAD_BLK(%o4, %f16))
+1:     EX_ST_FP(STORE_INIT(%g0, %o4 + %g3))
+       EX_LD_FP(LOAD_BLK(%o4, %f16))
        FREG_FROB(f0, f2, f4, f6, f8, f16, f18, f20, f22)
-       EX_ST(STORE_BLK(%f0, %o4 + %g3))
+       EX_ST_FP(STORE_BLK(%f0, %o4 + %g3))
        FREG_MOVE_5(f22, f24, f26, f28, f30)
        subcc           %g1, 64, %g1
        add             %o4, 64, %o4
@@ -332,10 +338,10 @@ FUNC_NAME:        /* %o0=dst, %o1=src, %o2=len */
 
 150:   sub             %o4, 32, %g2
        FREG_LOAD_4(%g2, f0, f2, f4, f6)
-1:     EX_ST(STORE_INIT(%g0, %o4 + %g3))
-       EX_LD(LOAD_BLK(%o4, %f16))
+1:     EX_ST_FP(STORE_INIT(%g0, %o4 + %g3))
+       EX_LD_FP(LOAD_BLK(%o4, %f16))
        FREG_FROB(f0, f2, f4, f6, f16, f18, f20, f22, f24)
-       EX_ST(STORE_BLK(%f0, %o4 + %g3))
+       EX_ST_FP(STORE_BLK(%f0, %o4 + %g3))
        FREG_MOVE_4(f24, f26, f28, f30)
        subcc           %g1, 64, %g1
        add             %o4, 64, %o4
@@ -346,10 +352,10 @@ FUNC_NAME:        /* %o0=dst, %o1=src, %o2=len */
 
 160:   sub             %o4, 24, %g2
        FREG_LOAD_3(%g2, f0, f2, f4)
-1:     EX_ST(STORE_INIT(%g0, %o4 + %g3))
-       EX_LD(LOAD_BLK(%o4, %f16))
+1:     EX_ST_FP(STORE_INIT(%g0, %o4 + %g3))
+       EX_LD_FP(LOAD_BLK(%o4, %f16))
        FREG_FROB(f0, f2, f4, f16, f18, f20, f22, f24, f26)
-       EX_ST(STORE_BLK(%f0, %o4 + %g3))
+       EX_ST_FP(STORE_BLK(%f0, %o4 + %g3))
        FREG_MOVE_3(f26, f28, f30)
        subcc           %g1, 64, %g1
        add             %o4, 64, %o4
@@ -360,10 +366,10 @@ FUNC_NAME:        /* %o0=dst, %o1=src, %o2=len */
 
 170:   sub             %o4, 16, %g2
        FREG_LOAD_2(%g2, f0, f2)
-1:     EX_ST(STORE_INIT(%g0, %o4 + %g3))
-       EX_LD(LOAD_BLK(%o4, %f16))
+1:     EX_ST_FP(STORE_INIT(%g0, %o4 + %g3))
+       EX_LD_FP(LOAD_BLK(%o4, %f16))
        FREG_FROB(f0, f2, f16, f18, f20, f22, f24, f26, f28)
-       EX_ST(STORE_BLK(%f0, %o4 + %g3))
+       EX_ST_FP(STORE_BLK(%f0, %o4 + %g3))
        FREG_MOVE_2(f28, f30)
        subcc           %g1, 64, %g1
        add             %o4, 64, %o4
@@ -374,10 +380,10 @@ FUNC_NAME:        /* %o0=dst, %o1=src, %o2=len */
 
 180:   sub             %o4, 8, %g2
        FREG_LOAD_1(%g2, f0)
-1:     EX_ST(STORE_INIT(%g0, %o4 + %g3))
-       EX_LD(LOAD_BLK(%o4, %f16))
+1:     EX_ST_FP(STORE_INIT(%g0, %o4 + %g3))
+       EX_LD_FP(LOAD_BLK(%o4, %f16))
        FREG_FROB(f0, f16, f18, f20, f22, f24, f26, f28, f30)
-       EX_ST(STORE_BLK(%f0, %o4 + %g3))
+       EX_ST_FP(STORE_BLK(%f0, %o4 + %g3))
        FREG_MOVE_1(f30)
        subcc           %g1, 64, %g1
        add             %o4, 64, %o4
@@ -387,10 +393,10 @@ FUNC_NAME:        /* %o0=dst, %o1=src, %o2=len */
         nop
 
 190:
-1:     EX_ST(STORE_INIT(%g0, %o4 + %g3))
+1:     EX_ST_FP(STORE_INIT(%g0, %o4 + %g3))
        subcc           %g1, 64, %g1
-       EX_LD(LOAD_BLK(%o4, %f0))
-       EX_ST(STORE_BLK(%f0, %o4 + %g3))
+       EX_LD_FP(LOAD_BLK(%o4, %f0))
+       EX_ST_FP(STORE_BLK(%f0, %o4 + %g3))
        add             %o4, 64, %o4
        bne,pt          %xcc, 1b
         LOAD(prefetch, %o4 + 64, #one_read)
index fd9f903ffa3269713dcec781a0ed93a77ae70c1b..2e8ee7ad07a9ce06129cd63c4129ccade674ab77 100644 (file)
        .text;                  \
        .align 4;
 
+#define EX_LD_FP(x)            \
+98:    x;                      \
+       .section __ex_table,"a";\
+       .align 4;               \
+       .word 98b, __retl_one_asi_fp;\
+       .text;                  \
+       .align 4;
+
 #ifndef ASI_AIUS
 #define ASI_AIUS       0x11
 #endif
index 9744c4540a8d99f6010a859aa1ef1510f7b70827..be0bf4590df8971ddf29a81153f05de7c0ef30da 100644 (file)
        .text;                  \
        .align 4;
 
+#define EX_ST_FP(x)            \
+98:    x;                      \
+       .section __ex_table,"a";\
+       .align 4;               \
+       .word 98b, __retl_one_asi_fp;\
+       .text;                  \
+       .align 4;
+
 #ifndef ASI_AIUS
 #define ASI_AIUS       0x11
 #endif
index 83aeeb1dffdb3b4c29293d5924cd5259e2269ce5..8e13ee1f4454ea2b6478d302a9a1048bfeb60aff 100644 (file)
 #ifndef EX_LD
 #define EX_LD(x)       x
 #endif
+#ifndef EX_LD_FP
+#define EX_LD_FP(x)    x
+#endif
 
 #ifndef EX_ST
 #define EX_ST(x)       x
 #endif
+#ifndef EX_ST_FP
+#define EX_ST_FP(x)    x
+#endif
 
 #ifndef EX_RETVAL
 #define EX_RETVAL(x)   x
@@ -210,17 +216,17 @@ FUNC_NAME:        /* %o0=dst, %o1=src, %o2=len */
        sub             %o2, %o4, %o2
        alignaddr       %o1, %g0, %g1
        add             %o1, %o4, %o1
-       EX_LD(LOAD(ldd, %g1 + 0x00, %f0))
-1:     EX_LD(LOAD(ldd, %g1 + 0x08, %f2))
+       EX_LD_FP(LOAD(ldd, %g1 + 0x00, %f0))
+1:     EX_LD_FP(LOAD(ldd, %g1 + 0x08, %f2))
        subcc           %o4, 0x40, %o4
-       EX_LD(LOAD(ldd, %g1 + 0x10, %f4))
-       EX_LD(LOAD(ldd, %g1 + 0x18, %f6))
-       EX_LD(LOAD(ldd, %g1 + 0x20, %f8))
-       EX_LD(LOAD(ldd, %g1 + 0x28, %f10))
-       EX_LD(LOAD(ldd, %g1 + 0x30, %f12))
-       EX_LD(LOAD(ldd, %g1 + 0x38, %f14))
+       EX_LD_FP(LOAD(ldd, %g1 + 0x10, %f4))
+       EX_LD_FP(LOAD(ldd, %g1 + 0x18, %f6))
+       EX_LD_FP(LOAD(ldd, %g1 + 0x20, %f8))
+       EX_LD_FP(LOAD(ldd, %g1 + 0x28, %f10))
+       EX_LD_FP(LOAD(ldd, %g1 + 0x30, %f12))
+       EX_LD_FP(LOAD(ldd, %g1 + 0x38, %f14))
        faligndata      %f0, %f2, %f16
-       EX_LD(LOAD(ldd, %g1 + 0x40, %f0))
+       EX_LD_FP(LOAD(ldd, %g1 + 0x40, %f0))
        faligndata      %f2, %f4, %f18
        add             %g1, 0x40, %g1
        faligndata      %f4, %f6, %f20
@@ -229,14 +235,14 @@ FUNC_NAME:        /* %o0=dst, %o1=src, %o2=len */
        faligndata      %f10, %f12, %f26
        faligndata      %f12, %f14, %f28
        faligndata      %f14, %f0, %f30
-       EX_ST(STORE(std, %f16, %o0 + 0x00))
-       EX_ST(STORE(std, %f18, %o0 + 0x08))
-       EX_ST(STORE(std, %f20, %o0 + 0x10))
-       EX_ST(STORE(std, %f22, %o0 + 0x18))
-       EX_ST(STORE(std, %f24, %o0 + 0x20))
-       EX_ST(STORE(std, %f26, %o0 + 0x28))
-       EX_ST(STORE(std, %f28, %o0 + 0x30))
-       EX_ST(STORE(std, %f30, %o0 + 0x38))
+       EX_ST_FP(STORE(std, %f16, %o0 + 0x00))
+       EX_ST_FP(STORE(std, %f18, %o0 + 0x08))
+       EX_ST_FP(STORE(std, %f20, %o0 + 0x10))
+       EX_ST_FP(STORE(std, %f22, %o0 + 0x18))
+       EX_ST_FP(STORE(std, %f24, %o0 + 0x20))
+       EX_ST_FP(STORE(std, %f26, %o0 + 0x28))
+       EX_ST_FP(STORE(std, %f28, %o0 + 0x30))
+       EX_ST_FP(STORE(std, %f30, %o0 + 0x38))
        add             %o0, 0x40, %o0
        bne,pt          %icc, 1b
         LOAD(prefetch, %g1 + 0x200, #n_reads_strong)
index a6ae2ea04bf5dfbffda2884a6a46b051ae2ac2a8..ecc5692fa2b49a3acfc6a6592c6c247835417b4c 100644 (file)
        .text;                  \
        .align 4;
 
+#define EX_LD_FP(x)            \
+98:    x;                      \
+       .section __ex_table,"a";\
+       .align 4;               \
+       .word 98b, __retl_one_fp;\
+       .text;                  \
+       .align 4;
+
 #define FUNC_NAME              ___copy_from_user
 #define LOAD(type,addr,dest)   type##a [addr] %asi, dest
 #define LOAD_BLK(addr,dest)    ldda [addr] ASI_BLK_AIUS, dest
index f4b970eeb485f838ce23dc5507a5bccd6defd348..9eea392e44d471679ba85c22867a9767b34912a5 100644 (file)
        .text;                  \
        .align 4;
 
+#define EX_ST_FP(x)            \
+98:    x;                      \
+       .section __ex_table,"a";\
+       .align 4;               \
+       .word 98b, __retl_one_fp;\
+       .text;                  \
+       .align 4;
+
 #define FUNC_NAME              ___copy_to_user
 #define STORE(type,src,addr)   type##a src, [addr] ASI_AIUS
 #define STORE_BLK(src,addr)    stda src, [addr] ASI_BLK_AIUS
index b67142b7768e50e20fb28d5c4ed562435ab145f5..3e6209ebb7d7865fd62bb21df56dabda07fe4f5f 100644 (file)
 #ifndef EX_LD
 #define EX_LD(x)       x
 #endif
+#ifndef EX_LD_FP
+#define EX_LD_FP(x)    x
+#endif
 
 #ifndef EX_ST
 #define EX_ST(x)       x
 #endif
+#ifndef EX_ST_FP
+#define EX_ST_FP(x)    x
+#endif
 
 #ifndef EX_RETVAL
 #define EX_RETVAL(x)   x
@@ -73,8 +79,8 @@
        faligndata              %f8, %f9, %f62;
 
 #define MAIN_LOOP_CHUNK(src, dest, fdest, fsrc, len, jmptgt)   \
-       EX_LD(LOAD_BLK(%src, %fdest));                          \
-       EX_ST(STORE_BLK(%fsrc, %dest));                         \
+       EX_LD_FP(LOAD_BLK(%src, %fdest));                               \
+       EX_ST_FP(STORE_BLK(%fsrc, %dest));                              \
        add                     %src, 0x40, %src;               \
        subcc                   %len, 0x40, %len;               \
        be,pn                   %xcc, jmptgt;                   \
 
 #define DO_SYNC                        membar  #Sync;
 #define STORE_SYNC(dest, fsrc)                         \
-       EX_ST(STORE_BLK(%fsrc, %dest));                 \
+       EX_ST_FP(STORE_BLK(%fsrc, %dest));                      \
        add                     %dest, 0x40, %dest;     \
        DO_SYNC
 
 #define STORE_JUMP(dest, fsrc, target)                 \
-       EX_ST(STORE_BLK(%fsrc, %dest));                 \
+       EX_ST_FP(STORE_BLK(%fsrc, %dest));                      \
        add                     %dest, 0x40, %dest;     \
        ba,pt                   %xcc, target;           \
         nop;
        subcc                   %left, 8, %left;\
        bl,pn                   %xcc, 95f;      \
         faligndata             %f0, %f1, %f48; \
-       EX_ST(STORE(std, %f48, %dest));         \
+       EX_ST_FP(STORE(std, %f48, %dest));              \
        add                     %dest, 8, %dest;
 
 #define UNEVEN_VISCHUNK_LAST(dest, f0, f1, left)       \
@@ -160,8 +166,8 @@ FUNC_NAME:          /* %o0=dst, %o1=src, %o2=len */
         and            %g2, 0x38, %g2
 
 1:     subcc           %g1, 0x1, %g1
-       EX_LD(LOAD(ldub, %o1 + 0x00, %o3))
-       EX_ST(STORE(stb, %o3, %o1 + %GLOBAL_SPARE))
+       EX_LD_FP(LOAD(ldub, %o1 + 0x00, %o3))
+       EX_ST_FP(STORE(stb, %o3, %o1 + %GLOBAL_SPARE))
        bgu,pt          %XCC, 1b
         add            %o1, 0x1, %o1
 
@@ -172,20 +178,20 @@ FUNC_NAME:                /* %o0=dst, %o1=src, %o2=len */
        be,pt           %icc, 3f
         alignaddr      %o1, %g0, %o1
 
-       EX_LD(LOAD(ldd, %o1, %f4))
-1:     EX_LD(LOAD(ldd, %o1 + 0x8, %f6))
+       EX_LD_FP(LOAD(ldd, %o1, %f4))
+1:     EX_LD_FP(LOAD(ldd, %o1 + 0x8, %f6))
        add             %o1, 0x8, %o1
        subcc           %g2, 0x8, %g2
        faligndata      %f4, %f6, %f0
-       EX_ST(STORE(std, %f0, %o0))
+       EX_ST_FP(STORE(std, %f0, %o0))
        be,pn           %icc, 3f
         add            %o0, 0x8, %o0
 
-       EX_LD(LOAD(ldd, %o1 + 0x8, %f4))
+       EX_LD_FP(LOAD(ldd, %o1 + 0x8, %f4))
        add             %o1, 0x8, %o1
        subcc           %g2, 0x8, %g2
        faligndata      %f6, %f4, %f0
-       EX_ST(STORE(std, %f0, %o0))
+       EX_ST_FP(STORE(std, %f0, %o0))
        bne,pt          %icc, 1b
         add            %o0, 0x8, %o0
 
@@ -208,13 +214,13 @@ FUNC_NAME:                /* %o0=dst, %o1=src, %o2=len */
        add             %g1, %GLOBAL_SPARE, %g1
        subcc           %o2, %g3, %o2
 
-       EX_LD(LOAD_BLK(%o1, %f0))
+       EX_LD_FP(LOAD_BLK(%o1, %f0))
        add             %o1, 0x40, %o1
        add             %g1, %g3, %g1
-       EX_LD(LOAD_BLK(%o1, %f16))
+       EX_LD_FP(LOAD_BLK(%o1, %f16))
        add             %o1, 0x40, %o1
        sub             %GLOBAL_SPARE, 0x80, %GLOBAL_SPARE
-       EX_LD(LOAD_BLK(%o1, %f32))
+       EX_LD_FP(LOAD_BLK(%o1, %f32))
        add             %o1, 0x40, %o1
 
        /* There are 8 instances of the unrolled loop,
@@ -426,28 +432,28 @@ FUNC_NAME:                /* %o0=dst, %o1=src, %o2=len */
 62:    FINISH_VISCHUNK(o0, f44, f46, g3)
 63:    UNEVEN_VISCHUNK_LAST(o0, f46, f0,  g3)
 
-93:    EX_LD(LOAD(ldd, %o1, %f2))
+93:    EX_LD_FP(LOAD(ldd, %o1, %f2))
        add             %o1, 8, %o1
        subcc           %g3, 8, %g3
        faligndata      %f0, %f2, %f8
-       EX_ST(STORE(std, %f8, %o0))
+       EX_ST_FP(STORE(std, %f8, %o0))
        bl,pn           %xcc, 95f
         add            %o0, 8, %o0
-       EX_LD(LOAD(ldd, %o1, %f0))
+       EX_LD_FP(LOAD(ldd, %o1, %f0))
        add             %o1, 8, %o1
        subcc           %g3, 8, %g3
        faligndata      %f2, %f0, %f8
-       EX_ST(STORE(std, %f8, %o0))
+       EX_ST_FP(STORE(std, %f8, %o0))
        bge,pt          %xcc, 93b
         add            %o0, 8, %o0
 
 95:    brz,pt          %o2, 2f
         mov            %g1, %o1
 
-1:     EX_LD(LOAD(ldub, %o1, %o3))
+1:     EX_LD_FP(LOAD(ldub, %o1, %o3))
        add             %o1, 1, %o1
        subcc           %o2, 1, %o2
-       EX_ST(STORE(stb, %o3, %o0))
+       EX_ST_FP(STORE(stb, %o3, %o0))
        bne,pt          %xcc, 1b
         add            %o0, 1, %o0
 
index b1acd1331c338fce1a70e6a13f597509b28501a7..88ad73d86fe44b64c2313483e7490cc8ae0ee438 100644 (file)
        .text;                  \
        .align 4;
 
+#define EX_LD_FP(x)            \
+98:    x;                      \
+       .section __ex_table,"a";\
+       .align 4;               \
+       .word 98b, __retl_one_fp;\
+       .text;                  \
+       .align 4;
+
 #define FUNC_NAME              U3copy_from_user
 #define LOAD(type,addr,dest)   type##a [addr] %asi, dest
 #define EX_RETVAL(x)           0
index ef1e493afdfa900a1b32863c2bf2995560cbe0cd..845139d7553720ce5fe98d6e30bcb11215f71e2f 100644 (file)
        .text;                  \
        .align 4;
 
+#define EX_ST_FP(x)            \
+98:    x;                      \
+       .section __ex_table,"a";\
+       .align 4;               \
+       .word 98b, __retl_one_fp;\
+       .text;                  \
+       .align 4;
+
 #define FUNC_NAME              U3copy_to_user
 #define STORE(type,src,addr)   type##a src, [addr] ASI_AIUS
 #define STORE_BLK(src,addr)    stda src, [addr] ASI_BLK_AIUS
index 7cae9cc6a204a46e535c8c651176ccc873778700..491ee69e49951fc2040640e77b896552872c8a0a 100644 (file)
 #ifndef EX_LD
 #define EX_LD(x)       x
 #endif
+#ifndef EX_LD_FP
+#define EX_LD_FP(x)    x
+#endif
 
 #ifndef EX_ST
 #define EX_ST(x)       x
 #endif
+#ifndef EX_ST_FP
+#define EX_ST_FP(x)    x
+#endif
 
 #ifndef EX_RETVAL
 #define EX_RETVAL(x)   x
@@ -120,8 +126,8 @@ FUNC_NAME:  /* %o0=dst, %o1=src, %o2=len */
         and            %g2, 0x38, %g2
 
 1:     subcc           %g1, 0x1, %g1
-       EX_LD(LOAD(ldub, %o1 + 0x00, %o3))
-       EX_ST(STORE(stb, %o3, %o1 + GLOBAL_SPARE))
+       EX_LD_FP(LOAD(ldub, %o1 + 0x00, %o3))
+       EX_ST_FP(STORE(stb, %o3, %o1 + GLOBAL_SPARE))
        bgu,pt          %XCC, 1b
         add            %o1, 0x1, %o1
 
@@ -132,20 +138,20 @@ FUNC_NAME:        /* %o0=dst, %o1=src, %o2=len */
        be,pt           %icc, 3f
         alignaddr      %o1, %g0, %o1
 
-       EX_LD(LOAD(ldd, %o1, %f4))
-1:     EX_LD(LOAD(ldd, %o1 + 0x8, %f6))
+       EX_LD_FP(LOAD(ldd, %o1, %f4))
+1:     EX_LD_FP(LOAD(ldd, %o1 + 0x8, %f6))
        add             %o1, 0x8, %o1
        subcc           %g2, 0x8, %g2
        faligndata      %f4, %f6, %f0
-       EX_ST(STORE(std, %f0, %o0))
+       EX_ST_FP(STORE(std, %f0, %o0))
        be,pn           %icc, 3f
         add            %o0, 0x8, %o0
 
-       EX_LD(LOAD(ldd, %o1 + 0x8, %f4))
+       EX_LD_FP(LOAD(ldd, %o1 + 0x8, %f4))
        add             %o1, 0x8, %o1
        subcc           %g2, 0x8, %g2
        faligndata      %f6, %f4, %f2
-       EX_ST(STORE(std, %f2, %o0))
+       EX_ST_FP(STORE(std, %f2, %o0))
        bne,pt          %icc, 1b
         add            %o0, 0x8, %o0
 
@@ -155,25 +161,25 @@ FUNC_NAME:        /* %o0=dst, %o1=src, %o2=len */
        LOAD(prefetch, %o1 + 0x080, #one_read)
        LOAD(prefetch, %o1 + 0x0c0, #one_read)
        LOAD(prefetch, %o1 + 0x100, #one_read)
-       EX_LD(LOAD(ldd, %o1 + 0x000, %f0))
+       EX_LD_FP(LOAD(ldd, %o1 + 0x000, %f0))
        LOAD(prefetch, %o1 + 0x140, #one_read)
-       EX_LD(LOAD(ldd, %o1 + 0x008, %f2))
+       EX_LD_FP(LOAD(ldd, %o1 + 0x008, %f2))
        LOAD(prefetch, %o1 + 0x180, #one_read)
-       EX_LD(LOAD(ldd, %o1 + 0x010, %f4))
+       EX_LD_FP(LOAD(ldd, %o1 + 0x010, %f4))
        LOAD(prefetch, %o1 + 0x1c0, #one_read)
        faligndata      %f0, %f2, %f16
-       EX_LD(LOAD(ldd, %o1 + 0x018, %f6))
+       EX_LD_FP(LOAD(ldd, %o1 + 0x018, %f6))
        faligndata      %f2, %f4, %f18
-       EX_LD(LOAD(ldd, %o1 + 0x020, %f8))
+       EX_LD_FP(LOAD(ldd, %o1 + 0x020, %f8))
        faligndata      %f4, %f6, %f20
-       EX_LD(LOAD(ldd, %o1 + 0x028, %f10))
+       EX_LD_FP(LOAD(ldd, %o1 + 0x028, %f10))
        faligndata      %f6, %f8, %f22
 
-       EX_LD(LOAD(ldd, %o1 + 0x030, %f12))
+       EX_LD_FP(LOAD(ldd, %o1 + 0x030, %f12))
        faligndata      %f8, %f10, %f24
-       EX_LD(LOAD(ldd, %o1 + 0x038, %f14))
+       EX_LD_FP(LOAD(ldd, %o1 + 0x038, %f14))
        faligndata      %f10, %f12, %f26
-       EX_LD(LOAD(ldd, %o1 + 0x040, %f0))
+       EX_LD_FP(LOAD(ldd, %o1 + 0x040, %f0))
 
        subcc           GLOBAL_SPARE, 0x80, GLOBAL_SPARE
        add             %o1, 0x40, %o1
@@ -184,26 +190,26 @@ FUNC_NAME:        /* %o0=dst, %o1=src, %o2=len */
 
        .align          64
 1:
-       EX_LD(LOAD(ldd, %o1 + 0x008, %f2))
+       EX_LD_FP(LOAD(ldd, %o1 + 0x008, %f2))
        faligndata      %f12, %f14, %f28
-       EX_LD(LOAD(ldd, %o1 + 0x010, %f4))
+       EX_LD_FP(LOAD(ldd, %o1 + 0x010, %f4))
        faligndata      %f14, %f0, %f30
-       EX_ST(STORE_BLK(%f16, %o0))
-       EX_LD(LOAD(ldd, %o1 + 0x018, %f6))
+       EX_ST_FP(STORE_BLK(%f16, %o0))
+       EX_LD_FP(LOAD(ldd, %o1 + 0x018, %f6))
        faligndata      %f0, %f2, %f16
        add             %o0, 0x40, %o0
 
-       EX_LD(LOAD(ldd, %o1 + 0x020, %f8))
+       EX_LD_FP(LOAD(ldd, %o1 + 0x020, %f8))
        faligndata      %f2, %f4, %f18
-       EX_LD(LOAD(ldd, %o1 + 0x028, %f10))
+       EX_LD_FP(LOAD(ldd, %o1 + 0x028, %f10))
        faligndata      %f4, %f6, %f20
-       EX_LD(LOAD(ldd, %o1 + 0x030, %f12))
+       EX_LD_FP(LOAD(ldd, %o1 + 0x030, %f12))
        subcc           %o3, 0x01, %o3
        faligndata      %f6, %f8, %f22
-       EX_LD(LOAD(ldd, %o1 + 0x038, %f14))
+       EX_LD_FP(LOAD(ldd, %o1 + 0x038, %f14))
 
        faligndata      %f8, %f10, %f24
-       EX_LD(LOAD(ldd, %o1 + 0x040, %f0))
+       EX_LD_FP(LOAD(ldd, %o1 + 0x040, %f0))
        LOAD(prefetch, %o1 + 0x1c0, #one_read)
        faligndata      %f10, %f12, %f26
        bg,pt           %XCC, 1b
@@ -211,29 +217,29 @@ FUNC_NAME:        /* %o0=dst, %o1=src, %o2=len */
 
        /* Finally we copy the last full 64-byte block. */
 2:
-       EX_LD(LOAD(ldd, %o1 + 0x008, %f2))
+       EX_LD_FP(LOAD(ldd, %o1 + 0x008, %f2))
        faligndata      %f12, %f14, %f28
-       EX_LD(LOAD(ldd, %o1 + 0x010, %f4))
+       EX_LD_FP(LOAD(ldd, %o1 + 0x010, %f4))
        faligndata      %f14, %f0, %f30
-       EX_ST(STORE_BLK(%f16, %o0))
-       EX_LD(LOAD(ldd, %o1 + 0x018, %f6))
+       EX_ST_FP(STORE_BLK(%f16, %o0))
+       EX_LD_FP(LOAD(ldd, %o1 + 0x018, %f6))
        faligndata      %f0, %f2, %f16
-       EX_LD(LOAD(ldd, %o1 + 0x020, %f8))
+       EX_LD_FP(LOAD(ldd, %o1 + 0x020, %f8))
        faligndata      %f2, %f4, %f18
-       EX_LD(LOAD(ldd, %o1 + 0x028, %f10))
+       EX_LD_FP(LOAD(ldd, %o1 + 0x028, %f10))
        faligndata      %f4, %f6, %f20
-       EX_LD(LOAD(ldd, %o1 + 0x030, %f12))
+       EX_LD_FP(LOAD(ldd, %o1 + 0x030, %f12))
        faligndata      %f6, %f8, %f22
-       EX_LD(LOAD(ldd, %o1 + 0x038, %f14))
+       EX_LD_FP(LOAD(ldd, %o1 + 0x038, %f14))
        faligndata      %f8, %f10, %f24
        cmp             %g1, 0
        be,pt           %XCC, 1f
         add            %o0, 0x40, %o0
-       EX_LD(LOAD(ldd, %o1 + 0x040, %f0))
+       EX_LD_FP(LOAD(ldd, %o1 + 0x040, %f0))
 1:     faligndata      %f10, %f12, %f26
        faligndata      %f12, %f14, %f28
        faligndata      %f14, %f0, %f30
-       EX_ST(STORE_BLK(%f16, %o0))
+       EX_ST_FP(STORE_BLK(%f16, %o0))
        add             %o0, 0x40, %o0
        add             %o1, 0x40, %o1
        membar          #Sync
@@ -253,20 +259,20 @@ FUNC_NAME:        /* %o0=dst, %o1=src, %o2=len */
 
        sub             %o2, %g2, %o2
        be,a,pt         %XCC, 1f
-        EX_LD(LOAD(ldd, %o1 + 0x00, %f0))
+        EX_LD_FP(LOAD(ldd, %o1 + 0x00, %f0))
 
-1:     EX_LD(LOAD(ldd, %o1 + 0x08, %f2))
+1:     EX_LD_FP(LOAD(ldd, %o1 + 0x08, %f2))
        add             %o1, 0x8, %o1
        subcc           %g2, 0x8, %g2
        faligndata      %f0, %f2, %f8
-       EX_ST(STORE(std, %f8, %o0))
+       EX_ST_FP(STORE(std, %f8, %o0))
        be,pn           %XCC, 2f
         add            %o0, 0x8, %o0
-       EX_LD(LOAD(ldd, %o1 + 0x08, %f0))
+       EX_LD_FP(LOAD(ldd, %o1 + 0x08, %f0))
        add             %o1, 0x8, %o1
        subcc           %g2, 0x8, %g2
        faligndata      %f2, %f0, %f8
-       EX_ST(STORE(std, %f8, %o0))
+       EX_ST_FP(STORE(std, %f8, %o0))
        bne,pn          %XCC, 1b
         add            %o0, 0x8, %o0
 
index bb509cee3b598807eeae1aca6056e7adaed59e19..8767060d70fb32eb2dfc0a7da1010233973d78ea 100644 (file)
@@ -21,7 +21,7 @@
  *  Copyright (C) 2008-2009 Red Hat, Inc., Ingo Molnar
  *  Copyright (C) 2009 Jaswinder Singh Rajput
  *  Copyright (C) 2009 Advanced Micro Devices, Inc., Robert Richter
- *  Copyright (C) 2008-2009 Red Hat, Inc., Peter Zijlstra <pzijlstr@redhat.com>
+ *  Copyright (C) 2008-2009 Red Hat, Inc., Peter Zijlstra
  *  Copyright (C) 2009 Intel Corporation, <markus.t.metzger@intel.com>
  *  Copyright (C) 2009 Google, Inc., Stephane Eranian
  */
index 25ed4098640eecf5fc23ae5a8a494b7275badb4a..e3abe6f3156d3fbacca4003c072954619c7e1bb1 100644 (file)
@@ -131,7 +131,7 @@ export LDS_ELF_FORMAT := $(ELF_FORMAT)
 # The wrappers will select whether using "malloc" or the kernel allocator.
 LINK_WRAPS = -Wl,--wrap,malloc -Wl,--wrap,free -Wl,--wrap,calloc
 
-LD_FLAGS_CMDLINE = $(foreach opt,$(LDFLAGS),-Wl,$(opt)) -lrt
+LD_FLAGS_CMDLINE = $(foreach opt,$(LDFLAGS),-Wl,$(opt))
 
 # Used by link-vmlinux.sh which has special support for um link
 export CFLAGS_vmlinux := $(LINK-y) $(LINK_WRAPS) $(LD_FLAGS_CMDLINE)
index e697a4136707e13c609a5e51529f87631896b0c6..e9f8445861dc73639bb32742bb5f6fae327a8b4c 100644 (file)
@@ -249,21 +249,23 @@ void close_addr(unsigned char *addr, unsigned char *netmask, void *arg)
 
 char *split_if_spec(char *str, ...)
 {
-       char **arg, *end;
+       char **arg, *end, *ret = NULL;
        va_list ap;
 
        va_start(ap, str);
        while ((arg = va_arg(ap, char **)) != NULL) {
                if (*str == '\0')
-                       return NULL;
+                       goto out;
                end = strchr(str, ',');
                if (end != str)
                        *arg = str;
                if (end == NULL)
-                       return NULL;
+                       goto out;
                *end++ = '\0';
                str = end;
        }
+       ret = str;
+out:
        va_end(ap);
-       return str;
+       return ret;
 }
index 57acbd67d85dbd4051cd3c534ceff2a300ce9906..fc8be0e3a4ff879a2cf9fddc8e017dfa974ffc95 100644 (file)
@@ -69,7 +69,7 @@ void do_signal(struct pt_regs *regs)
        struct ksignal ksig;
        int handled_sig = 0;
 
-       while (get_signal(&ksig)) {
+       if (get_signal(&ksig)) {
                handled_sig = 1;
                /* Whee!  Actually deliver the signal.  */
                handle_signal(&ksig, regs);
index 0033e96c3f09c165e5745ca410048335de2106d7..9011a88353ded70ece09718a04349464ee8467ec 100644 (file)
@@ -23,7 +23,6 @@
 #include <stdarg.h>
 #include <linux/types.h>
 #include <linux/edd.h>
-#include <asm/boot.h>
 #include <asm/setup.h>
 #include "bitops.h"
 #include "ctype.h"
index aa8a96b052e30263d60afc6b81a60e387fc55773..95c7a818c0ed6929800f72fbb5d507fbc4539195 100644 (file)
@@ -19,6 +19,8 @@
 #include "video.h"
 #include "vesa.h"
 
+#include <uapi/asm/boot.h>
+
 /*
  * Common variables
  */
index 05111bb8d018e38c71ae278ee0a78ccff76e34e2..77780e386e9b224ef8ec5421af644abc65d1eebd 100644 (file)
@@ -13,6 +13,8 @@
  * Select video mode
  */
 
+#include <uapi/asm/boot.h>
+
 #include "boot.h"
 #include "video.h"
 #include "vesa.h"
index 53616ca0324440d6cba482c3855433b5a63b4ef9..a55697d19824727fda8306c566bb99cb4ba6d980 100644 (file)
@@ -509,6 +509,17 @@ END(irq_entries_start)
         * tracking that we're in kernel mode.
         */
        SWAPGS
+
+       /*
+        * We need to tell lockdep that IRQs are off.  We can't do this until
+        * we fix gsbase, and we should do it before enter_from_user_mode
+        * (which can take locks).  Since TRACE_IRQS_OFF idempotent,
+        * the simplest way to handle it is to just call it twice if
+        * we enter from user mode.  There's no reason to optimize this since
+        * TRACE_IRQS_OFF is a no-op if lockdep is off.
+        */
+       TRACE_IRQS_OFF
+
 #ifdef CONFIG_CONTEXT_TRACKING
        call enter_from_user_mode
 #endif
@@ -1049,12 +1060,18 @@ ENTRY(error_entry)
        SWAPGS
 
 .Lerror_entry_from_usermode_after_swapgs:
+       /*
+        * We need to tell lockdep that IRQs are off.  We can't do this until
+        * we fix gsbase, and we should do it before enter_from_user_mode
+        * (which can take locks).
+        */
+       TRACE_IRQS_OFF
 #ifdef CONFIG_CONTEXT_TRACKING
        call enter_from_user_mode
 #endif
+       ret
 
 .Lerror_entry_done:
-
        TRACE_IRQS_OFF
        ret
 
index 9f3905697f123200eb1f7ecc749239dc5d5e1b2d..690b4027e17c994fdef4a626f270ca8b97ee041a 100644 (file)
@@ -35,7 +35,7 @@
 #define MSR_IA32_PERFCTR0              0x000000c1
 #define MSR_IA32_PERFCTR1              0x000000c2
 #define MSR_FSB_FREQ                   0x000000cd
-#define MSR_NHM_PLATFORM_INFO          0x000000ce
+#define MSR_PLATFORM_INFO              0x000000ce
 
 #define MSR_NHM_SNB_PKG_CST_CFG_CTL    0x000000e2
 #define NHM_C3_AUTO_DEMOTE             (1UL << 25)
@@ -44,7 +44,6 @@
 #define SNB_C1_AUTO_UNDEMOTE           (1UL << 27)
 #define SNB_C3_AUTO_UNDEMOTE           (1UL << 28)
 
-#define MSR_PLATFORM_INFO              0x000000ce
 #define MSR_MTRRcap                    0x000000fe
 #define MSR_IA32_BBL_CR_CTL            0x00000119
 #define MSR_IA32_BBL_CR_CTL3           0x0000011e
index c5b7fb2774d08e17bad6966933e2d753c6de92ec..cc071c6f7d4da2847b3df2c4cbf7666edde5675b 100644 (file)
@@ -9,19 +9,21 @@
 #define PAGE_SIZE      (_AC(1,UL) << PAGE_SHIFT)
 #define PAGE_MASK      (~(PAGE_SIZE-1))
 
+#define PMD_PAGE_SIZE          (_AC(1, UL) << PMD_SHIFT)
+#define PMD_PAGE_MASK          (~(PMD_PAGE_SIZE-1))
+
+#define PUD_PAGE_SIZE          (_AC(1, UL) << PUD_SHIFT)
+#define PUD_PAGE_MASK          (~(PUD_PAGE_SIZE-1))
+
 #define __PHYSICAL_MASK                ((phys_addr_t)((1ULL << __PHYSICAL_MASK_SHIFT) - 1))
 #define __VIRTUAL_MASK         ((1UL << __VIRTUAL_MASK_SHIFT) - 1)
 
-/* Cast PAGE_MASK to a signed type so that it is sign-extended if
+/* Cast *PAGE_MASK to a signed type so that it is sign-extended if
    virtual addresses are 32-bits but physical addresses are larger
    (ie, 32-bit PAE). */
 #define PHYSICAL_PAGE_MASK     (((signed long)PAGE_MASK) & __PHYSICAL_MASK)
-
-#define PMD_PAGE_SIZE          (_AC(1, UL) << PMD_SHIFT)
-#define PMD_PAGE_MASK          (~(PMD_PAGE_SIZE-1))
-
-#define PUD_PAGE_SIZE          (_AC(1, UL) << PUD_SHIFT)
-#define PUD_PAGE_MASK          (~(PUD_PAGE_SIZE-1))
+#define PHYSICAL_PMD_PAGE_MASK (((signed long)PMD_PAGE_MASK) & __PHYSICAL_MASK)
+#define PHYSICAL_PUD_PAGE_MASK (((signed long)PUD_PAGE_MASK) & __PHYSICAL_MASK)
 
 #define HPAGE_SHIFT            PMD_SHIFT
 #define HPAGE_SIZE             (_AC(1,UL) << HPAGE_SHIFT)
index dd5b0aa9dd2f93a01b554029ebc243aa56ae91d3..a471cadb9630e7b8f46340139efaf4f467a24aff 100644 (file)
@@ -279,17 +279,14 @@ static inline pmdval_t native_pmd_val(pmd_t pmd)
 static inline pudval_t pud_pfn_mask(pud_t pud)
 {
        if (native_pud_val(pud) & _PAGE_PSE)
-               return PUD_PAGE_MASK & PHYSICAL_PAGE_MASK;
+               return PHYSICAL_PUD_PAGE_MASK;
        else
                return PTE_PFN_MASK;
 }
 
 static inline pudval_t pud_flags_mask(pud_t pud)
 {
-       if (native_pud_val(pud) & _PAGE_PSE)
-               return ~(PUD_PAGE_MASK & (pudval_t)PHYSICAL_PAGE_MASK);
-       else
-               return ~PTE_PFN_MASK;
+       return ~pud_pfn_mask(pud);
 }
 
 static inline pudval_t pud_flags(pud_t pud)
@@ -300,17 +297,14 @@ static inline pudval_t pud_flags(pud_t pud)
 static inline pmdval_t pmd_pfn_mask(pmd_t pmd)
 {
        if (native_pmd_val(pmd) & _PAGE_PSE)
-               return PMD_PAGE_MASK & PHYSICAL_PAGE_MASK;
+               return PHYSICAL_PMD_PAGE_MASK;
        else
                return PTE_PFN_MASK;
 }
 
 static inline pmdval_t pmd_flags_mask(pmd_t pmd)
 {
-       if (native_pmd_val(pmd) & _PAGE_PSE)
-               return ~(PMD_PAGE_MASK & (pmdval_t)PHYSICAL_PAGE_MASK);
-       else
-               return ~PTE_PFN_MASK;
+       return ~pmd_pfn_mask(pmd);
 }
 
 static inline pmdval_t pmd_flags(pmd_t pmd)
index 7249e6d0902da572fe635cf9a7af35d72cec62f4..5973a2f3db3d709dabc0c88171aecf6f65c4466a 100644 (file)
@@ -55,6 +55,7 @@ enum sst_audio_device_id_mrfld {
        PIPE_MEDIA0_IN = 0x8F,
        PIPE_MEDIA1_IN = 0x90,
        PIPE_MEDIA2_IN = 0x91,
+       PIPE_MEDIA3_IN = 0x9C,
        PIPE_RSVD = 0xFF,
 };
 
index 48d34d28f5a60543bc72471e2a1931fcf13dc04e..cd0fc0cc78bc34f1d378c844baf6007ce60c1797 100644 (file)
@@ -1,7 +1,6 @@
 #ifndef _ASM_X86_PLATFORM_H
 #define _ASM_X86_PLATFORM_H
 
-#include <asm/pgtable_types.h>
 #include <asm/bootparam.h>
 
 struct mpc_bus;
index 4ddd780aeac90ab353134453316dc18108c8b308..c2b7522cbf357617bf8302f3c4f964834b940926 100644 (file)
@@ -273,10 +273,9 @@ __setup("nosmap", setup_disable_smap);
 
 static __always_inline void setup_smap(struct cpuinfo_x86 *c)
 {
-       unsigned long eflags;
+       unsigned long eflags = native_save_fl();
 
        /* This should have been cleared long ago */
-       raw_local_save_flags(eflags);
        BUG_ON(eflags & X86_EFLAGS_AC);
 
        if (cpu_has(c, X86_FEATURE_SMAP)) {
index 7fc27f1cca586a1752d95fa73c612db03db78437..b3e94ef461fddcea5c6d5696eb012b6c9c89edc8 100644 (file)
@@ -698,3 +698,4 @@ int __init microcode_init(void)
        return error;
 
 }
+late_initcall(microcode_init);
index 4562cf070c279d5edeb0e18ae94c8bff94166dd8..2bf79d7c97dfb8848b1e7b060a66ddedb4605a1a 100644 (file)
@@ -5,7 +5,7 @@
  *  Copyright (C) 2008-2009 Red Hat, Inc., Ingo Molnar
  *  Copyright (C) 2009 Jaswinder Singh Rajput
  *  Copyright (C) 2009 Advanced Micro Devices, Inc., Robert Richter
- *  Copyright (C) 2008-2009 Red Hat, Inc., Peter Zijlstra <pzijlstr@redhat.com>
+ *  Copyright (C) 2008-2009 Red Hat, Inc., Peter Zijlstra
  *  Copyright (C) 2009 Intel Corporation, <markus.t.metzger@intel.com>
  *  Copyright (C) 2009 Google, Inc., Stephane Eranian
  *
index 499f533dd3ccbd22bb84423649e031f2759080ca..d0e35ebb2adb1d34b526fcb04b2bc192c643fd55 100644 (file)
@@ -5,7 +5,7 @@
  *  Copyright (C) 2008-2009 Red Hat, Inc., Ingo Molnar
  *  Copyright (C) 2009 Jaswinder Singh Rajput
  *  Copyright (C) 2009 Advanced Micro Devices, Inc., Robert Richter
- *  Copyright (C) 2008-2009 Red Hat, Inc., Peter Zijlstra <pzijlstr@redhat.com>
+ *  Copyright (C) 2008-2009 Red Hat, Inc., Peter Zijlstra
  *  Copyright (C) 2009 Intel Corporation, <markus.t.metzger@intel.com>
  *  Copyright (C) 2009 Google, Inc., Stephane Eranian
  *
@@ -387,7 +387,7 @@ struct cpu_hw_events {
 /* Check flags and event code/umask, and set the HSW N/A flag */
 #define INTEL_FLAGS_UEVENT_CONSTRAINT_DATALA_NA(code, n) \
        __EVENT_CONSTRAINT(code, n,                     \
-                         INTEL_ARCH_EVENT_MASK|INTEL_ARCH_EVENT_MASK, \
+                         INTEL_ARCH_EVENT_MASK|X86_ALL_EVENT_FLAGS, \
                          HWEIGHT(n), 0, PERF_X86_EVENT_PEBS_NA_HSW)
 
 
@@ -627,6 +627,7 @@ struct x86_perf_task_context {
        u64 lbr_from[MAX_LBR_ENTRIES];
        u64 lbr_to[MAX_LBR_ENTRIES];
        u64 lbr_info[MAX_LBR_ENTRIES];
+       int tos;
        int lbr_callstack_users;
        int lbr_stack_state;
 };
index f63360be22387d4fb4cb30728f1834ee4cbd6228..e2a430021e46e71eb2904af74ae5a7d50653d048 100644 (file)
@@ -232,7 +232,7 @@ static struct event_constraint intel_hsw_event_constraints[] = {
        FIXED_EVENT_CONSTRAINT(0x00c0, 0), /* INST_RETIRED.ANY */
        FIXED_EVENT_CONSTRAINT(0x003c, 1), /* CPU_CLK_UNHALTED.CORE */
        FIXED_EVENT_CONSTRAINT(0x0300, 2), /* CPU_CLK_UNHALTED.REF */
-       INTEL_EVENT_CONSTRAINT(0x48, 0x4), /* L1D_PEND_MISS.* */
+       INTEL_UEVENT_CONSTRAINT(0x148, 0x4),    /* L1D_PEND_MISS.PENDING */
        INTEL_UEVENT_CONSTRAINT(0x01c0, 0x2), /* INST_RETIRED.PREC_DIST */
        INTEL_EVENT_CONSTRAINT(0xcd, 0x8), /* MEM_TRANS_RETIRED.LOAD_LATENCY */
        /* CYCLE_ACTIVITY.CYCLES_L1D_PENDING */
index 377e8f8ed39186ad4ef57b33264592ed8459a037..a316ca96f1b639d8a0f58f616c1c62d4da61bfdf 100644 (file)
@@ -298,7 +298,7 @@ static bool __match_event(struct perf_event *a, struct perf_event *b)
 static inline struct perf_cgroup *event_to_cgroup(struct perf_event *event)
 {
        if (event->attach_state & PERF_ATTACH_TASK)
-               return perf_cgroup_from_task(event->hw.target);
+               return perf_cgroup_from_task(event->hw.target, event->ctx);
 
        return event->cgrp;
 }
index bfd0b717e944ce012b7a0abe19c89f5294d284e1..659f01e165d57520f33b09ba68818f72cd206a4d 100644 (file)
@@ -239,7 +239,7 @@ static void __intel_pmu_lbr_restore(struct x86_perf_task_context *task_ctx)
        }
 
        mask = x86_pmu.lbr_nr - 1;
-       tos = intel_pmu_lbr_tos();
+       tos = task_ctx->tos;
        for (i = 0; i < tos; i++) {
                lbr_idx = (tos - i) & mask;
                wrmsrl(x86_pmu.lbr_from + lbr_idx, task_ctx->lbr_from[i]);
@@ -247,6 +247,7 @@ static void __intel_pmu_lbr_restore(struct x86_perf_task_context *task_ctx)
                if (x86_pmu.intel_cap.lbr_format == LBR_FORMAT_INFO)
                        wrmsrl(MSR_LBR_INFO_0 + lbr_idx, task_ctx->lbr_info[i]);
        }
+       wrmsrl(x86_pmu.lbr_tos, tos);
        task_ctx->lbr_stack_state = LBR_NONE;
 }
 
@@ -270,6 +271,7 @@ static void __intel_pmu_lbr_save(struct x86_perf_task_context *task_ctx)
                if (x86_pmu.intel_cap.lbr_format == LBR_FORMAT_INFO)
                        rdmsrl(MSR_LBR_INFO_0 + lbr_idx, task_ctx->lbr_info[i]);
        }
+       task_ctx->tos = tos;
        task_ctx->lbr_stack_state = LBR_VALID;
 }
 
index ef29b742cea79a99c8e653ea91ae83e82b08ba65..31c6a60505e6bc6e5acb84df728d45f73ef701aa 100644 (file)
@@ -385,20 +385,19 @@ fpu__alloc_mathframe(unsigned long sp, int ia32_frame,
  */
 void fpu__init_prepare_fx_sw_frame(void)
 {
-       int fsave_header_size = sizeof(struct fregs_state);
        int size = xstate_size + FP_XSTATE_MAGIC2_SIZE;
 
-       if (config_enabled(CONFIG_X86_32))
-               size += fsave_header_size;
-
        fx_sw_reserved.magic1 = FP_XSTATE_MAGIC1;
        fx_sw_reserved.extended_size = size;
        fx_sw_reserved.xfeatures = xfeatures_mask;
        fx_sw_reserved.xstate_size = xstate_size;
 
-       if (config_enabled(CONFIG_IA32_EMULATION)) {
+       if (config_enabled(CONFIG_IA32_EMULATION) ||
+           config_enabled(CONFIG_X86_32)) {
+               int fsave_header_size = sizeof(struct fregs_state);
+
                fx_sw_reserved_ia32 = fx_sw_reserved;
-               fx_sw_reserved_ia32.extended_size += fsave_header_size;
+               fx_sw_reserved_ia32.extended_size = size + fsave_header_size;
        }
 }
 
index 6454f2731b5666e49aeda8f87d96078d564de2f2..70fc312221fc6b6c3223673c0328dfdc73c59ea6 100644 (file)
@@ -694,7 +694,6 @@ void *get_xsave_addr(struct xregs_state *xsave, int xstate_feature)
        if (!boot_cpu_has(X86_FEATURE_XSAVE))
                return NULL;
 
-       xsave = &current->thread.fpu.state.xsave;
        /*
         * We should not ever be requesting features that we
         * have not enabled.  Remember that pcntxt_mask is
index dc5fa6a1e8d640aa8fc407ee3035feb0a1778451..3512ba607361403e587f417cbce2775cdec428a1 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * x86 specific code for irq_work
  *
- * Copyright (C) 2010 Red Hat, Inc., Peter Zijlstra <pzijlstr@redhat.com>
+ * Copyright (C) 2010 Red Hat, Inc., Peter Zijlstra
  */
 
 #include <linux/kernel.h>
index 94ea120fa21ff7a9de85cc123054e9d2133b2305..87e1762e2bca74a3f22004d09d9069d72b41b62b 100644 (file)
@@ -278,6 +278,12 @@ trace:
        /* save_mcount_regs fills in first two parameters */
        save_mcount_regs
 
+       /*
+        * When DYNAMIC_FTRACE is not defined, ARCH_SUPPORTS_FTRACE_OPS is not
+        * set (see include/asm/ftrace.h and include/linux/ftrace.h).  Only the
+        * ip and parent ip are used and the list function is called when
+        * function tracing is enabled.
+        */
        call   *ftrace_trace_function
 
        restore_mcount_regs
index 4f00b63d7ff33bea8f0016eaa8393d8cb6972fad..14415aff18136524cfa3d4c9b07bdde6ee0d6f54 100644 (file)
@@ -4,10 +4,22 @@
  */
 #include <linux/platform_device.h>
 #include <linux/module.h>
+#include <linux/ioport.h>
+
+static int found(u64 start, u64 end, void *data)
+{
+       return 1;
+}
 
 static __init int register_e820_pmem(void)
 {
+       char *pmem = "Persistent Memory (legacy)";
        struct platform_device *pdev;
+       int rc;
+
+       rc = walk_iomem_res(pmem, IORESOURCE_MEM, 0, -1, NULL, found);
+       if (rc <= 0)
+               return 0;
 
        /*
         * See drivers/nvdimm/e820.c for the implementation, this is
index 29db25f9a745ee11d23867cc974438817a6e5b15..d2bbe343fda74a87307675b3a65704e2cc96769b 100644 (file)
@@ -1250,8 +1250,6 @@ void __init setup_arch(char **cmdline_p)
        if (efi_enabled(EFI_BOOT))
                efi_apply_memmap_quirks();
 #endif
-
-       microcode_init();
 }
 
 #ifdef CONFIG_X86_32
index b7ffb7c00075787532ceec10b6aed0028ea01b5c..cb6282c3638ffbd32bcb33663d8cefc17eac8a8e 100644 (file)
@@ -690,12 +690,15 @@ handle_signal(struct ksignal *ksig, struct pt_regs *regs)
        signal_setup_done(failed, ksig, stepping);
 }
 
-#ifdef CONFIG_X86_32
-#define NR_restart_syscall     __NR_restart_syscall
-#else /* !CONFIG_X86_32 */
-#define NR_restart_syscall     \
-       test_thread_flag(TIF_IA32) ? __NR_ia32_restart_syscall : __NR_restart_syscall
-#endif /* CONFIG_X86_32 */
+static inline unsigned long get_nr_restart_syscall(const struct pt_regs *regs)
+{
+#if defined(CONFIG_X86_32) || !defined(CONFIG_X86_64)
+       return __NR_restart_syscall;
+#else /* !CONFIG_X86_32 && CONFIG_X86_64 */
+       return test_thread_flag(TIF_IA32) ? __NR_ia32_restart_syscall :
+               __NR_restart_syscall | (regs->orig_ax & __X32_SYSCALL_BIT);
+#endif /* CONFIG_X86_32 || !CONFIG_X86_64 */
+}
 
 /*
  * Note that 'init' is a special process: it doesn't get signals it doesn't
@@ -724,7 +727,7 @@ void do_signal(struct pt_regs *regs)
                        break;
 
                case -ERESTART_RESTARTBLOCK:
-                       regs->ax = NR_restart_syscall;
+                       regs->ax = get_nr_restart_syscall(regs);
                        regs->ip -= 2;
                        break;
                }
index 892ee2e5ecbce417df506715f7b28d28c403ef91..fbabe4fcc7fbb71802c756289ac01df9b11599ec 100644 (file)
@@ -509,7 +509,7 @@ void __inquire_remote_apic(int apicid)
  */
 #define UDELAY_10MS_DEFAULT 10000
 
-static unsigned int init_udelay = INT_MAX;
+static unsigned int init_udelay = UINT_MAX;
 
 static int __init cpu_init_udelay(char *str)
 {
@@ -522,14 +522,15 @@ early_param("cpu_init_udelay", cpu_init_udelay);
 static void __init smp_quirk_init_udelay(void)
 {
        /* if cmdline changed it from default, leave it alone */
-       if (init_udelay != INT_MAX)
+       if (init_udelay != UINT_MAX)
                return;
 
        /* if modern processor, use no delay */
        if (((boot_cpu_data.x86_vendor == X86_VENDOR_INTEL) && (boot_cpu_data.x86 == 6)) ||
-           ((boot_cpu_data.x86_vendor == X86_VENDOR_AMD) && (boot_cpu_data.x86 >= 0xF)))
+           ((boot_cpu_data.x86_vendor == X86_VENDOR_AMD) && (boot_cpu_data.x86 >= 0xF))) {
                init_udelay = 0;
-
+               return;
+       }
        /* else, use legacy delay */
        init_udelay = UDELAY_10MS_DEFAULT;
 }
index 06332cb7e7d1d79c5af04eba698ad8642c2762b5..3f5c48ddba453064ff6dbe91731d1d0c7776be53 100644 (file)
@@ -38,6 +38,14 @@ static inline bool guest_cpuid_has_xsave(struct kvm_vcpu *vcpu)
        return best && (best->ecx & bit(X86_FEATURE_XSAVE));
 }
 
+static inline bool guest_cpuid_has_mtrr(struct kvm_vcpu *vcpu)
+{
+       struct kvm_cpuid_entry2 *best;
+
+       best = kvm_find_cpuid_entry(vcpu, 1, 0);
+       return best && (best->edx & bit(X86_FEATURE_MTRR));
+}
+
 static inline bool guest_cpuid_has_tsc_adjust(struct kvm_vcpu *vcpu)
 {
        struct kvm_cpuid_entry2 *best;
index 9e8bf13572e6dc3f95d33d24f079d63e256a3a7a..3f8c732117eccf73140fded817e1b155dfa76073 100644 (file)
@@ -120,14 +120,22 @@ static u8 mtrr_default_type(struct kvm_mtrr *mtrr_state)
        return mtrr_state->deftype & IA32_MTRR_DEF_TYPE_TYPE_MASK;
 }
 
-static u8 mtrr_disabled_type(void)
+static u8 mtrr_disabled_type(struct kvm_vcpu *vcpu)
 {
        /*
         * Intel SDM 11.11.2.2: all MTRRs are disabled when
         * IA32_MTRR_DEF_TYPE.E bit is cleared, and the UC
         * memory type is applied to all of physical memory.
+        *
+        * However, virtual machines can be run with CPUID such that
+        * there are no MTRRs.  In that case, the firmware will never
+        * enable MTRRs and it is obviously undesirable to run the
+        * guest entirely with UC memory and we use WB.
         */
-       return MTRR_TYPE_UNCACHABLE;
+       if (guest_cpuid_has_mtrr(vcpu))
+               return MTRR_TYPE_UNCACHABLE;
+       else
+               return MTRR_TYPE_WRBACK;
 }
 
 /*
@@ -267,7 +275,7 @@ static int fixed_mtrr_addr_to_seg(u64 addr)
 
        for (seg = 0; seg < seg_num; seg++) {
                mtrr_seg = &fixed_seg_table[seg];
-               if (mtrr_seg->start >= addr && addr < mtrr_seg->end)
+               if (mtrr_seg->start <= addr && addr < mtrr_seg->end)
                        return seg;
        }
 
@@ -300,7 +308,6 @@ static void var_mtrr_range(struct kvm_mtrr_range *range, u64 *start, u64 *end)
        *start = range->base & PAGE_MASK;
 
        mask = range->mask & PAGE_MASK;
-       mask |= ~0ULL << boot_cpu_data.x86_phys_bits;
 
        /* This cannot overflow because writing to the reserved bits of
         * variable MTRRs causes a #GP.
@@ -356,10 +363,14 @@ static void set_var_mtrr_msr(struct kvm_vcpu *vcpu, u32 msr, u64 data)
        if (var_mtrr_range_is_valid(cur))
                list_del(&mtrr_state->var_ranges[index].node);
 
+       /* Extend the mask with all 1 bits to the left, since those
+        * bits must implicitly be 0.  The bits are then cleared
+        * when reading them.
+        */
        if (!is_mtrr_mask)
                cur->base = data;
        else
-               cur->mask = data;
+               cur->mask = data | (-1LL << cpuid_maxphyaddr(vcpu));
 
        /* add it to the list if it's enabled. */
        if (var_mtrr_range_is_valid(cur)) {
@@ -426,6 +437,8 @@ int kvm_mtrr_get_msr(struct kvm_vcpu *vcpu, u32 msr, u64 *pdata)
                        *pdata = vcpu->arch.mtrr_state.var_ranges[index].base;
                else
                        *pdata = vcpu->arch.mtrr_state.var_ranges[index].mask;
+
+               *pdata &= (1ULL << cpuid_maxphyaddr(vcpu)) - 1;
        }
 
        return 0;
@@ -670,7 +683,7 @@ u8 kvm_mtrr_get_guest_memory_type(struct kvm_vcpu *vcpu, gfn_t gfn)
        }
 
        if (iter.mtrr_disabled)
-               return mtrr_disabled_type();
+               return mtrr_disabled_type(vcpu);
 
        /* not contained in any MTRRs. */
        if (type == -1)
index 83a1c643f9a50fd3fa0ffc041c40d9f4d25aa5b5..899c40f826dd9a5f10c57e0758153cdbb1d9f1a6 100644 (file)
@@ -3422,6 +3422,8 @@ static int handle_exit(struct kvm_vcpu *vcpu)
        struct kvm_run *kvm_run = vcpu->run;
        u32 exit_code = svm->vmcb->control.exit_code;
 
+       trace_kvm_exit(exit_code, vcpu, KVM_ISA_SVM);
+
        if (!is_cr_intercept(svm, INTERCEPT_CR0_WRITE))
                vcpu->arch.cr0 = svm->vmcb->save.cr0;
        if (npt_enabled)
@@ -3892,8 +3894,6 @@ static void svm_vcpu_run(struct kvm_vcpu *vcpu)
        vcpu->arch.regs[VCPU_REGS_RSP] = svm->vmcb->save.rsp;
        vcpu->arch.regs[VCPU_REGS_RIP] = svm->vmcb->save.rip;
 
-       trace_kvm_exit(svm->vmcb->control.exit_code, vcpu, KVM_ISA_SVM);
-
        if (unlikely(svm->vmcb->control.exit_code == SVM_EXIT_NMI))
                kvm_before_handle_nmi(&svm->vcpu);
 
index 87acc5221740a588d256f9f0ed4059d366165872..44976a596fa65d2ca90421a7f7f06cfb2d0b17be 100644 (file)
@@ -2803,7 +2803,7 @@ static int vmx_get_msr(struct kvm_vcpu *vcpu, struct msr_data *msr_info)
                msr_info->data = vcpu->arch.ia32_xss;
                break;
        case MSR_TSC_AUX:
-               if (!guest_cpuid_has_rdtscp(vcpu))
+               if (!guest_cpuid_has_rdtscp(vcpu) && !msr_info->host_initiated)
                        return 1;
                /* Otherwise falls through */
        default:
@@ -2909,7 +2909,7 @@ static int vmx_set_msr(struct kvm_vcpu *vcpu, struct msr_data *msr_info)
                        clear_atomic_switch_msr(vmx, MSR_IA32_XSS);
                break;
        case MSR_TSC_AUX:
-               if (!guest_cpuid_has_rdtscp(vcpu))
+               if (!guest_cpuid_has_rdtscp(vcpu) && !msr_info->host_initiated)
                        return 1;
                /* Check reserved bit, higher 32 bits should be zero */
                if ((data >> 32) != 0)
@@ -7394,11 +7394,6 @@ static int handle_invvpid(struct kvm_vcpu *vcpu)
 
        switch (type) {
        case VMX_VPID_EXTENT_ALL_CONTEXT:
-               if (get_vmcs12(vcpu)->virtual_processor_id == 0) {
-                       nested_vmx_failValid(vcpu,
-                               VMXERR_INVALID_OPERAND_TO_INVEPT_INVVPID);
-                       return 1;
-               }
                __vmx_flush_tlb(vcpu, to_vmx(vcpu)->nested.vpid02);
                nested_vmx_succeed(vcpu);
                break;
@@ -8047,6 +8042,8 @@ static int vmx_handle_exit(struct kvm_vcpu *vcpu)
        u32 exit_reason = vmx->exit_reason;
        u32 vectoring_info = vmx->idt_vectoring_info;
 
+       trace_kvm_exit(exit_reason, vcpu, KVM_ISA_VMX);
+
        /*
         * Flush logged GPAs PML buffer, this will make dirty_bitmap more
         * updated. Another good is, in kvm_vm_ioctl_get_dirty_log, before
@@ -8673,7 +8670,6 @@ static void __noclone vmx_vcpu_run(struct kvm_vcpu *vcpu)
        vmx->loaded_vmcs->launched = 1;
 
        vmx->exit_reason = vmcs_read32(VM_EXIT_REASON);
-       trace_kvm_exit(vmx->exit_reason, vcpu, KVM_ISA_VMX);
 
        /*
         * the KVM_REQ_EVENT optimization bit is only on for one entry, and if
index 00462bd63129cfbde2c6b7e7bdf50eb073cc31b8..7ffc224bbe4127a90ef7741f09ae94f75e17feec 100644 (file)
@@ -2763,6 +2763,26 @@ static int kvm_vcpu_ioctl_set_lapic(struct kvm_vcpu *vcpu,
        return 0;
 }
 
+static int kvm_cpu_accept_dm_intr(struct kvm_vcpu *vcpu)
+{
+       return (!lapic_in_kernel(vcpu) ||
+               kvm_apic_accept_pic_intr(vcpu));
+}
+
+/*
+ * if userspace requested an interrupt window, check that the
+ * interrupt window is open.
+ *
+ * No need to exit to userspace if we already have an interrupt queued.
+ */
+static int kvm_vcpu_ready_for_interrupt_injection(struct kvm_vcpu *vcpu)
+{
+       return kvm_arch_interrupt_allowed(vcpu) &&
+               !kvm_cpu_has_interrupt(vcpu) &&
+               !kvm_event_needs_reinjection(vcpu) &&
+               kvm_cpu_accept_dm_intr(vcpu);
+}
+
 static int kvm_vcpu_ioctl_interrupt(struct kvm_vcpu *vcpu,
                                    struct kvm_interrupt *irq)
 {
@@ -2786,6 +2806,7 @@ static int kvm_vcpu_ioctl_interrupt(struct kvm_vcpu *vcpu,
                return -EEXIST;
 
        vcpu->arch.pending_external_vector = irq->irq;
+       kvm_make_request(KVM_REQ_EVENT, vcpu);
        return 0;
 }
 
@@ -3551,9 +3572,11 @@ static int kvm_vm_ioctl_get_pit(struct kvm *kvm, struct kvm_pit_state *ps)
 
 static int kvm_vm_ioctl_set_pit(struct kvm *kvm, struct kvm_pit_state *ps)
 {
+       int i;
        mutex_lock(&kvm->arch.vpit->pit_state.lock);
        memcpy(&kvm->arch.vpit->pit_state, ps, sizeof(struct kvm_pit_state));
-       kvm_pit_load_count(kvm, 0, ps->channels[0].count, 0);
+       for (i = 0; i < 3; i++)
+               kvm_pit_load_count(kvm, i, ps->channels[i].count, 0);
        mutex_unlock(&kvm->arch.vpit->pit_state.lock);
        return 0;
 }
@@ -3572,6 +3595,7 @@ static int kvm_vm_ioctl_get_pit2(struct kvm *kvm, struct kvm_pit_state2 *ps)
 static int kvm_vm_ioctl_set_pit2(struct kvm *kvm, struct kvm_pit_state2 *ps)
 {
        int start = 0;
+       int i;
        u32 prev_legacy, cur_legacy;
        mutex_lock(&kvm->arch.vpit->pit_state.lock);
        prev_legacy = kvm->arch.vpit->pit_state.flags & KVM_PIT_FLAGS_HPET_LEGACY;
@@ -3581,7 +3605,8 @@ static int kvm_vm_ioctl_set_pit2(struct kvm *kvm, struct kvm_pit_state2 *ps)
        memcpy(&kvm->arch.vpit->pit_state.channels, &ps->channels,
               sizeof(kvm->arch.vpit->pit_state.channels));
        kvm->arch.vpit->pit_state.flags = ps->flags;
-       kvm_pit_load_count(kvm, 0, kvm->arch.vpit->pit_state.channels[0].count, start);
+       for (i = 0; i < 3; i++)
+               kvm_pit_load_count(kvm, i, kvm->arch.vpit->pit_state.channels[i].count, start);
        mutex_unlock(&kvm->arch.vpit->pit_state.lock);
        return 0;
 }
@@ -5910,23 +5935,10 @@ static int emulator_fix_hypercall(struct x86_emulate_ctxt *ctxt)
        return emulator_write_emulated(ctxt, rip, instruction, 3, NULL);
 }
 
-/*
- * Check if userspace requested an interrupt window, and that the
- * interrupt window is open.
- *
- * No need to exit to userspace if we already have an interrupt queued.
- */
 static int dm_request_for_irq_injection(struct kvm_vcpu *vcpu)
 {
-       if (!vcpu->run->request_interrupt_window || pic_in_kernel(vcpu->kvm))
-               return false;
-
-       if (kvm_cpu_has_interrupt(vcpu))
-               return false;
-
-       return (irqchip_split(vcpu->kvm)
-               ? kvm_apic_accept_pic_intr(vcpu)
-               : kvm_arch_interrupt_allowed(vcpu));
+       return vcpu->run->request_interrupt_window &&
+               likely(!pic_in_kernel(vcpu->kvm));
 }
 
 static void post_kvm_run_save(struct kvm_vcpu *vcpu)
@@ -5937,17 +5949,9 @@ static void post_kvm_run_save(struct kvm_vcpu *vcpu)
        kvm_run->flags = is_smm(vcpu) ? KVM_RUN_X86_SMM : 0;
        kvm_run->cr8 = kvm_get_cr8(vcpu);
        kvm_run->apic_base = kvm_get_apic_base(vcpu);
-       if (!irqchip_in_kernel(vcpu->kvm))
-               kvm_run->ready_for_interrupt_injection =
-                       kvm_arch_interrupt_allowed(vcpu) &&
-                       !kvm_cpu_has_interrupt(vcpu) &&
-                       !kvm_event_needs_reinjection(vcpu);
-       else if (!pic_in_kernel(vcpu->kvm))
-               kvm_run->ready_for_interrupt_injection =
-                       kvm_apic_accept_pic_intr(vcpu) &&
-                       !kvm_cpu_has_interrupt(vcpu);
-       else
-               kvm_run->ready_for_interrupt_injection = 1;
+       kvm_run->ready_for_interrupt_injection =
+               pic_in_kernel(vcpu->kvm) ||
+               kvm_vcpu_ready_for_interrupt_injection(vcpu);
 }
 
 static void update_cr8_intercept(struct kvm_vcpu *vcpu)
@@ -6360,8 +6364,10 @@ void kvm_arch_mmu_notifier_invalidate_page(struct kvm *kvm,
 static int vcpu_enter_guest(struct kvm_vcpu *vcpu)
 {
        int r;
-       bool req_int_win = !lapic_in_kernel(vcpu) &&
-               vcpu->run->request_interrupt_window;
+       bool req_int_win =
+               dm_request_for_irq_injection(vcpu) &&
+               kvm_cpu_accept_dm_intr(vcpu);
+
        bool req_immediate_exit = false;
 
        if (vcpu->requests) {
@@ -6513,6 +6519,8 @@ static int vcpu_enter_guest(struct kvm_vcpu *vcpu)
        if (req_immediate_exit)
                smp_send_reschedule(vcpu->cpu);
 
+       trace_kvm_entry(vcpu->vcpu_id);
+       wait_lapic_expire(vcpu);
        __kvm_guest_enter();
 
        if (unlikely(vcpu->arch.switch_db_regs)) {
@@ -6525,8 +6533,6 @@ static int vcpu_enter_guest(struct kvm_vcpu *vcpu)
                vcpu->arch.switch_db_regs &= ~KVM_DEBUGREG_RELOAD;
        }
 
-       trace_kvm_entry(vcpu->vcpu_id);
-       wait_lapic_expire(vcpu);
        kvm_x86_ops->run(vcpu);
 
        /*
@@ -6663,7 +6669,8 @@ static int vcpu_run(struct kvm_vcpu *vcpu)
                if (kvm_cpu_has_pending_timer(vcpu))
                        kvm_inject_pending_timer_irqs(vcpu);
 
-               if (dm_request_for_irq_injection(vcpu)) {
+               if (dm_request_for_irq_injection(vcpu) &&
+                       kvm_vcpu_ready_for_interrupt_injection(vcpu)) {
                        r = 0;
                        vcpu->run->exit_reason = KVM_EXIT_IRQ_WINDOW_OPEN;
                        ++vcpu->stat.request_irq_exits;
index a035c2aa780190c8c198e1bd8c2bec20a18d8ecb..0f1c6fc3ddd88948646963772ac0fa12c492c212 100644 (file)
@@ -89,7 +89,7 @@ static struct addr_marker address_markers[] = {
        { 0/* VMALLOC_START */, "vmalloc() Area" },
        { 0/*VMALLOC_END*/,     "vmalloc() End" },
 # ifdef CONFIG_HIGHMEM
-       { 0/*PKMAP_BASE*/,      "Persisent kmap() Area" },
+       { 0/*PKMAP_BASE*/,      "Persistent kmap() Area" },
 # endif
        { 0/*FIXADDR_START*/,   "Fixmap Area" },
 #endif
index b0ae85f90f10acecc2898e7d19d06ddb6196db57..b2fd67da1701433d9168ebf1d0a908330544bd7d 100644 (file)
@@ -101,19 +101,19 @@ static int get_reg_offset(struct insn *insn, struct pt_regs *regs,
        switch (type) {
        case REG_TYPE_RM:
                regno = X86_MODRM_RM(insn->modrm.value);
-               if (X86_REX_B(insn->rex_prefix.value) == 1)
+               if (X86_REX_B(insn->rex_prefix.value))
                        regno += 8;
                break;
 
        case REG_TYPE_INDEX:
                regno = X86_SIB_INDEX(insn->sib.value);
-               if (X86_REX_X(insn->rex_prefix.value) == 1)
+               if (X86_REX_X(insn->rex_prefix.value))
                        regno += 8;
                break;
 
        case REG_TYPE_BASE:
                regno = X86_SIB_BASE(insn->sib.value);
-               if (X86_REX_B(insn->rex_prefix.value) == 1)
+               if (X86_REX_B(insn->rex_prefix.value))
                        regno += 8;
                break;
 
@@ -585,6 +585,29 @@ static unsigned long mpx_bd_entry_to_bt_addr(struct mm_struct *mm,
        return bt_addr;
 }
 
+/*
+ * We only want to do a 4-byte get_user() on 32-bit.  Otherwise,
+ * we might run off the end of the bounds table if we are on
+ * a 64-bit kernel and try to get 8 bytes.
+ */
+int get_user_bd_entry(struct mm_struct *mm, unsigned long *bd_entry_ret,
+               long __user *bd_entry_ptr)
+{
+       u32 bd_entry_32;
+       int ret;
+
+       if (is_64bit_mm(mm))
+               return get_user(*bd_entry_ret, bd_entry_ptr);
+
+       /*
+        * Note that get_user() uses the type of the *pointer* to
+        * establish the size of the get, not the destination.
+        */
+       ret = get_user(bd_entry_32, (u32 __user *)bd_entry_ptr);
+       *bd_entry_ret = bd_entry_32;
+       return ret;
+}
+
 /*
  * Get the base of bounds tables pointed by specific bounds
  * directory entry.
@@ -605,7 +628,7 @@ static int get_bt_addr(struct mm_struct *mm,
                int need_write = 0;
 
                pagefault_disable();
-               ret = get_user(bd_entry, bd_entry_ptr);
+               ret = get_user_bd_entry(mm, &bd_entry, bd_entry_ptr);
                pagefault_enable();
                if (!ret)
                        break;
@@ -700,11 +723,23 @@ static unsigned long mpx_get_bt_entry_offset_bytes(struct mm_struct *mm,
  */
 static inline unsigned long bd_entry_virt_space(struct mm_struct *mm)
 {
-       unsigned long long virt_space = (1ULL << boot_cpu_data.x86_virt_bits);
-       if (is_64bit_mm(mm))
-               return virt_space / MPX_BD_NR_ENTRIES_64;
-       else
-               return virt_space / MPX_BD_NR_ENTRIES_32;
+       unsigned long long virt_space;
+       unsigned long long GB = (1ULL << 30);
+
+       /*
+        * This covers 32-bit emulation as well as 32-bit kernels
+        * running on 64-bit harware.
+        */
+       if (!is_64bit_mm(mm))
+               return (4ULL * GB) / MPX_BD_NR_ENTRIES_32;
+
+       /*
+        * 'x86_virt_bits' returns what the hardware is capable
+        * of, and returns the full >32-bit adddress space when
+        * running 32-bit kernels on 64-bit hardware.
+        */
+       virt_space = (1ULL << boot_cpu_data.x86_virt_bits);
+       return virt_space / MPX_BD_NR_ENTRIES_64;
 }
 
 /*
index 7bcf06a7cd12069e9e4f5c2f13066e1551ba8a27..6eb3c8af96e23678f16378858d05d435e12199fd 100644 (file)
@@ -50,18 +50,9 @@ void x86_pci_root_bus_resources(int bus, struct list_head *resources)
        if (!found)
                pci_add_resource(resources, &info->busn);
 
-       list_for_each_entry(root_res, &info->resources, list) {
-               struct resource *res;
-               struct resource *root;
+       list_for_each_entry(root_res, &info->resources, list)
+               pci_add_resource(resources, &root_res->res);
 
-               res = &root_res->res;
-               pci_add_resource(resources, res);
-               if (res->flags & IORESOURCE_IO)
-                       root = &ioport_resource;
-               else
-                       root = &iomem_resource;
-               insert_resource(root, res);
-       }
        return;
 
 default_resources:
index 06934a8a48724dc5fc6600b49178e9573e7558c5..14fcd01ed99293c162582438b4755a47fff59f43 100644 (file)
@@ -211,7 +211,7 @@ static int copy_sc_from_user(struct pt_regs *regs,
                if (err)
                        return 1;
 
-               err = convert_fxsr_from_user(&fpx, sc.fpstate);
+               err = convert_fxsr_from_user(&fpx, (void *)sc.fpstate);
                if (err)
                        return 1;
 
@@ -227,7 +227,7 @@ static int copy_sc_from_user(struct pt_regs *regs,
        {
                struct user_i387_struct fp;
 
-               err = copy_from_user(&fp, sc.fpstate,
+               err = copy_from_user(&fp, (void *)sc.fpstate,
                                     sizeof(struct user_i387_struct));
                if (err)
                        return 1;
@@ -291,7 +291,7 @@ static int copy_sc_to_user(struct sigcontext __user *to,
 #endif
 #undef PUTREG
        sc.oldmask = mask;
-       sc.fpstate = to_fp;
+       sc.fpstate = (unsigned long)to_fp;
 
        err = copy_to_user(to, &sc, sizeof(struct sigcontext));
        if (err)
@@ -468,12 +468,10 @@ long sys_sigreturn(void)
        struct sigframe __user *frame = (struct sigframe __user *)(sp - 8);
        sigset_t set;
        struct sigcontext __user *sc = &frame->sc;
-       unsigned long __user *oldmask = &sc->oldmask;
-       unsigned long __user *extramask = frame->extramask;
        int sig_size = (_NSIG_WORDS - 1) * sizeof(unsigned long);
 
-       if (copy_from_user(&set.sig[0], oldmask, sizeof(set.sig[0])) ||
-           copy_from_user(&set.sig[1], extramask, sig_size))
+       if (copy_from_user(&set.sig[0], &sc->oldmask, sizeof(set.sig[0])) ||
+           copy_from_user(&set.sig[1], frame->extramask, sig_size))
                goto segfault;
 
        set_current_blocked(&set);
@@ -505,6 +503,7 @@ int setup_signal_stack_si(unsigned long stack_top, struct ksignal *ksig,
 {
        struct rt_sigframe __user *frame;
        int err = 0, sig = ksig->sig;
+       unsigned long fp_to;
 
        frame = (struct rt_sigframe __user *)
                round_down(stack_top - sizeof(struct rt_sigframe), 16);
@@ -526,7 +525,10 @@ int setup_signal_stack_si(unsigned long stack_top, struct ksignal *ksig,
        err |= __save_altstack(&frame->uc.uc_stack, PT_REGS_SP(regs));
        err |= copy_sc_to_user(&frame->uc.uc_mcontext, &frame->fpstate, regs,
                               set->sig[0]);
-       err |= __put_user(&frame->fpstate, &frame->uc.uc_mcontext.fpstate);
+
+       fp_to = (unsigned long)&frame->fpstate;
+
+       err |= __put_user(fp_to, &frame->uc.uc_mcontext.fpstate);
        if (sizeof(*set) == 16) {
                err |= __put_user(set->sig[0], &frame->uc.uc_sigmask.sig[0]);
                err |= __put_user(set->sig[1], &frame->uc.uc_sigmask.sig[1]);
index ac161db633885872fdebdce976d05b978e1235da..cb5e266a8bf752297eaf6fc0d822c9398239fadf 100644 (file)
@@ -2495,14 +2495,9 @@ void __init xen_init_mmu_ops(void)
 {
        x86_init.paging.pagetable_init = xen_pagetable_init;
 
-       /* Optimization - we can use the HVM one but it has no idea which
-        * VCPUs are descheduled - which means that it will needlessly IPI
-        * them. Xen knows so let it do the job.
-        */
-       if (xen_feature(XENFEAT_auto_translated_physmap)) {
-               pv_mmu_ops.flush_tlb_others = xen_flush_tlb_others;
+       if (xen_feature(XENFEAT_auto_translated_physmap))
                return;
-       }
+
        pv_mmu_ops = xen_mmu_ops;
 
        memset(dummy_mapping, 0xff, PAGE_SIZE);
index feddabdab4488c54784aa5a64067d09b50b3cb22..df0c4055958379753aac957dd2c9e4c68fbaf765 100644 (file)
@@ -1,6 +1,7 @@
 #include <linux/types.h>
 #include <linux/tick.h>
 
+#include <xen/xen.h>
 #include <xen/interface/xen.h>
 #include <xen/grant_table.h>
 #include <xen/events.h>
@@ -68,26 +69,16 @@ static void xen_pv_post_suspend(int suspend_cancelled)
 
 void xen_arch_pre_suspend(void)
 {
-       int cpu;
-
-       for_each_online_cpu(cpu)
-               xen_pmu_finish(cpu);
-
        if (xen_pv_domain())
                xen_pv_pre_suspend();
 }
 
 void xen_arch_post_suspend(int cancelled)
 {
-       int cpu;
-
        if (xen_pv_domain())
                xen_pv_post_suspend(cancelled);
        else
                xen_hvm_post_suspend(cancelled);
-
-       for_each_online_cpu(cpu)
-               xen_pmu_init(cpu);
 }
 
 static void xen_vcpu_notify_restore(void *data)
@@ -106,10 +97,20 @@ static void xen_vcpu_notify_suspend(void *data)
 
 void xen_arch_resume(void)
 {
+       int cpu;
+
        on_each_cpu(xen_vcpu_notify_restore, NULL, 1);
+
+       for_each_online_cpu(cpu)
+               xen_pmu_init(cpu);
 }
 
 void xen_arch_suspend(void)
 {
+       int cpu;
+
+       for_each_online_cpu(cpu)
+               xen_pmu_finish(cpu);
+
        on_each_cpu(xen_vcpu_notify_suspend, NULL, 1);
 }
index 5bcdfc10c23a6340367c4b9781496a49b5c81efe..5a37188b559fba8feb1da48b00d5290c3a6a09b6 100644 (file)
@@ -1127,15 +1127,15 @@ void blkcg_exit_queue(struct request_queue *q)
  * of the main cic data structures.  For now we allow a task to change
  * its cgroup only if it's the only owner of its ioc.
  */
-static int blkcg_can_attach(struct cgroup_subsys_state *css,
-                           struct cgroup_taskset *tset)
+static int blkcg_can_attach(struct cgroup_taskset *tset)
 {
        struct task_struct *task;
+       struct cgroup_subsys_state *dst_css;
        struct io_context *ioc;
        int ret = 0;
 
        /* task_lock() is needed to avoid races with exit_io_context() */
-       cgroup_taskset_for_each(task, tset) {
+       cgroup_taskset_for_each(task, dst_css, tset) {
                task_lock(task);
                ioc = task->io_context;
                if (ioc && atomic_read(&ioc->nr_tasks) > 1)
index 5131993b23a1a2b35670adcbd4ab7d569a29a3d2..33e2f62d50622ea8b40153175d0f44d96df399a6 100644 (file)
@@ -206,6 +206,22 @@ void blk_delay_queue(struct request_queue *q, unsigned long msecs)
 }
 EXPORT_SYMBOL(blk_delay_queue);
 
+/**
+ * blk_start_queue_async - asynchronously restart a previously stopped queue
+ * @q:    The &struct request_queue in question
+ *
+ * Description:
+ *   blk_start_queue_async() will clear the stop flag on the queue, and
+ *   ensure that the request_fn for the queue is run from an async
+ *   context.
+ **/
+void blk_start_queue_async(struct request_queue *q)
+{
+       queue_flag_clear(QUEUE_FLAG_STOPPED, q);
+       blk_run_queue_async(q);
+}
+EXPORT_SYMBOL(blk_start_queue_async);
+
 /**
  * blk_start_queue - restart a previously stopped queue
  * @q:    The &struct request_queue in question
@@ -1689,8 +1705,6 @@ static blk_qc_t blk_queue_bio(struct request_queue *q, struct bio *bio)
        struct request *req;
        unsigned int request_count = 0;
 
-       blk_queue_split(q, &bio, q->bio_split);
-
        /*
         * low level driver can indicate that it wants pages above a
         * certain limit bounced to low memory (ie for highmem, or even
@@ -1698,6 +1712,8 @@ static blk_qc_t blk_queue_bio(struct request_queue *q, struct bio *bio)
         */
        blk_queue_bounce(q, &bio);
 
+       blk_queue_split(q, &bio, q->bio_split);
+
        if (bio_integrity_enabled(bio) && bio_integrity_prep(bio)) {
                bio->bi_error = -EIO;
                bio_endio(bio);
@@ -2114,7 +2130,8 @@ blk_qc_t submit_bio(int rw, struct bio *bio)
 EXPORT_SYMBOL(submit_bio);
 
 /**
- * blk_rq_check_limits - Helper function to check a request for the queue limit
+ * blk_cloned_rq_check_limits - Helper function to check a cloned request
+ *                              for new the queue limits
  * @q:  the queue
  * @rq: the request being checked
  *
@@ -2125,20 +2142,13 @@ EXPORT_SYMBOL(submit_bio);
  *    after it is inserted to @q, it should be checked against @q before
  *    the insertion using this generic function.
  *
- *    This function should also be useful for request stacking drivers
- *    in some cases below, so export this function.
  *    Request stacking drivers like request-based dm may change the queue
- *    limits while requests are in the queue (e.g. dm's table swapping).
- *    Such request stacking drivers should check those requests against
- *    the new queue limits again when they dispatch those requests,
- *    although such checkings are also done against the old queue limits
- *    when submitting requests.
+ *    limits when retrying requests on other queues. Those requests need
+ *    to be checked against the new queue limits again during dispatch.
  */
-int blk_rq_check_limits(struct request_queue *q, struct request *rq)
+static int blk_cloned_rq_check_limits(struct request_queue *q,
+                                     struct request *rq)
 {
-       if (!rq_mergeable(rq))
-               return 0;
-
        if (blk_rq_sectors(rq) > blk_queue_get_max_sectors(q, rq->cmd_flags)) {
                printk(KERN_ERR "%s: over max size limit.\n", __func__);
                return -EIO;
@@ -2158,7 +2168,6 @@ int blk_rq_check_limits(struct request_queue *q, struct request *rq)
 
        return 0;
 }
-EXPORT_SYMBOL_GPL(blk_rq_check_limits);
 
 /**
  * blk_insert_cloned_request - Helper for stacking drivers to submit a request
@@ -2170,7 +2179,7 @@ int blk_insert_cloned_request(struct request_queue *q, struct request *rq)
        unsigned long flags;
        int where = ELEVATOR_INSERT_BACK;
 
-       if (blk_rq_check_limits(q, rq))
+       if (blk_cloned_rq_check_limits(q, rq))
                return -EIO;
 
        if (rq->rq_disk &&
@@ -3412,6 +3421,9 @@ int blk_pre_runtime_suspend(struct request_queue *q)
 {
        int ret = 0;
 
+       if (!q->dev)
+               return ret;
+
        spin_lock_irq(q->queue_lock);
        if (q->nr_pending) {
                ret = -EBUSY;
@@ -3439,6 +3451,9 @@ EXPORT_SYMBOL(blk_pre_runtime_suspend);
  */
 void blk_post_runtime_suspend(struct request_queue *q, int err)
 {
+       if (!q->dev)
+               return;
+
        spin_lock_irq(q->queue_lock);
        if (!err) {
                q->rpm_status = RPM_SUSPENDED;
@@ -3463,6 +3478,9 @@ EXPORT_SYMBOL(blk_post_runtime_suspend);
  */
 void blk_pre_runtime_resume(struct request_queue *q)
 {
+       if (!q->dev)
+               return;
+
        spin_lock_irq(q->queue_lock);
        q->rpm_status = RPM_RESUMING;
        spin_unlock_irq(q->queue_lock);
@@ -3485,6 +3503,9 @@ EXPORT_SYMBOL(blk_pre_runtime_resume);
  */
 void blk_post_runtime_resume(struct request_queue *q, int err)
 {
+       if (!q->dev)
+               return;
+
        spin_lock_irq(q->queue_lock);
        if (!err) {
                q->rpm_status = RPM_ACTIVE;
index de5716d8e525969e7849767a775aabec9e4d8b96..e73846a3d08a655a63a763d35732106b64ee4797 100644 (file)
@@ -76,9 +76,12 @@ static struct bio *blk_bio_segment_split(struct request_queue *q,
        struct bio_vec bv, bvprv, *bvprvp = NULL;
        struct bvec_iter iter;
        unsigned seg_size = 0, nsegs = 0, sectors = 0;
+       unsigned front_seg_size = bio->bi_seg_front_size;
+       bool do_split = true;
+       struct bio *new = NULL;
 
        bio_for_each_segment(bv, bio, iter) {
-               if (sectors + (bv.bv_len >> 9) > queue_max_sectors(q))
+               if (sectors + (bv.bv_len >> 9) > blk_max_size_offset(q, bio->bi_iter.bi_sector))
                        goto split;
 
                /*
@@ -98,8 +101,11 @@ static struct bio *blk_bio_segment_split(struct request_queue *q,
 
                        seg_size += bv.bv_len;
                        bvprv = bv;
-                       bvprvp = &bv;
+                       bvprvp = &bvprv;
                        sectors += bv.bv_len >> 9;
+
+                       if (nsegs == 1 && seg_size > front_seg_size)
+                               front_seg_size = seg_size;
                        continue;
                }
 new_segment:
@@ -108,16 +114,29 @@ new_segment:
 
                nsegs++;
                bvprv = bv;
-               bvprvp = &bv;
+               bvprvp = &bvprv;
                seg_size = bv.bv_len;
                sectors += bv.bv_len >> 9;
+
+               if (nsegs == 1 && seg_size > front_seg_size)
+                       front_seg_size = seg_size;
        }
 
-       *segs = nsegs;
-       return NULL;
+       do_split = false;
 split:
        *segs = nsegs;
-       return bio_split(bio, sectors, GFP_NOIO, bs);
+
+       if (do_split) {
+               new = bio_split(bio, sectors, GFP_NOIO, bs);
+               if (new)
+                       bio = new;
+       }
+
+       bio->bi_seg_front_size = front_seg_size;
+       if (seg_size > bio->bi_seg_back_size)
+               bio->bi_seg_back_size = seg_size;
+
+       return do_split ? new : NULL;
 }
 
 void blk_queue_split(struct request_queue *q, struct bio **bio,
@@ -412,6 +431,12 @@ int blk_rq_map_sg(struct request_queue *q, struct request *rq,
        if (sg)
                sg_mark_end(sg);
 
+       /*
+        * Something must have been wrong if the figured number of
+        * segment is bigger than number of req's physical segments
+        */
+       WARN_ON(nsegs > rq->nr_phys_segments);
+
        return nsegs;
 }
 EXPORT_SYMBOL(blk_rq_map_sg);
index 3ae09de62f19ce2ca230a89ae6137a511fc9ae16..6d6f8feb48c08ab875e67c496193a743709b0621 100644 (file)
@@ -1291,15 +1291,16 @@ static blk_qc_t blk_mq_make_request(struct request_queue *q, struct bio *bio)
                blk_mq_bio_to_request(rq, bio);
 
                /*
-                * we do limited pluging. If bio can be merged, do merge.
+                * We do limited pluging. If the bio can be merged, do that.
                 * Otherwise the existing request in the plug list will be
                 * issued. So the plug list will have one request at most
                 */
                if (plug) {
                        /*
                         * The plug list might get flushed before this. If that
-                        * happens, same_queue_rq is invalid and plug list is empty
-                        **/
+                        * happens, same_queue_rq is invalid and plug list is
+                        * empty
+                        */
                        if (same_queue_rq && !list_empty(&plug->mq_list)) {
                                old_rq = same_queue_rq;
                                list_del_init(&old_rq->queuelist);
@@ -1380,12 +1381,15 @@ static blk_qc_t blk_sq_make_request(struct request_queue *q, struct bio *bio)
                blk_mq_bio_to_request(rq, bio);
                if (!request_count)
                        trace_block_plug(q);
-               else if (request_count >= BLK_MAX_REQUEST_COUNT) {
+
+               blk_mq_put_ctx(data.ctx);
+
+               if (request_count >= BLK_MAX_REQUEST_COUNT) {
                        blk_flush_plug_list(plug, false);
                        trace_block_plug(q);
                }
+
                list_add_tail(&rq->queuelist, &plug->mq_list);
-               blk_mq_put_ctx(data.ctx);
                return cookie;
        }
 
index 7d8f129a1516b408d8ebd827e65ffd6d688b2df8..dd49735839789167d427dc8b64da71c6b21f08f5 100644 (file)
@@ -91,7 +91,8 @@ void blk_set_default_limits(struct queue_limits *lim)
        lim->seg_boundary_mask = BLK_SEG_BOUNDARY_MASK;
        lim->virt_boundary_mask = 0;
        lim->max_segment_size = BLK_MAX_SEGMENT_SIZE;
-       lim->max_sectors = lim->max_hw_sectors = BLK_SAFE_MAX_SECTORS;
+       lim->max_sectors = lim->max_dev_sectors = lim->max_hw_sectors =
+               BLK_SAFE_MAX_SECTORS;
        lim->chunk_sectors = 0;
        lim->max_write_same_sectors = 0;
        lim->max_discard_sectors = 0;
@@ -127,6 +128,7 @@ void blk_set_stacking_limits(struct queue_limits *lim)
        lim->max_hw_sectors = UINT_MAX;
        lim->max_segment_size = UINT_MAX;
        lim->max_sectors = UINT_MAX;
+       lim->max_dev_sectors = UINT_MAX;
        lim->max_write_same_sectors = UINT_MAX;
 }
 EXPORT_SYMBOL(blk_set_stacking_limits);
@@ -214,8 +216,8 @@ void blk_queue_bounce_limit(struct request_queue *q, u64 max_addr)
 EXPORT_SYMBOL(blk_queue_bounce_limit);
 
 /**
- * blk_limits_max_hw_sectors - set hard and soft limit of max sectors for request
- * @limits: the queue limits
+ * blk_queue_max_hw_sectors - set max sectors for a request for this queue
+ * @q:  the request queue for the device
  * @max_hw_sectors:  max hardware sectors in the usual 512b unit
  *
  * Description:
@@ -224,13 +226,19 @@ EXPORT_SYMBOL(blk_queue_bounce_limit);
  *    the device driver based upon the capabilities of the I/O
  *    controller.
  *
+ *    max_dev_sectors is a hard limit imposed by the storage device for
+ *    READ/WRITE requests. It is set by the disk driver.
+ *
  *    max_sectors is a soft limit imposed by the block layer for
  *    filesystem type requests.  This value can be overridden on a
  *    per-device basis in /sys/block/<device>/queue/max_sectors_kb.
  *    The soft limit can not exceed max_hw_sectors.
  **/
-void blk_limits_max_hw_sectors(struct queue_limits *limits, unsigned int max_hw_sectors)
+void blk_queue_max_hw_sectors(struct request_queue *q, unsigned int max_hw_sectors)
 {
+       struct queue_limits *limits = &q->limits;
+       unsigned int max_sectors;
+
        if ((max_hw_sectors << 9) < PAGE_CACHE_SIZE) {
                max_hw_sectors = 1 << (PAGE_CACHE_SHIFT - 9);
                printk(KERN_INFO "%s: set to minimum %d\n",
@@ -238,22 +246,9 @@ void blk_limits_max_hw_sectors(struct queue_limits *limits, unsigned int max_hw_
        }
 
        limits->max_hw_sectors = max_hw_sectors;
-       limits->max_sectors = min_t(unsigned int, max_hw_sectors,
-                                   BLK_DEF_MAX_SECTORS);
-}
-EXPORT_SYMBOL(blk_limits_max_hw_sectors);
-
-/**
- * blk_queue_max_hw_sectors - set max sectors for a request for this queue
- * @q:  the request queue for the device
- * @max_hw_sectors:  max hardware sectors in the usual 512b unit
- *
- * Description:
- *    See description for blk_limits_max_hw_sectors().
- **/
-void blk_queue_max_hw_sectors(struct request_queue *q, unsigned int max_hw_sectors)
-{
-       blk_limits_max_hw_sectors(&q->limits, max_hw_sectors);
+       max_sectors = min_not_zero(max_hw_sectors, limits->max_dev_sectors);
+       max_sectors = min_t(unsigned int, max_sectors, BLK_DEF_MAX_SECTORS);
+       limits->max_sectors = max_sectors;
 }
 EXPORT_SYMBOL(blk_queue_max_hw_sectors);
 
@@ -527,6 +522,7 @@ int blk_stack_limits(struct queue_limits *t, struct queue_limits *b,
 
        t->max_sectors = min_not_zero(t->max_sectors, b->max_sectors);
        t->max_hw_sectors = min_not_zero(t->max_hw_sectors, b->max_hw_sectors);
+       t->max_dev_sectors = min_not_zero(t->max_dev_sectors, b->max_dev_sectors);
        t->max_write_same_sectors = min(t->max_write_same_sectors,
                                        b->max_write_same_sectors);
        t->bounce_pfn = min_not_zero(t->bounce_pfn, b->bounce_pfn);
index 565b8dac578297edf327e7451dedfe80a75e5751..e140cc487ce11349ff1917e4e866eccf0a18106c 100644 (file)
@@ -205,6 +205,9 @@ queue_max_sectors_store(struct request_queue *q, const char *page, size_t count)
        if (ret < 0)
                return ret;
 
+       max_hw_sectors_kb = min_not_zero(max_hw_sectors_kb, (unsigned long)
+                                        q->limits.max_dev_sectors >> 1);
+
        if (max_sectors_kb > max_hw_sectors_kb || max_sectors_kb < page_kb)
                return -EINVAL;
 
index 246dfb16c3d988c4f84749065a66977b825c98b5..aa40aa93381b661b73d5aa0f531e247e148c56a0 100644 (file)
@@ -158,11 +158,13 @@ void blk_abort_request(struct request *req)
 {
        if (blk_mark_rq_complete(req))
                return;
-       blk_delete_timer(req);
-       if (req->q->mq_ops)
+
+       if (req->q->mq_ops) {
                blk_mq_rq_timed_out(req, false);
-       else
+       } else {
+               blk_delete_timer(req);
                blk_rq_timed_out(req);
+       }
 }
 EXPORT_SYMBOL_GPL(blk_abort_request);
 
index da722eb786df6afd6ff0e567024fe2f7b02488e7..c43926d3d74d0578216d1a699b1dfefff2a899df 100644 (file)
@@ -72,8 +72,6 @@ void blk_dequeue_request(struct request *rq);
 void __blk_queue_free_tags(struct request_queue *q);
 bool __blk_end_bidi_request(struct request *rq, int error,
                            unsigned int nr_bytes, unsigned int bidi_bytes);
-int blk_queue_enter(struct request_queue *q, gfp_t gfp);
-void blk_queue_exit(struct request_queue *q);
 void blk_freeze_queue(struct request_queue *q);
 
 static inline void blk_queue_enter_live(struct request_queue *q)
index 3de89d4690f3bf3e0d9abec1976a379b5dc171e5..a163c487cf38c8250ccbf0ec7beac913672796f0 100644 (file)
@@ -21,10 +21,10 @@ static void noop_merged_requests(struct request_queue *q, struct request *rq,
 static int noop_dispatch(struct request_queue *q, int force)
 {
        struct noop_data *nd = q->elevator->elevator_data;
+       struct request *rq;
 
-       if (!list_empty(&nd->queue)) {
-               struct request *rq;
-               rq = list_entry(nd->queue.next, struct request, queuelist);
+       rq = list_first_entry_or_null(&nd->queue, struct request, queuelist);
+       if (rq) {
                list_del_init(&rq->queuelist);
                elv_dispatch_sort(q, rq);
                return 1;
@@ -46,7 +46,7 @@ noop_former_request(struct request_queue *q, struct request *rq)
 
        if (rq->queuelist.prev == &nd->queue)
                return NULL;
-       return list_entry(rq->queuelist.prev, struct request, queuelist);
+       return list_prev_entry(rq, queuelist);
 }
 
 static struct request *
@@ -56,7 +56,7 @@ noop_latter_request(struct request_queue *q, struct request *rq)
 
        if (rq->queuelist.next == &nd->queue)
                return NULL;
-       return list_entry(rq->queuelist.next, struct request, queuelist);
+       return list_next_entry(rq, queuelist);
 }
 
 static int noop_init_queue(struct request_queue *q, struct elevator_type *e)
index 3b030157ec85c45faedd520b6993cd440254d763..746935a5973ca6c76b8f66cfff8d58ce50566994 100644 (file)
@@ -397,7 +397,7 @@ static int drop_partitions(struct gendisk *disk, struct block_device *bdev)
        struct hd_struct *part;
        int res;
 
-       if (bdev->bd_part_count)
+       if (bdev->bd_part_count || bdev->bd_super)
                return -EBUSY;
        res = invalidate_partition(disk, 0);
        if (res)
index c2c48ec64b2709c5f252e164bc3397df0c439210..621317ac4d59f5fd75e433718a194bad7b1c2a56 100644 (file)
@@ -32,7 +32,7 @@ int mac_partition(struct parsed_partitions *state)
        Sector sect;
        unsigned char *data;
        int slot, blocks_in_map;
-       unsigned secsize;
+       unsigned secsize, datasize, partoffset;
 #ifdef CONFIG_PPC_PMAC
        int found_root = 0;
        int found_root_goodness = 0;
@@ -50,10 +50,14 @@ int mac_partition(struct parsed_partitions *state)
        }
        secsize = be16_to_cpu(md->block_size);
        put_dev_sector(sect);
-       data = read_part_sector(state, secsize/512, &sect);
+       datasize = round_down(secsize, 512);
+       data = read_part_sector(state, datasize / 512, &sect);
        if (!data)
                return -1;
-       part = (struct mac_partition *) (data + secsize%512);
+       partoffset = secsize % 512;
+       if (partoffset + sizeof(*part) > datasize)
+               return -1;
+       part = (struct mac_partition *) (data + partoffset);
        if (be16_to_cpu(part->signature) != MAC_PARTITION_MAGIC) {
                put_dev_sector(sect);
                return 0;               /* not a MacOS disk */
index b4ffc5be1a93c1ff0bceb6b9a5cc3dc1b5101d97..e5b5721809e21d5d379e6e711e23ef709252e0ed 100644 (file)
@@ -277,12 +277,12 @@ static int ablkcipher_walk_first(struct ablkcipher_request *req,
        if (WARN_ON_ONCE(in_irq()))
                return -EDEADLK;
 
+       walk->iv = req->info;
        walk->nbytes = walk->total;
        if (unlikely(!walk->total))
                return 0;
 
        walk->iv_buffer = NULL;
-       walk->iv = req->info;
        if (unlikely(((unsigned long)walk->iv & alignmask))) {
                int err = ablkcipher_copy_iv(walk, tfm, alignmask);
 
index 0aa6fdfb448a8c4081e06aa9dcb041433dc280a5..6d4d4569447ee080ef44eb7c8c17d782bec23103 100644 (file)
@@ -125,7 +125,7 @@ static int aead_wait_for_data(struct sock *sk, unsigned flags)
        if (flags & MSG_DONTWAIT)
                return -EAGAIN;
 
-       set_bit(SOCK_ASYNC_WAITDATA, &sk->sk_socket->flags);
+       sk_set_bit(SOCKWQ_ASYNC_WAITDATA, sk);
 
        for (;;) {
                if (signal_pending(current))
@@ -139,7 +139,7 @@ static int aead_wait_for_data(struct sock *sk, unsigned flags)
        }
        finish_wait(sk_sleep(sk), &wait);
 
-       clear_bit(SOCK_ASYNC_WAITDATA, &sk->sk_socket->flags);
+       sk_clear_bit(SOCKWQ_ASYNC_WAITDATA, sk);
 
        return err;
 }
index af31a0ee4057370593536cb9f8cc0a4343ab91b8..634b4d1ab6817d56343d5b8b24b29cd34de422d1 100644 (file)
@@ -47,7 +47,7 @@ struct skcipher_ctx {
        bool merge;
        bool enc;
 
-       struct ablkcipher_request req;
+       struct skcipher_request req;
 };
 
 struct skcipher_async_rsgl {
@@ -64,13 +64,13 @@ struct skcipher_async_req {
 };
 
 #define GET_SREQ(areq, ctx) (struct skcipher_async_req *)((char *)areq + \
-       crypto_ablkcipher_reqsize(crypto_ablkcipher_reqtfm(&ctx->req)))
+       crypto_skcipher_reqsize(crypto_skcipher_reqtfm(&ctx->req)))
 
 #define GET_REQ_SIZE(ctx) \
-       crypto_ablkcipher_reqsize(crypto_ablkcipher_reqtfm(&ctx->req))
+       crypto_skcipher_reqsize(crypto_skcipher_reqtfm(&ctx->req))
 
 #define GET_IV_SIZE(ctx) \
-       crypto_ablkcipher_ivsize(crypto_ablkcipher_reqtfm(&ctx->req))
+       crypto_skcipher_ivsize(crypto_skcipher_reqtfm(&ctx->req))
 
 #define MAX_SGL_ENTS ((4096 - sizeof(struct skcipher_sg_list)) / \
                      sizeof(struct scatterlist) - 1)
@@ -212,7 +212,7 @@ static int skcipher_wait_for_wmem(struct sock *sk, unsigned flags)
        if (flags & MSG_DONTWAIT)
                return -EAGAIN;
 
-       set_bit(SOCK_ASYNC_NOSPACE, &sk->sk_socket->flags);
+       sk_set_bit(SOCKWQ_ASYNC_NOSPACE, sk);
 
        for (;;) {
                if (signal_pending(current))
@@ -258,7 +258,7 @@ static int skcipher_wait_for_data(struct sock *sk, unsigned flags)
                return -EAGAIN;
        }
 
-       set_bit(SOCK_ASYNC_WAITDATA, &sk->sk_socket->flags);
+       sk_set_bit(SOCKWQ_ASYNC_WAITDATA, sk);
 
        for (;;) {
                if (signal_pending(current))
@@ -272,7 +272,7 @@ static int skcipher_wait_for_data(struct sock *sk, unsigned flags)
        }
        finish_wait(sk_sleep(sk), &wait);
 
-       clear_bit(SOCK_ASYNC_WAITDATA, &sk->sk_socket->flags);
+       sk_clear_bit(SOCKWQ_ASYNC_WAITDATA, sk);
 
        return err;
 }
@@ -302,8 +302,8 @@ static int skcipher_sendmsg(struct socket *sock, struct msghdr *msg,
        struct sock *sk = sock->sk;
        struct alg_sock *ask = alg_sk(sk);
        struct skcipher_ctx *ctx = ask->private;
-       struct crypto_ablkcipher *tfm = crypto_ablkcipher_reqtfm(&ctx->req);
-       unsigned ivsize = crypto_ablkcipher_ivsize(tfm);
+       struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(&ctx->req);
+       unsigned ivsize = crypto_skcipher_ivsize(tfm);
        struct skcipher_sg_list *sgl;
        struct af_alg_control con = {};
        long copied = 0;
@@ -507,7 +507,7 @@ static int skcipher_recvmsg_async(struct socket *sock, struct msghdr *msg,
        struct skcipher_sg_list *sgl;
        struct scatterlist *sg;
        struct skcipher_async_req *sreq;
-       struct ablkcipher_request *req;
+       struct skcipher_request *req;
        struct skcipher_async_rsgl *last_rsgl = NULL;
        unsigned int txbufs = 0, len = 0, tx_nents = skcipher_all_sg_nents(ctx);
        unsigned int reqlen = sizeof(struct skcipher_async_req) +
@@ -531,9 +531,9 @@ static int skcipher_recvmsg_async(struct socket *sock, struct msghdr *msg,
        }
        sg_init_table(sreq->tsg, tx_nents);
        memcpy(sreq->iv, ctx->iv, GET_IV_SIZE(ctx));
-       ablkcipher_request_set_tfm(req, crypto_ablkcipher_reqtfm(&ctx->req));
-       ablkcipher_request_set_callback(req, CRYPTO_TFM_REQ_MAY_BACKLOG,
-                                       skcipher_async_cb, sk);
+       skcipher_request_set_tfm(req, crypto_skcipher_reqtfm(&ctx->req));
+       skcipher_request_set_callback(req, CRYPTO_TFM_REQ_MAY_BACKLOG,
+                                     skcipher_async_cb, sk);
 
        while (iov_iter_count(&msg->msg_iter)) {
                struct skcipher_async_rsgl *rsgl;
@@ -608,10 +608,10 @@ static int skcipher_recvmsg_async(struct socket *sock, struct msghdr *msg,
        if (mark)
                sg_mark_end(sreq->tsg + txbufs - 1);
 
-       ablkcipher_request_set_crypt(req, sreq->tsg, sreq->first_sgl.sgl.sg,
-                                    len, sreq->iv);
-       err = ctx->enc ? crypto_ablkcipher_encrypt(req) :
-                        crypto_ablkcipher_decrypt(req);
+       skcipher_request_set_crypt(req, sreq->tsg, sreq->first_sgl.sgl.sg,
+                                  len, sreq->iv);
+       err = ctx->enc ? crypto_skcipher_encrypt(req) :
+                        crypto_skcipher_decrypt(req);
        if (err == -EINPROGRESS) {
                atomic_inc(&ctx->inflight);
                err = -EIOCBQUEUED;
@@ -632,7 +632,7 @@ static int skcipher_recvmsg_sync(struct socket *sock, struct msghdr *msg,
        struct sock *sk = sock->sk;
        struct alg_sock *ask = alg_sk(sk);
        struct skcipher_ctx *ctx = ask->private;
-       unsigned bs = crypto_ablkcipher_blocksize(crypto_ablkcipher_reqtfm(
+       unsigned bs = crypto_skcipher_blocksize(crypto_skcipher_reqtfm(
                &ctx->req));
        struct skcipher_sg_list *sgl;
        struct scatterlist *sg;
@@ -669,14 +669,13 @@ static int skcipher_recvmsg_sync(struct socket *sock, struct msghdr *msg,
                if (!used)
                        goto free;
 
-               ablkcipher_request_set_crypt(&ctx->req, sg,
-                                            ctx->rsgl.sg, used,
-                                            ctx->iv);
+               skcipher_request_set_crypt(&ctx->req, sg, ctx->rsgl.sg, used,
+                                          ctx->iv);
 
                err = af_alg_wait_for_completion(
                                ctx->enc ?
-                                       crypto_ablkcipher_encrypt(&ctx->req) :
-                                       crypto_ablkcipher_decrypt(&ctx->req),
+                                       crypto_skcipher_encrypt(&ctx->req) :
+                                       crypto_skcipher_decrypt(&ctx->req),
                                &ctx->completion);
 
 free:
@@ -751,17 +750,17 @@ static struct proto_ops algif_skcipher_ops = {
 
 static void *skcipher_bind(const char *name, u32 type, u32 mask)
 {
-       return crypto_alloc_ablkcipher(name, type, mask);
+       return crypto_alloc_skcipher(name, type, mask);
 }
 
 static void skcipher_release(void *private)
 {
-       crypto_free_ablkcipher(private);
+       crypto_free_skcipher(private);
 }
 
 static int skcipher_setkey(void *private, const u8 *key, unsigned int keylen)
 {
-       return crypto_ablkcipher_setkey(private, key, keylen);
+       return crypto_skcipher_setkey(private, key, keylen);
 }
 
 static void skcipher_wait(struct sock *sk)
@@ -778,13 +777,13 @@ static void skcipher_sock_destruct(struct sock *sk)
 {
        struct alg_sock *ask = alg_sk(sk);
        struct skcipher_ctx *ctx = ask->private;
-       struct crypto_ablkcipher *tfm = crypto_ablkcipher_reqtfm(&ctx->req);
+       struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(&ctx->req);
 
        if (atomic_read(&ctx->inflight))
                skcipher_wait(sk);
 
        skcipher_free_sgl(sk);
-       sock_kzfree_s(sk, ctx->iv, crypto_ablkcipher_ivsize(tfm));
+       sock_kzfree_s(sk, ctx->iv, crypto_skcipher_ivsize(tfm));
        sock_kfree_s(sk, ctx, ctx->len);
        af_alg_release_parent(sk);
 }
@@ -793,20 +792,20 @@ static int skcipher_accept_parent(void *private, struct sock *sk)
 {
        struct skcipher_ctx *ctx;
        struct alg_sock *ask = alg_sk(sk);
-       unsigned int len = sizeof(*ctx) + crypto_ablkcipher_reqsize(private);
+       unsigned int len = sizeof(*ctx) + crypto_skcipher_reqsize(private);
 
        ctx = sock_kmalloc(sk, len, GFP_KERNEL);
        if (!ctx)
                return -ENOMEM;
 
-       ctx->iv = sock_kmalloc(sk, crypto_ablkcipher_ivsize(private),
+       ctx->iv = sock_kmalloc(sk, crypto_skcipher_ivsize(private),
                               GFP_KERNEL);
        if (!ctx->iv) {
                sock_kfree_s(sk, ctx, len);
                return -ENOMEM;
        }
 
-       memset(ctx->iv, 0, crypto_ablkcipher_ivsize(private));
+       memset(ctx->iv, 0, crypto_skcipher_ivsize(private));
 
        INIT_LIST_HEAD(&ctx->tsgl);
        ctx->len = len;
@@ -819,9 +818,9 @@ static int skcipher_accept_parent(void *private, struct sock *sk)
 
        ask->private = ctx;
 
-       ablkcipher_request_set_tfm(&ctx->req, private);
-       ablkcipher_request_set_callback(&ctx->req, CRYPTO_TFM_REQ_MAY_BACKLOG,
-                                       af_alg_complete, &ctx->completion);
+       skcipher_request_set_tfm(&ctx->req, private);
+       skcipher_request_set_callback(&ctx->req, CRYPTO_TFM_REQ_MAY_BACKLOG,
+                                     af_alg_complete, &ctx->completion);
 
        sk->sk_destruct = skcipher_sock_destruct;
 
index 11b981492031361f7cdf336b58ecbb98b8951196..8cc1622b2ee008ef7f5ff31a3ea7d8777f3f5f1b 100644 (file)
@@ -326,12 +326,12 @@ static int blkcipher_walk_first(struct blkcipher_desc *desc,
        if (WARN_ON_ONCE(in_irq()))
                return -EDEADLK;
 
+       walk->iv = desc->info;
        walk->nbytes = walk->total;
        if (unlikely(!walk->total))
                return 0;
 
        walk->buffer = NULL;
-       walk->iv = desc->info;
        if (unlikely(((unsigned long)walk->iv & walk->alignmask))) {
                int err = blkcipher_copy_iv(walk);
                if (err)
index 73d039156ea7694f14a444dea3ccbeda6c45a564..795d0ca714bfe45f25b97d3e6f566088925f5875 100644 (file)
@@ -63,6 +63,7 @@ obj-$(CONFIG_FB_I810)           += video/fbdev/i810/
 obj-$(CONFIG_FB_INTEL)          += video/fbdev/intelfb/
 
 obj-$(CONFIG_PARPORT)          += parport/
+obj-$(CONFIG_NVM)              += lightnvm/
 obj-y                          += base/ block/ misc/ mfd/ nfc/
 obj-$(CONFIG_LIBNVDIMM)                += nvdimm/
 obj-$(CONFIG_DMA_SHARED_BUFFER) += dma-buf/
@@ -70,7 +71,6 @@ obj-$(CONFIG_NUBUS)           += nubus/
 obj-y                          += macintosh/
 obj-$(CONFIG_IDE)              += ide/
 obj-$(CONFIG_SCSI)             += scsi/
-obj-$(CONFIG_NVM)              += lightnvm/
 obj-y                          += nvme/
 obj-$(CONFIG_ATA)              += ata/
 obj-$(CONFIG_TARGET_CORE)      += target/
index 25dbb76c02ccb0fd1d9b56d9956acb115d2e8419..5eef4cb4f70e6995f2d623268d1f8cd2daab63c2 100644 (file)
@@ -58,10 +58,10 @@ config ACPI_CCA_REQUIRED
        bool
 
 config ACPI_DEBUGGER
-       bool "In-kernel debugger (EXPERIMENTAL)"
+       bool "AML debugger interface (EXPERIMENTAL)"
        select ACPI_DEBUG
        help
-         Enable in-kernel debugging facilities: statistics, internal
+         Enable in-kernel debugging of AML facilities: statistics, internal
          object dump, single step control method execution.
          This is still under development, currently enabling this only
          results in the compilation of the ACPICA debugger files.
index 3c083d2cc4342049a97fae02407fb64b7e553036..6730f965b3793f25ba73125a00b18f346decf75f 100644 (file)
@@ -304,7 +304,7 @@ EXPORT_SYMBOL_GPL(acpi_get_psd_map);
 
 static int register_pcc_channel(int pcc_subspace_idx)
 {
-       struct acpi_pcct_subspace *cppc_ss;
+       struct acpi_pcct_hw_reduced *cppc_ss;
        unsigned int len;
 
        if (pcc_subspace_idx >= 0) {
index f61a7c83454063a5e77ebf35e13cb4bb1431891b..b420fb46669dd698c4d346559c325c0f4afeaf4d 100644 (file)
@@ -1103,7 +1103,7 @@ static int acpi_ec_query(struct acpi_ec *ec, u8 *data)
        }
 
 err_exit:
-       if (result && q)
+       if (result)
                acpi_ec_delete_query(q);
        if (data)
                *data = value;
index f7dab53b352ae0f70838d622ba32da62eb381d83..aa45d480270721280a9e8085574a14d086a079fc 100644 (file)
@@ -233,11 +233,12 @@ static bool add_spa(struct acpi_nfit_desc *acpi_desc,
                struct nfit_table_prev *prev,
                struct acpi_nfit_system_address *spa)
 {
+       size_t length = min_t(size_t, sizeof(*spa), spa->header.length);
        struct device *dev = acpi_desc->dev;
        struct nfit_spa *nfit_spa;
 
        list_for_each_entry(nfit_spa, &prev->spas, list) {
-               if (memcmp(nfit_spa->spa, spa, sizeof(*spa)) == 0) {
+               if (memcmp(nfit_spa->spa, spa, length) == 0) {
                        list_move_tail(&nfit_spa->list, &acpi_desc->spas);
                        return true;
                }
@@ -259,11 +260,12 @@ static bool add_memdev(struct acpi_nfit_desc *acpi_desc,
                struct nfit_table_prev *prev,
                struct acpi_nfit_memory_map *memdev)
 {
+       size_t length = min_t(size_t, sizeof(*memdev), memdev->header.length);
        struct device *dev = acpi_desc->dev;
        struct nfit_memdev *nfit_memdev;
 
        list_for_each_entry(nfit_memdev, &prev->memdevs, list)
-               if (memcmp(nfit_memdev->memdev, memdev, sizeof(*memdev)) == 0) {
+               if (memcmp(nfit_memdev->memdev, memdev, length) == 0) {
                        list_move_tail(&nfit_memdev->list, &acpi_desc->memdevs);
                        return true;
                }
@@ -284,11 +286,12 @@ static bool add_dcr(struct acpi_nfit_desc *acpi_desc,
                struct nfit_table_prev *prev,
                struct acpi_nfit_control_region *dcr)
 {
+       size_t length = min_t(size_t, sizeof(*dcr), dcr->header.length);
        struct device *dev = acpi_desc->dev;
        struct nfit_dcr *nfit_dcr;
 
        list_for_each_entry(nfit_dcr, &prev->dcrs, list)
-               if (memcmp(nfit_dcr->dcr, dcr, sizeof(*dcr)) == 0) {
+               if (memcmp(nfit_dcr->dcr, dcr, length) == 0) {
                        list_move_tail(&nfit_dcr->list, &acpi_desc->dcrs);
                        return true;
                }
@@ -308,11 +311,12 @@ static bool add_bdw(struct acpi_nfit_desc *acpi_desc,
                struct nfit_table_prev *prev,
                struct acpi_nfit_data_region *bdw)
 {
+       size_t length = min_t(size_t, sizeof(*bdw), bdw->header.length);
        struct device *dev = acpi_desc->dev;
        struct nfit_bdw *nfit_bdw;
 
        list_for_each_entry(nfit_bdw, &prev->bdws, list)
-               if (memcmp(nfit_bdw->bdw, bdw, sizeof(*bdw)) == 0) {
+               if (memcmp(nfit_bdw->bdw, bdw, length) == 0) {
                        list_move_tail(&nfit_bdw->list, &acpi_desc->bdws);
                        return true;
                }
@@ -332,11 +336,12 @@ static bool add_idt(struct acpi_nfit_desc *acpi_desc,
                struct nfit_table_prev *prev,
                struct acpi_nfit_interleave *idt)
 {
+       size_t length = min_t(size_t, sizeof(*idt), idt->header.length);
        struct device *dev = acpi_desc->dev;
        struct nfit_idt *nfit_idt;
 
        list_for_each_entry(nfit_idt, &prev->idts, list)
-               if (memcmp(nfit_idt->idt, idt, sizeof(*idt)) == 0) {
+               if (memcmp(nfit_idt->idt, idt, length) == 0) {
                        list_move_tail(&nfit_idt->list, &acpi_desc->idts);
                        return true;
                }
@@ -356,11 +361,12 @@ static bool add_flush(struct acpi_nfit_desc *acpi_desc,
                struct nfit_table_prev *prev,
                struct acpi_nfit_flush_address *flush)
 {
+       size_t length = min_t(size_t, sizeof(*flush), flush->header.length);
        struct device *dev = acpi_desc->dev;
        struct nfit_flush *nfit_flush;
 
        list_for_each_entry(nfit_flush, &prev->flushes, list)
-               if (memcmp(nfit_flush->flush, flush, sizeof(*flush)) == 0) {
+               if (memcmp(nfit_flush->flush, flush, length) == 0) {
                        list_move_tail(&nfit_flush->list, &acpi_desc->flushes);
                        return true;
                }
@@ -655,7 +661,7 @@ static ssize_t revision_show(struct device *dev,
        struct nvdimm_bus_descriptor *nd_desc = to_nd_desc(nvdimm_bus);
        struct acpi_nfit_desc *acpi_desc = to_acpi_desc(nd_desc);
 
-       return sprintf(buf, "%d\n", acpi_desc->nfit->header.revision);
+       return sprintf(buf, "%d\n", acpi_desc->acpi_header.revision);
 }
 static DEVICE_ATTR_RO(revision);
 
@@ -1652,7 +1658,6 @@ int acpi_nfit_init(struct acpi_nfit_desc *acpi_desc, acpi_size sz)
 
        data = (u8 *) acpi_desc->nfit;
        end = data + sz;
-       data += sizeof(struct acpi_table_nfit);
        while (!IS_ERR_OR_NULL(data))
                data = add_table(acpi_desc, &prev, data, end);
 
@@ -1748,13 +1753,29 @@ static int acpi_nfit_add(struct acpi_device *adev)
                return PTR_ERR(acpi_desc);
        }
 
-       acpi_desc->nfit = (struct acpi_table_nfit *) tbl;
+       /*
+        * Save the acpi header for later and then skip it,
+        * making nfit point to the first nfit table header.
+        */
+       acpi_desc->acpi_header = *tbl;
+       acpi_desc->nfit = (void *) tbl + sizeof(struct acpi_table_nfit);
+       sz -= sizeof(struct acpi_table_nfit);
 
        /* Evaluate _FIT and override with that if present */
        status = acpi_evaluate_object(adev->handle, "_FIT", NULL, &buf);
        if (ACPI_SUCCESS(status) && buf.length > 0) {
-               acpi_desc->nfit = (struct acpi_table_nfit *)buf.pointer;
-               sz = buf.length;
+               union acpi_object *obj;
+               /*
+                * Adjust for the acpi_object header of the _FIT
+                */
+               obj = buf.pointer;
+               if (obj->type == ACPI_TYPE_BUFFER) {
+                       acpi_desc->nfit =
+                               (struct acpi_nfit_header *)obj->buffer.pointer;
+                       sz = obj->buffer.length;
+               } else
+                       dev_dbg(dev, "%s invalid type %d, ignoring _FIT\n",
+                                __func__, (int) obj->type);
        }
 
        rc = acpi_nfit_init(acpi_desc, sz);
@@ -1777,7 +1798,8 @@ static void acpi_nfit_notify(struct acpi_device *adev, u32 event)
 {
        struct acpi_nfit_desc *acpi_desc = dev_get_drvdata(&adev->dev);
        struct acpi_buffer buf = { ACPI_ALLOCATE_BUFFER, NULL };
-       struct acpi_table_nfit *nfit_saved;
+       struct acpi_nfit_header *nfit_saved;
+       union acpi_object *obj;
        struct device *dev = &adev->dev;
        acpi_status status;
        int ret;
@@ -1788,7 +1810,7 @@ static void acpi_nfit_notify(struct acpi_device *adev, u32 event)
        if (!dev->driver) {
                /* dev->driver may be null if we're being removed */
                dev_dbg(dev, "%s: no driver found for dev\n", __func__);
-               return;
+               goto out_unlock;
        }
 
        if (!acpi_desc) {
@@ -1808,12 +1830,19 @@ static void acpi_nfit_notify(struct acpi_device *adev, u32 event)
        }
 
        nfit_saved = acpi_desc->nfit;
-       acpi_desc->nfit = (struct acpi_table_nfit *)buf.pointer;
-       ret = acpi_nfit_init(acpi_desc, buf.length);
-       if (!ret) {
-               /* Merge failed, restore old nfit, and exit */
-               acpi_desc->nfit = nfit_saved;
-               dev_err(dev, "failed to merge updated NFIT\n");
+       obj = buf.pointer;
+       if (obj->type == ACPI_TYPE_BUFFER) {
+               acpi_desc->nfit =
+                       (struct acpi_nfit_header *)obj->buffer.pointer;
+               ret = acpi_nfit_init(acpi_desc, obj->buffer.length);
+               if (ret) {
+                       /* Merge failed, restore old nfit, and exit */
+                       acpi_desc->nfit = nfit_saved;
+                       dev_err(dev, "failed to merge updated NFIT\n");
+               }
+       } else {
+               /* Bad _FIT, restore old nfit */
+               dev_err(dev, "Invalid _FIT\n");
        }
        kfree(buf.pointer);
 
index 2ea5c0797c8f4575c090a34352ceba14d9a5af40..3d549a3836590bb9dd55f6dd14dd8619698597ab 100644 (file)
@@ -96,7 +96,8 @@ struct nfit_mem {
 
 struct acpi_nfit_desc {
        struct nvdimm_bus_descriptor nd_desc;
-       struct acpi_table_nfit *nfit;
+       struct acpi_table_header acpi_header;
+       struct acpi_nfit_header *nfit;
        struct mutex spa_map_mutex;
        struct mutex init_mutex;
        struct list_head spa_maps;
index 850d7bf0c873fb64af77ada90e971a733527e2bd..ae3fe4e642035b2d51b2e3f6c4d93e68a6cb1bcc 100644 (file)
@@ -768,6 +768,13 @@ static void pci_acpi_root_add_resources(struct acpi_pci_root_info *info)
                else
                        continue;
 
+               /*
+                * Some legacy x86 host bridge drivers use iomem_resource and
+                * ioport_resource as default resource pool, skip it.
+                */
+               if (res == root)
+                       continue;
+
                conflict = insert_resource_conflict(root, res);
                if (conflict) {
                        dev_info(&info->bridge->dev,
index f4e02ae93f585fbb8de42c09d4d0fb32d2751887..11154a330f075dc04c0fec99299d6f5000e901be 100644 (file)
@@ -200,7 +200,8 @@ static int acpi_pss_perf_init(struct acpi_processor *pr,
                goto err_remove_sysfs_thermal;
        }
 
-       sysfs_remove_link(&pr->cdev->device.kobj, "device");
+       return 0;
+
  err_remove_sysfs_thermal:
        sysfs_remove_link(&device->dev.kobj, "thermal_cooling");
  err_thermal_unregister:
index bf034f8b7c1acde77f90ded7f39f70dbd636b7db..2fa8304171e09b70e501dcab7892a9b443c84695 100644 (file)
@@ -14,7 +14,6 @@
 #include <linux/delay.h>
 #include <linux/module.h>
 #include <linux/interrupt.h>
-#include <linux/dmi.h>
 #include "sbshc.h"
 
 #define PREFIX "ACPI: "
@@ -30,6 +29,7 @@ struct acpi_smb_hc {
        u8 query_bit;
        smbus_alarm_callback callback;
        void *context;
+       bool done;
 };
 
 static int acpi_smbus_hc_add(struct acpi_device *device);
@@ -88,8 +88,6 @@ enum acpi_smb_offset {
        ACPI_SMB_ALARM_DATA = 0x26,     /* 2 bytes alarm data */
 };
 
-static bool macbook;
-
 static inline int smb_hc_read(struct acpi_smb_hc *hc, u8 address, u8 *data)
 {
        return ec_read(hc->offset + address, data);
@@ -100,27 +98,11 @@ static inline int smb_hc_write(struct acpi_smb_hc *hc, u8 address, u8 data)
        return ec_write(hc->offset + address, data);
 }
 
-static inline int smb_check_done(struct acpi_smb_hc *hc)
-{
-       union acpi_smb_status status = {.raw = 0};
-       smb_hc_read(hc, ACPI_SMB_STATUS, &status.raw);
-       return status.fields.done && (status.fields.status == SMBUS_OK);
-}
-
 static int wait_transaction_complete(struct acpi_smb_hc *hc, int timeout)
 {
-       if (wait_event_timeout(hc->wait, smb_check_done(hc),
-                              msecs_to_jiffies(timeout)))
+       if (wait_event_timeout(hc->wait, hc->done, msecs_to_jiffies(timeout)))
                return 0;
-       /*
-        * After the timeout happens, OS will try to check the status of SMbus.
-        * If the status is what OS expected, it will be regarded as the bogus
-        * timeout.
-        */
-       if (smb_check_done(hc))
-               return 0;
-       else
-               return -ETIME;
+       return -ETIME;
 }
 
 static int acpi_smbus_transaction(struct acpi_smb_hc *hc, u8 protocol,
@@ -135,8 +117,7 @@ static int acpi_smbus_transaction(struct acpi_smb_hc *hc, u8 protocol,
        }
 
        mutex_lock(&hc->lock);
-       if (macbook)
-               udelay(5);
+       hc->done = false;
        if (smb_hc_read(hc, ACPI_SMB_PROTOCOL, &temp))
                goto end;
        if (temp) {
@@ -235,8 +216,10 @@ static int smbus_alarm(void *context)
        if (smb_hc_read(hc, ACPI_SMB_STATUS, &status.raw))
                return 0;
        /* Check if it is only a completion notify */
-       if (status.fields.done)
+       if (status.fields.done && status.fields.status == SMBUS_OK) {
+               hc->done = true;
                wake_up(&hc->wait);
+       }
        if (!status.fields.alarm)
                return 0;
        mutex_lock(&hc->lock);
@@ -262,29 +245,12 @@ extern int acpi_ec_add_query_handler(struct acpi_ec *ec, u8 query_bit,
                              acpi_handle handle, acpi_ec_query_func func,
                              void *data);
 
-static int macbook_dmi_match(const struct dmi_system_id *d)
-{
-       pr_debug("Detected MacBook, enabling workaround\n");
-       macbook = true;
-       return 0;
-}
-
-static struct dmi_system_id acpi_smbus_dmi_table[] = {
-       { macbook_dmi_match, "Apple MacBook", {
-         DMI_MATCH(DMI_BOARD_VENDOR, "Apple"),
-         DMI_MATCH(DMI_PRODUCT_NAME, "MacBook") },
-       },
-       { },
-};
-
 static int acpi_smbus_hc_add(struct acpi_device *device)
 {
        int status;
        unsigned long long val;
        struct acpi_smb_hc *hc;
 
-       dmi_check_system(acpi_smbus_dmi_table);
-
        if (!device)
                return -EINVAL;
 
index ff02bb4218fcaae3bbf60821e6d41f81b5a0e40d..cdfbcc54821fd6ea3a5dd6a11c969f12055c7e24 100644 (file)
@@ -314,16 +314,6 @@ static const struct pci_device_id ahci_pci_tbl[] = {
        { PCI_VDEVICE(INTEL, 0x1f37), board_ahci_avn }, /* Avoton RAID */
        { PCI_VDEVICE(INTEL, 0x1f3e), board_ahci_avn }, /* Avoton RAID */
        { PCI_VDEVICE(INTEL, 0x1f3f), board_ahci_avn }, /* Avoton RAID */
-       { PCI_VDEVICE(INTEL, 0xa182), board_ahci }, /* Lewisburg AHCI*/
-       { PCI_VDEVICE(INTEL, 0xa202), board_ahci }, /* Lewisburg AHCI*/
-       { PCI_VDEVICE(INTEL, 0xa184), board_ahci }, /* Lewisburg RAID*/
-       { PCI_VDEVICE(INTEL, 0xa204), board_ahci }, /* Lewisburg RAID*/
-       { PCI_VDEVICE(INTEL, 0xa186), board_ahci }, /* Lewisburg RAID*/
-       { PCI_VDEVICE(INTEL, 0xa206), board_ahci }, /* Lewisburg RAID*/
-       { PCI_VDEVICE(INTEL, 0x2822), board_ahci }, /* Lewisburg RAID*/
-       { PCI_VDEVICE(INTEL, 0x2826), board_ahci }, /* Lewisburg RAID*/
-       { PCI_VDEVICE(INTEL, 0xa18e), board_ahci }, /* Lewisburg RAID*/
-       { PCI_VDEVICE(INTEL, 0xa20e), board_ahci }, /* Lewisburg RAID*/
        { PCI_VDEVICE(INTEL, 0x2823), board_ahci }, /* Wellsburg RAID */
        { PCI_VDEVICE(INTEL, 0x2827), board_ahci }, /* Wellsburg RAID */
        { PCI_VDEVICE(INTEL, 0x8d02), board_ahci }, /* Wellsburg AHCI */
@@ -350,10 +340,22 @@ static const struct pci_device_id ahci_pci_tbl[] = {
        { PCI_VDEVICE(INTEL, 0x9d03), board_ahci }, /* Sunrise Point-LP AHCI */
        { PCI_VDEVICE(INTEL, 0x9d05), board_ahci }, /* Sunrise Point-LP RAID */
        { PCI_VDEVICE(INTEL, 0x9d07), board_ahci }, /* Sunrise Point-LP RAID */
+       { PCI_VDEVICE(INTEL, 0xa102), board_ahci }, /* Sunrise Point-H AHCI */
        { PCI_VDEVICE(INTEL, 0xa103), board_ahci }, /* Sunrise Point-H AHCI */
        { PCI_VDEVICE(INTEL, 0xa105), board_ahci }, /* Sunrise Point-H RAID */
+       { PCI_VDEVICE(INTEL, 0xa106), board_ahci }, /* Sunrise Point-H RAID */
        { PCI_VDEVICE(INTEL, 0xa107), board_ahci }, /* Sunrise Point-H RAID */
        { PCI_VDEVICE(INTEL, 0xa10f), board_ahci }, /* Sunrise Point-H RAID */
+       { PCI_VDEVICE(INTEL, 0x2822), board_ahci }, /* Lewisburg RAID*/
+       { PCI_VDEVICE(INTEL, 0x2826), board_ahci }, /* Lewisburg RAID*/
+       { PCI_VDEVICE(INTEL, 0xa182), board_ahci }, /* Lewisburg AHCI*/
+       { PCI_VDEVICE(INTEL, 0xa184), board_ahci }, /* Lewisburg RAID*/
+       { PCI_VDEVICE(INTEL, 0xa186), board_ahci }, /* Lewisburg RAID*/
+       { PCI_VDEVICE(INTEL, 0xa18e), board_ahci }, /* Lewisburg RAID*/
+       { PCI_VDEVICE(INTEL, 0xa202), board_ahci }, /* Lewisburg AHCI*/
+       { PCI_VDEVICE(INTEL, 0xa204), board_ahci }, /* Lewisburg RAID*/
+       { PCI_VDEVICE(INTEL, 0xa206), board_ahci }, /* Lewisburg RAID*/
+       { PCI_VDEVICE(INTEL, 0xa20e), board_ahci }, /* Lewisburg RAID*/
 
        /* JMicron 360/1/3/5/6, match class to avoid IDE function */
        { PCI_VENDOR_ID_JMICRON, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID,
index 8490d37aee2a466809c2634e51e8b96386e2eecb..f7a7fa81740e8f7e7f1daa0c6d6e48d344496ceb 100644 (file)
@@ -62,6 +62,7 @@ static void ahci_mvebu_regret_option(struct ahci_host_priv *hpriv)
        writel(0x80, hpriv->mmio + AHCI_VENDOR_SPECIFIC_0_DATA);
 }
 
+#ifdef CONFIG_PM_SLEEP
 static int ahci_mvebu_suspend(struct platform_device *pdev, pm_message_t state)
 {
        return ahci_platform_suspend_host(&pdev->dev);
@@ -81,6 +82,10 @@ static int ahci_mvebu_resume(struct platform_device *pdev)
 
        return ahci_platform_resume_host(&pdev->dev);
 }
+#else
+#define ahci_mvebu_suspend NULL
+#define ahci_mvebu_resume NULL
+#endif
 
 static const struct ata_port_info ahci_mvebu_port_info = {
        .flags     = AHCI_FLAG_COMMON,
index 096064cd6c52b1b0f72bf710d1a56893bd6bff9c..4665512dae44d99e9a5af194812094498d5888cf 100644 (file)
@@ -1273,6 +1273,15 @@ static int ahci_exec_polled_cmd(struct ata_port *ap, int pmp,
        ata_tf_to_fis(tf, pmp, is_cmd, fis);
        ahci_fill_cmd_slot(pp, 0, cmd_fis_len | flags | (pmp << 12));
 
+       /* set port value for softreset of Port Multiplier */
+       if (pp->fbs_enabled && pp->fbs_last_dev != pmp) {
+               tmp = readl(port_mmio + PORT_FBS);
+               tmp &= ~(PORT_FBS_DEV_MASK | PORT_FBS_DEC);
+               tmp |= pmp << PORT_FBS_DEV_OFFSET;
+               writel(tmp, port_mmio + PORT_FBS);
+               pp->fbs_last_dev = pmp;
+       }
+
        /* issue & wait */
        writel(1, port_mmio + PORT_CMD_ISSUE);
 
index cb0508af1459ac43f4aa26f1a16d94134bd9d0bc..961acc788f4490cea48abb4e215cb144d8fc5e93 100644 (file)
@@ -1505,12 +1505,20 @@ static const char *ata_err_string(unsigned int err_mask)
 unsigned int ata_read_log_page(struct ata_device *dev, u8 log,
                               u8 page, void *buf, unsigned int sectors)
 {
+       unsigned long ap_flags = dev->link->ap->flags;
        struct ata_taskfile tf;
        unsigned int err_mask;
        bool dma = false;
 
        DPRINTK("read log page - log 0x%x, page 0x%x\n", log, page);
 
+       /*
+        * Return error without actually issuing the command on controllers
+        * which e.g. lockup on a read log page.
+        */
+       if (ap_flags & ATA_FLAG_NO_LOG_PAGE)
+               return AC_ERR_DEV;
+
 retry:
        ata_tf_init(dev, &tf);
        if (dev->dma_mode && ata_id_has_read_log_dma_ext(dev->id) &&
index 5389579c51204cf336f2689052ccf29c48b8af98..a723ae92978310f64e65eeef44509337a027c8a5 100644 (file)
@@ -45,7 +45,8 @@ enum {
        SATA_FSL_MAX_PRD_DIRECT = 16,   /* Direct PRDT entries */
 
        SATA_FSL_HOST_FLAGS     = (ATA_FLAG_SATA | ATA_FLAG_PIO_DMA |
-                               ATA_FLAG_PMP | ATA_FLAG_NCQ | ATA_FLAG_AN),
+                                  ATA_FLAG_PMP | ATA_FLAG_NCQ |
+                                  ATA_FLAG_AN | ATA_FLAG_NO_LOG_PAGE),
 
        SATA_FSL_MAX_CMDS       = SATA_FSL_QUEUE_DEPTH,
        SATA_FSL_CMD_HDR_SIZE   = 16,   /* 4 DWORDS */
index dea6edcbf145c3d1eaf45d8265ae7f971d6c808c..29bcff086bcedd548f90a15fd67829c7b21a4de9 100644 (file)
@@ -630,6 +630,9 @@ static void sil_dev_config(struct ata_device *dev)
        unsigned int n, quirks = 0;
        unsigned char model_num[ATA_ID_PROD_LEN + 1];
 
+       /* This controller doesn't support trim */
+       dev->horkage |= ATA_HORKAGE_NOTRIM;
+
        ata_id_c_string(dev->id, model_num, ATA_ID_PROD, sizeof(model_num));
 
        for (n = 0; sil_blacklist[n].product; n++)
index 2804aed3f416aea878efde04937937e238ff4e5e..25425d3f257536b291f27aa975bb8f164c0c437c 100644 (file)
@@ -303,6 +303,10 @@ static int memory_subsys_offline(struct device *dev)
        if (mem->state == MEM_OFFLINE)
                return 0;
 
+       /* Can't offline block with non-present sections */
+       if (mem->section_count != sections_per_block)
+               return -EINVAL;
+
        return memory_block_change_state(mem, MEM_OFFLINE, MEM_ONLINE);
 }
 
index e03b1ad25a906334078490786dbd1406ac9ca76b..65f50eccd49b0aa4b6801912fd8d21a73f79a7b9 100644 (file)
@@ -390,6 +390,7 @@ static int pm_genpd_runtime_suspend(struct device *dev)
        struct generic_pm_domain *genpd;
        bool (*stop_ok)(struct device *__dev);
        struct gpd_timing_data *td = &dev_gpd_data(dev)->td;
+       bool runtime_pm = pm_runtime_enabled(dev);
        ktime_t time_start;
        s64 elapsed_ns;
        int ret;
@@ -400,12 +401,19 @@ static int pm_genpd_runtime_suspend(struct device *dev)
        if (IS_ERR(genpd))
                return -EINVAL;
 
+       /*
+        * A runtime PM centric subsystem/driver may re-use the runtime PM
+        * callbacks for other purposes than runtime PM. In those scenarios
+        * runtime PM is disabled. Under these circumstances, we shall skip
+        * validating/measuring the PM QoS latency.
+        */
        stop_ok = genpd->gov ? genpd->gov->stop_ok : NULL;
-       if (stop_ok && !stop_ok(dev))
+       if (runtime_pm && stop_ok && !stop_ok(dev))
                return -EBUSY;
 
        /* Measure suspend latency. */
-       time_start = ktime_get();
+       if (runtime_pm)
+               time_start = ktime_get();
 
        ret = genpd_save_dev(genpd, dev);
        if (ret)
@@ -418,13 +426,15 @@ static int pm_genpd_runtime_suspend(struct device *dev)
        }
 
        /* Update suspend latency value if the measured time exceeds it. */
-       elapsed_ns = ktime_to_ns(ktime_sub(ktime_get(), time_start));
-       if (elapsed_ns > td->suspend_latency_ns) {
-               td->suspend_latency_ns = elapsed_ns;
-               dev_dbg(dev, "suspend latency exceeded, %lld ns\n",
-                       elapsed_ns);
-               genpd->max_off_time_changed = true;
-               td->constraint_changed = true;
+       if (runtime_pm) {
+               elapsed_ns = ktime_to_ns(ktime_sub(ktime_get(), time_start));
+               if (elapsed_ns > td->suspend_latency_ns) {
+                       td->suspend_latency_ns = elapsed_ns;
+                       dev_dbg(dev, "suspend latency exceeded, %lld ns\n",
+                               elapsed_ns);
+                       genpd->max_off_time_changed = true;
+                       td->constraint_changed = true;
+               }
        }
 
        /*
@@ -453,6 +463,7 @@ static int pm_genpd_runtime_resume(struct device *dev)
 {
        struct generic_pm_domain *genpd;
        struct gpd_timing_data *td = &dev_gpd_data(dev)->td;
+       bool runtime_pm = pm_runtime_enabled(dev);
        ktime_t time_start;
        s64 elapsed_ns;
        int ret;
@@ -479,14 +490,14 @@ static int pm_genpd_runtime_resume(struct device *dev)
 
  out:
        /* Measure resume latency. */
-       if (timed)
+       if (timed && runtime_pm)
                time_start = ktime_get();
 
        genpd_start_dev(genpd, dev);
        genpd_restore_dev(genpd, dev);
 
        /* Update resume latency value if the measured time exceeds it. */
-       if (timed) {
+       if (timed && runtime_pm) {
                elapsed_ns = ktime_to_ns(ktime_sub(ktime_get(), time_start));
                if (elapsed_ns > td->resume_latency_ns) {
                        td->resume_latency_ns = elapsed_ns;
@@ -1775,10 +1786,10 @@ int genpd_dev_pm_attach(struct device *dev)
        }
 
        pd = of_genpd_get_from_provider(&pd_args);
+       of_node_put(pd_args.np);
        if (IS_ERR(pd)) {
                dev_dbg(dev, "%s() failed to find PM domain: %ld\n",
                        __func__, PTR_ERR(pd));
-               of_node_put(dev->of_node);
                return -EPROBE_DEFER;
        }
 
@@ -1796,7 +1807,6 @@ int genpd_dev_pm_attach(struct device *dev)
        if (ret < 0) {
                dev_err(dev, "failed to add to PM domain %s: %d",
                        pd->name, ret);
-               of_node_put(dev->of_node);
                goto out;
        }
 
index e60dd12e23aaee75a2a0d90ba0ba720c28c769e7..1e937ac5f45661b6e2af770e1ab9633e91ad7bd6 100644 (file)
@@ -160,9 +160,6 @@ static bool default_power_down_ok(struct dev_pm_domain *pd)
                struct gpd_timing_data *td;
                s64 constraint_ns;
 
-               if (!pdd->dev->driver)
-                       continue;
-
                /*
                 * Check if the device is allowed to be off long enough for the
                 * domain to turn off and on (that's how much time it will
index eb6e67451decee999901493d9182ed6c9cf21bf9..0d77cd6fd8d11653c789fa8834e8eb53b801a6d9 100644 (file)
@@ -68,6 +68,9 @@ int dev_pm_set_wake_irq(struct device *dev, int irq)
        struct wake_irq *wirq;
        int err;
 
+       if (irq < 0)
+               return -EINVAL;
+
        wirq = kzalloc(sizeof(*wirq), GFP_KERNEL);
        if (!wirq)
                return -ENOMEM;
@@ -167,6 +170,9 @@ int dev_pm_set_dedicated_wake_irq(struct device *dev, int irq)
        struct wake_irq *wirq;
        int err;
 
+       if (irq < 0)
+               return -EINVAL;
+
        wirq = kzalloc(sizeof(*wirq), GFP_KERNEL);
        if (!wirq)
                return -ENOMEM;
index a28a562f7b7f245355db7d536e0558c78cc7e374..3457ac8c03e2f3cfe10c8a2ccc26f9a706039831 100644 (file)
@@ -3810,7 +3810,6 @@ static int mtip_block_initialize(struct driver_data *dd)
        sector_t capacity;
        unsigned int index = 0;
        struct kobject *kobj;
-       unsigned char thd_name[16];
 
        if (dd->disk)
                goto skip_create_disk; /* hw init done, before rebuild */
@@ -3958,10 +3957,9 @@ skip_create_disk:
        }
 
 start_service_thread:
-       sprintf(thd_name, "mtip_svc_thd_%02d", index);
        dd->mtip_svc_handler = kthread_create_on_node(mtip_service_thread,
-                                               dd, dd->numa_node, "%s",
-                                               thd_name);
+                                               dd, dd->numa_node,
+                                               "mtip_svc_thd_%02d", index);
 
        if (IS_ERR(dd->mtip_svc_handler)) {
                dev_err(&dd->pdev->dev, "service thread failed to start\n");
index 6255d1c4bba46c802548806ff95ee213ffd3f0e6..09e3c0d87eccff2d526666b99d3036f3921662a8 100644 (file)
@@ -8,6 +8,7 @@
 #include <linux/slab.h>
 #include <linux/blk-mq.h>
 #include <linux/hrtimer.h>
+#include <linux/lightnvm.h>
 
 struct nullb_cmd {
        struct list_head list;
@@ -17,6 +18,7 @@ struct nullb_cmd {
        struct bio *bio;
        unsigned int tag;
        struct nullb_queue *nq;
+       struct hrtimer timer;
 };
 
 struct nullb_queue {
@@ -39,23 +41,14 @@ struct nullb {
 
        struct nullb_queue *queues;
        unsigned int nr_queues;
+       char disk_name[DISK_NAME_LEN];
 };
 
 static LIST_HEAD(nullb_list);
 static struct mutex lock;
 static int null_major;
 static int nullb_indexes;
-
-struct completion_queue {
-       struct llist_head list;
-       struct hrtimer timer;
-};
-
-/*
- * These are per-cpu for now, they will need to be configured by the
- * complete_queues parameter and appropriately mapped.
- */
-static DEFINE_PER_CPU(struct completion_queue, completion_queues);
+static struct kmem_cache *ppa_cache;
 
 enum {
        NULL_IRQ_NONE           = 0,
@@ -119,6 +112,10 @@ static int nr_devices = 2;
 module_param(nr_devices, int, S_IRUGO);
 MODULE_PARM_DESC(nr_devices, "Number of devices to register");
 
+static bool use_lightnvm;
+module_param(use_lightnvm, bool, S_IRUGO);
+MODULE_PARM_DESC(use_lightnvm, "Register as a LightNVM device");
+
 static int irqmode = NULL_IRQ_SOFTIRQ;
 
 static int null_set_irqmode(const char *str, const struct kernel_param *kp)
@@ -135,8 +132,8 @@ static const struct kernel_param_ops null_irqmode_param_ops = {
 device_param_cb(irqmode, &null_irqmode_param_ops, &irqmode, S_IRUGO);
 MODULE_PARM_DESC(irqmode, "IRQ completion handler. 0-none, 1-softirq, 2-timer");
 
-static int completion_nsec = 10000;
-module_param(completion_nsec, int, S_IRUGO);
+static unsigned long completion_nsec = 10000;
+module_param(completion_nsec, ulong, S_IRUGO);
 MODULE_PARM_DESC(completion_nsec, "Time in ns to complete a request in hardware. Default: 10,000ns");
 
 static int hw_queue_depth = 64;
@@ -173,6 +170,8 @@ static void free_cmd(struct nullb_cmd *cmd)
        put_tag(cmd->nq, cmd->tag);
 }
 
+static enum hrtimer_restart null_cmd_timer_expired(struct hrtimer *timer);
+
 static struct nullb_cmd *__alloc_cmd(struct nullb_queue *nq)
 {
        struct nullb_cmd *cmd;
@@ -183,6 +182,11 @@ static struct nullb_cmd *__alloc_cmd(struct nullb_queue *nq)
                cmd = &nq->cmds[tag];
                cmd->tag = tag;
                cmd->nq = nq;
+               if (irqmode == NULL_IRQ_TIMER) {
+                       hrtimer_init(&cmd->timer, CLOCK_MONOTONIC,
+                                    HRTIMER_MODE_REL);
+                       cmd->timer.function = null_cmd_timer_expired;
+               }
                return cmd;
        }
 
@@ -213,6 +217,11 @@ static struct nullb_cmd *alloc_cmd(struct nullb_queue *nq, int can_wait)
 
 static void end_cmd(struct nullb_cmd *cmd)
 {
+       struct request_queue *q = NULL;
+
+       if (cmd->rq)
+               q = cmd->rq->q;
+
        switch (queue_mode)  {
        case NULL_Q_MQ:
                blk_mq_end_request(cmd->rq, 0);
@@ -227,51 +236,29 @@ static void end_cmd(struct nullb_cmd *cmd)
        }
 
        free_cmd(cmd);
+
+       /* Restart queue if needed, as we are freeing a tag */
+       if (queue_mode == NULL_Q_RQ && blk_queue_stopped(q)) {
+               unsigned long flags;
+
+               spin_lock_irqsave(q->queue_lock, flags);
+               blk_start_queue_async(q);
+               spin_unlock_irqrestore(q->queue_lock, flags);
+       }
 }
 
 static enum hrtimer_restart null_cmd_timer_expired(struct hrtimer *timer)
 {
-       struct completion_queue *cq;
-       struct llist_node *entry;
-       struct nullb_cmd *cmd;
-
-       cq = &per_cpu(completion_queues, smp_processor_id());
-
-       while ((entry = llist_del_all(&cq->list)) != NULL) {
-               entry = llist_reverse_order(entry);
-               do {
-                       struct request_queue *q = NULL;
-
-                       cmd = container_of(entry, struct nullb_cmd, ll_list);
-                       entry = entry->next;
-                       if (cmd->rq)
-                               q = cmd->rq->q;
-                       end_cmd(cmd);
-
-                       if (q && !q->mq_ops && blk_queue_stopped(q)) {
-                               spin_lock(q->queue_lock);
-                               if (blk_queue_stopped(q))
-                                       blk_start_queue(q);
-                               spin_unlock(q->queue_lock);
-                       }
-               } while (entry);
-       }
+       end_cmd(container_of(timer, struct nullb_cmd, timer));
 
        return HRTIMER_NORESTART;
 }
 
 static void null_cmd_end_timer(struct nullb_cmd *cmd)
 {
-       struct completion_queue *cq = &per_cpu(completion_queues, get_cpu());
+       ktime_t kt = ktime_set(0, completion_nsec);
 
-       cmd->ll_list.next = NULL;
-       if (llist_add(&cmd->ll_list, &cq->list)) {
-               ktime_t kt = ktime_set(0, completion_nsec);
-
-               hrtimer_start(&cq->timer, kt, HRTIMER_MODE_REL_PINNED);
-       }
-
-       put_cpu();
+       hrtimer_start(&cmd->timer, kt, HRTIMER_MODE_REL);
 }
 
 static void null_softirq_done_fn(struct request *rq)
@@ -369,6 +356,10 @@ static int null_queue_rq(struct blk_mq_hw_ctx *hctx,
 {
        struct nullb_cmd *cmd = blk_mq_rq_to_pdu(bd->rq);
 
+       if (irqmode == NULL_IRQ_TIMER) {
+               hrtimer_init(&cmd->timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
+               cmd->timer.function = null_cmd_timer_expired;
+       }
        cmd->rq = bd->rq;
        cmd->nq = hctx->driver_data;
 
@@ -427,15 +418,157 @@ static void null_del_dev(struct nullb *nullb)
 {
        list_del_init(&nullb->list);
 
-       del_gendisk(nullb->disk);
+       if (use_lightnvm)
+               nvm_unregister(nullb->disk_name);
+       else
+               del_gendisk(nullb->disk);
        blk_cleanup_queue(nullb->q);
        if (queue_mode == NULL_Q_MQ)
                blk_mq_free_tag_set(&nullb->tag_set);
-       put_disk(nullb->disk);
+       if (!use_lightnvm)
+               put_disk(nullb->disk);
        cleanup_queues(nullb);
        kfree(nullb);
 }
 
+#ifdef CONFIG_NVM
+
+static void null_lnvm_end_io(struct request *rq, int error)
+{
+       struct nvm_rq *rqd = rq->end_io_data;
+       struct nvm_dev *dev = rqd->dev;
+
+       dev->mt->end_io(rqd, error);
+
+       blk_put_request(rq);
+}
+
+static int null_lnvm_submit_io(struct nvm_dev *dev, struct nvm_rq *rqd)
+{
+       struct request_queue *q = dev->q;
+       struct request *rq;
+       struct bio *bio = rqd->bio;
+
+       rq = blk_mq_alloc_request(q, bio_rw(bio), GFP_KERNEL, 0);
+       if (IS_ERR(rq))
+               return -ENOMEM;
+
+       rq->cmd_type = REQ_TYPE_DRV_PRIV;
+       rq->__sector = bio->bi_iter.bi_sector;
+       rq->ioprio = bio_prio(bio);
+
+       if (bio_has_data(bio))
+               rq->nr_phys_segments = bio_phys_segments(q, bio);
+
+       rq->__data_len = bio->bi_iter.bi_size;
+       rq->bio = rq->biotail = bio;
+
+       rq->end_io_data = rqd;
+
+       blk_execute_rq_nowait(q, NULL, rq, 0, null_lnvm_end_io);
+
+       return 0;
+}
+
+static int null_lnvm_id(struct nvm_dev *dev, struct nvm_id *id)
+{
+       sector_t size = gb * 1024 * 1024 * 1024ULL;
+       sector_t blksize;
+       struct nvm_id_group *grp;
+
+       id->ver_id = 0x1;
+       id->vmnt = 0;
+       id->cgrps = 1;
+       id->cap = 0x3;
+       id->dom = 0x1;
+
+       id->ppaf.blk_offset = 0;
+       id->ppaf.blk_len = 16;
+       id->ppaf.pg_offset = 16;
+       id->ppaf.pg_len = 16;
+       id->ppaf.sect_offset = 32;
+       id->ppaf.sect_len = 8;
+       id->ppaf.pln_offset = 40;
+       id->ppaf.pln_len = 8;
+       id->ppaf.lun_offset = 48;
+       id->ppaf.lun_len = 8;
+       id->ppaf.ch_offset = 56;
+       id->ppaf.ch_len = 8;
+
+       do_div(size, bs); /* convert size to pages */
+       do_div(size, 256); /* concert size to pgs pr blk */
+       grp = &id->groups[0];
+       grp->mtype = 0;
+       grp->fmtype = 0;
+       grp->num_ch = 1;
+       grp->num_pg = 256;
+       blksize = size;
+       do_div(size, (1 << 16));
+       grp->num_lun = size + 1;
+       do_div(blksize, grp->num_lun);
+       grp->num_blk = blksize;
+       grp->num_pln = 1;
+
+       grp->fpg_sz = bs;
+       grp->csecs = bs;
+       grp->trdt = 25000;
+       grp->trdm = 25000;
+       grp->tprt = 500000;
+       grp->tprm = 500000;
+       grp->tbet = 1500000;
+       grp->tbem = 1500000;
+       grp->mpos = 0x010101; /* single plane rwe */
+       grp->cpar = hw_queue_depth;
+
+       return 0;
+}
+
+static void *null_lnvm_create_dma_pool(struct nvm_dev *dev, char *name)
+{
+       mempool_t *virtmem_pool;
+
+       virtmem_pool = mempool_create_slab_pool(64, ppa_cache);
+       if (!virtmem_pool) {
+               pr_err("null_blk: Unable to create virtual memory pool\n");
+               return NULL;
+       }
+
+       return virtmem_pool;
+}
+
+static void null_lnvm_destroy_dma_pool(void *pool)
+{
+       mempool_destroy(pool);
+}
+
+static void *null_lnvm_dev_dma_alloc(struct nvm_dev *dev, void *pool,
+                               gfp_t mem_flags, dma_addr_t *dma_handler)
+{
+       return mempool_alloc(pool, mem_flags);
+}
+
+static void null_lnvm_dev_dma_free(void *pool, void *entry,
+                                                       dma_addr_t dma_handler)
+{
+       mempool_free(entry, pool);
+}
+
+static struct nvm_dev_ops null_lnvm_dev_ops = {
+       .identity               = null_lnvm_id,
+       .submit_io              = null_lnvm_submit_io,
+
+       .create_dma_pool        = null_lnvm_create_dma_pool,
+       .destroy_dma_pool       = null_lnvm_destroy_dma_pool,
+       .dev_dma_alloc          = null_lnvm_dev_dma_alloc,
+       .dev_dma_free           = null_lnvm_dev_dma_free,
+
+       /* Simulate nvme protocol restriction */
+       .max_phys_sect          = 64,
+};
+#else
+static struct nvm_dev_ops null_lnvm_dev_ops;
+#endif /* CONFIG_NVM */
+
 static int null_open(struct block_device *bdev, fmode_t mode)
 {
        return 0;
@@ -575,11 +708,6 @@ static int null_add_dev(void)
        queue_flag_set_unlocked(QUEUE_FLAG_NONROT, nullb->q);
        queue_flag_clear_unlocked(QUEUE_FLAG_ADD_RANDOM, nullb->q);
 
-       disk = nullb->disk = alloc_disk_node(1, home_node);
-       if (!disk) {
-               rv = -ENOMEM;
-               goto out_cleanup_blk_queue;
-       }
 
        mutex_lock(&lock);
        list_add_tail(&nullb->list, &nullb_list);
@@ -589,6 +717,21 @@ static int null_add_dev(void)
        blk_queue_logical_block_size(nullb->q, bs);
        blk_queue_physical_block_size(nullb->q, bs);
 
+       sprintf(nullb->disk_name, "nullb%d", nullb->index);
+
+       if (use_lightnvm) {
+               rv = nvm_register(nullb->q, nullb->disk_name,
+                                                       &null_lnvm_dev_ops);
+               if (rv)
+                       goto out_cleanup_blk_queue;
+               goto done;
+       }
+
+       disk = nullb->disk = alloc_disk_node(1, home_node);
+       if (!disk) {
+               rv = -ENOMEM;
+               goto out_cleanup_lightnvm;
+       }
        size = gb * 1024 * 1024 * 1024ULL;
        set_capacity(disk, size >> 9);
 
@@ -598,10 +741,15 @@ static int null_add_dev(void)
        disk->fops              = &null_fops;
        disk->private_data      = nullb;
        disk->queue             = nullb->q;
-       sprintf(disk->disk_name, "nullb%d", nullb->index);
+       strncpy(disk->disk_name, nullb->disk_name, DISK_NAME_LEN);
+
        add_disk(disk);
+done:
        return 0;
 
+out_cleanup_lightnvm:
+       if (use_lightnvm)
+               nvm_unregister(nullb->disk_name);
 out_cleanup_blk_queue:
        blk_cleanup_queue(nullb->q);
 out_cleanup_tags:
@@ -617,7 +765,9 @@ out:
 
 static int __init null_init(void)
 {
+       int ret = 0;
        unsigned int i;
+       struct nullb *nullb;
 
        if (bs > PAGE_SIZE) {
                pr_warn("null_blk: invalid block size\n");
@@ -625,6 +775,18 @@ static int __init null_init(void)
                bs = PAGE_SIZE;
        }
 
+       if (use_lightnvm && bs != 4096) {
+               pr_warn("null_blk: LightNVM only supports 4k block size\n");
+               pr_warn("null_blk: defaults block size to 4k\n");
+               bs = 4096;
+       }
+
+       if (use_lightnvm && queue_mode != NULL_Q_MQ) {
+               pr_warn("null_blk: LightNVM only supported for blk-mq\n");
+               pr_warn("null_blk: defaults queue mode to blk-mq\n");
+               queue_mode = NULL_Q_MQ;
+       }
+
        if (queue_mode == NULL_Q_MQ && use_per_node_hctx) {
                if (submit_queues < nr_online_nodes) {
                        pr_warn("null_blk: submit_queues param is set to %u.",
@@ -638,32 +800,38 @@ static int __init null_init(void)
 
        mutex_init(&lock);
 
-       /* Initialize a separate list for each CPU for issuing softirqs */
-       for_each_possible_cpu(i) {
-               struct completion_queue *cq = &per_cpu(completion_queues, i);
-
-               init_llist_head(&cq->list);
-
-               if (irqmode != NULL_IRQ_TIMER)
-                       continue;
-
-               hrtimer_init(&cq->timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
-               cq->timer.function = null_cmd_timer_expired;
-       }
-
        null_major = register_blkdev(0, "nullb");
        if (null_major < 0)
                return null_major;
 
-       for (i = 0; i < nr_devices; i++) {
-               if (null_add_dev()) {
-                       unregister_blkdev(null_major, "nullb");
-                       return -EINVAL;
+       if (use_lightnvm) {
+               ppa_cache = kmem_cache_create("ppa_cache", 64 * sizeof(u64),
+                                                               0, 0, NULL);
+               if (!ppa_cache) {
+                       pr_err("null_blk: unable to create ppa cache\n");
+                       ret = -ENOMEM;
+                       goto err_ppa;
                }
        }
 
+       for (i = 0; i < nr_devices; i++) {
+               ret = null_add_dev();
+               if (ret)
+                       goto err_dev;
+       }
+
        pr_info("null: module loaded\n");
        return 0;
+
+err_dev:
+       while (!list_empty(&nullb_list)) {
+               nullb = list_entry(nullb_list.next, struct nullb, list);
+               null_del_dev(nullb);
+       }
+       kmem_cache_destroy(ppa_cache);
+err_ppa:
+       unregister_blkdev(null_major, "nullb");
+       return ret;
 }
 
 static void __exit null_exit(void)
@@ -678,6 +846,8 @@ static void __exit null_exit(void)
                null_del_dev(nullb);
        }
        mutex_unlock(&lock);
+
+       kmem_cache_destroy(ppa_cache);
 }
 
 module_init(null_init);
index 235708c7c46eee709acb110acb95a28d85ebc946..81ea69fee7ca183313b8e8322833062262279187 100644 (file)
@@ -3442,6 +3442,7 @@ static void rbd_queue_workfn(struct work_struct *work)
                goto err_rq;
        }
        img_request->rq = rq;
+       snapc = NULL; /* img_request consumes a ref */
 
        if (op_type == OBJ_OP_DISCARD)
                result = rbd_img_request_fill(img_request, OBJ_REQUEST_NODATA,
index f9099940c2720f95874e6621b4c7e5e1e798fe2c..41fb1a917b172dc9446495d84357060847c2b569 100644 (file)
@@ -950,6 +950,8 @@ static int xen_blkbk_parse_indirect(struct blkif_request *req,
                goto unmap;
 
        for (n = 0, i = 0; n < nseg; n++) {
+               uint8_t first_sect, last_sect;
+
                if ((n % SEGS_PER_INDIRECT_FRAME) == 0) {
                        /* Map indirect segments */
                        if (segments)
@@ -957,15 +959,18 @@ static int xen_blkbk_parse_indirect(struct blkif_request *req,
                        segments = kmap_atomic(pages[n/SEGS_PER_INDIRECT_FRAME]->page);
                }
                i = n % SEGS_PER_INDIRECT_FRAME;
+
                pending_req->segments[n]->gref = segments[i].gref;
-               seg[n].nsec = segments[i].last_sect -
-                       segments[i].first_sect + 1;
-               seg[n].offset = (segments[i].first_sect << 9);
-               if ((segments[i].last_sect >= (XEN_PAGE_SIZE >> 9)) ||
-                   (segments[i].last_sect < segments[i].first_sect)) {
+
+               first_sect = READ_ONCE(segments[i].first_sect);
+               last_sect = READ_ONCE(segments[i].last_sect);
+               if (last_sect >= (XEN_PAGE_SIZE >> 9) || last_sect < first_sect) {
                        rc = -EINVAL;
                        goto unmap;
                }
+
+               seg[n].nsec = last_sect - first_sect + 1;
+               seg[n].offset = first_sect << 9;
                preq->nr_sects += seg[n].nsec;
        }
 
index 68e87a037b992df8c64d6894719b5b390ef1d10a..c929ae22764c9dd4345195a1542df997c5a8e29b 100644 (file)
@@ -408,8 +408,8 @@ static inline void blkif_get_x86_32_req(struct blkif_request *dst,
                                        struct blkif_x86_32_request *src)
 {
        int i, n = BLKIF_MAX_SEGMENTS_PER_REQUEST, j;
-       dst->operation = src->operation;
-       switch (src->operation) {
+       dst->operation = READ_ONCE(src->operation);
+       switch (dst->operation) {
        case BLKIF_OP_READ:
        case BLKIF_OP_WRITE:
        case BLKIF_OP_WRITE_BARRIER:
@@ -456,8 +456,8 @@ static inline void blkif_get_x86_64_req(struct blkif_request *dst,
                                        struct blkif_x86_64_request *src)
 {
        int i, n = BLKIF_MAX_SEGMENTS_PER_REQUEST, j;
-       dst->operation = src->operation;
-       switch (src->operation) {
+       dst->operation = READ_ONCE(src->operation);
+       switch (dst->operation) {
        case BLKIF_OP_READ:
        case BLKIF_OP_WRITE:
        case BLKIF_OP_WRITE_BARRIER:
index 9f185694875850427e9613aaf725859c7efbfc63..bf500e0e7362baf72f7a4321e5fda55dc4355f9b 100644 (file)
@@ -117,7 +117,7 @@ static struct platform_driver omap_ocp2scp_driver = {
 
 module_platform_driver(omap_ocp2scp_driver);
 
-MODULE_ALIAS("platform: omap-ocp2scp");
+MODULE_ALIAS("platform:omap-ocp2scp");
 MODULE_AUTHOR("Texas Instruments Inc.");
 MODULE_DESCRIPTION("OMAP OCP2SCP driver");
 MODULE_LICENSE("GPL v2");
index 846bc29c157dcca1bde81f288a5d323476042295..25996e2561105ac615cf4cc99c468f7a8db0f3df 100644 (file)
@@ -342,13 +342,13 @@ static int sunxi_rsb_read(struct sunxi_rsb *rsb, u8 rtaddr, u8 addr,
 
        ret = _sunxi_rsb_run_xfer(rsb);
        if (ret)
-               goto out;
+               goto unlock;
 
        *buf = readl(rsb->regs + RSB_DATA);
 
+unlock:
        mutex_unlock(&rsb->lock);
 
-out:
        return ret;
 }
 
@@ -527,9 +527,9 @@ static int sunxi_rsb_init_device_mode(struct sunxi_rsb *rsb)
  */
 
 static const struct sunxi_rsb_addr_map sunxi_rsb_addr_maps[] = {
-       { 0x3e3, 0x2d }, /* Primary PMIC: AXP223, AXP809, AXP81X, ... */
+       { 0x3a3, 0x2d }, /* Primary PMIC: AXP223, AXP809, AXP81X, ... */
        { 0x745, 0x3a }, /* Secondary PMIC: AXP806, ... */
-       { 0xe89, 0x45 }, /* Peripheral IC: AC100, ... */
+       { 0xe89, 0x4e }, /* Peripheral IC: AC100, ... */
 };
 
 static u8 sunxi_rsb_get_rtaddr(u16 hwaddr)
index 654f6f36a071c1411e21373d3cb53e00efadd4f6..4cc72fa017c7bbb02c4027e3bf44bc4d102d3849 100644 (file)
@@ -412,18 +412,42 @@ static enum si_sm_result start_next_msg(struct smi_info *smi_info)
        return rv;
 }
 
-static void start_check_enables(struct smi_info *smi_info)
+static void smi_mod_timer(struct smi_info *smi_info, unsigned long new_val)
+{
+       smi_info->last_timeout_jiffies = jiffies;
+       mod_timer(&smi_info->si_timer, new_val);
+       smi_info->timer_running = true;
+}
+
+/*
+ * Start a new message and (re)start the timer and thread.
+ */
+static void start_new_msg(struct smi_info *smi_info, unsigned char *msg,
+                         unsigned int size)
+{
+       smi_mod_timer(smi_info, jiffies + SI_TIMEOUT_JIFFIES);
+
+       if (smi_info->thread)
+               wake_up_process(smi_info->thread);
+
+       smi_info->handlers->start_transaction(smi_info->si_sm, msg, size);
+}
+
+static void start_check_enables(struct smi_info *smi_info, bool start_timer)
 {
        unsigned char msg[2];
 
        msg[0] = (IPMI_NETFN_APP_REQUEST << 2);
        msg[1] = IPMI_GET_BMC_GLOBAL_ENABLES_CMD;
 
-       smi_info->handlers->start_transaction(smi_info->si_sm, msg, 2);
+       if (start_timer)
+               start_new_msg(smi_info, msg, 2);
+       else
+               smi_info->handlers->start_transaction(smi_info->si_sm, msg, 2);
        smi_info->si_state = SI_CHECKING_ENABLES;
 }
 
-static void start_clear_flags(struct smi_info *smi_info)
+static void start_clear_flags(struct smi_info *smi_info, bool start_timer)
 {
        unsigned char msg[3];
 
@@ -432,7 +456,10 @@ static void start_clear_flags(struct smi_info *smi_info)
        msg[1] = IPMI_CLEAR_MSG_FLAGS_CMD;
        msg[2] = WDT_PRE_TIMEOUT_INT;
 
-       smi_info->handlers->start_transaction(smi_info->si_sm, msg, 3);
+       if (start_timer)
+               start_new_msg(smi_info, msg, 3);
+       else
+               smi_info->handlers->start_transaction(smi_info->si_sm, msg, 3);
        smi_info->si_state = SI_CLEARING_FLAGS;
 }
 
@@ -442,10 +469,8 @@ static void start_getting_msg_queue(struct smi_info *smi_info)
        smi_info->curr_msg->data[1] = IPMI_GET_MSG_CMD;
        smi_info->curr_msg->data_size = 2;
 
-       smi_info->handlers->start_transaction(
-               smi_info->si_sm,
-               smi_info->curr_msg->data,
-               smi_info->curr_msg->data_size);
+       start_new_msg(smi_info, smi_info->curr_msg->data,
+                     smi_info->curr_msg->data_size);
        smi_info->si_state = SI_GETTING_MESSAGES;
 }
 
@@ -455,20 +480,11 @@ static void start_getting_events(struct smi_info *smi_info)
        smi_info->curr_msg->data[1] = IPMI_READ_EVENT_MSG_BUFFER_CMD;
        smi_info->curr_msg->data_size = 2;
 
-       smi_info->handlers->start_transaction(
-               smi_info->si_sm,
-               smi_info->curr_msg->data,
-               smi_info->curr_msg->data_size);
+       start_new_msg(smi_info, smi_info->curr_msg->data,
+                     smi_info->curr_msg->data_size);
        smi_info->si_state = SI_GETTING_EVENTS;
 }
 
-static void smi_mod_timer(struct smi_info *smi_info, unsigned long new_val)
-{
-       smi_info->last_timeout_jiffies = jiffies;
-       mod_timer(&smi_info->si_timer, new_val);
-       smi_info->timer_running = true;
-}
-
 /*
  * When we have a situtaion where we run out of memory and cannot
  * allocate messages, we just leave them in the BMC and run the system
@@ -478,11 +494,11 @@ static void smi_mod_timer(struct smi_info *smi_info, unsigned long new_val)
  * Note that we cannot just use disable_irq(), since the interrupt may
  * be shared.
  */
-static inline bool disable_si_irq(struct smi_info *smi_info)
+static inline bool disable_si_irq(struct smi_info *smi_info, bool start_timer)
 {
        if ((smi_info->irq) && (!smi_info->interrupt_disabled)) {
                smi_info->interrupt_disabled = true;
-               start_check_enables(smi_info);
+               start_check_enables(smi_info, start_timer);
                return true;
        }
        return false;
@@ -492,7 +508,7 @@ static inline bool enable_si_irq(struct smi_info *smi_info)
 {
        if ((smi_info->irq) && (smi_info->interrupt_disabled)) {
                smi_info->interrupt_disabled = false;
-               start_check_enables(smi_info);
+               start_check_enables(smi_info, true);
                return true;
        }
        return false;
@@ -510,7 +526,7 @@ static struct ipmi_smi_msg *alloc_msg_handle_irq(struct smi_info *smi_info)
 
        msg = ipmi_alloc_smi_msg();
        if (!msg) {
-               if (!disable_si_irq(smi_info))
+               if (!disable_si_irq(smi_info, true))
                        smi_info->si_state = SI_NORMAL;
        } else if (enable_si_irq(smi_info)) {
                ipmi_free_smi_msg(msg);
@@ -526,7 +542,7 @@ static void handle_flags(struct smi_info *smi_info)
                /* Watchdog pre-timeout */
                smi_inc_stat(smi_info, watchdog_pretimeouts);
 
-               start_clear_flags(smi_info);
+               start_clear_flags(smi_info, true);
                smi_info->msg_flags &= ~WDT_PRE_TIMEOUT_INT;
                if (smi_info->intf)
                        ipmi_smi_watchdog_pretimeout(smi_info->intf);
@@ -879,8 +895,7 @@ static enum si_sm_result smi_event_handler(struct smi_info *smi_info,
                        msg[0] = (IPMI_NETFN_APP_REQUEST << 2);
                        msg[1] = IPMI_GET_MSG_FLAGS_CMD;
 
-                       smi_info->handlers->start_transaction(
-                               smi_info->si_sm, msg, 2);
+                       start_new_msg(smi_info, msg, 2);
                        smi_info->si_state = SI_GETTING_FLAGS;
                        goto restart;
                }
@@ -910,7 +925,7 @@ static enum si_sm_result smi_event_handler(struct smi_info *smi_info,
                 * disable and messages disabled.
                 */
                if (smi_info->supports_event_msg_buff || smi_info->irq) {
-                       start_check_enables(smi_info);
+                       start_check_enables(smi_info, true);
                } else {
                        smi_info->curr_msg = alloc_msg_handle_irq(smi_info);
                        if (!smi_info->curr_msg)
@@ -920,6 +935,13 @@ static enum si_sm_result smi_event_handler(struct smi_info *smi_info,
                }
                goto restart;
        }
+
+       if (si_sm_result == SI_SM_IDLE && smi_info->timer_running) {
+               /* Ok it if fails, the timer will just go off. */
+               if (del_timer(&smi_info->si_timer))
+                       smi_info->timer_running = false;
+       }
+
  out:
        return si_sm_result;
 }
@@ -1208,14 +1230,14 @@ static int smi_start_processing(void       *send_info,
 
        new_smi->intf = intf;
 
-       /* Try to claim any interrupts. */
-       if (new_smi->irq_setup)
-               new_smi->irq_setup(new_smi);
-
        /* Set up the timer that drives the interface. */
        setup_timer(&new_smi->si_timer, smi_timeout, (long)new_smi);
        smi_mod_timer(new_smi, jiffies + SI_TIMEOUT_JIFFIES);
 
+       /* Try to claim any interrupts. */
+       if (new_smi->irq_setup)
+               new_smi->irq_setup(new_smi);
+
        /*
         * Check if the user forcefully enabled the daemon.
         */
@@ -2560,6 +2582,7 @@ static const struct of_device_id of_ipmi_match[] = {
          .data = (void *)(unsigned long) SI_BT },
        {},
 };
+MODULE_DEVICE_TABLE(of, of_ipmi_match);
 
 static int of_ipmi_probe(struct platform_device *dev)
 {
@@ -2646,7 +2669,6 @@ static int of_ipmi_probe(struct platform_device *dev)
        }
        return 0;
 }
-MODULE_DEVICE_TABLE(of, of_ipmi_match);
 #else
 #define of_ipmi_match NULL
 static int of_ipmi_probe(struct platform_device *dev)
@@ -3613,7 +3635,7 @@ static int try_smi_init(struct smi_info *new_smi)
         * Start clearing the flags before we enable interrupts or the
         * timer to avoid racing with the timer.
         */
-       start_clear_flags(new_smi);
+       start_clear_flags(new_smi, false);
 
        /*
         * IRQ is defined to be set when non-zero.  req_events will
@@ -3908,7 +3930,7 @@ static void cleanup_one_si(struct smi_info *to_clean)
                poll(to_clean);
                schedule_timeout_uninterruptible(1);
        }
-       disable_si_irq(to_clean);
+       disable_si_irq(to_clean, false);
        while (to_clean->curr_msg || (to_clean->si_state != SI_NORMAL)) {
                poll(to_clean);
                schedule_timeout_uninterruptible(1);
index 0ac3bd1a5497c5bae41f1cc51ac8cdf667ed73b4..096f0cef4da14152653ea61daa010b367174759d 100644 (file)
@@ -153,6 +153,9 @@ static int timeout = 10;
 /* The pre-timeout is disabled by default. */
 static int pretimeout;
 
+/* Default timeout to set on panic */
+static int panic_wdt_timeout = 255;
+
 /* Default action is to reset the board on a timeout. */
 static unsigned char action_val = WDOG_TIMEOUT_RESET;
 
@@ -293,6 +296,9 @@ MODULE_PARM_DESC(timeout, "Timeout value in seconds.");
 module_param(pretimeout, timeout, 0644);
 MODULE_PARM_DESC(pretimeout, "Pretimeout value in seconds.");
 
+module_param(panic_wdt_timeout, timeout, 0644);
+MODULE_PARM_DESC(timeout, "Timeout value on kernel panic in seconds.");
+
 module_param_cb(action, &param_ops_str, action_op, 0644);
 MODULE_PARM_DESC(action, "Timeout action. One of: "
                 "reset, none, power_cycle, power_off.");
@@ -1189,7 +1195,7 @@ static int wdog_panic_handler(struct notifier_block *this,
                /* Make sure we do this only once. */
                panic_event_handled = 1;
 
-               timeout = 255;
+               timeout = panic_wdt_timeout;
                pretimeout = 0;
                panic_halt_ipmi_set_timeout();
        }
index 10819e2484145ebae0ef9b1092098d1bbc7848d1..335322dc403f48fcf773028d232e5c772f3cd8b5 100644 (file)
@@ -209,6 +209,8 @@ EXPORT_SYMBOL_GPL(clk_register_gpio_mux);
 
 struct clk_gpio_delayed_register_data {
        const char *gpio_name;
+       int num_parents;
+       const char **parent_names;
        struct device_node *node;
        struct mutex lock;
        struct clk *clk;
@@ -222,8 +224,6 @@ static struct clk *of_clk_gpio_delayed_register_get(
 {
        struct clk_gpio_delayed_register_data *data = _data;
        struct clk *clk;
-       const char **parent_names;
-       int i, num_parents;
        int gpio;
        enum of_gpio_flags of_flags;
 
@@ -248,26 +248,14 @@ static struct clk *of_clk_gpio_delayed_register_get(
                return ERR_PTR(gpio);
        }
 
-       num_parents = of_clk_get_parent_count(data->node);
-
-       parent_names = kcalloc(num_parents, sizeof(char *), GFP_KERNEL);
-       if (!parent_names) {
-               clk = ERR_PTR(-ENOMEM);
-               goto out;
-       }
-
-       for (i = 0; i < num_parents; i++)
-               parent_names[i] = of_clk_get_parent_name(data->node, i);
-
-       clk = data->clk_register_get(data->node->name, parent_names,
-                       num_parents, gpio, of_flags & OF_GPIO_ACTIVE_LOW);
+       clk = data->clk_register_get(data->node->name, data->parent_names,
+                       data->num_parents, gpio, of_flags & OF_GPIO_ACTIVE_LOW);
        if (IS_ERR(clk))
                goto out;
 
        data->clk = clk;
 out:
        mutex_unlock(&data->lock);
-       kfree(parent_names);
 
        return clk;
 }
@@ -296,11 +284,24 @@ static void __init of_gpio_clk_setup(struct device_node *node,
                                unsigned gpio, bool active_low))
 {
        struct clk_gpio_delayed_register_data *data;
+       const char **parent_names;
+       int i, num_parents;
 
        data = kzalloc(sizeof(*data), GFP_KERNEL);
        if (!data)
                return;
 
+       num_parents = of_clk_get_parent_count(node);
+
+       parent_names = kcalloc(num_parents, sizeof(char *), GFP_KERNEL);
+       if (!parent_names)
+               return;
+
+       for (i = 0; i < num_parents; i++)
+               parent_names[i] = of_clk_get_parent_name(node, i);
+
+       data->num_parents = num_parents;
+       data->parent_names = parent_names;
        data->node = node;
        data->gpio_name = gpio_name;
        data->clk_register_get = clk_register_get;
index 1ab0fb81c6a0ef7746d77427c488bdb84235011a..7bc1c4527ae48d0baad2ebb4e141385e695ff8f4 100644 (file)
@@ -778,8 +778,10 @@ static struct clk * __init create_one_cmux(struct clockgen *cg, int idx)
         */
        clksel = (cg_in(cg, hwc->reg) & CLKSEL_MASK) >> CLKSEL_SHIFT;
        div = get_pll_div(cg, hwc, clksel);
-       if (!div)
+       if (!div) {
+               kfree(hwc);
                return NULL;
+       }
 
        pct80_rate = clk_get_rate(div->clk);
        pct80_rate *= 8;
index 0b501a9fef92b96810655b952870c7da58400c2c..cd0f2726f5e0dd0da33b06e4518f02fc231cf1f7 100644 (file)
@@ -292,6 +292,7 @@ static int scpi_clocks_probe(struct platform_device *pdev)
                ret = scpi_clk_add(dev, child, match);
                if (ret) {
                        scpi_clocks_remove(pdev);
+                       of_node_put(child);
                        return ret;
                }
        }
index 8564e4342c7d1fa115c1b5f9043bf6bbb8d6e70d..82fe3662b5f6d43e5bf4d8cc1acb3ea3b29048b9 100644 (file)
@@ -52,7 +52,7 @@ static unsigned long clk_pllv1_recalc_rate(struct clk_hw *hw,
                unsigned long parent_rate)
 {
        struct clk_pllv1 *pll = to_clk_pllv1(hw);
-       long long ll;
+       unsigned long long ull;
        int mfn_abs;
        unsigned int mfi, mfn, mfd, pd;
        u32 reg;
@@ -94,16 +94,16 @@ static unsigned long clk_pllv1_recalc_rate(struct clk_hw *hw,
        rate = parent_rate * 2;
        rate /= pd + 1;
 
-       ll = (unsigned long long)rate * mfn_abs;
+       ull = (unsigned long long)rate * mfn_abs;
 
-       do_div(ll, mfd + 1);
+       do_div(ull, mfd + 1);
 
        if (mfn_is_negative(pll, mfn))
-               ll = -ll;
+               ull = (rate * mfi) - ull;
+       else
+               ull = (rate * mfi) + ull;
 
-       ll = (rate * mfi) + ll;
-
-       return ll;
+       return ull;
 }
 
 static struct clk_ops clk_pllv1_ops = {
index b18f875eac6acadd7e0ae27644fe8af0df240af6..4aeda56ce37279006a5cb8be93f9146d7e3d56d7 100644 (file)
@@ -79,7 +79,7 @@ static unsigned long __clk_pllv2_recalc_rate(unsigned long parent_rate,
 {
        long mfi, mfn, mfd, pdf, ref_clk;
        unsigned long dbl;
-       s64 temp;
+       u64 temp;
 
        dbl = dp_ctl & MXC_PLL_DP_CTL_DPDCK0_2_EN;
 
@@ -98,8 +98,9 @@ static unsigned long __clk_pllv2_recalc_rate(unsigned long parent_rate,
        temp = (u64) ref_clk * abs(mfn);
        do_div(temp, mfd + 1);
        if (mfn < 0)
-               temp = -temp;
-       temp = (ref_clk * mfi) + temp;
+               temp = (ref_clk * mfi) - temp;
+       else
+               temp = (ref_clk * mfi) + temp;
 
        return temp;
 }
@@ -126,7 +127,7 @@ static int __clk_pllv2_set_rate(unsigned long rate, unsigned long parent_rate,
 {
        u32 reg;
        long mfi, pdf, mfn, mfd = 999999;
-       s64 temp64;
+       u64 temp64;
        unsigned long quad_parent_rate;
 
        quad_parent_rate = 4 * parent_rate;
index d1b1c95177bbeb577c88bf06c06121db76477f24..0a94d9661d9123551b5b84cd5764cb9b91a6c176 100644 (file)
@@ -335,22 +335,22 @@ static void __init vf610_clocks_init(struct device_node *ccm_node)
        clk[VF610_CLK_SAI0_SEL] = imx_clk_mux("sai0_sel", CCM_CSCMR1, 0, 2, sai_sels, 4);
        clk[VF610_CLK_SAI0_EN] = imx_clk_gate("sai0_en", "sai0_sel", CCM_CSCDR1, 16);
        clk[VF610_CLK_SAI0_DIV] = imx_clk_divider("sai0_div", "sai0_en", CCM_CSCDR1, 0, 4);
-       clk[VF610_CLK_SAI0] = imx_clk_gate2("sai0", "sai0_div", CCM_CCGR0, CCM_CCGRx_CGn(15));
+       clk[VF610_CLK_SAI0] = imx_clk_gate2("sai0", "ipg_bus", CCM_CCGR0, CCM_CCGRx_CGn(15));
 
        clk[VF610_CLK_SAI1_SEL] = imx_clk_mux("sai1_sel", CCM_CSCMR1, 2, 2, sai_sels, 4);
        clk[VF610_CLK_SAI1_EN] = imx_clk_gate("sai1_en", "sai1_sel", CCM_CSCDR1, 17);
        clk[VF610_CLK_SAI1_DIV] = imx_clk_divider("sai1_div", "sai1_en", CCM_CSCDR1, 4, 4);
-       clk[VF610_CLK_SAI1] = imx_clk_gate2("sai1", "sai1_div", CCM_CCGR1, CCM_CCGRx_CGn(0));
+       clk[VF610_CLK_SAI1] = imx_clk_gate2("sai1", "ipg_bus", CCM_CCGR1, CCM_CCGRx_CGn(0));
 
        clk[VF610_CLK_SAI2_SEL] = imx_clk_mux("sai2_sel", CCM_CSCMR1, 4, 2, sai_sels, 4);
        clk[VF610_CLK_SAI2_EN] = imx_clk_gate("sai2_en", "sai2_sel", CCM_CSCDR1, 18);
        clk[VF610_CLK_SAI2_DIV] = imx_clk_divider("sai2_div", "sai2_en", CCM_CSCDR1, 8, 4);
-       clk[VF610_CLK_SAI2] = imx_clk_gate2("sai2", "sai2_div", CCM_CCGR1, CCM_CCGRx_CGn(1));
+       clk[VF610_CLK_SAI2] = imx_clk_gate2("sai2", "ipg_bus", CCM_CCGR1, CCM_CCGRx_CGn(1));
 
        clk[VF610_CLK_SAI3_SEL] = imx_clk_mux("sai3_sel", CCM_CSCMR1, 6, 2, sai_sels, 4);
        clk[VF610_CLK_SAI3_EN] = imx_clk_gate("sai3_en", "sai3_sel", CCM_CSCDR1, 19);
        clk[VF610_CLK_SAI3_DIV] = imx_clk_divider("sai3_div", "sai3_en", CCM_CSCDR1, 12, 4);
-       clk[VF610_CLK_SAI3] = imx_clk_gate2("sai3", "sai3_div", CCM_CCGR1, CCM_CCGRx_CGn(2));
+       clk[VF610_CLK_SAI3] = imx_clk_gate2("sai3", "ipg_bus", CCM_CCGR1, CCM_CCGRx_CGn(2));
 
        clk[VF610_CLK_NFC_SEL] = imx_clk_mux("nfc_sel", CCM_CSCMR1, 12, 2, nfc_sels, 4);
        clk[VF610_CLK_NFC_EN] = imx_clk_gate("nfc_en", "nfc_sel", CCM_CSCDR2, 9);
index 09d2832fbd7821a56e53fe8dc22ab16548fa3f1c..71fd29348f28b778faacba038cbcc94a887d08ba 100644 (file)
@@ -9,6 +9,7 @@
  * warranty of any kind, whether express or implied.
  */
 
+#include <linux/clk.h>
 #include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/spinlock.h>
index 93e967c0f972f954ef1f7af9bb2f90e0c3241cae..75244915df05f92aad3272887e3f5b55b10ba3be 100644 (file)
@@ -9,6 +9,7 @@
  * warranty of any kind, whether express or implied.
  */
 
+#include <linux/clk.h>
 #include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/spinlock.h>
index 993abcdb32cce825fdb1d2ea835cb69f3ecf94fc..37ba04ba13686c4f986b6559e7175eb005509e67 100644 (file)
@@ -9,6 +9,7 @@
  * warranty of any kind, whether express or implied.
  */
 
+#include <linux/clk.h>
 #include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/spinlock.h>
index 5484c31ec5683c6f92a0c4eeab2ceba1a782e562..0ee1f363e4be154749d4b37a07e215dbd705d76e 100644 (file)
 
 #define SUN4I_PLL2_OUTPUTS             4
 
-struct sun4i_pll2_data {
-       u32     post_div_offset;
-       u32     pre_div_flags;
-};
-
 static DEFINE_SPINLOCK(sun4i_a10_pll2_lock);
 
 static void __init sun4i_pll2_setup(struct device_node *node,
-                                   struct sun4i_pll2_data *data)
+                                   int post_div_offset)
 {
        const char *clk_name = node->name, *parent;
        struct clk **clks, *base_clk, *prediv_clk;
@@ -76,7 +71,7 @@ static void __init sun4i_pll2_setup(struct device_node *node,
                                          parent, 0, reg,
                                          SUN4I_PLL2_PRE_DIV_SHIFT,
                                          SUN4I_PLL2_PRE_DIV_WIDTH,
-                                         data->pre_div_flags,
+                                         CLK_DIVIDER_ONE_BASED | CLK_DIVIDER_ALLOW_ZERO,
                                          &sun4i_a10_pll2_lock);
        if (!prediv_clk) {
                pr_err("Couldn't register the prediv clock\n");
@@ -127,7 +122,7 @@ static void __init sun4i_pll2_setup(struct device_node *node,
         */
        val = readl(reg);
        val &= ~(SUN4I_PLL2_POST_DIV_MASK << SUN4I_PLL2_POST_DIV_SHIFT);
-       val |= (SUN4I_PLL2_POST_DIV_VALUE - data->post_div_offset) << SUN4I_PLL2_POST_DIV_SHIFT;
+       val |= (SUN4I_PLL2_POST_DIV_VALUE - post_div_offset) << SUN4I_PLL2_POST_DIV_SHIFT;
        writel(val, reg);
 
        of_property_read_string_index(node, "clock-output-names",
@@ -191,25 +186,17 @@ err_unmap:
        iounmap(reg);
 }
 
-static struct sun4i_pll2_data sun4i_a10_pll2_data = {
-       .pre_div_flags  = CLK_DIVIDER_ONE_BASED | CLK_DIVIDER_ALLOW_ZERO,
-};
-
 static void __init sun4i_a10_pll2_setup(struct device_node *node)
 {
-       sun4i_pll2_setup(node, &sun4i_a10_pll2_data);
+       sun4i_pll2_setup(node, 0);
 }
 
 CLK_OF_DECLARE(sun4i_a10_pll2, "allwinner,sun4i-a10-pll2-clk",
               sun4i_a10_pll2_setup);
 
-static struct sun4i_pll2_data sun5i_a13_pll2_data = {
-       .post_div_offset        = 1,
-};
-
 static void __init sun5i_a13_pll2_setup(struct device_node *node)
 {
-       sun4i_pll2_setup(node, &sun5i_a13_pll2_data);
+       sun4i_pll2_setup(node, 1);
 }
 
 CLK_OF_DECLARE(sun5i_a13_pll2, "allwinner,sun5i-a13-pll2-clk",
index 1dfad0c712cd87c63eb2dabecda3be0e17ba22be..2a5d84fdddc5d56c0f47fe56aa03683569a5e929 100644 (file)
@@ -20,6 +20,8 @@ static struct ti_dt_clk dm816x_clks[] = {
        DT_CLK(NULL, "sys_clkin", "sys_clkin_ck"),
        DT_CLK(NULL, "timer_sys_ck", "sys_clkin_ck"),
        DT_CLK(NULL, "sys_32k_ck", "sys_32k_ck"),
+       DT_CLK(NULL, "timer_32k_ck", "sysclk18_ck"),
+       DT_CLK(NULL, "timer_ext_ck", "tclkin_ck"),
        DT_CLK(NULL, "mpu_ck", "mpu_ck"),
        DT_CLK(NULL, "timer1_fck", "timer1_fck"),
        DT_CLK(NULL, "timer2_fck", "timer2_fck"),
index 9023ca9caf84dde6b02c7ffacdded5244b16795d..b5cc6f66ae5df5e1725dc21ebfd3b18ca5eac1fa 100644 (file)
@@ -240,7 +240,7 @@ u8 omap2_init_dpll_parent(struct clk_hw *hw)
  */
 unsigned long omap2_get_dpll_rate(struct clk_hw_omap *clk)
 {
-       long long dpll_clk;
+       u64 dpll_clk;
        u32 dpll_mult, dpll_div, v;
        struct dpll_data *dd;
 
@@ -262,7 +262,7 @@ unsigned long omap2_get_dpll_rate(struct clk_hw_omap *clk)
        dpll_div = v & dd->div1_mask;
        dpll_div >>= __ffs(dd->div1_mask);
 
-       dpll_clk = (long long)clk_get_rate(dd->clk_ref) * dpll_mult;
+       dpll_clk = (u64)clk_get_rate(dd->clk_ref) * dpll_mult;
        do_div(dpll_clk, dpll_div + 1);
 
        return dpll_clk;
index 5b1726829e6df038de9e8502471cbb6b70414fd5..df2558350fc1d6be681d818c361339acd2afaba3 100644 (file)
@@ -214,7 +214,6 @@ static int ti_clk_divider_set_rate(struct clk_hw *hw, unsigned long rate,
 {
        struct clk_divider *divider;
        unsigned int div, value;
-       unsigned long flags = 0;
        u32 val;
 
        if (!hw || !rate)
@@ -228,9 +227,6 @@ static int ti_clk_divider_set_rate(struct clk_hw *hw, unsigned long rate,
        if (value > div_mask(divider))
                value = div_mask(divider);
 
-       if (divider->lock)
-               spin_lock_irqsave(divider->lock, flags);
-
        if (divider->flags & CLK_DIVIDER_HIWORD_MASK) {
                val = div_mask(divider) << (divider->shift + 16);
        } else {
@@ -240,9 +236,6 @@ static int ti_clk_divider_set_rate(struct clk_hw *hw, unsigned long rate,
        val |= value << divider->shift;
        ti_clk_ll_ops->clk_writel(val, divider->reg);
 
-       if (divider->lock)
-               spin_unlock_irqrestore(divider->lock, flags);
-
        return 0;
 }
 
@@ -256,8 +249,7 @@ static struct clk *_register_divider(struct device *dev, const char *name,
                                     const char *parent_name,
                                     unsigned long flags, void __iomem *reg,
                                     u8 shift, u8 width, u8 clk_divider_flags,
-                                    const struct clk_div_table *table,
-                                    spinlock_t *lock)
+                                    const struct clk_div_table *table)
 {
        struct clk_divider *div;
        struct clk *clk;
@@ -288,7 +280,6 @@ static struct clk *_register_divider(struct device *dev, const char *name,
        div->shift = shift;
        div->width = width;
        div->flags = clk_divider_flags;
-       div->lock = lock;
        div->hw.init = &init;
        div->table = table;
 
@@ -421,7 +412,7 @@ struct clk *ti_clk_register_divider(struct ti_clk *setup)
 
        clk = _register_divider(NULL, setup->name, div->parent,
                                flags, (void __iomem *)reg, div->bit_shift,
-                               width, div_flags, table, NULL);
+                               width, div_flags, table);
 
        if (IS_ERR(clk))
                kfree(table);
@@ -584,8 +575,7 @@ static void __init of_ti_divider_clk_setup(struct device_node *node)
                goto cleanup;
 
        clk = _register_divider(NULL, node->name, parent_name, flags, reg,
-                               shift, width, clk_divider_flags, table,
-                               NULL);
+                               shift, width, clk_divider_flags, table);
 
        if (!IS_ERR(clk)) {
                of_clk_add_provider(node, of_clk_src_simple_get, clk);
index f4b2e9888bdf3c3079b0854b1c04c65a5201c5db..66a0d0ed8b55064ac7a888a1d2e6441d3021ceb1 100644 (file)
@@ -168,7 +168,7 @@ static unsigned long ti_fapll_recalc_rate(struct clk_hw *hw,
 {
        struct fapll_data *fd = to_fapll(hw);
        u32 fapll_n, fapll_p, v;
-       long long rate;
+       u64 rate;
 
        if (ti_fapll_clock_is_bypass(fd))
                return parent_rate;
@@ -314,7 +314,7 @@ static unsigned long ti_fapll_synth_recalc_rate(struct clk_hw *hw,
 {
        struct fapll_synth *synth = to_synth(hw);
        u32 synth_div_m;
-       long long rate;
+       u64 rate;
 
        /* The audio_pll_clk1 is hardwired to produce 32.768KiHz clock */
        if (!synth->div)
index 69f08a1d047d8672a758e441fcd718bbf64bb946..dab9ba88b9d6d2b1b97e2472694bbb588997d8de 100644 (file)
@@ -69,7 +69,6 @@ static int ti_clk_mux_set_parent(struct clk_hw *hw, u8 index)
 {
        struct clk_mux *mux = to_clk_mux(hw);
        u32 val;
-       unsigned long flags = 0;
 
        if (mux->table) {
                index = mux->table[index];
@@ -81,9 +80,6 @@ static int ti_clk_mux_set_parent(struct clk_hw *hw, u8 index)
                        index++;
        }
 
-       if (mux->lock)
-               spin_lock_irqsave(mux->lock, flags);
-
        if (mux->flags & CLK_MUX_HIWORD_MASK) {
                val = mux->mask << (mux->shift + 16);
        } else {
@@ -93,9 +89,6 @@ static int ti_clk_mux_set_parent(struct clk_hw *hw, u8 index)
        val |= index << mux->shift;
        ti_clk_ll_ops->clk_writel(val, mux->reg);
 
-       if (mux->lock)
-               spin_unlock_irqrestore(mux->lock, flags);
-
        return 0;
 }
 
@@ -109,7 +102,7 @@ static struct clk *_register_mux(struct device *dev, const char *name,
                                 const char **parent_names, u8 num_parents,
                                 unsigned long flags, void __iomem *reg,
                                 u8 shift, u32 mask, u8 clk_mux_flags,
-                                u32 *table, spinlock_t *lock)
+                                u32 *table)
 {
        struct clk_mux *mux;
        struct clk *clk;
@@ -133,7 +126,6 @@ static struct clk *_register_mux(struct device *dev, const char *name,
        mux->shift = shift;
        mux->mask = mask;
        mux->flags = clk_mux_flags;
-       mux->lock = lock;
        mux->table = table;
        mux->hw.init = &init;
 
@@ -175,7 +167,7 @@ struct clk *ti_clk_register_mux(struct ti_clk *setup)
 
        return _register_mux(NULL, setup->name, mux->parents, mux->num_parents,
                             flags, (void __iomem *)reg, mux->bit_shift, mask,
-                            mux_flags, NULL, NULL);
+                            mux_flags, NULL);
 }
 
 /**
@@ -227,8 +219,7 @@ static void of_mux_clk_setup(struct device_node *node)
        mask = (1 << fls(mask)) - 1;
 
        clk = _register_mux(NULL, node->name, parent_names, num_parents,
-                           flags, reg, shift, mask, clk_mux_flags, NULL,
-                           NULL);
+                           flags, reg, shift, mask, clk_mux_flags, NULL);
 
        if (!IS_ERR(clk))
                of_clk_add_provider(node, of_clk_src_simple_get, clk);
index 71cfdf7c97086273b1cc8ae1235ecf919abcfda1..2eb5f0efae903cd5235bdd2132ec455dfafe7c26 100644 (file)
@@ -1,4 +1,5 @@
 menu "Clock Source drivers"
+       depends on !ARCH_USES_GETTIMEOFFSET
 
 config CLKSRC_OF
        bool
index 10202f1fdfd7b2afc6ccf9cd044cecdc2d3d66a7..517e1c7624d442f7de842fa011516415d86c66b3 100644 (file)
@@ -203,7 +203,7 @@ static int __init ftm_clockevent_init(unsigned long freq, int irq)
        int err;
 
        ftm_writel(0x00, priv->clkevt_base + FTM_CNTIN);
-       ftm_writel(~0UL, priv->clkevt_base + FTM_MOD);
+       ftm_writel(~0u, priv->clkevt_base + FTM_MOD);
 
        ftm_reset_counter(priv->clkevt_base);
 
@@ -230,7 +230,7 @@ static int __init ftm_clocksource_init(unsigned long freq)
        int err;
 
        ftm_writel(0x00, priv->clksrc_base + FTM_CNTIN);
-       ftm_writel(~0UL, priv->clksrc_base + FTM_MOD);
+       ftm_writel(~0u, priv->clksrc_base + FTM_MOD);
 
        ftm_reset_counter(priv->clksrc_base);
 
index 1593ade2a8154da8840236bd9a0debb931ebfa5a..c4f7d7a9b68987e861bb52ea807f919ca785a1c9 100644 (file)
@@ -55,7 +55,7 @@ int __init clocksource_mmio_init(void __iomem *base, const char *name,
 {
        struct clocksource_mmio *cs;
 
-       if (bits > 32 || bits < 16)
+       if (bits > 64 || bits < 16)
                return -EINVAL;
 
        cs = kzalloc(sizeof(struct clocksource_mmio), GFP_KERNEL);
index 1582c1c016b098b7d40cccbaf52f7d715a0586d2..b1f8a73e5a943e8fc692dfcba7f28d1e08dba4f2 100644 (file)
@@ -84,6 +84,7 @@ config ARM_KIRKWOOD_CPUFREQ
 config ARM_MT8173_CPUFREQ
        bool "Mediatek MT8173 CPUFreq support"
        depends on ARCH_MEDIATEK && REGULATOR
+       depends on ARM64 || (ARM_CPU_TOPOLOGY && COMPILE_TEST)
        depends on !CPU_THERMAL || THERMAL=y
        select PM_OPP
        help
@@ -201,7 +202,7 @@ config ARM_SA1110_CPUFREQ
 
 config ARM_SCPI_CPUFREQ
         tristate "SCPI based CPUfreq driver"
-       depends on ARM_BIG_LITTLE_CPUFREQ && ARM_SCPI_PROTOCOL
+       depends on ARM_BIG_LITTLE_CPUFREQ && ARM_SCPI_PROTOCOL && COMMON_CLK_SCPI
         help
          This adds the CPUfreq driver support for ARM big.LITTLE platforms
          using SCPI protocol for CPU power management.
@@ -225,7 +226,7 @@ config ARM_TEGRA20_CPUFREQ
 
 config ARM_TEGRA124_CPUFREQ
        tristate "Tegra124 CPUFreq support"
-       depends on ARCH_TEGRA && CPUFREQ_DT
+       depends on ARCH_TEGRA && CPUFREQ_DT && REGULATOR
        default y
        help
          This adds the CPUFreq driver support for Tegra124 SOCs.
index adbd1de1cea55cbe6777d3a1c4dab546a6a68adf..c59bdcb83217071087cc0a90ef62e5cd01ce38d7 100644 (file)
@@ -5,7 +5,6 @@
 config X86_INTEL_PSTATE
        bool "Intel P state control"
        depends on X86
-       select ACPI_PROCESSOR if ACPI
        help
           This driver provides a P state for Intel core processors.
          The driver implements an internal governor and will become
index e8cb334094b0d5d89df7d8f482515f7901ac28f5..7c0bdfb1a2ca47ea9dcd0b36ef892274edd929b4 100644 (file)
@@ -98,10 +98,11 @@ static int cppc_cpufreq_cpu_init(struct cpufreq_policy *policy)
        policy->max = cpu->perf_caps.highest_perf;
        policy->cpuinfo.min_freq = policy->min;
        policy->cpuinfo.max_freq = policy->max;
+       policy->shared_type = cpu->shared_type;
 
        if (policy->shared_type == CPUFREQ_SHARED_TYPE_ANY)
                cpumask_copy(policy->cpus, cpu->shared_cpu_map);
-       else {
+       else if (policy->shared_type == CPUFREQ_SHARED_TYPE_ALL) {
                /* Support only SW_ANY for now. */
                pr_debug("Unsupported CPU co-ord type\n");
                return -EFAULT;
index 7c48e7316d91e23cd8374852c477375ae65e1ccb..8412ce5f93a712a03bfa81df25bee238a299d242 100644 (file)
@@ -976,10 +976,14 @@ static int cpufreq_init_policy(struct cpufreq_policy *policy)
 
        new_policy.governor = gov;
 
-       /* Use the default policy if its valid. */
-       if (cpufreq_driver->setpolicy)
-               cpufreq_parse_governor(gov->name, &new_policy.policy, NULL);
-
+       /* Use the default policy if there is no last_policy. */
+       if (cpufreq_driver->setpolicy) {
+               if (policy->last_policy)
+                       new_policy.policy = policy->last_policy;
+               else
+                       cpufreq_parse_governor(gov->name, &new_policy.policy,
+                                              NULL);
+       }
        /* set default policy */
        return cpufreq_set_policy(policy, &new_policy);
 }
@@ -1330,6 +1334,8 @@ static void cpufreq_offline_prepare(unsigned int cpu)
                if (has_target())
                        strncpy(policy->last_governor, policy->governor->name,
                                CPUFREQ_NAME_LEN);
+               else
+                       policy->last_policy = policy->policy;
        } else if (cpu == policy->cpu) {
                /* Nominate new CPU */
                policy->cpu = cpumask_any(policy->cpus);
@@ -1401,13 +1407,10 @@ static void cpufreq_remove_dev(struct device *dev, struct subsys_interface *sif)
        }
 
        cpumask_clear_cpu(cpu, policy->real_cpus);
+       remove_cpu_dev_symlink(policy, cpu);
 
-       if (cpumask_empty(policy->real_cpus)) {
+       if (cpumask_empty(policy->real_cpus))
                cpufreq_policy_free(policy, true);
-               return;
-       }
-
-       remove_cpu_dev_symlink(policy, cpu);
 }
 
 static void handle_update(struct work_struct *work)
index 2e31d097def6b884262295e0d46d0faa6418bd81..98fb8821382d8fc145c6bf9227b62236fdabedb1 100644 (file)
 #include <asm/cpu_device_id.h>
 #include <asm/cpufeature.h>
 
-#if IS_ENABLED(CONFIG_ACPI)
-#include <acpi/processor.h>
-#endif
-
-#define BYT_RATIOS             0x66a
-#define BYT_VIDS               0x66b
-#define BYT_TURBO_RATIOS       0x66c
-#define BYT_TURBO_VIDS         0x66d
+#define ATOM_RATIOS            0x66a
+#define ATOM_VIDS              0x66b
+#define ATOM_TURBO_RATIOS      0x66c
+#define ATOM_TURBO_VIDS                0x66d
 
 #define FRAC_BITS 8
 #define int_tofp(X) ((int64_t)(X) << FRAC_BITS)
@@ -117,9 +113,6 @@ struct cpudata {
        u64     prev_mperf;
        u64     prev_tsc;
        struct sample sample;
-#if IS_ENABLED(CONFIG_ACPI)
-       struct acpi_processor_performance acpi_perf_data;
-#endif
 };
 
 static struct cpudata **all_cpu_data;
@@ -150,7 +143,6 @@ struct cpu_defaults {
 static struct pstate_adjust_policy pid_params;
 static struct pstate_funcs pstate_funcs;
 static int hwp_active;
-static int no_acpi_perf;
 
 struct perf_limits {
        int no_turbo;
@@ -163,8 +155,6 @@ struct perf_limits {
        int max_sysfs_pct;
        int min_policy_pct;
        int min_sysfs_pct;
-       int max_perf_ctl;
-       int min_perf_ctl;
 };
 
 static struct perf_limits performance_limits = {
@@ -191,8 +181,6 @@ static struct perf_limits powersave_limits = {
        .max_sysfs_pct = 100,
        .min_policy_pct = 0,
        .min_sysfs_pct = 0,
-       .max_perf_ctl = 0,
-       .min_perf_ctl = 0,
 };
 
 #ifdef CONFIG_CPU_FREQ_DEFAULT_GOV_PERFORMANCE
@@ -201,153 +189,6 @@ static struct perf_limits *limits = &performance_limits;
 static struct perf_limits *limits = &powersave_limits;
 #endif
 
-#if IS_ENABLED(CONFIG_ACPI)
-/*
- * The max target pstate ratio is a 8 bit value in both PLATFORM_INFO MSR and
- * in TURBO_RATIO_LIMIT MSR, which pstate driver stores in max_pstate and
- * max_turbo_pstate fields. The PERF_CTL MSR contains 16 bit value for P state
- * ratio, out of it only high 8 bits are used. For example 0x1700 is setting
- * target ratio 0x17. The _PSS control value stores in a format which can be
- * directly written to PERF_CTL MSR. But in intel_pstate driver this shift
- * occurs during write to PERF_CTL (E.g. for cores core_set_pstate()).
- * This function converts the _PSS control value to intel pstate driver format
- * for comparison and assignment.
- */
-static int convert_to_native_pstate_format(struct cpudata *cpu, int index)
-{
-       return cpu->acpi_perf_data.states[index].control >> 8;
-}
-
-static int intel_pstate_init_perf_limits(struct cpufreq_policy *policy)
-{
-       struct cpudata *cpu;
-       int ret;
-       bool turbo_absent = false;
-       int max_pstate_index;
-       int min_pss_ctl, max_pss_ctl, turbo_pss_ctl;
-       int i;
-
-       cpu = all_cpu_data[policy->cpu];
-
-       pr_debug("intel_pstate: default limits 0x%x 0x%x 0x%x\n",
-                cpu->pstate.min_pstate, cpu->pstate.max_pstate,
-                cpu->pstate.turbo_pstate);
-
-       if (!cpu->acpi_perf_data.shared_cpu_map &&
-           zalloc_cpumask_var_node(&cpu->acpi_perf_data.shared_cpu_map,
-                                   GFP_KERNEL, cpu_to_node(policy->cpu))) {
-               return -ENOMEM;
-       }
-
-       ret = acpi_processor_register_performance(&cpu->acpi_perf_data,
-                                                 policy->cpu);
-       if (ret)
-               return ret;
-
-       /*
-        * Check if the control value in _PSS is for PERF_CTL MSR, which should
-        * guarantee that the states returned by it map to the states in our
-        * list directly.
-        */
-       if (cpu->acpi_perf_data.control_register.space_id !=
-                                               ACPI_ADR_SPACE_FIXED_HARDWARE)
-               return -EIO;
-
-       pr_debug("intel_pstate: CPU%u - ACPI _PSS perf data\n", policy->cpu);
-       for (i = 0; i < cpu->acpi_perf_data.state_count; i++)
-               pr_debug("     %cP%d: %u MHz, %u mW, 0x%x\n",
-                        (i == cpu->acpi_perf_data.state ? '*' : ' '), i,
-                        (u32) cpu->acpi_perf_data.states[i].core_frequency,
-                        (u32) cpu->acpi_perf_data.states[i].power,
-                        (u32) cpu->acpi_perf_data.states[i].control);
-
-       /*
-        * If there is only one entry _PSS, simply ignore _PSS and continue as
-        * usual without taking _PSS into account
-        */
-       if (cpu->acpi_perf_data.state_count < 2)
-               return 0;
-
-       turbo_pss_ctl = convert_to_native_pstate_format(cpu, 0);
-       min_pss_ctl = convert_to_native_pstate_format(cpu,
-                                       cpu->acpi_perf_data.state_count - 1);
-       /* Check if there is a turbo freq in _PSS */
-       if (turbo_pss_ctl <= cpu->pstate.max_pstate &&
-           turbo_pss_ctl > cpu->pstate.min_pstate) {
-               pr_debug("intel_pstate: no turbo range exists in _PSS\n");
-               limits->no_turbo = limits->turbo_disabled = 1;
-               cpu->pstate.turbo_pstate = cpu->pstate.max_pstate;
-               turbo_absent = true;
-       }
-
-       /* Check if the max non turbo p state < Intel P state max */
-       max_pstate_index = turbo_absent ? 0 : 1;
-       max_pss_ctl = convert_to_native_pstate_format(cpu, max_pstate_index);
-       if (max_pss_ctl < cpu->pstate.max_pstate &&
-           max_pss_ctl > cpu->pstate.min_pstate)
-               cpu->pstate.max_pstate = max_pss_ctl;
-
-       /* check If min perf > Intel P State min */
-       if (min_pss_ctl > cpu->pstate.min_pstate &&
-           min_pss_ctl < cpu->pstate.max_pstate) {
-               cpu->pstate.min_pstate = min_pss_ctl;
-               policy->cpuinfo.min_freq = min_pss_ctl * cpu->pstate.scaling;
-       }
-
-       if (turbo_absent)
-               policy->cpuinfo.max_freq = cpu->pstate.max_pstate *
-                                               cpu->pstate.scaling;
-       else {
-               policy->cpuinfo.max_freq = cpu->pstate.turbo_pstate *
-                                               cpu->pstate.scaling;
-               /*
-                * The _PSS table doesn't contain whole turbo frequency range.
-                * This just contains +1 MHZ above the max non turbo frequency,
-                * with control value corresponding to max turbo ratio. But
-                * when cpufreq set policy is called, it will call with this
-                * max frequency, which will cause a reduced performance as
-                * this driver uses real max turbo frequency as the max
-                * frequeny. So correct this frequency in _PSS table to
-                * correct max turbo frequency based on the turbo ratio.
-                * Also need to convert to MHz as _PSS freq is in MHz.
-                */
-               cpu->acpi_perf_data.states[0].core_frequency =
-                                               turbo_pss_ctl * 100;
-       }
-
-       pr_debug("intel_pstate: Updated limits using _PSS 0x%x 0x%x 0x%x\n",
-                cpu->pstate.min_pstate, cpu->pstate.max_pstate,
-                cpu->pstate.turbo_pstate);
-       pr_debug("intel_pstate: policy max_freq=%d Khz min_freq = %d KHz\n",
-                policy->cpuinfo.max_freq, policy->cpuinfo.min_freq);
-
-       return 0;
-}
-
-static int intel_pstate_exit_perf_limits(struct cpufreq_policy *policy)
-{
-       struct cpudata *cpu;
-
-       if (!no_acpi_perf)
-               return 0;
-
-       cpu = all_cpu_data[policy->cpu];
-       acpi_processor_unregister_performance(policy->cpu);
-       return 0;
-}
-
-#else
-static int intel_pstate_init_perf_limits(struct cpufreq_policy *policy)
-{
-       return 0;
-}
-
-static int intel_pstate_exit_perf_limits(struct cpufreq_policy *policy)
-{
-       return 0;
-}
-#endif
-
 static inline void pid_reset(struct _pid *pid, int setpoint, int busy,
                             int deadband, int integral) {
        pid->setpoint = setpoint;
@@ -687,31 +528,31 @@ static void intel_pstate_hwp_enable(struct cpudata *cpudata)
        wrmsrl_on_cpu(cpudata->cpu, MSR_PM_ENABLE, 0x1);
 }
 
-static int byt_get_min_pstate(void)
+static int atom_get_min_pstate(void)
 {
        u64 value;
 
-       rdmsrl(BYT_RATIOS, value);
+       rdmsrl(ATOM_RATIOS, value);
        return (value >> 8) & 0x7F;
 }
 
-static int byt_get_max_pstate(void)
+static int atom_get_max_pstate(void)
 {
        u64 value;
 
-       rdmsrl(BYT_RATIOS, value);
+       rdmsrl(ATOM_RATIOS, value);
        return (value >> 16) & 0x7F;
 }
 
-static int byt_get_turbo_pstate(void)
+static int atom_get_turbo_pstate(void)
 {
        u64 value;
 
-       rdmsrl(BYT_TURBO_RATIOS, value);
+       rdmsrl(ATOM_TURBO_RATIOS, value);
        return value & 0x7F;
 }
 
-static void byt_set_pstate(struct cpudata *cpudata, int pstate)
+static void atom_set_pstate(struct cpudata *cpudata, int pstate)
 {
        u64 val;
        int32_t vid_fp;
@@ -736,27 +577,42 @@ static void byt_set_pstate(struct cpudata *cpudata, int pstate)
        wrmsrl_on_cpu(cpudata->cpu, MSR_IA32_PERF_CTL, val);
 }
 
-#define BYT_BCLK_FREQS 5
-static int byt_freq_table[BYT_BCLK_FREQS] = { 833, 1000, 1333, 1167, 800};
-
-static int byt_get_scaling(void)
+static int silvermont_get_scaling(void)
 {
        u64 value;
        int i;
+       /* Defined in Table 35-6 from SDM (Sept 2015) */
+       static int silvermont_freq_table[] = {
+               83300, 100000, 133300, 116700, 80000};
 
        rdmsrl(MSR_FSB_FREQ, value);
-       i = value & 0x3;
+       i = value & 0x7;
+       WARN_ON(i > 4);
 
-       BUG_ON(i > BYT_BCLK_FREQS);
+       return silvermont_freq_table[i];
+}
 
-       return byt_freq_table[i] * 100;
+static int airmont_get_scaling(void)
+{
+       u64 value;
+       int i;
+       /* Defined in Table 35-10 from SDM (Sept 2015) */
+       static int airmont_freq_table[] = {
+               83300, 100000, 133300, 116700, 80000,
+               93300, 90000, 88900, 87500};
+
+       rdmsrl(MSR_FSB_FREQ, value);
+       i = value & 0xF;
+       WARN_ON(i > 8);
+
+       return airmont_freq_table[i];
 }
 
-static void byt_get_vid(struct cpudata *cpudata)
+static void atom_get_vid(struct cpudata *cpudata)
 {
        u64 value;
 
-       rdmsrl(BYT_VIDS, value);
+       rdmsrl(ATOM_VIDS, value);
        cpudata->vid.min = int_tofp((value >> 8) & 0x7f);
        cpudata->vid.max = int_tofp((value >> 16) & 0x7f);
        cpudata->vid.ratio = div_fp(
@@ -764,7 +620,7 @@ static void byt_get_vid(struct cpudata *cpudata)
                int_tofp(cpudata->pstate.max_pstate -
                        cpudata->pstate.min_pstate));
 
-       rdmsrl(BYT_TURBO_VIDS, value);
+       rdmsrl(ATOM_TURBO_VIDS, value);
        cpudata->vid.turbo = value & 0x7f;
 }
 
@@ -885,7 +741,7 @@ static struct cpu_defaults core_params = {
        },
 };
 
-static struct cpu_defaults byt_params = {
+static struct cpu_defaults silvermont_params = {
        .pid_policy = {
                .sample_rate_ms = 10,
                .deadband = 0,
@@ -895,13 +751,33 @@ static struct cpu_defaults byt_params = {
                .i_gain_pct = 4,
        },
        .funcs = {
-               .get_max = byt_get_max_pstate,
-               .get_max_physical = byt_get_max_pstate,
-               .get_min = byt_get_min_pstate,
-               .get_turbo = byt_get_turbo_pstate,
-               .set = byt_set_pstate,
-               .get_scaling = byt_get_scaling,
-               .get_vid = byt_get_vid,
+               .get_max = atom_get_max_pstate,
+               .get_max_physical = atom_get_max_pstate,
+               .get_min = atom_get_min_pstate,
+               .get_turbo = atom_get_turbo_pstate,
+               .set = atom_set_pstate,
+               .get_scaling = silvermont_get_scaling,
+               .get_vid = atom_get_vid,
+       },
+};
+
+static struct cpu_defaults airmont_params = {
+       .pid_policy = {
+               .sample_rate_ms = 10,
+               .deadband = 0,
+               .setpoint = 60,
+               .p_gain_pct = 14,
+               .d_gain_pct = 0,
+               .i_gain_pct = 4,
+       },
+       .funcs = {
+               .get_max = atom_get_max_pstate,
+               .get_max_physical = atom_get_max_pstate,
+               .get_min = atom_get_min_pstate,
+               .get_turbo = atom_get_turbo_pstate,
+               .set = atom_set_pstate,
+               .get_scaling = airmont_get_scaling,
+               .get_vid = atom_get_vid,
        },
 };
 
@@ -938,23 +814,12 @@ static void intel_pstate_get_min_max(struct cpudata *cpu, int *min, int *max)
         * policy, or by cpu specific default values determined through
         * experimentation.
         */
-       if (limits->max_perf_ctl && limits->max_sysfs_pct >=
-                                               limits->max_policy_pct) {
-               *max = limits->max_perf_ctl;
-       } else {
-               max_perf_adj = fp_toint(mul_fp(int_tofp(max_perf),
-                                       limits->max_perf));
-               *max = clamp_t(int, max_perf_adj, cpu->pstate.min_pstate,
-                              cpu->pstate.turbo_pstate);
-       }
+       max_perf_adj = fp_toint(mul_fp(int_tofp(max_perf), limits->max_perf));
+       *max = clamp_t(int, max_perf_adj,
+                       cpu->pstate.min_pstate, cpu->pstate.turbo_pstate);
 
-       if (limits->min_perf_ctl) {
-               *min = limits->min_perf_ctl;
-       } else {
-               min_perf = fp_toint(mul_fp(int_tofp(max_perf),
-                                   limits->min_perf));
-               *min = clamp_t(int, min_perf, cpu->pstate.min_pstate, max_perf);
-       }
+       min_perf = fp_toint(mul_fp(int_tofp(max_perf), limits->min_perf));
+       *min = clamp_t(int, min_perf, cpu->pstate.min_pstate, max_perf);
 }
 
 static void intel_pstate_set_pstate(struct cpudata *cpu, int pstate, bool force)
@@ -1153,7 +1018,7 @@ static void intel_pstate_timer_func(unsigned long __data)
 static const struct x86_cpu_id intel_pstate_cpu_ids[] = {
        ICPU(0x2a, core_params),
        ICPU(0x2d, core_params),
-       ICPU(0x37, byt_params),
+       ICPU(0x37, silvermont_params),
        ICPU(0x3a, core_params),
        ICPU(0x3c, core_params),
        ICPU(0x3d, core_params),
@@ -1162,7 +1027,7 @@ static const struct x86_cpu_id intel_pstate_cpu_ids[] = {
        ICPU(0x45, core_params),
        ICPU(0x46, core_params),
        ICPU(0x47, core_params),
-       ICPU(0x4c, byt_params),
+       ICPU(0x4c, airmont_params),
        ICPU(0x4e, core_params),
        ICPU(0x4f, core_params),
        ICPU(0x5e, core_params),
@@ -1229,12 +1094,6 @@ static unsigned int intel_pstate_get(unsigned int cpu_num)
 
 static int intel_pstate_set_policy(struct cpufreq_policy *policy)
 {
-#if IS_ENABLED(CONFIG_ACPI)
-       struct cpudata *cpu;
-       int i;
-#endif
-       pr_debug("intel_pstate: %s max %u policy->max %u\n", __func__,
-                policy->cpuinfo.max_freq, policy->max);
        if (!policy->cpuinfo.max_freq)
                return -ENODEV;
 
@@ -1242,6 +1101,8 @@ static int intel_pstate_set_policy(struct cpufreq_policy *policy)
            policy->max >= policy->cpuinfo.max_freq) {
                pr_debug("intel_pstate: set performance\n");
                limits = &performance_limits;
+               if (hwp_active)
+                       intel_pstate_hwp_set();
                return 0;
        }
 
@@ -1249,7 +1110,8 @@ static int intel_pstate_set_policy(struct cpufreq_policy *policy)
        limits = &powersave_limits;
        limits->min_policy_pct = (policy->min * 100) / policy->cpuinfo.max_freq;
        limits->min_policy_pct = clamp_t(int, limits->min_policy_pct, 0 , 100);
-       limits->max_policy_pct = (policy->max * 100) / policy->cpuinfo.max_freq;
+       limits->max_policy_pct = DIV_ROUND_UP(policy->max * 100,
+                                             policy->cpuinfo.max_freq);
        limits->max_policy_pct = clamp_t(int, limits->max_policy_pct, 0 , 100);
 
        /* Normalize user input to [min_policy_pct, max_policy_pct] */
@@ -1261,6 +1123,7 @@ static int intel_pstate_set_policy(struct cpufreq_policy *policy)
                                   limits->max_sysfs_pct);
        limits->max_perf_pct = max(limits->min_policy_pct,
                                   limits->max_perf_pct);
+       limits->max_perf = round_up(limits->max_perf, FRAC_BITS);
 
        /* Make sure min_perf_pct <= max_perf_pct */
        limits->min_perf_pct = min(limits->max_perf_pct, limits->min_perf_pct);
@@ -1270,23 +1133,6 @@ static int intel_pstate_set_policy(struct cpufreq_policy *policy)
        limits->max_perf = div_fp(int_tofp(limits->max_perf_pct),
                                  int_tofp(100));
 
-#if IS_ENABLED(CONFIG_ACPI)
-       cpu = all_cpu_data[policy->cpu];
-       for (i = 0; i < cpu->acpi_perf_data.state_count; i++) {
-               int control;
-
-               control = convert_to_native_pstate_format(cpu, i);
-               if (control * cpu->pstate.scaling == policy->max)
-                       limits->max_perf_ctl = control;
-               if (control * cpu->pstate.scaling == policy->min)
-                       limits->min_perf_ctl = control;
-       }
-
-       pr_debug("intel_pstate: max %u policy_max %u perf_ctl [0x%x-0x%x]\n",
-                policy->cpuinfo.max_freq, policy->max, limits->min_perf_ctl,
-                limits->max_perf_ctl);
-#endif
-
        if (hwp_active)
                intel_pstate_hwp_set();
 
@@ -1341,30 +1187,18 @@ static int intel_pstate_cpu_init(struct cpufreq_policy *policy)
        policy->cpuinfo.min_freq = cpu->pstate.min_pstate * cpu->pstate.scaling;
        policy->cpuinfo.max_freq =
                cpu->pstate.turbo_pstate * cpu->pstate.scaling;
-       if (!no_acpi_perf)
-               intel_pstate_init_perf_limits(policy);
-       /*
-        * If there is no acpi perf data or error, we ignore and use Intel P
-        * state calculated limits, So this is not fatal error.
-        */
        policy->cpuinfo.transition_latency = CPUFREQ_ETERNAL;
        cpumask_set_cpu(policy->cpu, policy->cpus);
 
        return 0;
 }
 
-static int intel_pstate_cpu_exit(struct cpufreq_policy *policy)
-{
-       return intel_pstate_exit_perf_limits(policy);
-}
-
 static struct cpufreq_driver intel_pstate_driver = {
        .flags          = CPUFREQ_CONST_LOOPS,
        .verify         = intel_pstate_verify_policy,
        .setpolicy      = intel_pstate_set_policy,
        .get            = intel_pstate_get,
        .init           = intel_pstate_cpu_init,
-       .exit           = intel_pstate_cpu_exit,
        .stop_cpu       = intel_pstate_stop_cpu,
        .name           = "intel_pstate",
 };
@@ -1406,6 +1240,7 @@ static void copy_cpu_funcs(struct pstate_funcs *funcs)
 }
 
 #if IS_ENABLED(CONFIG_ACPI)
+#include <acpi/processor.h>
 
 static bool intel_pstate_no_acpi_pss(void)
 {
@@ -1601,9 +1436,6 @@ static int __init intel_pstate_setup(char *str)
                force_load = 1;
        if (!strcmp(str, "hwp_only"))
                hwp_only = 1;
-       if (!strcmp(str, "no_acpi"))
-               no_acpi_perf = 1;
-
        return 0;
 }
 early_param("intel_pstate", intel_pstate_setup);
index 733aa5153e7451f645a65e3452ed44d6d488054a..68ef8fd9482fd2532762789973b8d4dfa98cfdd5 100644 (file)
@@ -648,7 +648,7 @@ late_initcall(s3c_cpufreq_initcall);
  *
  * Register the given set of PLLs with the system.
  */
-int __init s3c_plltab_register(struct cpufreq_frequency_table *plls,
+int s3c_plltab_register(struct cpufreq_frequency_table *plls,
                               unsigned int plls_no)
 {
        struct cpufreq_frequency_table *vals;
index 2c3b16fd3a01fc1c521f8201bd698dab2d6d1215..de5e89b2eaaa3db13413eec5762620c21623738c 100644 (file)
@@ -31,7 +31,7 @@ static struct scpi_ops *scpi_ops;
 
 static struct scpi_dvfs_info *scpi_get_dvfs_info(struct device *cpu_dev)
 {
-       u8 domain = topology_physical_package_id(cpu_dev->id);
+       int domain = topology_physical_package_id(cpu_dev->id);
 
        if (domain < 0)
                return ERR_PTR(-EINVAL);
index 73ef499227881e6fd5c71c65d00f486a1f173dd4..7038f364acb51934f51b5dfd6053b5ec6545ddfa 100644 (file)
@@ -409,7 +409,7 @@ static int ccm_nx_decrypt(struct aead_request   *req,
                processed += to_process;
        } while (processed < nbytes);
 
-       rc = memcmp(csbcpb->cpb.aes_ccm.out_pat_or_mac, priv->oauth_tag,
+       rc = crypto_memneq(csbcpb->cpb.aes_ccm.out_pat_or_mac, priv->oauth_tag,
                    authsize) ? -EBADMSG : 0;
 out:
        spin_unlock_irqrestore(&nx_ctx->lock, irq_flags);
index eee624f589b6545a310d081e772d5924094ed70d..abd465f479c433641f3e5024cfe6442d6b68024d 100644 (file)
@@ -21,6 +21,7 @@
 
 #include <crypto/internal/aead.h>
 #include <crypto/aes.h>
+#include <crypto/algapi.h>
 #include <crypto/scatterwalk.h>
 #include <linux/module.h>
 #include <linux/types.h>
@@ -418,7 +419,7 @@ mac:
                        itag, req->src, req->assoclen + nbytes,
                        crypto_aead_authsize(crypto_aead_reqtfm(req)),
                        SCATTERWALK_FROM_SG);
-               rc = memcmp(itag, otag,
+               rc = crypto_memneq(itag, otag,
                            crypto_aead_authsize(crypto_aead_reqtfm(req))) ?
                     -EBADMSG : 0;
        }
index 03856ad280b9349d650a0d06723a9f9da31e7c75..473d36d91644c2a00010d89dfc280d08c7ed343e 100644 (file)
@@ -198,7 +198,7 @@ static int adf_copy_key_value_data(struct adf_accel_dev *accel_dev,
                        goto out_err;
                }
 
-               params_head = section_head->params;
+               params_head = section.params;
 
                while (params_head) {
                        if (copy_from_user(&key_val, (void __user *)params_head,
index 46f531e19ccf07e97af05c221a5bfbb0d060d0a7..b6f9f42e2985b476ecc63ac16f648535be0cddc2 100644 (file)
@@ -977,7 +977,7 @@ static void ipsec_esp_decrypt_swauth_done(struct device *dev,
                } else
                        oicv = (char *)&edesc->link_tbl[0];
 
-               err = memcmp(oicv, icv, authsize) ? -EBADMSG : 0;
+               err = crypto_memneq(oicv, icv, authsize) ? -EBADMSG : 0;
        }
 
        kfree(edesc);
index e6cd1a32025a916cec7d219d4693c7c71e4c09a9..17655d9ba518b855a0203c7ba87d547b50003ab9 100644 (file)
@@ -432,7 +432,7 @@ config STE_DMA40
          Support for ST-Ericsson DMA40 controller
 
 config S3C24XX_DMAC
-       tristate "Samsung S3C24XX DMA support"
+       bool "Samsung S3C24XX DMA support"
        depends on ARCH_S3C24XX
        select DMA_ENGINE
        select DMA_VIRTUAL_CHANNELS
index 4e55239c7a307a61f84045d91b6966c4ad73aba1..53d22eb73b56a19884e6d8dea3c03bba245ebbc9 100644 (file)
@@ -729,8 +729,8 @@ atc_prep_dma_interleaved(struct dma_chan *chan,
                return NULL;
 
        dev_info(chan2dev(chan),
-                "%s: src=0x%08x, dest=0x%08x, numf=%d, frame_size=%d, flags=0x%lx\n",
-               __func__, xt->src_start, xt->dst_start, xt->numf,
+                "%s: src=%pad, dest=%pad, numf=%d, frame_size=%d, flags=0x%lx\n",
+               __func__, &xt->src_start, &xt->dst_start, xt->numf,
                xt->frame_size, flags);
 
        /*
@@ -824,8 +824,8 @@ atc_prep_dma_memcpy(struct dma_chan *chan, dma_addr_t dest, dma_addr_t src,
        u32                     ctrla;
        u32                     ctrlb;
 
-       dev_vdbg(chan2dev(chan), "prep_dma_memcpy: d0x%x s0x%x l0x%zx f0x%lx\n",
-                       dest, src, len, flags);
+       dev_vdbg(chan2dev(chan), "prep_dma_memcpy: d%pad s%pad l0x%zx f0x%lx\n",
+                       &dest, &src, len, flags);
 
        if (unlikely(!len)) {
                dev_dbg(chan2dev(chan), "prep_dma_memcpy: length is zero!\n");
@@ -938,8 +938,8 @@ atc_prep_dma_memset(struct dma_chan *chan, dma_addr_t dest, int value,
        void __iomem            *vaddr;
        dma_addr_t              paddr;
 
-       dev_vdbg(chan2dev(chan), "%s: d0x%x v0x%x l0x%zx f0x%lx\n", __func__,
-               dest, value, len, flags);
+       dev_vdbg(chan2dev(chan), "%s: d%pad v0x%x l0x%zx f0x%lx\n", __func__,
+               &dest, value, len, flags);
 
        if (unlikely(!len)) {
                dev_dbg(chan2dev(chan), "%s: length is zero!\n", __func__);
@@ -1022,8 +1022,8 @@ atc_prep_dma_memset_sg(struct dma_chan *chan,
                dma_addr_t dest = sg_dma_address(sg);
                size_t len = sg_dma_len(sg);
 
-               dev_vdbg(chan2dev(chan), "%s: d0x%08x, l0x%zx\n",
-                        __func__, dest, len);
+               dev_vdbg(chan2dev(chan), "%s: d%pad, l0x%zx\n",
+                        __func__, &dest, len);
 
                if (!is_dma_fill_aligned(chan->device, dest, 0, len)) {
                        dev_err(chan2dev(chan), "%s: buffer is not aligned\n",
@@ -1439,9 +1439,9 @@ atc_prep_dma_cyclic(struct dma_chan *chan, dma_addr_t buf_addr, size_t buf_len,
        unsigned int            periods = buf_len / period_len;
        unsigned int            i;
 
-       dev_vdbg(chan2dev(chan), "prep_dma_cyclic: %s buf@0x%08x - %d (%d/%d)\n",
+       dev_vdbg(chan2dev(chan), "prep_dma_cyclic: %s buf@%pad - %d (%d/%d)\n",
                        direction == DMA_MEM_TO_DEV ? "TO DEVICE" : "FROM DEVICE",
-                       buf_addr,
+                       &buf_addr,
                        periods, buf_len, period_len);
 
        if (unlikely(!atslave || !buf_len || !period_len)) {
index d1cfc8c876f933000c5708ae32af75007a774a2a..7f58f06157f6a35c9268b81472acb5ce8ea3aa87 100644 (file)
@@ -385,9 +385,9 @@ static void vdbg_dump_regs(struct at_dma_chan *atchan) {}
 static void atc_dump_lli(struct at_dma_chan *atchan, struct at_lli *lli)
 {
        dev_crit(chan2dev(&atchan->chan_common),
-                "  desc: s0x%x d0x%x ctrl0x%x:0x%x l0x%x\n",
-                lli->saddr, lli->daddr,
-                lli->ctrla, lli->ctrlb, lli->dscr);
+                "  desc: s%pad d%pad ctrl0x%x:0x%x l0x%pad\n",
+                &lli->saddr, &lli->daddr,
+                lli->ctrla, lli->ctrlb, &lli->dscr);
 }
 
 
index b5e132d4bae5b5f35d9b74cf8cd1f54bab8e20a6..370c661c7d7b25c237a3376dd18da79fbd44eadd 100644 (file)
 #define                AT_XDMAC_CC_WRIP        (0x1 << 23)     /* Write in Progress (read only) */
 #define                        AT_XDMAC_CC_WRIP_DONE           (0x0 << 23)
 #define                        AT_XDMAC_CC_WRIP_IN_PROGRESS    (0x1 << 23)
-#define                AT_XDMAC_CC_PERID(i)    (0x7f & (h) << 24)      /* Channel Peripheral Identifier */
+#define                AT_XDMAC_CC_PERID(i)    (0x7f & (i) << 24)      /* Channel Peripheral Identifier */
 #define AT_XDMAC_CDS_MSP       0x2C    /* Channel Data Stride Memory Set Pattern */
 #define AT_XDMAC_CSUS          0x30    /* Channel Source Microblock Stride */
 #define AT_XDMAC_CDUS          0x34    /* Channel Destination Microblock Stride */
@@ -920,8 +920,8 @@ at_xdmac_interleaved_queue_desc(struct dma_chan *chan,
        desc->lld.mbr_cfg = chan_cc;
 
        dev_dbg(chan2dev(chan),
-               "%s: lld: mbr_sa=0x%08x, mbr_da=0x%08x, mbr_ubc=0x%08x, mbr_cfg=0x%08x\n",
-               __func__, desc->lld.mbr_sa, desc->lld.mbr_da,
+               "%s: lld: mbr_sa=%pad, mbr_da=%pad, mbr_ubc=0x%08x, mbr_cfg=0x%08x\n",
+               __func__, &desc->lld.mbr_sa, &desc->lld.mbr_da,
                desc->lld.mbr_ubc, desc->lld.mbr_cfg);
 
        /* Chain lld. */
@@ -953,8 +953,8 @@ at_xdmac_prep_interleaved(struct dma_chan *chan,
        if ((xt->numf > 1) && (xt->frame_size > 1))
                return NULL;
 
-       dev_dbg(chan2dev(chan), "%s: src=0x%08x, dest=0x%08x, numf=%d, frame_size=%d, flags=0x%lx\n",
-               __func__, xt->src_start, xt->dst_start, xt->numf,
+       dev_dbg(chan2dev(chan), "%s: src=%pad, dest=%pad, numf=%d, frame_size=%d, flags=0x%lx\n",
+               __func__, &xt->src_start, &xt->dst_start,       xt->numf,
                xt->frame_size, flags);
 
        src_addr = xt->src_start;
@@ -965,7 +965,9 @@ at_xdmac_prep_interleaved(struct dma_chan *chan,
                                                        NULL,
                                                        src_addr, dst_addr,
                                                        xt, xt->sgl);
-               for (i = 0; i < xt->numf; i++)
+
+               /* Length of the block is (BLEN+1) microblocks. */
+               for (i = 0; i < xt->numf - 1; i++)
                        at_xdmac_increment_block_count(chan, first);
 
                dev_dbg(chan2dev(chan), "%s: add desc 0x%p to descs_list 0x%p\n",
@@ -1086,6 +1088,7 @@ at_xdmac_prep_dma_memcpy(struct dma_chan *chan, dma_addr_t dest, dma_addr_t src,
                /* Check remaining length and change data width if needed. */
                dwidth = at_xdmac_align_width(chan,
                                              src_addr | dst_addr | xfer_size);
+               chan_cc &= ~AT_XDMAC_CC_DWIDTH_MASK;
                chan_cc |= AT_XDMAC_CC_DWIDTH(dwidth);
 
                ublen = xfer_size >> dwidth;
@@ -1179,8 +1182,8 @@ static struct at_xdmac_desc *at_xdmac_memset_create_desc(struct dma_chan *chan,
        desc->lld.mbr_cfg = chan_cc;
 
        dev_dbg(chan2dev(chan),
-               "%s: lld: mbr_da=0x%08x, mbr_ds=0x%08x, mbr_ubc=0x%08x, mbr_cfg=0x%08x\n",
-               __func__, desc->lld.mbr_da, desc->lld.mbr_ds, desc->lld.mbr_ubc,
+               "%s: lld: mbr_da=%pad, mbr_ds=%pad, mbr_ubc=0x%08x, mbr_cfg=0x%08x\n",
+               __func__, &desc->lld.mbr_da, &desc->lld.mbr_ds, desc->lld.mbr_ubc,
                desc->lld.mbr_cfg);
 
        return desc;
@@ -1193,8 +1196,8 @@ at_xdmac_prep_dma_memset(struct dma_chan *chan, dma_addr_t dest, int value,
        struct at_xdmac_chan    *atchan = to_at_xdmac_chan(chan);
        struct at_xdmac_desc    *desc;
 
-       dev_dbg(chan2dev(chan), "%s: dest=0x%08x, len=%d, pattern=0x%x, flags=0x%lx\n",
-               __func__, dest, len, value, flags);
+       dev_dbg(chan2dev(chan), "%s: dest=%pad, len=%d, pattern=0x%x, flags=0x%lx\n",
+               __func__, &dest, len, value, flags);
 
        if (unlikely(!len))
                return NULL;
@@ -1229,8 +1232,8 @@ at_xdmac_prep_dma_memset_sg(struct dma_chan *chan, struct scatterlist *sgl,
 
        /* Prepare descriptors. */
        for_each_sg(sgl, sg, sg_len, i) {
-               dev_dbg(chan2dev(chan), "%s: dest=0x%08x, len=%d, pattern=0x%x, flags=0x%lx\n",
-                       __func__, sg_dma_address(sg), sg_dma_len(sg),
+               dev_dbg(chan2dev(chan), "%s: dest=%pad, len=%d, pattern=0x%x, flags=0x%lx\n",
+                       __func__, &sg_dma_address(sg), sg_dma_len(sg),
                        value, flags);
                desc = at_xdmac_memset_create_desc(chan, atchan,
                                                   sg_dma_address(sg),
@@ -1333,7 +1336,7 @@ at_xdmac_prep_dma_memset_sg(struct dma_chan *chan, struct scatterlist *sgl,
                 * since we don't care about the stride anymore.
                 */
                if ((i == (sg_len - 1)) &&
-                   sg_dma_len(ppsg) == sg_dma_len(psg)) {
+                   sg_dma_len(psg) == sg_dma_len(sg)) {
                        dev_dbg(chan2dev(chan),
                                "%s: desc 0x%p can be merged with desc 0x%p\n",
                                __func__, desc, pdesc);
index c92d6a70ccf303c69cfdb127210a09a1262122bc..996c4b00d323ed5c2dd6455f80eb36ed8e9a8b23 100644 (file)
@@ -31,6 +31,7 @@
  */
 #include <linux/dmaengine.h>
 #include <linux/dma-mapping.h>
+#include <linux/dmapool.h>
 #include <linux/err.h>
 #include <linux/init.h>
 #include <linux/interrupt.h>
@@ -62,6 +63,11 @@ struct bcm2835_dma_cb {
        uint32_t pad[2];
 };
 
+struct bcm2835_cb_entry {
+       struct bcm2835_dma_cb *cb;
+       dma_addr_t paddr;
+};
+
 struct bcm2835_chan {
        struct virt_dma_chan vc;
        struct list_head node;
@@ -72,18 +78,18 @@ struct bcm2835_chan {
 
        int ch;
        struct bcm2835_desc *desc;
+       struct dma_pool *cb_pool;
 
        void __iomem *chan_base;
        int irq_number;
 };
 
 struct bcm2835_desc {
+       struct bcm2835_chan *c;
        struct virt_dma_desc vd;
        enum dma_transfer_direction dir;
 
-       unsigned int control_block_size;
-       struct bcm2835_dma_cb *control_block_base;
-       dma_addr_t control_block_base_phys;
+       struct bcm2835_cb_entry *cb_list;
 
        unsigned int frames;
        size_t size;
@@ -143,10 +149,13 @@ static inline struct bcm2835_desc *to_bcm2835_dma_desc(
 static void bcm2835_dma_desc_free(struct virt_dma_desc *vd)
 {
        struct bcm2835_desc *desc = container_of(vd, struct bcm2835_desc, vd);
-       dma_free_coherent(desc->vd.tx.chan->device->dev,
-                       desc->control_block_size,
-                       desc->control_block_base,
-                       desc->control_block_base_phys);
+       int i;
+
+       for (i = 0; i < desc->frames; i++)
+               dma_pool_free(desc->c->cb_pool, desc->cb_list[i].cb,
+                             desc->cb_list[i].paddr);
+
+       kfree(desc->cb_list);
        kfree(desc);
 }
 
@@ -199,7 +208,7 @@ static void bcm2835_dma_start_desc(struct bcm2835_chan *c)
 
        c->desc = d = to_bcm2835_dma_desc(&vd->tx);
 
-       writel(d->control_block_base_phys, c->chan_base + BCM2835_DMA_ADDR);
+       writel(d->cb_list[0].paddr, c->chan_base + BCM2835_DMA_ADDR);
        writel(BCM2835_DMA_ACTIVE, c->chan_base + BCM2835_DMA_CS);
 }
 
@@ -232,9 +241,16 @@ static irqreturn_t bcm2835_dma_callback(int irq, void *data)
 static int bcm2835_dma_alloc_chan_resources(struct dma_chan *chan)
 {
        struct bcm2835_chan *c = to_bcm2835_dma_chan(chan);
+       struct device *dev = c->vc.chan.device->dev;
+
+       dev_dbg(dev, "Allocating DMA channel %d\n", c->ch);
 
-       dev_dbg(c->vc.chan.device->dev,
-                       "Allocating DMA channel %d\n", c->ch);
+       c->cb_pool = dma_pool_create(dev_name(dev), dev,
+                                    sizeof(struct bcm2835_dma_cb), 0, 0);
+       if (!c->cb_pool) {
+               dev_err(dev, "unable to allocate descriptor pool\n");
+               return -ENOMEM;
+       }
 
        return request_irq(c->irq_number,
                        bcm2835_dma_callback, 0, "DMA IRQ", c);
@@ -246,6 +262,7 @@ static void bcm2835_dma_free_chan_resources(struct dma_chan *chan)
 
        vchan_free_chan_resources(&c->vc);
        free_irq(c->irq_number, c);
+       dma_pool_destroy(c->cb_pool);
 
        dev_dbg(c->vc.chan.device->dev, "Freeing DMA channel %u\n", c->ch);
 }
@@ -261,8 +278,7 @@ static size_t bcm2835_dma_desc_size_pos(struct bcm2835_desc *d, dma_addr_t addr)
        size_t size;
 
        for (size = i = 0; i < d->frames; i++) {
-               struct bcm2835_dma_cb *control_block =
-                       &d->control_block_base[i];
+               struct bcm2835_dma_cb *control_block = d->cb_list[i].cb;
                size_t this_size = control_block->length;
                dma_addr_t dma;
 
@@ -343,6 +359,7 @@ static struct dma_async_tx_descriptor *bcm2835_dma_prep_dma_cyclic(
        dma_addr_t dev_addr;
        unsigned int es, sync_type;
        unsigned int frame;
+       int i;
 
        /* Grab configuration */
        if (!is_slave_direction(direction)) {
@@ -374,27 +391,31 @@ static struct dma_async_tx_descriptor *bcm2835_dma_prep_dma_cyclic(
        if (!d)
                return NULL;
 
+       d->c = c;
        d->dir = direction;
        d->frames = buf_len / period_len;
 
-       /* Allocate memory for control blocks */
-       d->control_block_size = d->frames * sizeof(struct bcm2835_dma_cb);
-       d->control_block_base = dma_zalloc_coherent(chan->device->dev,
-                       d->control_block_size, &d->control_block_base_phys,
-                       GFP_NOWAIT);
-
-       if (!d->control_block_base) {
+       d->cb_list = kcalloc(d->frames, sizeof(*d->cb_list), GFP_KERNEL);
+       if (!d->cb_list) {
                kfree(d);
                return NULL;
        }
+       /* Allocate memory for control blocks */
+       for (i = 0; i < d->frames; i++) {
+               struct bcm2835_cb_entry *cb_entry = &d->cb_list[i];
+
+               cb_entry->cb = dma_pool_zalloc(c->cb_pool, GFP_ATOMIC,
+                                              &cb_entry->paddr);
+               if (!cb_entry->cb)
+                       goto error_cb;
+       }
 
        /*
         * Iterate over all frames, create a control block
         * for each frame and link them together.
         */
        for (frame = 0; frame < d->frames; frame++) {
-               struct bcm2835_dma_cb *control_block =
-                       &d->control_block_base[frame];
+               struct bcm2835_dma_cb *control_block = d->cb_list[frame].cb;
 
                /* Setup adresses */
                if (d->dir == DMA_DEV_TO_MEM) {
@@ -428,12 +449,21 @@ static struct dma_async_tx_descriptor *bcm2835_dma_prep_dma_cyclic(
                 * This DMA engine driver currently only supports cyclic DMA.
                 * Therefore, wrap around at number of frames.
                 */
-               control_block->next = d->control_block_base_phys +
-                       sizeof(struct bcm2835_dma_cb)
-                       * ((frame + 1) % d->frames);
+               control_block->next = d->cb_list[((frame + 1) % d->frames)].paddr;
        }
 
        return vchan_tx_prep(&c->vc, &d->vd, flags);
+error_cb:
+       i--;
+       for (; i >= 0; i--) {
+               struct bcm2835_cb_entry *cb_entry = &d->cb_list[i];
+
+               dma_pool_free(c->cb_pool, cb_entry->cb, cb_entry->paddr);
+       }
+
+       kfree(d->cb_list);
+       kfree(d);
+       return NULL;
 }
 
 static int bcm2835_dma_slave_config(struct dma_chan *chan,
index 6b03e4e84e6bf29b2226359e2e60bb43cd1474ce..16fe773fb846b5e9c9cb70b625715a5f5f888237 100644 (file)
 
 /* CCCFG register */
 #define GET_NUM_DMACH(x)       (x & 0x7) /* bits 0-2 */
-#define GET_NUM_QDMACH(x)      (x & 0x70 >> 4) /* bits 4-6 */
+#define GET_NUM_QDMACH(x)      ((x & 0x70) >> 4) /* bits 4-6 */
 #define GET_NUM_PAENTRY(x)     ((x & 0x7000) >> 12) /* bits 12-14 */
 #define GET_NUM_EVQUE(x)       ((x & 0x70000) >> 16) /* bits 16-18 */
 #define GET_NUM_REGN(x)                ((x & 0x300000) >> 20) /* bits 20-21 */
@@ -1565,7 +1565,7 @@ static void edma_tc_set_pm_state(struct edma_tc *tc, bool enable)
        struct platform_device *tc_pdev;
        int ret;
 
-       if (!tc)
+       if (!IS_ENABLED(CONFIG_OF) || !tc)
                return;
 
        tc_pdev = of_find_device_by_node(tc->node);
@@ -1752,16 +1752,14 @@ static enum dma_status edma_tx_status(struct dma_chan *chan,
        return ret;
 }
 
-static bool edma_is_memcpy_channel(int ch_num, u16 *memcpy_channels)
+static bool edma_is_memcpy_channel(int ch_num, s32 *memcpy_channels)
 {
-       s16 *memcpy_ch = memcpy_channels;
-
        if (!memcpy_channels)
                return false;
-       while (*memcpy_ch != -1) {
-               if (*memcpy_ch == ch_num)
+       while (*memcpy_channels != -1) {
+               if (*memcpy_channels == ch_num)
                        return true;
-               memcpy_ch++;
+               memcpy_channels++;
        }
        return false;
 }
@@ -1775,7 +1773,7 @@ static void edma_dma_init(struct edma_cc *ecc, bool legacy_mode)
 {
        struct dma_device *s_ddev = &ecc->dma_slave;
        struct dma_device *m_ddev = NULL;
-       s16 *memcpy_channels = ecc->info->memcpy_channels;
+       s32 *memcpy_channels = ecc->info->memcpy_channels;
        int i, j;
 
        dma_cap_zero(s_ddev->cap_mask);
@@ -1996,16 +1994,16 @@ static struct edma_soc_info *edma_setup_info_from_dt(struct device *dev,
        prop = of_find_property(dev->of_node, "ti,edma-memcpy-channels", &sz);
        if (prop) {
                const char pname[] = "ti,edma-memcpy-channels";
-               size_t nelm = sz / sizeof(s16);
-               s16 *memcpy_ch;
+               size_t nelm = sz / sizeof(s32);
+               s32 *memcpy_ch;
 
-               memcpy_ch = devm_kcalloc(dev, nelm + 1, sizeof(s16),
+               memcpy_ch = devm_kcalloc(dev, nelm + 1, sizeof(s32),
                                         GFP_KERNEL);
                if (!memcpy_ch)
                        return ERR_PTR(-ENOMEM);
 
-               ret = of_property_read_u16_array(dev->of_node, pname,
-                                                (u16 *)memcpy_ch, nelm);
+               ret = of_property_read_u32_array(dev->of_node, pname,
+                                                (u32 *)memcpy_ch, nelm);
                if (ret)
                        return ERR_PTR(ret);
 
@@ -2017,31 +2015,50 @@ static struct edma_soc_info *edma_setup_info_from_dt(struct device *dev,
                                &sz);
        if (prop) {
                const char pname[] = "ti,edma-reserved-slot-ranges";
+               u32 (*tmp)[2];
                s16 (*rsv_slots)[2];
-               size_t nelm = sz / sizeof(*rsv_slots);
+               size_t nelm = sz / sizeof(*tmp);
                struct edma_rsv_info *rsv_info;
+               int i;
 
                if (!nelm)
                        return info;
 
+               tmp = kcalloc(nelm, sizeof(*tmp), GFP_KERNEL);
+               if (!tmp)
+                       return ERR_PTR(-ENOMEM);
+
                rsv_info = devm_kzalloc(dev, sizeof(*rsv_info), GFP_KERNEL);
-               if (!rsv_info)
+               if (!rsv_info) {
+                       kfree(tmp);
                        return ERR_PTR(-ENOMEM);
+               }
 
                rsv_slots = devm_kcalloc(dev, nelm + 1, sizeof(*rsv_slots),
                                         GFP_KERNEL);
-               if (!rsv_slots)
+               if (!rsv_slots) {
+                       kfree(tmp);
                        return ERR_PTR(-ENOMEM);
+               }
 
-               ret = of_property_read_u16_array(dev->of_node, pname,
-                                                (u16 *)rsv_slots, nelm * 2);
-               if (ret)
+               ret = of_property_read_u32_array(dev->of_node, pname,
+                                                (u32 *)tmp, nelm * 2);
+               if (ret) {
+                       kfree(tmp);
                        return ERR_PTR(ret);
+               }
 
+               for (i = 0; i < nelm; i++) {
+                       rsv_slots[i][0] = tmp[i][0];
+                       rsv_slots[i][1] = tmp[i][1];
+               }
                rsv_slots[nelm][0] = -1;
                rsv_slots[nelm][1] = -1;
+
                info->rsv = rsv_info;
                info->rsv->rsv_slots = (const s16 (*)[2])rsv_slots;
+
+               kfree(tmp);
        }
 
        return info;
index 7058d58ba5887b6711bf2fedef3cf70c19db83e5..0f6fd42f55ca41975b12dbe267ef3aabdb81c017 100644 (file)
@@ -1462,7 +1462,7 @@ err_firmware:
 
 #define EVENT_REMAP_CELLS 3
 
-static int __init sdma_event_remap(struct sdma_engine *sdma)
+static int sdma_event_remap(struct sdma_engine *sdma)
 {
        struct device_node *np = sdma->dev->of_node;
        struct device_node *gpr_np = of_parse_phandle(np, "gpr", 0);
index 068e920ecb68d5ec681a1ca8a84642796a39a704..cddfa8dbf4bdfb421508e8d10e74faa8a165c4f0 100644 (file)
@@ -317,6 +317,7 @@ mic_dma_prep_memcpy_lock(struct dma_chan *ch, dma_addr_t dma_dest,
        struct mic_dma_chan *mic_ch = to_mic_dma_chan(ch);
        struct device *dev = mic_dma_ch_to_device(mic_ch);
        int result;
+       struct dma_async_tx_descriptor *tx = NULL;
 
        if (!len && !flags)
                return NULL;
@@ -324,10 +325,13 @@ mic_dma_prep_memcpy_lock(struct dma_chan *ch, dma_addr_t dma_dest,
        spin_lock(&mic_ch->prep_lock);
        result = mic_dma_do_dma(mic_ch, flags, dma_src, dma_dest, len);
        if (result >= 0)
-               return allocate_tx(mic_ch);
-       dev_err(dev, "Error enqueueing dma, error=%d\n", result);
+               tx = allocate_tx(mic_ch);
+
+       if (!tx)
+               dev_err(dev, "Error enqueueing dma, error=%d\n", result);
+
        spin_unlock(&mic_ch->prep_lock);
-       return NULL;
+       return tx;
 }
 
 static struct dma_async_tx_descriptor *
@@ -335,13 +339,14 @@ mic_dma_prep_interrupt_lock(struct dma_chan *ch, unsigned long flags)
 {
        struct mic_dma_chan *mic_ch = to_mic_dma_chan(ch);
        int ret;
+       struct dma_async_tx_descriptor *tx = NULL;
 
        spin_lock(&mic_ch->prep_lock);
        ret = mic_dma_do_dma(mic_ch, flags, 0, 0, 0);
        if (!ret)
-               return allocate_tx(mic_ch);
+               tx = allocate_tx(mic_ch);
        spin_unlock(&mic_ch->prep_lock);
-       return NULL;
+       return tx;
 }
 
 /* Return the status of the transaction */
index ebd8a5f398b08ee2bc883ccb06a7752657eb4877..f1bcc2a163b30cef09b3d682b399037e2b9268c3 100644 (file)
@@ -679,8 +679,11 @@ static int usb_dmac_runtime_suspend(struct device *dev)
        struct usb_dmac *dmac = dev_get_drvdata(dev);
        int i;
 
-       for (i = 0; i < dmac->n_channels; ++i)
+       for (i = 0; i < dmac->n_channels; ++i) {
+               if (!dmac->channels[i].iomem)
+                       break;
                usb_dmac_chan_halt(&dmac->channels[i]);
+       }
 
        return 0;
 }
@@ -799,11 +802,10 @@ static int usb_dmac_probe(struct platform_device *pdev)
        ret = pm_runtime_get_sync(&pdev->dev);
        if (ret < 0) {
                dev_err(&pdev->dev, "runtime PM get sync failed (%d)\n", ret);
-               return ret;
+               goto error_pm;
        }
 
        ret = usb_dmac_init(dmac);
-       pm_runtime_put(&pdev->dev);
 
        if (ret) {
                dev_err(&pdev->dev, "failed to reset device\n");
@@ -851,10 +853,13 @@ static int usb_dmac_probe(struct platform_device *pdev)
        if (ret < 0)
                goto error;
 
+       pm_runtime_put(&pdev->dev);
        return 0;
 
 error:
        of_dma_controller_free(pdev->dev.of_node);
+       pm_runtime_put(&pdev->dev);
+error_pm:
        pm_runtime_disable(&pdev->dev);
        return ret;
 }
index a24f5cb877e0a2b32fcfccc14b80e01f2028a08d..953dc9195937d39bb1def7c7bfaa3f905f8d4032 100644 (file)
@@ -122,12 +122,10 @@ int fpga_mgr_firmware_load(struct fpga_manager *mgr, u32 flags,
        }
 
        ret = fpga_mgr_buf_load(mgr, flags, fw->data, fw->size);
-       if (ret)
-               return ret;
 
        release_firmware(fw);
 
-       return 0;
+       return ret;
 }
 EXPORT_SYMBOL_GPL(fpga_mgr_firmware_load);
 
@@ -256,7 +254,6 @@ int fpga_mgr_register(struct device *dev, const char *name,
                      void *priv)
 {
        struct fpga_manager *mgr;
-       const char *dt_label;
        int id, ret;
 
        if (!mops || !mops->write_init || !mops->write ||
@@ -300,11 +297,9 @@ int fpga_mgr_register(struct device *dev, const char *name,
        mgr->dev.id = id;
        dev_set_drvdata(dev, mgr);
 
-       dt_label = of_get_property(mgr->dev.of_node, "label", NULL);
-       if (dt_label)
-               ret = dev_set_name(&mgr->dev, "%s", dt_label);
-       else
-               ret = dev_set_name(&mgr->dev, "fpga%d", id);
+       ret = dev_set_name(&mgr->dev, "fpga%d", id);
+       if (ret)
+               goto error_device;
 
        ret = device_add(&mgr->dev);
        if (ret)
index 6ed7c0fb3378eac88af03b8c125d0a7c9749f3db..6b186829087c4b3f4746ebebb1e327df58486d15 100644 (file)
@@ -113,13 +113,16 @@ static int mmio_74xx_dir_out(struct gpio_chip *gc, unsigned int gpio, int val)
 
 static int mmio_74xx_gpio_probe(struct platform_device *pdev)
 {
-       const struct of_device_id *of_id =
-               of_match_device(mmio_74xx_gpio_ids, &pdev->dev);
+       const struct of_device_id *of_id;
        struct mmio_74xx_gpio_priv *priv;
        struct resource *res;
        void __iomem *dat;
        int err;
 
+       of_id = of_match_device(mmio_74xx_gpio_ids, &pdev->dev);
+       if (!of_id)
+               return -ENODEV;
+
        priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
        if (!priv)
                return -ENOMEM;
index e5827a56ff3b5eda451202849c41b2d8b0e54f31..5eaea8b812cf39515c3e7132d90d4f3d7e0fba17 100644 (file)
@@ -113,7 +113,7 @@ static int ar934x_gpio_direction_output(struct gpio_chip *chip, unsigned offset,
                __raw_writel(BIT(offset), ctrl->base + AR71XX_GPIO_REG_CLEAR);
 
        __raw_writel(
-               __raw_readl(ctrl->base + AR71XX_GPIO_REG_OE) & BIT(offset),
+               __raw_readl(ctrl->base + AR71XX_GPIO_REG_OE) & ~BIT(offset),
                ctrl->base + AR71XX_GPIO_REG_OE);
 
        spin_unlock_irqrestore(&ctrl->lock, flags);
index bd5193c67a9c272cb0bebf779ce3277d22aac479..88ae70ddb1274b11f31bad5dcb344d3a57f9c6e3 100644 (file)
@@ -141,9 +141,9 @@ static int bgpio_get_set(struct gpio_chip *gc, unsigned int gpio)
        unsigned long pinmask = bgc->pin2mask(bgc, gpio);
 
        if (bgc->dir & pinmask)
-               return bgc->read_reg(bgc->reg_set) & pinmask;
+               return !!(bgc->read_reg(bgc->reg_set) & pinmask);
        else
-               return bgc->read_reg(bgc->reg_dat) & pinmask;
+               return !!(bgc->read_reg(bgc->reg_dat) & pinmask);
 }
 
 static int bgpio_get(struct gpio_chip *gc, unsigned int gpio)
index 56d2d026e62e42bf6fec7db5ad2aa25aebd970f3..f7fbb46d5d797a32d9d35c119adb3df2166cc37e 100644 (file)
@@ -1122,8 +1122,6 @@ static int omap_gpio_chip_init(struct gpio_bank *bank, struct irq_chip *irqc)
        /* MPUIO is a bit different, reading IRQ status clears it */
        if (bank->is_mpuio) {
                irqc->irq_ack = dummy_irq_chip.irq_ack;
-               irqc->irq_mask = irq_gc_mask_set_bit;
-               irqc->irq_unmask = irq_gc_mask_clr_bit;
                if (!bank->regs->wkup_en)
                        irqc->irq_set_wake = NULL;
        }
index 171a6389f9ce086ffdf74f6c50523a77e205b473..52b447c071cbaa2e160bf5a67fc511ae26d6a55d 100644 (file)
@@ -167,6 +167,8 @@ static int palmas_gpio_probe(struct platform_device *pdev)
        const struct palmas_device_data *dev_data;
 
        match = of_match_device(of_palmas_gpio_match, &pdev->dev);
+       if (!match)
+               return -ENODEV;
        dev_data = match->data;
        if (!dev_data)
                dev_data = &palmas_dev_data;
index 045a952576c708e253de29438abaec95640989f2..7b25fdf64802339967ab541bb5ecd5bb876779d7 100644 (file)
@@ -187,11 +187,15 @@ MODULE_DEVICE_TABLE(of, syscon_gpio_ids);
 static int syscon_gpio_probe(struct platform_device *pdev)
 {
        struct device *dev = &pdev->dev;
-       const struct of_device_id *of_id = of_match_device(syscon_gpio_ids, dev);
+       const struct of_device_id *of_id;
        struct syscon_gpio_priv *priv;
        struct device_node *np = dev->of_node;
        int ret;
 
+       of_id = of_match_device(syscon_gpio_ids, dev);
+       if (!of_id)
+               return -ENODEV;
+
        priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
        if (!priv)
                return -ENOMEM;
index 027e5f47dd28738f04e6347f1807c6b28b34e618..896bf29776b093ee34efad4d4d29d073fda184b6 100644 (file)
@@ -375,6 +375,60 @@ static int tegra_gpio_irq_set_wake(struct irq_data *d, unsigned int enable)
 }
 #endif
 
+#ifdef CONFIG_DEBUG_FS
+
+#include <linux/debugfs.h>
+#include <linux/seq_file.h>
+
+static int dbg_gpio_show(struct seq_file *s, void *unused)
+{
+       int i;
+       int j;
+
+       for (i = 0; i < tegra_gpio_bank_count; i++) {
+               for (j = 0; j < 4; j++) {
+                       int gpio = tegra_gpio_compose(i, j, 0);
+                       seq_printf(s,
+                               "%d:%d %02x %02x %02x %02x %02x %02x %06x\n",
+                               i, j,
+                               tegra_gpio_readl(GPIO_CNF(gpio)),
+                               tegra_gpio_readl(GPIO_OE(gpio)),
+                               tegra_gpio_readl(GPIO_OUT(gpio)),
+                               tegra_gpio_readl(GPIO_IN(gpio)),
+                               tegra_gpio_readl(GPIO_INT_STA(gpio)),
+                               tegra_gpio_readl(GPIO_INT_ENB(gpio)),
+                               tegra_gpio_readl(GPIO_INT_LVL(gpio)));
+               }
+       }
+       return 0;
+}
+
+static int dbg_gpio_open(struct inode *inode, struct file *file)
+{
+       return single_open(file, dbg_gpio_show, &inode->i_private);
+}
+
+static const struct file_operations debug_fops = {
+       .open           = dbg_gpio_open,
+       .read           = seq_read,
+       .llseek         = seq_lseek,
+       .release        = single_release,
+};
+
+static void tegra_gpio_debuginit(void)
+{
+       (void) debugfs_create_file("tegra_gpio", S_IRUGO,
+                                       NULL, NULL, &debug_fops);
+}
+
+#else
+
+static inline void tegra_gpio_debuginit(void)
+{
+}
+
+#endif
+
 static struct irq_chip tegra_gpio_irq_chip = {
        .name           = "GPIO",
        .irq_ack        = tegra_gpio_irq_ack,
@@ -519,6 +573,8 @@ static int tegra_gpio_probe(struct platform_device *pdev)
                        spin_lock_init(&bank->lvl_lock[j]);
        }
 
+       tegra_gpio_debuginit();
+
        return 0;
 }
 
@@ -536,52 +592,3 @@ static int __init tegra_gpio_init(void)
        return platform_driver_register(&tegra_gpio_driver);
 }
 postcore_initcall(tegra_gpio_init);
-
-#ifdef CONFIG_DEBUG_FS
-
-#include <linux/debugfs.h>
-#include <linux/seq_file.h>
-
-static int dbg_gpio_show(struct seq_file *s, void *unused)
-{
-       int i;
-       int j;
-
-       for (i = 0; i < tegra_gpio_bank_count; i++) {
-               for (j = 0; j < 4; j++) {
-                       int gpio = tegra_gpio_compose(i, j, 0);
-                       seq_printf(s,
-                               "%d:%d %02x %02x %02x %02x %02x %02x %06x\n",
-                               i, j,
-                               tegra_gpio_readl(GPIO_CNF(gpio)),
-                               tegra_gpio_readl(GPIO_OE(gpio)),
-                               tegra_gpio_readl(GPIO_OUT(gpio)),
-                               tegra_gpio_readl(GPIO_IN(gpio)),
-                               tegra_gpio_readl(GPIO_INT_STA(gpio)),
-                               tegra_gpio_readl(GPIO_INT_ENB(gpio)),
-                               tegra_gpio_readl(GPIO_INT_LVL(gpio)));
-               }
-       }
-       return 0;
-}
-
-static int dbg_gpio_open(struct inode *inode, struct file *file)
-{
-       return single_open(file, dbg_gpio_show, &inode->i_private);
-}
-
-static const struct file_operations debug_fops = {
-       .open           = dbg_gpio_open,
-       .read           = seq_read,
-       .llseek         = seq_lseek,
-       .release        = single_release,
-};
-
-static int __init tegra_gpio_debuginit(void)
-{
-       (void) debugfs_create_file("tegra_gpio", S_IRUGO,
-                                       NULL, NULL, &debug_fops);
-       return 0;
-}
-late_initcall(tegra_gpio_debuginit);
-#endif
index a18f00fc1bb87544cc59182e6f4a5515464a2f29..4e4c3083ae567f02db4ff15444ec173ac53ebe0c 100644 (file)
@@ -233,7 +233,7 @@ static struct gpio_desc *gpio_name_to_desc(const char * const name)
                for (i = 0; i != chip->ngpio; ++i) {
                        struct gpio_desc *gpio = &chip->desc[i];
 
-                       if (!gpio->name)
+                       if (!gpio->name || !name)
                                continue;
 
                        if (!strcmp(gpio->name, name)) {
@@ -1279,7 +1279,13 @@ static int _gpiod_get_raw_value(const struct gpio_desc *desc)
        chip = desc->chip;
        offset = gpio_chip_hwgpio(desc);
        value = chip->get ? chip->get(chip, offset) : -EIO;
-       value = value < 0 ? value : !!value;
+       /*
+        * FIXME: fix all drivers to clamp to [0,1] or return negative,
+        * then change this to:
+        * value = value < 0 ? value : !!value;
+        * so we can properly propagate error codes.
+        */
+       value = !!value;
        trace_gpio_value(desc_to_gpio(desc), 1, value);
        return value;
 }
index 615ce6d464fb8bbbe821e2e606534168122890fe..048cfe073dae6a1e89112b219c6a130b3d513be9 100644 (file)
@@ -389,7 +389,6 @@ struct amdgpu_clock {
  * Fences.
  */
 struct amdgpu_fence_driver {
-       struct amdgpu_ring              *ring;
        uint64_t                        gpu_addr;
        volatile uint32_t               *cpu_addr;
        /* sync_seq is protected by ring emission lock */
@@ -398,7 +397,7 @@ struct amdgpu_fence_driver {
        bool                            initialized;
        struct amdgpu_irq_src           *irq_src;
        unsigned                        irq_type;
-       struct delayed_work             lockup_work;
+       struct timer_list               fallback_timer;
        wait_queue_head_t               fence_queue;
 };
 
@@ -497,6 +496,7 @@ struct amdgpu_bo_va_mapping {
 
 /* bo virtual addresses in a specific vm */
 struct amdgpu_bo_va {
+       struct mutex                    mutex;
        /* protected by bo being reserved */
        struct list_head                bo_list;
        struct fence                    *last_pt_update;
@@ -539,6 +539,7 @@ struct amdgpu_bo {
        /* Constant after initialization */
        struct amdgpu_device            *adev;
        struct drm_gem_object           gem_base;
+       struct amdgpu_bo                *parent;
 
        struct ttm_bo_kmap_obj          dma_buf_vmap;
        pid_t                           pid;
@@ -917,8 +918,8 @@ struct amdgpu_ring {
 #define AMDGPU_VM_FAULT_STOP_ALWAYS    2
 
 struct amdgpu_vm_pt {
-       struct amdgpu_bo                *bo;
-       uint64_t                        addr;
+       struct amdgpu_bo        *bo;
+       uint64_t                addr;
 };
 
 struct amdgpu_vm_id {
@@ -926,13 +927,9 @@ struct amdgpu_vm_id {
        uint64_t                pd_gpu_addr;
        /* last flushed PD/PT update */
        struct fence            *flushed_updates;
-       /* last use of vmid */
-       struct fence            *last_id_use;
 };
 
 struct amdgpu_vm {
-       struct mutex            mutex;
-
        struct rb_root          va;
 
        /* protecting invalidated */
@@ -957,24 +954,72 @@ struct amdgpu_vm {
 
        /* for id and flush management per ring */
        struct amdgpu_vm_id     ids[AMDGPU_MAX_RINGS];
+       /* for interval tree */
+       spinlock_t              it_lock;
+       /* protecting freed */
+       spinlock_t              freed_lock;
 };
 
 struct amdgpu_vm_manager {
-       struct fence                    *active[AMDGPU_NUM_VM];
-       uint32_t                        max_pfn;
+       struct {
+               struct fence    *active;
+               atomic_long_t   owner;
+       } ids[AMDGPU_NUM_VM];
+
+       uint32_t                                max_pfn;
        /* number of VMIDs */
-       unsigned                        nvm;
+       unsigned                                nvm;
        /* vram base address for page table entry  */
-       u64                             vram_base_offset;
+       u64                                     vram_base_offset;
        /* is vm enabled? */
-       bool                            enabled;
-       /* for hw to save the PD addr on suspend/resume */
-       uint32_t                        saved_table_addr[AMDGPU_NUM_VM];
+       bool                                    enabled;
        /* vm pte handling */
        const struct amdgpu_vm_pte_funcs        *vm_pte_funcs;
        struct amdgpu_ring                      *vm_pte_funcs_ring;
 };
 
+void amdgpu_vm_manager_fini(struct amdgpu_device *adev);
+int amdgpu_vm_init(struct amdgpu_device *adev, struct amdgpu_vm *vm);
+void amdgpu_vm_fini(struct amdgpu_device *adev, struct amdgpu_vm *vm);
+struct amdgpu_bo_list_entry *amdgpu_vm_get_bos(struct amdgpu_device *adev,
+                                              struct amdgpu_vm *vm,
+                                              struct list_head *head);
+int amdgpu_vm_grab_id(struct amdgpu_vm *vm, struct amdgpu_ring *ring,
+                     struct amdgpu_sync *sync);
+void amdgpu_vm_flush(struct amdgpu_ring *ring,
+                    struct amdgpu_vm *vm,
+                    struct fence *updates);
+void amdgpu_vm_fence(struct amdgpu_device *adev,
+                    struct amdgpu_vm *vm,
+                    struct fence *fence);
+uint64_t amdgpu_vm_map_gart(struct amdgpu_device *adev, uint64_t addr);
+int amdgpu_vm_update_page_directory(struct amdgpu_device *adev,
+                                   struct amdgpu_vm *vm);
+int amdgpu_vm_clear_freed(struct amdgpu_device *adev,
+                         struct amdgpu_vm *vm);
+int amdgpu_vm_clear_invalids(struct amdgpu_device *adev, struct amdgpu_vm *vm,
+                            struct amdgpu_sync *sync);
+int amdgpu_vm_bo_update(struct amdgpu_device *adev,
+                       struct amdgpu_bo_va *bo_va,
+                       struct ttm_mem_reg *mem);
+void amdgpu_vm_bo_invalidate(struct amdgpu_device *adev,
+                            struct amdgpu_bo *bo);
+struct amdgpu_bo_va *amdgpu_vm_bo_find(struct amdgpu_vm *vm,
+                                      struct amdgpu_bo *bo);
+struct amdgpu_bo_va *amdgpu_vm_bo_add(struct amdgpu_device *adev,
+                                     struct amdgpu_vm *vm,
+                                     struct amdgpu_bo *bo);
+int amdgpu_vm_bo_map(struct amdgpu_device *adev,
+                    struct amdgpu_bo_va *bo_va,
+                    uint64_t addr, uint64_t offset,
+                    uint64_t size, uint32_t flags);
+int amdgpu_vm_bo_unmap(struct amdgpu_device *adev,
+                      struct amdgpu_bo_va *bo_va,
+                      uint64_t addr);
+void amdgpu_vm_bo_rmv(struct amdgpu_device *adev,
+                     struct amdgpu_bo_va *bo_va);
+int amdgpu_vm_free_job(struct amdgpu_job *job);
+
 /*
  * context related structures
  */
@@ -1211,6 +1256,7 @@ struct amdgpu_cs_parser {
        /* relocations */
        struct amdgpu_bo_list_entry     *vm_bos;
        struct list_head        validated;
+       struct fence            *fence;
 
        struct amdgpu_ib        *ibs;
        uint32_t                num_ibs;
@@ -1218,7 +1264,8 @@ struct amdgpu_cs_parser {
        struct ww_acquire_ctx   ticket;
 
        /* user fence */
-       struct amdgpu_user_fence uf;
+       struct amdgpu_user_fence        uf;
+       struct amdgpu_bo_list_entry     uf_entry;
 };
 
 struct amdgpu_job {
@@ -1226,7 +1273,7 @@ struct amdgpu_job {
        struct amdgpu_device    *adev;
        struct amdgpu_ib        *ibs;
        uint32_t                num_ibs;
-       struct mutex            job_lock;
+       void                    *owner;
        struct amdgpu_user_fence uf;
        int (*free_job)(struct amdgpu_job *job);
 };
@@ -2257,11 +2304,6 @@ void amdgpu_pci_config_reset(struct amdgpu_device *adev);
 bool amdgpu_card_posted(struct amdgpu_device *adev);
 void amdgpu_update_display_priority(struct amdgpu_device *adev);
 bool amdgpu_boot_test_post_card(struct amdgpu_device *adev);
-struct amdgpu_cs_parser *amdgpu_cs_parser_create(struct amdgpu_device *adev,
-                                                struct drm_file *filp,
-                                                struct amdgpu_ctx *ctx,
-                                                struct amdgpu_ib *ibs,
-                                                uint32_t num_ibs);
 
 int amdgpu_cs_parser_init(struct amdgpu_cs_parser *p, void *data);
 int amdgpu_cs_get_ring(struct amdgpu_device *adev, u32 ip_type,
@@ -2318,49 +2360,6 @@ int amdgpu_get_vblank_timestamp_kms(struct drm_device *dev, unsigned int pipe,
 long amdgpu_kms_compat_ioctl(struct file *filp, unsigned int cmd,
                             unsigned long arg);
 
-/*
- * vm
- */
-int amdgpu_vm_init(struct amdgpu_device *adev, struct amdgpu_vm *vm);
-void amdgpu_vm_fini(struct amdgpu_device *adev, struct amdgpu_vm *vm);
-struct amdgpu_bo_list_entry *amdgpu_vm_get_bos(struct amdgpu_device *adev,
-                                         struct amdgpu_vm *vm,
-                                         struct list_head *head);
-int amdgpu_vm_grab_id(struct amdgpu_vm *vm, struct amdgpu_ring *ring,
-                     struct amdgpu_sync *sync);
-void amdgpu_vm_flush(struct amdgpu_ring *ring,
-                    struct amdgpu_vm *vm,
-                    struct fence *updates);
-void amdgpu_vm_fence(struct amdgpu_device *adev,
-                    struct amdgpu_vm *vm,
-                    struct amdgpu_fence *fence);
-uint64_t amdgpu_vm_map_gart(struct amdgpu_device *adev, uint64_t addr);
-int amdgpu_vm_update_page_directory(struct amdgpu_device *adev,
-                                   struct amdgpu_vm *vm);
-int amdgpu_vm_clear_freed(struct amdgpu_device *adev,
-                               struct amdgpu_vm *vm);
-int amdgpu_vm_clear_invalids(struct amdgpu_device *adev,
-                               struct amdgpu_vm *vm, struct amdgpu_sync *sync);
-int amdgpu_vm_bo_update(struct amdgpu_device *adev,
-                       struct amdgpu_bo_va *bo_va,
-                       struct ttm_mem_reg *mem);
-void amdgpu_vm_bo_invalidate(struct amdgpu_device *adev,
-                            struct amdgpu_bo *bo);
-struct amdgpu_bo_va *amdgpu_vm_bo_find(struct amdgpu_vm *vm,
-                                      struct amdgpu_bo *bo);
-struct amdgpu_bo_va *amdgpu_vm_bo_add(struct amdgpu_device *adev,
-                                     struct amdgpu_vm *vm,
-                                     struct amdgpu_bo *bo);
-int amdgpu_vm_bo_map(struct amdgpu_device *adev,
-                    struct amdgpu_bo_va *bo_va,
-                    uint64_t addr, uint64_t offset,
-                    uint64_t size, uint32_t flags);
-int amdgpu_vm_bo_unmap(struct amdgpu_device *adev,
-                      struct amdgpu_bo_va *bo_va,
-                      uint64_t addr);
-void amdgpu_vm_bo_rmv(struct amdgpu_device *adev,
-                     struct amdgpu_bo_va *bo_va);
-int amdgpu_vm_free_job(struct amdgpu_job *job);
 /*
  * functions used by amdgpu_encoder.c
  */
index dfc4d02c7a38f21501c3c3af565989522bea3bb6..25a3e2485cc2e9572943638d1975f678fbc26e38 100644 (file)
@@ -127,28 +127,35 @@ int amdgpu_cs_get_ring(struct amdgpu_device *adev, u32 ip_type,
        return 0;
 }
 
-struct amdgpu_cs_parser *amdgpu_cs_parser_create(struct amdgpu_device *adev,
-                                               struct drm_file *filp,
-                                               struct amdgpu_ctx *ctx,
-                                               struct amdgpu_ib *ibs,
-                                               uint32_t num_ibs)
+static int amdgpu_cs_user_fence_chunk(struct amdgpu_cs_parser *p,
+                                     struct drm_amdgpu_cs_chunk_fence *fence_data)
 {
-       struct amdgpu_cs_parser *parser;
-       int i;
+       struct drm_gem_object *gobj;
+       uint32_t handle;
+
+       handle = fence_data->handle;
+       gobj = drm_gem_object_lookup(p->adev->ddev, p->filp,
+                                    fence_data->handle);
+       if (gobj == NULL)
+               return -EINVAL;
+
+       p->uf.bo = amdgpu_bo_ref(gem_to_amdgpu_bo(gobj));
+       p->uf.offset = fence_data->offset;
 
-       parser = kzalloc(sizeof(struct amdgpu_cs_parser), GFP_KERNEL);
-       if (!parser)
-               return NULL;
+       if (amdgpu_ttm_tt_has_userptr(p->uf.bo->tbo.ttm)) {
+               drm_gem_object_unreference_unlocked(gobj);
+               return -EINVAL;
+       }
 
-       parser->adev = adev;
-       parser->filp = filp;
-       parser->ctx = ctx;
-       parser->ibs = ibs;
-       parser->num_ibs = num_ibs;
-       for (i = 0; i < num_ibs; i++)
-               ibs[i].ctx = ctx;
+       p->uf_entry.robj = amdgpu_bo_ref(p->uf.bo);
+       p->uf_entry.prefered_domains = AMDGPU_GEM_DOMAIN_GTT;
+       p->uf_entry.allowed_domains = AMDGPU_GEM_DOMAIN_GTT;
+       p->uf_entry.priority = 0;
+       p->uf_entry.tv.bo = &p->uf_entry.robj->tbo;
+       p->uf_entry.tv.shared = true;
 
-       return parser;
+       drm_gem_object_unreference_unlocked(gobj);
+       return 0;
 }
 
 int amdgpu_cs_parser_init(struct amdgpu_cs_parser *p, void *data)
@@ -231,26 +238,15 @@ int amdgpu_cs_parser_init(struct amdgpu_cs_parser *p, void *data)
 
                case AMDGPU_CHUNK_ID_FENCE:
                        size = sizeof(struct drm_amdgpu_cs_chunk_fence);
-                       if (p->chunks[i].length_dw * sizeof(uint32_t) >= size) {
-                               uint32_t handle;
-                               struct drm_gem_object *gobj;
-                               struct drm_amdgpu_cs_chunk_fence *fence_data;
-
-                               fence_data = (void *)p->chunks[i].kdata;
-                               handle = fence_data->handle;
-                               gobj = drm_gem_object_lookup(p->adev->ddev,
-                                                            p->filp, handle);
-                               if (gobj == NULL) {
-                                       ret = -EINVAL;
-                                       goto free_partial_kdata;
-                               }
-
-                               p->uf.bo = gem_to_amdgpu_bo(gobj);
-                               p->uf.offset = fence_data->offset;
-                       } else {
+                       if (p->chunks[i].length_dw * sizeof(uint32_t) < size) {
                                ret = -EINVAL;
                                goto free_partial_kdata;
                        }
+
+                       ret = amdgpu_cs_user_fence_chunk(p, (void *)p->chunks[i].kdata);
+                       if (ret)
+                               goto free_partial_kdata;
+
                        break;
 
                case AMDGPU_CHUNK_ID_DEPENDENCIES:
@@ -413,6 +409,9 @@ static int amdgpu_cs_parser_relocs(struct amdgpu_cs_parser *p)
        p->vm_bos = amdgpu_vm_get_bos(p->adev, &fpriv->vm,
                                      &p->validated);
 
+       if (p->uf.bo)
+               list_add(&p->uf_entry.tv.head, &p->validated);
+
        if (need_mmap_lock)
                down_read(&current->mm->mmap_sem);
 
@@ -463,8 +462,18 @@ static int cmp_size_smaller_first(void *priv, struct list_head *a,
        return (int)la->robj->tbo.num_pages - (int)lb->robj->tbo.num_pages;
 }
 
-static void amdgpu_cs_parser_fini_early(struct amdgpu_cs_parser *parser, int error, bool backoff)
+/**
+ * cs_parser_fini() - clean parser states
+ * @parser:    parser structure holding parsing context.
+ * @error:     error number
+ *
+ * If error is set than unvalidate buffer, otherwise just free memory
+ * used by parsing context.
+ **/
+static void amdgpu_cs_parser_fini(struct amdgpu_cs_parser *parser, int error, bool backoff)
 {
+       unsigned i;
+
        if (!error) {
                /* Sort the buffer list from the smallest to largest buffer,
                 * which affects the order of buffers in the LRU list.
@@ -479,17 +488,14 @@ static void amdgpu_cs_parser_fini_early(struct amdgpu_cs_parser *parser, int err
                list_sort(NULL, &parser->validated, cmp_size_smaller_first);
 
                ttm_eu_fence_buffer_objects(&parser->ticket,
-                               &parser->validated,
-                               &parser->ibs[parser->num_ibs-1].fence->base);
+                                           &parser->validated,
+                                           parser->fence);
        } else if (backoff) {
                ttm_eu_backoff_reservation(&parser->ticket,
                                           &parser->validated);
        }
-}
+       fence_put(parser->fence);
 
-static void amdgpu_cs_parser_fini_late(struct amdgpu_cs_parser *parser)
-{
-       unsigned i;
        if (parser->ctx)
                amdgpu_ctx_put(parser->ctx);
        if (parser->bo_list)
@@ -499,31 +505,12 @@ static void amdgpu_cs_parser_fini_late(struct amdgpu_cs_parser *parser)
        for (i = 0; i < parser->nchunks; i++)
                drm_free_large(parser->chunks[i].kdata);
        kfree(parser->chunks);
-       if (!amdgpu_enable_scheduler)
-       {
-               if (parser->ibs)
-                       for (i = 0; i < parser->num_ibs; i++)
-                               amdgpu_ib_free(parser->adev, &parser->ibs[i]);
-               kfree(parser->ibs);
-               if (parser->uf.bo)
-                       drm_gem_object_unreference_unlocked(&parser->uf.bo->gem_base);
-       }
-
-       kfree(parser);
-}
-
-/**
- * cs_parser_fini() - clean parser states
- * @parser:    parser structure holding parsing context.
- * @error:     error number
- *
- * If error is set than unvalidate buffer, otherwise just free memory
- * used by parsing context.
- **/
-static void amdgpu_cs_parser_fini(struct amdgpu_cs_parser *parser, int error, bool backoff)
-{
-       amdgpu_cs_parser_fini_early(parser, error, backoff);
-       amdgpu_cs_parser_fini_late(parser);
+       if (parser->ibs)
+               for (i = 0; i < parser->num_ibs; i++)
+                       amdgpu_ib_free(parser->adev, &parser->ibs[i]);
+       kfree(parser->ibs);
+       amdgpu_bo_unref(&parser->uf.bo);
+       amdgpu_bo_unref(&parser->uf_entry.robj);
 }
 
 static int amdgpu_bo_vm_update_pte(struct amdgpu_cs_parser *p,
@@ -610,15 +597,9 @@ static int amdgpu_cs_ib_vm_chunk(struct amdgpu_device *adev,
        }
 
        r = amdgpu_bo_vm_update_pte(parser, vm);
-       if (r) {
-               goto out;
-       }
-       amdgpu_cs_sync_rings(parser);
-       if (!amdgpu_enable_scheduler)
-               r = amdgpu_ib_schedule(adev, parser->num_ibs, parser->ibs,
-                                      parser->filp);
+       if (!r)
+               amdgpu_cs_sync_rings(parser);
 
-out:
        return r;
 }
 
@@ -818,7 +799,7 @@ static int amdgpu_cs_free_job(struct amdgpu_job *job)
                        amdgpu_ib_free(job->adev, &job->ibs[i]);
        kfree(job->ibs);
        if (job->uf.bo)
-               drm_gem_object_unreference_unlocked(&job->uf.bo->gem_base);
+               amdgpu_bo_unref(&job->uf.bo);
        return 0;
 }
 
@@ -826,38 +807,35 @@ int amdgpu_cs_ioctl(struct drm_device *dev, void *data, struct drm_file *filp)
 {
        struct amdgpu_device *adev = dev->dev_private;
        union drm_amdgpu_cs *cs = data;
-       struct amdgpu_fpriv *fpriv = filp->driver_priv;
-       struct amdgpu_vm *vm = &fpriv->vm;
-       struct amdgpu_cs_parser *parser;
+       struct amdgpu_cs_parser parser = {};
        bool reserved_buffers = false;
        int i, r;
 
        if (!adev->accel_working)
                return -EBUSY;
 
-       parser = amdgpu_cs_parser_create(adev, filp, NULL, NULL, 0);
-       if (!parser)
-               return -ENOMEM;
-       r = amdgpu_cs_parser_init(parser, data);
+       parser.adev = adev;
+       parser.filp = filp;
+
+       r = amdgpu_cs_parser_init(&parser, data);
        if (r) {
                DRM_ERROR("Failed to initialize parser !\n");
-               amdgpu_cs_parser_fini(parser, r, false);
+               amdgpu_cs_parser_fini(&parser, r, false);
                r = amdgpu_cs_handle_lockup(adev, r);
                return r;
        }
-       mutex_lock(&vm->mutex);
-       r = amdgpu_cs_parser_relocs(parser);
+       r = amdgpu_cs_parser_relocs(&parser);
        if (r == -ENOMEM)
                DRM_ERROR("Not enough memory for command submission!\n");
        else if (r && r != -ERESTARTSYS)
                DRM_ERROR("Failed to process the buffer list %d!\n", r);
        else if (!r) {
                reserved_buffers = true;
-               r = amdgpu_cs_ib_fill(adev, parser);
+               r = amdgpu_cs_ib_fill(adev, &parser);
        }
 
        if (!r) {
-               r = amdgpu_cs_dependencies(adev, parser);
+               r = amdgpu_cs_dependencies(adev, &parser);
                if (r)
                        DRM_ERROR("Failed in the dependencies handling %d!\n", r);
        }
@@ -865,63 +843,71 @@ int amdgpu_cs_ioctl(struct drm_device *dev, void *data, struct drm_file *filp)
        if (r)
                goto out;
 
-       for (i = 0; i < parser->num_ibs; i++)
-               trace_amdgpu_cs(parser, i);
+       for (i = 0; i < parser.num_ibs; i++)
+               trace_amdgpu_cs(&parser, i);
 
-       r = amdgpu_cs_ib_vm_chunk(adev, parser);
+       r = amdgpu_cs_ib_vm_chunk(adev, &parser);
        if (r)
                goto out;
 
-       if (amdgpu_enable_scheduler && parser->num_ibs) {
+       if (amdgpu_enable_scheduler && parser.num_ibs) {
+               struct amdgpu_ring * ring = parser.ibs->ring;
+               struct amd_sched_fence *fence;
                struct amdgpu_job *job;
-               struct amdgpu_ring * ring =  parser->ibs->ring;
+
                job = kzalloc(sizeof(struct amdgpu_job), GFP_KERNEL);
                if (!job) {
                        r = -ENOMEM;
                        goto out;
                }
+
                job->base.sched = &ring->sched;
-               job->base.s_entity = &parser->ctx->rings[ring->idx].entity;
-               job->adev = parser->adev;
-               job->ibs = parser->ibs;
-               job->num_ibs = parser->num_ibs;
-               job->base.owner = parser->filp;
-               mutex_init(&job->job_lock);
+               job->base.s_entity = &parser.ctx->rings[ring->idx].entity;
+               job->adev = parser.adev;
+               job->owner = parser.filp;
+               job->free_job = amdgpu_cs_free_job;
+
+               job->ibs = parser.ibs;
+               job->num_ibs = parser.num_ibs;
+               parser.ibs = NULL;
+               parser.num_ibs = 0;
+
                if (job->ibs[job->num_ibs - 1].user) {
-                       memcpy(&job->uf,  &parser->uf,
-                              sizeof(struct amdgpu_user_fence));
+                       job->uf = parser.uf;
                        job->ibs[job->num_ibs - 1].user = &job->uf;
+                       parser.uf.bo = NULL;
                }
 
-               job->free_job = amdgpu_cs_free_job;
-               mutex_lock(&job->job_lock);
-               r = amd_sched_entity_push_job(&job->base);
-               if (r) {
-                       mutex_unlock(&job->job_lock);
+               fence = amd_sched_fence_create(job->base.s_entity,
+                                              parser.filp);
+               if (!fence) {
+                       r = -ENOMEM;
                        amdgpu_cs_free_job(job);
                        kfree(job);
                        goto out;
                }
-               cs->out.handle =
-                       amdgpu_ctx_add_fence(parser->ctx, ring,
-                                            &job->base.s_fence->base);
-               parser->ibs[parser->num_ibs - 1].sequence = cs->out.handle;
+               job->base.s_fence = fence;
+               parser.fence = fence_get(&fence->base);
 
-               list_sort(NULL, &parser->validated, cmp_size_smaller_first);
-               ttm_eu_fence_buffer_objects(&parser->ticket,
-                               &parser->validated,
-                               &job->base.s_fence->base);
+               cs->out.handle = amdgpu_ctx_add_fence(parser.ctx, ring,
+                                                     &fence->base);
+               job->ibs[job->num_ibs - 1].sequence = cs->out.handle;
 
-               mutex_unlock(&job->job_lock);
-               amdgpu_cs_parser_fini_late(parser);
-               mutex_unlock(&vm->mutex);
-               return 0;
+               trace_amdgpu_cs_ioctl(job);
+               amd_sched_entity_push_job(&job->base);
+
+       } else {
+               struct amdgpu_fence *fence;
+
+               r = amdgpu_ib_schedule(adev, parser.num_ibs, parser.ibs,
+                                      parser.filp);
+               fence = parser.ibs[parser.num_ibs - 1].fence;
+               parser.fence = fence_get(&fence->base);
+               cs->out.handle = parser.ibs[parser.num_ibs - 1].sequence;
        }
 
-       cs->out.handle = parser->ibs[parser->num_ibs - 1].sequence;
 out:
-       amdgpu_cs_parser_fini(parser, r, reserved_buffers);
-       mutex_unlock(&vm->mutex);
+       amdgpu_cs_parser_fini(&parser, r, reserved_buffers);
        r = amdgpu_cs_handle_lockup(adev, r);
        return r;
 }
index e173a5a02f0d8052bb6c76203b188b6cf231d787..5580d3420c3a368815364d8eccce3e1421ce6a12 100644 (file)
@@ -73,6 +73,8 @@ static void amdgpu_flip_work_func(struct work_struct *__work)
        struct drm_crtc *crtc = &amdgpuCrtc->base;
        unsigned long flags;
        unsigned i;
+       int vpos, hpos, stat, min_udelay;
+       struct drm_vblank_crtc *vblank = &crtc->dev->vblank[work->crtc_id];
 
        amdgpu_flip_wait_fence(adev, &work->excl);
        for (i = 0; i < work->shared_count; ++i)
@@ -81,6 +83,41 @@ static void amdgpu_flip_work_func(struct work_struct *__work)
        /* We borrow the event spin lock for protecting flip_status */
        spin_lock_irqsave(&crtc->dev->event_lock, flags);
 
+       /* If this happens to execute within the "virtually extended" vblank
+        * interval before the start of the real vblank interval then it needs
+        * to delay programming the mmio flip until the real vblank is entered.
+        * This prevents completing a flip too early due to the way we fudge
+        * our vblank counter and vblank timestamps in order to work around the
+        * problem that the hw fires vblank interrupts before actual start of
+        * vblank (when line buffer refilling is done for a frame). It
+        * complements the fudging logic in amdgpu_get_crtc_scanoutpos() for
+        * timestamping and amdgpu_get_vblank_counter_kms() for vblank counts.
+        *
+        * In practice this won't execute very often unless on very fast
+        * machines because the time window for this to happen is very small.
+        */
+       for (;;) {
+               /* GET_DISTANCE_TO_VBLANKSTART returns distance to real vblank
+                * start in hpos, and to the "fudged earlier" vblank start in
+                * vpos.
+                */
+               stat = amdgpu_get_crtc_scanoutpos(adev->ddev, work->crtc_id,
+                                                 GET_DISTANCE_TO_VBLANKSTART,
+                                                 &vpos, &hpos, NULL, NULL,
+                                                 &crtc->hwmode);
+
+               if ((stat & (DRM_SCANOUTPOS_VALID | DRM_SCANOUTPOS_ACCURATE)) !=
+                   (DRM_SCANOUTPOS_VALID | DRM_SCANOUTPOS_ACCURATE) ||
+                   !(vpos >= 0 && hpos <= 0))
+                       break;
+
+               /* Sleep at least until estimated real start of hw vblank */
+               spin_unlock_irqrestore(&crtc->dev->event_lock, flags);
+               min_udelay = (-hpos + 1) * max(vblank->linedur_ns / 1000, 5);
+               usleep_range(min_udelay, 2 * min_udelay);
+               spin_lock_irqsave(&crtc->dev->event_lock, flags);
+       };
+
        /* do the flip (mmio) */
        adev->mode_info.funcs->page_flip(adev, work->crtc_id, work->base);
        /* set the flip status */
@@ -109,7 +146,7 @@ static void amdgpu_unpin_work_func(struct work_struct *__work)
        } else
                DRM_ERROR("failed to reserve buffer after flip\n");
 
-       drm_gem_object_unreference_unlocked(&work->old_rbo->gem_base);
+       amdgpu_bo_unref(&work->old_rbo);
        kfree(work->shared);
        kfree(work);
 }
@@ -148,8 +185,8 @@ int amdgpu_crtc_page_flip(struct drm_crtc *crtc,
        obj = old_amdgpu_fb->obj;
 
        /* take a reference to the old object */
-       drm_gem_object_reference(obj);
        work->old_rbo = gem_to_amdgpu_bo(obj);
+       amdgpu_bo_ref(work->old_rbo);
 
        new_amdgpu_fb = to_amdgpu_framebuffer(fb);
        obj = new_amdgpu_fb->obj;
@@ -222,7 +259,7 @@ pflip_cleanup:
        amdgpu_bo_unreserve(new_rbo);
 
 cleanup:
-       drm_gem_object_unreference_unlocked(&work->old_rbo->gem_base);
+       amdgpu_bo_unref(&work->old_rbo);
        fence_put(work->excl);
        for (i = 0; i < work->shared_count; ++i)
                fence_put(work->shared[i]);
@@ -712,6 +749,15 @@ bool amdgpu_crtc_scaling_mode_fixup(struct drm_crtc *crtc,
  * \param dev Device to query.
  * \param pipe Crtc to query.
  * \param flags Flags from caller (DRM_CALLED_FROM_VBLIRQ or 0).
+ *              For driver internal use only also supports these flags:
+ *
+ *              USE_REAL_VBLANKSTART to use the real start of vblank instead
+ *              of a fudged earlier start of vblank.
+ *
+ *              GET_DISTANCE_TO_VBLANKSTART to return distance to the
+ *              fudged earlier start of vblank in *vpos and the distance
+ *              to true start of vblank in *hpos.
+ *
  * \param *vpos Location where vertical scanout position should be stored.
  * \param *hpos Location where horizontal scanout position should go.
  * \param *stime Target location for timestamp taken immediately before
@@ -776,10 +822,40 @@ int amdgpu_get_crtc_scanoutpos(struct drm_device *dev, unsigned int pipe,
                vbl_end = 0;
        }
 
+       /* Called from driver internal vblank counter query code? */
+       if (flags & GET_DISTANCE_TO_VBLANKSTART) {
+           /* Caller wants distance from real vbl_start in *hpos */
+           *hpos = *vpos - vbl_start;
+       }
+
+       /* Fudge vblank to start a few scanlines earlier to handle the
+        * problem that vblank irqs fire a few scanlines before start
+        * of vblank. Some driver internal callers need the true vblank
+        * start to be used and signal this via the USE_REAL_VBLANKSTART flag.
+        *
+        * The cause of the "early" vblank irq is that the irq is triggered
+        * by the line buffer logic when the line buffer read position enters
+        * the vblank, whereas our crtc scanout position naturally lags the
+        * line buffer read position.
+        */
+       if (!(flags & USE_REAL_VBLANKSTART))
+               vbl_start -= adev->mode_info.crtcs[pipe]->lb_vblank_lead_lines;
+
        /* Test scanout position against vblank region. */
        if ((*vpos < vbl_start) && (*vpos >= vbl_end))
                in_vbl = false;
 
+       /* In vblank? */
+       if (in_vbl)
+           ret |= DRM_SCANOUTPOS_IN_VBLANK;
+
+       /* Called from driver internal vblank counter query code? */
+       if (flags & GET_DISTANCE_TO_VBLANKSTART) {
+               /* Caller wants distance from fudged earlier vbl_start */
+               *vpos -= vbl_start;
+               return ret;
+       }
+
        /* Check if inside vblank area and apply corrective offsets:
         * vpos will then be >=0 in video scanout area, but negative
         * within vblank area, counting down the number of lines until
@@ -795,32 +871,6 @@ int amdgpu_get_crtc_scanoutpos(struct drm_device *dev, unsigned int pipe,
        /* Correct for shifted end of vbl at vbl_end. */
        *vpos = *vpos - vbl_end;
 
-       /* In vblank? */
-       if (in_vbl)
-               ret |= DRM_SCANOUTPOS_IN_VBLANK;
-
-       /* Is vpos outside nominal vblank area, but less than
-        * 1/100 of a frame height away from start of vblank?
-        * If so, assume this isn't a massively delayed vblank
-        * interrupt, but a vblank interrupt that fired a few
-        * microseconds before true start of vblank. Compensate
-        * by adding a full frame duration to the final timestamp.
-        * Happens, e.g., on ATI R500, R600.
-        *
-        * We only do this if DRM_CALLED_FROM_VBLIRQ.
-        */
-       if ((flags & DRM_CALLED_FROM_VBLIRQ) && !in_vbl) {
-               vbl_start = mode->crtc_vdisplay;
-               vtotal = mode->crtc_vtotal;
-
-               if (vbl_start - *vpos < vtotal / 100) {
-                       *vpos -= vtotal;
-
-                       /* Signal this correction as "applied". */
-                       ret |= 0x8;
-               }
-       }
-
        return ret;
 }
 
index 257d72205bb5c247d17f6d4ec6a79ea868d8e16d..3671f9f220bd47617d0cd3761543cedcae581d5e 100644 (file)
@@ -47,6 +47,9 @@
  * that the the relevant GPU caches have been flushed.
  */
 
+static struct kmem_cache *amdgpu_fence_slab;
+static atomic_t amdgpu_fence_slab_ref = ATOMIC_INIT(0);
+
 /**
  * amdgpu_fence_write - write a fence value
  *
@@ -84,24 +87,6 @@ static u32 amdgpu_fence_read(struct amdgpu_ring *ring)
        return seq;
 }
 
-/**
- * amdgpu_fence_schedule_check - schedule lockup check
- *
- * @ring: pointer to struct amdgpu_ring
- *
- * Queues a delayed work item to check for lockups.
- */
-static void amdgpu_fence_schedule_check(struct amdgpu_ring *ring)
-{
-       /*
-        * Do not reset the timer here with mod_delayed_work,
-        * this can livelock in an interaction with TTM delayed destroy.
-        */
-       queue_delayed_work(system_power_efficient_wq,
-               &ring->fence_drv.lockup_work,
-               AMDGPU_FENCE_JIFFIES_TIMEOUT);
-}
-
 /**
  * amdgpu_fence_emit - emit a fence on the requested ring
  *
@@ -118,7 +103,7 @@ int amdgpu_fence_emit(struct amdgpu_ring *ring, void *owner,
        struct amdgpu_device *adev = ring->adev;
 
        /* we are protected by the ring emission mutex */
-       *fence = kmalloc(sizeof(struct amdgpu_fence), GFP_KERNEL);
+       *fence = kmem_cache_alloc(amdgpu_fence_slab, GFP_KERNEL);
        if ((*fence) == NULL) {
                return -ENOMEM;
        }
@@ -132,10 +117,22 @@ int amdgpu_fence_emit(struct amdgpu_ring *ring, void *owner,
        amdgpu_ring_emit_fence(ring, ring->fence_drv.gpu_addr,
                               (*fence)->seq,
                               AMDGPU_FENCE_FLAG_INT);
-       trace_amdgpu_fence_emit(ring->adev->ddev, ring->idx, (*fence)->seq);
        return 0;
 }
 
+/**
+ * amdgpu_fence_schedule_fallback - schedule fallback check
+ *
+ * @ring: pointer to struct amdgpu_ring
+ *
+ * Start a timer as fallback to our interrupts.
+ */
+static void amdgpu_fence_schedule_fallback(struct amdgpu_ring *ring)
+{
+       mod_timer(&ring->fence_drv.fallback_timer,
+                 jiffies + AMDGPU_FENCE_JIFFIES_TIMEOUT);
+}
+
 /**
  * amdgpu_fence_activity - check for fence activity
  *
@@ -202,45 +199,38 @@ static bool amdgpu_fence_activity(struct amdgpu_ring *ring)
        } while (atomic64_xchg(&ring->fence_drv.last_seq, seq) > seq);
 
        if (seq < last_emitted)
-               amdgpu_fence_schedule_check(ring);
+               amdgpu_fence_schedule_fallback(ring);
 
        return wake;
 }
 
 /**
- * amdgpu_fence_check_lockup - check for hardware lockup
+ * amdgpu_fence_process - process a fence
  *
- * @work: delayed work item
+ * @adev: amdgpu_device pointer
+ * @ring: ring index the fence is associated with
  *
- * Checks for fence activity and if there is none probe
- * the hardware if a lockup occured.
+ * Checks the current fence value and wakes the fence queue
+ * if the sequence number has increased (all asics).
  */
-static void amdgpu_fence_check_lockup(struct work_struct *work)
+void amdgpu_fence_process(struct amdgpu_ring *ring)
 {
-       struct amdgpu_fence_driver *fence_drv;
-       struct amdgpu_ring *ring;
-
-       fence_drv = container_of(work, struct amdgpu_fence_driver,
-                               lockup_work.work);
-       ring = fence_drv->ring;
-
        if (amdgpu_fence_activity(ring))
                wake_up_all(&ring->fence_drv.fence_queue);
 }
 
 /**
- * amdgpu_fence_process - process a fence
+ * amdgpu_fence_fallback - fallback for hardware interrupts
  *
- * @adev: amdgpu_device pointer
- * @ring: ring index the fence is associated with
+ * @work: delayed work item
  *
- * Checks the current fence value and wakes the fence queue
- * if the sequence number has increased (all asics).
+ * Checks for fence activity.
  */
-void amdgpu_fence_process(struct amdgpu_ring *ring)
+static void amdgpu_fence_fallback(unsigned long arg)
 {
-       if (amdgpu_fence_activity(ring))
-               wake_up_all(&ring->fence_drv.fence_queue);
+       struct amdgpu_ring *ring = (void *)arg;
+
+       amdgpu_fence_process(ring);
 }
 
 /**
@@ -290,7 +280,7 @@ static int amdgpu_fence_ring_wait_seq(struct amdgpu_ring *ring, uint64_t seq)
        if (atomic64_read(&ring->fence_drv.last_seq) >= seq)
                return 0;
 
-       amdgpu_fence_schedule_check(ring);
+       amdgpu_fence_schedule_fallback(ring);
        wait_event(ring->fence_drv.fence_queue, (
                   (signaled = amdgpu_fence_seq_signaled(ring, seq))));
 
@@ -491,9 +481,8 @@ int amdgpu_fence_driver_init_ring(struct amdgpu_ring *ring)
        atomic64_set(&ring->fence_drv.last_seq, 0);
        ring->fence_drv.initialized = false;
 
-       INIT_DELAYED_WORK(&ring->fence_drv.lockup_work,
-                       amdgpu_fence_check_lockup);
-       ring->fence_drv.ring = ring;
+       setup_timer(&ring->fence_drv.fallback_timer, amdgpu_fence_fallback,
+                   (unsigned long)ring);
 
        init_waitqueue_head(&ring->fence_drv.fence_queue);
 
@@ -536,6 +525,13 @@ int amdgpu_fence_driver_init_ring(struct amdgpu_ring *ring)
  */
 int amdgpu_fence_driver_init(struct amdgpu_device *adev)
 {
+       if (atomic_inc_return(&amdgpu_fence_slab_ref) == 1) {
+               amdgpu_fence_slab = kmem_cache_create(
+                       "amdgpu_fence", sizeof(struct amdgpu_fence), 0,
+                       SLAB_HWCACHE_ALIGN, NULL);
+               if (!amdgpu_fence_slab)
+                       return -ENOMEM;
+       }
        if (amdgpu_debugfs_fence_init(adev))
                dev_err(adev->dev, "fence debugfs file creation failed\n");
 
@@ -554,9 +550,12 @@ void amdgpu_fence_driver_fini(struct amdgpu_device *adev)
 {
        int i, r;
 
+       if (atomic_dec_and_test(&amdgpu_fence_slab_ref))
+               kmem_cache_destroy(amdgpu_fence_slab);
        mutex_lock(&adev->ring_lock);
        for (i = 0; i < AMDGPU_MAX_RINGS; i++) {
                struct amdgpu_ring *ring = adev->rings[i];
+
                if (!ring || !ring->fence_drv.initialized)
                        continue;
                r = amdgpu_fence_wait_empty(ring);
@@ -568,6 +567,7 @@ void amdgpu_fence_driver_fini(struct amdgpu_device *adev)
                amdgpu_irq_put(adev, ring->fence_drv.irq_src,
                               ring->fence_drv.irq_type);
                amd_sched_fini(&ring->sched);
+               del_timer_sync(&ring->fence_drv.fallback_timer);
                ring->fence_drv.initialized = false;
        }
        mutex_unlock(&adev->ring_lock);
@@ -751,18 +751,25 @@ static bool amdgpu_fence_enable_signaling(struct fence *f)
        fence->fence_wake.func = amdgpu_fence_check_signaled;
        __add_wait_queue(&ring->fence_drv.fence_queue, &fence->fence_wake);
        fence_get(f);
-       amdgpu_fence_schedule_check(ring);
+       if (!timer_pending(&ring->fence_drv.fallback_timer))
+               amdgpu_fence_schedule_fallback(ring);
        FENCE_TRACE(&fence->base, "armed on ring %i!\n", ring->idx);
        return true;
 }
 
+static void amdgpu_fence_release(struct fence *f)
+{
+       struct amdgpu_fence *fence = to_amdgpu_fence(f);
+       kmem_cache_free(amdgpu_fence_slab, fence);
+}
+
 const struct fence_ops amdgpu_fence_ops = {
        .get_driver_name = amdgpu_fence_get_driver_name,
        .get_timeline_name = amdgpu_fence_get_timeline_name,
        .enable_signaling = amdgpu_fence_enable_signaling,
        .signaled = amdgpu_fence_is_signaled,
        .wait = fence_default_wait,
-       .release = NULL,
+       .release = amdgpu_fence_release,
 };
 
 /*
index 087332858853c81da5db0121af9254bdff1db1cb..9c253c535d26053ae80244a68617675c9b19fc3c 100644 (file)
@@ -115,12 +115,9 @@ int amdgpu_gem_object_open(struct drm_gem_object *obj, struct drm_file *file_pri
        struct amdgpu_vm *vm = &fpriv->vm;
        struct amdgpu_bo_va *bo_va;
        int r;
-       mutex_lock(&vm->mutex);
        r = amdgpu_bo_reserve(rbo, false);
-       if (r) {
-               mutex_unlock(&vm->mutex);
+       if (r)
                return r;
-       }
 
        bo_va = amdgpu_vm_bo_find(vm, rbo);
        if (!bo_va) {
@@ -129,7 +126,6 @@ int amdgpu_gem_object_open(struct drm_gem_object *obj, struct drm_file *file_pri
                ++bo_va->ref_count;
        }
        amdgpu_bo_unreserve(rbo);
-       mutex_unlock(&vm->mutex);
        return 0;
 }
 
@@ -142,10 +138,8 @@ void amdgpu_gem_object_close(struct drm_gem_object *obj,
        struct amdgpu_vm *vm = &fpriv->vm;
        struct amdgpu_bo_va *bo_va;
        int r;
-       mutex_lock(&vm->mutex);
        r = amdgpu_bo_reserve(rbo, true);
        if (r) {
-               mutex_unlock(&vm->mutex);
                dev_err(adev->dev, "leaking bo va because "
                        "we fail to reserve bo (%d)\n", r);
                return;
@@ -157,7 +151,6 @@ void amdgpu_gem_object_close(struct drm_gem_object *obj,
                }
        }
        amdgpu_bo_unreserve(rbo);
-       mutex_unlock(&vm->mutex);
 }
 
 static int amdgpu_gem_handle_lockup(struct amdgpu_device *adev, int r)
@@ -242,8 +235,9 @@ int amdgpu_gem_userptr_ioctl(struct drm_device *dev, void *data,
            AMDGPU_GEM_USERPTR_REGISTER))
                return -EINVAL;
 
-       if (!(args->flags & AMDGPU_GEM_USERPTR_ANONONLY) ||
-                  !(args->flags & AMDGPU_GEM_USERPTR_REGISTER)) {
+       if (!(args->flags & AMDGPU_GEM_USERPTR_READONLY) && (
+            !(args->flags & AMDGPU_GEM_USERPTR_ANONONLY) ||
+            !(args->flags & AMDGPU_GEM_USERPTR_REGISTER))) {
 
                /* if we want to write to it we must require anonymous
                   memory and install a MMU notifier */
@@ -483,6 +477,17 @@ static void amdgpu_gem_va_update_vm(struct amdgpu_device *adev,
                if (domain == AMDGPU_GEM_DOMAIN_CPU)
                        goto error_unreserve;
        }
+       list_for_each_entry(entry, &duplicates, head) {
+               domain = amdgpu_mem_type_to_domain(entry->bo->mem.mem_type);
+               /* if anything is swapped out don't swap it in here,
+                  just abort and wait for the next CS */
+               if (domain == AMDGPU_GEM_DOMAIN_CPU)
+                       goto error_unreserve;
+       }
+
+       r = amdgpu_vm_update_page_directory(adev, bo_va->vm);
+       if (r)
+               goto error_unreserve;
 
        r = amdgpu_vm_clear_freed(adev, bo_va->vm);
        if (r)
@@ -512,6 +517,9 @@ int amdgpu_gem_va_ioctl(struct drm_device *dev, void *data,
        struct amdgpu_fpriv *fpriv = filp->driver_priv;
        struct amdgpu_bo *rbo;
        struct amdgpu_bo_va *bo_va;
+       struct ttm_validate_buffer tv, tv_pd;
+       struct ww_acquire_ctx ticket;
+       struct list_head list, duplicates;
        uint32_t invalid_flags, va_flags = 0;
        int r = 0;
 
@@ -547,19 +555,28 @@ int amdgpu_gem_va_ioctl(struct drm_device *dev, void *data,
        gobj = drm_gem_object_lookup(dev, filp, args->handle);
        if (gobj == NULL)
                return -ENOENT;
-       mutex_lock(&fpriv->vm.mutex);
        rbo = gem_to_amdgpu_bo(gobj);
-       r = amdgpu_bo_reserve(rbo, false);
+       INIT_LIST_HEAD(&list);
+       INIT_LIST_HEAD(&duplicates);
+       tv.bo = &rbo->tbo;
+       tv.shared = true;
+       list_add(&tv.head, &list);
+
+       if (args->operation == AMDGPU_VA_OP_MAP) {
+               tv_pd.bo = &fpriv->vm.page_directory->tbo;
+               tv_pd.shared = true;
+               list_add(&tv_pd.head, &list);
+       }
+       r = ttm_eu_reserve_buffers(&ticket, &list, true, &duplicates);
        if (r) {
-               mutex_unlock(&fpriv->vm.mutex);
                drm_gem_object_unreference_unlocked(gobj);
                return r;
        }
 
        bo_va = amdgpu_vm_bo_find(&fpriv->vm, rbo);
        if (!bo_va) {
-               amdgpu_bo_unreserve(rbo);
-               mutex_unlock(&fpriv->vm.mutex);
+               ttm_eu_backoff_reservation(&ticket, &list);
+               drm_gem_object_unreference_unlocked(gobj);
                return -ENOENT;
        }
 
@@ -581,10 +598,10 @@ int amdgpu_gem_va_ioctl(struct drm_device *dev, void *data,
        default:
                break;
        }
-
+       ttm_eu_backoff_reservation(&ticket, &list);
        if (!r && !(args->flags & AMDGPU_VM_DELAY_UPDATE))
                amdgpu_gem_va_update_vm(adev, bo_va, args->operation);
-       mutex_unlock(&fpriv->vm.mutex);
+
        drm_gem_object_unreference_unlocked(gobj);
        return r;
 }
index e65987743871b18bb521113d86e0245c50686b57..9e25edafa7210000d1bfad1959f82725228e91df 100644 (file)
@@ -62,7 +62,7 @@ int amdgpu_ib_get(struct amdgpu_ring *ring, struct amdgpu_vm *vm,
        int r;
 
        if (size) {
-               r = amdgpu_sa_bo_new(adev, &adev->ring_tmp_bo,
+               r = amdgpu_sa_bo_new(&adev->ring_tmp_bo,
                                      &ib->sa_bo, size, 256);
                if (r) {
                        dev_err(adev->dev, "failed to get a new IB (%d)\n", r);
@@ -216,7 +216,7 @@ int amdgpu_ib_schedule(struct amdgpu_device *adev, unsigned num_ibs,
        }
 
        if (ib->vm)
-               amdgpu_vm_fence(adev, ib->vm, ib->fence);
+               amdgpu_vm_fence(adev, ib->vm, &ib->fence->base);
 
        amdgpu_ring_unlock_commit(ring);
        return 0;
index 1618e2294a16056171458998ed65e62a83583774..e23843f4d877be7813a1574db0f855847f9aa591 100644 (file)
@@ -611,13 +611,59 @@ void amdgpu_driver_preclose_kms(struct drm_device *dev,
 u32 amdgpu_get_vblank_counter_kms(struct drm_device *dev, unsigned int pipe)
 {
        struct amdgpu_device *adev = dev->dev_private;
+       int vpos, hpos, stat;
+       u32 count;
 
        if (pipe >= adev->mode_info.num_crtc) {
                DRM_ERROR("Invalid crtc %u\n", pipe);
                return -EINVAL;
        }
 
-       return amdgpu_display_vblank_get_counter(adev, pipe);
+       /* The hw increments its frame counter at start of vsync, not at start
+        * of vblank, as is required by DRM core vblank counter handling.
+        * Cook the hw count here to make it appear to the caller as if it
+        * incremented at start of vblank. We measure distance to start of
+        * vblank in vpos. vpos therefore will be >= 0 between start of vblank
+        * and start of vsync, so vpos >= 0 means to bump the hw frame counter
+        * result by 1 to give the proper appearance to caller.
+        */
+       if (adev->mode_info.crtcs[pipe]) {
+               /* Repeat readout if needed to provide stable result if
+                * we cross start of vsync during the queries.
+                */
+               do {
+                       count = amdgpu_display_vblank_get_counter(adev, pipe);
+                       /* Ask amdgpu_get_crtc_scanoutpos to return vpos as
+                        * distance to start of vblank, instead of regular
+                        * vertical scanout pos.
+                        */
+                       stat = amdgpu_get_crtc_scanoutpos(
+                               dev, pipe, GET_DISTANCE_TO_VBLANKSTART,
+                               &vpos, &hpos, NULL, NULL,
+                               &adev->mode_info.crtcs[pipe]->base.hwmode);
+               } while (count != amdgpu_display_vblank_get_counter(adev, pipe));
+
+               if (((stat & (DRM_SCANOUTPOS_VALID | DRM_SCANOUTPOS_ACCURATE)) !=
+                   (DRM_SCANOUTPOS_VALID | DRM_SCANOUTPOS_ACCURATE))) {
+                       DRM_DEBUG_VBL("Query failed! stat %d\n", stat);
+               } else {
+                       DRM_DEBUG_VBL("crtc %d: dist from vblank start %d\n",
+                                     pipe, vpos);
+
+                       /* Bump counter if we are at >= leading edge of vblank,
+                        * but before vsync where vpos would turn negative and
+                        * the hw counter really increments.
+                        */
+                       if (vpos >= 0)
+                               count++;
+               }
+       } else {
+               /* Fallback to use value as is. */
+               count = amdgpu_display_vblank_get_counter(adev, pipe);
+               DRM_DEBUG_VBL("NULL mode info! Returned count may be wrong.\n");
+       }
+
+       return count;
 }
 
 /**
index b62c1710cab6b0fc00e33013ad741c97f9583ed2..064ebb3470748619e0b43ff7bfe2671a58c50bbd 100644 (file)
@@ -407,6 +407,7 @@ struct amdgpu_crtc {
        u32 line_time;
        u32 wm_low;
        u32 wm_high;
+       u32 lb_vblank_lead_lines;
        struct drm_display_mode hw_mode;
 };
 
@@ -528,6 +529,10 @@ struct amdgpu_framebuffer {
 #define ENCODER_MODE_IS_DP(em) (((em) == ATOM_ENCODER_MODE_DP) || \
                                ((em) == ATOM_ENCODER_MODE_DP_MST))
 
+/* Driver internal use only flags of amdgpu_get_crtc_scanoutpos() */
+#define USE_REAL_VBLANKSTART           (1 << 30)
+#define GET_DISTANCE_TO_VBLANKSTART    (1 << 31)
+
 void amdgpu_link_encoder_connector(struct drm_device *dev);
 
 struct drm_connector *
index 0d524384ff79c3b49d2dbaa1489d8cbff231d80a..c3ce103b6a33b2ef3a0a6f7f14877e18150ca405 100644 (file)
@@ -100,6 +100,7 @@ static void amdgpu_ttm_bo_destroy(struct ttm_buffer_object *tbo)
        list_del_init(&bo->list);
        mutex_unlock(&bo->adev->gem.mutex);
        drm_gem_object_release(&bo->gem_base);
+       amdgpu_bo_unref(&bo->parent);
        kfree(bo->metadata);
        kfree(bo);
 }
index 3c2ff4567798e1675adfb7a4563e4bd8931f0565..ea756e77b0232bcc131a90258b4ea454e1bc92e1 100644 (file)
@@ -189,10 +189,9 @@ int amdgpu_sa_bo_manager_start(struct amdgpu_device *adev,
                                      struct amdgpu_sa_manager *sa_manager);
 int amdgpu_sa_bo_manager_suspend(struct amdgpu_device *adev,
                                        struct amdgpu_sa_manager *sa_manager);
-int amdgpu_sa_bo_new(struct amdgpu_device *adev,
-                           struct amdgpu_sa_manager *sa_manager,
-                           struct amdgpu_sa_bo **sa_bo,
-                           unsigned size, unsigned align);
+int amdgpu_sa_bo_new(struct amdgpu_sa_manager *sa_manager,
+                    struct amdgpu_sa_bo **sa_bo,
+                    unsigned size, unsigned align);
 void amdgpu_sa_bo_free(struct amdgpu_device *adev,
                              struct amdgpu_sa_bo **sa_bo,
                              struct fence *fence);
index 0212b31dc194ba542f8f009113d15c027aba0026..8b88edb0434bfb43ed4b7aae7e6f3e7dc63d0893 100644 (file)
@@ -311,8 +311,7 @@ static bool amdgpu_sa_bo_next_hole(struct amdgpu_sa_manager *sa_manager,
        return false;
 }
 
-int amdgpu_sa_bo_new(struct amdgpu_device *adev,
-                    struct amdgpu_sa_manager *sa_manager,
+int amdgpu_sa_bo_new(struct amdgpu_sa_manager *sa_manager,
                     struct amdgpu_sa_bo **sa_bo,
                     unsigned size, unsigned align)
 {
index dcf4a8aca680d885fc6a52414ca2c8e5e3bd0914..438c05254695586bb95a9e3caa2ea356aa4b941f 100644 (file)
@@ -26,6 +26,7 @@
 #include <linux/sched.h>
 #include <drm/drmP.h>
 #include "amdgpu.h"
+#include "amdgpu_trace.h"
 
 static struct fence *amdgpu_sched_dependency(struct amd_sched_job *sched_job)
 {
@@ -44,11 +45,8 @@ static struct fence *amdgpu_sched_run_job(struct amd_sched_job *sched_job)
                return NULL;
        }
        job = to_amdgpu_job(sched_job);
-       mutex_lock(&job->job_lock);
-       r = amdgpu_ib_schedule(job->adev,
-                              job->num_ibs,
-                              job->ibs,
-                              job->base.owner);
+       trace_amdgpu_sched_run_job(job);
+       r = amdgpu_ib_schedule(job->adev, job->num_ibs, job->ibs, job->owner);
        if (r) {
                DRM_ERROR("Error scheduling IBs (%d)\n", r);
                goto err;
@@ -61,8 +59,6 @@ err:
        if (job->free_job)
                job->free_job(job);
 
-       mutex_unlock(&job->job_lock);
-       fence_put(&job->base.s_fence->base);
        kfree(job);
        return fence ? &fence->base : NULL;
 }
@@ -88,21 +84,19 @@ int amdgpu_sched_ib_submit_kernel_helper(struct amdgpu_device *adev,
                        return -ENOMEM;
                job->base.sched = &ring->sched;
                job->base.s_entity = &adev->kernel_ctx.rings[ring->idx].entity;
+               job->base.s_fence = amd_sched_fence_create(job->base.s_entity, owner);
+               if (!job->base.s_fence) {
+                       kfree(job);
+                       return -ENOMEM;
+               }
+               *f = fence_get(&job->base.s_fence->base);
+
                job->adev = adev;
                job->ibs = ibs;
                job->num_ibs = num_ibs;
-               job->base.owner = owner;
-               mutex_init(&job->job_lock);
+               job->owner = owner;
                job->free_job = free_job;
-               mutex_lock(&job->job_lock);
-               r = amd_sched_entity_push_job(&job->base);
-               if (r) {
-                       mutex_unlock(&job->job_lock);
-                       kfree(job);
-                       return r;
-               }
-               *f = fence_get(&job->base.s_fence->base);
-               mutex_unlock(&job->job_lock);
+               amd_sched_entity_push_job(&job->base);
        } else {
                r = amdgpu_ib_schedule(adev, num_ibs, ibs, owner);
                if (r)
index ff3ca52ec6fe5543ea85ed4a31e2c2dc2538a83f..1caaf201b708a0487db721fc5bb9b341370d26df 100644 (file)
@@ -40,7 +40,7 @@ int amdgpu_semaphore_create(struct amdgpu_device *adev,
        if (*semaphore == NULL) {
                return -ENOMEM;
        }
-       r = amdgpu_sa_bo_new(adev, &adev->ring_tmp_bo,
+       r = amdgpu_sa_bo_new(&adev->ring_tmp_bo,
                             &(*semaphore)->sa_bo, 8, 8);
        if (r) {
                kfree(*semaphore);
index a6697fd0521713cd9f60cbd7a2508b02e954b470..dd005c336c974ad708827c25edc4a4534772bb2c 100644 (file)
@@ -302,8 +302,14 @@ int amdgpu_sync_rings(struct amdgpu_sync *sync,
                        return -EINVAL;
                }
 
-               if (amdgpu_enable_scheduler || !amdgpu_enable_semaphores ||
-                   (count >= AMDGPU_NUM_SYNCS)) {
+               if (amdgpu_enable_scheduler || !amdgpu_enable_semaphores) {
+                       r = fence_wait(&fence->base, true);
+                       if (r)
+                               return r;
+                       continue;
+               }
+
+               if (count >= AMDGPU_NUM_SYNCS) {
                        /* not enough room, wait manually */
                        r = fence_wait(&fence->base, false);
                        if (r)
index 76ecbaf72a2e81bf70d12f63c1ca9c7517fdf3e6..8f9834ab1bd5a6ad2e0908dfeb0aa6ff5206fc31 100644 (file)
@@ -48,6 +48,57 @@ TRACE_EVENT(amdgpu_cs,
                      __entry->fences)
 );
 
+TRACE_EVENT(amdgpu_cs_ioctl,
+           TP_PROTO(struct amdgpu_job *job),
+           TP_ARGS(job),
+           TP_STRUCT__entry(
+                            __field(struct amdgpu_device *, adev)
+                            __field(struct amd_sched_job *, sched_job)
+                            __field(struct amdgpu_ib *, ib)
+                            __field(struct fence *, fence)
+                            __field(char *, ring_name)
+                            __field(u32, num_ibs)
+                            ),
+
+           TP_fast_assign(
+                          __entry->adev = job->adev;
+                          __entry->sched_job = &job->base;
+                          __entry->ib = job->ibs;
+                          __entry->fence = &job->base.s_fence->base;
+                          __entry->ring_name = job->ibs[0].ring->name;
+                          __entry->num_ibs = job->num_ibs;
+                          ),
+           TP_printk("adev=%p, sched_job=%p, first ib=%p, sched fence=%p, ring name:%s, num_ibs:%u",
+                     __entry->adev, __entry->sched_job, __entry->ib,
+                     __entry->fence, __entry->ring_name, __entry->num_ibs)
+);
+
+TRACE_EVENT(amdgpu_sched_run_job,
+           TP_PROTO(struct amdgpu_job *job),
+           TP_ARGS(job),
+           TP_STRUCT__entry(
+                            __field(struct amdgpu_device *, adev)
+                            __field(struct amd_sched_job *, sched_job)
+                            __field(struct amdgpu_ib *, ib)
+                            __field(struct fence *, fence)
+                            __field(char *, ring_name)
+                            __field(u32, num_ibs)
+                            ),
+
+           TP_fast_assign(
+                          __entry->adev = job->adev;
+                          __entry->sched_job = &job->base;
+                          __entry->ib = job->ibs;
+                          __entry->fence = &job->base.s_fence->base;
+                          __entry->ring_name = job->ibs[0].ring->name;
+                          __entry->num_ibs = job->num_ibs;
+                          ),
+           TP_printk("adev=%p, sched_job=%p, first ib=%p, sched fence=%p, ring name:%s, num_ibs:%u",
+                     __entry->adev, __entry->sched_job, __entry->ib,
+                     __entry->fence, __entry->ring_name, __entry->num_ibs)
+);
+
+
 TRACE_EVENT(amdgpu_vm_grab_id,
            TP_PROTO(unsigned vmid, int ring),
            TP_ARGS(vmid, ring),
@@ -196,49 +247,6 @@ TRACE_EVENT(amdgpu_bo_list_set,
            TP_printk("list=%p, bo=%p", __entry->list, __entry->bo)
 );
 
-DECLARE_EVENT_CLASS(amdgpu_fence_request,
-
-           TP_PROTO(struct drm_device *dev, int ring, u32 seqno),
-
-           TP_ARGS(dev, ring, seqno),
-
-           TP_STRUCT__entry(
-                            __field(u32, dev)
-                            __field(int, ring)
-                            __field(u32, seqno)
-                            ),
-
-           TP_fast_assign(
-                          __entry->dev = dev->primary->index;
-                          __entry->ring = ring;
-                          __entry->seqno = seqno;
-                          ),
-
-           TP_printk("dev=%u, ring=%d, seqno=%u",
-                     __entry->dev, __entry->ring, __entry->seqno)
-);
-
-DEFINE_EVENT(amdgpu_fence_request, amdgpu_fence_emit,
-
-           TP_PROTO(struct drm_device *dev, int ring, u32 seqno),
-
-           TP_ARGS(dev, ring, seqno)
-);
-
-DEFINE_EVENT(amdgpu_fence_request, amdgpu_fence_wait_begin,
-
-           TP_PROTO(struct drm_device *dev, int ring, u32 seqno),
-
-           TP_ARGS(dev, ring, seqno)
-);
-
-DEFINE_EVENT(amdgpu_fence_request, amdgpu_fence_wait_end,
-
-           TP_PROTO(struct drm_device *dev, int ring, u32 seqno),
-
-           TP_ARGS(dev, ring, seqno)
-);
-
 DECLARE_EVENT_CLASS(amdgpu_semaphore_request,
 
            TP_PROTO(int ring, struct amdgpu_semaphore *sem),
index 81bb8e9fc26dc2accddd19355d81461712420ef8..8a1752ff3d8e55a1d8b8ab3061f5c9c425058d0f 100644 (file)
@@ -587,9 +587,13 @@ static int amdgpu_ttm_backend_bind(struct ttm_tt *ttm,
        uint32_t flags = amdgpu_ttm_tt_pte_flags(gtt->adev, ttm, bo_mem);
        int r;
 
-       if (gtt->userptr)
-               amdgpu_ttm_tt_pin_userptr(ttm);
-
+       if (gtt->userptr) {
+               r = amdgpu_ttm_tt_pin_userptr(ttm);
+               if (r) {
+                       DRM_ERROR("failed to pin userptr\n");
+                       return r;
+               }
+       }
        gtt->offset = (unsigned long)(bo_mem->start << PAGE_SHIFT);
        if (!ttm->num_pages) {
                WARN(1, "nothing to bind %lu pages for mreg %p back %p!\n",
@@ -797,11 +801,12 @@ uint32_t amdgpu_ttm_tt_pte_flags(struct amdgpu_device *adev, struct ttm_tt *ttm,
        if (mem && mem->mem_type != TTM_PL_SYSTEM)
                flags |= AMDGPU_PTE_VALID;
 
-       if (mem && mem->mem_type == TTM_PL_TT)
+       if (mem && mem->mem_type == TTM_PL_TT) {
                flags |= AMDGPU_PTE_SYSTEM;
 
-       if (!ttm || ttm->caching_state == tt_cached)
-               flags |= AMDGPU_PTE_SNOOPED;
+               if (ttm->caching_state == tt_cached)
+                       flags |= AMDGPU_PTE_SNOOPED;
+       }
 
        if (adev->asic_type >= CHIP_TOPAZ)
                flags |= AMDGPU_PTE_EXECUTABLE;
@@ -1073,10 +1078,10 @@ static int amdgpu_mm_dump_table(struct seq_file *m, void *data)
        ret = drm_mm_dump_table(m, mm);
        spin_unlock(&glob->lru_lock);
        if (ttm_pl == TTM_PL_VRAM)
-               seq_printf(m, "man size:%llu pages, ram usage:%luMB, vis usage:%luMB\n",
+               seq_printf(m, "man size:%llu pages, ram usage:%lluMB, vis usage:%lluMB\n",
                           adev->mman.bdev.man[ttm_pl].size,
-                          atomic64_read(&adev->vram_usage) >> 20,
-                          atomic64_read(&adev->vram_vis_usage) >> 20);
+                          (u64)atomic64_read(&adev->vram_usage) >> 20,
+                          (u64)atomic64_read(&adev->vram_vis_usage) >> 20);
        return ret;
 }
 
index 03f0c3bae516899aa81ac9b5d4dc6a9c7c1d9660..a745eeeb5d8200f6b92e259c655b10b658c4cad5 100644 (file)
@@ -392,7 +392,10 @@ int amdgpu_vce_get_create_msg(struct amdgpu_ring *ring, uint32_t handle,
        ib->ptr[ib->length_dw++] = 0x00000001; /* session cmd */
        ib->ptr[ib->length_dw++] = handle;
 
-       ib->ptr[ib->length_dw++] = 0x00000030; /* len */
+       if ((ring->adev->vce.fw_version >> 24) >= 52)
+               ib->ptr[ib->length_dw++] = 0x00000040; /* len */
+       else
+               ib->ptr[ib->length_dw++] = 0x00000030; /* len */
        ib->ptr[ib->length_dw++] = 0x01000001; /* create cmd */
        ib->ptr[ib->length_dw++] = 0x00000000;
        ib->ptr[ib->length_dw++] = 0x00000042;
@@ -404,6 +407,12 @@ int amdgpu_vce_get_create_msg(struct amdgpu_ring *ring, uint32_t handle,
        ib->ptr[ib->length_dw++] = 0x00000100;
        ib->ptr[ib->length_dw++] = 0x0000000c;
        ib->ptr[ib->length_dw++] = 0x00000000;
+       if ((ring->adev->vce.fw_version >> 24) >= 52) {
+               ib->ptr[ib->length_dw++] = 0x00000000;
+               ib->ptr[ib->length_dw++] = 0x00000000;
+               ib->ptr[ib->length_dw++] = 0x00000000;
+               ib->ptr[ib->length_dw++] = 0x00000000;
+       }
 
        ib->ptr[ib->length_dw++] = 0x00000014; /* len */
        ib->ptr[ib->length_dw++] = 0x05000005; /* feedback buffer */
index 633a32a48560ec448a90475797fd1652b589dee7..b53d273eb7a1003a719fff9d1bd32a8b4fa20b78 100644 (file)
@@ -143,10 +143,15 @@ int amdgpu_vm_grab_id(struct amdgpu_vm *vm, struct amdgpu_ring *ring,
        unsigned i;
 
        /* check if the id is still valid */
-       if (vm_id->id && vm_id->last_id_use &&
-           vm_id->last_id_use == adev->vm_manager.active[vm_id->id]) {
-               trace_amdgpu_vm_grab_id(vm_id->id, ring->idx);
-               return 0;
+       if (vm_id->id) {
+               unsigned id = vm_id->id;
+               long owner;
+
+               owner = atomic_long_read(&adev->vm_manager.ids[id].owner);
+               if (owner == (long)vm) {
+                       trace_amdgpu_vm_grab_id(vm_id->id, ring->idx);
+                       return 0;
+               }
        }
 
        /* we definately need to flush */
@@ -154,7 +159,7 @@ int amdgpu_vm_grab_id(struct amdgpu_vm *vm, struct amdgpu_ring *ring,
 
        /* skip over VMID 0, since it is the system VM */
        for (i = 1; i < adev->vm_manager.nvm; ++i) {
-               struct fence *fence = adev->vm_manager.active[i];
+               struct fence *fence = adev->vm_manager.ids[i].active;
                struct amdgpu_ring *fring;
 
                if (fence == NULL) {
@@ -176,7 +181,7 @@ int amdgpu_vm_grab_id(struct amdgpu_vm *vm, struct amdgpu_ring *ring,
                if (choices[i]) {
                        struct fence *fence;
 
-                       fence  = adev->vm_manager.active[choices[i]];
+                       fence  = adev->vm_manager.ids[choices[i]].active;
                        vm_id->id = choices[i];
 
                        trace_amdgpu_vm_grab_id(choices[i], ring->idx);
@@ -207,24 +212,21 @@ void amdgpu_vm_flush(struct amdgpu_ring *ring,
        uint64_t pd_addr = amdgpu_bo_gpu_offset(vm->page_directory);
        struct amdgpu_vm_id *vm_id = &vm->ids[ring->idx];
        struct fence *flushed_updates = vm_id->flushed_updates;
-       bool is_earlier = false;
+       bool is_later;
 
-       if (flushed_updates && updates) {
-               BUG_ON(flushed_updates->context != updates->context);
-               is_earlier = (updates->seqno - flushed_updates->seqno <=
-                             INT_MAX) ? true : false;
-       }
-
-       if (pd_addr != vm_id->pd_gpu_addr || !flushed_updates ||
-           is_earlier) {
+       if (!flushed_updates)
+               is_later = true;
+       else if (!updates)
+               is_later = false;
+       else
+               is_later = fence_is_later(updates, flushed_updates);
 
+       if (pd_addr != vm_id->pd_gpu_addr || is_later) {
                trace_amdgpu_vm_flush(pd_addr, ring->idx, vm_id->id);
-               if (is_earlier) {
+               if (is_later) {
                        vm_id->flushed_updates = fence_get(updates);
                        fence_put(flushed_updates);
                }
-               if (!flushed_updates)
-                       vm_id->flushed_updates = fence_get(updates);
                vm_id->pd_gpu_addr = pd_addr;
                amdgpu_ring_emit_vm_flush(ring, vm_id->id, vm_id->pd_gpu_addr);
        }
@@ -244,16 +246,14 @@ void amdgpu_vm_flush(struct amdgpu_ring *ring,
  */
 void amdgpu_vm_fence(struct amdgpu_device *adev,
                     struct amdgpu_vm *vm,
-                    struct amdgpu_fence *fence)
+                    struct fence *fence)
 {
-       unsigned ridx = fence->ring->idx;
-       unsigned vm_id = vm->ids[ridx].id;
-
-       fence_put(adev->vm_manager.active[vm_id]);
-       adev->vm_manager.active[vm_id] = fence_get(&fence->base);
+       struct amdgpu_ring *ring = amdgpu_ring_from_fence(fence);
+       unsigned vm_id = vm->ids[ring->idx].id;
 
-       fence_put(vm->ids[ridx].last_id_use);
-       vm->ids[ridx].last_id_use = fence_get(&fence->base);
+       fence_put(adev->vm_manager.ids[vm_id].active);
+       adev->vm_manager.ids[vm_id].active = fence_get(fence);
+       atomic_long_set(&adev->vm_manager.ids[vm_id].owner, (long)vm);
 }
 
 /**
@@ -332,6 +332,8 @@ int amdgpu_vm_free_job(struct amdgpu_job *job)
  *
  * @adev: amdgpu_device pointer
  * @bo: bo to clear
+ *
+ * need to reserve bo first before calling it.
  */
 static int amdgpu_vm_clear_bo(struct amdgpu_device *adev,
                              struct amdgpu_bo *bo)
@@ -343,24 +345,20 @@ static int amdgpu_vm_clear_bo(struct amdgpu_device *adev,
        uint64_t addr;
        int r;
 
-       r = amdgpu_bo_reserve(bo, false);
-       if (r)
-               return r;
-
        r = reservation_object_reserve_shared(bo->tbo.resv);
        if (r)
                return r;
 
        r = ttm_bo_validate(&bo->tbo, &bo->placement, true, false);
        if (r)
-               goto error_unreserve;
+               goto error;
 
        addr = amdgpu_bo_gpu_offset(bo);
        entries = amdgpu_bo_size(bo) / 8;
 
        ib = kzalloc(sizeof(struct amdgpu_ib), GFP_KERNEL);
        if (!ib)
-               goto error_unreserve;
+               goto error;
 
        r = amdgpu_ib_get(ring, NULL, entries * 2 + 64, ib);
        if (r)
@@ -378,16 +376,14 @@ static int amdgpu_vm_clear_bo(struct amdgpu_device *adev,
        if (!r)
                amdgpu_bo_fence(bo, fence, true);
        fence_put(fence);
-       if (amdgpu_enable_scheduler) {
-               amdgpu_bo_unreserve(bo);
+       if (amdgpu_enable_scheduler)
                return 0;
-       }
+
 error_free:
        amdgpu_ib_free(adev, ib);
        kfree(ib);
 
-error_unreserve:
-       amdgpu_bo_unreserve(bo);
+error:
        return r;
 }
 
@@ -889,17 +885,21 @@ int amdgpu_vm_clear_freed(struct amdgpu_device *adev,
        struct amdgpu_bo_va_mapping *mapping;
        int r;
 
+       spin_lock(&vm->freed_lock);
        while (!list_empty(&vm->freed)) {
                mapping = list_first_entry(&vm->freed,
                        struct amdgpu_bo_va_mapping, list);
                list_del(&mapping->list);
-
+               spin_unlock(&vm->freed_lock);
                r = amdgpu_vm_bo_update_mapping(adev, vm, mapping, 0, 0, NULL);
                kfree(mapping);
                if (r)
                        return r;
 
+               spin_lock(&vm->freed_lock);
        }
+       spin_unlock(&vm->freed_lock);
+
        return 0;
 
 }
@@ -926,8 +926,9 @@ int amdgpu_vm_clear_invalids(struct amdgpu_device *adev,
                bo_va = list_first_entry(&vm->invalidated,
                        struct amdgpu_bo_va, vm_status);
                spin_unlock(&vm->status_lock);
-
+               mutex_lock(&bo_va->mutex);
                r = amdgpu_vm_bo_update(adev, bo_va, NULL);
+               mutex_unlock(&bo_va->mutex);
                if (r)
                        return r;
 
@@ -971,7 +972,7 @@ struct amdgpu_bo_va *amdgpu_vm_bo_add(struct amdgpu_device *adev,
        INIT_LIST_HEAD(&bo_va->valids);
        INIT_LIST_HEAD(&bo_va->invalids);
        INIT_LIST_HEAD(&bo_va->vm_status);
-
+       mutex_init(&bo_va->mutex);
        list_add_tail(&bo_va->bo_list, &bo->va);
 
        return bo_va;
@@ -989,7 +990,7 @@ struct amdgpu_bo_va *amdgpu_vm_bo_add(struct amdgpu_device *adev,
  * Add a mapping of the BO at the specefied addr into the VM.
  * Returns 0 for success, error for failure.
  *
- * Object has to be reserved and gets unreserved by this function!
+ * Object has to be reserved and unreserved outside!
  */
 int amdgpu_vm_bo_map(struct amdgpu_device *adev,
                     struct amdgpu_bo_va *bo_va,
@@ -1005,30 +1006,27 @@ int amdgpu_vm_bo_map(struct amdgpu_device *adev,
 
        /* validate the parameters */
        if (saddr & AMDGPU_GPU_PAGE_MASK || offset & AMDGPU_GPU_PAGE_MASK ||
-           size == 0 || size & AMDGPU_GPU_PAGE_MASK) {
-               amdgpu_bo_unreserve(bo_va->bo);
+           size == 0 || size & AMDGPU_GPU_PAGE_MASK)
                return -EINVAL;
-       }
 
        /* make sure object fit at this offset */
        eaddr = saddr + size;
-       if ((saddr >= eaddr) || (offset + size > amdgpu_bo_size(bo_va->bo))) {
-               amdgpu_bo_unreserve(bo_va->bo);
+       if ((saddr >= eaddr) || (offset + size > amdgpu_bo_size(bo_va->bo)))
                return -EINVAL;
-       }
 
        last_pfn = eaddr / AMDGPU_GPU_PAGE_SIZE;
        if (last_pfn > adev->vm_manager.max_pfn) {
                dev_err(adev->dev, "va above limit (0x%08X > 0x%08X)\n",
                        last_pfn, adev->vm_manager.max_pfn);
-               amdgpu_bo_unreserve(bo_va->bo);
                return -EINVAL;
        }
 
        saddr /= AMDGPU_GPU_PAGE_SIZE;
        eaddr /= AMDGPU_GPU_PAGE_SIZE;
 
+       spin_lock(&vm->it_lock);
        it = interval_tree_iter_first(&vm->va, saddr, eaddr - 1);
+       spin_unlock(&vm->it_lock);
        if (it) {
                struct amdgpu_bo_va_mapping *tmp;
                tmp = container_of(it, struct amdgpu_bo_va_mapping, it);
@@ -1036,14 +1034,12 @@ int amdgpu_vm_bo_map(struct amdgpu_device *adev,
                dev_err(adev->dev, "bo %p va 0x%010Lx-0x%010Lx conflict with "
                        "0x%010lx-0x%010lx\n", bo_va->bo, saddr, eaddr,
                        tmp->it.start, tmp->it.last + 1);
-               amdgpu_bo_unreserve(bo_va->bo);
                r = -EINVAL;
                goto error;
        }
 
        mapping = kmalloc(sizeof(*mapping), GFP_KERNEL);
        if (!mapping) {
-               amdgpu_bo_unreserve(bo_va->bo);
                r = -ENOMEM;
                goto error;
        }
@@ -1054,8 +1050,12 @@ int amdgpu_vm_bo_map(struct amdgpu_device *adev,
        mapping->offset = offset;
        mapping->flags = flags;
 
+       mutex_lock(&bo_va->mutex);
        list_add(&mapping->list, &bo_va->invalids);
+       mutex_unlock(&bo_va->mutex);
+       spin_lock(&vm->it_lock);
        interval_tree_insert(&mapping->it, &vm->va);
+       spin_unlock(&vm->it_lock);
        trace_amdgpu_vm_bo_map(bo_va, mapping);
 
        /* Make sure the page tables are allocated */
@@ -1067,8 +1067,6 @@ int amdgpu_vm_bo_map(struct amdgpu_device *adev,
        if (eaddr > vm->max_pde_used)
                vm->max_pde_used = eaddr;
 
-       amdgpu_bo_unreserve(bo_va->bo);
-
        /* walk over the address space and allocate the page tables */
        for (pt_idx = saddr; pt_idx <= eaddr; ++pt_idx) {
                struct reservation_object *resv = vm->page_directory->tbo.resv;
@@ -1077,16 +1075,19 @@ int amdgpu_vm_bo_map(struct amdgpu_device *adev,
                if (vm->page_tables[pt_idx].bo)
                        continue;
 
-               ww_mutex_lock(&resv->lock, NULL);
                r = amdgpu_bo_create(adev, AMDGPU_VM_PTE_COUNT * 8,
                                     AMDGPU_GPU_PAGE_SIZE, true,
                                     AMDGPU_GEM_DOMAIN_VRAM,
                                     AMDGPU_GEM_CREATE_NO_CPU_ACCESS,
                                     NULL, resv, &pt);
-               ww_mutex_unlock(&resv->lock);
                if (r)
                        goto error_free;
 
+               /* Keep a reference to the page table to avoid freeing
+                * them up in the wrong order.
+                */
+               pt->parent = amdgpu_bo_ref(vm->page_directory);
+
                r = amdgpu_vm_clear_bo(adev, pt);
                if (r) {
                        amdgpu_bo_unref(&pt);
@@ -1101,7 +1102,9 @@ int amdgpu_vm_bo_map(struct amdgpu_device *adev,
 
 error_free:
        list_del(&mapping->list);
+       spin_lock(&vm->it_lock);
        interval_tree_remove(&mapping->it, &vm->va);
+       spin_unlock(&vm->it_lock);
        trace_amdgpu_vm_bo_unmap(bo_va, mapping);
        kfree(mapping);
 
@@ -1119,7 +1122,7 @@ error:
  * Remove a mapping of the BO at the specefied addr from the VM.
  * Returns 0 for success, error for failure.
  *
- * Object has to be reserved and gets unreserved by this function!
+ * Object has to be reserved and unreserved outside!
  */
 int amdgpu_vm_bo_unmap(struct amdgpu_device *adev,
                       struct amdgpu_bo_va *bo_va,
@@ -1130,7 +1133,7 @@ int amdgpu_vm_bo_unmap(struct amdgpu_device *adev,
        bool valid = true;
 
        saddr /= AMDGPU_GPU_PAGE_SIZE;
-
+       mutex_lock(&bo_va->mutex);
        list_for_each_entry(mapping, &bo_va->valids, list) {
                if (mapping->it.start == saddr)
                        break;
@@ -1145,20 +1148,24 @@ int amdgpu_vm_bo_unmap(struct amdgpu_device *adev,
                }
 
                if (&mapping->list == &bo_va->invalids) {
-                       amdgpu_bo_unreserve(bo_va->bo);
+                       mutex_unlock(&bo_va->mutex);
                        return -ENOENT;
                }
        }
-
+       mutex_unlock(&bo_va->mutex);
        list_del(&mapping->list);
+       spin_lock(&vm->it_lock);
        interval_tree_remove(&mapping->it, &vm->va);
+       spin_unlock(&vm->it_lock);
        trace_amdgpu_vm_bo_unmap(bo_va, mapping);
 
-       if (valid)
+       if (valid) {
+               spin_lock(&vm->freed_lock);
                list_add(&mapping->list, &vm->freed);
-       else
+               spin_unlock(&vm->freed_lock);
+       } else {
                kfree(mapping);
-       amdgpu_bo_unreserve(bo_va->bo);
+       }
 
        return 0;
 }
@@ -1187,17 +1194,23 @@ void amdgpu_vm_bo_rmv(struct amdgpu_device *adev,
 
        list_for_each_entry_safe(mapping, next, &bo_va->valids, list) {
                list_del(&mapping->list);
+               spin_lock(&vm->it_lock);
                interval_tree_remove(&mapping->it, &vm->va);
+               spin_unlock(&vm->it_lock);
                trace_amdgpu_vm_bo_unmap(bo_va, mapping);
+               spin_lock(&vm->freed_lock);
                list_add(&mapping->list, &vm->freed);
+               spin_unlock(&vm->freed_lock);
        }
        list_for_each_entry_safe(mapping, next, &bo_va->invalids, list) {
                list_del(&mapping->list);
+               spin_lock(&vm->it_lock);
                interval_tree_remove(&mapping->it, &vm->va);
+               spin_unlock(&vm->it_lock);
                kfree(mapping);
        }
-
        fence_put(bo_va->last_pt_update);
+       mutex_destroy(&bo_va->mutex);
        kfree(bo_va);
 }
 
@@ -1241,15 +1254,14 @@ int amdgpu_vm_init(struct amdgpu_device *adev, struct amdgpu_vm *vm)
        for (i = 0; i < AMDGPU_MAX_RINGS; ++i) {
                vm->ids[i].id = 0;
                vm->ids[i].flushed_updates = NULL;
-               vm->ids[i].last_id_use = NULL;
        }
-       mutex_init(&vm->mutex);
        vm->va = RB_ROOT;
        spin_lock_init(&vm->status_lock);
        INIT_LIST_HEAD(&vm->invalidated);
        INIT_LIST_HEAD(&vm->cleared);
        INIT_LIST_HEAD(&vm->freed);
-
+       spin_lock_init(&vm->it_lock);
+       spin_lock_init(&vm->freed_lock);
        pd_size = amdgpu_vm_directory_size(adev);
        pd_entries = amdgpu_vm_num_pdes(adev);
 
@@ -1269,8 +1281,14 @@ int amdgpu_vm_init(struct amdgpu_device *adev, struct amdgpu_vm *vm)
                             NULL, NULL, &vm->page_directory);
        if (r)
                return r;
-
+       r = amdgpu_bo_reserve(vm->page_directory, false);
+       if (r) {
+               amdgpu_bo_unref(&vm->page_directory);
+               vm->page_directory = NULL;
+               return r;
+       }
        r = amdgpu_vm_clear_bo(adev, vm->page_directory);
+       amdgpu_bo_unreserve(vm->page_directory);
        if (r) {
                amdgpu_bo_unref(&vm->page_directory);
                vm->page_directory = NULL;
@@ -1313,11 +1331,27 @@ void amdgpu_vm_fini(struct amdgpu_device *adev, struct amdgpu_vm *vm)
 
        amdgpu_bo_unref(&vm->page_directory);
        fence_put(vm->page_directory_fence);
-
        for (i = 0; i < AMDGPU_MAX_RINGS; ++i) {
+               unsigned id = vm->ids[i].id;
+
+               atomic_long_cmpxchg(&adev->vm_manager.ids[id].owner,
+                                   (long)vm, 0);
                fence_put(vm->ids[i].flushed_updates);
-               fence_put(vm->ids[i].last_id_use);
        }
 
-       mutex_destroy(&vm->mutex);
+}
+
+/**
+ * amdgpu_vm_manager_fini - cleanup VM manager
+ *
+ * @adev: amdgpu_device pointer
+ *
+ * Cleanup the VM manager and free resources.
+ */
+void amdgpu_vm_manager_fini(struct amdgpu_device *adev)
+{
+       unsigned i;
+
+       for (i = 0; i < AMDGPU_NUM_VM; ++i)
+               fence_put(adev->vm_manager.ids[i].active);
 }
index a1a35a5df8e71357eea132019d3500a35a89fce4..57a2e347f04dc33a0f34394895900bf2d0552aa5 100644 (file)
@@ -6569,12 +6569,12 @@ static int ci_dpm_set_interrupt_state(struct amdgpu_device *adev,
                switch (state) {
                case AMDGPU_IRQ_STATE_DISABLE:
                        cg_thermal_int = RREG32_SMC(ixCG_THERMAL_INT);
-                       cg_thermal_int &= ~CG_THERMAL_INT_CTRL__THERM_INTH_MASK_MASK;
+                       cg_thermal_int |= CG_THERMAL_INT_CTRL__THERM_INTH_MASK_MASK;
                        WREG32_SMC(ixCG_THERMAL_INT, cg_thermal_int);
                        break;
                case AMDGPU_IRQ_STATE_ENABLE:
                        cg_thermal_int = RREG32_SMC(ixCG_THERMAL_INT);
-                       cg_thermal_int |= CG_THERMAL_INT_CTRL__THERM_INTH_MASK_MASK;
+                       cg_thermal_int &= ~CG_THERMAL_INT_CTRL__THERM_INTH_MASK_MASK;
                        WREG32_SMC(ixCG_THERMAL_INT, cg_thermal_int);
                        break;
                default:
@@ -6586,12 +6586,12 @@ static int ci_dpm_set_interrupt_state(struct amdgpu_device *adev,
                switch (state) {
                case AMDGPU_IRQ_STATE_DISABLE:
                        cg_thermal_int = RREG32_SMC(ixCG_THERMAL_INT);
-                       cg_thermal_int &= ~CG_THERMAL_INT_CTRL__THERM_INTL_MASK_MASK;
+                       cg_thermal_int |= CG_THERMAL_INT_CTRL__THERM_INTL_MASK_MASK;
                        WREG32_SMC(ixCG_THERMAL_INT, cg_thermal_int);
                        break;
                case AMDGPU_IRQ_STATE_ENABLE:
                        cg_thermal_int = RREG32_SMC(ixCG_THERMAL_INT);
-                       cg_thermal_int |= CG_THERMAL_INT_CTRL__THERM_INTL_MASK_MASK;
+                       cg_thermal_int &= ~CG_THERMAL_INT_CTRL__THERM_INTL_MASK_MASK;
                        WREG32_SMC(ixCG_THERMAL_INT, cg_thermal_int);
                        break;
                default:
index cb0f7747e3dcac2dfa923d43fc0dd8574968d575..4dcc8fba579203297ece7849ab8a861ecbe33f10 100644 (file)
@@ -1250,7 +1250,7 @@ static void dce_v10_0_program_watermarks(struct amdgpu_device *adev,
        u32 pixel_period;
        u32 line_time = 0;
        u32 latency_watermark_a = 0, latency_watermark_b = 0;
-       u32 tmp, wm_mask;
+       u32 tmp, wm_mask, lb_vblank_lead_lines = 0;
 
        if (amdgpu_crtc->base.enabled && num_heads && mode) {
                pixel_period = 1000000 / (u32)mode->clock;
@@ -1333,6 +1333,7 @@ static void dce_v10_0_program_watermarks(struct amdgpu_device *adev,
                    (adev->mode_info.disp_priority == 2)) {
                        DRM_DEBUG_KMS("force priority to high\n");
                }
+               lb_vblank_lead_lines = DIV_ROUND_UP(lb_size, mode->crtc_hdisplay);
        }
 
        /* select wm A */
@@ -1357,6 +1358,8 @@ static void dce_v10_0_program_watermarks(struct amdgpu_device *adev,
        amdgpu_crtc->line_time = line_time;
        amdgpu_crtc->wm_high = latency_watermark_a;
        amdgpu_crtc->wm_low = latency_watermark_b;
+       /* Save number of lines the linebuffer leads before the scanout */
+       amdgpu_crtc->lb_vblank_lead_lines = lb_vblank_lead_lines;
 }
 
 /**
index 5af3721851d67e99b521328babc38c811a7e2c09..8f1e51128b33882d5680731b9afb08fcf1b1023c 100644 (file)
@@ -1238,7 +1238,7 @@ static void dce_v11_0_program_watermarks(struct amdgpu_device *adev,
        u32 pixel_period;
        u32 line_time = 0;
        u32 latency_watermark_a = 0, latency_watermark_b = 0;
-       u32 tmp, wm_mask;
+       u32 tmp, wm_mask, lb_vblank_lead_lines = 0;
 
        if (amdgpu_crtc->base.enabled && num_heads && mode) {
                pixel_period = 1000000 / (u32)mode->clock;
@@ -1321,6 +1321,7 @@ static void dce_v11_0_program_watermarks(struct amdgpu_device *adev,
                    (adev->mode_info.disp_priority == 2)) {
                        DRM_DEBUG_KMS("force priority to high\n");
                }
+               lb_vblank_lead_lines = DIV_ROUND_UP(lb_size, mode->crtc_hdisplay);
        }
 
        /* select wm A */
@@ -1345,6 +1346,8 @@ static void dce_v11_0_program_watermarks(struct amdgpu_device *adev,
        amdgpu_crtc->line_time = line_time;
        amdgpu_crtc->wm_high = latency_watermark_a;
        amdgpu_crtc->wm_low = latency_watermark_b;
+       /* Save number of lines the linebuffer leads before the scanout */
+       amdgpu_crtc->lb_vblank_lead_lines = lb_vblank_lead_lines;
 }
 
 /**
index 4f7b49a6dc500c431ba9aa52727232156f60bda1..42d954dc436d03206c48aafe7655966870dfc931 100644 (file)
@@ -1193,7 +1193,7 @@ static void dce_v8_0_program_watermarks(struct amdgpu_device *adev,
        u32 pixel_period;
        u32 line_time = 0;
        u32 latency_watermark_a = 0, latency_watermark_b = 0;
-       u32 tmp, wm_mask;
+       u32 tmp, wm_mask, lb_vblank_lead_lines = 0;
 
        if (amdgpu_crtc->base.enabled && num_heads && mode) {
                pixel_period = 1000000 / (u32)mode->clock;
@@ -1276,6 +1276,7 @@ static void dce_v8_0_program_watermarks(struct amdgpu_device *adev,
                    (adev->mode_info.disp_priority == 2)) {
                        DRM_DEBUG_KMS("force priority to high\n");
                }
+               lb_vblank_lead_lines = DIV_ROUND_UP(lb_size, mode->crtc_hdisplay);
        }
 
        /* select wm A */
@@ -1302,6 +1303,8 @@ static void dce_v8_0_program_watermarks(struct amdgpu_device *adev,
        amdgpu_crtc->line_time = line_time;
        amdgpu_crtc->wm_high = latency_watermark_a;
        amdgpu_crtc->wm_low = latency_watermark_b;
+       /* Save number of lines the linebuffer leads before the scanout */
+       amdgpu_crtc->lb_vblank_lead_lines = lb_vblank_lead_lines;
 }
 
 /**
index 6776cf756d403415e29fc836785c66b828106879..e1dcab98e24944217d1e6a7485e5bee42587c0b8 100644 (file)
@@ -268,7 +268,6 @@ static const u32 fiji_mgcg_cgcg_init[] =
        mmCGTT_CP_CLK_CTRL, 0xffffffff, 0x00000100,
        mmCGTT_CPC_CLK_CTRL, 0xffffffff, 0x00000100,
        mmCGTT_CPF_CLK_CTRL, 0xffffffff, 0x40000100,
-       mmCGTT_DRM_CLK_CTRL0, 0xffffffff, 0x00600100,
        mmCGTT_GDS_CLK_CTRL, 0xffffffff, 0x00000100,
        mmCGTT_IA_CLK_CTRL, 0xffffffff, 0x06000100,
        mmCGTT_PA_CLK_CTRL, 0xffffffff, 0x00000100,
@@ -296,10 +295,6 @@ static const u32 fiji_mgcg_cgcg_init[] =
        mmCGTS_SM_CTRL_REG, 0xffffffff, 0x96e00200,
        mmCP_RB_WPTR_POLL_CNTL, 0xffffffff, 0x00900100,
        mmRLC_CGCG_CGLS_CTRL, 0xffffffff, 0x0020003c,
-       mmPCIE_INDEX, 0xffffffff, 0x0140001c,
-       mmPCIE_DATA, 0x000f0000, 0x00000000,
-       mmCGTT_DRM_CLK_CTRL0, 0xff000fff, 0x00000100,
-       mmHDP_XDP_CGTT_BLK_CTRL, 0xc0000fff, 0x00000104,
        mmCP_MEM_SLP_CNTL, 0x00000001, 0x00000001,
 };
 
@@ -1000,7 +995,7 @@ static void gfx_v8_0_gpu_early_init(struct amdgpu_device *adev)
                adev->gfx.config.max_cu_per_sh = 16;
                adev->gfx.config.max_sh_per_se = 1;
                adev->gfx.config.max_backends_per_se = 4;
-               adev->gfx.config.max_texture_channel_caches = 8;
+               adev->gfx.config.max_texture_channel_caches = 16;
                adev->gfx.config.max_gprs = 256;
                adev->gfx.config.max_gs_threads = 32;
                adev->gfx.config.max_hw_contexts = 8;
@@ -1613,6 +1608,296 @@ static void gfx_v8_0_tiling_mode_table_init(struct amdgpu_device *adev)
                        WREG32(mmGB_MACROTILE_MODE0 + reg_offset, gb_tile_moden);
                }
        case CHIP_FIJI:
+               for (reg_offset = 0; reg_offset < num_tile_mode_states; reg_offset++) {
+                       switch (reg_offset) {
+                       case 0:
+                               gb_tile_moden = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) |
+                                               PIPE_CONFIG(ADDR_SURF_P16_32x32_16x16) |
+                                               TILE_SPLIT(ADDR_SURF_TILE_SPLIT_64B) |
+                                               MICRO_TILE_MODE_NEW(ADDR_SURF_DEPTH_MICRO_TILING));
+                               break;
+                       case 1:
+                               gb_tile_moden = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) |
+                                               PIPE_CONFIG(ADDR_SURF_P16_32x32_16x16) |
+                                               TILE_SPLIT(ADDR_SURF_TILE_SPLIT_128B) |
+                                               MICRO_TILE_MODE_NEW(ADDR_SURF_DEPTH_MICRO_TILING));
+                               break;
+                       case 2:
+                               gb_tile_moden = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) |
+                                               PIPE_CONFIG(ADDR_SURF_P16_32x32_16x16) |
+                                               TILE_SPLIT(ADDR_SURF_TILE_SPLIT_256B) |
+                                               MICRO_TILE_MODE_NEW(ADDR_SURF_DEPTH_MICRO_TILING));
+                               break;
+                       case 3:
+                               gb_tile_moden = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) |
+                                               PIPE_CONFIG(ADDR_SURF_P16_32x32_16x16) |
+                                               TILE_SPLIT(ADDR_SURF_TILE_SPLIT_512B) |
+                                               MICRO_TILE_MODE_NEW(ADDR_SURF_DEPTH_MICRO_TILING));
+                               break;
+                       case 4:
+                               gb_tile_moden = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) |
+                                               PIPE_CONFIG(ADDR_SURF_P16_32x32_16x16) |
+                                               TILE_SPLIT(ADDR_SURF_TILE_SPLIT_2KB) |
+                                               MICRO_TILE_MODE_NEW(ADDR_SURF_DEPTH_MICRO_TILING));
+                               break;
+                       case 5:
+                               gb_tile_moden = (ARRAY_MODE(ARRAY_1D_TILED_THIN1) |
+                                               PIPE_CONFIG(ADDR_SURF_P16_32x32_16x16) |
+                                               TILE_SPLIT(ADDR_SURF_TILE_SPLIT_2KB) |
+                                               MICRO_TILE_MODE_NEW(ADDR_SURF_DEPTH_MICRO_TILING));
+                               break;
+                       case 6:
+                               gb_tile_moden = (ARRAY_MODE(ARRAY_PRT_TILED_THIN1) |
+                                               PIPE_CONFIG(ADDR_SURF_P16_32x32_16x16) |
+                                               TILE_SPLIT(ADDR_SURF_TILE_SPLIT_2KB) |
+                                               MICRO_TILE_MODE_NEW(ADDR_SURF_DEPTH_MICRO_TILING));
+                               break;
+                       case 7:
+                               gb_tile_moden = (ARRAY_MODE(ARRAY_PRT_TILED_THIN1) |
+                                               PIPE_CONFIG(ADDR_SURF_P4_16x16) |
+                                               TILE_SPLIT(ADDR_SURF_TILE_SPLIT_2KB) |
+                                               MICRO_TILE_MODE_NEW(ADDR_SURF_DEPTH_MICRO_TILING));
+                               break;
+                       case 8:
+                               gb_tile_moden = (ARRAY_MODE(ARRAY_LINEAR_ALIGNED) |
+                                               PIPE_CONFIG(ADDR_SURF_P16_32x32_16x16));
+                               break;
+                       case 9:
+                               gb_tile_moden = (ARRAY_MODE(ARRAY_1D_TILED_THIN1) |
+                                               PIPE_CONFIG(ADDR_SURF_P16_32x32_16x16) |
+                                               MICRO_TILE_MODE_NEW(ADDR_SURF_DISPLAY_MICRO_TILING) |
+                                               SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_2));
+                               break;
+                       case 10:
+                               gb_tile_moden = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) |
+                                               PIPE_CONFIG(ADDR_SURF_P16_32x32_16x16) |
+                                               MICRO_TILE_MODE_NEW(ADDR_SURF_DISPLAY_MICRO_TILING) |
+                                               SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_2));
+                               break;
+                       case 11:
+                               gb_tile_moden = (ARRAY_MODE(ARRAY_PRT_TILED_THIN1) |
+                                               PIPE_CONFIG(ADDR_SURF_P16_32x32_16x16) |
+                                               MICRO_TILE_MODE_NEW(ADDR_SURF_DISPLAY_MICRO_TILING) |
+                                               SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_8));
+                               break;
+                       case 12:
+                               gb_tile_moden = (ARRAY_MODE(ARRAY_PRT_TILED_THIN1) |
+                                               PIPE_CONFIG(ADDR_SURF_P4_16x16) |
+                                               MICRO_TILE_MODE_NEW(ADDR_SURF_DISPLAY_MICRO_TILING) |
+                                               SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_8));
+                               break;
+                       case 13:
+                               gb_tile_moden = (ARRAY_MODE(ARRAY_1D_TILED_THIN1) |
+                                               PIPE_CONFIG(ADDR_SURF_P16_32x32_16x16) |
+                                               MICRO_TILE_MODE_NEW(ADDR_SURF_THIN_MICRO_TILING) |
+                                               SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_2));
+                               break;
+                       case 14:
+                               gb_tile_moden = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) |
+                                               PIPE_CONFIG(ADDR_SURF_P16_32x32_16x16) |
+                                               MICRO_TILE_MODE_NEW(ADDR_SURF_THIN_MICRO_TILING) |
+                                               SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_2));
+                               break;
+                       case 15:
+                               gb_tile_moden = (ARRAY_MODE(ARRAY_3D_TILED_THIN1) |
+                                               PIPE_CONFIG(ADDR_SURF_P16_32x32_16x16) |
+                                               MICRO_TILE_MODE_NEW(ADDR_SURF_THIN_MICRO_TILING) |
+                                               SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_2));
+                               break;
+                       case 16:
+                               gb_tile_moden = (ARRAY_MODE(ARRAY_PRT_TILED_THIN1) |
+                                               PIPE_CONFIG(ADDR_SURF_P16_32x32_16x16) |
+                                               MICRO_TILE_MODE_NEW(ADDR_SURF_THIN_MICRO_TILING) |
+                                               SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_8));
+                               break;
+                       case 17:
+                               gb_tile_moden = (ARRAY_MODE(ARRAY_PRT_TILED_THIN1) |
+                                               PIPE_CONFIG(ADDR_SURF_P4_16x16) |
+                                               MICRO_TILE_MODE_NEW(ADDR_SURF_THIN_MICRO_TILING) |
+                                               SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_8));
+                               break;
+                       case 18:
+                               gb_tile_moden = (ARRAY_MODE(ARRAY_1D_TILED_THICK) |
+                                               PIPE_CONFIG(ADDR_SURF_P16_32x32_16x16) |
+                                               MICRO_TILE_MODE_NEW(ADDR_SURF_THIN_MICRO_TILING) |
+                                               SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_1));
+                               break;
+                       case 19:
+                               gb_tile_moden = (ARRAY_MODE(ARRAY_1D_TILED_THICK) |
+                                               PIPE_CONFIG(ADDR_SURF_P16_32x32_16x16) |
+                                               MICRO_TILE_MODE_NEW(ADDR_SURF_THICK_MICRO_TILING) |
+                                               SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_1));
+                               break;
+                       case 20:
+                               gb_tile_moden = (ARRAY_MODE(ARRAY_2D_TILED_THICK) |
+                                               PIPE_CONFIG(ADDR_SURF_P16_32x32_16x16) |
+                                               MICRO_TILE_MODE_NEW(ADDR_SURF_THICK_MICRO_TILING) |
+                                               SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_1));
+                               break;
+                       case 21:
+                               gb_tile_moden = (ARRAY_MODE(ARRAY_3D_TILED_THICK) |
+                                               PIPE_CONFIG(ADDR_SURF_P16_32x32_16x16) |
+                                               MICRO_TILE_MODE_NEW(ADDR_SURF_THICK_MICRO_TILING) |
+                                               SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_1));
+                               break;
+                       case 22:
+                               gb_tile_moden = (ARRAY_MODE(ARRAY_PRT_TILED_THICK) |
+                                               PIPE_CONFIG(ADDR_SURF_P16_32x32_16x16) |
+                                               MICRO_TILE_MODE_NEW(ADDR_SURF_THICK_MICRO_TILING) |
+                                               SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_1));
+                               break;
+                       case 23:
+                               gb_tile_moden = (ARRAY_MODE(ARRAY_PRT_TILED_THICK) |
+                                               PIPE_CONFIG(ADDR_SURF_P4_16x16) |
+                                               MICRO_TILE_MODE_NEW(ADDR_SURF_THICK_MICRO_TILING) |
+                                               SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_1));
+                               break;
+                       case 24:
+                               gb_tile_moden = (ARRAY_MODE(ARRAY_2D_TILED_THICK) |
+                                               PIPE_CONFIG(ADDR_SURF_P16_32x32_16x16) |
+                                               MICRO_TILE_MODE_NEW(ADDR_SURF_THIN_MICRO_TILING) |
+                                               SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_1));
+                               break;
+                       case 25:
+                               gb_tile_moden = (ARRAY_MODE(ARRAY_2D_TILED_XTHICK) |
+                                               PIPE_CONFIG(ADDR_SURF_P16_32x32_16x16) |
+                                               MICRO_TILE_MODE_NEW(ADDR_SURF_THICK_MICRO_TILING) |
+                                               SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_1));
+                               break;
+                       case 26:
+                               gb_tile_moden = (ARRAY_MODE(ARRAY_3D_TILED_XTHICK) |
+                                               PIPE_CONFIG(ADDR_SURF_P16_32x32_16x16) |
+                                               MICRO_TILE_MODE_NEW(ADDR_SURF_THICK_MICRO_TILING) |
+                                               SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_1));
+                               break;
+                       case 27:
+                               gb_tile_moden = (ARRAY_MODE(ARRAY_1D_TILED_THIN1) |
+                                               PIPE_CONFIG(ADDR_SURF_P16_32x32_16x16) |
+                                               MICRO_TILE_MODE_NEW(ADDR_SURF_ROTATED_MICRO_TILING) |
+                                               SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_2));
+                               break;
+                       case 28:
+                               gb_tile_moden = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) |
+                                               PIPE_CONFIG(ADDR_SURF_P16_32x32_16x16) |
+                                               MICRO_TILE_MODE_NEW(ADDR_SURF_ROTATED_MICRO_TILING) |
+                                               SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_2));
+                               break;
+                       case 29:
+                               gb_tile_moden = (ARRAY_MODE(ARRAY_PRT_TILED_THIN1) |
+                                               PIPE_CONFIG(ADDR_SURF_P16_32x32_16x16) |
+                                               MICRO_TILE_MODE_NEW(ADDR_SURF_ROTATED_MICRO_TILING) |
+                                               SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_8));
+                               break;
+                       case 30:
+                               gb_tile_moden = (ARRAY_MODE(ARRAY_PRT_TILED_THIN1) |
+                                               PIPE_CONFIG(ADDR_SURF_P4_16x16) |
+                                               MICRO_TILE_MODE_NEW(ADDR_SURF_ROTATED_MICRO_TILING) |
+                                               SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_8));
+                               break;
+                       default:
+                               gb_tile_moden = 0;
+                               break;
+                       }
+                       adev->gfx.config.tile_mode_array[reg_offset] = gb_tile_moden;
+                       WREG32(mmGB_TILE_MODE0 + reg_offset, gb_tile_moden);
+               }
+               for (reg_offset = 0; reg_offset < num_secondary_tile_mode_states; reg_offset++) {
+                       switch (reg_offset) {
+                       case 0:
+                               gb_tile_moden = (BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) |
+                                               BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_4) |
+                                               MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_2) |
+                                               NUM_BANKS(ADDR_SURF_8_BANK));
+                               break;
+                       case 1:
+                               gb_tile_moden = (BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) |
+                                               BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_4) |
+                                               MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_2) |
+                                               NUM_BANKS(ADDR_SURF_8_BANK));
+                               break;
+                       case 2:
+                               gb_tile_moden = (BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) |
+                                               BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_4) |
+                                               MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_2) |
+                                               NUM_BANKS(ADDR_SURF_8_BANK));
+                               break;
+                       case 3:
+                               gb_tile_moden = (BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) |
+                                               BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_4) |
+                                               MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_2) |
+                                               NUM_BANKS(ADDR_SURF_8_BANK));
+                               break;
+                       case 4:
+                               gb_tile_moden = (BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) |
+                                               BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_2) |
+                                               MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_1) |
+                                               NUM_BANKS(ADDR_SURF_8_BANK));
+                               break;
+                       case 5:
+                               gb_tile_moden = (BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) |
+                                               BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_1) |
+                                               MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_1) |
+                                               NUM_BANKS(ADDR_SURF_8_BANK));
+                               break;
+                       case 6:
+                               gb_tile_moden = (BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) |
+                                               BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_1) |
+                                               MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_1) |
+                                               NUM_BANKS(ADDR_SURF_8_BANK));
+                               break;
+                       case 8:
+                               gb_tile_moden = (BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) |
+                                               BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_8) |
+                                               MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_2) |
+                                               NUM_BANKS(ADDR_SURF_8_BANK));
+                               break;
+                       case 9:
+                               gb_tile_moden = (BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) |
+                                               BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_4) |
+                                               MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_2) |
+                                               NUM_BANKS(ADDR_SURF_8_BANK));
+                               break;
+                       case 10:
+                               gb_tile_moden = (BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) |
+                                               BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_2) |
+                                               MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_1) |
+                                               NUM_BANKS(ADDR_SURF_8_BANK));
+                               break;
+                       case 11:
+                               gb_tile_moden = (BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) |
+                                               BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_1) |
+                                               MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_1) |
+                                               NUM_BANKS(ADDR_SURF_8_BANK));
+                               break;
+                       case 12:
+                               gb_tile_moden = (BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) |
+                                               BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_2) |
+                                               MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_2) |
+                                               NUM_BANKS(ADDR_SURF_8_BANK));
+                               break;
+                       case 13:
+                               gb_tile_moden = (BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) |
+                                               BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_1) |
+                                               MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_2) |
+                                               NUM_BANKS(ADDR_SURF_8_BANK));
+                               break;
+                       case 14:
+                               gb_tile_moden = (BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) |
+                                               BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_1) |
+                                               MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_1) |
+                                               NUM_BANKS(ADDR_SURF_4_BANK));
+                               break;
+                       case 7:
+                               /* unused idx */
+                               continue;
+                       default:
+                               gb_tile_moden = 0;
+                               break;
+                       }
+                       adev->gfx.config.macrotile_mode_array[reg_offset] = gb_tile_moden;
+                       WREG32(mmGB_MACROTILE_MODE0 + reg_offset, gb_tile_moden);
+               }
+               break;
        case CHIP_TONGA:
                for (reg_offset = 0; reg_offset < num_tile_mode_states; reg_offset++) {
                        switch (reg_offset) {
@@ -2971,10 +3256,13 @@ static int gfx_v8_0_cp_gfx_start(struct amdgpu_device *adev)
        amdgpu_ring_write(ring, mmPA_SC_RASTER_CONFIG - PACKET3_SET_CONTEXT_REG_START);
        switch (adev->asic_type) {
        case CHIP_TONGA:
-       case CHIP_FIJI:
                amdgpu_ring_write(ring, 0x16000012);
                amdgpu_ring_write(ring, 0x0000002A);
                break;
+       case CHIP_FIJI:
+               amdgpu_ring_write(ring, 0x3a00161a);
+               amdgpu_ring_write(ring, 0x0000002e);
+               break;
        case CHIP_TOPAZ:
        case CHIP_CARRIZO:
                amdgpu_ring_write(ring, 0x00000002);
index 85bbcdc73fff0198d350ac1468a8d552b3a450c7..ed8abb58a785ef3efaba87a806e7bcdef7188a1b 100644 (file)
@@ -40,7 +40,7 @@
 static void gmc_v7_0_set_gart_funcs(struct amdgpu_device *adev);
 static void gmc_v7_0_set_irq_funcs(struct amdgpu_device *adev);
 
-MODULE_FIRMWARE("radeon/boniare_mc.bin");
+MODULE_FIRMWARE("radeon/bonaire_mc.bin");
 MODULE_FIRMWARE("radeon/hawaii_mc.bin");
 
 /**
@@ -501,6 +501,7 @@ static int gmc_v7_0_gart_enable(struct amdgpu_device *adev)
        tmp = REG_SET_FIELD(tmp, VM_L2_CNTL, ENABLE_L2_PDE0_CACHE_LRU_UPDATE_BY_WRITE, 1);
        tmp = REG_SET_FIELD(tmp, VM_L2_CNTL, EFFECTIVE_L2_QUEUE_SIZE, 7);
        tmp = REG_SET_FIELD(tmp, VM_L2_CNTL, CONTEXT1_IDENTITY_ACCESS_MODE, 1);
+       tmp = REG_SET_FIELD(tmp, VM_L2_CNTL, ENABLE_DEFAULT_PAGE_OUT_TO_SYSTEM_MEMORY, 1);
        WREG32(mmVM_L2_CNTL, tmp);
        tmp = REG_SET_FIELD(0, VM_L2_CNTL2, INVALIDATE_ALL_L1_TLBS, 1);
        tmp = REG_SET_FIELD(tmp, VM_L2_CNTL2, INVALIDATE_L2_CACHE, 1);
@@ -512,7 +513,7 @@ static int gmc_v7_0_gart_enable(struct amdgpu_device *adev)
        WREG32(mmVM_L2_CNTL3, tmp);
        /* setup context0 */
        WREG32(mmVM_CONTEXT0_PAGE_TABLE_START_ADDR, adev->mc.gtt_start >> 12);
-       WREG32(mmVM_CONTEXT0_PAGE_TABLE_END_ADDR, (adev->mc.gtt_end >> 12) - 1);
+       WREG32(mmVM_CONTEXT0_PAGE_TABLE_END_ADDR, adev->mc.gtt_end >> 12);
        WREG32(mmVM_CONTEXT0_PAGE_TABLE_BASE_ADDR, adev->gart.table_addr >> 12);
        WREG32(mmVM_CONTEXT0_PROTECTION_FAULT_DEFAULT_ADDR,
                        (u32)(adev->dummy_page.addr >> 12));
@@ -960,12 +961,10 @@ static int gmc_v7_0_sw_init(void *handle)
 
 static int gmc_v7_0_sw_fini(void *handle)
 {
-       int i;
        struct amdgpu_device *adev = (struct amdgpu_device *)handle;
 
        if (adev->vm_manager.enabled) {
-               for (i = 0; i < AMDGPU_NUM_VM; ++i)
-                       fence_put(adev->vm_manager.active[i]);
+               amdgpu_vm_manager_fini(adev);
                gmc_v7_0_vm_fini(adev);
                adev->vm_manager.enabled = false;
        }
@@ -1010,12 +1009,10 @@ static int gmc_v7_0_hw_fini(void *handle)
 
 static int gmc_v7_0_suspend(void *handle)
 {
-       int i;
        struct amdgpu_device *adev = (struct amdgpu_device *)handle;
 
        if (adev->vm_manager.enabled) {
-               for (i = 0; i < AMDGPU_NUM_VM; ++i)
-                       fence_put(adev->vm_manager.active[i]);
+               amdgpu_vm_manager_fini(adev);
                gmc_v7_0_vm_fini(adev);
                adev->vm_manager.enabled = false;
        }
index 1bcc4e74e3b485d694d9b91417b76998868b0e6f..d390284408144c923d8571da0df70b3fab38879c 100644 (file)
@@ -629,6 +629,7 @@ static int gmc_v8_0_gart_enable(struct amdgpu_device *adev)
        tmp = REG_SET_FIELD(tmp, VM_L2_CNTL, ENABLE_L2_PDE0_CACHE_LRU_UPDATE_BY_WRITE, 1);
        tmp = REG_SET_FIELD(tmp, VM_L2_CNTL, EFFECTIVE_L2_QUEUE_SIZE, 7);
        tmp = REG_SET_FIELD(tmp, VM_L2_CNTL, CONTEXT1_IDENTITY_ACCESS_MODE, 1);
+       tmp = REG_SET_FIELD(tmp, VM_L2_CNTL, ENABLE_DEFAULT_PAGE_OUT_TO_SYSTEM_MEMORY, 1);
        WREG32(mmVM_L2_CNTL, tmp);
        tmp = RREG32(mmVM_L2_CNTL2);
        tmp = REG_SET_FIELD(tmp, VM_L2_CNTL2, INVALIDATE_ALL_L1_TLBS, 1);
@@ -656,7 +657,7 @@ static int gmc_v8_0_gart_enable(struct amdgpu_device *adev)
        WREG32(mmVM_L2_CNTL4, tmp);
        /* setup context0 */
        WREG32(mmVM_CONTEXT0_PAGE_TABLE_START_ADDR, adev->mc.gtt_start >> 12);
-       WREG32(mmVM_CONTEXT0_PAGE_TABLE_END_ADDR, (adev->mc.gtt_end >> 12) - 1);
+       WREG32(mmVM_CONTEXT0_PAGE_TABLE_END_ADDR, adev->mc.gtt_end >> 12);
        WREG32(mmVM_CONTEXT0_PAGE_TABLE_BASE_ADDR, adev->gart.table_addr >> 12);
        WREG32(mmVM_CONTEXT0_PROTECTION_FAULT_DEFAULT_ADDR,
                        (u32)(adev->dummy_page.addr >> 12));
@@ -979,12 +980,10 @@ static int gmc_v8_0_sw_init(void *handle)
 
 static int gmc_v8_0_sw_fini(void *handle)
 {
-       int i;
        struct amdgpu_device *adev = (struct amdgpu_device *)handle;
 
        if (adev->vm_manager.enabled) {
-               for (i = 0; i < AMDGPU_NUM_VM; ++i)
-                       fence_put(adev->vm_manager.active[i]);
+               amdgpu_vm_manager_fini(adev);
                gmc_v8_0_vm_fini(adev);
                adev->vm_manager.enabled = false;
        }
@@ -1031,12 +1030,10 @@ static int gmc_v8_0_hw_fini(void *handle)
 
 static int gmc_v8_0_suspend(void *handle)
 {
-       int i;
        struct amdgpu_device *adev = (struct amdgpu_device *)handle;
 
        if (adev->vm_manager.enabled) {
-               for (i = 0; i < AMDGPU_NUM_VM; ++i)
-                       fence_put(adev->vm_manager.active[i]);
+               amdgpu_vm_manager_fini(adev);
                gmc_v8_0_vm_fini(adev);
                adev->vm_manager.enabled = false;
        }
index 6a52db6ad8d779afe7a82f29a731a4e912183bcb..370c6c9d81c26550302b974a4b794ed464090b65 100644 (file)
@@ -40,6 +40,9 @@
 
 #define GRBM_GFX_INDEX__VCE_INSTANCE__SHIFT    0x04
 #define GRBM_GFX_INDEX__VCE_INSTANCE_MASK      0x10
+#define mmVCE_LMI_VCPU_CACHE_40BIT_BAR0        0x8616
+#define mmVCE_LMI_VCPU_CACHE_40BIT_BAR1        0x8617
+#define mmVCE_LMI_VCPU_CACHE_40BIT_BAR2        0x8618
 
 #define VCE_V3_0_FW_SIZE       (384 * 1024)
 #define VCE_V3_0_STACK_SIZE    (64 * 1024)
@@ -130,9 +133,11 @@ static int vce_v3_0_start(struct amdgpu_device *adev)
 
                /* set BUSY flag */
                WREG32_P(mmVCE_STATUS, 1, ~1);
-
-               WREG32_P(mmVCE_VCPU_CNTL, VCE_VCPU_CNTL__CLK_EN_MASK,
-                       ~VCE_VCPU_CNTL__CLK_EN_MASK);
+               if (adev->asic_type >= CHIP_STONEY)
+                       WREG32_P(mmVCE_VCPU_CNTL, 1, ~0x200001);
+               else
+                       WREG32_P(mmVCE_VCPU_CNTL, VCE_VCPU_CNTL__CLK_EN_MASK,
+                               ~VCE_VCPU_CNTL__CLK_EN_MASK);
 
                WREG32_P(mmVCE_SOFT_RESET,
                         VCE_SOFT_RESET__ECPU_SOFT_RESET_MASK,
@@ -391,8 +396,12 @@ static void vce_v3_0_mc_resume(struct amdgpu_device *adev, int idx)
        WREG32(mmVCE_LMI_SWAP_CNTL, 0);
        WREG32(mmVCE_LMI_SWAP_CNTL1, 0);
        WREG32(mmVCE_LMI_VM_CTRL, 0);
-
-       WREG32(mmVCE_LMI_VCPU_CACHE_40BIT_BAR, (adev->vce.gpu_addr >> 8));
+       if (adev->asic_type >= CHIP_STONEY) {
+               WREG32(mmVCE_LMI_VCPU_CACHE_40BIT_BAR0, (adev->vce.gpu_addr >> 8));
+               WREG32(mmVCE_LMI_VCPU_CACHE_40BIT_BAR1, (adev->vce.gpu_addr >> 8));
+               WREG32(mmVCE_LMI_VCPU_CACHE_40BIT_BAR2, (adev->vce.gpu_addr >> 8));
+       } else
+               WREG32(mmVCE_LMI_VCPU_CACHE_40BIT_BAR, (adev->vce.gpu_addr >> 8));
        offset = AMDGPU_VCE_FIRMWARE_OFFSET;
        size = VCE_V3_0_FW_SIZE;
        WREG32(mmVCE_VCPU_CACHE_OFFSET0, offset & 0x7fffffff);
@@ -576,6 +585,11 @@ static int vce_v3_0_process_interrupt(struct amdgpu_device *adev,
                                      struct amdgpu_iv_entry *entry)
 {
        DRM_DEBUG("IH: VCE\n");
+
+       WREG32_P(mmVCE_SYS_INT_STATUS,
+               VCE_SYS_INT_STATUS__VCE_SYS_INT_TRAP_INTERRUPT_INT_MASK,
+               ~VCE_SYS_INT_STATUS__VCE_SYS_INT_TRAP_INTERRUPT_INT_MASK);
+
        switch (entry->src_data) {
        case 0:
                amdgpu_fence_process(&adev->vce.ring[0]);
index 144f50acc9715c0e2b30b459e68fb7c9f7c543ba..c89dc777768f8cdabe3ce882483c134faa6aefa7 100644 (file)
@@ -16,6 +16,8 @@ TRACE_EVENT(amd_sched_job,
            TP_ARGS(sched_job),
            TP_STRUCT__entry(
                             __field(struct amd_sched_entity *, entity)
+                            __field(struct amd_sched_job *, sched_job)
+                            __field(struct fence *, fence)
                             __field(const char *, name)
                             __field(u32, job_count)
                             __field(int, hw_job_count)
@@ -23,16 +25,32 @@ TRACE_EVENT(amd_sched_job,
 
            TP_fast_assign(
                           __entry->entity = sched_job->s_entity;
+                          __entry->sched_job = sched_job;
+                          __entry->fence = &sched_job->s_fence->base;
                           __entry->name = sched_job->sched->name;
                           __entry->job_count = kfifo_len(
                                   &sched_job->s_entity->job_queue) / sizeof(sched_job);
                           __entry->hw_job_count = atomic_read(
                                   &sched_job->sched->hw_rq_count);
                           ),
-           TP_printk("entity=%p, ring=%s, job count:%u, hw job count:%d",
-                     __entry->entity, __entry->name, __entry->job_count,
-                     __entry->hw_job_count)
+           TP_printk("entity=%p, sched job=%p, fence=%p, ring=%s, job count:%u, hw job count:%d",
+                     __entry->entity, __entry->sched_job, __entry->fence, __entry->name,
+                     __entry->job_count, __entry->hw_job_count)
 );
+
+TRACE_EVENT(amd_sched_process_job,
+           TP_PROTO(struct amd_sched_fence *fence),
+           TP_ARGS(fence),
+           TP_STRUCT__entry(
+                   __field(struct fence *, fence)
+                   ),
+
+           TP_fast_assign(
+                   __entry->fence = &fence->base;
+                   ),
+           TP_printk("fence=%p signaled", __entry->fence)
+);
+
 #endif
 
 /* This part must be outside protection */
index 89619a5a4289b882bfbed1a8f3e84dcd6bb3b582..3a4820e863ecbbc8ee003c47f3ccc088804f4f53 100644 (file)
 #define CREATE_TRACE_POINTS
 #include "gpu_sched_trace.h"
 
-static struct amd_sched_job *
-amd_sched_entity_pop_job(struct amd_sched_entity *entity);
+static bool amd_sched_entity_is_ready(struct amd_sched_entity *entity);
 static void amd_sched_wakeup(struct amd_gpu_scheduler *sched);
 
+struct kmem_cache *sched_fence_slab;
+atomic_t sched_fence_slab_ref = ATOMIC_INIT(0);
+
 /* Initialize a given run queue struct */
 static void amd_sched_rq_init(struct amd_sched_rq *rq)
 {
@@ -61,36 +63,36 @@ static void amd_sched_rq_remove_entity(struct amd_sched_rq *rq,
 }
 
 /**
- * Select next job from a specified run queue with round robin policy.
- * Return NULL if nothing available.
+ * Select an entity which could provide a job to run
+ *
+ * @rq         The run queue to check.
+ *
+ * Try to find a ready entity, returns NULL if none found.
  */
-static struct amd_sched_job *
-amd_sched_rq_select_job(struct amd_sched_rq *rq)
+static struct amd_sched_entity *
+amd_sched_rq_select_entity(struct amd_sched_rq *rq)
 {
        struct amd_sched_entity *entity;
-       struct amd_sched_job *sched_job;
 
        spin_lock(&rq->lock);
 
        entity = rq->current_entity;
        if (entity) {
                list_for_each_entry_continue(entity, &rq->entities, list) {
-                       sched_job = amd_sched_entity_pop_job(entity);
-                       if (sched_job) {
+                       if (amd_sched_entity_is_ready(entity)) {
                                rq->current_entity = entity;
                                spin_unlock(&rq->lock);
-                               return sched_job;
+                               return entity;
                        }
                }
        }
 
        list_for_each_entry(entity, &rq->entities, list) {
 
-               sched_job = amd_sched_entity_pop_job(entity);
-               if (sched_job) {
+               if (amd_sched_entity_is_ready(entity)) {
                        rq->current_entity = entity;
                        spin_unlock(&rq->lock);
-                       return sched_job;
+                       return entity;
                }
 
                if (entity == rq->current_entity)
@@ -173,6 +175,24 @@ static bool amd_sched_entity_is_idle(struct amd_sched_entity *entity)
        return false;
 }
 
+/**
+ * Check if entity is ready
+ *
+ * @entity     The pointer to a valid scheduler entity
+ *
+ * Return true if entity could provide a job.
+ */
+static bool amd_sched_entity_is_ready(struct amd_sched_entity *entity)
+{
+       if (kfifo_is_empty(&entity->job_queue))
+               return false;
+
+       if (ACCESS_ONCE(entity->dependency))
+               return false;
+
+       return true;
+}
+
 /**
  * Destroy a context entity
  *
@@ -208,32 +228,53 @@ static void amd_sched_entity_wakeup(struct fence *f, struct fence_cb *cb)
        amd_sched_wakeup(entity->sched);
 }
 
+static bool amd_sched_entity_add_dependency_cb(struct amd_sched_entity *entity)
+{
+       struct amd_gpu_scheduler *sched = entity->sched;
+       struct fence * fence = entity->dependency;
+       struct amd_sched_fence *s_fence;
+
+       if (fence->context == entity->fence_context) {
+               /* We can ignore fences from ourself */
+               fence_put(entity->dependency);
+               return false;
+       }
+
+       s_fence = to_amd_sched_fence(fence);
+       if (s_fence && s_fence->sched == sched) {
+               /* Fence is from the same scheduler */
+               if (test_bit(AMD_SCHED_FENCE_SCHEDULED_BIT, &fence->flags)) {
+                       /* Ignore it when it is already scheduled */
+                       fence_put(entity->dependency);
+                       return false;
+               }
+
+               /* Wait for fence to be scheduled */
+               entity->cb.func = amd_sched_entity_wakeup;
+               list_add_tail(&entity->cb.node, &s_fence->scheduled_cb);
+               return true;
+       }
+
+       if (!fence_add_callback(entity->dependency, &entity->cb,
+                               amd_sched_entity_wakeup))
+               return true;
+
+       fence_put(entity->dependency);
+       return false;
+}
+
 static struct amd_sched_job *
 amd_sched_entity_pop_job(struct amd_sched_entity *entity)
 {
        struct amd_gpu_scheduler *sched = entity->sched;
        struct amd_sched_job *sched_job;
 
-       if (ACCESS_ONCE(entity->dependency))
-               return NULL;
-
        if (!kfifo_out_peek(&entity->job_queue, &sched_job, sizeof(sched_job)))
                return NULL;
 
-       while ((entity->dependency = sched->ops->dependency(sched_job))) {
-
-               if (entity->dependency->context == entity->fence_context) {
-                       /* We can ignore fences from ourself */
-                       fence_put(entity->dependency);
-                       continue;
-               }
-
-               if (fence_add_callback(entity->dependency, &entity->cb,
-                                      amd_sched_entity_wakeup))
-                       fence_put(entity->dependency);
-               else
+       while ((entity->dependency = sched->ops->dependency(sched_job)))
+               if (amd_sched_entity_add_dependency_cb(entity))
                        return NULL;
-       }
 
        return sched_job;
 }
@@ -247,6 +288,7 @@ amd_sched_entity_pop_job(struct amd_sched_entity *entity)
  */
 static bool amd_sched_entity_in(struct amd_sched_job *sched_job)
 {
+       struct amd_gpu_scheduler *sched = sched_job->sched;
        struct amd_sched_entity *entity = sched_job->s_entity;
        bool added, first = false;
 
@@ -261,7 +303,7 @@ static bool amd_sched_entity_in(struct amd_sched_job *sched_job)
 
        /* first job wakes up scheduler */
        if (first)
-               amd_sched_wakeup(sched_job->sched);
+               amd_sched_wakeup(sched);
 
        return added;
 }
@@ -273,22 +315,13 @@ static bool amd_sched_entity_in(struct amd_sched_job *sched_job)
  *
  * Returns 0 for success, negative error code otherwise.
  */
-int amd_sched_entity_push_job(struct amd_sched_job *sched_job)
+void amd_sched_entity_push_job(struct amd_sched_job *sched_job)
 {
        struct amd_sched_entity *entity = sched_job->s_entity;
-       struct amd_sched_fence *fence = amd_sched_fence_create(
-               entity, sched_job->owner);
-
-       if (!fence)
-               return -ENOMEM;
-
-       fence_get(&fence->base);
-       sched_job->s_fence = fence;
 
+       trace_amd_sched_job(sched_job);
        wait_event(entity->sched->job_scheduled,
                   amd_sched_entity_in(sched_job));
-       trace_amd_sched_job(sched_job);
-       return 0;
 }
 
 /**
@@ -310,22 +343,22 @@ static void amd_sched_wakeup(struct amd_gpu_scheduler *sched)
 }
 
 /**
- * Select next to run
+ * Select next entity to process
 */
-static struct amd_sched_job *
-amd_sched_select_job(struct amd_gpu_scheduler *sched)
+static struct amd_sched_entity *
+amd_sched_select_entity(struct amd_gpu_scheduler *sched)
 {
-       struct amd_sched_job *sched_job;
+       struct amd_sched_entity *entity;
 
        if (!amd_sched_ready(sched))
                return NULL;
 
        /* Kernel run queue has higher priority than normal run queue*/
-       sched_job = amd_sched_rq_select_job(&sched->kernel_rq);
-       if (sched_job == NULL)
-               sched_job = amd_sched_rq_select_job(&sched->sched_rq);
+       entity = amd_sched_rq_select_entity(&sched->kernel_rq);
+       if (entity == NULL)
+               entity = amd_sched_rq_select_entity(&sched->sched_rq);
 
-       return sched_job;
+       return entity;
 }
 
 static void amd_sched_process_job(struct fence *f, struct fence_cb *cb)
@@ -343,6 +376,7 @@ static void amd_sched_process_job(struct fence *f, struct fence_cb *cb)
                list_del_init(&s_fence->list);
                spin_unlock_irqrestore(&sched->fence_list_lock, flags);
        }
+       trace_amd_sched_process_job(s_fence);
        fence_put(&s_fence->base);
        wake_up_interruptible(&sched->wake_up_worker);
 }
@@ -386,13 +420,16 @@ static int amd_sched_main(void *param)
                unsigned long flags;
 
                wait_event_interruptible(sched->wake_up_worker,
-                       kthread_should_stop() ||
-                       (sched_job = amd_sched_select_job(sched)));
+                       (entity = amd_sched_select_entity(sched)) ||
+                       kthread_should_stop());
 
+               if (!entity)
+                       continue;
+
+               sched_job = amd_sched_entity_pop_job(entity);
                if (!sched_job)
                        continue;
 
-               entity = sched_job->s_entity;
                s_fence = sched_job->s_fence;
 
                if (sched->timeout != MAX_SCHEDULE_TIMEOUT) {
@@ -405,6 +442,7 @@ static int amd_sched_main(void *param)
 
                atomic_inc(&sched->hw_rq_count);
                fence = sched->ops->run_job(sched_job);
+               amd_sched_fence_scheduled(s_fence);
                if (fence) {
                        r = fence_add_callback(fence, &s_fence->cb,
                                               amd_sched_process_job);
@@ -450,6 +488,13 @@ int amd_sched_init(struct amd_gpu_scheduler *sched,
        init_waitqueue_head(&sched->wake_up_worker);
        init_waitqueue_head(&sched->job_scheduled);
        atomic_set(&sched->hw_rq_count, 0);
+       if (atomic_inc_return(&sched_fence_slab_ref) == 1) {
+               sched_fence_slab = kmem_cache_create(
+                       "amd_sched_fence", sizeof(struct amd_sched_fence), 0,
+                       SLAB_HWCACHE_ALIGN, NULL);
+               if (!sched_fence_slab)
+                       return -ENOMEM;
+       }
 
        /* Each scheduler will run on a seperate kernel thread */
        sched->thread = kthread_run(amd_sched_main, sched, sched->name);
@@ -470,4 +515,6 @@ void amd_sched_fini(struct amd_gpu_scheduler *sched)
 {
        if (sched->thread)
                kthread_stop(sched->thread);
+       if (atomic_dec_and_test(&sched_fence_slab_ref))
+               kmem_cache_destroy(sched_fence_slab);
 }
index 929e9aced04195e24ed5ddcae99ab385ce830898..a0f0ae53aacdefacc6a80f2506b5bd9f2a4cea9c 100644 (file)
 #include <linux/kfifo.h>
 #include <linux/fence.h>
 
+#define AMD_SCHED_FENCE_SCHEDULED_BIT  FENCE_FLAG_USER_BITS
+
 struct amd_gpu_scheduler;
 struct amd_sched_rq;
 
+extern struct kmem_cache *sched_fence_slab;
+extern atomic_t sched_fence_slab_ref;
+
 /**
  * A scheduler entity is a wrapper around a job queue or a group
  * of other entities. Entities take turns emitting jobs from their 
@@ -65,6 +70,7 @@ struct amd_sched_rq {
 struct amd_sched_fence {
        struct fence                    base;
        struct fence_cb                 cb;
+       struct list_head                scheduled_cb;
        struct amd_gpu_scheduler        *sched;
        spinlock_t                      lock;
        void                            *owner;
@@ -76,7 +82,6 @@ struct amd_sched_job {
        struct amd_gpu_scheduler        *sched;
        struct amd_sched_entity         *s_entity;
        struct amd_sched_fence          *s_fence;
-       void                            *owner;
 };
 
 extern const struct fence_ops amd_sched_fence_ops;
@@ -128,11 +133,11 @@ int amd_sched_entity_init(struct amd_gpu_scheduler *sched,
                          uint32_t jobs);
 void amd_sched_entity_fini(struct amd_gpu_scheduler *sched,
                           struct amd_sched_entity *entity);
-int amd_sched_entity_push_job(struct amd_sched_job *sched_job);
+void amd_sched_entity_push_job(struct amd_sched_job *sched_job);
 
 struct amd_sched_fence *amd_sched_fence_create(
        struct amd_sched_entity *s_entity, void *owner);
+void amd_sched_fence_scheduled(struct amd_sched_fence *fence);
 void amd_sched_fence_signal(struct amd_sched_fence *fence);
 
-
 #endif
index d802638094f4bb3817bb6612f1e37bf2479cf142..87c78eecea649a2112035db7fb66bb467cf6f457 100644 (file)
@@ -32,9 +32,11 @@ struct amd_sched_fence *amd_sched_fence_create(struct amd_sched_entity *s_entity
        struct amd_sched_fence *fence = NULL;
        unsigned seq;
 
-       fence = kzalloc(sizeof(struct amd_sched_fence), GFP_KERNEL);
+       fence = kmem_cache_zalloc(sched_fence_slab, GFP_KERNEL);
        if (fence == NULL)
                return NULL;
+
+       INIT_LIST_HEAD(&fence->scheduled_cb);
        fence->owner = owner;
        fence->sched = s_entity->sched;
        spin_lock_init(&fence->lock);
@@ -55,6 +57,17 @@ void amd_sched_fence_signal(struct amd_sched_fence *fence)
                FENCE_TRACE(&fence->base, "was already signaled\n");
 }
 
+void amd_sched_fence_scheduled(struct amd_sched_fence *s_fence)
+{
+       struct fence_cb *cur, *tmp;
+
+       set_bit(AMD_SCHED_FENCE_SCHEDULED_BIT, &s_fence->base.flags);
+       list_for_each_entry_safe(cur, tmp, &s_fence->scheduled_cb, node) {
+               list_del_init(&cur->node);
+               cur->func(&s_fence->base, cur);
+       }
+}
+
 static const char *amd_sched_fence_get_driver_name(struct fence *fence)
 {
        return "amd_sched";
@@ -71,11 +84,17 @@ static bool amd_sched_fence_enable_signaling(struct fence *f)
        return true;
 }
 
+static void amd_sched_fence_release(struct fence *f)
+{
+       struct amd_sched_fence *fence = to_amd_sched_fence(f);
+       kmem_cache_free(sched_fence_slab, fence);
+}
+
 const struct fence_ops amd_sched_fence_ops = {
        .get_driver_name = amd_sched_fence_get_driver_name,
        .get_timeline_name = amd_sched_fence_get_timeline_name,
        .enable_signaling = amd_sched_fence_enable_signaling,
        .signaled = NULL,
        .wait = fence_default_wait,
-       .release = NULL,
+       .release = amd_sched_fence_release,
 };
index 7bb3845d997492d5aa60092e7441f445d74e6104..aeee083c7f95064fed6c6b08cd67b58d174204af 100644 (file)
@@ -1432,6 +1432,45 @@ static int atomic_set_prop(struct drm_atomic_state *state,
        return ret;
 }
 
+/**
+ * drm_atomic_update_old_fb -- Unset old_fb pointers and set plane->fb pointers.
+ *
+ * @dev: drm device to check.
+ * @plane_mask: plane mask for planes that were updated.
+ * @ret: return value, can be -EDEADLK for a retry.
+ *
+ * Before doing an update plane->old_fb is set to plane->fb,
+ * but before dropping the locks old_fb needs to be set to NULL
+ * and plane->fb updated. This is a common operation for each
+ * atomic update, so this call is split off as a helper.
+ */
+void drm_atomic_clean_old_fb(struct drm_device *dev,
+                            unsigned plane_mask,
+                            int ret)
+{
+       struct drm_plane *plane;
+
+       /* if succeeded, fixup legacy plane crtc/fb ptrs before dropping
+        * locks (ie. while it is still safe to deref plane->state).  We
+        * need to do this here because the driver entry points cannot
+        * distinguish between legacy and atomic ioctls.
+        */
+       drm_for_each_plane_mask(plane, dev, plane_mask) {
+               if (ret == 0) {
+                       struct drm_framebuffer *new_fb = plane->state->fb;
+                       if (new_fb)
+                               drm_framebuffer_reference(new_fb);
+                       plane->fb = new_fb;
+                       plane->crtc = plane->state->crtc;
+
+                       if (plane->old_fb)
+                               drm_framebuffer_unreference(plane->old_fb);
+               }
+               plane->old_fb = NULL;
+       }
+}
+EXPORT_SYMBOL(drm_atomic_clean_old_fb);
+
 int drm_mode_atomic_ioctl(struct drm_device *dev,
                          void *data, struct drm_file *file_priv)
 {
@@ -1446,7 +1485,7 @@ int drm_mode_atomic_ioctl(struct drm_device *dev,
        struct drm_plane *plane;
        struct drm_crtc *crtc;
        struct drm_crtc_state *crtc_state;
-       unsigned plane_mask = 0;
+       unsigned plane_mask;
        int ret = 0;
        unsigned int i, j;
 
@@ -1486,6 +1525,7 @@ int drm_mode_atomic_ioctl(struct drm_device *dev,
        state->allow_modeset = !!(arg->flags & DRM_MODE_ATOMIC_ALLOW_MODESET);
 
 retry:
+       plane_mask = 0;
        copied_objs = 0;
        copied_props = 0;
 
@@ -1576,24 +1616,7 @@ retry:
        }
 
 out:
-       /* if succeeded, fixup legacy plane crtc/fb ptrs before dropping
-        * locks (ie. while it is still safe to deref plane->state).  We
-        * need to do this here because the driver entry points cannot
-        * distinguish between legacy and atomic ioctls.
-        */
-       drm_for_each_plane_mask(plane, dev, plane_mask) {
-               if (ret == 0) {
-                       struct drm_framebuffer *new_fb = plane->state->fb;
-                       if (new_fb)
-                               drm_framebuffer_reference(new_fb);
-                       plane->fb = new_fb;
-                       plane->crtc = plane->state->crtc;
-
-                       if (plane->old_fb)
-                               drm_framebuffer_unreference(plane->old_fb);
-               }
-               plane->old_fb = NULL;
-       }
+       drm_atomic_clean_old_fb(dev, plane_mask, ret);
 
        if (ret && arg->flags & DRM_MODE_PAGE_FLIP_EVENT) {
                /*
index 0c6f62168776ee378ff0906d2269cd10221fb535..e5aec45bf9855bfb18192e46b5a9dfd05eb0d170 100644 (file)
@@ -210,6 +210,14 @@ update_connector_routing(struct drm_atomic_state *state, int conn_idx)
                return -EINVAL;
        }
 
+       if (!drm_encoder_crtc_ok(new_encoder, connector_state->crtc)) {
+               DRM_DEBUG_ATOMIC("[ENCODER:%d:%s] incompatible with [CRTC:%d]\n",
+                                new_encoder->base.id,
+                                new_encoder->name,
+                                connector_state->crtc->base.id);
+               return -EINVAL;
+       }
+
        if (new_encoder == connector_state->best_encoder) {
                DRM_DEBUG_ATOMIC("[CONNECTOR:%d:%s] keeps [ENCODER:%d:%s], now on [CRTC:%d]\n",
                                 connector->base.id,
@@ -1553,6 +1561,9 @@ retry:
                goto fail;
        }
 
+       if (plane_state->crtc && (plane == plane->crtc->cursor))
+               plane_state->state->legacy_cursor_update = true;
+
        ret = __drm_atomic_helper_disable_plane(plane, plane_state);
        if (ret != 0)
                goto fail;
@@ -1605,9 +1616,6 @@ int __drm_atomic_helper_disable_plane(struct drm_plane *plane,
        plane_state->src_h = 0;
        plane_state->src_w = 0;
 
-       if (plane->crtc && (plane == plane->crtc->cursor))
-               plane_state->state->legacy_cursor_update = true;
-
        return 0;
 }
 
@@ -1741,6 +1749,7 @@ int __drm_atomic_helper_set_config(struct drm_mode_set *set,
        struct drm_crtc_state *crtc_state;
        struct drm_plane_state *primary_state;
        struct drm_crtc *crtc = set->crtc;
+       int hdisplay, vdisplay;
        int ret;
 
        crtc_state = drm_atomic_get_crtc_state(state, crtc);
@@ -1783,19 +1792,21 @@ int __drm_atomic_helper_set_config(struct drm_mode_set *set,
        if (ret != 0)
                return ret;
 
+       drm_crtc_get_hv_timing(set->mode, &hdisplay, &vdisplay);
+
        drm_atomic_set_fb_for_plane(primary_state, set->fb);
        primary_state->crtc_x = 0;
        primary_state->crtc_y = 0;
-       primary_state->crtc_h = set->mode->vdisplay;
-       primary_state->crtc_w = set->mode->hdisplay;
+       primary_state->crtc_h = vdisplay;
+       primary_state->crtc_w = hdisplay;
        primary_state->src_x = set->x << 16;
        primary_state->src_y = set->y << 16;
        if (primary_state->rotation & (BIT(DRM_ROTATE_90) | BIT(DRM_ROTATE_270))) {
-               primary_state->src_h = set->mode->hdisplay << 16;
-               primary_state->src_w = set->mode->vdisplay << 16;
+               primary_state->src_h = hdisplay << 16;
+               primary_state->src_w = vdisplay << 16;
        } else {
-               primary_state->src_h = set->mode->vdisplay << 16;
-               primary_state->src_w = set->mode->hdisplay << 16;
+               primary_state->src_h = vdisplay << 16;
+               primary_state->src_w = hdisplay << 16;
        }
 
 commit:
index 9362609df38ae4077ae934d96f5098ffaabd59dd..7dd6728dd092e23af63516295be42331bcc1f3c8 100644 (file)
@@ -160,6 +160,11 @@ int drm_setmaster_ioctl(struct drm_device *dev, void *data,
                goto out_unlock;
        }
 
+       if (!file_priv->allowed_master) {
+               ret = drm_new_set_master(dev, file_priv);
+               goto out_unlock;
+       }
+
        file_priv->minor->master = drm_master_get(file_priv->master);
        file_priv->is_master = 1;
        if (dev->driver->master_set) {
index e673c13c7391153d6c7f3c54b7c56a0e17d26bca..69cbab5e5c81f29008247776d81447f21aede835 100644 (file)
@@ -342,6 +342,7 @@ static int restore_fbdev_mode_atomic(struct drm_fb_helper *fb_helper)
        struct drm_plane *plane;
        struct drm_atomic_state *state;
        int i, ret;
+       unsigned plane_mask;
 
        state = drm_atomic_state_alloc(dev);
        if (!state)
@@ -349,11 +350,10 @@ static int restore_fbdev_mode_atomic(struct drm_fb_helper *fb_helper)
 
        state->acquire_ctx = dev->mode_config.acquire_ctx;
 retry:
+       plane_mask = 0;
        drm_for_each_plane(plane, dev) {
                struct drm_plane_state *plane_state;
 
-               plane->old_fb = plane->fb;
-
                plane_state = drm_atomic_get_plane_state(state, plane);
                if (IS_ERR(plane_state)) {
                        ret = PTR_ERR(plane_state);
@@ -362,6 +362,9 @@ retry:
 
                plane_state->rotation = BIT(DRM_ROTATE_0);
 
+               plane->old_fb = plane->fb;
+               plane_mask |= 1 << drm_plane_index(plane);
+
                /* disable non-primary: */
                if (plane->type == DRM_PLANE_TYPE_PRIMARY)
                        continue;
@@ -382,19 +385,7 @@ retry:
        ret = drm_atomic_commit(state);
 
 fail:
-       drm_for_each_plane(plane, dev) {
-               if (ret == 0) {
-                       struct drm_framebuffer *new_fb = plane->state->fb;
-                       if (new_fb)
-                               drm_framebuffer_reference(new_fb);
-                       plane->fb = new_fb;
-                       plane->crtc = plane->state->crtc;
-
-                       if (plane->old_fb)
-                               drm_framebuffer_unreference(plane->old_fb);
-               }
-               plane->old_fb = NULL;
-       }
+       drm_atomic_clean_old_fb(dev, plane_mask, ret);
 
        if (ret == -EDEADLK)
                goto backoff;
@@ -1236,7 +1227,9 @@ static int pan_display_atomic(struct fb_var_screeninfo *var,
        struct drm_fb_helper *fb_helper = info->par;
        struct drm_device *dev = fb_helper->dev;
        struct drm_atomic_state *state;
+       struct drm_plane *plane;
        int i, ret;
+       unsigned plane_mask;
 
        state = drm_atomic_state_alloc(dev);
        if (!state)
@@ -1244,19 +1237,22 @@ static int pan_display_atomic(struct fb_var_screeninfo *var,
 
        state->acquire_ctx = dev->mode_config.acquire_ctx;
 retry:
+       plane_mask = 0;
        for(i = 0; i < fb_helper->crtc_count; i++) {
                struct drm_mode_set *mode_set;
 
                mode_set = &fb_helper->crtc_info[i].mode_set;
 
-               mode_set->crtc->primary->old_fb = mode_set->crtc->primary->fb;
-
                mode_set->x = var->xoffset;
                mode_set->y = var->yoffset;
 
                ret = __drm_atomic_helper_set_config(mode_set, state);
                if (ret != 0)
                        goto fail;
+
+               plane = mode_set->crtc->primary;
+               plane_mask |= drm_plane_index(plane);
+               plane->old_fb = plane->fb;
        }
 
        ret = drm_atomic_commit(state);
@@ -1268,26 +1264,7 @@ retry:
 
 
 fail:
-       for(i = 0; i < fb_helper->crtc_count; i++) {
-               struct drm_mode_set *mode_set;
-               struct drm_plane *plane;
-
-               mode_set = &fb_helper->crtc_info[i].mode_set;
-               plane = mode_set->crtc->primary;
-
-               if (ret == 0) {
-                       struct drm_framebuffer *new_fb = plane->state->fb;
-
-                       if (new_fb)
-                               drm_framebuffer_reference(new_fb);
-                       plane->fb = new_fb;
-                       plane->crtc = plane->state->crtc;
-
-                       if (plane->old_fb)
-                               drm_framebuffer_unreference(plane->old_fb);
-               }
-               plane->old_fb = NULL;
-       }
+       drm_atomic_clean_old_fb(dev, plane_mask, ret);
 
        if (ret == -EDEADLK)
                goto backoff;
index c59ce4d0ef75f4e878ad5964c90e86afd2467456..6b5625e6611975735a1bd4c218edd3cfa9ec5e69 100644 (file)
@@ -125,6 +125,60 @@ static int drm_cpu_valid(void)
        return 1;
 }
 
+/**
+ * drm_new_set_master - Allocate a new master object and become master for the
+ * associated master realm.
+ *
+ * @dev: The associated device.
+ * @fpriv: File private identifying the client.
+ *
+ * This function must be called with dev::struct_mutex held.
+ * Returns negative error code on failure. Zero on success.
+ */
+int drm_new_set_master(struct drm_device *dev, struct drm_file *fpriv)
+{
+       struct drm_master *old_master;
+       int ret;
+
+       lockdep_assert_held_once(&dev->master_mutex);
+
+       /* create a new master */
+       fpriv->minor->master = drm_master_create(fpriv->minor);
+       if (!fpriv->minor->master)
+               return -ENOMEM;
+
+       /* take another reference for the copy in the local file priv */
+       old_master = fpriv->master;
+       fpriv->master = drm_master_get(fpriv->minor->master);
+
+       if (dev->driver->master_create) {
+               ret = dev->driver->master_create(dev, fpriv->master);
+               if (ret)
+                       goto out_err;
+       }
+       if (dev->driver->master_set) {
+               ret = dev->driver->master_set(dev, fpriv, true);
+               if (ret)
+                       goto out_err;
+       }
+
+       fpriv->is_master = 1;
+       fpriv->allowed_master = 1;
+       fpriv->authenticated = 1;
+       if (old_master)
+               drm_master_put(&old_master);
+
+       return 0;
+
+out_err:
+       /* drop both references and restore old master on failure */
+       drm_master_put(&fpriv->minor->master);
+       drm_master_put(&fpriv->master);
+       fpriv->master = old_master;
+
+       return ret;
+}
+
 /**
  * Called whenever a process opens /dev/drm.
  *
@@ -189,35 +243,9 @@ static int drm_open_helper(struct file *filp, struct drm_minor *minor)
        mutex_lock(&dev->master_mutex);
        if (drm_is_primary_client(priv) && !priv->minor->master) {
                /* create a new master */
-               priv->minor->master = drm_master_create(priv->minor);
-               if (!priv->minor->master) {
-                       ret = -ENOMEM;
+               ret = drm_new_set_master(dev, priv);
+               if (ret)
                        goto out_close;
-               }
-
-               priv->is_master = 1;
-               /* take another reference for the copy in the local file priv */
-               priv->master = drm_master_get(priv->minor->master);
-               priv->authenticated = 1;
-
-               if (dev->driver->master_create) {
-                       ret = dev->driver->master_create(dev, priv->master);
-                       if (ret) {
-                               /* drop both references if this fails */
-                               drm_master_put(&priv->minor->master);
-                               drm_master_put(&priv->master);
-                               goto out_close;
-                       }
-               }
-               if (dev->driver->master_set) {
-                       ret = dev->driver->master_set(dev, priv, true);
-                       if (ret) {
-                               /* drop both references if this fails */
-                               drm_master_put(&priv->minor->master);
-                               drm_master_put(&priv->master);
-                               goto out_close;
-                       }
-               }
        } else if (drm_is_primary_client(priv)) {
                /* get a reference to the master */
                priv->master = drm_master_get(priv->minor->master);
index 2151ea551d3bd6526d850754b79ece388a9279df..607f493ae80132890ad97422f58f9cdf95eefc75 100644 (file)
@@ -980,7 +980,8 @@ static void send_vblank_event(struct drm_device *dev,
                struct drm_pending_vblank_event *e,
                unsigned long seq, struct timeval *now)
 {
-       WARN_ON_SMP(!spin_is_locked(&dev->event_lock));
+       assert_spin_locked(&dev->event_lock);
+
        e->event.sequence = seq;
        e->event.tv_sec = now->tv_sec;
        e->event.tv_usec = now->tv_usec;
@@ -992,6 +993,57 @@ static void send_vblank_event(struct drm_device *dev,
                                         e->event.sequence);
 }
 
+/**
+ * drm_arm_vblank_event - arm vblank event after pageflip
+ * @dev: DRM device
+ * @pipe: CRTC index
+ * @e: the event to prepare to send
+ *
+ * A lot of drivers need to generate vblank events for the very next vblank
+ * interrupt. For example when the page flip interrupt happens when the page
+ * flip gets armed, but not when it actually executes within the next vblank
+ * period. This helper function implements exactly the required vblank arming
+ * behaviour.
+ *
+ * Caller must hold event lock. Caller must also hold a vblank reference for
+ * the event @e, which will be dropped when the next vblank arrives.
+ *
+ * This is the legacy version of drm_crtc_arm_vblank_event().
+ */
+void drm_arm_vblank_event(struct drm_device *dev, unsigned int pipe,
+                         struct drm_pending_vblank_event *e)
+{
+       assert_spin_locked(&dev->event_lock);
+
+       e->pipe = pipe;
+       e->event.sequence = drm_vblank_count(dev, pipe);
+       list_add_tail(&e->base.link, &dev->vblank_event_list);
+}
+EXPORT_SYMBOL(drm_arm_vblank_event);
+
+/**
+ * drm_crtc_arm_vblank_event - arm vblank event after pageflip
+ * @crtc: the source CRTC of the vblank event
+ * @e: the event to send
+ *
+ * A lot of drivers need to generate vblank events for the very next vblank
+ * interrupt. For example when the page flip interrupt happens when the page
+ * flip gets armed, but not when it actually executes within the next vblank
+ * period. This helper function implements exactly the required vblank arming
+ * behaviour.
+ *
+ * Caller must hold event lock. Caller must also hold a vblank reference for
+ * the event @e, which will be dropped when the next vblank arrives.
+ *
+ * This is the native KMS version of drm_arm_vblank_event().
+ */
+void drm_crtc_arm_vblank_event(struct drm_crtc *crtc,
+                              struct drm_pending_vblank_event *e)
+{
+       drm_arm_vblank_event(crtc->dev, drm_crtc_index(crtc), e);
+}
+EXPORT_SYMBOL(drm_crtc_arm_vblank_event);
+
 /**
  * drm_send_vblank_event - helper to send vblank event after pageflip
  * @dev: DRM device
index a18164f2f6d28290c09462dd7a755168873a42d3..f8b5fcfa91a27521d40e52b818b15dc3c6a6bbaf 100644 (file)
@@ -229,7 +229,8 @@ static int drm_helper_probe_single_connector_modes_merge_bits(struct drm_connect
                mode_flags |= DRM_MODE_FLAG_3D_MASK;
 
        list_for_each_entry(mode, &connector->modes, head) {
-               mode->status = drm_mode_validate_basic(mode);
+               if (mode->status == MODE_OK)
+                       mode->status = drm_mode_validate_basic(mode);
 
                if (mode->status == MODE_OK)
                        mode->status = drm_mode_validate_size(mode, maxX, maxY);
index b3ba27fd9a6bc880d7e061039e61ca42babc148f..e69357172ffb56d2e5f5e86ff551b599196079ba 100644 (file)
@@ -55,6 +55,9 @@ static int exynos_crtc_atomic_check(struct drm_crtc *crtc,
 {
        struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(crtc);
 
+       if (!state->enable)
+               return 0;
+
        if (exynos_crtc->ops->atomic_check)
                return exynos_crtc->ops->atomic_check(exynos_crtc, state);
 
index a3b22bdacd44f539a81429d7e1946d86d8cb4f78..8aab974b0564c4a8bef46a6a05d5c200831d70f6 100644 (file)
@@ -2734,6 +2734,8 @@ static const char *power_domain_str(enum intel_display_power_domain domain)
                return "AUX_C";
        case POWER_DOMAIN_AUX_D:
                return "AUX_D";
+       case POWER_DOMAIN_GMBUS:
+               return "GMBUS";
        case POWER_DOMAIN_INIT:
                return "INIT";
        default:
index 8afda459a26e290fa218450c074089356ce31efb..f4af19a0d5696324c307617adfb0c86a3fdfed38 100644 (file)
@@ -199,6 +199,7 @@ enum intel_display_power_domain {
        POWER_DOMAIN_AUX_B,
        POWER_DOMAIN_AUX_C,
        POWER_DOMAIN_AUX_D,
+       POWER_DOMAIN_GMBUS,
        POWER_DOMAIN_INIT,
 
        POWER_DOMAIN_NUM,
@@ -351,6 +352,8 @@ enum intel_dpll_id {
        /* hsw/bdw */
        DPLL_ID_WRPLL1 = 0,
        DPLL_ID_WRPLL2 = 1,
+       DPLL_ID_SPLL = 2,
+
        /* skl */
        DPLL_ID_SKL_DPLL1 = 0,
        DPLL_ID_SKL_DPLL2 = 1,
@@ -367,6 +370,7 @@ struct intel_dpll_hw_state {
 
        /* hsw, bdw */
        uint32_t wrpll;
+       uint32_t spll;
 
        /* skl */
        /*
@@ -2189,8 +2193,17 @@ struct drm_i915_gem_request {
        struct drm_i915_private *i915;
        struct intel_engine_cs *ring;
 
-       /** GEM sequence number associated with this request. */
-       uint32_t seqno;
+        /** GEM sequence number associated with the previous request,
+         * when the HWS breadcrumb is equal to this the GPU is processing
+         * this request.
+         */
+       u32 previous_seqno;
+
+        /** GEM sequence number associated with this request,
+         * when the HWS breadcrumb is equal or greater than this the GPU
+         * has finished processing this request.
+         */
+       u32 seqno;
 
        /** Position in the ringbuffer of the start of the request */
        u32 head;
@@ -2648,6 +2661,7 @@ struct i915_params {
        int enable_cmd_parser;
        /* leave bools at the end to not create holes */
        bool enable_hangcheck;
+       bool fastboot;
        bool prefault_disable;
        bool load_detect_test;
        bool reset;
@@ -2834,6 +2848,7 @@ i915_gem_object_ggtt_pin(struct drm_i915_gem_object *obj,
 
 int i915_vma_bind(struct i915_vma *vma, enum i915_cache_level cache_level,
                  u32 flags);
+void __i915_vma_set_map_and_fenceable(struct i915_vma *vma);
 int __must_check i915_vma_unbind(struct i915_vma *vma);
 /*
  * BEWARE: Do not use the function below unless you can _absolutely_
@@ -2905,15 +2920,17 @@ i915_seqno_passed(uint32_t seq1, uint32_t seq2)
        return (int32_t)(seq1 - seq2) >= 0;
 }
 
+static inline bool i915_gem_request_started(struct drm_i915_gem_request *req,
+                                          bool lazy_coherency)
+{
+       u32 seqno = req->ring->get_seqno(req->ring, lazy_coherency);
+       return i915_seqno_passed(seqno, req->previous_seqno);
+}
+
 static inline bool i915_gem_request_completed(struct drm_i915_gem_request *req,
                                              bool lazy_coherency)
 {
-       u32 seqno;
-
-       BUG_ON(req == NULL);
-
-       seqno = req->ring->get_seqno(req->ring, lazy_coherency);
-
+       u32 seqno = req->ring->get_seqno(req->ring, lazy_coherency);
        return i915_seqno_passed(seqno, req->seqno);
 }
 
index 5cf4a1998273c3cfcc494c83210c0bc572f35c2e..f56af0aaafde511c1add59ce5f89fe2fa9be5c42 100644 (file)
@@ -1146,23 +1146,74 @@ static bool missed_irq(struct drm_i915_private *dev_priv,
        return test_bit(ring->id, &dev_priv->gpu_error.missed_irq_rings);
 }
 
-static int __i915_spin_request(struct drm_i915_gem_request *req)
+static unsigned long local_clock_us(unsigned *cpu)
+{
+       unsigned long t;
+
+       /* Cheaply and approximately convert from nanoseconds to microseconds.
+        * The result and subsequent calculations are also defined in the same
+        * approximate microseconds units. The principal source of timing
+        * error here is from the simple truncation.
+        *
+        * Note that local_clock() is only defined wrt to the current CPU;
+        * the comparisons are no longer valid if we switch CPUs. Instead of
+        * blocking preemption for the entire busywait, we can detect the CPU
+        * switch and use that as indicator of system load and a reason to
+        * stop busywaiting, see busywait_stop().
+        */
+       *cpu = get_cpu();
+       t = local_clock() >> 10;
+       put_cpu();
+
+       return t;
+}
+
+static bool busywait_stop(unsigned long timeout, unsigned cpu)
+{
+       unsigned this_cpu;
+
+       if (time_after(local_clock_us(&this_cpu), timeout))
+               return true;
+
+       return this_cpu != cpu;
+}
+
+static int __i915_spin_request(struct drm_i915_gem_request *req, int state)
 {
        unsigned long timeout;
+       unsigned cpu;
+
+       /* When waiting for high frequency requests, e.g. during synchronous
+        * rendering split between the CPU and GPU, the finite amount of time
+        * required to set up the irq and wait upon it limits the response
+        * rate. By busywaiting on the request completion for a short while we
+        * can service the high frequency waits as quick as possible. However,
+        * if it is a slow request, we want to sleep as quickly as possible.
+        * The tradeoff between waiting and sleeping is roughly the time it
+        * takes to sleep on a request, on the order of a microsecond.
+        */
 
-       if (i915_gem_request_get_ring(req)->irq_refcount)
+       if (req->ring->irq_refcount)
                return -EBUSY;
 
-       timeout = jiffies + 1;
+       /* Only spin if we know the GPU is processing this request */
+       if (!i915_gem_request_started(req, true))
+               return -EAGAIN;
+
+       timeout = local_clock_us(&cpu) + 5;
        while (!need_resched()) {
                if (i915_gem_request_completed(req, true))
                        return 0;
 
-               if (time_after_eq(jiffies, timeout))
+               if (signal_pending_state(state, current))
+                       break;
+
+               if (busywait_stop(timeout, cpu))
                        break;
 
                cpu_relax_lowlatency();
        }
+
        if (i915_gem_request_completed(req, false))
                return 0;
 
@@ -1197,6 +1248,7 @@ int __i915_wait_request(struct drm_i915_gem_request *req,
        struct drm_i915_private *dev_priv = dev->dev_private;
        const bool irq_test_in_progress =
                ACCESS_ONCE(dev_priv->gpu_error.test_irq_rings) & intel_ring_flag(ring);
+       int state = interruptible ? TASK_INTERRUPTIBLE : TASK_UNINTERRUPTIBLE;
        DEFINE_WAIT(wait);
        unsigned long timeout_expire;
        s64 before, now;
@@ -1210,8 +1262,16 @@ int __i915_wait_request(struct drm_i915_gem_request *req,
        if (i915_gem_request_completed(req, true))
                return 0;
 
-       timeout_expire = timeout ?
-               jiffies + nsecs_to_jiffies_timeout((u64)*timeout) : 0;
+       timeout_expire = 0;
+       if (timeout) {
+               if (WARN_ON(*timeout < 0))
+                       return -EINVAL;
+
+               if (*timeout == 0)
+                       return -ETIME;
+
+               timeout_expire = jiffies + nsecs_to_jiffies_timeout(*timeout);
+       }
 
        if (INTEL_INFO(dev_priv)->gen >= 6)
                gen6_rps_boost(dev_priv, rps, req->emitted_jiffies);
@@ -1221,7 +1281,7 @@ int __i915_wait_request(struct drm_i915_gem_request *req,
        before = ktime_get_raw_ns();
 
        /* Optimistic spin for the next jiffie before touching IRQs */
-       ret = __i915_spin_request(req);
+       ret = __i915_spin_request(req, state);
        if (ret == 0)
                goto out;
 
@@ -1233,8 +1293,7 @@ int __i915_wait_request(struct drm_i915_gem_request *req,
        for (;;) {
                struct timer_list timer;
 
-               prepare_to_wait(&ring->irq_queue, &wait,
-                               interruptible ? TASK_INTERRUPTIBLE : TASK_UNINTERRUPTIBLE);
+               prepare_to_wait(&ring->irq_queue, &wait, state);
 
                /* We need to check whether any gpu reset happened in between
                 * the caller grabbing the seqno and now ... */
@@ -1252,7 +1311,7 @@ int __i915_wait_request(struct drm_i915_gem_request *req,
                        break;
                }
 
-               if (interruptible && signal_pending(current)) {
+               if (signal_pending_state(state, current)) {
                        ret = -ERESTARTSYS;
                        break;
                }
@@ -2546,6 +2605,7 @@ void __i915_add_request(struct drm_i915_gem_request *request,
        request->batch_obj = obj;
 
        request->emitted_jiffies = jiffies;
+       request->previous_seqno = ring->last_submitted_seqno;
        ring->last_submitted_seqno = request->seqno;
        list_add_tail(&request->list, &ring->request_list);
 
@@ -3809,6 +3869,7 @@ int i915_gem_get_caching_ioctl(struct drm_device *dev, void *data,
 int i915_gem_set_caching_ioctl(struct drm_device *dev, void *data,
                               struct drm_file *file)
 {
+       struct drm_i915_private *dev_priv = dev->dev_private;
        struct drm_i915_gem_caching *args = data;
        struct drm_i915_gem_object *obj;
        enum i915_cache_level level;
@@ -3837,9 +3898,11 @@ int i915_gem_set_caching_ioctl(struct drm_device *dev, void *data,
                return -EINVAL;
        }
 
+       intel_runtime_pm_get(dev_priv);
+
        ret = i915_mutex_lock_interruptible(dev);
        if (ret)
-               return ret;
+               goto rpm_put;
 
        obj = to_intel_bo(drm_gem_object_lookup(dev, file, args->handle));
        if (&obj->base == NULL) {
@@ -3852,6 +3915,9 @@ int i915_gem_set_caching_ioctl(struct drm_device *dev, void *data,
        drm_gem_object_unreference(&obj->base);
 unlock:
        mutex_unlock(&dev->struct_mutex);
+rpm_put:
+       intel_runtime_pm_put(dev_priv);
+
        return ret;
 }
 
@@ -4066,6 +4132,29 @@ i915_vma_misplaced(struct i915_vma *vma, uint32_t alignment, uint64_t flags)
        return false;
 }
 
+void __i915_vma_set_map_and_fenceable(struct i915_vma *vma)
+{
+       struct drm_i915_gem_object *obj = vma->obj;
+       bool mappable, fenceable;
+       u32 fence_size, fence_alignment;
+
+       fence_size = i915_gem_get_gtt_size(obj->base.dev,
+                                          obj->base.size,
+                                          obj->tiling_mode);
+       fence_alignment = i915_gem_get_gtt_alignment(obj->base.dev,
+                                                    obj->base.size,
+                                                    obj->tiling_mode,
+                                                    true);
+
+       fenceable = (vma->node.size == fence_size &&
+                    (vma->node.start & (fence_alignment - 1)) == 0);
+
+       mappable = (vma->node.start + fence_size <=
+                   to_i915(obj->base.dev)->gtt.mappable_end);
+
+       obj->map_and_fenceable = mappable && fenceable;
+}
+
 static int
 i915_gem_object_do_pin(struct drm_i915_gem_object *obj,
                       struct i915_address_space *vm,
@@ -4133,25 +4222,7 @@ i915_gem_object_do_pin(struct drm_i915_gem_object *obj,
 
        if (ggtt_view && ggtt_view->type == I915_GGTT_VIEW_NORMAL &&
            (bound ^ vma->bound) & GLOBAL_BIND) {
-               bool mappable, fenceable;
-               u32 fence_size, fence_alignment;
-
-               fence_size = i915_gem_get_gtt_size(obj->base.dev,
-                                                  obj->base.size,
-                                                  obj->tiling_mode);
-               fence_alignment = i915_gem_get_gtt_alignment(obj->base.dev,
-                                                            obj->base.size,
-                                                            obj->tiling_mode,
-                                                            true);
-
-               fenceable = (vma->node.size == fence_size &&
-                            (vma->node.start & (fence_alignment - 1)) == 0);
-
-               mappable = (vma->node.start + fence_size <=
-                           dev_priv->gtt.mappable_end);
-
-               obj->map_and_fenceable = mappable && fenceable;
-
+               __i915_vma_set_map_and_fenceable(vma);
                WARN_ON(flags & PIN_MAPPABLE && !obj->map_and_fenceable);
        }
 
index 8c688a5f1589316b3f303d9a5b90857af7e112f8..02ceb7a4b4815e52a825a290aa8e6d2cd78d25b5 100644 (file)
@@ -141,8 +141,6 @@ static void i915_gem_context_clean(struct intel_context *ctx)
        if (!ppgtt)
                return;
 
-       WARN_ON(!list_empty(&ppgtt->base.active_list));
-
        list_for_each_entry_safe(vma, next, &ppgtt->base.inactive_list,
                                 mm_list) {
                if (WARN_ON(__i915_vma_unbind_no_wait(vma)))
index 40a10b25956c2a26fc75500d2e10a77b639e43fb..f010391b87f5cd0803c7bc994f8b44fd68a5e9b6 100644 (file)
@@ -642,11 +642,10 @@ i915_gem_detect_bit_6_swizzle(struct drm_device *dev)
                }
 
                /* check for L-shaped memory aka modified enhanced addressing */
-               if (IS_GEN4(dev)) {
-                       uint32_t ddc2 = I915_READ(DCC2);
-
-                       if (!(ddc2 & DCC2_MODIFIED_ENHANCED_DISABLE))
-                               dev_priv->quirks |= QUIRK_PIN_SWIZZLED_PAGES;
+               if (IS_GEN4(dev) &&
+                   !(I915_READ(DCC2) & DCC2_MODIFIED_ENHANCED_DISABLE)) {
+                       swizzle_x = I915_BIT_6_SWIZZLE_UNKNOWN;
+                       swizzle_y = I915_BIT_6_SWIZZLE_UNKNOWN;
                }
 
                if (dcc == 0xffffffff) {
@@ -675,16 +674,35 @@ i915_gem_detect_bit_6_swizzle(struct drm_device *dev)
                 * matching, which was the case for the swizzling required in
                 * the table above, or from the 1-ch value being less than
                 * the minimum size of a rank.
+                *
+                * Reports indicate that the swizzling actually
+                * varies depending upon page placement inside the
+                * channels, i.e. we see swizzled pages where the
+                * banks of memory are paired and unswizzled on the
+                * uneven portion, so leave that as unknown.
                 */
-               if (I915_READ16(C0DRB3) != I915_READ16(C1DRB3)) {
-                       swizzle_x = I915_BIT_6_SWIZZLE_NONE;
-                       swizzle_y = I915_BIT_6_SWIZZLE_NONE;
-               } else {
+               if (I915_READ16(C0DRB3) == I915_READ16(C1DRB3)) {
                        swizzle_x = I915_BIT_6_SWIZZLE_9_10;
                        swizzle_y = I915_BIT_6_SWIZZLE_9;
                }
        }
 
+       if (swizzle_x == I915_BIT_6_SWIZZLE_UNKNOWN ||
+           swizzle_y == I915_BIT_6_SWIZZLE_UNKNOWN) {
+               /* Userspace likes to explode if it sees unknown swizzling,
+                * so lie. We will finish the lie when reporting through
+                * the get-tiling-ioctl by reporting the physical swizzle
+                * mode as unknown instead.
+                *
+                * As we don't strictly know what the swizzling is, it may be
+                * bit17 dependent, and so we need to also prevent the pages
+                * from being moved.
+                */
+               dev_priv->quirks |= QUIRK_PIN_SWIZZLED_PAGES;
+               swizzle_x = I915_BIT_6_SWIZZLE_NONE;
+               swizzle_y = I915_BIT_6_SWIZZLE_NONE;
+       }
+
        dev_priv->mm.bit_6_swizzle_x = swizzle_x;
        dev_priv->mm.bit_6_swizzle_y = swizzle_y;
 }
index 43f35d12b677606d43b96cedc3cae476067946ab..86c7500454b4d1b3928dc41f37ab9aa6917fd557 100644 (file)
@@ -2676,6 +2676,7 @@ static int i915_gem_setup_global_gtt(struct drm_device *dev,
                        return ret;
                }
                vma->bound |= GLOBAL_BIND;
+               __i915_vma_set_map_and_fenceable(vma);
                list_add_tail(&vma->mm_list, &ggtt_vm->inactive_list);
        }
 
index cdacf3f5b77a571086024deae067bf32edc3a988..87e919a06b277fea6cfade79445a165bac925056 100644 (file)
@@ -687,6 +687,7 @@ i915_gem_object_create_stolen_for_preallocated(struct drm_device *dev,
                }
 
                vma->bound |= GLOBAL_BIND;
+               __i915_vma_set_map_and_fenceable(vma);
                list_add_tail(&vma->mm_list, &ggtt->inactive_list);
        }
 
index 96bb23865eac7a6acf3a731c0c5ecc8bbd25a4e5..4be13a5eb932797b233911c1935d1233dc9354c7 100644 (file)
@@ -40,6 +40,7 @@ struct i915_params i915 __read_mostly = {
        .preliminary_hw_support = IS_ENABLED(CONFIG_DRM_I915_PRELIMINARY_HW_SUPPORT),
        .disable_power_well = -1,
        .enable_ips = 1,
+       .fastboot = 0,
        .prefault_disable = 0,
        .load_detect_test = 0,
        .reset = true,
@@ -133,6 +134,10 @@ MODULE_PARM_DESC(disable_power_well,
 module_param_named_unsafe(enable_ips, i915.enable_ips, int, 0600);
 MODULE_PARM_DESC(enable_ips, "Enable IPS (default: true)");
 
+module_param_named(fastboot, i915.fastboot, bool, 0600);
+MODULE_PARM_DESC(fastboot,
+       "Try to skip unnecessary mode sets at boot time (default: false)");
+
 module_param_named_unsafe(prefault_disable, i915.prefault_disable, bool, 0600);
 MODULE_PARM_DESC(prefault_disable,
        "Disable page prefaulting for pread/pwrite/reloc (default:false). "
index b84aaa0bb48a228aa297756c85b132c9790f0eb6..6a2c76e367a5dc327e45691e4ff0ddf6294471ea 100644 (file)
@@ -138,18 +138,6 @@ static void hsw_crt_get_config(struct intel_encoder *encoder,
        pipe_config->base.adjusted_mode.flags |= intel_crt_get_flags(encoder);
 }
 
-static void hsw_crt_pre_enable(struct intel_encoder *encoder)
-{
-       struct drm_device *dev = encoder->base.dev;
-       struct drm_i915_private *dev_priv = dev->dev_private;
-
-       WARN(I915_READ(SPLL_CTL) & SPLL_PLL_ENABLE, "SPLL already enabled\n");
-       I915_WRITE(SPLL_CTL,
-                  SPLL_PLL_ENABLE | SPLL_PLL_FREQ_1350MHz | SPLL_PLL_SSC);
-       POSTING_READ(SPLL_CTL);
-       udelay(20);
-}
-
 /* Note: The caller is required to filter out dpms modes not supported by the
  * platform. */
 static void intel_crt_set_dpms(struct intel_encoder *encoder, int mode)
@@ -216,19 +204,6 @@ static void pch_post_disable_crt(struct intel_encoder *encoder)
        intel_disable_crt(encoder);
 }
 
-static void hsw_crt_post_disable(struct intel_encoder *encoder)
-{
-       struct drm_device *dev = encoder->base.dev;
-       struct drm_i915_private *dev_priv = dev->dev_private;
-       uint32_t val;
-
-       DRM_DEBUG_KMS("Disabling SPLL\n");
-       val = I915_READ(SPLL_CTL);
-       WARN_ON(!(val & SPLL_PLL_ENABLE));
-       I915_WRITE(SPLL_CTL, val & ~SPLL_PLL_ENABLE);
-       POSTING_READ(SPLL_CTL);
-}
-
 static void intel_enable_crt(struct intel_encoder *encoder)
 {
        struct intel_crt *crt = intel_encoder_to_crt(encoder);
@@ -280,6 +255,10 @@ static bool intel_crt_compute_config(struct intel_encoder *encoder,
        if (HAS_DDI(dev)) {
                pipe_config->ddi_pll_sel = PORT_CLK_SEL_SPLL;
                pipe_config->port_clock = 135000 * 2;
+
+               pipe_config->dpll_hw_state.wrpll = 0;
+               pipe_config->dpll_hw_state.spll =
+                       SPLL_PLL_ENABLE | SPLL_PLL_FREQ_1350MHz | SPLL_PLL_SSC;
        }
 
        return true;
@@ -860,8 +839,6 @@ void intel_crt_init(struct drm_device *dev)
        if (HAS_DDI(dev)) {
                crt->base.get_config = hsw_crt_get_config;
                crt->base.get_hw_state = intel_ddi_get_hw_state;
-               crt->base.pre_enable = hsw_crt_pre_enable;
-               crt->base.post_disable = hsw_crt_post_disable;
        } else {
                crt->base.get_config = intel_crt_get_config;
                crt->base.get_hw_state = intel_crt_get_hw_state;
index b25e99a432fbd3af325770b0a669d27ede78952b..a6752a61d99f268217e7054a8531036d109be7ee 100644 (file)
@@ -1286,6 +1286,18 @@ hsw_ddi_pll_select(struct intel_crtc *intel_crtc,
                }
 
                crtc_state->ddi_pll_sel = PORT_CLK_SEL_WRPLL(pll->id);
+       } else if (crtc_state->ddi_pll_sel == PORT_CLK_SEL_SPLL) {
+               struct drm_atomic_state *state = crtc_state->base.state;
+               struct intel_shared_dpll_config *spll =
+                       &intel_atomic_get_shared_dpll_state(state)[DPLL_ID_SPLL];
+
+               if (spll->crtc_mask &&
+                   WARN_ON(spll->hw_state.spll != crtc_state->dpll_hw_state.spll))
+                       return false;
+
+               crtc_state->shared_dpll = DPLL_ID_SPLL;
+               spll->hw_state.spll = crtc_state->dpll_hw_state.spll;
+               spll->crtc_mask |= 1 << intel_crtc->pipe;
        }
 
        return true;
@@ -2437,7 +2449,7 @@ static void intel_disable_ddi(struct intel_encoder *intel_encoder)
        }
 }
 
-static void hsw_ddi_pll_enable(struct drm_i915_private *dev_priv,
+static void hsw_ddi_wrpll_enable(struct drm_i915_private *dev_priv,
                               struct intel_shared_dpll *pll)
 {
        I915_WRITE(WRPLL_CTL(pll->id), pll->config.hw_state.wrpll);
@@ -2445,8 +2457,16 @@ static void hsw_ddi_pll_enable(struct drm_i915_private *dev_priv,
        udelay(20);
 }
 
-static void hsw_ddi_pll_disable(struct drm_i915_private *dev_priv,
+static void hsw_ddi_spll_enable(struct drm_i915_private *dev_priv,
                                struct intel_shared_dpll *pll)
+{
+       I915_WRITE(SPLL_CTL, pll->config.hw_state.spll);
+       POSTING_READ(SPLL_CTL);
+       udelay(20);
+}
+
+static void hsw_ddi_wrpll_disable(struct drm_i915_private *dev_priv,
+                                 struct intel_shared_dpll *pll)
 {
        uint32_t val;
 
@@ -2455,9 +2475,19 @@ static void hsw_ddi_pll_disable(struct drm_i915_private *dev_priv,
        POSTING_READ(WRPLL_CTL(pll->id));
 }
 
-static bool hsw_ddi_pll_get_hw_state(struct drm_i915_private *dev_priv,
-                                    struct intel_shared_dpll *pll,
-                                    struct intel_dpll_hw_state *hw_state)
+static void hsw_ddi_spll_disable(struct drm_i915_private *dev_priv,
+                                struct intel_shared_dpll *pll)
+{
+       uint32_t val;
+
+       val = I915_READ(SPLL_CTL);
+       I915_WRITE(SPLL_CTL, val & ~SPLL_PLL_ENABLE);
+       POSTING_READ(SPLL_CTL);
+}
+
+static bool hsw_ddi_wrpll_get_hw_state(struct drm_i915_private *dev_priv,
+                                      struct intel_shared_dpll *pll,
+                                      struct intel_dpll_hw_state *hw_state)
 {
        uint32_t val;
 
@@ -2470,25 +2500,50 @@ static bool hsw_ddi_pll_get_hw_state(struct drm_i915_private *dev_priv,
        return val & WRPLL_PLL_ENABLE;
 }
 
+static bool hsw_ddi_spll_get_hw_state(struct drm_i915_private *dev_priv,
+                                     struct intel_shared_dpll *pll,
+                                     struct intel_dpll_hw_state *hw_state)
+{
+       uint32_t val;
+
+       if (!intel_display_power_is_enabled(dev_priv, POWER_DOMAIN_PLLS))
+               return false;
+
+       val = I915_READ(SPLL_CTL);
+       hw_state->spll = val;
+
+       return val & SPLL_PLL_ENABLE;
+}
+
+
 static const char * const hsw_ddi_pll_names[] = {
        "WRPLL 1",
        "WRPLL 2",
+       "SPLL"
 };
 
 static void hsw_shared_dplls_init(struct drm_i915_private *dev_priv)
 {
        int i;
 
-       dev_priv->num_shared_dpll = 2;
+       dev_priv->num_shared_dpll = 3;
 
-       for (i = 0; i < dev_priv->num_shared_dpll; i++) {
+       for (i = 0; i < 2; i++) {
                dev_priv->shared_dplls[i].id = i;
                dev_priv->shared_dplls[i].name = hsw_ddi_pll_names[i];
-               dev_priv->shared_dplls[i].disable = hsw_ddi_pll_disable;
-               dev_priv->shared_dplls[i].enable = hsw_ddi_pll_enable;
+               dev_priv->shared_dplls[i].disable = hsw_ddi_wrpll_disable;
+               dev_priv->shared_dplls[i].enable = hsw_ddi_wrpll_enable;
                dev_priv->shared_dplls[i].get_hw_state =
-                       hsw_ddi_pll_get_hw_state;
+                       hsw_ddi_wrpll_get_hw_state;
        }
+
+       /* SPLL is special, but needs to be initialized anyway.. */
+       dev_priv->shared_dplls[i].id = i;
+       dev_priv->shared_dplls[i].name = hsw_ddi_pll_names[i];
+       dev_priv->shared_dplls[i].disable = hsw_ddi_spll_disable;
+       dev_priv->shared_dplls[i].enable = hsw_ddi_spll_enable;
+       dev_priv->shared_dplls[i].get_hw_state = hsw_ddi_spll_get_hw_state;
+
 }
 
 static const char * const skl_ddi_pll_names[] = {
index f62ffc04c21d516d193dbaadf1cbaa28ca2d0b94..32cf973469785cb916eb3c2bdd125a741efb5e4c 100644 (file)
@@ -116,6 +116,7 @@ static void skylake_pfit_enable(struct intel_crtc *crtc);
 static void ironlake_pfit_disable(struct intel_crtc *crtc, bool force);
 static void ironlake_pfit_enable(struct intel_crtc *crtc);
 static void intel_modeset_setup_hw_state(struct drm_device *dev);
+static void intel_pre_disable_primary(struct drm_crtc *crtc);
 
 typedef struct {
        int     min, max;
@@ -2607,6 +2608,8 @@ intel_find_initial_plane_obj(struct intel_crtc *intel_crtc,
        struct drm_i915_gem_object *obj;
        struct drm_plane *primary = intel_crtc->base.primary;
        struct drm_plane_state *plane_state = primary->state;
+       struct drm_crtc_state *crtc_state = intel_crtc->base.state;
+       struct intel_plane *intel_plane = to_intel_plane(primary);
        struct drm_framebuffer *fb;
 
        if (!plane_config->fb)
@@ -2643,14 +2646,28 @@ intel_find_initial_plane_obj(struct intel_crtc *intel_crtc,
                }
        }
 
+       /*
+        * We've failed to reconstruct the BIOS FB.  Current display state
+        * indicates that the primary plane is visible, but has a NULL FB,
+        * which will lead to problems later if we don't fix it up.  The
+        * simplest solution is to just disable the primary plane now and
+        * pretend the BIOS never had it enabled.
+        */
+       to_intel_plane_state(plane_state)->visible = false;
+       crtc_state->plane_mask &= ~(1 << drm_plane_index(primary));
+       intel_pre_disable_primary(&intel_crtc->base);
+       intel_plane->disable_plane(primary, &intel_crtc->base);
+
        return;
 
 valid_fb:
-       plane_state->src_x = plane_state->src_y = 0;
+       plane_state->src_x = 0;
+       plane_state->src_y = 0;
        plane_state->src_w = fb->width << 16;
        plane_state->src_h = fb->height << 16;
 
-       plane_state->crtc_x = plane_state->src_y = 0;
+       plane_state->crtc_x = 0;
+       plane_state->crtc_y = 0;
        plane_state->crtc_w = fb->width;
        plane_state->crtc_h = fb->height;
 
@@ -4237,6 +4254,7 @@ struct intel_shared_dpll *intel_get_shared_dpll(struct intel_crtc *crtc,
        struct intel_shared_dpll *pll;
        struct intel_shared_dpll_config *shared_dpll;
        enum intel_dpll_id i;
+       int max = dev_priv->num_shared_dpll;
 
        shared_dpll = intel_atomic_get_shared_dpll_state(crtc_state->base.state);
 
@@ -4271,9 +4289,11 @@ struct intel_shared_dpll *intel_get_shared_dpll(struct intel_crtc *crtc,
                WARN_ON(shared_dpll[i].crtc_mask);
 
                goto found;
-       }
+       } else if (INTEL_INFO(dev_priv)->gen < 9 && HAS_DDI(dev_priv))
+               /* Do not consider SPLL */
+               max = 2;
 
-       for (i = 0; i < dev_priv->num_shared_dpll; i++) {
+       for (i = 0; i < max; i++) {
                pll = &dev_priv->shared_dplls[i];
 
                /* Only want to check enabled timings first */
@@ -5189,11 +5209,31 @@ static enum intel_display_power_domain port_to_power_domain(enum port port)
        case PORT_E:
                return POWER_DOMAIN_PORT_DDI_E_2_LANES;
        default:
-               WARN_ON_ONCE(1);
+               MISSING_CASE(port);
                return POWER_DOMAIN_PORT_OTHER;
        }
 }
 
+static enum intel_display_power_domain port_to_aux_power_domain(enum port port)
+{
+       switch (port) {
+       case PORT_A:
+               return POWER_DOMAIN_AUX_A;
+       case PORT_B:
+               return POWER_DOMAIN_AUX_B;
+       case PORT_C:
+               return POWER_DOMAIN_AUX_C;
+       case PORT_D:
+               return POWER_DOMAIN_AUX_D;
+       case PORT_E:
+               /* FIXME: Check VBT for actual wiring of PORT E */
+               return POWER_DOMAIN_AUX_D;
+       default:
+               MISSING_CASE(port);
+               return POWER_DOMAIN_AUX_A;
+       }
+}
+
 #define for_each_power_domain(domain, mask)                            \
        for ((domain) = 0; (domain) < POWER_DOMAIN_NUM; (domain)++)     \
                if ((1 << (domain)) & (mask))
@@ -5225,6 +5265,36 @@ intel_display_port_power_domain(struct intel_encoder *intel_encoder)
        }
 }
 
+enum intel_display_power_domain
+intel_display_port_aux_power_domain(struct intel_encoder *intel_encoder)
+{
+       struct drm_device *dev = intel_encoder->base.dev;
+       struct intel_digital_port *intel_dig_port;
+
+       switch (intel_encoder->type) {
+       case INTEL_OUTPUT_UNKNOWN:
+       case INTEL_OUTPUT_HDMI:
+               /*
+                * Only DDI platforms should ever use these output types.
+                * We can get here after the HDMI detect code has already set
+                * the type of the shared encoder. Since we can't be sure
+                * what's the status of the given connectors, play safe and
+                * run the DP detection too.
+                */
+               WARN_ON_ONCE(!HAS_DDI(dev));
+       case INTEL_OUTPUT_DISPLAYPORT:
+       case INTEL_OUTPUT_EDP:
+               intel_dig_port = enc_to_dig_port(&intel_encoder->base);
+               return port_to_aux_power_domain(intel_dig_port->port);
+       case INTEL_OUTPUT_DP_MST:
+               intel_dig_port = enc_to_mst(&intel_encoder->base)->primary;
+               return port_to_aux_power_domain(intel_dig_port->port);
+       default:
+               MISSING_CASE(intel_encoder->type);
+               return POWER_DOMAIN_AUX_A;
+       }
+}
+
 static unsigned long get_crtc_power_domains(struct drm_crtc *crtc)
 {
        struct drm_device *dev = crtc->dev;
@@ -6254,9 +6324,11 @@ static void intel_crtc_disable_noatomic(struct drm_crtc *crtc)
        if (to_intel_plane_state(crtc->primary->state)->visible) {
                intel_crtc_wait_for_pending_flips(crtc);
                intel_pre_disable_primary(crtc);
+
+               intel_crtc_disable_planes(crtc, 1 << drm_plane_index(crtc->primary));
+               to_intel_plane_state(crtc->primary->state)->visible = false;
        }
 
-       intel_crtc_disable_planes(crtc, crtc->state->plane_mask);
        dev_priv->display.crtc_disable(crtc);
        intel_crtc->active = false;
        intel_update_watermarks(crtc);
@@ -9723,6 +9795,8 @@ static void haswell_get_ddi_pll(struct drm_i915_private *dev_priv,
        case PORT_CLK_SEL_WRPLL2:
                pipe_config->shared_dpll = DPLL_ID_WRPLL2;
                break;
+       case PORT_CLK_SEL_SPLL:
+               pipe_config->shared_dpll = DPLL_ID_SPLL;
        }
 }
 
@@ -9851,14 +9925,14 @@ static bool haswell_get_pipe_config(struct intel_crtc *crtc,
        return true;
 }
 
-static void i845_update_cursor(struct drm_crtc *crtc, u32 base)
+static void i845_update_cursor(struct drm_crtc *crtc, u32 base, bool on)
 {
        struct drm_device *dev = crtc->dev;
        struct drm_i915_private *dev_priv = dev->dev_private;
        struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
        uint32_t cntl = 0, size = 0;
 
-       if (base) {
+       if (on) {
                unsigned int width = intel_crtc->base.cursor->state->crtc_w;
                unsigned int height = intel_crtc->base.cursor->state->crtc_h;
                unsigned int stride = roundup_pow_of_two(width) * 4;
@@ -9913,16 +9987,15 @@ static void i845_update_cursor(struct drm_crtc *crtc, u32 base)
        }
 }
 
-static void i9xx_update_cursor(struct drm_crtc *crtc, u32 base)
+static void i9xx_update_cursor(struct drm_crtc *crtc, u32 base, bool on)
 {
        struct drm_device *dev = crtc->dev;
        struct drm_i915_private *dev_priv = dev->dev_private;
        struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
        int pipe = intel_crtc->pipe;
-       uint32_t cntl;
+       uint32_t cntl = 0;
 
-       cntl = 0;
-       if (base) {
+       if (on) {
                cntl = MCURSOR_GAMMA_ENABLE;
                switch (intel_crtc->base.cursor->state->crtc_w) {
                        case 64:
@@ -9973,18 +10046,17 @@ static void intel_crtc_update_cursor(struct drm_crtc *crtc,
        int y = cursor_state->crtc_y;
        u32 base = 0, pos = 0;
 
-       if (on)
-               base = intel_crtc->cursor_addr;
+       base = intel_crtc->cursor_addr;
 
        if (x >= intel_crtc->config->pipe_src_w)
-               base = 0;
+               on = false;
 
        if (y >= intel_crtc->config->pipe_src_h)
-               base = 0;
+               on = false;
 
        if (x < 0) {
                if (x + cursor_state->crtc_w <= 0)
-                       base = 0;
+                       on = false;
 
                pos |= CURSOR_POS_SIGN << CURSOR_X_SHIFT;
                x = -x;
@@ -9993,16 +10065,13 @@ static void intel_crtc_update_cursor(struct drm_crtc *crtc,
 
        if (y < 0) {
                if (y + cursor_state->crtc_h <= 0)
-                       base = 0;
+                       on = false;
 
                pos |= CURSOR_POS_SIGN << CURSOR_Y_SHIFT;
                y = -y;
        }
        pos |= y << CURSOR_Y_SHIFT;
 
-       if (base == 0 && intel_crtc->cursor_base == 0)
-               return;
-
        I915_WRITE(CURPOS(pipe), pos);
 
        /* ILK+ do this automagically */
@@ -10013,9 +10082,9 @@ static void intel_crtc_update_cursor(struct drm_crtc *crtc,
        }
 
        if (IS_845G(dev) || IS_I865G(dev))
-               i845_update_cursor(crtc, base);
+               i845_update_cursor(crtc, base, on);
        else
-               i9xx_update_cursor(crtc, base);
+               i9xx_update_cursor(crtc, base, on);
 }
 
 static bool cursor_size_ok(struct drm_device *dev,
@@ -12003,9 +12072,10 @@ static void intel_dump_pipe_config(struct intel_crtc *crtc,
                              pipe_config->dpll_hw_state.cfgcr1,
                              pipe_config->dpll_hw_state.cfgcr2);
        } else if (HAS_DDI(dev)) {
-               DRM_DEBUG_KMS("ddi_pll_sel: %u; dpll_hw_state: wrpll: 0x%x\n",
+               DRM_DEBUG_KMS("ddi_pll_sel: %u; dpll_hw_state: wrpll: 0x%x spll: 0x%x\n",
                              pipe_config->ddi_pll_sel,
-                             pipe_config->dpll_hw_state.wrpll);
+                             pipe_config->dpll_hw_state.wrpll,
+                             pipe_config->dpll_hw_state.spll);
        } else {
                DRM_DEBUG_KMS("dpll_hw_state: dpll: 0x%x, dpll_md: 0x%x, "
                              "fp0: 0x%x, fp1: 0x%x\n",
@@ -12053,18 +12123,22 @@ static void intel_dump_pipe_config(struct intel_crtc *crtc,
 static bool check_digital_port_conflicts(struct drm_atomic_state *state)
 {
        struct drm_device *dev = state->dev;
-       struct intel_encoder *encoder;
        struct drm_connector *connector;
-       struct drm_connector_state *connector_state;
        unsigned int used_ports = 0;
-       int i;
 
        /*
         * Walk the connector list instead of the encoder
         * list to detect the problem on ddi platforms
         * where there's just one encoder per digital port.
         */
-       for_each_connector_in_state(state, connector, connector_state, i) {
+       drm_for_each_connector(connector, dev) {
+               struct drm_connector_state *connector_state;
+               struct intel_encoder *encoder;
+
+               connector_state = drm_atomic_get_existing_connector_state(state, connector);
+               if (!connector_state)
+                       connector_state = connector->state;
+
                if (!connector_state->best_encoder)
                        continue;
 
@@ -12452,7 +12526,6 @@ intel_pipe_config_compare(struct drm_device *dev,
        if (INTEL_INFO(dev)->gen < 8) {
                PIPE_CONF_CHECK_M_N(dp_m_n);
 
-               PIPE_CONF_CHECK_I(has_drrs);
                if (current_config->has_drrs)
                        PIPE_CONF_CHECK_M_N(dp_m2_n2);
        } else
@@ -12528,6 +12601,7 @@ intel_pipe_config_compare(struct drm_device *dev,
        PIPE_CONF_CHECK_X(dpll_hw_state.fp0);
        PIPE_CONF_CHECK_X(dpll_hw_state.fp1);
        PIPE_CONF_CHECK_X(dpll_hw_state.wrpll);
+       PIPE_CONF_CHECK_X(dpll_hw_state.spll);
        PIPE_CONF_CHECK_X(dpll_hw_state.ctrl1);
        PIPE_CONF_CHECK_X(dpll_hw_state.cfgcr1);
        PIPE_CONF_CHECK_X(dpll_hw_state.cfgcr2);
@@ -13032,6 +13106,9 @@ static int intel_atomic_check(struct drm_device *dev,
                struct intel_crtc_state *pipe_config =
                        to_intel_crtc_state(crtc_state);
 
+               memset(&to_intel_crtc(crtc)->atomic, 0,
+                      sizeof(struct intel_crtc_atomic_commit));
+
                /* Catch I915_MODE_FLAG_INHERITED */
                if (crtc_state->mode.private_flags != crtc->state->mode.private_flags)
                        crtc_state->mode_changed = true;
@@ -13056,7 +13133,8 @@ static int intel_atomic_check(struct drm_device *dev,
                if (ret)
                        return ret;
 
-               if (intel_pipe_config_compare(state->dev,
+               if (i915.fastboot &&
+                   intel_pipe_config_compare(state->dev,
                                        to_intel_crtc_state(crtc->state),
                                        pipe_config, true)) {
                        crtc_state->mode_changed = false;
@@ -13654,6 +13732,7 @@ intel_check_cursor_plane(struct drm_plane *plane,
        struct drm_crtc *crtc = crtc_state->base.crtc;
        struct drm_framebuffer *fb = state->base.fb;
        struct drm_i915_gem_object *obj = intel_fb_obj(fb);
+       enum pipe pipe = to_intel_plane(plane)->pipe;
        unsigned stride;
        int ret;
 
@@ -13687,6 +13766,22 @@ intel_check_cursor_plane(struct drm_plane *plane,
                return -EINVAL;
        }
 
+       /*
+        * There's something wrong with the cursor on CHV pipe C.
+        * If it straddles the left edge of the screen then
+        * moving it away from the edge or disabling it often
+        * results in a pipe underrun, and often that can lead to
+        * dead pipe (constant underrun reported, and it scans
+        * out just a solid color). To recover from that, the
+        * display power well must be turned off and on again.
+        * Refuse the put the cursor into that compromised position.
+        */
+       if (IS_CHERRYVIEW(plane->dev) && pipe == PIPE_C &&
+           state->visible && state->base.crtc_x < 0) {
+               DRM_DEBUG_KMS("CHV cursor C not allowed to straddle the left screen edge\n");
+               return -EINVAL;
+       }
+
        return 0;
 }
 
@@ -13710,9 +13805,6 @@ intel_commit_cursor_plane(struct drm_plane *plane,
        crtc = crtc ? crtc : plane->crtc;
        intel_crtc = to_intel_crtc(crtc);
 
-       if (intel_crtc->cursor_bo == obj)
-               goto update;
-
        if (!obj)
                addr = 0;
        else if (!INTEL_INFO(dev)->cursor_needs_physical)
@@ -13721,9 +13813,7 @@ intel_commit_cursor_plane(struct drm_plane *plane,
                addr = obj->phys_handle->busaddr;
 
        intel_crtc->cursor_addr = addr;
-       intel_crtc->cursor_bo = obj;
 
-update:
        if (crtc->state->active)
                intel_crtc_update_cursor(crtc, state->visible);
 }
@@ -14364,16 +14454,17 @@ static int intel_framebuffer_init(struct drm_device *dev,
 static struct drm_framebuffer *
 intel_user_framebuffer_create(struct drm_device *dev,
                              struct drm_file *filp,
-                             struct drm_mode_fb_cmd2 *mode_cmd)
+                             struct drm_mode_fb_cmd2 *user_mode_cmd)
 {
        struct drm_i915_gem_object *obj;
+       struct drm_mode_fb_cmd2 mode_cmd = *user_mode_cmd;
 
        obj = to_intel_bo(drm_gem_object_lookup(dev, filp,
-                                               mode_cmd->handles[0]));
+                                               mode_cmd.handles[0]));
        if (&obj->base == NULL)
                return ERR_PTR(-ENOENT);
 
-       return intel_framebuffer_create(dev, mode_cmd, obj);
+       return intel_framebuffer_create(dev, &mode_cmd, obj);
 }
 
 #ifndef CONFIG_DRM_FBDEV_EMULATION
@@ -14705,6 +14796,9 @@ static struct intel_quirk intel_quirks[] = {
        /* Apple Macbook 2,1 (Core 2 T7400) */
        { 0x27a2, 0x8086, 0x7270, quirk_backlight_present },
 
+       /* Apple Macbook 4,1 */
+       { 0x2a02, 0x106b, 0x00a1, quirk_backlight_present },
+
        /* Toshiba CB35 Chromebook (Celeron 2955U) */
        { 0x0a06, 0x1179, 0x0a88, quirk_backlight_present },
 
index 09bdd94ca3ba435b452ef4593620b01fd59456d5..78b8ec84d576da24de0f96c56fabaf5d380ddea5 100644 (file)
@@ -277,7 +277,7 @@ static void pps_lock(struct intel_dp *intel_dp)
         * See vlv_power_sequencer_reset() why we need
         * a power domain reference here.
         */
-       power_domain = intel_display_port_power_domain(encoder);
+       power_domain = intel_display_port_aux_power_domain(encoder);
        intel_display_power_get(dev_priv, power_domain);
 
        mutex_lock(&dev_priv->pps_mutex);
@@ -293,7 +293,7 @@ static void pps_unlock(struct intel_dp *intel_dp)
 
        mutex_unlock(&dev_priv->pps_mutex);
 
-       power_domain = intel_display_port_power_domain(encoder);
+       power_domain = intel_display_port_aux_power_domain(encoder);
        intel_display_power_put(dev_priv, power_domain);
 }
 
@@ -816,8 +816,6 @@ intel_dp_aux_ch(struct intel_dp *intel_dp,
 
        intel_dp_check_edp(intel_dp);
 
-       intel_aux_display_runtime_get(dev_priv);
-
        /* Try to wait for any previous AUX channel activity */
        for (try = 0; try < 3; try++) {
                status = I915_READ_NOTRACE(ch_ctl);
@@ -926,7 +924,6 @@ done:
        ret = recv_bytes;
 out:
        pm_qos_update_request(&dev_priv->pm_qos, PM_QOS_DEFAULT_VALUE);
-       intel_aux_display_runtime_put(dev_priv);
 
        if (vdd)
                edp_panel_vdd_off(intel_dp, false);
@@ -1784,7 +1781,7 @@ static bool edp_panel_vdd_on(struct intel_dp *intel_dp)
        if (edp_have_panel_vdd(intel_dp))
                return need_to_disable;
 
-       power_domain = intel_display_port_power_domain(intel_encoder);
+       power_domain = intel_display_port_aux_power_domain(intel_encoder);
        intel_display_power_get(dev_priv, power_domain);
 
        DRM_DEBUG_KMS("Turning eDP port %c VDD on\n",
@@ -1874,7 +1871,7 @@ static void edp_panel_vdd_off_sync(struct intel_dp *intel_dp)
        if ((pp & POWER_TARGET_ON) == 0)
                intel_dp->last_power_cycle = jiffies;
 
-       power_domain = intel_display_port_power_domain(intel_encoder);
+       power_domain = intel_display_port_aux_power_domain(intel_encoder);
        intel_display_power_put(dev_priv, power_domain);
 }
 
@@ -2025,7 +2022,7 @@ static void edp_panel_off(struct intel_dp *intel_dp)
        wait_panel_off(intel_dp);
 
        /* We got a reference when we enabled the VDD. */
-       power_domain = intel_display_port_power_domain(intel_encoder);
+       power_domain = intel_display_port_aux_power_domain(intel_encoder);
        intel_display_power_put(dev_priv, power_domain);
 }
 
@@ -4765,26 +4762,6 @@ intel_dp_unset_edid(struct intel_dp *intel_dp)
        intel_dp->has_audio = false;
 }
 
-static enum intel_display_power_domain
-intel_dp_power_get(struct intel_dp *dp)
-{
-       struct intel_encoder *encoder = &dp_to_dig_port(dp)->base;
-       enum intel_display_power_domain power_domain;
-
-       power_domain = intel_display_port_power_domain(encoder);
-       intel_display_power_get(to_i915(encoder->base.dev), power_domain);
-
-       return power_domain;
-}
-
-static void
-intel_dp_power_put(struct intel_dp *dp,
-                  enum intel_display_power_domain power_domain)
-{
-       struct intel_encoder *encoder = &dp_to_dig_port(dp)->base;
-       intel_display_power_put(to_i915(encoder->base.dev), power_domain);
-}
-
 static enum drm_connector_status
 intel_dp_detect(struct drm_connector *connector, bool force)
 {
@@ -4808,7 +4785,8 @@ intel_dp_detect(struct drm_connector *connector, bool force)
                return connector_status_disconnected;
        }
 
-       power_domain = intel_dp_power_get(intel_dp);
+       power_domain = intel_display_port_aux_power_domain(intel_encoder);
+       intel_display_power_get(to_i915(dev), power_domain);
 
        /* Can't disconnect eDP, but you can close the lid... */
        if (is_edp(intel_dp))
@@ -4853,7 +4831,7 @@ intel_dp_detect(struct drm_connector *connector, bool force)
        }
 
 out:
-       intel_dp_power_put(intel_dp, power_domain);
+       intel_display_power_put(to_i915(dev), power_domain);
        return status;
 }
 
@@ -4862,6 +4840,7 @@ intel_dp_force(struct drm_connector *connector)
 {
        struct intel_dp *intel_dp = intel_attached_dp(connector);
        struct intel_encoder *intel_encoder = &dp_to_dig_port(intel_dp)->base;
+       struct drm_i915_private *dev_priv = to_i915(intel_encoder->base.dev);
        enum intel_display_power_domain power_domain;
 
        DRM_DEBUG_KMS("[CONNECTOR:%d:%s]\n",
@@ -4871,11 +4850,12 @@ intel_dp_force(struct drm_connector *connector)
        if (connector->status != connector_status_connected)
                return;
 
-       power_domain = intel_dp_power_get(intel_dp);
+       power_domain = intel_display_port_aux_power_domain(intel_encoder);
+       intel_display_power_get(dev_priv, power_domain);
 
        intel_dp_set_edid(intel_dp);
 
-       intel_dp_power_put(intel_dp, power_domain);
+       intel_display_power_put(dev_priv, power_domain);
 
        if (intel_encoder->type != INTEL_OUTPUT_EDP)
                intel_encoder->type = INTEL_OUTPUT_DISPLAYPORT;
@@ -5091,7 +5071,7 @@ static void intel_edp_panel_vdd_sanitize(struct intel_dp *intel_dp)
         * indefinitely.
         */
        DRM_DEBUG_KMS("VDD left on by BIOS, adjusting state tracking\n");
-       power_domain = intel_display_port_power_domain(&intel_dig_port->base);
+       power_domain = intel_display_port_aux_power_domain(&intel_dig_port->base);
        intel_display_power_get(dev_priv, power_domain);
 
        edp_panel_vdd_schedule_off(intel_dp);
@@ -5153,7 +5133,8 @@ intel_dp_hpd_pulse(struct intel_digital_port *intel_dig_port, bool long_hpd)
        enum intel_display_power_domain power_domain;
        enum irqreturn ret = IRQ_NONE;
 
-       if (intel_dig_port->base.type != INTEL_OUTPUT_EDP)
+       if (intel_dig_port->base.type != INTEL_OUTPUT_EDP &&
+           intel_dig_port->base.type != INTEL_OUTPUT_HDMI)
                intel_dig_port->base.type = INTEL_OUTPUT_DISPLAYPORT;
 
        if (long_hpd && intel_dig_port->base.type == INTEL_OUTPUT_EDP) {
@@ -5172,7 +5153,7 @@ intel_dp_hpd_pulse(struct intel_digital_port *intel_dig_port, bool long_hpd)
                      port_name(intel_dig_port->port),
                      long_hpd ? "long" : "short");
 
-       power_domain = intel_display_port_power_domain(intel_encoder);
+       power_domain = intel_display_port_aux_power_domain(intel_encoder);
        intel_display_power_get(dev_priv, power_domain);
 
        if (long_hpd) {
index 0598932ce6235b623df9ff6a62d74e100087f78e..0d00f07b7163c90c10d8e994b037b7b24b508d34 100644 (file)
@@ -550,7 +550,6 @@ struct intel_crtc {
        int adjusted_x;
        int adjusted_y;
 
-       struct drm_i915_gem_object *cursor_bo;
        uint32_t cursor_addr;
        uint32_t cursor_cntl;
        uint32_t cursor_size;
@@ -1169,6 +1168,8 @@ void hsw_enable_ips(struct intel_crtc *crtc);
 void hsw_disable_ips(struct intel_crtc *crtc);
 enum intel_display_power_domain
 intel_display_port_power_domain(struct intel_encoder *intel_encoder);
+enum intel_display_power_domain
+intel_display_port_aux_power_domain(struct intel_encoder *intel_encoder);
 void intel_mode_from_pipe_config(struct drm_display_mode *mode,
                                 struct intel_crtc_state *pipe_config);
 void intel_crtc_wait_for_pending_flips(struct drm_crtc *crtc);
@@ -1377,8 +1378,6 @@ void intel_display_power_get(struct drm_i915_private *dev_priv,
                             enum intel_display_power_domain domain);
 void intel_display_power_put(struct drm_i915_private *dev_priv,
                             enum intel_display_power_domain domain);
-void intel_aux_display_runtime_get(struct drm_i915_private *dev_priv);
-void intel_aux_display_runtime_put(struct drm_i915_private *dev_priv);
 void intel_runtime_pm_get(struct drm_i915_private *dev_priv);
 void intel_runtime_pm_get_noresume(struct drm_i915_private *dev_priv);
 void intel_runtime_pm_put(struct drm_i915_private *dev_priv);
index 9eafa191cee2e33c34942006ece7b0b8374cbc8f..e6c035b0fc1ce2d2e674aec93cb50c0ad7b7db67 100644 (file)
@@ -1335,21 +1335,17 @@ intel_hdmi_set_edid(struct drm_connector *connector, bool force)
 {
        struct drm_i915_private *dev_priv = to_i915(connector->dev);
        struct intel_hdmi *intel_hdmi = intel_attached_hdmi(connector);
-       struct intel_encoder *intel_encoder =
-               &hdmi_to_dig_port(intel_hdmi)->base;
-       enum intel_display_power_domain power_domain;
        struct edid *edid = NULL;
        bool connected = false;
 
-       power_domain = intel_display_port_power_domain(intel_encoder);
-       intel_display_power_get(dev_priv, power_domain);
+       intel_display_power_get(dev_priv, POWER_DOMAIN_GMBUS);
 
        if (force)
                edid = drm_get_edid(connector,
                                    intel_gmbus_get_adapter(dev_priv,
                                    intel_hdmi->ddc_bus));
 
-       intel_display_power_put(dev_priv, power_domain);
+       intel_display_power_put(dev_priv, POWER_DOMAIN_GMBUS);
 
        to_intel_connector(connector)->detect_edid = edid;
        if (edid && edid->input & DRM_EDID_INPUT_DIGITAL) {
@@ -1378,15 +1374,18 @@ intel_hdmi_detect(struct drm_connector *connector, bool force)
        struct intel_hdmi *intel_hdmi = intel_attached_hdmi(connector);
        struct drm_i915_private *dev_priv = to_i915(connector->dev);
        bool live_status = false;
-       unsigned int retry = 3;
+       unsigned int try;
 
        DRM_DEBUG_KMS("[CONNECTOR:%d:%s]\n",
                      connector->base.id, connector->name);
 
-       while (!live_status && --retry) {
+       intel_display_power_get(dev_priv, POWER_DOMAIN_GMBUS);
+
+       for (try = 0; !live_status && try < 9; try++) {
+               if (try)
+                       msleep(10);
                live_status = intel_digital_port_connected(dev_priv,
                                hdmi_to_dig_port(intel_hdmi));
-               mdelay(10);
        }
 
        if (!live_status)
@@ -1402,6 +1401,8 @@ intel_hdmi_detect(struct drm_connector *connector, bool force)
        } else
                status = connector_status_disconnected;
 
+       intel_display_power_put(dev_priv, POWER_DOMAIN_GMBUS);
+
        return status;
 }
 
index 1369fc41d03913f217894c700fa220465362b975..8324654037b65577fd4bdc65484576e9ceaf432a 100644 (file)
@@ -483,7 +483,7 @@ gmbus_xfer(struct i2c_adapter *adapter,
        int i = 0, inc, try = 0;
        int ret = 0;
 
-       intel_aux_display_runtime_get(dev_priv);
+       intel_display_power_get(dev_priv, POWER_DOMAIN_GMBUS);
        mutex_lock(&dev_priv->gmbus_mutex);
 
        if (bus->force_bit) {
@@ -595,7 +595,9 @@ timeout:
 
 out:
        mutex_unlock(&dev_priv->gmbus_mutex);
-       intel_aux_display_runtime_put(dev_priv);
+
+       intel_display_power_put(dev_priv, POWER_DOMAIN_GMBUS);
+
        return ret;
 }
 
index d52a15df6917cc054df25cccdba43f6ef8abfaa0..f091ad12d694a43ebb0dce69b31089ffd4abe366 100644 (file)
@@ -4449,7 +4449,7 @@ static void gen6_set_rps(struct drm_device *dev, u8 val)
        POSTING_READ(GEN6_RPNSWREQ);
 
        dev_priv->rps.cur_freq = val;
-       trace_intel_gpu_freq_change(val * 50);
+       trace_intel_gpu_freq_change(intel_gpu_freq(dev_priv, val));
 }
 
 static void valleyview_set_rps(struct drm_device *dev, u8 val)
@@ -4782,8 +4782,7 @@ static void gen9_enable_rc6(struct drm_device *dev)
        /* 2b: Program RC6 thresholds.*/
 
        /* WaRsDoubleRc6WrlWithCoarsePowerGating: Doubling WRL only when CPG is enabled */
-       if (IS_SKYLAKE(dev) && !((IS_SKL_GT3(dev) || IS_SKL_GT4(dev)) &&
-                                (INTEL_REVID(dev) <= SKL_REVID_E0)))
+       if (IS_SKYLAKE(dev))
                I915_WRITE(GEN6_RC6_WAKE_RATE_LIMIT, 108 << 16);
        else
                I915_WRITE(GEN6_RC6_WAKE_RATE_LIMIT, 54 << 16);
@@ -4825,7 +4824,7 @@ static void gen9_enable_rc6(struct drm_device *dev)
         * WaRsDisableCoarsePowerGating:skl,bxt - Render/Media PG need to be disabled with RC6.
         */
        if ((IS_BROXTON(dev) && (INTEL_REVID(dev) < BXT_REVID_B0)) ||
-           ((IS_SKL_GT3(dev) || IS_SKL_GT4(dev)) && (INTEL_REVID(dev) <= SKL_REVID_E0)))
+           ((IS_SKL_GT3(dev) || IS_SKL_GT4(dev)) && (INTEL_REVID(dev) <= SKL_REVID_F0)))
                I915_WRITE(GEN9_PG_ENABLE, 0);
        else
                I915_WRITE(GEN9_PG_ENABLE, (rc6_mask & GEN6_RC_CTL_RC6_ENABLE) ?
@@ -7255,7 +7254,8 @@ static int chv_freq_opcode(struct drm_i915_private *dev_priv, int val)
 int intel_gpu_freq(struct drm_i915_private *dev_priv, int val)
 {
        if (IS_GEN9(dev_priv->dev))
-               return (val * GT_FREQUENCY_MULTIPLIER) / GEN9_FREQ_SCALER;
+               return DIV_ROUND_CLOSEST(val * GT_FREQUENCY_MULTIPLIER,
+                                        GEN9_FREQ_SCALER);
        else if (IS_CHERRYVIEW(dev_priv->dev))
                return chv_gpu_freq(dev_priv, val);
        else if (IS_VALLEYVIEW(dev_priv->dev))
@@ -7267,13 +7267,14 @@ int intel_gpu_freq(struct drm_i915_private *dev_priv, int val)
 int intel_freq_opcode(struct drm_i915_private *dev_priv, int val)
 {
        if (IS_GEN9(dev_priv->dev))
-               return (val * GEN9_FREQ_SCALER) / GT_FREQUENCY_MULTIPLIER;
+               return DIV_ROUND_CLOSEST(val * GEN9_FREQ_SCALER,
+                                        GT_FREQUENCY_MULTIPLIER);
        else if (IS_CHERRYVIEW(dev_priv->dev))
                return chv_freq_opcode(dev_priv, val);
        else if (IS_VALLEYVIEW(dev_priv->dev))
                return byt_freq_opcode(dev_priv, val);
        else
-               return val / GT_FREQUENCY_MULTIPLIER;
+               return DIV_ROUND_CLOSEST(val, GT_FREQUENCY_MULTIPLIER);
 }
 
 struct request_boost {
index d89c1d0aa1b74793a4328c861c312a91709092e7..7e23d65c9b246ac6672ad432c0f4f4f38bab6254 100644 (file)
@@ -362,6 +362,7 @@ static void hsw_set_power_well(struct drm_i915_private *dev_priv,
        BIT(POWER_DOMAIN_AUX_C) |                       \
        BIT(POWER_DOMAIN_AUDIO) |                       \
        BIT(POWER_DOMAIN_VGA) |                         \
+       BIT(POWER_DOMAIN_GMBUS) |                       \
        BIT(POWER_DOMAIN_INIT))
 #define BXT_DISPLAY_POWERWELL_1_POWER_DOMAINS (                \
        BXT_DISPLAY_POWERWELL_2_POWER_DOMAINS |         \
@@ -1483,6 +1484,7 @@ void intel_display_power_put(struct drm_i915_private *dev_priv,
        BIT(POWER_DOMAIN_AUX_B) |                       \
        BIT(POWER_DOMAIN_AUX_C) |                       \
        BIT(POWER_DOMAIN_AUX_D) |                       \
+       BIT(POWER_DOMAIN_GMBUS) |                       \
        BIT(POWER_DOMAIN_INIT))
 #define HSW_DISPLAY_POWER_DOMAINS (                            \
        (POWER_DOMAIN_MASK & ~HSW_ALWAYS_ON_POWER_DOMAINS) |    \
@@ -1845,6 +1847,8 @@ int intel_power_domains_init(struct drm_i915_private *dev_priv)
        i915.disable_power_well = sanitize_disable_power_well_option(dev_priv,
                                                     i915.disable_power_well);
 
+       BUILD_BUG_ON(POWER_DOMAIN_NUM > 31);
+
        mutex_init(&power_domains->lock);
 
        /*
@@ -2063,36 +2067,6 @@ void intel_power_domains_init_hw(struct drm_i915_private *dev_priv)
        power_domains->initializing = false;
 }
 
-/**
- * intel_aux_display_runtime_get - grab an auxiliary power domain reference
- * @dev_priv: i915 device instance
- *
- * This function grabs a power domain reference for the auxiliary power domain
- * (for access to the GMBUS and DP AUX blocks) and ensures that it and all its
- * parents are powered up. Therefore users should only grab a reference to the
- * innermost power domain they need.
- *
- * Any power domain reference obtained by this function must have a symmetric
- * call to intel_aux_display_runtime_put() to release the reference again.
- */
-void intel_aux_display_runtime_get(struct drm_i915_private *dev_priv)
-{
-       intel_runtime_pm_get(dev_priv);
-}
-
-/**
- * intel_aux_display_runtime_put - release an auxiliary power domain reference
- * @dev_priv: i915 device instance
- *
- * This function drops the auxiliary power domain reference obtained by
- * intel_aux_display_runtime_get() and might power down the corresponding
- * hardware block right away if this is the last reference.
- */
-void intel_aux_display_runtime_put(struct drm_i915_private *dev_priv)
-{
-       intel_runtime_pm_put(dev_priv);
-}
-
 /**
  * intel_runtime_pm_get - grab a runtime pm reference
  * @dev_priv: i915 device instance
index 64f16ea779ef397346c9f75aa946096083225f04..7b990b4e96d234bcdc965572383092e3d9b303a0 100644 (file)
@@ -63,8 +63,7 @@ static void imx_drm_driver_lastclose(struct drm_device *drm)
 #if IS_ENABLED(CONFIG_DRM_IMX_FB_HELPER)
        struct imx_drm_device *imxdrm = drm->dev_private;
 
-       if (imxdrm->fbhelper)
-               drm_fbdev_cma_restore_mode(imxdrm->fbhelper);
+       drm_fbdev_cma_restore_mode(imxdrm->fbhelper);
 #endif
 }
 
@@ -340,7 +339,7 @@ err_kms:
  * imx_drm_add_crtc - add a new crtc
  */
 int imx_drm_add_crtc(struct drm_device *drm, struct drm_crtc *crtc,
-               struct imx_drm_crtc **new_crtc,
+               struct imx_drm_crtc **new_crtc, struct drm_plane *primary_plane,
                const struct imx_drm_crtc_helper_funcs *imx_drm_helper_funcs,
                struct device_node *port)
 {
@@ -379,7 +378,7 @@ int imx_drm_add_crtc(struct drm_device *drm, struct drm_crtc *crtc,
        drm_crtc_helper_add(crtc,
                        imx_drm_crtc->imx_drm_helper_funcs.crtc_helper_funcs);
 
-       drm_crtc_init(drm, crtc,
+       drm_crtc_init_with_planes(drm, crtc, primary_plane, NULL,
                        imx_drm_crtc->imx_drm_helper_funcs.crtc_funcs);
 
        return 0;
index 28e776d8d9d270259f0df5b270897cdb8aec0e24..83284b4d4be1ef86ebefbb3276ef41bf3d5eb6ef 100644 (file)
@@ -9,6 +9,7 @@ struct drm_display_mode;
 struct drm_encoder;
 struct drm_fbdev_cma;
 struct drm_framebuffer;
+struct drm_plane;
 struct imx_drm_crtc;
 struct platform_device;
 
@@ -24,7 +25,7 @@ struct imx_drm_crtc_helper_funcs {
 };
 
 int imx_drm_add_crtc(struct drm_device *drm, struct drm_crtc *crtc,
-               struct imx_drm_crtc **new_crtc,
+               struct imx_drm_crtc **new_crtc, struct drm_plane *primary_plane,
                const struct imx_drm_crtc_helper_funcs *imx_helper_funcs,
                struct device_node *port);
 int imx_drm_remove_crtc(struct imx_drm_crtc *);
index e671ad3694166041ce76c4eaa57539897eba81d1..f9597146dc674a041e89133143286063d07739f2 100644 (file)
@@ -721,6 +721,7 @@ static const struct of_device_id imx_tve_dt_ids[] = {
        { .compatible = "fsl,imx53-tve", },
        { /* sentinel */ }
 };
+MODULE_DEVICE_TABLE(of, imx_tve_dt_ids);
 
 static struct platform_driver imx_tve_driver = {
        .probe          = imx_tve_probe,
index 7bc8301faffffff69194f20ca9d64b8e398f6478..4ab841eebee19dc099758f0018d9cf5030b475c0 100644 (file)
@@ -212,7 +212,8 @@ static void ipu_crtc_handle_pageflip(struct ipu_crtc *ipu_crtc)
 
        spin_lock_irqsave(&drm->event_lock, flags);
        if (ipu_crtc->page_flip_event)
-               drm_send_vblank_event(drm, -1, ipu_crtc->page_flip_event);
+               drm_crtc_send_vblank_event(&ipu_crtc->base,
+                                          ipu_crtc->page_flip_event);
        ipu_crtc->page_flip_event = NULL;
        imx_drm_crtc_vblank_put(ipu_crtc->imx_crtc);
        spin_unlock_irqrestore(&drm->event_lock, flags);
@@ -349,7 +350,6 @@ static int ipu_crtc_init(struct ipu_crtc *ipu_crtc,
        struct ipu_soc *ipu = dev_get_drvdata(ipu_crtc->dev->parent);
        int dp = -EINVAL;
        int ret;
-       int id;
 
        ret = ipu_get_resources(ipu_crtc, pdata);
        if (ret) {
@@ -358,18 +358,23 @@ static int ipu_crtc_init(struct ipu_crtc *ipu_crtc,
                return ret;
        }
 
+       if (pdata->dp >= 0)
+               dp = IPU_DP_FLOW_SYNC_BG;
+       ipu_crtc->plane[0] = ipu_plane_init(drm, ipu, pdata->dma[0], dp, 0,
+                                           DRM_PLANE_TYPE_PRIMARY);
+       if (IS_ERR(ipu_crtc->plane[0])) {
+               ret = PTR_ERR(ipu_crtc->plane[0]);
+               goto err_put_resources;
+       }
+
        ret = imx_drm_add_crtc(drm, &ipu_crtc->base, &ipu_crtc->imx_crtc,
-                       &ipu_crtc_helper_funcs, ipu_crtc->dev->of_node);
+                       &ipu_crtc->plane[0]->base, &ipu_crtc_helper_funcs,
+                       ipu_crtc->dev->of_node);
        if (ret) {
                dev_err(ipu_crtc->dev, "adding crtc failed with %d.\n", ret);
                goto err_put_resources;
        }
 
-       if (pdata->dp >= 0)
-               dp = IPU_DP_FLOW_SYNC_BG;
-       id = imx_drm_crtc_id(ipu_crtc->imx_crtc);
-       ipu_crtc->plane[0] = ipu_plane_init(ipu_crtc->base.dev, ipu,
-                                           pdata->dma[0], dp, BIT(id), true);
        ret = ipu_plane_get_resources(ipu_crtc->plane[0]);
        if (ret) {
                dev_err(ipu_crtc->dev, "getting plane 0 resources failed with %d.\n",
@@ -379,10 +384,10 @@ static int ipu_crtc_init(struct ipu_crtc *ipu_crtc,
 
        /* If this crtc is using the DP, add an overlay plane */
        if (pdata->dp >= 0 && pdata->dma[1] > 0) {
-               ipu_crtc->plane[1] = ipu_plane_init(ipu_crtc->base.dev, ipu,
-                                                   pdata->dma[1],
-                                                   IPU_DP_FLOW_SYNC_FG,
-                                                   BIT(id), false);
+               ipu_crtc->plane[1] = ipu_plane_init(drm, ipu, pdata->dma[1],
+                                               IPU_DP_FLOW_SYNC_FG,
+                                               drm_crtc_mask(&ipu_crtc->base),
+                                               DRM_PLANE_TYPE_OVERLAY);
                if (IS_ERR(ipu_crtc->plane[1]))
                        ipu_crtc->plane[1] = NULL;
        }
@@ -407,28 +412,6 @@ err_put_resources:
        return ret;
 }
 
-static struct device_node *ipu_drm_get_port_by_id(struct device_node *parent,
-                                                 int port_id)
-{
-       struct device_node *port;
-       int id, ret;
-
-       port = of_get_child_by_name(parent, "port");
-       while (port) {
-               ret = of_property_read_u32(port, "reg", &id);
-               if (!ret && id == port_id)
-                       return port;
-
-               do {
-                       port = of_get_next_child(parent, port);
-                       if (!port)
-                               return NULL;
-               } while (of_node_cmp(port->name, "port"));
-       }
-
-       return NULL;
-}
-
 static int ipu_drm_bind(struct device *dev, struct device *master, void *data)
 {
        struct ipu_client_platformdata *pdata = dev->platform_data;
@@ -470,23 +453,11 @@ static const struct component_ops ipu_crtc_ops = {
 static int ipu_drm_probe(struct platform_device *pdev)
 {
        struct device *dev = &pdev->dev;
-       struct ipu_client_platformdata *pdata = dev->platform_data;
        int ret;
 
        if (!dev->platform_data)
                return -EINVAL;
 
-       if (!dev->of_node) {
-               /* Associate crtc device with the corresponding DI port node */
-               dev->of_node = ipu_drm_get_port_by_id(dev->parent->of_node,
-                                                     pdata->di + 2);
-               if (!dev->of_node) {
-                       dev_err(dev, "missing port@%d node in %s\n",
-                               pdata->di + 2, dev->parent->of_node->full_name);
-                       return -ENODEV;
-               }
-       }
-
        ret = dma_set_coherent_mask(dev, DMA_BIT_MASK(32));
        if (ret)
                return ret;
index 575f4c84388f0c64f54d2cdf598064011cfffd6e..e2ff410bab744442e5c6cb2e1bc27cbba58ee7f2 100644 (file)
@@ -381,7 +381,7 @@ static struct drm_plane_funcs ipu_plane_funcs = {
 
 struct ipu_plane *ipu_plane_init(struct drm_device *dev, struct ipu_soc *ipu,
                                 int dma, int dp, unsigned int possible_crtcs,
-                                bool priv)
+                                enum drm_plane_type type)
 {
        struct ipu_plane *ipu_plane;
        int ret;
@@ -399,10 +399,9 @@ struct ipu_plane *ipu_plane_init(struct drm_device *dev, struct ipu_soc *ipu,
        ipu_plane->dma = dma;
        ipu_plane->dp_flow = dp;
 
-       ret = drm_plane_init(dev, &ipu_plane->base, possible_crtcs,
-                            &ipu_plane_funcs, ipu_plane_formats,
-                            ARRAY_SIZE(ipu_plane_formats),
-                            priv);
+       ret = drm_universal_plane_init(dev, &ipu_plane->base, possible_crtcs,
+                                      &ipu_plane_funcs, ipu_plane_formats,
+                                      ARRAY_SIZE(ipu_plane_formats), type);
        if (ret) {
                DRM_ERROR("failed to initialize plane\n");
                kfree(ipu_plane);
index 9b5eff18f5b826b722d97b8e763dbd3017197aee..3a443b413c60caa9734883f7aaa95a69bb7f3e29 100644 (file)
@@ -34,7 +34,7 @@ struct ipu_plane {
 
 struct ipu_plane *ipu_plane_init(struct drm_device *dev, struct ipu_soc *ipu,
                                 int dma, int dp, unsigned int possible_crtcs,
-                                bool priv);
+                                enum drm_plane_type type);
 
 /* Init IDMAC, DMFC, DP */
 int ipu_plane_mode_set(struct ipu_plane *plane, struct drm_crtc *crtc,
index b4deb9cf9d71613fa49562c4619cf8ffec5a33f3..2e9b9f1b5cd2bc8e37f96a66ea2da2d2e61c2ba6 100644 (file)
@@ -54,7 +54,11 @@ static int imx_pd_connector_get_modes(struct drm_connector *connector)
 
        if (imxpd->panel && imxpd->panel->funcs &&
            imxpd->panel->funcs->get_modes) {
+               struct drm_display_info *di = &connector->display_info;
+
                num_modes = imxpd->panel->funcs->get_modes(imxpd->panel);
+               if (!imxpd->bus_format && di->num_bus_formats)
+                       imxpd->bus_format = di->bus_formats[0];
                if (num_modes > 0)
                        return num_modes;
        }
index 4f2068fe5d885cdba438a44745c27ccade5df9d0..a7bf6a90eae5a30e40ae3c1c5dbada0ea893bc8b 100644 (file)
@@ -70,6 +70,11 @@ int mga_crtc_cursor_set(struct drm_crtc *crtc,
        BUG_ON(pixels_2 != pixels_current && pixels_2 != pixels_prev);
        BUG_ON(pixels_current == pixels_prev);
 
+       if (!handle || !file_priv) {
+               mga_hide_cursor(mdev);
+               return 0;
+       }
+
        obj = drm_gem_object_lookup(dev, file_priv, handle);
        if (!obj)
                return -ENOENT;
@@ -88,12 +93,6 @@ int mga_crtc_cursor_set(struct drm_crtc *crtc,
                goto out_unreserve1;
        }
 
-       if (!handle) {
-               mga_hide_cursor(mdev);
-               ret = 0;
-               goto out1;
-       }
-
        /* Move cursor buffers into VRAM if they aren't already */
        if (!pixels_1->pin_count) {
                ret = mgag200_bo_pin(pixels_1, TTM_PL_FLAG_VRAM,
index 8f760002e4018ba05a6fb18a6ecc0d0cf53605fc..913192c94876febb1bf274213c92244b6af6b92d 100644 (file)
@@ -159,7 +159,6 @@ struct nvkm_device_func {
 struct nvkm_device_quirk {
        u8 tv_pin_mask;
        u8 tv_gpio;
-       bool War00C800_0;
 };
 
 struct nvkm_device_chip {
index 28bc202f9753e9fde7777461b5640a77a757a60b..40f845e312723744c52330bdc29b24666281b9f0 100644 (file)
@@ -7,6 +7,7 @@ struct nvkm_instmem {
        const struct nvkm_instmem_func *func;
        struct nvkm_subdev subdev;
 
+       spinlock_t lock;
        struct list_head list;
        u32 reserved;
 
index 8b8332e46f24059f561ca5b1f814ed849d51aa7b..d5e6938cc6bc06e9e2903a81da002289ae9e5688 100644 (file)
@@ -367,6 +367,7 @@ static int nouveau_rom_call(acpi_handle rom_handle, uint8_t *bios,
                return -ENODEV;
        }
        obj = (union acpi_object *)buffer.pointer;
+       len = min(len, (int)obj->buffer.length);
        memcpy(bios+offset, obj->buffer.pointer, len);
        kfree(buffer.pointer);
        return len;
index db6bc676054519b08f3dbe6e45a23782362c9376..64c8d932d5f19de27aa6f66c4e5371f5484cdd7c 100644 (file)
@@ -829,7 +829,6 @@ nouveau_finish_page_flip(struct nouveau_channel *chan,
        struct drm_device *dev = drm->dev;
        struct nouveau_page_flip_state *s;
        unsigned long flags;
-       int crtcid = -1;
 
        spin_lock_irqsave(&dev->event_lock, flags);
 
@@ -841,15 +840,19 @@ nouveau_finish_page_flip(struct nouveau_channel *chan,
 
        s = list_first_entry(&fctx->flip, struct nouveau_page_flip_state, head);
        if (s->event) {
-               /* Vblank timestamps/counts are only correct on >= NV-50 */
-               if (drm->device.info.family >= NV_DEVICE_INFO_V0_TESLA)
-                       crtcid = s->crtc;
+               if (drm->device.info.family < NV_DEVICE_INFO_V0_TESLA) {
+                       drm_arm_vblank_event(dev, s->crtc, s->event);
+               } else {
+                       drm_send_vblank_event(dev, s->crtc, s->event);
 
-               drm_send_vblank_event(dev, crtcid, s->event);
+                       /* Give up ownership of vblank for page-flipped crtc */
+                       drm_vblank_put(dev, s->crtc);
+               }
+       }
+       else {
+               /* Give up ownership of vblank for page-flipped crtc */
+               drm_vblank_put(dev, s->crtc);
        }
-
-       /* Give up ownership of vblank for page-flipped crtc */
-       drm_vblank_put(dev, s->crtc);
 
        list_del(&s->head);
        if (ps)
index 3050042e6c6d54b6fb1a07b48b66d23994e8d0ae..a02813e994ec574d57b695c310f6c60e443584f2 100644 (file)
@@ -39,6 +39,7 @@
 
 #include <nvif/client.h>
 #include <nvif/device.h>
+#include <nvif/ioctl.h>
 
 #include <drmP.h>
 
@@ -65,9 +66,10 @@ struct nouveau_drm_tile {
 };
 
 enum nouveau_drm_object_route {
-       NVDRM_OBJECT_NVIF = 0,
+       NVDRM_OBJECT_NVIF = NVIF_IOCTL_V0_OWNER_NVIF,
        NVDRM_OBJECT_USIF,
        NVDRM_OBJECT_ABI16,
+       NVDRM_OBJECT_ANY = NVIF_IOCTL_V0_OWNER_ANY,
 };
 
 enum nouveau_drm_notify_route {
index 89dc4ce63490e4d67d554b00ef44d18955479c7f..6ae1b3494bcd16a8492d65cffa95554d4125bfbc 100644 (file)
@@ -313,7 +313,10 @@ usif_ioctl(struct drm_file *filp, void __user *user, u32 argc)
        if (nvif_unpack(argv->v0, 0, 0, true)) {
                /* block access to objects not created via this interface */
                owner = argv->v0.owner;
-               argv->v0.owner = NVDRM_OBJECT_USIF;
+               if (argv->v0.object == 0ULL)
+                       argv->v0.owner = NVDRM_OBJECT_ANY; /* except client */
+               else
+                       argv->v0.owner = NVDRM_OBJECT_USIF;
        } else
                goto done;
 
index e3c783d0e2ab486abc37e09e5430b5013155392a..62ad0300cfa5ab0af8610773ae7d5c4b49e310bb 100644 (file)
@@ -258,12 +258,6 @@ nvkm_device_pci_10de_0df4[] = {
        {}
 };
 
-static const struct nvkm_device_pci_vendor
-nvkm_device_pci_10de_0fcd[] = {
-       { 0x17aa, 0x3801, NULL, { .War00C800_0 = true } }, /* Lenovo Y510P */
-       {}
-};
-
 static const struct nvkm_device_pci_vendor
 nvkm_device_pci_10de_0fd2[] = {
        { 0x1028, 0x0595, "GeForce GT 640M LE" },
@@ -684,7 +678,6 @@ nvkm_device_pci_10de_1189[] = {
 static const struct nvkm_device_pci_vendor
 nvkm_device_pci_10de_1199[] = {
        { 0x1458, 0xd001, "GeForce GTX 760" },
-       { 0x1462, 0x1106, "GeForce GTX 780M", { .War00C800_0 = true } }, /* Medion Erazer X7827 */
        {}
 };
 
@@ -694,14 +687,6 @@ nvkm_device_pci_10de_11e3[] = {
        {}
 };
 
-static const struct nvkm_device_pci_vendor
-nvkm_device_pci_10de_11fc[] = {
-       { 0x1179, 0x0001, NULL, { .War00C800_0 = true } }, /* Toshiba Tecra W50 */
-       { 0x17aa, 0x2211, NULL, { .War00C800_0 = true } }, /* Lenovo W541 */
-       { 0x17aa, 0x221e, NULL, { .War00C800_0 = true } }, /* Lenovo W541 */
-       {}
-};
-
 static const struct nvkm_device_pci_vendor
 nvkm_device_pci_10de_1247[] = {
        { 0x1043, 0x212a, "GeForce GT 635M" },
@@ -1356,7 +1341,7 @@ nvkm_device_pci_10de[] = {
        { 0x0fc6, "GeForce GTX 650" },
        { 0x0fc8, "GeForce GT 740" },
        { 0x0fc9, "GeForce GT 730" },
-       { 0x0fcd, "GeForce GT 755M", nvkm_device_pci_10de_0fcd },
+       { 0x0fcd, "GeForce GT 755M" },
        { 0x0fce, "GeForce GT 640M LE" },
        { 0x0fd1, "GeForce GT 650M" },
        { 0x0fd2, "GeForce GT 640M", nvkm_device_pci_10de_0fd2 },
@@ -1490,7 +1475,7 @@ nvkm_device_pci_10de[] = {
        { 0x11e2, "GeForce GTX 765M" },
        { 0x11e3, "GeForce GTX 760M", nvkm_device_pci_10de_11e3 },
        { 0x11fa, "Quadro K4000" },
-       { 0x11fc, "Quadro K2100M", nvkm_device_pci_10de_11fc },
+       { 0x11fc, "Quadro K2100M" },
        { 0x1200, "GeForce GTX 560 Ti" },
        { 0x1201, "GeForce GTX 560" },
        { 0x1203, "GeForce GTX 460 SE v2" },
index b5b875928abad24ad1350a9f342526680660a2b9..74de7a96c22afea939059db4a20ebc5adef162e1 100644 (file)
@@ -207,6 +207,8 @@ gf117_grctx_generate_attrib(struct gf100_grctx *info)
                        const u32 b =  beta * gr->ppc_tpc_nr[gpc][ppc];
                        const u32 t = timeslice_mode;
                        const u32 o = PPC_UNIT(gpc, ppc, 0);
+                       if (!(gr->ppc_mask[gpc] & (1 << ppc)))
+                               continue;
                        mmio_skip(info, o + 0xc0, (t << 28) | (b << 16) | ++bo);
                        mmio_wr32(info, o + 0xc0, (t << 28) | (b << 16) | --bo);
                        bo += grctx->attrib_nr_max * gr->ppc_tpc_nr[gpc][ppc];
index 194afe910d212885d01771a0355e4e8b009ab871..7dacb3cc0668afbce3841fecb99a189b15f780d6 100644 (file)
@@ -52,10 +52,12 @@ mmio_list_base:
 #endif
 
 #ifdef INCLUDE_CODE
+#define gpc_addr(reg,addr)                                                    /*
+*/     imm32(reg,addr)                                                       /*
+*/     or reg NV_PGRAPH_GPCX_GPCCS_MMIO_CTRL_BASE_ENABLE
 #define gpc_wr32(addr,reg)                                                    /*
+*/     gpc_addr($r14,addr)                                                   /*
 */     mov b32 $r15 reg                                                      /*
-*/     imm32($r14, addr)                                                     /*
-*/     or $r14 NV_PGRAPH_GPCX_GPCCS_MMIO_CTRL_BASE_ENABLE                    /*
 */     call(nv_wr32)
 
 // reports an exception to the host
@@ -161,7 +163,7 @@ init:
 
 #if NV_PGRAPH_GPCX_UNK__SIZE > 0
        // figure out which, and how many, UNKs are actually present
-       imm32($r14, 0x500c30)
+       gpc_addr($r14, 0x500c30)
        clear b32 $r2
        clear b32 $r3
        clear b32 $r4
index 64d07df4b8b14e3dd805948a783c41751adb8964..bb820ff28621f4e8c7dbb22cb6ac7f020dfafdfe 100644 (file)
@@ -314,7 +314,7 @@ uint32_t gf117_grgpc_code[] = {
        0x03f01200,
        0x0002d000,
        0x17f104bd,
-       0x10fe0542,
+       0x10fe0545,
        0x0007f100,
        0x0003f007,
        0xbd0000d0,
@@ -338,184 +338,184 @@ uint32_t gf117_grgpc_code[] = {
        0x02d00103,
        0xf104bd00,
        0xf00c30e7,
-       0x24bd50e3,
-       0x44bd34bd,
-/* 0x0430: init_unk_loop */
-       0xb06821f4,
-       0x0bf400f6,
-       0x01f7f00f,
-       0xfd04f2bb,
-       0x30b6054f,
-/* 0x0445: init_unk_next */
-       0x0120b601,
-       0xb004e0b6,
-       0x1bf40126,
-/* 0x0451: init_unk_done */
-       0x070380e2,
-       0xf1080480,
-       0xf0010027,
-       0x22cf0223,
-       0x9534bd00,
-       0x07f10825,
-       0x03f0c000,
-       0x0005d001,
-       0x07f104bd,
-       0x03f0c100,
-       0x0005d001,
-       0x0e9804bd,
-       0x010f9800,
-       0x015021f5,
-       0xbb002fbb,
-       0x0e98003f,
-       0x020f9801,
-       0x015021f5,
-       0xfd050e98,
-       0x2ebb00ef,
-       0x003ebb00,
-       0x98020e98,
-       0x21f5030f,
-       0x0e980150,
-       0x00effd07,
-       0xbb002ebb,
-       0x35b6003e,
-       0x0007f102,
-       0x0103f0d3,
-       0xbd0003d0,
-       0x0825b604,
-       0xb60635b6,
-       0x30b60120,
-       0x0824b601,
-       0xb90834b6,
-       0x21f5022f,
-       0x2fbb02d3,
-       0x003fbb00,
-       0x010007f1,
-       0xd00203f0,
+       0xe5f050e3,
+       0xbd24bd01,
+/* 0x0433: init_unk_loop */
+       0xf444bd34,
+       0xf6b06821,
+       0x0f0bf400,
+       0xbb01f7f0,
+       0x4ffd04f2,
+       0x0130b605,
+/* 0x0448: init_unk_next */
+       0xb60120b6,
+       0x26b004e0,
+       0xe21bf401,
+/* 0x0454: init_unk_done */
+       0x80070380,
+       0x27f10804,
+       0x23f00100,
+       0x0022cf02,
+       0x259534bd,
+       0x0007f108,
+       0x0103f0c0,
+       0xbd0005d0,
+       0x0007f104,
+       0x0103f0c1,
+       0xbd0005d0,
+       0x000e9804,
+       0xf5010f98,
+       0xbb015021,
+       0x3fbb002f,
+       0x010e9800,
+       0xf5020f98,
+       0x98015021,
+       0xeffd050e,
+       0x002ebb00,
+       0x98003ebb,
+       0x0f98020e,
+       0x5021f503,
+       0x070e9801,
+       0xbb00effd,
+       0x3ebb002e,
+       0x0235b600,
+       0xd30007f1,
+       0xd00103f0,
        0x04bd0003,
-       0x29f024bd,
-       0x0007f11f,
-       0x0203f008,
-       0xbd0002d0,
-/* 0x0505: main */
-       0x0031f404,
-       0xf00028f4,
-       0x21f424d7,
-       0xf401f439,
-       0xf404e4b0,
-       0x81fe1e18,
-       0x0627f001,
-       0x12fd20bd,
-       0x01e4b604,
-       0xfe051efd,
-       0x21f50018,
-       0x0ef405fa,
-/* 0x0535: main_not_ctx_xfer */
-       0x10ef94d3,
-       0xf501f5f0,
-       0xf4037e21,
-/* 0x0542: ih */
-       0x80f9c60e,
-       0xf90188fe,
-       0xf990f980,
-       0xf9b0f9a0,
-       0xf9e0f9d0,
-       0xf104bdf0,
-       0xf00200a7,
-       0xaacf00a3,
-       0x04abc400,
-       0xf02c0bf4,
-       0xe7f124d7,
-       0xe3f01a00,
-       0x00eecf00,
-       0x1900f7f1,
-       0xcf00f3f0,
-       0x21f400ff,
-       0x01e7f004,
-       0x1d0007f1,
-       0xd00003f0,
-       0x04bd000e,
-/* 0x0590: ih_no_fifo */
-       0x010007f1,
-       0xd00003f0,
-       0x04bd000a,
-       0xe0fcf0fc,
-       0xb0fcd0fc,
-       0x90fca0fc,
-       0x88fe80fc,
-       0xf480fc00,
-       0x01f80032,
-/* 0x05b4: hub_barrier_done */
-       0x9801f7f0,
-       0xfebb040e,
-       0x02ffb904,
-       0x9418e7f1,
-       0xf440e3f0,
-       0x00f89d21,
-/* 0x05cc: ctx_redswitch */
-       0xf120f7f0,
+       0xb60825b6,
+       0x20b60635,
+       0x0130b601,
+       0xb60824b6,
+       0x2fb90834,
+       0xd321f502,
+       0x002fbb02,
+       0xf1003fbb,
+       0xf0010007,
+       0x03d00203,
+       0xbd04bd00,
+       0x1f29f024,
+       0x080007f1,
+       0xd00203f0,
+       0x04bd0002,
+/* 0x0508: main */
+       0xf40031f4,
+       0xd7f00028,
+       0x3921f424,
+       0xb0f401f4,
+       0x18f404e4,
+       0x0181fe1e,
+       0xbd0627f0,
+       0x0412fd20,
+       0xfd01e4b6,
+       0x18fe051e,
+       0xfd21f500,
+       0xd30ef405,
+/* 0x0538: main_not_ctx_xfer */
+       0xf010ef94,
+       0x21f501f5,
+       0x0ef4037e,
+/* 0x0545: ih */
+       0xfe80f9c6,
+       0x80f90188,
+       0xa0f990f9,
+       0xd0f9b0f9,
+       0xf0f9e0f9,
+       0xa7f104bd,
+       0xa3f00200,
+       0x00aacf00,
+       0xf404abc4,
+       0xd7f02c0b,
+       0x00e7f124,
+       0x00e3f01a,
+       0xf100eecf,
+       0xf01900f7,
+       0xffcf00f3,
+       0x0421f400,
+       0xf101e7f0,
+       0xf01d0007,
+       0x0ed00003,
+/* 0x0593: ih_no_fifo */
+       0xf104bd00,
+       0xf0010007,
+       0x0ad00003,
+       0xfc04bd00,
+       0xfce0fcf0,
+       0xfcb0fcd0,
+       0xfc90fca0,
+       0x0088fe80,
+       0x32f480fc,
+/* 0x05b7: hub_barrier_done */
+       0xf001f800,
+       0x0e9801f7,
+       0x04febb04,
+       0xf102ffb9,
+       0xf09418e7,
+       0x21f440e3,
+/* 0x05cf: ctx_redswitch */
+       0xf000f89d,
+       0x07f120f7,
+       0x03f08500,
+       0x000fd001,
+       0xe7f004bd,
+/* 0x05e1: ctx_redswitch_delay */
+       0x01e2b608,
+       0xf1fd1bf4,
+       0xf10800f5,
+       0xf10200f5,
        0xf0850007,
        0x0fd00103,
-       0xf004bd00,
-/* 0x05de: ctx_redswitch_delay */
-       0xe2b608e7,
-       0xfd1bf401,
-       0x0800f5f1,
-       0x0200f5f1,
-       0x850007f1,
-       0xd00103f0,
-       0x04bd000f,
-/* 0x05fa: ctx_xfer */
-       0x07f100f8,
-       0x03f08100,
-       0x000fd002,
-       0x11f404bd,
-       0xcc21f507,
-/* 0x060d: ctx_xfer_not_load */
-       0x6a21f505,
-       0xf124bd02,
-       0xf047fc07,
-       0x02d00203,
-       0xf004bd00,
-       0x20b6012c,
-       0xfc07f103,
-       0x0203f04a,
-       0xbd0002d0,
-       0x01acf004,
-       0xf102a5f0,
-       0xf00000b7,
-       0x0c9850b3,
-       0x0fc4b604,
-       0x9800bcbb,
-       0x0d98000c,
-       0x00e7f001,
-       0x016f21f5,
-       0xf101acf0,
-       0xf04000b7,
-       0x0c9850b3,
-       0x0fc4b604,
-       0x9800bcbb,
-       0x0d98010c,
-       0x060f9802,
-       0x0800e7f1,
-       0x016f21f5,
+       0xf804bd00,
+/* 0x05fd: ctx_xfer */
+       0x0007f100,
+       0x0203f081,
+       0xbd000fd0,
+       0x0711f404,
+       0x05cf21f5,
+/* 0x0610: ctx_xfer_not_load */
+       0x026a21f5,
+       0x07f124bd,
+       0x03f047fc,
+       0x0002d002,
+       0x2cf004bd,
+       0x0320b601,
+       0x4afc07f1,
+       0xd00203f0,
+       0x04bd0002,
        0xf001acf0,
-       0xb7f104a5,
-       0xb3f03000,
+       0xb7f102a5,
+       0xb3f00000,
        0x040c9850,
        0xbb0fc4b6,
        0x0c9800bc,
-       0x030d9802,
-       0xf1080f98,
-       0xf50200e7,
-       0xf5016f21,
-       0xf4025e21,
-       0x12f40601,
-/* 0x06a9: ctx_xfer_post */
-       0x7f21f507,
-/* 0x06ad: ctx_xfer_done */
-       0xb421f502,
-       0x0000f805,
-       0x00000000,
+       0x010d9800,
+       0xf500e7f0,
+       0xf0016f21,
+       0xb7f101ac,
+       0xb3f04000,
+       0x040c9850,
+       0xbb0fc4b6,
+       0x0c9800bc,
+       0x020d9801,
+       0xf1060f98,
+       0xf50800e7,
+       0xf0016f21,
+       0xa5f001ac,
+       0x00b7f104,
+       0x50b3f030,
+       0xb6040c98,
+       0xbcbb0fc4,
+       0x020c9800,
+       0x98030d98,
+       0xe7f1080f,
+       0x21f50200,
+       0x21f5016f,
+       0x01f4025e,
+       0x0712f406,
+/* 0x06ac: ctx_xfer_post */
+       0x027f21f5,
+/* 0x06b0: ctx_xfer_done */
+       0x05b721f5,
+       0x000000f8,
        0x00000000,
        0x00000000,
        0x00000000,
index 2f596433c2220048fd55a7ee252f74619f7e041e..911976d209400fb565d84761875ba8ed0db94d3b 100644 (file)
@@ -314,7 +314,7 @@ uint32_t gk104_grgpc_code[] = {
        0x03f01200,
        0x0002d000,
        0x17f104bd,
-       0x10fe0542,
+       0x10fe0545,
        0x0007f100,
        0x0003f007,
        0xbd0000d0,
@@ -338,184 +338,184 @@ uint32_t gk104_grgpc_code[] = {
        0x02d00103,
        0xf104bd00,
        0xf00c30e7,
-       0x24bd50e3,
-       0x44bd34bd,
-/* 0x0430: init_unk_loop */
-       0xb06821f4,
-       0x0bf400f6,
-       0x01f7f00f,
-       0xfd04f2bb,
-       0x30b6054f,
-/* 0x0445: init_unk_next */
-       0x0120b601,
-       0xb004e0b6,
-       0x1bf40126,
-/* 0x0451: init_unk_done */
-       0x070380e2,
-       0xf1080480,
-       0xf0010027,
-       0x22cf0223,
-       0x9534bd00,
-       0x07f10825,
-       0x03f0c000,
-       0x0005d001,
-       0x07f104bd,
-       0x03f0c100,
-       0x0005d001,
-       0x0e9804bd,
-       0x010f9800,
-       0x015021f5,
-       0xbb002fbb,
-       0x0e98003f,
-       0x020f9801,
-       0x015021f5,
-       0xfd050e98,
-       0x2ebb00ef,
-       0x003ebb00,
-       0x98020e98,
-       0x21f5030f,
-       0x0e980150,
-       0x00effd07,
-       0xbb002ebb,
-       0x35b6003e,
-       0x0007f102,
-       0x0103f0d3,
-       0xbd0003d0,
-       0x0825b604,
-       0xb60635b6,
-       0x30b60120,
-       0x0824b601,
-       0xb90834b6,
-       0x21f5022f,
-       0x2fbb02d3,
-       0x003fbb00,
-       0x010007f1,
-       0xd00203f0,
+       0xe5f050e3,
+       0xbd24bd01,
+/* 0x0433: init_unk_loop */
+       0xf444bd34,
+       0xf6b06821,
+       0x0f0bf400,
+       0xbb01f7f0,
+       0x4ffd04f2,
+       0x0130b605,
+/* 0x0448: init_unk_next */
+       0xb60120b6,
+       0x26b004e0,
+       0xe21bf401,
+/* 0x0454: init_unk_done */
+       0x80070380,
+       0x27f10804,
+       0x23f00100,
+       0x0022cf02,
+       0x259534bd,
+       0x0007f108,
+       0x0103f0c0,
+       0xbd0005d0,
+       0x0007f104,
+       0x0103f0c1,
+       0xbd0005d0,
+       0x000e9804,
+       0xf5010f98,
+       0xbb015021,
+       0x3fbb002f,
+       0x010e9800,
+       0xf5020f98,
+       0x98015021,
+       0xeffd050e,
+       0x002ebb00,
+       0x98003ebb,
+       0x0f98020e,
+       0x5021f503,
+       0x070e9801,
+       0xbb00effd,
+       0x3ebb002e,
+       0x0235b600,
+       0xd30007f1,
+       0xd00103f0,
        0x04bd0003,
-       0x29f024bd,
-       0x0007f11f,
-       0x0203f008,
-       0xbd0002d0,
-/* 0x0505: main */
-       0x0031f404,
-       0xf00028f4,
-       0x21f424d7,
-       0xf401f439,
-       0xf404e4b0,
-       0x81fe1e18,
-       0x0627f001,
-       0x12fd20bd,
-       0x01e4b604,
-       0xfe051efd,
-       0x21f50018,
-       0x0ef405fa,
-/* 0x0535: main_not_ctx_xfer */
-       0x10ef94d3,
-       0xf501f5f0,
-       0xf4037e21,
-/* 0x0542: ih */
-       0x80f9c60e,
-       0xf90188fe,
-       0xf990f980,
-       0xf9b0f9a0,
-       0xf9e0f9d0,
-       0xf104bdf0,
-       0xf00200a7,
-       0xaacf00a3,
-       0x04abc400,
-       0xf02c0bf4,
-       0xe7f124d7,
-       0xe3f01a00,
-       0x00eecf00,
-       0x1900f7f1,
-       0xcf00f3f0,
-       0x21f400ff,
-       0x01e7f004,
-       0x1d0007f1,
-       0xd00003f0,
-       0x04bd000e,
-/* 0x0590: ih_no_fifo */
-       0x010007f1,
-       0xd00003f0,
-       0x04bd000a,
-       0xe0fcf0fc,
-       0xb0fcd0fc,
-       0x90fca0fc,
-       0x88fe80fc,
-       0xf480fc00,
-       0x01f80032,
-/* 0x05b4: hub_barrier_done */
-       0x9801f7f0,
-       0xfebb040e,
-       0x02ffb904,
-       0x9418e7f1,
-       0xf440e3f0,
-       0x00f89d21,
-/* 0x05cc: ctx_redswitch */
-       0xf120f7f0,
+       0xb60825b6,
+       0x20b60635,
+       0x0130b601,
+       0xb60824b6,
+       0x2fb90834,
+       0xd321f502,
+       0x002fbb02,
+       0xf1003fbb,
+       0xf0010007,
+       0x03d00203,
+       0xbd04bd00,
+       0x1f29f024,
+       0x080007f1,
+       0xd00203f0,
+       0x04bd0002,
+/* 0x0508: main */
+       0xf40031f4,
+       0xd7f00028,
+       0x3921f424,
+       0xb0f401f4,
+       0x18f404e4,
+       0x0181fe1e,
+       0xbd0627f0,
+       0x0412fd20,
+       0xfd01e4b6,
+       0x18fe051e,
+       0xfd21f500,
+       0xd30ef405,
+/* 0x0538: main_not_ctx_xfer */
+       0xf010ef94,
+       0x21f501f5,
+       0x0ef4037e,
+/* 0x0545: ih */
+       0xfe80f9c6,
+       0x80f90188,
+       0xa0f990f9,
+       0xd0f9b0f9,
+       0xf0f9e0f9,
+       0xa7f104bd,
+       0xa3f00200,
+       0x00aacf00,
+       0xf404abc4,
+       0xd7f02c0b,
+       0x00e7f124,
+       0x00e3f01a,
+       0xf100eecf,
+       0xf01900f7,
+       0xffcf00f3,
+       0x0421f400,
+       0xf101e7f0,
+       0xf01d0007,
+       0x0ed00003,
+/* 0x0593: ih_no_fifo */
+       0xf104bd00,
+       0xf0010007,
+       0x0ad00003,
+       0xfc04bd00,
+       0xfce0fcf0,
+       0xfcb0fcd0,
+       0xfc90fca0,
+       0x0088fe80,
+       0x32f480fc,
+/* 0x05b7: hub_barrier_done */
+       0xf001f800,
+       0x0e9801f7,
+       0x04febb04,
+       0xf102ffb9,
+       0xf09418e7,
+       0x21f440e3,
+/* 0x05cf: ctx_redswitch */
+       0xf000f89d,
+       0x07f120f7,
+       0x03f08500,
+       0x000fd001,
+       0xe7f004bd,
+/* 0x05e1: ctx_redswitch_delay */
+       0x01e2b608,
+       0xf1fd1bf4,
+       0xf10800f5,
+       0xf10200f5,
        0xf0850007,
        0x0fd00103,
-       0xf004bd00,
-/* 0x05de: ctx_redswitch_delay */
-       0xe2b608e7,
-       0xfd1bf401,
-       0x0800f5f1,
-       0x0200f5f1,
-       0x850007f1,
-       0xd00103f0,
-       0x04bd000f,
-/* 0x05fa: ctx_xfer */
-       0x07f100f8,
-       0x03f08100,
-       0x000fd002,
-       0x11f404bd,
-       0xcc21f507,
-/* 0x060d: ctx_xfer_not_load */
-       0x6a21f505,
-       0xf124bd02,
-       0xf047fc07,
-       0x02d00203,
-       0xf004bd00,
-       0x20b6012c,
-       0xfc07f103,
-       0x0203f04a,
-       0xbd0002d0,
-       0x01acf004,
-       0xf102a5f0,
-       0xf00000b7,
-       0x0c9850b3,
-       0x0fc4b604,
-       0x9800bcbb,
-       0x0d98000c,
-       0x00e7f001,
-       0x016f21f5,
-       0xf101acf0,
-       0xf04000b7,
-       0x0c9850b3,
-       0x0fc4b604,
-       0x9800bcbb,
-       0x0d98010c,
-       0x060f9802,
-       0x0800e7f1,
-       0x016f21f5,
+       0xf804bd00,
+/* 0x05fd: ctx_xfer */
+       0x0007f100,
+       0x0203f081,
+       0xbd000fd0,
+       0x0711f404,
+       0x05cf21f5,
+/* 0x0610: ctx_xfer_not_load */
+       0x026a21f5,
+       0x07f124bd,
+       0x03f047fc,
+       0x0002d002,
+       0x2cf004bd,
+       0x0320b601,
+       0x4afc07f1,
+       0xd00203f0,
+       0x04bd0002,
        0xf001acf0,
-       0xb7f104a5,
-       0xb3f03000,
+       0xb7f102a5,
+       0xb3f00000,
        0x040c9850,
        0xbb0fc4b6,
        0x0c9800bc,
-       0x030d9802,
-       0xf1080f98,
-       0xf50200e7,
-       0xf5016f21,
-       0xf4025e21,
-       0x12f40601,
-/* 0x06a9: ctx_xfer_post */
-       0x7f21f507,
-/* 0x06ad: ctx_xfer_done */
-       0xb421f502,
-       0x0000f805,
-       0x00000000,
+       0x010d9800,
+       0xf500e7f0,
+       0xf0016f21,
+       0xb7f101ac,
+       0xb3f04000,
+       0x040c9850,
+       0xbb0fc4b6,
+       0x0c9800bc,
+       0x020d9801,
+       0xf1060f98,
+       0xf50800e7,
+       0xf0016f21,
+       0xa5f001ac,
+       0x00b7f104,
+       0x50b3f030,
+       0xb6040c98,
+       0xbcbb0fc4,
+       0x020c9800,
+       0x98030d98,
+       0xe7f1080f,
+       0x21f50200,
+       0x21f5016f,
+       0x01f4025e,
+       0x0712f406,
+/* 0x06ac: ctx_xfer_post */
+       0x027f21f5,
+/* 0x06b0: ctx_xfer_done */
+       0x05b721f5,
+       0x000000f8,
        0x00000000,
        0x00000000,
        0x00000000,
index ee8e54db8fc9ed83bd5da4c176de4e4fbe6bed73..1c6e11b05df2e910685b76ebfbe37b046718d0bb 100644 (file)
@@ -314,7 +314,7 @@ uint32_t gk110_grgpc_code[] = {
        0x03f01200,
        0x0002d000,
        0x17f104bd,
-       0x10fe0542,
+       0x10fe0545,
        0x0007f100,
        0x0003f007,
        0xbd0000d0,
@@ -338,184 +338,184 @@ uint32_t gk110_grgpc_code[] = {
        0x02d00103,
        0xf104bd00,
        0xf00c30e7,
-       0x24bd50e3,
-       0x44bd34bd,
-/* 0x0430: init_unk_loop */
-       0xb06821f4,
-       0x0bf400f6,
-       0x01f7f00f,
-       0xfd04f2bb,
-       0x30b6054f,
-/* 0x0445: init_unk_next */
-       0x0120b601,
-       0xb004e0b6,
-       0x1bf40226,
-/* 0x0451: init_unk_done */
-       0x070380e2,
-       0xf1080480,
-       0xf0010027,
-       0x22cf0223,
-       0x9534bd00,
-       0x07f10825,
-       0x03f0c000,
-       0x0005d001,
-       0x07f104bd,
-       0x03f0c100,
-       0x0005d001,
-       0x0e9804bd,
-       0x010f9800,
-       0x015021f5,
-       0xbb002fbb,
-       0x0e98003f,
-       0x020f9801,
-       0x015021f5,
-       0xfd050e98,
-       0x2ebb00ef,
-       0x003ebb00,
-       0x98020e98,
-       0x21f5030f,
-       0x0e980150,
-       0x00effd07,
-       0xbb002ebb,
-       0x35b6003e,
-       0x0007f102,
-       0x0103f0d3,
-       0xbd0003d0,
-       0x0825b604,
-       0xb60635b6,
-       0x30b60120,
-       0x0824b601,
-       0xb90834b6,
-       0x21f5022f,
-       0x2fbb02d3,
-       0x003fbb00,
-       0x010007f1,
-       0xd00203f0,
+       0xe5f050e3,
+       0xbd24bd01,
+/* 0x0433: init_unk_loop */
+       0xf444bd34,
+       0xf6b06821,
+       0x0f0bf400,
+       0xbb01f7f0,
+       0x4ffd04f2,
+       0x0130b605,
+/* 0x0448: init_unk_next */
+       0xb60120b6,
+       0x26b004e0,
+       0xe21bf402,
+/* 0x0454: init_unk_done */
+       0x80070380,
+       0x27f10804,
+       0x23f00100,
+       0x0022cf02,
+       0x259534bd,
+       0x0007f108,
+       0x0103f0c0,
+       0xbd0005d0,
+       0x0007f104,
+       0x0103f0c1,
+       0xbd0005d0,
+       0x000e9804,
+       0xf5010f98,
+       0xbb015021,
+       0x3fbb002f,
+       0x010e9800,
+       0xf5020f98,
+       0x98015021,
+       0xeffd050e,
+       0x002ebb00,
+       0x98003ebb,
+       0x0f98020e,
+       0x5021f503,
+       0x070e9801,
+       0xbb00effd,
+       0x3ebb002e,
+       0x0235b600,
+       0xd30007f1,
+       0xd00103f0,
        0x04bd0003,
-       0x29f024bd,
-       0x0007f11f,
-       0x0203f030,
-       0xbd0002d0,
-/* 0x0505: main */
-       0x0031f404,
-       0xf00028f4,
-       0x21f424d7,
-       0xf401f439,
-       0xf404e4b0,
-       0x81fe1e18,
-       0x0627f001,
-       0x12fd20bd,
-       0x01e4b604,
-       0xfe051efd,
-       0x21f50018,
-       0x0ef405fa,
-/* 0x0535: main_not_ctx_xfer */
-       0x10ef94d3,
-       0xf501f5f0,
-       0xf4037e21,
-/* 0x0542: ih */
-       0x80f9c60e,
-       0xf90188fe,
-       0xf990f980,
-       0xf9b0f9a0,
-       0xf9e0f9d0,
-       0xf104bdf0,
-       0xf00200a7,
-       0xaacf00a3,
-       0x04abc400,
-       0xf02c0bf4,
-       0xe7f124d7,
-       0xe3f01a00,
-       0x00eecf00,
-       0x1900f7f1,
-       0xcf00f3f0,
-       0x21f400ff,
-       0x01e7f004,
-       0x1d0007f1,
-       0xd00003f0,
-       0x04bd000e,
-/* 0x0590: ih_no_fifo */
-       0x010007f1,
-       0xd00003f0,
-       0x04bd000a,
-       0xe0fcf0fc,
-       0xb0fcd0fc,
-       0x90fca0fc,
-       0x88fe80fc,
-       0xf480fc00,
-       0x01f80032,
-/* 0x05b4: hub_barrier_done */
-       0x9801f7f0,
-       0xfebb040e,
-       0x02ffb904,
-       0x9418e7f1,
-       0xf440e3f0,
-       0x00f89d21,
-/* 0x05cc: ctx_redswitch */
-       0xf120f7f0,
+       0xb60825b6,
+       0x20b60635,
+       0x0130b601,
+       0xb60824b6,
+       0x2fb90834,
+       0xd321f502,
+       0x002fbb02,
+       0xf1003fbb,
+       0xf0010007,
+       0x03d00203,
+       0xbd04bd00,
+       0x1f29f024,
+       0x300007f1,
+       0xd00203f0,
+       0x04bd0002,
+/* 0x0508: main */
+       0xf40031f4,
+       0xd7f00028,
+       0x3921f424,
+       0xb0f401f4,
+       0x18f404e4,
+       0x0181fe1e,
+       0xbd0627f0,
+       0x0412fd20,
+       0xfd01e4b6,
+       0x18fe051e,
+       0xfd21f500,
+       0xd30ef405,
+/* 0x0538: main_not_ctx_xfer */
+       0xf010ef94,
+       0x21f501f5,
+       0x0ef4037e,
+/* 0x0545: ih */
+       0xfe80f9c6,
+       0x80f90188,
+       0xa0f990f9,
+       0xd0f9b0f9,
+       0xf0f9e0f9,
+       0xa7f104bd,
+       0xa3f00200,
+       0x00aacf00,
+       0xf404abc4,
+       0xd7f02c0b,
+       0x00e7f124,
+       0x00e3f01a,
+       0xf100eecf,
+       0xf01900f7,
+       0xffcf00f3,
+       0x0421f400,
+       0xf101e7f0,
+       0xf01d0007,
+       0x0ed00003,
+/* 0x0593: ih_no_fifo */
+       0xf104bd00,
+       0xf0010007,
+       0x0ad00003,
+       0xfc04bd00,
+       0xfce0fcf0,
+       0xfcb0fcd0,
+       0xfc90fca0,
+       0x0088fe80,
+       0x32f480fc,
+/* 0x05b7: hub_barrier_done */
+       0xf001f800,
+       0x0e9801f7,
+       0x04febb04,
+       0xf102ffb9,
+       0xf09418e7,
+       0x21f440e3,
+/* 0x05cf: ctx_redswitch */
+       0xf000f89d,
+       0x07f120f7,
+       0x03f08500,
+       0x000fd001,
+       0xe7f004bd,
+/* 0x05e1: ctx_redswitch_delay */
+       0x01e2b608,
+       0xf1fd1bf4,
+       0xf10800f5,
+       0xf10200f5,
        0xf0850007,
        0x0fd00103,
-       0xf004bd00,
-/* 0x05de: ctx_redswitch_delay */
-       0xe2b608e7,
-       0xfd1bf401,
-       0x0800f5f1,
-       0x0200f5f1,
-       0x850007f1,
-       0xd00103f0,
-       0x04bd000f,
-/* 0x05fa: ctx_xfer */
-       0x07f100f8,
-       0x03f08100,
-       0x000fd002,
-       0x11f404bd,
-       0xcc21f507,
-/* 0x060d: ctx_xfer_not_load */
-       0x6a21f505,
-       0xf124bd02,
-       0xf047fc07,
-       0x02d00203,
-       0xf004bd00,
-       0x20b6012c,
-       0xfc07f103,
-       0x0203f04a,
-       0xbd0002d0,
-       0x01acf004,
-       0xf102a5f0,
-       0xf00000b7,
-       0x0c9850b3,
-       0x0fc4b604,
-       0x9800bcbb,
-       0x0d98000c,
-       0x00e7f001,
-       0x016f21f5,
-       0xf101acf0,
-       0xf04000b7,
-       0x0c9850b3,
-       0x0fc4b604,
-       0x9800bcbb,
-       0x0d98010c,
-       0x060f9802,
-       0x0800e7f1,
-       0x016f21f5,
+       0xf804bd00,
+/* 0x05fd: ctx_xfer */
+       0x0007f100,
+       0x0203f081,
+       0xbd000fd0,
+       0x0711f404,
+       0x05cf21f5,
+/* 0x0610: ctx_xfer_not_load */
+       0x026a21f5,
+       0x07f124bd,
+       0x03f047fc,
+       0x0002d002,
+       0x2cf004bd,
+       0x0320b601,
+       0x4afc07f1,
+       0xd00203f0,
+       0x04bd0002,
        0xf001acf0,
-       0xb7f104a5,
-       0xb3f03000,
+       0xb7f102a5,
+       0xb3f00000,
        0x040c9850,
        0xbb0fc4b6,
        0x0c9800bc,
-       0x030d9802,
-       0xf1080f98,
-       0xf50200e7,
-       0xf5016f21,
-       0xf4025e21,
-       0x12f40601,
-/* 0x06a9: ctx_xfer_post */
-       0x7f21f507,
-/* 0x06ad: ctx_xfer_done */
-       0xb421f502,
-       0x0000f805,
-       0x00000000,
+       0x010d9800,
+       0xf500e7f0,
+       0xf0016f21,
+       0xb7f101ac,
+       0xb3f04000,
+       0x040c9850,
+       0xbb0fc4b6,
+       0x0c9800bc,
+       0x020d9801,
+       0xf1060f98,
+       0xf50800e7,
+       0xf0016f21,
+       0xa5f001ac,
+       0x00b7f104,
+       0x50b3f030,
+       0xb6040c98,
+       0xbcbb0fc4,
+       0x020c9800,
+       0x98030d98,
+       0xe7f1080f,
+       0x21f50200,
+       0x21f5016f,
+       0x01f4025e,
+       0x0712f406,
+/* 0x06ac: ctx_xfer_post */
+       0x027f21f5,
+/* 0x06b0: ctx_xfer_done */
+       0x05b721f5,
+       0x000000f8,
        0x00000000,
        0x00000000,
        0x00000000,
index fbcc342f896f144708e059093156c0e99210e952..84af7ec6a78ea7df9f0f5e86e5a0e3764790a4d0 100644 (file)
@@ -276,7 +276,7 @@ uint32_t gk208_grgpc_code[] = {
        0x02020014,
        0xf6120040,
        0x04bd0002,
-       0xfe048141,
+       0xfe048441,
        0x00400010,
        0x0000f607,
        0x040204bd,
@@ -295,165 +295,165 @@ uint32_t gk208_grgpc_code[] = {
        0x01c90080,
        0xbd0002f6,
        0x0c308e04,
-       0xbd24bd50,
-/* 0x0383: init_unk_loop */
-       0x7e44bd34,
-       0xb0000065,
-       0x0bf400f6,
-       0xbb010f0e,
-       0x4ffd04f2,
-       0x0130b605,
-/* 0x0398: init_unk_next */
-       0xb60120b6,
-       0x26b004e0,
-       0xe21bf401,
-/* 0x03a4: init_unk_done */
-       0xb50703b5,
-       0x00820804,
-       0x22cf0201,
-       0x9534bd00,
-       0x00800825,
-       0x05f601c0,
-       0x8004bd00,
-       0xf601c100,
-       0x04bd0005,
-       0x98000e98,
-       0x207e010f,
-       0x2fbb0001,
-       0x003fbb00,
-       0x98010e98,
-       0x207e020f,
-       0x0e980001,
-       0x00effd05,
-       0xbb002ebb,
-       0x0e98003e,
-       0x030f9802,
-       0x0001207e,
-       0xfd070e98,
-       0x2ebb00ef,
-       0x003ebb00,
-       0x800235b6,
-       0xf601d300,
-       0x04bd0003,
-       0xb60825b6,
-       0x20b60635,
-       0x0130b601,
-       0xb60824b6,
-       0x2fb20834,
-       0x0002687e,
-       0xbb002fbb,
-       0x0080003f,
-       0x03f60201,
-       0xbd04bd00,
-       0x1f29f024,
-       0x02300080,
-       0xbd0002f6,
-/* 0x0445: main */
-       0x0031f404,
-       0x0d0028f4,
-       0x00377e24,
-       0xf401f400,
-       0xf404e4b0,
-       0x81fe1d18,
-       0xbd060201,
-       0x0412fd20,
-       0xfd01e4b6,
-       0x18fe051e,
-       0x05187e00,
-       0xd40ef400,
-/* 0x0474: main_not_ctx_xfer */
-       0xf010ef94,
-       0xf87e01f5,
-       0x0ef40002,
-/* 0x0481: ih */
-       0xfe80f9c7,
-       0x80f90188,
-       0xa0f990f9,
-       0xd0f9b0f9,
-       0xf0f9e0f9,
-       0x004a04bd,
-       0x00aacf02,
-       0xf404abc4,
-       0x240d1f0b,
-       0xcf1a004e,
-       0x004f00ee,
-       0x00ffcf19,
-       0x0000047e,
-       0x0040010e,
-       0x000ef61d,
-/* 0x04be: ih_no_fifo */
-       0x004004bd,
-       0x000af601,
-       0xf0fc04bd,
-       0xd0fce0fc,
-       0xa0fcb0fc,
-       0x80fc90fc,
-       0xfc0088fe,
-       0x0032f480,
-/* 0x04de: hub_barrier_done */
-       0x010f01f8,
-       0xbb040e98,
-       0xffb204fe,
-       0x4094188e,
-       0x00008f7e,
-/* 0x04f2: ctx_redswitch */
-       0x200f00f8,
+       0x01e5f050,
+       0x34bd24bd,
+/* 0x0386: init_unk_loop */
+       0x657e44bd,
+       0xf6b00000,
+       0x0e0bf400,
+       0xf2bb010f,
+       0x054ffd04,
+/* 0x039b: init_unk_next */
+       0xb60130b6,
+       0xe0b60120,
+       0x0126b004,
+/* 0x03a7: init_unk_done */
+       0xb5e21bf4,
+       0x04b50703,
+       0x01008208,
+       0x0022cf02,
+       0x259534bd,
+       0xc0008008,
+       0x0005f601,
+       0x008004bd,
+       0x05f601c1,
+       0x9804bd00,
+       0x0f98000e,
+       0x01207e01,
+       0x002fbb00,
+       0x98003fbb,
+       0x0f98010e,
+       0x01207e02,
+       0x050e9800,
+       0xbb00effd,
+       0x3ebb002e,
+       0x020e9800,
+       0x7e030f98,
+       0x98000120,
+       0xeffd070e,
+       0x002ebb00,
+       0xb6003ebb,
+       0x00800235,
+       0x03f601d3,
+       0xb604bd00,
+       0x35b60825,
+       0x0120b606,
+       0xb60130b6,
+       0x34b60824,
+       0x7e2fb208,
+       0xbb000268,
+       0x3fbb002f,
+       0x01008000,
+       0x0003f602,
+       0x24bd04bd,
+       0x801f29f0,
+       0xf6023000,
+       0x04bd0002,
+/* 0x0448: main */
+       0xf40031f4,
+       0x240d0028,
+       0x0000377e,
+       0xb0f401f4,
+       0x18f404e4,
+       0x0181fe1d,
+       0x20bd0602,
+       0xb60412fd,
+       0x1efd01e4,
+       0x0018fe05,
+       0x00051b7e,
+/* 0x0477: main_not_ctx_xfer */
+       0x94d40ef4,
+       0xf5f010ef,
+       0x02f87e01,
+       0xc70ef400,
+/* 0x0484: ih */
+       0x88fe80f9,
+       0xf980f901,
+       0xf9a0f990,
+       0xf9d0f9b0,
+       0xbdf0f9e0,
+       0x02004a04,
+       0xc400aacf,
+       0x0bf404ab,
+       0x4e240d1f,
+       0xeecf1a00,
+       0x19004f00,
+       0x7e00ffcf,
+       0x0e000004,
+       0x1d004001,
+       0xbd000ef6,
+/* 0x04c1: ih_no_fifo */
+       0x01004004,
+       0xbd000af6,
+       0xfcf0fc04,
+       0xfcd0fce0,
+       0xfca0fcb0,
+       0xfe80fc90,
+       0x80fc0088,
+       0xf80032f4,
+/* 0x04e1: hub_barrier_done */
+       0x98010f01,
+       0xfebb040e,
+       0x8effb204,
+       0x7e409418,
+       0xf800008f,
+/* 0x04f5: ctx_redswitch */
+       0x80200f00,
+       0xf6018500,
+       0x04bd000f,
+/* 0x0502: ctx_redswitch_delay */
+       0xe2b6080e,
+       0xfd1bf401,
+       0x0800f5f1,
+       0x0200f5f1,
        0x01850080,
        0xbd000ff6,
-/* 0x04ff: ctx_redswitch_delay */
-       0xb6080e04,
-       0x1bf401e2,
-       0x00f5f1fd,
-       0x00f5f108,
-       0x85008002,
-       0x000ff601,
-       0x00f804bd,
-/* 0x0518: ctx_xfer */
-       0x02810080,
-       0xbd000ff6,
-       0x0711f404,
-       0x0004f27e,
-/* 0x0528: ctx_xfer_not_load */
-       0x0002167e,
-       0xfc8024bd,
-       0x02f60247,
-       0xf004bd00,
-       0x20b6012c,
-       0x4afc8003,
+/* 0x051b: ctx_xfer */
+       0x8000f804,
+       0xf6028100,
+       0x04bd000f,
+       0x7e0711f4,
+/* 0x052b: ctx_xfer_not_load */
+       0x7e0004f5,
+       0xbd000216,
+       0x47fc8024,
        0x0002f602,
-       0xacf004bd,
-       0x02a5f001,
-       0x5000008b,
-       0xb6040c98,
-       0xbcbb0fc4,
-       0x000c9800,
-       0x0e010d98,
-       0x013d7e00,
-       0x01acf000,
-       0x5040008b,
-       0xb6040c98,
-       0xbcbb0fc4,
-       0x010c9800,
-       0x98020d98,
-       0x004e060f,
-       0x013d7e08,
-       0x01acf000,
-       0x8b04a5f0,
-       0x98503000,
+       0x2cf004bd,
+       0x0320b601,
+       0x024afc80,
+       0xbd0002f6,
+       0x01acf004,
+       0x8b02a5f0,
+       0x98500000,
        0xc4b6040c,
        0x00bcbb0f,
-       0x98020c98,
-       0x0f98030d,
-       0x02004e08,
+       0x98000c98,
+       0x000e010d,
        0x00013d7e,
-       0x00020a7e,
-       0xf40601f4,
-/* 0x05b2: ctx_xfer_post */
-       0x277e0712,
-/* 0x05b6: ctx_xfer_done */
-       0xde7e0002,
-       0x00f80004,
-       0x00000000,
+       0x8b01acf0,
+       0x98504000,
+       0xc4b6040c,
+       0x00bcbb0f,
+       0x98010c98,
+       0x0f98020d,
+       0x08004e06,
+       0x00013d7e,
+       0xf001acf0,
+       0x008b04a5,
+       0x0c985030,
+       0x0fc4b604,
+       0x9800bcbb,
+       0x0d98020c,
+       0x080f9803,
+       0x7e02004e,
+       0x7e00013d,
+       0xf400020a,
+       0x12f40601,
+/* 0x05b5: ctx_xfer_post */
+       0x02277e07,
+/* 0x05b9: ctx_xfer_done */
+       0x04e17e00,
+       0x0000f800,
        0x00000000,
        0x00000000,
        0x00000000,
index 51f5c3c6e96607914f5f7ffcc0973f7f4e347bcc..11bf363a6ae95842634853ca9b4418c00a6c660b 100644 (file)
@@ -289,7 +289,7 @@ uint32_t gm107_grgpc_code[] = {
        0x020014fe,
        0x12004002,
        0xbd0002f6,
-       0x05b04104,
+       0x05b34104,
        0x400010fe,
        0x00f60700,
        0x0204bd00,
@@ -308,259 +308,259 @@ uint32_t gm107_grgpc_code[] = {
        0xc900800f,
        0x0002f601,
        0x308e04bd,
-       0x24bd500c,
-       0x44bd34bd,
-/* 0x03b0: init_unk_loop */
-       0x0000657e,
-       0xf400f6b0,
-       0x010f0e0b,
-       0xfd04f2bb,
-       0x30b6054f,
-/* 0x03c5: init_unk_next */
-       0x0120b601,
-       0xb004e0b6,
-       0x1bf40226,
-/* 0x03d1: init_unk_done */
-       0x0703b5e2,
-       0x820804b5,
-       0xcf020100,
-       0x34bd0022,
-       0x80082595,
-       0xf601c000,
+       0xe5f0500c,
+       0xbd24bd01,
+/* 0x03b3: init_unk_loop */
+       0x7e44bd34,
+       0xb0000065,
+       0x0bf400f6,
+       0xbb010f0e,
+       0x4ffd04f2,
+       0x0130b605,
+/* 0x03c8: init_unk_next */
+       0xb60120b6,
+       0x26b004e0,
+       0xe21bf402,
+/* 0x03d4: init_unk_done */
+       0xb50703b5,
+       0x00820804,
+       0x22cf0201,
+       0x9534bd00,
+       0x00800825,
+       0x05f601c0,
+       0x8004bd00,
+       0xf601c100,
        0x04bd0005,
-       0x01c10080,
-       0xbd0005f6,
-       0x000e9804,
-       0x7e010f98,
-       0xbb000120,
-       0x3fbb002f,
-       0x010e9800,
-       0x7e020f98,
-       0x98000120,
-       0xeffd050e,
-       0x002ebb00,
-       0x98003ebb,
-       0x0f98020e,
-       0x01207e03,
-       0x070e9800,
-       0xbb00effd,
-       0x3ebb002e,
-       0x0235b600,
-       0x01d30080,
-       0xbd0003f6,
-       0x0825b604,
-       0xb60635b6,
-       0x30b60120,
-       0x0824b601,
-       0xb20834b6,
-       0x02687e2f,
-       0x002fbb00,
-       0x0f003fbb,
-       0x8effb23f,
-       0xf0501d60,
-       0x8f7e01e5,
-       0x0c0f0000,
-       0xa88effb2,
-       0xe5f0501d,
-       0x008f7e01,
-       0x03147e00,
-       0xb23f0f00,
-       0x1d608eff,
-       0x01e5f050,
-       0x00008f7e,
-       0xffb2000f,
-       0x501d9c8e,
-       0x7e01e5f0,
-       0x0f00008f,
-       0x03147e01,
-       0x8effb200,
+       0x98000e98,
+       0x207e010f,
+       0x2fbb0001,
+       0x003fbb00,
+       0x98010e98,
+       0x207e020f,
+       0x0e980001,
+       0x00effd05,
+       0xbb002ebb,
+       0x0e98003e,
+       0x030f9802,
+       0x0001207e,
+       0xfd070e98,
+       0x2ebb00ef,
+       0x003ebb00,
+       0x800235b6,
+       0xf601d300,
+       0x04bd0003,
+       0xb60825b6,
+       0x20b60635,
+       0x0130b601,
+       0xb60824b6,
+       0x2fb20834,
+       0x0002687e,
+       0xbb002fbb,
+       0x3f0f003f,
+       0x501d608e,
+       0xb201e5f0,
+       0x008f7eff,
+       0x8e0c0f00,
        0xf0501da8,
-       0x8f7e01e5,
-       0xff0f0000,
-       0x988effb2,
+       0xffb201e5,
+       0x00008f7e,
+       0x0003147e,
+       0x608e3f0f,
        0xe5f0501d,
-       0x008f7e01,
-       0xb2020f00,
-       0x1da88eff,
+       0x7effb201,
+       0x0f00008f,
+       0x1d9c8e00,
        0x01e5f050,
-       0x00008f7e,
+       0x8f7effb2,
+       0x010f0000,
        0x0003147e,
-       0x85050498,
-       0x98504000,
-       0x64b60406,
-       0x0056bb0f,
-/* 0x04e0: tpc_strand_init_tpc_loop */
-       0x05705eb8,
-       0x00657e00,
-       0xbdf6b200,
-/* 0x04ed: tpc_strand_init_idx_loop */
-       0x605eb874,
-       0x7fb20005,
-       0x00008f7e,
-       0x05885eb8,
-       0x082f9500,
-       0x00008f7e,
-       0x058c5eb8,
-       0x082f9500,
+       0x501da88e,
+       0xb201e5f0,
+       0x008f7eff,
+       0x8eff0f00,
+       0xf0501d98,
+       0xffb201e5,
        0x00008f7e,
-       0x05905eb8,
-       0x00657e00,
-       0x06f5b600,
-       0xb601f0b6,
-       0x2fbb08f4,
-       0x003fbb00,
-       0xb60170b6,
-       0x1bf40162,
-       0x0050b7bf,
-       0x0142b608,
-       0x0fa81bf4,
-       0x8effb23f,
-       0xf0501d60,
-       0x8f7e01e5,
-       0x0d0f0000,
-       0xa88effb2,
+       0xa88e020f,
        0xe5f0501d,
-       0x008f7e01,
-       0x03147e00,
-       0x01008000,
-       0x0003f602,
-       0x24bd04bd,
-       0x801f29f0,
-       0xf6023000,
-       0x04bd0002,
-/* 0x0574: main */
-       0xf40031f4,
-       0x240d0028,
-       0x0000377e,
-       0xb0f401f4,
-       0x18f404e4,
-       0x0181fe1d,
-       0x20bd0602,
-       0xb60412fd,
-       0x1efd01e4,
-       0x0018fe05,
-       0x0006477e,
-/* 0x05a3: main_not_ctx_xfer */
-       0x94d40ef4,
-       0xf5f010ef,
-       0x02f87e01,
-       0xc70ef400,
-/* 0x05b0: ih */
-       0x88fe80f9,
-       0xf980f901,
-       0xf9a0f990,
-       0xf9d0f9b0,
-       0xbdf0f9e0,
-       0x02004a04,
-       0xc400aacf,
-       0x0bf404ab,
-       0x4e240d1f,
-       0xeecf1a00,
-       0x19004f00,
-       0x7e00ffcf,
-       0x0e000004,
-       0x1d004001,
-       0xbd000ef6,
-/* 0x05ed: ih_no_fifo */
-       0x01004004,
-       0xbd000af6,
-       0xfcf0fc04,
-       0xfcd0fce0,
-       0xfca0fcb0,
-       0xfe80fc90,
-       0x80fc0088,
-       0xf80032f4,
-/* 0x060d: hub_barrier_done */
-       0x98010f01,
-       0xfebb040e,
-       0x8effb204,
-       0x7e409418,
-       0xf800008f,
-/* 0x0621: ctx_redswitch */
-       0x80200f00,
+       0x7effb201,
+       0x7e00008f,
+       0x98000314,
+       0x00850504,
+       0x06985040,
+       0x0f64b604,
+/* 0x04e3: tpc_strand_init_tpc_loop */
+       0xb80056bb,
+       0x0005705e,
+       0x0000657e,
+       0x74bdf6b2,
+/* 0x04f0: tpc_strand_init_idx_loop */
+       0x05605eb8,
+       0x7e7fb200,
+       0xb800008f,
+       0x0005885e,
+       0x7e082f95,
+       0xb800008f,
+       0x00058c5e,
+       0x7e082f95,
+       0xb800008f,
+       0x0005905e,
+       0x0000657e,
+       0xb606f5b6,
+       0xf4b601f0,
+       0x002fbb08,
+       0xb6003fbb,
+       0x62b60170,
+       0xbf1bf401,
+       0x080050b7,
+       0xf40142b6,
+       0x3f0fa81b,
+       0x501d608e,
+       0xb201e5f0,
+       0x008f7eff,
+       0x8e0d0f00,
+       0xf0501da8,
+       0xffb201e5,
+       0x00008f7e,
+       0x0003147e,
+       0x02010080,
+       0xbd0003f6,
+       0xf024bd04,
+       0x00801f29,
+       0x02f60230,
+/* 0x0577: main */
+       0xf404bd00,
+       0x28f40031,
+       0x7e240d00,
+       0xf4000037,
+       0xe4b0f401,
+       0x1d18f404,
+       0x020181fe,
+       0xfd20bd06,
+       0xe4b60412,
+       0x051efd01,
+       0x7e0018fe,
+       0xf400064a,
+/* 0x05a6: main_not_ctx_xfer */
+       0xef94d40e,
+       0x01f5f010,
+       0x0002f87e,
+/* 0x05b3: ih */
+       0xf9c70ef4,
+       0x0188fe80,
+       0x90f980f9,
+       0xb0f9a0f9,
+       0xe0f9d0f9,
+       0x04bdf0f9,
+       0xcf02004a,
+       0xabc400aa,
+       0x1f0bf404,
+       0x004e240d,
+       0x00eecf1a,
+       0xcf19004f,
+       0x047e00ff,
+       0x010e0000,
+       0xf61d0040,
+       0x04bd000e,
+/* 0x05f0: ih_no_fifo */
+       0xf6010040,
+       0x04bd000a,
+       0xe0fcf0fc,
+       0xb0fcd0fc,
+       0x90fca0fc,
+       0x88fe80fc,
+       0xf480fc00,
+       0x01f80032,
+/* 0x0610: hub_barrier_done */
+       0x0e98010f,
+       0x04febb04,
+       0x188effb2,
+       0x8f7e4094,
+       0x00f80000,
+/* 0x0624: ctx_redswitch */
+       0x0080200f,
+       0x0ff60185,
+       0x0e04bd00,
+/* 0x0631: ctx_redswitch_delay */
+       0x01e2b608,
+       0xf1fd1bf4,
+       0xf10800f5,
+       0x800200f5,
        0xf6018500,
        0x04bd000f,
-/* 0x062e: ctx_redswitch_delay */
-       0xe2b6080e,
-       0xfd1bf401,
-       0x0800f5f1,
-       0x0200f5f1,
-       0x01850080,
-       0xbd000ff6,
-/* 0x0647: ctx_xfer */
-       0x8000f804,
-       0xf6028100,
-       0x04bd000f,
-       0xc48effb2,
-       0xe5f0501d,
-       0x008f7e01,
-       0x0711f400,
-       0x0006217e,
-/* 0x0664: ctx_xfer_not_load */
-       0x0002167e,
-       0xfc8024bd,
-       0x02f60247,
-       0xf004bd00,
-       0x20b6012c,
-       0x4afc8003,
+/* 0x064a: ctx_xfer */
+       0x008000f8,
+       0x0ff60281,
+       0x8e04bd00,
+       0xf0501dc4,
+       0xffb201e5,
+       0x00008f7e,
+       0x7e0711f4,
+/* 0x0667: ctx_xfer_not_load */
+       0x7e000624,
+       0xbd000216,
+       0x47fc8024,
        0x0002f602,
-       0x0c0f04bd,
-       0xa88effb2,
-       0xe5f0501d,
-       0x008f7e01,
-       0x03147e00,
-       0xb23f0f00,
-       0x1d608eff,
-       0x01e5f050,
+       0x2cf004bd,
+       0x0320b601,
+       0x024afc80,
+       0xbd0002f6,
+       0x8e0c0f04,
+       0xf0501da8,
+       0xffb201e5,
        0x00008f7e,
-       0xffb2000f,
-       0x501d9c8e,
-       0x7e01e5f0,
+       0x0003147e,
+       0x608e3f0f,
+       0xe5f0501d,
+       0x7effb201,
        0x0f00008f,
-       0x03147e01,
-       0x01fcf000,
-       0xb203f0b6,
-       0x1da88eff,
+       0x1d9c8e00,
        0x01e5f050,
-       0x00008f7e,
-       0xf001acf0,
-       0x008b02a5,
-       0x0c985000,
-       0x0fc4b604,
-       0x9800bcbb,
-       0x0d98000c,
-       0x7e000e01,
-       0xf000013d,
-       0x008b01ac,
-       0x0c985040,
-       0x0fc4b604,
-       0x9800bcbb,
-       0x0d98010c,
-       0x060f9802,
-       0x7e08004e,
-       0xf000013d,
+       0x8f7effb2,
+       0x010f0000,
+       0x0003147e,
+       0xb601fcf0,
+       0xa88e03f0,
+       0xe5f0501d,
+       0x7effb201,
+       0xf000008f,
        0xa5f001ac,
-       0x30008b04,
+       0x00008b02,
        0x040c9850,
        0xbb0fc4b6,
        0x0c9800bc,
-       0x030d9802,
-       0x4e080f98,
-       0x3d7e0200,
-       0x0a7e0001,
-       0x147e0002,
-       0x01f40003,
-       0x1a12f406,
-/* 0x073c: ctx_xfer_post */
-       0x0002277e,
-       0xffb20d0f,
-       0x501da88e,
-       0x7e01e5f0,
-       0x7e00008f,
-/* 0x0753: ctx_xfer_done */
-       0x7e000314,
-       0xf800060d,
-       0x00000000,
+       0x010d9800,
+       0x3d7e000e,
+       0xacf00001,
+       0x40008b01,
+       0x040c9850,
+       0xbb0fc4b6,
+       0x0c9800bc,
+       0x020d9801,
+       0x4e060f98,
+       0x3d7e0800,
+       0xacf00001,
+       0x04a5f001,
+       0x5030008b,
+       0xb6040c98,
+       0xbcbb0fc4,
+       0x020c9800,
+       0x98030d98,
+       0x004e080f,
+       0x013d7e02,
+       0x020a7e00,
+       0x03147e00,
+       0x0601f400,
+/* 0x073f: ctx_xfer_post */
+       0x7e1a12f4,
+       0x0f000227,
+       0x1da88e0d,
+       0x01e5f050,
+       0x8f7effb2,
+       0x147e0000,
+/* 0x0756: ctx_xfer_done */
+       0x107e0003,
+       0x00f80006,
        0x00000000,
        0x00000000,
        0x00000000,
index dda7a7d224c9b9d22a5894e4930bc712644e157a..9f5dfc85147a50df62f30fdb84453c18a622380e 100644 (file)
@@ -143,7 +143,7 @@ gf100_gr_zbc_depth_get(struct gf100_gr *gr, int format,
 static int
 gf100_fermi_mthd_zbc_color(struct nvkm_object *object, void *data, u32 size)
 {
-       struct gf100_gr *gr = (void *)object->engine;
+       struct gf100_gr *gr = gf100_gr(nvkm_gr(object->engine));
        union {
                struct fermi_a_zbc_color_v0 v0;
        } *args = data;
@@ -189,7 +189,7 @@ gf100_fermi_mthd_zbc_color(struct nvkm_object *object, void *data, u32 size)
 static int
 gf100_fermi_mthd_zbc_depth(struct nvkm_object *object, void *data, u32 size)
 {
-       struct gf100_gr *gr = (void *)object->engine;
+       struct gf100_gr *gr = gf100_gr(nvkm_gr(object->engine));
        union {
                struct fermi_a_zbc_depth_v0 v0;
        } *args = data;
@@ -1530,6 +1530,8 @@ gf100_gr_oneinit(struct nvkm_gr *base)
                gr->ppc_nr[i]  = gr->func->ppc_nr;
                for (j = 0; j < gr->ppc_nr[i]; j++) {
                        u8 mask = nvkm_rd32(device, GPC_UNIT(i, 0x0c30 + (j * 4)));
+                       if (mask)
+                               gr->ppc_mask[i] |= (1 << j);
                        gr->ppc_tpc_nr[i][j] = hweight8(mask);
                }
        }
index 4611961b118743c304f6b40f545ffeb27ef0cb91..02e78b8d93f6743b67baee2a6c68757277ccf489 100644 (file)
@@ -97,6 +97,7 @@ struct gf100_gr {
        u8 tpc_nr[GPC_MAX];
        u8 tpc_total;
        u8 ppc_nr[GPC_MAX];
+       u8 ppc_mask[GPC_MAX];
        u8 ppc_tpc_nr[GPC_MAX][4];
 
        struct nvkm_memory *unk4188b4;
index 43006db6fd58252830842c02543ca1659ae23df2..80fed7e78dcbe0bc1e7df6a864c3efb475c2733a 100644 (file)
@@ -83,6 +83,7 @@ nvbios_fan_parse(struct nvkm_bios *bios, struct nvbios_therm_fan *fan)
                        fan->type = NVBIOS_THERM_FAN_UNK;
                }
 
+               fan->fan_mode = NVBIOS_THERM_FAN_LINEAR;
                fan->min_duty = nvbios_rd08(bios, data + 0x02);
                fan->max_duty = nvbios_rd08(bios, data + 0x03);
 
index 895ba74057d4aab45fb44ddfc707243b3252fbdb..1d7dd38292b375bd73ec35ff4e844cd2ae1defe7 100644 (file)
@@ -97,7 +97,9 @@ static void *
 nvkm_instobj_dtor(struct nvkm_memory *memory)
 {
        struct nvkm_instobj *iobj = nvkm_instobj(memory);
+       spin_lock(&iobj->imem->lock);
        list_del(&iobj->head);
+       spin_unlock(&iobj->imem->lock);
        nvkm_memory_del(&iobj->parent);
        return iobj;
 }
@@ -190,7 +192,9 @@ nvkm_instobj_new(struct nvkm_instmem *imem, u32 size, u32 align, bool zero,
                nvkm_memory_ctor(&nvkm_instobj_func_slow, &iobj->memory);
                iobj->parent = memory;
                iobj->imem = imem;
+               spin_lock(&iobj->imem->lock);
                list_add_tail(&iobj->head, &imem->list);
+               spin_unlock(&iobj->imem->lock);
                memory = &iobj->memory;
        }
 
@@ -309,5 +313,6 @@ nvkm_instmem_ctor(const struct nvkm_instmem_func *func,
 {
        nvkm_subdev_ctor(&nvkm_instmem, device, index, 0, &imem->subdev);
        imem->func = func;
+       spin_lock_init(&imem->lock);
        INIT_LIST_HEAD(&imem->list);
 }
index d942fa7b9f1871b362809baf0bac9c8c7d6ced2b..86f9f3b13f71f7caead9206f9cfcdab6bf88c728 100644 (file)
@@ -81,9 +81,7 @@ gk104_pmu_pgob(struct nvkm_pmu *pmu, bool enable)
        nvkm_mask(device, 0x000200, 0x00001000, 0x00001000);
        nvkm_rd32(device, 0x000200);
 
-       if ( nvkm_boolopt(device->cfgopt, "War00C800_0",
-           device->quirk ? device->quirk->War00C800_0 : false)) {
-               nvkm_info(&pmu->subdev, "hw bug workaround enabled\n");
+       if (nvkm_boolopt(device->cfgopt, "War00C800_0", true)) {
                switch (device->chipset) {
                case 0xe4:
                        magic(device, 0x04000000);
index b61509e26ec9f5d5192540c624e5c4ebdc96e087..b735173a18ff3d055dcfafcae2cd17c58b6a6c4a 100644 (file)
@@ -59,7 +59,7 @@ gk104_volt_set(struct nvkm_volt *base, u32 uv)
        duty = (uv - bios->base) * div / bios->pwm_range;
 
        nvkm_wr32(device, 0x20340, div);
-       nvkm_wr32(device, 0x20344, 0x8000000 | duty);
+       nvkm_wr32(device, 0x20344, 0x80000000 | duty);
 
        return 0;
 }
index b8e4cdec28c363c7e5c10881be4ea61461023ace..24f92bea39c7d731365be1464b5b551f3a278f49 100644 (file)
@@ -112,11 +112,8 @@ static int omap_fbdev_create(struct drm_fb_helper *helper,
        dma_addr_t paddr;
        int ret;
 
-       /* only doing ARGB32 since this is what is needed to alpha-blend
-        * with video overlays:
-        */
        sizes->surface_bpp = 32;
-       sizes->surface_depth = 32;
+       sizes->surface_depth = 24;
 
        DBG("create fbdev: %dx%d@%d (%dx%d)", sizes->surface_width,
                        sizes->surface_height, sizes->surface_bpp,
index 248953d2fdb742d69111193f62638c0a95f179d5..f81fb26410976840b02811de9693b875edfa3efa 100644 (file)
@@ -4173,11 +4173,7 @@ void cik_ring_ib_execute(struct radeon_device *rdev, struct radeon_ib *ib)
        control |= ib->length_dw | (vm_id << 24);
 
        radeon_ring_write(ring, header);
-       radeon_ring_write(ring,
-#ifdef __BIG_ENDIAN
-                         (2 << 0) |
-#endif
-                         (ib->gpu_addr & 0xFFFFFFFC));
+       radeon_ring_write(ring, (ib->gpu_addr & 0xFFFFFFFC));
        radeon_ring_write(ring, upper_32_bits(ib->gpu_addr) & 0xFFFF);
        radeon_ring_write(ring, control);
 }
@@ -8472,7 +8468,7 @@ restart_ih:
        if (queue_dp)
                schedule_work(&rdev->dp_work);
        if (queue_hotplug)
-               schedule_work(&rdev->hotplug_work);
+               schedule_delayed_work(&rdev->hotplug_work, 0);
        if (queue_reset) {
                rdev->needs_reset = true;
                wake_up_all(&rdev->fence_queue);
@@ -9630,6 +9626,9 @@ static void dce8_program_watermarks(struct radeon_device *rdev,
                    (rdev->disp_priority == 2)) {
                        DRM_DEBUG_KMS("force priority to high\n");
                }
+
+               /* Save number of lines the linebuffer leads before the scanout */
+               radeon_crtc->lb_vblank_lead_lines = DIV_ROUND_UP(lb_size, mode->crtc_hdisplay);
        }
 
        /* select wm A */
index 7f33767d7ed65f4a966cb2b3e01b250846cca340..2ad462896896b017402688352428082b6925df7b 100644 (file)
@@ -2372,6 +2372,9 @@ static void evergreen_program_watermarks(struct radeon_device *rdev,
                c.full = dfixed_div(c, a);
                priority_b_mark = dfixed_trunc(c);
                priority_b_cnt |= priority_b_mark & PRIORITY_MARK_MASK;
+
+               /* Save number of lines the linebuffer leads before the scanout */
+               radeon_crtc->lb_vblank_lead_lines = DIV_ROUND_UP(lb_size, mode->crtc_hdisplay);
        }
 
        /* select wm A */
@@ -5344,7 +5347,7 @@ restart_ih:
        if (queue_dp)
                schedule_work(&rdev->dp_work);
        if (queue_hotplug)
-               schedule_work(&rdev->hotplug_work);
+               schedule_delayed_work(&rdev->hotplug_work, 0);
        if (queue_hdmi)
                schedule_work(&rdev->audio_work);
        if (queue_thermal && rdev->pm.dpm_enabled)
index 238b13f045c180480ef4f49983bbc19b76016729..9e7e2bf03b815647451622d69c6cbce2d03582de 100644 (file)
@@ -806,7 +806,7 @@ int r100_irq_process(struct radeon_device *rdev)
                status = r100_irq_ack(rdev);
        }
        if (queue_hotplug)
-               schedule_work(&rdev->hotplug_work);
+               schedule_delayed_work(&rdev->hotplug_work, 0);
        if (rdev->msi_enabled) {
                switch (rdev->family) {
                case CHIP_RS400:
@@ -3217,6 +3217,9 @@ void r100_bandwidth_update(struct radeon_device *rdev)
        uint32_t pixel_bytes1 = 0;
        uint32_t pixel_bytes2 = 0;
 
+       /* Guess line buffer size to be 8192 pixels */
+       u32 lb_size = 8192;
+
        if (!rdev->mode_info.mode_config_initialized)
                return;
 
@@ -3631,6 +3634,13 @@ void r100_bandwidth_update(struct radeon_device *rdev)
                DRM_DEBUG_KMS("GRPH2_BUFFER_CNTL from to %x\n",
                          (unsigned int)RREG32(RADEON_GRPH2_BUFFER_CNTL));
        }
+
+       /* Save number of lines the linebuffer leads before the scanout */
+       if (mode1)
+           rdev->mode_info.crtcs[0]->lb_vblank_lead_lines = DIV_ROUND_UP(lb_size, mode1->crtc_hdisplay);
+
+       if (mode2)
+           rdev->mode_info.crtcs[1]->lb_vblank_lead_lines = DIV_ROUND_UP(lb_size, mode2->crtc_hdisplay);
 }
 
 int r100_ring_test(struct radeon_device *rdev, struct radeon_ring *ring)
index 4ea5b10ff5f412fb0fc2b161c8fe936ab154bd2f..cc2fdf0be37a600e313d239e07520331229a0035 100644 (file)
@@ -4276,7 +4276,7 @@ restart_ih:
                WREG32(IH_RB_RPTR, rptr);
        }
        if (queue_hotplug)
-               schedule_work(&rdev->hotplug_work);
+               schedule_delayed_work(&rdev->hotplug_work, 0);
        if (queue_hdmi)
                schedule_work(&rdev->audio_work);
        if (queue_thermal && rdev->pm.dpm_enabled)
index b6cbd816537e7e69bc920482961cdb47b6dfd68d..87db64983ea8c18a0305eeedf1e25f18cffc87ae 100644 (file)
@@ -2414,7 +2414,7 @@ struct radeon_device {
        struct r600_ih ih; /* r6/700 interrupt ring */
        struct radeon_rlc rlc;
        struct radeon_mec mec;
-       struct work_struct hotplug_work;
+       struct delayed_work hotplug_work;
        struct work_struct dp_work;
        struct work_struct audio_work;
        int num_crtc; /* number of crtcs */
index fe994aac3b0403357d40e9b29f46e8818be454bf..c77d349c561c6960e79d0b9338d7368302e1d188 100644 (file)
@@ -54,6 +54,9 @@ static struct radeon_agpmode_quirk radeon_agpmode_quirk_list[] = {
        /* Intel 82855PM host bridge / Mobility 9600 M10 RV350 Needs AGPMode 1 (lp #195051) */
        { PCI_VENDOR_ID_INTEL, 0x3340, PCI_VENDOR_ID_ATI, 0x4e50,
                PCI_VENDOR_ID_IBM, 0x0550, 1},
+       /* Intel 82855PM host bridge / RV250/M9 GL [Mobility FireGL 9000/Radeon 9000] needs AGPMode 1 (Thinkpad T40p) */
+       { PCI_VENDOR_ID_INTEL, 0x3340, PCI_VENDOR_ID_ATI, 0x4c66,
+               PCI_VENDOR_ID_IBM, 0x054d, 1},
        /* Intel 82855PM host bridge / Mobility M7 needs AGPMode 1 */
        { PCI_VENDOR_ID_INTEL, 0x3340, PCI_VENDOR_ID_ATI, 0x4c57,
                PCI_VENDOR_ID_IBM, 0x0530, 1},
index 5a2cafb4f1bc595220e603ed1942e65bf24b20b7..340f3f549f295314788fbf9b3052880b8095a7f1 100644 (file)
@@ -1234,13 +1234,32 @@ radeon_dvi_detect(struct drm_connector *connector, bool force)
        if (r < 0)
                return connector_status_disconnected;
 
+       if (radeon_connector->detected_hpd_without_ddc) {
+               force = true;
+               radeon_connector->detected_hpd_without_ddc = false;
+       }
+
        if (!force && radeon_check_hpd_status_unchanged(connector)) {
                ret = connector->status;
                goto exit;
        }
 
-       if (radeon_connector->ddc_bus)
+       if (radeon_connector->ddc_bus) {
                dret = radeon_ddc_probe(radeon_connector, false);
+
+               /* Sometimes the pins required for the DDC probe on DVI
+                * connectors don't make contact at the same time that the ones
+                * for HPD do. If the DDC probe fails even though we had an HPD
+                * signal, try again later */
+               if (!dret && !force &&
+                   connector->status != connector_status_connected) {
+                       DRM_DEBUG_KMS("hpd detected without ddc, retrying in 1 second\n");
+                       radeon_connector->detected_hpd_without_ddc = true;
+                       schedule_delayed_work(&rdev->hotplug_work,
+                                             msecs_to_jiffies(1000));
+                       goto exit;
+               }
+       }
        if (dret) {
                radeon_connector->detected_by_load = false;
                radeon_connector_free_edid(connector);
index a8d9927ed9eb9657d89e34c84481c9c9c9e3513f..1eca0acac016f314cd6960b9dda3067bcc04e83c 100644 (file)
@@ -322,7 +322,9 @@ void radeon_crtc_handle_vblank(struct radeon_device *rdev, int crtc_id)
         * to complete in this vblank?
         */
        if (update_pending &&
-           (DRM_SCANOUTPOS_VALID & radeon_get_crtc_scanoutpos(rdev->ddev, crtc_id, 0,
+           (DRM_SCANOUTPOS_VALID & radeon_get_crtc_scanoutpos(rdev->ddev,
+                                                              crtc_id,
+                                                              USE_REAL_VBLANKSTART,
                                                               &vpos, &hpos, NULL, NULL,
                                                               &rdev->mode_info.crtcs[crtc_id]->base.hwmode)) &&
            ((vpos >= (99 * rdev->mode_info.crtcs[crtc_id]->base.hwmode.crtc_vdisplay)/100) ||
@@ -401,6 +403,8 @@ static void radeon_flip_work_func(struct work_struct *__work)
        struct drm_crtc *crtc = &radeon_crtc->base;
        unsigned long flags;
        int r;
+       int vpos, hpos, stat, min_udelay;
+       struct drm_vblank_crtc *vblank = &crtc->dev->vblank[work->crtc_id];
 
         down_read(&rdev->exclusive_lock);
        if (work->fence) {
@@ -437,6 +441,41 @@ static void radeon_flip_work_func(struct work_struct *__work)
        /* set the proper interrupt */
        radeon_irq_kms_pflip_irq_get(rdev, radeon_crtc->crtc_id);
 
+       /* If this happens to execute within the "virtually extended" vblank
+        * interval before the start of the real vblank interval then it needs
+        * to delay programming the mmio flip until the real vblank is entered.
+        * This prevents completing a flip too early due to the way we fudge
+        * our vblank counter and vblank timestamps in order to work around the
+        * problem that the hw fires vblank interrupts before actual start of
+        * vblank (when line buffer refilling is done for a frame). It
+        * complements the fudging logic in radeon_get_crtc_scanoutpos() for
+        * timestamping and radeon_get_vblank_counter_kms() for vblank counts.
+        *
+        * In practice this won't execute very often unless on very fast
+        * machines because the time window for this to happen is very small.
+        */
+       for (;;) {
+               /* GET_DISTANCE_TO_VBLANKSTART returns distance to real vblank
+                * start in hpos, and to the "fudged earlier" vblank start in
+                * vpos.
+                */
+               stat = radeon_get_crtc_scanoutpos(rdev->ddev, work->crtc_id,
+                                                 GET_DISTANCE_TO_VBLANKSTART,
+                                                 &vpos, &hpos, NULL, NULL,
+                                                 &crtc->hwmode);
+
+               if ((stat & (DRM_SCANOUTPOS_VALID | DRM_SCANOUTPOS_ACCURATE)) !=
+                   (DRM_SCANOUTPOS_VALID | DRM_SCANOUTPOS_ACCURATE) ||
+                   !(vpos >= 0 && hpos <= 0))
+                       break;
+
+               /* Sleep at least until estimated real start of hw vblank */
+               spin_unlock_irqrestore(&crtc->dev->event_lock, flags);
+               min_udelay = (-hpos + 1) * max(vblank->linedur_ns / 1000, 5);
+               usleep_range(min_udelay, 2 * min_udelay);
+               spin_lock_irqsave(&crtc->dev->event_lock, flags);
+       };
+
        /* do the flip (mmio) */
        radeon_page_flip(rdev, radeon_crtc->crtc_id, work->base);
 
@@ -1768,6 +1807,15 @@ bool radeon_crtc_scaling_mode_fixup(struct drm_crtc *crtc,
  * \param dev Device to query.
  * \param crtc Crtc to query.
  * \param flags Flags from caller (DRM_CALLED_FROM_VBLIRQ or 0).
+ *              For driver internal use only also supports these flags:
+ *
+ *              USE_REAL_VBLANKSTART to use the real start of vblank instead
+ *              of a fudged earlier start of vblank.
+ *
+ *              GET_DISTANCE_TO_VBLANKSTART to return distance to the
+ *              fudged earlier start of vblank in *vpos and the distance
+ *              to true start of vblank in *hpos.
+ *
  * \param *vpos Location where vertical scanout position should be stored.
  * \param *hpos Location where horizontal scanout position should go.
  * \param *stime Target location for timestamp taken immediately before
@@ -1911,10 +1959,40 @@ int radeon_get_crtc_scanoutpos(struct drm_device *dev, unsigned int pipe,
                vbl_end = 0;
        }
 
+       /* Called from driver internal vblank counter query code? */
+       if (flags & GET_DISTANCE_TO_VBLANKSTART) {
+           /* Caller wants distance from real vbl_start in *hpos */
+           *hpos = *vpos - vbl_start;
+       }
+
+       /* Fudge vblank to start a few scanlines earlier to handle the
+        * problem that vblank irqs fire a few scanlines before start
+        * of vblank. Some driver internal callers need the true vblank
+        * start to be used and signal this via the USE_REAL_VBLANKSTART flag.
+        *
+        * The cause of the "early" vblank irq is that the irq is triggered
+        * by the line buffer logic when the line buffer read position enters
+        * the vblank, whereas our crtc scanout position naturally lags the
+        * line buffer read position.
+        */
+       if (!(flags & USE_REAL_VBLANKSTART))
+               vbl_start -= rdev->mode_info.crtcs[pipe]->lb_vblank_lead_lines;
+
        /* Test scanout position against vblank region. */
        if ((*vpos < vbl_start) && (*vpos >= vbl_end))
                in_vbl = false;
 
+       /* In vblank? */
+       if (in_vbl)
+           ret |= DRM_SCANOUTPOS_IN_VBLANK;
+
+       /* Called from driver internal vblank counter query code? */
+       if (flags & GET_DISTANCE_TO_VBLANKSTART) {
+               /* Caller wants distance from fudged earlier vbl_start */
+               *vpos -= vbl_start;
+               return ret;
+       }
+
        /* Check if inside vblank area and apply corrective offsets:
         * vpos will then be >=0 in video scanout area, but negative
         * within vblank area, counting down the number of lines until
@@ -1930,31 +2008,5 @@ int radeon_get_crtc_scanoutpos(struct drm_device *dev, unsigned int pipe,
        /* Correct for shifted end of vbl at vbl_end. */
        *vpos = *vpos - vbl_end;
 
-       /* In vblank? */
-       if (in_vbl)
-               ret |= DRM_SCANOUTPOS_IN_VBLANK;
-
-       /* Is vpos outside nominal vblank area, but less than
-        * 1/100 of a frame height away from start of vblank?
-        * If so, assume this isn't a massively delayed vblank
-        * interrupt, but a vblank interrupt that fired a few
-        * microseconds before true start of vblank. Compensate
-        * by adding a full frame duration to the final timestamp.
-        * Happens, e.g., on ATI R500, R600.
-        *
-        * We only do this if DRM_CALLED_FROM_VBLIRQ.
-        */
-       if ((flags & DRM_CALLED_FROM_VBLIRQ) && !in_vbl) {
-               vbl_start = mode->crtc_vdisplay;
-               vtotal = mode->crtc_vtotal;
-
-               if (vbl_start - *vpos < vtotal / 100) {
-                       *vpos -= vtotal;
-
-                       /* Signal this correction as "applied". */
-                       ret |= 0x8;
-               }
-       }
-
        return ret;
 }
index 171d3e43c30cc02257df75645c6c77f0a726de33..979f3bf65f2c474f231a26eb47af963d4436be0f 100644 (file)
@@ -74,7 +74,7 @@ irqreturn_t radeon_driver_irq_handler_kms(int irq, void *arg)
 static void radeon_hotplug_work_func(struct work_struct *work)
 {
        struct radeon_device *rdev = container_of(work, struct radeon_device,
-                                                 hotplug_work);
+                                                 hotplug_work.work);
        struct drm_device *dev = rdev->ddev;
        struct drm_mode_config *mode_config = &dev->mode_config;
        struct drm_connector *connector;
@@ -302,7 +302,7 @@ int radeon_irq_kms_init(struct radeon_device *rdev)
                }
        }
 
-       INIT_WORK(&rdev->hotplug_work, radeon_hotplug_work_func);
+       INIT_DELAYED_WORK(&rdev->hotplug_work, radeon_hotplug_work_func);
        INIT_WORK(&rdev->dp_work, radeon_dp_work_func);
        INIT_WORK(&rdev->audio_work, r600_audio_update_hdmi);
 
@@ -310,7 +310,7 @@ int radeon_irq_kms_init(struct radeon_device *rdev)
        r = drm_irq_install(rdev->ddev, rdev->ddev->pdev->irq);
        if (r) {
                rdev->irq.installed = false;
-               flush_work(&rdev->hotplug_work);
+               flush_delayed_work(&rdev->hotplug_work);
                return r;
        }
 
@@ -333,7 +333,7 @@ void radeon_irq_kms_fini(struct radeon_device *rdev)
                rdev->irq.installed = false;
                if (rdev->msi_enabled)
                        pci_disable_msi(rdev->pdev);
-               flush_work(&rdev->hotplug_work);
+               flush_delayed_work(&rdev->hotplug_work);
        }
 }
 
index 0ec6fcca16d3b12b898d8c9c036ab330cdc47226..d290a8a09036e9d28aa78332f7f2d22ee46ec0e2 100644 (file)
@@ -755,6 +755,8 @@ void radeon_driver_preclose_kms(struct drm_device *dev,
  */
 u32 radeon_get_vblank_counter_kms(struct drm_device *dev, int crtc)
 {
+       int vpos, hpos, stat;
+       u32 count;
        struct radeon_device *rdev = dev->dev_private;
 
        if (crtc < 0 || crtc >= rdev->num_crtc) {
@@ -762,7 +764,53 @@ u32 radeon_get_vblank_counter_kms(struct drm_device *dev, int crtc)
                return -EINVAL;
        }
 
-       return radeon_get_vblank_counter(rdev, crtc);
+       /* The hw increments its frame counter at start of vsync, not at start
+        * of vblank, as is required by DRM core vblank counter handling.
+        * Cook the hw count here to make it appear to the caller as if it
+        * incremented at start of vblank. We measure distance to start of
+        * vblank in vpos. vpos therefore will be >= 0 between start of vblank
+        * and start of vsync, so vpos >= 0 means to bump the hw frame counter
+        * result by 1 to give the proper appearance to caller.
+        */
+       if (rdev->mode_info.crtcs[crtc]) {
+               /* Repeat readout if needed to provide stable result if
+                * we cross start of vsync during the queries.
+                */
+               do {
+                       count = radeon_get_vblank_counter(rdev, crtc);
+                       /* Ask radeon_get_crtc_scanoutpos to return vpos as
+                        * distance to start of vblank, instead of regular
+                        * vertical scanout pos.
+                        */
+                       stat = radeon_get_crtc_scanoutpos(
+                               dev, crtc, GET_DISTANCE_TO_VBLANKSTART,
+                               &vpos, &hpos, NULL, NULL,
+                               &rdev->mode_info.crtcs[crtc]->base.hwmode);
+               } while (count != radeon_get_vblank_counter(rdev, crtc));
+
+               if (((stat & (DRM_SCANOUTPOS_VALID | DRM_SCANOUTPOS_ACCURATE)) !=
+                   (DRM_SCANOUTPOS_VALID | DRM_SCANOUTPOS_ACCURATE))) {
+                       DRM_DEBUG_VBL("Query failed! stat %d\n", stat);
+               }
+               else {
+                       DRM_DEBUG_VBL("crtc %d: dist from vblank start %d\n",
+                                     crtc, vpos);
+
+                       /* Bump counter if we are at >= leading edge of vblank,
+                        * but before vsync where vpos would turn negative and
+                        * the hw counter really increments.
+                        */
+                       if (vpos >= 0)
+                               count++;
+               }
+       }
+       else {
+           /* Fallback to use value as is. */
+           count = radeon_get_vblank_counter(rdev, crtc);
+           DRM_DEBUG_VBL("NULL mode info! Returned count may be wrong.\n");
+       }
+
+       return count;
 }
 
 /**
index 830e171c3a9e35c108f69acd2d4d45386033cd8b..bba112628b478476b0685dc8416ef4badc170d46 100644 (file)
@@ -367,6 +367,7 @@ struct radeon_crtc {
        u32 line_time;
        u32 wm_low;
        u32 wm_high;
+       u32 lb_vblank_lead_lines;
        struct drm_display_mode hw_mode;
        enum radeon_output_csc output_csc;
 };
@@ -553,6 +554,7 @@ struct radeon_connector {
        void *con_priv;
        bool dac_load_detect;
        bool detected_by_load; /* if the connection status was determined by load */
+       bool detected_hpd_without_ddc; /* if an HPD signal was detected on DVI, but ddc probing failed */
        uint16_t connector_object_id;
        struct radeon_hpd hpd;
        struct radeon_router router;
@@ -686,6 +688,9 @@ struct atom_voltage_table
        struct atom_voltage_table_entry entries[MAX_VOLTAGE_ENTRIES];
 };
 
+/* Driver internal use only flags of radeon_get_crtc_scanoutpos() */
+#define USE_REAL_VBLANKSTART           (1 << 30)
+#define GET_DISTANCE_TO_VBLANKSTART    (1 << 31)
 
 extern void
 radeon_add_atom_connector(struct drm_device *dev,
index d3024883b8449db854dbb93d0393ef1728ff0748..84d45633d28c9b1c58f58dc6ec6383eba2207230 100644 (file)
@@ -221,11 +221,17 @@ int radeon_bo_create(struct radeon_device *rdev,
        if (!(rdev->flags & RADEON_IS_PCIE))
                bo->flags &= ~(RADEON_GEM_GTT_WC | RADEON_GEM_GTT_UC);
 
+       /* Write-combined CPU mappings of GTT cause GPU hangs with RV6xx
+        * See https://bugs.freedesktop.org/show_bug.cgi?id=91268
+        */
+       if (rdev->family >= CHIP_RV610 && rdev->family <= CHIP_RV635)
+               bo->flags &= ~(RADEON_GEM_GTT_WC | RADEON_GEM_GTT_UC);
+
 #ifdef CONFIG_X86_32
        /* XXX: Write-combined CPU mappings of GTT seem broken on 32-bit
         * See https://bugs.freedesktop.org/show_bug.cgi?id=84627
         */
-       bo->flags &= ~RADEON_GEM_GTT_WC;
+       bo->flags &= ~(RADEON_GEM_GTT_WC | RADEON_GEM_GTT_UC);
 #elif defined(CONFIG_X86) && !defined(CONFIG_X86_PAT)
        /* Don't try to enable write-combining when it can't work, or things
         * may be slow
@@ -235,9 +241,10 @@ int radeon_bo_create(struct radeon_device *rdev,
 #warning Please enable CONFIG_MTRR and CONFIG_X86_PAT for better performance \
         thanks to write-combining
 
-       DRM_INFO_ONCE("Please enable CONFIG_MTRR and CONFIG_X86_PAT for "
-                     "better performance thanks to write-combining\n");
-       bo->flags &= ~RADEON_GEM_GTT_WC;
+       if (bo->flags & RADEON_GEM_GTT_WC)
+               DRM_INFO_ONCE("Please enable CONFIG_MTRR and CONFIG_X86_PAT for "
+                             "better performance thanks to write-combining\n");
+       bo->flags &= ~(RADEON_GEM_GTT_WC | RADEON_GEM_GTT_UC);
 #endif
 
        radeon_ttm_placement_from_domain(bo, domain);
index 6d80dde23400003dd1362539929c1d402a6500e3..59abebd6b5dc42d4941131adb51b76ab677d3fd4 100644 (file)
@@ -1542,8 +1542,7 @@ int radeon_pm_late_init(struct radeon_device *rdev)
                                ret = device_create_file(rdev->dev, &dev_attr_power_method);
                                if (ret)
                                        DRM_ERROR("failed to create device file for power method\n");
-                               if (!ret)
-                                       rdev->pm.sysfs_initialized = true;
+                               rdev->pm.sysfs_initialized = true;
                        }
 
                        mutex_lock(&rdev->pm.mutex);
@@ -1757,7 +1756,9 @@ static bool radeon_pm_in_vbl(struct radeon_device *rdev)
         */
        for (crtc = 0; (crtc < rdev->num_crtc) && in_vbl; crtc++) {
                if (rdev->pm.active_crtcs & (1 << crtc)) {
-                       vbl_status = radeon_get_crtc_scanoutpos(rdev->ddev, crtc, 0,
+                       vbl_status = radeon_get_crtc_scanoutpos(rdev->ddev,
+                                                               crtc,
+                                                               USE_REAL_VBLANKSTART,
                                                                &vpos, &hpos, NULL, NULL,
                                                                &rdev->mode_info.crtcs[crtc]->base.hwmode);
                        if ((vbl_status & DRM_SCANOUTPOS_VALID) &&
index 574f62bbd215bcf58c125861f7718aaabba7c423..7eb1ae758906142b86f5c7fd1c01dcc50ce74946 100644 (file)
@@ -361,31 +361,31 @@ int radeon_vce_get_create_msg(struct radeon_device *rdev, int ring,
 
        /* stitch together an VCE create msg */
        ib.length_dw = 0;
-       ib.ptr[ib.length_dw++] = 0x0000000c; /* len */
-       ib.ptr[ib.length_dw++] = 0x00000001; /* session cmd */
-       ib.ptr[ib.length_dw++] = handle;
-
-       ib.ptr[ib.length_dw++] = 0x00000030; /* len */
-       ib.ptr[ib.length_dw++] = 0x01000001; /* create cmd */
-       ib.ptr[ib.length_dw++] = 0x00000000;
-       ib.ptr[ib.length_dw++] = 0x00000042;
-       ib.ptr[ib.length_dw++] = 0x0000000a;
-       ib.ptr[ib.length_dw++] = 0x00000001;
-       ib.ptr[ib.length_dw++] = 0x00000080;
-       ib.ptr[ib.length_dw++] = 0x00000060;
-       ib.ptr[ib.length_dw++] = 0x00000100;
-       ib.ptr[ib.length_dw++] = 0x00000100;
-       ib.ptr[ib.length_dw++] = 0x0000000c;
-       ib.ptr[ib.length_dw++] = 0x00000000;
-
-       ib.ptr[ib.length_dw++] = 0x00000014; /* len */
-       ib.ptr[ib.length_dw++] = 0x05000005; /* feedback buffer */
-       ib.ptr[ib.length_dw++] = upper_32_bits(dummy);
-       ib.ptr[ib.length_dw++] = dummy;
-       ib.ptr[ib.length_dw++] = 0x00000001;
+       ib.ptr[ib.length_dw++] = cpu_to_le32(0x0000000c); /* len */
+       ib.ptr[ib.length_dw++] = cpu_to_le32(0x00000001); /* session cmd */
+       ib.ptr[ib.length_dw++] = cpu_to_le32(handle);
+
+       ib.ptr[ib.length_dw++] = cpu_to_le32(0x00000030); /* len */
+       ib.ptr[ib.length_dw++] = cpu_to_le32(0x01000001); /* create cmd */
+       ib.ptr[ib.length_dw++] = cpu_to_le32(0x00000000);
+       ib.ptr[ib.length_dw++] = cpu_to_le32(0x00000042);
+       ib.ptr[ib.length_dw++] = cpu_to_le32(0x0000000a);
+       ib.ptr[ib.length_dw++] = cpu_to_le32(0x00000001);
+       ib.ptr[ib.length_dw++] = cpu_to_le32(0x00000080);
+       ib.ptr[ib.length_dw++] = cpu_to_le32(0x00000060);
+       ib.ptr[ib.length_dw++] = cpu_to_le32(0x00000100);
+       ib.ptr[ib.length_dw++] = cpu_to_le32(0x00000100);
+       ib.ptr[ib.length_dw++] = cpu_to_le32(0x0000000c);
+       ib.ptr[ib.length_dw++] = cpu_to_le32(0x00000000);
+
+       ib.ptr[ib.length_dw++] = cpu_to_le32(0x00000014); /* len */
+       ib.ptr[ib.length_dw++] = cpu_to_le32(0x05000005); /* feedback buffer */
+       ib.ptr[ib.length_dw++] = cpu_to_le32(upper_32_bits(dummy));
+       ib.ptr[ib.length_dw++] = cpu_to_le32(dummy);
+       ib.ptr[ib.length_dw++] = cpu_to_le32(0x00000001);
 
        for (i = ib.length_dw; i < ib_size_dw; ++i)
-               ib.ptr[i] = 0x0;
+               ib.ptr[i] = cpu_to_le32(0x0);
 
        r = radeon_ib_schedule(rdev, &ib, NULL, false);
        if (r) {
@@ -428,21 +428,21 @@ int radeon_vce_get_destroy_msg(struct radeon_device *rdev, int ring,
 
        /* stitch together an VCE destroy msg */
        ib.length_dw = 0;
-       ib.ptr[ib.length_dw++] = 0x0000000c; /* len */
-       ib.ptr[ib.length_dw++] = 0x00000001; /* session cmd */
-       ib.ptr[ib.length_dw++] = handle;
+       ib.ptr[ib.length_dw++] = cpu_to_le32(0x0000000c); /* len */
+       ib.ptr[ib.length_dw++] = cpu_to_le32(0x00000001); /* session cmd */
+       ib.ptr[ib.length_dw++] = cpu_to_le32(handle);
 
-       ib.ptr[ib.length_dw++] = 0x00000014; /* len */
-       ib.ptr[ib.length_dw++] = 0x05000005; /* feedback buffer */
-       ib.ptr[ib.length_dw++] = upper_32_bits(dummy);
-       ib.ptr[ib.length_dw++] = dummy;
-       ib.ptr[ib.length_dw++] = 0x00000001;
+       ib.ptr[ib.length_dw++] = cpu_to_le32(0x00000014); /* len */
+       ib.ptr[ib.length_dw++] = cpu_to_le32(0x05000005); /* feedback buffer */
+       ib.ptr[ib.length_dw++] = cpu_to_le32(upper_32_bits(dummy));
+       ib.ptr[ib.length_dw++] = cpu_to_le32(dummy);
+       ib.ptr[ib.length_dw++] = cpu_to_le32(0x00000001);
 
-       ib.ptr[ib.length_dw++] = 0x00000008; /* len */
-       ib.ptr[ib.length_dw++] = 0x02000001; /* destroy cmd */
+       ib.ptr[ib.length_dw++] = cpu_to_le32(0x00000008); /* len */
+       ib.ptr[ib.length_dw++] = cpu_to_le32(0x02000001); /* destroy cmd */
 
        for (i = ib.length_dw; i < ib_size_dw; ++i)
-               ib.ptr[i] = 0x0;
+               ib.ptr[i] = cpu_to_le32(0x0);
 
        r = radeon_ib_schedule(rdev, &ib, NULL, false);
        if (r) {
@@ -699,12 +699,12 @@ bool radeon_vce_semaphore_emit(struct radeon_device *rdev,
 {
        uint64_t addr = semaphore->gpu_addr;
 
-       radeon_ring_write(ring, VCE_CMD_SEMAPHORE);
-       radeon_ring_write(ring, (addr >> 3) & 0x000FFFFF);
-       radeon_ring_write(ring, (addr >> 23) & 0x000FFFFF);
-       radeon_ring_write(ring, 0x01003000 | (emit_wait ? 1 : 0));
+       radeon_ring_write(ring, cpu_to_le32(VCE_CMD_SEMAPHORE));
+       radeon_ring_write(ring, cpu_to_le32((addr >> 3) & 0x000FFFFF));
+       radeon_ring_write(ring, cpu_to_le32((addr >> 23) & 0x000FFFFF));
+       radeon_ring_write(ring, cpu_to_le32(0x01003000 | (emit_wait ? 1 : 0)));
        if (!emit_wait)
-               radeon_ring_write(ring, VCE_CMD_END);
+               radeon_ring_write(ring, cpu_to_le32(VCE_CMD_END));
 
        return true;
 }
@@ -719,10 +719,10 @@ bool radeon_vce_semaphore_emit(struct radeon_device *rdev,
 void radeon_vce_ib_execute(struct radeon_device *rdev, struct radeon_ib *ib)
 {
        struct radeon_ring *ring = &rdev->ring[ib->ring];
-       radeon_ring_write(ring, VCE_CMD_IB);
-       radeon_ring_write(ring, ib->gpu_addr);
-       radeon_ring_write(ring, upper_32_bits(ib->gpu_addr));
-       radeon_ring_write(ring, ib->length_dw);
+       radeon_ring_write(ring, cpu_to_le32(VCE_CMD_IB));
+       radeon_ring_write(ring, cpu_to_le32(ib->gpu_addr));
+       radeon_ring_write(ring, cpu_to_le32(upper_32_bits(ib->gpu_addr)));
+       radeon_ring_write(ring, cpu_to_le32(ib->length_dw));
 }
 
 /**
@@ -738,12 +738,12 @@ void radeon_vce_fence_emit(struct radeon_device *rdev,
        struct radeon_ring *ring = &rdev->ring[fence->ring];
        uint64_t addr = rdev->fence_drv[fence->ring].gpu_addr;
 
-       radeon_ring_write(ring, VCE_CMD_FENCE);
-       radeon_ring_write(ring, addr);
-       radeon_ring_write(ring, upper_32_bits(addr));
-       radeon_ring_write(ring, fence->seq);
-       radeon_ring_write(ring, VCE_CMD_TRAP);
-       radeon_ring_write(ring, VCE_CMD_END);
+       radeon_ring_write(ring, cpu_to_le32(VCE_CMD_FENCE));
+       radeon_ring_write(ring, cpu_to_le32(addr));
+       radeon_ring_write(ring, cpu_to_le32(upper_32_bits(addr)));
+       radeon_ring_write(ring, cpu_to_le32(fence->seq));
+       radeon_ring_write(ring, cpu_to_le32(VCE_CMD_TRAP));
+       radeon_ring_write(ring, cpu_to_le32(VCE_CMD_END));
 }
 
 /**
@@ -765,7 +765,7 @@ int radeon_vce_ring_test(struct radeon_device *rdev, struct radeon_ring *ring)
                          ring->idx, r);
                return r;
        }
-       radeon_ring_write(ring, VCE_CMD_END);
+       radeon_ring_write(ring, cpu_to_le32(VCE_CMD_END));
        radeon_ring_unlock_commit(rdev, ring, false);
 
        for (i = 0; i < rdev->usec_timeout; i++) {
index 97a904835759f7876b2b69be104493cf302554a7..6244f4e44e9a541d15d5a76ac36beff8822c3145 100644 (file)
@@ -813,7 +813,7 @@ int rs600_irq_process(struct radeon_device *rdev)
                status = rs600_irq_ack(rdev);
        }
        if (queue_hotplug)
-               schedule_work(&rdev->hotplug_work);
+               schedule_delayed_work(&rdev->hotplug_work, 0);
        if (queue_hdmi)
                schedule_work(&rdev->audio_work);
        if (rdev->msi_enabled) {
index 516ca27cfa12847e904bd9f8ecb8047db53bdba5..6bc44c24e837b30e39970f0a74e64eab4be88294 100644 (file)
@@ -207,6 +207,9 @@ void rs690_line_buffer_adjust(struct radeon_device *rdev,
 {
        u32 tmp;
 
+       /* Guess line buffer size to be 8192 pixels */
+       u32 lb_size = 8192;
+
        /*
         * Line Buffer Setup
         * There is a single line buffer shared by both display controllers.
@@ -243,6 +246,13 @@ void rs690_line_buffer_adjust(struct radeon_device *rdev,
                tmp |= V_006520_DC_LB_MEMORY_SPLIT_D1_1Q_D2_3Q;
        }
        WREG32(R_006520_DC_LB_MEMORY_SPLIT, tmp);
+
+       /* Save number of lines the linebuffer leads before the scanout */
+       if (mode1)
+               rdev->mode_info.crtcs[0]->lb_vblank_lead_lines = DIV_ROUND_UP(lb_size, mode1->crtc_hdisplay);
+
+       if (mode2)
+               rdev->mode_info.crtcs[1]->lb_vblank_lead_lines = DIV_ROUND_UP(lb_size, mode2->crtc_hdisplay);
 }
 
 struct rs690_watermark {
index 3f5e1cf138ba46a2b0385f979a67fc4bac98ceee..d37ba2cb886e90f54093ca8069c6732994535b8e 100644 (file)
@@ -464,7 +464,7 @@ void rv730_stop_dpm(struct radeon_device *rdev)
        result = rv770_send_msg_to_smc(rdev, PPSMC_MSG_TwoLevelsDisabled);
 
        if (result != PPSMC_Result_OK)
-               DRM_ERROR("Could not force DPM to low\n");
+               DRM_DEBUG("Could not force DPM to low\n");
 
        WREG32_P(GENERAL_PWRMGT, 0, ~GLOBAL_PWRMGT_EN);
 
index b9c770745a7a1f717cb9c894a6882c090fd8153c..e830c8935db0d9f1a7455a5c4df4c54727241dbc 100644 (file)
@@ -193,7 +193,7 @@ void rv770_stop_dpm(struct radeon_device *rdev)
        result = rv770_send_msg_to_smc(rdev, PPSMC_MSG_TwoLevelsDisabled);
 
        if (result != PPSMC_Result_OK)
-               DRM_ERROR("Could not force DPM to low.\n");
+               DRM_DEBUG("Could not force DPM to low.\n");
 
        WREG32_P(GENERAL_PWRMGT, 0, ~GLOBAL_PWRMGT_EN);
 
@@ -1418,7 +1418,7 @@ int rv770_resume_smc(struct radeon_device *rdev)
 int rv770_set_sw_state(struct radeon_device *rdev)
 {
        if (rv770_send_msg_to_smc(rdev, PPSMC_MSG_SwitchToSwState) != PPSMC_Result_OK)
-               return -EINVAL;
+               DRM_DEBUG("rv770_set_sw_state failed\n");
        return 0;
 }
 
index 07037e32dea327f935ef39e0bdafea8fb640b39a..f878d6962da58b4aed296c22e485846bc14183c4 100644 (file)
@@ -2376,6 +2376,9 @@ static void dce6_program_watermarks(struct radeon_device *rdev,
                c.full = dfixed_div(c, a);
                priority_b_mark = dfixed_trunc(c);
                priority_b_cnt |= priority_b_mark & PRIORITY_MARK_MASK;
+
+               /* Save number of lines the linebuffer leads before the scanout */
+               radeon_crtc->lb_vblank_lead_lines = DIV_ROUND_UP(lb_size, mode->crtc_hdisplay);
        }
 
        /* select wm A */
@@ -6848,7 +6851,7 @@ restart_ih:
        if (queue_dp)
                schedule_work(&rdev->dp_work);
        if (queue_hotplug)
-               schedule_work(&rdev->hotplug_work);
+               schedule_delayed_work(&rdev->hotplug_work, 0);
        if (queue_thermal && rdev->pm.dpm_enabled)
                schedule_work(&rdev->pm.dpm.thermal.work);
        rdev->ih.rptr = rptr;
index e72bf46042e0a42f469cbfd8ff285b1ae9abb155..a82b891ae1febb4a4523fbde3dea3de398c8a40c 100644 (file)
@@ -2927,7 +2927,7 @@ static struct si_dpm_quirk si_dpm_quirk_list[] = {
        { PCI_VENDOR_ID_ATI, 0x6810, 0x1462, 0x3036, 0, 120000 },
        { PCI_VENDOR_ID_ATI, 0x6811, 0x174b, 0xe271, 0, 120000 },
        { PCI_VENDOR_ID_ATI, 0x6810, 0x174b, 0xe271, 85000, 90000 },
-       { PCI_VENDOR_ID_ATI, 0x6811, 0x1762, 0x2015, 0, 120000 },
+       { PCI_VENDOR_ID_ATI, 0x6811, 0x1462, 0x2015, 0, 120000 },
        { PCI_VENDOR_ID_ATI, 0x6811, 0x1043, 0x2015, 0, 120000 },
        { 0, 0, 0, 0 },
 };
index 8caea0a33dd84560be30f18b882dc8c4b3daed17..d908321b94ced4ffe10936f4c7ef37fc518d127a 100644 (file)
@@ -67,6 +67,7 @@ static int rockchip_drm_gem_object_mmap(struct drm_gem_object *obj,
         * VM_PFNMAP flag that was set by drm_gem_mmap_obj()/drm_gem_mmap().
         */
        vma->vm_flags &= ~VM_PFNMAP;
+       vma->vm_pgoff = 0;
 
        ret = dma_mmap_attrs(drm->dev, vma, rk_obj->kvaddr, rk_obj->dma_addr,
                             obj->size, &rk_obj->dma_attrs);
index 5d8ae5e49c440f98afda4c02d6aea8e335c78c82..03c47eeadc812ba649e68ad97270d5c512efea86 100644 (file)
@@ -374,6 +374,7 @@ static const struct of_device_id vop_driver_dt_match[] = {
          .data = &rk3288_vop },
        {},
 };
+MODULE_DEVICE_TABLE(of, vop_driver_dt_match);
 
 static inline void vop_writel(struct vop *vop, uint32_t offset, uint32_t v)
 {
@@ -959,8 +960,8 @@ static int vop_update_plane_event(struct drm_plane *plane,
        val = (dest.y2 - dest.y1 - 1) << 16;
        val |= (dest.x2 - dest.x1 - 1) & 0xffff;
        VOP_WIN_SET(vop, win, dsp_info, val);
-       val = (dsp_sty - 1) << 16;
-       val |= (dsp_stx - 1) & 0xffff;
+       val = dsp_sty << 16;
+       val |= dsp_stx & 0xffff;
        VOP_WIN_SET(vop, win, dsp_st, val);
        VOP_WIN_SET(vop, win, rb_swap, rb_swap);
 
@@ -1289,7 +1290,7 @@ static void vop_win_state_complete(struct vop_win *vop_win,
 
        if (state->event) {
                spin_lock_irqsave(&drm->event_lock, flags);
-               drm_send_vblank_event(drm, -1, state->event);
+               drm_crtc_send_vblank_event(crtc, state->event);
                spin_unlock_irqrestore(&drm->event_lock, flags);
        }
 
@@ -1575,32 +1576,25 @@ static int vop_initial(struct vop *vop)
                return PTR_ERR(vop->dclk);
        }
 
-       ret = clk_prepare(vop->hclk);
-       if (ret < 0) {
-               dev_err(vop->dev, "failed to prepare hclk\n");
-               return ret;
-       }
-
        ret = clk_prepare(vop->dclk);
        if (ret < 0) {
                dev_err(vop->dev, "failed to prepare dclk\n");
-               goto err_unprepare_hclk;
+               return ret;
        }
 
-       ret = clk_prepare(vop->aclk);
+       /* Enable both the hclk and aclk to setup the vop */
+       ret = clk_prepare_enable(vop->hclk);
        if (ret < 0) {
-               dev_err(vop->dev, "failed to prepare aclk\n");
+               dev_err(vop->dev, "failed to prepare/enable hclk\n");
                goto err_unprepare_dclk;
        }
 
-       /*
-        * enable hclk, so that we can config vop register.
-        */
-       ret = clk_enable(vop->hclk);
+       ret = clk_prepare_enable(vop->aclk);
        if (ret < 0) {
-               dev_err(vop->dev, "failed to prepare aclk\n");
-               goto err_unprepare_aclk;
+               dev_err(vop->dev, "failed to prepare/enable aclk\n");
+               goto err_disable_hclk;
        }
+
        /*
         * do hclk_reset, reset all vop registers.
         */
@@ -1608,7 +1602,7 @@ static int vop_initial(struct vop *vop)
        if (IS_ERR(ahb_rst)) {
                dev_err(vop->dev, "failed to get ahb reset\n");
                ret = PTR_ERR(ahb_rst);
-               goto err_disable_hclk;
+               goto err_disable_aclk;
        }
        reset_control_assert(ahb_rst);
        usleep_range(10, 20);
@@ -1634,26 +1628,25 @@ static int vop_initial(struct vop *vop)
        if (IS_ERR(vop->dclk_rst)) {
                dev_err(vop->dev, "failed to get dclk reset\n");
                ret = PTR_ERR(vop->dclk_rst);
-               goto err_unprepare_aclk;
+               goto err_disable_aclk;
        }
        reset_control_assert(vop->dclk_rst);
        usleep_range(10, 20);
        reset_control_deassert(vop->dclk_rst);
 
        clk_disable(vop->hclk);
+       clk_disable(vop->aclk);
 
        vop->is_enabled = false;
 
        return 0;
 
+err_disable_aclk:
+       clk_disable_unprepare(vop->aclk);
 err_disable_hclk:
-       clk_disable(vop->hclk);
-err_unprepare_aclk:
-       clk_unprepare(vop->aclk);
+       clk_disable_unprepare(vop->hclk);
 err_unprepare_dclk:
        clk_unprepare(vop->dclk);
-err_unprepare_hclk:
-       clk_unprepare(vop->hclk);
        return ret;
 }
 
index 6a954544727f3f13cfa8d9be0b8ff4cbf39d9367..f154fb1929bd18e300e226d8fe89925b9e8b3754 100644 (file)
@@ -180,7 +180,7 @@ int ttm_write_lock(struct ttm_lock *lock, bool interruptible)
                        spin_unlock(&lock->lock);
                }
        } else
-               wait_event(lock->queue, __ttm_read_lock(lock));
+               wait_event(lock->queue, __ttm_write_lock(lock));
 
        return ret;
 }
index 7a9f4768591eabe54877327bbf6c1cc220c6d525..265064c62d493b54023947d49597852a16328a5f 100644 (file)
@@ -168,7 +168,7 @@ static int vc4_get_clock_select(struct drm_crtc *crtc)
        struct drm_connector *connector;
 
        drm_for_each_connector(connector, crtc->dev) {
-               if (connector && connector->state->crtc == crtc) {
+               if (connector->state->crtc == crtc) {
                        struct drm_encoder *encoder = connector->encoder;
                        struct vc4_encoder *vc4_encoder =
                                to_vc4_encoder(encoder);
@@ -401,7 +401,8 @@ static void vc4_crtc_atomic_flush(struct drm_crtc *crtc,
                dlist_next++;
 
                HVS_WRITE(SCALER_DISPLISTX(vc4_crtc->channel),
-                         (u32 *)vc4_crtc->dlist - (u32 *)vc4->hvs->dlist);
+                         (u32 __iomem *)vc4_crtc->dlist -
+                         (u32 __iomem *)vc4->hvs->dlist);
 
                /* Make the next display list start after ours. */
                vc4_crtc->dlist_size -= (dlist_next - vc4_crtc->dlist);
@@ -591,14 +592,14 @@ static int vc4_crtc_bind(struct device *dev, struct device *master, void *data)
         * that will take too much.
         */
        primary_plane = vc4_plane_init(drm, DRM_PLANE_TYPE_PRIMARY);
-       if (!primary_plane) {
+       if (IS_ERR(primary_plane)) {
                dev_err(dev, "failed to construct primary plane\n");
                ret = PTR_ERR(primary_plane);
                goto err;
        }
 
        cursor_plane = vc4_plane_init(drm, DRM_PLANE_TYPE_CURSOR);
-       if (!cursor_plane) {
+       if (IS_ERR(cursor_plane)) {
                dev_err(dev, "failed to construct cursor plane\n");
                ret = PTR_ERR(cursor_plane);
                goto err_primary;
index 6e730605edccc01de7ff01fd6e3b7ca58f62ec6d..d5db9e0f3b736ee1acc07888f59c4650aaa84287 100644 (file)
@@ -259,7 +259,6 @@ static struct platform_driver vc4_platform_driver = {
        .remove         = vc4_platform_drm_remove,
        .driver         = {
                .name   = "vc4-drm",
-               .owner  = THIS_MODULE,
                .of_match_table = vc4_of_match,
        },
 };
index ab1673f672a4ec9c88e46e008de64aeb0dded415..8098c5b21ba447c43a16c7a62b9a4de0590abe1f 100644 (file)
@@ -75,10 +75,10 @@ void vc4_hvs_dump_state(struct drm_device *dev)
        for (i = 0; i < 64; i += 4) {
                DRM_INFO("0x%08x (%s): 0x%08x 0x%08x 0x%08x 0x%08x\n",
                         i * 4, i < HVS_BOOTLOADER_DLIST_END ? "B" : "D",
-                        ((uint32_t *)vc4->hvs->dlist)[i + 0],
-                        ((uint32_t *)vc4->hvs->dlist)[i + 1],
-                        ((uint32_t *)vc4->hvs->dlist)[i + 2],
-                        ((uint32_t *)vc4->hvs->dlist)[i + 3]);
+                        readl((u32 __iomem *)vc4->hvs->dlist + i + 0),
+                        readl((u32 __iomem *)vc4->hvs->dlist + i + 1),
+                        readl((u32 __iomem *)vc4->hvs->dlist + i + 2),
+                        readl((u32 __iomem *)vc4->hvs->dlist + i + 3));
        }
 }
 
index cdd8b10c014742cb8079837e2723163afb8d04c1..887f3caad0be6b6fd115b4e9430abfd3aeadd53f 100644 (file)
@@ -70,7 +70,7 @@ static bool plane_enabled(struct drm_plane_state *state)
        return state->fb && state->crtc;
 }
 
-struct drm_plane_state *vc4_plane_duplicate_state(struct drm_plane *plane)
+static struct drm_plane_state *vc4_plane_duplicate_state(struct drm_plane *plane)
 {
        struct vc4_plane_state *vc4_state;
 
@@ -97,8 +97,8 @@ struct drm_plane_state *vc4_plane_duplicate_state(struct drm_plane *plane)
        return &vc4_state->base;
 }
 
-void vc4_plane_destroy_state(struct drm_plane *plane,
-                            struct drm_plane_state *state)
+static void vc4_plane_destroy_state(struct drm_plane *plane,
+                                   struct drm_plane_state *state)
 {
        struct vc4_plane_state *vc4_state = to_vc4_plane_state(state);
 
@@ -108,7 +108,7 @@ void vc4_plane_destroy_state(struct drm_plane *plane,
 }
 
 /* Called during init to allocate the plane's atomic state. */
-void vc4_plane_reset(struct drm_plane *plane)
+static void vc4_plane_reset(struct drm_plane *plane)
 {
        struct vc4_plane_state *vc4_state;
 
@@ -157,6 +157,16 @@ static int vc4_plane_mode_set(struct drm_plane *plane,
        int crtc_w = state->crtc_w;
        int crtc_h = state->crtc_h;
 
+       if (state->crtc_w << 16 != state->src_w ||
+           state->crtc_h << 16 != state->src_h) {
+               /* We don't support scaling yet, which involves
+                * allocating the LBM memory for scaling temporary
+                * storage, and putting filter kernels in the HVS
+                * context.
+                */
+               return -EINVAL;
+       }
+
        if (crtc_x < 0) {
                offset += drm_format_plane_cpp(fb->pixel_format, 0) * -crtc_x;
                crtc_w += crtc_x;
index f545913a56c7a972fe71dea32a20972f5440f5fb..578fe0a9324cd9bd710e3d9ef2d393e8311d3cb2 100644 (file)
@@ -412,7 +412,7 @@ static const struct drm_connector_funcs virtio_gpu_connector_funcs = {
        .save = virtio_gpu_conn_save,
        .restore = virtio_gpu_conn_restore,
        .detect = virtio_gpu_conn_detect,
-       .fill_modes = drm_helper_probe_single_connector_modes,
+       .fill_modes = drm_helper_probe_single_connector_modes_nomerge,
        .destroy = virtio_gpu_conn_destroy,
        .reset = drm_atomic_helper_connector_reset,
        .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
index a09cf8529b9f6374649e2f943ef84e3cf08eeda1..c49812b80dd0dae82c77096f75fbd4cced19ffb1 100644 (file)
@@ -1233,6 +1233,7 @@ static void vmw_master_drop(struct drm_device *dev,
 
        vmw_fp->locked_master = drm_master_get(file_priv->master);
        ret = ttm_vt_lock(&vmaster->lock, false, vmw_fp->tfile);
+       vmw_kms_legacy_hotspot_clear(dev_priv);
        if (unlikely((ret != 0))) {
                DRM_ERROR("Unable to lock TTM at VT switch.\n");
                drm_master_put(&vmw_fp->locked_master);
index a8ae9dfb83b7d4916023d9e8e3835da42f0c3979..469cdd520615d036fdb99b0f7e27ed67ce3abd67 100644 (file)
@@ -925,6 +925,7 @@ int vmw_kms_present(struct vmw_private *dev_priv,
                    uint32_t num_clips);
 int vmw_kms_update_layout_ioctl(struct drm_device *dev, void *data,
                                struct drm_file *file_priv);
+void vmw_kms_legacy_hotspot_clear(struct vmw_private *dev_priv);
 
 int vmw_dumb_create(struct drm_file *file_priv,
                    struct drm_device *dev,
index a8baf5f5e76558679d128de151d2caaea193bc6c..b6a0806b06bffaf6da9178905f9b2f6bb037d384 100644 (file)
@@ -390,7 +390,7 @@ void *vmw_fifo_reserve_dx(struct vmw_private *dev_priv, uint32_t bytes,
        else if (ctx_id == SVGA3D_INVALID_ID)
                ret = vmw_local_fifo_reserve(dev_priv, bytes);
        else {
-               WARN_ON("Command buffer has not been allocated.\n");
+               WARN(1, "Command buffer has not been allocated.\n");
                ret = NULL;
        }
        if (IS_ERR_OR_NULL(ret)) {
index 9fcd7f82995c3e1a517930cb8a89a23351c55c15..9b4bb9e74d7300793f3ecb1c0feef42085780819 100644 (file)
@@ -133,13 +133,19 @@ void vmw_cursor_update_position(struct vmw_private *dev_priv,
        vmw_mmio_write(++count, fifo_mem + SVGA_FIFO_CURSOR_COUNT);
 }
 
-int vmw_du_crtc_cursor_set(struct drm_crtc *crtc, struct drm_file *file_priv,
-                          uint32_t handle, uint32_t width, uint32_t height)
+
+/*
+ * vmw_du_crtc_cursor_set2 - Driver cursor_set2 callback.
+ */
+int vmw_du_crtc_cursor_set2(struct drm_crtc *crtc, struct drm_file *file_priv,
+                           uint32_t handle, uint32_t width, uint32_t height,
+                           int32_t hot_x, int32_t hot_y)
 {
        struct vmw_private *dev_priv = vmw_priv(crtc->dev);
        struct vmw_display_unit *du = vmw_crtc_to_du(crtc);
        struct vmw_surface *surface = NULL;
        struct vmw_dma_buffer *dmabuf = NULL;
+       s32 hotspot_x, hotspot_y;
        int ret;
 
        /*
@@ -151,6 +157,8 @@ int vmw_du_crtc_cursor_set(struct drm_crtc *crtc, struct drm_file *file_priv,
         */
        drm_modeset_unlock_crtc(crtc);
        drm_modeset_lock_all(dev_priv->dev);
+       hotspot_x = hot_x + du->hotspot_x;
+       hotspot_y = hot_y + du->hotspot_y;
 
        /* A lot of the code assumes this */
        if (handle && (width != 64 || height != 64)) {
@@ -187,31 +195,34 @@ int vmw_du_crtc_cursor_set(struct drm_crtc *crtc, struct drm_file *file_priv,
                vmw_dmabuf_unreference(&du->cursor_dmabuf);
 
        /* setup new image */
+       ret = 0;
        if (surface) {
                /* vmw_user_surface_lookup takes one reference */
                du->cursor_surface = surface;
 
                du->cursor_surface->snooper.crtc = crtc;
                du->cursor_age = du->cursor_surface->snooper.age;
-               vmw_cursor_update_image(dev_priv, surface->snooper.image,
-                                       64, 64, du->hotspot_x, du->hotspot_y);
+               ret = vmw_cursor_update_image(dev_priv, surface->snooper.image,
+                                             64, 64, hotspot_x, hotspot_y);
        } else if (dmabuf) {
                /* vmw_user_surface_lookup takes one reference */
                du->cursor_dmabuf = dmabuf;
 
                ret = vmw_cursor_update_dmabuf(dev_priv, dmabuf, width, height,
-                                              du->hotspot_x, du->hotspot_y);
+                                              hotspot_x, hotspot_y);
        } else {
                vmw_cursor_update_position(dev_priv, false, 0, 0);
-               ret = 0;
                goto out;
        }
 
-       vmw_cursor_update_position(dev_priv, true,
-                                  du->cursor_x + du->hotspot_x,
-                                  du->cursor_y + du->hotspot_y);
+       if (!ret) {
+               vmw_cursor_update_position(dev_priv, true,
+                                          du->cursor_x + hotspot_x,
+                                          du->cursor_y + hotspot_y);
+               du->core_hotspot_x = hot_x;
+               du->core_hotspot_y = hot_y;
+       }
 
-       ret = 0;
 out:
        drm_modeset_unlock_all(dev_priv->dev);
        drm_modeset_lock_crtc(crtc, crtc->cursor);
@@ -239,8 +250,10 @@ int vmw_du_crtc_cursor_move(struct drm_crtc *crtc, int x, int y)
        drm_modeset_lock_all(dev_priv->dev);
 
        vmw_cursor_update_position(dev_priv, shown,
-                                  du->cursor_x + du->hotspot_x,
-                                  du->cursor_y + du->hotspot_y);
+                                  du->cursor_x + du->hotspot_x +
+                                  du->core_hotspot_x,
+                                  du->cursor_y + du->hotspot_y +
+                                  du->core_hotspot_y);
 
        drm_modeset_unlock_all(dev_priv->dev);
        drm_modeset_lock_crtc(crtc, crtc->cursor);
@@ -334,6 +347,29 @@ err_unreserve:
        ttm_bo_unreserve(bo);
 }
 
+/**
+ * vmw_kms_legacy_hotspot_clear - Clear legacy hotspots
+ *
+ * @dev_priv: Pointer to the device private struct.
+ *
+ * Clears all legacy hotspots.
+ */
+void vmw_kms_legacy_hotspot_clear(struct vmw_private *dev_priv)
+{
+       struct drm_device *dev = dev_priv->dev;
+       struct vmw_display_unit *du;
+       struct drm_crtc *crtc;
+
+       drm_modeset_lock_all(dev);
+       drm_for_each_crtc(crtc, dev) {
+               du = vmw_crtc_to_du(crtc);
+
+               du->hotspot_x = 0;
+               du->hotspot_y = 0;
+       }
+       drm_modeset_unlock_all(dev);
+}
+
 void vmw_kms_cursor_post_execbuf(struct vmw_private *dev_priv)
 {
        struct drm_device *dev = dev_priv->dev;
@@ -351,7 +387,9 @@ void vmw_kms_cursor_post_execbuf(struct vmw_private *dev_priv)
                du->cursor_age = du->cursor_surface->snooper.age;
                vmw_cursor_update_image(dev_priv,
                                        du->cursor_surface->snooper.image,
-                                       64, 64, du->hotspot_x, du->hotspot_y);
+                                       64, 64,
+                                       du->hotspot_x + du->core_hotspot_x,
+                                       du->hotspot_y + du->core_hotspot_y);
        }
 
        mutex_unlock(&dev->mode_config.mutex);
index 782df7ca97946220414dd66a2afbe4f94b6d403a..edd81503516dbbda1fab84ecd53ecc0df689f24e 100644 (file)
@@ -159,6 +159,8 @@ struct vmw_display_unit {
 
        int hotspot_x;
        int hotspot_y;
+       s32 core_hotspot_x;
+       s32 core_hotspot_y;
 
        unsigned unit;
 
@@ -193,8 +195,9 @@ void vmw_du_crtc_restore(struct drm_crtc *crtc);
 void vmw_du_crtc_gamma_set(struct drm_crtc *crtc,
                           u16 *r, u16 *g, u16 *b,
                           uint32_t start, uint32_t size);
-int vmw_du_crtc_cursor_set(struct drm_crtc *crtc, struct drm_file *file_priv,
-                          uint32_t handle, uint32_t width, uint32_t height);
+int vmw_du_crtc_cursor_set2(struct drm_crtc *crtc, struct drm_file *file_priv,
+                           uint32_t handle, uint32_t width, uint32_t height,
+                           int32_t hot_x, int32_t hot_y);
 int vmw_du_crtc_cursor_move(struct drm_crtc *crtc, int x, int y);
 int vmw_du_connector_dpms(struct drm_connector *connector, int mode);
 void vmw_du_connector_save(struct drm_connector *connector);
index bb63e4d795fae43bc07599babe45bedf26f6e114..52caecb4502ed3086b8ea6e15fac9e45a08d4659 100644 (file)
@@ -297,7 +297,7 @@ static int vmw_ldu_crtc_set_config(struct drm_mode_set *set)
 static struct drm_crtc_funcs vmw_legacy_crtc_funcs = {
        .save = vmw_du_crtc_save,
        .restore = vmw_du_crtc_restore,
-       .cursor_set = vmw_du_crtc_cursor_set,
+       .cursor_set2 = vmw_du_crtc_cursor_set2,
        .cursor_move = vmw_du_crtc_cursor_move,
        .gamma_set = vmw_du_crtc_gamma_set,
        .destroy = vmw_ldu_crtc_destroy,
index b96d1ab610c5527fb190ea476cdbbb82a2b2e158..13926ff192e3d6ce55b0e741ef66a04c9377596b 100644 (file)
@@ -533,7 +533,7 @@ out_no_fence:
 static struct drm_crtc_funcs vmw_screen_object_crtc_funcs = {
        .save = vmw_du_crtc_save,
        .restore = vmw_du_crtc_restore,
-       .cursor_set = vmw_du_crtc_cursor_set,
+       .cursor_set2 = vmw_du_crtc_cursor_set2,
        .cursor_move = vmw_du_crtc_cursor_move,
        .gamma_set = vmw_du_crtc_gamma_set,
        .destroy = vmw_sou_crtc_destroy,
index b1fc1c02792d4c3f89cb76a0dfb0f16f3dce2c47..f823fc3efed72473108acab83d65191a00e40e9a 100644 (file)
@@ -1043,7 +1043,7 @@ out_finish:
 static struct drm_crtc_funcs vmw_stdu_crtc_funcs = {
        .save = vmw_du_crtc_save,
        .restore = vmw_du_crtc_restore,
-       .cursor_set = vmw_du_crtc_cursor_set,
+       .cursor_set2 = vmw_du_crtc_cursor_set2,
        .cursor_move = vmw_du_crtc_cursor_move,
        .gamma_set = vmw_du_crtc_gamma_set,
        .destroy = vmw_stdu_crtc_destroy,
index ba47b30d28fad4f3d187393a44a17bd9605f6ad4..f2e13eb8339ffc1287110e247e0e54e922b7d72a 100644 (file)
@@ -28,6 +28,7 @@
 #include <linux/irqchip/chained_irq.h>
 #include <linux/irqdomain.h>
 #include <linux/of_device.h>
+#include <linux/of_graph.h>
 
 #include <drm/drm_fourcc.h>
 
@@ -993,11 +994,25 @@ static void platform_device_unregister_children(struct platform_device *pdev)
 struct ipu_platform_reg {
        struct ipu_client_platformdata pdata;
        const char *name;
-       int reg_offset;
 };
 
+/* These must be in the order of the corresponding device tree port nodes */
 static const struct ipu_platform_reg client_reg[] = {
        {
+               .pdata = {
+                       .csi = 0,
+                       .dma[0] = IPUV3_CHANNEL_CSI0,
+                       .dma[1] = -EINVAL,
+               },
+               .name = "imx-ipuv3-camera",
+       }, {
+               .pdata = {
+                       .csi = 1,
+                       .dma[0] = IPUV3_CHANNEL_CSI1,
+                       .dma[1] = -EINVAL,
+               },
+               .name = "imx-ipuv3-camera",
+       }, {
                .pdata = {
                        .di = 0,
                        .dc = 5,
@@ -1015,22 +1030,6 @@ static const struct ipu_platform_reg client_reg[] = {
                        .dma[1] = -EINVAL,
                },
                .name = "imx-ipuv3-crtc",
-       }, {
-               .pdata = {
-                       .csi = 0,
-                       .dma[0] = IPUV3_CHANNEL_CSI0,
-                       .dma[1] = -EINVAL,
-               },
-               .reg_offset = IPU_CM_CSI0_REG_OFS,
-               .name = "imx-ipuv3-camera",
-       }, {
-               .pdata = {
-                       .csi = 1,
-                       .dma[0] = IPUV3_CHANNEL_CSI1,
-                       .dma[1] = -EINVAL,
-               },
-               .reg_offset = IPU_CM_CSI1_REG_OFS,
-               .name = "imx-ipuv3-camera",
        },
 };
 
@@ -1051,22 +1050,30 @@ static int ipu_add_client_devices(struct ipu_soc *ipu, unsigned long ipu_base)
        for (i = 0; i < ARRAY_SIZE(client_reg); i++) {
                const struct ipu_platform_reg *reg = &client_reg[i];
                struct platform_device *pdev;
-               struct resource res;
-
-               if (reg->reg_offset) {
-                       memset(&res, 0, sizeof(res));
-                       res.flags = IORESOURCE_MEM;
-                       res.start = ipu_base + ipu->devtype->cm_ofs + reg->reg_offset;
-                       res.end = res.start + PAGE_SIZE - 1;
-                       pdev = platform_device_register_resndata(dev, reg->name,
-                               id++, &res, 1, &reg->pdata, sizeof(reg->pdata));
-               } else {
-                       pdev = platform_device_register_data(dev, reg->name,
-                               id++, &reg->pdata, sizeof(reg->pdata));
+
+               pdev = platform_device_alloc(reg->name, id++);
+               if (!pdev) {
+                       ret = -ENOMEM;
+                       goto err_register;
+               }
+
+               pdev->dev.parent = dev;
+
+               /* Associate subdevice with the corresponding port node */
+               pdev->dev.of_node = of_graph_get_port_by_id(dev->of_node, i);
+               if (!pdev->dev.of_node) {
+                       dev_err(dev, "missing port@%d node in %s\n", i,
+                               dev->of_node->full_name);
+                       ret = -ENODEV;
+                       goto err_register;
                }
 
-               if (IS_ERR(pdev)) {
-                       ret = PTR_ERR(pdev);
+               ret = platform_device_add_data(pdev, &reg->pdata,
+                                              sizeof(reg->pdata));
+               if (!ret)
+                       ret = platform_device_add(pdev);
+               if (ret) {
+                       platform_device_put(pdev);
                        goto err_register;
                }
        }
index 3166e4bc4eb6daea9a9fcad4eb5fce4b62b1b418..9abcaa53bd25a4149e850562628bdc17e81161ed 100644 (file)
@@ -395,8 +395,10 @@ int vga_get(struct pci_dev *pdev, unsigned int rsrc, int interruptible)
                set_current_state(interruptible ?
                                  TASK_INTERRUPTIBLE :
                                  TASK_UNINTERRUPTIBLE);
-               if (signal_pending(current)) {
-                       rc = -EINTR;
+               if (interruptible && signal_pending(current)) {
+                       __set_current_state(TASK_RUNNING);
+                       remove_wait_queue(&vga_wait_queue, &wait);
+                       rc = -ERESTARTSYS;
                        break;
                }
                schedule();
index ac1feea51be365e3a4c81042b56be75fec26a6a1..8b78a7f1f779faa586abd156a0f9ce7082616bc5 100644 (file)
 #define USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_A001      0xa001
 
 #define USB_VENDOR_ID_ELAN             0x04f3
-#define USB_DEVICE_ID_ELAN_TOUCHSCREEN 0x0089
-#define USB_DEVICE_ID_ELAN_TOUCHSCREEN_009B    0x009b
-#define USB_DEVICE_ID_ELAN_TOUCHSCREEN_0103    0x0103
-#define USB_DEVICE_ID_ELAN_TOUCHSCREEN_010c    0x010c
-#define USB_DEVICE_ID_ELAN_TOUCHSCREEN_016F    0x016f
 
 #define USB_VENDOR_ID_ELECOM           0x056e
 #define USB_DEVICE_ID_ELECOM_BM084     0x0061
 #define USB_DEVICE_ID_LOGITECH_HARMONY_FIRST  0xc110
 #define USB_DEVICE_ID_LOGITECH_HARMONY_LAST 0xc14f
 #define USB_DEVICE_ID_LOGITECH_HARMONY_PS3 0x0306
+#define USB_DEVICE_ID_LOGITECH_KEYBOARD_G710_PLUS 0xc24d
 #define USB_DEVICE_ID_LOGITECH_MOUSE_C01A      0xc01a
 #define USB_DEVICE_ID_LOGITECH_MOUSE_C05A      0xc05a
 #define USB_DEVICE_ID_LOGITECH_MOUSE_C06A      0xc06a
index c20ac76c0a8cb28ebbc8ea75827f3cfba5e2a787..c690fae02cf823d16b6d985d944b6bda143b6282 100644 (file)
@@ -665,8 +665,9 @@ static int lg_probe(struct hid_device *hdev, const struct hid_device_id *id)
        struct lg_drv_data *drv_data;
        int ret;
 
-       /* Only work with the 1st interface (G29 presents multiple) */
-       if (iface_num != 0) {
+       /* G29 only work with the 1st interface */
+       if ((hdev->product == USB_DEVICE_ID_LOGITECH_G29_WHEEL) &&
+           (iface_num != 0)) {
                dbg_hid("%s: ignoring ifnum %d\n", __func__, iface_num);
                return -ENODEV;
        }
index 94bb137abe3281bfb023c7bc438ad8bcf0d716a4..7dd0953cd70f222f037c72b7c217b76eff8d2942 100644 (file)
@@ -72,11 +72,7 @@ static const struct hid_blacklist {
        { USB_VENDOR_ID_CHICONY, USB_DEVICE_ID_CHICONY_PIXART_USB_OPTICAL_MOUSE, HID_QUIRK_ALWAYS_POLL },
        { USB_VENDOR_ID_DMI, USB_DEVICE_ID_DMI_ENC, HID_QUIRK_NOGET },
        { USB_VENDOR_ID_DRAGONRISE, USB_DEVICE_ID_DRAGONRISE_WIIU, HID_QUIRK_MULTI_INPUT },
-       { USB_VENDOR_ID_ELAN, USB_DEVICE_ID_ELAN_TOUCHSCREEN, HID_QUIRK_ALWAYS_POLL },
-       { USB_VENDOR_ID_ELAN, USB_DEVICE_ID_ELAN_TOUCHSCREEN_009B, HID_QUIRK_ALWAYS_POLL },
-       { USB_VENDOR_ID_ELAN, USB_DEVICE_ID_ELAN_TOUCHSCREEN_0103, HID_QUIRK_ALWAYS_POLL },
-       { USB_VENDOR_ID_ELAN, USB_DEVICE_ID_ELAN_TOUCHSCREEN_010c, HID_QUIRK_ALWAYS_POLL },
-       { USB_VENDOR_ID_ELAN, USB_DEVICE_ID_ELAN_TOUCHSCREEN_016F, HID_QUIRK_ALWAYS_POLL },
+       { USB_VENDOR_ID_ELAN, HID_ANY_ID, HID_QUIRK_ALWAYS_POLL },
        { 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 },
@@ -84,6 +80,7 @@ static const struct hid_blacklist {
        { USB_VENDOR_ID_HP, USB_PRODUCT_ID_HP_LOGITECH_OEM_USB_OPTICAL_MOUSE_0B4A, HID_QUIRK_ALWAYS_POLL },
        { USB_VENDOR_ID_HP, USB_PRODUCT_ID_HP_PIXART_OEM_USB_OPTICAL_MOUSE, HID_QUIRK_ALWAYS_POLL },
        { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_C077, HID_QUIRK_ALWAYS_POLL },
+       { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_KEYBOARD_G710_PLUS, HID_QUIRK_NOGET },
        { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_MOUSE_C01A, HID_QUIRK_ALWAYS_POLL },
        { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_MOUSE_C05A, HID_QUIRK_ALWAYS_POLL },
        { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_MOUSE_C06A, HID_QUIRK_ALWAYS_POLL },
@@ -339,7 +336,8 @@ static const struct hid_blacklist *usbhid_exists_squirk(const u16 idVendor,
 
        for (; hid_blacklist[n].idVendor; n++)
                if (hid_blacklist[n].idVendor == idVendor &&
-                               hid_blacklist[n].idProduct == idProduct)
+                       (hid_blacklist[n].idProduct == (__u16) HID_ANY_ID ||
+                               hid_blacklist[n].idProduct == idProduct))
                        bl_entry = &hid_blacklist[n];
 
        if (bl_entry != NULL)
index 8b29949507d1692f436b1db5045ca7ed4b8d54f3..01a4f05c16421b63a09737ad3eb4a4fb249259ae 100644 (file)
@@ -2481,7 +2481,7 @@ void wacom_setup_device_quirks(struct wacom *wacom)
                if (features->pktlen == WACOM_PKGLEN_BBTOUCH3) {
                        if (features->touch_max)
                                features->device_type |= WACOM_DEVICETYPE_TOUCH;
-                       if (features->type >= INTUOSHT || features->type <= BAMBOO_PT)
+                       if (features->type >= INTUOSHT && features->type <= BAMBOO_PT)
                                features->device_type |= WACOM_DEVICETYPE_PAD;
 
                        features->x_max = 4096;
@@ -3213,7 +3213,8 @@ static const struct wacom_features wacom_features_0x32F =
          WACOM_DTU_OFFSET, WACOM_DTU_OFFSET };
 static const struct wacom_features wacom_features_0x336 =
        { "Wacom DTU1141", 23472, 13203, 1023, 0,
-         DTUS, WACOM_INTUOS_RES, WACOM_INTUOS_RES, 4 };
+         DTUS, WACOM_INTUOS_RES, WACOM_INTUOS_RES, 4,
+         WACOM_DTU_OFFSET, WACOM_DTU_OFFSET };
 static const struct wacom_features wacom_features_0x57 =
        { "Wacom DTK2241", 95640, 54060, 2047, 63,
          DTK, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, 6,
index 842b0043ad9477160194a7c7a94b03f7ab06d5a1..80a73bfc1a65807db6fc276e3027f11500d2f96b 100644 (file)
@@ -324,6 +324,7 @@ config SENSORS_APPLESMC
 config SENSORS_ARM_SCPI
        tristate "ARM SCPI Sensors"
        depends on ARM_SCPI_PROTOCOL
+       depends on THERMAL || !THERMAL_OF
        help
          This driver provides support for temperature, voltage, current
          and power sensors available on ARM Ltd's SCP based platforms. The
@@ -1216,6 +1217,7 @@ config SENSORS_PWM_FAN
 config SENSORS_SHT15
        tristate "Sensiron humidity and temperature sensors. SHT15 and compat."
        depends on GPIOLIB || COMPILE_TEST
+       select BITREVERSE
        help
          If you say yes here you get support for the Sensiron SHT10, SHT11,
          SHT15, SHT71, SHT75 humidity and temperature sensors.
@@ -1471,6 +1473,7 @@ config SENSORS_INA209
 config SENSORS_INA2XX
        tristate "Texas Instruments INA219 and compatibles"
        depends on I2C
+       select REGMAP_I2C
        help
          If you say yes here you get support for INA219, INA220, INA226,
          INA230, and INA231 power monitor chips.
index 1f5e956941b1326c6f590b62354bffd40e29ea95..0af7fd311979d25d0684e585ec92f9a65169bdaa 100644 (file)
@@ -537,7 +537,7 @@ static int applesmc_init_index(struct applesmc_registers *s)
 static int applesmc_init_smcreg_try(void)
 {
        struct applesmc_registers *s = &smcreg;
-       bool left_light_sensor, right_light_sensor;
+       bool left_light_sensor = 0, right_light_sensor = 0;
        unsigned int count;
        u8 tmp[1];
        int ret;
index 2c1241bbf9affdbf616a357d3b95c7f7c9963669..7e20567bc36912ada47687716405733e1372bc8a 100644 (file)
@@ -117,7 +117,7 @@ static int scpi_hwmon_probe(struct platform_device *pdev)
        struct scpi_ops *scpi_ops;
        struct device *hwdev, *dev = &pdev->dev;
        struct scpi_sensors *scpi_sensors;
-       int ret;
+       int ret, idx;
 
        scpi_ops = get_scpi_ops();
        if (!scpi_ops)
@@ -146,8 +146,8 @@ static int scpi_hwmon_probe(struct platform_device *pdev)
 
        scpi_sensors->scpi_ops = scpi_ops;
 
-       for (i = 0; i < nr_sensors; i++) {
-               struct sensor_data *sensor = &scpi_sensors->data[i];
+       for (i = 0, idx = 0; i < nr_sensors; i++) {
+               struct sensor_data *sensor = &scpi_sensors->data[idx];
 
                ret = scpi_ops->sensor_get_info(i, &sensor->info);
                if (ret)
@@ -183,7 +183,7 @@ static int scpi_hwmon_probe(struct platform_device *pdev)
                        num_power++;
                        break;
                default:
-                       break;
+                       continue;
                }
 
                sensor->dev_attr_input.attr.mode = S_IRUGO;
@@ -194,11 +194,12 @@ static int scpi_hwmon_probe(struct platform_device *pdev)
                sensor->dev_attr_label.show = scpi_show_label;
                sensor->dev_attr_label.attr.name = sensor->label;
 
-               scpi_sensors->attrs[i << 1] = &sensor->dev_attr_input.attr;
-               scpi_sensors->attrs[(i << 1) + 1] = &sensor->dev_attr_label.attr;
+               scpi_sensors->attrs[idx << 1] = &sensor->dev_attr_input.attr;
+               scpi_sensors->attrs[(idx << 1) + 1] = &sensor->dev_attr_label.attr;
 
-               sysfs_attr_init(scpi_sensors->attrs[i << 1]);
-               sysfs_attr_init(scpi_sensors->attrs[(i << 1) + 1]);
+               sysfs_attr_init(scpi_sensors->attrs[idx << 1]);
+               sysfs_attr_init(scpi_sensors->attrs[(idx << 1) + 1]);
+               idx++;
        }
 
        scpi_sensors->group.attrs = scpi_sensors->attrs;
@@ -236,8 +237,8 @@ static int scpi_hwmon_probe(struct platform_device *pdev)
 
                zone->sensor_id = i;
                zone->scpi_sensors = scpi_sensors;
-               zone->tzd = thermal_zone_of_sensor_register(dev, i, zone,
-                                                           &scpi_sensor_ops);
+               zone->tzd = thermal_zone_of_sensor_register(dev,
+                               sensor->info.sensor_id, zone, &scpi_sensor_ops);
                /*
                 * The call to thermal_zone_of_sensor_register returns
                 * an error for sensors that are not associated with
index 65482624ea2c81a2ef2b5487d6a0470cc90fead7..5289aa0980a8fac074822ddb412f35e7a9380bd5 100644 (file)
@@ -58,6 +58,7 @@ struct tmp102 {
        u16 config_orig;
        unsigned long last_update;
        int temp[3];
+       bool first_time;
 };
 
 /* convert left adjusted 13-bit TMP102 register value to milliCelsius */
@@ -93,6 +94,7 @@ static struct tmp102 *tmp102_update_device(struct device *dev)
                                tmp102->temp[i] = tmp102_reg_to_mC(status);
                }
                tmp102->last_update = jiffies;
+               tmp102->first_time = false;
        }
        mutex_unlock(&tmp102->lock);
        return tmp102;
@@ -102,6 +104,12 @@ static int tmp102_read_temp(void *dev, int *temp)
 {
        struct tmp102 *tmp102 = tmp102_update_device(dev);
 
+       /* Is it too early even to return a conversion? */
+       if (tmp102->first_time) {
+               dev_dbg(dev, "%s: Conversion not ready yet..\n", __func__);
+               return -EAGAIN;
+       }
+
        *temp = tmp102->temp[0];
 
        return 0;
@@ -114,6 +122,10 @@ static ssize_t tmp102_show_temp(struct device *dev,
        struct sensor_device_attribute *sda = to_sensor_dev_attr(attr);
        struct tmp102 *tmp102 = tmp102_update_device(dev);
 
+       /* Is it too early even to return a read? */
+       if (tmp102->first_time)
+               return -EAGAIN;
+
        return sprintf(buf, "%d\n", tmp102->temp[sda->index]);
 }
 
@@ -207,7 +219,9 @@ static int tmp102_probe(struct i2c_client *client,
                status = -ENODEV;
                goto fail_restore_config;
        }
-       tmp102->last_update = jiffies - HZ;
+       tmp102->last_update = jiffies;
+       /* Mark that we are not ready with data until conversion is complete */
+       tmp102->first_time = true;
        mutex_init(&tmp102->lock);
 
        hwmon_dev = hwmon_device_register_with_groups(dev, client->name,
index e24c2b680b475880dd56d0bfb6f2691c00d26801..7b0aa82ea38b2e7521650e6c9a1cab5b25ac8ee4 100644 (file)
@@ -126,6 +126,7 @@ config I2C_I801
            Sunrise Point-LP (PCH)
            DNV (SOC)
            Broxton (SOC)
+           Lewisburg (PCH)
 
          This driver can also be built as a module.  If so, the module
          will be called i2c-i801.
index c5628a42170acf83d0a2c5d2dffa6a50e6572c59..a8bdcb5292f5b30a925c40f28c8d193395b443c6 100644 (file)
@@ -202,8 +202,15 @@ static void i2c_davinci_calc_clk_dividers(struct davinci_i2c_dev *dev)
         * d is always 6 on Keystone I2C controller
         */
 
-       /* get minimum of 7 MHz clock, but max of 12 MHz */
-       psc = (input_clock / 7000000) - 1;
+       /*
+        * Both Davinci and current Keystone User Guides recommend a value
+        * between 7MHz and 12MHz. In reality 7MHz module clock doesn't
+        * always produce enough margin between SDA and SCL transitions.
+        * Measurements show that the higher the module clock is, the
+        * bigger is the margin, providing more reliable communication.
+        * So we better target for 12MHz.
+        */
+       psc = (input_clock / 12000000) - 1;
        if ((input_clock / (psc + 1)) > 12000000)
                psc++;  /* better to run under spec than over */
        d = (psc >= 2) ? 5 : 7 - psc;
index 8c48b27ba05975e51a40ddaab979e7b23302e3e0..de7fbbb374cd34fce1cc8fffb11c45b21755bead 100644 (file)
@@ -813,6 +813,12 @@ static irqreturn_t i2c_dw_isr(int this_irq, void *dev_id)
 tx_aborted:
        if ((stat & (DW_IC_INTR_TX_ABRT | DW_IC_INTR_STOP_DET)) || dev->msg_err)
                complete(&dev->cmd_complete);
+       else if (unlikely(dev->accessor_flags & ACCESS_INTR_MASK)) {
+               /* workaround to trigger pending interrupt */
+               stat = dw_readl(dev, DW_IC_INTR_MASK);
+               i2c_dw_disable_int(dev);
+               dw_writel(dev, stat, DW_IC_INTR_MASK);
+       }
 
        return IRQ_HANDLED;
 }
index 1d50898e7b2403868c239f2ebc236a240a755bc7..9ffb63a60f95454ebbaf43f6a12bbe922de66179 100644 (file)
@@ -111,6 +111,7 @@ struct dw_i2c_dev {
 
 #define ACCESS_SWAP            0x00000001
 #define ACCESS_16BIT           0x00000002
+#define ACCESS_INTR_MASK       0x00000004
 
 extern int i2c_dw_init(struct dw_i2c_dev *dev);
 extern void i2c_dw_disable(struct dw_i2c_dev *dev);
index 809579ecb5a44fed6745af1274ed46864763651c..6b00061c37469b98613880ffe71d26118c76d92a 100644 (file)
@@ -93,6 +93,7 @@ static void dw_i2c_acpi_params(struct platform_device *pdev, char method[],
 static int dw_i2c_acpi_configure(struct platform_device *pdev)
 {
        struct dw_i2c_dev *dev = platform_get_drvdata(pdev);
+       const struct acpi_device_id *id;
 
        dev->adapter.nr = -1;
        dev->tx_fifo_depth = 32;
@@ -106,6 +107,10 @@ static int dw_i2c_acpi_configure(struct platform_device *pdev)
        dw_i2c_acpi_params(pdev, "FMCN", &dev->fs_hcnt, &dev->fs_lcnt,
                           &dev->sda_hold_time);
 
+       id = acpi_match_device(pdev->dev.driver->acpi_match_table, &pdev->dev);
+       if (id && id->driver_data)
+               dev->accessor_flags |= (u32)id->driver_data;
+
        return 0;
 }
 
@@ -116,7 +121,7 @@ static const struct acpi_device_id dw_i2c_acpi_match[] = {
        { "INT3433", 0 },
        { "80860F41", 0 },
        { "808622C1", 0 },
-       { "AMD0010", 0 },
+       { "AMD0010", ACCESS_INTR_MASK },
        { }
 };
 MODULE_DEVICE_TABLE(acpi, dw_i2c_acpi_match);
@@ -240,12 +245,10 @@ static int dw_i2c_plat_probe(struct platform_device *pdev)
        }
 
        r = i2c_dw_probe(dev);
-       if (r) {
+       if (r && !dev->pm_runtime_disabled)
                pm_runtime_disable(&pdev->dev);
-               return r;
-       }
 
-       return 0;
+       return r;
 }
 
 static int dw_i2c_plat_remove(struct platform_device *pdev)
@@ -260,7 +263,8 @@ static int dw_i2c_plat_remove(struct platform_device *pdev)
 
        pm_runtime_dont_use_autosuspend(&pdev->dev);
        pm_runtime_put_sync(&pdev->dev);
-       pm_runtime_disable(&pdev->dev);
+       if (!dev->pm_runtime_disabled)
+               pm_runtime_disable(&pdev->dev);
 
        return 0;
 }
index c306751ceadb44c24757b02281de24779038b1cb..f62d69799a9c55b0f79e2de5e29ec9a09b257c98 100644 (file)
@@ -62,6 +62,8 @@
  * Sunrise Point-LP (PCH)      0x9d23  32      hard    yes     yes     yes
  * DNV (SOC)                   0x19df  32      hard    yes     yes     yes
  * Broxton (SOC)               0x5ad4  32      hard    yes     yes     yes
+ * Lewisburg (PCH)             0xa1a3  32      hard    yes     yes     yes
+ * Lewisburg Supersku (PCH)    0xa223  32      hard    yes     yes     yes
  *
  * Features supported by this driver:
  * Software PEC                                no
 #define PCI_DEVICE_ID_INTEL_SUNRISEPOINT_LP_SMBUS      0x9d23
 #define PCI_DEVICE_ID_INTEL_DNV_SMBUS                  0x19df
 #define PCI_DEVICE_ID_INTEL_BROXTON_SMBUS              0x5ad4
+#define PCI_DEVICE_ID_INTEL_LEWISBURG_SMBUS            0xa1a3
+#define PCI_DEVICE_ID_INTEL_LEWISBURG_SSKU_SMBUS       0xa223
 
 struct i801_mux_config {
        char *gpio_chip;
@@ -869,6 +873,8 @@ static const struct pci_device_id i801_ids[] = {
        { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_SUNRISEPOINT_LP_SMBUS) },
        { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_DNV_SMBUS) },
        { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_BROXTON_SMBUS) },
+       { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_LEWISBURG_SMBUS) },
+       { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_LEWISBURG_SSKU_SMBUS) },
        { 0, }
 };
 
index 1e4d99da41646d98a85340369828bb262c77075f..d4d853680ae47881151effb56269e4e660d522e1 100644 (file)
@@ -50,6 +50,7 @@
 #include <linux/of_device.h>
 #include <linux/of_dma.h>
 #include <linux/of_gpio.h>
+#include <linux/pinctrl/consumer.h>
 #include <linux/platform_data/i2c-imx.h>
 #include <linux/platform_device.h>
 #include <linux/sched.h>
@@ -1118,6 +1119,8 @@ static int i2c_imx_probe(struct platform_device *pdev)
                        i2c_imx, IMX_I2C_I2CR);
        imx_i2c_write_reg(i2c_imx->hwdata->i2sr_clr_opcode, i2c_imx, IMX_I2C_I2SR);
 
+       i2c_imx_init_recovery_info(i2c_imx, pdev);
+
        /* Add I2C adapter */
        ret = i2c_add_numbered_adapter(&i2c_imx->adapter);
        if (ret < 0) {
@@ -1125,8 +1128,6 @@ static int i2c_imx_probe(struct platform_device *pdev)
                goto clk_disable;
        }
 
-       i2c_imx_init_recovery_info(i2c_imx, pdev);
-
        /* Set up platform driver data */
        platform_set_drvdata(pdev, i2c_imx);
        clk_disable_unprepare(i2c_imx->clk);
index 5801227b97ab089022f90608f6fc425ebd13cd87..43207f52e5a3733f5d405da921fb5d32b331321f 100644 (file)
@@ -146,6 +146,8 @@ struct mv64xxx_i2c_data {
        bool                    errata_delay;
        struct reset_control    *rstc;
        bool                    irq_clear_inverted;
+       /* Clk div is 2 to the power n, not 2 to the power n + 1 */
+       bool                    clk_n_base_0;
 };
 
 static struct mv64xxx_i2c_regs mv64xxx_i2c_regs_mv64xxx = {
@@ -757,25 +759,29 @@ MODULE_DEVICE_TABLE(of, mv64xxx_i2c_of_match_table);
 #ifdef CONFIG_OF
 #ifdef CONFIG_HAVE_CLK
 static int
-mv64xxx_calc_freq(const int tclk, const int n, const int m)
+mv64xxx_calc_freq(struct mv64xxx_i2c_data *drv_data,
+                 const int tclk, const int n, const int m)
 {
-       return tclk / (10 * (m + 1) * (2 << n));
+       if (drv_data->clk_n_base_0)
+               return tclk / (10 * (m + 1) * (1 << n));
+       else
+               return tclk / (10 * (m + 1) * (2 << n));
 }
 
 static bool
-mv64xxx_find_baud_factors(const u32 req_freq, const u32 tclk, u32 *best_n,
-                         u32 *best_m)
+mv64xxx_find_baud_factors(struct mv64xxx_i2c_data *drv_data,
+                         const u32 req_freq, const u32 tclk)
 {
        int freq, delta, best_delta = INT_MAX;
        int m, n;
 
        for (n = 0; n <= 7; n++)
                for (m = 0; m <= 15; m++) {
-                       freq = mv64xxx_calc_freq(tclk, n, m);
+                       freq = mv64xxx_calc_freq(drv_data, tclk, n, m);
                        delta = req_freq - freq;
                        if (delta >= 0 && delta < best_delta) {
-                               *best_m = m;
-                               *best_n = n;
+                               drv_data->freq_m = m;
+                               drv_data->freq_n = n;
                                best_delta = delta;
                        }
                        if (best_delta == 0)
@@ -813,8 +819,11 @@ mv64xxx_of_config(struct mv64xxx_i2c_data *drv_data,
        if (of_property_read_u32(np, "clock-frequency", &bus_freq))
                bus_freq = 100000; /* 100kHz by default */
 
-       if (!mv64xxx_find_baud_factors(bus_freq, tclk,
-                                      &drv_data->freq_n, &drv_data->freq_m)) {
+       if (of_device_is_compatible(np, "allwinner,sun4i-a10-i2c") ||
+           of_device_is_compatible(np, "allwinner,sun6i-a31-i2c"))
+               drv_data->clk_n_base_0 = true;
+
+       if (!mv64xxx_find_baud_factors(drv_data, bus_freq, tclk)) {
                rc = -EINVAL;
                goto out;
        }
index b0ae560b38c308335229f0f9b2317f0361b6b8a3..599c0d7bd906d19afc89417afc74d939e6985252 100644 (file)
@@ -576,7 +576,7 @@ static int rcar_reg_slave(struct i2c_client *slave)
        if (slave->flags & I2C_CLIENT_TEN)
                return -EAFNOSUPPORT;
 
-       pm_runtime_forbid(rcar_i2c_priv_to_dev(priv));
+       pm_runtime_get_sync(rcar_i2c_priv_to_dev(priv));
 
        priv->slave = slave;
        rcar_i2c_write(priv, ICSAR, slave->addr);
@@ -598,7 +598,7 @@ static int rcar_unreg_slave(struct i2c_client *slave)
 
        priv->slave = NULL;
 
-       pm_runtime_allow(rcar_i2c_priv_to_dev(priv));
+       pm_runtime_put(rcar_i2c_priv_to_dev(priv));
 
        return 0;
 }
index c1935ebd6a9c38971b6539cc1d1ae03dfc276d17..9096d17beb5bb002d914010a77f156a3f3f97f32 100644 (file)
@@ -908,7 +908,7 @@ static int rk3x_i2c_probe(struct platform_device *pdev)
                                 &i2c->scl_fall_ns))
                i2c->scl_fall_ns = 300;
        if (of_property_read_u32(pdev->dev.of_node, "i2c-sda-falling-time-ns",
-                                &i2c->scl_fall_ns))
+                                &i2c->sda_fall_ns))
                i2c->sda_fall_ns = i2c->scl_fall_ns;
 
        strlcpy(i2c->adap.name, "rk3x-i2c", sizeof(i2c->adap.name));
index ea72dca32fdfde83cfdd223525a915a5721d6816..25020ec777c9783bf5c62853051707bace5c4483 100644 (file)
@@ -822,7 +822,7 @@ static int st_i2c_probe(struct platform_device *pdev)
 
        adap = &i2c_dev->adap;
        i2c_set_adapdata(adap, i2c_dev);
-       snprintf(adap->name, sizeof(adap->name), "ST I2C(0x%pa)", &res->start);
+       snprintf(adap->name, sizeof(adap->name), "ST I2C(%pa)", &res->start);
        adap->owner = THIS_MODULE;
        adap->timeout = 2 * HZ;
        adap->retries = 0;
index e23a7b068c601906bb1b245d637b0413c2b2c29f..0b20449e48cfe84bba9a7954c641f72be236e5dc 100644 (file)
@@ -662,8 +662,10 @@ static void __xiic_start_xfer(struct xiic_i2c *i2c)
 
 static void xiic_start_xfer(struct xiic_i2c *i2c)
 {
-
+       spin_lock(&i2c->lock);
+       xiic_reinit(i2c);
        __xiic_start_xfer(i2c);
+       spin_unlock(&i2c->lock);
 }
 
 static int xiic_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
index 040af5cc8143f1aff2ce8ebaf0143482ddfeee02..ba8eb087f224655d1853c1192371759cf4d5e9f0 100644 (file)
@@ -715,7 +715,7 @@ static int i2c_device_probe(struct device *dev)
                if (wakeirq > 0 && wakeirq != client->irq)
                        status = dev_pm_set_dedicated_wake_irq(dev, wakeirq);
                else if (client->irq > 0)
-                       status = dev_pm_set_wake_irq(dev, wakeirq);
+                       status = dev_pm_set_wake_irq(dev, client->irq);
                else
                        status = 0;
 
index eea0c79111e7c7e2beb6be21cda21d597833e793..4d960d3b93c0b45c70183ed5f4a218649d0dfb87 100644 (file)
 #define AD7795_CH_AIN1M_AIN1M  8 /* AIN1(-) - AIN1(-) */
 
 /* ID Register Bit Designations (AD7793_REG_ID) */
-#define AD7785_ID              0xB
+#define AD7785_ID              0x3
 #define AD7792_ID              0xA
 #define AD7793_ID              0xB
 #define AD7794_ID              0xF
index 0c4618b4d51549cb7bfe8fead1e3ce61c1882366..c2babe50a0d8f59464f8b77837132192e70e3726 100644 (file)
@@ -839,8 +839,10 @@ static int vadc_get_dt_data(struct vadc_priv *vadc, struct device_node *node)
 
        for_each_available_child_of_node(node, child) {
                ret = vadc_get_dt_channel_data(vadc->dev, &prop, child);
-               if (ret)
+               if (ret) {
+                       of_node_put(child);
                        return ret;
+               }
 
                vadc->chan_props[index] = prop;
 
index 599cde3d03a117358f86defec5dcd10ac25b1ed7..b10f629cc44b5e8aa27b9bde4a5c39fbc3694a5e 100644 (file)
 
 #define DEFAULT_SAMPLE_TIME            1000
 
+/* V at 25°C of 696 mV */
+#define VF610_VTEMP25_3V0              950
+/* V at 25°C of 699 mV */
+#define VF610_VTEMP25_3V3              867
+/* Typical sensor slope coefficient at all temperatures */
+#define VF610_TEMP_SLOPE_COEFF         1840
+
 enum clk_sel {
        VF610_ADCIOC_BUSCLK_SET,
        VF610_ADCIOC_ALTCLK_SET,
@@ -197,6 +204,8 @@ static inline void vf610_adc_calculate_rates(struct vf610_adc *info)
                adc_feature->clk_div = 8;
        }
 
+       adck_rate = ipg_rate / adc_feature->clk_div;
+
        /*
         * Determine the long sample time adder value to be used based
         * on the default minimum sample time provided.
@@ -221,7 +230,6 @@ static inline void vf610_adc_calculate_rates(struct vf610_adc *info)
         * BCT (Base Conversion Time): fixed to 25 ADCK cycles for 12 bit mode
         * LSTAdder(Long Sample Time): 3, 5, 7, 9, 13, 17, 21, 25 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] *
@@ -663,11 +671,13 @@ static int vf610_read_raw(struct iio_dev *indio_dev,
                        break;
                case IIO_TEMP:
                        /*
-                       * Calculate in degree Celsius times 1000
-                       * Using sensor slope of 1.84 mV/°C and
-                       * V at 25°C of 696 mV
-                       */
-                       *val = 25000 - ((int)info->value - 864) * 1000000 / 1840;
+                        * Calculate in degree Celsius times 1000
+                        * Using the typical sensor slope of 1.84 mV/°C
+                        * and VREFH_ADC at 3.3V, V at 25°C of 699 mV
+                        */
+                       *val = 25000 - ((int)info->value - VF610_VTEMP25_3V3) *
+                                       1000000 / VF610_TEMP_SLOPE_COEFF;
+
                        break;
                default:
                        mutex_unlock(&indio_dev->mlock);
index 0370624a35db723a6b6089c99398cca36fc10590..02e636a1c49a7a17bbb2cd19356301c41781710f 100644 (file)
@@ -841,6 +841,7 @@ static int xadc_read_raw(struct iio_dev *indio_dev,
                        case XADC_REG_VCCINT:
                        case XADC_REG_VCCAUX:
                        case XADC_REG_VREFP:
+                       case XADC_REG_VREFN:
                        case XADC_REG_VCCBRAM:
                        case XADC_REG_VCCPINT:
                        case XADC_REG_VCCPAUX:
index 9e4d2c18b5541b2043e244229aeb393e79e737d4..81ca0081a019b355ce58ce26bf9370c84d48fb7b 100644 (file)
@@ -113,12 +113,16 @@ enum ad5064_type {
        ID_AD5065,
        ID_AD5628_1,
        ID_AD5628_2,
+       ID_AD5629_1,
+       ID_AD5629_2,
        ID_AD5648_1,
        ID_AD5648_2,
        ID_AD5666_1,
        ID_AD5666_2,
        ID_AD5668_1,
        ID_AD5668_2,
+       ID_AD5669_1,
+       ID_AD5669_2,
 };
 
 static int ad5064_write(struct ad5064_state *st, unsigned int cmd,
@@ -291,7 +295,7 @@ static const struct iio_chan_spec_ext_info ad5064_ext_info[] = {
        { },
 };
 
-#define AD5064_CHANNEL(chan, addr, bits) {                     \
+#define AD5064_CHANNEL(chan, addr, bits, _shift) {             \
        .type = IIO_VOLTAGE,                                    \
        .indexed = 1,                                           \
        .output = 1,                                            \
@@ -303,36 +307,39 @@ static const struct iio_chan_spec_ext_info ad5064_ext_info[] = {
                .sign = 'u',                                    \
                .realbits = (bits),                             \
                .storagebits = 16,                              \
-               .shift = 20 - bits,                             \
+               .shift = (_shift),                              \
        },                                                      \
        .ext_info = ad5064_ext_info,                            \
 }
 
-#define DECLARE_AD5064_CHANNELS(name, bits) \
+#define DECLARE_AD5064_CHANNELS(name, bits, shift) \
 const struct iio_chan_spec name[] = { \
-       AD5064_CHANNEL(0, 0, bits), \
-       AD5064_CHANNEL(1, 1, bits), \
-       AD5064_CHANNEL(2, 2, bits), \
-       AD5064_CHANNEL(3, 3, bits), \
-       AD5064_CHANNEL(4, 4, bits), \
-       AD5064_CHANNEL(5, 5, bits), \
-       AD5064_CHANNEL(6, 6, bits), \
-       AD5064_CHANNEL(7, 7, bits), \
+       AD5064_CHANNEL(0, 0, bits, shift), \
+       AD5064_CHANNEL(1, 1, bits, shift), \
+       AD5064_CHANNEL(2, 2, bits, shift), \
+       AD5064_CHANNEL(3, 3, bits, shift), \
+       AD5064_CHANNEL(4, 4, bits, shift), \
+       AD5064_CHANNEL(5, 5, bits, shift), \
+       AD5064_CHANNEL(6, 6, bits, shift), \
+       AD5064_CHANNEL(7, 7, bits, shift), \
 }
 
-#define DECLARE_AD5065_CHANNELS(name, bits) \
+#define DECLARE_AD5065_CHANNELS(name, bits, shift) \
 const struct iio_chan_spec name[] = { \
-       AD5064_CHANNEL(0, 0, bits), \
-       AD5064_CHANNEL(1, 3, bits), \
+       AD5064_CHANNEL(0, 0, bits, shift), \
+       AD5064_CHANNEL(1, 3, bits, shift), \
 }
 
-static DECLARE_AD5064_CHANNELS(ad5024_channels, 12);
-static DECLARE_AD5064_CHANNELS(ad5044_channels, 14);
-static DECLARE_AD5064_CHANNELS(ad5064_channels, 16);
+static DECLARE_AD5064_CHANNELS(ad5024_channels, 12, 8);
+static DECLARE_AD5064_CHANNELS(ad5044_channels, 14, 6);
+static DECLARE_AD5064_CHANNELS(ad5064_channels, 16, 4);
 
-static DECLARE_AD5065_CHANNELS(ad5025_channels, 12);
-static DECLARE_AD5065_CHANNELS(ad5045_channels, 14);
-static DECLARE_AD5065_CHANNELS(ad5065_channels, 16);
+static DECLARE_AD5065_CHANNELS(ad5025_channels, 12, 8);
+static DECLARE_AD5065_CHANNELS(ad5045_channels, 14, 6);
+static DECLARE_AD5065_CHANNELS(ad5065_channels, 16, 4);
+
+static DECLARE_AD5064_CHANNELS(ad5629_channels, 12, 4);
+static DECLARE_AD5064_CHANNELS(ad5669_channels, 16, 0);
 
 static const struct ad5064_chip_info ad5064_chip_info_tbl[] = {
        [ID_AD5024] = {
@@ -382,6 +389,18 @@ static const struct ad5064_chip_info ad5064_chip_info_tbl[] = {
                .channels = ad5024_channels,
                .num_channels = 8,
        },
+       [ID_AD5629_1] = {
+               .shared_vref = true,
+               .internal_vref = 2500000,
+               .channels = ad5629_channels,
+               .num_channels = 8,
+       },
+       [ID_AD5629_2] = {
+               .shared_vref = true,
+               .internal_vref = 5000000,
+               .channels = ad5629_channels,
+               .num_channels = 8,
+       },
        [ID_AD5648_1] = {
                .shared_vref = true,
                .internal_vref = 2500000,
@@ -418,6 +437,18 @@ static const struct ad5064_chip_info ad5064_chip_info_tbl[] = {
                .channels = ad5064_channels,
                .num_channels = 8,
        },
+       [ID_AD5669_1] = {
+               .shared_vref = true,
+               .internal_vref = 2500000,
+               .channels = ad5669_channels,
+               .num_channels = 8,
+       },
+       [ID_AD5669_2] = {
+               .shared_vref = true,
+               .internal_vref = 5000000,
+               .channels = ad5669_channels,
+               .num_channels = 8,
+       },
 };
 
 static inline unsigned int ad5064_num_vref(struct ad5064_state *st)
@@ -597,10 +628,16 @@ static int ad5064_i2c_write(struct ad5064_state *st, unsigned int cmd,
        unsigned int addr, unsigned int val)
 {
        struct i2c_client *i2c = to_i2c_client(st->dev);
+       int ret;
 
        st->data.i2c[0] = (cmd << 4) | addr;
        put_unaligned_be16(val, &st->data.i2c[1]);
-       return i2c_master_send(i2c, st->data.i2c, 3);
+
+       ret = i2c_master_send(i2c, st->data.i2c, 3);
+       if (ret < 0)
+               return ret;
+
+       return 0;
 }
 
 static int ad5064_i2c_probe(struct i2c_client *i2c,
@@ -616,12 +653,12 @@ static int ad5064_i2c_remove(struct i2c_client *i2c)
 }
 
 static const struct i2c_device_id ad5064_i2c_ids[] = {
-       {"ad5629-1", ID_AD5628_1},
-       {"ad5629-2", ID_AD5628_2},
-       {"ad5629-3", ID_AD5628_2}, /* similar enough to ad5629-2 */
-       {"ad5669-1", ID_AD5668_1},
-       {"ad5669-2", ID_AD5668_2},
-       {"ad5669-3", ID_AD5668_2}, /* similar enough to ad5669-2 */
+       {"ad5629-1", ID_AD5629_1},
+       {"ad5629-2", ID_AD5629_2},
+       {"ad5629-3", ID_AD5629_2}, /* similar enough to ad5629-2 */
+       {"ad5669-1", ID_AD5669_1},
+       {"ad5669-2", ID_AD5669_2},
+       {"ad5669-3", ID_AD5669_2}, /* similar enough to ad5669-2 */
        {}
 };
 MODULE_DEVICE_TABLE(i2c, ad5064_i2c_ids);
index 12128d1ca570fc4dd93461219628b6ab6461d95d..71991b5c0658d05fe728f797573b08843e51d9ad 100644 (file)
@@ -50,10 +50,10 @@ static int si7020_read_raw(struct iio_dev *indio_dev,
 
        switch (mask) {
        case IIO_CHAN_INFO_RAW:
-               ret = i2c_smbus_read_word_data(*client,
-                                              chan->type == IIO_TEMP ?
-                                              SI7020CMD_TEMP_HOLD :
-                                              SI7020CMD_RH_HOLD);
+               ret = i2c_smbus_read_word_swapped(*client,
+                                                 chan->type == IIO_TEMP ?
+                                                 SI7020CMD_TEMP_HOLD :
+                                                 SI7020CMD_RH_HOLD);
                if (ret < 0)
                        return ret;
                *val = ret >> 2;
index d7e908acb48020b3f5390030e5a3687b03ba9878..0f6f63b2026379ffd968a764e3309f8fb792eda5 100644 (file)
@@ -302,7 +302,7 @@ static int iio_scan_mask_set(struct iio_dev *indio_dev,
        if (trialmask == NULL)
                return -ENOMEM;
        if (!indio_dev->masklength) {
-               WARN_ON("Trying to set scanmask prior to registering buffer\n");
+               WARN(1, "Trying to set scanmask prior to registering buffer\n");
                goto err_invalid_mask;
        }
        bitmap_copy(trialmask, buffer->scan_mask, indio_dev->masklength);
index 208358f9e7e36582152cad8c4f4924d9667a58cc..159ede61f79318d4ee8e581a8a61df2028680aba 100644 (file)
@@ -655,7 +655,7 @@ int __iio_device_attr_init(struct device_attribute *dev_attr,
                        break;
                case IIO_SEPARATE:
                        if (!chan->indexed) {
-                               WARN_ON("Differential channels must be indexed\n");
+                               WARN(1, "Differential channels must be indexed\n");
                                ret = -EINVAL;
                                goto error_free_full_postfix;
                        }
index 7d269ef9e0625a81cdf1832c53667e9ed1039f18..f6a07dc32ae486a045b97cfb4406783a9aa05ab8 100644 (file)
@@ -453,6 +453,7 @@ static int apds9960_set_power_state(struct apds9960_data *data, bool on)
                        usleep_range(data->als_adc_int_us,
                                     APDS9960_MAX_INT_TIME_IN_US);
        } else {
+               pm_runtime_mark_last_busy(dev);
                ret = pm_runtime_put_autosuspend(dev);
        }
 
index 961f9f990faffa67fccf54dfa01118ce4339f3b9..e544fcfd5cedf4f3a1d806204b7bcdfbe0d0deb3 100644 (file)
@@ -130,10 +130,10 @@ static int lidar_get_measurement(struct lidar_data *data, u16 *reg)
                if (ret < 0)
                        break;
 
-               /* return 0 since laser is likely pointed out of range */
+               /* return -EINVAL since laser is likely pointed out of range */
                if (ret & LIDAR_REG_STATUS_INVALID) {
                        *reg = 0;
-                       ret = 0;
+                       ret = -EINVAL;
                        break;
                }
 
@@ -197,7 +197,7 @@ static irqreturn_t lidar_trigger_handler(int irq, void *private)
        if (!ret) {
                iio_push_to_buffers_with_timestamp(indio_dev, data->buffer,
                                                   iio_get_time_ns());
-       } else {
+       } else if (ret != -EINVAL) {
                dev_err(&data->client->dev, "cannot read LIDAR measurement");
        }
 
index 944cd90417bcc9b2a51d27f903feffad6f2307ea..2d762a2ecd81252cde34cbc2dbc1083c1d8832dc 100644 (file)
@@ -1126,10 +1126,7 @@ static bool validate_ipv4_net_dev(struct net_device *net_dev,
 
        rcu_read_lock();
        err = fib_lookup(dev_net(net_dev), &fl4, &res, 0);
-       if (err)
-               return false;
-
-       ret = FIB_RES_DEV(res) == net_dev;
+       ret = err == 0 && FIB_RES_DEV(res) == net_dev;
        rcu_read_unlock();
 
        return ret;
@@ -1268,15 +1265,17 @@ static bool cma_protocol_roce(const struct rdma_cm_id *id)
        return cma_protocol_roce_dev_port(device, port_num);
 }
 
-static bool cma_match_net_dev(const struct rdma_id_private *id_priv,
-                             const struct net_device *net_dev)
+static bool cma_match_net_dev(const struct rdma_cm_id *id,
+                             const struct net_device *net_dev,
+                             u8 port_num)
 {
-       const struct rdma_addr *addr = &id_priv->id.route.addr;
+       const struct rdma_addr *addr = &id->route.addr;
 
        if (!net_dev)
                /* This request is an AF_IB request or a RoCE request */
-               return addr->src_addr.ss_family == AF_IB ||
-                      cma_protocol_roce(&id_priv->id);
+               return (!id->port_num || id->port_num == port_num) &&
+                      (addr->src_addr.ss_family == AF_IB ||
+                       cma_protocol_roce_dev_port(id->device, port_num));
 
        return !addr->dev_addr.bound_dev_if ||
               (net_eq(dev_net(net_dev), addr->dev_addr.net) &&
@@ -1298,13 +1297,13 @@ static struct rdma_id_private *cma_find_listener(
        hlist_for_each_entry(id_priv, &bind_list->owners, node) {
                if (cma_match_private_data(id_priv, ib_event->private_data)) {
                        if (id_priv->id.device == cm_id->device &&
-                           cma_match_net_dev(id_priv, net_dev))
+                           cma_match_net_dev(&id_priv->id, net_dev, req->port))
                                return id_priv;
                        list_for_each_entry(id_priv_dev,
                                            &id_priv->listen_list,
                                            listen_list) {
                                if (id_priv_dev->id.device == cm_id->device &&
-                                   cma_match_net_dev(id_priv_dev, net_dev))
+                                   cma_match_net_dev(&id_priv_dev->id, net_dev, req->port))
                                        return id_priv_dev;
                        }
                }
index 8d8af7a41a30fae4ceb520ce0d11b6f541905c96..2281de122038e45a5c375f7d7669111ab2aee2de 100644 (file)
@@ -1811,6 +1811,11 @@ static int validate_mad(const struct ib_mad_hdr *mad_hdr,
                if (qp_num == 0)
                        valid = 1;
        } else {
+               /* CM attributes other than ClassPortInfo only use Send method */
+               if ((mad_hdr->mgmt_class == IB_MGMT_CLASS_CM) &&
+                   (mad_hdr->attr_id != IB_MGMT_CLASSPORTINFO_ATTR_ID) &&
+                   (mad_hdr->method != IB_MGMT_METHOD_SEND))
+                       goto out;
                /* Filter GSI packets sent to QP0 */
                if (qp_num != 0)
                        valid = 1;
index 2aba774f835b9caca8e9e1645d1efd6cf6f08bf9..a95a32ba596edc03728cf7790a6752c951cde951 100644 (file)
@@ -512,7 +512,7 @@ static int ib_nl_get_path_rec_attrs_len(ib_sa_comp_mask comp_mask)
        return len;
 }
 
-static int ib_nl_send_msg(struct ib_sa_query *query)
+static int ib_nl_send_msg(struct ib_sa_query *query, gfp_t gfp_mask)
 {
        struct sk_buff *skb = NULL;
        struct nlmsghdr *nlh;
@@ -526,7 +526,7 @@ static int ib_nl_send_msg(struct ib_sa_query *query)
        if (len <= 0)
                return -EMSGSIZE;
 
-       skb = nlmsg_new(len, GFP_KERNEL);
+       skb = nlmsg_new(len, gfp_mask);
        if (!skb)
                return -ENOMEM;
 
@@ -544,7 +544,7 @@ static int ib_nl_send_msg(struct ib_sa_query *query)
        /* Repair the nlmsg header length */
        nlmsg_end(skb, nlh);
 
-       ret = ibnl_multicast(skb, nlh, RDMA_NL_GROUP_LS, GFP_KERNEL);
+       ret = ibnl_multicast(skb, nlh, RDMA_NL_GROUP_LS, gfp_mask);
        if (!ret)
                ret = len;
        else
@@ -553,7 +553,7 @@ static int ib_nl_send_msg(struct ib_sa_query *query)
        return ret;
 }
 
-static int ib_nl_make_request(struct ib_sa_query *query)
+static int ib_nl_make_request(struct ib_sa_query *query, gfp_t gfp_mask)
 {
        unsigned long flags;
        unsigned long delay;
@@ -562,25 +562,27 @@ static int ib_nl_make_request(struct ib_sa_query *query)
        INIT_LIST_HEAD(&query->list);
        query->seq = (u32)atomic_inc_return(&ib_nl_sa_request_seq);
 
+       /* Put the request on the list first.*/
        spin_lock_irqsave(&ib_nl_request_lock, flags);
-       ret = ib_nl_send_msg(query);
-       if (ret <= 0) {
-               ret = -EIO;
-               goto request_out;
-       } else {
-               ret = 0;
-       }
-
        delay = msecs_to_jiffies(sa_local_svc_timeout_ms);
        query->timeout = delay + jiffies;
        list_add_tail(&query->list, &ib_nl_request_list);
        /* Start the timeout if this is the only request */
        if (ib_nl_request_list.next == &query->list)
                queue_delayed_work(ib_nl_wq, &ib_nl_timed_work, delay);
-
-request_out:
        spin_unlock_irqrestore(&ib_nl_request_lock, flags);
 
+       ret = ib_nl_send_msg(query, gfp_mask);
+       if (ret <= 0) {
+               ret = -EIO;
+               /* Remove the request */
+               spin_lock_irqsave(&ib_nl_request_lock, flags);
+               list_del(&query->list);
+               spin_unlock_irqrestore(&ib_nl_request_lock, flags);
+       } else {
+               ret = 0;
+       }
+
        return ret;
 }
 
@@ -1108,7 +1110,7 @@ static int send_mad(struct ib_sa_query *query, int timeout_ms, gfp_t gfp_mask)
 
        if (query->flags & IB_SA_ENABLE_LOCAL_SERVICE) {
                if (!ibnl_chk_listeners(RDMA_NL_GROUP_LS)) {
-                       if (!ib_nl_make_request(query))
+                       if (!ib_nl_make_request(query, gfp_mask))
                                return id;
                }
                ib_sa_disable_local_svc(query);
index 94816aeb95a0a186760fbe98de55edc69266a54c..1c02deab068fbf1031d5b21db960feb9b06865c5 100644 (file)
@@ -62,9 +62,11 @@ static struct uverbs_lock_class rule_lock_class = { .name = "RULE-uobj" };
  * The ib_uobject locking scheme is as follows:
  *
  * - ib_uverbs_idr_lock protects the uverbs idrs themselves, so it
- *   needs to be held during all idr operations.  When an object is
+ *   needs to be held during all idr write operations.  When an object is
  *   looked up, a reference must be taken on the object's kref before
- *   dropping this lock.
+ *   dropping this lock.  For read operations, the rcu_read_lock()
+ *   and rcu_write_lock() but similarly the kref reference is grabbed
+ *   before the rcu_read_unlock().
  *
  * - Each object also has an rwsem.  This rwsem must be held for
  *   reading while an operation that uses the object is performed.
@@ -96,7 +98,7 @@ static void init_uobj(struct ib_uobject *uobj, u64 user_handle,
 
 static void release_uobj(struct kref *kref)
 {
-       kfree(container_of(kref, struct ib_uobject, ref));
+       kfree_rcu(container_of(kref, struct ib_uobject, ref), rcu);
 }
 
 static void put_uobj(struct ib_uobject *uobj)
@@ -145,7 +147,7 @@ static struct ib_uobject *__idr_get_uobj(struct idr *idr, int id,
 {
        struct ib_uobject *uobj;
 
-       spin_lock(&ib_uverbs_idr_lock);
+       rcu_read_lock();
        uobj = idr_find(idr, id);
        if (uobj) {
                if (uobj->context == context)
@@ -153,7 +155,7 @@ static struct ib_uobject *__idr_get_uobj(struct idr *idr, int id,
                else
                        uobj = NULL;
        }
-       spin_unlock(&ib_uverbs_idr_lock);
+       rcu_read_unlock();
 
        return uobj;
 }
@@ -2446,6 +2448,7 @@ ssize_t ib_uverbs_post_send(struct ib_uverbs_file *file,
        int                             i, sg_ind;
        int                             is_ud;
        ssize_t                         ret = -EINVAL;
+       size_t                          next_size;
 
        if (copy_from_user(&cmd, buf, sizeof cmd))
                return -EFAULT;
@@ -2490,7 +2493,8 @@ ssize_t ib_uverbs_post_send(struct ib_uverbs_file *file,
                                goto out_put;
                        }
 
-                       ud = alloc_wr(sizeof(*ud), user_wr->num_sge);
+                       next_size = sizeof(*ud);
+                       ud = alloc_wr(next_size, user_wr->num_sge);
                        if (!ud) {
                                ret = -ENOMEM;
                                goto out_put;
@@ -2511,7 +2515,8 @@ ssize_t ib_uverbs_post_send(struct ib_uverbs_file *file,
                           user_wr->opcode == IB_WR_RDMA_READ) {
                        struct ib_rdma_wr *rdma;
 
-                       rdma = alloc_wr(sizeof(*rdma), user_wr->num_sge);
+                       next_size = sizeof(*rdma);
+                       rdma = alloc_wr(next_size, user_wr->num_sge);
                        if (!rdma) {
                                ret = -ENOMEM;
                                goto out_put;
@@ -2525,7 +2530,8 @@ ssize_t ib_uverbs_post_send(struct ib_uverbs_file *file,
                           user_wr->opcode == IB_WR_ATOMIC_FETCH_AND_ADD) {
                        struct ib_atomic_wr *atomic;
 
-                       atomic = alloc_wr(sizeof(*atomic), user_wr->num_sge);
+                       next_size = sizeof(*atomic);
+                       atomic = alloc_wr(next_size, user_wr->num_sge);
                        if (!atomic) {
                                ret = -ENOMEM;
                                goto out_put;
@@ -2540,7 +2546,8 @@ ssize_t ib_uverbs_post_send(struct ib_uverbs_file *file,
                } else if (user_wr->opcode == IB_WR_SEND ||
                           user_wr->opcode == IB_WR_SEND_WITH_IMM ||
                           user_wr->opcode == IB_WR_SEND_WITH_INV) {
-                       next = alloc_wr(sizeof(*next), user_wr->num_sge);
+                       next_size = sizeof(*next);
+                       next = alloc_wr(next_size, user_wr->num_sge);
                        if (!next) {
                                ret = -ENOMEM;
                                goto out_put;
@@ -2572,7 +2579,7 @@ ssize_t ib_uverbs_post_send(struct ib_uverbs_file *file,
 
                if (next->num_sge) {
                        next->sg_list = (void *) next +
-                               ALIGN(sizeof *next, sizeof (struct ib_sge));
+                               ALIGN(next_size, sizeof(struct ib_sge));
                        if (copy_from_user(next->sg_list,
                                           buf + sizeof cmd +
                                           cmd.wr_count * cmd.wqe_size +
index 043a60ee6836db72e498410ebd80e004ed220c7d..545906dec26dc5e936df37c635c68b94bb27e226 100644 (file)
@@ -1516,7 +1516,7 @@ EXPORT_SYMBOL(ib_map_mr_sg);
  * @sg_nents:      number of entries in sg
  * @set_page:      driver page assignment function pointer
  *
- * Core service helper for drivers to covert the largest
+ * Core service helper for drivers to convert the largest
  * prefix of given sg list to a page vector. The sg list
  * prefix converted is the prefix that meet the requirements
  * of ib_map_mr_sg.
@@ -1533,7 +1533,7 @@ int ib_sg_to_pages(struct ib_mr *mr,
        u64 last_end_dma_addr = 0, last_page_addr = 0;
        unsigned int last_page_off = 0;
        u64 page_mask = ~((u64)mr->page_size - 1);
-       int i;
+       int i, ret;
 
        mr->iova = sg_dma_address(&sgl[0]);
        mr->length = 0;
@@ -1544,27 +1544,29 @@ int ib_sg_to_pages(struct ib_mr *mr,
                u64 end_dma_addr = dma_addr + dma_len;
                u64 page_addr = dma_addr & page_mask;
 
-               if (i && page_addr != dma_addr) {
-                       if (last_end_dma_addr != dma_addr) {
-                               /* gap */
-                               goto done;
-
-                       } else if (last_page_off + dma_len <= mr->page_size) {
-                               /* chunk this fragment with the last */
-                               mr->length += dma_len;
-                               last_end_dma_addr += dma_len;
-                               last_page_off += dma_len;
-                               continue;
-                       } else {
-                               /* map starting from the next page */
-                               page_addr = last_page_addr + mr->page_size;
-                               dma_len -= mr->page_size - last_page_off;
-                       }
+               /*
+                * For the second and later elements, check whether either the
+                * end of element i-1 or the start of element i is not aligned
+                * on a page boundary.
+                */
+               if (i && (last_page_off != 0 || page_addr != dma_addr)) {
+                       /* Stop mapping if there is a gap. */
+                       if (last_end_dma_addr != dma_addr)
+                               break;
+
+                       /*
+                        * Coalesce this element with the last. If it is small
+                        * enough just update mr->length. Otherwise start
+                        * mapping from the next page.
+                        */
+                       goto next_page;
                }
 
                do {
-                       if (unlikely(set_page(mr, page_addr)))
-                               goto done;
+                       ret = set_page(mr, page_addr);
+                       if (unlikely(ret < 0))
+                               return i ? : ret;
+next_page:
                        page_addr += mr->page_size;
                } while (page_addr < end_dma_addr);
 
@@ -1574,7 +1576,6 @@ int ib_sg_to_pages(struct ib_mr *mr,
                last_page_off = end_dma_addr & ~page_mask;
        }
 
-done:
        return i;
 }
 EXPORT_SYMBOL(ib_sg_to_pages);
index f567160a4a56ed141320b2d153d21f2031cbb464..97d6878f993828085a0f26f941572674ce68b967 100644 (file)
@@ -456,7 +456,7 @@ static int mlx4_ib_query_device(struct ib_device *ibdev,
        props->max_qp_wr           = dev->dev->caps.max_wqes - MLX4_IB_SQ_MAX_SPARE;
        props->max_sge             = min(dev->dev->caps.max_sq_sg,
                                         dev->dev->caps.max_rq_sg);
-       props->max_sge_rd = props->max_sge;
+       props->max_sge_rd          = MLX4_MAX_SGE_RD;
        props->max_cq              = dev->dev->quotas.cq;
        props->max_cqe             = dev->dev->caps.max_cqes;
        props->max_mr              = dev->dev->quotas.mpt;
index a2e4ca56da44e5d9cec5ee4b6a02cf6ab9d7356c..13eaaf45288f80d4bb6658d5a18985a978e8c98d 100644 (file)
@@ -34,6 +34,7 @@
 #include <linux/log2.h>
 #include <linux/slab.h>
 #include <linux/netdevice.h>
+#include <linux/vmalloc.h>
 
 #include <rdma/ib_cache.h>
 #include <rdma/ib_pack.h>
@@ -795,8 +796,14 @@ static int create_qp_common(struct mlx4_ib_dev *dev, struct ib_pd *pd,
                if (err)
                        goto err_mtt;
 
-               qp->sq.wrid  = kmalloc(qp->sq.wqe_cnt * sizeof (u64), gfp);
-               qp->rq.wrid  = kmalloc(qp->rq.wqe_cnt * sizeof (u64), gfp);
+               qp->sq.wrid = kmalloc(qp->sq.wqe_cnt * sizeof(u64), gfp);
+               if (!qp->sq.wrid)
+                       qp->sq.wrid = __vmalloc(qp->sq.wqe_cnt * sizeof(u64),
+                                               gfp, PAGE_KERNEL);
+               qp->rq.wrid = kmalloc(qp->rq.wqe_cnt * sizeof(u64), gfp);
+               if (!qp->rq.wrid)
+                       qp->rq.wrid = __vmalloc(qp->rq.wqe_cnt * sizeof(u64),
+                                               gfp, PAGE_KERNEL);
                if (!qp->sq.wrid || !qp->rq.wrid) {
                        err = -ENOMEM;
                        goto err_wrid;
@@ -886,8 +893,8 @@ err_wrid:
                if (qp_has_rq(init_attr))
                        mlx4_ib_db_unmap_user(to_mucontext(pd->uobject->context), &qp->db);
        } else {
-               kfree(qp->sq.wrid);
-               kfree(qp->rq.wrid);
+               kvfree(qp->sq.wrid);
+               kvfree(qp->rq.wrid);
        }
 
 err_mtt:
@@ -1062,8 +1069,8 @@ static void destroy_qp_common(struct mlx4_ib_dev *dev, struct mlx4_ib_qp *qp,
                                              &qp->db);
                ib_umem_release(qp->umem);
        } else {
-               kfree(qp->sq.wrid);
-               kfree(qp->rq.wrid);
+               kvfree(qp->sq.wrid);
+               kvfree(qp->rq.wrid);
                if (qp->mlx4_ib_qp_type & (MLX4_IB_QPT_PROXY_SMI_OWNER |
                    MLX4_IB_QPT_PROXY_SMI | MLX4_IB_QPT_PROXY_GSI))
                        free_proxy_bufs(&dev->ib_dev, qp);
index dce5dfe3a70ea957a6780eca47e0c15e0d054300..c394376ebe06f159aebca07ef899ef5933386713 100644 (file)
@@ -34,6 +34,7 @@
 #include <linux/mlx4/qp.h>
 #include <linux/mlx4/srq.h>
 #include <linux/slab.h>
+#include <linux/vmalloc.h>
 
 #include "mlx4_ib.h"
 #include "user.h"
@@ -172,8 +173,12 @@ struct ib_srq *mlx4_ib_create_srq(struct ib_pd *pd,
 
                srq->wrid = kmalloc(srq->msrq.max * sizeof (u64), GFP_KERNEL);
                if (!srq->wrid) {
-                       err = -ENOMEM;
-                       goto err_mtt;
+                       srq->wrid = __vmalloc(srq->msrq.max * sizeof(u64),
+                                             GFP_KERNEL, PAGE_KERNEL);
+                       if (!srq->wrid) {
+                               err = -ENOMEM;
+                               goto err_mtt;
+                       }
                }
        }
 
@@ -204,7 +209,7 @@ err_wrid:
        if (pd->uobject)
                mlx4_ib_db_unmap_user(to_mucontext(pd->uobject->context), &srq->db);
        else
-               kfree(srq->wrid);
+               kvfree(srq->wrid);
 
 err_mtt:
        mlx4_mtt_cleanup(dev->dev, &srq->mtt);
@@ -281,7 +286,7 @@ int mlx4_ib_destroy_srq(struct ib_srq *srq)
                mlx4_ib_db_unmap_user(to_mucontext(srq->uobject->context), &msrq->db);
                ib_umem_release(msrq->umem);
        } else {
-               kfree(msrq->wrid);
+               kvfree(msrq->wrid);
                mlx4_buf_free(dev->dev, msrq->msrq.max << msrq->msrq.wqe_shift,
                              &msrq->buf);
                mlx4_db_free(dev->dev, &msrq->db);
index ec8993a7b3beea5a91370c1f66979dae583f49d4..6000f7aeede94301cbb7c281bfaae26299770106 100644 (file)
@@ -381,7 +381,19 @@ static void __cache_work_func(struct mlx5_cache_ent *ent)
                        }
                }
        } else if (ent->cur > 2 * ent->limit) {
-               if (!someone_adding(cache) &&
+               /*
+                * The remove_keys() logic is performed as garbage collection
+                * task. Such task is intended to be run when no other active
+                * processes are running.
+                *
+                * The need_resched() will return TRUE if there are user tasks
+                * to be activated in near future.
+                *
+                * In such case, we don't execute remove_keys() and postpone
+                * the garbage collection work to try to run in next cycle,
+                * in order to free CPU resources to other tasks.
+                */
+               if (!need_resched() && !someone_adding(cache) &&
                    time_after(jiffies, cache->last_add + 300 * HZ)) {
                        remove_keys(dev, i, 1);
                        if (ent->cur > ent->limit)
index ae80590aabdf7db6df756c0ee07afa4721f6c37c..040bb8b5cb15a65c34b15ab67c3c5fe14e27524c 100644 (file)
@@ -232,6 +232,10 @@ struct phy_info {
        u16 interface_type;
 };
 
+enum ocrdma_flags {
+       OCRDMA_FLAGS_LINK_STATUS_INIT = 0x01
+};
+
 struct ocrdma_dev {
        struct ib_device ibdev;
        struct ocrdma_dev_attr attr;
@@ -287,6 +291,7 @@ struct ocrdma_dev {
        atomic_t update_sl;
        u16 pvid;
        u32 asic_id;
+       u32 flags;
 
        ulong last_stats_time;
        struct mutex stats_lock; /* provide synch for debugfs operations */
@@ -591,4 +596,9 @@ static inline u8 ocrdma_is_enabled_and_synced(u32 state)
                (state & OCRDMA_STATE_FLAG_SYNC);
 }
 
+static inline u8 ocrdma_get_ae_link_state(u32 ae_state)
+{
+       return ((ae_state & OCRDMA_AE_LSC_LS_MASK) >> OCRDMA_AE_LSC_LS_SHIFT);
+}
+
 #endif
index 30f67bebffa35742189c4fc08b91654f75bfdcfa..283ca842ff7498b308fcec85a1268dcb452d56b0 100644 (file)
@@ -579,6 +579,8 @@ static int ocrdma_mbx_create_mq(struct ocrdma_dev *dev,
 
        cmd->async_event_bitmap = BIT(OCRDMA_ASYNC_GRP5_EVE_CODE);
        cmd->async_event_bitmap |= BIT(OCRDMA_ASYNC_RDMA_EVE_CODE);
+       /* Request link events on this  MQ. */
+       cmd->async_event_bitmap |= BIT(OCRDMA_ASYNC_LINK_EVE_CODE);
 
        cmd->async_cqid_ringsize = cq->id;
        cmd->async_cqid_ringsize |= (ocrdma_encoded_q_len(mq->len) <<
@@ -819,20 +821,42 @@ static void ocrdma_process_grp5_aync(struct ocrdma_dev *dev,
        }
 }
 
+static void ocrdma_process_link_state(struct ocrdma_dev *dev,
+                                     struct ocrdma_ae_mcqe *cqe)
+{
+       struct ocrdma_ae_lnkst_mcqe *evt;
+       u8 lstate;
+
+       evt = (struct ocrdma_ae_lnkst_mcqe *)cqe;
+       lstate = ocrdma_get_ae_link_state(evt->speed_state_ptn);
+
+       if (!(lstate & OCRDMA_AE_LSC_LLINK_MASK))
+               return;
+
+       if (dev->flags & OCRDMA_FLAGS_LINK_STATUS_INIT)
+               ocrdma_update_link_state(dev, (lstate & OCRDMA_LINK_ST_MASK));
+}
+
 static void ocrdma_process_acqe(struct ocrdma_dev *dev, void *ae_cqe)
 {
        /* async CQE processing */
        struct ocrdma_ae_mcqe *cqe = ae_cqe;
        u32 evt_code = (cqe->valid_ae_event & OCRDMA_AE_MCQE_EVENT_CODE_MASK) >>
                        OCRDMA_AE_MCQE_EVENT_CODE_SHIFT;
-
-       if (evt_code == OCRDMA_ASYNC_RDMA_EVE_CODE)
+       switch (evt_code) {
+       case OCRDMA_ASYNC_LINK_EVE_CODE:
+               ocrdma_process_link_state(dev, cqe);
+               break;
+       case OCRDMA_ASYNC_RDMA_EVE_CODE:
                ocrdma_dispatch_ibevent(dev, cqe);
-       else if (evt_code == OCRDMA_ASYNC_GRP5_EVE_CODE)
+               break;
+       case OCRDMA_ASYNC_GRP5_EVE_CODE:
                ocrdma_process_grp5_aync(dev, cqe);
-       else
+               break;
+       default:
                pr_err("%s(%d) invalid evt code=0x%x\n", __func__,
                       dev->id, evt_code);
+       }
 }
 
 static void ocrdma_process_mcqe(struct ocrdma_dev *dev, struct ocrdma_mcqe *cqe)
@@ -1363,7 +1387,8 @@ mbx_err:
        return status;
 }
 
-int ocrdma_mbx_get_link_speed(struct ocrdma_dev *dev, u8 *lnk_speed)
+int ocrdma_mbx_get_link_speed(struct ocrdma_dev *dev, u8 *lnk_speed,
+                             u8 *lnk_state)
 {
        int status = -ENOMEM;
        struct ocrdma_get_link_speed_rsp *rsp;
@@ -1384,8 +1409,11 @@ int ocrdma_mbx_get_link_speed(struct ocrdma_dev *dev, u8 *lnk_speed)
                goto mbx_err;
 
        rsp = (struct ocrdma_get_link_speed_rsp *)cmd;
-       *lnk_speed = (rsp->pflt_pps_ld_pnum & OCRDMA_PHY_PS_MASK)
-                       >> OCRDMA_PHY_PS_SHIFT;
+       if (lnk_speed)
+               *lnk_speed = (rsp->pflt_pps_ld_pnum & OCRDMA_PHY_PS_MASK)
+                             >> OCRDMA_PHY_PS_SHIFT;
+       if (lnk_state)
+               *lnk_state = (rsp->res_lnk_st & OCRDMA_LINK_ST_MASK);
 
 mbx_err:
        kfree(cmd);
@@ -2515,9 +2543,10 @@ static int ocrdma_set_av_params(struct ocrdma_qp *qp,
        ocrdma_cpu_to_le32(&cmd->params.sgid[0], sizeof(cmd->params.sgid));
        cmd->params.vlan_dmac_b4_to_b5 = mac_addr[4] | (mac_addr[5] << 8);
 
-       if (vlan_id < 0x1000) {
-               if (dev->pfc_state) {
-                       vlan_id = 0;
+       if (vlan_id == 0xFFFF)
+               vlan_id = 0;
+       if (vlan_id || dev->pfc_state) {
+               if (!vlan_id) {
                        pr_err("ocrdma%d:Using VLAN with PFC is recommended\n",
                               dev->id);
                        pr_err("ocrdma%d:Using VLAN 0 for this connection\n",
index 7ed885c1851e28740b81a0588493c0d0ca92bc42..ebc1f442aec37aabd691d374deb3fdd41acc4302 100644 (file)
@@ -106,7 +106,8 @@ void ocrdma_ring_cq_db(struct ocrdma_dev *, u16 cq_id, bool armed,
                       bool solicited, u16 cqe_popped);
 
 /* verbs specific mailbox commands */
-int ocrdma_mbx_get_link_speed(struct ocrdma_dev *dev, u8 *lnk_speed);
+int ocrdma_mbx_get_link_speed(struct ocrdma_dev *dev, u8 *lnk_speed,
+                             u8 *lnk_st);
 int ocrdma_query_config(struct ocrdma_dev *,
                        struct ocrdma_mbx_query_config *config);
 
@@ -153,5 +154,6 @@ char *port_speed_string(struct ocrdma_dev *dev);
 void ocrdma_init_service_level(struct ocrdma_dev *);
 void ocrdma_alloc_pd_pool(struct ocrdma_dev *dev);
 void ocrdma_free_pd_range(struct ocrdma_dev *dev);
+void ocrdma_update_link_state(struct ocrdma_dev *dev, u8 lstate);
 
 #endif                         /* __OCRDMA_HW_H__ */
index 62b7009daa6c18a4d21002636637b5a2d258b231..3afb40b85159bd2c10559443536f83af5e4fa9ca 100644 (file)
@@ -290,6 +290,7 @@ static void ocrdma_remove_sysfiles(struct ocrdma_dev *dev)
 static struct ocrdma_dev *ocrdma_add(struct be_dev_info *dev_info)
 {
        int status = 0, i;
+       u8 lstate = 0;
        struct ocrdma_dev *dev;
 
        dev = (struct ocrdma_dev *)ib_alloc_device(sizeof(struct ocrdma_dev));
@@ -319,6 +320,11 @@ static struct ocrdma_dev *ocrdma_add(struct be_dev_info *dev_info)
        if (status)
                goto alloc_err;
 
+       /* Query Link state and update */
+       status = ocrdma_mbx_get_link_speed(dev, NULL, &lstate);
+       if (!status)
+               ocrdma_update_link_state(dev, lstate);
+
        for (i = 0; i < ARRAY_SIZE(ocrdma_attributes); i++)
                if (device_create_file(&dev->ibdev.dev, ocrdma_attributes[i]))
                        goto sysfs_err;
@@ -373,7 +379,7 @@ static void ocrdma_remove(struct ocrdma_dev *dev)
        ocrdma_remove_free(dev);
 }
 
-static int ocrdma_open(struct ocrdma_dev *dev)
+static int ocrdma_dispatch_port_active(struct ocrdma_dev *dev)
 {
        struct ib_event port_event;
 
@@ -384,32 +390,9 @@ static int ocrdma_open(struct ocrdma_dev *dev)
        return 0;
 }
 
-static int ocrdma_close(struct ocrdma_dev *dev)
+static int ocrdma_dispatch_port_error(struct ocrdma_dev *dev)
 {
-       int i;
-       struct ocrdma_qp *qp, **cur_qp;
        struct ib_event err_event;
-       struct ib_qp_attr attrs;
-       int attr_mask = IB_QP_STATE;
-
-       attrs.qp_state = IB_QPS_ERR;
-       mutex_lock(&dev->dev_lock);
-       if (dev->qp_tbl) {
-               cur_qp = dev->qp_tbl;
-               for (i = 0; i < OCRDMA_MAX_QP; i++) {
-                       qp = cur_qp[i];
-                       if (qp && qp->ibqp.qp_type != IB_QPT_GSI) {
-                               /* change the QP state to ERROR */
-                               _ocrdma_modify_qp(&qp->ibqp, &attrs, attr_mask);
-
-                               err_event.event = IB_EVENT_QP_FATAL;
-                               err_event.element.qp = &qp->ibqp;
-                               err_event.device = &dev->ibdev;
-                               ib_dispatch_event(&err_event);
-                       }
-               }
-       }
-       mutex_unlock(&dev->dev_lock);
 
        err_event.event = IB_EVENT_PORT_ERR;
        err_event.element.port_num = 1;
@@ -420,7 +403,7 @@ static int ocrdma_close(struct ocrdma_dev *dev)
 
 static void ocrdma_shutdown(struct ocrdma_dev *dev)
 {
-       ocrdma_close(dev);
+       ocrdma_dispatch_port_error(dev);
        ocrdma_remove(dev);
 }
 
@@ -431,18 +414,28 @@ static void ocrdma_shutdown(struct ocrdma_dev *dev)
 static void ocrdma_event_handler(struct ocrdma_dev *dev, u32 event)
 {
        switch (event) {
-       case BE_DEV_UP:
-               ocrdma_open(dev);
-               break;
-       case BE_DEV_DOWN:
-               ocrdma_close(dev);
-               break;
        case BE_DEV_SHUTDOWN:
                ocrdma_shutdown(dev);
                break;
+       default:
+               break;
        }
 }
 
+void ocrdma_update_link_state(struct ocrdma_dev *dev, u8 lstate)
+{
+       if (!(dev->flags & OCRDMA_FLAGS_LINK_STATUS_INIT)) {
+               dev->flags |= OCRDMA_FLAGS_LINK_STATUS_INIT;
+               if (!lstate)
+                       return;
+       }
+
+       if (!lstate)
+               ocrdma_dispatch_port_error(dev);
+       else
+               ocrdma_dispatch_port_active(dev);
+}
+
 static struct ocrdma_driver ocrdma_drv = {
        .name                   = "ocrdma_driver",
        .add                    = ocrdma_add,
index 6a38268bbe9fb6b981e27f2ec42da8fd10adbfc2..99dd6fdf06d7b44bcea2f0fb28b90edf54aefcc0 100644 (file)
@@ -465,8 +465,11 @@ struct ocrdma_ae_qp_mcqe {
        u32 valid_ae_event;
 };
 
-#define OCRDMA_ASYNC_RDMA_EVE_CODE 0x14
-#define OCRDMA_ASYNC_GRP5_EVE_CODE 0x5
+enum ocrdma_async_event_code {
+       OCRDMA_ASYNC_LINK_EVE_CODE      = 0x01,
+       OCRDMA_ASYNC_GRP5_EVE_CODE      = 0x05,
+       OCRDMA_ASYNC_RDMA_EVE_CODE      = 0x14
+};
 
 enum ocrdma_async_grp5_events {
        OCRDMA_ASYNC_EVENT_QOS_VALUE    = 0x01,
@@ -489,6 +492,44 @@ enum OCRDMA_ASYNC_EVENT_TYPE {
        OCRDMA_MAX_ASYNC_ERRORS
 };
 
+struct ocrdma_ae_lnkst_mcqe {
+       u32 speed_state_ptn;
+       u32 qos_reason_falut;
+       u32 evt_tag;
+       u32 valid_ae_event;
+};
+
+enum {
+       OCRDMA_AE_LSC_PORT_NUM_MASK     = 0x3F,
+       OCRDMA_AE_LSC_PT_SHIFT          = 0x06,
+       OCRDMA_AE_LSC_PT_MASK           = (0x03 <<
+                       OCRDMA_AE_LSC_PT_SHIFT),
+       OCRDMA_AE_LSC_LS_SHIFT          = 0x08,
+       OCRDMA_AE_LSC_LS_MASK           = (0xFF <<
+                       OCRDMA_AE_LSC_LS_SHIFT),
+       OCRDMA_AE_LSC_LD_SHIFT          = 0x10,
+       OCRDMA_AE_LSC_LD_MASK           = (0xFF <<
+                       OCRDMA_AE_LSC_LD_SHIFT),
+       OCRDMA_AE_LSC_PPS_SHIFT         = 0x18,
+       OCRDMA_AE_LSC_PPS_MASK          = (0xFF <<
+                       OCRDMA_AE_LSC_PPS_SHIFT),
+       OCRDMA_AE_LSC_PPF_MASK          = 0xFF,
+       OCRDMA_AE_LSC_ER_SHIFT          = 0x08,
+       OCRDMA_AE_LSC_ER_MASK           = (0xFF <<
+                       OCRDMA_AE_LSC_ER_SHIFT),
+       OCRDMA_AE_LSC_QOS_SHIFT         = 0x10,
+       OCRDMA_AE_LSC_QOS_MASK          = (0xFFFF <<
+                       OCRDMA_AE_LSC_QOS_SHIFT)
+};
+
+enum {
+       OCRDMA_AE_LSC_PLINK_DOWN        = 0x00,
+       OCRDMA_AE_LSC_PLINK_UP          = 0x01,
+       OCRDMA_AE_LSC_LLINK_DOWN        = 0x02,
+       OCRDMA_AE_LSC_LLINK_MASK        = 0x02,
+       OCRDMA_AE_LSC_LLINK_UP          = 0x03
+};
+
 /* mailbox command request and responses */
 enum {
        OCRDMA_MBX_QUERY_CFG_CQ_OVERFLOW_SHIFT          = 2,
@@ -676,7 +717,7 @@ enum {
        OCRDMA_PHY_PFLT_SHIFT   = 0x18,
        OCRDMA_QOS_LNKSP_MASK   = 0xFFFF0000,
        OCRDMA_QOS_LNKSP_SHIFT  = 0x10,
-       OCRDMA_LLST_MASK        = 0xFF,
+       OCRDMA_LINK_ST_MASK     = 0x01,
        OCRDMA_PLFC_MASK        = 0x00000400,
        OCRDMA_PLFC_SHIFT       = 0x8,
        OCRDMA_PLRFC_MASK       = 0x00000200,
@@ -691,7 +732,7 @@ struct ocrdma_get_link_speed_rsp {
 
        u32 pflt_pps_ld_pnum;
        u32 qos_lsp;
-       u32 res_lls;
+       u32 res_lnk_st;
 };
 
 enum {
index 583001bcfb8fc8c10a1e088b451d7de12adc2aa8..76e96f97b3f6459e68d13c444be6e1beb6b578a9 100644 (file)
@@ -171,7 +171,7 @@ static inline void get_link_speed_and_width(struct ocrdma_dev *dev,
        int status;
        u8 speed;
 
-       status = ocrdma_mbx_get_link_speed(dev, &speed);
+       status = ocrdma_mbx_get_link_speed(dev, &speed, NULL);
        if (status)
                speed = OCRDMA_PHYS_LINK_SPEED_ZERO;
 
index 5e27f76805e28af0c0e0acdc9864360f8cf09b41..4c7c3c84a7417c32f2f348f7c91c2ce0e4b4e1b0 100644 (file)
@@ -292,7 +292,7 @@ int qib_refresh_qsfp_cache(struct qib_pportdata *ppd, struct qib_qsfp_cache *cp)
                qib_dev_porterr(ppd->dd, ppd->port,
                                "QSFP byte0 is 0x%02X, S/B 0x0C/D\n", peek[0]);
 
-       if ((peek[2] & 2) == 0) {
+       if ((peek[2] & 4) == 0) {
                /*
                 * If cable is paged, rather than "flat memory", we need to
                 * set the page to zero, Even if it already appears to be zero.
@@ -538,7 +538,7 @@ int qib_qsfp_dump(struct qib_pportdata *ppd, char *buf, int len)
        sofar += scnprintf(buf + sofar, len - sofar, "Date:%.*s\n",
                           QSFP_DATE_LEN, cd.date);
        sofar += scnprintf(buf + sofar, len - sofar, "Lot:%.*s\n",
-                          QSFP_LOT_LEN, cd.date);
+                          QSFP_LOT_LEN, cd.lot);
 
        while (bidx < QSFP_DEFAULT_HDR_CNT) {
                int iidx;
index 2baf5ad251ed24a02682051058e6d1a406419e04..bc803f33d5f6883200ca21e462febebb94393cd4 100644 (file)
@@ -329,9 +329,9 @@ struct qib_sge {
 struct qib_mr {
        struct ib_mr ibmr;
        struct ib_umem *umem;
-       struct qib_mregion mr;  /* must be last */
        u64 *pages;
        u32 npages;
+       struct qib_mregion mr;  /* must be last */
 };
 
 /*
index a93070210109699909075e02212fc6ae70710960..42f4da620f2e9f97062b9183b6ebf3ed54e56cfe 100644 (file)
@@ -1293,7 +1293,7 @@ u8 iser_check_task_pi_status(struct iscsi_iser_task *iser_task,
                if (mr_status.fail_status & IB_MR_CHECK_SIG_STATUS) {
                        sector_t sector_off = mr_status.sig_err.sig_err_offset;
 
-                       do_div(sector_off, sector_size + 8);
+                       sector_div(sector_off, sector_size + 8);
                        *sector = scsi_get_lba(iser_task->sc) + sector_off;
 
                        pr_err("PI error found type %d at sector %llx "
index dfbbbb28090b2301c7742fd28b145b62054a76af..8a51c3b5d657e5a49ae50c4e5f104a7298d732f2 100644 (file)
@@ -157,16 +157,9 @@ isert_create_qp(struct isert_conn *isert_conn,
        attr.recv_cq = comp->cq;
        attr.cap.max_send_wr = ISERT_QP_MAX_REQ_DTOS;
        attr.cap.max_recv_wr = ISERT_QP_MAX_RECV_DTOS + 1;
-       /*
-        * FIXME: Use devattr.max_sge - 2 for max_send_sge as
-        * work-around for RDMA_READs with ConnectX-2.
-        *
-        * Also, still make sure to have at least two SGEs for
-        * outgoing control PDU responses.
-        */
-       attr.cap.max_send_sge = max(2, device->dev_attr.max_sge - 2);
-       isert_conn->max_sge = attr.cap.max_send_sge;
-
+       attr.cap.max_send_sge = device->dev_attr.max_sge;
+       isert_conn->max_sge = min(device->dev_attr.max_sge,
+                                 device->dev_attr.max_sge_rd);
        attr.cap.max_recv_sge = 1;
        attr.sq_sig_type = IB_SIGNAL_REQ_WR;
        attr.qp_type = IB_QPT_RC;
index 9909022dc6c3eebd4c52ef3e7dca5221dc8b6038..3db9a659719b0f6283af610bf01b8f65d27292a9 100644 (file)
@@ -488,7 +488,7 @@ static int srp_create_ch_ib(struct srp_rdma_ch *ch)
        struct ib_qp *qp;
        struct ib_fmr_pool *fmr_pool = NULL;
        struct srp_fr_pool *fr_pool = NULL;
-       const int m = 1 + dev->use_fast_reg;
+       const int m = dev->use_fast_reg ? 3 : 1;
        struct ib_cq_init_attr cq_attr = {};
        int ret;
 
@@ -994,16 +994,16 @@ static int srp_connect_ch(struct srp_rdma_ch *ch, bool multich)
 
        ret = srp_lookup_path(ch);
        if (ret)
-               return ret;
+               goto out;
 
        while (1) {
                init_completion(&ch->done);
                ret = srp_send_req(ch, multich);
                if (ret)
-                       return ret;
+                       goto out;
                ret = wait_for_completion_interruptible(&ch->done);
                if (ret < 0)
-                       return ret;
+                       goto out;
 
                /*
                 * The CM event handling code will set status to
@@ -1011,15 +1011,16 @@ static int srp_connect_ch(struct srp_rdma_ch *ch, bool multich)
                 * back, or SRP_DLID_REDIRECT if we get a lid/qp
                 * redirect REJ back.
                 */
-               switch (ch->status) {
+               ret = ch->status;
+               switch (ret) {
                case 0:
                        ch->connected = true;
-                       return 0;
+                       goto out;
 
                case SRP_PORT_REDIRECT:
                        ret = srp_lookup_path(ch);
                        if (ret)
-                               return ret;
+                               goto out;
                        break;
 
                case SRP_DLID_REDIRECT:
@@ -1028,13 +1029,16 @@ static int srp_connect_ch(struct srp_rdma_ch *ch, bool multich)
                case SRP_STALE_CONN:
                        shost_printk(KERN_ERR, target->scsi_host, PFX
                                     "giving up on stale connection\n");
-                       ch->status = -ECONNRESET;
-                       return ch->status;
+                       ret = -ECONNRESET;
+                       goto out;
 
                default:
-                       return ch->status;
+                       goto out;
                }
        }
+
+out:
+       return ret <= 0 ? ret : -ENODEV;
 }
 
 static int srp_inv_rkey(struct srp_rdma_ch *ch, u32 rkey)
@@ -1309,7 +1313,7 @@ reset_state:
 }
 
 static int srp_map_finish_fr(struct srp_map_state *state,
-                            struct srp_rdma_ch *ch)
+                            struct srp_rdma_ch *ch, int sg_nents)
 {
        struct srp_target_port *target = ch->target;
        struct srp_device *dev = target->srp_host->srp_dev;
@@ -1324,10 +1328,10 @@ static int srp_map_finish_fr(struct srp_map_state *state,
 
        WARN_ON_ONCE(!dev->use_fast_reg);
 
-       if (state->sg_nents == 0)
+       if (sg_nents == 0)
                return 0;
 
-       if (state->sg_nents == 1 && target->global_mr) {
+       if (sg_nents == 1 && target->global_mr) {
                srp_map_desc(state, sg_dma_address(state->sg),
                             sg_dma_len(state->sg),
                             target->global_mr->rkey);
@@ -1341,8 +1345,7 @@ static int srp_map_finish_fr(struct srp_map_state *state,
        rkey = ib_inc_rkey(desc->mr->rkey);
        ib_update_fast_reg_key(desc->mr, rkey);
 
-       n = ib_map_mr_sg(desc->mr, state->sg, state->sg_nents,
-                        dev->mr_page_size);
+       n = ib_map_mr_sg(desc->mr, state->sg, sg_nents, dev->mr_page_size);
        if (unlikely(n < 0))
                return n;
 
@@ -1448,16 +1451,15 @@ static int srp_map_sg_fr(struct srp_map_state *state, struct srp_rdma_ch *ch,
        state->fr.next = req->fr_list;
        state->fr.end = req->fr_list + ch->target->cmd_sg_cnt;
        state->sg = scat;
-       state->sg_nents = scsi_sg_count(req->scmnd);
 
-       while (state->sg_nents) {
+       while (count) {
                int i, n;
 
-               n = srp_map_finish_fr(state, ch);
+               n = srp_map_finish_fr(state, ch, count);
                if (unlikely(n < 0))
                        return n;
 
-               state->sg_nents -= n;
+               count -= n;
                for (i = 0; i < n; i++)
                        state->sg = sg_next(state->sg);
        }
@@ -1517,10 +1519,12 @@ static int srp_map_idb(struct srp_rdma_ch *ch, struct srp_request *req,
 
        if (dev->use_fast_reg) {
                state.sg = idb_sg;
-               state.sg_nents = 1;
                sg_set_buf(idb_sg, req->indirect_desc, idb_len);
                idb_sg->dma_address = req->indirect_dma_addr; /* hack! */
-               ret = srp_map_finish_fr(&state, ch);
+#ifdef CONFIG_NEED_SG_DMA_LENGTH
+               idb_sg->dma_length = idb_sg->length;          /* hack^2 */
+#endif
+               ret = srp_map_finish_fr(&state, ch, 1);
                if (ret < 0)
                        return ret;
        } else if (dev->use_fmr) {
@@ -1655,7 +1659,7 @@ static int srp_map_data(struct scsi_cmnd *scmnd, struct srp_rdma_ch *ch,
                        return ret;
                req->nmdesc++;
        } else {
-               idb_rkey = target->global_mr->rkey;
+               idb_rkey = cpu_to_be32(target->global_mr->rkey);
        }
 
        indirect_hdr->table_desc.va = cpu_to_be64(req->indirect_dma_addr);
index 87a2a919dc43877141426e6d373d12727dc4b65e..f6af531f9f32c990cd30c7139d247c643144e55d 100644 (file)
@@ -300,10 +300,7 @@ struct srp_map_state {
        dma_addr_t              base_dma_addr;
        u32                     dma_len;
        u32                     total_len;
-       union {
-               unsigned int    npages;
-               int             sg_nents;
-       };
+       unsigned int            npages;
        unsigned int            nmdesc;
        unsigned int            ndesc;
 };
index 932d07307454bd47441da61ff06e3ef03ea93cd4..da326090c2b0e7f07ab4de5668012b1a4d5e92f3 100644 (file)
@@ -592,6 +592,7 @@ static void db9_attach(struct parport *pp)
                return;
        }
 
+       memset(&db9_parport_cb, 0, sizeof(db9_parport_cb));
        db9_parport_cb.flags = PARPORT_FLAG_EXCL;
 
        pd = parport_register_dev_model(pp, "db9", &db9_parport_cb, port_idx);
index 5a672dcac0d8174a151254ac31b591f0189f9d91..eae14d512353aae4902f3ce482c1cf87cba736b6 100644 (file)
@@ -951,6 +951,7 @@ static void gc_attach(struct parport *pp)
        pads = gc_cfg[port_idx].args + 1;
        n_pads = gc_cfg[port_idx].nargs - 1;
 
+       memset(&gc_parport_cb, 0, sizeof(gc_parport_cb));
        gc_parport_cb.flags = PARPORT_FLAG_EXCL;
 
        pd = parport_register_dev_model(pp, "gamecon", &gc_parport_cb,
index 9f5bca26bd2fb85a90ed4fd91bbdcf1a83e84162..77f575dd0901ff2732f47a62ebb7af37b826b608 100644 (file)
@@ -181,6 +181,7 @@ static void tgfx_attach(struct parport *pp)
        n_buttons = tgfx_cfg[port_idx].args + 1;
        n_devs = tgfx_cfg[port_idx].nargs - 1;
 
+       memset(&tgfx_parport_cb, 0, sizeof(tgfx_parport_cb));
        tgfx_parport_cb.flags = PARPORT_FLAG_EXCL;
 
        pd = parport_register_dev_model(pp, "turbografx", &tgfx_parport_cb,
index 9c07fe911075f3e1dba089f07d7d60d10ac327ba..70a893a17467608a103a81546eb7cce4cdf44010 100644 (file)
@@ -218,6 +218,7 @@ static void walkera0701_attach(struct parport *pp)
 
        w->parport = pp;
 
+       memset(&walkera0701_parport_cb, 0, sizeof(walkera0701_parport_cb));
        walkera0701_parport_cb.flags = PARPORT_FLAG_EXCL;
        walkera0701_parport_cb.irq_func = walkera0701_irq_handler;
        walkera0701_parport_cb.private = w;
index 4bf678541496e5971a3aa88cf9ded8e89558786a..d5994a745ffa5b5f4d1b411fec76f0a447a60f94 100644 (file)
@@ -97,8 +97,7 @@ static void arizona_haptics_work(struct work_struct *work)
 
                ret = regmap_update_bits(arizona->regmap,
                                         ARIZONA_HAPTICS_CONTROL_1,
-                                        ARIZONA_HAP_CTRL_MASK,
-                                        1 << ARIZONA_HAP_CTRL_SHIFT);
+                                        ARIZONA_HAP_CTRL_MASK, 0);
                if (ret != 0) {
                        dev_err(arizona->dev, "Failed to stop haptics: %d\n",
                                ret);
index 5e1665bbaa0baca86e2c865ba88162be2f209d2e..2f589857a0395d8c48f685f47bd1c9ceb8445213 100644 (file)
@@ -41,6 +41,7 @@
 
 #define DRIVER_NAME            "elan_i2c"
 #define ELAN_DRIVER_VERSION    "1.6.1"
+#define ELAN_VENDOR_ID         0x04f3
 #define ETP_MAX_PRESSURE       255
 #define ETP_FWIDTH_REDUCE      90
 #define ETP_FINGER_WIDTH       15
@@ -914,6 +915,8 @@ static int elan_setup_input_device(struct elan_tp_data *data)
 
        input->name = "Elan Touchpad";
        input->id.bustype = BUS_I2C;
+       input->id.vendor = ELAN_VENDOR_ID;
+       input->id.product = data->product_id;
        input_set_drvdata(input, data);
 
        error = input_mt_init_slots(input, ETP_MAX_FINGERS,
index 92c31b8f8fb489c317013f1cf77f133993fcc321..1edfac78d4ac742a8fe6d6183660c45652381804 100644 (file)
@@ -145,6 +145,7 @@ static int parkbd_getport(struct parport *pp)
 {
        struct pardev_cb parkbd_parport_cb;
 
+       memset(&parkbd_parport_cb, 0, sizeof(parkbd_parport_cb));
        parkbd_parport_cb.irq_func = parkbd_interrupt;
        parkbd_parport_cb.flags = PARPORT_FLAG_EXCL;
 
index e7f966da6efa318f1901ce912e4e0dd65b5c70f7..78ca44840d60cac1467c90cb563cedf2a05fcaab 100644 (file)
@@ -1819,6 +1819,14 @@ aiptek_probe(struct usb_interface *intf, const struct usb_device_id *id)
        input_set_abs_params(inputdev, ABS_TILT_Y, AIPTEK_TILT_MIN, AIPTEK_TILT_MAX, 0, 0);
        input_set_abs_params(inputdev, ABS_WHEEL, AIPTEK_WHEEL_MIN, AIPTEK_WHEEL_MAX - 1, 0, 0);
 
+       /* Verify that a device really has an endpoint */
+       if (intf->altsetting[0].desc.bNumEndpoints < 1) {
+               dev_err(&intf->dev,
+                       "interface has %d endpoints, but must have minimum 1\n",
+                       intf->altsetting[0].desc.bNumEndpoints);
+               err = -EINVAL;
+               goto fail3;
+       }
        endpoint = &intf->altsetting[0].endpoint[0].desc;
 
        /* Go set up our URB, which is called when the tablet receives
@@ -1861,6 +1869,7 @@ aiptek_probe(struct usb_interface *intf, const struct usb_device_id *id)
        if (i == ARRAY_SIZE(speeds)) {
                dev_info(&intf->dev,
                         "Aiptek tried all speeds, no sane response\n");
+               err = -EINVAL;
                goto fail3;
        }
 
index c5622058c22bba77b14ed336b764dc7b1ac6c617..2d5794ec338b72a1cea0367bccdaf9654db025d4 100644 (file)
@@ -2487,6 +2487,31 @@ static struct mxt_acpi_platform_data samus_platform_data[] = {
        { }
 };
 
+static unsigned int chromebook_tp_buttons[] = {
+       KEY_RESERVED,
+       KEY_RESERVED,
+       KEY_RESERVED,
+       KEY_RESERVED,
+       KEY_RESERVED,
+       BTN_LEFT
+};
+
+static struct mxt_acpi_platform_data chromebook_platform_data[] = {
+       {
+               /* Touchpad */
+               .hid    = "ATML0000",
+               .pdata  = {
+                       .t19_num_keys   = ARRAY_SIZE(chromebook_tp_buttons),
+                       .t19_keymap     = chromebook_tp_buttons,
+               },
+       },
+       {
+               /* Touchscreen */
+               .hid    = "ATML0001",
+       },
+       { }
+};
+
 static const struct dmi_system_id mxt_dmi_table[] = {
        {
                /* 2015 Google Pixel */
@@ -2497,6 +2522,14 @@ static const struct dmi_system_id mxt_dmi_table[] = {
                },
                .driver_data = samus_platform_data,
        },
+       {
+               /* Other Google Chromebooks */
+               .ident = "Chromebook",
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "GOOGLE"),
+               },
+               .driver_data = chromebook_platform_data,
+       },
        { }
 };
 
@@ -2701,6 +2734,7 @@ static const struct i2c_device_id mxt_id[] = {
        { "qt602240_ts", 0 },
        { "atmel_mxt_ts", 0 },
        { "atmel_mxt_tp", 0 },
+       { "maxtouch", 0 },
        { "mXT224", 0 },
        { }
 };
index 17cc20ef4923bdb2fb2edcf770d7c303be9d6af5..ac09855fa435d7fc2d87fb801fb277bb55f086ba 100644 (file)
@@ -1316,7 +1316,13 @@ static int __maybe_unused elants_i2c_suspend(struct device *dev)
 
        disable_irq(client->irq);
 
-       if (device_may_wakeup(dev) || ts->keep_power_in_suspend) {
+       if (device_may_wakeup(dev)) {
+               /*
+                * The device will automatically enter idle mode
+                * that has reduced power consumption.
+                */
+               ts->wake_irq_enabled = (enable_irq_wake(client->irq) == 0);
+       } else if (ts->keep_power_in_suspend) {
                for (retry_cnt = 0; retry_cnt < MAX_RETRIES; retry_cnt++) {
                        error = elants_i2c_send(client, set_sleep_cmd,
                                                sizeof(set_sleep_cmd));
@@ -1326,10 +1332,6 @@ static int __maybe_unused elants_i2c_suspend(struct device *dev)
                        dev_err(&client->dev,
                                "suspend command failed: %d\n", error);
                }
-
-               if (device_may_wakeup(dev))
-                       ts->wake_irq_enabled =
-                                       (enable_irq_wake(client->irq) == 0);
        } else {
                elants_i2c_power_off(ts);
        }
@@ -1345,10 +1347,11 @@ static int __maybe_unused elants_i2c_resume(struct device *dev)
        int retry_cnt;
        int error;
 
-       if (device_may_wakeup(dev) && ts->wake_irq_enabled)
-               disable_irq_wake(client->irq);
-
-       if (ts->keep_power_in_suspend) {
+       if (device_may_wakeup(dev)) {
+               if (ts->wake_irq_enabled)
+                       disable_irq_wake(client->irq);
+               elants_i2c_sw_reset(client);
+       } else if (ts->keep_power_in_suspend) {
                for (retry_cnt = 0; retry_cnt < MAX_RETRIES; retry_cnt++) {
                        error = elants_i2c_send(client, set_active_cmd,
                                                sizeof(set_active_cmd));
index d21d4edf7236abac49072c086290b76d2ae201b5..7caf2fa237f22bd7a3b0932c6387ed52e0b26424 100644 (file)
@@ -494,6 +494,22 @@ static void handle_fault_error(struct fault *fault)
        }
 }
 
+static bool access_error(struct vm_area_struct *vma, struct fault *fault)
+{
+       unsigned long requested = 0;
+
+       if (fault->flags & PPR_FAULT_EXEC)
+               requested |= VM_EXEC;
+
+       if (fault->flags & PPR_FAULT_READ)
+               requested |= VM_READ;
+
+       if (fault->flags & PPR_FAULT_WRITE)
+               requested |= VM_WRITE;
+
+       return (requested & ~vma->vm_flags) != 0;
+}
+
 static void do_fault(struct work_struct *work)
 {
        struct fault *fault = container_of(work, struct fault, work);
@@ -516,8 +532,8 @@ static void do_fault(struct work_struct *work)
                goto out;
        }
 
-       if (!(vma->vm_flags & (VM_READ | VM_EXEC | VM_WRITE))) {
-               /* handle_mm_fault would BUG_ON() */
+       /* Check if we have the right permissions on the vma */
+       if (access_error(vma, fault)) {
                up_read(&mm->mmap_sem);
                handle_fault_error(fault);
                goto out;
index f1042daef9ada83e931ae450623ce491ebd55959..ac7387686ddc7b2a7c7757f2cb3fbd003c8a23af 100644 (file)
@@ -2159,7 +2159,7 @@ static int __domain_mapping(struct dmar_domain *domain, unsigned long iov_pfn,
                        sg_res = aligned_nrpages(sg->offset, sg->length);
                        sg->dma_address = ((dma_addr_t)iov_pfn << VTD_PAGE_SHIFT) + sg->offset;
                        sg->dma_length = sg->length;
-                       pteval = (sg_phys(sg) & PAGE_MASK) | prot;
+                       pteval = page_to_phys(sg_page(sg)) | prot;
                        phys_pfn = pteval >> VTD_PAGE_SHIFT;
                }
 
@@ -3704,7 +3704,7 @@ static int intel_nontranslate_map_sg(struct device *hddev,
 
        for_each_sg(sglist, sg, nelems, i) {
                BUG_ON(!sg_page(sg));
-               sg->dma_address = sg_phys(sg);
+               sg->dma_address = page_to_phys(sg_page(sg)) + sg->offset;
                sg->dma_length = sg->length;
        }
        return nelems;
index c69e3f9ec9586bca0cd2ef712a3cf9fc25f4689f..50464833d0b84732a4d397cee8b73ed43a721712 100644 (file)
@@ -484,6 +484,23 @@ struct page_req_dsc {
 };
 
 #define PRQ_RING_MASK ((0x1000 << PRQ_ORDER) - 0x10)
+
+static bool access_error(struct vm_area_struct *vma, struct page_req_dsc *req)
+{
+       unsigned long requested = 0;
+
+       if (req->exe_req)
+               requested |= VM_EXEC;
+
+       if (req->rd_req)
+               requested |= VM_READ;
+
+       if (req->wr_req)
+               requested |= VM_WRITE;
+
+       return (requested & ~vma->vm_flags) != 0;
+}
+
 static irqreturn_t prq_event_thread(int irq, void *d)
 {
        struct intel_iommu *iommu = d;
@@ -539,6 +556,9 @@ static irqreturn_t prq_event_thread(int irq, void *d)
                if (!vma || address < vma->vm_start)
                        goto invalid;
 
+               if (access_error(vma, req))
+                       goto invalid;
+
                ret = handle_mm_fault(svm->mm, vma, address,
                                      req->wr_req ? FAULT_FLAG_WRITE : 0);
                if (ret & VM_FAULT_ERROR)
index abae363c7b9bd8932066e760beea7f76f22e7b8d..0e3b0092ec92c9d4d1dcb06e713edcf99c4a9293 100644 (file)
@@ -1430,7 +1430,7 @@ size_t default_iommu_map_sg(struct iommu_domain *domain, unsigned long iova,
        min_pagesz = 1 << __ffs(domain->ops->pgsize_bitmap);
 
        for_each_sg(sg, s, nents, i) {
-               phys_addr_t phys = sg_phys(s);
+               phys_addr_t phys = page_to_phys(sg_page(s)) + s->offset;
 
                /*
                 * We are mapping on IOMMU page boundaries, so offset within
index cbe198cb36991d3970f5a0ce4fc3596ee85eb5a7..471ee36b9c6eea6d72ad74302fadfb97c28f8a7f 100644 (file)
@@ -216,6 +216,7 @@ static int s390_iommu_update_trans(struct s390_domain *s390_domain,
        u8 *page_addr = (u8 *) (pa & PAGE_MASK);
        dma_addr_t start_dma_addr = dma_addr;
        unsigned long irq_flags, nr_pages, i;
+       unsigned long *entry;
        int rc = 0;
 
        if (dma_addr < s390_domain->domain.geometry.aperture_start ||
@@ -228,8 +229,12 @@ static int s390_iommu_update_trans(struct s390_domain *s390_domain,
 
        spin_lock_irqsave(&s390_domain->dma_table_lock, irq_flags);
        for (i = 0; i < nr_pages; i++) {
-               dma_update_cpu_trans(s390_domain->dma_table, page_addr,
-                                    dma_addr, flags);
+               entry = dma_walk_cpu_trans(s390_domain->dma_table, dma_addr);
+               if (!entry) {
+                       rc = -ENOMEM;
+                       goto undo_cpu_trans;
+               }
+               dma_update_cpu_trans(entry, page_addr, flags);
                page_addr += PAGE_SIZE;
                dma_addr += PAGE_SIZE;
        }
@@ -242,6 +247,20 @@ static int s390_iommu_update_trans(struct s390_domain *s390_domain,
                        break;
        }
        spin_unlock(&s390_domain->list_lock);
+
+undo_cpu_trans:
+       if (rc && ((flags & ZPCI_PTE_VALID_MASK) == ZPCI_PTE_VALID)) {
+               flags = ZPCI_PTE_INVALID;
+               while (i-- > 0) {
+                       page_addr -= PAGE_SIZE;
+                       dma_addr -= PAGE_SIZE;
+                       entry = dma_walk_cpu_trans(s390_domain->dma_table,
+                                                  dma_addr);
+                       if (!entry)
+                               break;
+                       dma_update_cpu_trans(entry, page_addr, flags);
+               }
+       }
        spin_unlock_irqrestore(&s390_domain->dma_table_lock, irq_flags);
 
        return rc;
index 44a077f3a4a2627c03953d9650a66e7607dd91e2..f174ce0ca36115dc36feec5f047af7bf402e180a 100644 (file)
@@ -84,12 +84,15 @@ void __init gic_dist_config(void __iomem *base, int gic_irqs,
                writel_relaxed(GICD_INT_DEF_PRI_X4, base + GIC_DIST_PRI + i);
 
        /*
-        * Disable all interrupts.  Leave the PPI and SGIs alone
-        * as they are enabled by redistributor registers.
+        * Deactivate and disable all SPIs. Leave the PPI and SGIs
+        * alone as they are in the redistributor registers on GICv3.
         */
-       for (i = 32; i < gic_irqs; i += 32)
+       for (i = 32; i < gic_irqs; i += 32) {
                writel_relaxed(GICD_INT_EN_CLR_X32,
-                                       base + GIC_DIST_ENABLE_CLEAR + i / 8);
+                              base + GIC_DIST_ACTIVE_CLEAR + i / 8);
+               writel_relaxed(GICD_INT_EN_CLR_X32,
+                              base + GIC_DIST_ENABLE_CLEAR + i / 8);
+       }
 
        if (sync_access)
                sync_access();
@@ -102,7 +105,9 @@ void gic_cpu_config(void __iomem *base, void (*sync_access)(void))
        /*
         * Deal with the banked PPI and SGI interrupts - disable all
         * PPI interrupts, ensure all SGI interrupts are enabled.
+        * Make sure everything is deactivated.
         */
+       writel_relaxed(GICD_INT_EN_CLR_X32, base + GIC_DIST_ACTIVE_CLEAR);
        writel_relaxed(GICD_INT_EN_CLR_PPI, base + GIC_DIST_ENABLE_CLEAR);
        writel_relaxed(GICD_INT_EN_SET_SGI, base + GIC_DIST_ENABLE_SET);
 
index 515c823c1c95cee63b46c18bed35bb70260ae9a9..abf2ffaed392270c97d14c7fdc2ab247e63a58e1 100644 (file)
@@ -73,9 +73,11 @@ struct gic_chip_data {
        union gic_base cpu_base;
 #ifdef CONFIG_CPU_PM
        u32 saved_spi_enable[DIV_ROUND_UP(1020, 32)];
+       u32 saved_spi_active[DIV_ROUND_UP(1020, 32)];
        u32 saved_spi_conf[DIV_ROUND_UP(1020, 16)];
        u32 saved_spi_target[DIV_ROUND_UP(1020, 4)];
        u32 __percpu *saved_ppi_enable;
+       u32 __percpu *saved_ppi_active;
        u32 __percpu *saved_ppi_conf;
 #endif
        struct irq_domain *domain;
@@ -566,6 +568,10 @@ static void gic_dist_save(unsigned int gic_nr)
        for (i = 0; i < DIV_ROUND_UP(gic_irqs, 32); i++)
                gic_data[gic_nr].saved_spi_enable[i] =
                        readl_relaxed(dist_base + GIC_DIST_ENABLE_SET + i * 4);
+
+       for (i = 0; i < DIV_ROUND_UP(gic_irqs, 32); i++)
+               gic_data[gic_nr].saved_spi_active[i] =
+                       readl_relaxed(dist_base + GIC_DIST_ACTIVE_SET + i * 4);
 }
 
 /*
@@ -604,9 +610,19 @@ static void gic_dist_restore(unsigned int gic_nr)
                writel_relaxed(gic_data[gic_nr].saved_spi_target[i],
                        dist_base + GIC_DIST_TARGET + i * 4);
 
-       for (i = 0; i < DIV_ROUND_UP(gic_irqs, 32); i++)
+       for (i = 0; i < DIV_ROUND_UP(gic_irqs, 32); i++) {
+               writel_relaxed(GICD_INT_EN_CLR_X32,
+                       dist_base + GIC_DIST_ENABLE_CLEAR + i * 4);
                writel_relaxed(gic_data[gic_nr].saved_spi_enable[i],
                        dist_base + GIC_DIST_ENABLE_SET + i * 4);
+       }
+
+       for (i = 0; i < DIV_ROUND_UP(gic_irqs, 32); i++) {
+               writel_relaxed(GICD_INT_EN_CLR_X32,
+                       dist_base + GIC_DIST_ACTIVE_CLEAR + i * 4);
+               writel_relaxed(gic_data[gic_nr].saved_spi_active[i],
+                       dist_base + GIC_DIST_ACTIVE_SET + i * 4);
+       }
 
        writel_relaxed(GICD_ENABLE, dist_base + GIC_DIST_CTRL);
 }
@@ -631,6 +647,10 @@ static void gic_cpu_save(unsigned int gic_nr)
        for (i = 0; i < DIV_ROUND_UP(32, 32); i++)
                ptr[i] = readl_relaxed(dist_base + GIC_DIST_ENABLE_SET + i * 4);
 
+       ptr = raw_cpu_ptr(gic_data[gic_nr].saved_ppi_active);
+       for (i = 0; i < DIV_ROUND_UP(32, 32); i++)
+               ptr[i] = readl_relaxed(dist_base + GIC_DIST_ACTIVE_SET + i * 4);
+
        ptr = raw_cpu_ptr(gic_data[gic_nr].saved_ppi_conf);
        for (i = 0; i < DIV_ROUND_UP(32, 16); i++)
                ptr[i] = readl_relaxed(dist_base + GIC_DIST_CONFIG + i * 4);
@@ -654,8 +674,18 @@ static void gic_cpu_restore(unsigned int gic_nr)
                return;
 
        ptr = raw_cpu_ptr(gic_data[gic_nr].saved_ppi_enable);
-       for (i = 0; i < DIV_ROUND_UP(32, 32); i++)
+       for (i = 0; i < DIV_ROUND_UP(32, 32); i++) {
+               writel_relaxed(GICD_INT_EN_CLR_X32,
+                              dist_base + GIC_DIST_ENABLE_CLEAR + i * 4);
                writel_relaxed(ptr[i], dist_base + GIC_DIST_ENABLE_SET + i * 4);
+       }
+
+       ptr = raw_cpu_ptr(gic_data[gic_nr].saved_ppi_active);
+       for (i = 0; i < DIV_ROUND_UP(32, 32); i++) {
+               writel_relaxed(GICD_INT_EN_CLR_X32,
+                              dist_base + GIC_DIST_ACTIVE_CLEAR + i * 4);
+               writel_relaxed(ptr[i], dist_base + GIC_DIST_ACTIVE_SET + i * 4);
+       }
 
        ptr = raw_cpu_ptr(gic_data[gic_nr].saved_ppi_conf);
        for (i = 0; i < DIV_ROUND_UP(32, 16); i++)
@@ -710,6 +740,10 @@ static void __init gic_pm_init(struct gic_chip_data *gic)
                sizeof(u32));
        BUG_ON(!gic->saved_ppi_enable);
 
+       gic->saved_ppi_active = __alloc_percpu(DIV_ROUND_UP(32, 32) * 4,
+               sizeof(u32));
+       BUG_ON(!gic->saved_ppi_active);
+
        gic->saved_ppi_conf = __alloc_percpu(DIV_ROUND_UP(32, 16) * 4,
                sizeof(u32));
        BUG_ON(!gic->saved_ppi_conf);
index 598ab3f0e0ac54b79f1438c2193f8bc112949975..cadf104e30746b34d242eaa6e91637b8f99e5370 100644 (file)
@@ -210,7 +210,12 @@ int __init fpga_irq_of_init(struct device_node *node,
                parent_irq = -1;
        }
 
+#ifdef CONFIG_ARCH_VERSATILE
+       fpga_irq_init(base, node->name, IRQ_SIC_START, parent_irq, valid_mask,
+                                 node);
+#else
        fpga_irq_init(base, node->name, 0, parent_irq, valid_mask, node);
+#endif
 
        writel(clear_mask, base + IRQ_ENABLE_CLEAR);
        writel(clear_mask, base + FIQ_ENABLE_CLEAR);
index 375be509e95f5bd302da79446cb8867f8ecb8ec7..2a506fe0c8a4500a16e83b1aba70a6ed2d192185 100644 (file)
@@ -67,8 +67,7 @@ static int write_modem(struct cardstate *cs)
        struct sk_buff *skb = bcs->tx_skb;
        int sent = -EOPNOTSUPP;
 
-       if (!tty || !tty->driver || !skb)
-               return -EINVAL;
+       WARN_ON(!tty || !tty->ops || !skb);
 
        if (!skb->len) {
                dev_kfree_skb_any(skb);
@@ -109,8 +108,7 @@ static int send_cb(struct cardstate *cs)
        unsigned long flags;
        int sent = 0;
 
-       if (!tty || !tty->driver)
-               return -EFAULT;
+       WARN_ON(!tty || !tty->ops);
 
        cb = cs->cmdbuf;
        if (!cb)
@@ -370,19 +368,18 @@ static void gigaset_freecshw(struct cardstate *cs)
        tasklet_kill(&cs->write_tasklet);
        if (!cs->hw.ser)
                return;
-       dev_set_drvdata(&cs->hw.ser->dev.dev, NULL);
        platform_device_unregister(&cs->hw.ser->dev);
-       kfree(cs->hw.ser);
-       cs->hw.ser = NULL;
 }
 
 static void gigaset_device_release(struct device *dev)
 {
-       struct platform_device *pdev = to_platform_device(dev);
+       struct cardstate *cs = dev_get_drvdata(dev);
 
-       /* adapted from platform_device_release() in drivers/base/platform.c */
-       kfree(dev->platform_data);
-       kfree(pdev->resource);
+       if (!cs)
+               return;
+       dev_set_drvdata(dev, NULL);
+       kfree(cs->hw.ser);
+       cs->hw.ser = NULL;
 }
 
 /*
@@ -432,7 +429,9 @@ static int gigaset_set_modem_ctrl(struct cardstate *cs, unsigned old_state,
        struct tty_struct *tty = cs->hw.ser->tty;
        unsigned int set, clear;
 
-       if (!tty || !tty->driver || !tty->ops->tiocmset)
+       WARN_ON(!tty || !tty->ops);
+       /* tiocmset is an optional tty driver method */
+       if (!tty->ops->tiocmset)
                return -EINVAL;
        set = new_state & ~old_state;
        clear = old_state & ~new_state;
index a77eea594b695c59c96903bba4be80063eec1ad7..cb428b9ee441b83819b7d6d4f173b725ba67d360 100644 (file)
@@ -1170,7 +1170,7 @@ mISDNipac_irq(struct ipac_hw *ipac, int maxloop)
 
        if (ipac->type & IPAC_TYPE_IPACX) {
                ista = ReadIPAC(ipac, ISACX_ISTA);
-               while (ista && cnt--) {
+               while (ista && --cnt) {
                        pr_debug("%s: ISTA %02x\n", ipac->name, ista);
                        if (ista & IPACX__ICA)
                                ipac_irq(&ipac->hscx[0], ista);
@@ -1182,7 +1182,7 @@ mISDNipac_irq(struct ipac_hw *ipac, int maxloop)
                }
        } else if (ipac->type & IPAC_TYPE_IPAC) {
                ista = ReadIPAC(ipac, IPAC_ISTA);
-               while (ista && cnt--) {
+               while (ista && --cnt) {
                        pr_debug("%s: ISTA %02x\n", ipac->name, ista);
                        if (ista & (IPAC__ICD | IPAC__EXD)) {
                                istad = ReadISAC(isac, ISAC_ISTA);
@@ -1200,7 +1200,7 @@ mISDNipac_irq(struct ipac_hw *ipac, int maxloop)
                        ista = ReadIPAC(ipac, IPAC_ISTA);
                }
        } else if (ipac->type & IPAC_TYPE_HSCX) {
-               while (cnt) {
+               while (--cnt) {
                        ista = ReadIPAC(ipac, IPAC_ISTAB + ipac->hscx[1].off);
                        pr_debug("%s: B2 ISTA %02x\n", ipac->name, ista);
                        if (ista)
@@ -1211,7 +1211,6 @@ mISDNipac_irq(struct ipac_hw *ipac, int maxloop)
                                mISDNisac_irq(isac, istad);
                        if (0 == (ista | istad))
                                break;
-                       cnt--;
                }
        }
        if (cnt > maxloop) /* only for ISAC/HSCX without PCI IRQ test */
index b33f53b3ca93257a6ec34f409c46e5f1d7662172..bf04d2a3cf4afe4614765b2b3d08d32ec77571a6 100644 (file)
@@ -1896,7 +1896,7 @@ static void EChannel_proc_rcv(struct hisax_d_if *d_if)
                                ptr--;
                                *ptr++ = '\n';
                                *ptr = 0;
-                               HiSax_putstatus(cs, NULL, "%s", cs->dlog);
+                               HiSax_putstatus(cs, NULL, cs->dlog);
                        } else
                                HiSax_putstatus(cs, "LogEcho: ",
                                                "warning Frame too big (%d)",
index 4a48255281887e8c03f9dbacccf404f4f9c52476..90449e1e91e5a27924da01df6215dfa6c326651e 100644 (file)
@@ -901,7 +901,7 @@ Begin:
                                        ptr--;
                                        *ptr++ = '\n';
                                        *ptr = 0;
-                                       HiSax_putstatus(cs, NULL, "%s", cs->dlog);
+                                       HiSax_putstatus(cs, NULL, cs->dlog);
                                } else
                                        HiSax_putstatus(cs, "LogEcho: ", "warning Frame too big (%d)", total - 3);
                        }
index b1fad81f0722e64b2e0d671215e8dc89c295f4a1..13b2151c10f54ff9fd5bcec76e1ceef2b99aa472 100644 (file)
@@ -674,7 +674,7 @@ receive_emsg(struct IsdnCardState *cs)
                                        ptr--;
                                        *ptr++ = '\n';
                                        *ptr = 0;
-                                       HiSax_putstatus(cs, NULL, "%s", cs->dlog);
+                                       HiSax_putstatus(cs, NULL, cs->dlog);
                                } else
                                        HiSax_putstatus(cs, "LogEcho: ", "warning Frame too big (%d)", skb->len);
                        }
index b420f8bd862e454df2cc08f4da84b8bc7ef76e57..ba4beb25d872dbc24d2cbe55a411dee28f219b47 100644 (file)
@@ -1179,7 +1179,7 @@ LogFrame(struct IsdnCardState *cs, u_char *buf, int size)
                dp--;
                *dp++ = '\n';
                *dp = 0;
-               HiSax_putstatus(cs, NULL, "%s", cs->dlog);
+               HiSax_putstatus(cs, NULL, cs->dlog);
        } else
                HiSax_putstatus(cs, "LogFrame: ", "warning Frame too big (%d)", size);
 }
@@ -1246,7 +1246,7 @@ dlogframe(struct IsdnCardState *cs, struct sk_buff *skb, int dir)
        }
        if (finish) {
                *dp = 0;
-               HiSax_putstatus(cs, NULL, "%s", cs->dlog);
+               HiSax_putstatus(cs, NULL, cs->dlog);
                return;
        }
        if ((0xfe & buf[0]) == PROTO_DIS_N0) {  /* 1TR6 */
@@ -1509,5 +1509,5 @@ dlogframe(struct IsdnCardState *cs, struct sk_buff *skb, int dir)
                dp += sprintf(dp, "Unknown protocol %x!", buf[0]);
        }
        *dp = 0;
-       HiSax_putstatus(cs, NULL, "%s", cs->dlog);
+       HiSax_putstatus(cs, NULL, cs->dlog);
 }
index a16bf56d3f283ece1cd204920ca84aff41eec915..85a339030e4b8ec4a85c46185e561576c47268db 100644 (file)
@@ -18,6 +18,7 @@ if NVM
 
 config NVM_DEBUG
        bool "Open-Channel SSD debugging support"
+       default n
        ---help---
        Exposes a debug management interface to create/remove targets at:
 
index f659e605a4067bed3489723470e32cc9ae02b791..8f41b245cd55b55862911baaf2220d885fc30142 100644 (file)
@@ -74,7 +74,7 @@ EXPORT_SYMBOL(nvm_unregister_target);
 void *nvm_dev_dma_alloc(struct nvm_dev *dev, gfp_t mem_flags,
                                                        dma_addr_t *dma_handler)
 {
-       return dev->ops->dev_dma_alloc(dev->q, dev->ppalist_pool, mem_flags,
+       return dev->ops->dev_dma_alloc(dev, dev->ppalist_pool, mem_flags,
                                                                dma_handler);
 }
 EXPORT_SYMBOL(nvm_dev_dma_alloc);
@@ -97,15 +97,47 @@ static struct nvmm_type *nvm_find_mgr_type(const char *name)
        return NULL;
 }
 
+struct nvmm_type *nvm_init_mgr(struct nvm_dev *dev)
+{
+       struct nvmm_type *mt;
+       int ret;
+
+       lockdep_assert_held(&nvm_lock);
+
+       list_for_each_entry(mt, &nvm_mgrs, list) {
+               ret = mt->register_mgr(dev);
+               if (ret < 0) {
+                       pr_err("nvm: media mgr failed to init (%d) on dev %s\n",
+                                                               ret, dev->name);
+                       return NULL; /* initialization failed */
+               } else if (ret > 0)
+                       return mt;
+       }
+
+       return NULL;
+}
+
 int nvm_register_mgr(struct nvmm_type *mt)
 {
+       struct nvm_dev *dev;
        int ret = 0;
 
        down_write(&nvm_lock);
-       if (nvm_find_mgr_type(mt->name))
+       if (nvm_find_mgr_type(mt->name)) {
                ret = -EEXIST;
-       else
+               goto finish;
+       } else {
                list_add(&mt->list, &nvm_mgrs);
+       }
+
+       /* try to register media mgr if any device have none configured */
+       list_for_each_entry(dev, &nvm_devices, devices) {
+               if (dev->mt)
+                       continue;
+
+               dev->mt = nvm_init_mgr(dev);
+       }
+finish:
        up_write(&nvm_lock);
 
        return ret;
@@ -160,11 +192,6 @@ int nvm_erase_blk(struct nvm_dev *dev, struct nvm_block *blk)
 }
 EXPORT_SYMBOL(nvm_erase_blk);
 
-static void nvm_core_free(struct nvm_dev *dev)
-{
-       kfree(dev);
-}
-
 static int nvm_core_init(struct nvm_dev *dev)
 {
        struct nvm_id *id = &dev->identity;
@@ -179,12 +206,21 @@ static int nvm_core_init(struct nvm_dev *dev)
        dev->sec_size = grp->csecs;
        dev->oob_size = grp->sos;
        dev->sec_per_pg = grp->fpg_sz / grp->csecs;
-       dev->addr_mode = id->ppat;
-       dev->addr_format = id->ppaf;
+       memcpy(&dev->ppaf, &id->ppaf, sizeof(struct nvm_addr_format));
 
        dev->plane_mode = NVM_PLANE_SINGLE;
        dev->max_rq_size = dev->ops->max_phys_sect * dev->sec_size;
 
+       if (grp->mtype != 0) {
+               pr_err("nvm: memory type not supported\n");
+               return -EINVAL;
+       }
+
+       if (grp->fmtype != 0 && grp->fmtype != 1) {
+               pr_err("nvm: flash type not supported\n");
+               return -EINVAL;
+       }
+
        if (grp->mpos & 0x020202)
                dev->plane_mode = NVM_PLANE_DOUBLE;
        if (grp->mpos & 0x040404)
@@ -213,21 +249,17 @@ static void nvm_free(struct nvm_dev *dev)
 
        if (dev->mt)
                dev->mt->unregister_mgr(dev);
-
-       nvm_core_free(dev);
 }
 
 static int nvm_init(struct nvm_dev *dev)
 {
-       struct nvmm_type *mt;
-       int ret = 0;
+       int ret = -EINVAL;
 
        if (!dev->q || !dev->ops)
-               return -EINVAL;
+               return ret;
 
-       if (dev->ops->identity(dev->q, &dev->identity)) {
+       if (dev->ops->identity(dev, &dev->identity)) {
                pr_err("nvm: device could not be identified\n");
-               ret = -EINVAL;
                goto err;
        }
 
@@ -251,29 +283,12 @@ static int nvm_init(struct nvm_dev *dev)
                goto err;
        }
 
-       /* register with device with a supported manager */
-       list_for_each_entry(mt, &nvm_mgrs, list) {
-               ret = mt->register_mgr(dev);
-               if (ret < 0)
-                       goto err; /* initialization failed */
-               if (ret > 0) {
-                       dev->mt = mt;
-                       break; /* successfully initialized */
-               }
-       }
-
-       if (!ret) {
-               pr_info("nvm: no compatible manager found.\n");
-               return 0;
-       }
-
        pr_info("nvm: registered %s [%u/%u/%u/%u/%u/%u]\n",
                        dev->name, dev->sec_per_pg, dev->nr_planes,
                        dev->pgs_per_blk, dev->blks_per_lun, dev->nr_luns,
                        dev->nr_chnls);
        return 0;
 err:
-       nvm_free(dev);
        pr_err("nvm: failed to initialize nvm\n");
        return ret;
 }
@@ -308,22 +323,27 @@ int nvm_register(struct request_queue *q, char *disk_name,
        if (ret)
                goto err_init;
 
-       down_write(&nvm_lock);
-       list_add(&dev->devices, &nvm_devices);
-       up_write(&nvm_lock);
+       if (dev->ops->max_phys_sect > 256) {
+               pr_info("nvm: max sectors supported is 256.\n");
+               ret = -EINVAL;
+               goto err_init;
+       }
 
        if (dev->ops->max_phys_sect > 1) {
-               dev->ppalist_pool = dev->ops->create_dma_pool(dev->q,
-                                                               "ppalist");
+               dev->ppalist_pool = dev->ops->create_dma_pool(dev, "ppalist");
                if (!dev->ppalist_pool) {
                        pr_err("nvm: could not create ppa pool\n");
-                       return -ENOMEM;
+                       ret = -ENOMEM;
+                       goto err_init;
                }
-       } else if (dev->ops->max_phys_sect > 256) {
-               pr_info("nvm: max sectors supported is 256.\n");
-               return -EINVAL;
        }
 
+       /* register device with a supported media manager */
+       down_write(&nvm_lock);
+       dev->mt = nvm_init_mgr(dev);
+       list_add(&dev->devices, &nvm_devices);
+       up_write(&nvm_lock);
+
        return 0;
 err_init:
        kfree(dev);
@@ -333,19 +353,22 @@ EXPORT_SYMBOL(nvm_register);
 
 void nvm_unregister(char *disk_name)
 {
-       struct nvm_dev *dev = nvm_find_nvm_dev(disk_name);
+       struct nvm_dev *dev;
 
+       down_write(&nvm_lock);
+       dev = nvm_find_nvm_dev(disk_name);
        if (!dev) {
                pr_err("nvm: could not find device %s to unregister\n",
                                                                disk_name);
+               up_write(&nvm_lock);
                return;
        }
 
-       nvm_exit(dev);
-
-       down_write(&nvm_lock);
        list_del(&dev->devices);
        up_write(&nvm_lock);
+
+       nvm_exit(dev);
+       kfree(dev);
 }
 EXPORT_SYMBOL(nvm_unregister);
 
@@ -358,38 +381,24 @@ static int nvm_create_target(struct nvm_dev *dev,
 {
        struct nvm_ioctl_create_simple *s = &create->conf.s;
        struct request_queue *tqueue;
-       struct nvmm_type *mt;
        struct gendisk *tdisk;
        struct nvm_tgt_type *tt;
        struct nvm_target *t;
        void *targetdata;
-       int ret = 0;
 
        if (!dev->mt) {
-               /* register with device with a supported NVM manager */
-               list_for_each_entry(mt, &nvm_mgrs, list) {
-                       ret = mt->register_mgr(dev);
-                       if (ret < 0)
-                               return ret; /* initialization failed */
-                       if (ret > 0) {
-                               dev->mt = mt;
-                               break; /* successfully initialized */
-                       }
-               }
-
-               if (!ret) {
-                       pr_info("nvm: no compatible nvm manager found.\n");
-                       return -ENODEV;
-               }
+               pr_info("nvm: device has no media manager registered.\n");
+               return -ENODEV;
        }
 
+       down_write(&nvm_lock);
        tt = nvm_find_target_type(create->tgttype);
        if (!tt) {
                pr_err("nvm: target type %s not found\n", create->tgttype);
+               up_write(&nvm_lock);
                return -EINVAL;
        }
 
-       down_write(&nvm_lock);
        list_for_each_entry(t, &dev->online_targets, list) {
                if (!strcmp(create->tgtname, t->disk->disk_name)) {
                        pr_err("nvm: target name already exists.\n");
@@ -457,11 +466,11 @@ static void nvm_remove_target(struct nvm_target *t)
        lockdep_assert_held(&nvm_lock);
 
        del_gendisk(tdisk);
+       blk_cleanup_queue(q);
+
        if (tt->exit)
                tt->exit(tdisk->private_data);
 
-       blk_cleanup_queue(q);
-
        put_disk(tdisk);
 
        list_del(&t->list);
@@ -473,7 +482,9 @@ static int __nvm_configure_create(struct nvm_ioctl_create *create)
        struct nvm_dev *dev;
        struct nvm_ioctl_create_simple *s;
 
+       down_write(&nvm_lock);
        dev = nvm_find_nvm_dev(create->dev);
+       up_write(&nvm_lock);
        if (!dev) {
                pr_err("nvm: device not found\n");
                return -EINVAL;
@@ -532,7 +543,9 @@ static int nvm_configure_show(const char *val)
                return -EINVAL;
        }
 
+       down_write(&nvm_lock);
        dev = nvm_find_nvm_dev(devname);
+       up_write(&nvm_lock);
        if (!dev) {
                pr_err("nvm: device not found\n");
                return -EINVAL;
@@ -541,7 +554,7 @@ static int nvm_configure_show(const char *val)
        if (!dev->mt)
                return 0;
 
-       dev->mt->free_blocks_print(dev);
+       dev->mt->lun_info_print(dev);
 
        return 0;
 }
@@ -677,8 +690,10 @@ static long nvm_ioctl_info(struct file *file, void __user *arg)
        info->tgtsize = tgt_iter;
        up_write(&nvm_lock);
 
-       if (copy_to_user(arg, info, sizeof(struct nvm_ioctl_info)))
+       if (copy_to_user(arg, info, sizeof(struct nvm_ioctl_info))) {
+               kfree(info);
                return -EFAULT;
+       }
 
        kfree(info);
        return 0;
@@ -721,8 +736,11 @@ static long nvm_ioctl_get_devices(struct file *file, void __user *arg)
 
        devices->nr_devices = i;
 
-       if (copy_to_user(arg, devices, sizeof(struct nvm_ioctl_get_devices)))
+       if (copy_to_user(arg, devices,
+                        sizeof(struct nvm_ioctl_get_devices))) {
+               kfree(devices);
                return -EFAULT;
+       }
 
        kfree(devices);
        return 0;
index ae1fb2bdc5f44b25aecdf010afdf9894de0dfede..a54b339951a3e695bfa68e96fb6eaf2e3e451c62 100644 (file)
@@ -60,23 +60,27 @@ static int gennvm_luns_init(struct nvm_dev *dev, struct gen_nvm *gn)
                lun->vlun.lun_id = i % dev->luns_per_chnl;
                lun->vlun.chnl_id = i / dev->luns_per_chnl;
                lun->vlun.nr_free_blocks = dev->blks_per_lun;
+               lun->vlun.nr_inuse_blocks = 0;
+               lun->vlun.nr_bad_blocks = 0;
        }
        return 0;
 }
 
-static int gennvm_block_bb(u32 lun_id, void *bb_bitmap, unsigned int nr_blocks,
+static int gennvm_block_bb(struct ppa_addr ppa, int nr_blocks, u8 *blks,
                                                                void *private)
 {
        struct gen_nvm *gn = private;
-       struct gen_lun *lun = &gn->luns[lun_id];
+       struct nvm_dev *dev = gn->dev;
+       struct gen_lun *lun;
        struct nvm_block *blk;
        int i;
 
-       if (unlikely(bitmap_empty(bb_bitmap, nr_blocks)))
-               return 0;
+       lun = &gn->luns[(dev->luns_per_chnl * ppa.g.ch) + ppa.g.lun];
+
+       for (i = 0; i < nr_blocks; i++) {
+               if (blks[i] == 0)
+                       continue;
 
-       i = -1;
-       while ((i = find_next_bit(bb_bitmap, nr_blocks, i + 1)) < nr_blocks) {
                blk = &lun->vlun.blocks[i];
                if (!blk) {
                        pr_err("gennvm: BB data is out of bounds.\n");
@@ -84,6 +88,7 @@ static int gennvm_block_bb(u32 lun_id, void *bb_bitmap, unsigned int nr_blocks,
                }
 
                list_move_tail(&blk->list, &lun->bb_list);
+               lun->vlun.nr_bad_blocks++;
        }
 
        return 0;
@@ -136,6 +141,7 @@ static int gennvm_block_map(u64 slba, u32 nlb, __le64 *entries, void *private)
                        list_move_tail(&blk->list, &lun->used_list);
                        blk->type = 1;
                        lun->vlun.nr_free_blocks--;
+                       lun->vlun.nr_inuse_blocks++;
                }
        }
 
@@ -164,22 +170,32 @@ static int gennvm_blocks_init(struct nvm_dev *dev, struct gen_nvm *gn)
                        block->id = cur_block_id++;
 
                        /* First block is reserved for device */
-                       if (unlikely(lun_iter == 0 && blk_iter == 0))
+                       if (unlikely(lun_iter == 0 && blk_iter == 0)) {
+                               lun->vlun.nr_free_blocks--;
                                continue;
+                       }
 
                        list_add_tail(&block->list, &lun->free_list);
                }
 
                if (dev->ops->get_bb_tbl) {
-                       ret = dev->ops->get_bb_tbl(dev->q, lun->vlun.id,
-                                       dev->blks_per_lun, gennvm_block_bb, gn);
+                       struct ppa_addr ppa;
+
+                       ppa.ppa = 0;
+                       ppa.g.ch = lun->vlun.chnl_id;
+                       ppa.g.lun = lun->vlun.id;
+                       ppa = generic_to_dev_addr(dev, ppa);
+
+                       ret = dev->ops->get_bb_tbl(dev, ppa,
+                                               dev->blks_per_lun,
+                                               gennvm_block_bb, gn);
                        if (ret)
                                pr_err("gennvm: could not read BB table\n");
                }
        }
 
        if (dev->ops->get_l2p_tbl) {
-               ret = dev->ops->get_l2p_tbl(dev->q, 0, dev->total_pages,
+               ret = dev->ops->get_l2p_tbl(dev, 0, dev->total_pages,
                                                        gennvm_block_map, dev);
                if (ret) {
                        pr_err("gennvm: could not read L2P table.\n");
@@ -190,15 +206,27 @@ static int gennvm_blocks_init(struct nvm_dev *dev, struct gen_nvm *gn)
        return 0;
 }
 
+static void gennvm_free(struct nvm_dev *dev)
+{
+       gennvm_blocks_free(dev);
+       gennvm_luns_free(dev);
+       kfree(dev->mp);
+       dev->mp = NULL;
+}
+
 static int gennvm_register(struct nvm_dev *dev)
 {
        struct gen_nvm *gn;
        int ret;
 
+       if (!try_module_get(THIS_MODULE))
+               return -ENODEV;
+
        gn = kzalloc(sizeof(struct gen_nvm), GFP_KERNEL);
        if (!gn)
                return -ENOMEM;
 
+       gn->dev = dev;
        gn->nr_luns = dev->nr_luns;
        dev->mp = gn;
 
@@ -216,16 +244,15 @@ static int gennvm_register(struct nvm_dev *dev)
 
        return 1;
 err:
-       kfree(gn);
+       gennvm_free(dev);
+       module_put(THIS_MODULE);
        return ret;
 }
 
 static void gennvm_unregister(struct nvm_dev *dev)
 {
-       gennvm_blocks_free(dev);
-       gennvm_luns_free(dev);
-       kfree(dev->mp);
-       dev->mp = NULL;
+       gennvm_free(dev);
+       module_put(THIS_MODULE);
 }
 
 static struct nvm_block *gennvm_get_blk(struct nvm_dev *dev,
@@ -240,23 +267,21 @@ static struct nvm_block *gennvm_get_blk(struct nvm_dev *dev,
        if (list_empty(&lun->free_list)) {
                pr_err_ratelimited("gennvm: lun %u have no free pages available",
                                                                lun->vlun.id);
-               spin_unlock(&vlun->lock);
                goto out;
        }
 
-       while (!is_gc && lun->vlun.nr_free_blocks < lun->reserved_blocks) {
-               spin_unlock(&vlun->lock);
+       if (!is_gc && lun->vlun.nr_free_blocks < lun->reserved_blocks)
                goto out;
-       }
 
        blk = list_first_entry(&lun->free_list, struct nvm_block, list);
        list_move_tail(&blk->list, &lun->used_list);
        blk->type = 1;
 
        lun->vlun.nr_free_blocks--;
+       lun->vlun.nr_inuse_blocks++;
 
-       spin_unlock(&vlun->lock);
 out:
+       spin_unlock(&vlun->lock);
        return blk;
 }
 
@@ -271,16 +296,21 @@ static void gennvm_put_blk(struct nvm_dev *dev, struct nvm_block *blk)
        case 1:
                list_move_tail(&blk->list, &lun->free_list);
                lun->vlun.nr_free_blocks++;
+               lun->vlun.nr_inuse_blocks--;
                blk->type = 0;
                break;
        case 2:
                list_move_tail(&blk->list, &lun->bb_list);
+               lun->vlun.nr_bad_blocks++;
+               lun->vlun.nr_inuse_blocks--;
                break;
        default:
                WARN_ON_ONCE(1);
                pr_err("gennvm: erroneous block type (%lu -> %u)\n",
                                                        blk->id, blk->type);
                list_move_tail(&blk->list, &lun->bb_list);
+               lun->vlun.nr_bad_blocks++;
+               lun->vlun.nr_inuse_blocks--;
        }
 
        spin_unlock(&vlun->lock);
@@ -292,10 +322,10 @@ static void gennvm_addr_to_generic_mode(struct nvm_dev *dev, struct nvm_rq *rqd)
 
        if (rqd->nr_pages > 1) {
                for (i = 0; i < rqd->nr_pages; i++)
-                       rqd->ppa_list[i] = addr_to_generic_mode(dev,
+                       rqd->ppa_list[i] = dev_to_generic_addr(dev,
                                                        rqd->ppa_list[i]);
        } else {
-               rqd->ppa_addr = addr_to_generic_mode(dev, rqd->ppa_addr);
+               rqd->ppa_addr = dev_to_generic_addr(dev, rqd->ppa_addr);
        }
 }
 
@@ -305,10 +335,10 @@ static void gennvm_generic_to_addr_mode(struct nvm_dev *dev, struct nvm_rq *rqd)
 
        if (rqd->nr_pages > 1) {
                for (i = 0; i < rqd->nr_pages; i++)
-                       rqd->ppa_list[i] = generic_to_addr_mode(dev,
+                       rqd->ppa_list[i] = generic_to_dev_addr(dev,
                                                        rqd->ppa_list[i]);
        } else {
-               rqd->ppa_addr = generic_to_addr_mode(dev, rqd->ppa_addr);
+               rqd->ppa_addr = generic_to_dev_addr(dev, rqd->ppa_addr);
        }
 }
 
@@ -321,7 +351,7 @@ static int gennvm_submit_io(struct nvm_dev *dev, struct nvm_rq *rqd)
        gennvm_generic_to_addr_mode(dev, rqd);
 
        rqd->dev = dev;
-       return dev->ops->submit_io(dev->q, rqd);
+       return dev->ops->submit_io(dev, rqd);
 }
 
 static void gennvm_blk_set_type(struct nvm_dev *dev, struct ppa_addr *ppa,
@@ -354,10 +384,10 @@ static void gennvm_mark_blk_bad(struct nvm_dev *dev, struct nvm_rq *rqd)
 {
        int i;
 
-       if (!dev->ops->set_bb)
+       if (!dev->ops->set_bb_tbl)
                return;
 
-       if (dev->ops->set_bb(dev->q, rqd, 1))
+       if (dev->ops->set_bb_tbl(dev, rqd, 1))
                return;
 
        gennvm_addr_to_generic_mode(dev, rqd);
@@ -425,7 +455,7 @@ static int gennvm_erase_blk(struct nvm_dev *dev, struct nvm_block *blk,
 
        gennvm_generic_to_addr_mode(dev, &rqd);
 
-       ret = dev->ops->erase_block(dev->q, &rqd);
+       ret = dev->ops->erase_block(dev, &rqd);
 
        if (plane_cnt)
                nvm_dev_dma_free(dev, rqd.ppa_list, rqd.dma_ppa_list);
@@ -440,15 +470,24 @@ static struct nvm_lun *gennvm_get_lun(struct nvm_dev *dev, int lunid)
        return &gn->luns[lunid].vlun;
 }
 
-static void gennvm_free_blocks_print(struct nvm_dev *dev)
+static void gennvm_lun_info_print(struct nvm_dev *dev)
 {
        struct gen_nvm *gn = dev->mp;
        struct gen_lun *lun;
        unsigned int i;
 
-       gennvm_for_each_lun(gn, lun, i)
-               pr_info("%s: lun%8u\t%u\n",
-                                       dev->name, i, lun->vlun.nr_free_blocks);
+
+       gennvm_for_each_lun(gn, lun, i) {
+               spin_lock(&lun->vlun.lock);
+
+               pr_info("%s: lun%8u\t%u\t%u\t%u\n",
+                               dev->name, i,
+                               lun->vlun.nr_free_blocks,
+                               lun->vlun.nr_inuse_blocks,
+                               lun->vlun.nr_bad_blocks);
+
+               spin_unlock(&lun->vlun.lock);
+       }
 }
 
 static struct nvmm_type gennvm = {
@@ -466,7 +505,7 @@ static struct nvmm_type gennvm = {
        .erase_blk      = gennvm_erase_blk,
 
        .get_lun        = gennvm_get_lun,
-       .free_blocks_print = gennvm_free_blocks_print,
+       .lun_info_print = gennvm_lun_info_print,
 };
 
 static int __init gennvm_module_init(void)
index d23bd3501ddc4e56abc8ce177e0fd82aa94fec13..9c24b5b32dac2cb37acc39a5d7c54449296fe231 100644 (file)
@@ -35,6 +35,8 @@ struct gen_lun {
 };
 
 struct gen_nvm {
+       struct nvm_dev *dev;
+
        int nr_luns;
        struct gen_lun *luns;
 };
index 7ba64c87ba1c10306c9b96d132f0d2f869a628da..134e4faba48259434db7d55d446f40f3deb206b9 100644 (file)
@@ -123,12 +123,42 @@ static u64 block_to_addr(struct rrpc *rrpc, struct rrpc_block *rblk)
        return blk->id * rrpc->dev->pgs_per_blk;
 }
 
+static struct ppa_addr linear_to_generic_addr(struct nvm_dev *dev,
+                                                       struct ppa_addr r)
+{
+       struct ppa_addr l;
+       int secs, pgs, blks, luns;
+       sector_t ppa = r.ppa;
+
+       l.ppa = 0;
+
+       div_u64_rem(ppa, dev->sec_per_pg, &secs);
+       l.g.sec = secs;
+
+       sector_div(ppa, dev->sec_per_pg);
+       div_u64_rem(ppa, dev->sec_per_blk, &pgs);
+       l.g.pg = pgs;
+
+       sector_div(ppa, dev->pgs_per_blk);
+       div_u64_rem(ppa, dev->blks_per_lun, &blks);
+       l.g.blk = blks;
+
+       sector_div(ppa, dev->blks_per_lun);
+       div_u64_rem(ppa, dev->luns_per_chnl, &luns);
+       l.g.lun = luns;
+
+       sector_div(ppa, dev->luns_per_chnl);
+       l.g.ch = ppa;
+
+       return l;
+}
+
 static struct ppa_addr rrpc_ppa_to_gaddr(struct nvm_dev *dev, u64 addr)
 {
        struct ppa_addr paddr;
 
        paddr.ppa = addr;
-       return __linear_to_generic_addr(dev, paddr);
+       return linear_to_generic_addr(dev, paddr);
 }
 
 /* requires lun->lock taken */
@@ -152,7 +182,7 @@ static struct rrpc_block *rrpc_get_blk(struct rrpc *rrpc, struct rrpc_lun *rlun,
        struct nvm_block *blk;
        struct rrpc_block *rblk;
 
-       blk = nvm_get_blk(rrpc->dev, rlun->parent, 0);
+       blk = nvm_get_blk(rrpc->dev, rlun->parent, flags);
        if (!blk)
                return NULL;
 
@@ -172,6 +202,20 @@ static void rrpc_put_blk(struct rrpc *rrpc, struct rrpc_block *rblk)
        nvm_put_blk(rrpc->dev, rblk->parent);
 }
 
+static void rrpc_put_blks(struct rrpc *rrpc)
+{
+       struct rrpc_lun *rlun;
+       int i;
+
+       for (i = 0; i < rrpc->nr_luns; i++) {
+               rlun = &rrpc->luns[i];
+               if (rlun->cur)
+                       rrpc_put_blk(rrpc, rlun->cur);
+               if (rlun->gc_cur)
+                       rrpc_put_blk(rrpc, rlun->gc_cur);
+       }
+}
+
 static struct rrpc_lun *get_next_lun(struct rrpc *rrpc)
 {
        int next = atomic_inc_return(&rrpc->next_lun);
@@ -972,7 +1016,7 @@ static int rrpc_map_init(struct rrpc *rrpc)
                return 0;
 
        /* Bring up the mapping table from device */
-       ret = dev->ops->get_l2p_tbl(dev->q, 0, dev->total_pages,
+       ret = dev->ops->get_l2p_tbl(dev, 0, dev->total_pages,
                                                        rrpc_l2p_update, rrpc);
        if (ret) {
                pr_err("nvm: rrpc: could not read L2P table.\n");
@@ -1194,18 +1238,21 @@ static int rrpc_luns_configure(struct rrpc *rrpc)
 
                rblk = rrpc_get_blk(rrpc, rlun, 0);
                if (!rblk)
-                       return -EINVAL;
+                       goto err;
 
                rrpc_set_lun_cur(rlun, rblk);
 
                /* Emergency gc block */
                rblk = rrpc_get_blk(rrpc, rlun, 1);
                if (!rblk)
-                       return -EINVAL;
+                       goto err;
                rlun->gc_cur = rblk;
        }
 
        return 0;
+err:
+       rrpc_put_blks(rrpc);
+       return -EINVAL;
 }
 
 static struct nvm_tgt_type tt_rrpc;
index 917d47e290ae08be08f4c964a3326f1f67acd077..3147c8d09ea84a0a76d0fd7ead35931a89e29aed 100644 (file)
@@ -112,7 +112,8 @@ struct iv_tcw_private {
  * and encrypts / decrypts at the same time.
  */
 enum flags { DM_CRYPT_SUSPENDED, DM_CRYPT_KEY_VALID,
-            DM_CRYPT_SAME_CPU, DM_CRYPT_NO_OFFLOAD };
+            DM_CRYPT_SAME_CPU, DM_CRYPT_NO_OFFLOAD,
+            DM_CRYPT_EXIT_THREAD};
 
 /*
  * The fields in here must be read only after initialization.
@@ -1203,20 +1204,18 @@ continue_locked:
                if (!RB_EMPTY_ROOT(&cc->write_tree))
                        goto pop_from_list;
 
+               if (unlikely(test_bit(DM_CRYPT_EXIT_THREAD, &cc->flags))) {
+                       spin_unlock_irq(&cc->write_thread_wait.lock);
+                       break;
+               }
+
                __set_current_state(TASK_INTERRUPTIBLE);
                __add_wait_queue(&cc->write_thread_wait, &wait);
 
                spin_unlock_irq(&cc->write_thread_wait.lock);
 
-               if (unlikely(kthread_should_stop())) {
-                       set_task_state(current, TASK_RUNNING);
-                       remove_wait_queue(&cc->write_thread_wait, &wait);
-                       break;
-               }
-
                schedule();
 
-               set_task_state(current, TASK_RUNNING);
                spin_lock_irq(&cc->write_thread_wait.lock);
                __remove_wait_queue(&cc->write_thread_wait, &wait);
                goto continue_locked;
@@ -1531,8 +1530,13 @@ static void crypt_dtr(struct dm_target *ti)
        if (!cc)
                return;
 
-       if (cc->write_thread)
+       if (cc->write_thread) {
+               spin_lock_irq(&cc->write_thread_wait.lock);
+               set_bit(DM_CRYPT_EXIT_THREAD, &cc->flags);
+               wake_up_locked(&cc->write_thread_wait);
+               spin_unlock_irq(&cc->write_thread_wait.lock);
                kthread_stop(cc->write_thread);
+       }
 
        if (cc->io_queue)
                destroy_workqueue(cc->io_queue);
index aaa6caa46a9f2dbceaf3d9c1aac92037b3b731b2..cfa29f574c2a9e1454788a5757471835b254d857 100644 (file)
@@ -1537,32 +1537,34 @@ static int multipath_prepare_ioctl(struct dm_target *ti,
                struct block_device **bdev, fmode_t *mode)
 {
        struct multipath *m = ti->private;
-       struct pgpath *pgpath;
        unsigned long flags;
        int r;
 
-       r = 0;
-
        spin_lock_irqsave(&m->lock, flags);
 
        if (!m->current_pgpath)
                __choose_pgpath(m, 0);
 
-       pgpath = m->current_pgpath;
-
-       if (pgpath) {
-               *bdev = pgpath->path.dev->bdev;
-               *mode = pgpath->path.dev->mode;
+       if (m->current_pgpath) {
+               if (!m->queue_io) {
+                       *bdev = m->current_pgpath->path.dev->bdev;
+                       *mode = m->current_pgpath->path.dev->mode;
+                       r = 0;
+               } else {
+                       /* pg_init has not started or completed */
+                       r = -ENOTCONN;
+               }
+       } else {
+               /* No path is available */
+               if (m->queue_if_no_path)
+                       r = -ENOTCONN;
+               else
+                       r = -EIO;
        }
 
-       if ((pgpath && m->queue_io) || (!pgpath && m->queue_if_no_path))
-               r = -ENOTCONN;
-       else if (!*bdev)
-               r = -EIO;
-
        spin_unlock_irqrestore(&m->lock, flags);
 
-       if (r == -ENOTCONN && !fatal_signal_pending(current)) {
+       if (r == -ENOTCONN) {
                spin_lock_irqsave(&m->lock, flags);
                if (!m->current_pg) {
                        /* Path status changed, redo selection */
index 1fa45695b68a4eb6ed3db388d30f6e88f06fee21..c219a053c7f66d1ebae80a19b005af38914dbe8c 100644 (file)
@@ -1206,6 +1206,12 @@ static int __reserve_metadata_snap(struct dm_pool_metadata *pmd)
        struct dm_block *copy, *sblock;
        dm_block_t held_root;
 
+       /*
+        * We commit to ensure the btree roots which we increment in a
+        * moment are up to date.
+        */
+       __commit_transaction(pmd);
+
        /*
         * Copy the superblock.
         */
@@ -1538,7 +1544,7 @@ static int __remove(struct dm_thin_device *td, dm_block_t block)
 static int __remove_range(struct dm_thin_device *td, dm_block_t begin, dm_block_t end)
 {
        int r;
-       unsigned count;
+       unsigned count, total_count = 0;
        struct dm_pool_metadata *pmd = td->pmd;
        dm_block_t keys[1] = { td->id };
        __le64 value;
@@ -1561,11 +1567,29 @@ static int __remove_range(struct dm_thin_device *td, dm_block_t begin, dm_block_
        if (r)
                return r;
 
-       r = dm_btree_remove_leaves(&pmd->bl_info, mapping_root, &begin, end, &mapping_root, &count);
-       if (r)
-               return r;
+       /*
+        * Remove leaves stops at the first unmapped entry, so we have to
+        * loop round finding mapped ranges.
+        */
+       while (begin < end) {
+               r = dm_btree_lookup_next(&pmd->bl_info, mapping_root, &begin, &begin, &value);
+               if (r == -ENODATA)
+                       break;
+
+               if (r)
+                       return r;
+
+               if (begin >= end)
+                       break;
+
+               r = dm_btree_remove_leaves(&pmd->bl_info, mapping_root, &begin, end, &mapping_root, &count);
+               if (r)
+                       return r;
+
+               total_count += count;
+       }
 
-       td->mapped_blocks -= count;
+       td->mapped_blocks -= total_count;
        td->changed = 1;
 
        /*
index 3897b90bd462d852e0aec27a792be14655efa150..63903a5a5d9ee3b580d552673b42b9716b99322c 100644 (file)
@@ -2432,6 +2432,7 @@ static void set_pool_mode(struct pool *pool, enum pool_mode new_mode)
        case PM_WRITE:
                if (old_mode != new_mode)
                        notify_of_pool_mode_change(pool, "write");
+               pool->pf.error_if_no_space = pt->requested_pf.error_if_no_space;
                dm_pool_metadata_read_write(pool->pmd);
                pool->process_bio = process_bio;
                pool->process_discard = process_discard_bio;
@@ -4249,10 +4250,9 @@ static void thin_io_hints(struct dm_target *ti, struct queue_limits *limits)
 {
        struct thin_c *tc = ti->private;
        struct pool *pool = tc->pool;
-       struct queue_limits *pool_limits = dm_get_queue_limits(pool->pool_md);
 
-       if (!pool_limits->discard_granularity)
-               return; /* pool's discard support is disabled */
+       if (!pool->pf.discard_enabled)
+               return;
 
        limits->discard_granularity = pool->sectors_per_block << SECTOR_SHIFT;
        limits->max_discard_sectors = 2048 * 1024 * 16; /* 16G */
index 6e15f3565892fce8315cef992e0b2721e8c20088..5df40480228b7a26e3c73ac78e963ce47ed25448 100644 (file)
@@ -591,7 +591,7 @@ retry:
 
 out:
        dm_put_live_table(md, *srcu_idx);
-       if (r == -ENOTCONN) {
+       if (r == -ENOTCONN && !fatal_signal_pending(current)) {
                msleep(10);
                goto retry;
        }
@@ -603,9 +603,10 @@ static int dm_blk_ioctl(struct block_device *bdev, fmode_t mode,
 {
        struct mapped_device *md = bdev->bd_disk->private_data;
        struct dm_target *tgt;
+       struct block_device *tgt_bdev = NULL;
        int srcu_idx, r;
 
-       r = dm_get_live_table_for_ioctl(md, &tgt, &bdev, &mode, &srcu_idx);
+       r = dm_get_live_table_for_ioctl(md, &tgt, &tgt_bdev, &mode, &srcu_idx);
        if (r < 0)
                return r;
 
@@ -620,7 +621,7 @@ static int dm_blk_ioctl(struct block_device *bdev, fmode_t mode,
                        goto out;
        }
 
-       r =  __blkdev_driver_ioctl(bdev, mode, cmd, arg);
+       r =  __blkdev_driver_ioctl(tgt_bdev, mode, cmd, arg);
 out:
        dm_put_live_table(md, srcu_idx);
        return r;
index 807095f4c793bb4f1d4119f81abf2653b83240cb..61aacab424cf1860dbb5651f5a4fc6c9f7188027 100644 (file)
@@ -314,8 +314,8 @@ static blk_qc_t md_make_request(struct request_queue *q, struct bio *bio)
  */
 void mddev_suspend(struct mddev *mddev)
 {
-       BUG_ON(mddev->suspended);
-       mddev->suspended = 1;
+       if (mddev->suspended++)
+               return;
        synchronize_rcu();
        wait_event(mddev->sb_wait, atomic_read(&mddev->active_io) == 0);
        mddev->pers->quiesce(mddev, 1);
@@ -326,7 +326,8 @@ EXPORT_SYMBOL_GPL(mddev_suspend);
 
 void mddev_resume(struct mddev *mddev)
 {
-       mddev->suspended = 0;
+       if (--mddev->suspended)
+               return;
        wake_up(&mddev->sb_wait);
        mddev->pers->quiesce(mddev, 0);
 
@@ -1652,7 +1653,7 @@ static int super_1_validate(struct mddev *mddev, struct md_rdev *rdev)
                        rdev->journal_tail = le64_to_cpu(sb->journal_tail);
                        if (mddev->recovery_cp == MaxSector)
                                set_bit(MD_JOURNAL_CLEAN, &mddev->flags);
-                       rdev->raid_disk = mddev->raid_disks;
+                       rdev->raid_disk = 0;
                        break;
                default:
                        rdev->saved_raid_disk = role;
@@ -2773,6 +2774,7 @@ slot_store(struct md_rdev *rdev, const char *buf, size_t len)
                /* Activating a spare .. or possibly reactivating
                 * if we ever get bitmaps working here.
                 */
+               int err;
 
                if (rdev->raid_disk != -1)
                        return -EBUSY;
@@ -2794,9 +2796,15 @@ slot_store(struct md_rdev *rdev, const char *buf, size_t len)
                        rdev->saved_raid_disk = -1;
                clear_bit(In_sync, &rdev->flags);
                clear_bit(Bitmap_sync, &rdev->flags);
-               remove_and_add_spares(rdev->mddev, rdev);
-               if (rdev->raid_disk == -1)
-                       return -EBUSY;
+               err = rdev->mddev->pers->
+                       hot_add_disk(rdev->mddev, rdev);
+               if (err) {
+                       rdev->raid_disk = -1;
+                       return err;
+               } else
+                       sysfs_notify_dirent_safe(rdev->sysfs_state);
+               if (sysfs_link_rdev(rdev->mddev, rdev))
+                       /* failure here is OK */;
                /* don't wakeup anyone, leave that to userspace. */
        } else {
                if (slot >= rdev->mddev->raid_disks &&
@@ -4318,8 +4326,7 @@ action_store(struct mddev *mddev, const char *page, size_t len)
                        }
                        mddev_unlock(mddev);
                }
-       } else if (test_bit(MD_RECOVERY_RUNNING, &mddev->recovery) ||
-                  test_bit(MD_RECOVERY_NEEDED, &mddev->recovery))
+       } else if (test_bit(MD_RECOVERY_RUNNING, &mddev->recovery))
                return -EBUSY;
        else if (cmd_match(page, "resync"))
                clear_bit(MD_RECOVERY_FROZEN, &mddev->recovery);
@@ -4332,8 +4339,12 @@ action_store(struct mddev *mddev, const char *page, size_t len)
                        return -EINVAL;
                err = mddev_lock(mddev);
                if (!err) {
-                       clear_bit(MD_RECOVERY_FROZEN, &mddev->recovery);
-                       err = mddev->pers->start_reshape(mddev);
+                       if (test_bit(MD_RECOVERY_RUNNING, &mddev->recovery))
+                               err =  -EBUSY;
+                       else {
+                               clear_bit(MD_RECOVERY_FROZEN, &mddev->recovery);
+                               err = mddev->pers->start_reshape(mddev);
+                       }
                        mddev_unlock(mddev);
                }
                if (err)
index 2bea51edfab707645a6d6b8a5b6c79bb0c6dde64..ca0b643fe3c18070b417a66daedb571457b440ca 100644 (file)
@@ -566,7 +566,9 @@ static inline char * mdname (struct mddev * mddev)
 static inline int sysfs_link_rdev(struct mddev *mddev, struct md_rdev *rdev)
 {
        char nm[20];
-       if (!test_bit(Replacement, &rdev->flags) && mddev->kobj.sd) {
+       if (!test_bit(Replacement, &rdev->flags) &&
+           !test_bit(Journal, &rdev->flags) &&
+           mddev->kobj.sd) {
                sprintf(nm, "rd%d", rdev->raid_disk);
                return sysfs_create_link(&mddev->kobj, &rdev->kobj, nm);
        } else
@@ -576,7 +578,9 @@ static inline int sysfs_link_rdev(struct mddev *mddev, struct md_rdev *rdev)
 static inline void sysfs_unlink_rdev(struct mddev *mddev, struct md_rdev *rdev)
 {
        char nm[20];
-       if (!test_bit(Replacement, &rdev->flags) && mddev->kobj.sd) {
+       if (!test_bit(Replacement, &rdev->flags) &&
+           !test_bit(Journal, &rdev->flags) &&
+           mddev->kobj.sd) {
                sprintf(nm, "rd%d", rdev->raid_disk);
                sysfs_remove_link(&mddev->kobj, nm);
        }
index c573402033b2dd9e89dc11ad2f6e1b7e8bbb4263..b1ced58eb5e1475b440a15de0e26811fb90b8159 100644 (file)
@@ -63,6 +63,11 @@ int lower_bound(struct btree_node *n, uint64_t key)
        return bsearch(n, key, 0);
 }
 
+static int upper_bound(struct btree_node *n, uint64_t key)
+{
+       return bsearch(n, key, 1);
+}
+
 void inc_children(struct dm_transaction_manager *tm, struct btree_node *n,
                  struct dm_btree_value_type *vt)
 {
@@ -252,6 +257,16 @@ static void pop_frame(struct del_stack *s)
        dm_tm_unlock(s->tm, f->b);
 }
 
+static void unlock_all_frames(struct del_stack *s)
+{
+       struct frame *f;
+
+       while (unprocessed_frames(s)) {
+               f = s->spine + s->top--;
+               dm_tm_unlock(s->tm, f->b);
+       }
+}
+
 int dm_btree_del(struct dm_btree_info *info, dm_block_t root)
 {
        int r;
@@ -308,9 +323,13 @@ int dm_btree_del(struct dm_btree_info *info, dm_block_t root)
                        pop_frame(s);
                }
        }
-
 out:
+       if (r) {
+               /* cleanup all frames of del_stack */
+               unlock_all_frames(s);
+       }
        kfree(s);
+
        return r;
 }
 EXPORT_SYMBOL_GPL(dm_btree_del);
@@ -392,6 +411,82 @@ int dm_btree_lookup(struct dm_btree_info *info, dm_block_t root,
 }
 EXPORT_SYMBOL_GPL(dm_btree_lookup);
 
+static int dm_btree_lookup_next_single(struct dm_btree_info *info, dm_block_t root,
+                                      uint64_t key, uint64_t *rkey, void *value_le)
+{
+       int r, i;
+       uint32_t flags, nr_entries;
+       struct dm_block *node;
+       struct btree_node *n;
+
+       r = bn_read_lock(info, root, &node);
+       if (r)
+               return r;
+
+       n = dm_block_data(node);
+       flags = le32_to_cpu(n->header.flags);
+       nr_entries = le32_to_cpu(n->header.nr_entries);
+
+       if (flags & INTERNAL_NODE) {
+               i = lower_bound(n, key);
+               if (i < 0 || i >= nr_entries) {
+                       r = -ENODATA;
+                       goto out;
+               }
+
+               r = dm_btree_lookup_next_single(info, value64(n, i), key, rkey, value_le);
+               if (r == -ENODATA && i < (nr_entries - 1)) {
+                       i++;
+                       r = dm_btree_lookup_next_single(info, value64(n, i), key, rkey, value_le);
+               }
+
+       } else {
+               i = upper_bound(n, key);
+               if (i < 0 || i >= nr_entries) {
+                       r = -ENODATA;
+                       goto out;
+               }
+
+               *rkey = le64_to_cpu(n->keys[i]);
+               memcpy(value_le, value_ptr(n, i), info->value_type.size);
+       }
+out:
+       dm_tm_unlock(info->tm, node);
+       return r;
+}
+
+int dm_btree_lookup_next(struct dm_btree_info *info, dm_block_t root,
+                        uint64_t *keys, uint64_t *rkey, void *value_le)
+{
+       unsigned level;
+       int r = -ENODATA;
+       __le64 internal_value_le;
+       struct ro_spine spine;
+
+       init_ro_spine(&spine, info);
+       for (level = 0; level < info->levels - 1u; level++) {
+               r = btree_lookup_raw(&spine, root, keys[level],
+                                    lower_bound, rkey,
+                                    &internal_value_le, sizeof(uint64_t));
+               if (r)
+                       goto out;
+
+               if (*rkey != keys[level]) {
+                       r = -ENODATA;
+                       goto out;
+               }
+
+               root = le64_to_cpu(internal_value_le);
+       }
+
+       r = dm_btree_lookup_next_single(info, root, keys[level], rkey, value_le);
+out:
+       exit_ro_spine(&spine);
+       return r;
+}
+
+EXPORT_SYMBOL_GPL(dm_btree_lookup_next);
+
 /*
  * Splits a node by creating a sibling node and shifting half the nodes
  * contents across.  Assumes there is a parent node, and it has room for
@@ -473,8 +568,10 @@ static int btree_split_sibling(struct shadow_spine *s, unsigned parent_index,
 
        r = insert_at(sizeof(__le64), pn, parent_index + 1,
                      le64_to_cpu(rn->keys[0]), &location);
-       if (r)
+       if (r) {
+               unlock_block(s->info, right);
                return r;
+       }
 
        if (key < le64_to_cpu(rn->keys[0])) {
                unlock_block(s->info, right);
index 11d8cf78621dded80328187e1009ca0dc35c6997..c74301fa5a379517b9c37e7e98ab380d97f3b9b0 100644 (file)
@@ -109,6 +109,13 @@ int dm_btree_del(struct dm_btree_info *info, dm_block_t root);
 int dm_btree_lookup(struct dm_btree_info *info, dm_block_t root,
                    uint64_t *keys, void *value_le);
 
+/*
+ * Tries to find the first key where the bottom level key is >= to that
+ * given.  Useful for skipping empty sections of the btree.
+ */
+int dm_btree_lookup_next(struct dm_btree_info *info, dm_block_t root,
+                        uint64_t *keys, uint64_t *rkey, void *value_le);
+
 /*
  * Insertion (or overwrite an existing value).  O(ln(n))
  */
@@ -135,9 +142,10 @@ int dm_btree_remove(struct dm_btree_info *info, dm_block_t root,
                    uint64_t *keys, dm_block_t *new_root);
 
 /*
- * Removes values between 'keys' and keys2, where keys2 is keys with the
- * final key replaced with 'end_key'.  'end_key' is the one-past-the-end
- * value.  'keys' may be altered.
+ * Removes a _contiguous_ run of values starting from 'keys' and not
+ * reaching keys2 (where keys2 is keys with the final key replaced with
+ * 'end_key').  'end_key' is the one-past-the-end value.  'keys' may be
+ * altered.
  */
 int dm_btree_remove_leaves(struct dm_btree_info *info, dm_block_t root,
                           uint64_t *keys, uint64_t end_key,
index 53091295fce9b7d9ffec9b91a6a0bdddd20ed67f..fca6dbcf9a4727f85d61f7d161094870f5db24d5 100644 (file)
@@ -136,7 +136,7 @@ static int brb_push(struct bop_ring_buffer *brb,
        return 0;
 }
 
-static int brb_pop(struct bop_ring_buffer *brb, struct block_op *result)
+static int brb_peek(struct bop_ring_buffer *brb, struct block_op *result)
 {
        struct block_op *bop;
 
@@ -147,6 +147,17 @@ static int brb_pop(struct bop_ring_buffer *brb, struct block_op *result)
        result->type = bop->type;
        result->block = bop->block;
 
+       return 0;
+}
+
+static int brb_pop(struct bop_ring_buffer *brb)
+{
+       struct block_op *bop;
+
+       if (brb_empty(brb))
+               return -ENODATA;
+
+       bop = brb->bops + brb->begin;
        brb->begin = brb_next(brb, brb->begin);
 
        return 0;
@@ -211,7 +222,7 @@ static int apply_bops(struct sm_metadata *smm)
        while (!brb_empty(&smm->uncommitted)) {
                struct block_op bop;
 
-               r = brb_pop(&smm->uncommitted, &bop);
+               r = brb_peek(&smm->uncommitted, &bop);
                if (r) {
                        DMERR("bug in bop ring buffer");
                        break;
@@ -220,6 +231,8 @@ static int apply_bops(struct sm_metadata *smm)
                r = commit_bop(smm, &bop);
                if (r)
                        break;
+
+               brb_pop(&smm->uncommitted);
        }
 
        return r;
@@ -683,7 +696,6 @@ static struct dm_space_map bootstrap_ops = {
 static int sm_metadata_extend(struct dm_space_map *sm, dm_block_t extra_blocks)
 {
        int r, i;
-       enum allocation_event ev;
        struct sm_metadata *smm = container_of(sm, struct sm_metadata, sm);
        dm_block_t old_len = smm->ll.nr_blocks;
 
@@ -705,11 +717,12 @@ static int sm_metadata_extend(struct dm_space_map *sm, dm_block_t extra_blocks)
         * allocate any new blocks.
         */
        do {
-               for (i = old_len; !r && i < smm->begin; i++) {
-                       r = sm_ll_inc(&smm->ll, i, &ev);
-                       if (r)
-                               goto out;
-               }
+               for (i = old_len; !r && i < smm->begin; i++)
+                       r = add_bop(smm, BOP_INC, i);
+
+               if (r)
+                       goto out;
+
                old_len = smm->begin;
 
                r = apply_bops(smm);
@@ -754,7 +767,6 @@ int dm_sm_metadata_create(struct dm_space_map *sm,
 {
        int r;
        dm_block_t i;
-       enum allocation_event ev;
        struct sm_metadata *smm = container_of(sm, struct sm_metadata, sm);
 
        smm->begin = superblock + 1;
@@ -782,7 +794,7 @@ int dm_sm_metadata_create(struct dm_space_map *sm,
         * allocated blocks that they were built from.
         */
        for (i = superblock; !r && i < smm->begin; i++)
-               r = sm_ll_inc(&smm->ll, i, &ev);
+               r = add_bop(smm, BOP_INC, i);
 
        if (r)
                return r;
index 41d70bc9ba2f879a2549868861afb74471140525..84e597e1c4890cd911243c511d1a65e39232e98e 100644 (file)
@@ -1946,6 +1946,8 @@ static void sync_request_write(struct mddev *mddev, struct r10bio *r10_bio)
 
        first = i;
        fbio = r10_bio->devs[i].bio;
+       fbio->bi_iter.bi_size = r10_bio->sectors << 9;
+       fbio->bi_iter.bi_idx = 0;
 
        vcnt = (r10_bio->sectors + (PAGE_SIZE >> 9) - 1) >> (PAGE_SHIFT - 9);
        /* now find blocks with errors */
@@ -1989,7 +1991,7 @@ static void sync_request_write(struct mddev *mddev, struct r10bio *r10_bio)
                bio_reset(tbio);
 
                tbio->bi_vcnt = vcnt;
-               tbio->bi_iter.bi_size = r10_bio->sectors << 9;
+               tbio->bi_iter.bi_size = fbio->bi_iter.bi_size;
                tbio->bi_rw = WRITE;
                tbio->bi_private = r10_bio;
                tbio->bi_iter.bi_sector = r10_bio->devs[i].addr;
index 35759a91d47dce2eaede0d0491910aeb0180cab7..e8f847226a199f308394302b1f24dacf186b6226 100644 (file)
@@ -1992,9 +1992,9 @@ static int cx23885_initdev(struct pci_dev *pci_dev,
                (unsigned long long)pci_resource_start(pci_dev, 0));
 
        pci_set_master(pci_dev);
-       if (!pci_set_dma_mask(pci_dev, 0xffffffff)) {
+       err = pci_set_dma_mask(pci_dev, 0xffffffff);
+       if (err) {
                printk("%s/0: Oops: no 32bit PCI DMA ???\n", dev->name);
-               err = -EIO;
                goto fail_context;
        }
 
index dbc695f327607285162a6f6482582f5fe1857ff8..0042803a9de7c4aaa0eabb375eaf58ccb3056f88 100644 (file)
@@ -1319,7 +1319,8 @@ static int cx25821_initdev(struct pci_dev *pci_dev,
                dev->pci_lat, (unsigned long long)dev->base_io_addr);
 
        pci_set_master(pci_dev);
-       if (!pci_set_dma_mask(pci_dev, 0xffffffff)) {
+       err = pci_set_dma_mask(pci_dev, 0xffffffff);
+       if (err) {
                pr_err("%s/0: Oops: no 32bit PCI DMA ???\n", dev->name);
                err = -EIO;
                goto fail_irq;
index 0ed1b65303746d3b5129997dc37dd00cbe784716..1b5268f9bb248f5b0787d16e707c25b84ffbe150 100644 (file)
@@ -890,9 +890,9 @@ static int snd_cx88_create(struct snd_card *card, struct pci_dev *pci,
                return err;
        }
 
-       if (!pci_set_dma_mask(pci,DMA_BIT_MASK(32))) {
+       err = pci_set_dma_mask(pci,DMA_BIT_MASK(32));
+       if (err) {
                dprintk(0, "%s/1: Oops: no 32bit PCI DMA ???\n",core->name);
-               err = -EIO;
                cx88_core_put(core, pci);
                return err;
        }
index 9db7767d1fe03eaad3244993d193f1045cb5f92b..f34c229f9b374d3dedd424bb54bc2119b0ee0607 100644 (file)
@@ -393,7 +393,8 @@ static int cx8802_init_common(struct cx8802_dev *dev)
        if (pci_enable_device(dev->pci))
                return -EIO;
        pci_set_master(dev->pci);
-       if (!pci_set_dma_mask(dev->pci,DMA_BIT_MASK(32))) {
+       err = pci_set_dma_mask(dev->pci,DMA_BIT_MASK(32));
+       if (err) {
                printk("%s/2: Oops: no 32bit PCI DMA ???\n",dev->core->name);
                return -EIO;
        }
index 0de1ad5a977d4d7b629819bb2d0ee0fb54539bb3..aef9acf351f6379017f967538a87d103fc7b7a94 100644 (file)
@@ -1314,9 +1314,9 @@ static int cx8800_initdev(struct pci_dev *pci_dev,
               dev->pci_lat,(unsigned long long)pci_resource_start(pci_dev,0));
 
        pci_set_master(pci_dev);
-       if (!pci_set_dma_mask(pci_dev,DMA_BIT_MASK(32))) {
+       err = pci_set_dma_mask(pci_dev,DMA_BIT_MASK(32));
+       if (err) {
                printk("%s/0: Oops: no 32bit PCI DMA ???\n",core->name);
-               err = -EIO;
                goto fail_core;
        }
        dev->alloc_ctx = vb2_dma_sg_init_ctx(&pci_dev->dev);
index 8616fa8193bca06bb806dc48b14d4e7dc6e21aef..c2e60b4f292d1d8d9791b5c44b0fa76c0ffd854b 100644 (file)
@@ -805,11 +805,11 @@ static void ivtv_init_struct2(struct ivtv *itv)
 {
        int i;
 
-       for (i = 0; i < IVTV_CARD_MAX_VIDEO_INPUTS - 1; i++)
+       for (i = 0; i < IVTV_CARD_MAX_VIDEO_INPUTS; i++)
                if (itv->card->video_inputs[i].video_type == 0)
                        break;
        itv->nof_inputs = i;
-       for (i = 0; i < IVTV_CARD_MAX_AUDIO_INPUTS - 1; i++)
+       for (i = 0; i < IVTV_CARD_MAX_AUDIO_INPUTS; i++)
                if (itv->card->audio_inputs[i].audio_type == 0)
                        break;
        itv->nof_audio_inputs = i;
index 60b2d462f98d0ea92a3738d45919dce57c3c9daf..3fdbd81b558060c1029c6bf621a45d2aa9fd9016 100644 (file)
@@ -810,7 +810,7 @@ static int netup_unidvb_initdev(struct pci_dev *pci_dev,
                "%s(): board vendor 0x%x, revision 0x%x\n",
                __func__, board_vendor, board_revision);
        pci_set_master(pci_dev);
-       if (!pci_set_dma_mask(pci_dev, 0xffffffff)) {
+       if (pci_set_dma_mask(pci_dev, 0xffffffff) < 0) {
                dev_err(&pci_dev->dev,
                        "%s(): 32bit PCI DMA is not supported\n", __func__);
                goto pci_detect_err;
index e79d63eb774e338898584ee33fa8476b0cb5b2cf..f720cea80e28ae553183c16a56d2620dd70ab303 100644 (file)
@@ -951,9 +951,9 @@ static int saa7134_initdev(struct pci_dev *pci_dev,
               pci_name(pci_dev), dev->pci_rev, pci_dev->irq,
               dev->pci_lat,(unsigned long long)pci_resource_start(pci_dev,0));
        pci_set_master(pci_dev);
-       if (!pci_set_dma_mask(pci_dev, DMA_BIT_MASK(32))) {
+       err = pci_set_dma_mask(pci_dev, DMA_BIT_MASK(32));
+       if (err) {
                pr_warn("%s: Oops: no 32bit PCI DMA ???\n", dev->name);
-               err = -EIO;
                goto fail1;
        }
 
index 8f36b48ef7338c13ae265f9d424e05348d389f6f..8bbd092fbe1db70052857584f598c3d0192236f3 100644 (file)
@@ -1264,9 +1264,9 @@ static int saa7164_initdev(struct pci_dev *pci_dev,
 
        pci_set_master(pci_dev);
        /* TODO */
-       if (!pci_set_dma_mask(pci_dev, 0xffffffff)) {
+       err = pci_set_dma_mask(pci_dev, 0xffffffff);
+       if (err) {
                printk("%s/0: Oops: no 32bit PCI DMA ???\n", dev->name);
-               err = -EIO;
                goto fail_irq;
        }
 
index 8c5655d351d35c4d1b82ca8f84390c32f31b0306..4e77618fbb2b9aa742de7bdcc218ab1f5feb7f3d 100644 (file)
@@ -257,9 +257,9 @@ static int tw68_initdev(struct pci_dev *pci_dev,
                dev->name, pci_name(pci_dev), dev->pci_rev, pci_dev->irq,
                dev->pci_lat, (u64)pci_resource_start(pci_dev, 0));
        pci_set_master(pci_dev);
-       if (!pci_set_dma_mask(pci_dev, DMA_BIT_MASK(32))) {
+       err = pci_set_dma_mask(pci_dev, DMA_BIT_MASK(32));
+       if (err) {
                pr_info("%s: Oops: no 32bit PCI DMA ???\n", dev->name);
-               err = -EIO;
                goto fail1;
        }
 
index fcbb49757614487aa0a88e2740bc0dcd4ff73236..565a59310747680858bb2bf30543e05becd579a0 100644 (file)
@@ -134,7 +134,7 @@ struct airspy {
        int            urbs_submitted;
 
        /* USB control message buffer */
-       #define BUF_SIZE 24
+       #define BUF_SIZE 128
        u8 buf[BUF_SIZE];
 
        /* Current configuration */
index e05bfec90f4608b0d8ebce199351dfe89db11994..0fe5cb2c260c2f771484d99bf25809cc23943ffb 100644 (file)
 #include <media/videobuf2-v4l2.h>
 #include <media/videobuf2-vmalloc.h>
 
+/*
+ * Used Avago MGA-81563 RF amplifier could be destroyed pretty easily with too
+ * strong signal or transmitting to bad antenna.
+ * Set RF gain control to 'grabbed' state by default for sure.
+ */
+static bool hackrf_enable_rf_gain_ctrl;
+module_param_named(enable_rf_gain_ctrl, hackrf_enable_rf_gain_ctrl, bool, 0644);
+MODULE_PARM_DESC(enable_rf_gain_ctrl, "enable RX/TX RF amplifier control (warn: could damage amplifier)");
+
 /* HackRF USB API commands (from HackRF Library) */
 enum {
        CMD_SET_TRANSCEIVER_MODE           = 0x01,
@@ -1451,6 +1460,7 @@ static int hackrf_probe(struct usb_interface *intf,
                dev_err(dev->dev, "Could not initialize controls\n");
                goto err_v4l2_ctrl_handler_free_rx;
        }
+       v4l2_ctrl_grab(dev->rx_rf_gain, !hackrf_enable_rf_gain_ctrl);
        v4l2_ctrl_handler_setup(&dev->rx_ctrl_handler);
 
        /* Register controls for transmitter */
@@ -1471,6 +1481,7 @@ static int hackrf_probe(struct usb_interface *intf,
                dev_err(dev->dev, "Could not initialize controls\n");
                goto err_v4l2_ctrl_handler_free_tx;
        }
+       v4l2_ctrl_grab(dev->tx_rf_gain, !hackrf_enable_rf_gain_ctrl);
        v4l2_ctrl_handler_setup(&dev->tx_ctrl_handler);
 
        /* Register the v4l2_device structure */
@@ -1530,7 +1541,7 @@ err_v4l2_ctrl_handler_free_rx:
 err_kfree:
        kfree(dev);
 err:
-       dev_dbg(dev->dev, "failed=%d\n", ret);
+       dev_dbg(&intf->dev, "failed=%d\n", ret);
        return ret;
 }
 
index e87459f6d686d011d6d11f902b78053f083e1b7a..acd1460cf7871c4ef4cffb0f0e196f41083aae36 100644 (file)
@@ -22,6 +22,7 @@
 #include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/compiler.h>
+#include <linux/sched.h>
 #include <linux/spinlock.h>
 #include <linux/types.h>
 #include <linux/slab.h>
index d2e75c88f4d2165762913c27c57e5d4487e431ad..f4090979349068b3057d0cd9d8a17d15168ce734 100644 (file)
@@ -497,6 +497,7 @@ static u64 calculate_sr(struct cxl_context *ctx)
 {
        u64 sr = 0;
 
+       set_endian(sr);
        if (ctx->master)
                sr |= CXL_PSL_SR_An_MP;
        if (mfspr(SPRN_LPCR) & LPCR_TC)
@@ -506,7 +507,6 @@ static u64 calculate_sr(struct cxl_context *ctx)
                sr |= CXL_PSL_SR_An_HV;
        } else {
                sr |= CXL_PSL_SR_An_PR | CXL_PSL_SR_An_R;
-               set_endian(sr);
                sr &= ~(CXL_PSL_SR_An_HV);
                if (!test_tsk_thread_flag(current, TIF_32BIT))
                        sr |= CXL_PSL_SR_An_SF;
index 23b6c8e8701ccd6e3ec57c85483276de4b02f51b..d8486168415ae1123f6a31d7126cfc9192fe884b 100644 (file)
@@ -65,8 +65,7 @@ MODULE_ALIAS("mmc:block");
 #define MMC_SANITIZE_REQ_TIMEOUT 240000
 #define MMC_EXTRACT_INDEX_FROM_ARG(x) ((x & 0x00FF0000) >> 16)
 
-#define mmc_req_rel_wr(req)    (((req->cmd_flags & REQ_FUA) || \
-                                 (req->cmd_flags & REQ_META)) && \
+#define mmc_req_rel_wr(req)    ((req->cmd_flags & REQ_FUA) && \
                                  (rq_data_dir(req) == WRITE))
 #define PACKED_CMD_VER 0x01
 #define PACKED_CMD_WR  0x02
@@ -1467,13 +1466,9 @@ static void mmc_blk_rw_rq_prep(struct mmc_queue_req *mqrq,
 
        /*
         * Reliable writes are used to implement Forced Unit Access and
-        * REQ_META accesses, and are supported only on MMCs.
-        *
-        * XXX: this really needs a good explanation of why REQ_META
-        * is treated special.
+        * are supported only on MMCs.
         */
-       bool do_rel_wr = ((req->cmd_flags & REQ_FUA) ||
-                         (req->cmd_flags & REQ_META)) &&
+       bool do_rel_wr = (req->cmd_flags & REQ_FUA) &&
                (rq_data_dir(req) == WRITE) &&
                (md->flags & MMC_BLK_REL_WR);
 
index c793fda27321da0086bb01d92e33d9aa44480ed0..3a9a79ec4343cd0f9f71158768e5707340def684 100644 (file)
@@ -1040,9 +1040,24 @@ static int mmc_select_hs_ddr(struct mmc_card *card)
        return err;
 }
 
+/* Caller must hold re-tuning */
+static int mmc_switch_status(struct mmc_card *card)
+{
+       u32 status;
+       int err;
+
+       err = mmc_send_status(card, &status);
+       if (err)
+               return err;
+
+       return mmc_switch_status_error(card->host, status);
+}
+
 static int mmc_select_hs400(struct mmc_card *card)
 {
        struct mmc_host *host = card->host;
+       bool send_status = true;
+       unsigned int max_dtr;
        int err = 0;
        u8 val;
 
@@ -1053,25 +1068,36 @@ static int mmc_select_hs400(struct mmc_card *card)
              host->ios.bus_width == MMC_BUS_WIDTH_8))
                return 0;
 
-       /*
-        * Before switching to dual data rate operation for HS400,
-        * it is required to convert from HS200 mode to HS mode.
-        */
-       mmc_set_timing(card->host, MMC_TIMING_MMC_HS);
-       mmc_set_bus_speed(card);
+       if (host->caps & MMC_CAP_WAIT_WHILE_BUSY)
+               send_status = false;
 
+       /* Reduce frequency to HS frequency */
+       max_dtr = card->ext_csd.hs_max_dtr;
+       mmc_set_clock(host, max_dtr);
+
+       /* Switch card to HS mode */
        val = EXT_CSD_TIMING_HS |
              card->drive_strength << EXT_CSD_DRV_STR_SHIFT;
        err = __mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
                           EXT_CSD_HS_TIMING, val,
                           card->ext_csd.generic_cmd6_time,
-                          true, true, true);
+                          true, send_status, true);
        if (err) {
                pr_err("%s: switch to high-speed from hs200 failed, err:%d\n",
                        mmc_hostname(host), err);
                return err;
        }
 
+       /* Set host controller to HS timing */
+       mmc_set_timing(card->host, MMC_TIMING_MMC_HS);
+
+       if (!send_status) {
+               err = mmc_switch_status(card);
+               if (err)
+                       goto out_err;
+       }
+
+       /* Switch card to DDR */
        err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
                         EXT_CSD_BUS_WIDTH,
                         EXT_CSD_DDR_BUS_WIDTH_8,
@@ -1082,22 +1108,35 @@ static int mmc_select_hs400(struct mmc_card *card)
                return err;
        }
 
+       /* Switch card to HS400 */
        val = EXT_CSD_TIMING_HS400 |
              card->drive_strength << EXT_CSD_DRV_STR_SHIFT;
        err = __mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
                           EXT_CSD_HS_TIMING, val,
                           card->ext_csd.generic_cmd6_time,
-                          true, true, true);
+                          true, send_status, true);
        if (err) {
                pr_err("%s: switch to hs400 failed, err:%d\n",
                         mmc_hostname(host), err);
                return err;
        }
 
+       /* Set host controller to HS400 timing and frequency */
        mmc_set_timing(host, MMC_TIMING_MMC_HS400);
        mmc_set_bus_speed(card);
 
+       if (!send_status) {
+               err = mmc_switch_status(card);
+               if (err)
+                       goto out_err;
+       }
+
        return 0;
+
+out_err:
+       pr_err("%s: %s failed, error %d\n", mmc_hostname(card->host),
+              __func__, err);
+       return err;
 }
 
 int mmc_hs200_to_hs400(struct mmc_card *card)
@@ -1105,19 +1144,6 @@ int mmc_hs200_to_hs400(struct mmc_card *card)
        return mmc_select_hs400(card);
 }
 
-/* Caller must hold re-tuning */
-static int mmc_switch_status(struct mmc_card *card)
-{
-       u32 status;
-       int err;
-
-       err = mmc_send_status(card, &status);
-       if (err)
-               return err;
-
-       return mmc_switch_status_error(card->host, status);
-}
-
 int mmc_hs400_to_hs200(struct mmc_card *card)
 {
        struct mmc_host *host = card->host;
@@ -1219,6 +1245,8 @@ static void mmc_select_driver_type(struct mmc_card *card)
 static int mmc_select_hs200(struct mmc_card *card)
 {
        struct mmc_host *host = card->host;
+       bool send_status = true;
+       unsigned int old_timing;
        int err = -EINVAL;
        u8 val;
 
@@ -1234,6 +1262,9 @@ static int mmc_select_hs200(struct mmc_card *card)
 
        mmc_select_driver_type(card);
 
+       if (host->caps & MMC_CAP_WAIT_WHILE_BUSY)
+               send_status = false;
+
        /*
         * Set the bus width(4 or 8) with host's support and
         * switch to HS200 mode if bus width is set successfully.
@@ -1245,11 +1276,25 @@ static int mmc_select_hs200(struct mmc_card *card)
                err = __mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
                                   EXT_CSD_HS_TIMING, val,
                                   card->ext_csd.generic_cmd6_time,
-                                  true, true, true);
-               if (!err)
-                       mmc_set_timing(host, MMC_TIMING_MMC_HS200);
+                                  true, send_status, true);
+               if (err)
+                       goto err;
+               old_timing = host->ios.timing;
+               mmc_set_timing(host, MMC_TIMING_MMC_HS200);
+               if (!send_status) {
+                       err = mmc_switch_status(card);
+                       /*
+                        * mmc_select_timing() assumes timing has not changed if
+                        * it is a switch error.
+                        */
+                       if (err == -EBADMSG)
+                               mmc_set_timing(host, old_timing);
+               }
        }
 err:
+       if (err)
+               pr_err("%s: %s failed, error %d\n", mmc_hostname(card->host),
+                      __func__, err);
        return err;
 }
 
index af71de5fda3b48c99fefd122a0cb6df9af2234ac..1dee533634c986d71176917f4d510a4c7214bf5a 100644 (file)
@@ -473,6 +473,7 @@ config MMC_DAVINCI
 
 config MMC_GOLDFISH
        tristate "goldfish qemu Multimedia Card Interface support"
+       depends on HAS_DMA
        depends on GOLDFISH || COMPILE_TEST
        help
          This selects the Goldfish Multimedia card Interface emulation
index 39568cc29a2a18cf752141dcf6233746b4d149e1..33dfd7e72516c3920b7ec641efb930668f0e15f5 100644 (file)
@@ -1276,7 +1276,7 @@ static struct msdc_delay_phase get_best_delay(struct msdc_host *host, u32 delay)
        int start = 0, len = 0;
        int start_final = 0, len_final = 0;
        u8 final_phase = 0xff;
-       struct msdc_delay_phase delay_phase;
+       struct msdc_delay_phase delay_phase = { 0, };
 
        if (delay == 0) {
                dev_err(host->dev, "phase error: [map:%x]\n", delay);
index 8cadd74e8407bb08d7e277a82ac5d80d496f77e4..ce08896b9d696b00440fe7807aeddf72b922f320 100644 (file)
@@ -805,7 +805,7 @@ static int pxamci_probe(struct platform_device *pdev)
                goto out;
        } else {
                mmc->caps |= host->pdata->gpio_card_ro_invert ?
-                       MMC_CAP2_RO_ACTIVE_HIGH : 0;
+                       0 : MMC_CAP2_RO_ACTIVE_HIGH;
        }
 
        if (gpio_is_valid(gpio_cd))
index dc4e8446f1ff10b55acf6c40a4cb0ac662cf2b06..5a99a93ed02568f5778f9a55d6a7c4ed6b44cadd 100644 (file)
@@ -25,6 +25,7 @@
 
 #include <linux/gpio.h>
 
+#include <asm/mach-jz4740/gpio.h>
 #include <asm/mach-jz4740/jz4740_nand.h>
 
 #define JZ_REG_NAND_CTRL       0x50
index cc74142938b0a21410cc76e0adca5a58aa1ce26f..ece544efccc3af3a46d73f0825f2ce797d401ae6 100644 (file)
@@ -3110,7 +3110,7 @@ static void nand_resume(struct mtd_info *mtd)
  */
 static void nand_shutdown(struct mtd_info *mtd)
 {
-       nand_get_device(mtd, FL_SHUTDOWN);
+       nand_get_device(mtd, FL_PM_SUSPENDED);
 }
 
 /* Set default functions */
index 669c3452f278fb0e365570872893855c9ce21e2c..9ed6038e47d210df74ec678de7cf8220797bf815 100644 (file)
@@ -46,10 +46,18 @@ static int parse_ofpart_partitions(struct mtd_info *master,
 
        ofpart_node = of_get_child_by_name(mtd_node, "partitions");
        if (!ofpart_node) {
-               pr_warn("%s: 'partitions' subnode not found on %s. Trying to parse direct subnodes as partitions.\n",
-                       master->name, mtd_node->full_name);
+               /*
+                * We might get here even when ofpart isn't used at all (e.g.,
+                * when using another parser), so don't be louder than
+                * KERN_DEBUG
+                */
+               pr_debug("%s: 'partitions' subnode not found on %s. Trying to parse direct subnodes as partitions.\n",
+                        master->name, mtd_node->full_name);
                ofpart_node = mtd_node;
                dedicated = false;
+       } else if (!of_device_is_compatible(ofpart_node, "fixed-partitions")) {
+               /* The 'partitions' subnode might be used by another parser */
+               return 0;
        }
 
        /* First count the subnodes */
index b077e43b5ba913b2ba208ed54673c3fe291afc66..c4cb15a3098c0933f607e4f0cba170e978f910ff 100644 (file)
@@ -236,7 +236,7 @@ int ubi_debugfs_init(void)
 
        dfs_rootdir = debugfs_create_dir("ubi", NULL);
        if (IS_ERR_OR_NULL(dfs_rootdir)) {
-               int err = dfs_rootdir ? -ENODEV : PTR_ERR(dfs_rootdir);
+               int err = dfs_rootdir ? PTR_ERR(dfs_rootdir) : -ENODEV;
 
                pr_err("UBI error: cannot create \"ubi\" debugfs directory, error %d\n",
                       err);
index 1fc23e48fe8e49fc947c972cca179399a60a37ec..10cf3b549959ce46f9c517b77fbcdd84e274a3d2 100644 (file)
@@ -1299,7 +1299,7 @@ static int self_check_peb_vid_hdr(const struct ubi_device *ubi, int pnum)
        if (err && err != UBI_IO_BITFLIPS && !mtd_is_eccerr(err))
                goto exit;
 
-       crc = crc32(UBI_CRC32_INIT, vid_hdr, UBI_EC_HDR_SIZE_CRC);
+       crc = crc32(UBI_CRC32_INIT, vid_hdr, UBI_VID_HDR_SIZE_CRC);
        hdr_crc = be32_to_cpu(vid_hdr->hdr_crc);
        if (hdr_crc != crc) {
                ubi_err(ubi, "bad VID header CRC at PEB %d, calculated %#08x, read %#08x",
index eb4489f9082fe84345d2ec68b0f8723888e5c177..56065632a5b85ebf50022f883e1edc968a069f93 100644 (file)
@@ -603,6 +603,7 @@ static int schedule_erase(struct ubi_device *ubi, struct ubi_wl_entry *e,
        return 0;
 }
 
+static int __erase_worker(struct ubi_device *ubi, struct ubi_work *wl_wrk);
 /**
  * do_sync_erase - run the erase worker synchronously.
  * @ubi: UBI device description object
@@ -615,20 +616,16 @@ static int schedule_erase(struct ubi_device *ubi, struct ubi_wl_entry *e,
 static int do_sync_erase(struct ubi_device *ubi, struct ubi_wl_entry *e,
                         int vol_id, int lnum, int torture)
 {
-       struct ubi_work *wl_wrk;
+       struct ubi_work wl_wrk;
 
        dbg_wl("sync erase of PEB %i", e->pnum);
 
-       wl_wrk = kmalloc(sizeof(struct ubi_work), GFP_NOFS);
-       if (!wl_wrk)
-               return -ENOMEM;
-
-       wl_wrk->e = e;
-       wl_wrk->vol_id = vol_id;
-       wl_wrk->lnum = lnum;
-       wl_wrk->torture = torture;
+       wl_wrk.e = e;
+       wl_wrk.vol_id = vol_id;
+       wl_wrk.lnum = lnum;
+       wl_wrk.torture = torture;
 
-       return erase_worker(ubi, wl_wrk, 0);
+       return __erase_worker(ubi, &wl_wrk);
 }
 
 /**
@@ -1014,7 +1011,7 @@ out_unlock:
 }
 
 /**
- * erase_worker - physical eraseblock erase worker function.
+ * __erase_worker - physical eraseblock erase worker function.
  * @ubi: UBI device description object
  * @wl_wrk: the work object
  * @shutdown: non-zero if the worker has to free memory and exit
@@ -1025,8 +1022,7 @@ out_unlock:
  * needed. Returns zero in case of success and a negative error code in case of
  * failure.
  */
-static int erase_worker(struct ubi_device *ubi, struct ubi_work *wl_wrk,
-                       int shutdown)
+static int __erase_worker(struct ubi_device *ubi, struct ubi_work *wl_wrk)
 {
        struct ubi_wl_entry *e = wl_wrk->e;
        int pnum = e->pnum;
@@ -1034,21 +1030,11 @@ static int erase_worker(struct ubi_device *ubi, struct ubi_work *wl_wrk,
        int lnum = wl_wrk->lnum;
        int err, available_consumed = 0;
 
-       if (shutdown) {
-               dbg_wl("cancel erasure of PEB %d EC %d", pnum, e->ec);
-               kfree(wl_wrk);
-               wl_entry_destroy(ubi, e);
-               return 0;
-       }
-
        dbg_wl("erase PEB %d EC %d LEB %d:%d",
               pnum, e->ec, wl_wrk->vol_id, wl_wrk->lnum);
 
        err = sync_erase(ubi, e, wl_wrk->torture);
        if (!err) {
-               /* Fine, we've erased it successfully */
-               kfree(wl_wrk);
-
                spin_lock(&ubi->wl_lock);
                wl_tree_add(e, &ubi->free);
                ubi->free_count++;
@@ -1066,7 +1052,6 @@ static int erase_worker(struct ubi_device *ubi, struct ubi_work *wl_wrk,
        }
 
        ubi_err(ubi, "failed to erase PEB %d, error %d", pnum, err);
-       kfree(wl_wrk);
 
        if (err == -EINTR || err == -ENOMEM || err == -EAGAIN ||
            err == -EBUSY) {
@@ -1075,6 +1060,7 @@ static int erase_worker(struct ubi_device *ubi, struct ubi_work *wl_wrk,
                /* Re-schedule the LEB for erasure */
                err1 = schedule_erase(ubi, e, vol_id, lnum, 0);
                if (err1) {
+                       wl_entry_destroy(ubi, e);
                        err = err1;
                        goto out_ro;
                }
@@ -1150,6 +1136,25 @@ out_ro:
        return err;
 }
 
+static int erase_worker(struct ubi_device *ubi, struct ubi_work *wl_wrk,
+                         int shutdown)
+{
+       int ret;
+
+       if (shutdown) {
+               struct ubi_wl_entry *e = wl_wrk->e;
+
+               dbg_wl("cancel erasure of PEB %d EC %d", e->pnum, e->ec);
+               kfree(wl_wrk);
+               wl_entry_destroy(ubi, e);
+               return 0;
+       }
+
+       ret = __erase_worker(ubi, wl_wrk);
+       kfree(wl_wrk);
+       return ret;
+}
+
 /**
  * ubi_wl_put_peb - return a PEB to the wear-leveling sub-system.
  * @ubi: UBI device description object
index 57dadd52b428a536d71f2364c006641e5e765083..1deb8ff90a89528e147b42353500d1610ff4a285 100644 (file)
@@ -501,8 +501,6 @@ static int bfin_can_err(struct net_device *dev, u16 isrc, u16 status)
                        cf->data[2] |= CAN_ERR_PROT_FORM;
                else if (status & SER)
                        cf->data[2] |= CAN_ERR_PROT_STUFF;
-               else
-                       cf->data[2] |= CAN_ERR_PROT_UNSPEC;
        }
 
        priv->can.state = state;
index 5d214d1353320856cf3de91d837b910df3f3de24..f91b094288dad3d86064f24a33a97ad58756f3ca 100644 (file)
@@ -962,7 +962,6 @@ static int c_can_handle_bus_err(struct net_device *dev,
         * type of the last error to occur on the CAN bus
         */
        cf->can_id |= CAN_ERR_PROT | CAN_ERR_BUSERROR;
-       cf->data[2] |= CAN_ERR_PROT_UNSPEC;
 
        switch (lec_type) {
        case LEC_STUFF_ERROR:
@@ -975,8 +974,7 @@ static int c_can_handle_bus_err(struct net_device *dev,
                break;
        case LEC_ACK_ERROR:
                netdev_dbg(dev, "ack error\n");
-               cf->data[3] |= (CAN_ERR_PROT_LOC_ACK |
-                               CAN_ERR_PROT_LOC_ACK_DEL);
+               cf->data[3] = CAN_ERR_PROT_LOC_ACK;
                break;
        case LEC_BIT1_ERROR:
                netdev_dbg(dev, "bit1 error\n");
@@ -988,8 +986,7 @@ static int c_can_handle_bus_err(struct net_device *dev,
                break;
        case LEC_CRC_ERROR:
                netdev_dbg(dev, "CRC error\n");
-               cf->data[3] |= (CAN_ERR_PROT_LOC_CRC_SEQ |
-                               CAN_ERR_PROT_LOC_CRC_DEL);
+               cf->data[3] = CAN_ERR_PROT_LOC_CRC_SEQ;
                break;
        default:
                break;
index 70a8cbb29e75844a02bea49a937bf0c05a200910..1e37313054f3950ee30e6c6fccad874d9262013a 100644 (file)
@@ -578,7 +578,7 @@ static int cc770_err(struct net_device *dev, u8 status)
                                cf->data[2] |= CAN_ERR_PROT_BIT0;
                                break;
                        case STAT_LEC_CRC:
-                               cf->data[3] |= CAN_ERR_PROT_LOC_CRC_SEQ;
+                               cf->data[3] = CAN_ERR_PROT_LOC_CRC_SEQ;
                                break;
                        }
                }
index 868fe945e35a39786bf15fb8b142c36a720179a5..41c0fc9f3b1465d9dbbde6b5c7798b1e40cf43ef 100644 (file)
@@ -535,13 +535,13 @@ static void do_bus_err(struct net_device *dev,
        if (reg_esr & FLEXCAN_ESR_ACK_ERR) {
                netdev_dbg(dev, "ACK_ERR irq\n");
                cf->can_id |= CAN_ERR_ACK;
-               cf->data[3] |= CAN_ERR_PROT_LOC_ACK;
+               cf->data[3] = CAN_ERR_PROT_LOC_ACK;
                tx_errors = 1;
        }
        if (reg_esr & FLEXCAN_ESR_CRC_ERR) {
                netdev_dbg(dev, "CRC_ERR irq\n");
                cf->data[2] |= CAN_ERR_PROT_BIT;
-               cf->data[3] |= CAN_ERR_PROT_LOC_CRC_SEQ;
+               cf->data[3] = CAN_ERR_PROT_LOC_CRC_SEQ;
                rx_errors = 1;
        }
        if (reg_esr & FLEXCAN_ESR_FRM_ERR) {
index c1e85368a198bd898f853c5842c58fbb3b01b04b..5d04f5464faf29a8b1c99dcc8bae86becbd1c485 100644 (file)
@@ -1096,7 +1096,6 @@ static int ican3_handle_cevtind(struct ican3_dev *mod, struct ican3_msg *msg)
                        cf->data[2] |= CAN_ERR_PROT_STUFF;
                        break;
                default:
-                       cf->data[2] |= CAN_ERR_PROT_UNSPEC;
                        cf->data[3] = ecc & ECC_SEG;
                        break;
                }
index ef655177bb5e5b62a7be1f821d08a88226ba7b84..39cf911f7a1e3c364d7818bdc6bcd162a6490951 100644 (file)
@@ -487,7 +487,6 @@ static int m_can_handle_lec_err(struct net_device *dev,
         * type of the last error to occur on the CAN bus
         */
        cf->can_id |= CAN_ERR_PROT | CAN_ERR_BUSERROR;
-       cf->data[2] |= CAN_ERR_PROT_UNSPEC;
 
        switch (lec_type) {
        case LEC_STUFF_ERROR:
@@ -500,8 +499,7 @@ static int m_can_handle_lec_err(struct net_device *dev,
                break;
        case LEC_ACK_ERROR:
                netdev_dbg(dev, "ack error\n");
-               cf->data[3] |= (CAN_ERR_PROT_LOC_ACK |
-                               CAN_ERR_PROT_LOC_ACK_DEL);
+               cf->data[3] = CAN_ERR_PROT_LOC_ACK;
                break;
        case LEC_BIT1_ERROR:
                netdev_dbg(dev, "bit1 error\n");
@@ -513,8 +511,7 @@ static int m_can_handle_lec_err(struct net_device *dev,
                break;
        case LEC_CRC_ERROR:
                netdev_dbg(dev, "CRC error\n");
-               cf->data[3] |= (CAN_ERR_PROT_LOC_CRC_SEQ |
-                               CAN_ERR_PROT_LOC_CRC_DEL);
+               cf->data[3] = CAN_ERR_PROT_LOC_CRC_SEQ;
                break;
        default:
                break;
index e187ca783da0946def7585ff8d85ac76ea201e05..c1317889d3d8d97858604feeb63fa4f7cec8a368 100644 (file)
@@ -559,8 +559,7 @@ static void pch_can_error(struct net_device *ndev, u32 status)
                stats->rx_errors++;
                break;
        case PCH_CRC_ERR:
-               cf->data[3] |= CAN_ERR_PROT_LOC_CRC_SEQ |
-                              CAN_ERR_PROT_LOC_CRC_DEL;
+               cf->data[3] = CAN_ERR_PROT_LOC_CRC_SEQ;
                priv->can.can_stats.bus_error++;
                stats->rx_errors++;
                break;
index 7bd54191f962a4ad3079eabdcefb0d001a14bf0b..bc46be39549d2ab317862ba376ccb063be65b7be 100644 (file)
@@ -241,17 +241,16 @@ static void rcar_can_error(struct net_device *ndev)
                u8 ecsr;
 
                netdev_dbg(priv->ndev, "Bus error interrupt:\n");
-               if (skb) {
+               if (skb)
                        cf->can_id |= CAN_ERR_BUSERROR | CAN_ERR_PROT;
-                       cf->data[2] = CAN_ERR_PROT_UNSPEC;
-               }
+
                ecsr = readb(&priv->regs->ecsr);
                if (ecsr & RCAR_CAN_ECSR_ADEF) {
                        netdev_dbg(priv->ndev, "ACK Delimiter Error\n");
                        tx_errors++;
                        writeb(~RCAR_CAN_ECSR_ADEF, &priv->regs->ecsr);
                        if (skb)
-                               cf->data[3] |= CAN_ERR_PROT_LOC_ACK_DEL;
+                               cf->data[3] = CAN_ERR_PROT_LOC_ACK_DEL;
                }
                if (ecsr & RCAR_CAN_ECSR_BE0F) {
                        netdev_dbg(priv->ndev, "Bit Error (dominant)\n");
@@ -272,7 +271,7 @@ static void rcar_can_error(struct net_device *ndev)
                        rx_errors++;
                        writeb(~RCAR_CAN_ECSR_CEF, &priv->regs->ecsr);
                        if (skb)
-                               cf->data[3] |= CAN_ERR_PROT_LOC_CRC_SEQ;
+                               cf->data[3] = CAN_ERR_PROT_LOC_CRC_SEQ;
                }
                if (ecsr & RCAR_CAN_ECSR_AEF) {
                        netdev_dbg(priv->ndev, "ACK Error\n");
@@ -280,7 +279,7 @@ static void rcar_can_error(struct net_device *ndev)
                        writeb(~RCAR_CAN_ECSR_AEF, &priv->regs->ecsr);
                        if (skb) {
                                cf->can_id |= CAN_ERR_ACK;
-                               cf->data[3] |= CAN_ERR_PROT_LOC_ACK;
+                               cf->data[3] = CAN_ERR_PROT_LOC_ACK;
                        }
                }
                if (ecsr & RCAR_CAN_ECSR_FEF) {
index 7b92e911a6168badb3e30f8fc55b2e6fdd0f61dc..8dda3b703d39a1e82ce7fc6a63707e883d235313 100644 (file)
@@ -218,6 +218,9 @@ static void sja1000_start(struct net_device *dev)
        priv->write_reg(priv, SJA1000_RXERR, 0x0);
        priv->read_reg(priv, SJA1000_ECC);
 
+       /* clear interrupt flags */
+       priv->read_reg(priv, SJA1000_IR);
+
        /* leave reset mode */
        set_normal_mode(dev);
 }
@@ -446,7 +449,6 @@ static int sja1000_err(struct net_device *dev, uint8_t isrc, uint8_t status)
                        cf->data[2] |= CAN_ERR_PROT_STUFF;
                        break;
                default:
-                       cf->data[2] |= CAN_ERR_PROT_UNSPEC;
                        cf->data[3] = ecc & ECC_SEG;
                        break;
                }
index d9a42c6467836cdf3aa00adc1d5a4f059b97469e..68ef0a4cd82153cd65699ab0a4d80a5a201393e6 100644 (file)
@@ -575,7 +575,6 @@ static int sun4i_can_err(struct net_device *dev, u8 isrc, u8 status)
                                cf->data[2] |= CAN_ERR_PROT_STUFF;
                                break;
                        default:
-                               cf->data[2] |= CAN_ERR_PROT_UNSPEC;
                                cf->data[3] = (ecc & SUN4I_STA_ERR_SEG_CODE)
                                               >> 16;
                                break;
index cf345cbfe8198ef23ee328fc2eb67f5841751ee1..680d1ff07a55ddd60ceb09eb42bb98faaa42ad9f 100644 (file)
@@ -722,7 +722,6 @@ static int ti_hecc_error(struct net_device *ndev, int int_status,
        if (err_status & HECC_BUS_ERROR) {
                ++priv->can.can_stats.bus_error;
                cf->can_id |= CAN_ERR_BUSERROR | CAN_ERR_PROT;
-               cf->data[2] |= CAN_ERR_PROT_UNSPEC;
                if (err_status & HECC_CANES_FE) {
                        hecc_set_bit(priv, HECC_CANES, HECC_CANES_FE);
                        cf->data[2] |= CAN_ERR_PROT_FORM;
@@ -737,13 +736,11 @@ static int ti_hecc_error(struct net_device *ndev, int int_status,
                }
                if (err_status & HECC_CANES_CRCE) {
                        hecc_set_bit(priv, HECC_CANES, HECC_CANES_CRCE);
-                       cf->data[3] |= CAN_ERR_PROT_LOC_CRC_SEQ |
-                                       CAN_ERR_PROT_LOC_CRC_DEL;
+                       cf->data[3] = CAN_ERR_PROT_LOC_CRC_SEQ;
                }
                if (err_status & HECC_CANES_ACKE) {
                        hecc_set_bit(priv, HECC_CANES, HECC_CANES_ACKE);
-                       cf->data[3] |= CAN_ERR_PROT_LOC_ACK |
-                                       CAN_ERR_PROT_LOC_ACK_DEL;
+                       cf->data[3] = CAN_ERR_PROT_LOC_ACK;
                }
        }
 
index 2d390384ef3bb3d3845fcf6102bef70715f1dd21..fc5b75675cd8b6dbebbbc79d357001676900fefa 100644 (file)
@@ -377,7 +377,6 @@ static void ems_usb_rx_err(struct ems_usb *dev, struct ems_cpc_msg *msg)
                        cf->data[2] |= CAN_ERR_PROT_STUFF;
                        break;
                default:
-                       cf->data[2] |= CAN_ERR_PROT_UNSPEC;
                        cf->data[3] = ecc & SJA1000_ECC_SEG;
                        break;
                }
index 0e5a4493ba4fee6d3c4fb5626a676f18802a6ef3..113e64fcd73be9a16635f0029ed3c6d0c2a17306 100644 (file)
@@ -282,7 +282,6 @@ static void esd_usb2_rx_event(struct esd_usb2_net_priv *priv,
                                cf->data[2] |= CAN_ERR_PROT_STUFF;
                                break;
                        default:
-                               cf->data[2] |= CAN_ERR_PROT_UNSPEC;
                                cf->data[3] = ecc & SJA1000_ECC_SEG;
                                break;
                        }
index 8b17a9065b0b193a0c5e5a93048c637f0f7fbad3..022bfa13ebfa0c85491cfc2cb17a3437c01f0205 100644 (file)
@@ -944,10 +944,9 @@ static void kvaser_usb_rx_error(const struct kvaser_usb *dev,
                        cf->can_id |= CAN_ERR_BUSERROR | CAN_ERR_PROT;
 
                        if (es->leaf.error_factor & M16C_EF_ACKE)
-                               cf->data[3] |= (CAN_ERR_PROT_LOC_ACK);
+                               cf->data[3] = CAN_ERR_PROT_LOC_ACK;
                        if (es->leaf.error_factor & M16C_EF_CRCE)
-                               cf->data[3] |= (CAN_ERR_PROT_LOC_CRC_SEQ |
-                                               CAN_ERR_PROT_LOC_CRC_DEL);
+                               cf->data[3] = CAN_ERR_PROT_LOC_CRC_SEQ;
                        if (es->leaf.error_factor & M16C_EF_FORME)
                                cf->data[2] |= CAN_ERR_PROT_FORM;
                        if (es->leaf.error_factor & M16C_EF_STFE)
index de95b1ccba3e3b6d4d00e313acb280cd178a000d..a731720f1d132501d12d6241ccee833ae2e61787 100644 (file)
@@ -401,9 +401,7 @@ static void usb_8dev_rx_err_msg(struct usb_8dev_priv *priv,
                tx_errors = 1;
                break;
        case USB_8DEV_STATUSMSG_CRC:
-               cf->data[2] |= CAN_ERR_PROT_UNSPEC;
-               cf->data[3] |= CAN_ERR_PROT_LOC_CRC_SEQ |
-                              CAN_ERR_PROT_LOC_CRC_DEL;
+               cf->data[3] = CAN_ERR_PROT_LOC_CRC_SEQ;
                rx_errors = 1;
                break;
        case USB_8DEV_STATUSMSG_BIT0:
index fc55e8e0351dfe5f3ca436d8aed64bf6d660db84..51670b322409b6606736751dae23433e1d165500 100644 (file)
@@ -608,17 +608,15 @@ static void xcan_err_interrupt(struct net_device *ndev, u32 isr)
 
        /* Check for error interrupt */
        if (isr & XCAN_IXR_ERROR_MASK) {
-               if (skb) {
+               if (skb)
                        cf->can_id |= CAN_ERR_PROT | CAN_ERR_BUSERROR;
-                       cf->data[2] |= CAN_ERR_PROT_UNSPEC;
-               }
 
                /* Check for Ack error interrupt */
                if (err_status & XCAN_ESR_ACKER_MASK) {
                        stats->tx_errors++;
                        if (skb) {
                                cf->can_id |= CAN_ERR_ACK;
-                               cf->data[3] |= CAN_ERR_PROT_LOC_ACK;
+                               cf->data[3] = CAN_ERR_PROT_LOC_ACK;
                        }
                }
 
@@ -654,8 +652,7 @@ static void xcan_err_interrupt(struct net_device *ndev, u32 isr)
                        stats->rx_errors++;
                        if (skb) {
                                cf->can_id |= CAN_ERR_PROT;
-                               cf->data[3] = CAN_ERR_PROT_LOC_CRC_SEQ |
-                                               CAN_ERR_PROT_LOC_CRC_DEL;
+                               cf->data[3] = CAN_ERR_PROT_LOC_CRC_SEQ;
                        }
                }
                        priv->can.can_stats.bus_error++;
index 9093577755f69bac2c548518922b1b63215a62a6..0527f485c3dc7c4d1cc689a7707820af993bc68f 100644 (file)
@@ -15,9 +15,7 @@
 #include <linux/netdevice.h>
 #include <linux/phy.h>
 #include <net/dsa.h>
-
-#define REG_PORT(p)            (8 + (p))
-#define REG_GLOBAL             0x0f
+#include "mv88e6060.h"
 
 static int reg_read(struct dsa_switch *ds, int addr, int reg)
 {
@@ -67,13 +65,14 @@ static char *mv88e6060_probe(struct device *host_dev, int sw_addr)
        if (bus == NULL)
                return NULL;
 
-       ret = mdiobus_read(bus, sw_addr + REG_PORT(0), 0x03);
+       ret = mdiobus_read(bus, sw_addr + REG_PORT(0), PORT_SWITCH_ID);
        if (ret >= 0) {
-               if (ret == 0x0600)
+               if (ret == PORT_SWITCH_ID_6060)
                        return "Marvell 88E6060 (A0)";
-               if (ret == 0x0601 || ret == 0x0602)
+               if (ret == PORT_SWITCH_ID_6060_R1 ||
+                   ret == PORT_SWITCH_ID_6060_R2)
                        return "Marvell 88E6060 (B0)";
-               if ((ret & 0xfff0) == 0x0600)
+               if ((ret & PORT_SWITCH_ID_6060_MASK) == PORT_SWITCH_ID_6060)
                        return "Marvell 88E6060";
        }
 
@@ -87,22 +86,26 @@ static int mv88e6060_switch_reset(struct dsa_switch *ds)
        unsigned long timeout;
 
        /* Set all ports to the disabled state. */
-       for (i = 0; i < 6; i++) {
-               ret = REG_READ(REG_PORT(i), 0x04);
-               REG_WRITE(REG_PORT(i), 0x04, ret & 0xfffc);
+       for (i = 0; i < MV88E6060_PORTS; i++) {
+               ret = REG_READ(REG_PORT(i), PORT_CONTROL);
+               REG_WRITE(REG_PORT(i), PORT_CONTROL,
+                         ret & ~PORT_CONTROL_STATE_MASK);
        }
 
        /* Wait for transmit queues to drain. */
        usleep_range(2000, 4000);
 
        /* Reset the switch. */
-       REG_WRITE(REG_GLOBAL, 0x0a, 0xa130);
+       REG_WRITE(REG_GLOBAL, GLOBAL_ATU_CONTROL,
+                 GLOBAL_ATU_CONTROL_SWRESET |
+                 GLOBAL_ATU_CONTROL_ATUSIZE_1024 |
+                 GLOBAL_ATU_CONTROL_ATE_AGE_5MIN);
 
        /* Wait up to one second for reset to complete. */
        timeout = jiffies + 1 * HZ;
        while (time_before(jiffies, timeout)) {
-               ret = REG_READ(REG_GLOBAL, 0x00);
-               if ((ret & 0x8000) == 0x0000)
+               ret = REG_READ(REG_GLOBAL, GLOBAL_STATUS);
+               if (ret & GLOBAL_STATUS_INIT_READY)
                        break;
 
                usleep_range(1000, 2000);
@@ -119,13 +122,15 @@ static int mv88e6060_setup_global(struct dsa_switch *ds)
         * set the maximum frame size to 1536 bytes, and mask all
         * interrupt sources.
         */
-       REG_WRITE(REG_GLOBAL, 0x04, 0x0800);
+       REG_WRITE(REG_GLOBAL, GLOBAL_CONTROL, GLOBAL_CONTROL_MAX_FRAME_1536);
 
        /* Enable automatic address learning, set the address
         * database size to 1024 entries, and set the default aging
         * time to 5 minutes.
         */
-       REG_WRITE(REG_GLOBAL, 0x0a, 0x2130);
+       REG_WRITE(REG_GLOBAL, GLOBAL_ATU_CONTROL,
+                 GLOBAL_ATU_CONTROL_ATUSIZE_1024 |
+                 GLOBAL_ATU_CONTROL_ATE_AGE_5MIN);
 
        return 0;
 }
@@ -139,25 +144,30 @@ static int mv88e6060_setup_port(struct dsa_switch *ds, int p)
         * state to Forwarding.  Additionally, if this is the CPU
         * port, enable Ingress and Egress Trailer tagging mode.
         */
-       REG_WRITE(addr, 0x04, dsa_is_cpu_port(ds, p) ?  0x4103 : 0x0003);
+       REG_WRITE(addr, PORT_CONTROL,
+                 dsa_is_cpu_port(ds, p) ?
+                       PORT_CONTROL_TRAILER |
+                       PORT_CONTROL_INGRESS_MODE |
+                       PORT_CONTROL_STATE_FORWARDING :
+                       PORT_CONTROL_STATE_FORWARDING);
 
        /* Port based VLAN map: give each port its own address
         * database, allow the CPU port to talk to each of the 'real'
         * ports, and allow each of the 'real' ports to only talk to
         * the CPU port.
         */
-       REG_WRITE(addr, 0x06,
-                       ((p & 0xf) << 12) |
-                        (dsa_is_cpu_port(ds, p) ?
-                               ds->phys_port_mask :
-                               (1 << ds->dst->cpu_port)));
+       REG_WRITE(addr, PORT_VLAN_MAP,
+                 ((p & 0xf) << PORT_VLAN_MAP_DBNUM_SHIFT) |
+                  (dsa_is_cpu_port(ds, p) ?
+                       ds->phys_port_mask :
+                       BIT(ds->dst->cpu_port)));
 
        /* Port Association Vector: when learning source addresses
         * of packets, add the address to the address database using
         * a port bitmap that has only the bit for this port set and
         * the other bits clear.
         */
-       REG_WRITE(addr, 0x0b, 1 << p);
+       REG_WRITE(addr, PORT_ASSOC_VECTOR, BIT(p));
 
        return 0;
 }
@@ -177,7 +187,7 @@ static int mv88e6060_setup(struct dsa_switch *ds)
        if (ret < 0)
                return ret;
 
-       for (i = 0; i < 6; i++) {
+       for (i = 0; i < MV88E6060_PORTS; i++) {
                ret = mv88e6060_setup_port(ds, i);
                if (ret < 0)
                        return ret;
@@ -188,16 +198,17 @@ static int mv88e6060_setup(struct dsa_switch *ds)
 
 static int mv88e6060_set_addr(struct dsa_switch *ds, u8 *addr)
 {
-       REG_WRITE(REG_GLOBAL, 0x01, (addr[0] << 8) | addr[1]);
-       REG_WRITE(REG_GLOBAL, 0x02, (addr[2] << 8) | addr[3]);
-       REG_WRITE(REG_GLOBAL, 0x03, (addr[4] << 8) | addr[5]);
+       /* Use the same MAC Address as FD Pause frames for all ports */
+       REG_WRITE(REG_GLOBAL, GLOBAL_MAC_01, (addr[0] << 9) | addr[1]);
+       REG_WRITE(REG_GLOBAL, GLOBAL_MAC_23, (addr[2] << 8) | addr[3]);
+       REG_WRITE(REG_GLOBAL, GLOBAL_MAC_45, (addr[4] << 8) | addr[5]);
 
        return 0;
 }
 
 static int mv88e6060_port_to_phy_addr(int port)
 {
-       if (port >= 0 && port <= 5)
+       if (port >= 0 && port < MV88E6060_PORTS)
                return port;
        return -1;
 }
@@ -225,54 +236,6 @@ mv88e6060_phy_write(struct dsa_switch *ds, int port, int regnum, u16 val)
        return reg_write(ds, addr, regnum, val);
 }
 
-static void mv88e6060_poll_link(struct dsa_switch *ds)
-{
-       int i;
-
-       for (i = 0; i < DSA_MAX_PORTS; i++) {
-               struct net_device *dev;
-               int uninitialized_var(port_status);
-               int link;
-               int speed;
-               int duplex;
-               int fc;
-
-               dev = ds->ports[i];
-               if (dev == NULL)
-                       continue;
-
-               link = 0;
-               if (dev->flags & IFF_UP) {
-                       port_status = reg_read(ds, REG_PORT(i), 0x00);
-                       if (port_status < 0)
-                               continue;
-
-                       link = !!(port_status & 0x1000);
-               }
-
-               if (!link) {
-                       if (netif_carrier_ok(dev)) {
-                               netdev_info(dev, "link down\n");
-                               netif_carrier_off(dev);
-                       }
-                       continue;
-               }
-
-               speed = (port_status & 0x0100) ? 100 : 10;
-               duplex = (port_status & 0x0200) ? 1 : 0;
-               fc = ((port_status & 0xc000) == 0xc000) ? 1 : 0;
-
-               if (!netif_carrier_ok(dev)) {
-                       netdev_info(dev,
-                                   "link up, %d Mb/s, %s duplex, flow control %sabled\n",
-                                   speed,
-                                   duplex ? "full" : "half",
-                                   fc ? "en" : "dis");
-                       netif_carrier_on(dev);
-               }
-       }
-}
-
 static struct dsa_switch_driver mv88e6060_switch_driver = {
        .tag_protocol   = DSA_TAG_PROTO_TRAILER,
        .probe          = mv88e6060_probe,
@@ -280,7 +243,6 @@ static struct dsa_switch_driver mv88e6060_switch_driver = {
        .set_addr       = mv88e6060_set_addr,
        .phy_read       = mv88e6060_phy_read,
        .phy_write      = mv88e6060_phy_write,
-       .poll_link      = mv88e6060_poll_link,
 };
 
 static int __init mv88e6060_init(void)
diff --git a/drivers/net/dsa/mv88e6060.h b/drivers/net/dsa/mv88e6060.h
new file mode 100644 (file)
index 0000000..cc9b2ed
--- /dev/null
@@ -0,0 +1,111 @@
+/*
+ * drivers/net/dsa/mv88e6060.h - Marvell 88e6060 switch chip support
+ * Copyright (c) 2015 Neil Armstrong
+ *
+ * Based on mv88e6xxx.h
+ * Copyright (c) 2008 Marvell Semiconductor
+ *
+ * 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 __MV88E6060_H
+#define __MV88E6060_H
+
+#define MV88E6060_PORTS        6
+
+#define REG_PORT(p)            (0x8 + (p))
+#define PORT_STATUS            0x00
+#define PORT_STATUS_PAUSE_EN   BIT(15)
+#define PORT_STATUS_MY_PAUSE   BIT(14)
+#define PORT_STATUS_FC         (PORT_STATUS_MY_PAUSE | PORT_STATUS_PAUSE_EN)
+#define PORT_STATUS_RESOLVED   BIT(13)
+#define PORT_STATUS_LINK       BIT(12)
+#define PORT_STATUS_PORTMODE   BIT(11)
+#define PORT_STATUS_PHYMODE    BIT(10)
+#define PORT_STATUS_DUPLEX     BIT(9)
+#define PORT_STATUS_SPEED      BIT(8)
+#define PORT_SWITCH_ID         0x03
+#define PORT_SWITCH_ID_6060    0x0600
+#define PORT_SWITCH_ID_6060_MASK       0xfff0
+#define PORT_SWITCH_ID_6060_R1 0x0601
+#define PORT_SWITCH_ID_6060_R2 0x0602
+#define PORT_CONTROL           0x04
+#define PORT_CONTROL_FORCE_FLOW_CTRL   BIT(15)
+#define PORT_CONTROL_TRAILER   BIT(14)
+#define PORT_CONTROL_HEADER    BIT(11)
+#define PORT_CONTROL_INGRESS_MODE      BIT(8)
+#define PORT_CONTROL_VLAN_TUNNEL       BIT(7)
+#define PORT_CONTROL_STATE_MASK        0x03
+#define PORT_CONTROL_STATE_DISABLED    0x00
+#define PORT_CONTROL_STATE_BLOCKING    0x01
+#define PORT_CONTROL_STATE_LEARNING    0x02
+#define PORT_CONTROL_STATE_FORWARDING  0x03
+#define PORT_VLAN_MAP          0x06
+#define PORT_VLAN_MAP_DBNUM_SHIFT      12
+#define PORT_VLAN_MAP_TABLE_MASK       0x1f
+#define PORT_ASSOC_VECTOR      0x0b
+#define PORT_ASSOC_VECTOR_MONITOR      BIT(15)
+#define PORT_ASSOC_VECTOR_PAV_MASK     0x1f
+#define PORT_RX_CNTR           0x10
+#define PORT_TX_CNTR           0x11
+
+#define REG_GLOBAL             0x0f
+#define GLOBAL_STATUS          0x00
+#define GLOBAL_STATUS_SW_MODE_MASK     (0x3 << 12)
+#define GLOBAL_STATUS_SW_MODE_0        (0x0 << 12)
+#define GLOBAL_STATUS_SW_MODE_1        (0x1 << 12)
+#define GLOBAL_STATUS_SW_MODE_2        (0x2 << 12)
+#define GLOBAL_STATUS_SW_MODE_3        (0x3 << 12)
+#define GLOBAL_STATUS_INIT_READY       BIT(11)
+#define GLOBAL_STATUS_ATU_FULL         BIT(3)
+#define GLOBAL_STATUS_ATU_DONE         BIT(2)
+#define GLOBAL_STATUS_PHY_INT  BIT(1)
+#define GLOBAL_STATUS_EEINT    BIT(0)
+#define GLOBAL_MAC_01          0x01
+#define GLOBAL_MAC_01_DIFF_ADDR        BIT(8)
+#define GLOBAL_MAC_23          0x02
+#define GLOBAL_MAC_45          0x03
+#define GLOBAL_CONTROL         0x04
+#define GLOBAL_CONTROL_DISCARD_EXCESS  BIT(13)
+#define GLOBAL_CONTROL_MAX_FRAME_1536  BIT(10)
+#define GLOBAL_CONTROL_RELOAD_EEPROM   BIT(9)
+#define GLOBAL_CONTROL_CTRMODE         BIT(8)
+#define GLOBAL_CONTROL_ATU_FULL_EN     BIT(3)
+#define GLOBAL_CONTROL_ATU_DONE_EN     BIT(2)
+#define GLOBAL_CONTROL_PHYINT_EN       BIT(1)
+#define GLOBAL_CONTROL_EEPROM_DONE_EN  BIT(0)
+#define GLOBAL_ATU_CONTROL     0x0a
+#define GLOBAL_ATU_CONTROL_SWRESET     BIT(15)
+#define GLOBAL_ATU_CONTROL_LEARNDIS    BIT(14)
+#define GLOBAL_ATU_CONTROL_ATUSIZE_256 (0x0 << 12)
+#define GLOBAL_ATU_CONTROL_ATUSIZE_512 (0x1 << 12)
+#define GLOBAL_ATU_CONTROL_ATUSIZE_1024        (0x2 << 12)
+#define GLOBAL_ATU_CONTROL_ATE_AGE_SHIFT       4
+#define GLOBAL_ATU_CONTROL_ATE_AGE_MASK        (0xff << 4)
+#define GLOBAL_ATU_CONTROL_ATE_AGE_5MIN        (0x13 << 4)
+#define GLOBAL_ATU_OP          0x0b
+#define GLOBAL_ATU_OP_BUSY     BIT(15)
+#define GLOBAL_ATU_OP_NOP              (0 << 12)
+#define GLOBAL_ATU_OP_FLUSH_ALL        ((1 << 12) | GLOBAL_ATU_OP_BUSY)
+#define GLOBAL_ATU_OP_FLUSH_UNLOCKED   ((2 << 12) | GLOBAL_ATU_OP_BUSY)
+#define GLOBAL_ATU_OP_LOAD_DB          ((3 << 12) | GLOBAL_ATU_OP_BUSY)
+#define GLOBAL_ATU_OP_GET_NEXT_DB      ((4 << 12) | GLOBAL_ATU_OP_BUSY)
+#define GLOBAL_ATU_OP_FLUSH_DB         ((5 << 12) | GLOBAL_ATU_OP_BUSY)
+#define GLOBAL_ATU_OP_FLUSH_UNLOCKED_DB ((6 << 12) | GLOBAL_ATU_OP_BUSY)
+#define GLOBAL_ATU_DATA                0x0c
+#define GLOBAL_ATU_DATA_PORT_VECTOR_MASK       0x3f0
+#define GLOBAL_ATU_DATA_PORT_VECTOR_SHIFT      4
+#define GLOBAL_ATU_DATA_STATE_MASK             0x0f
+#define GLOBAL_ATU_DATA_STATE_UNUSED           0x00
+#define GLOBAL_ATU_DATA_STATE_UC_STATIC                0x0e
+#define GLOBAL_ATU_DATA_STATE_UC_LOCKED                0x0f
+#define GLOBAL_ATU_DATA_STATE_MC_STATIC                0x07
+#define GLOBAL_ATU_DATA_STATE_MC_LOCKED                0x0e
+#define GLOBAL_ATU_MAC_01      0x0d
+#define GLOBAL_ATU_MAC_23      0x0e
+#define GLOBAL_ATU_MAC_45      0x0f
+
+#endif
index 05aa7597dab9b712de711f61c2d14e8bd0e992e6..31c5e476fd648fff18a9a4701ba0b214656e45db 100644 (file)
@@ -29,6 +29,7 @@ source "drivers/net/ethernet/apm/Kconfig"
 source "drivers/net/ethernet/apple/Kconfig"
 source "drivers/net/ethernet/arc/Kconfig"
 source "drivers/net/ethernet/atheros/Kconfig"
+source "drivers/net/ethernet/aurora/Kconfig"
 source "drivers/net/ethernet/cadence/Kconfig"
 source "drivers/net/ethernet/adi/Kconfig"
 source "drivers/net/ethernet/broadcom/Kconfig"
@@ -78,7 +79,6 @@ source "drivers/net/ethernet/ibm/Kconfig"
 source "drivers/net/ethernet/intel/Kconfig"
 source "drivers/net/ethernet/i825xx/Kconfig"
 source "drivers/net/ethernet/xscale/Kconfig"
-source "drivers/net/ethernet/icplus/Kconfig"
 
 config JME
        tristate "JMicron(R) PCI-Express Gigabit Ethernet support"
index ddfc808110a161f9adbd33ec6bdf594ba27d2524..071f84eb6f3f8c8f0b7add3e31d1873609dc4486 100644 (file)
@@ -15,6 +15,7 @@ obj-$(CONFIG_NET_XGENE) += apm/
 obj-$(CONFIG_NET_VENDOR_APPLE) += apple/
 obj-$(CONFIG_NET_VENDOR_ARC) += arc/
 obj-$(CONFIG_NET_VENDOR_ATHEROS) += atheros/
+obj-$(CONFIG_NET_VENDOR_AURORA) += aurora/
 obj-$(CONFIG_NET_CADENCE) += cadence/
 obj-$(CONFIG_NET_BFIN) += adi/
 obj-$(CONFIG_NET_VENDOR_BROADCOM) += broadcom/
@@ -41,7 +42,6 @@ obj-$(CONFIG_NET_VENDOR_IBM) += ibm/
 obj-$(CONFIG_NET_VENDOR_INTEL) += intel/
 obj-$(CONFIG_NET_VENDOR_I825XX) += i825xx/
 obj-$(CONFIG_NET_VENDOR_XSCALE) += xscale/
-obj-$(CONFIG_IP1000) += icplus/
 obj-$(CONFIG_JME) += jme.o
 obj-$(CONFIG_KORINA) += korina.o
 obj-$(CONFIG_LANTIQ_ETOP) += lantiq_etop.o
index e2afabf3a465860230cbae73d8e37166d30c5394..7ccebae9cb48794cd3977a6fb49844a5bc57e75a 100644 (file)
@@ -1500,10 +1500,11 @@ pcnet32_probe_pci(struct pci_dev *pdev, const struct pci_device_id *ent)
                return -ENODEV;
        }
 
-       if (!pci_set_dma_mask(pdev, PCNET32_DMA_MASK)) {
+       err = pci_set_dma_mask(pdev, PCNET32_DMA_MASK);
+       if (err) {
                if (pcnet32_debug & NETIF_MSG_PROBE)
                        pr_err("architecture does not support 32bit PCI busmaster DMA\n");
-               return -ENODEV;
+               return err;
        }
        if (!request_region(ioaddr, PCNET32_TOTAL_SIZE, "pcnet32_probe_pci")) {
                if (pcnet32_debug & NETIF_MSG_PROBE)
index 970781a9e67777a87b0b93f0cf8bf31d4541d855..f6a7161e3b85297eda9503a27280cab93b2ae70b 100644 (file)
@@ -1849,7 +1849,7 @@ static int xgbe_exit(struct xgbe_prv_data *pdata)
        usleep_range(10, 15);
 
        /* Poll Until Poll Condition */
-       while (count-- && XGMAC_IOREAD_BITS(pdata, DMA_MR, SWR))
+       while (--count && XGMAC_IOREAD_BITS(pdata, DMA_MR, SWR))
                usleep_range(500, 600);
 
        if (!count)
@@ -1873,7 +1873,7 @@ static int xgbe_flush_tx_queues(struct xgbe_prv_data *pdata)
        /* Poll Until Poll Condition */
        for (i = 0; i < pdata->tx_q_count; i++) {
                count = 2000;
-               while (count-- && XGMAC_MTL_IOREAD_BITS(pdata, i,
+               while (--count && XGMAC_MTL_IOREAD_BITS(pdata, i,
                                                        MTL_Q_TQOMR, FTQ))
                        usleep_range(500, 600);
 
index 991412ce6f48fbbf6fdfd6255003a0aa90e67e01..d0ae1a6cc2120cbb4d7d2eb9840e1f552605bd06 100644 (file)
@@ -289,6 +289,7 @@ static int xgene_enet_setup_tx_desc(struct xgene_enet_desc_ring *tx_ring,
                                    struct sk_buff *skb)
 {
        struct device *dev = ndev_to_dev(tx_ring->ndev);
+       struct xgene_enet_pdata *pdata = netdev_priv(tx_ring->ndev);
        struct xgene_enet_raw_desc *raw_desc;
        __le64 *exp_desc = NULL, *exp_bufs = NULL;
        dma_addr_t dma_addr, pbuf_addr, *frag_dma_addr;
@@ -419,6 +420,7 @@ out:
        raw_desc->m0 = cpu_to_le64(SET_VAL(LL, ll) | SET_VAL(NV, nv) |
                                   SET_VAL(USERINFO, tx_ring->tail));
        tx_ring->cp_ring->cp_skb[tx_ring->tail] = skb;
+       pdata->tx_level += count;
        tx_ring->tail = tail;
 
        return count;
@@ -429,14 +431,13 @@ static netdev_tx_t xgene_enet_start_xmit(struct sk_buff *skb,
 {
        struct xgene_enet_pdata *pdata = netdev_priv(ndev);
        struct xgene_enet_desc_ring *tx_ring = pdata->tx_ring;
-       struct xgene_enet_desc_ring *cp_ring = tx_ring->cp_ring;
-       u32 tx_level, cq_level;
+       u32 tx_level = pdata->tx_level;
        int count;
 
-       tx_level = pdata->ring_ops->len(tx_ring);
-       cq_level = pdata->ring_ops->len(cp_ring);
-       if (unlikely(tx_level > pdata->tx_qcnt_hi ||
-                    cq_level > pdata->cp_qcnt_hi)) {
+       if (tx_level < pdata->txc_level)
+               tx_level += ((typeof(pdata->tx_level))~0U);
+
+       if ((tx_level - pdata->txc_level) > pdata->tx_qcnt_hi) {
                netif_stop_queue(ndev);
                return NETDEV_TX_BUSY;
        }
@@ -450,12 +451,12 @@ static netdev_tx_t xgene_enet_start_xmit(struct sk_buff *skb,
                return NETDEV_TX_OK;
        }
 
-       pdata->ring_ops->wr_cmd(tx_ring, count);
        skb_tx_timestamp(skb);
 
        pdata->stats.tx_packets++;
        pdata->stats.tx_bytes += skb->len;
 
+       pdata->ring_ops->wr_cmd(tx_ring, count);
        return NETDEV_TX_OK;
 }
 
@@ -539,10 +540,13 @@ static int xgene_enet_process_ring(struct xgene_enet_desc_ring *ring,
        struct xgene_enet_raw_desc *raw_desc, *exp_desc;
        u16 head = ring->head;
        u16 slots = ring->slots - 1;
-       int ret, count = 0, processed = 0;
+       int ret, desc_count, count = 0, processed = 0;
+       bool is_completion;
 
        do {
                raw_desc = &ring->raw_desc[head];
+               desc_count = 0;
+               is_completion = false;
                exp_desc = NULL;
                if (unlikely(xgene_enet_is_desc_slot_empty(raw_desc)))
                        break;
@@ -559,18 +563,24 @@ static int xgene_enet_process_ring(struct xgene_enet_desc_ring *ring,
                        }
                        dma_rmb();
                        count++;
+                       desc_count++;
                }
-               if (is_rx_desc(raw_desc))
+               if (is_rx_desc(raw_desc)) {
                        ret = xgene_enet_rx_frame(ring, raw_desc);
-               else
+               } else {
                        ret = xgene_enet_tx_completion(ring, raw_desc);
+                       is_completion = true;
+               }
                xgene_enet_mark_desc_slot_empty(raw_desc);
                if (exp_desc)
                        xgene_enet_mark_desc_slot_empty(exp_desc);
 
                head = (head + 1) & slots;
                count++;
+               desc_count++;
                processed++;
+               if (is_completion)
+                       pdata->txc_level += desc_count;
 
                if (ret)
                        break;
@@ -580,10 +590,8 @@ static int xgene_enet_process_ring(struct xgene_enet_desc_ring *ring,
                pdata->ring_ops->wr_cmd(ring, -count);
                ring->head = head;
 
-               if (netif_queue_stopped(ring->ndev)) {
-                       if (pdata->ring_ops->len(ring) < pdata->cp_qcnt_low)
-                               netif_wake_queue(ring->ndev);
-               }
+               if (netif_queue_stopped(ring->ndev))
+                       netif_start_queue(ring->ndev);
        }
 
        return processed;
@@ -688,10 +696,10 @@ static int xgene_enet_open(struct net_device *ndev)
        mac_ops->tx_enable(pdata);
        mac_ops->rx_enable(pdata);
 
+       xgene_enet_napi_enable(pdata);
        ret = xgene_enet_register_irq(ndev);
        if (ret)
                return ret;
-       xgene_enet_napi_enable(pdata);
 
        if (pdata->phy_mode == PHY_INTERFACE_MODE_RGMII)
                phy_start(pdata->phy_dev);
@@ -715,13 +723,13 @@ static int xgene_enet_close(struct net_device *ndev)
        else
                cancel_delayed_work_sync(&pdata->link_work);
 
-       xgene_enet_napi_disable(pdata);
-       xgene_enet_free_irq(ndev);
-       xgene_enet_process_ring(pdata->rx_ring, -1);
-
        mac_ops->tx_disable(pdata);
        mac_ops->rx_disable(pdata);
 
+       xgene_enet_free_irq(ndev);
+       xgene_enet_napi_disable(pdata);
+       xgene_enet_process_ring(pdata->rx_ring, -1);
+
        return 0;
 }
 
@@ -1033,9 +1041,7 @@ static int xgene_enet_create_desc_rings(struct net_device *ndev)
        pdata->tx_ring->cp_ring = cp_ring;
        pdata->tx_ring->dst_ring_num = xgene_enet_dst_ring_num(cp_ring);
 
-       pdata->tx_qcnt_hi = pdata->tx_ring->slots / 2;
-       pdata->cp_qcnt_hi = pdata->rx_ring->slots / 2;
-       pdata->cp_qcnt_low = pdata->cp_qcnt_hi / 2;
+       pdata->tx_qcnt_hi = pdata->tx_ring->slots - 128;
 
        return 0;
 
@@ -1474,15 +1480,15 @@ static int xgene_enet_probe(struct platform_device *pdev)
        }
        ndev->hw_features = ndev->features;
 
-       ret = register_netdev(ndev);
+       ret = dma_coerce_mask_and_coherent(dev, DMA_BIT_MASK(64));
        if (ret) {
-               netdev_err(ndev, "Failed to register netdev\n");
+               netdev_err(ndev, "No usable DMA configuration\n");
                goto err;
        }
 
-       ret = dma_coerce_mask_and_coherent(dev, DMA_BIT_MASK(64));
+       ret = register_netdev(ndev);
        if (ret) {
-               netdev_err(ndev, "No usable DMA configuration\n");
+               netdev_err(ndev, "Failed to register netdev\n");
                goto err;
        }
 
@@ -1490,14 +1496,17 @@ static int xgene_enet_probe(struct platform_device *pdev)
        if (ret)
                goto err;
 
-       xgene_enet_napi_add(pdata);
        mac_ops = pdata->mac_ops;
-       if (pdata->phy_mode == PHY_INTERFACE_MODE_RGMII)
+       if (pdata->phy_mode == PHY_INTERFACE_MODE_RGMII) {
                ret = xgene_enet_mdio_config(pdata);
-       else
+               if (ret)
+                       goto err;
+       } else {
                INIT_DELAYED_WORK(&pdata->link_work, mac_ops->link_state);
+       }
 
-       return ret;
+       xgene_enet_napi_add(pdata);
+       return 0;
 err:
        unregister_netdev(ndev);
        free_netdev(ndev);
index a6e56b88c0a07a6bee7a1f0e6a050db802e5e989..1aa72c787f8de9464a22bf66a8ea2081a6679269 100644 (file)
@@ -155,11 +155,11 @@ struct xgene_enet_pdata {
        enum xgene_enet_id enet_id;
        struct xgene_enet_desc_ring *tx_ring;
        struct xgene_enet_desc_ring *rx_ring;
+       u16 tx_level;
+       u16 txc_level;
        char *dev_name;
        u32 rx_buff_cnt;
        u32 tx_qcnt_hi;
-       u32 cp_qcnt_hi;
-       u32 cp_qcnt_low;
        u32 rx_irq;
        u32 txc_irq;
        u8 cq_cnt;
index c8af3ce3ea38d16d4c470ec5773b2d4f088b0f15..bd377a6b067d4e7cc2e4640514d6910a03167450 100644 (file)
@@ -1534,6 +1534,8 @@ static const struct pci_device_id alx_pci_tbl[] = {
          .driver_data = ALX_DEV_QUIRK_MSI_INTX_DISABLE_BUG },
        { PCI_VDEVICE(ATTANSIC, ALX_DEV_ID_E2200),
          .driver_data = ALX_DEV_QUIRK_MSI_INTX_DISABLE_BUG },
+       { PCI_VDEVICE(ATTANSIC, ALX_DEV_ID_E2400),
+         .driver_data = ALX_DEV_QUIRK_MSI_INTX_DISABLE_BUG },
        { PCI_VDEVICE(ATTANSIC, ALX_DEV_ID_AR8162),
          .driver_data = ALX_DEV_QUIRK_MSI_INTX_DISABLE_BUG },
        { PCI_VDEVICE(ATTANSIC, ALX_DEV_ID_AR8171) },
index af006b44b2a66ec3fd0892672e6a61a9ca362cc3..0959e6824cb635f0262524db9729988986193fb4 100644 (file)
@@ -37,6 +37,7 @@
 
 #define ALX_DEV_ID_AR8161                              0x1091
 #define ALX_DEV_ID_E2200                               0xe091
+#define ALX_DEV_ID_E2400                               0xe0a1
 #define ALX_DEV_ID_AR8162                              0x1090
 #define ALX_DEV_ID_AR8171                              0x10A1
 #define ALX_DEV_ID_AR8172                              0x10A0
index 2795d6db10e1897e3c3c3b367e28e05ea33858c5..8b5988e210d55bcae21f4c6bb8614696cb7b0b64 100644 (file)
@@ -1016,13 +1016,12 @@ static int atl1c_setup_ring_resources(struct atl1c_adapter *adapter)
                sizeof(struct atl1c_recv_ret_status) * rx_desc_count +
                8 * 4;
 
-       ring_header->desc = pci_alloc_consistent(pdev, ring_header->size,
-                               &ring_header->dma);
+       ring_header->desc = dma_zalloc_coherent(&pdev->dev, ring_header->size,
+                                               &ring_header->dma, GFP_KERNEL);
        if (unlikely(!ring_header->desc)) {
-               dev_err(&pdev->dev, "pci_alloc_consistend failed\n");
+               dev_err(&pdev->dev, "could not get memory for DMA buffer\n");
                goto err_nomem;
        }
-       memset(ring_header->desc, 0, ring_header->size);
        /* init TPD ring */
 
        tpd_ring[0].dma = roundup(ring_header->dma, 8);
diff --git a/drivers/net/ethernet/aurora/Kconfig b/drivers/net/ethernet/aurora/Kconfig
new file mode 100644 (file)
index 0000000..8ba7f8f
--- /dev/null
@@ -0,0 +1,21 @@
+config NET_VENDOR_AURORA
+       bool "Aurora VLSI devices"
+       help
+         If you have a network (Ethernet) device belonging to this class,
+         say Y.
+
+         Note that the answer to this question doesn't directly affect the
+         kernel: saying N will just cause the configurator to skip all
+         questions about Aurora devices. If you say Y, you will be asked
+         for your specific device in the following questions.
+
+if NET_VENDOR_AURORA
+
+config AURORA_NB8800
+       tristate "Aurora AU-NB8800 support"
+       depends on HAS_DMA
+       select PHYLIB
+       help
+        Support for the AU-NB8800 gigabit Ethernet controller.
+
+endif
diff --git a/drivers/net/ethernet/aurora/Makefile b/drivers/net/ethernet/aurora/Makefile
new file mode 100644 (file)
index 0000000..6cb528a
--- /dev/null
@@ -0,0 +1 @@
+obj-$(CONFIG_AURORA_NB8800) += nb8800.o
diff --git a/drivers/net/ethernet/aurora/nb8800.c b/drivers/net/ethernet/aurora/nb8800.c
new file mode 100644 (file)
index 0000000..ecc4a33
--- /dev/null
@@ -0,0 +1,1552 @@
+/*
+ * Copyright (C) 2015 Mans Rullgard <mans@mansr.com>
+ *
+ * Mostly rewritten, based on driver from Sigma Designs.  Original
+ * copyright notice below.
+ *
+ *
+ * Driver for tangox SMP864x/SMP865x/SMP867x/SMP868x builtin Ethernet Mac.
+ *
+ * Copyright (C) 2005 Maxime Bizon <mbizon@freebox.fr>
+ *
+ * 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.
+ */
+
+#include <linux/module.h>
+#include <linux/etherdevice.h>
+#include <linux/delay.h>
+#include <linux/ethtool.h>
+#include <linux/interrupt.h>
+#include <linux/platform_device.h>
+#include <linux/of_device.h>
+#include <linux/of_mdio.h>
+#include <linux/of_net.h>
+#include <linux/dma-mapping.h>
+#include <linux/phy.h>
+#include <linux/cache.h>
+#include <linux/jiffies.h>
+#include <linux/io.h>
+#include <linux/iopoll.h>
+#include <asm/barrier.h>
+
+#include "nb8800.h"
+
+static void nb8800_tx_done(struct net_device *dev);
+static int nb8800_dma_stop(struct net_device *dev);
+
+static inline u8 nb8800_readb(struct nb8800_priv *priv, int reg)
+{
+       return readb_relaxed(priv->base + reg);
+}
+
+static inline u32 nb8800_readl(struct nb8800_priv *priv, int reg)
+{
+       return readl_relaxed(priv->base + reg);
+}
+
+static inline void nb8800_writeb(struct nb8800_priv *priv, int reg, u8 val)
+{
+       writeb_relaxed(val, priv->base + reg);
+}
+
+static inline void nb8800_writew(struct nb8800_priv *priv, int reg, u16 val)
+{
+       writew_relaxed(val, priv->base + reg);
+}
+
+static inline void nb8800_writel(struct nb8800_priv *priv, int reg, u32 val)
+{
+       writel_relaxed(val, priv->base + reg);
+}
+
+static inline void nb8800_maskb(struct nb8800_priv *priv, int reg,
+                               u32 mask, u32 val)
+{
+       u32 old = nb8800_readb(priv, reg);
+       u32 new = (old & ~mask) | (val & mask);
+
+       if (new != old)
+               nb8800_writeb(priv, reg, new);
+}
+
+static inline void nb8800_maskl(struct nb8800_priv *priv, int reg,
+                               u32 mask, u32 val)
+{
+       u32 old = nb8800_readl(priv, reg);
+       u32 new = (old & ~mask) | (val & mask);
+
+       if (new != old)
+               nb8800_writel(priv, reg, new);
+}
+
+static inline void nb8800_modb(struct nb8800_priv *priv, int reg, u8 bits,
+                              bool set)
+{
+       nb8800_maskb(priv, reg, bits, set ? bits : 0);
+}
+
+static inline void nb8800_setb(struct nb8800_priv *priv, int reg, u8 bits)
+{
+       nb8800_maskb(priv, reg, bits, bits);
+}
+
+static inline void nb8800_clearb(struct nb8800_priv *priv, int reg, u8 bits)
+{
+       nb8800_maskb(priv, reg, bits, 0);
+}
+
+static inline void nb8800_modl(struct nb8800_priv *priv, int reg, u32 bits,
+                              bool set)
+{
+       nb8800_maskl(priv, reg, bits, set ? bits : 0);
+}
+
+static inline void nb8800_setl(struct nb8800_priv *priv, int reg, u32 bits)
+{
+       nb8800_maskl(priv, reg, bits, bits);
+}
+
+static inline void nb8800_clearl(struct nb8800_priv *priv, int reg, u32 bits)
+{
+       nb8800_maskl(priv, reg, bits, 0);
+}
+
+static int nb8800_mdio_wait(struct mii_bus *bus)
+{
+       struct nb8800_priv *priv = bus->priv;
+       u32 val;
+
+       return readl_poll_timeout_atomic(priv->base + NB8800_MDIO_CMD,
+                                        val, !(val & MDIO_CMD_GO), 1, 1000);
+}
+
+static int nb8800_mdio_cmd(struct mii_bus *bus, u32 cmd)
+{
+       struct nb8800_priv *priv = bus->priv;
+       int err;
+
+       err = nb8800_mdio_wait(bus);
+       if (err)
+               return err;
+
+       nb8800_writel(priv, NB8800_MDIO_CMD, cmd);
+       udelay(10);
+       nb8800_writel(priv, NB8800_MDIO_CMD, cmd | MDIO_CMD_GO);
+
+       return nb8800_mdio_wait(bus);
+}
+
+static int nb8800_mdio_read(struct mii_bus *bus, int phy_id, int reg)
+{
+       struct nb8800_priv *priv = bus->priv;
+       u32 val;
+       int err;
+
+       err = nb8800_mdio_cmd(bus, MDIO_CMD_ADDR(phy_id) | MDIO_CMD_REG(reg));
+       if (err)
+               return err;
+
+       val = nb8800_readl(priv, NB8800_MDIO_STS);
+       if (val & MDIO_STS_ERR)
+               return 0xffff;
+
+       return val & 0xffff;
+}
+
+static int nb8800_mdio_write(struct mii_bus *bus, int phy_id, int reg, u16 val)
+{
+       u32 cmd = MDIO_CMD_ADDR(phy_id) | MDIO_CMD_REG(reg) |
+               MDIO_CMD_DATA(val) | MDIO_CMD_WR;
+
+       return nb8800_mdio_cmd(bus, cmd);
+}
+
+static void nb8800_mac_tx(struct net_device *dev, bool enable)
+{
+       struct nb8800_priv *priv = netdev_priv(dev);
+
+       while (nb8800_readl(priv, NB8800_TXC_CR) & TCR_EN)
+               cpu_relax();
+
+       nb8800_modb(priv, NB8800_TX_CTL1, TX_EN, enable);
+}
+
+static void nb8800_mac_rx(struct net_device *dev, bool enable)
+{
+       nb8800_modb(netdev_priv(dev), NB8800_RX_CTL, RX_EN, enable);
+}
+
+static void nb8800_mac_af(struct net_device *dev, bool enable)
+{
+       nb8800_modb(netdev_priv(dev), NB8800_RX_CTL, RX_AF_EN, enable);
+}
+
+static void nb8800_start_rx(struct net_device *dev)
+{
+       nb8800_setl(netdev_priv(dev), NB8800_RXC_CR, RCR_EN);
+}
+
+static int nb8800_alloc_rx(struct net_device *dev, unsigned int i, bool napi)
+{
+       struct nb8800_priv *priv = netdev_priv(dev);
+       struct nb8800_rx_desc *rxd = &priv->rx_descs[i];
+       struct nb8800_rx_buf *rxb = &priv->rx_bufs[i];
+       int size = L1_CACHE_ALIGN(RX_BUF_SIZE);
+       dma_addr_t dma_addr;
+       struct page *page;
+       unsigned long offset;
+       void *data;
+
+       data = napi ? napi_alloc_frag(size) : netdev_alloc_frag(size);
+       if (!data)
+               return -ENOMEM;
+
+       page = virt_to_head_page(data);
+       offset = data - page_address(page);
+
+       dma_addr = dma_map_page(&dev->dev, page, offset, RX_BUF_SIZE,
+                               DMA_FROM_DEVICE);
+
+       if (dma_mapping_error(&dev->dev, dma_addr)) {
+               skb_free_frag(data);
+               return -ENOMEM;
+       }
+
+       rxb->page = page;
+       rxb->offset = offset;
+       rxd->desc.s_addr = dma_addr;
+
+       return 0;
+}
+
+static void nb8800_receive(struct net_device *dev, unsigned int i,
+                          unsigned int len)
+{
+       struct nb8800_priv *priv = netdev_priv(dev);
+       struct nb8800_rx_desc *rxd = &priv->rx_descs[i];
+       struct page *page = priv->rx_bufs[i].page;
+       int offset = priv->rx_bufs[i].offset;
+       void *data = page_address(page) + offset;
+       dma_addr_t dma = rxd->desc.s_addr;
+       struct sk_buff *skb;
+       unsigned int size;
+       int err;
+
+       size = len <= RX_COPYBREAK ? len : RX_COPYHDR;
+
+       skb = napi_alloc_skb(&priv->napi, size);
+       if (!skb) {
+               netdev_err(dev, "rx skb allocation failed\n");
+               dev->stats.rx_dropped++;
+               return;
+       }
+
+       if (len <= RX_COPYBREAK) {
+               dma_sync_single_for_cpu(&dev->dev, dma, len, DMA_FROM_DEVICE);
+               memcpy(skb_put(skb, len), data, len);
+               dma_sync_single_for_device(&dev->dev, dma, len,
+                                          DMA_FROM_DEVICE);
+       } else {
+               err = nb8800_alloc_rx(dev, i, true);
+               if (err) {
+                       netdev_err(dev, "rx buffer allocation failed\n");
+                       dev->stats.rx_dropped++;
+                       return;
+               }
+
+               dma_unmap_page(&dev->dev, dma, RX_BUF_SIZE, DMA_FROM_DEVICE);
+               memcpy(skb_put(skb, RX_COPYHDR), data, RX_COPYHDR);
+               skb_add_rx_frag(skb, skb_shinfo(skb)->nr_frags, page,
+                               offset + RX_COPYHDR, len - RX_COPYHDR,
+                               RX_BUF_SIZE);
+       }
+
+       skb->protocol = eth_type_trans(skb, dev);
+       napi_gro_receive(&priv->napi, skb);
+}
+
+static void nb8800_rx_error(struct net_device *dev, u32 report)
+{
+       if (report & RX_LENGTH_ERR)
+               dev->stats.rx_length_errors++;
+
+       if (report & RX_FCS_ERR)
+               dev->stats.rx_crc_errors++;
+
+       if (report & RX_FIFO_OVERRUN)
+               dev->stats.rx_fifo_errors++;
+
+       if (report & RX_ALIGNMENT_ERROR)
+               dev->stats.rx_frame_errors++;
+
+       dev->stats.rx_errors++;
+}
+
+static int nb8800_poll(struct napi_struct *napi, int budget)
+{
+       struct net_device *dev = napi->dev;
+       struct nb8800_priv *priv = netdev_priv(dev);
+       struct nb8800_rx_desc *rxd;
+       unsigned int last = priv->rx_eoc;
+       unsigned int next;
+       int work = 0;
+
+       nb8800_tx_done(dev);
+
+again:
+       while (work < budget) {
+               struct nb8800_rx_buf *rxb;
+               unsigned int len;
+
+               next = (last + 1) % RX_DESC_COUNT;
+
+               rxb = &priv->rx_bufs[next];
+               rxd = &priv->rx_descs[next];
+
+               if (!rxd->report)
+                       break;
+
+               len = RX_BYTES_TRANSFERRED(rxd->report);
+
+               if (IS_RX_ERROR(rxd->report))
+                       nb8800_rx_error(dev, rxd->report);
+               else
+                       nb8800_receive(dev, next, len);
+
+               dev->stats.rx_packets++;
+               dev->stats.rx_bytes += len;
+
+               if (rxd->report & RX_MULTICAST_PKT)
+                       dev->stats.multicast++;
+
+               rxd->report = 0;
+               last = next;
+               work++;
+       }
+
+       if (work) {
+               priv->rx_descs[last].desc.config |= DESC_EOC;
+               wmb();  /* ensure new EOC is written before clearing old */
+               priv->rx_descs[priv->rx_eoc].desc.config &= ~DESC_EOC;
+               priv->rx_eoc = last;
+               nb8800_start_rx(dev);
+       }
+
+       if (work < budget) {
+               nb8800_writel(priv, NB8800_RX_ITR, priv->rx_itr_irq);
+
+               /* If a packet arrived after we last checked but
+                * before writing RX_ITR, the interrupt will be
+                * delayed, so we retrieve it now.
+                */
+               if (priv->rx_descs[next].report)
+                       goto again;
+
+               napi_complete_done(napi, work);
+       }
+
+       return work;
+}
+
+static void __nb8800_tx_dma_start(struct net_device *dev)
+{
+       struct nb8800_priv *priv = netdev_priv(dev);
+       struct nb8800_tx_buf *txb;
+       u32 txc_cr;
+
+       txb = &priv->tx_bufs[priv->tx_queue];
+       if (!txb->ready)
+               return;
+
+       txc_cr = nb8800_readl(priv, NB8800_TXC_CR);
+       if (txc_cr & TCR_EN)
+               return;
+
+       nb8800_writel(priv, NB8800_TX_DESC_ADDR, txb->dma_desc);
+       wmb();          /* ensure desc addr is written before starting DMA */
+       nb8800_writel(priv, NB8800_TXC_CR, txc_cr | TCR_EN);
+
+       priv->tx_queue = (priv->tx_queue + txb->chain_len) % TX_DESC_COUNT;
+}
+
+static void nb8800_tx_dma_start(struct net_device *dev)
+{
+       struct nb8800_priv *priv = netdev_priv(dev);
+
+       spin_lock_irq(&priv->tx_lock);
+       __nb8800_tx_dma_start(dev);
+       spin_unlock_irq(&priv->tx_lock);
+}
+
+static void nb8800_tx_dma_start_irq(struct net_device *dev)
+{
+       struct nb8800_priv *priv = netdev_priv(dev);
+
+       spin_lock(&priv->tx_lock);
+       __nb8800_tx_dma_start(dev);
+       spin_unlock(&priv->tx_lock);
+}
+
+static int nb8800_xmit(struct sk_buff *skb, struct net_device *dev)
+{
+       struct nb8800_priv *priv = netdev_priv(dev);
+       struct nb8800_tx_desc *txd;
+       struct nb8800_tx_buf *txb;
+       struct nb8800_dma_desc *desc;
+       dma_addr_t dma_addr;
+       unsigned int dma_len;
+       unsigned int align;
+       unsigned int next;
+
+       if (atomic_read(&priv->tx_free) <= NB8800_DESC_LOW) {
+               netif_stop_queue(dev);
+               return NETDEV_TX_BUSY;
+       }
+
+       align = (8 - (uintptr_t)skb->data) & 7;
+
+       dma_len = skb->len - align;
+       dma_addr = dma_map_single(&dev->dev, skb->data + align,
+                                 dma_len, DMA_TO_DEVICE);
+
+       if (dma_mapping_error(&dev->dev, dma_addr)) {
+               netdev_err(dev, "tx dma mapping error\n");
+               kfree_skb(skb);
+               dev->stats.tx_dropped++;
+               return NETDEV_TX_OK;
+       }
+
+       if (atomic_dec_return(&priv->tx_free) <= NB8800_DESC_LOW) {
+               netif_stop_queue(dev);
+               skb->xmit_more = 0;
+       }
+
+       next = priv->tx_next;
+       txb = &priv->tx_bufs[next];
+       txd = &priv->tx_descs[next];
+       desc = &txd->desc[0];
+
+       next = (next + 1) % TX_DESC_COUNT;
+
+       if (align) {
+               memcpy(txd->buf, skb->data, align);
+
+               desc->s_addr =
+                       txb->dma_desc + offsetof(struct nb8800_tx_desc, buf);
+               desc->n_addr = txb->dma_desc + sizeof(txd->desc[0]);
+               desc->config = DESC_BTS(2) | DESC_DS | align;
+
+               desc++;
+       }
+
+       desc->s_addr = dma_addr;
+       desc->n_addr = priv->tx_bufs[next].dma_desc;
+       desc->config = DESC_BTS(2) | DESC_DS | DESC_EOF | dma_len;
+
+       if (!skb->xmit_more)
+               desc->config |= DESC_EOC;
+
+       txb->skb = skb;
+       txb->dma_addr = dma_addr;
+       txb->dma_len = dma_len;
+
+       if (!priv->tx_chain) {
+               txb->chain_len = 1;
+               priv->tx_chain = txb;
+       } else {
+               priv->tx_chain->chain_len++;
+       }
+
+       netdev_sent_queue(dev, skb->len);
+
+       priv->tx_next = next;
+
+       if (!skb->xmit_more) {
+               smp_wmb();
+               priv->tx_chain->ready = true;
+               priv->tx_chain = NULL;
+               nb8800_tx_dma_start(dev);
+       }
+
+       return NETDEV_TX_OK;
+}
+
+static void nb8800_tx_error(struct net_device *dev, u32 report)
+{
+       if (report & TX_LATE_COLLISION)
+               dev->stats.collisions++;
+
+       if (report & TX_PACKET_DROPPED)
+               dev->stats.tx_dropped++;
+
+       if (report & TX_FIFO_UNDERRUN)
+               dev->stats.tx_fifo_errors++;
+
+       dev->stats.tx_errors++;
+}
+
+static void nb8800_tx_done(struct net_device *dev)
+{
+       struct nb8800_priv *priv = netdev_priv(dev);
+       unsigned int limit = priv->tx_next;
+       unsigned int done = priv->tx_done;
+       unsigned int packets = 0;
+       unsigned int len = 0;
+
+       while (done != limit) {
+               struct nb8800_tx_desc *txd = &priv->tx_descs[done];
+               struct nb8800_tx_buf *txb = &priv->tx_bufs[done];
+               struct sk_buff *skb;
+
+               if (!txd->report)
+                       break;
+
+               skb = txb->skb;
+               len += skb->len;
+
+               dma_unmap_single(&dev->dev, txb->dma_addr, txb->dma_len,
+                                DMA_TO_DEVICE);
+
+               if (IS_TX_ERROR(txd->report)) {
+                       nb8800_tx_error(dev, txd->report);
+                       kfree_skb(skb);
+               } else {
+                       consume_skb(skb);
+               }
+
+               dev->stats.tx_packets++;
+               dev->stats.tx_bytes += TX_BYTES_TRANSFERRED(txd->report);
+               dev->stats.collisions += TX_EARLY_COLLISIONS(txd->report);
+
+               txb->skb = NULL;
+               txb->ready = false;
+               txd->report = 0;
+
+               done = (done + 1) % TX_DESC_COUNT;
+               packets++;
+       }
+
+       if (packets) {
+               smp_mb__before_atomic();
+               atomic_add(packets, &priv->tx_free);
+               netdev_completed_queue(dev, packets, len);
+               netif_wake_queue(dev);
+               priv->tx_done = done;
+       }
+}
+
+static irqreturn_t nb8800_irq(int irq, void *dev_id)
+{
+       struct net_device *dev = dev_id;
+       struct nb8800_priv *priv = netdev_priv(dev);
+       irqreturn_t ret = IRQ_NONE;
+       u32 val;
+
+       /* tx interrupt */
+       val = nb8800_readl(priv, NB8800_TXC_SR);
+       if (val) {
+               nb8800_writel(priv, NB8800_TXC_SR, val);
+
+               if (val & TSR_DI)
+                       nb8800_tx_dma_start_irq(dev);
+
+               if (val & TSR_TI)
+                       napi_schedule_irqoff(&priv->napi);
+
+               if (unlikely(val & TSR_DE))
+                       netdev_err(dev, "TX DMA error\n");
+
+               /* should never happen with automatic status retrieval */
+               if (unlikely(val & TSR_TO))
+                       netdev_err(dev, "TX Status FIFO overflow\n");
+
+               ret = IRQ_HANDLED;
+       }
+
+       /* rx interrupt */
+       val = nb8800_readl(priv, NB8800_RXC_SR);
+       if (val) {
+               nb8800_writel(priv, NB8800_RXC_SR, val);
+
+               if (likely(val & (RSR_RI | RSR_DI))) {
+                       nb8800_writel(priv, NB8800_RX_ITR, priv->rx_itr_poll);
+                       napi_schedule_irqoff(&priv->napi);
+               }
+
+               if (unlikely(val & RSR_DE))
+                       netdev_err(dev, "RX DMA error\n");
+
+               /* should never happen with automatic status retrieval */
+               if (unlikely(val & RSR_RO))
+                       netdev_err(dev, "RX Status FIFO overflow\n");
+
+               ret = IRQ_HANDLED;
+       }
+
+       return ret;
+}
+
+static void nb8800_mac_config(struct net_device *dev)
+{
+       struct nb8800_priv *priv = netdev_priv(dev);
+       bool gigabit = priv->speed == SPEED_1000;
+       u32 mac_mode_mask = RGMII_MODE | HALF_DUPLEX | GMAC_MODE;
+       u32 mac_mode = 0;
+       u32 slot_time;
+       u32 phy_clk;
+       u32 ict;
+
+       if (!priv->duplex)
+               mac_mode |= HALF_DUPLEX;
+
+       if (gigabit) {
+               if (priv->phy_mode == PHY_INTERFACE_MODE_RGMII)
+                       mac_mode |= RGMII_MODE;
+
+               mac_mode |= GMAC_MODE;
+               phy_clk = 125000000;
+
+               /* Should be 512 but register is only 8 bits */
+               slot_time = 255;
+       } else {
+               phy_clk = 25000000;
+               slot_time = 128;
+       }
+
+       ict = DIV_ROUND_UP(phy_clk, clk_get_rate(priv->clk));
+
+       nb8800_writeb(priv, NB8800_IC_THRESHOLD, ict);
+       nb8800_writeb(priv, NB8800_SLOT_TIME, slot_time);
+       nb8800_maskb(priv, NB8800_MAC_MODE, mac_mode_mask, mac_mode);
+}
+
+static void nb8800_pause_config(struct net_device *dev)
+{
+       struct nb8800_priv *priv = netdev_priv(dev);
+       struct phy_device *phydev = priv->phydev;
+       u32 rxcr;
+
+       if (priv->pause_aneg) {
+               if (!phydev || !phydev->link)
+                       return;
+
+               priv->pause_rx = phydev->pause;
+               priv->pause_tx = phydev->pause ^ phydev->asym_pause;
+       }
+
+       nb8800_modb(priv, NB8800_RX_CTL, RX_PAUSE_EN, priv->pause_rx);
+
+       rxcr = nb8800_readl(priv, NB8800_RXC_CR);
+       if (!!(rxcr & RCR_FL) == priv->pause_tx)
+               return;
+
+       if (netif_running(dev)) {
+               napi_disable(&priv->napi);
+               netif_tx_lock_bh(dev);
+               nb8800_dma_stop(dev);
+               nb8800_modl(priv, NB8800_RXC_CR, RCR_FL, priv->pause_tx);
+               nb8800_start_rx(dev);
+               netif_tx_unlock_bh(dev);
+               napi_enable(&priv->napi);
+       } else {
+               nb8800_modl(priv, NB8800_RXC_CR, RCR_FL, priv->pause_tx);
+       }
+}
+
+static void nb8800_link_reconfigure(struct net_device *dev)
+{
+       struct nb8800_priv *priv = netdev_priv(dev);
+       struct phy_device *phydev = priv->phydev;
+       int change = 0;
+
+       if (phydev->link) {
+               if (phydev->speed != priv->speed) {
+                       priv->speed = phydev->speed;
+                       change = 1;
+               }
+
+               if (phydev->duplex != priv->duplex) {
+                       priv->duplex = phydev->duplex;
+                       change = 1;
+               }
+
+               if (change)
+                       nb8800_mac_config(dev);
+
+               nb8800_pause_config(dev);
+       }
+
+       if (phydev->link != priv->link) {
+               priv->link = phydev->link;
+               change = 1;
+       }
+
+       if (change)
+               phy_print_status(priv->phydev);
+}
+
+static void nb8800_update_mac_addr(struct net_device *dev)
+{
+       struct nb8800_priv *priv = netdev_priv(dev);
+       int i;
+
+       for (i = 0; i < ETH_ALEN; i++)
+               nb8800_writeb(priv, NB8800_SRC_ADDR(i), dev->dev_addr[i]);
+
+       for (i = 0; i < ETH_ALEN; i++)
+               nb8800_writeb(priv, NB8800_UC_ADDR(i), dev->dev_addr[i]);
+}
+
+static int nb8800_set_mac_address(struct net_device *dev, void *addr)
+{
+       struct sockaddr *sock = addr;
+
+       if (netif_running(dev))
+               return -EBUSY;
+
+       ether_addr_copy(dev->dev_addr, sock->sa_data);
+       nb8800_update_mac_addr(dev);
+
+       return 0;
+}
+
+static void nb8800_mc_init(struct net_device *dev, int val)
+{
+       struct nb8800_priv *priv = netdev_priv(dev);
+
+       nb8800_writeb(priv, NB8800_MC_INIT, val);
+       readb_poll_timeout_atomic(priv->base + NB8800_MC_INIT, val, !val,
+                                 1, 1000);
+}
+
+static void nb8800_set_rx_mode(struct net_device *dev)
+{
+       struct nb8800_priv *priv = netdev_priv(dev);
+       struct netdev_hw_addr *ha;
+       int i;
+
+       if (dev->flags & (IFF_PROMISC | IFF_ALLMULTI)) {
+               nb8800_mac_af(dev, false);
+               return;
+       }
+
+       nb8800_mac_af(dev, true);
+       nb8800_mc_init(dev, 0);
+
+       netdev_for_each_mc_addr(ha, dev) {
+               for (i = 0; i < ETH_ALEN; i++)
+                       nb8800_writeb(priv, NB8800_MC_ADDR(i), ha->addr[i]);
+
+               nb8800_mc_init(dev, 0xff);
+       }
+}
+
+#define RX_DESC_SIZE (RX_DESC_COUNT * sizeof(struct nb8800_rx_desc))
+#define TX_DESC_SIZE (TX_DESC_COUNT * sizeof(struct nb8800_tx_desc))
+
+static void nb8800_dma_free(struct net_device *dev)
+{
+       struct nb8800_priv *priv = netdev_priv(dev);
+       unsigned int i;
+
+       if (priv->rx_bufs) {
+               for (i = 0; i < RX_DESC_COUNT; i++)
+                       if (priv->rx_bufs[i].page)
+                               put_page(priv->rx_bufs[i].page);
+
+               kfree(priv->rx_bufs);
+               priv->rx_bufs = NULL;
+       }
+
+       if (priv->tx_bufs) {
+               for (i = 0; i < TX_DESC_COUNT; i++)
+                       kfree_skb(priv->tx_bufs[i].skb);
+
+               kfree(priv->tx_bufs);
+               priv->tx_bufs = NULL;
+       }
+
+       if (priv->rx_descs) {
+               dma_free_coherent(dev->dev.parent, RX_DESC_SIZE, priv->rx_descs,
+                                 priv->rx_desc_dma);
+               priv->rx_descs = NULL;
+       }
+
+       if (priv->tx_descs) {
+               dma_free_coherent(dev->dev.parent, TX_DESC_SIZE, priv->tx_descs,
+                                 priv->tx_desc_dma);
+               priv->tx_descs = NULL;
+       }
+}
+
+static void nb8800_dma_reset(struct net_device *dev)
+{
+       struct nb8800_priv *priv = netdev_priv(dev);
+       struct nb8800_rx_desc *rxd;
+       struct nb8800_tx_desc *txd;
+       unsigned int i;
+
+       for (i = 0; i < RX_DESC_COUNT; i++) {
+               dma_addr_t rx_dma = priv->rx_desc_dma + i * sizeof(*rxd);
+
+               rxd = &priv->rx_descs[i];
+               rxd->desc.n_addr = rx_dma + sizeof(*rxd);
+               rxd->desc.r_addr =
+                       rx_dma + offsetof(struct nb8800_rx_desc, report);
+               rxd->desc.config = priv->rx_dma_config;
+               rxd->report = 0;
+       }
+
+       rxd->desc.n_addr = priv->rx_desc_dma;
+       rxd->desc.config |= DESC_EOC;
+
+       priv->rx_eoc = RX_DESC_COUNT - 1;
+
+       for (i = 0; i < TX_DESC_COUNT; i++) {
+               struct nb8800_tx_buf *txb = &priv->tx_bufs[i];
+               dma_addr_t r_dma = txb->dma_desc +
+                       offsetof(struct nb8800_tx_desc, report);
+
+               txd = &priv->tx_descs[i];
+               txd->desc[0].r_addr = r_dma;
+               txd->desc[1].r_addr = r_dma;
+               txd->report = 0;
+       }
+
+       priv->tx_next = 0;
+       priv->tx_queue = 0;
+       priv->tx_done = 0;
+       atomic_set(&priv->tx_free, TX_DESC_COUNT);
+
+       nb8800_writel(priv, NB8800_RX_DESC_ADDR, priv->rx_desc_dma);
+
+       wmb();          /* ensure all setup is written before starting */
+}
+
+static int nb8800_dma_init(struct net_device *dev)
+{
+       struct nb8800_priv *priv = netdev_priv(dev);
+       unsigned int n_rx = RX_DESC_COUNT;
+       unsigned int n_tx = TX_DESC_COUNT;
+       unsigned int i;
+       int err;
+
+       priv->rx_descs = dma_alloc_coherent(dev->dev.parent, RX_DESC_SIZE,
+                                           &priv->rx_desc_dma, GFP_KERNEL);
+       if (!priv->rx_descs)
+               goto err_out;
+
+       priv->rx_bufs = kcalloc(n_rx, sizeof(*priv->rx_bufs), GFP_KERNEL);
+       if (!priv->rx_bufs)
+               goto err_out;
+
+       for (i = 0; i < n_rx; i++) {
+               err = nb8800_alloc_rx(dev, i, false);
+               if (err)
+                       goto err_out;
+       }
+
+       priv->tx_descs = dma_alloc_coherent(dev->dev.parent, TX_DESC_SIZE,
+                                           &priv->tx_desc_dma, GFP_KERNEL);
+       if (!priv->tx_descs)
+               goto err_out;
+
+       priv->tx_bufs = kcalloc(n_tx, sizeof(*priv->tx_bufs), GFP_KERNEL);
+       if (!priv->tx_bufs)
+               goto err_out;
+
+       for (i = 0; i < n_tx; i++)
+               priv->tx_bufs[i].dma_desc =
+                       priv->tx_desc_dma + i * sizeof(struct nb8800_tx_desc);
+
+       nb8800_dma_reset(dev);
+
+       return 0;
+
+err_out:
+       nb8800_dma_free(dev);
+
+       return -ENOMEM;
+}
+
+static int nb8800_dma_stop(struct net_device *dev)
+{
+       struct nb8800_priv *priv = netdev_priv(dev);
+       struct nb8800_tx_buf *txb = &priv->tx_bufs[0];
+       struct nb8800_tx_desc *txd = &priv->tx_descs[0];
+       int retry = 5;
+       u32 txcr;
+       u32 rxcr;
+       int err;
+       unsigned int i;
+
+       /* wait for tx to finish */
+       err = readl_poll_timeout_atomic(priv->base + NB8800_TXC_CR, txcr,
+                                       !(txcr & TCR_EN) &&
+                                       priv->tx_done == priv->tx_next,
+                                       1000, 1000000);
+       if (err)
+               return err;
+
+       /* The rx DMA only stops if it reaches the end of chain.
+        * To make this happen, we set the EOC flag on all rx
+        * descriptors, put the device in loopback mode, and send
+        * a few dummy frames.  The interrupt handler will ignore
+        * these since NAPI is disabled and no real frames are in
+        * the tx queue.
+        */
+
+       for (i = 0; i < RX_DESC_COUNT; i++)
+               priv->rx_descs[i].desc.config |= DESC_EOC;
+
+       txd->desc[0].s_addr =
+               txb->dma_desc + offsetof(struct nb8800_tx_desc, buf);
+       txd->desc[0].config = DESC_BTS(2) | DESC_DS | DESC_EOF | DESC_EOC | 8;
+       memset(txd->buf, 0, sizeof(txd->buf));
+
+       nb8800_mac_af(dev, false);
+       nb8800_setb(priv, NB8800_MAC_MODE, LOOPBACK_EN);
+
+       do {
+               nb8800_writel(priv, NB8800_TX_DESC_ADDR, txb->dma_desc);
+               wmb();
+               nb8800_writel(priv, NB8800_TXC_CR, txcr | TCR_EN);
+
+               err = readl_poll_timeout_atomic(priv->base + NB8800_RXC_CR,
+                                               rxcr, !(rxcr & RCR_EN),
+                                               1000, 100000);
+       } while (err && --retry);
+
+       nb8800_mac_af(dev, true);
+       nb8800_clearb(priv, NB8800_MAC_MODE, LOOPBACK_EN);
+       nb8800_dma_reset(dev);
+
+       return retry ? 0 : -ETIMEDOUT;
+}
+
+static void nb8800_pause_adv(struct net_device *dev)
+{
+       struct nb8800_priv *priv = netdev_priv(dev);
+       u32 adv = 0;
+
+       if (!priv->phydev)
+               return;
+
+       if (priv->pause_rx)
+               adv |= ADVERTISED_Pause | ADVERTISED_Asym_Pause;
+       if (priv->pause_tx)
+               adv ^= ADVERTISED_Asym_Pause;
+
+       priv->phydev->supported |= adv;
+       priv->phydev->advertising |= adv;
+}
+
+static int nb8800_open(struct net_device *dev)
+{
+       struct nb8800_priv *priv = netdev_priv(dev);
+       int err;
+
+       /* clear any pending interrupts */
+       nb8800_writel(priv, NB8800_RXC_SR, 0xf);
+       nb8800_writel(priv, NB8800_TXC_SR, 0xf);
+
+       err = nb8800_dma_init(dev);
+       if (err)
+               return err;
+
+       err = request_irq(dev->irq, nb8800_irq, 0, dev_name(&dev->dev), dev);
+       if (err)
+               goto err_free_dma;
+
+       nb8800_mac_rx(dev, true);
+       nb8800_mac_tx(dev, true);
+
+       priv->phydev = of_phy_connect(dev, priv->phy_node,
+                                     nb8800_link_reconfigure, 0,
+                                     priv->phy_mode);
+       if (!priv->phydev)
+               goto err_free_irq;
+
+       nb8800_pause_adv(dev);
+
+       netdev_reset_queue(dev);
+       napi_enable(&priv->napi);
+       netif_start_queue(dev);
+
+       nb8800_start_rx(dev);
+       phy_start(priv->phydev);
+
+       return 0;
+
+err_free_irq:
+       free_irq(dev->irq, dev);
+err_free_dma:
+       nb8800_dma_free(dev);
+
+       return err;
+}
+
+static int nb8800_stop(struct net_device *dev)
+{
+       struct nb8800_priv *priv = netdev_priv(dev);
+
+       phy_stop(priv->phydev);
+
+       netif_stop_queue(dev);
+       napi_disable(&priv->napi);
+
+       nb8800_dma_stop(dev);
+       nb8800_mac_rx(dev, false);
+       nb8800_mac_tx(dev, false);
+
+       phy_disconnect(priv->phydev);
+       priv->phydev = NULL;
+
+       free_irq(dev->irq, dev);
+
+       nb8800_dma_free(dev);
+
+       return 0;
+}
+
+static int nb8800_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
+{
+       struct nb8800_priv *priv = netdev_priv(dev);
+
+       return phy_mii_ioctl(priv->phydev, rq, cmd);
+}
+
+static const struct net_device_ops nb8800_netdev_ops = {
+       .ndo_open               = nb8800_open,
+       .ndo_stop               = nb8800_stop,
+       .ndo_start_xmit         = nb8800_xmit,
+       .ndo_set_mac_address    = nb8800_set_mac_address,
+       .ndo_set_rx_mode        = nb8800_set_rx_mode,
+       .ndo_do_ioctl           = nb8800_ioctl,
+       .ndo_change_mtu         = eth_change_mtu,
+       .ndo_validate_addr      = eth_validate_addr,
+};
+
+static int nb8800_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
+{
+       struct nb8800_priv *priv = netdev_priv(dev);
+
+       if (!priv->phydev)
+               return -ENODEV;
+
+       return phy_ethtool_gset(priv->phydev, cmd);
+}
+
+static int nb8800_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
+{
+       struct nb8800_priv *priv = netdev_priv(dev);
+
+       if (!priv->phydev)
+               return -ENODEV;
+
+       return phy_ethtool_sset(priv->phydev, cmd);
+}
+
+static int nb8800_nway_reset(struct net_device *dev)
+{
+       struct nb8800_priv *priv = netdev_priv(dev);
+
+       if (!priv->phydev)
+               return -ENODEV;
+
+       return genphy_restart_aneg(priv->phydev);
+}
+
+static void nb8800_get_pauseparam(struct net_device *dev,
+                                 struct ethtool_pauseparam *pp)
+{
+       struct nb8800_priv *priv = netdev_priv(dev);
+
+       pp->autoneg = priv->pause_aneg;
+       pp->rx_pause = priv->pause_rx;
+       pp->tx_pause = priv->pause_tx;
+}
+
+static int nb8800_set_pauseparam(struct net_device *dev,
+                                struct ethtool_pauseparam *pp)
+{
+       struct nb8800_priv *priv = netdev_priv(dev);
+
+       priv->pause_aneg = pp->autoneg;
+       priv->pause_rx = pp->rx_pause;
+       priv->pause_tx = pp->tx_pause;
+
+       nb8800_pause_adv(dev);
+
+       if (!priv->pause_aneg)
+               nb8800_pause_config(dev);
+       else if (priv->phydev)
+               phy_start_aneg(priv->phydev);
+
+       return 0;
+}
+
+static const char nb8800_stats_names[][ETH_GSTRING_LEN] = {
+       "rx_bytes_ok",
+       "rx_frames_ok",
+       "rx_undersize_frames",
+       "rx_fragment_frames",
+       "rx_64_byte_frames",
+       "rx_127_byte_frames",
+       "rx_255_byte_frames",
+       "rx_511_byte_frames",
+       "rx_1023_byte_frames",
+       "rx_max_size_frames",
+       "rx_oversize_frames",
+       "rx_bad_fcs_frames",
+       "rx_broadcast_frames",
+       "rx_multicast_frames",
+       "rx_control_frames",
+       "rx_pause_frames",
+       "rx_unsup_control_frames",
+       "rx_align_error_frames",
+       "rx_overrun_frames",
+       "rx_jabber_frames",
+       "rx_bytes",
+       "rx_frames",
+
+       "tx_bytes_ok",
+       "tx_frames_ok",
+       "tx_64_byte_frames",
+       "tx_127_byte_frames",
+       "tx_255_byte_frames",
+       "tx_511_byte_frames",
+       "tx_1023_byte_frames",
+       "tx_max_size_frames",
+       "tx_oversize_frames",
+       "tx_broadcast_frames",
+       "tx_multicast_frames",
+       "tx_control_frames",
+       "tx_pause_frames",
+       "tx_underrun_frames",
+       "tx_single_collision_frames",
+       "tx_multi_collision_frames",
+       "tx_deferred_collision_frames",
+       "tx_late_collision_frames",
+       "tx_excessive_collision_frames",
+       "tx_bytes",
+       "tx_frames",
+       "tx_collisions",
+};
+
+#define NB8800_NUM_STATS ARRAY_SIZE(nb8800_stats_names)
+
+static int nb8800_get_sset_count(struct net_device *dev, int sset)
+{
+       if (sset == ETH_SS_STATS)
+               return NB8800_NUM_STATS;
+
+       return -EOPNOTSUPP;
+}
+
+static void nb8800_get_strings(struct net_device *dev, u32 sset, u8 *buf)
+{
+       if (sset == ETH_SS_STATS)
+               memcpy(buf, &nb8800_stats_names, sizeof(nb8800_stats_names));
+}
+
+static u32 nb8800_read_stat(struct net_device *dev, int index)
+{
+       struct nb8800_priv *priv = netdev_priv(dev);
+
+       nb8800_writeb(priv, NB8800_STAT_INDEX, index);
+
+       return nb8800_readl(priv, NB8800_STAT_DATA);
+}
+
+static void nb8800_get_ethtool_stats(struct net_device *dev,
+                                    struct ethtool_stats *estats, u64 *st)
+{
+       unsigned int i;
+       u32 rx, tx;
+
+       for (i = 0; i < NB8800_NUM_STATS / 2; i++) {
+               rx = nb8800_read_stat(dev, i);
+               tx = nb8800_read_stat(dev, i | 0x80);
+               st[i] = rx;
+               st[i + NB8800_NUM_STATS / 2] = tx;
+       }
+}
+
+static const struct ethtool_ops nb8800_ethtool_ops = {
+       .get_settings           = nb8800_get_settings,
+       .set_settings           = nb8800_set_settings,
+       .nway_reset             = nb8800_nway_reset,
+       .get_link               = ethtool_op_get_link,
+       .get_pauseparam         = nb8800_get_pauseparam,
+       .set_pauseparam         = nb8800_set_pauseparam,
+       .get_sset_count         = nb8800_get_sset_count,
+       .get_strings            = nb8800_get_strings,
+       .get_ethtool_stats      = nb8800_get_ethtool_stats,
+};
+
+static int nb8800_hw_init(struct net_device *dev)
+{
+       struct nb8800_priv *priv = netdev_priv(dev);
+       u32 val;
+
+       val = TX_RETRY_EN | TX_PAD_EN | TX_APPEND_FCS;
+       nb8800_writeb(priv, NB8800_TX_CTL1, val);
+
+       /* Collision retry count */
+       nb8800_writeb(priv, NB8800_TX_CTL2, 5);
+
+       val = RX_PAD_STRIP | RX_AF_EN;
+       nb8800_writeb(priv, NB8800_RX_CTL, val);
+
+       /* Chosen by fair dice roll */
+       nb8800_writeb(priv, NB8800_RANDOM_SEED, 4);
+
+       /* TX cycles per deferral period */
+       nb8800_writeb(priv, NB8800_TX_SDP, 12);
+
+       /* The following three threshold values have been
+        * experimentally determined for good results.
+        */
+
+       /* RX/TX FIFO threshold for partial empty (64-bit entries) */
+       nb8800_writeb(priv, NB8800_PE_THRESHOLD, 0);
+
+       /* RX/TX FIFO threshold for partial full (64-bit entries) */
+       nb8800_writeb(priv, NB8800_PF_THRESHOLD, 255);
+
+       /* Buffer size for transmit (64-bit entries) */
+       nb8800_writeb(priv, NB8800_TX_BUFSIZE, 64);
+
+       /* Configure tx DMA */
+
+       val = nb8800_readl(priv, NB8800_TXC_CR);
+       val &= TCR_LE;          /* keep endian setting */
+       val |= TCR_DM;          /* DMA descriptor mode */
+       val |= TCR_RS;          /* automatically store tx status  */
+       val |= TCR_DIE;         /* interrupt on DMA chain completion */
+       val |= TCR_TFI(7);      /* interrupt after 7 frames transmitted */
+       val |= TCR_BTS(2);      /* 32-byte bus transaction size */
+       nb8800_writel(priv, NB8800_TXC_CR, val);
+
+       /* TX complete interrupt after 10 ms or 7 frames (see above) */
+       val = clk_get_rate(priv->clk) / 100;
+       nb8800_writel(priv, NB8800_TX_ITR, val);
+
+       /* Configure rx DMA */
+
+       val = nb8800_readl(priv, NB8800_RXC_CR);
+       val &= RCR_LE;          /* keep endian setting */
+       val |= RCR_DM;          /* DMA descriptor mode */
+       val |= RCR_RS;          /* automatically store rx status */
+       val |= RCR_DIE;         /* interrupt at end of DMA chain */
+       val |= RCR_RFI(7);      /* interrupt after 7 frames received */
+       val |= RCR_BTS(2);      /* 32-byte bus transaction size */
+       nb8800_writel(priv, NB8800_RXC_CR, val);
+
+       /* The rx interrupt can fire before the DMA has completed
+        * unless a small delay is added.  50 us is hopefully enough.
+        */
+       priv->rx_itr_irq = clk_get_rate(priv->clk) / 20000;
+
+       /* In NAPI poll mode we want to disable interrupts, but the
+        * hardware does not permit this.  Delay 10 ms instead.
+        */
+       priv->rx_itr_poll = clk_get_rate(priv->clk) / 100;
+
+       nb8800_writel(priv, NB8800_RX_ITR, priv->rx_itr_irq);
+
+       priv->rx_dma_config = RX_BUF_SIZE | DESC_BTS(2) | DESC_DS | DESC_EOF;
+
+       /* Flow control settings */
+
+       /* Pause time of 0.1 ms */
+       val = 100000 / 512;
+       nb8800_writeb(priv, NB8800_PQ1, val >> 8);
+       nb8800_writeb(priv, NB8800_PQ2, val & 0xff);
+
+       /* Auto-negotiate by default */
+       priv->pause_aneg = true;
+       priv->pause_rx = true;
+       priv->pause_tx = true;
+
+       nb8800_mc_init(dev, 0);
+
+       return 0;
+}
+
+static int nb8800_tangox_init(struct net_device *dev)
+{
+       struct nb8800_priv *priv = netdev_priv(dev);
+       u32 pad_mode = PAD_MODE_MII;
+
+       switch (priv->phy_mode) {
+       case PHY_INTERFACE_MODE_MII:
+       case PHY_INTERFACE_MODE_GMII:
+               pad_mode = PAD_MODE_MII;
+               break;
+
+       case PHY_INTERFACE_MODE_RGMII:
+               pad_mode = PAD_MODE_RGMII;
+               break;
+
+       case PHY_INTERFACE_MODE_RGMII_TXID:
+               pad_mode = PAD_MODE_RGMII | PAD_MODE_GTX_CLK_DELAY;
+               break;
+
+       default:
+               dev_err(dev->dev.parent, "unsupported phy mode %s\n",
+                       phy_modes(priv->phy_mode));
+               return -EINVAL;
+       }
+
+       nb8800_writeb(priv, NB8800_TANGOX_PAD_MODE, pad_mode);
+
+       return 0;
+}
+
+static int nb8800_tangox_reset(struct net_device *dev)
+{
+       struct nb8800_priv *priv = netdev_priv(dev);
+       int clk_div;
+
+       nb8800_writeb(priv, NB8800_TANGOX_RESET, 0);
+       usleep_range(1000, 10000);
+       nb8800_writeb(priv, NB8800_TANGOX_RESET, 1);
+
+       wmb();          /* ensure reset is cleared before proceeding */
+
+       clk_div = DIV_ROUND_UP(clk_get_rate(priv->clk), 2 * MAX_MDC_CLOCK);
+       nb8800_writew(priv, NB8800_TANGOX_MDIO_CLKDIV, clk_div);
+
+       return 0;
+}
+
+static const struct nb8800_ops nb8800_tangox_ops = {
+       .init   = nb8800_tangox_init,
+       .reset  = nb8800_tangox_reset,
+};
+
+static int nb8800_tango4_init(struct net_device *dev)
+{
+       struct nb8800_priv *priv = netdev_priv(dev);
+       int err;
+
+       err = nb8800_tangox_init(dev);
+       if (err)
+               return err;
+
+       /* On tango4 interrupt on DMA completion per frame works and gives
+        * better performance despite generating more rx interrupts.
+        */
+
+       /* Disable unnecessary interrupt on rx completion */
+       nb8800_clearl(priv, NB8800_RXC_CR, RCR_RFI(7));
+
+       /* Request interrupt on descriptor DMA completion */
+       priv->rx_dma_config |= DESC_ID;
+
+       return 0;
+}
+
+static const struct nb8800_ops nb8800_tango4_ops = {
+       .init   = nb8800_tango4_init,
+       .reset  = nb8800_tangox_reset,
+};
+
+static const struct of_device_id nb8800_dt_ids[] = {
+       {
+               .compatible = "aurora,nb8800",
+       },
+       {
+               .compatible = "sigma,smp8642-ethernet",
+               .data = &nb8800_tangox_ops,
+       },
+       {
+               .compatible = "sigma,smp8734-ethernet",
+               .data = &nb8800_tango4_ops,
+       },
+       { }
+};
+
+static int nb8800_probe(struct platform_device *pdev)
+{
+       const struct of_device_id *match;
+       const struct nb8800_ops *ops = NULL;
+       struct nb8800_priv *priv;
+       struct resource *res;
+       struct net_device *dev;
+       struct mii_bus *bus;
+       const unsigned char *mac;
+       void __iomem *base;
+       int irq;
+       int ret;
+
+       match = of_match_device(nb8800_dt_ids, &pdev->dev);
+       if (match)
+               ops = match->data;
+
+       irq = platform_get_irq(pdev, 0);
+       if (irq <= 0) {
+               dev_err(&pdev->dev, "No IRQ\n");
+               return -EINVAL;
+       }
+
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       base = devm_ioremap_resource(&pdev->dev, res);
+       if (IS_ERR(base))
+               return PTR_ERR(base);
+
+       dev_dbg(&pdev->dev, "AU-NB8800 Ethernet at %pa\n", &res->start);
+
+       dev = alloc_etherdev(sizeof(*priv));
+       if (!dev)
+               return -ENOMEM;
+
+       platform_set_drvdata(pdev, dev);
+       SET_NETDEV_DEV(dev, &pdev->dev);
+
+       priv = netdev_priv(dev);
+       priv->base = base;
+
+       priv->phy_mode = of_get_phy_mode(pdev->dev.of_node);
+       if (priv->phy_mode < 0)
+               priv->phy_mode = PHY_INTERFACE_MODE_RGMII;
+
+       priv->clk = devm_clk_get(&pdev->dev, NULL);
+       if (IS_ERR(priv->clk)) {
+               dev_err(&pdev->dev, "failed to get clock\n");
+               ret = PTR_ERR(priv->clk);
+               goto err_free_dev;
+       }
+
+       ret = clk_prepare_enable(priv->clk);
+       if (ret)
+               goto err_free_dev;
+
+       spin_lock_init(&priv->tx_lock);
+
+       if (ops && ops->reset) {
+               ret = ops->reset(dev);
+               if (ret)
+                       goto err_free_dev;
+       }
+
+       bus = devm_mdiobus_alloc(&pdev->dev);
+       if (!bus) {
+               ret = -ENOMEM;
+               goto err_disable_clk;
+       }
+
+       bus->name = "nb8800-mii";
+       bus->read = nb8800_mdio_read;
+       bus->write = nb8800_mdio_write;
+       bus->parent = &pdev->dev;
+       snprintf(bus->id, MII_BUS_ID_SIZE, "%lx.nb8800-mii",
+                (unsigned long)res->start);
+       bus->priv = priv;
+
+       ret = of_mdiobus_register(bus, pdev->dev.of_node);
+       if (ret) {
+               dev_err(&pdev->dev, "failed to register MII bus\n");
+               goto err_disable_clk;
+       }
+
+       priv->phy_node = of_parse_phandle(pdev->dev.of_node, "phy-handle", 0);
+       if (!priv->phy_node) {
+               dev_err(&pdev->dev, "no PHY specified\n");
+               ret = -ENODEV;
+               goto err_free_bus;
+       }
+
+       priv->mii_bus = bus;
+
+       ret = nb8800_hw_init(dev);
+       if (ret)
+               goto err_free_bus;
+
+       if (ops && ops->init) {
+               ret = ops->init(dev);
+               if (ret)
+                       goto err_free_bus;
+       }
+
+       dev->netdev_ops = &nb8800_netdev_ops;
+       dev->ethtool_ops = &nb8800_ethtool_ops;
+       dev->flags |= IFF_MULTICAST;
+       dev->irq = irq;
+
+       mac = of_get_mac_address(pdev->dev.of_node);
+       if (mac)
+               ether_addr_copy(dev->dev_addr, mac);
+
+       if (!is_valid_ether_addr(dev->dev_addr))
+               eth_hw_addr_random(dev);
+
+       nb8800_update_mac_addr(dev);
+
+       netif_carrier_off(dev);
+
+       ret = register_netdev(dev);
+       if (ret) {
+               netdev_err(dev, "failed to register netdev\n");
+               goto err_free_dma;
+       }
+
+       netif_napi_add(dev, &priv->napi, nb8800_poll, NAPI_POLL_WEIGHT);
+
+       netdev_info(dev, "MAC address %pM\n", dev->dev_addr);
+
+       return 0;
+
+err_free_dma:
+       nb8800_dma_free(dev);
+err_free_bus:
+       mdiobus_unregister(bus);
+err_disable_clk:
+       clk_disable_unprepare(priv->clk);
+err_free_dev:
+       free_netdev(dev);
+
+       return ret;
+}
+
+static int nb8800_remove(struct platform_device *pdev)
+{
+       struct net_device *ndev = platform_get_drvdata(pdev);
+       struct nb8800_priv *priv = netdev_priv(ndev);
+
+       unregister_netdev(ndev);
+
+       mdiobus_unregister(priv->mii_bus);
+
+       clk_disable_unprepare(priv->clk);
+
+       nb8800_dma_free(ndev);
+       free_netdev(ndev);
+
+       return 0;
+}
+
+static struct platform_driver nb8800_driver = {
+       .driver = {
+               .name           = "nb8800",
+               .of_match_table = nb8800_dt_ids,
+       },
+       .probe  = nb8800_probe,
+       .remove = nb8800_remove,
+};
+
+module_platform_driver(nb8800_driver);
+
+MODULE_DESCRIPTION("Aurora AU-NB8800 Ethernet driver");
+MODULE_AUTHOR("Mans Rullgard <mans@mansr.com>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/net/ethernet/aurora/nb8800.h b/drivers/net/ethernet/aurora/nb8800.h
new file mode 100644 (file)
index 0000000..e5adbc2
--- /dev/null
@@ -0,0 +1,316 @@
+#ifndef _NB8800_H_
+#define _NB8800_H_
+
+#include <linux/types.h>
+#include <linux/skbuff.h>
+#include <linux/phy.h>
+#include <linux/clk.h>
+#include <linux/bitops.h>
+
+#define RX_DESC_COUNT                  256
+#define TX_DESC_COUNT                  256
+
+#define NB8800_DESC_LOW                        4
+
+#define RX_BUF_SIZE                    1552
+
+#define RX_COPYBREAK                   256
+#define RX_COPYHDR                     128
+
+#define MAX_MDC_CLOCK                  2500000
+
+/* Stargate Solutions SSN8800 core registers */
+#define NB8800_TX_CTL1                 0x000
+#define TX_TPD                         BIT(5)
+#define TX_APPEND_FCS                  BIT(4)
+#define TX_PAD_EN                      BIT(3)
+#define TX_RETRY_EN                    BIT(2)
+#define TX_EN                          BIT(0)
+
+#define NB8800_TX_CTL2                 0x001
+
+#define NB8800_RX_CTL                  0x004
+#define RX_BC_DISABLE                  BIT(7)
+#define RX_RUNT                                BIT(6)
+#define RX_AF_EN                       BIT(5)
+#define RX_PAUSE_EN                    BIT(3)
+#define RX_SEND_CRC                    BIT(2)
+#define RX_PAD_STRIP                   BIT(1)
+#define RX_EN                          BIT(0)
+
+#define NB8800_RANDOM_SEED             0x008
+#define NB8800_TX_SDP                  0x14
+#define NB8800_TX_TPDP1                        0x18
+#define NB8800_TX_TPDP2                        0x19
+#define NB8800_SLOT_TIME               0x1c
+
+#define NB8800_MDIO_CMD                        0x020
+#define MDIO_CMD_GO                    BIT(31)
+#define MDIO_CMD_WR                    BIT(26)
+#define MDIO_CMD_ADDR(x)               ((x) << 21)
+#define MDIO_CMD_REG(x)                        ((x) << 16)
+#define MDIO_CMD_DATA(x)               ((x) <<  0)
+
+#define NB8800_MDIO_STS                        0x024
+#define MDIO_STS_ERR                   BIT(31)
+
+#define NB8800_MC_ADDR(i)              (0x028 + (i))
+#define NB8800_MC_INIT                 0x02e
+#define NB8800_UC_ADDR(i)              (0x03c + (i))
+
+#define NB8800_MAC_MODE                        0x044
+#define RGMII_MODE                     BIT(7)
+#define HALF_DUPLEX                    BIT(4)
+#define BURST_EN                       BIT(3)
+#define LOOPBACK_EN                    BIT(2)
+#define GMAC_MODE                      BIT(0)
+
+#define NB8800_IC_THRESHOLD            0x050
+#define NB8800_PE_THRESHOLD            0x051
+#define NB8800_PF_THRESHOLD            0x052
+#define NB8800_TX_BUFSIZE              0x054
+#define NB8800_FIFO_CTL                        0x056
+#define NB8800_PQ1                     0x060
+#define NB8800_PQ2                     0x061
+#define NB8800_SRC_ADDR(i)             (0x06a + (i))
+#define NB8800_STAT_DATA               0x078
+#define NB8800_STAT_INDEX              0x07c
+#define NB8800_STAT_CLEAR              0x07d
+
+#define NB8800_SLEEP_MODE              0x07e
+#define SLEEP_MODE                     BIT(0)
+
+#define NB8800_WAKEUP                  0x07f
+#define WAKEUP                         BIT(0)
+
+/* Aurora NB8800 host interface registers */
+#define NB8800_TXC_CR                  0x100
+#define TCR_LK                         BIT(12)
+#define TCR_DS                         BIT(11)
+#define TCR_BTS(x)                     (((x) & 0x7) << 8)
+#define TCR_DIE                                BIT(7)
+#define TCR_TFI(x)                     (((x) & 0x7) << 4)
+#define TCR_LE                         BIT(3)
+#define TCR_RS                         BIT(2)
+#define TCR_DM                         BIT(1)
+#define TCR_EN                         BIT(0)
+
+#define NB8800_TXC_SR                  0x104
+#define TSR_DE                         BIT(3)
+#define TSR_DI                         BIT(2)
+#define TSR_TO                         BIT(1)
+#define TSR_TI                         BIT(0)
+
+#define NB8800_TX_SAR                  0x108
+#define NB8800_TX_DESC_ADDR            0x10c
+
+#define NB8800_TX_REPORT_ADDR          0x110
+#define TX_BYTES_TRANSFERRED(x)                (((x) >> 16) & 0xffff)
+#define TX_FIRST_DEFERRAL              BIT(7)
+#define TX_EARLY_COLLISIONS(x)         (((x) >> 3) & 0xf)
+#define TX_LATE_COLLISION              BIT(2)
+#define TX_PACKET_DROPPED              BIT(1)
+#define TX_FIFO_UNDERRUN               BIT(0)
+#define IS_TX_ERROR(r)                 ((r) & 0x07)
+
+#define NB8800_TX_FIFO_SR              0x114
+#define NB8800_TX_ITR                  0x118
+
+#define NB8800_RXC_CR                  0x200
+#define RCR_FL                         BIT(13)
+#define RCR_LK                         BIT(12)
+#define RCR_DS                         BIT(11)
+#define RCR_BTS(x)                     (((x) & 7) << 8)
+#define RCR_DIE                                BIT(7)
+#define RCR_RFI(x)                     (((x) & 7) << 4)
+#define RCR_LE                         BIT(3)
+#define RCR_RS                         BIT(2)
+#define RCR_DM                         BIT(1)
+#define RCR_EN                         BIT(0)
+
+#define NB8800_RXC_SR                  0x204
+#define RSR_DE                         BIT(3)
+#define RSR_DI                         BIT(2)
+#define RSR_RO                         BIT(1)
+#define RSR_RI                         BIT(0)
+
+#define NB8800_RX_SAR                  0x208
+#define NB8800_RX_DESC_ADDR            0x20c
+
+#define NB8800_RX_REPORT_ADDR          0x210
+#define RX_BYTES_TRANSFERRED(x)                (((x) >> 16) & 0xFFFF)
+#define RX_MULTICAST_PKT               BIT(9)
+#define RX_BROADCAST_PKT               BIT(8)
+#define RX_LENGTH_ERR                  BIT(7)
+#define RX_FCS_ERR                     BIT(6)
+#define RX_RUNT_PKT                    BIT(5)
+#define RX_FIFO_OVERRUN                        BIT(4)
+#define RX_LATE_COLLISION              BIT(3)
+#define RX_ALIGNMENT_ERROR             BIT(2)
+#define RX_ERROR_MASK                  0xfc
+#define IS_RX_ERROR(r)                 ((r) & RX_ERROR_MASK)
+
+#define NB8800_RX_FIFO_SR              0x214
+#define NB8800_RX_ITR                  0x218
+
+/* Sigma Designs SMP86xx additional registers */
+#define NB8800_TANGOX_PAD_MODE         0x400
+#define PAD_MODE_MASK                  0x7
+#define PAD_MODE_MII                   0x0
+#define PAD_MODE_RGMII                 0x1
+#define PAD_MODE_GTX_CLK_INV           BIT(3)
+#define PAD_MODE_GTX_CLK_DELAY         BIT(4)
+
+#define NB8800_TANGOX_MDIO_CLKDIV      0x420
+#define NB8800_TANGOX_RESET            0x424
+
+/* Hardware DMA descriptor */
+struct nb8800_dma_desc {
+       u32                             s_addr; /* start address */
+       u32                             n_addr; /* next descriptor address */
+       u32                             r_addr; /* report address */
+       u32                             config;
+} __aligned(8);
+
+#define DESC_ID                                BIT(23)
+#define DESC_EOC                       BIT(22)
+#define DESC_EOF                       BIT(21)
+#define DESC_LK                                BIT(20)
+#define DESC_DS                                BIT(19)
+#define DESC_BTS(x)                    (((x) & 0x7) << 16)
+
+/* DMA descriptor and associated data for rx.
+ * Allocated from coherent memory.
+ */
+struct nb8800_rx_desc {
+       /* DMA descriptor */
+       struct nb8800_dma_desc          desc;
+
+       /* Status report filled in by hardware */
+       u32                             report;
+};
+
+/* Address of buffer on rx ring */
+struct nb8800_rx_buf {
+       struct page                     *page;
+       unsigned long                   offset;
+};
+
+/* DMA descriptors and associated data for tx.
+ * Allocated from coherent memory.
+ */
+struct nb8800_tx_desc {
+       /* DMA descriptor.  The second descriptor is used if packet
+        * data is unaligned.
+        */
+       struct nb8800_dma_desc          desc[2];
+
+       /* Status report filled in by hardware */
+       u32                             report;
+
+       /* Bounce buffer for initial unaligned part of packet */
+       u8                              buf[8] __aligned(8);
+};
+
+/* Packet in tx queue */
+struct nb8800_tx_buf {
+       /* Currently queued skb */
+       struct sk_buff                  *skb;
+
+       /* DMA address of the first descriptor */
+       dma_addr_t                      dma_desc;
+
+       /* DMA address of packet data */
+       dma_addr_t                      dma_addr;
+
+       /* Length of DMA mapping, less than skb->len if alignment
+        * buffer is used.
+        */
+       unsigned int                    dma_len;
+
+       /* Number of packets in chain starting here */
+       unsigned int                    chain_len;
+
+       /* Packet chain ready to be submitted to hardware */
+       bool                            ready;
+};
+
+struct nb8800_priv {
+       struct napi_struct              napi;
+
+       void __iomem                    *base;
+
+       /* RX DMA descriptors */
+       struct nb8800_rx_desc           *rx_descs;
+
+       /* RX buffers referenced by DMA descriptors */
+       struct nb8800_rx_buf            *rx_bufs;
+
+       /* Current end of chain */
+       u32                             rx_eoc;
+
+       /* Value for rx interrupt time register in NAPI interrupt mode */
+       u32                             rx_itr_irq;
+
+       /* Value for rx interrupt time register in NAPI poll mode */
+       u32                             rx_itr_poll;
+
+       /* Value for config field of rx DMA descriptors */
+       u32                             rx_dma_config;
+
+       /* TX DMA descriptors */
+       struct nb8800_tx_desc           *tx_descs;
+
+       /* TX packet queue */
+       struct nb8800_tx_buf            *tx_bufs;
+
+       /* Number of free tx queue entries */
+       atomic_t                        tx_free;
+
+       /* First free tx queue entry */
+       u32                             tx_next;
+
+       /* Next buffer to transmit */
+       u32                             tx_queue;
+
+       /* Start of current packet chain */
+       struct nb8800_tx_buf            *tx_chain;
+
+       /* Next buffer to reclaim */
+       u32                             tx_done;
+
+       /* Lock for DMA activation */
+       spinlock_t                      tx_lock;
+
+       struct mii_bus                  *mii_bus;
+       struct device_node              *phy_node;
+       struct phy_device               *phydev;
+
+       /* PHY connection type from DT */
+       int                             phy_mode;
+
+       /* Current link status */
+       int                             speed;
+       int                             duplex;
+       int                             link;
+
+       /* Pause settings */
+       bool                            pause_aneg;
+       bool                            pause_rx;
+       bool                            pause_tx;
+
+       /* DMA base address of rx descriptors, see rx_descs above */
+       dma_addr_t                      rx_desc_dma;
+
+       /* DMA base address of tx descriptors, see tx_descs above */
+       dma_addr_t                      tx_desc_dma;
+
+       struct clk                      *clk;
+};
+
+struct nb8800_ops {
+       int                             (*init)(struct net_device *dev);
+       int                             (*reset)(struct net_device *dev);
+};
+
+#endif /* _NB8800_H_ */
index f8d7a2f06950139b936dc7d793bb884bb579980d..c82ab87fcbe8fb09e59be79f866910751f4b4308 100644 (file)
@@ -3430,25 +3430,29 @@ static u32 bnx2x_xmit_type(struct bnx2x *bp, struct sk_buff *skb)
        return rc;
 }
 
-#if (MAX_SKB_FRAGS >= MAX_FETCH_BD - 3)
+/* VXLAN: 4 = 1 (for linear data BD) + 3 (2 for PBD and last BD) */
+#define BNX2X_NUM_VXLAN_TSO_WIN_SUB_BDS         4
+
+/* Regular: 3 = 1 (for linear data BD) + 2 (for PBD and last BD) */
+#define BNX2X_NUM_TSO_WIN_SUB_BDS               3
+
+#if (MAX_SKB_FRAGS >= MAX_FETCH_BD - BDS_PER_TX_PKT)
 /* check if packet requires linearization (packet is too fragmented)
    no need to check fragmentation if page size > 8K (there will be no
    violation to FW restrictions) */
 static int bnx2x_pkt_req_lin(struct bnx2x *bp, struct sk_buff *skb,
                             u32 xmit_type)
 {
-       int to_copy = 0;
-       int hlen = 0;
-       int first_bd_sz = 0;
+       int first_bd_sz = 0, num_tso_win_sub = BNX2X_NUM_TSO_WIN_SUB_BDS;
+       int to_copy = 0, hlen = 0;
 
-       /* 3 = 1 (for linear data BD) + 2 (for PBD and last BD) */
-       if (skb_shinfo(skb)->nr_frags >= (MAX_FETCH_BD - 3)) {
+       if (xmit_type & XMIT_GSO_ENC)
+               num_tso_win_sub = BNX2X_NUM_VXLAN_TSO_WIN_SUB_BDS;
 
+       if (skb_shinfo(skb)->nr_frags >= (MAX_FETCH_BD - num_tso_win_sub)) {
                if (xmit_type & XMIT_GSO) {
                        unsigned short lso_mss = skb_shinfo(skb)->gso_size;
-                       /* Check if LSO packet needs to be copied:
-                          3 = 1 (for headers BD) + 2 (for PBD and last BD) */
-                       int wnd_size = MAX_FETCH_BD - 3;
+                       int wnd_size = MAX_FETCH_BD - num_tso_win_sub;
                        /* Number of windows to check */
                        int num_wnds = skb_shinfo(skb)->nr_frags - wnd_size;
                        int wnd_idx = 0;
index f1d62d5dbaff9a83ccacd0a530c855b14209eb7a..2e611dc5f16210393852110c7dda5dadf4dfc560 100644 (file)
@@ -10139,8 +10139,8 @@ static void __bnx2x_del_vxlan_port(struct bnx2x *bp, u16 port)
                DP(BNX2X_MSG_SP, "Invalid vxlan port\n");
                return;
        }
-       bp->vxlan_dst_port--;
-       if (bp->vxlan_dst_port)
+       bp->vxlan_dst_port_count--;
+       if (bp->vxlan_dst_port_count)
                return;
 
        if (netif_running(bp->dev)) {
@@ -13207,7 +13207,7 @@ static int bnx2x_init_dev(struct bnx2x *bp, struct pci_dev *pdev,
 
        /* VF with OLD Hypervisor or old PF do not support filtering */
        if (IS_PF(bp)) {
-               if (CHIP_IS_E1x(bp))
+               if (chip_is_e1x)
                        bp->accept_any_vlan = true;
                else
                        dev->hw_features |= NETIF_F_HW_VLAN_CTAG_FILTER;
index db15c5ee09c53a528ea405961734dae927af0e06..07f5f239cb65baca35792dd5ba7a979d2b36b763 100644 (file)
@@ -2693,17 +2693,16 @@ static int bnxt_hwrm_func_drv_rgtr(struct bnxt *bp)
        req.ver_upd = DRV_VER_UPD;
 
        if (BNXT_PF(bp)) {
-               unsigned long vf_req_snif_bmap[4];
+               DECLARE_BITMAP(vf_req_snif_bmap, 256);
                u32 *data = (u32 *)vf_req_snif_bmap;
 
-               memset(vf_req_snif_bmap, 0, 32);
+               memset(vf_req_snif_bmap, 0, sizeof(vf_req_snif_bmap));
                for (i = 0; i < ARRAY_SIZE(bnxt_vf_req_snif); i++)
                        __set_bit(bnxt_vf_req_snif[i], vf_req_snif_bmap);
 
-               for (i = 0; i < 8; i++) {
-                       req.vf_req_fwd[i] = cpu_to_le32(*data);
-                       data++;
-               }
+               for (i = 0; i < 8; i++)
+                       req.vf_req_fwd[i] = cpu_to_le32(data[i]);
+
                req.enables |=
                        cpu_to_le32(FUNC_DRV_RGTR_REQ_ENABLES_VF_REQ_FWD);
        }
@@ -3625,6 +3624,7 @@ static int bnxt_hwrm_func_qcaps(struct bnxt *bp)
                pf->fw_fid = le16_to_cpu(resp->fid);
                pf->port_id = le16_to_cpu(resp->port_id);
                memcpy(pf->mac_addr, resp->perm_mac_address, ETH_ALEN);
+               memcpy(bp->dev->dev_addr, pf->mac_addr, ETH_ALEN);
                pf->max_rsscos_ctxs = le16_to_cpu(resp->max_rsscos_ctx);
                pf->max_cp_rings = le16_to_cpu(resp->max_cmpl_rings);
                pf->max_tx_rings = le16_to_cpu(resp->max_tx_rings);
@@ -3648,8 +3648,11 @@ static int bnxt_hwrm_func_qcaps(struct bnxt *bp)
 
                vf->fw_fid = le16_to_cpu(resp->fid);
                memcpy(vf->mac_addr, resp->perm_mac_address, ETH_ALEN);
-               if (!is_valid_ether_addr(vf->mac_addr))
-                       random_ether_addr(vf->mac_addr);
+               if (is_valid_ether_addr(vf->mac_addr))
+                       /* overwrite netdev dev_adr with admin VF MAC */
+                       memcpy(bp->dev->dev_addr, vf->mac_addr, ETH_ALEN);
+               else
+                       random_ether_addr(bp->dev->dev_addr);
 
                vf->max_rsscos_ctxs = le16_to_cpu(resp->max_rsscos_ctx);
                vf->max_cp_rings = le16_to_cpu(resp->max_cmpl_rings);
@@ -3880,6 +3883,8 @@ static int bnxt_alloc_rfs_vnics(struct bnxt *bp)
 #endif
 }
 
+static int bnxt_cfg_rx_mode(struct bnxt *);
+
 static int bnxt_init_chip(struct bnxt *bp, bool irq_re_init)
 {
        int rc = 0;
@@ -3946,11 +3951,9 @@ static int bnxt_init_chip(struct bnxt *bp, bool irq_re_init)
                bp->vnic_info[0].rx_mask |=
                                CFA_L2_SET_RX_MASK_REQ_MASK_PROMISCUOUS;
 
-       rc = bnxt_hwrm_cfa_l2_set_rx_mask(bp, 0);
-       if (rc) {
-               netdev_err(bp->dev, "HWRM cfa l2 rx mask failure rc: %x\n", rc);
+       rc = bnxt_cfg_rx_mode(bp);
+       if (rc)
                goto err_out;
-       }
 
        rc = bnxt_hwrm_set_coal(bp);
        if (rc)
@@ -4599,7 +4602,7 @@ static int __bnxt_open_nic(struct bnxt *bp, bool irq_re_init, bool link_re_init)
                        bp->nge_port_cnt = 1;
        }
 
-       bp->state = BNXT_STATE_OPEN;
+       set_bit(BNXT_STATE_OPEN, &bp->state);
        bnxt_enable_int(bp);
        /* Enable TX queues */
        bnxt_tx_enable(bp);
@@ -4675,8 +4678,10 @@ int bnxt_close_nic(struct bnxt *bp, bool irq_re_init, bool link_re_init)
        /* Change device state to avoid TX queue wake up's */
        bnxt_tx_disable(bp);
 
-       bp->state = BNXT_STATE_CLOSED;
-       cancel_work_sync(&bp->sp_task);
+       clear_bit(BNXT_STATE_OPEN, &bp->state);
+       smp_mb__after_atomic();
+       while (test_bit(BNXT_STATE_IN_SP_TASK, &bp->state))
+               msleep(20);
 
        /* Flush rings before disabling interrupts */
        bnxt_shutdown_nic(bp, irq_re_init);
@@ -4865,7 +4870,7 @@ static void bnxt_set_rx_mode(struct net_device *dev)
        }
 }
 
-static void bnxt_cfg_rx_mode(struct bnxt *bp)
+static int bnxt_cfg_rx_mode(struct bnxt *bp)
 {
        struct net_device *dev = bp->dev;
        struct bnxt_vnic_info *vnic = &bp->vnic_info[0];
@@ -4914,6 +4919,7 @@ static void bnxt_cfg_rx_mode(struct bnxt *bp)
                        netdev_err(bp->dev, "HWRM vnic filter failure rc: %x\n",
                                   rc);
                        vnic->uc_filter_count = i;
+                       return rc;
                }
        }
 
@@ -4922,6 +4928,8 @@ skip_uc:
        if (rc)
                netdev_err(bp->dev, "HWRM cfa l2 rx mask failure rc: %x\n",
                           rc);
+
+       return rc;
 }
 
 static netdev_features_t bnxt_fix_features(struct net_device *dev,
@@ -5023,8 +5031,10 @@ static void bnxt_dbg_dump_states(struct bnxt *bp)
 static void bnxt_reset_task(struct bnxt *bp)
 {
        bnxt_dbg_dump_states(bp);
-       if (netif_running(bp->dev))
-               bnxt_tx_disable(bp); /* prevent tx timout again */
+       if (netif_running(bp->dev)) {
+               bnxt_close_nic(bp, false, false);
+               bnxt_open_nic(bp, false, false);
+       }
 }
 
 static void bnxt_tx_timeout(struct net_device *dev)
@@ -5074,8 +5084,12 @@ static void bnxt_sp_task(struct work_struct *work)
        struct bnxt *bp = container_of(work, struct bnxt, sp_task);
        int rc;
 
-       if (bp->state != BNXT_STATE_OPEN)
+       set_bit(BNXT_STATE_IN_SP_TASK, &bp->state);
+       smp_mb__after_atomic();
+       if (!test_bit(BNXT_STATE_OPEN, &bp->state)) {
+               clear_bit(BNXT_STATE_IN_SP_TASK, &bp->state);
                return;
+       }
 
        if (test_and_clear_bit(BNXT_RX_MASK_SP_EVENT, &bp->sp_event))
                bnxt_cfg_rx_mode(bp);
@@ -5099,8 +5113,19 @@ static void bnxt_sp_task(struct work_struct *work)
                bnxt_hwrm_tunnel_dst_port_free(
                        bp, TUNNEL_DST_PORT_FREE_REQ_TUNNEL_TYPE_VXLAN);
        }
-       if (test_and_clear_bit(BNXT_RESET_TASK_SP_EVENT, &bp->sp_event))
+       if (test_and_clear_bit(BNXT_RESET_TASK_SP_EVENT, &bp->sp_event)) {
+               /* bnxt_reset_task() calls bnxt_close_nic() which waits
+                * for BNXT_STATE_IN_SP_TASK to clear.
+                */
+               clear_bit(BNXT_STATE_IN_SP_TASK, &bp->state);
+               rtnl_lock();
                bnxt_reset_task(bp);
+               set_bit(BNXT_STATE_IN_SP_TASK, &bp->state);
+               rtnl_unlock();
+       }
+
+       smp_mb__before_atomic();
+       clear_bit(BNXT_STATE_IN_SP_TASK, &bp->state);
 }
 
 static int bnxt_init_board(struct pci_dev *pdev, struct net_device *dev)
@@ -5179,7 +5204,7 @@ static int bnxt_init_board(struct pci_dev *pdev, struct net_device *dev)
        bp->timer.function = bnxt_timer;
        bp->current_interval = BNXT_TIMER_INTERVAL;
 
-       bp->state = BNXT_STATE_CLOSED;
+       clear_bit(BNXT_STATE_OPEN, &bp->state);
 
        return 0;
 
@@ -5212,13 +5237,27 @@ init_err:
 static int bnxt_change_mac_addr(struct net_device *dev, void *p)
 {
        struct sockaddr *addr = p;
+       struct bnxt *bp = netdev_priv(dev);
+       int rc = 0;
 
        if (!is_valid_ether_addr(addr->sa_data))
                return -EADDRNOTAVAIL;
 
+#ifdef CONFIG_BNXT_SRIOV
+       if (BNXT_VF(bp) && is_valid_ether_addr(bp->vf.mac_addr))
+               return -EADDRNOTAVAIL;
+#endif
+
+       if (ether_addr_equal(addr->sa_data, dev->dev_addr))
+               return 0;
+
        memcpy(dev->dev_addr, addr->sa_data, dev->addr_len);
+       if (netif_running(dev)) {
+               bnxt_close_nic(bp, false, false);
+               rc = bnxt_open_nic(bp, false, false);
+       }
 
-       return 0;
+       return rc;
 }
 
 /* rtnl_lock held */
@@ -5686,15 +5725,12 @@ static int bnxt_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
        bnxt_set_tpa_flags(bp);
        bnxt_set_ring_params(bp);
        dflt_rings = netif_get_num_default_rss_queues();
-       if (BNXT_PF(bp)) {
-               memcpy(dev->dev_addr, bp->pf.mac_addr, ETH_ALEN);
+       if (BNXT_PF(bp))
                bp->pf.max_irqs = max_irqs;
-       } else {
 #if defined(CONFIG_BNXT_SRIOV)
-               memcpy(dev->dev_addr, bp->vf.mac_addr, ETH_ALEN);
+       else
                bp->vf.max_irqs = max_irqs;
 #endif
-       }
        bnxt_get_max_rings(bp, &max_rx_rings, &max_tx_rings);
        bp->rx_nr_rings = min_t(int, dflt_rings, max_rx_rings);
        bp->tx_nr_rings_per_tc = min_t(int, dflt_rings, max_tx_rings);
index 674bc5159b91c7cd4972561fae11dd1bbed7d53c..f199f4cc8ffe05e7c5580dcc8b14b29ab1b8f3e9 100644 (file)
@@ -925,9 +925,9 @@ struct bnxt {
 
        struct timer_list       timer;
 
-       int                     state;
-#define BNXT_STATE_CLOSED      0
-#define BNXT_STATE_OPEN                1
+       unsigned long           state;
+#define BNXT_STATE_OPEN                0
+#define BNXT_STATE_IN_SP_TASK  1
 
        struct bnxt_irq *irq_tbl;
        u8                      mac_addr[ETH_ALEN];
index f4cf6886106906d90bff221038b83914d9bbbd24..ea044bbcd384886413cea2e2415aea8d25d28cf1 100644 (file)
@@ -21,7 +21,7 @@
 #ifdef CONFIG_BNXT_SRIOV
 static int bnxt_vf_ndo_prep(struct bnxt *bp, int vf_id)
 {
-       if (bp->state != BNXT_STATE_OPEN) {
+       if (!test_bit(BNXT_STATE_OPEN, &bp->state)) {
                netdev_err(bp->dev, "vf ndo called though PF is down\n");
                return -EINVAL;
        }
@@ -804,10 +804,9 @@ void bnxt_update_vf_mac(struct bnxt *bp)
        if (!is_valid_ether_addr(resp->perm_mac_address))
                goto update_vf_mac_exit;
 
-       if (ether_addr_equal(resp->perm_mac_address, bp->vf.mac_addr))
-               goto update_vf_mac_exit;
-
-       memcpy(bp->vf.mac_addr, resp->perm_mac_address, ETH_ALEN);
+       if (!ether_addr_equal(resp->perm_mac_address, bp->vf.mac_addr))
+               memcpy(bp->vf.mac_addr, resp->perm_mac_address, ETH_ALEN);
+       /* overwrite netdev dev_adr with admin VF MAC */
        memcpy(bp->dev->dev_addr, bp->vf.mac_addr, ETH_ALEN);
 update_vf_mac_exit:
        mutex_unlock(&bp->hwrm_cmd_lock);
index 88c1e1a834f8c44491c76269be7c6aa805906ab2..169059c92f80b776fb3901578ba56bb959624a07 100644 (file)
@@ -1682,6 +1682,8 @@ static void macb_init_hw(struct macb *bp)
        macb_set_hwaddr(bp);
 
        config = macb_mdc_clk_div(bp);
+       if (bp->phy_interface == PHY_INTERFACE_MODE_SGMII)
+               config |= GEM_BIT(SGMIIEN) | GEM_BIT(PCSSEL);
        config |= MACB_BF(RBOF, NET_IP_ALIGN);  /* Make eth data aligned */
        config |= MACB_BIT(PAE);                /* PAuse Enable */
        config |= MACB_BIT(DRFCS);              /* Discard Rx FCS */
@@ -2416,6 +2418,8 @@ static int macb_init(struct platform_device *pdev)
        /* Set MII management clock divider */
        val = macb_mdc_clk_div(bp);
        val |= macb_dbw(bp);
+       if (bp->phy_interface == PHY_INTERFACE_MODE_SGMII)
+               val |= GEM_BIT(SGMIIEN) | GEM_BIT(PCSSEL);
        macb_writel(bp, NCFGR, val);
 
        return 0;
index 6e1faea00ca829f5c9df34b45518d7e1a881c5c3..d83b0db7782194ad0695f0d2454a69ccf1d68220 100644 (file)
 /* GEM specific NCFGR bitfields. */
 #define GEM_GBE_OFFSET         10 /* Gigabit mode enable */
 #define GEM_GBE_SIZE           1
+#define GEM_PCSSEL_OFFSET      11
+#define GEM_PCSSEL_SIZE                1
 #define GEM_CLK_OFFSET         18 /* MDC clock division */
 #define GEM_CLK_SIZE           3
 #define GEM_DBW_OFFSET         21 /* Data bus width */
 #define GEM_DBW_SIZE           2
 #define GEM_RXCOEN_OFFSET      24
 #define GEM_RXCOEN_SIZE                1
+#define GEM_SGMIIEN_OFFSET     27
+#define GEM_SGMIIEN_SIZE       1
+
 
 /* Constants for data bus width. */
 #define GEM_DBW32              0 /* 32 bit AMBA AHB data bus width */
index f683d97d7614e7414ccf837ead2e2a507b07e4d3..b89504405b7207f12663aee0d6d3ecf78d392235 100644 (file)
@@ -560,7 +560,7 @@ static int liquidio_resume(struct pci_dev *pdev)
 #endif
 
 /* For PCI-E Advanced Error Recovery (AER) Interface */
-static struct pci_error_handlers liquidio_err_handler = {
+static const struct pci_error_handlers liquidio_err_handler = {
        .error_detected = liquidio_pcie_error_detected,
        .mmio_enabled   = liquidio_pcie_mmio_enabled,
        .slot_reset     = liquidio_pcie_slot_reset,
index d3950b20feb9e2a62d5a13aab9b08e0683fb7365..39ca6744a4e68fe317f93e1318e729509c1b978e 100644 (file)
  * Calculated for SCLK of 700Mhz
  * value written should be a 1/16th of what is expected
  *
- * 1 tick per 0.05usec = value of 2.2
- * This 10% would be covered in CQ timer thresh value
+ * 1 tick per 0.025usec
  */
-#define NICPF_CLK_PER_INT_TICK         2
+#define NICPF_CLK_PER_INT_TICK         1
 
 /* Time to wait before we decide that a SQ is stuck.
  *
index c561fdcb79a730aeeb890c5a985b05cb873faa45..5f24d11cb16aad5ae6bd474d538053ac6465c868 100644 (file)
@@ -615,6 +615,21 @@ static int nic_config_loopback(struct nicpf *nic, struct set_loopback *lbk)
        return 0;
 }
 
+static void nic_enable_vf(struct nicpf *nic, int vf, bool enable)
+{
+       int bgx, lmac;
+
+       nic->vf_enabled[vf] = enable;
+
+       if (vf >= nic->num_vf_en)
+               return;
+
+       bgx = NIC_GET_BGX_FROM_VF_LMAC_MAP(nic->vf_lmac_map[vf]);
+       lmac = NIC_GET_LMAC_FROM_VF_LMAC_MAP(nic->vf_lmac_map[vf]);
+
+       bgx_lmac_rx_tx_enable(nic->node, bgx, lmac, enable);
+}
+
 /* Interrupt handler to handle mailbox messages from VFs */
 static void nic_handle_mbx_intr(struct nicpf *nic, int vf)
 {
@@ -714,14 +729,14 @@ static void nic_handle_mbx_intr(struct nicpf *nic, int vf)
                break;
        case NIC_MBOX_MSG_CFG_DONE:
                /* Last message of VF config msg sequence */
-               nic->vf_enabled[vf] = true;
+               nic_enable_vf(nic, vf, true);
                goto unlock;
        case NIC_MBOX_MSG_SHUTDOWN:
                /* First msg in VF teardown sequence */
-               nic->vf_enabled[vf] = false;
                if (vf >= nic->num_vf_en)
                        nic->sqs_used[vf - nic->num_vf_en] = false;
                nic->pqs_vf[vf] = 0;
+               nic_enable_vf(nic, vf, false);
                break;
        case NIC_MBOX_MSG_ALLOC_SQS:
                nic_alloc_sqs(nic, &mbx.sqs_alloc);
@@ -1074,8 +1089,7 @@ static void nic_remove(struct pci_dev *pdev)
 
        if (nic->check_link) {
                /* Destroy work Queue */
-               cancel_delayed_work(&nic->dwork);
-               flush_workqueue(nic->check_link);
+               cancel_delayed_work_sync(&nic->dwork);
                destroy_workqueue(nic->check_link);
        }
 
index af54c10945c25175e344ebf052e47e88c62219a3..a12b2e38cf61221fc4de44f6395eb60de76825a5 100644 (file)
@@ -112,6 +112,13 @@ static int nicvf_get_settings(struct net_device *netdev,
 
        cmd->supported = 0;
        cmd->transceiver = XCVR_EXTERNAL;
+
+       if (!nic->link_up) {
+               cmd->duplex = DUPLEX_UNKNOWN;
+               ethtool_cmd_speed_set(cmd, SPEED_UNKNOWN);
+               return 0;
+       }
+
        if (nic->speed <= 1000) {
                cmd->port = PORT_MII;
                cmd->autoneg = AUTONEG_ENABLE;
@@ -125,6 +132,13 @@ static int nicvf_get_settings(struct net_device *netdev,
        return 0;
 }
 
+static u32 nicvf_get_link(struct net_device *netdev)
+{
+       struct nicvf *nic = netdev_priv(netdev);
+
+       return nic->link_up;
+}
+
 static void nicvf_get_drvinfo(struct net_device *netdev,
                              struct ethtool_drvinfo *info)
 {
@@ -660,7 +674,7 @@ static int nicvf_set_channels(struct net_device *dev,
 
 static const struct ethtool_ops nicvf_ethtool_ops = {
        .get_settings           = nicvf_get_settings,
-       .get_link               = ethtool_op_get_link,
+       .get_link               = nicvf_get_link,
        .get_drvinfo            = nicvf_get_drvinfo,
        .get_msglevel           = nicvf_get_msglevel,
        .set_msglevel           = nicvf_set_msglevel,
index a9377727c11c3fdb18a09f16ce8366ae4ef48057..dde8dc720cd3f3b7d513776662a4f05b1241486d 100644 (file)
@@ -1057,6 +1057,7 @@ int nicvf_stop(struct net_device *netdev)
 
        netif_carrier_off(netdev);
        netif_tx_stop_all_queues(nic->netdev);
+       nic->link_up = false;
 
        /* Teardown secondary qsets first */
        if (!nic->sqs_mode) {
@@ -1211,9 +1212,6 @@ int nicvf_open(struct net_device *netdev)
        nic->drv_stats.txq_stop = 0;
        nic->drv_stats.txq_wake = 0;
 
-       netif_carrier_on(netdev);
-       netif_tx_start_all_queues(netdev);
-
        return 0;
 cleanup:
        nicvf_disable_intr(nic, NICVF_INTR_MBOX, 0);
@@ -1583,8 +1581,14 @@ err_disable_device:
 static void nicvf_remove(struct pci_dev *pdev)
 {
        struct net_device *netdev = pci_get_drvdata(pdev);
-       struct nicvf *nic = netdev_priv(netdev);
-       struct net_device *pnetdev = nic->pnicvf->netdev;
+       struct nicvf *nic;
+       struct net_device *pnetdev;
+
+       if (!netdev)
+               return;
+
+       nic = netdev_priv(netdev);
+       pnetdev = nic->pnicvf->netdev;
 
        /* Check if this Qset is assigned to different VF.
         * If yes, clean primary and all secondary Qsets.
index e404ea837727eada97159544ccaca9406c7dd940..206b6a71a545aff776cdd88809c2f59b2f9d1216 100644 (file)
@@ -592,7 +592,7 @@ void nicvf_cmp_queue_config(struct nicvf *nic, struct queue_set *qs,
        /* Set threshold value for interrupt generation */
        nicvf_queue_reg_write(nic, NIC_QSET_CQ_0_7_THRESH, qidx, cq->thresh);
        nicvf_queue_reg_write(nic, NIC_QSET_CQ_0_7_CFG2,
-                             qidx, nic->cq_coalesce_usecs);
+                             qidx, CMP_QUEUE_TIMER_THRESH);
 }
 
 /* Configures transmit queue */
index fb4957d099144ca7ff62064b66be137dbbf6733e..033e8306e91c6942862ffe9dae0ca3836a8228f5 100644 (file)
@@ -76,7 +76,7 @@
 #define CMP_QSIZE              CMP_QUEUE_SIZE2
 #define CMP_QUEUE_LEN          (1ULL << (CMP_QSIZE + 10))
 #define CMP_QUEUE_CQE_THRESH   0
-#define CMP_QUEUE_TIMER_THRESH 220 /* 10usec */
+#define CMP_QUEUE_TIMER_THRESH 80 /* ~2usec */
 
 #define RBDR_SIZE              RBDR_SIZE0
 #define RCV_BUF_COUNT          (1ULL << (RBDR_SIZE + 13))
index 180aa9fabf4820df042f18cba8c39d5ce1668e9d..9df26c2263bcc37bdfced23e2db688c151942733 100644 (file)
@@ -186,6 +186,23 @@ void bgx_set_lmac_mac(int node, int bgx_idx, int lmacid, const u8 *mac)
 }
 EXPORT_SYMBOL(bgx_set_lmac_mac);
 
+void bgx_lmac_rx_tx_enable(int node, int bgx_idx, int lmacid, bool enable)
+{
+       struct bgx *bgx = bgx_vnic[(node * MAX_BGX_PER_CN88XX) + bgx_idx];
+       u64 cfg;
+
+       if (!bgx)
+               return;
+
+       cfg = bgx_reg_read(bgx, lmacid, BGX_CMRX_CFG);
+       if (enable)
+               cfg |= CMR_PKT_RX_EN | CMR_PKT_TX_EN;
+       else
+               cfg &= ~(CMR_PKT_RX_EN | CMR_PKT_TX_EN);
+       bgx_reg_write(bgx, lmacid, BGX_CMRX_CFG, cfg);
+}
+EXPORT_SYMBOL(bgx_lmac_rx_tx_enable);
+
 static void bgx_sgmii_change_link_state(struct lmac *lmac)
 {
        struct bgx *bgx = lmac->bgx;
@@ -612,6 +629,8 @@ static void bgx_poll_for_link(struct work_struct *work)
                lmac->last_duplex = 1;
        } else {
                lmac->link_up = 0;
+               lmac->last_speed = SPEED_UNKNOWN;
+               lmac->last_duplex = DUPLEX_UNKNOWN;
        }
 
        if (lmac->last_link != lmac->link_up) {
@@ -654,8 +673,7 @@ static int bgx_lmac_enable(struct bgx *bgx, u8 lmacid)
        }
 
        /* Enable lmac */
-       bgx_reg_modify(bgx, lmacid, BGX_CMRX_CFG,
-                      CMR_EN | CMR_PKT_RX_EN | CMR_PKT_TX_EN);
+       bgx_reg_modify(bgx, lmacid, BGX_CMRX_CFG, CMR_EN);
 
        /* Restore default cfg, incase low level firmware changed it */
        bgx_reg_write(bgx, lmacid, BGX_CMRX_RX_DMAC_CTL, 0x03);
@@ -695,8 +713,7 @@ static void bgx_lmac_disable(struct bgx *bgx, u8 lmacid)
        lmac = &bgx->lmac[lmacid];
        if (lmac->check_link) {
                /* Destroy work queue */
-               cancel_delayed_work(&lmac->dwork);
-               flush_workqueue(lmac->check_link);
+               cancel_delayed_work_sync(&lmac->dwork);
                destroy_workqueue(lmac->check_link);
        }
 
@@ -1009,6 +1026,9 @@ static int bgx_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
        struct bgx *bgx = NULL;
        u8 lmac;
 
+       /* Load octeon mdio driver */
+       octeon_mdiobus_force_mod_depencency();
+
        bgx = devm_kzalloc(dev, sizeof(*bgx), GFP_KERNEL);
        if (!bgx)
                return -ENOMEM;
index 07b7ec66c60db8dd398b7ff60321598c9317c4c9..149e179363a1e6dd71e0b7cbd00f26a5e5ef0116 100644 (file)
@@ -182,6 +182,8 @@ enum MCAST_MODE {
 #define BCAST_ACCEPT   1
 #define CAM_ACCEPT     1
 
+void octeon_mdiobus_force_mod_depencency(void);
+void bgx_lmac_rx_tx_enable(int node, int bgx_idx, int lmacid, bool enable);
 void bgx_add_dmac_addr(u64 dmac, int node, int bgx_idx, int lmac);
 unsigned bgx_get_map(int node);
 int bgx_get_lmac_count(int node, int bgx);
index ed41559bae771b8d58e49f21a46f7a79d9f20cac..b553409e04ad33ed50fafe3bdaa8de74d965e6eb 100644 (file)
@@ -98,8 +98,7 @@ static int csr0 = 0x01A00000 | 0x4800;
 #elif defined(__mips__)
 static int csr0 = 0x00200000 | 0x4000;
 #else
-#warning Processor architecture undefined!
-static int csr0 = 0x00A00000 | 0x4800;
+static int csr0;
 #endif
 
 /* Operational parameters that usually are not changed. */
@@ -1982,6 +1981,12 @@ static int __init tulip_init (void)
        pr_info("%s", version);
 #endif
 
+       if (!csr0) {
+               pr_warn("tulip: unknown CPU architecture, using default csr0\n");
+               /* default to 8 longword cache line alignment */
+               csr0 = 0x00A00000 | 0x4800;
+       }
+
        /* copy module parms into globals */
        tulip_rx_copybreak = rx_copybreak;
        tulip_max_interrupt_work = max_interrupt_work;
index 9beb3d34d4bad9f81ec8c11c560150d8b4640ed8..3c0e4d5c5fef41a8fe1fe99c0a163d30cd74fc31 100644 (file)
@@ -907,7 +907,7 @@ static void init_registers(struct net_device *dev)
 #elif defined(CONFIG_SPARC) || defined (CONFIG_PARISC) || defined(CONFIG_ARM)
        i |= 0x4800;
 #else
-#warning Processor architecture undefined
+       dev_warn(&dev->dev, "unknown CPU architecture, using default csr0 setting\n");
        i |= 0x4800;
 #endif
        iowrite32(i, ioaddr + PCIBusCfg);
index f6e858d0b9d421a54bdf7b1bf294b2dd77c3cc55..ebdc83247bb6af1c841d62513978ce21d59f0d92 100644 (file)
@@ -17,15 +17,16 @@ config NET_VENDOR_DLINK
 if NET_VENDOR_DLINK
 
 config DL2K
-       tristate "DL2000/TC902x-based Gigabit Ethernet support"
+       tristate "DL2000/TC902x/IP1000A-based Gigabit Ethernet support"
        depends on PCI
        select CRC32
        ---help---
-         This driver supports DL2000/TC902x-based Gigabit ethernet cards,
+         This driver supports DL2000/TC902x/IP1000A-based Gigabit ethernet cards,
          which includes
          D-Link DGE-550T Gigabit Ethernet Adapter.
          D-Link DL2000-based Gigabit Ethernet Adapter.
          Sundance/Tamarack TC902x Gigabit Ethernet Adapter.
+         ICPlus IP1000A-based cards
 
          To compile this driver as a module, choose M here: the
          module will be called dl2k.
index cf0a5fcdaaaf06e59772d5b4530547e11c7b4819..ccca4799c27b83cf191fc80f3d72a21328f8708e 100644 (file)
@@ -253,6 +253,19 @@ rio_probe1 (struct pci_dev *pdev, const struct pci_device_id *ent)
        if (err)
                goto err_out_unmap_rx;
 
+       if (np->chip_id == CHIP_IP1000A &&
+           (np->pdev->revision == 0x40 || np->pdev->revision == 0x41)) {
+               /* PHY magic taken from ipg driver, undocumented registers */
+               mii_write(dev, np->phy_addr, 31, 0x0001);
+               mii_write(dev, np->phy_addr, 27, 0x01e0);
+               mii_write(dev, np->phy_addr, 31, 0x0002);
+               mii_write(dev, np->phy_addr, 27, 0xeb8e);
+               mii_write(dev, np->phy_addr, 31, 0x0000);
+               mii_write(dev, np->phy_addr, 30, 0x005e);
+               /* advertise 1000BASE-T half & full duplex, prefer MASTER */
+               mii_write(dev, np->phy_addr, MII_CTRL1000, 0x0700);
+       }
+
        /* Fiber device? */
        np->phy_media = (dr16(ASICCtrl) & PhyMedia) ? 1 : 0;
        np->link_status = 0;
@@ -361,6 +374,11 @@ parse_eeprom (struct net_device *dev)
        for (i = 0; i < 6; i++)
                dev->dev_addr[i] = psrom->mac_addr[i];
 
+       if (np->chip_id == CHIP_IP1000A) {
+               np->led_mode = psrom->led_mode;
+               return 0;
+       }
+
        if (np->pdev->vendor != PCI_VENDOR_ID_DLINK) {
                return 0;
        }
@@ -406,6 +424,28 @@ parse_eeprom (struct net_device *dev)
        return 0;
 }
 
+static void rio_set_led_mode(struct net_device *dev)
+{
+       struct netdev_private *np = netdev_priv(dev);
+       void __iomem *ioaddr = np->ioaddr;
+       u32 mode;
+
+       if (np->chip_id != CHIP_IP1000A)
+               return;
+
+       mode = dr32(ASICCtrl);
+       mode &= ~(IPG_AC_LED_MODE_BIT_1 | IPG_AC_LED_MODE | IPG_AC_LED_SPEED);
+
+       if (np->led_mode & 0x01)
+               mode |= IPG_AC_LED_MODE;
+       if (np->led_mode & 0x02)
+               mode |= IPG_AC_LED_MODE_BIT_1;
+       if (np->led_mode & 0x08)
+               mode |= IPG_AC_LED_SPEED;
+
+       dw32(ASICCtrl, mode);
+}
+
 static int
 rio_open (struct net_device *dev)
 {
@@ -424,6 +464,8 @@ rio_open (struct net_device *dev)
             GlobalReset | DMAReset | FIFOReset | NetworkReset | HostReset);
        mdelay(10);
 
+       rio_set_led_mode(dev);
+
        /* DebugCtrl bit 4, 5, 9 must set */
        dw32(DebugCtrl, dr32(DebugCtrl) | 0x0230);
 
@@ -433,9 +475,13 @@ rio_open (struct net_device *dev)
 
        alloc_list (dev);
 
-       /* Get station address */
-       for (i = 0; i < 6; i++)
-               dw8(StationAddr0 + i, dev->dev_addr[i]);
+       /* Set station address */
+       /* 16 or 32-bit access is required by TC9020 datasheet but 8-bit works
+        * too. However, it doesn't work on IP1000A so we use 16-bit access.
+        */
+       for (i = 0; i < 3; i++)
+               dw16(StationAddr0 + 2 * i,
+                    cpu_to_le16(((u16 *)dev->dev_addr)[i]));
 
        set_multicast (dev);
        if (np->coalesce) {
@@ -780,6 +826,7 @@ tx_error (struct net_device *dev, int tx_status)
                                break;
                        mdelay (1);
                }
+               rio_set_led_mode(dev);
                rio_free_tx (dev, 1);
                /* Reset TFDListPtr */
                dw32(TFDListPtr0, np->tx_ring_dma +
@@ -799,6 +846,7 @@ tx_error (struct net_device *dev, int tx_status)
                                break;
                        mdelay (1);
                }
+               rio_set_led_mode(dev);
                /* Let TxStartThresh stay default value */
        }
        /* Maximum Collisions */
@@ -965,6 +1013,7 @@ rio_error (struct net_device *dev, int int_status)
                        dev->name, int_status);
                dw16(ASICCtrl + 2, GlobalReset | HostReset);
                mdelay (500);
+               rio_set_led_mode(dev);
        }
 }
 
index 23c07b0070696da9c41726aba73f01e338a4ca2e..8f4f61262d5cb7be21d994d7ffb411a654ae589b 100644 (file)
@@ -211,6 +211,10 @@ enum ASICCtrl_HiWord_bits {
        ResetBusy = 0x0400,
 };
 
+#define IPG_AC_LED_MODE                BIT(14)
+#define IPG_AC_LED_SPEED       BIT(27)
+#define IPG_AC_LED_MODE_BIT_1  BIT(29)
+
 /* Transmit Frame Control bits */
 enum TFC_bits {
        DwordAlign = 0x00000000,
@@ -332,7 +336,10 @@ typedef struct t_SROM {
        u16 asic_ctrl;          /* 0x02 */
        u16 sub_vendor_id;      /* 0x04 */
        u16 sub_system_id;      /* 0x06 */
-       u16 reserved1[12];      /* 0x08-0x1f */
+       u16 pci_base_1;         /* 0x08 (IP1000A only) */
+       u16 pci_base_2;         /* 0x0a (IP1000A only) */
+       u16 led_mode;           /* 0x0c (IP1000A only) */
+       u16 reserved1[9];       /* 0x0e-0x1f */
        u8 mac_addr[6];         /* 0x20-0x25 */
        u8 reserved2[10];       /* 0x26-0x2f */
        u8 sib[204];            /* 0x30-0xfb */
@@ -397,6 +404,7 @@ struct netdev_private {
        u16 advertising;        /* NWay media advertisement */
        u16 negotiate;          /* Negotiated media */
        int phy_addr;           /* PHY addresses. */
+       u16 led_mode;           /* LED mode read from EEPROM (IP1000A only) */
 };
 
 /* The station address location in the EEPROM. */
@@ -407,10 +415,15 @@ struct netdev_private {
         class_mask              of the class are honored during the comparison.
         driver_data             Data private to the driver.
 */
+#define CHIP_IP1000A   1
 
 static const struct pci_device_id rio_pci_tbl[] = {
        {0x1186, 0x4000, PCI_ANY_ID, PCI_ANY_ID, },
        {0x13f0, 0x1021, PCI_ANY_ID, PCI_ANY_ID, },
+       { PCI_VDEVICE(SUNDANCE, 0x1023), CHIP_IP1000A },
+       { PCI_VDEVICE(SUNDANCE, 0x2021), CHIP_IP1000A },
+       { PCI_VDEVICE(DLINK,    0x9021), CHIP_IP1000A },
+       { PCI_VDEVICE(DLINK,    0x4020), CHIP_IP1000A },
        { }
 };
 MODULE_DEVICE_TABLE (pci, rio_pci_tbl);
index d463563e1f7039ee5176ca36abfdc6bae3f2ed46..6ee78c203ecad7a18ba136e45ea0d2e24ec35930 100644 (file)
@@ -848,8 +848,6 @@ void be_roce_dev_remove(struct be_adapter *);
 /*
  * internal function to open-close roce device during ifup-ifdown.
  */
-void be_roce_dev_open(struct be_adapter *);
-void be_roce_dev_close(struct be_adapter *);
 void be_roce_dev_shutdown(struct be_adapter *);
 
 #endif                         /* BE_H */
index f4cb8e425853a3fd85151d3b6df5e7651b95f81a..734f655c99c113805e270a0846e934553fbca9b7 100644 (file)
@@ -1062,9 +1062,7 @@ static int be_get_rxnfc(struct net_device *netdev, struct ethtool_rxnfc *cmd,
 static int be_set_rss_hash_opts(struct be_adapter *adapter,
                                struct ethtool_rxnfc *cmd)
 {
-       struct be_rx_obj *rxo;
-       int status = 0, i, j;
-       u8 rsstable[128];
+       int status;
        u32 rss_flags = adapter->rss_info.rss_flags;
 
        if (cmd->data != L3_RSS_FLAGS &&
@@ -1113,20 +1111,11 @@ static int be_set_rss_hash_opts(struct be_adapter *adapter,
        }
 
        if (rss_flags == adapter->rss_info.rss_flags)
-               return status;
-
-       if (be_multi_rxq(adapter)) {
-               for (j = 0; j < 128; j += adapter->num_rss_qs) {
-                       for_all_rss_queues(adapter, rxo, i) {
-                               if ((j + i) >= 128)
-                                       break;
-                               rsstable[j + i] = rxo->rss_id;
-                       }
-               }
-       }
+               return 0;
 
        status = be_cmd_rss_config(adapter, adapter->rss_info.rsstable,
-                                  rss_flags, 128, adapter->rss_info.rss_hkey);
+                                  rss_flags, RSS_INDIR_TABLE_LEN,
+                                  adapter->rss_info.rss_hkey);
        if (!status)
                adapter->rss_info.rss_flags = rss_flags;
 
index eb48a977f8daabe78d6d5b6a94f6607bf19287b8..8a1d9fffd7d671ea88023a120c93f4cdefbcff54 100644 (file)
@@ -3299,8 +3299,10 @@ static int be_msix_register(struct be_adapter *adapter)
 
        return 0;
 err_msix:
-       for (i--, eqo = &adapter->eq_obj[i]; i >= 0; i--, eqo--)
+       for (i--; i >= 0; i--) {
+               eqo = &adapter->eq_obj[i];
                free_irq(be_msix_vec_get(adapter, eqo), eqo);
+       }
        dev_warn(&adapter->pdev->dev, "MSIX Request IRQ failed - err %d\n",
                 status);
        be_msix_disable(adapter);
@@ -3432,8 +3434,6 @@ static int be_close(struct net_device *netdev)
 
        be_disable_if_filters(adapter);
 
-       be_roce_dev_close(adapter);
-
        if (adapter->flags & BE_FLAGS_NAPI_ENABLED) {
                for_all_evt_queues(adapter, eqo, i) {
                        napi_disable(&eqo->napi);
@@ -3518,7 +3518,7 @@ static int be_rx_qs_create(struct be_adapter *adapter)
 
        netdev_rss_key_fill(rss_key, RSS_HASH_KEY_LEN);
        rc = be_cmd_rss_config(adapter, rss->rsstable, rss->rss_flags,
-                              128, rss_key);
+                              RSS_INDIR_TABLE_LEN, rss_key);
        if (rc) {
                rss->rss_flags = RSS_ENABLE_NONE;
                return rc;
@@ -3601,8 +3601,6 @@ static int be_open(struct net_device *netdev)
                be_link_status_update(adapter, link_status);
 
        netif_tx_start_all_queues(netdev);
-       be_roce_dev_open(adapter);
-
 #ifdef CONFIG_BE2NET_VXLAN
        if (skyhawk_chip(adapter))
                vxlan_get_rx_port(netdev);
index 60368207bf584188b4d0293d9f2a8d7235180a8d..4089156a7f5e20177dfee8d29315c404924f4d9e 100644 (file)
@@ -116,40 +116,6 @@ void be_roce_dev_remove(struct be_adapter *adapter)
        }
 }
 
-static void _be_roce_dev_open(struct be_adapter *adapter)
-{
-       if (ocrdma_drv && adapter->ocrdma_dev &&
-           ocrdma_drv->state_change_handler)
-               ocrdma_drv->state_change_handler(adapter->ocrdma_dev,
-                                                BE_DEV_UP);
-}
-
-void be_roce_dev_open(struct be_adapter *adapter)
-{
-       if (be_roce_supported(adapter)) {
-               mutex_lock(&be_adapter_list_lock);
-               _be_roce_dev_open(adapter);
-               mutex_unlock(&be_adapter_list_lock);
-       }
-}
-
-static void _be_roce_dev_close(struct be_adapter *adapter)
-{
-       if (ocrdma_drv && adapter->ocrdma_dev &&
-           ocrdma_drv->state_change_handler)
-               ocrdma_drv->state_change_handler(adapter->ocrdma_dev,
-                                                BE_DEV_DOWN);
-}
-
-void be_roce_dev_close(struct be_adapter *adapter)
-{
-       if (be_roce_supported(adapter)) {
-               mutex_lock(&be_adapter_list_lock);
-               _be_roce_dev_close(adapter);
-               mutex_unlock(&be_adapter_list_lock);
-       }
-}
-
 void be_roce_dev_shutdown(struct be_adapter *adapter)
 {
        if (be_roce_supported(adapter)) {
@@ -177,8 +143,6 @@ int be_roce_register_driver(struct ocrdma_driver *drv)
 
                _be_roce_dev_add(dev);
                netdev = dev->netdev;
-               if (netif_running(netdev) && netif_oper_up(netdev))
-                       _be_roce_dev_open(dev);
        }
        mutex_unlock(&be_adapter_list_lock);
        return 0;
index cde6ef905ec481dce0436858fb1fd78252471146..fde609789483872582bda5a990d6bad357dc25df 100644 (file)
@@ -60,9 +60,7 @@ struct ocrdma_driver {
        void (*state_change_handler) (struct ocrdma_dev *, u32 new_state);
 };
 
-enum {
-       BE_DEV_UP       = 0,
-       BE_DEV_DOWN     = 1,
+enum be_roce_event {
        BE_DEV_SHUTDOWN = 2
 };
 
index 63c2bcf8031a8a8cc39c714bb1510e3f3ae03793..b1026689b78f4075d30b240b4f8dc625d3b9299a 100644 (file)
@@ -48,21 +48,15 @@ static void nps_enet_read_rx_fifo(struct net_device *ndev,
                        *reg = nps_enet_reg_get(priv, NPS_ENET_REG_RX_BUF);
        else { /* !dst_is_aligned */
                for (i = 0; i < len; i++, reg++) {
-                       u32 buf =
-                               nps_enet_reg_get(priv, NPS_ENET_REG_RX_BUF);
-
-                       /* to accommodate word-unaligned address of "reg"
-                        * we have to do memcpy_toio() instead of simple "=".
-                        */
-                       memcpy_toio((void __iomem *)reg, &buf, sizeof(buf));
+                       u32 buf = nps_enet_reg_get(priv, NPS_ENET_REG_RX_BUF);
+                       put_unaligned(buf, reg);
                }
        }
 
        /* copy last bytes (if any) */
        if (last) {
                u32 buf = nps_enet_reg_get(priv, NPS_ENET_REG_RX_BUF);
-
-               memcpy_toio((void __iomem *)reg, &buf, last);
+               memcpy((u8*)reg, &buf, last);
        }
 }
 
@@ -367,7 +361,7 @@ static void nps_enet_send_frame(struct net_device *ndev,
        struct nps_enet_tx_ctl tx_ctrl;
        short length = skb->len;
        u32 i, len = DIV_ROUND_UP(length, sizeof(u32));
-       u32 *src = (u32 *)virt_to_phys(skb->data);
+       u32 *src = (void *)skb->data;
        bool src_is_aligned = IS_ALIGNED((unsigned long)src, sizeof(u32));
 
        tx_ctrl.value = 0;
@@ -375,17 +369,11 @@ static void nps_enet_send_frame(struct net_device *ndev,
        if (src_is_aligned)
                for (i = 0; i < len; i++, src++)
                        nps_enet_reg_set(priv, NPS_ENET_REG_TX_BUF, *src);
-       else { /* !src_is_aligned */
-               for (i = 0; i < len; i++, src++) {
-                       u32 buf;
-
-                       /* to accommodate word-unaligned address of "src"
-                        * we have to do memcpy_fromio() instead of simple "="
-                        */
-                       memcpy_fromio(&buf, (void __iomem *)src, sizeof(buf));
-                       nps_enet_reg_set(priv, NPS_ENET_REG_TX_BUF, buf);
-               }
-       }
+       else /* !src_is_aligned */
+               for (i = 0; i < len; i++, src++)
+                       nps_enet_reg_set(priv, NPS_ENET_REG_TX_BUF,
+                                        get_unaligned(src));
+
        /* Write the length of the Frame */
        tx_ctrl.nt = length;
 
index ff76d4e9dc1ba5eab90413f82592a876092a8ddf..bee32a9d9876f02719a5c46be9b65ff145f76c3b 100644 (file)
@@ -7,7 +7,8 @@ config NET_VENDOR_FREESCALE
        default y
        depends on FSL_SOC || QUICC_ENGINE || CPM1 || CPM2 || PPC_MPC512x || \
                   M523x || M527x || M5272 || M528x || M520x || M532x || \
-                  ARCH_MXC || ARCH_MXS || (PPC_MPC52xx && PPC_BESTCOMM)
+                  ARCH_MXC || ARCH_MXS || (PPC_MPC52xx && PPC_BESTCOMM) || \
+                  ARCH_LAYERSCAPE
        ---help---
          If you have a network (Ethernet) card belonging to this class, say Y.
 
index 08f5b911d96be1b01f99484ee748c24aaed7f483..52e0091b4fb261f983ab0e043d1cb0d48638dc03 100644 (file)
@@ -552,7 +552,7 @@ static void tx_restart(struct net_device *dev)
        cbd_t __iomem *prev_bd;
        cbd_t __iomem *last_tx_bd;
 
-       last_tx_bd = fep->tx_bd_base + (fpi->tx_ring * sizeof(cbd_t));
+       last_tx_bd = fep->tx_bd_base + ((fpi->tx_ring - 1) * sizeof(cbd_t));
 
        /* get the current bd held in TBPTR  and scan back from this point */
        recheck_bd = curr_tbptr = (cbd_t __iomem *)
index 55c36230e17634c3e063bdb20f4bb6a896bce4a6..40071dad1c570686de4d7b062d0b61682c878c2b 100644 (file)
@@ -464,7 +464,7 @@ static int fsl_pq_mdio_probe(struct platform_device *pdev)
                         * address). Print error message but continue anyway.
                         */
                        if ((void *)tbipa > priv->map + resource_size(&res) - 4)
-                               dev_err(&pdev->dev, "invalid register map (should be at least 0x%04x to contain TBI address)\n",
+                               dev_err(&pdev->dev, "invalid register map (should be at least 0x%04zx to contain TBI address)\n",
                                        ((void *)tbipa - priv->map) + 4);
 
                        iowrite32be(be32_to_cpup(prop), tbipa);
index 3e6b9b437497dba9431fdedd3cf03262c0af3b0f..3e233d924cce3b8bbf6bf5901b61455c5c0cd2dc 100644 (file)
@@ -647,9 +647,9 @@ static int gfar_parse_group(struct device_node *np,
        if (model && strcasecmp(model, "FEC")) {
                gfar_irq(grp, RX)->irq = irq_of_parse_and_map(np, 1);
                gfar_irq(grp, ER)->irq = irq_of_parse_and_map(np, 2);
-               if (gfar_irq(grp, TX)->irq == NO_IRQ ||
-                   gfar_irq(grp, RX)->irq == NO_IRQ ||
-                   gfar_irq(grp, ER)->irq == NO_IRQ)
+               if (!gfar_irq(grp, TX)->irq ||
+                   !gfar_irq(grp, RX)->irq ||
+                   !gfar_irq(grp, ER)->irq)
                        return -EINVAL;
        }
 
@@ -894,7 +894,8 @@ static int gfar_of_init(struct platform_device *ofdev, struct net_device **pdev)
                                     FSL_GIANFAR_DEV_HAS_VLAN |
                                     FSL_GIANFAR_DEV_HAS_MAGIC_PACKET |
                                     FSL_GIANFAR_DEV_HAS_EXTENDED_HASH |
-                                    FSL_GIANFAR_DEV_HAS_TIMER;
+                                    FSL_GIANFAR_DEV_HAS_TIMER |
+                                    FSL_GIANFAR_DEV_HAS_RX_FILER;
 
        err = of_property_read_string(np, "phy-connection-type", &ctype);
 
@@ -1396,8 +1397,9 @@ static int gfar_probe(struct platform_device *ofdev)
                priv->rx_queue[i]->rxic = DEFAULT_RXIC;
        }
 
-       /* always enable rx filer */
-       priv->rx_filer_enable = 1;
+       /* Always enable rx filer if available */
+       priv->rx_filer_enable =
+           (priv->device_flags & FSL_GIANFAR_DEV_HAS_RX_FILER) ? 1 : 0;
        /* Enable most messages by default */
        priv->msg_enable = (NETIF_MSG_IFUP << 1 ) - 1;
        /* use pritority h/w tx queue scheduling for single queue devices */
index f266b20f9ef5be53e6c55f2579484bb72d8794a1..cb77667971a7e4dd761ada53273f04a2047cf259 100644 (file)
@@ -923,6 +923,7 @@ struct gfar {
 #define FSL_GIANFAR_DEV_HAS_BUF_STASHING       0x00000400
 #define FSL_GIANFAR_DEV_HAS_TIMER              0x00000800
 #define FSL_GIANFAR_DEV_HAS_WAKE_ON_FILER      0x00001000
+#define FSL_GIANFAR_DEV_HAS_RX_FILER           0x00002000
 
 #if (MAXGROUPS == 2)
 #define DEFAULT_MAPPING        0xAA
index 664d0c261269097bccae55c12dcd7abcab140d5b..b40fba929d650d282c23f5d96636806ef4797d48 100644 (file)
@@ -467,7 +467,7 @@ static int gianfar_ptp_probe(struct platform_device *dev)
 
        etsects->irq = platform_get_irq(dev, 0);
 
-       if (etsects->irq == NO_IRQ) {
+       if (etsects->irq < 0) {
                pr_err("irq not in device tree\n");
                goto no_node;
        }
index 2a98eba660c06a4dc3736bf84686a20d87597e20..b674414a4d725569c87fa577aa23f5b822e80d50 100644 (file)
@@ -1259,12 +1259,8 @@ int hns_dsaf_set_mac_uc_entry(
        if (MAC_IS_ALL_ZEROS(mac_entry->addr) ||
            MAC_IS_BROADCAST(mac_entry->addr) ||
            MAC_IS_MULTICAST(mac_entry->addr)) {
-               dev_err(dsaf_dev->dev,
-                       "set_uc %s Mac %02x:%02x:%02x:%02x:%02x:%02x err!\n",
-                       dsaf_dev->ae_dev.name, mac_entry->addr[0],
-                       mac_entry->addr[1], mac_entry->addr[2],
-                       mac_entry->addr[3], mac_entry->addr[4],
-                       mac_entry->addr[5]);
+               dev_err(dsaf_dev->dev, "set_uc %s Mac %pM err!\n",
+                       dsaf_dev->ae_dev.name, mac_entry->addr);
                return -EINVAL;
        }
 
@@ -1331,12 +1327,8 @@ int hns_dsaf_set_mac_mc_entry(
 
        /* mac addr check */
        if (MAC_IS_ALL_ZEROS(mac_entry->addr)) {
-               dev_err(dsaf_dev->dev,
-                       "set uc %s Mac %02x:%02x:%02x:%02x:%02x:%02x err!\n",
-                       dsaf_dev->ae_dev.name, mac_entry->addr[0],
-                       mac_entry->addr[1], mac_entry->addr[2],
-                       mac_entry->addr[3],
-                       mac_entry->addr[4], mac_entry->addr[5]);
+               dev_err(dsaf_dev->dev, "set uc %s Mac %pM err!\n",
+                       dsaf_dev->ae_dev.name, mac_entry->addr);
                return -EINVAL;
        }
 
@@ -1410,11 +1402,8 @@ int hns_dsaf_add_mac_mc_port(struct dsaf_device *dsaf_dev,
 
        /*chechk mac addr */
        if (MAC_IS_ALL_ZEROS(mac_entry->addr)) {
-               dev_err(dsaf_dev->dev,
-                       "set_entry failed,addr %02x:%02x:%02x:%02x:%02x:%02x!\n",
-                       mac_entry->addr[0], mac_entry->addr[1],
-                       mac_entry->addr[2], mac_entry->addr[3],
-                       mac_entry->addr[4], mac_entry->addr[5]);
+               dev_err(dsaf_dev->dev, "set_entry failed,addr %pM!\n",
+                       mac_entry->addr);
                return -EINVAL;
        }
 
@@ -1497,9 +1486,8 @@ int hns_dsaf_del_mac_entry(struct dsaf_device *dsaf_dev, u16 vlan_id,
 
        /*check mac addr */
        if (MAC_IS_ALL_ZEROS(addr) || MAC_IS_BROADCAST(addr)) {
-               dev_err(dsaf_dev->dev,
-                       "del_entry failed,addr %02x:%02x:%02x:%02x:%02x:%02x!\n",
-                       addr[0], addr[1], addr[2], addr[3], addr[4], addr[5]);
+               dev_err(dsaf_dev->dev, "del_entry failed,addr %pM!\n",
+                       addr);
                return -EINVAL;
        }
 
@@ -1563,11 +1551,8 @@ int hns_dsaf_del_mac_mc_port(struct dsaf_device *dsaf_dev,
 
        /*check mac addr */
        if (MAC_IS_ALL_ZEROS(mac_entry->addr)) {
-               dev_err(dsaf_dev->dev,
-                       "del_port failed, addr %02x:%02x:%02x:%02x:%02x:%02x!\n",
-                       mac_entry->addr[0], mac_entry->addr[1],
-                       mac_entry->addr[2], mac_entry->addr[3],
-                       mac_entry->addr[4], mac_entry->addr[5]);
+               dev_err(dsaf_dev->dev, "del_port failed, addr %pM!\n",
+                       mac_entry->addr);
                return -EINVAL;
        }
 
@@ -1644,11 +1629,8 @@ int hns_dsaf_get_mac_uc_entry(struct dsaf_device *dsaf_dev,
        /* check macaddr */
        if (MAC_IS_ALL_ZEROS(mac_entry->addr) ||
            MAC_IS_BROADCAST(mac_entry->addr)) {
-               dev_err(dsaf_dev->dev,
-                       "get_entry failed,addr %02x:%02x:%02x:%02x:%02x:%02x\n",
-                       mac_entry->addr[0], mac_entry->addr[1],
-                       mac_entry->addr[2], mac_entry->addr[3],
-                       mac_entry->addr[4], mac_entry->addr[5]);
+               dev_err(dsaf_dev->dev, "get_entry failed,addr %pM\n",
+                       mac_entry->addr);
                return -EINVAL;
        }
 
@@ -1695,11 +1677,8 @@ int hns_dsaf_get_mac_mc_entry(struct dsaf_device *dsaf_dev,
        /*check mac addr */
        if (MAC_IS_ALL_ZEROS(mac_entry->addr) ||
            MAC_IS_BROADCAST(mac_entry->addr)) {
-               dev_err(dsaf_dev->dev,
-                       "get_entry failed,addr %02x:%02x:%02x:%02x:%02x:%02x\n",
-                       mac_entry->addr[0], mac_entry->addr[1],
-                       mac_entry->addr[2], mac_entry->addr[3],
-                       mac_entry->addr[4], mac_entry->addr[5]);
+               dev_err(dsaf_dev->dev, "get_entry failed,addr %pM\n",
+                       mac_entry->addr);
                return -EINVAL;
        }
 
index b475e1bf2e6fdb24d9bade9405aa3e575581664e..bdbd80423b17aaf36d9134109ece6bb8d22c4303 100644 (file)
 #define XGMAC_PAUSE_CTL_RSP_MODE_B     2
 #define XGMAC_PAUSE_CTL_TX_XOFF_B      3
 
-static inline void dsaf_write_reg(void *base, u32 reg, u32 value)
+static inline void dsaf_write_reg(void __iomem *base, u32 reg, u32 value)
 {
        u8 __iomem *reg_addr = ACCESS_ONCE(base);
 
@@ -908,7 +908,7 @@ static inline void dsaf_write_reg(void *base, u32 reg, u32 value)
 #define dsaf_write_dev(a, reg, value) \
        dsaf_write_reg((a)->io_base, (reg), (value))
 
-static inline u32 dsaf_read_reg(u8 *base, u32 reg)
+static inline u32 dsaf_read_reg(u8 __iomem *base, u32 reg)
 {
        u8 __iomem *reg_addr = ACCESS_ONCE(base);
 
@@ -927,8 +927,8 @@ static inline u32 dsaf_read_reg(u8 *base, u32 reg)
 #define dsaf_set_bit(origin, shift, val) \
        dsaf_set_field((origin), (1ull << (shift)), (shift), (val))
 
-static inline void dsaf_set_reg_field(void *base, u32 reg, u32 mask, u32 shift,
-                                     u32 val)
+static inline void dsaf_set_reg_field(void __iomem *base, u32 reg, u32 mask,
+                                     u32 shift, u32 val)
 {
        u32 origin = dsaf_read_reg(base, reg);
 
@@ -947,7 +947,8 @@ static inline void dsaf_set_reg_field(void *base, u32 reg, u32 mask, u32 shift,
 #define dsaf_get_bit(origin, shift) \
        dsaf_get_field((origin), (1ull << (shift)), (shift))
 
-static inline u32 dsaf_get_reg_field(void *base, u32 reg, u32 mask, u32 shift)
+static inline u32 dsaf_get_reg_field(void __iomem *base, u32 reg, u32 mask,
+                                    u32 shift)
 {
        u32 origin;
 
diff --git a/drivers/net/ethernet/icplus/Kconfig b/drivers/net/ethernet/icplus/Kconfig
deleted file mode 100644 (file)
index 14a66e9..0000000
+++ /dev/null
@@ -1,13 +0,0 @@
-#
-# IC Plus device configuration
-#
-
-config IP1000
-       tristate "IP1000 Gigabit Ethernet support"
-       depends on PCI
-       select MII
-       ---help---
-         This driver supports IP1000 gigabit Ethernet cards.
-
-         To compile this driver as a module, choose M here: the module
-         will be called ipg.  This is recommended.
diff --git a/drivers/net/ethernet/icplus/Makefile b/drivers/net/ethernet/icplus/Makefile
deleted file mode 100644 (file)
index 5bc87c1..0000000
+++ /dev/null
@@ -1,5 +0,0 @@
-#
-# Makefile for the IC Plus device drivers
-#
-
-obj-$(CONFIG_IP1000) += ipg.o
diff --git a/drivers/net/ethernet/icplus/ipg.c b/drivers/net/ethernet/icplus/ipg.c
deleted file mode 100644 (file)
index c3b6af8..0000000
+++ /dev/null
@@ -1,2300 +0,0 @@
-/*
- * ipg.c: Device Driver for the IP1000 Gigabit Ethernet Adapter
- *
- * Copyright (C) 2003, 2007  IC Plus Corp
- *
- * Original Author:
- *
- *   Craig Rich
- *   Sundance Technology, Inc.
- *   www.sundanceti.com
- *   craig_rich@sundanceti.com
- *
- * Current Maintainer:
- *
- *   Sorbica Shieh.
- *   http://www.icplus.com.tw
- *   sorbica@icplus.com.tw
- *
- *   Jesse Huang
- *   http://www.icplus.com.tw
- *   jesse@icplus.com.tw
- */
-
-#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
-
-#include <linux/crc32.h>
-#include <linux/ethtool.h>
-#include <linux/interrupt.h>
-#include <linux/gfp.h>
-#include <linux/mii.h>
-#include <linux/mutex.h>
-
-#include <asm/div64.h>
-
-#define IPG_RX_RING_BYTES      (sizeof(struct ipg_rx) * IPG_RFDLIST_LENGTH)
-#define IPG_TX_RING_BYTES      (sizeof(struct ipg_tx) * IPG_TFDLIST_LENGTH)
-#define IPG_RESET_MASK \
-       (IPG_AC_GLOBAL_RESET | IPG_AC_RX_RESET | IPG_AC_TX_RESET | \
-        IPG_AC_DMA | IPG_AC_FIFO | IPG_AC_NETWORK | IPG_AC_HOST | \
-        IPG_AC_AUTO_INIT)
-
-#define ipg_w32(val32, reg)    iowrite32((val32), ioaddr + (reg))
-#define ipg_w16(val16, reg)    iowrite16((val16), ioaddr + (reg))
-#define ipg_w8(val8, reg)      iowrite8((val8), ioaddr + (reg))
-
-#define ipg_r32(reg)           ioread32(ioaddr + (reg))
-#define ipg_r16(reg)           ioread16(ioaddr + (reg))
-#define ipg_r8(reg)            ioread8(ioaddr + (reg))
-
-enum {
-       netdev_io_size = 128
-};
-
-#include "ipg.h"
-#define DRV_NAME       "ipg"
-
-MODULE_AUTHOR("IC Plus Corp. 2003");
-MODULE_DESCRIPTION("IC Plus IP1000 Gigabit Ethernet Adapter Linux Driver");
-MODULE_LICENSE("GPL");
-
-/*
- * Defaults
- */
-#define IPG_MAX_RXFRAME_SIZE   0x0600
-#define IPG_RXFRAG_SIZE                0x0600
-#define IPG_RXSUPPORT_SIZE     0x0600
-#define IPG_IS_JUMBO           false
-
-/*
- * Variable record -- index by leading revision/length
- * Revision/Length(=N*4), Address1, Data1, Address2, Data2,...,AddressN,DataN
- */
-static const unsigned short DefaultPhyParam[] = {
-       /* 11/12/03 IP1000A v1-3 rev=0x40 */
-       /*--------------------------------------------------------------------------
-       (0x4000|(15*4)), 31, 0x0001, 27, 0x01e0, 31, 0x0002, 22, 0x85bd, 24, 0xfff2,
-                                27, 0x0c10, 28, 0x0c10, 29, 0x2c10, 31, 0x0003, 23, 0x92f6,
-                                31, 0x0000, 23, 0x003d, 30, 0x00de, 20, 0x20e7,  9, 0x0700,
-         --------------------------------------------------------------------------*/
-       /* 12/17/03 IP1000A v1-4 rev=0x40 */
-       (0x4000 | (07 * 4)), 31, 0x0001, 27, 0x01e0, 31, 0x0002, 27, 0xeb8e, 31,
-           0x0000,
-       30, 0x005e, 9, 0x0700,
-       /* 01/09/04 IP1000A v1-5 rev=0x41 */
-       (0x4100 | (07 * 4)), 31, 0x0001, 27, 0x01e0, 31, 0x0002, 27, 0xeb8e, 31,
-           0x0000,
-       30, 0x005e, 9, 0x0700,
-       0x0000
-};
-
-static const char * const ipg_brand_name[] = {
-       "IC PLUS IP1000 1000/100/10 based NIC",
-       "Sundance Technology ST2021 based NIC",
-       "Tamarack Microelectronics TC9020/9021 based NIC",
-       "D-Link NIC IP1000A"
-};
-
-static const struct pci_device_id ipg_pci_tbl[] = {
-       { PCI_VDEVICE(SUNDANCE, 0x1023), 0 },
-       { PCI_VDEVICE(SUNDANCE, 0x2021), 1 },
-       { PCI_VDEVICE(DLINK,    0x9021), 2 },
-       { PCI_VDEVICE(DLINK,    0x4020), 3 },
-       { 0, }
-};
-
-MODULE_DEVICE_TABLE(pci, ipg_pci_tbl);
-
-static inline void __iomem *ipg_ioaddr(struct net_device *dev)
-{
-       struct ipg_nic_private *sp = netdev_priv(dev);
-       return sp->ioaddr;
-}
-
-#ifdef IPG_DEBUG
-static void ipg_dump_rfdlist(struct net_device *dev)
-{
-       struct ipg_nic_private *sp = netdev_priv(dev);
-       void __iomem *ioaddr = sp->ioaddr;
-       unsigned int i;
-       u32 offset;
-
-       IPG_DEBUG_MSG("_dump_rfdlist\n");
-
-       netdev_info(dev, "rx_current = %02x\n", sp->rx_current);
-       netdev_info(dev, "rx_dirty   = %02x\n", sp->rx_dirty);
-       netdev_info(dev, "RFDList start address = %016lx\n",
-                   (unsigned long)sp->rxd_map);
-       netdev_info(dev, "RFDListPtr register   = %08x%08x\n",
-                   ipg_r32(IPG_RFDLISTPTR1), ipg_r32(IPG_RFDLISTPTR0));
-
-       for (i = 0; i < IPG_RFDLIST_LENGTH; i++) {
-               offset = (u32) &sp->rxd[i].next_desc - (u32) sp->rxd;
-               netdev_info(dev, "%02x %04x RFDNextPtr = %016lx\n",
-                           i, offset, (unsigned long)sp->rxd[i].next_desc);
-               offset = (u32) &sp->rxd[i].rfs - (u32) sp->rxd;
-               netdev_info(dev, "%02x %04x RFS        = %016lx\n",
-                           i, offset, (unsigned long)sp->rxd[i].rfs);
-               offset = (u32) &sp->rxd[i].frag_info - (u32) sp->rxd;
-               netdev_info(dev, "%02x %04x frag_info   = %016lx\n",
-                           i, offset, (unsigned long)sp->rxd[i].frag_info);
-       }
-}
-
-static void ipg_dump_tfdlist(struct net_device *dev)
-{
-       struct ipg_nic_private *sp = netdev_priv(dev);
-       void __iomem *ioaddr = sp->ioaddr;
-       unsigned int i;
-       u32 offset;
-
-       IPG_DEBUG_MSG("_dump_tfdlist\n");
-
-       netdev_info(dev, "tx_current         = %02x\n", sp->tx_current);
-       netdev_info(dev, "tx_dirty = %02x\n", sp->tx_dirty);
-       netdev_info(dev, "TFDList start address = %016lx\n",
-                   (unsigned long) sp->txd_map);
-       netdev_info(dev, "TFDListPtr register   = %08x%08x\n",
-                   ipg_r32(IPG_TFDLISTPTR1), ipg_r32(IPG_TFDLISTPTR0));
-
-       for (i = 0; i < IPG_TFDLIST_LENGTH; i++) {
-               offset = (u32) &sp->txd[i].next_desc - (u32) sp->txd;
-               netdev_info(dev, "%02x %04x TFDNextPtr = %016lx\n",
-                           i, offset, (unsigned long)sp->txd[i].next_desc);
-
-               offset = (u32) &sp->txd[i].tfc - (u32) sp->txd;
-               netdev_info(dev, "%02x %04x TFC        = %016lx\n",
-                           i, offset, (unsigned long) sp->txd[i].tfc);
-               offset = (u32) &sp->txd[i].frag_info - (u32) sp->txd;
-               netdev_info(dev, "%02x %04x frag_info   = %016lx\n",
-                           i, offset, (unsigned long) sp->txd[i].frag_info);
-       }
-}
-#endif
-
-static void ipg_write_phy_ctl(void __iomem *ioaddr, u8 data)
-{
-       ipg_w8(IPG_PC_RSVD_MASK & data, PHY_CTRL);
-       ndelay(IPG_PC_PHYCTRLWAIT_NS);
-}
-
-static void ipg_drive_phy_ctl_low_high(void __iomem *ioaddr, u8 data)
-{
-       ipg_write_phy_ctl(ioaddr, IPG_PC_MGMTCLK_LO | data);
-       ipg_write_phy_ctl(ioaddr, IPG_PC_MGMTCLK_HI | data);
-}
-
-static void send_three_state(void __iomem *ioaddr, u8 phyctrlpolarity)
-{
-       phyctrlpolarity |= (IPG_PC_MGMTDATA & 0) | IPG_PC_MGMTDIR;
-
-       ipg_drive_phy_ctl_low_high(ioaddr, phyctrlpolarity);
-}
-
-static void send_end(void __iomem *ioaddr, u8 phyctrlpolarity)
-{
-       ipg_w8((IPG_PC_MGMTCLK_LO | (IPG_PC_MGMTDATA & 0) | IPG_PC_MGMTDIR |
-               phyctrlpolarity) & IPG_PC_RSVD_MASK, PHY_CTRL);
-}
-
-static u16 read_phy_bit(void __iomem *ioaddr, u8 phyctrlpolarity)
-{
-       u16 bit_data;
-
-       ipg_write_phy_ctl(ioaddr, IPG_PC_MGMTCLK_LO | phyctrlpolarity);
-
-       bit_data = ((ipg_r8(PHY_CTRL) & IPG_PC_MGMTDATA) >> 1) & 1;
-
-       ipg_write_phy_ctl(ioaddr, IPG_PC_MGMTCLK_HI | phyctrlpolarity);
-
-       return bit_data;
-}
-
-/*
- * Read a register from the Physical Layer device located
- * on the IPG NIC, using the IPG PHYCTRL register.
- */
-static int mdio_read(struct net_device *dev, int phy_id, int phy_reg)
-{
-       void __iomem *ioaddr = ipg_ioaddr(dev);
-       /*
-        * The GMII mangement frame structure for a read is as follows:
-        *
-        * |Preamble|st|op|phyad|regad|ta|      data      |idle|
-        * |< 32 1s>|01|10|AAAAA|RRRRR|z0|DDDDDDDDDDDDDDDD|z   |
-        *
-        * <32 1s> = 32 consecutive logic 1 values
-        * A = bit of Physical Layer device address (MSB first)
-        * R = bit of register address (MSB first)
-        * z = High impedance state
-        * D = bit of read data (MSB first)
-        *
-        * Transmission order is 'Preamble' field first, bits transmitted
-        * left to right (first to last).
-        */
-       struct {
-               u32 field;
-               unsigned int len;
-       } p[] = {
-               { GMII_PREAMBLE,        32 },   /* Preamble */
-               { GMII_ST,              2  },   /* ST */
-               { GMII_READ,            2  },   /* OP */
-               { phy_id,               5  },   /* PHYAD */
-               { phy_reg,              5  },   /* REGAD */
-               { 0x0000,               2  },   /* TA */
-               { 0x0000,               16 },   /* DATA */
-               { 0x0000,               1  }    /* IDLE */
-       };
-       unsigned int i, j;
-       u8 polarity, data;
-
-       polarity  = ipg_r8(PHY_CTRL);
-       polarity &= (IPG_PC_DUPLEX_POLARITY | IPG_PC_LINK_POLARITY);
-
-       /* Create the Preamble, ST, OP, PHYAD, and REGAD field. */
-       for (j = 0; j < 5; j++) {
-               for (i = 0; i < p[j].len; i++) {
-                       /* For each variable length field, the MSB must be
-                        * transmitted first. Rotate through the field bits,
-                        * starting with the MSB, and move each bit into the
-                        * the 1st (2^1) bit position (this is the bit position
-                        * corresponding to the MgmtData bit of the PhyCtrl
-                        * register for the IPG).
-                        *
-                        * Example: ST = 01;
-                        *
-                        *          First write a '0' to bit 1 of the PhyCtrl
-                        *          register, then write a '1' to bit 1 of the
-                        *          PhyCtrl register.
-                        *
-                        * To do this, right shift the MSB of ST by the value:
-                        * [field length - 1 - #ST bits already written]
-                        * then left shift this result by 1.
-                        */
-                       data  = (p[j].field >> (p[j].len - 1 - i)) << 1;
-                       data &= IPG_PC_MGMTDATA;
-                       data |= polarity | IPG_PC_MGMTDIR;
-
-                       ipg_drive_phy_ctl_low_high(ioaddr, data);
-               }
-       }
-
-       send_three_state(ioaddr, polarity);
-
-       read_phy_bit(ioaddr, polarity);
-
-       /*
-        * For a read cycle, the bits for the next two fields (TA and
-        * DATA) are driven by the PHY (the IPG reads these bits).
-        */
-       for (i = 0; i < p[6].len; i++) {
-               p[6].field |=
-                   (read_phy_bit(ioaddr, polarity) << (p[6].len - 1 - i));
-       }
-
-       send_three_state(ioaddr, polarity);
-       send_three_state(ioaddr, polarity);
-       send_three_state(ioaddr, polarity);
-       send_end(ioaddr, polarity);
-
-       /* Return the value of the DATA field. */
-       return p[6].field;
-}
-
-/*
- * Write to a register from the Physical Layer device located
- * on the IPG NIC, using the IPG PHYCTRL register.
- */
-static void mdio_write(struct net_device *dev, int phy_id, int phy_reg, int val)
-{
-       void __iomem *ioaddr = ipg_ioaddr(dev);
-       /*
-        * The GMII mangement frame structure for a read is as follows:
-        *
-        * |Preamble|st|op|phyad|regad|ta|      data      |idle|
-        * |< 32 1s>|01|10|AAAAA|RRRRR|z0|DDDDDDDDDDDDDDDD|z   |
-        *
-        * <32 1s> = 32 consecutive logic 1 values
-        * A = bit of Physical Layer device address (MSB first)
-        * R = bit of register address (MSB first)
-        * z = High impedance state
-        * D = bit of write data (MSB first)
-        *
-        * Transmission order is 'Preamble' field first, bits transmitted
-        * left to right (first to last).
-        */
-       struct {
-               u32 field;
-               unsigned int len;
-       } p[] = {
-               { GMII_PREAMBLE,        32 },   /* Preamble */
-               { GMII_ST,              2  },   /* ST */
-               { GMII_WRITE,           2  },   /* OP */
-               { phy_id,               5  },   /* PHYAD */
-               { phy_reg,              5  },   /* REGAD */
-               { 0x0002,               2  },   /* TA */
-               { val & 0xffff,         16 },   /* DATA */
-               { 0x0000,               1  }    /* IDLE */
-       };
-       unsigned int i, j;
-       u8 polarity, data;
-
-       polarity  = ipg_r8(PHY_CTRL);
-       polarity &= (IPG_PC_DUPLEX_POLARITY | IPG_PC_LINK_POLARITY);
-
-       /* Create the Preamble, ST, OP, PHYAD, and REGAD field. */
-       for (j = 0; j < 7; j++) {
-               for (i = 0; i < p[j].len; i++) {
-                       /* For each variable length field, the MSB must be
-                        * transmitted first. Rotate through the field bits,
-                        * starting with the MSB, and move each bit into the
-                        * the 1st (2^1) bit position (this is the bit position
-                        * corresponding to the MgmtData bit of the PhyCtrl
-                        * register for the IPG).
-                        *
-                        * Example: ST = 01;
-                        *
-                        *          First write a '0' to bit 1 of the PhyCtrl
-                        *          register, then write a '1' to bit 1 of the
-                        *          PhyCtrl register.
-                        *
-                        * To do this, right shift the MSB of ST by the value:
-                        * [field length - 1 - #ST bits already written]
-                        * then left shift this result by 1.
-                        */
-                       data  = (p[j].field >> (p[j].len - 1 - i)) << 1;
-                       data &= IPG_PC_MGMTDATA;
-                       data |= polarity | IPG_PC_MGMTDIR;
-
-                       ipg_drive_phy_ctl_low_high(ioaddr, data);
-               }
-       }
-
-       /* The last cycle is a tri-state, so read from the PHY. */
-       ipg_write_phy_ctl(ioaddr, IPG_PC_MGMTCLK_LO | polarity);
-       ipg_r8(PHY_CTRL);
-       ipg_write_phy_ctl(ioaddr, IPG_PC_MGMTCLK_HI | polarity);
-}
-
-static void ipg_set_led_mode(struct net_device *dev)
-{
-       struct ipg_nic_private *sp = netdev_priv(dev);
-       void __iomem *ioaddr = sp->ioaddr;
-       u32 mode;
-
-       mode = ipg_r32(ASIC_CTRL);
-       mode &= ~(IPG_AC_LED_MODE_BIT_1 | IPG_AC_LED_MODE | IPG_AC_LED_SPEED);
-
-       if ((sp->led_mode & 0x03) > 1)
-               mode |= IPG_AC_LED_MODE_BIT_1;  /* Write Asic Control Bit 29 */
-
-       if ((sp->led_mode & 0x01) == 1)
-               mode |= IPG_AC_LED_MODE;        /* Write Asic Control Bit 14 */
-
-       if ((sp->led_mode & 0x08) == 8)
-               mode |= IPG_AC_LED_SPEED;       /* Write Asic Control Bit 27 */
-
-       ipg_w32(mode, ASIC_CTRL);
-}
-
-static void ipg_set_phy_set(struct net_device *dev)
-{
-       struct ipg_nic_private *sp = netdev_priv(dev);
-       void __iomem *ioaddr = sp->ioaddr;
-       int physet;
-
-       physet = ipg_r8(PHY_SET);
-       physet &= ~(IPG_PS_MEM_LENB9B | IPG_PS_MEM_LEN9 | IPG_PS_NON_COMPDET);
-       physet |= ((sp->led_mode & 0x70) >> 4);
-       ipg_w8(physet, PHY_SET);
-}
-
-static int ipg_reset(struct net_device *dev, u32 resetflags)
-{
-       /* Assert functional resets via the IPG AsicCtrl
-        * register as specified by the 'resetflags' input
-        * parameter.
-        */
-       void __iomem *ioaddr = ipg_ioaddr(dev);
-       unsigned int timeout_count = 0;
-
-       IPG_DEBUG_MSG("_reset\n");
-
-       ipg_w32(ipg_r32(ASIC_CTRL) | resetflags, ASIC_CTRL);
-
-       /* Delay added to account for problem with 10Mbps reset. */
-       mdelay(IPG_AC_RESETWAIT);
-
-       while (IPG_AC_RESET_BUSY & ipg_r32(ASIC_CTRL)) {
-               mdelay(IPG_AC_RESETWAIT);
-               if (++timeout_count > IPG_AC_RESET_TIMEOUT)
-                       return -ETIME;
-       }
-       /* Set LED Mode in Asic Control */
-       ipg_set_led_mode(dev);
-
-       /* Set PHYSet Register Value */
-       ipg_set_phy_set(dev);
-       return 0;
-}
-
-/* Find the GMII PHY address. */
-static int ipg_find_phyaddr(struct net_device *dev)
-{
-       unsigned int phyaddr, i;
-
-       for (i = 0; i < 32; i++) {
-               u32 status;
-
-               /* Search for the correct PHY address among 32 possible. */
-               phyaddr = (IPG_NIC_PHY_ADDRESS + i) % 32;
-
-               /* 10/22/03 Grace change verify from GMII_PHY_STATUS to
-                  GMII_PHY_ID1
-                */
-
-               status = mdio_read(dev, phyaddr, MII_BMSR);
-
-               if ((status != 0xFFFF) && (status != 0))
-                       return phyaddr;
-       }
-
-       return 0x1f;
-}
-
-/*
- * Configure IPG based on result of IEEE 802.3 PHY
- * auto-negotiation.
- */
-static int ipg_config_autoneg(struct net_device *dev)
-{
-       struct ipg_nic_private *sp = netdev_priv(dev);
-       void __iomem *ioaddr = sp->ioaddr;
-       unsigned int txflowcontrol;
-       unsigned int rxflowcontrol;
-       unsigned int fullduplex;
-       u32 mac_ctrl_val;
-       u32 asicctrl;
-       u8 phyctrl;
-       const char *speed;
-       const char *duplex;
-       const char *tx_desc;
-       const char *rx_desc;
-
-       IPG_DEBUG_MSG("_config_autoneg\n");
-
-       asicctrl = ipg_r32(ASIC_CTRL);
-       phyctrl = ipg_r8(PHY_CTRL);
-       mac_ctrl_val = ipg_r32(MAC_CTRL);
-
-       /* Set flags for use in resolving auto-negotiation, assuming
-        * non-1000Mbps, half duplex, no flow control.
-        */
-       fullduplex = 0;
-       txflowcontrol = 0;
-       rxflowcontrol = 0;
-
-       /* To accommodate a problem in 10Mbps operation,
-        * set a global flag if PHY running in 10Mbps mode.
-        */
-       sp->tenmbpsmode = 0;
-
-       /* Determine actual speed of operation. */
-       switch (phyctrl & IPG_PC_LINK_SPEED) {
-       case IPG_PC_LINK_SPEED_10MBPS:
-               speed = "10Mbps";
-               sp->tenmbpsmode = 1;
-               break;
-       case IPG_PC_LINK_SPEED_100MBPS:
-               speed = "100Mbps";
-               break;
-       case IPG_PC_LINK_SPEED_1000MBPS:
-               speed = "1000Mbps";
-               break;
-       default:
-               speed = "undefined!";
-               return 0;
-       }
-
-       netdev_info(dev, "Link speed = %s\n", speed);
-       if (sp->tenmbpsmode == 1)
-               netdev_info(dev, "10Mbps operational mode enabled\n");
-
-       if (phyctrl & IPG_PC_DUPLEX_STATUS) {
-               fullduplex = 1;
-               txflowcontrol = 1;
-               rxflowcontrol = 1;
-       }
-
-       /* Configure full duplex, and flow control. */
-       if (fullduplex == 1) {
-
-               /* Configure IPG for full duplex operation. */
-
-               duplex = "full";
-
-               mac_ctrl_val |= IPG_MC_DUPLEX_SELECT_FD;
-
-               if (txflowcontrol == 1) {
-                       tx_desc  = "";
-                       mac_ctrl_val |= IPG_MC_TX_FLOW_CONTROL_ENABLE;
-               } else {
-                       tx_desc = "no ";
-                       mac_ctrl_val &= ~IPG_MC_TX_FLOW_CONTROL_ENABLE;
-               }
-
-               if (rxflowcontrol == 1) {
-                       rx_desc = "";
-                       mac_ctrl_val |= IPG_MC_RX_FLOW_CONTROL_ENABLE;
-               } else {
-                       rx_desc = "no ";
-                       mac_ctrl_val &= ~IPG_MC_RX_FLOW_CONTROL_ENABLE;
-               }
-       } else {
-               duplex = "half";
-               tx_desc = "no ";
-               rx_desc = "no ";
-               mac_ctrl_val &= (~IPG_MC_DUPLEX_SELECT_FD &
-                                ~IPG_MC_TX_FLOW_CONTROL_ENABLE &
-                                ~IPG_MC_RX_FLOW_CONTROL_ENABLE);
-       }
-
-       netdev_info(dev, "setting %s duplex, %sTX, %sRX flow control\n",
-                   duplex, tx_desc, rx_desc);
-       ipg_w32(mac_ctrl_val, MAC_CTRL);
-
-       return 0;
-}
-
-/* Determine and configure multicast operation and set
- * receive mode for IPG.
- */
-static void ipg_nic_set_multicast_list(struct net_device *dev)
-{
-       void __iomem *ioaddr = ipg_ioaddr(dev);
-       struct netdev_hw_addr *ha;
-       unsigned int hashindex;
-       u32 hashtable[2];
-       u8 receivemode;
-
-       IPG_DEBUG_MSG("_nic_set_multicast_list\n");
-
-       receivemode = IPG_RM_RECEIVEUNICAST | IPG_RM_RECEIVEBROADCAST;
-
-       if (dev->flags & IFF_PROMISC) {
-               /* NIC to be configured in promiscuous mode. */
-               receivemode = IPG_RM_RECEIVEALLFRAMES;
-       } else if ((dev->flags & IFF_ALLMULTI) ||
-                  ((dev->flags & IFF_MULTICAST) &&
-                   (netdev_mc_count(dev) > IPG_MULTICAST_HASHTABLE_SIZE))) {
-               /* NIC to be configured to receive all multicast
-                * frames. */
-               receivemode |= IPG_RM_RECEIVEMULTICAST;
-       } else if ((dev->flags & IFF_MULTICAST) && !netdev_mc_empty(dev)) {
-               /* NIC to be configured to receive selected
-                * multicast addresses. */
-               receivemode |= IPG_RM_RECEIVEMULTICASTHASH;
-       }
-
-       /* Calculate the bits to set for the 64 bit, IPG HASHTABLE.
-        * The IPG applies a cyclic-redundancy-check (the same CRC
-        * used to calculate the frame data FCS) to the destination
-        * address all incoming multicast frames whose destination
-        * address has the multicast bit set. The least significant
-        * 6 bits of the CRC result are used as an addressing index
-        * into the hash table. If the value of the bit addressed by
-        * this index is a 1, the frame is passed to the host system.
-        */
-
-       /* Clear hashtable. */
-       hashtable[0] = 0x00000000;
-       hashtable[1] = 0x00000000;
-
-       /* Cycle through all multicast addresses to filter. */
-       netdev_for_each_mc_addr(ha, dev) {
-               /* Calculate CRC result for each multicast address. */
-               hashindex = crc32_le(0xffffffff, ha->addr,
-                                    ETH_ALEN);
-
-               /* Use only the least significant 6 bits. */
-               hashindex = hashindex & 0x3F;
-
-               /* Within "hashtable", set bit number "hashindex"
-                * to a logic 1.
-                */
-               set_bit(hashindex, (void *)hashtable);
-       }
-
-       /* Write the value of the hashtable, to the 4, 16 bit
-        * HASHTABLE IPG registers.
-        */
-       ipg_w32(hashtable[0], HASHTABLE_0);
-       ipg_w32(hashtable[1], HASHTABLE_1);
-
-       ipg_w8(IPG_RM_RSVD_MASK & receivemode, RECEIVE_MODE);
-
-       IPG_DEBUG_MSG("ReceiveMode = %x\n", ipg_r8(RECEIVE_MODE));
-}
-
-static int ipg_io_config(struct net_device *dev)
-{
-       struct ipg_nic_private *sp = netdev_priv(dev);
-       void __iomem *ioaddr = ipg_ioaddr(dev);
-       u32 origmacctrl;
-       u32 restoremacctrl;
-
-       IPG_DEBUG_MSG("_io_config\n");
-
-       origmacctrl = ipg_r32(MAC_CTRL);
-
-       restoremacctrl = origmacctrl | IPG_MC_STATISTICS_ENABLE;
-
-       /* Based on compilation option, determine if FCS is to be
-        * stripped on receive frames by IPG.
-        */
-       if (!IPG_STRIP_FCS_ON_RX)
-               restoremacctrl |= IPG_MC_RCV_FCS;
-
-       /* Determine if transmitter and/or receiver are
-        * enabled so we may restore MACCTRL correctly.
-        */
-       if (origmacctrl & IPG_MC_TX_ENABLED)
-               restoremacctrl |= IPG_MC_TX_ENABLE;
-
-       if (origmacctrl & IPG_MC_RX_ENABLED)
-               restoremacctrl |= IPG_MC_RX_ENABLE;
-
-       /* Transmitter and receiver must be disabled before setting
-        * IFSSelect.
-        */
-       ipg_w32((origmacctrl & (IPG_MC_RX_DISABLE | IPG_MC_TX_DISABLE)) &
-               IPG_MC_RSVD_MASK, MAC_CTRL);
-
-       /* Now that transmitter and receiver are disabled, write
-        * to IFSSelect.
-        */
-       ipg_w32((origmacctrl & IPG_MC_IFS_96BIT) & IPG_MC_RSVD_MASK, MAC_CTRL);
-
-       /* Set RECEIVEMODE register. */
-       ipg_nic_set_multicast_list(dev);
-
-       ipg_w16(sp->max_rxframe_size, MAX_FRAME_SIZE);
-
-       ipg_w8(IPG_RXDMAPOLLPERIOD_VALUE,   RX_DMA_POLL_PERIOD);
-       ipg_w8(IPG_RXDMAURGENTTHRESH_VALUE, RX_DMA_URGENT_THRESH);
-       ipg_w8(IPG_RXDMABURSTTHRESH_VALUE,  RX_DMA_BURST_THRESH);
-       ipg_w8(IPG_TXDMAPOLLPERIOD_VALUE,   TX_DMA_POLL_PERIOD);
-       ipg_w8(IPG_TXDMAURGENTTHRESH_VALUE, TX_DMA_URGENT_THRESH);
-       ipg_w8(IPG_TXDMABURSTTHRESH_VALUE,  TX_DMA_BURST_THRESH);
-       ipg_w16((IPG_IE_HOST_ERROR | IPG_IE_TX_DMA_COMPLETE |
-                IPG_IE_TX_COMPLETE | IPG_IE_INT_REQUESTED |
-                IPG_IE_UPDATE_STATS | IPG_IE_LINK_EVENT |
-                IPG_IE_RX_DMA_COMPLETE | IPG_IE_RX_DMA_PRIORITY), INT_ENABLE);
-       ipg_w16(IPG_FLOWONTHRESH_VALUE,  FLOW_ON_THRESH);
-       ipg_w16(IPG_FLOWOFFTHRESH_VALUE, FLOW_OFF_THRESH);
-
-       /* IPG multi-frag frame bug workaround.
-        * Per silicon revision B3 eratta.
-        */
-       ipg_w16(ipg_r16(DEBUG_CTRL) | 0x0200, DEBUG_CTRL);
-
-       /* IPG TX poll now bug workaround.
-        * Per silicon revision B3 eratta.
-        */
-       ipg_w16(ipg_r16(DEBUG_CTRL) | 0x0010, DEBUG_CTRL);
-
-       /* IPG RX poll now bug workaround.
-        * Per silicon revision B3 eratta.
-        */
-       ipg_w16(ipg_r16(DEBUG_CTRL) | 0x0020, DEBUG_CTRL);
-
-       /* Now restore MACCTRL to original setting. */
-       ipg_w32(IPG_MC_RSVD_MASK & restoremacctrl, MAC_CTRL);
-
-       /* Disable unused RMON statistics. */
-       ipg_w32(IPG_RZ_ALL, RMON_STATISTICS_MASK);
-
-       /* Disable unused MIB statistics. */
-       ipg_w32(IPG_SM_MACCONTROLFRAMESXMTD | IPG_SM_MACCONTROLFRAMESRCVD |
-               IPG_SM_BCSTOCTETXMTOK_BCSTFRAMESXMTDOK | IPG_SM_TXJUMBOFRAMES |
-               IPG_SM_MCSTOCTETXMTOK_MCSTFRAMESXMTDOK | IPG_SM_RXJUMBOFRAMES |
-               IPG_SM_BCSTOCTETRCVDOK_BCSTFRAMESRCVDOK |
-               IPG_SM_UDPCHECKSUMERRORS | IPG_SM_TCPCHECKSUMERRORS |
-               IPG_SM_IPCHECKSUMERRORS, STATISTICS_MASK);
-
-       return 0;
-}
-
-/*
- * Create a receive buffer within system memory and update
- * NIC private structure appropriately.
- */
-static int ipg_get_rxbuff(struct net_device *dev, int entry)
-{
-       struct ipg_nic_private *sp = netdev_priv(dev);
-       struct ipg_rx *rxfd = sp->rxd + entry;
-       struct sk_buff *skb;
-       u64 rxfragsize;
-
-       IPG_DEBUG_MSG("_get_rxbuff\n");
-
-       skb = netdev_alloc_skb_ip_align(dev, sp->rxsupport_size);
-       if (!skb) {
-               sp->rx_buff[entry] = NULL;
-               return -ENOMEM;
-       }
-
-       /* Save the address of the sk_buff structure. */
-       sp->rx_buff[entry] = skb;
-
-       rxfd->frag_info = cpu_to_le64(pci_map_single(sp->pdev, skb->data,
-               sp->rx_buf_sz, PCI_DMA_FROMDEVICE));
-
-       /* Set the RFD fragment length. */
-       rxfragsize = sp->rxfrag_size;
-       rxfd->frag_info |= cpu_to_le64((rxfragsize << 48) & IPG_RFI_FRAGLEN);
-
-       return 0;
-}
-
-static int init_rfdlist(struct net_device *dev)
-{
-       struct ipg_nic_private *sp = netdev_priv(dev);
-       void __iomem *ioaddr = sp->ioaddr;
-       unsigned int i;
-
-       IPG_DEBUG_MSG("_init_rfdlist\n");
-
-       for (i = 0; i < IPG_RFDLIST_LENGTH; i++) {
-               struct ipg_rx *rxfd = sp->rxd + i;
-
-               if (sp->rx_buff[i]) {
-                       pci_unmap_single(sp->pdev,
-                               le64_to_cpu(rxfd->frag_info) & ~IPG_RFI_FRAGLEN,
-                               sp->rx_buf_sz, PCI_DMA_FROMDEVICE);
-                       dev_kfree_skb_irq(sp->rx_buff[i]);
-                       sp->rx_buff[i] = NULL;
-               }
-
-               /* Clear out the RFS field. */
-               rxfd->rfs = 0x0000000000000000;
-
-               if (ipg_get_rxbuff(dev, i) < 0) {
-                       /*
-                        * A receive buffer was not ready, break the
-                        * RFD list here.
-                        */
-                       IPG_DEBUG_MSG("Cannot allocate Rx buffer\n");
-
-                       /* Just in case we cannot allocate a single RFD.
-                        * Should not occur.
-                        */
-                       if (i == 0) {
-                               netdev_err(dev, "No memory available for RFD list\n");
-                               return -ENOMEM;
-                       }
-               }
-
-               rxfd->next_desc = cpu_to_le64(sp->rxd_map +
-                       sizeof(struct ipg_rx)*(i + 1));
-       }
-       sp->rxd[i - 1].next_desc = cpu_to_le64(sp->rxd_map);
-
-       sp->rx_current = 0;
-       sp->rx_dirty = 0;
-
-       /* Write the location of the RFDList to the IPG. */
-       ipg_w32((u32) sp->rxd_map, RFD_LIST_PTR_0);
-       ipg_w32(0x00000000, RFD_LIST_PTR_1);
-
-       return 0;
-}
-
-static void init_tfdlist(struct net_device *dev)
-{
-       struct ipg_nic_private *sp = netdev_priv(dev);
-       void __iomem *ioaddr = sp->ioaddr;
-       unsigned int i;
-
-       IPG_DEBUG_MSG("_init_tfdlist\n");
-
-       for (i = 0; i < IPG_TFDLIST_LENGTH; i++) {
-               struct ipg_tx *txfd = sp->txd + i;
-
-               txfd->tfc = cpu_to_le64(IPG_TFC_TFDDONE);
-
-               if (sp->tx_buff[i]) {
-                       dev_kfree_skb_irq(sp->tx_buff[i]);
-                       sp->tx_buff[i] = NULL;
-               }
-
-               txfd->next_desc = cpu_to_le64(sp->txd_map +
-                       sizeof(struct ipg_tx)*(i + 1));
-       }
-       sp->txd[i - 1].next_desc = cpu_to_le64(sp->txd_map);
-
-       sp->tx_current = 0;
-       sp->tx_dirty = 0;
-
-       /* Write the location of the TFDList to the IPG. */
-       IPG_DDEBUG_MSG("Starting TFDListPtr = %08x\n",
-                      (u32) sp->txd_map);
-       ipg_w32((u32) sp->txd_map, TFD_LIST_PTR_0);
-       ipg_w32(0x00000000, TFD_LIST_PTR_1);
-
-       sp->reset_current_tfd = 1;
-}
-
-/*
- * Free all transmit buffers which have already been transferred
- * via DMA to the IPG.
- */
-static void ipg_nic_txfree(struct net_device *dev)
-{
-       struct ipg_nic_private *sp = netdev_priv(dev);
-       unsigned int released, pending, dirty;
-
-       IPG_DEBUG_MSG("_nic_txfree\n");
-
-       pending = sp->tx_current - sp->tx_dirty;
-       dirty = sp->tx_dirty % IPG_TFDLIST_LENGTH;
-
-       for (released = 0; released < pending; released++) {
-               struct sk_buff *skb = sp->tx_buff[dirty];
-               struct ipg_tx *txfd = sp->txd + dirty;
-
-               IPG_DEBUG_MSG("TFC = %016lx\n", (unsigned long) txfd->tfc);
-
-               /* Look at each TFD's TFC field beginning
-                * at the last freed TFD up to the current TFD.
-                * If the TFDDone bit is set, free the associated
-                * buffer.
-                */
-               if (!(txfd->tfc & cpu_to_le64(IPG_TFC_TFDDONE)))
-                        break;
-
-               /* Free the transmit buffer. */
-               if (skb) {
-                       pci_unmap_single(sp->pdev,
-                               le64_to_cpu(txfd->frag_info) & ~IPG_TFI_FRAGLEN,
-                               skb->len, PCI_DMA_TODEVICE);
-
-                       dev_kfree_skb_irq(skb);
-
-                       sp->tx_buff[dirty] = NULL;
-               }
-               dirty = (dirty + 1) % IPG_TFDLIST_LENGTH;
-       }
-
-       sp->tx_dirty += released;
-
-       if (netif_queue_stopped(dev) &&
-           (sp->tx_current != (sp->tx_dirty + IPG_TFDLIST_LENGTH))) {
-               netif_wake_queue(dev);
-       }
-}
-
-static void ipg_tx_timeout(struct net_device *dev)
-{
-       struct ipg_nic_private *sp = netdev_priv(dev);
-       void __iomem *ioaddr = sp->ioaddr;
-
-       ipg_reset(dev, IPG_AC_TX_RESET | IPG_AC_DMA | IPG_AC_NETWORK |
-                 IPG_AC_FIFO);
-
-       spin_lock_irq(&sp->lock);
-
-       /* Re-configure after DMA reset. */
-       if (ipg_io_config(dev) < 0)
-               netdev_info(dev, "Error during re-configuration\n");
-
-       init_tfdlist(dev);
-
-       spin_unlock_irq(&sp->lock);
-
-       ipg_w32((ipg_r32(MAC_CTRL) | IPG_MC_TX_ENABLE) & IPG_MC_RSVD_MASK,
-               MAC_CTRL);
-}
-
-/*
- * For TxComplete interrupts, free all transmit
- * buffers which have already been transferred via DMA
- * to the IPG.
- */
-static void ipg_nic_txcleanup(struct net_device *dev)
-{
-       struct ipg_nic_private *sp = netdev_priv(dev);
-       void __iomem *ioaddr = sp->ioaddr;
-       unsigned int i;
-
-       IPG_DEBUG_MSG("_nic_txcleanup\n");
-
-       for (i = 0; i < IPG_TFDLIST_LENGTH; i++) {
-               /* Reading the TXSTATUS register clears the
-                * TX_COMPLETE interrupt.
-                */
-               u32 txstatusdword = ipg_r32(TX_STATUS);
-
-               IPG_DEBUG_MSG("TxStatus = %08x\n", txstatusdword);
-
-               /* Check for Transmit errors. Error bits only valid if
-                * TX_COMPLETE bit in the TXSTATUS register is a 1.
-                */
-               if (!(txstatusdword & IPG_TS_TX_COMPLETE))
-                       break;
-
-               /* If in 10Mbps mode, indicate transmit is ready. */
-               if (sp->tenmbpsmode) {
-                       netif_wake_queue(dev);
-               }
-
-               /* Transmit error, increment stat counters. */
-               if (txstatusdword & IPG_TS_TX_ERROR) {
-                       IPG_DEBUG_MSG("Transmit error\n");
-                       sp->stats.tx_errors++;
-               }
-
-               /* Late collision, re-enable transmitter. */
-               if (txstatusdword & IPG_TS_LATE_COLLISION) {
-                       IPG_DEBUG_MSG("Late collision on transmit\n");
-                       ipg_w32((ipg_r32(MAC_CTRL) | IPG_MC_TX_ENABLE) &
-                               IPG_MC_RSVD_MASK, MAC_CTRL);
-               }
-
-               /* Maximum collisions, re-enable transmitter. */
-               if (txstatusdword & IPG_TS_TX_MAX_COLL) {
-                       IPG_DEBUG_MSG("Maximum collisions on transmit\n");
-                       ipg_w32((ipg_r32(MAC_CTRL) | IPG_MC_TX_ENABLE) &
-                               IPG_MC_RSVD_MASK, MAC_CTRL);
-               }
-
-               /* Transmit underrun, reset and re-enable
-                * transmitter.
-                */
-               if (txstatusdword & IPG_TS_TX_UNDERRUN) {
-                       IPG_DEBUG_MSG("Transmitter underrun\n");
-                       sp->stats.tx_fifo_errors++;
-                       ipg_reset(dev, IPG_AC_TX_RESET | IPG_AC_DMA |
-                                 IPG_AC_NETWORK | IPG_AC_FIFO);
-
-                       /* Re-configure after DMA reset. */
-                       if (ipg_io_config(dev) < 0) {
-                               netdev_info(dev, "Error during re-configuration\n");
-                       }
-                       init_tfdlist(dev);
-
-                       ipg_w32((ipg_r32(MAC_CTRL) | IPG_MC_TX_ENABLE) &
-                               IPG_MC_RSVD_MASK, MAC_CTRL);
-               }
-       }
-
-       ipg_nic_txfree(dev);
-}
-
-/* Provides statistical information about the IPG NIC. */
-static struct net_device_stats *ipg_nic_get_stats(struct net_device *dev)
-{
-       struct ipg_nic_private *sp = netdev_priv(dev);
-       void __iomem *ioaddr = sp->ioaddr;
-       u16 temp1;
-       u16 temp2;
-
-       IPG_DEBUG_MSG("_nic_get_stats\n");
-
-       /* Check to see if the NIC has been initialized via nic_open,
-        * before trying to read statistic registers.
-        */
-       if (!netif_running(dev))
-               return &sp->stats;
-
-       sp->stats.rx_packets += ipg_r32(IPG_FRAMESRCVDOK);
-       sp->stats.tx_packets += ipg_r32(IPG_FRAMESXMTDOK);
-       sp->stats.rx_bytes += ipg_r32(IPG_OCTETRCVOK);
-       sp->stats.tx_bytes += ipg_r32(IPG_OCTETXMTOK);
-       temp1 = ipg_r16(IPG_FRAMESLOSTRXERRORS);
-       sp->stats.rx_errors += temp1;
-       sp->stats.rx_missed_errors += temp1;
-       temp1 = ipg_r32(IPG_SINGLECOLFRAMES) + ipg_r32(IPG_MULTICOLFRAMES) +
-               ipg_r32(IPG_LATECOLLISIONS);
-       temp2 = ipg_r16(IPG_CARRIERSENSEERRORS);
-       sp->stats.collisions += temp1;
-       sp->stats.tx_dropped += ipg_r16(IPG_FRAMESABORTXSCOLLS);
-       sp->stats.tx_errors += ipg_r16(IPG_FRAMESWEXDEFERRAL) +
-               ipg_r32(IPG_FRAMESWDEFERREDXMT) + temp1 + temp2;
-       sp->stats.multicast += ipg_r32(IPG_MCSTOCTETRCVDOK);
-
-       /* detailed tx_errors */
-       sp->stats.tx_carrier_errors += temp2;
-
-       /* detailed rx_errors */
-       sp->stats.rx_length_errors += ipg_r16(IPG_INRANGELENGTHERRORS) +
-               ipg_r16(IPG_FRAMETOOLONGERRORS);
-       sp->stats.rx_crc_errors += ipg_r16(IPG_FRAMECHECKSEQERRORS);
-
-       /* Unutilized IPG statistic registers. */
-       ipg_r32(IPG_MCSTFRAMESRCVDOK);
-
-       return &sp->stats;
-}
-
-/* Restore used receive buffers. */
-static int ipg_nic_rxrestore(struct net_device *dev)
-{
-       struct ipg_nic_private *sp = netdev_priv(dev);
-       const unsigned int curr = sp->rx_current;
-       unsigned int dirty = sp->rx_dirty;
-
-       IPG_DEBUG_MSG("_nic_rxrestore\n");
-
-       for (dirty = sp->rx_dirty; curr - dirty > 0; dirty++) {
-               unsigned int entry = dirty % IPG_RFDLIST_LENGTH;
-
-               /* rx_copybreak may poke hole here and there. */
-               if (sp->rx_buff[entry])
-                       continue;
-
-               /* Generate a new receive buffer to replace the
-                * current buffer (which will be released by the
-                * Linux system).
-                */
-               if (ipg_get_rxbuff(dev, entry) < 0) {
-                       IPG_DEBUG_MSG("Cannot allocate new Rx buffer\n");
-
-                       break;
-               }
-
-               /* Reset the RFS field. */
-               sp->rxd[entry].rfs = 0x0000000000000000;
-       }
-       sp->rx_dirty = dirty;
-
-       return 0;
-}
-
-/* use jumboindex and jumbosize to control jumbo frame status
- * initial status is jumboindex=-1 and jumbosize=0
- * 1. jumboindex = -1 and jumbosize=0 : previous jumbo frame has been done.
- * 2. jumboindex != -1 and jumbosize != 0 : jumbo frame is not over size and receiving
- * 3. jumboindex = -1 and jumbosize != 0 : jumbo frame is over size, already dump
- *               previous receiving and need to continue dumping the current one
- */
-enum {
-       NORMAL_PACKET,
-       ERROR_PACKET
-};
-
-enum {
-       FRAME_NO_START_NO_END   = 0,
-       FRAME_WITH_START                = 1,
-       FRAME_WITH_END          = 10,
-       FRAME_WITH_START_WITH_END = 11
-};
-
-static void ipg_nic_rx_free_skb(struct net_device *dev)
-{
-       struct ipg_nic_private *sp = netdev_priv(dev);
-       unsigned int entry = sp->rx_current % IPG_RFDLIST_LENGTH;
-
-       if (sp->rx_buff[entry]) {
-               struct ipg_rx *rxfd = sp->rxd + entry;
-
-               pci_unmap_single(sp->pdev,
-                       le64_to_cpu(rxfd->frag_info) & ~IPG_RFI_FRAGLEN,
-                       sp->rx_buf_sz, PCI_DMA_FROMDEVICE);
-               dev_kfree_skb_irq(sp->rx_buff[entry]);
-               sp->rx_buff[entry] = NULL;
-       }
-}
-
-static int ipg_nic_rx_check_frame_type(struct net_device *dev)
-{
-       struct ipg_nic_private *sp = netdev_priv(dev);
-       struct ipg_rx *rxfd = sp->rxd + (sp->rx_current % IPG_RFDLIST_LENGTH);
-       int type = FRAME_NO_START_NO_END;
-
-       if (le64_to_cpu(rxfd->rfs) & IPG_RFS_FRAMESTART)
-               type += FRAME_WITH_START;
-       if (le64_to_cpu(rxfd->rfs) & IPG_RFS_FRAMEEND)
-               type += FRAME_WITH_END;
-       return type;
-}
-
-static int ipg_nic_rx_check_error(struct net_device *dev)
-{
-       struct ipg_nic_private *sp = netdev_priv(dev);
-       unsigned int entry = sp->rx_current % IPG_RFDLIST_LENGTH;
-       struct ipg_rx *rxfd = sp->rxd + entry;
-
-       if (IPG_DROP_ON_RX_ETH_ERRORS && (le64_to_cpu(rxfd->rfs) &
-            (IPG_RFS_RXFIFOOVERRUN | IPG_RFS_RXRUNTFRAME |
-             IPG_RFS_RXALIGNMENTERROR | IPG_RFS_RXFCSERROR |
-             IPG_RFS_RXOVERSIZEDFRAME | IPG_RFS_RXLENGTHERROR))) {
-               IPG_DEBUG_MSG("Rx error, RFS = %016lx\n",
-                             (unsigned long) rxfd->rfs);
-
-               /* Increment general receive error statistic. */
-               sp->stats.rx_errors++;
-
-               /* Increment detailed receive error statistics. */
-               if (le64_to_cpu(rxfd->rfs) & IPG_RFS_RXFIFOOVERRUN) {
-                       IPG_DEBUG_MSG("RX FIFO overrun occurred\n");
-
-                       sp->stats.rx_fifo_errors++;
-               }
-
-               if (le64_to_cpu(rxfd->rfs) & IPG_RFS_RXRUNTFRAME) {
-                       IPG_DEBUG_MSG("RX runt occurred\n");
-                       sp->stats.rx_length_errors++;
-               }
-
-               /* Do nothing for IPG_RFS_RXOVERSIZEDFRAME,
-                * error count handled by a IPG statistic register.
-                */
-
-               if (le64_to_cpu(rxfd->rfs) & IPG_RFS_RXALIGNMENTERROR) {
-                       IPG_DEBUG_MSG("RX alignment error occurred\n");
-                       sp->stats.rx_frame_errors++;
-               }
-
-               /* Do nothing for IPG_RFS_RXFCSERROR, error count
-                * handled by a IPG statistic register.
-                */
-
-               /* Free the memory associated with the RX
-                * buffer since it is erroneous and we will
-                * not pass it to higher layer processes.
-                */
-               if (sp->rx_buff[entry]) {
-                       pci_unmap_single(sp->pdev,
-                               le64_to_cpu(rxfd->frag_info) & ~IPG_RFI_FRAGLEN,
-                               sp->rx_buf_sz, PCI_DMA_FROMDEVICE);
-
-                       dev_kfree_skb_irq(sp->rx_buff[entry]);
-                       sp->rx_buff[entry] = NULL;
-               }
-               return ERROR_PACKET;
-       }
-       return NORMAL_PACKET;
-}
-
-static void ipg_nic_rx_with_start_and_end(struct net_device *dev,
-                                         struct ipg_nic_private *sp,
-                                         struct ipg_rx *rxfd, unsigned entry)
-{
-       struct ipg_jumbo *jumbo = &sp->jumbo;
-       struct sk_buff *skb;
-       int framelen;
-
-       if (jumbo->found_start) {
-               dev_kfree_skb_irq(jumbo->skb);
-               jumbo->found_start = 0;
-               jumbo->current_size = 0;
-               jumbo->skb = NULL;
-       }
-
-       /* 1: found error, 0 no error */
-       if (ipg_nic_rx_check_error(dev) != NORMAL_PACKET)
-               return;
-
-       skb = sp->rx_buff[entry];
-       if (!skb)
-               return;
-
-       /* accept this frame and send to upper layer */
-       framelen = le64_to_cpu(rxfd->rfs) & IPG_RFS_RXFRAMELEN;
-       if (framelen > sp->rxfrag_size)
-               framelen = sp->rxfrag_size;
-
-       skb_put(skb, framelen);
-       skb->protocol = eth_type_trans(skb, dev);
-       skb_checksum_none_assert(skb);
-       netif_rx(skb);
-       sp->rx_buff[entry] = NULL;
-}
-
-static void ipg_nic_rx_with_start(struct net_device *dev,
-                                 struct ipg_nic_private *sp,
-                                 struct ipg_rx *rxfd, unsigned entry)
-{
-       struct ipg_jumbo *jumbo = &sp->jumbo;
-       struct pci_dev *pdev = sp->pdev;
-       struct sk_buff *skb;
-
-       /* 1: found error, 0 no error */
-       if (ipg_nic_rx_check_error(dev) != NORMAL_PACKET)
-               return;
-
-       /* accept this frame and send to upper layer */
-       skb = sp->rx_buff[entry];
-       if (!skb)
-               return;
-
-       if (jumbo->found_start)
-               dev_kfree_skb_irq(jumbo->skb);
-
-       pci_unmap_single(pdev, le64_to_cpu(rxfd->frag_info) & ~IPG_RFI_FRAGLEN,
-                        sp->rx_buf_sz, PCI_DMA_FROMDEVICE);
-
-       skb_put(skb, sp->rxfrag_size);
-
-       jumbo->found_start = 1;
-       jumbo->current_size = sp->rxfrag_size;
-       jumbo->skb = skb;
-
-       sp->rx_buff[entry] = NULL;
-}
-
-static void ipg_nic_rx_with_end(struct net_device *dev,
-                               struct ipg_nic_private *sp,
-                               struct ipg_rx *rxfd, unsigned entry)
-{
-       struct ipg_jumbo *jumbo = &sp->jumbo;
-
-       /* 1: found error, 0 no error */
-       if (ipg_nic_rx_check_error(dev) == NORMAL_PACKET) {
-               struct sk_buff *skb = sp->rx_buff[entry];
-
-               if (!skb)
-                       return;
-
-               if (jumbo->found_start) {
-                       int framelen, endframelen;
-
-                       framelen = le64_to_cpu(rxfd->rfs) & IPG_RFS_RXFRAMELEN;
-
-                       endframelen = framelen - jumbo->current_size;
-                       if (framelen > sp->rxsupport_size)
-                               dev_kfree_skb_irq(jumbo->skb);
-                       else {
-                               memcpy(skb_put(jumbo->skb, endframelen),
-                                      skb->data, endframelen);
-
-                               jumbo->skb->protocol =
-                                   eth_type_trans(jumbo->skb, dev);
-
-                               skb_checksum_none_assert(jumbo->skb);
-                               netif_rx(jumbo->skb);
-                       }
-               }
-
-               jumbo->found_start = 0;
-               jumbo->current_size = 0;
-               jumbo->skb = NULL;
-
-               ipg_nic_rx_free_skb(dev);
-       } else {
-               dev_kfree_skb_irq(jumbo->skb);
-               jumbo->found_start = 0;
-               jumbo->current_size = 0;
-               jumbo->skb = NULL;
-       }
-}
-
-static void ipg_nic_rx_no_start_no_end(struct net_device *dev,
-                                      struct ipg_nic_private *sp,
-                                      struct ipg_rx *rxfd, unsigned entry)
-{
-       struct ipg_jumbo *jumbo = &sp->jumbo;
-
-       /* 1: found error, 0 no error */
-       if (ipg_nic_rx_check_error(dev) == NORMAL_PACKET) {
-               struct sk_buff *skb = sp->rx_buff[entry];
-
-               if (skb) {
-                       if (jumbo->found_start) {
-                               jumbo->current_size += sp->rxfrag_size;
-                               if (jumbo->current_size <= sp->rxsupport_size) {
-                                       memcpy(skb_put(jumbo->skb,
-                                                      sp->rxfrag_size),
-                                              skb->data, sp->rxfrag_size);
-                               }
-                       }
-                       ipg_nic_rx_free_skb(dev);
-               }
-       } else {
-               dev_kfree_skb_irq(jumbo->skb);
-               jumbo->found_start = 0;
-               jumbo->current_size = 0;
-               jumbo->skb = NULL;
-       }
-}
-
-static int ipg_nic_rx_jumbo(struct net_device *dev)
-{
-       struct ipg_nic_private *sp = netdev_priv(dev);
-       unsigned int curr = sp->rx_current;
-       void __iomem *ioaddr = sp->ioaddr;
-       unsigned int i;
-
-       IPG_DEBUG_MSG("_nic_rx\n");
-
-       for (i = 0; i < IPG_MAXRFDPROCESS_COUNT; i++, curr++) {
-               unsigned int entry = curr % IPG_RFDLIST_LENGTH;
-               struct ipg_rx *rxfd = sp->rxd + entry;
-
-               if (!(rxfd->rfs & cpu_to_le64(IPG_RFS_RFDDONE)))
-                       break;
-
-               switch (ipg_nic_rx_check_frame_type(dev)) {
-               case FRAME_WITH_START_WITH_END:
-                       ipg_nic_rx_with_start_and_end(dev, sp, rxfd, entry);
-                       break;
-               case FRAME_WITH_START:
-                       ipg_nic_rx_with_start(dev, sp, rxfd, entry);
-                       break;
-               case FRAME_WITH_END:
-                       ipg_nic_rx_with_end(dev, sp, rxfd, entry);
-                       break;
-               case FRAME_NO_START_NO_END:
-                       ipg_nic_rx_no_start_no_end(dev, sp, rxfd, entry);
-                       break;
-               }
-       }
-
-       sp->rx_current = curr;
-
-       if (i == IPG_MAXRFDPROCESS_COUNT) {
-               /* There are more RFDs to process, however the
-                * allocated amount of RFD processing time has
-                * expired. Assert Interrupt Requested to make
-                * sure we come back to process the remaining RFDs.
-                */
-               ipg_w32(ipg_r32(ASIC_CTRL) | IPG_AC_INT_REQUEST, ASIC_CTRL);
-       }
-
-       ipg_nic_rxrestore(dev);
-
-       return 0;
-}
-
-static int ipg_nic_rx(struct net_device *dev)
-{
-       /* Transfer received Ethernet frames to higher network layers. */
-       struct ipg_nic_private *sp = netdev_priv(dev);
-       unsigned int curr = sp->rx_current;
-       void __iomem *ioaddr = sp->ioaddr;
-       struct ipg_rx *rxfd;
-       unsigned int i;
-
-       IPG_DEBUG_MSG("_nic_rx\n");
-
-#define __RFS_MASK \
-       cpu_to_le64(IPG_RFS_RFDDONE | IPG_RFS_FRAMESTART | IPG_RFS_FRAMEEND)
-
-       for (i = 0; i < IPG_MAXRFDPROCESS_COUNT; i++, curr++) {
-               unsigned int entry = curr % IPG_RFDLIST_LENGTH;
-               struct sk_buff *skb = sp->rx_buff[entry];
-               unsigned int framelen;
-
-               rxfd = sp->rxd + entry;
-
-               if (((rxfd->rfs & __RFS_MASK) != __RFS_MASK) || !skb)
-                       break;
-
-               /* Get received frame length. */
-               framelen = le64_to_cpu(rxfd->rfs) & IPG_RFS_RXFRAMELEN;
-
-               /* Check for jumbo frame arrival with too small
-                * RXFRAG_SIZE.
-                */
-               if (framelen > sp->rxfrag_size) {
-                       IPG_DEBUG_MSG
-                           ("RFS FrameLen > allocated fragment size\n");
-
-                       framelen = sp->rxfrag_size;
-               }
-
-               if ((IPG_DROP_ON_RX_ETH_ERRORS && (le64_to_cpu(rxfd->rfs) &
-                      (IPG_RFS_RXFIFOOVERRUN | IPG_RFS_RXRUNTFRAME |
-                       IPG_RFS_RXALIGNMENTERROR | IPG_RFS_RXFCSERROR |
-                       IPG_RFS_RXOVERSIZEDFRAME | IPG_RFS_RXLENGTHERROR)))) {
-
-                       IPG_DEBUG_MSG("Rx error, RFS = %016lx\n",
-                                     (unsigned long int) rxfd->rfs);
-
-                       /* Increment general receive error statistic. */
-                       sp->stats.rx_errors++;
-
-                       /* Increment detailed receive error statistics. */
-                       if (le64_to_cpu(rxfd->rfs) & IPG_RFS_RXFIFOOVERRUN) {
-                               IPG_DEBUG_MSG("RX FIFO overrun occurred\n");
-                               sp->stats.rx_fifo_errors++;
-                       }
-
-                       if (le64_to_cpu(rxfd->rfs) & IPG_RFS_RXRUNTFRAME) {
-                               IPG_DEBUG_MSG("RX runt occurred\n");
-                               sp->stats.rx_length_errors++;
-                       }
-
-                       if (le64_to_cpu(rxfd->rfs) & IPG_RFS_RXOVERSIZEDFRAME) ;
-                       /* Do nothing, error count handled by a IPG
-                        * statistic register.
-                        */
-
-                       if (le64_to_cpu(rxfd->rfs) & IPG_RFS_RXALIGNMENTERROR) {
-                               IPG_DEBUG_MSG("RX alignment error occurred\n");
-                               sp->stats.rx_frame_errors++;
-                       }
-
-                       if (le64_to_cpu(rxfd->rfs) & IPG_RFS_RXFCSERROR) ;
-                       /* Do nothing, error count handled by a IPG
-                        * statistic register.
-                        */
-
-                       /* Free the memory associated with the RX
-                        * buffer since it is erroneous and we will
-                        * not pass it to higher layer processes.
-                        */
-                       if (skb) {
-                               __le64 info = rxfd->frag_info;
-
-                               pci_unmap_single(sp->pdev,
-                                       le64_to_cpu(info) & ~IPG_RFI_FRAGLEN,
-                                       sp->rx_buf_sz, PCI_DMA_FROMDEVICE);
-
-                               dev_kfree_skb_irq(skb);
-                       }
-               } else {
-
-                       /* Adjust the new buffer length to accommodate the size
-                        * of the received frame.
-                        */
-                       skb_put(skb, framelen);
-
-                       /* Set the buffer's protocol field to Ethernet. */
-                       skb->protocol = eth_type_trans(skb, dev);
-
-                       /* The IPG encountered an error with (or
-                        * there were no) IP/TCP/UDP checksums.
-                        * This may or may not indicate an invalid
-                        * IP/TCP/UDP frame was received. Let the
-                        * upper layer decide.
-                        */
-                       skb_checksum_none_assert(skb);
-
-                       /* Hand off frame for higher layer processing.
-                        * The function netif_rx() releases the sk_buff
-                        * when processing completes.
-                        */
-                       netif_rx(skb);
-               }
-
-               /* Assure RX buffer is not reused by IPG. */
-               sp->rx_buff[entry] = NULL;
-       }
-
-       /*
-        * If there are more RFDs to process and the allocated amount of RFD
-        * processing time has expired, assert Interrupt Requested to make
-        * sure we come back to process the remaining RFDs.
-        */
-       if (i == IPG_MAXRFDPROCESS_COUNT)
-               ipg_w32(ipg_r32(ASIC_CTRL) | IPG_AC_INT_REQUEST, ASIC_CTRL);
-
-#ifdef IPG_DEBUG
-       /* Check if the RFD list contained no receive frame data. */
-       if (!i)
-               sp->EmptyRFDListCount++;
-#endif
-       while ((le64_to_cpu(rxfd->rfs) & IPG_RFS_RFDDONE) &&
-              !((le64_to_cpu(rxfd->rfs) & IPG_RFS_FRAMESTART) &&
-                (le64_to_cpu(rxfd->rfs) & IPG_RFS_FRAMEEND))) {
-               unsigned int entry = curr++ % IPG_RFDLIST_LENGTH;
-
-               rxfd = sp->rxd + entry;
-
-               IPG_DEBUG_MSG("Frame requires multiple RFDs\n");
-
-               /* An unexpected event, additional code needed to handle
-                * properly. So for the time being, just disregard the
-                * frame.
-                */
-
-               /* Free the memory associated with the RX
-                * buffer since it is erroneous and we will
-                * not pass it to higher layer processes.
-                */
-               if (sp->rx_buff[entry]) {
-                       pci_unmap_single(sp->pdev,
-                               le64_to_cpu(rxfd->frag_info) & ~IPG_RFI_FRAGLEN,
-                               sp->rx_buf_sz, PCI_DMA_FROMDEVICE);
-                       dev_kfree_skb_irq(sp->rx_buff[entry]);
-               }
-
-               /* Assure RX buffer is not reused by IPG. */
-               sp->rx_buff[entry] = NULL;
-       }
-
-       sp->rx_current = curr;
-
-       /* Check to see if there are a minimum number of used
-        * RFDs before restoring any (should improve performance.)
-        */
-       if ((curr - sp->rx_dirty) >= IPG_MINUSEDRFDSTOFREE)
-               ipg_nic_rxrestore(dev);
-
-       return 0;
-}
-
-static void ipg_reset_after_host_error(struct work_struct *work)
-{
-       struct ipg_nic_private *sp =
-               container_of(work, struct ipg_nic_private, task.work);
-       struct net_device *dev = sp->dev;
-
-       /*
-        * Acknowledge HostError interrupt by resetting
-        * IPG DMA and HOST.
-        */
-       ipg_reset(dev, IPG_AC_GLOBAL_RESET | IPG_AC_HOST | IPG_AC_DMA);
-
-       init_rfdlist(dev);
-       init_tfdlist(dev);
-
-       if (ipg_io_config(dev) < 0) {
-               netdev_info(dev, "Cannot recover from PCI error\n");
-               schedule_delayed_work(&sp->task, HZ);
-       }
-}
-
-static irqreturn_t ipg_interrupt_handler(int irq, void *dev_inst)
-{
-       struct net_device *dev = dev_inst;
-       struct ipg_nic_private *sp = netdev_priv(dev);
-       void __iomem *ioaddr = sp->ioaddr;
-       unsigned int handled = 0;
-       u16 status;
-
-       IPG_DEBUG_MSG("_interrupt_handler\n");
-
-       if (sp->is_jumbo)
-               ipg_nic_rxrestore(dev);
-
-       spin_lock(&sp->lock);
-
-       /* Get interrupt source information, and acknowledge
-        * some (i.e. TxDMAComplete, RxDMAComplete, RxEarly,
-        * IntRequested, MacControlFrame, LinkEvent) interrupts
-        * if issued. Also, all IPG interrupts are disabled by
-        * reading IntStatusAck.
-        */
-       status = ipg_r16(INT_STATUS_ACK);
-
-       IPG_DEBUG_MSG("IntStatusAck = %04x\n", status);
-
-       /* Shared IRQ of remove event. */
-       if (!(status & IPG_IS_RSVD_MASK))
-               goto out_enable;
-
-       handled = 1;
-
-       if (unlikely(!netif_running(dev)))
-               goto out_unlock;
-
-       /* If RFDListEnd interrupt, restore all used RFDs. */
-       if (status & IPG_IS_RFD_LIST_END) {
-               IPG_DEBUG_MSG("RFDListEnd Interrupt\n");
-
-               /* The RFD list end indicates an RFD was encountered
-                * with a 0 NextPtr, or with an RFDDone bit set to 1
-                * (indicating the RFD is not read for use by the
-                * IPG.) Try to restore all RFDs.
-                */
-               ipg_nic_rxrestore(dev);
-
-#ifdef IPG_DEBUG
-               /* Increment the RFDlistendCount counter. */
-               sp->RFDlistendCount++;
-#endif
-       }
-
-       /* If RFDListEnd, RxDMAPriority, RxDMAComplete, or
-        * IntRequested interrupt, process received frames. */
-       if ((status & IPG_IS_RX_DMA_PRIORITY) ||
-           (status & IPG_IS_RFD_LIST_END) ||
-           (status & IPG_IS_RX_DMA_COMPLETE) ||
-           (status & IPG_IS_INT_REQUESTED)) {
-#ifdef IPG_DEBUG
-               /* Increment the RFD list checked counter if interrupted
-                * only to check the RFD list. */
-               if (status & (~(IPG_IS_RX_DMA_PRIORITY | IPG_IS_RFD_LIST_END |
-                               IPG_IS_RX_DMA_COMPLETE | IPG_IS_INT_REQUESTED) &
-                              (IPG_IS_HOST_ERROR | IPG_IS_TX_DMA_COMPLETE |
-                               IPG_IS_LINK_EVENT | IPG_IS_TX_COMPLETE |
-                               IPG_IS_UPDATE_STATS)))
-                       sp->RFDListCheckedCount++;
-#endif
-
-               if (sp->is_jumbo)
-                       ipg_nic_rx_jumbo(dev);
-               else
-                       ipg_nic_rx(dev);
-       }
-
-       /* If TxDMAComplete interrupt, free used TFDs. */
-       if (status & IPG_IS_TX_DMA_COMPLETE)
-               ipg_nic_txfree(dev);
-
-       /* TxComplete interrupts indicate one of numerous actions.
-        * Determine what action to take based on TXSTATUS register.
-        */
-       if (status & IPG_IS_TX_COMPLETE)
-               ipg_nic_txcleanup(dev);
-
-       /* If UpdateStats interrupt, update Linux Ethernet statistics */
-       if (status & IPG_IS_UPDATE_STATS)
-               ipg_nic_get_stats(dev);
-
-       /* If HostError interrupt, reset IPG. */
-       if (status & IPG_IS_HOST_ERROR) {
-               IPG_DDEBUG_MSG("HostError Interrupt\n");
-
-               schedule_delayed_work(&sp->task, 0);
-       }
-
-       /* If LinkEvent interrupt, resolve autonegotiation. */
-       if (status & IPG_IS_LINK_EVENT) {
-               if (ipg_config_autoneg(dev) < 0)
-                       netdev_info(dev, "Auto-negotiation error\n");
-       }
-
-       /* If MACCtrlFrame interrupt, do nothing. */
-       if (status & IPG_IS_MAC_CTRL_FRAME)
-               IPG_DEBUG_MSG("MACCtrlFrame interrupt\n");
-
-       /* If RxComplete interrupt, do nothing. */
-       if (status & IPG_IS_RX_COMPLETE)
-               IPG_DEBUG_MSG("RxComplete interrupt\n");
-
-       /* If RxEarly interrupt, do nothing. */
-       if (status & IPG_IS_RX_EARLY)
-               IPG_DEBUG_MSG("RxEarly interrupt\n");
-
-out_enable:
-       /* Re-enable IPG interrupts. */
-       ipg_w16(IPG_IE_TX_DMA_COMPLETE | IPG_IE_RX_DMA_COMPLETE |
-               IPG_IE_HOST_ERROR | IPG_IE_INT_REQUESTED | IPG_IE_TX_COMPLETE |
-               IPG_IE_LINK_EVENT | IPG_IE_UPDATE_STATS, INT_ENABLE);
-out_unlock:
-       spin_unlock(&sp->lock);
-
-       return IRQ_RETVAL(handled);
-}
-
-static void ipg_rx_clear(struct ipg_nic_private *sp)
-{
-       unsigned int i;
-
-       for (i = 0; i < IPG_RFDLIST_LENGTH; i++) {
-               if (sp->rx_buff[i]) {
-                       struct ipg_rx *rxfd = sp->rxd + i;
-
-                       dev_kfree_skb_irq(sp->rx_buff[i]);
-                       sp->rx_buff[i] = NULL;
-                       pci_unmap_single(sp->pdev,
-                               le64_to_cpu(rxfd->frag_info) & ~IPG_RFI_FRAGLEN,
-                               sp->rx_buf_sz, PCI_DMA_FROMDEVICE);
-               }
-       }
-}
-
-static void ipg_tx_clear(struct ipg_nic_private *sp)
-{
-       unsigned int i;
-
-       for (i = 0; i < IPG_TFDLIST_LENGTH; i++) {
-               if (sp->tx_buff[i]) {
-                       struct ipg_tx *txfd = sp->txd + i;
-
-                       pci_unmap_single(sp->pdev,
-                               le64_to_cpu(txfd->frag_info) & ~IPG_TFI_FRAGLEN,
-                               sp->tx_buff[i]->len, PCI_DMA_TODEVICE);
-
-                       dev_kfree_skb_irq(sp->tx_buff[i]);
-
-                       sp->tx_buff[i] = NULL;
-               }
-       }
-}
-
-static int ipg_nic_open(struct net_device *dev)
-{
-       struct ipg_nic_private *sp = netdev_priv(dev);
-       void __iomem *ioaddr = sp->ioaddr;
-       struct pci_dev *pdev = sp->pdev;
-       int rc;
-
-       IPG_DEBUG_MSG("_nic_open\n");
-
-       sp->rx_buf_sz = sp->rxsupport_size;
-
-       /* Check for interrupt line conflicts, and request interrupt
-        * line for IPG.
-        *
-        * IMPORTANT: Disable IPG interrupts prior to registering
-        *            IRQ.
-        */
-       ipg_w16(0x0000, INT_ENABLE);
-
-       /* Register the interrupt line to be used by the IPG within
-        * the Linux system.
-        */
-       rc = request_irq(pdev->irq, ipg_interrupt_handler, IRQF_SHARED,
-                        dev->name, dev);
-       if (rc < 0) {
-               netdev_info(dev, "Error when requesting interrupt\n");
-               goto out;
-       }
-
-       dev->irq = pdev->irq;
-
-       rc = -ENOMEM;
-
-       sp->rxd = dma_alloc_coherent(&pdev->dev, IPG_RX_RING_BYTES,
-                                    &sp->rxd_map, GFP_KERNEL);
-       if (!sp->rxd)
-               goto err_free_irq_0;
-
-       sp->txd = dma_alloc_coherent(&pdev->dev, IPG_TX_RING_BYTES,
-                                    &sp->txd_map, GFP_KERNEL);
-       if (!sp->txd)
-               goto err_free_rx_1;
-
-       rc = init_rfdlist(dev);
-       if (rc < 0) {
-               netdev_info(dev, "Error during configuration\n");
-               goto err_free_tx_2;
-       }
-
-       init_tfdlist(dev);
-
-       rc = ipg_io_config(dev);
-       if (rc < 0) {
-               netdev_info(dev, "Error during configuration\n");
-               goto err_release_tfdlist_3;
-       }
-
-       /* Resolve autonegotiation. */
-       if (ipg_config_autoneg(dev) < 0)
-               netdev_info(dev, "Auto-negotiation error\n");
-
-       /* initialize JUMBO Frame control variable */
-       sp->jumbo.found_start = 0;
-       sp->jumbo.current_size = 0;
-       sp->jumbo.skb = NULL;
-
-       /* Enable transmit and receive operation of the IPG. */
-       ipg_w32((ipg_r32(MAC_CTRL) | IPG_MC_RX_ENABLE | IPG_MC_TX_ENABLE) &
-                IPG_MC_RSVD_MASK, MAC_CTRL);
-
-       netif_start_queue(dev);
-out:
-       return rc;
-
-err_release_tfdlist_3:
-       ipg_tx_clear(sp);
-       ipg_rx_clear(sp);
-err_free_tx_2:
-       dma_free_coherent(&pdev->dev, IPG_TX_RING_BYTES, sp->txd, sp->txd_map);
-err_free_rx_1:
-       dma_free_coherent(&pdev->dev, IPG_RX_RING_BYTES, sp->rxd, sp->rxd_map);
-err_free_irq_0:
-       free_irq(pdev->irq, dev);
-       goto out;
-}
-
-static int ipg_nic_stop(struct net_device *dev)
-{
-       struct ipg_nic_private *sp = netdev_priv(dev);
-       void __iomem *ioaddr = sp->ioaddr;
-       struct pci_dev *pdev = sp->pdev;
-
-       IPG_DEBUG_MSG("_nic_stop\n");
-
-       netif_stop_queue(dev);
-
-       IPG_DUMPTFDLIST(dev);
-
-       do {
-               (void) ipg_r16(INT_STATUS_ACK);
-
-               ipg_reset(dev, IPG_AC_GLOBAL_RESET | IPG_AC_HOST | IPG_AC_DMA);
-
-               synchronize_irq(pdev->irq);
-       } while (ipg_r16(INT_ENABLE) & IPG_IE_RSVD_MASK);
-
-       ipg_rx_clear(sp);
-
-       ipg_tx_clear(sp);
-
-       pci_free_consistent(pdev, IPG_RX_RING_BYTES, sp->rxd, sp->rxd_map);
-       pci_free_consistent(pdev, IPG_TX_RING_BYTES, sp->txd, sp->txd_map);
-
-       free_irq(pdev->irq, dev);
-
-       return 0;
-}
-
-static netdev_tx_t ipg_nic_hard_start_xmit(struct sk_buff *skb,
-                                          struct net_device *dev)
-{
-       struct ipg_nic_private *sp = netdev_priv(dev);
-       void __iomem *ioaddr = sp->ioaddr;
-       unsigned int entry = sp->tx_current % IPG_TFDLIST_LENGTH;
-       unsigned long flags;
-       struct ipg_tx *txfd;
-
-       IPG_DDEBUG_MSG("_nic_hard_start_xmit\n");
-
-       /* If in 10Mbps mode, stop the transmit queue so
-        * no more transmit frames are accepted.
-        */
-       if (sp->tenmbpsmode)
-               netif_stop_queue(dev);
-
-       if (sp->reset_current_tfd) {
-               sp->reset_current_tfd = 0;
-               entry = 0;
-       }
-
-       txfd = sp->txd + entry;
-
-       sp->tx_buff[entry] = skb;
-
-       /* Clear all TFC fields, except TFDDONE. */
-       txfd->tfc = cpu_to_le64(IPG_TFC_TFDDONE);
-
-       /* Specify the TFC field within the TFD. */
-       txfd->tfc |= cpu_to_le64(IPG_TFC_WORDALIGNDISABLED |
-               (IPG_TFC_FRAMEID & sp->tx_current) |
-               (IPG_TFC_FRAGCOUNT & (1 << 24)));
-       /*
-        * 16--17 (WordAlign) <- 3 (disable),
-        * 0--15 (FrameId) <- sp->tx_current,
-        * 24--27 (FragCount) <- 1
-        */
-
-       /* Request TxComplete interrupts at an interval defined
-        * by the constant IPG_FRAMESBETWEENTXCOMPLETES.
-        * Request TxComplete interrupt for every frame
-        * if in 10Mbps mode to accommodate problem with 10Mbps
-        * processing.
-        */
-       if (sp->tenmbpsmode)
-               txfd->tfc |= cpu_to_le64(IPG_TFC_TXINDICATE);
-       txfd->tfc |= cpu_to_le64(IPG_TFC_TXDMAINDICATE);
-       /* Based on compilation option, determine if FCS is to be
-        * appended to transmit frame by IPG.
-        */
-       if (!(IPG_APPEND_FCS_ON_TX))
-               txfd->tfc |= cpu_to_le64(IPG_TFC_FCSAPPENDDISABLE);
-
-       /* Based on compilation option, determine if IP, TCP and/or
-        * UDP checksums are to be added to transmit frame by IPG.
-        */
-       if (IPG_ADD_IPCHECKSUM_ON_TX)
-               txfd->tfc |= cpu_to_le64(IPG_TFC_IPCHECKSUMENABLE);
-
-       if (IPG_ADD_TCPCHECKSUM_ON_TX)
-               txfd->tfc |= cpu_to_le64(IPG_TFC_TCPCHECKSUMENABLE);
-
-       if (IPG_ADD_UDPCHECKSUM_ON_TX)
-               txfd->tfc |= cpu_to_le64(IPG_TFC_UDPCHECKSUMENABLE);
-
-       /* Based on compilation option, determine if VLAN tag info is to be
-        * inserted into transmit frame by IPG.
-        */
-       if (IPG_INSERT_MANUAL_VLAN_TAG) {
-               txfd->tfc |= cpu_to_le64(IPG_TFC_VLANTAGINSERT |
-                       ((u64) IPG_MANUAL_VLAN_VID << 32) |
-                       ((u64) IPG_MANUAL_VLAN_CFI << 44) |
-                       ((u64) IPG_MANUAL_VLAN_USERPRIORITY << 45));
-       }
-
-       /* The fragment start location within system memory is defined
-        * by the sk_buff structure's data field. The physical address
-        * of this location within the system's virtual memory space
-        * is determined using the IPG_HOST2BUS_MAP function.
-        */
-       txfd->frag_info = cpu_to_le64(pci_map_single(sp->pdev, skb->data,
-               skb->len, PCI_DMA_TODEVICE));
-
-       /* The length of the fragment within system memory is defined by
-        * the sk_buff structure's len field.
-        */
-       txfd->frag_info |= cpu_to_le64(IPG_TFI_FRAGLEN &
-               ((u64) (skb->len & 0xffff) << 48));
-
-       /* Clear the TFDDone bit last to indicate the TFD is ready
-        * for transfer to the IPG.
-        */
-       txfd->tfc &= cpu_to_le64(~IPG_TFC_TFDDONE);
-
-       spin_lock_irqsave(&sp->lock, flags);
-
-       sp->tx_current++;
-
-       mmiowb();
-
-       ipg_w32(IPG_DC_TX_DMA_POLL_NOW, DMA_CTRL);
-
-       if (sp->tx_current == (sp->tx_dirty + IPG_TFDLIST_LENGTH))
-               netif_stop_queue(dev);
-
-       spin_unlock_irqrestore(&sp->lock, flags);
-
-       return NETDEV_TX_OK;
-}
-
-static void ipg_set_phy_default_param(unsigned char rev,
-                                     struct net_device *dev, int phy_address)
-{
-       unsigned short length;
-       unsigned char revision;
-       const unsigned short *phy_param;
-       unsigned short address, value;
-
-       phy_param = &DefaultPhyParam[0];
-       length = *phy_param & 0x00FF;
-       revision = (unsigned char)((*phy_param) >> 8);
-       phy_param++;
-       while (length != 0) {
-               if (rev == revision) {
-                       while (length > 1) {
-                               address = *phy_param;
-                               value = *(phy_param + 1);
-                               phy_param += 2;
-                               mdio_write(dev, phy_address, address, value);
-                               length -= 4;
-                       }
-                       break;
-               } else {
-                       phy_param += length / 2;
-                       length = *phy_param & 0x00FF;
-                       revision = (unsigned char)((*phy_param) >> 8);
-                       phy_param++;
-               }
-       }
-}
-
-static int read_eeprom(struct net_device *dev, int eep_addr)
-{
-       void __iomem *ioaddr = ipg_ioaddr(dev);
-       unsigned int i;
-       int ret = 0;
-       u16 value;
-
-       value = IPG_EC_EEPROM_READOPCODE | (eep_addr & 0xff);
-       ipg_w16(value, EEPROM_CTRL);
-
-       for (i = 0; i < 1000; i++) {
-               u16 data;
-
-               mdelay(10);
-               data = ipg_r16(EEPROM_CTRL);
-               if (!(data & IPG_EC_EEPROM_BUSY)) {
-                       ret = ipg_r16(EEPROM_DATA);
-                       break;
-               }
-       }
-       return ret;
-}
-
-static void ipg_init_mii(struct net_device *dev)
-{
-       struct ipg_nic_private *sp = netdev_priv(dev);
-       struct mii_if_info *mii_if = &sp->mii_if;
-       int phyaddr;
-
-       mii_if->dev          = dev;
-       mii_if->mdio_read    = mdio_read;
-       mii_if->mdio_write   = mdio_write;
-       mii_if->phy_id_mask  = 0x1f;
-       mii_if->reg_num_mask = 0x1f;
-
-       mii_if->phy_id = phyaddr = ipg_find_phyaddr(dev);
-
-       if (phyaddr != 0x1f) {
-               u16 mii_phyctrl, mii_1000cr;
-
-               mii_1000cr  = mdio_read(dev, phyaddr, MII_CTRL1000);
-               mii_1000cr |= ADVERTISE_1000FULL | ADVERTISE_1000HALF |
-                       GMII_PHY_1000BASETCONTROL_PreferMaster;
-               mdio_write(dev, phyaddr, MII_CTRL1000, mii_1000cr);
-
-               mii_phyctrl = mdio_read(dev, phyaddr, MII_BMCR);
-
-               /* Set default phyparam */
-               ipg_set_phy_default_param(sp->pdev->revision, dev, phyaddr);
-
-               /* Reset PHY */
-               mii_phyctrl |= BMCR_RESET | BMCR_ANRESTART;
-               mdio_write(dev, phyaddr, MII_BMCR, mii_phyctrl);
-
-       }
-}
-
-static int ipg_hw_init(struct net_device *dev)
-{
-       struct ipg_nic_private *sp = netdev_priv(dev);
-       void __iomem *ioaddr = sp->ioaddr;
-       unsigned int i;
-       int rc;
-
-       /* Read/Write and Reset EEPROM Value */
-       /* Read LED Mode Configuration from EEPROM */
-       sp->led_mode = read_eeprom(dev, 6);
-
-       /* Reset all functions within the IPG. Do not assert
-        * RST_OUT as not compatible with some PHYs.
-        */
-       rc = ipg_reset(dev, IPG_RESET_MASK);
-       if (rc < 0)
-               goto out;
-
-       ipg_init_mii(dev);
-
-       /* Read MAC Address from EEPROM */
-       for (i = 0; i < 3; i++)
-               sp->station_addr[i] = read_eeprom(dev, 16 + i);
-
-       for (i = 0; i < 3; i++)
-               ipg_w16(sp->station_addr[i], STATION_ADDRESS_0 + 2*i);
-
-       /* Set station address in ethernet_device structure. */
-       dev->dev_addr[0] =  ipg_r16(STATION_ADDRESS_0) & 0x00ff;
-       dev->dev_addr[1] = (ipg_r16(STATION_ADDRESS_0) & 0xff00) >> 8;
-       dev->dev_addr[2] =  ipg_r16(STATION_ADDRESS_1) & 0x00ff;
-       dev->dev_addr[3] = (ipg_r16(STATION_ADDRESS_1) & 0xff00) >> 8;
-       dev->dev_addr[4] =  ipg_r16(STATION_ADDRESS_2) & 0x00ff;
-       dev->dev_addr[5] = (ipg_r16(STATION_ADDRESS_2) & 0xff00) >> 8;
-out:
-       return rc;
-}
-
-static int ipg_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
-{
-       struct ipg_nic_private *sp = netdev_priv(dev);
-       int rc;
-
-       mutex_lock(&sp->mii_mutex);
-       rc = generic_mii_ioctl(&sp->mii_if, if_mii(ifr), cmd, NULL);
-       mutex_unlock(&sp->mii_mutex);
-
-       return rc;
-}
-
-static int ipg_nic_change_mtu(struct net_device *dev, int new_mtu)
-{
-       struct ipg_nic_private *sp = netdev_priv(dev);
-       int err;
-
-       /* Function to accommodate changes to Maximum Transfer Unit
-        * (or MTU) of IPG NIC. Cannot use default function since
-        * the default will not allow for MTU > 1500 bytes.
-        */
-
-       IPG_DEBUG_MSG("_nic_change_mtu\n");
-
-       /*
-        * Check that the new MTU value is between 68 (14 byte header, 46 byte
-        * payload, 4 byte FCS) and 10 KB, which is the largest supported MTU.
-        */
-       if (new_mtu < 68 || new_mtu > 10240)
-               return -EINVAL;
-
-       err = ipg_nic_stop(dev);
-       if (err)
-               return err;
-
-       dev->mtu = new_mtu;
-
-       sp->max_rxframe_size = new_mtu;
-
-       sp->rxfrag_size = new_mtu;
-       if (sp->rxfrag_size > 4088)
-               sp->rxfrag_size = 4088;
-
-       sp->rxsupport_size = sp->max_rxframe_size;
-
-       if (new_mtu > 0x0600)
-               sp->is_jumbo = true;
-       else
-               sp->is_jumbo = false;
-
-       return ipg_nic_open(dev);
-}
-
-static int ipg_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
-{
-       struct ipg_nic_private *sp = netdev_priv(dev);
-       int rc;
-
-       mutex_lock(&sp->mii_mutex);
-       rc = mii_ethtool_gset(&sp->mii_if, cmd);
-       mutex_unlock(&sp->mii_mutex);
-
-       return rc;
-}
-
-static int ipg_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
-{
-       struct ipg_nic_private *sp = netdev_priv(dev);
-       int rc;
-
-       mutex_lock(&sp->mii_mutex);
-       rc = mii_ethtool_sset(&sp->mii_if, cmd);
-       mutex_unlock(&sp->mii_mutex);
-
-       return rc;
-}
-
-static int ipg_nway_reset(struct net_device *dev)
-{
-       struct ipg_nic_private *sp = netdev_priv(dev);
-       int rc;
-
-       mutex_lock(&sp->mii_mutex);
-       rc = mii_nway_restart(&sp->mii_if);
-       mutex_unlock(&sp->mii_mutex);
-
-       return rc;
-}
-
-static const struct ethtool_ops ipg_ethtool_ops = {
-       .get_settings = ipg_get_settings,
-       .set_settings = ipg_set_settings,
-       .nway_reset   = ipg_nway_reset,
-};
-
-static void ipg_remove(struct pci_dev *pdev)
-{
-       struct net_device *dev = pci_get_drvdata(pdev);
-       struct ipg_nic_private *sp = netdev_priv(dev);
-
-       IPG_DEBUG_MSG("_remove\n");
-
-       /* Un-register Ethernet device. */
-       unregister_netdev(dev);
-
-       pci_iounmap(pdev, sp->ioaddr);
-
-       pci_release_regions(pdev);
-
-       free_netdev(dev);
-       pci_disable_device(pdev);
-}
-
-static const struct net_device_ops ipg_netdev_ops = {
-       .ndo_open               = ipg_nic_open,
-       .ndo_stop               = ipg_nic_stop,
-       .ndo_start_xmit         = ipg_nic_hard_start_xmit,
-       .ndo_get_stats          = ipg_nic_get_stats,
-       .ndo_set_rx_mode        = ipg_nic_set_multicast_list,
-       .ndo_do_ioctl           = ipg_ioctl,
-       .ndo_tx_timeout         = ipg_tx_timeout,
-       .ndo_change_mtu         = ipg_nic_change_mtu,
-       .ndo_set_mac_address    = eth_mac_addr,
-       .ndo_validate_addr      = eth_validate_addr,
-};
-
-static int ipg_probe(struct pci_dev *pdev, const struct pci_device_id *id)
-{
-       unsigned int i = id->driver_data;
-       struct ipg_nic_private *sp;
-       struct net_device *dev;
-       void __iomem *ioaddr;
-       int rc;
-
-       rc = pci_enable_device(pdev);
-       if (rc < 0)
-               goto out;
-
-       pr_info("%s: %s\n", pci_name(pdev), ipg_brand_name[i]);
-
-       pci_set_master(pdev);
-
-       rc = pci_set_dma_mask(pdev, DMA_BIT_MASK(40));
-       if (rc < 0) {
-               rc = pci_set_dma_mask(pdev, DMA_BIT_MASK(32));
-               if (rc < 0) {
-                       pr_err("%s: DMA config failed\n", pci_name(pdev));
-                       goto err_disable_0;
-               }
-       }
-
-       /*
-        * Initialize net device.
-        */
-       dev = alloc_etherdev(sizeof(struct ipg_nic_private));
-       if (!dev) {
-               rc = -ENOMEM;
-               goto err_disable_0;
-       }
-
-       sp = netdev_priv(dev);
-       spin_lock_init(&sp->lock);
-       mutex_init(&sp->mii_mutex);
-
-       sp->is_jumbo = IPG_IS_JUMBO;
-       sp->rxfrag_size = IPG_RXFRAG_SIZE;
-       sp->rxsupport_size = IPG_RXSUPPORT_SIZE;
-       sp->max_rxframe_size = IPG_MAX_RXFRAME_SIZE;
-
-       /* Declare IPG NIC functions for Ethernet device methods.
-        */
-       dev->netdev_ops = &ipg_netdev_ops;
-       SET_NETDEV_DEV(dev, &pdev->dev);
-       dev->ethtool_ops = &ipg_ethtool_ops;
-
-       rc = pci_request_regions(pdev, DRV_NAME);
-       if (rc)
-               goto err_free_dev_1;
-
-       ioaddr = pci_iomap(pdev, 1, pci_resource_len(pdev, 1));
-       if (!ioaddr) {
-               pr_err("%s: cannot map MMIO\n", pci_name(pdev));
-               rc = -EIO;
-               goto err_release_regions_2;
-       }
-
-       /* Save the pointer to the PCI device information. */
-       sp->ioaddr = ioaddr;
-       sp->pdev = pdev;
-       sp->dev = dev;
-
-       INIT_DELAYED_WORK(&sp->task, ipg_reset_after_host_error);
-
-       pci_set_drvdata(pdev, dev);
-
-       rc = ipg_hw_init(dev);
-       if (rc < 0)
-               goto err_unmap_3;
-
-       rc = register_netdev(dev);
-       if (rc < 0)
-               goto err_unmap_3;
-
-       netdev_info(dev, "Ethernet device registered\n");
-out:
-       return rc;
-
-err_unmap_3:
-       pci_iounmap(pdev, ioaddr);
-err_release_regions_2:
-       pci_release_regions(pdev);
-err_free_dev_1:
-       free_netdev(dev);
-err_disable_0:
-       pci_disable_device(pdev);
-       goto out;
-}
-
-static struct pci_driver ipg_pci_driver = {
-       .name           = IPG_DRIVER_NAME,
-       .id_table       = ipg_pci_tbl,
-       .probe          = ipg_probe,
-       .remove         = ipg_remove,
-};
-
-module_pci_driver(ipg_pci_driver);
diff --git a/drivers/net/ethernet/icplus/ipg.h b/drivers/net/ethernet/icplus/ipg.h
deleted file mode 100644 (file)
index de60628..0000000
+++ /dev/null
@@ -1,748 +0,0 @@
-/*
- * Include file for Gigabit Ethernet device driver for Network
- * Interface Cards (NICs) utilizing the Tamarack Microelectronics
- * Inc. IPG Gigabit or Triple Speed Ethernet Media Access
- * Controller.
- */
-#ifndef __LINUX_IPG_H
-#define __LINUX_IPG_H
-
-#include <linux/module.h>
-
-#include <linux/kernel.h>
-#include <linux/pci.h>
-#include <linux/ioport.h>
-#include <linux/errno.h>
-#include <asm/io.h>
-#include <linux/delay.h>
-#include <linux/types.h>
-#include <linux/netdevice.h>
-#include <linux/etherdevice.h>
-#include <linux/skbuff.h>
-#include <asm/bitops.h>
-
-/*
- *     Constants
- */
-
-/* GMII based PHY IDs */
-#define                NS                              0x2000
-#define                MARVELL                         0x0141
-#define                ICPLUS_PHY                      0x243
-
-/* NIC Physical Layer Device MII register fields. */
-#define         MII_PHY_SELECTOR_IEEE8023       0x0001
-#define         MII_PHY_TECHABILITYFIELD        0x1FE0
-
-/* GMII_PHY_1000 need to set to prefer master */
-#define         GMII_PHY_1000BASETCONTROL_PreferMaster 0x0400
-
-/* NIC Physical Layer Device GMII constants. */
-#define         GMII_PREAMBLE                    0xFFFFFFFF
-#define         GMII_ST                          0x1
-#define         GMII_READ                        0x2
-#define         GMII_WRITE                       0x1
-#define         GMII_TA_READ_MASK                0x1
-#define         GMII_TA_WRITE                    0x2
-
-/* I/O register offsets. */
-enum ipg_regs {
-       DMA_CTRL                = 0x00,
-       RX_DMA_STATUS           = 0x08, /* Unused + reserved */
-       TFD_LIST_PTR_0          = 0x10,
-       TFD_LIST_PTR_1          = 0x14,
-       TX_DMA_BURST_THRESH     = 0x18,
-       TX_DMA_URGENT_THRESH    = 0x19,
-       TX_DMA_POLL_PERIOD      = 0x1a,
-       RFD_LIST_PTR_0          = 0x1c,
-       RFD_LIST_PTR_1          = 0x20,
-       RX_DMA_BURST_THRESH     = 0x24,
-       RX_DMA_URGENT_THRESH    = 0x25,
-       RX_DMA_POLL_PERIOD      = 0x26,
-       DEBUG_CTRL              = 0x2c,
-       ASIC_CTRL               = 0x30,
-       FIFO_CTRL               = 0x38, /* Unused */
-       FLOW_OFF_THRESH         = 0x3c,
-       FLOW_ON_THRESH          = 0x3e,
-       EEPROM_DATA             = 0x48,
-       EEPROM_CTRL             = 0x4a,
-       EXPROM_ADDR             = 0x4c, /* Unused */
-       EXPROM_DATA             = 0x50, /* Unused */
-       WAKE_EVENT              = 0x51, /* Unused */
-       COUNTDOWN               = 0x54, /* Unused */
-       INT_STATUS_ACK          = 0x5a,
-       INT_ENABLE              = 0x5c,
-       INT_STATUS              = 0x5e, /* Unused */
-       TX_STATUS               = 0x60,
-       MAC_CTRL                = 0x6c,
-       VLAN_TAG                = 0x70, /* Unused */
-       PHY_SET                 = 0x75,
-       PHY_CTRL                = 0x76,
-       STATION_ADDRESS_0       = 0x78,
-       STATION_ADDRESS_1       = 0x7a,
-       STATION_ADDRESS_2       = 0x7c,
-       MAX_FRAME_SIZE          = 0x86,
-       RECEIVE_MODE            = 0x88,
-       HASHTABLE_0             = 0x8c,
-       HASHTABLE_1             = 0x90,
-       RMON_STATISTICS_MASK    = 0x98,
-       STATISTICS_MASK         = 0x9c,
-       RX_JUMBO_FRAMES         = 0xbc, /* Unused */
-       TCP_CHECKSUM_ERRORS     = 0xc0, /* Unused */
-       IP_CHECKSUM_ERRORS      = 0xc2, /* Unused */
-       UDP_CHECKSUM_ERRORS     = 0xc4, /* Unused */
-       TX_JUMBO_FRAMES         = 0xf4  /* Unused */
-};
-
-/* Ethernet MIB statistic register offsets. */
-#define        IPG_OCTETRCVOK                  0xA8
-#define        IPG_MCSTOCTETRCVDOK             0xAC
-#define        IPG_BCSTOCTETRCVOK              0xB0
-#define        IPG_FRAMESRCVDOK                0xB4
-#define        IPG_MCSTFRAMESRCVDOK            0xB8
-#define        IPG_BCSTFRAMESRCVDOK            0xBE
-#define        IPG_MACCONTROLFRAMESRCVD        0xC6
-#define        IPG_FRAMETOOLONGERRORS          0xC8
-#define        IPG_INRANGELENGTHERRORS         0xCA
-#define        IPG_FRAMECHECKSEQERRORS         0xCC
-#define        IPG_FRAMESLOSTRXERRORS          0xCE
-#define        IPG_OCTETXMTOK                  0xD0
-#define        IPG_MCSTOCTETXMTOK              0xD4
-#define        IPG_BCSTOCTETXMTOK              0xD8
-#define        IPG_FRAMESXMTDOK                0xDC
-#define        IPG_MCSTFRAMESXMTDOK            0xE0
-#define        IPG_FRAMESWDEFERREDXMT          0xE4
-#define        IPG_LATECOLLISIONS              0xE8
-#define        IPG_MULTICOLFRAMES              0xEC
-#define        IPG_SINGLECOLFRAMES             0xF0
-#define        IPG_BCSTFRAMESXMTDOK            0xF6
-#define        IPG_CARRIERSENSEERRORS          0xF8
-#define        IPG_MACCONTROLFRAMESXMTDOK      0xFA
-#define        IPG_FRAMESABORTXSCOLLS          0xFC
-#define        IPG_FRAMESWEXDEFERRAL           0xFE
-
-/* RMON statistic register offsets. */
-#define        IPG_ETHERSTATSCOLLISIONS                        0x100
-#define        IPG_ETHERSTATSOCTETSTRANSMIT                    0x104
-#define        IPG_ETHERSTATSPKTSTRANSMIT                      0x108
-#define        IPG_ETHERSTATSPKTS64OCTESTSTRANSMIT             0x10C
-#define        IPG_ETHERSTATSPKTS65TO127OCTESTSTRANSMIT        0x110
-#define        IPG_ETHERSTATSPKTS128TO255OCTESTSTRANSMIT       0x114
-#define        IPG_ETHERSTATSPKTS256TO511OCTESTSTRANSMIT       0x118
-#define        IPG_ETHERSTATSPKTS512TO1023OCTESTSTRANSMIT      0x11C
-#define        IPG_ETHERSTATSPKTS1024TO1518OCTESTSTRANSMIT     0x120
-#define        IPG_ETHERSTATSCRCALIGNERRORS                    0x124
-#define        IPG_ETHERSTATSUNDERSIZEPKTS                     0x128
-#define        IPG_ETHERSTATSFRAGMENTS                         0x12C
-#define        IPG_ETHERSTATSJABBERS                           0x130
-#define        IPG_ETHERSTATSOCTETS                            0x134
-#define        IPG_ETHERSTATSPKTS                              0x138
-#define        IPG_ETHERSTATSPKTS64OCTESTS                     0x13C
-#define        IPG_ETHERSTATSPKTS65TO127OCTESTS                0x140
-#define        IPG_ETHERSTATSPKTS128TO255OCTESTS               0x144
-#define        IPG_ETHERSTATSPKTS256TO511OCTESTS               0x148
-#define        IPG_ETHERSTATSPKTS512TO1023OCTESTS              0x14C
-#define        IPG_ETHERSTATSPKTS1024TO1518OCTESTS             0x150
-
-/* RMON statistic register equivalents. */
-#define        IPG_ETHERSTATSMULTICASTPKTSTRANSMIT             0xE0
-#define        IPG_ETHERSTATSBROADCASTPKTSTRANSMIT             0xF6
-#define        IPG_ETHERSTATSMULTICASTPKTS                     0xB8
-#define        IPG_ETHERSTATSBROADCASTPKTS                     0xBE
-#define        IPG_ETHERSTATSOVERSIZEPKTS                      0xC8
-#define        IPG_ETHERSTATSDROPEVENTS                        0xCE
-
-/* Serial EEPROM offsets */
-#define        IPG_EEPROM_CONFIGPARAM          0x00
-#define        IPG_EEPROM_ASICCTRL             0x01
-#define        IPG_EEPROM_SUBSYSTEMVENDORID    0x02
-#define        IPG_EEPROM_SUBSYSTEMID          0x03
-#define        IPG_EEPROM_STATIONADDRESS0      0x10
-#define        IPG_EEPROM_STATIONADDRESS1      0x11
-#define        IPG_EEPROM_STATIONADDRESS2      0x12
-
-/* Register & data structure bit masks */
-
-/* PCI register masks. */
-
-/* IOBaseAddress */
-#define         IPG_PIB_RSVD_MASK              0xFFFFFE01
-#define         IPG_PIB_IOBASEADDRESS          0xFFFFFF00
-#define         IPG_PIB_IOBASEADDRIND          0x00000001
-
-/* MemBaseAddress */
-#define         IPG_PMB_RSVD_MASK              0xFFFFFE07
-#define         IPG_PMB_MEMBASEADDRIND         0x00000001
-#define         IPG_PMB_MEMMAPTYPE             0x00000006
-#define         IPG_PMB_MEMMAPTYPE0            0x00000002
-#define         IPG_PMB_MEMMAPTYPE1            0x00000004
-#define         IPG_PMB_MEMBASEADDRESS         0xFFFFFE00
-
-/* ConfigStatus */
-#define IPG_CS_RSVD_MASK                0xFFB0
-#define IPG_CS_CAPABILITIES             0x0010
-#define IPG_CS_66MHZCAPABLE             0x0020
-#define IPG_CS_FASTBACK2BACK            0x0080
-#define IPG_CS_DATAPARITYREPORTED       0x0100
-#define IPG_CS_DEVSELTIMING             0x0600
-#define IPG_CS_SIGNALEDTARGETABORT      0x0800
-#define IPG_CS_RECEIVEDTARGETABORT      0x1000
-#define IPG_CS_RECEIVEDMASTERABORT      0x2000
-#define IPG_CS_SIGNALEDSYSTEMERROR      0x4000
-#define IPG_CS_DETECTEDPARITYERROR      0x8000
-
-/* TFD data structure masks. */
-
-/* TFDList, TFC */
-#define        IPG_TFC_RSVD_MASK                       0x0000FFFF9FFFFFFFULL
-#define        IPG_TFC_FRAMEID                         0x000000000000FFFFULL
-#define        IPG_TFC_WORDALIGN                       0x0000000000030000ULL
-#define        IPG_TFC_WORDALIGNTODWORD                0x0000000000000000ULL
-#define        IPG_TFC_WORDALIGNTOWORD                 0x0000000000020000ULL
-#define        IPG_TFC_WORDALIGNDISABLED               0x0000000000030000ULL
-#define        IPG_TFC_TCPCHECKSUMENABLE               0x0000000000040000ULL
-#define        IPG_TFC_UDPCHECKSUMENABLE               0x0000000000080000ULL
-#define        IPG_TFC_IPCHECKSUMENABLE                0x0000000000100000ULL
-#define        IPG_TFC_FCSAPPENDDISABLE                0x0000000000200000ULL
-#define        IPG_TFC_TXINDICATE                      0x0000000000400000ULL
-#define        IPG_TFC_TXDMAINDICATE                   0x0000000000800000ULL
-#define        IPG_TFC_FRAGCOUNT                       0x000000000F000000ULL
-#define        IPG_TFC_VLANTAGINSERT                   0x0000000010000000ULL
-#define        IPG_TFC_TFDDONE                         0x0000000080000000ULL
-#define        IPG_TFC_VID                             0x00000FFF00000000ULL
-#define        IPG_TFC_CFI                             0x0000100000000000ULL
-#define        IPG_TFC_USERPRIORITY                    0x0000E00000000000ULL
-
-/* TFDList, FragInfo */
-#define        IPG_TFI_RSVD_MASK                       0xFFFF00FFFFFFFFFFULL
-#define        IPG_TFI_FRAGADDR                        0x000000FFFFFFFFFFULL
-#define        IPG_TFI_FRAGLEN                         0xFFFF000000000000ULL
-
-/* RFD data structure masks. */
-
-/* RFDList, RFS */
-#define        IPG_RFS_RSVD_MASK                       0x0000FFFFFFFFFFFFULL
-#define        IPG_RFS_RXFRAMELEN                      0x000000000000FFFFULL
-#define        IPG_RFS_RXFIFOOVERRUN                   0x0000000000010000ULL
-#define        IPG_RFS_RXRUNTFRAME                     0x0000000000020000ULL
-#define        IPG_RFS_RXALIGNMENTERROR                0x0000000000040000ULL
-#define        IPG_RFS_RXFCSERROR                      0x0000000000080000ULL
-#define        IPG_RFS_RXOVERSIZEDFRAME                0x0000000000100000ULL
-#define        IPG_RFS_RXLENGTHERROR                   0x0000000000200000ULL
-#define        IPG_RFS_VLANDETECTED                    0x0000000000400000ULL
-#define        IPG_RFS_TCPDETECTED                     0x0000000000800000ULL
-#define        IPG_RFS_TCPERROR                        0x0000000001000000ULL
-#define        IPG_RFS_UDPDETECTED                     0x0000000002000000ULL
-#define        IPG_RFS_UDPERROR                        0x0000000004000000ULL
-#define        IPG_RFS_IPDETECTED                      0x0000000008000000ULL
-#define        IPG_RFS_IPERROR                         0x0000000010000000ULL
-#define        IPG_RFS_FRAMESTART                      0x0000000020000000ULL
-#define        IPG_RFS_FRAMEEND                        0x0000000040000000ULL
-#define        IPG_RFS_RFDDONE                         0x0000000080000000ULL
-#define        IPG_RFS_TCI                             0x0000FFFF00000000ULL
-
-/* RFDList, FragInfo */
-#define        IPG_RFI_RSVD_MASK                       0xFFFF00FFFFFFFFFFULL
-#define        IPG_RFI_FRAGADDR                        0x000000FFFFFFFFFFULL
-#define        IPG_RFI_FRAGLEN                         0xFFFF000000000000ULL
-
-/* I/O Register masks. */
-
-/* RMON Statistics Mask */
-#define        IPG_RZ_ALL                                      0x0FFFFFFF
-
-/* Statistics Mask */
-#define        IPG_SM_ALL                                      0x0FFFFFFF
-#define        IPG_SM_OCTETRCVOK_FRAMESRCVDOK                  0x00000001
-#define        IPG_SM_MCSTOCTETRCVDOK_MCSTFRAMESRCVDOK         0x00000002
-#define        IPG_SM_BCSTOCTETRCVDOK_BCSTFRAMESRCVDOK         0x00000004
-#define        IPG_SM_RXJUMBOFRAMES                            0x00000008
-#define        IPG_SM_TCPCHECKSUMERRORS                        0x00000010
-#define        IPG_SM_IPCHECKSUMERRORS                         0x00000020
-#define        IPG_SM_UDPCHECKSUMERRORS                        0x00000040
-#define        IPG_SM_MACCONTROLFRAMESRCVD                     0x00000080
-#define        IPG_SM_FRAMESTOOLONGERRORS                      0x00000100
-#define        IPG_SM_INRANGELENGTHERRORS                      0x00000200
-#define        IPG_SM_FRAMECHECKSEQERRORS                      0x00000400
-#define        IPG_SM_FRAMESLOSTRXERRORS                       0x00000800
-#define        IPG_SM_OCTETXMTOK_FRAMESXMTOK                   0x00001000
-#define        IPG_SM_MCSTOCTETXMTOK_MCSTFRAMESXMTDOK          0x00002000
-#define        IPG_SM_BCSTOCTETXMTOK_BCSTFRAMESXMTDOK          0x00004000
-#define        IPG_SM_FRAMESWDEFERREDXMT                       0x00008000
-#define        IPG_SM_LATECOLLISIONS                           0x00010000
-#define        IPG_SM_MULTICOLFRAMES                           0x00020000
-#define        IPG_SM_SINGLECOLFRAMES                          0x00040000
-#define        IPG_SM_TXJUMBOFRAMES                            0x00080000
-#define        IPG_SM_CARRIERSENSEERRORS                       0x00100000
-#define        IPG_SM_MACCONTROLFRAMESXMTD                     0x00200000
-#define        IPG_SM_FRAMESABORTXSCOLLS                       0x00400000
-#define        IPG_SM_FRAMESWEXDEFERAL                         0x00800000
-
-/* Countdown */
-#define        IPG_CD_RSVD_MASK                0x0700FFFF
-#define        IPG_CD_COUNT                    0x0000FFFF
-#define        IPG_CD_COUNTDOWNSPEED           0x01000000
-#define        IPG_CD_COUNTDOWNMODE            0x02000000
-#define        IPG_CD_COUNTINTENABLED          0x04000000
-
-/* TxDMABurstThresh */
-#define IPG_TB_RSVD_MASK                0xFF
-
-/* TxDMAUrgentThresh */
-#define IPG_TU_RSVD_MASK                0xFF
-
-/* TxDMAPollPeriod */
-#define IPG_TP_RSVD_MASK                0xFF
-
-/* RxDMAUrgentThresh */
-#define IPG_RU_RSVD_MASK                0xFF
-
-/* RxDMAPollPeriod */
-#define IPG_RP_RSVD_MASK                0xFF
-
-/* ReceiveMode */
-#define IPG_RM_RSVD_MASK                0x3F
-#define IPG_RM_RECEIVEUNICAST           0x01
-#define IPG_RM_RECEIVEMULTICAST         0x02
-#define IPG_RM_RECEIVEBROADCAST         0x04
-#define IPG_RM_RECEIVEALLFRAMES         0x08
-#define IPG_RM_RECEIVEMULTICASTHASH     0x10
-#define IPG_RM_RECEIVEIPMULTICAST       0x20
-
-/* PhySet */
-#define IPG_PS_MEM_LENB9B               0x01
-#define IPG_PS_MEM_LEN9                 0x02
-#define IPG_PS_NON_COMPDET              0x04
-
-/* PhyCtrl */
-#define IPG_PC_RSVD_MASK                0xFF
-#define IPG_PC_MGMTCLK_LO               0x00
-#define IPG_PC_MGMTCLK_HI               0x01
-#define IPG_PC_MGMTCLK                  0x01
-#define IPG_PC_MGMTDATA                 0x02
-#define IPG_PC_MGMTDIR                  0x04
-#define IPG_PC_DUPLEX_POLARITY          0x08
-#define IPG_PC_DUPLEX_STATUS            0x10
-#define IPG_PC_LINK_POLARITY            0x20
-#define IPG_PC_LINK_SPEED               0xC0
-#define IPG_PC_LINK_SPEED_10MBPS        0x40
-#define IPG_PC_LINK_SPEED_100MBPS       0x80
-#define IPG_PC_LINK_SPEED_1000MBPS      0xC0
-
-/* DMACtrl */
-#define IPG_DC_RSVD_MASK                0xC07D9818
-#define IPG_DC_RX_DMA_COMPLETE          0x00000008
-#define IPG_DC_RX_DMA_POLL_NOW          0x00000010
-#define IPG_DC_TX_DMA_COMPLETE          0x00000800
-#define IPG_DC_TX_DMA_POLL_NOW          0x00001000
-#define IPG_DC_TX_DMA_IN_PROG           0x00008000
-#define IPG_DC_RX_EARLY_DISABLE         0x00010000
-#define IPG_DC_MWI_DISABLE              0x00040000
-#define IPG_DC_TX_WRITE_BACK_DISABLE    0x00080000
-#define IPG_DC_TX_BURST_LIMIT           0x00700000
-#define IPG_DC_TARGET_ABORT             0x40000000
-#define IPG_DC_MASTER_ABORT             0x80000000
-
-/* ASICCtrl */
-#define IPG_AC_RSVD_MASK                0x07FFEFF2
-#define IPG_AC_EXP_ROM_SIZE             0x00000002
-#define IPG_AC_PHY_SPEED10              0x00000010
-#define IPG_AC_PHY_SPEED100             0x00000020
-#define IPG_AC_PHY_SPEED1000            0x00000040
-#define IPG_AC_PHY_MEDIA                0x00000080
-#define IPG_AC_FORCED_CFG               0x00000700
-#define IPG_AC_D3RESETDISABLE           0x00000800
-#define IPG_AC_SPEED_UP_MODE            0x00002000
-#define IPG_AC_LED_MODE                 0x00004000
-#define IPG_AC_RST_OUT_POLARITY         0x00008000
-#define IPG_AC_GLOBAL_RESET             0x00010000
-#define IPG_AC_RX_RESET                 0x00020000
-#define IPG_AC_TX_RESET                 0x00040000
-#define IPG_AC_DMA                      0x00080000
-#define IPG_AC_FIFO                     0x00100000
-#define IPG_AC_NETWORK                  0x00200000
-#define IPG_AC_HOST                     0x00400000
-#define IPG_AC_AUTO_INIT                0x00800000
-#define IPG_AC_RST_OUT                  0x01000000
-#define IPG_AC_INT_REQUEST              0x02000000
-#define IPG_AC_RESET_BUSY               0x04000000
-#define IPG_AC_LED_SPEED                0x08000000
-#define IPG_AC_LED_MODE_BIT_1           0x20000000
-
-/* EepromCtrl */
-#define IPG_EC_RSVD_MASK                0x83FF
-#define IPG_EC_EEPROM_ADDR              0x00FF
-#define IPG_EC_EEPROM_OPCODE            0x0300
-#define IPG_EC_EEPROM_SUBCOMMAD         0x0000
-#define IPG_EC_EEPROM_WRITEOPCODE       0x0100
-#define IPG_EC_EEPROM_READOPCODE        0x0200
-#define IPG_EC_EEPROM_ERASEOPCODE       0x0300
-#define IPG_EC_EEPROM_BUSY              0x8000
-
-/* FIFOCtrl */
-#define IPG_FC_RSVD_MASK                0xC001
-#define IPG_FC_RAM_TEST_MODE            0x0001
-#define IPG_FC_TRANSMITTING             0x4000
-#define IPG_FC_RECEIVING                0x8000
-
-/* TxStatus */
-#define IPG_TS_RSVD_MASK                0xFFFF00DD
-#define IPG_TS_TX_ERROR                 0x00000001
-#define IPG_TS_LATE_COLLISION           0x00000004
-#define IPG_TS_TX_MAX_COLL              0x00000008
-#define IPG_TS_TX_UNDERRUN              0x00000010
-#define IPG_TS_TX_IND_REQD              0x00000040
-#define IPG_TS_TX_COMPLETE              0x00000080
-#define IPG_TS_TX_FRAMEID               0xFFFF0000
-
-/* WakeEvent */
-#define IPG_WE_WAKE_PKT_ENABLE          0x01
-#define IPG_WE_MAGIC_PKT_ENABLE         0x02
-#define IPG_WE_LINK_EVT_ENABLE          0x04
-#define IPG_WE_WAKE_POLARITY            0x08
-#define IPG_WE_WAKE_PKT_EVT             0x10
-#define IPG_WE_MAGIC_PKT_EVT            0x20
-#define IPG_WE_LINK_EVT                 0x40
-#define IPG_WE_WOL_ENABLE               0x80
-
-/* IntEnable */
-#define IPG_IE_RSVD_MASK                0x1FFE
-#define IPG_IE_HOST_ERROR               0x0002
-#define IPG_IE_TX_COMPLETE              0x0004
-#define IPG_IE_MAC_CTRL_FRAME           0x0008
-#define IPG_IE_RX_COMPLETE              0x0010
-#define IPG_IE_RX_EARLY                 0x0020
-#define IPG_IE_INT_REQUESTED            0x0040
-#define IPG_IE_UPDATE_STATS             0x0080
-#define IPG_IE_LINK_EVENT               0x0100
-#define IPG_IE_TX_DMA_COMPLETE          0x0200
-#define IPG_IE_RX_DMA_COMPLETE          0x0400
-#define IPG_IE_RFD_LIST_END             0x0800
-#define IPG_IE_RX_DMA_PRIORITY          0x1000
-
-/* IntStatus */
-#define IPG_IS_RSVD_MASK                0x1FFF
-#define IPG_IS_INTERRUPT_STATUS         0x0001
-#define IPG_IS_HOST_ERROR               0x0002
-#define IPG_IS_TX_COMPLETE              0x0004
-#define IPG_IS_MAC_CTRL_FRAME           0x0008
-#define IPG_IS_RX_COMPLETE              0x0010
-#define IPG_IS_RX_EARLY                 0x0020
-#define IPG_IS_INT_REQUESTED            0x0040
-#define IPG_IS_UPDATE_STATS             0x0080
-#define IPG_IS_LINK_EVENT               0x0100
-#define IPG_IS_TX_DMA_COMPLETE          0x0200
-#define IPG_IS_RX_DMA_COMPLETE          0x0400
-#define IPG_IS_RFD_LIST_END             0x0800
-#define IPG_IS_RX_DMA_PRIORITY          0x1000
-
-/* MACCtrl */
-#define IPG_MC_RSVD_MASK                0x7FE33FA3
-#define IPG_MC_IFS_SELECT               0x00000003
-#define IPG_MC_IFS_4352BIT              0x00000003
-#define IPG_MC_IFS_1792BIT              0x00000002
-#define IPG_MC_IFS_1024BIT              0x00000001
-#define IPG_MC_IFS_96BIT                0x00000000
-#define IPG_MC_DUPLEX_SELECT            0x00000020
-#define IPG_MC_DUPLEX_SELECT_FD         0x00000020
-#define IPG_MC_DUPLEX_SELECT_HD         0x00000000
-#define IPG_MC_TX_FLOW_CONTROL_ENABLE   0x00000080
-#define IPG_MC_RX_FLOW_CONTROL_ENABLE   0x00000100
-#define IPG_MC_RCV_FCS                  0x00000200
-#define IPG_MC_FIFO_LOOPBACK            0x00000400
-#define IPG_MC_MAC_LOOPBACK             0x00000800
-#define IPG_MC_AUTO_VLAN_TAGGING        0x00001000
-#define IPG_MC_AUTO_VLAN_UNTAGGING      0x00002000
-#define IPG_MC_COLLISION_DETECT         0x00010000
-#define IPG_MC_CARRIER_SENSE            0x00020000
-#define IPG_MC_STATISTICS_ENABLE        0x00200000
-#define IPG_MC_STATISTICS_DISABLE       0x00400000
-#define IPG_MC_STATISTICS_ENABLED       0x00800000
-#define IPG_MC_TX_ENABLE                0x01000000
-#define IPG_MC_TX_DISABLE               0x02000000
-#define IPG_MC_TX_ENABLED               0x04000000
-#define IPG_MC_RX_ENABLE                0x08000000
-#define IPG_MC_RX_DISABLE               0x10000000
-#define IPG_MC_RX_ENABLED               0x20000000
-#define IPG_MC_PAUSED                   0x40000000
-
-/*
- *     Tune
- */
-
-/* Assign IPG_APPEND_FCS_ON_TX > 0 for auto FCS append on TX. */
-#define         IPG_APPEND_FCS_ON_TX         1
-
-/* Assign IPG_APPEND_FCS_ON_TX > 0 for auto FCS strip on RX. */
-#define         IPG_STRIP_FCS_ON_RX          1
-
-/* Assign IPG_DROP_ON_RX_ETH_ERRORS > 0 to drop RX frames with
- * Ethernet errors.
- */
-#define         IPG_DROP_ON_RX_ETH_ERRORS    1
-
-/* Assign IPG_INSERT_MANUAL_VLAN_TAG > 0 to insert VLAN tags manually
- * (via TFC).
- */
-#define                IPG_INSERT_MANUAL_VLAN_TAG   0
-
-/* Assign IPG_ADD_IPCHECKSUM_ON_TX > 0 for auto IP checksum on TX. */
-#define         IPG_ADD_IPCHECKSUM_ON_TX     0
-
-/* Assign IPG_ADD_TCPCHECKSUM_ON_TX > 0 for auto TCP checksum on TX.
- * DO NOT USE FOR SILICON REVISIONS B3 AND EARLIER.
- */
-#define         IPG_ADD_TCPCHECKSUM_ON_TX    0
-
-/* Assign IPG_ADD_UDPCHECKSUM_ON_TX > 0 for auto UDP checksum on TX.
- * DO NOT USE FOR SILICON REVISIONS B3 AND EARLIER.
- */
-#define         IPG_ADD_UDPCHECKSUM_ON_TX    0
-
-/* If inserting VLAN tags manually, assign the IPG_MANUAL_VLAN_xx
- * constants as desired.
- */
-#define                IPG_MANUAL_VLAN_VID             0xABC
-#define                IPG_MANUAL_VLAN_CFI             0x1
-#define                IPG_MANUAL_VLAN_USERPRIORITY 0x5
-
-#define         IPG_IO_REG_RANGE               0xFF
-#define         IPG_MEM_REG_RANGE              0x154
-#define         IPG_DRIVER_NAME                "Sundance Technology IPG Triple-Speed Ethernet"
-#define         IPG_NIC_PHY_ADDRESS          0x01
-#define                IPG_DMALIST_ALIGN_PAD   0x07
-#define                IPG_MULTICAST_HASHTABLE_SIZE    0x40
-
-/* Number of milliseconds to wait after issuing a software reset.
- * 0x05 <= IPG_AC_RESETWAIT to account for proper 10Mbps operation.
- */
-#define         IPG_AC_RESETWAIT             0x05
-
-/* Number of IPG_AC_RESETWAIT timeperiods before declaring timeout. */
-#define         IPG_AC_RESET_TIMEOUT         0x0A
-
-/* Minimum number of nanoseconds used to toggle MDC clock during
- * MII/GMII register access.
- */
-#define                IPG_PC_PHYCTRLWAIT_NS           200
-
-#define                IPG_TFDLIST_LENGTH              0x100
-
-/* Number of frames between TxDMAComplete interrupt.
- * 0 < IPG_FRAMESBETWEENTXDMACOMPLETES <= IPG_TFDLIST_LENGTH
- */
-#define                IPG_FRAMESBETWEENTXDMACOMPLETES 0x1
-
-#define                IPG_RFDLIST_LENGTH              0x100
-
-/* Maximum number of RFDs to process per interrupt.
- * 1 < IPG_MAXRFDPROCESS_COUNT < IPG_RFDLIST_LENGTH
- */
-#define                IPG_MAXRFDPROCESS_COUNT 0x80
-
-/* Minimum margin between last freed RFD, and current RFD.
- * 1 < IPG_MINUSEDRFDSTOFREE < IPG_RFDLIST_LENGTH
- */
-#define                IPG_MINUSEDRFDSTOFREE   0x80
-
-/* specify the jumbo frame maximum size
- * per unit is 0x600 (the rx_buffer size that one RFD can carry)
- */
-#define     MAX_JUMBOSIZE              0x8     /* max is 12K */
-
-/* Key register values loaded at driver start up. */
-
-/* TXDMAPollPeriod is specified in 320ns increments.
- *
- * Value       Time
- * ---------------------
- * 0x00-0x01   320ns
- * 0x03                ~1us
- * 0x1F                ~10us
- * 0xFF                ~82us
- */
-#define                IPG_TXDMAPOLLPERIOD_VALUE       0x26
-
-/* TxDMAUrgentThresh specifies the minimum amount of
- * data in the transmit FIFO before asserting an
- * urgent transmit DMA request.
- *
- * Value       Min TxFIFO occupied space before urgent TX request
- * ---------------------------------------------------------------
- * 0x00-0x04   128 bytes (1024 bits)
- * 0x27                1248 bytes (~10000 bits)
- * 0x30                1536 bytes (12288 bits)
- * 0xFF                8192 bytes (65535 bits)
- */
-#define                IPG_TXDMAURGENTTHRESH_VALUE     0x04
-
-/* TxDMABurstThresh specifies the minimum amount of
- * free space in the transmit FIFO before asserting an
- * transmit DMA request.
- *
- * Value       Min TxFIFO free space before TX request
- * ----------------------------------------------------
- * 0x00-0x08   256 bytes
- * 0x30                1536 bytes
- * 0xFF                8192 bytes
- */
-#define                IPG_TXDMABURSTTHRESH_VALUE      0x30
-
-/* RXDMAPollPeriod is specified in 320ns increments.
- *
- * Value       Time
- * ---------------------
- * 0x00-0x01   320ns
- * 0x03                ~1us
- * 0x1F                ~10us
- * 0xFF                ~82us
- */
-#define                IPG_RXDMAPOLLPERIOD_VALUE       0x01
-
-/* RxDMAUrgentThresh specifies the minimum amount of
- * free space within the receive FIFO before asserting
- * a urgent receive DMA request.
- *
- * Value       Min RxFIFO free space before urgent RX request
- * ---------------------------------------------------------------
- * 0x00-0x04   128 bytes (1024 bits)
- * 0x27                1248 bytes (~10000 bits)
- * 0x30                1536 bytes (12288 bits)
- * 0xFF                8192 bytes (65535 bits)
- */
-#define                IPG_RXDMAURGENTTHRESH_VALUE     0x30
-
-/* RxDMABurstThresh specifies the minimum amount of
- * occupied space within the receive FIFO before asserting
- * a receive DMA request.
- *
- * Value       Min TxFIFO free space before TX request
- * ----------------------------------------------------
- * 0x00-0x08   256 bytes
- * 0x30                1536 bytes
- * 0xFF                8192 bytes
- */
-#define                IPG_RXDMABURSTTHRESH_VALUE      0x30
-
-/* FlowOnThresh specifies the maximum amount of occupied
- * space in the receive FIFO before a PAUSE frame with
- * maximum pause time transmitted.
- *
- * Value       Max RxFIFO occupied space before PAUSE
- * ---------------------------------------------------
- * 0x0000      0 bytes
- * 0x0740      29,696 bytes
- * 0x07FF      32,752 bytes
- */
-#define                IPG_FLOWONTHRESH_VALUE  0x0740
-
-/* FlowOffThresh specifies the minimum amount of occupied
- * space in the receive FIFO before a PAUSE frame with
- * zero pause time is transmitted.
- *
- * Value       Max RxFIFO occupied space before PAUSE
- * ---------------------------------------------------
- * 0x0000      0 bytes
- * 0x00BF      3056 bytes
- * 0x07FF      32,752 bytes
- */
-#define                IPG_FLOWOFFTHRESH_VALUE 0x00BF
-
-/*
- * Miscellaneous macros.
- */
-
-/* Macros for printing debug statements. */
-#ifdef IPG_DEBUG
-#  define IPG_DEBUG_MSG(fmt, args...)                  \
-do {                                                   \
-       if (0)                                          \
-               printk(KERN_DEBUG "IPG: " fmt, ##args); \
-} while (0)
-#  define IPG_DDEBUG_MSG(fmt, args...)                 \
-       printk(KERN_DEBUG "IPG: " fmt, ##args)
-#  define IPG_DUMPRFDLIST(args) ipg_dump_rfdlist(args)
-#  define IPG_DUMPTFDLIST(args) ipg_dump_tfdlist(args)
-#else
-#  define IPG_DEBUG_MSG(fmt, args...)                  \
-do {                                                   \
-       if (0)                                          \
-               printk(KERN_DEBUG "IPG: " fmt, ##args); \
-} while (0)
-#  define IPG_DDEBUG_MSG(fmt, args...)                 \
-do {                                                   \
-       if (0)                                          \
-               printk(KERN_DEBUG "IPG: " fmt, ##args); \
-} while (0)
-#  define IPG_DUMPRFDLIST(args)
-#  define IPG_DUMPTFDLIST(args)
-#endif
-
-/*
- * End miscellaneous macros.
- */
-
-/* Transmit Frame Descriptor. The IPG supports 15 fragments,
- * however Linux requires only a single fragment. Note, each
- * TFD field is 64 bits wide.
- */
-struct ipg_tx {
-       __le64 next_desc;
-       __le64 tfc;
-       __le64 frag_info;
-};
-
-/* Receive Frame Descriptor. Note, each RFD field is 64 bits wide.
- */
-struct ipg_rx {
-       __le64 next_desc;
-       __le64 rfs;
-       __le64 frag_info;
-};
-
-struct ipg_jumbo {
-       int found_start;
-       int current_size;
-       struct sk_buff *skb;
-};
-
-/* Structure of IPG NIC specific data. */
-struct ipg_nic_private {
-       void __iomem *ioaddr;
-       struct ipg_tx *txd;
-       struct ipg_rx *rxd;
-       dma_addr_t txd_map;
-       dma_addr_t rxd_map;
-       struct sk_buff *tx_buff[IPG_TFDLIST_LENGTH];
-       struct sk_buff *rx_buff[IPG_RFDLIST_LENGTH];
-       unsigned int tx_current;
-       unsigned int tx_dirty;
-       unsigned int rx_current;
-       unsigned int rx_dirty;
-       bool is_jumbo;
-       struct ipg_jumbo jumbo;
-       unsigned long rxfrag_size;
-       unsigned long rxsupport_size;
-       unsigned long max_rxframe_size;
-       unsigned int rx_buf_sz;
-       struct pci_dev *pdev;
-       struct net_device *dev;
-       struct net_device_stats stats;
-       spinlock_t lock;
-       int tenmbpsmode;
-
-       u16 led_mode;
-       u16 station_addr[3];    /* Station Address in EEPROM Reg 0x10..0x12 */
-
-       struct mutex            mii_mutex;
-       struct mii_if_info      mii_if;
-       int reset_current_tfd;
-#ifdef IPG_DEBUG
-       int RFDlistendCount;
-       int RFDListCheckedCount;
-       int EmptyRFDListCount;
-#endif
-       struct delayed_work task;
-};
-
-#endif                         /* __LINUX_IPG_H */
index 639263d5e833a04d19967f6df3cd20d8ce574a3b..7781e80896a60a59e12eec15582cc3743447e1dd 100644 (file)
@@ -627,8 +627,10 @@ static netdev_tx_t fm10k_xmit_frame(struct sk_buff *skb, struct net_device *dev)
 
                /* verify the skb head is not shared */
                err = skb_cow_head(skb, 0);
-               if (err)
+               if (err) {
+                       dev_kfree_skb(skb);
                        return NETDEV_TX_OK;
+               }
 
                /* locate vlan header */
                vhdr = (struct vlan_hdr *)(skb->data + ETH_HLEN);
index 0ff8f01e57ee5a4a7de890485e5987fd9eec7f8a..1fd5ea82a9bc88950a29a305e7c4898c3b6b246c 100644 (file)
@@ -567,10 +567,6 @@ i40e_status i40e_init_adminq(struct i40e_hw *hw)
                goto init_adminq_exit;
        }
 
-       /* initialize locks */
-       mutex_init(&hw->aq.asq_mutex);
-       mutex_init(&hw->aq.arq_mutex);
-
        /* Set up register offsets */
        i40e_adminq_init_regs(hw);
 
@@ -664,8 +660,6 @@ i40e_status i40e_shutdown_adminq(struct i40e_hw *hw)
        i40e_shutdown_asq(hw);
        i40e_shutdown_arq(hw);
 
-       /* destroy the locks */
-
        if (hw->nvm_buff.va)
                i40e_free_virt_mem(hw, &hw->nvm_buff);
 
index b825f978d441d1987581b249694298bb5996538d..4a9873ec28c7119d28aabb791bd0628ceccf56ad 100644 (file)
@@ -10295,6 +10295,12 @@ static int i40e_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
        /* set up a default setting for link flow control */
        pf->hw.fc.requested_mode = I40E_FC_NONE;
 
+       /* set up the locks for the AQ, do this only once in probe
+        * and destroy them only once in remove
+        */
+       mutex_init(&hw->aq.asq_mutex);
+       mutex_init(&hw->aq.arq_mutex);
+
        err = i40e_init_adminq(hw);
 
        /* provide nvm, fw, api versions */
@@ -10697,7 +10703,6 @@ 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);
@@ -10740,6 +10745,10 @@ static void i40e_remove(struct pci_dev *pdev)
                         "Failed to destroy the Admin Queue resources: %d\n",
                         ret_code);
 
+       /* destroy the locks only once, here */
+       mutex_destroy(&hw->aq.arq_mutex);
+       mutex_destroy(&hw->aq.asq_mutex);
+
        /* Clear all dynamic memory lists of rings, q_vectors, and VSIs */
        i40e_clear_interrupt_scheme(pf);
        for (i = 0; i < pf->num_alloc_vsi; i++) {
index fd123ca60761e84721a02ab991ed677925338126..3f65e39b3fe43b9231ab28bfe32b8728aba95ce1 100644 (file)
@@ -551,10 +551,6 @@ i40e_status i40evf_init_adminq(struct i40e_hw *hw)
                goto init_adminq_exit;
        }
 
-       /* initialize locks */
-       mutex_init(&hw->aq.asq_mutex);
-       mutex_init(&hw->aq.arq_mutex);
-
        /* Set up register offsets */
        i40e_adminq_init_regs(hw);
 
@@ -596,8 +592,6 @@ i40e_status i40evf_shutdown_adminq(struct i40e_hw *hw)
        i40e_shutdown_asq(hw);
        i40e_shutdown_arq(hw);
 
-       /* destroy the locks */
-
        if (hw->nvm_buff.va)
                i40e_free_virt_mem(hw, &hw->nvm_buff);
 
index d962164dfb0fbf579a150223b8d594ecb073b51f..99d2cffae0cd8c2b4c583f4453aa3c09cc58f3eb 100644 (file)
@@ -2476,6 +2476,12 @@ static int i40evf_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
        hw->bus.device = PCI_SLOT(pdev->devfn);
        hw->bus.func = PCI_FUNC(pdev->devfn);
 
+       /* set up the locks for the AQ, do this only once in probe
+        * and destroy them only once in remove
+        */
+       mutex_init(&hw->aq.asq_mutex);
+       mutex_init(&hw->aq.arq_mutex);
+
        INIT_LIST_HEAD(&adapter->mac_filter_list);
        INIT_LIST_HEAD(&adapter->vlan_filter_list);
 
@@ -2629,6 +2635,10 @@ static void i40evf_remove(struct pci_dev *pdev)
        if (hw->aq.asq.count)
                i40evf_shutdown_adminq(hw);
 
+       /* destroy the locks only once, here */
+       mutex_destroy(&hw->aq.arq_mutex);
+       mutex_destroy(&hw->aq.asq_mutex);
+
        iounmap(hw->hw_addr);
        pci_release_regions(pdev);
 
index 47395ff5d908c43174a4c6afc4a8a089ae948c70..aed8d029b23dc53a7a630d74816e37d35bdbbc4a 100644 (file)
@@ -7920,6 +7920,9 @@ int ixgbe_setup_tc(struct net_device *dev, u8 tc)
         */
        if (netif_running(dev))
                ixgbe_close(dev);
+       else
+               ixgbe_reset(adapter);
+
        ixgbe_clear_interrupt_scheme(adapter);
 
 #ifdef CONFIG_IXGBE_DCB
index e84c7f2634d3759805326707a29c33737bcad615..ed622fa29dfab61c448c0c446ad2cae467ee1df2 100644 (file)
@@ -36,7 +36,7 @@
 
 /* Registers */
 #define MVNETA_RXQ_CONFIG_REG(q)                (0x1400 + ((q) << 2))
-#define      MVNETA_RXQ_HW_BUF_ALLOC            BIT(1)
+#define      MVNETA_RXQ_HW_BUF_ALLOC            BIT(0)
 #define      MVNETA_RXQ_PKT_OFFSET_ALL_MASK     (0xf    << 8)
 #define      MVNETA_RXQ_PKT_OFFSET_MASK(offs)   ((offs) << 8)
 #define MVNETA_RXQ_THRESHOLD_REG(q)             (0x14c0 + ((q) << 2))
@@ -62,6 +62,7 @@
 #define MVNETA_WIN_SIZE(w)                      (0x2204 + ((w) << 3))
 #define MVNETA_WIN_REMAP(w)                     (0x2280 + ((w) << 2))
 #define MVNETA_BASE_ADDR_ENABLE                 0x2290
+#define MVNETA_ACCESS_PROTECT_ENABLE            0x2294
 #define MVNETA_PORT_CONFIG                      0x2400
 #define      MVNETA_UNI_PROMISC_MODE            BIT(0)
 #define      MVNETA_DEF_RXQ(q)                  ((q) << 1)
 
 #define MVNETA_INTR_ENABLE                       0x25b8
 #define      MVNETA_TXQ_INTR_ENABLE_ALL_MASK     0x0000ff00
-#define      MVNETA_RXQ_INTR_ENABLE_ALL_MASK     0xff000000  // note: neta says it's 0x000000FF
+#define      MVNETA_RXQ_INTR_ENABLE_ALL_MASK     0x000000ff
 
 #define MVNETA_RXQ_CMD                           0x2680
 #define      MVNETA_RXQ_DISABLE_SHIFT            8
 #define MVNETA_VLAN_TAG_LEN             4
 
 #define MVNETA_CPU_D_CACHE_LINE_SIZE    32
+#define MVNETA_TX_CSUM_DEF_SIZE                1600
 #define MVNETA_TX_CSUM_MAX_SIZE                9800
 #define MVNETA_ACC_MODE_EXT            1
 
@@ -1579,12 +1581,16 @@ static int mvneta_rx(struct mvneta_port *pp, int rx_todo,
                }
 
                skb = build_skb(data, pp->frag_size > PAGE_SIZE ? 0 : pp->frag_size);
-               if (!skb)
-                       goto err_drop_frame;
 
+               /* After refill old buffer has to be unmapped regardless
+                * the skb is successfully built or not.
+                */
                dma_unmap_single(dev->dev.parent, phys_addr,
                                 MVNETA_RX_BUF_SIZE(pp->pkt_size), DMA_FROM_DEVICE);
 
+               if (!skb)
+                       goto err_drop_frame;
+
                rcvd_pkts++;
                rcvd_bytes += rx_bytes;
 
@@ -3191,6 +3197,7 @@ static void mvneta_conf_mbus_windows(struct mvneta_port *pp,
        }
 
        mvreg_write(pp, MVNETA_BASE_ADDR_ENABLE, win_enable);
+       mvreg_write(pp, MVNETA_ACCESS_PROTECT_ENABLE, win_protect);
 }
 
 /* Power up the port */
@@ -3250,6 +3257,7 @@ static int mvneta_probe(struct platform_device *pdev)
        char hw_mac_addr[ETH_ALEN];
        const char *mac_from;
        const char *managed;
+       int tx_csum_limit;
        int phy_mode;
        int err;
        int cpu;
@@ -3350,8 +3358,21 @@ static int mvneta_probe(struct platform_device *pdev)
                }
        }
 
-       if (of_device_is_compatible(dn, "marvell,armada-370-neta"))
-               pp->tx_csum_limit = 1600;
+       if (!of_property_read_u32(dn, "tx-csum-limit", &tx_csum_limit)) {
+               if (tx_csum_limit < 0 ||
+                   tx_csum_limit > MVNETA_TX_CSUM_MAX_SIZE) {
+                       tx_csum_limit = MVNETA_TX_CSUM_DEF_SIZE;
+                       dev_info(&pdev->dev,
+                                "Wrong TX csum limit in DT, set to %dB\n",
+                                MVNETA_TX_CSUM_DEF_SIZE);
+               }
+       } else if (of_device_is_compatible(dn, "marvell,armada-370-neta")) {
+               tx_csum_limit = MVNETA_TX_CSUM_DEF_SIZE;
+       } else {
+               tx_csum_limit = MVNETA_TX_CSUM_MAX_SIZE;
+       }
+
+       pp->tx_csum_limit = tx_csum_limit;
 
        pp->tx_ring_size = MVNETA_MAX_TXD;
        pp->rx_ring_size = MVNETA_MAX_RXD;
index d9884fd15b453e2486177d58b7fc40bcd5aaf7cc..a4beccf1fd46e26483dc796829d444a15f77723f 100644 (file)
@@ -3413,16 +3413,23 @@ static void mvpp2_bm_pool_bufsize_set(struct mvpp2 *priv,
 }
 
 /* Free all buffers from the pool */
-static void mvpp2_bm_bufs_free(struct mvpp2 *priv, struct mvpp2_bm_pool *bm_pool)
+static void mvpp2_bm_bufs_free(struct device *dev, struct mvpp2 *priv,
+                              struct mvpp2_bm_pool *bm_pool)
 {
        int i;
 
        for (i = 0; i < bm_pool->buf_num; i++) {
+               dma_addr_t buf_phys_addr;
                u32 vaddr;
 
                /* Get buffer virtual address (indirect access) */
-               mvpp2_read(priv, MVPP2_BM_PHY_ALLOC_REG(bm_pool->id));
+               buf_phys_addr = mvpp2_read(priv,
+                                          MVPP2_BM_PHY_ALLOC_REG(bm_pool->id));
                vaddr = mvpp2_read(priv, MVPP2_BM_VIRT_ALLOC_REG);
+
+               dma_unmap_single(dev, buf_phys_addr,
+                                bm_pool->buf_size, DMA_FROM_DEVICE);
+
                if (!vaddr)
                        break;
                dev_kfree_skb_any((struct sk_buff *)vaddr);
@@ -3439,7 +3446,7 @@ static int mvpp2_bm_pool_destroy(struct platform_device *pdev,
 {
        u32 val;
 
-       mvpp2_bm_bufs_free(priv, bm_pool);
+       mvpp2_bm_bufs_free(&pdev->dev, priv, bm_pool);
        if (bm_pool->buf_num) {
                WARN(1, "cannot free all buffers in pool %d\n", bm_pool->id);
                return 0;
@@ -3692,7 +3699,8 @@ mvpp2_bm_pool_use(struct mvpp2_port *port, int pool, enum mvpp2_bm_type type,
                                   MVPP2_BM_LONG_BUF_NUM :
                                   MVPP2_BM_SHORT_BUF_NUM;
                else
-                       mvpp2_bm_bufs_free(port->priv, new_pool);
+                       mvpp2_bm_bufs_free(port->dev->dev.parent,
+                                          port->priv, new_pool);
 
                new_pool->pkt_size = pkt_size;
 
@@ -3756,7 +3764,7 @@ static int mvpp2_bm_update_mtu(struct net_device *dev, int mtu)
        int pkt_size = MVPP2_RX_PKT_SIZE(mtu);
 
        /* Update BM pool with new buffer size */
-       mvpp2_bm_bufs_free(port->priv, port_pool);
+       mvpp2_bm_bufs_free(dev->dev.parent, port->priv, port_pool);
        if (port_pool->buf_num) {
                WARN(1, "cannot free all buffers in pool %d\n", port_pool->id);
                return -EIO;
@@ -4401,11 +4409,10 @@ static void mvpp2_txq_bufs_free(struct mvpp2_port *port,
 
                mvpp2_txq_inc_get(txq_pcpu);
 
-               if (!skb)
-                       continue;
-
                dma_unmap_single(port->dev->dev.parent, buf_phys_addr,
                                 skb_headlen(skb), DMA_TO_DEVICE);
+               if (!skb)
+                       continue;
                dev_kfree_skb_any(skb);
        }
 }
@@ -5092,7 +5099,8 @@ static int mvpp2_rx(struct mvpp2_port *port, int rx_todo,
                    struct mvpp2_rx_queue *rxq)
 {
        struct net_device *dev = port->dev;
-       int rx_received, rx_filled, i;
+       int rx_received;
+       int rx_done = 0;
        u32 rcvd_pkts = 0;
        u32 rcvd_bytes = 0;
 
@@ -5101,17 +5109,18 @@ static int mvpp2_rx(struct mvpp2_port *port, int rx_todo,
        if (rx_todo > rx_received)
                rx_todo = rx_received;
 
-       rx_filled = 0;
-       for (i = 0; i < rx_todo; i++) {
+       while (rx_done < rx_todo) {
                struct mvpp2_rx_desc *rx_desc = mvpp2_rxq_next_desc_get(rxq);
                struct mvpp2_bm_pool *bm_pool;
                struct sk_buff *skb;
+               dma_addr_t phys_addr;
                u32 bm, rx_status;
                int pool, rx_bytes, err;
 
-               rx_filled++;
+               rx_done++;
                rx_status = rx_desc->status;
                rx_bytes = rx_desc->data_size - MVPP2_MH_SIZE;
+               phys_addr = rx_desc->buf_phys_addr;
 
                bm = mvpp2_bm_cookie_build(rx_desc);
                pool = mvpp2_bm_cookie_pool_get(bm);
@@ -5128,8 +5137,10 @@ static int mvpp2_rx(struct mvpp2_port *port, int rx_todo,
                 * comprised by the RX descriptor.
                 */
                if (rx_status & MVPP2_RXD_ERR_SUMMARY) {
+               err_drop_frame:
                        dev->stats.rx_errors++;
                        mvpp2_rx_error(port, rx_desc);
+                       /* Return the buffer to the pool */
                        mvpp2_pool_refill(port, bm, rx_desc->buf_phys_addr,
                                          rx_desc->buf_cookie);
                        continue;
@@ -5137,6 +5148,15 @@ static int mvpp2_rx(struct mvpp2_port *port, int rx_todo,
 
                skb = (struct sk_buff *)rx_desc->buf_cookie;
 
+               err = mvpp2_rx_refill(port, bm_pool, bm, 0);
+               if (err) {
+                       netdev_err(port->dev, "failed to refill BM pools\n");
+                       goto err_drop_frame;
+               }
+
+               dma_unmap_single(dev->dev.parent, phys_addr,
+                                bm_pool->buf_size, DMA_FROM_DEVICE);
+
                rcvd_pkts++;
                rcvd_bytes += rx_bytes;
                atomic_inc(&bm_pool->in_use);
@@ -5147,12 +5167,6 @@ static int mvpp2_rx(struct mvpp2_port *port, int rx_todo,
                mvpp2_rx_csum(port, rx_status, skb);
 
                napi_gro_receive(&port->napi, skb);
-
-               err = mvpp2_rx_refill(port, bm_pool, bm, 0);
-               if (err) {
-                       netdev_err(port->dev, "failed to refill BM pools\n");
-                       rx_filled--;
-               }
        }
 
        if (rcvd_pkts) {
@@ -5166,7 +5180,7 @@ static int mvpp2_rx(struct mvpp2_port *port, int rx_todo,
 
        /* Update Rx queue management counters */
        wmb();
-       mvpp2_rxq_status_update(port, rxq->id, rx_todo, rx_filled);
+       mvpp2_rxq_status_update(port, rxq->id, rx_done, rx_done);
 
        return rx_todo;
 }
index 2177e56ed0be7d18ee40d2428b69003bd6f8cca5..d48d5793407d9ec729fe8548a049a2506d02a934 100644 (file)
@@ -1010,7 +1010,7 @@ static int mlx4_MAD_IFC_wrapper(struct mlx4_dev *dev, int slave,
                if (!(smp->mgmt_class == IB_MGMT_CLASS_SUBN_LID_ROUTED &&
                      smp->method == IB_MGMT_METHOD_GET) || network_view) {
                        mlx4_err(dev, "Unprivileged slave %d is trying to execute a Subnet MGMT MAD, class 0x%x, method 0x%x, view=%s for attr 0x%x. Rejecting\n",
-                                slave, smp->method, smp->mgmt_class,
+                                slave, smp->mgmt_class, smp->method,
                                 network_view ? "Network" : "Host",
                                 be16_to_cpu(smp->attr_id));
                        return -EPERM;
index 8a083d73efdbae61e7d71ee364c816b58a16b2f9..038f9ce391e626f02d3fe2f51a19fbd4b08a2711 100644 (file)
@@ -242,6 +242,13 @@ void mlx4_en_init_timestamp(struct mlx4_en_dev *mdev)
        unsigned long flags;
        u64 ns, zero = 0;
 
+       /* mlx4_en_init_timestamp is called for each netdev.
+        * mdev->ptp_clock is common for all ports, skip initialization if
+        * was done for other port.
+        */
+       if (mdev->ptp_clock)
+               return;
+
        rwlock_init(&mdev->clock_lock);
 
        memset(&mdev->cycles, 0, sizeof(mdev->cycles));
index 005f910ec955ecdaaa398c6edcc6d95c01d6c2c4..e0ec280a7fa13a55fd239f84c6f6c24db2c2e5e5 100644 (file)
@@ -232,9 +232,6 @@ static void mlx4_en_remove(struct mlx4_dev *dev, void *endev_ptr)
                if (mdev->pndev[i])
                        mlx4_en_destroy_netdev(mdev->pndev[i]);
 
-       if (mdev->dev->caps.flags2 & MLX4_DEV_CAP_FLAG2_TS)
-               mlx4_en_remove_timestamp(mdev);
-
        flush_workqueue(mdev->workqueue);
        destroy_workqueue(mdev->workqueue);
        (void) mlx4_mr_free(dev, &mdev->mr);
@@ -320,10 +317,6 @@ static void *mlx4_en_add(struct mlx4_dev *dev)
        mlx4_foreach_port(i, dev, MLX4_PORT_TYPE_ETH)
                mdev->port_cnt++;
 
-       /* Initialize time stamp mechanism */
-       if (mdev->dev->caps.flags2 & MLX4_DEV_CAP_FLAG2_TS)
-               mlx4_en_init_timestamp(mdev);
-
        /* Set default number of RX rings*/
        mlx4_en_set_num_rx_rings(mdev);
 
index 886e1bc86374d990fc92655c7e1b40a3d611b45c..7869f97de5daf94cb99554c51a28a610aca76348 100644 (file)
@@ -2072,6 +2072,9 @@ void mlx4_en_destroy_netdev(struct net_device *dev)
        /* flush any pending task for this netdev */
        flush_workqueue(mdev->workqueue);
 
+       if (mdev->dev->caps.flags2 & MLX4_DEV_CAP_FLAG2_TS)
+               mlx4_en_remove_timestamp(mdev);
+
        /* Detach the netdev so tasks would not attempt to access it */
        mutex_lock(&mdev->state_lock);
        mdev->pndev[priv->port] = NULL;
@@ -3058,9 +3061,12 @@ int mlx4_en_init_netdev(struct mlx4_en_dev *mdev, int port,
        }
        queue_delayed_work(mdev->workqueue, &priv->stats_task, STATS_DELAY);
 
+       /* Initialize time stamp mechanism */
        if (mdev->dev->caps.flags2 & MLX4_DEV_CAP_FLAG2_TS)
-               queue_delayed_work(mdev->workqueue, &priv->service_task,
-                                  SERVICE_TASK_DELAY);
+               mlx4_en_init_timestamp(mdev);
+
+       queue_delayed_work(mdev->workqueue, &priv->service_task,
+                          SERVICE_TASK_DELAY);
 
        mlx4_en_set_stats_bitmap(mdev->dev, &priv->stats_bitmap,
                                 mdev->profile.prof[priv->port].rx_ppp,
index 85f1b1e7e505727bcdb7f424348d9dce0c5825d3..31c491e02e69f15187a89e5a399bfc67e2693237 100644 (file)
@@ -892,9 +892,10 @@ static int mlx4_slave_cap(struct mlx4_dev *dev)
                dev->caps.qp1_proxy[i - 1] = func_cap.qp1_proxy_qpn;
                dev->caps.port_mask[i] = dev->caps.port_type[i];
                dev->caps.phys_port_id[i] = func_cap.phys_port_id;
-               if (mlx4_get_slave_pkey_gid_tbl_len(dev, i,
-                                                   &dev->caps.gid_table_len[i],
-                                                   &dev->caps.pkey_table_len[i]))
+               err = mlx4_get_slave_pkey_gid_tbl_len(dev, i,
+                                                     &dev->caps.gid_table_len[i],
+                                                     &dev->caps.pkey_table_len[i]);
+               if (err)
                        goto err_mem;
        }
 
@@ -906,6 +907,7 @@ static int mlx4_slave_cap(struct mlx4_dev *dev)
                         dev->caps.uar_page_size * dev->caps.num_uars,
                         (unsigned long long)
                         pci_resource_len(dev->persist->pdev, 2));
+               err = -ENOMEM;
                goto err_mem;
        }
 
index 9813d34f3e5b78e0b3d4a99e253b710278bc7171..cad6c44df91c4de9b97d367ede4f2562c65fc86b 100644 (file)
@@ -4306,9 +4306,10 @@ int mlx4_QP_FLOW_STEERING_ATTACH_wrapper(struct mlx4_dev *dev, int slave,
                return -EOPNOTSUPP;
 
        ctrl = (struct mlx4_net_trans_rule_hw_ctrl *)inbox->buf;
-       ctrl->port = mlx4_slave_convert_port(dev, slave, ctrl->port);
-       if (ctrl->port <= 0)
+       err = mlx4_slave_convert_port(dev, slave, ctrl->port);
+       if (err <= 0)
                return -EINVAL;
+       ctrl->port = err;
        qpn = be32_to_cpu(ctrl->qpn) & 0xffffff;
        err = get_res(dev, slave, qpn, RES_QP, &rqp);
        if (err) {
@@ -4952,26 +4953,41 @@ static void rem_slave_counters(struct mlx4_dev *dev, int slave)
        struct res_counter *counter;
        struct res_counter *tmp;
        int err;
-       int index;
+       int *counters_arr = NULL;
+       int i, j;
 
        err = move_all_busy(dev, slave, RES_COUNTER);
        if (err)
                mlx4_warn(dev, "rem_slave_counters: Could not move all counters - too busy for slave %d\n",
                          slave);
 
-       spin_lock_irq(mlx4_tlock(dev));
-       list_for_each_entry_safe(counter, tmp, counter_list, com.list) {
-               if (counter->com.owner == slave) {
-                       index = counter->com.res_id;
-                       rb_erase(&counter->com.node,
-                                &tracker->res_tree[RES_COUNTER]);
-                       list_del(&counter->com.list);
-                       kfree(counter);
-                       __mlx4_counter_free(dev, index);
+       counters_arr = kmalloc_array(dev->caps.max_counters,
+                                    sizeof(*counters_arr), GFP_KERNEL);
+       if (!counters_arr)
+               return;
+
+       do {
+               i = 0;
+               j = 0;
+               spin_lock_irq(mlx4_tlock(dev));
+               list_for_each_entry_safe(counter, tmp, counter_list, com.list) {
+                       if (counter->com.owner == slave) {
+                               counters_arr[i++] = counter->com.res_id;
+                               rb_erase(&counter->com.node,
+                                        &tracker->res_tree[RES_COUNTER]);
+                               list_del(&counter->com.list);
+                               kfree(counter);
+                       }
+               }
+               spin_unlock_irq(mlx4_tlock(dev));
+
+               while (j < i) {
+                       __mlx4_counter_free(dev, counters_arr[j++]);
                        mlx4_release_resource(dev, slave, RES_COUNTER, 1, 0);
                }
-       }
-       spin_unlock_irq(mlx4_tlock(dev));
+       } while (i);
+
+       kfree(counters_arr);
 }
 
 static void rem_slave_xrcdns(struct mlx4_dev *dev, int slave)
index f2ae62dd8c094ac4c11917f29d65fbb63c2194a2..22e72bf1ae4894a846d790d8973b87aee3ac6431 100644 (file)
@@ -334,9 +334,15 @@ struct mlx5e_tx_skb_cb {
 
 #define MLX5E_TX_SKB_CB(__skb) ((struct mlx5e_tx_skb_cb *)__skb->cb)
 
+enum mlx5e_dma_map_type {
+       MLX5E_DMA_MAP_SINGLE,
+       MLX5E_DMA_MAP_PAGE
+};
+
 struct mlx5e_sq_dma {
-       dma_addr_t addr;
-       u32        size;
+       dma_addr_t              addr;
+       u32                     size;
+       enum mlx5e_dma_map_type type;
 };
 
 enum {
index 5fc4d2d78cdf7525c4f469733ee317ae1f0142ca..1e52db32c73d28bdc5e76f4857522a7b2ecff90b 100644 (file)
@@ -1332,6 +1332,42 @@ static int mlx5e_modify_tir_lro(struct mlx5e_priv *priv, int tt)
        return err;
 }
 
+static int mlx5e_refresh_tir_self_loopback_enable(struct mlx5_core_dev *mdev,
+                                                 u32 tirn)
+{
+       void *in;
+       int inlen;
+       int err;
+
+       inlen = MLX5_ST_SZ_BYTES(modify_tir_in);
+       in = mlx5_vzalloc(inlen);
+       if (!in)
+               return -ENOMEM;
+
+       MLX5_SET(modify_tir_in, in, bitmask.self_lb_en, 1);
+
+       err = mlx5_core_modify_tir(mdev, tirn, in, inlen);
+
+       kvfree(in);
+
+       return err;
+}
+
+static int mlx5e_refresh_tirs_self_loopback_enable(struct mlx5e_priv *priv)
+{
+       int err;
+       int i;
+
+       for (i = 0; i < MLX5E_NUM_TT; i++) {
+               err = mlx5e_refresh_tir_self_loopback_enable(priv->mdev,
+                                                            priv->tirn[i]);
+               if (err)
+                       return err;
+       }
+
+       return 0;
+}
+
 static int mlx5e_set_dev_port_mtu(struct net_device *netdev)
 {
        struct mlx5e_priv *priv = netdev_priv(netdev);
@@ -1376,6 +1412,13 @@ int mlx5e_open_locked(struct net_device *netdev)
                goto err_clear_state_opened_flag;
        }
 
+       err = mlx5e_refresh_tirs_self_loopback_enable(priv);
+       if (err) {
+               netdev_err(netdev, "%s: mlx5e_refresh_tirs_self_loopback_enable failed, %d\n",
+                          __func__, err);
+               goto err_close_channels;
+       }
+
        mlx5e_update_carrier(priv);
        mlx5e_redirect_rqts(priv);
 
@@ -1383,6 +1426,8 @@ int mlx5e_open_locked(struct net_device *netdev)
 
        return 0;
 
+err_close_channels:
+       mlx5e_close_channels(priv);
 err_clear_state_opened_flag:
        clear_bit(MLX5E_STATE_OPENED, &priv->state);
        return err;
@@ -1856,6 +1901,8 @@ static int mlx5e_change_mtu(struct net_device *netdev, int new_mtu)
 
        mlx5_query_port_max_mtu(mdev, &max_mtu, 1);
 
+       max_mtu = MLX5E_HW2SW_MTU(max_mtu);
+
        if (new_mtu > max_mtu) {
                netdev_err(netdev,
                           "%s: Bad MTU (%d) > (%d) Max\n",
@@ -1909,6 +1956,9 @@ static int mlx5e_check_required_hca_cap(struct mlx5_core_dev *mdev)
                               "Not creating net device, some required device capabilities are missing\n");
                return -ENOTSUPP;
        }
+       if (!MLX5_CAP_ETH(mdev, self_lb_en_modifiable))
+               mlx5_core_warn(mdev, "Self loop back prevention is not supported\n");
+
        return 0;
 }
 
index cd8f85a251d7da5509c0651b6ab781ce1d152084..1341b1d3c421d2a0f2050b7c0103853cbecf1cd6 100644 (file)
@@ -61,39 +61,47 @@ void mlx5e_send_nop(struct mlx5e_sq *sq, bool notify_hw)
        }
 }
 
-static void mlx5e_dma_pop_last_pushed(struct mlx5e_sq *sq, dma_addr_t *addr,
-                                     u32 *size)
+static inline void mlx5e_tx_dma_unmap(struct device *pdev,
+                                     struct mlx5e_sq_dma *dma)
 {
-       sq->dma_fifo_pc--;
-       *addr = sq->dma_fifo[sq->dma_fifo_pc & sq->dma_fifo_mask].addr;
-       *size = sq->dma_fifo[sq->dma_fifo_pc & sq->dma_fifo_mask].size;
-}
-
-static void mlx5e_dma_unmap_wqe_err(struct mlx5e_sq *sq, struct sk_buff *skb)
-{
-       dma_addr_t addr;
-       u32 size;
-       int i;
-
-       for (i = 0; i < MLX5E_TX_SKB_CB(skb)->num_dma; i++) {
-               mlx5e_dma_pop_last_pushed(sq, &addr, &size);
-               dma_unmap_single(sq->pdev, addr, size, DMA_TO_DEVICE);
+       switch (dma->type) {
+       case MLX5E_DMA_MAP_SINGLE:
+               dma_unmap_single(pdev, dma->addr, dma->size, DMA_TO_DEVICE);
+               break;
+       case MLX5E_DMA_MAP_PAGE:
+               dma_unmap_page(pdev, dma->addr, dma->size, DMA_TO_DEVICE);
+               break;
+       default:
+               WARN_ONCE(true, "mlx5e_tx_dma_unmap unknown DMA type!\n");
        }
 }
 
-static inline void mlx5e_dma_push(struct mlx5e_sq *sq, dma_addr_t addr,
-                                 u32 size)
+static inline void mlx5e_dma_push(struct mlx5e_sq *sq,
+                                 dma_addr_t addr,
+                                 u32 size,
+                                 enum mlx5e_dma_map_type map_type)
 {
        sq->dma_fifo[sq->dma_fifo_pc & sq->dma_fifo_mask].addr = addr;
        sq->dma_fifo[sq->dma_fifo_pc & sq->dma_fifo_mask].size = size;
+       sq->dma_fifo[sq->dma_fifo_pc & sq->dma_fifo_mask].type = map_type;
        sq->dma_fifo_pc++;
 }
 
-static inline void mlx5e_dma_get(struct mlx5e_sq *sq, u32 i, dma_addr_t *addr,
-                                u32 *size)
+static inline struct mlx5e_sq_dma *mlx5e_dma_get(struct mlx5e_sq *sq, u32 i)
 {
-       *addr = sq->dma_fifo[i & sq->dma_fifo_mask].addr;
-       *size = sq->dma_fifo[i & sq->dma_fifo_mask].size;
+       return &sq->dma_fifo[i & sq->dma_fifo_mask];
+}
+
+static void mlx5e_dma_unmap_wqe_err(struct mlx5e_sq *sq, struct sk_buff *skb)
+{
+       int i;
+
+       for (i = 0; i < MLX5E_TX_SKB_CB(skb)->num_dma; i++) {
+               struct mlx5e_sq_dma *last_pushed_dma =
+                       mlx5e_dma_get(sq, --sq->dma_fifo_pc);
+
+               mlx5e_tx_dma_unmap(sq->pdev, last_pushed_dma);
+       }
 }
 
 u16 mlx5e_select_queue(struct net_device *dev, struct sk_buff *skb,
@@ -118,8 +126,15 @@ static inline u16 mlx5e_get_inline_hdr_size(struct mlx5e_sq *sq,
         */
 #define MLX5E_MIN_INLINE ETH_HLEN
 
-       if (bf && (skb_headlen(skb) <= sq->max_inline))
-               return skb_headlen(skb);
+       if (bf) {
+               u16 ihs = skb_headlen(skb);
+
+               if (skb_vlan_tag_present(skb))
+                       ihs += VLAN_HLEN;
+
+               if (ihs <= sq->max_inline)
+                       return skb_headlen(skb);
+       }
 
        return MLX5E_MIN_INLINE;
 }
@@ -218,7 +233,7 @@ static netdev_tx_t mlx5e_sq_xmit(struct mlx5e_sq *sq, struct sk_buff *skb)
                dseg->lkey       = sq->mkey_be;
                dseg->byte_count = cpu_to_be32(headlen);
 
-               mlx5e_dma_push(sq, dma_addr, headlen);
+               mlx5e_dma_push(sq, dma_addr, headlen, MLX5E_DMA_MAP_SINGLE);
                MLX5E_TX_SKB_CB(skb)->num_dma++;
 
                dseg++;
@@ -237,7 +252,7 @@ static netdev_tx_t mlx5e_sq_xmit(struct mlx5e_sq *sq, struct sk_buff *skb)
                dseg->lkey       = sq->mkey_be;
                dseg->byte_count = cpu_to_be32(fsz);
 
-               mlx5e_dma_push(sq, dma_addr, fsz);
+               mlx5e_dma_push(sq, dma_addr, fsz, MLX5E_DMA_MAP_PAGE);
                MLX5E_TX_SKB_CB(skb)->num_dma++;
 
                dseg++;
@@ -353,13 +368,10 @@ bool mlx5e_poll_tx_cq(struct mlx5e_cq *cq)
                        }
 
                        for (j = 0; j < MLX5E_TX_SKB_CB(skb)->num_dma; j++) {
-                               dma_addr_t addr;
-                               u32 size;
+                               struct mlx5e_sq_dma *dma =
+                                       mlx5e_dma_get(sq, dma_fifo_cc++);
 
-                               mlx5e_dma_get(sq, dma_fifo_cc, &addr, &size);
-                               dma_fifo_cc++;
-                               dma_unmap_single(sq->pdev, addr, size,
-                                                DMA_TO_DEVICE);
+                               mlx5e_tx_dma_unmap(sq->pdev, dma);
                        }
 
                        npkts++;
index b83f7c0fcf9965b30fd179f72fa821b87d928bfd..122c2ee3dfe2aaa5948efd35158bf2fdf32bc0d5 100644 (file)
@@ -1937,6 +1937,12 @@ static void refill_rx(struct net_device *dev)
                                break; /* Better luck next round. */
                        np->rx_dma[entry] = pci_map_single(np->pci_dev,
                                skb->data, buflen, PCI_DMA_FROMDEVICE);
+                       if (pci_dma_mapping_error(np->pci_dev,
+                                                 np->rx_dma[entry])) {
+                               dev_kfree_skb_any(skb);
+                               np->rx_skbuff[entry] = NULL;
+                               break; /* Better luck next round. */
+                       }
                        np->rx_ring[entry].addr = cpu_to_le32(np->rx_dma[entry]);
                }
                np->rx_ring[entry].cmd_status = cpu_to_le32(np->rx_buf_sz);
@@ -2093,6 +2099,12 @@ static netdev_tx_t start_tx(struct sk_buff *skb, struct net_device *dev)
        np->tx_skbuff[entry] = skb;
        np->tx_dma[entry] = pci_map_single(np->pci_dev,
                                skb->data,skb->len, PCI_DMA_TODEVICE);
+       if (pci_dma_mapping_error(np->pci_dev, np->tx_dma[entry])) {
+               np->tx_skbuff[entry] = NULL;
+               dev_kfree_skb_irq(skb);
+               dev->stats.tx_dropped++;
+               return NETDEV_TX_OK;
+       }
 
        np->tx_ring[entry].addr = cpu_to_le32(np->tx_dma[entry]);
 
index b159ef8303cc3e65d1e374367d19ca590d934901..057665180f13f3d9980eac2b807793675df16021 100644 (file)
@@ -1326,7 +1326,7 @@ static int lpc_eth_drv_probe(struct platform_device *pdev)
        /* Get platform resources */
        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
        irq = platform_get_irq(pdev, 0);
-       if ((!res) || (irq < 0) || (irq >= NR_IRQS)) {
+       if (!res || irq < 0) {
                dev_err(&pdev->dev, "error getting resources.\n");
                ret = -ENXIO;
                goto err_exit;
index ac17d8669b1adad9291a6a39646b51ff80693176..1292c360390cd79d532ca155158858bd630648d5 100644 (file)
@@ -299,6 +299,7 @@ struct qed_hwfn {
 
        /* Flag indicating whether interrupts are enabled or not*/
        bool                            b_int_enabled;
+       bool                            b_int_requested;
 
        struct qed_mcp_info             *mcp_info;
 
@@ -491,6 +492,8 @@ u32 qed_unzip_data(struct qed_hwfn *p_hwfn,
                   u32 input_len, u8 *input_buf,
                   u32 max_size, u8 *unzip_buf);
 
+int qed_slowpath_irq_req(struct qed_hwfn *hwfn);
+
 #define QED_ETH_INTERFACE_VERSION       300
 
 #endif /* _QED_H */
index 803b190ccada97b30b28098666146f9d05ad1c54..817bbd5476ffb5956fca105686fc9029d06339ff 100644 (file)
@@ -1385,52 +1385,63 @@ err0:
        return rc;
 }
 
-static u32 qed_hw_bar_size(struct qed_dev *cdev,
-                          u8 bar_id)
+static u32 qed_hw_bar_size(struct qed_hwfn     *p_hwfn,
+                          u8                   bar_id)
 {
-       u32 size = pci_resource_len(cdev->pdev, (bar_id > 0) ? 2 : 0);
+       u32 bar_reg = (bar_id == 0 ? PGLUE_B_REG_PF_BAR0_SIZE
+                      : PGLUE_B_REG_PF_BAR1_SIZE);
+       u32 val = qed_rd(p_hwfn, p_hwfn->p_main_ptt, bar_reg);
 
-       return size / cdev->num_hwfns;
+       /* Get the BAR size(in KB) from hardware given val */
+       return 1 << (val + 15);
 }
 
 int qed_hw_prepare(struct qed_dev *cdev,
                   int personality)
 {
-       int rc, i;
+       struct qed_hwfn *p_hwfn = QED_LEADING_HWFN(cdev);
+       int rc;
 
        /* Store the precompiled init data ptrs */
        qed_init_iro_array(cdev);
 
        /* Initialize the first hwfn - will learn number of hwfns */
-       rc = qed_hw_prepare_single(&cdev->hwfns[0], cdev->regview,
+       rc = qed_hw_prepare_single(p_hwfn,
+                                  cdev->regview,
                                   cdev->doorbells, personality);
        if (rc)
                return rc;
 
-       personality = cdev->hwfns[0].hw_info.personality;
+       personality = p_hwfn->hw_info.personality;
 
        /* Initialize the rest of the hwfns */
-       for (i = 1; i < cdev->num_hwfns; i++) {
+       if (cdev->num_hwfns > 1) {
                void __iomem *p_regview, *p_doorbell;
+               u8 __iomem *addr;
+
+               /* adjust bar offset for second engine */
+               addr = cdev->regview + qed_hw_bar_size(p_hwfn, 0) / 2;
+               p_regview = addr;
 
-               p_regview =  cdev->regview +
-                            i * qed_hw_bar_size(cdev, 0);
-               p_doorbell = cdev->doorbells +
-                            i * qed_hw_bar_size(cdev, 1);
-               rc = qed_hw_prepare_single(&cdev->hwfns[i], p_regview,
+               /* adjust doorbell bar offset for second engine */
+               addr = cdev->doorbells + qed_hw_bar_size(p_hwfn, 1) / 2;
+               p_doorbell = addr;
+
+               /* prepare second hw function */
+               rc = qed_hw_prepare_single(&cdev->hwfns[1], p_regview,
                                           p_doorbell, personality);
+
+               /* in case of error, need to free the previously
+                * initiliazed hwfn 0.
+                */
                if (rc) {
-                       /* Cleanup previously initialized hwfns */
-                       while (--i >= 0) {
-                               qed_init_free(&cdev->hwfns[i]);
-                               qed_mcp_free(&cdev->hwfns[i]);
-                               qed_hw_hwfn_free(&cdev->hwfns[i]);
-                       }
-                       return rc;
+                       qed_init_free(p_hwfn);
+                       qed_mcp_free(p_hwfn);
+                       qed_hw_hwfn_free(p_hwfn);
                }
        }
 
-       return 0;
+       return rc;
 }
 
 void qed_hw_remove(struct qed_dev *cdev)
index de50e84902afe3b6a26c422d34a687ec9bc523ec..9cc9d62c1fec64844eba85ca10213a77d3158227 100644 (file)
@@ -783,22 +783,16 @@ void qed_int_igu_enable_int(struct qed_hwfn *p_hwfn,
        qed_wr(p_hwfn, p_ptt, IGU_REG_PF_CONFIGURATION, igu_pf_conf);
 }
 
-void qed_int_igu_enable(struct qed_hwfn *p_hwfn,
-                       struct qed_ptt *p_ptt,
-                       enum qed_int_mode int_mode)
+int qed_int_igu_enable(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt,
+                      enum qed_int_mode int_mode)
 {
-       int i;
-
-       p_hwfn->b_int_enabled = 1;
+       int rc, i;
 
        /* Mask non-link attentions */
        for (i = 0; i < 9; i++)
                qed_wr(p_hwfn, p_ptt,
                       MISC_REG_AEU_ENABLE1_IGU_OUT_0 + (i << 2), 0);
 
-       /* Enable interrupt Generation */
-       qed_int_igu_enable_int(p_hwfn, p_ptt, int_mode);
-
        /* Configure AEU signal change to produce attentions for link */
        qed_wr(p_hwfn, p_ptt, IGU_REG_LEADING_EDGE_LATCH, 0xfff);
        qed_wr(p_hwfn, p_ptt, IGU_REG_TRAILING_EDGE_LATCH, 0xfff);
@@ -808,6 +802,19 @@ void qed_int_igu_enable(struct qed_hwfn *p_hwfn,
 
        /* Unmask AEU signals toward IGU */
        qed_wr(p_hwfn, p_ptt, MISC_REG_AEU_MASK_ATTN_IGU, 0xff);
+       if ((int_mode != QED_INT_MODE_INTA) || IS_LEAD_HWFN(p_hwfn)) {
+               rc = qed_slowpath_irq_req(p_hwfn);
+               if (rc != 0) {
+                       DP_NOTICE(p_hwfn, "Slowpath IRQ request failed\n");
+                       return -EINVAL;
+               }
+               p_hwfn->b_int_requested = true;
+       }
+       /* Enable interrupt Generation */
+       qed_int_igu_enable_int(p_hwfn, p_ptt, int_mode);
+       p_hwfn->b_int_enabled = 1;
+
+       return rc;
 }
 
 void qed_int_igu_disable_int(struct qed_hwfn *p_hwfn,
@@ -1127,3 +1134,11 @@ int qed_int_get_num_sbs(struct qed_hwfn *p_hwfn,
 
        return info->igu_sb_cnt;
 }
+
+void qed_int_disable_post_isr_release(struct qed_dev *cdev)
+{
+       int i;
+
+       for_each_hwfn(cdev, i)
+               cdev->hwfns[i].b_int_requested = false;
+}
index 16b57518e706728dde646688fb059a3f8f88bb97..51e0b09a7f47d3da8ca9c1d2d0982aa2e77d51f4 100644 (file)
@@ -169,10 +169,14 @@ int qed_int_get_num_sbs(struct qed_hwfn *p_hwfn,
                        int *p_iov_blks);
 
 /**
- * @file
+ * @brief qed_int_disable_post_isr_release - performs the cleanup post ISR
+ *        release. The API need to be called after releasing all slowpath IRQs
+ *        of the device.
+ *
+ * @param cdev
  *
- * @brief Interrupt handler
  */
+void qed_int_disable_post_isr_release(struct qed_dev *cdev);
 
 #define QED_CAU_DEF_RX_TIMER_RES 0
 #define QED_CAU_DEF_TX_TIMER_RES 0
@@ -366,10 +370,11 @@ void qed_int_setup(struct qed_hwfn *p_hwfn,
  * @param p_hwfn
  * @param p_ptt
  * @param int_mode
+ *
+ * @return int
  */
-void qed_int_igu_enable(struct qed_hwfn *p_hwfn,
-                       struct qed_ptt *p_ptt,
-                       enum qed_int_mode int_mode);
+int qed_int_igu_enable(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt,
+                      enum qed_int_mode int_mode);
 
 /**
  * @brief - Initialize CAU status block entry
index 947c7af72b25b32db163dc3ea47ca7d63db50490..174f7341c5c32c2bbcf81391b02f6d9a6d9327c2 100644 (file)
@@ -476,41 +476,22 @@ static irqreturn_t qed_single_int(int irq, void *dev_instance)
        return rc;
 }
 
-static int qed_slowpath_irq_req(struct qed_dev *cdev)
+int qed_slowpath_irq_req(struct qed_hwfn *hwfn)
 {
-       int i = 0, rc = 0;
+       struct qed_dev *cdev = hwfn->cdev;
+       int rc = 0;
+       u8 id;
 
        if (cdev->int_params.out.int_mode == QED_INT_MODE_MSIX) {
-               /* Request all the slowpath MSI-X vectors */
-               for (i = 0; i < cdev->num_hwfns; i++) {
-                       snprintf(cdev->hwfns[i].name, NAME_SIZE,
-                                "sp-%d-%02x:%02x.%02x",
-                                i, cdev->pdev->bus->number,
-                                PCI_SLOT(cdev->pdev->devfn),
-                                cdev->hwfns[i].abs_pf_id);
-
-                       rc = request_irq(cdev->int_params.msix_table[i].vector,
-                                        qed_msix_sp_int, 0,
-                                        cdev->hwfns[i].name,
-                                        cdev->hwfns[i].sp_dpc);
-                       if (rc)
-                               break;
-
-                       DP_VERBOSE(&cdev->hwfns[i],
-                                  (NETIF_MSG_INTR | QED_MSG_SP),
+               id = hwfn->my_id;
+               snprintf(hwfn->name, NAME_SIZE, "sp-%d-%02x:%02x.%02x",
+                        id, cdev->pdev->bus->number,
+                        PCI_SLOT(cdev->pdev->devfn), hwfn->abs_pf_id);
+               rc = request_irq(cdev->int_params.msix_table[id].vector,
+                                qed_msix_sp_int, 0, hwfn->name, hwfn->sp_dpc);
+               if (!rc)
+                       DP_VERBOSE(hwfn, (NETIF_MSG_INTR | QED_MSG_SP),
                                   "Requested slowpath MSI-X\n");
-               }
-
-               if (i != cdev->num_hwfns) {
-                       /* Free already request MSI-X vectors */
-                       for (i--; i >= 0; i--) {
-                               unsigned int vec =
-                                       cdev->int_params.msix_table[i].vector;
-                               synchronize_irq(vec);
-                               free_irq(cdev->int_params.msix_table[i].vector,
-                                        cdev->hwfns[i].sp_dpc);
-                       }
-               }
        } else {
                unsigned long flags = 0;
 
@@ -534,13 +515,17 @@ static void qed_slowpath_irq_free(struct qed_dev *cdev)
 
        if (cdev->int_params.out.int_mode == QED_INT_MODE_MSIX) {
                for_each_hwfn(cdev, i) {
+                       if (!cdev->hwfns[i].b_int_requested)
+                               break;
                        synchronize_irq(cdev->int_params.msix_table[i].vector);
                        free_irq(cdev->int_params.msix_table[i].vector,
                                 cdev->hwfns[i].sp_dpc);
                }
        } else {
-               free_irq(cdev->pdev->irq, cdev);
+               if (QED_LEADING_HWFN(cdev)->b_int_requested)
+                       free_irq(cdev->pdev->irq, cdev);
        }
+       qed_int_disable_post_isr_release(cdev);
 }
 
 static int qed_nic_stop(struct qed_dev *cdev)
@@ -765,16 +750,11 @@ static int qed_slowpath_start(struct qed_dev *cdev,
        if (rc)
                goto err1;
 
-       /* Request the slowpath IRQ */
-       rc = qed_slowpath_irq_req(cdev);
-       if (rc)
-               goto err2;
-
        /* Allocate stream for unzipping */
        rc = qed_alloc_stream_mem(cdev);
        if (rc) {
                DP_NOTICE(cdev, "Failed to allocate stream memory\n");
-               goto err3;
+               goto err2;
        }
 
        /* Start the slowpath */
index 7a5ce5914ace2287ec73afa20ed2d9d5eb328108..e8df12335a972cd3092cbefa8b675408446f06c9 100644 (file)
                0x7 << 0)
 #define  MCP_REG_NVM_CFG4_FLASH_SIZE_SHIFT \
        0
+#define PGLUE_B_REG_PF_BAR0_SIZE \
+       0x2aae60UL
+#define PGLUE_B_REG_PF_BAR1_SIZE \
+       0x2aae64UL
 #endif
index 31a1f1eb4f56a5d00f0ce3ae75a29af56a96ef12..287fadfab52d754e0a913d4ed044ca7e50cf1a09 100644 (file)
@@ -124,8 +124,12 @@ struct qed_spq {
        dma_addr_t              p_phys;
        struct qed_spq_entry    *p_virt;
 
-       /* Used as index for completions (returns on EQ by FW) */
-       u16                     echo_idx;
+#define SPQ_RING_SIZE \
+       (CORE_SPQE_PAGE_SIZE_BYTES / sizeof(struct slow_path_element))
+
+       /* Bitmap for handling out-of-order completions */
+       DECLARE_BITMAP(p_comp_bitmap, SPQ_RING_SIZE);
+       u8                      comp_bitmap_idx;
 
        /* Statistics */
        u32                     unlimited_pending_count;
index 7c0b8459666ed270ec754a87c9fa1c072d16dd49..3dd548ab8df14aabf9fa6a551cf54aa97f704d12 100644 (file)
@@ -112,8 +112,6 @@ static int
 qed_spq_fill_entry(struct qed_hwfn *p_hwfn,
                   struct qed_spq_entry *p_ent)
 {
-       p_ent->elem.hdr.echo = 0;
-       p_hwfn->p_spq->echo_idx++;
        p_ent->flags = 0;
 
        switch (p_ent->comp_mode) {
@@ -195,10 +193,12 @@ static int qed_spq_hw_post(struct qed_hwfn *p_hwfn,
                           struct qed_spq *p_spq,
                           struct qed_spq_entry *p_ent)
 {
-       struct qed_chain                *p_chain = &p_hwfn->p_spq->chain;
+       struct qed_chain *p_chain = &p_hwfn->p_spq->chain;
+       u16 echo = qed_chain_get_prod_idx(p_chain);
        struct slow_path_element        *elem;
        struct core_db_data             db;
 
+       p_ent->elem.hdr.echo    = cpu_to_le16(echo);
        elem = qed_chain_produce(p_chain);
        if (!elem) {
                DP_NOTICE(p_hwfn, "Failed to produce from SPQ chain\n");
@@ -437,7 +437,9 @@ void qed_spq_setup(struct qed_hwfn *p_hwfn)
        p_spq->comp_count               = 0;
        p_spq->comp_sent_count          = 0;
        p_spq->unlimited_pending_count  = 0;
-       p_spq->echo_idx                 = 0;
+
+       bitmap_zero(p_spq->p_comp_bitmap, SPQ_RING_SIZE);
+       p_spq->comp_bitmap_idx = 0;
 
        /* SPQ cid, cannot fail */
        qed_cxt_acquire_cid(p_hwfn, PROTOCOLID_CORE, &p_spq->cid);
@@ -582,26 +584,32 @@ qed_spq_add_entry(struct qed_hwfn *p_hwfn,
        struct qed_spq *p_spq = p_hwfn->p_spq;
 
        if (p_ent->queue == &p_spq->unlimited_pending) {
-               struct qed_spq_entry *p_en2;
 
                if (list_empty(&p_spq->free_pool)) {
                        list_add_tail(&p_ent->list, &p_spq->unlimited_pending);
                        p_spq->unlimited_pending_count++;
 
                        return 0;
-               }
+               } else {
+                       struct qed_spq_entry *p_en2;
 
-               p_en2 = list_first_entry(&p_spq->free_pool,
-                                        struct qed_spq_entry,
-                                        list);
-               list_del(&p_en2->list);
+                       p_en2 = list_first_entry(&p_spq->free_pool,
+                                                struct qed_spq_entry,
+                                                list);
+                       list_del(&p_en2->list);
+
+                       /* Copy the ring element physical pointer to the new
+                        * entry, since we are about to override the entire ring
+                        * entry and don't want to lose the pointer.
+                        */
+                       p_ent->elem.data_ptr = p_en2->elem.data_ptr;
 
-               /* Strcut assignment */
-               *p_en2 = *p_ent;
+                       *p_en2 = *p_ent;
 
-               kfree(p_ent);
+                       kfree(p_ent);
 
-               p_ent = p_en2;
+                       p_ent = p_en2;
+               }
        }
 
        /* entry is to be placed in 'pending' queue */
@@ -777,13 +785,38 @@ int qed_spq_completion(struct qed_hwfn *p_hwfn,
        list_for_each_entry_safe(p_ent, tmp, &p_spq->completion_pending,
                                 list) {
                if (p_ent->elem.hdr.echo == echo) {
+                       u16 pos = le16_to_cpu(echo) % SPQ_RING_SIZE;
+
                        list_del(&p_ent->list);
 
-                       qed_chain_return_produced(&p_spq->chain);
+                       /* Avoid overriding of SPQ entries when getting
+                        * out-of-order completions, by marking the completions
+                        * in a bitmap and increasing the chain consumer only
+                        * for the first successive completed entries.
+                        */
+                       bitmap_set(p_spq->p_comp_bitmap, pos, SPQ_RING_SIZE);
+
+                       while (test_bit(p_spq->comp_bitmap_idx,
+                                       p_spq->p_comp_bitmap)) {
+                               bitmap_clear(p_spq->p_comp_bitmap,
+                                            p_spq->comp_bitmap_idx,
+                                            SPQ_RING_SIZE);
+                               p_spq->comp_bitmap_idx++;
+                               qed_chain_return_produced(&p_spq->chain);
+                       }
+
                        p_spq->comp_count++;
                        found = p_ent;
                        break;
                }
+
+               /* This is relatively uncommon - depends on scenarios
+                * which have mutliple per-PF sent ramrods.
+                */
+               DP_VERBOSE(p_hwfn, QED_MSG_SPQ,
+                          "Got completion for echo %04x - doesn't match echo %04x in completion pending list\n",
+                          le16_to_cpu(echo),
+                          le16_to_cpu(p_ent->elem.hdr.echo));
        }
 
        /* Release lock before callback, as callback may post
index be7d7a62cc0d8c885c1f669f6c01f0f3a2259ea0..34906750b7e7091f5af122be88c659fd1c77f2e1 100644 (file)
@@ -246,12 +246,13 @@ int qlcnic_83xx_check_vnic_state(struct qlcnic_adapter *adapter)
        u32 state;
 
        state = QLCRDX(ahw, QLC_83XX_VNIC_STATE);
-       while (state != QLCNIC_DEV_NPAR_OPER && idc->vnic_wait_limit--) {
+       while (state != QLCNIC_DEV_NPAR_OPER && idc->vnic_wait_limit) {
+               idc->vnic_wait_limit--;
                msleep(1000);
                state = QLCRDX(ahw, QLC_83XX_VNIC_STATE);
        }
 
-       if (!idc->vnic_wait_limit) {
+       if (state != QLCNIC_DEV_NPAR_OPER) {
                dev_err(&adapter->pdev->dev,
                        "vNIC mode not operational, state check timed out.\n");
                return -EIO;
index 02b7115b6aaa64add8632094f6f0dfe354a89b7d..997976426799d90a328cef4ff958b92ce3ba491c 100644 (file)
@@ -4211,8 +4211,9 @@ static int ql_change_rx_buffers(struct ql_adapter *qdev)
 
        /* Wait for an outstanding reset to complete. */
        if (!test_bit(QL_ADAPTER_UP, &qdev->flags)) {
-               int i = 3;
-               while (i-- && !test_bit(QL_ADAPTER_UP, &qdev->flags)) {
+               int i = 4;
+
+               while (--i && !test_bit(QL_ADAPTER_UP, &qdev->flags)) {
                        netif_err(qdev, ifup, qdev->ndev,
                                  "Waiting for adapter UP...\n");
                        ssleep(1);
index ddb2c6c6ec94013efb5ada465d2c6446c34de5f0..689a4a5c8dcfc30fba2675e17293e98691648dd2 100644 (file)
@@ -736,9 +736,8 @@ qcaspi_netdev_tx_timeout(struct net_device *dev)
        netdev_info(qca->net_dev, "Transmit timeout at %ld, latency %ld\n",
                    jiffies, jiffies - dev->trans_start);
        qca->net_dev->stats.tx_errors++;
-       /* wake the queue if there is room */
-       if (qcaspi_tx_ring_has_space(&qca->txr))
-               netif_wake_queue(dev);
+       /* Trigger tx queue flush and QCA7000 reset */
+       qca->sync = QCASPI_SYNC_UNKNOWN;
 }
 
 static int
index b4f21232019a98c7e0afd9e5a43a5a160da765fe..79ef799f88ab1fc2518736163c5674aec360c065 100644 (file)
@@ -7429,15 +7429,15 @@ process_pkt:
 
                        rtl8169_rx_vlan_tag(desc, skb);
 
+                       if (skb->pkt_type == PACKET_MULTICAST)
+                               dev->stats.multicast++;
+
                        napi_gro_receive(&tp->napi, skb);
 
                        u64_stats_update_begin(&tp->rx_stats.syncp);
                        tp->rx_stats.packets++;
                        tp->rx_stats.bytes += pkt_size;
                        u64_stats_update_end(&tp->rx_stats.syncp);
-
-                       if (skb->pkt_type == PACKET_MULTICAST)
-                               dev->stats.multicast++;
                }
 release_descriptor:
                desc->opts2 = 0;
index aa7b2083cb539c15c8b831e4c0703ab16375a0ae..467d41698fd534e724d53ce03e35091bd01cdcdb 100644 (file)
@@ -408,8 +408,6 @@ static int ravb_dmac_init(struct net_device *ndev)
        /* Interrupt enable: */
        /* Frame receive */
        ravb_write(ndev, RIC0_FRE0 | RIC0_FRE1, RIC0);
-       /* Receive FIFO full warning */
-       ravb_write(ndev, RIC1_RFWE, RIC1);
        /* Receive FIFO full error, descriptor empty */
        ravb_write(ndev, RIC2_QFE0 | RIC2_QFE1 | RIC2_RFFE, RIC2);
        /* Frame transmitted, timestamp FIFO updated */
@@ -733,8 +731,10 @@ static irqreturn_t ravb_interrupt(int irq, void *dev_id)
                            ((tis  & tic)  & BIT(q))) {
                                if (napi_schedule_prep(&priv->napi[q])) {
                                        /* Mask RX and TX interrupts */
-                                       ravb_write(ndev, ric0 & ~BIT(q), RIC0);
-                                       ravb_write(ndev, tic  & ~BIT(q), TIC);
+                                       ric0 &= ~BIT(q);
+                                       tic &= ~BIT(q);
+                                       ravb_write(ndev, ric0, RIC0);
+                                       ravb_write(ndev, tic, TIC);
                                        __napi_schedule(&priv->napi[q]);
                                } else {
                                        netdev_warn(ndev,
@@ -905,6 +905,9 @@ static int ravb_phy_init(struct net_device *ndev)
                netdev_info(ndev, "limited PHY to 100Mbit/s\n");
        }
 
+       /* 10BASE is not supported */
+       phydev->supported &= ~PHY_10BT_FEATURES;
+
        netdev_info(ndev, "attached PHY %d (IRQ %d) to driver %s\n",
                    phydev->addr, phydev->irq, phydev->drv->name);
 
@@ -1037,7 +1040,7 @@ static const char ravb_gstrings_stats[][ETH_GSTRING_LEN] = {
        "rx_queue_1_mcast_packets",
        "rx_queue_1_errors",
        "rx_queue_1_crc_errors",
-       "rx_queue_1_frame_errors_",
+       "rx_queue_1_frame_errors",
        "rx_queue_1_length_errors",
        "rx_queue_1_missed_errors",
        "rx_queue_1_over_errors",
@@ -1225,7 +1228,7 @@ static int ravb_open(struct net_device *ndev)
        /* Device init */
        error = ravb_dmac_init(ndev);
        if (error)
-               goto out_free_irq;
+               goto out_free_irq2;
        ravb_emac_init(ndev);
 
        /* Initialise PTP Clock driver */
@@ -1243,9 +1246,11 @@ static int ravb_open(struct net_device *ndev)
 out_ptp_stop:
        /* Stop PTP Clock driver */
        ravb_ptp_stop(ndev);
+out_free_irq2:
+       if (priv->chip_id == RCAR_GEN3)
+               free_irq(priv->emac_irq, ndev);
 out_free_irq:
        free_irq(ndev->irq, ndev);
-       free_irq(priv->emac_irq, ndev);
 out_napi_off:
        napi_disable(&priv->napi[RAVB_NC]);
        napi_disable(&priv->napi[RAVB_BE]);
index e7bab7909ed9e1868dd5f8457b3cfc96c92788f1..6a8fc0f341ff2528fdda1cb97f8e2934d99c5f14 100644 (file)
@@ -52,6 +52,8 @@
                NETIF_MSG_RX_ERR| \
                NETIF_MSG_TX_ERR)
 
+#define SH_ETH_OFFSET_INVALID  ((u16)~0)
+
 #define SH_ETH_OFFSET_DEFAULTS                 \
        [0 ... SH_ETH_MAX_REGISTER_OFFSET - 1] = SH_ETH_OFFSET_INVALID
 
@@ -404,6 +406,28 @@ static const u16 sh_eth_offset_fast_sh3_sh2[SH_ETH_MAX_REGISTER_OFFSET] = {
 static void sh_eth_rcv_snd_disable(struct net_device *ndev);
 static struct net_device_stats *sh_eth_get_stats(struct net_device *ndev);
 
+static void sh_eth_write(struct net_device *ndev, u32 data, int enum_index)
+{
+       struct sh_eth_private *mdp = netdev_priv(ndev);
+       u16 offset = mdp->reg_offset[enum_index];
+
+       if (WARN_ON(offset == SH_ETH_OFFSET_INVALID))
+               return;
+
+       iowrite32(data, mdp->addr + offset);
+}
+
+static u32 sh_eth_read(struct net_device *ndev, int enum_index)
+{
+       struct sh_eth_private *mdp = netdev_priv(ndev);
+       u16 offset = mdp->reg_offset[enum_index];
+
+       if (WARN_ON(offset == SH_ETH_OFFSET_INVALID))
+               return ~0U;
+
+       return ioread32(mdp->addr + offset);
+}
+
 static bool sh_eth_is_gether(struct sh_eth_private *mdp)
 {
        return mdp->reg_offset == sh_eth_offset_gigabit;
@@ -1143,6 +1167,7 @@ static void sh_eth_ring_format(struct net_device *ndev)
        int tx_ringsize = sizeof(*txdesc) * mdp->num_tx_ring;
        int skbuff_size = mdp->rx_buf_sz + SH_ETH_RX_ALIGN + 32 - 1;
        dma_addr_t dma_addr;
+       u32 buf_len;
 
        mdp->cur_rx = 0;
        mdp->cur_tx = 0;
@@ -1163,16 +1188,16 @@ static void sh_eth_ring_format(struct net_device *ndev)
                /* RX descriptor */
                rxdesc = &mdp->rx_ring[i];
                /* The size of the buffer is a multiple of 32 bytes. */
-               rxdesc->buffer_length = ALIGN(mdp->rx_buf_sz, 32);
-               dma_addr = dma_map_single(&ndev->dev, skb->data,
-                                         rxdesc->buffer_length,
+               buf_len = ALIGN(mdp->rx_buf_sz, 32);
+               rxdesc->len = cpu_to_edmac(mdp, buf_len << 16);
+               dma_addr = dma_map_single(&ndev->dev, skb->data, buf_len,
                                          DMA_FROM_DEVICE);
                if (dma_mapping_error(&ndev->dev, dma_addr)) {
                        kfree_skb(skb);
                        break;
                }
                mdp->rx_skbuff[i] = skb;
-               rxdesc->addr = dma_addr;
+               rxdesc->addr = cpu_to_edmac(mdp, dma_addr);
                rxdesc->status = cpu_to_edmac(mdp, RD_RACT | RD_RFP);
 
                /* Rx descriptor address set */
@@ -1196,7 +1221,7 @@ static void sh_eth_ring_format(struct net_device *ndev)
                mdp->tx_skbuff[i] = NULL;
                txdesc = &mdp->tx_ring[i];
                txdesc->status = cpu_to_edmac(mdp, TD_TFP);
-               txdesc->buffer_length = 0;
+               txdesc->len = cpu_to_edmac(mdp, 0);
                if (i == 0) {
                        /* Tx descriptor address set */
                        sh_eth_write(ndev, mdp->tx_desc_dma, TDLAR);
@@ -1403,8 +1428,10 @@ static int sh_eth_txfree(struct net_device *ndev)
                           entry, edmac_to_cpu(mdp, txdesc->status));
                /* Free the original skb. */
                if (mdp->tx_skbuff[entry]) {
-                       dma_unmap_single(&ndev->dev, txdesc->addr,
-                                        txdesc->buffer_length, DMA_TO_DEVICE);
+                       dma_unmap_single(&ndev->dev,
+                                        edmac_to_cpu(mdp, txdesc->addr),
+                                        edmac_to_cpu(mdp, txdesc->len) >> 16,
+                                        DMA_TO_DEVICE);
                        dev_kfree_skb_irq(mdp->tx_skbuff[entry]);
                        mdp->tx_skbuff[entry] = NULL;
                        free_num++;
@@ -1414,7 +1441,7 @@ static int sh_eth_txfree(struct net_device *ndev)
                        txdesc->status |= cpu_to_edmac(mdp, TD_TDLE);
 
                ndev->stats.tx_packets++;
-               ndev->stats.tx_bytes += txdesc->buffer_length;
+               ndev->stats.tx_bytes += edmac_to_cpu(mdp, txdesc->len) >> 16;
        }
        return free_num;
 }
@@ -1433,6 +1460,7 @@ static int sh_eth_rx(struct net_device *ndev, u32 intr_status, int *quota)
        u32 desc_status;
        int skbuff_size = mdp->rx_buf_sz + SH_ETH_RX_ALIGN + 32 - 1;
        dma_addr_t dma_addr;
+       u32 buf_len;
 
        boguscnt = min(boguscnt, *quota);
        limit = boguscnt;
@@ -1441,7 +1469,7 @@ static int sh_eth_rx(struct net_device *ndev, u32 intr_status, int *quota)
                /* RACT bit must be checked before all the following reads */
                dma_rmb();
                desc_status = edmac_to_cpu(mdp, rxdesc->status);
-               pkt_len = rxdesc->frame_length;
+               pkt_len = edmac_to_cpu(mdp, rxdesc->len) & RD_RFL;
 
                if (--boguscnt < 0)
                        break;
@@ -1462,6 +1490,7 @@ static int sh_eth_rx(struct net_device *ndev, u32 intr_status, int *quota)
                if (mdp->cd->shift_rd0)
                        desc_status >>= 16;
 
+               skb = mdp->rx_skbuff[entry];
                if (desc_status & (RD_RFS1 | RD_RFS2 | RD_RFS3 | RD_RFS4 |
                                   RD_RFS5 | RD_RFS6 | RD_RFS10)) {
                        ndev->stats.rx_errors++;
@@ -1477,16 +1506,16 @@ static int sh_eth_rx(struct net_device *ndev, u32 intr_status, int *quota)
                                ndev->stats.rx_missed_errors++;
                        if (desc_status & RD_RFS10)
                                ndev->stats.rx_over_errors++;
-               } else {
+               } else  if (skb) {
+                       dma_addr = edmac_to_cpu(mdp, rxdesc->addr);
                        if (!mdp->cd->hw_swap)
                                sh_eth_soft_swap(
-                                       phys_to_virt(ALIGN(rxdesc->addr, 4)),
+                                       phys_to_virt(ALIGN(dma_addr, 4)),
                                        pkt_len + 2);
-                       skb = mdp->rx_skbuff[entry];
                        mdp->rx_skbuff[entry] = NULL;
                        if (mdp->cd->rpadir)
                                skb_reserve(skb, NET_IP_ALIGN);
-                       dma_unmap_single(&ndev->dev, rxdesc->addr,
+                       dma_unmap_single(&ndev->dev, dma_addr,
                                         ALIGN(mdp->rx_buf_sz, 32),
                                         DMA_FROM_DEVICE);
                        skb_put(skb, pkt_len);
@@ -1506,7 +1535,8 @@ static int sh_eth_rx(struct net_device *ndev, u32 intr_status, int *quota)
                entry = mdp->dirty_rx % mdp->num_rx_ring;
                rxdesc = &mdp->rx_ring[entry];
                /* The size of the buffer is 32 byte boundary. */
-               rxdesc->buffer_length = ALIGN(mdp->rx_buf_sz, 32);
+               buf_len = ALIGN(mdp->rx_buf_sz, 32);
+               rxdesc->len = cpu_to_edmac(mdp, buf_len << 16);
 
                if (mdp->rx_skbuff[entry] == NULL) {
                        skb = netdev_alloc_skb(ndev, skbuff_size);
@@ -1514,8 +1544,7 @@ static int sh_eth_rx(struct net_device *ndev, u32 intr_status, int *quota)
                                break;  /* Better luck next round. */
                        sh_eth_set_receive_align(skb);
                        dma_addr = dma_map_single(&ndev->dev, skb->data,
-                                                 rxdesc->buffer_length,
-                                                 DMA_FROM_DEVICE);
+                                                 buf_len, DMA_FROM_DEVICE);
                        if (dma_mapping_error(&ndev->dev, dma_addr)) {
                                kfree_skb(skb);
                                break;
@@ -1523,7 +1552,7 @@ static int sh_eth_rx(struct net_device *ndev, u32 intr_status, int *quota)
                        mdp->rx_skbuff[entry] = skb;
 
                        skb_checksum_none_assert(skb);
-                       rxdesc->addr = dma_addr;
+                       rxdesc->addr = cpu_to_edmac(mdp, dma_addr);
                }
                dma_wmb(); /* RACT bit must be set after all the above writes */
                if (entry >= mdp->num_rx_ring - 1)
@@ -2331,8 +2360,8 @@ static void sh_eth_tx_timeout(struct net_device *ndev)
        /* Free all the skbuffs in the Rx queue. */
        for (i = 0; i < mdp->num_rx_ring; i++) {
                rxdesc = &mdp->rx_ring[i];
-               rxdesc->status = 0;
-               rxdesc->addr = 0xBADF00D0;
+               rxdesc->status = cpu_to_edmac(mdp, 0);
+               rxdesc->addr = cpu_to_edmac(mdp, 0xBADF00D0);
                dev_kfree_skb(mdp->rx_skbuff[i]);
                mdp->rx_skbuff[i] = NULL;
        }
@@ -2350,6 +2379,7 @@ static int sh_eth_start_xmit(struct sk_buff *skb, struct net_device *ndev)
 {
        struct sh_eth_private *mdp = netdev_priv(ndev);
        struct sh_eth_txdesc *txdesc;
+       dma_addr_t dma_addr;
        u32 entry;
        unsigned long flags;
 
@@ -2372,15 +2402,15 @@ static int sh_eth_start_xmit(struct sk_buff *skb, struct net_device *ndev)
        txdesc = &mdp->tx_ring[entry];
        /* soft swap. */
        if (!mdp->cd->hw_swap)
-               sh_eth_soft_swap(phys_to_virt(ALIGN(txdesc->addr, 4)),
-                                skb->len + 2);
-       txdesc->addr = dma_map_single(&ndev->dev, skb->data, skb->len,
-                                     DMA_TO_DEVICE);
-       if (dma_mapping_error(&ndev->dev, txdesc->addr)) {
+               sh_eth_soft_swap(PTR_ALIGN(skb->data, 4), skb->len + 2);
+       dma_addr = dma_map_single(&ndev->dev, skb->data, skb->len,
+                                 DMA_TO_DEVICE);
+       if (dma_mapping_error(&ndev->dev, dma_addr)) {
                kfree_skb(skb);
                return NETDEV_TX_OK;
        }
-       txdesc->buffer_length = skb->len;
+       txdesc->addr = cpu_to_edmac(mdp, dma_addr);
+       txdesc->len  = cpu_to_edmac(mdp, skb->len << 16);
 
        dma_wmb(); /* TACT bit must be set after all the above writes */
        if (entry >= mdp->num_tx_ring - 1)
index 50382b1c9ddcf2e5b656c98236c0e7364ee3c1f2..72fcfc9245891e06bc4d37fd0e72a33880b48cd5 100644 (file)
@@ -283,7 +283,7 @@ enum DMAC_IM_BIT {
        DMAC_M_RINT1 = 0x00000001,
 };
 
-/* Receive descriptor bit */
+/* Receive descriptor 0 bits */
 enum RD_STS_BIT {
        RD_RACT = 0x80000000, RD_RDLE = 0x40000000,
        RD_RFP1 = 0x20000000, RD_RFP0 = 0x10000000,
@@ -298,6 +298,12 @@ enum RD_STS_BIT {
 #define RDFEND RD_RFP0
 #define RD_RFP (RD_RFP1|RD_RFP0)
 
+/* Receive descriptor 1 bits */
+enum RD_LEN_BIT {
+       RD_RFL  = 0x0000ffff,   /* receive frame  length */
+       RD_RBL  = 0xffff0000,   /* receive buffer length */
+};
+
 /* FCFTR */
 enum FCFTR_BIT {
        FCFTR_RFF2 = 0x00040000, FCFTR_RFF1 = 0x00020000,
@@ -307,7 +313,7 @@ enum FCFTR_BIT {
 #define DEFAULT_FIFO_F_D_RFF   (FCFTR_RFF2 | FCFTR_RFF1 | FCFTR_RFF0)
 #define DEFAULT_FIFO_F_D_RFD   (FCFTR_RFD2 | FCFTR_RFD1 | FCFTR_RFD0)
 
-/* Transmit descriptor bit */
+/* Transmit descriptor 0 bits */
 enum TD_STS_BIT {
        TD_TACT = 0x80000000, TD_TDLE = 0x40000000,
        TD_TFP1 = 0x20000000, TD_TFP0 = 0x10000000,
@@ -317,6 +323,11 @@ enum TD_STS_BIT {
 #define TDFEND TD_TFP0
 #define TD_TFP (TD_TFP1|TD_TFP0)
 
+/* Transmit descriptor 1 bits */
+enum TD_LEN_BIT {
+       TD_TBL  = 0xffff0000,   /* transmit buffer length */
+};
+
 /* RMCR */
 enum RMCR_BIT {
        RMCR_RNC = 0x00000001,
@@ -425,15 +436,9 @@ enum TSU_FWSLC_BIT {
  */
 struct sh_eth_txdesc {
        u32 status;             /* TD0 */
-#if defined(__LITTLE_ENDIAN)
-       u16 pad0;               /* TD1 */
-       u16 buffer_length;      /* TD1 */
-#else
-       u16 buffer_length;      /* TD1 */
-       u16 pad0;               /* TD1 */
-#endif
+       u32 len;                /* TD1 */
        u32 addr;               /* TD2 */
-       u32 pad1;               /* padding data */
+       u32 pad0;               /* padding data */
 } __aligned(2) __packed;
 
 /* The sh ether Rx buffer descriptors.
@@ -441,13 +446,7 @@ struct sh_eth_txdesc {
  */
 struct sh_eth_rxdesc {
        u32 status;             /* RD0 */
-#if defined(__LITTLE_ENDIAN)
-       u16 frame_length;       /* RD1 */
-       u16 buffer_length;      /* RD1 */
-#else
-       u16 buffer_length;      /* RD1 */
-       u16 frame_length;       /* RD1 */
-#endif
+       u32 len;                /* RD1 */
        u32 addr;               /* RD2 */
        u32 pad0;               /* padding data */
 } __aligned(2) __packed;
@@ -546,31 +545,6 @@ static inline void sh_eth_soft_swap(char *src, int len)
 #endif
 }
 
-#define SH_ETH_OFFSET_INVALID  ((u16) ~0)
-
-static inline void sh_eth_write(struct net_device *ndev, u32 data,
-                               int enum_index)
-{
-       struct sh_eth_private *mdp = netdev_priv(ndev);
-       u16 offset = mdp->reg_offset[enum_index];
-
-       if (WARN_ON(offset == SH_ETH_OFFSET_INVALID))
-               return;
-
-       iowrite32(data, mdp->addr + offset);
-}
-
-static inline u32 sh_eth_read(struct net_device *ndev, int enum_index)
-{
-       struct sh_eth_private *mdp = netdev_priv(ndev);
-       u16 offset = mdp->reg_offset[enum_index];
-
-       if (WARN_ON(offset == SH_ETH_OFFSET_INVALID))
-               return ~0U;
-
-       return ioread32(mdp->addr + offset);
-}
-
 static inline void *sh_eth_tsu_get_offset(struct sh_eth_private *mdp,
                                          int enum_index)
 {
index bc6d21b471be4f4ae2f0c4c1cb26430e92c24803..e6a084a6be12d0627da52a42e783839732c05c5e 100644 (file)
@@ -3299,7 +3299,8 @@ static int efx_ef10_filter_remove_internal(struct efx_nic *efx,
 
                new_spec.priority = EFX_FILTER_PRI_AUTO;
                new_spec.flags = (EFX_FILTER_FLAG_RX |
-                                 EFX_FILTER_FLAG_RX_RSS);
+                                 (efx_rss_enabled(efx) ?
+                                  EFX_FILTER_FLAG_RX_RSS : 0));
                new_spec.dmaq_id = 0;
                new_spec.rss_context = EFX_FILTER_RSS_CONTEXT_DEFAULT;
                rc = efx_ef10_filter_push(efx, &new_spec,
@@ -3921,6 +3922,7 @@ static int efx_ef10_filter_insert_addr_list(struct efx_nic *efx,
 {
        struct efx_ef10_filter_table *table = efx->filter_state;
        struct efx_ef10_dev_addr *addr_list;
+       enum efx_filter_flags filter_flags;
        struct efx_filter_spec spec;
        u8 baddr[ETH_ALEN];
        unsigned int i, j;
@@ -3935,11 +3937,11 @@ static int efx_ef10_filter_insert_addr_list(struct efx_nic *efx,
                addr_count = table->dev_uc_count;
        }
 
+       filter_flags = efx_rss_enabled(efx) ? EFX_FILTER_FLAG_RX_RSS : 0;
+
        /* Insert/renew filters */
        for (i = 0; i < addr_count; i++) {
-               efx_filter_init_rx(&spec, EFX_FILTER_PRI_AUTO,
-                                  EFX_FILTER_FLAG_RX_RSS,
-                                  0);
+               efx_filter_init_rx(&spec, EFX_FILTER_PRI_AUTO, filter_flags, 0);
                efx_filter_set_eth_local(&spec, EFX_FILTER_VID_UNSPEC,
                                         addr_list[i].addr);
                rc = efx_ef10_filter_insert(efx, &spec, true);
@@ -3968,9 +3970,7 @@ static int efx_ef10_filter_insert_addr_list(struct efx_nic *efx,
 
        if (multicast && rollback) {
                /* Also need an Ethernet broadcast filter */
-               efx_filter_init_rx(&spec, EFX_FILTER_PRI_AUTO,
-                                  EFX_FILTER_FLAG_RX_RSS,
-                                  0);
+               efx_filter_init_rx(&spec, EFX_FILTER_PRI_AUTO, filter_flags, 0);
                eth_broadcast_addr(baddr);
                efx_filter_set_eth_local(&spec, EFX_FILTER_VID_UNSPEC, baddr);
                rc = efx_ef10_filter_insert(efx, &spec, true);
@@ -4000,13 +4000,14 @@ static int efx_ef10_filter_insert_def(struct efx_nic *efx, bool multicast,
 {
        struct efx_ef10_filter_table *table = efx->filter_state;
        struct efx_ef10_nic_data *nic_data = efx->nic_data;
+       enum efx_filter_flags filter_flags;
        struct efx_filter_spec spec;
        u8 baddr[ETH_ALEN];
        int rc;
 
-       efx_filter_init_rx(&spec, EFX_FILTER_PRI_AUTO,
-                          EFX_FILTER_FLAG_RX_RSS,
-                          0);
+       filter_flags = efx_rss_enabled(efx) ? EFX_FILTER_FLAG_RX_RSS : 0;
+
+       efx_filter_init_rx(&spec, EFX_FILTER_PRI_AUTO, filter_flags, 0);
 
        if (multicast)
                efx_filter_set_mc_def(&spec);
@@ -4023,8 +4024,7 @@ static int efx_ef10_filter_insert_def(struct efx_nic *efx, bool multicast,
                if (!nic_data->workaround_26807) {
                        /* Also need an Ethernet broadcast filter */
                        efx_filter_init_rx(&spec, EFX_FILTER_PRI_AUTO,
-                                          EFX_FILTER_FLAG_RX_RSS,
-                                          0);
+                                          filter_flags, 0);
                        eth_broadcast_addr(baddr);
                        efx_filter_set_eth_local(&spec, EFX_FILTER_VID_UNSPEC,
                                                 baddr);
index d288f1c928de611455e44b515972b172340e4686..a3c42a376741f9c86179ca0fae5889203b9f16d5 100644 (file)
@@ -3422,7 +3422,7 @@ out:
  * with our request for slot reset the mmio_enabled callback will never be
  * called, and the link_reset callback is not used by AER or EEH mechanisms.
  */
-static struct pci_error_handlers efx_err_handlers = {
+static const struct pci_error_handlers efx_err_handlers = {
        .error_detected = efx_io_error_detected,
        .slot_reset     = efx_io_slot_reset,
        .resume         = efx_io_resume,
index 1aaf76c1ace866d7563afbd1eb19a87ec5ee2ff0..10827476bc0b38237b9b6999a31a907cd330cf9e 100644 (file)
@@ -76,6 +76,11 @@ void efx_schedule_slow_fill(struct efx_rx_queue *rx_queue);
 #define EFX_TXQ_MAX_ENT(efx)   (EFX_WORKAROUND_35388(efx) ? \
                                 EFX_MAX_DMAQ_SIZE / 2 : EFX_MAX_DMAQ_SIZE)
 
+static inline bool efx_rss_enabled(struct efx_nic *efx)
+{
+       return efx->rss_spread > 1;
+}
+
 /* Filters */
 
 void efx_mac_reconfigure(struct efx_nic *efx);
index 5a1c5a8f278ad1690e678b10cec82444ee45bb12..133e9e35be9e9212bf14531bffd1c0cf78fde742 100644 (file)
@@ -2242,7 +2242,7 @@ efx_farch_filter_init_rx_auto(struct efx_nic *efx,
         */
        spec->priority = EFX_FILTER_PRI_AUTO;
        spec->flags = (EFX_FILTER_FLAG_RX |
-                      (efx->n_rx_channels > 1 ? EFX_FILTER_FLAG_RX_RSS : 0) |
+                      (efx_rss_enabled(efx) ? EFX_FILTER_FLAG_RX_RSS : 0) |
                       (efx->rx_scatter ? EFX_FILTER_FLAG_RX_SCATTER : 0));
        spec->dmaq_id = 0;
 }
index 3d5ee3259885d9486933e5b821c3af2a94c910d2..194f67d9f3bfaa81bd99bf3ad64c6c1568476319 100644 (file)
@@ -418,7 +418,7 @@ static void txc_reset_logic_mmd(struct efx_nic *efx, int mmd)
 
        val |= (1 << TXC_GLCMD_LMTSWRST_LBN);
        efx_mdio_write(efx, mmd, TXC_GLRGS_GLCMD, val);
-       while (tries--) {
+       while (--tries) {
                val = efx_mdio_read(efx, mmd, TXC_GLRGS_GLCMD);
                if (!(val & (1 << TXC_GLCMD_LMTSWRST_LBN)))
                        break;
index c860c9007e49afda02165733ede46780da58abf3..219a99b7a631d5216c0667e24ca5595b67e56289 100644 (file)
@@ -809,22 +809,17 @@ static int smsc911x_phy_check_loopbackpkt(struct smsc911x_data *pdata)
 
 static int smsc911x_phy_reset(struct smsc911x_data *pdata)
 {
-       struct phy_device *phy_dev = pdata->phy_dev;
        unsigned int temp;
        unsigned int i = 100000;
 
-       BUG_ON(!phy_dev);
-       BUG_ON(!phy_dev->bus);
-
-       SMSC_TRACE(pdata, hw, "Performing PHY BCR Reset");
-       smsc911x_mii_write(phy_dev->bus, phy_dev->addr, MII_BMCR, BMCR_RESET);
+       temp = smsc911x_reg_read(pdata, PMT_CTRL);
+       smsc911x_reg_write(pdata, PMT_CTRL, temp | PMT_CTRL_PHY_RST_);
        do {
                msleep(1);
-               temp = smsc911x_mii_read(phy_dev->bus, phy_dev->addr,
-                       MII_BMCR);
-       } while ((i--) && (temp & BMCR_RESET));
+               temp = smsc911x_reg_read(pdata, PMT_CTRL);
+       } while ((i--) && (temp & PMT_CTRL_PHY_RST_));
 
-       if (temp & BMCR_RESET) {
+       if (unlikely(temp & PMT_CTRL_PHY_RST_)) {
                SMSC_WARN(pdata, hw, "PHY reset failed to complete");
                return -EIO;
        }
@@ -2296,7 +2291,7 @@ static int smsc911x_init(struct net_device *dev)
        }
 
        /* Reset the LAN911x */
-       if (smsc911x_soft_reset(pdata))
+       if (smsc911x_phy_reset(pdata) || smsc911x_soft_reset(pdata))
                return -ENODEV;
 
        dev->flags |= IFF_MULTICAST;
index 9d89bdbf029f4e0ba908bfa8f199514bd3eb026c..82de68b1a45277480e98c2229c82450a61835d2e 100644 (file)
@@ -337,11 +337,11 @@ static int ipq806x_gmac_probe(struct platform_device *pdev)
                             QSGMII_PHY_RX_SIGNAL_DETECT_EN |
                             QSGMII_PHY_TX_DRIVER_EN |
                             QSGMII_PHY_QSGMII_EN |
-                            0x4 << QSGMII_PHY_PHASE_LOOP_GAIN_OFFSET |
-                            0x3 << QSGMII_PHY_RX_DC_BIAS_OFFSET |
-                            0x1 << QSGMII_PHY_RX_INPUT_EQU_OFFSET |
-                            0x2 << QSGMII_PHY_CDR_PI_SLEW_OFFSET |
-                            0xC << QSGMII_PHY_TX_DRV_AMP_OFFSET);
+                            0x4ul << QSGMII_PHY_PHASE_LOOP_GAIN_OFFSET |
+                            0x3ul << QSGMII_PHY_RX_DC_BIAS_OFFSET |
+                            0x1ul << QSGMII_PHY_RX_INPUT_EQU_OFFSET |
+                            0x2ul << QSGMII_PHY_CDR_PI_SLEW_OFFSET |
+                            0xCul << QSGMII_PHY_TX_DRV_AMP_OFFSET);
        }
 
        plat_dat->has_gmac = true;
index 7f6f4a4fcc708973af0aa48418bedaad984ef5fd..58c05acc2aabbdf63419874605ae11af298471ca 100644 (file)
@@ -299,16 +299,17 @@ static int sti_dwmac_parse_data(struct sti_dwmac *dwmac,
        if (IS_PHY_IF_MODE_GBIT(dwmac->interface)) {
                const char *rs;
 
+               dwmac->tx_retime_src = TX_RETIME_SRC_CLKGEN;
+
                err = of_property_read_string(np, "st,tx-retime-src", &rs);
                if (err < 0) {
                        dev_warn(dev, "Use internal clock source\n");
-                       dwmac->tx_retime_src = TX_RETIME_SRC_CLKGEN;
-               } else if (!strcasecmp(rs, "clk_125")) {
-                       dwmac->tx_retime_src = TX_RETIME_SRC_CLK_125;
-               } else if (!strcasecmp(rs, "txclk")) {
-                       dwmac->tx_retime_src = TX_RETIME_SRC_TXCLK;
+               } else {
+                       if (!strcasecmp(rs, "clk_125"))
+                               dwmac->tx_retime_src = TX_RETIME_SRC_CLK_125;
+                       else if (!strcasecmp(rs, "txclk"))
+                               dwmac->tx_retime_src = TX_RETIME_SRC_TXCLK;
                }
-
                dwmac->speed = SPEED_1000;
        }
 
index 52b8ed9bd87c2e20707c41ab0eaac247de26afce..adff46375a32297ce01a7fdd519483ccc1226012 100644 (file)
@@ -153,7 +153,11 @@ static int sun7i_gmac_probe(struct platform_device *pdev)
        if (ret)
                return ret;
 
-       return stmmac_dvr_probe(&pdev->dev, plat_dat, &stmmac_res);
+       ret = stmmac_dvr_probe(&pdev->dev, plat_dat, &stmmac_res);
+       if (ret)
+               sun7i_gmac_exit(pdev, plat_dat->bsp_priv);
+
+       return ret;
 }
 
 static const struct of_device_id sun7i_dwmac_match[] = {
index 64d8aa4e0cad6420bcb1fa4cd827ad823ba3601d..a5b869eb46783e338708f93c31f33524116e637f 100644 (file)
@@ -185,7 +185,7 @@ static void stmmac_clk_csr_set(struct stmmac_priv *priv)
                        priv->clk_csr = STMMAC_CSR_100_150M;
                else if ((clk_rate >= CSR_F_150M) && (clk_rate < CSR_F_250M))
                        priv->clk_csr = STMMAC_CSR_150_250M;
-               else if ((clk_rate >= CSR_F_250M) && (clk_rate < CSR_F_300M))
+               else if ((clk_rate >= CSR_F_250M) && (clk_rate <= CSR_F_300M))
                        priv->clk_csr = STMMAC_CSR_250_300M;
        }
 }
@@ -2232,6 +2232,12 @@ static int stmmac_rx(struct stmmac_priv *priv, int limit)
 
                        frame_len = priv->hw->desc->get_rx_frame_len(p, coe);
 
+                       /*  check if frame_len fits the preallocated memory */
+                       if (frame_len > priv->dma_buf_sz) {
+                               priv->dev->stats.rx_length_errors++;
+                               break;
+                       }
+
                        /* ACS is set; GMAC core strips PAD/FCS for IEEE 802.3
                         * Type frames (LLC/LLC-SNAP)
                         */
@@ -3040,8 +3046,6 @@ int stmmac_suspend(struct net_device *ndev)
        priv->hw->dma->stop_tx(priv->ioaddr);
        priv->hw->dma->stop_rx(priv->ioaddr);
 
-       stmmac_clear_descriptors(priv);
-
        /* Enable Power down mode by programming the PMT regs */
        if (device_may_wakeup(priv->device)) {
                priv->hw->mac->pmt(priv->hw, priv->wolopts);
@@ -3099,9 +3103,15 @@ int stmmac_resume(struct net_device *ndev)
 
        netif_device_attach(ndev);
 
-       init_dma_desc_rings(ndev, GFP_ATOMIC);
+       priv->cur_rx = 0;
+       priv->dirty_rx = 0;
+       priv->dirty_tx = 0;
+       priv->cur_tx = 0;
+       stmmac_clear_descriptors(priv);
+
        stmmac_hw_setup(ndev, false);
        stmmac_init_tx_coalesce(priv);
+       stmmac_set_rx_mode(ndev);
 
        napi_enable(&priv->napi);
 
index ebf6abc4853f300392677614d6f45be0f95e8fca..bba670c42e3749483bf2218ad2da6b3b4c8d0587 100644 (file)
@@ -138,7 +138,6 @@ int stmmac_mdio_reset(struct mii_bus *bus)
 
 #ifdef CONFIG_OF
        if (priv->device->of_node) {
-               int reset_gpio, active_low;
 
                if (data->reset_gpio < 0) {
                        struct device_node *np = priv->device->of_node;
@@ -154,24 +153,23 @@ int stmmac_mdio_reset(struct mii_bus *bus)
                                                "snps,reset-active-low");
                        of_property_read_u32_array(np,
                                "snps,reset-delays-us", data->delays, 3);
-               }
 
-               reset_gpio = data->reset_gpio;
-               active_low = data->active_low;
+                       if (gpio_request(data->reset_gpio, "mdio-reset"))
+                               return 0;
+               }
 
-               if (!gpio_request(reset_gpio, "mdio-reset")) {
-                       gpio_direction_output(reset_gpio, active_low ? 1 : 0);
-                       if (data->delays[0])
-                               msleep(DIV_ROUND_UP(data->delays[0], 1000));
+               gpio_direction_output(data->reset_gpio,
+                                     data->active_low ? 1 : 0);
+               if (data->delays[0])
+                       msleep(DIV_ROUND_UP(data->delays[0], 1000));
 
-                       gpio_set_value(reset_gpio, active_low ? 0 : 1);
-                       if (data->delays[1])
-                               msleep(DIV_ROUND_UP(data->delays[1], 1000));
+               gpio_set_value(data->reset_gpio, data->active_low ? 0 : 1);
+               if (data->delays[1])
+                       msleep(DIV_ROUND_UP(data->delays[1], 1000));
 
-                       gpio_set_value(reset_gpio, active_low ? 1 : 0);
-                       if (data->delays[2])
-                               msleep(DIV_ROUND_UP(data->delays[2], 1000));
-               }
+               gpio_set_value(data->reset_gpio, data->active_low ? 1 : 0);
+               if (data->delays[2])
+                       msleep(DIV_ROUND_UP(data->delays[2], 1000));
        }
 #endif
 
index c08be62bceba6f2e2eb59e0da7ac9c3bdbe61813..1562ab4151e192a079fc2a54dec7f8c101bcd109 100644 (file)
@@ -78,6 +78,9 @@ static int cpsw_am33xx_cm_get_macid(struct device *dev, u16 offset, int slave,
 
 int ti_cm_get_macid(struct device *dev, int slave, u8 *mac_addr)
 {
+       if (of_machine_is_compatible("ti,dm8148"))
+               return cpsw_am33xx_cm_get_macid(dev, 0x630, slave, mac_addr);
+
        if (of_machine_is_compatible("ti,am33xx"))
                return cpsw_am33xx_cm_get_macid(dev, 0x630, slave, mac_addr);
 
index 48b92c9de12a5af4f75ab6b48b4ffd39a77d6ed5..fc958067d10a77d248115968ec0dc4625460aee2 100644 (file)
@@ -2026,45 +2026,54 @@ static int cpsw_probe_dt(struct cpsw_priv *priv,
        for_each_child_of_node(node, slave_node) {
                struct cpsw_slave_data *slave_data = data->slave_data + i;
                const void *mac_addr = NULL;
-               u32 phyid;
                int lenp;
                const __be32 *parp;
-               struct device_node *mdio_node;
-               struct platform_device *mdio;
 
                /* This is no slave child node, continue */
                if (strcmp(slave_node->name, "slave"))
                        continue;
 
                priv->phy_node = of_parse_phandle(slave_node, "phy-handle", 0);
+               parp = of_get_property(slave_node, "phy_id", &lenp);
                if (of_phy_is_fixed_link(slave_node)) {
-                       struct phy_device *pd;
+                       struct device_node *phy_node;
+                       struct phy_device *phy_dev;
 
+                       /* In the case of a fixed PHY, the DT node associated
+                        * to the PHY is the Ethernet MAC DT node.
+                        */
                        ret = of_phy_register_fixed_link(slave_node);
                        if (ret)
                                return ret;
-                       pd = of_phy_find_device(slave_node);
-                       if (!pd)
+                       phy_node = of_node_get(slave_node);
+                       phy_dev = of_phy_find_device(phy_node);
+                       if (!phy_dev)
                                return -ENODEV;
                        snprintf(slave_data->phy_id, sizeof(slave_data->phy_id),
-                                PHY_ID_FMT, pd->bus->id, pd->phy_id);
-                       goto no_phy_slave;
-               }
-               parp = of_get_property(slave_node, "phy_id", &lenp);
-               if ((parp == NULL) || (lenp != (sizeof(void *) * 2))) {
-                       dev_err(&pdev->dev, "Missing slave[%d] phy_id property\n", i);
+                                PHY_ID_FMT, phy_dev->bus->id, phy_dev->addr);
+               } else if (parp) {
+                       u32 phyid;
+                       struct device_node *mdio_node;
+                       struct platform_device *mdio;
+
+                       if (lenp != (sizeof(__be32) * 2)) {
+                               dev_err(&pdev->dev, "Invalid slave[%d] phy_id property\n", i);
+                               goto no_phy_slave;
+                       }
+                       mdio_node = of_find_node_by_phandle(be32_to_cpup(parp));
+                       phyid = be32_to_cpup(parp+1);
+                       mdio = of_find_device_by_node(mdio_node);
+                       of_node_put(mdio_node);
+                       if (!mdio) {
+                               dev_err(&pdev->dev, "Missing mdio platform device\n");
+                               return -EINVAL;
+                       }
+                       snprintf(slave_data->phy_id, sizeof(slave_data->phy_id),
+                                PHY_ID_FMT, mdio->name, phyid);
+               } else {
+                       dev_err(&pdev->dev, "No slave[%d] phy_id or fixed-link property\n", i);
                        goto no_phy_slave;
                }
-               mdio_node = of_find_node_by_phandle(be32_to_cpup(parp));
-               phyid = be32_to_cpup(parp+1);
-               mdio = of_find_device_by_node(mdio_node);
-               of_node_put(mdio_node);
-               if (!mdio) {
-                       dev_err(&pdev->dev, "Missing mdio platform device\n");
-                       return -EINVAL;
-               }
-               snprintf(slave_data->phy_id, sizeof(slave_data->phy_id),
-                        PHY_ID_FMT, mdio->name, phyid);
                slave_data->phy_if = of_get_phy_mode(slave_node);
                if (slave_data->phy_if < 0) {
                        dev_err(&pdev->dev, "Missing or malformed slave[%d] phy-mode property\n",
@@ -2418,7 +2427,7 @@ static int cpsw_probe(struct platform_device *pdev)
        ndev->irq = platform_get_irq(pdev, 1);
        if (ndev->irq < 0) {
                dev_err(priv->dev, "error getting irq resource\n");
-               ret = -ENOENT;
+               ret = ndev->irq;
                goto clean_ale_ret;
        }
 
@@ -2439,8 +2448,10 @@ static int cpsw_probe(struct platform_device *pdev)
 
        /* RX IRQ */
        irq = platform_get_irq(pdev, 1);
-       if (irq < 0)
+       if (irq < 0) {
+               ret = irq;
                goto clean_ale_ret;
+       }
 
        priv->irqs_table[0] = irq;
        ret = devm_request_irq(&pdev->dev, irq, cpsw_rx_interrupt,
@@ -2452,8 +2463,10 @@ static int cpsw_probe(struct platform_device *pdev)
 
        /* TX IRQ */
        irq = platform_get_irq(pdev, 2);
-       if (irq < 0)
+       if (irq < 0) {
+               ret = irq;
                goto clean_ale_ret;
+       }
 
        priv->irqs_table[1] = irq;
        ret = devm_request_irq(&pdev->dev, irq, cpsw_tx_interrupt,
index ae68afd50a156199b6f74b2d2e65420cddd02c73..f38696ceee74afcb1aa4eb731e70b3c307e40193 100644 (file)
@@ -345,13 +345,6 @@ VELOCITY_PARAM(flow_control, "Enable flow control ability");
 */
 VELOCITY_PARAM(speed_duplex, "Setting the speed and duplex mode");
 
-#define VAL_PKT_LEN_DEF     0
-/* ValPktLen[] is used for setting the checksum offload ability of NIC.
-   0: Receive frame with invalid layer 2 length (Default)
-   1: Drop frame with invalid layer 2 length
-*/
-VELOCITY_PARAM(ValPktLen, "Receiving or Drop invalid 802.3 frame");
-
 #define WOL_OPT_DEF     0
 #define WOL_OPT_MIN     0
 #define WOL_OPT_MAX     7
@@ -494,7 +487,6 @@ static void velocity_get_options(struct velocity_opt *opts, int index,
 
        velocity_set_int_opt(&opts->flow_cntl, flow_control[index], FLOW_CNTL_MIN, FLOW_CNTL_MAX, FLOW_CNTL_DEF, "flow_control", devname);
        velocity_set_bool_opt(&opts->flags, IP_byte_align[index], IP_ALIG_DEF, VELOCITY_FLAGS_IP_ALIGN, "IP_byte_align", devname);
-       velocity_set_bool_opt(&opts->flags, ValPktLen[index], VAL_PKT_LEN_DEF, VELOCITY_FLAGS_VAL_PKT_LEN, "ValPktLen", devname);
        velocity_set_int_opt((int *) &opts->spd_dpx, speed_duplex[index], MED_LNK_MIN, MED_LNK_MAX, MED_LNK_DEF, "Media link mode", devname);
        velocity_set_int_opt(&opts->wol_opts, wol_opts[index], WOL_OPT_MIN, WOL_OPT_MAX, WOL_OPT_DEF, "Wake On Lan options", devname);
        opts->numrx = (opts->numrx & ~3);
@@ -2055,8 +2047,9 @@ static int velocity_receive_frame(struct velocity_info *vptr, int idx)
        int pkt_len = le16_to_cpu(rd->rdesc0.len) & 0x3fff;
        struct sk_buff *skb;
 
-       if (rd->rdesc0.RSR & (RSR_STP | RSR_EDP)) {
-               VELOCITY_PRT(MSG_LEVEL_VERBOSE, KERN_ERR " %s : the received frame spans multiple RDs.\n", vptr->netdev->name);
+       if (unlikely(rd->rdesc0.RSR & (RSR_STP | RSR_EDP | RSR_RL))) {
+               if (rd->rdesc0.RSR & (RSR_STP | RSR_EDP))
+                       VELOCITY_PRT(MSG_LEVEL_VERBOSE, KERN_ERR " %s : the received frame spans multiple RDs.\n", vptr->netdev->name);
                stats->rx_length_errors++;
                return -EINVAL;
        }
@@ -2069,17 +2062,6 @@ static int velocity_receive_frame(struct velocity_info *vptr, int idx)
        dma_sync_single_for_cpu(vptr->dev, rd_info->skb_dma,
                                    vptr->rx.buf_sz, DMA_FROM_DEVICE);
 
-       /*
-        *      Drop frame not meeting IEEE 802.3
-        */
-
-       if (vptr->flags & VELOCITY_FLAGS_VAL_PKT_LEN) {
-               if (rd->rdesc0.RSR & RSR_RL) {
-                       stats->rx_length_errors++;
-                       return -EINVAL;
-               }
-       }
-
        velocity_rx_csum(rd, skb);
 
        if (velocity_rx_copy(&skb, pkt_len, vptr) < 0) {
index bb8b5304d85117354595d707585613e572ce24c0..b103adb8d62ecfa9c1b21647d5c2498fa9586c96 100644 (file)
@@ -599,7 +599,7 @@ int fjes_hw_unregister_buff_addr(struct fjes_hw *hw, int dest_epid)
                FJES_CMD_REQ_RES_CODE_BUSY) &&
               (timeout > 0)) {
                msleep(200 + hw->my_epid * 20);
-                       timeout -= (200 + hw->my_epid * 20);
+               timeout -= (200 + hw->my_epid * 20);
 
                res_buf->unshare_buffer.length = 0;
                res_buf->unshare_buffer.code = 0;
index de5c30c9f059203040cc47e83cce76ae9e5bfde6..58efdec12f300dec69f6790c19f7cd56b10a4b22 100644 (file)
@@ -967,8 +967,6 @@ static netdev_tx_t geneve6_xmit_skb(struct sk_buff *skb, struct net_device *dev,
        err = udp_tunnel6_xmit_skb(dst, gs6->sock->sk, skb, dev,
                                   &fl6.saddr, &fl6.daddr, prio, ttl,
                                   sport, geneve->dst_port, !udp_csum);
-
-       iptunnel_xmit_stats(err, &dev->stats, dev->tstats);
        return NETDEV_TX_OK;
 
 tx_error:
@@ -1157,7 +1155,7 @@ static int geneve_configure(struct net *net, struct net_device *dev,
        struct geneve_net *gn = net_generic(net, geneve_net_id);
        struct geneve_dev *t, *geneve = netdev_priv(dev);
        bool tun_collect_md, tun_on_same_port;
-       int err;
+       int err, encap_len;
 
        if (!remote)
                return -EINVAL;
@@ -1189,6 +1187,14 @@ static int geneve_configure(struct net *net, struct net_device *dev,
        if (t)
                return -EBUSY;
 
+       /* make enough headroom for basic scenario */
+       encap_len = GENEVE_BASE_HLEN + ETH_HLEN;
+       if (remote->sa.sa_family == AF_INET)
+               encap_len += sizeof(struct iphdr);
+       else
+               encap_len += sizeof(struct ipv6hdr);
+       dev->needed_headroom = encap_len + ETH_HLEN;
+
        if (metadata) {
                if (tun_on_same_port)
                        return -EPERM;
index 7c4a4151ef0f23fca16b0fd957769c09dc5823d0..9f0b1c342b770c26453753c52a7543303e09457c 100644 (file)
@@ -683,14 +683,14 @@ static void sixpack_close(struct tty_struct *tty)
        if (!atomic_dec_and_test(&sp->refcnt))
                down(&sp->dead_sem);
 
-       unregister_netdev(sp->dev);
-
-       del_timer(&sp->tx_t);
-       del_timer(&sp->resync_t);
+       del_timer_sync(&sp->tx_t);
+       del_timer_sync(&sp->resync_t);
 
        /* Free all 6pack frame buffers. */
        kfree(sp->rbuff);
        kfree(sp->xbuff);
+
+       unregister_netdev(sp->dev);
 }
 
 /* Perform I/O control on an active 6pack channel. */
index 216bfd350169a9da723035876d152e89b17c8432..0b72b9de520721fee48d3557b817452e2830c613 100644 (file)
@@ -798,13 +798,13 @@ static void mkiss_close(struct tty_struct *tty)
        if (!atomic_dec_and_test(&ax->refcnt))
                down(&ax->dead_sem);
 
-       unregister_netdev(ax->dev);
-
        /* Free all AX25 frame buffers. */
        kfree(ax->rbuff);
        kfree(ax->xbuff);
 
        ax->tty = NULL;
+
+       unregister_netdev(ax->dev);
 }
 
 /* Perform I/O control on an active ax25 channel. */
index d50887e3df6de3b41767ccbb3fb04a67c9d459af..8c48bb2a94ea063aa9dd7c4dc662aa772f34930c 100644 (file)
@@ -254,7 +254,7 @@ acct:
        }
 }
 
-static int ipvlan_rcv_frame(struct ipvl_addr *addr, struct sk_buff *skb,
+static int ipvlan_rcv_frame(struct ipvl_addr *addr, struct sk_buff **pskb,
                            bool local)
 {
        struct ipvl_dev *ipvlan = addr->master;
@@ -262,6 +262,7 @@ static int ipvlan_rcv_frame(struct ipvl_addr *addr, struct sk_buff *skb,
        unsigned int len;
        rx_handler_result_t ret = RX_HANDLER_CONSUMED;
        bool success = false;
+       struct sk_buff *skb = *pskb;
 
        len = skb->len + ETH_HLEN;
        if (unlikely(!(dev->flags & IFF_UP))) {
@@ -273,6 +274,7 @@ static int ipvlan_rcv_frame(struct ipvl_addr *addr, struct sk_buff *skb,
        if (!skb)
                goto out;
 
+       *pskb = skb;
        skb->dev = dev;
        skb->pkt_type = PACKET_HOST;
 
@@ -486,7 +488,7 @@ static int ipvlan_xmit_mode_l3(struct sk_buff *skb, struct net_device *dev)
 
        addr = ipvlan_addr_lookup(ipvlan->port, lyr3h, addr_type, true);
        if (addr)
-               return ipvlan_rcv_frame(addr, skb, true);
+               return ipvlan_rcv_frame(addr, &skb, true);
 
 out:
        skb->dev = ipvlan->phy_dev;
@@ -506,7 +508,7 @@ static int ipvlan_xmit_mode_l2(struct sk_buff *skb, struct net_device *dev)
                if (lyr3h) {
                        addr = ipvlan_addr_lookup(ipvlan->port, lyr3h, addr_type, true);
                        if (addr)
-                               return ipvlan_rcv_frame(addr, skb, true);
+                               return ipvlan_rcv_frame(addr, &skb, true);
                }
                skb = skb_share_check(skb, GFP_ATOMIC);
                if (!skb)
@@ -589,7 +591,7 @@ static rx_handler_result_t ipvlan_handle_mode_l3(struct sk_buff **pskb,
 
        addr = ipvlan_addr_lookup(port, lyr3h, addr_type, true);
        if (addr)
-               ret = ipvlan_rcv_frame(addr, skb, false);
+               ret = ipvlan_rcv_frame(addr, pskb, false);
 
 out:
        return ret;
@@ -626,7 +628,7 @@ static rx_handler_result_t ipvlan_handle_mode_l2(struct sk_buff **pskb,
 
                addr = ipvlan_addr_lookup(port, lyr3h, addr_type, true);
                if (addr)
-                       ret = ipvlan_rcv_frame(addr, skb, false);
+                       ret = ipvlan_rcv_frame(addr, pskb, false);
        }
 
        return ret;
@@ -651,5 +653,5 @@ rx_handler_result_t ipvlan_handle_frame(struct sk_buff **pskb)
        WARN_ONCE(true, "ipvlan_handle_frame() called for mode = [%hx]\n",
                          port->mode);
        kfree_skb(skb);
-       return NET_RX_DROP;
+       return RX_HANDLER_CONSUMED;
 }
index 86f6c6292c2726c6991f305bc8794a5af2c648af..06c8bfeaccd6c11cf15a8f05d87ce23c0f1e4405 100644 (file)
@@ -415,6 +415,7 @@ static rx_handler_result_t macvlan_handle_frame(struct sk_buff **pskb)
                skb = ip_check_defrag(dev_net(skb->dev), skb, IP_DEFRAG_MACVLAN);
                if (!skb)
                        return RX_HANDLER_CONSUMED;
+               *pskb = skb;
                eth = eth_hdr(skb);
                macvlan_forward_source(skb, port, eth->h_source);
                src = macvlan_hash_lookup(port, eth->h_source);
@@ -456,6 +457,7 @@ static rx_handler_result_t macvlan_handle_frame(struct sk_buff **pskb)
                goto out;
        }
 
+       *pskb = skb;
        skb->dev = dev;
        skb->pkt_type = PACKET_HOST;
 
index 54036ae0a388c9a34cbb92fc832980fc1e584dc2..0fc521941c718dbcdea487a18a900984ad176ea5 100644 (file)
@@ -498,7 +498,7 @@ static void macvtap_sock_write_space(struct sock *sk)
        wait_queue_head_t *wqueue;
 
        if (!sock_writeable(sk) ||
-           !test_and_clear_bit(SOCK_ASYNC_NOSPACE, &sk->sk_socket->flags))
+           !test_and_clear_bit(SOCKWQ_ASYNC_NOSPACE, &sk->sk_socket->flags))
                return;
 
        wqueue = sk_sleep(sk);
@@ -585,7 +585,7 @@ static unsigned int macvtap_poll(struct file *file, poll_table * wait)
                mask |= POLLIN | POLLRDNORM;
 
        if (sock_writeable(&q->sk) ||
-           (!test_and_set_bit(SOCK_ASYNC_NOSPACE, &q->sock.flags) &&
+           (!test_and_set_bit(SOCKWQ_ASYNC_NOSPACE, &q->sock.flags) &&
             sock_writeable(&q->sk)))
                mask |= POLLOUT | POLLWRNORM;
 
index fabf11d32d276d9ac6ef6ac50ccd24609a48f90f..2d020a3ec0b5bb0c2ea13dc0f568f123d77af94a 100644 (file)
@@ -308,6 +308,8 @@ static struct phy_driver at803x_driver[] = {
        .flags                  = PHY_HAS_INTERRUPT,
        .config_aneg            = genphy_config_aneg,
        .read_status            = genphy_read_status,
+       .ack_interrupt          = at803x_ack_interrupt,
+       .config_intr            = at803x_config_intr,
        .driver                 = {
                .owner = THIS_MODULE,
        },
@@ -327,6 +329,8 @@ static struct phy_driver at803x_driver[] = {
        .flags                  = PHY_HAS_INTERRUPT,
        .config_aneg            = genphy_config_aneg,
        .read_status            = genphy_read_status,
+       .ack_interrupt          = at803x_ack_interrupt,
+       .config_intr            = at803x_config_intr,
        .driver                 = {
                .owner = THIS_MODULE,
        },
index 07a6119121c38922aa50b3241e95d4604435a051..3ce5d9514623ce210ba9f8b13a113b0ef4c91165 100644 (file)
@@ -614,7 +614,7 @@ static struct mdio_device_id __maybe_unused broadcom_tbl[] = {
        { PHY_ID_BCM5461, 0xfffffff0 },
        { PHY_ID_BCM54616S, 0xfffffff0 },
        { PHY_ID_BCM5464, 0xfffffff0 },
-       { PHY_ID_BCM5482, 0xfffffff0 },
+       { PHY_ID_BCM5481, 0xfffffff0 },
        { PHY_ID_BCM5482, 0xfffffff0 },
        { PHY_ID_BCM50610, 0xfffffff0 },
        { PHY_ID_BCM50610M, 0xfffffff0 },
index 5de8d5827536b1c196b4dabe95f3815964dd0296..0240552b50f3228b16fb310afa52a0bdbe8fd4ef 100644 (file)
@@ -1153,6 +1153,21 @@ static struct phy_driver marvell_drivers[] = {
                .suspend = &genphy_suspend,
                .driver = { .owner = THIS_MODULE },
        },
+       {
+               .phy_id = MARVELL_PHY_ID_88E1540,
+               .phy_id_mask = MARVELL_PHY_ID_MASK,
+               .name = "Marvell 88E1540",
+               .features = PHY_GBIT_FEATURES,
+               .flags = PHY_HAS_INTERRUPT,
+               .config_aneg = &m88e1510_config_aneg,
+               .read_status = &marvell_read_status,
+               .ack_interrupt = &marvell_ack_interrupt,
+               .config_intr = &marvell_config_intr,
+               .did_interrupt = &m88e1121_did_interrupt,
+               .resume = &genphy_resume,
+               .suspend = &genphy_suspend,
+               .driver = { .owner = THIS_MODULE },
+       },
        {
                .phy_id = MARVELL_PHY_ID_88E3016,
                .phy_id_mask = MARVELL_PHY_ID_MASK,
@@ -1186,6 +1201,7 @@ static struct mdio_device_id __maybe_unused marvell_tbl[] = {
        { MARVELL_PHY_ID_88E1318S, MARVELL_PHY_ID_MASK },
        { MARVELL_PHY_ID_88E1116R, MARVELL_PHY_ID_MASK },
        { MARVELL_PHY_ID_88E1510, MARVELL_PHY_ID_MASK },
+       { MARVELL_PHY_ID_88E1540, MARVELL_PHY_ID_MASK },
        { MARVELL_PHY_ID_88E3016, MARVELL_PHY_ID_MASK },
        { }
 };
index 908e8d4863429fb6c11f4a625449500f3be36ce1..7f8e7662e28cbcb97891cb8af27d37c9fbb915c0 100644 (file)
@@ -149,9 +149,14 @@ int mdio_mux_init(struct device *dev,
                }
                cb->bus_number = v;
                cb->parent = pb;
+
                cb->mii_bus = mdiobus_alloc();
+               if (!cb->mii_bus) {
+                       ret_val = -ENOMEM;
+                       of_node_put(child_bus_node);
+                       break;
+               }
                cb->mii_bus->priv = cb;
-
                cb->mii_bus->irq = cb->phy_irq;
                cb->mii_bus->name = "mdio_mux";
                snprintf(cb->mii_bus->id, MII_BUS_ID_SIZE, "%x.%x",
index cf6312fafea545fbc3efb96e8ff6c63b35c7420e..e13ad6cdcc2216ca1d43b78bb41cac12933fe2b4 100644 (file)
@@ -339,9 +339,18 @@ static int ksz9021_config_init(struct phy_device *phydev)
 {
        const struct device *dev = &phydev->dev;
        const struct device_node *of_node = dev->of_node;
+       const struct device *dev_walker;
 
-       if (!of_node && dev->parent->of_node)
-               of_node = dev->parent->of_node;
+       /* The Micrel driver has a deprecated option to place phy OF
+        * properties in the MAC node. Walk up the tree of devices to
+        * find a device with an OF node.
+        */
+       dev_walker = &phydev->dev;
+       do {
+               of_node = dev_walker->of_node;
+               dev_walker = dev_walker->parent;
+
+       } while (!of_node && dev_walker);
 
        if (of_node) {
                ksz9021_load_values_from_of(phydev, of_node,
index adb48abafc872a71e801b5505d676f9db02c7466..47cd306dbb3c4909ae95feb586f0b89198126995 100644 (file)
@@ -448,7 +448,8 @@ int phy_mii_ioctl(struct phy_device *phydev, struct ifreq *ifr, int cmd)
                mdiobus_write(phydev->bus, mii_data->phy_id,
                              mii_data->reg_num, val);
 
-               if (mii_data->reg_num == MII_BMCR &&
+               if (mii_data->phy_id == phydev->addr &&
+                   mii_data->reg_num == MII_BMCR &&
                    val & BMCR_RESET)
                        return phy_init_hw(phydev);
 
@@ -863,6 +864,9 @@ void phy_state_machine(struct work_struct *work)
                        needs_aneg = true;
                break;
        case PHY_NOLINK:
+               if (phy_interrupt_is_valid(phydev))
+                       break;
+
                err = phy_read_status(phydev);
                if (err)
                        break;
index 76cad712ddb2c7c6bc2794389380e4e0a862d5f5..dd295dbaa074642a7115b65123d06920744c7f88 100644 (file)
@@ -66,6 +66,7 @@
 #define PHY_ID_VSC8244                 0x000fc6c0
 #define PHY_ID_VSC8514                 0x00070670
 #define PHY_ID_VSC8574                 0x000704a0
+#define PHY_ID_VSC8601                 0x00070420
 #define PHY_ID_VSC8662                 0x00070660
 #define PHY_ID_VSC8221                 0x000fc550
 #define PHY_ID_VSC8211                 0x000fc4b0
@@ -133,7 +134,8 @@ static int vsc82xx_config_intr(struct phy_device *phydev)
                        (phydev->drv->phy_id == PHY_ID_VSC8234 ||
                         phydev->drv->phy_id == PHY_ID_VSC8244 ||
                         phydev->drv->phy_id == PHY_ID_VSC8514 ||
-                        phydev->drv->phy_id == PHY_ID_VSC8574) ?
+                        phydev->drv->phy_id == PHY_ID_VSC8574 ||
+                        phydev->drv->phy_id == PHY_ID_VSC8601) ?
                                MII_VSC8244_IMASK_MASK :
                                MII_VSC8221_IMASK_MASK);
        else {
@@ -271,6 +273,18 @@ static struct phy_driver vsc82xx_driver[] = {
        .ack_interrupt  = &vsc824x_ack_interrupt,
        .config_intr    = &vsc82xx_config_intr,
        .driver         = { .owner = THIS_MODULE,},
+}, {
+       .phy_id         = PHY_ID_VSC8601,
+       .name           = "Vitesse VSC8601",
+       .phy_id_mask    = 0x000ffff0,
+       .features       = PHY_GBIT_FEATURES,
+       .flags          = PHY_HAS_INTERRUPT,
+       .config_init    = &genphy_config_init,
+       .config_aneg    = &genphy_config_aneg,
+       .read_status    = &genphy_read_status,
+       .ack_interrupt  = &vsc824x_ack_interrupt,
+       .config_intr    = &vsc82xx_config_intr,
+       .driver         = { .owner = THIS_MODULE,},
 }, {
        .phy_id         = PHY_ID_VSC8662,
        .name           = "Vitesse VSC8662",
index 5e0b43283bce2c4f5251e5c5db982ca679526d07..0a37f840fcc52d17cee2d23dce50d27723735bad 100644 (file)
@@ -568,6 +568,9 @@ static int pppoe_create(struct net *net, struct socket *sock, int kern)
        sk->sk_family           = PF_PPPOX;
        sk->sk_protocol         = PX_PROTO_OE;
 
+       INIT_WORK(&pppox_sk(sk)->proto.pppoe.padt_work,
+                 pppoe_unbind_sock_work);
+
        return 0;
 }
 
@@ -632,8 +635,6 @@ static int pppoe_connect(struct socket *sock, struct sockaddr *uservaddr,
 
        lock_sock(sk);
 
-       INIT_WORK(&po->proto.pppoe.padt_work, pppoe_unbind_sock_work);
-
        error = -EINVAL;
        if (sp->sa_protocol != PX_PROTO_OE)
                goto end;
@@ -663,8 +664,13 @@ static int pppoe_connect(struct socket *sock, struct sockaddr *uservaddr,
                        po->pppoe_dev = NULL;
                }
 
-               memset(sk_pppox(po) + 1, 0,
-                      sizeof(struct pppox_sock) - sizeof(struct sock));
+               po->pppoe_ifindex = 0;
+               memset(&po->pppoe_pa, 0, sizeof(po->pppoe_pa));
+               memset(&po->pppoe_relay, 0, sizeof(po->pppoe_relay));
+               memset(&po->chan, 0, sizeof(po->chan));
+               po->next = NULL;
+               po->num = 0;
+
                sk->sk_state = PPPOX_NONE;
        }
 
index fc69e41d09506e96b38f067fa05175bd680fa36b..597c53e0a2ecce6a7fecaaf5032006f31795b307 100644 (file)
@@ -419,6 +419,9 @@ static int pptp_bind(struct socket *sock, struct sockaddr *uservaddr,
        struct pptp_opt *opt = &po->proto.pptp;
        int error = 0;
 
+       if (sockaddr_len < sizeof(struct sockaddr_pppox))
+               return -EINVAL;
+
        lock_sock(sk);
 
        opt->src_addr = sp->sa_addr.pptp;
@@ -440,6 +443,9 @@ static int pptp_connect(struct socket *sock, struct sockaddr *uservaddr,
        struct flowi4 fl4;
        int error = 0;
 
+       if (sockaddr_len < sizeof(struct sockaddr_pppox))
+               return -EINVAL;
+
        if (sp->sa_protocol != PX_PROTO_PPTP)
                return -EINVAL;
 
index b1878faea3974f6ae984763109edae78c4cd3342..f0db770e8b2f9655be8d3c3000a9395f945284e2 100644 (file)
@@ -1040,7 +1040,7 @@ static unsigned int tun_chr_poll(struct file *file, poll_table *wait)
                mask |= POLLIN | POLLRDNORM;
 
        if (sock_writeable(sk) ||
-           (!test_and_set_bit(SOCK_ASYNC_NOSPACE, &sk->sk_socket->flags) &&
+           (!test_and_set_bit(SOCKWQ_ASYNC_NOSPACE, &sk->sk_socket->flags) &&
             sock_writeable(sk)))
                mask |= POLLOUT | POLLWRNORM;
 
@@ -1488,7 +1488,7 @@ static void tun_sock_write_space(struct sock *sk)
        if (!sock_writeable(sk))
                return;
 
-       if (!test_and_clear_bit(SOCK_ASYNC_NOSPACE, &sk->sk_socket->flags))
+       if (!test_and_clear_bit(SOCKWQ_ASYNC_NOSPACE, &sk->sk_socket->flags))
                return;
 
        wqueue = sk_sleep(sk);
index c78d3cb1b4648f771a2b5835e9424cd08c74d182..3da70bf9936a846c5939c389c2d91af1c674af58 100644 (file)
@@ -695,6 +695,11 @@ static const struct usb_device_id  products[] = {
        USB_VENDOR_AND_INTERFACE_INFO(0x1bc7, USB_CLASS_COMM,
                        USB_CDC_SUBCLASS_ETHERNET, USB_CDC_PROTO_NONE),
        .driver_info = (kernel_ulong_t) &wwan_info,
+}, {
+       /* Dell DW5580 modules */
+       USB_DEVICE_AND_INTERFACE_INFO(DELL_VENDOR_ID, 0x81ba, USB_CLASS_COMM,
+                       USB_CDC_SUBCLASS_ETHERNET, USB_CDC_PROTO_NONE),
+       .driver_info = (kernel_ulong_t)&wwan_info,
 }, {
        USB_INTERFACE_INFO(USB_CLASS_COMM, USB_CDC_SUBCLASS_ETHERNET,
                        USB_CDC_PROTO_NONE),
index bbde9884ab8ae7fb952cbf6583feff10c9ce1109..bdd83d95ec0aa677b8443476ef2ee66018aff701 100644 (file)
@@ -100,7 +100,7 @@ static const struct net_device_ops cdc_mbim_netdev_ops = {
        .ndo_stop             = usbnet_stop,
        .ndo_start_xmit       = usbnet_start_xmit,
        .ndo_tx_timeout       = usbnet_tx_timeout,
-       .ndo_change_mtu       = usbnet_change_mtu,
+       .ndo_change_mtu       = cdc_ncm_change_mtu,
        .ndo_set_mac_address  = eth_mac_addr,
        .ndo_validate_addr    = eth_validate_addr,
        .ndo_vlan_rx_add_vid  = cdc_mbim_rx_add_vid,
@@ -158,7 +158,7 @@ static int cdc_mbim_bind(struct usbnet *dev, struct usb_interface *intf)
        if (!cdc_ncm_comm_intf_is_mbim(intf->cur_altsetting))
                goto err;
 
-       ret = cdc_ncm_bind_common(dev, intf, data_altsetting, 0);
+       ret = cdc_ncm_bind_common(dev, intf, data_altsetting, dev->driver_info->data);
        if (ret)
                goto err;
 
@@ -582,6 +582,26 @@ static const struct driver_info cdc_mbim_info_zlp = {
        .tx_fixup = cdc_mbim_tx_fixup,
 };
 
+/* The spefication explicitly allows NDPs to be placed anywhere in the
+ * frame, but some devices fail unless the NDP is placed after the IP
+ * packets.  Using the CDC_NCM_FLAG_NDP_TO_END flags to force this
+ * behaviour.
+ *
+ * Note: The current implementation of this feature restricts each NTB
+ * to a single NDP, implying that multiplexed sessions cannot share an
+ * NTB. This might affect performace for multiplexed sessions.
+ */
+static const struct driver_info cdc_mbim_info_ndp_to_end = {
+       .description = "CDC MBIM",
+       .flags = FLAG_NO_SETINT | FLAG_MULTI_PACKET | FLAG_WWAN,
+       .bind = cdc_mbim_bind,
+       .unbind = cdc_mbim_unbind,
+       .manage_power = cdc_mbim_manage_power,
+       .rx_fixup = cdc_mbim_rx_fixup,
+       .tx_fixup = cdc_mbim_tx_fixup,
+       .data = CDC_NCM_FLAG_NDP_TO_END,
+};
+
 static const struct usb_device_id mbim_devs[] = {
        /* This duplicate NCM entry is intentional. MBIM devices can
         * be disguised as NCM by default, and this is necessary to
@@ -597,6 +617,10 @@ static const struct usb_device_id mbim_devs[] = {
        { USB_VENDOR_AND_INTERFACE_INFO(0x0bdb, USB_CLASS_COMM, USB_CDC_SUBCLASS_MBIM, USB_CDC_PROTO_NONE),
          .driver_info = (unsigned long)&cdc_mbim_info,
        },
+       /* Huawei E3372 fails unless NDP comes after the IP packets */
+       { USB_DEVICE_AND_INTERFACE_INFO(0x12d1, 0x157d, USB_CLASS_COMM, USB_CDC_SUBCLASS_MBIM, USB_CDC_PROTO_NONE),
+         .driver_info = (unsigned long)&cdc_mbim_info_ndp_to_end,
+       },
        /* default entry */
        { USB_INTERFACE_INFO(USB_CLASS_COMM, USB_CDC_SUBCLASS_MBIM, USB_CDC_PROTO_NONE),
          .driver_info = (unsigned long)&cdc_mbim_info_zlp,
index a187f08113ecbb77612dd11a2611d4649d79c47d..e8a1144c5a8bfa28c1ddca137c56c888b176ab32 100644 (file)
@@ -41,6 +41,7 @@
 #include <linux/module.h>
 #include <linux/netdevice.h>
 #include <linux/ctype.h>
+#include <linux/etherdevice.h>
 #include <linux/ethtool.h>
 #include <linux/workqueue.h>
 #include <linux/mii.h>
@@ -689,9 +690,35 @@ static void cdc_ncm_free(struct cdc_ncm_ctx *ctx)
        kfree(ctx);
 }
 
+/* we need to override the usbnet change_mtu ndo for two reasons:
+ *  - respect the negotiated maximum datagram size
+ *  - avoid unwanted changes to rx and tx buffers
+ */
+int cdc_ncm_change_mtu(struct net_device *net, int new_mtu)
+{
+       struct usbnet *dev = netdev_priv(net);
+       struct cdc_ncm_ctx *ctx = (struct cdc_ncm_ctx *)dev->data[0];
+       int maxmtu = ctx->max_datagram_size - cdc_ncm_eth_hlen(dev);
+
+       if (new_mtu <= 0 || new_mtu > maxmtu)
+               return -EINVAL;
+       net->mtu = new_mtu;
+       return 0;
+}
+EXPORT_SYMBOL_GPL(cdc_ncm_change_mtu);
+
+static const struct net_device_ops cdc_ncm_netdev_ops = {
+       .ndo_open            = usbnet_open,
+       .ndo_stop            = usbnet_stop,
+       .ndo_start_xmit      = usbnet_start_xmit,
+       .ndo_tx_timeout      = usbnet_tx_timeout,
+       .ndo_change_mtu      = cdc_ncm_change_mtu,
+       .ndo_set_mac_address = eth_mac_addr,
+       .ndo_validate_addr   = eth_validate_addr,
+};
+
 int cdc_ncm_bind_common(struct usbnet *dev, struct usb_interface *intf, u8 data_altsetting, int drvflags)
 {
-       const struct usb_cdc_union_desc *union_desc = NULL;
        struct cdc_ncm_ctx *ctx;
        struct usb_driver *driver;
        u8 *buf;
@@ -725,15 +752,16 @@ int cdc_ncm_bind_common(struct usbnet *dev, struct usb_interface *intf, u8 data_
        /* parse through descriptors associated with control interface */
        cdc_parse_cdc_header(&hdr, intf, buf, len);
 
-       ctx->data = usb_ifnum_to_if(dev->udev,
-                                   hdr.usb_cdc_union_desc->bSlaveInterface0);
+       if (hdr.usb_cdc_union_desc)
+               ctx->data = usb_ifnum_to_if(dev->udev,
+                                           hdr.usb_cdc_union_desc->bSlaveInterface0);
        ctx->ether_desc = hdr.usb_cdc_ether_desc;
        ctx->func_desc = hdr.usb_cdc_ncm_desc;
        ctx->mbim_desc = hdr.usb_cdc_mbim_desc;
        ctx->mbim_extended_desc = hdr.usb_cdc_mbim_extended_desc;
 
        /* some buggy devices have an IAD but no CDC Union */
-       if (!union_desc && intf->intf_assoc && intf->intf_assoc->bInterfaceCount == 2) {
+       if (!hdr.usb_cdc_union_desc && intf->intf_assoc && intf->intf_assoc->bInterfaceCount == 2) {
                ctx->data = usb_ifnum_to_if(dev->udev, intf->cur_altsetting->desc.bInterfaceNumber + 1);
                dev_dbg(&intf->dev, "CDC Union missing - got slave from IAD\n");
        }
@@ -823,6 +851,9 @@ int cdc_ncm_bind_common(struct usbnet *dev, struct usb_interface *intf, u8 data_
        /* add our sysfs attrs */
        dev->net->sysfs_groups[0] = &cdc_ncm_sysfs_attr_group;
 
+       /* must handle MTU changes */
+       dev->net->netdev_ops = &cdc_ncm_netdev_ops;
+
        return 0;
 
 error2:
@@ -955,10 +986,18 @@ static struct usb_cdc_ncm_ndp16 *cdc_ncm_ndp(struct cdc_ncm_ctx *ctx, struct sk_
        * NTH16 header as we would normally do. NDP isn't written to the SKB yet, and
        * the wNdpIndex field in the header is actually not consistent with reality. It will be later.
        */
-       if (ctx->drvflags & CDC_NCM_FLAG_NDP_TO_END)
+       if (ctx->drvflags & CDC_NCM_FLAG_NDP_TO_END) {
                if (ctx->delayed_ndp16->dwSignature == sign)
                        return ctx->delayed_ndp16;
 
+               /* We can only push a single NDP to the end. Return
+                * NULL to send what we've already got and queue this
+                * skb for later.
+                */
+               else if (ctx->delayed_ndp16->dwSignature)
+                       return NULL;
+       }
+
        /* follow the chain of NDPs, looking for a match */
        while (ndpoffset) {
                ndp16 = (struct usb_cdc_ncm_ndp16 *)(skb->data + ndpoffset);
@@ -1550,6 +1589,24 @@ static const struct usb_device_id cdc_devs[] = {
          .driver_info = (unsigned long) &wwan_info,
        },
 
+       /* DW5812 LTE Verizon Mobile Broadband Card
+        * Unlike DW5550 this device requires FLAG_NOARP
+        */
+       { USB_DEVICE_AND_INTERFACE_INFO(0x413c, 0x81bb,
+               USB_CLASS_COMM,
+               USB_CDC_SUBCLASS_NCM, USB_CDC_PROTO_NONE),
+         .driver_info = (unsigned long)&wwan_noarp_info,
+       },
+
+       /* DW5813 LTE AT&T Mobile Broadband Card
+        * Unlike DW5550 this device requires FLAG_NOARP
+        */
+       { USB_DEVICE_AND_INTERFACE_INFO(0x413c, 0x81bc,
+               USB_CLASS_COMM,
+               USB_CDC_SUBCLASS_NCM, USB_CDC_PROTO_NONE),
+         .driver_info = (unsigned long)&wwan_noarp_info,
+       },
+
        /* Dell branded MBM devices like DW5550 */
        { .match_flags = USB_DEVICE_ID_MATCH_INT_INFO
                | USB_DEVICE_ID_MATCH_VENDOR,
index 34799eaace41bcdb93cfa4c1ed76af31ae052ef3..9a5be8b851867e53f7427ba31f7a089ad02562fd 100644 (file)
@@ -725,6 +725,7 @@ static const struct usb_device_id products[] = {
        {QMI_FIXED_INTF(0x2357, 0x9000, 4)},    /* TP-LINK MA260 */
        {QMI_FIXED_INTF(0x1bc7, 0x1200, 5)},    /* Telit LE920 */
        {QMI_FIXED_INTF(0x1bc7, 0x1201, 2)},    /* Telit LE920 */
+       {QMI_FIXED_INTF(0x1c9e, 0x9b01, 3)},    /* XS Stick W100-2 from 4G Systems */
        {QMI_FIXED_INTF(0x0b3c, 0xc000, 4)},    /* Olivetti Olicard 100 */
        {QMI_FIXED_INTF(0x0b3c, 0xc001, 4)},    /* Olivetti Olicard 120 */
        {QMI_FIXED_INTF(0x0b3c, 0xc002, 4)},    /* Olivetti Olicard 140 */
index d9427ca3dba79628f402867b83e735bee78fac3b..2e32c41536ae9b0048e81e3fbb1faf8aa11327c3 100644 (file)
@@ -3067,17 +3067,6 @@ static int rtl8152_open(struct net_device *netdev)
 
        mutex_lock(&tp->control);
 
-       /* The WORK_ENABLE may be set when autoresume occurs */
-       if (test_bit(WORK_ENABLE, &tp->flags)) {
-               clear_bit(WORK_ENABLE, &tp->flags);
-               usb_kill_urb(tp->intr_urb);
-               cancel_delayed_work_sync(&tp->schedule);
-
-               /* disable the tx/rx, if the workqueue has enabled them. */
-               if (netif_carrier_ok(netdev))
-                       tp->rtl_ops.disable(tp);
-       }
-
        tp->rtl_ops.up(tp);
 
        rtl8152_set_speed(tp, AUTONEG_ENABLE,
@@ -3124,12 +3113,6 @@ static int rtl8152_close(struct net_device *netdev)
        } else {
                mutex_lock(&tp->control);
 
-               /* The autosuspend may have been enabled and wouldn't
-                * be disable when autoresume occurs, because the
-                * netif_running() would be false.
-                */
-               rtl_runtime_suspend_enable(tp, false);
-
                tp->rtl_ops.down(tp);
 
                mutex_unlock(&tp->control);
@@ -3512,7 +3495,7 @@ static int rtl8152_resume(struct usb_interface *intf)
                netif_device_attach(tp->netdev);
        }
 
-       if (netif_running(tp->netdev)) {
+       if (netif_running(tp->netdev) && tp->netdev->flags & IFF_UP) {
                if (test_bit(SELECTIVE_SUSPEND, &tp->flags)) {
                        rtl_runtime_suspend_enable(tp, false);
                        clear_bit(SELECTIVE_SUSPEND, &tp->flags);
@@ -3532,6 +3515,8 @@ static int rtl8152_resume(struct usb_interface *intf)
                }
                usb_submit_urb(tp->intr_urb, GFP_KERNEL);
        } else if (test_bit(SELECTIVE_SUSPEND, &tp->flags)) {
+               if (tp->netdev->flags & IFF_UP)
+                       rtl_runtime_suspend_enable(tp, false);
                clear_bit(SELECTIVE_SUSPEND, &tp->flags);
        }
 
index 0ef4a5ad555739870897bfbb96c7a95847deed20..ba21d072be31c95827833f9e5014f20cfa43bb8b 100644 (file)
@@ -117,12 +117,6 @@ static netdev_tx_t veth_xmit(struct sk_buff *skb, struct net_device *dev)
                kfree_skb(skb);
                goto drop;
        }
-       /* don't change ip_summed == CHECKSUM_PARTIAL, as that
-        * will cause bad checksum on forwarded packets
-        */
-       if (skb->ip_summed == CHECKSUM_NONE &&
-           rcv->features & NETIF_F_RXCSUM)
-               skb->ip_summed = CHECKSUM_UNNECESSARY;
 
        if (likely(dev_forward_skb(rcv, skb) == NET_RX_SUCCESS)) {
                struct pcpu_vstats *stats = this_cpu_ptr(dev->vstats);
index d8838dedb7a4cd06f54e2fa8a522b6c4bb15091e..f94ab786088fc8fd7f848edeaedd4d2aff160606 100644 (file)
@@ -140,6 +140,12 @@ struct virtnet_info {
 
        /* CPU hot plug notifier */
        struct notifier_block nb;
+
+       /* Control VQ buffers: protected by the rtnl lock */
+       struct virtio_net_ctrl_hdr ctrl_hdr;
+       virtio_net_ctrl_ack ctrl_status;
+       u8 ctrl_promisc;
+       u8 ctrl_allmulti;
 };
 
 struct padded_vnet_hdr {
@@ -976,31 +982,30 @@ static bool virtnet_send_command(struct virtnet_info *vi, u8 class, u8 cmd,
                                 struct scatterlist *out)
 {
        struct scatterlist *sgs[4], hdr, stat;
-       struct virtio_net_ctrl_hdr ctrl;
-       virtio_net_ctrl_ack status = ~0;
        unsigned out_num = 0, tmp;
 
        /* Caller should know better */
        BUG_ON(!virtio_has_feature(vi->vdev, VIRTIO_NET_F_CTRL_VQ));
 
-       ctrl.class = class;
-       ctrl.cmd = cmd;
+       vi->ctrl_status = ~0;
+       vi->ctrl_hdr.class = class;
+       vi->ctrl_hdr.cmd = cmd;
        /* Add header */
-       sg_init_one(&hdr, &ctrl, sizeof(ctrl));
+       sg_init_one(&hdr, &vi->ctrl_hdr, sizeof(vi->ctrl_hdr));
        sgs[out_num++] = &hdr;
 
        if (out)
                sgs[out_num++] = out;
 
        /* Add return status. */
-       sg_init_one(&stat, &status, sizeof(status));
+       sg_init_one(&stat, &vi->ctrl_status, sizeof(vi->ctrl_status));
        sgs[out_num] = &stat;
 
        BUG_ON(out_num + 1 > ARRAY_SIZE(sgs));
        virtqueue_add_sgs(vi->cvq, sgs, out_num, 1, vi, GFP_ATOMIC);
 
        if (unlikely(!virtqueue_kick(vi->cvq)))
-               return status == VIRTIO_NET_OK;
+               return vi->ctrl_status == VIRTIO_NET_OK;
 
        /* Spin for a response, the kick causes an ioport write, trapping
         * into the hypervisor, so the request should be handled immediately.
@@ -1009,7 +1014,7 @@ static bool virtnet_send_command(struct virtnet_info *vi, u8 class, u8 cmd,
               !virtqueue_is_broken(vi->cvq))
                cpu_relax();
 
-       return status == VIRTIO_NET_OK;
+       return vi->ctrl_status == VIRTIO_NET_OK;
 }
 
 static int virtnet_set_mac_address(struct net_device *dev, void *p)
@@ -1151,7 +1156,6 @@ static void virtnet_set_rx_mode(struct net_device *dev)
 {
        struct virtnet_info *vi = netdev_priv(dev);
        struct scatterlist sg[2];
-       u8 promisc, allmulti;
        struct virtio_net_ctrl_mac *mac_data;
        struct netdev_hw_addr *ha;
        int uc_count;
@@ -1163,22 +1167,22 @@ static void virtnet_set_rx_mode(struct net_device *dev)
        if (!virtio_has_feature(vi->vdev, VIRTIO_NET_F_CTRL_RX))
                return;
 
-       promisc = ((dev->flags & IFF_PROMISC) != 0);
-       allmulti = ((dev->flags & IFF_ALLMULTI) != 0);
+       vi->ctrl_promisc = ((dev->flags & IFF_PROMISC) != 0);
+       vi->ctrl_allmulti = ((dev->flags & IFF_ALLMULTI) != 0);
 
-       sg_init_one(sg, &promisc, sizeof(promisc));
+       sg_init_one(sg, &vi->ctrl_promisc, sizeof(vi->ctrl_promisc));
 
        if (!virtnet_send_command(vi, VIRTIO_NET_CTRL_RX,
                                  VIRTIO_NET_CTRL_RX_PROMISC, sg))
                dev_warn(&dev->dev, "Failed to %sable promisc mode.\n",
-                        promisc ? "en" : "dis");
+                        vi->ctrl_promisc ? "en" : "dis");
 
-       sg_init_one(sg, &allmulti, sizeof(allmulti));
+       sg_init_one(sg, &vi->ctrl_allmulti, sizeof(vi->ctrl_allmulti));
 
        if (!virtnet_send_command(vi, VIRTIO_NET_CTRL_RX,
                                  VIRTIO_NET_CTRL_RX_ALLMULTI, sg))
                dev_warn(&dev->dev, "Failed to %sable allmulti mode.\n",
-                        allmulti ? "en" : "dis");
+                        vi->ctrl_allmulti ? "en" : "dis");
 
        uc_count = netdev_uc_count(dev);
        mc_count = netdev_mc_count(dev);
index 46f4caddccbed84a56b12aad93a683618401fbdb..417903715437ebda5b07a859effdca86a62d196b 100644 (file)
@@ -587,6 +587,12 @@ vmxnet3_rq_alloc_rx_buf(struct vmxnet3_rx_queue *rq, u32 ring_idx,
                                                &adapter->pdev->dev,
                                                rbi->skb->data, rbi->len,
                                                PCI_DMA_FROMDEVICE);
+                               if (dma_mapping_error(&adapter->pdev->dev,
+                                                     rbi->dma_addr)) {
+                                       dev_kfree_skb_any(rbi->skb);
+                                       rq->stats.rx_buf_alloc_failure++;
+                                       break;
+                               }
                        } else {
                                /* rx buffer skipped by the device */
                        }
@@ -605,13 +611,18 @@ vmxnet3_rq_alloc_rx_buf(struct vmxnet3_rx_queue *rq, u32 ring_idx,
                                                &adapter->pdev->dev,
                                                rbi->page, 0, PAGE_SIZE,
                                                PCI_DMA_FROMDEVICE);
+                               if (dma_mapping_error(&adapter->pdev->dev,
+                                                     rbi->dma_addr)) {
+                                       put_page(rbi->page);
+                                       rq->stats.rx_buf_alloc_failure++;
+                                       break;
+                               }
                        } else {
                                /* rx buffers skipped by the device */
                        }
                        val = VMXNET3_RXD_BTYPE_BODY << VMXNET3_RXD_BTYPE_SHIFT;
                }
 
-               BUG_ON(rbi->dma_addr == 0);
                gd->rxd.addr = cpu_to_le64(rbi->dma_addr);
                gd->dword[2] = cpu_to_le32((!ring->gen << VMXNET3_RXD_GEN_SHIFT)
                                           | val | rbi->len);
@@ -655,7 +666,7 @@ vmxnet3_append_frag(struct sk_buff *skb, struct Vmxnet3_RxCompDesc *rcd,
 }
 
 
-static void
+static int
 vmxnet3_map_pkt(struct sk_buff *skb, struct vmxnet3_tx_ctx *ctx,
                struct vmxnet3_tx_queue *tq, struct pci_dev *pdev,
                struct vmxnet3_adapter *adapter)
@@ -715,6 +726,8 @@ vmxnet3_map_pkt(struct sk_buff *skb, struct vmxnet3_tx_ctx *ctx,
                tbi->dma_addr = dma_map_single(&adapter->pdev->dev,
                                skb->data + buf_offset, buf_size,
                                PCI_DMA_TODEVICE);
+               if (dma_mapping_error(&adapter->pdev->dev, tbi->dma_addr))
+                       return -EFAULT;
 
                tbi->len = buf_size;
 
@@ -755,6 +768,8 @@ vmxnet3_map_pkt(struct sk_buff *skb, struct vmxnet3_tx_ctx *ctx,
                        tbi->dma_addr = skb_frag_dma_map(&adapter->pdev->dev, frag,
                                                         buf_offset, buf_size,
                                                         DMA_TO_DEVICE);
+                       if (dma_mapping_error(&adapter->pdev->dev, tbi->dma_addr))
+                               return -EFAULT;
 
                        tbi->len = buf_size;
 
@@ -782,6 +797,8 @@ vmxnet3_map_pkt(struct sk_buff *skb, struct vmxnet3_tx_ctx *ctx,
        /* set the last buf_info for the pkt */
        tbi->skb = skb;
        tbi->sop_idx = ctx->sop_txd - tq->tx_ring.base;
+
+       return 0;
 }
 
 
@@ -1020,7 +1037,8 @@ vmxnet3_tq_xmit(struct sk_buff *skb, struct vmxnet3_tx_queue *tq,
        }
 
        /* fill tx descs related to addr & len */
-       vmxnet3_map_pkt(skb, &ctx, tq, adapter->pdev, adapter);
+       if (vmxnet3_map_pkt(skb, &ctx, tq, adapter->pdev, adapter))
+               goto unlock_drop_pkt;
 
        /* setup the EOP desc */
        ctx.eop_txd->dword[3] = cpu_to_le32(VMXNET3_TXD_CQ | VMXNET3_TXD_EOP);
@@ -1231,6 +1249,7 @@ vmxnet3_rq_rx_complete(struct vmxnet3_rx_queue *rq,
                struct vmxnet3_rx_buf_info *rbi;
                struct sk_buff *skb, *new_skb = NULL;
                struct page *new_page = NULL;
+               dma_addr_t new_dma_addr;
                int num_to_alloc;
                struct Vmxnet3_RxDesc *rxd;
                u32 idx, ring_idx;
@@ -1287,6 +1306,21 @@ vmxnet3_rq_rx_complete(struct vmxnet3_rx_queue *rq,
                                skip_page_frags = true;
                                goto rcd_done;
                        }
+                       new_dma_addr = dma_map_single(&adapter->pdev->dev,
+                                                     new_skb->data, rbi->len,
+                                                     PCI_DMA_FROMDEVICE);
+                       if (dma_mapping_error(&adapter->pdev->dev,
+                                             new_dma_addr)) {
+                               dev_kfree_skb(new_skb);
+                               /* Skb allocation failed, do not handover this
+                                * skb to stack. Reuse it. Drop the existing pkt
+                                */
+                               rq->stats.rx_buf_alloc_failure++;
+                               ctx->skb = NULL;
+                               rq->stats.drop_total++;
+                               skip_page_frags = true;
+                               goto rcd_done;
+                       }
 
                        dma_unmap_single(&adapter->pdev->dev, rbi->dma_addr,
                                         rbi->len,
@@ -1303,9 +1337,7 @@ vmxnet3_rq_rx_complete(struct vmxnet3_rx_queue *rq,
 
                        /* Immediate refill */
                        rbi->skb = new_skb;
-                       rbi->dma_addr = dma_map_single(&adapter->pdev->dev,
-                                                      rbi->skb->data, rbi->len,
-                                                      PCI_DMA_FROMDEVICE);
+                       rbi->dma_addr = new_dma_addr;
                        rxd->addr = cpu_to_le64(rbi->dma_addr);
                        rxd->len = rbi->len;
                        if (adapter->version == 2 &&
@@ -1348,6 +1380,19 @@ vmxnet3_rq_rx_complete(struct vmxnet3_rx_queue *rq,
                                        skip_page_frags = true;
                                        goto rcd_done;
                                }
+                               new_dma_addr = dma_map_page(&adapter->pdev->dev
+                                                       , rbi->page,
+                                                       0, PAGE_SIZE,
+                                                       PCI_DMA_FROMDEVICE);
+                               if (dma_mapping_error(&adapter->pdev->dev,
+                                                     new_dma_addr)) {
+                                       put_page(new_page);
+                                       rq->stats.rx_buf_alloc_failure++;
+                                       dev_kfree_skb(ctx->skb);
+                                       ctx->skb = NULL;
+                                       skip_page_frags = true;
+                                       goto rcd_done;
+                               }
 
                                dma_unmap_page(&adapter->pdev->dev,
                                               rbi->dma_addr, rbi->len,
@@ -1357,10 +1402,7 @@ vmxnet3_rq_rx_complete(struct vmxnet3_rx_queue *rq,
 
                                /* Immediate refill */
                                rbi->page = new_page;
-                               rbi->dma_addr = dma_map_page(&adapter->pdev->dev
-                                                       , rbi->page,
-                                                       0, PAGE_SIZE,
-                                                       PCI_DMA_FROMDEVICE);
+                               rbi->dma_addr = new_dma_addr;
                                rxd->addr = cpu_to_le64(rbi->dma_addr);
                                rxd->len = rbi->len;
                        }
@@ -2157,16 +2199,18 @@ vmxnet3_set_mc(struct net_device *netdev)
                if (!netdev_mc_empty(netdev)) {
                        new_table = vmxnet3_copy_mc(netdev);
                        if (new_table) {
-                               rxConf->mfTableLen = cpu_to_le16(
-                                       netdev_mc_count(netdev) * ETH_ALEN);
+                               size_t sz = netdev_mc_count(netdev) * ETH_ALEN;
+
+                               rxConf->mfTableLen = cpu_to_le16(sz);
                                new_table_pa = dma_map_single(
                                                        &adapter->pdev->dev,
                                                        new_table,
-                                                       rxConf->mfTableLen,
+                                                       sz,
                                                        PCI_DMA_TODEVICE);
                        }
 
-                       if (new_table_pa) {
+                       if (!dma_mapping_error(&adapter->pdev->dev,
+                                              new_table_pa)) {
                                new_mode |= VMXNET3_RXM_MCAST;
                                rxConf->mfTablePA = cpu_to_le64(new_table_pa);
                        } else {
@@ -3074,6 +3118,11 @@ vmxnet3_probe_device(struct pci_dev *pdev,
        adapter->adapter_pa = dma_map_single(&adapter->pdev->dev, adapter,
                                             sizeof(struct vmxnet3_adapter),
                                             PCI_DMA_TODEVICE);
+       if (dma_mapping_error(&adapter->pdev->dev, adapter->adapter_pa)) {
+               dev_err(&pdev->dev, "Failed to map dma\n");
+               err = -EFAULT;
+               goto err_dma_map;
+       }
        adapter->shared = dma_alloc_coherent(
                                &adapter->pdev->dev,
                                sizeof(struct Vmxnet3_DriverShared),
@@ -3232,6 +3281,7 @@ err_alloc_queue_desc:
 err_alloc_shared:
        dma_unmap_single(&adapter->pdev->dev, adapter->adapter_pa,
                         sizeof(struct vmxnet3_adapter), PCI_DMA_TODEVICE);
+err_dma_map:
        free_netdev(netdev);
        return err;
 }
index 3f859a55c035d6ab3b53530c4345083424566404..4c58c83dc2253a43b7c6150866d67bcd0c02e250 100644 (file)
 /*
  * Version numbers
  */
-#define VMXNET3_DRIVER_VERSION_STRING   "1.4.3.0-k"
+#define VMXNET3_DRIVER_VERSION_STRING   "1.4.4.0-k"
 
 /* a 32-bit int, each byte encode a verion number in VMXNET3_DRIVER_VERSION */
-#define VMXNET3_DRIVER_VERSION_NUM      0x01040300
+#define VMXNET3_DRIVER_VERSION_NUM      0x01040400
 
 #if defined(CONFIG_PCI_MSI)
        /* RSS only makes sense if MSI-X is supported. */
index 92fa3e1ea65cca564907a43a78a859b6063f7f65..4f9748457f5a722658e5cfb01b6cbcc0f488d14f 100644 (file)
@@ -907,7 +907,6 @@ static int vrf_newlink(struct net *src_net, struct net_device *dev,
                       struct nlattr *tb[], struct nlattr *data[])
 {
        struct net_vrf *vrf = netdev_priv(dev);
-       int err;
 
        if (!data || !data[IFLA_VRF_TABLE])
                return -EINVAL;
@@ -916,15 +915,7 @@ static int vrf_newlink(struct net *src_net, struct net_device *dev,
 
        dev->priv_flags |= IFF_L3MDEV_MASTER;
 
-       err = register_netdevice(dev);
-       if (err < 0)
-               goto out_fail;
-
-       return 0;
-
-out_fail:
-       free_netdev(dev);
-       return err;
+       return register_netdevice(dev);
 }
 
 static size_t vrf_nl_getsize(const struct net_device *dev)
index 6369a5734d4c3e899e96ec74469b0af4b3bca865..ba363cedef80820feb11b5ce6f5f347f8a575d12 100644 (file)
@@ -1158,7 +1158,6 @@ static void vxlan_rcv(struct vxlan_sock *vs, struct sk_buff *skb,
        struct pcpu_sw_netstats *stats;
        union vxlan_addr saddr;
        int err = 0;
-       union vxlan_addr *remote_ip;
 
        /* For flow based devices, map all packets to VNI 0 */
        if (vs->flags & VXLAN_F_COLLECT_METADATA)
@@ -1169,7 +1168,6 @@ static void vxlan_rcv(struct vxlan_sock *vs, struct sk_buff *skb,
        if (!vxlan)
                goto drop;
 
-       remote_ip = &vxlan->default_dst.remote_ip;
        skb_reset_mac_header(skb);
        skb_scrub_packet(skb, !net_eq(vxlan->net, dev_net(vxlan->dev)));
        skb->protocol = eth_type_trans(skb, vxlan->dev);
@@ -1179,8 +1177,8 @@ static void vxlan_rcv(struct vxlan_sock *vs, struct sk_buff *skb,
        if (ether_addr_equal(eth_hdr(skb)->h_source, vxlan->dev->dev_addr))
                goto drop;
 
-       /* Re-examine inner Ethernet packet */
-       if (remote_ip->sa.sa_family == AF_INET) {
+       /* Get data from the outer IP header */
+       if (vxlan_get_sk_family(vs) == AF_INET) {
                oip = ip_hdr(skb);
                saddr.sin.sin_addr.s_addr = oip->saddr;
                saddr.sa.sa_family = AF_INET;
@@ -1848,6 +1846,34 @@ static int vxlan_xmit_skb(struct rtable *rt, struct sock *sk, struct sk_buff *sk
                                   !(vxflags & VXLAN_F_UDP_CSUM));
 }
 
+#if IS_ENABLED(CONFIG_IPV6)
+static struct dst_entry *vxlan6_get_route(struct vxlan_dev *vxlan,
+                                         struct sk_buff *skb, int oif,
+                                         const struct in6_addr *daddr,
+                                         struct in6_addr *saddr)
+{
+       struct dst_entry *ndst;
+       struct flowi6 fl6;
+       int err;
+
+       memset(&fl6, 0, sizeof(fl6));
+       fl6.flowi6_oif = oif;
+       fl6.daddr = *daddr;
+       fl6.saddr = vxlan->cfg.saddr.sin6.sin6_addr;
+       fl6.flowi6_mark = skb->mark;
+       fl6.flowi6_proto = IPPROTO_UDP;
+
+       err = ipv6_stub->ipv6_dst_lookup(vxlan->net,
+                                        vxlan->vn6_sock->sock->sk,
+                                        &ndst, &fl6);
+       if (err < 0)
+               return ERR_PTR(err);
+
+       *saddr = fl6.saddr;
+       return ndst;
+}
+#endif
+
 /* Bypass encapsulation if the destination is local */
 static void vxlan_encap_bypass(struct sk_buff *skb, struct vxlan_dev *src_vxlan,
                               struct vxlan_dev *dst_vxlan)
@@ -2035,21 +2061,17 @@ static void vxlan_xmit_one(struct sk_buff *skb, struct net_device *dev,
 #if IS_ENABLED(CONFIG_IPV6)
        } else {
                struct dst_entry *ndst;
-               struct flowi6 fl6;
+               struct in6_addr saddr;
                u32 rt6i_flags;
 
                if (!vxlan->vn6_sock)
                        goto drop;
                sk = vxlan->vn6_sock->sock->sk;
 
-               memset(&fl6, 0, sizeof(fl6));
-               fl6.flowi6_oif = rdst ? rdst->remote_ifindex : 0;
-               fl6.daddr = dst->sin6.sin6_addr;
-               fl6.saddr = vxlan->cfg.saddr.sin6.sin6_addr;
-               fl6.flowi6_mark = skb->mark;
-               fl6.flowi6_proto = IPPROTO_UDP;
-
-               if (ipv6_stub->ipv6_dst_lookup(vxlan->net, sk, &ndst, &fl6)) {
+               ndst = vxlan6_get_route(vxlan, skb,
+                                       rdst ? rdst->remote_ifindex : 0,
+                                       &dst->sin6.sin6_addr, &saddr);
+               if (IS_ERR(ndst)) {
                        netdev_dbg(dev, "no route to %pI6\n",
                                   &dst->sin6.sin6_addr);
                        dev->stats.tx_carrier_errors++;
@@ -2081,7 +2103,7 @@ static void vxlan_xmit_one(struct sk_buff *skb, struct net_device *dev,
                }
 
                ttl = ttl ? : ip6_dst_hoplimit(ndst);
-               err = vxlan6_xmit_skb(ndst, sk, skb, dev, &fl6.saddr, &fl6.daddr,
+               err = vxlan6_xmit_skb(ndst, sk, skb, dev, &saddr, &dst->sin6.sin6_addr,
                                      0, ttl, src_port, dst_port, htonl(vni << 8), md,
                                      !net_eq(vxlan->net, dev_net(vxlan->dev)),
                                      flags);
@@ -2395,9 +2417,30 @@ static int vxlan_fill_metadata_dst(struct net_device *dev, struct sk_buff *skb)
                                  vxlan->cfg.port_max, true);
        dport = info->key.tp_dst ? : vxlan->cfg.dst_port;
 
-       if (ip_tunnel_info_af(info) == AF_INET)
+       if (ip_tunnel_info_af(info) == AF_INET) {
+               if (!vxlan->vn4_sock)
+                       return -EINVAL;
                return egress_ipv4_tun_info(dev, skb, info, sport, dport);
-       return -EINVAL;
+       } else {
+#if IS_ENABLED(CONFIG_IPV6)
+               struct dst_entry *ndst;
+
+               if (!vxlan->vn6_sock)
+                       return -EINVAL;
+               ndst = vxlan6_get_route(vxlan, skb, 0,
+                                       &info->key.u.ipv6.dst,
+                                       &info->key.u.ipv6.src);
+               if (IS_ERR(ndst))
+                       return PTR_ERR(ndst);
+               dst_release(ndst);
+
+               info->key.tp_src = sport;
+               info->key.tp_dst = dport;
+#else /* !CONFIG_IPV6 */
+               return -EPFNOSUPPORT;
+#endif
+       }
+       return 0;
 }
 
 static const struct net_device_ops vxlan_netdev_ops = {
index e92aaf61590109430aa6b9b6cd100b7d35daf90b..89541cc90e877b476bf6d1fc973d4393bc01acc7 100644 (file)
@@ -1075,11 +1075,10 @@ static int fr_add_pvc(struct net_device *frad, unsigned int dlci, int type)
 
        used = pvc_is_used(pvc);
 
-       if (type == ARPHRD_ETHER) {
+       if (type == ARPHRD_ETHER)
                dev = alloc_netdev(0, "pvceth%d", NET_NAME_UNKNOWN,
                                   ether_setup);
-               dev->priv_flags &= ~IFF_TX_SKB_SHARING;
-       } else
+       else
                dev = alloc_netdev(0, "pvc%d", NET_NAME_UNKNOWN, pvc_setup);
 
        if (!dev) {
@@ -1088,9 +1087,10 @@ static int fr_add_pvc(struct net_device *frad, unsigned int dlci, int type)
                return -ENOBUFS;
        }
 
-       if (type == ARPHRD_ETHER)
+       if (type == ARPHRD_ETHER) {
+               dev->priv_flags &= ~IFF_TX_SKB_SHARING;
                eth_hw_addr_random(dev);
-       else {
+       else {
                *(__be16*)dev->dev_addr = htons(dlci);
                dlci_to_q922(dev->broadcast, dlci);
        }
index 5c47b011a9d7f3000a27d4c81d3dc75e5f855129..cd39025d2abf5923f49e83adb08bb8de88373cb5 100644 (file)
@@ -549,16 +549,12 @@ static void x25_asy_receive_buf(struct tty_struct *tty,
 
 static int x25_asy_open_tty(struct tty_struct *tty)
 {
-       struct x25_asy *sl = tty->disc_data;
+       struct x25_asy *sl;
        int err;
 
        if (tty->ops->write == NULL)
                return -EOPNOTSUPP;
 
-       /* First make sure we're not already connected. */
-       if (sl && sl->magic == X25_ASY_MAGIC)
-               return -EEXIST;
-
        /* OK.  Find a free X.25 channel to use. */
        sl = x25_asy_alloc();
        if (sl == NULL)
index aa9bd92ac4edf7e5b78229a136ca499f8f7c15e3..0947cc271e693feaf73b3ae25d0478d2fa529ff1 100644 (file)
@@ -51,6 +51,7 @@ MODULE_PARM_DESC(rawmode, "Use raw 802.11 frame datapath");
 static const struct ath10k_hw_params ath10k_hw_params_list[] = {
        {
                .id = QCA988X_HW_2_0_VERSION,
+               .dev_id = QCA988X_2_0_DEVICE_ID,
                .name = "qca988x hw2.0",
                .patch_load_addr = QCA988X_HW_2_0_PATCH_LOAD_ADDR,
                .uart_pin = 7,
@@ -69,6 +70,25 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = {
        },
        {
                .id = QCA6174_HW_2_1_VERSION,
+               .dev_id = QCA6164_2_1_DEVICE_ID,
+               .name = "qca6164 hw2.1",
+               .patch_load_addr = QCA6174_HW_2_1_PATCH_LOAD_ADDR,
+               .uart_pin = 6,
+               .otp_exe_param = 0,
+               .channel_counters_freq_hz = 88000,
+               .max_probe_resp_desc_thres = 0,
+               .fw = {
+                       .dir = QCA6174_HW_2_1_FW_DIR,
+                       .fw = QCA6174_HW_2_1_FW_FILE,
+                       .otp = QCA6174_HW_2_1_OTP_FILE,
+                       .board = QCA6174_HW_2_1_BOARD_DATA_FILE,
+                       .board_size = QCA6174_BOARD_DATA_SZ,
+                       .board_ext_size = QCA6174_BOARD_EXT_DATA_SZ,
+               },
+       },
+       {
+               .id = QCA6174_HW_2_1_VERSION,
+               .dev_id = QCA6174_2_1_DEVICE_ID,
                .name = "qca6174 hw2.1",
                .patch_load_addr = QCA6174_HW_2_1_PATCH_LOAD_ADDR,
                .uart_pin = 6,
@@ -86,6 +106,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = {
        },
        {
                .id = QCA6174_HW_3_0_VERSION,
+               .dev_id = QCA6174_2_1_DEVICE_ID,
                .name = "qca6174 hw3.0",
                .patch_load_addr = QCA6174_HW_3_0_PATCH_LOAD_ADDR,
                .uart_pin = 6,
@@ -103,6 +124,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = {
        },
        {
                .id = QCA6174_HW_3_2_VERSION,
+               .dev_id = QCA6174_2_1_DEVICE_ID,
                .name = "qca6174 hw3.2",
                .patch_load_addr = QCA6174_HW_3_0_PATCH_LOAD_ADDR,
                .uart_pin = 6,
@@ -121,6 +143,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = {
        },
        {
                .id = QCA99X0_HW_2_0_DEV_VERSION,
+               .dev_id = QCA99X0_2_0_DEVICE_ID,
                .name = "qca99x0 hw2.0",
                .patch_load_addr = QCA99X0_HW_2_0_PATCH_LOAD_ADDR,
                .uart_pin = 7,
@@ -139,10 +162,31 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = {
        },
        {
                .id = QCA9377_HW_1_0_DEV_VERSION,
+               .dev_id = QCA9377_1_0_DEVICE_ID,
                .name = "qca9377 hw1.0",
                .patch_load_addr = QCA9377_HW_1_0_PATCH_LOAD_ADDR,
-               .uart_pin = 7,
+               .uart_pin = 6,
                .otp_exe_param = 0,
+               .channel_counters_freq_hz = 88000,
+               .max_probe_resp_desc_thres = 0,
+               .fw = {
+                       .dir = QCA9377_HW_1_0_FW_DIR,
+                       .fw = QCA9377_HW_1_0_FW_FILE,
+                       .otp = QCA9377_HW_1_0_OTP_FILE,
+                       .board = QCA9377_HW_1_0_BOARD_DATA_FILE,
+                       .board_size = QCA9377_BOARD_DATA_SZ,
+                       .board_ext_size = QCA9377_BOARD_EXT_DATA_SZ,
+               },
+       },
+       {
+               .id = QCA9377_HW_1_1_DEV_VERSION,
+               .dev_id = QCA9377_1_0_DEVICE_ID,
+               .name = "qca9377 hw1.1",
+               .patch_load_addr = QCA9377_HW_1_0_PATCH_LOAD_ADDR,
+               .uart_pin = 6,
+               .otp_exe_param = 0,
+               .channel_counters_freq_hz = 88000,
+               .max_probe_resp_desc_thres = 0,
                .fw = {
                        .dir = QCA9377_HW_1_0_FW_DIR,
                        .fw = QCA9377_HW_1_0_FW_FILE,
@@ -1263,7 +1307,8 @@ static int ath10k_init_hw_params(struct ath10k *ar)
        for (i = 0; i < ARRAY_SIZE(ath10k_hw_params_list); i++) {
                hw_params = &ath10k_hw_params_list[i];
 
-               if (hw_params->id == ar->target_version)
+               if (hw_params->id == ar->target_version &&
+                   hw_params->dev_id == ar->dev_id)
                        break;
        }
 
index 018c64f4fd25b8cf1ab8db0f3b21e65962a5f45e..858d75f49a9ffe5b1ea9e511d834bd3a5815e3de 100644 (file)
@@ -636,6 +636,7 @@ struct ath10k {
 
        struct ath10k_hw_params {
                u32 id;
+               u16 dev_id;
                const char *name;
                u32 patch_load_addr;
                int uart_pin;
index 39966a05c1cc20f5b69e7111d5ddb711a070c5e9..713c2bcea17825f701b2be37a9cf82badef11caf 100644 (file)
 
 #define ATH10K_FW_DIR                  "ath10k"
 
+#define QCA988X_2_0_DEVICE_ID   (0x003c)
+#define QCA6164_2_1_DEVICE_ID   (0x0041)
+#define QCA6174_2_1_DEVICE_ID   (0x003e)
+#define QCA99X0_2_0_DEVICE_ID   (0x0040)
+#define QCA9377_1_0_DEVICE_ID   (0x0042)
+
 /* QCA988X 1.0 definitions (unsupported) */
 #define QCA988X_HW_1_0_CHIP_ID_REV     0x0
 
 #define QCA6174_HW_3_0_VERSION         0x05020000
 #define QCA6174_HW_3_2_VERSION         0x05030000
 
+/* QCA9377 target BMI version signatures */
+#define QCA9377_HW_1_0_DEV_VERSION     0x05020000
+#define QCA9377_HW_1_1_DEV_VERSION     0x05020001
+
 enum qca6174_pci_rev {
        QCA6174_PCI_REV_1_1 = 0x11,
        QCA6174_PCI_REV_1_3 = 0x13,
@@ -60,6 +70,11 @@ enum qca6174_chip_id_rev {
        QCA6174_HW_3_2_CHIP_ID_REV = 10,
 };
 
+enum qca9377_chip_id_rev {
+       QCA9377_HW_1_0_CHIP_ID_REV = 0x0,
+       QCA9377_HW_1_1_CHIP_ID_REV = 0x1,
+};
+
 #define QCA6174_HW_2_1_FW_DIR          "ath10k/QCA6174/hw2.1"
 #define QCA6174_HW_2_1_FW_FILE         "firmware.bin"
 #define QCA6174_HW_2_1_OTP_FILE                "otp.bin"
@@ -85,8 +100,6 @@ enum qca6174_chip_id_rev {
 #define QCA99X0_HW_2_0_PATCH_LOAD_ADDR 0x1234
 
 /* QCA9377 1.0 definitions */
-#define QCA9377_HW_1_0_DEV_VERSION     0x05020001
-#define QCA9377_HW_1_0_CHIP_ID_REV     0x1
 #define QCA9377_HW_1_0_FW_DIR          ATH10K_FW_DIR "/QCA9377/hw1.0"
 #define QCA9377_HW_1_0_FW_FILE         "firmware.bin"
 #define QCA9377_HW_1_0_OTP_FILE        "otp.bin"
index a7411fe90cc43ebcef7590538cb3d6cb73a6a13a..95a55405ebf0d1f8348cbfa54f567e780c7dfc13 100644 (file)
@@ -4225,7 +4225,7 @@ static int ath10k_config(struct ieee80211_hw *hw, u32 changed)
 
 static u32 get_nss_from_chainmask(u16 chain_mask)
 {
-       if ((chain_mask & 0x15) == 0x15)
+       if ((chain_mask & 0xf) == 0xf)
                return 4;
        else if ((chain_mask & 0x7) == 0x7)
                return 3;
index 3fca200b986ca75baa0de2568d36460be709d834..930785a724e1e50705d55e6051d9f53c595ef5ed 100644 (file)
@@ -57,12 +57,6 @@ MODULE_PARM_DESC(reset_mode, "0: auto, 1: warm only (default: 0)");
 #define ATH10K_PCI_TARGET_WAIT 3000
 #define ATH10K_PCI_NUM_WARM_RESET_ATTEMPTS 3
 
-#define QCA988X_2_0_DEVICE_ID  (0x003c)
-#define QCA6164_2_1_DEVICE_ID  (0x0041)
-#define QCA6174_2_1_DEVICE_ID  (0x003e)
-#define QCA99X0_2_0_DEVICE_ID  (0x0040)
-#define QCA9377_1_0_DEVICE_ID  (0x0042)
-
 static const struct pci_device_id ath10k_pci_id_table[] = {
        { PCI_VDEVICE(ATHEROS, QCA988X_2_0_DEVICE_ID) }, /* PCI-E QCA988X V2 */
        { PCI_VDEVICE(ATHEROS, QCA6164_2_1_DEVICE_ID) }, /* PCI-E QCA6164 V2.1 */
@@ -92,7 +86,9 @@ static const struct ath10k_pci_supp_chip ath10k_pci_supp_chips[] = {
        { QCA6174_2_1_DEVICE_ID, QCA6174_HW_3_2_CHIP_ID_REV },
 
        { QCA99X0_2_0_DEVICE_ID, QCA99X0_HW_2_0_CHIP_ID_REV },
+
        { QCA9377_1_0_DEVICE_ID, QCA9377_HW_1_0_CHIP_ID_REV },
+       { QCA9377_1_0_DEVICE_ID, QCA9377_HW_1_1_CHIP_ID_REV },
 };
 
 static void ath10k_pci_buffer_cleanup(struct ath10k *ar);
@@ -111,8 +107,9 @@ static void ath10k_pci_htc_tx_cb(struct ath10k_ce_pipe *ce_state);
 static void ath10k_pci_htc_rx_cb(struct ath10k_ce_pipe *ce_state);
 static void ath10k_pci_htt_tx_cb(struct ath10k_ce_pipe *ce_state);
 static void ath10k_pci_htt_rx_cb(struct ath10k_ce_pipe *ce_state);
+static void ath10k_pci_htt_htc_rx_cb(struct ath10k_ce_pipe *ce_state);
 
-static const struct ce_attr host_ce_config_wlan[] = {
+static struct ce_attr host_ce_config_wlan[] = {
        /* CE0: host->target HTC control and raw streams */
        {
                .flags = CE_ATTR_FLAGS,
@@ -128,7 +125,7 @@ static const struct ce_attr host_ce_config_wlan[] = {
                .src_nentries = 0,
                .src_sz_max = 2048,
                .dest_nentries = 512,
-               .recv_cb = ath10k_pci_htc_rx_cb,
+               .recv_cb = ath10k_pci_htt_htc_rx_cb,
        },
 
        /* CE2: target->host WMI */
@@ -217,7 +214,7 @@ static const struct ce_attr host_ce_config_wlan[] = {
 };
 
 /* Target firmware's Copy Engine configuration. */
-static const struct ce_pipe_config target_ce_config_wlan[] = {
+static struct ce_pipe_config target_ce_config_wlan[] = {
        /* CE0: host->target HTC control and raw streams */
        {
                .pipenum = __cpu_to_le32(0),
@@ -330,7 +327,7 @@ static const struct ce_pipe_config target_ce_config_wlan[] = {
  * This table is derived from the CE_PCI TABLE, above.
  * It is passed to the Target at startup for use by firmware.
  */
-static const struct service_to_pipe target_service_to_ce_map_wlan[] = {
+static struct service_to_pipe target_service_to_ce_map_wlan[] = {
        {
                __cpu_to_le32(ATH10K_HTC_SVC_ID_WMI_DATA_VO),
                __cpu_to_le32(PIPEDIR_OUT),     /* out = UL = host -> target */
@@ -1208,6 +1205,16 @@ static void ath10k_pci_htc_rx_cb(struct ath10k_ce_pipe *ce_state)
        ath10k_pci_process_rx_cb(ce_state, ath10k_htc_rx_completion_handler);
 }
 
+static void ath10k_pci_htt_htc_rx_cb(struct ath10k_ce_pipe *ce_state)
+{
+       /* CE4 polling needs to be done whenever CE pipe which transports
+        * HTT Rx (target->host) is processed.
+        */
+       ath10k_ce_per_engine_service(ce_state->ar, 4);
+
+       ath10k_pci_process_rx_cb(ce_state, ath10k_htc_rx_completion_handler);
+}
+
 /* Called by lower (CE) layer when a send to HTT Target completes. */
 static void ath10k_pci_htt_tx_cb(struct ath10k_ce_pipe *ce_state)
 {
@@ -2027,6 +2034,29 @@ static int ath10k_pci_init_config(struct ath10k *ar)
        return 0;
 }
 
+static void ath10k_pci_override_ce_config(struct ath10k *ar)
+{
+       struct ce_attr *attr;
+       struct ce_pipe_config *config;
+
+       /* For QCA6174 we're overriding the Copy Engine 5 configuration,
+        * since it is currently used for other feature.
+        */
+
+       /* Override Host's Copy Engine 5 configuration */
+       attr = &host_ce_config_wlan[5];
+       attr->src_sz_max = 0;
+       attr->dest_nentries = 0;
+
+       /* Override Target firmware's Copy Engine configuration */
+       config = &target_ce_config_wlan[5];
+       config->pipedir = __cpu_to_le32(PIPEDIR_OUT);
+       config->nbytes_max = __cpu_to_le32(2048);
+
+       /* Map from service/endpoint to Copy Engine */
+       target_service_to_ce_map_wlan[15].pipenum = __cpu_to_le32(1);
+}
+
 static int ath10k_pci_alloc_pipes(struct ath10k *ar)
 {
        struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
@@ -3020,6 +3050,9 @@ static int ath10k_pci_probe(struct pci_dev *pdev,
                goto err_core_destroy;
        }
 
+       if (QCA_REV_6174(ar))
+               ath10k_pci_override_ce_config(ar);
+
        ret = ath10k_pci_alloc_pipes(ar);
        if (ret) {
                ath10k_err(ar, "failed to allocate copy engine pipes: %d\n",
index 1a73c7a1da77d0e0fe16fbdc6fb866d6c65226ee..d9a4aee246a6379c6a6aee7d6185ff680387c55e 100644 (file)
 
 /* Highest firmware API version supported */
 #define IWL7260_UCODE_API_MAX  17
+#define IWL7265_UCODE_API_MAX  19
+#define IWL7265D_UCODE_API_MAX 19
 
 /* Oldest version we won't warn about */
 #define IWL7260_UCODE_API_OK   13
+#define IWL7265_UCODE_API_OK   13
+#define IWL7265D_UCODE_API_OK  13
 
 /* Lowest firmware API version supported */
 #define IWL7260_UCODE_API_MIN  13
+#define IWL7265_UCODE_API_MIN  13
+#define IWL7265D_UCODE_API_MIN 13
 
 /* NVM versions */
 #define IWL7260_NVM_VERSION            0x0a1d
@@ -149,10 +155,7 @@ static const struct iwl_ht_params iwl7000_ht_params = {
        .ht40_bands = BIT(IEEE80211_BAND_2GHZ) | BIT(IEEE80211_BAND_5GHZ),
 };
 
-#define IWL_DEVICE_7000                                                \
-       .ucode_api_max = IWL7260_UCODE_API_MAX,                 \
-       .ucode_api_ok = IWL7260_UCODE_API_OK,                   \
-       .ucode_api_min = IWL7260_UCODE_API_MIN,                 \
+#define IWL_DEVICE_7000_COMMON                                 \
        .device_family = IWL_DEVICE_FAMILY_7000,                \
        .max_inst_size = IWL60_RTC_INST_SIZE,                   \
        .max_data_size = IWL60_RTC_DATA_SIZE,                   \
@@ -163,6 +166,24 @@ static const struct iwl_ht_params iwl7000_ht_params = {
        .max_ht_ampdu_exponent = IEEE80211_HT_MAX_AMPDU_64K,    \
        .dccm_offset = IWL7000_DCCM_OFFSET
 
+#define IWL_DEVICE_7000                                                \
+       IWL_DEVICE_7000_COMMON,                                 \
+       .ucode_api_max = IWL7260_UCODE_API_MAX,                 \
+       .ucode_api_ok = IWL7260_UCODE_API_OK,                   \
+       .ucode_api_min = IWL7260_UCODE_API_MIN
+
+#define IWL_DEVICE_7005                                                \
+       IWL_DEVICE_7000_COMMON,                                 \
+       .ucode_api_max = IWL7265_UCODE_API_MAX,                 \
+       .ucode_api_ok = IWL7265_UCODE_API_OK,                   \
+       .ucode_api_min = IWL7265_UCODE_API_MIN
+
+#define IWL_DEVICE_7005D                                       \
+       IWL_DEVICE_7000_COMMON,                                 \
+       .ucode_api_max = IWL7265D_UCODE_API_MAX,                \
+       .ucode_api_ok = IWL7265D_UCODE_API_OK,                  \
+       .ucode_api_min = IWL7265D_UCODE_API_MIN
+
 const struct iwl_cfg iwl7260_2ac_cfg = {
        .name = "Intel(R) Dual Band Wireless AC 7260",
        .fw_name_pre = IWL7260_FW_PRE,
@@ -266,7 +287,7 @@ static const struct iwl_ht_params iwl7265_ht_params = {
 const struct iwl_cfg iwl3165_2ac_cfg = {
        .name = "Intel(R) Dual Band Wireless AC 3165",
        .fw_name_pre = IWL7265D_FW_PRE,
-       IWL_DEVICE_7000,
+       IWL_DEVICE_7005D,
        .ht_params = &iwl7000_ht_params,
        .nvm_ver = IWL3165_NVM_VERSION,
        .nvm_calib_ver = IWL3165_TX_POWER_VERSION,
@@ -277,7 +298,7 @@ const struct iwl_cfg iwl3165_2ac_cfg = {
 const struct iwl_cfg iwl7265_2ac_cfg = {
        .name = "Intel(R) Dual Band Wireless AC 7265",
        .fw_name_pre = IWL7265_FW_PRE,
-       IWL_DEVICE_7000,
+       IWL_DEVICE_7005,
        .ht_params = &iwl7265_ht_params,
        .nvm_ver = IWL7265_NVM_VERSION,
        .nvm_calib_ver = IWL7265_TX_POWER_VERSION,
@@ -288,7 +309,7 @@ const struct iwl_cfg iwl7265_2ac_cfg = {
 const struct iwl_cfg iwl7265_2n_cfg = {
        .name = "Intel(R) Dual Band Wireless N 7265",
        .fw_name_pre = IWL7265_FW_PRE,
-       IWL_DEVICE_7000,
+       IWL_DEVICE_7005,
        .ht_params = &iwl7265_ht_params,
        .nvm_ver = IWL7265_NVM_VERSION,
        .nvm_calib_ver = IWL7265_TX_POWER_VERSION,
@@ -299,7 +320,7 @@ const struct iwl_cfg iwl7265_2n_cfg = {
 const struct iwl_cfg iwl7265_n_cfg = {
        .name = "Intel(R) Wireless N 7265",
        .fw_name_pre = IWL7265_FW_PRE,
-       IWL_DEVICE_7000,
+       IWL_DEVICE_7005,
        .ht_params = &iwl7265_ht_params,
        .nvm_ver = IWL7265_NVM_VERSION,
        .nvm_calib_ver = IWL7265_TX_POWER_VERSION,
@@ -310,7 +331,7 @@ const struct iwl_cfg iwl7265_n_cfg = {
 const struct iwl_cfg iwl7265d_2ac_cfg = {
        .name = "Intel(R) Dual Band Wireless AC 7265",
        .fw_name_pre = IWL7265D_FW_PRE,
-       IWL_DEVICE_7000,
+       IWL_DEVICE_7005D,
        .ht_params = &iwl7265_ht_params,
        .nvm_ver = IWL7265D_NVM_VERSION,
        .nvm_calib_ver = IWL7265_TX_POWER_VERSION,
@@ -321,7 +342,7 @@ const struct iwl_cfg iwl7265d_2ac_cfg = {
 const struct iwl_cfg iwl7265d_2n_cfg = {
        .name = "Intel(R) Dual Band Wireless N 7265",
        .fw_name_pre = IWL7265D_FW_PRE,
-       IWL_DEVICE_7000,
+       IWL_DEVICE_7005D,
        .ht_params = &iwl7265_ht_params,
        .nvm_ver = IWL7265D_NVM_VERSION,
        .nvm_calib_ver = IWL7265_TX_POWER_VERSION,
@@ -332,7 +353,7 @@ const struct iwl_cfg iwl7265d_2n_cfg = {
 const struct iwl_cfg iwl7265d_n_cfg = {
        .name = "Intel(R) Wireless N 7265",
        .fw_name_pre = IWL7265D_FW_PRE,
-       IWL_DEVICE_7000,
+       IWL_DEVICE_7005D,
        .ht_params = &iwl7265_ht_params,
        .nvm_ver = IWL7265D_NVM_VERSION,
        .nvm_calib_ver = IWL7265_TX_POWER_VERSION,
@@ -342,5 +363,5 @@ const struct iwl_cfg iwl7265d_n_cfg = {
 
 MODULE_FIRMWARE(IWL7260_MODULE_FIRMWARE(IWL7260_UCODE_API_OK));
 MODULE_FIRMWARE(IWL3160_MODULE_FIRMWARE(IWL7260_UCODE_API_OK));
-MODULE_FIRMWARE(IWL7265_MODULE_FIRMWARE(IWL7260_UCODE_API_OK));
-MODULE_FIRMWARE(IWL7265D_MODULE_FIRMWARE(IWL7260_UCODE_API_OK));
+MODULE_FIRMWARE(IWL7265_MODULE_FIRMWARE(IWL7265_UCODE_API_OK));
+MODULE_FIRMWARE(IWL7265D_MODULE_FIRMWARE(IWL7265D_UCODE_API_OK));
index 0116e5a4c39389ac4123100bf1486d96c11ad10a..9bcc0bf937d8810f42da44656cf6bc7d11df4f5a 100644 (file)
@@ -69,7 +69,7 @@
 #include "iwl-agn-hw.h"
 
 /* Highest firmware API version supported */
-#define IWL8000_UCODE_API_MAX  17
+#define IWL8000_UCODE_API_MAX  19
 
 /* Oldest version we won't warn about */
 #define IWL8000_UCODE_API_OK   13
index 85ae902df7c08d9d1d0ad4611e7947ace08bf0f7..29ae58ebf223fa82be3e072ea4ac000e62d54884 100644 (file)
@@ -309,9 +309,9 @@ static void iwl_mvm_wowlan_program_keys(struct ieee80211_hw *hw,
         * to transmit packets to the AP, i.e. the PTK.
         */
        if (key->flags & IEEE80211_KEY_FLAG_PAIRWISE) {
-               key->hw_key_idx = 0;
                mvm->ptk_ivlen = key->iv_len;
                mvm->ptk_icvlen = key->icv_len;
+               ret = iwl_mvm_set_sta_key(mvm, vif, sta, key, 0);
        } else {
                /*
                 * firmware only supports TSC/RSC for a single key,
@@ -319,12 +319,11 @@ static void iwl_mvm_wowlan_program_keys(struct ieee80211_hw *hw,
                 * with new ones -- this relies on mac80211 doing
                 * list_add_tail().
                 */
-               key->hw_key_idx = 1;
                mvm->gtk_ivlen = key->iv_len;
                mvm->gtk_icvlen = key->icv_len;
+               ret = iwl_mvm_set_sta_key(mvm, vif, sta, key, 1);
        }
 
-       ret = iwl_mvm_set_sta_key(mvm, vif, sta, key, true);
        data->error = ret != 0;
 out_unlock:
        mutex_unlock(&mvm->mutex);
@@ -772,9 +771,6 @@ static int iwl_mvm_switch_to_d3(struct iwl_mvm *mvm)
         */
        set_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status);
 
-       /* We reprogram keys and shouldn't allocate new key indices */
-       memset(mvm->fw_key_table, 0, sizeof(mvm->fw_key_table));
-
        mvm->ptk_ivlen = 0;
        mvm->ptk_icvlen = 0;
        mvm->ptk_ivlen = 0;
index 1fb684693040eac8130cf62c348b0bf96dd4f005..e88afac51c5d69fe5d6c8f4e032cdcf95f48a168 100644 (file)
@@ -2941,6 +2941,7 @@ static int iwl_mvm_mac_set_key(struct ieee80211_hw *hw,
 {
        struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
        int ret;
+       u8 key_offset;
 
        if (iwlwifi_mod_params.sw_crypto) {
                IWL_DEBUG_MAC80211(mvm, "leave - hwcrypto disabled\n");
@@ -3006,10 +3007,14 @@ static int iwl_mvm_mac_set_key(struct ieee80211_hw *hw,
                        break;
                }
 
+               /* in HW restart reuse the index, otherwise request a new one */
+               if (test_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status))
+                       key_offset = key->hw_key_idx;
+               else
+                       key_offset = STA_KEY_IDX_INVALID;
+
                IWL_DEBUG_MAC80211(mvm, "set hwcrypto key\n");
-               ret = iwl_mvm_set_sta_key(mvm, vif, sta, key,
-                                         test_bit(IWL_MVM_STATUS_IN_HW_RESTART,
-                                                  &mvm->status));
+               ret = iwl_mvm_set_sta_key(mvm, vif, sta, key, key_offset);
                if (ret) {
                        IWL_WARN(mvm, "set key failed\n");
                        /*
index 300a249486e4df2398738b62c53a7870f87a757b..2b976b110207f87532162e6f8587c1fcd0063c83 100644 (file)
@@ -1201,7 +1201,8 @@ static int iwl_mvm_set_fw_key_idx(struct iwl_mvm *mvm)
        return max_offs;
 }
 
-static u8 iwl_mvm_get_key_sta_id(struct ieee80211_vif *vif,
+static u8 iwl_mvm_get_key_sta_id(struct iwl_mvm *mvm,
+                                struct ieee80211_vif *vif,
                                 struct ieee80211_sta *sta)
 {
        struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
@@ -1218,8 +1219,21 @@ static u8 iwl_mvm_get_key_sta_id(struct ieee80211_vif *vif,
         * station ID, then use AP's station ID.
         */
        if (vif->type == NL80211_IFTYPE_STATION &&
-           mvmvif->ap_sta_id != IWL_MVM_STATION_COUNT)
-               return mvmvif->ap_sta_id;
+           mvmvif->ap_sta_id != IWL_MVM_STATION_COUNT) {
+               u8 sta_id = mvmvif->ap_sta_id;
+
+               sta = rcu_dereference_check(mvm->fw_id_to_mac_id[sta_id],
+                                           lockdep_is_held(&mvm->mutex));
+               /*
+                * It is possible that the 'sta' parameter is NULL,
+                * for example when a GTK is removed - the sta_id will then
+                * be the AP ID, and no station was passed by mac80211.
+                */
+               if (IS_ERR_OR_NULL(sta))
+                       return IWL_MVM_STATION_COUNT;
+
+               return sta_id;
+       }
 
        return IWL_MVM_STATION_COUNT;
 }
@@ -1227,7 +1241,8 @@ static u8 iwl_mvm_get_key_sta_id(struct ieee80211_vif *vif,
 static int iwl_mvm_send_sta_key(struct iwl_mvm *mvm,
                                struct iwl_mvm_sta *mvm_sta,
                                struct ieee80211_key_conf *keyconf, bool mcast,
-                               u32 tkip_iv32, u16 *tkip_p1k, u32 cmd_flags)
+                               u32 tkip_iv32, u16 *tkip_p1k, u32 cmd_flags,
+                               u8 key_offset)
 {
        struct iwl_mvm_add_sta_key_cmd cmd = {};
        __le16 key_flags;
@@ -1269,7 +1284,7 @@ static int iwl_mvm_send_sta_key(struct iwl_mvm *mvm,
        if (mcast)
                key_flags |= cpu_to_le16(STA_KEY_MULTICAST);
 
-       cmd.key_offset = keyconf->hw_key_idx;
+       cmd.key_offset = key_offset;
        cmd.key_flags = key_flags;
        cmd.sta_id = sta_id;
 
@@ -1360,6 +1375,7 @@ static int __iwl_mvm_set_sta_key(struct iwl_mvm *mvm,
                                 struct ieee80211_vif *vif,
                                 struct ieee80211_sta *sta,
                                 struct ieee80211_key_conf *keyconf,
+                                u8 key_offset,
                                 bool mcast)
 {
        struct iwl_mvm_sta *mvm_sta = iwl_mvm_sta_from_mac80211(sta);
@@ -1375,17 +1391,17 @@ static int __iwl_mvm_set_sta_key(struct iwl_mvm *mvm,
                ieee80211_get_key_rx_seq(keyconf, 0, &seq);
                ieee80211_get_tkip_rx_p1k(keyconf, addr, seq.tkip.iv32, p1k);
                ret = iwl_mvm_send_sta_key(mvm, mvm_sta, keyconf, mcast,
-                                          seq.tkip.iv32, p1k, 0);
+                                          seq.tkip.iv32, p1k, 0, key_offset);
                break;
        case WLAN_CIPHER_SUITE_CCMP:
        case WLAN_CIPHER_SUITE_WEP40:
        case WLAN_CIPHER_SUITE_WEP104:
                ret = iwl_mvm_send_sta_key(mvm, mvm_sta, keyconf, mcast,
-                                          0, NULL, 0);
+                                          0, NULL, 0, key_offset);
                break;
        default:
                ret = iwl_mvm_send_sta_key(mvm, mvm_sta, keyconf, mcast,
-                                          0, NULL, 0);
+                                          0, NULL, 0, key_offset);
        }
 
        return ret;
@@ -1433,7 +1449,7 @@ int iwl_mvm_set_sta_key(struct iwl_mvm *mvm,
                        struct ieee80211_vif *vif,
                        struct ieee80211_sta *sta,
                        struct ieee80211_key_conf *keyconf,
-                       bool have_key_offset)
+                       u8 key_offset)
 {
        bool mcast = !(keyconf->flags & IEEE80211_KEY_FLAG_PAIRWISE);
        u8 sta_id;
@@ -1443,7 +1459,7 @@ int iwl_mvm_set_sta_key(struct iwl_mvm *mvm,
        lockdep_assert_held(&mvm->mutex);
 
        /* Get the station id from the mvm local station table */
-       sta_id = iwl_mvm_get_key_sta_id(vif, sta);
+       sta_id = iwl_mvm_get_key_sta_id(mvm, vif, sta);
        if (sta_id == IWL_MVM_STATION_COUNT) {
                IWL_ERR(mvm, "Failed to find station id\n");
                return -EINVAL;
@@ -1470,18 +1486,25 @@ int iwl_mvm_set_sta_key(struct iwl_mvm *mvm,
        if (WARN_ON_ONCE(iwl_mvm_sta_from_mac80211(sta)->vif != vif))
                return -EINVAL;
 
-       if (!have_key_offset) {
-               /*
-                * The D3 firmware hardcodes the PTK offset to 0, so we have to
-                * configure it there. As a result, this workaround exists to
-                * let the caller set the key offset (hw_key_idx), see d3.c.
-                */
-               keyconf->hw_key_idx = iwl_mvm_set_fw_key_idx(mvm);
-               if (keyconf->hw_key_idx == STA_KEY_IDX_INVALID)
+       /* If the key_offset is not pre-assigned, we need to find a
+        * new offset to use.  In normal cases, the offset is not
+        * pre-assigned, but during HW_RESTART we want to reuse the
+        * same indices, so we pass them when this function is called.
+        *
+        * In D3 entry, we need to hardcoded the indices (because the
+        * firmware hardcodes the PTK offset to 0).  In this case, we
+        * need to make sure we don't overwrite the hw_key_idx in the
+        * keyconf structure, because otherwise we cannot configure
+        * the original ones back when resuming.
+        */
+       if (key_offset == STA_KEY_IDX_INVALID) {
+               key_offset  = iwl_mvm_set_fw_key_idx(mvm);
+               if (key_offset == STA_KEY_IDX_INVALID)
                        return -ENOSPC;
+               keyconf->hw_key_idx = key_offset;
        }
 
-       ret = __iwl_mvm_set_sta_key(mvm, vif, sta, keyconf, mcast);
+       ret = __iwl_mvm_set_sta_key(mvm, vif, sta, keyconf, key_offset, mcast);
        if (ret) {
                __clear_bit(keyconf->hw_key_idx, mvm->fw_key_table);
                goto end;
@@ -1495,7 +1518,8 @@ int iwl_mvm_set_sta_key(struct iwl_mvm *mvm,
         */
        if (keyconf->cipher == WLAN_CIPHER_SUITE_WEP40 ||
            keyconf->cipher == WLAN_CIPHER_SUITE_WEP104) {
-               ret = __iwl_mvm_set_sta_key(mvm, vif, sta, keyconf, !mcast);
+               ret = __iwl_mvm_set_sta_key(mvm, vif, sta, keyconf,
+                                           key_offset, !mcast);
                if (ret) {
                        __clear_bit(keyconf->hw_key_idx, mvm->fw_key_table);
                        __iwl_mvm_remove_sta_key(mvm, sta_id, keyconf, mcast);
@@ -1521,7 +1545,7 @@ int iwl_mvm_remove_sta_key(struct iwl_mvm *mvm,
        lockdep_assert_held(&mvm->mutex);
 
        /* Get the station id from the mvm local station table */
-       sta_id = iwl_mvm_get_key_sta_id(vif, sta);
+       sta_id = iwl_mvm_get_key_sta_id(mvm, vif, sta);
 
        IWL_DEBUG_WEP(mvm, "mvm remove dynamic key: idx=%d sta=%d\n",
                      keyconf->keyidx, sta_id);
@@ -1547,24 +1571,6 @@ int iwl_mvm_remove_sta_key(struct iwl_mvm *mvm,
                return 0;
        }
 
-       /*
-        * It is possible that the 'sta' parameter is NULL, and thus
-        * there is a need to retrieve the sta from the local station table,
-        * for example when a GTK is removed (where the sta_id will then be
-        * the AP ID, and no station was passed by mac80211.)
-        */
-       if (!sta) {
-               sta = rcu_dereference_protected(mvm->fw_id_to_mac_id[sta_id],
-                                               lockdep_is_held(&mvm->mutex));
-               if (!sta) {
-                       IWL_ERR(mvm, "Invalid station id\n");
-                       return -EINVAL;
-               }
-       }
-
-       if (WARN_ON_ONCE(iwl_mvm_sta_from_mac80211(sta)->vif != vif))
-               return -EINVAL;
-
        ret = __iwl_mvm_remove_sta_key(mvm, sta_id, keyconf, mcast);
        if (ret)
                return ret;
@@ -1584,14 +1590,15 @@ void iwl_mvm_update_tkip_key(struct iwl_mvm *mvm,
                             u16 *phase1key)
 {
        struct iwl_mvm_sta *mvm_sta;
-       u8 sta_id = iwl_mvm_get_key_sta_id(vif, sta);
+       u8 sta_id;
        bool mcast = !(keyconf->flags & IEEE80211_KEY_FLAG_PAIRWISE);
 
-       if (WARN_ON_ONCE(sta_id == IWL_MVM_STATION_COUNT))
-               return;
-
        rcu_read_lock();
 
+       sta_id = iwl_mvm_get_key_sta_id(mvm, vif, sta);
+       if (WARN_ON_ONCE(sta_id == IWL_MVM_STATION_COUNT))
+               goto unlock;
+
        if (!sta) {
                sta = rcu_dereference(mvm->fw_id_to_mac_id[sta_id]);
                if (WARN_ON(IS_ERR_OR_NULL(sta))) {
@@ -1602,7 +1609,9 @@ void iwl_mvm_update_tkip_key(struct iwl_mvm *mvm,
 
        mvm_sta = iwl_mvm_sta_from_mac80211(sta);
        iwl_mvm_send_sta_key(mvm, mvm_sta, keyconf, mcast,
-                            iv32, phase1key, CMD_ASYNC);
+                            iv32, phase1key, CMD_ASYNC, keyconf->hw_key_idx);
+
+ unlock:
        rcu_read_unlock();
 }
 
index eedb215eba3f6efd08f2ca387de80e46ec39bfb2..0631cc0a6d3c908d71c93270a15679270272c6c7 100644 (file)
@@ -365,8 +365,8 @@ int iwl_mvm_rm_sta_id(struct iwl_mvm *mvm,
 int iwl_mvm_set_sta_key(struct iwl_mvm *mvm,
                        struct ieee80211_vif *vif,
                        struct ieee80211_sta *sta,
-                       struct ieee80211_key_conf *key,
-                       bool have_key_offset);
+                       struct ieee80211_key_conf *keyconf,
+                       u8 key_offset);
 int iwl_mvm_remove_sta_key(struct iwl_mvm *mvm,
                           struct ieee80211_vif *vif,
                           struct ieee80211_sta *sta,
index 644b58bc5226c52b3cdee0a24b9a392c25e8ac02..639761fb2bfb2f8a1dbd5925984e6ad0c15f9587 100644 (file)
@@ -423,14 +423,21 @@ static const struct pci_device_id iwl_hw_card_ids[] = {
 /* 8000 Series */
        {IWL_PCI_DEVICE(0x24F3, 0x0010, iwl8260_2ac_cfg)},
        {IWL_PCI_DEVICE(0x24F3, 0x1010, iwl8260_2ac_cfg)},
+       {IWL_PCI_DEVICE(0x24F3, 0x0130, iwl8260_2ac_cfg)},
+       {IWL_PCI_DEVICE(0x24F3, 0x1130, iwl8260_2ac_cfg)},
+       {IWL_PCI_DEVICE(0x24F3, 0x0132, iwl8260_2ac_cfg)},
+       {IWL_PCI_DEVICE(0x24F3, 0x1132, iwl8260_2ac_cfg)},
        {IWL_PCI_DEVICE(0x24F3, 0x0110, iwl8260_2ac_cfg)},
+       {IWL_PCI_DEVICE(0x24F3, 0x01F0, iwl8260_2ac_cfg)},
+       {IWL_PCI_DEVICE(0x24F3, 0x0012, iwl8260_2ac_cfg)},
+       {IWL_PCI_DEVICE(0x24F3, 0x1012, iwl8260_2ac_cfg)},
        {IWL_PCI_DEVICE(0x24F3, 0x1110, iwl8260_2ac_cfg)},
        {IWL_PCI_DEVICE(0x24F3, 0x0050, iwl8260_2ac_cfg)},
        {IWL_PCI_DEVICE(0x24F3, 0x0250, iwl8260_2ac_cfg)},
        {IWL_PCI_DEVICE(0x24F3, 0x1050, iwl8260_2ac_cfg)},
        {IWL_PCI_DEVICE(0x24F3, 0x0150, iwl8260_2ac_cfg)},
+       {IWL_PCI_DEVICE(0x24F3, 0x1150, iwl8260_2ac_cfg)},
        {IWL_PCI_DEVICE(0x24F4, 0x0030, iwl8260_2ac_cfg)},
-       {IWL_PCI_DEVICE(0x24F4, 0x1130, iwl8260_2ac_cfg)},
        {IWL_PCI_DEVICE(0x24F4, 0x1030, iwl8260_2ac_cfg)},
        {IWL_PCI_DEVICE(0x24F3, 0xC010, iwl8260_2ac_cfg)},
        {IWL_PCI_DEVICE(0x24F3, 0xC110, iwl8260_2ac_cfg)},
@@ -438,18 +445,28 @@ static const struct pci_device_id iwl_hw_card_ids[] = {
        {IWL_PCI_DEVICE(0x24F3, 0xC050, iwl8260_2ac_cfg)},
        {IWL_PCI_DEVICE(0x24F3, 0xD050, iwl8260_2ac_cfg)},
        {IWL_PCI_DEVICE(0x24F3, 0x8010, iwl8260_2ac_cfg)},
+       {IWL_PCI_DEVICE(0x24F3, 0x8110, iwl8260_2ac_cfg)},
        {IWL_PCI_DEVICE(0x24F3, 0x9010, iwl8260_2ac_cfg)},
+       {IWL_PCI_DEVICE(0x24F3, 0x9110, iwl8260_2ac_cfg)},
        {IWL_PCI_DEVICE(0x24F4, 0x8030, iwl8260_2ac_cfg)},
        {IWL_PCI_DEVICE(0x24F4, 0x9030, iwl8260_2ac_cfg)},
+       {IWL_PCI_DEVICE(0x24F3, 0x8130, iwl8260_2ac_cfg)},
+       {IWL_PCI_DEVICE(0x24F3, 0x9130, iwl8260_2ac_cfg)},
+       {IWL_PCI_DEVICE(0x24F3, 0x8132, iwl8260_2ac_cfg)},
+       {IWL_PCI_DEVICE(0x24F3, 0x9132, iwl8260_2ac_cfg)},
        {IWL_PCI_DEVICE(0x24F3, 0x8050, iwl8260_2ac_cfg)},
+       {IWL_PCI_DEVICE(0x24F3, 0x8150, iwl8260_2ac_cfg)},
        {IWL_PCI_DEVICE(0x24F3, 0x9050, iwl8260_2ac_cfg)},
+       {IWL_PCI_DEVICE(0x24F3, 0x9150, iwl8260_2ac_cfg)},
        {IWL_PCI_DEVICE(0x24F3, 0x0004, iwl8260_2n_cfg)},
+       {IWL_PCI_DEVICE(0x24F3, 0x0044, iwl8260_2n_cfg)},
        {IWL_PCI_DEVICE(0x24F5, 0x0010, iwl4165_2ac_cfg)},
        {IWL_PCI_DEVICE(0x24F6, 0x0030, iwl4165_2ac_cfg)},
        {IWL_PCI_DEVICE(0x24F3, 0x0810, iwl8260_2ac_cfg)},
        {IWL_PCI_DEVICE(0x24F3, 0x0910, iwl8260_2ac_cfg)},
        {IWL_PCI_DEVICE(0x24F3, 0x0850, iwl8260_2ac_cfg)},
        {IWL_PCI_DEVICE(0x24F3, 0x0950, iwl8260_2ac_cfg)},
+       {IWL_PCI_DEVICE(0x24F3, 0x0930, iwl8260_2ac_cfg)},
 #endif /* CONFIG_IWLMVM */
 
        {0}
index 6e9418ed90c289bee5b7f2dfc478f847dfc7ca68..bbb789f8990b10944d0a8eed60c7700af2a4121e 100644 (file)
@@ -2272,7 +2272,7 @@ void rtl8821ae_enable_interrupt(struct ieee80211_hw *hw)
        struct rtl_priv *rtlpriv = rtl_priv(hw);
        struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
 
-       if (!rtlpci->int_clear)
+       if (rtlpci->int_clear)
                rtl8821ae_clear_interrupt(hw);/*clear it here first*/
 
        rtl_write_dword(rtlpriv, REG_HIMR, rtlpci->irq_mask[0] & 0xFFFFFFFF);
index 8ee141a55bc5cc6b566e79dde58cdb05583e7fdf..142bdff4ed605b6e148cdbac588f80020b2c76c9 100644 (file)
@@ -448,7 +448,7 @@ MODULE_PARM_DESC(fwlps, "Set to 1 to use FW control power save (default 1)\n");
 MODULE_PARM_DESC(msi, "Set to 1 to use MSI interrupts mode (default 1)\n");
 MODULE_PARM_DESC(debug, "Set debug level (0-5) (default 0)");
 MODULE_PARM_DESC(disable_watchdog, "Set to 1 to disable the watchdog (default 0)\n");
-MODULE_PARM_DESC(int_clear, "Set to 1 to disable interrupt clear before set (default 0)\n");
+MODULE_PARM_DESC(int_clear, "Set to 0 to disable interrupt clear before set (default 1)\n");
 
 static SIMPLE_DEV_PM_OPS(rtlwifi_pm_ops, rtl_pci_suspend, rtl_pci_resume);
 
index e481f3710bd38a330d00501c8bd4afadff9de8ff..1049c34e7d430fab13e8d36e54af1b049eb02a03 100644 (file)
@@ -258,18 +258,18 @@ static struct xenvif_rx_meta *get_next_rx_buffer(struct xenvif_queue *queue,
                                                 struct netrx_pending_operations *npo)
 {
        struct xenvif_rx_meta *meta;
-       struct xen_netif_rx_request *req;
+       struct xen_netif_rx_request req;
 
-       req = RING_GET_REQUEST(&queue->rx, queue->rx.req_cons++);
+       RING_COPY_REQUEST(&queue->rx, queue->rx.req_cons++, &req);
 
        meta = npo->meta + npo->meta_prod++;
        meta->gso_type = XEN_NETIF_GSO_TYPE_NONE;
        meta->gso_size = 0;
        meta->size = 0;
-       meta->id = req->id;
+       meta->id = req.id;
 
        npo->copy_off = 0;
-       npo->copy_gref = req->gref;
+       npo->copy_gref = req.gref;
 
        return meta;
 }
@@ -424,7 +424,7 @@ static int xenvif_gop_skb(struct sk_buff *skb,
        struct xenvif *vif = netdev_priv(skb->dev);
        int nr_frags = skb_shinfo(skb)->nr_frags;
        int i;
-       struct xen_netif_rx_request *req;
+       struct xen_netif_rx_request req;
        struct xenvif_rx_meta *meta;
        unsigned char *data;
        int head = 1;
@@ -443,15 +443,15 @@ static int xenvif_gop_skb(struct sk_buff *skb,
 
        /* Set up a GSO prefix descriptor, if necessary */
        if ((1 << gso_type) & vif->gso_prefix_mask) {
-               req = RING_GET_REQUEST(&queue->rx, queue->rx.req_cons++);
+               RING_COPY_REQUEST(&queue->rx, queue->rx.req_cons++, &req);
                meta = npo->meta + npo->meta_prod++;
                meta->gso_type = gso_type;
                meta->gso_size = skb_shinfo(skb)->gso_size;
                meta->size = 0;
-               meta->id = req->id;
+               meta->id = req.id;
        }
 
-       req = RING_GET_REQUEST(&queue->rx, queue->rx.req_cons++);
+       RING_COPY_REQUEST(&queue->rx, queue->rx.req_cons++, &req);
        meta = npo->meta + npo->meta_prod++;
 
        if ((1 << gso_type) & vif->gso_mask) {
@@ -463,9 +463,9 @@ static int xenvif_gop_skb(struct sk_buff *skb,
        }
 
        meta->size = 0;
-       meta->id = req->id;
+       meta->id = req.id;
        npo->copy_off = 0;
-       npo->copy_gref = req->gref;
+       npo->copy_gref = req.gref;
 
        data = skb->data;
        while (data < skb_tail_pointer(skb)) {
@@ -679,9 +679,7 @@ static void tx_add_credit(struct xenvif_queue *queue)
         * Allow a burst big enough to transmit a jumbo packet of up to 128kB.
         * Otherwise the interface can seize up due to insufficient credit.
         */
-       max_burst = RING_GET_REQUEST(&queue->tx, queue->tx.req_cons)->size;
-       max_burst = min(max_burst, 131072UL);
-       max_burst = max(max_burst, queue->credit_bytes);
+       max_burst = max(131072UL, queue->credit_bytes);
 
        /* Take care that adding a new chunk of credit doesn't wrap to zero. */
        max_credit = queue->remaining_credit + queue->credit_bytes;
@@ -711,7 +709,7 @@ static void xenvif_tx_err(struct xenvif_queue *queue,
                spin_unlock_irqrestore(&queue->response_lock, flags);
                if (cons == end)
                        break;
-               txp = RING_GET_REQUEST(&queue->tx, cons++);
+               RING_COPY_REQUEST(&queue->tx, cons++, txp);
        } while (1);
        queue->tx.req_cons = cons;
 }
@@ -778,8 +776,7 @@ static int xenvif_count_requests(struct xenvif_queue *queue,
                if (drop_err)
                        txp = &dropped_tx;
 
-               memcpy(txp, RING_GET_REQUEST(&queue->tx, cons + slots),
-                      sizeof(*txp));
+               RING_COPY_REQUEST(&queue->tx, cons + slots, txp);
 
                /* If the guest submitted a frame >= 64 KiB then
                 * first->size overflowed and following slots will
@@ -1112,8 +1109,7 @@ static int xenvif_get_extras(struct xenvif_queue *queue,
                        return -EBADR;
                }
 
-               memcpy(&extra, RING_GET_REQUEST(&queue->tx, cons),
-                      sizeof(extra));
+               RING_COPY_REQUEST(&queue->tx, cons, &extra);
                if (unlikely(!extra.type ||
                             extra.type >= XEN_NETIF_EXTRA_TYPE_MAX)) {
                        queue->tx.req_cons = ++cons;
@@ -1322,7 +1318,7 @@ static void xenvif_tx_build_gops(struct xenvif_queue *queue,
 
                idx = queue->tx.req_cons;
                rmb(); /* Ensure that we see the request before we copy it. */
-               memcpy(&txreq, RING_GET_REQUEST(&queue->tx, idx), sizeof(txreq));
+               RING_COPY_REQUEST(&queue->tx, idx, &txreq);
 
                /* Credit-based scheduling. */
                if (txreq.size > queue->remaining_credit &&
index 219dc206fa5f24dc6fdffb3a2a6ec17df20d5281..a5fe239525868b1b86ec2d5337cfdb5e324424d6 100644 (file)
@@ -1,4 +1,5 @@
 
 obj-$(CONFIG_BLK_DEV_NVME)     += nvme.o
 
-nvme-y         += pci.o scsi.o lightnvm.o
+lightnvm-$(CONFIG_NVM) := lightnvm.o
+nvme-y         += pci.o scsi.o $(lightnvm-y)
index e0b7b95813bc98e1fc7f25fd422fad87690ec2e4..15f2acb4d5cd4937ee350e7daaf67f1b8ec56ad6 100644 (file)
@@ -22,8 +22,6 @@
 
 #include "nvme.h"
 
-#ifdef CONFIG_NVM
-
 #include <linux/nvme.h>
 #include <linux/bitops.h>
 #include <linux/lightnvm.h>
@@ -93,7 +91,7 @@ struct nvme_nvm_l2ptbl {
        __le16                  cdw14[6];
 };
 
-struct nvme_nvm_bbtbl {
+struct nvme_nvm_getbbtbl {
        __u8                    opcode;
        __u8                    flags;
        __u16                   command_id;
@@ -101,10 +99,23 @@ struct nvme_nvm_bbtbl {
        __u64                   rsvd[2];
        __le64                  prp1;
        __le64                  prp2;
-       __le32                  prp1_len;
-       __le32                  prp2_len;
-       __le32                  lbb;
-       __u32                   rsvd11[3];
+       __le64                  spba;
+       __u32                   rsvd4[4];
+};
+
+struct nvme_nvm_setbbtbl {
+       __u8                    opcode;
+       __u8                    flags;
+       __u16                   command_id;
+       __le32                  nsid;
+       __le64                  rsvd[2];
+       __le64                  prp1;
+       __le64                  prp2;
+       __le64                  spba;
+       __le16                  nlb;
+       __u8                    value;
+       __u8                    rsvd3;
+       __u32                   rsvd4[3];
 };
 
 struct nvme_nvm_erase_blk {
@@ -129,8 +140,8 @@ struct nvme_nvm_command {
                struct nvme_nvm_hb_rw hb_rw;
                struct nvme_nvm_ph_rw ph_rw;
                struct nvme_nvm_l2ptbl l2p;
-               struct nvme_nvm_bbtbl get_bb;
-               struct nvme_nvm_bbtbl set_bb;
+               struct nvme_nvm_getbbtbl get_bb;
+               struct nvme_nvm_setbbtbl set_bb;
                struct nvme_nvm_erase_blk erase;
        };
 };
@@ -142,11 +153,13 @@ struct nvme_nvm_id_group {
        __u8                    num_ch;
        __u8                    num_lun;
        __u8                    num_pln;
+       __u8                    rsvd1;
        __le16                  num_blk;
        __le16                  num_pg;
        __le16                  fpg_sz;
        __le16                  csecs;
        __le16                  sos;
+       __le16                  rsvd2;
        __le32                  trdt;
        __le32                  trdm;
        __le32                  tprt;
@@ -154,8 +167,9 @@ struct nvme_nvm_id_group {
        __le32                  tbet;
        __le32                  tbem;
        __le32                  mpos;
+       __le32                  mccap;
        __le16                  cpar;
-       __u8                    reserved[913];
+       __u8                    reserved[906];
 } __packed;
 
 struct nvme_nvm_addr_format {
@@ -178,15 +192,28 @@ struct nvme_nvm_id {
        __u8                    ver_id;
        __u8                    vmnt;
        __u8                    cgrps;
-       __u8                    res[5];
+       __u8                    res;
        __le32                  cap;
        __le32                  dom;
        struct nvme_nvm_addr_format ppaf;
-       __u8                    ppat;
-       __u8                    resv[223];
+       __u8                    resv[228];
        struct nvme_nvm_id_group groups[4];
 } __packed;
 
+struct nvme_nvm_bb_tbl {
+       __u8    tblid[4];
+       __le16  verid;
+       __le16  revid;
+       __le32  rvsd1;
+       __le32  tblks;
+       __le32  tfact;
+       __le32  tgrown;
+       __le32  tdresv;
+       __le32  thresv;
+       __le32  rsvd2[8];
+       __u8    blk[0];
+};
+
 /*
  * Check we didn't inadvertently grow the command struct
  */
@@ -195,12 +222,14 @@ static inline void _nvme_nvm_check_size(void)
        BUILD_BUG_ON(sizeof(struct nvme_nvm_identity) != 64);
        BUILD_BUG_ON(sizeof(struct nvme_nvm_hb_rw) != 64);
        BUILD_BUG_ON(sizeof(struct nvme_nvm_ph_rw) != 64);
-       BUILD_BUG_ON(sizeof(struct nvme_nvm_bbtbl) != 64);
+       BUILD_BUG_ON(sizeof(struct nvme_nvm_getbbtbl) != 64);
+       BUILD_BUG_ON(sizeof(struct nvme_nvm_setbbtbl) != 64);
        BUILD_BUG_ON(sizeof(struct nvme_nvm_l2ptbl) != 64);
        BUILD_BUG_ON(sizeof(struct nvme_nvm_erase_blk) != 64);
        BUILD_BUG_ON(sizeof(struct nvme_nvm_id_group) != 960);
        BUILD_BUG_ON(sizeof(struct nvme_nvm_addr_format) != 128);
        BUILD_BUG_ON(sizeof(struct nvme_nvm_id) != 4096);
+       BUILD_BUG_ON(sizeof(struct nvme_nvm_bb_tbl) != 512);
 }
 
 static int init_grps(struct nvm_id *nvm_id, struct nvme_nvm_id *nvme_nvm_id)
@@ -234,6 +263,7 @@ static int init_grps(struct nvm_id *nvm_id, struct nvme_nvm_id *nvme_nvm_id)
                dst->tbet = le32_to_cpu(src->tbet);
                dst->tbem = le32_to_cpu(src->tbem);
                dst->mpos = le32_to_cpu(src->mpos);
+               dst->mccap = le32_to_cpu(src->mccap);
 
                dst->cpar = le16_to_cpu(src->cpar);
        }
@@ -241,9 +271,10 @@ static int init_grps(struct nvm_id *nvm_id, struct nvme_nvm_id *nvme_nvm_id)
        return 0;
 }
 
-static int nvme_nvm_identity(struct request_queue *q, struct nvm_id *nvm_id)
+static int nvme_nvm_identity(struct nvm_dev *nvmdev, struct nvm_id *nvm_id)
 {
-       struct nvme_ns *ns = q->queuedata;
+       struct nvme_ns *ns = nvmdev->q->queuedata;
+       struct nvme_dev *dev = ns->dev;
        struct nvme_nvm_id *nvme_nvm_id;
        struct nvme_nvm_command c = {};
        int ret;
@@ -256,8 +287,8 @@ static int nvme_nvm_identity(struct request_queue *q, struct nvm_id *nvm_id)
        if (!nvme_nvm_id)
                return -ENOMEM;
 
-       ret = nvme_submit_sync_cmd(q, (struct nvme_command *)&c, nvme_nvm_id,
-                                               sizeof(struct nvme_nvm_id));
+       ret = nvme_submit_sync_cmd(dev->admin_q, (struct nvme_command *)&c,
+                               nvme_nvm_id, sizeof(struct nvme_nvm_id));
        if (ret) {
                ret = -EIO;
                goto out;
@@ -268,6 +299,8 @@ static int nvme_nvm_identity(struct request_queue *q, struct nvm_id *nvm_id)
        nvm_id->cgrps = nvme_nvm_id->cgrps;
        nvm_id->cap = le32_to_cpu(nvme_nvm_id->cap);
        nvm_id->dom = le32_to_cpu(nvme_nvm_id->dom);
+       memcpy(&nvm_id->ppaf, &nvme_nvm_id->ppaf,
+                                       sizeof(struct nvme_nvm_addr_format));
 
        ret = init_grps(nvm_id, nvme_nvm_id);
 out:
@@ -275,13 +308,13 @@ out:
        return ret;
 }
 
-static int nvme_nvm_get_l2p_tbl(struct request_queue *q, u64 slba, u32 nlb,
+static int nvme_nvm_get_l2p_tbl(struct nvm_dev *nvmdev, u64 slba, u32 nlb,
                                nvm_l2p_update_fn *update_l2p, void *priv)
 {
-       struct nvme_ns *ns = q->queuedata;
+       struct nvme_ns *ns = nvmdev->q->queuedata;
        struct nvme_dev *dev = ns->dev;
        struct nvme_nvm_command c = {};
-       u32 len = queue_max_hw_sectors(q) << 9;
+       u32 len = queue_max_hw_sectors(dev->admin_q) << 9;
        u32 nlb_pr_rq = len / sizeof(u64);
        u64 cmd_slba = slba;
        void *entries;
@@ -299,8 +332,8 @@ static int nvme_nvm_get_l2p_tbl(struct request_queue *q, u64 slba, u32 nlb,
                c.l2p.slba = cpu_to_le64(cmd_slba);
                c.l2p.nlb = cpu_to_le32(cmd_nlb);
 
-               ret = nvme_submit_sync_cmd(q, (struct nvme_command *)&c,
-                                                               entries, len);
+               ret = nvme_submit_sync_cmd(dev->admin_q,
+                               (struct nvme_command *)&c, entries, len);
                if (ret) {
                        dev_err(dev->dev, "L2P table transfer failed (%d)\n",
                                                                        ret);
@@ -322,43 +355,84 @@ out:
        return ret;
 }
 
-static int nvme_nvm_get_bb_tbl(struct request_queue *q, int lunid,
-                               unsigned int nr_blocks,
-                               nvm_bb_update_fn *update_bbtbl, void *priv)
+static int nvme_nvm_get_bb_tbl(struct nvm_dev *nvmdev, struct ppa_addr ppa,
+                               int nr_blocks, nvm_bb_update_fn *update_bbtbl,
+                               void *priv)
 {
+       struct request_queue *q = nvmdev->q;
        struct nvme_ns *ns = q->queuedata;
        struct nvme_dev *dev = ns->dev;
        struct nvme_nvm_command c = {};
-       void *bb_bitmap;
-       u16 bb_bitmap_size;
+       struct nvme_nvm_bb_tbl *bb_tbl;
+       int tblsz = sizeof(struct nvme_nvm_bb_tbl) + nr_blocks;
        int ret = 0;
 
        c.get_bb.opcode = nvme_nvm_admin_get_bb_tbl;
        c.get_bb.nsid = cpu_to_le32(ns->ns_id);
-       c.get_bb.lbb = cpu_to_le32(lunid);
-       bb_bitmap_size = ((nr_blocks >> 15) + 1) * PAGE_SIZE;
-       bb_bitmap = kmalloc(bb_bitmap_size, GFP_KERNEL);
-       if (!bb_bitmap)
-               return -ENOMEM;
+       c.get_bb.spba = cpu_to_le64(ppa.ppa);
 
-       bitmap_zero(bb_bitmap, nr_blocks);
+       bb_tbl = kzalloc(tblsz, GFP_KERNEL);
+       if (!bb_tbl)
+               return -ENOMEM;
 
-       ret = nvme_submit_sync_cmd(q, (struct nvme_command *)&c, bb_bitmap,
-                                                               bb_bitmap_size);
+       ret = nvme_submit_sync_cmd(dev->admin_q, (struct nvme_command *)&c,
+                                                               bb_tbl, tblsz);
        if (ret) {
                dev_err(dev->dev, "get bad block table failed (%d)\n", ret);
                ret = -EIO;
                goto out;
        }
 
-       ret = update_bbtbl(lunid, bb_bitmap, nr_blocks, priv);
+       if (bb_tbl->tblid[0] != 'B' || bb_tbl->tblid[1] != 'B' ||
+               bb_tbl->tblid[2] != 'L' || bb_tbl->tblid[3] != 'T') {
+               dev_err(dev->dev, "bbt format mismatch\n");
+               ret = -EINVAL;
+               goto out;
+       }
+
+       if (le16_to_cpu(bb_tbl->verid) != 1) {
+               ret = -EINVAL;
+               dev_err(dev->dev, "bbt version not supported\n");
+               goto out;
+       }
+
+       if (le32_to_cpu(bb_tbl->tblks) != nr_blocks) {
+               ret = -EINVAL;
+               dev_err(dev->dev, "bbt unsuspected blocks returned (%u!=%u)",
+                                       le32_to_cpu(bb_tbl->tblks), nr_blocks);
+               goto out;
+       }
+
+       ppa = dev_to_generic_addr(nvmdev, ppa);
+       ret = update_bbtbl(ppa, nr_blocks, bb_tbl->blk, priv);
        if (ret) {
                ret = -EINTR;
                goto out;
        }
 
 out:
-       kfree(bb_bitmap);
+       kfree(bb_tbl);
+       return ret;
+}
+
+static int nvme_nvm_set_bb_tbl(struct nvm_dev *nvmdev, struct nvm_rq *rqd,
+                                                               int type)
+{
+       struct nvme_ns *ns = nvmdev->q->queuedata;
+       struct nvme_dev *dev = ns->dev;
+       struct nvme_nvm_command c = {};
+       int ret = 0;
+
+       c.set_bb.opcode = nvme_nvm_admin_set_bb_tbl;
+       c.set_bb.nsid = cpu_to_le32(ns->ns_id);
+       c.set_bb.spba = cpu_to_le64(rqd->ppa_addr.ppa);
+       c.set_bb.nlb = cpu_to_le16(rqd->nr_pages - 1);
+       c.set_bb.value = type;
+
+       ret = nvme_submit_sync_cmd(dev->admin_q, (struct nvme_command *)&c,
+                                                               NULL, 0);
+       if (ret)
+               dev_err(dev->dev, "set bad block table failed (%d)\n", ret);
        return ret;
 }
 
@@ -381,7 +455,7 @@ static void nvme_nvm_end_io(struct request *rq, int error)
        struct nvm_rq *rqd = rq->end_io_data;
        struct nvm_dev *dev = rqd->dev;
 
-       if (dev->mt->end_io(rqd, error))
+       if (dev->mt && dev->mt->end_io(rqd, error))
                pr_err("nvme: err status: %x result: %lx\n",
                                rq->errors, (unsigned long)rq->special);
 
@@ -389,8 +463,9 @@ static void nvme_nvm_end_io(struct request *rq, int error)
        blk_mq_free_request(rq);
 }
 
-static int nvme_nvm_submit_io(struct request_queue *q, struct nvm_rq *rqd)
+static int nvme_nvm_submit_io(struct nvm_dev *dev, struct nvm_rq *rqd)
 {
+       struct request_queue *q = dev->q;
        struct nvme_ns *ns = q->queuedata;
        struct request *rq;
        struct bio *bio = rqd->bio;
@@ -428,8 +503,9 @@ static int nvme_nvm_submit_io(struct request_queue *q, struct nvm_rq *rqd)
        return 0;
 }
 
-static int nvme_nvm_erase_block(struct request_queue *q, struct nvm_rq *rqd)
+static int nvme_nvm_erase_block(struct nvm_dev *dev, struct nvm_rq *rqd)
 {
+       struct request_queue *q = dev->q;
        struct nvme_ns *ns = q->queuedata;
        struct nvme_nvm_command c = {};
 
@@ -441,9 +517,9 @@ static int nvme_nvm_erase_block(struct request_queue *q, struct nvm_rq *rqd)
        return nvme_submit_sync_cmd(q, (struct nvme_command *)&c, NULL, 0);
 }
 
-static void *nvme_nvm_create_dma_pool(struct request_queue *q, char *name)
+static void *nvme_nvm_create_dma_pool(struct nvm_dev *nvmdev, char *name)
 {
-       struct nvme_ns *ns = q->queuedata;
+       struct nvme_ns *ns = nvmdev->q->queuedata;
        struct nvme_dev *dev = ns->dev;
 
        return dma_pool_create(name, dev->dev, PAGE_SIZE, PAGE_SIZE, 0);
@@ -456,7 +532,7 @@ static void nvme_nvm_destroy_dma_pool(void *pool)
        dma_pool_destroy(dma_pool);
 }
 
-static void *nvme_nvm_dev_dma_alloc(struct request_queue *q, void *pool,
+static void *nvme_nvm_dev_dma_alloc(struct nvm_dev *dev, void *pool,
                                    gfp_t mem_flags, dma_addr_t *dma_handler)
 {
        return dma_pool_alloc(pool, mem_flags, dma_handler);
@@ -474,6 +550,7 @@ static struct nvm_dev_ops nvme_nvm_dev_ops = {
        .get_l2p_tbl            = nvme_nvm_get_l2p_tbl,
 
        .get_bb_tbl             = nvme_nvm_get_bb_tbl,
+       .set_bb_tbl             = nvme_nvm_set_bb_tbl,
 
        .submit_io              = nvme_nvm_submit_io,
        .erase_block            = nvme_nvm_erase_block,
@@ -496,31 +573,27 @@ void nvme_nvm_unregister(struct request_queue *q, char *disk_name)
        nvm_unregister(disk_name);
 }
 
+/* move to shared place when used in multiple places. */
+#define PCI_VENDOR_ID_CNEX 0x1d1d
+#define PCI_DEVICE_ID_CNEX_WL 0x2807
+#define PCI_DEVICE_ID_CNEX_QEMU 0x1f1f
+
 int nvme_nvm_ns_supported(struct nvme_ns *ns, struct nvme_id_ns *id)
 {
        struct nvme_dev *dev = ns->dev;
        struct pci_dev *pdev = to_pci_dev(dev->dev);
 
        /* QEMU NVMe simulator - PCI ID + Vendor specific bit */
-       if (pdev->vendor == PCI_VENDOR_ID_INTEL && pdev->device == 0x5845 &&
+       if (pdev->vendor == PCI_VENDOR_ID_CNEX &&
+                               pdev->device == PCI_DEVICE_ID_CNEX_QEMU &&
                                                        id->vs[0] == 0x1)
                return 1;
 
        /* CNEX Labs - PCI ID + Vendor specific bit */
-       if (pdev->vendor == 0x1d1d && pdev->device == 0x2807 &&
+       if (pdev->vendor == PCI_VENDOR_ID_CNEX &&
+                               pdev->device == PCI_DEVICE_ID_CNEX_WL &&
                                                        id->vs[0] == 0x1)
                return 1;
 
        return 0;
 }
-#else
-int nvme_nvm_register(struct request_queue *q, char *disk_name)
-{
-       return 0;
-}
-void nvme_nvm_unregister(struct request_queue *q, char *disk_name) {};
-int nvme_nvm_ns_supported(struct nvme_ns *ns, struct nvme_id_ns *id)
-{
-       return 0;
-}
-#endif /* CONFIG_NVM */
index fdb4e5bad9ac73c59c67e70100aba411d124ab2e..044253dca30a433549a37ec7e28c3a6c161d38a5 100644 (file)
@@ -136,8 +136,22 @@ int nvme_sg_io(struct nvme_ns *ns, struct sg_io_hdr __user *u_hdr);
 int nvme_sg_io32(struct nvme_ns *ns, unsigned long arg);
 int nvme_sg_get_version_num(int __user *ip);
 
+#ifdef CONFIG_NVM
 int nvme_nvm_ns_supported(struct nvme_ns *ns, struct nvme_id_ns *id);
 int nvme_nvm_register(struct request_queue *q, char *disk_name);
 void nvme_nvm_unregister(struct request_queue *q, char *disk_name);
+#else
+static inline int nvme_nvm_register(struct request_queue *q, char *disk_name)
+{
+       return 0;
+}
+
+static inline void nvme_nvm_unregister(struct request_queue *q, char *disk_name) {};
+
+static inline int nvme_nvm_ns_supported(struct nvme_ns *ns, struct nvme_id_ns *id)
+{
+       return 0;
+}
+#endif /* CONFIG_NVM */
 
 #endif /* _NVME_H */
index 8187df20469535023ae9966aecfb1542260b4270..0c67b57be83c4630a89c670acbbd150b65ec667f 100644 (file)
@@ -896,19 +896,28 @@ static int nvme_queue_rq(struct blk_mq_hw_ctx *hctx,
                        goto retry_cmd;
                }
                if (blk_integrity_rq(req)) {
-                       if (blk_rq_count_integrity_sg(req->q, req->bio) != 1)
+                       if (blk_rq_count_integrity_sg(req->q, req->bio) != 1) {
+                               dma_unmap_sg(dev->dev, iod->sg, iod->nents,
+                                               dma_dir);
                                goto error_cmd;
+                       }
 
                        sg_init_table(iod->meta_sg, 1);
                        if (blk_rq_map_integrity_sg(
-                                       req->q, req->bio, iod->meta_sg) != 1)
+                                       req->q, req->bio, iod->meta_sg) != 1) {
+                               dma_unmap_sg(dev->dev, iod->sg, iod->nents,
+                                               dma_dir);
                                goto error_cmd;
+                       }
 
                        if (rq_data_dir(req))
                                nvme_dif_remap(req, nvme_dif_prep);
 
-                       if (!dma_map_sg(nvmeq->q_dmadev, iod->meta_sg, 1, dma_dir))
+                       if (!dma_map_sg(nvmeq->q_dmadev, iod->meta_sg, 1, dma_dir)) {
+                               dma_unmap_sg(dev->dev, iod->sg, iod->nents,
+                                               dma_dir);
                                goto error_cmd;
+                       }
                }
        }
 
@@ -968,7 +977,8 @@ static void __nvme_process_cq(struct nvme_queue *nvmeq, unsigned int *tag)
        if (head == nvmeq->cq_head && phase == nvmeq->cq_phase)
                return;
 
-       writel(head, nvmeq->q_db + nvmeq->dev->db_stride);
+       if (likely(nvmeq->cq_vector >= 0))
+               writel(head, nvmeq->q_db + nvmeq->dev->db_stride);
        nvmeq->cq_head = head;
        nvmeq->cq_phase = phase;
 
@@ -1727,9 +1737,13 @@ static int nvme_configure_admin_queue(struct nvme_dev *dev)
        u32 aqa;
        u64 cap = lo_hi_readq(&dev->bar->cap);
        struct nvme_queue *nvmeq;
-       unsigned page_shift = PAGE_SHIFT;
+       /*
+        * default to a 4K page size, with the intention to update this
+        * path in the future to accomodate architectures with differing
+        * kernel and IO page sizes.
+        */
+       unsigned page_shift = 12;
        unsigned dev_page_min = NVME_CAP_MPSMIN(cap) + 12;
-       unsigned dev_page_max = NVME_CAP_MPSMAX(cap) + 12;
 
        if (page_shift < dev_page_min) {
                dev_err(dev->dev,
@@ -1738,13 +1752,6 @@ static int nvme_configure_admin_queue(struct nvme_dev *dev)
                                1 << page_shift);
                return -ENODEV;
        }
-       if (page_shift > dev_page_max) {
-               dev_info(dev->dev,
-                               "Device maximum page size (%u) smaller than "
-                               "host (%u); enabling work-around\n",
-                               1 << dev_page_max, 1 << page_shift);
-               page_shift = dev_page_max;
-       }
 
        dev->subsystem = readl(&dev->bar->vs) >= NVME_VS(1, 1) ?
                                                NVME_CAP_NSSRC(cap) : 0;
@@ -2268,7 +2275,7 @@ static void nvme_alloc_ns(struct nvme_dev *dev, unsigned nsid)
        if (dev->max_hw_sectors) {
                blk_queue_max_hw_sectors(ns->queue, dev->max_hw_sectors);
                blk_queue_max_segments(ns->queue,
-                       ((dev->max_hw_sectors << 9) / dev->page_size) + 1);
+                       (dev->max_hw_sectors / (dev->page_size >> 9)) + 1);
        }
        if (dev->stripe_size)
                blk_queue_chunk_sectors(ns->queue, dev->stripe_size >> 9);
@@ -2533,8 +2540,17 @@ static void nvme_ns_remove(struct nvme_ns *ns)
 {
        bool kill = nvme_io_incapable(ns->dev) && !blk_queue_dying(ns->queue);
 
-       if (kill)
+       if (kill) {
                blk_set_queue_dying(ns->queue);
+
+               /*
+                * The controller was shutdown first if we got here through
+                * device removal. The shutdown may requeue outstanding
+                * requests. These need to be aborted immediately so
+                * del_gendisk doesn't block indefinitely for their completion.
+                */
+               blk_mq_abort_requeue_list(ns->queue);
+       }
        if (ns->disk->flags & GENHD_FL_UP)
                del_gendisk(ns->disk);
        if (kill || !blk_queue_dying(ns->queue)) {
@@ -2701,6 +2717,18 @@ static int nvme_dev_map(struct nvme_dev *dev)
        dev->q_depth = min_t(int, NVME_CAP_MQES(cap) + 1, NVME_Q_DEPTH);
        dev->db_stride = 1 << NVME_CAP_STRIDE(cap);
        dev->dbs = ((void __iomem *)dev->bar) + 4096;
+
+       /*
+        * Temporary fix for the Apple controller found in the MacBook8,1 and
+        * some MacBook7,1 to avoid controller resets and data loss.
+        */
+       if (pdev->vendor == PCI_VENDOR_ID_APPLE && pdev->device == 0x2001) {
+               dev->q_depth = 2;
+               dev_warn(dev->dev, "detected Apple NVMe controller, set "
+                       "queue depth=%u to work around controller resets\n",
+                       dev->q_depth);
+       }
+
        if (readl(&dev->bar->vs) >= NVME_VS(1, 2))
                dev->cmb = nvme_map_cmb(dev);
 
@@ -2787,6 +2815,10 @@ static void nvme_del_queue_end(struct nvme_queue *nvmeq)
 {
        struct nvme_delq_ctx *dq = nvmeq->cmdinfo.ctx;
        nvme_put_dq(dq);
+
+       spin_lock_irq(&nvmeq->q_lock);
+       nvme_process_cq(nvmeq);
+       spin_unlock_irq(&nvmeq->q_lock);
 }
 
 static int adapter_async_del_queue(struct nvme_queue *nvmeq, u8 opcode,
@@ -2954,6 +2986,15 @@ static void nvme_dev_remove(struct nvme_dev *dev)
 {
        struct nvme_ns *ns, *next;
 
+       if (nvme_io_incapable(dev)) {
+               /*
+                * If the device is not capable of IO (surprise hot-removal,
+                * for example), we need to quiesce prior to deleting the
+                * namespaces. This will end outstanding requests and prevent
+                * attempts to sync dirty data.
+                */
+               nvme_dev_shutdown(dev);
+       }
        list_for_each_entry_safe(ns, next, &dev->namespaces, list)
                nvme_ns_remove(ns);
 }
index cd53fe4a0c8684900a94fb4bee76f9bd668e3837..9582c5703b3c905486da173d08a2f986883bda26 100644 (file)
@@ -485,9 +485,10 @@ static int of_translate_one(struct device_node *parent, struct of_bus *bus,
        int rone;
        u64 offset = OF_BAD_ADDR;
 
-       /* Normally, an absence of a "ranges" property means we are
+       /*
+        * Normally, an absence of a "ranges" property means we are
         * crossing a non-translatable boundary, and thus the addresses
-        * below the current not cannot be converted to CPU physical ones.
+        * below the current cannot be converted to CPU physical ones.
         * Unfortunately, while this is very clear in the spec, it's not
         * what Apple understood, and they do have things like /uni-n or
         * /ht nodes with no "ranges" property and a lot of perfectly
index d2430298a309a86d3f2110623d3728b9dedb228f..655f79db7899ffd0628714d51203847630a8075c 100644 (file)
@@ -13,6 +13,7 @@
 #include <linux/kernel.h>
 #include <linux/initrd.h>
 #include <linux/memblock.h>
+#include <linux/mutex.h>
 #include <linux/of.h>
 #include <linux/of_fdt.h>
 #include <linux/of_reserved_mem.h>
@@ -436,6 +437,8 @@ static void *kernel_tree_alloc(u64 size, u64 align)
        return kzalloc(size, GFP_KERNEL);
 }
 
+static DEFINE_MUTEX(of_fdt_unflatten_mutex);
+
 /**
  * of_fdt_unflatten_tree - create tree of device_nodes from flat blob
  *
@@ -447,7 +450,9 @@ static void *kernel_tree_alloc(u64 size, u64 align)
 void of_fdt_unflatten_tree(const unsigned long *blob,
                        struct device_node **mynodes)
 {
+       mutex_lock(&of_fdt_unflatten_mutex);
        __unflatten_device_tree(blob, mynodes, &kernel_tree_alloc);
+       mutex_unlock(&of_fdt_unflatten_mutex);
 }
 EXPORT_SYMBOL_GPL(of_fdt_unflatten_tree);
 
@@ -1041,7 +1046,7 @@ void __init __weak early_init_dt_add_memory_arch(u64 base, u64 size)
 int __init __weak early_init_dt_reserve_memory_arch(phys_addr_t base,
                                        phys_addr_t size, bool nomap)
 {
-       pr_err("Reserved memory not supported, ignoring range 0x%pa - 0x%pa%s\n",
+       pr_err("Reserved memory not supported, ignoring range %pa - %pa%s\n",
                  &base, &size, nomap ? " (nomap)" : "");
        return -ENOSYS;
 }
index 902b89be7217137726be7eb1ab19263c0372635a..4fa916dffc91924a0354c3c779ae5bf41cb79cec 100644 (file)
@@ -53,7 +53,7 @@ EXPORT_SYMBOL_GPL(irq_of_parse_and_map);
  * Returns a pointer to the interrupt parent node, or NULL if the interrupt
  * parent could not be determined.
  */
-static struct device_node *of_irq_find_parent(struct device_node *child)
+struct device_node *of_irq_find_parent(struct device_node *child)
 {
        struct device_node *p;
        const __be32 *parp;
@@ -77,6 +77,7 @@ static struct device_node *of_irq_find_parent(struct device_node *child)
 
        return p;
 }
+EXPORT_SYMBOL_GPL(of_irq_find_parent);
 
 /**
  * of_irq_parse_raw - Low level interrupt tree parsing
index be77e75c587db95c55a51e556f228f97810e051c..1a3556a9e9ea126b451b2a3c68e0407135af242f 100644 (file)
@@ -206,7 +206,13 @@ static int __init __rmem_cmp(const void *a, const void *b)
 {
        const struct reserved_mem *ra = a, *rb = b;
 
-       return ra->base - rb->base;
+       if (ra->base < rb->base)
+               return -1;
+
+       if (ra->base > rb->base)
+               return 1;
+
+       return 0;
 }
 
 static void __init __rmem_check_for_overlap(void)
index 761e77bfce5d2f43f251ebb74f82245d52c5f5f3..e56f1569f6c396f8c29448e9adb26214e26ba9fc 100644 (file)
@@ -104,7 +104,11 @@ iommu_coalesce_chunks(struct ioc *ioc, struct device *dev,
        struct scatterlist *contig_sg;     /* contig chunk head */
        unsigned long dma_offset, dma_len; /* start/len of DMA stream */
        unsigned int n_mappings = 0;
-       unsigned int max_seg_size = dma_get_max_seg_size(dev);
+       unsigned int max_seg_size = min(dma_get_max_seg_size(dev),
+                                       (unsigned)DMA_CHUNK_SIZE);
+       unsigned int max_seg_boundary = dma_get_seg_boundary(dev) + 1;
+       if (max_seg_boundary)   /* check if the addition above didn't overflow */
+               max_seg_size = min(max_seg_size, max_seg_boundary);
 
        while (nents > 0) {
 
@@ -138,14 +142,11 @@ iommu_coalesce_chunks(struct ioc *ioc, struct device *dev,
 
                        /*
                        ** First make sure current dma stream won't
-                       ** exceed DMA_CHUNK_SIZE if we coalesce the
+                       ** exceed max_seg_size if we coalesce the
                        ** next entry.
                        */   
-                       if(unlikely(ALIGN(dma_len + dma_offset + startsg->length,
-                                           IOVP_SIZE) > DMA_CHUNK_SIZE))
-                               break;
-
-                       if (startsg->length + dma_len > max_seg_size)
+                       if (unlikely(ALIGN(dma_len + dma_offset + startsg->length, IOVP_SIZE) >
+                                    max_seg_size))
                                break;
 
                        /*
index e5dda38bdde5e1735a50b4de9fcd2cd6307d13c5..99da549d5d06a067b58d3bbe08c39041a9d90605 100644 (file)
 #define TLP_CFG_DW2(bus, devfn, offset)        \
                                (((bus) << 24) | ((devfn) << 16) | (offset))
 #define TLP_REQ_ID(bus, devfn)         (((bus) << 8) | (devfn))
+#define TLP_COMP_STATUS(s)             (((s) >> 12) & 7)
 #define TLP_HDR_SIZE                   3
 #define TLP_LOOP                       500
+#define RP_DEVFN                       0
 
 #define INTX_NUM                       4
 
@@ -166,34 +168,41 @@ static bool altera_pcie_valid_config(struct altera_pcie *pcie,
 
 static int tlp_read_packet(struct altera_pcie *pcie, u32 *value)
 {
-       u8 loop;
+       int i;
        bool sop = 0;
        u32 ctrl;
        u32 reg0, reg1;
+       u32 comp_status = 1;
 
        /*
         * Minimum 2 loops to read TLP headers and 1 loop to read data
         * payload.
         */
-       for (loop = 0; loop < TLP_LOOP; loop++) {
+       for (i = 0; i < TLP_LOOP; i++) {
                ctrl = cra_readl(pcie, RP_RXCPL_STATUS);
                if ((ctrl & RP_RXCPL_SOP) || (ctrl & RP_RXCPL_EOP) || sop) {
                        reg0 = cra_readl(pcie, RP_RXCPL_REG0);
                        reg1 = cra_readl(pcie, RP_RXCPL_REG1);
 
-                       if (ctrl & RP_RXCPL_SOP)
+                       if (ctrl & RP_RXCPL_SOP) {
                                sop = true;
+                               comp_status = TLP_COMP_STATUS(reg1);
+                       }
 
                        if (ctrl & RP_RXCPL_EOP) {
+                               if (comp_status)
+                                       return PCIBIOS_DEVICE_NOT_FOUND;
+
                                if (value)
                                        *value = reg0;
+
                                return PCIBIOS_SUCCESSFUL;
                        }
                }
                udelay(5);
        }
 
-       return -ENOENT;
+       return PCIBIOS_DEVICE_NOT_FOUND;
 }
 
 static void tlp_write_packet(struct altera_pcie *pcie, u32 *headers,
@@ -233,7 +242,7 @@ static int tlp_cfg_dword_read(struct altera_pcie *pcie, u8 bus, u32 devfn,
        else
                headers[0] = TLP_CFG_DW0(TLP_FMTTYPE_CFGRD1);
 
-       headers[1] = TLP_CFG_DW1(TLP_REQ_ID(pcie->root_bus_nr, devfn),
+       headers[1] = TLP_CFG_DW1(TLP_REQ_ID(pcie->root_bus_nr, RP_DEVFN),
                                        TLP_READ_TAG, byte_en);
        headers[2] = TLP_CFG_DW2(bus, devfn, where);
 
@@ -253,7 +262,7 @@ static int tlp_cfg_dword_write(struct altera_pcie *pcie, u8 bus, u32 devfn,
        else
                headers[0] = TLP_CFG_DW0(TLP_FMTTYPE_CFGWR1);
 
-       headers[1] = TLP_CFG_DW1(TLP_REQ_ID(pcie->root_bus_nr, devfn),
+       headers[1] = TLP_CFG_DW1(TLP_REQ_ID(pcie->root_bus_nr, RP_DEVFN),
                                        TLP_WRITE_TAG, byte_en);
        headers[2] = TLP_CFG_DW2(bus, devfn, where);
 
@@ -458,7 +467,7 @@ static int altera_pcie_init_irq_domain(struct altera_pcie *pcie)
        struct device_node *node = dev->of_node;
 
        /* Setup INTx */
-       pcie->irq_domain = irq_domain_add_linear(node, INTX_NUM,
+       pcie->irq_domain = irq_domain_add_linear(node, INTX_NUM + 1,
                                        &intx_domain_ops, pcie);
        if (!pcie->irq_domain) {
                dev_err(dev, "Failed to get a INTx IRQ domain\n");
index 540f077c37eae7b59b983c31fa6ddce51d8bda6e..02a7452bdf235cf52731b3a822066c27d33e8a76 100644 (file)
@@ -440,7 +440,6 @@ int dw_pcie_host_init(struct pcie_port *pp)
                                         ret, pp->io);
                                continue;
                        }
-                       pp->io_base = pp->io->start;
                        break;
                case IORESOURCE_MEM:
                        pp->mem = win->res;
index 35457ecd8e70f4d6f856573f45f8bbc2991d1f6d..77f7c669a1b9bb497528874c10262430c868959d 100644 (file)
@@ -61,7 +61,9 @@ static int hisi_pcie_cfg_read(struct pcie_port *pp, int where, int size,
                *val = *(u8 __force *) walker;
        else if (size == 2)
                *val = *(u16 __force *) walker;
-       else if (size != 4)
+       else if (size == 4)
+               *val = reg_val;
+       else
                return PCIBIOS_BAD_REGISTER_NUMBER;
 
        return PCIBIOS_SUCCESSFUL;
@@ -111,7 +113,7 @@ static struct pcie_host_ops hisi_pcie_host_ops = {
        .link_up = hisi_pcie_link_up,
 };
 
-static int __init hisi_add_pcie_port(struct pcie_port *pp,
+static int hisi_add_pcie_port(struct pcie_port *pp,
                                     struct platform_device *pdev)
 {
        int ret;
@@ -139,7 +141,7 @@ static int __init hisi_add_pcie_port(struct pcie_port *pp,
        return 0;
 }
 
-static int __init hisi_pcie_probe(struct platform_device *pdev)
+static int hisi_pcie_probe(struct platform_device *pdev)
 {
        struct hisi_pcie *hisi_pcie;
        struct pcie_port *pp;
index 53e463244bb7e35ac368ff088a4976c2153fce3d..7eaa4c87fec71c8dd792ccffc919b322711d91dd 100644 (file)
@@ -54,7 +54,7 @@ static int pci_msi_setup_msi_irqs(struct pci_dev *dev, int nvec, int type)
        struct irq_domain *domain;
 
        domain = pci_msi_get_domain(dev);
-       if (domain)
+       if (domain && irq_domain_is_hierarchy(domain))
                return pci_msi_domain_alloc_irqs(domain, dev, nvec, type);
 
        return arch_setup_msi_irqs(dev, nvec, type);
@@ -65,7 +65,7 @@ static void pci_msi_teardown_msi_irqs(struct pci_dev *dev)
        struct irq_domain *domain;
 
        domain = pci_msi_get_domain(dev);
-       if (domain)
+       if (domain && irq_domain_is_hierarchy(domain))
                pci_msi_domain_free_irqs(domain, dev);
        else
                arch_teardown_msi_irqs(dev);
index 4446fcb5effd347d87fb6314473297acc4558769..d7ffd66814bb51c14cbdf849fcd6a0a33f30dba7 100644 (file)
@@ -1146,9 +1146,21 @@ static int pci_pm_runtime_suspend(struct device *dev)
        pci_dev->state_saved = false;
        pci_dev->no_d3cold = false;
        error = pm->runtime_suspend(dev);
-       suspend_report_result(pm->runtime_suspend, error);
-       if (error)
+       if (error) {
+               /*
+                * -EBUSY and -EAGAIN is used to request the runtime PM core
+                * to schedule a new suspend, so log the event only with debug
+                * log level.
+                */
+               if (error == -EBUSY || error == -EAGAIN)
+                       dev_dbg(dev, "can't suspend now (%pf returned %d)\n",
+                               pm->runtime_suspend, error);
+               else
+                       dev_err(dev, "can't suspend (%pf returned %d)\n",
+                               pm->runtime_suspend, error);
+
                return error;
+       }
        if (!pci_dev->d3cold_allowed)
                pci_dev->no_d3cold = true;
 
index 92618686604cb9d314aa1e6bf833363cfbaaa1b5..eead54cd01b2bfad6a5514f53067429e616db6b7 100644 (file)
@@ -216,7 +216,10 @@ static ssize_t numa_node_store(struct device *dev,
        if (ret)
                return ret;
 
-       if (node >= MAX_NUMNODES || !node_online(node))
+       if ((node < 0 && node != NUMA_NO_NODE) || node >= MAX_NUMNODES)
+               return -EINVAL;
+
+       if (node != NUMA_NO_NODE && !node_online(node))
                return -EINVAL;
 
        add_taint(TAINT_FIRMWARE_WORKAROUND, LOCKDEP_STILL_OK);
index fd2f03fa53f33a34977fc8713fd8cf6759cad2d5..d390fc1475eccf9f77491b5b401a823067b2995b 100644 (file)
@@ -337,6 +337,4 @@ static inline int pci_dev_specific_reset(struct pci_dev *dev, int probe)
 }
 #endif
 
-struct pci_host_bridge *pci_find_host_bridge(struct pci_bus *bus);
-
 #endif /* DRIVERS_PCI_H */
index e735c728e3b34aa441d1bc140e5473554af8385d..edb1984201e9702162321c50f33f76ba362bac5a 100644 (file)
@@ -1685,8 +1685,8 @@ static void pci_dma_configure(struct pci_dev *dev)
 {
        struct device *bridge = pci_get_host_bridge_device(dev);
 
-       if (IS_ENABLED(CONFIG_OF) && dev->dev.of_node) {
-               if (bridge->parent)
+       if (IS_ENABLED(CONFIG_OF) &&
+               bridge->parent && bridge->parent->of_node) {
                        of_dma_configure(&dev->dev, bridge->parent->of_node);
        } else if (has_acpi_companion(bridge)) {
                struct acpi_device *adev = to_acpi_device_node(bridge->fwnode);
index 7eb5859dd035fefabea842f40722580cfcdfe64a..03cb3ea2d2c035b32254022b1506fcf52d770655 100644 (file)
@@ -233,6 +233,7 @@ config PHY_SUN9I_USB
        tristate "Allwinner sun9i SoC USB PHY driver"
        depends on ARCH_SUNXI && HAS_IOMEM && OF
        depends on RESET_CONTROLLER
+       depends on USB_COMMON
        select GENERIC_PHY
        help
          Enable this to support the transceiver that is part of Allwinner
index 7ad72b7d2b981b6ff4ae59011fdd5e6c5538ef51..082c03f6438f796af868cb83127f1ce9ca56f83b 100644 (file)
@@ -128,6 +128,7 @@ static int cygnus_pcie_phy_probe(struct platform_device *pdev)
        struct phy_provider *provider;
        struct resource *res;
        unsigned cnt = 0;
+       int ret;
 
        if (of_get_child_count(node) == 0) {
                dev_err(dev, "PHY no child node\n");
@@ -154,24 +155,28 @@ static int cygnus_pcie_phy_probe(struct platform_device *pdev)
                if (of_property_read_u32(child, "reg", &id)) {
                        dev_err(dev, "missing reg property for %s\n",
                                child->name);
-                       return -EINVAL;
+                       ret = -EINVAL;
+                       goto put_child;
                }
 
                if (id >= MAX_NUM_PHYS) {
                        dev_err(dev, "invalid PHY id: %u\n", id);
-                       return -EINVAL;
+                       ret = -EINVAL;
+                       goto put_child;
                }
 
                if (core->phys[id].phy) {
                        dev_err(dev, "duplicated PHY id: %u\n", id);
-                       return -EINVAL;
+                       ret = -EINVAL;
+                       goto put_child;
                }
 
                p = &core->phys[id];
                p->phy = devm_phy_create(dev, child, &cygnus_pcie_phy_ops);
                if (IS_ERR(p->phy)) {
                        dev_err(dev, "failed to create PHY\n");
-                       return PTR_ERR(p->phy);
+                       ret = PTR_ERR(p->phy);
+                       goto put_child;
                }
 
                p->core = core;
@@ -191,6 +196,9 @@ static int cygnus_pcie_phy_probe(struct platform_device *pdev)
        dev_dbg(dev, "registered %u PCIe PHY(s)\n", cnt);
 
        return 0;
+put_child:
+       of_node_put(child);
+       return ret;
 }
 
 static const struct of_device_id cygnus_pcie_phy_match_table[] = {
index 77a2e054fdea0f46ccd3d2841f5f837f80a985e1..f84a33a1bdd935c5a6c171929d172b1a1a67840c 100644 (file)
@@ -195,7 +195,7 @@ static int phy_berlin_sata_probe(struct platform_device *pdev)
        struct phy_provider *phy_provider;
        struct phy_berlin_priv *priv;
        struct resource *res;
-       int i = 0;
+       int ret, i = 0;
        u32 phy_id;
 
        priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
@@ -237,22 +237,27 @@ static int phy_berlin_sata_probe(struct platform_device *pdev)
                if (of_property_read_u32(child, "reg", &phy_id)) {
                        dev_err(dev, "missing reg property in node %s\n",
                                child->name);
-                       return -EINVAL;
+                       ret = -EINVAL;
+                       goto put_child;
                }
 
                if (phy_id >= ARRAY_SIZE(phy_berlin_power_down_bits)) {
                        dev_err(dev, "invalid reg in node %s\n", child->name);
-                       return -EINVAL;
+                       ret = -EINVAL;
+                       goto put_child;
                }
 
                phy_desc = devm_kzalloc(dev, sizeof(*phy_desc), GFP_KERNEL);
-               if (!phy_desc)
-                       return -ENOMEM;
+               if (!phy_desc) {
+                       ret = -ENOMEM;
+                       goto put_child;
+               }
 
                phy = devm_phy_create(dev, NULL, &phy_berlin_sata_ops);
                if (IS_ERR(phy)) {
                        dev_err(dev, "failed to create PHY %d\n", phy_id);
-                       return PTR_ERR(phy);
+                       ret = PTR_ERR(phy);
+                       goto put_child;
                }
 
                phy_desc->phy = phy;
@@ -269,6 +274,9 @@ static int phy_berlin_sata_probe(struct platform_device *pdev)
        phy_provider =
                devm_of_phy_provider_register(dev, phy_berlin_sata_phy_xlate);
        return PTR_ERR_OR_ZERO(phy_provider);
+put_child:
+       of_node_put(child);
+       return ret;
 }
 
 static const struct of_device_id phy_berlin_sata_of_match[] = {
index 8a2cb16a1937d20e88b045868beec28db966be5c..cd9dba8205668d98665d938b13a5e254b74bdb17 100644 (file)
@@ -140,7 +140,7 @@ static int brcm_sata_phy_probe(struct platform_device *pdev)
        struct brcm_sata_phy *priv;
        struct resource *res;
        struct phy_provider *provider;
-       int count = 0;
+       int ret, count = 0;
 
        if (of_get_child_count(dn) == 0)
                return -ENODEV;
@@ -163,16 +163,19 @@ static int brcm_sata_phy_probe(struct platform_device *pdev)
                if (of_property_read_u32(child, "reg", &id)) {
                        dev_err(dev, "missing reg property in node %s\n",
                                        child->name);
-                       return -EINVAL;
+                       ret = -EINVAL;
+                       goto put_child;
                }
 
                if (id >= MAX_PORTS) {
                        dev_err(dev, "invalid reg: %u\n", id);
-                       return -EINVAL;
+                       ret = -EINVAL;
+                       goto put_child;
                }
                if (priv->phys[id].phy) {
                        dev_err(dev, "already registered port %u\n", id);
-                       return -EINVAL;
+                       ret = -EINVAL;
+                       goto put_child;
                }
 
                port = &priv->phys[id];
@@ -182,7 +185,8 @@ static int brcm_sata_phy_probe(struct platform_device *pdev)
                port->ssc_en = of_property_read_bool(child, "brcm,enable-ssc");
                if (IS_ERR(port->phy)) {
                        dev_err(dev, "failed to create PHY\n");
-                       return PTR_ERR(port->phy);
+                       ret = PTR_ERR(port->phy);
+                       goto put_child;
                }
 
                phy_set_drvdata(port->phy, port);
@@ -198,6 +202,9 @@ static int brcm_sata_phy_probe(struct platform_device *pdev)
        dev_info(dev, "registered %d port(s)\n", count);
 
        return 0;
+put_child:
+       of_node_put(child);
+       return ret;
 }
 
 static struct platform_driver brcm_sata_phy_driver = {
index fc48fac003a62ba124bd7c6820f24d5d040fcbf7..8c7f27db6ad352260f8ad8675758ed365b6390a6 100644 (file)
@@ -636,8 +636,9 @@ EXPORT_SYMBOL_GPL(devm_of_phy_get);
  * @np: node containing the phy
  * @index: index of the phy
  *
- * Gets the phy using _of_phy_get(), and associates a device with it using
- * devres. On driver detach, release function is invoked on the devres data,
+ * Gets the phy using _of_phy_get(), then gets a refcount to it,
+ * and associates a device with it using devres. On driver detach,
+ * release function is invoked on the devres data,
  * then, devres data is freed.
  *
  */
@@ -651,13 +652,21 @@ struct phy *devm_of_phy_get_by_index(struct device *dev, struct device_node *np,
                return ERR_PTR(-ENOMEM);
 
        phy = _of_phy_get(np, index);
-       if (!IS_ERR(phy)) {
-               *ptr = phy;
-               devres_add(dev, ptr);
-       } else {
+       if (IS_ERR(phy)) {
                devres_free(ptr);
+               return phy;
        }
 
+       if (!try_module_get(phy->ops->owner)) {
+               devres_free(ptr);
+               return ERR_PTR(-EPROBE_DEFER);
+       }
+
+       get_device(&phy->dev);
+
+       *ptr = phy;
+       devres_add(dev, ptr);
+
        return phy;
 }
 EXPORT_SYMBOL_GPL(devm_of_phy_get_by_index);
index c47b56b4a2b8892810f00179a53e9eceba7c612c..3acd2a1808dfbf9ccfa5d58467b6defdb793c2bb 100644 (file)
@@ -1226,15 +1226,18 @@ static int miphy28lp_probe(struct platform_device *pdev)
 
                miphy_phy = devm_kzalloc(&pdev->dev, sizeof(*miphy_phy),
                                         GFP_KERNEL);
-               if (!miphy_phy)
-                       return -ENOMEM;
+               if (!miphy_phy) {
+                       ret = -ENOMEM;
+                       goto put_child;
+               }
 
                miphy_dev->phys[port] = miphy_phy;
 
                phy = devm_phy_create(&pdev->dev, child, &miphy28lp_ops);
                if (IS_ERR(phy)) {
                        dev_err(&pdev->dev, "failed to create PHY\n");
-                       return PTR_ERR(phy);
+                       ret = PTR_ERR(phy);
+                       goto put_child;
                }
 
                miphy_dev->phys[port]->phy = phy;
@@ -1242,11 +1245,11 @@ static int miphy28lp_probe(struct platform_device *pdev)
 
                ret = miphy28lp_of_probe(child, miphy_phy);
                if (ret)
-                       return ret;
+                       goto put_child;
 
                ret = miphy28lp_probe_resets(child, miphy_dev->phys[port]);
                if (ret)
-                       return ret;
+                       goto put_child;
 
                phy_set_drvdata(phy, miphy_dev->phys[port]);
                port++;
@@ -1255,6 +1258,9 @@ static int miphy28lp_probe(struct platform_device *pdev)
 
        provider = devm_of_phy_provider_register(&pdev->dev, miphy28lp_xlate);
        return PTR_ERR_OR_ZERO(provider);
+put_child:
+       of_node_put(child);
+       return ret;
 }
 
 static const struct of_device_id miphy28lp_of_match[] = {
index 00a686a073ed6ee804ea96ebcdb0ef3813482a85..e661f3b36eaa0cdf992cde8f88d92644ff585c5e 100644 (file)
@@ -566,22 +566,25 @@ static int miphy365x_probe(struct platform_device *pdev)
 
                miphy_phy = devm_kzalloc(&pdev->dev, sizeof(*miphy_phy),
                                         GFP_KERNEL);
-               if (!miphy_phy)
-                       return -ENOMEM;
+               if (!miphy_phy) {
+                       ret = -ENOMEM;
+                       goto put_child;
+               }
 
                miphy_dev->phys[port] = miphy_phy;
 
                phy = devm_phy_create(&pdev->dev, child, &miphy365x_ops);
                if (IS_ERR(phy)) {
                        dev_err(&pdev->dev, "failed to create PHY\n");
-                       return PTR_ERR(phy);
+                       ret = PTR_ERR(phy);
+                       goto put_child;
                }
 
                miphy_dev->phys[port]->phy = phy;
 
                ret = miphy365x_of_probe(child, miphy_phy);
                if (ret)
-                       return ret;
+                       goto put_child;
 
                phy_set_drvdata(phy, miphy_dev->phys[port]);
 
@@ -591,12 +594,15 @@ static int miphy365x_probe(struct platform_device *pdev)
                                        &miphy_phy->ctrlreg);
                if (ret) {
                        dev_err(&pdev->dev, "No sysconfig offset found\n");
-                       return ret;
+                       goto put_child;
                }
        }
 
        provider = devm_of_phy_provider_register(&pdev->dev, miphy365x_xlate);
        return PTR_ERR_OR_ZERO(provider);
+put_child:
+       of_node_put(child);
+       return ret;
 }
 
 static const struct of_device_id miphy365x_of_match[] = {
index f30b28bd41fe7b11a8cce95e889ae894fef20518..e427c3b788ff35e23a49808116936f0d5f39ffa4 100644 (file)
@@ -415,7 +415,7 @@ static int mt65xx_u3phy_probe(struct platform_device *pdev)
        struct resource *sif_res;
        struct mt65xx_u3phy *u3phy;
        struct resource res;
-       int port;
+       int port, retval;
 
        u3phy = devm_kzalloc(dev, sizeof(*u3phy), GFP_KERNEL);
        if (!u3phy)
@@ -447,31 +447,34 @@ static int mt65xx_u3phy_probe(struct platform_device *pdev)
        for_each_child_of_node(np, child_np) {
                struct mt65xx_phy_instance *instance;
                struct phy *phy;
-               int retval;
 
                instance = devm_kzalloc(dev, sizeof(*instance), GFP_KERNEL);
-               if (!instance)
-                       return -ENOMEM;
+               if (!instance) {
+                       retval = -ENOMEM;
+                       goto put_child;
+               }
 
                u3phy->phys[port] = instance;
 
                phy = devm_phy_create(dev, child_np, &mt65xx_u3phy_ops);
                if (IS_ERR(phy)) {
                        dev_err(dev, "failed to create phy\n");
-                       return PTR_ERR(phy);
+                       retval = PTR_ERR(phy);
+                       goto put_child;
                }
 
                retval = of_address_to_resource(child_np, 0, &res);
                if (retval) {
                        dev_err(dev, "failed to get address resource(id-%d)\n",
                                port);
-                       return retval;
+                       goto put_child;
                }
 
                instance->port_base = devm_ioremap_resource(&phy->dev, &res);
                if (IS_ERR(instance->port_base)) {
                        dev_err(dev, "failed to remap phy regs\n");
-                       return PTR_ERR(instance->port_base);
+                       retval = PTR_ERR(instance->port_base);
+                       goto put_child;
                }
 
                instance->phy = phy;
@@ -483,6 +486,9 @@ static int mt65xx_u3phy_probe(struct platform_device *pdev)
        provider = devm_of_phy_provider_register(dev, mt65xx_phy_xlate);
 
        return PTR_ERR_OR_ZERO(provider);
+put_child:
+       of_node_put(child_np);
+       return retval;
 }
 
 static const struct of_device_id mt65xx_u3phy_id_table[] = {
index 91d6f342c56596fc2e3fcff18213dba004546c3e..62c43c435194313e7d5ea7049d568cb673857da9 100644 (file)
@@ -108,13 +108,16 @@ static int rockchip_usb_phy_probe(struct platform_device *pdev)
 
        for_each_available_child_of_node(dev->of_node, child) {
                rk_phy = devm_kzalloc(dev, sizeof(*rk_phy), GFP_KERNEL);
-               if (!rk_phy)
-                       return -ENOMEM;
+               if (!rk_phy) {
+                       err = -ENOMEM;
+                       goto put_child;
+               }
 
                if (of_property_read_u32(child, "reg", &reg_offset)) {
                        dev_err(dev, "missing reg property in node %s\n",
                                child->name);
-                       return -EINVAL;
+                       err = -EINVAL;
+                       goto put_child;
                }
 
                rk_phy->reg_offset = reg_offset;
@@ -127,18 +130,22 @@ static int rockchip_usb_phy_probe(struct platform_device *pdev)
                rk_phy->phy = devm_phy_create(dev, child, &ops);
                if (IS_ERR(rk_phy->phy)) {
                        dev_err(dev, "failed to create PHY\n");
-                       return PTR_ERR(rk_phy->phy);
+                       err = PTR_ERR(rk_phy->phy);
+                       goto put_child;
                }
                phy_set_drvdata(rk_phy->phy, rk_phy);
 
                /* only power up usb phy when it use, so disable it when init*/
                err = rockchip_usb_phy_power(rk_phy, 1);
                if (err)
-                       return err;
+                       goto put_child;
        }
 
        phy_provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate);
        return PTR_ERR_OR_ZERO(phy_provider);
+put_child:
+       of_node_put(child);
+       return err;
 }
 
 static const struct of_device_id rockchip_usb_phy_dt_ids[] = {
index b422e4ed73f4266f7a8d13db4ec1096395163fc3..312c78b27a3206c813c85912e14b570ffa43a0a6 100644 (file)
@@ -5,8 +5,6 @@
 config PINCTRL
        bool
 
-if PINCTRL
-
 menu "Pin controllers"
        depends on PINCTRL
 
@@ -274,5 +272,3 @@ config PINCTRL_TB10X
        select GPIOLIB
 
 endmenu
-
-endif
index a1ea565fcd46490e58d48e4363318c2ce6970ebc..2e6ca69635aa001531d2b9aca128d001b97d9aca 100644 (file)
@@ -342,12 +342,6 @@ static int bcm2835_gpio_get(struct gpio_chip *chip, unsigned offset)
        return bcm2835_gpio_get_bit(pc, GPLEV0, offset);
 }
 
-static int bcm2835_gpio_direction_output(struct gpio_chip *chip,
-               unsigned offset, int value)
-{
-       return pinctrl_gpio_direction_output(chip->base + offset);
-}
-
 static void bcm2835_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
 {
        struct bcm2835_pinctrl *pc = dev_get_drvdata(chip->dev);
@@ -355,6 +349,13 @@ static void bcm2835_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
        bcm2835_gpio_set_bit(pc, value ? GPSET0 : GPCLR0, offset);
 }
 
+static int bcm2835_gpio_direction_output(struct gpio_chip *chip,
+               unsigned offset, int value)
+{
+       bcm2835_gpio_set(chip, offset, value);
+       return pinctrl_gpio_direction_output(chip->base + offset);
+}
+
 static int bcm2835_gpio_to_irq(struct gpio_chip *chip, unsigned offset)
 {
        struct bcm2835_pinctrl *pc = dev_get_drvdata(chip->dev);
index 88a7fac11bd499f72c831b91f0f6c05bd29b19f7..acaf84cadca3fcac638656638a3ea8310011c6da 100644 (file)
@@ -538,8 +538,10 @@ static int imx1_pinctrl_parse_functions(struct device_node *np,
                func->groups[i] = child->name;
                grp = &info->groups[grp_index++];
                ret = imx1_pinctrl_parse_groups(child, grp, info, i++);
-               if (ret == -ENOMEM)
+               if (ret == -ENOMEM) {
+                       of_node_put(child);
                        return ret;
+               }
        }
 
        return 0;
@@ -582,8 +584,10 @@ static int imx1_pinctrl_parse_dt(struct platform_device *pdev,
 
        for_each_child_of_node(np, child) {
                ret = imx1_pinctrl_parse_functions(child, info, ifunc++);
-               if (ret == -ENOMEM)
+               if (ret == -ENOMEM) {
+                       of_node_put(child);
                        return -ENOMEM;
+               }
        }
 
        return 0;
index 37a037543d299115a09e6a4106f1592acc9566a9..587d1ff6210efb62341b792d0318b412c0a4d046 100644 (file)
@@ -299,7 +299,7 @@ static const struct pinctrl_pin_desc vf610_pinctrl_pads[] = {
 static struct imx_pinctrl_soc_info vf610_pinctrl_info = {
        .pins = vf610_pinctrl_pads,
        .npins = ARRAY_SIZE(vf610_pinctrl_pads),
-       .flags = SHARE_MUX_CONF_REG,
+       .flags = SHARE_MUX_CONF_REG | ZERO_OFFSET_VALID,
 };
 
 static const struct of_device_id vf610_pinctrl_of_match[] = {
index e42d5d4183f57ff0dc0d942254f5925dabd3c07a..5979d38c46b254965e8a7782de9a6c902894ce9a 100644 (file)
@@ -28,6 +28,7 @@
                .padcfglock_offset = BXT_PADCFGLOCK,    \
                .hostown_offset = BXT_HOSTSW_OWN,       \
                .ie_offset = BXT_GPI_IE,                \
+               .gpp_size = 32,                         \
                .pin_base = (s),                        \
                .npins = ((e) - (s) + 1),               \
        }
index 392e28d3f48d0bee1a4087154e904c7dfdc0faa7..26f6b6ffea5b23fac04224d9772996db12bc6176 100644 (file)
@@ -25,9 +25,6 @@
 
 #include "pinctrl-intel.h"
 
-/* Maximum number of pads in each group */
-#define NPADS_IN_GPP                   24
-
 /* Offset from regs */
 #define PADBAR                         0x00c
 #define GPI_IS                         0x100
@@ -37,6 +34,7 @@
 #define PADOWN_BITS                    4
 #define PADOWN_SHIFT(p)                        ((p) % 8 * PADOWN_BITS)
 #define PADOWN_MASK(p)                 (0xf << PADOWN_SHIFT(p))
+#define PADOWN_GPP(p)                  ((p) / 8)
 
 /* Offset from pad_regs */
 #define PADCFG0                                0x000
@@ -142,7 +140,7 @@ static void __iomem *intel_get_padcfg(struct intel_pinctrl *pctrl, unsigned pin,
 static bool intel_pad_owned_by_host(struct intel_pinctrl *pctrl, unsigned pin)
 {
        const struct intel_community *community;
-       unsigned padno, gpp, gpp_offset, offset;
+       unsigned padno, gpp, offset, group;
        void __iomem *padown;
 
        community = intel_get_community(pctrl, pin);
@@ -152,9 +150,9 @@ static bool intel_pad_owned_by_host(struct intel_pinctrl *pctrl, unsigned pin)
                return true;
 
        padno = pin_to_padno(community, pin);
-       gpp = padno / NPADS_IN_GPP;
-       gpp_offset = padno % NPADS_IN_GPP;
-       offset = community->padown_offset + gpp * 16 + (gpp_offset / 8) * 4;
+       group = padno / community->gpp_size;
+       gpp = PADOWN_GPP(padno % community->gpp_size);
+       offset = community->padown_offset + 0x10 * group + gpp * 4;
        padown = community->regs + offset;
 
        return !(readl(padown) & PADOWN_MASK(padno));
@@ -173,11 +171,11 @@ static bool intel_pad_acpi_mode(struct intel_pinctrl *pctrl, unsigned pin)
                return false;
 
        padno = pin_to_padno(community, pin);
-       gpp = padno / NPADS_IN_GPP;
+       gpp = padno / community->gpp_size;
        offset = community->hostown_offset + gpp * 4;
        hostown = community->regs + offset;
 
-       return !(readl(hostown) & BIT(padno % NPADS_IN_GPP));
+       return !(readl(hostown) & BIT(padno % community->gpp_size));
 }
 
 static bool intel_pad_locked(struct intel_pinctrl *pctrl, unsigned pin)
@@ -193,7 +191,7 @@ static bool intel_pad_locked(struct intel_pinctrl *pctrl, unsigned pin)
                return false;
 
        padno = pin_to_padno(community, pin);
-       gpp = padno / NPADS_IN_GPP;
+       gpp = padno / community->gpp_size;
 
        /*
         * If PADCFGLOCK and PADCFGLOCKTX bits are both clear for this pad,
@@ -202,12 +200,12 @@ static bool intel_pad_locked(struct intel_pinctrl *pctrl, unsigned pin)
         */
        offset = community->padcfglock_offset + gpp * 8;
        value = readl(community->regs + offset);
-       if (value & BIT(pin % NPADS_IN_GPP))
+       if (value & BIT(pin % community->gpp_size))
                return true;
 
        offset = community->padcfglock_offset + 4 + gpp * 8;
        value = readl(community->regs + offset);
-       if (value & BIT(pin % NPADS_IN_GPP))
+       if (value & BIT(pin % community->gpp_size))
                return true;
 
        return false;
@@ -663,8 +661,8 @@ static void intel_gpio_irq_ack(struct irq_data *d)
        community = intel_get_community(pctrl, pin);
        if (community) {
                unsigned padno = pin_to_padno(community, pin);
-               unsigned gpp_offset = padno % NPADS_IN_GPP;
-               unsigned gpp = padno / NPADS_IN_GPP;
+               unsigned gpp_offset = padno % community->gpp_size;
+               unsigned gpp = padno / community->gpp_size;
 
                writel(BIT(gpp_offset), community->regs + GPI_IS + gpp * 4);
        }
@@ -685,8 +683,8 @@ static void intel_gpio_irq_mask_unmask(struct irq_data *d, bool mask)
        community = intel_get_community(pctrl, pin);
        if (community) {
                unsigned padno = pin_to_padno(community, pin);
-               unsigned gpp_offset = padno % NPADS_IN_GPP;
-               unsigned gpp = padno / NPADS_IN_GPP;
+               unsigned gpp_offset = padno % community->gpp_size;
+               unsigned gpp = padno / community->gpp_size;
                void __iomem *reg;
                u32 value;
 
@@ -780,8 +778,8 @@ static int intel_gpio_irq_wake(struct irq_data *d, unsigned int on)
                return -EINVAL;
 
        padno = pin_to_padno(community, pin);
-       gpp = padno / NPADS_IN_GPP;
-       gpp_offset = padno % NPADS_IN_GPP;
+       gpp = padno / community->gpp_size;
+       gpp_offset = padno % community->gpp_size;
 
        /* Clear the existing wake status */
        writel(BIT(gpp_offset), community->regs + GPI_GPE_STS + gpp * 4);
@@ -819,14 +817,14 @@ static irqreturn_t intel_gpio_community_irq_handler(struct intel_pinctrl *pctrl,
                /* Only interrupts that are enabled */
                pending &= enabled;
 
-               for_each_set_bit(gpp_offset, &pending, NPADS_IN_GPP) {
+               for_each_set_bit(gpp_offset, &pending, community->gpp_size) {
                        unsigned padno, irq;
 
                        /*
                         * The last group in community can have less pins
                         * than NPADS_IN_GPP.
                         */
-                       padno = gpp_offset + gpp * NPADS_IN_GPP;
+                       padno = gpp_offset + gpp * community->gpp_size;
                        if (padno >= community->npins)
                                break;
 
@@ -1002,7 +1000,8 @@ int intel_pinctrl_probe(struct platform_device *pdev,
 
                community->regs = regs;
                community->pad_regs = regs + padbar;
-               community->ngpps = DIV_ROUND_UP(community->npins, NPADS_IN_GPP);
+               community->ngpps = DIV_ROUND_UP(community->npins,
+                                               community->gpp_size);
        }
 
        irq = platform_get_irq(pdev, 0);
index 4ec8b572a288fbc337f5b40affdfbd012634a028..b60215793017bb95b42d39692020aa2f4c41ac0d 100644 (file)
@@ -55,6 +55,8 @@ struct intel_function {
  *                  ACPI).
  * @ie_offset: Register offset of GPI_IE from @regs.
  * @pin_base: Starting pin of pins in this community
+ * @gpp_size: Maximum number of pads in each group, such as PADCFGLOCK,
+ *            HOSTSW_OWN,  GPI_IS, GPI_IE, etc.
  * @npins: Number of pins in this community
  * @regs: Community specific common registers (reserved for core driver)
  * @pad_regs: Community specific pad registers (reserved for core driver)
@@ -68,6 +70,7 @@ struct intel_community {
        unsigned hostown_offset;
        unsigned ie_offset;
        unsigned pin_base;
+       unsigned gpp_size;
        size_t npins;
        void __iomem *regs;
        void __iomem *pad_regs;
index 1de9ae5010db285b53c01d7e67dec2bde7ce5233..c725a5313b4e692df92630535237e4b8374658a7 100644 (file)
@@ -30,6 +30,7 @@
                .padcfglock_offset = SPT_PADCFGLOCK,    \
                .hostown_offset = SPT_HOSTSW_OWN,       \
                .ie_offset = SPT_GPI_IE,                \
+               .gpp_size = 24,                         \
                .pin_base = (s),                        \
                .npins = ((e) - (s) + 1),               \
        }
index f307f1d27d646fcd3954a9d497528fffbf16dc2b..5c717275a7fa805f370cdd68815e64f8982b142b 100644 (file)
@@ -747,7 +747,7 @@ static int mtk_gpio_get_direction(struct gpio_chip *chip, unsigned offset)
        reg_addr =  mtk_get_port(pctl, offset) + pctl->devdata->dir_offset;
        bit = BIT(offset & 0xf);
        regmap_read(pctl->regmap1, reg_addr, &read_val);
-       return !!(read_val & bit);
+       return !(read_val & bit);
 }
 
 static int mtk_gpio_get(struct gpio_chip *chip, unsigned offset)
@@ -757,12 +757,8 @@ static int mtk_gpio_get(struct gpio_chip *chip, unsigned offset)
        unsigned int read_val = 0;
        struct mtk_pinctrl *pctl = dev_get_drvdata(chip->dev);
 
-       if (mtk_gpio_get_direction(chip, offset))
-               reg_addr = mtk_get_port(pctl, offset) +
-                       pctl->devdata->dout_offset;
-       else
-               reg_addr = mtk_get_port(pctl, offset) +
-                       pctl->devdata->din_offset;
+       reg_addr = mtk_get_port(pctl, offset) +
+               pctl->devdata->din_offset;
 
        bit = BIT(offset & 0xf);
        regmap_read(pctl->regmap1, reg_addr, &read_val);
@@ -997,6 +993,7 @@ static struct gpio_chip mtk_gpio_chip = {
        .owner                  = THIS_MODULE,
        .request                = gpiochip_generic_request,
        .free                   = gpiochip_generic_free,
+       .get_direction          = mtk_gpio_get_direction,
        .direction_input        = mtk_gpio_direction_input,
        .direction_output       = mtk_gpio_direction_output,
        .get                    = mtk_gpio_get,
index d809c9eaa3231817512bdda858ad208d0f1138e4..19a3c3bc2f1f7213d31ea8f23ef56b815031a3a0 100644 (file)
@@ -672,7 +672,7 @@ static int pm8xxx_gpio_probe(struct platform_device *pdev)
                return -ENOMEM;
 
        pctrl->dev = &pdev->dev;
-       pctrl->npins = (unsigned)of_device_get_match_data(&pdev->dev);
+       pctrl->npins = (unsigned long)of_device_get_match_data(&pdev->dev);
 
        pctrl->regmap = dev_get_regmap(pdev->dev.parent, NULL);
        if (!pctrl->regmap) {
index 8982027de8e8b528f026f38d58ccdf692901635c..b868ef1766a0910e50dbfe43b80e650cea19739f 100644 (file)
@@ -763,7 +763,7 @@ static int pm8xxx_mpp_probe(struct platform_device *pdev)
                return -ENOMEM;
 
        pctrl->dev = &pdev->dev;
-       pctrl->npins = (unsigned)of_device_get_match_data(&pdev->dev);
+       pctrl->npins = (unsigned long)of_device_get_match_data(&pdev->dev);
 
        pctrl->regmap = dev_get_regmap(pdev->dev.parent, NULL);
        if (!pctrl->regmap) {
index e7deb51de7dc4fd4c76bc1b7483ac2127e1da850..9842bb1067969701a8879b3de481f3da6d2349a7 100644 (file)
        PORT_GP_12(5, fn, sfx)
 
 #undef _GP_DATA
-#define _GP_DATA(bank, pin, name, sfx)                                 \
+#define _GP_DATA(bank, pin, name, sfx, cfg)                            \
        PINMUX_DATA(name##_DATA, name##_FN, name##_IN, name##_OUT)
 
-#define _GP_INOUTSEL(bank, pin, name, sfx)     name##_IN, name##_OUT
-#define _GP_INDT(bank, pin, name, sfx)         name##_DATA
+#define _GP_INOUTSEL(bank, pin, name, sfx, cfg)        name##_IN, name##_OUT
+#define _GP_INDT(bank, pin, name, sfx, cfg)    name##_DATA
 #define GP_INOUTSEL(bank)      PORT_GP_32_REV(bank, _GP_INOUTSEL, unused)
 #define GP_INDT(bank)          PORT_GP_32_REV(bank, _GP_INDT, unused)
 
index cc97f0869791d371c85f7e21c0ca04e1e595ac23..48747c28a43d4ac2fc1bed10f29cd1224ddd10f0 100644 (file)
@@ -1341,10 +1341,13 @@ static int rapl_detect_domains(struct rapl_package *rp, int cpu)
 
        for (rd = rp->domains; rd < rp->domains + rp->nr_domains; rd++) {
                /* check if the domain is locked by BIOS */
-               if (rapl_read_data_raw(rd, FW_LOCK, false, &locked)) {
+               ret = rapl_read_data_raw(rd, FW_LOCK, false, &locked);
+               if (ret)
+                       return ret;
+               if (locked) {
                        pr_info("RAPL package %d domain %s locked by BIOS\n",
                                rp->id, rd->name);
-                               rd->state |= DOMAIN_STATE_BIOS_LOCKED;
+                       rd->state |= DOMAIN_STATE_BIOS_LOCKED;
                }
        }
 
index 8b3130f22b42b334ff0d22718e46484012fb2c2b..9e03d158f4119133f09b0979d8b5b70e1ae63c06 100644 (file)
@@ -1478,6 +1478,8 @@ module_init(remoteproc_init);
 
 static void __exit remoteproc_exit(void)
 {
+       ida_destroy(&rproc_dev_index);
+
        rproc_exit_debugfs();
 }
 module_exit(remoteproc_exit);
index 9d30809bb407174214e1be674b323b0dd88c0a8e..916af5096f57b93b7f7e148d28716329b31c7be6 100644 (file)
@@ -156,7 +156,7 @@ rproc_recovery_write(struct file *filp, const char __user *user_buf,
        char buf[10];
        int ret;
 
-       if (count > sizeof(buf))
+       if (count < 1 || count > sizeof(buf))
                return count;
 
        ret = copy_from_user(buf, user_buf, count);
index 284b587da65c5fb20f6e96b8c843e52c0b420415..d6c853bbfa9fcbe0fee8968dda872041c6c8545a 100644 (file)
@@ -483,24 +483,23 @@ static int da9063_rtc_probe(struct platform_device *pdev)
 
        platform_set_drvdata(pdev, rtc);
 
+       rtc->rtc_dev = devm_rtc_device_register(&pdev->dev, DA9063_DRVNAME_RTC,
+                                          &da9063_rtc_ops, THIS_MODULE);
+       if (IS_ERR(rtc->rtc_dev))
+               return PTR_ERR(rtc->rtc_dev);
+
+       da9063_data_to_tm(data, &rtc->alarm_time, rtc);
+       rtc->rtc_sync = false;
+
        irq_alarm = platform_get_irq_byname(pdev, "ALARM");
        ret = devm_request_threaded_irq(&pdev->dev, irq_alarm, NULL,
                                        da9063_alarm_event,
                                        IRQF_TRIGGER_LOW | IRQF_ONESHOT,
                                        "ALARM", rtc);
-       if (ret) {
+       if (ret)
                dev_err(&pdev->dev, "Failed to request ALARM IRQ %d: %d\n",
                        irq_alarm, ret);
-               return ret;
-       }
-
-       rtc->rtc_dev = devm_rtc_device_register(&pdev->dev, DA9063_DRVNAME_RTC,
-                                          &da9063_rtc_ops, THIS_MODULE);
-       if (IS_ERR(rtc->rtc_dev))
-               return PTR_ERR(rtc->rtc_dev);
 
-       da9063_data_to_tm(data, &rtc->alarm_time, rtc);
-       rtc->rtc_sync = false;
        return ret;
 }
 
index 188006c55ce0708771709199b183aff93c16c3b1..aa705bb4748c08ac302d45775ef698cf26c69d5b 100644 (file)
@@ -15,9 +15,6 @@
 #include <linux/i2c.h>
 #include <linux/init.h>
 #include <linux/module.h>
-#include <linux/of_device.h>
-#include <linux/of_irq.h>
-#include <linux/pm_wakeirq.h>
 #include <linux/rtc/ds1307.h>
 #include <linux/rtc.h>
 #include <linux/slab.h>
@@ -117,7 +114,6 @@ struct ds1307 {
 #define HAS_ALARM      1               /* bit 1 == irq claimed */
        struct i2c_client       *client;
        struct rtc_device       *rtc;
-       int                     wakeirq;
        s32 (*read_block_data)(const struct i2c_client *client, u8 command,
                               u8 length, u8 *values);
        s32 (*write_block_data)(const struct i2c_client *client, u8 command,
@@ -1138,7 +1134,10 @@ read_rtc:
                                bin2bcd(tmp));
        }
 
-       device_set_wakeup_capable(&client->dev, want_irq);
+       if (want_irq) {
+               device_set_wakeup_capable(&client->dev, true);
+               set_bit(HAS_ALARM, &ds1307->flags);
+       }
        ds1307->rtc = devm_rtc_device_register(&client->dev, client->name,
                                rtc_ops, THIS_MODULE);
        if (IS_ERR(ds1307->rtc)) {
@@ -1146,43 +1145,19 @@ read_rtc:
        }
 
        if (want_irq) {
-               struct device_node *node = client->dev.of_node;
-
                err = devm_request_threaded_irq(&client->dev,
                                                client->irq, NULL, irq_handler,
                                                IRQF_SHARED | IRQF_ONESHOT,
                                                ds1307->rtc->name, client);
                if (err) {
                        client->irq = 0;
+                       device_set_wakeup_capable(&client->dev, false);
+                       clear_bit(HAS_ALARM, &ds1307->flags);
                        dev_err(&client->dev, "unable to request IRQ!\n");
-                       goto no_irq;
-               }
-
-               set_bit(HAS_ALARM, &ds1307->flags);
-               dev_dbg(&client->dev, "got IRQ %d\n", client->irq);
-
-               /* Currently supported by OF code only! */
-               if (!node)
-                       goto no_irq;
-
-               err = of_irq_get(node, 1);
-               if (err <= 0) {
-                       if (err == -EPROBE_DEFER)
-                               goto exit;
-                       goto no_irq;
-               }
-               ds1307->wakeirq = err;
-
-               err = dev_pm_set_dedicated_wake_irq(&client->dev,
-                                                   ds1307->wakeirq);
-               if (err) {
-                       dev_err(&client->dev, "unable to setup wakeIRQ %d!\n",
-                               err);
-                       goto exit;
-               }
+               } else
+                       dev_dbg(&client->dev, "got IRQ %d\n", client->irq);
        }
 
-no_irq:
        if (chip->nvram_size) {
 
                ds1307->nvram = devm_kzalloc(&client->dev,
@@ -1226,9 +1201,6 @@ static int ds1307_remove(struct i2c_client *client)
 {
        struct ds1307 *ds1307 = i2c_get_clientdata(client);
 
-       if (ds1307->wakeirq)
-               dev_pm_clear_wake_irq(&client->dev);
-
        if (test_and_clear_bit(HAS_NVRAM, &ds1307->flags))
                sysfs_remove_bin_file(&client->dev.kobj, ds1307->nvram);
 
index 91ca0bc1b484b4af1120b3e1701a931a4e1ff6fc..35c9aada07c8ef3a19f44cf8d4a3e8811f484e3f 100644 (file)
@@ -56,6 +56,42 @@ struct rk808_rtc {
        int irq;
 };
 
+/*
+ * The Rockchip calendar used by the RK808 counts November with 31 days. We use
+ * these translation functions to convert its dates to/from the Gregorian
+ * calendar used by the rest of the world. We arbitrarily define Jan 1st, 2016
+ * as the day when both calendars were in sync, and treat all other dates
+ * relative to that.
+ * NOTE: Other system software (e.g. firmware) that reads the same hardware must
+ * implement this exact same conversion algorithm, with the same anchor date.
+ */
+static time64_t nov2dec_transitions(struct rtc_time *tm)
+{
+       return (tm->tm_year + 1900) - 2016 + (tm->tm_mon + 1 > 11 ? 1 : 0);
+}
+
+static void rockchip_to_gregorian(struct rtc_time *tm)
+{
+       /* If it's Nov 31st, rtc_tm_to_time64() will count that like Dec 1st */
+       time64_t time = rtc_tm_to_time64(tm);
+       rtc_time64_to_tm(time + nov2dec_transitions(tm) * 86400, tm);
+}
+
+static void gregorian_to_rockchip(struct rtc_time *tm)
+{
+       time64_t extra_days = nov2dec_transitions(tm);
+       time64_t time = rtc_tm_to_time64(tm);
+       rtc_time64_to_tm(time - extra_days * 86400, tm);
+
+       /* Compensate if we went back over Nov 31st (will work up to 2381) */
+       if (nov2dec_transitions(tm) < extra_days) {
+               if (tm->tm_mon + 1 == 11)
+                       tm->tm_mday++;  /* This may result in 31! */
+               else
+                       rtc_time64_to_tm(time - (extra_days - 1) * 86400, tm);
+       }
+}
+
 /* Read current time and date in RTC */
 static int rk808_rtc_readtime(struct device *dev, struct rtc_time *tm)
 {
@@ -101,9 +137,10 @@ static int rk808_rtc_readtime(struct device *dev, struct rtc_time *tm)
        tm->tm_mon = (bcd2bin(rtc_data[4] & MONTHS_REG_MSK)) - 1;
        tm->tm_year = (bcd2bin(rtc_data[5] & YEARS_REG_MSK)) + 100;
        tm->tm_wday = bcd2bin(rtc_data[6] & WEEKS_REG_MSK);
+       rockchip_to_gregorian(tm);
        dev_dbg(dev, "RTC date/time %4d-%02d-%02d(%d) %02d:%02d:%02d\n",
                1900 + tm->tm_year, tm->tm_mon + 1, tm->tm_mday,
-               tm->tm_wday, tm->tm_hour , tm->tm_min, tm->tm_sec);
+               tm->tm_wday, tm->tm_hour, tm->tm_min, tm->tm_sec);
 
        return ret;
 }
@@ -116,6 +153,10 @@ static int rk808_rtc_set_time(struct device *dev, struct rtc_time *tm)
        u8 rtc_data[NUM_TIME_REGS];
        int ret;
 
+       dev_dbg(dev, "set RTC date/time %4d-%02d-%02d(%d) %02d:%02d:%02d\n",
+               1900 + tm->tm_year, tm->tm_mon + 1, tm->tm_mday,
+               tm->tm_wday, tm->tm_hour, tm->tm_min, tm->tm_sec);
+       gregorian_to_rockchip(tm);
        rtc_data[0] = bin2bcd(tm->tm_sec);
        rtc_data[1] = bin2bcd(tm->tm_min);
        rtc_data[2] = bin2bcd(tm->tm_hour);
@@ -123,9 +164,6 @@ static int rk808_rtc_set_time(struct device *dev, struct rtc_time *tm)
        rtc_data[4] = bin2bcd(tm->tm_mon + 1);
        rtc_data[5] = bin2bcd(tm->tm_year - 100);
        rtc_data[6] = bin2bcd(tm->tm_wday);
-       dev_dbg(dev, "set RTC date/time %4d-%02d-%02d(%d) %02d:%02d:%02d\n",
-               1900 + tm->tm_year, tm->tm_mon + 1, tm->tm_mday,
-               tm->tm_wday, tm->tm_hour , tm->tm_min, tm->tm_sec);
 
        /* Stop RTC while updating the RTC registers */
        ret = regmap_update_bits(rk808->regmap, RK808_RTC_CTRL_REG,
@@ -170,6 +208,7 @@ static int rk808_rtc_readalarm(struct device *dev, struct rtc_wkalrm *alrm)
        alrm->time.tm_mday = bcd2bin(alrm_data[3] & DAYS_REG_MSK);
        alrm->time.tm_mon = (bcd2bin(alrm_data[4] & MONTHS_REG_MSK)) - 1;
        alrm->time.tm_year = (bcd2bin(alrm_data[5] & YEARS_REG_MSK)) + 100;
+       rockchip_to_gregorian(&alrm->time);
 
        ret = regmap_read(rk808->regmap, RK808_RTC_INT_REG, &int_reg);
        if (ret) {
@@ -227,6 +266,7 @@ static int rk808_rtc_setalarm(struct device *dev, struct rtc_wkalrm *alrm)
                alrm->time.tm_mday, alrm->time.tm_wday, alrm->time.tm_hour,
                alrm->time.tm_min, alrm->time.tm_sec);
 
+       gregorian_to_rockchip(&alrm->time);
        alrm_data[0] = bin2bcd(alrm->time.tm_sec);
        alrm_data[1] = bin2bcd(alrm->time.tm_min);
        alrm_data[2] = bin2bcd(alrm->time.tm_hour);
index 548a18916a31ec11f5abf0fae9c3626755422d46..a831d18596a5ef592f88ec5af031f639606c8c0b 100644 (file)
@@ -1080,28 +1080,10 @@ void __init chsc_init_cleanup(void)
        free_page((unsigned long)sei_page);
 }
 
-int chsc_enable_facility(int operation_code)
+int __chsc_enable_facility(struct chsc_sda_area *sda_area, int operation_code)
 {
-       unsigned long flags;
        int ret;
-       struct {
-               struct chsc_header request;
-               u8 reserved1:4;
-               u8 format:4;
-               u8 reserved2;
-               u16 operation_code;
-               u32 reserved3;
-               u32 reserved4;
-               u32 operation_data_area[252];
-               struct chsc_header response;
-               u32 reserved5:4;
-               u32 format2:4;
-               u32 reserved6:24;
-       } __attribute__ ((packed)) *sda_area;
 
-       spin_lock_irqsave(&chsc_page_lock, flags);
-       memset(chsc_page, 0, PAGE_SIZE);
-       sda_area = chsc_page;
        sda_area->request.length = 0x0400;
        sda_area->request.code = 0x0031;
        sda_area->operation_code = operation_code;
@@ -1119,10 +1101,25 @@ int chsc_enable_facility(int operation_code)
        default:
                ret = chsc_error_from_response(sda_area->response.code);
        }
+out:
+       return ret;
+}
+
+int chsc_enable_facility(int operation_code)
+{
+       struct chsc_sda_area *sda_area;
+       unsigned long flags;
+       int ret;
+
+       spin_lock_irqsave(&chsc_page_lock, flags);
+       memset(chsc_page, 0, PAGE_SIZE);
+       sda_area = chsc_page;
+
+       ret = __chsc_enable_facility(sda_area, operation_code);
        if (ret != 0)
                CIO_CRW_EVENT(2, "chsc: sda (oc=%x) failed (rc=%04x)\n",
                              operation_code, sda_area->response.code);
-out:
+
        spin_unlock_irqrestore(&chsc_page_lock, flags);
        return ret;
 }
index 76c9b50700b24975842713560b4d4fce2e9ddba6..0de134c3a2044be8956a31fa01c142d581e3a792 100644 (file)
@@ -115,6 +115,20 @@ struct chsc_scpd {
        u8 data[PAGE_SIZE - 20];
 } __attribute__ ((packed));
 
+struct chsc_sda_area {
+       struct chsc_header request;
+       u8 :4;
+       u8 format:4;
+       u8 :8;
+       u16 operation_code;
+       u32 :32;
+       u32 :32;
+       u32 operation_data_area[252];
+       struct chsc_header response;
+       u32 :4;
+       u32 format2:4;
+       u32 :24;
+} __packed __aligned(PAGE_SIZE);
 
 extern int chsc_get_ssd_info(struct subchannel_id schid,
                             struct chsc_ssd_info *ssd);
@@ -122,6 +136,7 @@ extern int chsc_determine_css_characteristics(void);
 extern int chsc_init(void);
 extern void chsc_init_cleanup(void);
 
+int __chsc_enable_facility(struct chsc_sda_area *sda_area, int operation_code);
 extern int chsc_enable_facility(int);
 struct channel_subsystem;
 extern int chsc_secm(struct channel_subsystem *, int);
index b5620e818d6b91307c329cfe67f2de5ac4847ca5..690b8547e828deb81d94a2646459d2babc79dc24 100644 (file)
@@ -925,18 +925,32 @@ void reipl_ccw_dev(struct ccw_dev_id *devid)
 
 int __init cio_get_iplinfo(struct cio_iplinfo *iplinfo)
 {
+       static struct chsc_sda_area sda_area __initdata;
        struct subchannel_id schid;
        struct schib schib;
 
        schid = *(struct subchannel_id *)&S390_lowcore.subchannel_id;
        if (!schid.one)
                return -ENODEV;
+
+       if (schid.ssid) {
+               /*
+                * Firmware should have already enabled MSS but whoever started
+                * the kernel might have initiated a channel subsystem reset.
+                * Ensure that MSS is enabled.
+                */
+               memset(&sda_area, 0, sizeof(sda_area));
+               if (__chsc_enable_facility(&sda_area, CHSC_SDA_OC_MSS))
+                       return -ENODEV;
+       }
        if (stsch_err(schid, &schib))
                return -ENODEV;
        if (schib.pmcw.st != SUBCHANNEL_TYPE_IO)
                return -ENODEV;
        if (!schib.pmcw.dnv)
                return -ENODEV;
+
+       iplinfo->ssid = schid.ssid;
        iplinfo->devno = schib.pmcw.dev;
        iplinfo->is_qdio = schib.pmcw.qf;
        return 0;
index 2ee3053bdc124319abf79a91f3ba07eb66835524..489e703dc82d85b49d33990bd3d5c2b687d9eb0f 100644 (file)
@@ -702,17 +702,12 @@ css_generate_pgid(struct channel_subsystem *css, u32 tod_high)
                css->global_pgid.pgid_high.ext_cssid.version = 0x80;
                css->global_pgid.pgid_high.ext_cssid.cssid = css->cssid;
        } else {
-#ifdef CONFIG_SMP
                css->global_pgid.pgid_high.cpu_addr = stap();
-#else
-               css->global_pgid.pgid_high.cpu_addr = 0;
-#endif
        }
        get_cpu_id(&cpu_id);
        css->global_pgid.cpu_id = cpu_id.ident;
        css->global_pgid.cpu_model = cpu_id.machine;
        css->global_pgid.tod_high = tod_high;
-
 }
 
 static void
index 57f710b3c8a42862357d65653494f72d89580b32..b8ab18676e69a39d2077fa3b5ff7c192ed3d3fe9 100644 (file)
@@ -3,6 +3,9 @@
 #
 
 ap-objs := ap_bus.o
-obj-$(CONFIG_ZCRYPT) += ap.o zcrypt_api.o zcrypt_pcixcc.o
-obj-$(CONFIG_ZCRYPT) += zcrypt_cex2a.o zcrypt_cex4.o
+# zcrypt_api depends on ap
+obj-$(CONFIG_ZCRYPT) += ap.o zcrypt_api.o
+# msgtype* depend on zcrypt_api
 obj-$(CONFIG_ZCRYPT) += zcrypt_msgtype6.o zcrypt_msgtype50.o
+# adapter drivers depend on ap, zcrypt_api and msgtype*
+obj-$(CONFIG_ZCRYPT) += zcrypt_pcixcc.o zcrypt_cex2a.o zcrypt_cex4.o
index 9cb3dfbcaddbc491f537fc431471a16a98f50b69..24ec282e15d8ae436e7dab130a4696708e34be9e 100644 (file)
@@ -74,6 +74,7 @@ static struct device *ap_root_device = NULL;
 static struct ap_config_info *ap_configuration;
 static DEFINE_SPINLOCK(ap_device_list_lock);
 static LIST_HEAD(ap_device_list);
+static bool initialised;
 
 /*
  * Workqueue timer for bus rescan.
@@ -598,8 +599,10 @@ static enum ap_wait ap_sm_read(struct ap_device *ap_dev)
        status = ap_sm_recv(ap_dev);
        switch (status.response_code) {
        case AP_RESPONSE_NORMAL:
-               if (ap_dev->queue_count > 0)
+               if (ap_dev->queue_count > 0) {
+                       ap_dev->state = AP_STATE_WORKING;
                        return AP_WAIT_AGAIN;
+               }
                ap_dev->state = AP_STATE_IDLE;
                return AP_WAIT_NONE;
        case AP_RESPONSE_NO_PENDING_REPLY:
@@ -1384,6 +1387,9 @@ int ap_driver_register(struct ap_driver *ap_drv, struct module *owner,
 {
        struct device_driver *drv = &ap_drv->driver;
 
+       if (!initialised)
+               return -ENODEV;
+
        drv->bus = &ap_bus_type;
        drv->probe = ap_device_probe;
        drv->remove = ap_device_remove;
@@ -1808,6 +1814,7 @@ int __init ap_module_init(void)
                goto out_pm;
 
        queue_work(system_long_wq, &ap_scan_work);
+       initialised = true;
 
        return 0;
 
@@ -1837,6 +1844,7 @@ void ap_module_exit(void)
 {
        int i;
 
+       initialised = false;
        ap_reset_domain();
        ap_poll_thread_stop();
        del_timer_sync(&ap_config_timer);
index a9603ebbc1f8fdd6ca03eb9b4702d356648157b4..9f8fa42c062c22f59681f2e18026214d39a2b7c0 100644 (file)
@@ -317,11 +317,9 @@ EXPORT_SYMBOL(zcrypt_device_unregister);
 
 void zcrypt_msgtype_register(struct zcrypt_ops *zops)
 {
-       if (zops->owner) {
-               spin_lock_bh(&zcrypt_ops_list_lock);
-               list_add_tail(&zops->list, &zcrypt_ops_list);
-               spin_unlock_bh(&zcrypt_ops_list_lock);
-       }
+       spin_lock_bh(&zcrypt_ops_list_lock);
+       list_add_tail(&zops->list, &zcrypt_ops_list);
+       spin_unlock_bh(&zcrypt_ops_list_lock);
 }
 EXPORT_SYMBOL(zcrypt_msgtype_register);
 
@@ -342,7 +340,7 @@ struct zcrypt_ops *__ops_lookup(unsigned char *name, int variant)
        spin_lock_bh(&zcrypt_ops_list_lock);
        list_for_each_entry(zops, &zcrypt_ops_list, list) {
                if ((zops->variant == variant) &&
-                   (!strncmp(zops->owner->name, name, MODULE_NAME_LEN))) {
+                   (!strncmp(zops->name, name, sizeof(zops->name)))) {
                        found = 1;
                        break;
                }
index 750876891931627641131a59dfd58df2c4e8f8ce..38618f05ad924c340d324500d9d3b887798c7cd8 100644 (file)
@@ -96,6 +96,7 @@ struct zcrypt_ops {
        struct list_head list;          /* zcrypt ops list. */
        struct module *owner;
        int variant;
+       char name[128];
 };
 
 struct zcrypt_device {
index 71ceee9137a88919d8c53ca7148afff0a7211e95..74edf2934e7c9fd652c33d1d14bb47b9e2bf44b8 100644 (file)
@@ -513,6 +513,7 @@ static struct zcrypt_ops zcrypt_msgtype50_ops = {
        .rsa_modexpo = zcrypt_cex2a_modexpo,
        .rsa_modexpo_crt = zcrypt_cex2a_modexpo_crt,
        .owner = THIS_MODULE,
+       .name = MSGTYPE50_NAME,
        .variant = MSGTYPE50_VARIANT_DEFAULT,
 };
 
index 74762214193b0326a8ee2cb6d21141f3c414123b..9a2dd472c1cc9870d37e98c5692c1c9c1e0ebac3 100644 (file)
@@ -1119,6 +1119,7 @@ static long zcrypt_msgtype6_rng(struct zcrypt_device *zdev,
  */
 static struct zcrypt_ops zcrypt_msgtype6_norng_ops = {
        .owner = THIS_MODULE,
+       .name = MSGTYPE06_NAME,
        .variant = MSGTYPE06_VARIANT_NORNG,
        .rsa_modexpo = zcrypt_msgtype6_modexpo,
        .rsa_modexpo_crt = zcrypt_msgtype6_modexpo_crt,
@@ -1127,6 +1128,7 @@ static struct zcrypt_ops zcrypt_msgtype6_norng_ops = {
 
 static struct zcrypt_ops zcrypt_msgtype6_ops = {
        .owner = THIS_MODULE,
+       .name = MSGTYPE06_NAME,
        .variant = MSGTYPE06_VARIANT_DEFAULT,
        .rsa_modexpo = zcrypt_msgtype6_modexpo,
        .rsa_modexpo_crt = zcrypt_msgtype6_modexpo_crt,
@@ -1136,6 +1138,7 @@ static struct zcrypt_ops zcrypt_msgtype6_ops = {
 
 static struct zcrypt_ops zcrypt_msgtype6_ep11_ops = {
        .owner = THIS_MODULE,
+       .name = MSGTYPE06_NAME,
        .variant = MSGTYPE06_VARIANT_EP11,
        .rsa_modexpo = NULL,
        .rsa_modexpo_crt = NULL,
index b2a1a81e6fc8f048c202b7eca54b2b0b6c22b368..1b831598df7c6544057f23ef69da5ea54bbafcdd 100644 (file)
@@ -984,6 +984,36 @@ static struct virtqueue *virtio_ccw_vq_by_ind(struct virtio_ccw_device *vcdev,
        return vq;
 }
 
+static void virtio_ccw_check_activity(struct virtio_ccw_device *vcdev,
+                                     __u32 activity)
+{
+       if (vcdev->curr_io & activity) {
+               switch (activity) {
+               case VIRTIO_CCW_DOING_READ_FEAT:
+               case VIRTIO_CCW_DOING_WRITE_FEAT:
+               case VIRTIO_CCW_DOING_READ_CONFIG:
+               case VIRTIO_CCW_DOING_WRITE_CONFIG:
+               case VIRTIO_CCW_DOING_WRITE_STATUS:
+               case VIRTIO_CCW_DOING_SET_VQ:
+               case VIRTIO_CCW_DOING_SET_IND:
+               case VIRTIO_CCW_DOING_SET_CONF_IND:
+               case VIRTIO_CCW_DOING_RESET:
+               case VIRTIO_CCW_DOING_READ_VQ_CONF:
+               case VIRTIO_CCW_DOING_SET_IND_ADAPTER:
+               case VIRTIO_CCW_DOING_SET_VIRTIO_REV:
+                       vcdev->curr_io &= ~activity;
+                       wake_up(&vcdev->wait_q);
+                       break;
+               default:
+                       /* don't know what to do... */
+                       dev_warn(&vcdev->cdev->dev,
+                                "Suspicious activity '%08x'\n", activity);
+                       WARN_ON(1);
+                       break;
+               }
+       }
+}
+
 static void virtio_ccw_int_handler(struct ccw_device *cdev,
                                   unsigned long intparm,
                                   struct irb *irb)
@@ -995,6 +1025,12 @@ static void virtio_ccw_int_handler(struct ccw_device *cdev,
 
        if (!vcdev)
                return;
+       if (IS_ERR(irb)) {
+               vcdev->err = PTR_ERR(irb);
+               virtio_ccw_check_activity(vcdev, activity);
+               /* Don't poke around indicators, something's wrong. */
+               return;
+       }
        /* Check if it's a notification from the host. */
        if ((intparm == 0) &&
            (scsw_stctl(&irb->scsw) ==
@@ -1010,31 +1046,7 @@ static void virtio_ccw_int_handler(struct ccw_device *cdev,
                        /* Map everything else to -EIO. */
                        vcdev->err = -EIO;
        }
-       if (vcdev->curr_io & activity) {
-               switch (activity) {
-               case VIRTIO_CCW_DOING_READ_FEAT:
-               case VIRTIO_CCW_DOING_WRITE_FEAT:
-               case VIRTIO_CCW_DOING_READ_CONFIG:
-               case VIRTIO_CCW_DOING_WRITE_CONFIG:
-               case VIRTIO_CCW_DOING_WRITE_STATUS:
-               case VIRTIO_CCW_DOING_SET_VQ:
-               case VIRTIO_CCW_DOING_SET_IND:
-               case VIRTIO_CCW_DOING_SET_CONF_IND:
-               case VIRTIO_CCW_DOING_RESET:
-               case VIRTIO_CCW_DOING_READ_VQ_CONF:
-               case VIRTIO_CCW_DOING_SET_IND_ADAPTER:
-               case VIRTIO_CCW_DOING_SET_VIRTIO_REV:
-                       vcdev->curr_io &= ~activity;
-                       wake_up(&vcdev->wait_q);
-                       break;
-               default:
-                       /* don't know what to do... */
-                       dev_warn(&cdev->dev, "Suspicious activity '%08x'\n",
-                                activity);
-                       WARN_ON(1);
-                       break;
-               }
-       }
+       virtio_ccw_check_activity(vcdev, activity);
        for_each_set_bit(i, &vcdev->indicators,
                         sizeof(vcdev->indicators) * BITS_PER_BYTE) {
                /* The bit clear must happen before the vring kick. */
index 5f692ae4074959e019a74eb0c81405cb2869195c..64eed87d34a87840d5da60d267383589541e1d73 100644 (file)
@@ -364,6 +364,7 @@ config SCSI_HPSA
        tristate "HP Smart Array SCSI driver"
        depends on PCI && SCSI
        select CHECK_SIGNATURE
+       select SCSI_SAS_ATTRS
        help
          This driver supports HP Smart Array Controllers (circa 2009).
          It is a SCSI alternative to the cciss driver, which is a block
@@ -499,6 +500,7 @@ config SCSI_ADVANSYS
        tristate "AdvanSys SCSI support"
        depends on SCSI
        depends on ISA || EISA || PCI
+       depends on ISA_DMA_API || !ISA
        help
          This is a driver for all SCSI host adapters manufactured by
          AdvanSys. It is documented in the kernel source in
index 519f9a4b3dadf39c07be7e61f20fc2481cddbd02..febbd83e2ecd9d6a6984500eb8cc02d6690c3984 100644 (file)
@@ -7803,7 +7803,7 @@ adv_build_req(struct asc_board *boardp, struct scsi_cmnd *scp,
                return ASC_BUSY;
        }
        scsiqp->sense_addr = cpu_to_le32(sense_addr);
-       scsiqp->sense_len = cpu_to_le32(SCSI_SENSE_BUFFERSIZE);
+       scsiqp->sense_len = SCSI_SENSE_BUFFERSIZE;
 
        /* Build ADV_SCSI_REQ_Q */
 
index 323982fd00c3ba985dfb59bf04b6eff04f86e9b7..82ac1cd818ac18e1310ba2abaede9c8b262f9976 100644 (file)
@@ -333,6 +333,17 @@ static void scsi_host_dev_release(struct device *dev)
                kfree(queuedata);
        }
 
+       if (shost->shost_state == SHOST_CREATED) {
+               /*
+                * Free the shost_dev device name here if scsi_host_alloc()
+                * and scsi_host_put() have been called but neither
+                * scsi_host_add() nor scsi_host_remove() has been called.
+                * This avoids that the memory allocated for the shost_dev
+                * name is leaked.
+                */
+               kfree(dev_name(&shost->shost_dev));
+       }
+
        scsi_destroy_command_freelist(shost);
        if (shost_use_blk_mq(shost)) {
                if (shost->tag_set.tags)
index 6a8f95808ee0f92027796651a6254e6c9382ca5a..a3860367b568aa06adf4290bf84717458c241e77 100644 (file)
@@ -8671,7 +8671,7 @@ static void hpsa_disable_rld_caching(struct ctlr_info *h)
        if ((rc != 0)  || (c->err_info->CommandStatus != 0))
                goto errout;
 
-       if (*options && HPSA_DIAG_OPTS_DISABLE_RLD_CACHING)
+       if (*options & HPSA_DIAG_OPTS_DISABLE_RLD_CACHING)
                goto out;
 
 errout:
index 29061467cc174e118848dd44244ff28bb198deb3..b736dbc8048530e6c2c8dae2a8f7e1aac896ce10 100644 (file)
@@ -71,3 +71,12 @@ config SCSI_MPT3SAS_MAX_SGE
        MAX_PHYS_SEGMENTS in most kernels.  However in SuSE kernels this
        can be 256. However, it may decreased down to 16.  Decreasing this
        parameter will reduce memory requirements on a per controller instance.
+
+config SCSI_MPT2SAS
+       tristate "Legacy MPT2SAS config option"
+       default n
+       select SCSI_MPT3SAS
+       depends on PCI && SCSI
+       ---help---
+       Dummy config option for backwards compatiblity: configure the MPT3SAS
+       driver instead.
index d95206b7e1167861531d2cd29c9ef27e7da82c25..9ab77b06434d19a61a92bb771aef0e70da0f31d8 100644 (file)
@@ -3905,8 +3905,7 @@ scsih_qcmd(struct Scsi_Host *shost, struct scsi_cmnd *scmd)
         * We do not expose raid functionality to upper layer for warpdrive.
         */
        if (!ioc->is_warpdrive && !scsih_is_raid(&scmd->device->sdev_gendev)
-           && (sas_device_priv_data->flags & MPT_DEVICE_TLR_ON) &&
-           scmd->cmd_len != 32)
+           && sas_is_tlr_enabled(scmd->device) && scmd->cmd_len != 32)
                mpi_control |= MPI2_SCSIIO_CONTROL_TLR_ON;
 
        smid = mpt3sas_base_get_smid_scsiio(ioc, ioc->scsi_io_cb_idx, scmd);
index 90fdf0e859e31fd9e72352d2ed19a889061e6ed4..675e7fab0796e4c1ebfc3e7e77aa109592a25c02 100644 (file)
@@ -758,7 +758,7 @@ mvs_store_interrupt_coalescing(struct device *cdev,
                        struct device_attribute *attr,
                        const char *buffer, size_t size)
 {
-       int val = 0;
+       unsigned int val = 0;
        struct mvs_info *mvi = NULL;
        struct Scsi_Host *shost = class_to_shost(cdev);
        struct sas_ha_struct *sha = SHOST_TO_SAS_HA(shost);
@@ -766,7 +766,7 @@ mvs_store_interrupt_coalescing(struct device *cdev,
        if (buffer == NULL)
                return size;
 
-       if (sscanf(buffer, "%d", &val) != 1)
+       if (sscanf(buffer, "%u", &val) != 1)
                return -EINVAL;
 
        if (val >= 0x10000) {
index eb0cc5475c451860d56c6f74679ce026f3808710..b6b4cfdd76201d76f26ca4a99c60aa49ec6b4c69 100644 (file)
@@ -433,7 +433,7 @@ qla82xx_pci_get_crb_addr_2M(struct qla_hw_data *ha, ulong off_in,
        if (off_in < QLA82XX_PCI_CRBSPACE)
                return -1;
 
-       *off_out = (void __iomem *)(off_in - QLA82XX_PCI_CRBSPACE);
+       off_in -= QLA82XX_PCI_CRBSPACE;
 
        /* Try direct map */
        m = &crb_128M_2M_map[CRB_BLK(off_in)].sub_block[CRB_SUBBLK(off_in)];
@@ -443,6 +443,7 @@ qla82xx_pci_get_crb_addr_2M(struct qla_hw_data *ha, ulong off_in,
                return 0;
        }
        /* Not in direct map, use crb window */
+       *off_out = (void __iomem *)off_in;
        return 1;
 }
 
index 3ba2e9564b9a78f000c234fa1be7bb05e24eaebd..81af294f15a7d4deb557b162dc51ca676df9618a 100644 (file)
@@ -902,7 +902,7 @@ static ssize_t tcm_qla2xxx_tpg_fabric_prot_type_show(struct config_item *item,
        return sprintf(page, "%d\n", tpg->tpg_attrib.fabric_prot_type);
 }
 
-CONFIGFS_ATTR_WO(tcm_qla2xxx_tpg_, enable);
+CONFIGFS_ATTR(tcm_qla2xxx_tpg_, enable);
 CONFIGFS_ATTR_RO(tcm_qla2xxx_tpg_, dynamic_sessions);
 CONFIGFS_ATTR(tcm_qla2xxx_tpg_, fabric_prot_type);
 
index dfcc45bb03b1f30e808e611a567c2f76cc734d3c..d09d60293c272663b5b9b84f27ce2fab3e61a6aa 100644 (file)
@@ -465,8 +465,9 @@ static const struct opcode_info_t opcode_info_arr[SDEB_I_LAST_ELEMENT + 1] = {
             0} },
        {0, 0, 0, F_INV_OP | FF_RESPOND, NULL, NULL, /* MAINT OUT */
            {0,  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
-       {0, 0, 0, F_INV_OP | FF_RESPOND, NULL, NULL, /* VERIFY */
-           {0,  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
+       {0, 0x2f, 0, F_D_OUT_MAYBE | FF_DIRECT_IO, NULL, NULL, /* VERIFY(10) */
+           {10,  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc7,
+            0, 0, 0, 0, 0, 0} },
        {1, 0x7f, 0x9, F_SA_HIGH | F_D_IN | FF_DIRECT_IO, resp_read_dt0,
            vl_iarr, {32,  0xc7, 0, 0, 0, 0, 0x1f, 0x18, 0x0, 0x9, 0xfe, 0,
                      0xff, 0xff, 0xff, 0xff} },/* VARIABLE LENGTH, READ(32) */
@@ -477,8 +478,8 @@ static const struct opcode_info_t opcode_info_arr[SDEB_I_LAST_ELEMENT + 1] = {
            {10,  0x13, 0xff, 0xff, 0, 0, 0, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0,
             0} },
 /* 20 */
-       {0, 0, 0, F_INV_OP | FF_RESPOND, NULL, NULL, /* ALLOW REMOVAL */
-           {0,  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
+       {0, 0x1e, 0, 0, NULL, NULL, /* ALLOW REMOVAL */
+           {6,  0, 0, 0, 0x3, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
        {0, 0x1, 0, 0, resp_start_stop, NULL, /* REWIND ?? */
            {6,  0x1, 0, 0, 0, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
        {0, 0, 0, F_INV_OP | FF_RESPOND, NULL, NULL, /* ATA_PT */
index e4b7998379485454d26e39f6a5a91917a155ffbb..459abe1dcc87a6dfc1beca5672dc3d59d88bdbd2 100644 (file)
@@ -219,13 +219,13 @@ static int sdev_runtime_suspend(struct device *dev)
        struct scsi_device *sdev = to_scsi_device(dev);
        int err = 0;
 
-       if (pm && pm->runtime_suspend) {
-               err = blk_pre_runtime_suspend(sdev->request_queue);
-               if (err)
-                       return err;
+       err = blk_pre_runtime_suspend(sdev->request_queue);
+       if (err)
+               return err;
+       if (pm && pm->runtime_suspend)
                err = pm->runtime_suspend(dev);
-               blk_post_runtime_suspend(sdev->request_queue, err);
-       }
+       blk_post_runtime_suspend(sdev->request_queue, err);
+
        return err;
 }
 
@@ -248,11 +248,11 @@ static int sdev_runtime_resume(struct device *dev)
        const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL;
        int err = 0;
 
-       if (pm && pm->runtime_resume) {
-               blk_pre_runtime_resume(sdev->request_queue);
+       blk_pre_runtime_resume(sdev->request_queue);
+       if (pm && pm->runtime_resume)
                err = pm->runtime_resume(dev);
-               blk_post_runtime_resume(sdev->request_queue, err);
-       }
+       blk_post_runtime_resume(sdev->request_queue, err);
+
        return err;
 }
 
index 83245391e956bc6f351a668473debeba6121b71b..054923e3393c6f2dffd0959fea6ee610ecf177ac 100644 (file)
@@ -701,9 +701,12 @@ static int scsi_probe_lun(struct scsi_device *sdev, unsigned char *inq_result,
         * strings.
         */
        if (sdev->inquiry_len < 36) {
-               sdev_printk(KERN_INFO, sdev,
-                           "scsi scan: INQUIRY result too short (%d),"
-                           " using 36\n", sdev->inquiry_len);
+               if (!sdev->host->short_inquiry) {
+                       shost_printk(KERN_INFO, sdev->host,
+                                   "scsi scan: INQUIRY result too short (%d),"
+                                   " using 36\n", sdev->inquiry_len);
+                       sdev->host->short_inquiry = 1;
+               }
                sdev->inquiry_len = 36;
        }
 
index 8d2312239ae0cda01238ae549f0ae8007de233ea..21930c9ac9cd90caf6e5386b4495992fb3f8542d 100644 (file)
@@ -1102,6 +1102,14 @@ void __scsi_remove_device(struct scsi_device *sdev)
 {
        struct device *dev = &sdev->sdev_gendev;
 
+       /*
+        * This cleanup path is not reentrant and while it is impossible
+        * to get a new reference with scsi_device_get() someone can still
+        * hold a previously acquired one.
+        */
+       if (sdev->sdev_state == SDEV_DEL)
+               return;
+
        if (sdev->is_visible) {
                if (scsi_device_set_state(sdev, SDEV_CANCEL) != 0)
                        return;
@@ -1110,7 +1118,9 @@ void __scsi_remove_device(struct scsi_device *sdev)
                device_unregister(&sdev->sdev_dev);
                transport_remove_device(dev);
                scsi_dh_remove_device(sdev);
-       }
+               device_del(dev);
+       } else
+               put_device(&sdev->sdev_dev);
 
        /*
         * Stop accepting new requests and wait until all queuecommand() and
@@ -1121,16 +1131,6 @@ void __scsi_remove_device(struct scsi_device *sdev)
        blk_cleanup_queue(sdev->request_queue);
        cancel_work_sync(&sdev->requeue_work);
 
-       /*
-        * Remove the device after blk_cleanup_queue() has been called such
-        * a possible bdi_register() call with the same name occurs after
-        * blk_cleanup_queue() has called bdi_destroy().
-        */
-       if (sdev->is_visible)
-               device_del(dev);
-       else
-               put_device(&sdev->sdev_dev);
-
        if (sdev->host->hostt->slave_destroy)
                sdev->host->hostt->slave_destroy(sdev);
        transport_destroy_device(dev);
index 54519804c46a57b99ce680ee665b4fe28dd91148..3d22fc3e3c1a7ba6df90665f59cf10e8d38ef715 100644 (file)
@@ -638,11 +638,24 @@ static void sd_config_discard(struct scsi_disk *sdkp, unsigned int mode)
        unsigned int max_blocks = 0;
 
        q->limits.discard_zeroes_data = 0;
-       q->limits.discard_alignment = sdkp->unmap_alignment *
-               logical_block_size;
-       q->limits.discard_granularity =
-               max(sdkp->physical_block_size,
-                   sdkp->unmap_granularity * logical_block_size);
+
+       /*
+        * When LBPRZ is reported, discard alignment and granularity
+        * must be fixed to the logical block size. Otherwise the block
+        * layer will drop misaligned portions of the request which can
+        * lead to data corruption. If LBPRZ is not set, we honor the
+        * device preference.
+        */
+       if (sdkp->lbprz) {
+               q->limits.discard_alignment = 0;
+               q->limits.discard_granularity = 1;
+       } else {
+               q->limits.discard_alignment = sdkp->unmap_alignment *
+                       logical_block_size;
+               q->limits.discard_granularity =
+                       max(sdkp->physical_block_size,
+                           sdkp->unmap_granularity * logical_block_size);
+       }
 
        sdkp->provisioning_mode = mode;
 
@@ -2321,11 +2334,8 @@ got_data:
                }
        }
 
-       if (sdkp->capacity > 0xffffffff) {
+       if (sdkp->capacity > 0xffffffff)
                sdp->use_16_for_rw = 1;
-               sdkp->max_xfer_blocks = SD_MAX_XFER_BLOCKS;
-       } else
-               sdkp->max_xfer_blocks = SD_DEF_XFER_BLOCKS;
 
        /* Rescale capacity to 512-byte units */
        if (sector_size == 4096)
@@ -2642,7 +2652,6 @@ static void sd_read_block_limits(struct scsi_disk *sdkp)
 {
        unsigned int sector_sz = sdkp->device->sector_size;
        const int vpd_len = 64;
-       u32 max_xfer_length;
        unsigned char *buffer = kmalloc(vpd_len, GFP_KERNEL);
 
        if (!buffer ||
@@ -2650,14 +2659,11 @@ static void sd_read_block_limits(struct scsi_disk *sdkp)
            scsi_get_vpd_page(sdkp->device, 0xb0, buffer, vpd_len))
                goto out;
 
-       max_xfer_length = get_unaligned_be32(&buffer[8]);
-       if (max_xfer_length)
-               sdkp->max_xfer_blocks = max_xfer_length;
-
        blk_queue_io_min(sdkp->disk->queue,
                         get_unaligned_be16(&buffer[6]) * sector_sz);
-       blk_queue_io_opt(sdkp->disk->queue,
-                        get_unaligned_be32(&buffer[12]) * sector_sz);
+
+       sdkp->max_xfer_blocks = get_unaligned_be32(&buffer[8]);
+       sdkp->opt_xfer_blocks = get_unaligned_be32(&buffer[12]);
 
        if (buffer[3] == 0x3c) {
                unsigned int lba_count, desc_count;
@@ -2806,6 +2812,11 @@ static int sd_try_extended_inquiry(struct scsi_device *sdp)
        return 0;
 }
 
+static inline u32 logical_to_sectors(struct scsi_device *sdev, u32 blocks)
+{
+       return blocks << (ilog2(sdev->sector_size) - 9);
+}
+
 /**
  *     sd_revalidate_disk - called the first time a new disk is seen,
  *     performs disk spin up, read_capacity, etc.
@@ -2815,8 +2826,9 @@ static int sd_revalidate_disk(struct gendisk *disk)
 {
        struct scsi_disk *sdkp = scsi_disk(disk);
        struct scsi_device *sdp = sdkp->device;
+       struct request_queue *q = sdkp->disk->queue;
        unsigned char *buffer;
-       unsigned int max_xfer;
+       unsigned int dev_max, rw_max;
 
        SCSI_LOG_HLQUEUE(3, sd_printk(KERN_INFO, sdkp,
                                      "sd_revalidate_disk\n"));
@@ -2864,11 +2876,26 @@ static int sd_revalidate_disk(struct gendisk *disk)
         */
        sd_set_flush_flag(sdkp);
 
-       max_xfer = sdkp->max_xfer_blocks;
-       max_xfer <<= ilog2(sdp->sector_size) - 9;
+       /* Initial block count limit based on CDB TRANSFER LENGTH field size. */
+       dev_max = sdp->use_16_for_rw ? SD_MAX_XFER_BLOCKS : SD_DEF_XFER_BLOCKS;
+
+       /* Some devices report a maximum block count for READ/WRITE requests. */
+       dev_max = min_not_zero(dev_max, sdkp->max_xfer_blocks);
+       q->limits.max_dev_sectors = logical_to_sectors(sdp, dev_max);
+
+       /*
+        * Use the device's preferred I/O size for reads and writes
+        * unless the reported value is unreasonably large (or garbage).
+        */
+       if (sdkp->opt_xfer_blocks && sdkp->opt_xfer_blocks <= dev_max &&
+           sdkp->opt_xfer_blocks <= SD_DEF_XFER_BLOCKS)
+               rw_max = q->limits.io_opt =
+                       logical_to_sectors(sdp, sdkp->opt_xfer_blocks);
+       else
+               rw_max = BLK_DEF_MAX_SECTORS;
 
-       sdkp->disk->queue->limits.max_sectors =
-               min_not_zero(queue_max_hw_sectors(sdkp->disk->queue), max_xfer);
+       /* Combine with controller limits */
+       q->limits.max_sectors = min(rw_max, queue_max_hw_sectors(q));
 
        set_capacity(disk, sdkp->capacity);
        sd_config_write_same(sdkp);
index 63ba5ca7f9a16b21735c1283c2a17df40a7ee06c..5f2a84aff29fb9cbd003e5bbe6996355a5c07075 100644 (file)
@@ -67,6 +67,7 @@ struct scsi_disk {
        atomic_t        openers;
        sector_t        capacity;       /* size in 512-byte sectors */
        u32             max_xfer_blocks;
+       u32             opt_xfer_blocks;
        u32             max_ws_blocks;
        u32             max_unmap_blocks;
        u32             unmap_granularity;
index dcb0d76d7312847d37809df1f5763206567d5daf..044d06410d4c86c0dc88071bb0de668dd91bb0e2 100644 (file)
@@ -84,6 +84,7 @@ static void init_device_slot_control(unsigned char *dest_desc,
 static int ses_recv_diag(struct scsi_device *sdev, int page_code,
                         void *buf, int bufflen)
 {
+       int ret;
        unsigned char cmd[] = {
                RECEIVE_DIAGNOSTIC,
                1,              /* Set PCV bit */
@@ -92,9 +93,26 @@ static int ses_recv_diag(struct scsi_device *sdev, int page_code,
                bufflen & 0xff,
                0
        };
+       unsigned char recv_page_code;
 
-       return scsi_execute_req(sdev, cmd, DMA_FROM_DEVICE, buf, bufflen,
+       ret =  scsi_execute_req(sdev, cmd, DMA_FROM_DEVICE, buf, bufflen,
                                NULL, SES_TIMEOUT, SES_RETRIES, NULL);
+       if (unlikely(!ret))
+               return ret;
+
+       recv_page_code = ((unsigned char *)buf)[0];
+
+       if (likely(recv_page_code == page_code))
+               return ret;
+
+       /* successful diagnostic but wrong page code.  This happens to some
+        * USB devices, just print a message and pretend there was an error */
+
+       sdev_printk(KERN_ERR, sdev,
+                   "Wrong diagnostic page; asked for %d got %u\n",
+                   page_code, recv_page_code);
+
+       return -EINVAL;
 }
 
 static int ses_send_diag(struct scsi_device *sdev, int page_code,
@@ -541,7 +559,15 @@ static void ses_enclosure_data_process(struct enclosure_device *edev,
                        if (desc_ptr)
                                desc_ptr += len;
 
-                       if (addl_desc_ptr)
+                       if (addl_desc_ptr &&
+                           /* only find additional descriptions for specific devices */
+                           (type_ptr[0] == ENCLOSURE_COMPONENT_DEVICE ||
+                            type_ptr[0] == ENCLOSURE_COMPONENT_ARRAY_DEVICE ||
+                            type_ptr[0] == ENCLOSURE_COMPONENT_SAS_EXPANDER ||
+                            /* these elements are optional */
+                            type_ptr[0] == ENCLOSURE_COMPONENT_SCSI_TARGET_PORT ||
+                            type_ptr[0] == ENCLOSURE_COMPONENT_SCSI_INITIATOR_PORT ||
+                            type_ptr[0] == ENCLOSURE_COMPONENT_CONTROLLER_ELECTRONICS))
                                addl_desc_ptr += addl_desc_ptr[1] + 2;
 
                }
index e0a1e52a04e736b35dc2b03371a72fc0590b85b1..2e522951b619740b08a712695dfca31962b16de0 100644 (file)
@@ -4083,6 +4083,7 @@ static int create_one_cdev(struct scsi_tape *tape, int mode, int rew)
        }
        cdev->owner = THIS_MODULE;
        cdev->ops = &st_fops;
+       STm->cdevs[rew] = cdev;
 
        error = cdev_add(cdev, cdev_devno, 1);
        if (error) {
@@ -4091,7 +4092,6 @@ static int create_one_cdev(struct scsi_tape *tape, int mode, int rew)
                pr_err("st%d: Device not attached.\n", dev_num);
                goto out_free;
        }
-       STm->cdevs[rew] = cdev;
 
        i = mode << (4 - ST_NBR_MODE_BITS);
        snprintf(name, 10, "%s%s%s", rew ? "n" : "",
@@ -4110,8 +4110,9 @@ static int create_one_cdev(struct scsi_tape *tape, int mode, int rew)
        return 0;
 out_free:
        cdev_del(STm->cdevs[rew]);
-       STm->cdevs[rew] = NULL;
 out:
+       STm->cdevs[rew] = NULL;
+       STm->devs[rew] = NULL;
        return error;
 }
 
index 25abd4eb7d102113d94c62bf7bbc1b8f935f0ca8..91a003011acfacb277e892b47c99771ceae80ffa 100644 (file)
@@ -34,7 +34,7 @@ static struct pm_clk_notifier_block platform_bus_notifier = {
 
 static int __init sh_pm_runtime_init(void)
 {
-       if (IS_ENABLED(CONFIG_ARCH_SHMOBILE_MULTI)) {
+       if (IS_ENABLED(CONFIG_ARCH_SHMOBILE)) {
                if (!of_find_compatible_node(NULL, NULL,
                                             "renesas,cpg-mstp-clocks"))
                        return 0;
index 9d5068248aa0486f147bbbc90f1f2ac495ad0378..0a4ea809a61b0cddb37fd6fc2b72e6047a343bf4 100644 (file)
@@ -23,6 +23,7 @@ config MTK_PMIC_WRAP
 config MTK_SCPSYS
        bool "MediaTek SCPSYS Support"
        depends on ARCH_MEDIATEK || COMPILE_TEST
+       default ARM64 && ARCH_MEDIATEK
        select REGMAP
        select MTK_INFRACFG
        select PM_GENERIC_DOMAINS if PM
index f3a0b6a4b54ef8093f2dbbabbcdd7c07de1cddbe..8c03a80b482ddac7c1e22ac4178772f7d29819ff 100644 (file)
@@ -1179,7 +1179,7 @@ static int knav_queue_setup_link_ram(struct knav_device *kdev)
 
                block++;
                if (!block->size)
-                       return 0;
+                       continue;
 
                dev_dbg(kdev->dev, "linkram1: phys:%x, virt:%p, size:%x\n",
                        block->phys, block->virt, block->size);
@@ -1519,9 +1519,9 @@ static int knav_queue_load_pdsp(struct knav_device *kdev,
 
        for (i = 0; i < ARRAY_SIZE(knav_acc_firmwares); i++) {
                if (knav_acc_firmwares[i]) {
-                       ret = request_firmware(&fw,
-                                              knav_acc_firmwares[i],
-                                              kdev->dev);
+                       ret = request_firmware_direct(&fw,
+                                                     knav_acc_firmwares[i],
+                                                     kdev->dev);
                        if (!ret) {
                                found = true;
                                break;
index 06858e04ec59a8f2e290c398f6f06e2d1b15e28a..bf9a610e5b898106af79e49a586d7ad4061ef4e0 100644 (file)
@@ -562,8 +562,8 @@ static int bcm63xx_spi_probe(struct platform_device *pdev)
                goto out_clk_disable;
        }
 
-       dev_info(dev, "at 0x%08x (irq %d, FIFOs size %d)\n",
-                r->start, irq, bs->fifo_size);
+       dev_info(dev, "at %pr (irq %d, FIFOs size %d)\n",
+                r, irq, bs->fifo_size);
 
        return 0;
 
index 59a11437db7090f9c8464f8ca0584c789be2e997..39412c9097c6a240466c51c941ec890a4612542e 100644 (file)
@@ -167,7 +167,7 @@ static inline int is_double_byte_mode(struct fsl_dspi *dspi)
 {
        unsigned int val;
 
-       regmap_read(dspi->regmap, SPI_CTAR(dspi->cs), &val);
+       regmap_read(dspi->regmap, SPI_CTAR(0), &val);
 
        return ((val & SPI_FRAME_BITS_MASK) == SPI_FRAME_BITS(8)) ? 0 : 1;
 }
@@ -257,7 +257,7 @@ static u32 dspi_data_to_pushr(struct fsl_dspi *dspi, int tx_word)
 
        return  SPI_PUSHR_TXDATA(d16) |
                SPI_PUSHR_PCS(dspi->cs) |
-               SPI_PUSHR_CTAS(dspi->cs) |
+               SPI_PUSHR_CTAS(0) |
                SPI_PUSHR_CONT;
 }
 
@@ -290,7 +290,7 @@ static int dspi_eoq_write(struct fsl_dspi *dspi)
                 */
                if (tx_word && (dspi->len == 1)) {
                        dspi->dataflags |= TRAN_STATE_WORD_ODD_NUM;
-                       regmap_update_bits(dspi->regmap, SPI_CTAR(dspi->cs),
+                       regmap_update_bits(dspi->regmap, SPI_CTAR(0),
                                        SPI_FRAME_BITS_MASK, SPI_FRAME_BITS(8));
                        tx_word = 0;
                }
@@ -339,7 +339,7 @@ static int dspi_tcfq_write(struct fsl_dspi *dspi)
 
        if (tx_word && (dspi->len == 1)) {
                dspi->dataflags |= TRAN_STATE_WORD_ODD_NUM;
-               regmap_update_bits(dspi->regmap, SPI_CTAR(dspi->cs),
+               regmap_update_bits(dspi->regmap, SPI_CTAR(0),
                                SPI_FRAME_BITS_MASK, SPI_FRAME_BITS(8));
                tx_word = 0;
        }
@@ -407,7 +407,7 @@ static int dspi_transfer_one_message(struct spi_master *master,
                regmap_update_bits(dspi->regmap, SPI_MCR,
                                SPI_MCR_CLR_TXF | SPI_MCR_CLR_RXF,
                                SPI_MCR_CLR_TXF | SPI_MCR_CLR_RXF);
-               regmap_write(dspi->regmap, SPI_CTAR(dspi->cs),
+               regmap_write(dspi->regmap, SPI_CTAR(0),
                                dspi->cur_chip->ctar_val);
 
                trans_mode = dspi->devtype_data->trans_mode;
@@ -566,7 +566,7 @@ static irqreturn_t dspi_interrupt(int irq, void *dev_id)
                if (!dspi->len) {
                        if (dspi->dataflags & TRAN_STATE_WORD_ODD_NUM) {
                                regmap_update_bits(dspi->regmap,
-                                                  SPI_CTAR(dspi->cs),
+                                                  SPI_CTAR(0),
                                                   SPI_FRAME_BITS_MASK,
                                                   SPI_FRAME_BITS(16));
                                dspi->dataflags &= ~TRAN_STATE_WORD_ODD_NUM;
index 563954a614242718bd125f16f9a3549f783346b8..7840067062a8daf950f4de9a07e232f1482c9485 100644 (file)
@@ -410,7 +410,7 @@ static int mtk_spi_setup(struct spi_device *spi)
        if (!spi->controller_data)
                spi->controller_data = (void *)&mtk_default_chip_info;
 
-       if (mdata->dev_comp->need_pad_sel)
+       if (mdata->dev_comp->need_pad_sel && gpio_is_valid(spi->cs_gpio))
                gpio_direction_output(spi->cs_gpio, !(spi->mode & SPI_CS_HIGH));
 
        return 0;
@@ -632,13 +632,23 @@ static int mtk_spi_probe(struct platform_device *pdev)
                        goto err_put_master;
                }
 
-               for (i = 0; i < master->num_chipselect; i++) {
-                       ret = devm_gpio_request(&pdev->dev, master->cs_gpios[i],
-                                               dev_name(&pdev->dev));
-                       if (ret) {
-                               dev_err(&pdev->dev,
-                                       "can't get CS GPIO %i\n", i);
-                               goto err_put_master;
+               if (!master->cs_gpios && master->num_chipselect > 1) {
+                       dev_err(&pdev->dev,
+                               "cs_gpios not specified and num_chipselect > 1\n");
+                       ret = -EINVAL;
+                       goto err_put_master;
+               }
+
+               if (master->cs_gpios) {
+                       for (i = 0; i < master->num_chipselect; i++) {
+                               ret = devm_gpio_request(&pdev->dev,
+                                                       master->cs_gpios[i],
+                                                       dev_name(&pdev->dev));
+                               if (ret) {
+                                       dev_err(&pdev->dev,
+                                               "can't get CS GPIO %i\n", i);
+                                       goto err_put_master;
+                               }
                        }
                }
        }
index 94af80676684e4708d373e1551b8a6c46ea118fa..5e5fd77e27119d6ceb8d64f657884ab4ef9f3759 100644 (file)
@@ -1171,19 +1171,31 @@ err_no_rxchan:
 static int pl022_dma_autoprobe(struct pl022 *pl022)
 {
        struct device *dev = &pl022->adev->dev;
+       struct dma_chan *chan;
+       int err;
 
        /* automatically configure DMA channels from platform, normally using DT */
-       pl022->dma_rx_channel = dma_request_slave_channel(dev, "rx");
-       if (!pl022->dma_rx_channel)
+       chan = dma_request_slave_channel_reason(dev, "rx");
+       if (IS_ERR(chan)) {
+               err = PTR_ERR(chan);
                goto err_no_rxchan;
+       }
+
+       pl022->dma_rx_channel = chan;
 
-       pl022->dma_tx_channel = dma_request_slave_channel(dev, "tx");
-       if (!pl022->dma_tx_channel)
+       chan = dma_request_slave_channel_reason(dev, "tx");
+       if (IS_ERR(chan)) {
+               err = PTR_ERR(chan);
                goto err_no_txchan;
+       }
+
+       pl022->dma_tx_channel = chan;
 
        pl022->dummypage = kmalloc(PAGE_SIZE, GFP_KERNEL);
-       if (!pl022->dummypage)
+       if (!pl022->dummypage) {
+               err = -ENOMEM;
                goto err_no_dummypage;
+       }
 
        return 0;
 
@@ -1194,7 +1206,7 @@ err_no_txchan:
        dma_release_channel(pl022->dma_rx_channel);
        pl022->dma_rx_channel = NULL;
 err_no_rxchan:
-       return -ENODEV;
+       return err;
 }
                
 static void terminate_dma(struct pl022 *pl022)
@@ -2236,6 +2248,10 @@ static int pl022_probe(struct amba_device *adev, const struct amba_id *id)
 
        /* Get DMA channels, try autoconfiguration first */
        status = pl022_dma_autoprobe(pl022);
+       if (status == -EPROBE_DEFER) {
+               dev_dbg(dev, "deferring probe to get DMA channel\n");
+               goto err_no_irq;
+       }
 
        /* If that failed, use channels from platform_info */
        if (status == 0)
index e2415be209d5a77e9224add30db37d65244fabda..dee1cb87d24f4aaca1fd3d2e43b8101d3bf6e246 100644 (file)
@@ -376,6 +376,7 @@ static void spi_drv_shutdown(struct device *dev)
 
 /**
  * __spi_register_driver - register a SPI driver
+ * @owner: owner module of the driver to register
  * @sdrv: the driver to register
  * Context: can sleep
  *
@@ -1704,7 +1705,7 @@ struct spi_master *spi_alloc_master(struct device *dev, unsigned size)
        master->bus_num = -1;
        master->num_chipselect = 1;
        master->dev.class = &spi_master_class;
-       master->dev.parent = get_device(dev);
+       master->dev.parent = dev;
        spi_master_set_devdata(master, &master[1]);
 
        return master;
@@ -2130,6 +2131,7 @@ static int __spi_validate(struct spi_device *spi, struct spi_message *message)
         * Set transfer tx_nbits and rx_nbits as single transfer default
         * (SPI_NBITS_SINGLE) if it is not set for this transfer.
         */
+       message->frame_length = 0;
        list_for_each_entry(xfer, &message->transfers, transfer_list) {
                message->frame_length += xfer->len;
                if (!xfer->bits_per_word)
index 91a0fcd72423080900c6c733f6aeb7e800a85538..d0e7dfc647cf21a729696cbe499f7fc6dbf53b02 100644 (file)
@@ -651,11 +651,11 @@ static int spidev_release(struct inode *inode, struct file *filp)
                kfree(spidev->rx_buffer);
                spidev->rx_buffer = NULL;
 
+               spin_lock_irq(&spidev->spi_lock);
                if (spidev->spi)
                        spidev->speed_hz = spidev->spi->max_speed_hz;
 
                /* ... after we unbound from the underlying device? */
-               spin_lock_irq(&spidev->spi_lock);
                dofree = (spidev->spi == NULL);
                spin_unlock_irq(&spidev->spi_lock);
 
index 195c41d7bd53b3b6926507cdfea2a8de42d45578..0813163f962f09e328d6fc448238201f84cc55cd 100644 (file)
@@ -81,7 +81,7 @@ static int ion_chunk_heap_allocate(struct ion_heap *heap,
 err:
        sg = table->sgl;
        for (i -= 1; i >= 0; i--) {
-               gen_pool_free(chunk_heap->pool, sg_phys(sg) & PAGE_MASK,
+               gen_pool_free(chunk_heap->pool, page_to_phys(sg_page(sg)),
                              sg->length);
                sg = sg_next(sg);
        }
@@ -109,7 +109,7 @@ static void ion_chunk_heap_free(struct ion_buffer *buffer)
                                                        DMA_BIDIRECTIONAL);
 
        for_each_sg(table->sgl, sg, table->nents, i) {
-               gen_pool_free(chunk_heap->pool, sg_phys(sg) & PAGE_MASK,
+               gen_pool_free(chunk_heap->pool, page_to_phys(sg_page(sg)),
                              sg->length);
        }
        chunk_heap->allocated -= allocated_size;
index 6d5b38d6957852ee81caa09cb6e3c047c55d26b8..9d7f0004d2d7b25bcd7e67b345aaa4f3ad407d32 100644 (file)
@@ -18,7 +18,8 @@ source "drivers/staging/iio/resolver/Kconfig"
 source "drivers/staging/iio/trigger/Kconfig"
 
 config IIO_DUMMY_EVGEN
-       tristate
+       tristate
+       select IRQ_WORK
 
 config IIO_SIMPLE_DUMMY
        tristate "An example driver with no hardware requirements"
index d11c54b721860cccb0c6db82a6d9353787560896..b51f237cd817c9dc8fe668bb61ae708577bf8287 100644 (file)
@@ -76,7 +76,7 @@ static int lpc32xx_read_raw(struct iio_dev *indio_dev,
 
        if (mask == IIO_CHAN_INFO_RAW) {
                mutex_lock(&indio_dev->mlock);
-               clk_enable(info->clk);
+               clk_prepare_enable(info->clk);
                /* Measurement setup */
                __raw_writel(AD_INTERNAL | (chan->address) | AD_REFp | AD_REFm,
                             LPC32XX_ADC_SELECT(info->adc_base));
@@ -84,7 +84,7 @@ static int lpc32xx_read_raw(struct iio_dev *indio_dev,
                __raw_writel(AD_PDN_CTRL | AD_STROBE,
                             LPC32XX_ADC_CTRL(info->adc_base));
                wait_for_completion(&info->completion); /* set by ISR */
-               clk_disable(info->clk);
+               clk_disable_unprepare(info->clk);
                *val = info->value;
                mutex_unlock(&indio_dev->mlock);
 
index bfbf1c56bd22630e19ac739eadd514157071ab2b..6eb600ff70569ef6ceb902afcc49ddce08b09953 100644 (file)
@@ -159,7 +159,7 @@ static irqreturn_t iio_simple_dummy_get_timestamp(int irq, void *private)
        struct iio_dummy_state *st = iio_priv(indio_dev);
 
        st->event_timestamp = iio_get_time_ns();
-       return IRQ_HANDLED;
+       return IRQ_WAKE_THREAD;
 }
 
 /**
index f5d741f25ffdeb189a6b56f7ce871630f7e303be..485ab267091859214576da349e2bf89a5874667d 100644 (file)
@@ -110,7 +110,6 @@ struct libcfs_ioctl_handler {
 #define IOC_LIBCFS_CLEAR_DEBUG      _IOWR('e', 31, long)
 #define IOC_LIBCFS_MARK_DEBUG        _IOWR('e', 32, long)
 #define IOC_LIBCFS_MEMHOG                _IOWR('e', 36, long)
-#define IOC_LIBCFS_PING_TEST          _IOWR('e', 37, long)
 /* lnet ioctls */
 #define IOC_LIBCFS_GET_NI                _IOWR('e', 50, long)
 #define IOC_LIBCFS_FAIL_NID            _IOWR('e', 51, long)
index 07a68594c2791df5c75cbe138564b78008e8aefb..e7c2b26156b9d36026a4a64a4e0565804bcc1312 100644 (file)
@@ -274,23 +274,6 @@ static int libcfs_ioctl_int(struct cfs_psdev_file *pfile, unsigned long cmd,
                }
                break;
 
-       case IOC_LIBCFS_PING_TEST: {
-               extern void (kping_client)(struct libcfs_ioctl_data *);
-               void (*ping)(struct libcfs_ioctl_data *);
-
-               CDEBUG(D_IOCTL, "doing %d pings to nid %s (%s)\n",
-                      data->ioc_count, libcfs_nid2str(data->ioc_nid),
-                      libcfs_nid2str(data->ioc_nid));
-               ping = symbol_get(kping_client);
-               if (!ping)
-                       CERROR("symbol_get failed\n");
-               else {
-                       ping(data);
-                       symbol_put(kping_client);
-               }
-               return 0;
-       }
-
        default: {
                struct libcfs_ioctl_handler *hand;
 
index f61ef669644cdadfc10c54539c5743c012082d09..a4a9a763ff023821644197fca610e7783d773129 100644 (file)
@@ -1270,6 +1270,7 @@ static int
 echo_copyout_lsm(struct lov_stripe_md *lsm, void *_ulsm, int ulsm_nob)
 {
        struct lov_stripe_md *ulsm = _ulsm;
+       struct lov_oinfo **p;
        int nob, i;
 
        nob = offsetof(struct lov_stripe_md, lsm_oinfo[lsm->lsm_stripe_count]);
@@ -1279,9 +1280,10 @@ echo_copyout_lsm(struct lov_stripe_md *lsm, void *_ulsm, int ulsm_nob)
        if (copy_to_user(ulsm, lsm, sizeof(*ulsm)))
                return -EFAULT;
 
-       for (i = 0; i < lsm->lsm_stripe_count; i++) {
-               if (copy_to_user(ulsm->lsm_oinfo[i], lsm->lsm_oinfo[i],
-                                     sizeof(lsm->lsm_oinfo[0])))
+       for (i = 0, p = lsm->lsm_oinfo; i < lsm->lsm_stripe_count; i++, p++) {
+               struct lov_oinfo __user *up;
+               if (get_user(up, ulsm->lsm_oinfo + i) ||
+                   copy_to_user(up, *p, sizeof(struct lov_oinfo)))
                        return -EFAULT;
        }
        return 0;
@@ -1289,9 +1291,10 @@ echo_copyout_lsm(struct lov_stripe_md *lsm, void *_ulsm, int ulsm_nob)
 
 static int
 echo_copyin_lsm(struct echo_device *ed, struct lov_stripe_md *lsm,
-                void *ulsm, int ulsm_nob)
+               struct lov_stripe_md __user *ulsm, int ulsm_nob)
 {
        struct echo_client_obd *ec = ed->ed_ec;
+       struct lov_oinfo **p;
        int                  i;
 
        if (ulsm_nob < sizeof(*lsm))
@@ -1306,11 +1309,10 @@ echo_copyin_lsm(struct echo_device *ed, struct lov_stripe_md *lsm,
            ((__u64)lsm->lsm_stripe_size * lsm->lsm_stripe_count > ~0UL))
                return -EINVAL;
 
-       for (i = 0; i < lsm->lsm_stripe_count; i++) {
-               if (copy_from_user(lsm->lsm_oinfo[i],
-                                      ((struct lov_stripe_md *)ulsm)-> \
-                                      lsm_oinfo[i],
-                                      sizeof(lsm->lsm_oinfo[0])))
+       for (i = 0, p = lsm->lsm_oinfo; i < lsm->lsm_stripe_count; i++, p++) {
+               struct lov_oinfo __user *up;
+               if (get_user(up, ulsm->lsm_oinfo + i) ||
+                   copy_from_user(*p, up, sizeof(struct lov_oinfo)))
                        return -EFAULT;
        }
        return 0;
index e10c6ffa698a6f541ad4e40c7007ddc4852b50cd..9568bdb6319bb77a84d49544e77410182a528ad7 100644 (file)
 #include "wilc_wlan.h"
 #include <linux/errno.h>
 #include <linux/slab.h>
-#include <linux/etherdevice.h>
 #define TAG_PARAM_OFFSET       (MAC_HDR_LEN + TIME_STAMP_LEN + \
                                                        BEACON_INTERVAL_LEN + CAP_INFO_LEN)
-#define ADDR1 4
-#define ADDR2 10
-#define ADDR3 16
 
 /* Basic Frame Type Codes (2-bit) */
 enum basic_frame_type {
@@ -175,32 +171,38 @@ static inline u8 get_from_ds(u8 *header)
        return ((header[1] & 0x02) >> 1);
 }
 
+/* This function extracts the MAC Address in 'address1' field of the MAC     */
+/* header and updates the MAC Address in the allocated 'addr' variable.      */
+static inline void get_address1(u8 *pu8msa, u8 *addr)
+{
+       memcpy(addr, pu8msa + 4, 6);
+}
+
+/* This function extracts the MAC Address in 'address2' field of the MAC     */
+/* header and updates the MAC Address in the allocated 'addr' variable.      */
+static inline void get_address2(u8 *pu8msa, u8 *addr)
+{
+       memcpy(addr, pu8msa + 10, 6);
+}
+
+/* This function extracts the MAC Address in 'address3' field of the MAC     */
+/* header and updates the MAC Address in the allocated 'addr' variable.      */
+static inline void get_address3(u8 *pu8msa, u8 *addr)
+{
+       memcpy(addr, pu8msa + 16, 6);
+}
+
 /* This function extracts the BSSID from the incoming WLAN packet based on   */
-/* the 'from ds' bit, and updates the MAC Address in the allocated 'data'    */
+/* the 'from ds' bit, and updates the MAC Address in the allocated 'addr'    */
 /* variable.                                                                 */
 static inline void get_BSSID(u8 *data, u8 *bssid)
 {
        if (get_from_ds(data) == 1)
-               /*
-                * Extract the MAC Address in 'address2' field of the MAC
-                * header and update the MAC Address in the allocated 'data'
-                *  variable.
-                */
-               ether_addr_copy(data, bssid + ADDR2);
+               get_address2(data, bssid);
        else if (get_to_ds(data) == 1)
-               /*
-                * Extract the MAC Address in 'address1' field of the MAC
-                * header and update the MAC Address in the allocated 'data'
-                * variable.
-                */
-               ether_addr_copy(data, bssid + ADDR1);
+               get_address1(data, bssid);
        else
-               /*
-                * Extract the MAC Address in 'address3' field of the MAC
-                * header and update the MAC Address in the allocated 'data'
-                * variable.
-                */
-               ether_addr_copy(data, bssid + ADDR3);
+               get_address3(data, bssid);
 }
 
 /* This function extracts the SSID from a beacon/probe response frame        */
index 342a07c58d89400643b26236875d6ffa6a91062e..72204fbf2bb13be5cdb7211ca6001b58f0c4fbc6 100644 (file)
@@ -4074,6 +4074,17 @@ reject:
        return iscsit_add_reject(conn, ISCSI_REASON_BOOKMARK_NO_RESOURCES, buf);
 }
 
+static bool iscsi_target_check_conn_state(struct iscsi_conn *conn)
+{
+       bool ret;
+
+       spin_lock_bh(&conn->state_lock);
+       ret = (conn->conn_state != TARG_CONN_STATE_LOGGED_IN);
+       spin_unlock_bh(&conn->state_lock);
+
+       return ret;
+}
+
 int iscsi_target_rx_thread(void *arg)
 {
        int ret, rc;
@@ -4091,7 +4102,7 @@ int iscsi_target_rx_thread(void *arg)
         * incoming iscsi/tcp socket I/O, and/or failing the connection.
         */
        rc = wait_for_completion_interruptible(&conn->rx_login_comp);
-       if (rc < 0)
+       if (rc < 0 || iscsi_target_check_conn_state(conn))
                return 0;
 
        if (conn->conn_transport->transport_type == ISCSI_INFINIBAND) {
index 5c964c09c89ff25e6076b272d4afff1a0466a372..9fc9117d0f226a9e3f559d73697de025fc30fd72 100644 (file)
@@ -388,6 +388,7 @@ err:
        if (login->login_complete) {
                if (conn->rx_thread && conn->rx_thread_active) {
                        send_sig(SIGINT, conn->rx_thread, 1);
+                       complete(&conn->rx_login_comp);
                        kthread_stop(conn->rx_thread);
                }
                if (conn->tx_thread && conn->tx_thread_active) {
index 51d1734d5390409e2c98a34c4ad9fc787c1fc362..2cbea2af7cd032512572a07275f713aef366475b 100644 (file)
@@ -208,7 +208,7 @@ int iscsi_create_default_params(struct iscsi_param_list **param_list_ptr)
        if (!pl) {
                pr_err("Unable to allocate memory for"
                                " struct iscsi_param_list.\n");
-               return -;
+               return -ENOMEM;
        }
        INIT_LIST_HEAD(&pl->param_list);
        INIT_LIST_HEAD(&pl->extra_response_list);
@@ -578,7 +578,7 @@ int iscsi_copy_param_list(
        param_list = kzalloc(sizeof(struct iscsi_param_list), GFP_KERNEL);
        if (!param_list) {
                pr_err("Unable to allocate memory for struct iscsi_param_list.\n");
-               return -1;
+               return -ENOMEM;
        }
        INIT_LIST_HEAD(&param_list->param_list);
        INIT_LIST_HEAD(&param_list->extra_response_list);
@@ -629,7 +629,7 @@ int iscsi_copy_param_list(
 
 err_out:
        iscsi_release_param_list(param_list);
-       return -1;
+       return -ENOMEM;
 }
 
 static void iscsi_release_extra_responses(struct iscsi_param_list *param_list)
@@ -729,7 +729,7 @@ static int iscsi_add_notunderstood_response(
        if (!extra_response) {
                pr_err("Unable to allocate memory for"
                        " struct iscsi_extra_response.\n");
-               return -1;
+               return -ENOMEM;
        }
        INIT_LIST_HEAD(&extra_response->er_list);
 
@@ -1370,7 +1370,7 @@ int iscsi_decode_text_input(
        tmpbuf = kzalloc(length + 1, GFP_KERNEL);
        if (!tmpbuf) {
                pr_err("Unable to allocate %u + 1 bytes for tmpbuf.\n", length);
-               return -1;
+               return -ENOMEM;
        }
 
        memcpy(tmpbuf, textbuf, length);
index 0b4b2a67d9f9ed597479f1f2c0ea356126f55006..98698d87574262226bcf893da2cb3d3849e6df32 100644 (file)
@@ -371,7 +371,8 @@ sbc_setup_write_same(struct se_cmd *cmd, unsigned char *flags, struct sbc_ops *o
        return 0;
 }
 
-static sense_reason_t xdreadwrite_callback(struct se_cmd *cmd, bool success)
+static sense_reason_t xdreadwrite_callback(struct se_cmd *cmd, bool success,
+                                          int *post_ret)
 {
        unsigned char *buf, *addr;
        struct scatterlist *sg;
@@ -437,7 +438,8 @@ sbc_execute_rw(struct se_cmd *cmd)
                               cmd->data_direction);
 }
 
-static sense_reason_t compare_and_write_post(struct se_cmd *cmd, bool success)
+static sense_reason_t compare_and_write_post(struct se_cmd *cmd, bool success,
+                                            int *post_ret)
 {
        struct se_device *dev = cmd->se_dev;
 
@@ -447,8 +449,10 @@ static sense_reason_t compare_and_write_post(struct se_cmd *cmd, bool success)
         * sent to the backend driver.
         */
        spin_lock_irq(&cmd->t_state_lock);
-       if ((cmd->transport_state & CMD_T_SENT) && !cmd->scsi_status)
+       if ((cmd->transport_state & CMD_T_SENT) && !cmd->scsi_status) {
                cmd->se_cmd_flags |= SCF_COMPARE_AND_WRITE_POST;
+               *post_ret = 1;
+       }
        spin_unlock_irq(&cmd->t_state_lock);
 
        /*
@@ -460,7 +464,8 @@ static sense_reason_t compare_and_write_post(struct se_cmd *cmd, bool success)
        return TCM_NO_SENSE;
 }
 
-static sense_reason_t compare_and_write_callback(struct se_cmd *cmd, bool success)
+static sense_reason_t compare_and_write_callback(struct se_cmd *cmd, bool success,
+                                                int *post_ret)
 {
        struct se_device *dev = cmd->se_dev;
        struct scatterlist *write_sg = NULL, *sg;
@@ -556,11 +561,11 @@ static sense_reason_t compare_and_write_callback(struct se_cmd *cmd, bool succes
 
                if (block_size < PAGE_SIZE) {
                        sg_set_page(&write_sg[i], m.page, block_size,
-                                   block_size);
+                                   m.piter.sg->offset + block_size);
                } else {
                        sg_miter_next(&m);
                        sg_set_page(&write_sg[i], m.page, block_size,
-                                   0);
+                                   m.piter.sg->offset);
                }
                len -= block_size;
                i++;
index 273c72b2b83dc016b2a317b778a8c391eebcb9c8..81a6b3e07687232df9b2bba5d77c1caf01d6c6e8 100644 (file)
@@ -246,7 +246,7 @@ static ssize_t target_stat_lu_prod_show(struct config_item *item, char *page)
        char str[sizeof(dev->t10_wwn.model)+1];
 
        /* scsiLuProductId */
-       for (i = 0; i < sizeof(dev->t10_wwn.vendor); i++)
+       for (i = 0; i < sizeof(dev->t10_wwn.model); i++)
                str[i] = ISPRINT(dev->t10_wwn.model[i]) ?
                        dev->t10_wwn.model[i] : ' ';
        str[i] = '\0';
index 5b2820312310ec21bf83824efa318caab132e046..28fb3016370faf1048bd361c1b98d2c3855483c8 100644 (file)
@@ -130,6 +130,9 @@ void core_tmr_abort_task(
                if (tmr->ref_task_tag != ref_tag)
                        continue;
 
+               if (!kref_get_unless_zero(&se_cmd->cmd_kref))
+                       continue;
+
                printk("ABORT_TASK: Found referenced %s task_tag: %llu\n",
                        se_cmd->se_tfo->get_fabric_name(), ref_tag);
 
@@ -139,13 +142,15 @@ void core_tmr_abort_task(
                               " skipping\n", ref_tag);
                        spin_unlock(&se_cmd->t_state_lock);
                        spin_unlock_irqrestore(&se_sess->sess_cmd_lock, flags);
+
+                       target_put_sess_cmd(se_cmd);
+
                        goto out;
                }
                se_cmd->transport_state |= CMD_T_ABORTED;
                spin_unlock(&se_cmd->t_state_lock);
 
                list_del_init(&se_cmd->se_cmd_list);
-               kref_get(&se_cmd->cmd_kref);
                spin_unlock_irqrestore(&se_sess->sess_cmd_lock, flags);
 
                cancel_work_sync(&se_cmd->work);
index 5bacc7b5ed6d85cf54d6d8fe445dcac08ee8081b..4fdcee2006d1698f4b4e8689c7976ea161a34685 100644 (file)
@@ -1658,7 +1658,7 @@ bool target_stop_cmd(struct se_cmd *cmd, unsigned long *flags)
 void transport_generic_request_failure(struct se_cmd *cmd,
                sense_reason_t sense_reason)
 {
-       int ret = 0;
+       int ret = 0, post_ret = 0;
 
        pr_debug("-----[ Storage Engine Exception for cmd: %p ITT: 0x%08llx"
                " CDB: 0x%02x\n", cmd, cmd->tag, cmd->t_task_cdb[0]);
@@ -1680,7 +1680,7 @@ void transport_generic_request_failure(struct se_cmd *cmd,
         */
        if ((cmd->se_cmd_flags & SCF_COMPARE_AND_WRITE) &&
             cmd->transport_complete_callback)
-               cmd->transport_complete_callback(cmd, false);
+               cmd->transport_complete_callback(cmd, false, &post_ret);
 
        switch (sense_reason) {
        case TCM_NON_EXISTENT_LUN:
@@ -2068,11 +2068,13 @@ static void target_complete_ok_work(struct work_struct *work)
         */
        if (cmd->transport_complete_callback) {
                sense_reason_t rc;
+               bool caw = (cmd->se_cmd_flags & SCF_COMPARE_AND_WRITE);
+               bool zero_dl = !(cmd->data_length);
+               int post_ret = 0;
 
-               rc = cmd->transport_complete_callback(cmd, true);
-               if (!rc && !(cmd->se_cmd_flags & SCF_COMPARE_AND_WRITE_POST)) {
-                       if ((cmd->se_cmd_flags & SCF_COMPARE_AND_WRITE) &&
-                           !cmd->data_length)
+               rc = cmd->transport_complete_callback(cmd, true, &post_ret);
+               if (!rc && !post_ret) {
+                       if (caw && zero_dl)
                                goto queue_rsp;
 
                        return;
@@ -2507,23 +2509,24 @@ out:
 EXPORT_SYMBOL(target_get_sess_cmd);
 
 static void target_release_cmd_kref(struct kref *kref)
-               __releases(&se_cmd->se_sess->sess_cmd_lock)
 {
        struct se_cmd *se_cmd = container_of(kref, struct se_cmd, cmd_kref);
        struct se_session *se_sess = se_cmd->se_sess;
+       unsigned long flags;
 
+       spin_lock_irqsave(&se_sess->sess_cmd_lock, flags);
        if (list_empty(&se_cmd->se_cmd_list)) {
-               spin_unlock(&se_sess->sess_cmd_lock);
+               spin_unlock_irqrestore(&se_sess->sess_cmd_lock, flags);
                se_cmd->se_tfo->release_cmd(se_cmd);
                return;
        }
        if (se_sess->sess_tearing_down && se_cmd->cmd_wait_set) {
-               spin_unlock(&se_sess->sess_cmd_lock);
+               spin_unlock_irqrestore(&se_sess->sess_cmd_lock, flags);
                complete(&se_cmd->cmd_wait_comp);
                return;
        }
        list_del(&se_cmd->se_cmd_list);
-       spin_unlock(&se_sess->sess_cmd_lock);
+       spin_unlock_irqrestore(&se_sess->sess_cmd_lock, flags);
 
        se_cmd->se_tfo->release_cmd(se_cmd);
 }
@@ -2539,8 +2542,7 @@ int target_put_sess_cmd(struct se_cmd *se_cmd)
                se_cmd->se_tfo->release_cmd(se_cmd);
                return 1;
        }
-       return kref_put_spinlock_irqsave(&se_cmd->cmd_kref, target_release_cmd_kref,
-                       &se_sess->sess_cmd_lock);
+       return kref_put(&se_cmd->cmd_kref, target_release_cmd_kref);
 }
 EXPORT_SYMBOL(target_put_sess_cmd);
 
index 937cebf7663324b53a7fa773f519403a3953b87d..5e6d6cb348fc1c902ea74079357430d5dfb0d44a 100644 (file)
@@ -638,7 +638,7 @@ static int tcmu_check_expired_cmd(int id, void *p, void *data)
        if (test_bit(TCMU_CMD_BIT_EXPIRED, &cmd->flags))
                return 0;
 
-       if (!time_after(cmd->deadline, jiffies))
+       if (!time_after(jiffies, cmd->deadline))
                return 0;
 
        set_bit(TCMU_CMD_BIT_EXPIRED, &cmd->flags);
@@ -1101,8 +1101,6 @@ tcmu_parse_cdb(struct se_cmd *cmd)
 
 static const struct target_backend_ops tcmu_ops = {
        .name                   = "user",
-       .inquiry_prod           = "USER",
-       .inquiry_rev            = TCMU_VERSION,
        .owner                  = THIS_MODULE,
        .transport_flags        = TRANSPORT_FLAG_PASSTHROUGH,
        .attach_hba             = tcmu_attach_hba,
index c463c89b90efd89c9cf1a29b8472b25e41bf6c17..8cc4ac64a91c36347b9307addb88ae99d545d2b7 100644 (file)
@@ -382,7 +382,7 @@ endmenu
 
 config QCOM_SPMI_TEMP_ALARM
        tristate "Qualcomm SPMI PMIC Temperature Alarm"
-       depends on OF && (SPMI || COMPILE_TEST) && IIO
+       depends on OF && SPMI && IIO
        select REGMAP_SPMI
        help
          This enables a thermal sysfs driver for Qualcomm plug-and-play (QPNP)
index c8fe3cac2e0e04d8196694f264b6d9f4fcd5cc5d..c5547bd711dbe2b4d681e54213e25e992afb51af 100644 (file)
@@ -55,6 +55,7 @@
 #define TEMPSENSE2_PANIC_VALUE_SHIFT   16
 #define TEMPSENSE2_PANIC_VALUE_MASK    0xfff0000
 
+#define OCOTP_MEM0                     0x0480
 #define OCOTP_ANA1                     0x04e0
 
 /* The driver supports 1 passive trip point and 1 critical trip point */
@@ -64,12 +65,6 @@ enum imx_thermal_trip {
        IMX_TRIP_NUM,
 };
 
-/*
- * It defines the temperature in millicelsius for passive trip point
- * that will trigger cooling action when crossed.
- */
-#define IMX_TEMP_PASSIVE               85000
-
 #define IMX_POLLING_DELAY              2000 /* millisecond */
 #define IMX_PASSIVE_DELAY              1000
 
@@ -100,12 +95,14 @@ struct imx_thermal_data {
        u32 c1, c2; /* See formula in imx_get_sensor_data() */
        int temp_passive;
        int temp_critical;
+       int temp_max;
        int alarm_temp;
        int last_temp;
        bool irq_enabled;
        int irq;
        struct clk *thermal_clk;
        const struct thermal_soc_data *socdata;
+       const char *temp_grade;
 };
 
 static void imx_set_panic_temp(struct imx_thermal_data *data,
@@ -285,10 +282,12 @@ static int imx_set_trip_temp(struct thermal_zone_device *tz, int trip,
 {
        struct imx_thermal_data *data = tz->devdata;
 
+       /* do not allow changing critical threshold */
        if (trip == IMX_TRIP_CRITICAL)
                return -EPERM;
 
-       if (temp < 0 || temp > IMX_TEMP_PASSIVE)
+       /* do not allow passive to be set higher than critical */
+       if (temp < 0 || temp > data->temp_critical)
                return -EINVAL;
 
        data->temp_passive = temp;
@@ -404,17 +403,39 @@ static int imx_get_sensor_data(struct platform_device *pdev)
        data->c1 = temp64;
        data->c2 = n1 * data->c1 + 1000 * t1;
 
-       /*
-        * Set the default passive cooling trip point,
-        * can be changed from userspace.
-        */
-       data->temp_passive = IMX_TEMP_PASSIVE;
+       /* use OTP for thermal grade */
+       ret = regmap_read(map, OCOTP_MEM0, &val);
+       if (ret) {
+               dev_err(&pdev->dev, "failed to read temp grade: %d\n", ret);
+               return ret;
+       }
+
+       /* The maximum die temp is specified by the Temperature Grade */
+       switch ((val >> 6) & 0x3) {
+       case 0: /* Commercial (0 to 95C) */
+               data->temp_grade = "Commercial";
+               data->temp_max = 95000;
+               break;
+       case 1: /* Extended Commercial (-20 to 105C) */
+               data->temp_grade = "Extended Commercial";
+               data->temp_max = 105000;
+               break;
+       case 2: /* Industrial (-40 to 105C) */
+               data->temp_grade = "Industrial";
+               data->temp_max = 105000;
+               break;
+       case 3: /* Automotive (-40 to 125C) */
+               data->temp_grade = "Automotive";
+               data->temp_max = 125000;
+               break;
+       }
 
        /*
-        * The maximum die temperature set to 20 C higher than
-        * IMX_TEMP_PASSIVE.
+        * Set the critical trip point at 5C under max
+        * Set the passive trip point at 10C under max (can change via sysfs)
         */
-       data->temp_critical = 1000 * 20 + data->temp_passive;
+       data->temp_critical = data->temp_max - (1000 * 5);
+       data->temp_passive = data->temp_max - (1000 * 10);
 
        return 0;
 }
@@ -551,6 +572,11 @@ static int imx_thermal_probe(struct platform_device *pdev)
                return ret;
        }
 
+       dev_info(&pdev->dev, "%s CPU temperature grade - max:%dC"
+                " critical:%dC passive:%dC\n", data->temp_grade,
+                data->temp_max / 1000, data->temp_critical / 1000,
+                data->temp_passive / 1000);
+
        /* Enable measurements at ~ 10 Hz */
        regmap_write(map, TEMPSENSE1 + REG_CLR, TEMPSENSE1_MEASURE_FREQ);
        measure_freq = DIV_ROUND_UP(32768, 10); /* 10 Hz */
index 42b7d4253b9446511150c6b599ac548f82e04f1a..be4eedcb839ac22158fe180c2abc37df712d9511 100644 (file)
@@ -964,7 +964,7 @@ void of_thermal_destroy_zones(void)
 
        np = of_find_node_by_name(NULL, "thermal-zones");
        if (!np) {
-               pr_err("unable to find thermal zones\n");
+               pr_debug("unable to find thermal zones\n");
                return;
        }
 
index f0fbea386869a66d9ab60fdcc7f74d7e0179b095..1246aa6fcab0caeda03ace6806c4df2d46c1f164 100644 (file)
@@ -174,7 +174,6 @@ static void estimate_pid_constants(struct thermal_zone_device *tz,
 /**
  * pid_controller() - PID controller
  * @tz:        thermal zone we are operating in
- * @current_temp:      the current temperature in millicelsius
  * @control_temp:      the target temperature in millicelsius
  * @max_allocatable_power:     maximum allocatable power for this thermal zone
  *
@@ -191,7 +190,6 @@ static void estimate_pid_constants(struct thermal_zone_device *tz,
  * Return: The power budget for the next period.
  */
 static u32 pid_controller(struct thermal_zone_device *tz,
-                         int current_temp,
                          int control_temp,
                          u32 max_allocatable_power)
 {
@@ -211,7 +209,7 @@ static u32 pid_controller(struct thermal_zone_device *tz,
                                       true);
        }
 
-       err = control_temp - current_temp;
+       err = control_temp - tz->temperature;
        err = int_to_frac(err);
 
        /* Calculate the proportional term */
@@ -332,7 +330,6 @@ static void divvy_up_power(u32 *req_power, u32 *max_power, int num_actors,
 }
 
 static int allocate_power(struct thermal_zone_device *tz,
-                         int current_temp,
                          int control_temp)
 {
        struct thermal_instance *instance;
@@ -418,8 +415,7 @@ static int allocate_power(struct thermal_zone_device *tz,
                i++;
        }
 
-       power_range = pid_controller(tz, current_temp, control_temp,
-                                    max_allocatable_power);
+       power_range = pid_controller(tz, control_temp, max_allocatable_power);
 
        divvy_up_power(weighted_req_power, max_power, num_actors,
                       total_weighted_req_power, power_range, granted_power,
@@ -444,8 +440,8 @@ static int allocate_power(struct thermal_zone_device *tz,
        trace_thermal_power_allocator(tz, req_power, total_req_power,
                                      granted_power, total_granted_power,
                                      num_actors, power_range,
-                                     max_allocatable_power, current_temp,
-                                     control_temp - current_temp);
+                                     max_allocatable_power, tz->temperature,
+                                     control_temp - tz->temperature);
 
        kfree(req_power);
 unlock:
@@ -612,7 +608,7 @@ static void power_allocator_unbind(struct thermal_zone_device *tz)
 static int power_allocator_throttle(struct thermal_zone_device *tz, int trip)
 {
        int ret;
-       int switch_on_temp, control_temp, current_temp;
+       int switch_on_temp, control_temp;
        struct power_allocator_params *params = tz->governor_data;
 
        /*
@@ -622,15 +618,9 @@ static int power_allocator_throttle(struct thermal_zone_device *tz, int trip)
        if (trip != params->trip_max_desired_temperature)
                return 0;
 
-       ret = thermal_zone_get_temp(tz, &current_temp);
-       if (ret) {
-               dev_warn(&tz->device, "Failed to get temperature: %d\n", ret);
-               return ret;
-       }
-
        ret = tz->ops->get_trip_temp(tz, params->trip_switch_on,
                                     &switch_on_temp);
-       if (!ret && (current_temp < switch_on_temp)) {
+       if (!ret && (tz->temperature < switch_on_temp)) {
                tz->passive = 0;
                reset_pid_controller(params);
                allow_maximum_power(tz);
@@ -648,7 +638,7 @@ static int power_allocator_throttle(struct thermal_zone_device *tz, int trip)
                return ret;
        }
 
-       return allocate_power(tz, current_temp, control_temp);
+       return allocate_power(tz, control_temp);
 }
 
 static struct thermal_governor thermal_gov_power_allocator = {
index 5d4ae7d705e0024528c8d52d56134bd92e280ea1..13d01edc7a043812611719bf7a342260f09ababa 100644 (file)
@@ -361,6 +361,24 @@ static irqreturn_t rcar_thermal_irq(int irq, void *data)
 /*
  *             platform functions
  */
+static int rcar_thermal_remove(struct platform_device *pdev)
+{
+       struct rcar_thermal_common *common = platform_get_drvdata(pdev);
+       struct device *dev = &pdev->dev;
+       struct rcar_thermal_priv *priv;
+
+       rcar_thermal_for_each_priv(priv, common) {
+               if (rcar_has_irq_support(priv))
+                       rcar_thermal_irq_disable(priv);
+               thermal_zone_device_unregister(priv->zone);
+       }
+
+       pm_runtime_put(dev);
+       pm_runtime_disable(dev);
+
+       return 0;
+}
+
 static int rcar_thermal_probe(struct platform_device *pdev)
 {
        struct rcar_thermal_common *common;
@@ -377,6 +395,8 @@ static int rcar_thermal_probe(struct platform_device *pdev)
        if (!common)
                return -ENOMEM;
 
+       platform_set_drvdata(pdev, common);
+
        INIT_LIST_HEAD(&common->head);
        spin_lock_init(&common->lock);
        common->dev = dev;
@@ -454,43 +474,16 @@ static int rcar_thermal_probe(struct platform_device *pdev)
                rcar_thermal_common_write(common, ENR, enr_bits);
        }
 
-       platform_set_drvdata(pdev, common);
-
        dev_info(dev, "%d sensor probed\n", i);
 
        return 0;
 
 error_unregister:
-       rcar_thermal_for_each_priv(priv, common) {
-               if (rcar_has_irq_support(priv))
-                       rcar_thermal_irq_disable(priv);
-               thermal_zone_device_unregister(priv->zone);
-       }
-
-       pm_runtime_put(dev);
-       pm_runtime_disable(dev);
+       rcar_thermal_remove(pdev);
 
        return ret;
 }
 
-static int rcar_thermal_remove(struct platform_device *pdev)
-{
-       struct rcar_thermal_common *common = platform_get_drvdata(pdev);
-       struct device *dev = &pdev->dev;
-       struct rcar_thermal_priv *priv;
-
-       rcar_thermal_for_each_priv(priv, common) {
-               if (rcar_has_irq_support(priv))
-                       rcar_thermal_irq_disable(priv);
-               thermal_zone_device_unregister(priv->zone);
-       }
-
-       pm_runtime_put(dev);
-       pm_runtime_disable(dev);
-
-       return 0;
-}
-
 static const struct of_device_id rcar_thermal_dt_ids[] = {
        { .compatible = "renesas,rcar-thermal", },
        {},
index 9787e8aa509fc406ab4fe5c8ff46811bac19b2de..e845841ab036cc82033d0a6829058a0f15f2543e 100644 (file)
@@ -1,6 +1,9 @@
 /*
  * Copyright (c) 2014, Fuzhou Rockchip Electronics Co., Ltd
  *
+ * Copyright (c) 2015, Fuzhou Rockchip Electronics Co., Ltd
+ * Caesar Wang <wxt@rock-chips.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.
@@ -45,17 +48,50 @@ enum tshut_polarity {
 };
 
 /**
- * The system has three Temperature Sensors.  channel 0 is reserved,
- * channel 1 is for CPU, and channel 2 is for GPU.
+ * The system has two Temperature Sensors.
+ * sensor0 is for CPU, and sensor1 is for GPU.
  */
 enum sensor_id {
-       SENSOR_CPU = 1,
+       SENSOR_CPU = 0,
        SENSOR_GPU,
 };
 
+/**
+* The conversion table has the adc value and temperature.
+* ADC_DECREMENT is the adc value decremnet.(e.g. v2_code_table)
+* ADC_INCREMNET is the adc value incremnet.(e.g. v3_code_table)
+*/
+enum adc_sort_mode {
+       ADC_DECREMENT = 0,
+       ADC_INCREMENT,
+};
+
+/**
+ * The max sensors is two in rockchip SoCs.
+ * Two sensors: CPU and GPU sensor.
+ */
+#define SOC_MAX_SENSORS        2
+
+struct chip_tsadc_table {
+       const struct tsadc_table *id;
+
+       /* the array table size*/
+       unsigned int length;
+
+       /* that analogic mask data */
+       u32 data_mask;
+
+       /* the sort mode is adc value that increment or decrement in table */
+       enum adc_sort_mode mode;
+};
+
 struct rockchip_tsadc_chip {
+       /* The sensor id of chip correspond to the ADC channel */
+       int chn_id[SOC_MAX_SENSORS];
+       int chn_num;
+
        /* The hardware-controlled tshut property */
-       long tshut_temp;
+       int tshut_temp;
        enum tshut_mode tshut_mode;
        enum tshut_polarity tshut_polarity;
 
@@ -65,37 +101,40 @@ struct rockchip_tsadc_chip {
        void (*control)(void __iomem *reg, bool on);
 
        /* Per-sensor methods */
-       int (*get_temp)(int chn, void __iomem *reg, int *temp);
-       void (*set_tshut_temp)(int chn, void __iomem *reg, long temp);
+       int (*get_temp)(struct chip_tsadc_table table,
+                       int chn, void __iomem *reg, int *temp);
+       void (*set_tshut_temp)(struct chip_tsadc_table table,
+                              int chn, void __iomem *reg, int temp);
        void (*set_tshut_mode)(int chn, void __iomem *reg, enum tshut_mode m);
+
+       /* Per-table methods */
+       struct chip_tsadc_table table;
 };
 
 struct rockchip_thermal_sensor {
        struct rockchip_thermal_data *thermal;
        struct thermal_zone_device *tzd;
-       enum sensor_id id;
+       int id;
 };
 
-#define NUM_SENSORS    2 /* Ignore unused sensor 0 */
-
 struct rockchip_thermal_data {
        const struct rockchip_tsadc_chip *chip;
        struct platform_device *pdev;
        struct reset_control *reset;
 
-       struct rockchip_thermal_sensor sensors[NUM_SENSORS];
+       struct rockchip_thermal_sensor sensors[SOC_MAX_SENSORS];
 
        struct clk *clk;
        struct clk *pclk;
 
        void __iomem *regs;
 
-       long tshut_temp;
+       int tshut_temp;
        enum tshut_mode tshut_mode;
        enum tshut_polarity tshut_polarity;
 };
 
-/* TSADC V2 Sensor info define: */
+/* TSADC Sensor info define: */
 #define TSADCV2_AUTO_CON                       0x04
 #define TSADCV2_INT_EN                         0x08
 #define TSADCV2_INT_PD                         0x0c
@@ -117,6 +156,8 @@ struct rockchip_thermal_data {
 #define TSADCV2_INT_PD_CLEAR_MASK              ~BIT(8)
 
 #define TSADCV2_DATA_MASK                      0xfff
+#define TSADCV3_DATA_MASK                      0x3ff
+
 #define TSADCV2_HIGHT_INT_DEBOUNCE_COUNT       4
 #define TSADCV2_HIGHT_TSHUT_DEBOUNCE_COUNT     4
 #define TSADCV2_AUTO_PERIOD_TIME               250 /* msec */
@@ -124,7 +165,7 @@ struct rockchip_thermal_data {
 
 struct tsadc_table {
        u32 code;
-       long temp;
+       int temp;
 };
 
 static const struct tsadc_table v2_code_table[] = {
@@ -165,21 +206,61 @@ static const struct tsadc_table v2_code_table[] = {
        {3421, 125000},
 };
 
-static u32 rk_tsadcv2_temp_to_code(long temp)
+static const struct tsadc_table v3_code_table[] = {
+       {0, -40000},
+       {106, -40000},
+       {108, -35000},
+       {110, -30000},
+       {112, -25000},
+       {114, -20000},
+       {116, -15000},
+       {118, -10000},
+       {120, -5000},
+       {122, 0},
+       {124, 5000},
+       {126, 10000},
+       {128, 15000},
+       {130, 20000},
+       {132, 25000},
+       {134, 30000},
+       {136, 35000},
+       {138, 40000},
+       {140, 45000},
+       {142, 50000},
+       {144, 55000},
+       {146, 60000},
+       {148, 65000},
+       {150, 70000},
+       {152, 75000},
+       {154, 80000},
+       {156, 85000},
+       {158, 90000},
+       {160, 95000},
+       {162, 100000},
+       {163, 105000},
+       {165, 110000},
+       {167, 115000},
+       {169, 120000},
+       {171, 125000},
+       {TSADCV3_DATA_MASK, 125000},
+};
+
+static u32 rk_tsadcv2_temp_to_code(struct chip_tsadc_table table,
+                                  int temp)
 {
        int high, low, mid;
 
        low = 0;
-       high = ARRAY_SIZE(v2_code_table) - 1;
+       high = table.length - 1;
        mid = (high + low) / 2;
 
-       if (temp < v2_code_table[low].temp || temp > v2_code_table[high].temp)
+       if (temp < table.id[low].temp || temp > table.id[high].temp)
                return 0;
 
        while (low <= high) {
-               if (temp == v2_code_table[mid].temp)
-                       return v2_code_table[mid].code;
-               else if (temp < v2_code_table[mid].temp)
+               if (temp == table.id[mid].temp)
+                       return table.id[mid].code;
+               else if (temp < table.id[mid].temp)
                        high = mid - 1;
                else
                        low = mid + 1;
@@ -189,29 +270,54 @@ static u32 rk_tsadcv2_temp_to_code(long temp)
        return 0;
 }
 
-static int rk_tsadcv2_code_to_temp(u32 code, int *temp)
+static int rk_tsadcv2_code_to_temp(struct chip_tsadc_table table, u32 code,
+                                  int *temp)
 {
        unsigned int low = 1;
-       unsigned int high = ARRAY_SIZE(v2_code_table) - 1;
+       unsigned int high = table.length - 1;
        unsigned int mid = (low + high) / 2;
        unsigned int num;
        unsigned long denom;
 
-       BUILD_BUG_ON(ARRAY_SIZE(v2_code_table) < 2);
-
-       code &= TSADCV2_DATA_MASK;
-       if (code < v2_code_table[high].code)
-               return -EAGAIN;         /* Incorrect reading */
-
-       while (low <= high) {
-               if (code >= v2_code_table[mid].code &&
-                   code < v2_code_table[mid - 1].code)
-                       break;
-               else if (code < v2_code_table[mid].code)
-                       low = mid + 1;
-               else
-                       high = mid - 1;
-               mid = (low + high) / 2;
+       WARN_ON(table.length < 2);
+
+       switch (table.mode) {
+       case ADC_DECREMENT:
+               code &= table.data_mask;
+               if (code < table.id[high].code)
+                       return -EAGAIN;         /* Incorrect reading */
+
+               while (low <= high) {
+                       if (code >= table.id[mid].code &&
+                           code < table.id[mid - 1].code)
+                               break;
+                       else if (code < table.id[mid].code)
+                               low = mid + 1;
+                       else
+                               high = mid - 1;
+
+                       mid = (low + high) / 2;
+               }
+               break;
+       case ADC_INCREMENT:
+               code &= table.data_mask;
+               if (code < table.id[low].code)
+                       return -EAGAIN;         /* Incorrect reading */
+
+               while (low <= high) {
+                       if (code >= table.id[mid - 1].code &&
+                           code < table.id[mid].code)
+                               break;
+                       else if (code > table.id[mid].code)
+                               low = mid + 1;
+                       else
+                               high = mid - 1;
+
+                       mid = (low + high) / 2;
+               }
+               break;
+       default:
+               pr_err("Invalid the conversion table\n");
        }
 
        /*
@@ -220,24 +326,28 @@ static int rk_tsadcv2_code_to_temp(u32 code, int *temp)
         * temperature between 2 table entries is linear and interpolate
         * to produce less granular result.
         */
-       num = v2_code_table[mid].temp - v2_code_table[mid - 1].temp;
-       num *= v2_code_table[mid - 1].code - code;
-       denom = v2_code_table[mid - 1].code - v2_code_table[mid].code;
-       *temp = v2_code_table[mid - 1].temp + (num / denom);
+       num = table.id[mid].temp - v2_code_table[mid - 1].temp;
+       num *= abs(table.id[mid - 1].code - code);
+       denom = abs(table.id[mid - 1].code - table.id[mid].code);
+       *temp = table.id[mid - 1].temp + (num / denom);
 
        return 0;
 }
 
 /**
- * rk_tsadcv2_initialize - initialize TASDC Controller
- * (1) Set TSADCV2_AUTO_PERIOD, configure the interleave between
- * every two accessing of TSADC in normal operation.
- * (2) Set TSADCV2_AUTO_PERIOD_HT, configure the interleave between
- * every two accessing of TSADC after the temperature is higher
- * than COM_SHUT or COM_INT.
- * (3) Set TSADCV2_HIGH_INT_DEBOUNCE and TSADC_HIGHT_TSHUT_DEBOUNCE,
- * if the temperature is higher than COMP_INT or COMP_SHUT for
- * "debounce" times, TSADC controller will generate interrupt or TSHUT.
+ * rk_tsadcv2_initialize - initialize TASDC Controller.
+ *
+ * (1) Set TSADC_V2_AUTO_PERIOD:
+ *     Configure the interleave between every two accessing of
+ *     TSADC in normal operation.
+ *
+ * (2) Set TSADCV2_AUTO_PERIOD_HT:
+ *     Configure the interleave between every two accessing of
+ *     TSADC after the temperature is higher than COM_SHUT or COM_INT.
+ *
+ * (3) Set TSADCV2_HIGH_INT_DEBOUNCE and TSADC_HIGHT_TSHUT_DEBOUNCE:
+ *     If the temperature is higher than COMP_INT or COMP_SHUT for
+ *     "debounce" times, TSADC controller will generate interrupt or TSHUT.
  */
 static void rk_tsadcv2_initialize(void __iomem *regs,
                                  enum tshut_polarity tshut_polarity)
@@ -279,20 +389,22 @@ static void rk_tsadcv2_control(void __iomem *regs, bool enable)
        writel_relaxed(val, regs + TSADCV2_AUTO_CON);
 }
 
-static int rk_tsadcv2_get_temp(int chn, void __iomem *regs, int *temp)
+static int rk_tsadcv2_get_temp(struct chip_tsadc_table table,
+                              int chn, void __iomem *regs, int *temp)
 {
        u32 val;
 
        val = readl_relaxed(regs + TSADCV2_DATA(chn));
 
-       return rk_tsadcv2_code_to_temp(val, temp);
+       return rk_tsadcv2_code_to_temp(table, val, temp);
 }
 
-static void rk_tsadcv2_tshut_temp(int chn, void __iomem *regs, long temp)
+static void rk_tsadcv2_tshut_temp(struct chip_tsadc_table table,
+                                 int chn, void __iomem *regs, int temp)
 {
        u32 tshut_value, val;
 
-       tshut_value = rk_tsadcv2_temp_to_code(temp);
+       tshut_value = rk_tsadcv2_temp_to_code(table, temp);
        writel_relaxed(tshut_value, regs + TSADCV2_COMP_SHUT(chn));
 
        /* TSHUT will be valid */
@@ -318,6 +430,10 @@ static void rk_tsadcv2_tshut_mode(int chn, void __iomem *regs,
 }
 
 static const struct rockchip_tsadc_chip rk3288_tsadc_data = {
+       .chn_id[SENSOR_CPU] = 1, /* cpu sensor is channel 1 */
+       .chn_id[SENSOR_GPU] = 2, /* gpu sensor is channel 2 */
+       .chn_num = 2, /* two channels for tsadc */
+
        .tshut_mode = TSHUT_MODE_GPIO, /* default TSHUT via GPIO give PMIC */
        .tshut_polarity = TSHUT_LOW_ACTIVE, /* default TSHUT LOW ACTIVE */
        .tshut_temp = 95000,
@@ -328,6 +444,37 @@ static const struct rockchip_tsadc_chip rk3288_tsadc_data = {
        .get_temp = rk_tsadcv2_get_temp,
        .set_tshut_temp = rk_tsadcv2_tshut_temp,
        .set_tshut_mode = rk_tsadcv2_tshut_mode,
+
+       .table = {
+               .id = v2_code_table,
+               .length = ARRAY_SIZE(v2_code_table),
+               .data_mask = TSADCV2_DATA_MASK,
+               .mode = ADC_DECREMENT,
+       },
+};
+
+static const struct rockchip_tsadc_chip rk3368_tsadc_data = {
+       .chn_id[SENSOR_CPU] = 0, /* cpu sensor is channel 0 */
+       .chn_id[SENSOR_GPU] = 1, /* gpu sensor is channel 1 */
+       .chn_num = 2, /* two channels for tsadc */
+
+       .tshut_mode = TSHUT_MODE_GPIO, /* default TSHUT via GPIO give PMIC */
+       .tshut_polarity = TSHUT_LOW_ACTIVE, /* default TSHUT LOW ACTIVE */
+       .tshut_temp = 95000,
+
+       .initialize = rk_tsadcv2_initialize,
+       .irq_ack = rk_tsadcv2_irq_ack,
+       .control = rk_tsadcv2_control,
+       .get_temp = rk_tsadcv2_get_temp,
+       .set_tshut_temp = rk_tsadcv2_tshut_temp,
+       .set_tshut_mode = rk_tsadcv2_tshut_mode,
+
+       .table = {
+               .id = v3_code_table,
+               .length = ARRAY_SIZE(v3_code_table),
+               .data_mask = TSADCV3_DATA_MASK,
+               .mode = ADC_INCREMENT,
+       },
 };
 
 static const struct of_device_id of_rockchip_thermal_match[] = {
@@ -335,6 +482,10 @@ static const struct of_device_id of_rockchip_thermal_match[] = {
                .compatible = "rockchip,rk3288-tsadc",
                .data = (void *)&rk3288_tsadc_data,
        },
+       {
+               .compatible = "rockchip,rk3368-tsadc",
+               .data = (void *)&rk3368_tsadc_data,
+       },
        { /* end */ },
 };
 MODULE_DEVICE_TABLE(of, of_rockchip_thermal_match);
@@ -357,7 +508,7 @@ static irqreturn_t rockchip_thermal_alarm_irq_thread(int irq, void *dev)
 
        thermal->chip->irq_ack(thermal->regs);
 
-       for (i = 0; i < ARRAY_SIZE(thermal->sensors); i++)
+       for (i = 0; i < thermal->chip->chn_num; i++)
                thermal_zone_device_update(thermal->sensors[i].tzd);
 
        return IRQ_HANDLED;
@@ -370,7 +521,8 @@ static int rockchip_thermal_get_temp(void *_sensor, int *out_temp)
        const struct rockchip_tsadc_chip *tsadc = sensor->thermal->chip;
        int retval;
 
-       retval = tsadc->get_temp(sensor->id, thermal->regs, out_temp);
+       retval = tsadc->get_temp(tsadc->table,
+                                sensor->id, thermal->regs, out_temp);
        dev_dbg(&thermal->pdev->dev, "sensor %d - temp: %d, retval: %d\n",
                sensor->id, *out_temp, retval);
 
@@ -389,7 +541,7 @@ static int rockchip_configure_from_dt(struct device *dev,
 
        if (of_property_read_u32(np, "rockchip,hw-tshut-temp", &shut_temp)) {
                dev_warn(dev,
-                        "Missing tshut temp property, using default %ld\n",
+                        "Missing tshut temp property, using default %d\n",
                         thermal->chip->tshut_temp);
                thermal->tshut_temp = thermal->chip->tshut_temp;
        } else {
@@ -397,7 +549,7 @@ static int rockchip_configure_from_dt(struct device *dev,
        }
 
        if (thermal->tshut_temp > INT_MAX) {
-               dev_err(dev, "Invalid tshut temperature specified: %ld\n",
+               dev_err(dev, "Invalid tshut temperature specified: %d\n",
                        thermal->tshut_temp);
                return -ERANGE;
        }
@@ -442,13 +594,14 @@ static int
 rockchip_thermal_register_sensor(struct platform_device *pdev,
                                 struct rockchip_thermal_data *thermal,
                                 struct rockchip_thermal_sensor *sensor,
-                                enum sensor_id id)
+                                int id)
 {
        const struct rockchip_tsadc_chip *tsadc = thermal->chip;
        int error;
 
        tsadc->set_tshut_mode(id, thermal->regs, thermal->tshut_mode);
-       tsadc->set_tshut_temp(id, thermal->regs, thermal->tshut_temp);
+       tsadc->set_tshut_temp(tsadc->table, id, thermal->regs,
+                             thermal->tshut_temp);
 
        sensor->thermal = thermal;
        sensor->id = id;
@@ -481,7 +634,7 @@ static int rockchip_thermal_probe(struct platform_device *pdev)
        const struct of_device_id *match;
        struct resource *res;
        int irq;
-       int i;
+       int i, j;
        int error;
 
        match = of_match_node(of_rockchip_thermal_match, np);
@@ -556,22 +709,19 @@ static int rockchip_thermal_probe(struct platform_device *pdev)
 
        thermal->chip->initialize(thermal->regs, thermal->tshut_polarity);
 
-       error = rockchip_thermal_register_sensor(pdev, thermal,
-                                                &thermal->sensors[0],
-                                                SENSOR_CPU);
-       if (error) {
-               dev_err(&pdev->dev,
-                       "failed to register CPU thermal sensor: %d\n", error);
-               goto err_disable_pclk;
-       }
-
-       error = rockchip_thermal_register_sensor(pdev, thermal,
-                                                &thermal->sensors[1],
-                                                SENSOR_GPU);
-       if (error) {
-               dev_err(&pdev->dev,
-                       "failed to register GPU thermal sensor: %d\n", error);
-               goto err_unregister_cpu_sensor;
+       for (i = 0; i < thermal->chip->chn_num; i++) {
+               error = rockchip_thermal_register_sensor(pdev, thermal,
+                                               &thermal->sensors[i],
+                                               thermal->chip->chn_id[i]);
+               if (error) {
+                       dev_err(&pdev->dev,
+                               "failed to register sensor[%d] : error = %d\n",
+                               i, error);
+                       for (j = 0; j < i; j++)
+                               thermal_zone_of_sensor_unregister(&pdev->dev,
+                                               thermal->sensors[j].tzd);
+                       goto err_disable_pclk;
+               }
        }
 
        error = devm_request_threaded_irq(&pdev->dev, irq, NULL,
@@ -581,22 +731,23 @@ static int rockchip_thermal_probe(struct platform_device *pdev)
        if (error) {
                dev_err(&pdev->dev,
                        "failed to request tsadc irq: %d\n", error);
-               goto err_unregister_gpu_sensor;
+               goto err_unregister_sensor;
        }
 
        thermal->chip->control(thermal->regs, true);
 
-       for (i = 0; i < ARRAY_SIZE(thermal->sensors); i++)
+       for (i = 0; i < thermal->chip->chn_num; i++)
                rockchip_thermal_toggle_sensor(&thermal->sensors[i], true);
 
        platform_set_drvdata(pdev, thermal);
 
        return 0;
 
-err_unregister_gpu_sensor:
-       thermal_zone_of_sensor_unregister(&pdev->dev, thermal->sensors[1].tzd);
-err_unregister_cpu_sensor:
-       thermal_zone_of_sensor_unregister(&pdev->dev, thermal->sensors[0].tzd);
+err_unregister_sensor:
+       while (i--)
+               thermal_zone_of_sensor_unregister(&pdev->dev,
+                                                 thermal->sensors[i].tzd);
+
 err_disable_pclk:
        clk_disable_unprepare(thermal->pclk);
 err_disable_clk:
@@ -610,7 +761,7 @@ static int rockchip_thermal_remove(struct platform_device *pdev)
        struct rockchip_thermal_data *thermal = platform_get_drvdata(pdev);
        int i;
 
-       for (i = 0; i < ARRAY_SIZE(thermal->sensors); i++) {
+       for (i = 0; i < thermal->chip->chn_num; i++) {
                struct rockchip_thermal_sensor *sensor = &thermal->sensors[i];
 
                rockchip_thermal_toggle_sensor(sensor, false);
@@ -631,7 +782,7 @@ static int __maybe_unused rockchip_thermal_suspend(struct device *dev)
        struct rockchip_thermal_data *thermal = platform_get_drvdata(pdev);
        int i;
 
-       for (i = 0; i < ARRAY_SIZE(thermal->sensors); i++)
+       for (i = 0; i < thermal->chip->chn_num; i++)
                rockchip_thermal_toggle_sensor(&thermal->sensors[i], false);
 
        thermal->chip->control(thermal->regs, false);
@@ -663,18 +814,19 @@ static int __maybe_unused rockchip_thermal_resume(struct device *dev)
 
        thermal->chip->initialize(thermal->regs, thermal->tshut_polarity);
 
-       for (i = 0; i < ARRAY_SIZE(thermal->sensors); i++) {
-               enum sensor_id id = thermal->sensors[i].id;
+       for (i = 0; i < thermal->chip->chn_num; i++) {
+               int id = thermal->sensors[i].id;
 
                thermal->chip->set_tshut_mode(id, thermal->regs,
                                              thermal->tshut_mode);
-               thermal->chip->set_tshut_temp(id, thermal->regs,
+               thermal->chip->set_tshut_temp(thermal->chip->table,
+                                             id, thermal->regs,
                                              thermal->tshut_temp);
        }
 
        thermal->chip->control(thermal->regs, true);
 
-       for (i = 0; i < ARRAY_SIZE(thermal->sensors); i++)
+       for (i = 0; i < thermal->chip->chn_num; i++)
                rockchip_thermal_toggle_sensor(&thermal->sensors[i], true);
 
        pinctrl_pm_select_default_state(dev);
index 13844261cd5f3cdad44131a3e215f97d2ecae2f4..e49c2bce551d31db115b97f0a12807339258b69b 100644 (file)
@@ -169,7 +169,7 @@ static inline int tty_copy_to_user(struct tty_struct *tty,
 {
        struct n_tty_data *ldata = tty->disc_data;
 
-       tty_audit_add_data(tty, to, n, ldata->icanon);
+       tty_audit_add_data(tty, from, n, ldata->icanon);
        return copy_to_user(to, from, n);
 }
 
@@ -2054,13 +2054,13 @@ static int canon_copy_from_read_buf(struct tty_struct *tty,
        size_t eol;
        size_t tail;
        int ret, found = 0;
-       bool eof_push = 0;
 
        /* N.B. avoid overrun if nr == 0 */
-       n = min(*nr, smp_load_acquire(&ldata->canon_head) - ldata->read_tail);
-       if (!n)
+       if (!*nr)
                return 0;
 
+       n = min(*nr + 1, smp_load_acquire(&ldata->canon_head) - ldata->read_tail);
+
        tail = ldata->read_tail & (N_TTY_BUF_SIZE - 1);
        size = min_t(size_t, tail + n, N_TTY_BUF_SIZE);
 
@@ -2081,12 +2081,11 @@ static int canon_copy_from_read_buf(struct tty_struct *tty,
        n = eol - tail;
        if (n > N_TTY_BUF_SIZE)
                n += N_TTY_BUF_SIZE;
-       n += found;
-       c = n;
+       c = n + found;
 
-       if (found && !ldata->push && read_buf(ldata, eol) == __DISABLED_CHAR) {
-               n--;
-               eof_push = !n && ldata->read_tail != ldata->line_start;
+       if (!found || read_buf(ldata, eol) != __DISABLED_CHAR) {
+               c = min(*nr, c);
+               n = c;
        }
 
        n_tty_trace("%s: eol:%zu found:%d n:%zu c:%zu size:%zu more:%zu\n",
@@ -2116,7 +2115,7 @@ static int canon_copy_from_read_buf(struct tty_struct *tty,
                        ldata->push = 0;
                tty_audit_push(tty);
        }
-       return eof_push ? -EAGAIN : 0;
+       return 0;
 }
 
 extern ssize_t redirected_tty_write(struct file *, const char __user *,
@@ -2273,10 +2272,7 @@ static ssize_t n_tty_read(struct tty_struct *tty, struct file *file,
 
                if (ldata->icanon && !L_EXTPROC(tty)) {
                        retval = canon_copy_from_read_buf(tty, &b, &nr);
-                       if (retval == -EAGAIN) {
-                               retval = 0;
-                               continue;
-                       } else if (retval)
+                       if (retval)
                                break;
                } else {
                        int uncopied;
index c0533a57ec539f60768bdbed0aa49e929aaa16bd..910bfee5a88b7f07f5a4c00aad47a45361a1d19b 100644 (file)
@@ -60,3 +60,4 @@ int fsl8250_handle_irq(struct uart_port *port)
        spin_unlock_irqrestore(&up->port.lock, flags);
        return 1;
 }
+EXPORT_SYMBOL_GPL(fsl8250_handle_irq);
index d11621e2cf1df083ca4c58309ef610df6c9c70fa..245edbb68d4ba5fe98e6e8fa915bf518cc4f28a5 100644 (file)
@@ -115,12 +115,16 @@ static void uniphier_serial_out(struct uart_port *p, int offset, int value)
  */
 static int uniphier_serial_dl_read(struct uart_8250_port *up)
 {
-       return readl(up->port.membase + UNIPHIER_UART_DLR);
+       int offset = UNIPHIER_UART_DLR << up->port.regshift;
+
+       return readl(up->port.membase + offset);
 }
 
 static void uniphier_serial_dl_write(struct uart_8250_port *up, int value)
 {
-       writel(value, up->port.membase + UNIPHIER_UART_DLR);
+       int offset = UNIPHIER_UART_DLR << up->port.regshift;
+
+       writel(value, up->port.membase + offset);
 }
 
 static int uniphier_of_serial_setup(struct device *dev, struct uart_port *port,
index e6f5e12a2d83bcc5c03b3e2b81caf50f70721467..6412f1455beb3622f27e1738a468ff93d00fedfc 100644 (file)
@@ -373,6 +373,7 @@ config SERIAL_8250_MID
        depends on SERIAL_8250 && PCI
        select HSU_DMA if SERIAL_8250_DMA
        select HSU_DMA_PCI if X86_INTEL_MID
+       select RATIONAL
        help
          Selecting this option will enable handling of the extra features
          present on the UART found on Intel Medfield SOC and various other
index 1aec4404062d8f1995e8da8da821a1b176cb0e7a..f38beb28e7ae60e87316754b555ba08e2e77a3ac 100644 (file)
@@ -1539,7 +1539,6 @@ config SERIAL_FSL_LPUART
        tristate "Freescale lpuart serial port support"
        depends on HAS_DMA
        select SERIAL_CORE
-       select SERIAL_EARLYCON
        help
          Support for the on-chip lpuart on some Freescale SOCs.
 
@@ -1547,6 +1546,7 @@ config SERIAL_FSL_LPUART_CONSOLE
        bool "Console on Freescale lpuart serial port"
        depends on SERIAL_FSL_LPUART=y
        select SERIAL_CORE_CONSOLE
+       select SERIAL_EARLYCON
        help
          If you have enabled the lpuart serial port on the Freescale SoCs,
          you can make it the console by answering Y to this option.
index 681e0f3d5e0ef895b0f618a24a40cf138f8f0eca..a1c0a89d9c7f3cfcfd994477e7e7e69aa1755d04 100644 (file)
@@ -474,7 +474,7 @@ static int bcm_uart_startup(struct uart_port *port)
 
        /* register irq and enable rx interrupts */
        ret = request_irq(port->irq, bcm_uart_interrupt, 0,
-                         bcm_uart_type(port), port);
+                         dev_name(port->dev), port);
        if (ret)
                return ret;
        bcm_uart_writel(port, UART_RX_INT_MASK, UART_IR_REG);
index f09636083426d5fc2fdb18a65a2a1af49a0093b7..b5b2f2be6be7c613b5c051c0d9730d3fa3b5e177 100644 (file)
@@ -115,6 +115,7 @@ static int __init register_earlycon(char *buf, const struct earlycon_id *match)
        if (buf && !parse_options(&early_console_dev, buf))
                buf = NULL;
 
+       spin_lock_init(&port->lock);
        port->uartclk = BASE_BAUD * 16;
        if (port->mapbase)
                port->membase = earlycon_map(port->mapbase, 64);
@@ -202,6 +203,7 @@ int __init of_setup_earlycon(unsigned long addr,
        int err;
        struct uart_port *port = &early_console_dev.port;
 
+       spin_lock_init(&port->lock);
        port->iotype = UPIO_MEM;
        port->mapbase = addr;
        port->uartclk = BASE_BAUD * 16;
index 6813e316e9ff3d3e58fb2c68d582a3a285295aa3..2f80bc7e44fb3c4f16210a806c0fcaecee3e3b1c 100644 (file)
@@ -894,7 +894,7 @@ static int etraxfs_uart_probe(struct platform_device *pdev)
        up->regi_ser = of_iomap(np, 0);
        up->port.dev = &pdev->dev;
 
-       up->gpios = mctrl_gpio_init(&pdev->dev, 0);
+       up->gpios = mctrl_gpio_init_noauto(&pdev->dev, 0);
        if (IS_ERR(up->gpios))
                return PTR_ERR(up->gpios);
 
index 960e50a97558cff52a1fb9eb8ed8879a5238991c..51c7507b0444957bcbc9c2c832bd6048a5f3b596 100644 (file)
@@ -1437,7 +1437,7 @@ static void sci_request_dma(struct uart_port *port)
                        sg_init_table(sg, 1);
                        s->rx_buf[i] = buf;
                        sg_dma_address(sg) = dma;
-                       sg->length = s->buf_len_rx;
+                       sg_dma_len(sg) = s->buf_len_rx;
 
                        buf += s->buf_len_rx;
                        dma += s->buf_len_rx;
index 064031870ba0d1b0bf09fd3bcb299d17dcaf76d5..ca0d3802f2af45fb8be9cad11d9763fb615e516a 100644 (file)
@@ -148,8 +148,10 @@ static int receive_chars_read(struct uart_port *port)
                        uart_handle_dcd_change(port, 1);
                }
 
-               for (i = 0; i < bytes_read; i++)
-                       uart_handle_sysrq_char(port, con_read_page[i]);
+               if (port->sysrq != 0 &&  *con_read_page) {
+                       for (i = 0; i < bytes_read; i++)
+                               uart_handle_sysrq_char(port, con_read_page[i]);
+               }
 
                if (port->state == NULL)
                        continue;
@@ -168,17 +170,17 @@ struct sunhv_ops {
        int (*receive_chars)(struct uart_port *port);
 };
 
-static struct sunhv_ops bychar_ops = {
+static const struct sunhv_ops bychar_ops = {
        .transmit_chars = transmit_chars_putchar,
        .receive_chars = receive_chars_getchar,
 };
 
-static struct sunhv_ops bywrite_ops = {
+static const struct sunhv_ops bywrite_ops = {
        .transmit_chars = transmit_chars_write,
        .receive_chars = receive_chars_read,
 };
 
-static struct sunhv_ops *sunhv_ops = &bychar_ops;
+static const struct sunhv_ops *sunhv_ops = &bychar_ops;
 
 static struct tty_port *receive_chars(struct uart_port *port)
 {
index 90ca082935f635236a5c2ca5f4da48b99297b48f..3d245cd3d8e62082301b7061144ec2329cf16609 100644 (file)
@@ -265,7 +265,7 @@ static struct tty_audit_buf *tty_audit_buf_get(struct tty_struct *tty,
  *
  *     Audit @data of @size from @tty, if necessary.
  */
-void tty_audit_add_data(struct tty_struct *tty, unsigned char *data,
+void tty_audit_add_data(struct tty_struct *tty, const void *data,
                        size_t size, unsigned icanon)
 {
        struct tty_audit_buf *buf;
index 9a479e61791a2a80cd0ae3fd5c93c6d0873d6998..3cd31e0d4bd9545b5357cda0ffa14373d181e670 100644 (file)
@@ -450,7 +450,7 @@ receive_buf(struct tty_struct *tty, struct tty_buffer *head, int count)
                count = disc->ops->receive_buf2(tty, p, f, count);
        else {
                count = min_t(int, count, tty->receive_room);
-               if (count)
+               if (count && disc->ops->receive_buf)
                        disc->ops->receive_buf(tty, p, f, count);
        }
        return count;
index 0c41dbcb90b8bc7d8ab430d562206e7c2469411f..bcc8e1e8bb720996cf73438c67a397362173edca 100644 (file)
@@ -1282,18 +1282,22 @@ int tty_send_xchar(struct tty_struct *tty, char ch)
        int     was_stopped = tty->stopped;
 
        if (tty->ops->send_xchar) {
+               down_read(&tty->termios_rwsem);
                tty->ops->send_xchar(tty, ch);
+               up_read(&tty->termios_rwsem);
                return 0;
        }
 
        if (tty_write_lock(tty, 0) < 0)
                return -ERESTARTSYS;
 
+       down_read(&tty->termios_rwsem);
        if (was_stopped)
                start_tty(tty);
        tty->ops->write(tty, &ch, 1);
        if (was_stopped)
                stop_tty(tty);
+       up_read(&tty->termios_rwsem);
        tty_write_unlock(tty);
        return 0;
 }
index 9c5aebfe7053cbcae1fd65a95f3312509525e8e6..1445dd39aa6227ab641130ef7344eaba9f113b86 100644 (file)
@@ -1147,16 +1147,12 @@ int n_tty_ioctl_helper(struct tty_struct *tty, struct file *file,
                        spin_unlock_irq(&tty->flow_lock);
                        break;
                case TCIOFF:
-                       down_read(&tty->termios_rwsem);
                        if (STOP_CHAR(tty) != __DISABLED_CHAR)
                                retval = tty_send_xchar(tty, STOP_CHAR(tty));
-                       up_read(&tty->termios_rwsem);
                        break;
                case TCION:
-                       down_read(&tty->termios_rwsem);
                        if (START_CHAR(tty) != __DISABLED_CHAR)
                                retval = tty_send_xchar(tty, START_CHAR(tty));
-                       up_read(&tty->termios_rwsem);
                        break;
                default:
                        return -EINVAL;
index 5af8f1874c1aab02fc16dbb0950d7264caa282ca..629e3c865072035f14fd4e6ece5a2544bcbf713c 100644 (file)
@@ -592,7 +592,7 @@ int tty_set_ldisc(struct tty_struct *tty, int ldisc)
 
        /* Restart the work queue in case no characters kick it off. Safe if
           already running */
-       schedule_work(&tty->port->buf.work);
+       tty_buffer_restart_work(tty->port);
 
        tty_unlock(tty);
        return retval;
index 6ccbf60cdd5c1204f77072a396d9791c6bfdcc2a..5a048b7b92e8f8c7821f3e0a6880f38ab3259733 100644 (file)
@@ -84,6 +84,12 @@ struct ci_hdrc_imx_data {
        struct imx_usbmisc_data *usbmisc_data;
        bool supports_runtime_pm;
        bool in_lpm;
+       /* SoC before i.mx6 (except imx23/imx28) needs three clks */
+       bool need_three_clks;
+       struct clk *clk_ipg;
+       struct clk *clk_ahb;
+       struct clk *clk_per;
+       /* --------------------------------- */
 };
 
 /* Common functions shared by usbmisc drivers */
@@ -135,6 +141,102 @@ static struct imx_usbmisc_data *usbmisc_get_init_data(struct device *dev)
 }
 
 /* End of common functions shared by usbmisc drivers*/
+static int imx_get_clks(struct device *dev)
+{
+       struct ci_hdrc_imx_data *data = dev_get_drvdata(dev);
+       int ret = 0;
+
+       data->clk_ipg = devm_clk_get(dev, "ipg");
+       if (IS_ERR(data->clk_ipg)) {
+               /* If the platform only needs one clocks */
+               data->clk = devm_clk_get(dev, NULL);
+               if (IS_ERR(data->clk)) {
+                       ret = PTR_ERR(data->clk);
+                       dev_err(dev,
+                               "Failed to get clks, err=%ld,%ld\n",
+                               PTR_ERR(data->clk), PTR_ERR(data->clk_ipg));
+                       return ret;
+               }
+               return ret;
+       }
+
+       data->clk_ahb = devm_clk_get(dev, "ahb");
+       if (IS_ERR(data->clk_ahb)) {
+               ret = PTR_ERR(data->clk_ahb);
+               dev_err(dev,
+                       "Failed to get ahb clock, err=%d\n", ret);
+               return ret;
+       }
+
+       data->clk_per = devm_clk_get(dev, "per");
+       if (IS_ERR(data->clk_per)) {
+               ret = PTR_ERR(data->clk_per);
+               dev_err(dev,
+                       "Failed to get per clock, err=%d\n", ret);
+               return ret;
+       }
+
+       data->need_three_clks = true;
+       return ret;
+}
+
+static int imx_prepare_enable_clks(struct device *dev)
+{
+       struct ci_hdrc_imx_data *data = dev_get_drvdata(dev);
+       int ret = 0;
+
+       if (data->need_three_clks) {
+               ret = clk_prepare_enable(data->clk_ipg);
+               if (ret) {
+                       dev_err(dev,
+                               "Failed to prepare/enable ipg clk, err=%d\n",
+                               ret);
+                       return ret;
+               }
+
+               ret = clk_prepare_enable(data->clk_ahb);
+               if (ret) {
+                       dev_err(dev,
+                               "Failed to prepare/enable ahb clk, err=%d\n",
+                               ret);
+                       clk_disable_unprepare(data->clk_ipg);
+                       return ret;
+               }
+
+               ret = clk_prepare_enable(data->clk_per);
+               if (ret) {
+                       dev_err(dev,
+                               "Failed to prepare/enable per clk, err=%d\n",
+                               ret);
+                       clk_disable_unprepare(data->clk_ahb);
+                       clk_disable_unprepare(data->clk_ipg);
+                       return ret;
+               }
+       } else {
+               ret = clk_prepare_enable(data->clk);
+               if (ret) {
+                       dev_err(dev,
+                               "Failed to prepare/enable clk, err=%d\n",
+                               ret);
+                       return ret;
+               }
+       }
+
+       return ret;
+}
+
+static void imx_disable_unprepare_clks(struct device *dev)
+{
+       struct ci_hdrc_imx_data *data = dev_get_drvdata(dev);
+
+       if (data->need_three_clks) {
+               clk_disable_unprepare(data->clk_per);
+               clk_disable_unprepare(data->clk_ahb);
+               clk_disable_unprepare(data->clk_ipg);
+       } else {
+               clk_disable_unprepare(data->clk);
+       }
+}
 
 static int ci_hdrc_imx_probe(struct platform_device *pdev)
 {
@@ -145,31 +247,31 @@ static int ci_hdrc_imx_probe(struct platform_device *pdev)
                .flags          = CI_HDRC_SET_NON_ZERO_TTHA,
        };
        int ret;
-       const struct of_device_id *of_id =
-                       of_match_device(ci_hdrc_imx_dt_ids, &pdev->dev);
-       const struct ci_hdrc_imx_platform_flag *imx_platform_flag = of_id->data;
+       const struct of_device_id *of_id;
+       const struct ci_hdrc_imx_platform_flag *imx_platform_flag;
+
+       of_id = of_match_device(ci_hdrc_imx_dt_ids, &pdev->dev);
+       if (!of_id)
+               return -ENODEV;
+
+       imx_platform_flag = of_id->data;
 
        data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL);
        if (!data)
                return -ENOMEM;
 
+       platform_set_drvdata(pdev, data);
        data->usbmisc_data = usbmisc_get_init_data(&pdev->dev);
        if (IS_ERR(data->usbmisc_data))
                return PTR_ERR(data->usbmisc_data);
 
-       data->clk = devm_clk_get(&pdev->dev, NULL);
-       if (IS_ERR(data->clk)) {
-               dev_err(&pdev->dev,
-                       "Failed to get clock, err=%ld\n", PTR_ERR(data->clk));
-               return PTR_ERR(data->clk);
-       }
+       ret = imx_get_clks(&pdev->dev);
+       if (ret)
+               return ret;
 
-       ret = clk_prepare_enable(data->clk);
-       if (ret) {
-               dev_err(&pdev->dev,
-                       "Failed to prepare or enable clock, err=%d\n", ret);
+       ret = imx_prepare_enable_clks(&pdev->dev);
+       if (ret)
                return ret;
-       }
 
        data->phy = devm_usb_get_phy_by_phandle(&pdev->dev, "fsl,usbphy", 0);
        if (IS_ERR(data->phy)) {
@@ -212,8 +314,6 @@ static int ci_hdrc_imx_probe(struct platform_device *pdev)
                goto disable_device;
        }
 
-       platform_set_drvdata(pdev, data);
-
        if (data->supports_runtime_pm) {
                pm_runtime_set_active(&pdev->dev);
                pm_runtime_enable(&pdev->dev);
@@ -226,7 +326,7 @@ static int ci_hdrc_imx_probe(struct platform_device *pdev)
 disable_device:
        ci_hdrc_remove_device(data->ci_pdev);
 err_clk:
-       clk_disable_unprepare(data->clk);
+       imx_disable_unprepare_clks(&pdev->dev);
        return ret;
 }
 
@@ -240,7 +340,7 @@ static int ci_hdrc_imx_remove(struct platform_device *pdev)
                pm_runtime_put_noidle(&pdev->dev);
        }
        ci_hdrc_remove_device(data->ci_pdev);
-       clk_disable_unprepare(data->clk);
+       imx_disable_unprepare_clks(&pdev->dev);
 
        return 0;
 }
@@ -252,7 +352,7 @@ static int imx_controller_suspend(struct device *dev)
 
        dev_dbg(dev, "at %s\n", __func__);
 
-       clk_disable_unprepare(data->clk);
+       imx_disable_unprepare_clks(dev);
        data->in_lpm = true;
 
        return 0;
@@ -270,7 +370,7 @@ static int imx_controller_resume(struct device *dev)
                return 0;
        }
 
-       ret = clk_prepare_enable(data->clk);
+       ret = imx_prepare_enable_clks(dev);
        if (ret)
                return ret;
 
@@ -285,7 +385,7 @@ static int imx_controller_resume(struct device *dev)
        return 0;
 
 clk_disable:
-       clk_disable_unprepare(data->clk);
+       imx_disable_unprepare_clks(dev);
        return ret;
 }
 
index 080b7be3daf034939bd12c509353c041b6027f49..58c8485a0715ada6c585a29e23883f25091fa127 100644 (file)
@@ -322,8 +322,10 @@ static ssize_t ci_role_write(struct file *file, const char __user *ubuf,
                return -EINVAL;
 
        pm_runtime_get_sync(ci->dev);
+       disable_irq(ci->irq);
        ci_role_stop(ci);
        ret = ci_role_start(ci, role);
+       enable_irq(ci->irq);
        pm_runtime_put_sync(ci->dev);
 
        return ret ? ret : count;
index 8223fe73ea85926477cf710227fc3907b5ad9ff1..391a1225b0ba330cd818028f240cb151e8ade65c 100644 (file)
@@ -1751,6 +1751,22 @@ static int ci_udc_start(struct usb_gadget *gadget,
        return retval;
 }
 
+static void ci_udc_stop_for_otg_fsm(struct ci_hdrc *ci)
+{
+       if (!ci_otg_is_fsm_mode(ci))
+               return;
+
+       mutex_lock(&ci->fsm.lock);
+       if (ci->fsm.otg->state == OTG_STATE_A_PERIPHERAL) {
+               ci->fsm.a_bidl_adis_tmout = 1;
+               ci_hdrc_otg_fsm_start(ci);
+       } else if (ci->fsm.otg->state == OTG_STATE_B_PERIPHERAL) {
+               ci->fsm.protocol = PROTO_UNDEF;
+               ci->fsm.otg->state = OTG_STATE_UNDEFINED;
+       }
+       mutex_unlock(&ci->fsm.lock);
+}
+
 /**
  * ci_udc_stop: unregister a gadget driver
  */
@@ -1775,6 +1791,7 @@ static int ci_udc_stop(struct usb_gadget *gadget)
        ci->driver = NULL;
        spin_unlock_irqrestore(&ci->lock, flags);
 
+       ci_udc_stop_for_otg_fsm(ci);
        return 0;
 }
 
index fcea4eb36eeedbceac777ecd8d676e5ede74cba6..ab8b027e8cc870615d399abb631849875db72427 100644 (file)
@@ -500,7 +500,11 @@ static int usbmisc_imx_probe(struct platform_device *pdev)
 {
        struct resource *res;
        struct imx_usbmisc *data;
-       struct of_device_id *tmp_dev;
+       const struct of_device_id *of_id;
+
+       of_id = of_match_device(usbmisc_imx_dt_ids, &pdev->dev);
+       if (!of_id)
+               return -ENODEV;
 
        data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL);
        if (!data)
@@ -513,9 +517,7 @@ static int usbmisc_imx_probe(struct platform_device *pdev)
        if (IS_ERR(data->base))
                return PTR_ERR(data->base);
 
-       tmp_dev = (struct of_device_id *)
-               of_match_device(usbmisc_imx_dt_ids, &pdev->dev);
-       data->ops = (const struct usbmisc_ops *)tmp_dev->data;
+       data->ops = (const struct usbmisc_ops *)of_id->data;
        platform_set_drvdata(pdev, data);
 
        return 0;
index b30e7423549b04b0e7d442a128048b4221c68062..26ca4f910cb020aae539f29b260a98fe1eee92b0 100644 (file)
@@ -1838,6 +1838,11 @@ static const struct usb_device_id acm_ids[] = {
        },
 #endif
 
+       /* Exclude Infineon Flash Loader utility */
+       { USB_DEVICE(0x058b, 0x0041),
+       .driver_info = IGNORE_DEVICE,
+       },
+
        /* control interfaces without any protocol set */
        { USB_INTERFACE_INFO(USB_CLASS_COMM, USB_CDC_SUBCLASS_ACM,
                USB_CDC_PROTO_NONE) },
index 433bbc34a8a481ff15c8070e9917ecf1ec1455e8..071964c7847f1fbf148c2cb485fe0750e8518adc 100644 (file)
@@ -884,11 +884,11 @@ static int usblp_wwait(struct usblp *usblp, int nonblock)
 
        add_wait_queue(&usblp->wwait, &waita);
        for (;;) {
-               set_current_state(TASK_INTERRUPTIBLE);
                if (mutex_lock_interruptible(&usblp->mut)) {
                        rc = -EINTR;
                        break;
                }
+               set_current_state(TASK_INTERRUPTIBLE);
                rc = usblp_wtest(usblp, nonblock);
                mutex_unlock(&usblp->mut);
                if (rc <= 0)
index a99c89e781264b2cc260409f9b27d3dbd32a85bf..dd280108758f3aff975f25653119d107b1e6cc3a 100644 (file)
@@ -77,8 +77,7 @@ config USB_OTG_BLACKLIST_HUB
 
 config USB_OTG_FSM
        tristate "USB 2.0 OTG FSM implementation"
-       depends on USB
-       select USB_OTG
+       depends on USB && USB_OTG
        select USB_PHY
        help
          Implements OTG Finite State Machine as specified in On-The-Go
index 7caff020106e23f26f9c3bb9c34585885064848d..5050760f5e17cf3872952ae5fa6a40d01aab394b 100644 (file)
@@ -115,7 +115,8 @@ static void usb_parse_ss_endpoint_companion(struct device *ddev, int cfgno,
                   USB_SS_MULT(desc->bmAttributes) > 3) {
                dev_warn(ddev, "Isoc endpoint has Mult of %d in "
                                "config %d interface %d altsetting %d ep %d: "
-                               "setting to 3\n", desc->bmAttributes + 1,
+                               "setting to 3\n",
+                               USB_SS_MULT(desc->bmAttributes),
                                cfgno, inum, asnum, ep->desc.bEndpointAddress);
                ep->ss_ep_comp.bmAttributes = 2;
        }
index bdeadc112d29f9b4545bf3ab82645b52982f5cfd..ddbf32d599cba4e51aeb81eea8519500a8bbea01 100644 (file)
@@ -124,6 +124,10 @@ struct usb_hub *usb_hub_to_struct_hub(struct usb_device *hdev)
 
 int usb_device_supports_lpm(struct usb_device *udev)
 {
+       /* Some devices have trouble with LPM */
+       if (udev->quirks & USB_QUIRK_NO_LPM)
+               return 0;
+
        /* USB 2.1 (and greater) devices indicate LPM support through
         * their USB 2.0 Extended Capabilities BOS descriptor.
         */
@@ -1031,10 +1035,20 @@ static void hub_activate(struct usb_hub *hub, enum hub_activation_type type)
        unsigned delay;
 
        /* Continue a partial initialization */
-       if (type == HUB_INIT2)
-               goto init2;
-       if (type == HUB_INIT3)
+       if (type == HUB_INIT2 || type == HUB_INIT3) {
+               device_lock(hub->intfdev);
+
+               /* Was the hub disconnected while we were waiting? */
+               if (hub->disconnected) {
+                       device_unlock(hub->intfdev);
+                       kref_put(&hub->kref, hub_release);
+                       return;
+               }
+               if (type == HUB_INIT2)
+                       goto init2;
                goto init3;
+       }
+       kref_get(&hub->kref);
 
        /* The superspeed hub except for root hub has to use Hub Depth
         * value as an offset into the route string to locate the bits
@@ -1232,6 +1246,7 @@ static void hub_activate(struct usb_hub *hub, enum hub_activation_type type)
                        queue_delayed_work(system_power_efficient_wq,
                                        &hub->init_work,
                                        msecs_to_jiffies(delay));
+                       device_unlock(hub->intfdev);
                        return;         /* Continues at init3: below */
                } else {
                        msleep(delay);
@@ -1253,6 +1268,11 @@ static void hub_activate(struct usb_hub *hub, enum hub_activation_type type)
        /* Allow autosuspend if it was suppressed */
        if (type <= HUB_INIT3)
                usb_autopm_put_interface_async(to_usb_interface(hub->intfdev));
+
+       if (type == HUB_INIT2 || type == HUB_INIT3)
+               device_unlock(hub->intfdev);
+
+       kref_put(&hub->kref, hub_release);
 }
 
 /* Implement the continuations for the delays above */
@@ -4512,6 +4532,8 @@ hub_port_init(struct usb_hub *hub, struct usb_device *udev, int port1,
                goto fail;
        }
 
+       usb_detect_quirks(udev);
+
        if (udev->wusb == 0 && le16_to_cpu(udev->descriptor.bcdUSB) >= 0x0201) {
                retval = usb_get_bos_descriptor(udev);
                if (!retval) {
@@ -4710,7 +4732,6 @@ static void hub_port_connect(struct usb_hub *hub, int port1, u16 portstatus,
                if (status < 0)
                        goto loop;
 
-               usb_detect_quirks(udev);
                if (udev->quirks & USB_QUIRK_DELAY_INIT)
                        msleep(1000);
 
@@ -5326,9 +5347,6 @@ static int usb_reset_and_verify_device(struct usb_device *udev)
        if (udev->usb2_hw_lpm_enabled == 1)
                usb_set_usb2_hardware_lpm(udev, 0);
 
-       bos = udev->bos;
-       udev->bos = NULL;
-
        /* Disable LPM and LTM while we reset the device and reinstall the alt
         * settings.  Device-initiated LPM settings, and system exit latency
         * settings are cleared when the device is reset, so we have to set
@@ -5337,15 +5355,18 @@ static int usb_reset_and_verify_device(struct usb_device *udev)
        ret = usb_unlocked_disable_lpm(udev);
        if (ret) {
                dev_err(&udev->dev, "%s Failed to disable LPM\n.", __func__);
-               goto re_enumerate;
+               goto re_enumerate_no_bos;
        }
        ret = usb_disable_ltm(udev);
        if (ret) {
                dev_err(&udev->dev, "%s Failed to disable LTM\n.",
                                __func__);
-               goto re_enumerate;
+               goto re_enumerate_no_bos;
        }
 
+       bos = udev->bos;
+       udev->bos = NULL;
+
        for (i = 0; i < SET_CONFIG_TRIES; ++i) {
 
                /* ep0 maxpacket size may change; let the HCD know about it.
@@ -5442,10 +5463,11 @@ done:
        return 0;
 
 re_enumerate:
-       /* LPM state doesn't matter when we're about to destroy the device. */
-       hub_port_logical_disconnect(parent_hub, port1);
        usb_release_bos_descriptor(udev);
        udev->bos = bos;
+re_enumerate_no_bos:
+       /* LPM state doesn't matter when we're about to destroy the device. */
+       hub_port_logical_disconnect(parent_hub, port1);
        return -ENODEV;
 }
 
index 210618319f10a4110bc53191fc8a06a860992c3a..5487fe308f01b7be30bcecebc12726a295f9daa9 100644 (file)
@@ -206,7 +206,7 @@ static int link_peers(struct usb_port *left, struct usb_port *right)
                else
                        method = "default";
 
-               pr_warn("usb: failed to peer %s and %s by %s (%s:%s) (%s:%s)\n",
+               pr_debug("usb: failed to peer %s and %s by %s (%s:%s) (%s:%s)\n",
                        dev_name(&left->dev), dev_name(&right->dev), method,
                        dev_name(&left->dev),
                        lpeer ? dev_name(&lpeer->dev) : "none",
@@ -265,7 +265,7 @@ static void link_peers_report(struct usb_port *left, struct usb_port *right)
        if (rc == 0) {
                dev_dbg(&left->dev, "peered to %s\n", dev_name(&right->dev));
        } else {
-               dev_warn(&left->dev, "failed to peer to %s (%d)\n",
+               dev_dbg(&left->dev, "failed to peer to %s (%d)\n",
                                dev_name(&right->dev), rc);
                pr_warn_once("usb: port power management may be unreliable\n");
                usb_port_block_power_off = 1;
index f5a381945db2886a77e23a8fcf40ba9a34bb7fe7..6dc810bce295ab22dbb10b47755dddb421f96957 100644 (file)
@@ -125,6 +125,9 @@ static const struct usb_device_id usb_quirk_list[] = {
        { USB_DEVICE(0x04f3, 0x016f), .driver_info =
                        USB_QUIRK_DEVICE_QUALIFIER },
 
+       { USB_DEVICE(0x04f3, 0x21b8), .driver_info =
+                       USB_QUIRK_DEVICE_QUALIFIER },
+
        /* Roland SC-8820 */
        { USB_DEVICE(0x0582, 0x0007), .driver_info = USB_QUIRK_RESET_RESUME },
 
@@ -199,6 +202,12 @@ static const struct usb_device_id usb_quirk_list[] = {
        { USB_DEVICE(0x1a0a, 0x0200), .driver_info =
                        USB_QUIRK_LINEAR_UFRAME_INTR_BINTERVAL },
 
+       /* Blackmagic Design Intensity Shuttle */
+       { USB_DEVICE(0x1edb, 0xbd3b), .driver_info = USB_QUIRK_NO_LPM },
+
+       /* Blackmagic Design UltraStudio SDI */
+       { USB_DEVICE(0x1edb, 0xbd4f), .driver_info = USB_QUIRK_NO_LPM },
+
        { }  /* terminating entry must be last */
 };
 
index e79baf73c234f58bf3162bb9d52d5efce9bca1ca..571c21727ff9f5cb8c774eeb1178cfc55e8e88b4 100644 (file)
@@ -324,12 +324,13 @@ void dwc2_hcd_disconnect(struct dwc2_hsotg *hsotg)
  */
 static void dwc2_hcd_rem_wakeup(struct dwc2_hsotg *hsotg)
 {
-       if (hsotg->lx_state == DWC2_L2) {
+       if (hsotg->bus_suspended) {
                hsotg->flags.b.port_suspend_change = 1;
                usb_hcd_resume_root_hub(hsotg->priv);
-       } else {
-               hsotg->flags.b.port_l1_change = 1;
        }
+
+       if (hsotg->lx_state == DWC2_L1)
+               hsotg->flags.b.port_l1_change = 1;
 }
 
 /**
@@ -1428,8 +1429,8 @@ static void dwc2_wakeup_detected(unsigned long data)
        dev_dbg(hsotg->dev, "Clear Resume: HPRT0=%0x\n",
                dwc2_readl(hsotg->regs + HPRT0));
 
-       hsotg->bus_suspended = 0;
        dwc2_hcd_rem_wakeup(hsotg);
+       hsotg->bus_suspended = 0;
 
        /* Change to L0 state */
        hsotg->lx_state = DWC2_L0;
index 5859b0fa19ee3f907b2bfa93945a6378ae10911a..39c1cbf0e75d9a5957b1567def5d23fb3631a015 100644 (file)
@@ -108,7 +108,8 @@ static const struct dwc2_core_params params_rk3066 = {
        .host_ls_low_power_phy_clk      = -1,
        .ts_dline                       = -1,
        .reload_ctl                     = -1,
-       .ahbcfg                         = 0x7, /* INCR16 */
+       .ahbcfg                         = GAHBCFG_HBSTLEN_INCR16 <<
+                                         GAHBCFG_HBSTLEN_SHIFT,
        .uframe_sched                   = -1,
        .external_id_pin_ctl            = -1,
        .hibernation                    = -1,
@@ -124,9 +125,11 @@ static int __dwc2_lowlevel_hw_enable(struct dwc2_hsotg *hsotg)
        if (ret)
                return ret;
 
-       ret = clk_prepare_enable(hsotg->clk);
-       if (ret)
-               return ret;
+       if (hsotg->clk) {
+               ret = clk_prepare_enable(hsotg->clk);
+               if (ret)
+                       return ret;
+       }
 
        if (hsotg->uphy)
                ret = usb_phy_init(hsotg->uphy);
@@ -174,7 +177,8 @@ static int __dwc2_lowlevel_hw_disable(struct dwc2_hsotg *hsotg)
        if (ret)
                return ret;
 
-       clk_disable_unprepare(hsotg->clk);
+       if (hsotg->clk)
+               clk_disable_unprepare(hsotg->clk);
 
        ret = regulator_bulk_disable(ARRAY_SIZE(hsotg->supplies),
                                     hsotg->supplies);
@@ -211,14 +215,41 @@ static int dwc2_lowlevel_hw_init(struct dwc2_hsotg *hsotg)
         */
        hsotg->phy = devm_phy_get(hsotg->dev, "usb2-phy");
        if (IS_ERR(hsotg->phy)) {
-               hsotg->phy = NULL;
+               ret = PTR_ERR(hsotg->phy);
+               switch (ret) {
+               case -ENODEV:
+               case -ENOSYS:
+                       hsotg->phy = NULL;
+                       break;
+               case -EPROBE_DEFER:
+                       return ret;
+               default:
+                       dev_err(hsotg->dev, "error getting phy %d\n", ret);
+                       return ret;
+               }
+       }
+
+       if (!hsotg->phy) {
                hsotg->uphy = devm_usb_get_phy(hsotg->dev, USB_PHY_TYPE_USB2);
-               if (IS_ERR(hsotg->uphy))
-                       hsotg->uphy = NULL;
-               else
-                       hsotg->plat = dev_get_platdata(hsotg->dev);
+               if (IS_ERR(hsotg->uphy)) {
+                       ret = PTR_ERR(hsotg->uphy);
+                       switch (ret) {
+                       case -ENODEV:
+                       case -ENXIO:
+                               hsotg->uphy = NULL;
+                               break;
+                       case -EPROBE_DEFER:
+                               return ret;
+                       default:
+                               dev_err(hsotg->dev, "error getting usb phy %d\n",
+                                       ret);
+                               return ret;
+                       }
+               }
        }
 
+       hsotg->plat = dev_get_platdata(hsotg->dev);
+
        if (hsotg->phy) {
                /*
                 * If using the generic PHY framework, check if the PHY bus
@@ -228,11 +259,6 @@ static int dwc2_lowlevel_hw_init(struct dwc2_hsotg *hsotg)
                        hsotg->phyif = GUSBCFG_PHYIF8;
        }
 
-       if (!hsotg->phy && !hsotg->uphy && !hsotg->plat) {
-               dev_err(hsotg->dev, "no platform data or transceiver defined\n");
-               return -EPROBE_DEFER;
-       }
-
        /* Clock */
        hsotg->clk = devm_clk_get(hsotg->dev, "otg");
        if (IS_ERR(hsotg->clk)) {
@@ -341,20 +367,6 @@ static int dwc2_driver_probe(struct platform_device *dev)
        if (retval)
                return retval;
 
-       irq = platform_get_irq(dev, 0);
-       if (irq < 0) {
-               dev_err(&dev->dev, "missing IRQ resource\n");
-               return irq;
-       }
-
-       dev_dbg(hsotg->dev, "registering common handler for irq%d\n",
-               irq);
-       retval = devm_request_irq(hsotg->dev, irq,
-                                 dwc2_handle_common_intr, IRQF_SHARED,
-                                 dev_name(hsotg->dev), hsotg);
-       if (retval)
-               return retval;
-
        res = platform_get_resource(dev, IORESOURCE_MEM, 0);
        hsotg->regs = devm_ioremap_resource(&dev->dev, res);
        if (IS_ERR(hsotg->regs))
@@ -389,6 +401,20 @@ static int dwc2_driver_probe(struct platform_device *dev)
 
        dwc2_set_all_params(hsotg->core_params, -1);
 
+       irq = platform_get_irq(dev, 0);
+       if (irq < 0) {
+               dev_err(&dev->dev, "missing IRQ resource\n");
+               return irq;
+       }
+
+       dev_dbg(hsotg->dev, "registering common handler for irq%d\n",
+               irq);
+       retval = devm_request_irq(hsotg->dev, irq,
+                                 dwc2_handle_common_intr, IRQF_SHARED,
+                                 dev_name(hsotg->dev), hsotg);
+       if (retval)
+               return retval;
+
        retval = dwc2_lowlevel_hw_enable(hsotg);
        if (retval)
                return retval;
index 77a622cb48ab1555a87dfaf279f5d25368672e99..009d83048c8c9ab51ae01191e3cb2aa30207d928 100644 (file)
@@ -34,6 +34,8 @@
 #define PCI_DEVICE_ID_INTEL_BSW                        0x22b7
 #define PCI_DEVICE_ID_INTEL_SPTLP              0x9d30
 #define PCI_DEVICE_ID_INTEL_SPTH               0xa130
+#define PCI_DEVICE_ID_INTEL_BXT                        0x0aaa
+#define PCI_DEVICE_ID_INTEL_APL                        0x5aaa
 
 static const struct acpi_gpio_params reset_gpios = { 0, 0, false };
 static const struct acpi_gpio_params cs_gpios = { 1, 0, false };
@@ -210,6 +212,8 @@ static const struct pci_device_id dwc3_pci_id_table[] = {
        { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_MRFLD), },
        { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_SPTLP), },
        { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_SPTH), },
+       { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_BXT), },
+       { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_APL), },
        { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_NL_USB), },
        {  }    /* Terminating Entry */
 };
index 55ba447fdf8bf56720eeac029ed4f96d932ee0ea..a58376fd65fe6d788fa817d5600696bfd431c791 100644 (file)
@@ -1078,6 +1078,7 @@ static int __dwc3_gadget_ep_queue(struct dwc3_ep *dep, struct dwc3_request *req)
         * little bit faster.
         */
        if (!usb_endpoint_xfer_isoc(dep->endpoint.desc) &&
+                       !usb_endpoint_xfer_int(dep->endpoint.desc) &&
                        !(dep->flags & DWC3_EP_BUSY)) {
                ret = __dwc3_gadget_kick_transfer(dep, 0, true);
                goto out;
@@ -2744,11 +2745,33 @@ int dwc3_gadget_init(struct dwc3 *dwc)
        }
 
        dwc->gadget.ops                 = &dwc3_gadget_ops;
-       dwc->gadget.max_speed           = USB_SPEED_SUPER;
        dwc->gadget.speed               = USB_SPEED_UNKNOWN;
        dwc->gadget.sg_supported        = true;
        dwc->gadget.name                = "dwc3-gadget";
 
+       /*
+        * FIXME We might be setting max_speed to <SUPER, however versions
+        * <2.20a of dwc3 have an issue with metastability (documented
+        * elsewhere in this driver) which tells us we can't set max speed to
+        * anything lower than SUPER.
+        *
+        * Because gadget.max_speed is only used by composite.c and function
+        * drivers (i.e. it won't go into dwc3's registers) we are allowing this
+        * to happen so we avoid sending SuperSpeed Capability descriptor
+        * together with our BOS descriptor as that could confuse host into
+        * thinking we can handle super speed.
+        *
+        * Note that, in fact, we won't even support GetBOS requests when speed
+        * is less than super speed because we don't have means, yet, to tell
+        * composite.c that we are USB 2.0 + LPM ECN.
+        */
+       if (dwc->revision < DWC3_REVISION_220A)
+               dwc3_trace(trace_dwc3_gadget,
+                               "Changing max_speed on rev %08x\n",
+                               dwc->revision);
+
+       dwc->gadget.max_speed           = dwc->maximum_speed;
+
        /*
         * Per databook, DWC3 needs buffer size to be aligned to MaxPacketSize
         * on ep out.
index adc6d52efa4639387c30bcde2ae7cee95331b1bc..cf43e9e18368dcd84668b9378b1036b17276b593 100644 (file)
@@ -423,7 +423,7 @@ static ssize_t __ffs_ep0_read_events(struct ffs_data *ffs, char __user *buf,
        spin_unlock_irq(&ffs->ev.waitq.lock);
        mutex_unlock(&ffs->mutex);
 
-       return unlikely(__copy_to_user(buf, events, size)) ? -EFAULT : size;
+       return unlikely(copy_to_user(buf, events, size)) ? -EFAULT : size;
 }
 
 static ssize_t ffs_ep0_read(struct file *file, char __user *buf,
@@ -513,7 +513,7 @@ static ssize_t ffs_ep0_read(struct file *file, char __user *buf,
 
                /* unlocks spinlock */
                ret = __ffs_ep0_queue_wait(ffs, data, len);
-               if (likely(ret > 0) && unlikely(__copy_to_user(buf, data, len)))
+               if (likely(ret > 0) && unlikely(copy_to_user(buf, data, len)))
                        ret = -EFAULT;
                goto done_mutex;
 
@@ -3493,7 +3493,7 @@ static char *ffs_prepare_buffer(const char __user *buf, size_t len)
        if (unlikely(!data))
                return ERR_PTR(-ENOMEM);
 
-       if (unlikely(__copy_from_user(data, buf, len))) {
+       if (unlikely(copy_from_user(data, buf, len))) {
                kfree(data);
                return ERR_PTR(-EFAULT);
        }
index 23933bdf2d9d6cebc66750050ba704c9a20d109c..ddc3aad886b7457dd0ab4c79587104b474889ca0 100644 (file)
@@ -329,7 +329,7 @@ static int alloc_requests(struct usb_composite_dev *cdev,
        for (i = 0; i < loop->qlen && result == 0; i++) {
                result = -ENOMEM;
 
-               in_req = usb_ep_alloc_request(loop->in_ep, GFP_KERNEL);
+               in_req = usb_ep_alloc_request(loop->in_ep, GFP_ATOMIC);
                if (!in_req)
                        goto fail;
 
index 42acb45e1ab42dd9436244bec16d4903603d6089..898a570319f17c3128b7a44878ebc09ea7242961 100644 (file)
@@ -370,6 +370,7 @@ static int f_midi_set_alt(struct usb_function *f, unsigned intf, unsigned alt)
                if (err) {
                        ERROR(midi, "%s queue req: %d\n",
                                    midi->out_ep->name, err);
+                       free_ep_req(midi->out_ep, req);
                }
        }
 
@@ -545,7 +546,7 @@ static void f_midi_transmit(struct f_midi *midi, struct usb_request *req)
                }
        }
 
-       if (req->length > 0) {
+       if (req->length > 0 && ep->enabled) {
                int err;
 
                err = usb_ep_queue(ep, req, GFP_ATOMIC);
index 289ebca316d3f4ab0e136a14858bb7275eee53c0..ad8c9b05572d7421885ff161d32543f8942eb90d 100644 (file)
@@ -20,7 +20,7 @@
 #define UVC_ATTR(prefix, cname, aname) \
 static struct configfs_attribute prefix##attr_##cname = { \
        .ca_name        = __stringify(aname),                           \
-       .ca_mode        = S_IRUGO,                                      \
+       .ca_mode        = S_IRUGO | S_IWUGO,                            \
        .ca_owner       = THIS_MODULE,                                  \
        .show           = prefix##cname##_show,                         \
        .store          = prefix##cname##_store,                        \
index f0f2b066ac08366d353b046d3a3a193600977d1d..f92f5aff0dd5e8ece600cc44b5ba6168e3f1bb81 100644 (file)
@@ -1633,7 +1633,7 @@ static irqreturn_t usba_udc_irq(int irq, void *devid)
        spin_lock(&udc->lock);
 
        int_enb = usba_int_enb_get(udc);
-       status = usba_readl(udc, INT_STA) & int_enb;
+       status = usba_readl(udc, INT_STA) & (int_enb | USBA_HIGH_SPEED);
        DBG(DBG_INT, "irq, status=%#08x\n", status);
 
        if (status & USBA_DET_SUSPEND) {
index 670ac0b12f00842ad7a5b840c941f2e8a8a7f1cc..001a3b74a993ea677dd65650a4457f5f14376a7c 100644 (file)
@@ -2536,6 +2536,9 @@ static int pxa_udc_suspend(struct platform_device *_dev, pm_message_t state)
        udc->pullup_resume = udc->pullup_on;
        dplus_pullup(udc, 0);
 
+       if (udc->driver)
+               udc->driver->disconnect(&udc->gadget);
+
        return 0;
 }
 
index 342ffd1401222179589906ccc1d09ec102a1f03b..8c6e15bd6ff0b27ce2e8cb22c2fe03e9866f1768 100644 (file)
@@ -473,6 +473,8 @@ static int ohci_hcd_at91_drv_probe(struct platform_device *pdev)
        if (!pdata)
                return -ENOMEM;
 
+       pdev->dev.platform_data = pdata;
+
        if (!of_property_read_u32(np, "num-ports", &ports))
                pdata->ports = ports;
 
@@ -483,6 +485,7 @@ static int ohci_hcd_at91_drv_probe(struct platform_device *pdev)
                 */
                if (i >= pdata->ports) {
                        pdata->vbus_pin[i] = -EINVAL;
+                       pdata->overcurrent_pin[i] = -EINVAL;
                        continue;
                }
 
@@ -513,10 +516,8 @@ static int ohci_hcd_at91_drv_probe(struct platform_device *pdev)
        }
 
        at91_for_each_port(i) {
-               if (i >= pdata->ports) {
-                       pdata->overcurrent_pin[i] = -EINVAL;
-                       continue;
-               }
+               if (i >= pdata->ports)
+                       break;
 
                pdata->overcurrent_pin[i] =
                        of_get_named_gpio_flags(np, "atmel,oc-gpio", i, &flags);
@@ -552,8 +553,6 @@ static int ohci_hcd_at91_drv_probe(struct platform_device *pdev)
                }
        }
 
-       pdev->dev.platform_data = pdata;
-
        device_init_wakeup(&pdev->dev, 1);
        return usb_hcd_at91_probe(&ohci_at91_hc_driver, pdev);
 }
index dc31c425ce0179551b27e2d7a900f1bb7b411ad8..9f1c0538b211217d21184ef2527f764933aace0d 100644 (file)
@@ -377,6 +377,10 @@ static int qset_fill_page_list(struct whc *whc, struct whc_std *std, gfp_t mem_f
        if (std->pl_virt == NULL)
                return -ENOMEM;
        std->dma_addr = dma_map_single(whc->wusbhc.dev, std->pl_virt, pl_len, DMA_TO_DEVICE);
+       if (dma_mapping_error(whc->wusbhc.dev, std->dma_addr)) {
+               kfree(std->pl_virt);
+               return -EFAULT;
+       }
 
        for (p = 0; p < std->num_pointers; p++) {
                std->pl_virt[p].buf_ptr = cpu_to_le64(dma_addr);
index 5d2d7e954bd4cb8dbaa51ec1121e236e8f472dce..f980c239eded9bd5e9615ebf96deefce5c7ec591 100644 (file)
@@ -733,8 +733,30 @@ static u32 xhci_get_port_status(struct usb_hcd *hcd,
                if ((raw_port_status & PORT_RESET) ||
                                !(raw_port_status & PORT_PE))
                        return 0xffffffff;
-               if (time_after_eq(jiffies,
-                                       bus_state->resume_done[wIndex])) {
+               /* did port event handler already start resume timing? */
+               if (!bus_state->resume_done[wIndex]) {
+                       /* If not, maybe we are in a host initated resume? */
+                       if (test_bit(wIndex, &bus_state->resuming_ports)) {
+                               /* Host initated resume doesn't time the resume
+                                * signalling using resume_done[].
+                                * It manually sets RESUME state, sleeps 20ms
+                                * and sets U0 state. This should probably be
+                                * changed, but not right now.
+                                */
+                       } else {
+                               /* port resume was discovered now and here,
+                                * start resume timing
+                                */
+                               unsigned long timeout = jiffies +
+                                       msecs_to_jiffies(USB_RESUME_TIMEOUT);
+
+                               set_bit(wIndex, &bus_state->resuming_ports);
+                               bus_state->resume_done[wIndex] = timeout;
+                               mod_timer(&hcd->rh_timer, timeout);
+                       }
+               /* Has resume been signalled for USB_RESUME_TIME yet? */
+               } else if (time_after_eq(jiffies,
+                                        bus_state->resume_done[wIndex])) {
                        int time_left;
 
                        xhci_dbg(xhci, "Resume USB2 port %d\n",
@@ -775,19 +797,35 @@ static u32 xhci_get_port_status(struct usb_hcd *hcd,
                } else {
                        /*
                         * The resume has been signaling for less than
-                        * 20ms. Report the port status as SUSPEND,
-                        * let the usbcore check port status again
-                        * and clear resume signaling later.
+                        * USB_RESUME_TIME. Report the port status as SUSPEND,
+                        * let the usbcore check port status again and clear
+                        * resume signaling later.
                         */
                        status |= USB_PORT_STAT_SUSPEND;
                }
        }
-       if ((raw_port_status & PORT_PLS_MASK) == XDEV_U0
-                       && (raw_port_status & PORT_POWER)
-                       && (bus_state->suspended_ports & (1 << wIndex))) {
-               bus_state->suspended_ports &= ~(1 << wIndex);
-               if (hcd->speed < HCD_USB3)
-                       bus_state->port_c_suspend |= 1 << wIndex;
+       /*
+        * Clear stale usb2 resume signalling variables in case port changed
+        * state during resume signalling. For example on error
+        */
+       if ((bus_state->resume_done[wIndex] ||
+            test_bit(wIndex, &bus_state->resuming_ports)) &&
+           (raw_port_status & PORT_PLS_MASK) != XDEV_U3 &&
+           (raw_port_status & PORT_PLS_MASK) != XDEV_RESUME) {
+               bus_state->resume_done[wIndex] = 0;
+               clear_bit(wIndex, &bus_state->resuming_ports);
+       }
+
+
+       if ((raw_port_status & PORT_PLS_MASK) == XDEV_U0 &&
+           (raw_port_status & PORT_POWER)) {
+               if (bus_state->suspended_ports & (1 << wIndex)) {
+                       bus_state->suspended_ports &= ~(1 << wIndex);
+                       if (hcd->speed < HCD_USB3)
+                               bus_state->port_c_suspend |= 1 << wIndex;
+               }
+               bus_state->resume_done[wIndex] = 0;
+               clear_bit(wIndex, &bus_state->resuming_ports);
        }
        if (raw_port_status & PORT_CONNECT) {
                status |= USB_PORT_STAT_CONNECTION;
@@ -1112,6 +1150,7 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
                                if ((temp & PORT_PE) == 0)
                                        goto error;
 
+                               set_bit(wIndex, &bus_state->resuming_ports);
                                xhci_set_link_state(xhci, port_array, wIndex,
                                                        XDEV_RESUME);
                                spin_unlock_irqrestore(&xhci->lock, flags);
@@ -1119,6 +1158,7 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
                                spin_lock_irqsave(&xhci->lock, flags);
                                xhci_set_link_state(xhci, port_array, wIndex,
                                                        XDEV_U0);
+                               clear_bit(wIndex, &bus_state->resuming_ports);
                        }
                        bus_state->port_c_suspend |= 1 << wIndex;
 
index 17f6897acde2a5a7674ccff44ddc55f0db192166..c62109091d12855f7b5bb0e2b44a0b6b516cc88b 100644 (file)
@@ -188,10 +188,14 @@ static void xhci_pme_acpi_rtd3_enable(struct pci_dev *dev)
                0xb7, 0x0c, 0x34, 0xac, 0x01, 0xe9, 0xbf, 0x45,
                0xb7, 0xe6, 0x2b, 0x34, 0xec, 0x93, 0x1e, 0x23,
        };
-       acpi_evaluate_dsm(ACPI_HANDLE(&dev->dev), intel_dsm_uuid, 3, 1, NULL);
+       union acpi_object *obj;
+
+       obj = acpi_evaluate_dsm(ACPI_HANDLE(&dev->dev), intel_dsm_uuid, 3, 1,
+                               NULL);
+       ACPI_FREE(obj);
 }
 #else
-       static void xhci_pme_acpi_rtd3_enable(struct pci_dev *dev) { }
+static void xhci_pme_acpi_rtd3_enable(struct pci_dev *dev) { }
 #endif /* CONFIG_ACPI */
 
 /* called during probe() after chip reset completes */
index fa836251ca21e4f19c59b3fd37b3b788b7b81008..eeaa6c6bd540870f8065338a61ee37d838c6b07e 100644 (file)
@@ -1583,7 +1583,8 @@ static void handle_port_status(struct xhci_hcd *xhci,
                         */
                        bogus_port_status = true;
                        goto cleanup;
-               } else {
+               } else if (!test_bit(faked_port_index,
+                                    &bus_state->resuming_ports)) {
                        xhci_dbg(xhci, "resume HS port %d\n", port_id);
                        bus_state->resume_done[faked_port_index] = jiffies +
                                msecs_to_jiffies(USB_RESUME_TIMEOUT);
@@ -3896,28 +3897,6 @@ cleanup:
        return ret;
 }
 
-static int ep_ring_is_processing(struct xhci_hcd *xhci,
-               int slot_id, unsigned int ep_index)
-{
-       struct xhci_virt_device *xdev;
-       struct xhci_ring *ep_ring;
-       struct xhci_ep_ctx *ep_ctx;
-       struct xhci_virt_ep *xep;
-       dma_addr_t hw_deq;
-
-       xdev = xhci->devs[slot_id];
-       xep = &xhci->devs[slot_id]->eps[ep_index];
-       ep_ring = xep->ring;
-       ep_ctx = xhci_get_ep_ctx(xhci, xdev->out_ctx, ep_index);
-
-       if ((le32_to_cpu(ep_ctx->ep_info) & EP_STATE_MASK) != EP_STATE_RUNNING)
-               return 0;
-
-       hw_deq = le64_to_cpu(ep_ctx->deq) & ~EP_CTX_CYCLE_MASK;
-       return (hw_deq !=
-               xhci_trb_virt_to_dma(ep_ring->enq_seg, ep_ring->enqueue));
-}
-
 /*
  * Check transfer ring to guarantee there is enough room for the urb.
  * Update ISO URB start_frame and interval.
@@ -3983,10 +3962,12 @@ int xhci_queue_isoc_tx_prepare(struct xhci_hcd *xhci, gfp_t mem_flags,
        }
 
        /* Calculate the start frame and put it in urb->start_frame. */
-       if (HCC_CFC(xhci->hcc_params) &&
-                       ep_ring_is_processing(xhci, slot_id, ep_index)) {
-               urb->start_frame = xep->next_frame_id;
-               goto skip_start_over;
+       if (HCC_CFC(xhci->hcc_params) && !list_empty(&ep_ring->td_list)) {
+               if ((le32_to_cpu(ep_ctx->ep_info) & EP_STATE_MASK) ==
+                               EP_STATE_RUNNING) {
+                       urb->start_frame = xep->next_frame_id;
+                       goto skip_start_over;
+               }
        }
 
        start_frame = readl(&xhci->run_regs->microframe_index);
index 6e7dc6f93978c54e300caaa1b53155a672c91019..3f912705dcef93a5f27e6979f8aea9a6972b44eb 100644 (file)
@@ -175,6 +175,16 @@ int xhci_reset(struct xhci_hcd *xhci)
        command |= CMD_RESET;
        writel(command, &xhci->op_regs->command);
 
+       /* Existing Intel xHCI controllers require a delay of 1 mS,
+        * after setting the CMD_RESET bit, and before accessing any
+        * HC registers. This allows the HC to complete the
+        * reset operation and be ready for HC register access.
+        * Without this delay, the subsequent HC register access,
+        * may result in a system hang very rarely.
+        */
+       if (xhci->quirks & XHCI_INTEL_HOST)
+               udelay(1000);
+
        ret = xhci_handshake(&xhci->op_regs->command,
                        CMD_RESET, 0, 10 * 1000 * 1000);
        if (ret)
@@ -4768,8 +4778,16 @@ int xhci_update_hub_device(struct usb_hcd *hcd, struct usb_device *hdev,
        ctrl_ctx->add_flags |= cpu_to_le32(SLOT_FLAG);
        slot_ctx = xhci_get_slot_ctx(xhci, config_cmd->in_ctx);
        slot_ctx->dev_info |= cpu_to_le32(DEV_HUB);
+       /*
+        * refer to section 6.2.2: MTT should be 0 for full speed hub,
+        * but it may be already set to 1 when setup an xHCI virtual
+        * device, so clear it anyway.
+        */
        if (tt->multi)
                slot_ctx->dev_info |= cpu_to_le32(DEV_MTT);
+       else if (hdev->speed == USB_SPEED_FULL)
+               slot_ctx->dev_info &= cpu_to_le32(~DEV_MTT);
+
        if (xhci->hci_version > 0x95) {
                xhci_dbg(xhci, "xHCI version %x needs hub "
                                "TT think time and number of ports\n",
index 1f2037bbeb0d1619572a2912bda7fa6e2c168ac0..45c83baf675dfb341089ca2f399ae636b45b0de5 100644 (file)
@@ -159,7 +159,7 @@ config USB_TI_CPPI_DMA
 
 config USB_TI_CPPI41_DMA
        bool 'TI CPPI 4.1 (AM335x)'
-       depends on ARCH_OMAP
+       depends on ARCH_OMAP && DMADEVICES
        select TI_CPPI41
 
 config USB_TUSB_OMAP_DMA
index ba13529cbd52ff82658e88bdba30db82a8e99790..ee9ff7028b926b1a7303afb261c3b261f91c9da4 100644 (file)
@@ -132,7 +132,7 @@ static inline struct musb *dev_to_musb(struct device *dev)
 /*-------------------------------------------------------------------------*/
 
 #ifndef CONFIG_BLACKFIN
-static int musb_ulpi_read(struct usb_phy *phy, u32 offset)
+static int musb_ulpi_read(struct usb_phy *phy, u32 reg)
 {
        void __iomem *addr = phy->io_priv;
        int     i = 0;
@@ -151,7 +151,7 @@ static int musb_ulpi_read(struct usb_phy *phy, u32 offset)
         * ULPICarKitControlDisableUTMI after clearing POWER_SUSPENDM.
         */
 
-       musb_writeb(addr, MUSB_ULPI_REG_ADDR, (u8)offset);
+       musb_writeb(addr, MUSB_ULPI_REG_ADDR, (u8)reg);
        musb_writeb(addr, MUSB_ULPI_REG_CONTROL,
                        MUSB_ULPI_REG_REQ | MUSB_ULPI_RDN_WR);
 
@@ -176,7 +176,7 @@ out:
        return ret;
 }
 
-static int musb_ulpi_write(struct usb_phy *phy, u32 offset, u32 data)
+static int musb_ulpi_write(struct usb_phy *phy, u32 val, u32 reg)
 {
        void __iomem *addr = phy->io_priv;
        int     i = 0;
@@ -191,8 +191,8 @@ static int musb_ulpi_write(struct usb_phy *phy, u32 offset, u32 data)
        power &= ~MUSB_POWER_SUSPENDM;
        musb_writeb(addr, MUSB_POWER, power);
 
-       musb_writeb(addr, MUSB_ULPI_REG_ADDR, (u8)offset);
-       musb_writeb(addr, MUSB_ULPI_REG_DATA, (u8)data);
+       musb_writeb(addr, MUSB_ULPI_REG_ADDR, (u8)reg);
+       musb_writeb(addr, MUSB_ULPI_REG_DATA, (u8)val);
        musb_writeb(addr, MUSB_ULPI_REG_CONTROL, MUSB_ULPI_REG_REQ);
 
        while (!(musb_readb(addr, MUSB_ULPI_REG_CONTROL)
@@ -1668,7 +1668,7 @@ EXPORT_SYMBOL_GPL(musb_interrupt);
 static bool use_dma = 1;
 
 /* "modprobe ... use_dma=0" etc */
-module_param(use_dma, bool, 0);
+module_param(use_dma, bool, 0644);
 MODULE_PARM_DESC(use_dma, "enable/disable use of DMA");
 
 void musb_dma_completion(struct musb *musb, u8 epnum, u8 transmit)
@@ -2017,7 +2017,6 @@ musb_init_controller(struct device *dev, int nIrq, void __iomem *ctrl)
        /* 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:
@@ -2095,6 +2094,7 @@ musb_init_controller(struct device *dev, int nIrq, void __iomem *ctrl)
 #ifndef CONFIG_MUSB_PIO_ONLY
        if (!musb->ops->dma_init || !musb->ops->dma_exit) {
                dev_err(dev, "DMA controller not set\n");
+               status = -ENODEV;
                goto fail2;
        }
        musb_dma_controller_create = musb->ops->dma_init;
@@ -2218,6 +2218,12 @@ musb_init_controller(struct device *dev, int nIrq, void __iomem *ctrl)
 
        pm_runtime_put(musb->controller);
 
+       /*
+        * For why this is currently needed, see commit 3e43a0725637
+        * ("usb: musb: core: add pm_runtime_irq_safe()")
+        */
+       pm_runtime_irq_safe(musb->controller);
+
        return 0;
 
 fail5:
index 26c65e66cc0f1db8680933d13ed2d2b960603906..795a45b1b25bacb016552b4d0635166965ebfce6 100644 (file)
@@ -112,22 +112,32 @@ static void musb_h_tx_flush_fifo(struct musb_hw_ep *ep)
        struct musb     *musb = ep->musb;
        void __iomem    *epio = ep->regs;
        u16             csr;
-       u16             lastcsr = 0;
        int             retries = 1000;
 
        csr = musb_readw(epio, MUSB_TXCSR);
        while (csr & MUSB_TXCSR_FIFONOTEMPTY) {
-               if (csr != lastcsr)
-                       dev_dbg(musb->controller, "Host TX FIFONOTEMPTY csr: %02x\n", csr);
-               lastcsr = csr;
                csr |= MUSB_TXCSR_FLUSHFIFO | MUSB_TXCSR_TXPKTRDY;
                musb_writew(epio, MUSB_TXCSR, csr);
                csr = musb_readw(epio, MUSB_TXCSR);
-               if (WARN(retries-- < 1,
+
+               /*
+                * FIXME: sometimes the tx fifo flush failed, it has been
+                * observed during device disconnect on AM335x.
+                *
+                * To reproduce the issue, ensure tx urb(s) are queued when
+                * unplug the usb device which is connected to AM335x usb
+                * host port.
+                *
+                * I found using a usb-ethernet device and running iperf
+                * (client on AM335x) has very high chance to trigger it.
+                *
+                * Better to turn on dev_dbg() in musb_cleanup_urb() with
+                * CPPI enabled to see the issue when aborting the tx channel.
+                */
+               if (dev_WARN_ONCE(musb->controller, retries-- < 1,
                                "Could not flush host TX%d fifo: csr: %04x\n",
                                ep->epnum, csr))
                        return;
-               mdelay(1);
        }
 }
 
index 173132416170108b6a156568f53f3c51224a86c2..22e8ecb6bfbd282236a77525cf4cabda25555c66 100644 (file)
@@ -21,7 +21,6 @@ config AB8500_USB
 config FSL_USB2_OTG
        bool "Freescale USB OTG Transceiver Driver"
        depends on USB_EHCI_FSL && USB_FSL_USB2 && USB_OTG_FSM && PM
-       select USB_OTG
        select USB_PHY
        help
          Enable this to support Freescale USB OTG transceiver.
@@ -168,8 +167,7 @@ config USB_QCOM_8X16_PHY
 
 config USB_MV_OTG
        tristate "Marvell USB OTG support"
-       depends on USB_EHCI_MV && USB_MV_UDC && PM
-       select USB_OTG
+       depends on USB_EHCI_MV && USB_MV_UDC && PM && USB_OTG
        select USB_PHY
        help
          Say Y here if you want to build Marvell USB OTG transciever
index 80eb991c2506c758315cc2e6e1f39b6ebbf319f4..0d19a6d61a71f7ccb7a55e1b90a7d5d5f27db535 100644 (file)
@@ -1506,7 +1506,6 @@ static int msm_otg_read_dt(struct platform_device *pdev, struct msm_otg *motg)
 {
        struct msm_otg_platform_data *pdata;
        struct extcon_dev *ext_id, *ext_vbus;
-       const struct of_device_id *id;
        struct device_node *node = pdev->dev.of_node;
        struct property *prop;
        int len, ret, words;
@@ -1518,8 +1517,9 @@ static int msm_otg_read_dt(struct platform_device *pdev, struct msm_otg *motg)
 
        motg->pdata = pdata;
 
-       id = of_match_device(msm_otg_dt_match, &pdev->dev);
-       pdata->phy_type = (enum msm_usb_phy_type) id->data;
+       pdata->phy_type = (enum msm_usb_phy_type)of_device_get_match_data(&pdev->dev);
+       if (!pdata->phy_type)
+               return 1;
 
        motg->link_rst = devm_reset_control_get(&pdev->dev, "link");
        if (IS_ERR(motg->link_rst))
index 4d863ebc117c0f59cce46f39fda4d191e93b9843..c2936dc48ca7b45b0e5c186859d2879569719323 100644 (file)
@@ -143,12 +143,17 @@ static const struct mxs_phy_data imx6sx_phy_data = {
        .flags = MXS_PHY_DISCONNECT_LINE_WITHOUT_VBUS,
 };
 
+static const struct mxs_phy_data imx6ul_phy_data = {
+       .flags = MXS_PHY_DISCONNECT_LINE_WITHOUT_VBUS,
+};
+
 static const struct of_device_id mxs_phy_dt_ids[] = {
        { .compatible = "fsl,imx6sx-usbphy", .data = &imx6sx_phy_data, },
        { .compatible = "fsl,imx6sl-usbphy", .data = &imx6sl_phy_data, },
        { .compatible = "fsl,imx6q-usbphy", .data = &imx6q_phy_data, },
        { .compatible = "fsl,imx23-usbphy", .data = &imx23_phy_data, },
        { .compatible = "fsl,vf610-usbphy", .data = &vf610_phy_data, },
+       { .compatible = "fsl,imx6ul-usbphy", .data = &imx6ul_phy_data, },
        { /* sentinel */ }
 };
 MODULE_DEVICE_TABLE(of, mxs_phy_dt_ids);
@@ -452,10 +457,13 @@ static int mxs_phy_probe(struct platform_device *pdev)
        struct clk *clk;
        struct mxs_phy *mxs_phy;
        int ret;
-       const struct of_device_id *of_id =
-                       of_match_device(mxs_phy_dt_ids, &pdev->dev);
+       const struct of_device_id *of_id;
        struct device_node *np = pdev->dev.of_node;
 
+       of_id = of_match_device(mxs_phy_dt_ids, &pdev->dev);
+       if (!of_id)
+               return -ENODEV;
+
        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
        base = devm_ioremap_resource(&pdev->dev, res);
        if (IS_ERR(base))
index 1270906ccb95808714d174f0461a081c8d1d1cc6..c4bf2de6d14ec3a47259f06977e27ea1f3329ed1 100644 (file)
@@ -105,7 +105,6 @@ static int omap_otg_probe(struct platform_device *pdev)
        extcon = extcon_get_extcon_dev(config->extcon);
        if (!extcon)
                return -EPROBE_DEFER;
-       otg_dev->extcon = extcon;
 
        otg_dev = devm_kzalloc(&pdev->dev, sizeof(*otg_dev), GFP_KERNEL);
        if (!otg_dev)
@@ -115,6 +114,7 @@ static int omap_otg_probe(struct platform_device *pdev)
        if (IS_ERR(otg_dev->base))
                return PTR_ERR(otg_dev->base);
 
+       otg_dev->extcon = extcon;
        otg_dev->id_nb.notifier_call = omap_otg_id_notifier;
        otg_dev->vbus_nb.notifier_call = omap_otg_vbus_notifier;
 
index de4f97d84a822ffd746b5550dcb68da08b581438..8f7a78e7097598a50e9d7ba3cc72831b41af25b8 100644 (file)
@@ -131,7 +131,8 @@ static void __usbhsg_queue_pop(struct usbhsg_uep *uep,
        struct device *dev = usbhsg_gpriv_to_dev(gpriv);
        struct usbhs_priv *priv = usbhsg_gpriv_to_priv(gpriv);
 
-       dev_dbg(dev, "pipe %d : queue pop\n", usbhs_pipe_number(pipe));
+       if (pipe)
+               dev_dbg(dev, "pipe %d : queue pop\n", usbhs_pipe_number(pipe));
 
        ureq->req.status = status;
        spin_unlock(usbhs_priv_to_lock(priv));
@@ -685,7 +686,13 @@ static int usbhsg_ep_dequeue(struct usb_ep *ep, struct usb_request *req)
        struct usbhsg_request *ureq = usbhsg_req_to_ureq(req);
        struct usbhs_pipe *pipe = usbhsg_uep_to_pipe(uep);
 
-       usbhs_pkt_pop(pipe, usbhsg_ureq_to_pkt(ureq));
+       if (pipe)
+               usbhs_pkt_pop(pipe, usbhsg_ureq_to_pkt(ureq));
+
+       /*
+        * To dequeue a request, this driver should call the usbhsg_queue_pop()
+        * even if the pipe is NULL.
+        */
        usbhsg_queue_pop(uep, ureq, -ECONNRESET);
 
        return 0;
index eac7ccaa3c859cc3bae90e897fc071caa7168cfd..7d4f51a32e66fcb2b7568af975fcd5574edd7f88 100644 (file)
@@ -132,7 +132,6 @@ static const struct usb_device_id id_table[] = {
        { USB_DEVICE(0x10C4, 0xEA60) }, /* Silicon Labs factory default */
        { USB_DEVICE(0x10C4, 0xEA61) }, /* Silicon Labs factory default */
        { USB_DEVICE(0x10C4, 0xEA70) }, /* Silicon Labs factory default */
-       { USB_DEVICE(0x10C4, 0xEA80) }, /* Silicon Labs factory default */
        { USB_DEVICE(0x10C4, 0xEA71) }, /* Infinity GPS-MIC-1 Radio Monophone */
        { USB_DEVICE(0x10C4, 0xF001) }, /* Elan Digital Systems USBscope50 */
        { USB_DEVICE(0x10C4, 0xF002) }, /* Elan Digital Systems USBwave12 */
index f51a5d52c0edab01b9c9fbd91b8c1d7389d00f78..ec1b8f2c11837fecd39468c1e053880d72da9f94 100644 (file)
@@ -531,7 +531,8 @@ static int ipaq_open(struct tty_struct *tty,
         * through. Since this has a reasonably high failure rate, we retry
         * several times.
         */
-       while (retries--) {
+       while (retries) {
+               retries--;
                result = usb_control_msg(serial->dev,
                                usb_sndctrlpipe(serial->dev, 0), 0x22, 0x21,
                                0x1, 0, NULL, 0, 100);
index 685fef71d3d14e28ce125983b3508ae73ed6579c..f2280606b73c0c897d83d7738747b3d6f97a2c71 100644 (file)
@@ -161,6 +161,7 @@ static void option_instat_callback(struct urb *urb);
 #define NOVATELWIRELESS_PRODUCT_HSPA_EMBEDDED_HIGHSPEED        0x9001
 #define NOVATELWIRELESS_PRODUCT_E362           0x9010
 #define NOVATELWIRELESS_PRODUCT_E371           0x9011
+#define NOVATELWIRELESS_PRODUCT_U620L          0x9022
 #define NOVATELWIRELESS_PRODUCT_G2             0xA010
 #define NOVATELWIRELESS_PRODUCT_MC551          0xB001
 
@@ -354,6 +355,7 @@ static void option_instat_callback(struct urb *urb);
 /* This is the 4G XS Stick W14 a.k.a. Mobilcom Debitel Surf-Stick *
  * It seems to contain a Qualcomm QSC6240/6290 chipset            */
 #define FOUR_G_SYSTEMS_PRODUCT_W14             0x9603
+#define FOUR_G_SYSTEMS_PRODUCT_W100            0x9b01
 
 /* iBall 3.5G connect wireless modem */
 #define IBALL_3_5G_CONNECT                     0x9605
@@ -519,6 +521,11 @@ static const struct option_blacklist_info four_g_w14_blacklist = {
        .sendsetup = BIT(0) | BIT(1),
 };
 
+static const struct option_blacklist_info four_g_w100_blacklist = {
+       .sendsetup = BIT(1) | BIT(2),
+       .reserved = BIT(3),
+};
+
 static const struct option_blacklist_info alcatel_x200_blacklist = {
        .sendsetup = BIT(0) | BIT(1),
        .reserved = BIT(4),
@@ -1052,6 +1059,7 @@ static const struct usb_device_id option_ids[] = {
        { USB_DEVICE_AND_INTERFACE_INFO(NOVATELWIRELESS_VENDOR_ID, NOVATELWIRELESS_PRODUCT_MC551, 0xff, 0xff, 0xff) },
        { USB_DEVICE_AND_INTERFACE_INFO(NOVATELWIRELESS_VENDOR_ID, NOVATELWIRELESS_PRODUCT_E362, 0xff, 0xff, 0xff) },
        { USB_DEVICE_AND_INTERFACE_INFO(NOVATELWIRELESS_VENDOR_ID, NOVATELWIRELESS_PRODUCT_E371, 0xff, 0xff, 0xff) },
+       { USB_DEVICE_AND_INTERFACE_INFO(NOVATELWIRELESS_VENDOR_ID, NOVATELWIRELESS_PRODUCT_U620L, 0xff, 0x00, 0x00) },
 
        { USB_DEVICE(AMOI_VENDOR_ID, AMOI_PRODUCT_H01) },
        { USB_DEVICE(AMOI_VENDOR_ID, AMOI_PRODUCT_H01A) },
@@ -1641,6 +1649,9 @@ static const struct usb_device_id option_ids[] = {
        { USB_DEVICE(LONGCHEER_VENDOR_ID, FOUR_G_SYSTEMS_PRODUCT_W14),
          .driver_info = (kernel_ulong_t)&four_g_w14_blacklist
        },
+       { USB_DEVICE(LONGCHEER_VENDOR_ID, FOUR_G_SYSTEMS_PRODUCT_W100),
+         .driver_info = (kernel_ulong_t)&four_g_w100_blacklist
+       },
        { USB_DEVICE_INTERFACE_CLASS(LONGCHEER_VENDOR_ID, SPEEDUP_PRODUCT_SU9800, 0xff) },
        { USB_DEVICE(LONGCHEER_VENDOR_ID, ZOOM_PRODUCT_4597) },
        { USB_DEVICE(LONGCHEER_VENDOR_ID, IBALL_3_5G_CONNECT) },
index 5022fcfa02605a604f6998ef7dcbf0d3f0b2b590..9919d2a9faf278177aacf32c149fda22b00a1d83 100644 (file)
@@ -22,6 +22,8 @@
 #define DRIVER_AUTHOR "Qualcomm Inc"
 #define DRIVER_DESC "Qualcomm USB Serial driver"
 
+#define QUECTEL_EC20_PID       0x9215
+
 /* standard device layouts supported by this driver */
 enum qcserial_layouts {
        QCSERIAL_G2K = 0,       /* Gobi 2000 */
@@ -171,6 +173,38 @@ static const struct usb_device_id id_table[] = {
 };
 MODULE_DEVICE_TABLE(usb, id_table);
 
+static int handle_quectel_ec20(struct device *dev, int ifnum)
+{
+       int altsetting = 0;
+
+       /*
+        * Quectel EC20 Mini PCIe LTE module layout:
+        * 0: DM/DIAG (use libqcdm from ModemManager for communication)
+        * 1: NMEA
+        * 2: AT-capable modem port
+        * 3: Modem interface
+        * 4: NDIS
+        */
+       switch (ifnum) {
+       case 0:
+               dev_dbg(dev, "Quectel EC20 DM/DIAG interface found\n");
+               break;
+       case 1:
+               dev_dbg(dev, "Quectel EC20 NMEA GPS interface found\n");
+               break;
+       case 2:
+       case 3:
+               dev_dbg(dev, "Quectel EC20 Modem port found\n");
+               break;
+       case 4:
+               /* Don't claim the QMI/net interface */
+               altsetting = -1;
+               break;
+       }
+
+       return altsetting;
+}
+
 static int qcprobe(struct usb_serial *serial, const struct usb_device_id *id)
 {
        struct usb_host_interface *intf = serial->interface->cur_altsetting;
@@ -181,6 +215,10 @@ static int qcprobe(struct usb_serial *serial, const struct usb_device_id *id)
        int altsetting = -1;
        bool sendsetup = false;
 
+       /* we only support vendor specific functions */
+       if (intf->desc.bInterfaceClass != USB_CLASS_VENDOR_SPEC)
+               goto done;
+
        nintf = serial->dev->actconfig->desc.bNumInterfaces;
        dev_dbg(dev, "Num Interfaces = %d\n", nintf);
        ifnum = intf->desc.bInterfaceNumber;
@@ -240,6 +278,12 @@ static int qcprobe(struct usb_serial *serial, const struct usb_device_id *id)
                        altsetting = -1;
                break;
        case QCSERIAL_G2K:
+               /* handle non-standard layouts */
+               if (nintf == 5 && id->idProduct == QUECTEL_EC20_PID) {
+                       altsetting = handle_quectel_ec20(dev, ifnum);
+                       goto done;
+               }
+
                /*
                 * Gobi 2K+ USB layout:
                 * 0: QMI/net
@@ -301,29 +345,39 @@ static int qcprobe(struct usb_serial *serial, const struct usb_device_id *id)
                break;
        case QCSERIAL_HWI:
                /*
-                * Huawei layout:
-                * 0: AT-capable modem port
-                * 1: DM/DIAG
-                * 2: AT-capable modem port
-                * 3: CCID-compatible PCSC interface
-                * 4: QMI/net
-                * 5: NMEA
+                * Huawei devices map functions by subclass + protocol
+                * instead of interface numbers. The protocol identify
+                * a specific function, while the subclass indicate a
+                * specific firmware source
+                *
+                * This is a blacklist of functions known to be
+                * non-serial.  The rest are assumed to be serial and
+                * will be handled by this driver
                 */
-               switch (ifnum) {
-               case 0:
-               case 2:
-                       dev_dbg(dev, "Modem port found\n");
-                       break;
-               case 1:
-                       dev_dbg(dev, "DM/DIAG interface found\n");
-                       break;
-               case 5:
-                       dev_dbg(dev, "NMEA GPS interface found\n");
-                       break;
-               default:
-                       /* don't claim any unsupported interface */
+               switch (intf->desc.bInterfaceProtocol) {
+                       /* QMI combined (qmi_wwan) */
+               case 0x07:
+               case 0x37:
+               case 0x67:
+                       /* QMI data (qmi_wwan) */
+               case 0x08:
+               case 0x38:
+               case 0x68:
+                       /* QMI control (qmi_wwan) */
+               case 0x09:
+               case 0x39:
+               case 0x69:
+                       /* NCM like (huawei_cdc_ncm) */
+               case 0x16:
+               case 0x46:
+               case 0x76:
                        altsetting = -1;
                        break;
+               default:
+                       dev_dbg(dev, "Huawei type serial port found (%02x/%02x/%02x)\n",
+                               intf->desc.bInterfaceClass,
+                               intf->desc.bInterfaceSubClass,
+                               intf->desc.bInterfaceProtocol);
                }
                break;
        default:
index e9da41d9fe7fce04c24ee604b3d17a832dbded0e..2694df2f4559b0116e5e96ebc0587017f818fc39 100644 (file)
@@ -159,6 +159,7 @@ static const struct usb_device_id ti_id_table_3410[] = {
        { USB_DEVICE(ABBOTT_VENDOR_ID, ABBOTT_STEREO_PLUG_ID) },
        { USB_DEVICE(ABBOTT_VENDOR_ID, ABBOTT_STRIP_PORT_ID) },
        { USB_DEVICE(TI_VENDOR_ID, FRI2_PRODUCT_ID) },
+       { USB_DEVICE(HONEYWELL_VENDOR_ID, HONEYWELL_HGI80_PRODUCT_ID) },
        { }     /* terminator */
 };
 
@@ -191,6 +192,7 @@ static const struct usb_device_id ti_id_table_combined[] = {
        { USB_DEVICE(ABBOTT_VENDOR_ID, ABBOTT_PRODUCT_ID) },
        { USB_DEVICE(ABBOTT_VENDOR_ID, ABBOTT_STRIP_PORT_ID) },
        { USB_DEVICE(TI_VENDOR_ID, FRI2_PRODUCT_ID) },
+       { USB_DEVICE(HONEYWELL_VENDOR_ID, HONEYWELL_HGI80_PRODUCT_ID) },
        { }     /* terminator */
 };
 
index 4a2423e84d55820b594ca43ed99fc8ae88b2f002..98f35c656c02d8589828e54a79b4675b76c35a2e 100644 (file)
 #define ABBOTT_PRODUCT_ID              ABBOTT_STEREO_PLUG_ID
 #define ABBOTT_STRIP_PORT_ID           0x3420
 
+/* Honeywell vendor and product IDs */
+#define HONEYWELL_VENDOR_ID            0x10ac
+#define HONEYWELL_HGI80_PRODUCT_ID     0x0102  /* Honeywell HGI80 */
+
 /* Commands */
 #define TI_GET_VERSION                 0x01
 #define TI_GET_PORT_STATUS             0x02
index 3658662898fcb170fcdca07a8a676383e4d70347..a204782ae530e1de8f7982f869a94f9b80ce9dad 100644 (file)
@@ -53,6 +53,7 @@ DEVICE(funsoft, FUNSOFT_IDS);
 
 /* Infineon Flashloader driver */
 #define FLASHLOADER_IDS()              \
+       { USB_DEVICE_INTERFACE_CLASS(0x058b, 0x0041, USB_CLASS_CDC_DATA) }, \
        { USB_DEVICE(0x8087, 0x0716) }
 DEVICE(flashloader, FLASHLOADER_IDS);
 
index e6915166443607283f8229eaca83fac38ed68377..5c66d3f7a6d070c54632751af97ef3c3d660744b 100644 (file)
@@ -796,6 +796,10 @@ static int uas_slave_configure(struct scsi_device *sdev)
        if (devinfo->flags & US_FL_NO_REPORT_OPCODES)
                sdev->no_report_opcodes = 1;
 
+       /* A few buggy USB-ATA bridges don't understand FUA */
+       if (devinfo->flags & US_FL_BROKEN_FUA)
+               sdev->broken_fua = 1;
+
        scsi_change_queue_depth(sdev, devinfo->qdepth - 2);
        return 0;
 }
index 6b2479123de7762f7145c93fdcd58efb11f51093..7ffe4209067bb35b62220660997b4d83344706ed 100644 (file)
@@ -1987,7 +1987,7 @@ UNUSUAL_DEV(  0x14cd, 0x6600, 0x0201, 0x0201,
                US_FL_IGNORE_RESIDUE ),
 
 /* Reported by Michael Büsch <m@bues.ch> */
-UNUSUAL_DEV(  0x152d, 0x0567, 0x0114, 0x0114,
+UNUSUAL_DEV(  0x152d, 0x0567, 0x0114, 0x0116,
                "JMicron",
                "USB to ATA/ATAPI Bridge",
                USB_SC_DEVICE, USB_PR_DEVICE, NULL,
index c85ea530085f12d86ca691d82122f04e9f2166ae..ccc113e83d88e2b1e69e207989a5d5b49d526ae2 100644 (file)
@@ -132,7 +132,7 @@ UNUSUAL_DEV(0x152d, 0x0567, 0x0000, 0x9999,
                "JMicron",
                "JMS567",
                USB_SC_DEVICE, USB_PR_DEVICE, NULL,
-               US_FL_NO_REPORT_OPCODES),
+               US_FL_BROKEN_FUA | US_FL_NO_REPORT_OPCODES),
 
 /* Reported-by: Hans de Goede <hdegoede@redhat.com> */
 UNUSUAL_DEV(0x2109, 0x0711, 0x0000, 0x9999,
index da6e2ce77495b21ec127209664567b7e2f8f467e..850d86ca685b273344271eda7c95ad4f82b28244 100644 (file)
@@ -31,21 +31,6 @@ menuconfig VFIO
 
          If you don't know what to do here, say N.
 
-menuconfig VFIO_NOIOMMU
-       bool "VFIO No-IOMMU support"
-       depends on VFIO
-       help
-         VFIO is built on the ability to isolate devices using the IOMMU.
-         Only with an IOMMU can userspace access to DMA capable devices be
-         considered secure.  VFIO No-IOMMU mode enables IOMMU groups for
-         devices without IOMMU backing for the purpose of re-using the VFIO
-         infrastructure in a non-secure mode.  Use of this mode will result
-         in an unsupportable kernel and will therefore taint the kernel.
-         Device assignment to virtual machines is also not possible with
-         this mode since there is no IOMMU to provide DMA translation.
-
-         If you don't know what to do here, say N.
-
 source "drivers/vfio/pci/Kconfig"
 source "drivers/vfio/platform/Kconfig"
 source "virt/lib/Kconfig"
index 32b88bd2c82c7e3a3f4cd8cae11a253a171c76fa..56bf6dbb93db7ac281a0af4fa01a8d212fd87670 100644 (file)
@@ -940,13 +940,13 @@ static int vfio_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
        if (pdev->hdr_type != PCI_HEADER_TYPE_NORMAL)
                return -EINVAL;
 
-       group = vfio_iommu_group_get(&pdev->dev);
+       group = iommu_group_get(&pdev->dev);
        if (!group)
                return -EINVAL;
 
        vdev = kzalloc(sizeof(*vdev), GFP_KERNEL);
        if (!vdev) {
-               vfio_iommu_group_put(group, &pdev->dev);
+               iommu_group_put(group);
                return -ENOMEM;
        }
 
@@ -957,7 +957,7 @@ static int vfio_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
 
        ret = vfio_add_group_dev(&pdev->dev, &vfio_pci_ops, vdev);
        if (ret) {
-               vfio_iommu_group_put(group, &pdev->dev);
+               iommu_group_put(group);
                kfree(vdev);
                return ret;
        }
@@ -993,7 +993,7 @@ static void vfio_pci_remove(struct pci_dev *pdev)
        if (!vdev)
                return;
 
-       vfio_iommu_group_put(pdev->dev.iommu_group, &pdev->dev);
+       iommu_group_put(pdev->dev.iommu_group);
        kfree(vdev);
 
        if (vfio_pci_is_vga(pdev)) {
@@ -1035,7 +1035,7 @@ static pci_ers_result_t vfio_pci_aer_err_detected(struct pci_dev *pdev,
        return PCI_ERS_RESULT_CAN_RECOVER;
 }
 
-static struct pci_error_handlers vfio_err_handlers = {
+static const struct pci_error_handlers vfio_err_handlers = {
        .error_detected = vfio_pci_aer_err_detected,
 };
 
index f1625dcfbb23d49d6b0586977a203462df0e75a5..b1cc3a768784426fbf7616316aa9731f21b77ddb 100644 (file)
@@ -92,7 +92,6 @@ static struct platform_driver vfio_platform_driver = {
        .remove         = vfio_platform_remove,
        .driver = {
                .name   = "vfio-platform",
-               .owner  = THIS_MODULE,
        },
 };
 
index a1c50d63079200ce90741ccd55e60bc703c73eb2..418cdd9ba3f4841353c5cbdddb345e9363578736 100644 (file)
@@ -51,13 +51,10 @@ static vfio_platform_reset_fn_t vfio_platform_lookup_reset(const char *compat,
 
 static void vfio_platform_get_reset(struct vfio_platform_device *vdev)
 {
-       char modname[256];
-
        vdev->reset = vfio_platform_lookup_reset(vdev->compat,
                                                &vdev->reset_module);
        if (!vdev->reset) {
-               snprintf(modname, 256, "vfio-reset:%s", vdev->compat);
-               request_module(modname);
+               request_module("vfio-reset:%s", vdev->compat);
                vdev->reset = vfio_platform_lookup_reset(vdev->compat,
                                                         &vdev->reset_module);
        }
index de632da2e22f60d4eee042631821c1a4a9b7e558..6070b793cbcb244d98a784bf6c41a5f0fabb662b 100644 (file)
@@ -62,7 +62,6 @@ struct vfio_container {
        struct rw_semaphore             group_lock;
        struct vfio_iommu_driver        *iommu_driver;
        void                            *iommu_data;
-       bool                            noiommu;
 };
 
 struct vfio_unbound_dev {
@@ -85,7 +84,6 @@ struct vfio_group {
        struct list_head                unbound_list;
        struct mutex                    unbound_lock;
        atomic_t                        opened;
-       bool                            noiommu;
 };
 
 struct vfio_device {
@@ -97,147 +95,6 @@ struct vfio_device {
        void                            *device_data;
 };
 
-#ifdef CONFIG_VFIO_NOIOMMU
-static bool noiommu __read_mostly;
-module_param_named(enable_unsafe_noiommu_support,
-                  noiommu, bool, S_IRUGO | S_IWUSR);
-MODULE_PARM_DESC(enable_unsafe_noiommu_mode, "Enable UNSAFE, no-IOMMU mode.  This mode provides no device isolation, no DMA translation, no host kernel protection, cannot be used for device assignment to virtual machines, requires RAWIO permissions, and will taint the kernel.  If you do not know what this is for, step away. (default: false)");
-#endif
-
-/*
- * vfio_iommu_group_{get,put} are only intended for VFIO bus driver probe
- * and remove functions, any use cases other than acquiring the first
- * reference for the purpose of calling vfio_add_group_dev() or removing
- * that symmetric reference after vfio_del_group_dev() should use the raw
- * iommu_group_{get,put} functions.  In particular, vfio_iommu_group_put()
- * removes the device from the dummy group and cannot be nested.
- */
-struct iommu_group *vfio_iommu_group_get(struct device *dev)
-{
-       struct iommu_group *group;
-       int __maybe_unused ret;
-
-       group = iommu_group_get(dev);
-
-#ifdef CONFIG_VFIO_NOIOMMU
-       /*
-        * With noiommu enabled, an IOMMU group will be created for a device
-        * that doesn't already have one and doesn't have an iommu_ops on their
-        * bus.  We use iommu_present() again in the main code to detect these
-        * fake groups.
-        */
-       if (group || !noiommu || iommu_present(dev->bus))
-               return group;
-
-       group = iommu_group_alloc();
-       if (IS_ERR(group))
-               return NULL;
-
-       iommu_group_set_name(group, "vfio-noiommu");
-       ret = iommu_group_add_device(group, dev);
-       iommu_group_put(group);
-       if (ret)
-               return NULL;
-
-       /*
-        * Where to taint?  At this point we've added an IOMMU group for a
-        * device that is not backed by iommu_ops, therefore any iommu_
-        * callback using iommu_ops can legitimately Oops.  So, while we may
-        * be about to give a DMA capable device to a user without IOMMU
-        * protection, which is clearly taint-worthy, let's go ahead and do
-        * it here.
-        */
-       add_taint(TAINT_USER, LOCKDEP_STILL_OK);
-       dev_warn(dev, "Adding kernel taint for vfio-noiommu group on device\n");
-#endif
-
-       return group;
-}
-EXPORT_SYMBOL_GPL(vfio_iommu_group_get);
-
-void vfio_iommu_group_put(struct iommu_group *group, struct device *dev)
-{
-#ifdef CONFIG_VFIO_NOIOMMU
-       if (!iommu_present(dev->bus))
-               iommu_group_remove_device(dev);
-#endif
-
-       iommu_group_put(group);
-}
-EXPORT_SYMBOL_GPL(vfio_iommu_group_put);
-
-#ifdef CONFIG_VFIO_NOIOMMU
-static void *vfio_noiommu_open(unsigned long arg)
-{
-       if (arg != VFIO_NOIOMMU_IOMMU)
-               return ERR_PTR(-EINVAL);
-       if (!capable(CAP_SYS_RAWIO))
-               return ERR_PTR(-EPERM);
-
-       return NULL;
-}
-
-static void vfio_noiommu_release(void *iommu_data)
-{
-}
-
-static long vfio_noiommu_ioctl(void *iommu_data,
-                              unsigned int cmd, unsigned long arg)
-{
-       if (cmd == VFIO_CHECK_EXTENSION)
-               return arg == VFIO_NOIOMMU_IOMMU ? 1 : 0;
-
-       return -ENOTTY;
-}
-
-static int vfio_iommu_present(struct device *dev, void *unused)
-{
-       return iommu_present(dev->bus) ? 1 : 0;
-}
-
-static int vfio_noiommu_attach_group(void *iommu_data,
-                                    struct iommu_group *iommu_group)
-{
-       return iommu_group_for_each_dev(iommu_group, NULL,
-                                       vfio_iommu_present) ? -EINVAL : 0;
-}
-
-static void vfio_noiommu_detach_group(void *iommu_data,
-                                     struct iommu_group *iommu_group)
-{
-}
-
-static struct vfio_iommu_driver_ops vfio_noiommu_ops = {
-       .name = "vfio-noiommu",
-       .owner = THIS_MODULE,
-       .open = vfio_noiommu_open,
-       .release = vfio_noiommu_release,
-       .ioctl = vfio_noiommu_ioctl,
-       .attach_group = vfio_noiommu_attach_group,
-       .detach_group = vfio_noiommu_detach_group,
-};
-
-static struct vfio_iommu_driver vfio_noiommu_driver = {
-       .ops = &vfio_noiommu_ops,
-};
-
-/*
- * Wrap IOMMU drivers, the noiommu driver is the one and only driver for
- * noiommu groups (and thus containers) and not available for normal groups.
- */
-#define vfio_for_each_iommu_driver(con, pos)                           \
-       for (pos = con->noiommu ? &vfio_noiommu_driver :                \
-            list_first_entry(&vfio.iommu_drivers_list,                 \
-                             struct vfio_iommu_driver, vfio_next);     \
-            (con->noiommu ? pos != NULL :                              \
-                       &pos->vfio_next != &vfio.iommu_drivers_list);   \
-             pos = con->noiommu ? NULL : list_next_entry(pos, vfio_next))
-#else
-#define vfio_for_each_iommu_driver(con, pos)                           \
-       list_for_each_entry(pos, &vfio.iommu_drivers_list, vfio_next)
-#endif
-
-
 /**
  * IOMMU driver registration
  */
@@ -342,8 +199,7 @@ static void vfio_group_unlock_and_free(struct vfio_group *group)
 /**
  * Group objects - create, release, get, put, search
  */
-static struct vfio_group *vfio_create_group(struct iommu_group *iommu_group,
-                                           bool noiommu)
+static struct vfio_group *vfio_create_group(struct iommu_group *iommu_group)
 {
        struct vfio_group *group, *tmp;
        struct device *dev;
@@ -361,7 +217,6 @@ static struct vfio_group *vfio_create_group(struct iommu_group *iommu_group,
        atomic_set(&group->container_users, 0);
        atomic_set(&group->opened, 0);
        group->iommu_group = iommu_group;
-       group->noiommu = noiommu;
 
        group->nb.notifier_call = vfio_iommu_group_notifier;
 
@@ -397,8 +252,7 @@ static struct vfio_group *vfio_create_group(struct iommu_group *iommu_group,
 
        dev = device_create(vfio.class, NULL,
                            MKDEV(MAJOR(vfio.group_devt), minor),
-                           group, "%s%d", noiommu ? "noiommu-" : "",
-                           iommu_group_id(iommu_group));
+                           group, "%d", iommu_group_id(iommu_group));
        if (IS_ERR(dev)) {
                vfio_free_group_minor(minor);
                vfio_group_unlock_and_free(group);
@@ -682,7 +536,7 @@ static int vfio_group_nb_add_dev(struct vfio_group *group, struct device *dev)
                return 0;
 
        /* TODO Prevent device auto probing */
-       WARN("Device %s added to live group %d!\n", dev_name(dev),
+       WARN(1, "Device %s added to live group %d!\n", dev_name(dev),
             iommu_group_id(group->iommu_group));
 
        return 0;
@@ -786,8 +640,7 @@ int vfio_add_group_dev(struct device *dev,
 
        group = vfio_group_get_from_iommu(iommu_group);
        if (!group) {
-               group = vfio_create_group(iommu_group,
-                                         !iommu_present(dev->bus));
+               group = vfio_create_group(iommu_group);
                if (IS_ERR(group)) {
                        iommu_group_put(iommu_group);
                        return PTR_ERR(group);
@@ -999,7 +852,8 @@ static long vfio_ioctl_check_extension(struct vfio_container *container,
                 */
                if (!driver) {
                        mutex_lock(&vfio.iommu_drivers_lock);
-                       vfio_for_each_iommu_driver(container, driver) {
+                       list_for_each_entry(driver, &vfio.iommu_drivers_list,
+                                           vfio_next) {
                                if (!try_module_get(driver->ops->owner))
                                        continue;
 
@@ -1068,7 +922,7 @@ static long vfio_ioctl_set_iommu(struct vfio_container *container,
        }
 
        mutex_lock(&vfio.iommu_drivers_lock);
-       vfio_for_each_iommu_driver(container, driver) {
+       list_for_each_entry(driver, &vfio.iommu_drivers_list, vfio_next) {
                void *data;
 
                if (!try_module_get(driver->ops->owner))
@@ -1333,9 +1187,6 @@ static int vfio_group_set_container(struct vfio_group *group, int container_fd)
        if (atomic_read(&group->container_users))
                return -EINVAL;
 
-       if (group->noiommu && !capable(CAP_SYS_RAWIO))
-               return -EPERM;
-
        f = fdget(container_fd);
        if (!f.file)
                return -EBADF;
@@ -1351,13 +1202,6 @@ static int vfio_group_set_container(struct vfio_group *group, int container_fd)
 
        down_write(&container->group_lock);
 
-       /* Real groups and fake groups cannot mix */
-       if (!list_empty(&container->group_list) &&
-           container->noiommu != group->noiommu) {
-               ret = -EPERM;
-               goto unlock_out;
-       }
-
        driver = container->iommu_driver;
        if (driver) {
                ret = driver->ops->attach_group(container->iommu_data,
@@ -1367,7 +1211,6 @@ static int vfio_group_set_container(struct vfio_group *group, int container_fd)
        }
 
        group->container = container;
-       container->noiommu = group->noiommu;
        list_add(&group->container_next, &container->group_list);
 
        /* Get a reference on the container and mark a user within the group */
@@ -1398,9 +1241,6 @@ static int vfio_group_get_device_fd(struct vfio_group *group, char *buf)
            !group->container->iommu_driver || !vfio_group_viable(group))
                return -EINVAL;
 
-       if (group->noiommu && !capable(CAP_SYS_RAWIO))
-               return -EPERM;
-
        device = vfio_device_get_from_name(group, buf);
        if (!device)
                return -ENODEV;
@@ -1443,10 +1283,6 @@ static int vfio_group_get_device_fd(struct vfio_group *group, char *buf)
 
        fd_install(ret, filep);
 
-       if (group->noiommu)
-               dev_warn(device->dev, "vfio-noiommu device opened by user "
-                        "(%s:%d)\n", current->comm, task_pid_nr(current));
-
        return ret;
 }
 
@@ -1535,11 +1371,6 @@ static int vfio_group_fops_open(struct inode *inode, struct file *filep)
        if (!group)
                return -ENODEV;
 
-       if (group->noiommu && !capable(CAP_SYS_RAWIO)) {
-               vfio_group_put(group);
-               return -EPERM;
-       }
-
        /* Do we need multiple instances of the group open?  Seems not. */
        opened = atomic_cmpxchg(&group->opened, 0, 1);
        if (opened) {
@@ -1702,11 +1533,6 @@ struct vfio_group *vfio_group_get_external_user(struct file *filep)
        if (!atomic_inc_not_zero(&group->container_users))
                return ERR_PTR(-EINVAL);
 
-       if (group->noiommu) {
-               atomic_dec(&group->container_users);
-               return ERR_PTR(-EPERM);
-       }
-
        if (!group->container->iommu_driver ||
                        !vfio_group_viable(group)) {
                atomic_dec(&group->container_users);
index eec2f11809ff2463d2a714224925af9c679fead1..ad2146a9ab2d4b19cca5469402c203ade61e8545 100644 (file)
@@ -819,7 +819,7 @@ long vhost_vring_ioctl(struct vhost_dev *d, int ioctl, void __user *argp)
                BUILD_BUG_ON(__alignof__ *vq->used > VRING_USED_ALIGN_SIZE);
                if ((a.avail_user_addr & (VRING_AVAIL_ALIGN_SIZE - 1)) ||
                    (a.used_user_addr & (VRING_USED_ALIGN_SIZE - 1)) ||
-                   (a.log_guest_addr & (sizeof(u64) - 1))) {
+                   (a.log_guest_addr & (VRING_USED_ALIGN_SIZE - 1))) {
                        r = -EINVAL;
                        break;
                }
@@ -1369,7 +1369,7 @@ int vhost_get_vq_desc(struct vhost_virtqueue *vq,
        /* Grab the next descriptor number they're advertising, and increment
         * the index we've seen. */
        if (unlikely(__get_user(ring_head,
-                               &vq->avail->ring[last_avail_idx % vq->num]))) {
+                               &vq->avail->ring[last_avail_idx & (vq->num - 1)]))) {
                vq_err(vq, "Failed to read head: idx %d address %p\n",
                       last_avail_idx,
                       &vq->avail->ring[last_avail_idx % vq->num]);
@@ -1489,7 +1489,7 @@ static int __vhost_add_used_n(struct vhost_virtqueue *vq,
        u16 old, new;
        int start;
 
-       start = vq->last_used_idx % vq->num;
+       start = vq->last_used_idx & (vq->num - 1);
        used = vq->used->ring + start;
        if (count == 1) {
                if (__put_user(heads[0].id, &used->id)) {
@@ -1531,7 +1531,7 @@ int vhost_add_used_n(struct vhost_virtqueue *vq, struct vring_used_elem *heads,
 {
        int start, n, r;
 
-       start = vq->last_used_idx % vq->num;
+       start = vq->last_used_idx & (vq->num - 1);
        n = vq->num - start;
        if (n < count) {
                r = __vhost_add_used_n(vq, heads, n);
index b335c1ae8625106efff818d696ebad532ade7f17..fe00a07c122e69f0735baf8832fdd112677b4dd6 100644 (file)
@@ -479,7 +479,10 @@ static enum fsl_diu_monitor_port fsl_diu_name_to_port(const char *s)
                        port = FSL_DIU_PORT_DLVDS;
        }
 
-       return diu_ops.valid_monitor_port(port);
+       if (diu_ops.valid_monitor_port)
+               port = diu_ops.valid_monitor_port(port);
+
+       return port;
 }
 
 /*
@@ -1915,6 +1918,14 @@ static int __init fsl_diu_init(void)
 #else
        monitor_port = fsl_diu_name_to_port(monitor_string);
 #endif
+
+       /*
+        * Must to verify set_pixel_clock. If not implement on platform,
+        * then that means that there is no platform support for the DIU.
+        */
+       if (!diu_ops.set_pixel_clock)
+               return -ENODEV;
+
        pr_info("Freescale Display Interface Unit (DIU) framebuffer driver\n");
 
 #ifdef CONFIG_NOT_COHERENT_CACHE
index 99ca268c1cddf24332308b58fbeb051d565b8dca..d05a54922ba6953bb686f07ba2ac4315f91aeace 100644 (file)
@@ -275,6 +275,12 @@ const struct omap_video_timings omap_dss_pal_timings = {
        .vbp            = 41,
 
        .interlace      = true,
+
+       .hsync_level = OMAPDSS_SIG_ACTIVE_LOW,
+       .vsync_level = OMAPDSS_SIG_ACTIVE_LOW,
+       .data_pclk_edge = OMAPDSS_DRIVE_SIG_RISING_EDGE,
+       .de_level = OMAPDSS_SIG_ACTIVE_HIGH,
+       .sync_pclk_edge = OMAPDSS_DRIVE_SIG_FALLING_EDGE,
 };
 EXPORT_SYMBOL(omap_dss_pal_timings);
 
@@ -290,6 +296,12 @@ const struct omap_video_timings omap_dss_ntsc_timings = {
        .vbp            = 31,
 
        .interlace      = true,
+
+       .hsync_level = OMAPDSS_SIG_ACTIVE_LOW,
+       .vsync_level = OMAPDSS_SIG_ACTIVE_LOW,
+       .data_pclk_edge = OMAPDSS_DRIVE_SIG_RISING_EDGE,
+       .de_level = OMAPDSS_SIG_ACTIVE_HIGH,
+       .sync_pclk_edge = OMAPDSS_DRIVE_SIG_FALLING_EDGE,
 };
 EXPORT_SYMBOL(omap_dss_ntsc_timings);
 
index b1877d73fa563d6d48f2d55b7958f02daa8d9ad7..7062bb0975a521f1a28125c092c2f0d0bbd35787 100644 (file)
@@ -412,6 +412,7 @@ static int virtio_init(void)
 static void __exit virtio_exit(void)
 {
        bus_unregister(&virtio_bus);
+       ida_destroy(&virtio_index_ida);
 }
 core_initcall(virtio_init);
 module_exit(virtio_exit);
index 096b857e7b75abad526f487c84392d863c3c6b06..ee663c458b20a449c353c5ea0df4632933087e66 100644 (file)
@@ -80,6 +80,12 @@ struct vring_virtqueue {
        /* Last used index we've seen. */
        u16 last_used_idx;
 
+       /* Last written value to avail->flags */
+       u16 avail_flags_shadow;
+
+       /* Last written value to avail->idx in guest byte order */
+       u16 avail_idx_shadow;
+
        /* How to notify other side. FIXME: commonalize hcalls! */
        bool (*notify)(struct virtqueue *vq);
 
@@ -109,7 +115,7 @@ static struct vring_desc *alloc_indirect(struct virtqueue *_vq,
         * otherwise virt_to_phys will give us bogus addresses in the
         * virtqueue.
         */
-       gfp &= ~(__GFP_HIGHMEM | __GFP_HIGH);
+       gfp &= ~__GFP_HIGHMEM;
 
        desc = kmalloc(total_sg * sizeof(struct vring_desc), gfp);
        if (!desc)
@@ -235,13 +241,14 @@ static inline int virtqueue_add(struct virtqueue *_vq,
 
        /* Put entry in available array (but don't update avail->idx until they
         * do sync). */
-       avail = virtio16_to_cpu(_vq->vdev, vq->vring.avail->idx) & (vq->vring.num - 1);
+       avail = vq->avail_idx_shadow & (vq->vring.num - 1);
        vq->vring.avail->ring[avail] = cpu_to_virtio16(_vq->vdev, head);
 
        /* Descriptors and available array need to be set before we expose the
         * new available array entries. */
        virtio_wmb(vq->weak_barriers);
-       vq->vring.avail->idx = cpu_to_virtio16(_vq->vdev, virtio16_to_cpu(_vq->vdev, vq->vring.avail->idx) + 1);
+       vq->avail_idx_shadow++;
+       vq->vring.avail->idx = cpu_to_virtio16(_vq->vdev, vq->avail_idx_shadow);
        vq->num_added++;
 
        pr_debug("Added buffer head %i to %p\n", head, vq);
@@ -354,8 +361,8 @@ bool virtqueue_kick_prepare(struct virtqueue *_vq)
         * event. */
        virtio_mb(vq->weak_barriers);
 
-       old = virtio16_to_cpu(_vq->vdev, vq->vring.avail->idx) - vq->num_added;
-       new = virtio16_to_cpu(_vq->vdev, vq->vring.avail->idx);
+       old = vq->avail_idx_shadow - vq->num_added;
+       new = vq->avail_idx_shadow;
        vq->num_added = 0;
 
 #ifdef DEBUG
@@ -510,7 +517,7 @@ void *virtqueue_get_buf(struct virtqueue *_vq, unsigned int *len)
        /* If we expect an interrupt for the next entry, tell host
         * by writing event index and flush out the write before
         * the read in the next get_buf call. */
-       if (!(vq->vring.avail->flags & cpu_to_virtio16(_vq->vdev, VRING_AVAIL_F_NO_INTERRUPT))) {
+       if (!(vq->avail_flags_shadow & VRING_AVAIL_F_NO_INTERRUPT)) {
                vring_used_event(&vq->vring) = cpu_to_virtio16(_vq->vdev, vq->last_used_idx);
                virtio_mb(vq->weak_barriers);
        }
@@ -537,7 +544,11 @@ void virtqueue_disable_cb(struct virtqueue *_vq)
 {
        struct vring_virtqueue *vq = to_vvq(_vq);
 
-       vq->vring.avail->flags |= cpu_to_virtio16(_vq->vdev, VRING_AVAIL_F_NO_INTERRUPT);
+       if (!(vq->avail_flags_shadow & VRING_AVAIL_F_NO_INTERRUPT)) {
+               vq->avail_flags_shadow |= VRING_AVAIL_F_NO_INTERRUPT;
+               vq->vring.avail->flags = cpu_to_virtio16(_vq->vdev, vq->avail_flags_shadow);
+       }
+
 }
 EXPORT_SYMBOL_GPL(virtqueue_disable_cb);
 
@@ -565,7 +576,10 @@ unsigned virtqueue_enable_cb_prepare(struct virtqueue *_vq)
        /* Depending on the VIRTIO_RING_F_EVENT_IDX feature, we need to
         * either clear the flags bit or point the event index at the next
         * entry. Always do both to keep code simple. */
-       vq->vring.avail->flags &= cpu_to_virtio16(_vq->vdev, ~VRING_AVAIL_F_NO_INTERRUPT);
+       if (vq->avail_flags_shadow & VRING_AVAIL_F_NO_INTERRUPT) {
+               vq->avail_flags_shadow &= ~VRING_AVAIL_F_NO_INTERRUPT;
+               vq->vring.avail->flags = cpu_to_virtio16(_vq->vdev, vq->avail_flags_shadow);
+       }
        vring_used_event(&vq->vring) = cpu_to_virtio16(_vq->vdev, last_used_idx = vq->last_used_idx);
        END_USE(vq);
        return last_used_idx;
@@ -633,9 +647,12 @@ bool virtqueue_enable_cb_delayed(struct virtqueue *_vq)
        /* Depending on the VIRTIO_RING_F_USED_EVENT_IDX feature, we need to
         * either clear the flags bit or point the event index at the next
         * entry. Always do both to keep code simple. */
-       vq->vring.avail->flags &= cpu_to_virtio16(_vq->vdev, ~VRING_AVAIL_F_NO_INTERRUPT);
+       if (vq->avail_flags_shadow & VRING_AVAIL_F_NO_INTERRUPT) {
+               vq->avail_flags_shadow &= ~VRING_AVAIL_F_NO_INTERRUPT;
+               vq->vring.avail->flags = cpu_to_virtio16(_vq->vdev, vq->avail_flags_shadow);
+       }
        /* TODO: tune this threshold */
-       bufs = (u16)(virtio16_to_cpu(_vq->vdev, vq->vring.avail->idx) - vq->last_used_idx) * 3 / 4;
+       bufs = (u16)(vq->avail_idx_shadow - vq->last_used_idx) * 3 / 4;
        vring_used_event(&vq->vring) = cpu_to_virtio16(_vq->vdev, vq->last_used_idx + bufs);
        virtio_mb(vq->weak_barriers);
        if (unlikely((u16)(virtio16_to_cpu(_vq->vdev, vq->vring.used->idx) - vq->last_used_idx) > bufs)) {
@@ -670,7 +687,8 @@ void *virtqueue_detach_unused_buf(struct virtqueue *_vq)
                /* detach_buf clears data, so grab it now. */
                buf = vq->data[i];
                detach_buf(vq, i);
-               vq->vring.avail->idx = cpu_to_virtio16(_vq->vdev, virtio16_to_cpu(_vq->vdev, vq->vring.avail->idx) - 1);
+               vq->avail_idx_shadow--;
+               vq->vring.avail->idx = cpu_to_virtio16(_vq->vdev, vq->avail_idx_shadow);
                END_USE(vq);
                return buf;
        }
@@ -735,6 +753,8 @@ struct virtqueue *vring_new_virtqueue(unsigned int index,
        vq->weak_barriers = weak_barriers;
        vq->broken = false;
        vq->last_used_idx = 0;
+       vq->avail_flags_shadow = 0;
+       vq->avail_idx_shadow = 0;
        vq->num_added = 0;
        list_add_tail(&vq->vq.list, &vdev->vqs);
 #ifdef DEBUG
@@ -746,8 +766,10 @@ struct virtqueue *vring_new_virtqueue(unsigned int index,
        vq->event = virtio_has_feature(vdev, VIRTIO_RING_F_EVENT_IDX);
 
        /* No callback?  Tell other side not to bother us. */
-       if (!callback)
-               vq->vring.avail->flags |= cpu_to_virtio16(vdev, VRING_AVAIL_F_NO_INTERRUPT);
+       if (!callback) {
+               vq->avail_flags_shadow |= VRING_AVAIL_F_NO_INTERRUPT;
+               vq->vring.avail->flags = cpu_to_virtio16(vdev, vq->avail_flags_shadow);
+       }
 
        /* Put everything in free lists. */
        vq->free_head = 0;
index 7a8a6c6952e92b7fd2b659e1e2e0f4cbd2c39919..1c427beffadd97b3e95522fc9236193006d58fcc 100644 (file)
@@ -446,7 +446,7 @@ config MAX63XX_WATCHDOG
 
 config IMX2_WDT
        tristate "IMX2+ Watchdog"
-       depends on ARCH_MXC
+       depends on ARCH_MXC || ARCH_LAYERSCAPE
        select REGMAP_MMIO
        select WATCHDOG_CORE
        help
index 6ad9df948711080ca3c87464d0195bdd3c0d9feb..b751f43d76ed5c9d8e168389a1238b9218bee46f 100644 (file)
@@ -123,6 +123,7 @@ static int mtk_wdt_stop(struct watchdog_device *wdt_dev)
 
        reg = readl(wdt_base + WDT_MODE);
        reg &= ~WDT_MODE_EN;
+       reg |= WDT_MODE_KEY;
        iowrite32(reg, wdt_base + WDT_MODE);
 
        return 0;
index d96bee017fd3caa2fbcde961cc3ba9941b34c341..6f17c935a6cf86b1fcb47856532a8d6374bd0d82 100644 (file)
@@ -205,7 +205,7 @@ static int omap_wdt_set_timeout(struct watchdog_device *wdog,
 
 static unsigned int omap_wdt_get_timeleft(struct watchdog_device *wdog)
 {
-       struct omap_wdt_dev *wdev = watchdog_get_drvdata(wdog);
+       struct omap_wdt_dev *wdev = to_omap_wdt_dev(wdog);
        void __iomem *base = wdev->base;
        u32 value;
 
index 4224b3ec83a5515dc76a57507ec81122dd9316e1..313cd1c6fda0efcfa03897f1d23fc18b138e3779 100644 (file)
@@ -80,7 +80,7 @@ static unsigned int heartbeat = DEFAULT_HEARTBEAT;
 
 static DEFINE_SPINLOCK(io_lock);
 static void __iomem    *wdt_base;
-struct clk             *wdt_clk;
+static struct clk      *wdt_clk;
 
 static int pnx4008_wdt_start(struct watchdog_device *wdd)
 {
@@ -161,7 +161,7 @@ static int pnx4008_wdt_probe(struct platform_device *pdev)
        if (IS_ERR(wdt_clk))
                return PTR_ERR(wdt_clk);
 
-       ret = clk_enable(wdt_clk);
+       ret = clk_prepare_enable(wdt_clk);
        if (ret)
                return ret;
 
@@ -184,7 +184,7 @@ static int pnx4008_wdt_probe(struct platform_device *pdev)
        return 0;
 
 disable_clk:
-       clk_disable(wdt_clk);
+       clk_disable_unprepare(wdt_clk);
        return ret;
 }
 
@@ -192,7 +192,7 @@ static int pnx4008_wdt_remove(struct platform_device *pdev)
 {
        watchdog_unregister_device(&pnx4008_wdd);
 
-       clk_disable(wdt_clk);
+       clk_disable_unprepare(wdt_clk);
 
        return 0;
 }
index 7f97cdd53f29624f6c732b0e44c0448a856c8a5c..9ec57608da82931e6f2a913246825ff9be11e034 100644 (file)
@@ -140,8 +140,10 @@ static int tegra_wdt_set_timeout(struct watchdog_device *wdd,
 {
        wdd->timeout = timeout;
 
-       if (watchdog_active(wdd))
+       if (watchdog_active(wdd)) {
+               tegra_wdt_stop(wdd);
                return tegra_wdt_start(wdd);
+       }
 
        return 0;
 }
index 91bf55a2002497eca6de68258515484ba9f13efa..20e2bba10400910cfbd86a68d3d6f988b9d77dec 100644 (file)
@@ -224,7 +224,7 @@ static int wdt_keepalive(void)
 
 static int wdt_set_timeout(int t)
 {
-       int tmrval;
+       unsigned int tmrval;
 
        /*
         * Convert seconds to watchdog counter time units, rounding up.
index 849500e4e14d14af7dd29fe7737d77d62f87a36d..524c22146429d7c87acc8682976031c2f8a727d6 100644 (file)
@@ -39,6 +39,7 @@
 #include <asm/irq.h>
 #include <asm/idle.h>
 #include <asm/io_apic.h>
+#include <asm/i8259.h>
 #include <asm/xen/pci.h>
 #endif
 #include <asm/sync_bitops.h>
@@ -420,7 +421,7 @@ static int __must_check xen_allocate_irq_gsi(unsigned gsi)
                return xen_allocate_irq_dynamic();
 
        /* Legacy IRQ descriptors are already allocated by the arch. */
-       if (gsi < NR_IRQS_LEGACY)
+       if (gsi < nr_legacy_irqs())
                irq = gsi;
        else
                irq = irq_alloc_desc_at(gsi, -1);
@@ -446,7 +447,7 @@ static void xen_free_irq(unsigned irq)
        kfree(info);
 
        /* Legacy IRQ descriptors are managed by the arch. */
-       if (irq < NR_IRQS_LEGACY)
+       if (irq < nr_legacy_irqs())
                return;
 
        irq_free_desc(irq);
index e3e9e3d46d1bf55028cf4a7902fa72b494fb3ce6..96a1b8da53715e7501d09369ee9ef375f421e936 100644 (file)
@@ -281,7 +281,8 @@ static void handle_irq_for_port(unsigned port)
 
 static void consume_one_event(unsigned cpu,
                              struct evtchn_fifo_control_block *control_block,
-                             unsigned priority, unsigned long *ready)
+                             unsigned priority, unsigned long *ready,
+                             bool drop)
 {
        struct evtchn_fifo_queue *q = &per_cpu(cpu_queue, cpu);
        uint32_t head;
@@ -313,13 +314,17 @@ static void consume_one_event(unsigned cpu,
        if (head == 0)
                clear_bit(priority, ready);
 
-       if (evtchn_fifo_is_pending(port) && !evtchn_fifo_is_masked(port))
-               handle_irq_for_port(port);
+       if (evtchn_fifo_is_pending(port) && !evtchn_fifo_is_masked(port)) {
+               if (unlikely(drop))
+                       pr_warn("Dropping pending event for port %u\n", port);
+               else
+                       handle_irq_for_port(port);
+       }
 
        q->head[priority] = head;
 }
 
-static void evtchn_fifo_handle_events(unsigned cpu)
+static void __evtchn_fifo_handle_events(unsigned cpu, bool drop)
 {
        struct evtchn_fifo_control_block *control_block;
        unsigned long ready;
@@ -331,11 +336,16 @@ static void evtchn_fifo_handle_events(unsigned cpu)
 
        while (ready) {
                q = find_first_bit(&ready, EVTCHN_FIFO_MAX_QUEUES);
-               consume_one_event(cpu, control_block, q, &ready);
+               consume_one_event(cpu, control_block, q, &ready, drop);
                ready |= xchg(&control_block->ready, 0);
        }
 }
 
+static void evtchn_fifo_handle_events(unsigned cpu)
+{
+       __evtchn_fifo_handle_events(cpu, false);
+}
+
 static void evtchn_fifo_resume(void)
 {
        unsigned cpu;
@@ -420,6 +430,9 @@ static int evtchn_fifo_cpu_notification(struct notifier_block *self,
                if (!per_cpu(cpu_control_block, cpu))
                        ret = evtchn_fifo_alloc_control_block(cpu);
                break;
+       case CPU_DEAD:
+               __evtchn_fifo_handle_events(cpu, true);
+               break;
        default:
                break;
        }
index 00f40f051d95668b01ebf6b4c17e6f0e90912198..38272ad245516c272ab571bed1a5c962f4a0e808 100644 (file)
@@ -49,6 +49,8 @@
 #include <linux/init.h>
 #include <linux/mutex.h>
 #include <linux/cpu.h>
+#include <linux/mm.h>
+#include <linux/vmalloc.h>
 
 #include <xen/xen.h>
 #include <xen/events.h>
 struct per_user_data {
        struct mutex bind_mutex; /* serialize bind/unbind operations */
        struct rb_root evtchns;
+       unsigned int nr_evtchns;
 
        /* Notification ring, accessed via /dev/xen/evtchn. */
-#define EVTCHN_RING_SIZE     (PAGE_SIZE / sizeof(evtchn_port_t))
-#define EVTCHN_RING_MASK(_i) ((_i)&(EVTCHN_RING_SIZE-1))
+       unsigned int ring_size;
        evtchn_port_t *ring;
        unsigned int ring_cons, ring_prod, ring_overflow;
        struct mutex ring_cons_mutex; /* protect against concurrent readers */
@@ -80,10 +82,41 @@ struct user_evtchn {
        bool enabled;
 };
 
+static evtchn_port_t *evtchn_alloc_ring(unsigned int size)
+{
+       evtchn_port_t *ring;
+       size_t s = size * sizeof(*ring);
+
+       ring = kmalloc(s, GFP_KERNEL);
+       if (!ring)
+               ring = vmalloc(s);
+
+       return ring;
+}
+
+static void evtchn_free_ring(evtchn_port_t *ring)
+{
+       kvfree(ring);
+}
+
+static unsigned int evtchn_ring_offset(struct per_user_data *u,
+                                      unsigned int idx)
+{
+       return idx & (u->ring_size - 1);
+}
+
+static evtchn_port_t *evtchn_ring_entry(struct per_user_data *u,
+                                       unsigned int idx)
+{
+       return u->ring + evtchn_ring_offset(u, idx);
+}
+
 static int add_evtchn(struct per_user_data *u, struct user_evtchn *evtchn)
 {
        struct rb_node **new = &(u->evtchns.rb_node), *parent = NULL;
 
+       u->nr_evtchns++;
+
        while (*new) {
                struct user_evtchn *this;
 
@@ -107,6 +140,7 @@ static int add_evtchn(struct per_user_data *u, struct user_evtchn *evtchn)
 
 static void del_evtchn(struct per_user_data *u, struct user_evtchn *evtchn)
 {
+       u->nr_evtchns--;
        rb_erase(&evtchn->node, &u->evtchns);
        kfree(evtchn);
 }
@@ -144,8 +178,8 @@ static irqreturn_t evtchn_interrupt(int irq, void *data)
 
        spin_lock(&u->ring_prod_lock);
 
-       if ((u->ring_prod - u->ring_cons) < EVTCHN_RING_SIZE) {
-               u->ring[EVTCHN_RING_MASK(u->ring_prod)] = evtchn->port;
+       if ((u->ring_prod - u->ring_cons) < u->ring_size) {
+               *evtchn_ring_entry(u, u->ring_prod) = evtchn->port;
                wmb(); /* Ensure ring contents visible */
                if (u->ring_cons == u->ring_prod++) {
                        wake_up_interruptible(&u->evtchn_wait);
@@ -200,10 +234,10 @@ static ssize_t evtchn_read(struct file *file, char __user *buf,
        }
 
        /* Byte lengths of two chunks. Chunk split (if any) is at ring wrap. */
-       if (((c ^ p) & EVTCHN_RING_SIZE) != 0) {
-               bytes1 = (EVTCHN_RING_SIZE - EVTCHN_RING_MASK(c)) *
+       if (((c ^ p) & u->ring_size) != 0) {
+               bytes1 = (u->ring_size - evtchn_ring_offset(u, c)) *
                        sizeof(evtchn_port_t);
-               bytes2 = EVTCHN_RING_MASK(p) * sizeof(evtchn_port_t);
+               bytes2 = evtchn_ring_offset(u, p) * sizeof(evtchn_port_t);
        } else {
                bytes1 = (p - c) * sizeof(evtchn_port_t);
                bytes2 = 0;
@@ -219,7 +253,7 @@ static ssize_t evtchn_read(struct file *file, char __user *buf,
 
        rc = -EFAULT;
        rmb(); /* Ensure that we see the port before we copy it. */
-       if (copy_to_user(buf, &u->ring[EVTCHN_RING_MASK(c)], bytes1) ||
+       if (copy_to_user(buf, evtchn_ring_entry(u, c), bytes1) ||
            ((bytes2 != 0) &&
             copy_to_user(&buf[bytes1], &u->ring[0], bytes2)))
                goto unlock_out;
@@ -278,6 +312,66 @@ static ssize_t evtchn_write(struct file *file, const char __user *buf,
        return rc;
 }
 
+static int evtchn_resize_ring(struct per_user_data *u)
+{
+       unsigned int new_size;
+       evtchn_port_t *new_ring, *old_ring;
+       unsigned int p, c;
+
+       /*
+        * Ensure the ring is large enough to capture all possible
+        * events. i.e., one free slot for each bound event.
+        */
+       if (u->nr_evtchns <= u->ring_size)
+               return 0;
+
+       if (u->ring_size == 0)
+               new_size = 64;
+       else
+               new_size = 2 * u->ring_size;
+
+       new_ring = evtchn_alloc_ring(new_size);
+       if (!new_ring)
+               return -ENOMEM;
+
+       old_ring = u->ring;
+
+       /*
+        * Access to the ring contents is serialized by either the
+        * prod /or/ cons lock so take both when resizing.
+        */
+       mutex_lock(&u->ring_cons_mutex);
+       spin_lock_irq(&u->ring_prod_lock);
+
+       /*
+        * Copy the old ring contents to the new ring.
+        *
+        * If the ring contents crosses the end of the current ring,
+        * it needs to be copied in two chunks.
+        *
+        * +---------+    +------------------+
+        * |34567  12| -> |       1234567    |
+        * +-----p-c-+    +------------------+
+        */
+       p = evtchn_ring_offset(u, u->ring_prod);
+       c = evtchn_ring_offset(u, u->ring_cons);
+       if (p < c) {
+               memcpy(new_ring + c, u->ring + c, (u->ring_size - c) * sizeof(*u->ring));
+               memcpy(new_ring + u->ring_size, u->ring, p * sizeof(*u->ring));
+       } else
+               memcpy(new_ring + c, u->ring + c, (p - c) * sizeof(*u->ring));
+
+       u->ring = new_ring;
+       u->ring_size = new_size;
+
+       spin_unlock_irq(&u->ring_prod_lock);
+       mutex_unlock(&u->ring_cons_mutex);
+
+       evtchn_free_ring(old_ring);
+
+       return 0;
+}
+
 static int evtchn_bind_to_user(struct per_user_data *u, int port)
 {
        struct user_evtchn *evtchn;
@@ -305,6 +399,10 @@ static int evtchn_bind_to_user(struct per_user_data *u, int port)
        if (rc < 0)
                goto err;
 
+       rc = evtchn_resize_ring(u);
+       if (rc < 0)
+               goto err;
+
        rc = bind_evtchn_to_irqhandler(port, evtchn_interrupt, 0,
                                       u->name, evtchn);
        if (rc < 0)
@@ -503,13 +601,6 @@ static int evtchn_open(struct inode *inode, struct file *filp)
 
        init_waitqueue_head(&u->evtchn_wait);
 
-       u->ring = (evtchn_port_t *)__get_free_page(GFP_KERNEL);
-       if (u->ring == NULL) {
-               kfree(u->name);
-               kfree(u);
-               return -ENOMEM;
-       }
-
        mutex_init(&u->bind_mutex);
        mutex_init(&u->ring_cons_mutex);
        spin_lock_init(&u->ring_prod_lock);
@@ -532,7 +623,7 @@ static int evtchn_release(struct inode *inode, struct file *filp)
                evtchn_unbind_from_user(u, evtchn);
        }
 
-       free_page((unsigned long)u->ring);
+       evtchn_free_ring(u->ring);
        kfree(u->name);
        kfree(u);
 
index 2ea0b3b2a91d2585a2d37f8ead07f08f32c79826..1be5dd048622f6c8c4f9aa805514b9fd5b5c5d7b 100644 (file)
@@ -804,7 +804,7 @@ static int gntdev_mmap(struct file *flip, struct vm_area_struct *vma)
 
        vma->vm_ops = &gntdev_vmops;
 
-       vma->vm_flags |= VM_DONTEXPAND | VM_DONTDUMP;
+       vma->vm_flags |= VM_DONTEXPAND | VM_DONTDUMP | VM_IO;
 
        if (use_ptemod)
                vma->vm_flags |= VM_DONTCOPY;
index 58e38d586f524fd6b78b18594cbf2de593c1119e..4d529f3e40df93941c99f6fffee06da540f28ca2 100644 (file)
@@ -37,6 +37,7 @@ struct xen_pcibk_device {
        struct xen_pci_sharedinfo *sh_info;
        unsigned long flags;
        struct work_struct op_work;
+       struct xen_pci_op op;
 };
 
 struct xen_pcibk_dev_data {
index c4a0666de6f5e08a17edf4fcbcb001478d0e303b..73dafdc494aa8322e037f1d4a9ad4ec5530c5743 100644 (file)
@@ -70,6 +70,13 @@ static void xen_pcibk_control_isr(struct pci_dev *dev, int reset)
                enable ? "enable" : "disable");
 
        if (enable) {
+               /*
+                * The MSI or MSI-X should not have an IRQ handler. Otherwise
+                * if the guest terminates we BUG_ON in free_msi_irqs.
+                */
+               if (dev->msi_enabled || dev->msix_enabled)
+                       goto out;
+
                rc = request_irq(dev_data->irq,
                                xen_pcibk_guest_interrupt, IRQF_SHARED,
                                dev_data->irq_name, dev);
@@ -144,7 +151,12 @@ int xen_pcibk_enable_msi(struct xen_pcibk_device *pdev,
        if (unlikely(verbose_request))
                printk(KERN_DEBUG DRV_NAME ": %s: enable MSI\n", pci_name(dev));
 
-       status = pci_enable_msi(dev);
+       if (dev->msi_enabled)
+               status = -EALREADY;
+       else if (dev->msix_enabled)
+               status = -ENXIO;
+       else
+               status = pci_enable_msi(dev);
 
        if (status) {
                pr_warn_ratelimited("%s: error enabling MSI for guest %u: err %d\n",
@@ -173,20 +185,23 @@ static
 int xen_pcibk_disable_msi(struct xen_pcibk_device *pdev,
                          struct pci_dev *dev, struct xen_pci_op *op)
 {
-       struct xen_pcibk_dev_data *dev_data;
-
        if (unlikely(verbose_request))
                printk(KERN_DEBUG DRV_NAME ": %s: disable MSI\n",
                       pci_name(dev));
-       pci_disable_msi(dev);
 
+       if (dev->msi_enabled) {
+               struct xen_pcibk_dev_data *dev_data;
+
+               pci_disable_msi(dev);
+
+               dev_data = pci_get_drvdata(dev);
+               if (dev_data)
+                       dev_data->ack_intr = 1;
+       }
        op->value = dev->irq ? xen_pirq_from_irq(dev->irq) : 0;
        if (unlikely(verbose_request))
                printk(KERN_DEBUG DRV_NAME ": %s: MSI: %d\n", pci_name(dev),
                        op->value);
-       dev_data = pci_get_drvdata(dev);
-       if (dev_data)
-               dev_data->ack_intr = 1;
        return 0;
 }
 
@@ -197,13 +212,26 @@ int xen_pcibk_enable_msix(struct xen_pcibk_device *pdev,
        struct xen_pcibk_dev_data *dev_data;
        int i, result;
        struct msix_entry *entries;
+       u16 cmd;
 
        if (unlikely(verbose_request))
                printk(KERN_DEBUG DRV_NAME ": %s: enable MSI-X\n",
                       pci_name(dev));
+
        if (op->value > SH_INFO_MAX_VEC)
                return -EINVAL;
 
+       if (dev->msix_enabled)
+               return -EALREADY;
+
+       /*
+        * PCI_COMMAND_MEMORY must be enabled, otherwise we may not be able
+        * to access the BARs where the MSI-X entries reside.
+        */
+       pci_read_config_word(dev, PCI_COMMAND, &cmd);
+       if (dev->msi_enabled || !(cmd & PCI_COMMAND_MEMORY))
+               return -ENXIO;
+
        entries = kmalloc(op->value * sizeof(*entries), GFP_KERNEL);
        if (entries == NULL)
                return -ENOMEM;
@@ -245,23 +273,27 @@ static
 int xen_pcibk_disable_msix(struct xen_pcibk_device *pdev,
                           struct pci_dev *dev, struct xen_pci_op *op)
 {
-       struct xen_pcibk_dev_data *dev_data;
        if (unlikely(verbose_request))
                printk(KERN_DEBUG DRV_NAME ": %s: disable MSI-X\n",
                        pci_name(dev));
-       pci_disable_msix(dev);
 
+       if (dev->msix_enabled) {
+               struct xen_pcibk_dev_data *dev_data;
+
+               pci_disable_msix(dev);
+
+               dev_data = pci_get_drvdata(dev);
+               if (dev_data)
+                       dev_data->ack_intr = 1;
+       }
        /*
         * SR-IOV devices (which don't have any legacy IRQ) have
         * an undefined IRQ value of zero.
         */
        op->value = dev->irq ? xen_pirq_from_irq(dev->irq) : 0;
        if (unlikely(verbose_request))
-               printk(KERN_DEBUG DRV_NAME ": %s: MSI-X: %d\n", pci_name(dev),
-                       op->value);
-       dev_data = pci_get_drvdata(dev);
-       if (dev_data)
-               dev_data->ack_intr = 1;
+               printk(KERN_DEBUG DRV_NAME ": %s: MSI-X: %d\n",
+                      pci_name(dev), op->value);
        return 0;
 }
 #endif
@@ -298,9 +330,11 @@ void xen_pcibk_do_op(struct work_struct *data)
                container_of(data, struct xen_pcibk_device, op_work);
        struct pci_dev *dev;
        struct xen_pcibk_dev_data *dev_data = NULL;
-       struct xen_pci_op *op = &pdev->sh_info->op;
+       struct xen_pci_op *op = &pdev->op;
        int test_intx = 0;
 
+       *op = pdev->sh_info->op;
+       barrier();
        dev = xen_pcibk_get_pci_dev(pdev, op->domain, op->bus, op->devfn);
 
        if (dev == NULL)
@@ -342,6 +376,17 @@ void xen_pcibk_do_op(struct work_struct *data)
                if ((dev_data->enable_intx != test_intx))
                        xen_pcibk_control_isr(dev, 0 /* no reset */);
        }
+       pdev->sh_info->op.err = op->err;
+       pdev->sh_info->op.value = op->value;
+#ifdef CONFIG_PCI_MSI
+       if (op->cmd == XEN_PCI_OP_enable_msix && op->err == 0) {
+               unsigned int i;
+
+               for (i = 0; i < op->value; i++)
+                       pdev->sh_info->op.msix_entries[i].vector =
+                               op->msix_entries[i].vector;
+       }
+#endif
        /* Tell the driver domain that we're done. */
        wmb();
        clear_bit(_XEN_PCIF_active, (unsigned long *)&pdev->sh_info->flags);
index 98bc345f296ef866eaf0e3b1ffffad12ca35fb7e..4843741e703a336da72162af91165392f0560490 100644 (file)
@@ -44,7 +44,6 @@ static struct xen_pcibk_device *alloc_pdev(struct xenbus_device *xdev)
        dev_dbg(&xdev->dev, "allocated pdev @ 0x%p\n", pdev);
 
        pdev->xdev = xdev;
-       dev_set_drvdata(&xdev->dev, pdev);
 
        mutex_init(&pdev->dev_lock);
 
@@ -58,6 +57,9 @@ static struct xen_pcibk_device *alloc_pdev(struct xenbus_device *xdev)
                kfree(pdev);
                pdev = NULL;
        }
+
+       dev_set_drvdata(&xdev->dev, pdev);
+
 out:
        return pdev;
 }
index 43bcae852546ad2e5021b4a1d326dda375ae4023..ad4eb1024d1ffb7663db4e770fdd4c5c2663e821 100644 (file)
@@ -726,7 +726,7 @@ static int scsiback_do_cmd_fn(struct vscsibk_info *info)
                if (!pending_req)
                        return 1;
 
-               ring_req = *RING_GET_REQUEST(ring, rc);
+               RING_COPY_REQUEST(ring, rc, &ring_req);
                ring->req_cons = ++rc;
 
                err = prepare_pending_reqs(info, &ring_req, pending_req);
index 699941e906672b87eb1b5199f7966e29528e0116..511078586fa13543c30ac887dbb4e825888efee0 100644 (file)
@@ -451,9 +451,9 @@ void v9fs_evict_inode(struct inode *inode)
 {
        struct v9fs_inode *v9inode = V9FS_I(inode);
 
-       truncate_inode_pages_final(inode->i_mapping);
+       truncate_inode_pages_final(&inode->i_data);
        clear_inode(inode);
-       filemap_fdatawrite(inode->i_mapping);
+       filemap_fdatawrite(&inode->i_data);
 
        v9fs_cache_inode_put_cookie(inode);
        /* clunk the fid stashed in writeback_fid */
index da3f32f1a4e4bd9f43a6d5a81c192d43612aa8e1..6ce72d8d1ee12473bfcb1e550967be2a0a1c8d27 100644 (file)
@@ -46,6 +46,12 @@ config FS_DAX
          or if unsure, say N.  Saying Y will increase the size of the kernel
          by about 5kB.
 
+config FS_DAX_PMD
+       bool
+       default FS_DAX
+       depends on FS_DAX
+       depends on BROKEN
+
 endif # BLOCK
 
 # Posix ACL utility routines
index bb0dfb1c7af1838029bb6d66625e179c733ddc02..44d4a1e9244e74e923d7b26018d4b420aa2e1323 100644 (file)
@@ -390,9 +390,17 @@ int bdev_read_page(struct block_device *bdev, sector_t sector,
                        struct page *page)
 {
        const struct block_device_operations *ops = bdev->bd_disk->fops;
+       int result = -EOPNOTSUPP;
+
        if (!ops->rw_page || bdev_get_integrity(bdev))
-               return -EOPNOTSUPP;
-       return ops->rw_page(bdev, sector + get_start_sect(bdev), page, READ);
+               return result;
+
+       result = blk_queue_enter(bdev->bd_queue, GFP_KERNEL);
+       if (result)
+               return result;
+       result = ops->rw_page(bdev, sector + get_start_sect(bdev), page, READ);
+       blk_queue_exit(bdev->bd_queue);
+       return result;
 }
 EXPORT_SYMBOL_GPL(bdev_read_page);
 
@@ -421,14 +429,20 @@ int bdev_write_page(struct block_device *bdev, sector_t sector,
        int result;
        int rw = (wbc->sync_mode == WB_SYNC_ALL) ? WRITE_SYNC : WRITE;
        const struct block_device_operations *ops = bdev->bd_disk->fops;
+
        if (!ops->rw_page || bdev_get_integrity(bdev))
                return -EOPNOTSUPP;
+       result = blk_queue_enter(bdev->bd_queue, GFP_KERNEL);
+       if (result)
+               return result;
+
        set_page_writeback(page);
        result = ops->rw_page(bdev, sector + get_start_sect(bdev), page, rw);
        if (result)
                end_page_writeback(page);
        else
                unlock_page(page);
+       blk_queue_exit(bdev->bd_queue);
        return result;
 }
 EXPORT_SYMBOL_GPL(bdev_write_page);
@@ -1509,11 +1523,14 @@ static void __blkdev_put(struct block_device *bdev, fmode_t mode, int for_part)
                WARN_ON_ONCE(bdev->bd_holders);
                sync_blockdev(bdev);
                kill_bdev(bdev);
+
+               bdev_write_inode(bdev);
                /*
-                * ->release can cause the queue to disappear, so flush all
-                * dirty data before.
+                * Detaching bdev inode from its wb in __destroy_inode()
+                * is too late: the queue which embeds its bdi (along with
+                * root wb) can be gone as soon as we put_disk() below.
                 */
-               bdev_write_inode(bdev);
+               inode_detach_wb(bdev->bd_inode);
        }
        if (bdev->bd_contains == bdev) {
                if (disk->fops->release)
index 6dcdb2ec921185ae350aa0f2ff49cd65eaa0d500..d453d62ab0c6e322b3c0df0a05b20daa6751d5ad 100644 (file)
@@ -355,7 +355,7 @@ static int __resolve_indirect_ref(struct btrfs_fs_info *fs_info,
 
        index = srcu_read_lock(&fs_info->subvol_srcu);
 
-       root = btrfs_read_fs_root_no_name(fs_info, &root_key);
+       root = btrfs_get_fs_root(fs_info, &root_key, false);
        if (IS_ERR(root)) {
                srcu_read_unlock(&fs_info->subvol_srcu, index);
                ret = PTR_ERR(root);
index 8c58191249cc14c33c376bb0c8c0a469cb95b894..35489e7129a7e8de9d0232279d41d3bbd19ae1df 100644 (file)
@@ -3416,6 +3416,7 @@ int btrfs_cross_ref_exist(struct btrfs_trans_handle *trans,
 struct btrfs_block_group_cache *btrfs_lookup_block_group(
                                                 struct btrfs_fs_info *info,
                                                 u64 bytenr);
+void btrfs_get_block_group(struct btrfs_block_group_cache *cache);
 void btrfs_put_block_group(struct btrfs_block_group_cache *cache);
 int get_block_group_index(struct btrfs_block_group_cache *cache);
 struct extent_buffer *btrfs_alloc_tree_block(struct btrfs_trans_handle *trans,
@@ -3479,6 +3480,9 @@ int btrfs_make_block_group(struct btrfs_trans_handle *trans,
                           struct btrfs_root *root, u64 bytes_used,
                           u64 type, u64 chunk_objectid, u64 chunk_offset,
                           u64 size);
+struct btrfs_trans_handle *btrfs_start_trans_remove_block_group(
+                               struct btrfs_fs_info *fs_info,
+                               const u64 chunk_offset);
 int btrfs_remove_block_group(struct btrfs_trans_handle *trans,
                             struct btrfs_root *root, u64 group_start,
                             struct extent_map *em);
index acf3ed11cfb60e95b685aeb009e4d72fbdba3c3b..c4661db2b72ae4c412adaaecb7cbc236fbe1e7cf 100644 (file)
@@ -124,7 +124,7 @@ static int block_group_bits(struct btrfs_block_group_cache *cache, u64 bits)
        return (cache->flags & bits) == bits;
 }
 
-static void btrfs_get_block_group(struct btrfs_block_group_cache *cache)
+void btrfs_get_block_group(struct btrfs_block_group_cache *cache)
 {
        atomic_inc(&cache->count);
 }
@@ -5915,19 +5915,6 @@ static int update_block_group(struct btrfs_trans_handle *trans,
                        set_extent_dirty(info->pinned_extents,
                                         bytenr, bytenr + num_bytes - 1,
                                         GFP_NOFS | __GFP_NOFAIL);
-                       /*
-                        * No longer have used bytes in this block group, queue
-                        * it for deletion.
-                        */
-                       if (old_val == 0) {
-                               spin_lock(&info->unused_bgs_lock);
-                               if (list_empty(&cache->bg_list)) {
-                                       btrfs_get_block_group(cache);
-                                       list_add_tail(&cache->bg_list,
-                                                     &info->unused_bgs);
-                               }
-                               spin_unlock(&info->unused_bgs_lock);
-                       }
                }
 
                spin_lock(&trans->transaction->dirty_bgs_lock);
@@ -5939,6 +5926,22 @@ static int update_block_group(struct btrfs_trans_handle *trans,
                }
                spin_unlock(&trans->transaction->dirty_bgs_lock);
 
+               /*
+                * No longer have used bytes in this block group, queue it for
+                * deletion. We do this after adding the block group to the
+                * dirty list to avoid races between cleaner kthread and space
+                * cache writeout.
+                */
+               if (!alloc && old_val == 0) {
+                       spin_lock(&info->unused_bgs_lock);
+                       if (list_empty(&cache->bg_list)) {
+                               btrfs_get_block_group(cache);
+                               list_add_tail(&cache->bg_list,
+                                             &info->unused_bgs);
+                       }
+                       spin_unlock(&info->unused_bgs_lock);
+               }
+
                btrfs_put_block_group(cache);
                total -= num_bytes;
                bytenr += num_bytes;
@@ -8105,21 +8108,47 @@ reada:
 }
 
 /*
- * TODO: Modify related function to add related node/leaf to dirty_extent_root,
- * for later qgroup accounting.
- *
- * Current, this function does nothing.
+ * These may not be seen by the usual inc/dec ref code so we have to
+ * add them here.
  */
+static int record_one_subtree_extent(struct btrfs_trans_handle *trans,
+                                    struct btrfs_root *root, u64 bytenr,
+                                    u64 num_bytes)
+{
+       struct btrfs_qgroup_extent_record *qrecord;
+       struct btrfs_delayed_ref_root *delayed_refs;
+
+       qrecord = kmalloc(sizeof(*qrecord), GFP_NOFS);
+       if (!qrecord)
+               return -ENOMEM;
+
+       qrecord->bytenr = bytenr;
+       qrecord->num_bytes = num_bytes;
+       qrecord->old_roots = NULL;
+
+       delayed_refs = &trans->transaction->delayed_refs;
+       spin_lock(&delayed_refs->lock);
+       if (btrfs_qgroup_insert_dirty_extent(delayed_refs, qrecord))
+               kfree(qrecord);
+       spin_unlock(&delayed_refs->lock);
+
+       return 0;
+}
+
 static int account_leaf_items(struct btrfs_trans_handle *trans,
                              struct btrfs_root *root,
                              struct extent_buffer *eb)
 {
        int nr = btrfs_header_nritems(eb);
-       int i, extent_type;
+       int i, extent_type, ret;
        struct btrfs_key key;
        struct btrfs_file_extent_item *fi;
        u64 bytenr, num_bytes;
 
+       /* We can be called directly from walk_up_proc() */
+       if (!root->fs_info->quota_enabled)
+               return 0;
+
        for (i = 0; i < nr; i++) {
                btrfs_item_key_to_cpu(eb, &key, i);
 
@@ -8138,6 +8167,10 @@ static int account_leaf_items(struct btrfs_trans_handle *trans,
                        continue;
 
                num_bytes = btrfs_file_extent_disk_num_bytes(eb, fi);
+
+               ret = record_one_subtree_extent(trans, root, bytenr, num_bytes);
+               if (ret)
+                       return ret;
        }
        return 0;
 }
@@ -8206,8 +8239,6 @@ static int adjust_slots_upwards(struct btrfs_root *root,
 
 /*
  * root_eb is the subtree root and is locked before this function is called.
- * TODO: Modify this function to mark all (including complete shared node)
- * to dirty_extent_root to allow it get accounted in qgroup.
  */
 static int account_shared_subtree(struct btrfs_trans_handle *trans,
                                  struct btrfs_root *root,
@@ -8285,6 +8316,11 @@ walk_down:
                        btrfs_tree_read_lock(eb);
                        btrfs_set_lock_blocking_rw(eb, BTRFS_READ_LOCK);
                        path->locks[level] = BTRFS_READ_LOCK_BLOCKING;
+
+                       ret = record_one_subtree_extent(trans, root, child_bytenr,
+                                                       root->nodesize);
+                       if (ret)
+                               goto out;
                }
 
                if (level == 0) {
@@ -10256,6 +10292,47 @@ out:
        return ret;
 }
 
+struct btrfs_trans_handle *
+btrfs_start_trans_remove_block_group(struct btrfs_fs_info *fs_info,
+                                    const u64 chunk_offset)
+{
+       struct extent_map_tree *em_tree = &fs_info->mapping_tree.map_tree;
+       struct extent_map *em;
+       struct map_lookup *map;
+       unsigned int num_items;
+
+       read_lock(&em_tree->lock);
+       em = lookup_extent_mapping(em_tree, chunk_offset, 1);
+       read_unlock(&em_tree->lock);
+       ASSERT(em && em->start == chunk_offset);
+
+       /*
+        * We need to reserve 3 + N units from the metadata space info in order
+        * to remove a block group (done at btrfs_remove_chunk() and at
+        * btrfs_remove_block_group()), which are used for:
+        *
+        * 1 unit for adding the free space inode's orphan (located in the tree
+        * of tree roots).
+        * 1 unit for deleting the block group item (located in the extent
+        * tree).
+        * 1 unit for deleting the free space item (located in tree of tree
+        * roots).
+        * N units for deleting N device extent items corresponding to each
+        * stripe (located in the device tree).
+        *
+        * In order to remove a block group we also need to reserve units in the
+        * system space info in order to update the chunk tree (update one or
+        * more device items and remove one chunk item), but this is done at
+        * btrfs_remove_chunk() through a call to check_system_chunk().
+        */
+       map = (struct map_lookup *)em->bdev;
+       num_items = 3 + map->num_stripes;
+       free_extent_map(em);
+
+       return btrfs_start_transaction_fallback_global_rsv(fs_info->extent_root,
+                                                          num_items, 1);
+}
+
 /*
  * Process the unused_bgs list and remove any that don't have any allocated
  * space inside of them.
@@ -10322,8 +10399,8 @@ void btrfs_delete_unused_bgs(struct btrfs_fs_info *fs_info)
                 * Want to do this before we do anything else so we can recover
                 * properly if we fail to join the transaction.
                 */
-               /* 1 for btrfs_orphan_reserve_metadata() */
-               trans = btrfs_start_transaction(root, 1);
+               trans = btrfs_start_trans_remove_block_group(fs_info,
+                                                    block_group->key.objectid);
                if (IS_ERR(trans)) {
                        btrfs_dec_block_group_ro(root, block_group);
                        ret = PTR_ERR(trans);
@@ -10403,11 +10480,15 @@ void btrfs_delete_unused_bgs(struct btrfs_fs_info *fs_info)
                 * until transaction commit to do the actual discard.
                 */
                if (trimming) {
-                       WARN_ON(!list_empty(&block_group->bg_list));
-                       spin_lock(&trans->transaction->deleted_bgs_lock);
+                       spin_lock(&fs_info->unused_bgs_lock);
+                       /*
+                        * A concurrent scrub might have added us to the list
+                        * fs_info->unused_bgs, so use a list_move operation
+                        * to add the block group to the deleted_bgs list.
+                        */
                        list_move(&block_group->bg_list,
                                  &trans->transaction->deleted_bgs);
-                       spin_unlock(&trans->transaction->deleted_bgs_lock);
+                       spin_unlock(&fs_info->unused_bgs_lock);
                        btrfs_get_block_group(block_group);
                }
 end_trans:
index 977e715f0bf21a4ea8908700cfe4207dee1fe95d..0f09526aa7d9d2017bb229eb4310f777c4b3b578 100644 (file)
@@ -1291,7 +1291,8 @@ out:
  * on error we return an unlocked page and the error value
  * on success we return a locked page and 0
  */
-static int prepare_uptodate_page(struct page *page, u64 pos,
+static int prepare_uptodate_page(struct inode *inode,
+                                struct page *page, u64 pos,
                                 bool force_uptodate)
 {
        int ret = 0;
@@ -1306,6 +1307,10 @@ static int prepare_uptodate_page(struct page *page, u64 pos,
                        unlock_page(page);
                        return -EIO;
                }
+               if (page->mapping != inode->i_mapping) {
+                       unlock_page(page);
+                       return -EAGAIN;
+               }
        }
        return 0;
 }
@@ -1324,6 +1329,7 @@ static noinline int prepare_pages(struct inode *inode, struct page **pages,
        int faili;
 
        for (i = 0; i < num_pages; i++) {
+again:
                pages[i] = find_or_create_page(inode->i_mapping, index + i,
                                               mask | __GFP_WRITE);
                if (!pages[i]) {
@@ -1333,13 +1339,17 @@ static noinline int prepare_pages(struct inode *inode, struct page **pages,
                }
 
                if (i == 0)
-                       err = prepare_uptodate_page(pages[i], pos,
+                       err = prepare_uptodate_page(inode, pages[i], pos,
                                                    force_uptodate);
-               if (i == num_pages - 1)
-                       err = prepare_uptodate_page(pages[i],
+               if (!err && i == num_pages - 1)
+                       err = prepare_uptodate_page(inode, pages[i],
                                                    pos + write_bytes, false);
                if (err) {
                        page_cache_release(pages[i]);
+                       if (err == -EAGAIN) {
+                               err = 0;
+                               goto again;
+                       }
                        faili = i - 1;
                        goto fail;
                }
@@ -1882,8 +1892,13 @@ int btrfs_sync_file(struct file *file, loff_t start, loff_t end, int datasync)
        struct btrfs_log_ctx ctx;
        int ret = 0;
        bool full_sync = 0;
-       const u64 len = end - start + 1;
+       u64 len;
 
+       /*
+        * The range length can be represented by u64, we have to do the typecasts
+        * to avoid signed overflow if it's [0, LLONG_MAX] eg. from fsync()
+        */
+       len = (u64)end - (u64)start + 1;
        trace_btrfs_sync_file(file, datasync);
 
        /*
@@ -2071,8 +2086,7 @@ int btrfs_sync_file(struct file *file, loff_t start, loff_t end, int datasync)
                        }
                }
                if (!full_sync) {
-                       ret = btrfs_wait_ordered_range(inode, start,
-                                                      end - start + 1);
+                       ret = btrfs_wait_ordered_range(inode, start, len);
                        if (ret) {
                                btrfs_end_transaction(trans, root);
                                goto out;
index 85a1f8621b51f09f0893abae9ffab90382efdcfc..cfe99bec49dedd723e2a7fff04ace299be37ef87 100644 (file)
@@ -891,7 +891,7 @@ out:
                spin_unlock(&block_group->lock);
                ret = 0;
 
-               btrfs_warn(fs_info, "failed to load free space cache for block group %llu, rebuild it now",
+               btrfs_warn(fs_info, "failed to load free space cache for block group %llu, rebuilding it now",
                        block_group->key.objectid);
        }
 
@@ -2972,7 +2972,7 @@ setup_cluster_bitmap(struct btrfs_block_group_cache *block_group,
                     u64 cont1_bytes, u64 min_bytes)
 {
        struct btrfs_free_space_ctl *ctl = block_group->free_space_ctl;
-       struct btrfs_free_space *entry;
+       struct btrfs_free_space *entry = NULL;
        int ret = -ENOSPC;
        u64 bitmap_offset = offset_to_bitmap(ctl, offset);
 
@@ -2983,8 +2983,10 @@ setup_cluster_bitmap(struct btrfs_block_group_cache *block_group,
         * The bitmap that covers offset won't be in the list unless offset
         * is just its start offset.
         */
-       entry = list_first_entry(bitmaps, struct btrfs_free_space, list);
-       if (entry->offset != bitmap_offset) {
+       if (!list_empty(bitmaps))
+               entry = list_first_entry(bitmaps, struct btrfs_free_space, list);
+
+       if (!entry || entry->offset != bitmap_offset) {
                entry = tree_search_offset(ctl, bitmap_offset, 1, 0);
                if (entry && list_empty(&entry->list))
                        list_add(&entry->list, bitmaps);
index 994490d5fa6423dee4971e0ff013777d853fe6a6..a70c5790f8f5908f08f606d097fe33e6966af36b 100644 (file)
@@ -4046,9 +4046,7 @@ int btrfs_unlink_inode(struct btrfs_trans_handle *trans,
  */
 static struct btrfs_trans_handle *__unlink_start_trans(struct inode *dir)
 {
-       struct btrfs_trans_handle *trans;
        struct btrfs_root *root = BTRFS_I(dir)->root;
-       int ret;
 
        /*
         * 1 for the possible orphan item
@@ -4057,27 +4055,7 @@ static struct btrfs_trans_handle *__unlink_start_trans(struct inode *dir)
         * 1 for the inode ref
         * 1 for the inode
         */
-       trans = btrfs_start_transaction(root, 5);
-       if (!IS_ERR(trans) || PTR_ERR(trans) != -ENOSPC)
-               return trans;
-
-       if (PTR_ERR(trans) == -ENOSPC) {
-               u64 num_bytes = btrfs_calc_trans_metadata_size(root, 5);
-
-               trans = btrfs_start_transaction(root, 0);
-               if (IS_ERR(trans))
-                       return trans;
-               ret = btrfs_cond_migrate_bytes(root->fs_info,
-                                              &root->fs_info->trans_block_rsv,
-                                              num_bytes, 5);
-               if (ret) {
-                       btrfs_end_transaction(trans, root);
-                       return ERR_PTR(ret);
-               }
-               trans->block_rsv = &root->fs_info->trans_block_rsv;
-               trans->bytes_reserved = num_bytes;
-       }
-       return trans;
+       return btrfs_start_transaction_fallback_global_rsv(root, 5, 5);
 }
 
 static int btrfs_unlink(struct inode *dir, struct dentry *dentry)
index 93e12c18ffd736ec77351ecb0443bbfec606a938..5279fdae7142fbe3177a556a020ed1af3a7aa8f1 100644 (file)
@@ -993,9 +993,10 @@ int btrfs_quota_disable(struct btrfs_trans_handle *trans,
        mutex_lock(&fs_info->qgroup_ioctl_lock);
        if (!fs_info->quota_root)
                goto out;
-       spin_lock(&fs_info->qgroup_lock);
        fs_info->quota_enabled = 0;
        fs_info->pending_quota_state = 0;
+       btrfs_qgroup_wait_for_completion(fs_info);
+       spin_lock(&fs_info->qgroup_lock);
        quota_root = fs_info->quota_root;
        fs_info->quota_root = NULL;
        fs_info->qgroup_flags &= ~BTRFS_QGROUP_STATUS_FLAG_ON;
@@ -1461,6 +1462,8 @@ struct btrfs_qgroup_extent_record
        struct btrfs_qgroup_extent_record *entry;
        u64 bytenr = record->bytenr;
 
+       assert_spin_locked(&delayed_refs->lock);
+
        while (*p) {
                parent_node = *p;
                entry = rb_entry(parent_node, struct btrfs_qgroup_extent_record,
index 2907a77fb1f6f4670885a7985ab40ed3e79c4925..b091d94ceef68013e992161b0aaf31b47cc645dc 100644 (file)
@@ -3432,7 +3432,9 @@ out:
 static noinline_for_stack int scrub_chunk(struct scrub_ctx *sctx,
                                          struct btrfs_device *scrub_dev,
                                          u64 chunk_offset, u64 length,
-                                         u64 dev_offset, int is_dev_replace)
+                                         u64 dev_offset,
+                                         struct btrfs_block_group_cache *cache,
+                                         int is_dev_replace)
 {
        struct btrfs_mapping_tree *map_tree =
                &sctx->dev_root->fs_info->mapping_tree;
@@ -3445,8 +3447,18 @@ static noinline_for_stack int scrub_chunk(struct scrub_ctx *sctx,
        em = lookup_extent_mapping(&map_tree->map_tree, chunk_offset, 1);
        read_unlock(&map_tree->map_tree.lock);
 
-       if (!em)
-               return -EINVAL;
+       if (!em) {
+               /*
+                * Might have been an unused block group deleted by the cleaner
+                * kthread or relocation.
+                */
+               spin_lock(&cache->lock);
+               if (!cache->removed)
+                       ret = -EINVAL;
+               spin_unlock(&cache->lock);
+
+               return ret;
+       }
 
        map = (struct map_lookup *)em->bdev;
        if (em->start != chunk_offset)
@@ -3483,6 +3495,7 @@ int scrub_enumerate_chunks(struct scrub_ctx *sctx,
        u64 length;
        u64 chunk_offset;
        int ret = 0;
+       int ro_set;
        int slot;
        struct extent_buffer *l;
        struct btrfs_key key;
@@ -3568,7 +3581,21 @@ int scrub_enumerate_chunks(struct scrub_ctx *sctx,
                scrub_pause_on(fs_info);
                ret = btrfs_inc_block_group_ro(root, cache);
                scrub_pause_off(fs_info);
-               if (ret) {
+
+               if (ret == 0) {
+                       ro_set = 1;
+               } else if (ret == -ENOSPC) {
+                       /*
+                        * btrfs_inc_block_group_ro return -ENOSPC when it
+                        * failed in creating new chunk for metadata.
+                        * It is not a problem for scrub/replace, because
+                        * metadata are always cowed, and our scrub paused
+                        * commit_transactions.
+                        */
+                       ro_set = 0;
+               } else {
+                       btrfs_warn(fs_info, "failed setting block group ro, ret=%d\n",
+                                  ret);
                        btrfs_put_block_group(cache);
                        break;
                }
@@ -3577,7 +3604,7 @@ int scrub_enumerate_chunks(struct scrub_ctx *sctx,
                dev_replace->cursor_left = found_key.offset;
                dev_replace->item_needs_writeback = 1;
                ret = scrub_chunk(sctx, scrub_dev, chunk_offset, length,
-                                 found_key.offset, is_dev_replace);
+                                 found_key.offset, cache, is_dev_replace);
 
                /*
                 * flush, submit all pending read and write bios, afterwards
@@ -3611,7 +3638,30 @@ int scrub_enumerate_chunks(struct scrub_ctx *sctx,
 
                scrub_pause_off(fs_info);
 
-               btrfs_dec_block_group_ro(root, cache);
+               if (ro_set)
+                       btrfs_dec_block_group_ro(root, cache);
+
+               /*
+                * We might have prevented the cleaner kthread from deleting
+                * this block group if it was already unused because we raced
+                * and set it to RO mode first. So add it back to the unused
+                * list, otherwise it might not ever be deleted unless a manual
+                * balance is triggered or it becomes used and unused again.
+                */
+               spin_lock(&cache->lock);
+               if (!cache->removed && !cache->ro && cache->reserved == 0 &&
+                   btrfs_block_group_used(&cache->item) == 0) {
+                       spin_unlock(&cache->lock);
+                       spin_lock(&fs_info->unused_bgs_lock);
+                       if (list_empty(&cache->bg_list)) {
+                               btrfs_get_block_group(cache);
+                               list_add_tail(&cache->bg_list,
+                                             &fs_info->unused_bgs);
+                       }
+                       spin_unlock(&fs_info->unused_bgs_lock);
+               } else {
+                       spin_unlock(&cache->lock);
+               }
 
                btrfs_put_block_group(cache);
                if (ret)
index c8c3d70c31ffad4e02acd04e0f7dcaa54ad0fe2b..8b72b005bfb9a212518a711a2e476c2d70b47b24 100644 (file)
@@ -898,8 +898,10 @@ int btrfs_test_free_space_cache(void)
        }
 
        root = btrfs_alloc_dummy_root();
-       if (!root)
+       if (IS_ERR(root)) {
+               ret = PTR_ERR(root);
                goto out;
+       }
 
        root->fs_info = btrfs_alloc_dummy_fs_info();
        if (!root->fs_info)
index 418c6a2ad7d88658f8624d99a1ba0e9e84c13d45..be8eae80ff6572608a478610f9c2b16f3bcb1871 100644 (file)
@@ -274,7 +274,6 @@ loop:
        cur_trans->num_dirty_bgs = 0;
        spin_lock_init(&cur_trans->dirty_bgs_lock);
        INIT_LIST_HEAD(&cur_trans->deleted_bgs);
-       spin_lock_init(&cur_trans->deleted_bgs_lock);
        spin_lock_init(&cur_trans->dropped_roots_lock);
        list_add_tail(&cur_trans->list, &fs_info->trans_list);
        extent_io_tree_init(&cur_trans->dirty_pages,
@@ -592,6 +591,38 @@ struct btrfs_trans_handle *btrfs_start_transaction(struct btrfs_root *root,
        return start_transaction(root, num_items, TRANS_START,
                                 BTRFS_RESERVE_FLUSH_ALL);
 }
+struct btrfs_trans_handle *btrfs_start_transaction_fallback_global_rsv(
+                                       struct btrfs_root *root,
+                                       unsigned int num_items,
+                                       int min_factor)
+{
+       struct btrfs_trans_handle *trans;
+       u64 num_bytes;
+       int ret;
+
+       trans = btrfs_start_transaction(root, num_items);
+       if (!IS_ERR(trans) || PTR_ERR(trans) != -ENOSPC)
+               return trans;
+
+       trans = btrfs_start_transaction(root, 0);
+       if (IS_ERR(trans))
+               return trans;
+
+       num_bytes = btrfs_calc_trans_metadata_size(root, num_items);
+       ret = btrfs_cond_migrate_bytes(root->fs_info,
+                                      &root->fs_info->trans_block_rsv,
+                                      num_bytes,
+                                      min_factor);
+       if (ret) {
+               btrfs_end_transaction(trans, root);
+               return ERR_PTR(ret);
+       }
+
+       trans->block_rsv = &root->fs_info->trans_block_rsv;
+       trans->bytes_reserved = num_bytes;
+
+       return trans;
+}
 
 struct btrfs_trans_handle *btrfs_start_transaction_lflush(
                                        struct btrfs_root *root,
index b05b2f64d9133313f1af231c4a4254ff16972f00..64c8221b6165bb7a6b786ac74e1833f2b93a197b 100644 (file)
@@ -77,8 +77,8 @@ struct btrfs_transaction {
         */
        struct mutex cache_write_mutex;
        spinlock_t dirty_bgs_lock;
+       /* Protected by spin lock fs_info->unused_bgs_lock. */
        struct list_head deleted_bgs;
-       spinlock_t deleted_bgs_lock;
        spinlock_t dropped_roots_lock;
        struct btrfs_delayed_ref_root delayed_refs;
        int aborted;
@@ -185,6 +185,10 @@ int btrfs_end_transaction(struct btrfs_trans_handle *trans,
                          struct btrfs_root *root);
 struct btrfs_trans_handle *btrfs_start_transaction(struct btrfs_root *root,
                                                   unsigned int num_items);
+struct btrfs_trans_handle *btrfs_start_transaction_fallback_global_rsv(
+                                       struct btrfs_root *root,
+                                       unsigned int num_items,
+                                       int min_factor);
 struct btrfs_trans_handle *btrfs_start_transaction_lflush(
                                        struct btrfs_root *root,
                                        unsigned int num_items);
index a6df8fdc1312ce78e97f9f90037ff5b236a58a92..a23399e8e3aba2f63d4c0cee90932d073d3bd113 100644 (file)
@@ -1973,8 +1973,7 @@ void btrfs_rm_dev_replace_remove_srcdev(struct btrfs_fs_info *fs_info,
        if (srcdev->writeable) {
                fs_devices->rw_devices--;
                /* zero out the old super if it is writable */
-               btrfs_scratch_superblocks(srcdev->bdev,
-                                       rcu_str_deref(srcdev->name));
+               btrfs_scratch_superblocks(srcdev->bdev, srcdev->name->str);
        }
 
        if (srcdev->bdev)
@@ -2024,8 +2023,7 @@ void btrfs_destroy_dev_replace_tgtdev(struct btrfs_fs_info *fs_info,
        btrfs_sysfs_rm_device_link(fs_info->fs_devices, tgtdev);
 
        if (tgtdev->bdev) {
-               btrfs_scratch_superblocks(tgtdev->bdev,
-                                       rcu_str_deref(tgtdev->name));
+               btrfs_scratch_superblocks(tgtdev->bdev, tgtdev->name->str);
                fs_info->fs_devices->open_devices--;
        }
        fs_info->fs_devices->num_devices--;
@@ -2853,7 +2851,8 @@ static int btrfs_relocate_chunk(struct btrfs_root *root, u64 chunk_offset)
        if (ret)
                return ret;
 
-       trans = btrfs_start_transaction(root, 0);
+       trans = btrfs_start_trans_remove_block_group(root->fs_info,
+                                                    chunk_offset);
        if (IS_ERR(trans)) {
                ret = PTR_ERR(trans);
                btrfs_std_error(root->fs_info, ret, NULL);
@@ -3123,7 +3122,7 @@ static int chunk_profiles_filter(u64 chunk_type,
        return 1;
 }
 
-static int chunk_usage_filter(struct btrfs_fs_info *fs_info, u64 chunk_offset,
+static int chunk_usage_range_filter(struct btrfs_fs_info *fs_info, u64 chunk_offset,
                              struct btrfs_balance_args *bargs)
 {
        struct btrfs_block_group_cache *cache;
@@ -3156,7 +3155,7 @@ static int chunk_usage_filter(struct btrfs_fs_info *fs_info, u64 chunk_offset,
        return ret;
 }
 
-static int chunk_usage_range_filter(struct btrfs_fs_info *fs_info,
+static int chunk_usage_filter(struct btrfs_fs_info *fs_info,
                u64 chunk_offset, struct btrfs_balance_args *bargs)
 {
        struct btrfs_block_group_cache *cache;
@@ -3549,12 +3548,11 @@ again:
 
                        ret = btrfs_force_chunk_alloc(trans, chunk_root,
                                                      BTRFS_BLOCK_GROUP_DATA);
+                       btrfs_end_transaction(trans, chunk_root);
                        if (ret < 0) {
                                mutex_unlock(&fs_info->delete_unused_bgs_mutex);
                                goto error;
                        }
-
-                       btrfs_end_transaction(trans, chunk_root);
                        chunk_reserved = 1;
                }
 
index ec571237273208fcb87f7be1c473b0c6a1392b50..d5c84f6b13538a338d90560b6520be4fe56c3125 100644 (file)
@@ -382,7 +382,7 @@ struct map_lookup {
 #define BTRFS_BALANCE_ARGS_LIMIT       (1ULL << 5)
 #define BTRFS_BALANCE_ARGS_LIMIT_RANGE (1ULL << 6)
 #define BTRFS_BALANCE_ARGS_STRIPES_RANGE (1ULL << 7)
-#define BTRFS_BALANCE_ARGS_USAGE_RANGE (1ULL << 8)
+#define BTRFS_BALANCE_ARGS_USAGE_RANGE (1ULL << 10)
 
 #define BTRFS_BALANCE_ARGS_MASK                        \
        (BTRFS_BALANCE_ARGS_PROFILES |          \
index 7a6b02f727874352d80a9fd34fa0355dda8a5cb1..c0f3da3926a0c6d4b8cf95e2c24a2a1ebd9d6655 100644 (file)
@@ -879,7 +879,7 @@ int cachefiles_write_page(struct fscache_storage *op, struct page *page)
        loff_t pos, eof;
        size_t len;
        void *data;
-       int ret;
+       int ret = -ENOBUFS;
 
        ASSERT(op != NULL);
        ASSERT(page != NULL);
index 6b66dd5d15408676ab6510f7ce415164fe5c0571..a329f5ba35aad8649ce3f644b9b11913c57cc5f8 100644 (file)
@@ -1831,11 +1831,11 @@ cifs_invalidate_mapping(struct inode *inode)
  * @word: long word containing the bit lock
  */
 static int
-cifs_wait_bit_killable(struct wait_bit_key *key)
+cifs_wait_bit_killable(struct wait_bit_key *key, int mode)
 {
-       if (fatal_signal_pending(current))
-               return -ERESTARTSYS;
        freezable_schedule_unsafe();
+       if (signal_pending_state(mode, current))
+               return -ERESTARTSYS;
        return 0;
 }
 
index c81ce7f200a6d9944b4670de2729f909048e773c..a7a1b218f308af56ac3094fa5f2ddb6b2749dd4a 100644 (file)
@@ -1636,6 +1636,116 @@ const struct file_operations configfs_dir_operations = {
        .iterate        = configfs_readdir,
 };
 
+/**
+ * configfs_register_group - creates a parent-child relation between two groups
+ * @parent_group:      parent group
+ * @group:             child group
+ *
+ * link groups, creates dentry for the child and attaches it to the
+ * parent dentry.
+ *
+ * Return: 0 on success, negative errno code on error
+ */
+int configfs_register_group(struct config_group *parent_group,
+                           struct config_group *group)
+{
+       struct configfs_subsystem *subsys = parent_group->cg_subsys;
+       struct dentry *parent;
+       int ret;
+
+       mutex_lock(&subsys->su_mutex);
+       link_group(parent_group, group);
+       mutex_unlock(&subsys->su_mutex);
+
+       parent = parent_group->cg_item.ci_dentry;
+
+       mutex_lock_nested(&d_inode(parent)->i_mutex, I_MUTEX_PARENT);
+       ret = create_default_group(parent_group, group);
+       if (!ret) {
+               spin_lock(&configfs_dirent_lock);
+               configfs_dir_set_ready(group->cg_item.ci_dentry->d_fsdata);
+               spin_unlock(&configfs_dirent_lock);
+       }
+       mutex_unlock(&d_inode(parent)->i_mutex);
+       return ret;
+}
+EXPORT_SYMBOL(configfs_register_group);
+
+/**
+ * configfs_unregister_group() - unregisters a child group from its parent
+ * @group: parent group to be unregistered
+ *
+ * Undoes configfs_register_group()
+ */
+void configfs_unregister_group(struct config_group *group)
+{
+       struct configfs_subsystem *subsys = group->cg_subsys;
+       struct dentry *dentry = group->cg_item.ci_dentry;
+       struct dentry *parent = group->cg_item.ci_parent->ci_dentry;
+
+       mutex_lock_nested(&d_inode(parent)->i_mutex, I_MUTEX_PARENT);
+       spin_lock(&configfs_dirent_lock);
+       configfs_detach_prep(dentry, NULL);
+       spin_unlock(&configfs_dirent_lock);
+
+       configfs_detach_group(&group->cg_item);
+       d_inode(dentry)->i_flags |= S_DEAD;
+       dont_mount(dentry);
+       d_delete(dentry);
+       mutex_unlock(&d_inode(parent)->i_mutex);
+
+       dput(dentry);
+
+       mutex_lock(&subsys->su_mutex);
+       unlink_group(group);
+       mutex_unlock(&subsys->su_mutex);
+}
+EXPORT_SYMBOL(configfs_unregister_group);
+
+/**
+ * configfs_register_default_group() - allocates and registers a child group
+ * @parent_group:      parent group
+ * @name:              child group name
+ * @item_type:         child item type description
+ *
+ * boilerplate to allocate and register a child group with its parent. We need
+ * kzalloc'ed memory because child's default_group is initially empty.
+ *
+ * Return: allocated config group or ERR_PTR() on error
+ */
+struct config_group *
+configfs_register_default_group(struct config_group *parent_group,
+                               const char *name,
+                               struct config_item_type *item_type)
+{
+       int ret;
+       struct config_group *group;
+
+       group = kzalloc(sizeof(*group), GFP_KERNEL);
+       if (!group)
+               return ERR_PTR(-ENOMEM);
+       config_group_init_type_name(group, name, item_type);
+
+       ret = configfs_register_group(parent_group, group);
+       if (ret) {
+               kfree(group);
+               return ERR_PTR(ret);
+       }
+       return group;
+}
+EXPORT_SYMBOL(configfs_register_default_group);
+
+/**
+ * configfs_unregister_default_group() - unregisters and frees a child group
+ * @group:     the group to act on
+ */
+void configfs_unregister_default_group(struct config_group *group)
+{
+       configfs_unregister_group(group);
+       kfree(group);
+}
+EXPORT_SYMBOL(configfs_unregister_default_group);
+
 int configfs_register_subsystem(struct configfs_subsystem *subsys)
 {
        int err;
index d1e5cb7311a1de295ecd4348360a9a9947e71142..43671b68220ed968386f5c1ad9067f236fbab67e 100644 (file)
--- a/fs/dax.c
+++ b/fs/dax.c
@@ -541,6 +541,10 @@ int __dax_pmd_fault(struct vm_area_struct *vma, unsigned long address,
        unsigned long pfn;
        int result = 0;
 
+       /* dax pmd mappings are broken wrt gup and fork */
+       if (!IS_ENABLED(CONFIG_FS_DAX_PMD))
+               return VM_FAULT_FALLBACK;
+
        /* Fall back to PTEs if we're going to COW */
        if (write && !(vma->vm_flags & VM_SHARED))
                return VM_FAULT_FALLBACK;
index cb5337d8c273a5dd58e97d9be587fb56d643e52a..602e8441bc0fb6b094ec96dfb3273ff73b8b1506 100644 (file)
@@ -1169,6 +1169,16 @@ do_blockdev_direct_IO(struct kiocb *iocb, struct inode *inode,
                }
        }
 
+       /* Once we sampled i_size check for reads beyond EOF */
+       dio->i_size = i_size_read(inode);
+       if (iov_iter_rw(iter) == READ && offset >= dio->i_size) {
+               if (dio->flags & DIO_LOCKING)
+                       mutex_unlock(&inode->i_mutex);
+               kmem_cache_free(dio_cache, dio);
+               retval = 0;
+               goto out;
+       }
+
        /*
         * For file extending writes updating i_size before data writeouts
         * complete can expose uninitialized blocks in dumb filesystems.
@@ -1222,7 +1232,6 @@ do_blockdev_direct_IO(struct kiocb *iocb, struct inode *inode,
        sdio.next_block_for_io = -1;
 
        dio->iocb = iocb;
-       dio->i_size = i_size_read(inode);
 
        spin_lock_init(&dio->bio_lock);
        dio->refcount = 1;
index 87e9d796cf7dd9ae2e4e0f221867dc69e8ea28df..3a37bd3f9637811c3b86e5c05be5aa47f32819c3 100644 (file)
@@ -421,7 +421,7 @@ static void lowcomms_write_space(struct sock *sk)
 
        if (test_and_clear_bit(CF_APP_LIMITED, &con->flags)) {
                con->sock->sk->sk_write_pending--;
-               clear_bit(SOCK_ASYNC_NOSPACE, &con->sock->flags);
+               clear_bit(SOCKWQ_ASYNC_NOSPACE, &con->sock->flags);
        }
 
        if (!test_and_set_bit(CF_WRITE_PENDING, &con->flags))
@@ -1448,7 +1448,7 @@ static void send_to_sock(struct connection *con)
                                              msg_flags);
                        if (ret == -EAGAIN || ret == 0) {
                                if (ret == -EAGAIN &&
-                                   test_bit(SOCK_ASYNC_NOSPACE, &con->sock->flags) &&
+                                   test_bit(SOCKWQ_ASYNC_NOSPACE, &con->sock->flags) &&
                                    !test_and_set_bit(CF_APP_LIMITED, &con->flags)) {
                                        /* Notify TCP that we're limited by the
                                         * application window size.
index 73c64daa0f5517b4ff8271bd17e25740bb83d506..60f03b78914e3012e50c90a9e9069aff615467be 100644 (file)
@@ -592,10 +592,7 @@ static struct page *__r4w_get_page(void *priv, u64 offset, bool *uptodate)
                        }
                        unlock_page(page);
                }
-               if (PageDirty(page) || PageWriteback(page))
-                       *uptodate = true;
-               else
-                       *uptodate = PageUptodate(page);
+               *uptodate = PageUptodate(page);
                EXOFS_DBGMSG2("index=0x%lx uptodate=%d\n", index, *uptodate);
                return page;
        } else {
index 3a71cea684208f16beb587f61989bfffb0a0d006..748d35afc90266123407d61d7aed944f2e9ad9ca 100644 (file)
@@ -569,6 +569,8 @@ static int parse_options(char *options, struct super_block *sb)
                        /* Fall through */
                case Opt_dax:
 #ifdef CONFIG_FS_DAX
+                       ext2_msg(sb, KERN_WARNING,
+               "DAX enabled. Warning: EXPERIMENTAL, use at your own risk");
                        set_opt(sbi->s_mount_opt, DAX);
 #else
                        ext2_msg(sb, KERN_INFO, "dax option not supported");
index af06830bfc00c743369737551e7bceea3b61eede..1a0835073663ff3f1dad1f376328de5e2b1332ce 100644 (file)
@@ -389,7 +389,7 @@ int ext4_encrypted_zeroout(struct inode *inode, struct ext4_extent *ex)
        struct ext4_crypto_ctx  *ctx;
        struct page             *ciphertext_page = NULL;
        struct bio              *bio;
-       ext4_lblk_t             lblk = ex->ee_block;
+       ext4_lblk_t             lblk = le32_to_cpu(ex->ee_block);
        ext4_fsblk_t            pblk = ext4_ext_pblock(ex);
        unsigned int            len = ext4_ext_get_actual_len(ex);
        int                     ret, err = 0;
index 750063f7a50c6cc2b9808318538762be67ce098d..cc7ca4e87144a540332213ce03b63e80e601f40e 100644 (file)
@@ -26,6 +26,7 @@
 #include <linux/seqlock.h>
 #include <linux/mutex.h>
 #include <linux/timer.h>
+#include <linux/version.h>
 #include <linux/wait.h>
 #include <linux/blockgroup_lock.h>
 #include <linux/percpu_counter.h>
@@ -727,19 +728,55 @@ struct move_extent {
        <= (EXT4_GOOD_OLD_INODE_SIZE +                  \
            (einode)->i_extra_isize))                   \
 
+/*
+ * We use an encoding that preserves the times for extra epoch "00":
+ *
+ * extra  msb of                         adjust for signed
+ * epoch  32-bit                         32-bit tv_sec to
+ * bits   time    decoded 64-bit tv_sec  64-bit tv_sec      valid time range
+ * 0 0    1    -0x80000000..-0x00000001  0x000000000 1901-12-13..1969-12-31
+ * 0 0    0    0x000000000..0x07fffffff  0x000000000 1970-01-01..2038-01-19
+ * 0 1    1    0x080000000..0x0ffffffff  0x100000000 2038-01-19..2106-02-07
+ * 0 1    0    0x100000000..0x17fffffff  0x100000000 2106-02-07..2174-02-25
+ * 1 0    1    0x180000000..0x1ffffffff  0x200000000 2174-02-25..2242-03-16
+ * 1 0    0    0x200000000..0x27fffffff  0x200000000 2242-03-16..2310-04-04
+ * 1 1    1    0x280000000..0x2ffffffff  0x300000000 2310-04-04..2378-04-22
+ * 1 1    0    0x300000000..0x37fffffff  0x300000000 2378-04-22..2446-05-10
+ *
+ * Note that previous versions of the kernel on 64-bit systems would
+ * incorrectly use extra epoch bits 1,1 for dates between 1901 and
+ * 1970.  e2fsck will correct this, assuming that it is run on the
+ * affected filesystem before 2242.
+ */
+
 static inline __le32 ext4_encode_extra_time(struct timespec *time)
 {
-       return cpu_to_le32((sizeof(time->tv_sec) > 4 ?
-                          (time->tv_sec >> 32) & EXT4_EPOCH_MASK : 0) |
-                          ((time->tv_nsec << EXT4_EPOCH_BITS) & EXT4_NSEC_MASK));
+       u32 extra = sizeof(time->tv_sec) > 4 ?
+               ((time->tv_sec - (s32)time->tv_sec) >> 32) & EXT4_EPOCH_MASK : 0;
+       return cpu_to_le32(extra | (time->tv_nsec << EXT4_EPOCH_BITS));
 }
 
 static inline void ext4_decode_extra_time(struct timespec *time, __le32 extra)
 {
-       if (sizeof(time->tv_sec) > 4)
-              time->tv_sec |= (__u64)(le32_to_cpu(extra) & EXT4_EPOCH_MASK)
-                              << 32;
-       time->tv_nsec = (le32_to_cpu(extra) & EXT4_NSEC_MASK) >> EXT4_EPOCH_BITS;
+       if (unlikely(sizeof(time->tv_sec) > 4 &&
+                       (extra & cpu_to_le32(EXT4_EPOCH_MASK)))) {
+#if LINUX_VERSION_CODE < KERNEL_VERSION(4,20,0)
+               /* Handle legacy encoding of pre-1970 dates with epoch
+                * bits 1,1.  We assume that by kernel version 4.20,
+                * everyone will have run fsck over the affected
+                * filesystems to correct the problem.  (This
+                * backwards compatibility may be removed before this
+                * time, at the discretion of the ext4 developers.)
+                */
+               u64 extra_bits = le32_to_cpu(extra) & EXT4_EPOCH_MASK;
+               if (extra_bits == 3 && ((time->tv_sec) & 0x80000000) != 0)
+                       extra_bits = 0;
+               time->tv_sec += extra_bits << 32;
+#else
+               time->tv_sec += (u64)(le32_to_cpu(extra) & EXT4_EPOCH_MASK) << 32;
+#endif
+       }
+       time->tv_nsec = (le32_to_cpu(extra) & EXT4_NSEC_MASK) >> EXT4_EPOCH_BITS;
 }
 
 #define EXT4_INODE_SET_XTIME(xtime, inode, raw_inode)                         \
index 753f4e68b820da0dd78fc7a7e3a66e529846ea0b..c9ab67da6e5abbe871ce4bc7760c007e07f2b479 100644 (file)
@@ -1664,8 +1664,12 @@ static int handle_mount_opt(struct super_block *sb, char *opt, int token,
                }
                sbi->s_jquota_fmt = m->mount_opt;
 #endif
-#ifndef CONFIG_FS_DAX
        } else if (token == Opt_dax) {
+#ifdef CONFIG_FS_DAX
+               ext4_msg(sb, KERN_WARNING,
+               "DAX enabled. Warning: EXPERIMENTAL, use at your own risk");
+                       sbi->s_mount_opt |= m->mount_opt;
+#else
                ext4_msg(sb, KERN_INFO, "dax option not supported");
                return -1;
 #endif
index abe2401ce405669f0d315319f5275a9fc321c697..e8e7af62ac95fc4e5268c32df1bc496a337202a7 100644 (file)
@@ -52,7 +52,7 @@ static const char *ext4_encrypted_follow_link(struct dentry *dentry, void **cook
        /* Symlink is encrypted */
        sd = (struct ext4_encrypted_symlink_data *)caddr;
        cstr.name = sd->encrypted_path;
-       cstr.len  = le32_to_cpu(sd->len);
+       cstr.len  = le16_to_cpu(sd->len);
        if ((cstr.len +
             sizeof(struct ext4_encrypted_symlink_data) - 1) >
            max_size) {
index 1b57c72f4a009aafc8c3510eac81dd9d8a5f9482..1420a3c614afb1a4c06e87471163acf01b3b98d8 100644 (file)
@@ -358,7 +358,7 @@ static int name##_open(struct inode *inode, struct file *file) \
        return single_open(file, ext4_seq_##name##_show, PDE_DATA(inode)); \
 } \
 \
-const struct file_operations ext4_seq_##name##_fops = { \
+static const struct file_operations ext4_seq_##name##_fops = { \
        .owner          = THIS_MODULE, \
        .open           = name##_open, \
        .read           = seq_read, \
index 4afc4d9d2e4127debe45cb51b5f1fc17d16fee4d..8b2127ffb226cca2ece880d41fd756624c5d3118 100644 (file)
@@ -610,9 +610,9 @@ parse_record:
                int status = fat_parse_long(inode, &cpos, &bh, &de,
                                            &unicode, &nr_slots);
                if (status < 0) {
-                       ctx->pos = cpos;
+                       bh = NULL;
                        ret = status;
-                       goto out;
+                       goto end_of_dir;
                } else if (status == PARSE_INVALID)
                        goto record_end;
                else if (status == PARSE_NOT_LONGNAME)
@@ -654,8 +654,9 @@ parse_record:
        fill_len = short_len;
 
 start_filldir:
-       if (!fake_offset)
-               ctx->pos = cpos - (nr_slots + 1) * sizeof(struct msdos_dir_entry);
+       ctx->pos = cpos - (nr_slots + 1) * sizeof(struct msdos_dir_entry);
+       if (fake_offset && ctx->pos < 2)
+               ctx->pos = 2;
 
        if (!memcmp(de->name, MSDOS_DOT, MSDOS_NAME)) {
                if (!dir_emit_dot(file, ctx))
@@ -681,14 +682,19 @@ record_end:
        fake_offset = 0;
        ctx->pos = cpos;
        goto get_new;
+
 end_of_dir:
-       ctx->pos = cpos;
+       if (fake_offset && cpos < 2)
+               ctx->pos = 2;
+       else
+               ctx->pos = cpos;
 fill_failed:
        brelse(bh);
        if (unicode)
                __putname(unicode);
 out:
        mutex_unlock(&sbi->s_lock);
+
        return ret;
 }
 
index eae2c11268bcb484075cfd08482beeb172dd66bc..8e3ee1936c7e38ba381b33c26b2f1847422a613f 100644 (file)
@@ -549,6 +549,8 @@ static int cuse_channel_release(struct inode *inode, struct file *file)
                unregister_chrdev_region(cc->cdev->dev, 1);
                cdev_del(cc->cdev);
        }
+       /* Base reference is now owned by "fud" */
+       fuse_conn_put(&cc->fc);
 
        rc = fuse_dev_release(inode, file);     /* puts the base reference */
 
index e0faf8f2c868a26b80331ef78c89db85091715ea..570ca4053c805eb76acd76a44161f8349a9a6325 100644 (file)
@@ -1049,6 +1049,7 @@ static ssize_t fuse_fill_write_pages(struct fuse_req *req,
                tmp = iov_iter_copy_from_user_atomic(page, ii, offset, bytes);
                flush_dcache_page(page);
 
+               iov_iter_advance(ii, tmp);
                if (!tmp) {
                        unlock_page(page);
                        page_cache_release(page);
@@ -1061,7 +1062,6 @@ static ssize_t fuse_fill_write_pages(struct fuse_req *req,
                req->page_descs[req->num_pages].length = tmp;
                req->num_pages++;
 
-               iov_iter_advance(ii, tmp);
                count += tmp;
                pos += tmp;
                offset += tmp;
index 316adb968b6588faca5d64cf57005f48e067bb08..de4bdfac0cec36f7f3e1d5cee94ec4aecef3e311 100644 (file)
@@ -332,12 +332,17 @@ static void remove_huge_page(struct page *page)
  * truncation is indicated by end of range being LLONG_MAX
  *     In this case, we first scan the range and release found pages.
  *     After releasing pages, hugetlb_unreserve_pages cleans up region/reserv
- *     maps and global counts.
+ *     maps and global counts.  Page faults can not race with truncation
+ *     in this routine.  hugetlb_no_page() prevents page faults in the
+ *     truncated range.  It checks i_size before allocation, and again after
+ *     with the page table lock for the page held.  The same lock must be
+ *     acquired to unmap a page.
  * hole punch is indicated if end is not LLONG_MAX
  *     In the hole punch case we scan the range and release found pages.
  *     Only when releasing a page is the associated region/reserv map
  *     deleted.  The region/reserv map for ranges without associated
- *     pages are not modified.
+ *     pages are not modified.  Page faults can race with hole punch.
+ *     This is indicated if we find a mapped page.
  * Note: If the passed end of range value is beyond the end of file, but
  * not LLONG_MAX this routine still performs a hole punch operation.
  */
@@ -361,46 +366,37 @@ static void remove_inode_hugepages(struct inode *inode, loff_t lstart,
        next = start;
        while (next < end) {
                /*
-                * Make sure to never grab more pages that we
-                * might possibly need.
+                * Don't grab more pages than the number left in the range.
                 */
                if (end - next < lookup_nr)
                        lookup_nr = end - next;
 
                /*
-                * This pagevec_lookup() may return pages past 'end',
-                * so we must check for page->index > end.
+                * When no more pages are found, we are done.
                 */
-               if (!pagevec_lookup(&pvec, mapping, next, lookup_nr)) {
-                       if (next == start)
-                               break;
-                       next = start;
-                       continue;
-               }
+               if (!pagevec_lookup(&pvec, mapping, next, lookup_nr))
+                       break;
 
                for (i = 0; i < pagevec_count(&pvec); ++i) {
                        struct page *page = pvec.pages[i];
                        u32 hash;
 
+                       /*
+                        * The page (index) could be beyond end.  This is
+                        * only possible in the punch hole case as end is
+                        * max page offset in the truncate case.
+                        */
+                       next = page->index;
+                       if (next >= end)
+                               break;
+
                        hash = hugetlb_fault_mutex_hash(h, current->mm,
                                                        &pseudo_vma,
                                                        mapping, next, 0);
                        mutex_lock(&hugetlb_fault_mutex_table[hash]);
 
                        lock_page(page);
-                       if (page->index >= end) {
-                               unlock_page(page);
-                               mutex_unlock(&hugetlb_fault_mutex_table[hash]);
-                               next = end;     /* we are done */
-                               break;
-                       }
-
-                       /*
-                        * If page is mapped, it was faulted in after being
-                        * unmapped.  Do nothing in this race case.  In the
-                        * normal case page is not mapped.
-                        */
-                       if (!page_mapped(page)) {
+                       if (likely(!page_mapped(page))) {
                                bool rsv_on_error = !PagePrivate(page);
                                /*
                                 * We must free the huge page and remove
@@ -421,17 +417,23 @@ static void remove_inode_hugepages(struct inode *inode, loff_t lstart,
                                                hugetlb_fix_reserve_counts(
                                                        inode, rsv_on_error);
                                }
+                       } else {
+                               /*
+                                * If page is mapped, it was faulted in after
+                                * being unmapped.  It indicates a race between
+                                * hole punch and page fault.  Do nothing in
+                                * this case.  Getting here in a truncate
+                                * operation is a bug.
+                                */
+                               BUG_ON(truncate_op);
                        }
 
-                       if (page->index > next)
-                               next = page->index;
-
-                       ++next;
                        unlock_page(page);
-
                        mutex_unlock(&hugetlb_fault_mutex_table[hash]);
                }
+               ++next;
                huge_pagevec_release(&pvec);
+               cond_resched();
        }
 
        if (truncate_op)
@@ -647,9 +649,6 @@ static long hugetlbfs_fallocate(struct file *file, int mode, loff_t offset,
        if (!(mode & FALLOC_FL_KEEP_SIZE) && offset + len > inode->i_size)
                i_size_write(inode, offset + len);
        inode->i_ctime = CURRENT_TIME;
-       spin_lock(&inode->i_lock);
-       inode->i_private = NULL;
-       spin_unlock(&inode->i_lock);
 out:
        mutex_unlock(&inode->i_mutex);
        return error;
index 89463eee67914643a02ce711463e62fac0b83c8d..ca181e81c765518d4a599025c914adbac626e739 100644 (file)
@@ -1009,7 +1009,8 @@ out:
 }
 
 /* Fast check whether buffer is already attached to the required transaction */
-static bool jbd2_write_access_granted(handle_t *handle, struct buffer_head *bh)
+static bool jbd2_write_access_granted(handle_t *handle, struct buffer_head *bh,
+                                                       bool undo)
 {
        struct journal_head *jh;
        bool ret = false;
@@ -1036,6 +1037,9 @@ static bool jbd2_write_access_granted(handle_t *handle, struct buffer_head *bh)
        jh = READ_ONCE(bh->b_private);
        if (!jh)
                goto out;
+       /* For undo access buffer must have data copied */
+       if (undo && !jh->b_committed_data)
+               goto out;
        if (jh->b_transaction != handle->h_transaction &&
            jh->b_next_transaction != handle->h_transaction)
                goto out;
@@ -1073,7 +1077,7 @@ int jbd2_journal_get_write_access(handle_t *handle, struct buffer_head *bh)
        struct journal_head *jh;
        int rc;
 
-       if (jbd2_write_access_granted(handle, bh))
+       if (jbd2_write_access_granted(handle, bh, false))
                return 0;
 
        jh = jbd2_journal_add_journal_head(bh);
@@ -1210,7 +1214,7 @@ int jbd2_journal_get_undo_access(handle_t *handle, struct buffer_head *bh)
        char *committed_data = NULL;
 
        JBUFFER_TRACE(jh, "entry");
-       if (jbd2_write_access_granted(handle, bh))
+       if (jbd2_write_access_granted(handle, bh, true))
                return 0;
 
        jh = jbd2_journal_add_journal_head(bh);
@@ -2152,6 +2156,7 @@ static int journal_unmap_buffer(journal_t *journal, struct buffer_head *bh,
 
                if (!buffer_dirty(bh)) {
                        /* bdflush has written it.  We can drop it now */
+                       __jbd2_journal_remove_checkpoint(jh);
                        goto zap_buffer;
                }
 
@@ -2181,6 +2186,7 @@ static int journal_unmap_buffer(journal_t *journal, struct buffer_head *bh,
                                /* The orphan record's transaction has
                                 * committed.  We can cleanse this buffer */
                                clear_buffer_jbddirty(bh);
+                               __jbd2_journal_remove_checkpoint(jh);
                                goto zap_buffer;
                        }
                }
index d84d7c7515fc44415f11488f192e52ef3c9c9990..0c3974cd3ecd55670ccab51c596b0b141cbdd721 100644 (file)
@@ -1996,7 +1996,6 @@ static const char *path_init(struct nameidata *nd, unsigned flags)
        nd->last_type = LAST_ROOT; /* if there are only slashes... */
        nd->flags = flags | LOOKUP_JUMPED | LOOKUP_PARENT;
        nd->depth = 0;
-       nd->total_link_count = 0;
        if (flags & LOOKUP_ROOT) {
                struct dentry *root = nd->root.dentry;
                struct inode *inode = root->d_inode;
index 79b113048eacdc645fb67994cb0dcb25aad84dd0..0a3f9b594602341350afb79f27ba2cd8191468e8 100644 (file)
@@ -525,6 +525,8 @@ static long __ncp_ioctl(struct inode *inode, unsigned int cmd, unsigned long arg
                        switch (rqdata.cmd) {
                                case NCP_LOCK_EX:
                                case NCP_LOCK_SH:
+                                               if (rqdata.timeout < 0)
+                                                       return -EINVAL;
                                                if (rqdata.timeout == 0)
                                                        rqdata.timeout = NCP_LOCK_DEFAULT_TIMEOUT;
                                                else if (rqdata.timeout > NCP_LOCK_MAX_TIMEOUT)
index 326d9e10d83370f56061220c51e72a42de0595b2..c7e8b87da5b24d13dff36f5d2510244c01b7abf4 100644 (file)
@@ -75,11 +75,11 @@ nfs_fattr_to_ino_t(struct nfs_fattr *fattr)
  * nfs_wait_bit_killable - helper for functions that are sleeping on bit locks
  * @word: long word containing the bit lock
  */
-int nfs_wait_bit_killable(struct wait_bit_key *key)
+int nfs_wait_bit_killable(struct wait_bit_key *key, int mode)
 {
-       if (fatal_signal_pending(current))
-               return -ERESTARTSYS;
        freezable_schedule_unsafe();
+       if (signal_pending_state(mode, current))
+               return -ERESTARTSYS;
        return 0;
 }
 EXPORT_SYMBOL_GPL(nfs_wait_bit_killable);
@@ -618,7 +618,10 @@ void nfs_setattr_update_inode(struct inode *inode, struct iattr *attr,
                nfs_inc_stats(inode, NFSIOS_SETATTRTRUNC);
                nfs_vmtruncate(inode, attr->ia_size);
        }
-       nfs_update_inode(inode, fattr);
+       if (fattr->valid)
+               nfs_update_inode(inode, fattr);
+       else
+               NFS_I(inode)->cache_validity |= NFS_INO_INVALID_ATTR;
        spin_unlock(&inode->i_lock);
 }
 EXPORT_SYMBOL_GPL(nfs_setattr_update_inode);
@@ -1824,7 +1827,11 @@ static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr)
                if ((long)fattr->gencount - (long)nfsi->attr_gencount > 0)
                        nfsi->attr_gencount = fattr->gencount;
        }
-       invalid &= ~NFS_INO_INVALID_ATTR;
+
+       /* Don't declare attrcache up to date if there were no attrs! */
+       if (fattr->valid != 0)
+               invalid &= ~NFS_INO_INVALID_ATTR;
+
        /* Don't invalidate the data if we were to blame */
        if (!(S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode)
                                || S_ISLNK(inode->i_mode)))
index 56cfde26fb9cea0100a99bb7c3fe8a2be813dc63..9dea85f7f918ec410c5281f959e6f546c1700bf2 100644 (file)
@@ -379,7 +379,7 @@ extern int nfs_drop_inode(struct inode *);
 extern void nfs_clear_inode(struct inode *);
 extern void nfs_evict_inode(struct inode *);
 void nfs_zap_acl_cache(struct inode *inode);
-extern int nfs_wait_bit_killable(struct wait_bit_key *key);
+extern int nfs_wait_bit_killable(struct wait_bit_key *key, int mode);
 
 /* super.c */
 extern const struct super_operations nfs_sops;
index 3e92a3cde15d8b61878a7c2ce7d13da1cf01b290..6b1ce9825430c7c9659b49ac9bff545b620bd7bb 100644 (file)
@@ -14,7 +14,7 @@
 #include "pnfs.h"
 #include "internal.h"
 
-#define NFSDBG_FACILITY NFSDBG_PNFS
+#define NFSDBG_FACILITY NFSDBG_PROC
 
 static int nfs42_set_rw_stateid(nfs4_stateid *dst, struct file *file,
                                fmode_t fmode)
@@ -284,6 +284,7 @@ static int _nfs42_proc_clone(struct rpc_message *msg, struct file *src_f,
                .dst_fh = NFS_FH(dst_inode),
                .src_offset = src_offset,
                .dst_offset = dst_offset,
+               .count = count,
                .dst_bitmask = server->cache_consistency_bitmask,
        };
        struct nfs42_clone_res res = {
index 223bedda64ae49f3d94226677e652e31da4c8d84..10410e8b58530389d7efb18352e8a6253d12b267 100644 (file)
@@ -33,7 +33,7 @@ static int nfs_get_cb_ident_idr(struct nfs_client *clp, int minorversion)
                return ret;
        idr_preload(GFP_KERNEL);
        spin_lock(&nn->nfs_client_lock);
-       ret = idr_alloc(&nn->cb_ident_idr, clp, 0, 0, GFP_NOWAIT);
+       ret = idr_alloc(&nn->cb_ident_idr, clp, 1, 0, GFP_NOWAIT);
        if (ret >= 0)
                clp->cl_cb_ident = ret;
        spin_unlock(&nn->nfs_client_lock);
index 4aa571956cd618499df260f6bcf6a0f7c2df8045..db9b5fea5b3ef12f6eacf36cd2154c2db7d4d9f2 100644 (file)
@@ -7,6 +7,7 @@
 #include <linux/file.h>
 #include <linux/falloc.h>
 #include <linux/nfs_fs.h>
+#include <uapi/linux/btrfs.h>  /* BTRFS_IOC_CLONE/BTRFS_IOC_CLONE_RANGE */
 #include "delegation.h"
 #include "internal.h"
 #include "iostat.h"
@@ -203,6 +204,7 @@ nfs42_ioctl_clone(struct file *dst_file, unsigned long srcfd,
        struct fd src_file;
        struct inode *src_inode;
        unsigned int bs = server->clone_blksize;
+       bool same_inode = false;
        int ret;
 
        /* dst file must be opened for writing */
@@ -221,10 +223,8 @@ nfs42_ioctl_clone(struct file *dst_file, unsigned long srcfd,
 
        src_inode = file_inode(src_file.file);
 
-       /* src and dst must be different files */
-       ret = -EINVAL;
        if (src_inode == dst_inode)
-               goto out_fput;
+               same_inode = true;
 
        /* src file must be opened for reading */
        if (!(src_file.file->f_mode & FMODE_READ))
@@ -249,8 +249,16 @@ nfs42_ioctl_clone(struct file *dst_file, unsigned long srcfd,
                        goto out_fput;
        }
 
+       /* verify if ranges are overlapped within the same file */
+       if (same_inode) {
+               if (dst_off + count > src_off && dst_off < src_off + count)
+                       goto out_fput;
+       }
+
        /* XXX: do we lock at all? what if server needs CB_RECALL_LAYOUT? */
-       if (dst_inode < src_inode) {
+       if (same_inode) {
+               mutex_lock(&src_inode->i_mutex);
+       } else if (dst_inode < src_inode) {
                mutex_lock_nested(&dst_inode->i_mutex, I_MUTEX_PARENT);
                mutex_lock_nested(&src_inode->i_mutex, I_MUTEX_CHILD);
        } else {
@@ -275,7 +283,9 @@ nfs42_ioctl_clone(struct file *dst_file, unsigned long srcfd,
                truncate_inode_pages_range(&dst_inode->i_data, dst_off, dst_off + count - 1);
 
 out_unlock:
-       if (dst_inode < src_inode) {
+       if (same_inode) {
+               mutex_unlock(&src_inode->i_mutex);
+       } else if (dst_inode < src_inode) {
                mutex_unlock(&src_inode->i_mutex);
                mutex_unlock(&dst_inode->i_mutex);
        } else {
@@ -291,46 +301,31 @@ out_drop_write:
 
 static long nfs42_ioctl_clone_range(struct file *dst_file, void __user *argp)
 {
-       struct nfs_ioctl_clone_range_args args;
+       struct btrfs_ioctl_clone_range_args args;
 
        if (copy_from_user(&args, argp, sizeof(args)))
                return -EFAULT;
 
-       return nfs42_ioctl_clone(dst_file, args.src_fd, args.src_off, args.dst_off, args.count);
-}
-#else
-static long nfs42_ioctl_clone(struct file *dst_file, unsigned long srcfd,
-               u64 src_off, u64 dst_off, u64 count)
-{
-       return -ENOTTY;
-}
-
-static long nfs42_ioctl_clone_range(struct file *dst_file, void __user *argp)
-{
-       return -ENOTTY;
+       return nfs42_ioctl_clone(dst_file, args.src_fd, args.src_offset,
+                                args.dest_offset, args.src_length);
 }
-#endif /* CONFIG_NFS_V4_2 */
 
 long nfs4_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
 {
        void __user *argp = (void __user *)arg;
 
        switch (cmd) {
-       case NFS_IOC_CLONE:
+       case BTRFS_IOC_CLONE:
                return nfs42_ioctl_clone(file, arg, 0, 0, 0);
-       case NFS_IOC_CLONE_RANGE:
+       case BTRFS_IOC_CLONE_RANGE:
                return nfs42_ioctl_clone_range(file, argp);
        }
 
        return -ENOTTY;
 }
+#endif /* CONFIG_NFS_V4_2 */
 
 const struct file_operations nfs4_file_operations = {
-#ifdef CONFIG_NFS_V4_2
-       .llseek         = nfs4_file_llseek,
-#else
-       .llseek         = nfs_file_llseek,
-#endif
        .read_iter      = nfs_file_read,
        .write_iter     = nfs_file_write,
        .mmap           = nfs_file_mmap,
@@ -342,14 +337,14 @@ const struct file_operations nfs4_file_operations = {
        .flock          = nfs_flock,
        .splice_read    = nfs_file_splice_read,
        .splice_write   = iter_file_splice_write,
-#ifdef CONFIG_NFS_V4_2
-       .fallocate      = nfs42_fallocate,
-#endif /* CONFIG_NFS_V4_2 */
        .check_flags    = nfs_check_flags,
        .setlease       = simple_nosetlease,
-#ifdef CONFIG_COMPAT
+#ifdef CONFIG_NFS_V4_2
+       .llseek         = nfs4_file_llseek,
+       .fallocate      = nfs42_fallocate,
        .unlocked_ioctl = nfs4_ioctl,
-#else
        .compat_ioctl   = nfs4_ioctl,
-#endif /* CONFIG_COMPAT */
+#else
+       .llseek         = nfs_file_llseek,
+#endif
 };
index 765a035593638cfd17b4aedd646c0362068343c6..89818036f035b01eaaa4e45797205d53f48e9934 100644 (file)
@@ -7866,7 +7866,7 @@ static void nfs4_layoutget_done(struct rpc_task *task, void *calldata)
                        spin_unlock(&inode->i_lock);
                goto out_restart;
        }
-       if (nfs4_async_handle_error(task, server, state, NULL) == -EAGAIN)
+       if (nfs4_async_handle_error(task, server, state, &lgp->timeout) == -EAGAIN)
                goto out_restart;
 out:
        dprintk("<-- %s\n", __func__);
index dfed4f5c8fccf91a91b5669461d4a3f490b12cb2..4e4441216804ec550f2c135ef0f393f4f7a1426c 100644 (file)
@@ -3615,6 +3615,7 @@ static int decode_attr_fs_locations(struct xdr_stream *xdr, uint32_t *bitmap, st
        status = 0;
        if (unlikely(!(bitmap[0] & FATTR4_WORD0_FS_LOCATIONS)))
                goto out;
+       bitmap[0] &= ~FATTR4_WORD0_FS_LOCATIONS;
        status = -EIO;
        /* Ignore borken servers that return unrequested attrs */
        if (unlikely(res == NULL))
index 5c0c6b58157f906d6c35ce737a6d4a5623027bf1..9aebffb4050597e1daae74f28375d86335f73e0c 100644 (file)
@@ -476,10 +476,7 @@ static struct page *__r4w_get_page(void *priv, u64 offset, bool *uptodate)
                }
                unlock_page(page);
        }
-       if (PageDirty(page) || PageWriteback(page))
-               *uptodate = true;
-       else
-               *uptodate = PageUptodate(page);
+       *uptodate = PageUptodate(page);
        dprintk("%s: index=0x%lx uptodate=%d\n", __func__, index, *uptodate);
        return page;
 }
index fe3ddd20ff89095331ad854bafb4b26bc019e01e..452a011ba0d8a33e9e4b9afd858f82858185f57e 100644 (file)
@@ -129,7 +129,7 @@ __nfs_iocounter_wait(struct nfs_io_counter *c)
                set_bit(NFS_IO_INPROGRESS, &c->flags);
                if (atomic_read(&c->io_count) == 0)
                        break;
-               ret = nfs_wait_bit_killable(&q.key);
+               ret = nfs_wait_bit_killable(&q.key, TASK_KILLABLE);
        } while (atomic_read(&c->io_count) != 0 && !ret);
        finish_wait(wq, &q.wait);
        return ret;
index 93496c0598375409876f4a25f95d90ef7feb7334..bec0384499f76dd1acc8fb13bbf34c2ee17e6a9b 100644 (file)
@@ -872,33 +872,38 @@ send_layoutget(struct pnfs_layout_hdr *lo,
 
        dprintk("--> %s\n", __func__);
 
-       lgp = kzalloc(sizeof(*lgp), gfp_flags);
-       if (lgp == NULL)
-               return NULL;
+       /*
+        * Synchronously retrieve layout information from server and
+        * store in lseg. If we race with a concurrent seqid morphing
+        * op, then re-send the LAYOUTGET.
+        */
+       do {
+               lgp = kzalloc(sizeof(*lgp), gfp_flags);
+               if (lgp == NULL)
+                       return NULL;
+
+               i_size = i_size_read(ino);
+
+               lgp->args.minlength = PAGE_CACHE_SIZE;
+               if (lgp->args.minlength > range->length)
+                       lgp->args.minlength = range->length;
+               if (range->iomode == IOMODE_READ) {
+                       if (range->offset >= i_size)
+                               lgp->args.minlength = 0;
+                       else if (i_size - range->offset < lgp->args.minlength)
+                               lgp->args.minlength = i_size - range->offset;
+               }
+               lgp->args.maxcount = PNFS_LAYOUT_MAXSIZE;
+               lgp->args.range = *range;
+               lgp->args.type = server->pnfs_curr_ld->id;
+               lgp->args.inode = ino;
+               lgp->args.ctx = get_nfs_open_context(ctx);
+               lgp->gfp_flags = gfp_flags;
+               lgp->cred = lo->plh_lc_cred;
 
-       i_size = i_size_read(ino);
+               lseg = nfs4_proc_layoutget(lgp, gfp_flags);
+       } while (lseg == ERR_PTR(-EAGAIN));
 
-       lgp->args.minlength = PAGE_CACHE_SIZE;
-       if (lgp->args.minlength > range->length)
-               lgp->args.minlength = range->length;
-       if (range->iomode == IOMODE_READ) {
-               if (range->offset >= i_size)
-                       lgp->args.minlength = 0;
-               else if (i_size - range->offset < lgp->args.minlength)
-                       lgp->args.minlength = i_size - range->offset;
-       }
-       lgp->args.maxcount = PNFS_LAYOUT_MAXSIZE;
-       lgp->args.range = *range;
-       lgp->args.type = server->pnfs_curr_ld->id;
-       lgp->args.inode = ino;
-       lgp->args.ctx = get_nfs_open_context(ctx);
-       lgp->gfp_flags = gfp_flags;
-       lgp->cred = lo->plh_lc_cred;
-
-       /* Synchronously retrieve layout information from server and
-        * store in lseg.
-        */
-       lseg = nfs4_proc_layoutget(lgp, gfp_flags);
        if (IS_ERR(lseg)) {
                switch (PTR_ERR(lseg)) {
                case -ENOMEM:
@@ -1461,11 +1466,11 @@ static bool pnfs_within_mdsthreshold(struct nfs_open_context *ctx,
 }
 
 /* stop waiting if someone clears NFS_LAYOUT_RETRY_LAYOUTGET bit. */
-static int pnfs_layoutget_retry_bit_wait(struct wait_bit_key *key)
+static int pnfs_layoutget_retry_bit_wait(struct wait_bit_key *key, int mode)
 {
        if (!test_bit(NFS_LAYOUT_RETRY_LAYOUTGET, key->flags))
                return 1;
-       return nfs_wait_bit_killable(key);
+       return nfs_wait_bit_killable(key, mode);
 }
 
 static bool pnfs_prepare_to_retry_layoutget(struct pnfs_layout_hdr *lo)
@@ -1687,6 +1692,7 @@ pnfs_layout_process(struct nfs4_layoutget *lgp)
                /* existing state ID, make sure the sequence number matches. */
                if (pnfs_layout_stateid_blocked(lo, &res->stateid)) {
                        dprintk("%s forget reply due to sequence\n", __func__);
+                       status = -EAGAIN;
                        goto out_forget_reply;
                }
                pnfs_set_layout_stateid(lo, &res->stateid, false);
index 9ffef06b30d51e2acb2ae1a6570f14c2c47eac59..c9d6c715c0fb7e3187ffd1f2105f9527aa32259b 100644 (file)
@@ -616,6 +616,7 @@ nfsd4_cb_layout_prepare(struct nfsd4_callback *cb)
 
        mutex_lock(&ls->ls_mutex);
        nfs4_inc_and_copy_stateid(&ls->ls_recall_sid, &ls->ls_stid);
+       mutex_unlock(&ls->ls_mutex);
 }
 
 static int
@@ -659,7 +660,6 @@ nfsd4_cb_layout_release(struct nfsd4_callback *cb)
 
        trace_layout_recall_release(&ls->ls_stid.sc_stateid);
 
-       mutex_unlock(&ls->ls_mutex);
        nfsd4_return_all_layouts(ls, &reaplist);
        nfsd4_free_layouts(&reaplist);
        nfs4_put_stid(&ls->ls_stid);
index ce38b4ccc9ab6c52c796a148b496bab0d8d46510..84f2f8079466a7fc07c8a4fda50d3513a02b68f9 100644 (file)
@@ -2843,6 +2843,8 @@ again:
        res->state &= ~DLM_LOCK_RES_BLOCK_DIRTY;
        if (!ret)
                BUG_ON(!(res->state & DLM_LOCK_RES_MIGRATING));
+       else
+               res->migration_pending = 0;
        spin_unlock(&res->spinlock);
 
        /*
index 652ece4a9d9e2e90a72a95b4be1d910ea46cfc9f..d56f0079b858081241357b26667bf7fba9de5e3e 100644 (file)
@@ -67,7 +67,10 @@ static int ocfs2_do_flock(struct file *file, struct inode *inode,
                 */
 
                locks_lock_file_wait(file,
-                                    &(struct file_lock){.fl_type = F_UNLCK});
+                               &(struct file_lock) {
+                                       .fl_type = F_UNLCK,
+                                       .fl_flags = FL_FLOCK
+                               });
 
                ocfs2_file_unlock(file);
        }
index 3b48ac25d8a7c450ac23360b5f7d28e9fafcc263..3123408da9352b365e8bb3ca5e619a8f188cdc5a 100644 (file)
@@ -367,7 +367,7 @@ static int ocfs2_mknod(struct inode *dir,
                goto leave;
        }
 
-       status = posix_acl_create(dir, &mode, &default_acl, &acl);
+       status = posix_acl_create(dir, &inode->i_mode, &default_acl, &acl);
        if (status) {
                mlog_errno(status);
                goto leave;
index d5da6f624142812ab63e83f5ab1b90e05151fed3..79b8021302b3eed84b9c59637cddd0e4844eb78b 100644 (file)
 static u16 ocfs2_calc_new_backup_super(struct inode *inode,
                                       struct ocfs2_group_desc *gd,
                                       u16 cl_cpg,
+                                      u16 old_bg_clusters,
                                       int set)
 {
        int i;
        u16 backups = 0;
-       u32 cluster;
+       u32 cluster, lgd_cluster;
        u64 blkno, gd_blkno, lgd_blkno = le64_to_cpu(gd->bg_blkno);
 
        for (i = 0; i < OCFS2_MAX_BACKUP_SUPERBLOCKS; i++) {
@@ -71,6 +72,12 @@ static u16 ocfs2_calc_new_backup_super(struct inode *inode,
                else if (gd_blkno > lgd_blkno)
                        break;
 
+               /* check if already done backup super */
+               lgd_cluster = ocfs2_blocks_to_clusters(inode->i_sb, lgd_blkno);
+               lgd_cluster += old_bg_clusters;
+               if (lgd_cluster >= cluster)
+                       continue;
+
                if (set)
                        ocfs2_set_bit(cluster % cl_cpg,
                                      (unsigned long *)gd->bg_bitmap);
@@ -99,6 +106,7 @@ static int ocfs2_update_last_group_and_inode(handle_t *handle,
        u16 chain, num_bits, backups = 0;
        u16 cl_bpc = le16_to_cpu(cl->cl_bpc);
        u16 cl_cpg = le16_to_cpu(cl->cl_cpg);
+       u16 old_bg_clusters;
 
        trace_ocfs2_update_last_group_and_inode(new_clusters,
                                                first_new_cluster);
@@ -112,6 +120,7 @@ static int ocfs2_update_last_group_and_inode(handle_t *handle,
 
        group = (struct ocfs2_group_desc *)group_bh->b_data;
 
+       old_bg_clusters = le16_to_cpu(group->bg_bits) / cl_bpc;
        /* update the group first. */
        num_bits = new_clusters * cl_bpc;
        le16_add_cpu(&group->bg_bits, num_bits);
@@ -125,7 +134,7 @@ static int ocfs2_update_last_group_and_inode(handle_t *handle,
                                     OCFS2_FEATURE_COMPAT_BACKUP_SB)) {
                backups = ocfs2_calc_new_backup_super(bm_inode,
                                                     group,
-                                                    cl_cpg, 1);
+                                                    cl_cpg, old_bg_clusters, 1);
                le16_add_cpu(&group->bg_free_bits_count, -1 * backups);
        }
 
@@ -163,7 +172,7 @@ out_rollback:
        if (ret < 0) {
                ocfs2_calc_new_backup_super(bm_inode,
                                            group,
-                                           cl_cpg, 0);
+                                           cl_cpg, old_bg_clusters, 0);
                le16_add_cpu(&group->bg_free_bits_count, backups);
                le16_add_cpu(&group->bg_bits, -1 * num_bits);
                le16_add_cpu(&group->bg_free_bits_count, -1 * num_bits);
index 871fcb67be9741f2aab81f3d6552306dedf4c967..0a8983492d917bbc61888559e8417f738eb607be 100644 (file)
@@ -195,8 +195,7 @@ int ovl_set_attr(struct dentry *upperdentry, struct kstat *stat)
 
 static int ovl_copy_up_locked(struct dentry *workdir, struct dentry *upperdir,
                              struct dentry *dentry, struct path *lowerpath,
-                             struct kstat *stat, struct iattr *attr,
-                             const char *link)
+                             struct kstat *stat, const char *link)
 {
        struct inode *wdir = workdir->d_inode;
        struct inode *udir = upperdir->d_inode;
@@ -240,8 +239,6 @@ static int ovl_copy_up_locked(struct dentry *workdir, struct dentry *upperdir,
 
        mutex_lock(&newdentry->d_inode->i_mutex);
        err = ovl_set_attr(newdentry, stat);
-       if (!err && attr)
-               err = notify_change(newdentry, attr, NULL);
        mutex_unlock(&newdentry->d_inode->i_mutex);
        if (err)
                goto out_cleanup;
@@ -286,8 +283,7 @@ out_cleanup:
  * that point the file will have already been copied up anyway.
  */
 int ovl_copy_up_one(struct dentry *parent, struct dentry *dentry,
-                   struct path *lowerpath, struct kstat *stat,
-                   struct iattr *attr)
+                   struct path *lowerpath, struct kstat *stat)
 {
        struct dentry *workdir = ovl_workdir(dentry);
        int err;
@@ -345,26 +341,19 @@ int ovl_copy_up_one(struct dentry *parent, struct dentry *dentry,
        }
        upperdentry = ovl_dentry_upper(dentry);
        if (upperdentry) {
-               unlock_rename(workdir, upperdir);
+               /* Raced with another copy-up?  Nothing to do, then... */
                err = 0;
-               /* Raced with another copy-up?  Do the setattr here */
-               if (attr) {
-                       mutex_lock(&upperdentry->d_inode->i_mutex);
-                       err = notify_change(upperdentry, attr, NULL);
-                       mutex_unlock(&upperdentry->d_inode->i_mutex);
-               }
-               goto out_put_cred;
+               goto out_unlock;
        }
 
        err = ovl_copy_up_locked(workdir, upperdir, dentry, lowerpath,
-                                stat, attr, link);
+                                stat, link);
        if (!err) {
                /* Restore timestamps on parent (best effort) */
                ovl_set_timestamps(upperdir, &pstat);
        }
 out_unlock:
        unlock_rename(workdir, upperdir);
-out_put_cred:
        revert_creds(old_cred);
        put_cred(override_cred);
 
@@ -406,7 +395,7 @@ int ovl_copy_up(struct dentry *dentry)
                ovl_path_lower(next, &lowerpath);
                err = vfs_getattr(&lowerpath, &stat);
                if (!err)
-                       err = ovl_copy_up_one(parent, next, &lowerpath, &stat, NULL);
+                       err = ovl_copy_up_one(parent, next, &lowerpath, &stat);
 
                dput(parent);
                dput(next);
index ec0c2a050043afbb3eff4c7451930dc6d86006ec..4060ffde87225c81114d086c000773d4019255b5 100644 (file)
@@ -12,8 +12,7 @@
 #include <linux/xattr.h>
 #include "overlayfs.h"
 
-static int ovl_copy_up_last(struct dentry *dentry, struct iattr *attr,
-                           bool no_data)
+static int ovl_copy_up_truncate(struct dentry *dentry)
 {
        int err;
        struct dentry *parent;
@@ -30,10 +29,8 @@ static int ovl_copy_up_last(struct dentry *dentry, struct iattr *attr,
        if (err)
                goto out_dput_parent;
 
-       if (no_data)
-               stat.size = 0;
-
-       err = ovl_copy_up_one(parent, dentry, &lowerpath, &stat, attr);
+       stat.size = 0;
+       err = ovl_copy_up_one(parent, dentry, &lowerpath, &stat);
 
 out_dput_parent:
        dput(parent);
@@ -49,13 +46,13 @@ int ovl_setattr(struct dentry *dentry, struct iattr *attr)
        if (err)
                goto out;
 
-       upperdentry = ovl_dentry_upper(dentry);
-       if (upperdentry) {
+       err = ovl_copy_up(dentry);
+       if (!err) {
+               upperdentry = ovl_dentry_upper(dentry);
+
                mutex_lock(&upperdentry->d_inode->i_mutex);
                err = notify_change(upperdentry, attr, NULL);
                mutex_unlock(&upperdentry->d_inode->i_mutex);
-       } else {
-               err = ovl_copy_up_last(dentry, attr, false);
        }
        ovl_drop_write(dentry);
 out:
@@ -353,7 +350,7 @@ struct inode *ovl_d_select_inode(struct dentry *dentry, unsigned file_flags)
                        return ERR_PTR(err);
 
                if (file_flags & O_TRUNC)
-                       err = ovl_copy_up_last(dentry, NULL, true);
+                       err = ovl_copy_up_truncate(dentry);
                else
                        err = ovl_copy_up(dentry);
                ovl_drop_write(dentry);
index ea5a40b06e3ad3f9e114bd7d3aab8b931b567051..e17154aeaae4761ca8ec466b96afe913cd40c322 100644 (file)
@@ -194,7 +194,6 @@ void ovl_cleanup(struct inode *dir, struct dentry *dentry);
 /* copy_up.c */
 int ovl_copy_up(struct dentry *dentry);
 int ovl_copy_up_one(struct dentry *parent, struct dentry *dentry,
-                   struct path *lowerpath, struct kstat *stat,
-                   struct iattr *attr);
+                   struct path *lowerpath, struct kstat *stat);
 int ovl_copy_xattr(struct dentry *old, struct dentry *new);
 int ovl_set_attr(struct dentry *upper, struct kstat *stat);
index bd3e9e68125b8933b2e32a4fea2e2282397dc1cd..4bd5d3118acd4b152d6e6f17b38b0a03b0f723d6 100644 (file)
@@ -2494,6 +2494,7 @@ static ssize_t proc_coredump_filter_write(struct file *file,
        mm = get_task_mm(task);
        if (!mm)
                goto out_no_mm;
+       ret = 0;
 
        for (i = 0, mask = 1; i < MMF_DUMP_FILTER_BITS; i++, mask <<= 1) {
                if (val & mask)
index 801c21cd77fe4f1d344aed6fa7b28369972d82b2..4cf700d50b4037e6c334b0647cdb81b816f9ef65 100644 (file)
@@ -809,6 +809,13 @@ static int splice_from_pipe_feed(struct pipe_inode_info *pipe, struct splice_des
  */
 static int splice_from_pipe_next(struct pipe_inode_info *pipe, struct splice_desc *sd)
 {
+       /*
+        * Check for signal early to make process killable when there are
+        * always buffers available
+        */
+       if (signal_pending(current))
+               return -ERESTARTSYS;
+
        while (!pipe->nrbufs) {
                if (!pipe->writers)
                        return 0;
@@ -884,6 +891,7 @@ ssize_t __splice_from_pipe(struct pipe_inode_info *pipe, struct splice_desc *sd,
 
        splice_from_pipe_begin(sd);
        do {
+               cond_resched();
                ret = splice_from_pipe_next(pipe, sd);
                if (ret > 0)
                        ret = splice_from_pipe_feed(pipe, sd, actor);
index 590ad9206e3f4e761d2c2ad95cfaedfa76b47e16..02fa1dcc5969f6b596a6c527170fcf9193c437e5 100644 (file)
@@ -162,15 +162,8 @@ void sysv_set_inode(struct inode *inode, dev_t rdev)
                inode->i_fop = &sysv_dir_operations;
                inode->i_mapping->a_ops = &sysv_aops;
        } else if (S_ISLNK(inode->i_mode)) {
-               if (inode->i_blocks) {
-                       inode->i_op = &sysv_symlink_inode_operations;
-                       inode->i_mapping->a_ops = &sysv_aops;
-               } else {
-                       inode->i_op = &simple_symlink_inode_operations;
-                       inode->i_link = (char *)SYSV_I(inode)->i_data;
-                       nd_terminate_link(inode->i_link, inode->i_size,
-                               sizeof(SYSV_I(inode)->i_data) - 1);
-               }
+               inode->i_op = &sysv_symlink_inode_operations;
+               inode->i_mapping->a_ops = &sysv_aops;
        } else
                init_special_inode(inode, inode->i_mode, rdev);
 }
index db284bff29dcceb39360d458cec3a194745955f8..9dbb739cafa0c16dda9d011d30ce8cd9b4091fd4 100644 (file)
@@ -5,7 +5,7 @@
  * Copyright 2001 Red Hat, Inc.
  * Based on code from mm/memory.c Copyright Linus Torvalds and others.
  *
- * Copyright 2011 Red Hat, Inc., Peter Zijlstra <pzijlstr@redhat.com>
+ * Copyright 2011 Red Hat, Inc., Peter Zijlstra
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License
index 0b921ae06cd83585e1d1cf2adb6baf665f203013..0a271ca1f7c7ec12199b4c9781bb5aa5ded75dae 100644 (file)
@@ -309,6 +309,11 @@ struct drm_file {
        unsigned universal_planes:1;
        /* true if client understands atomic properties */
        unsigned atomic:1;
+       /*
+        * This client is allowed to gain master privileges for @master.
+        * Protected by struct drm_device::master_mutex.
+        */
+       unsigned allowed_master:1;
 
        struct pid *pid;
        kuid_t uid;
@@ -910,6 +915,7 @@ extern int drm_open(struct inode *inode, struct file *filp);
 extern ssize_t drm_read(struct file *filp, char __user *buffer,
                        size_t count, loff_t *offset);
 extern int drm_release(struct inode *inode, struct file *filp);
+extern int drm_new_set_master(struct drm_device *dev, struct drm_file *fpriv);
 
                                /* Mapping support (drm_vm.h) */
 extern unsigned int drm_poll(struct file *filp, struct poll_table_struct *wait);
@@ -947,6 +953,10 @@ extern void drm_send_vblank_event(struct drm_device *dev, unsigned int pipe,
                                  struct drm_pending_vblank_event *e);
 extern void drm_crtc_send_vblank_event(struct drm_crtc *crtc,
                                       struct drm_pending_vblank_event *e);
+extern void drm_arm_vblank_event(struct drm_device *dev, unsigned int pipe,
+                                struct drm_pending_vblank_event *e);
+extern void drm_crtc_arm_vblank_event(struct drm_crtc *crtc,
+                                     struct drm_pending_vblank_event *e);
 extern bool drm_handle_vblank(struct drm_device *dev, unsigned int pipe);
 extern bool drm_crtc_handle_vblank(struct drm_crtc *crtc);
 extern int drm_vblank_get(struct drm_device *dev, unsigned int pipe);
index e67aeac2aee05c077eec5a47abc9d73eef6831d6..4b74c97d297a3e8f24a50de057cb4db79750f39c 100644 (file)
@@ -136,6 +136,9 @@ drm_atomic_connectors_for_crtc(struct drm_atomic_state *state,
 
 void drm_atomic_legacy_backoff(struct drm_atomic_state *state);
 
+void
+drm_atomic_clean_old_fb(struct drm_device *dev, unsigned plane_mask, int ret);
+
 int __must_check drm_atomic_check_only(struct drm_atomic_state *state);
 int __must_check drm_atomic_commit(struct drm_atomic_state *state);
 int __must_check drm_atomic_async_commit(struct drm_atomic_state *state);
index 9c747cb14ad88809b9c77df72d8c0563f0230319..d2f41477f8ae77600a8683890b3615766b9a3701 100644 (file)
@@ -342,10 +342,10 @@ int kvm_vgic_inject_mapped_irq(struct kvm *kvm, int cpuid,
                               struct irq_phys_map *map, bool level);
 void vgic_v3_dispatch_sgi(struct kvm_vcpu *vcpu, u64 reg);
 int kvm_vgic_vcpu_pending_irq(struct kvm_vcpu *vcpu);
-int kvm_vgic_vcpu_active_irq(struct kvm_vcpu *vcpu);
 struct irq_phys_map *kvm_vgic_map_phys_irq(struct kvm_vcpu *vcpu,
                                           int virt_irq, int irq);
 int kvm_vgic_unmap_phys_irq(struct kvm_vcpu *vcpu, struct irq_phys_map *map);
+bool kvm_vgic_map_is_active(struct kvm_vcpu *vcpu, struct irq_phys_map *map);
 
 #define irqchip_in_kernel(k)   (!!((k)->arch.vgic.in_kernel))
 #define vgic_initialized(k)    (!!((k)->arch.vgic.nr_cpus))
index 05483393999534d91425b01c4573a5a4aa494fbc..1991aea2ec4cff401b84db2841ac60fe28f00080 100644 (file)
@@ -870,8 +870,8 @@ static inline int acpi_dev_get_property(struct acpi_device *adev,
 }
 
 static inline int acpi_node_get_property_reference(struct fwnode_handle *fwnode,
-                               const char *name, const char *cells_name,
-                               size_t index, struct acpi_reference_args *args)
+                               const char *name, size_t index,
+                               struct acpi_reference_args *args)
 {
        return -ENXIO;
 }
index 2b8ed123ad36b26bc26956293452937d3ac1b90e..defeaac0745f1b26340d7a13f5b73810de743193 100644 (file)
@@ -107,7 +107,7 @@ static inline __u64 ror64(__u64 word, unsigned int shift)
  */
 static inline __u32 rol32(__u32 word, unsigned int shift)
 {
-       return (word << shift) | (word >> (32 - shift));
+       return (word << shift) | (word >> ((-shift) & 31));
 }
 
 /**
index 3fe27f8d91f04f83751453f19f4e4bb6a4f9a2b4..c70e3588a48c723f4b7cd8536c0dabfc02871d5c 100644 (file)
@@ -254,6 +254,7 @@ struct queue_limits {
        unsigned long           virt_boundary_mask;
 
        unsigned int            max_hw_sectors;
+       unsigned int            max_dev_sectors;
        unsigned int            chunk_sectors;
        unsigned int            max_sectors;
        unsigned int            max_segment_size;
@@ -773,7 +774,6 @@ extern void blk_rq_set_block_pc(struct request *);
 extern void blk_requeue_request(struct request_queue *, struct request *);
 extern void blk_add_request_payload(struct request *rq, struct page *page,
                unsigned int len);
-extern int blk_rq_check_limits(struct request_queue *q, struct request *rq);
 extern int blk_lld_busy(struct request_queue *q);
 extern int blk_rq_prep_clone(struct request *rq, struct request *rq_src,
                             struct bio_set *bs, gfp_t gfp_mask,
@@ -794,7 +794,10 @@ extern int scsi_cmd_ioctl(struct request_queue *, struct gendisk *, fmode_t,
 extern int sg_scsi_ioctl(struct request_queue *, struct gendisk *, fmode_t,
                         struct scsi_ioctl_command __user *);
 
+extern int blk_queue_enter(struct request_queue *q, gfp_t gfp);
+extern void blk_queue_exit(struct request_queue *q);
 extern void blk_start_queue(struct request_queue *q);
+extern void blk_start_queue_async(struct request_queue *q);
 extern void blk_stop_queue(struct request_queue *q);
 extern void blk_sync_queue(struct request_queue *q);
 extern void __blk_stop_queue(struct request_queue *q);
@@ -958,7 +961,6 @@ extern struct request_queue *blk_init_allocated_queue(struct request_queue *,
 extern void blk_cleanup_queue(struct request_queue *);
 extern void blk_queue_make_request(struct request_queue *, make_request_fn *);
 extern void blk_queue_bounce_limit(struct request_queue *, u64);
-extern void blk_limits_max_hw_sectors(struct queue_limits *, unsigned int);
 extern void blk_queue_max_hw_sectors(struct request_queue *, unsigned int);
 extern void blk_queue_chunk_sectors(struct request_queue *, unsigned int);
 extern void blk_queue_max_segments(struct request_queue *, unsigned short);
index de464e6683b68f247492d69a02b463f6bfb4b3df..83d1926c61e4567b881bfbc26b75b802c428cbc3 100644 (file)
@@ -40,6 +40,7 @@ struct bpf_map {
        struct user_struct *user;
        const struct bpf_map_ops *ops;
        struct work_struct work;
+       atomic_t usercnt;
 };
 
 struct bpf_map_type_list {
@@ -167,8 +168,10 @@ struct bpf_prog *bpf_prog_get(u32 ufd);
 void bpf_prog_put(struct bpf_prog *prog);
 void bpf_prog_put_rcu(struct bpf_prog *prog);
 
-struct bpf_map *bpf_map_get(u32 ufd);
+struct bpf_map *bpf_map_get_with_uref(u32 ufd);
 struct bpf_map *__bpf_map_get(struct fd f);
+void bpf_map_inc(struct bpf_map *map, bool uref);
+void bpf_map_put_with_uref(struct bpf_map *map);
 void bpf_map_put(struct bpf_map *map);
 
 extern int sysctl_unprivileged_bpf_disabled;
index 60d44b26276d84a77d7f7e3379ae12821a8b3eeb..06b77f9dd3f2052ac87f970b8aa8c195b78f7ada 100644 (file)
@@ -90,7 +90,6 @@ enum {
  */
 struct cgroup_file {
        /* do not access any fields from outside cgroup core */
-       struct list_head node;                  /* anchored at css->files */
        struct kernfs_node *kn;
 };
 
@@ -134,9 +133,6 @@ struct cgroup_subsys_state {
         */
        u64 serial_nr;
 
-       /* all cgroup_files associated with this css */
-       struct list_head files;
-
        /* percpu_ref killing and RCU release */
        struct rcu_head rcu_head;
        struct work_struct destroy_work;
@@ -426,12 +422,9 @@ struct cgroup_subsys {
        void (*css_reset)(struct cgroup_subsys_state *css);
        void (*css_e_css_changed)(struct cgroup_subsys_state *css);
 
-       int (*can_attach)(struct cgroup_subsys_state *css,
-                         struct cgroup_taskset *tset);
-       void (*cancel_attach)(struct cgroup_subsys_state *css,
-                             struct cgroup_taskset *tset);
-       void (*attach)(struct cgroup_subsys_state *css,
-                      struct cgroup_taskset *tset);
+       int (*can_attach)(struct cgroup_taskset *tset);
+       void (*cancel_attach)(struct cgroup_taskset *tset);
+       void (*attach)(struct cgroup_taskset *tset);
        int (*can_fork)(struct task_struct *task, void **priv_p);
        void (*cancel_fork)(struct task_struct *task, void *priv);
        void (*fork)(struct task_struct *task, void *priv);
index 22e3754f89c511374af4ca8ac5a518786dcd6d88..cb91b44f5f7877d5899403b26ca1d9231c1ac9b6 100644 (file)
@@ -88,6 +88,7 @@ int cgroup_transfer_tasks(struct cgroup *to, struct cgroup *from);
 int cgroup_add_dfl_cftypes(struct cgroup_subsys *ss, struct cftype *cfts);
 int cgroup_add_legacy_cftypes(struct cgroup_subsys *ss, struct cftype *cfts);
 int cgroup_rm_cftypes(struct cftype *cfts);
+void cgroup_file_notify(struct cgroup_file *cfile);
 
 char *task_cgroup_path(struct task_struct *task, char *buf, size_t buflen);
 int cgroupstats_build(struct cgroupstats *stats, struct dentry *dentry);
@@ -119,8 +120,10 @@ struct cgroup_subsys_state *css_rightmost_descendant(struct cgroup_subsys_state
 struct cgroup_subsys_state *css_next_descendant_post(struct cgroup_subsys_state *pos,
                                                     struct cgroup_subsys_state *css);
 
-struct task_struct *cgroup_taskset_first(struct cgroup_taskset *tset);
-struct task_struct *cgroup_taskset_next(struct cgroup_taskset *tset);
+struct task_struct *cgroup_taskset_first(struct cgroup_taskset *tset,
+                                        struct cgroup_subsys_state **dst_cssp);
+struct task_struct *cgroup_taskset_next(struct cgroup_taskset *tset,
+                                       struct cgroup_subsys_state **dst_cssp);
 
 void css_task_iter_start(struct cgroup_subsys_state *css,
                         struct css_task_iter *it);
@@ -235,30 +238,39 @@ void css_task_iter_end(struct css_task_iter *it);
 /**
  * cgroup_taskset_for_each - iterate cgroup_taskset
  * @task: the loop cursor
+ * @dst_css: the destination css
  * @tset: taskset to iterate
  *
  * @tset may contain multiple tasks and they may belong to multiple
- * processes.  When there are multiple tasks in @tset, if a task of a
- * process is in @tset, all tasks of the process are in @tset.  Also, all
- * are guaranteed to share the same source and destination csses.
+ * processes.
+ *
+ * On the v2 hierarchy, there may be tasks from multiple processes and they
+ * may not share the source or destination csses.
+ *
+ * On traditional hierarchies, when there are multiple tasks in @tset, if a
+ * task of a process is in @tset, all tasks of the process are in @tset.
+ * Also, all are guaranteed to share the same source and destination csses.
  *
  * Iteration is not in any specific order.
  */
-#define cgroup_taskset_for_each(task, tset)                            \
-       for ((task) = cgroup_taskset_first((tset)); (task);             \
-            (task) = cgroup_taskset_next((tset)))
+#define cgroup_taskset_for_each(task, dst_css, tset)                   \
+       for ((task) = cgroup_taskset_first((tset), &(dst_css));         \
+            (task);                                                    \
+            (task) = cgroup_taskset_next((tset), &(dst_css)))
 
 /**
  * cgroup_taskset_for_each_leader - iterate group leaders in a cgroup_taskset
  * @leader: the loop cursor
+ * @dst_css: the destination css
  * @tset: takset to iterate
  *
  * Iterate threadgroup leaders of @tset.  For single-task migrations, @tset
  * may not contain any.
  */
-#define cgroup_taskset_for_each_leader(leader, tset)                   \
-       for ((leader) = cgroup_taskset_first((tset)); (leader);         \
-            (leader) = cgroup_taskset_next((tset)))                    \
+#define cgroup_taskset_for_each_leader(leader, dst_css, tset)          \
+       for ((leader) = cgroup_taskset_first((tset), &(dst_css));       \
+            (leader);                                                  \
+            (leader) = cgroup_taskset_next((tset), &(dst_css)))        \
                if ((leader) != (leader)->group_leader)                 \
                        ;                                               \
                else
@@ -516,19 +528,6 @@ static inline void pr_cont_cgroup_path(struct cgroup *cgrp)
        pr_cont_kernfs_path(cgrp->kn);
 }
 
-/**
- * cgroup_file_notify - generate a file modified event for a cgroup_file
- * @cfile: target cgroup_file
- *
- * @cfile must have been obtained by setting cftype->file_offset.
- */
-static inline void cgroup_file_notify(struct cgroup_file *cfile)
-{
-       /* might not have been created due to one of the CFTYPE selector flags */
-       if (cfile->kn)
-               kernfs_notify(cfile->kn);
-}
-
 #else /* !CONFIG_CGROUPS */
 
 struct cgroup_subsys_state;
index a8a335b7fce083984c0b05df49e3ff74f7732719..758a029011b11a3d1d2c1acfe9fa171e82a55343 100644 (file)
@@ -197,6 +197,16 @@ static inline struct configfs_subsystem *to_configfs_subsystem(struct config_gro
 int configfs_register_subsystem(struct configfs_subsystem *subsys);
 void configfs_unregister_subsystem(struct configfs_subsystem *subsys);
 
+int configfs_register_group(struct config_group *parent_group,
+                           struct config_group *group);
+void configfs_unregister_group(struct config_group *group);
+
+struct config_group *
+configfs_register_default_group(struct config_group *parent_group,
+                               const char *name,
+                               struct config_item_type *item_type);
+void configfs_unregister_default_group(struct config_group *group);
+
 /* These functions can sleep and can alloc with GFP_KERNEL */
 /* WARNING: These cannot be called underneath configfs callbacks!! */
 int configfs_depend_item(struct configfs_subsystem *subsys, struct config_item *target);
index ef4c5b1a860f5c610c0ee4646aa2b729aa81f71a..177c7680c1a8a81bcc942497ee228c148fbf5a0b 100644 (file)
@@ -77,6 +77,7 @@ struct cpufreq_policy {
        unsigned int            suspend_freq; /* freq to set during suspend */
 
        unsigned int            policy; /* see above */
+       unsigned int            last_policy; /* policy before unplug */
        struct cpufreq_governor *governor; /* see below */
        void                    *governor_data;
        bool                    governor_enabled; /* governor start/stop flag */
index cc92268af89ae02e8a26fe08f671485b2ca67bc3..6ac3cad9aef109171a5882ee2c5afb30e230c8d4 100644 (file)
@@ -27,7 +27,7 @@
 #ifdef __KERNEL__
 
 extern int dns_query(const char *type, const char *name, size_t namelen,
-                    const char *options, char **_result, time_t *_expiry);
+                    const char *options, char **_result, time64_t *_expiry);
 
 #endif /* KERNEL */
 
index 7be22da321f38eb1327bbbcaabddd6cbca131d44..a4cf57cd0f7512d66b15a036cb76114d5bf633e0 100644 (file)
 /* A few generic types ... taken from ses-2 */
 enum enclosure_component_type {
        ENCLOSURE_COMPONENT_DEVICE = 0x01,
+       ENCLOSURE_COMPONENT_CONTROLLER_ELECTRONICS = 0x07,
+       ENCLOSURE_COMPONENT_SCSI_TARGET_PORT = 0x14,
+       ENCLOSURE_COMPONENT_SCSI_INITIATOR_PORT = 0x15,
        ENCLOSURE_COMPONENT_ARRAY_DEVICE = 0x17,
+       ENCLOSURE_COMPONENT_SAS_EXPANDER = 0x18,
 };
 
 /* ses-2 common element status */
index 6523109e136dfa6c2ca16ceab13cc637a13339a5..8942af0813e38cc267d4efbcef6e737f32fc7def 100644 (file)
@@ -271,7 +271,7 @@ static inline int gfpflags_to_migratetype(const gfp_t gfp_flags)
 
 static inline bool gfpflags_allow_blocking(const gfp_t gfp_flags)
 {
-       return gfp_flags & __GFP_DIRECT_RECLAIM;
+       return (bool __force)(gfp_flags & __GFP_DIRECT_RECLAIM);
 }
 
 #ifdef CONFIG_HIGHMEM
index 0ef2a97ccdb50bc83baaf727f37d2fa034eea036..402753bccafa37b4ec1e597902f608548fbdbd22 100644 (file)
@@ -227,7 +227,7 @@ struct ipv6_pinfo {
        struct ipv6_ac_socklist *ipv6_ac_list;
        struct ipv6_fl_socklist __rcu *ipv6_fl_list;
 
-       struct ipv6_txoptions   *opt;
+       struct ipv6_txoptions __rcu     *opt;
        struct sk_buff          *pktoptions;
        struct sk_buff          *rxpmtu;
        struct inet6_cork       cork;
index c9ae0c6ec050569fc592b6f07b3ce1fa052bcc59..d5d798b35c1f6c105c81d0993bce6140bc4fc83b 100644 (file)
@@ -330,6 +330,7 @@ struct rdists {
 };
 
 struct irq_domain;
+struct device_node;
 int its_cpu_init(void);
 int its_init(struct device_node *node, struct rdists *rdists,
             struct irq_domain *domain);
index 8dde55974f186bca7c1488866aaacdd805c347b3..0536524bb9eb6467013a51a70ed28b576494e649 100644 (file)
@@ -5,7 +5,7 @@
  * Jump label support
  *
  * Copyright (C) 2009-2012 Jason Baron <jbaron@redhat.com>
- * Copyright (C) 2011-2012 Peter Zijlstra <pzijlstr@redhat.com>
+ * Copyright (C) 2011-2012 Red Hat, Inc., Peter Zijlstra
  *
  * DEPRECATED API:
  *
index d0a1f99e24e3eb43219e9f8b8aad400c1cc867a9..4894c6888bc6cfb95e50d43366784769faf9b281 100644 (file)
@@ -25,7 +25,7 @@
 
 #ifdef CONFIG_DEBUG_KMEMLEAK
 
-extern void kmemleak_init(void) __ref;
+extern void kmemleak_init(void) __init;
 extern void kmemleak_alloc(const void *ptr, size_t size, int min_count,
                           gfp_t gfp) __ref;
 extern void kmemleak_alloc_percpu(const void __percpu *ptr, size_t size,
index 484604d184be7380807868d9a12edc80e9064db3..e15828fd71f1b589780b933549e3b07c9652c1e9 100644 (file)
@@ -19,7 +19,6 @@
 #include <linux/atomic.h>
 #include <linux/kernel.h>
 #include <linux/mutex.h>
-#include <linux/spinlock.h>
 
 struct kref {
        atomic_t refcount;
@@ -99,38 +98,6 @@ static inline int kref_put(struct kref *kref, void (*release)(struct kref *kref)
        return kref_sub(kref, 1, release);
 }
 
-/**
- * kref_put_spinlock_irqsave - decrement refcount for object.
- * @kref: object.
- * @release: pointer to the function that will clean up the object when the
- *          last reference to the object is released.
- *          This pointer is required, and it is not acceptable to pass kfree
- *          in as this function.
- * @lock: lock to take in release case
- *
- * Behaves identical to kref_put with one exception.  If the reference count
- * drops to zero, the lock will be taken atomically wrt dropping the reference
- * count.  The release function has to call spin_unlock() without _irqrestore.
- */
-static inline int kref_put_spinlock_irqsave(struct kref *kref,
-               void (*release)(struct kref *kref),
-               spinlock_t *lock)
-{
-       unsigned long flags;
-
-       WARN_ON(release == NULL);
-       if (atomic_add_unless(&kref->refcount, -1, 1))
-               return 0;
-       spin_lock_irqsave(lock, flags);
-       if (atomic_dec_and_test(&kref->refcount)) {
-               release(kref);
-               local_irq_restore(flags);
-               return 1;
-       }
-       spin_unlock_irqrestore(lock, flags);
-       return 0;
-}
-
 static inline int kref_put_mutex(struct kref *kref,
                                 void (*release)(struct kref *kref),
                                 struct mutex *lock)
index 5706a2108f0a67826ed644dce761edd21a6a05c0..c923350ca20a5a53453576f360e52498de232abe 100644 (file)
@@ -460,6 +460,17 @@ static inline struct kvm_vcpu *kvm_get_vcpu(struct kvm *kvm, int i)
             (vcpup = kvm_get_vcpu(kvm, idx)) != NULL; \
             idx++)
 
+static inline struct kvm_vcpu *kvm_get_vcpu_by_id(struct kvm *kvm, int id)
+{
+       struct kvm_vcpu *vcpu;
+       int i;
+
+       kvm_for_each_vcpu(i, vcpu, kvm)
+               if (vcpu->vcpu_id == id)
+                       return vcpu;
+       return NULL;
+}
+
 #define kvm_for_each_memslot(memslot, slots)   \
        for (memslot = &slots->memslots[0];     \
              memslot < slots->memslots + KVM_MEM_SLOTS_NUM && memslot->npages;\
index 83577f8fd15bcd0f8693ef6a1a2a9fb216b32b2b..600c1e0626a5ff6c91df3a0b2f2fcf0ef485fedf 100644 (file)
@@ -210,6 +210,7 @@ enum {
        ATA_FLAG_SLAVE_POSS     = (1 << 0), /* host supports slave dev */
                                            /* (doesn't imply presence) */
        ATA_FLAG_SATA           = (1 << 1),
+       ATA_FLAG_NO_LOG_PAGE    = (1 << 5), /* do not issue log page read */
        ATA_FLAG_NO_ATAPI       = (1 << 6), /* No ATAPI support */
        ATA_FLAG_PIO_DMA        = (1 << 7), /* PIO cmds via DMA */
        ATA_FLAG_PIO_LBA48      = (1 << 8), /* Host DMA engine is LBA28 only */
index 69c9057e1ab89330b1ed22cd0681bf5440ce0096..034117b3be5f7d91e5e869ea9e856f51964ebac6 100644 (file)
@@ -50,15 +50,21 @@ enum {
        NVM_IO_DUAL_ACCESS      = 0x1,
        NVM_IO_QUAD_ACCESS      = 0x2,
 
+       /* NAND Access Modes */
        NVM_IO_SUSPEND          = 0x80,
        NVM_IO_SLC_MODE         = 0x100,
        NVM_IO_SCRAMBLE_DISABLE = 0x200,
+
+       /* Block Types */
+       NVM_BLK_T_FREE          = 0x0,
+       NVM_BLK_T_BAD           = 0x1,
+       NVM_BLK_T_DEV           = 0x2,
+       NVM_BLK_T_HOST          = 0x4,
 };
 
 struct nvm_id_group {
        u8      mtype;
        u8      fmtype;
-       u16     res16;
        u8      num_ch;
        u8      num_lun;
        u8      num_pln;
@@ -74,9 +80,9 @@ struct nvm_id_group {
        u32     tbet;
        u32     tbem;
        u32     mpos;
+       u32     mccap;
        u16     cpar;
-       u8      res[913];
-} __packed;
+};
 
 struct nvm_addr_format {
        u8      ch_offset;
@@ -91,19 +97,15 @@ struct nvm_addr_format {
        u8      pg_len;
        u8      sect_offset;
        u8      sect_len;
-       u8      res[4];
 };
 
 struct nvm_id {
        u8      ver_id;
        u8      vmnt;
        u8      cgrps;
-       u8      res[5];
        u32     cap;
        u32     dom;
        struct nvm_addr_format ppaf;
-       u8      ppat;
-       u8      resv[224];
        struct nvm_id_group groups[4];
 } __packed;
 
@@ -123,39 +125,28 @@ struct nvm_tgt_instance {
 #define NVM_VERSION_MINOR 0
 #define NVM_VERSION_PATCH 0
 
-#define NVM_SEC_BITS (8)
-#define NVM_PL_BITS  (6)
-#define NVM_PG_BITS  (16)
 #define NVM_BLK_BITS (16)
-#define NVM_LUN_BITS (10)
+#define NVM_PG_BITS  (16)
+#define NVM_SEC_BITS (8)
+#define NVM_PL_BITS  (8)
+#define NVM_LUN_BITS (8)
 #define NVM_CH_BITS  (8)
 
 struct ppa_addr {
+       /* Generic structure for all addresses */
        union {
-               /* Channel-based PPA format in nand 4x2x2x2x8x10 */
-               struct {
-                       u64 ch          : 4;
-                       u64 sec         : 2; /* 4 sectors per page */
-                       u64 pl          : 2; /* 4 planes per LUN */
-                       u64 lun         : 2; /* 4 LUNs per channel */
-                       u64 pg          : 8; /* 256 pages per block */
-                       u64 blk         : 10;/* 1024 blocks per plane */
-                       u64 resved              : 36;
-               } chnl;
-
-               /* Generic structure for all addresses */
                struct {
+                       u64 blk         : NVM_BLK_BITS;
+                       u64 pg          : NVM_PG_BITS;
                        u64 sec         : NVM_SEC_BITS;
                        u64 pl          : NVM_PL_BITS;
-                       u64 pg          : NVM_PG_BITS;
-                       u64 blk         : NVM_BLK_BITS;
                        u64 lun         : NVM_LUN_BITS;
                        u64 ch          : NVM_CH_BITS;
                } g;
 
                u64 ppa;
        };
-} __packed;
+};
 
 struct nvm_rq {
        struct nvm_tgt_instance *ins;
@@ -191,18 +182,18 @@ static inline void *nvm_rq_to_pdu(struct nvm_rq *rqdata)
 struct nvm_block;
 
 typedef int (nvm_l2p_update_fn)(u64, u32, __le64 *, void *);
-typedef int (nvm_bb_update_fn)(u32, void *, unsigned int, void *);
-typedef int (nvm_id_fn)(struct request_queue *, struct nvm_id *);
-typedef int (nvm_get_l2p_tbl_fn)(struct request_queue *, u64, u32,
+typedef int (nvm_bb_update_fn)(struct ppa_addr, int, u8 *, void *);
+typedef int (nvm_id_fn)(struct nvm_dev *, struct nvm_id *);
+typedef int (nvm_get_l2p_tbl_fn)(struct nvm_dev *, u64, u32,
                                nvm_l2p_update_fn *, void *);
-typedef int (nvm_op_bb_tbl_fn)(struct request_queue *, int, unsigned int,
+typedef int (nvm_op_bb_tbl_fn)(struct nvm_dev *, struct ppa_addr, int,
                                nvm_bb_update_fn *, void *);
-typedef int (nvm_op_set_bb_fn)(struct request_queue *, struct nvm_rq *, int);
-typedef int (nvm_submit_io_fn)(struct request_queue *, struct nvm_rq *);
-typedef int (nvm_erase_blk_fn)(struct request_queue *, struct nvm_rq *);
-typedef void *(nvm_create_dma_pool_fn)(struct request_queue *, char *);
+typedef int (nvm_op_set_bb_fn)(struct nvm_dev *, struct nvm_rq *, int);
+typedef int (nvm_submit_io_fn)(struct nvm_dev *, struct nvm_rq *);
+typedef int (nvm_erase_blk_fn)(struct nvm_dev *, struct nvm_rq *);
+typedef void *(nvm_create_dma_pool_fn)(struct nvm_dev *, char *);
 typedef void (nvm_destroy_dma_pool_fn)(void *);
-typedef void *(nvm_dev_dma_alloc_fn)(struct request_queue *, void *, gfp_t,
+typedef void *(nvm_dev_dma_alloc_fn)(struct nvm_dev *, void *, gfp_t,
                                                                dma_addr_t *);
 typedef void (nvm_dev_dma_free_fn)(void *, void*, dma_addr_t);
 
@@ -210,7 +201,7 @@ struct nvm_dev_ops {
        nvm_id_fn               *identity;
        nvm_get_l2p_tbl_fn      *get_l2p_tbl;
        nvm_op_bb_tbl_fn        *get_bb_tbl;
-       nvm_op_set_bb_fn        *set_bb;
+       nvm_op_set_bb_fn        *set_bb_tbl;
 
        nvm_submit_io_fn        *submit_io;
        nvm_erase_blk_fn        *erase_block;
@@ -220,7 +211,7 @@ struct nvm_dev_ops {
        nvm_dev_dma_alloc_fn    *dev_dma_alloc;
        nvm_dev_dma_free_fn     *dev_dma_free;
 
-       uint8_t                 max_phys_sect;
+       unsigned int            max_phys_sect;
 };
 
 struct nvm_lun {
@@ -229,7 +220,9 @@ struct nvm_lun {
        int lun_id;
        int chnl_id;
 
+       unsigned int nr_inuse_blocks;   /* Number of used blocks */
        unsigned int nr_free_blocks;    /* Number of unused blocks */
+       unsigned int nr_bad_blocks;     /* Number of bad blocks */
        struct nvm_block *blocks;
 
        spinlock_t lock;
@@ -263,8 +256,7 @@ struct nvm_dev {
        int blks_per_lun;
        int sec_size;
        int oob_size;
-       int addr_mode;
-       struct nvm_addr_format addr_format;
+       struct nvm_addr_format ppaf;
 
        /* Calculated/Cached values. These do not reflect the actual usable
         * blocks at run-time.
@@ -290,118 +282,45 @@ struct nvm_dev {
        char name[DISK_NAME_LEN];
 };
 
-/* fallback conversion */
-static struct ppa_addr __generic_to_linear_addr(struct nvm_dev *dev,
-                                                       struct ppa_addr r)
+static inline struct ppa_addr generic_to_dev_addr(struct nvm_dev *dev,
+                                               struct ppa_addr r)
 {
        struct ppa_addr l;
 
-       l.ppa = r.g.sec +
-               r.g.pg  * dev->sec_per_pg +
-               r.g.blk * (dev->pgs_per_blk *
-                               dev->sec_per_pg) +
-               r.g.lun * (dev->blks_per_lun *
-                               dev->pgs_per_blk *
-                               dev->sec_per_pg) +
-               r.g.ch * (dev->blks_per_lun *
-                               dev->pgs_per_blk *
-                               dev->luns_per_chnl *
-                               dev->sec_per_pg);
+       l.ppa = ((u64)r.g.blk) << dev->ppaf.blk_offset;
+       l.ppa |= ((u64)r.g.pg) << dev->ppaf.pg_offset;
+       l.ppa |= ((u64)r.g.sec) << dev->ppaf.sect_offset;
+       l.ppa |= ((u64)r.g.pl) << dev->ppaf.pln_offset;
+       l.ppa |= ((u64)r.g.lun) << dev->ppaf.lun_offset;
+       l.ppa |= ((u64)r.g.ch) << dev->ppaf.ch_offset;
 
        return l;
 }
 
-/* fallback conversion */
-static struct ppa_addr __linear_to_generic_addr(struct nvm_dev *dev,
-                                                       struct ppa_addr r)
+static inline struct ppa_addr dev_to_generic_addr(struct nvm_dev *dev,
+                                               struct ppa_addr r)
 {
        struct ppa_addr l;
-       int secs, pgs, blks, luns;
-       sector_t ppa = r.ppa;
-
-       l.ppa = 0;
-
-       div_u64_rem(ppa, dev->sec_per_pg, &secs);
-       l.g.sec = secs;
 
-       sector_div(ppa, dev->sec_per_pg);
-       div_u64_rem(ppa, dev->sec_per_blk, &pgs);
-       l.g.pg = pgs;
-
-       sector_div(ppa, dev->pgs_per_blk);
-       div_u64_rem(ppa, dev->blks_per_lun, &blks);
-       l.g.blk = blks;
-
-       sector_div(ppa, dev->blks_per_lun);
-       div_u64_rem(ppa, dev->luns_per_chnl, &luns);
-       l.g.lun = luns;
-
-       sector_div(ppa, dev->luns_per_chnl);
-       l.g.ch = ppa;
-
-       return l;
-}
-
-static struct ppa_addr __generic_to_chnl_addr(struct ppa_addr r)
-{
-       struct ppa_addr l;
-
-       l.ppa = 0;
-
-       l.chnl.sec = r.g.sec;
-       l.chnl.pl = r.g.pl;
-       l.chnl.pg = r.g.pg;
-       l.chnl.blk = r.g.blk;
-       l.chnl.lun = r.g.lun;
-       l.chnl.ch = r.g.ch;
-
-       return l;
-}
-
-static struct ppa_addr __chnl_to_generic_addr(struct ppa_addr r)
-{
-       struct ppa_addr l;
-
-       l.ppa = 0;
-
-       l.g.sec = r.chnl.sec;
-       l.g.pl = r.chnl.pl;
-       l.g.pg = r.chnl.pg;
-       l.g.blk = r.chnl.blk;
-       l.g.lun = r.chnl.lun;
-       l.g.ch = r.chnl.ch;
+       /*
+        * (r.ppa << X offset) & X len bitmask. X eq. blk, pg, etc.
+        */
+       l.g.blk = (r.ppa >> dev->ppaf.blk_offset) &
+                                       (((1 << dev->ppaf.blk_len) - 1));
+       l.g.pg |= (r.ppa >> dev->ppaf.pg_offset) &
+                                       (((1 << dev->ppaf.pg_len) - 1));
+       l.g.sec |= (r.ppa >> dev->ppaf.sect_offset) &
+                                       (((1 << dev->ppaf.sect_len) - 1));
+       l.g.pl |= (r.ppa >> dev->ppaf.pln_offset) &
+                                       (((1 << dev->ppaf.pln_len) - 1));
+       l.g.lun |= (r.ppa >> dev->ppaf.lun_offset) &
+                                       (((1 << dev->ppaf.lun_len) - 1));
+       l.g.ch |= (r.ppa >> dev->ppaf.ch_offset) &
+                                       (((1 << dev->ppaf.ch_len) - 1));
 
        return l;
 }
 
-static inline struct ppa_addr addr_to_generic_mode(struct nvm_dev *dev,
-                                               struct ppa_addr gppa)
-{
-       switch (dev->addr_mode) {
-       case NVM_ADDRMODE_LINEAR:
-               return __linear_to_generic_addr(dev, gppa);
-       case NVM_ADDRMODE_CHANNEL:
-               return __chnl_to_generic_addr(gppa);
-       default:
-               BUG();
-       }
-       return gppa;
-}
-
-static inline struct ppa_addr generic_to_addr_mode(struct nvm_dev *dev,
-                                               struct ppa_addr gppa)
-{
-       switch (dev->addr_mode) {
-       case NVM_ADDRMODE_LINEAR:
-               return __generic_to_linear_addr(dev, gppa);
-       case NVM_ADDRMODE_CHANNEL:
-               return __generic_to_chnl_addr(gppa);
-       default:
-               BUG();
-       }
-       return gppa;
-}
-
 static inline int ppa_empty(struct ppa_addr ppa_addr)
 {
        return (ppa_addr.ppa == ADDR_EMPTY);
@@ -468,7 +387,7 @@ typedef int (nvmm_end_io_fn)(struct nvm_rq *, int);
 typedef int (nvmm_erase_blk_fn)(struct nvm_dev *, struct nvm_block *,
                                                                unsigned long);
 typedef struct nvm_lun *(nvmm_get_lun_fn)(struct nvm_dev *, int);
-typedef void (nvmm_free_blocks_print_fn)(struct nvm_dev *);
+typedef void (nvmm_lun_info_print_fn)(struct nvm_dev *);
 
 struct nvmm_type {
        const char *name;
@@ -492,7 +411,7 @@ struct nvmm_type {
        nvmm_get_lun_fn *get_lun;
 
        /* Statistics */
-       nvmm_free_blocks_print_fn *free_blocks_print;
+       nvmm_lun_info_print_fn *lun_info_print;
        struct list_head list;
 };
 
index 70400dc7660f72028cd6ce84cf6ec90b69537137..c57e424d914b70fc5032f9b6d1ec918e8e195c64 100644 (file)
@@ -2,7 +2,7 @@
  * Runtime locking correctness validator
  *
  *  Copyright (C) 2006,2007 Red Hat, Inc., Ingo Molnar <mingo@redhat.com>
- *  Copyright (C) 2007 Red Hat, Inc., Peter Zijlstra <pzijlstr@redhat.com>
+ *  Copyright (C) 2007 Red Hat, Inc., Peter Zijlstra
  *
  * see Documentation/locking/lockdep-design.txt for more details.
  */
index e6982ac3200d65a537f2561bd51c2a0696b62e70..a57f0dfb6db7f2c0e0e268397b261fe8b45efa89 100644 (file)
@@ -16,6 +16,7 @@
 #define MARVELL_PHY_ID_88E1318S                0x01410e90
 #define MARVELL_PHY_ID_88E1116R                0x01410e40
 #define MARVELL_PHY_ID_88E1510         0x01410dd0
+#define MARVELL_PHY_ID_88E1540         0x01410eb0
 #define MARVELL_PHY_ID_88E3016         0x01410e60
 
 /* struct phy_device dev_flags definitions */
index 7501626ab5293414c29df692edb6fa7122871c84..d3133be12d922521e24528480edbdb31659a7007 100644 (file)
@@ -426,6 +426,17 @@ enum {
        MLX4_MAX_FAST_REG_PAGES = 511,
 };
 
+enum {
+       /*
+        * Max wqe size for rdma read is 512 bytes, so this
+        * limits our max_sge_rd as the wqe needs to fit:
+        * - ctrl segment (16 bytes)
+        * - rdma segment (16 bytes)
+        * - scatter elements (16 bytes each)
+        */
+       MLX4_MAX_SGE_RD = (512 - 16 - 16) / 16
+};
+
 enum {
        MLX4_DEV_PMC_SUBTYPE_GUID_INFO   = 0x14,
        MLX4_DEV_PMC_SUBTYPE_PORT_INFO   = 0x15,
index dd2097455a2e3b54cbb69c409bbe8fa7463264ec..1565324eb620cc22931aa93e5a4e0f8b7a332460 100644 (file)
@@ -453,26 +453,28 @@ struct mlx5_ifc_per_protocol_networking_offload_caps_bits {
        u8         lro_cap[0x1];
        u8         lro_psh_flag[0x1];
        u8         lro_time_stamp[0x1];
-       u8         reserved_0[0x6];
+       u8         reserved_0[0x3];
+       u8         self_lb_en_modifiable[0x1];
+       u8         reserved_1[0x2];
        u8         max_lso_cap[0x5];
-       u8         reserved_1[0x4];
+       u8         reserved_2[0x4];
        u8         rss_ind_tbl_cap[0x4];
-       u8         reserved_2[0x3];
+       u8         reserved_3[0x3];
        u8         tunnel_lso_const_out_ip_id[0x1];
-       u8         reserved_3[0x2];
+       u8         reserved_4[0x2];
        u8         tunnel_statless_gre[0x1];
        u8         tunnel_stateless_vxlan[0x1];
 
-       u8         reserved_4[0x20];
+       u8         reserved_5[0x20];
 
-       u8         reserved_5[0x10];
+       u8         reserved_6[0x10];
        u8         lro_min_mss_size[0x10];
 
-       u8         reserved_6[0x120];
+       u8         reserved_7[0x120];
 
        u8         lro_timer_supported_periods[4][0x20];
 
-       u8         reserved_7[0x600];
+       u8         reserved_8[0x600];
 };
 
 struct mlx5_ifc_roce_cap_bits {
@@ -4051,9 +4053,11 @@ struct mlx5_ifc_modify_tis_in_bits {
 };
 
 struct mlx5_ifc_modify_tir_bitmask_bits {
-       u8         reserved[0x20];
+       u8         reserved_0[0x20];
 
-       u8         reserved1[0x1f];
+       u8         reserved_1[0x1b];
+       u8         self_lb_en[0x1];
+       u8         reserved_2[0x3];
        u8         lro[0x1];
 };
 
index 877ef226f90fb3b945831c7e8f9edbabba1e9775..772362adf4713b77be041b6232097c97a7f5aad7 100644 (file)
@@ -1,6 +1,7 @@
 #ifndef LINUX_MM_DEBUG_H
 #define LINUX_MM_DEBUG_H 1
 
+#include <linux/bug.h>
 #include <linux/stringify.h>
 
 struct page;
index 70ac5e28e6b737f7aac7b0b27d929adacf4aad12..0b4ac7da583a8b2dff7983b4602cb9a81887ea86 100644 (file)
@@ -34,8 +34,12 @@ struct inode;
 struct file;
 struct net;
 
-#define SOCK_ASYNC_NOSPACE     0
-#define SOCK_ASYNC_WAITDATA    1
+/* Historically, SOCKWQ_ASYNC_NOSPACE & SOCKWQ_ASYNC_WAITDATA were located
+ * in sock->flags, but moved into sk->sk_wq->flags to be RCU protected.
+ * Eventually all flags will be in sk->sk_wq_flags.
+ */
+#define SOCKWQ_ASYNC_NOSPACE   0
+#define SOCKWQ_ASYNC_WAITDATA  1
 #define SOCK_NOSPACE           2
 #define SOCK_PASSCRED          3
 #define SOCK_PASSSEC           4
@@ -89,6 +93,7 @@ struct socket_wq {
        /* Note: wait MUST be first field of socket_wq */
        wait_queue_head_t       wait;
        struct fasync_struct    *fasync_list;
+       unsigned long           flags; /* %SOCKWQ_ASYNC_NOSPACE, etc */
        struct rcu_head         rcu;
 } ____cacheline_aligned_in_smp;
 
@@ -96,7 +101,7 @@ struct socket_wq {
  *  struct socket - general BSD socket
  *  @state: socket state (%SS_CONNECTED, etc)
  *  @type: socket type (%SOCK_STREAM, etc)
- *  @flags: socket flags (%SOCK_ASYNC_NOSPACE, etc)
+ *  @flags: socket flags (%SOCK_NOSPACE, etc)
  *  @ops: protocol specific socket operations
  *  @file: File back pointer for gc
  *  @sk: internal networking protocol agnostic socket representation
@@ -202,7 +207,7 @@ enum {
        SOCK_WAKE_URG,
 };
 
-int sock_wake_async(struct socket *sk, int how, int band);
+int sock_wake_async(struct socket_wq *sk_wq, int how, int band);
 int sock_register(const struct net_proto_family *fam);
 void sock_unregister(int family);
 int __sock_create(struct net *net, int family, int type, int proto,
index d20891465247dfaa983225ce9336b14c91cb7fab..3143c847bddbca47bed1a324bf85e58283e966a5 100644 (file)
@@ -1398,7 +1398,8 @@ enum netdev_priv_flags {
  *     @dma:           DMA channel
  *     @mtu:           Interface MTU value
  *     @type:          Interface hardware type
- *     @hard_header_len: Hardware header length
+ *     @hard_header_len: Hardware header length, which means that this is the
+ *                       minimum size of a packet.
  *
  *     @needed_headroom: Extra headroom the hardware may need, but not in all
  *                       cases can this be guaranteed
@@ -2068,20 +2069,23 @@ struct pcpu_sw_netstats {
        struct u64_stats_sync   syncp;
 };
 
-#define netdev_alloc_pcpu_stats(type)                          \
-({                                                             \
-       typeof(type) __percpu *pcpu_stats = alloc_percpu(type); \
-       if (pcpu_stats) {                                       \
-               int __cpu;                                      \
-               for_each_possible_cpu(__cpu) {                  \
-                       typeof(type) *stat;                     \
-                       stat = per_cpu_ptr(pcpu_stats, __cpu);  \
-                       u64_stats_init(&stat->syncp);           \
-               }                                               \
-       }                                                       \
-       pcpu_stats;                                             \
+#define __netdev_alloc_pcpu_stats(type, gfp)                           \
+({                                                                     \
+       typeof(type) __percpu *pcpu_stats = alloc_percpu_gfp(type, gfp);\
+       if (pcpu_stats) {                                               \
+               int __cpu;                                              \
+               for_each_possible_cpu(__cpu) {                          \
+                       typeof(type) *stat;                             \
+                       stat = per_cpu_ptr(pcpu_stats, __cpu);          \
+                       u64_stats_init(&stat->syncp);                   \
+               }                                                       \
+       }                                                               \
+       pcpu_stats;                                                     \
 })
 
+#define netdev_alloc_pcpu_stats(type)                                  \
+       __netdev_alloc_pcpu_stats(type, GFP_KERNEL)
+
 #include <linux/notifier.h>
 
 /* netdevice notifier chain. Please remember to update the rtnetlink
@@ -3854,6 +3858,11 @@ static inline bool netif_is_bridge_master(const struct net_device *dev)
        return dev->priv_flags & IFF_EBRIDGE;
 }
 
+static inline bool netif_is_bridge_port(const struct net_device *dev)
+{
+       return dev->priv_flags & IFF_BRIDGE_PORT;
+}
+
 static inline bool netif_is_ovs_master(const struct net_device *dev)
 {
        return dev->priv_flags & IFF_OPENVSWITCH;
index 48bb01edcf3047bb70b70188430080c5970583a8..0e1f433cc4b78537c24e0e5f410894655d90aa0e 100644 (file)
@@ -421,7 +421,7 @@ extern void ip_set_free(void *members);
 extern int ip_set_get_ipaddr4(struct nlattr *nla,  __be32 *ipaddr);
 extern int ip_set_get_ipaddr6(struct nlattr *nla, union nf_inet_addr *ipaddr);
 extern size_t ip_set_elem_len(struct ip_set *set, struct nlattr *tb[],
-                             size_t len);
+                             size_t len, size_t align);
 extern int ip_set_get_extensions(struct ip_set *set, struct nlattr *tb[],
                                 struct ip_set_ext *ext);
 
index 249d1bb01e03b0367f56f251c02269b24be0dac6..5646b24bfc64040d595b6fd4109e0caadc21494d 100644 (file)
@@ -14,7 +14,7 @@ struct nfnl_callback {
        int (*call_rcu)(struct sock *nl, struct sk_buff *skb, 
                    const struct nlmsghdr *nlh,
                    const struct nlattr * const cda[]);
-       int (*call_batch)(struct sock *nl, struct sk_buff *skb,
+       int (*call_batch)(struct net *net, struct sock *nl, struct sk_buff *skb,
                          const struct nlmsghdr *nlh,
                          const struct nlattr * const cda[]);
        const struct nla_policy *policy;        /* netlink attribute policy */
index 187feabe557c379b2a78bb4467623722e7ed4996..5fcd375ef175b1a4e4870e99eb54d729a343b194 100644 (file)
@@ -5,10 +5,13 @@
 #include <linux/netdevice.h>
 
 #ifdef CONFIG_NETFILTER_INGRESS
-static inline int nf_hook_ingress_active(struct sk_buff *skb)
+static inline bool nf_hook_ingress_active(const struct sk_buff *skb)
 {
-       return nf_hook_list_active(&skb->dev->nf_hooks_ingress,
-                                  NFPROTO_NETDEV, NF_NETDEV_INGRESS);
+#ifdef HAVE_JUMP_LABEL
+       if (!static_key_false(&nf_hooks_needed[NFPROTO_NETDEV][NF_NETDEV_INGRESS]))
+               return false;
+#endif
+       return !list_empty(&skb->dev->nf_hooks_ingress);
 }
 
 static inline int nf_hook_ingress(struct sk_buff *skb)
@@ -16,8 +19,8 @@ static inline int nf_hook_ingress(struct sk_buff *skb)
        struct nf_hook_state state;
 
        nf_hook_state_init(&state, &skb->dev->nf_hooks_ingress,
-                          NF_NETDEV_INGRESS, INT_MIN, NFPROTO_NETDEV, NULL,
-                          skb->dev, NULL, dev_net(skb->dev), NULL);
+                          NF_NETDEV_INGRESS, INT_MIN, NFPROTO_NETDEV,
+                          skb->dev, NULL, NULL, dev_net(skb->dev), NULL);
        return nf_hook_slow(skb, &state);
 }
 
index 570d630f98ae53a34b4c9420f037d87c4b97a3cc..11bbae44f4cbf91dd3ed62aa9d2e1849b14a8839 100644 (file)
@@ -251,6 +251,7 @@ struct nfs4_layoutget {
        struct nfs4_layoutget_res res;
        struct rpc_cred *cred;
        gfp_t gfp_flags;
+       long timeout;
 };
 
 struct nfs4_getdeviceinfo_args {
index 36112cdd665a7f881693105e2cbfd4737e0a9881..b90d8ec57c1fb43fcc182b59e3d3267c79c68865 100644 (file)
@@ -80,7 +80,7 @@ static inline int of_dma_router_register(struct device_node *np,
 static inline struct dma_chan *of_dma_request_slave_channel(struct device_node *np,
                                                     const char *name)
 {
-       return NULL;
+       return ERR_PTR(-ENODEV);
 }
 
 static inline struct dma_chan *of_dma_simple_xlate(struct of_phandle_args *dma_spec,
index 039f2eec49ced0ae1c638354d1a34c924cebde51..1e0deb8e849458ca179c1df4734bb24f0e4cd748 100644 (file)
@@ -46,12 +46,14 @@ extern int of_irq_get(struct device_node *dev, int index);
 extern int of_irq_get_byname(struct device_node *dev, const char *name);
 extern int of_irq_to_resource_table(struct device_node *dev,
                struct resource *res, int nr_irqs);
+extern struct device_node *of_irq_find_parent(struct device_node *child);
 extern struct irq_domain *of_msi_get_domain(struct device *dev,
                                            struct device_node *np,
                                            enum irq_domain_bus_token token);
 extern struct irq_domain *of_msi_map_get_device_domain(struct device *dev,
                                                       u32 rid);
 extern void of_msi_configure(struct device *dev, struct device_node *np);
+u32 of_msi_map_rid(struct device *dev, struct device_node *msi_np, u32 rid_in);
 #else
 static inline int of_irq_count(struct device_node *dev)
 {
@@ -70,6 +72,11 @@ static inline int of_irq_to_resource_table(struct device_node *dev,
 {
        return 0;
 }
+static inline void *of_irq_find_parent(struct device_node *child)
+{
+       return NULL;
+}
+
 static inline struct irq_domain *of_msi_get_domain(struct device *dev,
                                                   struct device_node *np,
                                                   enum irq_domain_bus_token token)
@@ -84,6 +91,11 @@ static inline struct irq_domain *of_msi_map_get_device_domain(struct device *dev
 static inline void of_msi_configure(struct device *dev, struct device_node *np)
 {
 }
+static inline u32 of_msi_map_rid(struct device *dev,
+                                struct device_node *msi_np, u32 rid_in)
+{
+       return rid_in;
+}
 #endif
 
 #if defined(CONFIG_OF_IRQ) || defined(CONFIG_SPARC)
@@ -93,7 +105,6 @@ static inline void of_msi_configure(struct device *dev, struct device_node *np)
  * so declare it here regardless of the CONFIG_OF_IRQ setting.
  */
 extern unsigned int irq_of_parse_and_map(struct device_node *node, int index);
-u32 of_msi_map_rid(struct device *dev, struct device_node *msi_np, u32 rid_in);
 
 #else /* !CONFIG_OF && !CONFIG_SPARC */
 static inline unsigned int irq_of_parse_and_map(struct device_node *dev,
@@ -101,12 +112,6 @@ static inline unsigned int irq_of_parse_and_map(struct device_node *dev,
 {
        return 0;
 }
-
-static inline u32 of_msi_map_rid(struct device *dev,
-                                struct device_node *msi_np, u32 rid_in)
-{
-       return rid_in;
-}
 #endif /* !CONFIG_OF */
 
 #endif /* __OF_IRQ_H */
index e828e7b4afec67a4b9f083cfa65c2ff3cffe8571..6ae25aae88fd1254f40227341ca20b73a2e08ce2 100644 (file)
@@ -412,9 +412,18 @@ struct pci_host_bridge {
        void (*release_fn)(struct pci_host_bridge *);
        void *release_data;
        unsigned int ignore_reset_delay:1;      /* for entire hierarchy */
+       /* Resource alignment requirements */
+       resource_size_t (*align_resource)(struct pci_dev *dev,
+                       const struct resource *res,
+                       resource_size_t start,
+                       resource_size_t size,
+                       resource_size_t align);
 };
 
 #define        to_pci_host_bridge(n) container_of(n, struct pci_host_bridge, dev)
+
+struct pci_host_bridge *pci_find_host_bridge(struct pci_bus *bus);
+
 void pci_set_host_bridge_release(struct pci_host_bridge *bridge,
                     void (*release_fn)(struct pci_host_bridge *),
                     void *release_data);
index d841d33bcdc9c370742db6408e1f979594d37099..f9828a48f16addab4737683f3c8345ab87e52a0a 100644 (file)
@@ -697,9 +697,11 @@ struct perf_cgroup {
  * if there is no cgroup event for the current CPU context.
  */
 static inline struct perf_cgroup *
-perf_cgroup_from_task(struct task_struct *task)
+perf_cgroup_from_task(struct task_struct *task, struct perf_event_context *ctx)
 {
-       return container_of(task_css(task, perf_event_cgrp_id),
+       return container_of(task_css_check(task, perf_event_cgrp_id,
+                                          ctx ? lockdep_is_held(&ctx->lock)
+                                              : true),
                            struct perf_cgroup, css);
 }
 #endif /* CONFIG_CGROUP_PERF */
index 5e0bc779e6c531b6141a4c0c8dca9d14c977a8e7..15bf56ee8af7d21d307c924df06d0f443d835975 100644 (file)
@@ -13,6 +13,9 @@
  */
 #define S3C64XX_AC97_GPD  0
 #define S3C64XX_AC97_GPE  1
+
+#include <linux/dmaengine.h>
+
 extern void s3c64xx_ac97_setup_gpio(int);
 
 struct samsung_i2s {
@@ -39,6 +42,11 @@ struct samsung_i2s {
  */
 struct s3c_audio_pdata {
        int (*cfg_gpio)(struct platform_device *);
+       dma_filter_fn dma_filter;
+       void *dma_playback;
+       void *dma_capture;
+       void *dma_play_sec;
+       void *dma_capture_mic;
        union {
                struct samsung_i2s i2s;
        } type;
index e2878baeb90e8c804a27d90c37c7d79f14e95942..4299f4ba03bdde8a8eae4209f1cf537b63f0171f 100644 (file)
@@ -72,7 +72,7 @@ struct edma_soc_info {
        struct edma_rsv_info    *rsv;
 
        /* List of channels allocated for memcpy, terminated with -1 */
-       s16                     *memcpy_channels;
+       s32                     *memcpy_channels;
 
        s8      (*queue_priority_mapping)[2];
        const s16       (*xbar_chans)[2];
index 5440f64d2942a7957e0831a15918fc070ac63193..21221338ad18018b9b8c479efe1f938b67e6f685 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * FLoating proportions
  *
- *  Copyright (C) 2007 Red Hat, Inc., Peter Zijlstra <pzijlstr@redhat.com>
+ *  Copyright (C) 2007 Red Hat, Inc., Peter Zijlstra
  *
  * This file contains the public data structure and API definitions.
  */
index 6a4347639c0329235a735d723a564acecf59f022..1d1ba2c5ee7a26f6a35b1835c016a6bd7755fcd8 100644 (file)
@@ -9,6 +9,8 @@
 #ifndef __COMMON_HSI__
 #define __COMMON_HSI__
 
+#define CORE_SPQE_PAGE_SIZE_BYTES                       4096
+
 #define FW_MAJOR_VERSION       8
 #define FW_MINOR_VERSION       4
 #define FW_REVISION_VERSION    2
index b920c3605c462ef0bdb9c8ba0c8cd9d8957addb7..41b9049b57e2475575d076b4f0728234618ce07e 100644 (file)
@@ -111,7 +111,8 @@ static inline u16 qed_chain_get_elem_left(struct qed_chain *p_chain)
        used = ((u32)0x10000u + (u32)(p_chain->prod_idx)) -
                (u32)p_chain->cons_idx;
        if (p_chain->mode == QED_CHAIN_MODE_NEXT_PTR)
-               used -= (used / p_chain->elem_per_page);
+               used -= p_chain->prod_idx / p_chain->elem_per_page -
+                       p_chain->cons_idx / p_chain->elem_per_page;
 
        return p_chain->capacity - used;
 }
index 843ceca9a21e5f1327fa5c82fa5f3089c5ebab23..e50b31d18462c02e5362e84bdeac4f0ab4e0f1ea 100644 (file)
@@ -19,6 +19,7 @@
 
 #include <linux/atomic.h>
 #include <linux/compiler.h>
+#include <linux/err.h>
 #include <linux/errno.h>
 #include <linux/jhash.h>
 #include <linux/list_nulls.h>
@@ -339,10 +340,11 @@ static inline int lockdep_rht_bucket_is_held(const struct bucket_table *tbl,
 int rhashtable_init(struct rhashtable *ht,
                    const struct rhashtable_params *params);
 
-int rhashtable_insert_slow(struct rhashtable *ht, const void *key,
-                          struct rhash_head *obj,
-                          struct bucket_table *old_tbl);
-int rhashtable_insert_rehash(struct rhashtable *ht);
+struct bucket_table *rhashtable_insert_slow(struct rhashtable *ht,
+                                           const void *key,
+                                           struct rhash_head *obj,
+                                           struct bucket_table *old_tbl);
+int rhashtable_insert_rehash(struct rhashtable *ht, struct bucket_table *tbl);
 
 int rhashtable_walk_init(struct rhashtable *ht, struct rhashtable_iter *iter);
 void rhashtable_walk_exit(struct rhashtable_iter *iter);
@@ -598,9 +600,11 @@ restart:
 
        new_tbl = rht_dereference_rcu(tbl->future_tbl, ht);
        if (unlikely(new_tbl)) {
-               err = rhashtable_insert_slow(ht, key, obj, new_tbl);
-               if (err == -EAGAIN)
+               tbl = rhashtable_insert_slow(ht, key, obj, new_tbl);
+               if (!IS_ERR_OR_NULL(tbl))
                        goto slow_path;
+
+               err = PTR_ERR(tbl);
                goto out;
        }
 
@@ -611,7 +615,7 @@ restart:
        if (unlikely(rht_grow_above_100(ht, tbl))) {
 slow_path:
                spin_unlock_bh(lock);
-               err = rhashtable_insert_rehash(ht);
+               err = rhashtable_insert_rehash(ht, tbl);
                rcu_read_unlock();
                if (err)
                        return err;
index 80af3cd35ae4edf30dc05e1148cf8ee75033fcb3..72ce932c69b28b3bf240e9782d00c5555bf6a97d 100644 (file)
@@ -71,7 +71,7 @@ struct scpi_ops {
        int (*sensor_get_value)(u16, u32 *);
 };
 
-#if IS_ENABLED(CONFIG_ARM_SCPI_PROTOCOL)
+#if IS_REACHABLE(CONFIG_ARM_SCPI_PROTOCOL)
 struct scpi_ops *get_scpi_ops(void);
 #else
 static inline struct scpi_ops *get_scpi_ops(void) { return NULL; }
index ab1e0392b5ac1ce89c80dc2bf0e4e4ccc7a736bd..92557bbce7e7b9a3d9c6c6ed4c4d4f54ff7ff9e5 100644 (file)
@@ -239,7 +239,6 @@ extern int sigprocmask(int, sigset_t *, sigset_t *);
 extern void set_current_blocked(sigset_t *);
 extern void __set_current_blocked(const sigset_t *);
 extern int show_unhandled_signals;
-extern int sigsuspend(sigset_t *);
 
 struct sigaction {
 #ifndef __ARCH_HAS_IRIX_SIGACTION
index 7c82e3b307a332e27204b0d3316300d62f8990a0..2037a861e3679910152a98ba98a667b395c6773c 100644 (file)
@@ -157,6 +157,24 @@ size_t ksize(const void *);
 #define ARCH_KMALLOC_MINALIGN __alignof__(unsigned long long)
 #endif
 
+/*
+ * Setting ARCH_SLAB_MINALIGN in arch headers allows a different alignment.
+ * Intended for arches that get misalignment faults even for 64 bit integer
+ * aligned buffers.
+ */
+#ifndef ARCH_SLAB_MINALIGN
+#define ARCH_SLAB_MINALIGN __alignof__(unsigned long long)
+#endif
+
+/*
+ * kmalloc and friends return ARCH_KMALLOC_MINALIGN aligned
+ * pointers. kmem_cache_alloc and friends return ARCH_SLAB_MINALIGN
+ * aligned pointers.
+ */
+#define __assume_kmalloc_alignment __assume_aligned(ARCH_KMALLOC_MINALIGN)
+#define __assume_slab_alignment __assume_aligned(ARCH_SLAB_MINALIGN)
+#define __assume_page_alignment __assume_aligned(PAGE_SIZE)
+
 /*
  * Kmalloc array related definitions
  */
@@ -286,8 +304,8 @@ static __always_inline int kmalloc_index(size_t size)
 }
 #endif /* !CONFIG_SLOB */
 
-void *__kmalloc(size_t size, gfp_t flags);
-void *kmem_cache_alloc(struct kmem_cache *, gfp_t flags);
+void *__kmalloc(size_t size, gfp_t flags) __assume_kmalloc_alignment;
+void *kmem_cache_alloc(struct kmem_cache *, gfp_t flags) __assume_slab_alignment;
 void kmem_cache_free(struct kmem_cache *, void *);
 
 /*
@@ -298,11 +316,11 @@ void kmem_cache_free(struct kmem_cache *, void *);
  * Note that interrupts must be enabled when calling these functions.
  */
 void kmem_cache_free_bulk(struct kmem_cache *, size_t, void **);
-bool kmem_cache_alloc_bulk(struct kmem_cache *, gfp_t, size_t, void **);
+int kmem_cache_alloc_bulk(struct kmem_cache *, gfp_t, size_t, void **);
 
 #ifdef CONFIG_NUMA
-void *__kmalloc_node(size_t size, gfp_t flags, int node);
-void *kmem_cache_alloc_node(struct kmem_cache *, gfp_t flags, int node);
+void *__kmalloc_node(size_t size, gfp_t flags, int node) __assume_kmalloc_alignment;
+void *kmem_cache_alloc_node(struct kmem_cache *, gfp_t flags, int node) __assume_slab_alignment;
 #else
 static __always_inline void *__kmalloc_node(size_t size, gfp_t flags, int node)
 {
@@ -316,12 +334,12 @@ static __always_inline void *kmem_cache_alloc_node(struct kmem_cache *s, gfp_t f
 #endif
 
 #ifdef CONFIG_TRACING
-extern void *kmem_cache_alloc_trace(struct kmem_cache *, gfp_t, size_t);
+extern void *kmem_cache_alloc_trace(struct kmem_cache *, gfp_t, size_t) __assume_slab_alignment;
 
 #ifdef CONFIG_NUMA
 extern void *kmem_cache_alloc_node_trace(struct kmem_cache *s,
                                           gfp_t gfpflags,
-                                          int node, size_t size);
+                                          int node, size_t size) __assume_slab_alignment;
 #else
 static __always_inline void *
 kmem_cache_alloc_node_trace(struct kmem_cache *s,
@@ -354,10 +372,10 @@ kmem_cache_alloc_node_trace(struct kmem_cache *s,
 }
 #endif /* CONFIG_TRACING */
 
-extern void *kmalloc_order(size_t size, gfp_t flags, unsigned int order);
+extern void *kmalloc_order(size_t size, gfp_t flags, unsigned int order) __assume_page_alignment;
 
 #ifdef CONFIG_TRACING
-extern void *kmalloc_order_trace(size_t size, gfp_t flags, unsigned int order);
+extern void *kmalloc_order_trace(size_t size, gfp_t flags, unsigned int order) __assume_page_alignment;
 #else
 static __always_inline void *
 kmalloc_order_trace(size_t size, gfp_t flags, unsigned int order)
@@ -482,15 +500,6 @@ static __always_inline void *kmalloc_node(size_t size, gfp_t flags, int node)
        return __kmalloc_node(size, flags, node);
 }
 
-/*
- * Setting ARCH_SLAB_MINALIGN in arch headers allows a different alignment.
- * Intended for arches that get misalignment faults even for 64 bit integer
- * aligned buffers.
- */
-#ifndef ARCH_SLAB_MINALIGN
-#define ARCH_SLAB_MINALIGN __alignof__(unsigned long long)
-#endif
-
 struct memcg_cache_array {
        struct rcu_head rcu;
        struct kmem_cache *entries[0];
index 0adedca24c5bfbd4ca7a25b80641e76e0e638738..0e1b1540597a47253b6a2e5cc3ef1709d4a42992 100644 (file)
@@ -99,7 +99,7 @@ static inline int try_stop_cpus(const struct cpumask *cpumask,
  * grabbing every spinlock (and more).  So the "read" side to such a
  * lock is anything which disables preemption.
  */
-#if defined(CONFIG_STOP_MACHINE) && defined(CONFIG_SMP)
+#if defined(CONFIG_SMP) || defined(CONFIG_HOTPLUG_CPU)
 
 /**
  * stop_machine: freeze the machine on all CPUs and run this function
@@ -118,7 +118,7 @@ int stop_machine(cpu_stop_fn_t fn, void *data, const struct cpumask *cpus);
 
 int stop_machine_from_inactive_cpu(cpu_stop_fn_t fn, void *data,
                                   const struct cpumask *cpus);
-#else   /* CONFIG_STOP_MACHINE && CONFIG_SMP */
+#else  /* CONFIG_SMP || CONFIG_HOTPLUG_CPU */
 
 static inline int stop_machine(cpu_stop_fn_t fn, void *data,
                                 const struct cpumask *cpus)
@@ -137,5 +137,5 @@ static inline int stop_machine_from_inactive_cpu(cpu_stop_fn_t fn, void *data,
        return stop_machine(fn, data, cpus);
 }
 
-#endif /* CONFIG_STOP_MACHINE && CONFIG_SMP */
+#endif /* CONFIG_SMP || CONFIG_HOTPLUG_CPU */
 #endif /* _LINUX_STOP_MACHINE */
index a156b82dd14cbad0b6f2867d07fc883fbc685c1e..c2b66a277e9807de8a224879793c121df63f7d69 100644 (file)
@@ -524,7 +524,7 @@ asmlinkage long sys_chown(const char __user *filename,
 asmlinkage long sys_lchown(const char __user *filename,
                                uid_t user, gid_t group);
 asmlinkage long sys_fchown(unsigned int fd, uid_t user, gid_t group);
-#ifdef CONFIG_UID16
+#ifdef CONFIG_HAVE_UID16
 asmlinkage long sys_chown16(const char __user *filename,
                                old_uid_t user, old_gid_t group);
 asmlinkage long sys_lchown16(const char __user *filename,
index 4014a59828fcba8142e27f6feb1feaf4f64d3171..613c29bd6baf4763e57530b794df843d9cea61ee 100644 (file)
@@ -438,7 +438,8 @@ static inline void thermal_zone_device_unregister(
 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)
+       unsigned long upper, unsigned long lower,
+       unsigned int weight)
 { return -ENODEV; }
 static inline int thermal_zone_unbind_cooling_device(
        struct thermal_zone_device *tz, int trip,
index 5b04b0a5375b338dabbfa4a68b8482e04ffbbbc9..5e31f1b99037d3cc1d43d2336886a8dcb435808f 100644 (file)
@@ -607,7 +607,7 @@ extern void n_tty_inherit_ops(struct tty_ldisc_ops *ops);
 
 /* tty_audit.c */
 #ifdef CONFIG_AUDIT
-extern void tty_audit_add_data(struct tty_struct *tty, unsigned char *data,
+extern void tty_audit_add_data(struct tty_struct *tty, const void *data,
                               size_t size, unsigned icanon);
 extern void tty_audit_exit(void);
 extern void tty_audit_fork(struct signal_struct *sig);
@@ -615,8 +615,8 @@ extern void tty_audit_tiocsti(struct tty_struct *tty, char ch);
 extern void tty_audit_push(struct tty_struct *tty);
 extern int tty_audit_push_current(void);
 #else
-static inline void tty_audit_add_data(struct tty_struct *tty,
-               unsigned char *data, size_t size, unsigned icanon)
+static inline void tty_audit_add_data(struct tty_struct *tty, const void *data,
+                                     size_t size, unsigned icanon)
 {
 }
 static inline void tty_audit_tiocsti(struct tty_struct *tty, char ch)
index 70d8500bddf15e9c68bc5149b29c487e28e5f201..70dd3dfde6319e661069f6b8c2d5a6b15804f27f 100644 (file)
@@ -35,7 +35,7 @@ typedef __kernel_gid16_t        gid16_t;
 
 typedef unsigned long          uintptr_t;
 
-#ifdef CONFIG_UID16
+#ifdef CONFIG_HAVE_UID16
 /* This is defined by include/asm-{arch}/posix_types.h */
 typedef __kernel_old_uid_t     old_uid_t;
 typedef __kernel_old_gid_t     old_gid_t;
index 0bdc72f3690545dd3ac34d1f4b204f2e1db02eb6..4a29c75b146e1c9afc550c6c6bab58f17ed8e2da 100644 (file)
@@ -21,7 +21,7 @@
  * Authors:
  *     Srikar Dronamraju
  *     Jim Keniston
- * Copyright (C) 2011-2012 Red Hat, Inc., Peter Zijlstra <pzijlstr@redhat.com>
+ * Copyright (C) 2011-2012 Red Hat, Inc., Peter Zijlstra
  */
 
 #include <linux/errno.h>
index 1f6526c76ee84f4068707bd0ecae16aaa25c0759..3a375d07d0dc0284441133228af266956ed94f89 100644 (file)
@@ -138,6 +138,7 @@ struct cdc_ncm_ctx {
 };
 
 u8 cdc_ncm_select_altsetting(struct usb_interface *intf);
+int cdc_ncm_change_mtu(struct net_device *net, int new_mtu);
 int cdc_ncm_bind_common(struct usbnet *dev, struct usb_interface *intf, u8 data_altsetting, int drvflags);
 void cdc_ncm_unbind(struct usbnet *dev, struct usb_interface *intf);
 struct sk_buff *cdc_ncm_fill_tx_frame(struct usbnet *dev, struct sk_buff *skb, __le32 sign);
index 9948c874e3f1e4e254ea666a3a7e623678edc26d..1d0043dc34e427403a1c82458249bed83e87d3a0 100644 (file)
@@ -47,4 +47,7 @@
 /* device generates spurious wakeup, ignore remote wakeup capability */
 #define USB_QUIRK_IGNORE_REMOTE_WAKEUP         BIT(9)
 
+/* device can't handle Link Power Management */
+#define USB_QUIRK_NO_LPM                       BIT(10)
+
 #endif /* __LINUX_USB_QUIRKS_H */
index 610a86a892b8896363ece505cdbe686096505cfc..ddb44097538245f17e882efff635143ada49e089 100644 (file)
@@ -44,9 +44,6 @@ struct vfio_device_ops {
        void    (*request)(void *device_data, unsigned int count);
 };
 
-extern struct iommu_group *vfio_iommu_group_get(struct device *dev);
-extern void vfio_iommu_group_put(struct iommu_group *group, struct device *dev);
-
 extern int vfio_add_group_dev(struct device *dev,
                              const struct vfio_device_ops *ops,
                              void *device_data);
index 5dbc8b0ee567a751cf8c60872ae692fccb6a86ab..3e5d9075960f6c756ead3c60013f84f873206932 100644 (file)
@@ -176,11 +176,11 @@ extern void zone_statistics(struct zone *, struct zone *, gfp_t gfp);
 #define sub_zone_page_state(__z, __i, __d) mod_zone_page_state(__z, __i, -(__d))
 
 #ifdef CONFIG_SMP
-void __mod_zone_page_state(struct zone *, enum zone_stat_item item, int);
+void __mod_zone_page_state(struct zone *, enum zone_stat_item item, long);
 void __inc_zone_page_state(struct page *, enum zone_stat_item);
 void __dec_zone_page_state(struct page *, enum zone_stat_item);
 
-void mod_zone_page_state(struct zone *, enum zone_stat_item, int);
+void mod_zone_page_state(struct zone *, enum zone_stat_item, long);
 void inc_zone_page_state(struct page *, enum zone_stat_item);
 void dec_zone_page_state(struct page *, enum zone_stat_item);
 
@@ -205,7 +205,7 @@ void set_pgdat_percpu_threshold(pg_data_t *pgdat,
  * The functions directly modify the zone and global counters.
  */
 static inline void __mod_zone_page_state(struct zone *zone,
-                       enum zone_stat_item item, int delta)
+                       enum zone_stat_item item, long delta)
 {
        zone_page_state_add(delta, zone, item);
 }
index 1e1bf9f963a947fc686125d0a2809ad63b8a13ed..513b36f04dfd80bbe9cf40a272e8d2cd2eab452b 100644 (file)
@@ -145,7 +145,7 @@ __remove_wait_queue(wait_queue_head_t *head, wait_queue_t *old)
        list_del(&old->task_list);
 }
 
-typedef int wait_bit_action_f(struct wait_bit_key *);
+typedef int wait_bit_action_f(struct wait_bit_key *, int mode);
 void __wake_up(wait_queue_head_t *q, unsigned int mode, int nr, void *key);
 void __wake_up_locked_key(wait_queue_head_t *q, unsigned int mode, void *key);
 void __wake_up_sync_key(wait_queue_head_t *q, unsigned int mode, int nr, void *key);
@@ -960,10 +960,10 @@ int wake_bit_function(wait_queue_t *wait, unsigned mode, int sync, void *key);
        } while (0)
 
 
-extern int bit_wait(struct wait_bit_key *);
-extern int bit_wait_io(struct wait_bit_key *);
-extern int bit_wait_timeout(struct wait_bit_key *);
-extern int bit_wait_io_timeout(struct wait_bit_key *);
+extern int bit_wait(struct wait_bit_key *, int);
+extern int bit_wait_io(struct wait_bit_key *, int);
+extern int bit_wait_timeout(struct wait_bit_key *, int);
+extern int bit_wait_io_timeout(struct wait_bit_key *, int);
 
 /**
  * wait_on_bit - wait for a bit to be cleared
index b36d837c701ec9fe94280a91df3cf1e359ad50af..2a91a0561a478393ca9e9d2f1993467cc4c5c9cb 100644 (file)
@@ -62,6 +62,7 @@ struct unix_sock {
 #define UNIX_GC_CANDIDATE      0
 #define UNIX_GC_MAYBE_CYCLE    1
        struct socket_wq        peer_wq;
+       wait_queue_t            peer_wake;
 };
 
 static inline struct unix_sock *unix_sk(const struct sock *sk)
index 1279f9b09791ace6885b0dd67c2c28d578b6cd8e..c7329dcd90cc0637e16fe65eb78246a5d8d21521 100644 (file)
@@ -322,6 +322,39 @@ static inline void skb_dst_force(struct sk_buff *skb)
        }
 }
 
+/**
+ * dst_hold_safe - Take a reference on a dst if possible
+ * @dst: pointer to dst entry
+ *
+ * This helper returns false if it could not safely
+ * take a reference on a dst.
+ */
+static inline bool dst_hold_safe(struct dst_entry *dst)
+{
+       if (dst->flags & DST_NOCACHE)
+               return atomic_inc_not_zero(&dst->__refcnt);
+       dst_hold(dst);
+       return true;
+}
+
+/**
+ * skb_dst_force_safe - makes sure skb dst is refcounted
+ * @skb: buffer
+ *
+ * If dst is not yet refcounted and not destroyed, grab a ref on it.
+ */
+static inline void skb_dst_force_safe(struct sk_buff *skb)
+{
+       if (skb_dst_is_noref(skb)) {
+               struct dst_entry *dst = skb_dst(skb);
+
+               if (!dst_hold_safe(dst))
+                       dst = NULL;
+
+               skb->_skb_refdst = (unsigned long)dst;
+       }
+}
+
 
 /**
  *     __skb_tunnel_rx - prepare skb for rx reinsert
index 2134e6d815bcb0611a2f65cd7b4da44cb7762b8c..625bdf95d673d16eda11884e9adf1595c9926d0f 100644 (file)
@@ -210,18 +210,37 @@ struct inet_sock {
 #define IP_CMSG_ORIGDSTADDR    BIT(6)
 #define IP_CMSG_CHECKSUM       BIT(7)
 
-/* SYNACK messages might be attached to request sockets.
+/**
+ * sk_to_full_sk - Access to a full socket
+ * @sk: pointer to a socket
+ *
+ * SYNACK messages might be attached to request sockets.
  * Some places want to reach the listener in this case.
  */
-static inline struct sock *skb_to_full_sk(const struct sk_buff *skb)
+static inline struct sock *sk_to_full_sk(struct sock *sk)
 {
-       struct sock *sk = skb->sk;
-
+#ifdef CONFIG_INET
        if (sk && sk->sk_state == TCP_NEW_SYN_RECV)
                sk = inet_reqsk(sk)->rsk_listener;
+#endif
+       return sk;
+}
+
+/* sk_to_full_sk() variant with a const argument */
+static inline const struct sock *sk_const_to_full_sk(const struct sock *sk)
+{
+#ifdef CONFIG_INET
+       if (sk && sk->sk_state == TCP_NEW_SYN_RECV)
+               sk = ((const struct request_sock *)sk)->rsk_listener;
+#endif
        return sk;
 }
 
+static inline struct sock *skb_to_full_sk(const struct sk_buff *skb)
+{
+       return sk_to_full_sk(skb->sk);
+}
+
 static inline struct inet_sock *inet_sk(const struct sock *sk)
 {
        return (struct inet_sock *)sk;
index 4a6009d4486b9cfc914d583c5065a3be3d23fa7e..235c7811a86a1df748d838c6b4fd453cea0cbf40 100644 (file)
@@ -78,6 +78,7 @@ void inet_initpeers(void) __init;
 static inline void inetpeer_set_addr_v4(struct inetpeer_addr *iaddr, __be32 ip)
 {
        iaddr->a4.addr = ip;
+       iaddr->a4.vif = 0;
        iaddr->family = AF_INET;
 }
 
index aaf9700fc9e5f8279a172a7ee447cf4f9b5b6ffe..fb961a576abe4a62d02c69d6393abd91a2930fe1 100644 (file)
@@ -167,7 +167,8 @@ static inline void rt6_update_expires(struct rt6_info *rt0, int timeout)
 
 static inline u32 rt6_get_cookie(const struct rt6_info *rt)
 {
-       if (rt->rt6i_flags & RTF_PCPU || unlikely(rt->dst.flags & DST_NOCACHE))
+       if (rt->rt6i_flags & RTF_PCPU ||
+           (unlikely(rt->dst.flags & DST_NOCACHE) && rt->dst.from))
                rt = (struct rt6_info *)(rt->dst.from);
 
        return rt->rt6i_node ? rt->rt6i_node->fn_sernum : 0;
index 2bfb2ad2fab1981696e52a914cd89a0dad495e76..877f682989b892fb1d70256bda6b33f03e34a0f5 100644 (file)
@@ -133,27 +133,18 @@ void rt6_clean_tohost(struct net *net, struct in6_addr *gateway);
 /*
  *     Store a destination cache entry in a socket
  */
-static inline void __ip6_dst_store(struct sock *sk, struct dst_entry *dst,
-                                  const struct in6_addr *daddr,
-                                  const struct in6_addr *saddr)
+static inline void ip6_dst_store(struct sock *sk, struct dst_entry *dst,
+                                const struct in6_addr *daddr,
+                                const struct in6_addr *saddr)
 {
        struct ipv6_pinfo *np = inet6_sk(sk);
-       struct rt6_info *rt = (struct rt6_info *) dst;
 
+       np->dst_cookie = rt6_get_cookie((struct rt6_info *)dst);
        sk_setup_caps(sk, dst);
        np->daddr_cache = daddr;
 #ifdef CONFIG_IPV6_SUBTREES
        np->saddr_cache = saddr;
 #endif
-       np->dst_cookie = rt6_get_cookie(rt);
-}
-
-static inline void ip6_dst_store(struct sock *sk, struct dst_entry *dst,
-                                struct in6_addr *daddr, struct in6_addr *saddr)
-{
-       spin_lock(&sk->sk_dst_lock);
-       __ip6_dst_store(sk, dst, daddr, saddr);
-       spin_unlock(&sk->sk_dst_lock);
 }
 
 static inline bool ipv6_unicast_destination(const struct sk_buff *skb)
index aaee6fa02cf1d2a756eb6b97559501c47af1c635..ff788b665277d59d8039fd4588f3e0256639833c 100644 (file)
@@ -90,11 +90,12 @@ static inline void ip6tunnel_xmit(struct sock *sk, struct sk_buff *skb,
        err = ip6_local_out(dev_net(skb_dst(skb)->dev), sk, skb);
 
        if (net_xmit_eval(err) == 0) {
-               struct pcpu_sw_netstats *tstats = this_cpu_ptr(dev->tstats);
+               struct pcpu_sw_netstats *tstats = get_cpu_ptr(dev->tstats);
                u64_stats_update_begin(&tstats->syncp);
                tstats->tx_bytes += pkt_len;
                tstats->tx_packets++;
                u64_stats_update_end(&tstats->syncp);
+               put_cpu_ptr(tstats);
        } else {
                stats->tx_errors++;
                stats->tx_aborted_errors++;
index f6dafec9102c5f03e08fdd7fc3efc4812e4137ce..62a750a6a8f8cb32c9eb5d8d160aa94a20898473 100644 (file)
@@ -287,12 +287,13 @@ static inline void iptunnel_xmit_stats(int err,
                                       struct pcpu_sw_netstats __percpu *stats)
 {
        if (err > 0) {
-               struct pcpu_sw_netstats *tstats = this_cpu_ptr(stats);
+               struct pcpu_sw_netstats *tstats = get_cpu_ptr(stats);
 
                u64_stats_update_begin(&tstats->syncp);
                tstats->tx_bytes += err;
                tstats->tx_packets++;
                u64_stats_update_end(&tstats->syncp);
+               put_cpu_ptr(tstats);
        } else if (err < 0) {
                err_stats->tx_errors++;
                err_stats->tx_aborted_errors++;
index e1a10b0ac0b027189732372e2c0040e5ea8350f2..9a5c9f01378455c4c8b9eb860b170504c878f1a5 100644 (file)
@@ -205,6 +205,7 @@ extern rwlock_t ip6_ra_lock;
  */
 
 struct ipv6_txoptions {
+       atomic_t                refcnt;
        /* Length of this structure */
        int                     tot_len;
 
@@ -217,7 +218,7 @@ struct ipv6_txoptions {
        struct ipv6_opt_hdr     *dst0opt;
        struct ipv6_rt_hdr      *srcrt; /* Routing Header */
        struct ipv6_opt_hdr     *dst1opt;
-
+       struct rcu_head         rcu;
        /* Option buffer, as read by IPV6_PKTOPTIONS, starts here. */
 };
 
@@ -252,6 +253,24 @@ struct ipv6_fl_socklist {
        struct rcu_head                 rcu;
 };
 
+static inline struct ipv6_txoptions *txopt_get(const struct ipv6_pinfo *np)
+{
+       struct ipv6_txoptions *opt;
+
+       rcu_read_lock();
+       opt = rcu_dereference(np->opt);
+       if (opt && !atomic_inc_not_zero(&opt->refcnt))
+               opt = NULL;
+       rcu_read_unlock();
+       return opt;
+}
+
+static inline void txopt_put(struct ipv6_txoptions *opt)
+{
+       if (opt && atomic_dec_and_test(&opt->refcnt))
+               kfree_rcu(opt, rcu);
+}
+
 struct ip6_flowlabel *fl6_sock_lookup(struct sock *sk, __be32 label);
 struct ipv6_txoptions *fl6_merge_options(struct ipv6_txoptions *opt_space,
                                         struct ip6_flowlabel *fl,
@@ -490,6 +509,7 @@ struct ip6_create_arg {
        u32 user;
        const struct in6_addr *src;
        const struct in6_addr *dst;
+       int iif;
        u8 ecn;
 };
 
index 82045fca388b20a9cf28ad9112236668c31f46cb..760bc4d5a2cfe87aadd2e96a98292855cf2eb050 100644 (file)
@@ -2003,8 +2003,10 @@ enum ieee80211_hw_flags {
  *     it shouldn't be set.
  *
  * @max_tx_aggregation_subframes: maximum number of subframes in an
- *     aggregate an HT driver will transmit, used by the peer as a
- *     hint to size its reorder buffer.
+ *     aggregate an HT driver will transmit. Though ADDBA will advertise
+ *     a constant value of 64 as some older APs can crash if the window
+ *     size is smaller (an example is LinkSys WRT120N with FW v1.0.07
+ *     build 002 Jun 18 2012).
  *
  * @offchannel_tx_hw_queue: HW queue ID to use for offchannel TX
  *     (if %IEEE80211_HW_QUEUE_CONTROL is set)
index bf39374310305d61e2948cbd1801eee056efc323..2d8edaad29cb1cf0fe1e9a6dc9ae8f2653a3334e 100644 (file)
@@ -181,8 +181,7 @@ void ndisc_cleanup(void);
 int ndisc_rcv(struct sk_buff *skb);
 
 void ndisc_send_ns(struct net_device *dev, const struct in6_addr *solicit,
-                  const struct in6_addr *daddr, const struct in6_addr *saddr,
-                  struct sk_buff *oskb);
+                  const struct in6_addr *daddr, const struct in6_addr *saddr);
 
 void ndisc_send_rs(struct net_device *dev,
                   const struct in6_addr *saddr, const struct in6_addr *daddr);
index c9149cc0a02d30683288de140bc3276d75e640ce..4bd7508bedc9fefb08c8e3a8cd65278553c4412c 100644 (file)
@@ -618,6 +618,8 @@ struct nft_expr_ops {
        void                            (*eval)(const struct nft_expr *expr,
                                                struct nft_regs *regs,
                                                const struct nft_pktinfo *pkt);
+       int                             (*clone)(struct nft_expr *dst,
+                                                const struct nft_expr *src);
        unsigned int                    size;
 
        int                             (*init)(const struct nft_ctx *ctx,
@@ -660,10 +662,20 @@ void nft_expr_destroy(const struct nft_ctx *ctx, struct nft_expr *expr);
 int nft_expr_dump(struct sk_buff *skb, unsigned int attr,
                  const struct nft_expr *expr);
 
-static inline void nft_expr_clone(struct nft_expr *dst, struct nft_expr *src)
+static inline int nft_expr_clone(struct nft_expr *dst, struct nft_expr *src)
 {
+       int err;
+
        __module_get(src->ops->type->owner);
-       memcpy(dst, src, src->ops->size);
+       if (src->ops->clone) {
+               dst->ops = src->ops;
+               err = src->ops->clone(dst, src);
+               if (err < 0)
+                       return err;
+       } else {
+               memcpy(dst, src, src->ops->size);
+       }
+       return 0;
 }
 
 /**
index 4c79ce8c1f92f2d47eb87ffacd55fa01292e7378..b2a8e6338576d3e91f0906297e6b34e7db0eade3 100644 (file)
@@ -61,6 +61,9 @@ struct Qdisc {
                                      */
 #define TCQ_F_WARN_NONWC       (1 << 16)
 #define TCQ_F_CPUSTATS         0x20 /* run using percpu statistics */
+#define TCQ_F_NOPARENT         0x40 /* root of its hierarchy :
+                                     * qdisc_tree_decrease_qlen() should stop.
+                                     */
        u32                     limit;
        const struct Qdisc_ops  *ops;
        struct qdisc_size_table __rcu *stab;
index 495c87e367b3f2e8941807f56a77d2e14469bfed..eea9bdeecba27f0ecff39e9d821fc029028f8e5b 100644 (file)
@@ -775,10 +775,10 @@ struct sctp_transport {
                hb_sent:1,
 
                /* Is the Path MTU update pending on this tranport */
-               pmtu_pending:1;
+               pmtu_pending:1,
 
-       /* Has this transport moved the ctsn since we last sacked */
-       __u32 sack_generation;
+               /* Has this transport moved the ctsn since we last sacked */
+               sack_generation:1;
        u32 dst_cookie;
 
        struct flowi fl;
@@ -1482,19 +1482,20 @@ struct sctp_association {
                        prsctp_capable:1,   /* Can peer do PR-SCTP? */
                        auth_capable:1;     /* Is peer doing SCTP-AUTH? */
 
-               /* Ack State   : This flag indicates if the next received
+               /* sack_needed : This flag indicates if the next received
                 *             : packet is to be responded to with a
-                *             : SACK. This is initializedto 0.  When a packet
-                *             : is received it is incremented. If this value
+                *             : SACK. This is initialized to 0.  When a packet
+                *             : is received sack_cnt is incremented. If this value
                 *             : reaches 2 or more, a SACK is sent and the
                 *             : value is reset to 0. Note: This is used only
                 *             : when no DATA chunks are received out of
                 *             : order.  When DATA chunks are out of order,
                 *             : SACK's are not delayed (see Section 6).
                 */
-               __u8    sack_needed;     /* Do we need to sack the peer? */
+               __u8    sack_needed:1,     /* Do we need to sack the peer? */
+                       sack_generation:1,
+                       zero_window_announced:1;
                __u32   sack_cnt;
-               __u32   sack_generation;
 
                __u32   adaptation_ind;  /* Adaptation Code point. */
 
index bbf7c2cf15b4ec278bca5426b3319ca501454d66..14d3c07340079b7a3e9de54ee635011589247ffd 100644 (file)
@@ -254,7 +254,6 @@ struct cg_proto;
   *    @sk_wq: sock wait queue and async head
   *    @sk_rx_dst: receive input route used by early demux
   *    @sk_dst_cache: destination cache
-  *    @sk_dst_lock: destination cache lock
   *    @sk_policy: flow policy
   *    @sk_receive_queue: incoming packets
   *    @sk_wmem_alloc: transmit queue bytes committed
@@ -384,14 +383,16 @@ struct sock {
        int                     sk_rcvbuf;
 
        struct sk_filter __rcu  *sk_filter;
-       struct socket_wq __rcu  *sk_wq;
-
+       union {
+               struct socket_wq __rcu  *sk_wq;
+               struct socket_wq        *sk_wq_raw;
+       };
 #ifdef CONFIG_XFRM
-       struct xfrm_policy      *sk_policy[2];
+       struct xfrm_policy __rcu *sk_policy[2];
 #endif
        struct dst_entry        *sk_rx_dst;
        struct dst_entry __rcu  *sk_dst_cache;
-       spinlock_t              sk_dst_lock;
+       /* Note: 32bit hole on 64bit arches */
        atomic_t                sk_wmem_alloc;
        atomic_t                sk_omem_alloc;
        int                     sk_sndbuf;
@@ -403,6 +404,7 @@ struct sock {
                                sk_userlocks : 4,
                                sk_protocol  : 8,
                                sk_type      : 16;
+#define SK_PROTOCOL_MAX U8_MAX
        kmemcheck_bitfield_end(flags);
        int                     sk_wmem_queued;
        gfp_t                   sk_allocation;
@@ -739,6 +741,8 @@ enum sock_flags {
        SOCK_SELECT_ERR_QUEUE, /* Wake select on error queue */
 };
 
+#define SK_FLAGS_TIMESTAMP ((1UL << SOCK_TIMESTAMP) | (1UL << SOCK_TIMESTAMPING_RX_SOFTWARE))
+
 static inline void sock_copy_flags(struct sock *nsk, struct sock *osk)
 {
        nsk->sk_flags = osk->sk_flags;
@@ -813,7 +817,7 @@ void sk_stream_write_space(struct sock *sk);
 static inline void __sk_add_backlog(struct sock *sk, struct sk_buff *skb)
 {
        /* dont let skb dst not refcounted, we are going to leave rcu lock */
-       skb_dst_force(skb);
+       skb_dst_force_safe(skb);
 
        if (!sk->sk_backlog.tail)
                sk->sk_backlog.head = skb;
@@ -2005,10 +2009,27 @@ static inline unsigned long sock_wspace(struct sock *sk)
        return amt;
 }
 
-static inline void sk_wake_async(struct sock *sk, int how, int band)
+/* Note:
+ *  We use sk->sk_wq_raw, from contexts knowing this
+ *  pointer is not NULL and cannot disappear/change.
+ */
+static inline void sk_set_bit(int nr, struct sock *sk)
+{
+       set_bit(nr, &sk->sk_wq_raw->flags);
+}
+
+static inline void sk_clear_bit(int nr, struct sock *sk)
+{
+       clear_bit(nr, &sk->sk_wq_raw->flags);
+}
+
+static inline void sk_wake_async(const struct sock *sk, int how, int band)
 {
-       if (sock_flag(sk, SOCK_FASYNC))
-               sock_wake_async(sk->sk_socket, how, band);
+       if (sock_flag(sk, SOCK_FASYNC)) {
+               rcu_read_lock();
+               sock_wake_async(rcu_dereference(sk->sk_wq), how, band);
+               rcu_read_unlock();
+       }
 }
 
 /* Since sk_{r,w}mem_alloc sums skb->truesize, even a small frame might
@@ -2226,6 +2247,31 @@ static inline bool sk_listener(const struct sock *sk)
        return (1 << sk->sk_state) & (TCPF_LISTEN | TCPF_NEW_SYN_RECV);
 }
 
+/**
+ * sk_state_load - read sk->sk_state for lockless contexts
+ * @sk: socket pointer
+ *
+ * Paired with sk_state_store(). Used in places we do not hold socket lock :
+ * tcp_diag_get_info(), tcp_get_info(), tcp_poll(), get_tcp4_sock() ...
+ */
+static inline int sk_state_load(const struct sock *sk)
+{
+       return smp_load_acquire(&sk->sk_state);
+}
+
+/**
+ * sk_state_store - update sk->sk_state
+ * @sk: socket pointer
+ * @newstate: new state
+ *
+ * Paired with sk_state_load(). Should be used in contexts where
+ * state change might impact lockless readers.
+ */
+static inline void sk_state_store(struct sock *sk, int newstate)
+{
+       smp_store_release(&sk->sk_state, newstate);
+}
+
 void sock_enable_timestamp(struct sock *sk, int flag);
 int sock_get_timestamp(struct sock *, struct timeval __user *);
 int sock_get_timestampns(struct sock *, struct timespec __user *);
index bc865e244efea0c4757a182274ad7ca9f9cc3266..1d22ce9f352e2e7610095c4b1774164aa6af4516 100644 (file)
@@ -323,7 +323,7 @@ static inline int switchdev_port_fdb_dump(struct sk_buff *skb,
                                          struct net_device *filter_dev,
                                          int idx)
 {
-       return -EOPNOTSUPP;
+       return idx;
 }
 
 static inline void switchdev_port_fwd_mark_set(struct net_device *dev,
index c1c899c3a51be42f680fff5ce0f5c5e997652daa..e289ada6adf6b0a7bd45debd46488a28b2642ee6 100644 (file)
@@ -79,7 +79,7 @@ struct vxlanhdr {
 };
 
 /* VXLAN header flags. */
-#define VXLAN_HF_RCO BIT(24)
+#define VXLAN_HF_RCO BIT(21)
 #define VXLAN_HF_VNI BIT(27)
 #define VXLAN_HF_GBP BIT(31)
 
index 4a9c21f9b4ea189075901a3f2c8c12ec6814f5fe..d6f6e5006ee9e3cb8dcd61e151fcc95ce165eab9 100644 (file)
@@ -548,6 +548,7 @@ struct xfrm_policy {
        u16                     family;
        struct xfrm_sec_ctx     *security;
        struct xfrm_tmpl        xfrm_vec[XFRM_MAX_DEPTH];
+       struct rcu_head         rcu;
 };
 
 static inline struct net *xp_net(const struct xfrm_policy *xp)
@@ -1141,12 +1142,14 @@ static inline int xfrm6_route_forward(struct sk_buff *skb)
        return xfrm_route_forward(skb, AF_INET6);
 }
 
-int __xfrm_sk_clone_policy(struct sock *sk);
+int __xfrm_sk_clone_policy(struct sock *sk, const struct sock *osk);
 
-static inline int xfrm_sk_clone_policy(struct sock *sk)
+static inline int xfrm_sk_clone_policy(struct sock *sk, const struct sock *osk)
 {
-       if (unlikely(sk->sk_policy[0] || sk->sk_policy[1]))
-               return __xfrm_sk_clone_policy(sk);
+       sk->sk_policy[0] = NULL;
+       sk->sk_policy[1] = NULL;
+       if (unlikely(osk->sk_policy[0] || osk->sk_policy[1]))
+               return __xfrm_sk_clone_policy(sk, osk);
        return 0;
 }
 
@@ -1154,12 +1157,16 @@ int xfrm_policy_delete(struct xfrm_policy *pol, int dir);
 
 static inline void xfrm_sk_free_policy(struct sock *sk)
 {
-       if (unlikely(sk->sk_policy[0] != NULL)) {
-               xfrm_policy_delete(sk->sk_policy[0], XFRM_POLICY_MAX);
+       struct xfrm_policy *pol;
+
+       pol = rcu_dereference_protected(sk->sk_policy[0], 1);
+       if (unlikely(pol != NULL)) {
+               xfrm_policy_delete(pol, XFRM_POLICY_MAX);
                sk->sk_policy[0] = NULL;
        }
-       if (unlikely(sk->sk_policy[1] != NULL)) {
-               xfrm_policy_delete(sk->sk_policy[1], XFRM_POLICY_MAX+1);
+       pol = rcu_dereference_protected(sk->sk_policy[1], 1);
+       if (unlikely(pol != NULL)) {
+               xfrm_policy_delete(pol, XFRM_POLICY_MAX+1);
                sk->sk_policy[1] = NULL;
        }
 }
@@ -1169,7 +1176,7 @@ void xfrm_garbage_collect(struct net *net);
 #else
 
 static inline void xfrm_sk_free_policy(struct sock *sk) {}
-static inline int xfrm_sk_clone_policy(struct sock *sk) { return 0; }
+static inline int xfrm_sk_clone_policy(struct sock *sk, const struct sock *osk) { return 0; }
 static inline int xfrm6_route_forward(struct sk_buff *skb) { return 1; }  
 static inline int xfrm4_route_forward(struct sk_buff *skb) { return 1; } 
 static inline int xfrm6_policy_check(struct sock *sk, int dir, struct sk_buff *skb)
index 188df91d58514a3248cab5b1b0d7ee09513295a6..ec9b44dd3d806b20d80920a0cb37487ea2d12c24 100644 (file)
@@ -237,6 +237,8 @@ struct ib_vendor_mad {
        u8                      data[IB_MGMT_VENDOR_DATA];
 };
 
+#define IB_MGMT_CLASSPORTINFO_ATTR_ID  cpu_to_be16(0x0001)
+
 struct ib_class_port_info {
        u8                      base_version;
        u8                      class_version;
index 9a68a19532ba57c27042cec499843f3cebfa273c..120da1d7f57eb578c327507ad2affa5b89488dbb 100644 (file)
@@ -1271,6 +1271,7 @@ struct ib_uobject {
        int                     id;             /* index into kernel idr */
        struct kref             ref;
        struct rw_semaphore     mutex;          /* protects .live */
+       struct rcu_head         rcu;            /* kfree_rcu() overhead */
        int                     live;
 };
 
index ed527121031dd31b424c1ff596f9139cfcdefd02..fcfa3d7f5e7e38f1bffcf50495730f24bb9e6b2b 100644 (file)
@@ -668,6 +668,9 @@ struct Scsi_Host {
        unsigned use_blk_mq:1;
        unsigned use_cmd_list:1;
 
+       /* Host responded with short (<36 bytes) INQUIRY result */
+       unsigned short_inquiry:1;
+
        /*
         * Optional work queue to be utilized by the transport
         */
index 74bc85473b58c18e3bc92e2fcf7c70a232fe75d7..15aa5f07c955bed7f6b0d7f1dfc9471d7f229120 100644 (file)
 #define AC97_RATES_MIC_ADC     4
 #define AC97_RATES_SPDIF       5
 
+#define AC97_NUM_GPIOS         16
 /*
  *
  */
 
 struct snd_ac97;
+struct snd_ac97_gpio_priv;
 struct snd_pcm_chmap;
 
 struct snd_ac97_build_ops {
@@ -529,6 +531,7 @@ struct snd_ac97 {
        struct delayed_work power_work;
 #endif
        struct device dev;
+       struct snd_ac97_gpio_priv *gpio_priv;
 
        struct snd_pcm_chmap *chmaps[2]; /* channel-maps (optional) */
 };
diff --git a/include/sound/da7218.h b/include/sound/da7218.h
new file mode 100644 (file)
index 0000000..0dbb818
--- /dev/null
@@ -0,0 +1,109 @@
+/*
+ * da7218.h - DA7218 ASoC Codec Driver Platform Data
+ *
+ * Copyright (c) 2015 Dialog Semiconductor
+ *
+ * Author: Adam Thomson <Adam.Thomson.Opensource@diasemi.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 _DA7218_PDATA_H
+#define _DA7218_PDATA_H
+
+/* Mic Bias */
+enum da7218_micbias_voltage {
+       DA7218_MICBIAS_1_2V = -1,
+       DA7218_MICBIAS_1_6V,
+       DA7218_MICBIAS_1_8V,
+       DA7218_MICBIAS_2_0V,
+       DA7218_MICBIAS_2_2V,
+       DA7218_MICBIAS_2_4V,
+       DA7218_MICBIAS_2_6V,
+       DA7218_MICBIAS_2_8V,
+       DA7218_MICBIAS_3_0V,
+};
+
+enum da7218_mic_amp_in_sel {
+       DA7218_MIC_AMP_IN_SEL_DIFF = 0,
+       DA7218_MIC_AMP_IN_SEL_SE_P,
+       DA7218_MIC_AMP_IN_SEL_SE_N,
+};
+
+/* DMIC */
+enum da7218_dmic_data_sel {
+       DA7218_DMIC_DATA_LRISE_RFALL = 0,
+       DA7218_DMIC_DATA_LFALL_RRISE,
+};
+
+enum da7218_dmic_samplephase {
+       DA7218_DMIC_SAMPLE_ON_CLKEDGE = 0,
+       DA7218_DMIC_SAMPLE_BETWEEN_CLKEDGE,
+};
+
+enum da7218_dmic_clk_rate {
+       DA7218_DMIC_CLK_3_0MHZ = 0,
+       DA7218_DMIC_CLK_1_5MHZ,
+};
+
+/* Headphone Detect */
+enum da7218_hpldet_jack_rate {
+       DA7218_HPLDET_JACK_RATE_5US = 0,
+       DA7218_HPLDET_JACK_RATE_10US,
+       DA7218_HPLDET_JACK_RATE_20US,
+       DA7218_HPLDET_JACK_RATE_40US,
+       DA7218_HPLDET_JACK_RATE_80US,
+       DA7218_HPLDET_JACK_RATE_160US,
+       DA7218_HPLDET_JACK_RATE_320US,
+       DA7218_HPLDET_JACK_RATE_640US,
+};
+
+enum da7218_hpldet_jack_debounce {
+       DA7218_HPLDET_JACK_DEBOUNCE_OFF = 0,
+       DA7218_HPLDET_JACK_DEBOUNCE_2,
+       DA7218_HPLDET_JACK_DEBOUNCE_3,
+       DA7218_HPLDET_JACK_DEBOUNCE_4,
+};
+
+enum da7218_hpldet_jack_thr {
+       DA7218_HPLDET_JACK_THR_84PCT = 0,
+       DA7218_HPLDET_JACK_THR_88PCT,
+       DA7218_HPLDET_JACK_THR_92PCT,
+       DA7218_HPLDET_JACK_THR_96PCT,
+};
+
+struct da7218_hpldet_pdata {
+       enum da7218_hpldet_jack_rate jack_rate;
+       enum da7218_hpldet_jack_debounce jack_debounce;
+       enum da7218_hpldet_jack_thr jack_thr;
+       bool comp_inv;
+       bool hyst;
+       bool discharge;
+};
+
+struct da7218_pdata {
+       /* Mic */
+       enum da7218_micbias_voltage micbias1_lvl;
+       enum da7218_micbias_voltage micbias2_lvl;
+       enum da7218_mic_amp_in_sel mic1_amp_in_sel;
+       enum da7218_mic_amp_in_sel mic2_amp_in_sel;
+
+       /* DMIC */
+       enum da7218_dmic_data_sel dmic1_data_sel;
+       enum da7218_dmic_data_sel dmic2_data_sel;
+       enum da7218_dmic_samplephase dmic1_samplephase;
+       enum da7218_dmic_samplephase dmic2_samplephase;
+       enum da7218_dmic_clk_rate dmic1_clk_rate;
+       enum da7218_dmic_clk_rate dmic2_clk_rate;
+
+       /* HP Diff Supply - DA7217 only */
+       bool hp_diff_single_supply;
+
+       /* HP Detect - DA7218 only */
+       struct da7218_hpldet_pdata *hpldet_pdata;
+};
+
+#endif /* _DA7218_PDATA_H */
index 3f39e135312db031a0e55cf3b538fee230415c9a..02876acdc8406a5bda9351051dabac54fc2b3641 100644 (file)
 #ifndef __DA7219_PDATA_H
 #define __DA7219_PDATA_H
 
-/* LDO */
-enum da7219_ldo_lvl_sel {
-       DA7219_LDO_LVL_SEL_1_05V = 0,
-       DA7219_LDO_LVL_SEL_1_10V,
-       DA7219_LDO_LVL_SEL_1_20V,
-       DA7219_LDO_LVL_SEL_1_40V,
-};
-
 /* Mic Bias */
 enum da7219_micbias_voltage {
-       DA7219_MICBIAS_1_8V = 1,
+       DA7219_MICBIAS_1_6V = 0,
+       DA7219_MICBIAS_1_8V,
        DA7219_MICBIAS_2_0V,
        DA7219_MICBIAS_2_2V,
        DA7219_MICBIAS_2_4V,
@@ -41,9 +34,6 @@ enum da7219_mic_amp_in_sel {
 struct da7219_aad_pdata;
 
 struct da7219_pdata {
-       /* Internal LDO */
-       enum da7219_ldo_lvl_sel ldo_lvl_sel;
-
        /* Mic */
        enum da7219_micbias_voltage micbias_lvl;
        enum da7219_mic_amp_in_sel mic_amp_in_sel;
index 8966ba7c962951de6fd1f972c092266a38b823d2..5681855396c411210b51fffe1b368d6ccf5a1027 100644 (file)
@@ -45,6 +45,12 @@ struct i2s_platform_data {
        u32 snd_fmts;
        u32 snd_rates;
 
+       #define DW_I2S_QUIRK_COMP_REG_OFFSET    (1 << 0)
+       #define DW_I2S_QUIRK_COMP_PARAM1        (1 << 1)
+       unsigned int quirks;
+       unsigned int i2s_reg_comp1;
+       unsigned int i2s_reg_comp2;
+
        void *play_dma_data;
        void *capture_dma_data;
        bool (*filter)(struct dma_chan *chan, void *slave);
index 2ae8812d7b1a37845789b7c0522c0ab1b4300c45..ff1aecf325e87543d73bc4b4914790c181139110 100644 (file)
@@ -93,6 +93,9 @@ enum { SDI0, SDI1, SDI2, SDI3, SDO0, SDO1, SDO2, SDO3 };
 #define AZX_REG_HSW_EM4                        0x100c
 #define AZX_REG_HSW_EM5                        0x1010
 
+/* Skylake/Broxton display HD-A controller Extended Mode registers */
+#define AZX_REG_SKL_EM4L               0x1040
+
 /* PCI space */
 #define AZX_PCIREG_TCSEL               0x44
 
@@ -230,6 +233,15 @@ enum { SDI0, SDI1, SDI2, SDI3, SDO0, SDO1, SDO2, SDO3 };
 #define AZX_MLCTL_SPA                  (1<<16)
 #define AZX_MLCTL_CPA                  23
 
+
+/* registers for DMA Resume Capability Structure */
+#define AZX_DRSM_CAP_ID                        0x5
+#define AZX_REG_DRSM_CTL               0x4
+/* Base used to calculate the iterating register offset */
+#define AZX_DRSM_BASE                  0x08
+/* Interval used to calculate the iterating register offset */
+#define AZX_DRSM_INTERVAL              0x08
+
 /*
  * helpers to read the stream position
  */
index a4cadd9c297a810e1bb548d2cb02e4ab92b5eea2..07fa59237feb032e3e6dcb6660cca6d17b5679e4 100644 (file)
@@ -12,6 +12,7 @@
  * @spbcap: SPIB capabilities pointer
  * @mlcap: MultiLink capabilities pointer
  * @gtscap: gts capabilities pointer
+ * @drsmcap: dma resume capabilities pointer
  * @hlink_list: link list of HDA links
  */
 struct hdac_ext_bus {
@@ -23,6 +24,7 @@ struct hdac_ext_bus {
        void __iomem *spbcap;
        void __iomem *mlcap;
        void __iomem *gtscap;
+       void __iomem *drsmcap;
 
        struct list_head hlink_list;
 };
@@ -72,6 +74,9 @@ enum hdac_ext_stream_type {
  * @pplc_addr: processing pipe link stream pointer
  * @spib_addr: software position in buffers stream pointer
  * @fifo_addr: software position Max fifos stream pointer
+ * @dpibr_addr: DMA position in buffer resume pointer
+ * @dpib: DMA position in buffer
+ * @lpib: Linear position in buffer
  * @decoupled: stream host and link is decoupled
  * @link_locked: link is locked
  * @link_prepared: link is prepared
@@ -86,6 +91,10 @@ struct hdac_ext_stream {
        void __iomem *spib_addr;
        void __iomem *fifo_addr;
 
+       void __iomem *dpibr_addr;
+
+       u32 dpib;
+       u32 lpib;
        bool decoupled:1;
        bool link_locked:1;
        bool link_prepared;
@@ -116,6 +125,11 @@ int snd_hdac_ext_stream_set_spib(struct hdac_ext_bus *ebus,
                                 struct hdac_ext_stream *stream, u32 value);
 int snd_hdac_ext_stream_get_spbmaxfifo(struct hdac_ext_bus *ebus,
                                 struct hdac_ext_stream *stream);
+void snd_hdac_ext_stream_drsm_enable(struct hdac_ext_bus *ebus,
+                               bool enable, int index);
+int snd_hdac_ext_stream_set_dpibr(struct hdac_ext_bus *ebus,
+                               struct hdac_ext_stream *stream, u32 value);
+int snd_hdac_ext_stream_set_lpib(struct hdac_ext_stream *stream, u32 value);
 
 void snd_hdac_ext_link_stream_start(struct hdac_ext_stream *hstream);
 void snd_hdac_ext_link_stream_clear(struct hdac_ext_stream *hstream);
@@ -133,6 +147,7 @@ struct hdac_ext_link {
 
 int snd_hdac_ext_bus_link_power_up(struct hdac_ext_link *link);
 int snd_hdac_ext_bus_link_power_down(struct hdac_ext_link *link);
+int snd_hdac_ext_bus_link_power_up_all(struct hdac_ext_bus *ebus);
 int snd_hdac_ext_bus_link_power_down_all(struct hdac_ext_bus *ebus);
 void snd_hdac_ext_link_set_stream_id(struct hdac_ext_link *link,
                                 int stream);
@@ -186,9 +201,15 @@ struct hdac_ext_device {
        /* codec ops */
        struct hdac_ext_codec_ops ops;
 
+       struct snd_card *card;
+       void *scodec;
        void *private_data;
 };
 
+struct hdac_ext_dma_params {
+       u32 format;
+       u8 stream_tag;
+};
 #define to_ehdac_device(dev) (container_of((dev), \
                                 struct hdac_ext_device, hdac))
 /*
diff --git a/include/sound/rt5659.h b/include/sound/rt5659.h
new file mode 100644 (file)
index 0000000..656c4d5
--- /dev/null
@@ -0,0 +1,49 @@
+/*
+ * linux/sound/rt5659.h -- Platform data for RT5659
+ *
+ * Copyright 2013 Realtek Microelectronics
+ *
+ * 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 __LINUX_SND_RT5659_H
+#define __LINUX_SND_RT5659_H
+
+enum rt5659_dmic1_data_pin {
+       RT5659_DMIC1_NULL,
+       RT5659_DMIC1_DATA_IN2N,
+       RT5659_DMIC1_DATA_GPIO5,
+       RT5659_DMIC1_DATA_GPIO9,
+       RT5659_DMIC1_DATA_GPIO11,
+};
+
+enum rt5659_dmic2_data_pin {
+       RT5659_DMIC2_NULL,
+       RT5659_DMIC2_DATA_IN2P,
+       RT5659_DMIC2_DATA_GPIO6,
+       RT5659_DMIC2_DATA_GPIO10,
+       RT5659_DMIC2_DATA_GPIO12,
+};
+
+enum rt5659_jd_src {
+       RT5659_JD_NULL,
+       RT5659_JD3,
+};
+
+struct rt5659_platform_data {
+       bool in1_diff;
+       bool in3_diff;
+       bool in4_diff;
+
+       int ldo1_en; /* GPIO for LDO1_EN */
+       int reset; /* GPIO for RESET */
+
+       enum rt5659_dmic1_data_pin dmic1_data_pin;
+       enum rt5659_dmic2_data_pin dmic2_data_pin;
+       enum rt5659_jd_src jd_src;
+};
+
+#endif
+
index 212eaaf172ed49b8ac26d619ef3e0bce9553bee2..964b7de1a1cc2ebd8cd58fe16487cc631caf9f71 100644 (file)
@@ -222,6 +222,7 @@ struct snd_soc_dai_driver {
        const char *name;
        unsigned int id;
        unsigned int base;
+       struct snd_soc_dobj dobj;
 
        /* DAI driver callbacks */
        int (*probe)(struct snd_soc_dai *dai);
index 7855cfe46b69a044040f9ac5be92591e33af1799..97069466c38dd90ffb518fc8b367073c787697be 100644 (file)
@@ -49,6 +49,9 @@ struct device;
 #define SND_SOC_DAPM_SIGGEN(wname) \
 {      .id = snd_soc_dapm_siggen, .name = wname, .kcontrol_news = NULL, \
        .num_kcontrols = 0, .reg = SND_SOC_NOPM }
+#define SND_SOC_DAPM_SINK(wname) \
+{      .id = snd_soc_dapm_sink, .name = wname, .kcontrol_news = NULL, \
+       .num_kcontrols = 0, .reg = SND_SOC_NOPM }
 #define SND_SOC_DAPM_INPUT(wname) \
 {      .id = snd_soc_dapm_input, .name = wname, .kcontrol_news = NULL, \
        .num_kcontrols = 0, .reg = SND_SOC_NOPM }
@@ -398,6 +401,7 @@ int snd_soc_dapm_del_routes(struct snd_soc_dapm_context *dapm,
 int snd_soc_dapm_weak_routes(struct snd_soc_dapm_context *dapm,
                             const struct snd_soc_dapm_route *route, int num);
 void snd_soc_dapm_free_widget(struct snd_soc_dapm_widget *w);
+void snd_soc_dapm_reset_cache(struct snd_soc_dapm_context *dapm);
 
 /* dapm events */
 void snd_soc_dapm_stream_event(struct snd_soc_pcm_runtime *rtd, int stream,
@@ -484,6 +488,7 @@ enum snd_soc_dapm_type {
        snd_soc_dapm_aif_in,            /* audio interface input */
        snd_soc_dapm_aif_out,           /* audio interface output */
        snd_soc_dapm_siggen,            /* signal generator */
+       snd_soc_dapm_sink,
        snd_soc_dapm_dai_in,            /* link to DAI structure */
        snd_soc_dapm_dai_out,
        snd_soc_dapm_dai_link,          /* link between two DAI structures */
index 086cd7ff6ddcbb457ee31277baf3fee143f0181d..5b68e3f5aa85b301eaab5ff6975b76e257a00c52 100644 (file)
@@ -92,8 +92,10 @@ struct snd_soc_tplg_kcontrol_ops {
 /* Bytes ext operations, for TLV byte controls */
 struct snd_soc_tplg_bytes_ext_ops {
        u32 id;
-       int (*get)(unsigned int __user *bytes, unsigned int size);
-       int (*put)(const unsigned int __user *bytes, unsigned int size);
+       int (*get)(struct snd_kcontrol *kcontrol, unsigned int __user *bytes,
+                                                       unsigned int size);
+       int (*put)(struct snd_kcontrol *kcontrol,
+                       const unsigned int __user *bytes, unsigned int size);
 };
 
 /*
index a8b4b9c8b1d2415e7220913715fc2cd4bd95212c..7afb72ceac5628b5efbdb616bde8e123580e3260 100644 (file)
        .put = snd_soc_put_volsw, \
        .private_value = SOC_DOUBLE_VALUE(reg, shift_left, shift_right, \
                                          max, invert, 0) }
+#define SOC_DOUBLE_STS(xname, reg, shift_left, shift_right, max, invert) \
+{                                                                      \
+       .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname),           \
+       .info = snd_soc_info_volsw, .get = snd_soc_get_volsw,           \
+       .access = SNDRV_CTL_ELEM_ACCESS_READ |                          \
+               SNDRV_CTL_ELEM_ACCESS_VOLATILE,                         \
+       .private_value = SOC_DOUBLE_VALUE(reg, shift_left, shift_right, \
+                                         max, invert, 0) }
 #define SOC_DOUBLE_R(xname, reg_left, reg_right, xshift, xmax, xinvert) \
 {      .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname), \
        .info = snd_soc_info_volsw, \
                {.base = xbase, .num_regs = xregs,            \
                 .mask = xmask }) }
 
+/*
+ * SND_SOC_BYTES_EXT is deprecated, please USE SND_SOC_BYTES_TLV instead
+ */
 #define SND_SOC_BYTES_EXT(xname, xcount, xhandler_get, xhandler_put) \
 {      .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
        .info = snd_soc_bytes_info_ext, \
@@ -787,6 +798,7 @@ struct snd_soc_component {
        unsigned int registered_as_component:1;
 
        struct list_head list;
+       struct list_head list_aux; /* for auxiliary component of the card */
 
        struct snd_soc_dai_driver *dai_drv;
        int num_dai;
@@ -830,6 +842,9 @@ struct snd_soc_component {
        int (*probe)(struct snd_soc_component *);
        void (*remove)(struct snd_soc_component *);
 
+       /* machine specific init */
+       int (*init)(struct snd_soc_component *component);
+
 #ifdef CONFIG_DEBUG_FS
        void (*init_debugfs)(struct snd_soc_component *component);
        const char *debugfs_prefix;
@@ -1037,6 +1052,9 @@ struct snd_soc_dai_link {
 
        /* pmdown_time is ignored at stop */
        unsigned int ignore_pmdown_time:1;
+
+       struct list_head list; /* DAI link list of the soc card */
+       struct snd_soc_dobj dobj; /* For topology */
 };
 
 struct snd_soc_codec_conf {
@@ -1101,12 +1119,20 @@ struct snd_soc_card {
                                   struct snd_soc_dapm_context *dapm,
                                   enum snd_soc_bias_level level);
 
+       int (*add_dai_link)(struct snd_soc_card *,
+                           struct snd_soc_dai_link *link);
+       void (*remove_dai_link)(struct snd_soc_card *,
+                           struct snd_soc_dai_link *link);
+
        long pmdown_time;
 
        /* CPU <--> Codec DAI links  */
-       struct snd_soc_dai_link *dai_link;
-       int num_links;
-       struct snd_soc_pcm_runtime *rtd;
+       struct snd_soc_dai_link *dai_link;  /* predefined links only */
+       int num_links;  /* predefined links only */
+       struct list_head dai_link_list; /* all links */
+       int num_dai_links;
+
+       struct list_head rtd_list;
        int num_rtd;
 
        /* optional codec specific configuration */
@@ -1119,8 +1145,7 @@ struct snd_soc_card {
         */
        struct snd_soc_aux_dev *aux_dev;
        int num_aux_devs;
-       struct snd_soc_pcm_runtime *rtd_aux;
-       int num_aux_rtd;
+       struct list_head aux_comp_list;
 
        const struct snd_kcontrol_new *controls;
        int num_controls;
@@ -1201,6 +1226,9 @@ struct snd_soc_pcm_runtime {
        struct dentry *debugfs_dpcm_root;
        struct dentry *debugfs_dpcm_state;
 #endif
+
+       unsigned int num; /* 0-based and monotonic increasing */
+       struct list_head list; /* rtd list of the soc card */
 };
 
 /* mixer control */
@@ -1225,8 +1253,10 @@ struct soc_bytes_ext {
        struct snd_soc_dobj dobj;
 
        /* used for TLV byte control */
-       int (*get)(unsigned int __user *bytes, unsigned int size);
-       int (*put)(const unsigned int __user *bytes, unsigned int size);
+       int (*get)(struct snd_kcontrol *kcontrol, unsigned int __user *bytes,
+                       unsigned int size);
+       int (*put)(struct snd_kcontrol *kcontrol, const unsigned int __user *bytes,
+                       unsigned int size);
 };
 
 /* multi register control */
@@ -1523,6 +1553,7 @@ static inline void snd_soc_initialize_card_lists(struct snd_soc_card *card)
        INIT_LIST_HEAD(&card->widgets);
        INIT_LIST_HEAD(&card->paths);
        INIT_LIST_HEAD(&card->dapm_list);
+       INIT_LIST_HEAD(&card->aux_comp_list);
 }
 
 static inline bool snd_soc_volsw_is_stereo(struct soc_mixer_control *mc)
@@ -1644,6 +1675,14 @@ int snd_soc_of_get_dai_link_codecs(struct device *dev,
                                   struct device_node *of_node,
                                   struct snd_soc_dai_link *dai_link);
 
+int snd_soc_add_dai_link(struct snd_soc_card *card,
+                               struct snd_soc_dai_link *dai_link);
+void snd_soc_remove_dai_link(struct snd_soc_card *card,
+                            struct snd_soc_dai_link *dai_link);
+
+int snd_soc_register_dai(struct snd_soc_component *component,
+       struct snd_soc_dai_driver *dai_drv);
+
 #include <sound/soc-dai.h>
 
 #ifdef CONFIG_DEBUG_FS
@@ -1655,7 +1694,7 @@ extern const struct dev_pm_ops snd_soc_pm_ops;
 /* Helper functions */
 static inline void snd_soc_dapm_mutex_lock(struct snd_soc_dapm_context *dapm)
 {
-       mutex_lock(&dapm->card->dapm_mutex);
+       mutex_lock_nested(&dapm->card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME);
 }
 
 static inline void snd_soc_dapm_mutex_unlock(struct snd_soc_dapm_context *dapm)
index 0a2c74008e5388f6d817272735882f40abc3a013..aabf0aca017157a72dd84accb5975c87fe98e79b 100644 (file)
@@ -474,7 +474,7 @@ struct se_cmd {
        struct completion       cmd_wait_comp;
        const struct target_core_fabric_ops *se_tfo;
        sense_reason_t          (*execute_cmd)(struct se_cmd *);
-       sense_reason_t (*transport_complete_callback)(struct se_cmd *, bool);
+       sense_reason_t (*transport_complete_callback)(struct se_cmd *, bool, int *);
        void                    *protocol_data;
 
        unsigned char           *t_task_cdb;
index 628e6e64c2fb4ff2c858a57e0beeca3aa4fd49b6..c2e5d6cb34e36ba2e409985c7d66c70347dbebc7 100644 (file)
@@ -186,6 +186,7 @@ header-y += if_tunnel.h
 header-y += if_vlan.h
 header-y += if_x25.h
 header-y += igmp.h
+header-y += ila.h
 header-y += in6.h
 header-y += inet_diag.h
 header-y += in.h
index 654bae3f1a389a4fcff05ba6098fcdd6d6b3204a..5e6296160361cc7b7a7b9d80411ef172c3a453c7 100644 (file)
 
 #define NFS_PIPE_DIRNAME "nfs"
 
-/* NFS ioctls */
-/* Let's follow btrfs lead on CLONE to avoid messing userspace */
-#define NFS_IOC_CLONE          _IOW(0x94, 9, int)
-#define NFS_IOC_CLONE_RANGE    _IOW(0x94, 13, int)
-
-struct nfs_ioctl_clone_range_args {
-       __s64 src_fd;
-       __u64 src_off, count;
-       __u64 dst_off;
-};
-
 /*
  * NFS stats. The good thing with these values is that NFSv3 errors are
  * a superset of NFSv2 errors (with the exception of NFSERR_WFLUSH which
index 28ccedd000f5720f6f41660ea6f049b9fd9f145c..a27222d5b413a85d4c773b5b43563bf9b57831d2 100644 (file)
@@ -628,7 +628,7 @@ struct ovs_action_hash {
  * @OVS_CT_ATTR_MARK: u32 value followed by u32 mask. For each bit set in the
  * mask, the corresponding bit in the value is copied to the connection
  * tracking mark field in the connection.
- * @OVS_CT_ATTR_LABEL: %OVS_CT_LABELS_LEN value followed by %OVS_CT_LABELS_LEN
+ * @OVS_CT_ATTR_LABELS: %OVS_CT_LABELS_LEN value followed by %OVS_CT_LABELS_LEN
  * mask. For each bit set in the mask, the corresponding bit in the value is
  * copied to the connection tracking label field in the connection.
  * @OVS_CT_ATTR_HELPER: variable length string defining conntrack ALG.
index 751b69f858c80411c910f21db7fb50c8902e94cf..9fd7b5d8df2fa357f434a899cccfa7810f826107 100644 (file)
 
 #define VFIO_SPAPR_TCE_v2_IOMMU                7
 
-/*
- * The No-IOMMU IOMMU offers no translation or isolation for devices and
- * supports no ioctls outside of VFIO_CHECK_EXTENSION.  Use of VFIO's No-IOMMU
- * code will taint the host kernel and should be used with extreme caution.
- */
-#define VFIO_NOIOMMU_IOMMU             8
-
 /*
  * The IOCTL interface is designed for extensibility by embedding the
  * structure length (argsz) and flags into structures passed between
index 26539a7e488081933f151c570220ff4561deec40..c4cc1e40b35c1343595d716b6b5b5e7d894226ce 100644 (file)
@@ -243,7 +243,7 @@ struct snd_soc_tplg_manifest {
        __le32 control_elems;   /* number of control elements */
        __le32 widget_elems;    /* number of widget elements */
        __le32 graph_elems;     /* number of graph elements */
-       __le32 dai_elems;       /* number of DAI elements */
+       __le32 pcm_elems;       /* number of PCM elements */
        __le32 dai_link_elems;  /* number of DAI link elements */
        struct snd_soc_tplg_private priv;
 } __attribute__((packed));
index d9bd9ca0d5b020519da8c8aebb3b93cc5a295c71..9625484a4a2a2a12e5ad8d00a759e27ea48a96b3 100644 (file)
@@ -73,7 +73,8 @@
 #define SND_AUDIOCODEC_IEC61937              ((__u32) 0x0000000B)
 #define SND_AUDIOCODEC_G723_1                ((__u32) 0x0000000C)
 #define SND_AUDIOCODEC_G729                  ((__u32) 0x0000000D)
-#define SND_AUDIOCODEC_MAX                   SND_AUDIOCODEC_G729
+#define SND_AUDIOCODEC_BESPOKE               ((__u32) 0x0000000E)
+#define SND_AUDIOCODEC_MAX                   SND_AUDIOCODEC_BESPOKE
 
 /*
  * Profile and modes are listed with bit masks. This allows for a
@@ -312,7 +313,7 @@ struct snd_enc_flac {
 
 struct snd_enc_generic {
        __u32 bw;       /* encoder bandwidth */
-       __s32 reserved[15];
+       __s32 reserved[15];     /* Can be used for SND_AUDIOCODEC_BESPOKE */
 } __attribute__((packed, aligned(4)));
 
 union snd_codec_options {
index 85dedca3dcfb04e738764023b673a7ba3d47926d..eeba75395f7d10b61fabf995d2b0157aec6d9ee5 100644 (file)
@@ -343,7 +343,6 @@ struct ipu_client_platformdata {
        int di;
        int dc;
        int dp;
-       int dmfc;
        int dma[2];
 };
 
index 7d28aff605c7eb600c4c3bfe93b8b5f1edbaebfe..7dc685b4057d33ad227d861a2a3115a5ca55cd3e 100644 (file)
@@ -181,6 +181,20 @@ struct __name##_back_ring {                                                \
 #define RING_GET_REQUEST(_r, _idx)                                     \
     (&((_r)->sring->ring[((_idx) & (RING_SIZE(_r) - 1))].req))
 
+/*
+ * Get a local copy of a request.
+ *
+ * Use this in preference to RING_GET_REQUEST() so all processing is
+ * done on a local copy that cannot be modified by the other end.
+ *
+ * Note that https://gcc.gnu.org/bugzilla/show_bug.cgi?id=58145 may cause this
+ * to be ineffective where _req is a struct which consists of only bitfields.
+ */
+#define RING_COPY_REQUEST(_r, _idx, _req) do {                         \
+       /* Use volatile to force the copy into _req. */                 \
+       *(_req) = *(volatile typeof(_req))RING_GET_REQUEST(_r, _idx);   \
+} while (0)
+
 #define RING_GET_RESPONSE(_r, _idx)                                    \
     (&((_r)->sring->ring[((_idx) & (RING_SIZE(_r) - 1))].rsp))
 
index c24b6f767bf0f2a4d8a873388a5fbd59ba01c562..235c7a2c0d2004f1121b7d98f4140683ab45ef53 100644 (file)
@@ -2030,13 +2030,6 @@ config INIT_ALL_POSSIBLE
          it was better to provide this option than to break all the archs
          and have several arch maintainers pursuing me down dark alleys.
 
-config STOP_MACHINE
-       bool
-       default y
-       depends on (SMP && MODULE_UNLOAD) || HOTPLUG_CPU
-       help
-         Need stop_machine() primitive.
-
 source "block/Kconfig"
 
 config PREEMPT_NOTIFIERS
index 3f4c99e06c6bbf8a5e28f882633e8161f3974929..b0799bced518691bd847a16973be74184bcdcbaf 100644 (file)
@@ -28,11 +28,17 @@ static struct bpf_map *array_map_alloc(union bpf_attr *attr)
            attr->value_size == 0)
                return ERR_PTR(-EINVAL);
 
+       if (attr->value_size >= 1 << (KMALLOC_SHIFT_MAX - 1))
+               /* if value_size is bigger, the user space won't be able to
+                * access the elements.
+                */
+               return ERR_PTR(-E2BIG);
+
        elem_size = round_up(attr->value_size, 8);
 
        /* check round_up into zero and u32 overflow */
        if (elem_size == 0 ||
-           attr->max_entries > (U32_MAX - sizeof(*array)) / elem_size)
+           attr->max_entries > (U32_MAX - PAGE_SIZE - sizeof(*array)) / elem_size)
                return ERR_PTR(-ENOMEM);
 
        array_size = sizeof(*array) + attr->max_entries * elem_size;
@@ -105,7 +111,7 @@ static int array_map_update_elem(struct bpf_map *map, void *key, void *value,
                /* all elements already exist */
                return -EEXIST;
 
-       memcpy(array->value + array->elem_size * index, value, array->elem_size);
+       memcpy(array->value + array->elem_size * index, value, map->value_size);
        return 0;
 }
 
index 19909b22b4f8398d7373cc3838b835728265ed23..34777b3746fadf6407ca9805f33df608be619f21 100644 (file)
@@ -64,12 +64,35 @@ static struct bpf_map *htab_map_alloc(union bpf_attr *attr)
                 */
                goto free_htab;
 
-       err = -ENOMEM;
+       if (htab->map.value_size >= (1 << (KMALLOC_SHIFT_MAX - 1)) -
+           MAX_BPF_STACK - sizeof(struct htab_elem))
+               /* if value_size is bigger, the user space won't be able to
+                * access the elements via bpf syscall. This check also makes
+                * sure that the elem_size doesn't overflow and it's
+                * kmalloc-able later in htab_map_update_elem()
+                */
+               goto free_htab;
+
+       htab->elem_size = sizeof(struct htab_elem) +
+                         round_up(htab->map.key_size, 8) +
+                         htab->map.value_size;
+
        /* prevent zero size kmalloc and check for u32 overflow */
        if (htab->n_buckets == 0 ||
            htab->n_buckets > U32_MAX / sizeof(struct hlist_head))
                goto free_htab;
 
+       if ((u64) htab->n_buckets * sizeof(struct hlist_head) +
+           (u64) htab->elem_size * htab->map.max_entries >=
+           U32_MAX - PAGE_SIZE)
+               /* make sure page count doesn't overflow */
+               goto free_htab;
+
+       htab->map.pages = round_up(htab->n_buckets * sizeof(struct hlist_head) +
+                                  htab->elem_size * htab->map.max_entries,
+                                  PAGE_SIZE) >> PAGE_SHIFT;
+
+       err = -ENOMEM;
        htab->buckets = kmalloc_array(htab->n_buckets, sizeof(struct hlist_head),
                                      GFP_USER | __GFP_NOWARN);
 
@@ -85,13 +108,6 @@ static struct bpf_map *htab_map_alloc(union bpf_attr *attr)
        raw_spin_lock_init(&htab->lock);
        htab->count = 0;
 
-       htab->elem_size = sizeof(struct htab_elem) +
-                         round_up(htab->map.key_size, 8) +
-                         htab->map.value_size;
-
-       htab->map.pages = round_up(htab->n_buckets * sizeof(struct hlist_head) +
-                                  htab->elem_size * htab->map.max_entries,
-                                  PAGE_SIZE) >> PAGE_SHIFT;
        return &htab->map;
 
 free_htab:
@@ -222,7 +238,7 @@ static int htab_map_update_elem(struct bpf_map *map, void *key, void *value,
        WARN_ON_ONCE(!rcu_read_lock_held());
 
        /* allocate new element outside of lock */
-       l_new = kmalloc(htab->elem_size, GFP_ATOMIC);
+       l_new = kmalloc(htab->elem_size, GFP_ATOMIC | __GFP_NOWARN);
        if (!l_new)
                return -ENOMEM;
 
index be6d726e31c9429860141925130d0e5c71011e7b..5a8a797d50b74a8bb698760856c1849ff9bcc084 100644 (file)
@@ -34,7 +34,7 @@ static void *bpf_any_get(void *raw, enum bpf_type type)
                atomic_inc(&((struct bpf_prog *)raw)->aux->refcnt);
                break;
        case BPF_TYPE_MAP:
-               atomic_inc(&((struct bpf_map *)raw)->refcnt);
+               bpf_map_inc(raw, true);
                break;
        default:
                WARN_ON_ONCE(1);
@@ -51,7 +51,7 @@ static void bpf_any_put(void *raw, enum bpf_type type)
                bpf_prog_put(raw);
                break;
        case BPF_TYPE_MAP:
-               bpf_map_put(raw);
+               bpf_map_put_with_uref(raw);
                break;
        default:
                WARN_ON_ONCE(1);
@@ -64,7 +64,7 @@ static void *bpf_fd_probe_obj(u32 ufd, enum bpf_type *type)
        void *raw;
 
        *type = BPF_TYPE_MAP;
-       raw = bpf_map_get(ufd);
+       raw = bpf_map_get_with_uref(ufd);
        if (IS_ERR(raw)) {
                *type = BPF_TYPE_PROG;
                raw = bpf_prog_get(ufd);
index 0d3313d02a7e512e1ca7f58fb52aa3e39bae60a3..3b39550d84856494d43aefe926457add41d2a435 100644 (file)
@@ -82,6 +82,14 @@ static void bpf_map_free_deferred(struct work_struct *work)
        map->ops->map_free(map);
 }
 
+static void bpf_map_put_uref(struct bpf_map *map)
+{
+       if (atomic_dec_and_test(&map->usercnt)) {
+               if (map->map_type == BPF_MAP_TYPE_PROG_ARRAY)
+                       bpf_fd_array_map_clear(map);
+       }
+}
+
 /* decrement map refcnt and schedule it for freeing via workqueue
  * (unrelying map implementation ops->map_free() might sleep)
  */
@@ -93,17 +101,15 @@ void bpf_map_put(struct bpf_map *map)
        }
 }
 
-static int bpf_map_release(struct inode *inode, struct file *filp)
+void bpf_map_put_with_uref(struct bpf_map *map)
 {
-       struct bpf_map *map = filp->private_data;
-
-       if (map->map_type == BPF_MAP_TYPE_PROG_ARRAY)
-               /* prog_array stores refcnt-ed bpf_prog pointers
-                * release them all when user space closes prog_array_fd
-                */
-               bpf_fd_array_map_clear(map);
-
+       bpf_map_put_uref(map);
        bpf_map_put(map);
+}
+
+static int bpf_map_release(struct inode *inode, struct file *filp)
+{
+       bpf_map_put_with_uref(filp->private_data);
        return 0;
 }
 
@@ -142,6 +148,7 @@ static int map_create(union bpf_attr *attr)
                return PTR_ERR(map);
 
        atomic_set(&map->refcnt, 1);
+       atomic_set(&map->usercnt, 1);
 
        err = bpf_map_charge_memlock(map);
        if (err)
@@ -174,7 +181,14 @@ struct bpf_map *__bpf_map_get(struct fd f)
        return f.file->private_data;
 }
 
-struct bpf_map *bpf_map_get(u32 ufd)
+void bpf_map_inc(struct bpf_map *map, bool uref)
+{
+       atomic_inc(&map->refcnt);
+       if (uref)
+               atomic_inc(&map->usercnt);
+}
+
+struct bpf_map *bpf_map_get_with_uref(u32 ufd)
 {
        struct fd f = fdget(ufd);
        struct bpf_map *map;
@@ -183,7 +197,7 @@ struct bpf_map *bpf_map_get(u32 ufd)
        if (IS_ERR(map))
                return map;
 
-       atomic_inc(&map->refcnt);
+       bpf_map_inc(map, true);
        fdput(f);
 
        return map;
@@ -226,7 +240,7 @@ static int map_lookup_elem(union bpf_attr *attr)
                goto free_key;
 
        err = -ENOMEM;
-       value = kmalloc(map->value_size, GFP_USER);
+       value = kmalloc(map->value_size, GFP_USER | __GFP_NOWARN);
        if (!value)
                goto free_key;
 
@@ -285,7 +299,7 @@ static int map_update_elem(union bpf_attr *attr)
                goto free_key;
 
        err = -ENOMEM;
-       value = kmalloc(map->value_size, GFP_USER);
+       value = kmalloc(map->value_size, GFP_USER | __GFP_NOWARN);
        if (!value)
                goto free_key;
 
index c6073056badf02293c7e9d1e35dce9bb88536c67..a7945d10b378bed8eb7243bd52923d232b1f49de 100644 (file)
@@ -2021,8 +2021,7 @@ static int replace_map_fd_with_map_ptr(struct verifier_env *env)
                         * will be used by the valid program until it's unloaded
                         * and all maps are released in free_bpf_prog_info()
                         */
-                       atomic_inc(&map->refcnt);
-
+                       bpf_map_inc(map, false);
                        fdput(f);
 next_insn:
                        insn++;
index f1603c153890d2b9dbd37a5c687fd297c6137f24..470f6536b9e8cfb029eedb5ecdb3c3e8c3c341be 100644 (file)
@@ -97,6 +97,12 @@ static DEFINE_SPINLOCK(css_set_lock);
  */
 static DEFINE_SPINLOCK(cgroup_idr_lock);
 
+/*
+ * Protects cgroup_file->kn for !self csses.  It synchronizes notifications
+ * against file removal/re-creation across css hiding.
+ */
+static DEFINE_SPINLOCK(cgroup_file_kn_lock);
+
 /*
  * Protects cgroup_subsys->release_agent_path.  Modifying it also requires
  * cgroup_mutex.  Reading requires either cgroup_mutex or this spinlock.
@@ -754,9 +760,11 @@ static void put_css_set_locked(struct css_set *cset)
        if (!atomic_dec_and_test(&cset->refcount))
                return;
 
-       /* This css_set is dead. unlink it and release cgroup refcounts */
-       for_each_subsys(ss, ssid)
+       /* This css_set is dead. unlink it and release cgroup and css refs */
+       for_each_subsys(ss, ssid) {
                list_del(&cset->e_cset_node[ssid]);
+               css_put(cset->subsys[ssid]);
+       }
        hash_del(&cset->hlist);
        css_set_count--;
 
@@ -1056,9 +1064,13 @@ static struct css_set *find_css_set(struct css_set *old_cset,
        key = css_set_hash(cset->subsys);
        hash_add(css_set_table, &cset->hlist, key);
 
-       for_each_subsys(ss, ssid)
+       for_each_subsys(ss, ssid) {
+               struct cgroup_subsys_state *css = cset->subsys[ssid];
+
                list_add_tail(&cset->e_cset_node[ssid],
-                             &cset->subsys[ssid]->cgroup->e_csets[ssid]);
+                             &css->cgroup->e_csets[ssid]);
+               css_get(css);
+       }
 
        spin_unlock_bh(&css_set_lock);
 
@@ -1393,6 +1405,16 @@ static void cgroup_rm_file(struct cgroup *cgrp, const struct cftype *cft)
        char name[CGROUP_FILE_NAME_MAX];
 
        lockdep_assert_held(&cgroup_mutex);
+
+       if (cft->file_offset) {
+               struct cgroup_subsys_state *css = cgroup_css(cgrp, cft->ss);
+               struct cgroup_file *cfile = (void *)css + cft->file_offset;
+
+               spin_lock_irq(&cgroup_file_kn_lock);
+               cfile->kn = NULL;
+               spin_unlock_irq(&cgroup_file_kn_lock);
+       }
+
        kernfs_remove_by_name(cgrp->kn, cgroup_file_name(cgrp, cft, name));
 }
 
@@ -1856,7 +1878,6 @@ static void init_cgroup_housekeeping(struct cgroup *cgrp)
 
        INIT_LIST_HEAD(&cgrp->self.sibling);
        INIT_LIST_HEAD(&cgrp->self.children);
-       INIT_LIST_HEAD(&cgrp->self.files);
        INIT_LIST_HEAD(&cgrp->cset_links);
        INIT_LIST_HEAD(&cgrp->pidlists);
        mutex_init(&cgrp->pidlist_mutex);
@@ -2216,6 +2237,9 @@ struct cgroup_taskset {
        struct list_head        src_csets;
        struct list_head        dst_csets;
 
+       /* the subsys currently being processed */
+       int                     ssid;
+
        /*
         * Fields for cgroup_taskset_*() iteration.
         *
@@ -2278,25 +2302,29 @@ static void cgroup_taskset_add(struct task_struct *task,
 /**
  * cgroup_taskset_first - reset taskset and return the first task
  * @tset: taskset of interest
+ * @dst_cssp: output variable for the destination css
  *
  * @tset iteration is initialized and the first task is returned.
  */
-struct task_struct *cgroup_taskset_first(struct cgroup_taskset *tset)
+struct task_struct *cgroup_taskset_first(struct cgroup_taskset *tset,
+                                        struct cgroup_subsys_state **dst_cssp)
 {
        tset->cur_cset = list_first_entry(tset->csets, struct css_set, mg_node);
        tset->cur_task = NULL;
 
-       return cgroup_taskset_next(tset);
+       return cgroup_taskset_next(tset, dst_cssp);
 }
 
 /**
  * cgroup_taskset_next - iterate to the next task in taskset
  * @tset: taskset of interest
+ * @dst_cssp: output variable for the destination css
  *
  * Return the next task in @tset.  Iteration must have been initialized
  * with cgroup_taskset_first().
  */
-struct task_struct *cgroup_taskset_next(struct cgroup_taskset *tset)
+struct task_struct *cgroup_taskset_next(struct cgroup_taskset *tset,
+                                       struct cgroup_subsys_state **dst_cssp)
 {
        struct css_set *cset = tset->cur_cset;
        struct task_struct *task = tset->cur_task;
@@ -2311,6 +2339,18 @@ struct task_struct *cgroup_taskset_next(struct cgroup_taskset *tset)
                if (&task->cg_list != &cset->mg_tasks) {
                        tset->cur_cset = cset;
                        tset->cur_task = task;
+
+                       /*
+                        * This function may be called both before and
+                        * after cgroup_taskset_migrate().  The two cases
+                        * can be distinguished by looking at whether @cset
+                        * has its ->mg_dst_cset set.
+                        */
+                       if (cset->mg_dst_cset)
+                               *dst_cssp = cset->mg_dst_cset->subsys[tset->ssid];
+                       else
+                               *dst_cssp = cset->subsys[tset->ssid];
+
                        return task;
                }
 
@@ -2346,7 +2386,8 @@ static int cgroup_taskset_migrate(struct cgroup_taskset *tset,
        /* check that we can legitimately attach to the cgroup */
        for_each_e_css(css, i, dst_cgrp) {
                if (css->ss->can_attach) {
-                       ret = css->ss->can_attach(css, tset);
+                       tset->ssid = i;
+                       ret = css->ss->can_attach(tset);
                        if (ret) {
                                failed_css = css;
                                goto out_cancel_attach;
@@ -2379,9 +2420,12 @@ static int cgroup_taskset_migrate(struct cgroup_taskset *tset,
         */
        tset->csets = &tset->dst_csets;
 
-       for_each_e_css(css, i, dst_cgrp)
-               if (css->ss->attach)
-                       css->ss->attach(css, tset);
+       for_each_e_css(css, i, dst_cgrp) {
+               if (css->ss->attach) {
+                       tset->ssid = i;
+                       css->ss->attach(tset);
+               }
+       }
 
        ret = 0;
        goto out_release_tset;
@@ -2390,8 +2434,10 @@ out_cancel_attach:
        for_each_e_css(css, i, dst_cgrp) {
                if (css == failed_css)
                        break;
-               if (css->ss->cancel_attach)
-                       css->ss->cancel_attach(css, tset);
+               if (css->ss->cancel_attach) {
+                       tset->ssid = i;
+                       css->ss->cancel_attach(tset);
+               }
        }
 out_release_tset:
        spin_lock_bh(&css_set_lock);
@@ -3313,9 +3359,9 @@ static int cgroup_add_file(struct cgroup_subsys_state *css, struct cgroup *cgrp,
        if (cft->file_offset) {
                struct cgroup_file *cfile = (void *)css + cft->file_offset;
 
-               kernfs_get(kn);
+               spin_lock_irq(&cgroup_file_kn_lock);
                cfile->kn = kn;
-               list_add(&cfile->node, &css->files);
+               spin_unlock_irq(&cgroup_file_kn_lock);
        }
 
        return 0;
@@ -3552,6 +3598,22 @@ int cgroup_add_legacy_cftypes(struct cgroup_subsys *ss, struct cftype *cfts)
        return cgroup_add_cftypes(ss, cfts);
 }
 
+/**
+ * cgroup_file_notify - generate a file modified event for a cgroup_file
+ * @cfile: target cgroup_file
+ *
+ * @cfile must have been obtained by setting cftype->file_offset.
+ */
+void cgroup_file_notify(struct cgroup_file *cfile)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&cgroup_file_kn_lock, flags);
+       if (cfile->kn)
+               kernfs_notify(cfile->kn);
+       spin_unlock_irqrestore(&cgroup_file_kn_lock, flags);
+}
+
 /**
  * cgroup_task_count - count the number of tasks in a cgroup.
  * @cgrp: the cgroup in question
@@ -4613,13 +4675,9 @@ static void css_free_work_fn(struct work_struct *work)
                container_of(work, struct cgroup_subsys_state, destroy_work);
        struct cgroup_subsys *ss = css->ss;
        struct cgroup *cgrp = css->cgroup;
-       struct cgroup_file *cfile;
 
        percpu_ref_exit(&css->refcnt);
 
-       list_for_each_entry(cfile, &css->files, node)
-               kernfs_put(cfile->kn);
-
        if (ss) {
                /* css free path */
                int id = css->id;
@@ -4724,7 +4782,6 @@ static void init_and_link_css(struct cgroup_subsys_state *css,
        css->ss = ss;
        INIT_LIST_HEAD(&css->sibling);
        INIT_LIST_HEAD(&css->children);
-       INIT_LIST_HEAD(&css->files);
        css->serial_nr = css_serial_nr_next++;
 
        if (cgroup_parent(cgrp)) {
index f1b30ad5dc6d925685f92ecbc0918b7c78018f30..2d3df82c54f2dd84484e0b4d739551cb69861e4e 100644 (file)
@@ -155,12 +155,10 @@ static void freezer_css_free(struct cgroup_subsys_state *css)
  * @freezer->lock.  freezer_attach() makes the new tasks conform to the
  * current state and all following state changes can see the new tasks.
  */
-static void freezer_attach(struct cgroup_subsys_state *new_css,
-                          struct cgroup_taskset *tset)
+static void freezer_attach(struct cgroup_taskset *tset)
 {
-       struct freezer *freezer = css_freezer(new_css);
        struct task_struct *task;
-       bool clear_frozen = false;
+       struct cgroup_subsys_state *new_css;
 
        mutex_lock(&freezer_mutex);
 
@@ -174,22 +172,21 @@ static void freezer_attach(struct cgroup_subsys_state *new_css,
         * current state before executing the following - !frozen tasks may
         * be visible in a FROZEN cgroup and frozen tasks in a THAWED one.
         */
-       cgroup_taskset_for_each(task, tset) {
+       cgroup_taskset_for_each(task, new_css, tset) {
+               struct freezer *freezer = css_freezer(new_css);
+
                if (!(freezer->state & CGROUP_FREEZING)) {
                        __thaw_task(task);
                } else {
                        freeze_task(task);
-                       freezer->state &= ~CGROUP_FROZEN;
-                       clear_frozen = true;
+                       /* clear FROZEN and propagate upwards */
+                       while (freezer && (freezer->state & CGROUP_FROZEN)) {
+                               freezer->state &= ~CGROUP_FROZEN;
+                               freezer = parent_freezer(freezer);
+                       }
                }
        }
 
-       /* propagate FROZEN clearing upwards */
-       while (clear_frozen && (freezer = parent_freezer(freezer))) {
-               freezer->state &= ~CGROUP_FROZEN;
-               clear_frozen = freezer->state & CGROUP_FREEZING;
-       }
-
        mutex_unlock(&freezer_mutex);
 }
 
index cdd8df4e991c7781ac5996677d724bcd23314623..b50d5a167fda7d2ae6902efd55e551efed780007 100644 (file)
@@ -106,7 +106,7 @@ static void pids_uncharge(struct pids_cgroup *pids, int num)
 {
        struct pids_cgroup *p;
 
-       for (p = pids; p; p = parent_pids(p))
+       for (p = pids; parent_pids(p); p = parent_pids(p))
                pids_cancel(p, num);
 }
 
@@ -123,7 +123,7 @@ static void pids_charge(struct pids_cgroup *pids, int num)
 {
        struct pids_cgroup *p;
 
-       for (p = pids; p; p = parent_pids(p))
+       for (p = pids; parent_pids(p); p = parent_pids(p))
                atomic64_add(num, &p->counter);
 }
 
@@ -140,7 +140,7 @@ static int pids_try_charge(struct pids_cgroup *pids, int num)
 {
        struct pids_cgroup *p, *q;
 
-       for (p = pids; p; p = parent_pids(p)) {
+       for (p = pids; parent_pids(p); p = parent_pids(p)) {
                int64_t new = atomic64_add_return(num, &p->counter);
 
                /*
@@ -162,13 +162,13 @@ revert:
        return -EAGAIN;
 }
 
-static int pids_can_attach(struct cgroup_subsys_state *css,
-                          struct cgroup_taskset *tset)
+static int pids_can_attach(struct cgroup_taskset *tset)
 {
-       struct pids_cgroup *pids = css_pids(css);
        struct task_struct *task;
+       struct cgroup_subsys_state *dst_css;
 
-       cgroup_taskset_for_each(task, tset) {
+       cgroup_taskset_for_each(task, dst_css, tset) {
+               struct pids_cgroup *pids = css_pids(dst_css);
                struct cgroup_subsys_state *old_css;
                struct pids_cgroup *old_pids;
 
@@ -187,13 +187,13 @@ static int pids_can_attach(struct cgroup_subsys_state *css,
        return 0;
 }
 
-static void pids_cancel_attach(struct cgroup_subsys_state *css,
-                              struct cgroup_taskset *tset)
+static void pids_cancel_attach(struct cgroup_taskset *tset)
 {
-       struct pids_cgroup *pids = css_pids(css);
        struct task_struct *task;
+       struct cgroup_subsys_state *dst_css;
 
-       cgroup_taskset_for_each(task, tset) {
+       cgroup_taskset_for_each(task, dst_css, tset) {
+               struct pids_cgroup *pids = css_pids(dst_css);
                struct cgroup_subsys_state *old_css;
                struct pids_cgroup *old_pids;
 
@@ -205,65 +205,28 @@ static void pids_cancel_attach(struct cgroup_subsys_state *css,
        }
 }
 
+/*
+ * task_css_check(true) in pids_can_fork() and pids_cancel_fork() relies
+ * on threadgroup_change_begin() held by the copy_process().
+ */
 static int pids_can_fork(struct task_struct *task, void **priv_p)
 {
        struct cgroup_subsys_state *css;
        struct pids_cgroup *pids;
-       int err;
 
-       /*
-        * Use the "current" task_css for the pids subsystem as the tentative
-        * css. It is possible we will charge the wrong hierarchy, in which
-        * case we will forcefully revert/reapply the charge on the right
-        * hierarchy after it is committed to the task proper.
-        */
-       css = task_get_css(current, pids_cgrp_id);
+       css = task_css_check(current, pids_cgrp_id, true);
        pids = css_pids(css);
-
-       err = pids_try_charge(pids, 1);
-       if (err)
-               goto err_css_put;
-
-       *priv_p = css;
-       return 0;
-
-err_css_put:
-       css_put(css);
-       return err;
+       return pids_try_charge(pids, 1);
 }
 
 static void pids_cancel_fork(struct task_struct *task, void *priv)
-{
-       struct cgroup_subsys_state *css = priv;
-       struct pids_cgroup *pids = css_pids(css);
-
-       pids_uncharge(pids, 1);
-       css_put(css);
-}
-
-static void pids_fork(struct task_struct *task, void *priv)
 {
        struct cgroup_subsys_state *css;
-       struct cgroup_subsys_state *old_css = priv;
        struct pids_cgroup *pids;
-       struct pids_cgroup *old_pids = css_pids(old_css);
 
-       css = task_get_css(task, pids_cgrp_id);
+       css = task_css_check(current, pids_cgrp_id, true);
        pids = css_pids(css);
-
-       /*
-        * If the association has changed, we have to revert and reapply the
-        * charge/uncharge on the wrong hierarchy to the current one. Since
-        * the association can only change due to an organisation event, its
-        * okay for us to ignore the limit in this case.
-        */
-       if (pids != old_pids) {
-               pids_uncharge(old_pids, 1);
-               pids_charge(pids, 1);
-       }
-
-       css_put(css);
-       css_put(old_css);
+       pids_uncharge(pids, 1);
 }
 
 static void pids_free(struct task_struct *task)
@@ -335,6 +298,7 @@ static struct cftype pids_files[] = {
        {
                .name = "current",
                .read_s64 = pids_current_read,
+               .flags = CFTYPE_NOT_ON_ROOT,
        },
        { }     /* terminate */
 };
@@ -346,7 +310,6 @@ struct cgroup_subsys pids_cgrp_subsys = {
        .cancel_attach  = pids_cancel_attach,
        .can_fork       = pids_can_fork,
        .cancel_fork    = pids_cancel_fork,
-       .fork           = pids_fork,
        .free           = pids_free,
        .legacy_cftypes = pids_files,
        .dfl_cftypes    = pids_files,
index 10ae73611d80a560977aa554d6cbedee78bec19a..02a8ea5c99632907b2ae887015c59bd4ad35da9d 100644 (file)
@@ -1429,15 +1429,16 @@ static int fmeter_getrate(struct fmeter *fmp)
 static struct cpuset *cpuset_attach_old_cs;
 
 /* Called by cgroups to determine if a cpuset is usable; cpuset_mutex held */
-static int cpuset_can_attach(struct cgroup_subsys_state *css,
-                            struct cgroup_taskset *tset)
+static int cpuset_can_attach(struct cgroup_taskset *tset)
 {
-       struct cpuset *cs = css_cs(css);
+       struct cgroup_subsys_state *css;
+       struct cpuset *cs;
        struct task_struct *task;
        int ret;
 
        /* used later by cpuset_attach() */
-       cpuset_attach_old_cs = task_cs(cgroup_taskset_first(tset));
+       cpuset_attach_old_cs = task_cs(cgroup_taskset_first(tset, &css));
+       cs = css_cs(css);
 
        mutex_lock(&cpuset_mutex);
 
@@ -1447,7 +1448,7 @@ static int cpuset_can_attach(struct cgroup_subsys_state *css,
            (cpumask_empty(cs->cpus_allowed) || nodes_empty(cs->mems_allowed)))
                goto out_unlock;
 
-       cgroup_taskset_for_each(task, tset) {
+       cgroup_taskset_for_each(task, css, tset) {
                ret = task_can_attach(task, cs->cpus_allowed);
                if (ret)
                        goto out_unlock;
@@ -1467,9 +1468,14 @@ out_unlock:
        return ret;
 }
 
-static void cpuset_cancel_attach(struct cgroup_subsys_state *css,
-                                struct cgroup_taskset *tset)
+static void cpuset_cancel_attach(struct cgroup_taskset *tset)
 {
+       struct cgroup_subsys_state *css;
+       struct cpuset *cs;
+
+       cgroup_taskset_first(tset, &css);
+       cs = css_cs(css);
+
        mutex_lock(&cpuset_mutex);
        css_cs(css)->attach_in_progress--;
        mutex_unlock(&cpuset_mutex);
@@ -1482,16 +1488,19 @@ static void cpuset_cancel_attach(struct cgroup_subsys_state *css,
  */
 static cpumask_var_t cpus_attach;
 
-static void cpuset_attach(struct cgroup_subsys_state *css,
-                         struct cgroup_taskset *tset)
+static void cpuset_attach(struct cgroup_taskset *tset)
 {
        /* static buf protected by cpuset_mutex */
        static nodemask_t cpuset_attach_nodemask_to;
        struct task_struct *task;
        struct task_struct *leader;
-       struct cpuset *cs = css_cs(css);
+       struct cgroup_subsys_state *css;
+       struct cpuset *cs;
        struct cpuset *oldcs = cpuset_attach_old_cs;
 
+       cgroup_taskset_first(tset, &css);
+       cs = css_cs(css);
+
        mutex_lock(&cpuset_mutex);
 
        /* prepare for attach */
@@ -1502,7 +1511,7 @@ static void cpuset_attach(struct cgroup_subsys_state *css,
 
        guarantee_online_mems(cs, &cpuset_attach_nodemask_to);
 
-       cgroup_taskset_for_each(task, tset) {
+       cgroup_taskset_for_each(task, css, tset) {
                /*
                 * can_attach beforehand should guarantee that this doesn't
                 * fail.  TODO: have a better way to handle failure here
@@ -1518,7 +1527,7 @@ static void cpuset_attach(struct cgroup_subsys_state *css,
         * sleep and should be moved outside migration path proper.
         */
        cpuset_attach_nodemask_to = cs->effective_mems;
-       cgroup_taskset_for_each_leader(leader, tset) {
+       cgroup_taskset_for_each_leader(leader, css, tset) {
                struct mm_struct *mm = get_task_mm(leader);
 
                if (mm) {
index d659487254d5d77de07f279ceb0ba0bebe93ed03..9c418002b8c1fa15217b3390250453b492849344 100644 (file)
@@ -3,7 +3,7 @@
  *
  *  Copyright (C) 2008 Thomas Gleixner <tglx@linutronix.de>
  *  Copyright (C) 2008-2011 Red Hat, Inc., Ingo Molnar
- *  Copyright (C) 2008-2011 Red Hat, Inc., Peter Zijlstra <pzijlstr@redhat.com>
+ *  Copyright (C) 2008-2011 Red Hat, Inc., Peter Zijlstra
  *  Copyright  Â©  2009 Paul Mackerras, IBM Corp. <paulus@au1.ibm.com>
  *
  * For licensing details see kernel-base/COPYING
index 36babfd2064842c28d4951a656ea1e84500bbf8f..ef2d6ea10736e4805e758cae83524dc13c2f06e9 100644 (file)
@@ -3,7 +3,7 @@
  *
  *  Copyright (C) 2008 Thomas Gleixner <tglx@linutronix.de>
  *  Copyright (C) 2008-2011 Red Hat, Inc., Ingo Molnar
- *  Copyright (C) 2008-2011 Red Hat, Inc., Peter Zijlstra <pzijlstr@redhat.com>
+ *  Copyright (C) 2008-2011 Red Hat, Inc., Peter Zijlstra
  *  Copyright  Â©  2009 Paul Mackerras, IBM Corp. <paulus@au1.ibm.com>
  *
  * For licensing details see kernel-base/COPYING
@@ -435,7 +435,7 @@ static inline void update_cgrp_time_from_event(struct perf_event *event)
        if (!is_cgroup_event(event))
                return;
 
-       cgrp = perf_cgroup_from_task(current);
+       cgrp = perf_cgroup_from_task(current, event->ctx);
        /*
         * Do not update time when cgroup is not active
         */
@@ -458,7 +458,7 @@ perf_cgroup_set_timestamp(struct task_struct *task,
        if (!task || !ctx->nr_cgroups)
                return;
 
-       cgrp = perf_cgroup_from_task(task);
+       cgrp = perf_cgroup_from_task(task, ctx);
        info = this_cpu_ptr(cgrp->info);
        info->timestamp = ctx->timestamp;
 }
@@ -489,7 +489,6 @@ static void perf_cgroup_switch(struct task_struct *task, int mode)
         * we reschedule only in the presence of cgroup
         * constrained events.
         */
-       rcu_read_lock();
 
        list_for_each_entry_rcu(pmu, &pmus, entry) {
                cpuctx = this_cpu_ptr(pmu->pmu_cpu_context);
@@ -522,8 +521,10 @@ static void perf_cgroup_switch(struct task_struct *task, int mode)
                                 * set cgrp before ctxsw in to allow
                                 * event_filter_match() to not have to pass
                                 * task around
+                                * we pass the cpuctx->ctx to perf_cgroup_from_task()
+                                * because cgorup events are only per-cpu
                                 */
-                               cpuctx->cgrp = perf_cgroup_from_task(task);
+                               cpuctx->cgrp = perf_cgroup_from_task(task, &cpuctx->ctx);
                                cpu_ctx_sched_in(cpuctx, EVENT_ALL, task);
                        }
                        perf_pmu_enable(cpuctx->ctx.pmu);
@@ -531,8 +532,6 @@ static void perf_cgroup_switch(struct task_struct *task, int mode)
                }
        }
 
-       rcu_read_unlock();
-
        local_irq_restore(flags);
 }
 
@@ -542,17 +541,20 @@ static inline void perf_cgroup_sched_out(struct task_struct *task,
        struct perf_cgroup *cgrp1;
        struct perf_cgroup *cgrp2 = NULL;
 
+       rcu_read_lock();
        /*
         * we come here when we know perf_cgroup_events > 0
+        * we do not need to pass the ctx here because we know
+        * we are holding the rcu lock
         */
-       cgrp1 = perf_cgroup_from_task(task);
+       cgrp1 = perf_cgroup_from_task(task, NULL);
 
        /*
         * next is NULL when called from perf_event_enable_on_exec()
         * that will systematically cause a cgroup_switch()
         */
        if (next)
-               cgrp2 = perf_cgroup_from_task(next);
+               cgrp2 = perf_cgroup_from_task(next, NULL);
 
        /*
         * only schedule out current cgroup events if we know
@@ -561,6 +563,8 @@ static inline void perf_cgroup_sched_out(struct task_struct *task,
         */
        if (cgrp1 != cgrp2)
                perf_cgroup_switch(task, PERF_CGROUP_SWOUT);
+
+       rcu_read_unlock();
 }
 
 static inline void perf_cgroup_sched_in(struct task_struct *prev,
@@ -569,13 +573,16 @@ static inline void perf_cgroup_sched_in(struct task_struct *prev,
        struct perf_cgroup *cgrp1;
        struct perf_cgroup *cgrp2 = NULL;
 
+       rcu_read_lock();
        /*
         * we come here when we know perf_cgroup_events > 0
+        * we do not need to pass the ctx here because we know
+        * we are holding the rcu lock
         */
-       cgrp1 = perf_cgroup_from_task(task);
+       cgrp1 = perf_cgroup_from_task(task, NULL);
 
        /* prev can never be NULL */
-       cgrp2 = perf_cgroup_from_task(prev);
+       cgrp2 = perf_cgroup_from_task(prev, NULL);
 
        /*
         * only need to schedule in cgroup events if we are changing
@@ -584,6 +591,8 @@ static inline void perf_cgroup_sched_in(struct task_struct *prev,
         */
        if (cgrp1 != cgrp2)
                perf_cgroup_switch(task, PERF_CGROUP_SWIN);
+
+       rcu_read_unlock();
 }
 
 static inline int perf_cgroup_connect(int fd, struct perf_event *event,
@@ -4216,7 +4225,14 @@ retry:
                goto retry;
        }
 
-       __perf_event_period(&pe);
+       if (event->attr.freq) {
+               event->attr.sample_freq = value;
+       } else {
+               event->attr.sample_period = value;
+               event->hw.sample_period = value;
+       }
+
+       local64_set(&event->hw.period_left, 0);
        raw_spin_unlock_irq(&ctx->lock);
 
        return 0;
@@ -5666,6 +5682,17 @@ perf_event_aux_ctx(struct perf_event_context *ctx,
        }
 }
 
+static void
+perf_event_aux_task_ctx(perf_event_aux_output_cb output, void *data,
+                       struct perf_event_context *task_ctx)
+{
+       rcu_read_lock();
+       preempt_disable();
+       perf_event_aux_ctx(task_ctx, output, data);
+       preempt_enable();
+       rcu_read_unlock();
+}
+
 static void
 perf_event_aux(perf_event_aux_output_cb output, void *data,
               struct perf_event_context *task_ctx)
@@ -5675,14 +5702,23 @@ perf_event_aux(perf_event_aux_output_cb output, void *data,
        struct pmu *pmu;
        int ctxn;
 
+       /*
+        * If we have task_ctx != NULL we only notify
+        * the task context itself. The task_ctx is set
+        * only for EXIT events before releasing task
+        * context.
+        */
+       if (task_ctx) {
+               perf_event_aux_task_ctx(output, data, task_ctx);
+               return;
+       }
+
        rcu_read_lock();
        list_for_each_entry_rcu(pmu, &pmus, entry) {
                cpuctx = get_cpu_ptr(pmu->pmu_cpu_context);
                if (cpuctx->unique_pmu != pmu)
                        goto next;
                perf_event_aux_ctx(&cpuctx->ctx, output, data);
-               if (task_ctx)
-                       goto next;
                ctxn = pmu->task_ctx_nr;
                if (ctxn < 0)
                        goto next;
@@ -5692,12 +5728,6 @@ perf_event_aux(perf_event_aux_output_cb output, void *data,
 next:
                put_cpu_ptr(pmu->pmu_cpu_context);
        }
-
-       if (task_ctx) {
-               preempt_disable();
-               perf_event_aux_ctx(task_ctx, output, data);
-               preempt_enable();
-       }
        rcu_read_unlock();
 }
 
@@ -8787,10 +8817,8 @@ static void perf_event_exit_task_context(struct task_struct *child, int ctxn)
        struct perf_event_context *child_ctx, *clone_ctx = NULL;
        unsigned long flags;
 
-       if (likely(!child->perf_event_ctxp[ctxn])) {
-               perf_event_task(child, NULL, 0);
+       if (likely(!child->perf_event_ctxp[ctxn]))
                return;
-       }
 
        local_irq_save(flags);
        /*
@@ -8874,6 +8902,14 @@ void perf_event_exit_task(struct task_struct *child)
 
        for_each_task_context_nr(ctxn)
                perf_event_exit_task_context(child, ctxn);
+
+       /*
+        * The perf_event_exit_task_context calls perf_event_task
+        * with child's task_ctx, which generates EXIT events for
+        * child contexts and sets child->perf_event_ctxp[] to NULL.
+        * At this point we need to send EXIT events to cpu contexts.
+        */
+       perf_event_task(child, NULL, 0);
 }
 
 static void perf_free_event(struct perf_event *event,
@@ -9452,16 +9488,18 @@ static void perf_cgroup_css_free(struct cgroup_subsys_state *css)
 static int __perf_cgroup_move(void *info)
 {
        struct task_struct *task = info;
+       rcu_read_lock();
        perf_cgroup_switch(task, PERF_CGROUP_SWOUT | PERF_CGROUP_SWIN);
+       rcu_read_unlock();
        return 0;
 }
 
-static void perf_cgroup_attach(struct cgroup_subsys_state *css,
-                              struct cgroup_taskset *tset)
+static void perf_cgroup_attach(struct cgroup_taskset *tset)
 {
        struct task_struct *task;
+       struct cgroup_subsys_state *css;
 
-       cgroup_taskset_for_each(task, tset)
+       cgroup_taskset_for_each(task, css, tset)
                task_function_call(task, __perf_cgroup_move, task);
 }
 
index b5d1ea79c5953e2a2c7a5ee843de5f76ad47077a..adfdc0536117c1f10bf8f0dd8014798011e1f855 100644 (file)
@@ -3,7 +3,7 @@
  *
  *  Copyright (C) 2008 Thomas Gleixner <tglx@linutronix.de>
  *  Copyright (C) 2008-2011 Red Hat, Inc., Ingo Molnar
- *  Copyright (C) 2008-2011 Red Hat, Inc., Peter Zijlstra <pzijlstr@redhat.com>
+ *  Copyright (C) 2008-2011 Red Hat, Inc., Peter Zijlstra
  *  Copyright  Â©  2009 Paul Mackerras, IBM Corp. <paulus@au1.ibm.com>
  *
  * For licensing details see kernel-base/COPYING
index 4e5e9798aa0c0d426962642b69985b9eb09021d6..7dad84913abfb06df2495fae555e7f8bcac2b104 100644 (file)
@@ -19,7 +19,7 @@
  * Authors:
  *     Srikar Dronamraju
  *     Jim Keniston
- * Copyright (C) 2011-2012 Red Hat, Inc., Peter Zijlstra <pzijlstr@redhat.com>
+ * Copyright (C) 2011-2012 Red Hat, Inc., Peter Zijlstra
  */
 
 #include <linux/kernel.h>
index f97f2c449f5cf556ea6c54cb4aec6e894dd8bab5..fce002ee3ddffbab7613d0f9ec390683901f3c67 100644 (file)
@@ -1368,8 +1368,7 @@ static struct task_struct *copy_process(unsigned long clone_flags,
        p->real_start_time = ktime_get_boot_ns();
        p->io_context = NULL;
        p->audit_context = NULL;
-       if (clone_flags & CLONE_THREAD)
-               threadgroup_change_begin(current);
+       threadgroup_change_begin(current);
        cgroup_fork(p);
 #ifdef CONFIG_NUMA
        p->mempolicy = mpol_dup(p->mempolicy);
@@ -1610,8 +1609,7 @@ static struct task_struct *copy_process(unsigned long clone_flags,
 
        proc_fork_connector(p);
        cgroup_post_fork(p, cgrp_ss_priv);
-       if (clone_flags & CLONE_THREAD)
-               threadgroup_change_end(current);
+       threadgroup_change_end(current);
        perf_event_fork(p);
 
        trace_task_newtask(p, clone_flags);
@@ -1652,8 +1650,7 @@ bad_fork_cleanup_policy:
        mpol_put(p->mempolicy);
 bad_fork_cleanup_threadgroup_lock:
 #endif
-       if (clone_flags & CLONE_THREAD)
-               threadgroup_change_end(current);
+       threadgroup_change_end(current);
        delayacct_tsk_free(p);
 bad_fork_cleanup_count:
        atomic_dec(&p->cred->user->processes);
index cbf9fb899d929bfc52a2d803b64643732b0b7bbd..bcf107ce085450552c17d6b045816cd4656e97c0 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2010 Red Hat, Inc., Peter Zijlstra <pzijlstr@redhat.com>
+ * Copyright (C) 2010 Red Hat, Inc., Peter Zijlstra
  *
  * Provides a framework for enqueueing and running callbacks from hardirq
  * context. The enqueueing is NMI-safe.
index f7dd15d537f9b1135eb01036bf2fa3a5594ed9b6..05254eeb4b4e485be75bacff667c8ed3aab4a200 100644 (file)
@@ -2,7 +2,7 @@
  * jump label support
  *
  * Copyright (C) 2009 Jason Baron <jbaron@redhat.com>
- * Copyright (C) 2011 Peter Zijlstra <pzijlstr@redhat.com>
+ * Copyright (C) 2011 Peter Zijlstra
  *
  */
 #include <linux/memory.h>
index 6e5344112419ca43ace3474466db35d1692752ab..db545cbcdb8933e1ab4b95a9c276eb523de8ba43 100644 (file)
@@ -294,6 +294,12 @@ static int klp_write_object_relocations(struct module *pmod,
 
        for (reloc = obj->relocs; reloc->name; reloc++) {
                if (!klp_is_module(obj)) {
+
+#if defined(CONFIG_RANDOMIZE_BASE)
+                       /* If KASLR has been enabled, adjust old value accordingly */
+                       if (kaslr_enabled())
+                               reloc->val += kaslr_offset();
+#endif
                        ret = klp_verify_vmlinux_symbol(reloc->name,
                                                        reloc->val);
                        if (ret)
index deae3907ac1eec585bbe71a44f6dc57ad024784a..60ace56618f6c222de90e569bf1702b6dba05e26 100644 (file)
@@ -6,7 +6,7 @@
  * Started by Ingo Molnar:
  *
  *  Copyright (C) 2006,2007 Red Hat, Inc., Ingo Molnar <mingo@redhat.com>
- *  Copyright (C) 2007 Red Hat, Inc., Peter Zijlstra <pzijlstr@redhat.com>
+ *  Copyright (C) 2007 Red Hat, Inc., Peter Zijlstra
  *
  * this code maps all the lock dependencies as they occur in a live kernel
  * and will warn about the following classes of locking bugs:
index d83d798bef95a042e1060a35bf4b79e7c7a6c05c..dbb61a3025484b4d38bd090bd5923c21a3960ced 100644 (file)
@@ -6,7 +6,7 @@
  * Started by Ingo Molnar:
  *
  *  Copyright (C) 2006,2007 Red Hat, Inc., Ingo Molnar <mingo@redhat.com>
- *  Copyright (C) 2007 Red Hat, Inc., Peter Zijlstra <pzijlstr@redhat.com>
+ *  Copyright (C) 2007 Red Hat, Inc., Peter Zijlstra
  *
  * Code for /proc/lockdep and /proc/lockdep_stats:
  *
index d092a0c9c2d4ed838004215cdf038691a14f4598..05a37857ab5516012949ca64b31cff3d133c61e7 100644 (file)
@@ -93,10 +93,12 @@ bool osq_lock(struct optimistic_spin_queue *lock)
        node->cpu = curr;
 
        /*
-        * ACQUIRE semantics, pairs with corresponding RELEASE
-        * in unlock() uncontended, or fastpath.
+        * We need both ACQUIRE (pairs with corresponding RELEASE in
+        * unlock() uncontended, or fastpath) and RELEASE (to publish
+        * the node fields we just initialised) semantics when updating
+        * the lock tail.
         */
-       old = atomic_xchg_acquire(&lock->tail, curr);
+       old = atomic_xchg(&lock->tail, curr);
        if (old == OSQ_UNLOCKED_VAL)
                return true;
 
index 4579dbb7ed872a7e1c119fdbbf98d9dc8cd67a87..4b150bc0c6c111ee09f783eaa6aa101339f6ceec 100644 (file)
@@ -152,8 +152,11 @@ void panic(const char *fmt, ...)
         * We may have ended up stopping the CPU holding the lock (in
         * smp_send_stop()) while still having some valuable data in the console
         * buffer.  Try to acquire the lock then release it regardless of the
-        * result.  The release will also print the buffers out.
+        * result.  The release will also print the buffers out.  Locks debug
+        * should be disabled to avoid reporting bad unlock balance when
+        * panic() is not being callled from OOPS.
         */
+       debug_locks_off();
        console_trylock();
        console_unlock();
 
index ca368793808e37688f7b0219b54d458fede30765..78b3d9f80d443fb4fa601e41088eb2041385ab20 100644 (file)
@@ -467,7 +467,7 @@ struct pid *get_task_pid(struct task_struct *task, enum pid_type type)
        rcu_read_lock();
        if (type != PIDTYPE_PID)
                task = task->group_leader;
-       pid = get_pid(task->pids[type].pid);
+       pid = get_pid(rcu_dereference(task->pids[type].pid));
        rcu_read_unlock();
        return pid;
 }
@@ -528,7 +528,7 @@ pid_t __task_pid_nr_ns(struct task_struct *task, enum pid_type type,
        if (likely(pid_alive(task))) {
                if (type != PIDTYPE_PID)
                        task = task->group_leader;
-               nr = pid_nr_ns(task->pids[type].pid, ns);
+               nr = pid_nr_ns(rcu_dereference(task->pids[type].pid), ns);
        }
        rcu_read_unlock();
 
index c0a205101c231a5b6e29e786228fb69c46772f5e..caf4041f5b0ae6769bc562fccc189852eae77fcf 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * sched_clock for unstable cpu clocks
  *
- *  Copyright (C) 2008 Red Hat, Inc., Peter Zijlstra <pzijlstr@redhat.com>
+ *  Copyright (C) 2008 Red Hat, Inc., Peter Zijlstra
  *
  *  Updates and enhancements:
  *    Copyright (C) 2008 Red Hat, Inc. Steven Rostedt <srostedt@redhat.com>
index 4d568ac9319eaf04c9d00673483678bc5e14f22e..732e993b564b8179e5723bb88839329eec6df8f5 100644 (file)
@@ -1946,6 +1946,25 @@ try_to_wake_up(struct task_struct *p, unsigned int state, int wake_flags)
                goto stat;
 
 #ifdef CONFIG_SMP
+       /*
+        * Ensure we load p->on_cpu _after_ p->on_rq, otherwise it would be
+        * possible to, falsely, observe p->on_cpu == 0.
+        *
+        * One must be running (->on_cpu == 1) in order to remove oneself
+        * from the runqueue.
+        *
+        *  [S] ->on_cpu = 1;   [L] ->on_rq
+        *      UNLOCK rq->lock
+        *                      RMB
+        *      LOCK   rq->lock
+        *  [S] ->on_rq = 0;    [L] ->on_cpu
+        *
+        * Pairs with the full barrier implied in the UNLOCK+LOCK on rq->lock
+        * from the consecutive calls to schedule(); the first switching to our
+        * task, the second putting it to sleep.
+        */
+       smp_rmb();
+
        /*
         * If the owning (remote) cpu is still in the middle of schedule() with
         * this task as prev, wait until its done referencing the task.
@@ -1953,7 +1972,13 @@ try_to_wake_up(struct task_struct *p, unsigned int state, int wake_flags)
        while (p->on_cpu)
                cpu_relax();
        /*
-        * Pairs with the smp_wmb() in finish_lock_switch().
+        * Combined with the control dependency above, we have an effective
+        * smp_load_acquire() without the need for full barriers.
+        *
+        * Pairs with the smp_store_release() in finish_lock_switch().
+        *
+        * This ensures that tasks getting woken will be fully ordered against
+        * their previous state and preserve Program Order.
         */
        smp_rmb();
 
@@ -2039,7 +2064,6 @@ out:
  */
 int wake_up_process(struct task_struct *p)
 {
-       WARN_ON(task_is_stopped_or_traced(p));
        return try_to_wake_up(p, TASK_NORMAL, 0);
 }
 EXPORT_SYMBOL(wake_up_process);
@@ -5847,13 +5871,13 @@ static int init_rootdomain(struct root_domain *rd)
 {
        memset(rd, 0, sizeof(*rd));
 
-       if (!alloc_cpumask_var(&rd->span, GFP_KERNEL))
+       if (!zalloc_cpumask_var(&rd->span, GFP_KERNEL))
                goto out;
-       if (!alloc_cpumask_var(&rd->online, GFP_KERNEL))
+       if (!zalloc_cpumask_var(&rd->online, GFP_KERNEL))
                goto free_span;
-       if (!alloc_cpumask_var(&rd->dlo_mask, GFP_KERNEL))
+       if (!zalloc_cpumask_var(&rd->dlo_mask, GFP_KERNEL))
                goto free_online;
-       if (!alloc_cpumask_var(&rd->rto_mask, GFP_KERNEL))
+       if (!zalloc_cpumask_var(&rd->rto_mask, GFP_KERNEL))
                goto free_dlo_mask;
 
        init_dl_bw(&rd->dl_bw);
@@ -8217,12 +8241,12 @@ static void cpu_cgroup_fork(struct task_struct *task, void *private)
        sched_move_task(task);
 }
 
-static int cpu_cgroup_can_attach(struct cgroup_subsys_state *css,
-                                struct cgroup_taskset *tset)
+static int cpu_cgroup_can_attach(struct cgroup_taskset *tset)
 {
        struct task_struct *task;
+       struct cgroup_subsys_state *css;
 
-       cgroup_taskset_for_each(task, tset) {
+       cgroup_taskset_for_each(task, css, tset) {
 #ifdef CONFIG_RT_GROUP_SCHED
                if (!sched_rt_can_attach(css_tg(css), task))
                        return -EINVAL;
@@ -8235,12 +8259,12 @@ static int cpu_cgroup_can_attach(struct cgroup_subsys_state *css,
        return 0;
 }
 
-static void cpu_cgroup_attach(struct cgroup_subsys_state *css,
-                             struct cgroup_taskset *tset)
+static void cpu_cgroup_attach(struct cgroup_taskset *tset)
 {
        struct task_struct *task;
+       struct cgroup_subsys_state *css;
 
-       cgroup_taskset_for_each(task, tset)
+       cgroup_taskset_for_each(task, css, tset)
                sched_move_task(task);
 }
 
index 26a54461bf59ca46ce7f68d7a926b03840ca8711..05de80b48586e9fa3241c708c7e6fd7c9b6fb24a 100644 (file)
@@ -788,6 +788,9 @@ cputime_t task_gtime(struct task_struct *t)
        unsigned int seq;
        cputime_t gtime;
 
+       if (!context_tracking_is_enabled())
+               return t->gtime;
+
        do {
                seq = read_seqbegin(&t->vtime_seqlock);
 
index f04fda8f669c8eff57e936fcb1334b13a4140ce5..90e26b11deaa1ab4b78302605850523a7852720b 100644 (file)
@@ -17,7 +17,7 @@
  *  Copyright (C) 2007, Thomas Gleixner <tglx@linutronix.de>
  *
  *  Adaptive scheduling granularity, math enhancements by Peter Zijlstra
- *  Copyright (C) 2007 Red Hat, Inc., Peter Zijlstra <pzijlstr@redhat.com>
+ *  Copyright (C) 2007 Red Hat, Inc., Peter Zijlstra
  */
 
 #include <linux/latencytop.h>
index e3cc16312046689fd04db8748304210c0d9fc8df..8ec86abe0ea188369ee4e7efd21789d8cb127c14 100644 (file)
@@ -64,7 +64,7 @@ static void start_rt_bandwidth(struct rt_bandwidth *rt_b)
        raw_spin_unlock(&rt_b->rt_runtime_lock);
 }
 
-#ifdef CONFIG_SMP
+#if defined(CONFIG_SMP) && defined(HAVE_RT_PUSH_IPI)
 static void push_irq_work_func(struct irq_work *work);
 #endif
 
index efd3bfc7e34722883e2f08ca82f91cffde812963..b242775bf670e116233862c590915e06132485ca 100644 (file)
@@ -1073,6 +1073,9 @@ static inline void finish_lock_switch(struct rq *rq, struct task_struct *prev)
         * We must ensure this doesn't happen until the switch is completely
         * finished.
         *
+        * In particular, the load of prev->state in finish_task_switch() must
+        * happen before this.
+        *
         * Pairs with the control dependency and rmb in try_to_wake_up().
         */
        smp_store_release(&prev->on_cpu, 0);
index 052e02672d12428ce1e9e1f7266c7cd754ace5af..f15d6b6a538a9d01c2d7c4045af0a661d34c3c4a 100644 (file)
@@ -392,7 +392,7 @@ __wait_on_bit(wait_queue_head_t *wq, struct wait_bit_queue *q,
        do {
                prepare_to_wait(wq, &q->wait, mode);
                if (test_bit(q->key.bit_nr, q->key.flags))
-                       ret = (*action)(&q->key);
+                       ret = (*action)(&q->key, mode);
        } while (test_bit(q->key.bit_nr, q->key.flags) && !ret);
        finish_wait(wq, &q->wait);
        return ret;
@@ -431,7 +431,7 @@ __wait_on_bit_lock(wait_queue_head_t *wq, struct wait_bit_queue *q,
                prepare_to_wait_exclusive(wq, &q->wait, mode);
                if (!test_bit(q->key.bit_nr, q->key.flags))
                        continue;
-               ret = action(&q->key);
+               ret = action(&q->key, mode);
                if (!ret)
                        continue;
                abort_exclusive_wait(wq, &q->wait, mode, &q->key);
@@ -581,44 +581,44 @@ void wake_up_atomic_t(atomic_t *p)
 }
 EXPORT_SYMBOL(wake_up_atomic_t);
 
-__sched int bit_wait(struct wait_bit_key *word)
+__sched int bit_wait(struct wait_bit_key *word, int mode)
 {
-       if (signal_pending_state(current->state, current))
-               return 1;
        schedule();
+       if (signal_pending_state(mode, current))
+               return -EINTR;
        return 0;
 }
 EXPORT_SYMBOL(bit_wait);
 
-__sched int bit_wait_io(struct wait_bit_key *word)
+__sched int bit_wait_io(struct wait_bit_key *word, int mode)
 {
-       if (signal_pending_state(current->state, current))
-               return 1;
        io_schedule();
+       if (signal_pending_state(mode, current))
+               return -EINTR;
        return 0;
 }
 EXPORT_SYMBOL(bit_wait_io);
 
-__sched int bit_wait_timeout(struct wait_bit_key *word)
+__sched int bit_wait_timeout(struct wait_bit_key *word, int mode)
 {
        unsigned long now = READ_ONCE(jiffies);
-       if (signal_pending_state(current->state, current))
-               return 1;
        if (time_after_eq(now, word->timeout))
                return -EAGAIN;
        schedule_timeout(word->timeout - now);
+       if (signal_pending_state(mode, current))
+               return -EINTR;
        return 0;
 }
 EXPORT_SYMBOL_GPL(bit_wait_timeout);
 
-__sched int bit_wait_io_timeout(struct wait_bit_key *word)
+__sched int bit_wait_io_timeout(struct wait_bit_key *word, int mode)
 {
        unsigned long now = READ_ONCE(jiffies);
-       if (signal_pending_state(current->state, current))
-               return 1;
        if (time_after_eq(now, word->timeout))
                return -EAGAIN;
        io_schedule_timeout(word->timeout - now);
+       if (signal_pending_state(mode, current))
+               return -EINTR;
        return 0;
 }
 EXPORT_SYMBOL_GPL(bit_wait_io_timeout);
index c0b01fe24bbd3fae555b2e479e86f9199f3a7c3b..f3f1f7a972fd40f3d437d6bf3b5db2cacaffe6ca 100644 (file)
@@ -3503,7 +3503,7 @@ SYSCALL_DEFINE0(pause)
 
 #endif
 
-int sigsuspend(sigset_t *set)
+static int sigsuspend(sigset_t *set)
 {
        current->saved_sigmask = current->blocked;
        set_current_blocked(set);
index 867bc20e1ef142a63349c345932af24b26a1adfc..a3bbaee77c586e9836567f900012aa5231e94dbd 100644 (file)
@@ -531,7 +531,7 @@ static int __init cpu_stop_init(void)
 }
 early_initcall(cpu_stop_init);
 
-#ifdef CONFIG_STOP_MACHINE
+#if defined(CONFIG_SMP) || defined(CONFIG_HOTPLUG_CPU)
 
 static int __stop_machine(cpu_stop_fn_t fn, void *data, const struct cpumask *cpus)
 {
@@ -631,4 +631,4 @@ int stop_machine_from_inactive_cpu(cpu_stop_fn_t fn, void *data,
        return ret ?: done.ret;
 }
 
-#endif /* CONFIG_STOP_MACHINE */
+#endif /* CONFIG_SMP || CONFIG_HOTPLUG_CPU */
index 75f1d05ea82dcce04e9f6a581f26969e503dc773..9c6045a27ba356252546971fb26dbae30149c89c 100644 (file)
@@ -1887,12 +1887,6 @@ rb_event_index(struct ring_buffer_event *event)
        return (addr & ~PAGE_MASK) - BUF_PAGE_HDR_SIZE;
 }
 
-static void rb_reset_reader_page(struct ring_buffer_per_cpu *cpu_buffer)
-{
-       cpu_buffer->read_stamp = cpu_buffer->reader_page->page->time_stamp;
-       cpu_buffer->reader_page->read = 0;
-}
-
 static void rb_inc_iter(struct ring_buffer_iter *iter)
 {
        struct ring_buffer_per_cpu *cpu_buffer = iter->cpu_buffer;
@@ -2803,8 +2797,11 @@ rb_reserve_next_event(struct ring_buffer *buffer,
 
        event = __rb_reserve_next(cpu_buffer, &info);
 
-       if (unlikely(PTR_ERR(event) == -EAGAIN))
+       if (unlikely(PTR_ERR(event) == -EAGAIN)) {
+               if (info.add_timestamp)
+                       info.length -= RB_LEN_TIME_EXTEND;
                goto again;
+       }
 
        if (!event)
                goto out_fail;
@@ -3626,7 +3623,7 @@ rb_get_reader_page(struct ring_buffer_per_cpu *cpu_buffer)
 
        /* Finally update the reader page to the new head */
        cpu_buffer->reader_page = reader;
-       rb_reset_reader_page(cpu_buffer);
+       cpu_buffer->reader_page->read = 0;
 
        if (overwrite != cpu_buffer->last_overrun) {
                cpu_buffer->lost_events = overwrite - cpu_buffer->last_overrun;
@@ -3636,6 +3633,10 @@ rb_get_reader_page(struct ring_buffer_per_cpu *cpu_buffer)
        goto again;
 
  out:
+       /* Update the read_stamp on the first event */
+       if (reader && reader->read == 0)
+               cpu_buffer->read_stamp = reader->page->time_stamp;
+
        arch_spin_unlock(&cpu_buffer->lock);
        local_irq_restore(flags);
 
index abfc903e741e8550d67bd638ead8a338a0c95fec..cc9f7a9319bea63104ef05c97634c43286a5268c 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * trace event based perf event profiling/tracing
  *
- * Copyright (C) 2009 Red Hat Inc, Peter Zijlstra <pzijlstr@redhat.com>
+ * Copyright (C) 2009 Red Hat Inc, Peter Zijlstra
  * Copyright (C) 2009-2010 Frederic Weisbecker <fweisbec@gmail.com>
  */
 
index 6bbc5f652355745d24f6252a93d7b437a0efea15..4f6ef6912e00173040867f6a68c52f010bbfd21d 100644 (file)
@@ -582,6 +582,12 @@ static void __ftrace_clear_event_pids(struct trace_array *tr)
        unregister_trace_sched_wakeup(event_filter_pid_sched_wakeup_probe_pre, tr);
        unregister_trace_sched_wakeup(event_filter_pid_sched_wakeup_probe_post, tr);
 
+       unregister_trace_sched_wakeup_new(event_filter_pid_sched_wakeup_probe_pre, tr);
+       unregister_trace_sched_wakeup_new(event_filter_pid_sched_wakeup_probe_post, tr);
+
+       unregister_trace_sched_waking(event_filter_pid_sched_wakeup_probe_pre, tr);
+       unregister_trace_sched_waking(event_filter_pid_sched_wakeup_probe_post, tr);
+
        list_for_each_entry(file, &tr->events, list) {
                clear_bit(EVENT_FILE_FL_PID_FILTER_BIT, &file->flags);
        }
@@ -1729,6 +1735,16 @@ ftrace_event_pid_write(struct file *filp, const char __user *ubuf,
                                                 tr, INT_MAX);
                register_trace_prio_sched_wakeup(event_filter_pid_sched_wakeup_probe_post,
                                                 tr, 0);
+
+               register_trace_prio_sched_wakeup_new(event_filter_pid_sched_wakeup_probe_pre,
+                                                    tr, INT_MAX);
+               register_trace_prio_sched_wakeup_new(event_filter_pid_sched_wakeup_probe_post,
+                                                    tr, 0);
+
+               register_trace_prio_sched_waking(event_filter_pid_sched_wakeup_probe_pre,
+                                                tr, INT_MAX);
+               register_trace_prio_sched_waking(event_filter_pid_sched_wakeup_probe_post,
+                                                tr, 0);
        }
 
        /*
index 4264871ea1a00194750116a82c48e18d18edbd44..f93a945274af12575f8fbbceb821552b2a13e61e 100644 (file)
@@ -5,7 +5,7 @@
  *
  * Copyright (c) 2007-2008 Joern Engel <joern@logfs.org>
  * Bits and pieces stolen from Peter Zijlstra's code, which is
- * Copyright 2007, Red Hat Inc. Peter Zijlstra <pzijlstr@redhat.com>
+ * Copyright 2007, Red Hat Inc. Peter Zijlstra
  * GPLv2
  *
  * see http://programming.kicks-ass.net/kernel-patches/vma_lookup/btree.patch
index 8855f019ebe8a61957795b0d5f5c3339fe180f5a..d34bd24c2c84779c38c300f470b22df52e76cb58 100644 (file)
@@ -1464,7 +1464,7 @@ void debug_dma_alloc_coherent(struct device *dev, size_t size,
        entry->type      = dma_debug_coherent;
        entry->dev       = dev;
        entry->pfn       = page_to_pfn(virt_to_page(virt));
-       entry->offset    = (size_t) virt & PAGE_MASK;
+       entry->offset    = (size_t) virt & ~PAGE_MASK;
        entry->size      = size;
        entry->dev_addr  = dma_addr;
        entry->direction = DMA_BIDIRECTIONAL;
@@ -1480,7 +1480,7 @@ void debug_dma_free_coherent(struct device *dev, size_t size,
                .type           = dma_debug_coherent,
                .dev            = dev,
                .pfn            = page_to_pfn(virt_to_page(virt)),
-               .offset         = (size_t) virt & PAGE_MASK,
+               .offset         = (size_t) virt & ~PAGE_MASK,
                .dev_addr       = addr,
                .size           = size,
                .direction      = DMA_BIDIRECTIONAL,
index 6f724298f67a11199407870e2dbb1541ee55db6c..efa54f259ea9d316176c03c66badd9c23cfc8e20 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * Floating proportions
  *
- *  Copyright (C) 2007 Red Hat, Inc., Peter Zijlstra <pzijlstr@redhat.com>
+ *  Copyright (C) 2007 Red Hat, Inc., Peter Zijlstra
  *
  * Description:
  *
index a54ff8949f9116184631414086a9fa2d956c8031..51282f5797606545330a29e93b3728d843616ea9 100644 (file)
@@ -389,33 +389,31 @@ static bool rhashtable_check_elasticity(struct rhashtable *ht,
        return false;
 }
 
-int rhashtable_insert_rehash(struct rhashtable *ht)
+int rhashtable_insert_rehash(struct rhashtable *ht,
+                            struct bucket_table *tbl)
 {
        struct bucket_table *old_tbl;
        struct bucket_table *new_tbl;
-       struct bucket_table *tbl;
        unsigned int size;
        int err;
 
        old_tbl = rht_dereference_rcu(ht->tbl, ht);
-       tbl = rhashtable_last_table(ht, old_tbl);
 
        size = tbl->size;
 
+       err = -EBUSY;
+
        if (rht_grow_above_75(ht, tbl))
                size *= 2;
        /* Do not schedule more than one rehash */
        else if (old_tbl != tbl)
-               return -EBUSY;
+               goto fail;
+
+       err = -ENOMEM;
 
        new_tbl = bucket_table_alloc(ht, size, GFP_ATOMIC);
-       if (new_tbl == NULL) {
-               /* Schedule async resize/rehash to try allocation
-                * non-atomic context.
-                */
-               schedule_work(&ht->run_work);
-               return -ENOMEM;
-       }
+       if (new_tbl == NULL)
+               goto fail;
 
        err = rhashtable_rehash_attach(ht, tbl, new_tbl);
        if (err) {
@@ -426,12 +424,24 @@ int rhashtable_insert_rehash(struct rhashtable *ht)
                schedule_work(&ht->run_work);
 
        return err;
+
+fail:
+       /* Do not fail the insert if someone else did a rehash. */
+       if (likely(rcu_dereference_raw(tbl->future_tbl)))
+               return 0;
+
+       /* Schedule async rehash to retry allocation in process context. */
+       if (err == -ENOMEM)
+               schedule_work(&ht->run_work);
+
+       return err;
 }
 EXPORT_SYMBOL_GPL(rhashtable_insert_rehash);
 
-int rhashtable_insert_slow(struct rhashtable *ht, const void *key,
-                          struct rhash_head *obj,
-                          struct bucket_table *tbl)
+struct bucket_table *rhashtable_insert_slow(struct rhashtable *ht,
+                                           const void *key,
+                                           struct rhash_head *obj,
+                                           struct bucket_table *tbl)
 {
        struct rhash_head *head;
        unsigned int hash;
@@ -467,7 +477,12 @@ int rhashtable_insert_slow(struct rhashtable *ht, const void *key,
 exit:
        spin_unlock(rht_bucket_lock(tbl, hash));
 
-       return err;
+       if (err == 0)
+               return NULL;
+       else if (err == -EAGAIN)
+               return tbl;
+       else
+               return ERR_PTR(err);
 }
 EXPORT_SYMBOL_GPL(rhashtable_insert_slow);
 
@@ -503,10 +518,11 @@ int rhashtable_walk_init(struct rhashtable *ht, struct rhashtable_iter *iter)
        if (!iter->walker)
                return -ENOMEM;
 
-       mutex_lock(&ht->mutex);
-       iter->walker->tbl = rht_dereference(ht->tbl, ht);
+       spin_lock(&ht->lock);
+       iter->walker->tbl =
+               rcu_dereference_protected(ht->tbl, lockdep_is_held(&ht->lock));
        list_add(&iter->walker->list, &iter->walker->tbl->walkers);
-       mutex_unlock(&ht->mutex);
+       spin_unlock(&ht->lock);
 
        return 0;
 }
@@ -520,10 +536,10 @@ EXPORT_SYMBOL_GPL(rhashtable_walk_init);
  */
 void rhashtable_walk_exit(struct rhashtable_iter *iter)
 {
-       mutex_lock(&iter->ht->mutex);
+       spin_lock(&iter->ht->lock);
        if (iter->walker->tbl)
                list_del(&iter->walker->list);
-       mutex_unlock(&iter->ht->mutex);
+       spin_unlock(&iter->ht->lock);
        kfree(iter->walker);
 }
 EXPORT_SYMBOL_GPL(rhashtable_walk_exit);
@@ -547,14 +563,12 @@ int rhashtable_walk_start(struct rhashtable_iter *iter)
 {
        struct rhashtable *ht = iter->ht;
 
-       mutex_lock(&ht->mutex);
+       rcu_read_lock();
 
+       spin_lock(&ht->lock);
        if (iter->walker->tbl)
                list_del(&iter->walker->list);
-
-       rcu_read_lock();
-
-       mutex_unlock(&ht->mutex);
+       spin_unlock(&ht->lock);
 
        if (!iter->walker->tbl) {
                iter->walker->tbl = rht_dereference_rcu(ht->tbl, ht);
@@ -723,9 +737,6 @@ int rhashtable_init(struct rhashtable *ht,
        if (params->nulls_base && params->nulls_base < (1U << RHT_BASE_SHIFT))
                return -EINVAL;
 
-       if (params->nelem_hint)
-               size = rounded_hashtable_size(params);
-
        memset(ht, 0, sizeof(*ht));
        mutex_init(&ht->mutex);
        spin_lock_init(&ht->lock);
@@ -745,6 +756,9 @@ int rhashtable_init(struct rhashtable *ht,
 
        ht->p.min_size = max(ht->p.min_size, HASH_MIN_SIZE);
 
+       if (params->nelem_hint)
+               size = rounded_hashtable_size(&ht->p);
+
        /* The maximum (not average) chain length grows with the
         * size of the hash table, at a rate of (log N)/(log log N).
         * The value of 16 is selected so that even if the hash
index 8ed2ffd963c53b910f91e1b60b04c56385a3129f..7340353f8aea08ef428edcf7b287c45b312aeb1a 100644 (file)
@@ -957,8 +957,9 @@ EXPORT_SYMBOL(congestion_wait);
  * jiffies for either a BDI to exit congestion of the given @sync queue
  * or a write to complete.
  *
- * In the absence of zone congestion, cond_resched() is called to yield
- * the processor if necessary but otherwise does not sleep.
+ * In the absence of zone congestion, a short sleep or a cond_resched is
+ * performed to yield the processor and to allow other subsystems to make
+ * a forward progress.
  *
  * The return value is 0 if the sleep is for the full timeout. Otherwise,
  * it is the number of jiffies that were still remaining when the function
@@ -978,7 +979,19 @@ long wait_iff_congested(struct zone *zone, int sync, long timeout)
         */
        if (atomic_read(&nr_wb_congested[sync]) == 0 ||
            !test_bit(ZONE_CONGESTED, &zone->flags)) {
-               cond_resched();
+
+               /*
+                * Memory allocation/reclaim might be called from a WQ
+                * context and the current implementation of the WQ
+                * concurrency control doesn't recognize that a particular
+                * WQ is congested if the worker thread is looping without
+                * ever sleeping. Therefore we have to do a short sleep
+                * here rather than calling cond_resched().
+                */
+               if (current->flags & PF_WQ_WORKER)
+                       schedule_timeout(1);
+               else
+                       cond_resched();
 
                /* In case we scheduled, work out time remaining */
                ret = timeout - (jiffies - start);
index c29ddebc870509e7e35b69da5cce5a7d9988542d..62fe06bb7d04bacccc8c2213a6a65134fa274010 100644 (file)
@@ -2009,7 +2009,7 @@ int hugepage_madvise(struct vm_area_struct *vma,
                /*
                 * Be somewhat over-protective like KSM for now!
                 */
-               if (*vm_flags & (VM_HUGEPAGE | VM_NO_THP))
+               if (*vm_flags & VM_NO_THP)
                        return -EINVAL;
                *vm_flags &= ~VM_NOHUGEPAGE;
                *vm_flags |= VM_HUGEPAGE;
@@ -2025,7 +2025,7 @@ int hugepage_madvise(struct vm_area_struct *vma,
                /*
                 * Be somewhat over-protective like KSM for now!
                 */
-               if (*vm_flags & (VM_NOHUGEPAGE | VM_NO_THP))
+               if (*vm_flags & VM_NO_THP)
                        return -EINVAL;
                *vm_flags &= ~VM_HUGEPAGE;
                *vm_flags |= VM_NOHUGEPAGE;
index 827bb02a43a4e425393c296db89e7a49d6adf02b..ef6963b577fd2920c1a4857f7b74b50e91c98b7a 100644 (file)
@@ -372,8 +372,10 @@ retry_locked:
                spin_unlock(&resv->lock);
 
                trg = kmalloc(sizeof(*trg), GFP_KERNEL);
-               if (!trg)
+               if (!trg) {
+                       kfree(nrg);
                        return -ENOMEM;
+               }
 
                spin_lock(&resv->lock);
                list_add(&trg->link, &resv->region_cache);
@@ -483,8 +485,16 @@ static long region_del(struct resv_map *resv, long f, long t)
 retry:
        spin_lock(&resv->lock);
        list_for_each_entry_safe(rg, trg, head, link) {
-               if (rg->to <= f)
+               /*
+                * Skip regions before the range to be deleted.  file_region
+                * ranges are normally of the form [from, to).  However, there
+                * may be a "placeholder" entry in the map which is of the form
+                * (from, to) with from == to.  Check for placeholder entries
+                * at the beginning of the range to be deleted.
+                */
+               if (rg->to <= f && (rg->to != rg->from || rg->to != f))
                        continue;
+
                if (rg->from >= t)
                        break;
 
@@ -1886,7 +1896,10 @@ struct page *alloc_huge_page(struct vm_area_struct *vma,
                page = __alloc_buddy_huge_page_with_mpol(h, vma, addr);
                if (!page)
                        goto out_uncharge_cgroup;
-
+               if (!avoid_reserve && vma_has_reserves(vma, gbl_chg)) {
+                       SetPagePrivate(page);
+                       h->resv_huge_pages--;
+               }
                spin_lock(&hugetlb_lock);
                list_move(&page->lru, &h->hugepage_activelist);
                /* Fall through */
@@ -3693,12 +3706,12 @@ int hugetlb_fault(struct mm_struct *mm, struct vm_area_struct *vma,
                } else if (unlikely(is_hugetlb_entry_hwpoisoned(entry)))
                        return VM_FAULT_HWPOISON_LARGE |
                                VM_FAULT_SET_HINDEX(hstate_index(h));
+       } else {
+               ptep = huge_pte_alloc(mm, address, huge_page_size(h));
+               if (!ptep)
+                       return VM_FAULT_OOM;
        }
 
-       ptep = huge_pte_alloc(mm, address, huge_page_size(h));
-       if (!ptep)
-               return VM_FAULT_OOM;
-
        mapping = vma->vm_file->f_mapping;
        idx = vma_hugecache_offset(h, vma, address);
 
index d41b21bce6a030a0ea0356d34e9a495f6dfbb5b0..bc0a8d8b8f42faf7bca01501425ba73e156ee293 100644 (file)
@@ -19,6 +19,7 @@
 #include <linux/export.h>
 #include <linux/init.h>
 #include <linux/kernel.h>
+#include <linux/kmemleak.h>
 #include <linux/memblock.h>
 #include <linux/memory.h>
 #include <linux/mm.h>
@@ -444,6 +445,7 @@ int kasan_module_alloc(void *addr, size_t size)
 
        if (ret) {
                find_vm_area(addr)->flags |= VM_KASAN;
+               kmemleak_ignore(ret);
                return 0;
        }
 
index 9acfb165eb52eeff2271888ec61fe093c9015641..fc10620967c79d7b8fbbcc0f82fd9804b1562f13 100644 (file)
@@ -903,14 +903,20 @@ struct mem_cgroup *mem_cgroup_iter(struct mem_cgroup *root,
                if (prev && reclaim->generation != iter->generation)
                        goto out_unlock;
 
-               do {
+               while (1) {
                        pos = READ_ONCE(iter->position);
+                       if (!pos || css_tryget(&pos->css))
+                               break;
                        /*
-                        * A racing update may change the position and
-                        * put the last reference, hence css_tryget(),
-                        * or retry to see the updated position.
+                        * css reference reached zero, so iter->position will
+                        * be cleared by ->css_released. However, we should not
+                        * rely on this happening soon, because ->css_released
+                        * is called from a work queue, and by busy-waiting we
+                        * might block it. So we clear iter->position right
+                        * away.
                         */
-               } while (pos && !css_tryget(&pos->css));
+                       (void)cmpxchg(&iter->position, pos, NULL);
+               }
        }
 
        if (pos)
@@ -956,17 +962,13 @@ struct mem_cgroup *mem_cgroup_iter(struct mem_cgroup *root,
        }
 
        if (reclaim) {
-               if (cmpxchg(&iter->position, pos, memcg) == pos) {
-                       if (memcg)
-                               css_get(&memcg->css);
-                       if (pos)
-                               css_put(&pos->css);
-               }
-
                /*
-                * pairs with css_tryget when dereferencing iter->position
-                * above.
+                * The position could have already been updated by a competing
+                * thread, so check that the value hasn't changed since we read
+                * it to avoid reclaiming from the same cgroup twice.
                 */
+               (void)cmpxchg(&iter->position, pos, memcg);
+
                if (pos)
                        css_put(&pos->css);
 
@@ -999,6 +1001,28 @@ void mem_cgroup_iter_break(struct mem_cgroup *root,
                css_put(&prev->css);
 }
 
+static void invalidate_reclaim_iterators(struct mem_cgroup *dead_memcg)
+{
+       struct mem_cgroup *memcg = dead_memcg;
+       struct mem_cgroup_reclaim_iter *iter;
+       struct mem_cgroup_per_zone *mz;
+       int nid, zid;
+       int i;
+
+       while ((memcg = parent_mem_cgroup(memcg))) {
+               for_each_node(nid) {
+                       for (zid = 0; zid < MAX_NR_ZONES; zid++) {
+                               mz = &memcg->nodeinfo[nid]->zoneinfo[zid];
+                               for (i = 0; i <= DEF_PRIORITY; i++) {
+                                       iter = &mz->iter[i];
+                                       cmpxchg(&iter->position,
+                                               dead_memcg, NULL);
+                               }
+                       }
+               }
+       }
+}
+
 /*
  * Iteration constructs for visiting all cgroups (under a tree).  If
  * loops are exited prematurely (break), mem_cgroup_iter_break() must
@@ -2128,7 +2152,7 @@ done_restock:
         */
        do {
                if (page_counter_read(&memcg->memory) > memcg->high) {
-                       current->memcg_nr_pages_over_high += nr_pages;
+                       current->memcg_nr_pages_over_high += batch;
                        set_notify_resume(current);
                        break;
                }
@@ -4324,6 +4348,13 @@ static void mem_cgroup_css_offline(struct cgroup_subsys_state *css)
        wb_memcg_offline(memcg);
 }
 
+static void mem_cgroup_css_released(struct cgroup_subsys_state *css)
+{
+       struct mem_cgroup *memcg = mem_cgroup_from_css(css);
+
+       invalidate_reclaim_iterators(memcg);
+}
+
 static void mem_cgroup_css_free(struct cgroup_subsys_state *css)
 {
        struct mem_cgroup *memcg = mem_cgroup_from_css(css);
@@ -4779,23 +4810,18 @@ static void mem_cgroup_clear_mc(void)
        spin_unlock(&mc.lock);
 }
 
-static int mem_cgroup_can_attach(struct cgroup_subsys_state *css,
-                                struct cgroup_taskset *tset)
+static int mem_cgroup_can_attach(struct cgroup_taskset *tset)
 {
-       struct mem_cgroup *memcg = mem_cgroup_from_css(css);
+       struct cgroup_subsys_state *css;
+       struct mem_cgroup *memcg;
        struct mem_cgroup *from;
        struct task_struct *leader, *p;
        struct mm_struct *mm;
        unsigned long move_flags;
        int ret = 0;
 
-       /*
-        * We are now commited to this value whatever it is. Changes in this
-        * tunable will only affect upcoming migrations, not the current one.
-        * So we need to save it, and keep it going.
-        */
-       move_flags = READ_ONCE(memcg->move_charge_at_immigrate);
-       if (!move_flags)
+       /* charge immigration isn't supported on the default hierarchy */
+       if (cgroup_subsys_on_dfl(memory_cgrp_subsys))
                return 0;
 
        /*
@@ -4805,13 +4831,23 @@ static int mem_cgroup_can_attach(struct cgroup_subsys_state *css,
         * multiple.
         */
        p = NULL;
-       cgroup_taskset_for_each_leader(leader, tset) {
+       cgroup_taskset_for_each_leader(leader, css, tset) {
                WARN_ON_ONCE(p);
                p = leader;
+               memcg = mem_cgroup_from_css(css);
        }
        if (!p)
                return 0;
 
+       /*
+        * We are now commited to this value whatever it is. Changes in this
+        * tunable will only affect upcoming migrations, not the current one.
+        * So we need to save it, and keep it going.
+        */
+       move_flags = READ_ONCE(memcg->move_charge_at_immigrate);
+       if (!move_flags)
+               return 0;
+
        from = mem_cgroup_from_task(p);
 
        VM_BUG_ON(from == memcg);
@@ -4842,8 +4878,7 @@ static int mem_cgroup_can_attach(struct cgroup_subsys_state *css,
        return ret;
 }
 
-static void mem_cgroup_cancel_attach(struct cgroup_subsys_state *css,
-                                    struct cgroup_taskset *tset)
+static void mem_cgroup_cancel_attach(struct cgroup_taskset *tset)
 {
        if (mc.to)
                mem_cgroup_clear_mc();
@@ -4985,10 +5020,10 @@ retry:
        atomic_dec(&mc.from->moving_account);
 }
 
-static void mem_cgroup_move_task(struct cgroup_subsys_state *css,
-                                struct cgroup_taskset *tset)
+static void mem_cgroup_move_task(struct cgroup_taskset *tset)
 {
-       struct task_struct *p = cgroup_taskset_first(tset);
+       struct cgroup_subsys_state *css;
+       struct task_struct *p = cgroup_taskset_first(tset, &css);
        struct mm_struct *mm = get_task_mm(p);
 
        if (mm) {
@@ -5000,17 +5035,14 @@ static void mem_cgroup_move_task(struct cgroup_subsys_state *css,
                mem_cgroup_clear_mc();
 }
 #else  /* !CONFIG_MMU */
-static int mem_cgroup_can_attach(struct cgroup_subsys_state *css,
-                                struct cgroup_taskset *tset)
+static int mem_cgroup_can_attach(struct cgroup_taskset *tset)
 {
        return 0;
 }
-static void mem_cgroup_cancel_attach(struct cgroup_subsys_state *css,
-                                    struct cgroup_taskset *tset)
+static void mem_cgroup_cancel_attach(struct cgroup_taskset *tset)
 {
 }
-static void mem_cgroup_move_task(struct cgroup_subsys_state *css,
-                                struct cgroup_taskset *tset)
+static void mem_cgroup_move_task(struct cgroup_taskset *tset)
 {
 }
 #endif
@@ -5184,6 +5216,7 @@ struct cgroup_subsys memory_cgrp_subsys = {
        .css_alloc = mem_cgroup_css_alloc,
        .css_online = mem_cgroup_css_online,
        .css_offline = mem_cgroup_css_offline,
+       .css_released = mem_cgroup_css_released,
        .css_free = mem_cgroup_css_free,
        .css_reset = mem_cgroup_css_reset,
        .can_attach = mem_cgroup_can_attach,
@@ -5511,11 +5544,11 @@ void mem_cgroup_uncharge_list(struct list_head *page_list)
  * mem_cgroup_replace_page - migrate a charge to another page
  * @oldpage: currently charged page
  * @newpage: page to transfer the charge to
- * @lrucare: either or both pages might be on the LRU already
  *
  * Migrate the charge from @oldpage to @newpage.
  *
  * Both pages must be locked, @newpage->mapping must be set up.
+ * Either or both pages might be on the LRU already.
  */
 void mem_cgroup_replace_page(struct page *oldpage, struct page *newpage)
 {
index deb679c31f2ab897cafebf72643aec4f66233308..c387430f06c319d52794152b7e100a66a10c9f68 100644 (file)
@@ -3015,9 +3015,9 @@ static int do_cow_fault(struct mm_struct *mm, struct vm_area_struct *vma,
                } else {
                        /*
                         * The fault handler has no page to lock, so it holds
-                        * i_mmap_lock for write to protect against truncate.
+                        * i_mmap_lock for read to protect against truncate.
                         */
-                       i_mmap_unlock_write(vma->vm_file->f_mapping);
+                       i_mmap_unlock_read(vma->vm_file->f_mapping);
                }
                goto uncharge_out;
        }
@@ -3031,9 +3031,9 @@ static int do_cow_fault(struct mm_struct *mm, struct vm_area_struct *vma,
        } else {
                /*
                 * The fault handler has no page to lock, so it holds
-                * i_mmap_lock for write to protect against truncate.
+                * i_mmap_lock for read to protect against truncate.
                 */
-               i_mmap_unlock_write(vma->vm_file->f_mapping);
+               i_mmap_unlock_read(vma->vm_file->f_mapping);
        }
        return ret;
 uncharge_out:
index 67d488ab495e57b9018484932e135078c787903c..a042a9d537bb31984d6b2a8d3cc8ae1e54361e4f 100644 (file)
@@ -1375,23 +1375,30 @@ int is_mem_section_removable(unsigned long start_pfn, unsigned long nr_pages)
  */
 int test_pages_in_a_zone(unsigned long start_pfn, unsigned long end_pfn)
 {
-       unsigned long pfn;
+       unsigned long pfn, sec_end_pfn;
        struct zone *zone = NULL;
        struct page *page;
        int i;
-       for (pfn = start_pfn;
+       for (pfn = start_pfn, sec_end_pfn = SECTION_ALIGN_UP(start_pfn);
             pfn < end_pfn;
-            pfn += MAX_ORDER_NR_PAGES) {
-               i = 0;
-               /* This is just a CONFIG_HOLES_IN_ZONE check.*/
-               while ((i < MAX_ORDER_NR_PAGES) && !pfn_valid_within(pfn + i))
-                       i++;
-               if (i == MAX_ORDER_NR_PAGES)
+            pfn = sec_end_pfn + 1, sec_end_pfn += PAGES_PER_SECTION) {
+               /* Make sure the memory section is present first */
+               if (!present_section_nr(pfn_to_section_nr(pfn)))
                        continue;
-               page = pfn_to_page(pfn + i);
-               if (zone && page_zone(page) != zone)
-                       return 0;
-               zone = page_zone(page);
+               for (; pfn < sec_end_pfn && pfn < end_pfn;
+                    pfn += MAX_ORDER_NR_PAGES) {
+                       i = 0;
+                       /* This is just a CONFIG_HOLES_IN_ZONE check.*/
+                       while ((i < MAX_ORDER_NR_PAGES) &&
+                               !pfn_valid_within(pfn + i))
+                               i++;
+                       if (i == MAX_ORDER_NR_PAGES)
+                               continue;
+                       page = pfn_to_page(pfn + i);
+                       if (zone && page_zone(page) != zone)
+                               return 0;
+                       zone = page_zone(page);
+               }
        }
        return 1;
 }
index d13a33918fa23e685bc629bc23f58d97729beb62..c12680993ff334560dbfc84ffcee4e0bd0487650 100644 (file)
@@ -608,6 +608,8 @@ void oom_kill_process(struct oom_control *oc, struct task_struct *p,
                        continue;
                if (unlikely(p->flags & PF_KTHREAD))
                        continue;
+               if (is_global_init(p))
+                       continue;
                if (p->signal->oom_score_adj == OOM_SCORE_ADJ_MIN)
                        continue;
 
index 2c90357c34ea4c4d81521b7bf14d669d6565cc07..d15d88c8efa1e25bf76fe3bf07f6eeb08fd14fd5 100644 (file)
@@ -2,7 +2,7 @@
  * mm/page-writeback.c
  *
  * Copyright (C) 2002, Linus Torvalds.
- * Copyright (C) 2007 Red Hat, Inc., Peter Zijlstra <pzijlstr@redhat.com>
+ * Copyright (C) 2007 Red Hat, Inc., Peter Zijlstra
  *
  * Contains functions related to writing back dirty pages at the
  * address_space level.
@@ -1542,7 +1542,9 @@ static void balance_dirty_pages(struct address_space *mapping,
        for (;;) {
                unsigned long now = jiffies;
                unsigned long dirty, thresh, bg_thresh;
-               unsigned long m_dirty, m_thresh, m_bg_thresh;
+               unsigned long m_dirty = 0;      /* stop bogus uninit warnings */
+               unsigned long m_thresh = 0;
+               unsigned long m_bg_thresh = 0;
 
                /*
                 * Unstable writes are a feature of certain networked
index 17a3c66639a9cd6625f333b4f64ab012e2cb56c4..9d666df5ef9502b70cf7ba0aedef5eb805fdd811 100644 (file)
@@ -3647,8 +3647,9 @@ static void show_migration_types(unsigned char type)
 {
        static const char types[MIGRATE_TYPES] = {
                [MIGRATE_UNMOVABLE]     = 'U',
-               [MIGRATE_RECLAIMABLE]   = 'E',
                [MIGRATE_MOVABLE]       = 'M',
+               [MIGRATE_RECLAIMABLE]   = 'E',
+               [MIGRATE_HIGHATOMIC]    = 'H',
 #ifdef CONFIG_CMA
                [MIGRATE_CMA]           = 'C',
 #endif
index 9187eee4128b45769583dae2a73720e3545ee933..2afcdbbdb68506096d5c6fad584a8425709d10aa 100644 (file)
@@ -843,14 +843,14 @@ static int shmem_writepage(struct page *page, struct writeback_control *wbc)
                list_add_tail(&info->swaplist, &shmem_swaplist);
 
        if (add_to_swap_cache(page, swap, GFP_ATOMIC) == 0) {
-               swap_shmem_alloc(swap);
-               shmem_delete_from_page_cache(page, swp_to_radix_entry(swap));
-
                spin_lock(&info->lock);
-               info->swapped++;
                shmem_recalc_inode(inode);
+               info->swapped++;
                spin_unlock(&info->lock);
 
+               swap_shmem_alloc(swap);
+               shmem_delete_from_page_cache(page, swp_to_radix_entry(swap));
+
                mutex_unlock(&shmem_swaplist_mutex);
                BUG_ON(page_mapped(page));
                swap_writepage(page, wbc);
@@ -1078,7 +1078,7 @@ repeat:
        if (sgp != SGP_WRITE && sgp != SGP_FALLOC &&
            ((loff_t)index << PAGE_CACHE_SHIFT) >= i_size_read(inode)) {
                error = -EINVAL;
-               goto failed;
+               goto unlock;
        }
 
        if (page && sgp == SGP_WRITE)
@@ -1246,11 +1246,15 @@ clear:
        /* Perhaps the file has been truncated since we checked */
        if (sgp != SGP_WRITE && sgp != SGP_FALLOC &&
            ((loff_t)index << PAGE_CACHE_SHIFT) >= i_size_read(inode)) {
+               if (alloced) {
+                       ClearPageDirty(page);
+                       delete_from_page_cache(page);
+                       spin_lock(&info->lock);
+                       shmem_recalc_inode(inode);
+                       spin_unlock(&info->lock);
+               }
                error = -EINVAL;
-               if (alloced)
-                       goto trunc;
-               else
-                       goto failed;
+               goto unlock;
        }
        *pagep = page;
        return 0;
@@ -1258,23 +1262,13 @@ clear:
        /*
         * Error recovery.
         */
-trunc:
-       info = SHMEM_I(inode);
-       ClearPageDirty(page);
-       delete_from_page_cache(page);
-       spin_lock(&info->lock);
-       info->alloced--;
-       inode->i_blocks -= BLOCKS_PER_PAGE;
-       spin_unlock(&info->lock);
 decused:
-       sbinfo = SHMEM_SB(inode->i_sb);
        if (sbinfo->max_blocks)
                percpu_counter_add(&sbinfo->used_blocks, -1);
 unacct:
        shmem_unacct_blocks(info->flags, 1);
 failed:
-       if (swap.val && error != -EINVAL &&
-           !shmem_confirm_swap(mapping, index, swap))
+       if (swap.val && !shmem_confirm_swap(mapping, index, swap))
                error = -EEXIST;
 unlock:
        if (page) {
index e0819fa96559f3d166a35001dbefd4982ffd2a08..4765c97ce6900d98b8ce2968cf9ff62a176f6e42 100644 (file)
--- a/mm/slab.c
+++ b/mm/slab.c
@@ -3419,7 +3419,7 @@ void kmem_cache_free_bulk(struct kmem_cache *s, size_t size, void **p)
 }
 EXPORT_SYMBOL(kmem_cache_free_bulk);
 
-bool kmem_cache_alloc_bulk(struct kmem_cache *s, gfp_t flags, size_t size,
+int kmem_cache_alloc_bulk(struct kmem_cache *s, gfp_t flags, size_t size,
                                                                void **p)
 {
        return __kmem_cache_alloc_bulk(s, flags, size, p);
index 27492eb678f722400147e22da62a68de893497e8..7b608719799763cb075c35e3fd4c15e0fddc18b5 100644 (file)
--- a/mm/slab.h
+++ b/mm/slab.h
@@ -170,7 +170,7 @@ ssize_t slabinfo_write(struct file *file, const char __user *buffer,
  * may be allocated or freed using these operations.
  */
 void __kmem_cache_free_bulk(struct kmem_cache *, size_t, void **);
-bool __kmem_cache_alloc_bulk(struct kmem_cache *, gfp_t, size_t, void **);
+int __kmem_cache_alloc_bulk(struct kmem_cache *, gfp_t, size_t, void **);
 
 #ifdef CONFIG_MEMCG_KMEM
 /*
index d88e97c10a2e31669753681efc74f6bf50fdf2ef..3c6a86b4ec25f8462c1584dcb5bcf01e4edbd4ff 100644 (file)
@@ -112,7 +112,7 @@ void __kmem_cache_free_bulk(struct kmem_cache *s, size_t nr, void **p)
                kmem_cache_free(s, p[i]);
 }
 
-bool __kmem_cache_alloc_bulk(struct kmem_cache *s, gfp_t flags, size_t nr,
+int __kmem_cache_alloc_bulk(struct kmem_cache *s, gfp_t flags, size_t nr,
                                                                void **p)
 {
        size_t i;
@@ -121,10 +121,10 @@ bool __kmem_cache_alloc_bulk(struct kmem_cache *s, gfp_t flags, size_t nr,
                void *x = p[i] = kmem_cache_alloc(s, flags);
                if (!x) {
                        __kmem_cache_free_bulk(s, i, p);
-                       return false;
+                       return 0;
                }
        }
-       return true;
+       return i;
 }
 
 #ifdef CONFIG_MEMCG_KMEM
index 0d7e5df74d1f03e7069d1d938452b9474bc9a969..17e8f8cc7c534adca165f6d0e9b546e2f8484148 100644 (file)
--- a/mm/slob.c
+++ b/mm/slob.c
@@ -617,7 +617,7 @@ void kmem_cache_free_bulk(struct kmem_cache *s, size_t size, void **p)
 }
 EXPORT_SYMBOL(kmem_cache_free_bulk);
 
-bool kmem_cache_alloc_bulk(struct kmem_cache *s, gfp_t flags, size_t size,
+int kmem_cache_alloc_bulk(struct kmem_cache *s, gfp_t flags, size_t size,
                                                                void **p)
 {
        return __kmem_cache_alloc_bulk(s, flags, size, p);
index 7cb4bf9ae32002494e519130a71af0532de4af87..46997517406ede0e987388763c9fa1d07875c1db 100644 (file)
--- a/mm/slub.c
+++ b/mm/slub.c
@@ -1065,11 +1065,15 @@ bad:
        return 0;
 }
 
+/* Supports checking bulk free of a constructed freelist */
 static noinline struct kmem_cache_node *free_debug_processing(
-       struct kmem_cache *s, struct page *page, void *object,
+       struct kmem_cache *s, struct page *page,
+       void *head, void *tail, int bulk_cnt,
        unsigned long addr, unsigned long *flags)
 {
        struct kmem_cache_node *n = get_node(s, page_to_nid(page));
+       void *object = head;
+       int cnt = 0;
 
        spin_lock_irqsave(&n->list_lock, *flags);
        slab_lock(page);
@@ -1077,6 +1081,9 @@ static noinline struct kmem_cache_node *free_debug_processing(
        if (!check_slab(s, page))
                goto fail;
 
+next_object:
+       cnt++;
+
        if (!check_valid_pointer(s, page, object)) {
                slab_err(s, page, "Invalid object pointer 0x%p", object);
                goto fail;
@@ -1107,8 +1114,19 @@ static noinline struct kmem_cache_node *free_debug_processing(
        if (s->flags & SLAB_STORE_USER)
                set_track(s, object, TRACK_FREE, addr);
        trace(s, page, object, 0);
+       /* Freepointer not overwritten by init_object(), SLAB_POISON moved it */
        init_object(s, object, SLUB_RED_INACTIVE);
+
+       /* Reached end of constructed freelist yet? */
+       if (object != tail) {
+               object = get_freepointer(s, object);
+               goto next_object;
+       }
 out:
+       if (cnt != bulk_cnt)
+               slab_err(s, page, "Bulk freelist count(%d) invalid(%d)\n",
+                        bulk_cnt, cnt);
+
        slab_unlock(page);
        /*
         * Keep node_lock to preserve integrity
@@ -1204,7 +1222,7 @@ unsigned long kmem_cache_flags(unsigned long object_size,
 
        return flags;
 }
-#else
+#else /* !CONFIG_SLUB_DEBUG */
 static inline void setup_object_debug(struct kmem_cache *s,
                        struct page *page, void *object) {}
 
@@ -1212,7 +1230,8 @@ static inline int alloc_debug_processing(struct kmem_cache *s,
        struct page *page, void *object, unsigned long addr) { return 0; }
 
 static inline struct kmem_cache_node *free_debug_processing(
-       struct kmem_cache *s, struct page *page, void *object,
+       struct kmem_cache *s, struct page *page,
+       void *head, void *tail, int bulk_cnt,
        unsigned long addr, unsigned long *flags) { return NULL; }
 
 static inline int slab_pad_check(struct kmem_cache *s, struct page *page)
@@ -1273,14 +1292,21 @@ static inline struct kmem_cache *slab_pre_alloc_hook(struct kmem_cache *s,
        return memcg_kmem_get_cache(s, flags);
 }
 
-static inline void slab_post_alloc_hook(struct kmem_cache *s,
-                                       gfp_t flags, void *object)
+static inline void slab_post_alloc_hook(struct kmem_cache *s, gfp_t flags,
+                                       size_t size, void **p)
 {
+       size_t i;
+
        flags &= gfp_allowed_mask;
-       kmemcheck_slab_alloc(s, flags, object, slab_ksize(s));
-       kmemleak_alloc_recursive(object, s->object_size, 1, s->flags, flags);
+       for (i = 0; i < size; i++) {
+               void *object = p[i];
+
+               kmemcheck_slab_alloc(s, flags, object, slab_ksize(s));
+               kmemleak_alloc_recursive(object, s->object_size, 1,
+                                        s->flags, flags);
+               kasan_slab_alloc(s, object);
+       }
        memcg_kmem_put_cache(s);
-       kasan_slab_alloc(s, object);
 }
 
 static inline void slab_free_hook(struct kmem_cache *s, void *x)
@@ -1308,6 +1334,29 @@ static inline void slab_free_hook(struct kmem_cache *s, void *x)
        kasan_slab_free(s, x);
 }
 
+static inline void slab_free_freelist_hook(struct kmem_cache *s,
+                                          void *head, void *tail)
+{
+/*
+ * Compiler cannot detect this function can be removed if slab_free_hook()
+ * evaluates to nothing.  Thus, catch all relevant config debug options here.
+ */
+#if defined(CONFIG_KMEMCHECK) ||               \
+       defined(CONFIG_LOCKDEP) ||              \
+       defined(CONFIG_DEBUG_KMEMLEAK) ||       \
+       defined(CONFIG_DEBUG_OBJECTS_FREE) ||   \
+       defined(CONFIG_KASAN)
+
+       void *object = head;
+       void *tail_obj = tail ? : head;
+
+       do {
+               slab_free_hook(s, object);
+       } while ((object != tail_obj) &&
+                (object = get_freepointer(s, object)));
+#endif
+}
+
 static void setup_object(struct kmem_cache *s, struct page *page,
                                void *object)
 {
@@ -2295,23 +2344,15 @@ static inline void *get_freelist(struct kmem_cache *s, struct page *page)
  * And if we were unable to get a new slab from the partial slab lists then
  * we need to allocate a new slab. This is the slowest path since it involves
  * a call to the page allocator and the setup of a new slab.
+ *
+ * Version of __slab_alloc to use when we know that interrupts are
+ * already disabled (which is the case for bulk allocation).
  */
-static void *__slab_alloc(struct kmem_cache *s, gfp_t gfpflags, int node,
+static void *___slab_alloc(struct kmem_cache *s, gfp_t gfpflags, int node,
                          unsigned long addr, struct kmem_cache_cpu *c)
 {
        void *freelist;
        struct page *page;
-       unsigned long flags;
-
-       local_irq_save(flags);
-#ifdef CONFIG_PREEMPT
-       /*
-        * We may have been preempted and rescheduled on a different
-        * cpu before disabling interrupts. Need to reload cpu area
-        * pointer.
-        */
-       c = this_cpu_ptr(s->cpu_slab);
-#endif
 
        page = c->page;
        if (!page)
@@ -2369,7 +2410,6 @@ load_freelist:
        VM_BUG_ON(!c->page->frozen);
        c->freelist = get_freepointer(s, freelist);
        c->tid = next_tid(c->tid);
-       local_irq_restore(flags);
        return freelist;
 
 new_slab:
@@ -2386,7 +2426,6 @@ new_slab:
 
        if (unlikely(!freelist)) {
                slab_out_of_memory(s, gfpflags, node);
-               local_irq_restore(flags);
                return NULL;
        }
 
@@ -2402,10 +2441,34 @@ new_slab:
        deactivate_slab(s, page, get_freepointer(s, freelist));
        c->page = NULL;
        c->freelist = NULL;
-       local_irq_restore(flags);
        return freelist;
 }
 
+/*
+ * Another one that disabled interrupt and compensates for possible
+ * cpu changes by refetching the per cpu area pointer.
+ */
+static void *__slab_alloc(struct kmem_cache *s, gfp_t gfpflags, int node,
+                         unsigned long addr, struct kmem_cache_cpu *c)
+{
+       void *p;
+       unsigned long flags;
+
+       local_irq_save(flags);
+#ifdef CONFIG_PREEMPT
+       /*
+        * We may have been preempted and rescheduled on a different
+        * cpu before disabling interrupts. Need to reload cpu area
+        * pointer.
+        */
+       c = this_cpu_ptr(s->cpu_slab);
+#endif
+
+       p = ___slab_alloc(s, gfpflags, node, addr, c);
+       local_irq_restore(flags);
+       return p;
+}
+
 /*
  * Inlined fastpath so that allocation functions (kmalloc, kmem_cache_alloc)
  * have the fastpath folded into their functions. So no function call
@@ -2419,7 +2482,7 @@ new_slab:
 static __always_inline void *slab_alloc_node(struct kmem_cache *s,
                gfp_t gfpflags, int node, unsigned long addr)
 {
-       void **object;
+       void *object;
        struct kmem_cache_cpu *c;
        struct page *page;
        unsigned long tid;
@@ -2498,7 +2561,7 @@ redo:
        if (unlikely(gfpflags & __GFP_ZERO) && object)
                memset(object, 0, s->object_size);
 
-       slab_post_alloc_hook(s, gfpflags, object);
+       slab_post_alloc_hook(s, gfpflags, 1, &object);
 
        return object;
 }
@@ -2569,10 +2632,11 @@ EXPORT_SYMBOL(kmem_cache_alloc_node_trace);
  * handling required then we can return immediately.
  */
 static void __slab_free(struct kmem_cache *s, struct page *page,
-                       void *x, unsigned long addr)
+                       void *head, void *tail, int cnt,
+                       unsigned long addr)
+
 {
        void *prior;
-       void **object = (void *)x;
        int was_frozen;
        struct page new;
        unsigned long counters;
@@ -2582,7 +2646,8 @@ static void __slab_free(struct kmem_cache *s, struct page *page,
        stat(s, FREE_SLOWPATH);
 
        if (kmem_cache_debug(s) &&
-               !(n = free_debug_processing(s, page, x, addr, &flags)))
+           !(n = free_debug_processing(s, page, head, tail, cnt,
+                                       addr, &flags)))
                return;
 
        do {
@@ -2592,10 +2657,10 @@ static void __slab_free(struct kmem_cache *s, struct page *page,
                }
                prior = page->freelist;
                counters = page->counters;
-               set_freepointer(s, object, prior);
+               set_freepointer(s, tail, prior);
                new.counters = counters;
                was_frozen = new.frozen;
-               new.inuse--;
+               new.inuse -= cnt;
                if ((!new.inuse || !prior) && !was_frozen) {
 
                        if (kmem_cache_has_cpu_partial(s) && !prior) {
@@ -2626,7 +2691,7 @@ static void __slab_free(struct kmem_cache *s, struct page *page,
 
        } while (!cmpxchg_double_slab(s, page,
                prior, counters,
-               object, new.counters,
+               head, new.counters,
                "__slab_free"));
 
        if (likely(!n)) {
@@ -2691,15 +2756,20 @@ slab_empty:
  *
  * If fastpath is not possible then fall back to __slab_free where we deal
  * with all sorts of special processing.
+ *
+ * Bulk free of a freelist with several objects (all pointing to the
+ * same page) possible by specifying head and tail ptr, plus objects
+ * count (cnt). Bulk free indicated by tail pointer being set.
  */
-static __always_inline void slab_free(struct kmem_cache *s,
-                       struct page *page, void *x, unsigned long addr)
+static __always_inline void slab_free(struct kmem_cache *s, struct page *page,
+                                     void *head, void *tail, int cnt,
+                                     unsigned long addr)
 {
-       void **object = (void *)x;
+       void *tail_obj = tail ? : head;
        struct kmem_cache_cpu *c;
        unsigned long tid;
 
-       slab_free_hook(s, x);
+       slab_free_freelist_hook(s, head, tail);
 
 redo:
        /*
@@ -2718,19 +2788,19 @@ redo:
        barrier();
 
        if (likely(page == c->page)) {
-               set_freepointer(s, object, c->freelist);
+               set_freepointer(s, tail_obj, c->freelist);
 
                if (unlikely(!this_cpu_cmpxchg_double(
                                s->cpu_slab->freelist, s->cpu_slab->tid,
                                c->freelist, tid,
-                               object, next_tid(tid)))) {
+                               head, next_tid(tid)))) {
 
                        note_cmpxchg_failure("slab_free", s, tid);
                        goto redo;
                }
                stat(s, FREE_FASTPATH);
        } else
-               __slab_free(s, page, x, addr);
+               __slab_free(s, page, head, tail_obj, cnt, addr);
 
 }
 
@@ -2739,59 +2809,116 @@ void kmem_cache_free(struct kmem_cache *s, void *x)
        s = cache_from_obj(s, x);
        if (!s)
                return;
-       slab_free(s, virt_to_head_page(x), x, _RET_IP_);
+       slab_free(s, virt_to_head_page(x), x, NULL, 1, _RET_IP_);
        trace_kmem_cache_free(_RET_IP_, x);
 }
 EXPORT_SYMBOL(kmem_cache_free);
 
-/* Note that interrupts must be enabled when calling this function. */
-void kmem_cache_free_bulk(struct kmem_cache *s, size_t size, void **p)
-{
-       struct kmem_cache_cpu *c;
+struct detached_freelist {
        struct page *page;
-       int i;
+       void *tail;
+       void *freelist;
+       int cnt;
+};
 
-       local_irq_disable();
-       c = this_cpu_ptr(s->cpu_slab);
+/*
+ * This function progressively scans the array with free objects (with
+ * a limited look ahead) and extract objects belonging to the same
+ * page.  It builds a detached freelist directly within the given
+ * page/objects.  This can happen without any need for
+ * synchronization, because the objects are owned by running process.
+ * The freelist is build up as a single linked list in the objects.
+ * The idea is, that this detached freelist can then be bulk
+ * transferred to the real freelist(s), but only requiring a single
+ * synchronization primitive.  Look ahead in the array is limited due
+ * to performance reasons.
+ */
+static int build_detached_freelist(struct kmem_cache *s, size_t size,
+                                  void **p, struct detached_freelist *df)
+{
+       size_t first_skipped_index = 0;
+       int lookahead = 3;
+       void *object;
 
-       for (i = 0; i < size; i++) {
-               void *object = p[i];
+       /* Always re-init detached_freelist */
+       df->page = NULL;
 
-               BUG_ON(!object);
-               /* kmem cache debug support */
-               s = cache_from_obj(s, object);
-               if (unlikely(!s))
-                       goto exit;
-               slab_free_hook(s, object);
+       do {
+               object = p[--size];
+       } while (!object && size);
 
-               page = virt_to_head_page(object);
+       if (!object)
+               return 0;
 
-               if (c->page == page) {
-                       /* Fastpath: local CPU free */
-                       set_freepointer(s, object, c->freelist);
-                       c->freelist = object;
-               } else {
-                       c->tid = next_tid(c->tid);
-                       local_irq_enable();
-                       /* Slowpath: overhead locked cmpxchg_double_slab */
-                       __slab_free(s, page, object, _RET_IP_);
-                       local_irq_disable();
-                       c = this_cpu_ptr(s->cpu_slab);
+       /* Start new detached freelist */
+       set_freepointer(s, object, NULL);
+       df->page = virt_to_head_page(object);
+       df->tail = object;
+       df->freelist = object;
+       p[size] = NULL; /* mark object processed */
+       df->cnt = 1;
+
+       while (size) {
+               object = p[--size];
+               if (!object)
+                       continue; /* Skip processed objects */
+
+               /* df->page is always set at this point */
+               if (df->page == virt_to_head_page(object)) {
+                       /* Opportunity build freelist */
+                       set_freepointer(s, object, df->freelist);
+                       df->freelist = object;
+                       df->cnt++;
+                       p[size] = NULL; /* mark object processed */
+
+                       continue;
                }
+
+               /* Limit look ahead search */
+               if (!--lookahead)
+                       break;
+
+               if (!first_skipped_index)
+                       first_skipped_index = size + 1;
        }
-exit:
-       c->tid = next_tid(c->tid);
-       local_irq_enable();
+
+       return first_skipped_index;
+}
+
+
+/* Note that interrupts must be enabled when calling this function. */
+void kmem_cache_free_bulk(struct kmem_cache *orig_s, size_t size, void **p)
+{
+       if (WARN_ON(!size))
+               return;
+
+       do {
+               struct detached_freelist df;
+               struct kmem_cache *s;
+
+               /* Support for memcg */
+               s = cache_from_obj(orig_s, p[size - 1]);
+
+               size = build_detached_freelist(s, size, p, &df);
+               if (unlikely(!df.page))
+                       continue;
+
+               slab_free(s, df.page, df.freelist, df.tail, df.cnt, _RET_IP_);
+       } while (likely(size));
 }
 EXPORT_SYMBOL(kmem_cache_free_bulk);
 
 /* Note that interrupts must be enabled when calling this function. */
-bool kmem_cache_alloc_bulk(struct kmem_cache *s, gfp_t flags, size_t size,
-                          void **p)
+int kmem_cache_alloc_bulk(struct kmem_cache *s, gfp_t flags, size_t size,
+                         void **p)
 {
        struct kmem_cache_cpu *c;
        int i;
 
+       /* memcg and kmem_cache debug support */
+       s = slab_pre_alloc_hook(s, flags);
+       if (unlikely(!s))
+               return false;
        /*
         * Drain objects in the per cpu slab, while disabling local
         * IRQs, which protects against PREEMPT and interrupts
@@ -2804,36 +2931,20 @@ bool kmem_cache_alloc_bulk(struct kmem_cache *s, gfp_t flags, size_t size,
                void *object = c->freelist;
 
                if (unlikely(!object)) {
-                       local_irq_enable();
                        /*
                         * Invoking slow path likely have side-effect
                         * of re-populating per CPU c->freelist
                         */
-                       p[i] = __slab_alloc(s, flags, NUMA_NO_NODE,
+                       p[i] = ___slab_alloc(s, flags, NUMA_NO_NODE,
                                            _RET_IP_, c);
-                       if (unlikely(!p[i])) {
-                               __kmem_cache_free_bulk(s, i, p);
-                               return false;
-                       }
-                       local_irq_disable();
+                       if (unlikely(!p[i]))
+                               goto error;
+
                        c = this_cpu_ptr(s->cpu_slab);
                        continue; /* goto for-loop */
                }
-
-               /* kmem_cache debug support */
-               s = slab_pre_alloc_hook(s, flags);
-               if (unlikely(!s)) {
-                       __kmem_cache_free_bulk(s, i, p);
-                       c->tid = next_tid(c->tid);
-                       local_irq_enable();
-                       return false;
-               }
-
                c->freelist = get_freepointer(s, object);
                p[i] = object;
-
-               /* kmem_cache debug support */
-               slab_post_alloc_hook(s, flags, object);
        }
        c->tid = next_tid(c->tid);
        local_irq_enable();
@@ -2846,7 +2957,14 @@ bool kmem_cache_alloc_bulk(struct kmem_cache *s, gfp_t flags, size_t size,
                        memset(p[j], 0, s->object_size);
        }
 
-       return true;
+       /* memcg and kmem_cache debug support */
+       slab_post_alloc_hook(s, flags, size, p);
+       return i;
+error:
+       local_irq_enable();
+       slab_post_alloc_hook(s, flags, i, p);
+       __kmem_cache_free_bulk(s, i, p);
+       return 0;
 }
 EXPORT_SYMBOL(kmem_cache_alloc_bulk);
 
@@ -3511,7 +3629,7 @@ void kfree(const void *x)
                __free_kmem_pages(page, compound_order(page));
                return;
        }
-       slab_free(page->slab_cache, page, object, _RET_IP_);
+       slab_free(page->slab_cache, page, object, NULL, 1, _RET_IP_);
 }
 EXPORT_SYMBOL(kfree);
 
index d04563480c94f4137efb6102e8d8beaef3a9dda7..8e3c9c5a3042b6149ff783bb1dfc0c0e08dc4046 100644 (file)
@@ -1443,7 +1443,6 @@ struct vm_struct *remove_vm_area(const void *addr)
                vmap_debug_free_range(va->va_start, va->va_end);
                kasan_free_shadow(vm);
                free_unmap_vmap_area(va);
-               vm->size -= PAGE_SIZE;
 
                return vm;
        }
@@ -1468,8 +1467,8 @@ static void __vunmap(const void *addr, int deallocate_pages)
                return;
        }
 
-       debug_check_no_locks_freed(addr, area->size);
-       debug_check_no_obj_freed(addr, area->size);
+       debug_check_no_locks_freed(addr, get_vm_area_size(area));
+       debug_check_no_obj_freed(addr, get_vm_area_size(area));
 
        if (deallocate_pages) {
                int i;
index 879a2be23325ce73158e097eb381628a5fd5f548..4ebc17d948cb8414e3e2b0ea5b8f9342f71c77c2 100644 (file)
@@ -219,7 +219,7 @@ void set_pgdat_percpu_threshold(pg_data_t *pgdat,
  * particular counter cannot be updated from interrupt context.
  */
 void __mod_zone_page_state(struct zone *zone, enum zone_stat_item item,
-                               int delta)
+                          long delta)
 {
        struct per_cpu_pageset __percpu *pcp = zone->pageset;
        s8 __percpu *p = pcp->vm_stat_diff + item;
@@ -318,8 +318,8 @@ EXPORT_SYMBOL(__dec_zone_page_state);
  *     1       Overstepping half of threshold
  *     -1      Overstepping minus half of threshold
 */
-static inline void mod_state(struct zone *zone,
-       enum zone_stat_item item, int delta, int overstep_mode)
+static inline void mod_state(struct zone *zone, enum zone_stat_item item,
+                            long delta, int overstep_mode)
 {
        struct per_cpu_pageset __percpu *pcp = zone->pageset;
        s8 __percpu *p = pcp->vm_stat_diff + item;
@@ -357,7 +357,7 @@ static inline void mod_state(struct zone *zone,
 }
 
 void mod_zone_page_state(struct zone *zone, enum zone_stat_item item,
-                                       int delta)
+                        long delta)
 {
        mod_state(zone, item, delta, 0);
 }
@@ -384,7 +384,7 @@ EXPORT_SYMBOL(dec_zone_page_state);
  * Use interrupt disable to serialize counter updates
  */
 void mod_zone_page_state(struct zone *zone, enum zone_stat_item item,
-                                       int delta)
+                        long delta)
 {
        unsigned long flags;
 
@@ -921,8 +921,8 @@ static void walk_zones_in_node(struct seq_file *m, pg_data_t *pgdat,
 #ifdef CONFIG_PROC_FS
 static char * const migratetype_names[MIGRATE_TYPES] = {
        "Unmovable",
-       "Reclaimable",
        "Movable",
+       "Reclaimable",
        "HighAtomic",
 #ifdef CONFIG_CMA
        "CMA",
@@ -1379,6 +1379,7 @@ static const struct file_operations proc_vmstat_file_operations = {
 #endif /* CONFIG_PROC_FS */
 
 #ifdef CONFIG_SMP
+static struct workqueue_struct *vmstat_wq;
 static DEFINE_PER_CPU(struct delayed_work, vmstat_work);
 int sysctl_stat_interval __read_mostly = HZ;
 static cpumask_var_t cpu_stat_off;
@@ -1391,7 +1392,7 @@ static void vmstat_update(struct work_struct *w)
                 * to occur in the future. Keep on running the
                 * update worker thread.
                 */
-               schedule_delayed_work_on(smp_processor_id(),
+               queue_delayed_work_on(smp_processor_id(), vmstat_wq,
                        this_cpu_ptr(&vmstat_work),
                        round_jiffies_relative(sysctl_stat_interval));
        } else {
@@ -1460,7 +1461,7 @@ static void vmstat_shepherd(struct work_struct *w)
                if (need_update(cpu) &&
                        cpumask_test_and_clear_cpu(cpu, cpu_stat_off))
 
-                       schedule_delayed_work_on(cpu,
+                       queue_delayed_work_on(cpu, vmstat_wq,
                                &per_cpu(vmstat_work, cpu), 0);
 
        put_online_cpus();
@@ -1549,6 +1550,7 @@ static int __init setup_vmstat(void)
 
        start_shepherd_timer();
        cpu_notifier_register_done();
+       vmstat_wq = alloc_workqueue("vmstat", WQ_FREEZABLE|WQ_MEM_RECLAIM, 0);
 #endif
 #ifdef CONFIG_PROC_FS
        proc_create("buddyinfo", S_IRUGO, NULL, &fragmentation_file_operations);
index 025f8dc723dedf60da7d2d9d580ac208e75cd8f6..bf14508afd64573d8310a5a3e12b99b629fc8c02 100644 (file)
@@ -541,6 +541,7 @@ static struct zswap_pool *zswap_pool_last_get(void)
        return last;
 }
 
+/* type and compressor must be null-terminated */
 static struct zswap_pool *zswap_pool_find_get(char *type, char *compressor)
 {
        struct zswap_pool *pool;
@@ -548,10 +549,9 @@ static struct zswap_pool *zswap_pool_find_get(char *type, char *compressor)
        assert_spin_locked(&zswap_pools_lock);
 
        list_for_each_entry_rcu(pool, &zswap_pools, list) {
-               if (strncmp(pool->tfm_name, compressor, sizeof(pool->tfm_name)))
+               if (strcmp(pool->tfm_name, compressor))
                        continue;
-               if (strncmp(zpool_get_type(pool->zpool), type,
-                           sizeof(zswap_zpool_type)))
+               if (strcmp(zpool_get_type(pool->zpool), type))
                        continue;
                /* if we can't get it, it's about to be destroyed */
                if (!zswap_pool_get(pool))
index 496b27588493ded6edb0bf408440ecaa56dcd59c..e2ed69850489bb79a6a055ee3264456a31acee3e 100644 (file)
@@ -30,7 +30,9 @@ bool vlan_do_receive(struct sk_buff **skbp)
                        skb->pkt_type = PACKET_HOST;
        }
 
-       if (!(vlan_dev_priv(vlan_dev)->flags & VLAN_FLAG_REORDER_HDR)) {
+       if (!(vlan_dev_priv(vlan_dev)->flags & VLAN_FLAG_REORDER_HDR) &&
+           !netif_is_macvlan_port(vlan_dev) &&
+           !netif_is_bridge_port(vlan_dev)) {
                unsigned int offset = skb->data - skb_mac_header(skb);
 
                /*
index ae3a47f9d1d5298406ca33900624fe49c9c85719..fbd0acf80b13236bd8c768bc8bf5d69d6a7e7125 100644 (file)
@@ -805,6 +805,9 @@ static int ax25_create(struct net *net, struct socket *sock, int protocol,
        struct sock *sk;
        ax25_cb *ax25;
 
+       if (protocol < 0 || protocol > SK_PROTOCOL_MAX)
+               return -EINVAL;
+
        if (!net_eq(net, &init_net))
                return -EAFNOSUPPORT;
 
index 83bc1aaf5800cbc68aa8a33f967a2ae5533af801..a49c705fb86b861f5595c8c0cfb7b8b1e1010589 100644 (file)
@@ -566,6 +566,7 @@ batadv_dat_select_candidates(struct batadv_priv *bat_priv, __be32 ip_dst)
        int select;
        batadv_dat_addr_t last_max = BATADV_DAT_ADDR_MAX, ip_key;
        struct batadv_dat_candidate *res;
+       struct batadv_dat_entry dat;
 
        if (!bat_priv->orig_hash)
                return NULL;
@@ -575,7 +576,9 @@ batadv_dat_select_candidates(struct batadv_priv *bat_priv, __be32 ip_dst)
        if (!res)
                return NULL;
 
-       ip_key = (batadv_dat_addr_t)batadv_hash_dat(&ip_dst,
+       dat.ip = ip_dst;
+       dat.vid = 0;
+       ip_key = (batadv_dat_addr_t)batadv_hash_dat(&dat,
                                                    BATADV_DAT_ADDR_MAX);
 
        batadv_dbg(BATADV_DBG_DAT, bat_priv,
index 8d990b070a2e87db6a6e71f9e3eaad93dbf4a59e..3207667e69de30e92499c705f39319c55f36732f 100644 (file)
@@ -836,6 +836,7 @@ int batadv_recv_unicast_packet(struct sk_buff *skb,
        u8 *orig_addr;
        struct batadv_orig_node *orig_node = NULL;
        int check, hdr_size = sizeof(*unicast_packet);
+       enum batadv_subtype subtype;
        bool is4addr;
 
        unicast_packet = (struct batadv_unicast_packet *)skb->data;
@@ -863,10 +864,20 @@ int batadv_recv_unicast_packet(struct sk_buff *skb,
        /* packet for me */
        if (batadv_is_my_mac(bat_priv, unicast_packet->dest)) {
                if (is4addr) {
-                       batadv_dat_inc_counter(bat_priv,
-                                              unicast_4addr_packet->subtype);
-                       orig_addr = unicast_4addr_packet->src;
-                       orig_node = batadv_orig_hash_find(bat_priv, orig_addr);
+                       subtype = unicast_4addr_packet->subtype;
+                       batadv_dat_inc_counter(bat_priv, subtype);
+
+                       /* Only payload data should be considered for speedy
+                        * join. For example, DAT also uses unicast 4addr
+                        * types, but those packets should not be considered
+                        * for speedy join, since the clients do not actually
+                        * reside at the sending originator.
+                        */
+                       if (subtype == BATADV_P_DATA) {
+                               orig_addr = unicast_4addr_packet->src;
+                               orig_node = batadv_orig_hash_find(bat_priv,
+                                                                 orig_addr);
+                       }
                }
 
                if (batadv_dat_snoop_incoming_arp_request(bat_priv, skb,
index 4228b10c47ead06db9284997afc1899e181d6505..76f19ba62462bf03fadba72171d3ae01a565ba57 100644 (file)
@@ -68,13 +68,15 @@ static void batadv_tt_global_del(struct batadv_priv *bat_priv,
                                 unsigned short vid, const char *message,
                                 bool roaming);
 
-/* returns 1 if they are the same mac addr */
+/* returns 1 if they are the same mac addr and vid */
 static int batadv_compare_tt(const struct hlist_node *node, const void *data2)
 {
        const void *data1 = container_of(node, struct batadv_tt_common_entry,
                                         hash_entry);
+       const struct batadv_tt_common_entry *tt1 = data1;
+       const struct batadv_tt_common_entry *tt2 = data2;
 
-       return batadv_compare_eth(data1, data2);
+       return (tt1->vid == tt2->vid) && batadv_compare_eth(data1, data2);
 }
 
 /**
@@ -1427,9 +1429,15 @@ static bool batadv_tt_global_add(struct batadv_priv *bat_priv,
                }
 
                /* if the client was temporary added before receiving the first
-                * OGM announcing it, we have to clear the TEMP flag
+                * OGM announcing it, we have to clear the TEMP flag. Also,
+                * remove the previous temporary orig node and re-add it
+                * if required. If the orig entry changed, the new one which
+                * is a non-temporary entry is preferred.
                 */
-               common->flags &= ~BATADV_TT_CLIENT_TEMP;
+               if (common->flags & BATADV_TT_CLIENT_TEMP) {
+                       batadv_tt_global_del_orig_list(tt_global_entry);
+                       common->flags &= ~BATADV_TT_CLIENT_TEMP;
+               }
 
                /* the change can carry possible "attribute" flags like the
                 * TT_CLIENT_WIFI, therefore they have to be copied in the
index a3bffd1ec2b46adbc7a2130573ae991950789a77..70306cc9d8140f696e440de10f9fff864b0abd94 100644 (file)
@@ -271,11 +271,11 @@ static long bt_sock_data_wait(struct sock *sk, long timeo)
                if (signal_pending(current) || !timeo)
                        break;
 
-               set_bit(SOCK_ASYNC_WAITDATA, &sk->sk_socket->flags);
+               sk_set_bit(SOCKWQ_ASYNC_WAITDATA, sk);
                release_sock(sk);
                timeo = schedule_timeout(timeo);
                lock_sock(sk);
-               clear_bit(SOCK_ASYNC_WAITDATA, &sk->sk_socket->flags);
+               sk_clear_bit(SOCKWQ_ASYNC_WAITDATA, sk);
        }
 
        __set_current_state(TASK_RUNNING);
@@ -441,7 +441,7 @@ unsigned int bt_sock_poll(struct file *file, struct socket *sock,
        if (!test_bit(BT_SK_SUSPEND, &bt_sk(sk)->flags) && sock_writeable(sk))
                mask |= POLLOUT | POLLWRNORM | POLLWRBAND;
        else
-               set_bit(SOCK_ASYNC_NOSPACE, &sk->sk_socket->flags);
+               sk_set_bit(SOCKWQ_ASYNC_NOSPACE, sk);
 
        return mask;
 }
index fe129663bd3f7faeb39f20d02a8425d525da071d..f52bcbf2e58cd8b8ded4c3d65c8dd9b87034b002 100644 (file)
@@ -526,6 +526,9 @@ static int sco_sock_bind(struct socket *sock, struct sockaddr *addr,
        if (!addr || addr->sa_family != AF_BLUETOOTH)
                return -EINVAL;
 
+       if (addr_len < sizeof(struct sockaddr_sco))
+               return -EINVAL;
+
        lock_sock(sk);
 
        if (sk->sk_state != BT_OPEN) {
index c91353841e40500790c13d2ce894460e1cbbe9e3..ffed8a1d4f27634866c93d22b4ceb059b956cc91 100644 (file)
@@ -3027,8 +3027,13 @@ static void smp_ready_cb(struct l2cap_chan *chan)
 
        BT_DBG("chan %p", chan);
 
+       /* No need to call l2cap_chan_hold() here since we already own
+        * the reference taken in smp_new_conn_cb(). This is just the
+        * first time that we tie it to a specific pointer. The code in
+        * l2cap_core.c ensures that there's no risk this function wont
+        * get called if smp_new_conn_cb was previously called.
+        */
        conn->smp = chan;
-       l2cap_chan_hold(chan);
 
        if (hcon->type == ACL_LINK && test_bit(HCI_CONN_ENCRYPT, &hcon->flags))
                bredr_pairing(chan);
index f7e8dee64fc80ec04152788c945dea1b346b3dcd..5f3f6455317924e0e74281d23075d2af68d72d73 100644 (file)
@@ -48,7 +48,7 @@ void br_set_state(struct net_bridge_port *p, unsigned int state)
 
        p->state = state;
        err = switchdev_port_attr_set(p->dev, &attr);
-       if (err)
+       if (err && err != -EOPNOTSUPP)
                br_warn(p->br, "error setting offload STP state on port %u(%s)\n",
                                (unsigned int) p->port_no, p->dev->name);
 }
index fa53d7a89f485ac9039b6168db3063512c4d9d42..12045dea276c2ddae68f0d17ad0444eba02b8d02 100644 (file)
@@ -39,7 +39,7 @@ void br_init_port(struct net_bridge_port *p)
        struct switchdev_attr attr = {
                .id = SWITCHDEV_ATTR_ID_BRIDGE_AGEING_TIME,
                .flags = SWITCHDEV_F_SKIP_EOPNOTSUPP | SWITCHDEV_F_DEFER,
-               .u.ageing_time = p->br->ageing_time,
+               .u.ageing_time = jiffies_to_clock_t(p->br->ageing_time),
        };
        int err;
 
@@ -50,7 +50,7 @@ void br_init_port(struct net_bridge_port *p)
        p->config_pending = 0;
 
        err = switchdev_port_attr_set(p->dev, &attr);
-       if (err)
+       if (err && err != -EOPNOTSUPP)
                netdev_err(p->dev, "failed to set HW ageing time\n");
 }
 
index cc858919108ee1f9645bce1046be8650a640d821..aa209b1066c9699a12510055e70ae79b33ee05b7 100644 (file)
@@ -323,7 +323,7 @@ static long caif_stream_data_wait(struct sock *sk, long timeo)
                        !timeo)
                        break;
 
-               set_bit(SOCK_ASYNC_WAITDATA, &sk->sk_socket->flags);
+               sk_set_bit(SOCKWQ_ASYNC_WAITDATA, sk);
                release_sock(sk);
                timeo = schedule_timeout(timeo);
                lock_sock(sk);
@@ -331,7 +331,7 @@ static long caif_stream_data_wait(struct sock *sk, long timeo)
                if (sock_flag(sk, SOCK_DEAD))
                        break;
 
-               clear_bit(SOCK_ASYNC_WAITDATA, &sk->sk_socket->flags);
+               sk_clear_bit(SOCKWQ_ASYNC_WAITDATA, sk);
        }
 
        finish_wait(sk_sleep(sk), &wait);
index 617088aee21d41ba98d4ef5ebee5d6c002efe029..d62af69ad844de0f940cdc2f38c5e2720053895c 100644 (file)
@@ -785,7 +785,7 @@ unsigned int datagram_poll(struct file *file, struct socket *sock,
        if (sock_writeable(sk))
                mask |= POLLOUT | POLLWRNORM | POLLWRBAND;
        else
-               set_bit(SOCK_ASYNC_NOSPACE, &sk->sk_socket->flags);
+               sk_set_bit(SOCKWQ_ASYNC_NOSPACE, sk);
 
        return mask;
 }
index ab9b8d0d115e4ce479fed2aa8304947be09f1f32..ae00b894e67555257b1ba81dd57cecec72eed161 100644 (file)
@@ -2403,17 +2403,20 @@ static void skb_warn_bad_offload(const struct sk_buff *skb)
 {
        static const netdev_features_t null_features = 0;
        struct net_device *dev = skb->dev;
-       const char *driver = "";
+       const char *name = "";
 
        if (!net_ratelimit())
                return;
 
-       if (dev && dev->dev.parent)
-               driver = dev_driver_string(dev->dev.parent);
-
+       if (dev) {
+               if (dev->dev.parent)
+                       name = dev_driver_string(dev->dev.parent);
+               else
+                       name = netdev_name(dev);
+       }
        WARN(1, "%s: caps=(%pNF, %pNF) len=%d data_len=%d gso_size=%d "
             "gso_type=%d ip_summed=%d\n",
-            driver, dev ? &dev->features : &null_features,
+            name, dev ? &dev->features : &null_features,
             skb->sk ? &skb->sk->sk_route_caps : &null_features,
             skb->len, skb->data_len, skb_shinfo(skb)->gso_size,
             skb_shinfo(skb)->gso_type, skb->ip_summed);
@@ -6426,11 +6429,16 @@ int __netdev_update_features(struct net_device *dev)
 
        if (dev->netdev_ops->ndo_set_features)
                err = dev->netdev_ops->ndo_set_features(dev, features);
+       else
+               err = 0;
 
        if (unlikely(err < 0)) {
                netdev_err(dev,
                        "set_features() failed (%d); wanted %pNF, left %pNF\n",
                        err, &features, &dev->features);
+               /* return non-0 since some features might have changed and
+                * it's better to fire a spurious notification than miss it
+                */
                return -1;
        }
 
index 1aa8437ed6c4437d196ad513f0d3619198914416..f18ae91b652e971ccba5c03177301f1a46a8da57 100644 (file)
@@ -857,7 +857,7 @@ static void neigh_probe(struct neighbour *neigh)
        struct sk_buff *skb = skb_peek_tail(&neigh->arp_queue);
        /* keep skb alive even if arp_queue overflows */
        if (skb)
-               skb = skb_copy(skb, GFP_ATOMIC);
+               skb = skb_clone(skb, GFP_ATOMIC);
        write_unlock(&neigh->lock);
        neigh->ops->solicit(neigh, skb);
        atomic_inc(&neigh->probes);
@@ -2215,7 +2215,7 @@ static int pneigh_fill_info(struct sk_buff *skb, struct pneigh_entry *pn,
        ndm->ndm_pad2    = 0;
        ndm->ndm_flags   = pn->flags | NTF_PROXY;
        ndm->ndm_type    = RTN_UNICAST;
-       ndm->ndm_ifindex = pn->dev->ifindex;
+       ndm->ndm_ifindex = pn->dev ? pn->dev->ifindex : 0;
        ndm->ndm_state   = NUD_NONE;
 
        if (nla_put(skb, NDA_DST, tbl->key_len, pn->key))
@@ -2333,7 +2333,7 @@ static int pneigh_dump_table(struct neigh_table *tbl, struct sk_buff *skb,
                if (h > s_h)
                        s_idx = 0;
                for (n = tbl->phash_buckets[h], idx = 0; n; n = n->next) {
-                       if (dev_net(n->dev) != net)
+                       if (pneigh_net(n) != net)
                                continue;
                        if (idx < s_idx)
                                goto next;
index 6441f47b1a8ffc78731896fd4ab1b12db43f0992..d9ee8d08a3a6944ebb6e5d8dafe6fb5032aa7a52 100644 (file)
@@ -56,7 +56,7 @@ static void cgrp_css_free(struct cgroup_subsys_state *css)
        kfree(css_cls_state(css));
 }
 
-static int update_classid(const void *v, struct file *file, unsigned n)
+static int update_classid_sock(const void *v, struct file *file, unsigned n)
 {
        int err;
        struct socket *sock = sock_from_file(file, &err);
@@ -67,18 +67,27 @@ static int update_classid(const void *v, struct file *file, unsigned n)
        return 0;
 }
 
-static void cgrp_attach(struct cgroup_subsys_state *css,
-                       struct cgroup_taskset *tset)
+static void update_classid(struct cgroup_subsys_state *css, void *v)
 {
-       struct cgroup_cls_state *cs = css_cls_state(css);
-       void *v = (void *)(unsigned long)cs->classid;
+       struct css_task_iter it;
        struct task_struct *p;
 
-       cgroup_taskset_for_each(p, tset) {
+       css_task_iter_start(css, &it);
+       while ((p = css_task_iter_next(&it))) {
                task_lock(p);
-               iterate_fd(p->files, 0, update_classid, v);
+               iterate_fd(p->files, 0, update_classid_sock, v);
                task_unlock(p);
        }
+       css_task_iter_end(&it);
+}
+
+static void cgrp_attach(struct cgroup_taskset *tset)
+{
+       struct cgroup_subsys_state *css;
+
+       cgroup_taskset_first(tset, &css);
+       update_classid(css,
+                      (void *)(unsigned long)css_cls_state(css)->classid);
 }
 
 static u64 read_classid(struct cgroup_subsys_state *css, struct cftype *cft)
@@ -89,8 +98,11 @@ static u64 read_classid(struct cgroup_subsys_state *css, struct cftype *cft)
 static int write_classid(struct cgroup_subsys_state *css, struct cftype *cft,
                         u64 value)
 {
-       css_cls_state(css)->classid = (u32) value;
+       struct cgroup_cls_state *cs = css_cls_state(css);
+
+       cs->classid = (u32)value;
 
+       update_classid(css, (void *)(unsigned long)cs->classid);
        return 0;
 }
 
index cbd0a199bf52c79780e7935f1ed123f3f86758ec..40fd09fe06ae91e133bbf1fe499e38870903c8ca 100644 (file)
@@ -218,13 +218,14 @@ static int update_netprio(const void *v, struct file *file, unsigned n)
        return 0;
 }
 
-static void net_prio_attach(struct cgroup_subsys_state *css,
-                           struct cgroup_taskset *tset)
+static void net_prio_attach(struct cgroup_taskset *tset)
 {
        struct task_struct *p;
-       void *v = (void *)(unsigned long)css->cgroup->id;
+       struct cgroup_subsys_state *css;
+
+       cgroup_taskset_for_each(p, css, tset) {
+               void *v = (void *)(unsigned long)css->cgroup->id;
 
-       cgroup_taskset_for_each(p, tset) {
                task_lock(p);
                iterate_fd(p->files, 0, update_netprio, v);
                task_unlock(p);
index 504bd17b7456c3a16a0832ed28ede040c41ff316..34ba7a08876de74409ea5d2ad3af6f78124ff0a7 100644 (file)
@@ -1045,15 +1045,156 @@ static int rtnl_phys_switch_id_fill(struct sk_buff *skb, struct net_device *dev)
        return 0;
 }
 
+static noinline_for_stack int rtnl_fill_stats(struct sk_buff *skb,
+                                             struct net_device *dev)
+{
+       const struct rtnl_link_stats64 *stats;
+       struct rtnl_link_stats64 temp;
+       struct nlattr *attr;
+
+       stats = dev_get_stats(dev, &temp);
+
+       attr = nla_reserve(skb, IFLA_STATS,
+                          sizeof(struct rtnl_link_stats));
+       if (!attr)
+               return -EMSGSIZE;
+
+       copy_rtnl_link_stats(nla_data(attr), stats);
+
+       attr = nla_reserve(skb, IFLA_STATS64,
+                          sizeof(struct rtnl_link_stats64));
+       if (!attr)
+               return -EMSGSIZE;
+
+       copy_rtnl_link_stats64(nla_data(attr), stats);
+
+       return 0;
+}
+
+static noinline_for_stack int rtnl_fill_vfinfo(struct sk_buff *skb,
+                                              struct net_device *dev,
+                                              int vfs_num,
+                                              struct nlattr *vfinfo)
+{
+       struct ifla_vf_rss_query_en vf_rss_query_en;
+       struct ifla_vf_link_state vf_linkstate;
+       struct ifla_vf_spoofchk vf_spoofchk;
+       struct ifla_vf_tx_rate vf_tx_rate;
+       struct ifla_vf_stats vf_stats;
+       struct ifla_vf_trust vf_trust;
+       struct ifla_vf_vlan vf_vlan;
+       struct ifla_vf_rate vf_rate;
+       struct nlattr *vf, *vfstats;
+       struct ifla_vf_mac vf_mac;
+       struct ifla_vf_info ivi;
+
+       /* Not all SR-IOV capable drivers support the
+        * spoofcheck and "RSS query enable" query.  Preset to
+        * -1 so the user space tool can detect that the driver
+        * didn't report anything.
+        */
+       ivi.spoofchk = -1;
+       ivi.rss_query_en = -1;
+       ivi.trusted = -1;
+       memset(ivi.mac, 0, sizeof(ivi.mac));
+       /* The default value for VF link state is "auto"
+        * IFLA_VF_LINK_STATE_AUTO which equals zero
+        */
+       ivi.linkstate = 0;
+       if (dev->netdev_ops->ndo_get_vf_config(dev, vfs_num, &ivi))
+               return 0;
+
+       vf_mac.vf =
+               vf_vlan.vf =
+               vf_rate.vf =
+               vf_tx_rate.vf =
+               vf_spoofchk.vf =
+               vf_linkstate.vf =
+               vf_rss_query_en.vf =
+               vf_trust.vf = ivi.vf;
+
+       memcpy(vf_mac.mac, ivi.mac, sizeof(ivi.mac));
+       vf_vlan.vlan = ivi.vlan;
+       vf_vlan.qos = ivi.qos;
+       vf_tx_rate.rate = ivi.max_tx_rate;
+       vf_rate.min_tx_rate = ivi.min_tx_rate;
+       vf_rate.max_tx_rate = ivi.max_tx_rate;
+       vf_spoofchk.setting = ivi.spoofchk;
+       vf_linkstate.link_state = ivi.linkstate;
+       vf_rss_query_en.setting = ivi.rss_query_en;
+       vf_trust.setting = ivi.trusted;
+       vf = nla_nest_start(skb, IFLA_VF_INFO);
+       if (!vf) {
+               nla_nest_cancel(skb, vfinfo);
+               return -EMSGSIZE;
+       }
+       if (nla_put(skb, IFLA_VF_MAC, sizeof(vf_mac), &vf_mac) ||
+           nla_put(skb, IFLA_VF_VLAN, sizeof(vf_vlan), &vf_vlan) ||
+           nla_put(skb, IFLA_VF_RATE, sizeof(vf_rate),
+                   &vf_rate) ||
+           nla_put(skb, IFLA_VF_TX_RATE, sizeof(vf_tx_rate),
+                   &vf_tx_rate) ||
+           nla_put(skb, IFLA_VF_SPOOFCHK, sizeof(vf_spoofchk),
+                   &vf_spoofchk) ||
+           nla_put(skb, IFLA_VF_LINK_STATE, sizeof(vf_linkstate),
+                   &vf_linkstate) ||
+           nla_put(skb, IFLA_VF_RSS_QUERY_EN,
+                   sizeof(vf_rss_query_en),
+                   &vf_rss_query_en) ||
+           nla_put(skb, IFLA_VF_TRUST,
+                   sizeof(vf_trust), &vf_trust))
+               return -EMSGSIZE;
+       memset(&vf_stats, 0, sizeof(vf_stats));
+       if (dev->netdev_ops->ndo_get_vf_stats)
+               dev->netdev_ops->ndo_get_vf_stats(dev, vfs_num,
+                                               &vf_stats);
+       vfstats = nla_nest_start(skb, IFLA_VF_STATS);
+       if (!vfstats) {
+               nla_nest_cancel(skb, vf);
+               nla_nest_cancel(skb, vfinfo);
+               return -EMSGSIZE;
+       }
+       if (nla_put_u64(skb, IFLA_VF_STATS_RX_PACKETS,
+                       vf_stats.rx_packets) ||
+           nla_put_u64(skb, IFLA_VF_STATS_TX_PACKETS,
+                       vf_stats.tx_packets) ||
+           nla_put_u64(skb, IFLA_VF_STATS_RX_BYTES,
+                       vf_stats.rx_bytes) ||
+           nla_put_u64(skb, IFLA_VF_STATS_TX_BYTES,
+                       vf_stats.tx_bytes) ||
+           nla_put_u64(skb, IFLA_VF_STATS_BROADCAST,
+                       vf_stats.broadcast) ||
+           nla_put_u64(skb, IFLA_VF_STATS_MULTICAST,
+                       vf_stats.multicast))
+               return -EMSGSIZE;
+       nla_nest_end(skb, vfstats);
+       nla_nest_end(skb, vf);
+       return 0;
+}
+
+static int rtnl_fill_link_ifmap(struct sk_buff *skb, struct net_device *dev)
+{
+       struct rtnl_link_ifmap map = {
+               .mem_start   = dev->mem_start,
+               .mem_end     = dev->mem_end,
+               .base_addr   = dev->base_addr,
+               .irq         = dev->irq,
+               .dma         = dev->dma,
+               .port        = dev->if_port,
+       };
+       if (nla_put(skb, IFLA_MAP, sizeof(map), &map))
+               return -EMSGSIZE;
+
+       return 0;
+}
+
 static int rtnl_fill_ifinfo(struct sk_buff *skb, struct net_device *dev,
                            int type, u32 pid, u32 seq, u32 change,
                            unsigned int flags, u32 ext_filter_mask)
 {
        struct ifinfomsg *ifm;
        struct nlmsghdr *nlh;
-       struct rtnl_link_stats64 temp;
-       const struct rtnl_link_stats64 *stats;
-       struct nlattr *attr, *af_spec;
+       struct nlattr *af_spec;
        struct rtnl_af_ops *af_ops;
        struct net_device *upper_dev = netdev_master_upper_dev_get(dev);
 
@@ -1096,18 +1237,8 @@ static int rtnl_fill_ifinfo(struct sk_buff *skb, struct net_device *dev,
            nla_put_u8(skb, IFLA_PROTO_DOWN, dev->proto_down))
                goto nla_put_failure;
 
-       if (1) {
-               struct rtnl_link_ifmap map = {
-                       .mem_start   = dev->mem_start,
-                       .mem_end     = dev->mem_end,
-                       .base_addr   = dev->base_addr,
-                       .irq         = dev->irq,
-                       .dma         = dev->dma,
-                       .port        = dev->if_port,
-               };
-               if (nla_put(skb, IFLA_MAP, sizeof(map), &map))
-                       goto nla_put_failure;
-       }
+       if (rtnl_fill_link_ifmap(skb, dev))
+               goto nla_put_failure;
 
        if (dev->addr_len) {
                if (nla_put(skb, IFLA_ADDRESS, dev->addr_len, dev->dev_addr) ||
@@ -1124,128 +1255,27 @@ static int rtnl_fill_ifinfo(struct sk_buff *skb, struct net_device *dev,
        if (rtnl_phys_switch_id_fill(skb, dev))
                goto nla_put_failure;
 
-       attr = nla_reserve(skb, IFLA_STATS,
-                       sizeof(struct rtnl_link_stats));
-       if (attr == NULL)
-               goto nla_put_failure;
-
-       stats = dev_get_stats(dev, &temp);
-       copy_rtnl_link_stats(nla_data(attr), stats);
-
-       attr = nla_reserve(skb, IFLA_STATS64,
-                       sizeof(struct rtnl_link_stats64));
-       if (attr == NULL)
+       if (rtnl_fill_stats(skb, dev))
                goto nla_put_failure;
-       copy_rtnl_link_stats64(nla_data(attr), stats);
 
        if (dev->dev.parent && (ext_filter_mask & RTEXT_FILTER_VF) &&
            nla_put_u32(skb, IFLA_NUM_VF, dev_num_vf(dev->dev.parent)))
                goto nla_put_failure;
 
-       if (dev->netdev_ops->ndo_get_vf_config && dev->dev.parent
-           && (ext_filter_mask & RTEXT_FILTER_VF)) {
+       if (dev->netdev_ops->ndo_get_vf_config && dev->dev.parent &&
+           ext_filter_mask & RTEXT_FILTER_VF) {
                int i;
-
-               struct nlattr *vfinfo, *vf, *vfstats;
+               struct nlattr *vfinfo;
                int num_vfs = dev_num_vf(dev->dev.parent);
 
                vfinfo = nla_nest_start(skb, IFLA_VFINFO_LIST);
                if (!vfinfo)
                        goto nla_put_failure;
                for (i = 0; i < num_vfs; i++) {
-                       struct ifla_vf_info ivi;
-                       struct ifla_vf_mac vf_mac;
-                       struct ifla_vf_vlan vf_vlan;
-                       struct ifla_vf_rate vf_rate;
-                       struct ifla_vf_tx_rate vf_tx_rate;
-                       struct ifla_vf_spoofchk vf_spoofchk;
-                       struct ifla_vf_link_state vf_linkstate;
-                       struct ifla_vf_rss_query_en vf_rss_query_en;
-                       struct ifla_vf_stats vf_stats;
-                       struct ifla_vf_trust vf_trust;
-
-                       /*
-                        * Not all SR-IOV capable drivers support the
-                        * spoofcheck and "RSS query enable" query.  Preset to
-                        * -1 so the user space tool can detect that the driver
-                        * didn't report anything.
-                        */
-                       ivi.spoofchk = -1;
-                       ivi.rss_query_en = -1;
-                       ivi.trusted = -1;
-                       memset(ivi.mac, 0, sizeof(ivi.mac));
-                       /* The default value for VF link state is "auto"
-                        * IFLA_VF_LINK_STATE_AUTO which equals zero
-                        */
-                       ivi.linkstate = 0;
-                       if (dev->netdev_ops->ndo_get_vf_config(dev, i, &ivi))
-                               break;
-                       vf_mac.vf =
-                               vf_vlan.vf =
-                               vf_rate.vf =
-                               vf_tx_rate.vf =
-                               vf_spoofchk.vf =
-                               vf_linkstate.vf =
-                               vf_rss_query_en.vf =
-                               vf_trust.vf = ivi.vf;
-
-                       memcpy(vf_mac.mac, ivi.mac, sizeof(ivi.mac));
-                       vf_vlan.vlan = ivi.vlan;
-                       vf_vlan.qos = ivi.qos;
-                       vf_tx_rate.rate = ivi.max_tx_rate;
-                       vf_rate.min_tx_rate = ivi.min_tx_rate;
-                       vf_rate.max_tx_rate = ivi.max_tx_rate;
-                       vf_spoofchk.setting = ivi.spoofchk;
-                       vf_linkstate.link_state = ivi.linkstate;
-                       vf_rss_query_en.setting = ivi.rss_query_en;
-                       vf_trust.setting = ivi.trusted;
-                       vf = nla_nest_start(skb, IFLA_VF_INFO);
-                       if (!vf) {
-                               nla_nest_cancel(skb, vfinfo);
-                               goto nla_put_failure;
-                       }
-                       if (nla_put(skb, IFLA_VF_MAC, sizeof(vf_mac), &vf_mac) ||
-                           nla_put(skb, IFLA_VF_VLAN, sizeof(vf_vlan), &vf_vlan) ||
-                           nla_put(skb, IFLA_VF_RATE, sizeof(vf_rate),
-                                   &vf_rate) ||
-                           nla_put(skb, IFLA_VF_TX_RATE, sizeof(vf_tx_rate),
-                                   &vf_tx_rate) ||
-                           nla_put(skb, IFLA_VF_SPOOFCHK, sizeof(vf_spoofchk),
-                                   &vf_spoofchk) ||
-                           nla_put(skb, IFLA_VF_LINK_STATE, sizeof(vf_linkstate),
-                                   &vf_linkstate) ||
-                           nla_put(skb, IFLA_VF_RSS_QUERY_EN,
-                                   sizeof(vf_rss_query_en),
-                                   &vf_rss_query_en) ||
-                           nla_put(skb, IFLA_VF_TRUST,
-                                   sizeof(vf_trust), &vf_trust))
+                       if (rtnl_fill_vfinfo(skb, dev, i, vfinfo))
                                goto nla_put_failure;
-                       memset(&vf_stats, 0, sizeof(vf_stats));
-                       if (dev->netdev_ops->ndo_get_vf_stats)
-                               dev->netdev_ops->ndo_get_vf_stats(dev, i,
-                                                                 &vf_stats);
-                       vfstats = nla_nest_start(skb, IFLA_VF_STATS);
-                       if (!vfstats) {
-                               nla_nest_cancel(skb, vf);
-                               nla_nest_cancel(skb, vfinfo);
-                               goto nla_put_failure;
-                       }
-                       if (nla_put_u64(skb, IFLA_VF_STATS_RX_PACKETS,
-                                       vf_stats.rx_packets) ||
-                           nla_put_u64(skb, IFLA_VF_STATS_TX_PACKETS,
-                                       vf_stats.tx_packets) ||
-                           nla_put_u64(skb, IFLA_VF_STATS_RX_BYTES,
-                                       vf_stats.rx_bytes) ||
-                           nla_put_u64(skb, IFLA_VF_STATS_TX_BYTES,
-                                       vf_stats.tx_bytes) ||
-                           nla_put_u64(skb, IFLA_VF_STATS_BROADCAST,
-                                       vf_stats.broadcast) ||
-                           nla_put_u64(skb, IFLA_VF_STATS_MULTICAST,
-                                       vf_stats.multicast))
-                               goto nla_put_failure;
-                       nla_nest_end(skb, vfstats);
-                       nla_nest_end(skb, vf);
                }
+
                nla_nest_end(skb, vfinfo);
        }
 
index 3b6899b7d810d569057b051162b51fde7c51cba8..8a1741b14302bd0cecdc265848feba8222400d17 100644 (file)
@@ -305,6 +305,8 @@ void scm_detach_fds(struct msghdr *msg, struct scm_cookie *scm)
                        err = put_user(cmlen, &cm->cmsg_len);
                if (!err) {
                        cmlen = CMSG_SPACE(i*sizeof(int));
+                       if (msg->msg_controllen < cmlen)
+                               cmlen = msg->msg_controllen;
                        msg->msg_control += cmlen;
                        msg->msg_controllen -= cmlen;
                }
index aa41e6dd642913f2181832145e22ec1dad6fa7b8..b2df375ec9c2173a8132b8efa1c3062f0510284b 100644 (file)
@@ -3643,7 +3643,8 @@ static void __skb_complete_tx_timestamp(struct sk_buff *skb,
        serr->ee.ee_info = tstype;
        if (sk->sk_tsflags & SOF_TIMESTAMPING_OPT_ID) {
                serr->ee.ee_data = skb_shinfo(skb)->tskey;
-               if (sk->sk_protocol == IPPROTO_TCP)
+               if (sk->sk_protocol == IPPROTO_TCP &&
+                   sk->sk_type == SOCK_STREAM)
                        serr->ee.ee_data -= sk->sk_tskey;
        }
 
@@ -4268,7 +4269,8 @@ static struct sk_buff *skb_reorder_vlan_header(struct sk_buff *skb)
                return NULL;
        }
 
-       memmove(skb->data - ETH_HLEN, skb->data - VLAN_ETH_HLEN, 2 * ETH_ALEN);
+       memmove(skb->data - ETH_HLEN, skb->data - skb->mac_len - VLAN_HLEN,
+               2 * ETH_ALEN);
        skb->mac_header += VLAN_HLEN;
        return skb;
 }
index 1e4dd54bfb5a525ef6070905f07472f60e9f137f..0d91f7dca751efc3e32348ba217c29e8ed55e80b 100644 (file)
@@ -433,8 +433,6 @@ static bool sock_needs_netstamp(const struct sock *sk)
        }
 }
 
-#define SK_FLAGS_TIMESTAMP ((1UL << SOCK_TIMESTAMP) | (1UL << SOCK_TIMESTAMPING_RX_SOFTWARE))
-
 static void sock_disable_timestamp(struct sock *sk, unsigned long flags)
 {
        if (sk->sk_flags & flags) {
@@ -874,7 +872,8 @@ set_rcvbuf:
 
                if (val & SOF_TIMESTAMPING_OPT_ID &&
                    !(sk->sk_tsflags & SOF_TIMESTAMPING_OPT_ID)) {
-                       if (sk->sk_protocol == IPPROTO_TCP) {
+                       if (sk->sk_protocol == IPPROTO_TCP &&
+                           sk->sk_type == SOCK_STREAM) {
                                if (sk->sk_state != TCP_ESTABLISHED) {
                                        ret = -EINVAL;
                                        break;
@@ -1530,7 +1529,6 @@ struct sock *sk_clone_lock(const struct sock *sk, const gfp_t priority)
                skb_queue_head_init(&newsk->sk_receive_queue);
                skb_queue_head_init(&newsk->sk_write_queue);
 
-               spin_lock_init(&newsk->sk_dst_lock);
                rwlock_init(&newsk->sk_callback_lock);
                lockdep_set_class_and_name(&newsk->sk_callback_lock,
                                af_callback_keys + newsk->sk_family,
@@ -1553,7 +1551,7 @@ struct sock *sk_clone_lock(const struct sock *sk, const gfp_t priority)
                         */
                        is_charged = sk_filter_charge(newsk, filter);
 
-               if (unlikely(!is_charged || xfrm_sk_clone_policy(newsk))) {
+               if (unlikely(!is_charged || xfrm_sk_clone_policy(newsk, sk))) {
                        /* It is still raw copy of parent, so invalidate
                         * destructor and make plain sk_free() */
                        newsk->sk_destruct = NULL;
@@ -1607,7 +1605,7 @@ void sk_setup_caps(struct sock *sk, struct dst_entry *dst)
 {
        u32 max_segs = 1;
 
-       __sk_dst_set(sk, dst);
+       sk_dst_set(sk, dst);
        sk->sk_route_caps = dst->dev->features;
        if (sk->sk_route_caps & NETIF_F_GSO)
                sk->sk_route_caps |= NETIF_F_GSO_SOFTWARE;
@@ -1815,7 +1813,7 @@ static long sock_wait_for_wmem(struct sock *sk, long timeo)
 {
        DEFINE_WAIT(wait);
 
-       clear_bit(SOCK_ASYNC_NOSPACE, &sk->sk_socket->flags);
+       sk_clear_bit(SOCKWQ_ASYNC_NOSPACE, sk);
        for (;;) {
                if (!timeo)
                        break;
@@ -1861,7 +1859,7 @@ struct sk_buff *sock_alloc_send_pskb(struct sock *sk, unsigned long header_len,
                if (sk_wmem_alloc_get(sk) < sk->sk_sndbuf)
                        break;
 
-               set_bit(SOCK_ASYNC_NOSPACE, &sk->sk_socket->flags);
+               sk_set_bit(SOCKWQ_ASYNC_NOSPACE, sk);
                set_bit(SOCK_NOSPACE, &sk->sk_socket->flags);
                err = -EAGAIN;
                if (!timeo)
@@ -2048,9 +2046,9 @@ int sk_wait_data(struct sock *sk, long *timeo, const struct sk_buff *skb)
        DEFINE_WAIT(wait);
 
        prepare_to_wait(sk_sleep(sk), &wait, TASK_INTERRUPTIBLE);
-       set_bit(SOCK_ASYNC_WAITDATA, &sk->sk_socket->flags);
+       sk_set_bit(SOCKWQ_ASYNC_WAITDATA, sk);
        rc = sk_wait_event(sk, timeo, skb_peek_tail(&sk->sk_receive_queue) != skb);
-       clear_bit(SOCK_ASYNC_WAITDATA, &sk->sk_socket->flags);
+       sk_clear_bit(SOCKWQ_ASYNC_WAITDATA, sk);
        finish_wait(sk_sleep(sk), &wait);
        return rc;
 }
@@ -2388,7 +2386,6 @@ void sock_init_data(struct socket *sock, struct sock *sk)
        } else
                sk->sk_wq       =       NULL;
 
-       spin_lock_init(&sk->sk_dst_lock);
        rwlock_init(&sk->sk_callback_lock);
        lockdep_set_class_and_name(&sk->sk_callback_lock,
                        af_callback_keys + sk->sk_family,
index d70f77a0c8898582e0adabd24c6165675d12dce7..b96f7a79e54458bfa1d0d1a51f77be08a45e8207 100644 (file)
@@ -39,7 +39,7 @@ void sk_stream_write_space(struct sock *sk)
                        wake_up_interruptible_poll(&wq->wait, POLLOUT |
                                                POLLWRNORM | POLLWRBAND);
                if (wq && wq->fasync_list && !(sk->sk_shutdown & SEND_SHUTDOWN))
-                       sock_wake_async(sock, SOCK_WAKE_SPACE, POLL_OUT);
+                       sock_wake_async(wq, SOCK_WAKE_SPACE, POLL_OUT);
                rcu_read_unlock();
        }
 }
@@ -126,7 +126,7 @@ int sk_stream_wait_memory(struct sock *sk, long *timeo_p)
                current_timeo = vm_wait = (prandom_u32() % (HZ / 5)) + 2;
 
        while (1) {
-               set_bit(SOCK_ASYNC_NOSPACE, &sk->sk_socket->flags);
+               sk_set_bit(SOCKWQ_ASYNC_NOSPACE, sk);
 
                prepare_to_wait(sk_sleep(sk), &wait, TASK_INTERRUPTIBLE);
 
@@ -139,7 +139,7 @@ int sk_stream_wait_memory(struct sock *sk, long *timeo_p)
                }
                if (signal_pending(current))
                        goto do_interrupted;
-               clear_bit(SOCK_ASYNC_NOSPACE, &sk->sk_socket->flags);
+               sk_clear_bit(SOCKWQ_ASYNC_NOSPACE, sk);
                if (sk_stream_memory_free(sk) && !vm_wait)
                        break;
 
index db5fc2440a232c856bccfd8e0222a24bcf3d6d11..9c6d0508e63a2ab7f13105cd91ea8c027c4a7557 100644 (file)
@@ -202,7 +202,9 @@ static int dccp_v6_send_response(const struct sock *sk, struct request_sock *req
        security_req_classify_flow(req, flowi6_to_flowi(&fl6));
 
 
-       final_p = fl6_update_dst(&fl6, np->opt, &final);
+       rcu_read_lock();
+       final_p = fl6_update_dst(&fl6, rcu_dereference(np->opt), &final);
+       rcu_read_unlock();
 
        dst = ip6_dst_lookup_flow(sk, &fl6, final_p);
        if (IS_ERR(dst)) {
@@ -219,7 +221,10 @@ static int dccp_v6_send_response(const struct sock *sk, struct request_sock *req
                                                         &ireq->ir_v6_loc_addr,
                                                         &ireq->ir_v6_rmt_addr);
                fl6.daddr = ireq->ir_v6_rmt_addr;
-               err = ip6_xmit(sk, skb, &fl6, np->opt, np->tclass);
+               rcu_read_lock();
+               err = ip6_xmit(sk, skb, &fl6, rcu_dereference(np->opt),
+                              np->tclass);
+               rcu_read_unlock();
                err = net_xmit_eval(err);
        }
 
@@ -387,6 +392,7 @@ static struct sock *dccp_v6_request_recv_sock(const struct sock *sk,
        struct inet_request_sock *ireq = inet_rsk(req);
        struct ipv6_pinfo *newnp;
        const struct ipv6_pinfo *np = inet6_sk(sk);
+       struct ipv6_txoptions *opt;
        struct inet_sock *newinet;
        struct dccp6_sock *newdp6;
        struct sock *newsk;
@@ -453,7 +459,7 @@ static struct sock *dccp_v6_request_recv_sock(const struct sock *sk,
         * comment in that function for the gory details. -acme
         */
 
-       __ip6_dst_store(newsk, dst, NULL, NULL);
+       ip6_dst_store(newsk, dst, NULL, NULL);
        newsk->sk_route_caps = dst->dev->features & ~(NETIF_F_IP_CSUM |
                                                      NETIF_F_TSO);
        newdp6 = (struct dccp6_sock *)newsk;
@@ -488,13 +494,15 @@ static struct sock *dccp_v6_request_recv_sock(const struct sock *sk,
         * Yes, keeping reference count would be much more clever, but we make
         * one more one thing there: reattach optmem to newsk.
         */
-       if (np->opt != NULL)
-               newnp->opt = ipv6_dup_options(newsk, np->opt);
-
+       opt = rcu_dereference(np->opt);
+       if (opt) {
+               opt = ipv6_dup_options(newsk, opt);
+               RCU_INIT_POINTER(newnp->opt, opt);
+       }
        inet_csk(newsk)->icsk_ext_hdr_len = 0;
-       if (newnp->opt != NULL)
-               inet_csk(newsk)->icsk_ext_hdr_len = (newnp->opt->opt_nflen +
-                                                    newnp->opt->opt_flen);
+       if (opt)
+               inet_csk(newsk)->icsk_ext_hdr_len = opt->opt_nflen +
+                                                   opt->opt_flen;
 
        dccp_sync_mss(newsk, dst_mtu(dst));
 
@@ -757,6 +765,7 @@ static int dccp_v6_connect(struct sock *sk, struct sockaddr *uaddr,
        struct ipv6_pinfo *np = inet6_sk(sk);
        struct dccp_sock *dp = dccp_sk(sk);
        struct in6_addr *saddr = NULL, *final_p, final;
+       struct ipv6_txoptions *opt;
        struct flowi6 fl6;
        struct dst_entry *dst;
        int addr_type;
@@ -856,7 +865,8 @@ static int dccp_v6_connect(struct sock *sk, struct sockaddr *uaddr,
        fl6.fl6_sport = inet->inet_sport;
        security_sk_classify_flow(sk, flowi6_to_flowi(&fl6));
 
-       final_p = fl6_update_dst(&fl6, np->opt, &final);
+       opt = rcu_dereference_protected(np->opt, sock_owned_by_user(sk));
+       final_p = fl6_update_dst(&fl6, opt, &final);
 
        dst = ip6_dst_lookup_flow(sk, &fl6, final_p);
        if (IS_ERR(dst)) {
@@ -873,12 +883,11 @@ static int dccp_v6_connect(struct sock *sk, struct sockaddr *uaddr,
        np->saddr = *saddr;
        inet->inet_rcv_saddr = LOOPBACK4_IPV6;
 
-       __ip6_dst_store(sk, dst, NULL, NULL);
+       ip6_dst_store(sk, dst, NULL, NULL);
 
        icsk->icsk_ext_hdr_len = 0;
-       if (np->opt != NULL)
-               icsk->icsk_ext_hdr_len = (np->opt->opt_flen +
-                                         np->opt->opt_nflen);
+       if (opt)
+               icsk->icsk_ext_hdr_len = opt->opt_flen + opt->opt_nflen;
 
        inet->inet_dport = usin->sin6_port;
 
index b5cf13a2800923486ad597c296a66145bc248596..41e65804ddf59651c78ae58b697e7e5e603c9167 100644 (file)
@@ -339,8 +339,7 @@ unsigned int dccp_poll(struct file *file, struct socket *sock,
                        if (sk_stream_is_writeable(sk)) {
                                mask |= POLLOUT | POLLWRNORM;
                        } else {  /* send SIGIO later */
-                               set_bit(SOCK_ASYNC_NOSPACE,
-                                       &sk->sk_socket->flags);
+                               sk_set_bit(SOCKWQ_ASYNC_NOSPACE, sk);
                                set_bit(SOCK_NOSPACE, &sk->sk_socket->flags);
 
                                /* Race breaker. If space is freed after
index 675cf94e04f862b77644f86628af6e8a46933055..13d6b1a6e0fc2b0730827d93d154d6464a3e58ec 100644 (file)
@@ -678,6 +678,9 @@ static int dn_create(struct net *net, struct socket *sock, int protocol,
 {
        struct sock *sk;
 
+       if (protocol < 0 || protocol > SK_PROTOCOL_MAX)
+               return -EINVAL;
+
        if (!net_eq(net, &init_net))
                return -EAFNOSUPPORT;
 
@@ -1747,9 +1750,9 @@ static int dn_recvmsg(struct socket *sock, struct msghdr *msg, size_t size,
                }
 
                prepare_to_wait(sk_sleep(sk), &wait, TASK_INTERRUPTIBLE);
-               set_bit(SOCK_ASYNC_WAITDATA, &sk->sk_socket->flags);
+               sk_set_bit(SOCKWQ_ASYNC_WAITDATA, sk);
                sk_wait_event(sk, &timeo, dn_data_ready(sk, queue, flags, target));
-               clear_bit(SOCK_ASYNC_WAITDATA, &sk->sk_socket->flags);
+               sk_clear_bit(SOCKWQ_ASYNC_WAITDATA, sk);
                finish_wait(sk_sleep(sk), &wait);
        }
 
@@ -2004,10 +2007,10 @@ static int dn_sendmsg(struct socket *sock, struct msghdr *msg, size_t size)
                        }
 
                        prepare_to_wait(sk_sleep(sk), &wait, TASK_INTERRUPTIBLE);
-                       set_bit(SOCK_ASYNC_WAITDATA, &sk->sk_socket->flags);
+                       sk_set_bit(SOCKWQ_ASYNC_WAITDATA, sk);
                        sk_wait_event(sk, &timeo,
                                      !dn_queue_too_long(scp, queue, flags));
-                       clear_bit(SOCK_ASYNC_WAITDATA, &sk->sk_socket->flags);
+                       sk_clear_bit(SOCKWQ_ASYNC_WAITDATA, sk);
                        finish_wait(sk_sleep(sk), &wait);
                        continue;
                }
index 4677b6fa6dda2c71ace9d97536a450684d18d3ef..ecc28cff08ab8110a9d96d6f7abe690ca77e9962 100644 (file)
@@ -67,7 +67,7 @@
  * Returns the size of the result on success, -ve error code otherwise.
  */
 int dns_query(const char *type, const char *name, size_t namelen,
-             const char *options, char **_result, time_t *_expiry)
+             const char *options, char **_result, time64_t *_expiry)
 {
        struct key *rkey;
        const struct user_key_payload *upayload;
index 35a9788bb3ae734d8e5b2f5199901a6c47f7a587..c7d1adca30d891b183b0832712e0d57aa1f33201 100644 (file)
@@ -312,7 +312,7 @@ static void send_hsr_supervision_frame(struct hsr_port *master, u8 type)
        return;
 
 out:
-       WARN_ON_ONCE("HSR: Could not send supervision frame\n");
+       WARN_ONCE(1, "HSR: Could not send supervision frame\n");
        kfree_skb(skb);
 }
 
index 11c4ca13ec3b0434090b3d5cbdd7a0aae784952f..5c5db6636704daa0c49fc13e84b2c5b282a44ed3 100644 (file)
@@ -257,6 +257,9 @@ static int inet_create(struct net *net, struct socket *sock, int protocol,
        int try_loading_module = 0;
        int err;
 
+       if (protocol < 0 || protocol >= IPPROTO_MAX)
+               return -EINVAL;
+
        sock->state = SS_UNCONNECTED;
 
        /* Look for the requested type/protocol pair. */
index cc8f3e506cded3fbcc9a64bbd369577c5f7cb52d..47344759306011b5bb940e9cab9237b9e9f624b4 100644 (file)
@@ -1155,6 +1155,7 @@ static int fib_inetaddr_event(struct notifier_block *this, unsigned long event,
 static int fib_netdev_event(struct notifier_block *this, unsigned long event, void *ptr)
 {
        struct net_device *dev = netdev_notifier_info_to_dev(ptr);
+       struct netdev_notifier_changeupper_info *info;
        struct in_device *in_dev;
        struct net *net = dev_net(dev);
        unsigned int flags;
@@ -1193,6 +1194,14 @@ static int fib_netdev_event(struct notifier_block *this, unsigned long event, vo
        case NETDEV_CHANGEMTU:
                rt_cache_flush(net);
                break;
+       case NETDEV_CHANGEUPPER:
+               info = ptr;
+               /* flush all routes if dev is linked to or unlinked from
+                * an L3 master device (e.g., VRF)
+                */
+               if (info->upper_dev && netif_is_l3_master(info->upper_dev))
+                       fib_disable_ip(dev, NETDEV_DOWN, true);
+               break;
        }
        return NOTIFY_DONE;
 }
index e0fcbbbcfe54d0b35b46597b5f217075ffbc745c..bd903fe0f7508d9d7a94c4ce1e0a825f3e35c398 100644 (file)
@@ -24,6 +24,7 @@ struct fou {
        u16 type;
        struct udp_offload udp_offloads;
        struct list_head list;
+       struct rcu_head rcu;
 };
 
 #define FOU_F_REMCSUM_NOPARTIAL BIT(0)
@@ -417,7 +418,7 @@ static void fou_release(struct fou *fou)
        list_del(&fou->list);
        udp_tunnel_sock_release(sock);
 
-       kfree(fou);
+       kfree_rcu(fou, rcu);
 }
 
 static int fou_encap_init(struct sock *sk, struct fou *fou, struct fou_cfg *cfg)
index 6baf36e11808e5c93c2e092139bed60cdacc4c8a..05e4cba14162f3583ec588657af7e8b68546b111 100644 (file)
@@ -2126,7 +2126,7 @@ int ip_mc_leave_group(struct sock *sk, struct ip_mreqn *imr)
        ASSERT_RTNL();
 
        in_dev = ip_mc_find_dev(net, imr);
-       if (!in_dev) {
+       if (!imr->imr_ifindex && !imr->imr_address.s_addr && !in_dev) {
                ret = -ENODEV;
                goto out;
        }
@@ -2147,7 +2147,8 @@ int ip_mc_leave_group(struct sock *sk, struct ip_mreqn *imr)
 
                *imlp = iml->next_rcu;
 
-               ip_mc_dec_group(in_dev, group);
+               if (in_dev)
+                       ip_mc_dec_group(in_dev, group);
 
                /* decrease mem now to avoid the memleak warning */
                atomic_sub(sizeof(*iml), &sk->sk_omem_alloc);
index 1feb15f23de8c4f673fd0fe713df2dd9195995cf..46b9c887bede0568ec378d3b809dda8fa463a166 100644 (file)
@@ -563,7 +563,7 @@ static void reqsk_timer_handler(unsigned long data)
        int max_retries, thresh;
        u8 defer_accept;
 
-       if (sk_listener->sk_state != TCP_LISTEN)
+       if (sk_state_load(sk_listener) != TCP_LISTEN)
                goto drop;
 
        max_retries = icsk->icsk_syn_retries ? : sysctl_tcp_synack_retries;
@@ -749,7 +749,7 @@ int inet_csk_listen_start(struct sock *sk, int backlog)
         * It is OK, because this socket enters to hash table only
         * after validation is complete.
         */
-       sk->sk_state = TCP_LISTEN;
+       sk_state_store(sk, TCP_LISTEN);
        if (!sk->sk_prot->get_port(sk, inet->inet_num)) {
                inet->inet_sport = htons(inet->inet_num);
 
index f34c31defafe083fcc9146affff5c39745150d04..a09fb0dec725a8827ba5d1e928597c103d1f9322 100644 (file)
@@ -253,9 +253,6 @@ ipip_tunnel_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
 
        p.i_key = p.o_key = 0;
        p.i_flags = p.o_flags = 0;
-       if (p.iph.ttl)
-               p.iph.frag_off |= htons(IP_DF);
-
        err = ip_tunnel_ioctl(dev, &p, cmd);
        if (err)
                return err;
index 92dd4b74d513ab40ba4f6f3f2f5ce7a73085f379..c3a38353f5dc8094de5c1dcec06ae54ab0b29a9e 100644 (file)
@@ -134,7 +134,7 @@ static int __ipmr_fill_mroute(struct mr_table *mrt, struct sk_buff *skb,
                              struct mfc_cache *c, struct rtmsg *rtm);
 static void mroute_netlink_event(struct mr_table *mrt, struct mfc_cache *mfc,
                                 int cmd);
-static void mroute_clean_tables(struct mr_table *mrt);
+static void mroute_clean_tables(struct mr_table *mrt, bool all);
 static void ipmr_expire_process(unsigned long arg);
 
 #ifdef CONFIG_IP_MROUTE_MULTIPLE_TABLES
@@ -350,7 +350,7 @@ static struct mr_table *ipmr_new_table(struct net *net, u32 id)
 static void ipmr_free_table(struct mr_table *mrt)
 {
        del_timer_sync(&mrt->ipmr_expire_timer);
-       mroute_clean_tables(mrt);
+       mroute_clean_tables(mrt, true);
        kfree(mrt);
 }
 
@@ -441,10 +441,6 @@ struct net_device *ipmr_new_tunnel(struct net *net, struct vifctl *v)
        return dev;
 
 failure:
-       /* allow the register to be completed before unregistering. */
-       rtnl_unlock();
-       rtnl_lock();
-
        unregister_netdevice(dev);
        return NULL;
 }
@@ -540,10 +536,6 @@ static struct net_device *ipmr_reg_vif(struct net *net, struct mr_table *mrt)
        return dev;
 
 failure:
-       /* allow the register to be completed before unregistering. */
-       rtnl_unlock();
-       rtnl_lock();
-
        unregister_netdevice(dev);
        return NULL;
 }
@@ -1208,7 +1200,7 @@ static int ipmr_mfc_add(struct net *net, struct mr_table *mrt,
  *     Close the multicast socket, and clear the vif tables etc
  */
 
-static void mroute_clean_tables(struct mr_table *mrt)
+static void mroute_clean_tables(struct mr_table *mrt, bool all)
 {
        int i;
        LIST_HEAD(list);
@@ -1217,8 +1209,9 @@ static void mroute_clean_tables(struct mr_table *mrt)
        /* Shut down all active vif entries */
 
        for (i = 0; i < mrt->maxvif; i++) {
-               if (!(mrt->vif_table[i].flags & VIFF_STATIC))
-                       vif_delete(mrt, i, 0, &list);
+               if (!all && (mrt->vif_table[i].flags & VIFF_STATIC))
+                       continue;
+               vif_delete(mrt, i, 0, &list);
        }
        unregister_netdevice_many(&list);
 
@@ -1226,7 +1219,7 @@ static void mroute_clean_tables(struct mr_table *mrt)
 
        for (i = 0; i < MFC_LINES; i++) {
                list_for_each_entry_safe(c, next, &mrt->mfc_cache_array[i], list) {
-                       if (c->mfc_flags & MFC_STATIC)
+                       if (!all && (c->mfc_flags & MFC_STATIC))
                                continue;
                        list_del_rcu(&c->list);
                        mroute_netlink_event(mrt, c, RTM_DELROUTE);
@@ -1261,7 +1254,7 @@ static void mrtsock_destruct(struct sock *sk)
                                                    NETCONFA_IFINDEX_ALL,
                                                    net->ipv4.devconf_all);
                        RCU_INIT_POINTER(mrt->mroute_sk, NULL);
-                       mroute_clean_tables(mrt);
+                       mroute_clean_tables(mrt, false);
                }
        }
        rtnl_unlock();
index a3558417653567ffe3a83d06515fb1b68ec36dcf..c187c60e3e0c75e0f9c298eaa831c2f19d9a73fc 100644 (file)
@@ -60,6 +60,7 @@ config NFT_REJECT_IPV4
 
 config NFT_DUP_IPV4
        tristate "IPv4 nf_tables packet duplication support"
+       depends on !NF_CONNTRACK || NF_CONNTRACK
        select NF_DUP_IPV4
        help
          This module enables IPv4 packet duplication support for nf_tables.
index 657d2307f031e7fb2a2e38f763cf528329931614..b3ca21b2ba9b638550b552c85e297234ccf39caa 100644 (file)
@@ -45,7 +45,7 @@ static void pptp_nat_expected(struct nf_conn *ct,
        struct net *net = nf_ct_net(ct);
        const struct nf_conn *master = ct->master;
        struct nf_conntrack_expect *other_exp;
-       struct nf_conntrack_tuple t;
+       struct nf_conntrack_tuple t = {};
        const struct nf_ct_pptp_master *ct_pptp_info;
        const struct nf_nat_pptp *nat_pptp_info;
        struct nf_nat_range range;
index 8c0d0bdc2a7c59ad44752f2d378a07d505753a8b..63e5be0abd86ddab6476221161c48aacef34d8c4 100644 (file)
@@ -406,10 +406,12 @@ static int raw_send_hdrinc(struct sock *sk, struct flowi4 *fl4,
                        ip_select_ident(net, skb, NULL);
 
                iph->check = ip_fast_csum((unsigned char *)iph, iph->ihl);
+               skb->transport_header += iphlen;
+               if (iph->protocol == IPPROTO_ICMP &&
+                   length >= iphlen + sizeof(struct icmphdr))
+                       icmp_out_count(net, ((struct icmphdr *)
+                               skb_transport_header(skb))->type);
        }
-       if (iph->protocol == IPPROTO_ICMP)
-               icmp_out_count(net, ((struct icmphdr *)
-                       skb_transport_header(skb))->type);
 
        err = NF_HOOK(NFPROTO_IPV4, NF_INET_LOCAL_OUT,
                      net, sk, skb, NULL, rt->dst.dev,
index 0cfa7c0c1e80dae18b3aa51c3d71d021dd8b4f84..c82cca18c90fbd67c2daf71c6769ee5fef21d2a9 100644 (file)
@@ -451,11 +451,14 @@ unsigned int tcp_poll(struct file *file, struct socket *sock, poll_table *wait)
        unsigned int mask;
        struct sock *sk = sock->sk;
        const struct tcp_sock *tp = tcp_sk(sk);
+       int state;
 
        sock_rps_record_flow(sk);
 
        sock_poll_wait(file, sk_sleep(sk), wait);
-       if (sk->sk_state == TCP_LISTEN)
+
+       state = sk_state_load(sk);
+       if (state == TCP_LISTEN)
                return inet_csk_listen_poll(sk);
 
        /* Socket is not locked. We are protected from async events
@@ -492,14 +495,14 @@ unsigned int tcp_poll(struct file *file, struct socket *sock, poll_table *wait)
         * NOTE. Check for TCP_CLOSE is added. The goal is to prevent
         * blocking on fresh not-connected or disconnected socket. --ANK
         */
-       if (sk->sk_shutdown == SHUTDOWN_MASK || sk->sk_state == TCP_CLOSE)
+       if (sk->sk_shutdown == SHUTDOWN_MASK || state == TCP_CLOSE)
                mask |= POLLHUP;
        if (sk->sk_shutdown & RCV_SHUTDOWN)
                mask |= POLLIN | POLLRDNORM | POLLRDHUP;
 
        /* Connected or passive Fast Open socket? */
-       if (sk->sk_state != TCP_SYN_SENT &&
-           (sk->sk_state != TCP_SYN_RECV || tp->fastopen_rsk)) {
+       if (state != TCP_SYN_SENT &&
+           (state != TCP_SYN_RECV || tp->fastopen_rsk)) {
                int target = sock_rcvlowat(sk, 0, INT_MAX);
 
                if (tp->urg_seq == tp->copied_seq &&
@@ -507,9 +510,6 @@ unsigned int tcp_poll(struct file *file, struct socket *sock, poll_table *wait)
                    tp->urg_data)
                        target++;
 
-               /* Potential race condition. If read of tp below will
-                * escape above sk->sk_state, we can be illegally awaken
-                * in SYN_* states. */
                if (tp->rcv_nxt - tp->copied_seq >= target)
                        mask |= POLLIN | POLLRDNORM;
 
@@ -517,8 +517,7 @@ unsigned int tcp_poll(struct file *file, struct socket *sock, poll_table *wait)
                        if (sk_stream_is_writeable(sk)) {
                                mask |= POLLOUT | POLLWRNORM;
                        } else {  /* send SIGIO later */
-                               set_bit(SOCK_ASYNC_NOSPACE,
-                                       &sk->sk_socket->flags);
+                               sk_set_bit(SOCKWQ_ASYNC_NOSPACE, sk);
                                set_bit(SOCK_NOSPACE, &sk->sk_socket->flags);
 
                                /* Race breaker. If space is freed after
@@ -906,7 +905,7 @@ static ssize_t do_tcp_sendpages(struct sock *sk, struct page *page, int offset,
                        goto out_err;
        }
 
-       clear_bit(SOCK_ASYNC_NOSPACE, &sk->sk_socket->flags);
+       sk_clear_bit(SOCKWQ_ASYNC_NOSPACE, sk);
 
        mss_now = tcp_send_mss(sk, &size_goal, flags);
        copied = 0;
@@ -1134,7 +1133,7 @@ int tcp_sendmsg(struct sock *sk, struct msghdr *msg, size_t size)
        }
 
        /* This should be in poll */
-       clear_bit(SOCK_ASYNC_NOSPACE, &sk->sk_socket->flags);
+       sk_clear_bit(SOCKWQ_ASYNC_NOSPACE, sk);
 
        mss_now = tcp_send_mss(sk, &size_goal, flags);
 
@@ -1934,7 +1933,7 @@ void tcp_set_state(struct sock *sk, int state)
        /* Change state AFTER socket is unhashed to avoid closed
         * socket sitting in hash tables.
         */
-       sk->sk_state = state;
+       sk_state_store(sk, state);
 
 #ifdef STATE_TRACE
        SOCK_DEBUG(sk, "TCP sk=%p, State %s -> %s\n", sk, statename[oldstate], statename[state]);
@@ -2644,7 +2643,8 @@ void tcp_get_info(struct sock *sk, struct tcp_info *info)
        if (sk->sk_type != SOCK_STREAM)
                return;
 
-       info->tcpi_state = sk->sk_state;
+       info->tcpi_state = sk_state_load(sk);
+
        info->tcpi_ca_state = icsk->icsk_ca_state;
        info->tcpi_retransmits = icsk->icsk_retransmits;
        info->tcpi_probes = icsk->icsk_probes_out;
@@ -2672,7 +2672,7 @@ void tcp_get_info(struct sock *sk, struct tcp_info *info)
        info->tcpi_snd_mss = tp->mss_cache;
        info->tcpi_rcv_mss = icsk->icsk_ack.rcv_mss;
 
-       if (sk->sk_state == TCP_LISTEN) {
+       if (info->tcpi_state == TCP_LISTEN) {
                info->tcpi_unacked = sk->sk_ack_backlog;
                info->tcpi_sacked = sk->sk_max_ack_backlog;
        } else {
index 479f34946177eb3f65d9dfa2f3930a0ce2faad65..b31604086edd6b8aec2eaaf67c755b63caf75743 100644 (file)
@@ -21,7 +21,7 @@ static void tcp_diag_get_info(struct sock *sk, struct inet_diag_msg *r,
 {
        struct tcp_info *info = _info;
 
-       if (sk->sk_state == TCP_LISTEN) {
+       if (sk_state_load(sk) == TCP_LISTEN) {
                r->idiag_rqueue = sk->sk_ack_backlog;
                r->idiag_wqueue = sk->sk_max_ack_backlog;
        } else if (sk->sk_type == SOCK_STREAM) {
index fdd88c3803a673881053039cdc8ff44bc1b8aa4a..2d656eef7f8e16458127ba591e0a4154365f6a83 100644 (file)
@@ -4481,19 +4481,34 @@ static int __must_check tcp_queue_rcv(struct sock *sk, struct sk_buff *skb, int
 int tcp_send_rcvq(struct sock *sk, struct msghdr *msg, size_t size)
 {
        struct sk_buff *skb;
+       int err = -ENOMEM;
+       int data_len = 0;
        bool fragstolen;
 
        if (size == 0)
                return 0;
 
-       skb = alloc_skb(size, sk->sk_allocation);
+       if (size > PAGE_SIZE) {
+               int npages = min_t(size_t, size >> PAGE_SHIFT, MAX_SKB_FRAGS);
+
+               data_len = npages << PAGE_SHIFT;
+               size = data_len + (size & ~PAGE_MASK);
+       }
+       skb = alloc_skb_with_frags(size - data_len, data_len,
+                                  PAGE_ALLOC_COSTLY_ORDER,
+                                  &err, sk->sk_allocation);
        if (!skb)
                goto err;
 
+       skb_put(skb, size - data_len);
+       skb->data_len = data_len;
+       skb->len = size;
+
        if (tcp_try_rmem_schedule(sk, skb, skb->truesize))
                goto err_free;
 
-       if (memcpy_from_msg(skb_put(skb, size), msg, size))
+       err = skb_copy_datagram_from_iter(skb, 0, &msg->msg_iter, size);
+       if (err)
                goto err_free;
 
        TCP_SKB_CB(skb)->seq = tcp_sk(sk)->rcv_nxt;
@@ -4509,7 +4524,8 @@ int tcp_send_rcvq(struct sock *sk, struct msghdr *msg, size_t size)
 err_free:
        kfree_skb(skb);
 err:
-       return -ENOMEM;
+       return err;
+
 }
 
 static void tcp_data_queue(struct sock *sk, struct sk_buff *skb)
@@ -5667,6 +5683,7 @@ discard:
                }
 
                tp->rcv_nxt = TCP_SKB_CB(skb)->seq + 1;
+               tp->copied_seq = tp->rcv_nxt;
                tp->rcv_wup = TCP_SKB_CB(skb)->seq + 1;
 
                /* RFC1323: The window in SYN & SYN/ACK segments is
index 950e28c0cdf25e23658926cdcf37335aed3fb193..d8841a2f15691fd80c46fbaa62e2431e9ca16003 100644 (file)
@@ -921,7 +921,8 @@ int tcp_md5_do_add(struct sock *sk, const union tcp_md5_addr *addr,
        }
 
        md5sig = rcu_dereference_protected(tp->md5sig_info,
-                                          sock_owned_by_user(sk));
+                                          sock_owned_by_user(sk) ||
+                                          lockdep_is_held(&sk->sk_lock.slock));
        if (!md5sig) {
                md5sig = kmalloc(sizeof(*md5sig), gfp);
                if (!md5sig)
@@ -1492,7 +1493,7 @@ bool tcp_prequeue(struct sock *sk, struct sk_buff *skb)
        if (likely(sk->sk_rx_dst))
                skb_dst_drop(skb);
        else
-               skb_dst_force(skb);
+               skb_dst_force_safe(skb);
 
        __skb_queue_tail(&tp->ucopy.prequeue, skb);
        tp->ucopy.memory += skb->truesize;
@@ -1720,8 +1721,7 @@ void inet_sk_rx_dst_set(struct sock *sk, const struct sk_buff *skb)
 {
        struct dst_entry *dst = skb_dst(skb);
 
-       if (dst) {
-               dst_hold(dst);
+       if (dst && dst_hold_safe(dst)) {
                sk->sk_rx_dst = dst;
                inet_sk(sk)->rx_dst_ifindex = skb->skb_iif;
        }
@@ -2158,6 +2158,7 @@ static void get_tcp4_sock(struct sock *sk, struct seq_file *f, int i)
        __u16 destp = ntohs(inet->inet_dport);
        __u16 srcp = ntohs(inet->inet_sport);
        int rx_queue;
+       int state;
 
        if (icsk->icsk_pending == ICSK_TIME_RETRANS ||
            icsk->icsk_pending == ICSK_TIME_EARLY_RETRANS ||
@@ -2175,17 +2176,18 @@ static void get_tcp4_sock(struct sock *sk, struct seq_file *f, int i)
                timer_expires = jiffies;
        }
 
-       if (sk->sk_state == TCP_LISTEN)
+       state = sk_state_load(sk);
+       if (state == TCP_LISTEN)
                rx_queue = sk->sk_ack_backlog;
        else
-               /*
-                * because we dont lock socket, we might find a transient negative value
+               /* Because we don't lock the socket,
+                * we might find a transient negative value.
                 */
                rx_queue = max_t(int, tp->rcv_nxt - tp->copied_seq, 0);
 
        seq_printf(f, "%4d: %08X:%04X %08X:%04X %02X %08X:%08X %02X:%08lX "
                        "%08X %5u %8d %lu %d %pK %lu %lu %u %u %d",
-               i, src, srcp, dest, destp, sk->sk_state,
+               i, src, srcp, dest, destp, state,
                tp->write_seq - tp->snd_una,
                rx_queue,
                timer_active,
@@ -2199,8 +2201,8 @@ static void get_tcp4_sock(struct sock *sk, struct seq_file *f, int i)
                jiffies_to_clock_t(icsk->icsk_ack.ato),
                (icsk->icsk_ack.quick << 1) | icsk->icsk_ack.pingpong,
                tp->snd_cwnd,
-               sk->sk_state == TCP_LISTEN ?
-                   (fastopenq ? fastopenq->max_qlen : 0) :
+               state == TCP_LISTEN ?
+                   fastopenq->max_qlen :
                    (tcp_in_initial_slowstart(tp) ? -1 : tp->snd_ssthresh));
 }
 
index cb7ca569052c5b69f78418e9c966cb285eff1d50..9bfc39ff2285aecaab86f519a017b84282cb6597 100644 (file)
@@ -3150,7 +3150,7 @@ static int tcp_send_syn_data(struct sock *sk, struct sk_buff *syn)
 {
        struct tcp_sock *tp = tcp_sk(sk);
        struct tcp_fastopen_request *fo = tp->fastopen_req;
-       int syn_loss = 0, space, err = 0, copied;
+       int syn_loss = 0, space, err = 0;
        unsigned long last_syn_loss = 0;
        struct sk_buff *syn_data;
 
@@ -3188,17 +3188,18 @@ static int tcp_send_syn_data(struct sock *sk, struct sk_buff *syn)
                goto fallback;
        syn_data->ip_summed = CHECKSUM_PARTIAL;
        memcpy(syn_data->cb, syn->cb, sizeof(syn->cb));
-       copied = copy_from_iter(skb_put(syn_data, space), space,
-                               &fo->data->msg_iter);
-       if (unlikely(!copied)) {
-               kfree_skb(syn_data);
-               goto fallback;
-       }
-       if (copied != space) {
-               skb_trim(syn_data, copied);
-               space = copied;
+       if (space) {
+               int copied = copy_from_iter(skb_put(syn_data, space), space,
+                                           &fo->data->msg_iter);
+               if (unlikely(!copied)) {
+                       kfree_skb(syn_data);
+                       goto fallback;
+               }
+               if (copied != space) {
+                       skb_trim(syn_data, copied);
+                       space = copied;
+               }
        }
-
        /* No more data pending in inet_wait_for_connect() */
        if (space == fo->size)
                fo->data = NULL;
index c9c716a483e457e8b4fe063776ae3d7a855889cc..193ba1fa8a9abbc190823a86398722d5c5a605fe 100644 (file)
@@ -168,7 +168,7 @@ static int tcp_write_timeout(struct sock *sk)
                        dst_negative_advice(sk);
                        if (tp->syn_fastopen || tp->syn_data)
                                tcp_fastopen_cache_set(sk, 0, NULL, true, 0);
-                       if (tp->syn_data)
+                       if (tp->syn_data && icsk->icsk_retransmits == 1)
                                NET_INC_STATS_BH(sock_net(sk),
                                                 LINUX_MIB_TCPFASTOPENACTIVEFAIL);
                }
@@ -176,6 +176,18 @@ static int tcp_write_timeout(struct sock *sk)
                syn_set = true;
        } else {
                if (retransmits_timed_out(sk, sysctl_tcp_retries1, 0, 0)) {
+                       /* Some middle-boxes may black-hole Fast Open _after_
+                        * the handshake. Therefore we conservatively disable
+                        * Fast Open on this path on recurring timeouts with
+                        * few or zero bytes acked after Fast Open.
+                        */
+                       if (tp->syn_data_acked &&
+                           tp->bytes_acked <= tp->rx_opt.mss_clamp) {
+                               tcp_fastopen_cache_set(sk, 0, NULL, true, 0);
+                               if (icsk->icsk_retransmits == sysctl_tcp_retries1)
+                                       NET_INC_STATS_BH(sock_net(sk),
+                                                        LINUX_MIB_TCPFASTOPENACTIVEFAIL);
+                       }
                        /* Black hole detection */
                        tcp_mtu_probing(icsk, sk);
 
index 24ec14f9825c20834eca20b820ec953ba108da52..0c7b0e61b917158af7e431f9e7781f7bce313c83 100644 (file)
 #include <linux/slab.h>
 #include <net/tcp_states.h>
 #include <linux/skbuff.h>
-#include <linux/netdevice.h>
 #include <linux/proc_fs.h>
 #include <linux/seq_file.h>
 #include <net/net_namespace.h>
index 1e0c3c835a6349eedca54e2dff191ed56b437613..7b0edb37a1150427ef3b0d9a7f2be11421ef67b0 100644 (file)
@@ -259,7 +259,7 @@ static void xfrm4_dst_ifdown(struct dst_entry *dst, struct net_device *dev,
        xfrm_dst_ifdown(dst, dev);
 }
 
-static struct dst_ops xfrm4_dst_ops = {
+static struct dst_ops xfrm4_dst_ops_template = {
        .family =               AF_INET,
        .gc =                   xfrm4_garbage_collect,
        .update_pmtu =          xfrm4_update_pmtu,
@@ -273,7 +273,7 @@ static struct dst_ops xfrm4_dst_ops = {
 
 static struct xfrm_policy_afinfo xfrm4_policy_afinfo = {
        .family =               AF_INET,
-       .dst_ops =              &xfrm4_dst_ops,
+       .dst_ops =              &xfrm4_dst_ops_template,
        .dst_lookup =           xfrm4_dst_lookup,
        .get_saddr =            xfrm4_get_saddr,
        .decode_session =       _decode_session4,
@@ -295,7 +295,7 @@ static struct ctl_table xfrm4_policy_table[] = {
        { }
 };
 
-static int __net_init xfrm4_net_init(struct net *net)
+static int __net_init xfrm4_net_sysctl_init(struct net *net)
 {
        struct ctl_table *table;
        struct ctl_table_header *hdr;
@@ -323,7 +323,7 @@ err_alloc:
        return -ENOMEM;
 }
 
-static void __net_exit xfrm4_net_exit(struct net *net)
+static void __net_exit xfrm4_net_sysctl_exit(struct net *net)
 {
        struct ctl_table *table;
 
@@ -335,12 +335,44 @@ static void __net_exit xfrm4_net_exit(struct net *net)
        if (!net_eq(net, &init_net))
                kfree(table);
 }
+#else /* CONFIG_SYSCTL */
+static int inline xfrm4_net_sysctl_init(struct net *net)
+{
+       return 0;
+}
+
+static void inline xfrm4_net_sysctl_exit(struct net *net)
+{
+}
+#endif
+
+static int __net_init xfrm4_net_init(struct net *net)
+{
+       int ret;
+
+       memcpy(&net->xfrm.xfrm4_dst_ops, &xfrm4_dst_ops_template,
+              sizeof(xfrm4_dst_ops_template));
+       ret = dst_entries_init(&net->xfrm.xfrm4_dst_ops);
+       if (ret)
+               return ret;
+
+       ret = xfrm4_net_sysctl_init(net);
+       if (ret)
+               dst_entries_destroy(&net->xfrm.xfrm4_dst_ops);
+
+       return ret;
+}
+
+static void __net_exit xfrm4_net_exit(struct net *net)
+{
+       xfrm4_net_sysctl_exit(net);
+       dst_entries_destroy(&net->xfrm.xfrm4_dst_ops);
+}
 
 static struct pernet_operations __net_initdata xfrm4_net_ops = {
        .init   = xfrm4_net_init,
        .exit   = xfrm4_net_exit,
 };
-#endif
 
 static void __init xfrm4_policy_init(void)
 {
@@ -349,13 +381,9 @@ static void __init xfrm4_policy_init(void)
 
 void __init xfrm4_init(void)
 {
-       dst_entries_init(&xfrm4_dst_ops);
-
        xfrm4_state_init();
        xfrm4_policy_init();
        xfrm4_protocol_init();
-#ifdef CONFIG_SYSCTL
        register_pernet_subsys(&xfrm4_net_ops);
-#endif
 }
 
index d84742f003a9fca65a3545abdb7a4d517989ed4c..1f21087accab258e5be6cc104f8b8ced13fedd6d 100644 (file)
@@ -350,6 +350,12 @@ static struct inet6_dev *ipv6_add_dev(struct net_device *dev)
        setup_timer(&ndev->rs_timer, addrconf_rs_timer,
                    (unsigned long)ndev);
        memcpy(&ndev->cnf, dev_net(dev)->ipv6.devconf_dflt, sizeof(ndev->cnf));
+
+       if (ndev->cnf.stable_secret.initialized)
+               ndev->addr_gen_mode = IN6_ADDR_GEN_MODE_STABLE_PRIVACY;
+       else
+               ndev->addr_gen_mode = IN6_ADDR_GEN_MODE_EUI64;
+
        ndev->cnf.mtu6 = dev->mtu;
        ndev->cnf.sysctl = NULL;
        ndev->nd_parms = neigh_parms_alloc(dev, &nd_tbl);
@@ -2455,7 +2461,7 @@ ok:
 #ifdef CONFIG_IPV6_OPTIMISTIC_DAD
                        if (in6_dev->cnf.optimistic_dad &&
                            !net->ipv6.devconf_all->forwarding && sllao)
-                               addr_flags = IFA_F_OPTIMISTIC;
+                               addr_flags |= IFA_F_OPTIMISTIC;
 #endif
 
                        /* Do not allow to create too much of autoconfigured
@@ -3642,7 +3648,7 @@ static void addrconf_dad_work(struct work_struct *w)
 
        /* send a neighbour solicitation for our addr */
        addrconf_addr_solict_mult(&ifp->addr, &mcaddr);
-       ndisc_send_ns(ifp->idev->dev, &ifp->addr, &mcaddr, &in6addr_any, NULL);
+       ndisc_send_ns(ifp->idev->dev, &ifp->addr, &mcaddr, &in6addr_any);
 out:
        in6_ifa_put(ifp);
        rtnl_unlock();
@@ -5363,13 +5369,10 @@ static int addrconf_sysctl_stable_secret(struct ctl_table *ctl, int write,
                goto out;
        }
 
-       if (!write) {
-               err = snprintf(str, sizeof(str), "%pI6",
-                              &secret->secret);
-               if (err >= sizeof(str)) {
-                       err = -EIO;
-                       goto out;
-               }
+       err = snprintf(str, sizeof(str), "%pI6", &secret->secret);
+       if (err >= sizeof(str)) {
+               err = -EIO;
+               goto out;
        }
 
        err = proc_dostring(&lctl, write, buffer, lenp, ppos);
index 882124ebb438bd033765c4284ddf7ada9834d39d..a8f6986dcbe5ea5a36a3cc6fcf51becebb50c33b 100644 (file)
@@ -552,7 +552,7 @@ static int ip6addrlbl_get(struct sk_buff *in_skb, struct nlmsghdr *nlh)
 
        rcu_read_lock();
        p = __ipv6_addr_label(net, addr, ipv6_addr_type(addr), ifal->ifal_index);
-       if (p && ip6addrlbl_hold(p))
+       if (p && !ip6addrlbl_hold(p))
                p = NULL;
        lseq = ip6addrlbl_table.seq;
        rcu_read_unlock();
index 44bb66bde0e2d97308c3c68a8d6b225ce04d08a8..9f5137cd604e51316c6c3a85ca5423b30ed7ce30 100644 (file)
@@ -109,6 +109,9 @@ static int inet6_create(struct net *net, struct socket *sock, int protocol,
        int try_loading_module = 0;
        int err;
 
+       if (protocol < 0 || protocol >= IPPROTO_MAX)
+               return -EINVAL;
+
        /* Look for the requested type/protocol pair. */
 lookup_protocol:
        err = -ESOCKTNOSUPPORT;
@@ -428,9 +431,11 @@ void inet6_destroy_sock(struct sock *sk)
 
        /* Free tx options */
 
-       opt = xchg(&np->opt, NULL);
-       if (opt)
-               sock_kfree_s(sk, opt, opt->tot_len);
+       opt = xchg((__force struct ipv6_txoptions **)&np->opt, NULL);
+       if (opt) {
+               atomic_sub(opt->tot_len, &sk->sk_omem_alloc);
+               txopt_put(opt);
+       }
 }
 EXPORT_SYMBOL_GPL(inet6_destroy_sock);
 
@@ -659,7 +664,10 @@ int inet6_sk_rebuild_header(struct sock *sk)
                fl6.fl6_sport = inet->inet_sport;
                security_sk_classify_flow(sk, flowi6_to_flowi(&fl6));
 
-               final_p = fl6_update_dst(&fl6, np->opt, &final);
+               rcu_read_lock();
+               final_p = fl6_update_dst(&fl6, rcu_dereference(np->opt),
+                                        &final);
+               rcu_read_unlock();
 
                dst = ip6_dst_lookup_flow(sk, &fl6, final_p);
                if (IS_ERR(dst)) {
@@ -668,7 +676,7 @@ int inet6_sk_rebuild_header(struct sock *sk)
                        return PTR_ERR(dst);
                }
 
-               __ip6_dst_store(sk, dst, NULL, NULL);
+               ip6_dst_store(sk, dst, NULL, NULL);
        }
 
        return 0;
index d70b0238f468f4e5602d09469eddc98a07a3e61c..517c55b01ba84b55a0004ce9505d14c4a3951cfc 100644 (file)
@@ -167,8 +167,10 @@ ipv4_connected:
 
        security_sk_classify_flow(sk, flowi6_to_flowi(&fl6));
 
-       opt = flowlabel ? flowlabel->opt : np->opt;
+       rcu_read_lock();
+       opt = flowlabel ? flowlabel->opt : rcu_dereference(np->opt);
        final_p = fl6_update_dst(&fl6, opt, &final);
+       rcu_read_unlock();
 
        dst = ip6_dst_lookup_flow(sk, &fl6, final_p);
        err = 0;
index ce203b0402bea3b16deb34b4835cd2e89e94f899..ea7c4d64a00adad60a634afb2c6efca4ab029799 100644 (file)
@@ -727,6 +727,7 @@ ipv6_dup_options(struct sock *sk, struct ipv6_txoptions *opt)
                        *((char **)&opt2->dst1opt) += dif;
                if (opt2->srcrt)
                        *((char **)&opt2->srcrt) += dif;
+               atomic_set(&opt2->refcnt, 1);
        }
        return opt2;
 }
@@ -790,7 +791,7 @@ ipv6_renew_options(struct sock *sk, struct ipv6_txoptions *opt,
                return ERR_PTR(-ENOBUFS);
 
        memset(opt2, 0, tot_len);
-
+       atomic_set(&opt2->refcnt, 1);
        opt2->tot_len = tot_len;
        p = (char *)(opt2 + 1);
 
index 36c5a98b04727b220e9ea77e00d96410d4bb3f74..0a37ddc7af51579f56b644ba0e4c3c3a7a2e2bc7 100644 (file)
@@ -834,11 +834,6 @@ void icmpv6_flow_init(struct sock *sk, struct flowi6 *fl6,
        security_sk_classify_flow(sk, flowi6_to_flowi(fl6));
 }
 
-/*
- * Special lock-class for __icmpv6_sk:
- */
-static struct lock_class_key icmpv6_socket_sk_dst_lock_key;
-
 static int __net_init icmpv6_sk_init(struct net *net)
 {
        struct sock *sk;
@@ -860,15 +855,6 @@ static int __net_init icmpv6_sk_init(struct net *net)
 
                net->ipv6.icmp_sk[i] = sk;
 
-               /*
-                * Split off their lock-class, because sk->sk_dst_lock
-                * gets used from softirqs, which is safe for
-                * __icmpv6_sk (because those never get directly used
-                * via userspace syscalls), but unsafe for normal sockets.
-                */
-               lockdep_set_class(&sk->sk_dst_lock,
-                                 &icmpv6_socket_sk_dst_lock_key);
-
                /* Enough space for 2 64K ICMP packets, including
                 * sk_buff struct overhead.
                 */
index 5d1c7cee2cb2bdc45b0889b4fe197c7af4db01e7..a7ca2cde2ecbcff85c9a6151b4770e3897d16314 100644 (file)
@@ -78,7 +78,9 @@ struct dst_entry *inet6_csk_route_req(const struct sock *sk,
        memset(fl6, 0, sizeof(*fl6));
        fl6->flowi6_proto = proto;
        fl6->daddr = ireq->ir_v6_rmt_addr;
-       final_p = fl6_update_dst(fl6, np->opt, &final);
+       rcu_read_lock();
+       final_p = fl6_update_dst(fl6, rcu_dereference(np->opt), &final);
+       rcu_read_unlock();
        fl6->saddr = ireq->ir_v6_loc_addr;
        fl6->flowi6_oif = ireq->ir_iif;
        fl6->flowi6_mark = ireq->ir_mark;
@@ -108,14 +110,6 @@ void inet6_csk_addr2sockaddr(struct sock *sk, struct sockaddr *uaddr)
 }
 EXPORT_SYMBOL_GPL(inet6_csk_addr2sockaddr);
 
-static inline
-void __inet6_csk_dst_store(struct sock *sk, struct dst_entry *dst,
-                          const struct in6_addr *daddr,
-                          const struct in6_addr *saddr)
-{
-       __ip6_dst_store(sk, dst, daddr, saddr);
-}
-
 static inline
 struct dst_entry *__inet6_csk_dst_check(struct sock *sk, u32 cookie)
 {
@@ -142,14 +136,16 @@ static struct dst_entry *inet6_csk_route_socket(struct sock *sk,
        fl6->fl6_dport = inet->inet_dport;
        security_sk_classify_flow(sk, flowi6_to_flowi(fl6));
 
-       final_p = fl6_update_dst(fl6, np->opt, &final);
+       rcu_read_lock();
+       final_p = fl6_update_dst(fl6, rcu_dereference(np->opt), &final);
+       rcu_read_unlock();
 
        dst = __inet6_csk_dst_check(sk, np->dst_cookie);
        if (!dst) {
                dst = ip6_dst_lookup_flow(sk, fl6, final_p);
 
                if (!IS_ERR(dst))
-                       __inet6_csk_dst_store(sk, dst, NULL, NULL);
+                       ip6_dst_store(sk, dst, NULL, NULL);
        }
        return dst;
 }
@@ -175,7 +171,8 @@ int inet6_csk_xmit(struct sock *sk, struct sk_buff *skb, struct flowi *fl_unused
        /* Restore final destination back after routing done */
        fl6.daddr = sk->sk_v6_daddr;
 
-       res = ip6_xmit(sk, skb, &fl6, np->opt, np->tclass);
+       res = ip6_xmit(sk, skb, &fl6, rcu_dereference(np->opt),
+                      np->tclass);
        rcu_read_unlock();
        return res;
 }
index 3c7b9310b33fdb052e2b97d4cd502482524b4dd8..e5ea177d34c6492713d5271032394a69874a300c 100644 (file)
@@ -1571,13 +1571,11 @@ static int ip6gre_changelink(struct net_device *dev, struct nlattr *tb[],
                        return -EEXIST;
        } else {
                t = nt;
-
-               ip6gre_tunnel_unlink(ign, t);
-               ip6gre_tnl_change(t, &p, !tb[IFLA_MTU]);
-               ip6gre_tunnel_link(ign, t);
-               netdev_state_change(dev);
        }
 
+       ip6gre_tunnel_unlink(ign, t);
+       ip6gre_tnl_change(t, &p, !tb[IFLA_MTU]);
+       ip6gre_tunnel_link(ign, t);
        return 0;
 }
 
index eabffbb89795d921b0977989345b25d81f553ee0..137fca42aaa6bb809d46e7809b240d8810d89a04 100644 (file)
@@ -177,7 +177,7 @@ void ip6_tnl_dst_reset(struct ip6_tnl *t)
        int i;
 
        for_each_possible_cpu(i)
-               ip6_tnl_per_cpu_dst_set(raw_cpu_ptr(t->dst_cache), NULL);
+               ip6_tnl_per_cpu_dst_set(per_cpu_ptr(t->dst_cache, i), NULL);
 }
 EXPORT_SYMBOL_GPL(ip6_tnl_dst_reset);
 
index ad19136086dd5e1ae4e362e3da0f0267fc755b02..a10e77103c88dfc952f80c645a7b87c57b8f6dbf 100644 (file)
@@ -118,7 +118,7 @@ static void mr6_netlink_event(struct mr6_table *mrt, struct mfc6_cache *mfc,
                              int cmd);
 static int ip6mr_rtm_dumproute(struct sk_buff *skb,
                               struct netlink_callback *cb);
-static void mroute_clean_tables(struct mr6_table *mrt);
+static void mroute_clean_tables(struct mr6_table *mrt, bool all);
 static void ipmr_expire_process(unsigned long arg);
 
 #ifdef CONFIG_IPV6_MROUTE_MULTIPLE_TABLES
@@ -334,7 +334,7 @@ static struct mr6_table *ip6mr_new_table(struct net *net, u32 id)
 static void ip6mr_free_table(struct mr6_table *mrt)
 {
        del_timer_sync(&mrt->ipmr_expire_timer);
-       mroute_clean_tables(mrt);
+       mroute_clean_tables(mrt, true);
        kfree(mrt);
 }
 
@@ -765,10 +765,6 @@ static struct net_device *ip6mr_reg_vif(struct net *net, struct mr6_table *mrt)
        return dev;
 
 failure:
-       /* allow the register to be completed before unregistering. */
-       rtnl_unlock();
-       rtnl_lock();
-
        unregister_netdevice(dev);
        return NULL;
 }
@@ -1542,7 +1538,7 @@ static int ip6mr_mfc_add(struct net *net, struct mr6_table *mrt,
  *     Close the multicast socket, and clear the vif tables etc
  */
 
-static void mroute_clean_tables(struct mr6_table *mrt)
+static void mroute_clean_tables(struct mr6_table *mrt, bool all)
 {
        int i;
        LIST_HEAD(list);
@@ -1552,8 +1548,9 @@ static void mroute_clean_tables(struct mr6_table *mrt)
         *      Shut down all active vif entries
         */
        for (i = 0; i < mrt->maxvif; i++) {
-               if (!(mrt->vif6_table[i].flags & VIFF_STATIC))
-                       mif6_delete(mrt, i, &list);
+               if (!all && (mrt->vif6_table[i].flags & VIFF_STATIC))
+                       continue;
+               mif6_delete(mrt, i, &list);
        }
        unregister_netdevice_many(&list);
 
@@ -1562,7 +1559,7 @@ static void mroute_clean_tables(struct mr6_table *mrt)
         */
        for (i = 0; i < MFC6_LINES; i++) {
                list_for_each_entry_safe(c, next, &mrt->mfc6_cache_array[i], list) {
-                       if (c->mfc_flags & MFC_STATIC)
+                       if (!all && (c->mfc_flags & MFC_STATIC))
                                continue;
                        write_lock_bh(&mrt_lock);
                        list_del(&c->list);
@@ -1625,7 +1622,7 @@ int ip6mr_sk_done(struct sock *sk)
                                                     net->ipv6.devconf_all);
                        write_unlock_bh(&mrt_lock);
 
-                       mroute_clean_tables(mrt);
+                       mroute_clean_tables(mrt, false);
                        err = 0;
                        break;
                }
index 63e6956917c9cf20ee74968de3a7f03c1b48c849..4449ad1f81147cab79c44209f3f2a73dc1f6a934 100644 (file)
@@ -111,7 +111,8 @@ struct ipv6_txoptions *ipv6_update_options(struct sock *sk,
                        icsk->icsk_sync_mss(sk, icsk->icsk_pmtu_cookie);
                }
        }
-       opt = xchg(&inet6_sk(sk)->opt, opt);
+       opt = xchg((__force struct ipv6_txoptions **)&inet6_sk(sk)->opt,
+                  opt);
        sk_dst_reset(sk);
 
        return opt;
@@ -231,9 +232,12 @@ static int do_ipv6_setsockopt(struct sock *sk, int level, int optname,
                                sk->sk_socket->ops = &inet_dgram_ops;
                                sk->sk_family = PF_INET;
                        }
-                       opt = xchg(&np->opt, NULL);
-                       if (opt)
-                               sock_kfree_s(sk, opt, opt->tot_len);
+                       opt = xchg((__force struct ipv6_txoptions **)&np->opt,
+                                  NULL);
+                       if (opt) {
+                               atomic_sub(opt->tot_len, &sk->sk_omem_alloc);
+                               txopt_put(opt);
+                       }
                        pktopt = xchg(&np->pktoptions, NULL);
                        kfree_skb(pktopt);
 
@@ -403,7 +407,8 @@ static int do_ipv6_setsockopt(struct sock *sk, int level, int optname,
                if (optname != IPV6_RTHDR && !ns_capable(net->user_ns, CAP_NET_RAW))
                        break;
 
-               opt = ipv6_renew_options(sk, np->opt, optname,
+               opt = rcu_dereference_protected(np->opt, sock_owned_by_user(sk));
+               opt = ipv6_renew_options(sk, opt, optname,
                                         (struct ipv6_opt_hdr __user *)optval,
                                         optlen);
                if (IS_ERR(opt)) {
@@ -432,8 +437,10 @@ static int do_ipv6_setsockopt(struct sock *sk, int level, int optname,
                retv = 0;
                opt = ipv6_update_options(sk, opt);
 sticky_done:
-               if (opt)
-                       sock_kfree_s(sk, opt, opt->tot_len);
+               if (opt) {
+                       atomic_sub(opt->tot_len, &sk->sk_omem_alloc);
+                       txopt_put(opt);
+               }
                break;
        }
 
@@ -486,6 +493,7 @@ sticky_done:
                        break;
 
                memset(opt, 0, sizeof(*opt));
+               atomic_set(&opt->refcnt, 1);
                opt->tot_len = sizeof(*opt) + optlen;
                retv = -EFAULT;
                if (copy_from_user(opt+1, optval, optlen))
@@ -502,8 +510,10 @@ update:
                retv = 0;
                opt = ipv6_update_options(sk, opt);
 done:
-               if (opt)
-                       sock_kfree_s(sk, opt, opt->tot_len);
+               if (opt) {
+                       atomic_sub(opt->tot_len, &sk->sk_omem_alloc);
+                       txopt_put(opt);
+               }
                break;
        }
        case IPV6_UNICAST_HOPS:
@@ -1110,10 +1120,11 @@ static int do_ipv6_getsockopt(struct sock *sk, int level, int optname,
        case IPV6_RTHDR:
        case IPV6_DSTOPTS:
        {
+               struct ipv6_txoptions *opt;
 
                lock_sock(sk);
-               len = ipv6_getsockopt_sticky(sk, np->opt,
-                                            optname, optval, len);
+               opt = rcu_dereference_protected(np->opt, sock_owned_by_user(sk));
+               len = ipv6_getsockopt_sticky(sk, opt, optname, optval, len);
                release_sock(sk);
                /* check if ipv6_getsockopt_sticky() returns err code */
                if (len < 0)
index 124338a39e29cb3e3a5e602fb706486f330fb529..5ee56d0a8699e22434d5ad8b4380f890fa8d2126 100644 (file)
@@ -1651,7 +1651,6 @@ out:
        if (!err) {
                ICMP6MSGOUT_INC_STATS(net, idev, ICMPV6_MLD2_REPORT);
                ICMP6_INC_STATS(net, idev, ICMP6_MIB_OUTMSGS);
-               IP6_UPD_PO_STATS(net, idev, IPSTATS_MIB_OUTMCAST, payload_len);
        } else {
                IP6_INC_STATS(net, idev, IPSTATS_MIB_OUTDISCARDS);
        }
@@ -2015,7 +2014,6 @@ out:
        if (!err) {
                ICMP6MSGOUT_INC_STATS(net, idev, type);
                ICMP6_INC_STATS(net, idev, ICMP6_MIB_OUTMSGS);
-               IP6_UPD_PO_STATS(net, idev, IPSTATS_MIB_OUTMCAST, full_len);
        } else
                IP6_INC_STATS(net, idev, IPSTATS_MIB_OUTDISCARDS);
 
index 3e0f855e1bead049064a284494eda378f85ae47e..84afb9a7727848038b51ee7a60eebb28d555f693 100644 (file)
@@ -556,8 +556,7 @@ static void ndisc_send_unsol_na(struct net_device *dev)
 }
 
 void ndisc_send_ns(struct net_device *dev, const struct in6_addr *solicit,
-                  const struct in6_addr *daddr, const struct in6_addr *saddr,
-                  struct sk_buff *oskb)
+                  const struct in6_addr *daddr, const struct in6_addr *saddr)
 {
        struct sk_buff *skb;
        struct in6_addr addr_buf;
@@ -593,9 +592,6 @@ void ndisc_send_ns(struct net_device *dev, const struct in6_addr *solicit,
                ndisc_fill_addr_option(skb, ND_OPT_SOURCE_LL_ADDR,
                                       dev->dev_addr);
 
-       if (!(dev->priv_flags & IFF_XMIT_DST_RELEASE) && oskb)
-               skb_dst_copy(skb, oskb);
-
        ndisc_send_skb(skb, daddr, saddr);
 }
 
@@ -682,12 +678,12 @@ static void ndisc_solicit(struct neighbour *neigh, struct sk_buff *skb)
                                  "%s: trying to ucast probe in NUD_INVALID: %pI6\n",
                                  __func__, target);
                }
-               ndisc_send_ns(dev, target, target, saddr, skb);
+               ndisc_send_ns(dev, target, target, saddr);
        } else if ((probes -= NEIGH_VAR(neigh->parms, APP_PROBES)) < 0) {
                neigh_app_ns(neigh);
        } else {
                addrconf_addr_solict_mult(target, &mcaddr);
-               ndisc_send_ns(dev, target, &mcaddr, saddr, skb);
+               ndisc_send_ns(dev, target, &mcaddr, saddr);
        }
 }
 
@@ -1187,7 +1183,7 @@ static void ndisc_router_discovery(struct sk_buff *skb)
         */
        if (!in6_dev->cnf.accept_ra_from_local &&
            ipv6_chk_addr(dev_net(in6_dev->dev), &ipv6_hdr(skb)->saddr,
-                         NULL, 0)) {
+                         in6_dev->dev, 0)) {
                ND_PRINTK(2, info,
                          "RA from local address detected on dev: %s: default router ignored\n",
                          skb->dev->name);
@@ -1341,7 +1337,7 @@ skip_linkparms:
 #ifdef CONFIG_IPV6_ROUTE_INFO
        if (!in6_dev->cnf.accept_ra_from_local &&
            ipv6_chk_addr(dev_net(in6_dev->dev), &ipv6_hdr(skb)->saddr,
-                         NULL, 0)) {
+                         in6_dev->dev, 0)) {
                ND_PRINTK(2, info,
                          "RA from local address detected on dev: %s: router info ignored.\n",
                          skb->dev->name);
index f6a024e141e595541009cb24c172e0c52a8a879f..e10a04c9cdc7be6bd8fc18f960e7bf51f43cbd81 100644 (file)
@@ -49,6 +49,7 @@ config NFT_REJECT_IPV6
 
 config NFT_DUP_IPV6
        tristate "IPv6 nf_tables packet duplication support"
+       depends on !NF_CONNTRACK || NF_CONNTRACK
        select NF_DUP_IPV6
        help
          This module enables IPv6 packet duplication support for nf_tables.
index d5efeb87350e7fc8643962036c0b26cfe471cdc4..bab4441ed4e43906ce0b20d7618668eef81f1162 100644 (file)
@@ -190,7 +190,7 @@ static void nf_ct_frag6_expire(unsigned long data)
 /* Creation primitives. */
 static inline struct frag_queue *fq_find(struct net *net, __be32 id,
                                         u32 user, struct in6_addr *src,
-                                        struct in6_addr *dst, u8 ecn)
+                                        struct in6_addr *dst, int iif, u8 ecn)
 {
        struct inet_frag_queue *q;
        struct ip6_create_arg arg;
@@ -200,6 +200,7 @@ static inline struct frag_queue *fq_find(struct net *net, __be32 id,
        arg.user = user;
        arg.src = src;
        arg.dst = dst;
+       arg.iif = iif;
        arg.ecn = ecn;
 
        local_bh_disable();
@@ -601,7 +602,7 @@ struct sk_buff *nf_ct_frag6_gather(struct net *net, struct sk_buff *skb, u32 use
        fhdr = (struct frag_hdr *)skb_transport_header(clone);
 
        fq = fq_find(net, fhdr->identification, user, &hdr->saddr, &hdr->daddr,
-                    ip6_frag_ecn(hdr));
+                    skb->dev ? skb->dev->ifindex : 0, ip6_frag_ecn(hdr));
        if (fq == NULL) {
                pr_debug("Can't find and can't create new queue\n");
                goto ret_orig;
index dc65ec198f7c3f7ae19176fdaa8752c7fb4e13a5..99140986e88716529b90f082bf2b7011a2db8c15 100644 (file)
@@ -733,6 +733,7 @@ static int raw6_getfrag(void *from, char *to, int offset, int len, int odd,
 
 static int rawv6_sendmsg(struct sock *sk, struct msghdr *msg, size_t len)
 {
+       struct ipv6_txoptions *opt_to_free = NULL;
        struct ipv6_txoptions opt_space;
        DECLARE_SOCKADDR(struct sockaddr_in6 *, sin6, msg->msg_name);
        struct in6_addr *daddr, *final_p, final;
@@ -839,8 +840,10 @@ static int rawv6_sendmsg(struct sock *sk, struct msghdr *msg, size_t len)
                if (!(opt->opt_nflen|opt->opt_flen))
                        opt = NULL;
        }
-       if (!opt)
-               opt = np->opt;
+       if (!opt) {
+               opt = txopt_get(np);
+               opt_to_free = opt;
+               }
        if (flowlabel)
                opt = fl6_merge_options(&opt_space, flowlabel, opt);
        opt = ipv6_fixup_options(&opt_space, opt);
@@ -906,6 +909,7 @@ done:
        dst_release(dst);
 out:
        fl6_sock_release(flowlabel);
+       txopt_put(opt_to_free);
        return err < 0 ? err : len;
 do_confirm:
        dst_confirm(dst);
index 44e21a03cfc3fff395903d36e8e01a7a3e395afa..45f5ae51de65c0fb4d700bad79a05c1e750309e0 100644 (file)
@@ -108,7 +108,10 @@ bool ip6_frag_match(const struct inet_frag_queue *q, const void *a)
        return  fq->id == arg->id &&
                fq->user == arg->user &&
                ipv6_addr_equal(&fq->saddr, arg->src) &&
-               ipv6_addr_equal(&fq->daddr, arg->dst);
+               ipv6_addr_equal(&fq->daddr, arg->dst) &&
+               (arg->iif == fq->iif ||
+                !(ipv6_addr_type(arg->dst) & (IPV6_ADDR_MULTICAST |
+                                              IPV6_ADDR_LINKLOCAL)));
 }
 EXPORT_SYMBOL(ip6_frag_match);
 
@@ -180,7 +183,7 @@ static void ip6_frag_expire(unsigned long data)
 
 static struct frag_queue *
 fq_find(struct net *net, __be32 id, const struct in6_addr *src,
-       const struct in6_addr *dst, u8 ecn)
+       const struct in6_addr *dst, int iif, u8 ecn)
 {
        struct inet_frag_queue *q;
        struct ip6_create_arg arg;
@@ -190,6 +193,7 @@ fq_find(struct net *net, __be32 id, const struct in6_addr *src,
        arg.user = IP6_DEFRAG_LOCAL_DELIVER;
        arg.src = src;
        arg.dst = dst;
+       arg.iif = iif;
        arg.ecn = ecn;
 
        hash = inet6_hash_frag(id, src, dst);
@@ -551,7 +555,7 @@ static int ipv6_frag_rcv(struct sk_buff *skb)
        }
 
        fq = fq_find(net, fhdr->identification, &hdr->saddr, &hdr->daddr,
-                    ip6_frag_ecn(hdr));
+                    skb->dev ? skb->dev->ifindex : 0, ip6_frag_ecn(hdr));
        if (fq) {
                int ret;
 
index c8bc9b4ac32835e7328025a8912f3627b365e38a..826e6aa44f8d42c9c2e815ee134a4f58f1f29c80 100644 (file)
@@ -404,6 +404,14 @@ static void ip6_dst_ifdown(struct dst_entry *dst, struct net_device *dev,
        }
 }
 
+static bool __rt6_check_expired(const struct rt6_info *rt)
+{
+       if (rt->rt6i_flags & RTF_EXPIRES)
+               return time_after(jiffies, rt->dst.expires);
+       else
+               return false;
+}
+
 static bool rt6_check_expired(const struct rt6_info *rt)
 {
        if (rt->rt6i_flags & RTF_EXPIRES) {
@@ -515,7 +523,7 @@ static void rt6_probe_deferred(struct work_struct *w)
                container_of(w, struct __rt6_probe_work, work);
 
        addrconf_addr_solict_mult(&work->target, &mcaddr);
-       ndisc_send_ns(work->dev, &work->target, &mcaddr, NULL, NULL);
+       ndisc_send_ns(work->dev, &work->target, &mcaddr, NULL);
        dev_put(work->dev);
        kfree(work);
 }
@@ -1252,7 +1260,8 @@ static struct dst_entry *rt6_check(struct rt6_info *rt, u32 cookie)
 
 static struct dst_entry *rt6_dst_from_check(struct rt6_info *rt, u32 cookie)
 {
-       if (rt->dst.obsolete == DST_OBSOLETE_FORCE_CHK &&
+       if (!__rt6_check_expired(rt) &&
+           rt->dst.obsolete == DST_OBSOLETE_FORCE_CHK &&
            rt6_check((struct rt6_info *)(rt->dst.from), cookie))
                return &rt->dst;
        else
@@ -1272,7 +1281,8 @@ static struct dst_entry *ip6_dst_check(struct dst_entry *dst, u32 cookie)
 
        rt6_dst_from_metrics_check(rt);
 
-       if ((rt->rt6i_flags & RTF_PCPU) || unlikely(dst->flags & DST_NOCACHE))
+       if (rt->rt6i_flags & RTF_PCPU ||
+           (unlikely(dst->flags & DST_NOCACHE) && rt->dst.from))
                return rt6_dst_from_check(rt, cookie);
        else
                return rt6_check(rt, cookie);
@@ -1322,6 +1332,12 @@ static void rt6_do_update_pmtu(struct rt6_info *rt, u32 mtu)
        rt6_update_expires(rt, net->ipv6.sysctl.ip6_rt_mtu_expires);
 }
 
+static bool rt6_cache_allowed_for_pmtu(const struct rt6_info *rt)
+{
+       return !(rt->rt6i_flags & RTF_CACHE) &&
+               (rt->rt6i_flags & RTF_PCPU || rt->rt6i_node);
+}
+
 static void __ip6_rt_update_pmtu(struct dst_entry *dst, const struct sock *sk,
                                 const struct ipv6hdr *iph, u32 mtu)
 {
@@ -1335,7 +1351,7 @@ static void __ip6_rt_update_pmtu(struct dst_entry *dst, const struct sock *sk,
        if (mtu >= dst_mtu(dst))
                return;
 
-       if (rt6->rt6i_flags & RTF_CACHE) {
+       if (!rt6_cache_allowed_for_pmtu(rt6)) {
                rt6_do_update_pmtu(rt6, mtu);
        } else {
                const struct in6_addr *daddr, *saddr;
index bb8f2fa1c7fbbe1ac0936688ad684ae30679d917..eaf7ac496d506937cd52944bbdc17da720110b59 100644 (file)
@@ -222,7 +222,7 @@ struct sock *cookie_v6_check(struct sock *sk, struct sk_buff *skb)
                memset(&fl6, 0, sizeof(fl6));
                fl6.flowi6_proto = IPPROTO_TCP;
                fl6.daddr = ireq->ir_v6_rmt_addr;
-               final_p = fl6_update_dst(&fl6, np->opt, &final);
+               final_p = fl6_update_dst(&fl6, rcu_dereference(np->opt), &final);
                fl6.saddr = ireq->ir_v6_loc_addr;
                fl6.flowi6_oif = sk->sk_bound_dev_if;
                fl6.flowi6_mark = ireq->ir_mark;
index 5baa8e754e412c454ca22c03822cc57c29df8c35..6b8a8a9091fa113ee28906c570e78811e6f29815 100644 (file)
@@ -93,10 +93,9 @@ static void inet6_sk_rx_dst_set(struct sock *sk, const struct sk_buff *skb)
 {
        struct dst_entry *dst = skb_dst(skb);
 
-       if (dst) {
+       if (dst && dst_hold_safe(dst)) {
                const struct rt6_info *rt = (const struct rt6_info *)dst;
 
-               dst_hold(dst);
                sk->sk_rx_dst = dst;
                inet_sk(sk)->rx_dst_ifindex = skb->skb_iif;
                inet6_sk(sk)->rx_dst_cookie = rt6_get_cookie(rt);
@@ -120,6 +119,7 @@ static int tcp_v6_connect(struct sock *sk, struct sockaddr *uaddr,
        struct ipv6_pinfo *np = inet6_sk(sk);
        struct tcp_sock *tp = tcp_sk(sk);
        struct in6_addr *saddr = NULL, *final_p, final;
+       struct ipv6_txoptions *opt;
        struct flowi6 fl6;
        struct dst_entry *dst;
        int addr_type;
@@ -235,7 +235,8 @@ static int tcp_v6_connect(struct sock *sk, struct sockaddr *uaddr,
        fl6.fl6_dport = usin->sin6_port;
        fl6.fl6_sport = inet->inet_sport;
 
-       final_p = fl6_update_dst(&fl6, np->opt, &final);
+       opt = rcu_dereference_protected(np->opt, sock_owned_by_user(sk));
+       final_p = fl6_update_dst(&fl6, opt, &final);
 
        security_sk_classify_flow(sk, flowi6_to_flowi(&fl6));
 
@@ -255,7 +256,7 @@ static int tcp_v6_connect(struct sock *sk, struct sockaddr *uaddr,
        inet->inet_rcv_saddr = LOOPBACK4_IPV6;
 
        sk->sk_gso_type = SKB_GSO_TCPV6;
-       __ip6_dst_store(sk, dst, NULL, NULL);
+       ip6_dst_store(sk, dst, NULL, NULL);
 
        if (tcp_death_row.sysctl_tw_recycle &&
            !tp->rx_opt.ts_recent_stamp &&
@@ -263,9 +264,9 @@ static int tcp_v6_connect(struct sock *sk, struct sockaddr *uaddr,
                tcp_fetch_timewait_stamp(sk, dst);
 
        icsk->icsk_ext_hdr_len = 0;
-       if (np->opt)
-               icsk->icsk_ext_hdr_len = (np->opt->opt_flen +
-                                         np->opt->opt_nflen);
+       if (opt)
+               icsk->icsk_ext_hdr_len = opt->opt_flen +
+                                        opt->opt_nflen;
 
        tp->rx_opt.mss_clamp = IPV6_MIN_MTU - sizeof(struct tcphdr) - sizeof(struct ipv6hdr);
 
@@ -461,7 +462,8 @@ static int tcp_v6_send_synack(const struct sock *sk, struct dst_entry *dst,
                if (np->repflow && ireq->pktopts)
                        fl6->flowlabel = ip6_flowlabel(ipv6_hdr(ireq->pktopts));
 
-               err = ip6_xmit(sk, skb, fl6, np->opt, np->tclass);
+               err = ip6_xmit(sk, skb, fl6, rcu_dereference(np->opt),
+                              np->tclass);
                err = net_xmit_eval(err);
        }
 
@@ -972,6 +974,7 @@ static struct sock *tcp_v6_syn_recv_sock(const struct sock *sk, struct sk_buff *
        struct inet_request_sock *ireq;
        struct ipv6_pinfo *newnp;
        const struct ipv6_pinfo *np = inet6_sk(sk);
+       struct ipv6_txoptions *opt;
        struct tcp6_sock *newtcp6sk;
        struct inet_sock *newinet;
        struct tcp_sock *newtp;
@@ -1056,7 +1059,7 @@ static struct sock *tcp_v6_syn_recv_sock(const struct sock *sk, struct sk_buff *
         */
 
        newsk->sk_gso_type = SKB_GSO_TCPV6;
-       __ip6_dst_store(newsk, dst, NULL, NULL);
+       ip6_dst_store(newsk, dst, NULL, NULL);
        inet6_sk_rx_dst_set(newsk, skb);
 
        newtcp6sk = (struct tcp6_sock *)newsk;
@@ -1098,13 +1101,15 @@ static struct sock *tcp_v6_syn_recv_sock(const struct sock *sk, struct sk_buff *
           but we make one more one thing there: reattach optmem
           to newsk.
         */
-       if (np->opt)
-               newnp->opt = ipv6_dup_options(newsk, np->opt);
-
+       opt = rcu_dereference(np->opt);
+       if (opt) {
+               opt = ipv6_dup_options(newsk, opt);
+               RCU_INIT_POINTER(newnp->opt, opt);
+       }
        inet_csk(newsk)->icsk_ext_hdr_len = 0;
-       if (newnp->opt)
-               inet_csk(newsk)->icsk_ext_hdr_len = (newnp->opt->opt_nflen +
-                                                    newnp->opt->opt_flen);
+       if (opt)
+               inet_csk(newsk)->icsk_ext_hdr_len = opt->opt_nflen +
+                                                   opt->opt_flen;
 
        tcp_ca_openreq_child(newsk, dst);
 
@@ -1690,6 +1695,8 @@ static void get_tcp6_sock(struct seq_file *seq, struct sock *sp, int i)
        const struct tcp_sock *tp = tcp_sk(sp);
        const struct inet_connection_sock *icsk = inet_csk(sp);
        const struct fastopen_queue *fastopenq = &icsk->icsk_accept_queue.fastopenq;
+       int rx_queue;
+       int state;
 
        dest  = &sp->sk_v6_daddr;
        src   = &sp->sk_v6_rcv_saddr;
@@ -1710,6 +1717,15 @@ static void get_tcp6_sock(struct seq_file *seq, struct sock *sp, int i)
                timer_expires = jiffies;
        }
 
+       state = sk_state_load(sp);
+       if (state == TCP_LISTEN)
+               rx_queue = sp->sk_ack_backlog;
+       else
+               /* Because we don't lock the socket,
+                * we might find a transient negative value.
+                */
+               rx_queue = max_t(int, tp->rcv_nxt - tp->copied_seq, 0);
+
        seq_printf(seq,
                   "%4d: %08X%08X%08X%08X:%04X %08X%08X%08X%08X:%04X "
                   "%02X %08X:%08X %02X:%08lX %08X %5u %8d %lu %d %pK %lu %lu %u %u %d\n",
@@ -1718,9 +1734,9 @@ static void get_tcp6_sock(struct seq_file *seq, struct sock *sp, int i)
                   src->s6_addr32[2], src->s6_addr32[3], srcp,
                   dest->s6_addr32[0], dest->s6_addr32[1],
                   dest->s6_addr32[2], dest->s6_addr32[3], destp,
-                  sp->sk_state,
-                  tp->write_seq-tp->snd_una,
-                  (sp->sk_state == TCP_LISTEN) ? sp->sk_ack_backlog : (tp->rcv_nxt - tp->copied_seq),
+                  state,
+                  tp->write_seq - tp->snd_una,
+                  rx_queue,
                   timer_active,
                   jiffies_delta_to_clock_t(timer_expires - jiffies),
                   icsk->icsk_retransmits,
@@ -1732,7 +1748,7 @@ static void get_tcp6_sock(struct seq_file *seq, struct sock *sp, int i)
                   jiffies_to_clock_t(icsk->icsk_ack.ato),
                   (icsk->icsk_ack.quick << 1) | icsk->icsk_ack.pingpong,
                   tp->snd_cwnd,
-                  sp->sk_state == TCP_LISTEN ?
+                  state == TCP_LISTEN ?
                        fastopenq->max_qlen :
                        (tcp_in_initial_slowstart(tp) ? -1 : tp->snd_ssthresh)
                   );
index 01bcb49619ee6659aefbd198d40f25bab8319749..9da3287a392370a5c05c538a30613f8ce74f8de1 100644 (file)
@@ -1110,6 +1110,7 @@ int udpv6_sendmsg(struct sock *sk, struct msghdr *msg, size_t len)
        DECLARE_SOCKADDR(struct sockaddr_in6 *, sin6, msg->msg_name);
        struct in6_addr *daddr, *final_p, final;
        struct ipv6_txoptions *opt = NULL;
+       struct ipv6_txoptions *opt_to_free = NULL;
        struct ip6_flowlabel *flowlabel = NULL;
        struct flowi6 fl6;
        struct dst_entry *dst;
@@ -1263,8 +1264,10 @@ do_udp_sendmsg:
                        opt = NULL;
                connected = 0;
        }
-       if (!opt)
-               opt = np->opt;
+       if (!opt) {
+               opt = txopt_get(np);
+               opt_to_free = opt;
+       }
        if (flowlabel)
                opt = fl6_merge_options(&opt_space, flowlabel, opt);
        opt = ipv6_fixup_options(&opt_space, opt);
@@ -1373,6 +1376,7 @@ release_dst:
 out:
        dst_release(dst);
        fl6_sock_release(flowlabel);
+       txopt_put(opt_to_free);
        if (!err)
                return len;
        /*
index 5643423fe67a238c05aee5398ac4064a77bafc16..c074771a10f761253f99611de8294172bdb0e142 100644 (file)
@@ -279,7 +279,7 @@ static void xfrm6_dst_ifdown(struct dst_entry *dst, struct net_device *dev,
        xfrm_dst_ifdown(dst, dev);
 }
 
-static struct dst_ops xfrm6_dst_ops = {
+static struct dst_ops xfrm6_dst_ops_template = {
        .family =               AF_INET6,
        .gc =                   xfrm6_garbage_collect,
        .update_pmtu =          xfrm6_update_pmtu,
@@ -293,7 +293,7 @@ static struct dst_ops xfrm6_dst_ops = {
 
 static struct xfrm_policy_afinfo xfrm6_policy_afinfo = {
        .family =               AF_INET6,
-       .dst_ops =              &xfrm6_dst_ops,
+       .dst_ops =              &xfrm6_dst_ops_template,
        .dst_lookup =           xfrm6_dst_lookup,
        .get_saddr =            xfrm6_get_saddr,
        .decode_session =       _decode_session6,
@@ -325,7 +325,7 @@ static struct ctl_table xfrm6_policy_table[] = {
        { }
 };
 
-static int __net_init xfrm6_net_init(struct net *net)
+static int __net_init xfrm6_net_sysctl_init(struct net *net)
 {
        struct ctl_table *table;
        struct ctl_table_header *hdr;
@@ -353,7 +353,7 @@ err_alloc:
        return -ENOMEM;
 }
 
-static void __net_exit xfrm6_net_exit(struct net *net)
+static void __net_exit xfrm6_net_sysctl_exit(struct net *net)
 {
        struct ctl_table *table;
 
@@ -365,24 +365,52 @@ static void __net_exit xfrm6_net_exit(struct net *net)
        if (!net_eq(net, &init_net))
                kfree(table);
 }
+#else /* CONFIG_SYSCTL */
+static int inline xfrm6_net_sysctl_init(struct net *net)
+{
+       return 0;
+}
+
+static void inline xfrm6_net_sysctl_exit(struct net *net)
+{
+}
+#endif
+
+static int __net_init xfrm6_net_init(struct net *net)
+{
+       int ret;
+
+       memcpy(&net->xfrm.xfrm6_dst_ops, &xfrm6_dst_ops_template,
+              sizeof(xfrm6_dst_ops_template));
+       ret = dst_entries_init(&net->xfrm.xfrm6_dst_ops);
+       if (ret)
+               return ret;
+
+       ret = xfrm6_net_sysctl_init(net);
+       if (ret)
+               dst_entries_destroy(&net->xfrm.xfrm6_dst_ops);
+
+       return ret;
+}
+
+static void __net_exit xfrm6_net_exit(struct net *net)
+{
+       xfrm6_net_sysctl_exit(net);
+       dst_entries_destroy(&net->xfrm.xfrm6_dst_ops);
+}
 
 static struct pernet_operations xfrm6_net_ops = {
        .init   = xfrm6_net_init,
        .exit   = xfrm6_net_exit,
 };
-#endif
 
 int __init xfrm6_init(void)
 {
        int ret;
 
-       dst_entries_init(&xfrm6_dst_ops);
-
        ret = xfrm6_policy_init();
-       if (ret) {
-               dst_entries_destroy(&xfrm6_dst_ops);
+       if (ret)
                goto out;
-       }
        ret = xfrm6_state_init();
        if (ret)
                goto out_policy;
@@ -391,9 +419,7 @@ int __init xfrm6_init(void)
        if (ret)
                goto out_state;
 
-#ifdef CONFIG_SYSCTL
        register_pernet_subsys(&xfrm6_net_ops);
-#endif
 out:
        return ret;
 out_state:
@@ -405,11 +431,8 @@ out_policy:
 
 void xfrm6_fini(void)
 {
-#ifdef CONFIG_SYSCTL
        unregister_pernet_subsys(&xfrm6_net_ops);
-#endif
        xfrm6_protocol_fini();
        xfrm6_policy_fini();
        xfrm6_state_fini();
-       dst_entries_destroy(&xfrm6_dst_ops);
 }
index e6aa48b5395c67e2600eed9482c97b9a626d01bd..923abd6b3064074f39f84644b2d3d1f068403f51 100644 (file)
@@ -1086,6 +1086,9 @@ static int irda_create(struct net *net, struct socket *sock, int protocol,
        struct sock *sk;
        struct irda_sock *self;
 
+       if (protocol < 0 || protocol > SK_PROTOCOL_MAX)
+               return -EINVAL;
+
        if (net != &init_net)
                return -EAFNOSUPPORT;
 
index fcb2752419c6635b06706d4cec542cb30ae3c85c..435608c4306d4afccf690eda945d4cb7eb962c6b 100644 (file)
@@ -1483,7 +1483,7 @@ unsigned int iucv_sock_poll(struct file *file, struct socket *sock,
        if (sock_writeable(sk) && iucv_below_msglim(sk))
                mask |= POLLOUT | POLLWRNORM | POLLWRBAND;
        else
-               set_bit(SOCK_ASYNC_NOSPACE, &sk->sk_socket->flags);
+               sk_set_bit(SOCKWQ_ASYNC_NOSPACE, sk);
 
        return mask;
 }
index aca38d8aed8e80b47ded2c81bbf346a39a678ce2..a2c8747d2936c305753224e7a786d67087b2cb1a 100644 (file)
@@ -486,6 +486,7 @@ static int l2tp_ip6_sendmsg(struct sock *sk, struct msghdr *msg, size_t len)
        DECLARE_SOCKADDR(struct sockaddr_l2tpip6 *, lsa, msg->msg_name);
        struct in6_addr *daddr, *final_p, final;
        struct ipv6_pinfo *np = inet6_sk(sk);
+       struct ipv6_txoptions *opt_to_free = NULL;
        struct ipv6_txoptions *opt = NULL;
        struct ip6_flowlabel *flowlabel = NULL;
        struct dst_entry *dst = NULL;
@@ -575,8 +576,10 @@ static int l2tp_ip6_sendmsg(struct sock *sk, struct msghdr *msg, size_t len)
                        opt = NULL;
        }
 
-       if (opt == NULL)
-               opt = np->opt;
+       if (!opt) {
+               opt = txopt_get(np);
+               opt_to_free = opt;
+       }
        if (flowlabel)
                opt = fl6_merge_options(&opt_space, flowlabel, opt);
        opt = ipv6_fixup_options(&opt_space, opt);
@@ -631,6 +634,7 @@ done:
        dst_release(dst);
 out:
        fl6_sock_release(flowlabel);
+       txopt_put(opt_to_free);
 
        return err < 0 ? err : len;
 
index a758eb84e8f057ac6518eef6c73bc8785dc7e746..ff757181b0a85c820e1acc53a088e95c78b87bff 100644 (file)
@@ -500,7 +500,7 @@ void ieee80211_tx_ba_session_handle_start(struct sta_info *sta, int tid)
        /* send AddBA request */
        ieee80211_send_addba_request(sdata, sta->sta.addr, tid,
                                     tid_tx->dialog_token, start_seq_num,
-                                    local->hw.max_tx_aggregation_subframes,
+                                    IEEE80211_MAX_AMPDU_BUF,
                                     tid_tx->timeout);
 }
 
@@ -926,6 +926,7 @@ void ieee80211_process_addba_resp(struct ieee80211_local *local,
        amsdu = capab & IEEE80211_ADDBA_PARAM_AMSDU_MASK;
        tid = (capab & IEEE80211_ADDBA_PARAM_TID_MASK) >> 2;
        buf_size = (capab & IEEE80211_ADDBA_PARAM_BUF_SIZE_MASK) >> 6;
+       buf_size = min(buf_size, local->hw.max_tx_aggregation_subframes);
 
        mutex_lock(&sta->ampdu_mlme.mtx);
 
index c2bd1b6a69224e4e07b6247c71077e2a79939dac..c12f348138acf7075297e5854b6e17391646d52b 100644 (file)
@@ -1169,8 +1169,7 @@ static int sta_apply_parameters(struct ieee80211_local *local,
                 * rc isn't initialized here yet, so ignore it
                 */
                __ieee80211_vht_handle_opmode(sdata, sta,
-                                             params->opmode_notif,
-                                             band, false);
+                                             params->opmode_notif, band);
        }
 
        if (ieee80211_vif_is_mesh(&sdata->vif))
@@ -3454,8 +3453,12 @@ static int ieee80211_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev,
                        goto out_unlock;
                }
        } else {
-               /* for cookie below */
-               ack_skb = skb;
+               /* Assign a dummy non-zero cookie, it's not sent to
+                * userspace in this case but we rely on its value
+                * internally in the need_offchan case to distinguish
+                * mgmt-tx from remain-on-channel.
+                */
+               *cookie = 0xffffffff;
        }
 
        if (!need_offchan) {
index d832bd59236be15c5a6bb86dbb1efc4547025f51..5322b4c716307f90710153bdb91e5425221b1742 100644 (file)
@@ -1709,10 +1709,10 @@ enum ieee80211_sta_rx_bandwidth ieee80211_sta_cur_vht_bw(struct sta_info *sta);
 void ieee80211_sta_set_rx_nss(struct sta_info *sta);
 u32 __ieee80211_vht_handle_opmode(struct ieee80211_sub_if_data *sdata,
                                   struct sta_info *sta, u8 opmode,
-                                  enum ieee80211_band band, bool nss_only);
+                                 enum ieee80211_band band);
 void ieee80211_vht_handle_opmode(struct ieee80211_sub_if_data *sdata,
                                 struct sta_info *sta, u8 opmode,
-                                enum ieee80211_band band, bool nss_only);
+                                enum ieee80211_band band);
 void ieee80211_apply_vhtcap_overrides(struct ieee80211_sub_if_data *sdata,
                                      struct ieee80211_sta_vht_cap *vht_cap);
 void ieee80211_get_vht_mask_from_cap(__le16 vht_cap,
index d0dc1bfaeec2d5440573d114b98e16099616f43d..c9e325d2e120c0f9c230dbace71c3c405b9216a3 100644 (file)
@@ -76,7 +76,8 @@ bool __ieee80211_recalc_txpower(struct ieee80211_sub_if_data *sdata)
 void ieee80211_recalc_txpower(struct ieee80211_sub_if_data *sdata,
                              bool update_bss)
 {
-       if (__ieee80211_recalc_txpower(sdata) || update_bss)
+       if (__ieee80211_recalc_txpower(sdata) ||
+           (update_bss && ieee80211_sdata_running(sdata)))
                ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_TXPOWER);
 }
 
@@ -1861,6 +1862,7 @@ void ieee80211_if_remove(struct ieee80211_sub_if_data *sdata)
                unregister_netdevice(sdata->dev);
        } else {
                cfg80211_unregister_wdev(&sdata->wdev);
+               ieee80211_teardown_sdata(sdata);
                kfree(sdata);
        }
 }
@@ -1870,7 +1872,6 @@ void ieee80211_sdata_stop(struct ieee80211_sub_if_data *sdata)
        if (WARN_ON_ONCE(!test_bit(SDATA_STATE_RUNNING, &sdata->state)))
                return;
        ieee80211_do_stop(sdata, true);
-       ieee80211_teardown_sdata(sdata);
 }
 
 void ieee80211_remove_interfaces(struct ieee80211_local *local)
index 858f6b1cb1494702bbc6e0d8d25f1b4d4b4d1470..175ffcf7fb06bfb5c9c1f95e2c17f42d666ee26f 100644 (file)
@@ -541,8 +541,7 @@ struct ieee80211_hw *ieee80211_alloc_hw_nm(size_t priv_data_len,
                           NL80211_FEATURE_HT_IBSS |
                           NL80211_FEATURE_VIF_TXPOWER |
                           NL80211_FEATURE_MAC_ON_CREATE |
-                          NL80211_FEATURE_USERSPACE_MPM |
-                          NL80211_FEATURE_FULL_AP_CLIENT_STATE;
+                          NL80211_FEATURE_USERSPACE_MPM;
 
        if (!ops->hw_scan)
                wiphy->features |= NL80211_FEATURE_LOW_PRIORITY_SCAN |
index b890e225a8f1b98681c53c764fc5252e5f2d5c8d..b3b44a5dd375c3a4bc391e29de21ae702a62418d 100644 (file)
@@ -779,10 +779,8 @@ void mesh_plink_broken(struct sta_info *sta)
 static void mesh_path_node_reclaim(struct rcu_head *rp)
 {
        struct mpath_node *node = container_of(rp, struct mpath_node, rcu);
-       struct ieee80211_sub_if_data *sdata = node->mpath->sdata;
 
        del_timer_sync(&node->mpath->timer);
-       atomic_dec(&sdata->u.mesh.mpaths);
        kfree(node->mpath);
        kfree(node);
 }
@@ -790,8 +788,9 @@ static void mesh_path_node_reclaim(struct rcu_head *rp)
 /* needs to be called with the corresponding hashwlock taken */
 static void __mesh_path_del(struct mesh_table *tbl, struct mpath_node *node)
 {
-       struct mesh_path *mpath;
-       mpath = node->mpath;
+       struct mesh_path *mpath = node->mpath;
+       struct ieee80211_sub_if_data *sdata = node->mpath->sdata;
+
        spin_lock(&mpath->state_lock);
        mpath->flags |= MESH_PATH_RESOLVING;
        if (mpath->is_gate)
@@ -799,6 +798,7 @@ static void __mesh_path_del(struct mesh_table *tbl, struct mpath_node *node)
        hlist_del_rcu(&node->list);
        call_rcu(&node->rcu, mesh_path_node_reclaim);
        spin_unlock(&mpath->state_lock);
+       atomic_dec(&sdata->u.mesh.mpaths);
        atomic_dec(&tbl->entries);
 }
 
index b140cc6651f4a7a650380965c0901b60c800746c..3aa04344942bfc06c75341abf841646745c58c7f 100644 (file)
@@ -1379,21 +1379,26 @@ static u32 ieee80211_handle_pwr_constr(struct ieee80211_sub_if_data *sdata,
         */
        if (has_80211h_pwr &&
            (!has_cisco_pwr || pwr_level_80211h <= pwr_level_cisco)) {
+               new_ap_level = pwr_level_80211h;
+
+               if (sdata->ap_power_level == new_ap_level)
+                       return 0;
+
                sdata_dbg(sdata,
                          "Limiting TX power to %d (%d - %d) dBm as advertised by %pM\n",
                          pwr_level_80211h, chan_pwr, pwr_reduction_80211h,
                          sdata->u.mgd.bssid);
-               new_ap_level = pwr_level_80211h;
        } else {  /* has_cisco_pwr is always true here. */
+               new_ap_level = pwr_level_cisco;
+
+               if (sdata->ap_power_level == new_ap_level)
+                       return 0;
+
                sdata_dbg(sdata,
                          "Limiting TX power to %d dBm as advertised by %pM\n",
                          pwr_level_cisco, sdata->u.mgd.bssid);
-               new_ap_level = pwr_level_cisco;
        }
 
-       if (sdata->ap_power_level == new_ap_level)
-               return 0;
-
        sdata->ap_power_level = new_ap_level;
        if (__ieee80211_recalc_txpower(sdata))
                return BSS_CHANGED_TXPOWER;
@@ -3575,7 +3580,7 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata,
 
        if (sta && elems.opmode_notif)
                ieee80211_vht_handle_opmode(sdata, sta, *elems.opmode_notif,
-                                           rx_status->band, true);
+                                           rx_status->band);
        mutex_unlock(&local->sta_mtx);
 
        changed |= ieee80211_handle_pwr_constr(sdata, chan, mgmt,
index 8bae5de0dc44299146993df3581a951078eed733..82af407fea7a094db5f08e6426ae670a4cab3729 100644 (file)
@@ -2736,8 +2736,7 @@ ieee80211_rx_h_action(struct ieee80211_rx_data *rx)
                        opmode = mgmt->u.action.u.vht_opmode_notif.operating_mode;
 
                        ieee80211_vht_handle_opmode(rx->sdata, rx->sta,
-                                                   opmode, status->band,
-                                                   false);
+                                                   opmode, status->band);
                        goto handled;
                }
                default:
index 4aeca4b0c3cb426ba65b23d4a8ebc756e7a826a4..a413e52f7691418116d928f684a0fc27b308c2d6 100644 (file)
@@ -597,8 +597,8 @@ static int __ieee80211_start_scan(struct ieee80211_sub_if_data *sdata,
                /* We need to ensure power level is at max for scanning. */
                ieee80211_hw_config(local, 0);
 
-               if ((req->channels[0]->flags &
-                    IEEE80211_CHAN_NO_IR) ||
+               if ((req->channels[0]->flags & (IEEE80211_CHAN_NO_IR |
+                                               IEEE80211_CHAN_RADAR)) ||
                    !req->n_ssids) {
                        next_delay = IEEE80211_PASSIVE_CHANNEL_TIME;
                } else {
@@ -645,7 +645,7 @@ ieee80211_scan_get_channel_time(struct ieee80211_channel *chan)
         * TODO: channel switching also consumes quite some time,
         * add that delay as well to get a better estimation
         */
-       if (chan->flags & IEEE80211_CHAN_NO_IR)
+       if (chan->flags & (IEEE80211_CHAN_NO_IR | IEEE80211_CHAN_RADAR))
                return IEEE80211_PASSIVE_CHANNEL_TIME;
        return IEEE80211_PROBE_DELAY + IEEE80211_CHANNEL_TIME;
 }
@@ -777,7 +777,8 @@ static void ieee80211_scan_state_set_channel(struct ieee80211_local *local,
         *
         * In any case, it is not necessary for a passive scan.
         */
-       if (chan->flags & IEEE80211_CHAN_NO_IR || !scan_req->n_ssids) {
+       if ((chan->flags & (IEEE80211_CHAN_NO_IR | IEEE80211_CHAN_RADAR)) ||
+           !scan_req->n_ssids) {
                *next_delay = IEEE80211_PASSIVE_CHANNEL_TIME;
                local->next_scan_state = SCAN_DECISION;
                return;
index 74058020b7d6154c1ea1613e9a8a9775789736fa..33344f5a66a85e8a4c0842807249aee3e9d3d02e 100644 (file)
@@ -1641,6 +1641,29 @@ void ieee80211_stop_device(struct ieee80211_local *local)
        drv_stop(local);
 }
 
+static void ieee80211_flush_completed_scan(struct ieee80211_local *local,
+                                          bool aborted)
+{
+       /* It's possible that we don't handle the scan completion in
+        * time during suspend, so if it's still marked as completed
+        * here, queue the work and flush it to clean things up.
+        * Instead of calling the worker function directly here, we
+        * really queue it to avoid potential races with other flows
+        * scheduling the same work.
+        */
+       if (test_bit(SCAN_COMPLETED, &local->scanning)) {
+               /* If coming from reconfiguration failure, abort the scan so
+                * we don't attempt to continue a partial HW scan - which is
+                * possible otherwise if (e.g.) the 2.4 GHz portion was the
+                * completed scan, and a 5 GHz portion is still pending.
+                */
+               if (aborted)
+                       set_bit(SCAN_ABORTED, &local->scanning);
+               ieee80211_queue_delayed_work(&local->hw, &local->scan_work, 0);
+               flush_delayed_work(&local->scan_work);
+       }
+}
+
 static void ieee80211_handle_reconfig_failure(struct ieee80211_local *local)
 {
        struct ieee80211_sub_if_data *sdata;
@@ -1660,6 +1683,8 @@ static void ieee80211_handle_reconfig_failure(struct ieee80211_local *local)
        local->suspended = false;
        local->in_reconfig = false;
 
+       ieee80211_flush_completed_scan(local, true);
+
        /* scheduled scan clearly can't be running any more, but tell
         * cfg80211 and clear local state
         */
@@ -1698,6 +1723,27 @@ static void ieee80211_assign_chanctx(struct ieee80211_local *local,
        mutex_unlock(&local->chanctx_mtx);
 }
 
+static void ieee80211_reconfig_stations(struct ieee80211_sub_if_data *sdata)
+{
+       struct ieee80211_local *local = sdata->local;
+       struct sta_info *sta;
+
+       /* add STAs back */
+       mutex_lock(&local->sta_mtx);
+       list_for_each_entry(sta, &local->sta_list, list) {
+               enum ieee80211_sta_state state;
+
+               if (!sta->uploaded || sta->sdata != sdata)
+                       continue;
+
+               for (state = IEEE80211_STA_NOTEXIST;
+                    state < sta->sta_state; state++)
+                       WARN_ON(drv_sta_state(local, sta->sdata, sta, state,
+                                             state + 1));
+       }
+       mutex_unlock(&local->sta_mtx);
+}
+
 int ieee80211_reconfig(struct ieee80211_local *local)
 {
        struct ieee80211_hw *hw = &local->hw;
@@ -1833,50 +1879,11 @@ int ieee80211_reconfig(struct ieee80211_local *local)
                                WARN_ON(drv_add_chanctx(local, ctx));
                mutex_unlock(&local->chanctx_mtx);
 
-               list_for_each_entry(sdata, &local->interfaces, list) {
-                       if (!ieee80211_sdata_running(sdata))
-                               continue;
-                       ieee80211_assign_chanctx(local, sdata);
-               }
-
                sdata = rtnl_dereference(local->monitor_sdata);
                if (sdata && ieee80211_sdata_running(sdata))
                        ieee80211_assign_chanctx(local, sdata);
        }
 
-       /* add STAs back */
-       mutex_lock(&local->sta_mtx);
-       list_for_each_entry(sta, &local->sta_list, list) {
-               enum ieee80211_sta_state state;
-
-               if (!sta->uploaded)
-                       continue;
-
-               /* AP-mode stations will be added later */
-               if (sta->sdata->vif.type == NL80211_IFTYPE_AP)
-                       continue;
-
-               for (state = IEEE80211_STA_NOTEXIST;
-                    state < sta->sta_state; state++)
-                       WARN_ON(drv_sta_state(local, sta->sdata, sta, state,
-                                             state + 1));
-       }
-       mutex_unlock(&local->sta_mtx);
-
-       /* reconfigure tx conf */
-       if (hw->queues >= IEEE80211_NUM_ACS) {
-               list_for_each_entry(sdata, &local->interfaces, list) {
-                       if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN ||
-                           sdata->vif.type == NL80211_IFTYPE_MONITOR ||
-                           !ieee80211_sdata_running(sdata))
-                               continue;
-
-                       for (i = 0; i < IEEE80211_NUM_ACS; i++)
-                               drv_conf_tx(local, sdata, i,
-                                           &sdata->tx_conf[i]);
-               }
-       }
-
        /* reconfigure hardware */
        ieee80211_hw_config(local, ~0);
 
@@ -1889,6 +1896,22 @@ int ieee80211_reconfig(struct ieee80211_local *local)
                if (!ieee80211_sdata_running(sdata))
                        continue;
 
+               ieee80211_assign_chanctx(local, sdata);
+
+               switch (sdata->vif.type) {
+               case NL80211_IFTYPE_AP_VLAN:
+               case NL80211_IFTYPE_MONITOR:
+                       break;
+               default:
+                       ieee80211_reconfig_stations(sdata);
+                       /* fall through */
+               case NL80211_IFTYPE_AP: /* AP stations are handled later */
+                       for (i = 0; i < IEEE80211_NUM_ACS; i++)
+                               drv_conf_tx(local, sdata, i,
+                                           &sdata->tx_conf[i]);
+                       break;
+               }
+
                /* common change flags for all interface types */
                changed = BSS_CHANGED_ERP_CTS_PROT |
                          BSS_CHANGED_ERP_PREAMBLE |
@@ -2074,17 +2097,7 @@ int ieee80211_reconfig(struct ieee80211_local *local)
        mb();
        local->resuming = false;
 
-       /* It's possible that we don't handle the scan completion in
-        * time during suspend, so if it's still marked as completed
-        * here, queue the work and flush it to clean things up.
-        * Instead of calling the worker function directly here, we
-        * really queue it to avoid potential races with other flows
-        * scheduling the same work.
-        */
-       if (test_bit(SCAN_COMPLETED, &local->scanning)) {
-               ieee80211_queue_delayed_work(&local->hw, &local->scan_work, 0);
-               flush_delayed_work(&local->scan_work);
-       }
+       ieee80211_flush_completed_scan(local, false);
 
        if (local->open_count && !reconfig_due_to_wowlan)
                drv_reconfig_complete(local, IEEE80211_RECONFIG_TYPE_SUSPEND);
index ff1c798921a6acc90181923456cf92bed0973f61..c38b2f07a919e20dc22363fe80911f5f5a0b004f 100644 (file)
@@ -378,7 +378,7 @@ void ieee80211_sta_set_rx_nss(struct sta_info *sta)
 
 u32 __ieee80211_vht_handle_opmode(struct ieee80211_sub_if_data *sdata,
                                  struct sta_info *sta, u8 opmode,
-                                 enum ieee80211_band band, bool nss_only)
+                                 enum ieee80211_band band)
 {
        struct ieee80211_local *local = sdata->local;
        struct ieee80211_supported_band *sband;
@@ -401,9 +401,6 @@ u32 __ieee80211_vht_handle_opmode(struct ieee80211_sub_if_data *sdata,
                changed |= IEEE80211_RC_NSS_CHANGED;
        }
 
-       if (nss_only)
-               return changed;
-
        switch (opmode & IEEE80211_OPMODE_NOTIF_CHANWIDTH_MASK) {
        case IEEE80211_OPMODE_NOTIF_CHANWIDTH_20MHZ:
                sta->cur_max_bandwidth = IEEE80211_STA_RX_BW_20;
@@ -430,13 +427,12 @@ u32 __ieee80211_vht_handle_opmode(struct ieee80211_sub_if_data *sdata,
 
 void ieee80211_vht_handle_opmode(struct ieee80211_sub_if_data *sdata,
                                 struct sta_info *sta, u8 opmode,
-                                enum ieee80211_band band, bool nss_only)
+                                enum ieee80211_band band)
 {
        struct ieee80211_local *local = sdata->local;
        struct ieee80211_supported_band *sband = local->hw.wiphy->bands[band];
 
-       u32 changed = __ieee80211_vht_handle_opmode(sdata, sta, opmode,
-                                                   band, nss_only);
+       u32 changed = __ieee80211_vht_handle_opmode(sdata, sta, opmode, band);
 
        if (changed > 0)
                rate_control_rate_update(local, sband, sta, changed);
index c70d750148b66759ce47525c6f6b348c2e69efaa..c32fc411a911a414db2d0c1e141cb76093079d33 100644 (file)
@@ -27,6 +27,8 @@
  */
 #define MAX_MP_SELECT_LABELS 4
 
+#define MPLS_NEIGH_TABLE_UNSPEC (NEIGH_LINK_TABLE + 1)
+
 static int zero = 0;
 static int label_limit = (1 << 20) - 1;
 
@@ -317,7 +319,13 @@ static int mpls_forward(struct sk_buff *skb, struct net_device *dev,
                }
        }
 
-       err = neigh_xmit(nh->nh_via_table, out_dev, mpls_nh_via(rt, nh), skb);
+       /* If via wasn't specified then send out using device address */
+       if (nh->nh_via_table == MPLS_NEIGH_TABLE_UNSPEC)
+               err = neigh_xmit(NEIGH_LINK_TABLE, out_dev,
+                                out_dev->dev_addr, skb);
+       else
+               err = neigh_xmit(nh->nh_via_table, out_dev,
+                                mpls_nh_via(rt, nh), skb);
        if (err)
                net_dbg_ratelimited("%s: packet transmission failed: %d\n",
                                    __func__, err);
@@ -534,6 +542,10 @@ static int mpls_nh_assign_dev(struct net *net, struct mpls_route *rt,
        if (!mpls_dev_get(dev))
                goto errout;
 
+       if ((nh->nh_via_table == NEIGH_LINK_TABLE) &&
+           (dev->addr_len != nh->nh_via_alen))
+               goto errout;
+
        RCU_INIT_POINTER(nh->nh_dev, dev);
 
        return 0;
@@ -592,10 +604,14 @@ static int mpls_nh_build(struct net *net, struct mpls_route *rt,
                        goto errout;
        }
 
-       err = nla_get_via(via, &nh->nh_via_alen, &nh->nh_via_table,
-                         __mpls_nh_via(rt, nh));
-       if (err)
-               goto errout;
+       if (via) {
+               err = nla_get_via(via, &nh->nh_via_alen, &nh->nh_via_table,
+                                 __mpls_nh_via(rt, nh));
+               if (err)
+                       goto errout;
+       } else {
+               nh->nh_via_table = MPLS_NEIGH_TABLE_UNSPEC;
+       }
 
        err = mpls_nh_assign_dev(net, rt, nh, oif);
        if (err)
@@ -677,9 +693,6 @@ static int mpls_nh_build_multi(struct mpls_route_config *cfg,
                        nla_newdst = nla_find(attrs, attrlen, RTA_NEWDST);
                }
 
-               if (!nla_via)
-                       goto errout;
-
                err = mpls_nh_build(cfg->rc_nlinfo.nl_net, rt, nh,
                                    rtnh->rtnh_ifindex, nla_via,
                                    nla_newdst);
@@ -1118,6 +1131,7 @@ static int rtm_to_route_config(struct sk_buff *skb,  struct nlmsghdr *nlh,
 
        cfg->rc_label           = LABEL_NOT_SPECIFIED;
        cfg->rc_protocol        = rtm->rtm_protocol;
+       cfg->rc_via_table       = MPLS_NEIGH_TABLE_UNSPEC;
        cfg->rc_nlflags         = nlh->nlmsg_flags;
        cfg->rc_nlinfo.portid   = NETLINK_CB(skb).portid;
        cfg->rc_nlinfo.nlh      = nlh;
@@ -1231,7 +1245,8 @@ static int mpls_dump_route(struct sk_buff *skb, u32 portid, u32 seq, int event,
                    nla_put_labels(skb, RTA_NEWDST, nh->nh_labels,
                                   nh->nh_label))
                        goto nla_put_failure;
-               if (nla_put_via(skb, nh->nh_via_table, mpls_nh_via(rt, nh),
+               if (nh->nh_via_table != MPLS_NEIGH_TABLE_UNSPEC &&
+                   nla_put_via(skb, nh->nh_via_table, mpls_nh_via(rt, nh),
                                nh->nh_via_alen))
                        goto nla_put_failure;
                dev = rtnl_dereference(nh->nh_dev);
@@ -1257,7 +1272,8 @@ static int mpls_dump_route(struct sk_buff *skb, u32 portid, u32 seq, int event,
                                                            nh->nh_labels,
                                                            nh->nh_label))
                                goto nla_put_failure;
-                       if (nla_put_via(skb, nh->nh_via_table,
+                       if (nh->nh_via_table != MPLS_NEIGH_TABLE_UNSPEC &&
+                           nla_put_via(skb, nh->nh_via_table,
                                        mpls_nh_via(rt, nh),
                                        nh->nh_via_alen))
                                goto nla_put_failure;
@@ -1319,7 +1335,8 @@ static inline size_t lfib_nlmsg_size(struct mpls_route *rt)
 
                if (nh->nh_dev)
                        payload += nla_total_size(4); /* RTA_OIF */
-               payload += nla_total_size(2 + nh->nh_via_alen); /* RTA_VIA */
+               if (nh->nh_via_table != MPLS_NEIGH_TABLE_UNSPEC) /* RTA_VIA */
+                       payload += nla_total_size(2 + nh->nh_via_alen);
                if (nh->nh_labels) /* RTA_NEWDST */
                        payload += nla_total_size(nh->nh_labels * 4);
        } else {
@@ -1328,7 +1345,9 @@ static inline size_t lfib_nlmsg_size(struct mpls_route *rt)
 
                for_nexthops(rt) {
                        nhsize += nla_total_size(sizeof(struct rtnexthop));
-                       nhsize += nla_total_size(2 + nh->nh_via_alen);
+                       /* RTA_VIA */
+                       if (nh->nh_via_table != MPLS_NEIGH_TABLE_UNSPEC)
+                               nhsize += nla_total_size(2 + nh->nh_via_alen);
                        if (nh->nh_labels)
                                nhsize += nla_total_size(nh->nh_labels * 4);
                } endfor_nexthops(rt);
index 67591aef9cae6fb203ef802272baad6e5b191000..64afd3d0b14407c252a766ab2280a30452a684c5 100644 (file)
@@ -54,10 +54,10 @@ int mpls_output(struct net *net, struct sock *sk, struct sk_buff *skb)
        unsigned int ttl;
 
        /* Obtain the ttl */
-       if (skb->protocol == htons(ETH_P_IP)) {
+       if (dst->ops->family == AF_INET) {
                ttl = ip_hdr(skb)->ttl;
                rt = (struct rtable *)dst;
-       } else if (skb->protocol == htons(ETH_P_IPV6)) {
+       } else if (dst->ops->family == AF_INET6) {
                ttl = ipv6_hdr(skb)->hop_limit;
                rt6 = (struct rt6_info *)dst;
        } else {
index e22349ea725605a05ce03cb3701142856daf420c..4692782b528053a408b15f0daccaf6f6cb3fc10e 100644 (file)
@@ -869,7 +869,7 @@ config NETFILTER_XT_TARGET_TEE
        depends on IPV6 || IPV6=n
        depends on !NF_CONNTRACK || NF_CONNTRACK
        select NF_DUP_IPV4
-       select NF_DUP_IPV6 if IP6_NF_IPTABLES
+       select NF_DUP_IPV6 if IP6_NF_IPTABLES != n
        ---help---
        This option adds a "TEE" target with which a packet can be cloned and
        this clone be rerouted to another nexthop.
@@ -882,7 +882,7 @@ config NETFILTER_XT_TARGET_TPROXY
        depends on IP6_NF_IPTABLES || IP6_NF_IPTABLES=n
        depends on IP_NF_MANGLE
        select NF_DEFRAG_IPV4
-       select NF_DEFRAG_IPV6 if IP6_NF_IPTABLES
+       select NF_DEFRAG_IPV6 if IP6_NF_IPTABLES != n
        help
          This option adds a `TPROXY' target, which is somewhat similar to
          REDIRECT.  It can only be used in the mangle table and is useful
@@ -1375,7 +1375,7 @@ config NETFILTER_XT_MATCH_SOCKET
        depends on IPV6 || IPV6=n
        depends on IP6_NF_IPTABLES || IP6_NF_IPTABLES=n
        select NF_DEFRAG_IPV4
-       select NF_DEFRAG_IPV6 if IP6_NF_IPTABLES
+       select NF_DEFRAG_IPV6 if IP6_NF_IPTABLES != n
        help
          This option adds a `socket' match, which can be used to match
          packets for which a TCP or UDP socket lookup finds a valid socket.
index d05e759ed0fafe62ef299e6f097f0d18f08ec567..b0bc475f641e3b2c808f78f5be54283de6866d25 100644 (file)
@@ -33,7 +33,7 @@
 #define mtype_gc               IPSET_TOKEN(MTYPE, _gc)
 #define mtype                  MTYPE
 
-#define get_ext(set, map, id)  ((map)->extensions + (set)->dsize * (id))
+#define get_ext(set, map, id)  ((map)->extensions + ((set)->dsize * (id)))
 
 static void
 mtype_gc_init(struct ip_set *set, void (*gc)(unsigned long ul_set))
@@ -67,12 +67,9 @@ mtype_destroy(struct ip_set *set)
                del_timer_sync(&map->gc);
 
        ip_set_free(map->members);
-       if (set->dsize) {
-               if (set->extensions & IPSET_EXT_DESTROY)
-                       mtype_ext_cleanup(set);
-               ip_set_free(map->extensions);
-       }
-       kfree(map);
+       if (set->dsize && set->extensions & IPSET_EXT_DESTROY)
+               mtype_ext_cleanup(set);
+       ip_set_free(map);
 
        set->data = NULL;
 }
@@ -92,16 +89,14 @@ mtype_head(struct ip_set *set, struct sk_buff *skb)
 {
        const struct mtype *map = set->data;
        struct nlattr *nested;
+       size_t memsize = sizeof(*map) + map->memsize;
 
        nested = ipset_nest_start(skb, IPSET_ATTR_DATA);
        if (!nested)
                goto nla_put_failure;
        if (mtype_do_head(skb, map) ||
            nla_put_net32(skb, IPSET_ATTR_REFERENCES, htonl(set->ref - 1)) ||
-           nla_put_net32(skb, IPSET_ATTR_MEMSIZE,
-                         htonl(sizeof(*map) +
-                               map->memsize +
-                               set->dsize * map->elements)))
+           nla_put_net32(skb, IPSET_ATTR_MEMSIZE, htonl(memsize)))
                goto nla_put_failure;
        if (unlikely(ip_set_put_flags(skb, set)))
                goto nla_put_failure;
index 64a5643344180d813e3b3fc914c1b1c93dcd58be..4783efff0bde6b7c70707c8153563669308d995a 100644 (file)
@@ -41,7 +41,6 @@ MODULE_ALIAS("ip_set_bitmap:ip");
 /* Type structure */
 struct bitmap_ip {
        void *members;          /* the set members */
-       void *extensions;       /* data extensions */
        u32 first_ip;           /* host byte order, included in range */
        u32 last_ip;            /* host byte order, included in range */
        u32 elements;           /* number of max elements in the set */
@@ -49,6 +48,8 @@ struct bitmap_ip {
        size_t memsize;         /* members size */
        u8 netmask;             /* subnet netmask */
        struct timer_list gc;   /* garbage collection */
+       unsigned char extensions[0]     /* data extensions */
+               __aligned(__alignof__(u64));
 };
 
 /* ADT structure for generic function args */
@@ -224,13 +225,6 @@ init_map_ip(struct ip_set *set, struct bitmap_ip *map,
        map->members = ip_set_alloc(map->memsize);
        if (!map->members)
                return false;
-       if (set->dsize) {
-               map->extensions = ip_set_alloc(set->dsize * elements);
-               if (!map->extensions) {
-                       kfree(map->members);
-                       return false;
-               }
-       }
        map->first_ip = first_ip;
        map->last_ip = last_ip;
        map->elements = elements;
@@ -316,13 +310,13 @@ bitmap_ip_create(struct net *net, struct ip_set *set, struct nlattr *tb[],
        pr_debug("hosts %u, elements %llu\n",
                 hosts, (unsigned long long)elements);
 
-       map = kzalloc(sizeof(*map), GFP_KERNEL);
+       set->dsize = ip_set_elem_len(set, tb, 0, 0);
+       map = ip_set_alloc(sizeof(*map) + elements * set->dsize);
        if (!map)
                return -ENOMEM;
 
        map->memsize = bitmap_bytes(0, elements - 1);
        set->variant = &bitmap_ip;
-       set->dsize = ip_set_elem_len(set, tb, 0);
        if (!init_map_ip(set, map, first_ip, last_ip,
                         elements, hosts, netmask)) {
                kfree(map);
index 1430535118fb0d9c23c1f05c72e75034c1953cd7..29dde208381dac6cdfca67094dc4fc07bc85b40c 100644 (file)
@@ -47,24 +47,26 @@ enum {
 /* Type structure */
 struct bitmap_ipmac {
        void *members;          /* the set members */
-       void *extensions;       /* MAC + data extensions */
        u32 first_ip;           /* host byte order, included in range */
        u32 last_ip;            /* host byte order, included in range */
        u32 elements;           /* number of max elements in the set */
        size_t memsize;         /* members size */
        struct timer_list gc;   /* garbage collector */
+       unsigned char extensions[0]     /* MAC + data extensions */
+               __aligned(__alignof__(u64));
 };
 
 /* ADT structure for generic function args */
 struct bitmap_ipmac_adt_elem {
+       unsigned char ether[ETH_ALEN] __aligned(2);
        u16 id;
-       unsigned char *ether;
+       u16 add_mac;
 };
 
 struct bitmap_ipmac_elem {
        unsigned char ether[ETH_ALEN];
        unsigned char filled;
-} __attribute__ ((aligned));
+} __aligned(__alignof__(u64));
 
 static inline u32
 ip_to_id(const struct bitmap_ipmac *m, u32 ip)
@@ -72,11 +74,11 @@ ip_to_id(const struct bitmap_ipmac *m, u32 ip)
        return ip - m->first_ip;
 }
 
-static inline struct bitmap_ipmac_elem *
-get_elem(void *extensions, u16 id, size_t dsize)
-{
-       return (struct bitmap_ipmac_elem *)(extensions + id * dsize);
-}
+#define get_elem(extensions, id, dsize)                \
+       (struct bitmap_ipmac_elem *)(extensions + (id) * (dsize))
+
+#define get_const_elem(extensions, id, dsize)  \
+       (const struct bitmap_ipmac_elem *)(extensions + (id) * (dsize))
 
 /* Common functions */
 
@@ -88,10 +90,9 @@ bitmap_ipmac_do_test(const struct bitmap_ipmac_adt_elem *e,
 
        if (!test_bit(e->id, map->members))
                return 0;
-       elem = get_elem(map->extensions, e->id, dsize);
-       if (elem->filled == MAC_FILLED)
-               return !e->ether ||
-                      ether_addr_equal(e->ether, elem->ether);
+       elem = get_const_elem(map->extensions, e->id, dsize);
+       if (e->add_mac && elem->filled == MAC_FILLED)
+               return ether_addr_equal(e->ether, elem->ether);
        /* Trigger kernel to fill out the ethernet address */
        return -EAGAIN;
 }
@@ -103,7 +104,7 @@ bitmap_ipmac_gc_test(u16 id, const struct bitmap_ipmac *map, size_t dsize)
 
        if (!test_bit(id, map->members))
                return 0;
-       elem = get_elem(map->extensions, id, dsize);
+       elem = get_const_elem(map->extensions, id, dsize);
        /* Timer not started for the incomplete elements */
        return elem->filled == MAC_FILLED;
 }
@@ -133,7 +134,7 @@ bitmap_ipmac_add_timeout(unsigned long *timeout,
                 * and we can reuse it later when MAC is filled out,
                 * possibly by the kernel
                 */
-               if (e->ether)
+               if (e->add_mac)
                        ip_set_timeout_set(timeout, t);
                else
                        *timeout = t;
@@ -150,7 +151,7 @@ bitmap_ipmac_do_add(const struct bitmap_ipmac_adt_elem *e,
        elem = get_elem(map->extensions, e->id, dsize);
        if (test_bit(e->id, map->members)) {
                if (elem->filled == MAC_FILLED) {
-                       if (e->ether &&
+                       if (e->add_mac &&
                            (flags & IPSET_FLAG_EXIST) &&
                            !ether_addr_equal(e->ether, elem->ether)) {
                                /* memcpy isn't atomic */
@@ -159,7 +160,7 @@ bitmap_ipmac_do_add(const struct bitmap_ipmac_adt_elem *e,
                                ether_addr_copy(elem->ether, e->ether);
                        }
                        return IPSET_ADD_FAILED;
-               } else if (!e->ether)
+               } else if (!e->add_mac)
                        /* Already added without ethernet address */
                        return IPSET_ADD_FAILED;
                /* Fill the MAC address and trigger the timer activation */
@@ -168,7 +169,7 @@ bitmap_ipmac_do_add(const struct bitmap_ipmac_adt_elem *e,
                ether_addr_copy(elem->ether, e->ether);
                elem->filled = MAC_FILLED;
                return IPSET_ADD_START_STORED_TIMEOUT;
-       } else if (e->ether) {
+       } else if (e->add_mac) {
                /* We can store MAC too */
                ether_addr_copy(elem->ether, e->ether);
                elem->filled = MAC_FILLED;
@@ -191,7 +192,7 @@ bitmap_ipmac_do_list(struct sk_buff *skb, const struct bitmap_ipmac *map,
                     u32 id, size_t dsize)
 {
        const struct bitmap_ipmac_elem *elem =
-               get_elem(map->extensions, id, dsize);
+               get_const_elem(map->extensions, id, dsize);
 
        return nla_put_ipaddr4(skb, IPSET_ATTR_IP,
                               htonl(map->first_ip + id)) ||
@@ -213,7 +214,7 @@ bitmap_ipmac_kadt(struct ip_set *set, const struct sk_buff *skb,
 {
        struct bitmap_ipmac *map = set->data;
        ipset_adtfn adtfn = set->variant->adt[adt];
-       struct bitmap_ipmac_adt_elem e = { .id = 0 };
+       struct bitmap_ipmac_adt_elem e = { .id = 0, .add_mac = 1 };
        struct ip_set_ext ext = IP_SET_INIT_KEXT(skb, opt, set);
        u32 ip;
 
@@ -231,7 +232,7 @@ bitmap_ipmac_kadt(struct ip_set *set, const struct sk_buff *skb,
                return -EINVAL;
 
        e.id = ip_to_id(map, ip);
-       e.ether = eth_hdr(skb)->h_source;
+       memcpy(e.ether, eth_hdr(skb)->h_source, ETH_ALEN);
 
        return adtfn(set, &e, &ext, &opt->ext, opt->cmdflags);
 }
@@ -265,11 +266,10 @@ bitmap_ipmac_uadt(struct ip_set *set, struct nlattr *tb[],
                return -IPSET_ERR_BITMAP_RANGE;
 
        e.id = ip_to_id(map, ip);
-       if (tb[IPSET_ATTR_ETHER])
-               e.ether = nla_data(tb[IPSET_ATTR_ETHER]);
-       else
-               e.ether = NULL;
-
+       if (tb[IPSET_ATTR_ETHER]) {
+               memcpy(e.ether, nla_data(tb[IPSET_ATTR_ETHER]), ETH_ALEN);
+               e.add_mac = 1;
+       }
        ret = adtfn(set, &e, &ext, &ext, flags);
 
        return ip_set_eexist(ret, flags) ? 0 : ret;
@@ -300,13 +300,6 @@ init_map_ipmac(struct ip_set *set, struct bitmap_ipmac *map,
        map->members = ip_set_alloc(map->memsize);
        if (!map->members)
                return false;
-       if (set->dsize) {
-               map->extensions = ip_set_alloc(set->dsize * elements);
-               if (!map->extensions) {
-                       kfree(map->members);
-                       return false;
-               }
-       }
        map->first_ip = first_ip;
        map->last_ip = last_ip;
        map->elements = elements;
@@ -361,14 +354,15 @@ bitmap_ipmac_create(struct net *net, struct ip_set *set, struct nlattr *tb[],
        if (elements > IPSET_BITMAP_MAX_RANGE + 1)
                return -IPSET_ERR_BITMAP_RANGE_SIZE;
 
-       map = kzalloc(sizeof(*map), GFP_KERNEL);
+       set->dsize = ip_set_elem_len(set, tb,
+                                    sizeof(struct bitmap_ipmac_elem),
+                                    __alignof__(struct bitmap_ipmac_elem));
+       map = ip_set_alloc(sizeof(*map) + elements * set->dsize);
        if (!map)
                return -ENOMEM;
 
        map->memsize = bitmap_bytes(0, elements - 1);
        set->variant = &bitmap_ipmac;
-       set->dsize = ip_set_elem_len(set, tb,
-                                    sizeof(struct bitmap_ipmac_elem));
        if (!init_map_ipmac(set, map, first_ip, last_ip, elements)) {
                kfree(map);
                return -ENOMEM;
index 5338ccd5da461eea08142479fd8315a208fc50c4..7f0c733358a428225e15afe611aad1edcd52812a 100644 (file)
@@ -35,12 +35,13 @@ MODULE_ALIAS("ip_set_bitmap:port");
 /* Type structure */
 struct bitmap_port {
        void *members;          /* the set members */
-       void *extensions;       /* data extensions */
        u16 first_port;         /* host byte order, included in range */
        u16 last_port;          /* host byte order, included in range */
        u32 elements;           /* number of max elements in the set */
        size_t memsize;         /* members size */
        struct timer_list gc;   /* garbage collection */
+       unsigned char extensions[0]     /* data extensions */
+               __aligned(__alignof__(u64));
 };
 
 /* ADT structure for generic function args */
@@ -209,13 +210,6 @@ init_map_port(struct ip_set *set, struct bitmap_port *map,
        map->members = ip_set_alloc(map->memsize);
        if (!map->members)
                return false;
-       if (set->dsize) {
-               map->extensions = ip_set_alloc(set->dsize * map->elements);
-               if (!map->extensions) {
-                       kfree(map->members);
-                       return false;
-               }
-       }
        map->first_port = first_port;
        map->last_port = last_port;
        set->timeout = IPSET_NO_TIMEOUT;
@@ -232,6 +226,7 @@ bitmap_port_create(struct net *net, struct ip_set *set, struct nlattr *tb[],
 {
        struct bitmap_port *map;
        u16 first_port, last_port;
+       u32 elements;
 
        if (unlikely(!ip_set_attr_netorder(tb, IPSET_ATTR_PORT) ||
                     !ip_set_attr_netorder(tb, IPSET_ATTR_PORT_TO) ||
@@ -248,14 +243,15 @@ bitmap_port_create(struct net *net, struct ip_set *set, struct nlattr *tb[],
                last_port = tmp;
        }
 
-       map = kzalloc(sizeof(*map), GFP_KERNEL);
+       elements = last_port - first_port + 1;
+       set->dsize = ip_set_elem_len(set, tb, 0, 0);
+       map = ip_set_alloc(sizeof(*map) + elements * set->dsize);
        if (!map)
                return -ENOMEM;
 
-       map->elements = last_port - first_port + 1;
+       map->elements = elements;
        map->memsize = bitmap_bytes(0, map->elements);
        set->variant = &bitmap_port;
-       set->dsize = ip_set_elem_len(set, tb, 0);
        if (!init_map_port(set, map, first_port, last_port)) {
                kfree(map);
                return -ENOMEM;
index 69ab9c2634e1566fac04e9509cf4c51e64ea36e8..54f3d7cb23e6efe4a3d9c4084df66cca76a44b03 100644 (file)
@@ -364,25 +364,27 @@ add_extension(enum ip_set_ext_id id, u32 flags, struct nlattr *tb[])
 }
 
 size_t
-ip_set_elem_len(struct ip_set *set, struct nlattr *tb[], size_t len)
+ip_set_elem_len(struct ip_set *set, struct nlattr *tb[], size_t len,
+               size_t align)
 {
        enum ip_set_ext_id id;
-       size_t offset = len;
        u32 cadt_flags = 0;
 
        if (tb[IPSET_ATTR_CADT_FLAGS])
                cadt_flags = ip_set_get_h32(tb[IPSET_ATTR_CADT_FLAGS]);
        if (cadt_flags & IPSET_FLAG_WITH_FORCEADD)
                set->flags |= IPSET_CREATE_FLAG_FORCEADD;
+       if (!align)
+               align = 1;
        for (id = 0; id < IPSET_EXT_ID_MAX; id++) {
                if (!add_extension(id, cadt_flags, tb))
                        continue;
-               offset = ALIGN(offset, ip_set_extensions[id].align);
-               set->offset[id] = offset;
+               len = ALIGN(len, ip_set_extensions[id].align);
+               set->offset[id] = len;
                set->extensions |= ip_set_extensions[id].type;
-               offset += ip_set_extensions[id].len;
+               len += ip_set_extensions[id].len;
        }
-       return offset;
+       return ALIGN(len, align);
 }
 EXPORT_SYMBOL_GPL(ip_set_elem_len);
 
index 691b54fcaf2a47189665454fdcaff419236b020f..e5336ab36d679d707704a3988baec47360e6b9a4 100644 (file)
@@ -72,8 +72,9 @@ struct hbucket {
        DECLARE_BITMAP(used, AHASH_MAX_TUNED);
        u8 size;                /* size of the array */
        u8 pos;                 /* position of the first free entry */
-       unsigned char value[0]; /* the array of the values */
-} __attribute__ ((aligned));
+       unsigned char value[0]  /* the array of the values */
+               __aligned(__alignof__(u64));
+};
 
 /* The hash table: the table size stored here in order to make resizing easy */
 struct htable {
@@ -475,7 +476,7 @@ static void
 mtype_expire(struct ip_set *set, struct htype *h, u8 nets_length, size_t dsize)
 {
        struct htable *t;
-       struct hbucket *n;
+       struct hbucket *n, *tmp;
        struct mtype_elem *data;
        u32 i, j, d;
 #ifdef IP_SET_HASH_WITH_NETS
@@ -510,9 +511,14 @@ mtype_expire(struct ip_set *set, struct htype *h, u8 nets_length, size_t dsize)
                        }
                }
                if (d >= AHASH_INIT_SIZE) {
-                       struct hbucket *tmp = kzalloc(sizeof(*tmp) +
-                                       (n->size - AHASH_INIT_SIZE) * dsize,
-                                       GFP_ATOMIC);
+                       if (d >= n->size) {
+                               rcu_assign_pointer(hbucket(t, i), NULL);
+                               kfree_rcu(n, rcu);
+                               continue;
+                       }
+                       tmp = kzalloc(sizeof(*tmp) +
+                                     (n->size - AHASH_INIT_SIZE) * dsize,
+                                     GFP_ATOMIC);
                        if (!tmp)
                                /* Still try to delete expired elements */
                                continue;
@@ -522,7 +528,7 @@ mtype_expire(struct ip_set *set, struct htype *h, u8 nets_length, size_t dsize)
                                        continue;
                                data = ahash_data(n, j, dsize);
                                memcpy(tmp->value + d * dsize, data, dsize);
-                               set_bit(j, tmp->used);
+                               set_bit(d, tmp->used);
                                d++;
                        }
                        tmp->pos = d;
@@ -1323,12 +1329,14 @@ IPSET_TOKEN(HTYPE, _create)(struct net *net, struct ip_set *set,
 #endif
                set->variant = &IPSET_TOKEN(HTYPE, 4_variant);
                set->dsize = ip_set_elem_len(set, tb,
-                               sizeof(struct IPSET_TOKEN(HTYPE, 4_elem)));
+                       sizeof(struct IPSET_TOKEN(HTYPE, 4_elem)),
+                       __alignof__(struct IPSET_TOKEN(HTYPE, 4_elem)));
 #ifndef IP_SET_PROTO_UNDEF
        } else {
                set->variant = &IPSET_TOKEN(HTYPE, 6_variant);
                set->dsize = ip_set_elem_len(set, tb,
-                               sizeof(struct IPSET_TOKEN(HTYPE, 6_elem)));
+                       sizeof(struct IPSET_TOKEN(HTYPE, 6_elem)),
+                       __alignof__(struct IPSET_TOKEN(HTYPE, 6_elem)));
        }
 #endif
        if (tb[IPSET_ATTR_TIMEOUT]) {
index 5a30ce6e8c90d278ac37cb0115f45a4390f9a6d7..bbede95c9f68cee1a1e0b5c285231c78d987df63 100644 (file)
@@ -31,7 +31,7 @@ struct set_elem {
        struct rcu_head rcu;
        struct list_head list;
        ip_set_id_t id;
-};
+} __aligned(__alignof__(u64));
 
 struct set_adt_elem {
        ip_set_id_t id;
@@ -618,7 +618,8 @@ list_set_create(struct net *net, struct ip_set *set, struct nlattr *tb[],
                size = IP_SET_LIST_MIN_SIZE;
 
        set->variant = &set_variant;
-       set->dsize = ip_set_elem_len(set, tb, sizeof(struct set_elem));
+       set->dsize = ip_set_elem_len(set, tb, sizeof(struct set_elem),
+                                    __alignof__(struct set_elem));
        if (!init_list_set(net, set, size))
                return -ENOMEM;
        if (tb[IPSET_ATTR_TIMEOUT]) {
index 1e24fff53e4b5eef8fab776b2e3dc93a3ae4545c..f57b4dcdb2330e40110ce18ede71b742249edf00 100644 (file)
@@ -1176,6 +1176,7 @@ ip_vs_out(struct netns_ipvs *ipvs, unsigned int hooknum, struct sk_buff *skb, in
        struct ip_vs_protocol *pp;
        struct ip_vs_proto_data *pd;
        struct ip_vs_conn *cp;
+       struct sock *sk;
 
        EnterFunction(11);
 
@@ -1183,13 +1184,12 @@ ip_vs_out(struct netns_ipvs *ipvs, unsigned int hooknum, struct sk_buff *skb, in
        if (skb->ipvs_property)
                return NF_ACCEPT;
 
+       sk = skb_to_full_sk(skb);
        /* Bad... Do not break raw sockets */
-       if (unlikely(skb->sk != NULL && hooknum == NF_INET_LOCAL_OUT &&
+       if (unlikely(sk && hooknum == NF_INET_LOCAL_OUT &&
                     af == AF_INET)) {
-               struct sock *sk = skb->sk;
-               struct inet_sock *inet = inet_sk(skb->sk);
 
-               if (inet && sk->sk_family == PF_INET && inet->nodefrag)
+               if (sk->sk_family == PF_INET && inet_sk(sk)->nodefrag)
                        return NF_ACCEPT;
        }
 
@@ -1681,6 +1681,7 @@ ip_vs_in(struct netns_ipvs *ipvs, unsigned int hooknum, struct sk_buff *skb, int
        struct ip_vs_conn *cp;
        int ret, pkts;
        int conn_reuse_mode;
+       struct sock *sk;
 
        /* Already marked as IPVS request or reply? */
        if (skb->ipvs_property)
@@ -1708,12 +1709,11 @@ ip_vs_in(struct netns_ipvs *ipvs, unsigned int hooknum, struct sk_buff *skb, int
        ip_vs_fill_iph_skb(af, skb, false, &iph);
 
        /* Bad... Do not break raw sockets */
-       if (unlikely(skb->sk != NULL && hooknum == NF_INET_LOCAL_OUT &&
+       sk = skb_to_full_sk(skb);
+       if (unlikely(sk && hooknum == NF_INET_LOCAL_OUT &&
                     af == AF_INET)) {
-               struct sock *sk = skb->sk;
-               struct inet_sock *inet = inet_sk(skb->sk);
 
-               if (inet && sk->sk_family == PF_INET && inet->nodefrag)
+               if (sk->sk_family == PF_INET && inet_sk(sk)->nodefrag)
                        return NF_ACCEPT;
        }
 
index 93cc4737018fdf3d13a2896c19a9c65891355f9e..2cb429d34c03c99e2e030becede22b05db604a76 100644 (file)
@@ -89,6 +89,7 @@ nf_tables_afinfo_lookup(struct net *net, int family, bool autoload)
 }
 
 static void nft_ctx_init(struct nft_ctx *ctx,
+                        struct net *net,
                         const struct sk_buff *skb,
                         const struct nlmsghdr *nlh,
                         struct nft_af_info *afi,
@@ -96,7 +97,7 @@ static void nft_ctx_init(struct nft_ctx *ctx,
                         struct nft_chain *chain,
                         const struct nlattr * const *nla)
 {
-       ctx->net        = sock_net(skb->sk);
+       ctx->net        = net;
        ctx->afi        = afi;
        ctx->table      = table;
        ctx->chain      = chain;
@@ -672,15 +673,14 @@ err:
        return ret;
 }
 
-static int nf_tables_newtable(struct sock *nlsk, struct sk_buff *skb,
-                             const struct nlmsghdr *nlh,
+static int nf_tables_newtable(struct net *net, struct sock *nlsk,
+                             struct sk_buff *skb, const struct nlmsghdr *nlh,
                              const struct nlattr * const nla[])
 {
        const struct nfgenmsg *nfmsg = nlmsg_data(nlh);
        const struct nlattr *name;
        struct nft_af_info *afi;
        struct nft_table *table;
-       struct net *net = sock_net(skb->sk);
        int family = nfmsg->nfgen_family;
        u32 flags = 0;
        struct nft_ctx ctx;
@@ -706,7 +706,7 @@ static int nf_tables_newtable(struct sock *nlsk, struct sk_buff *skb,
                if (nlh->nlmsg_flags & NLM_F_REPLACE)
                        return -EOPNOTSUPP;
 
-               nft_ctx_init(&ctx, skb, nlh, afi, table, NULL, nla);
+               nft_ctx_init(&ctx, net, skb, nlh, afi, table, NULL, nla);
                return nf_tables_updtable(&ctx);
        }
 
@@ -730,7 +730,7 @@ static int nf_tables_newtable(struct sock *nlsk, struct sk_buff *skb,
        INIT_LIST_HEAD(&table->sets);
        table->flags = flags;
 
-       nft_ctx_init(&ctx, skb, nlh, afi, table, NULL, nla);
+       nft_ctx_init(&ctx, net, skb, nlh, afi, table, NULL, nla);
        err = nft_trans_table_add(&ctx, NFT_MSG_NEWTABLE);
        if (err < 0)
                goto err3;
@@ -810,18 +810,17 @@ out:
        return err;
 }
 
-static int nf_tables_deltable(struct sock *nlsk, struct sk_buff *skb,
-                             const struct nlmsghdr *nlh,
+static int nf_tables_deltable(struct net *net, struct sock *nlsk,
+                             struct sk_buff *skb, const struct nlmsghdr *nlh,
                              const struct nlattr * const nla[])
 {
        const struct nfgenmsg *nfmsg = nlmsg_data(nlh);
        struct nft_af_info *afi;
        struct nft_table *table;
-       struct net *net = sock_net(skb->sk);
        int family = nfmsg->nfgen_family;
        struct nft_ctx ctx;
 
-       nft_ctx_init(&ctx, skb, nlh, NULL, NULL, NULL, nla);
+       nft_ctx_init(&ctx, net, skb, nlh, NULL, NULL, NULL, nla);
        if (family == AF_UNSPEC || nla[NFTA_TABLE_NAME] == NULL)
                return nft_flush(&ctx, family);
 
@@ -1221,8 +1220,8 @@ static void nf_tables_chain_destroy(struct nft_chain *chain)
        }
 }
 
-static int nf_tables_newchain(struct sock *nlsk, struct sk_buff *skb,
-                             const struct nlmsghdr *nlh,
+static int nf_tables_newchain(struct net *net, struct sock *nlsk,
+                             struct sk_buff *skb, const struct nlmsghdr *nlh,
                              const struct nlattr * const nla[])
 {
        const struct nfgenmsg *nfmsg = nlmsg_data(nlh);
@@ -1232,7 +1231,6 @@ static int nf_tables_newchain(struct sock *nlsk, struct sk_buff *skb,
        struct nft_chain *chain;
        struct nft_base_chain *basechain = NULL;
        struct nlattr *ha[NFTA_HOOK_MAX + 1];
-       struct net *net = sock_net(skb->sk);
        int family = nfmsg->nfgen_family;
        struct net_device *dev = NULL;
        u8 policy = NF_ACCEPT;
@@ -1313,7 +1311,7 @@ static int nf_tables_newchain(struct sock *nlsk, struct sk_buff *skb,
                                return PTR_ERR(stats);
                }
 
-               nft_ctx_init(&ctx, skb, nlh, afi, table, chain, nla);
+               nft_ctx_init(&ctx, net, skb, nlh, afi, table, chain, nla);
                trans = nft_trans_alloc(&ctx, NFT_MSG_NEWCHAIN,
                                        sizeof(struct nft_trans_chain));
                if (trans == NULL) {
@@ -1461,7 +1459,7 @@ static int nf_tables_newchain(struct sock *nlsk, struct sk_buff *skb,
        if (err < 0)
                goto err1;
 
-       nft_ctx_init(&ctx, skb, nlh, afi, table, chain, nla);
+       nft_ctx_init(&ctx, net, skb, nlh, afi, table, chain, nla);
        err = nft_trans_chain_add(&ctx, NFT_MSG_NEWCHAIN);
        if (err < 0)
                goto err2;
@@ -1476,15 +1474,14 @@ err1:
        return err;
 }
 
-static int nf_tables_delchain(struct sock *nlsk, struct sk_buff *skb,
-                             const struct nlmsghdr *nlh,
+static int nf_tables_delchain(struct net *net, struct sock *nlsk,
+                             struct sk_buff *skb, const struct nlmsghdr *nlh,
                              const struct nlattr * const nla[])
 {
        const struct nfgenmsg *nfmsg = nlmsg_data(nlh);
        struct nft_af_info *afi;
        struct nft_table *table;
        struct nft_chain *chain;
-       struct net *net = sock_net(skb->sk);
        int family = nfmsg->nfgen_family;
        struct nft_ctx ctx;
 
@@ -1506,7 +1503,7 @@ static int nf_tables_delchain(struct sock *nlsk, struct sk_buff *skb,
        if (chain->use > 0)
                return -EBUSY;
 
-       nft_ctx_init(&ctx, skb, nlh, afi, table, chain, nla);
+       nft_ctx_init(&ctx, net, skb, nlh, afi, table, chain, nla);
 
        return nft_delchain(&ctx);
 }
@@ -2010,13 +2007,12 @@ static void nf_tables_rule_destroy(const struct nft_ctx *ctx,
 
 static struct nft_expr_info *info;
 
-static int nf_tables_newrule(struct sock *nlsk, struct sk_buff *skb,
-                            const struct nlmsghdr *nlh,
+static int nf_tables_newrule(struct net *net, struct sock *nlsk,
+                            struct sk_buff *skb, const struct nlmsghdr *nlh,
                             const struct nlattr * const nla[])
 {
        const struct nfgenmsg *nfmsg = nlmsg_data(nlh);
        struct nft_af_info *afi;
-       struct net *net = sock_net(skb->sk);
        struct nft_table *table;
        struct nft_chain *chain;
        struct nft_rule *rule, *old_rule = NULL;
@@ -2075,7 +2071,7 @@ static int nf_tables_newrule(struct sock *nlsk, struct sk_buff *skb,
                        return PTR_ERR(old_rule);
        }
 
-       nft_ctx_init(&ctx, skb, nlh, afi, table, chain, nla);
+       nft_ctx_init(&ctx, net, skb, nlh, afi, table, chain, nla);
 
        n = 0;
        size = 0;
@@ -2176,13 +2172,12 @@ err1:
        return err;
 }
 
-static int nf_tables_delrule(struct sock *nlsk, struct sk_buff *skb,
-                            const struct nlmsghdr *nlh,
+static int nf_tables_delrule(struct net *net, struct sock *nlsk,
+                            struct sk_buff *skb, const struct nlmsghdr *nlh,
                             const struct nlattr * const nla[])
 {
        const struct nfgenmsg *nfmsg = nlmsg_data(nlh);
        struct nft_af_info *afi;
-       struct net *net = sock_net(skb->sk);
        struct nft_table *table;
        struct nft_chain *chain = NULL;
        struct nft_rule *rule;
@@ -2205,7 +2200,7 @@ static int nf_tables_delrule(struct sock *nlsk, struct sk_buff *skb,
                        return PTR_ERR(chain);
        }
 
-       nft_ctx_init(&ctx, skb, nlh, afi, table, chain, nla);
+       nft_ctx_init(&ctx, net, skb, nlh, afi, table, chain, nla);
 
        if (chain) {
                if (nla[NFTA_RULE_HANDLE]) {
@@ -2344,12 +2339,11 @@ static const struct nla_policy nft_set_desc_policy[NFTA_SET_DESC_MAX + 1] = {
        [NFTA_SET_DESC_SIZE]            = { .type = NLA_U32 },
 };
 
-static int nft_ctx_init_from_setattr(struct nft_ctx *ctx,
+static int nft_ctx_init_from_setattr(struct nft_ctx *ctx, struct net *net,
                                     const struct sk_buff *skb,
                                     const struct nlmsghdr *nlh,
                                     const struct nlattr * const nla[])
 {
-       struct net *net = sock_net(skb->sk);
        const struct nfgenmsg *nfmsg = nlmsg_data(nlh);
        struct nft_af_info *afi = NULL;
        struct nft_table *table = NULL;
@@ -2371,7 +2365,7 @@ static int nft_ctx_init_from_setattr(struct nft_ctx *ctx,
                        return -ENOENT;
        }
 
-       nft_ctx_init(ctx, skb, nlh, afi, table, NULL, nla);
+       nft_ctx_init(ctx, net, skb, nlh, afi, table, NULL, nla);
        return 0;
 }
 
@@ -2623,6 +2617,7 @@ static int nf_tables_getset(struct sock *nlsk, struct sk_buff *skb,
                            const struct nlmsghdr *nlh,
                            const struct nlattr * const nla[])
 {
+       struct net *net = sock_net(skb->sk);
        const struct nft_set *set;
        struct nft_ctx ctx;
        struct sk_buff *skb2;
@@ -2630,7 +2625,7 @@ static int nf_tables_getset(struct sock *nlsk, struct sk_buff *skb,
        int err;
 
        /* Verify existence before starting dump */
-       err = nft_ctx_init_from_setattr(&ctx, skb, nlh, nla);
+       err = nft_ctx_init_from_setattr(&ctx, net, skb, nlh, nla);
        if (err < 0)
                return err;
 
@@ -2693,14 +2688,13 @@ static int nf_tables_set_desc_parse(const struct nft_ctx *ctx,
        return 0;
 }
 
-static int nf_tables_newset(struct sock *nlsk, struct sk_buff *skb,
-                           const struct nlmsghdr *nlh,
+static int nf_tables_newset(struct net *net, struct sock *nlsk,
+                           struct sk_buff *skb, const struct nlmsghdr *nlh,
                            const struct nlattr * const nla[])
 {
        const struct nfgenmsg *nfmsg = nlmsg_data(nlh);
        const struct nft_set_ops *ops;
        struct nft_af_info *afi;
-       struct net *net = sock_net(skb->sk);
        struct nft_table *table;
        struct nft_set *set;
        struct nft_ctx ctx;
@@ -2798,7 +2792,7 @@ static int nf_tables_newset(struct sock *nlsk, struct sk_buff *skb,
        if (IS_ERR(table))
                return PTR_ERR(table);
 
-       nft_ctx_init(&ctx, skb, nlh, afi, table, NULL, nla);
+       nft_ctx_init(&ctx, net, skb, nlh, afi, table, NULL, nla);
 
        set = nf_tables_set_lookup(table, nla[NFTA_SET_NAME]);
        if (IS_ERR(set)) {
@@ -2882,8 +2876,8 @@ static void nf_tables_set_destroy(const struct nft_ctx *ctx, struct nft_set *set
        nft_set_destroy(set);
 }
 
-static int nf_tables_delset(struct sock *nlsk, struct sk_buff *skb,
-                           const struct nlmsghdr *nlh,
+static int nf_tables_delset(struct net *net, struct sock *nlsk,
+                           struct sk_buff *skb, const struct nlmsghdr *nlh,
                            const struct nlattr * const nla[])
 {
        const struct nfgenmsg *nfmsg = nlmsg_data(nlh);
@@ -2896,7 +2890,7 @@ static int nf_tables_delset(struct sock *nlsk, struct sk_buff *skb,
        if (nla[NFTA_SET_TABLE] == NULL)
                return -EINVAL;
 
-       err = nft_ctx_init_from_setattr(&ctx, skb, nlh, nla);
+       err = nft_ctx_init_from_setattr(&ctx, net, skb, nlh, nla);
        if (err < 0)
                return err;
 
@@ -3024,7 +3018,7 @@ static const struct nla_policy nft_set_elem_list_policy[NFTA_SET_ELEM_LIST_MAX +
        [NFTA_SET_ELEM_LIST_SET_ID]     = { .type = NLA_U32 },
 };
 
-static int nft_ctx_init_from_elemattr(struct nft_ctx *ctx,
+static int nft_ctx_init_from_elemattr(struct nft_ctx *ctx, struct net *net,
                                      const struct sk_buff *skb,
                                      const struct nlmsghdr *nlh,
                                      const struct nlattr * const nla[],
@@ -3033,7 +3027,6 @@ static int nft_ctx_init_from_elemattr(struct nft_ctx *ctx,
        const struct nfgenmsg *nfmsg = nlmsg_data(nlh);
        struct nft_af_info *afi;
        struct nft_table *table;
-       struct net *net = sock_net(skb->sk);
 
        afi = nf_tables_afinfo_lookup(net, nfmsg->nfgen_family, false);
        if (IS_ERR(afi))
@@ -3045,7 +3038,7 @@ static int nft_ctx_init_from_elemattr(struct nft_ctx *ctx,
        if (!trans && (table->flags & NFT_TABLE_INACTIVE))
                return -ENOENT;
 
-       nft_ctx_init(ctx, skb, nlh, afi, table, NULL, nla);
+       nft_ctx_init(ctx, net, skb, nlh, afi, table, NULL, nla);
        return 0;
 }
 
@@ -3135,6 +3128,7 @@ static int nf_tables_dump_setelem(const struct nft_ctx *ctx,
 
 static int nf_tables_dump_set(struct sk_buff *skb, struct netlink_callback *cb)
 {
+       struct net *net = sock_net(skb->sk);
        const struct nft_set *set;
        struct nft_set_dump_args args;
        struct nft_ctx ctx;
@@ -3150,8 +3144,8 @@ static int nf_tables_dump_set(struct sk_buff *skb, struct netlink_callback *cb)
        if (err < 0)
                return err;
 
-       err = nft_ctx_init_from_elemattr(&ctx, cb->skb, cb->nlh, (void *)nla,
-                                        false);
+       err = nft_ctx_init_from_elemattr(&ctx, net, cb->skb, cb->nlh,
+                                        (void *)nla, false);
        if (err < 0)
                return err;
 
@@ -3212,11 +3206,12 @@ static int nf_tables_getsetelem(struct sock *nlsk, struct sk_buff *skb,
                                const struct nlmsghdr *nlh,
                                const struct nlattr * const nla[])
 {
+       struct net *net = sock_net(skb->sk);
        const struct nft_set *set;
        struct nft_ctx ctx;
        int err;
 
-       err = nft_ctx_init_from_elemattr(&ctx, skb, nlh, nla, false);
+       err = nft_ctx_init_from_elemattr(&ctx, net, skb, nlh, nla, false);
        if (err < 0)
                return err;
 
@@ -3528,11 +3523,10 @@ err1:
        return err;
 }
 
-static int nf_tables_newsetelem(struct sock *nlsk, struct sk_buff *skb,
-                               const struct nlmsghdr *nlh,
+static int nf_tables_newsetelem(struct net *net, struct sock *nlsk,
+                               struct sk_buff *skb, const struct nlmsghdr *nlh,
                                const struct nlattr * const nla[])
 {
-       struct net *net = sock_net(skb->sk);
        const struct nlattr *attr;
        struct nft_set *set;
        struct nft_ctx ctx;
@@ -3541,7 +3535,7 @@ static int nf_tables_newsetelem(struct sock *nlsk, struct sk_buff *skb,
        if (nla[NFTA_SET_ELEM_LIST_ELEMENTS] == NULL)
                return -EINVAL;
 
-       err = nft_ctx_init_from_elemattr(&ctx, skb, nlh, nla, true);
+       err = nft_ctx_init_from_elemattr(&ctx, net, skb, nlh, nla, true);
        if (err < 0)
                return err;
 
@@ -3623,8 +3617,8 @@ err1:
        return err;
 }
 
-static int nf_tables_delsetelem(struct sock *nlsk, struct sk_buff *skb,
-                               const struct nlmsghdr *nlh,
+static int nf_tables_delsetelem(struct net *net, struct sock *nlsk,
+                               struct sk_buff *skb, const struct nlmsghdr *nlh,
                                const struct nlattr * const nla[])
 {
        const struct nlattr *attr;
@@ -3635,7 +3629,7 @@ static int nf_tables_delsetelem(struct sock *nlsk, struct sk_buff *skb,
        if (nla[NFTA_SET_ELEM_LIST_ELEMENTS] == NULL)
                return -EINVAL;
 
-       err = nft_ctx_init_from_elemattr(&ctx, skb, nlh, nla, false);
+       err = nft_ctx_init_from_elemattr(&ctx, net, skb, nlh, nla, false);
        if (err < 0)
                return err;
 
@@ -4030,7 +4024,8 @@ static int nf_tables_abort(struct sk_buff *skb)
        struct nft_trans *trans, *next;
        struct nft_trans_elem *te;
 
-       list_for_each_entry_safe(trans, next, &net->nft.commit_list, list) {
+       list_for_each_entry_safe_reverse(trans, next, &net->nft.commit_list,
+                                        list) {
                switch (trans->msg_type) {
                case NFT_MSG_NEWTABLE:
                        if (nft_trans_table_update(trans)) {
index 7b9c053ba75072276ee9227ea8d1e67ce3307715..edb3502f20161cf53d44e3fe84d9f0c63072be6a 100644 (file)
@@ -94,7 +94,7 @@ nft_do_chain_netdev(void *priv, struct sk_buff *skb,
 {
        struct nft_pktinfo pkt;
 
-       switch (eth_hdr(skb)->h_proto) {
+       switch (skb->protocol) {
        case htons(ETH_P_IP):
                nft_netdev_set_pktinfo_ipv4(&pkt, skb, state);
                break;
index 46453ab318db0bf2a4bc957dcad6742ccbcacc92..77afe913d03db73c65631fba8c42732cb3f33f32 100644 (file)
@@ -295,8 +295,6 @@ replay:
        if (!skb)
                return netlink_ack(oskb, nlh, -ENOMEM);
 
-       skb->sk = oskb->sk;
-
        nfnl_lock(subsys_id);
        ss = rcu_dereference_protected(table[subsys_id].subsys,
                                       lockdep_is_held(&table[subsys_id].mutex));
@@ -381,7 +379,7 @@ replay:
                                goto ack;
 
                        if (nc->call_batch) {
-                               err = nc->call_batch(net->nfnl, skb, nlh,
+                               err = nc->call_batch(net, net->nfnl, skb, nlh,
                                                     (const struct nlattr **)cda);
                        }
 
index 06eb48fceb42e4c31dba2d91c0d182bfc82e5b19..740cce4685acfab8920a46d5d33e40a68da02f8c 100644 (file)
@@ -825,7 +825,7 @@ nfulnl_recv_config(struct sock *ctnl, struct sk_buff *skb,
        struct net *net = sock_net(ctnl);
        struct nfnl_log_net *log = nfnl_log_pernet(net);
        int ret = 0;
-       u16 flags;
+       u16 flags = 0;
 
        if (nfula[NFULA_CFG_CMD]) {
                u_int8_t pf = nfmsg->nfgen_family;
index 7d81d280cb4ff3e8878af96bd644930f68a4340c..861c6615253bfe3b45e648d9c98a7715d873cbf9 100644 (file)
@@ -365,8 +365,9 @@ nfqnl_build_packet_message(struct net *net, struct nfqnl_instance *queue,
                break;
        }
 
+       nfnl_ct = rcu_dereference(nfnl_ct_hook);
+
        if (queue->flags & NFQA_CFG_F_CONNTRACK) {
-               nfnl_ct = rcu_dereference(nfnl_ct_hook);
                if (nfnl_ct != NULL) {
                        ct = nfnl_ct->get_ct(entskb, &ctinfo);
                        if (ct != NULL)
@@ -1064,9 +1065,10 @@ nfqnl_recv_verdict(struct sock *ctnl, struct sk_buff *skb,
        if (entry == NULL)
                return -ENOENT;
 
+       /* rcu lock already held from nfnl->call_rcu. */
+       nfnl_ct = rcu_dereference(nfnl_ct_hook);
+
        if (nfqa[NFQA_CT]) {
-               /* rcu lock already held from nfnl->call_rcu. */
-               nfnl_ct = rcu_dereference(nfnl_ct_hook);
                if (nfnl_ct != NULL)
                        ct = nfqnl_ct_parse(nfnl_ct, nlh, nfqa, entry, &ctinfo);
        }
@@ -1417,6 +1419,7 @@ static int __init nfnetlink_queue_init(void)
 
 cleanup_netlink_notifier:
        netlink_unregister_notifier(&nfqnl_rtnl_notifier);
+       unregister_pernet_subsys(&nfnl_queue_net_ops);
 out:
        return status;
 }
index 1067fb4c1ffa2ec24988143fc7ec8d134dc9dda6..c7808fc19719c4687457d039586f9708179b804e 100644 (file)
@@ -47,27 +47,34 @@ static void nft_counter_eval(const struct nft_expr *expr,
        local_bh_enable();
 }
 
-static int nft_counter_dump(struct sk_buff *skb, const struct nft_expr *expr)
+static void nft_counter_fetch(const struct nft_counter_percpu __percpu *counter,
+                             struct nft_counter *total)
 {
-       struct nft_counter_percpu_priv *priv = nft_expr_priv(expr);
-       struct nft_counter_percpu *cpu_stats;
-       struct nft_counter total;
+       const struct nft_counter_percpu *cpu_stats;
        u64 bytes, packets;
        unsigned int seq;
        int cpu;
 
-       memset(&total, 0, sizeof(total));
+       memset(total, 0, sizeof(*total));
        for_each_possible_cpu(cpu) {
-               cpu_stats = per_cpu_ptr(priv->counter, cpu);
+               cpu_stats = per_cpu_ptr(counter, cpu);
                do {
                        seq     = u64_stats_fetch_begin_irq(&cpu_stats->syncp);
                        bytes   = cpu_stats->counter.bytes;
                        packets = cpu_stats->counter.packets;
                } while (u64_stats_fetch_retry_irq(&cpu_stats->syncp, seq));
 
-               total.packets += packets;
-               total.bytes += bytes;
+               total->packets += packets;
+               total->bytes += bytes;
        }
+}
+
+static int nft_counter_dump(struct sk_buff *skb, const struct nft_expr *expr)
+{
+       struct nft_counter_percpu_priv *priv = nft_expr_priv(expr);
+       struct nft_counter total;
+
+       nft_counter_fetch(priv->counter, &total);
 
        if (nla_put_be64(skb, NFTA_COUNTER_BYTES, cpu_to_be64(total.bytes)) ||
            nla_put_be64(skb, NFTA_COUNTER_PACKETS, cpu_to_be64(total.packets)))
@@ -118,6 +125,31 @@ static void nft_counter_destroy(const struct nft_ctx *ctx,
        free_percpu(priv->counter);
 }
 
+static int nft_counter_clone(struct nft_expr *dst, const struct nft_expr *src)
+{
+       struct nft_counter_percpu_priv *priv = nft_expr_priv(src);
+       struct nft_counter_percpu_priv *priv_clone = nft_expr_priv(dst);
+       struct nft_counter_percpu __percpu *cpu_stats;
+       struct nft_counter_percpu *this_cpu;
+       struct nft_counter total;
+
+       nft_counter_fetch(priv->counter, &total);
+
+       cpu_stats = __netdev_alloc_pcpu_stats(struct nft_counter_percpu,
+                                             GFP_ATOMIC);
+       if (cpu_stats == NULL)
+               return ENOMEM;
+
+       preempt_disable();
+       this_cpu = this_cpu_ptr(cpu_stats);
+       this_cpu->counter.packets = total.packets;
+       this_cpu->counter.bytes = total.bytes;
+       preempt_enable();
+
+       priv_clone->counter = cpu_stats;
+       return 0;
+}
+
 static struct nft_expr_type nft_counter_type;
 static const struct nft_expr_ops nft_counter_ops = {
        .type           = &nft_counter_type,
@@ -126,6 +158,7 @@ static const struct nft_expr_ops nft_counter_ops = {
        .init           = nft_counter_init,
        .destroy        = nft_counter_destroy,
        .dump           = nft_counter_dump,
+       .clone          = nft_counter_clone,
 };
 
 static struct nft_expr_type nft_counter_type __read_mostly = {
index 8cbca3432f90324f8a28df2bd67da88cdaf72b12..939921532764acdd61a4d33c352abd2b8e1d4756 100644 (file)
@@ -366,6 +366,7 @@ static int nft_ct_get_dump(struct sk_buff *skb, const struct nft_expr *expr)
                goto nla_put_failure;
 
        switch (priv->key) {
+       case NFT_CT_L3PROTOCOL:
        case NFT_CT_PROTOCOL:
        case NFT_CT_SRC:
        case NFT_CT_DST:
index 513a8ef60a5922526eaa7f59fbc5abf1bb0552ba..9dec3bd1b63cc01a784ec025f7cf97f42b38fd06 100644 (file)
@@ -50,8 +50,9 @@ static void *nft_dynset_new(struct nft_set *set, const struct nft_expr *expr,
        }
 
        ext = nft_set_elem_ext(set, elem);
-       if (priv->expr != NULL)
-               nft_expr_clone(nft_set_ext_expr(ext), priv->expr);
+       if (priv->expr != NULL &&
+           nft_expr_clone(nft_set_ext_expr(ext), priv->expr) < 0)
+               return NULL;
 
        return elem;
 }
index b7de0da46acddc1eaaf041dedfbc9e2cf3697559..ecf0a0196f18040fb3fb2dc21b79273da92a470e 100644 (file)
@@ -572,7 +572,7 @@ static unsigned int llcp_sock_poll(struct file *file, struct socket *sock,
        if (sock_writeable(sk) && sk->sk_state == LLCP_CONNECTED)
                mask |= POLLOUT | POLLWRNORM | POLLWRBAND;
        else
-               set_bit(SOCK_ASYNC_NOSPACE, &sk->sk_socket->flags);
+               sk_set_bit(SOCKWQ_ASYNC_NOSPACE, sk);
 
        pr_debug("mask 0x%x\n", mask);
 
index c2cc11168fd5e164fa122da5dd44f7aa47279a1e..e004067ec24ac448467c0bd5a552eea019975e56 100644 (file)
@@ -53,6 +53,8 @@ struct ovs_conntrack_info {
        struct md_labels labels;
 };
 
+static void __ovs_ct_free_action(struct ovs_conntrack_info *ct_info);
+
 static u16 key_to_nfproto(const struct sw_flow_key *key)
 {
        switch (ntohs(key->eth.type)) {
@@ -141,6 +143,7 @@ static void __ovs_ct_update_key(struct sw_flow_key *key, u8 state,
  * previously sent the packet to conntrack via the ct action.
  */
 static void ovs_ct_update_key(const struct sk_buff *skb,
+                             const struct ovs_conntrack_info *info,
                              struct sw_flow_key *key, bool post_ct)
 {
        const struct nf_conntrack_zone *zone = &nf_ct_zone_dflt;
@@ -158,13 +161,15 @@ static void ovs_ct_update_key(const struct sk_buff *skb,
                zone = nf_ct_zone(ct);
        } else if (post_ct) {
                state = OVS_CS_F_TRACKED | OVS_CS_F_INVALID;
+               if (info)
+                       zone = &info->zone;
        }
        __ovs_ct_update_key(key, state, zone, ct);
 }
 
 void ovs_ct_fill_key(const struct sk_buff *skb, struct sw_flow_key *key)
 {
-       ovs_ct_update_key(skb, key, false);
+       ovs_ct_update_key(skb, NULL, key, false);
 }
 
 int ovs_ct_put_key(const struct sw_flow_key *key, struct sk_buff *skb)
@@ -418,7 +423,7 @@ static int __ovs_ct_lookup(struct net *net, struct sw_flow_key *key,
                }
        }
 
-       ovs_ct_update_key(skb, key, true);
+       ovs_ct_update_key(skb, info, key, true);
 
        return 0;
 }
@@ -693,6 +698,10 @@ int ovs_ct_copy_action(struct net *net, const struct nlattr *attr,
                OVS_NLERR(log, "Failed to allocate conntrack template");
                return -ENOMEM;
        }
+
+       __set_bit(IPS_CONFIRMED_BIT, &ct_info.ct->status);
+       nf_conntrack_get(&ct_info.ct->ct_general);
+
        if (helper) {
                err = ovs_ct_add_helper(&ct_info, helper, key, log);
                if (err)
@@ -704,11 +713,9 @@ int ovs_ct_copy_action(struct net *net, const struct nlattr *attr,
        if (err)
                goto err_free_ct;
 
-       __set_bit(IPS_CONFIRMED_BIT, &ct_info.ct->status);
-       nf_conntrack_get(&ct_info.ct->ct_general);
        return 0;
 err_free_ct:
-       nf_conntrack_free(ct_info.ct);
+       __ovs_ct_free_action(&ct_info);
        return err;
 }
 
@@ -750,6 +757,11 @@ void ovs_ct_free_action(const struct nlattr *a)
 {
        struct ovs_conntrack_info *ct_info = nla_data(a);
 
+       __ovs_ct_free_action(ct_info);
+}
+
+static void __ovs_ct_free_action(struct ovs_conntrack_info *ct_info)
+{
        if (ct_info->helper)
                module_put(ct_info->helper->me);
        if (ct_info->ct)
index a7a80a6b77b0ab15ecdd5859ee732417ee4a4705..653d073bae4533acf80d63fec54ed604249d83f0 100644 (file)
@@ -58,7 +58,7 @@ void ovs_dp_notify_wq(struct work_struct *work)
                        struct hlist_node *n;
 
                        hlist_for_each_entry_safe(vport, n, &dp->ports[i], dp_hash_node) {
-                               if (vport->ops->type != OVS_VPORT_TYPE_NETDEV)
+                               if (vport->ops->type == OVS_VPORT_TYPE_INTERNAL)
                                        continue;
 
                                if (!(vport->dev->priv_flags & IFF_OVS_DATAPATH))
index 907d6fd28ede695cc1b876570c101883ed0b4b0e..d1bd4a45ca2d64eca6439335d967aa21feff2b8b 100644 (file)
@@ -2434,7 +2434,10 @@ static int set_action_to_attr(const struct nlattr *a, struct sk_buff *skb)
                if (!start)
                        return -EMSGSIZE;
 
-               err = ovs_nla_put_tunnel_info(skb, tun_info);
+               err =  ip_tun_to_nlattr(skb, &tun_info->key,
+                                       ip_tunnel_info_opts(tun_info),
+                                       tun_info->options_len,
+                                       ip_tunnel_info_af(tun_info));
                if (err)
                        return err;
                nla_nest_end(skb, start);
index efb736bb685545a0cb6a323d3eca87fc54eeb9f4..e41cd12d9b2d1aacc7a143138511ddf86f6597df 100644 (file)
@@ -117,7 +117,6 @@ static struct vport_ops ovs_geneve_vport_ops = {
        .destroy        = ovs_netdev_tunnel_destroy,
        .get_options    = geneve_get_options,
        .send           = dev_queue_xmit,
-       .owner          = THIS_MODULE,
 };
 
 static int __init ovs_geneve_tnl_init(void)
index c3257d78d3d28e6ed06e1be9c2e4a4f452c52886..7f8897f33a67fe6512436aff86c43098c15e3445 100644 (file)
@@ -89,7 +89,6 @@ static struct vport_ops ovs_gre_vport_ops = {
        .create         = gre_create,
        .send           = dev_queue_xmit,
        .destroy        = ovs_netdev_tunnel_destroy,
-       .owner          = THIS_MODULE,
 };
 
 static int __init ovs_gre_tnl_init(void)
index b327368a3848238013cf0f6f62445569d7e29251..6b0190b987ec62c043e04fea80b4122a81bd67b9 100644 (file)
@@ -180,9 +180,13 @@ void ovs_netdev_tunnel_destroy(struct vport *vport)
        if (vport->dev->priv_flags & IFF_OVS_DATAPATH)
                ovs_netdev_detach_dev(vport);
 
-       /* Early release so we can unregister the device */
+       /* We can be invoked by both explicit vport deletion and
+        * underlying netdev deregistration; delete the link only
+        * if it's not already shutting down.
+        */
+       if (vport->dev->reg_state == NETREG_REGISTERED)
+               rtnl_delete_link(vport->dev);
        dev_put(vport->dev);
-       rtnl_delete_link(vport->dev);
        vport->dev = NULL;
        rtnl_unlock();
 
index 0ac0fd004d7ed885c009560d966da5b29b47f242..31cbc8c5c7db821e69945957f346fc361a07f9a0 100644 (file)
@@ -71,7 +71,7 @@ static struct hlist_head *hash_bucket(const struct net *net, const char *name)
        return &dev_table[hash & (VPORT_HASH_BUCKETS - 1)];
 }
 
-int ovs_vport_ops_register(struct vport_ops *ops)
+int __ovs_vport_ops_register(struct vport_ops *ops)
 {
        int err = -EEXIST;
        struct vport_ops *o;
@@ -87,7 +87,7 @@ errout:
        ovs_unlock();
        return err;
 }
-EXPORT_SYMBOL_GPL(ovs_vport_ops_register);
+EXPORT_SYMBOL_GPL(__ovs_vport_ops_register);
 
 void ovs_vport_ops_unregister(struct vport_ops *ops)
 {
@@ -256,8 +256,8 @@ int ovs_vport_set_options(struct vport *vport, struct nlattr *options)
  *
  * @vport: vport to delete.
  *
- * Detaches @vport from its datapath and destroys it.  It is possible to fail
- * for reasons such as lack of memory.  ovs_mutex must be held.
+ * Detaches @vport from its datapath and destroys it.  ovs_mutex must
+ * be held.
  */
 void ovs_vport_del(struct vport *vport)
 {
index bdfd82a7c064948dc1dc83acbc85b6534c1bcf9b..8ea3a96980acff90b1237387be70967c25f1236e 100644 (file)
@@ -196,7 +196,13 @@ static inline const char *ovs_vport_name(struct vport *vport)
        return vport->dev->name;
 }
 
-int ovs_vport_ops_register(struct vport_ops *ops);
+int __ovs_vport_ops_register(struct vport_ops *ops);
+#define ovs_vport_ops_register(ops)            \
+       ({                                      \
+               (ops)->owner = THIS_MODULE;     \
+               __ovs_vport_ops_register(ops);  \
+       })
+
 void ovs_vport_ops_unregister(struct vport_ops *ops);
 
 static inline struct rtable *ovs_tunnel_route_lookup(struct net *net,
index af399cac5205402480300ae7b7d6fbb2094095fb..992396aa635ce1174f6e62f19ae3f19a550668c6 100644 (file)
@@ -1741,6 +1741,20 @@ static void fanout_release(struct sock *sk)
                kfree_rcu(po->rollover, rcu);
 }
 
+static bool packet_extra_vlan_len_allowed(const struct net_device *dev,
+                                         struct sk_buff *skb)
+{
+       /* Earlier code assumed this would be a VLAN pkt, double-check
+        * this now that we have the actual packet in hand. We can only
+        * do this check on Ethernet devices.
+        */
+       if (unlikely(dev->type != ARPHRD_ETHER))
+               return false;
+
+       skb_reset_mac_header(skb);
+       return likely(eth_hdr(skb)->h_proto == htons(ETH_P_8021Q));
+}
+
 static const struct proto_ops packet_ops;
 
 static const struct proto_ops packet_ops_spkt;
@@ -1902,18 +1916,10 @@ retry:
                goto retry;
        }
 
-       if (len > (dev->mtu + dev->hard_header_len + extra_len)) {
-               /* Earlier code assumed this would be a VLAN pkt,
-                * double-check this now that we have the actual
-                * packet in hand.
-                */
-               struct ethhdr *ehdr;
-               skb_reset_mac_header(skb);
-               ehdr = eth_hdr(skb);
-               if (ehdr->h_proto != htons(ETH_P_8021Q)) {
-                       err = -EMSGSIZE;
-                       goto out_unlock;
-               }
+       if (len > (dev->mtu + dev->hard_header_len + extra_len) &&
+           !packet_extra_vlan_len_allowed(dev, skb)) {
+               err = -EMSGSIZE;
+               goto out_unlock;
        }
 
        skb->protocol = proto;
@@ -2323,8 +2329,8 @@ static void tpacket_destruct_skb(struct sk_buff *skb)
 static bool ll_header_truncated(const struct net_device *dev, int len)
 {
        /* net device doesn't like empty head */
-       if (unlikely(len <= dev->hard_header_len)) {
-               net_warn_ratelimited("%s: packet size is too short (%d <= %d)\n",
+       if (unlikely(len < dev->hard_header_len)) {
+               net_warn_ratelimited("%s: packet size is too short (%d < %d)\n",
                                     current->comm, len, dev->hard_header_len);
                return true;
        }
@@ -2332,6 +2338,15 @@ static bool ll_header_truncated(const struct net_device *dev, int len)
        return false;
 }
 
+static void tpacket_set_protocol(const struct net_device *dev,
+                                struct sk_buff *skb)
+{
+       if (dev->type == ARPHRD_ETHER) {
+               skb_reset_mac_header(skb);
+               skb->protocol = eth_hdr(skb)->h_proto;
+       }
+}
+
 static int tpacket_fill_skb(struct packet_sock *po, struct sk_buff *skb,
                void *frame, struct net_device *dev, int size_max,
                __be16 proto, unsigned char *addr, int hlen)
@@ -2368,8 +2383,6 @@ static int tpacket_fill_skb(struct packet_sock *po, struct sk_buff *skb,
        skb_reserve(skb, hlen);
        skb_reset_network_header(skb);
 
-       if (!packet_use_direct_xmit(po))
-               skb_probe_transport_header(skb, 0);
        if (unlikely(po->tp_tx_has_off)) {
                int off_min, off_max, off;
                off_min = po->tp_hdrlen - sizeof(struct sockaddr_ll);
@@ -2415,6 +2428,8 @@ static int tpacket_fill_skb(struct packet_sock *po, struct sk_buff *skb,
                                dev->hard_header_len);
                if (unlikely(err))
                        return err;
+               if (!skb->protocol)
+                       tpacket_set_protocol(dev, skb);
 
                data += dev->hard_header_len;
                to_write -= dev->hard_header_len;
@@ -2449,6 +2464,8 @@ static int tpacket_fill_skb(struct packet_sock *po, struct sk_buff *skb,
                len = ((to_write > len_max) ? len_max : to_write);
        }
 
+       skb_probe_transport_header(skb, 0);
+
        return tp_len;
 }
 
@@ -2493,12 +2510,13 @@ static int tpacket_snd(struct packet_sock *po, struct msghdr *msg)
        if (unlikely(!(dev->flags & IFF_UP)))
                goto out_put;
 
-       reserve = dev->hard_header_len + VLAN_HLEN;
+       if (po->sk.sk_socket->type == SOCK_RAW)
+               reserve = dev->hard_header_len;
        size_max = po->tx_ring.frame_size
                - (po->tp_hdrlen - sizeof(struct sockaddr_ll));
 
-       if (size_max > dev->mtu + reserve)
-               size_max = dev->mtu + reserve;
+       if (size_max > dev->mtu + reserve + VLAN_HLEN)
+               size_max = dev->mtu + reserve + VLAN_HLEN;
 
        do {
                ph = packet_current_frame(po, &po->tx_ring,
@@ -2525,18 +2543,10 @@ static int tpacket_snd(struct packet_sock *po, struct msghdr *msg)
                tp_len = tpacket_fill_skb(po, skb, ph, dev, size_max, proto,
                                          addr, hlen);
                if (likely(tp_len >= 0) &&
-                   tp_len > dev->mtu + dev->hard_header_len) {
-                       struct ethhdr *ehdr;
-                       /* Earlier code assumed this would be a VLAN pkt,
-                        * double-check this now that we have the actual
-                        * packet in hand.
-                        */
+                   tp_len > dev->mtu + reserve &&
+                   !packet_extra_vlan_len_allowed(dev, skb))
+                       tp_len = -EMSGSIZE;
 
-                       skb_reset_mac_header(skb);
-                       ehdr = eth_hdr(skb);
-                       if (ehdr->h_proto != htons(ETH_P_8021Q))
-                               tp_len = -EMSGSIZE;
-               }
                if (unlikely(tp_len < 0)) {
                        if (po->tp_loss) {
                                __packet_set_status(po, ph,
@@ -2765,18 +2775,10 @@ static int packet_snd(struct socket *sock, struct msghdr *msg, size_t len)
 
        sock_tx_timestamp(sk, &skb_shinfo(skb)->tx_flags);
 
-       if (!gso_type && (len > dev->mtu + reserve + extra_len)) {
-               /* Earlier code assumed this would be a VLAN pkt,
-                * double-check this now that we have the actual
-                * packet in hand.
-                */
-               struct ethhdr *ehdr;
-               skb_reset_mac_header(skb);
-               ehdr = eth_hdr(skb);
-               if (ehdr->h_proto != htons(ETH_P_8021Q)) {
-                       err = -EMSGSIZE;
-                       goto out_free;
-               }
+       if (!gso_type && (len > dev->mtu + reserve + extra_len) &&
+           !packet_extra_vlan_len_allowed(dev, skb)) {
+               err = -EMSGSIZE;
+               goto out_free;
        }
 
        skb->protocol = proto;
@@ -2807,8 +2809,8 @@ static int packet_snd(struct socket *sock, struct msghdr *msg, size_t len)
                len += vnet_hdr_len;
        }
 
-       if (!packet_use_direct_xmit(po))
-               skb_probe_transport_header(skb, reserve);
+       skb_probe_transport_header(skb, reserve);
+
        if (unlikely(extra_len == 4))
                skb->no_fcs = 1;
 
@@ -4107,7 +4109,7 @@ static int packet_set_ring(struct sock *sk, union tpacket_req_u *req_u,
                err = -EINVAL;
                if (unlikely((int)req->tp_block_size <= 0))
                        goto out;
-               if (unlikely(req->tp_block_size & (PAGE_SIZE - 1)))
+               if (unlikely(!PAGE_ALIGNED(req->tp_block_size)))
                        goto out;
                if (po->tp_version >= TPACKET_V3 &&
                    (int)(req->tp_block_size -
@@ -4119,8 +4121,8 @@ static int packet_set_ring(struct sock *sk, union tpacket_req_u *req_u,
                if (unlikely(req->tp_frame_size & (TPACKET_ALIGNMENT - 1)))
                        goto out;
 
-               rb->frames_per_block = req->tp_block_size/req->tp_frame_size;
-               if (unlikely(rb->frames_per_block <= 0))
+               rb->frames_per_block = req->tp_block_size / req->tp_frame_size;
+               if (unlikely(rb->frames_per_block == 0))
                        goto out;
                if (unlikely((rb->frames_per_block * req->tp_block_nr) !=
                                        req->tp_frame_nr))
index d4564036a339a04d31c65ec6c90cdc9e6a051efc..e3b118cae81d5e859e0244df1bf323aaa1798b8e 100644 (file)
@@ -186,12 +186,6 @@ static struct rds_connection *__rds_conn_create(struct net *net,
                }
        }
 
-       if (trans == NULL) {
-               kmem_cache_free(rds_conn_slab, conn);
-               conn = ERR_PTR(-ENODEV);
-               goto out;
-       }
-
        conn->c_trans = trans;
 
        ret = trans->conn_alloc(conn, gfp);
index 827155c2ead10376cb633c45c2f43917f5f5cd12..c9cdb358ea885e3e356cc675b579f1313ed94ff9 100644 (file)
@@ -1013,11 +1013,13 @@ int rds_sendmsg(struct socket *sock, struct msghdr *msg, size_t payload_len)
                release_sock(sk);
        }
 
-       /* racing with another thread binding seems ok here */
+       lock_sock(sk);
        if (daddr == 0 || rs->rs_bound_addr == 0) {
+               release_sock(sk);
                ret = -ENOTCONN; /* XXX not a great errno */
                goto out;
        }
+       release_sock(sk);
 
        if (payload_len > rds_sk_sndbuf(rs)) {
                ret = -EMSGSIZE;
index b41e9ea2ffff461847465d621a3284480f433cc5..f53bf3b6558b094b6e1b379568620157b4ffae17 100644 (file)
@@ -49,7 +49,6 @@
 struct rfkill {
        spinlock_t              lock;
 
-       const char              *name;
        enum rfkill_type        type;
 
        unsigned long           state;
@@ -73,6 +72,7 @@ struct rfkill {
        struct delayed_work     poll_work;
        struct work_struct      uevent_work;
        struct work_struct      sync_work;
+       char                    name[];
 };
 #define to_rfkill(d)   container_of(d, struct rfkill, dev)
 
@@ -876,14 +876,14 @@ struct rfkill * __must_check rfkill_alloc(const char *name,
        if (WARN_ON(type == RFKILL_TYPE_ALL || type >= NUM_RFKILL_TYPES))
                return NULL;
 
-       rfkill = kzalloc(sizeof(*rfkill), GFP_KERNEL);
+       rfkill = kzalloc(sizeof(*rfkill) + strlen(name) + 1, GFP_KERNEL);
        if (!rfkill)
                return NULL;
 
        spin_lock_init(&rfkill->lock);
        INIT_LIST_HEAD(&rfkill->node);
        rfkill->type = type;
-       rfkill->name = name;
+       strcpy(rfkill->name, name);
        rfkill->ops = ops;
        rfkill->data = ops_data;
 
index e0547f521f20d79c688c773286d609066c990a1d..adc555e0323d70b90d786c630f5a04dfddd60b32 100644 (file)
@@ -723,8 +723,10 @@ process_further:
 
                        if ((call->state == RXRPC_CALL_CLIENT_AWAIT_REPLY ||
                             call->state == RXRPC_CALL_SERVER_AWAIT_ACK) &&
-                           hard > tx)
+                           hard > tx) {
+                               call->acks_hard = tx;
                                goto all_acked;
+                       }
 
                        smp_rmb();
                        rxrpc_rotate_tx_window(call, hard - 1);
index a40d3afe93b7f3ee657985753c320210815f62a9..14c4e12c47b0f87f1c560d752bbd897d3ae2f952 100644 (file)
@@ -531,7 +531,7 @@ static int rxrpc_send_data(struct rxrpc_sock *rx,
        timeo = sock_sndtimeo(sk, msg->msg_flags & MSG_DONTWAIT);
 
        /* this should be in poll */
-       clear_bit(SOCK_ASYNC_NOSPACE, &sk->sk_socket->flags);
+       sk_clear_bit(SOCKWQ_ASYNC_NOSPACE, sk);
 
        if (sk->sk_err || (sk->sk_shutdown & SEND_SHUTDOWN))
                return -EPIPE;
index f43c8f33f09ef60e0f2a49ffd62f03624798c61b..b5c2cf2aa6d4bc00e5c4bac2b3326db3d785c8be 100644 (file)
@@ -253,7 +253,8 @@ int qdisc_set_default(const char *name)
 }
 
 /* We know handle. Find qdisc among all qdisc's attached to device
-   (root qdisc, all its children, children of children etc.)
+ * (root qdisc, all its children, children of children etc.)
+ * Note: caller either uses rtnl or rcu_read_lock()
  */
 
 static struct Qdisc *qdisc_match_from_root(struct Qdisc *root, u32 handle)
@@ -264,7 +265,7 @@ static struct Qdisc *qdisc_match_from_root(struct Qdisc *root, u32 handle)
            root->handle == handle)
                return root;
 
-       list_for_each_entry(q, &root->list, list) {
+       list_for_each_entry_rcu(q, &root->list, list) {
                if (q->handle == handle)
                        return q;
        }
@@ -277,15 +278,18 @@ void qdisc_list_add(struct Qdisc *q)
                struct Qdisc *root = qdisc_dev(q)->qdisc;
 
                WARN_ON_ONCE(root == &noop_qdisc);
-               list_add_tail(&q->list, &root->list);
+               ASSERT_RTNL();
+               list_add_tail_rcu(&q->list, &root->list);
        }
 }
 EXPORT_SYMBOL(qdisc_list_add);
 
 void qdisc_list_del(struct Qdisc *q)
 {
-       if ((q->parent != TC_H_ROOT) && !(q->flags & TCQ_F_INGRESS))
-               list_del(&q->list);
+       if ((q->parent != TC_H_ROOT) && !(q->flags & TCQ_F_INGRESS)) {
+               ASSERT_RTNL();
+               list_del_rcu(&q->list);
+       }
 }
 EXPORT_SYMBOL(qdisc_list_del);
 
@@ -750,14 +754,18 @@ void qdisc_tree_decrease_qlen(struct Qdisc *sch, unsigned int n)
        if (n == 0)
                return;
        drops = max_t(int, n, 0);
+       rcu_read_lock();
        while ((parentid = sch->parent)) {
                if (TC_H_MAJ(parentid) == TC_H_MAJ(TC_H_INGRESS))
-                       return;
+                       break;
 
+               if (sch->flags & TCQ_F_NOPARENT)
+                       break;
+               /* TODO: perform the search on a per txq basis */
                sch = qdisc_lookup(qdisc_dev(sch), TC_H_MAJ(parentid));
                if (sch == NULL) {
-                       WARN_ON(parentid != TC_H_ROOT);
-                       return;
+                       WARN_ON_ONCE(parentid != TC_H_ROOT);
+                       break;
                }
                cops = sch->ops->cl_ops;
                if (cops->qlen_notify) {
@@ -768,6 +776,7 @@ void qdisc_tree_decrease_qlen(struct Qdisc *sch, unsigned int n)
                sch->q.qlen -= n;
                __qdisc_qstats_drop(sch, drops);
        }
+       rcu_read_unlock();
 }
 EXPORT_SYMBOL(qdisc_tree_decrease_qlen);
 
index cb5d4ad32946cf0c6f3391fe9742bceb7dd702e6..e82a1ad80aa521291fba4e704bb3828e88a009db 100644 (file)
@@ -737,7 +737,7 @@ static void attach_one_default_qdisc(struct net_device *dev,
                return;
        }
        if (!netif_is_multiqueue(dev))
-               qdisc->flags |= TCQ_F_ONETXQUEUE;
+               qdisc->flags |= TCQ_F_ONETXQUEUE | TCQ_F_NOPARENT;
        dev_queue->qdisc_sleeping = qdisc;
 }
 
index f3cbaecd283af4ce5a78ad90d135d008d2b542d7..3e82f047caaf40461c9f408bd0572a64147e1a8f 100644 (file)
@@ -63,7 +63,7 @@ static int mq_init(struct Qdisc *sch, struct nlattr *opt)
                if (qdisc == NULL)
                        goto err;
                priv->qdiscs[ntx] = qdisc;
-               qdisc->flags |= TCQ_F_ONETXQUEUE;
+               qdisc->flags |= TCQ_F_ONETXQUEUE | TCQ_F_NOPARENT;
        }
 
        sch->flags |= TCQ_F_MQROOT;
@@ -156,7 +156,7 @@ static int mq_graft(struct Qdisc *sch, unsigned long cl, struct Qdisc *new,
 
        *old = dev_graft_qdisc(dev_queue, new);
        if (new)
-               new->flags |= TCQ_F_ONETXQUEUE;
+               new->flags |= TCQ_F_ONETXQUEUE | TCQ_F_NOPARENT;
        if (dev->flags & IFF_UP)
                dev_activate(dev);
        return 0;
index 3811a745452cf402cd498ed47058fdf655d18cbd..ad70ecf57ce793d7b50b50e9220c24fa4ab30ab5 100644 (file)
@@ -132,7 +132,7 @@ static int mqprio_init(struct Qdisc *sch, struct nlattr *opt)
                        goto err;
                }
                priv->qdiscs[i] = qdisc;
-               qdisc->flags |= TCQ_F_ONETXQUEUE;
+               qdisc->flags |= TCQ_F_ONETXQUEUE | TCQ_F_NOPARENT;
        }
 
        /* If the mqprio options indicate that hardware should own
@@ -209,7 +209,7 @@ static int mqprio_graft(struct Qdisc *sch, unsigned long cl, struct Qdisc *new,
        *old = dev_graft_qdisc(dev_queue, new);
 
        if (new)
-               new->flags |= TCQ_F_ONETXQUEUE;
+               new->flags |= TCQ_F_ONETXQUEUE | TCQ_F_NOPARENT;
 
        if (dev->flags & IFF_UP)
                dev_activate(dev);
index 4f15b7d730e13d6aaa58ba7a28262c9831afea95..1543e39f47c33f6662abd80b5846a845d3760fdc 100644 (file)
@@ -809,8 +809,8 @@ int sctp_auth_ep_set_hmacs(struct sctp_endpoint *ep,
        if (!has_sha1)
                return -EINVAL;
 
-       memcpy(ep->auth_hmacs_list->hmac_ids, &hmacs->shmac_idents[0],
-               hmacs->shmac_num_idents * sizeof(__u16));
+       for (i = 0; i < hmacs->shmac_num_idents; i++)
+               ep->auth_hmacs_list->hmac_ids[i] = htons(hmacs->shmac_idents[i]);
        ep->auth_hmacs_list->param_hdr.length = htons(sizeof(sctp_paramhdr_t) +
                                hmacs->shmac_num_idents * sizeof(__u16));
        return 0;
index e917d27328ea835419ba3e4c26eae1d7b7fade77..ec529121f38a03c4b3e2317249cd0694fd619d3f 100644 (file)
@@ -209,6 +209,7 @@ static int sctp_v6_xmit(struct sk_buff *skb, struct sctp_transport *transport)
        struct sock *sk = skb->sk;
        struct ipv6_pinfo *np = inet6_sk(sk);
        struct flowi6 *fl6 = &transport->fl.u.ip6;
+       int res;
 
        pr_debug("%s: skb:%p, len:%d, src:%pI6 dst:%pI6\n", __func__, skb,
                 skb->len, &fl6->saddr, &fl6->daddr);
@@ -220,7 +221,10 @@ static int sctp_v6_xmit(struct sk_buff *skb, struct sctp_transport *transport)
 
        SCTP_INC_STATS(sock_net(sk), SCTP_MIB_OUTSCTPPACKS);
 
-       return ip6_xmit(sk, skb, fl6, np->opt, np->tclass);
+       rcu_read_lock();
+       res = ip6_xmit(sk, skb, fl6, rcu_dereference(np->opt), np->tclass);
+       rcu_read_unlock();
+       return res;
 }
 
 /* Returns the dst cache entry for the given source and destination ip
@@ -262,7 +266,10 @@ static void sctp_v6_get_dst(struct sctp_transport *t, union sctp_addr *saddr,
                pr_debug("src=%pI6 - ", &fl6->saddr);
        }
 
-       final_p = fl6_update_dst(fl6, np->opt, &final);
+       rcu_read_lock();
+       final_p = fl6_update_dst(fl6, rcu_dereference(np->opt), &final);
+       rcu_read_unlock();
+
        dst = ip6_dst_lookup_flow(sk, fl6, final_p);
        if (!asoc || saddr)
                goto out;
@@ -316,14 +323,13 @@ static void sctp_v6_get_dst(struct sctp_transport *t, union sctp_addr *saddr,
                        }
                }
        }
-       rcu_read_unlock();
-
        if (baddr) {
                fl6->saddr = baddr->v6.sin6_addr;
                fl6->fl6_sport = baddr->v6.sin6_port;
-               final_p = fl6_update_dst(fl6, np->opt, &final);
+               final_p = fl6_update_dst(fl6, rcu_dereference(np->opt), &final);
                dst = ip6_dst_lookup_flow(sk, fl6, final_p);
        }
+       rcu_read_unlock();
 
 out:
        if (!IS_ERR_OR_NULL(dst)) {
@@ -635,6 +641,7 @@ static struct sock *sctp_v6_create_accept_sk(struct sock *sk,
        struct sock *newsk;
        struct ipv6_pinfo *newnp, *np = inet6_sk(sk);
        struct sctp6_sock *newsctp6sk;
+       struct ipv6_txoptions *opt;
 
        newsk = sk_alloc(sock_net(sk), PF_INET6, GFP_KERNEL, sk->sk_prot, 0);
        if (!newsk)
@@ -654,6 +661,13 @@ static struct sock *sctp_v6_create_accept_sk(struct sock *sk,
 
        memcpy(newnp, np, sizeof(struct ipv6_pinfo));
 
+       rcu_read_lock();
+       opt = rcu_dereference(np->opt);
+       if (opt)
+               opt = ipv6_dup_options(newsk, opt);
+       RCU_INIT_POINTER(newnp->opt, opt);
+       rcu_read_unlock();
+
        /* Initialize sk's sport, dport, rcv_saddr and daddr for getsockname()
         * and getpeername().
         */
index 7e8f0a117106cabbf043e24e33f56b307cf4fc88..c0380cfb16ae4eb77bdab457e8310c0cb15a1c4a 100644 (file)
@@ -324,6 +324,7 @@ int sctp_outq_tail(struct sctp_outq *q, struct sctp_chunk *chunk)
                                 sctp_cname(SCTP_ST_CHUNK(chunk->chunk_hdr->type)) :
                                 "illegal chunk");
 
+                       sctp_chunk_hold(chunk);
                        sctp_outq_tail_data(q, chunk);
                        if (chunk->chunk_hdr->flags & SCTP_DATA_UNORDERED)
                                SCTP_INC_STATS(net, SCTP_MIB_OUTUNORDERCHUNKS);
@@ -1251,6 +1252,7 @@ int sctp_outq_sack(struct sctp_outq *q, struct sctp_chunk *chunk)
         */
 
        sack_a_rwnd = ntohl(sack->a_rwnd);
+       asoc->peer.zero_window_announced = !sack_a_rwnd;
        outstanding = q->outstanding_bytes;
 
        if (outstanding < sack_a_rwnd)
index 763e06a55155b2a9e0a9d918ecc1fe2dd6d9e0c0..5d6a03fad3789a12290f5f14c5a7efa69c98f41a 100644 (file)
@@ -1652,7 +1652,7 @@ static sctp_cookie_param_t *sctp_pack_cookie(const struct sctp_endpoint *ep,
 
        /* Set an expiration time for the cookie.  */
        cookie->c.expiration = ktime_add(asoc->cookie_life,
-                                        ktime_get());
+                                        ktime_get_real());
 
        /* Copy the peer's init packet.  */
        memcpy(&cookie->c.peer_init[0], init_chunk->chunk_hdr,
@@ -1780,7 +1780,7 @@ no_hmac:
        if (sock_flag(ep->base.sk, SOCK_TIMESTAMP))
                kt = skb_get_ktime(skb);
        else
-               kt = ktime_get();
+               kt = ktime_get_real();
 
        if (!asoc && ktime_before(bear_cookie->expiration, kt)) {
                /*
index 6f46aa16cb76963de27cb87e5e8cedf617a259a9..22c2bf367d7e8c7025065f33eabfd7e93a7f4021 100644 (file)
@@ -4829,7 +4829,8 @@ sctp_disposition_t sctp_sf_do_9_1_prm_abort(
 
        retval = SCTP_DISPOSITION_CONSUME;
 
-       sctp_add_cmd_sf(commands, SCTP_CMD_REPLY, SCTP_CHUNK(abort));
+       if (abort)
+               sctp_add_cmd_sf(commands, SCTP_CMD_REPLY, SCTP_CHUNK(abort));
 
        /* Even if we can't send the ABORT due to low memory delete the
         * TCB.  This is a departure from our typical NOMEM handling.
@@ -4966,7 +4967,8 @@ sctp_disposition_t sctp_sf_cookie_wait_prm_abort(
                        SCTP_TO(SCTP_EVENT_TIMEOUT_T1_INIT));
        retval = SCTP_DISPOSITION_CONSUME;
 
-       sctp_add_cmd_sf(commands, SCTP_CMD_REPLY, SCTP_CHUNK(abort));
+       if (abort)
+               sctp_add_cmd_sf(commands, SCTP_CMD_REPLY, SCTP_CHUNK(abort));
 
        sctp_add_cmd_sf(commands, SCTP_CMD_NEW_STATE,
                        SCTP_STATE(SCTP_STATE_CLOSED));
@@ -5412,7 +5414,8 @@ sctp_disposition_t sctp_sf_do_6_3_3_rtx(struct net *net,
        SCTP_INC_STATS(net, SCTP_MIB_T3_RTX_EXPIREDS);
 
        if (asoc->overall_error_count >= asoc->max_retrans) {
-               if (asoc->state == SCTP_STATE_SHUTDOWN_PENDING) {
+               if (asoc->peer.zero_window_announced &&
+                   asoc->state == SCTP_STATE_SHUTDOWN_PENDING) {
                        /*
                         * We are here likely because the receiver had its rwnd
                         * closed for a while and we have not been able to
index 897c01c029cab3d5805cc56b0964c70e06f4143a..ef1d90fdc773d2ca4104c9dabc96d1058e99629a 100644 (file)
@@ -972,7 +972,7 @@ static int sctp_setsockopt_bindx(struct sock *sk,
                return -EFAULT;
 
        /* Alloc space for the address array in kernel memory.  */
-       kaddrs = kmalloc(addrs_size, GFP_KERNEL);
+       kaddrs = kmalloc(addrs_size, GFP_USER | __GFP_NOWARN);
        if (unlikely(!kaddrs))
                return -ENOMEM;
 
@@ -1301,8 +1301,9 @@ static int __sctp_setsockopt_connectx(struct sock *sk,
                                      int addrs_size,
                                      sctp_assoc_t *assoc_id)
 {
-       int err = 0;
        struct sockaddr *kaddrs;
+       gfp_t gfp = GFP_KERNEL;
+       int err = 0;
 
        pr_debug("%s: sk:%p addrs:%p addrs_size:%d\n",
                 __func__, sk, addrs, addrs_size);
@@ -1315,7 +1316,9 @@ static int __sctp_setsockopt_connectx(struct sock *sk,
                return -EFAULT;
 
        /* Alloc space for the address array in kernel memory.  */
-       kaddrs = kmalloc(addrs_size, GFP_KERNEL);
+       if (sk->sk_socket->file)
+               gfp = GFP_USER | __GFP_NOWARN;
+       kaddrs = kmalloc(addrs_size, gfp);
        if (unlikely(!kaddrs))
                return -ENOMEM;
 
@@ -1513,8 +1516,7 @@ static void sctp_close(struct sock *sk, long timeout)
                        struct sctp_chunk *chunk;
 
                        chunk = sctp_make_abort_user(asoc, NULL, 0);
-                       if (chunk)
-                               sctp_primitive_ABORT(net, asoc, chunk);
+                       sctp_primitive_ABORT(net, asoc, chunk);
                } else
                        sctp_primitive_SHUTDOWN(net, asoc, NULL);
        }
@@ -1952,8 +1954,6 @@ static int sctp_sendmsg(struct sock *sk, struct msghdr *msg, size_t msg_len)
 
        /* Now send the (possibly) fragmented message. */
        list_for_each_entry(chunk, &datamsg->chunks, frag_list) {
-               sctp_chunk_hold(chunk);
-
                /* Do accounting for the write space.  */
                sctp_set_owner_w(chunk);
 
@@ -1966,15 +1966,13 @@ static int sctp_sendmsg(struct sock *sk, struct msghdr *msg, size_t msg_len)
         * breaks.
         */
        err = sctp_primitive_SEND(net, asoc, datamsg);
+       sctp_datamsg_put(datamsg);
        /* Did the lower layer accept the chunk? */
-       if (err) {
-               sctp_datamsg_free(datamsg);
+       if (err)
                goto out_free;
-       }
 
        pr_debug("%s: we sent primitively\n", __func__);
 
-       sctp_datamsg_put(datamsg);
        err = msg_len;
 
        if (unlikely(wait_connect)) {
@@ -4928,7 +4926,7 @@ static int sctp_getsockopt_local_addrs(struct sock *sk, int len,
        to = optval + offsetof(struct sctp_getaddrs, addrs);
        space_left = len - offsetof(struct sctp_getaddrs, addrs);
 
-       addrs = kmalloc(space_left, GFP_KERNEL);
+       addrs = kmalloc(space_left, GFP_USER | __GFP_NOWARN);
        if (!addrs)
                return -ENOMEM;
 
@@ -5777,7 +5775,7 @@ static int sctp_getsockopt_assoc_ids(struct sock *sk, int len,
 
        len = sizeof(struct sctp_assoc_ids) + sizeof(sctp_assoc_t) * num;
 
-       ids = kmalloc(len, GFP_KERNEL);
+       ids = kmalloc(len, GFP_USER | __GFP_NOWARN);
        if (unlikely(!ids))
                return -ENOMEM;
 
@@ -6458,7 +6456,7 @@ unsigned int sctp_poll(struct file *file, struct socket *sock, poll_table *wait)
        if (sctp_writeable(sk)) {
                mask |= POLLOUT | POLLWRNORM;
        } else {
-               set_bit(SOCK_ASYNC_NOSPACE, &sk->sk_socket->flags);
+               sk_set_bit(SOCKWQ_ASYNC_NOSPACE, sk);
                /*
                 * Since the socket is not locked, the buffer
                 * might be made available after the writeable check and
@@ -6801,26 +6799,30 @@ no_packet:
 static void __sctp_write_space(struct sctp_association *asoc)
 {
        struct sock *sk = asoc->base.sk;
-       struct socket *sock = sk->sk_socket;
 
-       if ((sctp_wspace(asoc) > 0) && sock) {
-               if (waitqueue_active(&asoc->wait))
-                       wake_up_interruptible(&asoc->wait);
+       if (sctp_wspace(asoc) <= 0)
+               return;
 
-               if (sctp_writeable(sk)) {
-                       wait_queue_head_t *wq = sk_sleep(sk);
+       if (waitqueue_active(&asoc->wait))
+               wake_up_interruptible(&asoc->wait);
 
-                       if (wq && waitqueue_active(wq))
-                               wake_up_interruptible(wq);
+       if (sctp_writeable(sk)) {
+               struct socket_wq *wq;
+
+               rcu_read_lock();
+               wq = rcu_dereference(sk->sk_wq);
+               if (wq) {
+                       if (waitqueue_active(&wq->wait))
+                               wake_up_interruptible(&wq->wait);
 
                        /* Note that we try to include the Async I/O support
                         * here by modeling from the current TCP/UDP code.
                         * We have not tested with it yet.
                         */
                        if (!(sk->sk_shutdown & SEND_SHUTDOWN))
-                               sock_wake_async(sock,
-                                               SOCK_WAKE_SPACE, POLL_OUT);
+                               sock_wake_async(wq, SOCK_WAKE_SPACE, POLL_OUT);
                }
+               rcu_read_unlock();
        }
 }
 
@@ -7163,6 +7165,7 @@ void sctp_copy_sock(struct sock *newsk, struct sock *sk,
        newsk->sk_type = sk->sk_type;
        newsk->sk_bound_dev_if = sk->sk_bound_dev_if;
        newsk->sk_flags = sk->sk_flags;
+       newsk->sk_tsflags = sk->sk_tsflags;
        newsk->sk_no_check_tx = sk->sk_no_check_tx;
        newsk->sk_no_check_rx = sk->sk_no_check_rx;
        newsk->sk_reuse = sk->sk_reuse;
@@ -7195,6 +7198,11 @@ void sctp_copy_sock(struct sock *newsk, struct sock *sk,
        newinet->mc_ttl = 1;
        newinet->mc_index = 0;
        newinet->mc_list = NULL;
+
+       if (newsk->sk_flags & SK_FLAGS_TIMESTAMP)
+               net_enable_timestamp();
+
+       security_sk_clone(sk, newsk);
 }
 
 static inline void sctp_copy_descendant(struct sock *sk_to,
@@ -7375,6 +7383,13 @@ struct proto sctp_prot = {
 
 #if IS_ENABLED(CONFIG_IPV6)
 
+#include <net/transp_v6.h>
+static void sctp_v6_destroy_sock(struct sock *sk)
+{
+       sctp_destroy_sock(sk);
+       inet6_destroy_sock(sk);
+}
+
 struct proto sctpv6_prot = {
        .name           = "SCTPv6",
        .owner          = THIS_MODULE,
@@ -7384,7 +7399,7 @@ struct proto sctpv6_prot = {
        .accept         = sctp_accept,
        .ioctl          = sctp_ioctl,
        .init           = sctp_init_sock,
-       .destroy        = sctp_destroy_sock,
+       .destroy        = sctp_v6_destroy_sock,
        .shutdown       = sctp_shutdown,
        .setsockopt     = sctp_setsockopt,
        .getsockopt     = sctp_getsockopt,
index dd2c247c99e30a7950323c85e1ea9cb604eac218..d730ef9dfbf02aba150d5229a0d2875ddc23aa4d 100644 (file)
@@ -257,6 +257,7 @@ static struct inode *sock_alloc_inode(struct super_block *sb)
        }
        init_waitqueue_head(&wq->wait);
        wq->fasync_list = NULL;
+       wq->flags = 0;
        RCU_INIT_POINTER(ei->socket.wq, wq);
 
        ei->socket.state = SS_UNCONNECTED;
@@ -1056,27 +1057,20 @@ static int sock_fasync(int fd, struct file *filp, int on)
        return 0;
 }
 
-/* This function may be called only under socket lock or callback_lock or rcu_lock */
+/* This function may be called only under rcu_lock */
 
-int sock_wake_async(struct socket *sock, int how, int band)
+int sock_wake_async(struct socket_wq *wq, int how, int band)
 {
-       struct socket_wq *wq;
-
-       if (!sock)
-               return -1;
-       rcu_read_lock();
-       wq = rcu_dereference(sock->wq);
-       if (!wq || !wq->fasync_list) {
-               rcu_read_unlock();
+       if (!wq || !wq->fasync_list)
                return -1;
-       }
+
        switch (how) {
        case SOCK_WAKE_WAITD:
-               if (test_bit(SOCK_ASYNC_WAITDATA, &sock->flags))
+               if (test_bit(SOCKWQ_ASYNC_WAITDATA, &wq->flags))
                        break;
                goto call_kill;
        case SOCK_WAKE_SPACE:
-               if (!test_and_clear_bit(SOCK_ASYNC_NOSPACE, &sock->flags))
+               if (!test_and_clear_bit(SOCKWQ_ASYNC_NOSPACE, &wq->flags))
                        break;
                /* fall through */
        case SOCK_WAKE_IO:
@@ -1086,7 +1080,7 @@ call_kill:
        case SOCK_WAKE_URG:
                kill_fasync(&wq->fasync_list, SIGURG, band);
        }
-       rcu_read_unlock();
+
        return 0;
 }
 EXPORT_SYMBOL(sock_wake_async);
@@ -1702,6 +1696,7 @@ SYSCALL_DEFINE6(recvfrom, int, fd, void __user *, ubuf, size_t, size,
        msg.msg_name = addr ? (struct sockaddr *)&address : NULL;
        /* We assume all kernel code knows the size of sockaddr_storage */
        msg.msg_namelen = 0;
+       msg.msg_iocb = NULL;
        if (sock->file->f_flags & O_NONBLOCK)
                flags |= MSG_DONTWAIT;
        err = sock_recvmsg(sock, &msg, iov_iter_count(&msg.msg_iter), flags);
index f14f24ee998344f5c356ef49e3b3fc52d581a39c..73ad57a59989cb9234d06c1d399e02408e50c7d3 100644 (file)
@@ -250,11 +250,11 @@ void rpc_destroy_wait_queue(struct rpc_wait_queue *queue)
 }
 EXPORT_SYMBOL_GPL(rpc_destroy_wait_queue);
 
-static int rpc_wait_bit_killable(struct wait_bit_key *key)
+static int rpc_wait_bit_killable(struct wait_bit_key *key, int mode)
 {
-       if (fatal_signal_pending(current))
-               return -ERESTARTSYS;
        freezable_schedule_unsafe();
+       if (signal_pending_state(mode, current))
+               return -ERESTARTSYS;
        return 0;
 }
 
index bc5b7b5032ca54ce95b17de76bb22cbebc8a001a..cc9852897395c6f6db42653c773788446a9c5d3e 100644 (file)
@@ -1364,6 +1364,19 @@ bc_svc_process(struct svc_serv *serv, struct rpc_rqst *req,
        memcpy(&rqstp->rq_arg, &req->rq_rcv_buf, sizeof(rqstp->rq_arg));
        memcpy(&rqstp->rq_res, &req->rq_snd_buf, sizeof(rqstp->rq_res));
 
+       /* Adjust the argument buffer length */
+       rqstp->rq_arg.len = req->rq_private_buf.len;
+       if (rqstp->rq_arg.len <= rqstp->rq_arg.head[0].iov_len) {
+               rqstp->rq_arg.head[0].iov_len = rqstp->rq_arg.len;
+               rqstp->rq_arg.page_len = 0;
+       } else if (rqstp->rq_arg.len <= rqstp->rq_arg.head[0].iov_len +
+                       rqstp->rq_arg.page_len)
+               rqstp->rq_arg.page_len = rqstp->rq_arg.len -
+                       rqstp->rq_arg.head[0].iov_len;
+       else
+               rqstp->rq_arg.len = rqstp->rq_arg.head[0].iov_len +
+                       rqstp->rq_arg.page_len;
+
        /* reset result send buffer "put" position */
        resv->iov_len = 0;
 
index 1d1a7049891020264f5602d6237f12bac405c704..2ffaf6a794994ae20247fda57a6dd4c4bee64b0d 100644 (file)
@@ -398,7 +398,7 @@ static int xs_sendpages(struct socket *sock, struct sockaddr *addr, int addrlen,
        if (unlikely(!sock))
                return -ENOTSOCK;
 
-       clear_bit(SOCK_ASYNC_NOSPACE, &sock->flags);
+       clear_bit(SOCKWQ_ASYNC_NOSPACE, &sock->flags);
        if (base != 0) {
                addr = NULL;
                addrlen = 0;
@@ -442,7 +442,7 @@ static void xs_nospace_callback(struct rpc_task *task)
        struct sock_xprt *transport = container_of(task->tk_rqstp->rq_xprt, struct sock_xprt, xprt);
 
        transport->inet->sk_write_pending--;
-       clear_bit(SOCK_ASYNC_NOSPACE, &transport->sock->flags);
+       clear_bit(SOCKWQ_ASYNC_NOSPACE, &transport->sock->flags);
 }
 
 /**
@@ -467,7 +467,7 @@ static int xs_nospace(struct rpc_task *task)
 
        /* Don't race with disconnect */
        if (xprt_connected(xprt)) {
-               if (test_bit(SOCK_ASYNC_NOSPACE, &transport->sock->flags)) {
+               if (test_bit(SOCKWQ_ASYNC_NOSPACE, &transport->sock->flags)) {
                        /*
                         * Notify TCP that we're limited by the application
                         * window size
@@ -478,7 +478,7 @@ static int xs_nospace(struct rpc_task *task)
                        xprt_wait_for_buffer_space(task, xs_nospace_callback);
                }
        } else {
-               clear_bit(SOCK_ASYNC_NOSPACE, &transport->sock->flags);
+               clear_bit(SOCKWQ_ASYNC_NOSPACE, &transport->sock->flags);
                ret = -ENOTCONN;
        }
 
@@ -626,7 +626,7 @@ process_status:
        case -EPERM:
                /* When the server has died, an ICMP port unreachable message
                 * prompts ECONNREFUSED. */
-               clear_bit(SOCK_ASYNC_NOSPACE, &transport->sock->flags);
+               clear_bit(SOCKWQ_ASYNC_NOSPACE, &transport->sock->flags);
        }
 
        return status;
@@ -715,7 +715,7 @@ static int xs_tcp_send_request(struct rpc_task *task)
        case -EADDRINUSE:
        case -ENOBUFS:
        case -EPIPE:
-               clear_bit(SOCK_ASYNC_NOSPACE, &transport->sock->flags);
+               clear_bit(SOCKWQ_ASYNC_NOSPACE, &transport->sock->flags);
        }
 
        return status;
@@ -1618,7 +1618,7 @@ static void xs_write_space(struct sock *sk)
 
        if (unlikely(!(xprt = xprt_from_sock(sk))))
                return;
-       if (test_and_clear_bit(SOCK_ASYNC_NOSPACE, &sock->flags) == 0)
+       if (test_and_clear_bit(SOCKWQ_ASYNC_NOSPACE, &sock->flags) == 0)
                return;
 
        xprt_write_space(xprt);
index 9efbdbde2b0863542a08c91c136fadc9aa0cc6d8..91aea071ab27fee550e3c88ecc4097adac399d83 100644 (file)
@@ -191,6 +191,7 @@ void tipc_link_add_bc_peer(struct tipc_link *snd_l,
 
        snd_l->ackers++;
        rcv_l->acked = snd_l->snd_nxt - 1;
+       snd_l->state = LINK_ESTABLISHED;
        tipc_link_build_bc_init_msg(uc_l, xmitq);
 }
 
@@ -206,6 +207,7 @@ void tipc_link_remove_bc_peer(struct tipc_link *snd_l,
        rcv_l->state = LINK_RESET;
        if (!snd_l->ackers) {
                tipc_link_reset(snd_l);
+               snd_l->state = LINK_RESET;
                __skb_queue_purge(xmitq);
        }
 }
index 552dbaba9cf386a07e6c4f499fda27ca1f8a8f4a..b53246fb04128345304f2de5d3c895683ab0133b 100644 (file)
@@ -105,6 +105,7 @@ struct tipc_sock {
 static int tipc_backlog_rcv(struct sock *sk, struct sk_buff *skb);
 static void tipc_data_ready(struct sock *sk);
 static void tipc_write_space(struct sock *sk);
+static void tipc_sock_destruct(struct sock *sk);
 static int tipc_release(struct socket *sock);
 static int tipc_accept(struct socket *sock, struct socket *new_sock, int flags);
 static int tipc_wait_for_sndmsg(struct socket *sock, long *timeo_p);
@@ -381,6 +382,7 @@ static int tipc_sk_create(struct net *net, struct socket *sock,
        sk->sk_rcvbuf = sysctl_tipc_rmem[1];
        sk->sk_data_ready = tipc_data_ready;
        sk->sk_write_space = tipc_write_space;
+       sk->sk_destruct = tipc_sock_destruct;
        tsk->conn_timeout = CONN_TIMEOUT_DEFAULT;
        tsk->sent_unacked = 0;
        atomic_set(&tsk->dupl_rcvcnt, 0);
@@ -470,9 +472,6 @@ static int tipc_release(struct socket *sock)
                tipc_node_remove_conn(net, dnode, tsk->portid);
        }
 
-       /* Discard any remaining (connection-based) messages in receive queue */
-       __skb_queue_purge(&sk->sk_receive_queue);
-
        /* Reject any messages that accumulated in backlog queue */
        sock->state = SS_DISCONNECTING;
        release_sock(sk);
@@ -1515,6 +1514,11 @@ static void tipc_data_ready(struct sock *sk)
        rcu_read_unlock();
 }
 
+static void tipc_sock_destruct(struct sock *sk)
+{
+       __skb_queue_purge(&sk->sk_receive_queue);
+}
+
 /**
  * filter_connect - Handle all incoming messages for a connection-based socket
  * @tsk: TIPC socket
index ad2719ad4c1baf38cd8e31b244fe703382da002a..70c03271b798f429d8d6faa5142fb2654753d342 100644 (file)
@@ -158,8 +158,11 @@ static int tipc_udp_send_msg(struct net *net, struct sk_buff *skb,
        struct udp_media_addr *src = (struct udp_media_addr *)&b->addr.value;
        struct rtable *rt;
 
-       if (skb_headroom(skb) < UDP_MIN_HEADROOM)
-               pskb_expand_head(skb, UDP_MIN_HEADROOM, 0, GFP_ATOMIC);
+       if (skb_headroom(skb) < UDP_MIN_HEADROOM) {
+               err = pskb_expand_head(skb, UDP_MIN_HEADROOM, 0, GFP_ATOMIC);
+               if (err)
+                       goto tx_error;
+       }
 
        skb_set_inner_protocol(skb, htons(ETH_P_TIPC));
        ub = rcu_dereference_rtnl(b->media_ptr);
index aaa0b58d6aba29816aa81c0f6ce444a0ab0be0fb..a4631477cedf94361d3390f8fc616409dc4fcc6c 100644 (file)
@@ -326,6 +326,118 @@ found:
        return s;
 }
 
+/* Support code for asymmetrically connected dgram sockets
+ *
+ * If a datagram socket is connected to a socket not itself connected
+ * to the first socket (eg, /dev/log), clients may only enqueue more
+ * messages if the present receive queue of the server socket is not
+ * "too large". This means there's a second writeability condition
+ * poll and sendmsg need to test. The dgram recv code will do a wake
+ * up on the peer_wait wait queue of a socket upon reception of a
+ * datagram which needs to be propagated to sleeping would-be writers
+ * since these might not have sent anything so far. This can't be
+ * accomplished via poll_wait because the lifetime of the server
+ * socket might be less than that of its clients if these break their
+ * association with it or if the server socket is closed while clients
+ * are still connected to it and there's no way to inform "a polling
+ * implementation" that it should let go of a certain wait queue
+ *
+ * In order to propagate a wake up, a wait_queue_t of the client
+ * socket is enqueued on the peer_wait queue of the server socket
+ * whose wake function does a wake_up on the ordinary client socket
+ * wait queue. This connection is established whenever a write (or
+ * poll for write) hit the flow control condition and broken when the
+ * association to the server socket is dissolved or after a wake up
+ * was relayed.
+ */
+
+static int unix_dgram_peer_wake_relay(wait_queue_t *q, unsigned mode, int flags,
+                                     void *key)
+{
+       struct unix_sock *u;
+       wait_queue_head_t *u_sleep;
+
+       u = container_of(q, struct unix_sock, peer_wake);
+
+       __remove_wait_queue(&unix_sk(u->peer_wake.private)->peer_wait,
+                           q);
+       u->peer_wake.private = NULL;
+
+       /* relaying can only happen while the wq still exists */
+       u_sleep = sk_sleep(&u->sk);
+       if (u_sleep)
+               wake_up_interruptible_poll(u_sleep, key);
+
+       return 0;
+}
+
+static int unix_dgram_peer_wake_connect(struct sock *sk, struct sock *other)
+{
+       struct unix_sock *u, *u_other;
+       int rc;
+
+       u = unix_sk(sk);
+       u_other = unix_sk(other);
+       rc = 0;
+       spin_lock(&u_other->peer_wait.lock);
+
+       if (!u->peer_wake.private) {
+               u->peer_wake.private = other;
+               __add_wait_queue(&u_other->peer_wait, &u->peer_wake);
+
+               rc = 1;
+       }
+
+       spin_unlock(&u_other->peer_wait.lock);
+       return rc;
+}
+
+static void unix_dgram_peer_wake_disconnect(struct sock *sk,
+                                           struct sock *other)
+{
+       struct unix_sock *u, *u_other;
+
+       u = unix_sk(sk);
+       u_other = unix_sk(other);
+       spin_lock(&u_other->peer_wait.lock);
+
+       if (u->peer_wake.private == other) {
+               __remove_wait_queue(&u_other->peer_wait, &u->peer_wake);
+               u->peer_wake.private = NULL;
+       }
+
+       spin_unlock(&u_other->peer_wait.lock);
+}
+
+static void unix_dgram_peer_wake_disconnect_wakeup(struct sock *sk,
+                                                  struct sock *other)
+{
+       unix_dgram_peer_wake_disconnect(sk, other);
+       wake_up_interruptible_poll(sk_sleep(sk),
+                                  POLLOUT |
+                                  POLLWRNORM |
+                                  POLLWRBAND);
+}
+
+/* preconditions:
+ *     - unix_peer(sk) == other
+ *     - association is stable
+ */
+static int unix_dgram_peer_wake_me(struct sock *sk, struct sock *other)
+{
+       int connected;
+
+       connected = unix_dgram_peer_wake_connect(sk, other);
+
+       if (unix_recvq_full(other))
+               return 1;
+
+       if (connected)
+               unix_dgram_peer_wake_disconnect(sk, other);
+
+       return 0;
+}
+
 static int unix_writable(const struct sock *sk)
 {
        return sk->sk_state != TCP_LISTEN &&
@@ -431,6 +543,8 @@ static void unix_release_sock(struct sock *sk, int embrion)
                        skpair->sk_state_change(skpair);
                        sk_wake_async(skpair, SOCK_WAKE_WAITD, POLL_HUP);
                }
+
+               unix_dgram_peer_wake_disconnect(sk, skpair);
                sock_put(skpair); /* It may now die */
                unix_peer(sk) = NULL;
        }
@@ -441,6 +555,7 @@ static void unix_release_sock(struct sock *sk, int embrion)
                if (state == TCP_LISTEN)
                        unix_release_sock(skb->sk, 1);
                /* passed fds are erased in the kfree_skb hook        */
+               UNIXCB(skb).consumed = skb->len;
                kfree_skb(skb);
        }
 
@@ -665,6 +780,7 @@ static struct sock *unix_create1(struct net *net, struct socket *sock, int kern)
        INIT_LIST_HEAD(&u->link);
        mutex_init(&u->readlock); /* single task reading lock */
        init_waitqueue_head(&u->peer_wait);
+       init_waitqueue_func_entry(&u->peer_wake, unix_dgram_peer_wake_relay);
        unix_insert_socket(unix_sockets_unbound(sk), sk);
 out:
        if (sk == NULL)
@@ -1032,6 +1148,8 @@ restart:
        if (unix_peer(sk)) {
                struct sock *old_peer = unix_peer(sk);
                unix_peer(sk) = other;
+               unix_dgram_peer_wake_disconnect_wakeup(sk, old_peer);
+
                unix_state_double_unlock(sk, other);
 
                if (other != old_peer)
@@ -1433,6 +1551,14 @@ static int unix_scm_to_skb(struct scm_cookie *scm, struct sk_buff *skb, bool sen
        return err;
 }
 
+static bool unix_passcred_enabled(const struct socket *sock,
+                                 const struct sock *other)
+{
+       return test_bit(SOCK_PASSCRED, &sock->flags) ||
+              !other->sk_socket ||
+              test_bit(SOCK_PASSCRED, &other->sk_socket->flags);
+}
+
 /*
  * Some apps rely on write() giving SCM_CREDENTIALS
  * We include credentials if source or destination socket
@@ -1443,14 +1569,41 @@ static void maybe_add_creds(struct sk_buff *skb, const struct socket *sock,
 {
        if (UNIXCB(skb).pid)
                return;
-       if (test_bit(SOCK_PASSCRED, &sock->flags) ||
-           !other->sk_socket ||
-           test_bit(SOCK_PASSCRED, &other->sk_socket->flags)) {
+       if (unix_passcred_enabled(sock, other)) {
                UNIXCB(skb).pid  = get_pid(task_tgid(current));
                current_uid_gid(&UNIXCB(skb).uid, &UNIXCB(skb).gid);
        }
 }
 
+static int maybe_init_creds(struct scm_cookie *scm,
+                           struct socket *socket,
+                           const struct sock *other)
+{
+       int err;
+       struct msghdr msg = { .msg_controllen = 0 };
+
+       err = scm_send(socket, &msg, scm, false);
+       if (err)
+               return err;
+
+       if (unix_passcred_enabled(socket, other)) {
+               scm->pid = get_pid(task_tgid(current));
+               current_uid_gid(&scm->creds.uid, &scm->creds.gid);
+       }
+       return err;
+}
+
+static bool unix_skb_scm_eq(struct sk_buff *skb,
+                           struct scm_cookie *scm)
+{
+       const struct unix_skb_parms *u = &UNIXCB(skb);
+
+       return u->pid == scm->pid &&
+              uid_eq(u->uid, scm->creds.uid) &&
+              gid_eq(u->gid, scm->creds.gid) &&
+              unix_secdata_eq(scm, skb);
+}
+
 /*
  *     Send AF_UNIX data.
  */
@@ -1471,6 +1624,7 @@ static int unix_dgram_sendmsg(struct socket *sock, struct msghdr *msg,
        struct scm_cookie scm;
        int max_level;
        int data_len = 0;
+       int sk_locked;
 
        wait_for_unix_gc();
        err = scm_send(sock, msg, &scm, false);
@@ -1549,12 +1703,14 @@ restart:
                goto out_free;
        }
 
+       sk_locked = 0;
        unix_state_lock(other);
+restart_locked:
        err = -EPERM;
        if (!unix_may_send(sk, other))
                goto out_unlock;
 
-       if (sock_flag(other, SOCK_DEAD)) {
+       if (unlikely(sock_flag(other, SOCK_DEAD))) {
                /*
                 *      Check with 1003.1g - what should
                 *      datagram error
@@ -1562,10 +1718,14 @@ restart:
                unix_state_unlock(other);
                sock_put(other);
 
+               if (!sk_locked)
+                       unix_state_lock(sk);
+
                err = 0;
-               unix_state_lock(sk);
                if (unix_peer(sk) == other) {
                        unix_peer(sk) = NULL;
+                       unix_dgram_peer_wake_disconnect_wakeup(sk, other);
+
                        unix_state_unlock(sk);
 
                        unix_dgram_disconnected(sk, other);
@@ -1591,21 +1751,38 @@ restart:
                        goto out_unlock;
        }
 
-       if (unix_peer(other) != sk && unix_recvq_full(other)) {
-               if (!timeo) {
-                       err = -EAGAIN;
-                       goto out_unlock;
+       if (unlikely(unix_peer(other) != sk && unix_recvq_full(other))) {
+               if (timeo) {
+                       timeo = unix_wait_for_peer(other, timeo);
+
+                       err = sock_intr_errno(timeo);
+                       if (signal_pending(current))
+                               goto out_free;
+
+                       goto restart;
                }
 
-               timeo = unix_wait_for_peer(other, timeo);
+               if (!sk_locked) {
+                       unix_state_unlock(other);
+                       unix_state_double_lock(sk, other);
+               }
 
-               err = sock_intr_errno(timeo);
-               if (signal_pending(current))
-                       goto out_free;
+               if (unix_peer(sk) != other ||
+                   unix_dgram_peer_wake_me(sk, other)) {
+                       err = -EAGAIN;
+                       sk_locked = 1;
+                       goto out_unlock;
+               }
 
-               goto restart;
+               if (!sk_locked) {
+                       sk_locked = 1;
+                       goto restart_locked;
+               }
        }
 
+       if (unlikely(sk_locked))
+               unix_state_unlock(sk);
+
        if (sock_flag(other, SOCK_RCVTSTAMP))
                __net_timestamp(skb);
        maybe_add_creds(skb, sock, other);
@@ -1619,6 +1796,8 @@ restart:
        return len;
 
 out_unlock:
+       if (sk_locked)
+               unix_state_unlock(sk);
        unix_state_unlock(other);
 out_free:
        kfree_skb(skb);
@@ -1740,8 +1919,10 @@ out_err:
 static ssize_t unix_stream_sendpage(struct socket *socket, struct page *page,
                                    int offset, size_t size, int flags)
 {
-       int err = 0;
-       bool send_sigpipe = true;
+       int err;
+       bool send_sigpipe = false;
+       bool init_scm = true;
+       struct scm_cookie scm;
        struct sock *other, *sk = socket->sk;
        struct sk_buff *skb, *newskb = NULL, *tail = NULL;
 
@@ -1759,7 +1940,7 @@ alloc_skb:
                newskb = sock_alloc_send_pskb(sk, 0, 0, flags & MSG_DONTWAIT,
                                              &err, 0);
                if (!newskb)
-                       return err;
+                       goto err;
        }
 
        /* we must acquire readlock as we modify already present
@@ -1768,12 +1949,12 @@ alloc_skb:
        err = mutex_lock_interruptible(&unix_sk(other)->readlock);
        if (err) {
                err = flags & MSG_DONTWAIT ? -EAGAIN : -ERESTARTSYS;
-               send_sigpipe = false;
                goto err;
        }
 
        if (sk->sk_shutdown & SEND_SHUTDOWN) {
                err = -EPIPE;
+               send_sigpipe = true;
                goto err_unlock;
        }
 
@@ -1782,23 +1963,34 @@ alloc_skb:
        if (sock_flag(other, SOCK_DEAD) ||
            other->sk_shutdown & RCV_SHUTDOWN) {
                err = -EPIPE;
+               send_sigpipe = true;
                goto err_state_unlock;
        }
 
+       if (init_scm) {
+               err = maybe_init_creds(&scm, socket, other);
+               if (err)
+                       goto err_state_unlock;
+               init_scm = false;
+       }
+
        skb = skb_peek_tail(&other->sk_receive_queue);
        if (tail && tail == skb) {
                skb = newskb;
-       } else if (!skb) {
-               if (newskb)
+       } else if (!skb || !unix_skb_scm_eq(skb, &scm)) {
+               if (newskb) {
                        skb = newskb;
-               else
+               } else {
+                       tail = skb;
                        goto alloc_skb;
+               }
        } else if (newskb) {
                /* this is fast path, we don't necessarily need to
                 * call to kfree_skb even though with newskb == NULL
                 * this - does no harm
                 */
                consume_skb(newskb);
+               newskb = NULL;
        }
 
        if (skb_append_pagefrags(skb, page, offset, size)) {
@@ -1811,14 +2003,20 @@ alloc_skb:
        skb->truesize += size;
        atomic_add(size, &sk->sk_wmem_alloc);
 
-       if (newskb)
+       if (newskb) {
+               err = unix_scm_to_skb(&scm, skb, false);
+               if (err)
+                       goto err_state_unlock;
+               spin_lock(&other->sk_receive_queue.lock);
                __skb_queue_tail(&other->sk_receive_queue, newskb);
+               spin_unlock(&other->sk_receive_queue.lock);
+       }
 
        unix_state_unlock(other);
        mutex_unlock(&unix_sk(other)->readlock);
 
        other->sk_data_ready(other);
-
+       scm_destroy(&scm);
        return size;
 
 err_state_unlock:
@@ -1829,6 +2027,8 @@ err:
        kfree_skb(newskb);
        if (send_sigpipe && !(flags & MSG_NOSIGNAL))
                send_sig(SIGPIPE, current, 0);
+       if (!init_scm)
+               scm_destroy(&scm);
        return err;
 }
 
@@ -1991,7 +2191,7 @@ static long unix_stream_data_wait(struct sock *sk, long timeo,
                    !timeo)
                        break;
 
-               set_bit(SOCK_ASYNC_WAITDATA, &sk->sk_socket->flags);
+               sk_set_bit(SOCKWQ_ASYNC_WAITDATA, sk);
                unix_state_unlock(sk);
                timeo = freezable_schedule_timeout(timeo);
                unix_state_lock(sk);
@@ -1999,7 +2199,7 @@ static long unix_stream_data_wait(struct sock *sk, long timeo,
                if (sock_flag(sk, SOCK_DEAD))
                        break;
 
-               clear_bit(SOCK_ASYNC_WAITDATA, &sk->sk_socket->flags);
+               sk_clear_bit(SOCKWQ_ASYNC_WAITDATA, sk);
        }
 
        finish_wait(sk_sleep(sk), &wait);
@@ -2056,14 +2256,7 @@ static int unix_stream_read_generic(struct unix_stream_read_state *state)
        /* Lock the socket to prevent queue disordering
         * while sleeps in memcpy_tomsg
         */
-       err = mutex_lock_interruptible(&u->readlock);
-       if (unlikely(err)) {
-               /* recvmsg() in non blocking mode is supposed to return -EAGAIN
-                * sk_rcvtimeo is not honored by mutex_lock_interruptible()
-                */
-               err = noblock ? -EAGAIN : -ERESTARTSYS;
-               goto out;
-       }
+       mutex_lock(&u->readlock);
 
        if (flags & MSG_PEEK)
                skip = sk_peek_offset(sk, flags);
@@ -2072,6 +2265,7 @@ static int unix_stream_read_generic(struct unix_stream_read_state *state)
 
        do {
                int chunk;
+               bool drop_skb;
                struct sk_buff *skb, *last;
 
                unix_state_lock(sk);
@@ -2106,12 +2300,12 @@ again:
                        timeo = unix_stream_data_wait(sk, timeo, last,
                                                      last_len);
 
-                       if (signal_pending(current) ||
-                           mutex_lock_interruptible(&u->readlock)) {
+                       if (signal_pending(current)) {
                                err = sock_intr_errno(timeo);
                                goto out;
                        }
 
+                       mutex_lock(&u->readlock);
                        continue;
 unlock:
                        unix_state_unlock(sk);
@@ -2131,10 +2325,7 @@ unlock:
 
                if (check_creds) {
                        /* Never glue messages from different writers */
-                       if ((UNIXCB(skb).pid  != scm.pid) ||
-                           !uid_eq(UNIXCB(skb).uid, scm.creds.uid) ||
-                           !gid_eq(UNIXCB(skb).gid, scm.creds.gid) ||
-                           !unix_secdata_eq(&scm, skb))
+                       if (!unix_skb_scm_eq(skb, &scm))
                                break;
                } else if (test_bit(SOCK_PASSCRED, &sock->flags)) {
                        /* Copy credentials */
@@ -2152,7 +2343,11 @@ unlock:
                }
 
                chunk = min_t(unsigned int, unix_skb_len(skb) - skip, size);
+               skb_get(skb);
                chunk = state->recv_actor(skb, skip, chunk, state);
+               drop_skb = !unix_skb_len(skb);
+               /* skb is only safe to use if !drop_skb */
+               consume_skb(skb);
                if (chunk < 0) {
                        if (copied == 0)
                                copied = -EFAULT;
@@ -2161,6 +2356,18 @@ unlock:
                copied += chunk;
                size -= chunk;
 
+               if (drop_skb) {
+                       /* the skb was touched by a concurrent reader;
+                        * we should not expect anything from this skb
+                        * anymore and assume it invalid - we can be
+                        * sure it was dropped from the socket queue
+                        *
+                        * let's report a short read
+                        */
+                       err = 0;
+                       break;
+               }
+
                /* Mark read part of skb as used */
                if (!(flags & MSG_PEEK)) {
                        UNIXCB(skb).consumed += chunk;
@@ -2454,20 +2661,22 @@ static unsigned int unix_dgram_poll(struct file *file, struct socket *sock,
                return mask;
 
        writable = unix_writable(sk);
-       other = unix_peer_get(sk);
-       if (other) {
-               if (unix_peer(other) != sk) {
-                       sock_poll_wait(file, &unix_sk(other)->peer_wait, wait);
-                       if (unix_recvq_full(other))
-                               writable = 0;
-               }
-               sock_put(other);
+       if (writable) {
+               unix_state_lock(sk);
+
+               other = unix_peer(sk);
+               if (other && unix_peer(other) != sk &&
+                   unix_recvq_full(other) &&
+                   unix_dgram_peer_wake_me(sk, other))
+                       writable = 0;
+
+               unix_state_unlock(sk);
        }
 
        if (writable)
                mask |= POLLOUT | POLLWRNORM | POLLWRBAND;
        else
-               set_bit(SOCK_ASYNC_NOSPACE, &sk->sk_socket->flags);
+               sk_set_bit(SOCKWQ_ASYNC_NOSPACE, sk);
 
        return mask;
 }
index c71e274c810ac6610df652ec029838000ee7c69d..75b0d23ee882293a07fb9e236757931780def482 100644 (file)
@@ -7941,8 +7941,10 @@ static int nl80211_connect(struct sk_buff *skb, struct genl_info *info)
        if (nla_get_flag(info->attrs[NL80211_ATTR_USE_RRM])) {
                if (!(rdev->wiphy.features &
                      NL80211_FEATURE_DS_PARAM_SET_IE_IN_PROBES) ||
-                   !(rdev->wiphy.features & NL80211_FEATURE_QUIET))
+                   !(rdev->wiphy.features & NL80211_FEATURE_QUIET)) {
+                       kzfree(connkeys);
                        return -EINVAL;
+               }
                connect.flags |= ASSOC_REQ_USE_RRM;
        }
 
@@ -9503,6 +9505,7 @@ static int nl80211_set_wowlan(struct sk_buff *skb, struct genl_info *info)
        if (new_triggers.tcp && new_triggers.tcp->sock)
                sock_release(new_triggers.tcp->sock);
        kfree(new_triggers.tcp);
+       kfree(new_triggers.nd_config);
        return err;
 }
 #endif
index 2e8d6f39ed564ac7111be036a1f735da1d87d68b..06d050da0d94720cb40d3ad28425b06da22b3e89 100644 (file)
@@ -3029,6 +3029,7 @@ int set_regdom(const struct ieee80211_regdomain *rd,
                break;
        default:
                WARN(1, "invalid initiator %d\n", lr->initiator);
+               kfree(rd);
                return -EINVAL;
        }
 
@@ -3221,8 +3222,10 @@ int __init regulatory_init(void)
        /* We always try to get an update for the static regdomain */
        err = regulatory_hint_core(cfg80211_world_regdom->alpha2);
        if (err) {
-               if (err == -ENOMEM)
+               if (err == -ENOMEM) {
+                       platform_device_unregister(reg_pdev);
                        return err;
+               }
                /*
                 * N.B. kobject_uevent_env() can fail mainly for when we're out
                 * memory which is handled and propagated appropriately above
index 09bfcbac63bb3f75d909aecd840b63d36b169eec..b5e665b3cfb05f4d08970387802fee8aec8243dd 100644 (file)
@@ -303,6 +303,14 @@ struct xfrm_policy *xfrm_policy_alloc(struct net *net, gfp_t gfp)
 }
 EXPORT_SYMBOL(xfrm_policy_alloc);
 
+static void xfrm_policy_destroy_rcu(struct rcu_head *head)
+{
+       struct xfrm_policy *policy = container_of(head, struct xfrm_policy, rcu);
+
+       security_xfrm_policy_free(policy->security);
+       kfree(policy);
+}
+
 /* Destroy xfrm_policy: descendant resources must be released to this moment. */
 
 void xfrm_policy_destroy(struct xfrm_policy *policy)
@@ -312,8 +320,7 @@ void xfrm_policy_destroy(struct xfrm_policy *policy)
        if (del_timer(&policy->timer) || del_timer(&policy->polq.hold_timer))
                BUG();
 
-       security_xfrm_policy_free(policy->security);
-       kfree(policy);
+       call_rcu(&policy->rcu, xfrm_policy_destroy_rcu);
 }
 EXPORT_SYMBOL(xfrm_policy_destroy);
 
@@ -1214,8 +1221,10 @@ static struct xfrm_policy *xfrm_sk_policy_lookup(const struct sock *sk, int dir,
        struct xfrm_policy *pol;
        struct net *net = sock_net(sk);
 
+       rcu_read_lock();
        read_lock_bh(&net->xfrm.xfrm_policy_lock);
-       if ((pol = sk->sk_policy[dir]) != NULL) {
+       pol = rcu_dereference(sk->sk_policy[dir]);
+       if (pol != NULL) {
                bool match = xfrm_selector_match(&pol->selector, fl,
                                                 sk->sk_family);
                int err = 0;
@@ -1239,6 +1248,7 @@ static struct xfrm_policy *xfrm_sk_policy_lookup(const struct sock *sk, int dir,
        }
 out:
        read_unlock_bh(&net->xfrm.xfrm_policy_lock);
+       rcu_read_unlock();
        return pol;
 }
 
@@ -1307,13 +1317,14 @@ int xfrm_sk_policy_insert(struct sock *sk, int dir, struct xfrm_policy *pol)
 #endif
 
        write_lock_bh(&net->xfrm.xfrm_policy_lock);
-       old_pol = sk->sk_policy[dir];
-       sk->sk_policy[dir] = pol;
+       old_pol = rcu_dereference_protected(sk->sk_policy[dir],
+                               lockdep_is_held(&net->xfrm.xfrm_policy_lock));
        if (pol) {
                pol->curlft.add_time = get_seconds();
                pol->index = xfrm_gen_index(net, XFRM_POLICY_MAX+dir, 0);
                xfrm_sk_policy_link(pol, dir);
        }
+       rcu_assign_pointer(sk->sk_policy[dir], pol);
        if (old_pol) {
                if (pol)
                        xfrm_policy_requeue(old_pol, pol);
@@ -1361,17 +1372,26 @@ static struct xfrm_policy *clone_policy(const struct xfrm_policy *old, int dir)
        return newp;
 }
 
-int __xfrm_sk_clone_policy(struct sock *sk)
+int __xfrm_sk_clone_policy(struct sock *sk, const struct sock *osk)
 {
-       struct xfrm_policy *p0 = sk->sk_policy[0],
-                          *p1 = sk->sk_policy[1];
+       const struct xfrm_policy *p;
+       struct xfrm_policy *np;
+       int i, ret = 0;
 
-       sk->sk_policy[0] = sk->sk_policy[1] = NULL;
-       if (p0 && (sk->sk_policy[0] = clone_policy(p0, 0)) == NULL)
-               return -ENOMEM;
-       if (p1 && (sk->sk_policy[1] = clone_policy(p1, 1)) == NULL)
-               return -ENOMEM;
-       return 0;
+       rcu_read_lock();
+       for (i = 0; i < 2; i++) {
+               p = rcu_dereference(osk->sk_policy[i]);
+               if (p) {
+                       np = clone_policy(p, i);
+                       if (unlikely(!np)) {
+                               ret = -ENOMEM;
+                               break;
+                       }
+                       rcu_assign_pointer(sk->sk_policy[i], np);
+               }
+       }
+       rcu_read_unlock();
+       return ret;
 }
 
 static int
@@ -2198,6 +2218,7 @@ struct dst_entry *xfrm_lookup(struct net *net, struct dst_entry *dst_orig,
        xdst = NULL;
        route = NULL;
 
+       sk = sk_const_to_full_sk(sk);
        if (sk && sk->sk_policy[XFRM_POLICY_OUT]) {
                num_pols = 1;
                pols[0] = xfrm_sk_policy_lookup(sk, XFRM_POLICY_OUT, fl);
@@ -2477,6 +2498,7 @@ int __xfrm_policy_check(struct sock *sk, int dir, struct sk_buff *skb,
        }
 
        pol = NULL;
+       sk = sk_to_full_sk(sk);
        if (sk && sk->sk_policy[dir]) {
                pol = xfrm_sk_policy_lookup(sk, dir, &fl);
                if (IS_ERR(pol)) {
@@ -2804,7 +2826,6 @@ static struct neighbour *xfrm_neigh_lookup(const struct dst_entry *dst,
 
 int xfrm_policy_register_afinfo(struct xfrm_policy_afinfo *afinfo)
 {
-       struct net *net;
        int err = 0;
        if (unlikely(afinfo == NULL))
                return -EINVAL;
@@ -2835,26 +2856,6 @@ int xfrm_policy_register_afinfo(struct xfrm_policy_afinfo *afinfo)
        }
        spin_unlock(&xfrm_policy_afinfo_lock);
 
-       rtnl_lock();
-       for_each_net(net) {
-               struct dst_ops *xfrm_dst_ops;
-
-               switch (afinfo->family) {
-               case AF_INET:
-                       xfrm_dst_ops = &net->xfrm.xfrm4_dst_ops;
-                       break;
-#if IS_ENABLED(CONFIG_IPV6)
-               case AF_INET6:
-                       xfrm_dst_ops = &net->xfrm.xfrm6_dst_ops;
-                       break;
-#endif
-               default:
-                       BUG();
-               }
-               *xfrm_dst_ops = *afinfo->dst_ops;
-       }
-       rtnl_unlock();
-
        return err;
 }
 EXPORT_SYMBOL(xfrm_policy_register_afinfo);
@@ -2890,22 +2891,6 @@ int xfrm_policy_unregister_afinfo(struct xfrm_policy_afinfo *afinfo)
 }
 EXPORT_SYMBOL(xfrm_policy_unregister_afinfo);
 
-static void __net_init xfrm_dst_ops_init(struct net *net)
-{
-       struct xfrm_policy_afinfo *afinfo;
-
-       rcu_read_lock();
-       afinfo = rcu_dereference(xfrm_policy_afinfo[AF_INET]);
-       if (afinfo)
-               net->xfrm.xfrm4_dst_ops = *afinfo->dst_ops;
-#if IS_ENABLED(CONFIG_IPV6)
-       afinfo = rcu_dereference(xfrm_policy_afinfo[AF_INET6]);
-       if (afinfo)
-               net->xfrm.xfrm6_dst_ops = *afinfo->dst_ops;
-#endif
-       rcu_read_unlock();
-}
-
 static int xfrm_dev_event(struct notifier_block *this, unsigned long event, void *ptr)
 {
        struct net_device *dev = netdev_notifier_info_to_dev(ptr);
@@ -3054,7 +3039,6 @@ static int __net_init xfrm_net_init(struct net *net)
        rv = xfrm_policy_init(net);
        if (rv < 0)
                goto out_policy;
-       xfrm_dst_ops_init(net);
        rv = xfrm_sysctl_init(net);
        if (rv < 0)
                goto out_sysctl;
index 79b4596b5f9a45758776d91affe855c59d6fa39d..edd638b5825f8a96e6f6e16fe47f58c4262ca6f1 100644 (file)
@@ -67,10 +67,13 @@ HOSTLOADLIBES_lathist += -lelf
 # point this to your LLVM backend with bpf support
 LLC=$(srctree)/tools/bpf/llvm/bld/Debug+Asserts/bin/llc
 
+# asm/sysreg.h inline assmbly used by it is incompatible with llvm.
+# But, ehere is not easy way to fix it, so just exclude it since it is
+# useless for BPF samples.
 $(obj)/%.o: $(src)/%.c
        clang $(NOSTDINC_FLAGS) $(LINUXINCLUDE) $(EXTRA_CFLAGS) \
-               -D__KERNEL__ -Wno-unused-value -Wno-pointer-sign \
+               -D__KERNEL__ -D__ASM_SYSREG_H -Wno-unused-value -Wno-pointer-sign \
                -O2 -emit-llvm -c $< -o -| $(LLC) -march=bpf -filetype=obj -o $@
        clang $(NOSTDINC_FLAGS) $(LINUXINCLUDE) $(EXTRA_CFLAGS) \
-               -D__KERNEL__ -Wno-unused-value -Wno-pointer-sign \
+               -D__KERNEL__ -D__ASM_SYSREG_H -Wno-unused-value -Wno-pointer-sign \
                -O2 -emit-llvm -c $< -o -| $(LLC) -march=bpf -filetype=asm -o $@.s
index 125b906cd1d4bba50c727b108ead1a3d81e1e302..638a38e1b419518712c1f44c1497e80bac096240 100755 (executable)
@@ -2711,7 +2711,7 @@ $kernelversion = get_kernel_version();
 
 # generate a sequence of code that will splice in highlighting information
 # using the s// operator.
-foreach my $k (keys @highlights) {
+for (my $k = 0; $k < @highlights; $k++) {
     my $pattern = $highlights[$k][0];
     my $result = $highlights[$k][1];
 #   print STDERR "scanning pattern:$pattern, highlight:($result)\n";
index 1a10d8ac81620faad519d4f95ca8552ac4a958c1..dacf71a43ad41f678e3a0574c84321bacd0ff30e 100755 (executable)
@@ -62,7 +62,7 @@ vmlinux_link()
                        -Wl,--start-group                                    \
                                 ${KBUILD_VMLINUX_MAIN}                      \
                        -Wl,--end-group                                      \
-                       -lutil ${1}
+                       -lutil -lrt ${1}
                rm -f linux
        fi
 }
index 698768bdc5815021b61814ddabc408d4310c3c0e..301d70b0174f3b3ff3aaea7a721ffdd905a576f9 100644 (file)
 
 static int fd_map;     /* File descriptor for file being modified. */
 static int mmap_failed; /* Boolean flag. */
-static void *ehdr_curr; /* current ElfXX_Ehdr *  for resource cleanup */
 static char gpfx;      /* prefix for global symbol name (sometimes '_') */
 static struct stat sb; /* Remember .st_size, etc. */
 static jmp_buf jmpenv; /* setjmp/longjmp per-file error escape */
 static const char *altmcount;  /* alternate mcount symbol name */
 static int warn_on_notrace_sect; /* warn when section has mcount not being recorded */
+static void *file_map; /* pointer of the mapped file */
+static void *file_end; /* pointer to the end of the mapped file */
+static int file_updated; /* flag to state file was changed */
+static void *file_ptr; /* current file pointer location */
+static void *file_append; /* added to the end of the file */
+static size_t file_append_size; /* how much is added to end of file */
 
 /* setjmp() return values */
 enum {
@@ -67,10 +72,14 @@ static void
 cleanup(void)
 {
        if (!mmap_failed)
-               munmap(ehdr_curr, sb.st_size);
+               munmap(file_map, sb.st_size);
        else
-               free(ehdr_curr);
-       close(fd_map);
+               free(file_map);
+       file_map = NULL;
+       free(file_append);
+       file_append = NULL;
+       file_append_size = 0;
+       file_updated = 0;
 }
 
 static void __attribute__((noreturn))
@@ -92,12 +101,22 @@ succeed_file(void)
 static off_t
 ulseek(int const fd, off_t const offset, int const whence)
 {
-       off_t const w = lseek(fd, offset, whence);
-       if (w == (off_t)-1) {
-               perror("lseek");
+       switch (whence) {
+       case SEEK_SET:
+               file_ptr = file_map + offset;
+               break;
+       case SEEK_CUR:
+               file_ptr += offset;
+               break;
+       case SEEK_END:
+               file_ptr = file_map + (sb.st_size - offset);
+               break;
+       }
+       if (file_ptr < file_map) {
+               fprintf(stderr, "lseek: seek before file\n");
                fail_file();
        }
-       return w;
+       return file_ptr - file_map;
 }
 
 static size_t
@@ -114,12 +133,38 @@ uread(int const fd, void *const buf, size_t const count)
 static size_t
 uwrite(int const fd, void const *const buf, size_t const count)
 {
-       size_t const n = write(fd, buf, count);
-       if (n != count) {
-               perror("write");
-               fail_file();
+       size_t cnt = count;
+       off_t idx = 0;
+
+       file_updated = 1;
+
+       if (file_ptr + count >= file_end) {
+               off_t aoffset = (file_ptr + count) - file_end;
+
+               if (aoffset > file_append_size) {
+                       file_append = realloc(file_append, aoffset);
+                       file_append_size = aoffset;
+               }
+               if (!file_append) {
+                       perror("write");
+                       fail_file();
+               }
+               if (file_ptr < file_end) {
+                       cnt = file_end - file_ptr;
+               } else {
+                       cnt = 0;
+                       idx = aoffset - count;
+               }
        }
-       return n;
+
+       if (cnt)
+               memcpy(file_ptr, buf, cnt);
+
+       if (cnt < count)
+               memcpy(file_append + idx, buf + cnt, count - cnt);
+
+       file_ptr += count;
+       return count;
 }
 
 static void *
@@ -192,9 +237,7 @@ static int make_nop_arm64(void *map, size_t const offset)
  */
 static void *mmap_file(char const *fname)
 {
-       void *addr;
-
-       fd_map = open(fname, O_RDWR);
+       fd_map = open(fname, O_RDONLY);
        if (fd_map < 0 || fstat(fd_map, &sb) < 0) {
                perror(fname);
                fail_file();
@@ -203,15 +246,58 @@ static void *mmap_file(char const *fname)
                fprintf(stderr, "not a regular file: %s\n", fname);
                fail_file();
        }
-       addr = mmap(0, sb.st_size, PROT_READ|PROT_WRITE, MAP_PRIVATE,
-                   fd_map, 0);
+       file_map = mmap(0, sb.st_size, PROT_READ|PROT_WRITE, MAP_PRIVATE,
+                       fd_map, 0);
        mmap_failed = 0;
-       if (addr == MAP_FAILED) {
+       if (file_map == MAP_FAILED) {
                mmap_failed = 1;
-               addr = umalloc(sb.st_size);
-               uread(fd_map, addr, sb.st_size);
+               file_map = umalloc(sb.st_size);
+               uread(fd_map, file_map, sb.st_size);
+       }
+       close(fd_map);
+
+       file_end = file_map + sb.st_size;
+
+       return file_map;
+}
+
+static void write_file(const char *fname)
+{
+       char tmp_file[strlen(fname) + 4];
+       size_t n;
+
+       if (!file_updated)
+               return;
+
+       sprintf(tmp_file, "%s.rc", fname);
+
+       /*
+        * After reading the entire file into memory, delete it
+        * and write it back, to prevent weird side effects of modifying
+        * an object file in place.
+        */
+       fd_map = open(tmp_file, O_WRONLY | O_TRUNC | O_CREAT, sb.st_mode);
+       if (fd_map < 0) {
+               perror(fname);
+               fail_file();
+       }
+       n = write(fd_map, file_map, sb.st_size);
+       if (n != sb.st_size) {
+               perror("write");
+               fail_file();
+       }
+       if (file_append_size) {
+               n = write(fd_map, file_append, file_append_size);
+               if (n != file_append_size) {
+                       perror("write");
+                       fail_file();
+               }
+       }
+       close(fd_map);
+       if (rename(tmp_file, fname) < 0) {
+               perror(fname);
+               fail_file();
        }
-       return addr;
 }
 
 /* w8rev, w8nat, ...: Handle endianness. */
@@ -318,7 +404,6 @@ do_file(char const *const fname)
        Elf32_Ehdr *const ehdr = mmap_file(fname);
        unsigned int reltype = 0;
 
-       ehdr_curr = ehdr;
        w = w4nat;
        w2 = w2nat;
        w8 = w8nat;
@@ -441,6 +526,7 @@ do_file(char const *const fname)
        }
        }  /* end switch */
 
+       write_file(fname);
        cleanup();
 }
 
@@ -493,11 +579,14 @@ main(int argc, char *argv[])
                case SJ_SETJMP:    /* normal sequence */
                        /* Avoid problems if early cleanup() */
                        fd_map = -1;
-                       ehdr_curr = NULL;
                        mmap_failed = 1;
+                       file_map = NULL;
+                       file_ptr = NULL;
+                       file_updated = 0;
                        do_file(file);
                        break;
                case SJ_FAIL:    /* error in do_file or below */
+                       sprintf("%s: failed\n", file);
                        ++n_error;
                        break;
                case SJ_SUCCEED:    /* premature success */
index 927db9f35ad6f1bddeb51169e84c1bb526f85f21..696ccfa08d103cd29ae56ac38c117bbd7725da06 100644 (file)
@@ -845,6 +845,8 @@ static int encrypted_update(struct key *key, struct key_preparsed_payload *prep)
        size_t datalen = prep->datalen;
        int ret = 0;
 
+       if (test_bit(KEY_FLAG_NEGATIVE, &key->flags))
+               return -ENOKEY;
        if (datalen <= 0 || datalen > 32767 || !prep->data)
                return -EINVAL;
 
index fb111eafcb893e4f5146c74a84f8499d4e1553c4..1c3872aeed14ace421a9d43fc396c43afdd5b93c 100644 (file)
@@ -751,16 +751,16 @@ long keyctl_read_key(key_serial_t keyid, char __user *buffer, size_t buflen)
 
        /* the key is probably readable - now try to read it */
 can_read_key:
-       ret = key_validate(key);
-       if (ret == 0) {
-               ret = -EOPNOTSUPP;
-               if (key->type->read) {
-                       /* read the data with the semaphore held (since we
-                        * might sleep) */
-                       down_read(&key->sem);
+       ret = -EOPNOTSUPP;
+       if (key->type->read) {
+               /* Read the data with the semaphore held (since we might sleep)
+                * to protect against the key being updated or revoked.
+                */
+               down_read(&key->sem);
+               ret = key_validate(key);
+               if (ret == 0)
                        ret = key->type->read(key, buffer, buflen);
-                       up_read(&key->sem);
-               }
+               up_read(&key->sem);
        }
 
 error2:
index 903dace648a1731b2afbb2dc8b40b8169a05aba2..16dec53184b663f745c010d11e78128ca995bf58 100644 (file)
@@ -1007,13 +1007,16 @@ static void trusted_rcu_free(struct rcu_head *rcu)
  */
 static int trusted_update(struct key *key, struct key_preparsed_payload *prep)
 {
-       struct trusted_key_payload *p = key->payload.data[0];
+       struct trusted_key_payload *p;
        struct trusted_key_payload *new_p;
        struct trusted_key_options *new_o;
        size_t datalen = prep->datalen;
        char *datablob;
        int ret = 0;
 
+       if (test_bit(KEY_FLAG_NEGATIVE, &key->flags))
+               return -ENOKEY;
+       p = key->payload.data[0];
        if (!p->migratable)
                return -EPERM;
        if (datalen <= 0 || datalen > 32767 || !prep->data)
index 28cb30f80256911cf9ee41631659b9e8f5a6b5dd..8705d79b2c6f289736fde21fd38e6013a4e4ae3c 100644 (file)
@@ -120,7 +120,10 @@ int user_update(struct key *key, struct key_preparsed_payload *prep)
 
        if (ret == 0) {
                /* attach the new data, displacing the old */
-               zap = key->payload.data[0];
+               if (!test_bit(KEY_FLAG_NEGATIVE, &key->flags))
+                       zap = key->payload.data[0];
+               else
+                       zap = NULL;
                rcu_assign_keypointer(key, upayload);
                key->expiry = 0;
        }
index 18643bf9894d5e393bdb51b0d7b0740f34960e75..456e1a9bcfde14e594789de0b1055c63f8dd549e 100644 (file)
@@ -638,7 +638,7 @@ void cond_compute_av(struct avtab *ctab, struct avtab_key *key,
 {
        struct avtab_node *node;
 
-       if (!ctab || !key || !avd || !xperms)
+       if (!ctab || !key || !avd)
                return;
 
        for (node = avtab_search_node(ctab, key); node;
@@ -657,7 +657,7 @@ void cond_compute_av(struct avtab *ctab, struct avtab_key *key,
                if ((u16)(AVTAB_AUDITALLOW|AVTAB_ENABLED) ==
                    (node->key.specified & (AVTAB_AUDITALLOW|AVTAB_ENABLED)))
                        avd->auditallow |= node->datum.u.data;
-               if ((node->key.specified & AVTAB_ENABLED) &&
+               if (xperms && (node->key.specified & AVTAB_ENABLED) &&
                                (node->key.specified & AVTAB_XPERMS))
                        services_compute_xperms_drivers(xperms, node);
        }
index 5d99436dfcaee5e70f3957a8f8b59be3d9e213d3..0cda05c72f504383a5031e06aa956e2544ef93c8 100644 (file)
@@ -12,9 +12,11 @@ MODULE_AUTHOR("Clemens Ladisch <clemens@ladisch.de>");
 MODULE_LICENSE("GPL v2");
 
 #define OUI_WEISS              0x001c6a
+#define OUI_LOUD               0x000ff2
 
 #define DICE_CATEGORY_ID       0x04
 #define WEISS_CATEGORY_ID      0x00
+#define LOUD_CATEGORY_ID       0x10
 
 static int dice_interface_check(struct fw_unit *unit)
 {
@@ -57,6 +59,8 @@ static int dice_interface_check(struct fw_unit *unit)
        }
        if (vendor == OUI_WEISS)
                category = WEISS_CATEGORY_ID;
+       else if (vendor == OUI_LOUD)
+               category = LOUD_CATEGORY_ID;
        else
                category = DICE_CATEGORY_ID;
        if (device->config_rom[3] != ((vendor << 8) | category) ||
index 63215b17247c8e98e456ff588f96ed5f9bb1cf26..548cc1e4114bb81af0136cf77d517b4e751c6736 100644 (file)
@@ -77,6 +77,12 @@ int snd_hdac_ext_bus_parse_capabilities(struct hdac_ext_bus *ebus)
                        ebus->spbcap = bus->remap_addr + offset;
                        break;
 
+               case AZX_DRSM_CAP_ID:
+                       /* DMA resume  capability found, handler function */
+                       dev_dbg(bus->dev, "Found DRSM capability\n");
+                       ebus->drsmcap = bus->remap_addr + offset;
+                       break;
+
                default:
                        dev_dbg(bus->dev, "Unknown capability %d\n", cur_cap);
                        break;
@@ -240,7 +246,7 @@ static int check_hdac_link_power_active(struct hdac_ext_link *link, bool enable)
        int mask = (1 << AZX_MLCTL_CPA);
 
        udelay(3);
-       timeout = 50;
+       timeout = 150;
 
        do {
                val = readl(link->ml_addr + AZX_REG_ML_LCTL);
@@ -281,6 +287,27 @@ int snd_hdac_ext_bus_link_power_down(struct hdac_ext_link *link)
 }
 EXPORT_SYMBOL_GPL(snd_hdac_ext_bus_link_power_down);
 
+/**
+ * snd_hdac_ext_bus_link_power_up_all -power up all hda link
+ * @ebus: HD-audio extended bus
+ */
+int snd_hdac_ext_bus_link_power_up_all(struct hdac_ext_bus *ebus)
+{
+       struct hdac_ext_link *hlink = NULL;
+       int ret;
+
+       list_for_each_entry(hlink, &ebus->hlink_list, list) {
+               snd_hdac_updatel(hlink->ml_addr,
+                               AZX_REG_ML_LCTL, 0, AZX_MLCTL_SPA);
+               ret = check_hdac_link_power_active(hlink, true);
+               if (ret < 0)
+                       return ret;
+       }
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(snd_hdac_ext_bus_link_power_up_all);
+
 /**
  * snd_hdac_ext_bus_link_power_down_all -power down all hda link
  * @ebus: HD-audio extended bus
index cb89ec7c8147b2d44a90061ac531514ef5ce4de2..023cc4cad5c1965b31a334503d94c37752e733e4 100644 (file)
@@ -59,6 +59,10 @@ void snd_hdac_ext_stream_init(struct hdac_ext_bus *ebus,
                                        AZX_SPB_MAXFIFO;
        }
 
+       if (ebus->drsmcap)
+               stream->dpibr_addr = ebus->drsmcap + AZX_DRSM_BASE +
+                                       AZX_DRSM_INTERVAL * idx;
+
        stream->decoupled = false;
        snd_hdac_stream_init(bus, &stream->hstream, idx, direction, tag);
 }
@@ -107,6 +111,7 @@ void snd_hdac_stream_free_all(struct hdac_ext_bus *ebus)
        while (!list_empty(&bus->stream_list)) {
                s = list_first_entry(&bus->stream_list, struct hdac_stream, list);
                stream = stream_to_hdac_ext_stream(s);
+               snd_hdac_ext_stream_decouple(ebus, stream, false);
                list_del(&s->list);
                kfree(stream);
        }
@@ -497,3 +502,70 @@ void snd_hdac_ext_stop_streams(struct hdac_ext_bus *ebus)
        }
 }
 EXPORT_SYMBOL_GPL(snd_hdac_ext_stop_streams);
+
+/**
+ * snd_hdac_ext_stream_drsm_enable - enable DMA resume for a stream
+ * @ebus: HD-audio ext core bus
+ * @enable: flag to enable/disable DRSM
+ * @index: stream index for which DRSM need to be enabled
+ */
+void snd_hdac_ext_stream_drsm_enable(struct hdac_ext_bus *ebus,
+                               bool enable, int index)
+{
+       u32 mask = 0;
+       u32 register_mask = 0;
+       struct hdac_bus *bus = &ebus->bus;
+
+       if (!ebus->drsmcap) {
+               dev_err(bus->dev, "Address of DRSM capability is NULL");
+               return;
+       }
+
+       mask |= (1 << index);
+
+       register_mask = readl(ebus->drsmcap + AZX_REG_SPB_SPBFCCTL);
+
+       mask |= register_mask;
+
+       if (enable)
+               snd_hdac_updatel(ebus->drsmcap, AZX_REG_DRSM_CTL, 0, mask);
+       else
+               snd_hdac_updatel(ebus->drsmcap, AZX_REG_DRSM_CTL, mask, 0);
+}
+EXPORT_SYMBOL_GPL(snd_hdac_ext_stream_drsm_enable);
+
+/**
+ * snd_hdac_ext_stream_set_dpibr - sets the dpibr value of a stream
+ * @ebus: HD-audio ext core bus
+ * @stream: hdac_ext_stream
+ * @value: dpib value to set
+ */
+int snd_hdac_ext_stream_set_dpibr(struct hdac_ext_bus *ebus,
+                                struct hdac_ext_stream *stream, u32 value)
+{
+       struct hdac_bus *bus = &ebus->bus;
+
+       if (!ebus->drsmcap) {
+               dev_err(bus->dev, "Address of DRSM capability is NULL");
+               return -EINVAL;
+       }
+
+       writel(value, stream->dpibr_addr);
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(snd_hdac_ext_stream_set_dpibr);
+
+/**
+ * snd_hdac_ext_stream_set_lpib - sets the lpib value of a stream
+ * @ebus: HD-audio ext core bus
+ * @stream: hdac_ext_stream
+ * @value: lpib value to set
+ */
+int snd_hdac_ext_stream_set_lpib(struct hdac_ext_stream *stream, u32 value)
+{
+       snd_hdac_stream_writel(&stream->hstream, SD_LPIB, value);
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(snd_hdac_ext_stream_set_lpib);
index 8a7fbdcb4072f6a35f956ba51a5820f3d3054eaf..3b36582970702219f0e1b28f16093b4de6425b48 100644 (file)
@@ -312,6 +312,10 @@ enum {
        (AZX_DCAPS_INTEL_PCH | AZX_DCAPS_SEPARATE_STREAM_TAG |\
         AZX_DCAPS_I915_POWERWELL)
 
+#define AZX_DCAPS_INTEL_BROXTON \
+       (AZX_DCAPS_INTEL_PCH | AZX_DCAPS_SEPARATE_STREAM_TAG |\
+        AZX_DCAPS_I915_POWERWELL)
+
 /* quirks for ATI SB / AMD Hudson */
 #define AZX_DCAPS_PRESET_ATI_SB \
        (AZX_DCAPS_NO_TCSEL | AZX_DCAPS_SYNC_WRITE | AZX_DCAPS_POSFIX_LPIB |\
@@ -351,6 +355,8 @@ enum {
                                        ((pci)->device == 0x0d0c) || \
                                        ((pci)->device == 0x160c))
 
+#define IS_BROXTON(pci)        ((pci)->device == 0x5a98)
+
 static char *driver_short_names[] = {
        [AZX_DRIVER_ICH] = "HDA Intel",
        [AZX_DRIVER_PCH] = "HDA Intel PCH",
@@ -502,15 +508,36 @@ static void azx_init_pci(struct azx *chip)
         }
 }
 
+/*
+ * In BXT-P A0, HD-Audio DMA requests is later than expected,
+ * and makes an audio stream sensitive to system latencies when
+ * 24/32 bits are playing.
+ * Adjusting threshold of DMA fifo to force the DMA request
+ * sooner to improve latency tolerance at the expense of power.
+ */
+static void bxt_reduce_dma_latency(struct azx *chip)
+{
+       u32 val;
+
+       val = azx_readl(chip, SKL_EM4L);
+       val &= (0x3 << 20);
+       azx_writel(chip, SKL_EM4L, val);
+}
+
 static void hda_intel_init_chip(struct azx *chip, bool full_reset)
 {
        struct hdac_bus *bus = azx_bus(chip);
+       struct pci_dev *pci = chip->pci;
 
        if (chip->driver_caps & AZX_DCAPS_I915_POWERWELL)
                snd_hdac_set_codec_wakeup(bus, true);
        azx_init_chip(chip, full_reset);
        if (chip->driver_caps & AZX_DCAPS_I915_POWERWELL)
                snd_hdac_set_codec_wakeup(bus, false);
+
+       /* reduce dma latency to avoid noise */
+       if (IS_BROXTON(pci))
+               bxt_reduce_dma_latency(chip);
 }
 
 /* calculate runtime delay from LPIB */
@@ -927,6 +954,36 @@ static int azx_resume(struct device *dev)
 }
 #endif /* CONFIG_PM_SLEEP || SUPPORT_VGA_SWITCHEROO */
 
+#ifdef CONFIG_PM_SLEEP
+/* put codec down to D3 at hibernation for Intel SKL+;
+ * otherwise BIOS may still access the codec and screw up the driver
+ */
+#define IS_SKL(pci) ((pci)->vendor == 0x8086 && (pci)->device == 0xa170)
+#define IS_SKL_LP(pci) ((pci)->vendor == 0x8086 && (pci)->device == 0x9d70)
+#define IS_BXT(pci) ((pci)->vendor == 0x8086 && (pci)->device == 0x5a98)
+#define IS_SKL_PLUS(pci) (IS_SKL(pci) || IS_SKL_LP(pci) || IS_BXT(pci))
+
+static int azx_freeze_noirq(struct device *dev)
+{
+       struct pci_dev *pci = to_pci_dev(dev);
+
+       if (IS_SKL_PLUS(pci))
+               pci_set_power_state(pci, PCI_D3hot);
+
+       return 0;
+}
+
+static int azx_thaw_noirq(struct device *dev)
+{
+       struct pci_dev *pci = to_pci_dev(dev);
+
+       if (IS_SKL_PLUS(pci))
+               pci_set_power_state(pci, PCI_D0);
+
+       return 0;
+}
+#endif /* CONFIG_PM_SLEEP */
+
 #ifdef CONFIG_PM
 static int azx_runtime_suspend(struct device *dev)
 {
@@ -1036,6 +1093,10 @@ static int azx_runtime_idle(struct device *dev)
 
 static const struct dev_pm_ops azx_pm = {
        SET_SYSTEM_SLEEP_PM_OPS(azx_suspend, azx_resume)
+#ifdef CONFIG_PM_SLEEP
+       .freeze_noirq = azx_freeze_noirq,
+       .thaw_noirq = azx_thaw_noirq,
+#endif
        SET_RUNTIME_PM_OPS(azx_runtime_suspend, azx_runtime_resume, azx_runtime_idle)
 };
 
@@ -2124,6 +2185,9 @@ static const struct pci_device_id azx_ids[] = {
        /* Sunrise Point-LP */
        { PCI_DEVICE(0x8086, 0x9d70),
          .driver_data = AZX_DRIVER_PCH | AZX_DCAPS_INTEL_SKYLAKE },
+       /* Broxton-P(Apollolake) */
+       { PCI_DEVICE(0x8086, 0x5a98),
+         .driver_data = AZX_DRIVER_PCH | AZX_DCAPS_INTEL_BROXTON },
        /* Haswell */
        { PCI_DEVICE(0x8086, 0x0a0c),
          .driver_data = AZX_DRIVER_HDMI | AZX_DCAPS_INTEL_HASWELL },
index f8a12ca477f1ab775a101c8bb41876a11707477e..4ef2259f88cae3b1cf328880447dbf528ad42a95 100644 (file)
@@ -778,7 +778,8 @@ static const struct hda_pintbl alienware_pincfgs[] = {
 };
 
 static const struct snd_pci_quirk ca0132_quirks[] = {
-       SND_PCI_QUIRK(0x1028, 0x0685, "Alienware 15", QUIRK_ALIENWARE),
+       SND_PCI_QUIRK(0x1028, 0x0685, "Alienware 15 2015", QUIRK_ALIENWARE),
+       SND_PCI_QUIRK(0x1028, 0x0688, "Alienware 17 2015", QUIRK_ALIENWARE),
        {}
 };
 
index c8b8ef5246a6f94c99b281c837e220e118dbf8a9..ef198903c0c3e6bca1685c3cc6a53420e77e1333 100644 (file)
@@ -955,6 +955,7 @@ static int patch_conexant_auto(struct hda_codec *codec)
  */
 
 static const struct hda_device_id snd_hda_id_conexant[] = {
+       HDA_CODEC_ENTRY(0x14f12008, "CX8200", patch_conexant_auto),
        HDA_CODEC_ENTRY(0x14f15045, "CX20549 (Venice)", patch_conexant_auto),
        HDA_CODEC_ENTRY(0x14f15047, "CX20551 (Waikiki)", patch_conexant_auto),
        HDA_CODEC_ENTRY(0x14f15051, "CX20561 (Hermosa)", patch_conexant_auto),
@@ -972,9 +973,9 @@ static const struct hda_device_id snd_hda_id_conexant[] = {
        HDA_CODEC_ENTRY(0x14f150ac, "CX20652", patch_conexant_auto),
        HDA_CODEC_ENTRY(0x14f150b8, "CX20664", patch_conexant_auto),
        HDA_CODEC_ENTRY(0x14f150b9, "CX20665", patch_conexant_auto),
-       HDA_CODEC_ENTRY(0x14f150f1, "CX20721", patch_conexant_auto),
+       HDA_CODEC_ENTRY(0x14f150f1, "CX21722", patch_conexant_auto),
        HDA_CODEC_ENTRY(0x14f150f2, "CX20722", patch_conexant_auto),
-       HDA_CODEC_ENTRY(0x14f150f3, "CX20723", patch_conexant_auto),
+       HDA_CODEC_ENTRY(0x14f150f3, "CX21724", patch_conexant_auto),
        HDA_CODEC_ENTRY(0x14f150f4, "CX20724", patch_conexant_auto),
        HDA_CODEC_ENTRY(0x14f1510f, "CX20751/2", patch_conexant_auto),
        HDA_CODEC_ENTRY(0x14f15110, "CX20751/2", patch_conexant_auto),
index 60cd9e70090981076fcaec5bcb55cfd92ececdc9..4b6fb668c91cd1ba2e4964d49c0d610cab43c458 100644 (file)
@@ -2352,6 +2352,12 @@ static void intel_pin_eld_notify(void *audio_ptr, int port)
        struct hda_codec *codec = audio_ptr;
        int pin_nid = port + 0x04;
 
+       /* skip notification during system suspend (but not in runtime PM);
+        * the state will be updated at resume
+        */
+       if (snd_power_get_state(codec->card) != SNDRV_CTL_POWER_D0)
+               return;
+
        check_presence_and_report(codec, pin_nid);
 }
 
@@ -2378,7 +2384,8 @@ static int patch_generic_hdmi(struct hda_codec *codec)
         * can cover the codec power request, and so need not set this flag.
         * For previous platforms, there is no such power well feature.
         */
-       if (is_valleyview_plus(codec) || is_skylake(codec))
+       if (is_valleyview_plus(codec) || is_skylake(codec) ||
+                       is_broxton(codec))
                codec->core.link_power_control = 1;
 
        if (is_haswell_plus(codec) || is_valleyview_plus(codec)) {
index 2f7b065f9ac43e88ee19b6845506c066485c679a..fe96428aa40343f362237121f246e67b734c0446 100644 (file)
@@ -111,6 +111,7 @@ struct alc_spec {
        void (*power_hook)(struct hda_codec *codec);
 #endif
        void (*shutup)(struct hda_codec *codec);
+       void (*reboot_notify)(struct hda_codec *codec);
 
        int init_amp;
        int codec_variant;      /* flag for other variants */
@@ -773,6 +774,25 @@ static inline void alc_shutup(struct hda_codec *codec)
                snd_hda_shutup_pins(codec);
 }
 
+static void alc_reboot_notify(struct hda_codec *codec)
+{
+       struct alc_spec *spec = codec->spec;
+
+       if (spec && spec->reboot_notify)
+               spec->reboot_notify(codec);
+       else
+               alc_shutup(codec);
+}
+
+/* power down codec to D3 at reboot/shutdown; set as reboot_notify ops */
+static void alc_d3_at_reboot(struct hda_codec *codec)
+{
+       snd_hda_codec_set_power_to_all(codec, codec->core.afg, AC_PWRST_D3);
+       snd_hda_codec_write(codec, codec->core.afg, 0,
+                           AC_VERB_SET_POWER_STATE, AC_PWRST_D3);
+       msleep(10);
+}
+
 #define alc_free       snd_hda_gen_free
 
 #ifdef CONFIG_PM
@@ -818,7 +838,7 @@ static const struct hda_codec_ops alc_patch_ops = {
        .suspend = alc_suspend,
        .check_power_status = snd_hda_gen_check_power_status,
 #endif
-       .reboot_notify = alc_shutup,
+       .reboot_notify = alc_reboot_notify,
 };
 
 
@@ -1755,10 +1775,12 @@ enum {
        ALC889_FIXUP_MBA11_VREF,
        ALC889_FIXUP_MBA21_VREF,
        ALC889_FIXUP_MP11_VREF,
+       ALC889_FIXUP_MP41_VREF,
        ALC882_FIXUP_INV_DMIC,
        ALC882_FIXUP_NO_PRIMARY_HP,
        ALC887_FIXUP_ASUS_BASS,
        ALC887_FIXUP_BASS_CHMAP,
+       ALC882_FIXUP_DISABLE_AAMIX,
 };
 
 static void alc889_fixup_coef(struct hda_codec *codec,
@@ -1842,7 +1864,7 @@ static void alc889_fixup_mbp_vref(struct hda_codec *codec,
                                  const struct hda_fixup *fix, int action)
 {
        struct alc_spec *spec = codec->spec;
-       static hda_nid_t nids[2] = { 0x14, 0x15 };
+       static hda_nid_t nids[3] = { 0x14, 0x15, 0x19 };
        int i;
 
        if (action != HDA_FIXUP_ACT_INIT)
@@ -1920,6 +1942,8 @@ static void alc882_fixup_no_primary_hp(struct hda_codec *codec,
 
 static void alc_fixup_bass_chmap(struct hda_codec *codec,
                                 const struct hda_fixup *fix, int action);
+static void alc_fixup_disable_aamix(struct hda_codec *codec,
+                                   const struct hda_fixup *fix, int action);
 
 static const struct hda_fixup alc882_fixups[] = {
        [ALC882_FIXUP_ABIT_AW9D_MAX] = {
@@ -2130,6 +2154,12 @@ static const struct hda_fixup alc882_fixups[] = {
                .chained = true,
                .chain_id = ALC885_FIXUP_MACPRO_GPIO,
        },
+       [ALC889_FIXUP_MP41_VREF] = {
+               .type = HDA_FIXUP_FUNC,
+               .v.func = alc889_fixup_mbp_vref,
+               .chained = true,
+               .chain_id = ALC885_FIXUP_MACPRO_GPIO,
+       },
        [ALC882_FIXUP_INV_DMIC] = {
                .type = HDA_FIXUP_FUNC,
                .v.func = alc_fixup_inv_dmic,
@@ -2151,6 +2181,10 @@ static const struct hda_fixup alc882_fixups[] = {
                .type = HDA_FIXUP_FUNC,
                .v.func = alc_fixup_bass_chmap,
        },
+       [ALC882_FIXUP_DISABLE_AAMIX] = {
+               .type = HDA_FIXUP_FUNC,
+               .v.func = alc_fixup_disable_aamix,
+       },
 };
 
 static const struct snd_pci_quirk alc882_fixup_tbl[] = {
@@ -2208,7 +2242,7 @@ static const struct snd_pci_quirk alc882_fixup_tbl[] = {
        SND_PCI_QUIRK(0x106b, 0x3f00, "Macbook 5,1", ALC889_FIXUP_IMAC91_VREF),
        SND_PCI_QUIRK(0x106b, 0x4000, "MacbookPro 5,1", ALC889_FIXUP_IMAC91_VREF),
        SND_PCI_QUIRK(0x106b, 0x4100, "Macmini 3,1", ALC889_FIXUP_IMAC91_VREF),
-       SND_PCI_QUIRK(0x106b, 0x4200, "Mac Pro 5,1", ALC885_FIXUP_MACPRO_GPIO),
+       SND_PCI_QUIRK(0x106b, 0x4200, "Mac Pro 4,1/5,1", ALC889_FIXUP_MP41_VREF),
        SND_PCI_QUIRK(0x106b, 0x4300, "iMac 9,1", ALC889_FIXUP_IMAC91_VREF),
        SND_PCI_QUIRK(0x106b, 0x4600, "MacbookPro 5,2", ALC889_FIXUP_IMAC91_VREF),
        SND_PCI_QUIRK(0x106b, 0x4900, "iMac 9,1 Aluminum", ALC889_FIXUP_IMAC91_VREF),
@@ -2218,6 +2252,7 @@ static const struct snd_pci_quirk alc882_fixup_tbl[] = {
        SND_PCI_QUIRK(0x1462, 0x7350, "MSI-7350", ALC889_FIXUP_CD),
        SND_PCI_QUIRK_VENDOR(0x1462, "MSI", ALC882_FIXUP_GPIO3),
        SND_PCI_QUIRK(0x1458, 0xa002, "Gigabyte EP45-DS3/Z87X-UD3H", ALC889_FIXUP_FRONT_HP_NO_PRESENCE),
+       SND_PCI_QUIRK(0x1458, 0xa182, "Gigabyte Z170X-UD3", ALC882_FIXUP_DISABLE_AAMIX),
        SND_PCI_QUIRK(0x147b, 0x107a, "Abit AW9D-MAX", ALC882_FIXUP_ABIT_AW9D_MAX),
        SND_PCI_QUIRK_VENDOR(0x1558, "Clevo laptop", ALC882_FIXUP_EAPD),
        SND_PCI_QUIRK(0x161f, 0x2054, "Medion laptop", ALC883_FIXUP_EAPD),
@@ -4190,6 +4225,8 @@ static void alc_fixup_tpt440_dock(struct hda_codec *codec,
        struct alc_spec *spec = codec->spec;
 
        if (action == HDA_FIXUP_ACT_PRE_PROBE) {
+               spec->shutup = alc_no_shutup; /* reduce click noise */
+               spec->reboot_notify = alc_d3_at_reboot; /* reduce noise */
                spec->parse_flags = HDA_PINCFG_NO_HP_FIXUP;
                codec->power_save_node = 0; /* avoid click noises */
                snd_hda_apply_pincfgs(codec, pincfgs);
@@ -4570,6 +4607,7 @@ enum {
        ALC255_FIXUP_HEADSET_MODE_NO_HP_MIC,
        ALC293_FIXUP_DELL1_MIC_NO_PRESENCE,
        ALC292_FIXUP_TPT440_DOCK,
+       ALC292_FIXUP_TPT440,
        ALC283_FIXUP_BXBT2807_MIC,
        ALC255_FIXUP_DELL_WMI_MIC_MUTE_LED,
        ALC282_FIXUP_ASPIRE_V5_PINS,
@@ -4585,8 +4623,11 @@ enum {
        ALC288_FIXUP_DISABLE_AAMIX,
        ALC292_FIXUP_DELL_E7X,
        ALC292_FIXUP_DISABLE_AAMIX,
+       ALC293_FIXUP_DISABLE_AAMIX_MULTIJACK,
        ALC298_FIXUP_DELL1_MIC_NO_PRESENCE,
        ALC275_FIXUP_DELL_XPS,
+       ALC256_FIXUP_DELL_XPS_13_HEADPHONE_NOISE,
+       ALC293_FIXUP_LENOVO_SPK_NOISE,
 };
 
 static const struct hda_fixup alc269_fixups[] = {
@@ -5041,6 +5082,12 @@ static const struct hda_fixup alc269_fixups[] = {
                .chained = true,
                .chain_id = ALC269_FIXUP_LIMIT_INT_MIC_BOOST
        },
+       [ALC292_FIXUP_TPT440] = {
+               .type = HDA_FIXUP_FUNC,
+               .v.func = alc_fixup_disable_aamix,
+               .chained = true,
+               .chain_id = ALC292_FIXUP_TPT440_DOCK,
+       },
        [ALC283_FIXUP_BXBT2807_MIC] = {
                .type = HDA_FIXUP_PINS,
                .v.pins = (const struct hda_pintbl[]) {
@@ -5140,6 +5187,12 @@ static const struct hda_fixup alc269_fixups[] = {
                .chained = true,
                .chain_id = ALC269_FIXUP_DELL2_MIC_NO_PRESENCE
        },
+       [ALC293_FIXUP_DISABLE_AAMIX_MULTIJACK] = {
+               .type = HDA_FIXUP_FUNC,
+               .v.func = alc_fixup_disable_aamix,
+               .chained = true,
+               .chain_id = ALC293_FIXUP_DELL1_MIC_NO_PRESENCE
+       },
        [ALC292_FIXUP_DELL_E7X] = {
                .type = HDA_FIXUP_FUNC,
                .v.func = alc_fixup_dell_xps13,
@@ -5167,6 +5220,23 @@ static const struct hda_fixup alc269_fixups[] = {
                        {}
                }
        },
+       [ALC256_FIXUP_DELL_XPS_13_HEADPHONE_NOISE] = {
+               .type = HDA_FIXUP_VERBS,
+               .v.verbs = (const struct hda_verb[]) {
+                       /* Disable pass-through path for FRONT 14h */
+                       {0x20, AC_VERB_SET_COEF_INDEX, 0x36},
+                       {0x20, AC_VERB_SET_PROC_COEF, 0x1737},
+                       {}
+               },
+               .chained = true,
+               .chain_id = ALC255_FIXUP_DELL1_MIC_NO_PRESENCE
+       },
+       [ALC293_FIXUP_LENOVO_SPK_NOISE] = {
+               .type = HDA_FIXUP_FUNC,
+               .v.func = alc_fixup_disable_aamix,
+               .chained = true,
+               .chain_id = ALC269_FIXUP_THINKPAD_ACPI
+       },
 };
 
 static const struct snd_pci_quirk alc269_fixup_tbl[] = {
@@ -5180,8 +5250,10 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = {
        SND_PCI_QUIRK(0x1025, 0x0742, "Acer AO756", ALC271_FIXUP_HP_GATE_MIC_JACK),
        SND_PCI_QUIRK(0x1025, 0x0775, "Acer Aspire E1-572", ALC271_FIXUP_HP_GATE_MIC_JACK_E1_572),
        SND_PCI_QUIRK(0x1025, 0x079b, "Acer Aspire V5-573G", ALC282_FIXUP_ASPIRE_V5_PINS),
+       SND_PCI_QUIRK(0x1025, 0x106d, "Acer Cloudbook 14", ALC283_FIXUP_CHROME_BOOK),
        SND_PCI_QUIRK(0x1028, 0x0470, "Dell M101z", ALC269_FIXUP_DELL_M101Z),
        SND_PCI_QUIRK(0x1028, 0x054b, "Dell XPS one 2710", ALC275_FIXUP_DELL_XPS),
+       SND_PCI_QUIRK(0x1028, 0x05bd, "Dell Latitude E6440", ALC292_FIXUP_DELL_E7X),
        SND_PCI_QUIRK(0x1028, 0x05ca, "Dell Latitude E7240", ALC292_FIXUP_DELL_E7X),
        SND_PCI_QUIRK(0x1028, 0x05cb, "Dell Latitude E7440", ALC292_FIXUP_DELL_E7X),
        SND_PCI_QUIRK(0x1028, 0x05da, "Dell Vostro 5460", ALC290_FIXUP_SUBWOOFER),
@@ -5199,11 +5271,12 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = {
        SND_PCI_QUIRK(0x1028, 0x06c7, "Dell", ALC255_FIXUP_DELL1_MIC_NO_PRESENCE),
        SND_PCI_QUIRK(0x1028, 0x06d9, "Dell", ALC293_FIXUP_DELL1_MIC_NO_PRESENCE),
        SND_PCI_QUIRK(0x1028, 0x06da, "Dell", ALC293_FIXUP_DELL1_MIC_NO_PRESENCE),
-       SND_PCI_QUIRK(0x1028, 0x06db, "Dell", ALC292_FIXUP_DISABLE_AAMIX),
-       SND_PCI_QUIRK(0x1028, 0x06dd, "Dell", ALC292_FIXUP_DISABLE_AAMIX),
-       SND_PCI_QUIRK(0x1028, 0x06de, "Dell", ALC292_FIXUP_DISABLE_AAMIX),
-       SND_PCI_QUIRK(0x1028, 0x06df, "Dell", ALC292_FIXUP_DISABLE_AAMIX),
-       SND_PCI_QUIRK(0x1028, 0x06e0, "Dell", ALC292_FIXUP_DISABLE_AAMIX),
+       SND_PCI_QUIRK(0x1028, 0x06db, "Dell", ALC293_FIXUP_DISABLE_AAMIX_MULTIJACK),
+       SND_PCI_QUIRK(0x1028, 0x06dd, "Dell", ALC293_FIXUP_DISABLE_AAMIX_MULTIJACK),
+       SND_PCI_QUIRK(0x1028, 0x06de, "Dell", ALC293_FIXUP_DISABLE_AAMIX_MULTIJACK),
+       SND_PCI_QUIRK(0x1028, 0x06df, "Dell", ALC293_FIXUP_DISABLE_AAMIX_MULTIJACK),
+       SND_PCI_QUIRK(0x1028, 0x06e0, "Dell", ALC293_FIXUP_DISABLE_AAMIX_MULTIJACK),
+       SND_PCI_QUIRK(0x1028, 0x0704, "Dell XPS 13", ALC256_FIXUP_DELL_XPS_13_HEADPHONE_NOISE),
        SND_PCI_QUIRK(0x1028, 0x164a, "Dell", ALC293_FIXUP_DELL1_MIC_NO_PRESENCE),
        SND_PCI_QUIRK(0x1028, 0x164b, "Dell", ALC293_FIXUP_DELL1_MIC_NO_PRESENCE),
        SND_PCI_QUIRK(0x103c, 0x1586, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC2),
@@ -5302,15 +5375,17 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = {
        SND_PCI_QUIRK(0x17aa, 0x21fb, "Thinkpad T430s", ALC269_FIXUP_LENOVO_DOCK),
        SND_PCI_QUIRK(0x17aa, 0x2203, "Thinkpad X230 Tablet", ALC269_FIXUP_LENOVO_DOCK),
        SND_PCI_QUIRK(0x17aa, 0x2208, "Thinkpad T431s", ALC269_FIXUP_LENOVO_DOCK),
-       SND_PCI_QUIRK(0x17aa, 0x220c, "Thinkpad T440s", ALC292_FIXUP_TPT440_DOCK),
+       SND_PCI_QUIRK(0x17aa, 0x220c, "Thinkpad T440s", ALC292_FIXUP_TPT440),
        SND_PCI_QUIRK(0x17aa, 0x220e, "Thinkpad T440p", ALC292_FIXUP_TPT440_DOCK),
        SND_PCI_QUIRK(0x17aa, 0x2210, "Thinkpad T540p", ALC292_FIXUP_TPT440_DOCK),
        SND_PCI_QUIRK(0x17aa, 0x2211, "Thinkpad W541", ALC292_FIXUP_TPT440_DOCK),
        SND_PCI_QUIRK(0x17aa, 0x2212, "Thinkpad T440", ALC292_FIXUP_TPT440_DOCK),
        SND_PCI_QUIRK(0x17aa, 0x2214, "Thinkpad X240", ALC292_FIXUP_TPT440_DOCK),
        SND_PCI_QUIRK(0x17aa, 0x2215, "Thinkpad", ALC269_FIXUP_LIMIT_INT_MIC_BOOST),
+       SND_PCI_QUIRK(0x17aa, 0x2218, "Thinkpad X1 Carbon 2nd", ALC292_FIXUP_TPT440_DOCK),
        SND_PCI_QUIRK(0x17aa, 0x2223, "ThinkPad T550", ALC292_FIXUP_TPT440_DOCK),
        SND_PCI_QUIRK(0x17aa, 0x2226, "ThinkPad X250", ALC292_FIXUP_TPT440_DOCK),
+       SND_PCI_QUIRK(0x17aa, 0x2233, "Thinkpad", ALC293_FIXUP_LENOVO_SPK_NOISE),
        SND_PCI_QUIRK(0x17aa, 0x3977, "IdeaPad S210", ALC283_FIXUP_INT_MIC),
        SND_PCI_QUIRK(0x17aa, 0x3978, "IdeaPad Y410P", ALC269_FIXUP_NO_SHUTUP),
        SND_PCI_QUIRK(0x17aa, 0x5013, "Thinkpad", ALC269_FIXUP_LIMIT_INT_MIC_BOOST),
@@ -5320,6 +5395,7 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = {
        SND_PCI_QUIRK(0x17aa, 0x5034, "Thinkpad T450", ALC292_FIXUP_TPT440_DOCK),
        SND_PCI_QUIRK(0x17aa, 0x5036, "Thinkpad T450s", ALC292_FIXUP_TPT440_DOCK),
        SND_PCI_QUIRK(0x17aa, 0x503c, "Thinkpad L450", ALC292_FIXUP_TPT440_DOCK),
+       SND_PCI_QUIRK(0x17aa, 0x504b, "Thinkpad", ALC293_FIXUP_LENOVO_SPK_NOISE),
        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),
@@ -5400,6 +5476,7 @@ static const struct hda_model_fixup alc269_fixup_models[] = {
        {.id = ALC283_FIXUP_CHROME_BOOK, .name = "alc283-dac-wcaps"},
        {.id = ALC283_FIXUP_SENSE_COMBO_JACK, .name = "alc283-sense-combo"},
        {.id = ALC292_FIXUP_TPT440_DOCK, .name = "tpt440-dock"},
+       {.id = ALC292_FIXUP_TPT440, .name = "tpt440"},
        {}
 };
 
@@ -6386,6 +6463,7 @@ static const struct hda_fixup alc662_fixups[] = {
 static const struct snd_pci_quirk alc662_fixup_tbl[] = {
        SND_PCI_QUIRK(0x1019, 0x9087, "ECS", ALC662_FIXUP_ASUS_MODE2),
        SND_PCI_QUIRK(0x1025, 0x022f, "Acer Aspire One", ALC662_FIXUP_INV_DMIC),
+       SND_PCI_QUIRK(0x1025, 0x0241, "Packard Bell DOTS", ALC662_FIXUP_INV_DMIC),
        SND_PCI_QUIRK(0x1025, 0x0308, "Acer Aspire 8942G", ALC662_FIXUP_ASPIRE),
        SND_PCI_QUIRK(0x1025, 0x031c, "Gateway NV79", ALC662_FIXUP_SKU_IGNORE),
        SND_PCI_QUIRK(0x1025, 0x0349, "eMachines eM250", ALC662_FIXUP_INV_DMIC),
index 826122d8aceec4a931e64e99875dcd8cef661736..2c7c5eb8b1e9514779b78bc278412803862062e9 100644 (file)
@@ -3110,6 +3110,29 @@ static void stac92hd71bxx_fixup_hp_hdx(struct hda_codec *codec,
        spec->gpio_led = 0x08;
 }
 
+static bool is_hp_output(struct hda_codec *codec, hda_nid_t pin)
+{
+       unsigned int pin_cfg = snd_hda_codec_get_pincfg(codec, pin);
+
+       /* count line-out, too, as BIOS sets often so */
+       return get_defcfg_connect(pin_cfg) != AC_JACK_PORT_NONE &&
+               (get_defcfg_device(pin_cfg) == AC_JACK_LINE_OUT ||
+                get_defcfg_device(pin_cfg) == AC_JACK_HP_OUT);
+}
+
+static void fixup_hp_headphone(struct hda_codec *codec, hda_nid_t pin)
+{
+       unsigned int pin_cfg = snd_hda_codec_get_pincfg(codec, pin);
+
+       /* It was changed in the BIOS to just satisfy MS DTM.
+        * Lets turn it back into slaved HP
+        */
+       pin_cfg = (pin_cfg & (~AC_DEFCFG_DEVICE)) |
+               (AC_JACK_HP_OUT << AC_DEFCFG_DEVICE_SHIFT);
+       pin_cfg = (pin_cfg & (~(AC_DEFCFG_DEF_ASSOC | AC_DEFCFG_SEQUENCE))) |
+               0x1f;
+       snd_hda_codec_set_pincfg(codec, pin, pin_cfg);
+}
 
 static void stac92hd71bxx_fixup_hp(struct hda_codec *codec,
                                   const struct hda_fixup *fix, int action)
@@ -3119,22 +3142,12 @@ static void stac92hd71bxx_fixup_hp(struct hda_codec *codec,
        if (action != HDA_FIXUP_ACT_PRE_PROBE)
                return;
 
-       if (hp_blike_system(codec->core.subsystem_id)) {
-               unsigned int pin_cfg = snd_hda_codec_get_pincfg(codec, 0x0f);
-               if (get_defcfg_device(pin_cfg) == AC_JACK_LINE_OUT ||
-                       get_defcfg_device(pin_cfg) == AC_JACK_SPEAKER  ||
-                       get_defcfg_device(pin_cfg) == AC_JACK_HP_OUT) {
-                       /* It was changed in the BIOS to just satisfy MS DTM.
-                        * Lets turn it back into slaved HP
-                        */
-                       pin_cfg = (pin_cfg & (~AC_DEFCFG_DEVICE))
-                                       | (AC_JACK_HP_OUT <<
-                                               AC_DEFCFG_DEVICE_SHIFT);
-                       pin_cfg = (pin_cfg & (~(AC_DEFCFG_DEF_ASSOC
-                                                       | AC_DEFCFG_SEQUENCE)))
-                                                               | 0x1f;
-                       snd_hda_codec_set_pincfg(codec, 0x0f, pin_cfg);
-               }
+       /* when both output A and F are assigned, these are supposedly
+        * dock and built-in headphones; fix both pin configs
+        */
+       if (is_hp_output(codec, 0x0a) && is_hp_output(codec, 0x0f)) {
+               fixup_hp_headphone(codec, 0x0a);
+               fixup_hp_headphone(codec, 0x0f);
        }
 
        if (find_mute_led_cfg(codec, 1))
index 714df906249eab42c54816fed4630cc4890d7603..41c31db650390c651617530ce08b44e11a889e2f 100644 (file)
@@ -741,10 +741,11 @@ snd_rme96_playback_setrate(struct rme96 *rme96,
        {
                /* change to/from double-speed: reset the DAC (if available) */
                snd_rme96_reset_dac(rme96);
+               return 1; /* need to restore volume */
        } else {
                writel(rme96->wcreg, rme96->iobase + RME96_IO_CONTROL_REGISTER);
+               return 0;
        }
-       return 0;
 }
 
 static int
@@ -980,6 +981,7 @@ snd_rme96_playback_hw_params(struct snd_pcm_substream *substream,
        struct rme96 *rme96 = snd_pcm_substream_chip(substream);
        struct snd_pcm_runtime *runtime = substream->runtime;
        int err, rate, dummy;
+       bool apply_dac_volume = false;
 
        runtime->dma_area = (void __force *)(rme96->iobase +
                                             RME96_IO_PLAY_BUFFER);
@@ -993,24 +995,26 @@ snd_rme96_playback_hw_params(struct snd_pcm_substream *substream,
        {
                 /* slave clock */
                 if ((int)params_rate(params) != rate) {
-                       spin_unlock_irq(&rme96->lock);
-                       return -EIO;                    
-                }
-       } else if ((err = snd_rme96_playback_setrate(rme96, params_rate(params))) < 0) {
-               spin_unlock_irq(&rme96->lock);
-               return err;
-       }
-       if ((err = snd_rme96_playback_setformat(rme96, params_format(params))) < 0) {
-               spin_unlock_irq(&rme96->lock);
-               return err;
+                       err = -EIO;
+                       goto error;
+               }
+       } else {
+               err = snd_rme96_playback_setrate(rme96, params_rate(params));
+               if (err < 0)
+                       goto error;
+               apply_dac_volume = err > 0; /* need to restore volume later? */
        }
+
+       err = snd_rme96_playback_setformat(rme96, params_format(params));
+       if (err < 0)
+               goto error;
        snd_rme96_setframelog(rme96, params_channels(params), 1);
        if (rme96->capture_periodsize != 0) {
                if (params_period_size(params) << rme96->playback_frlog !=
                    rme96->capture_periodsize)
                {
-                       spin_unlock_irq(&rme96->lock);
-                       return -EBUSY;
+                       err = -EBUSY;
+                       goto error;
                }
        }
        rme96->playback_periodsize =
@@ -1021,9 +1025,16 @@ snd_rme96_playback_hw_params(struct snd_pcm_substream *substream,
                rme96->wcreg &= ~(RME96_WCR_PRO | RME96_WCR_DOLBY | RME96_WCR_EMP);
                writel(rme96->wcreg |= rme96->wcreg_spdif_stream, rme96->iobase + RME96_IO_CONTROL_REGISTER);
        }
+
+       err = 0;
+ error:
        spin_unlock_irq(&rme96->lock);
-               
-       return 0;
+       if (apply_dac_volume) {
+               usleep_range(3000, 10000);
+               snd_rme96_apply_dac_volume(rme96);
+       }
+
+       return err;
 }
 
 static int
index 7ff7d88e46ddd60796ada2b64c67bd6e3816ce6f..7ea66ee3653ffeec0ca1bbb24aeb29224f06f272 100644 (file)
@@ -38,6 +38,7 @@ config SND_SOC_TOPOLOGY
 
 # All the supported SoCs
 source "sound/soc/adi/Kconfig"
+source "sound/soc/amd/Kconfig"
 source "sound/soc/atmel/Kconfig"
 source "sound/soc/au1x/Kconfig"
 source "sound/soc/bcm/Kconfig"
@@ -50,6 +51,7 @@ source "sound/soc/jz4740/Kconfig"
 source "sound/soc/nuc900/Kconfig"
 source "sound/soc/omap/Kconfig"
 source "sound/soc/kirkwood/Kconfig"
+source "sound/soc/img/Kconfig"
 source "sound/soc/intel/Kconfig"
 source "sound/soc/mediatek/Kconfig"
 source "sound/soc/mxs/Kconfig"
index 8eb06db32fa0dcd53bf2ed7ee3bd94fb92df7adb..9a30f21d16ee8efb2ddfcb84e757245e1b395bee 100644 (file)
@@ -18,6 +18,7 @@ obj-$(CONFIG_SND_SOC) += snd-soc-core.o
 obj-$(CONFIG_SND_SOC)  += codecs/
 obj-$(CONFIG_SND_SOC)  += generic/
 obj-$(CONFIG_SND_SOC)  += adi/
+obj-$(CONFIG_SND_SOC)  += amd/
 obj-$(CONFIG_SND_SOC)  += atmel/
 obj-$(CONFIG_SND_SOC)  += au1x/
 obj-$(CONFIG_SND_SOC)  += bcm/
@@ -27,6 +28,7 @@ obj-$(CONFIG_SND_SOC) += davinci/
 obj-$(CONFIG_SND_SOC)  += dwc/
 obj-$(CONFIG_SND_SOC)  += fsl/
 obj-$(CONFIG_SND_SOC)  += jz4740/
+obj-$(CONFIG_SND_SOC)  += img/
 obj-$(CONFIG_SND_SOC)  += intel/
 obj-$(CONFIG_SND_SOC)  += mediatek/
 obj-$(CONFIG_SND_SOC)  += mxs/
diff --git a/sound/soc/amd/Kconfig b/sound/soc/amd/Kconfig
new file mode 100644 (file)
index 0000000..78187eb
--- /dev/null
@@ -0,0 +1,4 @@
+config SND_SOC_AMD_ACP
+       tristate "AMD Audio Coprocessor support"
+       help
+        This option enables ACP DMA support on AMD platform.
diff --git a/sound/soc/amd/Makefile b/sound/soc/amd/Makefile
new file mode 100644 (file)
index 0000000..1a66ec0
--- /dev/null
@@ -0,0 +1,3 @@
+snd-soc-acp-pcm-objs   := acp-pcm-dma.o
+
+obj-$(CONFIG_SND_SOC_AMD_ACP) += snd-soc-acp-pcm.o
diff --git a/sound/soc/amd/acp-pcm-dma.c b/sound/soc/amd/acp-pcm-dma.c
new file mode 100644 (file)
index 0000000..3191e0a
--- /dev/null
@@ -0,0 +1,1043 @@
+/*
+ * AMD ALSA SoC PCM Driver for ACP 2.x
+ *
+ * Copyright 2014-2015 Advanced Micro Devices, Inc.
+ *
+ * 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/delay.h>
+#include <linux/io.h>
+#include <linux/sizes.h>
+#include <linux/pm_runtime.h>
+
+#include <sound/soc.h>
+
+#include "acp.h"
+
+#define PLAYBACK_MIN_NUM_PERIODS    2
+#define PLAYBACK_MAX_NUM_PERIODS    2
+#define PLAYBACK_MAX_PERIOD_SIZE    16384
+#define PLAYBACK_MIN_PERIOD_SIZE    1024
+#define CAPTURE_MIN_NUM_PERIODS     2
+#define CAPTURE_MAX_NUM_PERIODS     2
+#define CAPTURE_MAX_PERIOD_SIZE     16384
+#define CAPTURE_MIN_PERIOD_SIZE     1024
+
+#define MAX_BUFFER (PLAYBACK_MAX_PERIOD_SIZE * PLAYBACK_MAX_NUM_PERIODS)
+#define MIN_BUFFER MAX_BUFFER
+
+static const struct snd_pcm_hardware acp_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_BATCH |
+               SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_RESUME,
+       .formats = SNDRV_PCM_FMTBIT_S16_LE |
+               SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE,
+       .channels_min = 1,
+       .channels_max = 8,
+       .rates = SNDRV_PCM_RATE_8000_96000,
+       .rate_min = 8000,
+       .rate_max = 96000,
+       .buffer_bytes_max = PLAYBACK_MAX_NUM_PERIODS * PLAYBACK_MAX_PERIOD_SIZE,
+       .period_bytes_min = PLAYBACK_MIN_PERIOD_SIZE,
+       .period_bytes_max = PLAYBACK_MAX_PERIOD_SIZE,
+       .periods_min = PLAYBACK_MIN_NUM_PERIODS,
+       .periods_max = PLAYBACK_MAX_NUM_PERIODS,
+};
+
+static const struct snd_pcm_hardware acp_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_BATCH |
+           SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_RESUME,
+       .formats = SNDRV_PCM_FMTBIT_S16_LE |
+               SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE,
+       .channels_min = 1,
+       .channels_max = 2,
+       .rates = SNDRV_PCM_RATE_8000_48000,
+       .rate_min = 8000,
+       .rate_max = 48000,
+       .buffer_bytes_max = CAPTURE_MAX_NUM_PERIODS * CAPTURE_MAX_PERIOD_SIZE,
+       .period_bytes_min = CAPTURE_MIN_PERIOD_SIZE,
+       .period_bytes_max = CAPTURE_MAX_PERIOD_SIZE,
+       .periods_min = CAPTURE_MIN_NUM_PERIODS,
+       .periods_max = CAPTURE_MAX_NUM_PERIODS,
+};
+
+struct audio_drv_data {
+       struct snd_pcm_substream *play_stream;
+       struct snd_pcm_substream *capture_stream;
+       void __iomem *acp_mmio;
+};
+
+static u32 acp_reg_read(void __iomem *acp_mmio, u32 reg)
+{
+       return readl(acp_mmio + (reg * 4));
+}
+
+static void acp_reg_write(u32 val, void __iomem *acp_mmio, u32 reg)
+{
+       writel(val, acp_mmio + (reg * 4));
+}
+
+/* Configure a given dma channel parameters - enable/disble,
+ * number of descriptors, priority
+ */
+static void config_acp_dma_channel(void __iomem *acp_mmio, u8 ch_num,
+                                  u16 dscr_strt_idx, u16 num_dscrs,
+                                  enum acp_dma_priority_level priority_level)
+{
+       u32 dma_ctrl;
+
+       /* disable the channel run field */
+       dma_ctrl = acp_reg_read(acp_mmio, mmACP_DMA_CNTL_0 + ch_num);
+       dma_ctrl &= ~ACP_DMA_CNTL_0__DMAChRun_MASK;
+       acp_reg_write(dma_ctrl, acp_mmio, mmACP_DMA_CNTL_0 + ch_num);
+
+       /* program a DMA channel with first descriptor to be processed. */
+       acp_reg_write((ACP_DMA_DSCR_STRT_IDX_0__DMAChDscrStrtIdx_MASK
+                       & dscr_strt_idx),
+                       acp_mmio, mmACP_DMA_DSCR_STRT_IDX_0 + ch_num);
+
+       /* program a DMA channel with the number of descriptors to be
+        * processed in the transfer
+       */
+       acp_reg_write(ACP_DMA_DSCR_CNT_0__DMAChDscrCnt_MASK & num_dscrs,
+               acp_mmio, mmACP_DMA_DSCR_CNT_0 + ch_num);
+
+       /* set DMA channel priority */
+       acp_reg_write(priority_level, acp_mmio, mmACP_DMA_PRIO_0 + ch_num);
+}
+
+/* Initialize a dma descriptor in SRAM based on descritor information passed */
+static void config_dma_descriptor_in_sram(void __iomem *acp_mmio,
+                                         u16 descr_idx,
+                                         acp_dma_dscr_transfer_t *descr_info)
+{
+       u32 sram_offset;
+
+       sram_offset = (descr_idx * sizeof(acp_dma_dscr_transfer_t));
+
+       /* program the source base address. */
+       acp_reg_write(sram_offset, acp_mmio, mmACP_SRBM_Targ_Idx_Addr);
+       acp_reg_write(descr_info->src,  acp_mmio, mmACP_SRBM_Targ_Idx_Data);
+       /* program the destination base address. */
+       acp_reg_write(sram_offset + 4,  acp_mmio, mmACP_SRBM_Targ_Idx_Addr);
+       acp_reg_write(descr_info->dest, acp_mmio, mmACP_SRBM_Targ_Idx_Data);
+
+       /* program the number of bytes to be transferred for this descriptor. */
+       acp_reg_write(sram_offset + 8,  acp_mmio, mmACP_SRBM_Targ_Idx_Addr);
+       acp_reg_write(descr_info->xfer_val, acp_mmio, mmACP_SRBM_Targ_Idx_Data);
+}
+
+/* Initialize the DMA descriptor information for transfer between
+ * system memory <-> ACP SRAM
+ */
+static void set_acp_sysmem_dma_descriptors(void __iomem *acp_mmio,
+                                          u32 size, int direction,
+                                          u32 pte_offset)
+{
+       u16 i;
+       u16 dma_dscr_idx = PLAYBACK_START_DMA_DESCR_CH12;
+       acp_dma_dscr_transfer_t dmadscr[NUM_DSCRS_PER_CHANNEL];
+
+       for (i = 0; i < NUM_DSCRS_PER_CHANNEL; i++) {
+               dmadscr[i].xfer_val = 0;
+               if (direction == SNDRV_PCM_STREAM_PLAYBACK) {
+                       dma_dscr_idx = PLAYBACK_START_DMA_DESCR_CH12 + i;
+                       dmadscr[i].dest = ACP_SHARED_RAM_BANK_1_ADDRESS +
+                                       (size / 2) - (i * (size/2));
+                       dmadscr[i].src = ACP_INTERNAL_APERTURE_WINDOW_0_ADDRESS
+                               + (pte_offset * SZ_4K) + (i * (size/2));
+                       dmadscr[i].xfer_val |=
+                       (ACP_DMA_ATTRIBUTES_DAGB_ONION_TO_SHAREDMEM << 16) |
+                       (size / 2);
+               } else {
+                       dma_dscr_idx = CAPTURE_START_DMA_DESCR_CH14 + i;
+                       dmadscr[i].src = ACP_SHARED_RAM_BANK_5_ADDRESS +
+                                       (i * (size/2));
+                       dmadscr[i].dest = ACP_INTERNAL_APERTURE_WINDOW_0_ADDRESS
+                                               + (pte_offset * SZ_4K) +
+                                               (i * (size/2));
+                       dmadscr[i].xfer_val |=
+                       BIT(22) |
+                       (ACP_DMA_ATTRIBUTES_SHAREDMEM_TO_DAGB_ONION << 16) |
+                       (size / 2);
+               }
+               config_dma_descriptor_in_sram(acp_mmio, dma_dscr_idx,
+                                               &dmadscr[i]);
+       }
+       if (direction == SNDRV_PCM_STREAM_PLAYBACK)
+               config_acp_dma_channel(acp_mmio, SYSRAM_TO_ACP_CH_NUM,
+                                       PLAYBACK_START_DMA_DESCR_CH12,
+                                       NUM_DSCRS_PER_CHANNEL,
+                                       ACP_DMA_PRIORITY_LEVEL_NORMAL);
+       else
+               config_acp_dma_channel(acp_mmio, ACP_TO_SYSRAM_CH_NUM,
+                                       CAPTURE_START_DMA_DESCR_CH14,
+                                       NUM_DSCRS_PER_CHANNEL,
+                                       ACP_DMA_PRIORITY_LEVEL_NORMAL);
+}
+
+/* Initialize the DMA descriptor information for transfer between
+ * ACP SRAM <-> I2S
+ */
+static void set_acp_to_i2s_dma_descriptors(void __iomem *acp_mmio,
+                                          u32 size, int direction)
+{
+
+       u16 i;
+       u16 dma_dscr_idx = PLAYBACK_START_DMA_DESCR_CH13;
+       acp_dma_dscr_transfer_t dmadscr[NUM_DSCRS_PER_CHANNEL];
+
+       for (i = 0; i < NUM_DSCRS_PER_CHANNEL; i++) {
+               dmadscr[i].xfer_val = 0;
+               if (direction == SNDRV_PCM_STREAM_PLAYBACK) {
+                       dma_dscr_idx = PLAYBACK_START_DMA_DESCR_CH13 + i;
+                       dmadscr[i].src = ACP_SHARED_RAM_BANK_1_ADDRESS +
+                                        (i * (size/2));
+                       /* dmadscr[i].dest is unused by hardware. */
+                       dmadscr[i].dest = 0;
+                       dmadscr[i].xfer_val |= BIT(22) | (TO_ACP_I2S_1 << 16) |
+                                               (size / 2);
+               } else {
+                       dma_dscr_idx = CAPTURE_START_DMA_DESCR_CH15 + i;
+                       /* dmadscr[i].src is unused by hardware. */
+                       dmadscr[i].src = 0;
+                       dmadscr[i].dest = ACP_SHARED_RAM_BANK_5_ADDRESS +
+                                       (i * (size / 2));
+                       dmadscr[i].xfer_val |= BIT(22) |
+                                       (FROM_ACP_I2S_1 << 16) | (size / 2);
+               }
+               config_dma_descriptor_in_sram(acp_mmio, dma_dscr_idx,
+                                               &dmadscr[i]);
+       }
+       /* Configure the DMA channel with the above descriptore */
+       if (direction == SNDRV_PCM_STREAM_PLAYBACK)
+               config_acp_dma_channel(acp_mmio, ACP_TO_I2S_DMA_CH_NUM,
+                                       PLAYBACK_START_DMA_DESCR_CH13,
+                                       NUM_DSCRS_PER_CHANNEL,
+                                       ACP_DMA_PRIORITY_LEVEL_NORMAL);
+       else
+               config_acp_dma_channel(acp_mmio, I2S_TO_ACP_DMA_CH_NUM,
+                                       CAPTURE_START_DMA_DESCR_CH15,
+                                       NUM_DSCRS_PER_CHANNEL,
+                                       ACP_DMA_PRIORITY_LEVEL_NORMAL);
+}
+
+/* Create page table entries in ACP SRAM for the allocated memory */
+static void acp_pte_config(void __iomem *acp_mmio, struct page *pg,
+                          u16 num_of_pages, u32 pte_offset)
+{
+       u16 page_idx;
+       u64 addr;
+       u32 low;
+       u32 high;
+       u32 offset;
+
+       offset  = ACP_DAGB_GRP_SRBM_SRAM_BASE_OFFSET + (pte_offset * 8);
+       for (page_idx = 0; page_idx < (num_of_pages); page_idx++) {
+               /* Load the low address of page int ACP SRAM through SRBM */
+               acp_reg_write((offset + (page_idx * 8)),
+                       acp_mmio, mmACP_SRBM_Targ_Idx_Addr);
+               addr = page_to_phys(pg);
+
+               low = lower_32_bits(addr);
+               high = upper_32_bits(addr);
+
+               acp_reg_write(low, acp_mmio, mmACP_SRBM_Targ_Idx_Data);
+
+               /* Load the High address of page int ACP SRAM through SRBM */
+               acp_reg_write((offset + (page_idx * 8) + 4),
+                       acp_mmio, mmACP_SRBM_Targ_Idx_Addr);
+
+               /* page enable in ACP */
+               high |= BIT(31);
+               acp_reg_write(high, acp_mmio, mmACP_SRBM_Targ_Idx_Data);
+
+               /* Move to next physically contiguos page */
+               pg++;
+       }
+}
+
+static void config_acp_dma(void __iomem *acp_mmio,
+                          struct audio_substream_data *audio_config)
+{
+       u32 pte_offset;
+
+       if (audio_config->direction == SNDRV_PCM_STREAM_PLAYBACK)
+               pte_offset = ACP_PLAYBACK_PTE_OFFSET;
+       else
+               pte_offset = ACP_CAPTURE_PTE_OFFSET;
+
+       acp_pte_config(acp_mmio, audio_config->pg, audio_config->num_of_pages,
+                       pte_offset);
+
+       /* Configure System memory <-> ACP SRAM DMA descriptors */
+       set_acp_sysmem_dma_descriptors(acp_mmio, audio_config->size,
+                                      audio_config->direction, pte_offset);
+
+       /* Configure ACP SRAM <-> I2S DMA descriptors */
+       set_acp_to_i2s_dma_descriptors(acp_mmio, audio_config->size,
+                                       audio_config->direction);
+}
+
+/* Start a given DMA channel transfer */
+static void acp_dma_start(void __iomem *acp_mmio,
+                        u16 ch_num, bool is_circular)
+{
+       u32 dma_ctrl;
+
+       /* read the dma control register and disable the channel run field */
+       dma_ctrl = acp_reg_read(acp_mmio, mmACP_DMA_CNTL_0 + ch_num);
+
+       /* Invalidating the DAGB cache */
+       acp_reg_write(1, acp_mmio, mmACP_DAGB_ATU_CTRL);
+
+       /* configure the DMA channel and start the DMA transfer
+        * set dmachrun bit to start the transfer and enable the
+        * interrupt on completion of the dma transfer
+        */
+       dma_ctrl |= ACP_DMA_CNTL_0__DMAChRun_MASK;
+
+       switch (ch_num) {
+       case ACP_TO_I2S_DMA_CH_NUM:
+       case ACP_TO_SYSRAM_CH_NUM:
+       case I2S_TO_ACP_DMA_CH_NUM:
+               dma_ctrl |= ACP_DMA_CNTL_0__DMAChIOCEn_MASK;
+               break;
+       default:
+               dma_ctrl &= ~ACP_DMA_CNTL_0__DMAChIOCEn_MASK;
+               break;
+       }
+
+       /* enable  for ACP SRAM to/from I2S DMA channel */
+       if (is_circular == true)
+               dma_ctrl |= ACP_DMA_CNTL_0__Circular_DMA_En_MASK;
+       else
+               dma_ctrl &= ~ACP_DMA_CNTL_0__Circular_DMA_En_MASK;
+
+       acp_reg_write(dma_ctrl, acp_mmio, mmACP_DMA_CNTL_0 + ch_num);
+}
+
+/* Stop a given DMA channel transfer */
+static int acp_dma_stop(void __iomem *acp_mmio, u8 ch_num)
+{
+       u32 dma_ctrl;
+       u32 dma_ch_sts;
+       u32 count = ACP_DMA_RESET_TIME;
+
+       dma_ctrl = acp_reg_read(acp_mmio, mmACP_DMA_CNTL_0 + ch_num);
+
+       /* clear the dma control register fields before writing zero
+        * in reset bit
+       */
+       dma_ctrl &= ~ACP_DMA_CNTL_0__DMAChRun_MASK;
+       dma_ctrl &= ~ACP_DMA_CNTL_0__DMAChIOCEn_MASK;
+
+       acp_reg_write(dma_ctrl, acp_mmio, mmACP_DMA_CNTL_0 + ch_num);
+       dma_ch_sts = acp_reg_read(acp_mmio, mmACP_DMA_CH_STS);
+
+       if (dma_ch_sts & BIT(ch_num)) {
+               /* set the reset bit for this channel to stop the dma
+               *  transfer
+               */
+               dma_ctrl |= ACP_DMA_CNTL_0__DMAChRst_MASK;
+               acp_reg_write(dma_ctrl, acp_mmio, mmACP_DMA_CNTL_0 + ch_num);
+       }
+
+       /* check the channel status bit for some time and return the status */
+       while (true) {
+               dma_ch_sts = acp_reg_read(acp_mmio, mmACP_DMA_CH_STS);
+               if (!(dma_ch_sts & BIT(ch_num))) {
+                       /* clear the reset flag after successfully stopping
+                       * the dma transfer and break from the loop
+                       */
+                       dma_ctrl &= ~ACP_DMA_CNTL_0__DMAChRst_MASK;
+
+                       acp_reg_write(dma_ctrl, acp_mmio, mmACP_DMA_CNTL_0
+                                                               + ch_num);
+                       break;
+               }
+               if (--count == 0) {
+                       pr_err("Failed to stop ACP DMA channel : %d\n", ch_num);
+                       return -ETIMEDOUT;
+               }
+               udelay(100);
+       }
+       return 0;
+}
+
+static void acp_set_sram_bank_state(void __iomem *acp_mmio, u16 bank,
+                                       bool power_on)
+{
+       u32 val, req_reg, sts_reg, sts_reg_mask;
+       u32 loops = 1000;
+
+       if (bank < 32) {
+               req_reg = mmACP_MEM_SHUT_DOWN_REQ_LO;
+               sts_reg = mmACP_MEM_SHUT_DOWN_STS_LO;
+               sts_reg_mask = 0xFFFFFFFF;
+
+       } else {
+               bank -= 32;
+               req_reg = mmACP_MEM_SHUT_DOWN_REQ_HI;
+               sts_reg = mmACP_MEM_SHUT_DOWN_STS_HI;
+               sts_reg_mask = 0x0000FFFF;
+       }
+
+       val = acp_reg_read(acp_mmio, req_reg);
+       if (val & (1 << bank)) {
+               /* bank is in off state */
+               if (power_on == true)
+                       /* request to on */
+                       val &= ~(1 << bank);
+               else
+                       /* request to off */
+                       return;
+       } else {
+               /* bank is in on state */
+               if (power_on == false)
+                       /* request to off */
+                       val |= 1 << bank;
+               else
+                       /* request to on */
+                       return;
+       }
+       acp_reg_write(val, acp_mmio, req_reg);
+
+       while (acp_reg_read(acp_mmio, sts_reg) != sts_reg_mask) {
+               if (!loops--) {
+                       pr_err("ACP SRAM bank %d state change failed\n", bank);
+                       break;
+               }
+               cpu_relax();
+       }
+}
+
+/* Initialize and bring ACP hardware to default state. */
+static int acp_init(void __iomem *acp_mmio)
+{
+       u16 bank;
+       u32 val, count, sram_pte_offset;
+
+       /* Assert Soft reset of ACP */
+       val = acp_reg_read(acp_mmio, mmACP_SOFT_RESET);
+
+       val |= ACP_SOFT_RESET__SoftResetAud_MASK;
+       acp_reg_write(val, acp_mmio, mmACP_SOFT_RESET);
+
+       count = ACP_SOFT_RESET_DONE_TIME_OUT_VALUE;
+       while (true) {
+               val = acp_reg_read(acp_mmio, mmACP_SOFT_RESET);
+               if (ACP_SOFT_RESET__SoftResetAudDone_MASK ==
+                   (val & ACP_SOFT_RESET__SoftResetAudDone_MASK))
+                       break;
+               if (--count == 0) {
+                       pr_err("Failed to reset ACP\n");
+                       return -ETIMEDOUT;
+               }
+               udelay(100);
+       }
+
+       /* Enable clock to ACP and wait until the clock is enabled */
+       val = acp_reg_read(acp_mmio, mmACP_CONTROL);
+       val = val | ACP_CONTROL__ClkEn_MASK;
+       acp_reg_write(val, acp_mmio, mmACP_CONTROL);
+
+       count = ACP_CLOCK_EN_TIME_OUT_VALUE;
+
+       while (true) {
+               val = acp_reg_read(acp_mmio, mmACP_STATUS);
+               if (val & (u32) 0x1)
+                       break;
+               if (--count == 0) {
+                       pr_err("Failed to reset ACP\n");
+                       return -ETIMEDOUT;
+               }
+               udelay(100);
+       }
+
+       /* Deassert the SOFT RESET flags */
+       val = acp_reg_read(acp_mmio, mmACP_SOFT_RESET);
+       val &= ~ACP_SOFT_RESET__SoftResetAud_MASK;
+       acp_reg_write(val, acp_mmio, mmACP_SOFT_RESET);
+
+       /* initiailize Onion control DAGB register */
+       acp_reg_write(ACP_ONION_CNTL_DEFAULT, acp_mmio,
+                       mmACP_AXI2DAGB_ONION_CNTL);
+
+       /* initiailize Garlic control DAGB registers */
+       acp_reg_write(ACP_GARLIC_CNTL_DEFAULT, acp_mmio,
+                       mmACP_AXI2DAGB_GARLIC_CNTL);
+
+       sram_pte_offset = ACP_DAGB_GRP_SRAM_BASE_ADDRESS |
+                       ACP_DAGB_BASE_ADDR_GRP_1__AXI2DAGBSnoopSel_MASK |
+                       ACP_DAGB_BASE_ADDR_GRP_1__AXI2DAGBTargetMemSel_MASK |
+                       ACP_DAGB_BASE_ADDR_GRP_1__AXI2DAGBGrpEnable_MASK;
+       acp_reg_write(sram_pte_offset,  acp_mmio, mmACP_DAGB_BASE_ADDR_GRP_1);
+       acp_reg_write(ACP_PAGE_SIZE_4K_ENABLE, acp_mmio,
+                       mmACP_DAGB_PAGE_SIZE_GRP_1);
+
+       acp_reg_write(ACP_SRAM_BASE_ADDRESS, acp_mmio,
+                       mmACP_DMA_DESC_BASE_ADDR);
+
+       /* Num of descriptiors in SRAM 0x4, means 256 descriptors;(64 * 4) */
+       acp_reg_write(0x4, acp_mmio, mmACP_DMA_DESC_MAX_NUM_DSCR);
+       acp_reg_write(ACP_EXTERNAL_INTR_CNTL__DMAIOCMask_MASK,
+               acp_mmio, mmACP_EXTERNAL_INTR_CNTL);
+
+       /* When ACP_TILE_P1 is turned on, all SRAM banks get turned on.
+       * Now, turn off all of them. This can't be done in 'poweron' of
+       * ACP pm domain, as this requires ACP to be initialized.
+       */
+       for (bank = 1; bank < 48; bank++)
+               acp_set_sram_bank_state(acp_mmio, bank, false);
+
+       return 0;
+}
+
+/* Deintialize ACP */
+static int acp_deinit(void __iomem *acp_mmio)
+{
+       u32 val;
+       u32 count;
+
+       /* Assert Soft reset of ACP */
+       val = acp_reg_read(acp_mmio, mmACP_SOFT_RESET);
+
+       val |= ACP_SOFT_RESET__SoftResetAud_MASK;
+       acp_reg_write(val, acp_mmio, mmACP_SOFT_RESET);
+
+       count = ACP_SOFT_RESET_DONE_TIME_OUT_VALUE;
+       while (true) {
+               val = acp_reg_read(acp_mmio, mmACP_SOFT_RESET);
+               if (ACP_SOFT_RESET__SoftResetAudDone_MASK ==
+                   (val & ACP_SOFT_RESET__SoftResetAudDone_MASK))
+                       break;
+               if (--count == 0) {
+                       pr_err("Failed to reset ACP\n");
+                       return -ETIMEDOUT;
+               }
+               udelay(100);
+       }
+       /** Disable ACP clock */
+       val = acp_reg_read(acp_mmio, mmACP_CONTROL);
+       val &= ~ACP_CONTROL__ClkEn_MASK;
+       acp_reg_write(val, acp_mmio, mmACP_CONTROL);
+
+       count = ACP_CLOCK_EN_TIME_OUT_VALUE;
+
+       while (true) {
+               val = acp_reg_read(acp_mmio, mmACP_STATUS);
+               if (!(val & (u32) 0x1))
+                       break;
+               if (--count == 0) {
+                       pr_err("Failed to reset ACP\n");
+                       return -ETIMEDOUT;
+               }
+               udelay(100);
+       }
+       return 0;
+}
+
+/* ACP DMA irq handler routine for playback, capture usecases */
+static irqreturn_t dma_irq_handler(int irq, void *arg)
+{
+       u16 dscr_idx;
+       u32 intr_flag, ext_intr_status;
+       struct audio_drv_data *irq_data;
+       void __iomem *acp_mmio;
+       struct device *dev = arg;
+       bool valid_irq = false;
+
+       irq_data = dev_get_drvdata(dev);
+       acp_mmio = irq_data->acp_mmio;
+
+       ext_intr_status = acp_reg_read(acp_mmio, mmACP_EXTERNAL_INTR_STAT);
+       intr_flag = (((ext_intr_status &
+                     ACP_EXTERNAL_INTR_STAT__DMAIOCStat_MASK) >>
+                    ACP_EXTERNAL_INTR_STAT__DMAIOCStat__SHIFT));
+
+       if ((intr_flag & BIT(ACP_TO_I2S_DMA_CH_NUM)) != 0) {
+               valid_irq = true;
+               if (acp_reg_read(acp_mmio, mmACP_DMA_CUR_DSCR_13) ==
+                               PLAYBACK_START_DMA_DESCR_CH13)
+                       dscr_idx = PLAYBACK_START_DMA_DESCR_CH12;
+               else
+                       dscr_idx = PLAYBACK_END_DMA_DESCR_CH12;
+               config_acp_dma_channel(acp_mmio, SYSRAM_TO_ACP_CH_NUM, dscr_idx,
+                                      1, 0);
+               acp_dma_start(acp_mmio, SYSRAM_TO_ACP_CH_NUM, false);
+
+               snd_pcm_period_elapsed(irq_data->play_stream);
+
+               acp_reg_write((intr_flag & BIT(ACP_TO_I2S_DMA_CH_NUM)) << 16,
+                               acp_mmio, mmACP_EXTERNAL_INTR_STAT);
+       }
+
+       if ((intr_flag & BIT(I2S_TO_ACP_DMA_CH_NUM)) != 0) {
+               valid_irq = true;
+               if (acp_reg_read(acp_mmio, mmACP_DMA_CUR_DSCR_15) ==
+                               CAPTURE_START_DMA_DESCR_CH15)
+                       dscr_idx = CAPTURE_END_DMA_DESCR_CH14;
+               else
+                       dscr_idx = CAPTURE_START_DMA_DESCR_CH14;
+               config_acp_dma_channel(acp_mmio, ACP_TO_SYSRAM_CH_NUM, dscr_idx,
+                                      1, 0);
+               acp_dma_start(acp_mmio, ACP_TO_SYSRAM_CH_NUM, false);
+
+               acp_reg_write((intr_flag & BIT(I2S_TO_ACP_DMA_CH_NUM)) << 16,
+                               acp_mmio, mmACP_EXTERNAL_INTR_STAT);
+       }
+
+       if ((intr_flag & BIT(ACP_TO_SYSRAM_CH_NUM)) != 0) {
+               valid_irq = true;
+               snd_pcm_period_elapsed(irq_data->capture_stream);
+               acp_reg_write((intr_flag & BIT(ACP_TO_SYSRAM_CH_NUM)) << 16,
+                               acp_mmio, mmACP_EXTERNAL_INTR_STAT);
+       }
+
+       if (valid_irq)
+               return IRQ_HANDLED;
+       else
+               return IRQ_NONE;
+}
+
+static int acp_dma_open(struct snd_pcm_substream *substream)
+{
+       u16 bank;
+       int ret = 0;
+       struct snd_pcm_runtime *runtime = substream->runtime;
+       struct snd_soc_pcm_runtime *prtd = substream->private_data;
+       struct audio_drv_data *intr_data = dev_get_drvdata(prtd->platform->dev);
+
+       struct audio_substream_data *adata =
+               kzalloc(sizeof(struct audio_substream_data), GFP_KERNEL);
+       if (adata == NULL)
+               return -ENOMEM;
+
+       if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+               runtime->hw = acp_pcm_hardware_playback;
+       else
+               runtime->hw = acp_pcm_hardware_capture;
+
+       ret = snd_pcm_hw_constraint_integer(runtime,
+                                           SNDRV_PCM_HW_PARAM_PERIODS);
+       if (ret < 0) {
+               dev_err(prtd->platform->dev, "set integer constraint failed\n");
+               return ret;
+       }
+
+       adata->acp_mmio = intr_data->acp_mmio;
+       runtime->private_data = adata;
+
+       /* Enable ACP irq, when neither playback or capture streams are
+        * active by the time when a new stream is being opened.
+        * This enablement is not required for another stream, if current
+        * stream is not closed
+       */
+       if (!intr_data->play_stream && !intr_data->capture_stream)
+               acp_reg_write(1, adata->acp_mmio, mmACP_EXTERNAL_INTR_ENB);
+
+       if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+               intr_data->play_stream = substream;
+               for (bank = 1; bank <= 4; bank++)
+                       acp_set_sram_bank_state(intr_data->acp_mmio, bank,
+                                               true);
+       } else {
+               intr_data->capture_stream = substream;
+               for (bank = 5; bank <= 8; bank++)
+                       acp_set_sram_bank_state(intr_data->acp_mmio, bank,
+                                               true);
+       }
+
+       return 0;
+}
+
+static int acp_dma_hw_params(struct snd_pcm_substream *substream,
+                            struct snd_pcm_hw_params *params)
+{
+       int status;
+       uint64_t size;
+       struct snd_dma_buffer *dma_buffer;
+       struct page *pg;
+       struct snd_pcm_runtime *runtime;
+       struct audio_substream_data *rtd;
+
+       dma_buffer = &substream->dma_buffer;
+
+       runtime = substream->runtime;
+       rtd = runtime->private_data;
+
+       if (WARN_ON(!rtd))
+               return -EINVAL;
+
+       size = params_buffer_bytes(params);
+       status = snd_pcm_lib_malloc_pages(substream, size);
+       if (status < 0)
+               return status;
+
+       memset(substream->runtime->dma_area, 0, params_buffer_bytes(params));
+       pg = virt_to_page(substream->dma_buffer.area);
+
+       if (pg != NULL) {
+               acp_set_sram_bank_state(rtd->acp_mmio, 0, true);
+               /* Save for runtime private data */
+               rtd->pg = pg;
+               rtd->order = get_order(size);
+
+               /* Fill the page table entries in ACP SRAM */
+               rtd->pg = pg;
+               rtd->size = size;
+               rtd->num_of_pages = PAGE_ALIGN(size) >> PAGE_SHIFT;
+               rtd->direction = substream->stream;
+
+               config_acp_dma(rtd->acp_mmio, rtd);
+               status = 0;
+       } else {
+               status = -ENOMEM;
+       }
+       return status;
+}
+
+static int acp_dma_hw_free(struct snd_pcm_substream *substream)
+{
+       return snd_pcm_lib_free_pages(substream);
+}
+
+static snd_pcm_uframes_t acp_dma_pointer(struct snd_pcm_substream *substream)
+{
+       u16 dscr;
+       u32 mul, dma_config, period_bytes;
+       u32 pos = 0;
+
+       struct snd_pcm_runtime *runtime = substream->runtime;
+       struct audio_substream_data *rtd = runtime->private_data;
+
+       period_bytes = frames_to_bytes(runtime, runtime->period_size);
+       if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+               dscr = acp_reg_read(rtd->acp_mmio, mmACP_DMA_CUR_DSCR_13);
+
+               if (dscr == PLAYBACK_START_DMA_DESCR_CH13)
+                       mul = 0;
+               else
+                       mul = 1;
+               pos =  (mul * period_bytes);
+       } else {
+               dma_config = acp_reg_read(rtd->acp_mmio, mmACP_DMA_CNTL_14);
+               if (dma_config != 0) {
+                       dscr = acp_reg_read(rtd->acp_mmio,
+                                               mmACP_DMA_CUR_DSCR_14);
+                       if (dscr == CAPTURE_START_DMA_DESCR_CH14)
+                               mul = 1;
+                       else
+                               mul = 2;
+                       pos = (mul * period_bytes);
+               }
+
+               if (pos >= (2 * period_bytes))
+                       pos = 0;
+
+       }
+       return bytes_to_frames(runtime, pos);
+}
+
+static int acp_dma_mmap(struct snd_pcm_substream *substream,
+                       struct vm_area_struct *vma)
+{
+       return snd_pcm_lib_default_mmap(substream, vma);
+}
+
+static int acp_dma_prepare(struct snd_pcm_substream *substream)
+{
+       struct snd_pcm_runtime *runtime = substream->runtime;
+       struct audio_substream_data *rtd = runtime->private_data;
+
+       if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+               config_acp_dma_channel(rtd->acp_mmio, SYSRAM_TO_ACP_CH_NUM,
+                                       PLAYBACK_START_DMA_DESCR_CH12,
+                                       NUM_DSCRS_PER_CHANNEL, 0);
+               config_acp_dma_channel(rtd->acp_mmio, ACP_TO_I2S_DMA_CH_NUM,
+                                       PLAYBACK_START_DMA_DESCR_CH13,
+                                       NUM_DSCRS_PER_CHANNEL, 0);
+               /* Fill ACP SRAM (2 periods) with zeros from System RAM
+                * which is zero-ed in hw_params
+               */
+               acp_dma_start(rtd->acp_mmio, SYSRAM_TO_ACP_CH_NUM, false);
+
+               /* ACP SRAM (2 periods of buffer size) is intially filled with
+                * zeros. Before rendering starts, 2nd half of SRAM will be
+                * filled with valid audio data DMA'ed from first half of system
+                * RAM and 1st half of SRAM will be filled with Zeros. This is
+                * the initial scenario when redering starts from SRAM. Later
+                * on, 2nd half of system memory will be DMA'ed to 1st half of
+                * SRAM, 1st half of system memory will be DMA'ed to 2nd half of
+                * SRAM in ping-pong way till rendering stops.
+               */
+               config_acp_dma_channel(rtd->acp_mmio, SYSRAM_TO_ACP_CH_NUM,
+                                       PLAYBACK_START_DMA_DESCR_CH12,
+                                       1, 0);
+       } else {
+               config_acp_dma_channel(rtd->acp_mmio, ACP_TO_SYSRAM_CH_NUM,
+                                       CAPTURE_START_DMA_DESCR_CH14,
+                                       NUM_DSCRS_PER_CHANNEL, 0);
+               config_acp_dma_channel(rtd->acp_mmio, I2S_TO_ACP_DMA_CH_NUM,
+                                       CAPTURE_START_DMA_DESCR_CH15,
+                                       NUM_DSCRS_PER_CHANNEL, 0);
+       }
+       return 0;
+}
+
+static int acp_dma_trigger(struct snd_pcm_substream *substream, int cmd)
+{
+       int ret;
+       u32 loops = 1000;
+
+       struct snd_pcm_runtime *runtime = substream->runtime;
+       struct snd_soc_pcm_runtime *prtd = substream->private_data;
+       struct audio_substream_data *rtd = runtime->private_data;
+
+       if (!rtd)
+               return -EINVAL;
+       switch (cmd) {
+       case SNDRV_PCM_TRIGGER_START:
+       case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+       case SNDRV_PCM_TRIGGER_RESUME:
+               if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+                       acp_dma_start(rtd->acp_mmio,
+                                               SYSRAM_TO_ACP_CH_NUM, false);
+                       while (acp_reg_read(rtd->acp_mmio, mmACP_DMA_CH_STS) &
+                                               BIT(SYSRAM_TO_ACP_CH_NUM)) {
+                               if (!loops--) {
+                                       dev_err(prtd->platform->dev,
+                                               "acp dma start timeout\n");
+                                       return -ETIMEDOUT;
+                               }
+                               cpu_relax();
+                       }
+
+                       acp_dma_start(rtd->acp_mmio,
+                                       ACP_TO_I2S_DMA_CH_NUM, true);
+
+               } else {
+                       acp_dma_start(rtd->acp_mmio,
+                                           I2S_TO_ACP_DMA_CH_NUM, true);
+               }
+               ret = 0;
+               break;
+       case SNDRV_PCM_TRIGGER_STOP:
+       case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+       case SNDRV_PCM_TRIGGER_SUSPEND:
+               /* Need to stop only circular DMA channels :
+                * ACP_TO_I2S_DMA_CH_NUM / I2S_TO_ACP_DMA_CH_NUM. Non-circular
+                * channels will stopped automatically after its transfer
+                * completes : SYSRAM_TO_ACP_CH_NUM / ACP_TO_SYSRAM_CH_NUM
+                */
+               if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+                       ret = acp_dma_stop(rtd->acp_mmio,
+                                       ACP_TO_I2S_DMA_CH_NUM);
+               else
+                       ret = acp_dma_stop(rtd->acp_mmio,
+                                       I2S_TO_ACP_DMA_CH_NUM);
+               break;
+       default:
+               ret = -EINVAL;
+
+       }
+       return ret;
+}
+
+static int acp_dma_new(struct snd_soc_pcm_runtime *rtd)
+{
+       return snd_pcm_lib_preallocate_pages_for_all(rtd->pcm,
+                                                       SNDRV_DMA_TYPE_DEV,
+                                                       NULL, MIN_BUFFER,
+                                                       MAX_BUFFER);
+}
+
+static int acp_dma_close(struct snd_pcm_substream *substream)
+{
+       u16 bank;
+       struct snd_pcm_runtime *runtime = substream->runtime;
+       struct audio_substream_data *rtd = runtime->private_data;
+       struct snd_soc_pcm_runtime *prtd = substream->private_data;
+       struct audio_drv_data *adata = dev_get_drvdata(prtd->platform->dev);
+
+       kfree(rtd);
+
+       if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+               adata->play_stream = NULL;
+               for (bank = 1; bank <= 4; bank++)
+                       acp_set_sram_bank_state(adata->acp_mmio, bank,
+                                               false);
+       } else {
+               adata->capture_stream = NULL;
+               for (bank = 5; bank <= 8; bank++)
+                       acp_set_sram_bank_state(adata->acp_mmio, bank,
+                                               false);
+       }
+
+       /* Disable ACP irq, when the current stream is being closed and
+        * another stream is also not active.
+       */
+       if (!adata->play_stream && !adata->capture_stream)
+               acp_reg_write(0, adata->acp_mmio, mmACP_EXTERNAL_INTR_ENB);
+
+       return 0;
+}
+
+static struct snd_pcm_ops acp_dma_ops = {
+       .open = acp_dma_open,
+       .close = acp_dma_close,
+       .ioctl = snd_pcm_lib_ioctl,
+       .hw_params = acp_dma_hw_params,
+       .hw_free = acp_dma_hw_free,
+       .trigger = acp_dma_trigger,
+       .pointer = acp_dma_pointer,
+       .mmap = acp_dma_mmap,
+       .prepare = acp_dma_prepare,
+};
+
+static struct snd_soc_platform_driver acp_asoc_platform = {
+       .ops = &acp_dma_ops,
+       .pcm_new = acp_dma_new,
+};
+
+static int acp_audio_probe(struct platform_device *pdev)
+{
+       int status;
+       struct audio_drv_data *audio_drv_data;
+       struct resource *res;
+
+       audio_drv_data = devm_kzalloc(&pdev->dev, sizeof(struct audio_drv_data),
+                                       GFP_KERNEL);
+       if (audio_drv_data == NULL)
+               return -ENOMEM;
+
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       audio_drv_data->acp_mmio = devm_ioremap_resource(&pdev->dev, res);
+
+       /* The following members gets populated in device 'open'
+        * function. Till then interrupts are disabled in 'acp_init'
+        * and device doesn't generate any interrupts.
+        */
+
+       audio_drv_data->play_stream = NULL;
+       audio_drv_data->capture_stream = NULL;
+
+       res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+       if (!res) {
+               dev_err(&pdev->dev, "IORESOURCE_IRQ FAILED\n");
+               return -ENODEV;
+       }
+
+       status = devm_request_irq(&pdev->dev, res->start, dma_irq_handler,
+                                       0, "ACP_IRQ", &pdev->dev);
+       if (status) {
+               dev_err(&pdev->dev, "ACP IRQ request failed\n");
+               return status;
+       }
+
+       dev_set_drvdata(&pdev->dev, audio_drv_data);
+
+       /* Initialize the ACP */
+       acp_init(audio_drv_data->acp_mmio);
+
+       status = snd_soc_register_platform(&pdev->dev, &acp_asoc_platform);
+       if (status != 0) {
+               dev_err(&pdev->dev, "Fail to register ALSA platform device\n");
+               return status;
+       }
+
+       pm_runtime_set_autosuspend_delay(&pdev->dev, 10000);
+       pm_runtime_use_autosuspend(&pdev->dev);
+       pm_runtime_enable(&pdev->dev);
+
+       return status;
+}
+
+static int acp_audio_remove(struct platform_device *pdev)
+{
+       struct audio_drv_data *adata = dev_get_drvdata(&pdev->dev);
+
+       acp_deinit(adata->acp_mmio);
+       snd_soc_unregister_platform(&pdev->dev);
+       pm_runtime_disable(&pdev->dev);
+
+       return 0;
+}
+
+static int acp_pcm_resume(struct device *dev)
+{
+       u16 bank;
+       struct audio_drv_data *adata = dev_get_drvdata(dev);
+
+       acp_init(adata->acp_mmio);
+
+       if (adata->play_stream && adata->play_stream->runtime) {
+               for (bank = 1; bank <= 4; bank++)
+                       acp_set_sram_bank_state(adata->acp_mmio, bank,
+                                               true);
+               config_acp_dma(adata->acp_mmio,
+                               adata->play_stream->runtime->private_data);
+       }
+       if (adata->capture_stream && adata->capture_stream->runtime) {
+               for (bank = 5; bank <= 8; bank++)
+                       acp_set_sram_bank_state(adata->acp_mmio, bank,
+                                               true);
+               config_acp_dma(adata->acp_mmio,
+                               adata->capture_stream->runtime->private_data);
+       }
+       acp_reg_write(1, adata->acp_mmio, mmACP_EXTERNAL_INTR_ENB);
+       return 0;
+}
+
+static int acp_pcm_runtime_suspend(struct device *dev)
+{
+       struct audio_drv_data *adata = dev_get_drvdata(dev);
+
+       acp_deinit(adata->acp_mmio);
+       acp_reg_write(0, adata->acp_mmio, mmACP_EXTERNAL_INTR_ENB);
+       return 0;
+}
+
+static int acp_pcm_runtime_resume(struct device *dev)
+{
+       struct audio_drv_data *adata = dev_get_drvdata(dev);
+
+       acp_init(adata->acp_mmio);
+       acp_reg_write(1, adata->acp_mmio, mmACP_EXTERNAL_INTR_ENB);
+       return 0;
+}
+
+static const struct dev_pm_ops acp_pm_ops = {
+       .resume = acp_pcm_resume,
+       .runtime_suspend = acp_pcm_runtime_suspend,
+       .runtime_resume = acp_pcm_runtime_resume,
+};
+
+static struct platform_driver acp_dma_driver = {
+       .probe = acp_audio_probe,
+       .remove = acp_audio_remove,
+       .driver = {
+               .name = "acp_audio_dma",
+               .pm = &acp_pm_ops,
+       },
+};
+
+module_platform_driver(acp_dma_driver);
+
+MODULE_AUTHOR("Maruthi.Bayyavarapu@amd.com");
+MODULE_DESCRIPTION("AMD ACP PCM Driver");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:acp-dma-audio");
diff --git a/sound/soc/amd/acp.h b/sound/soc/amd/acp.h
new file mode 100644 (file)
index 0000000..330832e
--- /dev/null
@@ -0,0 +1,118 @@
+#ifndef __ACP_HW_H
+#define __ACP_HW_H
+
+#include "include/acp_2_2_d.h"
+#include "include/acp_2_2_sh_mask.h"
+
+#define ACP_PAGE_SIZE_4K_ENABLE                        0x02
+
+#define ACP_PLAYBACK_PTE_OFFSET                        10
+#define ACP_CAPTURE_PTE_OFFSET                 0
+
+#define ACP_GARLIC_CNTL_DEFAULT                        0x00000FB4
+#define ACP_ONION_CNTL_DEFAULT                 0x00000FB4
+
+#define ACP_PHYSICAL_BASE                      0x14000
+
+/* Playback SRAM address (as a destination in dma descriptor) */
+#define ACP_SHARED_RAM_BANK_1_ADDRESS          0x4002000
+
+/* Capture SRAM address (as a source in dma descriptor) */
+#define ACP_SHARED_RAM_BANK_5_ADDRESS          0x400A000
+
+#define ACP_DMA_RESET_TIME                     10000
+#define ACP_CLOCK_EN_TIME_OUT_VALUE            0x000000FF
+#define ACP_SOFT_RESET_DONE_TIME_OUT_VALUE     0x000000FF
+#define ACP_DMA_COMPLETE_TIME_OUT_VALUE                0x000000FF
+
+#define ACP_SRAM_BASE_ADDRESS                  0x4000000
+#define ACP_DAGB_GRP_SRAM_BASE_ADDRESS         0x4001000
+#define ACP_DAGB_GRP_SRBM_SRAM_BASE_OFFSET     0x1000
+#define ACP_INTERNAL_APERTURE_WINDOW_0_ADDRESS 0x00000000
+#define ACP_INTERNAL_APERTURE_WINDOW_4_ADDRESS 0x01800000
+
+#define TO_ACP_I2S_1   0x2
+#define TO_ACP_I2S_2   0x4
+#define FROM_ACP_I2S_1 0xa
+#define FROM_ACP_I2S_2 0xb
+
+#define ACP_TILE_ON_MASK                0x03
+#define ACP_TILE_OFF_MASK               0x02
+#define ACP_TILE_ON_RETAIN_REG_MASK     0x1f
+#define ACP_TILE_OFF_RETAIN_REG_MASK    0x20
+
+#define ACP_TILE_P1_MASK                0x3e
+#define ACP_TILE_P2_MASK                0x3d
+#define ACP_TILE_DSP0_MASK              0x3b
+#define ACP_TILE_DSP1_MASK              0x37
+
+#define ACP_TILE_DSP2_MASK              0x2f
+/* Playback DMA channels */
+#define SYSRAM_TO_ACP_CH_NUM 12
+#define ACP_TO_I2S_DMA_CH_NUM 13
+
+/* Capture DMA channels */
+#define ACP_TO_SYSRAM_CH_NUM 14
+#define I2S_TO_ACP_DMA_CH_NUM 15
+
+#define NUM_DSCRS_PER_CHANNEL 2
+
+#define PLAYBACK_START_DMA_DESCR_CH12 0
+#define PLAYBACK_END_DMA_DESCR_CH12 1
+#define PLAYBACK_START_DMA_DESCR_CH13 2
+#define PLAYBACK_END_DMA_DESCR_CH13 3
+
+#define CAPTURE_START_DMA_DESCR_CH14 4
+#define CAPTURE_END_DMA_DESCR_CH14 5
+#define CAPTURE_START_DMA_DESCR_CH15 6
+#define CAPTURE_END_DMA_DESCR_CH15 7
+
+enum acp_dma_priority_level {
+       /* 0x0 Specifies the DMA channel is given normal priority */
+       ACP_DMA_PRIORITY_LEVEL_NORMAL = 0x0,
+       /* 0x1 Specifies the DMA channel is given high priority */
+       ACP_DMA_PRIORITY_LEVEL_HIGH = 0x1,
+       ACP_DMA_PRIORITY_LEVEL_FORCESIZE = 0xFF
+};
+
+struct audio_substream_data {
+       struct page *pg;
+       unsigned int order;
+       u16 num_of_pages;
+       u16 direction;
+       uint64_t size;
+       void __iomem *acp_mmio;
+};
+
+enum {
+       ACP_TILE_P1 = 0,
+       ACP_TILE_P2,
+       ACP_TILE_DSP0,
+       ACP_TILE_DSP1,
+       ACP_TILE_DSP2,
+};
+
+enum {
+       ACP_DMA_ATTRIBUTES_SHAREDMEM_TO_DAGB_ONION = 0x0,
+       ACP_DMA_ATTRIBUTES_SHARED_MEM_TO_DAGB_GARLIC = 0x1,
+       ACP_DMA_ATTRIBUTES_DAGB_ONION_TO_SHAREDMEM = 0x8,
+       ACP_DMA_ATTRIBUTES_DAGB_GARLIC_TO_SHAREDMEM = 0x9,
+       ACP_DMA_ATTRIBUTES_FORCE_SIZE = 0xF
+};
+
+typedef struct acp_dma_dscr_transfer {
+       /* Specifies the source memory location for the DMA data transfer. */
+       u32 src;
+       /* Specifies the destination memory location to where the data will
+        * be transferred.
+       */
+       u32 dest;
+       /* Specifies the number of bytes need to be transferred
+       * from source to destination memory.Transfer direction & IOC enable
+       */
+       u32 xfer_val;
+       /* Reserved for future use */
+       u32 reserved;
+} acp_dma_dscr_transfer_t;
+
+#endif /*__ACP_HW_H */
diff --git a/sound/soc/amd/include/acp_2_2_d.h b/sound/soc/amd/include/acp_2_2_d.h
new file mode 100644 (file)
index 0000000..0118fe9
--- /dev/null
@@ -0,0 +1,609 @@
+/*
+ * ACP_2_2 Register documentation
+ *
+ * Copyright (C) 2014  Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#ifndef ACP_2_2_D_H
+#define ACP_2_2_D_H
+
+#define mmACP_DMA_CNTL_0                                                        0x5000
+#define mmACP_DMA_CNTL_1                                                        0x5001
+#define mmACP_DMA_CNTL_2                                                        0x5002
+#define mmACP_DMA_CNTL_3                                                        0x5003
+#define mmACP_DMA_CNTL_4                                                        0x5004
+#define mmACP_DMA_CNTL_5                                                        0x5005
+#define mmACP_DMA_CNTL_6                                                        0x5006
+#define mmACP_DMA_CNTL_7                                                        0x5007
+#define mmACP_DMA_CNTL_8                                                        0x5008
+#define mmACP_DMA_CNTL_9                                                        0x5009
+#define mmACP_DMA_CNTL_10                                                       0x500a
+#define mmACP_DMA_CNTL_11                                                       0x500b
+#define mmACP_DMA_CNTL_12                                                       0x500c
+#define mmACP_DMA_CNTL_13                                                       0x500d
+#define mmACP_DMA_CNTL_14                                                       0x500e
+#define mmACP_DMA_CNTL_15                                                       0x500f
+#define mmACP_DMA_DSCR_STRT_IDX_0                                               0x5010
+#define mmACP_DMA_DSCR_STRT_IDX_1                                               0x5011
+#define mmACP_DMA_DSCR_STRT_IDX_2                                               0x5012
+#define mmACP_DMA_DSCR_STRT_IDX_3                                               0x5013
+#define mmACP_DMA_DSCR_STRT_IDX_4                                               0x5014
+#define mmACP_DMA_DSCR_STRT_IDX_5                                               0x5015
+#define mmACP_DMA_DSCR_STRT_IDX_6                                               0x5016
+#define mmACP_DMA_DSCR_STRT_IDX_7                                               0x5017
+#define mmACP_DMA_DSCR_STRT_IDX_8                                               0x5018
+#define mmACP_DMA_DSCR_STRT_IDX_9                                               0x5019
+#define mmACP_DMA_DSCR_STRT_IDX_10                                              0x501a
+#define mmACP_DMA_DSCR_STRT_IDX_11                                              0x501b
+#define mmACP_DMA_DSCR_STRT_IDX_12                                              0x501c
+#define mmACP_DMA_DSCR_STRT_IDX_13                                              0x501d
+#define mmACP_DMA_DSCR_STRT_IDX_14                                              0x501e
+#define mmACP_DMA_DSCR_STRT_IDX_15                                              0x501f
+#define mmACP_DMA_DSCR_CNT_0                                                    0x5020
+#define mmACP_DMA_DSCR_CNT_1                                                    0x5021
+#define mmACP_DMA_DSCR_CNT_2                                                    0x5022
+#define mmACP_DMA_DSCR_CNT_3                                                    0x5023
+#define mmACP_DMA_DSCR_CNT_4                                                    0x5024
+#define mmACP_DMA_DSCR_CNT_5                                                    0x5025
+#define mmACP_DMA_DSCR_CNT_6                                                    0x5026
+#define mmACP_DMA_DSCR_CNT_7                                                    0x5027
+#define mmACP_DMA_DSCR_CNT_8                                                    0x5028
+#define mmACP_DMA_DSCR_CNT_9                                                    0x5029
+#define mmACP_DMA_DSCR_CNT_10                                                   0x502a
+#define mmACP_DMA_DSCR_CNT_11                                                   0x502b
+#define mmACP_DMA_DSCR_CNT_12                                                   0x502c
+#define mmACP_DMA_DSCR_CNT_13                                                   0x502d
+#define mmACP_DMA_DSCR_CNT_14                                                   0x502e
+#define mmACP_DMA_DSCR_CNT_15                                                   0x502f
+#define mmACP_DMA_PRIO_0                                                        0x5030
+#define mmACP_DMA_PRIO_1                                                        0x5031
+#define mmACP_DMA_PRIO_2                                                        0x5032
+#define mmACP_DMA_PRIO_3                                                        0x5033
+#define mmACP_DMA_PRIO_4                                                        0x5034
+#define mmACP_DMA_PRIO_5                                                        0x5035
+#define mmACP_DMA_PRIO_6                                                        0x5036
+#define mmACP_DMA_PRIO_7                                                        0x5037
+#define mmACP_DMA_PRIO_8                                                        0x5038
+#define mmACP_DMA_PRIO_9                                                        0x5039
+#define mmACP_DMA_PRIO_10                                                       0x503a
+#define mmACP_DMA_PRIO_11                                                       0x503b
+#define mmACP_DMA_PRIO_12                                                       0x503c
+#define mmACP_DMA_PRIO_13                                                       0x503d
+#define mmACP_DMA_PRIO_14                                                       0x503e
+#define mmACP_DMA_PRIO_15                                                       0x503f
+#define mmACP_DMA_CUR_DSCR_0                                                    0x5040
+#define mmACP_DMA_CUR_DSCR_1                                                    0x5041
+#define mmACP_DMA_CUR_DSCR_2                                                    0x5042
+#define mmACP_DMA_CUR_DSCR_3                                                    0x5043
+#define mmACP_DMA_CUR_DSCR_4                                                    0x5044
+#define mmACP_DMA_CUR_DSCR_5                                                    0x5045
+#define mmACP_DMA_CUR_DSCR_6                                                    0x5046
+#define mmACP_DMA_CUR_DSCR_7                                                    0x5047
+#define mmACP_DMA_CUR_DSCR_8                                                    0x5048
+#define mmACP_DMA_CUR_DSCR_9                                                    0x5049
+#define mmACP_DMA_CUR_DSCR_10                                                   0x504a
+#define mmACP_DMA_CUR_DSCR_11                                                   0x504b
+#define mmACP_DMA_CUR_DSCR_12                                                   0x504c
+#define mmACP_DMA_CUR_DSCR_13                                                   0x504d
+#define mmACP_DMA_CUR_DSCR_14                                                   0x504e
+#define mmACP_DMA_CUR_DSCR_15                                                   0x504f
+#define mmACP_DMA_CUR_TRANS_CNT_0                                               0x5050
+#define mmACP_DMA_CUR_TRANS_CNT_1                                               0x5051
+#define mmACP_DMA_CUR_TRANS_CNT_2                                               0x5052
+#define mmACP_DMA_CUR_TRANS_CNT_3                                               0x5053
+#define mmACP_DMA_CUR_TRANS_CNT_4                                               0x5054
+#define mmACP_DMA_CUR_TRANS_CNT_5                                               0x5055
+#define mmACP_DMA_CUR_TRANS_CNT_6                                               0x5056
+#define mmACP_DMA_CUR_TRANS_CNT_7                                               0x5057
+#define mmACP_DMA_CUR_TRANS_CNT_8                                               0x5058
+#define mmACP_DMA_CUR_TRANS_CNT_9                                               0x5059
+#define mmACP_DMA_CUR_TRANS_CNT_10                                              0x505a
+#define mmACP_DMA_CUR_TRANS_CNT_11                                              0x505b
+#define mmACP_DMA_CUR_TRANS_CNT_12                                              0x505c
+#define mmACP_DMA_CUR_TRANS_CNT_13                                              0x505d
+#define mmACP_DMA_CUR_TRANS_CNT_14                                              0x505e
+#define mmACP_DMA_CUR_TRANS_CNT_15                                              0x505f
+#define mmACP_DMA_ERR_STS_0                                                     0x5060
+#define mmACP_DMA_ERR_STS_1                                                     0x5061
+#define mmACP_DMA_ERR_STS_2                                                     0x5062
+#define mmACP_DMA_ERR_STS_3                                                     0x5063
+#define mmACP_DMA_ERR_STS_4                                                     0x5064
+#define mmACP_DMA_ERR_STS_5                                                     0x5065
+#define mmACP_DMA_ERR_STS_6                                                     0x5066
+#define mmACP_DMA_ERR_STS_7                                                     0x5067
+#define mmACP_DMA_ERR_STS_8                                                     0x5068
+#define mmACP_DMA_ERR_STS_9                                                     0x5069
+#define mmACP_DMA_ERR_STS_10                                                    0x506a
+#define mmACP_DMA_ERR_STS_11                                                    0x506b
+#define mmACP_DMA_ERR_STS_12                                                    0x506c
+#define mmACP_DMA_ERR_STS_13                                                    0x506d
+#define mmACP_DMA_ERR_STS_14                                                    0x506e
+#define mmACP_DMA_ERR_STS_15                                                    0x506f
+#define mmACP_DMA_DESC_BASE_ADDR                                                0x5070
+#define mmACP_DMA_DESC_MAX_NUM_DSCR                                             0x5071
+#define mmACP_DMA_CH_STS                                                        0x5072
+#define mmACP_DMA_CH_GROUP                                                      0x5073
+#define mmACP_DSP0_CACHE_OFFSET0                                                0x5078
+#define mmACP_DSP0_CACHE_SIZE0                                                  0x5079
+#define mmACP_DSP0_CACHE_OFFSET1                                                0x507a
+#define mmACP_DSP0_CACHE_SIZE1                                                  0x507b
+#define mmACP_DSP0_CACHE_OFFSET2                                                0x507c
+#define mmACP_DSP0_CACHE_SIZE2                                                  0x507d
+#define mmACP_DSP0_CACHE_OFFSET3                                                0x507e
+#define mmACP_DSP0_CACHE_SIZE3                                                  0x507f
+#define mmACP_DSP0_CACHE_OFFSET4                                                0x5080
+#define mmACP_DSP0_CACHE_SIZE4                                                  0x5081
+#define mmACP_DSP0_CACHE_OFFSET5                                                0x5082
+#define mmACP_DSP0_CACHE_SIZE5                                                  0x5083
+#define mmACP_DSP0_CACHE_OFFSET6                                                0x5084
+#define mmACP_DSP0_CACHE_SIZE6                                                  0x5085
+#define mmACP_DSP0_CACHE_OFFSET7                                                0x5086
+#define mmACP_DSP0_CACHE_SIZE7                                                  0x5087
+#define mmACP_DSP0_CACHE_OFFSET8                                                0x5088
+#define mmACP_DSP0_CACHE_SIZE8                                                  0x5089
+#define mmACP_DSP0_NONCACHE_OFFSET0                                             0x508a
+#define mmACP_DSP0_NONCACHE_SIZE0                                               0x508b
+#define mmACP_DSP0_NONCACHE_OFFSET1                                             0x508c
+#define mmACP_DSP0_NONCACHE_SIZE1                                               0x508d
+#define mmACP_DSP0_DEBUG_PC                                                     0x508e
+#define mmACP_DSP0_NMI_SEL                                                      0x508f
+#define mmACP_DSP0_CLKRST_CNTL                                                  0x5090
+#define mmACP_DSP0_RUNSTALL                                                     0x5091
+#define mmACP_DSP0_OCD_HALT_ON_RST                                              0x5092
+#define mmACP_DSP0_WAIT_MODE                                                    0x5093
+#define mmACP_DSP0_VECT_SEL                                                     0x5094
+#define mmACP_DSP0_DEBUG_REG1                                                   0x5095
+#define mmACP_DSP0_DEBUG_REG2                                                   0x5096
+#define mmACP_DSP0_DEBUG_REG3                                                   0x5097
+#define mmACP_DSP1_CACHE_OFFSET0                                                0x509d
+#define mmACP_DSP1_CACHE_SIZE0                                                  0x509e
+#define mmACP_DSP1_CACHE_OFFSET1                                                0x509f
+#define mmACP_DSP1_CACHE_SIZE1                                                  0x50a0
+#define mmACP_DSP1_CACHE_OFFSET2                                                0x50a1
+#define mmACP_DSP1_CACHE_SIZE2                                                  0x50a2
+#define mmACP_DSP1_CACHE_OFFSET3                                                0x50a3
+#define mmACP_DSP1_CACHE_SIZE3                                                  0x50a4
+#define mmACP_DSP1_CACHE_OFFSET4                                                0x50a5
+#define mmACP_DSP1_CACHE_SIZE4                                                  0x50a6
+#define mmACP_DSP1_CACHE_OFFSET5                                                0x50a7
+#define mmACP_DSP1_CACHE_SIZE5                                                  0x50a8
+#define mmACP_DSP1_CACHE_OFFSET6                                                0x50a9
+#define mmACP_DSP1_CACHE_SIZE6                                                  0x50aa
+#define mmACP_DSP1_CACHE_OFFSET7                                                0x50ab
+#define mmACP_DSP1_CACHE_SIZE7                                                  0x50ac
+#define mmACP_DSP1_CACHE_OFFSET8                                                0x50ad
+#define mmACP_DSP1_CACHE_SIZE8                                                  0x50ae
+#define mmACP_DSP1_NONCACHE_OFFSET0                                             0x50af
+#define mmACP_DSP1_NONCACHE_SIZE0                                               0x50b0
+#define mmACP_DSP1_NONCACHE_OFFSET1                                             0x50b1
+#define mmACP_DSP1_NONCACHE_SIZE1                                               0x50b2
+#define mmACP_DSP1_DEBUG_PC                                                     0x50b3
+#define mmACP_DSP1_NMI_SEL                                                      0x50b4
+#define mmACP_DSP1_CLKRST_CNTL                                                  0x50b5
+#define mmACP_DSP1_RUNSTALL                                                     0x50b6
+#define mmACP_DSP1_OCD_HALT_ON_RST                                              0x50b7
+#define mmACP_DSP1_WAIT_MODE                                                    0x50b8
+#define mmACP_DSP1_VECT_SEL                                                     0x50b9
+#define mmACP_DSP1_DEBUG_REG1                                                   0x50ba
+#define mmACP_DSP1_DEBUG_REG2                                                   0x50bb
+#define mmACP_DSP1_DEBUG_REG3                                                   0x50bc
+#define mmACP_DSP2_CACHE_OFFSET0                                                0x50c2
+#define mmACP_DSP2_CACHE_SIZE0                                                  0x50c3
+#define mmACP_DSP2_CACHE_OFFSET1                                                0x50c4
+#define mmACP_DSP2_CACHE_SIZE1                                                  0x50c5
+#define mmACP_DSP2_CACHE_OFFSET2                                                0x50c6
+#define mmACP_DSP2_CACHE_SIZE2                                                  0x50c7
+#define mmACP_DSP2_CACHE_OFFSET3                                                0x50c8
+#define mmACP_DSP2_CACHE_SIZE3                                                  0x50c9
+#define mmACP_DSP2_CACHE_OFFSET4                                                0x50ca
+#define mmACP_DSP2_CACHE_SIZE4                                                  0x50cb
+#define mmACP_DSP2_CACHE_OFFSET5                                                0x50cc
+#define mmACP_DSP2_CACHE_SIZE5                                                  0x50cd
+#define mmACP_DSP2_CACHE_OFFSET6                                                0x50ce
+#define mmACP_DSP2_CACHE_SIZE6                                                  0x50cf
+#define mmACP_DSP2_CACHE_OFFSET7                                                0x50d0
+#define mmACP_DSP2_CACHE_SIZE7                                                  0x50d1
+#define mmACP_DSP2_CACHE_OFFSET8                                                0x50d2
+#define mmACP_DSP2_CACHE_SIZE8                                                  0x50d3
+#define mmACP_DSP2_NONCACHE_OFFSET0                                             0x50d4
+#define mmACP_DSP2_NONCACHE_SIZE0                                               0x50d5
+#define mmACP_DSP2_NONCACHE_OFFSET1                                             0x50d6
+#define mmACP_DSP2_NONCACHE_SIZE1                                               0x50d7
+#define mmACP_DSP2_DEBUG_PC                                                     0x50d8
+#define mmACP_DSP2_NMI_SEL                                                      0x50d9
+#define mmACP_DSP2_CLKRST_CNTL                                                  0x50da
+#define mmACP_DSP2_RUNSTALL                                                     0x50db
+#define mmACP_DSP2_OCD_HALT_ON_RST                                              0x50dc
+#define mmACP_DSP2_WAIT_MODE                                                    0x50dd
+#define mmACP_DSP2_VECT_SEL                                                     0x50de
+#define mmACP_DSP2_DEBUG_REG1                                                   0x50df
+#define mmACP_DSP2_DEBUG_REG2                                                   0x50e0
+#define mmACP_DSP2_DEBUG_REG3                                                   0x50e1
+#define mmACP_AXI2DAGB_ONION_CNTL                                               0x50e7
+#define mmACP_AXI2DAGB_ONION_ERR_STATUS_WR                                      0x50e8
+#define mmACP_AXI2DAGB_ONION_ERR_STATUS_RD                                      0x50e9
+#define mmACP_DAGB_Onion_TransPerf_Counter_Control                              0x50ea
+#define mmACP_DAGB_Onion_Wr_TransPerf_Counter_Current                           0x50eb
+#define mmACP_DAGB_Onion_Wr_TransPerf_Counter_Peak                              0x50ec
+#define mmACP_DAGB_Onion_Rd_TransPerf_Counter_Current                           0x50ed
+#define mmACP_DAGB_Onion_Rd_TransPerf_Counter_Peak                              0x50ee
+#define mmACP_AXI2DAGB_GARLIC_CNTL                                              0x50f3
+#define mmACP_AXI2DAGB_GARLIC_ERR_STATUS_WR                                     0x50f4
+#define mmACP_AXI2DAGB_GARLIC_ERR_STATUS_RD                                     0x50f5
+#define mmACP_DAGB_Garlic_TransPerf_Counter_Control                             0x50f6
+#define mmACP_DAGB_Garlic_Wr_TransPerf_Counter_Current                          0x50f7
+#define mmACP_DAGB_Garlic_Wr_TransPerf_Counter_Peak                             0x50f8
+#define mmACP_DAGB_Garlic_Rd_TransPerf_Counter_Current                          0x50f9
+#define mmACP_DAGB_Garlic_Rd_TransPerf_Counter_Peak                             0x50fa
+#define mmACP_DAGB_PAGE_SIZE_GRP_1                                              0x50ff
+#define mmACP_DAGB_BASE_ADDR_GRP_1                                              0x5100
+#define mmACP_DAGB_PAGE_SIZE_GRP_2                                              0x5101
+#define mmACP_DAGB_BASE_ADDR_GRP_2                                              0x5102
+#define mmACP_DAGB_PAGE_SIZE_GRP_3                                              0x5103
+#define mmACP_DAGB_BASE_ADDR_GRP_3                                              0x5104
+#define mmACP_DAGB_PAGE_SIZE_GRP_4                                              0x5105
+#define mmACP_DAGB_BASE_ADDR_GRP_4                                              0x5106
+#define mmACP_DAGB_PAGE_SIZE_GRP_5                                              0x5107
+#define mmACP_DAGB_BASE_ADDR_GRP_5                                              0x5108
+#define mmACP_DAGB_PAGE_SIZE_GRP_6                                              0x5109
+#define mmACP_DAGB_BASE_ADDR_GRP_6                                              0x510a
+#define mmACP_DAGB_PAGE_SIZE_GRP_7                                              0x510b
+#define mmACP_DAGB_BASE_ADDR_GRP_7                                              0x510c
+#define mmACP_DAGB_PAGE_SIZE_GRP_8                                              0x510d
+#define mmACP_DAGB_BASE_ADDR_GRP_8                                              0x510e
+#define mmACP_DAGB_ATU_CTRL                                                     0x510f
+#define mmACP_CONTROL                                                           0x5131
+#define mmACP_STATUS                                                            0x5133
+#define mmACP_SOFT_RESET                                                        0x5134
+#define mmACP_PwrMgmt_CNTL                                                      0x5135
+#define mmACP_CAC_INDICATOR_CONTROL                                             0x5136
+#define mmACP_SMU_MAILBOX                                                       0x5137
+#define mmACP_FUTURE_REG_SCLK_0                                                 0x5138
+#define mmACP_FUTURE_REG_SCLK_1                                                 0x5139
+#define mmACP_FUTURE_REG_SCLK_2                                                 0x513a
+#define mmACP_FUTURE_REG_SCLK_3                                                 0x513b
+#define mmACP_FUTURE_REG_SCLK_4                                                 0x513c
+#define mmACP_DAGB_DEBUG_CNT_ENABLE                                             0x513d
+#define mmACP_DAGBG_WR_ASK_CNT                                                  0x513e
+#define mmACP_DAGBG_WR_GO_CNT                                                   0x513f
+#define mmACP_DAGBG_WR_EXP_RESP_CNT                                             0x5140
+#define mmACP_DAGBG_WR_ACTUAL_RESP_CNT                                          0x5141
+#define mmACP_DAGBG_RD_ASK_CNT                                                  0x5142
+#define mmACP_DAGBG_RD_GO_CNT                                                   0x5143
+#define mmACP_DAGBG_RD_EXP_RESP_CNT                                             0x5144
+#define mmACP_DAGBG_RD_ACTUAL_RESP_CNT                                          0x5145
+#define mmACP_DAGBO_WR_ASK_CNT                                                  0x5146
+#define mmACP_DAGBO_WR_GO_CNT                                                   0x5147
+#define mmACP_DAGBO_WR_EXP_RESP_CNT                                             0x5148
+#define mmACP_DAGBO_WR_ACTUAL_RESP_CNT                                          0x5149
+#define mmACP_DAGBO_RD_ASK_CNT                                                  0x514a
+#define mmACP_DAGBO_RD_GO_CNT                                                   0x514b
+#define mmACP_DAGBO_RD_EXP_RESP_CNT                                             0x514c
+#define mmACP_DAGBO_RD_ACTUAL_RESP_CNT                                          0x514d
+#define mmACP_BRB_CONTROL                                                       0x5156
+#define mmACP_EXTERNAL_INTR_ENB                                                 0x5157
+#define mmACP_EXTERNAL_INTR_CNTL                                                0x5158
+#define mmACP_ERROR_SOURCE_STS                                                  0x5159
+#define mmACP_DSP_SW_INTR_TRIG                                                  0x515a
+#define mmACP_DSP_SW_INTR_CNTL                                                  0x515b
+#define mmACP_DAGBG_TIMEOUT_CNTL                                                0x515c
+#define mmACP_DAGBO_TIMEOUT_CNTL                                                0x515d
+#define mmACP_EXTERNAL_INTR_STAT                                                0x515e
+#define mmACP_DSP_SW_INTR_STAT                                                  0x515f
+#define mmACP_DSP0_INTR_CNTL                                                    0x5160
+#define mmACP_DSP0_INTR_STAT                                                    0x5161
+#define mmACP_DSP0_TIMEOUT_CNTL                                                 0x5162
+#define mmACP_DSP1_INTR_CNTL                                                    0x5163
+#define mmACP_DSP1_INTR_STAT                                                    0x5164
+#define mmACP_DSP1_TIMEOUT_CNTL                                                 0x5165
+#define mmACP_DSP2_INTR_CNTL                                                    0x5166
+#define mmACP_DSP2_INTR_STAT                                                    0x5167
+#define mmACP_DSP2_TIMEOUT_CNTL                                                 0x5168
+#define mmACP_DSP0_EXT_TIMER_CNTL                                               0x5169
+#define mmACP_DSP1_EXT_TIMER_CNTL                                               0x516a
+#define mmACP_DSP2_EXT_TIMER_CNTL                                               0x516b
+#define mmACP_AXI2DAGB_SEM_0                                                    0x516c
+#define mmACP_AXI2DAGB_SEM_1                                                    0x516d
+#define mmACP_AXI2DAGB_SEM_2                                                    0x516e
+#define mmACP_AXI2DAGB_SEM_3                                                    0x516f
+#define mmACP_AXI2DAGB_SEM_4                                                    0x5170
+#define mmACP_AXI2DAGB_SEM_5                                                    0x5171
+#define mmACP_AXI2DAGB_SEM_6                                                    0x5172
+#define mmACP_AXI2DAGB_SEM_7                                                    0x5173
+#define mmACP_AXI2DAGB_SEM_8                                                    0x5174
+#define mmACP_AXI2DAGB_SEM_9                                                    0x5175
+#define mmACP_AXI2DAGB_SEM_10                                                   0x5176
+#define mmACP_AXI2DAGB_SEM_11                                                   0x5177
+#define mmACP_AXI2DAGB_SEM_12                                                   0x5178
+#define mmACP_AXI2DAGB_SEM_13                                                   0x5179
+#define mmACP_AXI2DAGB_SEM_14                                                   0x517a
+#define mmACP_AXI2DAGB_SEM_15                                                   0x517b
+#define mmACP_AXI2DAGB_SEM_16                                                   0x517c
+#define mmACP_AXI2DAGB_SEM_17                                                   0x517d
+#define mmACP_AXI2DAGB_SEM_18                                                   0x517e
+#define mmACP_AXI2DAGB_SEM_19                                                   0x517f
+#define mmACP_AXI2DAGB_SEM_20                                                   0x5180
+#define mmACP_AXI2DAGB_SEM_21                                                   0x5181
+#define mmACP_AXI2DAGB_SEM_22                                                   0x5182
+#define mmACP_AXI2DAGB_SEM_23                                                   0x5183
+#define mmACP_AXI2DAGB_SEM_24                                                   0x5184
+#define mmACP_AXI2DAGB_SEM_25                                                   0x5185
+#define mmACP_AXI2DAGB_SEM_26                                                   0x5186
+#define mmACP_AXI2DAGB_SEM_27                                                   0x5187
+#define mmACP_AXI2DAGB_SEM_28                                                   0x5188
+#define mmACP_AXI2DAGB_SEM_29                                                   0x5189
+#define mmACP_AXI2DAGB_SEM_30                                                   0x518a
+#define mmACP_AXI2DAGB_SEM_31                                                   0x518b
+#define mmACP_AXI2DAGB_SEM_32                                                   0x518c
+#define mmACP_AXI2DAGB_SEM_33                                                   0x518d
+#define mmACP_AXI2DAGB_SEM_34                                                   0x518e
+#define mmACP_AXI2DAGB_SEM_35                                                   0x518f
+#define mmACP_AXI2DAGB_SEM_36                                                   0x5190
+#define mmACP_AXI2DAGB_SEM_37                                                   0x5191
+#define mmACP_AXI2DAGB_SEM_38                                                   0x5192
+#define mmACP_AXI2DAGB_SEM_39                                                   0x5193
+#define mmACP_AXI2DAGB_SEM_40                                                   0x5194
+#define mmACP_AXI2DAGB_SEM_41                                                   0x5195
+#define mmACP_AXI2DAGB_SEM_42                                                   0x5196
+#define mmACP_AXI2DAGB_SEM_43                                                   0x5197
+#define mmACP_AXI2DAGB_SEM_44                                                   0x5198
+#define mmACP_AXI2DAGB_SEM_45                                                   0x5199
+#define mmACP_AXI2DAGB_SEM_46                                                   0x519a
+#define mmACP_AXI2DAGB_SEM_47                                                   0x519b
+#define mmACP_SRBM_Client_Base_Addr                                             0x519c
+#define mmACP_SRBM_Client_RDDATA                                                0x519d
+#define mmACP_SRBM_Cycle_Sts                                                    0x519e
+#define mmACP_SRBM_Targ_Idx_Addr                                                0x519f
+#define mmACP_SRBM_Targ_Idx_Data                                                0x51a0
+#define mmACP_SEMA_ADDR_LOW                                                     0x51a1
+#define mmACP_SEMA_ADDR_HIGH                                                    0x51a2
+#define mmACP_SEMA_CMD                                                          0x51a3
+#define mmACP_SEMA_STS                                                          0x51a4
+#define mmACP_SEMA_REQ                                                          0x51a5
+#define mmACP_FW_STATUS                                                         0x51a6
+#define mmACP_FUTURE_REG_ACLK_0                                                 0x51a7
+#define mmACP_FUTURE_REG_ACLK_1                                                 0x51a8
+#define mmACP_FUTURE_REG_ACLK_2                                                 0x51a9
+#define mmACP_FUTURE_REG_ACLK_3                                                 0x51aa
+#define mmACP_FUTURE_REG_ACLK_4                                                 0x51ab
+#define mmACP_TIMER                                                             0x51ac
+#define mmACP_TIMER_CNTL                                                        0x51ad
+#define mmACP_DSP0_TIMER                                                        0x51ae
+#define mmACP_DSP1_TIMER                                                        0x51af
+#define mmACP_DSP2_TIMER                                                        0x51b0
+#define mmACP_I2S_TRANSMIT_BYTE_CNT_HIGH                                        0x51b1
+#define mmACP_I2S_TRANSMIT_BYTE_CNT_LOW                                         0x51b2
+#define mmACP_I2S_BT_TRANSMIT_BYTE_CNT_HIGH                                     0x51b3
+#define mmACP_I2S_BT_TRANSMIT_BYTE_CNT_LOW                                      0x51b4
+#define mmACP_I2S_BT_RECEIVE_BYTE_CNT_HIGH                                      0x51b5
+#define mmACP_I2S_BT_RECEIVE_BYTE_CNT_LOW                                       0x51b6
+#define mmACP_DSP0_CS_STATE                                                     0x51b7
+#define mmACP_DSP1_CS_STATE                                                     0x51b8
+#define mmACP_DSP2_CS_STATE                                                     0x51b9
+#define mmACP_SCRATCH_REG_BASE_ADDR                                             0x51ba
+#define mmCC_ACP_EFUSE                                                          0x51c8
+#define mmACP_PGFSM_RETAIN_REG                                                  0x51c9
+#define mmACP_PGFSM_CONFIG_REG                                                  0x51ca
+#define mmACP_PGFSM_WRITE_REG                                                   0x51cb
+#define mmACP_PGFSM_READ_REG_0                                                  0x51cc
+#define mmACP_PGFSM_READ_REG_1                                                  0x51cd
+#define mmACP_PGFSM_READ_REG_2                                                  0x51ce
+#define mmACP_PGFSM_READ_REG_3                                                  0x51cf
+#define mmACP_PGFSM_READ_REG_4                                                  0x51d0
+#define mmACP_PGFSM_READ_REG_5                                                  0x51d1
+#define mmACP_IP_PGFSM_ENABLE                                                   0x51d2
+#define mmACP_I2S_PIN_CONFIG                                                    0x51d3
+#define mmACP_AZALIA_I2S_SELECT                                                 0x51d4
+#define mmACP_CHIP_PKG_FOR_PAD_ISOLATION                                        0x51d5
+#define mmACP_AUDIO_PAD_PULLUP_PULLDOWN_CTRL                                    0x51d6
+#define mmACP_BT_UART_PAD_SEL                                                   0x51d7
+#define mmACP_SCRATCH_REG_0                                                     0x52c0
+#define mmACP_SCRATCH_REG_1                                                     0x52c1
+#define mmACP_SCRATCH_REG_2                                                     0x52c2
+#define mmACP_SCRATCH_REG_3                                                     0x52c3
+#define mmACP_SCRATCH_REG_4                                                     0x52c4
+#define mmACP_SCRATCH_REG_5                                                     0x52c5
+#define mmACP_SCRATCH_REG_6                                                     0x52c6
+#define mmACP_SCRATCH_REG_7                                                     0x52c7
+#define mmACP_SCRATCH_REG_8                                                     0x52c8
+#define mmACP_SCRATCH_REG_9                                                     0x52c9
+#define mmACP_SCRATCH_REG_10                                                    0x52ca
+#define mmACP_SCRATCH_REG_11                                                    0x52cb
+#define mmACP_SCRATCH_REG_12                                                    0x52cc
+#define mmACP_SCRATCH_REG_13                                                    0x52cd
+#define mmACP_SCRATCH_REG_14                                                    0x52ce
+#define mmACP_SCRATCH_REG_15                                                    0x52cf
+#define mmACP_SCRATCH_REG_16                                                    0x52d0
+#define mmACP_SCRATCH_REG_17                                                    0x52d1
+#define mmACP_SCRATCH_REG_18                                                    0x52d2
+#define mmACP_SCRATCH_REG_19                                                    0x52d3
+#define mmACP_SCRATCH_REG_20                                                    0x52d4
+#define mmACP_SCRATCH_REG_21                                                    0x52d5
+#define mmACP_SCRATCH_REG_22                                                    0x52d6
+#define mmACP_SCRATCH_REG_23                                                    0x52d7
+#define mmACP_SCRATCH_REG_24                                                    0x52d8
+#define mmACP_SCRATCH_REG_25                                                    0x52d9
+#define mmACP_SCRATCH_REG_26                                                    0x52da
+#define mmACP_SCRATCH_REG_27                                                    0x52db
+#define mmACP_SCRATCH_REG_28                                                    0x52dc
+#define mmACP_SCRATCH_REG_29                                                    0x52dd
+#define mmACP_SCRATCH_REG_30                                                    0x52de
+#define mmACP_SCRATCH_REG_31                                                    0x52df
+#define mmACP_SCRATCH_REG_32                                                    0x52e0
+#define mmACP_SCRATCH_REG_33                                                    0x52e1
+#define mmACP_SCRATCH_REG_34                                                    0x52e2
+#define mmACP_SCRATCH_REG_35                                                    0x52e3
+#define mmACP_SCRATCH_REG_36                                                    0x52e4
+#define mmACP_SCRATCH_REG_37                                                    0x52e5
+#define mmACP_SCRATCH_REG_38                                                    0x52e6
+#define mmACP_SCRATCH_REG_39                                                    0x52e7
+#define mmACP_SCRATCH_REG_40                                                    0x52e8
+#define mmACP_SCRATCH_REG_41                                                    0x52e9
+#define mmACP_SCRATCH_REG_42                                                    0x52ea
+#define mmACP_SCRATCH_REG_43                                                    0x52eb
+#define mmACP_SCRATCH_REG_44                                                    0x52ec
+#define mmACP_SCRATCH_REG_45                                                    0x52ed
+#define mmACP_SCRATCH_REG_46                                                    0x52ee
+#define mmACP_SCRATCH_REG_47                                                    0x52ef
+#define mmACP_VOICE_WAKEUP_ENABLE                                               0x51e8
+#define mmACP_VOICE_WAKEUP_STATUS                                               0x51e9
+#define mmI2S_VOICE_WAKEUP_LOWER_THRESHOLD                                      0x51ea
+#define mmI2S_VOICE_WAKEUP_HIGHER_THRESHOLD                                     0x51eb
+#define mmI2S_VOICE_WAKEUP_NO_OF_SAMPLES                                        0x51ec
+#define mmI2S_VOICE_WAKEUP_NO_OF_PEAKS                                          0x51ed
+#define mmI2S_VOICE_WAKEUP_DURATION_OF_N_PEAKS                                  0x51ee
+#define mmI2S_VOICE_WAKEUP_BITCLK_TOGGLE_DETECTION                              0x51ef
+#define mmI2S_VOICE_WAKEUP_DATA_PATH_SWITCH                                     0x51f0
+#define mmI2S_VOICE_WAKEUP_DATA_POINTER                                         0x51f1
+#define mmI2S_VOICE_WAKEUP_AUTH_MATCH                                           0x51f2
+#define mmI2S_VOICE_WAKEUP_8KB_WRAP                                             0x51f3
+#define mmACP_I2S_RECEIVED_BYTE_CNT_HIGH                                        0x51f4
+#define mmACP_I2S_RECEIVED_BYTE_CNT_LOW                                         0x51f5
+#define mmACP_I2S_MICSP_TRANSMIT_BYTE_CNT_HIGH                                  0x51f6
+#define mmACP_I2S_MICSP_TRANSMIT_BYTE_CNT_LOW                                   0x51f7
+#define mmACP_MEM_SHUT_DOWN_REQ_LO                                              0x51f8
+#define mmACP_MEM_SHUT_DOWN_REQ_HI                                              0x51f9
+#define mmACP_MEM_SHUT_DOWN_STS_LO                                              0x51fa
+#define mmACP_MEM_SHUT_DOWN_STS_HI                                              0x51fb
+#define mmACP_MEM_DEEP_SLEEP_REQ_LO                                             0x51fc
+#define mmACP_MEM_DEEP_SLEEP_REQ_HI                                             0x51fd
+#define mmACP_MEM_DEEP_SLEEP_STS_LO                                             0x51fe
+#define mmACP_MEM_DEEP_SLEEP_STS_HI                                             0x51ff
+#define mmACP_MEM_WAKEUP_FROM_SHUT_DOWN_LO                                      0x5200
+#define mmACP_MEM_WAKEUP_FROM_SHUT_DOWN_HI                                      0x5201
+#define mmACP_MEM_WAKEUP_FROM_SLEEP_LO                                          0x5202
+#define mmACP_MEM_WAKEUP_FROM_SLEEP_HI                                          0x5203
+#define mmACP_I2SSP_IER                                                         0x5210
+#define mmACP_I2SSP_IRER                                                        0x5211
+#define mmACP_I2SSP_ITER                                                        0x5212
+#define mmACP_I2SSP_CER                                                         0x5213
+#define mmACP_I2SSP_CCR                                                         0x5214
+#define mmACP_I2SSP_RXFFR                                                       0x5215
+#define mmACP_I2SSP_TXFFR                                                       0x5216
+#define mmACP_I2SSP_LRBR0                                                       0x5218
+#define mmACP_I2SSP_RRBR0                                                       0x5219
+#define mmACP_I2SSP_RER0                                                        0x521a
+#define mmACP_I2SSP_TER0                                                        0x521b
+#define mmACP_I2SSP_RCR0                                                        0x521c
+#define mmACP_I2SSP_TCR0                                                        0x521d
+#define mmACP_I2SSP_ISR0                                                        0x521e
+#define mmACP_I2SSP_IMR0                                                        0x521f
+#define mmACP_I2SSP_ROR0                                                        0x5220
+#define mmACP_I2SSP_TOR0                                                        0x5221
+#define mmACP_I2SSP_RFCR0                                                       0x5222
+#define mmACP_I2SSP_TFCR0                                                       0x5223
+#define mmACP_I2SSP_RFF0                                                        0x5224
+#define mmACP_I2SSP_TFF0                                                        0x5225
+#define mmACP_I2SSP_RXDMA                                                       0x5226
+#define mmACP_I2SSP_RRXDMA                                                      0x5227
+#define mmACP_I2SSP_TXDMA                                                       0x5228
+#define mmACP_I2SSP_RTXDMA                                                      0x5229
+#define mmACP_I2SSP_COMP_PARAM_2                                                0x522a
+#define mmACP_I2SSP_COMP_PARAM_1                                                0x522b
+#define mmACP_I2SSP_COMP_VERSION                                                0x522c
+#define mmACP_I2SSP_COMP_TYPE                                                   0x522d
+#define mmACP_I2SMICSP_IER                                                      0x522e
+#define mmACP_I2SMICSP_IRER                                                     0x522f
+#define mmACP_I2SMICSP_ITER                                                     0x5230
+#define mmACP_I2SMICSP_CER                                                      0x5231
+#define mmACP_I2SMICSP_CCR                                                      0x5232
+#define mmACP_I2SMICSP_RXFFR                                                    0x5233
+#define mmACP_I2SMICSP_TXFFR                                                    0x5234
+#define mmACP_I2SMICSP_LRBR0                                                    0x5236
+#define mmACP_I2SMICSP_RRBR0                                                    0x5237
+#define mmACP_I2SMICSP_RER0                                                     0x5238
+#define mmACP_I2SMICSP_TER0                                                     0x5239
+#define mmACP_I2SMICSP_RCR0                                                     0x523a
+#define mmACP_I2SMICSP_TCR0                                                     0x523b
+#define mmACP_I2SMICSP_ISR0                                                     0x523c
+#define mmACP_I2SMICSP_IMR0                                                     0x523d
+#define mmACP_I2SMICSP_ROR0                                                     0x523e
+#define mmACP_I2SMICSP_TOR0                                                     0x523f
+#define mmACP_I2SMICSP_RFCR0                                                    0x5240
+#define mmACP_I2SMICSP_TFCR0                                                    0x5241
+#define mmACP_I2SMICSP_RFF0                                                     0x5242
+#define mmACP_I2SMICSP_TFF0                                                     0x5243
+#define mmACP_I2SMICSP_LRBR1                                                    0x5246
+#define mmACP_I2SMICSP_RRBR1                                                    0x5247
+#define mmACP_I2SMICSP_RER1                                                     0x5248
+#define mmACP_I2SMICSP_TER1                                                     0x5249
+#define mmACP_I2SMICSP_RCR1                                                     0x524a
+#define mmACP_I2SMICSP_TCR1                                                     0x524b
+#define mmACP_I2SMICSP_ISR1                                                     0x524c
+#define mmACP_I2SMICSP_IMR1                                                     0x524d
+#define mmACP_I2SMICSP_ROR1                                                     0x524e
+#define mmACP_I2SMICSP_TOR1                                                     0x524f
+#define mmACP_I2SMICSP_RFCR1                                                    0x5250
+#define mmACP_I2SMICSP_TFCR1                                                    0x5251
+#define mmACP_I2SMICSP_RFF1                                                     0x5252
+#define mmACP_I2SMICSP_TFF1                                                     0x5253
+#define mmACP_I2SMICSP_RXDMA                                                    0x5254
+#define mmACP_I2SMICSP_RRXDMA                                                   0x5255
+#define mmACP_I2SMICSP_TXDMA                                                    0x5256
+#define mmACP_I2SMICSP_RTXDMA                                                   0x5257
+#define mmACP_I2SMICSP_COMP_PARAM_2                                             0x5258
+#define mmACP_I2SMICSP_COMP_PARAM_1                                             0x5259
+#define mmACP_I2SMICSP_COMP_VERSION                                             0x525a
+#define mmACP_I2SMICSP_COMP_TYPE                                                0x525b
+#define mmACP_I2SBT_IER                                                         0x525c
+#define mmACP_I2SBT_IRER                                                        0x525d
+#define mmACP_I2SBT_ITER                                                        0x525e
+#define mmACP_I2SBT_CER                                                         0x525f
+#define mmACP_I2SBT_CCR                                                         0x5260
+#define mmACP_I2SBT_RXFFR                                                       0x5261
+#define mmACP_I2SBT_TXFFR                                                       0x5262
+#define mmACP_I2SBT_LRBR0                                                       0x5264
+#define mmACP_I2SBT_RRBR0                                                       0x5265
+#define mmACP_I2SBT_RER0                                                        0x5266
+#define mmACP_I2SBT_TER0                                                        0x5267
+#define mmACP_I2SBT_RCR0                                                        0x5268
+#define mmACP_I2SBT_TCR0                                                        0x5269
+#define mmACP_I2SBT_ISR0                                                        0x526a
+#define mmACP_I2SBT_IMR0                                                        0x526b
+#define mmACP_I2SBT_ROR0                                                        0x526c
+#define mmACP_I2SBT_TOR0                                                        0x526d
+#define mmACP_I2SBT_RFCR0                                                       0x526e
+#define mmACP_I2SBT_TFCR0                                                       0x526f
+#define mmACP_I2SBT_RFF0                                                        0x5270
+#define mmACP_I2SBT_TFF0                                                        0x5271
+#define mmACP_I2SBT_LRBR1                                                       0x5274
+#define mmACP_I2SBT_RRBR1                                                       0x5275
+#define mmACP_I2SBT_RER1                                                        0x5276
+#define mmACP_I2SBT_TER1                                                        0x5277
+#define mmACP_I2SBT_RCR1                                                        0x5278
+#define mmACP_I2SBT_TCR1                                                        0x5279
+#define mmACP_I2SBT_ISR1                                                        0x527a
+#define mmACP_I2SBT_IMR1                                                        0x527b
+#define mmACP_I2SBT_ROR1                                                        0x527c
+#define mmACP_I2SBT_TOR1                                                        0x527d
+#define mmACP_I2SBT_RFCR1                                                       0x527e
+#define mmACP_I2SBT_TFCR1                                                       0x527f
+#define mmACP_I2SBT_RFF1                                                        0x5280
+#define mmACP_I2SBT_TFF1                                                        0x5281
+#define mmACP_I2SBT_RXDMA                                                       0x5282
+#define mmACP_I2SBT_RRXDMA                                                      0x5283
+#define mmACP_I2SBT_TXDMA                                                       0x5284
+#define mmACP_I2SBT_RTXDMA                                                      0x5285
+#define mmACP_I2SBT_COMP_PARAM_2                                                0x5286
+#define mmACP_I2SBT_COMP_PARAM_1                                                0x5287
+#define mmACP_I2SBT_COMP_VERSION                                                0x5288
+#define mmACP_I2SBT_COMP_TYPE                                                   0x5289
+
+#endif /* ACP_2_2_D_H */
diff --git a/sound/soc/amd/include/acp_2_2_enum.h b/sound/soc/amd/include/acp_2_2_enum.h
new file mode 100644 (file)
index 0000000..f3577c8
--- /dev/null
@@ -0,0 +1,1068 @@
+/*
+ * ACP_2_2 Register documentation
+ *
+ * Copyright (C) 2014  Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#ifndef ACP_2_2_ENUM_H
+#define ACP_2_2_ENUM_H
+
+typedef enum DebugBlockId {
+       DBG_BLOCK_ID_RESERVED                            = 0x0,
+       DBG_BLOCK_ID_DBG                                 = 0x1,
+       DBG_BLOCK_ID_VMC                                 = 0x2,
+       DBG_BLOCK_ID_PDMA                                = 0x3,
+       DBG_BLOCK_ID_CG                                  = 0x4,
+       DBG_BLOCK_ID_SRBM                                = 0x5,
+       DBG_BLOCK_ID_GRBM                                = 0x6,
+       DBG_BLOCK_ID_RLC                                 = 0x7,
+       DBG_BLOCK_ID_CSC                                 = 0x8,
+       DBG_BLOCK_ID_SEM                                 = 0x9,
+       DBG_BLOCK_ID_IH                                  = 0xa,
+       DBG_BLOCK_ID_SC                                  = 0xb,
+       DBG_BLOCK_ID_SQ                                  = 0xc,
+       DBG_BLOCK_ID_UVDU                                = 0xd,
+       DBG_BLOCK_ID_SQA                                 = 0xe,
+       DBG_BLOCK_ID_SDMA0                               = 0xf,
+       DBG_BLOCK_ID_SDMA1                               = 0x10,
+       DBG_BLOCK_ID_SPIM                                = 0x11,
+       DBG_BLOCK_ID_GDS                                 = 0x12,
+       DBG_BLOCK_ID_VC0                                 = 0x13,
+       DBG_BLOCK_ID_VC1                                 = 0x14,
+       DBG_BLOCK_ID_PA0                                 = 0x15,
+       DBG_BLOCK_ID_PA1                                 = 0x16,
+       DBG_BLOCK_ID_CP0                                 = 0x17,
+       DBG_BLOCK_ID_CP1                                 = 0x18,
+       DBG_BLOCK_ID_CP2                                 = 0x19,
+       DBG_BLOCK_ID_XBR                                 = 0x1a,
+       DBG_BLOCK_ID_UVDM                                = 0x1b,
+       DBG_BLOCK_ID_VGT0                                = 0x1c,
+       DBG_BLOCK_ID_VGT1                                = 0x1d,
+       DBG_BLOCK_ID_IA                                  = 0x1e,
+       DBG_BLOCK_ID_SXM0                                = 0x1f,
+       DBG_BLOCK_ID_SXM1                                = 0x20,
+       DBG_BLOCK_ID_SCT0                                = 0x21,
+       DBG_BLOCK_ID_SCT1                                = 0x22,
+       DBG_BLOCK_ID_SPM0                                = 0x23,
+       DBG_BLOCK_ID_SPM1                                = 0x24,
+       DBG_BLOCK_ID_UNUSED0                             = 0x25,
+       DBG_BLOCK_ID_UNUSED1                             = 0x26,
+       DBG_BLOCK_ID_TCAA                                = 0x27,
+       DBG_BLOCK_ID_TCAB                                = 0x28,
+       DBG_BLOCK_ID_TCCA                                = 0x29,
+       DBG_BLOCK_ID_TCCB                                = 0x2a,
+       DBG_BLOCK_ID_MCC0                                = 0x2b,
+       DBG_BLOCK_ID_MCC1                                = 0x2c,
+       DBG_BLOCK_ID_MCC2                                = 0x2d,
+       DBG_BLOCK_ID_MCC3                                = 0x2e,
+       DBG_BLOCK_ID_SXS0                                = 0x2f,
+       DBG_BLOCK_ID_SXS1                                = 0x30,
+       DBG_BLOCK_ID_SXS2                                = 0x31,
+       DBG_BLOCK_ID_SXS3                                = 0x32,
+       DBG_BLOCK_ID_SXS4                                = 0x33,
+       DBG_BLOCK_ID_SXS5                                = 0x34,
+       DBG_BLOCK_ID_SXS6                                = 0x35,
+       DBG_BLOCK_ID_SXS7                                = 0x36,
+       DBG_BLOCK_ID_SXS8                                = 0x37,
+       DBG_BLOCK_ID_SXS9                                = 0x38,
+       DBG_BLOCK_ID_BCI0                                = 0x39,
+       DBG_BLOCK_ID_BCI1                                = 0x3a,
+       DBG_BLOCK_ID_BCI2                                = 0x3b,
+       DBG_BLOCK_ID_BCI3                                = 0x3c,
+       DBG_BLOCK_ID_MCB                                 = 0x3d,
+       DBG_BLOCK_ID_UNUSED6                             = 0x3e,
+       DBG_BLOCK_ID_SQA00                               = 0x3f,
+       DBG_BLOCK_ID_SQA01                               = 0x40,
+       DBG_BLOCK_ID_SQA02                               = 0x41,
+       DBG_BLOCK_ID_SQA10                               = 0x42,
+       DBG_BLOCK_ID_SQA11                               = 0x43,
+       DBG_BLOCK_ID_SQA12                               = 0x44,
+       DBG_BLOCK_ID_UNUSED7                             = 0x45,
+       DBG_BLOCK_ID_UNUSED8                             = 0x46,
+       DBG_BLOCK_ID_SQB00                               = 0x47,
+       DBG_BLOCK_ID_SQB01                               = 0x48,
+       DBG_BLOCK_ID_SQB10                               = 0x49,
+       DBG_BLOCK_ID_SQB11                               = 0x4a,
+       DBG_BLOCK_ID_SQ00                                = 0x4b,
+       DBG_BLOCK_ID_SQ01                                = 0x4c,
+       DBG_BLOCK_ID_SQ10                                = 0x4d,
+       DBG_BLOCK_ID_SQ11                                = 0x4e,
+       DBG_BLOCK_ID_CB00                                = 0x4f,
+       DBG_BLOCK_ID_CB01                                = 0x50,
+       DBG_BLOCK_ID_CB02                                = 0x51,
+       DBG_BLOCK_ID_CB03                                = 0x52,
+       DBG_BLOCK_ID_CB04                                = 0x53,
+       DBG_BLOCK_ID_UNUSED9                             = 0x54,
+       DBG_BLOCK_ID_UNUSED10                            = 0x55,
+       DBG_BLOCK_ID_UNUSED11                            = 0x56,
+       DBG_BLOCK_ID_CB10                                = 0x57,
+       DBG_BLOCK_ID_CB11                                = 0x58,
+       DBG_BLOCK_ID_CB12                                = 0x59,
+       DBG_BLOCK_ID_CB13                                = 0x5a,
+       DBG_BLOCK_ID_CB14                                = 0x5b,
+       DBG_BLOCK_ID_UNUSED12                            = 0x5c,
+       DBG_BLOCK_ID_UNUSED13                            = 0x5d,
+       DBG_BLOCK_ID_UNUSED14                            = 0x5e,
+       DBG_BLOCK_ID_TCP0                                = 0x5f,
+       DBG_BLOCK_ID_TCP1                                = 0x60,
+       DBG_BLOCK_ID_TCP2                                = 0x61,
+       DBG_BLOCK_ID_TCP3                                = 0x62,
+       DBG_BLOCK_ID_TCP4                                = 0x63,
+       DBG_BLOCK_ID_TCP5                                = 0x64,
+       DBG_BLOCK_ID_TCP6                                = 0x65,
+       DBG_BLOCK_ID_TCP7                                = 0x66,
+       DBG_BLOCK_ID_TCP8                                = 0x67,
+       DBG_BLOCK_ID_TCP9                                = 0x68,
+       DBG_BLOCK_ID_TCP10                               = 0x69,
+       DBG_BLOCK_ID_TCP11                               = 0x6a,
+       DBG_BLOCK_ID_TCP12                               = 0x6b,
+       DBG_BLOCK_ID_TCP13                               = 0x6c,
+       DBG_BLOCK_ID_TCP14                               = 0x6d,
+       DBG_BLOCK_ID_TCP15                               = 0x6e,
+       DBG_BLOCK_ID_TCP16                               = 0x6f,
+       DBG_BLOCK_ID_TCP17                               = 0x70,
+       DBG_BLOCK_ID_TCP18                               = 0x71,
+       DBG_BLOCK_ID_TCP19                               = 0x72,
+       DBG_BLOCK_ID_TCP20                               = 0x73,
+       DBG_BLOCK_ID_TCP21                               = 0x74,
+       DBG_BLOCK_ID_TCP22                               = 0x75,
+       DBG_BLOCK_ID_TCP23                               = 0x76,
+       DBG_BLOCK_ID_TCP_RESERVED0                       = 0x77,
+       DBG_BLOCK_ID_TCP_RESERVED1                       = 0x78,
+       DBG_BLOCK_ID_TCP_RESERVED2                       = 0x79,
+       DBG_BLOCK_ID_TCP_RESERVED3                       = 0x7a,
+       DBG_BLOCK_ID_TCP_RESERVED4                       = 0x7b,
+       DBG_BLOCK_ID_TCP_RESERVED5                       = 0x7c,
+       DBG_BLOCK_ID_TCP_RESERVED6                       = 0x7d,
+       DBG_BLOCK_ID_TCP_RESERVED7                       = 0x7e,
+       DBG_BLOCK_ID_DB00                                = 0x7f,
+       DBG_BLOCK_ID_DB01                                = 0x80,
+       DBG_BLOCK_ID_DB02                                = 0x81,
+       DBG_BLOCK_ID_DB03                                = 0x82,
+       DBG_BLOCK_ID_DB04                                = 0x83,
+       DBG_BLOCK_ID_UNUSED15                            = 0x84,
+       DBG_BLOCK_ID_UNUSED16                            = 0x85,
+       DBG_BLOCK_ID_UNUSED17                            = 0x86,
+       DBG_BLOCK_ID_DB10                                = 0x87,
+       DBG_BLOCK_ID_DB11                                = 0x88,
+       DBG_BLOCK_ID_DB12                                = 0x89,
+       DBG_BLOCK_ID_DB13                                = 0x8a,
+       DBG_BLOCK_ID_DB14                                = 0x8b,
+       DBG_BLOCK_ID_UNUSED18                            = 0x8c,
+       DBG_BLOCK_ID_UNUSED19                            = 0x8d,
+       DBG_BLOCK_ID_UNUSED20                            = 0x8e,
+       DBG_BLOCK_ID_TCC0                                = 0x8f,
+       DBG_BLOCK_ID_TCC1                                = 0x90,
+       DBG_BLOCK_ID_TCC2                                = 0x91,
+       DBG_BLOCK_ID_TCC3                                = 0x92,
+       DBG_BLOCK_ID_TCC4                                = 0x93,
+       DBG_BLOCK_ID_TCC5                                = 0x94,
+       DBG_BLOCK_ID_TCC6                                = 0x95,
+       DBG_BLOCK_ID_TCC7                                = 0x96,
+       DBG_BLOCK_ID_SPS00                               = 0x97,
+       DBG_BLOCK_ID_SPS01                               = 0x98,
+       DBG_BLOCK_ID_SPS02                               = 0x99,
+       DBG_BLOCK_ID_SPS10                               = 0x9a,
+       DBG_BLOCK_ID_SPS11                               = 0x9b,
+       DBG_BLOCK_ID_SPS12                               = 0x9c,
+       DBG_BLOCK_ID_UNUSED21                            = 0x9d,
+       DBG_BLOCK_ID_UNUSED22                            = 0x9e,
+       DBG_BLOCK_ID_TA00                                = 0x9f,
+       DBG_BLOCK_ID_TA01                                = 0xa0,
+       DBG_BLOCK_ID_TA02                                = 0xa1,
+       DBG_BLOCK_ID_TA03                                = 0xa2,
+       DBG_BLOCK_ID_TA04                                = 0xa3,
+       DBG_BLOCK_ID_TA05                                = 0xa4,
+       DBG_BLOCK_ID_TA06                                = 0xa5,
+       DBG_BLOCK_ID_TA07                                = 0xa6,
+       DBG_BLOCK_ID_TA08                                = 0xa7,
+       DBG_BLOCK_ID_TA09                                = 0xa8,
+       DBG_BLOCK_ID_TA0A                                = 0xa9,
+       DBG_BLOCK_ID_TA0B                                = 0xaa,
+       DBG_BLOCK_ID_UNUSED23                            = 0xab,
+       DBG_BLOCK_ID_UNUSED24                            = 0xac,
+       DBG_BLOCK_ID_UNUSED25                            = 0xad,
+       DBG_BLOCK_ID_UNUSED26                            = 0xae,
+       DBG_BLOCK_ID_TA10                                = 0xaf,
+       DBG_BLOCK_ID_TA11                                = 0xb0,
+       DBG_BLOCK_ID_TA12                                = 0xb1,
+       DBG_BLOCK_ID_TA13                                = 0xb2,
+       DBG_BLOCK_ID_TA14                                = 0xb3,
+       DBG_BLOCK_ID_TA15                                = 0xb4,
+       DBG_BLOCK_ID_TA16                                = 0xb5,
+       DBG_BLOCK_ID_TA17                                = 0xb6,
+       DBG_BLOCK_ID_TA18                                = 0xb7,
+       DBG_BLOCK_ID_TA19                                = 0xb8,
+       DBG_BLOCK_ID_TA1A                                = 0xb9,
+       DBG_BLOCK_ID_TA1B                                = 0xba,
+       DBG_BLOCK_ID_UNUSED27                            = 0xbb,
+       DBG_BLOCK_ID_UNUSED28                            = 0xbc,
+       DBG_BLOCK_ID_UNUSED29                            = 0xbd,
+       DBG_BLOCK_ID_UNUSED30                            = 0xbe,
+       DBG_BLOCK_ID_TD00                                = 0xbf,
+       DBG_BLOCK_ID_TD01                                = 0xc0,
+       DBG_BLOCK_ID_TD02                                = 0xc1,
+       DBG_BLOCK_ID_TD03                                = 0xc2,
+       DBG_BLOCK_ID_TD04                                = 0xc3,
+       DBG_BLOCK_ID_TD05                                = 0xc4,
+       DBG_BLOCK_ID_TD06                                = 0xc5,
+       DBG_BLOCK_ID_TD07                                = 0xc6,
+       DBG_BLOCK_ID_TD08                                = 0xc7,
+       DBG_BLOCK_ID_TD09                                = 0xc8,
+       DBG_BLOCK_ID_TD0A                                = 0xc9,
+       DBG_BLOCK_ID_TD0B                                = 0xca,
+       DBG_BLOCK_ID_UNUSED31                            = 0xcb,
+       DBG_BLOCK_ID_UNUSED32                            = 0xcc,
+       DBG_BLOCK_ID_UNUSED33                            = 0xcd,
+       DBG_BLOCK_ID_UNUSED34                            = 0xce,
+       DBG_BLOCK_ID_TD10                                = 0xcf,
+       DBG_BLOCK_ID_TD11                                = 0xd0,
+       DBG_BLOCK_ID_TD12                                = 0xd1,
+       DBG_BLOCK_ID_TD13                                = 0xd2,
+       DBG_BLOCK_ID_TD14                                = 0xd3,
+       DBG_BLOCK_ID_TD15                                = 0xd4,
+       DBG_BLOCK_ID_TD16                                = 0xd5,
+       DBG_BLOCK_ID_TD17                                = 0xd6,
+       DBG_BLOCK_ID_TD18                                = 0xd7,
+       DBG_BLOCK_ID_TD19                                = 0xd8,
+       DBG_BLOCK_ID_TD1A                                = 0xd9,
+       DBG_BLOCK_ID_TD1B                                = 0xda,
+       DBG_BLOCK_ID_UNUSED35                            = 0xdb,
+       DBG_BLOCK_ID_UNUSED36                            = 0xdc,
+       DBG_BLOCK_ID_UNUSED37                            = 0xdd,
+       DBG_BLOCK_ID_UNUSED38                            = 0xde,
+       DBG_BLOCK_ID_LDS00                               = 0xdf,
+       DBG_BLOCK_ID_LDS01                               = 0xe0,
+       DBG_BLOCK_ID_LDS02                               = 0xe1,
+       DBG_BLOCK_ID_LDS03                               = 0xe2,
+       DBG_BLOCK_ID_LDS04                               = 0xe3,
+       DBG_BLOCK_ID_LDS05                               = 0xe4,
+       DBG_BLOCK_ID_LDS06                               = 0xe5,
+       DBG_BLOCK_ID_LDS07                               = 0xe6,
+       DBG_BLOCK_ID_LDS08                               = 0xe7,
+       DBG_BLOCK_ID_LDS09                               = 0xe8,
+       DBG_BLOCK_ID_LDS0A                               = 0xe9,
+       DBG_BLOCK_ID_LDS0B                               = 0xea,
+       DBG_BLOCK_ID_UNUSED39                            = 0xeb,
+       DBG_BLOCK_ID_UNUSED40                            = 0xec,
+       DBG_BLOCK_ID_UNUSED41                            = 0xed,
+       DBG_BLOCK_ID_UNUSED42                            = 0xee,
+       DBG_BLOCK_ID_LDS10                               = 0xef,
+       DBG_BLOCK_ID_LDS11                               = 0xf0,
+       DBG_BLOCK_ID_LDS12                               = 0xf1,
+       DBG_BLOCK_ID_LDS13                               = 0xf2,
+       DBG_BLOCK_ID_LDS14                               = 0xf3,
+       DBG_BLOCK_ID_LDS15                               = 0xf4,
+       DBG_BLOCK_ID_LDS16                               = 0xf5,
+       DBG_BLOCK_ID_LDS17                               = 0xf6,
+       DBG_BLOCK_ID_LDS18                               = 0xf7,
+       DBG_BLOCK_ID_LDS19                               = 0xf8,
+       DBG_BLOCK_ID_LDS1A                               = 0xf9,
+       DBG_BLOCK_ID_LDS1B                               = 0xfa,
+       DBG_BLOCK_ID_UNUSED43                            = 0xfb,
+       DBG_BLOCK_ID_UNUSED44                            = 0xfc,
+       DBG_BLOCK_ID_UNUSED45                            = 0xfd,
+       DBG_BLOCK_ID_UNUSED46                            = 0xfe,
+} DebugBlockId;
+typedef enum DebugBlockId_BY2 {
+       DBG_BLOCK_ID_RESERVED_BY2                        = 0x0,
+       DBG_BLOCK_ID_VMC_BY2                             = 0x1,
+       DBG_BLOCK_ID_UNUSED0_BY2                         = 0x2,
+       DBG_BLOCK_ID_GRBM_BY2                            = 0x3,
+       DBG_BLOCK_ID_CSC_BY2                             = 0x4,
+       DBG_BLOCK_ID_IH_BY2                              = 0x5,
+       DBG_BLOCK_ID_SQ_BY2                              = 0x6,
+       DBG_BLOCK_ID_UVD_BY2                             = 0x7,
+       DBG_BLOCK_ID_SDMA0_BY2                           = 0x8,
+       DBG_BLOCK_ID_SPIM_BY2                            = 0x9,
+       DBG_BLOCK_ID_VC0_BY2                             = 0xa,
+       DBG_BLOCK_ID_PA_BY2                              = 0xb,
+       DBG_BLOCK_ID_CP0_BY2                             = 0xc,
+       DBG_BLOCK_ID_CP2_BY2                             = 0xd,
+       DBG_BLOCK_ID_PC0_BY2                             = 0xe,
+       DBG_BLOCK_ID_BCI0_BY2                            = 0xf,
+       DBG_BLOCK_ID_SXM0_BY2                            = 0x10,
+       DBG_BLOCK_ID_SCT0_BY2                            = 0x11,
+       DBG_BLOCK_ID_SPM0_BY2                            = 0x12,
+       DBG_BLOCK_ID_BCI2_BY2                            = 0x13,
+       DBG_BLOCK_ID_TCA_BY2                             = 0x14,
+       DBG_BLOCK_ID_TCCA_BY2                            = 0x15,
+       DBG_BLOCK_ID_MCC_BY2                             = 0x16,
+       DBG_BLOCK_ID_MCC2_BY2                            = 0x17,
+       DBG_BLOCK_ID_MCD_BY2                             = 0x18,
+       DBG_BLOCK_ID_MCD2_BY2                            = 0x19,
+       DBG_BLOCK_ID_MCD4_BY2                            = 0x1a,
+       DBG_BLOCK_ID_MCB_BY2                             = 0x1b,
+       DBG_BLOCK_ID_SQA_BY2                             = 0x1c,
+       DBG_BLOCK_ID_SQA02_BY2                           = 0x1d,
+       DBG_BLOCK_ID_SQA11_BY2                           = 0x1e,
+       DBG_BLOCK_ID_UNUSED8_BY2                         = 0x1f,
+       DBG_BLOCK_ID_SQB_BY2                             = 0x20,
+       DBG_BLOCK_ID_SQB10_BY2                           = 0x21,
+       DBG_BLOCK_ID_UNUSED10_BY2                        = 0x22,
+       DBG_BLOCK_ID_UNUSED12_BY2                        = 0x23,
+       DBG_BLOCK_ID_CB_BY2                              = 0x24,
+       DBG_BLOCK_ID_CB02_BY2                            = 0x25,
+       DBG_BLOCK_ID_CB10_BY2                            = 0x26,
+       DBG_BLOCK_ID_CB12_BY2                            = 0x27,
+       DBG_BLOCK_ID_SXS_BY2                             = 0x28,
+       DBG_BLOCK_ID_SXS2_BY2                            = 0x29,
+       DBG_BLOCK_ID_SXS4_BY2                            = 0x2a,
+       DBG_BLOCK_ID_SXS6_BY2                            = 0x2b,
+       DBG_BLOCK_ID_DB_BY2                              = 0x2c,
+       DBG_BLOCK_ID_DB02_BY2                            = 0x2d,
+       DBG_BLOCK_ID_DB10_BY2                            = 0x2e,
+       DBG_BLOCK_ID_DB12_BY2                            = 0x2f,
+       DBG_BLOCK_ID_TCP_BY2                             = 0x30,
+       DBG_BLOCK_ID_TCP2_BY2                            = 0x31,
+       DBG_BLOCK_ID_TCP4_BY2                            = 0x32,
+       DBG_BLOCK_ID_TCP6_BY2                            = 0x33,
+       DBG_BLOCK_ID_TCP8_BY2                            = 0x34,
+       DBG_BLOCK_ID_TCP10_BY2                           = 0x35,
+       DBG_BLOCK_ID_TCP12_BY2                           = 0x36,
+       DBG_BLOCK_ID_TCP14_BY2                           = 0x37,
+       DBG_BLOCK_ID_TCP16_BY2                           = 0x38,
+       DBG_BLOCK_ID_TCP18_BY2                           = 0x39,
+       DBG_BLOCK_ID_TCP20_BY2                           = 0x3a,
+       DBG_BLOCK_ID_TCP22_BY2                           = 0x3b,
+       DBG_BLOCK_ID_TCP_RESERVED0_BY2                   = 0x3c,
+       DBG_BLOCK_ID_TCP_RESERVED2_BY2                   = 0x3d,
+       DBG_BLOCK_ID_TCP_RESERVED4_BY2                   = 0x3e,
+       DBG_BLOCK_ID_TCP_RESERVED6_BY2                   = 0x3f,
+       DBG_BLOCK_ID_TCC_BY2                             = 0x40,
+       DBG_BLOCK_ID_TCC2_BY2                            = 0x41,
+       DBG_BLOCK_ID_TCC4_BY2                            = 0x42,
+       DBG_BLOCK_ID_TCC6_BY2                            = 0x43,
+       DBG_BLOCK_ID_SPS_BY2                             = 0x44,
+       DBG_BLOCK_ID_SPS02_BY2                           = 0x45,
+       DBG_BLOCK_ID_SPS11_BY2                           = 0x46,
+       DBG_BLOCK_ID_UNUSED14_BY2                        = 0x47,
+       DBG_BLOCK_ID_TA_BY2                              = 0x48,
+       DBG_BLOCK_ID_TA02_BY2                            = 0x49,
+       DBG_BLOCK_ID_TA04_BY2                            = 0x4a,
+       DBG_BLOCK_ID_TA06_BY2                            = 0x4b,
+       DBG_BLOCK_ID_TA08_BY2                            = 0x4c,
+       DBG_BLOCK_ID_TA0A_BY2                            = 0x4d,
+       DBG_BLOCK_ID_UNUSED20_BY2                        = 0x4e,
+       DBG_BLOCK_ID_UNUSED22_BY2                        = 0x4f,
+       DBG_BLOCK_ID_TA10_BY2                            = 0x50,
+       DBG_BLOCK_ID_TA12_BY2                            = 0x51,
+       DBG_BLOCK_ID_TA14_BY2                            = 0x52,
+       DBG_BLOCK_ID_TA16_BY2                            = 0x53,
+       DBG_BLOCK_ID_TA18_BY2                            = 0x54,
+       DBG_BLOCK_ID_TA1A_BY2                            = 0x55,
+       DBG_BLOCK_ID_UNUSED24_BY2                        = 0x56,
+       DBG_BLOCK_ID_UNUSED26_BY2                        = 0x57,
+       DBG_BLOCK_ID_TD_BY2                              = 0x58,
+       DBG_BLOCK_ID_TD02_BY2                            = 0x59,
+       DBG_BLOCK_ID_TD04_BY2                            = 0x5a,
+       DBG_BLOCK_ID_TD06_BY2                            = 0x5b,
+       DBG_BLOCK_ID_TD08_BY2                            = 0x5c,
+       DBG_BLOCK_ID_TD0A_BY2                            = 0x5d,
+       DBG_BLOCK_ID_UNUSED28_BY2                        = 0x5e,
+       DBG_BLOCK_ID_UNUSED30_BY2                        = 0x5f,
+       DBG_BLOCK_ID_TD10_BY2                            = 0x60,
+       DBG_BLOCK_ID_TD12_BY2                            = 0x61,
+       DBG_BLOCK_ID_TD14_BY2                            = 0x62,
+       DBG_BLOCK_ID_TD16_BY2                            = 0x63,
+       DBG_BLOCK_ID_TD18_BY2                            = 0x64,
+       DBG_BLOCK_ID_TD1A_BY2                            = 0x65,
+       DBG_BLOCK_ID_UNUSED32_BY2                        = 0x66,
+       DBG_BLOCK_ID_UNUSED34_BY2                        = 0x67,
+       DBG_BLOCK_ID_LDS_BY2                             = 0x68,
+       DBG_BLOCK_ID_LDS02_BY2                           = 0x69,
+       DBG_BLOCK_ID_LDS04_BY2                           = 0x6a,
+       DBG_BLOCK_ID_LDS06_BY2                           = 0x6b,
+       DBG_BLOCK_ID_LDS08_BY2                           = 0x6c,
+       DBG_BLOCK_ID_LDS0A_BY2                           = 0x6d,
+       DBG_BLOCK_ID_UNUSED36_BY2                        = 0x6e,
+       DBG_BLOCK_ID_UNUSED38_BY2                        = 0x6f,
+       DBG_BLOCK_ID_LDS10_BY2                           = 0x70,
+       DBG_BLOCK_ID_LDS12_BY2                           = 0x71,
+       DBG_BLOCK_ID_LDS14_BY2                           = 0x72,
+       DBG_BLOCK_ID_LDS16_BY2                           = 0x73,
+       DBG_BLOCK_ID_LDS18_BY2                           = 0x74,
+       DBG_BLOCK_ID_LDS1A_BY2                           = 0x75,
+       DBG_BLOCK_ID_UNUSED40_BY2                        = 0x76,
+       DBG_BLOCK_ID_UNUSED42_BY2                        = 0x77,
+} DebugBlockId_BY2;
+typedef enum DebugBlockId_BY4 {
+       DBG_BLOCK_ID_RESERVED_BY4                        = 0x0,
+       DBG_BLOCK_ID_UNUSED0_BY4                         = 0x1,
+       DBG_BLOCK_ID_CSC_BY4                             = 0x2,
+       DBG_BLOCK_ID_SQ_BY4                              = 0x3,
+       DBG_BLOCK_ID_SDMA0_BY4                           = 0x4,
+       DBG_BLOCK_ID_VC0_BY4                             = 0x5,
+       DBG_BLOCK_ID_CP0_BY4                             = 0x6,
+       DBG_BLOCK_ID_UNUSED1_BY4                         = 0x7,
+       DBG_BLOCK_ID_SXM0_BY4                            = 0x8,
+       DBG_BLOCK_ID_SPM0_BY4                            = 0x9,
+       DBG_BLOCK_ID_TCAA_BY4                            = 0xa,
+       DBG_BLOCK_ID_MCC_BY4                             = 0xb,
+       DBG_BLOCK_ID_MCD_BY4                             = 0xc,
+       DBG_BLOCK_ID_MCD4_BY4                            = 0xd,
+       DBG_BLOCK_ID_SQA_BY4                             = 0xe,
+       DBG_BLOCK_ID_SQA11_BY4                           = 0xf,
+       DBG_BLOCK_ID_SQB_BY4                             = 0x10,
+       DBG_BLOCK_ID_UNUSED10_BY4                        = 0x11,
+       DBG_BLOCK_ID_CB_BY4                              = 0x12,
+       DBG_BLOCK_ID_CB10_BY4                            = 0x13,
+       DBG_BLOCK_ID_SXS_BY4                             = 0x14,
+       DBG_BLOCK_ID_SXS4_BY4                            = 0x15,
+       DBG_BLOCK_ID_DB_BY4                              = 0x16,
+       DBG_BLOCK_ID_DB10_BY4                            = 0x17,
+       DBG_BLOCK_ID_TCP_BY4                             = 0x18,
+       DBG_BLOCK_ID_TCP4_BY4                            = 0x19,
+       DBG_BLOCK_ID_TCP8_BY4                            = 0x1a,
+       DBG_BLOCK_ID_TCP12_BY4                           = 0x1b,
+       DBG_BLOCK_ID_TCP16_BY4                           = 0x1c,
+       DBG_BLOCK_ID_TCP20_BY4                           = 0x1d,
+       DBG_BLOCK_ID_TCP_RESERVED0_BY4                   = 0x1e,
+       DBG_BLOCK_ID_TCP_RESERVED4_BY4                   = 0x1f,
+       DBG_BLOCK_ID_TCC_BY4                             = 0x20,
+       DBG_BLOCK_ID_TCC4_BY4                            = 0x21,
+       DBG_BLOCK_ID_SPS_BY4                             = 0x22,
+       DBG_BLOCK_ID_SPS11_BY4                           = 0x23,
+       DBG_BLOCK_ID_TA_BY4                              = 0x24,
+       DBG_BLOCK_ID_TA04_BY4                            = 0x25,
+       DBG_BLOCK_ID_TA08_BY4                            = 0x26,
+       DBG_BLOCK_ID_UNUSED20_BY4                        = 0x27,
+       DBG_BLOCK_ID_TA10_BY4                            = 0x28,
+       DBG_BLOCK_ID_TA14_BY4                            = 0x29,
+       DBG_BLOCK_ID_TA18_BY4                            = 0x2a,
+       DBG_BLOCK_ID_UNUSED24_BY4                        = 0x2b,
+       DBG_BLOCK_ID_TD_BY4                              = 0x2c,
+       DBG_BLOCK_ID_TD04_BY4                            = 0x2d,
+       DBG_BLOCK_ID_TD08_BY4                            = 0x2e,
+       DBG_BLOCK_ID_UNUSED28_BY4                        = 0x2f,
+       DBG_BLOCK_ID_TD10_BY4                            = 0x30,
+       DBG_BLOCK_ID_TD14_BY4                            = 0x31,
+       DBG_BLOCK_ID_TD18_BY4                            = 0x32,
+       DBG_BLOCK_ID_UNUSED32_BY4                        = 0x33,
+       DBG_BLOCK_ID_LDS_BY4                             = 0x34,
+       DBG_BLOCK_ID_LDS04_BY4                           = 0x35,
+       DBG_BLOCK_ID_LDS08_BY4                           = 0x36,
+       DBG_BLOCK_ID_UNUSED36_BY4                        = 0x37,
+       DBG_BLOCK_ID_LDS10_BY4                           = 0x38,
+       DBG_BLOCK_ID_LDS14_BY4                           = 0x39,
+       DBG_BLOCK_ID_LDS18_BY4                           = 0x3a,
+       DBG_BLOCK_ID_UNUSED40_BY4                        = 0x3b,
+} DebugBlockId_BY4;
+typedef enum DebugBlockId_BY8 {
+       DBG_BLOCK_ID_RESERVED_BY8                        = 0x0,
+       DBG_BLOCK_ID_CSC_BY8                             = 0x1,
+       DBG_BLOCK_ID_SDMA0_BY8                           = 0x2,
+       DBG_BLOCK_ID_CP0_BY8                             = 0x3,
+       DBG_BLOCK_ID_SXM0_BY8                            = 0x4,
+       DBG_BLOCK_ID_TCA_BY8                             = 0x5,
+       DBG_BLOCK_ID_MCD_BY8                             = 0x6,
+       DBG_BLOCK_ID_SQA_BY8                             = 0x7,
+       DBG_BLOCK_ID_SQB_BY8                             = 0x8,
+       DBG_BLOCK_ID_CB_BY8                              = 0x9,
+       DBG_BLOCK_ID_SXS_BY8                             = 0xa,
+       DBG_BLOCK_ID_DB_BY8                              = 0xb,
+       DBG_BLOCK_ID_TCP_BY8                             = 0xc,
+       DBG_BLOCK_ID_TCP8_BY8                            = 0xd,
+       DBG_BLOCK_ID_TCP16_BY8                           = 0xe,
+       DBG_BLOCK_ID_TCP_RESERVED0_BY8                   = 0xf,
+       DBG_BLOCK_ID_TCC_BY8                             = 0x10,
+       DBG_BLOCK_ID_SPS_BY8                             = 0x11,
+       DBG_BLOCK_ID_TA_BY8                              = 0x12,
+       DBG_BLOCK_ID_TA08_BY8                            = 0x13,
+       DBG_BLOCK_ID_TA10_BY8                            = 0x14,
+       DBG_BLOCK_ID_TA18_BY8                            = 0x15,
+       DBG_BLOCK_ID_TD_BY8                              = 0x16,
+       DBG_BLOCK_ID_TD08_BY8                            = 0x17,
+       DBG_BLOCK_ID_TD10_BY8                            = 0x18,
+       DBG_BLOCK_ID_TD18_BY8                            = 0x19,
+       DBG_BLOCK_ID_LDS_BY8                             = 0x1a,
+       DBG_BLOCK_ID_LDS08_BY8                           = 0x1b,
+       DBG_BLOCK_ID_LDS10_BY8                           = 0x1c,
+       DBG_BLOCK_ID_LDS18_BY8                           = 0x1d,
+} DebugBlockId_BY8;
+typedef enum DebugBlockId_BY16 {
+       DBG_BLOCK_ID_RESERVED_BY16                       = 0x0,
+       DBG_BLOCK_ID_SDMA0_BY16                          = 0x1,
+       DBG_BLOCK_ID_SXM_BY16                            = 0x2,
+       DBG_BLOCK_ID_MCD_BY16                            = 0x3,
+       DBG_BLOCK_ID_SQB_BY16                            = 0x4,
+       DBG_BLOCK_ID_SXS_BY16                            = 0x5,
+       DBG_BLOCK_ID_TCP_BY16                            = 0x6,
+       DBG_BLOCK_ID_TCP16_BY16                          = 0x7,
+       DBG_BLOCK_ID_TCC_BY16                            = 0x8,
+       DBG_BLOCK_ID_TA_BY16                             = 0x9,
+       DBG_BLOCK_ID_TA10_BY16                           = 0xa,
+       DBG_BLOCK_ID_TD_BY16                             = 0xb,
+       DBG_BLOCK_ID_TD10_BY16                           = 0xc,
+       DBG_BLOCK_ID_LDS_BY16                            = 0xd,
+       DBG_BLOCK_ID_LDS10_BY16                          = 0xe,
+} DebugBlockId_BY16;
+typedef enum SurfaceEndian {
+       ENDIAN_NONE                                      = 0x0,
+       ENDIAN_8IN16                                     = 0x1,
+       ENDIAN_8IN32                                     = 0x2,
+       ENDIAN_8IN64                                     = 0x3,
+} SurfaceEndian;
+typedef enum ArrayMode {
+       ARRAY_LINEAR_GENERAL                             = 0x0,
+       ARRAY_LINEAR_ALIGNED                             = 0x1,
+       ARRAY_1D_TILED_THIN1                             = 0x2,
+       ARRAY_1D_TILED_THICK                             = 0x3,
+       ARRAY_2D_TILED_THIN1                             = 0x4,
+       ARRAY_PRT_TILED_THIN1                            = 0x5,
+       ARRAY_PRT_2D_TILED_THIN1                         = 0x6,
+       ARRAY_2D_TILED_THICK                             = 0x7,
+       ARRAY_2D_TILED_XTHICK                            = 0x8,
+       ARRAY_PRT_TILED_THICK                            = 0x9,
+       ARRAY_PRT_2D_TILED_THICK                         = 0xa,
+       ARRAY_PRT_3D_TILED_THIN1                         = 0xb,
+       ARRAY_3D_TILED_THIN1                             = 0xc,
+       ARRAY_3D_TILED_THICK                             = 0xd,
+       ARRAY_3D_TILED_XTHICK                            = 0xe,
+       ARRAY_PRT_3D_TILED_THICK                         = 0xf,
+} ArrayMode;
+typedef enum PipeTiling {
+       CONFIG_1_PIPE                                    = 0x0,
+       CONFIG_2_PIPE                                    = 0x1,
+       CONFIG_4_PIPE                                    = 0x2,
+       CONFIG_8_PIPE                                    = 0x3,
+} PipeTiling;
+typedef enum BankTiling {
+       CONFIG_4_BANK                                    = 0x0,
+       CONFIG_8_BANK                                    = 0x1,
+} BankTiling;
+typedef enum GroupInterleave {
+       CONFIG_256B_GROUP                                = 0x0,
+       CONFIG_512B_GROUP                                = 0x1,
+} GroupInterleave;
+typedef enum RowTiling {
+       CONFIG_1KB_ROW                                   = 0x0,
+       CONFIG_2KB_ROW                                   = 0x1,
+       CONFIG_4KB_ROW                                   = 0x2,
+       CONFIG_8KB_ROW                                   = 0x3,
+       CONFIG_1KB_ROW_OPT                               = 0x4,
+       CONFIG_2KB_ROW_OPT                               = 0x5,
+       CONFIG_4KB_ROW_OPT                               = 0x6,
+       CONFIG_8KB_ROW_OPT                               = 0x7,
+} RowTiling;
+typedef enum BankSwapBytes {
+       CONFIG_128B_SWAPS                                = 0x0,
+       CONFIG_256B_SWAPS                                = 0x1,
+       CONFIG_512B_SWAPS                                = 0x2,
+       CONFIG_1KB_SWAPS                                 = 0x3,
+} BankSwapBytes;
+typedef enum SampleSplitBytes {
+       CONFIG_1KB_SPLIT                                 = 0x0,
+       CONFIG_2KB_SPLIT                                 = 0x1,
+       CONFIG_4KB_SPLIT                                 = 0x2,
+       CONFIG_8KB_SPLIT                                 = 0x3,
+} SampleSplitBytes;
+typedef enum NumPipes {
+       ADDR_CONFIG_1_PIPE                               = 0x0,
+       ADDR_CONFIG_2_PIPE                               = 0x1,
+       ADDR_CONFIG_4_PIPE                               = 0x2,
+       ADDR_CONFIG_8_PIPE                               = 0x3,
+} NumPipes;
+typedef enum PipeInterleaveSize {
+       ADDR_CONFIG_PIPE_INTERLEAVE_256B                 = 0x0,
+       ADDR_CONFIG_PIPE_INTERLEAVE_512B                 = 0x1,
+} PipeInterleaveSize;
+typedef enum BankInterleaveSize {
+       ADDR_CONFIG_BANK_INTERLEAVE_1                    = 0x0,
+       ADDR_CONFIG_BANK_INTERLEAVE_2                    = 0x1,
+       ADDR_CONFIG_BANK_INTERLEAVE_4                    = 0x2,
+       ADDR_CONFIG_BANK_INTERLEAVE_8                    = 0x3,
+} BankInterleaveSize;
+typedef enum NumShaderEngines {
+       ADDR_CONFIG_1_SHADER_ENGINE                      = 0x0,
+       ADDR_CONFIG_2_SHADER_ENGINE                      = 0x1,
+} NumShaderEngines;
+typedef enum ShaderEngineTileSize {
+       ADDR_CONFIG_SE_TILE_16                           = 0x0,
+       ADDR_CONFIG_SE_TILE_32                           = 0x1,
+} ShaderEngineTileSize;
+typedef enum NumGPUs {
+       ADDR_CONFIG_1_GPU                                = 0x0,
+       ADDR_CONFIG_2_GPU                                = 0x1,
+       ADDR_CONFIG_4_GPU                                = 0x2,
+} NumGPUs;
+typedef enum MultiGPUTileSize {
+       ADDR_CONFIG_GPU_TILE_16                          = 0x0,
+       ADDR_CONFIG_GPU_TILE_32                          = 0x1,
+       ADDR_CONFIG_GPU_TILE_64                          = 0x2,
+       ADDR_CONFIG_GPU_TILE_128                         = 0x3,
+} MultiGPUTileSize;
+typedef enum RowSize {
+       ADDR_CONFIG_1KB_ROW                              = 0x0,
+       ADDR_CONFIG_2KB_ROW                              = 0x1,
+       ADDR_CONFIG_4KB_ROW                              = 0x2,
+} RowSize;
+typedef enum NumLowerPipes {
+       ADDR_CONFIG_1_LOWER_PIPES                        = 0x0,
+       ADDR_CONFIG_2_LOWER_PIPES                        = 0x1,
+} NumLowerPipes;
+typedef enum ColorTransform {
+       DCC_CT_AUTO                                      = 0x0,
+       DCC_CT_NONE                                      = 0x1,
+       ABGR_TO_A_BG_G_RB                                = 0x2,
+       BGRA_TO_BG_G_RB_A                                = 0x3,
+} ColorTransform;
+typedef enum CompareRef {
+       REF_NEVER                                        = 0x0,
+       REF_LESS                                         = 0x1,
+       REF_EQUAL                                        = 0x2,
+       REF_LEQUAL                                       = 0x3,
+       REF_GREATER                                      = 0x4,
+       REF_NOTEQUAL                                     = 0x5,
+       REF_GEQUAL                                       = 0x6,
+       REF_ALWAYS                                       = 0x7,
+} CompareRef;
+typedef enum ReadSize {
+       READ_256_BITS                                    = 0x0,
+       READ_512_BITS                                    = 0x1,
+} ReadSize;
+typedef enum DepthFormat {
+       DEPTH_INVALID                                    = 0x0,
+       DEPTH_16                                         = 0x1,
+       DEPTH_X8_24                                      = 0x2,
+       DEPTH_8_24                                       = 0x3,
+       DEPTH_X8_24_FLOAT                                = 0x4,
+       DEPTH_8_24_FLOAT                                 = 0x5,
+       DEPTH_32_FLOAT                                   = 0x6,
+       DEPTH_X24_8_32_FLOAT                             = 0x7,
+} DepthFormat;
+typedef enum ZFormat {
+       Z_INVALID                                        = 0x0,
+       Z_16                                             = 0x1,
+       Z_24                                             = 0x2,
+       Z_32_FLOAT                                       = 0x3,
+} ZFormat;
+typedef enum StencilFormat {
+       STENCIL_INVALID                                  = 0x0,
+       STENCIL_8                                        = 0x1,
+} StencilFormat;
+typedef enum CmaskMode {
+       CMASK_CLEAR_NONE                                 = 0x0,
+       CMASK_CLEAR_ONE                                  = 0x1,
+       CMASK_CLEAR_ALL                                  = 0x2,
+       CMASK_ANY_EXPANDED                               = 0x3,
+       CMASK_ALPHA0_FRAG1                               = 0x4,
+       CMASK_ALPHA0_FRAG2                               = 0x5,
+       CMASK_ALPHA0_FRAG4                               = 0x6,
+       CMASK_ALPHA0_FRAGS                               = 0x7,
+       CMASK_ALPHA1_FRAG1                               = 0x8,
+       CMASK_ALPHA1_FRAG2                               = 0x9,
+       CMASK_ALPHA1_FRAG4                               = 0xa,
+       CMASK_ALPHA1_FRAGS                               = 0xb,
+       CMASK_ALPHAX_FRAG1                               = 0xc,
+       CMASK_ALPHAX_FRAG2                               = 0xd,
+       CMASK_ALPHAX_FRAG4                               = 0xe,
+       CMASK_ALPHAX_FRAGS                               = 0xf,
+} CmaskMode;
+typedef enum QuadExportFormat {
+       EXPORT_UNUSED                                    = 0x0,
+       EXPORT_32_R                                      = 0x1,
+       EXPORT_32_GR                                     = 0x2,
+       EXPORT_32_AR                                     = 0x3,
+       EXPORT_FP16_ABGR                                 = 0x4,
+       EXPORT_UNSIGNED16_ABGR                           = 0x5,
+       EXPORT_SIGNED16_ABGR                             = 0x6,
+       EXPORT_32_ABGR                                   = 0x7,
+} QuadExportFormat;
+typedef enum QuadExportFormatOld {
+       EXPORT_4P_32BPC_ABGR                             = 0x0,
+       EXPORT_4P_16BPC_ABGR                             = 0x1,
+       EXPORT_4P_32BPC_GR                               = 0x2,
+       EXPORT_4P_32BPC_AR                               = 0x3,
+       EXPORT_2P_32BPC_ABGR                             = 0x4,
+       EXPORT_8P_32BPC_R                                = 0x5,
+} QuadExportFormatOld;
+typedef enum ColorFormat {
+       COLOR_INVALID                                    = 0x0,
+       COLOR_8                                          = 0x1,
+       COLOR_16                                         = 0x2,
+       COLOR_8_8                                        = 0x3,
+       COLOR_32                                         = 0x4,
+       COLOR_16_16                                      = 0x5,
+       COLOR_10_11_11                                   = 0x6,
+       COLOR_11_11_10                                   = 0x7,
+       COLOR_10_10_10_2                                 = 0x8,
+       COLOR_2_10_10_10                                 = 0x9,
+       COLOR_8_8_8_8                                    = 0xa,
+       COLOR_32_32                                      = 0xb,
+       COLOR_16_16_16_16                                = 0xc,
+       COLOR_RESERVED_13                                = 0xd,
+       COLOR_32_32_32_32                                = 0xe,
+       COLOR_RESERVED_15                                = 0xf,
+       COLOR_5_6_5                                      = 0x10,
+       COLOR_1_5_5_5                                    = 0x11,
+       COLOR_5_5_5_1                                    = 0x12,
+       COLOR_4_4_4_4                                    = 0x13,
+       COLOR_8_24                                       = 0x14,
+       COLOR_24_8                                       = 0x15,
+       COLOR_X24_8_32_FLOAT                             = 0x16,
+       COLOR_RESERVED_23                                = 0x17,
+} ColorFormat;
+typedef enum SurfaceFormat {
+       FMT_INVALID                                      = 0x0,
+       FMT_8                                            = 0x1,
+       FMT_16                                           = 0x2,
+       FMT_8_8                                          = 0x3,
+       FMT_32                                           = 0x4,
+       FMT_16_16                                        = 0x5,
+       FMT_10_11_11                                     = 0x6,
+       FMT_11_11_10                                     = 0x7,
+       FMT_10_10_10_2                                   = 0x8,
+       FMT_2_10_10_10                                   = 0x9,
+       FMT_8_8_8_8                                      = 0xa,
+       FMT_32_32                                        = 0xb,
+       FMT_16_16_16_16                                  = 0xc,
+       FMT_32_32_32                                     = 0xd,
+       FMT_32_32_32_32                                  = 0xe,
+       FMT_RESERVED_4                                   = 0xf,
+       FMT_5_6_5                                        = 0x10,
+       FMT_1_5_5_5                                      = 0x11,
+       FMT_5_5_5_1                                      = 0x12,
+       FMT_4_4_4_4                                      = 0x13,
+       FMT_8_24                                         = 0x14,
+       FMT_24_8                                         = 0x15,
+       FMT_X24_8_32_FLOAT                               = 0x16,
+       FMT_RESERVED_33                                  = 0x17,
+       FMT_11_11_10_FLOAT                               = 0x18,
+       FMT_16_FLOAT                                     = 0x19,
+       FMT_32_FLOAT                                     = 0x1a,
+       FMT_16_16_FLOAT                                  = 0x1b,
+       FMT_8_24_FLOAT                                   = 0x1c,
+       FMT_24_8_FLOAT                                   = 0x1d,
+       FMT_32_32_FLOAT                                  = 0x1e,
+       FMT_10_11_11_FLOAT                               = 0x1f,
+       FMT_16_16_16_16_FLOAT                            = 0x20,
+       FMT_3_3_2                                        = 0x21,
+       FMT_6_5_5                                        = 0x22,
+       FMT_32_32_32_32_FLOAT                            = 0x23,
+       FMT_RESERVED_36                                  = 0x24,
+       FMT_1                                            = 0x25,
+       FMT_1_REVERSED                                   = 0x26,
+       FMT_GB_GR                                        = 0x27,
+       FMT_BG_RG                                        = 0x28,
+       FMT_32_AS_8                                      = 0x29,
+       FMT_32_AS_8_8                                    = 0x2a,
+       FMT_5_9_9_9_SHAREDEXP                            = 0x2b,
+       FMT_8_8_8                                        = 0x2c,
+       FMT_16_16_16                                     = 0x2d,
+       FMT_16_16_16_FLOAT                               = 0x2e,
+       FMT_4_4                                          = 0x2f,
+       FMT_32_32_32_FLOAT                               = 0x30,
+       FMT_BC1                                          = 0x31,
+       FMT_BC2                                          = 0x32,
+       FMT_BC3                                          = 0x33,
+       FMT_BC4                                          = 0x34,
+       FMT_BC5                                          = 0x35,
+       FMT_BC6                                          = 0x36,
+       FMT_BC7                                          = 0x37,
+       FMT_32_AS_32_32_32_32                            = 0x38,
+       FMT_APC3                                         = 0x39,
+       FMT_APC4                                         = 0x3a,
+       FMT_APC5                                         = 0x3b,
+       FMT_APC6                                         = 0x3c,
+       FMT_APC7                                         = 0x3d,
+       FMT_CTX1                                         = 0x3e,
+       FMT_RESERVED_63                                  = 0x3f,
+} SurfaceFormat;
+typedef enum BUF_DATA_FORMAT {
+       BUF_DATA_FORMAT_INVALID                          = 0x0,
+       BUF_DATA_FORMAT_8                                = 0x1,
+       BUF_DATA_FORMAT_16                               = 0x2,
+       BUF_DATA_FORMAT_8_8                              = 0x3,
+       BUF_DATA_FORMAT_32                               = 0x4,
+       BUF_DATA_FORMAT_16_16                            = 0x5,
+       BUF_DATA_FORMAT_10_11_11                         = 0x6,
+       BUF_DATA_FORMAT_11_11_10                         = 0x7,
+       BUF_DATA_FORMAT_10_10_10_2                       = 0x8,
+       BUF_DATA_FORMAT_2_10_10_10                       = 0x9,
+       BUF_DATA_FORMAT_8_8_8_8                          = 0xa,
+       BUF_DATA_FORMAT_32_32                            = 0xb,
+       BUF_DATA_FORMAT_16_16_16_16                      = 0xc,
+       BUF_DATA_FORMAT_32_32_32                         = 0xd,
+       BUF_DATA_FORMAT_32_32_32_32                      = 0xe,
+       BUF_DATA_FORMAT_RESERVED_15                      = 0xf,
+} BUF_DATA_FORMAT;
+typedef enum IMG_DATA_FORMAT {
+       IMG_DATA_FORMAT_INVALID                          = 0x0,
+       IMG_DATA_FORMAT_8                                = 0x1,
+       IMG_DATA_FORMAT_16                               = 0x2,
+       IMG_DATA_FORMAT_8_8                              = 0x3,
+       IMG_DATA_FORMAT_32                               = 0x4,
+       IMG_DATA_FORMAT_16_16                            = 0x5,
+       IMG_DATA_FORMAT_10_11_11                         = 0x6,
+       IMG_DATA_FORMAT_11_11_10                         = 0x7,
+       IMG_DATA_FORMAT_10_10_10_2                       = 0x8,
+       IMG_DATA_FORMAT_2_10_10_10                       = 0x9,
+       IMG_DATA_FORMAT_8_8_8_8                          = 0xa,
+       IMG_DATA_FORMAT_32_32                            = 0xb,
+       IMG_DATA_FORMAT_16_16_16_16                      = 0xc,
+       IMG_DATA_FORMAT_32_32_32                         = 0xd,
+       IMG_DATA_FORMAT_32_32_32_32                      = 0xe,
+       IMG_DATA_FORMAT_RESERVED_15                      = 0xf,
+       IMG_DATA_FORMAT_5_6_5                            = 0x10,
+       IMG_DATA_FORMAT_1_5_5_5                          = 0x11,
+       IMG_DATA_FORMAT_5_5_5_1                          = 0x12,
+       IMG_DATA_FORMAT_4_4_4_4                          = 0x13,
+       IMG_DATA_FORMAT_8_24                             = 0x14,
+       IMG_DATA_FORMAT_24_8                             = 0x15,
+       IMG_DATA_FORMAT_X24_8_32                         = 0x16,
+       IMG_DATA_FORMAT_RESERVED_23                      = 0x17,
+       IMG_DATA_FORMAT_RESERVED_24                      = 0x18,
+       IMG_DATA_FORMAT_RESERVED_25                      = 0x19,
+       IMG_DATA_FORMAT_RESERVED_26                      = 0x1a,
+       IMG_DATA_FORMAT_RESERVED_27                      = 0x1b,
+       IMG_DATA_FORMAT_RESERVED_28                      = 0x1c,
+       IMG_DATA_FORMAT_RESERVED_29                      = 0x1d,
+       IMG_DATA_FORMAT_RESERVED_30                      = 0x1e,
+       IMG_DATA_FORMAT_RESERVED_31                      = 0x1f,
+       IMG_DATA_FORMAT_GB_GR                            = 0x20,
+       IMG_DATA_FORMAT_BG_RG                            = 0x21,
+       IMG_DATA_FORMAT_5_9_9_9                          = 0x22,
+       IMG_DATA_FORMAT_BC1                              = 0x23,
+       IMG_DATA_FORMAT_BC2                              = 0x24,
+       IMG_DATA_FORMAT_BC3                              = 0x25,
+       IMG_DATA_FORMAT_BC4                              = 0x26,
+       IMG_DATA_FORMAT_BC5                              = 0x27,
+       IMG_DATA_FORMAT_BC6                              = 0x28,
+       IMG_DATA_FORMAT_BC7                              = 0x29,
+       IMG_DATA_FORMAT_RESERVED_42                      = 0x2a,
+       IMG_DATA_FORMAT_RESERVED_43                      = 0x2b,
+       IMG_DATA_FORMAT_FMASK8_S2_F1                     = 0x2c,
+       IMG_DATA_FORMAT_FMASK8_S4_F1                     = 0x2d,
+       IMG_DATA_FORMAT_FMASK8_S8_F1                     = 0x2e,
+       IMG_DATA_FORMAT_FMASK8_S2_F2                     = 0x2f,
+       IMG_DATA_FORMAT_FMASK8_S4_F2                     = 0x30,
+       IMG_DATA_FORMAT_FMASK8_S4_F4                     = 0x31,
+       IMG_DATA_FORMAT_FMASK16_S16_F1                   = 0x32,
+       IMG_DATA_FORMAT_FMASK16_S8_F2                    = 0x33,
+       IMG_DATA_FORMAT_FMASK32_S16_F2                   = 0x34,
+       IMG_DATA_FORMAT_FMASK32_S8_F4                    = 0x35,
+       IMG_DATA_FORMAT_FMASK32_S8_F8                    = 0x36,
+       IMG_DATA_FORMAT_FMASK64_S16_F4                   = 0x37,
+       IMG_DATA_FORMAT_FMASK64_S16_F8                   = 0x38,
+       IMG_DATA_FORMAT_4_4                              = 0x39,
+       IMG_DATA_FORMAT_6_5_5                            = 0x3a,
+       IMG_DATA_FORMAT_1                                = 0x3b,
+       IMG_DATA_FORMAT_1_REVERSED                       = 0x3c,
+       IMG_DATA_FORMAT_32_AS_8                          = 0x3d,
+       IMG_DATA_FORMAT_32_AS_8_8                        = 0x3e,
+       IMG_DATA_FORMAT_32_AS_32_32_32_32                = 0x3f,
+} IMG_DATA_FORMAT;
+typedef enum BUF_NUM_FORMAT {
+       BUF_NUM_FORMAT_UNORM                             = 0x0,
+       BUF_NUM_FORMAT_SNORM                             = 0x1,
+       BUF_NUM_FORMAT_USCALED                           = 0x2,
+       BUF_NUM_FORMAT_SSCALED                           = 0x3,
+       BUF_NUM_FORMAT_UINT                              = 0x4,
+       BUF_NUM_FORMAT_SINT                              = 0x5,
+       BUF_NUM_FORMAT_RESERVED_6                        = 0x6,
+       BUF_NUM_FORMAT_FLOAT                             = 0x7,
+} BUF_NUM_FORMAT;
+typedef enum IMG_NUM_FORMAT {
+       IMG_NUM_FORMAT_UNORM                             = 0x0,
+       IMG_NUM_FORMAT_SNORM                             = 0x1,
+       IMG_NUM_FORMAT_USCALED                           = 0x2,
+       IMG_NUM_FORMAT_SSCALED                           = 0x3,
+       IMG_NUM_FORMAT_UINT                              = 0x4,
+       IMG_NUM_FORMAT_SINT                              = 0x5,
+       IMG_NUM_FORMAT_RESERVED_6                        = 0x6,
+       IMG_NUM_FORMAT_FLOAT                             = 0x7,
+       IMG_NUM_FORMAT_RESERVED_8                        = 0x8,
+       IMG_NUM_FORMAT_SRGB                              = 0x9,
+       IMG_NUM_FORMAT_RESERVED_10                       = 0xa,
+       IMG_NUM_FORMAT_RESERVED_11                       = 0xb,
+       IMG_NUM_FORMAT_RESERVED_12                       = 0xc,
+       IMG_NUM_FORMAT_RESERVED_13                       = 0xd,
+       IMG_NUM_FORMAT_RESERVED_14                       = 0xe,
+       IMG_NUM_FORMAT_RESERVED_15                       = 0xf,
+} IMG_NUM_FORMAT;
+typedef enum TileType {
+       ARRAY_COLOR_TILE                                 = 0x0,
+       ARRAY_DEPTH_TILE                                 = 0x1,
+} TileType;
+typedef enum NonDispTilingOrder {
+       ADDR_SURF_MICRO_TILING_DISPLAY                   = 0x0,
+       ADDR_SURF_MICRO_TILING_NON_DISPLAY               = 0x1,
+} NonDispTilingOrder;
+typedef enum MicroTileMode {
+       ADDR_SURF_DISPLAY_MICRO_TILING                   = 0x0,
+       ADDR_SURF_THIN_MICRO_TILING                      = 0x1,
+       ADDR_SURF_DEPTH_MICRO_TILING                     = 0x2,
+       ADDR_SURF_ROTATED_MICRO_TILING                   = 0x3,
+       ADDR_SURF_THICK_MICRO_TILING                     = 0x4,
+} MicroTileMode;
+typedef enum TileSplit {
+       ADDR_SURF_TILE_SPLIT_64B                         = 0x0,
+       ADDR_SURF_TILE_SPLIT_128B                        = 0x1,
+       ADDR_SURF_TILE_SPLIT_256B                        = 0x2,
+       ADDR_SURF_TILE_SPLIT_512B                        = 0x3,
+       ADDR_SURF_TILE_SPLIT_1KB                         = 0x4,
+       ADDR_SURF_TILE_SPLIT_2KB                         = 0x5,
+       ADDR_SURF_TILE_SPLIT_4KB                         = 0x6,
+} TileSplit;
+typedef enum SampleSplit {
+       ADDR_SURF_SAMPLE_SPLIT_1                         = 0x0,
+       ADDR_SURF_SAMPLE_SPLIT_2                         = 0x1,
+       ADDR_SURF_SAMPLE_SPLIT_4                         = 0x2,
+       ADDR_SURF_SAMPLE_SPLIT_8                         = 0x3,
+} SampleSplit;
+typedef enum PipeConfig {
+       ADDR_SURF_P2                                     = 0x0,
+       ADDR_SURF_P2_RESERVED0                           = 0x1,
+       ADDR_SURF_P2_RESERVED1                           = 0x2,
+       ADDR_SURF_P2_RESERVED2                           = 0x3,
+       ADDR_SURF_P4_8x16                                = 0x4,
+       ADDR_SURF_P4_16x16                               = 0x5,
+       ADDR_SURF_P4_16x32                               = 0x6,
+       ADDR_SURF_P4_32x32                               = 0x7,
+       ADDR_SURF_P8_16x16_8x16                          = 0x8,
+       ADDR_SURF_P8_16x32_8x16                          = 0x9,
+       ADDR_SURF_P8_32x32_8x16                          = 0xa,
+       ADDR_SURF_P8_16x32_16x16                         = 0xb,
+       ADDR_SURF_P8_32x32_16x16                         = 0xc,
+       ADDR_SURF_P8_32x32_16x32                         = 0xd,
+       ADDR_SURF_P8_32x64_32x32                         = 0xe,
+       ADDR_SURF_P8_RESERVED0                           = 0xf,
+       ADDR_SURF_P16_32x32_8x16                         = 0x10,
+       ADDR_SURF_P16_32x32_16x16                        = 0x11,
+} PipeConfig;
+typedef enum NumBanks {
+       ADDR_SURF_2_BANK                                 = 0x0,
+       ADDR_SURF_4_BANK                                 = 0x1,
+       ADDR_SURF_8_BANK                                 = 0x2,
+       ADDR_SURF_16_BANK                                = 0x3,
+} NumBanks;
+typedef enum BankWidth {
+       ADDR_SURF_BANK_WIDTH_1                           = 0x0,
+       ADDR_SURF_BANK_WIDTH_2                           = 0x1,
+       ADDR_SURF_BANK_WIDTH_4                           = 0x2,
+       ADDR_SURF_BANK_WIDTH_8                           = 0x3,
+} BankWidth;
+typedef enum BankHeight {
+       ADDR_SURF_BANK_HEIGHT_1                          = 0x0,
+       ADDR_SURF_BANK_HEIGHT_2                          = 0x1,
+       ADDR_SURF_BANK_HEIGHT_4                          = 0x2,
+       ADDR_SURF_BANK_HEIGHT_8                          = 0x3,
+} BankHeight;
+typedef enum BankWidthHeight {
+       ADDR_SURF_BANK_WH_1                              = 0x0,
+       ADDR_SURF_BANK_WH_2                              = 0x1,
+       ADDR_SURF_BANK_WH_4                              = 0x2,
+       ADDR_SURF_BANK_WH_8                              = 0x3,
+} BankWidthHeight;
+typedef enum MacroTileAspect {
+       ADDR_SURF_MACRO_ASPECT_1                         = 0x0,
+       ADDR_SURF_MACRO_ASPECT_2                         = 0x1,
+       ADDR_SURF_MACRO_ASPECT_4                         = 0x2,
+       ADDR_SURF_MACRO_ASPECT_8                         = 0x3,
+} MacroTileAspect;
+typedef enum GATCL1RequestType {
+       GATCL1_TYPE_NORMAL                               = 0x0,
+       GATCL1_TYPE_SHOOTDOWN                            = 0x1,
+       GATCL1_TYPE_BYPASS                               = 0x2,
+} GATCL1RequestType;
+typedef enum TCC_CACHE_POLICIES {
+       TCC_CACHE_POLICY_LRU                             = 0x0,
+       TCC_CACHE_POLICY_STREAM                          = 0x1,
+} TCC_CACHE_POLICIES;
+typedef enum MTYPE {
+       MTYPE_NC_NV                                      = 0x0,
+       MTYPE_NC                                         = 0x1,
+       MTYPE_CC                                         = 0x2,
+       MTYPE_UC                                         = 0x3,
+} MTYPE;
+typedef enum PERFMON_COUNTER_MODE {
+       PERFMON_COUNTER_MODE_ACCUM                       = 0x0,
+       PERFMON_COUNTER_MODE_ACTIVE_CYCLES               = 0x1,
+       PERFMON_COUNTER_MODE_MAX                         = 0x2,
+       PERFMON_COUNTER_MODE_DIRTY                       = 0x3,
+       PERFMON_COUNTER_MODE_SAMPLE                      = 0x4,
+       PERFMON_COUNTER_MODE_CYCLES_SINCE_FIRST_EVENT    = 0x5,
+       PERFMON_COUNTER_MODE_CYCLES_SINCE_LAST_EVENT     = 0x6,
+       PERFMON_COUNTER_MODE_CYCLES_GE_HI                = 0x7,
+       PERFMON_COUNTER_MODE_CYCLES_EQ_HI                = 0x8,
+       PERFMON_COUNTER_MODE_INACTIVE_CYCLES             = 0x9,
+       PERFMON_COUNTER_MODE_RESERVED                    = 0xf,
+} PERFMON_COUNTER_MODE;
+typedef enum PERFMON_SPM_MODE {
+       PERFMON_SPM_MODE_OFF                             = 0x0,
+       PERFMON_SPM_MODE_16BIT_CLAMP                     = 0x1,
+       PERFMON_SPM_MODE_16BIT_NO_CLAMP                  = 0x2,
+       PERFMON_SPM_MODE_32BIT_CLAMP                     = 0x3,
+       PERFMON_SPM_MODE_32BIT_NO_CLAMP                  = 0x4,
+       PERFMON_SPM_MODE_RESERVED_5                      = 0x5,
+       PERFMON_SPM_MODE_RESERVED_6                      = 0x6,
+       PERFMON_SPM_MODE_RESERVED_7                      = 0x7,
+       PERFMON_SPM_MODE_TEST_MODE_0                     = 0x8,
+       PERFMON_SPM_MODE_TEST_MODE_1                     = 0x9,
+       PERFMON_SPM_MODE_TEST_MODE_2                     = 0xa,
+} PERFMON_SPM_MODE;
+typedef enum SurfaceTiling {
+       ARRAY_LINEAR                                     = 0x0,
+       ARRAY_TILED                                      = 0x1,
+} SurfaceTiling;
+typedef enum SurfaceArray {
+       ARRAY_1D                                         = 0x0,
+       ARRAY_2D                                         = 0x1,
+       ARRAY_3D                                         = 0x2,
+       ARRAY_3D_SLICE                                   = 0x3,
+} SurfaceArray;
+typedef enum ColorArray {
+       ARRAY_2D_ALT_COLOR                               = 0x0,
+       ARRAY_2D_COLOR                                   = 0x1,
+       ARRAY_3D_SLICE_COLOR                             = 0x3,
+} ColorArray;
+typedef enum DepthArray {
+       ARRAY_2D_ALT_DEPTH                               = 0x0,
+       ARRAY_2D_DEPTH                                   = 0x1,
+} DepthArray;
+typedef enum ENUM_NUM_SIMD_PER_CU {
+       NUM_SIMD_PER_CU                                  = 0x4,
+} ENUM_NUM_SIMD_PER_CU;
+typedef enum MEM_PWR_FORCE_CTRL {
+       NO_FORCE_REQUEST                                 = 0x0,
+       FORCE_LIGHT_SLEEP_REQUEST                        = 0x1,
+       FORCE_DEEP_SLEEP_REQUEST                         = 0x2,
+       FORCE_SHUT_DOWN_REQUEST                          = 0x3,
+} MEM_PWR_FORCE_CTRL;
+typedef enum MEM_PWR_FORCE_CTRL2 {
+       NO_FORCE_REQ                                     = 0x0,
+       FORCE_LIGHT_SLEEP_REQ                            = 0x1,
+} MEM_PWR_FORCE_CTRL2;
+typedef enum MEM_PWR_DIS_CTRL {
+       ENABLE_MEM_PWR_CTRL                              = 0x0,
+       DISABLE_MEM_PWR_CTRL                             = 0x1,
+} MEM_PWR_DIS_CTRL;
+typedef enum MEM_PWR_SEL_CTRL {
+       DYNAMIC_SHUT_DOWN_ENABLE                         = 0x0,
+       DYNAMIC_DEEP_SLEEP_ENABLE                        = 0x1,
+       DYNAMIC_LIGHT_SLEEP_ENABLE                       = 0x2,
+} MEM_PWR_SEL_CTRL;
+typedef enum MEM_PWR_SEL_CTRL2 {
+       DYNAMIC_DEEP_SLEEP_EN                            = 0x0,
+       DYNAMIC_LIGHT_SLEEP_EN                           = 0x1,
+} MEM_PWR_SEL_CTRL2;
+
+#endif /* ACP_2_2_ENUM_H */
diff --git a/sound/soc/amd/include/acp_2_2_sh_mask.h b/sound/soc/amd/include/acp_2_2_sh_mask.h
new file mode 100644 (file)
index 0000000..32d2d41
--- /dev/null
@@ -0,0 +1,2292 @@
+/*
+ * ACP_2_2 Register documentation
+ *
+ * Copyright (C) 2014  Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#ifndef ACP_2_2_SH_MASK_H
+#define ACP_2_2_SH_MASK_H
+
+#define ACP_DMA_CNTL_0__DMAChRst_MASK 0x1
+#define ACP_DMA_CNTL_0__DMAChRst__SHIFT 0x0
+#define ACP_DMA_CNTL_0__DMAChRun_MASK 0x2
+#define ACP_DMA_CNTL_0__DMAChRun__SHIFT 0x1
+#define ACP_DMA_CNTL_0__DMAChIOCEn_MASK 0x4
+#define ACP_DMA_CNTL_0__DMAChIOCEn__SHIFT 0x2
+#define ACP_DMA_CNTL_0__Circular_DMA_En_MASK 0x8
+#define ACP_DMA_CNTL_0__Circular_DMA_En__SHIFT 0x3
+#define ACP_DMA_CNTL_0__DMAChGracefulRstEn_MASK 0x10
+#define ACP_DMA_CNTL_0__DMAChGracefulRstEn__SHIFT 0x4
+#define ACP_DMA_CNTL_1__DMAChRst_MASK 0x1
+#define ACP_DMA_CNTL_1__DMAChRst__SHIFT 0x0
+#define ACP_DMA_CNTL_1__DMAChRun_MASK 0x2
+#define ACP_DMA_CNTL_1__DMAChRun__SHIFT 0x1
+#define ACP_DMA_CNTL_1__DMAChIOCEn_MASK 0x4
+#define ACP_DMA_CNTL_1__DMAChIOCEn__SHIFT 0x2
+#define ACP_DMA_CNTL_1__Circular_DMA_En_MASK 0x8
+#define ACP_DMA_CNTL_1__Circular_DMA_En__SHIFT 0x3
+#define ACP_DMA_CNTL_1__DMAChGracefulRstEn_MASK 0x10
+#define ACP_DMA_CNTL_1__DMAChGracefulRstEn__SHIFT 0x4
+#define ACP_DMA_CNTL_2__DMAChRst_MASK 0x1
+#define ACP_DMA_CNTL_2__DMAChRst__SHIFT 0x0
+#define ACP_DMA_CNTL_2__DMAChRun_MASK 0x2
+#define ACP_DMA_CNTL_2__DMAChRun__SHIFT 0x1
+#define ACP_DMA_CNTL_2__DMAChIOCEn_MASK 0x4
+#define ACP_DMA_CNTL_2__DMAChIOCEn__SHIFT 0x2
+#define ACP_DMA_CNTL_2__Circular_DMA_En_MASK 0x8
+#define ACP_DMA_CNTL_2__Circular_DMA_En__SHIFT 0x3
+#define ACP_DMA_CNTL_2__DMAChGracefulRstEn_MASK 0x10
+#define ACP_DMA_CNTL_2__DMAChGracefulRstEn__SHIFT 0x4
+#define ACP_DMA_CNTL_3__DMAChRst_MASK 0x1
+#define ACP_DMA_CNTL_3__DMAChRst__SHIFT 0x0
+#define ACP_DMA_CNTL_3__DMAChRun_MASK 0x2
+#define ACP_DMA_CNTL_3__DMAChRun__SHIFT 0x1
+#define ACP_DMA_CNTL_3__DMAChIOCEn_MASK 0x4
+#define ACP_DMA_CNTL_3__DMAChIOCEn__SHIFT 0x2
+#define ACP_DMA_CNTL_3__Circular_DMA_En_MASK 0x8
+#define ACP_DMA_CNTL_3__Circular_DMA_En__SHIFT 0x3
+#define ACP_DMA_CNTL_3__DMAChGracefulRstEn_MASK 0x10
+#define ACP_DMA_CNTL_3__DMAChGracefulRstEn__SHIFT 0x4
+#define ACP_DMA_CNTL_4__DMAChRst_MASK 0x1
+#define ACP_DMA_CNTL_4__DMAChRst__SHIFT 0x0
+#define ACP_DMA_CNTL_4__DMAChRun_MASK 0x2
+#define ACP_DMA_CNTL_4__DMAChRun__SHIFT 0x1
+#define ACP_DMA_CNTL_4__DMAChIOCEn_MASK 0x4
+#define ACP_DMA_CNTL_4__DMAChIOCEn__SHIFT 0x2
+#define ACP_DMA_CNTL_4__Circular_DMA_En_MASK 0x8
+#define ACP_DMA_CNTL_4__Circular_DMA_En__SHIFT 0x3
+#define ACP_DMA_CNTL_4__DMAChGracefulRstEn_MASK 0x10
+#define ACP_DMA_CNTL_4__DMAChGracefulRstEn__SHIFT 0x4
+#define ACP_DMA_CNTL_5__DMAChRst_MASK 0x1
+#define ACP_DMA_CNTL_5__DMAChRst__SHIFT 0x0
+#define ACP_DMA_CNTL_5__DMAChRun_MASK 0x2
+#define ACP_DMA_CNTL_5__DMAChRun__SHIFT 0x1
+#define ACP_DMA_CNTL_5__DMAChIOCEn_MASK 0x4
+#define ACP_DMA_CNTL_5__DMAChIOCEn__SHIFT 0x2
+#define ACP_DMA_CNTL_5__Circular_DMA_En_MASK 0x8
+#define ACP_DMA_CNTL_5__Circular_DMA_En__SHIFT 0x3
+#define ACP_DMA_CNTL_5__DMAChGracefulRstEn_MASK 0x10
+#define ACP_DMA_CNTL_5__DMAChGracefulRstEn__SHIFT 0x4
+#define ACP_DMA_CNTL_6__DMAChRst_MASK 0x1
+#define ACP_DMA_CNTL_6__DMAChRst__SHIFT 0x0
+#define ACP_DMA_CNTL_6__DMAChRun_MASK 0x2
+#define ACP_DMA_CNTL_6__DMAChRun__SHIFT 0x1
+#define ACP_DMA_CNTL_6__DMAChIOCEn_MASK 0x4
+#define ACP_DMA_CNTL_6__DMAChIOCEn__SHIFT 0x2
+#define ACP_DMA_CNTL_6__Circular_DMA_En_MASK 0x8
+#define ACP_DMA_CNTL_6__Circular_DMA_En__SHIFT 0x3
+#define ACP_DMA_CNTL_6__DMAChGracefulRstEn_MASK 0x10
+#define ACP_DMA_CNTL_6__DMAChGracefulRstEn__SHIFT 0x4
+#define ACP_DMA_CNTL_7__DMAChRst_MASK 0x1
+#define ACP_DMA_CNTL_7__DMAChRst__SHIFT 0x0
+#define ACP_DMA_CNTL_7__DMAChRun_MASK 0x2
+#define ACP_DMA_CNTL_7__DMAChRun__SHIFT 0x1
+#define ACP_DMA_CNTL_7__DMAChIOCEn_MASK 0x4
+#define ACP_DMA_CNTL_7__DMAChIOCEn__SHIFT 0x2
+#define ACP_DMA_CNTL_7__Circular_DMA_En_MASK 0x8
+#define ACP_DMA_CNTL_7__Circular_DMA_En__SHIFT 0x3
+#define ACP_DMA_CNTL_7__DMAChGracefulRstEn_MASK 0x10
+#define ACP_DMA_CNTL_7__DMAChGracefulRstEn__SHIFT 0x4
+#define ACP_DMA_CNTL_8__DMAChRst_MASK 0x1
+#define ACP_DMA_CNTL_8__DMAChRst__SHIFT 0x0
+#define ACP_DMA_CNTL_8__DMAChRun_MASK 0x2
+#define ACP_DMA_CNTL_8__DMAChRun__SHIFT 0x1
+#define ACP_DMA_CNTL_8__DMAChIOCEn_MASK 0x4
+#define ACP_DMA_CNTL_8__DMAChIOCEn__SHIFT 0x2
+#define ACP_DMA_CNTL_8__Circular_DMA_En_MASK 0x8
+#define ACP_DMA_CNTL_8__Circular_DMA_En__SHIFT 0x3
+#define ACP_DMA_CNTL_8__DMAChGracefulRstEn_MASK 0x10
+#define ACP_DMA_CNTL_8__DMAChGracefulRstEn__SHIFT 0x4
+#define ACP_DMA_CNTL_9__DMAChRst_MASK 0x1
+#define ACP_DMA_CNTL_9__DMAChRst__SHIFT 0x0
+#define ACP_DMA_CNTL_9__DMAChRun_MASK 0x2
+#define ACP_DMA_CNTL_9__DMAChRun__SHIFT 0x1
+#define ACP_DMA_CNTL_9__DMAChIOCEn_MASK 0x4
+#define ACP_DMA_CNTL_9__DMAChIOCEn__SHIFT 0x2
+#define ACP_DMA_CNTL_9__Circular_DMA_En_MASK 0x8
+#define ACP_DMA_CNTL_9__Circular_DMA_En__SHIFT 0x3
+#define ACP_DMA_CNTL_9__DMAChGracefulRstEn_MASK 0x10
+#define ACP_DMA_CNTL_9__DMAChGracefulRstEn__SHIFT 0x4
+#define ACP_DMA_CNTL_10__DMAChRst_MASK 0x1
+#define ACP_DMA_CNTL_10__DMAChRst__SHIFT 0x0
+#define ACP_DMA_CNTL_10__DMAChRun_MASK 0x2
+#define ACP_DMA_CNTL_10__DMAChRun__SHIFT 0x1
+#define ACP_DMA_CNTL_10__DMAChIOCEn_MASK 0x4
+#define ACP_DMA_CNTL_10__DMAChIOCEn__SHIFT 0x2
+#define ACP_DMA_CNTL_10__Circular_DMA_En_MASK 0x8
+#define ACP_DMA_CNTL_10__Circular_DMA_En__SHIFT 0x3
+#define ACP_DMA_CNTL_10__DMAChGracefulRstEn_MASK 0x10
+#define ACP_DMA_CNTL_10__DMAChGracefulRstEn__SHIFT 0x4
+#define ACP_DMA_CNTL_11__DMAChRst_MASK 0x1
+#define ACP_DMA_CNTL_11__DMAChRst__SHIFT 0x0
+#define ACP_DMA_CNTL_11__DMAChRun_MASK 0x2
+#define ACP_DMA_CNTL_11__DMAChRun__SHIFT 0x1
+#define ACP_DMA_CNTL_11__DMAChIOCEn_MASK 0x4
+#define ACP_DMA_CNTL_11__DMAChIOCEn__SHIFT 0x2
+#define ACP_DMA_CNTL_11__Circular_DMA_En_MASK 0x8
+#define ACP_DMA_CNTL_11__Circular_DMA_En__SHIFT 0x3
+#define ACP_DMA_CNTL_11__DMAChGracefulRstEn_MASK 0x10
+#define ACP_DMA_CNTL_11__DMAChGracefulRstEn__SHIFT 0x4
+#define ACP_DMA_CNTL_12__DMAChRst_MASK 0x1
+#define ACP_DMA_CNTL_12__DMAChRst__SHIFT 0x0
+#define ACP_DMA_CNTL_12__DMAChRun_MASK 0x2
+#define ACP_DMA_CNTL_12__DMAChRun__SHIFT 0x1
+#define ACP_DMA_CNTL_12__DMAChIOCEn_MASK 0x4
+#define ACP_DMA_CNTL_12__DMAChIOCEn__SHIFT 0x2
+#define ACP_DMA_CNTL_12__Circular_DMA_En_MASK 0x8
+#define ACP_DMA_CNTL_12__Circular_DMA_En__SHIFT 0x3
+#define ACP_DMA_CNTL_12__DMAChGracefulRstEn_MASK 0x10
+#define ACP_DMA_CNTL_12__DMAChGracefulRstEn__SHIFT 0x4
+#define ACP_DMA_CNTL_13__DMAChRst_MASK 0x1
+#define ACP_DMA_CNTL_13__DMAChRst__SHIFT 0x0
+#define ACP_DMA_CNTL_13__DMAChRun_MASK 0x2
+#define ACP_DMA_CNTL_13__DMAChRun__SHIFT 0x1
+#define ACP_DMA_CNTL_13__DMAChIOCEn_MASK 0x4
+#define ACP_DMA_CNTL_13__DMAChIOCEn__SHIFT 0x2
+#define ACP_DMA_CNTL_13__Circular_DMA_En_MASK 0x8
+#define ACP_DMA_CNTL_13__Circular_DMA_En__SHIFT 0x3
+#define ACP_DMA_CNTL_13__DMAChGracefulRstEn_MASK 0x10
+#define ACP_DMA_CNTL_13__DMAChGracefulRstEn__SHIFT 0x4
+#define ACP_DMA_CNTL_14__DMAChRst_MASK 0x1
+#define ACP_DMA_CNTL_14__DMAChRst__SHIFT 0x0
+#define ACP_DMA_CNTL_14__DMAChRun_MASK 0x2
+#define ACP_DMA_CNTL_14__DMAChRun__SHIFT 0x1
+#define ACP_DMA_CNTL_14__DMAChIOCEn_MASK 0x4
+#define ACP_DMA_CNTL_14__DMAChIOCEn__SHIFT 0x2
+#define ACP_DMA_CNTL_14__Circular_DMA_En_MASK 0x8
+#define ACP_DMA_CNTL_14__Circular_DMA_En__SHIFT 0x3
+#define ACP_DMA_CNTL_14__DMAChGracefulRstEn_MASK 0x10
+#define ACP_DMA_CNTL_14__DMAChGracefulRstEn__SHIFT 0x4
+#define ACP_DMA_CNTL_15__DMAChRst_MASK 0x1
+#define ACP_DMA_CNTL_15__DMAChRst__SHIFT 0x0
+#define ACP_DMA_CNTL_15__DMAChRun_MASK 0x2
+#define ACP_DMA_CNTL_15__DMAChRun__SHIFT 0x1
+#define ACP_DMA_CNTL_15__DMAChIOCEn_MASK 0x4
+#define ACP_DMA_CNTL_15__DMAChIOCEn__SHIFT 0x2
+#define ACP_DMA_CNTL_15__Circular_DMA_En_MASK 0x8
+#define ACP_DMA_CNTL_15__Circular_DMA_En__SHIFT 0x3
+#define ACP_DMA_CNTL_15__DMAChGracefulRstEn_MASK 0x10
+#define ACP_DMA_CNTL_15__DMAChGracefulRstEn__SHIFT 0x4
+#define ACP_DMA_DSCR_STRT_IDX_0__DMAChDscrStrtIdx_MASK 0x3ff
+#define ACP_DMA_DSCR_STRT_IDX_0__DMAChDscrStrtIdx__SHIFT 0x0
+#define ACP_DMA_DSCR_STRT_IDX_1__DMAChDscrStrtIdx_MASK 0x3ff
+#define ACP_DMA_DSCR_STRT_IDX_1__DMAChDscrStrtIdx__SHIFT 0x0
+#define ACP_DMA_DSCR_STRT_IDX_2__DMAChDscrStrtIdx_MASK 0x3ff
+#define ACP_DMA_DSCR_STRT_IDX_2__DMAChDscrStrtIdx__SHIFT 0x0
+#define ACP_DMA_DSCR_STRT_IDX_3__DMAChDscrStrtIdx_MASK 0x3ff
+#define ACP_DMA_DSCR_STRT_IDX_3__DMAChDscrStrtIdx__SHIFT 0x0
+#define ACP_DMA_DSCR_STRT_IDX_4__DMAChDscrStrtIdx_MASK 0x3ff
+#define ACP_DMA_DSCR_STRT_IDX_4__DMAChDscrStrtIdx__SHIFT 0x0
+#define ACP_DMA_DSCR_STRT_IDX_5__DMAChDscrStrtIdx_MASK 0x3ff
+#define ACP_DMA_DSCR_STRT_IDX_5__DMAChDscrStrtIdx__SHIFT 0x0
+#define ACP_DMA_DSCR_STRT_IDX_6__DMAChDscrStrtIdx_MASK 0x3ff
+#define ACP_DMA_DSCR_STRT_IDX_6__DMAChDscrStrtIdx__SHIFT 0x0
+#define ACP_DMA_DSCR_STRT_IDX_7__DMAChDscrStrtIdx_MASK 0x3ff
+#define ACP_DMA_DSCR_STRT_IDX_7__DMAChDscrStrtIdx__SHIFT 0x0
+#define ACP_DMA_DSCR_STRT_IDX_8__DMAChDscrStrtIdx_MASK 0x3ff
+#define ACP_DMA_DSCR_STRT_IDX_8__DMAChDscrStrtIdx__SHIFT 0x0
+#define ACP_DMA_DSCR_STRT_IDX_9__DMAChDscrStrtIdx_MASK 0x3ff
+#define ACP_DMA_DSCR_STRT_IDX_9__DMAChDscrStrtIdx__SHIFT 0x0
+#define ACP_DMA_DSCR_STRT_IDX_10__DMAChDscrStrtIdx_MASK 0x3ff
+#define ACP_DMA_DSCR_STRT_IDX_10__DMAChDscrStrtIdx__SHIFT 0x0
+#define ACP_DMA_DSCR_STRT_IDX_11__DMAChDscrStrtIdx_MASK 0x3ff
+#define ACP_DMA_DSCR_STRT_IDX_11__DMAChDscrStrtIdx__SHIFT 0x0
+#define ACP_DMA_DSCR_STRT_IDX_12__DMAChDscrStrtIdx_MASK 0x3ff
+#define ACP_DMA_DSCR_STRT_IDX_12__DMAChDscrStrtIdx__SHIFT 0x0
+#define ACP_DMA_DSCR_STRT_IDX_13__DMAChDscrStrtIdx_MASK 0x3ff
+#define ACP_DMA_DSCR_STRT_IDX_13__DMAChDscrStrtIdx__SHIFT 0x0
+#define ACP_DMA_DSCR_STRT_IDX_14__DMAChDscrStrtIdx_MASK 0x3ff
+#define ACP_DMA_DSCR_STRT_IDX_14__DMAChDscrStrtIdx__SHIFT 0x0
+#define ACP_DMA_DSCR_STRT_IDX_15__DMAChDscrStrtIdx_MASK 0x3ff
+#define ACP_DMA_DSCR_STRT_IDX_15__DMAChDscrStrtIdx__SHIFT 0x0
+#define ACP_DMA_DSCR_CNT_0__DMAChDscrCnt_MASK 0x3ff
+#define ACP_DMA_DSCR_CNT_0__DMAChDscrCnt__SHIFT 0x0
+#define ACP_DMA_DSCR_CNT_1__DMAChDscrCnt_MASK 0x3ff
+#define ACP_DMA_DSCR_CNT_1__DMAChDscrCnt__SHIFT 0x0
+#define ACP_DMA_DSCR_CNT_2__DMAChDscrCnt_MASK 0x3ff
+#define ACP_DMA_DSCR_CNT_2__DMAChDscrCnt__SHIFT 0x0
+#define ACP_DMA_DSCR_CNT_3__DMAChDscrCnt_MASK 0x3ff
+#define ACP_DMA_DSCR_CNT_3__DMAChDscrCnt__SHIFT 0x0
+#define ACP_DMA_DSCR_CNT_4__DMAChDscrCnt_MASK 0x3ff
+#define ACP_DMA_DSCR_CNT_4__DMAChDscrCnt__SHIFT 0x0
+#define ACP_DMA_DSCR_CNT_5__DMAChDscrCnt_MASK 0x3ff
+#define ACP_DMA_DSCR_CNT_5__DMAChDscrCnt__SHIFT 0x0
+#define ACP_DMA_DSCR_CNT_6__DMAChDscrCnt_MASK 0x3ff
+#define ACP_DMA_DSCR_CNT_6__DMAChDscrCnt__SHIFT 0x0
+#define ACP_DMA_DSCR_CNT_7__DMAChDscrCnt_MASK 0x3ff
+#define ACP_DMA_DSCR_CNT_7__DMAChDscrCnt__SHIFT 0x0
+#define ACP_DMA_DSCR_CNT_8__DMAChDscrCnt_MASK 0x3ff
+#define ACP_DMA_DSCR_CNT_8__DMAChDscrCnt__SHIFT 0x0
+#define ACP_DMA_DSCR_CNT_9__DMAChDscrCnt_MASK 0x3ff
+#define ACP_DMA_DSCR_CNT_9__DMAChDscrCnt__SHIFT 0x0
+#define ACP_DMA_DSCR_CNT_10__DMAChDscrCnt_MASK 0x3ff
+#define ACP_DMA_DSCR_CNT_10__DMAChDscrCnt__SHIFT 0x0
+#define ACP_DMA_DSCR_CNT_11__DMAChDscrCnt_MASK 0x3ff
+#define ACP_DMA_DSCR_CNT_11__DMAChDscrCnt__SHIFT 0x0
+#define ACP_DMA_DSCR_CNT_12__DMAChDscrCnt_MASK 0x3ff
+#define ACP_DMA_DSCR_CNT_12__DMAChDscrCnt__SHIFT 0x0
+#define ACP_DMA_DSCR_CNT_13__DMAChDscrCnt_MASK 0x3ff
+#define ACP_DMA_DSCR_CNT_13__DMAChDscrCnt__SHIFT 0x0
+#define ACP_DMA_DSCR_CNT_14__DMAChDscrCnt_MASK 0x3ff
+#define ACP_DMA_DSCR_CNT_14__DMAChDscrCnt__SHIFT 0x0
+#define ACP_DMA_DSCR_CNT_15__DMAChDscrCnt_MASK 0x3ff
+#define ACP_DMA_DSCR_CNT_15__DMAChDscrCnt__SHIFT 0x0
+#define ACP_DMA_PRIO_0__DMAChPrioLvl_MASK 0x1
+#define ACP_DMA_PRIO_0__DMAChPrioLvl__SHIFT 0x0
+#define ACP_DMA_PRIO_1__DMAChPrioLvl_MASK 0x1
+#define ACP_DMA_PRIO_1__DMAChPrioLvl__SHIFT 0x0
+#define ACP_DMA_PRIO_2__DMAChPrioLvl_MASK 0x1
+#define ACP_DMA_PRIO_2__DMAChPrioLvl__SHIFT 0x0
+#define ACP_DMA_PRIO_3__DMAChPrioLvl_MASK 0x1
+#define ACP_DMA_PRIO_3__DMAChPrioLvl__SHIFT 0x0
+#define ACP_DMA_PRIO_4__DMAChPrioLvl_MASK 0x1
+#define ACP_DMA_PRIO_4__DMAChPrioLvl__SHIFT 0x0
+#define ACP_DMA_PRIO_5__DMAChPrioLvl_MASK 0x1
+#define ACP_DMA_PRIO_5__DMAChPrioLvl__SHIFT 0x0
+#define ACP_DMA_PRIO_6__DMAChPrioLvl_MASK 0x1
+#define ACP_DMA_PRIO_6__DMAChPrioLvl__SHIFT 0x0
+#define ACP_DMA_PRIO_7__DMAChPrioLvl_MASK 0x1
+#define ACP_DMA_PRIO_7__DMAChPrioLvl__SHIFT 0x0
+#define ACP_DMA_PRIO_8__DMAChPrioLvl_MASK 0x1
+#define ACP_DMA_PRIO_8__DMAChPrioLvl__SHIFT 0x0
+#define ACP_DMA_PRIO_9__DMAChPrioLvl_MASK 0x1
+#define ACP_DMA_PRIO_9__DMAChPrioLvl__SHIFT 0x0
+#define ACP_DMA_PRIO_10__DMAChPrioLvl_MASK 0x1
+#define ACP_DMA_PRIO_10__DMAChPrioLvl__SHIFT 0x0
+#define ACP_DMA_PRIO_11__DMAChPrioLvl_MASK 0x1
+#define ACP_DMA_PRIO_11__DMAChPrioLvl__SHIFT 0x0
+#define ACP_DMA_PRIO_12__DMAChPrioLvl_MASK 0x1
+#define ACP_DMA_PRIO_12__DMAChPrioLvl__SHIFT 0x0
+#define ACP_DMA_PRIO_13__DMAChPrioLvl_MASK 0x1
+#define ACP_DMA_PRIO_13__DMAChPrioLvl__SHIFT 0x0
+#define ACP_DMA_PRIO_14__DMAChPrioLvl_MASK 0x1
+#define ACP_DMA_PRIO_14__DMAChPrioLvl__SHIFT 0x0
+#define ACP_DMA_PRIO_15__DMAChPrioLvl_MASK 0x1
+#define ACP_DMA_PRIO_15__DMAChPrioLvl__SHIFT 0x0
+#define ACP_DMA_CUR_DSCR_0__DMAChCurDscrIdx_MASK 0x3ff
+#define ACP_DMA_CUR_DSCR_0__DMAChCurDscrIdx__SHIFT 0x0
+#define ACP_DMA_CUR_DSCR_1__DMAChCurDscrIdx_MASK 0x3ff
+#define ACP_DMA_CUR_DSCR_1__DMAChCurDscrIdx__SHIFT 0x0
+#define ACP_DMA_CUR_DSCR_2__DMAChCurDscrIdx_MASK 0x3ff
+#define ACP_DMA_CUR_DSCR_2__DMAChCurDscrIdx__SHIFT 0x0
+#define ACP_DMA_CUR_DSCR_3__DMAChCurDscrIdx_MASK 0x3ff
+#define ACP_DMA_CUR_DSCR_3__DMAChCurDscrIdx__SHIFT 0x0
+#define ACP_DMA_CUR_DSCR_4__DMAChCurDscrIdx_MASK 0x3ff
+#define ACP_DMA_CUR_DSCR_4__DMAChCurDscrIdx__SHIFT 0x0
+#define ACP_DMA_CUR_DSCR_5__DMAChCurDscrIdx_MASK 0x3ff
+#define ACP_DMA_CUR_DSCR_5__DMAChCurDscrIdx__SHIFT 0x0
+#define ACP_DMA_CUR_DSCR_6__DMAChCurDscrIdx_MASK 0x3ff
+#define ACP_DMA_CUR_DSCR_6__DMAChCurDscrIdx__SHIFT 0x0
+#define ACP_DMA_CUR_DSCR_7__DMAChCurDscrIdx_MASK 0x3ff
+#define ACP_DMA_CUR_DSCR_7__DMAChCurDscrIdx__SHIFT 0x0
+#define ACP_DMA_CUR_DSCR_8__DMAChCurDscrIdx_MASK 0x3ff
+#define ACP_DMA_CUR_DSCR_8__DMAChCurDscrIdx__SHIFT 0x0
+#define ACP_DMA_CUR_DSCR_9__DMAChCurDscrIdx_MASK 0x3ff
+#define ACP_DMA_CUR_DSCR_9__DMAChCurDscrIdx__SHIFT 0x0
+#define ACP_DMA_CUR_DSCR_10__DMAChCurDscrIdx_MASK 0x3ff
+#define ACP_DMA_CUR_DSCR_10__DMAChCurDscrIdx__SHIFT 0x0
+#define ACP_DMA_CUR_DSCR_11__DMAChCurDscrIdx_MASK 0x3ff
+#define ACP_DMA_CUR_DSCR_11__DMAChCurDscrIdx__SHIFT 0x0
+#define ACP_DMA_CUR_DSCR_12__DMAChCurDscrIdx_MASK 0x3ff
+#define ACP_DMA_CUR_DSCR_12__DMAChCurDscrIdx__SHIFT 0x0
+#define ACP_DMA_CUR_DSCR_13__DMAChCurDscrIdx_MASK 0x3ff
+#define ACP_DMA_CUR_DSCR_13__DMAChCurDscrIdx__SHIFT 0x0
+#define ACP_DMA_CUR_DSCR_14__DMAChCurDscrIdx_MASK 0x3ff
+#define ACP_DMA_CUR_DSCR_14__DMAChCurDscrIdx__SHIFT 0x0
+#define ACP_DMA_CUR_DSCR_15__DMAChCurDscrIdx_MASK 0x3ff
+#define ACP_DMA_CUR_DSCR_15__DMAChCurDscrIdx__SHIFT 0x0
+#define ACP_DMA_CUR_TRANS_CNT_0__DMAChCurTransCnt_MASK 0x1ffff
+#define ACP_DMA_CUR_TRANS_CNT_0__DMAChCurTransCnt__SHIFT 0x0
+#define ACP_DMA_CUR_TRANS_CNT_1__DMAChCurTransCnt_MASK 0x1ffff
+#define ACP_DMA_CUR_TRANS_CNT_1__DMAChCurTransCnt__SHIFT 0x0
+#define ACP_DMA_CUR_TRANS_CNT_2__DMAChCurTransCnt_MASK 0x1ffff
+#define ACP_DMA_CUR_TRANS_CNT_2__DMAChCurTransCnt__SHIFT 0x0
+#define ACP_DMA_CUR_TRANS_CNT_3__DMAChCurTransCnt_MASK 0x1ffff
+#define ACP_DMA_CUR_TRANS_CNT_3__DMAChCurTransCnt__SHIFT 0x0
+#define ACP_DMA_CUR_TRANS_CNT_4__DMAChCurTransCnt_MASK 0x1ffff
+#define ACP_DMA_CUR_TRANS_CNT_4__DMAChCurTransCnt__SHIFT 0x0
+#define ACP_DMA_CUR_TRANS_CNT_5__DMAChCurTransCnt_MASK 0x1ffff
+#define ACP_DMA_CUR_TRANS_CNT_5__DMAChCurTransCnt__SHIFT 0x0
+#define ACP_DMA_CUR_TRANS_CNT_6__DMAChCurTransCnt_MASK 0x1ffff
+#define ACP_DMA_CUR_TRANS_CNT_6__DMAChCurTransCnt__SHIFT 0x0
+#define ACP_DMA_CUR_TRANS_CNT_7__DMAChCurTransCnt_MASK 0x1ffff
+#define ACP_DMA_CUR_TRANS_CNT_7__DMAChCurTransCnt__SHIFT 0x0
+#define ACP_DMA_CUR_TRANS_CNT_8__DMAChCurTransCnt_MASK 0x1ffff
+#define ACP_DMA_CUR_TRANS_CNT_8__DMAChCurTransCnt__SHIFT 0x0
+#define ACP_DMA_CUR_TRANS_CNT_9__DMAChCurTransCnt_MASK 0x1ffff
+#define ACP_DMA_CUR_TRANS_CNT_9__DMAChCurTransCnt__SHIFT 0x0
+#define ACP_DMA_CUR_TRANS_CNT_10__DMAChCurTransCnt_MASK 0x1ffff
+#define ACP_DMA_CUR_TRANS_CNT_10__DMAChCurTransCnt__SHIFT 0x0
+#define ACP_DMA_CUR_TRANS_CNT_11__DMAChCurTransCnt_MASK 0x1ffff
+#define ACP_DMA_CUR_TRANS_CNT_11__DMAChCurTransCnt__SHIFT 0x0
+#define ACP_DMA_CUR_TRANS_CNT_12__DMAChCurTransCnt_MASK 0x1ffff
+#define ACP_DMA_CUR_TRANS_CNT_12__DMAChCurTransCnt__SHIFT 0x0
+#define ACP_DMA_CUR_TRANS_CNT_13__DMAChCurTransCnt_MASK 0x1ffff
+#define ACP_DMA_CUR_TRANS_CNT_13__DMAChCurTransCnt__SHIFT 0x0
+#define ACP_DMA_CUR_TRANS_CNT_14__DMAChCurTransCnt_MASK 0x1ffff
+#define ACP_DMA_CUR_TRANS_CNT_14__DMAChCurTransCnt__SHIFT 0x0
+#define ACP_DMA_CUR_TRANS_CNT_15__DMAChCurTransCnt_MASK 0x1ffff
+#define ACP_DMA_CUR_TRANS_CNT_15__DMAChCurTransCnt__SHIFT 0x0
+#define ACP_DMA_ERR_STS_0__DMAChTermErr_MASK 0x1
+#define ACP_DMA_ERR_STS_0__DMAChTermErr__SHIFT 0x0
+#define ACP_DMA_ERR_STS_0__DMAChErrCode_MASK 0x1e
+#define ACP_DMA_ERR_STS_0__DMAChErrCode__SHIFT 0x1
+#define ACP_DMA_ERR_STS_1__DMAChTermErr_MASK 0x1
+#define ACP_DMA_ERR_STS_1__DMAChTermErr__SHIFT 0x0
+#define ACP_DMA_ERR_STS_1__DMAChErrCode_MASK 0x1e
+#define ACP_DMA_ERR_STS_1__DMAChErrCode__SHIFT 0x1
+#define ACP_DMA_ERR_STS_2__DMAChTermErr_MASK 0x1
+#define ACP_DMA_ERR_STS_2__DMAChTermErr__SHIFT 0x0
+#define ACP_DMA_ERR_STS_2__DMAChErrCode_MASK 0x1e
+#define ACP_DMA_ERR_STS_2__DMAChErrCode__SHIFT 0x1
+#define ACP_DMA_ERR_STS_3__DMAChTermErr_MASK 0x1
+#define ACP_DMA_ERR_STS_3__DMAChTermErr__SHIFT 0x0
+#define ACP_DMA_ERR_STS_3__DMAChErrCode_MASK 0x1e
+#define ACP_DMA_ERR_STS_3__DMAChErrCode__SHIFT 0x1
+#define ACP_DMA_ERR_STS_4__DMAChTermErr_MASK 0x1
+#define ACP_DMA_ERR_STS_4__DMAChTermErr__SHIFT 0x0
+#define ACP_DMA_ERR_STS_4__DMAChErrCode_MASK 0x1e
+#define ACP_DMA_ERR_STS_4__DMAChErrCode__SHIFT 0x1
+#define ACP_DMA_ERR_STS_5__DMAChTermErr_MASK 0x1
+#define ACP_DMA_ERR_STS_5__DMAChTermErr__SHIFT 0x0
+#define ACP_DMA_ERR_STS_5__DMAChErrCode_MASK 0x1e
+#define ACP_DMA_ERR_STS_5__DMAChErrCode__SHIFT 0x1
+#define ACP_DMA_ERR_STS_6__DMAChTermErr_MASK 0x1
+#define ACP_DMA_ERR_STS_6__DMAChTermErr__SHIFT 0x0
+#define ACP_DMA_ERR_STS_6__DMAChErrCode_MASK 0x1e
+#define ACP_DMA_ERR_STS_6__DMAChErrCode__SHIFT 0x1
+#define ACP_DMA_ERR_STS_7__DMAChTermErr_MASK 0x1
+#define ACP_DMA_ERR_STS_7__DMAChTermErr__SHIFT 0x0
+#define ACP_DMA_ERR_STS_7__DMAChErrCode_MASK 0x1e
+#define ACP_DMA_ERR_STS_7__DMAChErrCode__SHIFT 0x1
+#define ACP_DMA_ERR_STS_8__DMAChTermErr_MASK 0x1
+#define ACP_DMA_ERR_STS_8__DMAChTermErr__SHIFT 0x0
+#define ACP_DMA_ERR_STS_8__DMAChErrCode_MASK 0x1e
+#define ACP_DMA_ERR_STS_8__DMAChErrCode__SHIFT 0x1
+#define ACP_DMA_ERR_STS_9__DMAChTermErr_MASK 0x1
+#define ACP_DMA_ERR_STS_9__DMAChTermErr__SHIFT 0x0
+#define ACP_DMA_ERR_STS_9__DMAChErrCode_MASK 0x1e
+#define ACP_DMA_ERR_STS_9__DMAChErrCode__SHIFT 0x1
+#define ACP_DMA_ERR_STS_10__DMAChTermErr_MASK 0x1
+#define ACP_DMA_ERR_STS_10__DMAChTermErr__SHIFT 0x0
+#define ACP_DMA_ERR_STS_10__DMAChErrCode_MASK 0x1e
+#define ACP_DMA_ERR_STS_10__DMAChErrCode__SHIFT 0x1
+#define ACP_DMA_ERR_STS_11__DMAChTermErr_MASK 0x1
+#define ACP_DMA_ERR_STS_11__DMAChTermErr__SHIFT 0x0
+#define ACP_DMA_ERR_STS_11__DMAChErrCode_MASK 0x1e
+#define ACP_DMA_ERR_STS_11__DMAChErrCode__SHIFT 0x1
+#define ACP_DMA_ERR_STS_12__DMAChTermErr_MASK 0x1
+#define ACP_DMA_ERR_STS_12__DMAChTermErr__SHIFT 0x0
+#define ACP_DMA_ERR_STS_12__DMAChErrCode_MASK 0x1e
+#define ACP_DMA_ERR_STS_12__DMAChErrCode__SHIFT 0x1
+#define ACP_DMA_ERR_STS_13__DMAChTermErr_MASK 0x1
+#define ACP_DMA_ERR_STS_13__DMAChTermErr__SHIFT 0x0
+#define ACP_DMA_ERR_STS_13__DMAChErrCode_MASK 0x1e
+#define ACP_DMA_ERR_STS_13__DMAChErrCode__SHIFT 0x1
+#define ACP_DMA_ERR_STS_14__DMAChTermErr_MASK 0x1
+#define ACP_DMA_ERR_STS_14__DMAChTermErr__SHIFT 0x0
+#define ACP_DMA_ERR_STS_14__DMAChErrCode_MASK 0x1e
+#define ACP_DMA_ERR_STS_14__DMAChErrCode__SHIFT 0x1
+#define ACP_DMA_ERR_STS_15__DMAChTermErr_MASK 0x1
+#define ACP_DMA_ERR_STS_15__DMAChTermErr__SHIFT 0x0
+#define ACP_DMA_ERR_STS_15__DMAChErrCode_MASK 0x1e
+#define ACP_DMA_ERR_STS_15__DMAChErrCode__SHIFT 0x1
+#define ACP_DMA_DESC_BASE_ADDR__DescriptorBaseAddr_MASK 0xffffffff
+#define ACP_DMA_DESC_BASE_ADDR__DescriptorBaseAddr__SHIFT 0x0
+#define ACP_DMA_DESC_MAX_NUM_DSCR__MaximumNumberDescr_MASK 0xf
+#define ACP_DMA_DESC_MAX_NUM_DSCR__MaximumNumberDescr__SHIFT 0x0
+#define ACP_DMA_CH_STS__DMAChSts_MASK 0xffff
+#define ACP_DMA_CH_STS__DMAChSts__SHIFT 0x0
+#define ACP_DMA_CH_GROUP__DMAChanelGrouping_MASK 0x1
+#define ACP_DMA_CH_GROUP__DMAChanelGrouping__SHIFT 0x0
+#define ACP_DSP0_CACHE_OFFSET0__Offset_MASK 0xfffffff
+#define ACP_DSP0_CACHE_OFFSET0__Offset__SHIFT 0x0
+#define ACP_DSP0_CACHE_OFFSET0__OnionGarlicSel_MASK 0x80000000
+#define ACP_DSP0_CACHE_OFFSET0__OnionGarlicSel__SHIFT 0x1f
+#define ACP_DSP0_CACHE_SIZE0__Size_MASK 0xffffff
+#define ACP_DSP0_CACHE_SIZE0__Size__SHIFT 0x0
+#define ACP_DSP0_CACHE_SIZE0__PageEnable_MASK 0x80000000
+#define ACP_DSP0_CACHE_SIZE0__PageEnable__SHIFT 0x1f
+#define ACP_DSP0_CACHE_OFFSET1__Offset_MASK 0xfffffff
+#define ACP_DSP0_CACHE_OFFSET1__Offset__SHIFT 0x0
+#define ACP_DSP0_CACHE_OFFSET1__OnionGarlicSel_MASK 0x80000000
+#define ACP_DSP0_CACHE_OFFSET1__OnionGarlicSel__SHIFT 0x1f
+#define ACP_DSP0_CACHE_SIZE1__Size_MASK 0xffffff
+#define ACP_DSP0_CACHE_SIZE1__Size__SHIFT 0x0
+#define ACP_DSP0_CACHE_SIZE1__PageEnable_MASK 0x80000000
+#define ACP_DSP0_CACHE_SIZE1__PageEnable__SHIFT 0x1f
+#define ACP_DSP0_CACHE_OFFSET2__Offset_MASK 0xfffffff
+#define ACP_DSP0_CACHE_OFFSET2__Offset__SHIFT 0x0
+#define ACP_DSP0_CACHE_OFFSET2__OnionGarlicSel_MASK 0x80000000
+#define ACP_DSP0_CACHE_OFFSET2__OnionGarlicSel__SHIFT 0x1f
+#define ACP_DSP0_CACHE_SIZE2__Size_MASK 0xffffff
+#define ACP_DSP0_CACHE_SIZE2__Size__SHIFT 0x0
+#define ACP_DSP0_CACHE_SIZE2__PageEnable_MASK 0x80000000
+#define ACP_DSP0_CACHE_SIZE2__PageEnable__SHIFT 0x1f
+#define ACP_DSP0_CACHE_OFFSET3__Offset_MASK 0xfffffff
+#define ACP_DSP0_CACHE_OFFSET3__Offset__SHIFT 0x0
+#define ACP_DSP0_CACHE_OFFSET3__OnionGarlicSel_MASK 0x80000000
+#define ACP_DSP0_CACHE_OFFSET3__OnionGarlicSel__SHIFT 0x1f
+#define ACP_DSP0_CACHE_SIZE3__Size_MASK 0xffffff
+#define ACP_DSP0_CACHE_SIZE3__Size__SHIFT 0x0
+#define ACP_DSP0_CACHE_SIZE3__PageEnable_MASK 0x80000000
+#define ACP_DSP0_CACHE_SIZE3__PageEnable__SHIFT 0x1f
+#define ACP_DSP0_CACHE_OFFSET4__Offset_MASK 0xfffffff
+#define ACP_DSP0_CACHE_OFFSET4__Offset__SHIFT 0x0
+#define ACP_DSP0_CACHE_OFFSET4__OnionGarlicSel_MASK 0x80000000
+#define ACP_DSP0_CACHE_OFFSET4__OnionGarlicSel__SHIFT 0x1f
+#define ACP_DSP0_CACHE_SIZE4__Size_MASK 0xffffff
+#define ACP_DSP0_CACHE_SIZE4__Size__SHIFT 0x0
+#define ACP_DSP0_CACHE_SIZE4__PageEnable_MASK 0x80000000
+#define ACP_DSP0_CACHE_SIZE4__PageEnable__SHIFT 0x1f
+#define ACP_DSP0_CACHE_OFFSET5__Offset_MASK 0xfffffff
+#define ACP_DSP0_CACHE_OFFSET5__Offset__SHIFT 0x0
+#define ACP_DSP0_CACHE_OFFSET5__OnionGarlicSel_MASK 0x80000000
+#define ACP_DSP0_CACHE_OFFSET5__OnionGarlicSel__SHIFT 0x1f
+#define ACP_DSP0_CACHE_SIZE5__Size_MASK 0xffffff
+#define ACP_DSP0_CACHE_SIZE5__Size__SHIFT 0x0
+#define ACP_DSP0_CACHE_SIZE5__PageEnable_MASK 0x80000000
+#define ACP_DSP0_CACHE_SIZE5__PageEnable__SHIFT 0x1f
+#define ACP_DSP0_CACHE_OFFSET6__Offset_MASK 0xfffffff
+#define ACP_DSP0_CACHE_OFFSET6__Offset__SHIFT 0x0
+#define ACP_DSP0_CACHE_OFFSET6__OnionGarlicSel_MASK 0x80000000
+#define ACP_DSP0_CACHE_OFFSET6__OnionGarlicSel__SHIFT 0x1f
+#define ACP_DSP0_CACHE_SIZE6__Size_MASK 0xffffff
+#define ACP_DSP0_CACHE_SIZE6__Size__SHIFT 0x0
+#define ACP_DSP0_CACHE_SIZE6__PageEnable_MASK 0x80000000
+#define ACP_DSP0_CACHE_SIZE6__PageEnable__SHIFT 0x1f
+#define ACP_DSP0_CACHE_OFFSET7__Offset_MASK 0xfffffff
+#define ACP_DSP0_CACHE_OFFSET7__Offset__SHIFT 0x0
+#define ACP_DSP0_CACHE_OFFSET7__OnionGarlicSel_MASK 0x80000000
+#define ACP_DSP0_CACHE_OFFSET7__OnionGarlicSel__SHIFT 0x1f
+#define ACP_DSP0_CACHE_SIZE7__Size_MASK 0xffffff
+#define ACP_DSP0_CACHE_SIZE7__Size__SHIFT 0x0
+#define ACP_DSP0_CACHE_SIZE7__PageEnable_MASK 0x80000000
+#define ACP_DSP0_CACHE_SIZE7__PageEnable__SHIFT 0x1f
+#define ACP_DSP0_CACHE_OFFSET8__Offset_MASK 0xfffffff
+#define ACP_DSP0_CACHE_OFFSET8__Offset__SHIFT 0x0
+#define ACP_DSP0_CACHE_OFFSET8__OnionGarlicSel_MASK 0x80000000
+#define ACP_DSP0_CACHE_OFFSET8__OnionGarlicSel__SHIFT 0x1f
+#define ACP_DSP0_CACHE_SIZE8__Size_MASK 0xffffff
+#define ACP_DSP0_CACHE_SIZE8__Size__SHIFT 0x0
+#define ACP_DSP0_CACHE_SIZE8__PageEnable_MASK 0x80000000
+#define ACP_DSP0_CACHE_SIZE8__PageEnable__SHIFT 0x1f
+#define ACP_DSP0_NONCACHE_OFFSET0__Offset_MASK 0xfffffff
+#define ACP_DSP0_NONCACHE_OFFSET0__Offset__SHIFT 0x0
+#define ACP_DSP0_NONCACHE_OFFSET0__OnionGarlicSel_MASK 0x80000000
+#define ACP_DSP0_NONCACHE_OFFSET0__OnionGarlicSel__SHIFT 0x1f
+#define ACP_DSP0_NONCACHE_SIZE0__Size_MASK 0xffffff
+#define ACP_DSP0_NONCACHE_SIZE0__Size__SHIFT 0x0
+#define ACP_DSP0_NONCACHE_SIZE0__PageEnable_MASK 0x80000000
+#define ACP_DSP0_NONCACHE_SIZE0__PageEnable__SHIFT 0x1f
+#define ACP_DSP0_NONCACHE_OFFSET1__Offset_MASK 0xfffffff
+#define ACP_DSP0_NONCACHE_OFFSET1__Offset__SHIFT 0x0
+#define ACP_DSP0_NONCACHE_OFFSET1__OnionGarlicSel_MASK 0x80000000
+#define ACP_DSP0_NONCACHE_OFFSET1__OnionGarlicSel__SHIFT 0x1f
+#define ACP_DSP0_NONCACHE_SIZE1__Size_MASK 0xffffff
+#define ACP_DSP0_NONCACHE_SIZE1__Size__SHIFT 0x0
+#define ACP_DSP0_NONCACHE_SIZE1__PageEnable_MASK 0x80000000
+#define ACP_DSP0_NONCACHE_SIZE1__PageEnable__SHIFT 0x1f
+#define ACP_DSP0_DEBUG_PC__DebugPC_MASK 0xffffffff
+#define ACP_DSP0_DEBUG_PC__DebugPC__SHIFT 0x0
+#define ACP_DSP0_NMI_SEL__NMISel_MASK 0x1
+#define ACP_DSP0_NMI_SEL__NMISel__SHIFT 0x0
+#define ACP_DSP0_CLKRST_CNTL__ClkEn_MASK 0x1
+#define ACP_DSP0_CLKRST_CNTL__ClkEn__SHIFT 0x0
+#define ACP_DSP0_CLKRST_CNTL__SoftResetDSP_MASK 0x2
+#define ACP_DSP0_CLKRST_CNTL__SoftResetDSP__SHIFT 0x1
+#define ACP_DSP0_CLKRST_CNTL__InternalSoftResetMode_MASK 0x4
+#define ACP_DSP0_CLKRST_CNTL__InternalSoftResetMode__SHIFT 0x2
+#define ACP_DSP0_CLKRST_CNTL__ExternalSoftResetMode_MASK 0x8
+#define ACP_DSP0_CLKRST_CNTL__ExternalSoftResetMode__SHIFT 0x3
+#define ACP_DSP0_CLKRST_CNTL__SoftResetDSPDone_MASK 0x10
+#define ACP_DSP0_CLKRST_CNTL__SoftResetDSPDone__SHIFT 0x4
+#define ACP_DSP0_CLKRST_CNTL__Clk_ON_Status_MASK 0x20
+#define ACP_DSP0_CLKRST_CNTL__Clk_ON_Status__SHIFT 0x5
+#define ACP_DSP0_RUNSTALL__RunStallCntl_MASK 0x1
+#define ACP_DSP0_RUNSTALL__RunStallCntl__SHIFT 0x0
+#define ACP_DSP0_OCD_HALT_ON_RST__OCD_HALT_ON_RST_MASK 0x1
+#define ACP_DSP0_OCD_HALT_ON_RST__OCD_HALT_ON_RST__SHIFT 0x0
+#define ACP_DSP0_WAIT_MODE__WaitMode_MASK 0x1
+#define ACP_DSP0_WAIT_MODE__WaitMode__SHIFT 0x0
+#define ACP_DSP0_VECT_SEL__StaticVectorSel_MASK 0x1
+#define ACP_DSP0_VECT_SEL__StaticVectorSel__SHIFT 0x0
+#define ACP_DSP0_DEBUG_REG1__ACP_DSP_DEBUG_REG1_MASK 0xffffffff
+#define ACP_DSP0_DEBUG_REG1__ACP_DSP_DEBUG_REG1__SHIFT 0x0
+#define ACP_DSP0_DEBUG_REG2__ACP_DSP_DEBUG_REG2_MASK 0xffffffff
+#define ACP_DSP0_DEBUG_REG2__ACP_DSP_DEBUG_REG2__SHIFT 0x0
+#define ACP_DSP0_DEBUG_REG3__ACP_DSP_DEBUG_REG3_MASK 0xffffffff
+#define ACP_DSP0_DEBUG_REG3__ACP_DSP_DEBUG_REG3__SHIFT 0x0
+#define ACP_DSP1_CACHE_OFFSET0__Offset_MASK 0xfffffff
+#define ACP_DSP1_CACHE_OFFSET0__Offset__SHIFT 0x0
+#define ACP_DSP1_CACHE_OFFSET0__OnionGarlicSel_MASK 0x80000000
+#define ACP_DSP1_CACHE_OFFSET0__OnionGarlicSel__SHIFT 0x1f
+#define ACP_DSP1_CACHE_SIZE0__Size_MASK 0xffffff
+#define ACP_DSP1_CACHE_SIZE0__Size__SHIFT 0x0
+#define ACP_DSP1_CACHE_SIZE0__PageEnable_MASK 0x80000000
+#define ACP_DSP1_CACHE_SIZE0__PageEnable__SHIFT 0x1f
+#define ACP_DSP1_CACHE_OFFSET1__Offset_MASK 0xfffffff
+#define ACP_DSP1_CACHE_OFFSET1__Offset__SHIFT 0x0
+#define ACP_DSP1_CACHE_OFFSET1__OnionGarlicSel_MASK 0x80000000
+#define ACP_DSP1_CACHE_OFFSET1__OnionGarlicSel__SHIFT 0x1f
+#define ACP_DSP1_CACHE_SIZE1__Size_MASK 0xffffff
+#define ACP_DSP1_CACHE_SIZE1__Size__SHIFT 0x0
+#define ACP_DSP1_CACHE_SIZE1__PageEnable_MASK 0x80000000
+#define ACP_DSP1_CACHE_SIZE1__PageEnable__SHIFT 0x1f
+#define ACP_DSP1_CACHE_OFFSET2__Offset_MASK 0xfffffff
+#define ACP_DSP1_CACHE_OFFSET2__Offset__SHIFT 0x0
+#define ACP_DSP1_CACHE_OFFSET2__OnionGarlicSel_MASK 0x80000000
+#define ACP_DSP1_CACHE_OFFSET2__OnionGarlicSel__SHIFT 0x1f
+#define ACP_DSP1_CACHE_SIZE2__Size_MASK 0xffffff
+#define ACP_DSP1_CACHE_SIZE2__Size__SHIFT 0x0
+#define ACP_DSP1_CACHE_SIZE2__PageEnable_MASK 0x80000000
+#define ACP_DSP1_CACHE_SIZE2__PageEnable__SHIFT 0x1f
+#define ACP_DSP1_CACHE_OFFSET3__Offset_MASK 0xfffffff
+#define ACP_DSP1_CACHE_OFFSET3__Offset__SHIFT 0x0
+#define ACP_DSP1_CACHE_OFFSET3__OnionGarlicSel_MASK 0x80000000
+#define ACP_DSP1_CACHE_OFFSET3__OnionGarlicSel__SHIFT 0x1f
+#define ACP_DSP1_CACHE_SIZE3__Size_MASK 0xffffff
+#define ACP_DSP1_CACHE_SIZE3__Size__SHIFT 0x0
+#define ACP_DSP1_CACHE_SIZE3__PageEnable_MASK 0x80000000
+#define ACP_DSP1_CACHE_SIZE3__PageEnable__SHIFT 0x1f
+#define ACP_DSP1_CACHE_OFFSET4__Offset_MASK 0xfffffff
+#define ACP_DSP1_CACHE_OFFSET4__Offset__SHIFT 0x0
+#define ACP_DSP1_CACHE_OFFSET4__OnionGarlicSel_MASK 0x80000000
+#define ACP_DSP1_CACHE_OFFSET4__OnionGarlicSel__SHIFT 0x1f
+#define ACP_DSP1_CACHE_SIZE4__Size_MASK 0xffffff
+#define ACP_DSP1_CACHE_SIZE4__Size__SHIFT 0x0
+#define ACP_DSP1_CACHE_SIZE4__PageEnable_MASK 0x80000000
+#define ACP_DSP1_CACHE_SIZE4__PageEnable__SHIFT 0x1f
+#define ACP_DSP1_CACHE_OFFSET5__Offset_MASK 0xfffffff
+#define ACP_DSP1_CACHE_OFFSET5__Offset__SHIFT 0x0
+#define ACP_DSP1_CACHE_OFFSET5__OnionGarlicSel_MASK 0x80000000
+#define ACP_DSP1_CACHE_OFFSET5__OnionGarlicSel__SHIFT 0x1f
+#define ACP_DSP1_CACHE_SIZE5__Size_MASK 0xffffff
+#define ACP_DSP1_CACHE_SIZE5__Size__SHIFT 0x0
+#define ACP_DSP1_CACHE_SIZE5__PageEnable_MASK 0x80000000
+#define ACP_DSP1_CACHE_SIZE5__PageEnable__SHIFT 0x1f
+#define ACP_DSP1_CACHE_OFFSET6__Offset_MASK 0xfffffff
+#define ACP_DSP1_CACHE_OFFSET6__Offset__SHIFT 0x0
+#define ACP_DSP1_CACHE_OFFSET6__OnionGarlicSel_MASK 0x80000000
+#define ACP_DSP1_CACHE_OFFSET6__OnionGarlicSel__SHIFT 0x1f
+#define ACP_DSP1_CACHE_SIZE6__Size_MASK 0xffffff
+#define ACP_DSP1_CACHE_SIZE6__Size__SHIFT 0x0
+#define ACP_DSP1_CACHE_SIZE6__PageEnable_MASK 0x80000000
+#define ACP_DSP1_CACHE_SIZE6__PageEnable__SHIFT 0x1f
+#define ACP_DSP1_CACHE_OFFSET7__Offset_MASK 0xfffffff
+#define ACP_DSP1_CACHE_OFFSET7__Offset__SHIFT 0x0
+#define ACP_DSP1_CACHE_OFFSET7__OnionGarlicSel_MASK 0x80000000
+#define ACP_DSP1_CACHE_OFFSET7__OnionGarlicSel__SHIFT 0x1f
+#define ACP_DSP1_CACHE_SIZE7__Size_MASK 0xffffff
+#define ACP_DSP1_CACHE_SIZE7__Size__SHIFT 0x0
+#define ACP_DSP1_CACHE_SIZE7__PageEnable_MASK 0x80000000
+#define ACP_DSP1_CACHE_SIZE7__PageEnable__SHIFT 0x1f
+#define ACP_DSP1_CACHE_OFFSET8__Offset_MASK 0xfffffff
+#define ACP_DSP1_CACHE_OFFSET8__Offset__SHIFT 0x0
+#define ACP_DSP1_CACHE_OFFSET8__OnionGarlicSel_MASK 0x80000000
+#define ACP_DSP1_CACHE_OFFSET8__OnionGarlicSel__SHIFT 0x1f
+#define ACP_DSP1_CACHE_SIZE8__Size_MASK 0xffffff
+#define ACP_DSP1_CACHE_SIZE8__Size__SHIFT 0x0
+#define ACP_DSP1_CACHE_SIZE8__PageEnable_MASK 0x80000000
+#define ACP_DSP1_CACHE_SIZE8__PageEnable__SHIFT 0x1f
+#define ACP_DSP1_NONCACHE_OFFSET0__Offset_MASK 0xfffffff
+#define ACP_DSP1_NONCACHE_OFFSET0__Offset__SHIFT 0x0
+#define ACP_DSP1_NONCACHE_OFFSET0__OnionGarlicSel_MASK 0x80000000
+#define ACP_DSP1_NONCACHE_OFFSET0__OnionGarlicSel__SHIFT 0x1f
+#define ACP_DSP1_NONCACHE_SIZE0__Size_MASK 0xffffff
+#define ACP_DSP1_NONCACHE_SIZE0__Size__SHIFT 0x0
+#define ACP_DSP1_NONCACHE_SIZE0__PageEnable_MASK 0x80000000
+#define ACP_DSP1_NONCACHE_SIZE0__PageEnable__SHIFT 0x1f
+#define ACP_DSP1_NONCACHE_OFFSET1__Offset_MASK 0xfffffff
+#define ACP_DSP1_NONCACHE_OFFSET1__Offset__SHIFT 0x0
+#define ACP_DSP1_NONCACHE_OFFSET1__OnionGarlicSel_MASK 0x80000000
+#define ACP_DSP1_NONCACHE_OFFSET1__OnionGarlicSel__SHIFT 0x1f
+#define ACP_DSP1_NONCACHE_SIZE1__Size_MASK 0xffffff
+#define ACP_DSP1_NONCACHE_SIZE1__Size__SHIFT 0x0
+#define ACP_DSP1_NONCACHE_SIZE1__PageEnable_MASK 0x80000000
+#define ACP_DSP1_NONCACHE_SIZE1__PageEnable__SHIFT 0x1f
+#define ACP_DSP1_DEBUG_PC__DebugPC_MASK 0xffffffff
+#define ACP_DSP1_DEBUG_PC__DebugPC__SHIFT 0x0
+#define ACP_DSP1_NMI_SEL__NMISel_MASK 0x1
+#define ACP_DSP1_NMI_SEL__NMISel__SHIFT 0x0
+#define ACP_DSP1_CLKRST_CNTL__ClkEn_MASK 0x1
+#define ACP_DSP1_CLKRST_CNTL__ClkEn__SHIFT 0x0
+#define ACP_DSP1_CLKRST_CNTL__SoftResetDSP_MASK 0x2
+#define ACP_DSP1_CLKRST_CNTL__SoftResetDSP__SHIFT 0x1
+#define ACP_DSP1_CLKRST_CNTL__InternalSoftResetMode_MASK 0x4
+#define ACP_DSP1_CLKRST_CNTL__InternalSoftResetMode__SHIFT 0x2
+#define ACP_DSP1_CLKRST_CNTL__ExternalSoftResetMode_MASK 0x8
+#define ACP_DSP1_CLKRST_CNTL__ExternalSoftResetMode__SHIFT 0x3
+#define ACP_DSP1_CLKRST_CNTL__SoftResetDSPDone_MASK 0x10
+#define ACP_DSP1_CLKRST_CNTL__SoftResetDSPDone__SHIFT 0x4
+#define ACP_DSP1_CLKRST_CNTL__Clk_ON_Status_MASK 0x20
+#define ACP_DSP1_CLKRST_CNTL__Clk_ON_Status__SHIFT 0x5
+#define ACP_DSP1_RUNSTALL__RunStallCntl_MASK 0x1
+#define ACP_DSP1_RUNSTALL__RunStallCntl__SHIFT 0x0
+#define ACP_DSP1_OCD_HALT_ON_RST__OCD_HALT_ON_RST_MASK 0x1
+#define ACP_DSP1_OCD_HALT_ON_RST__OCD_HALT_ON_RST__SHIFT 0x0
+#define ACP_DSP1_WAIT_MODE__WaitMode_MASK 0x1
+#define ACP_DSP1_WAIT_MODE__WaitMode__SHIFT 0x0
+#define ACP_DSP1_VECT_SEL__StaticVectorSel_MASK 0x1
+#define ACP_DSP1_VECT_SEL__StaticVectorSel__SHIFT 0x0
+#define ACP_DSP1_DEBUG_REG1__ACP_DSP_DEBUG_REG1_MASK 0xffffffff
+#define ACP_DSP1_DEBUG_REG1__ACP_DSP_DEBUG_REG1__SHIFT 0x0
+#define ACP_DSP1_DEBUG_REG2__ACP_DSP_DEBUG_REG2_MASK 0xffffffff
+#define ACP_DSP1_DEBUG_REG2__ACP_DSP_DEBUG_REG2__SHIFT 0x0
+#define ACP_DSP1_DEBUG_REG3__ACP_DSP_DEBUG_REG3_MASK 0xffffffff
+#define ACP_DSP1_DEBUG_REG3__ACP_DSP_DEBUG_REG3__SHIFT 0x0
+#define ACP_DSP2_CACHE_OFFSET0__Offset_MASK 0xfffffff
+#define ACP_DSP2_CACHE_OFFSET0__Offset__SHIFT 0x0
+#define ACP_DSP2_CACHE_OFFSET0__OnionGarlicSel_MASK 0x80000000
+#define ACP_DSP2_CACHE_OFFSET0__OnionGarlicSel__SHIFT 0x1f
+#define ACP_DSP2_CACHE_SIZE0__Size_MASK 0xffffff
+#define ACP_DSP2_CACHE_SIZE0__Size__SHIFT 0x0
+#define ACP_DSP2_CACHE_SIZE0__PageEnable_MASK 0x80000000
+#define ACP_DSP2_CACHE_SIZE0__PageEnable__SHIFT 0x1f
+#define ACP_DSP2_CACHE_OFFSET1__Offset_MASK 0xfffffff
+#define ACP_DSP2_CACHE_OFFSET1__Offset__SHIFT 0x0
+#define ACP_DSP2_CACHE_OFFSET1__OnionGarlicSel_MASK 0x80000000
+#define ACP_DSP2_CACHE_OFFSET1__OnionGarlicSel__SHIFT 0x1f
+#define ACP_DSP2_CACHE_SIZE1__Size_MASK 0xffffff
+#define ACP_DSP2_CACHE_SIZE1__Size__SHIFT 0x0
+#define ACP_DSP2_CACHE_SIZE1__PageEnable_MASK 0x80000000
+#define ACP_DSP2_CACHE_SIZE1__PageEnable__SHIFT 0x1f
+#define ACP_DSP2_CACHE_OFFSET2__Offset_MASK 0xfffffff
+#define ACP_DSP2_CACHE_OFFSET2__Offset__SHIFT 0x0
+#define ACP_DSP2_CACHE_OFFSET2__OnionGarlicSel_MASK 0x80000000
+#define ACP_DSP2_CACHE_OFFSET2__OnionGarlicSel__SHIFT 0x1f
+#define ACP_DSP2_CACHE_SIZE2__Size_MASK 0xffffff
+#define ACP_DSP2_CACHE_SIZE2__Size__SHIFT 0x0
+#define ACP_DSP2_CACHE_SIZE2__PageEnable_MASK 0x80000000
+#define ACP_DSP2_CACHE_SIZE2__PageEnable__SHIFT 0x1f
+#define ACP_DSP2_CACHE_OFFSET3__Offset_MASK 0xfffffff
+#define ACP_DSP2_CACHE_OFFSET3__Offset__SHIFT 0x0
+#define ACP_DSP2_CACHE_OFFSET3__OnionGarlicSel_MASK 0x80000000
+#define ACP_DSP2_CACHE_OFFSET3__OnionGarlicSel__SHIFT 0x1f
+#define ACP_DSP2_CACHE_SIZE3__Size_MASK 0xffffff
+#define ACP_DSP2_CACHE_SIZE3__Size__SHIFT 0x0
+#define ACP_DSP2_CACHE_SIZE3__PageEnable_MASK 0x80000000
+#define ACP_DSP2_CACHE_SIZE3__PageEnable__SHIFT 0x1f
+#define ACP_DSP2_CACHE_OFFSET4__Offset_MASK 0xfffffff
+#define ACP_DSP2_CACHE_OFFSET4__Offset__SHIFT 0x0
+#define ACP_DSP2_CACHE_OFFSET4__OnionGarlicSel_MASK 0x80000000
+#define ACP_DSP2_CACHE_OFFSET4__OnionGarlicSel__SHIFT 0x1f
+#define ACP_DSP2_CACHE_SIZE4__Size_MASK 0xffffff
+#define ACP_DSP2_CACHE_SIZE4__Size__SHIFT 0x0
+#define ACP_DSP2_CACHE_SIZE4__PageEnable_MASK 0x80000000
+#define ACP_DSP2_CACHE_SIZE4__PageEnable__SHIFT 0x1f
+#define ACP_DSP2_CACHE_OFFSET5__Offset_MASK 0xfffffff
+#define ACP_DSP2_CACHE_OFFSET5__Offset__SHIFT 0x0
+#define ACP_DSP2_CACHE_OFFSET5__OnionGarlicSel_MASK 0x80000000
+#define ACP_DSP2_CACHE_OFFSET5__OnionGarlicSel__SHIFT 0x1f
+#define ACP_DSP2_CACHE_SIZE5__Size_MASK 0xffffff
+#define ACP_DSP2_CACHE_SIZE5__Size__SHIFT 0x0
+#define ACP_DSP2_CACHE_SIZE5__PageEnable_MASK 0x80000000
+#define ACP_DSP2_CACHE_SIZE5__PageEnable__SHIFT 0x1f
+#define ACP_DSP2_CACHE_OFFSET6__Offset_MASK 0xfffffff
+#define ACP_DSP2_CACHE_OFFSET6__Offset__SHIFT 0x0
+#define ACP_DSP2_CACHE_OFFSET6__OnionGarlicSel_MASK 0x80000000
+#define ACP_DSP2_CACHE_OFFSET6__OnionGarlicSel__SHIFT 0x1f
+#define ACP_DSP2_CACHE_SIZE6__Size_MASK 0xffffff
+#define ACP_DSP2_CACHE_SIZE6__Size__SHIFT 0x0
+#define ACP_DSP2_CACHE_SIZE6__PageEnable_MASK 0x80000000
+#define ACP_DSP2_CACHE_SIZE6__PageEnable__SHIFT 0x1f
+#define ACP_DSP2_CACHE_OFFSET7__Offset_MASK 0xfffffff
+#define ACP_DSP2_CACHE_OFFSET7__Offset__SHIFT 0x0
+#define ACP_DSP2_CACHE_OFFSET7__OnionGarlicSel_MASK 0x80000000
+#define ACP_DSP2_CACHE_OFFSET7__OnionGarlicSel__SHIFT 0x1f
+#define ACP_DSP2_CACHE_SIZE7__Size_MASK 0xffffff
+#define ACP_DSP2_CACHE_SIZE7__Size__SHIFT 0x0
+#define ACP_DSP2_CACHE_SIZE7__PageEnable_MASK 0x80000000
+#define ACP_DSP2_CACHE_SIZE7__PageEnable__SHIFT 0x1f
+#define ACP_DSP2_CACHE_OFFSET8__Offset_MASK 0xfffffff
+#define ACP_DSP2_CACHE_OFFSET8__Offset__SHIFT 0x0
+#define ACP_DSP2_CACHE_OFFSET8__OnionGarlicSel_MASK 0x80000000
+#define ACP_DSP2_CACHE_OFFSET8__OnionGarlicSel__SHIFT 0x1f
+#define ACP_DSP2_CACHE_SIZE8__Size_MASK 0xffffff
+#define ACP_DSP2_CACHE_SIZE8__Size__SHIFT 0x0
+#define ACP_DSP2_CACHE_SIZE8__PageEnable_MASK 0x80000000
+#define ACP_DSP2_CACHE_SIZE8__PageEnable__SHIFT 0x1f
+#define ACP_DSP2_NONCACHE_OFFSET0__Offset_MASK 0xfffffff
+#define ACP_DSP2_NONCACHE_OFFSET0__Offset__SHIFT 0x0
+#define ACP_DSP2_NONCACHE_OFFSET0__OnionGarlicSel_MASK 0x80000000
+#define ACP_DSP2_NONCACHE_OFFSET0__OnionGarlicSel__SHIFT 0x1f
+#define ACP_DSP2_NONCACHE_SIZE0__Size_MASK 0xffffff
+#define ACP_DSP2_NONCACHE_SIZE0__Size__SHIFT 0x0
+#define ACP_DSP2_NONCACHE_SIZE0__PageEnable_MASK 0x80000000
+#define ACP_DSP2_NONCACHE_SIZE0__PageEnable__SHIFT 0x1f
+#define ACP_DSP2_NONCACHE_OFFSET1__Offset_MASK 0xfffffff
+#define ACP_DSP2_NONCACHE_OFFSET1__Offset__SHIFT 0x0
+#define ACP_DSP2_NONCACHE_OFFSET1__OnionGarlicSel_MASK 0x80000000
+#define ACP_DSP2_NONCACHE_OFFSET1__OnionGarlicSel__SHIFT 0x1f
+#define ACP_DSP2_NONCACHE_SIZE1__Size_MASK 0xffffff
+#define ACP_DSP2_NONCACHE_SIZE1__Size__SHIFT 0x0
+#define ACP_DSP2_NONCACHE_SIZE1__PageEnable_MASK 0x80000000
+#define ACP_DSP2_NONCACHE_SIZE1__PageEnable__SHIFT 0x1f
+#define ACP_DSP2_DEBUG_PC__DebugPC_MASK 0xffffffff
+#define ACP_DSP2_DEBUG_PC__DebugPC__SHIFT 0x0
+#define ACP_DSP2_NMI_SEL__NMISel_MASK 0x1
+#define ACP_DSP2_NMI_SEL__NMISel__SHIFT 0x0
+#define ACP_DSP2_CLKRST_CNTL__ClkEn_MASK 0x1
+#define ACP_DSP2_CLKRST_CNTL__ClkEn__SHIFT 0x0
+#define ACP_DSP2_CLKRST_CNTL__SoftResetDSP_MASK 0x2
+#define ACP_DSP2_CLKRST_CNTL__SoftResetDSP__SHIFT 0x1
+#define ACP_DSP2_CLKRST_CNTL__InternalSoftResetMode_MASK 0x4
+#define ACP_DSP2_CLKRST_CNTL__InternalSoftResetMode__SHIFT 0x2
+#define ACP_DSP2_CLKRST_CNTL__ExternalSoftResetMode_MASK 0x8
+#define ACP_DSP2_CLKRST_CNTL__ExternalSoftResetMode__SHIFT 0x3
+#define ACP_DSP2_CLKRST_CNTL__SoftResetDSPDone_MASK 0x10
+#define ACP_DSP2_CLKRST_CNTL__SoftResetDSPDone__SHIFT 0x4
+#define ACP_DSP2_CLKRST_CNTL__Clk_ON_Status_MASK 0x20
+#define ACP_DSP2_CLKRST_CNTL__Clk_ON_Status__SHIFT 0x5
+#define ACP_DSP2_RUNSTALL__RunStallCntl_MASK 0x1
+#define ACP_DSP2_RUNSTALL__RunStallCntl__SHIFT 0x0
+#define ACP_DSP2_OCD_HALT_ON_RST__OCD_HALT_ON_RST_MASK 0x1
+#define ACP_DSP2_OCD_HALT_ON_RST__OCD_HALT_ON_RST__SHIFT 0x0
+#define ACP_DSP2_WAIT_MODE__WaitMode_MASK 0x1
+#define ACP_DSP2_WAIT_MODE__WaitMode__SHIFT 0x0
+#define ACP_DSP2_VECT_SEL__StaticVectorSel_MASK 0x1
+#define ACP_DSP2_VECT_SEL__StaticVectorSel__SHIFT 0x0
+#define ACP_DSP2_DEBUG_REG1__ACP_DSP_DEBUG_REG1_MASK 0xffffffff
+#define ACP_DSP2_DEBUG_REG1__ACP_DSP_DEBUG_REG1__SHIFT 0x0
+#define ACP_DSP2_DEBUG_REG2__ACP_DSP_DEBUG_REG2_MASK 0xffffffff
+#define ACP_DSP2_DEBUG_REG2__ACP_DSP_DEBUG_REG2__SHIFT 0x0
+#define ACP_DSP2_DEBUG_REG3__ACP_DSP_DEBUG_REG3_MASK 0xffffffff
+#define ACP_DSP2_DEBUG_REG3__ACP_DSP_DEBUG_REG3__SHIFT 0x0
+#define ACP_AXI2DAGB_ONION_CNTL__AXI2DAGBDataSwap_MASK 0x3
+#define ACP_AXI2DAGB_ONION_CNTL__AXI2DAGBDataSwap__SHIFT 0x0
+#define ACP_AXI2DAGB_ONION_CNTL__AXI2DAGBEnbMultRdReq_MASK 0x4
+#define ACP_AXI2DAGB_ONION_CNTL__AXI2DAGBEnbMultRdReq__SHIFT 0x2
+#define ACP_AXI2DAGB_ONION_CNTL__AXI2DAGBEnbMultWrReq_MASK 0x18
+#define ACP_AXI2DAGB_ONION_CNTL__AXI2DAGBEnbMultWrReq__SHIFT 0x3
+#define ACP_AXI2DAGB_ONION_CNTL__AXI2DAGBMaxReadBurst_MASK 0x60
+#define ACP_AXI2DAGB_ONION_CNTL__AXI2DAGBMaxReadBurst__SHIFT 0x5
+#define ACP_AXI2DAGB_ONION_CNTL__AXI2DAGBStallEnb_MASK 0x80
+#define ACP_AXI2DAGB_ONION_CNTL__AXI2DAGBStallEnb__SHIFT 0x7
+#define ACP_AXI2DAGB_ONION_CNTL__AXI2DAGBNackChkEnb_MASK 0x100
+#define ACP_AXI2DAGB_ONION_CNTL__AXI2DAGBNackChkEnb__SHIFT 0x8
+#define ACP_AXI2DAGB_ONION_CNTL__AXI2DAGBAdrWinViolChkEnb_MASK 0x200
+#define ACP_AXI2DAGB_ONION_CNTL__AXI2DAGBAdrWinViolChkEnb__SHIFT 0x9
+#define ACP_AXI2DAGB_ONION_CNTL__AXI2DAGBUrgEnb_MASK 0x400
+#define ACP_AXI2DAGB_ONION_CNTL__AXI2DAGBUrgEnb__SHIFT 0xa
+#define ACP_AXI2DAGB_ONION_CNTL__AXI2DAGBUrgCntMult_MASK 0x1800
+#define ACP_AXI2DAGB_ONION_CNTL__AXI2DAGBUrgCntMult__SHIFT 0xb
+#define ACP_AXI2DAGB_ONION_CNTL__AXI2DAGBStallMode_MASK 0x2000
+#define ACP_AXI2DAGB_ONION_CNTL__AXI2DAGBStallMode__SHIFT 0xd
+#define ACP_AXI2DAGB_ONION_ERR_STATUS_WR__AXI2DAGBAdrWinViolOver_MASK 0x2000000
+#define ACP_AXI2DAGB_ONION_ERR_STATUS_WR__AXI2DAGBAdrWinViolOver__SHIFT 0x19
+#define ACP_AXI2DAGB_ONION_ERR_STATUS_WR__AXI2DAGBAdrWinViolSource_MASK 0x1c000000
+#define ACP_AXI2DAGB_ONION_ERR_STATUS_WR__AXI2DAGBAdrWinViolSource__SHIFT 0x1a
+#define ACP_AXI2DAGB_ONION_ERR_STATUS_WR__AXI2DAGBAdrWinViol_MASK 0x20000000
+#define ACP_AXI2DAGB_ONION_ERR_STATUS_WR__AXI2DAGBAdrWinViol__SHIFT 0x1d
+#define ACP_AXI2DAGB_ONION_ERR_STATUS_WR__AXI2DAGBNackOver_MASK 0x40000000
+#define ACP_AXI2DAGB_ONION_ERR_STATUS_WR__AXI2DAGBNackOver__SHIFT 0x1e
+#define ACP_AXI2DAGB_ONION_ERR_STATUS_WR__AXI2DAGBNackVal_MASK 0x80000000
+#define ACP_AXI2DAGB_ONION_ERR_STATUS_WR__AXI2DAGBNackVal__SHIFT 0x1f
+#define ACP_AXI2DAGB_ONION_ERR_STATUS_RD__AXI2DAGBAdrWinViolOver_MASK 0x2000000
+#define ACP_AXI2DAGB_ONION_ERR_STATUS_RD__AXI2DAGBAdrWinViolOver__SHIFT 0x19
+#define ACP_AXI2DAGB_ONION_ERR_STATUS_RD__AXI2DAGBAdrWinViolSource_MASK 0x1c000000
+#define ACP_AXI2DAGB_ONION_ERR_STATUS_RD__AXI2DAGBAdrWinViolSource__SHIFT 0x1a
+#define ACP_AXI2DAGB_ONION_ERR_STATUS_RD__AXI2DAGBAdrWinViol_MASK 0x20000000
+#define ACP_AXI2DAGB_ONION_ERR_STATUS_RD__AXI2DAGBAdrWinViol__SHIFT 0x1d
+#define ACP_AXI2DAGB_ONION_ERR_STATUS_RD__AXI2DAGBNackOver_MASK 0x40000000
+#define ACP_AXI2DAGB_ONION_ERR_STATUS_RD__AXI2DAGBNackOver__SHIFT 0x1e
+#define ACP_AXI2DAGB_ONION_ERR_STATUS_RD__AXI2DAGBNackVal_MASK 0x80000000
+#define ACP_AXI2DAGB_ONION_ERR_STATUS_RD__AXI2DAGBNackVal__SHIFT 0x1f
+#define ACP_DAGB_Onion_TransPerf_Counter_Control__EnbDAGBTransPerfCntr_MASK 0x1
+#define ACP_DAGB_Onion_TransPerf_Counter_Control__EnbDAGBTransPerfCntr__SHIFT 0x0
+#define ACP_DAGB_Onion_Wr_TransPerf_Counter_Current__CurDAGBTransPerfCntrTime_MASK 0x1ffff
+#define ACP_DAGB_Onion_Wr_TransPerf_Counter_Current__CurDAGBTransPerfCntrTime__SHIFT 0x0
+#define ACP_DAGB_Onion_Wr_TransPerf_Counter_Current__ClrCurDAGBTransPerfCntr_MASK 0x80000000
+#define ACP_DAGB_Onion_Wr_TransPerf_Counter_Current__ClrCurDAGBTransPerfCntr__SHIFT 0x1f
+#define ACP_DAGB_Onion_Wr_TransPerf_Counter_Peak__PeakDAGBTransPerfCntrTime_MASK 0x1ffff
+#define ACP_DAGB_Onion_Wr_TransPerf_Counter_Peak__PeakDAGBTransPerfCntrTime__SHIFT 0x0
+#define ACP_DAGB_Onion_Wr_TransPerf_Counter_Peak__ClrPeakDAGBTransPerfCntr_MASK 0x80000000
+#define ACP_DAGB_Onion_Wr_TransPerf_Counter_Peak__ClrPeakDAGBTransPerfCntr__SHIFT 0x1f
+#define ACP_DAGB_Onion_Rd_TransPerf_Counter_Current__CurDAGBTransPerfCntrTime_MASK 0x1ffff
+#define ACP_DAGB_Onion_Rd_TransPerf_Counter_Current__CurDAGBTransPerfCntrTime__SHIFT 0x0
+#define ACP_DAGB_Onion_Rd_TransPerf_Counter_Current__ClrCurDAGBTransPerfCntr_MASK 0x80000000
+#define ACP_DAGB_Onion_Rd_TransPerf_Counter_Current__ClrCurDAGBTransPerfCntr__SHIFT 0x1f
+#define ACP_DAGB_Onion_Rd_TransPerf_Counter_Peak__PeakDAGBTransPerfCntrTime_MASK 0x1ffff
+#define ACP_DAGB_Onion_Rd_TransPerf_Counter_Peak__PeakDAGBTransPerfCntrTime__SHIFT 0x0
+#define ACP_DAGB_Onion_Rd_TransPerf_Counter_Peak__ClrPeakDAGBTransPerfCntr_MASK 0x80000000
+#define ACP_DAGB_Onion_Rd_TransPerf_Counter_Peak__ClrPeakDAGBTransPerfCntr__SHIFT 0x1f
+#define ACP_AXI2DAGB_GARLIC_CNTL__AXI2DAGBDataSwap_MASK 0x3
+#define ACP_AXI2DAGB_GARLIC_CNTL__AXI2DAGBDataSwap__SHIFT 0x0
+#define ACP_AXI2DAGB_GARLIC_CNTL__AXI2DAGBEnbMultRdReq_MASK 0x4
+#define ACP_AXI2DAGB_GARLIC_CNTL__AXI2DAGBEnbMultRdReq__SHIFT 0x2
+#define ACP_AXI2DAGB_GARLIC_CNTL__AXI2DAGBEnbMultWrReq_MASK 0x18
+#define ACP_AXI2DAGB_GARLIC_CNTL__AXI2DAGBEnbMultWrReq__SHIFT 0x3
+#define ACP_AXI2DAGB_GARLIC_CNTL__AXI2DAGBMaxReadBurst_MASK 0x60
+#define ACP_AXI2DAGB_GARLIC_CNTL__AXI2DAGBMaxReadBurst__SHIFT 0x5
+#define ACP_AXI2DAGB_GARLIC_CNTL__AXI2DAGBStallEnb_MASK 0x80
+#define ACP_AXI2DAGB_GARLIC_CNTL__AXI2DAGBStallEnb__SHIFT 0x7
+#define ACP_AXI2DAGB_GARLIC_CNTL__AXI2DAGBNackChkEnb_MASK 0x100
+#define ACP_AXI2DAGB_GARLIC_CNTL__AXI2DAGBNackChkEnb__SHIFT 0x8
+#define ACP_AXI2DAGB_GARLIC_CNTL__AXI2DAGBAdrWinViolChkEnb_MASK 0x200
+#define ACP_AXI2DAGB_GARLIC_CNTL__AXI2DAGBAdrWinViolChkEnb__SHIFT 0x9
+#define ACP_AXI2DAGB_GARLIC_CNTL__AXI2DAGBUrgEnb_MASK 0x400
+#define ACP_AXI2DAGB_GARLIC_CNTL__AXI2DAGBUrgEnb__SHIFT 0xa
+#define ACP_AXI2DAGB_GARLIC_CNTL__AXI2DAGBUrgCntMult_MASK 0x1800
+#define ACP_AXI2DAGB_GARLIC_CNTL__AXI2DAGBUrgCntMult__SHIFT 0xb
+#define ACP_AXI2DAGB_GARLIC_CNTL__AXI2DAGBStallMode_MASK 0x2000
+#define ACP_AXI2DAGB_GARLIC_CNTL__AXI2DAGBStallMode__SHIFT 0xd
+#define ACP_AXI2DAGB_GARLIC_ERR_STATUS_WR__AXI2DAGBAdrWinViolOver_MASK 0x2000000
+#define ACP_AXI2DAGB_GARLIC_ERR_STATUS_WR__AXI2DAGBAdrWinViolOver__SHIFT 0x19
+#define ACP_AXI2DAGB_GARLIC_ERR_STATUS_WR__AXI2DAGBAdrWinViolSource_MASK 0x1c000000
+#define ACP_AXI2DAGB_GARLIC_ERR_STATUS_WR__AXI2DAGBAdrWinViolSource__SHIFT 0x1a
+#define ACP_AXI2DAGB_GARLIC_ERR_STATUS_WR__AXI2DAGBAdrWinViol_MASK 0x20000000
+#define ACP_AXI2DAGB_GARLIC_ERR_STATUS_WR__AXI2DAGBAdrWinViol__SHIFT 0x1d
+#define ACP_AXI2DAGB_GARLIC_ERR_STATUS_WR__AXI2DAGBNackOver_MASK 0x40000000
+#define ACP_AXI2DAGB_GARLIC_ERR_STATUS_WR__AXI2DAGBNackOver__SHIFT 0x1e
+#define ACP_AXI2DAGB_GARLIC_ERR_STATUS_WR__AXI2DAGBNackVal_MASK 0x80000000
+#define ACP_AXI2DAGB_GARLIC_ERR_STATUS_WR__AXI2DAGBNackVal__SHIFT 0x1f
+#define ACP_AXI2DAGB_GARLIC_ERR_STATUS_RD__AXI2DAGBAdrWinViolOver_MASK 0x2000000
+#define ACP_AXI2DAGB_GARLIC_ERR_STATUS_RD__AXI2DAGBAdrWinViolOver__SHIFT 0x19
+#define ACP_AXI2DAGB_GARLIC_ERR_STATUS_RD__AXI2DAGBAdrWinViolSource_MASK 0x1c000000
+#define ACP_AXI2DAGB_GARLIC_ERR_STATUS_RD__AXI2DAGBAdrWinViolSource__SHIFT 0x1a
+#define ACP_AXI2DAGB_GARLIC_ERR_STATUS_RD__AXI2DAGBAdrWinViol_MASK 0x20000000
+#define ACP_AXI2DAGB_GARLIC_ERR_STATUS_RD__AXI2DAGBAdrWinViol__SHIFT 0x1d
+#define ACP_AXI2DAGB_GARLIC_ERR_STATUS_RD__AXI2DAGBNackOver_MASK 0x40000000
+#define ACP_AXI2DAGB_GARLIC_ERR_STATUS_RD__AXI2DAGBNackOver__SHIFT 0x1e
+#define ACP_AXI2DAGB_GARLIC_ERR_STATUS_RD__AXI2DAGBNackVal_MASK 0x80000000
+#define ACP_AXI2DAGB_GARLIC_ERR_STATUS_RD__AXI2DAGBNackVal__SHIFT 0x1f
+#define ACP_DAGB_Garlic_TransPerf_Counter_Control__EnbDAGBTransPerfCntr_MASK 0x1
+#define ACP_DAGB_Garlic_TransPerf_Counter_Control__EnbDAGBTransPerfCntr__SHIFT 0x0
+#define ACP_DAGB_Garlic_Wr_TransPerf_Counter_Current__CurDAGBTransPerfCntrTime_MASK 0x1ffff
+#define ACP_DAGB_Garlic_Wr_TransPerf_Counter_Current__CurDAGBTransPerfCntrTime__SHIFT 0x0
+#define ACP_DAGB_Garlic_Wr_TransPerf_Counter_Current__ClrCurDAGBTransPerfCntr_MASK 0x80000000
+#define ACP_DAGB_Garlic_Wr_TransPerf_Counter_Current__ClrCurDAGBTransPerfCntr__SHIFT 0x1f
+#define ACP_DAGB_Garlic_Wr_TransPerf_Counter_Peak__PeakDAGBTransPerfCntrTime_MASK 0x1ffff
+#define ACP_DAGB_Garlic_Wr_TransPerf_Counter_Peak__PeakDAGBTransPerfCntrTime__SHIFT 0x0
+#define ACP_DAGB_Garlic_Wr_TransPerf_Counter_Peak__ClrPeakDAGBTransPerfCntr_MASK 0x80000000
+#define ACP_DAGB_Garlic_Wr_TransPerf_Counter_Peak__ClrPeakDAGBTransPerfCntr__SHIFT 0x1f
+#define ACP_DAGB_Garlic_Rd_TransPerf_Counter_Current__CurDAGBTransPerfCntrTime_MASK 0x1ffff
+#define ACP_DAGB_Garlic_Rd_TransPerf_Counter_Current__CurDAGBTransPerfCntrTime__SHIFT 0x0
+#define ACP_DAGB_Garlic_Rd_TransPerf_Counter_Current__ClrCurDAGBTransPerfCntr_MASK 0x80000000
+#define ACP_DAGB_Garlic_Rd_TransPerf_Counter_Current__ClrCurDAGBTransPerfCntr__SHIFT 0x1f
+#define ACP_DAGB_Garlic_Rd_TransPerf_Counter_Peak__PeakDAGBTransPerfCntrTime_MASK 0x1ffff
+#define ACP_DAGB_Garlic_Rd_TransPerf_Counter_Peak__PeakDAGBTransPerfCntrTime__SHIFT 0x0
+#define ACP_DAGB_Garlic_Rd_TransPerf_Counter_Peak__ClrPeakDAGBTransPerfCntr_MASK 0x80000000
+#define ACP_DAGB_Garlic_Rd_TransPerf_Counter_Peak__ClrPeakDAGBTransPerfCntr__SHIFT 0x1f
+#define ACP_DAGB_PAGE_SIZE_GRP_1__AXI2DAGBPageSize_MASK 0x3
+#define ACP_DAGB_PAGE_SIZE_GRP_1__AXI2DAGBPageSize__SHIFT 0x0
+#define ACP_DAGB_BASE_ADDR_GRP_1__AXI2DAGBBaseAddr_MASK 0xfffffff
+#define ACP_DAGB_BASE_ADDR_GRP_1__AXI2DAGBBaseAddr__SHIFT 0x0
+#define ACP_DAGB_BASE_ADDR_GRP_1__AXI2DAGBSnoopSel_MASK 0x20000000
+#define ACP_DAGB_BASE_ADDR_GRP_1__AXI2DAGBSnoopSel__SHIFT 0x1d
+#define ACP_DAGB_BASE_ADDR_GRP_1__AXI2DAGBTargetMemSel_MASK 0x40000000
+#define ACP_DAGB_BASE_ADDR_GRP_1__AXI2DAGBTargetMemSel__SHIFT 0x1e
+#define ACP_DAGB_BASE_ADDR_GRP_1__AXI2DAGBGrpEnable_MASK 0x80000000
+#define ACP_DAGB_BASE_ADDR_GRP_1__AXI2DAGBGrpEnable__SHIFT 0x1f
+#define ACP_DAGB_PAGE_SIZE_GRP_2__AXI2DAGBPageSize_MASK 0x3
+#define ACP_DAGB_PAGE_SIZE_GRP_2__AXI2DAGBPageSize__SHIFT 0x0
+#define ACP_DAGB_BASE_ADDR_GRP_2__AXI2DAGBBaseAddr_MASK 0xfffffff
+#define ACP_DAGB_BASE_ADDR_GRP_2__AXI2DAGBBaseAddr__SHIFT 0x0
+#define ACP_DAGB_BASE_ADDR_GRP_2__AXI2DAGBSnoopSel_MASK 0x20000000
+#define ACP_DAGB_BASE_ADDR_GRP_2__AXI2DAGBSnoopSel__SHIFT 0x1d
+#define ACP_DAGB_BASE_ADDR_GRP_2__AXI2DAGBTargetMemSel_MASK 0x40000000
+#define ACP_DAGB_BASE_ADDR_GRP_2__AXI2DAGBTargetMemSel__SHIFT 0x1e
+#define ACP_DAGB_BASE_ADDR_GRP_2__AXI2DAGBGrpEnable_MASK 0x80000000
+#define ACP_DAGB_BASE_ADDR_GRP_2__AXI2DAGBGrpEnable__SHIFT 0x1f
+#define ACP_DAGB_PAGE_SIZE_GRP_3__AXI2DAGBPageSize_MASK 0x3
+#define ACP_DAGB_PAGE_SIZE_GRP_3__AXI2DAGBPageSize__SHIFT 0x0
+#define ACP_DAGB_BASE_ADDR_GRP_3__AXI2DAGBBaseAddr_MASK 0xfffffff
+#define ACP_DAGB_BASE_ADDR_GRP_3__AXI2DAGBBaseAddr__SHIFT 0x0
+#define ACP_DAGB_BASE_ADDR_GRP_3__AXI2DAGBSnoopSel_MASK 0x20000000
+#define ACP_DAGB_BASE_ADDR_GRP_3__AXI2DAGBSnoopSel__SHIFT 0x1d
+#define ACP_DAGB_BASE_ADDR_GRP_3__AXI2DAGBTargetMemSel_MASK 0x40000000
+#define ACP_DAGB_BASE_ADDR_GRP_3__AXI2DAGBTargetMemSel__SHIFT 0x1e
+#define ACP_DAGB_BASE_ADDR_GRP_3__AXI2DAGBGrpEnable_MASK 0x80000000
+#define ACP_DAGB_BASE_ADDR_GRP_3__AXI2DAGBGrpEnable__SHIFT 0x1f
+#define ACP_DAGB_PAGE_SIZE_GRP_4__AXI2DAGBPageSize_MASK 0x3
+#define ACP_DAGB_PAGE_SIZE_GRP_4__AXI2DAGBPageSize__SHIFT 0x0
+#define ACP_DAGB_BASE_ADDR_GRP_4__AXI2DAGBBaseAddr_MASK 0xfffffff
+#define ACP_DAGB_BASE_ADDR_GRP_4__AXI2DAGBBaseAddr__SHIFT 0x0
+#define ACP_DAGB_BASE_ADDR_GRP_4__AXI2DAGBSnoopSel_MASK 0x20000000
+#define ACP_DAGB_BASE_ADDR_GRP_4__AXI2DAGBSnoopSel__SHIFT 0x1d
+#define ACP_DAGB_BASE_ADDR_GRP_4__AXI2DAGBTargetMemSel_MASK 0x40000000
+#define ACP_DAGB_BASE_ADDR_GRP_4__AXI2DAGBTargetMemSel__SHIFT 0x1e
+#define ACP_DAGB_BASE_ADDR_GRP_4__AXI2DAGBGrpEnable_MASK 0x80000000
+#define ACP_DAGB_BASE_ADDR_GRP_4__AXI2DAGBGrpEnable__SHIFT 0x1f
+#define ACP_DAGB_PAGE_SIZE_GRP_5__AXI2DAGBPageSize_MASK 0x3
+#define ACP_DAGB_PAGE_SIZE_GRP_5__AXI2DAGBPageSize__SHIFT 0x0
+#define ACP_DAGB_BASE_ADDR_GRP_5__AXI2DAGBBaseAddr_MASK 0xfffffff
+#define ACP_DAGB_BASE_ADDR_GRP_5__AXI2DAGBBaseAddr__SHIFT 0x0
+#define ACP_DAGB_BASE_ADDR_GRP_5__AXI2DAGBSnoopSel_MASK 0x20000000
+#define ACP_DAGB_BASE_ADDR_GRP_5__AXI2DAGBSnoopSel__SHIFT 0x1d
+#define ACP_DAGB_BASE_ADDR_GRP_5__AXI2DAGBTargetMemSel_MASK 0x40000000
+#define ACP_DAGB_BASE_ADDR_GRP_5__AXI2DAGBTargetMemSel__SHIFT 0x1e
+#define ACP_DAGB_BASE_ADDR_GRP_5__AXI2DAGBGrpEnable_MASK 0x80000000
+#define ACP_DAGB_BASE_ADDR_GRP_5__AXI2DAGBGrpEnable__SHIFT 0x1f
+#define ACP_DAGB_PAGE_SIZE_GRP_6__AXI2DAGBPageSize_MASK 0x3
+#define ACP_DAGB_PAGE_SIZE_GRP_6__AXI2DAGBPageSize__SHIFT 0x0
+#define ACP_DAGB_BASE_ADDR_GRP_6__AXI2DAGBBaseAddr_MASK 0xfffffff
+#define ACP_DAGB_BASE_ADDR_GRP_6__AXI2DAGBBaseAddr__SHIFT 0x0
+#define ACP_DAGB_BASE_ADDR_GRP_6__AXI2DAGBSnoopSel_MASK 0x20000000
+#define ACP_DAGB_BASE_ADDR_GRP_6__AXI2DAGBSnoopSel__SHIFT 0x1d
+#define ACP_DAGB_BASE_ADDR_GRP_6__AXI2DAGBTargetMemSel_MASK 0x40000000
+#define ACP_DAGB_BASE_ADDR_GRP_6__AXI2DAGBTargetMemSel__SHIFT 0x1e
+#define ACP_DAGB_BASE_ADDR_GRP_6__AXI2DAGBGrpEnable_MASK 0x80000000
+#define ACP_DAGB_BASE_ADDR_GRP_6__AXI2DAGBGrpEnable__SHIFT 0x1f
+#define ACP_DAGB_PAGE_SIZE_GRP_7__AXI2DAGBPageSize_MASK 0x3
+#define ACP_DAGB_PAGE_SIZE_GRP_7__AXI2DAGBPageSize__SHIFT 0x0
+#define ACP_DAGB_BASE_ADDR_GRP_7__AXI2DAGBBaseAddr_MASK 0xfffffff
+#define ACP_DAGB_BASE_ADDR_GRP_7__AXI2DAGBBaseAddr__SHIFT 0x0
+#define ACP_DAGB_BASE_ADDR_GRP_7__AXI2DAGBSnoopSel_MASK 0x20000000
+#define ACP_DAGB_BASE_ADDR_GRP_7__AXI2DAGBSnoopSel__SHIFT 0x1d
+#define ACP_DAGB_BASE_ADDR_GRP_7__AXI2DAGBTargetMemSel_MASK 0x40000000
+#define ACP_DAGB_BASE_ADDR_GRP_7__AXI2DAGBTargetMemSel__SHIFT 0x1e
+#define ACP_DAGB_BASE_ADDR_GRP_7__AXI2DAGBGrpEnable_MASK 0x80000000
+#define ACP_DAGB_BASE_ADDR_GRP_7__AXI2DAGBGrpEnable__SHIFT 0x1f
+#define ACP_DAGB_PAGE_SIZE_GRP_8__AXI2DAGBPageSize_MASK 0x3
+#define ACP_DAGB_PAGE_SIZE_GRP_8__AXI2DAGBPageSize__SHIFT 0x0
+#define ACP_DAGB_BASE_ADDR_GRP_8__AXI2DAGBBaseAddr_MASK 0xfffffff
+#define ACP_DAGB_BASE_ADDR_GRP_8__AXI2DAGBBaseAddr__SHIFT 0x0
+#define ACP_DAGB_BASE_ADDR_GRP_8__AXI2DAGBSnoopSel_MASK 0x20000000
+#define ACP_DAGB_BASE_ADDR_GRP_8__AXI2DAGBSnoopSel__SHIFT 0x1d
+#define ACP_DAGB_BASE_ADDR_GRP_8__AXI2DAGBTargetMemSel_MASK 0x40000000
+#define ACP_DAGB_BASE_ADDR_GRP_8__AXI2DAGBTargetMemSel__SHIFT 0x1e
+#define ACP_DAGB_BASE_ADDR_GRP_8__AXI2DAGBGrpEnable_MASK 0x80000000
+#define ACP_DAGB_BASE_ADDR_GRP_8__AXI2DAGBGrpEnable__SHIFT 0x1f
+#define ACP_DAGB_ATU_CTRL__AXI2DAGBCacheInvalidate_MASK 0x1
+#define ACP_DAGB_ATU_CTRL__AXI2DAGBCacheInvalidate__SHIFT 0x0
+#define ACP_CONTROL__ClkEn_MASK 0x1
+#define ACP_CONTROL__ClkEn__SHIFT 0x0
+#define ACP_CONTROL__JtagEn_MASK 0x400
+#define ACP_CONTROL__JtagEn__SHIFT 0xa
+#define ACP_STATUS__ClkOn_MASK 0x1
+#define ACP_STATUS__ClkOn__SHIFT 0x0
+#define ACP_STATUS__ACPRefClkSpd_MASK 0x2
+#define ACP_STATUS__ACPRefClkSpd__SHIFT 0x1
+#define ACP_STATUS__SMUStutterLastEdge_MASK 0x4
+#define ACP_STATUS__SMUStutterLastEdge__SHIFT 0x2
+#define ACP_STATUS__MCStutterLastEdge_MASK 0x8
+#define ACP_STATUS__MCStutterLastEdge__SHIFT 0x3
+#define ACP_SOFT_RESET__SoftResetAud_MASK 0x100
+#define ACP_SOFT_RESET__SoftResetAud__SHIFT 0x8
+#define ACP_SOFT_RESET__SoftResetDMA_MASK 0x200
+#define ACP_SOFT_RESET__SoftResetDMA__SHIFT 0x9
+#define ACP_SOFT_RESET__InternalSoftResetMode_MASK 0x4000
+#define ACP_SOFT_RESET__InternalSoftResetMode__SHIFT 0xe
+#define ACP_SOFT_RESET__ExternalSoftResetMode_MASK 0x8000
+#define ACP_SOFT_RESET__ExternalSoftResetMode__SHIFT 0xf
+#define ACP_SOFT_RESET__SoftResetAudDone_MASK 0x1000000
+#define ACP_SOFT_RESET__SoftResetAudDone__SHIFT 0x18
+#define ACP_SOFT_RESET__SoftResetDMADone_MASK 0x2000000
+#define ACP_SOFT_RESET__SoftResetDMADone__SHIFT 0x19
+#define ACP_PwrMgmt_CNTL__SCLKSleepCntl_MASK 0x3
+#define ACP_PwrMgmt_CNTL__SCLKSleepCntl__SHIFT 0x0
+#define ACP_CAC_INDICATOR_CONTROL__ACP_Cac_Indicator_Counter_MASK 0xffff
+#define ACP_CAC_INDICATOR_CONTROL__ACP_Cac_Indicator_Counter__SHIFT 0x0
+#define ACP_SMU_MAILBOX__ACP_SMU_Mailbox_MASK 0xffffffff
+#define ACP_SMU_MAILBOX__ACP_SMU_Mailbox__SHIFT 0x0
+#define ACP_FUTURE_REG_SCLK_0__ACPFutureReg_MASK 0xffffffff
+#define ACP_FUTURE_REG_SCLK_0__ACPFutureReg__SHIFT 0x0
+#define ACP_FUTURE_REG_SCLK_1__ACPFutureReg_MASK 0xffffffff
+#define ACP_FUTURE_REG_SCLK_1__ACPFutureReg__SHIFT 0x0
+#define ACP_FUTURE_REG_SCLK_2__ACPFutureReg_MASK 0xffffffff
+#define ACP_FUTURE_REG_SCLK_2__ACPFutureReg__SHIFT 0x0
+#define ACP_FUTURE_REG_SCLK_3__ACPFutureReg_MASK 0xffffffff
+#define ACP_FUTURE_REG_SCLK_3__ACPFutureReg__SHIFT 0x0
+#define ACP_FUTURE_REG_SCLK_4__ACPFutureReg_MASK 0xffffffff
+#define ACP_FUTURE_REG_SCLK_4__ACPFutureReg__SHIFT 0x0
+#define ACP_DAGB_DEBUG_CNT_ENABLE__garlic_wr_ask_cnt_enable_MASK 0x1
+#define ACP_DAGB_DEBUG_CNT_ENABLE__garlic_wr_ask_cnt_enable__SHIFT 0x0
+#define ACP_DAGB_DEBUG_CNT_ENABLE__garlic_wr_go_cnt_enable_MASK 0x2
+#define ACP_DAGB_DEBUG_CNT_ENABLE__garlic_wr_go_cnt_enable__SHIFT 0x1
+#define ACP_DAGB_DEBUG_CNT_ENABLE__garlic_wr_exp_respcnt_enable_MASK 0x4
+#define ACP_DAGB_DEBUG_CNT_ENABLE__garlic_wr_exp_respcnt_enable__SHIFT 0x2
+#define ACP_DAGB_DEBUG_CNT_ENABLE__garlic_wr_actual_respcnt_enable_MASK 0x8
+#define ACP_DAGB_DEBUG_CNT_ENABLE__garlic_wr_actual_respcnt_enable__SHIFT 0x3
+#define ACP_DAGB_DEBUG_CNT_ENABLE__garlic_rd_ask_cnt_enable_MASK 0x10
+#define ACP_DAGB_DEBUG_CNT_ENABLE__garlic_rd_ask_cnt_enable__SHIFT 0x4
+#define ACP_DAGB_DEBUG_CNT_ENABLE__garlic_rd_go_cnt_enable_MASK 0x20
+#define ACP_DAGB_DEBUG_CNT_ENABLE__garlic_rd_go_cnt_enable__SHIFT 0x5
+#define ACP_DAGB_DEBUG_CNT_ENABLE__garlic_rd_exp_respcnt_enable_MASK 0x40
+#define ACP_DAGB_DEBUG_CNT_ENABLE__garlic_rd_exp_respcnt_enable__SHIFT 0x6
+#define ACP_DAGB_DEBUG_CNT_ENABLE__garlic_rd_actual_respcnt_enable_MASK 0x80
+#define ACP_DAGB_DEBUG_CNT_ENABLE__garlic_rd_actual_respcnt_enable__SHIFT 0x7
+#define ACP_DAGB_DEBUG_CNT_ENABLE__onion_wr_ask_cnt_enable_MASK 0x100
+#define ACP_DAGB_DEBUG_CNT_ENABLE__onion_wr_ask_cnt_enable__SHIFT 0x8
+#define ACP_DAGB_DEBUG_CNT_ENABLE__onion_wr_go_cnt_enable_MASK 0x200
+#define ACP_DAGB_DEBUG_CNT_ENABLE__onion_wr_go_cnt_enable__SHIFT 0x9
+#define ACP_DAGB_DEBUG_CNT_ENABLE__onion_wr_exp_respcnt_enable_MASK 0x400
+#define ACP_DAGB_DEBUG_CNT_ENABLE__onion_wr_exp_respcnt_enable__SHIFT 0xa
+#define ACP_DAGB_DEBUG_CNT_ENABLE__onion_wr_actual_respcnt_enable_MASK 0x800
+#define ACP_DAGB_DEBUG_CNT_ENABLE__onion_wr_actual_respcnt_enable__SHIFT 0xb
+#define ACP_DAGB_DEBUG_CNT_ENABLE__onion_rd_ask_cnt_enable_MASK 0x1000
+#define ACP_DAGB_DEBUG_CNT_ENABLE__onion_rd_ask_cnt_enable__SHIFT 0xc
+#define ACP_DAGB_DEBUG_CNT_ENABLE__onion_rd_go_cnt_enable_MASK 0x2000
+#define ACP_DAGB_DEBUG_CNT_ENABLE__onion_rd_go_cnt_enable__SHIFT 0xd
+#define ACP_DAGB_DEBUG_CNT_ENABLE__onion_rd_exp_respcnt_enable_MASK 0x4000
+#define ACP_DAGB_DEBUG_CNT_ENABLE__onion_rd_exp_respcnt_enable__SHIFT 0xe
+#define ACP_DAGB_DEBUG_CNT_ENABLE__onion_rd_actual_respcnt_enable_MASK 0x8000
+#define ACP_DAGB_DEBUG_CNT_ENABLE__onion_rd_actual_respcnt_enable__SHIFT 0xf
+#define ACP_DAGBG_WR_ASK_CNT__garlic_wr_only_ask_cnt_MASK 0xffff
+#define ACP_DAGBG_WR_ASK_CNT__garlic_wr_only_ask_cnt__SHIFT 0x0
+#define ACP_DAGBG_WR_GO_CNT__garlic_wr_only_go_cnt_MASK 0xffff
+#define ACP_DAGBG_WR_GO_CNT__garlic_wr_only_go_cnt__SHIFT 0x0
+#define ACP_DAGBG_WR_EXP_RESP_CNT__garlic_wr_exp_resp_cnt_MASK 0xffff
+#define ACP_DAGBG_WR_EXP_RESP_CNT__garlic_wr_exp_resp_cnt__SHIFT 0x0
+#define ACP_DAGBG_WR_ACTUAL_RESP_CNT__garlic_wr_actual_resp_cnt_MASK 0xffff
+#define ACP_DAGBG_WR_ACTUAL_RESP_CNT__garlic_wr_actual_resp_cnt__SHIFT 0x0
+#define ACP_DAGBG_RD_ASK_CNT__garlic_rd_only_ask_cnt_MASK 0xffff
+#define ACP_DAGBG_RD_ASK_CNT__garlic_rd_only_ask_cnt__SHIFT 0x0
+#define ACP_DAGBG_RD_GO_CNT__garlic_rd_only_go_cnt_MASK 0xffff
+#define ACP_DAGBG_RD_GO_CNT__garlic_rd_only_go_cnt__SHIFT 0x0
+#define ACP_DAGBG_RD_EXP_RESP_CNT__garlic_rd_exp_resp_cnt_MASK 0xffff
+#define ACP_DAGBG_RD_EXP_RESP_CNT__garlic_rd_exp_resp_cnt__SHIFT 0x0
+#define ACP_DAGBG_RD_ACTUAL_RESP_CNT__garlic_rd_actual_resp_cnt_MASK 0xffff
+#define ACP_DAGBG_RD_ACTUAL_RESP_CNT__garlic_rd_actual_resp_cnt__SHIFT 0x0
+#define ACP_DAGBO_WR_ASK_CNT__onion_wr_only_ask_cnt_MASK 0xffff
+#define ACP_DAGBO_WR_ASK_CNT__onion_wr_only_ask_cnt__SHIFT 0x0
+#define ACP_DAGBO_WR_GO_CNT__onion_wr_only_go_cnt_MASK 0xffff
+#define ACP_DAGBO_WR_GO_CNT__onion_wr_only_go_cnt__SHIFT 0x0
+#define ACP_DAGBO_WR_EXP_RESP_CNT__onion_wr_exp_resp_cnt_MASK 0xffff
+#define ACP_DAGBO_WR_EXP_RESP_CNT__onion_wr_exp_resp_cnt__SHIFT 0x0
+#define ACP_DAGBO_WR_ACTUAL_RESP_CNT__onion_wr_actual_resp_cnt_MASK 0xffff
+#define ACP_DAGBO_WR_ACTUAL_RESP_CNT__onion_wr_actual_resp_cnt__SHIFT 0x0
+#define ACP_DAGBO_RD_ASK_CNT__onion_rd_only_ask_cnt_MASK 0xffff
+#define ACP_DAGBO_RD_ASK_CNT__onion_rd_only_ask_cnt__SHIFT 0x0
+#define ACP_DAGBO_RD_GO_CNT__onion_rd_only_go_cnt_MASK 0xffff
+#define ACP_DAGBO_RD_GO_CNT__onion_rd_only_go_cnt__SHIFT 0x0
+#define ACP_DAGBO_RD_EXP_RESP_CNT__onion_rd_exp_resp_cnt_MASK 0xffff
+#define ACP_DAGBO_RD_EXP_RESP_CNT__onion_rd_exp_resp_cnt__SHIFT 0x0
+#define ACP_DAGBO_RD_ACTUAL_RESP_CNT__onion_rd_actual_resp_cnt_MASK 0xffff
+#define ACP_DAGBO_RD_ACTUAL_RESP_CNT__onion_rd_actual_resp_cnt__SHIFT 0x0
+#define ACP_BRB_CONTROL__BRB_BlockSharedRAMArbCntrl_MASK 0xf
+#define ACP_BRB_CONTROL__BRB_BlockSharedRAMArbCntrl__SHIFT 0x0
+#define ACP_EXTERNAL_INTR_ENB__ACPExtIntrEnb_MASK 0x1
+#define ACP_EXTERNAL_INTR_ENB__ACPExtIntrEnb__SHIFT 0x0
+#define ACP_EXTERNAL_INTR_CNTL__ACPErrMask_MASK 0x1
+#define ACP_EXTERNAL_INTR_CNTL__ACPErrMask__SHIFT 0x0
+#define ACP_EXTERNAL_INTR_CNTL__I2SMicDataAvMask_MASK 0x2
+#define ACP_EXTERNAL_INTR_CNTL__I2SMicDataAvMask__SHIFT 0x1
+#define ACP_EXTERNAL_INTR_CNTL__I2SSpkr0DataEmptyMask_MASK 0x4
+#define ACP_EXTERNAL_INTR_CNTL__I2SSpkr0DataEmptyMask__SHIFT 0x2
+#define ACP_EXTERNAL_INTR_CNTL__I2SSpkr1DataEmptyMask_MASK 0x8
+#define ACP_EXTERNAL_INTR_CNTL__I2SSpkr1DataEmptyMask__SHIFT 0x3
+#define ACP_EXTERNAL_INTR_CNTL__I2SBTDataAvMask_MASK 0x10
+#define ACP_EXTERNAL_INTR_CNTL__I2SBTDataAvMask__SHIFT 0x4
+#define ACP_EXTERNAL_INTR_CNTL__AzaliaIntrMask_MASK 0x40
+#define ACP_EXTERNAL_INTR_CNTL__AzaliaIntrMask__SHIFT 0x6
+#define ACP_EXTERNAL_INTR_CNTL__DSP0TimeoutMask_MASK 0x100
+#define ACP_EXTERNAL_INTR_CNTL__DSP0TimeoutMask__SHIFT 0x8
+#define ACP_EXTERNAL_INTR_CNTL__DSP1TimeoutMask_MASK 0x200
+#define ACP_EXTERNAL_INTR_CNTL__DSP1TimeoutMask__SHIFT 0x9
+#define ACP_EXTERNAL_INTR_CNTL__DSP2TimeoutMask_MASK 0x400
+#define ACP_EXTERNAL_INTR_CNTL__DSP2TimeoutMask__SHIFT 0xa
+#define ACP_EXTERNAL_INTR_CNTL__I2SBTDataEmptyMask_MASK 0x800
+#define ACP_EXTERNAL_INTR_CNTL__I2SBTDataEmptyMask__SHIFT 0xb
+#define ACP_EXTERNAL_INTR_CNTL__DMAIOCMask_MASK 0xffff0000
+#define ACP_EXTERNAL_INTR_CNTL__DMAIOCMask__SHIFT 0x10
+#define ACP_ERROR_SOURCE_STS__ACPRegUdefADDRErr_MASK 0x1
+#define ACP_ERROR_SOURCE_STS__ACPRegUdefADDRErr__SHIFT 0x0
+#define ACP_ERROR_SOURCE_STS__ACPRegUdefADDRErrSource_MASK 0xe
+#define ACP_ERROR_SOURCE_STS__ACPRegUdefADDRErrSource__SHIFT 0x1
+#define ACP_ERROR_SOURCE_STS__ACPRegUdefADDRErrSourceOver_MASK 0x10
+#define ACP_ERROR_SOURCE_STS__ACPRegUdefADDRErrSourceOver__SHIFT 0x4
+#define ACP_ERROR_SOURCE_STS__BRBAddrErr_MASK 0x20
+#define ACP_ERROR_SOURCE_STS__BRBAddrErr__SHIFT 0x5
+#define ACP_ERROR_SOURCE_STS__BRBAddrErrSource_MASK 0x3c0
+#define ACP_ERROR_SOURCE_STS__BRBAddrErrSource__SHIFT 0x6
+#define ACP_ERROR_SOURCE_STS__BRBAddrErrSourceOver_MASK 0x400
+#define ACP_ERROR_SOURCE_STS__BRBAddrErrSourceOver__SHIFT 0xa
+#define ACP_ERROR_SOURCE_STS__I2SMicOverFlowErr_MASK 0x800
+#define ACP_ERROR_SOURCE_STS__I2SMicOverFlowErr__SHIFT 0xb
+#define ACP_ERROR_SOURCE_STS__I2SSpeaker0OverFlowErr_MASK 0x1000
+#define ACP_ERROR_SOURCE_STS__I2SSpeaker0OverFlowErr__SHIFT 0xc
+#define ACP_ERROR_SOURCE_STS__I2SSpeaker1OverFlowErr_MASK 0x2000
+#define ACP_ERROR_SOURCE_STS__I2SSpeaker1OverFlowErr__SHIFT 0xd
+#define ACP_ERROR_SOURCE_STS__I2SBTRxFifoOverFlowErr_MASK 0x4000
+#define ACP_ERROR_SOURCE_STS__I2SBTRxFifoOverFlowErr__SHIFT 0xe
+#define ACP_ERROR_SOURCE_STS__DSPAdrTransRangeErr_MASK 0x8000
+#define ACP_ERROR_SOURCE_STS__DSPAdrTransRangeErr__SHIFT 0xf
+#define ACP_ERROR_SOURCE_STS__DSPAdrTransRangeErrSource_MASK 0x70000
+#define ACP_ERROR_SOURCE_STS__DSPAdrTransRangeErrSource__SHIFT 0x10
+#define ACP_ERROR_SOURCE_STS__DSPAdrTransRangeErrSourceOver_MASK 0x80000
+#define ACP_ERROR_SOURCE_STS__DSPAdrTransRangeErrSourceOver__SHIFT 0x13
+#define ACP_ERROR_SOURCE_STS__DAGBErr_MASK 0x100000
+#define ACP_ERROR_SOURCE_STS__DAGBErr__SHIFT 0x14
+#define ACP_ERROR_SOURCE_STS__DAGBErrSource_MASK 0x1e00000
+#define ACP_ERROR_SOURCE_STS__DAGBErrSource__SHIFT 0x15
+#define ACP_ERROR_SOURCE_STS__DAGBErrSourceOver_MASK 0x2000000
+#define ACP_ERROR_SOURCE_STS__DAGBErrSourceOver__SHIFT 0x19
+#define ACP_ERROR_SOURCE_STS__DMATermOnErr_MASK 0x4000000
+#define ACP_ERROR_SOURCE_STS__DMATermOnErr__SHIFT 0x1a
+#define ACP_ERROR_SOURCE_STS__I2SBTTxFifoOverFlowErr_MASK 0x10000000
+#define ACP_ERROR_SOURCE_STS__I2SBTTxFifoOverFlowErr__SHIFT 0x1c
+#define ACP_DSP_SW_INTR_TRIG__TrigSWIntHostDSP0_MASK 0x1
+#define ACP_DSP_SW_INTR_TRIG__TrigSWIntHostDSP0__SHIFT 0x0
+#define ACP_DSP_SW_INTR_TRIG__TrigSWIntHostDSP1_MASK 0x2
+#define ACP_DSP_SW_INTR_TRIG__TrigSWIntHostDSP1__SHIFT 0x1
+#define ACP_DSP_SW_INTR_TRIG__TrigSWIntHostDSP2_MASK 0x4
+#define ACP_DSP_SW_INTR_TRIG__TrigSWIntHostDSP2__SHIFT 0x2
+#define ACP_DSP_SW_INTR_TRIG__TrigSWIntDSPnDSP0_MASK 0x100
+#define ACP_DSP_SW_INTR_TRIG__TrigSWIntDSPnDSP0__SHIFT 0x8
+#define ACP_DSP_SW_INTR_TRIG__TrigSWIntDSPnDSP1_MASK 0x200
+#define ACP_DSP_SW_INTR_TRIG__TrigSWIntDSPnDSP1__SHIFT 0x9
+#define ACP_DSP_SW_INTR_TRIG__TrigSWIntDSPnDSP2_MASK 0x400
+#define ACP_DSP_SW_INTR_TRIG__TrigSWIntDSPnDSP2__SHIFT 0xa
+#define ACP_DSP_SW_INTR_TRIG__TrigSWIntDSP0Host_MASK 0x10000
+#define ACP_DSP_SW_INTR_TRIG__TrigSWIntDSP0Host__SHIFT 0x10
+#define ACP_DSP_SW_INTR_TRIG__TrigSWIntDSP1Host_MASK 0x20000
+#define ACP_DSP_SW_INTR_TRIG__TrigSWIntDSP1Host__SHIFT 0x11
+#define ACP_DSP_SW_INTR_TRIG__TrigSWIntDSP2Host_MASK 0x40000
+#define ACP_DSP_SW_INTR_TRIG__TrigSWIntDSP2Host__SHIFT 0x12
+#define ACP_DSP_SW_INTR_CNTL__EnbSWIntHostDSP0_MASK 0x1
+#define ACP_DSP_SW_INTR_CNTL__EnbSWIntHostDSP0__SHIFT 0x0
+#define ACP_DSP_SW_INTR_CNTL__EnbSWIntHostDSP1_MASK 0x2
+#define ACP_DSP_SW_INTR_CNTL__EnbSWIntHostDSP1__SHIFT 0x1
+#define ACP_DSP_SW_INTR_CNTL__EnbSWIntHostDSP2_MASK 0x4
+#define ACP_DSP_SW_INTR_CNTL__EnbSWIntHostDSP2__SHIFT 0x2
+#define ACP_DSP_SW_INTR_CNTL__EnbSWIntDSPnDSP0_MASK 0x100
+#define ACP_DSP_SW_INTR_CNTL__EnbSWIntDSPnDSP0__SHIFT 0x8
+#define ACP_DSP_SW_INTR_CNTL__EnbSWIntDSPnDSP1_MASK 0x200
+#define ACP_DSP_SW_INTR_CNTL__EnbSWIntDSPnDSP1__SHIFT 0x9
+#define ACP_DSP_SW_INTR_CNTL__EnbSWIntDSPnDSP2_MASK 0x400
+#define ACP_DSP_SW_INTR_CNTL__EnbSWIntDSPnDSP2__SHIFT 0xa
+#define ACP_DSP_SW_INTR_CNTL__EnbKernelIntrDSP0Mask_MASK 0x10000
+#define ACP_DSP_SW_INTR_CNTL__EnbKernelIntrDSP0Mask__SHIFT 0x10
+#define ACP_DSP_SW_INTR_CNTL__EmbKernelIntrDSP1Mask_MASK 0x20000
+#define ACP_DSP_SW_INTR_CNTL__EmbKernelIntrDSP1Mask__SHIFT 0x11
+#define ACP_DSP_SW_INTR_CNTL__EmbKernelIntrDSP2Mask_MASK 0x40000
+#define ACP_DSP_SW_INTR_CNTL__EmbKernelIntrDSP2Mask__SHIFT 0x12
+#define ACP_DAGBG_TIMEOUT_CNTL__DAGBGTimeoutValue_MASK 0x3ffff
+#define ACP_DAGBG_TIMEOUT_CNTL__DAGBGTimeoutValue__SHIFT 0x0
+#define ACP_DAGBG_TIMEOUT_CNTL__CntEn_MASK 0x80000000
+#define ACP_DAGBG_TIMEOUT_CNTL__CntEn__SHIFT 0x1f
+#define ACP_DAGBO_TIMEOUT_CNTL__DAGBOTimeoutValue_MASK 0x3ffff
+#define ACP_DAGBO_TIMEOUT_CNTL__DAGBOTimeoutValue__SHIFT 0x0
+#define ACP_DAGBO_TIMEOUT_CNTL__CntEn_MASK 0x80000000
+#define ACP_DAGBO_TIMEOUT_CNTL__CntEn__SHIFT 0x1f
+#define ACP_EXTERNAL_INTR_STAT__ACPErrStat_MASK 0x1
+#define ACP_EXTERNAL_INTR_STAT__ACPErrStat__SHIFT 0x0
+#define ACP_EXTERNAL_INTR_STAT__ACPErrAck_MASK 0x1
+#define ACP_EXTERNAL_INTR_STAT__ACPErrAck__SHIFT 0x0
+#define ACP_EXTERNAL_INTR_STAT__I2SMicDataAvStat_MASK 0x2
+#define ACP_EXTERNAL_INTR_STAT__I2SMicDataAvStat__SHIFT 0x1
+#define ACP_EXTERNAL_INTR_STAT__I2SMicDataAvAck_MASK 0x2
+#define ACP_EXTERNAL_INTR_STAT__I2SMicDataAvAck__SHIFT 0x1
+#define ACP_EXTERNAL_INTR_STAT__I2SSpkr0DataEmptyStat_MASK 0x4
+#define ACP_EXTERNAL_INTR_STAT__I2SSpkr0DataEmptyStat__SHIFT 0x2
+#define ACP_EXTERNAL_INTR_STAT__I2SSpkr0DataEmptyAck_MASK 0x4
+#define ACP_EXTERNAL_INTR_STAT__I2SSpkr0DataEmptyAck__SHIFT 0x2
+#define ACP_EXTERNAL_INTR_STAT__I2SSpkr1DataEmptyStat_MASK 0x8
+#define ACP_EXTERNAL_INTR_STAT__I2SSpkr1DataEmptyStat__SHIFT 0x3
+#define ACP_EXTERNAL_INTR_STAT__I2SSpkr1DataEmptyAck_MASK 0x8
+#define ACP_EXTERNAL_INTR_STAT__I2SSpkr1DataEmptyAck__SHIFT 0x3
+#define ACP_EXTERNAL_INTR_STAT__I2SBTDataAvStat_MASK 0x10
+#define ACP_EXTERNAL_INTR_STAT__I2SBTDataAvStat__SHIFT 0x4
+#define ACP_EXTERNAL_INTR_STAT__I2SBTDataAvAck_MASK 0x10
+#define ACP_EXTERNAL_INTR_STAT__I2SBTDataAvAck__SHIFT 0x4
+#define ACP_EXTERNAL_INTR_STAT__AzaliaIntrStat_MASK 0x40
+#define ACP_EXTERNAL_INTR_STAT__AzaliaIntrStat__SHIFT 0x6
+#define ACP_EXTERNAL_INTR_STAT__AzaliaIntrAck_MASK 0x40
+#define ACP_EXTERNAL_INTR_STAT__AzaliaIntrAck__SHIFT 0x6
+#define ACP_EXTERNAL_INTR_STAT__DSP0TimeoutStat_MASK 0x100
+#define ACP_EXTERNAL_INTR_STAT__DSP0TimeoutStat__SHIFT 0x8
+#define ACP_EXTERNAL_INTR_STAT__DSP0TimeoutAck_MASK 0x100
+#define ACP_EXTERNAL_INTR_STAT__DSP0TimeoutAck__SHIFT 0x8
+#define ACP_EXTERNAL_INTR_STAT__DSP1TimeoutStat_MASK 0x200
+#define ACP_EXTERNAL_INTR_STAT__DSP1TimeoutStat__SHIFT 0x9
+#define ACP_EXTERNAL_INTR_STAT__DSP1TimeoutAck_MASK 0x200
+#define ACP_EXTERNAL_INTR_STAT__DSP1TimeoutAck__SHIFT 0x9
+#define ACP_EXTERNAL_INTR_STAT__DSP2TimeoutStat_MASK 0x400
+#define ACP_EXTERNAL_INTR_STAT__DSP2TimeoutStat__SHIFT 0xa
+#define ACP_EXTERNAL_INTR_STAT__DSP2TimeoutAck_MASK 0x400
+#define ACP_EXTERNAL_INTR_STAT__DSP2TimeoutAck__SHIFT 0xa
+#define ACP_EXTERNAL_INTR_STAT__I2SBTDataEmptyStat_MASK 0x800
+#define ACP_EXTERNAL_INTR_STAT__I2SBTDataEmptyStat__SHIFT 0xb
+#define ACP_EXTERNAL_INTR_STAT__I2SBTDataEmptyAck_MASK 0x800
+#define ACP_EXTERNAL_INTR_STAT__I2SBTDataEmptyAck__SHIFT 0xb
+#define ACP_EXTERNAL_INTR_STAT__DMAIOCStat_MASK 0xffff0000
+#define ACP_EXTERNAL_INTR_STAT__DMAIOCStat__SHIFT 0x10
+#define ACP_EXTERNAL_INTR_STAT__DMAIOCAck_MASK 0xffff0000
+#define ACP_EXTERNAL_INTR_STAT__DMAIOCAck__SHIFT 0x10
+#define ACP_DSP_SW_INTR_STAT__SWIntHostDSP0Stat_MASK 0x1
+#define ACP_DSP_SW_INTR_STAT__SWIntHostDSP0Stat__SHIFT 0x0
+#define ACP_DSP_SW_INTR_STAT__SWIntHostDSP0Ack_MASK 0x1
+#define ACP_DSP_SW_INTR_STAT__SWIntHostDSP0Ack__SHIFT 0x0
+#define ACP_DSP_SW_INTR_STAT__SWIntHostDSP1Stat_MASK 0x2
+#define ACP_DSP_SW_INTR_STAT__SWIntHostDSP1Stat__SHIFT 0x1
+#define ACP_DSP_SW_INTR_STAT__SWIntHostDSP1Ack_MASK 0x2
+#define ACP_DSP_SW_INTR_STAT__SWIntHostDSP1Ack__SHIFT 0x1
+#define ACP_DSP_SW_INTR_STAT__SWIntHostDSP2Stat_MASK 0x4
+#define ACP_DSP_SW_INTR_STAT__SWIntHostDSP2Stat__SHIFT 0x2
+#define ACP_DSP_SW_INTR_STAT__SWIntHostDSP2Ack_MASK 0x4
+#define ACP_DSP_SW_INTR_STAT__SWIntHostDSP2Ack__SHIFT 0x2
+#define ACP_DSP_SW_INTR_STAT__SWIntDSPnDSP0Stat_MASK 0x100
+#define ACP_DSP_SW_INTR_STAT__SWIntDSPnDSP0Stat__SHIFT 0x8
+#define ACP_DSP_SW_INTR_STAT__SWIntDSPnDSP0Ack_MASK 0x100
+#define ACP_DSP_SW_INTR_STAT__SWIntDSPnDSP0Ack__SHIFT 0x8
+#define ACP_DSP_SW_INTR_STAT__SWIntDSPnDSP1Stat_MASK 0x200
+#define ACP_DSP_SW_INTR_STAT__SWIntDSPnDSP1Stat__SHIFT 0x9
+#define ACP_DSP_SW_INTR_STAT__SWIntDSPnDSP1Ack_MASK 0x200
+#define ACP_DSP_SW_INTR_STAT__SWIntDSPnDSP1Ack__SHIFT 0x9
+#define ACP_DSP_SW_INTR_STAT__SWIntDSPnDSP2Stat_MASK 0x400
+#define ACP_DSP_SW_INTR_STAT__SWIntDSPnDSP2Stat__SHIFT 0xa
+#define ACP_DSP_SW_INTR_STAT__SWIntDSPnDSP2Ack_MASK 0x400
+#define ACP_DSP_SW_INTR_STAT__SWIntDSPnDSP2Ack__SHIFT 0xa
+#define ACP_DSP_SW_INTR_STAT__SWKernelIntrDSP0Stat_MASK 0x10000
+#define ACP_DSP_SW_INTR_STAT__SWKernelIntrDSP0Stat__SHIFT 0x10
+#define ACP_DSP_SW_INTR_STAT__SWKernelIntrDSP0Ack_MASK 0x10000
+#define ACP_DSP_SW_INTR_STAT__SWKernelIntrDSP0Ack__SHIFT 0x10
+#define ACP_DSP_SW_INTR_STAT__SWKernelIntrDSP1Stat_MASK 0x20000
+#define ACP_DSP_SW_INTR_STAT__SWKernelIntrDSP1Stat__SHIFT 0x11
+#define ACP_DSP_SW_INTR_STAT__SWKernelIntrDSP1Ack_MASK 0x20000
+#define ACP_DSP_SW_INTR_STAT__SWKernelIntrDSP1Ack__SHIFT 0x11
+#define ACP_DSP_SW_INTR_STAT__SWKernelIntrDSP2Stat_MASK 0x40000
+#define ACP_DSP_SW_INTR_STAT__SWKernelIntrDSP2Stat__SHIFT 0x12
+#define ACP_DSP_SW_INTR_STAT__SWKernelIntrDSP2Ack_MASK 0x40000
+#define ACP_DSP_SW_INTR_STAT__SWKernelIntrDSP2Ack__SHIFT 0x12
+#define ACP_DSP0_INTR_CNTL__ACPErrMask_MASK 0x1
+#define ACP_DSP0_INTR_CNTL__ACPErrMask__SHIFT 0x0
+#define ACP_DSP0_INTR_CNTL__I2SMicDataAvMask_MASK 0x2
+#define ACP_DSP0_INTR_CNTL__I2SMicDataAvMask__SHIFT 0x1
+#define ACP_DSP0_INTR_CNTL__I2SSpkr0DataEmptyMask_MASK 0x4
+#define ACP_DSP0_INTR_CNTL__I2SSpkr0DataEmptyMask__SHIFT 0x2
+#define ACP_DSP0_INTR_CNTL__I2SSpkr1DataEmptyMask_MASK 0x8
+#define ACP_DSP0_INTR_CNTL__I2SSpkr1DataEmptyMask__SHIFT 0x3
+#define ACP_DSP0_INTR_CNTL__I2SBTDataAvMask_MASK 0x10
+#define ACP_DSP0_INTR_CNTL__I2SBTDataAvMask__SHIFT 0x4
+#define ACP_DSP0_INTR_CNTL__AzaliaIntrMask_MASK 0x40
+#define ACP_DSP0_INTR_CNTL__AzaliaIntrMask__SHIFT 0x6
+#define ACP_DSP0_INTR_CNTL__SMUMailboxWriteMask_MASK 0x100
+#define ACP_DSP0_INTR_CNTL__SMUMailboxWriteMask__SHIFT 0x8
+#define ACP_DSP0_INTR_CNTL__SMUStutterStatusMask_MASK 0x200
+#define ACP_DSP0_INTR_CNTL__SMUStutterStatusMask__SHIFT 0x9
+#define ACP_DSP0_INTR_CNTL__MCStutterStatusMask_MASK 0x400
+#define ACP_DSP0_INTR_CNTL__MCStutterStatusMask__SHIFT 0xa
+#define ACP_DSP0_INTR_CNTL__DSPExtTimerMask_MASK 0x800
+#define ACP_DSP0_INTR_CNTL__DSPExtTimerMask__SHIFT 0xb
+#define ACP_DSP0_INTR_CNTL__DSPSemRespMask_MASK 0x1000
+#define ACP_DSP0_INTR_CNTL__DSPSemRespMask__SHIFT 0xc
+#define ACP_DSP0_INTR_CNTL__I2SBTDataEmptyMask_MASK 0x2000
+#define ACP_DSP0_INTR_CNTL__I2SBTDataEmptyMask__SHIFT 0xd
+#define ACP_DSP0_INTR_CNTL__DMAIOCMask_MASK 0xffff0000
+#define ACP_DSP0_INTR_CNTL__DMAIOCMask__SHIFT 0x10
+#define ACP_DSP0_INTR_STAT__ACPErrStat_MASK 0x1
+#define ACP_DSP0_INTR_STAT__ACPErrStat__SHIFT 0x0
+#define ACP_DSP0_INTR_STAT__ACPErrAck_MASK 0x1
+#define ACP_DSP0_INTR_STAT__ACPErrAck__SHIFT 0x0
+#define ACP_DSP0_INTR_STAT__I2SMicDataAvStat_MASK 0x2
+#define ACP_DSP0_INTR_STAT__I2SMicDataAvStat__SHIFT 0x1
+#define ACP_DSP0_INTR_STAT__I2SMicDataAvAck_MASK 0x2
+#define ACP_DSP0_INTR_STAT__I2SMicDataAvAck__SHIFT 0x1
+#define ACP_DSP0_INTR_STAT__I2SSpkr0DataEmptyStat_MASK 0x4
+#define ACP_DSP0_INTR_STAT__I2SSpkr0DataEmptyStat__SHIFT 0x2
+#define ACP_DSP0_INTR_STAT__I2SSpkr0DataEmptyAck_MASK 0x4
+#define ACP_DSP0_INTR_STAT__I2SSpkr0DataEmptyAck__SHIFT 0x2
+#define ACP_DSP0_INTR_STAT__I2SSpkr1DataEmptyStat_MASK 0x8
+#define ACP_DSP0_INTR_STAT__I2SSpkr1DataEmptyStat__SHIFT 0x3
+#define ACP_DSP0_INTR_STAT__I2SSpkr1DataEmptyAck_MASK 0x8
+#define ACP_DSP0_INTR_STAT__I2SSpkr1DataEmptyAck__SHIFT 0x3
+#define ACP_DSP0_INTR_STAT__I2SBTDataAvStat_MASK 0x10
+#define ACP_DSP0_INTR_STAT__I2SBTDataAvStat__SHIFT 0x4
+#define ACP_DSP0_INTR_STAT__I2SBTDataAvAck_MASK 0x10
+#define ACP_DSP0_INTR_STAT__I2SBTDataAvAck__SHIFT 0x4
+#define ACP_DSP0_INTR_STAT__AzaliaIntrStat_MASK 0x40
+#define ACP_DSP0_INTR_STAT__AzaliaIntrStat__SHIFT 0x6
+#define ACP_DSP0_INTR_STAT__AzaliaIntrAck_MASK 0x40
+#define ACP_DSP0_INTR_STAT__AzaliaIntrAck__SHIFT 0x6
+#define ACP_DSP0_INTR_STAT__SMUMailboxWriteStat_MASK 0x100
+#define ACP_DSP0_INTR_STAT__SMUMailboxWriteStat__SHIFT 0x8
+#define ACP_DSP0_INTR_STAT__SMUMailboxWriteAck_MASK 0x100
+#define ACP_DSP0_INTR_STAT__SMUMailboxWriteAck__SHIFT 0x8
+#define ACP_DSP0_INTR_STAT__SMUStutterStatusStat_MASK 0x200
+#define ACP_DSP0_INTR_STAT__SMUStutterStatusStat__SHIFT 0x9
+#define ACP_DSP0_INTR_STAT__SMUStutterStatusAck_MASK 0x200
+#define ACP_DSP0_INTR_STAT__SMUStutterStatusAck__SHIFT 0x9
+#define ACP_DSP0_INTR_STAT__MCStutterStatusStat_MASK 0x400
+#define ACP_DSP0_INTR_STAT__MCStutterStatusStat__SHIFT 0xa
+#define ACP_DSP0_INTR_STAT__MCStutterStatusAck_MASK 0x400
+#define ACP_DSP0_INTR_STAT__MCStutterStatusAck__SHIFT 0xa
+#define ACP_DSP0_INTR_STAT__DSPExtTimerStat_MASK 0x800
+#define ACP_DSP0_INTR_STAT__DSPExtTimerStat__SHIFT 0xb
+#define ACP_DSP0_INTR_STAT__DSPExtTimerAck_MASK 0x800
+#define ACP_DSP0_INTR_STAT__DSPExtTimerAck__SHIFT 0xb
+#define ACP_DSP0_INTR_STAT__DSPSemRespStat_MASK 0x1000
+#define ACP_DSP0_INTR_STAT__DSPSemRespStat__SHIFT 0xc
+#define ACP_DSP0_INTR_STAT__DSPSemRespAck_MASK 0x1000
+#define ACP_DSP0_INTR_STAT__DSPSemRespAck__SHIFT 0xc
+#define ACP_DSP0_INTR_STAT__I2SBTDataEmptyStat_MASK 0x2000
+#define ACP_DSP0_INTR_STAT__I2SBTDataEmptyStat__SHIFT 0xd
+#define ACP_DSP0_INTR_STAT__I2SBTDataEmptyAck_MASK 0x2000
+#define ACP_DSP0_INTR_STAT__I2SBTDataEmptyAck__SHIFT 0xd
+#define ACP_DSP0_INTR_STAT__DMAIOCStat_MASK 0xffff0000
+#define ACP_DSP0_INTR_STAT__DMAIOCStat__SHIFT 0x10
+#define ACP_DSP0_INTR_STAT__DMAIOCAck_MASK 0xffff0000
+#define ACP_DSP0_INTR_STAT__DMAIOCAck__SHIFT 0x10
+#define ACP_DSP0_TIMEOUT_CNTL__DSP0TimeoutValue_MASK 0x3ffff
+#define ACP_DSP0_TIMEOUT_CNTL__DSP0TimeoutValue__SHIFT 0x0
+#define ACP_DSP0_TIMEOUT_CNTL__CntEn_MASK 0x80000000
+#define ACP_DSP0_TIMEOUT_CNTL__CntEn__SHIFT 0x1f
+#define ACP_DSP1_INTR_CNTL__ACPErrMask_MASK 0x1
+#define ACP_DSP1_INTR_CNTL__ACPErrMask__SHIFT 0x0
+#define ACP_DSP1_INTR_CNTL__I2SMicDataAvMask_MASK 0x2
+#define ACP_DSP1_INTR_CNTL__I2SMicDataAvMask__SHIFT 0x1
+#define ACP_DSP1_INTR_CNTL__I2SSpkr0DataEmptyMask_MASK 0x4
+#define ACP_DSP1_INTR_CNTL__I2SSpkr0DataEmptyMask__SHIFT 0x2
+#define ACP_DSP1_INTR_CNTL__I2SSpkr1DataEmptyMask_MASK 0x8
+#define ACP_DSP1_INTR_CNTL__I2SSpkr1DataEmptyMask__SHIFT 0x3
+#define ACP_DSP1_INTR_CNTL__I2SBTDataAvMask_MASK 0x10
+#define ACP_DSP1_INTR_CNTL__I2SBTDataAvMask__SHIFT 0x4
+#define ACP_DSP1_INTR_CNTL__AzaliaIntrMask_MASK 0x40
+#define ACP_DSP1_INTR_CNTL__AzaliaIntrMask__SHIFT 0x6
+#define ACP_DSP1_INTR_CNTL__SMUMailboxWriteMask_MASK 0x100
+#define ACP_DSP1_INTR_CNTL__SMUMailboxWriteMask__SHIFT 0x8
+#define ACP_DSP1_INTR_CNTL__SMUStutterStatusMask_MASK 0x200
+#define ACP_DSP1_INTR_CNTL__SMUStutterStatusMask__SHIFT 0x9
+#define ACP_DSP1_INTR_CNTL__MCStutterStatusMask_MASK 0x400
+#define ACP_DSP1_INTR_CNTL__MCStutterStatusMask__SHIFT 0xa
+#define ACP_DSP1_INTR_CNTL__DSPExtTimerMask_MASK 0x800
+#define ACP_DSP1_INTR_CNTL__DSPExtTimerMask__SHIFT 0xb
+#define ACP_DSP1_INTR_CNTL__DSPSemRespMask_MASK 0x1000
+#define ACP_DSP1_INTR_CNTL__DSPSemRespMask__SHIFT 0xc
+#define ACP_DSP1_INTR_CNTL__I2SBTDataEmptyMask_MASK 0x2000
+#define ACP_DSP1_INTR_CNTL__I2SBTDataEmptyMask__SHIFT 0xd
+#define ACP_DSP1_INTR_CNTL__DMAIOCMask_MASK 0xffff0000
+#define ACP_DSP1_INTR_CNTL__DMAIOCMask__SHIFT 0x10
+#define ACP_DSP1_INTR_STAT__ACPErrStat_MASK 0x1
+#define ACP_DSP1_INTR_STAT__ACPErrStat__SHIFT 0x0
+#define ACP_DSP1_INTR_STAT__ACPErrAck_MASK 0x1
+#define ACP_DSP1_INTR_STAT__ACPErrAck__SHIFT 0x0
+#define ACP_DSP1_INTR_STAT__I2SMicDataAvStat_MASK 0x2
+#define ACP_DSP1_INTR_STAT__I2SMicDataAvStat__SHIFT 0x1
+#define ACP_DSP1_INTR_STAT__I2SMicDataAvAck_MASK 0x2
+#define ACP_DSP1_INTR_STAT__I2SMicDataAvAck__SHIFT 0x1
+#define ACP_DSP1_INTR_STAT__I2SSpkr0DataEmptyStat_MASK 0x4
+#define ACP_DSP1_INTR_STAT__I2SSpkr0DataEmptyStat__SHIFT 0x2
+#define ACP_DSP1_INTR_STAT__I2SSpkr0DataEmptyAck_MASK 0x4
+#define ACP_DSP1_INTR_STAT__I2SSpkr0DataEmptyAck__SHIFT 0x2
+#define ACP_DSP1_INTR_STAT__I2SSpkr1DataEmptyStat_MASK 0x8
+#define ACP_DSP1_INTR_STAT__I2SSpkr1DataEmptyStat__SHIFT 0x3
+#define ACP_DSP1_INTR_STAT__I2SSpkr1DataEmptyAck_MASK 0x8
+#define ACP_DSP1_INTR_STAT__I2SSpkr1DataEmptyAck__SHIFT 0x3
+#define ACP_DSP1_INTR_STAT__I2SBTDataAvStat_MASK 0x10
+#define ACP_DSP1_INTR_STAT__I2SBTDataAvStat__SHIFT 0x4
+#define ACP_DSP1_INTR_STAT__I2SBTDataAvAck_MASK 0x10
+#define ACP_DSP1_INTR_STAT__I2SBTDataAvAck__SHIFT 0x4
+#define ACP_DSP1_INTR_STAT__AzaliaIntrStat_MASK 0x40
+#define ACP_DSP1_INTR_STAT__AzaliaIntrStat__SHIFT 0x6
+#define ACP_DSP1_INTR_STAT__AzaliaIntrAck_MASK 0x40
+#define ACP_DSP1_INTR_STAT__AzaliaIntrAck__SHIFT 0x6
+#define ACP_DSP1_INTR_STAT__SMUMailboxWriteStat_MASK 0x100
+#define ACP_DSP1_INTR_STAT__SMUMailboxWriteStat__SHIFT 0x8
+#define ACP_DSP1_INTR_STAT__SMUMailboxWriteAck_MASK 0x100
+#define ACP_DSP1_INTR_STAT__SMUMailboxWriteAck__SHIFT 0x8
+#define ACP_DSP1_INTR_STAT__SMUStutterStatusStat_MASK 0x200
+#define ACP_DSP1_INTR_STAT__SMUStutterStatusStat__SHIFT 0x9
+#define ACP_DSP1_INTR_STAT__SMUStutterStatusAck_MASK 0x200
+#define ACP_DSP1_INTR_STAT__SMUStutterStatusAck__SHIFT 0x9
+#define ACP_DSP1_INTR_STAT__MCStutterStatusStat_MASK 0x400
+#define ACP_DSP1_INTR_STAT__MCStutterStatusStat__SHIFT 0xa
+#define ACP_DSP1_INTR_STAT__MCStutterStatusAck_MASK 0x400
+#define ACP_DSP1_INTR_STAT__MCStutterStatusAck__SHIFT 0xa
+#define ACP_DSP1_INTR_STAT__DSPExtTimerStat_MASK 0x800
+#define ACP_DSP1_INTR_STAT__DSPExtTimerStat__SHIFT 0xb
+#define ACP_DSP1_INTR_STAT__DSPExtTimerAck_MASK 0x800
+#define ACP_DSP1_INTR_STAT__DSPExtTimerAck__SHIFT 0xb
+#define ACP_DSP1_INTR_STAT__DSPSemRespStat_MASK 0x1000
+#define ACP_DSP1_INTR_STAT__DSPSemRespStat__SHIFT 0xc
+#define ACP_DSP1_INTR_STAT__DSPSemRespAck_MASK 0x1000
+#define ACP_DSP1_INTR_STAT__DSPSemRespAck__SHIFT 0xc
+#define ACP_DSP1_INTR_STAT__I2SBTDataEmptyStat_MASK 0x2000
+#define ACP_DSP1_INTR_STAT__I2SBTDataEmptyStat__SHIFT 0xd
+#define ACP_DSP1_INTR_STAT__I2SBTDataEmptyAck_MASK 0x2000
+#define ACP_DSP1_INTR_STAT__I2SBTDataEmptyAck__SHIFT 0xd
+#define ACP_DSP1_INTR_STAT__DMAIOCStat_MASK 0xffff0000
+#define ACP_DSP1_INTR_STAT__DMAIOCStat__SHIFT 0x10
+#define ACP_DSP1_INTR_STAT__DMAIOCAck_MASK 0xffff0000
+#define ACP_DSP1_INTR_STAT__DMAIOCAck__SHIFT 0x10
+#define ACP_DSP1_TIMEOUT_CNTL__DSP1TimeoutValue_MASK 0x3ffff
+#define ACP_DSP1_TIMEOUT_CNTL__DSP1TimeoutValue__SHIFT 0x0
+#define ACP_DSP1_TIMEOUT_CNTL__CntEn_MASK 0x80000000
+#define ACP_DSP1_TIMEOUT_CNTL__CntEn__SHIFT 0x1f
+#define ACP_DSP2_INTR_CNTL__ACPErrMask_MASK 0x1
+#define ACP_DSP2_INTR_CNTL__ACPErrMask__SHIFT 0x0
+#define ACP_DSP2_INTR_CNTL__I2SMicDataAvMask_MASK 0x2
+#define ACP_DSP2_INTR_CNTL__I2SMicDataAvMask__SHIFT 0x1
+#define ACP_DSP2_INTR_CNTL__I2SSpkr0DataEmptyMask_MASK 0x4
+#define ACP_DSP2_INTR_CNTL__I2SSpkr0DataEmptyMask__SHIFT 0x2
+#define ACP_DSP2_INTR_CNTL__I2SSpkr1DataEmptyMask_MASK 0x8
+#define ACP_DSP2_INTR_CNTL__I2SSpkr1DataEmptyMask__SHIFT 0x3
+#define ACP_DSP2_INTR_CNTL__I2SBTDataAvMask_MASK 0x10
+#define ACP_DSP2_INTR_CNTL__I2SBTDataAvMask__SHIFT 0x4
+#define ACP_DSP2_INTR_CNTL__AzaliaIntrMask_MASK 0x40
+#define ACP_DSP2_INTR_CNTL__AzaliaIntrMask__SHIFT 0x6
+#define ACP_DSP2_INTR_CNTL__SMUMailboxWriteMask_MASK 0x100
+#define ACP_DSP2_INTR_CNTL__SMUMailboxWriteMask__SHIFT 0x8
+#define ACP_DSP2_INTR_CNTL__SMUStutterStatusMask_MASK 0x200
+#define ACP_DSP2_INTR_CNTL__SMUStutterStatusMask__SHIFT 0x9
+#define ACP_DSP2_INTR_CNTL__MCStutterStatusMask_MASK 0x400
+#define ACP_DSP2_INTR_CNTL__MCStutterStatusMask__SHIFT 0xa
+#define ACP_DSP2_INTR_CNTL__DSPExtTimerMask_MASK 0x800
+#define ACP_DSP2_INTR_CNTL__DSPExtTimerMask__SHIFT 0xb
+#define ACP_DSP2_INTR_CNTL__DSPSemRespMask_MASK 0x1000
+#define ACP_DSP2_INTR_CNTL__DSPSemRespMask__SHIFT 0xc
+#define ACP_DSP2_INTR_CNTL__I2SBTDataEmptyMask_MASK 0x2000
+#define ACP_DSP2_INTR_CNTL__I2SBTDataEmptyMask__SHIFT 0xd
+#define ACP_DSP2_INTR_CNTL__DMAIOCMask_MASK 0xffff0000
+#define ACP_DSP2_INTR_CNTL__DMAIOCMask__SHIFT 0x10
+#define ACP_DSP2_INTR_STAT__ACPErrStat_MASK 0x1
+#define ACP_DSP2_INTR_STAT__ACPErrStat__SHIFT 0x0
+#define ACP_DSP2_INTR_STAT__ACPErrAck_MASK 0x1
+#define ACP_DSP2_INTR_STAT__ACPErrAck__SHIFT 0x0
+#define ACP_DSP2_INTR_STAT__I2SMicDataAvStat_MASK 0x2
+#define ACP_DSP2_INTR_STAT__I2SMicDataAvStat__SHIFT 0x1
+#define ACP_DSP2_INTR_STAT__I2SMicDataAvAck_MASK 0x2
+#define ACP_DSP2_INTR_STAT__I2SMicDataAvAck__SHIFT 0x1
+#define ACP_DSP2_INTR_STAT__I2SSpkr0DataEmptyStat_MASK 0x4
+#define ACP_DSP2_INTR_STAT__I2SSpkr0DataEmptyStat__SHIFT 0x2
+#define ACP_DSP2_INTR_STAT__I2SSpkr0DataEmptyAck_MASK 0x4
+#define ACP_DSP2_INTR_STAT__I2SSpkr0DataEmptyAck__SHIFT 0x2
+#define ACP_DSP2_INTR_STAT__I2SSpkr1DataEmptyStat_MASK 0x8
+#define ACP_DSP2_INTR_STAT__I2SSpkr1DataEmptyStat__SHIFT 0x3
+#define ACP_DSP2_INTR_STAT__I2SSpkr1DataEmptyAck_MASK 0x8
+#define ACP_DSP2_INTR_STAT__I2SSpkr1DataEmptyAck__SHIFT 0x3
+#define ACP_DSP2_INTR_STAT__I2SBTDataAvStat_MASK 0x10
+#define ACP_DSP2_INTR_STAT__I2SBTDataAvStat__SHIFT 0x4
+#define ACP_DSP2_INTR_STAT__I2SBTDataAvAck_MASK 0x10
+#define ACP_DSP2_INTR_STAT__I2SBTDataAvAck__SHIFT 0x4
+#define ACP_DSP2_INTR_STAT__AzaliaIntrStat_MASK 0x40
+#define ACP_DSP2_INTR_STAT__AzaliaIntrStat__SHIFT 0x6
+#define ACP_DSP2_INTR_STAT__AzaliaIntrAck_MASK 0x40
+#define ACP_DSP2_INTR_STAT__AzaliaIntrAck__SHIFT 0x6
+#define ACP_DSP2_INTR_STAT__SMUMailboxWriteStat_MASK 0x100
+#define ACP_DSP2_INTR_STAT__SMUMailboxWriteStat__SHIFT 0x8
+#define ACP_DSP2_INTR_STAT__SMUMailboxWriteAck_MASK 0x100
+#define ACP_DSP2_INTR_STAT__SMUMailboxWriteAck__SHIFT 0x8
+#define ACP_DSP2_INTR_STAT__SMUStutterStatusStat_MASK 0x200
+#define ACP_DSP2_INTR_STAT__SMUStutterStatusStat__SHIFT 0x9
+#define ACP_DSP2_INTR_STAT__SMUStutterStatusAck_MASK 0x200
+#define ACP_DSP2_INTR_STAT__SMUStutterStatusAck__SHIFT 0x9
+#define ACP_DSP2_INTR_STAT__MCStutterStatusStat_MASK 0x400
+#define ACP_DSP2_INTR_STAT__MCStutterStatusStat__SHIFT 0xa
+#define ACP_DSP2_INTR_STAT__MCStutterStatusAck_MASK 0x400
+#define ACP_DSP2_INTR_STAT__MCStutterStatusAck__SHIFT 0xa
+#define ACP_DSP2_INTR_STAT__DSPExtTimerStat_MASK 0x800
+#define ACP_DSP2_INTR_STAT__DSPExtTimerStat__SHIFT 0xb
+#define ACP_DSP2_INTR_STAT__DSPExtTimerAck_MASK 0x800
+#define ACP_DSP2_INTR_STAT__DSPExtTimerAck__SHIFT 0xb
+#define ACP_DSP2_INTR_STAT__DSPSemRespStat_MASK 0x1000
+#define ACP_DSP2_INTR_STAT__DSPSemRespStat__SHIFT 0xc
+#define ACP_DSP2_INTR_STAT__DSPSemRespAck_MASK 0x1000
+#define ACP_DSP2_INTR_STAT__DSPSemRespAck__SHIFT 0xc
+#define ACP_DSP2_INTR_STAT__I2SBTDataEmptyStat_MASK 0x2000
+#define ACP_DSP2_INTR_STAT__I2SBTDataEmptyStat__SHIFT 0xd
+#define ACP_DSP2_INTR_STAT__I2SBTDataEmptyAck_MASK 0x2000
+#define ACP_DSP2_INTR_STAT__I2SBTDataEmptyAck__SHIFT 0xd
+#define ACP_DSP2_INTR_STAT__DMAIOCStat_MASK 0xffff0000
+#define ACP_DSP2_INTR_STAT__DMAIOCStat__SHIFT 0x10
+#define ACP_DSP2_INTR_STAT__DMAIOCAck_MASK 0xffff0000
+#define ACP_DSP2_INTR_STAT__DMAIOCAck__SHIFT 0x10
+#define ACP_DSP2_TIMEOUT_CNTL__DSP2TimeoutValue_MASK 0x3ffff
+#define ACP_DSP2_TIMEOUT_CNTL__DSP2TimeoutValue__SHIFT 0x0
+#define ACP_DSP2_TIMEOUT_CNTL__CntEn_MASK 0x80000000
+#define ACP_DSP2_TIMEOUT_CNTL__CntEn__SHIFT 0x1f
+#define ACP_DSP0_EXT_TIMER_CNTL__TimerCount_MASK 0xffffff
+#define ACP_DSP0_EXT_TIMER_CNTL__TimerCount__SHIFT 0x0
+#define ACP_DSP0_EXT_TIMER_CNTL__TimerCntl_MASK 0xc0000000
+#define ACP_DSP0_EXT_TIMER_CNTL__TimerCntl__SHIFT 0x1e
+#define ACP_DSP1_EXT_TIMER_CNTL__TimerCount_MASK 0xffffff
+#define ACP_DSP1_EXT_TIMER_CNTL__TimerCount__SHIFT 0x0
+#define ACP_DSP1_EXT_TIMER_CNTL__TimerCntl_MASK 0xc0000000
+#define ACP_DSP1_EXT_TIMER_CNTL__TimerCntl__SHIFT 0x1e
+#define ACP_DSP2_EXT_TIMER_CNTL__TimerCount_MASK 0xffffff
+#define ACP_DSP2_EXT_TIMER_CNTL__TimerCount__SHIFT 0x0
+#define ACP_DSP2_EXT_TIMER_CNTL__TimerCntl_MASK 0xc0000000
+#define ACP_DSP2_EXT_TIMER_CNTL__TimerCntl__SHIFT 0x1e
+#define ACP_AXI2DAGB_SEM_0__AXI2DAGBGblSemReg_MASK 0x1
+#define ACP_AXI2DAGB_SEM_0__AXI2DAGBGblSemReg__SHIFT 0x0
+#define ACP_AXI2DAGB_SEM_1__AXI2DAGBGblSemReg_MASK 0x1
+#define ACP_AXI2DAGB_SEM_1__AXI2DAGBGblSemReg__SHIFT 0x0
+#define ACP_AXI2DAGB_SEM_2__AXI2DAGBGblSemReg_MASK 0x1
+#define ACP_AXI2DAGB_SEM_2__AXI2DAGBGblSemReg__SHIFT 0x0
+#define ACP_AXI2DAGB_SEM_3__AXI2DAGBGblSemReg_MASK 0x1
+#define ACP_AXI2DAGB_SEM_3__AXI2DAGBGblSemReg__SHIFT 0x0
+#define ACP_AXI2DAGB_SEM_4__AXI2DAGBGblSemReg_MASK 0x1
+#define ACP_AXI2DAGB_SEM_4__AXI2DAGBGblSemReg__SHIFT 0x0
+#define ACP_AXI2DAGB_SEM_5__AXI2DAGBGblSemReg_MASK 0x1
+#define ACP_AXI2DAGB_SEM_5__AXI2DAGBGblSemReg__SHIFT 0x0
+#define ACP_AXI2DAGB_SEM_6__AXI2DAGBGblSemReg_MASK 0x1
+#define ACP_AXI2DAGB_SEM_6__AXI2DAGBGblSemReg__SHIFT 0x0
+#define ACP_AXI2DAGB_SEM_7__AXI2DAGBGblSemReg_MASK 0x1
+#define ACP_AXI2DAGB_SEM_7__AXI2DAGBGblSemReg__SHIFT 0x0
+#define ACP_AXI2DAGB_SEM_8__AXI2DAGBGblSemReg_MASK 0x1
+#define ACP_AXI2DAGB_SEM_8__AXI2DAGBGblSemReg__SHIFT 0x0
+#define ACP_AXI2DAGB_SEM_9__AXI2DAGBGblSemReg_MASK 0x1
+#define ACP_AXI2DAGB_SEM_9__AXI2DAGBGblSemReg__SHIFT 0x0
+#define ACP_AXI2DAGB_SEM_10__AXI2DAGBGblSemReg_MASK 0x1
+#define ACP_AXI2DAGB_SEM_10__AXI2DAGBGblSemReg__SHIFT 0x0
+#define ACP_AXI2DAGB_SEM_11__AXI2DAGBGblSemReg_MASK 0x1
+#define ACP_AXI2DAGB_SEM_11__AXI2DAGBGblSemReg__SHIFT 0x0
+#define ACP_AXI2DAGB_SEM_12__AXI2DAGBGblSemReg_MASK 0x1
+#define ACP_AXI2DAGB_SEM_12__AXI2DAGBGblSemReg__SHIFT 0x0
+#define ACP_AXI2DAGB_SEM_13__AXI2DAGBGblSemReg_MASK 0x1
+#define ACP_AXI2DAGB_SEM_13__AXI2DAGBGblSemReg__SHIFT 0x0
+#define ACP_AXI2DAGB_SEM_14__AXI2DAGBGblSemReg_MASK 0x1
+#define ACP_AXI2DAGB_SEM_14__AXI2DAGBGblSemReg__SHIFT 0x0
+#define ACP_AXI2DAGB_SEM_15__AXI2DAGBGblSemReg_MASK 0x1
+#define ACP_AXI2DAGB_SEM_15__AXI2DAGBGblSemReg__SHIFT 0x0
+#define ACP_AXI2DAGB_SEM_16__AXI2DAGBGblSemReg_MASK 0x1
+#define ACP_AXI2DAGB_SEM_16__AXI2DAGBGblSemReg__SHIFT 0x0
+#define ACP_AXI2DAGB_SEM_17__AXI2DAGBGblSemReg_MASK 0x1
+#define ACP_AXI2DAGB_SEM_17__AXI2DAGBGblSemReg__SHIFT 0x0
+#define ACP_AXI2DAGB_SEM_18__AXI2DAGBGblSemReg_MASK 0x1
+#define ACP_AXI2DAGB_SEM_18__AXI2DAGBGblSemReg__SHIFT 0x0
+#define ACP_AXI2DAGB_SEM_19__AXI2DAGBGblSemReg_MASK 0x1
+#define ACP_AXI2DAGB_SEM_19__AXI2DAGBGblSemReg__SHIFT 0x0
+#define ACP_AXI2DAGB_SEM_20__AXI2DAGBGblSemReg_MASK 0x1
+#define ACP_AXI2DAGB_SEM_20__AXI2DAGBGblSemReg__SHIFT 0x0
+#define ACP_AXI2DAGB_SEM_21__AXI2DAGBGblSemReg_MASK 0x1
+#define ACP_AXI2DAGB_SEM_21__AXI2DAGBGblSemReg__SHIFT 0x0
+#define ACP_AXI2DAGB_SEM_22__AXI2DAGBGblSemReg_MASK 0x1
+#define ACP_AXI2DAGB_SEM_22__AXI2DAGBGblSemReg__SHIFT 0x0
+#define ACP_AXI2DAGB_SEM_23__AXI2DAGBGblSemReg_MASK 0x1
+#define ACP_AXI2DAGB_SEM_23__AXI2DAGBGblSemReg__SHIFT 0x0
+#define ACP_AXI2DAGB_SEM_24__AXI2DAGBGblSemReg_MASK 0x1
+#define ACP_AXI2DAGB_SEM_24__AXI2DAGBGblSemReg__SHIFT 0x0
+#define ACP_AXI2DAGB_SEM_25__AXI2DAGBGblSemReg_MASK 0x1
+#define ACP_AXI2DAGB_SEM_25__AXI2DAGBGblSemReg__SHIFT 0x0
+#define ACP_AXI2DAGB_SEM_26__AXI2DAGBGblSemReg_MASK 0x1
+#define ACP_AXI2DAGB_SEM_26__AXI2DAGBGblSemReg__SHIFT 0x0
+#define ACP_AXI2DAGB_SEM_27__AXI2DAGBGblSemReg_MASK 0x1
+#define ACP_AXI2DAGB_SEM_27__AXI2DAGBGblSemReg__SHIFT 0x0
+#define ACP_AXI2DAGB_SEM_28__AXI2DAGBGblSemReg_MASK 0x1
+#define ACP_AXI2DAGB_SEM_28__AXI2DAGBGblSemReg__SHIFT 0x0
+#define ACP_AXI2DAGB_SEM_29__AXI2DAGBGblSemReg_MASK 0x1
+#define ACP_AXI2DAGB_SEM_29__AXI2DAGBGblSemReg__SHIFT 0x0
+#define ACP_AXI2DAGB_SEM_30__AXI2DAGBGblSemReg_MASK 0x1
+#define ACP_AXI2DAGB_SEM_30__AXI2DAGBGblSemReg__SHIFT 0x0
+#define ACP_AXI2DAGB_SEM_31__AXI2DAGBGblSemReg_MASK 0x1
+#define ACP_AXI2DAGB_SEM_31__AXI2DAGBGblSemReg__SHIFT 0x0
+#define ACP_AXI2DAGB_SEM_32__AXI2DAGBGblSemReg_MASK 0x1
+#define ACP_AXI2DAGB_SEM_32__AXI2DAGBGblSemReg__SHIFT 0x0
+#define ACP_AXI2DAGB_SEM_33__AXI2DAGBGblSemReg_MASK 0x1
+#define ACP_AXI2DAGB_SEM_33__AXI2DAGBGblSemReg__SHIFT 0x0
+#define ACP_AXI2DAGB_SEM_34__AXI2DAGBGblSemReg_MASK 0x1
+#define ACP_AXI2DAGB_SEM_34__AXI2DAGBGblSemReg__SHIFT 0x0
+#define ACP_AXI2DAGB_SEM_35__AXI2DAGBGblSemReg_MASK 0x1
+#define ACP_AXI2DAGB_SEM_35__AXI2DAGBGblSemReg__SHIFT 0x0
+#define ACP_AXI2DAGB_SEM_36__AXI2DAGBGblSemReg_MASK 0x1
+#define ACP_AXI2DAGB_SEM_36__AXI2DAGBGblSemReg__SHIFT 0x0
+#define ACP_AXI2DAGB_SEM_37__AXI2DAGBGblSemReg_MASK 0x1
+#define ACP_AXI2DAGB_SEM_37__AXI2DAGBGblSemReg__SHIFT 0x0
+#define ACP_AXI2DAGB_SEM_38__AXI2DAGBGblSemReg_MASK 0x1
+#define ACP_AXI2DAGB_SEM_38__AXI2DAGBGblSemReg__SHIFT 0x0
+#define ACP_AXI2DAGB_SEM_39__AXI2DAGBGblSemReg_MASK 0x1
+#define ACP_AXI2DAGB_SEM_39__AXI2DAGBGblSemReg__SHIFT 0x0
+#define ACP_AXI2DAGB_SEM_40__AXI2DAGBGblSemReg_MASK 0x1
+#define ACP_AXI2DAGB_SEM_40__AXI2DAGBGblSemReg__SHIFT 0x0
+#define ACP_AXI2DAGB_SEM_41__AXI2DAGBGblSemReg_MASK 0x1
+#define ACP_AXI2DAGB_SEM_41__AXI2DAGBGblSemReg__SHIFT 0x0
+#define ACP_AXI2DAGB_SEM_42__AXI2DAGBGblSemReg_MASK 0x1
+#define ACP_AXI2DAGB_SEM_42__AXI2DAGBGblSemReg__SHIFT 0x0
+#define ACP_AXI2DAGB_SEM_43__AXI2DAGBGblSemReg_MASK 0x1
+#define ACP_AXI2DAGB_SEM_43__AXI2DAGBGblSemReg__SHIFT 0x0
+#define ACP_AXI2DAGB_SEM_44__AXI2DAGBGblSemReg_MASK 0x1
+#define ACP_AXI2DAGB_SEM_44__AXI2DAGBGblSemReg__SHIFT 0x0
+#define ACP_AXI2DAGB_SEM_45__AXI2DAGBGblSemReg_MASK 0x1
+#define ACP_AXI2DAGB_SEM_45__AXI2DAGBGblSemReg__SHIFT 0x0
+#define ACP_AXI2DAGB_SEM_46__AXI2DAGBGblSemReg_MASK 0x1
+#define ACP_AXI2DAGB_SEM_46__AXI2DAGBGblSemReg__SHIFT 0x0
+#define ACP_AXI2DAGB_SEM_47__AXI2DAGBGblSemReg_MASK 0x1
+#define ACP_AXI2DAGB_SEM_47__AXI2DAGBGblSemReg__SHIFT 0x0
+#define ACP_SRBM_Client_Base_Addr__SRBM_Client_base_addr_MASK 0xff
+#define ACP_SRBM_Client_Base_Addr__SRBM_Client_base_addr__SHIFT 0x0
+#define ACP_SRBM_Client_RDDATA__ReadData_MASK 0xffffffff
+#define ACP_SRBM_Client_RDDATA__ReadData__SHIFT 0x0
+#define ACP_SRBM_Cycle_Sts__SRBM_Client_Sts_MASK 0x1
+#define ACP_SRBM_Cycle_Sts__SRBM_Client_Sts__SHIFT 0x0
+#define ACP_SRBM_Targ_Idx_Addr__SRBM_Targ_Idx_addr_MASK 0x7ffffff
+#define ACP_SRBM_Targ_Idx_Addr__SRBM_Targ_Idx_addr__SHIFT 0x0
+#define ACP_SRBM_Targ_Idx_Data__SRBM_Targ_Idx_Data_MASK 0xffffffff
+#define ACP_SRBM_Targ_Idx_Data__SRBM_Targ_Idx_Data__SHIFT 0x0
+#define ACP_SEMA_ADDR_LOW__ADDR_9_3_MASK 0x7f
+#define ACP_SEMA_ADDR_LOW__ADDR_9_3__SHIFT 0x0
+#define ACP_SEMA_ADDR_HIGH__ADDR_39_10_MASK 0x3fffffff
+#define ACP_SEMA_ADDR_HIGH__ADDR_39_10__SHIFT 0x0
+#define ACP_SEMA_CMD__REQ_CMD_MASK 0xf
+#define ACP_SEMA_CMD__REQ_CMD__SHIFT 0x0
+#define ACP_SEMA_CMD__WR_PHASE_MASK 0x30
+#define ACP_SEMA_CMD__WR_PHASE__SHIFT 0x4
+#define ACP_SEMA_CMD__VMID_EN_MASK 0x80
+#define ACP_SEMA_CMD__VMID_EN__SHIFT 0x7
+#define ACP_SEMA_CMD__VMID_MASK 0xf00
+#define ACP_SEMA_CMD__VMID__SHIFT 0x8
+#define ACP_SEMA_CMD__ATC_MASK 0x1000
+#define ACP_SEMA_CMD__ATC__SHIFT 0xc
+#define ACP_SEMA_STS__REQ_STS_MASK 0x3
+#define ACP_SEMA_STS__REQ_STS__SHIFT 0x0
+#define ACP_SEMA_STS__REQ_RESP_AVAIL_MASK 0x100
+#define ACP_SEMA_STS__REQ_RESP_AVAIL__SHIFT 0x8
+#define ACP_SEMA_REQ__ISSUE_POLL_REQ_MASK 0x1
+#define ACP_SEMA_REQ__ISSUE_POLL_REQ__SHIFT 0x0
+#define ACP_FW_STATUS__RUN_MASK 0x1
+#define ACP_FW_STATUS__RUN__SHIFT 0x0
+#define ACP_FUTURE_REG_ACLK_0__ACPFutureReg_MASK 0xffffffff
+#define ACP_FUTURE_REG_ACLK_0__ACPFutureReg__SHIFT 0x0
+#define ACP_FUTURE_REG_ACLK_1__ACPFutureReg_MASK 0xffffffff
+#define ACP_FUTURE_REG_ACLK_1__ACPFutureReg__SHIFT 0x0
+#define ACP_FUTURE_REG_ACLK_2__ACPFutureReg_MASK 0xffffffff
+#define ACP_FUTURE_REG_ACLK_2__ACPFutureReg__SHIFT 0x0
+#define ACP_FUTURE_REG_ACLK_3__ACPFutureReg_MASK 0xffffffff
+#define ACP_FUTURE_REG_ACLK_3__ACPFutureReg__SHIFT 0x0
+#define ACP_FUTURE_REG_ACLK_4__ACPFutureReg_MASK 0xffffffff
+#define ACP_FUTURE_REG_ACLK_4__ACPFutureReg__SHIFT 0x0
+#define ACP_TIMER__ACP_Timer_count_MASK 0xffffffff
+#define ACP_TIMER__ACP_Timer_count__SHIFT 0x0
+#define ACP_TIMER_CNTL__ACP_Timer_control_MASK 0x1
+#define ACP_TIMER_CNTL__ACP_Timer_control__SHIFT 0x0
+#define ACP_DSP0_TIMER__ACP_DSP0_timer_MASK 0xffffff
+#define ACP_DSP0_TIMER__ACP_DSP0_timer__SHIFT 0x0
+#define ACP_DSP1_TIMER__ACP_DSP1_timer_MASK 0xffffff
+#define ACP_DSP1_TIMER__ACP_DSP1_timer__SHIFT 0x0
+#define ACP_DSP2_TIMER__ACP_DSP2_timer_MASK 0xffffff
+#define ACP_DSP2_TIMER__ACP_DSP2_timer__SHIFT 0x0
+#define ACP_I2S_TRANSMIT_BYTE_CNT_HIGH__i2s_sp_tx_byte_cnt_high_MASK 0xffffffff
+#define ACP_I2S_TRANSMIT_BYTE_CNT_HIGH__i2s_sp_tx_byte_cnt_high__SHIFT 0x0
+#define ACP_I2S_TRANSMIT_BYTE_CNT_LOW__i2s_sp_tx_byte_cnt_low_MASK 0xffffffff
+#define ACP_I2S_TRANSMIT_BYTE_CNT_LOW__i2s_sp_tx_byte_cnt_low__SHIFT 0x0
+#define ACP_I2S_BT_TRANSMIT_BYTE_CNT_HIGH__i2s_bt_tx_byte_cnt_high_MASK 0xffffffff
+#define ACP_I2S_BT_TRANSMIT_BYTE_CNT_HIGH__i2s_bt_tx_byte_cnt_high__SHIFT 0x0
+#define ACP_I2S_BT_TRANSMIT_BYTE_CNT_LOW__i2s_bt_tx_byte_cnt_low_MASK 0xffffffff
+#define ACP_I2S_BT_TRANSMIT_BYTE_CNT_LOW__i2s_bt_tx_byte_cnt_low__SHIFT 0x0
+#define ACP_I2S_BT_RECEIVE_BYTE_CNT_HIGH__i2s_bt_rx_byte_cnt_high_MASK 0xffffffff
+#define ACP_I2S_BT_RECEIVE_BYTE_CNT_HIGH__i2s_bt_rx_byte_cnt_high__SHIFT 0x0
+#define ACP_I2S_BT_RECEIVE_BYTE_CNT_LOW__i2s_bt_rx_byte_cnt_low_MASK 0xffffffff
+#define ACP_I2S_BT_RECEIVE_BYTE_CNT_LOW__i2s_bt_rx_byte_cnt_low__SHIFT 0x0
+#define ACP_DSP0_CS_STATE__DSP0_CS_state_MASK 0x1
+#define ACP_DSP0_CS_STATE__DSP0_CS_state__SHIFT 0x0
+#define ACP_DSP1_CS_STATE__DSP1_CS_state_MASK 0x1
+#define ACP_DSP1_CS_STATE__DSP1_CS_state__SHIFT 0x0
+#define ACP_DSP2_CS_STATE__DSP2_CS_state_MASK 0x1
+#define ACP_DSP2_CS_STATE__DSP2_CS_state__SHIFT 0x0
+#define ACP_SCRATCH_REG_BASE_ADDR__SCRATCH_REG_BASE_ADDR_MASK 0x7ffff
+#define ACP_SCRATCH_REG_BASE_ADDR__SCRATCH_REG_BASE_ADDR__SHIFT 0x0
+#define CC_ACP_EFUSE__DSP0_DISABLE_MASK 0x2
+#define CC_ACP_EFUSE__DSP0_DISABLE__SHIFT 0x1
+#define CC_ACP_EFUSE__DSP1_DISABLE_MASK 0x4
+#define CC_ACP_EFUSE__DSP1_DISABLE__SHIFT 0x2
+#define CC_ACP_EFUSE__DSP2_DISABLE_MASK 0x8
+#define CC_ACP_EFUSE__DSP2_DISABLE__SHIFT 0x3
+#define CC_ACP_EFUSE__ACP_DISABLE_MASK 0x10
+#define CC_ACP_EFUSE__ACP_DISABLE__SHIFT 0x4
+#define ACP_PGFSM_RETAIN_REG__ACP_P1_ON_OFF_MASK 0x1
+#define ACP_PGFSM_RETAIN_REG__ACP_P1_ON_OFF__SHIFT 0x0
+#define ACP_PGFSM_RETAIN_REG__ACP_P2_ON_OFF_MASK 0x2
+#define ACP_PGFSM_RETAIN_REG__ACP_P2_ON_OFF__SHIFT 0x1
+#define ACP_PGFSM_RETAIN_REG__ACP_DSP0_ON_OFF_MASK 0x4
+#define ACP_PGFSM_RETAIN_REG__ACP_DSP0_ON_OFF__SHIFT 0x2
+#define ACP_PGFSM_RETAIN_REG__ACP_DSP1_ON_OFF_MASK 0x8
+#define ACP_PGFSM_RETAIN_REG__ACP_DSP1_ON_OFF__SHIFT 0x3
+#define ACP_PGFSM_RETAIN_REG__ACP_DSP2_ON_OFF_MASK 0x10
+#define ACP_PGFSM_RETAIN_REG__ACP_DSP2_ON_OFF__SHIFT 0x4
+#define ACP_PGFSM_RETAIN_REG__ACP_AZ_ON_OFF_MASK 0x20
+#define ACP_PGFSM_RETAIN_REG__ACP_AZ_ON_OFF__SHIFT 0x5
+#define ACP_PGFSM_CONFIG_REG__FSM_ADDR_MASK 0xff
+#define ACP_PGFSM_CONFIG_REG__FSM_ADDR__SHIFT 0x0
+#define ACP_PGFSM_CONFIG_REG__Power_Down_MASK 0x100
+#define ACP_PGFSM_CONFIG_REG__Power_Down__SHIFT 0x8
+#define ACP_PGFSM_CONFIG_REG__Power_Up_MASK 0x200
+#define ACP_PGFSM_CONFIG_REG__Power_Up__SHIFT 0x9
+#define ACP_PGFSM_CONFIG_REG__P1_Select_MASK 0x400
+#define ACP_PGFSM_CONFIG_REG__P1_Select__SHIFT 0xa
+#define ACP_PGFSM_CONFIG_REG__P2_Select_MASK 0x800
+#define ACP_PGFSM_CONFIG_REG__P2_Select__SHIFT 0xb
+#define ACP_PGFSM_CONFIG_REG__Wr_MASK 0x1000
+#define ACP_PGFSM_CONFIG_REG__Wr__SHIFT 0xc
+#define ACP_PGFSM_CONFIG_REG__Rd_MASK 0x2000
+#define ACP_PGFSM_CONFIG_REG__Rd__SHIFT 0xd
+#define ACP_PGFSM_CONFIG_REG__RdData_Reset_MASK 0x4000
+#define ACP_PGFSM_CONFIG_REG__RdData_Reset__SHIFT 0xe
+#define ACP_PGFSM_CONFIG_REG__Short_Format_MASK 0x8000
+#define ACP_PGFSM_CONFIG_REG__Short_Format__SHIFT 0xf
+#define ACP_PGFSM_CONFIG_REG__BPM_CG_MG_FGCG_MASK 0x3ff0000
+#define ACP_PGFSM_CONFIG_REG__BPM_CG_MG_FGCG__SHIFT 0x10
+#define ACP_PGFSM_CONFIG_REG__SRBM_override_MASK 0x4000000
+#define ACP_PGFSM_CONFIG_REG__SRBM_override__SHIFT 0x1a
+#define ACP_PGFSM_CONFIG_REG__Rsvd_BPM_Addr_MASK 0x8000000
+#define ACP_PGFSM_CONFIG_REG__Rsvd_BPM_Addr__SHIFT 0x1b
+#define ACP_PGFSM_CONFIG_REG__REG_ADDR_MASK 0xf0000000
+#define ACP_PGFSM_CONFIG_REG__REG_ADDR__SHIFT 0x1c
+#define ACP_PGFSM_WRITE_REG__Write_value_MASK 0xffffffff
+#define ACP_PGFSM_WRITE_REG__Write_value__SHIFT 0x0
+#define ACP_PGFSM_READ_REG_0__Read_value_MASK 0xffffff
+#define ACP_PGFSM_READ_REG_0__Read_value__SHIFT 0x0
+#define ACP_PGFSM_READ_REG_1__Read_value_MASK 0xffffff
+#define ACP_PGFSM_READ_REG_1__Read_value__SHIFT 0x0
+#define ACP_PGFSM_READ_REG_2__Read_value_MASK 0xffffff
+#define ACP_PGFSM_READ_REG_2__Read_value__SHIFT 0x0
+#define ACP_PGFSM_READ_REG_3__Read_value_MASK 0xffffff
+#define ACP_PGFSM_READ_REG_3__Read_value__SHIFT 0x0
+#define ACP_PGFSM_READ_REG_4__Read_value_MASK 0xffffff
+#define ACP_PGFSM_READ_REG_4__Read_value__SHIFT 0x0
+#define ACP_PGFSM_READ_REG_5__Read_value_MASK 0xffffff
+#define ACP_PGFSM_READ_REG_5__Read_value__SHIFT 0x0
+#define ACP_IP_PGFSM_ENABLE__ACP_IP_ACCESS_MASK 0x1
+#define ACP_IP_PGFSM_ENABLE__ACP_IP_ACCESS__SHIFT 0x0
+#define ACP_I2S_PIN_CONFIG__ACP_I2S_PIN_CONFIG_MASK 0x3
+#define ACP_I2S_PIN_CONFIG__ACP_I2S_PIN_CONFIG__SHIFT 0x0
+#define ACP_AZALIA_I2S_SELECT__AZ_I2S_SELECT_MASK 0x1
+#define ACP_AZALIA_I2S_SELECT__AZ_I2S_SELECT__SHIFT 0x0
+#define ACP_CHIP_PKG_FOR_PAD_ISOLATION__external_fch_package_MASK 0x1
+#define ACP_CHIP_PKG_FOR_PAD_ISOLATION__external_fch_package__SHIFT 0x0
+#define ACP_AUDIO_PAD_PULLUP_PULLDOWN_CTRL__ACP_AUDIO_PAD_pullup_disable_MASK 0x7ff
+#define ACP_AUDIO_PAD_PULLUP_PULLDOWN_CTRL__ACP_AUDIO_PAD_pullup_disable__SHIFT 0x0
+#define ACP_AUDIO_PAD_PULLUP_PULLDOWN_CTRL__ACP_AUDIO_PAD_pulldown_enable_MASK 0x7ff0000
+#define ACP_AUDIO_PAD_PULLUP_PULLDOWN_CTRL__ACP_AUDIO_PAD_pulldown_enable__SHIFT 0x10
+#define ACP_BT_UART_PAD_SEL__ACP_BT_UART_PAD_SEL_MASK 0x1
+#define ACP_BT_UART_PAD_SEL__ACP_BT_UART_PAD_SEL__SHIFT 0x0
+#define ACP_SCRATCH_REG_0__ACP_SCRATCH_REG_MASK 0xffffffff
+#define ACP_SCRATCH_REG_0__ACP_SCRATCH_REG__SHIFT 0x0
+#define ACP_SCRATCH_REG_1__ACP_SCRATCH_REG_MASK 0xffffffff
+#define ACP_SCRATCH_REG_1__ACP_SCRATCH_REG__SHIFT 0x0
+#define ACP_SCRATCH_REG_2__ACP_SCRATCH_REG_MASK 0xffffffff
+#define ACP_SCRATCH_REG_2__ACP_SCRATCH_REG__SHIFT 0x0
+#define ACP_SCRATCH_REG_3__ACP_SCRATCH_REG_MASK 0xffffffff
+#define ACP_SCRATCH_REG_3__ACP_SCRATCH_REG__SHIFT 0x0
+#define ACP_SCRATCH_REG_4__ACP_SCRATCH_REG_MASK 0xffffffff
+#define ACP_SCRATCH_REG_4__ACP_SCRATCH_REG__SHIFT 0x0
+#define ACP_SCRATCH_REG_5__ACP_SCRATCH_REG_MASK 0xffffffff
+#define ACP_SCRATCH_REG_5__ACP_SCRATCH_REG__SHIFT 0x0
+#define ACP_SCRATCH_REG_6__ACP_SCRATCH_REG_MASK 0xffffffff
+#define ACP_SCRATCH_REG_6__ACP_SCRATCH_REG__SHIFT 0x0
+#define ACP_SCRATCH_REG_7__ACP_SCRATCH_REG_MASK 0xffffffff
+#define ACP_SCRATCH_REG_7__ACP_SCRATCH_REG__SHIFT 0x0
+#define ACP_SCRATCH_REG_8__ACP_SCRATCH_REG_MASK 0xffffffff
+#define ACP_SCRATCH_REG_8__ACP_SCRATCH_REG__SHIFT 0x0
+#define ACP_SCRATCH_REG_9__ACP_SCRATCH_REG_MASK 0xffffffff
+#define ACP_SCRATCH_REG_9__ACP_SCRATCH_REG__SHIFT 0x0
+#define ACP_SCRATCH_REG_10__ACP_SCRATCH_REG_MASK 0xffffffff
+#define ACP_SCRATCH_REG_10__ACP_SCRATCH_REG__SHIFT 0x0
+#define ACP_SCRATCH_REG_11__ACP_SCRATCH_REG_MASK 0xffffffff
+#define ACP_SCRATCH_REG_11__ACP_SCRATCH_REG__SHIFT 0x0
+#define ACP_SCRATCH_REG_12__ACP_SCRATCH_REG_MASK 0xffffffff
+#define ACP_SCRATCH_REG_12__ACP_SCRATCH_REG__SHIFT 0x0
+#define ACP_SCRATCH_REG_13__ACP_SCRATCH_REG_MASK 0xffffffff
+#define ACP_SCRATCH_REG_13__ACP_SCRATCH_REG__SHIFT 0x0
+#define ACP_SCRATCH_REG_14__ACP_SCRATCH_REG_MASK 0xffffffff
+#define ACP_SCRATCH_REG_14__ACP_SCRATCH_REG__SHIFT 0x0
+#define ACP_SCRATCH_REG_15__ACP_SCRATCH_REG_MASK 0xffffffff
+#define ACP_SCRATCH_REG_15__ACP_SCRATCH_REG__SHIFT 0x0
+#define ACP_SCRATCH_REG_16__ACP_SCRATCH_REG_MASK 0xffffffff
+#define ACP_SCRATCH_REG_16__ACP_SCRATCH_REG__SHIFT 0x0
+#define ACP_SCRATCH_REG_17__ACP_SCRATCH_REG_MASK 0xffffffff
+#define ACP_SCRATCH_REG_17__ACP_SCRATCH_REG__SHIFT 0x0
+#define ACP_SCRATCH_REG_18__ACP_SCRATCH_REG_MASK 0xffffffff
+#define ACP_SCRATCH_REG_18__ACP_SCRATCH_REG__SHIFT 0x0
+#define ACP_SCRATCH_REG_19__ACP_SCRATCH_REG_MASK 0xffffffff
+#define ACP_SCRATCH_REG_19__ACP_SCRATCH_REG__SHIFT 0x0
+#define ACP_SCRATCH_REG_20__ACP_SCRATCH_REG_MASK 0xffffffff
+#define ACP_SCRATCH_REG_20__ACP_SCRATCH_REG__SHIFT 0x0
+#define ACP_SCRATCH_REG_21__ACP_SCRATCH_REG_MASK 0xffffffff
+#define ACP_SCRATCH_REG_21__ACP_SCRATCH_REG__SHIFT 0x0
+#define ACP_SCRATCH_REG_22__ACP_SCRATCH_REG_MASK 0xffffffff
+#define ACP_SCRATCH_REG_22__ACP_SCRATCH_REG__SHIFT 0x0
+#define ACP_SCRATCH_REG_23__ACP_SCRATCH_REG_MASK 0xffffffff
+#define ACP_SCRATCH_REG_23__ACP_SCRATCH_REG__SHIFT 0x0
+#define ACP_SCRATCH_REG_24__ACP_SCRATCH_REG_MASK 0xffffffff
+#define ACP_SCRATCH_REG_24__ACP_SCRATCH_REG__SHIFT 0x0
+#define ACP_SCRATCH_REG_25__ACP_SCRATCH_REG_MASK 0xffffffff
+#define ACP_SCRATCH_REG_25__ACP_SCRATCH_REG__SHIFT 0x0
+#define ACP_SCRATCH_REG_26__ACP_SCRATCH_REG_MASK 0xffffffff
+#define ACP_SCRATCH_REG_26__ACP_SCRATCH_REG__SHIFT 0x0
+#define ACP_SCRATCH_REG_27__ACP_SCRATCH_REG_MASK 0xffffffff
+#define ACP_SCRATCH_REG_27__ACP_SCRATCH_REG__SHIFT 0x0
+#define ACP_SCRATCH_REG_28__ACP_SCRATCH_REG_MASK 0xffffffff
+#define ACP_SCRATCH_REG_28__ACP_SCRATCH_REG__SHIFT 0x0
+#define ACP_SCRATCH_REG_29__ACP_SCRATCH_REG_MASK 0xffffffff
+#define ACP_SCRATCH_REG_29__ACP_SCRATCH_REG__SHIFT 0x0
+#define ACP_SCRATCH_REG_30__ACP_SCRATCH_REG_MASK 0xffffffff
+#define ACP_SCRATCH_REG_30__ACP_SCRATCH_REG__SHIFT 0x0
+#define ACP_SCRATCH_REG_31__ACP_SCRATCH_REG_MASK 0xffffffff
+#define ACP_SCRATCH_REG_31__ACP_SCRATCH_REG__SHIFT 0x0
+#define ACP_SCRATCH_REG_32__ACP_SCRATCH_REG_MASK 0xffffffff
+#define ACP_SCRATCH_REG_32__ACP_SCRATCH_REG__SHIFT 0x0
+#define ACP_SCRATCH_REG_33__ACP_SCRATCH_REG_MASK 0xffffffff
+#define ACP_SCRATCH_REG_33__ACP_SCRATCH_REG__SHIFT 0x0
+#define ACP_SCRATCH_REG_34__ACP_SCRATCH_REG_MASK 0xffffffff
+#define ACP_SCRATCH_REG_34__ACP_SCRATCH_REG__SHIFT 0x0
+#define ACP_SCRATCH_REG_35__ACP_SCRATCH_REG_MASK 0xffffffff
+#define ACP_SCRATCH_REG_35__ACP_SCRATCH_REG__SHIFT 0x0
+#define ACP_SCRATCH_REG_36__ACP_SCRATCH_REG_MASK 0xffffffff
+#define ACP_SCRATCH_REG_36__ACP_SCRATCH_REG__SHIFT 0x0
+#define ACP_SCRATCH_REG_37__ACP_SCRATCH_REG_MASK 0xffffffff
+#define ACP_SCRATCH_REG_37__ACP_SCRATCH_REG__SHIFT 0x0
+#define ACP_SCRATCH_REG_38__ACP_SCRATCH_REG_MASK 0xffffffff
+#define ACP_SCRATCH_REG_38__ACP_SCRATCH_REG__SHIFT 0x0
+#define ACP_SCRATCH_REG_39__ACP_SCRATCH_REG_MASK 0xffffffff
+#define ACP_SCRATCH_REG_39__ACP_SCRATCH_REG__SHIFT 0x0
+#define ACP_SCRATCH_REG_40__ACP_SCRATCH_REG_MASK 0xffffffff
+#define ACP_SCRATCH_REG_40__ACP_SCRATCH_REG__SHIFT 0x0
+#define ACP_SCRATCH_REG_41__ACP_SCRATCH_REG_MASK 0xffffffff
+#define ACP_SCRATCH_REG_41__ACP_SCRATCH_REG__SHIFT 0x0
+#define ACP_SCRATCH_REG_42__ACP_SCRATCH_REG_MASK 0xffffffff
+#define ACP_SCRATCH_REG_42__ACP_SCRATCH_REG__SHIFT 0x0
+#define ACP_SCRATCH_REG_43__ACP_SCRATCH_REG_MASK 0xffffffff
+#define ACP_SCRATCH_REG_43__ACP_SCRATCH_REG__SHIFT 0x0
+#define ACP_SCRATCH_REG_44__ACP_SCRATCH_REG_MASK 0xffffffff
+#define ACP_SCRATCH_REG_44__ACP_SCRATCH_REG__SHIFT 0x0
+#define ACP_SCRATCH_REG_45__ACP_SCRATCH_REG_MASK 0xffffffff
+#define ACP_SCRATCH_REG_45__ACP_SCRATCH_REG__SHIFT 0x0
+#define ACP_SCRATCH_REG_46__ACP_SCRATCH_REG_MASK 0xffffffff
+#define ACP_SCRATCH_REG_46__ACP_SCRATCH_REG__SHIFT 0x0
+#define ACP_SCRATCH_REG_47__ACP_SCRATCH_REG_MASK 0xffffffff
+#define ACP_SCRATCH_REG_47__ACP_SCRATCH_REG__SHIFT 0x0
+#define ACP_VOICE_WAKEUP_ENABLE__voice_wakeup_enable_MASK 0x1
+#define ACP_VOICE_WAKEUP_ENABLE__voice_wakeup_enable__SHIFT 0x0
+#define ACP_VOICE_WAKEUP_STATUS__voice_wakeup_status_MASK 0x1
+#define ACP_VOICE_WAKEUP_STATUS__voice_wakeup_status__SHIFT 0x0
+#define I2S_VOICE_WAKEUP_LOWER_THRESHOLD__i2s_voice_wakeup_lower_threshold_MASK 0xffffffff
+#define I2S_VOICE_WAKEUP_LOWER_THRESHOLD__i2s_voice_wakeup_lower_threshold__SHIFT 0x0
+#define I2S_VOICE_WAKEUP_HIGHER_THRESHOLD__i2s_voice_wakeup_higher_threshold_MASK 0xffffffff
+#define I2S_VOICE_WAKEUP_HIGHER_THRESHOLD__i2s_voice_wakeup_higher_threshold__SHIFT 0x0
+#define I2S_VOICE_WAKEUP_NO_OF_SAMPLES__i2s_voice_wakeup_no_of_samples_MASK 0xffff
+#define I2S_VOICE_WAKEUP_NO_OF_SAMPLES__i2s_voice_wakeup_no_of_samples__SHIFT 0x0
+#define I2S_VOICE_WAKEUP_NO_OF_PEAKS__i2s_voice_wakeup_no_of_peaks_MASK 0xffff
+#define I2S_VOICE_WAKEUP_NO_OF_PEAKS__i2s_voice_wakeup_no_of_peaks__SHIFT 0x0
+#define I2S_VOICE_WAKEUP_DURATION_OF_N_PEAKS__i2s_voice_wakeup_duration_of_n_peaks_MASK 0xffffffff
+#define I2S_VOICE_WAKEUP_DURATION_OF_N_PEAKS__i2s_voice_wakeup_duration_of_n_peaks__SHIFT 0x0
+#define I2S_VOICE_WAKEUP_BITCLK_TOGGLE_DETECTION__i2s_voice_wakeup_bitclk_toggle_wakeup_en_MASK 0x1
+#define I2S_VOICE_WAKEUP_BITCLK_TOGGLE_DETECTION__i2s_voice_wakeup_bitclk_toggle_wakeup_en__SHIFT 0x0
+#define I2S_VOICE_WAKEUP_DATA_PATH_SWITCH__i2s_voice_wakeup_data_path_switch_req_MASK 0x1
+#define I2S_VOICE_WAKEUP_DATA_PATH_SWITCH__i2s_voice_wakeup_data_path_switch_req__SHIFT 0x0
+#define I2S_VOICE_WAKEUP_DATA_PATH_SWITCH__i2s_voice_wakeup_data_path_switch_ack_MASK 0x2
+#define I2S_VOICE_WAKEUP_DATA_PATH_SWITCH__i2s_voice_wakeup_data_path_switch_ack__SHIFT 0x1
+#define I2S_VOICE_WAKEUP_DATA_POINTER__i2s_voice_wakeup_data_pointer_MASK 0xffffffff
+#define I2S_VOICE_WAKEUP_DATA_POINTER__i2s_voice_wakeup_data_pointer__SHIFT 0x0
+#define I2S_VOICE_WAKEUP_AUTH_MATCH__i2s_voice_wakeup_authentication_valid_MASK 0x1
+#define I2S_VOICE_WAKEUP_AUTH_MATCH__i2s_voice_wakeup_authentication_valid__SHIFT 0x0
+#define I2S_VOICE_WAKEUP_AUTH_MATCH__i2s_voice_wakeup_authentication_match_MASK 0x2
+#define I2S_VOICE_WAKEUP_AUTH_MATCH__i2s_voice_wakeup_authentication_match__SHIFT 0x1
+#define I2S_VOICE_WAKEUP_8KB_WRAP__i2s_voice_wakeup_8kb_wrap_MASK 0x1
+#define I2S_VOICE_WAKEUP_8KB_WRAP__i2s_voice_wakeup_8kb_wrap__SHIFT 0x0
+#define ACP_I2S_RECEIVED_BYTE_CNT_HIGH__i2s_mic_rx_byte_cnt_high_MASK 0xffffffff
+#define ACP_I2S_RECEIVED_BYTE_CNT_HIGH__i2s_mic_rx_byte_cnt_high__SHIFT 0x0
+#define ACP_I2S_RECEIVED_BYTE_CNT_LOW__i2s_mic_rx_byte_cnt_low_MASK 0xffffffff
+#define ACP_I2S_RECEIVED_BYTE_CNT_LOW__i2s_mic_rx_byte_cnt_low__SHIFT 0x0
+#define ACP_I2S_MICSP_TRANSMIT_BYTE_CNT_HIGH__i2s_micsp_tx_byte_cnt_high_MASK 0xffffffff
+#define ACP_I2S_MICSP_TRANSMIT_BYTE_CNT_HIGH__i2s_micsp_tx_byte_cnt_high__SHIFT 0x0
+#define ACP_I2S_MICSP_TRANSMIT_BYTE_CNT_LOW__i2s_micsp_tx_byte_cnt_low_MASK 0xffffffff
+#define ACP_I2S_MICSP_TRANSMIT_BYTE_CNT_LOW__i2s_micsp_tx_byte_cnt_low__SHIFT 0x0
+#define ACP_MEM_SHUT_DOWN_REQ_LO__ACP_ShutDownReq_RAML_MASK 0xffffffff
+#define ACP_MEM_SHUT_DOWN_REQ_LO__ACP_ShutDownReq_RAML__SHIFT 0x0
+#define ACP_MEM_SHUT_DOWN_REQ_HI__ACP_ShutDownReq_RAMH_MASK 0xffff
+#define ACP_MEM_SHUT_DOWN_REQ_HI__ACP_ShutDownReq_RAMH__SHIFT 0x0
+#define ACP_MEM_SHUT_DOWN_STS_LO__ACP_ShutDownSts_RAML_MASK 0xffffffff
+#define ACP_MEM_SHUT_DOWN_STS_LO__ACP_ShutDownSts_RAML__SHIFT 0x0
+#define ACP_MEM_SHUT_DOWN_STS_HI__ACP_ShutDownSts_RAMH_MASK 0xffff
+#define ACP_MEM_SHUT_DOWN_STS_HI__ACP_ShutDownSts_RAMH__SHIFT 0x0
+#define ACP_MEM_DEEP_SLEEP_REQ_LO__ACP_DeepSleepReq_RAML_MASK 0xffffffff
+#define ACP_MEM_DEEP_SLEEP_REQ_LO__ACP_DeepSleepReq_RAML__SHIFT 0x0
+#define ACP_MEM_DEEP_SLEEP_REQ_HI__ACP_DeepSleepReq_RAMH_MASK 0xffff
+#define ACP_MEM_DEEP_SLEEP_REQ_HI__ACP_DeepSleepReq_RAMH__SHIFT 0x0
+#define ACP_MEM_DEEP_SLEEP_STS_LO__ACP_DeepSleepSts_RAML_MASK 0xffffffff
+#define ACP_MEM_DEEP_SLEEP_STS_LO__ACP_DeepSleepSts_RAML__SHIFT 0x0
+#define ACP_MEM_DEEP_SLEEP_STS_HI__ACP_DeepSleepSts_RAMH_MASK 0xffff
+#define ACP_MEM_DEEP_SLEEP_STS_HI__ACP_DeepSleepSts_RAMH__SHIFT 0x0
+#define ACP_MEM_WAKEUP_FROM_SHUT_DOWN_LO__acp_mem_wakeup_from_shut_down_lo_MASK 0xffffffff
+#define ACP_MEM_WAKEUP_FROM_SHUT_DOWN_LO__acp_mem_wakeup_from_shut_down_lo__SHIFT 0x0
+#define ACP_MEM_WAKEUP_FROM_SHUT_DOWN_HI__acp_mem_wakeup_from_shut_down_hi_MASK 0xffff
+#define ACP_MEM_WAKEUP_FROM_SHUT_DOWN_HI__acp_mem_wakeup_from_shut_down_hi__SHIFT 0x0
+#define ACP_MEM_WAKEUP_FROM_SLEEP_LO__acp_mem_wakeup_from_sleep_lo_MASK 0xffffffff
+#define ACP_MEM_WAKEUP_FROM_SLEEP_LO__acp_mem_wakeup_from_sleep_lo__SHIFT 0x0
+#define ACP_MEM_WAKEUP_FROM_SLEEP_HI__acp_mem_wakeup_from_sleep_hi_MASK 0xffff
+#define ACP_MEM_WAKEUP_FROM_SLEEP_HI__acp_mem_wakeup_from_sleep_hi__SHIFT 0x0
+#define ACP_I2SSP_IER__I2SSP_IEN_MASK 0x1
+#define ACP_I2SSP_IER__I2SSP_IEN__SHIFT 0x0
+#define ACP_I2SSP_IRER__I2SSP_RXEN_MASK 0x1
+#define ACP_I2SSP_IRER__I2SSP_RXEN__SHIFT 0x0
+#define ACP_I2SSP_ITER__I2SSP_TXEN_MASK 0x1
+#define ACP_I2SSP_ITER__I2SSP_TXEN__SHIFT 0x0
+#define ACP_I2SSP_CER__I2SSP_CLKEN_MASK 0x1
+#define ACP_I2SSP_CER__I2SSP_CLKEN__SHIFT 0x0
+#define ACP_I2SSP_CCR__I2SSP_SCLKG_MASK 0x7
+#define ACP_I2SSP_CCR__I2SSP_SCLKG__SHIFT 0x0
+#define ACP_I2SSP_CCR__I2SSP_WSS_MASK 0x18
+#define ACP_I2SSP_CCR__I2SSP_WSS__SHIFT 0x3
+#define ACP_I2SSP_RXFFR__I2SSP_RXFFR_MASK 0x1
+#define ACP_I2SSP_RXFFR__I2SSP_RXFFR__SHIFT 0x0
+#define ACP_I2SSP_TXFFR__I2SSP_TXFFR_MASK 0x1
+#define ACP_I2SSP_TXFFR__I2SSP_TXFFR__SHIFT 0x0
+#define ACP_I2SSP_LRBR0__I2SSP_LRBR0_MASK 0xffffffff
+#define ACP_I2SSP_LRBR0__I2SSP_LRBR0__SHIFT 0x0
+#define ACP_I2SSP_RRBR0__I2SSP_RRBR0_MASK 0xffffffff
+#define ACP_I2SSP_RRBR0__I2SSP_RRBR0__SHIFT 0x0
+#define ACP_I2SSP_RER0__I2SSP_RXCHEN0_MASK 0x1
+#define ACP_I2SSP_RER0__I2SSP_RXCHEN0__SHIFT 0x0
+#define ACP_I2SSP_TER0__I2SSP_TXCHEN0_MASK 0x1
+#define ACP_I2SSP_TER0__I2SSP_TXCHEN0__SHIFT 0x0
+#define ACP_I2SSP_RCR0__I2SSP_WLEN_MASK 0x7
+#define ACP_I2SSP_RCR0__I2SSP_WLEN__SHIFT 0x0
+#define ACP_I2SSP_TCR0__I2SSP_WLEN_MASK 0x7
+#define ACP_I2SSP_TCR0__I2SSP_WLEN__SHIFT 0x0
+#define ACP_I2SSP_ISR0__I2SSP_RXDA_MASK 0x1
+#define ACP_I2SSP_ISR0__I2SSP_RXDA__SHIFT 0x0
+#define ACP_I2SSP_ISR0__I2SSP_RXFO_MASK 0x2
+#define ACP_I2SSP_ISR0__I2SSP_RXFO__SHIFT 0x1
+#define ACP_I2SSP_ISR0__I2SSP_TXFE_MASK 0x10
+#define ACP_I2SSP_ISR0__I2SSP_TXFE__SHIFT 0x4
+#define ACP_I2SSP_ISR0__I2SSP_TXFO_MASK 0x20
+#define ACP_I2SSP_ISR0__I2SSP_TXFO__SHIFT 0x5
+#define ACP_I2SSP_IMR0__I2SSP_RXDAM_MASK 0x1
+#define ACP_I2SSP_IMR0__I2SSP_RXDAM__SHIFT 0x0
+#define ACP_I2SSP_IMR0__I2SSP_RXFOM_MASK 0x2
+#define ACP_I2SSP_IMR0__I2SSP_RXFOM__SHIFT 0x1
+#define ACP_I2SSP_IMR0__I2SSP_TXFEM_MASK 0x10
+#define ACP_I2SSP_IMR0__I2SSP_TXFEM__SHIFT 0x4
+#define ACP_I2SSP_IMR0__I2SSP_TXFOM_MASK 0x20
+#define ACP_I2SSP_IMR0__I2SSP_TXFOM__SHIFT 0x5
+#define ACP_I2SSP_ROR0__I2SSP_RXCHO_MASK 0x1
+#define ACP_I2SSP_ROR0__I2SSP_RXCHO__SHIFT 0x0
+#define ACP_I2SSP_TOR0__I2SSP_TXCHO_MASK 0x1
+#define ACP_I2SSP_TOR0__I2SSP_TXCHO__SHIFT 0x0
+#define ACP_I2SSP_RFCR0__I2SSP_RXCHDT_MASK 0xf
+#define ACP_I2SSP_RFCR0__I2SSP_RXCHDT__SHIFT 0x0
+#define ACP_I2SSP_TFCR0__I2SSP_TXCHET_MASK 0xf
+#define ACP_I2SSP_TFCR0__I2SSP_TXCHET__SHIFT 0x0
+#define ACP_I2SSP_RFF0__I2SSP_RXCHFR_MASK 0x1
+#define ACP_I2SSP_RFF0__I2SSP_RXCHFR__SHIFT 0x0
+#define ACP_I2SSP_TFF0__I2SSP_TXCHFR_MASK 0x1
+#define ACP_I2SSP_TFF0__I2SSP_TXCHFR__SHIFT 0x0
+#define ACP_I2SSP_RXDMA__I2SSP_RXDMA_MASK 0xffffffff
+#define ACP_I2SSP_RXDMA__I2SSP_RXDMA__SHIFT 0x0
+#define ACP_I2SSP_RRXDMA__I2SSP_RRXDMA_MASK 0x1
+#define ACP_I2SSP_RRXDMA__I2SSP_RRXDMA__SHIFT 0x0
+#define ACP_I2SSP_TXDMA__I2SSP_TXDMA_MASK 0xffffffff
+#define ACP_I2SSP_TXDMA__I2SSP_TXDMA__SHIFT 0x0
+#define ACP_I2SSP_RTXDMA__I2SSP_RTXDMA_MASK 0x1
+#define ACP_I2SSP_RTXDMA__I2SSP_RTXDMA__SHIFT 0x0
+#define ACP_I2SSP_COMP_PARAM_2__I2SSP_RX_WPRDSIZE_0_MASK 0x7
+#define ACP_I2SSP_COMP_PARAM_2__I2SSP_RX_WPRDSIZE_0__SHIFT 0x0
+#define ACP_I2SSP_COMP_PARAM_2__I2SSP_RX_WPRDSIZE_1_MASK 0x38
+#define ACP_I2SSP_COMP_PARAM_2__I2SSP_RX_WPRDSIZE_1__SHIFT 0x3
+#define ACP_I2SSP_COMP_PARAM_2__I2SSP_RX_WPRDSIZE_2_MASK 0x380
+#define ACP_I2SSP_COMP_PARAM_2__I2SSP_RX_WPRDSIZE_2__SHIFT 0x7
+#define ACP_I2SSP_COMP_PARAM_2__I2SSP_RX_WPRDSIZE_3_MASK 0x1c00
+#define ACP_I2SSP_COMP_PARAM_2__I2SSP_RX_WPRDSIZE_3__SHIFT 0xa
+#define ACP_I2SSP_COMP_PARAM_1__I2SSP_APB_DATA_WIDTH_MASK 0x3
+#define ACP_I2SSP_COMP_PARAM_1__I2SSP_APB_DATA_WIDTH__SHIFT 0x0
+#define ACP_I2SSP_COMP_PARAM_1__I2SSP_FIFO_DEPTH_GLOBAL_MASK 0xc
+#define ACP_I2SSP_COMP_PARAM_1__I2SSP_FIFO_DEPTH_GLOBAL__SHIFT 0x2
+#define ACP_I2SSP_COMP_PARAM_1__I2SSP_MODE_EN_MASK 0x10
+#define ACP_I2SSP_COMP_PARAM_1__I2SSP_MODE_EN__SHIFT 0x4
+#define ACP_I2SSP_COMP_PARAM_1__I2SSP_TRANSMITTER_BLOCK_MASK 0x20
+#define ACP_I2SSP_COMP_PARAM_1__I2SSP_TRANSMITTER_BLOCK__SHIFT 0x5
+#define ACP_I2SSP_COMP_PARAM_1__I2SSP_RECEIVER_BLOCK_MASK 0x40
+#define ACP_I2SSP_COMP_PARAM_1__I2SSP_RECEIVER_BLOCK__SHIFT 0x6
+#define ACP_I2SSP_COMP_PARAM_1__I2SSP_RX_CHANNLES_MASK 0x180
+#define ACP_I2SSP_COMP_PARAM_1__I2SSP_RX_CHANNLES__SHIFT 0x7
+#define ACP_I2SSP_COMP_PARAM_1__I2SSP_TX_CHANNLES_MASK 0x600
+#define ACP_I2SSP_COMP_PARAM_1__I2SSP_TX_CHANNLES__SHIFT 0x9
+#define ACP_I2SSP_COMP_PARAM_1__I2SSP_TX_WORDSIZE_0_MASK 0x70000
+#define ACP_I2SSP_COMP_PARAM_1__I2SSP_TX_WORDSIZE_0__SHIFT 0x10
+#define ACP_I2SSP_COMP_PARAM_1__I2SSP_TX_WORDSIZE_1_MASK 0x380000
+#define ACP_I2SSP_COMP_PARAM_1__I2SSP_TX_WORDSIZE_1__SHIFT 0x13
+#define ACP_I2SSP_COMP_PARAM_1__I2SSP_TX_WORDSIZE_2_MASK 0x1c00000
+#define ACP_I2SSP_COMP_PARAM_1__I2SSP_TX_WORDSIZE_2__SHIFT 0x16
+#define ACP_I2SSP_COMP_PARAM_1__I2SSP_TX_WORDSIZE_3_MASK 0xe000000
+#define ACP_I2SSP_COMP_PARAM_1__I2SSP_TX_WORDSIZE_3__SHIFT 0x19
+#define ACP_I2SSP_COMP_VERSION__I2SSP_APB_DATA_WIDTH_MASK 0xffffffff
+#define ACP_I2SSP_COMP_VERSION__I2SSP_APB_DATA_WIDTH__SHIFT 0x0
+#define ACP_I2SSP_COMP_TYPE__I2SSP_COMP_TYPE_MASK 0xffffffff
+#define ACP_I2SSP_COMP_TYPE__I2SSP_COMP_TYPE__SHIFT 0x0
+#define ACP_I2SMICSP_IER__I2SMICSP_IEN_MASK 0x1
+#define ACP_I2SMICSP_IER__I2SMICSP_IEN__SHIFT 0x0
+#define ACP_I2SMICSP_IRER__I2SMICSP_RXEN_MASK 0x1
+#define ACP_I2SMICSP_IRER__I2SMICSP_RXEN__SHIFT 0x0
+#define ACP_I2SMICSP_ITER__I2SMICSP_TXEN_MASK 0x1
+#define ACP_I2SMICSP_ITER__I2SMICSP_TXEN__SHIFT 0x0
+#define ACP_I2SMICSP_CER__I2SMICSP_CLKEN_MASK 0x1
+#define ACP_I2SMICSP_CER__I2SMICSP_CLKEN__SHIFT 0x0
+#define ACP_I2SMICSP_CCR__I2SMICSP_SCLKG_MASK 0x7
+#define ACP_I2SMICSP_CCR__I2SMICSP_SCLKG__SHIFT 0x0
+#define ACP_I2SMICSP_CCR__I2SMICSP_WSS_MASK 0x18
+#define ACP_I2SMICSP_CCR__I2SMICSP_WSS__SHIFT 0x3
+#define ACP_I2SMICSP_RXFFR__I2SMICSP_RXFFR_MASK 0x1
+#define ACP_I2SMICSP_RXFFR__I2SMICSP_RXFFR__SHIFT 0x0
+#define ACP_I2SMICSP_TXFFR__I2SMICSP_TXFFR_MASK 0x1
+#define ACP_I2SMICSP_TXFFR__I2SMICSP_TXFFR__SHIFT 0x0
+#define ACP_I2SMICSP_LRBR0__I2SMICSP_LRBR0_MASK 0xffffffff
+#define ACP_I2SMICSP_LRBR0__I2SMICSP_LRBR0__SHIFT 0x0
+#define ACP_I2SMICSP_RRBR0__I2SMICSP_RRBR0_MASK 0xffffffff
+#define ACP_I2SMICSP_RRBR0__I2SMICSP_RRBR0__SHIFT 0x0
+#define ACP_I2SMICSP_RER0__I2SMICSP_RXCHEN0_MASK 0x1
+#define ACP_I2SMICSP_RER0__I2SMICSP_RXCHEN0__SHIFT 0x0
+#define ACP_I2SMICSP_TER0__I2SMICSP_TXCHEN0_MASK 0x1
+#define ACP_I2SMICSP_TER0__I2SMICSP_TXCHEN0__SHIFT 0x0
+#define ACP_I2SMICSP_RCR0__I2SMICSP_WLEN_MASK 0x7
+#define ACP_I2SMICSP_RCR0__I2SMICSP_WLEN__SHIFT 0x0
+#define ACP_I2SMICSP_TCR0__I2SMICSP_WLEN_MASK 0x7
+#define ACP_I2SMICSP_TCR0__I2SMICSP_WLEN__SHIFT 0x0
+#define ACP_I2SMICSP_ISR0__I2SMICSP_RXDA_MASK 0x1
+#define ACP_I2SMICSP_ISR0__I2SMICSP_RXDA__SHIFT 0x0
+#define ACP_I2SMICSP_ISR0__I2SMICSP_RXFO_MASK 0x2
+#define ACP_I2SMICSP_ISR0__I2SMICSP_RXFO__SHIFT 0x1
+#define ACP_I2SMICSP_ISR0__I2SMICSP_TXFE_MASK 0x10
+#define ACP_I2SMICSP_ISR0__I2SMICSP_TXFE__SHIFT 0x4
+#define ACP_I2SMICSP_ISR0__I2SMICSP_TXFO_MASK 0x20
+#define ACP_I2SMICSP_ISR0__I2SMICSP_TXFO__SHIFT 0x5
+#define ACP_I2SMICSP_IMR0__I2SMICSP_RXDAM_MASK 0x1
+#define ACP_I2SMICSP_IMR0__I2SMICSP_RXDAM__SHIFT 0x0
+#define ACP_I2SMICSP_IMR0__I2SMICSP_RXFOM_MASK 0x2
+#define ACP_I2SMICSP_IMR0__I2SMICSP_RXFOM__SHIFT 0x1
+#define ACP_I2SMICSP_IMR0__I2SMICSP_TXFEM_MASK 0x10
+#define ACP_I2SMICSP_IMR0__I2SMICSP_TXFEM__SHIFT 0x4
+#define ACP_I2SMICSP_IMR0__I2SMICSP_TXFOM_MASK 0x20
+#define ACP_I2SMICSP_IMR0__I2SMICSP_TXFOM__SHIFT 0x5
+#define ACP_I2SMICSP_ROR0__I2SMICSP_RXCHO_MASK 0x1
+#define ACP_I2SMICSP_ROR0__I2SMICSP_RXCHO__SHIFT 0x0
+#define ACP_I2SMICSP_TOR0__I2SMICSP_TXCHO_MASK 0x1
+#define ACP_I2SMICSP_TOR0__I2SMICSP_TXCHO__SHIFT 0x0
+#define ACP_I2SMICSP_RFCR0__I2SMICSP_RXCHDT_MASK 0xf
+#define ACP_I2SMICSP_RFCR0__I2SMICSP_RXCHDT__SHIFT 0x0
+#define ACP_I2SMICSP_TFCR0__I2SMICSP_TXCHET_MASK 0xf
+#define ACP_I2SMICSP_TFCR0__I2SMICSP_TXCHET__SHIFT 0x0
+#define ACP_I2SMICSP_RFF0__I2SMICSP_RXCHFR_MASK 0x1
+#define ACP_I2SMICSP_RFF0__I2SMICSP_RXCHFR__SHIFT 0x0
+#define ACP_I2SMICSP_TFF0__I2SMICSP_TXCHFR_MASK 0x1
+#define ACP_I2SMICSP_TFF0__I2SMICSP_TXCHFR__SHIFT 0x0
+#define ACP_I2SMICSP_LRBR1__I2SMICSP_LRBR1_MASK 0xffffffff
+#define ACP_I2SMICSP_LRBR1__I2SMICSP_LRBR1__SHIFT 0x0
+#define ACP_I2SMICSP_RRBR1__I2SMICSP_RRBR1_MASK 0xffffffff
+#define ACP_I2SMICSP_RRBR1__I2SMICSP_RRBR1__SHIFT 0x0
+#define ACP_I2SMICSP_RER1__I2SMICSP_RXCHEN1_MASK 0x1
+#define ACP_I2SMICSP_RER1__I2SMICSP_RXCHEN1__SHIFT 0x0
+#define ACP_I2SMICSP_TER1__I2SMICSP_TXCHEN1_MASK 0x1
+#define ACP_I2SMICSP_TER1__I2SMICSP_TXCHEN1__SHIFT 0x0
+#define ACP_I2SMICSP_RCR1__I2SMICSP_WLEN_MASK 0x7
+#define ACP_I2SMICSP_RCR1__I2SMICSP_WLEN__SHIFT 0x0
+#define ACP_I2SMICSP_TCR1__I2SMICSP_WLEN_MASK 0x7
+#define ACP_I2SMICSP_TCR1__I2SMICSP_WLEN__SHIFT 0x0
+#define ACP_I2SMICSP_ISR1__I2SMICSP_RXDA_MASK 0x1
+#define ACP_I2SMICSP_ISR1__I2SMICSP_RXDA__SHIFT 0x0
+#define ACP_I2SMICSP_ISR1__I2SMICSP_RXFO_MASK 0x2
+#define ACP_I2SMICSP_ISR1__I2SMICSP_RXFO__SHIFT 0x1
+#define ACP_I2SMICSP_ISR1__I2SMICSP_TXFE_MASK 0x10
+#define ACP_I2SMICSP_ISR1__I2SMICSP_TXFE__SHIFT 0x4
+#define ACP_I2SMICSP_ISR1__I2SMICSP_TXFO_MASK 0x20
+#define ACP_I2SMICSP_ISR1__I2SMICSP_TXFO__SHIFT 0x5
+#define ACP_I2SMICSP_IMR1__I2SMICSP_RXDAM_MASK 0x1
+#define ACP_I2SMICSP_IMR1__I2SMICSP_RXDAM__SHIFT 0x0
+#define ACP_I2SMICSP_IMR1__I2SMICSP_RXFOM_MASK 0x2
+#define ACP_I2SMICSP_IMR1__I2SMICSP_RXFOM__SHIFT 0x1
+#define ACP_I2SMICSP_IMR1__I2SMICSP_TXFEM_MASK 0x10
+#define ACP_I2SMICSP_IMR1__I2SMICSP_TXFEM__SHIFT 0x4
+#define ACP_I2SMICSP_IMR1__I2SMICSP_TXFOM_MASK 0x20
+#define ACP_I2SMICSP_IMR1__I2SMICSP_TXFOM__SHIFT 0x5
+#define ACP_I2SMICSP_ROR1__I2SMICSP_RXCHO_MASK 0x1
+#define ACP_I2SMICSP_ROR1__I2SMICSP_RXCHO__SHIFT 0x0
+#define ACP_I2SMICSP_TOR1__I2SMICSP_TXCHO_MASK 0x1
+#define ACP_I2SMICSP_TOR1__I2SMICSP_TXCHO__SHIFT 0x0
+#define ACP_I2SMICSP_RFCR1__I2SMICSP_RXCHDT_MASK 0xf
+#define ACP_I2SMICSP_RFCR1__I2SMICSP_RXCHDT__SHIFT 0x0
+#define ACP_I2SMICSP_TFCR1__I2SMICSP_TXCHET_MASK 0xf
+#define ACP_I2SMICSP_TFCR1__I2SMICSP_TXCHET__SHIFT 0x0
+#define ACP_I2SMICSP_RFF1__I2SMICSP_RXCHFR_MASK 0x1
+#define ACP_I2SMICSP_RFF1__I2SMICSP_RXCHFR__SHIFT 0x0
+#define ACP_I2SMICSP_TFF1__I2SMICSP_TXCHFR_MASK 0x1
+#define ACP_I2SMICSP_TFF1__I2SMICSP_TXCHFR__SHIFT 0x0
+#define ACP_I2SMICSP_RXDMA__I2SMICSP_RXDMA_MASK 0xffffffff
+#define ACP_I2SMICSP_RXDMA__I2SMICSP_RXDMA__SHIFT 0x0
+#define ACP_I2SMICSP_RRXDMA__I2SMICSP_RRXDMA_MASK 0x1
+#define ACP_I2SMICSP_RRXDMA__I2SMICSP_RRXDMA__SHIFT 0x0
+#define ACP_I2SMICSP_TXDMA__I2SMICSP_TXDMA_MASK 0xffffffff
+#define ACP_I2SMICSP_TXDMA__I2SMICSP_TXDMA__SHIFT 0x0
+#define ACP_I2SMICSP_RTXDMA__I2SMICSP_RTXDMA_MASK 0x1
+#define ACP_I2SMICSP_RTXDMA__I2SMICSP_RTXDMA__SHIFT 0x0
+#define ACP_I2SMICSP_COMP_PARAM_2__I2SMICSP_RX_WPRDSIZE_0_MASK 0x7
+#define ACP_I2SMICSP_COMP_PARAM_2__I2SMICSP_RX_WPRDSIZE_0__SHIFT 0x0
+#define ACP_I2SMICSP_COMP_PARAM_2__I2SMICSP_RX_WPRDSIZE_1_MASK 0x38
+#define ACP_I2SMICSP_COMP_PARAM_2__I2SMICSP_RX_WPRDSIZE_1__SHIFT 0x3
+#define ACP_I2SMICSP_COMP_PARAM_2__I2SMICSP_RX_WPRDSIZE_2_MASK 0x380
+#define ACP_I2SMICSP_COMP_PARAM_2__I2SMICSP_RX_WPRDSIZE_2__SHIFT 0x7
+#define ACP_I2SMICSP_COMP_PARAM_2__I2SMICSP_RX_WPRDSIZE_3_MASK 0x1c00
+#define ACP_I2SMICSP_COMP_PARAM_2__I2SMICSP_RX_WPRDSIZE_3__SHIFT 0xa
+#define ACP_I2SMICSP_COMP_PARAM_1__I2SMICSP_APB_DATA_WIDTH_MASK 0x3
+#define ACP_I2SMICSP_COMP_PARAM_1__I2SMICSP_APB_DATA_WIDTH__SHIFT 0x0
+#define ACP_I2SMICSP_COMP_PARAM_1__I2SMICSP_FIFO_DEPTH_GLOBAL_MASK 0xc
+#define ACP_I2SMICSP_COMP_PARAM_1__I2SMICSP_FIFO_DEPTH_GLOBAL__SHIFT 0x2
+#define ACP_I2SMICSP_COMP_PARAM_1__I2SMICSP_MODE_EN_MASK 0x10
+#define ACP_I2SMICSP_COMP_PARAM_1__I2SMICSP_MODE_EN__SHIFT 0x4
+#define ACP_I2SMICSP_COMP_PARAM_1__I2SMICSP_TRANSMITTER_BLOCK_MASK 0x20
+#define ACP_I2SMICSP_COMP_PARAM_1__I2SMICSP_TRANSMITTER_BLOCK__SHIFT 0x5
+#define ACP_I2SMICSP_COMP_PARAM_1__I2SMICSP_RECEIVER_BLOCK_MASK 0x40
+#define ACP_I2SMICSP_COMP_PARAM_1__I2SMICSP_RECEIVER_BLOCK__SHIFT 0x6
+#define ACP_I2SMICSP_COMP_PARAM_1__I2SMICSP_RX_CHANNLES_MASK 0x180
+#define ACP_I2SMICSP_COMP_PARAM_1__I2SMICSP_RX_CHANNLES__SHIFT 0x7
+#define ACP_I2SMICSP_COMP_PARAM_1__I2SMICSP_TX_CHANNLES_MASK 0x600
+#define ACP_I2SMICSP_COMP_PARAM_1__I2SMICSP_TX_CHANNLES__SHIFT 0x9
+#define ACP_I2SMICSP_COMP_PARAM_1__I2SMICSP_TX_WORDSIZE_0_MASK 0x70000
+#define ACP_I2SMICSP_COMP_PARAM_1__I2SMICSP_TX_WORDSIZE_0__SHIFT 0x10
+#define ACP_I2SMICSP_COMP_PARAM_1__I2SMICSP_TX_WORDSIZE_1_MASK 0x380000
+#define ACP_I2SMICSP_COMP_PARAM_1__I2SMICSP_TX_WORDSIZE_1__SHIFT 0x13
+#define ACP_I2SMICSP_COMP_PARAM_1__I2SMICSP_TX_WORDSIZE_2_MASK 0x1c00000
+#define ACP_I2SMICSP_COMP_PARAM_1__I2SMICSP_TX_WORDSIZE_2__SHIFT 0x16
+#define ACP_I2SMICSP_COMP_PARAM_1__I2SMICSP_TX_WORDSIZE_3_MASK 0xe000000
+#define ACP_I2SMICSP_COMP_PARAM_1__I2SMICSP_TX_WORDSIZE_3__SHIFT 0x19
+#define ACP_I2SMICSP_COMP_VERSION__I2SMICSP_APB_DATA_WIDTH_MASK 0xffffffff
+#define ACP_I2SMICSP_COMP_VERSION__I2SMICSP_APB_DATA_WIDTH__SHIFT 0x0
+#define ACP_I2SMICSP_COMP_TYPE__I2SMICSP_COMP_TYPE_MASK 0xffffffff
+#define ACP_I2SMICSP_COMP_TYPE__I2SMICSP_COMP_TYPE__SHIFT 0x0
+#define ACP_I2SBT_IER__I2SBT_IEN_MASK 0x1
+#define ACP_I2SBT_IER__I2SBT_IEN__SHIFT 0x0
+#define ACP_I2SBT_IRER__I2SBT_RXEN_MASK 0x1
+#define ACP_I2SBT_IRER__I2SBT_RXEN__SHIFT 0x0
+#define ACP_I2SBT_ITER__I2SBT_TXEN_MASK 0x1
+#define ACP_I2SBT_ITER__I2SBT_TXEN__SHIFT 0x0
+#define ACP_I2SBT_CER__I2SBT_CLKEN_MASK 0x1
+#define ACP_I2SBT_CER__I2SBT_CLKEN__SHIFT 0x0
+#define ACP_I2SBT_CCR__I2SBT_SCLKG_MASK 0x7
+#define ACP_I2SBT_CCR__I2SBT_SCLKG__SHIFT 0x0
+#define ACP_I2SBT_CCR__I2SBT_WSS_MASK 0x18
+#define ACP_I2SBT_CCR__I2SBT_WSS__SHIFT 0x3
+#define ACP_I2SBT_RXFFR__I2SBT_RXFFR_MASK 0x1
+#define ACP_I2SBT_RXFFR__I2SBT_RXFFR__SHIFT 0x0
+#define ACP_I2SBT_TXFFR__I2SBT_TXFFR_MASK 0x1
+#define ACP_I2SBT_TXFFR__I2SBT_TXFFR__SHIFT 0x0
+#define ACP_I2SBT_LRBR0__I2SBT_LRBR0_MASK 0xffffffff
+#define ACP_I2SBT_LRBR0__I2SBT_LRBR0__SHIFT 0x0
+#define ACP_I2SBT_RRBR0__I2SBT_RRBR0_MASK 0xffffffff
+#define ACP_I2SBT_RRBR0__I2SBT_RRBR0__SHIFT 0x0
+#define ACP_I2SBT_RER0__I2SBT_RXCHEN0_MASK 0x1
+#define ACP_I2SBT_RER0__I2SBT_RXCHEN0__SHIFT 0x0
+#define ACP_I2SBT_TER0__I2SBT_TXCHEN0_MASK 0x1
+#define ACP_I2SBT_TER0__I2SBT_TXCHEN0__SHIFT 0x0
+#define ACP_I2SBT_RCR0__I2SBT_WLEN_MASK 0x7
+#define ACP_I2SBT_RCR0__I2SBT_WLEN__SHIFT 0x0
+#define ACP_I2SBT_TCR0__I2SBT_WLEN_MASK 0x7
+#define ACP_I2SBT_TCR0__I2SBT_WLEN__SHIFT 0x0
+#define ACP_I2SBT_ISR0__I2SBT_RXDA_MASK 0x1
+#define ACP_I2SBT_ISR0__I2SBT_RXDA__SHIFT 0x0
+#define ACP_I2SBT_ISR0__I2SBT_RXFO_MASK 0x2
+#define ACP_I2SBT_ISR0__I2SBT_RXFO__SHIFT 0x1
+#define ACP_I2SBT_ISR0__I2SBT_TXFE_MASK 0x10
+#define ACP_I2SBT_ISR0__I2SBT_TXFE__SHIFT 0x4
+#define ACP_I2SBT_ISR0__I2SBT_TXFO_MASK 0x20
+#define ACP_I2SBT_ISR0__I2SBT_TXFO__SHIFT 0x5
+#define ACP_I2SBT_IMR0__I2SBT_RXDAM_MASK 0x1
+#define ACP_I2SBT_IMR0__I2SBT_RXDAM__SHIFT 0x0
+#define ACP_I2SBT_IMR0__I2SBT_RXFOM_MASK 0x2
+#define ACP_I2SBT_IMR0__I2SBT_RXFOM__SHIFT 0x1
+#define ACP_I2SBT_IMR0__I2SBT_TXFEM_MASK 0x10
+#define ACP_I2SBT_IMR0__I2SBT_TXFEM__SHIFT 0x4
+#define ACP_I2SBT_IMR0__I2SBT_TXFOM_MASK 0x20
+#define ACP_I2SBT_IMR0__I2SBT_TXFOM__SHIFT 0x5
+#define ACP_I2SBT_ROR0__I2SBT_RXCHO_MASK 0x1
+#define ACP_I2SBT_ROR0__I2SBT_RXCHO__SHIFT 0x0
+#define ACP_I2SBT_TOR0__I2SBT_TXCHO_MASK 0x1
+#define ACP_I2SBT_TOR0__I2SBT_TXCHO__SHIFT 0x0
+#define ACP_I2SBT_RFCR0__I2SBT_RXCHDT_MASK 0xf
+#define ACP_I2SBT_RFCR0__I2SBT_RXCHDT__SHIFT 0x0
+#define ACP_I2SBT_TFCR0__I2SBT_TXCHET_MASK 0xf
+#define ACP_I2SBT_TFCR0__I2SBT_TXCHET__SHIFT 0x0
+#define ACP_I2SBT_RFF0__I2SBT_RXCHFR_MASK 0x1
+#define ACP_I2SBT_RFF0__I2SBT_RXCHFR__SHIFT 0x0
+#define ACP_I2SBT_TFF0__I2SBT_TXCHFR_MASK 0x1
+#define ACP_I2SBT_TFF0__I2SBT_TXCHFR__SHIFT 0x0
+#define ACP_I2SBT_LRBR1__I2SBT_LRBR1_MASK 0xffffffff
+#define ACP_I2SBT_LRBR1__I2SBT_LRBR1__SHIFT 0x0
+#define ACP_I2SBT_RRBR1__I2SBT_RRBR1_MASK 0xffffffff
+#define ACP_I2SBT_RRBR1__I2SBT_RRBR1__SHIFT 0x0
+#define ACP_I2SBT_RER1__I2SBT_RXCHEN1_MASK 0x1
+#define ACP_I2SBT_RER1__I2SBT_RXCHEN1__SHIFT 0x0
+#define ACP_I2SBT_TER1__I2SBT_TXCHEN1_MASK 0x1
+#define ACP_I2SBT_TER1__I2SBT_TXCHEN1__SHIFT 0x0
+#define ACP_I2SBT_RCR1__I2SBT_WLEN_MASK 0x7
+#define ACP_I2SBT_RCR1__I2SBT_WLEN__SHIFT 0x0
+#define ACP_I2SBT_TCR1__I2SBT_WLEN_MASK 0x7
+#define ACP_I2SBT_TCR1__I2SBT_WLEN__SHIFT 0x0
+#define ACP_I2SBT_ISR1__I2SBT_RXDA_MASK 0x1
+#define ACP_I2SBT_ISR1__I2SBT_RXDA__SHIFT 0x0
+#define ACP_I2SBT_ISR1__I2SBT_RXFO_MASK 0x2
+#define ACP_I2SBT_ISR1__I2SBT_RXFO__SHIFT 0x1
+#define ACP_I2SBT_ISR1__I2SBT_TXFE_MASK 0x10
+#define ACP_I2SBT_ISR1__I2SBT_TXFE__SHIFT 0x4
+#define ACP_I2SBT_ISR1__I2SBT_TXFO_MASK 0x20
+#define ACP_I2SBT_ISR1__I2SBT_TXFO__SHIFT 0x5
+#define ACP_I2SBT_IMR1__I2SBT_RXDAM_MASK 0x1
+#define ACP_I2SBT_IMR1__I2SBT_RXDAM__SHIFT 0x0
+#define ACP_I2SBT_IMR1__I2SBT_RXFOM_MASK 0x2
+#define ACP_I2SBT_IMR1__I2SBT_RXFOM__SHIFT 0x1
+#define ACP_I2SBT_IMR1__I2SBT_TXFEM_MASK 0x10
+#define ACP_I2SBT_IMR1__I2SBT_TXFEM__SHIFT 0x4
+#define ACP_I2SBT_IMR1__I2SBT_TXFOM_MASK 0x20
+#define ACP_I2SBT_IMR1__I2SBT_TXFOM__SHIFT 0x5
+#define ACP_I2SBT_ROR1__I2SBT_RXCHO_MASK 0x1
+#define ACP_I2SBT_ROR1__I2SBT_RXCHO__SHIFT 0x0
+#define ACP_I2SBT_TOR1__I2SBT_TXCHO_MASK 0x1
+#define ACP_I2SBT_TOR1__I2SBT_TXCHO__SHIFT 0x0
+#define ACP_I2SBT_RFCR1__I2SBT_RXCHDT_MASK 0xf
+#define ACP_I2SBT_RFCR1__I2SBT_RXCHDT__SHIFT 0x0
+#define ACP_I2SBT_TFCR1__I2SBT_TXCHET_MASK 0xf
+#define ACP_I2SBT_TFCR1__I2SBT_TXCHET__SHIFT 0x0
+#define ACP_I2SBT_RFF1__I2SBT_RXCHFR_MASK 0x1
+#define ACP_I2SBT_RFF1__I2SBT_RXCHFR__SHIFT 0x0
+#define ACP_I2SBT_TFF1__I2SBT_TXCHFR_MASK 0x1
+#define ACP_I2SBT_TFF1__I2SBT_TXCHFR__SHIFT 0x0
+#define ACP_I2SBT_RXDMA__I2SBT_RXDMA_MASK 0xffffffff
+#define ACP_I2SBT_RXDMA__I2SBT_RXDMA__SHIFT 0x0
+#define ACP_I2SBT_RRXDMA__I2SBT_RRXDMA_MASK 0x1
+#define ACP_I2SBT_RRXDMA__I2SBT_RRXDMA__SHIFT 0x0
+#define ACP_I2SBT_TXDMA__I2SBT_TXDMA_MASK 0xffffffff
+#define ACP_I2SBT_TXDMA__I2SBT_TXDMA__SHIFT 0x0
+#define ACP_I2SBT_RTXDMA__I2SBT_RTXDMA_MASK 0x1
+#define ACP_I2SBT_RTXDMA__I2SBT_RTXDMA__SHIFT 0x0
+#define ACP_I2SBT_COMP_PARAM_2__I2SBT_RX_WPRDSIZE_0_MASK 0x7
+#define ACP_I2SBT_COMP_PARAM_2__I2SBT_RX_WPRDSIZE_0__SHIFT 0x0
+#define ACP_I2SBT_COMP_PARAM_2__I2SBT_RX_WPRDSIZE_1_MASK 0x38
+#define ACP_I2SBT_COMP_PARAM_2__I2SBT_RX_WPRDSIZE_1__SHIFT 0x3
+#define ACP_I2SBT_COMP_PARAM_2__I2SBT_RX_WPRDSIZE_2_MASK 0x380
+#define ACP_I2SBT_COMP_PARAM_2__I2SBT_RX_WPRDSIZE_2__SHIFT 0x7
+#define ACP_I2SBT_COMP_PARAM_2__I2SBT_RX_WPRDSIZE_3_MASK 0x1c00
+#define ACP_I2SBT_COMP_PARAM_2__I2SBT_RX_WPRDSIZE_3__SHIFT 0xa
+#define ACP_I2SBT_COMP_PARAM_1__I2SBT_APB_DATA_WIDTH_MASK 0x3
+#define ACP_I2SBT_COMP_PARAM_1__I2SBT_APB_DATA_WIDTH__SHIFT 0x0
+#define ACP_I2SBT_COMP_PARAM_1__I2SBT_FIFO_DEPTH_GLOBAL_MASK 0xc
+#define ACP_I2SBT_COMP_PARAM_1__I2SBT_FIFO_DEPTH_GLOBAL__SHIFT 0x2
+#define ACP_I2SBT_COMP_PARAM_1__I2SBT_MODE_EN_MASK 0x10
+#define ACP_I2SBT_COMP_PARAM_1__I2SBT_MODE_EN__SHIFT 0x4
+#define ACP_I2SBT_COMP_PARAM_1__I2SBT_TRANSMITTER_BLOCK_MASK 0x20
+#define ACP_I2SBT_COMP_PARAM_1__I2SBT_TRANSMITTER_BLOCK__SHIFT 0x5
+#define ACP_I2SBT_COMP_PARAM_1__I2SBT_RECEIVER_BLOCK_MASK 0x40
+#define ACP_I2SBT_COMP_PARAM_1__I2SBT_RECEIVER_BLOCK__SHIFT 0x6
+#define ACP_I2SBT_COMP_PARAM_1__I2SBT_RX_CHANNLES_MASK 0x180
+#define ACP_I2SBT_COMP_PARAM_1__I2SBT_RX_CHANNLES__SHIFT 0x7
+#define ACP_I2SBT_COMP_PARAM_1__I2SBT_TX_CHANNLES_MASK 0x600
+#define ACP_I2SBT_COMP_PARAM_1__I2SBT_TX_CHANNLES__SHIFT 0x9
+#define ACP_I2SBT_COMP_PARAM_1__I2SBT_TX_WORDSIZE_0_MASK 0x70000
+#define ACP_I2SBT_COMP_PARAM_1__I2SBT_TX_WORDSIZE_0__SHIFT 0x10
+#define ACP_I2SBT_COMP_PARAM_1__I2SBT_TX_WORDSIZE_1_MASK 0x380000
+#define ACP_I2SBT_COMP_PARAM_1__I2SBT_TX_WORDSIZE_1__SHIFT 0x13
+#define ACP_I2SBT_COMP_PARAM_1__I2SBT_TX_WORDSIZE_2_MASK 0x1c00000
+#define ACP_I2SBT_COMP_PARAM_1__I2SBT_TX_WORDSIZE_2__SHIFT 0x16
+#define ACP_I2SBT_COMP_PARAM_1__I2SBT_TX_WORDSIZE_3_MASK 0xe000000
+#define ACP_I2SBT_COMP_PARAM_1__I2SBT_TX_WORDSIZE_3__SHIFT 0x19
+#define ACP_I2SBT_COMP_VERSION__I2SBT_APB_DATA_WIDTH_MASK 0xffffffff
+#define ACP_I2SBT_COMP_VERSION__I2SBT_APB_DATA_WIDTH__SHIFT 0x0
+#define ACP_I2SBT_COMP_TYPE__I2SBT_COMP_TYPE_MASK 0xffffffff
+#define ACP_I2SBT_COMP_TYPE__I2SBT_COMP_TYPE__SHIFT 0x0
+
+#endif /* ACP_2_2_SH_MASK_H */
index 2d30464b81cef315b2faf29f6dc21352b38c60d2..06e099e802df94039328fdb677480cda521021fb 100644 (file)
@@ -68,4 +68,13 @@ config SND_ATMEL_SOC_CLASSD
        help
          Say Y if you want to add support for Atmel ASoC driver for boards using
          CLASSD.
+
+config SND_ATMEL_SOC_PDMIC
+       tristate "Atmel ASoC driver for boards using PDMIC"
+       depends on OF && (ARCH_AT91 || COMPILE_TEST)
+       select SND_SOC_GENERIC_DMAENGINE_PCM
+       select REGMAP_MMIO
+       help
+         Say Y if you want to add support for Atmel ASoC driver for boards using
+         PDMIC.
 endif
index f6f7db4282164a7b15ffcc52535ca64c9296e045..a2b127bd9c8717ac6c1501eff669014c306058a5 100644 (file)
@@ -12,8 +12,10 @@ snd-soc-sam9g20-wm8731-objs := sam9g20_wm8731.o
 snd-atmel-soc-wm8904-objs := atmel_wm8904.o
 snd-soc-sam9x5-wm8731-objs := sam9x5_wm8731.o
 snd-atmel-soc-classd-objs := atmel-classd.o
+snd-atmel-soc-pdmic-objs := atmel-pdmic.o
 
 obj-$(CONFIG_SND_AT91_SOC_SAM9G20_WM8731) += snd-soc-sam9g20-wm8731.o
 obj-$(CONFIG_SND_ATMEL_SOC_WM8904) += snd-atmel-soc-wm8904.o
 obj-$(CONFIG_SND_AT91_SOC_SAM9X5_WM8731) += snd-soc-sam9x5-wm8731.o
 obj-$(CONFIG_SND_ATMEL_SOC_CLASSD) += snd-atmel-soc-classd.o
+obj-$(CONFIG_SND_ATMEL_SOC_PDMIC) += snd-atmel-soc-pdmic.o
index 8276675730ef1252483b4a5e1d2b649bf71dfe1e..6107de9c538b51d27c0f09888e14b56592fad68e 100644 (file)
@@ -106,7 +106,7 @@ static const struct snd_pcm_hardware atmel_classd_hw = {
        .rates                  = ATMEL_CLASSD_RATES,
        .rate_min               = 8000,
        .rate_max               = 96000,
-       .channels_min           = 2,
+       .channels_min           = 1,
        .channels_max           = 2,
        .buffer_bytes_max       = 64 * 1024,
        .period_bytes_min       = 256,
@@ -145,7 +145,7 @@ static const struct snd_soc_dai_ops atmel_classd_cpu_dai_ops = {
 
 static struct snd_soc_dai_driver atmel_classd_cpu_dai = {
        .playback = {
-               .channels_min   = 2,
+               .channels_min   = 1,
                .channels_max   = 2,
                .rates          = ATMEL_CLASSD_RATES,
                .formats        = SNDRV_PCM_FMTBIT_S16_LE,},
@@ -171,9 +171,13 @@ atmel_classd_platform_configure_dma(struct snd_pcm_substream *substream,
                return -EINVAL;
        }
 
+       if (params_channels(params) == 1)
+               slave_config->dst_addr_width = DMA_SLAVE_BUSWIDTH_2_BYTES;
+       else
+               slave_config->dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
+
        slave_config->direction         = DMA_MEM_TO_DEV;
        slave_config->dst_addr          = dd->phy_base + CLASSD_THR;
-       slave_config->dst_addr_width    = DMA_SLAVE_BUSWIDTH_4_BYTES;
        slave_config->dst_maxburst      = 1;
        slave_config->src_maxburst      = 1;
        slave_config->device_fc         = false;
@@ -486,7 +490,7 @@ static struct snd_soc_dai_driver atmel_classd_codec_dai = {
        .name = ATMEL_CLASSD_CODEC_DAI_NAME,
        .playback = {
                .stream_name    = "Playback",
-               .channels_min   = 2,
+               .channels_min   = 1,
                .channels_max   = 2,
                .rates          = ATMEL_CLASSD_RATES,
                .formats        = SNDRV_PCM_FMTBIT_S16_LE,
@@ -636,8 +640,10 @@ static int atmel_classd_probe(struct platform_device *pdev)
 
        /* register sound card */
        card = devm_kzalloc(dev, sizeof(*card), GFP_KERNEL);
-       if (!card)
-               return -ENOMEM;
+       if (!card) {
+               ret = -ENOMEM;
+               goto unregister_codec;
+       }
 
        snd_soc_card_set_drvdata(card, dd);
        platform_set_drvdata(pdev, card);
@@ -645,16 +651,20 @@ static int atmel_classd_probe(struct platform_device *pdev)
        ret = atmel_classd_asoc_card_init(dev, card);
        if (ret) {
                dev_err(dev, "failed to init sound card\n");
-               return ret;
+               goto unregister_codec;
        }
 
        ret = devm_snd_soc_register_card(dev, card);
        if (ret) {
                dev_err(dev, "failed to register sound card: %d\n", ret);
-               return ret;
+               goto unregister_codec;
        }
 
        return 0;
+
+unregister_codec:
+       snd_soc_unregister_codec(dev);
+       return ret;
 }
 
 static int atmel_classd_remove(struct platform_device *pdev)
diff --git a/sound/soc/atmel/atmel-pdmic.c b/sound/soc/atmel/atmel-pdmic.c
new file mode 100644 (file)
index 0000000..aee4787
--- /dev/null
@@ -0,0 +1,738 @@
+/* Atmel PDMIC driver
+ *
+ * Copyright (C) 2015 Atmel
+ *
+ * Author: Songjun Wu <songjun.wu@atmel.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 or later
+ * as published by the Free Software Foundation.
+ */
+
+#include <linux/of.h>
+#include <linux/clk.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+#include <sound/core.h>
+#include <sound/dmaengine_pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/tlv.h>
+#include "atmel-pdmic.h"
+
+struct atmel_pdmic_pdata {
+       u32 mic_min_freq;
+       u32 mic_max_freq;
+       s32 mic_offset;
+       const char *card_name;
+};
+
+struct atmel_pdmic {
+       dma_addr_t phy_base;
+       struct regmap *regmap;
+       struct clk *pclk;
+       struct clk *gclk;
+       int irq;
+       struct snd_pcm_substream *substream;
+       const struct atmel_pdmic_pdata *pdata;
+};
+
+static const struct of_device_id atmel_pdmic_of_match[] = {
+       {
+               .compatible = "atmel,sama5d2-pdmic",
+       }, {
+               /* sentinel */
+       }
+};
+MODULE_DEVICE_TABLE(of, atmel_pdmic_of_match);
+
+#define PDMIC_OFFSET_MAX_VAL   S16_MAX
+#define PDMIC_OFFSET_MIN_VAL   S16_MIN
+
+static struct atmel_pdmic_pdata *atmel_pdmic_dt_init(struct device *dev)
+{
+       struct device_node *np = dev->of_node;
+       struct atmel_pdmic_pdata *pdata;
+
+       if (!np) {
+               dev_err(dev, "device node not found\n");
+               return ERR_PTR(-EINVAL);
+       }
+
+       pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);
+       if (!pdata)
+               return ERR_PTR(-ENOMEM);
+
+       if (of_property_read_string(np, "atmel,model", &pdata->card_name))
+               pdata->card_name = "PDMIC";
+
+       if (of_property_read_u32(np, "atmel,mic-min-freq",
+                                &pdata->mic_min_freq)) {
+               dev_err(dev, "failed to get mic-min-freq\n");
+               return ERR_PTR(-EINVAL);
+       }
+
+       if (of_property_read_u32(np, "atmel,mic-max-freq",
+                                &pdata->mic_max_freq)) {
+               dev_err(dev, "failed to get mic-max-freq\n");
+               return ERR_PTR(-EINVAL);
+       }
+
+       if (pdata->mic_max_freq < pdata->mic_min_freq) {
+               dev_err(dev,
+                       "mic-max-freq should not less than mic-min-freq\n");
+               return ERR_PTR(-EINVAL);
+       }
+
+       if (of_property_read_s32(np, "atmel,mic-offset", &pdata->mic_offset))
+               pdata->mic_offset = 0;
+
+       if (pdata->mic_offset > PDMIC_OFFSET_MAX_VAL) {
+               dev_warn(dev,
+                        "mic-offset value %d is larger than the max value %d, the max value is specified\n",
+                        pdata->mic_offset, PDMIC_OFFSET_MAX_VAL);
+               pdata->mic_offset = PDMIC_OFFSET_MAX_VAL;
+       } else if (pdata->mic_offset < PDMIC_OFFSET_MIN_VAL) {
+               dev_warn(dev,
+                        "mic-offset value %d is less than the min value %d, the min value is specified\n",
+                        pdata->mic_offset, PDMIC_OFFSET_MIN_VAL);
+               pdata->mic_offset = PDMIC_OFFSET_MIN_VAL;
+       }
+
+       return pdata;
+}
+
+/* cpu dai component */
+static int atmel_pdmic_cpu_dai_startup(struct snd_pcm_substream *substream,
+                                       struct snd_soc_dai *cpu_dai)
+{
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+       struct atmel_pdmic *dd = snd_soc_card_get_drvdata(rtd->card);
+       int ret;
+
+       ret = clk_prepare_enable(dd->gclk);
+       if (ret)
+               return ret;
+
+       ret =  clk_prepare_enable(dd->pclk);
+       if (ret)
+               return ret;
+
+       /* Clear all bits in the Control Register(PDMIC_CR) */
+       regmap_write(dd->regmap, PDMIC_CR, 0);
+
+       dd->substream = substream;
+
+       /* Enable the overrun error interrupt */
+       regmap_write(dd->regmap, PDMIC_IER, PDMIC_IER_OVRE);
+
+       return 0;
+}
+
+static void atmel_pdmic_cpu_dai_shutdown(struct snd_pcm_substream *substream,
+                                       struct snd_soc_dai *cpu_dai)
+{
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+       struct atmel_pdmic *dd = snd_soc_card_get_drvdata(rtd->card);
+
+       /* Disable the overrun error interrupt */
+       regmap_write(dd->regmap, PDMIC_IDR, PDMIC_IDR_OVRE);
+
+       clk_disable_unprepare(dd->gclk);
+       clk_disable_unprepare(dd->pclk);
+}
+
+static int atmel_pdmic_cpu_dai_prepare(struct snd_pcm_substream *substream,
+                                       struct snd_soc_dai *cpu_dai)
+{
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+       struct atmel_pdmic *dd = snd_soc_card_get_drvdata(rtd->card);
+       u32 val;
+
+       /* Clean the PDMIC Converted Data Register */
+       return regmap_read(dd->regmap, PDMIC_CDR, &val);
+}
+
+static const struct snd_soc_dai_ops atmel_pdmic_cpu_dai_ops = {
+       .startup        = atmel_pdmic_cpu_dai_startup,
+       .shutdown       = atmel_pdmic_cpu_dai_shutdown,
+       .prepare        = atmel_pdmic_cpu_dai_prepare,
+};
+
+#define ATMEL_PDMIC_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S32_LE)
+
+static struct snd_soc_dai_driver atmel_pdmic_cpu_dai = {
+       .capture = {
+               .channels_min   = 1,
+               .channels_max   = 1,
+               .rates          = SNDRV_PCM_RATE_KNOT,
+               .formats        = ATMEL_PDMIC_FORMATS,},
+       .ops = &atmel_pdmic_cpu_dai_ops,
+};
+
+static const struct snd_soc_component_driver atmel_pdmic_cpu_dai_component = {
+       .name = "atmel-pdmic",
+};
+
+/* platform */
+#define ATMEL_PDMIC_MAX_BUF_SIZE  (64 * 1024)
+#define ATMEL_PDMIC_PREALLOC_BUF_SIZE  ATMEL_PDMIC_MAX_BUF_SIZE
+
+static const struct snd_pcm_hardware atmel_pdmic_hw = {
+       .info                   = SNDRV_PCM_INFO_MMAP
+                               | SNDRV_PCM_INFO_MMAP_VALID
+                               | SNDRV_PCM_INFO_INTERLEAVED
+                               | SNDRV_PCM_INFO_RESUME
+                               | SNDRV_PCM_INFO_PAUSE,
+       .formats                = ATMEL_PDMIC_FORMATS,
+       .buffer_bytes_max       = ATMEL_PDMIC_MAX_BUF_SIZE,
+       .period_bytes_min       = 256,
+       .period_bytes_max       = 32 * 1024,
+       .periods_min            = 2,
+       .periods_max            = 256,
+};
+
+static int
+atmel_pdmic_platform_configure_dma(struct snd_pcm_substream *substream,
+                               struct snd_pcm_hw_params *params,
+                               struct dma_slave_config *slave_config)
+{
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+       struct atmel_pdmic *dd = snd_soc_card_get_drvdata(rtd->card);
+       int ret;
+
+       ret = snd_hwparams_to_dma_slave_config(substream, params,
+                                              slave_config);
+       if (ret) {
+               dev_err(rtd->platform->dev,
+                       "hw params to dma slave configure failed\n");
+               return ret;
+       }
+
+       slave_config->src_addr          = dd->phy_base + PDMIC_CDR;
+       slave_config->src_maxburst      = 1;
+       slave_config->dst_maxburst      = 1;
+
+       return 0;
+}
+
+static const struct snd_dmaengine_pcm_config
+atmel_pdmic_dmaengine_pcm_config = {
+       .prepare_slave_config   = atmel_pdmic_platform_configure_dma,
+       .pcm_hardware           = &atmel_pdmic_hw,
+       .prealloc_buffer_size   = ATMEL_PDMIC_PREALLOC_BUF_SIZE,
+};
+
+/* codec */
+/* Mic Gain = dgain * 2^(-scale) */
+struct mic_gain {
+       unsigned int dgain;
+       unsigned int scale;
+};
+
+/* range from -90 dB to 90 dB */
+static const struct mic_gain mic_gain_table[] = {
+{    1, 15}, {    1, 14},                           /* -90, -84 dB */
+{    3, 15}, {    1, 13}, {    3, 14}, {    1, 12}, /* -81, -78, -75, -72 dB */
+{    5, 14}, {   13, 15},                           /* -70, -68 dB */
+{    9, 14}, {   21, 15}, {   23, 15}, {   13, 14}, /* -65 ~ -62 dB */
+{   29, 15}, {   33, 15}, {   37, 15}, {   41, 15}, /* -61 ~ -58 dB */
+{   23, 14}, {   13, 13}, {   58, 15}, {   65, 15}, /* -57 ~ -54 dB */
+{   73, 15}, {   41, 14}, {   23, 13}, {   13, 12}, /* -53 ~ -50 dB */
+{   29, 13}, {   65, 14}, {   73, 14}, {   41, 13}, /* -49 ~ -46 dB */
+{   23, 12}, {  207, 15}, {   29, 12}, {   65, 13}, /* -45 ~ -42 dB */
+{   73, 13}, {   41, 12}, {   23, 11}, {  413, 15}, /* -41 ~ -38 dB */
+{  463, 15}, {  519, 15}, {  583, 15}, {  327, 14}, /* -37 ~ -34 dB */
+{  367, 14}, {  823, 15}, {  231, 13}, { 1036, 15}, /* -33 ~ -30 dB */
+{ 1163, 15}, { 1305, 15}, {  183, 12}, { 1642, 15}, /* -29 ~ -26 dB */
+{ 1843, 15}, { 2068, 15}, {  145, 11}, { 2603, 15}, /* -25 ~ -22 dB */
+{  365, 12}, { 3277, 15}, { 3677, 15}, { 4125, 15}, /* -21 ~ -18 dB */
+{ 4629, 15}, { 5193, 15}, { 5827, 15}, { 3269, 14}, /* -17 ~ -14 dB */
+{  917, 12}, { 8231, 15}, { 9235, 15}, { 5181, 14}, /* -13 ~ -10 dB */
+{11627, 15}, {13045, 15}, {14637, 15}, {16423, 15}, /*  -9 ~ -6 dB */
+{18427, 15}, {20675, 15}, { 5799, 13}, {26029, 15}, /*  -5 ~ -2 dB */
+{ 7301, 13}, {    1,  0}, {18383, 14}, {10313, 13}, /*  -1 ~ 2 dB */
+{23143, 14}, {25967, 14}, {29135, 14}, {16345, 13}, /*   3 ~ 6 dB */
+{ 4585, 11}, {20577, 13}, { 1443,  9}, {25905, 13}, /*   7 ~ 10 dB */
+{14533, 12}, { 8153, 11}, { 2287,  9}, {20529, 12}, /*  11 ~ 14 dB */
+{11517, 11}, { 6461, 10}, {28997, 12}, { 4067,  9}, /*  15 ~ 18 dB */
+{18253, 11}, {   10,  0}, {22979, 11}, {25783, 11}, /*  19 ~ 22 dB */
+{28929, 11}, {32459, 11}, { 9105,  9}, {20431, 10}, /*  23 ~ 26 dB */
+{22925, 10}, {12861,  9}, { 7215,  8}, {16191,  9}, /*  27 ~ 30 dB */
+{ 9083,  8}, {20383,  9}, {11435,  8}, { 6145,  7}, /*  31 ~ 34 dB */
+{ 3599,  6}, {32305,  9}, {18123,  8}, {20335,  8}, /*  35 ~ 38 dB */
+{  713,  3}, {  100,  0}, { 7181,  6}, { 8057,  6}, /*  39 ~ 42 dB */
+{  565,  2}, {20287,  7}, {11381,  6}, {25539,  7}, /*  43 ~ 46 dB */
+{ 1791,  3}, { 4019,  4}, { 9019,  5}, {20239,  6}, /*  47 ~ 50 dB */
+{ 5677,  4}, {25479,  6}, { 7147,  4}, { 8019,  4}, /*  51 ~ 54 dB */
+{17995,  5}, {20191,  5}, {11327,  4}, {12709,  4}, /*  55 ~ 58 dB */
+{ 3565,  2}, { 1000,  0}, { 1122,  0}, { 1259,  0}, /*  59 ~ 62 dB */
+{ 2825,  1}, {12679,  3}, { 7113,  2}, { 7981,  2}, /*  63 ~ 66 dB */
+{ 8955,  2}, {20095,  3}, {22547,  3}, {12649,  2}, /*  67 ~ 70 dB */
+{28385,  3}, { 3981,  0}, {17867,  2}, {20047,  2}, /*  71 ~ 74 dB */
+{11247,  1}, {12619,  1}, {14159,  1}, {31773,  2}, /*  75 ~ 78 dB */
+{17825,  1}, {10000,  0}, {11220,  0}, {12589,  0}, /*  79 ~ 82 dB */
+{28251,  1}, {15849,  0}, {17783,  0}, {19953,  0}, /*  83 ~ 86 dB */
+{22387,  0}, {25119,  0}, {28184,  0}, {31623,  0}, /*  87 ~ 90 dB */
+};
+
+static const DECLARE_TLV_DB_RANGE(mic_gain_tlv,
+       0, 1, TLV_DB_SCALE_ITEM(-9000, 600, 0),
+       2, 5, TLV_DB_SCALE_ITEM(-8100, 300, 0),
+       6, 7, TLV_DB_SCALE_ITEM(-7000, 200, 0),
+       8, ARRAY_SIZE(mic_gain_table)-1, TLV_DB_SCALE_ITEM(-6500, 100, 0),
+);
+
+int pdmic_get_mic_volsw(struct snd_kcontrol *kcontrol,
+       struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
+       unsigned int dgain_val, scale_val;
+       int i;
+
+       dgain_val = (snd_soc_read(codec, PDMIC_DSPR1) & PDMIC_DSPR1_DGAIN_MASK)
+                   >> PDMIC_DSPR1_DGAIN_SHIFT;
+
+       scale_val = (snd_soc_read(codec, PDMIC_DSPR0) & PDMIC_DSPR0_SCALE_MASK)
+                   >> PDMIC_DSPR0_SCALE_SHIFT;
+
+       for (i = 0; i < ARRAY_SIZE(mic_gain_table); i++) {
+               if ((mic_gain_table[i].dgain == dgain_val) &&
+                   (mic_gain_table[i].scale == scale_val))
+                       ucontrol->value.integer.value[0] = i;
+       }
+
+       return 0;
+}
+
+static int pdmic_put_mic_volsw(struct snd_kcontrol *kcontrol,
+       struct snd_ctl_elem_value *ucontrol)
+{
+       struct soc_mixer_control *mc =
+               (struct soc_mixer_control *)kcontrol->private_value;
+       struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
+       int max = mc->max;
+       unsigned int val;
+       int ret;
+
+       val = ucontrol->value.integer.value[0];
+
+       if (val > max)
+               return -EINVAL;
+
+       ret = snd_soc_update_bits(codec, PDMIC_DSPR1, PDMIC_DSPR1_DGAIN_MASK,
+                        mic_gain_table[val].dgain << PDMIC_DSPR1_DGAIN_SHIFT);
+       if (ret < 0)
+               return ret;
+
+       ret = snd_soc_update_bits(codec, PDMIC_DSPR0, PDMIC_DSPR0_SCALE_MASK,
+                        mic_gain_table[val].scale << PDMIC_DSPR0_SCALE_SHIFT);
+       if (ret < 0)
+               return ret;
+
+       return 0;
+}
+
+static const struct snd_kcontrol_new atmel_pdmic_snd_controls[] = {
+SOC_SINGLE_EXT_TLV("Mic Capture Volume", PDMIC_DSPR1, PDMIC_DSPR1_DGAIN_SHIFT,
+                  ARRAY_SIZE(mic_gain_table)-1, 0,
+                  pdmic_get_mic_volsw, pdmic_put_mic_volsw, mic_gain_tlv),
+
+SOC_SINGLE("High Pass Filter Switch", PDMIC_DSPR0,
+          PDMIC_DSPR0_HPFBYP_SHIFT, 1, 1),
+
+SOC_SINGLE("SINCC Filter Switch", PDMIC_DSPR0, PDMIC_DSPR0_SINBYP_SHIFT, 1, 1),
+};
+
+static int atmel_pdmic_codec_probe(struct snd_soc_codec *codec)
+{
+       struct snd_soc_card *card = snd_soc_codec_get_drvdata(codec);
+       struct atmel_pdmic *dd = snd_soc_card_get_drvdata(card);
+
+       snd_soc_update_bits(codec, PDMIC_DSPR1, PDMIC_DSPR1_OFFSET_MASK,
+                    (u32)(dd->pdata->mic_offset << PDMIC_DSPR1_OFFSET_SHIFT));
+
+       return 0;
+}
+
+static struct snd_soc_codec_driver soc_codec_dev_pdmic = {
+       .probe          = atmel_pdmic_codec_probe,
+       .controls       = atmel_pdmic_snd_controls,
+       .num_controls   = ARRAY_SIZE(atmel_pdmic_snd_controls),
+};
+
+/* codec dai component */
+#define PDMIC_MR_PRESCAL_MAX_VAL 127
+
+static int
+atmel_pdmic_codec_dai_hw_params(struct snd_pcm_substream *substream,
+                           struct snd_pcm_hw_params *params,
+                           struct snd_soc_dai *codec_dai)
+{
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+       struct atmel_pdmic *dd = snd_soc_card_get_drvdata(rtd->card);
+       struct snd_soc_codec *codec = codec_dai->codec;
+       unsigned int rate_min = substream->runtime->hw.rate_min;
+       unsigned int rate_max = substream->runtime->hw.rate_max;
+       int fs = params_rate(params);
+       int bits = params_width(params);
+       unsigned long pclk_rate, gclk_rate;
+       unsigned int f_pdmic;
+       u32 mr_val, dspr0_val, pclk_prescal, gclk_prescal;
+
+       if (params_channels(params) != 1) {
+               dev_err(codec->dev,
+                       "only supports one channel\n");
+               return -EINVAL;
+       }
+
+       if ((fs < rate_min) || (fs > rate_max)) {
+               dev_err(codec->dev,
+                       "sample rate is %dHz, min rate is %dHz, max rate is %dHz\n",
+                       fs, rate_min, rate_max);
+
+               return -EINVAL;
+       }
+
+       switch (bits) {
+       case 16:
+               dspr0_val = (PDMIC_DSPR0_SIZE_16_BITS
+                            << PDMIC_DSPR0_SIZE_SHIFT);
+               break;
+       case 32:
+               dspr0_val = (PDMIC_DSPR0_SIZE_32_BITS
+                            << PDMIC_DSPR0_SIZE_SHIFT);
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       if ((fs << 7) > (rate_max << 6)) {
+               f_pdmic = fs << 6;
+               dspr0_val |= PDMIC_DSPR0_OSR_64 << PDMIC_DSPR0_OSR_SHIFT;
+       } else {
+               f_pdmic = fs << 7;
+               dspr0_val |= PDMIC_DSPR0_OSR_128 << PDMIC_DSPR0_OSR_SHIFT;
+       }
+
+       pclk_rate = clk_get_rate(dd->pclk);
+       gclk_rate = clk_get_rate(dd->gclk);
+
+       /* PRESCAL = SELCK/(2*f_pdmic) - 1*/
+       pclk_prescal = (u32)(pclk_rate/(f_pdmic << 1)) - 1;
+       gclk_prescal = (u32)(gclk_rate/(f_pdmic << 1)) - 1;
+
+       if ((pclk_prescal > PDMIC_MR_PRESCAL_MAX_VAL) ||
+           (gclk_rate/((gclk_prescal + 1) << 1) <
+            pclk_rate/((pclk_prescal + 1) << 1))) {
+               mr_val = gclk_prescal << PDMIC_MR_PRESCAL_SHIFT;
+               mr_val |= PDMIC_MR_CLKS_GCK << PDMIC_MR_CLKS_SHIFT;
+       } else {
+               mr_val = pclk_prescal << PDMIC_MR_PRESCAL_SHIFT;
+               mr_val |= PDMIC_MR_CLKS_PCK << PDMIC_MR_CLKS_SHIFT;
+       }
+
+       snd_soc_update_bits(codec, PDMIC_MR,
+               PDMIC_MR_PRESCAL_MASK | PDMIC_MR_CLKS_MASK, mr_val);
+
+       snd_soc_update_bits(codec, PDMIC_DSPR0,
+               PDMIC_DSPR0_OSR_MASK | PDMIC_DSPR0_SIZE_MASK, dspr0_val);
+
+       return 0;
+}
+
+static int atmel_pdmic_codec_dai_prepare(struct snd_pcm_substream *substream,
+                                       struct snd_soc_dai *codec_dai)
+{
+       struct snd_soc_codec *codec = codec_dai->codec;
+
+       snd_soc_update_bits(codec, PDMIC_CR, PDMIC_CR_ENPDM_MASK,
+                           PDMIC_CR_ENPDM_DIS << PDMIC_CR_ENPDM_SHIFT);
+
+       return 0;
+}
+
+static int atmel_pdmic_codec_dai_trigger(struct snd_pcm_substream *substream,
+                                       int cmd, struct snd_soc_dai *codec_dai)
+{
+       struct snd_soc_codec *codec = codec_dai->codec;
+       u32 val;
+
+       switch (cmd) {
+       case SNDRV_PCM_TRIGGER_START:
+       case SNDRV_PCM_TRIGGER_RESUME:
+       case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+               val = PDMIC_CR_ENPDM_EN << PDMIC_CR_ENPDM_SHIFT;
+               break;
+       case SNDRV_PCM_TRIGGER_STOP:
+       case SNDRV_PCM_TRIGGER_SUSPEND:
+       case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+               val = PDMIC_CR_ENPDM_DIS << PDMIC_CR_ENPDM_SHIFT;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       snd_soc_update_bits(codec, PDMIC_CR, PDMIC_CR_ENPDM_MASK, val);
+
+       return 0;
+}
+
+static const struct snd_soc_dai_ops atmel_pdmic_codec_dai_ops = {
+       .hw_params      = atmel_pdmic_codec_dai_hw_params,
+       .prepare        = atmel_pdmic_codec_dai_prepare,
+       .trigger        = atmel_pdmic_codec_dai_trigger,
+};
+
+#define ATMEL_PDMIC_CODEC_DAI_NAME  "atmel-pdmic-hifi"
+
+static struct snd_soc_dai_driver atmel_pdmic_codec_dai = {
+       .name = ATMEL_PDMIC_CODEC_DAI_NAME,
+       .capture = {
+               .stream_name    = "Capture",
+               .channels_min   = 1,
+               .channels_max   = 1,
+               .rates          = SNDRV_PCM_RATE_KNOT,
+               .formats        = ATMEL_PDMIC_FORMATS,
+       },
+       .ops = &atmel_pdmic_codec_dai_ops,
+};
+
+/* ASoC sound card */
+static int atmel_pdmic_asoc_card_init(struct device *dev,
+                               struct snd_soc_card *card)
+{
+       struct snd_soc_dai_link *dai_link;
+       struct atmel_pdmic *dd = snd_soc_card_get_drvdata(card);
+
+       dai_link = devm_kzalloc(dev, sizeof(*dai_link), GFP_KERNEL);
+       if (!dai_link)
+               return -ENOMEM;
+
+       dai_link->name                  = "PDMIC";
+       dai_link->stream_name           = "PDMIC PCM";
+       dai_link->codec_dai_name        = ATMEL_PDMIC_CODEC_DAI_NAME;
+       dai_link->cpu_dai_name          = dev_name(dev);
+       dai_link->codec_name            = dev_name(dev);
+       dai_link->platform_name         = dev_name(dev);
+
+       card->dai_link  = dai_link;
+       card->num_links = 1;
+       card->name      = dd->pdata->card_name;
+       card->dev       = dev;
+
+       return 0;
+}
+
+static void atmel_pdmic_get_sample_rate(struct atmel_pdmic *dd,
+       unsigned int *rate_min, unsigned int *rate_max)
+{
+       u32 mic_min_freq = dd->pdata->mic_min_freq;
+       u32 mic_max_freq = dd->pdata->mic_max_freq;
+       u32 clk_max_rate = (u32)(clk_get_rate(dd->pclk) >> 1);
+       u32 clk_min_rate = (u32)(clk_get_rate(dd->gclk) >> 8);
+
+       if (mic_max_freq > clk_max_rate)
+               mic_max_freq = clk_max_rate;
+
+       if (mic_min_freq < clk_min_rate)
+               mic_min_freq = clk_min_rate;
+
+       *rate_min = DIV_ROUND_CLOSEST(mic_min_freq, 128);
+       *rate_max = mic_max_freq >> 6;
+}
+
+/* PDMIC interrupt handler */
+static irqreturn_t atmel_pdmic_interrupt(int irq, void *dev_id)
+{
+       struct atmel_pdmic *dd = (struct atmel_pdmic *)dev_id;
+       u32 pdmic_isr;
+       irqreturn_t ret = IRQ_NONE;
+
+       regmap_read(dd->regmap, PDMIC_ISR, &pdmic_isr);
+
+       if (pdmic_isr & PDMIC_ISR_OVRE) {
+               regmap_update_bits(dd->regmap, PDMIC_CR, PDMIC_CR_ENPDM_MASK,
+                                  PDMIC_CR_ENPDM_DIS << PDMIC_CR_ENPDM_SHIFT);
+
+               snd_pcm_stop_xrun(dd->substream);
+
+               ret = IRQ_HANDLED;
+       }
+
+       return ret;
+}
+
+/* regmap configuration */
+#define ATMEL_PDMIC_REG_MAX    0x124
+static const struct regmap_config atmel_pdmic_regmap_config = {
+       .reg_bits       = 32,
+       .reg_stride     = 4,
+       .val_bits       = 32,
+       .max_register   = ATMEL_PDMIC_REG_MAX,
+};
+
+static int atmel_pdmic_probe(struct platform_device *pdev)
+{
+       struct device *dev = &pdev->dev;
+       struct atmel_pdmic *dd;
+       struct resource *res;
+       void __iomem *io_base;
+       const struct atmel_pdmic_pdata *pdata;
+       struct snd_soc_card *card;
+       unsigned int rate_min, rate_max;
+       int ret;
+
+       pdata = atmel_pdmic_dt_init(dev);
+       if (IS_ERR(pdata))
+               return PTR_ERR(pdata);
+
+       dd = devm_kzalloc(dev, sizeof(*dd), GFP_KERNEL);
+       if (!dd)
+               return -ENOMEM;
+
+       dd->pdata = pdata;
+
+       dd->irq = platform_get_irq(pdev, 0);
+       if (dd->irq < 0) {
+               ret = dd->irq;
+               dev_err(dev, "failed to could not get irq: %d\n", ret);
+               return ret;
+       }
+
+       dd->pclk = devm_clk_get(dev, "pclk");
+       if (IS_ERR(dd->pclk)) {
+               ret = PTR_ERR(dd->pclk);
+               dev_err(dev, "failed to get peripheral clock: %d\n", ret);
+               return ret;
+       }
+
+       dd->gclk = devm_clk_get(dev, "gclk");
+       if (IS_ERR(dd->gclk)) {
+               ret = PTR_ERR(dd->gclk);
+               dev_err(dev, "failed to get GCK: %d\n", ret);
+               return ret;
+       }
+
+       /* The gclk clock frequency must always be tree times
+        * lower than the pclk clock frequency
+        */
+       ret = clk_set_rate(dd->gclk, clk_get_rate(dd->pclk)/3);
+       if (ret) {
+               dev_err(dev, "failed to set GCK clock rate: %d\n", ret);
+               return ret;
+       }
+
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       if (!res) {
+               dev_err(dev, "no memory resource\n");
+               return -ENXIO;
+       }
+
+       io_base = devm_ioremap_resource(dev, res);
+       if (IS_ERR(io_base)) {
+               ret = PTR_ERR(io_base);
+               dev_err(dev, "failed to remap register memory: %d\n", ret);
+               return ret;
+       }
+
+       dd->phy_base = res->start;
+
+       dd->regmap = devm_regmap_init_mmio(dev, io_base,
+                                          &atmel_pdmic_regmap_config);
+       if (IS_ERR(dd->regmap)) {
+               ret = PTR_ERR(dd->regmap);
+               dev_err(dev, "failed to init register map: %d\n", ret);
+               return ret;
+       }
+
+       ret =  devm_request_irq(dev, dd->irq, atmel_pdmic_interrupt, 0,
+                               "PDMIC", (void *)dd);
+       if (ret < 0) {
+               dev_err(dev, "can't register ISR for IRQ %u (ret=%i)\n",
+                       dd->irq, ret);
+               return ret;
+       }
+
+       /* Get the minimal and maximal sample rate that micphone supports */
+       atmel_pdmic_get_sample_rate(dd, &rate_min, &rate_max);
+
+       /* register cpu dai */
+       atmel_pdmic_cpu_dai.capture.rate_min = rate_min;
+       atmel_pdmic_cpu_dai.capture.rate_max = rate_max;
+       ret = devm_snd_soc_register_component(dev,
+                                             &atmel_pdmic_cpu_dai_component,
+                                             &atmel_pdmic_cpu_dai, 1);
+       if (ret) {
+               dev_err(dev, "could not register CPU DAI: %d\n", ret);
+               return ret;
+       }
+
+       /* register platform */
+       ret = devm_snd_dmaengine_pcm_register(dev,
+                                            &atmel_pdmic_dmaengine_pcm_config,
+                                            0);
+       if (ret) {
+               dev_err(dev, "could not register platform: %d\n", ret);
+               return ret;
+       }
+
+       /* register codec and codec dai */
+       atmel_pdmic_codec_dai.capture.rate_min = rate_min;
+       atmel_pdmic_codec_dai.capture.rate_max = rate_max;
+       ret = snd_soc_register_codec(dev, &soc_codec_dev_pdmic,
+                                    &atmel_pdmic_codec_dai, 1);
+       if (ret) {
+               dev_err(dev, "could not register codec: %d\n", ret);
+               return ret;
+       }
+
+       /* register sound card */
+       card = devm_kzalloc(dev, sizeof(*card), GFP_KERNEL);
+       if (!card) {
+               ret = -ENOMEM;
+               goto unregister_codec;
+       }
+
+       snd_soc_card_set_drvdata(card, dd);
+       platform_set_drvdata(pdev, card);
+
+       ret = atmel_pdmic_asoc_card_init(dev, card);
+       if (ret) {
+               dev_err(dev, "failed to init sound card: %d\n", ret);
+               goto unregister_codec;
+       }
+
+       ret = devm_snd_soc_register_card(dev, card);
+       if (ret) {
+               dev_err(dev, "failed to register sound card: %d\n", ret);
+               goto unregister_codec;
+       }
+
+       return 0;
+
+unregister_codec:
+       snd_soc_unregister_codec(dev);
+       return ret;
+}
+
+static int atmel_pdmic_remove(struct platform_device *pdev)
+{
+       snd_soc_unregister_codec(&pdev->dev);
+       return 0;
+}
+
+static struct platform_driver atmel_pdmic_driver = {
+       .driver = {
+               .name           = "atmel-pdmic",
+               .of_match_table = of_match_ptr(atmel_pdmic_of_match),
+               .pm             = &snd_soc_pm_ops,
+       },
+       .probe  = atmel_pdmic_probe,
+       .remove = atmel_pdmic_remove,
+};
+module_platform_driver(atmel_pdmic_driver);
+
+MODULE_DESCRIPTION("Atmel PDMIC driver under ALSA SoC architecture");
+MODULE_AUTHOR("Songjun Wu <songjun.wu@atmel.com>");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/atmel/atmel-pdmic.h b/sound/soc/atmel/atmel-pdmic.h
new file mode 100644 (file)
index 0000000..4527ac7
--- /dev/null
@@ -0,0 +1,80 @@
+#ifndef __ATMEL_PDMIC_H_
+#define __ATMEL_PDMIC_H_
+
+#include <linux/bitops.h>
+
+#define PDMIC_CR       0x00000000
+
+#define PDMIC_CR_SWRST         0x1
+#define PDMIC_CR_SWRST_MASK    BIT(0)
+#define PDMIC_CR_SWRST_SHIFT   (0)
+
+#define PDMIC_CR_ENPDM_DIS     0x0
+#define PDMIC_CR_ENPDM_EN      0x1
+#define PDMIC_CR_ENPDM_MASK    BIT(4)
+#define PDMIC_CR_ENPDM_SHIFT   (4)
+
+#define PDMIC_MR       0x00000004
+
+#define PDMIC_MR_CLKS_PCK      0x0
+#define PDMIC_MR_CLKS_GCK      0x1
+#define PDMIC_MR_CLKS_MASK     BIT(4)
+#define PDMIC_MR_CLKS_SHIFT    (4)
+
+#define PDMIC_MR_PRESCAL_MASK  GENMASK(14, 8)
+#define PDMIC_MR_PRESCAL_SHIFT (8)
+
+#define PDMIC_CDR      0x00000014
+
+#define PDMIC_IER      0x00000018
+#define PDMIC_IER_OVRE                 BIT(25)
+
+#define PDMIC_IDR      0x0000001c
+#define PDMIC_IDR_OVRE                 BIT(25)
+
+#define PDMIC_IMR      0x00000020
+
+#define PDMIC_ISR      0x00000024
+#define PDMIC_ISR_OVRE                 BIT(25)
+
+#define PDMIC_DSPR0    0x00000058
+
+#define PDMIC_DSPR0_HPFBYP_DIS         0x1
+#define PDMIC_DSPR0_HPFBYP_EN          0x0
+#define PDMIC_DSPR0_HPFBYP_MASK                BIT(1)
+#define PDMIC_DSPR0_HPFBYP_SHIFT       (1)
+
+#define PDMIC_DSPR0_SINBYP_DIS         0x1
+#define PDMIC_DSPR0_SINBYP_EN          0x0
+#define PDMIC_DSPR0_SINBYP_MASK                BIT(2)
+#define PDMIC_DSPR0_SINBYP_SHIFT       (2)
+
+#define PDMIC_DSPR0_SIZE_16_BITS       0x0
+#define PDMIC_DSPR0_SIZE_32_BITS       0x1
+#define PDMIC_DSPR0_SIZE_MASK          BIT(3)
+#define PDMIC_DSPR0_SIZE_SHIFT         (3)
+
+#define PDMIC_DSPR0_OSR_128            0x0
+#define PDMIC_DSPR0_OSR_64             0x1
+#define PDMIC_DSPR0_OSR_MASK           GENMASK(6, 4)
+#define PDMIC_DSPR0_OSR_SHIFT          (4)
+
+#define PDMIC_DSPR0_SCALE_MASK         GENMASK(11, 8)
+#define PDMIC_DSPR0_SCALE_SHIFT                (8)
+
+#define PDMIC_DSPR0_SHIFT_MASK         GENMASK(15, 12)
+#define PDMIC_DSPR0_SHIFT_SHIFT                (12)
+
+#define PDMIC_DSPR1    0x0000005c
+
+#define PDMIC_DSPR1_DGAIN_MASK         GENMASK(14, 0)
+#define PDMIC_DSPR1_DGAIN_SHIFT                (0)
+
+#define PDMIC_DSPR1_OFFSET_MASK                GENMASK(31, 16)
+#define PDMIC_DSPR1_OFFSET_SHIFT       (16)
+
+#define PDMIC_WPMR     0x000000e4
+
+#define PDMIC_WPSR     0x000000e8
+
+#endif
index 1933bcd46cca043d68db0ecc771124da37416908..fdd28ed3e0b9ec3d6c80e7081dd03b408472f45b 100644 (file)
@@ -183,6 +183,7 @@ static struct platform_driver atmel_asoc_wm8904_driver = {
        .driver = {
                .name = "atmel-wm8904-audio",
                .of_match_table = of_match_ptr(atmel_asoc_wm8904_dt_ids),
+               .pm             = &snd_soc_pm_ops,
        },
        .probe = atmel_asoc_wm8904_probe,
        .remove = atmel_asoc_wm8904_remove,
index 8c435beb263dfc02df2ee714b1abf43a6cbe6bad..3303d5f58082f68b68b535b2bdf7ce8d14cafcc4 100644 (file)
  * General Public License for more details.
  */
 
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/device.h>
 #include <linux/init.h>
+#include <linux/io.h>
 #include <linux/module.h>
-#include <linux/device.h>
 #include <linux/slab.h>
-#include <linux/delay.h>
-#include <linux/io.h>
-#include <linux/clk.h>
 
 #include <sound/core.h>
+#include <sound/dmaengine_pcm.h>
+#include <sound/initval.h>
 #include <sound/pcm.h>
 #include <sound/pcm_params.h>
-#include <sound/initval.h>
 #include <sound/soc.h>
-#include <sound/dmaengine_pcm.h>
 
 /* Clock registers */
 #define BCM2835_CLK_PCMCTL_REG  0x00
index cfdafc4c11ea9a64c465eef6d9ac4ed3520c159a..50693c867e71d06a2b6ccebf0d2f303c1ef9a0f5 100644 (file)
@@ -55,9 +55,11 @@ config SND_SOC_ALL_CODECS
        select SND_SOC_CS4271_SPI if SPI_MASTER
        select SND_SOC_CS42XX8_I2C if I2C
        select SND_SOC_CS4349 if I2C
+       select SND_SOC_CS47L24 if MFD_CS47L24
        select SND_SOC_CX20442 if TTY
        select SND_SOC_DA7210 if SND_SOC_I2C_AND_SPI
        select SND_SOC_DA7213 if I2C
+       select SND_SOC_DA7218 if I2C
        select SND_SOC_DA7219 if I2C
        select SND_SOC_DA732X if I2C
        select SND_SOC_DA9055 if I2C
@@ -66,7 +68,9 @@ config SND_SOC_ALL_CODECS
        select SND_SOC_ES8328_SPI if SPI_MASTER
        select SND_SOC_ES8328_I2C if I2C
        select SND_SOC_GTM601
+       select SND_SOC_HDAC_HDMI
        select SND_SOC_ICS43432
+       select SND_SOC_INNO_RK3036
        select SND_SOC_ISABELLE if I2C
        select SND_SOC_JZ4740_CODEC
        select SND_SOC_LM4857 if I2C
@@ -83,16 +87,20 @@ config SND_SOC_ALL_CODECS
        select SND_SOC_ML26124 if I2C
        select SND_SOC_NAU8825 if I2C
        select SND_SOC_PCM1681 if I2C
-       select SND_SOC_PCM1792A if SPI_MASTER
+       select SND_SOC_PCM179X if SPI_MASTER
        select SND_SOC_PCM3008
+       select SND_SOC_PCM3168A_I2C if I2C
+       select SND_SOC_PCM3168A_SPI if SPI_MASTER
        select SND_SOC_PCM512x_I2C if I2C
        select SND_SOC_PCM512x_SPI if SPI_MASTER
        select SND_SOC_RT286 if I2C
        select SND_SOC_RT298 if I2C
+       select SND_SOC_RT5616 if I2C
        select SND_SOC_RT5631 if I2C
        select SND_SOC_RT5640 if I2C
        select SND_SOC_RT5645 if I2C
        select SND_SOC_RT5651 if I2C
+       select SND_SOC_RT5659 if I2C
        select SND_SOC_RT5670 if I2C
        select SND_SOC_RT5677 if I2C && SPI_MASTER
        select SND_SOC_SGTL5000 if I2C
@@ -195,10 +203,12 @@ config SND_SOC_88PM860X
 
 config SND_SOC_ARIZONA
        tristate
+       default y if SND_SOC_CS47L24=y
        default y if SND_SOC_WM5102=y
        default y if SND_SOC_WM5110=y
        default y if SND_SOC_WM8997=y
        default y if SND_SOC_WM8998=y
+       default m if SND_SOC_CS47L24=m
        default m if SND_SOC_WM5102=m
        default m if SND_SOC_WM5110=m
        default m if SND_SOC_WM8997=m
@@ -211,9 +221,12 @@ config SND_SOC_WM_HUBS
 
 config SND_SOC_WM_ADSP
        tristate
+       select SND_SOC_COMPRESS
+       default y if SND_SOC_CS47L24=y
        default y if SND_SOC_WM5102=y
        default y if SND_SOC_WM5110=y
        default y if SND_SOC_WM2200=y
+       default m if SND_SOC_CS47L24=m
        default m if SND_SOC_WM5102=m
        default m if SND_SOC_WM5110=m
        default m if SND_SOC_WM2200=m
@@ -422,6 +435,9 @@ config SND_SOC_CS4349
        tristate "Cirrus Logic CS4349 CODEC"
        depends on I2C
 
+config SND_SOC_CS47L24
+       tristate
+
 config SND_SOC_CX20442
        tristate
        depends on TTY
@@ -439,6 +455,9 @@ config SND_SOC_DA7210
 config SND_SOC_DA7213
         tristate
 
+config SND_SOC_DA7218
+       tristate
+
 config SND_SOC_DA7219
         tristate
 
@@ -468,9 +487,17 @@ config SND_SOC_ES8328_SPI
 config SND_SOC_GTM601
        tristate 'GTM601 UMTS modem audio codec'
 
+config SND_SOC_HDAC_HDMI
+       tristate
+       select SND_HDA_EXT_CORE
+       select HDMI
+
 config SND_SOC_ICS43432
        tristate
 
+config SND_SOC_INNO_RK3036
+       tristate "Inno codec driver for RK3036 SoC"
+
 config SND_SOC_ISABELLE
         tristate
 
@@ -499,13 +526,28 @@ config SND_SOC_PCM1681
        tristate "Texas Instruments PCM1681 CODEC"
        depends on I2C
 
-config SND_SOC_PCM1792A
-       tristate "Texas Instruments PCM1792A CODEC"
+config SND_SOC_PCM179X
+       tristate "Texas Instruments PCM179X CODEC"
        depends on SPI_MASTER
 
 config SND_SOC_PCM3008
        tristate
 
+config SND_SOC_PCM3168A
+       tristate
+
+config SND_SOC_PCM3168A_I2C
+       tristate "Texas Instruments PCM3168A CODEC - I2C"
+       depends on I2C
+       select SND_SOC_PCM3168A
+       select REGMAP_I2C
+
+config SND_SOC_PCM3168A_SPI
+       tristate "Texas Instruments PCM3168A CODEC - SPI"
+       depends on SPI_MASTER
+       select SND_SOC_PCM3168A
+       select REGMAP_SPI
+
 config SND_SOC_PCM512x
        tristate
 
@@ -523,14 +565,18 @@ config SND_SOC_PCM512x_SPI
 
 config SND_SOC_RL6231
        tristate
+       default y if SND_SOC_RT5616=y
        default y if SND_SOC_RT5640=y
        default y if SND_SOC_RT5645=y
        default y if SND_SOC_RT5651=y
+       default y if SND_SOC_RT5659=y
        default y if SND_SOC_RT5670=y
        default y if SND_SOC_RT5677=y
+       default m if SND_SOC_RT5616=m
        default m if SND_SOC_RT5640=m
        default m if SND_SOC_RT5645=m
        default m if SND_SOC_RT5651=m
+       default m if SND_SOC_RT5659=m
        default m if SND_SOC_RT5670=m
        default m if SND_SOC_RT5677=m
 
@@ -549,6 +595,9 @@ config SND_SOC_RT298
        tristate
        depends on I2C
 
+config SND_SOC_RT5616
+       tristate
+
 config SND_SOC_RT5631
        tristate "Realtek ALC5631/RT5631 CODEC"
        depends on I2C
@@ -562,6 +611,9 @@ config SND_SOC_RT5645
 config SND_SOC_RT5651
        tristate
 
+config SND_SOC_RT5659
+       tristate
+
 config SND_SOC_RT5670
        tristate
 
@@ -838,7 +890,8 @@ config SND_SOC_WM8971
        tristate
 
 config SND_SOC_WM8974
-       tristate
+       tristate "Wolfson Microelectronics WM8974 codec"
+       depends on I2C
 
 config SND_SOC_WM8978
        tristate "Wolfson Microelectronics WM8978 codec"
@@ -891,6 +944,7 @@ config SND_SOC_WM9712
 
 config SND_SOC_WM9713
        tristate
+       select REGMAP_AC97
 
 # Amp
 config SND_SOC_LM4857
index f632fc42f59f08d9d6c72f6aac045d9fe28176a1..d44f7d347183cbe9a0aca29826b9c6477c52d6c4 100644 (file)
@@ -47,9 +47,11 @@ snd-soc-cs4271-spi-objs := cs4271-spi.o
 snd-soc-cs42xx8-objs := cs42xx8.o
 snd-soc-cs42xx8-i2c-objs := cs42xx8-i2c.o
 snd-soc-cs4349-objs := cs4349.o
+snd-soc-cs47l24-objs := cs47l24.o
 snd-soc-cx20442-objs := cx20442.o
 snd-soc-da7210-objs := da7210.o
 snd-soc-da7213-objs := da7213.o
+snd-soc-da7218-objs := da7218.o
 snd-soc-da7219-objs := da7219.o da7219-aad.o
 snd-soc-da732x-objs := da732x.o
 snd-soc-da9055-objs := da9055.o
@@ -59,7 +61,9 @@ snd-soc-es8328-objs := es8328.o
 snd-soc-es8328-i2c-objs := es8328-i2c.o
 snd-soc-es8328-spi-objs := es8328-spi.o
 snd-soc-gtm601-objs := gtm601.o
+snd-soc-hdac-hdmi-objs := hdac_hdmi.o
 snd-soc-ics43432-objs := ics43432.o
+snd-soc-inno-rk3036-objs := inno_rk3036.o
 snd-soc-isabelle-objs := isabelle.o
 snd-soc-jz4740-codec-objs := jz4740.o
 snd-soc-l3-objs := l3.o
@@ -76,8 +80,11 @@ snd-soc-mc13783-objs := mc13783.o
 snd-soc-ml26124-objs := ml26124.o
 snd-soc-nau8825-objs := nau8825.o
 snd-soc-pcm1681-objs := pcm1681.o
-snd-soc-pcm1792a-codec-objs := pcm1792a.o
+snd-soc-pcm179x-codec-objs := pcm179x.o
 snd-soc-pcm3008-objs := pcm3008.o
+snd-soc-pcm3168a-objs := pcm3168a.o
+snd-soc-pcm3168a-i2c-objs := pcm3168a-i2c.o
+snd-soc-pcm3168a-spi-objs := pcm3168a-spi.o
 snd-soc-pcm512x-objs := pcm512x.o
 snd-soc-pcm512x-i2c-objs := pcm512x-i2c.o
 snd-soc-pcm512x-spi-objs := pcm512x-spi.o
@@ -85,10 +92,12 @@ snd-soc-rl6231-objs := rl6231.o
 snd-soc-rl6347a-objs := rl6347a.o
 snd-soc-rt286-objs := rt286.o
 snd-soc-rt298-objs := rt298.o
+snd-soc-rt5616-objs := rt5616.o
 snd-soc-rt5631-objs := rt5631.o
 snd-soc-rt5640-objs := rt5640.o
 snd-soc-rt5645-objs := rt5645.o
 snd-soc-rt5651-objs := rt5651.o
+snd-soc-rt5659-objs := rt5659.o
 snd-soc-rt5670-objs := rt5670.o
 snd-soc-rt5677-objs := rt5677.o
 snd-soc-rt5677-spi-objs := rt5677-spi.o
@@ -242,9 +251,11 @@ obj-$(CONFIG_SND_SOC_CS4271_SPI)   += snd-soc-cs4271-spi.o
 obj-$(CONFIG_SND_SOC_CS42XX8)  += snd-soc-cs42xx8.o
 obj-$(CONFIG_SND_SOC_CS42XX8_I2C) += snd-soc-cs42xx8-i2c.o
 obj-$(CONFIG_SND_SOC_CS4349)   += snd-soc-cs4349.o
+obj-$(CONFIG_SND_SOC_CS47L24)  += snd-soc-cs47l24.o
 obj-$(CONFIG_SND_SOC_CX20442)  += snd-soc-cx20442.o
 obj-$(CONFIG_SND_SOC_DA7210)   += snd-soc-da7210.o
 obj-$(CONFIG_SND_SOC_DA7213)   += snd-soc-da7213.o
+obj-$(CONFIG_SND_SOC_DA7218)   += snd-soc-da7218.o
 obj-$(CONFIG_SND_SOC_DA7219)   += snd-soc-da7219.o
 obj-$(CONFIG_SND_SOC_DA732X)   += snd-soc-da732x.o
 obj-$(CONFIG_SND_SOC_DA9055)   += snd-soc-da9055.o
@@ -254,7 +265,9 @@ obj-$(CONFIG_SND_SOC_ES8328)        += snd-soc-es8328.o
 obj-$(CONFIG_SND_SOC_ES8328_I2C)+= snd-soc-es8328-i2c.o
 obj-$(CONFIG_SND_SOC_ES8328_SPI)+= snd-soc-es8328-spi.o
 obj-$(CONFIG_SND_SOC_GTM601)    += snd-soc-gtm601.o
+obj-$(CONFIG_SND_SOC_HDAC_HDMI) += snd-soc-hdac-hdmi.o
 obj-$(CONFIG_SND_SOC_ICS43432) += snd-soc-ics43432.o
+obj-$(CONFIG_SND_SOC_INNO_RK3036)      += snd-soc-inno-rk3036.o
 obj-$(CONFIG_SND_SOC_ISABELLE) += snd-soc-isabelle.o
 obj-$(CONFIG_SND_SOC_JZ4740_CODEC)     += snd-soc-jz4740-codec.o
 obj-$(CONFIG_SND_SOC_L3)       += snd-soc-l3.o
@@ -271,8 +284,11 @@ obj-$(CONFIG_SND_SOC_MC13783)      += snd-soc-mc13783.o
 obj-$(CONFIG_SND_SOC_ML26124)  += snd-soc-ml26124.o
 obj-$(CONFIG_SND_SOC_NAU8825)   += snd-soc-nau8825.o
 obj-$(CONFIG_SND_SOC_PCM1681)  += snd-soc-pcm1681.o
-obj-$(CONFIG_SND_SOC_PCM1792A) += snd-soc-pcm1792a-codec.o
+obj-$(CONFIG_SND_SOC_PCM179X)  += snd-soc-pcm179x-codec.o
 obj-$(CONFIG_SND_SOC_PCM3008)  += snd-soc-pcm3008.o
+obj-$(CONFIG_SND_SOC_PCM3168A) += snd-soc-pcm3168a.o
+obj-$(CONFIG_SND_SOC_PCM3168A_I2C)     += snd-soc-pcm3168a-i2c.o
+obj-$(CONFIG_SND_SOC_PCM3168A_SPI)     += snd-soc-pcm3168a-spi.o
 obj-$(CONFIG_SND_SOC_PCM512x)  += snd-soc-pcm512x.o
 obj-$(CONFIG_SND_SOC_PCM512x_I2C)      += snd-soc-pcm512x-i2c.o
 obj-$(CONFIG_SND_SOC_PCM512x_SPI)      += snd-soc-pcm512x-spi.o
@@ -280,10 +296,12 @@ obj-$(CONFIG_SND_SOC_RL6231)      += snd-soc-rl6231.o
 obj-$(CONFIG_SND_SOC_RL6347A)  += snd-soc-rl6347a.o
 obj-$(CONFIG_SND_SOC_RT286)    += snd-soc-rt286.o
 obj-$(CONFIG_SND_SOC_RT298)    += snd-soc-rt298.o
+obj-$(CONFIG_SND_SOC_RT5616)   += snd-soc-rt5616.o
 obj-$(CONFIG_SND_SOC_RT5631)   += snd-soc-rt5631.o
 obj-$(CONFIG_SND_SOC_RT5640)   += snd-soc-rt5640.o
 obj-$(CONFIG_SND_SOC_RT5645)   += snd-soc-rt5645.o
 obj-$(CONFIG_SND_SOC_RT5651)   += snd-soc-rt5651.o
+obj-$(CONFIG_SND_SOC_RT5659)   += snd-soc-rt5659.o
 obj-$(CONFIG_SND_SOC_RT5670)   += snd-soc-rt5670.o
 obj-$(CONFIG_SND_SOC_RT5677)   += snd-soc-rt5677.o
 obj-$(CONFIG_SND_SOC_RT5677_SPI)       += snd-soc-rt5677-spi.o
index 07a266460ec39cb3941dde8d4fe96eeb1bb8d414..647f69de6baac94c3d6aef8a9ff297894ec0c47b 100644 (file)
 #define FMT_MASK       (0xf8)
 
 /* CTRL2 */
+#define DFS_MASK               (3 << 2)
 #define DFS_NORMAL_SPEED       (0 << 2)
 #define DFS_DOUBLE_SPEED       (1 << 2)
 #define DFS_QUAD_SPEED         (2 << 2)
 
-struct ak4613_priv {
-       struct mutex lock;
-
-       unsigned int fmt;
-       u8 fmt_ctrl;
-       int cnt;
-};
-
 struct ak4613_formats {
        unsigned int width;
        unsigned int fmt;
@@ -92,6 +85,16 @@ struct ak4613_interface {
        struct ak4613_formats playback;
 };
 
+struct ak4613_priv {
+       struct mutex lock;
+       const struct ak4613_interface *iface;
+
+       unsigned int fmt;
+       u8 oc;
+       u8 ic;
+       int cnt;
+};
+
 /*
  * Playback Volume
  *
@@ -126,7 +129,7 @@ static const struct reg_default ak4613_reg[] = {
        { 0x14, 0x00 }, { 0x15, 0x00 }, { 0x16, 0x00 },
 };
 
-#define AUDIO_IFACE_IDX_TO_VAL(i) (i << 3)
+#define AUDIO_IFACE_TO_VAL(fmts) ((fmts - ak4613_iface) << 3)
 #define AUDIO_IFACE(b, fmt) { b, SND_SOC_DAIFMT_##fmt }
 static const struct ak4613_interface ak4613_iface[] = {
        /* capture */                           /* playback */
@@ -240,7 +243,7 @@ static void ak4613_dai_shutdown(struct snd_pcm_substream *substream,
                priv->cnt = 0;
        }
        if (!priv->cnt)
-               priv->fmt_ctrl = NO_FMT;
+               priv->iface = NULL;
        mutex_unlock(&priv->lock);
 }
 
@@ -265,13 +268,35 @@ static int ak4613_dai_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
        return 0;
 }
 
+static bool ak4613_dai_fmt_matching(const struct ak4613_interface *iface,
+                                   int is_play,
+                                   unsigned int fmt, unsigned int width)
+{
+       const struct ak4613_formats *fmts;
+
+       fmts = (is_play) ? &iface->playback : &iface->capture;
+
+       if (fmts->fmt != fmt)
+               return false;
+
+       if (fmt == SND_SOC_DAIFMT_RIGHT_J) {
+               if (fmts->width != width)
+                       return false;
+       } else {
+               if (fmts->width < width)
+                       return false;
+       }
+
+       return true;
+}
+
 static int ak4613_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 ak4613_priv *priv = snd_soc_codec_get_drvdata(codec);
-       const struct ak4613_formats *fmts;
+       const struct ak4613_interface *iface;
        struct device *dev = codec->dev;
        unsigned int width = params_width(params);
        unsigned int fmt = priv->fmt;
@@ -305,33 +330,27 @@ static int ak4613_dai_hw_params(struct snd_pcm_substream *substream,
         * It doesn't support TDM at this point
         */
        fmt_ctrl = NO_FMT;
-       for (i = 0; i < ARRAY_SIZE(ak4613_iface); i++) {
-               fmts = (is_play) ?      &ak4613_iface[i].playback :
-                                       &ak4613_iface[i].capture;
-
-               if (fmts->fmt != fmt)
-                       continue;
+       ret = -EINVAL;
+       iface = NULL;
 
-               if (fmt == SND_SOC_DAIFMT_RIGHT_J) {
-                       if (fmts->width != width)
-                               continue;
-               } else {
-                       if (fmts->width < width)
+       mutex_lock(&priv->lock);
+       if (priv->iface) {
+               if (ak4613_dai_fmt_matching(priv->iface, is_play, fmt, width))
+                       iface = priv->iface;
+       } else {
+               for (i = ARRAY_SIZE(ak4613_iface); i >= 0; i--) {
+                       if (!ak4613_dai_fmt_matching(ak4613_iface + i,
+                                                    is_play,
+                                                    fmt, width))
                                continue;
+                       iface = ak4613_iface + i;
+                       break;
                }
-
-               fmt_ctrl = AUDIO_IFACE_IDX_TO_VAL(i);
-               break;
        }
 
-       ret = -EINVAL;
-       if (fmt_ctrl == NO_FMT)
-               goto hw_params_end;
-
-       mutex_lock(&priv->lock);
-       if ((priv->fmt_ctrl == NO_FMT) ||
-           (priv->fmt_ctrl == fmt_ctrl)) {
-               priv->fmt_ctrl = fmt_ctrl;
+       if ((priv->iface == NULL) ||
+           (priv->iface == iface)) {
+               priv->iface = iface;
                priv->cnt++;
                ret = 0;
        }
@@ -340,8 +359,13 @@ static int ak4613_dai_hw_params(struct snd_pcm_substream *substream,
        if (ret < 0)
                goto hw_params_end;
 
+       fmt_ctrl = AUDIO_IFACE_TO_VAL(iface);
+
        snd_soc_update_bits(codec, CTRL1, FMT_MASK, fmt_ctrl);
-       snd_soc_write(codec, CTRL2, ctrl2);
+       snd_soc_update_bits(codec, CTRL2, DFS_MASK, ctrl2);
+
+       snd_soc_write(codec, ICTRL, priv->ic);
+       snd_soc_write(codec, OCTRL, priv->oc);
 
 hw_params_end:
        if (ret < 0)
@@ -431,6 +455,28 @@ static struct snd_soc_codec_driver soc_codec_dev_ak4613 = {
        .num_dapm_routes        = ARRAY_SIZE(ak4613_intercon),
 };
 
+static void ak4613_parse_of(struct ak4613_priv *priv,
+                           struct device *dev)
+{
+       struct device_node *np = dev->of_node;
+       char prop[32];
+       int i;
+
+       /* Input 1 - 2 */
+       for (i = 0; i < 2; i++) {
+               snprintf(prop, sizeof(prop), "asahi-kasei,in%d-single-end", i + 1);
+               if (!of_get_property(np, prop, NULL))
+                       priv->ic |= 1 << i;
+       }
+
+       /* Output 1 - 6 */
+       for (i = 0; i < 6; i++) {
+               snprintf(prop, sizeof(prop), "asahi-kasei,out%d-single-end", i + 1);
+               if (!of_get_property(np, prop, NULL))
+                       priv->oc |= 1 << i;
+       }
+}
+
 static int ak4613_i2c_probe(struct i2c_client *i2c,
                            const struct i2c_device_id *id)
 {
@@ -458,7 +504,9 @@ static int ak4613_i2c_probe(struct i2c_client *i2c,
        if (!priv)
                return -ENOMEM;
 
-       priv->fmt_ctrl          = NO_FMT;
+       ak4613_parse_of(priv, dev);
+
+       priv->iface             = NULL;
        priv->cnt               = 0;
 
        mutex_init(&priv->lock);
index 9929efc6b9aaa4257a155e844b7feb2f91ea80f9..33143fe1de0bdeaa0c6b04bc9bfd159b49bf658b 100644 (file)
@@ -310,7 +310,7 @@ int arizona_init_gpio(struct snd_soc_codec *codec)
 }
 EXPORT_SYMBOL_GPL(arizona_init_gpio);
 
-const char *arizona_mixer_texts[ARIZONA_NUM_MIXER_INPUTS] = {
+const char * const arizona_mixer_texts[ARIZONA_NUM_MIXER_INPUTS] = {
        "None",
        "Tone Generator 1",
        "Tone Generator 2",
@@ -418,7 +418,7 @@ const char *arizona_mixer_texts[ARIZONA_NUM_MIXER_INPUTS] = {
 };
 EXPORT_SYMBOL_GPL(arizona_mixer_texts);
 
-int arizona_mixer_values[ARIZONA_NUM_MIXER_INPUTS] = {
+unsigned int arizona_mixer_values[ARIZONA_NUM_MIXER_INPUTS] = {
        0x00,  /* None */
        0x04,  /* Tone */
        0x05,
@@ -555,12 +555,12 @@ const char *arizona_sample_rate_val_to_name(unsigned int rate_val)
 }
 EXPORT_SYMBOL_GPL(arizona_sample_rate_val_to_name);
 
-const char *arizona_rate_text[ARIZONA_RATE_ENUM_SIZE] = {
+const char * const arizona_rate_text[ARIZONA_RATE_ENUM_SIZE] = {
        "SYNCCLK rate", "8kHz", "16kHz", "ASYNCCLK rate",
 };
 EXPORT_SYMBOL_GPL(arizona_rate_text);
 
-const int arizona_rate_val[ARIZONA_RATE_ENUM_SIZE] = {
+const unsigned int arizona_rate_val[ARIZONA_RATE_ENUM_SIZE] = {
        0, 1, 2, 8,
 };
 EXPORT_SYMBOL_GPL(arizona_rate_val);
@@ -702,6 +702,100 @@ const struct soc_enum arizona_in_dmic_osr[] = {
 };
 EXPORT_SYMBOL_GPL(arizona_in_dmic_osr);
 
+static const char * const arizona_anc_input_src_text[] = {
+       "None", "IN1", "IN2", "IN3", "IN4",
+};
+
+static const char * const arizona_anc_channel_src_text[] = {
+       "None", "Left", "Right", "Combine",
+};
+
+const struct soc_enum arizona_anc_input_src[] = {
+       SOC_ENUM_SINGLE(ARIZONA_ANC_SRC,
+                       ARIZONA_IN_RXANCL_SEL_SHIFT,
+                       ARRAY_SIZE(arizona_anc_input_src_text),
+                       arizona_anc_input_src_text),
+       SOC_ENUM_SINGLE(ARIZONA_FCL_ADC_REFORMATTER_CONTROL,
+                       ARIZONA_FCL_MIC_MODE_SEL,
+                       ARRAY_SIZE(arizona_anc_channel_src_text),
+                       arizona_anc_channel_src_text),
+       SOC_ENUM_SINGLE(ARIZONA_ANC_SRC,
+                       ARIZONA_IN_RXANCR_SEL_SHIFT,
+                       ARRAY_SIZE(arizona_anc_input_src_text),
+                       arizona_anc_input_src_text),
+       SOC_ENUM_SINGLE(ARIZONA_FCR_ADC_REFORMATTER_CONTROL,
+                       ARIZONA_FCR_MIC_MODE_SEL,
+                       ARRAY_SIZE(arizona_anc_channel_src_text),
+                       arizona_anc_channel_src_text),
+};
+EXPORT_SYMBOL_GPL(arizona_anc_input_src);
+
+static const char * const arizona_anc_ng_texts[] = {
+       "None",
+       "Internal",
+       "External",
+};
+
+SOC_ENUM_SINGLE_DECL(arizona_anc_ng_enum, SND_SOC_NOPM, 0,
+                    arizona_anc_ng_texts);
+EXPORT_SYMBOL_GPL(arizona_anc_ng_enum);
+
+static const char * const arizona_output_anc_src_text[] = {
+       "None", "RXANCL", "RXANCR",
+};
+
+const struct soc_enum arizona_output_anc_src[] = {
+       SOC_ENUM_SINGLE(ARIZONA_OUTPUT_PATH_CONFIG_1L,
+                       ARIZONA_OUT1L_ANC_SRC_SHIFT,
+                       ARRAY_SIZE(arizona_output_anc_src_text),
+                       arizona_output_anc_src_text),
+       SOC_ENUM_SINGLE(ARIZONA_OUTPUT_PATH_CONFIG_1R,
+                       ARIZONA_OUT1R_ANC_SRC_SHIFT,
+                       ARRAY_SIZE(arizona_output_anc_src_text),
+                       arizona_output_anc_src_text),
+       SOC_ENUM_SINGLE(ARIZONA_OUTPUT_PATH_CONFIG_2L,
+                       ARIZONA_OUT2L_ANC_SRC_SHIFT,
+                       ARRAY_SIZE(arizona_output_anc_src_text),
+                       arizona_output_anc_src_text),
+       SOC_ENUM_SINGLE(ARIZONA_OUTPUT_PATH_CONFIG_2R,
+                       ARIZONA_OUT2R_ANC_SRC_SHIFT,
+                       ARRAY_SIZE(arizona_output_anc_src_text),
+                       arizona_output_anc_src_text),
+       SOC_ENUM_SINGLE(ARIZONA_OUTPUT_PATH_CONFIG_3L,
+                       ARIZONA_OUT3L_ANC_SRC_SHIFT,
+                       ARRAY_SIZE(arizona_output_anc_src_text),
+                       arizona_output_anc_src_text),
+       SOC_ENUM_SINGLE(ARIZONA_DAC_VOLUME_LIMIT_3R,
+                       ARIZONA_OUT3R_ANC_SRC_SHIFT,
+                       ARRAY_SIZE(arizona_output_anc_src_text),
+                       arizona_output_anc_src_text),
+       SOC_ENUM_SINGLE(ARIZONA_OUTPUT_PATH_CONFIG_4L,
+                       ARIZONA_OUT4L_ANC_SRC_SHIFT,
+                       ARRAY_SIZE(arizona_output_anc_src_text),
+                       arizona_output_anc_src_text),
+       SOC_ENUM_SINGLE(ARIZONA_OUTPUT_PATH_CONFIG_4R,
+                       ARIZONA_OUT4R_ANC_SRC_SHIFT,
+                       ARRAY_SIZE(arizona_output_anc_src_text),
+                       arizona_output_anc_src_text),
+       SOC_ENUM_SINGLE(ARIZONA_OUTPUT_PATH_CONFIG_5L,
+                       ARIZONA_OUT5L_ANC_SRC_SHIFT,
+                       ARRAY_SIZE(arizona_output_anc_src_text),
+                       arizona_output_anc_src_text),
+       SOC_ENUM_SINGLE(ARIZONA_OUTPUT_PATH_CONFIG_5R,
+                       ARIZONA_OUT5R_ANC_SRC_SHIFT,
+                       ARRAY_SIZE(arizona_output_anc_src_text),
+                       arizona_output_anc_src_text),
+       SOC_ENUM_SINGLE(ARIZONA_OUTPUT_PATH_CONFIG_6L,
+                       ARIZONA_OUT6L_ANC_SRC_SHIFT,
+                       ARRAY_SIZE(arizona_output_anc_src_text),
+                       arizona_output_anc_src_text),
+       SOC_ENUM_SINGLE(ARIZONA_OUTPUT_PATH_CONFIG_6R,
+                       ARIZONA_OUT6R_ANC_SRC_SHIFT,
+                       ARRAY_SIZE(arizona_output_anc_src_text),
+                       arizona_output_anc_src_text),
+};
+EXPORT_SYMBOL_GPL(arizona_output_anc_src);
+
 static void arizona_in_set_vu(struct snd_soc_codec *codec, int ena)
 {
        struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
@@ -1023,24 +1117,43 @@ void arizona_init_dvfs(struct arizona_priv *priv)
 }
 EXPORT_SYMBOL_GPL(arizona_init_dvfs);
 
-static unsigned int arizona_sysclk_48k_rates[] = {
+int arizona_anc_ev(struct snd_soc_dapm_widget *w,
+                  struct snd_kcontrol *kcontrol,
+                  int event)
+{
+       struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+       unsigned int mask = 0x3 << w->shift;
+       unsigned int val;
+
+       switch (event) {
+       case SND_SOC_DAPM_POST_PMU:
+               val = 1 << w->shift;
+               break;
+       case SND_SOC_DAPM_PRE_PMD:
+               val = 1 << (w->shift + 1);
+               break;
+       default:
+               return 0;
+       }
+
+       snd_soc_update_bits(codec, ARIZONA_CLOCK_CONTROL, mask, val);
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(arizona_anc_ev);
+
+static unsigned int arizona_opclk_ref_48k_rates[] = {
        6144000,
        12288000,
        24576000,
        49152000,
-       73728000,
-       98304000,
-       147456000,
 };
 
-static unsigned int arizona_sysclk_44k1_rates[] = {
+static unsigned int arizona_opclk_ref_44k1_rates[] = {
        5644800,
        11289600,
        22579200,
        45158400,
-       67737600,
-       90316800,
-       135475200,
 };
 
 static int arizona_set_opclk(struct snd_soc_codec *codec, unsigned int clk,
@@ -1065,11 +1178,11 @@ static int arizona_set_opclk(struct snd_soc_codec *codec, unsigned int clk,
        }
 
        if (refclk % 8000)
-               rates = arizona_sysclk_44k1_rates;
+               rates = arizona_opclk_ref_44k1_rates;
        else
-               rates = arizona_sysclk_48k_rates;
+               rates = arizona_opclk_ref_48k_rates;
 
-       for (ref = 0; ref < ARRAY_SIZE(arizona_sysclk_48k_rates) &&
+       for (ref = 0; ref < ARRAY_SIZE(arizona_opclk_ref_48k_rates) &&
                     rates[ref] <= refclk; ref++) {
                div = 1;
                while (rates[ref] / div >= freq && div < 32) {
@@ -1101,7 +1214,7 @@ int arizona_set_sysclk(struct snd_soc_codec *codec, int clk_id,
        unsigned int reg;
        unsigned int mask = ARIZONA_SYSCLK_FREQ_MASK | ARIZONA_SYSCLK_SRC_MASK;
        unsigned int val = source << ARIZONA_SYSCLK_SRC_SHIFT;
-       unsigned int *clk;
+       int *clk;
 
        switch (clk_id) {
        case ARIZONA_CLK_SYSCLK:
@@ -1381,6 +1494,9 @@ static int arizona_startup(struct snd_pcm_substream *substream,
        const struct snd_pcm_hw_constraint_list *constraint;
        unsigned int base_rate;
 
+       if (!substream->runtime)
+               return 0;
+
        switch (dai_priv->clk) {
        case ARIZONA_CLK_SYSCLK:
                base_rate = priv->sysclk;
@@ -1543,7 +1659,7 @@ static int arizona_hw_params(struct snd_pcm_substream *substream,
        bool reconfig;
        unsigned int aif_tx_state, aif_rx_state;
 
-       if (params_rate(params) % 8000)
+       if (params_rate(params) % 4000)
                rates = &arizona_44k1_bclk_rates[0];
        else
                rates = &arizona_48k_bclk_rates[0];
@@ -1907,18 +2023,18 @@ static int arizona_calc_fratio(struct arizona_fll *fll,
        }
 
        switch (fll->arizona->type) {
+       case WM5102:
+       case WM8997:
+               return init_ratio;
        case WM5110:
        case WM8280:
                if (fll->arizona->rev < 3 || sync)
                        return init_ratio;
                break;
-       case WM8998:
-       case WM1814:
+       default:
                if (sync)
                        return init_ratio;
                break;
-       default:
-               return init_ratio;
        }
 
        cfg->fratio = init_ratio - 1;
@@ -2099,9 +2215,9 @@ static int arizona_enable_fll(struct arizona_fll *fll)
                /* Facilitate smooth refclk across the transition */
                regmap_update_bits_async(fll->arizona->regmap, fll->base + 0x9,
                                         ARIZONA_FLL1_GAIN_MASK, 0);
-               regmap_update_bits_async(fll->arizona->regmap, fll->base + 1,
-                                        ARIZONA_FLL1_FREERUN,
-                                        ARIZONA_FLL1_FREERUN);
+               regmap_update_bits(fll->arizona->regmap, fll->base + 1,
+                                  ARIZONA_FLL1_FREERUN, ARIZONA_FLL1_FREERUN);
+               udelay(32);
        }
 
        /*
index fea8b8ae8e1a1517929bca406f20066fa25724bb..8b6adb5419bb896482139426167752a22aa4df57 100644 (file)
@@ -57,7 +57,7 @@
 #define ARIZONA_CLK_98MHZ  5
 #define ARIZONA_CLK_147MHZ 6
 
-#define ARIZONA_MAX_DAI  6
+#define ARIZONA_MAX_DAI  8
 #define ARIZONA_MAX_ADSP 4
 
 #define ARIZONA_DVFS_SR1_RQ    0x001
@@ -96,8 +96,8 @@ struct arizona_priv {
 #define ARIZONA_NUM_MIXER_INPUTS 104
 
 extern const unsigned int arizona_mixer_tlv[];
-extern const char *arizona_mixer_texts[ARIZONA_NUM_MIXER_INPUTS];
-extern int arizona_mixer_values[ARIZONA_NUM_MIXER_INPUTS];
+extern const char * const arizona_mixer_texts[ARIZONA_NUM_MIXER_INPUTS];
+extern unsigned int arizona_mixer_values[ARIZONA_NUM_MIXER_INPUTS];
 
 #define ARIZONA_GAINMUX_CONTROLS(name, base) \
        SOC_SINGLE_RANGE_TLV(name " Input Volume", base + 1,            \
@@ -216,8 +216,8 @@ extern int arizona_mixer_values[ARIZONA_NUM_MIXER_INPUTS];
 #define ARIZONA_RATE_ENUM_SIZE 4
 #define ARIZONA_SAMPLE_RATE_ENUM_SIZE 14
 
-extern const char *arizona_rate_text[ARIZONA_RATE_ENUM_SIZE];
-extern const int arizona_rate_val[ARIZONA_RATE_ENUM_SIZE];
+extern const char * const arizona_rate_text[ARIZONA_RATE_ENUM_SIZE];
+extern const unsigned int arizona_rate_val[ARIZONA_RATE_ENUM_SIZE];
 extern const char * const arizona_sample_rate_text[ARIZONA_SAMPLE_RATE_ENUM_SIZE];
 extern const unsigned int arizona_sample_rate_val[ARIZONA_SAMPLE_RATE_ENUM_SIZE];
 
@@ -242,6 +242,10 @@ extern const struct soc_enum arizona_in_dmic_osr[];
 
 extern const struct snd_kcontrol_new arizona_adsp2_rate_controls[];
 
+extern const struct soc_enum arizona_anc_input_src[];
+extern const struct soc_enum arizona_anc_ng_enum;
+extern const struct soc_enum arizona_output_anc_src[];
+
 extern int arizona_in_ev(struct snd_soc_dapm_widget *w,
                         struct snd_kcontrol *kcontrol,
                         int event);
@@ -251,6 +255,9 @@ extern int arizona_out_ev(struct snd_soc_dapm_widget *w,
 extern int arizona_hp_ev(struct snd_soc_dapm_widget *w,
                         struct snd_kcontrol *kcontrol,
                         int event);
+extern int arizona_anc_ev(struct snd_soc_dapm_widget *w,
+                         struct snd_kcontrol *kcontrol,
+                         int event);
 
 extern int arizona_eq_coeff_put(struct snd_kcontrol *kcontrol,
                                struct snd_ctl_elem_value *ucontrol);
diff --git a/sound/soc/codecs/cs47l24.c b/sound/soc/codecs/cs47l24.c
new file mode 100644 (file)
index 0000000..dc5ae7f
--- /dev/null
@@ -0,0 +1,1148 @@
+/*
+ * cs47l24.h  --  ALSA SoC Audio driver for Cirrus Logic CS47L24
+ *
+ * Copyright 2015 Cirrus Logic Inc.
+ *
+ * Author: Richard Fitzgerald <rf@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/module.h>
+#include <linux/moduleparam.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/pm.h>
+#include <linux/pm_runtime.h>
+#include <linux/regmap.h>
+#include <linux/slab.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/jack.h>
+#include <sound/initval.h>
+#include <sound/tlv.h>
+
+#include <linux/mfd/arizona/core.h>
+#include <linux/mfd/arizona/registers.h>
+
+#include "arizona.h"
+#include "wm_adsp.h"
+#include "cs47l24.h"
+
+struct cs47l24_priv {
+       struct arizona_priv core;
+       struct arizona_fll fll[2];
+};
+
+static const struct wm_adsp_region cs47l24_dsp2_regions[] = {
+       { .type = WMFW_ADSP2_PM, .base = 0x200000 },
+       { .type = WMFW_ADSP2_ZM, .base = 0x280000 },
+       { .type = WMFW_ADSP2_XM, .base = 0x290000 },
+       { .type = WMFW_ADSP2_YM, .base = 0x2a8000 },
+};
+
+static const struct wm_adsp_region cs47l24_dsp3_regions[] = {
+       { .type = WMFW_ADSP2_PM, .base = 0x300000 },
+       { .type = WMFW_ADSP2_ZM, .base = 0x380000 },
+       { .type = WMFW_ADSP2_XM, .base = 0x390000 },
+       { .type = WMFW_ADSP2_YM, .base = 0x3a8000 },
+};
+
+static const struct wm_adsp_region *cs47l24_dsp_regions[] = {
+       cs47l24_dsp2_regions,
+       cs47l24_dsp3_regions,
+};
+
+static DECLARE_TLV_DB_SCALE(eq_tlv, -1200, 100, 0);
+static DECLARE_TLV_DB_SCALE(digital_tlv, -6400, 50, 0);
+static DECLARE_TLV_DB_SCALE(noise_tlv, -13200, 600, 0);
+static DECLARE_TLV_DB_SCALE(ng_tlv, -10200, 600, 0);
+
+#define CS47L24_NG_SRC(name, base) \
+       SOC_SINGLE(name " NG HPOUT1L Switch",  base,  0, 1, 0), \
+       SOC_SINGLE(name " NG HPOUT1R Switch",  base,  1, 1, 0), \
+       SOC_SINGLE(name " NG SPKOUT Switch",  base,  6, 1, 0)
+
+static const struct snd_kcontrol_new cs47l24_snd_controls[] = {
+SOC_ENUM("IN1 OSR", arizona_in_dmic_osr[0]),
+SOC_ENUM("IN2 OSR", arizona_in_dmic_osr[1]),
+
+SOC_ENUM("IN HPF Cutoff Frequency", arizona_in_hpf_cut_enum),
+
+SOC_SINGLE("IN1L HPF Switch", ARIZONA_IN1L_CONTROL,
+          ARIZONA_IN1L_HPF_SHIFT, 1, 0),
+SOC_SINGLE("IN1R HPF Switch", ARIZONA_IN1R_CONTROL,
+          ARIZONA_IN1R_HPF_SHIFT, 1, 0),
+SOC_SINGLE("IN2L HPF Switch", ARIZONA_IN2L_CONTROL,
+          ARIZONA_IN2L_HPF_SHIFT, 1, 0),
+SOC_SINGLE("IN2R HPF Switch", ARIZONA_IN2R_CONTROL,
+          ARIZONA_IN2R_HPF_SHIFT, 1, 0),
+
+SOC_SINGLE_TLV("IN1L Digital Volume", ARIZONA_ADC_DIGITAL_VOLUME_1L,
+              ARIZONA_IN1L_DIG_VOL_SHIFT, 0xbf, 0, digital_tlv),
+SOC_SINGLE_TLV("IN1R Digital Volume", ARIZONA_ADC_DIGITAL_VOLUME_1R,
+              ARIZONA_IN1R_DIG_VOL_SHIFT, 0xbf, 0, digital_tlv),
+SOC_SINGLE_TLV("IN2L Digital Volume", ARIZONA_ADC_DIGITAL_VOLUME_2L,
+              ARIZONA_IN2L_DIG_VOL_SHIFT, 0xbf, 0, digital_tlv),
+SOC_SINGLE_TLV("IN2R Digital Volume", ARIZONA_ADC_DIGITAL_VOLUME_2R,
+              ARIZONA_IN2R_DIG_VOL_SHIFT, 0xbf, 0, digital_tlv),
+
+SOC_ENUM("Input Ramp Up", arizona_in_vi_ramp),
+SOC_ENUM("Input Ramp Down", arizona_in_vd_ramp),
+
+ARIZONA_MIXER_CONTROLS("EQ1", ARIZONA_EQ1MIX_INPUT_1_SOURCE),
+ARIZONA_MIXER_CONTROLS("EQ2", ARIZONA_EQ2MIX_INPUT_1_SOURCE),
+
+ARIZONA_EQ_CONTROL("EQ1 Coefficients", ARIZONA_EQ1_2),
+SOC_SINGLE_TLV("EQ1 B1 Volume", ARIZONA_EQ1_1, ARIZONA_EQ1_B1_GAIN_SHIFT,
+              24, 0, eq_tlv),
+SOC_SINGLE_TLV("EQ1 B2 Volume", ARIZONA_EQ1_1, ARIZONA_EQ1_B2_GAIN_SHIFT,
+              24, 0, eq_tlv),
+SOC_SINGLE_TLV("EQ1 B3 Volume", ARIZONA_EQ1_1, ARIZONA_EQ1_B3_GAIN_SHIFT,
+              24, 0, eq_tlv),
+SOC_SINGLE_TLV("EQ1 B4 Volume", ARIZONA_EQ1_2, ARIZONA_EQ1_B4_GAIN_SHIFT,
+              24, 0, eq_tlv),
+SOC_SINGLE_TLV("EQ1 B5 Volume", ARIZONA_EQ1_2, ARIZONA_EQ1_B5_GAIN_SHIFT,
+              24, 0, eq_tlv),
+
+ARIZONA_EQ_CONTROL("EQ2 Coefficients", ARIZONA_EQ2_2),
+SOC_SINGLE_TLV("EQ2 B1 Volume", ARIZONA_EQ2_1, ARIZONA_EQ2_B1_GAIN_SHIFT,
+              24, 0, eq_tlv),
+SOC_SINGLE_TLV("EQ2 B2 Volume", ARIZONA_EQ2_1, ARIZONA_EQ2_B2_GAIN_SHIFT,
+              24, 0, eq_tlv),
+SOC_SINGLE_TLV("EQ2 B3 Volume", ARIZONA_EQ2_1, ARIZONA_EQ2_B3_GAIN_SHIFT,
+              24, 0, eq_tlv),
+SOC_SINGLE_TLV("EQ2 B4 Volume", ARIZONA_EQ2_2, ARIZONA_EQ2_B4_GAIN_SHIFT,
+              24, 0, eq_tlv),
+SOC_SINGLE_TLV("EQ2 B5 Volume", ARIZONA_EQ2_2, ARIZONA_EQ2_B5_GAIN_SHIFT,
+              24, 0, eq_tlv),
+
+ARIZONA_MIXER_CONTROLS("DRC1L", ARIZONA_DRC1LMIX_INPUT_1_SOURCE),
+ARIZONA_MIXER_CONTROLS("DRC1R", ARIZONA_DRC1RMIX_INPUT_1_SOURCE),
+ARIZONA_MIXER_CONTROLS("DRC2L", ARIZONA_DRC2LMIX_INPUT_1_SOURCE),
+ARIZONA_MIXER_CONTROLS("DRC2R", ARIZONA_DRC2RMIX_INPUT_1_SOURCE),
+
+SND_SOC_BYTES_MASK("DRC1", ARIZONA_DRC1_CTRL1, 5,
+                  ARIZONA_DRC1R_ENA | ARIZONA_DRC1L_ENA),
+SND_SOC_BYTES_MASK("DRC2", ARIZONA_DRC2_CTRL1, 5,
+                  ARIZONA_DRC2R_ENA | ARIZONA_DRC2L_ENA),
+
+ARIZONA_MIXER_CONTROLS("LHPF1", ARIZONA_HPLP1MIX_INPUT_1_SOURCE),
+ARIZONA_MIXER_CONTROLS("LHPF2", ARIZONA_HPLP2MIX_INPUT_1_SOURCE),
+ARIZONA_MIXER_CONTROLS("LHPF3", ARIZONA_HPLP3MIX_INPUT_1_SOURCE),
+ARIZONA_MIXER_CONTROLS("LHPF4", ARIZONA_HPLP4MIX_INPUT_1_SOURCE),
+
+ARIZONA_LHPF_CONTROL("LHPF1 Coefficients", ARIZONA_HPLPF1_2),
+ARIZONA_LHPF_CONTROL("LHPF2 Coefficients", ARIZONA_HPLPF2_2),
+ARIZONA_LHPF_CONTROL("LHPF3 Coefficients", ARIZONA_HPLPF3_2),
+ARIZONA_LHPF_CONTROL("LHPF4 Coefficients", ARIZONA_HPLPF4_2),
+
+SOC_ENUM("LHPF1 Mode", arizona_lhpf1_mode),
+SOC_ENUM("LHPF2 Mode", arizona_lhpf2_mode),
+SOC_ENUM("LHPF3 Mode", arizona_lhpf3_mode),
+SOC_ENUM("LHPF4 Mode", arizona_lhpf4_mode),
+
+SOC_ENUM("ISRC1 FSL", arizona_isrc_fsl[0]),
+SOC_ENUM("ISRC2 FSL", arizona_isrc_fsl[1]),
+SOC_ENUM("ISRC3 FSL", arizona_isrc_fsl[2]),
+SOC_ENUM("ISRC1 FSH", arizona_isrc_fsh[0]),
+SOC_ENUM("ISRC2 FSH", arizona_isrc_fsh[1]),
+SOC_ENUM("ISRC3 FSH", arizona_isrc_fsh[2]),
+SOC_ENUM("ASRC RATE 1", arizona_asrc_rate1),
+
+ARIZONA_MIXER_CONTROLS("DSP2L", ARIZONA_DSP2LMIX_INPUT_1_SOURCE),
+ARIZONA_MIXER_CONTROLS("DSP2R", ARIZONA_DSP2RMIX_INPUT_1_SOURCE),
+ARIZONA_MIXER_CONTROLS("DSP3L", ARIZONA_DSP3LMIX_INPUT_1_SOURCE),
+ARIZONA_MIXER_CONTROLS("DSP3R", ARIZONA_DSP3RMIX_INPUT_1_SOURCE),
+
+SOC_SINGLE_TLV("Noise Generator Volume", ARIZONA_COMFORT_NOISE_GENERATOR,
+              ARIZONA_NOISE_GEN_GAIN_SHIFT, 0x16, 0, noise_tlv),
+
+ARIZONA_MIXER_CONTROLS("HPOUT1L", ARIZONA_OUT1LMIX_INPUT_1_SOURCE),
+ARIZONA_MIXER_CONTROLS("HPOUT1R", ARIZONA_OUT1RMIX_INPUT_1_SOURCE),
+ARIZONA_MIXER_CONTROLS("SPKOUT", ARIZONA_OUT4LMIX_INPUT_1_SOURCE),
+
+SOC_SINGLE("HPOUT1 SC Protect Switch", ARIZONA_HP1_SHORT_CIRCUIT_CTRL,
+          ARIZONA_HP1_SC_ENA_SHIFT, 1, 0),
+
+SOC_DOUBLE_R("HPOUT1 Digital Switch", ARIZONA_DAC_DIGITAL_VOLUME_1L,
+            ARIZONA_DAC_DIGITAL_VOLUME_1R, ARIZONA_OUT1L_MUTE_SHIFT, 1, 1),
+SOC_SINGLE("Speaker Digital Switch", ARIZONA_DAC_DIGITAL_VOLUME_4L,
+            ARIZONA_OUT4L_MUTE_SHIFT, 1, 1),
+
+SOC_DOUBLE_R_TLV("HPOUT1 Digital Volume", ARIZONA_DAC_DIGITAL_VOLUME_1L,
+                ARIZONA_DAC_DIGITAL_VOLUME_1R, ARIZONA_OUT1L_VOL_SHIFT,
+                0xbf, 0, digital_tlv),
+SOC_SINGLE_TLV("Speaker Digital Volume", ARIZONA_DAC_DIGITAL_VOLUME_4L,
+                ARIZONA_OUT4L_VOL_SHIFT,
+                0xbf, 0, digital_tlv),
+
+SOC_ENUM("Output Ramp Up", arizona_out_vi_ramp),
+SOC_ENUM("Output Ramp Down", arizona_out_vd_ramp),
+
+SOC_SINGLE("Noise Gate Switch", ARIZONA_NOISE_GATE_CONTROL,
+          ARIZONA_NGATE_ENA_SHIFT, 1, 0),
+SOC_SINGLE_TLV("Noise Gate Threshold Volume", ARIZONA_NOISE_GATE_CONTROL,
+              ARIZONA_NGATE_THR_SHIFT, 7, 1, ng_tlv),
+SOC_ENUM("Noise Gate Hold", arizona_ng_hold),
+
+CS47L24_NG_SRC("HPOUT1L", ARIZONA_NOISE_GATE_SELECT_1L),
+CS47L24_NG_SRC("HPOUT1R", ARIZONA_NOISE_GATE_SELECT_1R),
+CS47L24_NG_SRC("SPKOUT", ARIZONA_NOISE_GATE_SELECT_4L),
+
+ARIZONA_MIXER_CONTROLS("AIF1TX1", ARIZONA_AIF1TX1MIX_INPUT_1_SOURCE),
+ARIZONA_MIXER_CONTROLS("AIF1TX2", ARIZONA_AIF1TX2MIX_INPUT_1_SOURCE),
+ARIZONA_MIXER_CONTROLS("AIF1TX3", ARIZONA_AIF1TX3MIX_INPUT_1_SOURCE),
+ARIZONA_MIXER_CONTROLS("AIF1TX4", ARIZONA_AIF1TX4MIX_INPUT_1_SOURCE),
+ARIZONA_MIXER_CONTROLS("AIF1TX5", ARIZONA_AIF1TX5MIX_INPUT_1_SOURCE),
+ARIZONA_MIXER_CONTROLS("AIF1TX6", ARIZONA_AIF1TX6MIX_INPUT_1_SOURCE),
+ARIZONA_MIXER_CONTROLS("AIF1TX7", ARIZONA_AIF1TX7MIX_INPUT_1_SOURCE),
+ARIZONA_MIXER_CONTROLS("AIF1TX8", ARIZONA_AIF1TX8MIX_INPUT_1_SOURCE),
+
+ARIZONA_MIXER_CONTROLS("AIF2TX1", ARIZONA_AIF2TX1MIX_INPUT_1_SOURCE),
+ARIZONA_MIXER_CONTROLS("AIF2TX2", ARIZONA_AIF2TX2MIX_INPUT_1_SOURCE),
+ARIZONA_MIXER_CONTROLS("AIF2TX3", ARIZONA_AIF2TX3MIX_INPUT_1_SOURCE),
+ARIZONA_MIXER_CONTROLS("AIF2TX4", ARIZONA_AIF2TX4MIX_INPUT_1_SOURCE),
+ARIZONA_MIXER_CONTROLS("AIF2TX5", ARIZONA_AIF2TX5MIX_INPUT_1_SOURCE),
+ARIZONA_MIXER_CONTROLS("AIF2TX6", ARIZONA_AIF2TX6MIX_INPUT_1_SOURCE),
+
+ARIZONA_MIXER_CONTROLS("AIF3TX1", ARIZONA_AIF3TX1MIX_INPUT_1_SOURCE),
+ARIZONA_MIXER_CONTROLS("AIF3TX2", ARIZONA_AIF3TX2MIX_INPUT_1_SOURCE),
+};
+
+ARIZONA_MIXER_ENUMS(EQ1, ARIZONA_EQ1MIX_INPUT_1_SOURCE);
+ARIZONA_MIXER_ENUMS(EQ2, ARIZONA_EQ2MIX_INPUT_1_SOURCE);
+
+ARIZONA_MIXER_ENUMS(DRC1L, ARIZONA_DRC1LMIX_INPUT_1_SOURCE);
+ARIZONA_MIXER_ENUMS(DRC1R, ARIZONA_DRC1RMIX_INPUT_1_SOURCE);
+ARIZONA_MIXER_ENUMS(DRC2L, ARIZONA_DRC2LMIX_INPUT_1_SOURCE);
+ARIZONA_MIXER_ENUMS(DRC2R, ARIZONA_DRC2RMIX_INPUT_1_SOURCE);
+
+ARIZONA_MIXER_ENUMS(LHPF1, ARIZONA_HPLP1MIX_INPUT_1_SOURCE);
+ARIZONA_MIXER_ENUMS(LHPF2, ARIZONA_HPLP2MIX_INPUT_1_SOURCE);
+ARIZONA_MIXER_ENUMS(LHPF3, ARIZONA_HPLP3MIX_INPUT_1_SOURCE);
+ARIZONA_MIXER_ENUMS(LHPF4, ARIZONA_HPLP4MIX_INPUT_1_SOURCE);
+
+ARIZONA_MIXER_ENUMS(DSP2L, ARIZONA_DSP2LMIX_INPUT_1_SOURCE);
+ARIZONA_MIXER_ENUMS(DSP2R, ARIZONA_DSP2RMIX_INPUT_1_SOURCE);
+ARIZONA_DSP_AUX_ENUMS(DSP2, ARIZONA_DSP2AUX1MIX_INPUT_1_SOURCE);
+
+ARIZONA_MIXER_ENUMS(DSP3L, ARIZONA_DSP3LMIX_INPUT_1_SOURCE);
+ARIZONA_MIXER_ENUMS(DSP3R, ARIZONA_DSP3RMIX_INPUT_1_SOURCE);
+ARIZONA_DSP_AUX_ENUMS(DSP3, ARIZONA_DSP3AUX1MIX_INPUT_1_SOURCE);
+
+ARIZONA_MIXER_ENUMS(PWM1, ARIZONA_PWM1MIX_INPUT_1_SOURCE);
+ARIZONA_MIXER_ENUMS(PWM2, ARIZONA_PWM2MIX_INPUT_1_SOURCE);
+
+ARIZONA_MIXER_ENUMS(OUT1L, ARIZONA_OUT1LMIX_INPUT_1_SOURCE);
+ARIZONA_MIXER_ENUMS(OUT1R, ARIZONA_OUT1RMIX_INPUT_1_SOURCE);
+ARIZONA_MIXER_ENUMS(SPKOUT, ARIZONA_OUT4LMIX_INPUT_1_SOURCE);
+
+ARIZONA_MIXER_ENUMS(AIF1TX1, ARIZONA_AIF1TX1MIX_INPUT_1_SOURCE);
+ARIZONA_MIXER_ENUMS(AIF1TX2, ARIZONA_AIF1TX2MIX_INPUT_1_SOURCE);
+ARIZONA_MIXER_ENUMS(AIF1TX3, ARIZONA_AIF1TX3MIX_INPUT_1_SOURCE);
+ARIZONA_MIXER_ENUMS(AIF1TX4, ARIZONA_AIF1TX4MIX_INPUT_1_SOURCE);
+ARIZONA_MIXER_ENUMS(AIF1TX5, ARIZONA_AIF1TX5MIX_INPUT_1_SOURCE);
+ARIZONA_MIXER_ENUMS(AIF1TX6, ARIZONA_AIF1TX6MIX_INPUT_1_SOURCE);
+ARIZONA_MIXER_ENUMS(AIF1TX7, ARIZONA_AIF1TX7MIX_INPUT_1_SOURCE);
+ARIZONA_MIXER_ENUMS(AIF1TX8, ARIZONA_AIF1TX8MIX_INPUT_1_SOURCE);
+
+ARIZONA_MIXER_ENUMS(AIF2TX1, ARIZONA_AIF2TX1MIX_INPUT_1_SOURCE);
+ARIZONA_MIXER_ENUMS(AIF2TX2, ARIZONA_AIF2TX2MIX_INPUT_1_SOURCE);
+ARIZONA_MIXER_ENUMS(AIF2TX3, ARIZONA_AIF2TX3MIX_INPUT_1_SOURCE);
+ARIZONA_MIXER_ENUMS(AIF2TX4, ARIZONA_AIF2TX4MIX_INPUT_1_SOURCE);
+ARIZONA_MIXER_ENUMS(AIF2TX5, ARIZONA_AIF2TX5MIX_INPUT_1_SOURCE);
+ARIZONA_MIXER_ENUMS(AIF2TX6, ARIZONA_AIF2TX6MIX_INPUT_1_SOURCE);
+
+ARIZONA_MIXER_ENUMS(AIF3TX1, ARIZONA_AIF3TX1MIX_INPUT_1_SOURCE);
+ARIZONA_MIXER_ENUMS(AIF3TX2, ARIZONA_AIF3TX2MIX_INPUT_1_SOURCE);
+
+ARIZONA_MUX_ENUMS(ASRC1L, ARIZONA_ASRC1LMIX_INPUT_1_SOURCE);
+ARIZONA_MUX_ENUMS(ASRC1R, ARIZONA_ASRC1RMIX_INPUT_1_SOURCE);
+ARIZONA_MUX_ENUMS(ASRC2L, ARIZONA_ASRC2LMIX_INPUT_1_SOURCE);
+ARIZONA_MUX_ENUMS(ASRC2R, ARIZONA_ASRC2RMIX_INPUT_1_SOURCE);
+
+ARIZONA_MUX_ENUMS(ISRC1INT1, ARIZONA_ISRC1INT1MIX_INPUT_1_SOURCE);
+ARIZONA_MUX_ENUMS(ISRC1INT2, ARIZONA_ISRC1INT2MIX_INPUT_1_SOURCE);
+ARIZONA_MUX_ENUMS(ISRC1INT3, ARIZONA_ISRC1INT3MIX_INPUT_1_SOURCE);
+ARIZONA_MUX_ENUMS(ISRC1INT4, ARIZONA_ISRC1INT4MIX_INPUT_1_SOURCE);
+
+ARIZONA_MUX_ENUMS(ISRC1DEC1, ARIZONA_ISRC1DEC1MIX_INPUT_1_SOURCE);
+ARIZONA_MUX_ENUMS(ISRC1DEC2, ARIZONA_ISRC1DEC2MIX_INPUT_1_SOURCE);
+ARIZONA_MUX_ENUMS(ISRC1DEC3, ARIZONA_ISRC1DEC3MIX_INPUT_1_SOURCE);
+ARIZONA_MUX_ENUMS(ISRC1DEC4, ARIZONA_ISRC1DEC4MIX_INPUT_1_SOURCE);
+
+ARIZONA_MUX_ENUMS(ISRC2INT1, ARIZONA_ISRC2INT1MIX_INPUT_1_SOURCE);
+ARIZONA_MUX_ENUMS(ISRC2INT2, ARIZONA_ISRC2INT2MIX_INPUT_1_SOURCE);
+ARIZONA_MUX_ENUMS(ISRC2INT3, ARIZONA_ISRC2INT3MIX_INPUT_1_SOURCE);
+ARIZONA_MUX_ENUMS(ISRC2INT4, ARIZONA_ISRC2INT4MIX_INPUT_1_SOURCE);
+
+ARIZONA_MUX_ENUMS(ISRC2DEC1, ARIZONA_ISRC2DEC1MIX_INPUT_1_SOURCE);
+ARIZONA_MUX_ENUMS(ISRC2DEC2, ARIZONA_ISRC2DEC2MIX_INPUT_1_SOURCE);
+ARIZONA_MUX_ENUMS(ISRC2DEC3, ARIZONA_ISRC2DEC3MIX_INPUT_1_SOURCE);
+ARIZONA_MUX_ENUMS(ISRC2DEC4, ARIZONA_ISRC2DEC4MIX_INPUT_1_SOURCE);
+
+ARIZONA_MUX_ENUMS(ISRC3INT1, ARIZONA_ISRC3INT1MIX_INPUT_1_SOURCE);
+ARIZONA_MUX_ENUMS(ISRC3INT2, ARIZONA_ISRC3INT2MIX_INPUT_1_SOURCE);
+ARIZONA_MUX_ENUMS(ISRC3INT3, ARIZONA_ISRC3INT3MIX_INPUT_1_SOURCE);
+ARIZONA_MUX_ENUMS(ISRC3INT4, ARIZONA_ISRC3INT4MIX_INPUT_1_SOURCE);
+
+ARIZONA_MUX_ENUMS(ISRC3DEC1, ARIZONA_ISRC3DEC1MIX_INPUT_1_SOURCE);
+ARIZONA_MUX_ENUMS(ISRC3DEC2, ARIZONA_ISRC3DEC2MIX_INPUT_1_SOURCE);
+ARIZONA_MUX_ENUMS(ISRC3DEC3, ARIZONA_ISRC3DEC3MIX_INPUT_1_SOURCE);
+ARIZONA_MUX_ENUMS(ISRC3DEC4, ARIZONA_ISRC3DEC4MIX_INPUT_1_SOURCE);
+
+static const char * const cs47l24_aec_loopback_texts[] = {
+       "HPOUT1L", "HPOUT1R", "SPKOUT",
+};
+
+static const unsigned int cs47l24_aec_loopback_values[] = {
+       0, 1, 6,
+};
+
+static const struct soc_enum cs47l24_aec_loopback =
+       SOC_VALUE_ENUM_SINGLE(ARIZONA_DAC_AEC_CONTROL_1,
+                             ARIZONA_AEC_LOOPBACK_SRC_SHIFT, 0xf,
+                             ARRAY_SIZE(cs47l24_aec_loopback_texts),
+                             cs47l24_aec_loopback_texts,
+                             cs47l24_aec_loopback_values);
+
+static const struct snd_kcontrol_new cs47l24_aec_loopback_mux =
+       SOC_DAPM_ENUM("AEC Loopback", cs47l24_aec_loopback);
+
+static const struct snd_soc_dapm_widget cs47l24_dapm_widgets[] = {
+SND_SOC_DAPM_SUPPLY("SYSCLK", ARIZONA_SYSTEM_CLOCK_1,
+                   ARIZONA_SYSCLK_ENA_SHIFT, 0, NULL, 0),
+SND_SOC_DAPM_SUPPLY("ASYNCCLK", ARIZONA_ASYNC_CLOCK_1,
+                   ARIZONA_ASYNC_CLK_ENA_SHIFT, 0, NULL, 0),
+SND_SOC_DAPM_SUPPLY("OPCLK", ARIZONA_OUTPUT_SYSTEM_CLOCK,
+                   ARIZONA_OPCLK_ENA_SHIFT, 0, NULL, 0),
+SND_SOC_DAPM_SUPPLY("ASYNCOPCLK", ARIZONA_OUTPUT_ASYNC_CLOCK,
+                   ARIZONA_OPCLK_ASYNC_ENA_SHIFT, 0, NULL, 0),
+
+SND_SOC_DAPM_REGULATOR_SUPPLY("CPVDD", 20, 0),
+SND_SOC_DAPM_REGULATOR_SUPPLY("MICVDD", 0, SND_SOC_DAPM_REGULATOR_BYPASS),
+SND_SOC_DAPM_REGULATOR_SUPPLY("SPKVDD", 0, 0),
+
+SND_SOC_DAPM_SIGGEN("TONE"),
+SND_SOC_DAPM_SIGGEN("NOISE"),
+SND_SOC_DAPM_SIGGEN("HAPTICS"),
+
+SND_SOC_DAPM_INPUT("IN1L"),
+SND_SOC_DAPM_INPUT("IN1R"),
+SND_SOC_DAPM_INPUT("IN2L"),
+SND_SOC_DAPM_INPUT("IN2R"),
+
+SND_SOC_DAPM_OUTPUT("DRC1 Signal Activity"),
+SND_SOC_DAPM_OUTPUT("DRC2 Signal Activity"),
+
+SND_SOC_DAPM_PGA_E("IN1L PGA", ARIZONA_INPUT_ENABLES, ARIZONA_IN1L_ENA_SHIFT,
+                  0, NULL, 0, arizona_in_ev,
+                  SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD |
+                  SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU),
+SND_SOC_DAPM_PGA_E("IN1R PGA", ARIZONA_INPUT_ENABLES, ARIZONA_IN1R_ENA_SHIFT,
+                  0, NULL, 0, arizona_in_ev,
+                  SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD |
+                  SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU),
+SND_SOC_DAPM_PGA_E("IN2L PGA", ARIZONA_INPUT_ENABLES, ARIZONA_IN2L_ENA_SHIFT,
+                  0, NULL, 0, arizona_in_ev,
+                  SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD |
+                  SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU),
+SND_SOC_DAPM_PGA_E("IN2R PGA", ARIZONA_INPUT_ENABLES, ARIZONA_IN2R_ENA_SHIFT,
+                  0, NULL, 0, arizona_in_ev,
+                  SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD |
+                  SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU),
+
+SND_SOC_DAPM_SUPPLY("MICBIAS1", ARIZONA_MIC_BIAS_CTRL_1,
+                   ARIZONA_MICB1_ENA_SHIFT, 0, NULL, 0),
+SND_SOC_DAPM_SUPPLY("MICBIAS2", ARIZONA_MIC_BIAS_CTRL_2,
+                   ARIZONA_MICB1_ENA_SHIFT, 0, NULL, 0),
+
+SND_SOC_DAPM_PGA("Noise Generator", ARIZONA_COMFORT_NOISE_GENERATOR,
+                ARIZONA_NOISE_GEN_ENA_SHIFT, 0, NULL, 0),
+
+SND_SOC_DAPM_PGA("Tone Generator 1", ARIZONA_TONE_GENERATOR_1,
+                ARIZONA_TONE1_ENA_SHIFT, 0, NULL, 0),
+SND_SOC_DAPM_PGA("Tone Generator 2", ARIZONA_TONE_GENERATOR_1,
+                ARIZONA_TONE2_ENA_SHIFT, 0, NULL, 0),
+
+SND_SOC_DAPM_PGA("EQ1", ARIZONA_EQ1_1, ARIZONA_EQ1_ENA_SHIFT, 0, NULL, 0),
+SND_SOC_DAPM_PGA("EQ2", ARIZONA_EQ2_1, ARIZONA_EQ2_ENA_SHIFT, 0, NULL, 0),
+
+SND_SOC_DAPM_PGA("DRC1L", ARIZONA_DRC1_CTRL1, ARIZONA_DRC1L_ENA_SHIFT, 0,
+                NULL, 0),
+SND_SOC_DAPM_PGA("DRC1R", ARIZONA_DRC1_CTRL1, ARIZONA_DRC1R_ENA_SHIFT, 0,
+                NULL, 0),
+SND_SOC_DAPM_PGA("DRC2L", ARIZONA_DRC2_CTRL1, ARIZONA_DRC2L_ENA_SHIFT, 0,
+                NULL, 0),
+SND_SOC_DAPM_PGA("DRC2R", ARIZONA_DRC2_CTRL1, ARIZONA_DRC2R_ENA_SHIFT, 0,
+                NULL, 0),
+
+SND_SOC_DAPM_PGA("LHPF1", ARIZONA_HPLPF1_1, ARIZONA_LHPF1_ENA_SHIFT, 0,
+                NULL, 0),
+SND_SOC_DAPM_PGA("LHPF2", ARIZONA_HPLPF2_1, ARIZONA_LHPF2_ENA_SHIFT, 0,
+                NULL, 0),
+SND_SOC_DAPM_PGA("LHPF3", ARIZONA_HPLPF3_1, ARIZONA_LHPF3_ENA_SHIFT, 0,
+                NULL, 0),
+SND_SOC_DAPM_PGA("LHPF4", ARIZONA_HPLPF4_1, ARIZONA_LHPF4_ENA_SHIFT, 0,
+                NULL, 0),
+
+SND_SOC_DAPM_PGA("PWM1 Driver", ARIZONA_PWM_DRIVE_1, ARIZONA_PWM1_ENA_SHIFT,
+                0, NULL, 0),
+SND_SOC_DAPM_PGA("PWM2 Driver", ARIZONA_PWM_DRIVE_1, ARIZONA_PWM2_ENA_SHIFT,
+                0, NULL, 0),
+
+SND_SOC_DAPM_PGA("ASRC1L", ARIZONA_ASRC_ENABLE, ARIZONA_ASRC1L_ENA_SHIFT, 0,
+                NULL, 0),
+SND_SOC_DAPM_PGA("ASRC1R", ARIZONA_ASRC_ENABLE, ARIZONA_ASRC1R_ENA_SHIFT, 0,
+                NULL, 0),
+SND_SOC_DAPM_PGA("ASRC2L", ARIZONA_ASRC_ENABLE, ARIZONA_ASRC2L_ENA_SHIFT, 0,
+                NULL, 0),
+SND_SOC_DAPM_PGA("ASRC2R", ARIZONA_ASRC_ENABLE, ARIZONA_ASRC2R_ENA_SHIFT, 0,
+                NULL, 0),
+
+WM_ADSP2("DSP2", 1),
+WM_ADSP2("DSP3", 2),
+
+SND_SOC_DAPM_PGA("ISRC1INT1", ARIZONA_ISRC_1_CTRL_3,
+                ARIZONA_ISRC1_INT0_ENA_SHIFT, 0, NULL, 0),
+SND_SOC_DAPM_PGA("ISRC1INT2", ARIZONA_ISRC_1_CTRL_3,
+                ARIZONA_ISRC1_INT1_ENA_SHIFT, 0, NULL, 0),
+SND_SOC_DAPM_PGA("ISRC1INT3", ARIZONA_ISRC_1_CTRL_3,
+                ARIZONA_ISRC1_INT2_ENA_SHIFT, 0, NULL, 0),
+SND_SOC_DAPM_PGA("ISRC1INT4", ARIZONA_ISRC_1_CTRL_3,
+                ARIZONA_ISRC1_INT3_ENA_SHIFT, 0, NULL, 0),
+
+SND_SOC_DAPM_PGA("ISRC1DEC1", ARIZONA_ISRC_1_CTRL_3,
+                ARIZONA_ISRC1_DEC0_ENA_SHIFT, 0, NULL, 0),
+SND_SOC_DAPM_PGA("ISRC1DEC2", ARIZONA_ISRC_1_CTRL_3,
+                ARIZONA_ISRC1_DEC1_ENA_SHIFT, 0, NULL, 0),
+SND_SOC_DAPM_PGA("ISRC1DEC3", ARIZONA_ISRC_1_CTRL_3,
+                ARIZONA_ISRC1_DEC2_ENA_SHIFT, 0, NULL, 0),
+SND_SOC_DAPM_PGA("ISRC1DEC4", ARIZONA_ISRC_1_CTRL_3,
+                ARIZONA_ISRC1_DEC3_ENA_SHIFT, 0, NULL, 0),
+
+SND_SOC_DAPM_PGA("ISRC2INT1", ARIZONA_ISRC_2_CTRL_3,
+                ARIZONA_ISRC2_INT0_ENA_SHIFT, 0, NULL, 0),
+SND_SOC_DAPM_PGA("ISRC2INT2", ARIZONA_ISRC_2_CTRL_3,
+                ARIZONA_ISRC2_INT1_ENA_SHIFT, 0, NULL, 0),
+SND_SOC_DAPM_PGA("ISRC2INT3", ARIZONA_ISRC_2_CTRL_3,
+                ARIZONA_ISRC2_INT2_ENA_SHIFT, 0, NULL, 0),
+SND_SOC_DAPM_PGA("ISRC2INT4", ARIZONA_ISRC_2_CTRL_3,
+                ARIZONA_ISRC2_INT3_ENA_SHIFT, 0, NULL, 0),
+
+SND_SOC_DAPM_PGA("ISRC2DEC1", ARIZONA_ISRC_2_CTRL_3,
+                ARIZONA_ISRC2_DEC0_ENA_SHIFT, 0, NULL, 0),
+SND_SOC_DAPM_PGA("ISRC2DEC2", ARIZONA_ISRC_2_CTRL_3,
+                ARIZONA_ISRC2_DEC1_ENA_SHIFT, 0, NULL, 0),
+SND_SOC_DAPM_PGA("ISRC2DEC3", ARIZONA_ISRC_2_CTRL_3,
+                ARIZONA_ISRC2_DEC2_ENA_SHIFT, 0, NULL, 0),
+SND_SOC_DAPM_PGA("ISRC2DEC4", ARIZONA_ISRC_2_CTRL_3,
+                ARIZONA_ISRC2_DEC3_ENA_SHIFT, 0, NULL, 0),
+
+SND_SOC_DAPM_PGA("ISRC3INT1", ARIZONA_ISRC_3_CTRL_3,
+                ARIZONA_ISRC3_INT0_ENA_SHIFT, 0, NULL, 0),
+SND_SOC_DAPM_PGA("ISRC3INT2", ARIZONA_ISRC_3_CTRL_3,
+                ARIZONA_ISRC3_INT1_ENA_SHIFT, 0, NULL, 0),
+SND_SOC_DAPM_PGA("ISRC3INT3", ARIZONA_ISRC_3_CTRL_3,
+                ARIZONA_ISRC3_INT2_ENA_SHIFT, 0, NULL, 0),
+SND_SOC_DAPM_PGA("ISRC3INT4", ARIZONA_ISRC_3_CTRL_3,
+                ARIZONA_ISRC3_INT3_ENA_SHIFT, 0, NULL, 0),
+
+SND_SOC_DAPM_PGA("ISRC3DEC1", ARIZONA_ISRC_3_CTRL_3,
+                ARIZONA_ISRC3_DEC0_ENA_SHIFT, 0, NULL, 0),
+SND_SOC_DAPM_PGA("ISRC3DEC2", ARIZONA_ISRC_3_CTRL_3,
+                ARIZONA_ISRC3_DEC1_ENA_SHIFT, 0, NULL, 0),
+SND_SOC_DAPM_PGA("ISRC3DEC3", ARIZONA_ISRC_3_CTRL_3,
+                ARIZONA_ISRC3_DEC2_ENA_SHIFT, 0, NULL, 0),
+SND_SOC_DAPM_PGA("ISRC3DEC4", ARIZONA_ISRC_3_CTRL_3,
+                ARIZONA_ISRC3_DEC3_ENA_SHIFT, 0, NULL, 0),
+
+SND_SOC_DAPM_MUX("AEC Loopback", ARIZONA_DAC_AEC_CONTROL_1,
+                      ARIZONA_AEC_LOOPBACK_ENA_SHIFT, 0,
+                      &cs47l24_aec_loopback_mux),
+
+SND_SOC_DAPM_AIF_OUT("AIF1TX1", NULL, 0,
+                    ARIZONA_AIF1_TX_ENABLES, ARIZONA_AIF1TX1_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_OUT("AIF1TX2", NULL, 0,
+                    ARIZONA_AIF1_TX_ENABLES, ARIZONA_AIF1TX2_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_OUT("AIF1TX3", NULL, 0,
+                    ARIZONA_AIF1_TX_ENABLES, ARIZONA_AIF1TX3_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_OUT("AIF1TX4", NULL, 0,
+                    ARIZONA_AIF1_TX_ENABLES, ARIZONA_AIF1TX4_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_OUT("AIF1TX5", NULL, 0,
+                    ARIZONA_AIF1_TX_ENABLES, ARIZONA_AIF1TX5_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_OUT("AIF1TX6", NULL, 0,
+                    ARIZONA_AIF1_TX_ENABLES, ARIZONA_AIF1TX6_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_OUT("AIF1TX7", NULL, 0,
+                    ARIZONA_AIF1_TX_ENABLES, ARIZONA_AIF1TX7_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_OUT("AIF1TX8", NULL, 0,
+                    ARIZONA_AIF1_TX_ENABLES, ARIZONA_AIF1TX8_ENA_SHIFT, 0),
+
+SND_SOC_DAPM_AIF_IN("AIF1RX1", NULL, 0,
+                   ARIZONA_AIF1_RX_ENABLES, ARIZONA_AIF1RX1_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_IN("AIF1RX2", NULL, 0,
+                   ARIZONA_AIF1_RX_ENABLES, ARIZONA_AIF1RX2_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_IN("AIF1RX3", NULL, 0,
+                   ARIZONA_AIF1_RX_ENABLES, ARIZONA_AIF1RX3_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_IN("AIF1RX4", NULL, 0,
+                   ARIZONA_AIF1_RX_ENABLES, ARIZONA_AIF1RX4_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_IN("AIF1RX5", NULL, 0,
+                   ARIZONA_AIF1_RX_ENABLES, ARIZONA_AIF1RX5_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_IN("AIF1RX6", NULL, 0,
+                   ARIZONA_AIF1_RX_ENABLES, ARIZONA_AIF1RX6_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_IN("AIF1RX7", NULL, 0,
+                   ARIZONA_AIF1_RX_ENABLES, ARIZONA_AIF1RX7_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_IN("AIF1RX8", NULL, 0,
+                   ARIZONA_AIF1_RX_ENABLES, ARIZONA_AIF1RX8_ENA_SHIFT, 0),
+
+SND_SOC_DAPM_AIF_OUT("AIF2TX1", NULL, 0,
+                    ARIZONA_AIF2_TX_ENABLES, ARIZONA_AIF2TX1_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_OUT("AIF2TX2", NULL, 0,
+                    ARIZONA_AIF2_TX_ENABLES, ARIZONA_AIF2TX2_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_OUT("AIF2TX3", NULL, 0,
+                    ARIZONA_AIF2_TX_ENABLES, ARIZONA_AIF2TX3_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_OUT("AIF2TX4", NULL, 0,
+                    ARIZONA_AIF2_TX_ENABLES, ARIZONA_AIF2TX4_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_OUT("AIF2TX5", NULL, 0,
+                    ARIZONA_AIF2_TX_ENABLES, ARIZONA_AIF2TX5_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_OUT("AIF2TX6", NULL, 0,
+                    ARIZONA_AIF2_TX_ENABLES, ARIZONA_AIF2TX6_ENA_SHIFT, 0),
+
+SND_SOC_DAPM_AIF_IN("AIF2RX1", NULL, 0,
+                   ARIZONA_AIF2_RX_ENABLES, ARIZONA_AIF2RX1_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_IN("AIF2RX2", NULL, 0,
+                   ARIZONA_AIF2_RX_ENABLES, ARIZONA_AIF2RX2_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_IN("AIF2RX3", NULL, 0,
+                   ARIZONA_AIF2_RX_ENABLES, ARIZONA_AIF2RX3_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_IN("AIF2RX4", NULL, 0,
+                   ARIZONA_AIF2_RX_ENABLES, ARIZONA_AIF2RX4_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_IN("AIF2RX5", NULL, 0,
+                   ARIZONA_AIF2_RX_ENABLES, ARIZONA_AIF2RX5_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_IN("AIF2RX6", NULL, 0,
+                   ARIZONA_AIF2_RX_ENABLES, ARIZONA_AIF2RX6_ENA_SHIFT, 0),
+
+SND_SOC_DAPM_AIF_OUT("AIF3TX1", NULL, 0,
+                    ARIZONA_AIF3_TX_ENABLES, ARIZONA_AIF3TX1_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_OUT("AIF3TX2", NULL, 0,
+                    ARIZONA_AIF3_TX_ENABLES, ARIZONA_AIF3TX2_ENA_SHIFT, 0),
+
+SND_SOC_DAPM_AIF_IN("AIF3RX1", NULL, 0,
+                   ARIZONA_AIF3_RX_ENABLES, ARIZONA_AIF3RX1_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_IN("AIF3RX2", NULL, 0,
+                   ARIZONA_AIF3_RX_ENABLES, ARIZONA_AIF3RX2_ENA_SHIFT, 0),
+
+SND_SOC_DAPM_PGA_E("OUT1L", SND_SOC_NOPM,
+                  ARIZONA_OUT1L_ENA_SHIFT, 0, NULL, 0, arizona_hp_ev,
+                  SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD |
+                  SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU),
+SND_SOC_DAPM_PGA_E("OUT1R", SND_SOC_NOPM,
+                  ARIZONA_OUT1R_ENA_SHIFT, 0, NULL, 0, arizona_hp_ev,
+                  SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD |
+                  SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU),
+
+ARIZONA_MIXER_WIDGETS(EQ1, "EQ1"),
+ARIZONA_MIXER_WIDGETS(EQ2, "EQ2"),
+
+ARIZONA_MIXER_WIDGETS(DRC1L, "DRC1L"),
+ARIZONA_MIXER_WIDGETS(DRC1R, "DRC1R"),
+ARIZONA_MIXER_WIDGETS(DRC2L, "DRC2L"),
+ARIZONA_MIXER_WIDGETS(DRC2R, "DRC2R"),
+
+ARIZONA_MIXER_WIDGETS(LHPF1, "LHPF1"),
+ARIZONA_MIXER_WIDGETS(LHPF2, "LHPF2"),
+ARIZONA_MIXER_WIDGETS(LHPF3, "LHPF3"),
+ARIZONA_MIXER_WIDGETS(LHPF4, "LHPF4"),
+
+ARIZONA_MIXER_WIDGETS(PWM1, "PWM1"),
+ARIZONA_MIXER_WIDGETS(PWM2, "PWM2"),
+
+ARIZONA_MIXER_WIDGETS(OUT1L, "HPOUT1L"),
+ARIZONA_MIXER_WIDGETS(OUT1R, "HPOUT1R"),
+ARIZONA_MIXER_WIDGETS(SPKOUT, "SPKOUT"),
+
+ARIZONA_MIXER_WIDGETS(AIF1TX1, "AIF1TX1"),
+ARIZONA_MIXER_WIDGETS(AIF1TX2, "AIF1TX2"),
+ARIZONA_MIXER_WIDGETS(AIF1TX3, "AIF1TX3"),
+ARIZONA_MIXER_WIDGETS(AIF1TX4, "AIF1TX4"),
+ARIZONA_MIXER_WIDGETS(AIF1TX5, "AIF1TX5"),
+ARIZONA_MIXER_WIDGETS(AIF1TX6, "AIF1TX6"),
+ARIZONA_MIXER_WIDGETS(AIF1TX7, "AIF1TX7"),
+ARIZONA_MIXER_WIDGETS(AIF1TX8, "AIF1TX8"),
+
+ARIZONA_MIXER_WIDGETS(AIF2TX1, "AIF2TX1"),
+ARIZONA_MIXER_WIDGETS(AIF2TX2, "AIF2TX2"),
+ARIZONA_MIXER_WIDGETS(AIF2TX3, "AIF2TX3"),
+ARIZONA_MIXER_WIDGETS(AIF2TX4, "AIF2TX4"),
+ARIZONA_MIXER_WIDGETS(AIF2TX5, "AIF2TX5"),
+ARIZONA_MIXER_WIDGETS(AIF2TX6, "AIF2TX6"),
+
+ARIZONA_MIXER_WIDGETS(AIF3TX1, "AIF3TX1"),
+ARIZONA_MIXER_WIDGETS(AIF3TX2, "AIF3TX2"),
+
+ARIZONA_MUX_WIDGETS(ASRC1L, "ASRC1L"),
+ARIZONA_MUX_WIDGETS(ASRC1R, "ASRC1R"),
+ARIZONA_MUX_WIDGETS(ASRC2L, "ASRC2L"),
+ARIZONA_MUX_WIDGETS(ASRC2R, "ASRC2R"),
+
+ARIZONA_DSP_WIDGETS(DSP2, "DSP2"),
+ARIZONA_DSP_WIDGETS(DSP3, "DSP3"),
+
+ARIZONA_MUX_WIDGETS(ISRC1DEC1, "ISRC1DEC1"),
+ARIZONA_MUX_WIDGETS(ISRC1DEC2, "ISRC1DEC2"),
+ARIZONA_MUX_WIDGETS(ISRC1DEC3, "ISRC1DEC3"),
+ARIZONA_MUX_WIDGETS(ISRC1DEC4, "ISRC1DEC4"),
+
+ARIZONA_MUX_WIDGETS(ISRC1INT1, "ISRC1INT1"),
+ARIZONA_MUX_WIDGETS(ISRC1INT2, "ISRC1INT2"),
+ARIZONA_MUX_WIDGETS(ISRC1INT3, "ISRC1INT3"),
+ARIZONA_MUX_WIDGETS(ISRC1INT4, "ISRC1INT4"),
+
+ARIZONA_MUX_WIDGETS(ISRC2DEC1, "ISRC2DEC1"),
+ARIZONA_MUX_WIDGETS(ISRC2DEC2, "ISRC2DEC2"),
+ARIZONA_MUX_WIDGETS(ISRC2DEC3, "ISRC2DEC3"),
+ARIZONA_MUX_WIDGETS(ISRC2DEC4, "ISRC2DEC4"),
+
+ARIZONA_MUX_WIDGETS(ISRC2INT1, "ISRC2INT1"),
+ARIZONA_MUX_WIDGETS(ISRC2INT2, "ISRC2INT2"),
+ARIZONA_MUX_WIDGETS(ISRC2INT3, "ISRC2INT3"),
+ARIZONA_MUX_WIDGETS(ISRC2INT4, "ISRC2INT4"),
+
+ARIZONA_MUX_WIDGETS(ISRC3DEC1, "ISRC3DEC1"),
+ARIZONA_MUX_WIDGETS(ISRC3DEC2, "ISRC3DEC2"),
+ARIZONA_MUX_WIDGETS(ISRC3DEC3, "ISRC3DEC3"),
+ARIZONA_MUX_WIDGETS(ISRC3DEC4, "ISRC3DEC4"),
+
+ARIZONA_MUX_WIDGETS(ISRC3INT1, "ISRC3INT1"),
+ARIZONA_MUX_WIDGETS(ISRC3INT2, "ISRC3INT2"),
+ARIZONA_MUX_WIDGETS(ISRC3INT3, "ISRC3INT3"),
+ARIZONA_MUX_WIDGETS(ISRC3INT4, "ISRC3INT4"),
+
+SND_SOC_DAPM_OUTPUT("HPOUT1L"),
+SND_SOC_DAPM_OUTPUT("HPOUT1R"),
+SND_SOC_DAPM_OUTPUT("SPKOUTN"),
+SND_SOC_DAPM_OUTPUT("SPKOUTP"),
+
+SND_SOC_DAPM_OUTPUT("MICSUPP"),
+};
+
+#define ARIZONA_MIXER_INPUT_ROUTES(name)       \
+       { name, "Noise Generator", "Noise Generator" }, \
+       { name, "Tone Generator 1", "Tone Generator 1" }, \
+       { name, "Tone Generator 2", "Tone Generator 2" }, \
+       { name, "Haptics", "HAPTICS" }, \
+       { name, "AEC", "AEC Loopback" }, \
+       { name, "IN1L", "IN1L PGA" }, \
+       { name, "IN1R", "IN1R PGA" }, \
+       { name, "IN2L", "IN2L PGA" }, \
+       { name, "IN2R", "IN2R PGA" }, \
+       { name, "AIF1RX1", "AIF1RX1" }, \
+       { name, "AIF1RX2", "AIF1RX2" }, \
+       { name, "AIF1RX3", "AIF1RX3" }, \
+       { name, "AIF1RX4", "AIF1RX4" }, \
+       { name, "AIF1RX5", "AIF1RX5" }, \
+       { name, "AIF1RX6", "AIF1RX6" }, \
+       { name, "AIF1RX7", "AIF1RX7" }, \
+       { name, "AIF1RX8", "AIF1RX8" }, \
+       { name, "AIF2RX1", "AIF2RX1" }, \
+       { name, "AIF2RX2", "AIF2RX2" }, \
+       { name, "AIF2RX3", "AIF2RX3" }, \
+       { name, "AIF2RX4", "AIF2RX4" }, \
+       { name, "AIF2RX5", "AIF2RX5" }, \
+       { name, "AIF2RX6", "AIF2RX6" }, \
+       { name, "AIF3RX1", "AIF3RX1" }, \
+       { name, "AIF3RX2", "AIF3RX2" }, \
+       { name, "EQ1", "EQ1" }, \
+       { name, "EQ2", "EQ2" }, \
+       { name, "DRC1L", "DRC1L" }, \
+       { name, "DRC1R", "DRC1R" }, \
+       { name, "DRC2L", "DRC2L" }, \
+       { name, "DRC2R", "DRC2R" }, \
+       { name, "LHPF1", "LHPF1" }, \
+       { name, "LHPF2", "LHPF2" }, \
+       { name, "LHPF3", "LHPF3" }, \
+       { name, "LHPF4", "LHPF4" }, \
+       { name, "ASRC1L", "ASRC1L" }, \
+       { name, "ASRC1R", "ASRC1R" }, \
+       { name, "ASRC2L", "ASRC2L" }, \
+       { name, "ASRC2R", "ASRC2R" }, \
+       { name, "ISRC1DEC1", "ISRC1DEC1" }, \
+       { name, "ISRC1DEC2", "ISRC1DEC2" }, \
+       { name, "ISRC1DEC3", "ISRC1DEC3" }, \
+       { name, "ISRC1DEC4", "ISRC1DEC4" }, \
+       { name, "ISRC1INT1", "ISRC1INT1" }, \
+       { name, "ISRC1INT2", "ISRC1INT2" }, \
+       { name, "ISRC1INT3", "ISRC1INT3" }, \
+       { name, "ISRC1INT4", "ISRC1INT4" }, \
+       { name, "ISRC2DEC1", "ISRC2DEC1" }, \
+       { name, "ISRC2DEC2", "ISRC2DEC2" }, \
+       { name, "ISRC2DEC3", "ISRC2DEC3" }, \
+       { name, "ISRC2DEC4", "ISRC2DEC4" }, \
+       { name, "ISRC2INT1", "ISRC2INT1" }, \
+       { name, "ISRC2INT2", "ISRC2INT2" }, \
+       { name, "ISRC2INT3", "ISRC2INT3" }, \
+       { name, "ISRC2INT4", "ISRC2INT4" }, \
+       { name, "ISRC3DEC1", "ISRC3DEC1" }, \
+       { name, "ISRC3DEC2", "ISRC3DEC2" }, \
+       { name, "ISRC3DEC3", "ISRC3DEC3" }, \
+       { name, "ISRC3DEC4", "ISRC3DEC4" }, \
+       { name, "ISRC3INT1", "ISRC3INT1" }, \
+       { name, "ISRC3INT2", "ISRC3INT2" }, \
+       { name, "ISRC3INT3", "ISRC3INT3" }, \
+       { name, "ISRC3INT4", "ISRC3INT4" }, \
+       { name, "DSP2.1", "DSP2" }, \
+       { name, "DSP2.2", "DSP2" }, \
+       { name, "DSP2.3", "DSP2" }, \
+       { name, "DSP2.4", "DSP2" }, \
+       { name, "DSP2.5", "DSP2" }, \
+       { name, "DSP2.6", "DSP2" }, \
+       { name, "DSP3.1", "DSP3" }, \
+       { name, "DSP3.2", "DSP3" }, \
+       { name, "DSP3.3", "DSP3" }, \
+       { name, "DSP3.4", "DSP3" }, \
+       { name, "DSP3.5", "DSP3" }, \
+       { name, "DSP3.6", "DSP3" }
+
+static const struct snd_soc_dapm_route cs47l24_dapm_routes[] = {
+       { "OUT1L", NULL, "CPVDD" },
+       { "OUT1R", NULL, "CPVDD" },
+
+       { "OUT4L", NULL, "SPKVDD" },
+
+       { "OUT1L", NULL, "SYSCLK" },
+       { "OUT1R", NULL, "SYSCLK" },
+       { "OUT4L", NULL, "SYSCLK" },
+
+       { "IN1L", NULL, "SYSCLK" },
+       { "IN1R", NULL, "SYSCLK" },
+       { "IN2L", NULL, "SYSCLK" },
+       { "IN2R", NULL, "SYSCLK" },
+
+       { "MICBIAS1", NULL, "MICVDD" },
+       { "MICBIAS2", NULL, "MICVDD" },
+
+       { "Noise Generator", NULL, "SYSCLK" },
+       { "Tone Generator 1", NULL, "SYSCLK" },
+       { "Tone Generator 2", NULL, "SYSCLK" },
+
+       { "Noise Generator", NULL, "NOISE" },
+       { "Tone Generator 1", NULL, "TONE" },
+       { "Tone Generator 2", NULL, "TONE" },
+
+       { "AIF1 Capture", NULL, "AIF1TX1" },
+       { "AIF1 Capture", NULL, "AIF1TX2" },
+       { "AIF1 Capture", NULL, "AIF1TX3" },
+       { "AIF1 Capture", NULL, "AIF1TX4" },
+       { "AIF1 Capture", NULL, "AIF1TX5" },
+       { "AIF1 Capture", NULL, "AIF1TX6" },
+       { "AIF1 Capture", NULL, "AIF1TX7" },
+       { "AIF1 Capture", NULL, "AIF1TX8" },
+
+       { "AIF1RX1", NULL, "AIF1 Playback" },
+       { "AIF1RX2", NULL, "AIF1 Playback" },
+       { "AIF1RX3", NULL, "AIF1 Playback" },
+       { "AIF1RX4", NULL, "AIF1 Playback" },
+       { "AIF1RX5", NULL, "AIF1 Playback" },
+       { "AIF1RX6", NULL, "AIF1 Playback" },
+       { "AIF1RX7", NULL, "AIF1 Playback" },
+       { "AIF1RX8", NULL, "AIF1 Playback" },
+
+       { "AIF2 Capture", NULL, "AIF2TX1" },
+       { "AIF2 Capture", NULL, "AIF2TX2" },
+       { "AIF2 Capture", NULL, "AIF2TX3" },
+       { "AIF2 Capture", NULL, "AIF2TX4" },
+       { "AIF2 Capture", NULL, "AIF2TX5" },
+       { "AIF2 Capture", NULL, "AIF2TX6" },
+
+       { "AIF2RX1", NULL, "AIF2 Playback" },
+       { "AIF2RX2", NULL, "AIF2 Playback" },
+       { "AIF2RX3", NULL, "AIF2 Playback" },
+       { "AIF2RX4", NULL, "AIF2 Playback" },
+       { "AIF2RX5", NULL, "AIF2 Playback" },
+       { "AIF2RX6", NULL, "AIF2 Playback" },
+
+       { "AIF3 Capture", NULL, "AIF3TX1" },
+       { "AIF3 Capture", NULL, "AIF3TX2" },
+
+       { "AIF3RX1", NULL, "AIF3 Playback" },
+       { "AIF3RX2", NULL, "AIF3 Playback" },
+
+       { "AIF1 Playback", NULL, "SYSCLK" },
+       { "AIF2 Playback", NULL, "SYSCLK" },
+       { "AIF3 Playback", NULL, "SYSCLK" },
+
+       { "AIF1 Capture", NULL, "SYSCLK" },
+       { "AIF2 Capture", NULL, "SYSCLK" },
+       { "AIF3 Capture", NULL, "SYSCLK" },
+
+       { "IN1L PGA", NULL, "IN1L" },
+       { "IN1R PGA", NULL, "IN1R" },
+
+       { "IN2L PGA", NULL, "IN2L" },
+       { "IN2R PGA", NULL, "IN2R" },
+
+       ARIZONA_MIXER_ROUTES("OUT1L", "HPOUT1L"),
+       ARIZONA_MIXER_ROUTES("OUT1R", "HPOUT1R"),
+
+       ARIZONA_MIXER_ROUTES("OUT4L", "SPKOUT"),
+
+       ARIZONA_MIXER_ROUTES("PWM1 Driver", "PWM1"),
+       ARIZONA_MIXER_ROUTES("PWM2 Driver", "PWM2"),
+
+       ARIZONA_MIXER_ROUTES("AIF1TX1", "AIF1TX1"),
+       ARIZONA_MIXER_ROUTES("AIF1TX2", "AIF1TX2"),
+       ARIZONA_MIXER_ROUTES("AIF1TX3", "AIF1TX3"),
+       ARIZONA_MIXER_ROUTES("AIF1TX4", "AIF1TX4"),
+       ARIZONA_MIXER_ROUTES("AIF1TX5", "AIF1TX5"),
+       ARIZONA_MIXER_ROUTES("AIF1TX6", "AIF1TX6"),
+       ARIZONA_MIXER_ROUTES("AIF1TX7", "AIF1TX7"),
+       ARIZONA_MIXER_ROUTES("AIF1TX8", "AIF1TX8"),
+
+       ARIZONA_MIXER_ROUTES("AIF2TX1", "AIF2TX1"),
+       ARIZONA_MIXER_ROUTES("AIF2TX2", "AIF2TX2"),
+       ARIZONA_MIXER_ROUTES("AIF2TX3", "AIF2TX3"),
+       ARIZONA_MIXER_ROUTES("AIF2TX4", "AIF2TX4"),
+       ARIZONA_MIXER_ROUTES("AIF2TX5", "AIF2TX5"),
+       ARIZONA_MIXER_ROUTES("AIF2TX6", "AIF2TX6"),
+
+       ARIZONA_MIXER_ROUTES("AIF3TX1", "AIF3TX1"),
+       ARIZONA_MIXER_ROUTES("AIF3TX2", "AIF3TX2"),
+
+       ARIZONA_MIXER_ROUTES("EQ1", "EQ1"),
+       ARIZONA_MIXER_ROUTES("EQ2", "EQ2"),
+
+       ARIZONA_MIXER_ROUTES("DRC1L", "DRC1L"),
+       ARIZONA_MIXER_ROUTES("DRC1R", "DRC1R"),
+       ARIZONA_MIXER_ROUTES("DRC2L", "DRC2L"),
+       ARIZONA_MIXER_ROUTES("DRC2R", "DRC2R"),
+
+       ARIZONA_MIXER_ROUTES("LHPF1", "LHPF1"),
+       ARIZONA_MIXER_ROUTES("LHPF2", "LHPF2"),
+       ARIZONA_MIXER_ROUTES("LHPF3", "LHPF3"),
+       ARIZONA_MIXER_ROUTES("LHPF4", "LHPF4"),
+
+       ARIZONA_MUX_ROUTES("ASRC1L", "ASRC1L"),
+       ARIZONA_MUX_ROUTES("ASRC1R", "ASRC1R"),
+       ARIZONA_MUX_ROUTES("ASRC2L", "ASRC2L"),
+       ARIZONA_MUX_ROUTES("ASRC2R", "ASRC2R"),
+
+       ARIZONA_DSP_ROUTES("DSP2"),
+       ARIZONA_DSP_ROUTES("DSP3"),
+
+       ARIZONA_MUX_ROUTES("ISRC1INT1", "ISRC1INT1"),
+       ARIZONA_MUX_ROUTES("ISRC1INT2", "ISRC1INT2"),
+       ARIZONA_MUX_ROUTES("ISRC1INT3", "ISRC1INT3"),
+       ARIZONA_MUX_ROUTES("ISRC1INT4", "ISRC1INT4"),
+
+       ARIZONA_MUX_ROUTES("ISRC1DEC1", "ISRC1DEC1"),
+       ARIZONA_MUX_ROUTES("ISRC1DEC2", "ISRC1DEC2"),
+       ARIZONA_MUX_ROUTES("ISRC1DEC3", "ISRC1DEC3"),
+       ARIZONA_MUX_ROUTES("ISRC1DEC4", "ISRC1DEC4"),
+
+       ARIZONA_MUX_ROUTES("ISRC2INT1", "ISRC2INT1"),
+       ARIZONA_MUX_ROUTES("ISRC2INT2", "ISRC2INT2"),
+       ARIZONA_MUX_ROUTES("ISRC2INT3", "ISRC2INT3"),
+       ARIZONA_MUX_ROUTES("ISRC2INT4", "ISRC2INT4"),
+
+       ARIZONA_MUX_ROUTES("ISRC2DEC1", "ISRC2DEC1"),
+       ARIZONA_MUX_ROUTES("ISRC2DEC2", "ISRC2DEC2"),
+       ARIZONA_MUX_ROUTES("ISRC2DEC3", "ISRC2DEC3"),
+       ARIZONA_MUX_ROUTES("ISRC2DEC4", "ISRC2DEC4"),
+
+       ARIZONA_MUX_ROUTES("ISRC3INT1", "ISRC3INT1"),
+       ARIZONA_MUX_ROUTES("ISRC3INT2", "ISRC3INT2"),
+       ARIZONA_MUX_ROUTES("ISRC3INT3", "ISRC3INT3"),
+       ARIZONA_MUX_ROUTES("ISRC3INT4", "ISRC3INT4"),
+
+       ARIZONA_MUX_ROUTES("ISRC3DEC1", "ISRC3DEC1"),
+       ARIZONA_MUX_ROUTES("ISRC3DEC2", "ISRC3DEC2"),
+       ARIZONA_MUX_ROUTES("ISRC3DEC3", "ISRC3DEC3"),
+       ARIZONA_MUX_ROUTES("ISRC3DEC4", "ISRC3DEC4"),
+
+       { "AEC Loopback", "HPOUT1L", "OUT1L" },
+       { "AEC Loopback", "HPOUT1R", "OUT1R" },
+       { "HPOUT1L", NULL, "OUT1L" },
+       { "HPOUT1R", NULL, "OUT1R" },
+
+       { "AEC Loopback", "SPKOUT", "OUT4L" },
+       { "SPKOUTN", NULL, "OUT4L" },
+       { "SPKOUTP", NULL, "OUT4L" },
+
+       { "MICSUPP", NULL, "SYSCLK" },
+
+       { "DRC1 Signal Activity", NULL, "DRC1L" },
+       { "DRC1 Signal Activity", NULL, "DRC1R" },
+       { "DRC2 Signal Activity", NULL, "DRC2L" },
+       { "DRC2 Signal Activity", NULL, "DRC2R" },
+};
+
+static int cs47l24_set_fll(struct snd_soc_codec *codec, int fll_id, int source,
+                         unsigned int Fref, unsigned int Fout)
+{
+       struct cs47l24_priv *cs47l24 = snd_soc_codec_get_drvdata(codec);
+
+       switch (fll_id) {
+       case CS47L24_FLL1:
+               return arizona_set_fll(&cs47l24->fll[0], source, Fref, Fout);
+       case CS47L24_FLL2:
+               return arizona_set_fll(&cs47l24->fll[1], source, Fref, Fout);
+       case CS47L24_FLL1_REFCLK:
+               return arizona_set_fll_refclk(&cs47l24->fll[0], source, Fref,
+                                             Fout);
+       case CS47L24_FLL2_REFCLK:
+               return arizona_set_fll_refclk(&cs47l24->fll[1], source, Fref,
+                                             Fout);
+       default:
+               return -EINVAL;
+       }
+}
+
+#define CS47L24_RATES SNDRV_PCM_RATE_8000_192000
+
+#define CS47L24_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\
+                        SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE)
+
+static struct snd_soc_dai_driver cs47l24_dai[] = {
+       {
+               .name = "cs47l24-aif1",
+               .id = 1,
+               .base = ARIZONA_AIF1_BCLK_CTRL,
+               .playback = {
+                       .stream_name = "AIF1 Playback",
+                       .channels_min = 1,
+                       .channels_max = 8,
+                       .rates = CS47L24_RATES,
+                       .formats = CS47L24_FORMATS,
+               },
+               .capture = {
+                        .stream_name = "AIF1 Capture",
+                        .channels_min = 1,
+                        .channels_max = 8,
+                        .rates = CS47L24_RATES,
+                        .formats = CS47L24_FORMATS,
+                },
+               .ops = &arizona_dai_ops,
+               .symmetric_rates = 1,
+               .symmetric_samplebits = 1,
+       },
+       {
+               .name = "cs47l24-aif2",
+               .id = 2,
+               .base = ARIZONA_AIF2_BCLK_CTRL,
+               .playback = {
+                       .stream_name = "AIF2 Playback",
+                       .channels_min = 1,
+                       .channels_max = 6,
+                       .rates = CS47L24_RATES,
+                       .formats = CS47L24_FORMATS,
+               },
+               .capture = {
+                        .stream_name = "AIF2 Capture",
+                        .channels_min = 1,
+                        .channels_max = 6,
+                        .rates = CS47L24_RATES,
+                        .formats = CS47L24_FORMATS,
+                },
+               .ops = &arizona_dai_ops,
+               .symmetric_rates = 1,
+               .symmetric_samplebits = 1,
+       },
+       {
+               .name = "cs47l24-aif3",
+               .id = 3,
+               .base = ARIZONA_AIF3_BCLK_CTRL,
+               .playback = {
+                       .stream_name = "AIF3 Playback",
+                       .channels_min = 1,
+                       .channels_max = 2,
+                       .rates = CS47L24_RATES,
+                       .formats = CS47L24_FORMATS,
+               },
+               .capture = {
+                        .stream_name = "AIF3 Capture",
+                        .channels_min = 1,
+                        .channels_max = 2,
+                        .rates = CS47L24_RATES,
+                        .formats = CS47L24_FORMATS,
+                },
+               .ops = &arizona_dai_ops,
+               .symmetric_rates = 1,
+               .symmetric_samplebits = 1,
+       },
+};
+
+static int cs47l24_codec_probe(struct snd_soc_codec *codec)
+{
+       struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
+       struct cs47l24_priv *priv = snd_soc_codec_get_drvdata(codec);
+       int ret;
+
+       priv->core.arizona->dapm = dapm;
+
+       arizona_init_spk(codec);
+       arizona_init_gpio(codec);
+       arizona_init_mono(codec);
+
+       ret = wm_adsp2_codec_probe(&priv->core.adsp[1], codec);
+       if (ret)
+               goto err_adsp2_codec_probe;
+
+       ret = wm_adsp2_codec_probe(&priv->core.adsp[2], codec);
+       if (ret)
+               goto err_adsp2_codec_probe;
+
+       ret = snd_soc_add_codec_controls(codec,
+                                        &arizona_adsp2_rate_controls[1], 2);
+       if (ret)
+               goto err_adsp2_codec_probe;
+
+       snd_soc_dapm_disable_pin(dapm, "HAPTICS");
+
+       return 0;
+
+err_adsp2_codec_probe:
+       wm_adsp2_codec_remove(&priv->core.adsp[1], codec);
+       wm_adsp2_codec_remove(&priv->core.adsp[2], codec);
+
+       return ret;
+}
+
+static int cs47l24_codec_remove(struct snd_soc_codec *codec)
+{
+       struct cs47l24_priv *priv = snd_soc_codec_get_drvdata(codec);
+
+
+       wm_adsp2_codec_remove(&priv->core.adsp[1], codec);
+       wm_adsp2_codec_remove(&priv->core.adsp[2], codec);
+
+       priv->core.arizona->dapm = NULL;
+
+       return 0;
+}
+
+#define CS47L24_DIG_VU 0x0200
+
+static unsigned int cs47l24_digital_vu[] = {
+       ARIZONA_DAC_DIGITAL_VOLUME_1L,
+       ARIZONA_DAC_DIGITAL_VOLUME_1R,
+       ARIZONA_DAC_DIGITAL_VOLUME_4L,
+};
+
+static struct regmap *cs47l24_get_regmap(struct device *dev)
+{
+       struct cs47l24_priv *priv = dev_get_drvdata(dev);
+
+       return priv->core.arizona->regmap;
+}
+
+static struct snd_soc_codec_driver soc_codec_dev_cs47l24 = {
+       .probe = cs47l24_codec_probe,
+       .remove = cs47l24_codec_remove,
+       .get_regmap = cs47l24_get_regmap,
+
+       .idle_bias_off = true,
+
+       .set_sysclk = arizona_set_sysclk,
+       .set_pll = cs47l24_set_fll,
+
+       .controls = cs47l24_snd_controls,
+       .num_controls = ARRAY_SIZE(cs47l24_snd_controls),
+       .dapm_widgets = cs47l24_dapm_widgets,
+       .num_dapm_widgets = ARRAY_SIZE(cs47l24_dapm_widgets),
+       .dapm_routes = cs47l24_dapm_routes,
+       .num_dapm_routes = ARRAY_SIZE(cs47l24_dapm_routes),
+};
+
+static int cs47l24_probe(struct platform_device *pdev)
+{
+       struct arizona *arizona = dev_get_drvdata(pdev->dev.parent);
+       struct cs47l24_priv *cs47l24;
+       int i, ret;
+
+       BUILD_BUG_ON(ARRAY_SIZE(cs47l24_dai) > ARIZONA_MAX_DAI);
+
+       cs47l24 = devm_kzalloc(&pdev->dev, sizeof(struct cs47l24_priv),
+                             GFP_KERNEL);
+       if (!cs47l24)
+               return -ENOMEM;
+
+       platform_set_drvdata(pdev, cs47l24);
+
+       cs47l24->core.arizona = arizona;
+       cs47l24->core.num_inputs = 4;
+
+       for (i = 1; i <= 2; i++) {
+               cs47l24->core.adsp[i].part = "cs47l24";
+               cs47l24->core.adsp[i].num = i + 1;
+               cs47l24->core.adsp[i].type = WMFW_ADSP2;
+               cs47l24->core.adsp[i].dev = arizona->dev;
+               cs47l24->core.adsp[i].regmap = arizona->regmap;
+
+               cs47l24->core.adsp[i].base = ARIZONA_DSP1_CONTROL_1 +
+                                            (0x100 * i);
+               cs47l24->core.adsp[i].mem = cs47l24_dsp_regions[i - 1];
+               cs47l24->core.adsp[i].num_mems =
+                               ARRAY_SIZE(cs47l24_dsp2_regions);
+
+               ret = wm_adsp2_init(&cs47l24->core.adsp[i]);
+               if (ret != 0)
+                       return ret;
+       }
+
+       for (i = 0; i < ARRAY_SIZE(cs47l24->fll); i++)
+               cs47l24->fll[i].vco_mult = 3;
+
+       arizona_init_fll(arizona, 1, ARIZONA_FLL1_CONTROL_1 - 1,
+                        ARIZONA_IRQ_FLL1_LOCK, ARIZONA_IRQ_FLL1_CLOCK_OK,
+                        &cs47l24->fll[0]);
+       arizona_init_fll(arizona, 2, ARIZONA_FLL2_CONTROL_1 - 1,
+                        ARIZONA_IRQ_FLL2_LOCK, ARIZONA_IRQ_FLL2_CLOCK_OK,
+                        &cs47l24->fll[1]);
+
+       /* SR2 fixed at 8kHz, SR3 fixed at 16kHz */
+       regmap_update_bits(arizona->regmap, ARIZONA_SAMPLE_RATE_2,
+                          ARIZONA_SAMPLE_RATE_2_MASK, 0x11);
+       regmap_update_bits(arizona->regmap, ARIZONA_SAMPLE_RATE_3,
+                          ARIZONA_SAMPLE_RATE_3_MASK, 0x12);
+
+       for (i = 0; i < ARRAY_SIZE(cs47l24_dai); i++)
+               arizona_init_dai(&cs47l24->core, i);
+
+       /* Latch volume update bits */
+       for (i = 0; i < ARRAY_SIZE(cs47l24_digital_vu); i++)
+               regmap_update_bits(arizona->regmap, cs47l24_digital_vu[i],
+                                  CS47L24_DIG_VU, CS47L24_DIG_VU);
+
+       pm_runtime_enable(&pdev->dev);
+       pm_runtime_idle(&pdev->dev);
+
+       return snd_soc_register_codec(&pdev->dev, &soc_codec_dev_cs47l24,
+                                     cs47l24_dai, ARRAY_SIZE(cs47l24_dai));
+}
+
+static int cs47l24_remove(struct platform_device *pdev)
+{
+       snd_soc_unregister_codec(&pdev->dev);
+       pm_runtime_disable(&pdev->dev);
+
+       return 0;
+}
+
+static struct platform_driver cs47l24_codec_driver = {
+       .driver = {
+               .name = "cs47l24-codec",
+       },
+       .probe = cs47l24_probe,
+       .remove = cs47l24_remove,
+};
+
+module_platform_driver(cs47l24_codec_driver);
+
+MODULE_DESCRIPTION("ASoC CS47L24 driver");
+MODULE_AUTHOR("Richard Fitzgerald <rf@opensource.wolfsonmicro.com>");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:cs47l24-codec");
diff --git a/sound/soc/codecs/cs47l24.h b/sound/soc/codecs/cs47l24.h
new file mode 100644 (file)
index 0000000..77ab2b7
--- /dev/null
@@ -0,0 +1,23 @@
+/*
+ * cs47l24.h  --  ALSA SoC Audio driver for Cirrus Logic CS47L24
+ *
+ * Copyright 2015 Cirrus Logic Inc.
+ *
+ * Author: Richard Fitzgerald <rf@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.
+ */
+
+#ifndef _CS47L24_H
+#define _CS47L24_H
+
+#include "arizona.h"
+
+#define CS47L24_FLL1        1
+#define CS47L24_FLL2        2
+#define CS47L24_FLL1_REFCLK 3
+#define CS47L24_FLL2_REFCLK 4
+
+#endif
diff --git a/sound/soc/codecs/da7218.c b/sound/soc/codecs/da7218.c
new file mode 100644 (file)
index 0000000..93575f2
--- /dev/null
@@ -0,0 +1,3341 @@
+/*
+ * da7218.c - DA7218 ALSA SoC Codec Driver
+ *
+ * Copyright (c) 2015 Dialog Semiconductor
+ *
+ * Author: Adam Thomson <Adam.Thomson.Opensource@diasemi.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 <linux/clk.h>
+#include <linux/i2c.h>
+#include <linux/of_device.h>
+#include <linux/regmap.h>
+#include <linux/slab.h>
+#include <linux/pm.h>
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/regulator/consumer.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include <sound/jack.h>
+#include <sound/initval.h>
+#include <sound/tlv.h>
+#include <asm/div64.h>
+
+#include <sound/da7218.h>
+#include "da7218.h"
+
+
+/*
+ * TLVs and Enums
+ */
+
+/* Input TLVs */
+static const DECLARE_TLV_DB_SCALE(da7218_mic_gain_tlv, -600, 600, 0);
+static const DECLARE_TLV_DB_SCALE(da7218_mixin_gain_tlv, -450, 150, 0);
+static const DECLARE_TLV_DB_SCALE(da7218_in_dig_gain_tlv, -8325, 75, 0);
+static const DECLARE_TLV_DB_SCALE(da7218_ags_trigger_tlv, -9000, 600, 0);
+static const DECLARE_TLV_DB_SCALE(da7218_ags_att_max_tlv, 0, 600, 0);
+static const DECLARE_TLV_DB_SCALE(da7218_alc_threshold_tlv, -9450, 150, 0);
+static const DECLARE_TLV_DB_SCALE(da7218_alc_gain_tlv, 0, 600, 0);
+static const DECLARE_TLV_DB_SCALE(da7218_alc_ana_gain_tlv, 0, 600, 0);
+
+/* Input/Output TLVs */
+static const DECLARE_TLV_DB_SCALE(da7218_dmix_gain_tlv, -4200, 150, 0);
+
+/* Output TLVs */
+static const DECLARE_TLV_DB_SCALE(da7218_dgs_trigger_tlv, -9450, 150, 0);
+static const DECLARE_TLV_DB_SCALE(da7218_dgs_anticlip_tlv, -4200, 600, 0);
+static const DECLARE_TLV_DB_SCALE(da7218_dgs_signal_tlv, -9000, 600, 0);
+static const DECLARE_TLV_DB_SCALE(da7218_out_eq_band_tlv, -1050, 150, 0);
+static const DECLARE_TLV_DB_SCALE(da7218_out_dig_gain_tlv, -8325, 75, 0);
+static const DECLARE_TLV_DB_SCALE(da7218_dac_ng_threshold_tlv, -10200, 600, 0);
+static const DECLARE_TLV_DB_SCALE(da7218_mixout_gain_tlv, -100, 50, 0);
+static const DECLARE_TLV_DB_SCALE(da7218_hp_gain_tlv, -5700, 150, 0);
+
+/* Input Enums */
+static const char * const da7218_alc_attack_rate_txt[] = {
+       "7.33/fs", "14.66/fs", "29.32/fs", "58.64/fs", "117.3/fs", "234.6/fs",
+       "469.1/fs", "938.2/fs", "1876/fs", "3753/fs", "7506/fs", "15012/fs",
+       "30024/fs",
+};
+
+static const struct soc_enum da7218_alc_attack_rate =
+       SOC_ENUM_SINGLE(DA7218_ALC_CTRL2, DA7218_ALC_ATTACK_SHIFT,
+                       DA7218_ALC_ATTACK_MAX, da7218_alc_attack_rate_txt);
+
+static const char * const da7218_alc_release_rate_txt[] = {
+       "28.66/fs", "57.33/fs", "114.6/fs", "229.3/fs", "458.6/fs", "917.1/fs",
+       "1834/fs", "3668/fs", "7337/fs", "14674/fs", "29348/fs",
+};
+
+static const struct soc_enum da7218_alc_release_rate =
+       SOC_ENUM_SINGLE(DA7218_ALC_CTRL2, DA7218_ALC_RELEASE_SHIFT,
+                       DA7218_ALC_RELEASE_MAX, da7218_alc_release_rate_txt);
+
+static const char * const da7218_alc_hold_time_txt[] = {
+       "62/fs", "124/fs", "248/fs", "496/fs", "992/fs", "1984/fs", "3968/fs",
+       "7936/fs", "15872/fs", "31744/fs", "63488/fs", "126976/fs",
+       "253952/fs", "507904/fs", "1015808/fs", "2031616/fs"
+};
+
+static const struct soc_enum da7218_alc_hold_time =
+       SOC_ENUM_SINGLE(DA7218_ALC_CTRL3, DA7218_ALC_HOLD_SHIFT,
+                       DA7218_ALC_HOLD_MAX, da7218_alc_hold_time_txt);
+
+static const char * const da7218_alc_anticlip_step_txt[] = {
+       "0.034dB/fs", "0.068dB/fs", "0.136dB/fs", "0.272dB/fs",
+};
+
+static const struct soc_enum da7218_alc_anticlip_step =
+       SOC_ENUM_SINGLE(DA7218_ALC_ANTICLIP_CTRL,
+                       DA7218_ALC_ANTICLIP_STEP_SHIFT,
+                       DA7218_ALC_ANTICLIP_STEP_MAX,
+                       da7218_alc_anticlip_step_txt);
+
+static const char * const da7218_integ_rate_txt[] = {
+       "1/4", "1/16", "1/256", "1/65536"
+};
+
+static const struct soc_enum da7218_integ_attack_rate =
+       SOC_ENUM_SINGLE(DA7218_ENV_TRACK_CTRL, DA7218_INTEG_ATTACK_SHIFT,
+                       DA7218_INTEG_MAX, da7218_integ_rate_txt);
+
+static const struct soc_enum da7218_integ_release_rate =
+       SOC_ENUM_SINGLE(DA7218_ENV_TRACK_CTRL, DA7218_INTEG_RELEASE_SHIFT,
+                       DA7218_INTEG_MAX, da7218_integ_rate_txt);
+
+/* Input/Output Enums */
+static const char * const da7218_gain_ramp_rate_txt[] = {
+       "Nominal Rate * 8", "Nominal Rate", "Nominal Rate / 8",
+       "Nominal Rate / 16",
+};
+
+static const struct soc_enum da7218_gain_ramp_rate =
+       SOC_ENUM_SINGLE(DA7218_GAIN_RAMP_CTRL, DA7218_GAIN_RAMP_RATE_SHIFT,
+                       DA7218_GAIN_RAMP_RATE_MAX, da7218_gain_ramp_rate_txt);
+
+static const char * const da7218_hpf_mode_txt[] = {
+       "Disabled", "Audio", "Voice",
+};
+
+static const unsigned int da7218_hpf_mode_val[] = {
+       DA7218_HPF_DISABLED, DA7218_HPF_AUDIO_EN, DA7218_HPF_VOICE_EN,
+};
+
+static const struct soc_enum da7218_in1_hpf_mode =
+       SOC_VALUE_ENUM_SINGLE(DA7218_IN_1_HPF_FILTER_CTRL,
+                             DA7218_HPF_MODE_SHIFT, DA7218_HPF_MODE_MASK,
+                             DA7218_HPF_MODE_MAX, da7218_hpf_mode_txt,
+                             da7218_hpf_mode_val);
+
+static const struct soc_enum da7218_in2_hpf_mode =
+       SOC_VALUE_ENUM_SINGLE(DA7218_IN_2_HPF_FILTER_CTRL,
+                             DA7218_HPF_MODE_SHIFT, DA7218_HPF_MODE_MASK,
+                             DA7218_HPF_MODE_MAX, da7218_hpf_mode_txt,
+                             da7218_hpf_mode_val);
+
+static const struct soc_enum da7218_out1_hpf_mode =
+       SOC_VALUE_ENUM_SINGLE(DA7218_OUT_1_HPF_FILTER_CTRL,
+                             DA7218_HPF_MODE_SHIFT, DA7218_HPF_MODE_MASK,
+                             DA7218_HPF_MODE_MAX, da7218_hpf_mode_txt,
+                             da7218_hpf_mode_val);
+
+static const char * const da7218_audio_hpf_corner_txt[] = {
+       "2Hz", "4Hz", "8Hz", "16Hz",
+};
+
+static const struct soc_enum da7218_in1_audio_hpf_corner =
+       SOC_ENUM_SINGLE(DA7218_IN_1_HPF_FILTER_CTRL,
+                       DA7218_IN_1_AUDIO_HPF_CORNER_SHIFT,
+                       DA7218_AUDIO_HPF_CORNER_MAX,
+                       da7218_audio_hpf_corner_txt);
+
+static const struct soc_enum da7218_in2_audio_hpf_corner =
+       SOC_ENUM_SINGLE(DA7218_IN_2_HPF_FILTER_CTRL,
+                       DA7218_IN_2_AUDIO_HPF_CORNER_SHIFT,
+                       DA7218_AUDIO_HPF_CORNER_MAX,
+                       da7218_audio_hpf_corner_txt);
+
+static const struct soc_enum da7218_out1_audio_hpf_corner =
+       SOC_ENUM_SINGLE(DA7218_OUT_1_HPF_FILTER_CTRL,
+                       DA7218_OUT_1_AUDIO_HPF_CORNER_SHIFT,
+                       DA7218_AUDIO_HPF_CORNER_MAX,
+                       da7218_audio_hpf_corner_txt);
+
+static const char * const da7218_voice_hpf_corner_txt[] = {
+       "2.5Hz", "25Hz", "50Hz", "100Hz", "150Hz", "200Hz", "300Hz", "400Hz",
+};
+
+static const struct soc_enum da7218_in1_voice_hpf_corner =
+       SOC_ENUM_SINGLE(DA7218_IN_1_HPF_FILTER_CTRL,
+                       DA7218_IN_1_VOICE_HPF_CORNER_SHIFT,
+                       DA7218_VOICE_HPF_CORNER_MAX,
+                       da7218_voice_hpf_corner_txt);
+
+static const struct soc_enum da7218_in2_voice_hpf_corner =
+       SOC_ENUM_SINGLE(DA7218_IN_2_HPF_FILTER_CTRL,
+                       DA7218_IN_2_VOICE_HPF_CORNER_SHIFT,
+                       DA7218_VOICE_HPF_CORNER_MAX,
+                       da7218_voice_hpf_corner_txt);
+
+static const struct soc_enum da7218_out1_voice_hpf_corner =
+       SOC_ENUM_SINGLE(DA7218_OUT_1_HPF_FILTER_CTRL,
+                       DA7218_OUT_1_VOICE_HPF_CORNER_SHIFT,
+                       DA7218_VOICE_HPF_CORNER_MAX,
+                       da7218_voice_hpf_corner_txt);
+
+static const char * const da7218_tonegen_dtmf_key_txt[] = {
+       "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "A", "B", "C", "D",
+       "*", "#"
+};
+
+static const struct soc_enum da7218_tonegen_dtmf_key =
+       SOC_ENUM_SINGLE(DA7218_TONE_GEN_CFG1, DA7218_DTMF_REG_SHIFT,
+                       DA7218_DTMF_REG_MAX, da7218_tonegen_dtmf_key_txt);
+
+static const char * const da7218_tonegen_swg_sel_txt[] = {
+       "Sum", "SWG1", "SWG2", "SWG1_1-Cos"
+};
+
+static const struct soc_enum da7218_tonegen_swg_sel =
+       SOC_ENUM_SINGLE(DA7218_TONE_GEN_CFG2, DA7218_SWG_SEL_SHIFT,
+                       DA7218_SWG_SEL_MAX, da7218_tonegen_swg_sel_txt);
+
+/* Output Enums */
+static const char * const da7218_dgs_rise_coeff_txt[] = {
+       "1/1", "1/16", "1/64", "1/256", "1/1024", "1/4096", "1/16384",
+};
+
+static const struct soc_enum da7218_dgs_rise_coeff =
+       SOC_ENUM_SINGLE(DA7218_DGS_RISE_FALL, DA7218_DGS_RISE_COEFF_SHIFT,
+                       DA7218_DGS_RISE_COEFF_MAX, da7218_dgs_rise_coeff_txt);
+
+static const char * const da7218_dgs_fall_coeff_txt[] = {
+       "1/4", "1/16", "1/64", "1/256", "1/1024", "1/4096", "1/16384", "1/65536",
+};
+
+static const struct soc_enum da7218_dgs_fall_coeff =
+       SOC_ENUM_SINGLE(DA7218_DGS_RISE_FALL, DA7218_DGS_FALL_COEFF_SHIFT,
+                       DA7218_DGS_FALL_COEFF_MAX, da7218_dgs_fall_coeff_txt);
+
+static const char * const da7218_dac_ng_setup_time_txt[] = {
+       "256 Samples", "512 Samples", "1024 Samples", "2048 Samples"
+};
+
+static const struct soc_enum da7218_dac_ng_setup_time =
+       SOC_ENUM_SINGLE(DA7218_DAC_NG_SETUP_TIME,
+                       DA7218_DAC_NG_SETUP_TIME_SHIFT,
+                       DA7218_DAC_NG_SETUP_TIME_MAX,
+                       da7218_dac_ng_setup_time_txt);
+
+static const char * const da7218_dac_ng_rampup_txt[] = {
+       "0.22ms/dB", "0.0138ms/dB"
+};
+
+static const struct soc_enum da7218_dac_ng_rampup_rate =
+       SOC_ENUM_SINGLE(DA7218_DAC_NG_SETUP_TIME,
+                       DA7218_DAC_NG_RAMPUP_RATE_SHIFT,
+                       DA7218_DAC_NG_RAMPUP_RATE_MAX,
+                       da7218_dac_ng_rampup_txt);
+
+static const char * const da7218_dac_ng_rampdown_txt[] = {
+       "0.88ms/dB", "14.08ms/dB"
+};
+
+static const struct soc_enum da7218_dac_ng_rampdown_rate =
+       SOC_ENUM_SINGLE(DA7218_DAC_NG_SETUP_TIME,
+                       DA7218_DAC_NG_RAMPDN_RATE_SHIFT,
+                       DA7218_DAC_NG_RAMPDN_RATE_MAX,
+                       da7218_dac_ng_rampdown_txt);
+
+static const char * const da7218_cp_mchange_txt[] = {
+       "Largest Volume", "DAC Volume", "Signal Magnitude"
+};
+
+static const unsigned int da7218_cp_mchange_val[] = {
+       DA7218_CP_MCHANGE_LARGEST_VOL, DA7218_CP_MCHANGE_DAC_VOL,
+       DA7218_CP_MCHANGE_SIG_MAG
+};
+
+static const struct soc_enum da7218_cp_mchange =
+       SOC_VALUE_ENUM_SINGLE(DA7218_CP_CTRL, DA7218_CP_MCHANGE_SHIFT,
+                             DA7218_CP_MCHANGE_REL_MASK, DA7218_CP_MCHANGE_MAX,
+                             da7218_cp_mchange_txt, da7218_cp_mchange_val);
+
+static const char * const da7218_cp_fcontrol_txt[] = {
+       "1MHz", "500KHz", "250KHz", "125KHz", "63KHz", "0KHz"
+};
+
+static const struct soc_enum da7218_cp_fcontrol =
+       SOC_ENUM_SINGLE(DA7218_CP_DELAY, DA7218_CP_FCONTROL_SHIFT,
+                       DA7218_CP_FCONTROL_MAX, da7218_cp_fcontrol_txt);
+
+static const char * const da7218_cp_tau_delay_txt[] = {
+       "0ms", "2ms", "4ms", "16ms", "64ms", "128ms", "256ms", "512ms"
+};
+
+static const struct soc_enum da7218_cp_tau_delay =
+       SOC_ENUM_SINGLE(DA7218_CP_DELAY, DA7218_CP_TAU_DELAY_SHIFT,
+                       DA7218_CP_TAU_DELAY_MAX, da7218_cp_tau_delay_txt);
+
+/*
+ * Control Functions
+ */
+
+/* ALC */
+static void da7218_alc_calib(struct snd_soc_codec *codec)
+{
+       u8 mic_1_ctrl, mic_2_ctrl;
+       u8 mixin_1_ctrl, mixin_2_ctrl;
+       u8 in_1l_filt_ctrl, in_1r_filt_ctrl, in_2l_filt_ctrl, in_2r_filt_ctrl;
+       u8 in_1_hpf_ctrl, in_2_hpf_ctrl;
+       u8 calib_ctrl;
+       int i = 0;
+       bool calibrated = false;
+
+       /* Save current state of MIC control registers */
+       mic_1_ctrl = snd_soc_read(codec, DA7218_MIC_1_CTRL);
+       mic_2_ctrl = snd_soc_read(codec, DA7218_MIC_2_CTRL);
+
+       /* Save current state of input mixer control registers */
+       mixin_1_ctrl = snd_soc_read(codec, DA7218_MIXIN_1_CTRL);
+       mixin_2_ctrl = snd_soc_read(codec, DA7218_MIXIN_2_CTRL);
+
+       /* Save current state of input filter control registers */
+       in_1l_filt_ctrl = snd_soc_read(codec, DA7218_IN_1L_FILTER_CTRL);
+       in_1r_filt_ctrl = snd_soc_read(codec, DA7218_IN_1R_FILTER_CTRL);
+       in_2l_filt_ctrl = snd_soc_read(codec, DA7218_IN_2L_FILTER_CTRL);
+       in_2r_filt_ctrl = snd_soc_read(codec, DA7218_IN_2R_FILTER_CTRL);
+
+       /* Save current state of input HPF control registers */
+       in_1_hpf_ctrl = snd_soc_read(codec, DA7218_IN_1_HPF_FILTER_CTRL);
+       in_2_hpf_ctrl = snd_soc_read(codec, DA7218_IN_2_HPF_FILTER_CTRL);
+
+       /* Enable then Mute MIC PGAs */
+       snd_soc_update_bits(codec, DA7218_MIC_1_CTRL, DA7218_MIC_1_AMP_EN_MASK,
+                           DA7218_MIC_1_AMP_EN_MASK);
+       snd_soc_update_bits(codec, DA7218_MIC_2_CTRL, DA7218_MIC_2_AMP_EN_MASK,
+                           DA7218_MIC_2_AMP_EN_MASK);
+       snd_soc_update_bits(codec, DA7218_MIC_1_CTRL,
+                           DA7218_MIC_1_AMP_MUTE_EN_MASK,
+                           DA7218_MIC_1_AMP_MUTE_EN_MASK);
+       snd_soc_update_bits(codec, DA7218_MIC_2_CTRL,
+                           DA7218_MIC_2_AMP_MUTE_EN_MASK,
+                           DA7218_MIC_2_AMP_MUTE_EN_MASK);
+
+       /* Enable input mixers unmuted */
+       snd_soc_update_bits(codec, DA7218_MIXIN_1_CTRL,
+                           DA7218_MIXIN_1_AMP_EN_MASK |
+                           DA7218_MIXIN_1_AMP_MUTE_EN_MASK,
+                           DA7218_MIXIN_1_AMP_EN_MASK);
+       snd_soc_update_bits(codec, DA7218_MIXIN_2_CTRL,
+                           DA7218_MIXIN_2_AMP_EN_MASK |
+                           DA7218_MIXIN_2_AMP_MUTE_EN_MASK,
+                           DA7218_MIXIN_2_AMP_EN_MASK);
+
+       /* Enable input filters unmuted */
+       snd_soc_update_bits(codec, DA7218_IN_1L_FILTER_CTRL,
+                           DA7218_IN_1L_FILTER_EN_MASK |
+                           DA7218_IN_1L_MUTE_EN_MASK,
+                           DA7218_IN_1L_FILTER_EN_MASK);
+       snd_soc_update_bits(codec, DA7218_IN_1R_FILTER_CTRL,
+                           DA7218_IN_1R_FILTER_EN_MASK |
+                           DA7218_IN_1R_MUTE_EN_MASK,
+                           DA7218_IN_1R_FILTER_EN_MASK);
+       snd_soc_update_bits(codec, DA7218_IN_2L_FILTER_CTRL,
+                           DA7218_IN_2L_FILTER_EN_MASK |
+                           DA7218_IN_2L_MUTE_EN_MASK,
+                           DA7218_IN_2L_FILTER_EN_MASK);
+       snd_soc_update_bits(codec, DA7218_IN_2R_FILTER_CTRL,
+                           DA7218_IN_2R_FILTER_EN_MASK |
+                           DA7218_IN_2R_MUTE_EN_MASK,
+                           DA7218_IN_2R_FILTER_EN_MASK);
+
+       /*
+        * Make sure input HPFs voice mode is disabled, otherwise for sampling
+        * rates above 32KHz the ADC signals will be stopped and will cause
+        * calibration to lock up.
+        */
+       snd_soc_update_bits(codec, DA7218_IN_1_HPF_FILTER_CTRL,
+                           DA7218_IN_1_VOICE_EN_MASK, 0);
+       snd_soc_update_bits(codec, DA7218_IN_2_HPF_FILTER_CTRL,
+                           DA7218_IN_2_VOICE_EN_MASK, 0);
+
+       /* Perform auto calibration */
+       snd_soc_update_bits(codec, DA7218_CALIB_CTRL, DA7218_CALIB_AUTO_EN_MASK,
+                           DA7218_CALIB_AUTO_EN_MASK);
+       do {
+               calib_ctrl = snd_soc_read(codec, DA7218_CALIB_CTRL);
+               if (calib_ctrl & DA7218_CALIB_AUTO_EN_MASK) {
+                       ++i;
+                       usleep_range(DA7218_ALC_CALIB_DELAY_MIN,
+                                    DA7218_ALC_CALIB_DELAY_MAX);
+               } else {
+                       calibrated = true;
+               }
+
+       } while ((i < DA7218_ALC_CALIB_MAX_TRIES) && (!calibrated));
+
+       /* If auto calibration fails, disable DC offset, hybrid ALC */
+       if ((!calibrated) || (calib_ctrl & DA7218_CALIB_OVERFLOW_MASK)) {
+               dev_warn(codec->dev,
+                        "ALC auto calibration failed - %s\n",
+                        (calibrated) ? "overflow" : "timeout");
+               snd_soc_update_bits(codec, DA7218_CALIB_CTRL,
+                                   DA7218_CALIB_OFFSET_EN_MASK, 0);
+               snd_soc_update_bits(codec, DA7218_ALC_CTRL1,
+                                   DA7218_ALC_SYNC_MODE_MASK, 0);
+
+       } else {
+               /* Enable DC offset cancellation */
+               snd_soc_update_bits(codec, DA7218_CALIB_CTRL,
+                                   DA7218_CALIB_OFFSET_EN_MASK,
+                                   DA7218_CALIB_OFFSET_EN_MASK);
+
+               /* Enable ALC hybrid mode */
+               snd_soc_update_bits(codec, DA7218_ALC_CTRL1,
+                                   DA7218_ALC_SYNC_MODE_MASK,
+                                   DA7218_ALC_SYNC_MODE_CH1 |
+                                   DA7218_ALC_SYNC_MODE_CH2);
+       }
+
+       /* Restore input HPF control registers to original states */
+       snd_soc_write(codec, DA7218_IN_1_HPF_FILTER_CTRL, in_1_hpf_ctrl);
+       snd_soc_write(codec, DA7218_IN_2_HPF_FILTER_CTRL, in_2_hpf_ctrl);
+
+       /* Restore input filter control registers to original states */
+       snd_soc_write(codec, DA7218_IN_1L_FILTER_CTRL, in_1l_filt_ctrl);
+       snd_soc_write(codec, DA7218_IN_1R_FILTER_CTRL, in_1r_filt_ctrl);
+       snd_soc_write(codec, DA7218_IN_2L_FILTER_CTRL, in_2l_filt_ctrl);
+       snd_soc_write(codec, DA7218_IN_2R_FILTER_CTRL, in_2r_filt_ctrl);
+
+       /* Restore input mixer control registers to original state */
+       snd_soc_write(codec, DA7218_MIXIN_1_CTRL, mixin_1_ctrl);
+       snd_soc_write(codec, DA7218_MIXIN_2_CTRL, mixin_2_ctrl);
+
+       /* Restore MIC control registers to original states */
+       snd_soc_write(codec, DA7218_MIC_1_CTRL, mic_1_ctrl);
+       snd_soc_write(codec, DA7218_MIC_2_CTRL, mic_2_ctrl);
+}
+
+static int da7218_mixin_gain_put(struct snd_kcontrol *kcontrol,
+                                struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
+       struct da7218_priv *da7218 = snd_soc_codec_get_drvdata(codec);
+       int ret;
+
+       ret = snd_soc_put_volsw(kcontrol, ucontrol);
+
+       /*
+        * If ALC in operation and value of control has been updated,
+        * make sure calibrated offsets are updated.
+        */
+       if ((ret == 1) && (da7218->alc_en))
+               da7218_alc_calib(codec);
+
+       return ret;
+}
+
+static int da7218_alc_sw_put(struct snd_kcontrol *kcontrol,
+                            struct snd_ctl_elem_value *ucontrol)
+{
+       struct soc_mixer_control *mc =
+               (struct soc_mixer_control *) kcontrol->private_value;
+       struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
+       struct da7218_priv *da7218 = snd_soc_codec_get_drvdata(codec);
+       unsigned int lvalue = ucontrol->value.integer.value[0];
+       unsigned int rvalue = ucontrol->value.integer.value[1];
+       unsigned int lshift = mc->shift;
+       unsigned int rshift = mc->rshift;
+       unsigned int mask = (mc->max << lshift) | (mc->max << rshift);
+
+       /* Force ALC offset calibration if enabling ALC */
+       if ((lvalue || rvalue) && (!da7218->alc_en))
+               da7218_alc_calib(codec);
+
+       /* Update bits to detail which channels are enabled/disabled */
+       da7218->alc_en &= ~mask;
+       da7218->alc_en |= (lvalue << lshift) | (rvalue << rshift);
+
+       return snd_soc_put_volsw(kcontrol, ucontrol);
+}
+
+/* ToneGen */
+static int da7218_tonegen_freq_get(struct snd_kcontrol *kcontrol,
+                                  struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
+       struct da7218_priv *da7218 = snd_soc_codec_get_drvdata(codec);
+       struct soc_mixer_control *mixer_ctrl =
+               (struct soc_mixer_control *) kcontrol->private_value;
+       unsigned int reg = mixer_ctrl->reg;
+       u16 val;
+       int ret;
+
+       /*
+        * Frequency value spans two 8-bit registers, lower then upper byte.
+        * Therefore we need to convert to host endianness here.
+        */
+       ret = regmap_raw_read(da7218->regmap, reg, &val, 2);
+       if (ret)
+               return ret;
+
+       ucontrol->value.integer.value[0] = le16_to_cpu(val);
+
+       return 0;
+}
+
+static int da7218_tonegen_freq_put(struct snd_kcontrol *kcontrol,
+                                  struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
+       struct da7218_priv *da7218 = snd_soc_codec_get_drvdata(codec);
+       struct soc_mixer_control *mixer_ctrl =
+               (struct soc_mixer_control *) kcontrol->private_value;
+       unsigned int reg = mixer_ctrl->reg;
+       u16 val;
+
+       /*
+        * Frequency value spans two 8-bit registers, lower then upper byte.
+        * Therefore we need to convert to little endian here to align with
+        * HW registers.
+        */
+       val = cpu_to_le16(ucontrol->value.integer.value[0]);
+
+       return regmap_raw_write(da7218->regmap, reg, &val, 2);
+}
+
+static int da7218_mic_lvl_det_sw_put(struct snd_kcontrol *kcontrol,
+                                    struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
+       struct da7218_priv *da7218 = snd_soc_codec_get_drvdata(codec);
+       struct soc_mixer_control *mixer_ctrl =
+               (struct soc_mixer_control *) kcontrol->private_value;
+       unsigned int lvalue = ucontrol->value.integer.value[0];
+       unsigned int rvalue = ucontrol->value.integer.value[1];
+       unsigned int lshift = mixer_ctrl->shift;
+       unsigned int rshift = mixer_ctrl->rshift;
+       unsigned int mask = (mixer_ctrl->max << lshift) |
+                           (mixer_ctrl->max << rshift);
+       da7218->mic_lvl_det_en &= ~mask;
+       da7218->mic_lvl_det_en |= (lvalue << lshift) | (rvalue << rshift);
+
+       /*
+        * Here we only enable the feature on paths which are already
+        * powered. If a channel is enabled here for level detect, but that path
+        * isn't powered, then the channel will actually be enabled when we do
+        * power the path (IN_FILTER widget events). This handling avoids
+        * unwanted level detect events.
+        */
+       return snd_soc_write(codec, mixer_ctrl->reg,
+                            (da7218->in_filt_en & da7218->mic_lvl_det_en));
+}
+
+static int da7218_mic_lvl_det_sw_get(struct snd_kcontrol *kcontrol,
+                                    struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
+       struct da7218_priv *da7218 = snd_soc_codec_get_drvdata(codec);
+       struct soc_mixer_control *mixer_ctrl =
+               (struct soc_mixer_control *) kcontrol->private_value;
+       unsigned int lshift = mixer_ctrl->shift;
+       unsigned int rshift = mixer_ctrl->rshift;
+       unsigned int lmask = (mixer_ctrl->max << lshift);
+       unsigned int rmask = (mixer_ctrl->max << rshift);
+
+       ucontrol->value.integer.value[0] =
+               (da7218->mic_lvl_det_en & lmask) >> lshift;
+       ucontrol->value.integer.value[1] =
+               (da7218->mic_lvl_det_en & rmask) >> rshift;
+
+       return 0;
+}
+
+static int da7218_biquad_coeff_get(struct snd_kcontrol *kcontrol,
+                                  struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
+       struct da7218_priv *da7218 = snd_soc_codec_get_drvdata(codec);
+       struct soc_bytes_ext *bytes_ext =
+               (struct soc_bytes_ext *) kcontrol->private_value;
+
+       /* Determine which BiQuads we're setting based on size of config data */
+       switch (bytes_ext->max) {
+       case DA7218_OUT_1_BIQ_5STAGE_CFG_SIZE:
+               memcpy(ucontrol->value.bytes.data, da7218->biq_5stage_coeff,
+                      bytes_ext->max);
+               break;
+       case DA7218_SIDETONE_BIQ_3STAGE_CFG_SIZE:
+               memcpy(ucontrol->value.bytes.data, da7218->stbiq_3stage_coeff,
+                      bytes_ext->max);
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static int da7218_biquad_coeff_put(struct snd_kcontrol *kcontrol,
+                                  struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
+       struct da7218_priv *da7218 = snd_soc_codec_get_drvdata(codec);
+       struct soc_bytes_ext *bytes_ext =
+               (struct soc_bytes_ext *) kcontrol->private_value;
+       u8 reg, out_filt1l;
+       u8 cfg[DA7218_BIQ_CFG_SIZE];
+       int i;
+
+       /*
+        * Determine which BiQuads we're setting based on size of config data,
+        * and stored the data for use by get function.
+        */
+       switch (bytes_ext->max) {
+       case DA7218_OUT_1_BIQ_5STAGE_CFG_SIZE:
+               reg = DA7218_OUT_1_BIQ_5STAGE_DATA;
+               memcpy(da7218->biq_5stage_coeff, ucontrol->value.bytes.data,
+                      bytes_ext->max);
+               break;
+       case DA7218_SIDETONE_BIQ_3STAGE_CFG_SIZE:
+               reg = DA7218_SIDETONE_BIQ_3STAGE_DATA;
+               memcpy(da7218->stbiq_3stage_coeff, ucontrol->value.bytes.data,
+                      bytes_ext->max);
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       /* Make sure at least out filter1 enabled to allow programming */
+       out_filt1l = snd_soc_read(codec, DA7218_OUT_1L_FILTER_CTRL);
+       snd_soc_write(codec, DA7218_OUT_1L_FILTER_CTRL,
+                     out_filt1l | DA7218_OUT_1L_FILTER_EN_MASK);
+
+       for (i = 0; i < bytes_ext->max; ++i) {
+               cfg[DA7218_BIQ_CFG_DATA] = ucontrol->value.bytes.data[i];
+               cfg[DA7218_BIQ_CFG_ADDR] = i;
+               regmap_raw_write(da7218->regmap, reg, cfg, DA7218_BIQ_CFG_SIZE);
+       }
+
+       /* Restore filter to previous setting */
+       snd_soc_write(codec, DA7218_OUT_1L_FILTER_CTRL, out_filt1l);
+
+       return 0;
+}
+
+
+/*
+ * KControls
+ */
+
+static const struct snd_kcontrol_new da7218_snd_controls[] = {
+       /* Mics */
+       SOC_SINGLE_TLV("Mic1 Volume", DA7218_MIC_1_GAIN,
+                      DA7218_MIC_1_AMP_GAIN_SHIFT, DA7218_MIC_AMP_GAIN_MAX,
+                      DA7218_NO_INVERT, da7218_mic_gain_tlv),
+       SOC_SINGLE("Mic1 Switch", DA7218_MIC_1_CTRL,
+                  DA7218_MIC_1_AMP_MUTE_EN_SHIFT, DA7218_SWITCH_EN_MAX,
+                  DA7218_INVERT),
+       SOC_SINGLE_TLV("Mic2 Volume", DA7218_MIC_2_GAIN,
+                      DA7218_MIC_2_AMP_GAIN_SHIFT, DA7218_MIC_AMP_GAIN_MAX,
+                      DA7218_NO_INVERT, da7218_mic_gain_tlv),
+       SOC_SINGLE("Mic2 Switch", DA7218_MIC_2_CTRL,
+                  DA7218_MIC_2_AMP_MUTE_EN_SHIFT, DA7218_SWITCH_EN_MAX,
+                  DA7218_INVERT),
+
+       /* Mixer Input */
+       SOC_SINGLE_EXT_TLV("Mixin1 Volume", DA7218_MIXIN_1_GAIN,
+                          DA7218_MIXIN_1_AMP_GAIN_SHIFT,
+                          DA7218_MIXIN_AMP_GAIN_MAX, DA7218_NO_INVERT,
+                          snd_soc_get_volsw, da7218_mixin_gain_put,
+                          da7218_mixin_gain_tlv),
+       SOC_SINGLE("Mixin1 Switch", DA7218_MIXIN_1_CTRL,
+                  DA7218_MIXIN_1_AMP_MUTE_EN_SHIFT, DA7218_SWITCH_EN_MAX,
+                  DA7218_INVERT),
+       SOC_SINGLE("Mixin1 Gain Ramp Switch", DA7218_MIXIN_1_CTRL,
+                  DA7218_MIXIN_1_AMP_RAMP_EN_SHIFT, DA7218_SWITCH_EN_MAX,
+                  DA7218_NO_INVERT),
+       SOC_SINGLE("Mixin1 ZC Gain Switch", DA7218_MIXIN_1_CTRL,
+                  DA7218_MIXIN_1_AMP_ZC_EN_SHIFT, DA7218_SWITCH_EN_MAX,
+                  DA7218_NO_INVERT),
+       SOC_SINGLE_EXT_TLV("Mixin2 Volume", DA7218_MIXIN_2_GAIN,
+                          DA7218_MIXIN_2_AMP_GAIN_SHIFT,
+                          DA7218_MIXIN_AMP_GAIN_MAX, DA7218_NO_INVERT,
+                          snd_soc_get_volsw, da7218_mixin_gain_put,
+                          da7218_mixin_gain_tlv),
+       SOC_SINGLE("Mixin2 Switch", DA7218_MIXIN_2_CTRL,
+                  DA7218_MIXIN_2_AMP_MUTE_EN_SHIFT, DA7218_SWITCH_EN_MAX,
+                  DA7218_INVERT),
+       SOC_SINGLE("Mixin2 Gain Ramp Switch", DA7218_MIXIN_2_CTRL,
+                  DA7218_MIXIN_2_AMP_RAMP_EN_SHIFT, DA7218_SWITCH_EN_MAX,
+                  DA7218_NO_INVERT),
+       SOC_SINGLE("Mixin2 ZC Gain Switch", DA7218_MIXIN_2_CTRL,
+                  DA7218_MIXIN_2_AMP_ZC_EN_SHIFT, DA7218_SWITCH_EN_MAX,
+                  DA7218_NO_INVERT),
+
+       /* ADCs */
+       SOC_SINGLE("ADC1 AAF Switch", DA7218_ADC_1_CTRL,
+                  DA7218_ADC_1_AAF_EN_SHIFT, DA7218_SWITCH_EN_MAX,
+                  DA7218_NO_INVERT),
+       SOC_SINGLE("ADC2 AAF Switch", DA7218_ADC_2_CTRL,
+                  DA7218_ADC_2_AAF_EN_SHIFT, DA7218_SWITCH_EN_MAX,
+                  DA7218_NO_INVERT),
+       SOC_SINGLE("ADC LP Mode Switch", DA7218_ADC_MODE,
+                  DA7218_ADC_LP_MODE_SHIFT, DA7218_SWITCH_EN_MAX,
+                  DA7218_NO_INVERT),
+
+       /* Input Filters */
+       SOC_SINGLE_TLV("In Filter1L Volume", DA7218_IN_1L_GAIN,
+                      DA7218_IN_1L_DIGITAL_GAIN_SHIFT,
+                      DA7218_IN_DIGITAL_GAIN_MAX, DA7218_NO_INVERT,
+                      da7218_in_dig_gain_tlv),
+       SOC_SINGLE("In Filter1L Switch", DA7218_IN_1L_FILTER_CTRL,
+                  DA7218_IN_1L_MUTE_EN_SHIFT, DA7218_SWITCH_EN_MAX,
+                  DA7218_INVERT),
+       SOC_SINGLE("In Filter1L Gain Ramp Switch", DA7218_IN_1L_FILTER_CTRL,
+                  DA7218_IN_1L_RAMP_EN_SHIFT, DA7218_SWITCH_EN_MAX,
+                  DA7218_NO_INVERT),
+       SOC_SINGLE_TLV("In Filter1R Volume", DA7218_IN_1R_GAIN,
+                      DA7218_IN_1R_DIGITAL_GAIN_SHIFT,
+                      DA7218_IN_DIGITAL_GAIN_MAX, DA7218_NO_INVERT,
+                      da7218_in_dig_gain_tlv),
+       SOC_SINGLE("In Filter1R Switch", DA7218_IN_1R_FILTER_CTRL,
+                  DA7218_IN_1R_MUTE_EN_SHIFT, DA7218_SWITCH_EN_MAX,
+                  DA7218_INVERT),
+       SOC_SINGLE("In Filter1R Gain Ramp Switch",
+                  DA7218_IN_1R_FILTER_CTRL, DA7218_IN_1R_RAMP_EN_SHIFT,
+                  DA7218_SWITCH_EN_MAX, DA7218_NO_INVERT),
+       SOC_SINGLE_TLV("In Filter2L Volume", DA7218_IN_2L_GAIN,
+                      DA7218_IN_2L_DIGITAL_GAIN_SHIFT,
+                      DA7218_IN_DIGITAL_GAIN_MAX, DA7218_NO_INVERT,
+                      da7218_in_dig_gain_tlv),
+       SOC_SINGLE("In Filter2L Switch", DA7218_IN_2L_FILTER_CTRL,
+                  DA7218_IN_2L_MUTE_EN_SHIFT, DA7218_SWITCH_EN_MAX,
+                  DA7218_INVERT),
+       SOC_SINGLE("In Filter2L Gain Ramp Switch", DA7218_IN_2L_FILTER_CTRL,
+                  DA7218_IN_2L_RAMP_EN_SHIFT, DA7218_SWITCH_EN_MAX,
+                  DA7218_NO_INVERT),
+       SOC_SINGLE_TLV("In Filter2R Volume", DA7218_IN_2R_GAIN,
+                      DA7218_IN_2R_DIGITAL_GAIN_SHIFT,
+                      DA7218_IN_DIGITAL_GAIN_MAX, DA7218_NO_INVERT,
+                      da7218_in_dig_gain_tlv),
+       SOC_SINGLE("In Filter2R Switch", DA7218_IN_2R_FILTER_CTRL,
+                  DA7218_IN_2R_MUTE_EN_SHIFT, DA7218_SWITCH_EN_MAX,
+                  DA7218_INVERT),
+       SOC_SINGLE("In Filter2R Gain Ramp Switch",
+                  DA7218_IN_2R_FILTER_CTRL, DA7218_IN_2R_RAMP_EN_SHIFT,
+                  DA7218_SWITCH_EN_MAX, DA7218_NO_INVERT),
+
+       /* AGS */
+       SOC_SINGLE_TLV("AGS Trigger", DA7218_AGS_TRIGGER,
+                      DA7218_AGS_TRIGGER_SHIFT, DA7218_AGS_TRIGGER_MAX,
+                      DA7218_INVERT, da7218_ags_trigger_tlv),
+       SOC_SINGLE_TLV("AGS Max Attenuation", DA7218_AGS_ATT_MAX,
+                      DA7218_AGS_ATT_MAX_SHIFT, DA7218_AGS_ATT_MAX_MAX,
+                      DA7218_NO_INVERT, da7218_ags_att_max_tlv),
+       SOC_SINGLE("AGS Anticlip Switch", DA7218_AGS_ANTICLIP_CTRL,
+                  DA7218_AGS_ANTICLIP_EN_SHIFT, DA7218_SWITCH_EN_MAX,
+                  DA7218_NO_INVERT),
+       SOC_SINGLE("AGS Channel1 Switch", DA7218_AGS_ENABLE,
+                  DA7218_AGS_ENABLE_CHAN1_SHIFT, DA7218_SWITCH_EN_MAX,
+                  DA7218_NO_INVERT),
+       SOC_SINGLE("AGS Channel2 Switch", DA7218_AGS_ENABLE,
+                  DA7218_AGS_ENABLE_CHAN2_SHIFT, DA7218_SWITCH_EN_MAX,
+                  DA7218_NO_INVERT),
+
+       /* ALC */
+       SOC_ENUM("ALC Attack Rate", da7218_alc_attack_rate),
+       SOC_ENUM("ALC Release Rate", da7218_alc_release_rate),
+       SOC_ENUM("ALC Hold Time", da7218_alc_hold_time),
+       SOC_SINGLE_TLV("ALC Noise Threshold", DA7218_ALC_NOISE,
+                      DA7218_ALC_NOISE_SHIFT, DA7218_ALC_THRESHOLD_MAX,
+                      DA7218_INVERT, da7218_alc_threshold_tlv),
+       SOC_SINGLE_TLV("ALC Min Threshold", DA7218_ALC_TARGET_MIN,
+                      DA7218_ALC_THRESHOLD_MIN_SHIFT, DA7218_ALC_THRESHOLD_MAX,
+                      DA7218_INVERT, da7218_alc_threshold_tlv),
+       SOC_SINGLE_TLV("ALC Max Threshold", DA7218_ALC_TARGET_MAX,
+                      DA7218_ALC_THRESHOLD_MAX_SHIFT, DA7218_ALC_THRESHOLD_MAX,
+                      DA7218_INVERT, da7218_alc_threshold_tlv),
+       SOC_SINGLE_TLV("ALC Max Attenuation", DA7218_ALC_GAIN_LIMITS,
+                      DA7218_ALC_ATTEN_MAX_SHIFT, DA7218_ALC_ATTEN_GAIN_MAX,
+                      DA7218_NO_INVERT, da7218_alc_gain_tlv),
+       SOC_SINGLE_TLV("ALC Max Gain", DA7218_ALC_GAIN_LIMITS,
+                      DA7218_ALC_GAIN_MAX_SHIFT, DA7218_ALC_ATTEN_GAIN_MAX,
+                      DA7218_NO_INVERT, da7218_alc_gain_tlv),
+       SOC_SINGLE_RANGE_TLV("ALC Min Analog Gain", DA7218_ALC_ANA_GAIN_LIMITS,
+                            DA7218_ALC_ANA_GAIN_MIN_SHIFT,
+                            DA7218_ALC_ANA_GAIN_MIN, DA7218_ALC_ANA_GAIN_MAX,
+                            DA7218_NO_INVERT, da7218_alc_ana_gain_tlv),
+       SOC_SINGLE_RANGE_TLV("ALC Max Analog Gain", DA7218_ALC_ANA_GAIN_LIMITS,
+                            DA7218_ALC_ANA_GAIN_MAX_SHIFT,
+                            DA7218_ALC_ANA_GAIN_MIN, DA7218_ALC_ANA_GAIN_MAX,
+                            DA7218_NO_INVERT, da7218_alc_ana_gain_tlv),
+       SOC_ENUM("ALC Anticlip Step", da7218_alc_anticlip_step),
+       SOC_SINGLE("ALC Anticlip Switch", DA7218_ALC_ANTICLIP_CTRL,
+                  DA7218_ALC_ANTICLIP_EN_SHIFT, DA7218_SWITCH_EN_MAX,
+                  DA7218_NO_INVERT),
+       SOC_DOUBLE_EXT("ALC Channel1 Switch", DA7218_ALC_CTRL1,
+                      DA7218_ALC_CHAN1_L_EN_SHIFT, DA7218_ALC_CHAN1_R_EN_SHIFT,
+                      DA7218_SWITCH_EN_MAX, DA7218_NO_INVERT,
+                      snd_soc_get_volsw, da7218_alc_sw_put),
+       SOC_DOUBLE_EXT("ALC Channel2 Switch", DA7218_ALC_CTRL1,
+                      DA7218_ALC_CHAN2_L_EN_SHIFT, DA7218_ALC_CHAN2_R_EN_SHIFT,
+                      DA7218_SWITCH_EN_MAX, DA7218_NO_INVERT,
+                      snd_soc_get_volsw, da7218_alc_sw_put),
+
+       /* Envelope Tracking */
+       SOC_ENUM("Envelope Tracking Attack Rate", da7218_integ_attack_rate),
+       SOC_ENUM("Envelope Tracking Release Rate", da7218_integ_release_rate),
+
+       /* Input High-Pass Filters */
+       SOC_ENUM("In Filter1 HPF Mode", da7218_in1_hpf_mode),
+       SOC_ENUM("In Filter1 HPF Corner Audio", da7218_in1_audio_hpf_corner),
+       SOC_ENUM("In Filter1 HPF Corner Voice", da7218_in1_voice_hpf_corner),
+       SOC_ENUM("In Filter2 HPF Mode", da7218_in2_hpf_mode),
+       SOC_ENUM("In Filter2 HPF Corner Audio", da7218_in2_audio_hpf_corner),
+       SOC_ENUM("In Filter2 HPF Corner Voice", da7218_in2_voice_hpf_corner),
+
+       /* Mic Level Detect */
+       SOC_DOUBLE_EXT("Mic Level Detect Channel1 Switch", DA7218_LVL_DET_CTRL,
+                      DA7218_LVL_DET_EN_CHAN1L_SHIFT,
+                      DA7218_LVL_DET_EN_CHAN1R_SHIFT, DA7218_SWITCH_EN_MAX,
+                      DA7218_NO_INVERT, da7218_mic_lvl_det_sw_get,
+                      da7218_mic_lvl_det_sw_put),
+       SOC_DOUBLE_EXT("Mic Level Detect Channel2 Switch", DA7218_LVL_DET_CTRL,
+                      DA7218_LVL_DET_EN_CHAN2L_SHIFT,
+                      DA7218_LVL_DET_EN_CHAN2R_SHIFT, DA7218_SWITCH_EN_MAX,
+                      DA7218_NO_INVERT, da7218_mic_lvl_det_sw_get,
+                      da7218_mic_lvl_det_sw_put),
+       SOC_SINGLE("Mic Level Detect Level", DA7218_LVL_DET_LEVEL,
+                  DA7218_LVL_DET_LEVEL_SHIFT, DA7218_LVL_DET_LEVEL_MAX,
+                  DA7218_NO_INVERT),
+
+       /* Digital Mixer (Input) */
+       SOC_SINGLE_TLV("DMix In Filter1L Out1 DAIL Volume",
+                      DA7218_DMIX_OUTDAI_1L_INFILT_1L_GAIN,
+                      DA7218_OUTDAI_1L_INFILT_1L_GAIN_SHIFT,
+                      DA7218_DMIX_GAIN_MAX, DA7218_NO_INVERT,
+                      da7218_dmix_gain_tlv),
+       SOC_SINGLE_TLV("DMix In Filter1L Out1 DAIR Volume",
+                      DA7218_DMIX_OUTDAI_1R_INFILT_1L_GAIN,
+                      DA7218_OUTDAI_1R_INFILT_1L_GAIN_SHIFT,
+                      DA7218_DMIX_GAIN_MAX, DA7218_NO_INVERT,
+                      da7218_dmix_gain_tlv),
+       SOC_SINGLE_TLV("DMix In Filter1L Out2 DAIL Volume",
+                      DA7218_DMIX_OUTDAI_2L_INFILT_1L_GAIN,
+                      DA7218_OUTDAI_2L_INFILT_1L_GAIN_SHIFT,
+                      DA7218_DMIX_GAIN_MAX, DA7218_NO_INVERT,
+                      da7218_dmix_gain_tlv),
+       SOC_SINGLE_TLV("DMix In Filter1L Out2 DAIR Volume",
+                      DA7218_DMIX_OUTDAI_2R_INFILT_1L_GAIN,
+                      DA7218_OUTDAI_2R_INFILT_1L_GAIN_SHIFT,
+                      DA7218_DMIX_GAIN_MAX, DA7218_NO_INVERT,
+                      da7218_dmix_gain_tlv),
+
+       SOC_SINGLE_TLV("DMix In Filter1R Out1 DAIL Volume",
+                      DA7218_DMIX_OUTDAI_1L_INFILT_1R_GAIN,
+                      DA7218_OUTDAI_1L_INFILT_1R_GAIN_SHIFT,
+                      DA7218_DMIX_GAIN_MAX, DA7218_NO_INVERT,
+                      da7218_dmix_gain_tlv),
+       SOC_SINGLE_TLV("DMix In Filter1R Out1 DAIR Volume",
+                      DA7218_DMIX_OUTDAI_1R_INFILT_1R_GAIN,
+                      DA7218_OUTDAI_1R_INFILT_1R_GAIN_SHIFT,
+                      DA7218_DMIX_GAIN_MAX, DA7218_NO_INVERT,
+                      da7218_dmix_gain_tlv),
+       SOC_SINGLE_TLV("DMix In Filter1R Out2 DAIL Volume",
+                      DA7218_DMIX_OUTDAI_2L_INFILT_1R_GAIN,
+                      DA7218_OUTDAI_2L_INFILT_1R_GAIN_SHIFT,
+                      DA7218_DMIX_GAIN_MAX, DA7218_NO_INVERT,
+                      da7218_dmix_gain_tlv),
+       SOC_SINGLE_TLV("DMix In Filter1R Out2 DAIR Volume",
+                      DA7218_DMIX_OUTDAI_2R_INFILT_1R_GAIN,
+                      DA7218_OUTDAI_2R_INFILT_1R_GAIN_SHIFT,
+                      DA7218_DMIX_GAIN_MAX, DA7218_NO_INVERT,
+                      da7218_dmix_gain_tlv),
+
+       SOC_SINGLE_TLV("DMix In Filter2L Out1 DAIL Volume",
+                      DA7218_DMIX_OUTDAI_1L_INFILT_2L_GAIN,
+                      DA7218_OUTDAI_1L_INFILT_2L_GAIN_SHIFT,
+                      DA7218_DMIX_GAIN_MAX, DA7218_NO_INVERT,
+                      da7218_dmix_gain_tlv),
+       SOC_SINGLE_TLV("DMix In Filter2L Out1 DAIR Volume",
+                      DA7218_DMIX_OUTDAI_1R_INFILT_2L_GAIN,
+                      DA7218_OUTDAI_1R_INFILT_2L_GAIN_SHIFT,
+                      DA7218_DMIX_GAIN_MAX, DA7218_NO_INVERT,
+                      da7218_dmix_gain_tlv),
+       SOC_SINGLE_TLV("DMix In Filter2L Out2 DAIL Volume",
+                      DA7218_DMIX_OUTDAI_2L_INFILT_2L_GAIN,
+                      DA7218_OUTDAI_2L_INFILT_2L_GAIN_SHIFT,
+                      DA7218_DMIX_GAIN_MAX, DA7218_NO_INVERT,
+                      da7218_dmix_gain_tlv),
+       SOC_SINGLE_TLV("DMix In Filter2L Out2 DAIR Volume",
+                      DA7218_DMIX_OUTDAI_2R_INFILT_2L_GAIN,
+                      DA7218_OUTDAI_2R_INFILT_2L_GAIN_SHIFT,
+                      DA7218_DMIX_GAIN_MAX, DA7218_NO_INVERT,
+                      da7218_dmix_gain_tlv),
+
+       SOC_SINGLE_TLV("DMix In Filter2R Out1 DAIL Volume",
+                      DA7218_DMIX_OUTDAI_1L_INFILT_2R_GAIN,
+                      DA7218_OUTDAI_1L_INFILT_2R_GAIN_SHIFT,
+                      DA7218_DMIX_GAIN_MAX, DA7218_NO_INVERT,
+                      da7218_dmix_gain_tlv),
+       SOC_SINGLE_TLV("DMix In Filter2R Out1 DAIR Volume",
+                      DA7218_DMIX_OUTDAI_1R_INFILT_2R_GAIN,
+                      DA7218_OUTDAI_1R_INFILT_2R_GAIN_SHIFT,
+                      DA7218_DMIX_GAIN_MAX, DA7218_NO_INVERT,
+                      da7218_dmix_gain_tlv),
+       SOC_SINGLE_TLV("DMix In Filter2R Out2 DAIL Volume",
+                      DA7218_DMIX_OUTDAI_2L_INFILT_2R_GAIN,
+                      DA7218_OUTDAI_2L_INFILT_2R_GAIN_SHIFT,
+                      DA7218_DMIX_GAIN_MAX, DA7218_NO_INVERT,
+                      da7218_dmix_gain_tlv),
+       SOC_SINGLE_TLV("DMix In Filter2R Out2 DAIR Volume",
+                      DA7218_DMIX_OUTDAI_2R_INFILT_2R_GAIN,
+                      DA7218_OUTDAI_2R_INFILT_2R_GAIN_SHIFT,
+                      DA7218_DMIX_GAIN_MAX, DA7218_NO_INVERT,
+                      da7218_dmix_gain_tlv),
+
+       SOC_SINGLE_TLV("DMix ToneGen Out1 DAIL Volume",
+                      DA7218_DMIX_OUTDAI_1L_TONEGEN_GAIN,
+                      DA7218_OUTDAI_1L_TONEGEN_GAIN_SHIFT,
+                      DA7218_DMIX_GAIN_MAX, DA7218_NO_INVERT,
+                      da7218_dmix_gain_tlv),
+       SOC_SINGLE_TLV("DMix ToneGen Out1 DAIR Volume",
+                      DA7218_DMIX_OUTDAI_1R_TONEGEN_GAIN,
+                      DA7218_OUTDAI_1R_TONEGEN_GAIN_SHIFT,
+                      DA7218_DMIX_GAIN_MAX, DA7218_NO_INVERT,
+                      da7218_dmix_gain_tlv),
+       SOC_SINGLE_TLV("DMix ToneGen Out2 DAIL Volume",
+                      DA7218_DMIX_OUTDAI_2L_TONEGEN_GAIN,
+                      DA7218_OUTDAI_2L_TONEGEN_GAIN_SHIFT,
+                      DA7218_DMIX_GAIN_MAX, DA7218_NO_INVERT,
+                      da7218_dmix_gain_tlv),
+       SOC_SINGLE_TLV("DMix ToneGen Out2 DAIR Volume",
+                      DA7218_DMIX_OUTDAI_2R_TONEGEN_GAIN,
+                      DA7218_OUTDAI_2R_TONEGEN_GAIN_SHIFT,
+                      DA7218_DMIX_GAIN_MAX, DA7218_NO_INVERT,
+                      da7218_dmix_gain_tlv),
+
+       SOC_SINGLE_TLV("DMix In DAIL Out1 DAIL Volume",
+                      DA7218_DMIX_OUTDAI_1L_INDAI_1L_GAIN,
+                      DA7218_OUTDAI_1L_INDAI_1L_GAIN_SHIFT,
+                      DA7218_DMIX_GAIN_MAX, DA7218_NO_INVERT,
+                      da7218_dmix_gain_tlv),
+       SOC_SINGLE_TLV("DMix In DAIL Out1 DAIR Volume",
+                      DA7218_DMIX_OUTDAI_1R_INDAI_1L_GAIN,
+                      DA7218_OUTDAI_1R_INDAI_1L_GAIN_SHIFT,
+                      DA7218_DMIX_GAIN_MAX, DA7218_NO_INVERT,
+                      da7218_dmix_gain_tlv),
+       SOC_SINGLE_TLV("DMix In DAIL Out2 DAIL Volume",
+                      DA7218_DMIX_OUTDAI_2L_INDAI_1L_GAIN,
+                      DA7218_OUTDAI_2L_INDAI_1L_GAIN_SHIFT,
+                      DA7218_DMIX_GAIN_MAX, DA7218_NO_INVERT,
+                      da7218_dmix_gain_tlv),
+       SOC_SINGLE_TLV("DMix In DAIL Out2 DAIR Volume",
+                      DA7218_DMIX_OUTDAI_2R_INDAI_1L_GAIN,
+                      DA7218_OUTDAI_2R_INDAI_1L_GAIN_SHIFT,
+                      DA7218_DMIX_GAIN_MAX, DA7218_NO_INVERT,
+                      da7218_dmix_gain_tlv),
+
+       SOC_SINGLE_TLV("DMix In DAIR Out1 DAIL Volume",
+                      DA7218_DMIX_OUTDAI_1L_INDAI_1R_GAIN,
+                      DA7218_OUTDAI_1L_INDAI_1R_GAIN_SHIFT,
+                      DA7218_DMIX_GAIN_MAX, DA7218_NO_INVERT,
+                      da7218_dmix_gain_tlv),
+       SOC_SINGLE_TLV("DMix In DAIR Out1 DAIR Volume",
+                      DA7218_DMIX_OUTDAI_1R_INDAI_1R_GAIN,
+                      DA7218_OUTDAI_1R_INDAI_1R_GAIN_SHIFT,
+                      DA7218_DMIX_GAIN_MAX, DA7218_NO_INVERT,
+                      da7218_dmix_gain_tlv),
+       SOC_SINGLE_TLV("DMix In DAIR Out2 DAIL Volume",
+                      DA7218_DMIX_OUTDAI_2L_INDAI_1R_GAIN,
+                      DA7218_OUTDAI_2L_INDAI_1R_GAIN_SHIFT,
+                      DA7218_DMIX_GAIN_MAX, DA7218_NO_INVERT,
+                      da7218_dmix_gain_tlv),
+       SOC_SINGLE_TLV("DMix In DAIR Out2 DAIR Volume",
+                      DA7218_DMIX_OUTDAI_2R_INDAI_1R_GAIN,
+                      DA7218_OUTDAI_2R_INDAI_1R_GAIN_SHIFT,
+                      DA7218_DMIX_GAIN_MAX, DA7218_NO_INVERT,
+                      da7218_dmix_gain_tlv),
+
+       /* Digital Mixer (Output) */
+       SOC_SINGLE_TLV("DMix In Filter1L Out FilterL Volume",
+                      DA7218_DMIX_OUTFILT_1L_INFILT_1L_GAIN,
+                      DA7218_OUTFILT_1L_INFILT_1L_GAIN_SHIFT,
+                      DA7218_DMIX_GAIN_MAX, DA7218_NO_INVERT,
+                      da7218_dmix_gain_tlv),
+       SOC_SINGLE_TLV("DMix In Filter1L Out FilterR Volume",
+                      DA7218_DMIX_OUTFILT_1R_INFILT_1L_GAIN,
+                      DA7218_OUTFILT_1R_INFILT_1L_GAIN_SHIFT,
+                      DA7218_DMIX_GAIN_MAX, DA7218_NO_INVERT,
+                      da7218_dmix_gain_tlv),
+
+       SOC_SINGLE_TLV("DMix In Filter1R Out FilterL Volume",
+                      DA7218_DMIX_OUTFILT_1L_INFILT_1R_GAIN,
+                      DA7218_OUTFILT_1L_INFILT_1R_GAIN_SHIFT,
+                      DA7218_DMIX_GAIN_MAX, DA7218_NO_INVERT,
+                      da7218_dmix_gain_tlv),
+       SOC_SINGLE_TLV("DMix In Filter1R Out FilterR Volume",
+                      DA7218_DMIX_OUTFILT_1R_INFILT_1R_GAIN,
+                      DA7218_OUTFILT_1R_INFILT_1R_GAIN_SHIFT,
+                      DA7218_DMIX_GAIN_MAX, DA7218_NO_INVERT,
+                      da7218_dmix_gain_tlv),
+
+       SOC_SINGLE_TLV("DMix In Filter2L Out FilterL Volume",
+                      DA7218_DMIX_OUTFILT_1L_INFILT_2L_GAIN,
+                      DA7218_OUTFILT_1L_INFILT_2L_GAIN_SHIFT,
+                      DA7218_DMIX_GAIN_MAX, DA7218_NO_INVERT,
+                      da7218_dmix_gain_tlv),
+       SOC_SINGLE_TLV("DMix In Filter2L Out FilterR Volume",
+                      DA7218_DMIX_OUTFILT_1R_INFILT_2L_GAIN,
+                      DA7218_OUTFILT_1R_INFILT_2L_GAIN_SHIFT,
+                      DA7218_DMIX_GAIN_MAX, DA7218_NO_INVERT,
+                      da7218_dmix_gain_tlv),
+
+       SOC_SINGLE_TLV("DMix In Filter2R Out FilterL Volume",
+                      DA7218_DMIX_OUTFILT_1L_INFILT_2R_GAIN,
+                      DA7218_OUTFILT_1L_INFILT_2R_GAIN_SHIFT,
+                      DA7218_DMIX_GAIN_MAX, DA7218_NO_INVERT,
+                      da7218_dmix_gain_tlv),
+       SOC_SINGLE_TLV("DMix In Filter2R Out FilterR Volume",
+                      DA7218_DMIX_OUTFILT_1R_INFILT_2R_GAIN,
+                      DA7218_OUTFILT_1R_INFILT_2R_GAIN_SHIFT,
+                      DA7218_DMIX_GAIN_MAX, DA7218_NO_INVERT,
+                      da7218_dmix_gain_tlv),
+
+       SOC_SINGLE_TLV("DMix ToneGen Out FilterL Volume",
+                      DA7218_DMIX_OUTFILT_1L_TONEGEN_GAIN,
+                      DA7218_OUTFILT_1L_TONEGEN_GAIN_SHIFT,
+                      DA7218_DMIX_GAIN_MAX, DA7218_NO_INVERT,
+                      da7218_dmix_gain_tlv),
+       SOC_SINGLE_TLV("DMix ToneGen Out FilterR Volume",
+                      DA7218_DMIX_OUTFILT_1R_TONEGEN_GAIN,
+                      DA7218_OUTFILT_1R_TONEGEN_GAIN_SHIFT,
+                      DA7218_DMIX_GAIN_MAX, DA7218_NO_INVERT,
+                      da7218_dmix_gain_tlv),
+
+       SOC_SINGLE_TLV("DMix In DAIL Out FilterL Volume",
+                      DA7218_DMIX_OUTFILT_1L_INDAI_1L_GAIN,
+                      DA7218_OUTFILT_1L_INDAI_1L_GAIN_SHIFT,
+                      DA7218_DMIX_GAIN_MAX, DA7218_NO_INVERT,
+                      da7218_dmix_gain_tlv),
+       SOC_SINGLE_TLV("DMix In DAIL Out FilterR Volume",
+                      DA7218_DMIX_OUTFILT_1R_INDAI_1L_GAIN,
+                      DA7218_OUTFILT_1R_INDAI_1L_GAIN_SHIFT,
+                      DA7218_DMIX_GAIN_MAX, DA7218_NO_INVERT,
+                      da7218_dmix_gain_tlv),
+
+       SOC_SINGLE_TLV("DMix In DAIR Out FilterL Volume",
+                      DA7218_DMIX_OUTFILT_1L_INDAI_1R_GAIN,
+                      DA7218_OUTFILT_1L_INDAI_1R_GAIN_SHIFT,
+                      DA7218_DMIX_GAIN_MAX, DA7218_NO_INVERT,
+                      da7218_dmix_gain_tlv),
+       SOC_SINGLE_TLV("DMix In DAIR Out FilterR Volume",
+                      DA7218_DMIX_OUTFILT_1R_INDAI_1R_GAIN,
+                      DA7218_OUTFILT_1R_INDAI_1R_GAIN_SHIFT,
+                      DA7218_DMIX_GAIN_MAX, DA7218_NO_INVERT,
+                      da7218_dmix_gain_tlv),
+
+       /* Sidetone Filter */
+       SND_SOC_BYTES_EXT("Sidetone BiQuad Coefficients",
+                         DA7218_SIDETONE_BIQ_3STAGE_CFG_SIZE,
+                         da7218_biquad_coeff_get, da7218_biquad_coeff_put),
+       SOC_SINGLE_TLV("Sidetone Volume", DA7218_SIDETONE_GAIN,
+                      DA7218_SIDETONE_GAIN_SHIFT, DA7218_DMIX_GAIN_MAX,
+                      DA7218_NO_INVERT, da7218_dmix_gain_tlv),
+       SOC_SINGLE("Sidetone Switch", DA7218_SIDETONE_CTRL,
+                  DA7218_SIDETONE_MUTE_EN_SHIFT, DA7218_SWITCH_EN_MAX,
+                  DA7218_INVERT),
+
+       /* Tone Generator */
+       SOC_ENUM("ToneGen DTMF Key", da7218_tonegen_dtmf_key),
+       SOC_SINGLE("ToneGen DTMF Switch", DA7218_TONE_GEN_CFG1,
+                  DA7218_DTMF_EN_SHIFT, DA7218_SWITCH_EN_MAX,
+                  DA7218_NO_INVERT),
+       SOC_ENUM("ToneGen Sinewave Gen Type", da7218_tonegen_swg_sel),
+       SOC_SINGLE_EXT("ToneGen Sinewave1 Freq", DA7218_TONE_GEN_FREQ1_L,
+                      DA7218_FREQ1_L_SHIFT, DA7218_FREQ_MAX, DA7218_NO_INVERT,
+                      da7218_tonegen_freq_get, da7218_tonegen_freq_put),
+       SOC_SINGLE_EXT("ToneGen Sinewave2 Freq", DA7218_TONE_GEN_FREQ2_L,
+                      DA7218_FREQ2_L_SHIFT, DA7218_FREQ_MAX, DA7218_NO_INVERT,
+                      da7218_tonegen_freq_get, da7218_tonegen_freq_put),
+       SOC_SINGLE("ToneGen On Time", DA7218_TONE_GEN_ON_PER,
+                  DA7218_BEEP_ON_PER_SHIFT, DA7218_BEEP_ON_OFF_MAX,
+                  DA7218_NO_INVERT),
+       SOC_SINGLE("ToneGen Off Time", DA7218_TONE_GEN_OFF_PER,
+                  DA7218_BEEP_OFF_PER_SHIFT, DA7218_BEEP_ON_OFF_MAX,
+                  DA7218_NO_INVERT),
+
+       /* Gain ramping */
+       SOC_ENUM("Gain Ramp Rate", da7218_gain_ramp_rate),
+
+       /* DGS */
+       SOC_SINGLE_TLV("DGS Trigger", DA7218_DGS_TRIGGER,
+                      DA7218_DGS_TRIGGER_LVL_SHIFT, DA7218_DGS_TRIGGER_MAX,
+                      DA7218_INVERT, da7218_dgs_trigger_tlv),
+       SOC_ENUM("DGS Rise Coefficient", da7218_dgs_rise_coeff),
+       SOC_ENUM("DGS Fall Coefficient", da7218_dgs_fall_coeff),
+       SOC_SINGLE("DGS Sync Delay", DA7218_DGS_SYNC_DELAY,
+                  DA7218_DGS_SYNC_DELAY_SHIFT, DA7218_DGS_SYNC_DELAY_MAX,
+                  DA7218_NO_INVERT),
+       SOC_SINGLE("DGS Fast SR Sync Delay", DA7218_DGS_SYNC_DELAY2,
+                  DA7218_DGS_SYNC_DELAY2_SHIFT, DA7218_DGS_SYNC_DELAY_MAX,
+                  DA7218_NO_INVERT),
+       SOC_SINGLE("DGS Voice Filter Sync Delay", DA7218_DGS_SYNC_DELAY3,
+                  DA7218_DGS_SYNC_DELAY3_SHIFT, DA7218_DGS_SYNC_DELAY3_MAX,
+                  DA7218_NO_INVERT),
+       SOC_SINGLE_TLV("DGS Anticlip Level", DA7218_DGS_LEVELS,
+                      DA7218_DGS_ANTICLIP_LVL_SHIFT,
+                      DA7218_DGS_ANTICLIP_LVL_MAX, DA7218_INVERT,
+                      da7218_dgs_anticlip_tlv),
+       SOC_SINGLE_TLV("DGS Signal Level", DA7218_DGS_LEVELS,
+                      DA7218_DGS_SIGNAL_LVL_SHIFT, DA7218_DGS_SIGNAL_LVL_MAX,
+                      DA7218_INVERT, da7218_dgs_signal_tlv),
+       SOC_SINGLE("DGS Gain Subrange Switch", DA7218_DGS_GAIN_CTRL,
+                  DA7218_DGS_SUBR_EN_SHIFT, DA7218_SWITCH_EN_MAX,
+                  DA7218_NO_INVERT),
+       SOC_SINGLE("DGS Gain Ramp Switch", DA7218_DGS_GAIN_CTRL,
+                  DA7218_DGS_RAMP_EN_SHIFT, DA7218_SWITCH_EN_MAX,
+                  DA7218_NO_INVERT),
+       SOC_SINGLE("DGS Gain Steps", DA7218_DGS_GAIN_CTRL,
+                  DA7218_DGS_STEPS_SHIFT, DA7218_DGS_STEPS_MAX,
+                  DA7218_NO_INVERT),
+       SOC_DOUBLE("DGS Switch", DA7218_DGS_ENABLE, DA7218_DGS_ENABLE_L_SHIFT,
+                  DA7218_DGS_ENABLE_R_SHIFT, DA7218_SWITCH_EN_MAX,
+                  DA7218_NO_INVERT),
+
+       /* Output High-Pass Filter */
+       SOC_ENUM("Out Filter HPF Mode", da7218_out1_hpf_mode),
+       SOC_ENUM("Out Filter HPF Corner Audio", da7218_out1_audio_hpf_corner),
+       SOC_ENUM("Out Filter HPF Corner Voice", da7218_out1_voice_hpf_corner),
+
+       /* 5-Band Equaliser */
+       SOC_SINGLE_TLV("Out EQ Band1 Volume", DA7218_OUT_1_EQ_12_FILTER_CTRL,
+                      DA7218_OUT_1_EQ_BAND1_SHIFT, DA7218_OUT_EQ_BAND_MAX,
+                      DA7218_NO_INVERT, da7218_out_eq_band_tlv),
+       SOC_SINGLE_TLV("Out EQ Band2 Volume", DA7218_OUT_1_EQ_12_FILTER_CTRL,
+                      DA7218_OUT_1_EQ_BAND2_SHIFT, DA7218_OUT_EQ_BAND_MAX,
+                      DA7218_NO_INVERT, da7218_out_eq_band_tlv),
+       SOC_SINGLE_TLV("Out EQ Band3 Volume", DA7218_OUT_1_EQ_34_FILTER_CTRL,
+                      DA7218_OUT_1_EQ_BAND3_SHIFT, DA7218_OUT_EQ_BAND_MAX,
+                      DA7218_NO_INVERT, da7218_out_eq_band_tlv),
+       SOC_SINGLE_TLV("Out EQ Band4 Volume", DA7218_OUT_1_EQ_34_FILTER_CTRL,
+                      DA7218_OUT_1_EQ_BAND4_SHIFT, DA7218_OUT_EQ_BAND_MAX,
+                      DA7218_NO_INVERT, da7218_out_eq_band_tlv),
+       SOC_SINGLE_TLV("Out EQ Band5 Volume", DA7218_OUT_1_EQ_5_FILTER_CTRL,
+                      DA7218_OUT_1_EQ_BAND5_SHIFT, DA7218_OUT_EQ_BAND_MAX,
+                      DA7218_NO_INVERT, da7218_out_eq_band_tlv),
+       SOC_SINGLE("Out EQ Switch", DA7218_OUT_1_EQ_5_FILTER_CTRL,
+                  DA7218_OUT_1_EQ_EN_SHIFT, DA7218_SWITCH_EN_MAX,
+                  DA7218_NO_INVERT),
+
+       /* BiQuad Filters */
+       SND_SOC_BYTES_EXT("BiQuad Coefficients",
+                         DA7218_OUT_1_BIQ_5STAGE_CFG_SIZE,
+                         da7218_biquad_coeff_get, da7218_biquad_coeff_put),
+       SOC_SINGLE("BiQuad Filter Switch", DA7218_OUT_1_BIQ_5STAGE_CTRL,
+                  DA7218_OUT_1_BIQ_5STAGE_MUTE_EN_SHIFT, DA7218_SWITCH_EN_MAX,
+                  DA7218_INVERT),
+
+       /* Output Filters */
+       SOC_DOUBLE_R_RANGE_TLV("Out Filter Volume", DA7218_OUT_1L_GAIN,
+                              DA7218_OUT_1R_GAIN,
+                              DA7218_OUT_1L_DIGITAL_GAIN_SHIFT,
+                              DA7218_OUT_DIGITAL_GAIN_MIN,
+                              DA7218_OUT_DIGITAL_GAIN_MAX, DA7218_NO_INVERT,
+                              da7218_out_dig_gain_tlv),
+       SOC_DOUBLE_R("Out Filter Switch", DA7218_OUT_1L_FILTER_CTRL,
+                    DA7218_OUT_1R_FILTER_CTRL, DA7218_OUT_1L_MUTE_EN_SHIFT,
+                    DA7218_SWITCH_EN_MAX, DA7218_INVERT),
+       SOC_DOUBLE_R("Out Filter Gain Subrange Switch",
+                    DA7218_OUT_1L_FILTER_CTRL, DA7218_OUT_1R_FILTER_CTRL,
+                    DA7218_OUT_1L_SUBRANGE_EN_SHIFT, DA7218_SWITCH_EN_MAX,
+                    DA7218_NO_INVERT),
+       SOC_DOUBLE_R("Out Filter Gain Ramp Switch", DA7218_OUT_1L_FILTER_CTRL,
+                    DA7218_OUT_1R_FILTER_CTRL, DA7218_OUT_1L_RAMP_EN_SHIFT,
+                    DA7218_SWITCH_EN_MAX, DA7218_NO_INVERT),
+
+       /* Mixer Output */
+       SOC_DOUBLE_R_RANGE_TLV("Mixout Volume", DA7218_MIXOUT_L_GAIN,
+                              DA7218_MIXOUT_R_GAIN,
+                              DA7218_MIXOUT_L_AMP_GAIN_SHIFT,
+                              DA7218_MIXOUT_AMP_GAIN_MIN,
+                              DA7218_MIXOUT_AMP_GAIN_MAX, DA7218_NO_INVERT,
+                              da7218_mixout_gain_tlv),
+
+       /* DAC Noise Gate */
+       SOC_ENUM("DAC NG Setup Time", da7218_dac_ng_setup_time),
+       SOC_ENUM("DAC NG Rampup Rate", da7218_dac_ng_rampup_rate),
+       SOC_ENUM("DAC NG Rampdown Rate", da7218_dac_ng_rampdown_rate),
+       SOC_SINGLE_TLV("DAC NG Off Threshold", DA7218_DAC_NG_OFF_THRESH,
+                      DA7218_DAC_NG_OFF_THRESHOLD_SHIFT,
+                      DA7218_DAC_NG_THRESHOLD_MAX, DA7218_NO_INVERT,
+                      da7218_dac_ng_threshold_tlv),
+       SOC_SINGLE_TLV("DAC NG On Threshold", DA7218_DAC_NG_ON_THRESH,
+                      DA7218_DAC_NG_ON_THRESHOLD_SHIFT,
+                      DA7218_DAC_NG_THRESHOLD_MAX, DA7218_NO_INVERT,
+                      da7218_dac_ng_threshold_tlv),
+       SOC_SINGLE("DAC NG Switch", DA7218_DAC_NG_CTRL, DA7218_DAC_NG_EN_SHIFT,
+                  DA7218_SWITCH_EN_MAX, DA7218_NO_INVERT),
+
+       /* CP */
+       SOC_ENUM("Charge Pump Track Mode", da7218_cp_mchange),
+       SOC_ENUM("Charge Pump Frequency", da7218_cp_fcontrol),
+       SOC_ENUM("Charge Pump Decay Rate", da7218_cp_tau_delay),
+       SOC_SINGLE("Charge Pump Threshold", DA7218_CP_VOL_THRESHOLD1,
+                  DA7218_CP_THRESH_VDD2_SHIFT, DA7218_CP_THRESH_VDD2_MAX,
+                  DA7218_NO_INVERT),
+
+       /* Headphones */
+       SOC_DOUBLE_R_RANGE_TLV("Headphone Volume", DA7218_HP_L_GAIN,
+                              DA7218_HP_R_GAIN, DA7218_HP_L_AMP_GAIN_SHIFT,
+                              DA7218_HP_AMP_GAIN_MIN, DA7218_HP_AMP_GAIN_MAX,
+                              DA7218_NO_INVERT, da7218_hp_gain_tlv),
+       SOC_DOUBLE_R("Headphone Switch", DA7218_HP_L_CTRL, DA7218_HP_R_CTRL,
+                    DA7218_HP_L_AMP_MUTE_EN_SHIFT, DA7218_SWITCH_EN_MAX,
+                    DA7218_INVERT),
+       SOC_DOUBLE_R("Headphone Gain Ramp Switch", DA7218_HP_L_CTRL,
+                    DA7218_HP_R_CTRL, DA7218_HP_L_AMP_RAMP_EN_SHIFT,
+                    DA7218_SWITCH_EN_MAX, DA7218_NO_INVERT),
+       SOC_DOUBLE_R("Headphone ZC Gain Switch", DA7218_HP_L_CTRL,
+                    DA7218_HP_R_CTRL, DA7218_HP_L_AMP_ZC_EN_SHIFT,
+                    DA7218_SWITCH_EN_MAX, DA7218_NO_INVERT),
+};
+
+
+/*
+ * DAPM Mux Controls
+ */
+
+static const char * const da7218_mic_sel_text[] = { "Analog", "Digital" };
+
+static const struct soc_enum da7218_mic1_sel =
+       SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(da7218_mic_sel_text),
+                           da7218_mic_sel_text);
+
+static const struct snd_kcontrol_new da7218_mic1_sel_mux =
+       SOC_DAPM_ENUM("Mic1 Mux", da7218_mic1_sel);
+
+static const struct soc_enum da7218_mic2_sel =
+       SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(da7218_mic_sel_text),
+                           da7218_mic_sel_text);
+
+static const struct snd_kcontrol_new da7218_mic2_sel_mux =
+       SOC_DAPM_ENUM("Mic2 Mux", da7218_mic2_sel);
+
+static const char * const da7218_sidetone_in_sel_txt[] = {
+       "In Filter1L", "In Filter1R", "In Filter2L", "In Filter2R"
+};
+
+static const struct soc_enum da7218_sidetone_in_sel =
+       SOC_ENUM_SINGLE(DA7218_SIDETONE_IN_SELECT,
+                       DA7218_SIDETONE_IN_SELECT_SHIFT,
+                       DA7218_SIDETONE_IN_SELECT_MAX,
+                       da7218_sidetone_in_sel_txt);
+
+static const struct snd_kcontrol_new da7218_sidetone_in_sel_mux =
+       SOC_DAPM_ENUM("Sidetone Mux", da7218_sidetone_in_sel);
+
+static const char * const da7218_out_filt_biq_sel_txt[] = {
+       "Bypass", "Enabled"
+};
+
+static const struct soc_enum da7218_out_filtl_biq_sel =
+       SOC_ENUM_SINGLE(DA7218_OUT_1L_FILTER_CTRL,
+                       DA7218_OUT_1L_BIQ_5STAGE_SEL_SHIFT,
+                       DA7218_OUT_BIQ_5STAGE_SEL_MAX,
+                       da7218_out_filt_biq_sel_txt);
+
+static const struct snd_kcontrol_new da7218_out_filtl_biq_sel_mux =
+       SOC_DAPM_ENUM("Out FilterL BiQuad Mux", da7218_out_filtl_biq_sel);
+
+static const struct soc_enum da7218_out_filtr_biq_sel =
+       SOC_ENUM_SINGLE(DA7218_OUT_1R_FILTER_CTRL,
+                       DA7218_OUT_1R_BIQ_5STAGE_SEL_SHIFT,
+                       DA7218_OUT_BIQ_5STAGE_SEL_MAX,
+                       da7218_out_filt_biq_sel_txt);
+
+static const struct snd_kcontrol_new da7218_out_filtr_biq_sel_mux =
+       SOC_DAPM_ENUM("Out FilterR BiQuad Mux", da7218_out_filtr_biq_sel);
+
+
+/*
+ * DAPM Mixer Controls
+ */
+
+#define DA7218_DMIX_CTRLS(reg)                                         \
+       SOC_DAPM_SINGLE("In Filter1L Switch", reg,                      \
+                       DA7218_DMIX_SRC_INFILT1L,                       \
+                       DA7218_SWITCH_EN_MAX, DA7218_NO_INVERT),        \
+       SOC_DAPM_SINGLE("In Filter1R Switch", reg,                      \
+                       DA7218_DMIX_SRC_INFILT1R,                       \
+                       DA7218_SWITCH_EN_MAX, DA7218_NO_INVERT),        \
+       SOC_DAPM_SINGLE("In Filter2L Switch", reg,                      \
+                       DA7218_DMIX_SRC_INFILT2L,                       \
+                       DA7218_SWITCH_EN_MAX, DA7218_NO_INVERT),        \
+       SOC_DAPM_SINGLE("In Filter2R Switch", reg,                      \
+                       DA7218_DMIX_SRC_INFILT2R,                       \
+                       DA7218_SWITCH_EN_MAX, DA7218_NO_INVERT),        \
+       SOC_DAPM_SINGLE("ToneGen Switch", reg,                          \
+                       DA7218_DMIX_SRC_TONEGEN,                        \
+                       DA7218_SWITCH_EN_MAX, DA7218_NO_INVERT),        \
+       SOC_DAPM_SINGLE("DAIL Switch", reg, DA7218_DMIX_SRC_DAIL,       \
+                       DA7218_SWITCH_EN_MAX, DA7218_NO_INVERT),        \
+       SOC_DAPM_SINGLE("DAIR Switch", reg, DA7218_DMIX_SRC_DAIR,       \
+                       DA7218_SWITCH_EN_MAX, DA7218_NO_INVERT)
+
+static const struct snd_kcontrol_new da7218_out_dai1l_mix_controls[] = {
+       DA7218_DMIX_CTRLS(DA7218_DROUTING_OUTDAI_1L),
+};
+
+static const struct snd_kcontrol_new da7218_out_dai1r_mix_controls[] = {
+       DA7218_DMIX_CTRLS(DA7218_DROUTING_OUTDAI_1R),
+};
+
+static const struct snd_kcontrol_new da7218_out_dai2l_mix_controls[] = {
+       DA7218_DMIX_CTRLS(DA7218_DROUTING_OUTDAI_2L),
+};
+
+static const struct snd_kcontrol_new da7218_out_dai2r_mix_controls[] = {
+       DA7218_DMIX_CTRLS(DA7218_DROUTING_OUTDAI_2R),
+};
+
+static const struct snd_kcontrol_new da7218_out_filtl_mix_controls[] = {
+       DA7218_DMIX_CTRLS(DA7218_DROUTING_OUTFILT_1L),
+};
+
+static const struct snd_kcontrol_new da7218_out_filtr_mix_controls[] = {
+       DA7218_DMIX_CTRLS(DA7218_DROUTING_OUTFILT_1R),
+};
+
+#define DA7218_DMIX_ST_CTRLS(reg)                                      \
+       SOC_DAPM_SINGLE("Out FilterL Switch", reg,                      \
+                       DA7218_DMIX_ST_SRC_OUTFILT1L,                   \
+                       DA7218_SWITCH_EN_MAX, DA7218_NO_INVERT),        \
+       SOC_DAPM_SINGLE("Out FilterR Switch", reg,                      \
+                       DA7218_DMIX_ST_SRC_OUTFILT1R,                   \
+                       DA7218_SWITCH_EN_MAX, DA7218_NO_INVERT),        \
+       SOC_DAPM_SINGLE("Sidetone Switch", reg,                         \
+                       DA7218_DMIX_ST_SRC_SIDETONE,                    \
+                       DA7218_SWITCH_EN_MAX, DA7218_NO_INVERT)         \
+
+static const struct snd_kcontrol_new da7218_st_out_filtl_mix_controls[] = {
+       DA7218_DMIX_ST_CTRLS(DA7218_DROUTING_ST_OUTFILT_1L),
+};
+
+static const struct snd_kcontrol_new da7218_st_out_filtr_mix_controls[] = {
+       DA7218_DMIX_ST_CTRLS(DA7218_DROUTING_ST_OUTFILT_1R),
+};
+
+
+/*
+ * DAPM Events
+ */
+
+/*
+ * We keep track of which input filters are enabled. This is used in the logic
+ * for controlling the mic level detect feature.
+ */
+static int da7218_in_filter_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);
+       struct da7218_priv *da7218 = snd_soc_codec_get_drvdata(codec);
+       u8 mask;
+
+       switch (w->reg) {
+       case DA7218_IN_1L_FILTER_CTRL:
+               mask = (1 << DA7218_LVL_DET_EN_CHAN1L_SHIFT);
+               break;
+       case DA7218_IN_1R_FILTER_CTRL:
+               mask = (1 << DA7218_LVL_DET_EN_CHAN1R_SHIFT);
+               break;
+       case DA7218_IN_2L_FILTER_CTRL:
+               mask = (1 << DA7218_LVL_DET_EN_CHAN2L_SHIFT);
+               break;
+       case DA7218_IN_2R_FILTER_CTRL:
+               mask = (1 << DA7218_LVL_DET_EN_CHAN2R_SHIFT);
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       switch (event) {
+       case SND_SOC_DAPM_POST_PMU:
+               da7218->in_filt_en |= mask;
+               /*
+                * If we're enabling path for mic level detect, wait for path
+                * to settle before enabling feature to avoid incorrect and
+                * unwanted detect events.
+                */
+               if (mask & da7218->mic_lvl_det_en)
+                       msleep(DA7218_MIC_LVL_DET_DELAY);
+               break;
+       case SND_SOC_DAPM_PRE_PMD:
+               da7218->in_filt_en &= ~mask;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       /* Enable configured level detection paths */
+       snd_soc_write(codec, DA7218_LVL_DET_CTRL,
+                     (da7218->in_filt_en & da7218->mic_lvl_det_en));
+
+       return 0;
+}
+
+static int da7218_dai_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);
+       struct da7218_priv *da7218 = snd_soc_codec_get_drvdata(codec);
+       u8 pll_ctrl, pll_status, refosc_cal;
+       int i;
+       bool success;
+
+       switch (event) {
+       case SND_SOC_DAPM_POST_PMU:
+               if (da7218->master)
+                       /* Enable DAI clks for master mode */
+                       snd_soc_update_bits(codec, DA7218_DAI_CLK_MODE,
+                                           DA7218_DAI_CLK_EN_MASK,
+                                           DA7218_DAI_CLK_EN_MASK);
+
+               /* Tune reference oscillator */
+               snd_soc_write(codec, DA7218_PLL_REFOSC_CAL,
+                             DA7218_PLL_REFOSC_CAL_START_MASK);
+               snd_soc_write(codec, DA7218_PLL_REFOSC_CAL,
+                             DA7218_PLL_REFOSC_CAL_START_MASK |
+                             DA7218_PLL_REFOSC_CAL_EN_MASK);
+
+               /* Check tuning complete */
+               i = 0;
+               success = false;
+               do {
+                       refosc_cal = snd_soc_read(codec, DA7218_PLL_REFOSC_CAL);
+                       if (!(refosc_cal & DA7218_PLL_REFOSC_CAL_START_MASK)) {
+                               success = true;
+                       } else {
+                               ++i;
+                               usleep_range(DA7218_REF_OSC_CHECK_DELAY_MIN,
+                                            DA7218_REF_OSC_CHECK_DELAY_MAX);
+                       }
+               } while ((i < DA7218_REF_OSC_CHECK_TRIES) && (!success));
+
+               if (!success)
+                       dev_warn(codec->dev,
+                                "Reference oscillator failed calibration\n");
+
+               /* PC synchronised to DAI */
+               snd_soc_write(codec, DA7218_PC_COUNT,
+                             DA7218_PC_RESYNC_AUTO_MASK);
+
+               /* If SRM not enabled, we don't need to check status */
+               pll_ctrl = snd_soc_read(codec, DA7218_PLL_CTRL);
+               if ((pll_ctrl & DA7218_PLL_MODE_MASK) != DA7218_PLL_MODE_SRM)
+                       return 0;
+
+               /* Check SRM has locked */
+               i = 0;
+               success = false;
+               do {
+                       pll_status = snd_soc_read(codec, DA7218_PLL_STATUS);
+                       if (pll_status & DA7218_PLL_SRM_STATUS_SRM_LOCK) {
+                               success = true;
+                       } else {
+                               ++i;
+                               msleep(DA7218_SRM_CHECK_DELAY);
+                       }
+               } while ((i < DA7218_SRM_CHECK_TRIES) & (!success));
+
+               if (!success)
+                       dev_warn(codec->dev, "SRM failed to lock\n");
+
+               return 0;
+       case SND_SOC_DAPM_POST_PMD:
+               /* PC free-running */
+               snd_soc_write(codec, DA7218_PC_COUNT, DA7218_PC_FREERUN_MASK);
+
+               if (da7218->master)
+                       /* Disable DAI clks for master mode */
+                       snd_soc_update_bits(codec, DA7218_DAI_CLK_MODE,
+                                           DA7218_DAI_CLK_EN_MASK, 0);
+
+               return 0;
+       default:
+               return -EINVAL;
+       }
+}
+
+static int da7218_cp_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);
+       struct da7218_priv *da7218 = snd_soc_codec_get_drvdata(codec);
+
+       /*
+        * If this is DA7217 and we're using single supply for differential
+        * output, we really don't want to touch the charge pump.
+        */
+       if (da7218->hp_single_supply)
+               return 0;
+
+       switch (event) {
+       case SND_SOC_DAPM_PRE_PMU:
+               snd_soc_update_bits(codec, DA7218_CP_CTRL, DA7218_CP_EN_MASK,
+                                   DA7218_CP_EN_MASK);
+               return 0;
+       case SND_SOC_DAPM_PRE_PMD:
+               snd_soc_update_bits(codec, DA7218_CP_CTRL, DA7218_CP_EN_MASK,
+                                   0);
+               return 0;
+       default:
+               return -EINVAL;
+       }
+}
+
+static int da7218_hp_pga_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_POST_PMU:
+               /* Enable headphone output */
+               snd_soc_update_bits(codec, w->reg, DA7218_HP_AMP_OE_MASK,
+                                   DA7218_HP_AMP_OE_MASK);
+               return 0;
+       case SND_SOC_DAPM_PRE_PMD:
+               /* Headphone output high impedance */
+               snd_soc_update_bits(codec, w->reg, DA7218_HP_AMP_OE_MASK, 0);
+               return 0;
+       default:
+               return -EINVAL;
+       }
+}
+
+
+/*
+ * DAPM Widgets
+ */
+
+static const struct snd_soc_dapm_widget da7218_dapm_widgets[] = {
+       /* Input Supplies */
+       SND_SOC_DAPM_SUPPLY("Mic Bias1", DA7218_MICBIAS_EN,
+                           DA7218_MICBIAS_1_EN_SHIFT, DA7218_NO_INVERT,
+                           NULL, 0),
+       SND_SOC_DAPM_SUPPLY("Mic Bias2", DA7218_MICBIAS_EN,
+                           DA7218_MICBIAS_2_EN_SHIFT, DA7218_NO_INVERT,
+                           NULL, 0),
+       SND_SOC_DAPM_SUPPLY("DMic1 Left", DA7218_DMIC_1_CTRL,
+                           DA7218_DMIC_1L_EN_SHIFT, DA7218_NO_INVERT,
+                           NULL, 0),
+       SND_SOC_DAPM_SUPPLY("DMic1 Right", DA7218_DMIC_1_CTRL,
+                           DA7218_DMIC_1R_EN_SHIFT, DA7218_NO_INVERT,
+                           NULL, 0),
+       SND_SOC_DAPM_SUPPLY("DMic2 Left", DA7218_DMIC_2_CTRL,
+                           DA7218_DMIC_2L_EN_SHIFT, DA7218_NO_INVERT,
+                           NULL, 0),
+       SND_SOC_DAPM_SUPPLY("DMic2 Right", DA7218_DMIC_2_CTRL,
+                           DA7218_DMIC_2R_EN_SHIFT, DA7218_NO_INVERT,
+                           NULL, 0),
+
+       /* Inputs */
+       SND_SOC_DAPM_INPUT("MIC1"),
+       SND_SOC_DAPM_INPUT("MIC2"),
+       SND_SOC_DAPM_INPUT("DMIC1L"),
+       SND_SOC_DAPM_INPUT("DMIC1R"),
+       SND_SOC_DAPM_INPUT("DMIC2L"),
+       SND_SOC_DAPM_INPUT("DMIC2R"),
+
+       /* Input Mixer Supplies */
+       SND_SOC_DAPM_SUPPLY("Mixin1 Supply", DA7218_MIXIN_1_CTRL,
+                           DA7218_MIXIN_1_MIX_SEL_SHIFT, DA7218_NO_INVERT,
+                           NULL, 0),
+       SND_SOC_DAPM_SUPPLY("Mixin2 Supply", DA7218_MIXIN_2_CTRL,
+                           DA7218_MIXIN_2_MIX_SEL_SHIFT, DA7218_NO_INVERT,
+                           NULL, 0),
+
+       /* Input PGAs */
+       SND_SOC_DAPM_PGA("Mic1 PGA", DA7218_MIC_1_CTRL,
+                        DA7218_MIC_1_AMP_EN_SHIFT, DA7218_NO_INVERT,
+                        NULL, 0),
+       SND_SOC_DAPM_PGA("Mic2 PGA", DA7218_MIC_2_CTRL,
+                        DA7218_MIC_2_AMP_EN_SHIFT, DA7218_NO_INVERT,
+                        NULL, 0),
+       SND_SOC_DAPM_PGA("Mixin1 PGA", DA7218_MIXIN_1_CTRL,
+                        DA7218_MIXIN_1_AMP_EN_SHIFT, DA7218_NO_INVERT,
+                        NULL, 0),
+       SND_SOC_DAPM_PGA("Mixin2 PGA", DA7218_MIXIN_2_CTRL,
+                        DA7218_MIXIN_2_AMP_EN_SHIFT, DA7218_NO_INVERT,
+                        NULL, 0),
+
+       /* Mic/DMic Muxes */
+       SND_SOC_DAPM_MUX("Mic1 Mux", SND_SOC_NOPM, 0, 0, &da7218_mic1_sel_mux),
+       SND_SOC_DAPM_MUX("Mic2 Mux", SND_SOC_NOPM, 0, 0, &da7218_mic2_sel_mux),
+
+       /* Input Filters */
+       SND_SOC_DAPM_ADC_E("In Filter1L", NULL, DA7218_IN_1L_FILTER_CTRL,
+                          DA7218_IN_1L_FILTER_EN_SHIFT, DA7218_NO_INVERT,
+                          da7218_in_filter_event,
+                          SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
+       SND_SOC_DAPM_ADC_E("In Filter1R", NULL, DA7218_IN_1R_FILTER_CTRL,
+                          DA7218_IN_1R_FILTER_EN_SHIFT, DA7218_NO_INVERT,
+                          da7218_in_filter_event,
+                          SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
+       SND_SOC_DAPM_ADC_E("In Filter2L", NULL, DA7218_IN_2L_FILTER_CTRL,
+                          DA7218_IN_2L_FILTER_EN_SHIFT, DA7218_NO_INVERT,
+                          da7218_in_filter_event,
+                          SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
+       SND_SOC_DAPM_ADC_E("In Filter2R", NULL, DA7218_IN_2R_FILTER_CTRL,
+                          DA7218_IN_2R_FILTER_EN_SHIFT, DA7218_NO_INVERT,
+                          da7218_in_filter_event,
+                          SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
+
+       /* Tone Generator */
+       SND_SOC_DAPM_SIGGEN("TONE"),
+       SND_SOC_DAPM_PGA("Tone Generator", DA7218_TONE_GEN_CFG1,
+                        DA7218_START_STOPN_SHIFT, DA7218_NO_INVERT, NULL, 0),
+
+       /* Sidetone Input */
+       SND_SOC_DAPM_MUX("Sidetone Mux", SND_SOC_NOPM, 0, 0,
+                        &da7218_sidetone_in_sel_mux),
+       SND_SOC_DAPM_ADC("Sidetone Filter", NULL, DA7218_SIDETONE_CTRL,
+                        DA7218_SIDETONE_FILTER_EN_SHIFT, DA7218_NO_INVERT),
+
+       /* Input Mixers */
+       SND_SOC_DAPM_MIXER("Mixer DAI1L", SND_SOC_NOPM, 0, 0,
+                          da7218_out_dai1l_mix_controls,
+                          ARRAY_SIZE(da7218_out_dai1l_mix_controls)),
+       SND_SOC_DAPM_MIXER("Mixer DAI1R", SND_SOC_NOPM, 0, 0,
+                          da7218_out_dai1r_mix_controls,
+                          ARRAY_SIZE(da7218_out_dai1r_mix_controls)),
+       SND_SOC_DAPM_MIXER("Mixer DAI2L", SND_SOC_NOPM, 0, 0,
+                          da7218_out_dai2l_mix_controls,
+                          ARRAY_SIZE(da7218_out_dai2l_mix_controls)),
+       SND_SOC_DAPM_MIXER("Mixer DAI2R", SND_SOC_NOPM, 0, 0,
+                          da7218_out_dai2r_mix_controls,
+                          ARRAY_SIZE(da7218_out_dai2r_mix_controls)),
+
+       /* DAI Supply */
+       SND_SOC_DAPM_SUPPLY("DAI", DA7218_DAI_CTRL, DA7218_DAI_EN_SHIFT,
+                           DA7218_NO_INVERT, da7218_dai_event,
+                           SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+
+       /* DAI */
+       SND_SOC_DAPM_AIF_OUT("DAIOUT", "Capture", 0, SND_SOC_NOPM, 0, 0),
+       SND_SOC_DAPM_AIF_IN("DAIIN", "Playback", 0, SND_SOC_NOPM, 0, 0),
+
+       /* Output Mixers */
+       SND_SOC_DAPM_MIXER("Mixer Out FilterL", SND_SOC_NOPM, 0, 0,
+                          da7218_out_filtl_mix_controls,
+                          ARRAY_SIZE(da7218_out_filtl_mix_controls)),
+       SND_SOC_DAPM_MIXER("Mixer Out FilterR", SND_SOC_NOPM, 0, 0,
+                          da7218_out_filtr_mix_controls,
+                          ARRAY_SIZE(da7218_out_filtr_mix_controls)),
+
+       /* BiQuad Filters */
+       SND_SOC_DAPM_MUX("Out FilterL BiQuad Mux", SND_SOC_NOPM, 0, 0,
+                        &da7218_out_filtl_biq_sel_mux),
+       SND_SOC_DAPM_MUX("Out FilterR BiQuad Mux", SND_SOC_NOPM, 0, 0,
+                        &da7218_out_filtr_biq_sel_mux),
+       SND_SOC_DAPM_DAC("BiQuad Filter", NULL, DA7218_OUT_1_BIQ_5STAGE_CTRL,
+                        DA7218_OUT_1_BIQ_5STAGE_FILTER_EN_SHIFT,
+                        DA7218_NO_INVERT),
+
+       /* Sidetone Mixers */
+       SND_SOC_DAPM_MIXER("ST Mixer Out FilterL", SND_SOC_NOPM, 0, 0,
+                          da7218_st_out_filtl_mix_controls,
+                          ARRAY_SIZE(da7218_st_out_filtl_mix_controls)),
+       SND_SOC_DAPM_MIXER("ST Mixer Out FilterR", SND_SOC_NOPM, 0, 0,
+                          da7218_st_out_filtr_mix_controls,
+                          ARRAY_SIZE(da7218_st_out_filtr_mix_controls)),
+
+       /* Output Filters */
+       SND_SOC_DAPM_DAC("Out FilterL", NULL, DA7218_OUT_1L_FILTER_CTRL,
+                        DA7218_OUT_1L_FILTER_EN_SHIFT, DA7218_NO_INVERT),
+       SND_SOC_DAPM_DAC("Out FilterR", NULL, DA7218_OUT_1R_FILTER_CTRL,
+                        DA7218_IN_1R_FILTER_EN_SHIFT, DA7218_NO_INVERT),
+
+       /* Output PGAs */
+       SND_SOC_DAPM_PGA("Mixout Left PGA", DA7218_MIXOUT_L_CTRL,
+                        DA7218_MIXOUT_L_AMP_EN_SHIFT, DA7218_NO_INVERT,
+                        NULL, 0),
+       SND_SOC_DAPM_PGA("Mixout Right PGA", DA7218_MIXOUT_R_CTRL,
+                        DA7218_MIXOUT_R_AMP_EN_SHIFT, DA7218_NO_INVERT,
+                        NULL, 0),
+       SND_SOC_DAPM_PGA_E("Headphone Left PGA", DA7218_HP_L_CTRL,
+                          DA7218_HP_L_AMP_EN_SHIFT, DA7218_NO_INVERT, NULL, 0,
+                          da7218_hp_pga_event,
+                          SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
+       SND_SOC_DAPM_PGA_E("Headphone Right PGA", DA7218_HP_R_CTRL,
+                          DA7218_HP_R_AMP_EN_SHIFT, DA7218_NO_INVERT, NULL, 0,
+                          da7218_hp_pga_event,
+                          SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
+
+       /* Output Supplies */
+       SND_SOC_DAPM_SUPPLY("Charge Pump", SND_SOC_NOPM, 0, 0, da7218_cp_event,
+                           SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_PRE_PMD),
+
+       /* Outputs */
+       SND_SOC_DAPM_OUTPUT("HPL"),
+       SND_SOC_DAPM_OUTPUT("HPR"),
+};
+
+
+/*
+ * DAPM Mixer Routes
+ */
+
+#define DA7218_DMIX_ROUTES(name)                               \
+       {name, "In Filter1L Switch", "In Filter1L"},            \
+       {name, "In Filter1R Switch", "In Filter1R"},            \
+       {name, "In Filter2L Switch", "In Filter2L"},            \
+       {name, "In Filter2R Switch", "In Filter2R"},            \
+       {name, "ToneGen Switch", "Tone Generator"},             \
+       {name, "DAIL Switch", "DAIIN"},                         \
+       {name, "DAIR Switch", "DAIIN"}
+
+#define DA7218_DMIX_ST_ROUTES(name)                            \
+       {name, "Out FilterL Switch", "Out FilterL BiQuad Mux"}, \
+       {name, "Out FilterR Switch", "Out FilterR BiQuad Mux"}, \
+       {name, "Sidetone Switch", "Sidetone Filter"}
+
+
+/*
+ * DAPM audio route definition
+ */
+
+static const struct snd_soc_dapm_route da7218_audio_map[] = {
+       /* Input paths */
+       {"MIC1", NULL, "Mic Bias1"},
+       {"MIC2", NULL, "Mic Bias2"},
+       {"DMIC1L", NULL, "Mic Bias1"},
+       {"DMIC1L", NULL, "DMic1 Left"},
+       {"DMIC1R", NULL, "Mic Bias1"},
+       {"DMIC1R", NULL, "DMic1 Right"},
+       {"DMIC2L", NULL, "Mic Bias2"},
+       {"DMIC2L", NULL, "DMic2 Left"},
+       {"DMIC2R", NULL, "Mic Bias2"},
+       {"DMIC2R", NULL, "DMic2 Right"},
+
+       {"Mic1 PGA", NULL, "MIC1"},
+       {"Mic2 PGA", NULL, "MIC2"},
+
+       {"Mixin1 PGA", NULL, "Mixin1 Supply"},
+       {"Mixin2 PGA", NULL, "Mixin2 Supply"},
+
+       {"Mixin1 PGA", NULL, "Mic1 PGA"},
+       {"Mixin2 PGA", NULL, "Mic2 PGA"},
+
+       {"Mic1 Mux", "Analog", "Mixin1 PGA"},
+       {"Mic1 Mux", "Digital", "DMIC1L"},
+       {"Mic1 Mux", "Digital", "DMIC1R"},
+       {"Mic2 Mux", "Analog", "Mixin2 PGA"},
+       {"Mic2 Mux", "Digital", "DMIC2L"},
+       {"Mic2 Mux", "Digital", "DMIC2R"},
+
+       {"In Filter1L", NULL, "Mic1 Mux"},
+       {"In Filter1R", NULL, "Mic1 Mux"},
+       {"In Filter2L", NULL, "Mic2 Mux"},
+       {"In Filter2R", NULL, "Mic2 Mux"},
+
+       {"Tone Generator", NULL, "TONE"},
+
+       {"Sidetone Mux", "In Filter1L", "In Filter1L"},
+       {"Sidetone Mux", "In Filter1R", "In Filter1R"},
+       {"Sidetone Mux", "In Filter2L", "In Filter2L"},
+       {"Sidetone Mux", "In Filter2R", "In Filter2R"},
+       {"Sidetone Filter", NULL, "Sidetone Mux"},
+
+       DA7218_DMIX_ROUTES("Mixer DAI1L"),
+       DA7218_DMIX_ROUTES("Mixer DAI1R"),
+       DA7218_DMIX_ROUTES("Mixer DAI2L"),
+       DA7218_DMIX_ROUTES("Mixer DAI2R"),
+
+       {"DAIOUT", NULL, "Mixer DAI1L"},
+       {"DAIOUT", NULL, "Mixer DAI1R"},
+       {"DAIOUT", NULL, "Mixer DAI2L"},
+       {"DAIOUT", NULL, "Mixer DAI2R"},
+
+       {"DAIOUT", NULL, "DAI"},
+
+       /* Output paths */
+       {"DAIIN", NULL, "DAI"},
+
+       DA7218_DMIX_ROUTES("Mixer Out FilterL"),
+       DA7218_DMIX_ROUTES("Mixer Out FilterR"),
+
+       {"BiQuad Filter", NULL, "Mixer Out FilterL"},
+       {"BiQuad Filter", NULL, "Mixer Out FilterR"},
+
+       {"Out FilterL BiQuad Mux", "Bypass", "Mixer Out FilterL"},
+       {"Out FilterL BiQuad Mux", "Enabled", "BiQuad Filter"},
+       {"Out FilterR BiQuad Mux", "Bypass", "Mixer Out FilterR"},
+       {"Out FilterR BiQuad Mux", "Enabled", "BiQuad Filter"},
+
+       DA7218_DMIX_ST_ROUTES("ST Mixer Out FilterL"),
+       DA7218_DMIX_ST_ROUTES("ST Mixer Out FilterR"),
+
+       {"Out FilterL", NULL, "ST Mixer Out FilterL"},
+       {"Out FilterR", NULL, "ST Mixer Out FilterR"},
+
+       {"Mixout Left PGA", NULL, "Out FilterL"},
+       {"Mixout Right PGA", NULL, "Out FilterR"},
+
+       {"Headphone Left PGA", NULL, "Mixout Left PGA"},
+       {"Headphone Right PGA", NULL, "Mixout Right PGA"},
+
+       {"HPL", NULL, "Headphone Left PGA"},
+       {"HPR", NULL, "Headphone Right PGA"},
+
+       {"HPL", NULL, "Charge Pump"},
+       {"HPR", NULL, "Charge Pump"},
+};
+
+
+/*
+ * DAI operations
+ */
+
+static int da7218_set_dai_sysclk(struct snd_soc_dai *codec_dai,
+                                int clk_id, unsigned int freq, int dir)
+{
+       struct snd_soc_codec *codec = codec_dai->codec;
+       struct da7218_priv *da7218 = snd_soc_codec_get_drvdata(codec);
+       int ret;
+
+       if (da7218->mclk_rate == freq)
+               return 0;
+
+       if (((freq < 2000000) && (freq != 32768)) || (freq > 54000000)) {
+               dev_err(codec_dai->dev, "Unsupported MCLK value %d\n",
+                       freq);
+               return -EINVAL;
+       }
+
+       switch (clk_id) {
+       case DA7218_CLKSRC_MCLK_SQR:
+               snd_soc_update_bits(codec, DA7218_PLL_CTRL,
+                                   DA7218_PLL_MCLK_SQR_EN_MASK,
+                                   DA7218_PLL_MCLK_SQR_EN_MASK);
+               break;
+       case DA7218_CLKSRC_MCLK:
+               snd_soc_update_bits(codec, DA7218_PLL_CTRL,
+                                   DA7218_PLL_MCLK_SQR_EN_MASK, 0);
+               break;
+       default:
+               dev_err(codec_dai->dev, "Unknown clock source %d\n", clk_id);
+               return -EINVAL;
+       }
+
+       if (da7218->mclk) {
+               freq = clk_round_rate(da7218->mclk, freq);
+               ret = clk_set_rate(da7218->mclk, freq);
+               if (ret) {
+                       dev_err(codec_dai->dev, "Failed to set clock rate %d\n",
+                               freq);
+                       return ret;
+               }
+       }
+
+       da7218->mclk_rate = freq;
+
+       return 0;
+}
+
+static int da7218_set_dai_pll(struct snd_soc_dai *codec_dai, int pll_id,
+                             int source, unsigned int fref, unsigned int fout)
+{
+       struct snd_soc_codec *codec = codec_dai->codec;
+       struct da7218_priv *da7218 = snd_soc_codec_get_drvdata(codec);
+
+       u8 pll_ctrl, indiv_bits, indiv;
+       u8 pll_frac_top, pll_frac_bot, pll_integer;
+       u32 freq_ref;
+       u64 frac_div;
+
+       /* Verify 32KHz, 2MHz - 54MHz MCLK provided, and set input divider */
+       if (da7218->mclk_rate == 32768) {
+               indiv_bits = DA7218_PLL_INDIV_2_5_MHZ;
+               indiv = DA7218_PLL_INDIV_2_10_MHZ_VAL;
+       } else if (da7218->mclk_rate < 2000000) {
+               dev_err(codec->dev, "PLL input clock %d below valid range\n",
+                       da7218->mclk_rate);
+               return -EINVAL;
+       } else if (da7218->mclk_rate <= 5000000) {
+               indiv_bits = DA7218_PLL_INDIV_2_5_MHZ;
+               indiv = DA7218_PLL_INDIV_2_10_MHZ_VAL;
+       } else if (da7218->mclk_rate <= 10000000) {
+               indiv_bits = DA7218_PLL_INDIV_5_10_MHZ;
+               indiv = DA7218_PLL_INDIV_2_10_MHZ_VAL;
+       } else if (da7218->mclk_rate <= 20000000) {
+               indiv_bits = DA7218_PLL_INDIV_10_20_MHZ;
+               indiv = DA7218_PLL_INDIV_10_20_MHZ_VAL;
+       } else if (da7218->mclk_rate <= 40000000) {
+               indiv_bits = DA7218_PLL_INDIV_20_40_MHZ;
+               indiv = DA7218_PLL_INDIV_20_40_MHZ_VAL;
+       } else if (da7218->mclk_rate <= 54000000) {
+               indiv_bits = DA7218_PLL_INDIV_40_54_MHZ;
+               indiv = DA7218_PLL_INDIV_40_54_MHZ_VAL;
+       } else {
+               dev_err(codec->dev, "PLL input clock %d above valid range\n",
+                       da7218->mclk_rate);
+               return -EINVAL;
+       }
+       freq_ref = (da7218->mclk_rate / indiv);
+       pll_ctrl = indiv_bits;
+
+       /* Configure PLL */
+       switch (source) {
+       case DA7218_SYSCLK_MCLK:
+               pll_ctrl |= DA7218_PLL_MODE_BYPASS;
+               snd_soc_update_bits(codec, DA7218_PLL_CTRL,
+                                   DA7218_PLL_INDIV_MASK |
+                                   DA7218_PLL_MODE_MASK, pll_ctrl);
+               return 0;
+       case DA7218_SYSCLK_PLL:
+               pll_ctrl |= DA7218_PLL_MODE_NORMAL;
+               break;
+       case DA7218_SYSCLK_PLL_SRM:
+               pll_ctrl |= DA7218_PLL_MODE_SRM;
+               break;
+       case DA7218_SYSCLK_PLL_32KHZ:
+               pll_ctrl |= DA7218_PLL_MODE_32KHZ;
+               break;
+       default:
+               dev_err(codec->dev, "Invalid PLL config\n");
+               return -EINVAL;
+       }
+
+       /* Calculate dividers for PLL */
+       pll_integer = fout / freq_ref;
+       frac_div = (u64)(fout % freq_ref) * 8192ULL;
+       do_div(frac_div, freq_ref);
+       pll_frac_top = (frac_div >> DA7218_BYTE_SHIFT) & DA7218_BYTE_MASK;
+       pll_frac_bot = (frac_div) & DA7218_BYTE_MASK;
+
+       /* Write PLL config & dividers */
+       snd_soc_write(codec, DA7218_PLL_FRAC_TOP, pll_frac_top);
+       snd_soc_write(codec, DA7218_PLL_FRAC_BOT, pll_frac_bot);
+       snd_soc_write(codec, DA7218_PLL_INTEGER, pll_integer);
+       snd_soc_update_bits(codec, DA7218_PLL_CTRL,
+                           DA7218_PLL_MODE_MASK | DA7218_PLL_INDIV_MASK,
+                           pll_ctrl);
+
+       return 0;
+}
+
+static int da7218_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt)
+{
+       struct snd_soc_codec *codec = codec_dai->codec;
+       struct da7218_priv *da7218 = snd_soc_codec_get_drvdata(codec);
+       u8 dai_clk_mode = 0, dai_ctrl = 0;
+
+       switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+       case SND_SOC_DAIFMT_CBM_CFM:
+               da7218->master = true;
+               break;
+       case SND_SOC_DAIFMT_CBS_CFS:
+               da7218->master = false;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+       case SND_SOC_DAIFMT_I2S:
+       case SND_SOC_DAIFMT_LEFT_J:
+       case SND_SOC_DAIFMT_RIGHT_J:
+               switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+               case SND_SOC_DAIFMT_NB_NF:
+                       break;
+               case SND_SOC_DAIFMT_NB_IF:
+                       dai_clk_mode |= DA7218_DAI_WCLK_POL_INV;
+                       break;
+               case SND_SOC_DAIFMT_IB_NF:
+                       dai_clk_mode |= DA7218_DAI_CLK_POL_INV;
+                       break;
+               case SND_SOC_DAIFMT_IB_IF:
+                       dai_clk_mode |= DA7218_DAI_WCLK_POL_INV |
+                                       DA7218_DAI_CLK_POL_INV;
+                       break;
+               default:
+                       return -EINVAL;
+               }
+               break;
+       case SND_SOC_DAIFMT_DSP_B:
+               switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+               case SND_SOC_DAIFMT_NB_NF:
+                       dai_clk_mode |= DA7218_DAI_CLK_POL_INV;
+                       break;
+               case SND_SOC_DAIFMT_NB_IF:
+                       dai_clk_mode |= DA7218_DAI_WCLK_POL_INV |
+                                       DA7218_DAI_CLK_POL_INV;
+                       break;
+               case SND_SOC_DAIFMT_IB_NF:
+                       break;
+               case SND_SOC_DAIFMT_IB_IF:
+                       dai_clk_mode |= DA7218_DAI_WCLK_POL_INV;
+                       break;
+               default:
+                       return -EINVAL;
+               }
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+       case SND_SOC_DAIFMT_I2S:
+               dai_ctrl |= DA7218_DAI_FORMAT_I2S;
+               break;
+       case SND_SOC_DAIFMT_LEFT_J:
+               dai_ctrl |= DA7218_DAI_FORMAT_LEFT_J;
+               break;
+       case SND_SOC_DAIFMT_RIGHT_J:
+               dai_ctrl |= DA7218_DAI_FORMAT_RIGHT_J;
+               break;
+       case SND_SOC_DAIFMT_DSP_B:
+               dai_ctrl |= DA7218_DAI_FORMAT_DSP;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       /* By default 64 BCLKs per WCLK is supported */
+       dai_clk_mode |= DA7218_DAI_BCLKS_PER_WCLK_64;
+
+       snd_soc_write(codec, DA7218_DAI_CLK_MODE, dai_clk_mode);
+       snd_soc_update_bits(codec, DA7218_DAI_CTRL, DA7218_DAI_FORMAT_MASK,
+                           dai_ctrl);
+
+       return 0;
+}
+
+static int da7218_set_dai_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;
+       u8 dai_bclks_per_wclk;
+       u32 frame_size;
+
+       /* No channels enabled so disable TDM, revert to 64-bit frames */
+       if (!tx_mask) {
+               snd_soc_update_bits(codec, DA7218_DAI_TDM_CTRL,
+                                   DA7218_DAI_TDM_CH_EN_MASK |
+                                   DA7218_DAI_TDM_MODE_EN_MASK, 0);
+               snd_soc_update_bits(codec, DA7218_DAI_CLK_MODE,
+                                   DA7218_DAI_BCLKS_PER_WCLK_MASK,
+                                   DA7218_DAI_BCLKS_PER_WCLK_64);
+               return 0;
+       }
+
+       /* Check we have valid slots */
+       if (fls(tx_mask) > DA7218_DAI_TDM_MAX_SLOTS) {
+               dev_err(codec->dev, "Invalid number of slots, max = %d\n",
+                       DA7218_DAI_TDM_MAX_SLOTS);
+               return -EINVAL;
+       }
+
+       /* Check we have a valid offset given (first 2 bytes of rx_mask) */
+       if (rx_mask >> DA7218_2BYTE_SHIFT) {
+               dev_err(codec->dev, "Invalid slot offset, max = %d\n",
+                       DA7218_2BYTE_MASK);
+               return -EINVAL;
+       }
+
+       /* Calculate & validate frame size based on slot info provided. */
+       frame_size = slots * slot_width;
+       switch (frame_size) {
+       case 32:
+               dai_bclks_per_wclk = DA7218_DAI_BCLKS_PER_WCLK_32;
+               break;
+       case 64:
+               dai_bclks_per_wclk = DA7218_DAI_BCLKS_PER_WCLK_64;
+               break;
+       case 128:
+               dai_bclks_per_wclk = DA7218_DAI_BCLKS_PER_WCLK_128;
+               break;
+       case 256:
+               dai_bclks_per_wclk = DA7218_DAI_BCLKS_PER_WCLK_256;
+               break;
+       default:
+               dev_err(codec->dev, "Invalid frame size\n");
+               return -EINVAL;
+       }
+
+       snd_soc_update_bits(codec, DA7218_DAI_CLK_MODE,
+                           DA7218_DAI_BCLKS_PER_WCLK_MASK,
+                           dai_bclks_per_wclk);
+       snd_soc_write(codec, DA7218_DAI_OFFSET_LOWER,
+                     (rx_mask & DA7218_BYTE_MASK));
+       snd_soc_write(codec, DA7218_DAI_OFFSET_UPPER,
+                     ((rx_mask >> DA7218_BYTE_SHIFT) & DA7218_BYTE_MASK));
+       snd_soc_update_bits(codec, DA7218_DAI_TDM_CTRL,
+                           DA7218_DAI_TDM_CH_EN_MASK |
+                           DA7218_DAI_TDM_MODE_EN_MASK,
+                           (tx_mask << DA7218_DAI_TDM_CH_EN_SHIFT) |
+                           DA7218_DAI_TDM_MODE_EN_MASK);
+
+       return 0;
+}
+
+static int da7218_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;
+       u8 dai_ctrl = 0, fs;
+       unsigned int channels;
+
+       switch (params_width(params)) {
+       case 16:
+               dai_ctrl |= DA7218_DAI_WORD_LENGTH_S16_LE;
+               break;
+       case 20:
+               dai_ctrl |= DA7218_DAI_WORD_LENGTH_S20_LE;
+               break;
+       case 24:
+               dai_ctrl |= DA7218_DAI_WORD_LENGTH_S24_LE;
+               break;
+       case 32:
+               dai_ctrl |= DA7218_DAI_WORD_LENGTH_S32_LE;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       channels = params_channels(params);
+       if ((channels < 1) || (channels > DA7218_DAI_CH_NUM_MAX)) {
+               dev_err(codec->dev,
+                       "Invalid number of channels, only 1 to %d supported\n",
+                       DA7218_DAI_CH_NUM_MAX);
+               return -EINVAL;
+       }
+       dai_ctrl |= channels << DA7218_DAI_CH_NUM_SHIFT;
+
+       switch (params_rate(params)) {
+       case 8000:
+               fs = DA7218_SR_8000;
+               break;
+       case 11025:
+               fs = DA7218_SR_11025;
+               break;
+       case 12000:
+               fs = DA7218_SR_12000;
+               break;
+       case 16000:
+               fs = DA7218_SR_16000;
+               break;
+       case 22050:
+               fs = DA7218_SR_22050;
+               break;
+       case 24000:
+               fs = DA7218_SR_24000;
+               break;
+       case 32000:
+               fs = DA7218_SR_32000;
+               break;
+       case 44100:
+               fs = DA7218_SR_44100;
+               break;
+       case 48000:
+               fs = DA7218_SR_48000;
+               break;
+       case 88200:
+               fs = DA7218_SR_88200;
+               break;
+       case 96000:
+               fs = DA7218_SR_96000;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       snd_soc_update_bits(codec, DA7218_DAI_CTRL,
+                           DA7218_DAI_WORD_LENGTH_MASK | DA7218_DAI_CH_NUM_MASK,
+                           dai_ctrl);
+       /* SRs tied for ADCs and DACs. */
+       snd_soc_write(codec, DA7218_SR,
+                     (fs << DA7218_SR_DAC_SHIFT) | (fs << DA7218_SR_ADC_SHIFT));
+
+       return 0;
+}
+
+static const struct snd_soc_dai_ops da7218_dai_ops = {
+       .hw_params      = da7218_hw_params,
+       .set_sysclk     = da7218_set_dai_sysclk,
+       .set_pll        = da7218_set_dai_pll,
+       .set_fmt        = da7218_set_dai_fmt,
+       .set_tdm_slot   = da7218_set_dai_tdm_slot,
+};
+
+#define DA7218_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\
+                       SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE)
+
+static struct snd_soc_dai_driver da7218_dai = {
+       .name = "da7218-hifi",
+       .playback = {
+               .stream_name = "Playback",
+               .channels_min = 1,
+               .channels_max = 4,      /* Only 2 channels of data */
+               .rates = SNDRV_PCM_RATE_8000_96000,
+               .formats = DA7218_FORMATS,
+       },
+       .capture = {
+               .stream_name = "Capture",
+               .channels_min = 1,
+               .channels_max = 4,
+               .rates = SNDRV_PCM_RATE_8000_96000,
+               .formats = DA7218_FORMATS,
+       },
+       .ops = &da7218_dai_ops,
+       .symmetric_rates = 1,
+       .symmetric_channels = 1,
+       .symmetric_samplebits = 1,
+};
+
+
+/*
+ * HP Detect
+ */
+
+int da7218_hpldet(struct snd_soc_codec *codec, struct snd_soc_jack *jack)
+{
+       struct da7218_priv *da7218 = snd_soc_codec_get_drvdata(codec);
+
+       if (da7218->dev_id == DA7217_DEV_ID)
+               return -EINVAL;
+
+       da7218->jack = jack;
+       snd_soc_update_bits(codec, DA7218_HPLDET_JACK,
+                           DA7218_HPLDET_JACK_EN_MASK,
+                           jack ? DA7218_HPLDET_JACK_EN_MASK : 0);
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(da7218_hpldet);
+
+static void da7218_micldet_irq(struct snd_soc_codec *codec)
+{
+       char *envp[] = {
+               "EVENT=MIC_LEVEL_DETECT",
+               NULL,
+       };
+
+       kobject_uevent_env(&codec->dev->kobj, KOBJ_CHANGE, envp);
+}
+
+static void da7218_hpldet_irq(struct snd_soc_codec *codec)
+{
+       struct da7218_priv *da7218 = snd_soc_codec_get_drvdata(codec);
+       u8 jack_status;
+       int report;
+
+       jack_status = snd_soc_read(codec, DA7218_EVENT_STATUS);
+
+       if (jack_status & DA7218_HPLDET_JACK_STS_MASK)
+               report = SND_JACK_HEADPHONE;
+       else
+               report = 0;
+
+       snd_soc_jack_report(da7218->jack, report, SND_JACK_HEADPHONE);
+}
+
+/*
+ * IRQ
+ */
+
+static irqreturn_t da7218_irq_thread(int irq, void *data)
+{
+       struct snd_soc_codec *codec = data;
+       u8 status;
+
+       /* Read IRQ status reg */
+       status = snd_soc_read(codec, DA7218_EVENT);
+       if (!status)
+               return IRQ_NONE;
+
+       /* Mic level detect */
+       if (status & DA7218_LVL_DET_EVENT_MASK)
+               da7218_micldet_irq(codec);
+
+       /* HP detect */
+       if (status & DA7218_HPLDET_JACK_EVENT_MASK)
+               da7218_hpldet_irq(codec);
+
+       /* Clear interrupts */
+       snd_soc_write(codec, DA7218_EVENT, status);
+
+       return IRQ_HANDLED;
+}
+
+/*
+ * DT
+ */
+
+static const struct of_device_id da7218_of_match[] = {
+       { .compatible = "dlg,da7217", .data = (void *) DA7217_DEV_ID },
+       { .compatible = "dlg,da7218", .data = (void *) DA7218_DEV_ID },
+       { }
+};
+MODULE_DEVICE_TABLE(of, da7218_of_match);
+
+static inline int da7218_of_get_id(struct device *dev)
+{
+       const struct of_device_id *id = of_match_device(da7218_of_match, dev);
+
+       if (id)
+               return (uintptr_t)id->data;
+       else
+               return -EINVAL;
+}
+
+static enum da7218_micbias_voltage
+       da7218_of_micbias_lvl(struct snd_soc_codec *codec, u32 val)
+{
+       switch (val) {
+       case 1200:
+               return DA7218_MICBIAS_1_2V;
+       case 1600:
+               return DA7218_MICBIAS_1_6V;
+       case 1800:
+               return DA7218_MICBIAS_1_8V;
+       case 2000:
+               return DA7218_MICBIAS_2_0V;
+       case 2200:
+               return DA7218_MICBIAS_2_2V;
+       case 2400:
+               return DA7218_MICBIAS_2_4V;
+       case 2600:
+               return DA7218_MICBIAS_2_6V;
+       case 2800:
+               return DA7218_MICBIAS_2_8V;
+       case 3000:
+               return DA7218_MICBIAS_3_0V;
+       default:
+               dev_warn(codec->dev, "Invalid micbias level");
+               return DA7218_MICBIAS_1_6V;
+       }
+}
+
+static enum da7218_mic_amp_in_sel
+       da7218_of_mic_amp_in_sel(struct snd_soc_codec *codec, const char *str)
+{
+       if (!strcmp(str, "diff")) {
+               return DA7218_MIC_AMP_IN_SEL_DIFF;
+       } else if (!strcmp(str, "se_p")) {
+               return DA7218_MIC_AMP_IN_SEL_SE_P;
+       } else if (!strcmp(str, "se_n")) {
+               return DA7218_MIC_AMP_IN_SEL_SE_N;
+       } else {
+               dev_warn(codec->dev, "Invalid mic input type selection");
+               return DA7218_MIC_AMP_IN_SEL_DIFF;
+       }
+}
+
+static enum da7218_dmic_data_sel
+       da7218_of_dmic_data_sel(struct snd_soc_codec *codec, const char *str)
+{
+       if (!strcmp(str, "lrise_rfall")) {
+               return DA7218_DMIC_DATA_LRISE_RFALL;
+       } else if (!strcmp(str, "lfall_rrise")) {
+               return DA7218_DMIC_DATA_LFALL_RRISE;
+       } else {
+               dev_warn(codec->dev, "Invalid DMIC data type selection");
+               return DA7218_DMIC_DATA_LRISE_RFALL;
+       }
+}
+
+static enum da7218_dmic_samplephase
+       da7218_of_dmic_samplephase(struct snd_soc_codec *codec, const char *str)
+{
+       if (!strcmp(str, "on_clkedge")) {
+               return DA7218_DMIC_SAMPLE_ON_CLKEDGE;
+       } else if (!strcmp(str, "between_clkedge")) {
+               return DA7218_DMIC_SAMPLE_BETWEEN_CLKEDGE;
+       } else {
+               dev_warn(codec->dev, "Invalid DMIC sample phase");
+               return DA7218_DMIC_SAMPLE_ON_CLKEDGE;
+       }
+}
+
+static enum da7218_dmic_clk_rate
+       da7218_of_dmic_clkrate(struct snd_soc_codec *codec, u32 val)
+{
+       switch (val) {
+       case 1500000:
+               return DA7218_DMIC_CLK_1_5MHZ;
+       case 3000000:
+               return DA7218_DMIC_CLK_3_0MHZ;
+       default:
+               dev_warn(codec->dev, "Invalid DMIC clock rate");
+               return DA7218_DMIC_CLK_3_0MHZ;
+       }
+}
+
+static enum da7218_hpldet_jack_rate
+       da7218_of_jack_rate(struct snd_soc_codec *codec, u32 val)
+{
+       switch (val) {
+       case 5:
+               return DA7218_HPLDET_JACK_RATE_5US;
+       case 10:
+               return DA7218_HPLDET_JACK_RATE_10US;
+       case 20:
+               return DA7218_HPLDET_JACK_RATE_20US;
+       case 40:
+               return DA7218_HPLDET_JACK_RATE_40US;
+       case 80:
+               return DA7218_HPLDET_JACK_RATE_80US;
+       case 160:
+               return DA7218_HPLDET_JACK_RATE_160US;
+       case 320:
+               return DA7218_HPLDET_JACK_RATE_320US;
+       case 640:
+               return DA7218_HPLDET_JACK_RATE_640US;
+       default:
+               dev_warn(codec->dev, "Invalid jack detect rate");
+               return DA7218_HPLDET_JACK_RATE_40US;
+       }
+}
+
+static enum da7218_hpldet_jack_debounce
+       da7218_of_jack_debounce(struct snd_soc_codec *codec, u32 val)
+{
+       switch (val) {
+       case 0:
+               return DA7218_HPLDET_JACK_DEBOUNCE_OFF;
+       case 2:
+               return DA7218_HPLDET_JACK_DEBOUNCE_2;
+       case 3:
+               return DA7218_HPLDET_JACK_DEBOUNCE_3;
+       case 4:
+               return DA7218_HPLDET_JACK_DEBOUNCE_4;
+       default:
+               dev_warn(codec->dev, "Invalid jack debounce");
+               return DA7218_HPLDET_JACK_DEBOUNCE_2;
+       }
+}
+
+static enum da7218_hpldet_jack_thr
+       da7218_of_jack_thr(struct snd_soc_codec *codec, u32 val)
+{
+       switch (val) {
+       case 84:
+               return DA7218_HPLDET_JACK_THR_84PCT;
+       case 88:
+               return DA7218_HPLDET_JACK_THR_88PCT;
+       case 92:
+               return DA7218_HPLDET_JACK_THR_92PCT;
+       case 96:
+               return DA7218_HPLDET_JACK_THR_96PCT;
+       default:
+               dev_warn(codec->dev, "Invalid jack threshold level");
+               return DA7218_HPLDET_JACK_THR_84PCT;
+       }
+}
+
+static struct da7218_pdata *da7218_of_to_pdata(struct snd_soc_codec *codec)
+{
+       struct da7218_priv *da7218 = snd_soc_codec_get_drvdata(codec);
+       struct device_node *np = codec->dev->of_node;
+       struct device_node *hpldet_np;
+       struct da7218_pdata *pdata;
+       struct da7218_hpldet_pdata *hpldet_pdata;
+       const char *of_str;
+       u32 of_val32;
+
+       pdata = devm_kzalloc(codec->dev, sizeof(*pdata), GFP_KERNEL);
+       if (!pdata) {
+               dev_warn(codec->dev, "Failed to allocate memory for pdata\n");
+               return NULL;
+       }
+
+       if (of_property_read_u32(np, "dlg,micbias1-lvl-millivolt", &of_val32) >= 0)
+               pdata->micbias1_lvl = da7218_of_micbias_lvl(codec, of_val32);
+       else
+               pdata->micbias1_lvl = DA7218_MICBIAS_1_6V;
+
+       if (of_property_read_u32(np, "dlg,micbias2-lvl-millivolt", &of_val32) >= 0)
+               pdata->micbias2_lvl = da7218_of_micbias_lvl(codec, of_val32);
+       else
+               pdata->micbias2_lvl = DA7218_MICBIAS_1_6V;
+
+       if (!of_property_read_string(np, "dlg,mic1-amp-in-sel", &of_str))
+               pdata->mic1_amp_in_sel =
+                       da7218_of_mic_amp_in_sel(codec, of_str);
+       else
+               pdata->mic1_amp_in_sel = DA7218_MIC_AMP_IN_SEL_DIFF;
+
+       if (!of_property_read_string(np, "dlg,mic2-amp-in-sel", &of_str))
+               pdata->mic2_amp_in_sel =
+                       da7218_of_mic_amp_in_sel(codec, of_str);
+       else
+               pdata->mic2_amp_in_sel = DA7218_MIC_AMP_IN_SEL_DIFF;
+
+       if (!of_property_read_string(np, "dlg,dmic1-data-sel", &of_str))
+               pdata->dmic1_data_sel = da7218_of_dmic_data_sel(codec, of_str);
+       else
+               pdata->dmic1_data_sel = DA7218_DMIC_DATA_LRISE_RFALL;
+
+       if (!of_property_read_string(np, "dlg,dmic1-samplephase", &of_str))
+               pdata->dmic1_samplephase =
+                       da7218_of_dmic_samplephase(codec, of_str);
+       else
+               pdata->dmic1_samplephase = DA7218_DMIC_SAMPLE_ON_CLKEDGE;
+
+       if (of_property_read_u32(np, "dlg,dmic1-clkrate-hz", &of_val32) >= 0)
+               pdata->dmic1_clk_rate = da7218_of_dmic_clkrate(codec, of_val32);
+       else
+               pdata->dmic1_clk_rate = DA7218_DMIC_CLK_3_0MHZ;
+
+       if (!of_property_read_string(np, "dlg,dmic2-data-sel", &of_str))
+               pdata->dmic2_data_sel = da7218_of_dmic_data_sel(codec, of_str);
+       else
+               pdata->dmic2_data_sel = DA7218_DMIC_DATA_LRISE_RFALL;
+
+       if (!of_property_read_string(np, "dlg,dmic2-samplephase", &of_str))
+               pdata->dmic2_samplephase =
+                       da7218_of_dmic_samplephase(codec, of_str);
+       else
+               pdata->dmic2_samplephase = DA7218_DMIC_SAMPLE_ON_CLKEDGE;
+
+       if (of_property_read_u32(np, "dlg,dmic2-clkrate-hz", &of_val32) >= 0)
+               pdata->dmic2_clk_rate = da7218_of_dmic_clkrate(codec, of_val32);
+       else
+               pdata->dmic2_clk_rate = DA7218_DMIC_CLK_3_0MHZ;
+
+       if (da7218->dev_id == DA7217_DEV_ID) {
+               if (of_property_read_bool(np, "dlg,hp-diff-single-supply"))
+                       pdata->hp_diff_single_supply = true;
+       }
+
+       if (da7218->dev_id == DA7218_DEV_ID) {
+               hpldet_np = of_find_node_by_name(np, "da7218_hpldet");
+               if (!hpldet_np)
+                       return pdata;
+
+               hpldet_pdata = devm_kzalloc(codec->dev, sizeof(*hpldet_pdata),
+                                           GFP_KERNEL);
+               if (!hpldet_pdata) {
+                       dev_warn(codec->dev,
+                                "Failed to allocate memory for hpldet pdata\n");
+                       of_node_put(hpldet_np);
+                       return pdata;
+               }
+               pdata->hpldet_pdata = hpldet_pdata;
+
+               if (of_property_read_u32(hpldet_np, "dlg,jack-rate-us",
+                                        &of_val32) >= 0)
+                       hpldet_pdata->jack_rate =
+                               da7218_of_jack_rate(codec, of_val32);
+               else
+                       hpldet_pdata->jack_rate = DA7218_HPLDET_JACK_RATE_40US;
+
+               if (of_property_read_u32(hpldet_np, "dlg,jack-debounce",
+                                        &of_val32) >= 0)
+                       hpldet_pdata->jack_debounce =
+                               da7218_of_jack_debounce(codec, of_val32);
+               else
+                       hpldet_pdata->jack_debounce =
+                               DA7218_HPLDET_JACK_DEBOUNCE_2;
+
+               if (of_property_read_u32(hpldet_np, "dlg,jack-threshold-pct",
+                                        &of_val32) >= 0)
+                       hpldet_pdata->jack_thr =
+                               da7218_of_jack_thr(codec, of_val32);
+               else
+                       hpldet_pdata->jack_thr = DA7218_HPLDET_JACK_THR_84PCT;
+
+               if (of_property_read_bool(hpldet_np, "dlg,comp-inv"))
+                       hpldet_pdata->comp_inv = true;
+
+               if (of_property_read_bool(hpldet_np, "dlg,hyst"))
+                       hpldet_pdata->hyst = true;
+
+               if (of_property_read_bool(hpldet_np, "dlg,discharge"))
+                       hpldet_pdata->discharge = true;
+
+               of_node_put(hpldet_np);
+       }
+
+       return pdata;
+}
+
+
+/*
+ * Codec driver functions
+ */
+
+static int da7218_set_bias_level(struct snd_soc_codec *codec,
+                                enum snd_soc_bias_level level)
+{
+       struct da7218_priv *da7218 = snd_soc_codec_get_drvdata(codec);
+       int ret;
+
+       switch (level) {
+       case SND_SOC_BIAS_ON:
+       case SND_SOC_BIAS_PREPARE:
+               break;
+       case SND_SOC_BIAS_STANDBY:
+               if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_OFF) {
+                       /* MCLK */
+                       if (da7218->mclk) {
+                               ret = clk_prepare_enable(da7218->mclk);
+                               if (ret) {
+                                       dev_err(codec->dev,
+                                               "Failed to enable mclk\n");
+                                       return ret;
+                               }
+                       }
+
+                       /* Master bias */
+                       snd_soc_update_bits(codec, DA7218_REFERENCES,
+                                           DA7218_BIAS_EN_MASK,
+                                           DA7218_BIAS_EN_MASK);
+
+                       /* Internal LDO */
+                       snd_soc_update_bits(codec, DA7218_LDO_CTRL,
+                                           DA7218_LDO_EN_MASK,
+                                           DA7218_LDO_EN_MASK);
+               }
+               break;
+       case SND_SOC_BIAS_OFF:
+               /* Only disable if jack detection disabled */
+               if (!da7218->jack) {
+                       /* Internal LDO */
+                       snd_soc_update_bits(codec, DA7218_LDO_CTRL,
+                                           DA7218_LDO_EN_MASK, 0);
+
+                       /* Master bias */
+                       snd_soc_update_bits(codec, DA7218_REFERENCES,
+                                           DA7218_BIAS_EN_MASK, 0);
+               }
+
+               /* MCLK */
+               if (da7218->mclk)
+                       clk_disable_unprepare(da7218->mclk);
+               break;
+       }
+
+       return 0;
+}
+
+static const char *da7218_supply_names[DA7218_NUM_SUPPLIES] = {
+       [DA7218_SUPPLY_VDD] = "VDD",
+       [DA7218_SUPPLY_VDDMIC] = "VDDMIC",
+       [DA7218_SUPPLY_VDDIO] = "VDDIO",
+};
+
+static int da7218_handle_supplies(struct snd_soc_codec *codec)
+{
+       struct da7218_priv *da7218 = snd_soc_codec_get_drvdata(codec);
+       struct regulator *vddio;
+       u8 io_voltage_lvl = DA7218_IO_VOLTAGE_LEVEL_2_5V_3_6V;
+       int i, ret;
+
+       /* Get required supplies */
+       for (i = 0; i < DA7218_NUM_SUPPLIES; ++i)
+               da7218->supplies[i].supply = da7218_supply_names[i];
+
+       ret = devm_regulator_bulk_get(codec->dev, DA7218_NUM_SUPPLIES,
+                                     da7218->supplies);
+       if (ret) {
+               dev_err(codec->dev, "Failed to get supplies\n");
+               return ret;
+       }
+
+       /* Determine VDDIO voltage provided */
+       vddio = da7218->supplies[DA7218_SUPPLY_VDDIO].consumer;
+       ret = regulator_get_voltage(vddio);
+       if (ret < 1500000)
+               dev_warn(codec->dev, "Invalid VDDIO voltage\n");
+       else if (ret < 2500000)
+               io_voltage_lvl = DA7218_IO_VOLTAGE_LEVEL_1_5V_2_5V;
+
+       /* Enable main supplies */
+       ret = regulator_bulk_enable(DA7218_NUM_SUPPLIES, da7218->supplies);
+       if (ret) {
+               dev_err(codec->dev, "Failed to enable supplies\n");
+               return ret;
+       }
+
+       /* Ensure device in active mode */
+       snd_soc_write(codec, DA7218_SYSTEM_ACTIVE, DA7218_SYSTEM_ACTIVE_MASK);
+
+       /* Update IO voltage level range */
+       snd_soc_write(codec, DA7218_IO_CTRL, io_voltage_lvl);
+
+       return 0;
+}
+
+static void da7218_handle_pdata(struct snd_soc_codec *codec)
+{
+       struct da7218_priv *da7218 = snd_soc_codec_get_drvdata(codec);
+       struct da7218_pdata *pdata = da7218->pdata;
+
+       if (pdata) {
+               u8 micbias_lvl = 0, dmic_cfg = 0;
+
+               /* Mic Bias voltages */
+               switch (pdata->micbias1_lvl) {
+               case DA7218_MICBIAS_1_2V:
+                       micbias_lvl |= DA7218_MICBIAS_1_LP_MODE_MASK;
+                       break;
+               case DA7218_MICBIAS_1_6V:
+               case DA7218_MICBIAS_1_8V:
+               case DA7218_MICBIAS_2_0V:
+               case DA7218_MICBIAS_2_2V:
+               case DA7218_MICBIAS_2_4V:
+               case DA7218_MICBIAS_2_6V:
+               case DA7218_MICBIAS_2_8V:
+               case DA7218_MICBIAS_3_0V:
+                       micbias_lvl |= (pdata->micbias1_lvl <<
+                                       DA7218_MICBIAS_1_LEVEL_SHIFT);
+                       break;
+               }
+
+               switch (pdata->micbias2_lvl) {
+               case DA7218_MICBIAS_1_2V:
+                       micbias_lvl |= DA7218_MICBIAS_2_LP_MODE_MASK;
+                       break;
+               case DA7218_MICBIAS_1_6V:
+               case DA7218_MICBIAS_1_8V:
+               case DA7218_MICBIAS_2_0V:
+               case DA7218_MICBIAS_2_2V:
+               case DA7218_MICBIAS_2_4V:
+               case DA7218_MICBIAS_2_6V:
+               case DA7218_MICBIAS_2_8V:
+               case DA7218_MICBIAS_3_0V:
+                       micbias_lvl |= (pdata->micbias2_lvl <<
+                                        DA7218_MICBIAS_2_LEVEL_SHIFT);
+                       break;
+               }
+
+               snd_soc_write(codec, DA7218_MICBIAS_CTRL, micbias_lvl);
+
+               /* Mic */
+               switch (pdata->mic1_amp_in_sel) {
+               case DA7218_MIC_AMP_IN_SEL_DIFF:
+               case DA7218_MIC_AMP_IN_SEL_SE_P:
+               case DA7218_MIC_AMP_IN_SEL_SE_N:
+                       snd_soc_write(codec, DA7218_MIC_1_SELECT,
+                                     pdata->mic1_amp_in_sel);
+                       break;
+               }
+
+               switch (pdata->mic2_amp_in_sel) {
+               case DA7218_MIC_AMP_IN_SEL_DIFF:
+               case DA7218_MIC_AMP_IN_SEL_SE_P:
+               case DA7218_MIC_AMP_IN_SEL_SE_N:
+                       snd_soc_write(codec, DA7218_MIC_2_SELECT,
+                                     pdata->mic2_amp_in_sel);
+                       break;
+               }
+
+               /* DMic */
+               switch (pdata->dmic1_data_sel) {
+               case DA7218_DMIC_DATA_LFALL_RRISE:
+               case DA7218_DMIC_DATA_LRISE_RFALL:
+                       dmic_cfg |= (pdata->dmic1_data_sel <<
+                                    DA7218_DMIC_1_DATA_SEL_SHIFT);
+                       break;
+               }
+
+               switch (pdata->dmic1_samplephase) {
+               case DA7218_DMIC_SAMPLE_ON_CLKEDGE:
+               case DA7218_DMIC_SAMPLE_BETWEEN_CLKEDGE:
+                       dmic_cfg |= (pdata->dmic1_samplephase <<
+                                    DA7218_DMIC_1_SAMPLEPHASE_SHIFT);
+                       break;
+               }
+
+               switch (pdata->dmic1_clk_rate) {
+               case DA7218_DMIC_CLK_3_0MHZ:
+               case DA7218_DMIC_CLK_1_5MHZ:
+                       dmic_cfg |= (pdata->dmic1_clk_rate <<
+                                    DA7218_DMIC_1_CLK_RATE_SHIFT);
+                       break;
+               }
+
+               snd_soc_update_bits(codec, DA7218_DMIC_1_CTRL,
+                                   DA7218_DMIC_1_DATA_SEL_MASK |
+                                   DA7218_DMIC_1_SAMPLEPHASE_MASK |
+                                   DA7218_DMIC_1_CLK_RATE_MASK, dmic_cfg);
+
+               dmic_cfg = 0;
+               switch (pdata->dmic2_data_sel) {
+               case DA7218_DMIC_DATA_LFALL_RRISE:
+               case DA7218_DMIC_DATA_LRISE_RFALL:
+                       dmic_cfg |= (pdata->dmic2_data_sel <<
+                                    DA7218_DMIC_2_DATA_SEL_SHIFT);
+                       break;
+               }
+
+               switch (pdata->dmic2_samplephase) {
+               case DA7218_DMIC_SAMPLE_ON_CLKEDGE:
+               case DA7218_DMIC_SAMPLE_BETWEEN_CLKEDGE:
+                       dmic_cfg |= (pdata->dmic2_samplephase <<
+                                    DA7218_DMIC_2_SAMPLEPHASE_SHIFT);
+                       break;
+               }
+
+               switch (pdata->dmic2_clk_rate) {
+               case DA7218_DMIC_CLK_3_0MHZ:
+               case DA7218_DMIC_CLK_1_5MHZ:
+                       dmic_cfg |= (pdata->dmic2_clk_rate <<
+                                    DA7218_DMIC_2_CLK_RATE_SHIFT);
+                       break;
+               }
+
+               snd_soc_update_bits(codec, DA7218_DMIC_2_CTRL,
+                                   DA7218_DMIC_2_DATA_SEL_MASK |
+                                   DA7218_DMIC_2_SAMPLEPHASE_MASK |
+                                   DA7218_DMIC_2_CLK_RATE_MASK, dmic_cfg);
+
+               /* DA7217 Specific */
+               if (da7218->dev_id == DA7217_DEV_ID) {
+                       da7218->hp_single_supply =
+                               pdata->hp_diff_single_supply;
+
+                       if (da7218->hp_single_supply) {
+                               snd_soc_write(codec, DA7218_HP_DIFF_UNLOCK,
+                                             DA7218_HP_DIFF_UNLOCK_VAL);
+                               snd_soc_update_bits(codec, DA7218_HP_DIFF_CTRL,
+                                                   DA7218_HP_AMP_SINGLE_SUPPLY_EN_MASK,
+                                                   DA7218_HP_AMP_SINGLE_SUPPLY_EN_MASK);
+                       }
+               }
+
+               /* DA7218 Specific */
+               if ((da7218->dev_id == DA7218_DEV_ID) &&
+                   (pdata->hpldet_pdata)) {
+                       struct da7218_hpldet_pdata *hpldet_pdata =
+                               pdata->hpldet_pdata;
+                       u8 hpldet_cfg = 0;
+
+                       switch (hpldet_pdata->jack_rate) {
+                       case DA7218_HPLDET_JACK_RATE_5US:
+                       case DA7218_HPLDET_JACK_RATE_10US:
+                       case DA7218_HPLDET_JACK_RATE_20US:
+                       case DA7218_HPLDET_JACK_RATE_40US:
+                       case DA7218_HPLDET_JACK_RATE_80US:
+                       case DA7218_HPLDET_JACK_RATE_160US:
+                       case DA7218_HPLDET_JACK_RATE_320US:
+                       case DA7218_HPLDET_JACK_RATE_640US:
+                               hpldet_cfg |=
+                                       (hpldet_pdata->jack_rate <<
+                                        DA7218_HPLDET_JACK_RATE_SHIFT);
+                               break;
+                       }
+
+                       switch (hpldet_pdata->jack_debounce) {
+                       case DA7218_HPLDET_JACK_DEBOUNCE_OFF:
+                       case DA7218_HPLDET_JACK_DEBOUNCE_2:
+                       case DA7218_HPLDET_JACK_DEBOUNCE_3:
+                       case DA7218_HPLDET_JACK_DEBOUNCE_4:
+                               hpldet_cfg |=
+                                       (hpldet_pdata->jack_debounce <<
+                                        DA7218_HPLDET_JACK_DEBOUNCE_SHIFT);
+                               break;
+                       }
+
+                       switch (hpldet_pdata->jack_thr) {
+                       case DA7218_HPLDET_JACK_THR_84PCT:
+                       case DA7218_HPLDET_JACK_THR_88PCT:
+                       case DA7218_HPLDET_JACK_THR_92PCT:
+                       case DA7218_HPLDET_JACK_THR_96PCT:
+                               hpldet_cfg |=
+                                       (hpldet_pdata->jack_thr <<
+                                        DA7218_HPLDET_JACK_THR_SHIFT);
+                               break;
+                       }
+                       snd_soc_update_bits(codec, DA7218_HPLDET_JACK,
+                                           DA7218_HPLDET_JACK_RATE_MASK |
+                                           DA7218_HPLDET_JACK_DEBOUNCE_MASK |
+                                           DA7218_HPLDET_JACK_THR_MASK,
+                                           hpldet_cfg);
+
+                       hpldet_cfg = 0;
+                       if (hpldet_pdata->comp_inv)
+                               hpldet_cfg |= DA7218_HPLDET_COMP_INV_MASK;
+
+                       if (hpldet_pdata->hyst)
+                               hpldet_cfg |= DA7218_HPLDET_HYST_EN_MASK;
+
+                       if (hpldet_pdata->discharge)
+                               hpldet_cfg |= DA7218_HPLDET_DISCHARGE_EN_MASK;
+
+                       snd_soc_write(codec, DA7218_HPLDET_CTRL, hpldet_cfg);
+               }
+       }
+}
+
+static int da7218_probe(struct snd_soc_codec *codec)
+{
+       struct da7218_priv *da7218 = snd_soc_codec_get_drvdata(codec);
+       int ret;
+
+       /* Regulator configuration */
+       ret = da7218_handle_supplies(codec);
+       if (ret)
+               return ret;
+
+       /* Handle DT/Platform data */
+       if (codec->dev->of_node)
+               da7218->pdata = da7218_of_to_pdata(codec);
+       else
+               da7218->pdata = dev_get_platdata(codec->dev);
+
+       da7218_handle_pdata(codec);
+
+       /* Check if MCLK provided, if not the clock is NULL */
+       da7218->mclk = devm_clk_get(codec->dev, "mclk");
+       if (IS_ERR(da7218->mclk)) {
+               if (PTR_ERR(da7218->mclk) != -ENOENT) {
+                       ret = PTR_ERR(da7218->mclk);
+                       goto err_disable_reg;
+               } else {
+                       da7218->mclk = NULL;
+               }
+       }
+
+       /* Default PC to free-running */
+       snd_soc_write(codec, DA7218_PC_COUNT, DA7218_PC_FREERUN_MASK);
+
+       /*
+        * Default Output Filter mixers to off otherwise DAPM will power
+        * Mic to HP passthrough paths by default at startup.
+        */
+       snd_soc_write(codec, DA7218_DROUTING_OUTFILT_1L, 0);
+       snd_soc_write(codec, DA7218_DROUTING_OUTFILT_1R, 0);
+
+       /* Default CP to normal load, power mode */
+       snd_soc_update_bits(codec, DA7218_CP_CTRL,
+                           DA7218_CP_SMALL_SWITCH_FREQ_EN_MASK, 0);
+
+       /* Default gain ramping */
+       snd_soc_update_bits(codec, DA7218_MIXIN_1_CTRL,
+                           DA7218_MIXIN_1_AMP_RAMP_EN_MASK,
+                           DA7218_MIXIN_1_AMP_RAMP_EN_MASK);
+       snd_soc_update_bits(codec, DA7218_MIXIN_2_CTRL,
+                           DA7218_MIXIN_2_AMP_RAMP_EN_MASK,
+                           DA7218_MIXIN_2_AMP_RAMP_EN_MASK);
+       snd_soc_update_bits(codec, DA7218_IN_1L_FILTER_CTRL,
+                           DA7218_IN_1L_RAMP_EN_MASK,
+                           DA7218_IN_1L_RAMP_EN_MASK);
+       snd_soc_update_bits(codec, DA7218_IN_1R_FILTER_CTRL,
+                           DA7218_IN_1R_RAMP_EN_MASK,
+                           DA7218_IN_1R_RAMP_EN_MASK);
+       snd_soc_update_bits(codec, DA7218_IN_2L_FILTER_CTRL,
+                           DA7218_IN_2L_RAMP_EN_MASK,
+                           DA7218_IN_2L_RAMP_EN_MASK);
+       snd_soc_update_bits(codec, DA7218_IN_2R_FILTER_CTRL,
+                           DA7218_IN_2R_RAMP_EN_MASK,
+                           DA7218_IN_2R_RAMP_EN_MASK);
+       snd_soc_update_bits(codec, DA7218_DGS_GAIN_CTRL,
+                           DA7218_DGS_RAMP_EN_MASK, DA7218_DGS_RAMP_EN_MASK);
+       snd_soc_update_bits(codec, DA7218_OUT_1L_FILTER_CTRL,
+                           DA7218_OUT_1L_RAMP_EN_MASK,
+                           DA7218_OUT_1L_RAMP_EN_MASK);
+       snd_soc_update_bits(codec, DA7218_OUT_1R_FILTER_CTRL,
+                           DA7218_OUT_1R_RAMP_EN_MASK,
+                           DA7218_OUT_1R_RAMP_EN_MASK);
+       snd_soc_update_bits(codec, DA7218_HP_L_CTRL,
+                           DA7218_HP_L_AMP_RAMP_EN_MASK,
+                           DA7218_HP_L_AMP_RAMP_EN_MASK);
+       snd_soc_update_bits(codec, DA7218_HP_R_CTRL,
+                           DA7218_HP_R_AMP_RAMP_EN_MASK,
+                           DA7218_HP_R_AMP_RAMP_EN_MASK);
+
+       /* Default infinite tone gen, start/stop by Kcontrol */
+       snd_soc_write(codec, DA7218_TONE_GEN_CYCLES, DA7218_BEEP_CYCLES_MASK);
+
+       /* DA7217 specific config */
+       if (da7218->dev_id == DA7217_DEV_ID) {
+               snd_soc_update_bits(codec, DA7218_HP_DIFF_CTRL,
+                                   DA7218_HP_AMP_DIFF_MODE_EN_MASK,
+                                   DA7218_HP_AMP_DIFF_MODE_EN_MASK);
+
+               /* Only DA7218 supports HP detect, mask off for DA7217 */
+               snd_soc_write(codec, DA7218_EVENT_MASK,
+                             DA7218_HPLDET_JACK_EVENT_IRQ_MSK_MASK);
+       }
+
+       if (da7218->irq) {
+               ret = devm_request_threaded_irq(codec->dev, da7218->irq, NULL,
+                                               da7218_irq_thread,
+                                               IRQF_TRIGGER_LOW | IRQF_ONESHOT,
+                                               "da7218", codec);
+               if (ret != 0) {
+                       dev_err(codec->dev, "Failed to request IRQ %d: %d\n",
+                               da7218->irq, ret);
+                       goto err_disable_reg;
+               }
+
+       }
+
+       return 0;
+
+err_disable_reg:
+       regulator_bulk_disable(DA7218_NUM_SUPPLIES, da7218->supplies);
+
+       return ret;
+}
+
+static int da7218_remove(struct snd_soc_codec *codec)
+{
+       struct da7218_priv *da7218 = snd_soc_codec_get_drvdata(codec);
+
+       regulator_bulk_disable(DA7218_NUM_SUPPLIES, da7218->supplies);
+
+       return 0;
+}
+
+#ifdef CONFIG_PM
+static int da7218_suspend(struct snd_soc_codec *codec)
+{
+       struct da7218_priv *da7218 = snd_soc_codec_get_drvdata(codec);
+
+       da7218_set_bias_level(codec, SND_SOC_BIAS_OFF);
+
+       /* Put device into standby mode if jack detection disabled */
+       if (!da7218->jack)
+               snd_soc_write(codec, DA7218_SYSTEM_ACTIVE, 0);
+
+       return 0;
+}
+
+static int da7218_resume(struct snd_soc_codec *codec)
+{
+       struct da7218_priv *da7218 = snd_soc_codec_get_drvdata(codec);
+
+       /* Put device into active mode if previously moved to standby */
+       if (!da7218->jack)
+               snd_soc_write(codec, DA7218_SYSTEM_ACTIVE,
+                             DA7218_SYSTEM_ACTIVE_MASK);
+
+       da7218_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
+
+       return 0;
+}
+#else
+#define da7218_suspend NULL
+#define da7218_resume NULL
+#endif
+
+static struct snd_soc_codec_driver soc_codec_dev_da7218 = {
+       .probe                  = da7218_probe,
+       .remove                 = da7218_remove,
+       .suspend                = da7218_suspend,
+       .resume                 = da7218_resume,
+       .set_bias_level         = da7218_set_bias_level,
+
+       .controls               = da7218_snd_controls,
+       .num_controls           = ARRAY_SIZE(da7218_snd_controls),
+
+       .dapm_widgets           = da7218_dapm_widgets,
+       .num_dapm_widgets       = ARRAY_SIZE(da7218_dapm_widgets),
+       .dapm_routes            = da7218_audio_map,
+       .num_dapm_routes        = ARRAY_SIZE(da7218_audio_map),
+};
+
+
+/*
+ * Regmap configs
+ */
+
+static struct reg_default da7218_reg_defaults[] = {
+       { DA7218_SYSTEM_ACTIVE, 0x00 },
+       { DA7218_CIF_CTRL, 0x00 },
+       { DA7218_SPARE1, 0x00 },
+       { DA7218_SR, 0xAA },
+       { DA7218_PC_COUNT, 0x02 },
+       { DA7218_GAIN_RAMP_CTRL, 0x00 },
+       { DA7218_CIF_TIMEOUT_CTRL, 0x01 },
+       { DA7218_SYSTEM_MODES_INPUT, 0x00 },
+       { DA7218_SYSTEM_MODES_OUTPUT, 0x00 },
+       { DA7218_IN_1L_FILTER_CTRL, 0x00 },
+       { DA7218_IN_1R_FILTER_CTRL, 0x00 },
+       { DA7218_IN_2L_FILTER_CTRL, 0x00 },
+       { DA7218_IN_2R_FILTER_CTRL, 0x00 },
+       { DA7218_OUT_1L_FILTER_CTRL, 0x40 },
+       { DA7218_OUT_1R_FILTER_CTRL, 0x40 },
+       { DA7218_OUT_1_HPF_FILTER_CTRL, 0x80 },
+       { DA7218_OUT_1_EQ_12_FILTER_CTRL, 0x77 },
+       { DA7218_OUT_1_EQ_34_FILTER_CTRL, 0x77 },
+       { DA7218_OUT_1_EQ_5_FILTER_CTRL, 0x07 },
+       { DA7218_OUT_1_BIQ_5STAGE_CTRL, 0x40 },
+       { DA7218_OUT_1_BIQ_5STAGE_DATA, 0x00 },
+       { DA7218_OUT_1_BIQ_5STAGE_ADDR, 0x00 },
+       { DA7218_MIXIN_1_CTRL, 0x48 },
+       { DA7218_MIXIN_1_GAIN, 0x03 },
+       { DA7218_MIXIN_2_CTRL, 0x48 },
+       { DA7218_MIXIN_2_GAIN, 0x03 },
+       { DA7218_ALC_CTRL1, 0x00 },
+       { DA7218_ALC_CTRL2, 0x00 },
+       { DA7218_ALC_CTRL3, 0x00 },
+       { DA7218_ALC_NOISE, 0x3F },
+       { DA7218_ALC_TARGET_MIN, 0x3F },
+       { DA7218_ALC_TARGET_MAX, 0x00 },
+       { DA7218_ALC_GAIN_LIMITS, 0xFF },
+       { DA7218_ALC_ANA_GAIN_LIMITS, 0x71 },
+       { DA7218_ALC_ANTICLIP_CTRL, 0x00 },
+       { DA7218_AGS_ENABLE, 0x00 },
+       { DA7218_AGS_TRIGGER, 0x09 },
+       { DA7218_AGS_ATT_MAX, 0x00 },
+       { DA7218_AGS_TIMEOUT, 0x00 },
+       { DA7218_AGS_ANTICLIP_CTRL, 0x00 },
+       { DA7218_ENV_TRACK_CTRL, 0x00 },
+       { DA7218_LVL_DET_CTRL, 0x00 },
+       { DA7218_LVL_DET_LEVEL, 0x7F },
+       { DA7218_DGS_TRIGGER, 0x24 },
+       { DA7218_DGS_ENABLE, 0x00 },
+       { DA7218_DGS_RISE_FALL, 0x50 },
+       { DA7218_DGS_SYNC_DELAY, 0xA3 },
+       { DA7218_DGS_SYNC_DELAY2, 0x31 },
+       { DA7218_DGS_SYNC_DELAY3, 0x11 },
+       { DA7218_DGS_LEVELS, 0x01 },
+       { DA7218_DGS_GAIN_CTRL, 0x74 },
+       { DA7218_DROUTING_OUTDAI_1L, 0x01 },
+       { DA7218_DMIX_OUTDAI_1L_INFILT_1L_GAIN, 0x1C },
+       { DA7218_DMIX_OUTDAI_1L_INFILT_1R_GAIN, 0x1C },
+       { DA7218_DMIX_OUTDAI_1L_INFILT_2L_GAIN, 0x1C },
+       { DA7218_DMIX_OUTDAI_1L_INFILT_2R_GAIN, 0x1C },
+       { DA7218_DMIX_OUTDAI_1L_TONEGEN_GAIN, 0x1C },
+       { DA7218_DMIX_OUTDAI_1L_INDAI_1L_GAIN, 0x1C },
+       { DA7218_DMIX_OUTDAI_1L_INDAI_1R_GAIN, 0x1C },
+       { DA7218_DROUTING_OUTDAI_1R, 0x04 },
+       { DA7218_DMIX_OUTDAI_1R_INFILT_1L_GAIN, 0x1C },
+       { DA7218_DMIX_OUTDAI_1R_INFILT_1R_GAIN, 0x1C },
+       { DA7218_DMIX_OUTDAI_1R_INFILT_2L_GAIN, 0x1C },
+       { DA7218_DMIX_OUTDAI_1R_INFILT_2R_GAIN, 0x1C },
+       { DA7218_DMIX_OUTDAI_1R_TONEGEN_GAIN, 0x1C },
+       { DA7218_DMIX_OUTDAI_1R_INDAI_1L_GAIN, 0x1C },
+       { DA7218_DMIX_OUTDAI_1R_INDAI_1R_GAIN, 0x1C },
+       { DA7218_DROUTING_OUTFILT_1L, 0x01 },
+       { DA7218_DMIX_OUTFILT_1L_INFILT_1L_GAIN, 0x1C },
+       { DA7218_DMIX_OUTFILT_1L_INFILT_1R_GAIN, 0x1C },
+       { DA7218_DMIX_OUTFILT_1L_INFILT_2L_GAIN, 0x1C },
+       { DA7218_DMIX_OUTFILT_1L_INFILT_2R_GAIN, 0x1C },
+       { DA7218_DMIX_OUTFILT_1L_TONEGEN_GAIN, 0x1C },
+       { DA7218_DMIX_OUTFILT_1L_INDAI_1L_GAIN, 0x1C },
+       { DA7218_DMIX_OUTFILT_1L_INDAI_1R_GAIN, 0x1C },
+       { DA7218_DROUTING_OUTFILT_1R, 0x04 },
+       { DA7218_DMIX_OUTFILT_1R_INFILT_1L_GAIN, 0x1C },
+       { DA7218_DMIX_OUTFILT_1R_INFILT_1R_GAIN, 0x1C },
+       { DA7218_DMIX_OUTFILT_1R_INFILT_2L_GAIN, 0x1C },
+       { DA7218_DMIX_OUTFILT_1R_INFILT_2R_GAIN, 0x1C },
+       { DA7218_DMIX_OUTFILT_1R_TONEGEN_GAIN, 0x1C },
+       { DA7218_DMIX_OUTFILT_1R_INDAI_1L_GAIN, 0x1C },
+       { DA7218_DMIX_OUTFILT_1R_INDAI_1R_GAIN, 0x1C },
+       { DA7218_DROUTING_OUTDAI_2L, 0x04 },
+       { DA7218_DMIX_OUTDAI_2L_INFILT_1L_GAIN, 0x1C },
+       { DA7218_DMIX_OUTDAI_2L_INFILT_1R_GAIN, 0x1C },
+       { DA7218_DMIX_OUTDAI_2L_INFILT_2L_GAIN, 0x1C },
+       { DA7218_DMIX_OUTDAI_2L_INFILT_2R_GAIN, 0x1C },
+       { DA7218_DMIX_OUTDAI_2L_TONEGEN_GAIN, 0x1C },
+       { DA7218_DMIX_OUTDAI_2L_INDAI_1L_GAIN, 0x1C },
+       { DA7218_DMIX_OUTDAI_2L_INDAI_1R_GAIN, 0x1C },
+       { DA7218_DROUTING_OUTDAI_2R, 0x08 },
+       { DA7218_DMIX_OUTDAI_2R_INFILT_1L_GAIN, 0x1C },
+       { DA7218_DMIX_OUTDAI_2R_INFILT_1R_GAIN, 0x1C },
+       { DA7218_DMIX_OUTDAI_2R_INFILT_2L_GAIN, 0x1C },
+       { DA7218_DMIX_OUTDAI_2R_INFILT_2R_GAIN, 0x1C },
+       { DA7218_DMIX_OUTDAI_2R_TONEGEN_GAIN, 0x1C },
+       { DA7218_DMIX_OUTDAI_2R_INDAI_1L_GAIN, 0x1C },
+       { DA7218_DMIX_OUTDAI_2R_INDAI_1R_GAIN, 0x1C },
+       { DA7218_DAI_CTRL, 0x28 },
+       { DA7218_DAI_TDM_CTRL, 0x40 },
+       { DA7218_DAI_OFFSET_LOWER, 0x00 },
+       { DA7218_DAI_OFFSET_UPPER, 0x00 },
+       { DA7218_DAI_CLK_MODE, 0x01 },
+       { DA7218_PLL_CTRL, 0x04 },
+       { DA7218_PLL_FRAC_TOP, 0x00 },
+       { DA7218_PLL_FRAC_BOT, 0x00 },
+       { DA7218_PLL_INTEGER, 0x20 },
+       { DA7218_DAC_NG_CTRL, 0x00 },
+       { DA7218_DAC_NG_SETUP_TIME, 0x00 },
+       { DA7218_DAC_NG_OFF_THRESH, 0x00 },
+       { DA7218_DAC_NG_ON_THRESH, 0x00 },
+       { DA7218_TONE_GEN_CFG2, 0x00 },
+       { DA7218_TONE_GEN_FREQ1_L, 0x55 },
+       { DA7218_TONE_GEN_FREQ1_U, 0x15 },
+       { DA7218_TONE_GEN_FREQ2_L, 0x00 },
+       { DA7218_TONE_GEN_FREQ2_U, 0x40 },
+       { DA7218_TONE_GEN_CYCLES, 0x00 },
+       { DA7218_TONE_GEN_ON_PER, 0x02 },
+       { DA7218_TONE_GEN_OFF_PER, 0x01 },
+       { DA7218_CP_CTRL, 0x60 },
+       { DA7218_CP_DELAY, 0x11 },
+       { DA7218_CP_VOL_THRESHOLD1, 0x0E },
+       { DA7218_MIC_1_CTRL, 0x40 },
+       { DA7218_MIC_1_GAIN, 0x01 },
+       { DA7218_MIC_1_SELECT, 0x00 },
+       { DA7218_MIC_2_CTRL, 0x40 },
+       { DA7218_MIC_2_GAIN, 0x01 },
+       { DA7218_MIC_2_SELECT, 0x00 },
+       { DA7218_IN_1_HPF_FILTER_CTRL, 0x80 },
+       { DA7218_IN_2_HPF_FILTER_CTRL, 0x80 },
+       { DA7218_ADC_1_CTRL, 0x07 },
+       { DA7218_ADC_2_CTRL, 0x07 },
+       { DA7218_MIXOUT_L_CTRL, 0x00 },
+       { DA7218_MIXOUT_L_GAIN, 0x03 },
+       { DA7218_MIXOUT_R_CTRL, 0x00 },
+       { DA7218_MIXOUT_R_GAIN, 0x03 },
+       { DA7218_HP_L_CTRL, 0x40 },
+       { DA7218_HP_L_GAIN, 0x3B },
+       { DA7218_HP_R_CTRL, 0x40 },
+       { DA7218_HP_R_GAIN, 0x3B },
+       { DA7218_HP_DIFF_CTRL, 0x00 },
+       { DA7218_HP_DIFF_UNLOCK, 0xC3 },
+       { DA7218_HPLDET_JACK, 0x0B },
+       { DA7218_HPLDET_CTRL, 0x00 },
+       { DA7218_REFERENCES, 0x08 },
+       { DA7218_IO_CTRL, 0x00 },
+       { DA7218_LDO_CTRL, 0x00 },
+       { DA7218_SIDETONE_CTRL, 0x40 },
+       { DA7218_SIDETONE_IN_SELECT, 0x00 },
+       { DA7218_SIDETONE_GAIN, 0x1C },
+       { DA7218_DROUTING_ST_OUTFILT_1L, 0x01 },
+       { DA7218_DROUTING_ST_OUTFILT_1R, 0x02 },
+       { DA7218_SIDETONE_BIQ_3STAGE_DATA, 0x00 },
+       { DA7218_SIDETONE_BIQ_3STAGE_ADDR, 0x00 },
+       { DA7218_EVENT_MASK, 0x00 },
+       { DA7218_DMIC_1_CTRL, 0x00 },
+       { DA7218_DMIC_2_CTRL, 0x00 },
+       { DA7218_IN_1L_GAIN, 0x6F },
+       { DA7218_IN_1R_GAIN, 0x6F },
+       { DA7218_IN_2L_GAIN, 0x6F },
+       { DA7218_IN_2R_GAIN, 0x6F },
+       { DA7218_OUT_1L_GAIN, 0x6F },
+       { DA7218_OUT_1R_GAIN, 0x6F },
+       { DA7218_MICBIAS_CTRL, 0x00 },
+       { DA7218_MICBIAS_EN, 0x00 },
+};
+
+static bool da7218_volatile_register(struct device *dev, unsigned int reg)
+{
+       switch (reg) {
+       case DA7218_STATUS1:
+       case DA7218_SOFT_RESET:
+       case DA7218_SYSTEM_STATUS:
+       case DA7218_CALIB_CTRL:
+       case DA7218_CALIB_OFFSET_AUTO_M_1:
+       case DA7218_CALIB_OFFSET_AUTO_U_1:
+       case DA7218_CALIB_OFFSET_AUTO_M_2:
+       case DA7218_CALIB_OFFSET_AUTO_U_2:
+       case DA7218_PLL_STATUS:
+       case DA7218_PLL_REFOSC_CAL:
+       case DA7218_TONE_GEN_CFG1:
+       case DA7218_ADC_MODE:
+       case DA7218_HP_SNGL_CTRL:
+       case DA7218_HPLDET_TEST:
+       case DA7218_EVENT_STATUS:
+       case DA7218_EVENT:
+               return true;
+       default:
+               return false;
+       }
+}
+
+static const struct regmap_config da7218_regmap_config = {
+       .reg_bits = 8,
+       .val_bits = 8,
+
+       .max_register = DA7218_MICBIAS_EN,
+       .reg_defaults = da7218_reg_defaults,
+       .num_reg_defaults = ARRAY_SIZE(da7218_reg_defaults),
+       .volatile_reg = da7218_volatile_register,
+       .cache_type = REGCACHE_RBTREE,
+};
+
+
+/*
+ * I2C layer
+ */
+
+static int da7218_i2c_probe(struct i2c_client *i2c,
+                           const struct i2c_device_id *id)
+{
+       struct da7218_priv *da7218;
+       int ret;
+
+       da7218 = devm_kzalloc(&i2c->dev, sizeof(struct da7218_priv),
+                             GFP_KERNEL);
+       if (!da7218)
+               return -ENOMEM;
+
+       i2c_set_clientdata(i2c, da7218);
+
+       if (i2c->dev.of_node)
+               da7218->dev_id = da7218_of_get_id(&i2c->dev);
+       else
+               da7218->dev_id = id->driver_data;
+
+       if ((da7218->dev_id != DA7217_DEV_ID) &&
+           (da7218->dev_id != DA7218_DEV_ID)) {
+               dev_err(&i2c->dev, "Invalid device Id\n");
+               return -EINVAL;
+       }
+
+       da7218->irq = i2c->irq;
+
+       da7218->regmap = devm_regmap_init_i2c(i2c, &da7218_regmap_config);
+       if (IS_ERR(da7218->regmap)) {
+               ret = PTR_ERR(da7218->regmap);
+               dev_err(&i2c->dev, "regmap_init() failed: %d\n", ret);
+               return ret;
+       }
+
+       ret = snd_soc_register_codec(&i2c->dev,
+                       &soc_codec_dev_da7218, &da7218_dai, 1);
+       if (ret < 0) {
+               dev_err(&i2c->dev, "Failed to register da7218 codec: %d\n",
+                       ret);
+       }
+       return ret;
+}
+
+static int da7218_i2c_remove(struct i2c_client *client)
+{
+       snd_soc_unregister_codec(&client->dev);
+       return 0;
+}
+
+static const struct i2c_device_id da7218_i2c_id[] = {
+       { "da7217", DA7217_DEV_ID },
+       { "da7218", DA7218_DEV_ID },
+       { }
+};
+MODULE_DEVICE_TABLE(i2c, da7218_i2c_id);
+
+static struct i2c_driver da7218_i2c_driver = {
+       .driver = {
+               .name = "da7218",
+               .of_match_table = of_match_ptr(da7218_of_match),
+       },
+       .probe          = da7218_i2c_probe,
+       .remove         = da7218_i2c_remove,
+       .id_table       = da7218_i2c_id,
+};
+
+module_i2c_driver(da7218_i2c_driver);
+
+MODULE_DESCRIPTION("ASoC DA7218 Codec driver");
+MODULE_AUTHOR("Adam Thomson <Adam.Thomson.Opensource@diasemi.com>");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/da7218.h b/sound/soc/codecs/da7218.h
new file mode 100644 (file)
index 0000000..c2c5904
--- /dev/null
@@ -0,0 +1,1414 @@
+/*
+ * da7218.h - DA7218 ALSA SoC Codec Driver
+ *
+ * Copyright (c) 2015 Dialog Semiconductor
+ *
+ * Author: Adam Thomson <Adam.Thomson.Opensource@diasemi.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 _DA7218_H
+#define _DA7218_H
+
+#include <linux/regmap.h>
+#include <linux/regulator/consumer.h>
+#include <sound/da7218.h>
+
+
+/*
+ * Registers
+ */
+#define DA7218_SYSTEM_ACTIVE                   0x0
+#define DA7218_CIF_CTRL                                0x1
+#define DA7218_CHIP_ID1                                0x4
+#define DA7218_CHIP_ID2                                0x5
+#define DA7218_CHIP_REVISION                   0x6
+#define DA7218_SPARE1                          0x7
+#define DA7218_STATUS1                         0x8
+#define DA7218_SOFT_RESET                      0x9
+#define DA7218_SR                              0xB
+#define DA7218_PC_COUNT                                0xC
+#define DA7218_GAIN_RAMP_CTRL                  0xD
+#define DA7218_CIF_TIMEOUT_CTRL                        0x10
+#define DA7218_SYSTEM_MODES_INPUT              0x14
+#define DA7218_SYSTEM_MODES_OUTPUT             0x15
+#define DA7218_SYSTEM_STATUS                   0x16
+#define DA7218_IN_1L_FILTER_CTRL               0x18
+#define DA7218_IN_1R_FILTER_CTRL               0x19
+#define DA7218_IN_2L_FILTER_CTRL               0x1A
+#define DA7218_IN_2R_FILTER_CTRL               0x1B
+#define DA7218_OUT_1L_FILTER_CTRL              0x20
+#define DA7218_OUT_1R_FILTER_CTRL              0x21
+#define DA7218_OUT_1_HPF_FILTER_CTRL           0x24
+#define DA7218_OUT_1_EQ_12_FILTER_CTRL         0x25
+#define DA7218_OUT_1_EQ_34_FILTER_CTRL         0x26
+#define DA7218_OUT_1_EQ_5_FILTER_CTRL          0x27
+#define DA7218_OUT_1_BIQ_5STAGE_CTRL           0x28
+#define DA7218_OUT_1_BIQ_5STAGE_DATA           0x29
+#define DA7218_OUT_1_BIQ_5STAGE_ADDR           0x2A
+#define DA7218_MIXIN_1_CTRL                    0x2C
+#define DA7218_MIXIN_1_GAIN                    0x2D
+#define DA7218_MIXIN_2_CTRL                    0x2E
+#define DA7218_MIXIN_2_GAIN                    0x2F
+#define DA7218_ALC_CTRL1                       0x30
+#define DA7218_ALC_CTRL2                       0x31
+#define DA7218_ALC_CTRL3                       0x32
+#define DA7218_ALC_NOISE                       0x33
+#define DA7218_ALC_TARGET_MIN                  0x34
+#define DA7218_ALC_TARGET_MAX                  0x35
+#define DA7218_ALC_GAIN_LIMITS                 0x36
+#define DA7218_ALC_ANA_GAIN_LIMITS             0x37
+#define DA7218_ALC_ANTICLIP_CTRL               0x38
+#define DA7218_AGS_ENABLE                      0x3C
+#define DA7218_AGS_TRIGGER                     0x3D
+#define DA7218_AGS_ATT_MAX                     0x3E
+#define DA7218_AGS_TIMEOUT                     0x3F
+#define DA7218_AGS_ANTICLIP_CTRL               0x40
+#define DA7218_CALIB_CTRL                      0x44
+#define DA7218_CALIB_OFFSET_AUTO_M_1           0x45
+#define DA7218_CALIB_OFFSET_AUTO_U_1           0x46
+#define DA7218_CALIB_OFFSET_AUTO_M_2           0x47
+#define DA7218_CALIB_OFFSET_AUTO_U_2           0x48
+#define DA7218_ENV_TRACK_CTRL                  0x4C
+#define DA7218_LVL_DET_CTRL                    0x50
+#define DA7218_LVL_DET_LEVEL                   0x51
+#define DA7218_DGS_TRIGGER                     0x54
+#define DA7218_DGS_ENABLE                      0x55
+#define DA7218_DGS_RISE_FALL                   0x56
+#define DA7218_DGS_SYNC_DELAY                  0x57
+#define DA7218_DGS_SYNC_DELAY2                 0x58
+#define DA7218_DGS_SYNC_DELAY3                 0x59
+#define DA7218_DGS_LEVELS                      0x5A
+#define DA7218_DGS_GAIN_CTRL                   0x5B
+#define DA7218_DROUTING_OUTDAI_1L              0x5C
+#define DA7218_DMIX_OUTDAI_1L_INFILT_1L_GAIN   0x5D
+#define DA7218_DMIX_OUTDAI_1L_INFILT_1R_GAIN   0x5E
+#define DA7218_DMIX_OUTDAI_1L_INFILT_2L_GAIN   0x5F
+#define DA7218_DMIX_OUTDAI_1L_INFILT_2R_GAIN   0x60
+#define DA7218_DMIX_OUTDAI_1L_TONEGEN_GAIN     0x61
+#define DA7218_DMIX_OUTDAI_1L_INDAI_1L_GAIN    0x62
+#define DA7218_DMIX_OUTDAI_1L_INDAI_1R_GAIN    0x63
+#define DA7218_DROUTING_OUTDAI_1R              0x64
+#define DA7218_DMIX_OUTDAI_1R_INFILT_1L_GAIN   0x65
+#define DA7218_DMIX_OUTDAI_1R_INFILT_1R_GAIN   0x66
+#define DA7218_DMIX_OUTDAI_1R_INFILT_2L_GAIN   0x67
+#define DA7218_DMIX_OUTDAI_1R_INFILT_2R_GAIN   0x68
+#define DA7218_DMIX_OUTDAI_1R_TONEGEN_GAIN     0x69
+#define DA7218_DMIX_OUTDAI_1R_INDAI_1L_GAIN    0x6A
+#define DA7218_DMIX_OUTDAI_1R_INDAI_1R_GAIN    0x6B
+#define DA7218_DROUTING_OUTFILT_1L             0x6C
+#define DA7218_DMIX_OUTFILT_1L_INFILT_1L_GAIN  0x6D
+#define DA7218_DMIX_OUTFILT_1L_INFILT_1R_GAIN  0x6E
+#define DA7218_DMIX_OUTFILT_1L_INFILT_2L_GAIN  0x6F
+#define DA7218_DMIX_OUTFILT_1L_INFILT_2R_GAIN  0x70
+#define DA7218_DMIX_OUTFILT_1L_TONEGEN_GAIN    0x71
+#define DA7218_DMIX_OUTFILT_1L_INDAI_1L_GAIN   0x72
+#define DA7218_DMIX_OUTFILT_1L_INDAI_1R_GAIN   0x73
+#define DA7218_DROUTING_OUTFILT_1R             0x74
+#define DA7218_DMIX_OUTFILT_1R_INFILT_1L_GAIN  0x75
+#define DA7218_DMIX_OUTFILT_1R_INFILT_1R_GAIN  0x76
+#define DA7218_DMIX_OUTFILT_1R_INFILT_2L_GAIN  0x77
+#define DA7218_DMIX_OUTFILT_1R_INFILT_2R_GAIN  0x78
+#define DA7218_DMIX_OUTFILT_1R_TONEGEN_GAIN    0x79
+#define DA7218_DMIX_OUTFILT_1R_INDAI_1L_GAIN   0x7A
+#define DA7218_DMIX_OUTFILT_1R_INDAI_1R_GAIN   0x7B
+#define DA7218_DROUTING_OUTDAI_2L              0x7C
+#define DA7218_DMIX_OUTDAI_2L_INFILT_1L_GAIN   0x7D
+#define DA7218_DMIX_OUTDAI_2L_INFILT_1R_GAIN   0x7E
+#define DA7218_DMIX_OUTDAI_2L_INFILT_2L_GAIN   0x7F
+#define DA7218_DMIX_OUTDAI_2L_INFILT_2R_GAIN   0x80
+#define DA7218_DMIX_OUTDAI_2L_TONEGEN_GAIN     0x81
+#define DA7218_DMIX_OUTDAI_2L_INDAI_1L_GAIN    0x82
+#define DA7218_DMIX_OUTDAI_2L_INDAI_1R_GAIN    0x83
+#define DA7218_DROUTING_OUTDAI_2R              0x84
+#define DA7218_DMIX_OUTDAI_2R_INFILT_1L_GAIN   0x85
+#define DA7218_DMIX_OUTDAI_2R_INFILT_1R_GAIN   0x86
+#define DA7218_DMIX_OUTDAI_2R_INFILT_2L_GAIN   0x87
+#define DA7218_DMIX_OUTDAI_2R_INFILT_2R_GAIN   0x88
+#define DA7218_DMIX_OUTDAI_2R_TONEGEN_GAIN     0x89
+#define DA7218_DMIX_OUTDAI_2R_INDAI_1L_GAIN    0x8A
+#define DA7218_DMIX_OUTDAI_2R_INDAI_1R_GAIN    0x8B
+#define DA7218_DAI_CTRL                                0x8C
+#define DA7218_DAI_TDM_CTRL                    0x8D
+#define DA7218_DAI_OFFSET_LOWER                        0x8E
+#define DA7218_DAI_OFFSET_UPPER                        0x8F
+#define DA7218_DAI_CLK_MODE                    0x90
+#define DA7218_PLL_CTRL                                0x91
+#define DA7218_PLL_FRAC_TOP                    0x92
+#define DA7218_PLL_FRAC_BOT                    0x93
+#define DA7218_PLL_INTEGER                     0x94
+#define DA7218_PLL_STATUS                      0x95
+#define DA7218_PLL_REFOSC_CAL                  0x98
+#define DA7218_DAC_NG_CTRL                     0x9C
+#define DA7218_DAC_NG_SETUP_TIME               0x9D
+#define DA7218_DAC_NG_OFF_THRESH               0x9E
+#define DA7218_DAC_NG_ON_THRESH                        0x9F
+#define DA7218_TONE_GEN_CFG1                   0xA0
+#define DA7218_TONE_GEN_CFG2                   0xA1
+#define DA7218_TONE_GEN_FREQ1_L                        0xA2
+#define DA7218_TONE_GEN_FREQ1_U                        0xA3
+#define DA7218_TONE_GEN_FREQ2_L                        0xA4
+#define DA7218_TONE_GEN_FREQ2_U                        0xA5
+#define DA7218_TONE_GEN_CYCLES                 0xA6
+#define DA7218_TONE_GEN_ON_PER                 0xA7
+#define DA7218_TONE_GEN_OFF_PER                        0xA8
+#define DA7218_CP_CTRL                         0xAC
+#define DA7218_CP_DELAY                                0xAD
+#define DA7218_CP_VOL_THRESHOLD1               0xAE
+#define DA7218_MIC_1_CTRL                      0xB4
+#define DA7218_MIC_1_GAIN                      0xB5
+#define DA7218_MIC_1_SELECT                    0xB7
+#define DA7218_MIC_2_CTRL                      0xB8
+#define DA7218_MIC_2_GAIN                      0xB9
+#define DA7218_MIC_2_SELECT                    0xBB
+#define DA7218_IN_1_HPF_FILTER_CTRL            0xBC
+#define DA7218_IN_2_HPF_FILTER_CTRL            0xBD
+#define DA7218_ADC_1_CTRL                      0xC0
+#define DA7218_ADC_2_CTRL                      0xC1
+#define DA7218_ADC_MODE                                0xC2
+#define DA7218_MIXOUT_L_CTRL                   0xCC
+#define DA7218_MIXOUT_L_GAIN                   0xCD
+#define DA7218_MIXOUT_R_CTRL                   0xCE
+#define DA7218_MIXOUT_R_GAIN                   0xCF
+#define DA7218_HP_L_CTRL                       0xD0
+#define DA7218_HP_L_GAIN                       0xD1
+#define DA7218_HP_R_CTRL                       0xD2
+#define DA7218_HP_R_GAIN                       0xD3
+#define DA7218_HP_SNGL_CTRL                    0xD4
+#define DA7218_HP_DIFF_CTRL                    0xD5
+#define DA7218_HP_DIFF_UNLOCK                  0xD7
+#define DA7218_HPLDET_JACK                     0xD8
+#define DA7218_HPLDET_CTRL                     0xD9
+#define DA7218_HPLDET_TEST                     0xDA
+#define DA7218_REFERENCES                      0xDC
+#define DA7218_IO_CTRL                         0xE0
+#define DA7218_LDO_CTRL                                0xE1
+#define DA7218_SIDETONE_CTRL                   0xE4
+#define DA7218_SIDETONE_IN_SELECT              0xE5
+#define DA7218_SIDETONE_GAIN                   0xE6
+#define DA7218_DROUTING_ST_OUTFILT_1L          0xE8
+#define DA7218_DROUTING_ST_OUTFILT_1R          0xE9
+#define DA7218_SIDETONE_BIQ_3STAGE_DATA                0xEA
+#define DA7218_SIDETONE_BIQ_3STAGE_ADDR                0xEB
+#define DA7218_EVENT_STATUS                    0xEC
+#define DA7218_EVENT                           0xED
+#define DA7218_EVENT_MASK                      0xEE
+#define DA7218_DMIC_1_CTRL                     0xF0
+#define DA7218_DMIC_2_CTRL                     0xF1
+#define DA7218_IN_1L_GAIN                      0xF4
+#define DA7218_IN_1R_GAIN                      0xF5
+#define DA7218_IN_2L_GAIN                      0xF6
+#define DA7218_IN_2R_GAIN                      0xF7
+#define DA7218_OUT_1L_GAIN                     0xF8
+#define DA7218_OUT_1R_GAIN                     0xF9
+#define DA7218_MICBIAS_CTRL                    0xFC
+#define DA7218_MICBIAS_EN                      0xFD
+
+
+/*
+ * Bit Fields
+ */
+
+#define DA7218_SWITCH_EN_MAX           0x1
+
+/* DA7218_SYSTEM_ACTIVE = 0x0 */
+#define DA7218_SYSTEM_ACTIVE_SHIFT     0
+#define DA7218_SYSTEM_ACTIVE_MASK      (0x1 << 0)
+
+/* DA7218_CIF_CTRL = 0x1 */
+#define DA7218_CIF_I2C_WRITE_MODE_SHIFT        0
+#define DA7218_CIF_I2C_WRITE_MODE_MASK (0x1 << 0)
+
+/* DA7218_CHIP_ID1 = 0x4 */
+#define DA7218_CHIP_ID1_SHIFT  0
+#define DA7218_CHIP_ID1_MASK   (0xFF << 0)
+
+/* DA7218_CHIP_ID2 = 0x5 */
+#define DA7218_CHIP_ID2_SHIFT  0
+#define DA7218_CHIP_ID2_MASK   (0xFF << 0)
+
+/* DA7218_CHIP_REVISION = 0x6 */
+#define DA7218_CHIP_MINOR_SHIFT        0
+#define DA7218_CHIP_MINOR_MASK (0xF << 0)
+#define DA7218_CHIP_MAJOR_SHIFT        4
+#define DA7218_CHIP_MAJOR_MASK (0xF << 4)
+
+/* DA7218_SPARE1 = 0x7 */
+#define DA7218_SPARE1_SHIFT    0
+#define DA7218_SPARE1_MASK     (0xFF << 0)
+
+/* DA7218_STATUS1 = 0x8 */
+#define DA7218_STATUS_SPARE1_SHIFT     0
+#define DA7218_STATUS_SPARE1_MASK      (0xFF << 0)
+
+/* DA7218_SOFT_RESET = 0x9 */
+#define DA7218_CIF_REG_SOFT_RESET_SHIFT        7
+#define DA7218_CIF_REG_SOFT_RESET_MASK (0x1 << 7)
+
+/* DA7218_SR = 0xB */
+#define DA7218_SR_ADC_SHIFT    0
+#define DA7218_SR_ADC_MASK     (0xF << 0)
+#define DA7218_SR_DAC_SHIFT    4
+#define DA7218_SR_DAC_MASK     (0xF << 4)
+#define DA7218_SR_8000         0x01
+#define DA7218_SR_11025                0x02
+#define DA7218_SR_12000                0x03
+#define DA7218_SR_16000                0x05
+#define DA7218_SR_22050                0x06
+#define DA7218_SR_24000                0x07
+#define DA7218_SR_32000                0x09
+#define DA7218_SR_44100                0x0A
+#define DA7218_SR_48000                0x0B
+#define DA7218_SR_88200                0x0E
+#define DA7218_SR_96000                0x0F
+
+/* DA7218_PC_COUNT = 0xC */
+#define DA7218_PC_FREERUN_SHIFT                0
+#define DA7218_PC_FREERUN_MASK         (0x1 << 0)
+#define DA7218_PC_RESYNC_AUTO_SHIFT    1
+#define DA7218_PC_RESYNC_AUTO_MASK     (0x1 << 1)
+
+/* DA7218_GAIN_RAMP_CTRL = 0xD */
+#define DA7218_GAIN_RAMP_RATE_SHIFT    0
+#define DA7218_GAIN_RAMP_RATE_MASK     (0x3 << 0)
+#define DA7218_GAIN_RAMP_RATE_MAX      4
+
+/* DA7218_CIF_TIMEOUT_CTRL = 0x10 */
+#define DA7218_I2C_TIMEOUT_EN_SHIFT    0
+#define DA7218_I2C_TIMEOUT_EN_MASK     (0x1 << 0)
+
+/* DA7218_SYSTEM_MODES_INPUT = 0x14 */
+#define DA7218_MODE_SUBMIT_SHIFT       0
+#define DA7218_MODE_SUBMIT_MASK                (0x1 << 0)
+#define DA7218_ADC_MODE_SHIFT          1
+#define DA7218_ADC_MODE_MASK           (0x7F << 1)
+
+/* DA7218_SYSTEM_MODES_OUTPUT = 0x15 */
+#define DA7218_MODE_SUBMIT_SHIFT       0
+#define DA7218_MODE_SUBMIT_MASK                (0x1 << 0)
+#define DA7218_DAC_MODE_SHIFT          1
+#define DA7218_DAC_MODE_MASK           (0x7F << 1)
+
+/* DA7218_SYSTEM_STATUS = 0x16 */
+#define DA7218_SC1_BUSY_SHIFT  0
+#define DA7218_SC1_BUSY_MASK   (0x1 << 0)
+#define DA7218_SC2_BUSY_SHIFT  1
+#define DA7218_SC2_BUSY_MASK   (0x1 << 1)
+
+/* DA7218_IN_1L_FILTER_CTRL = 0x18 */
+#define DA7218_IN_1L_RAMP_EN_SHIFT     5
+#define DA7218_IN_1L_RAMP_EN_MASK      (0x1 << 5)
+#define DA7218_IN_1L_MUTE_EN_SHIFT     6
+#define DA7218_IN_1L_MUTE_EN_MASK      (0x1 << 6)
+#define DA7218_IN_1L_FILTER_EN_SHIFT   7
+#define DA7218_IN_1L_FILTER_EN_MASK    (0x1 << 7)
+
+/* DA7218_IN_1R_FILTER_CTRL = 0x19 */
+#define DA7218_IN_1R_RAMP_EN_SHIFT     5
+#define DA7218_IN_1R_RAMP_EN_MASK      (0x1 << 5)
+#define DA7218_IN_1R_MUTE_EN_SHIFT     6
+#define DA7218_IN_1R_MUTE_EN_MASK      (0x1 << 6)
+#define DA7218_IN_1R_FILTER_EN_SHIFT   7
+#define DA7218_IN_1R_FILTER_EN_MASK    (0x1 << 7)
+
+/* DA7218_IN_2L_FILTER_CTRL = 0x1A */
+#define DA7218_IN_2L_RAMP_EN_SHIFT     5
+#define DA7218_IN_2L_RAMP_EN_MASK      (0x1 << 5)
+#define DA7218_IN_2L_MUTE_EN_SHIFT     6
+#define DA7218_IN_2L_MUTE_EN_MASK      (0x1 << 6)
+#define DA7218_IN_2L_FILTER_EN_SHIFT   7
+#define DA7218_IN_2L_FILTER_EN_MASK    (0x1 << 7)
+
+/* DA7218_IN_2R_FILTER_CTRL = 0x1B */
+#define DA7218_IN_2R_RAMP_EN_SHIFT     5
+#define DA7218_IN_2R_RAMP_EN_MASK      (0x1 << 5)
+#define DA7218_IN_2R_MUTE_EN_SHIFT     6
+#define DA7218_IN_2R_MUTE_EN_MASK      (0x1 << 6)
+#define DA7218_IN_2R_FILTER_EN_SHIFT   7
+#define DA7218_IN_2R_FILTER_EN_MASK    (0x1 << 7)
+
+/* DA7218_OUT_1L_FILTER_CTRL = 0x20 */
+#define DA7218_OUT_1L_BIQ_5STAGE_SEL_SHIFT     3
+#define DA7218_OUT_1L_BIQ_5STAGE_SEL_MASK      (0x1 << 3)
+#define DA7218_OUT_BIQ_5STAGE_SEL_MAX          2
+#define DA7218_OUT_1L_SUBRANGE_EN_SHIFT                4
+#define DA7218_OUT_1L_SUBRANGE_EN_MASK         (0x1 << 4)
+#define DA7218_OUT_1L_RAMP_EN_SHIFT            5
+#define DA7218_OUT_1L_RAMP_EN_MASK             (0x1 << 5)
+#define DA7218_OUT_1L_MUTE_EN_SHIFT            6
+#define DA7218_OUT_1L_MUTE_EN_MASK             (0x1 << 6)
+#define DA7218_OUT_1L_FILTER_EN_SHIFT          7
+#define DA7218_OUT_1L_FILTER_EN_MASK           (0x1 << 7)
+
+/* DA7218_OUT_1R_FILTER_CTRL = 0x21 */
+#define DA7218_OUT_1R_BIQ_5STAGE_SEL_SHIFT     3
+#define DA7218_OUT_1R_BIQ_5STAGE_SEL_MASK      (0x1 << 3)
+#define DA7218_OUT_1R_SUBRANGE_EN_SHIFT                4
+#define DA7218_OUT_1R_SUBRANGE_EN_MASK         (0x1 << 4)
+#define DA7218_OUT_1R_RAMP_EN_SHIFT            5
+#define DA7218_OUT_1R_RAMP_EN_MASK             (0x1 << 5)
+#define DA7218_OUT_1R_MUTE_EN_SHIFT            6
+#define DA7218_OUT_1R_MUTE_EN_MASK             (0x1 << 6)
+#define DA7218_OUT_1R_FILTER_EN_SHIFT          7
+#define DA7218_OUT_1R_FILTER_EN_MASK           (0x1 << 7)
+
+/* DA7218_OUT_1_HPF_FILTER_CTRL = 0x24 */
+#define DA7218_OUT_1_VOICE_HPF_CORNER_SHIFT    0
+#define DA7218_OUT_1_VOICE_HPF_CORNER_MASK     (0x7 << 0)
+#define DA7218_VOICE_HPF_CORNER_MAX            8
+#define DA7218_OUT_1_VOICE_EN_SHIFT            3
+#define DA7218_OUT_1_VOICE_EN_MASK             (0x1 << 3)
+#define DA7218_OUT_1_AUDIO_HPF_CORNER_SHIFT    4
+#define DA7218_OUT_1_AUDIO_HPF_CORNER_MASK     (0x3 << 4)
+#define DA7218_AUDIO_HPF_CORNER_MAX            4
+#define DA7218_OUT_1_HPF_EN_SHIFT              7
+#define DA7218_OUT_1_HPF_EN_MASK               (0x1 << 7)
+#define DA7218_HPF_MODE_SHIFT                  0
+#define DA7218_HPF_DISABLED                    ((0x0 << 3) | (0x0 << 7))
+#define DA7218_HPF_AUDIO_EN                    ((0x0 << 3) | (0x1 << 7))
+#define DA7218_HPF_VOICE_EN                    ((0x1 << 3) | (0x1 << 7))
+#define DA7218_HPF_MODE_MASK                   ((0x1 << 3) | (0x1 << 7))
+#define DA7218_HPF_MODE_MAX                    3
+
+/* DA7218_OUT_1_EQ_12_FILTER_CTRL = 0x25 */
+#define DA7218_OUT_1_EQ_BAND1_SHIFT    0
+#define DA7218_OUT_1_EQ_BAND1_MASK     (0xF << 0)
+#define DA7218_OUT_EQ_BAND_MAX         0xF
+#define DA7218_OUT_1_EQ_BAND2_SHIFT    4
+#define DA7218_OUT_1_EQ_BAND2_MASK     (0xF << 4)
+
+/* DA7218_OUT_1_EQ_34_FILTER_CTRL = 0x26 */
+#define DA7218_OUT_1_EQ_BAND3_SHIFT    0
+#define DA7218_OUT_1_EQ_BAND3_MASK     (0xF << 0)
+#define DA7218_OUT_1_EQ_BAND4_SHIFT    4
+#define DA7218_OUT_1_EQ_BAND4_MASK     (0xF << 4)
+
+/* DA7218_OUT_1_EQ_5_FILTER_CTRL = 0x27 */
+#define DA7218_OUT_1_EQ_BAND5_SHIFT    0
+#define DA7218_OUT_1_EQ_BAND5_MASK     (0xF << 0)
+#define DA7218_OUT_1_EQ_EN_SHIFT       7
+#define DA7218_OUT_1_EQ_EN_MASK                (0x1 << 7)
+
+/* DA7218_OUT_1_BIQ_5STAGE_CTRL = 0x28 */
+#define DA7218_OUT_1_BIQ_5STAGE_MUTE_EN_SHIFT  6
+#define DA7218_OUT_1_BIQ_5STAGE_MUTE_EN_MASK   (0x1 << 6)
+#define DA7218_OUT_1_BIQ_5STAGE_FILTER_EN_SHIFT        7
+#define DA7218_OUT_1_BIQ_5STAGE_FILTER_EN_MASK (0x1 << 7)
+
+/* DA7218_OUT_1_BIQ_5STAGE_DATA = 0x29 */
+#define DA7218_OUT_1_BIQ_5STAGE_DATA_SHIFT     0
+#define DA7218_OUT_1_BIQ_5STAGE_DATA_MASK      (0xFF << 0)
+
+/* DA7218_OUT_1_BIQ_5STAGE_ADDR = 0x2A */
+#define DA7218_OUT_1_BIQ_5STAGE_ADDR_SHIFT     0
+#define DA7218_OUT_1_BIQ_5STAGE_ADDR_MASK      (0x3F << 0)
+#define DA7218_OUT_1_BIQ_5STAGE_CFG_SIZE       50
+
+/* DA7218_MIXIN_1_CTRL = 0x2C */
+#define DA7218_MIXIN_1_MIX_SEL_SHIFT           3
+#define DA7218_MIXIN_1_MIX_SEL_MASK            (0x1 << 3)
+#define DA7218_MIXIN_1_AMP_ZC_EN_SHIFT         4
+#define DA7218_MIXIN_1_AMP_ZC_EN_MASK          (0x1 << 4)
+#define DA7218_MIXIN_1_AMP_RAMP_EN_SHIFT       5
+#define DA7218_MIXIN_1_AMP_RAMP_EN_MASK                (0x1 << 5)
+#define DA7218_MIXIN_1_AMP_MUTE_EN_SHIFT       6
+#define DA7218_MIXIN_1_AMP_MUTE_EN_MASK                (0x1 << 6)
+#define DA7218_MIXIN_1_AMP_EN_SHIFT            7
+#define DA7218_MIXIN_1_AMP_EN_MASK             (0x1 << 7)
+
+/* DA7218_MIXIN_1_GAIN = 0x2D */
+#define DA7218_MIXIN_1_AMP_GAIN_SHIFT  0
+#define DA7218_MIXIN_1_AMP_GAIN_MASK   (0xF << 0)
+#define DA7218_MIXIN_AMP_GAIN_MAX      0xF
+
+/* DA7218_MIXIN_2_CTRL = 0x2E */
+#define DA7218_MIXIN_2_MIX_SEL_SHIFT           3
+#define DA7218_MIXIN_2_MIX_SEL_MASK            (0x1 << 3)
+#define DA7218_MIXIN_2_AMP_ZC_EN_SHIFT         4
+#define DA7218_MIXIN_2_AMP_ZC_EN_MASK          (0x1 << 4)
+#define DA7218_MIXIN_2_AMP_RAMP_EN_SHIFT       5
+#define DA7218_MIXIN_2_AMP_RAMP_EN_MASK                (0x1 << 5)
+#define DA7218_MIXIN_2_AMP_MUTE_EN_SHIFT       6
+#define DA7218_MIXIN_2_AMP_MUTE_EN_MASK                (0x1 << 6)
+#define DA7218_MIXIN_2_AMP_EN_SHIFT            7
+#define DA7218_MIXIN_2_AMP_EN_MASK             (0x1 << 7)
+
+/* DA7218_MIXIN_2_GAIN = 0x2F */
+#define DA7218_MIXIN_2_AMP_GAIN_SHIFT  0
+#define DA7218_MIXIN_2_AMP_GAIN_MASK   (0xF << 0)
+
+/* DA7218_ALC_CTRL1 = 0x30 */
+#define DA7218_ALC_EN_SHIFT            0
+#define DA7218_ALC_EN_MASK             (0xF << 0)
+#define DA7218_ALC_CHAN1_L_EN_SHIFT    0
+#define DA7218_ALC_CHAN1_R_EN_SHIFT    1
+#define DA7218_ALC_CHAN2_L_EN_SHIFT    2
+#define DA7218_ALC_CHAN2_R_EN_SHIFT    3
+#define DA7218_ALC_SYNC_MODE_SHIFT     4
+#define DA7218_ALC_SYNC_MODE_MASK      (0xF << 4)
+#define DA7218_ALC_SYNC_MODE_CH1       (0x1 << 4)
+#define DA7218_ALC_SYNC_MODE_CH2       (0x4 << 4)
+
+/* DA7218_ALC_CTRL2 = 0x31 */
+#define DA7218_ALC_ATTACK_SHIFT                0
+#define DA7218_ALC_ATTACK_MASK         (0xF << 0)
+#define DA7218_ALC_ATTACK_MAX          13
+#define DA7218_ALC_RELEASE_SHIFT       4
+#define DA7218_ALC_RELEASE_MASK                (0xF << 4)
+#define DA7218_ALC_RELEASE_MAX         11
+
+/* DA7218_ALC_CTRL3 = 0x32 */
+#define DA7218_ALC_HOLD_SHIFT  0
+#define DA7218_ALC_HOLD_MASK   (0xF << 0)
+#define DA7218_ALC_HOLD_MAX    16
+
+/* DA7218_ALC_NOISE = 0x33 */
+#define DA7218_ALC_NOISE_SHIFT         0
+#define DA7218_ALC_NOISE_MASK          (0x3F << 0)
+#define DA7218_ALC_THRESHOLD_MAX       0x3F
+
+/* DA7218_ALC_TARGET_MIN = 0x34 */
+#define DA7218_ALC_THRESHOLD_MIN_SHIFT 0
+#define DA7218_ALC_THRESHOLD_MIN_MASK  (0x3F << 0)
+
+/* DA7218_ALC_TARGET_MAX = 0x35 */
+#define DA7218_ALC_THRESHOLD_MAX_SHIFT 0
+#define DA7218_ALC_THRESHOLD_MAX_MASK  (0x3F << 0)
+
+/* DA7218_ALC_GAIN_LIMITS = 0x36 */
+#define DA7218_ALC_ATTEN_MAX_SHIFT     0
+#define DA7218_ALC_ATTEN_MAX_MASK      (0xF << 0)
+#define DA7218_ALC_ATTEN_GAIN_MAX      0xF
+#define DA7218_ALC_GAIN_MAX_SHIFT      4
+#define DA7218_ALC_GAIN_MAX_MASK       (0xF << 4)
+
+/* DA7218_ALC_ANA_GAIN_LIMITS = 0x37 */
+#define DA7218_ALC_ANA_GAIN_MIN_SHIFT  0
+#define DA7218_ALC_ANA_GAIN_MIN_MASK   (0x7 << 0)
+#define DA7218_ALC_ANA_GAIN_MIN                0x1
+#define DA7218_ALC_ANA_GAIN_MAX                0x7
+#define DA7218_ALC_ANA_GAIN_MAX_SHIFT  4
+#define DA7218_ALC_ANA_GAIN_MAX_MASK   (0x7 << 4)
+
+/* DA7218_ALC_ANTICLIP_CTRL = 0x38 */
+#define DA7218_ALC_ANTICLIP_STEP_SHIFT 0
+#define DA7218_ALC_ANTICLIP_STEP_MASK  (0x3 << 0)
+#define DA7218_ALC_ANTICLIP_STEP_MAX   4
+#define DA7218_ALC_ANTICLIP_EN_SHIFT   7
+#define DA7218_ALC_ANTICLIP_EN_MASK    (0x1 << 7)
+
+/* DA7218_AGS_ENABLE = 0x3C */
+#define DA7218_AGS_ENABLE_SHIFT                0
+#define DA7218_AGS_ENABLE_MASK         (0x3 << 0)
+#define DA7218_AGS_ENABLE_CHAN1_SHIFT  0
+#define DA7218_AGS_ENABLE_CHAN2_SHIFT  1
+
+/* DA7218_AGS_TRIGGER = 0x3D */
+#define DA7218_AGS_TRIGGER_SHIFT       0
+#define DA7218_AGS_TRIGGER_MASK                (0xF << 0)
+#define DA7218_AGS_TRIGGER_MAX         0xF
+
+/* DA7218_AGS_ATT_MAX = 0x3E */
+#define DA7218_AGS_ATT_MAX_SHIFT       0
+#define DA7218_AGS_ATT_MAX_MASK                (0x7 << 0)
+#define DA7218_AGS_ATT_MAX_MAX         0x7
+
+/* DA7218_AGS_TIMEOUT = 0x3F */
+#define DA7218_AGS_TIMEOUT_EN_SHIFT    0
+#define DA7218_AGS_TIMEOUT_EN_MASK     (0x1 << 0)
+
+/* DA7218_AGS_ANTICLIP_CTRL = 0x40 */
+#define DA7218_AGS_ANTICLIP_EN_SHIFT   7
+#define DA7218_AGS_ANTICLIP_EN_MASK    (0x1 << 7)
+
+/* DA7218_CALIB_CTRL = 0x44 */
+#define DA7218_CALIB_OFFSET_EN_SHIFT   0
+#define DA7218_CALIB_OFFSET_EN_MASK    (0x1 << 0)
+#define DA7218_CALIB_AUTO_EN_SHIFT     2
+#define DA7218_CALIB_AUTO_EN_MASK      (0x1 << 2)
+#define DA7218_CALIB_OVERFLOW_SHIFT    3
+#define DA7218_CALIB_OVERFLOW_MASK     (0x1 << 3)
+
+/* DA7218_CALIB_OFFSET_AUTO_M_1 = 0x45 */
+#define DA7218_CALIB_OFFSET_AUTO_M_1_SHIFT     0
+#define DA7218_CALIB_OFFSET_AUTO_M_1_MASK      (0xFF << 0)
+
+/* DA7218_CALIB_OFFSET_AUTO_U_1 = 0x46 */
+#define DA7218_CALIB_OFFSET_AUTO_U_1_SHIFT     0
+#define DA7218_CALIB_OFFSET_AUTO_U_1_MASK      (0xF << 0)
+
+/* DA7218_CALIB_OFFSET_AUTO_M_2 = 0x47 */
+#define DA7218_CALIB_OFFSET_AUTO_M_2_SHIFT     0
+#define DA7218_CALIB_OFFSET_AUTO_M_2_MASK      (0xFF << 0)
+
+/* DA7218_CALIB_OFFSET_AUTO_U_2 = 0x48 */
+#define DA7218_CALIB_OFFSET_AUTO_U_2_SHIFT     0
+#define DA7218_CALIB_OFFSET_AUTO_U_2_MASK      (0xF << 0)
+
+/* DA7218_ENV_TRACK_CTRL = 0x4C */
+#define DA7218_INTEG_ATTACK_SHIFT      0
+#define DA7218_INTEG_ATTACK_MASK       (0x3 << 0)
+#define DA7218_INTEG_RELEASE_SHIFT     4
+#define DA7218_INTEG_RELEASE_MASK      (0x3 << 4)
+#define DA7218_INTEG_MAX               4
+
+/* DA7218_LVL_DET_CTRL = 0x50 */
+#define DA7218_LVL_DET_EN_SHIFT                0
+#define DA7218_LVL_DET_EN_MASK         (0xF << 0)
+#define DA7218_LVL_DET_EN_CHAN1L_SHIFT 0
+#define DA7218_LVL_DET_EN_CHAN1R_SHIFT 1
+#define DA7218_LVL_DET_EN_CHAN2L_SHIFT 2
+#define DA7218_LVL_DET_EN_CHAN2R_SHIFT 3
+
+/* DA7218_LVL_DET_LEVEL = 0x51 */
+#define DA7218_LVL_DET_LEVEL_SHIFT     0
+#define DA7218_LVL_DET_LEVEL_MASK      (0x7F << 0)
+#define DA7218_LVL_DET_LEVEL_MAX       0x7F
+
+/* DA7218_DGS_TRIGGER = 0x54 */
+#define DA7218_DGS_TRIGGER_LVL_SHIFT   0
+#define DA7218_DGS_TRIGGER_LVL_MASK    (0x3F << 0)
+#define DA7218_DGS_TRIGGER_MAX         0x3F
+
+/* DA7218_DGS_ENABLE = 0x55 */
+#define DA7218_DGS_ENABLE_SHIFT                0
+#define DA7218_DGS_ENABLE_MASK         (0x3 << 0)
+#define DA7218_DGS_ENABLE_L_SHIFT      0
+#define DA7218_DGS_ENABLE_R_SHIFT      1
+
+/* DA7218_DGS_RISE_FALL = 0x56 */
+#define DA7218_DGS_RISE_COEFF_SHIFT    0
+#define DA7218_DGS_RISE_COEFF_MASK     (0x7 << 0)
+#define DA7218_DGS_RISE_COEFF_MAX      7
+#define DA7218_DGS_FALL_COEFF_SHIFT    4
+#define DA7218_DGS_FALL_COEFF_MASK     (0x7 << 4)
+#define DA7218_DGS_FALL_COEFF_MAX      8
+
+/* DA7218_DGS_SYNC_DELAY = 0x57 */
+#define DA7218_DGS_SYNC_DELAY_SHIFT    0
+#define DA7218_DGS_SYNC_DELAY_MASK     (0xFF << 0)
+#define DA7218_DGS_SYNC_DELAY_MAX      0xFF
+
+/* DA7218_DGS_SYNC_DELAY2 = 0x58 */
+#define DA7218_DGS_SYNC_DELAY2_SHIFT   0
+#define DA7218_DGS_SYNC_DELAY2_MASK    (0xFF << 0)
+
+/* DA7218_DGS_SYNC_DELAY3 = 0x59 */
+#define DA7218_DGS_SYNC_DELAY3_SHIFT   0
+#define DA7218_DGS_SYNC_DELAY3_MASK    (0x7F << 0)
+#define DA7218_DGS_SYNC_DELAY3_MAX     0x7F
+
+/* DA7218_DGS_LEVELS = 0x5A */
+#define DA7218_DGS_ANTICLIP_LVL_SHIFT  0
+#define DA7218_DGS_ANTICLIP_LVL_MASK   (0x7 << 0)
+#define DA7218_DGS_ANTICLIP_LVL_MAX    0x7
+#define DA7218_DGS_SIGNAL_LVL_SHIFT    4
+#define DA7218_DGS_SIGNAL_LVL_MASK     (0xF << 4)
+#define DA7218_DGS_SIGNAL_LVL_MAX      0xF
+
+/* DA7218_DGS_GAIN_CTRL = 0x5B */
+#define DA7218_DGS_STEPS_SHIFT         0
+#define DA7218_DGS_STEPS_MASK          (0x1F << 0)
+#define DA7218_DGS_STEPS_MAX           0x1F
+#define DA7218_DGS_RAMP_EN_SHIFT       5
+#define DA7218_DGS_RAMP_EN_MASK                (0x1 << 5)
+#define DA7218_DGS_SUBR_EN_SHIFT       6
+#define DA7218_DGS_SUBR_EN_MASK                (0x1 << 6)
+
+/* DA7218_DROUTING_OUTDAI_1L = 0x5C */
+#define DA7218_OUTDAI_1L_SRC_SHIFT     0
+#define DA7218_OUTDAI_1L_SRC_MASK      (0x7F << 0)
+#define DA7218_DMIX_SRC_INFILT1L       0
+#define DA7218_DMIX_SRC_INFILT1R       1
+#define DA7218_DMIX_SRC_INFILT2L       2
+#define DA7218_DMIX_SRC_INFILT2R       3
+#define DA7218_DMIX_SRC_TONEGEN                4
+#define DA7218_DMIX_SRC_DAIL           5
+#define DA7218_DMIX_SRC_DAIR           6
+
+/* DA7218_DMIX_OUTDAI_1L_INFILT_1L_GAIN = 0x5D */
+#define DA7218_OUTDAI_1L_INFILT_1L_GAIN_SHIFT  0
+#define DA7218_OUTDAI_1L_INFILT_1L_GAIN_MASK   (0x1F << 0)
+#define DA7218_DMIX_GAIN_MAX                   0x1F
+
+/* DA7218_DMIX_OUTDAI_1L_INFILT_1R_GAIN = 0x5E */
+#define DA7218_OUTDAI_1L_INFILT_1R_GAIN_SHIFT  0
+#define DA7218_OUTDAI_1L_INFILT_1R_GAIN_MASK   (0x1F << 0)
+
+/* DA7218_DMIX_OUTDAI_1L_INFILT_2L_GAIN = 0x5F */
+#define DA7218_OUTDAI_1L_INFILT_2L_GAIN_SHIFT  0
+#define DA7218_OUTDAI_1L_INFILT_2L_GAIN_MASK   (0x1F << 0)
+
+/* DA7218_DMIX_OUTDAI_1L_INFILT_2R_GAIN = 0x60 */
+#define DA7218_OUTDAI_1L_INFILT_2R_GAIN_SHIFT  0
+#define DA7218_OUTDAI_1L_INFILT_2R_GAIN_MASK   (0x1F << 0)
+
+/* DA7218_DMIX_OUTDAI_1L_TONEGEN_GAIN = 0x61 */
+#define DA7218_OUTDAI_1L_TONEGEN_GAIN_SHIFT    0
+#define DA7218_OUTDAI_1L_TONEGEN_GAIN_MASK     (0x1F << 0)
+
+/* DA7218_DMIX_OUTDAI_1L_INDAI_1L_GAIN = 0x62 */
+#define DA7218_OUTDAI_1L_INDAI_1L_GAIN_SHIFT   0
+#define DA7218_OUTDAI_1L_INDAI_1L_GAIN_MASK    (0x1F << 0)
+
+/* DA7218_DMIX_OUTDAI_1L_INDAI_1R_GAIN = 0x63 */
+#define DA7218_OUTDAI_1L_INDAI_1R_GAIN_SHIFT   0
+#define DA7218_OUTDAI_1L_INDAI_1R_GAIN_MASK    (0x1F << 0)
+
+/* DA7218_DROUTING_OUTDAI_1R = 0x64 */
+#define DA7218_OUTDAI_1R_SRC_SHIFT     0
+#define DA7218_OUTDAI_1R_SRC_MASK      (0x7F << 0)
+
+/* DA7218_DMIX_OUTDAI_1R_INFILT_1L_GAIN = 0x65 */
+#define DA7218_OUTDAI_1R_INFILT_1L_GAIN_SHIFT  0
+#define DA7218_OUTDAI_1R_INFILT_1L_GAIN_MASK   (0x1F << 0)
+
+/* DA7218_DMIX_OUTDAI_1R_INFILT_1R_GAIN = 0x66 */
+#define DA7218_OUTDAI_1R_INFILT_1R_GAIN_SHIFT  0
+#define DA7218_OUTDAI_1R_INFILT_1R_GAIN_MASK   (0x1F << 0)
+
+/* DA7218_DMIX_OUTDAI_1R_INFILT_2L_GAIN = 0x67 */
+#define DA7218_OUTDAI_1R_INFILT_2L_GAIN_SHIFT  0
+#define DA7218_OUTDAI_1R_INFILT_2L_GAIN_MASK   (0x1F << 0)
+
+/* DA7218_DMIX_OUTDAI_1R_INFILT_2R_GAIN = 0x68 */
+#define DA7218_OUTDAI_1R_INFILT_2R_GAIN_SHIFT  0
+#define DA7218_OUTDAI_1R_INFILT_2R_GAIN_MASK   (0x1F << 0)
+
+/* DA7218_DMIX_OUTDAI_1R_TONEGEN_GAIN = 0x69 */
+#define DA7218_OUTDAI_1R_TONEGEN_GAIN_SHIFT    0
+#define DA7218_OUTDAI_1R_TONEGEN_GAIN_MASK     (0x1F << 0)
+
+/* DA7218_DMIX_OUTDAI_1R_INDAI_1L_GAIN = 0x6A */
+#define DA7218_OUTDAI_1R_INDAI_1L_GAIN_SHIFT   0
+#define DA7218_OUTDAI_1R_INDAI_1L_GAIN_MASK    (0x1F << 0)
+
+/* DA7218_DMIX_OUTDAI_1R_INDAI_1R_GAIN = 0x6B */
+#define DA7218_OUTDAI_1R_INDAI_1R_GAIN_SHIFT   0
+#define DA7218_OUTDAI_1R_INDAI_1R_GAIN_MASK    (0x1F << 0)
+
+/* DA7218_DROUTING_OUTFILT_1L = 0x6C */
+#define DA7218_OUTFILT_1L_SRC_SHIFT    0
+#define DA7218_OUTFILT_1L_SRC_MASK     (0x7F << 0)
+
+/* DA7218_DMIX_OUTFILT_1L_INFILT_1L_GAIN = 0x6D */
+#define DA7218_OUTFILT_1L_INFILT_1L_GAIN_SHIFT 0
+#define DA7218_OUTFILT_1L_INFILT_1L_GAIN_MASK  (0x1F << 0)
+
+/* DA7218_DMIX_OUTFILT_1L_INFILT_1R_GAIN = 0x6E */
+#define DA7218_OUTFILT_1L_INFILT_1R_GAIN_SHIFT 0
+#define DA7218_OUTFILT_1L_INFILT_1R_GAIN_MASK  (0x1F << 0)
+
+/* DA7218_DMIX_OUTFILT_1L_INFILT_2L_GAIN = 0x6F */
+#define DA7218_OUTFILT_1L_INFILT_2L_GAIN_SHIFT 0
+#define DA7218_OUTFILT_1L_INFILT_2L_GAIN_MASK  (0x1F << 0)
+
+/* DA7218_DMIX_OUTFILT_1L_INFILT_2R_GAIN = 0x70 */
+#define DA7218_OUTFILT_1L_INFILT_2R_GAIN_SHIFT 0
+#define DA7218_OUTFILT_1L_INFILT_2R_GAIN_MASK  (0x1F << 0)
+
+/* DA7218_DMIX_OUTFILT_1L_TONEGEN_GAIN = 0x71 */
+#define DA7218_OUTFILT_1L_TONEGEN_GAIN_SHIFT   0
+#define DA7218_OUTFILT_1L_TONEGEN_GAIN_MASK    (0x1F << 0)
+
+/* DA7218_DMIX_OUTFILT_1L_INDAI_1L_GAIN = 0x72 */
+#define DA7218_OUTFILT_1L_INDAI_1L_GAIN_SHIFT  0
+#define DA7218_OUTFILT_1L_INDAI_1L_GAIN_MASK   (0x1F << 0)
+
+/* DA7218_DMIX_OUTFILT_1L_INDAI_1R_GAIN = 0x73 */
+#define DA7218_OUTFILT_1L_INDAI_1R_GAIN_SHIFT  0
+#define DA7218_OUTFILT_1L_INDAI_1R_GAIN_MASK   (0x1F << 0)
+
+/* DA7218_DROUTING_OUTFILT_1R = 0x74 */
+#define DA7218_OUTFILT_1R_SRC_SHIFT    0
+#define DA7218_OUTFILT_1R_SRC_MASK     (0x7F << 0)
+
+/* DA7218_DMIX_OUTFILT_1R_INFILT_1L_GAIN = 0x75 */
+#define DA7218_OUTFILT_1R_INFILT_1L_GAIN_SHIFT 0
+#define DA7218_OUTFILT_1R_INFILT_1L_GAIN_MASK  (0x1F << 0)
+
+/* DA7218_DMIX_OUTFILT_1R_INFILT_1R_GAIN = 0x76 */
+#define DA7218_OUTFILT_1R_INFILT_1R_GAIN_SHIFT 0
+#define DA7218_OUTFILT_1R_INFILT_1R_GAIN_MASK  (0x1F << 0)
+
+/* DA7218_DMIX_OUTFILT_1R_INFILT_2L_GAIN = 0x77 */
+#define DA7218_OUTFILT_1R_INFILT_2L_GAIN_SHIFT 0
+#define DA7218_OUTFILT_1R_INFILT_2L_GAIN_MASK  (0x1F << 0)
+
+/* DA7218_DMIX_OUTFILT_1R_INFILT_2R_GAIN = 0x78 */
+#define DA7218_OUTFILT_1R_INFILT_2R_GAIN_SHIFT 0
+#define DA7218_OUTFILT_1R_INFILT_2R_GAIN_MASK  (0x1F << 0)
+
+/* DA7218_DMIX_OUTFILT_1R_TONEGEN_GAIN = 0x79 */
+#define DA7218_OUTFILT_1R_TONEGEN_GAIN_SHIFT   0
+#define DA7218_OUTFILT_1R_TONEGEN_GAIN_MASK    (0x1F << 0)
+
+/* DA7218_DMIX_OUTFILT_1R_INDAI_1L_GAIN = 0x7A */
+#define DA7218_OUTFILT_1R_INDAI_1L_GAIN_SHIFT  0
+#define DA7218_OUTFILT_1R_INDAI_1L_GAIN_MASK   (0x1F << 0)
+
+/* DA7218_DMIX_OUTFILT_1R_INDAI_1R_GAIN = 0x7B */
+#define DA7218_OUTFILT_1R_INDAI_1R_GAIN_SHIFT  0
+#define DA7218_OUTFILT_1R_INDAI_1R_GAIN_MASK   (0x1F << 0)
+
+/* DA7218_DROUTING_OUTDAI_2L = 0x7C */
+#define DA7218_OUTDAI_2L_SRC_SHIFT     0
+#define DA7218_OUTDAI_2L_SRC_MASK      (0x7F << 0)
+
+/* DA7218_DMIX_OUTDAI_2L_INFILT_1L_GAIN = 0x7D */
+#define DA7218_OUTDAI_2L_INFILT_1L_GAIN_SHIFT  0
+#define DA7218_OUTDAI_2L_INFILT_1L_GAIN_MASK   (0x1F << 0)
+
+/* DA7218_DMIX_OUTDAI_2L_INFILT_1R_GAIN = 0x7E */
+#define DA7218_OUTDAI_2L_INFILT_1R_GAIN_SHIFT  0
+#define DA7218_OUTDAI_2L_INFILT_1R_GAIN_MASK   (0x1F << 0)
+
+/* DA7218_DMIX_OUTDAI_2L_INFILT_2L_GAIN = 0x7F */
+#define DA7218_OUTDAI_2L_INFILT_2L_GAIN_SHIFT  0
+#define DA7218_OUTDAI_2L_INFILT_2L_GAIN_MASK   (0x1F << 0)
+
+/* DA7218_DMIX_OUTDAI_2L_INFILT_2R_GAIN = 0x80 */
+#define DA7218_OUTDAI_2L_INFILT_2R_GAIN_SHIFT  0
+#define DA7218_OUTDAI_2L_INFILT_2R_GAIN_MASK   (0x1F << 0)
+
+/* DA7218_DMIX_OUTDAI_2L_TONEGEN_GAIN = 0x81 */
+#define DA7218_OUTDAI_2L_TONEGEN_GAIN_SHIFT    0
+#define DA7218_OUTDAI_2L_TONEGEN_GAIN_MASK     (0x1F << 0)
+
+/* DA7218_DMIX_OUTDAI_2L_INDAI_1L_GAIN = 0x82 */
+#define DA7218_OUTDAI_2L_INDAI_1L_GAIN_SHIFT   0
+#define DA7218_OUTDAI_2L_INDAI_1L_GAIN_MASK    (0x1F << 0)
+
+/* DA7218_DMIX_OUTDAI_2L_INDAI_1R_GAIN = 0x83 */
+#define DA7218_OUTDAI_2L_INDAI_1R_GAIN_SHIFT   0
+#define DA7218_OUTDAI_2L_INDAI_1R_GAIN_MASK    (0x1F << 0)
+
+/* DA7218_DROUTING_OUTDAI_2R = 0x84 */
+#define DA7218_OUTDAI_2R_SRC_SHIFT     0
+#define DA7218_OUTDAI_2R_SRC_MASK      (0x7F << 0)
+
+/* DA7218_DMIX_OUTDAI_2R_INFILT_1L_GAIN = 0x85 */
+#define DA7218_OUTDAI_2R_INFILT_1L_GAIN_SHIFT  0
+#define DA7218_OUTDAI_2R_INFILT_1L_GAIN_MASK   (0x1F << 0)
+
+/* DA7218_DMIX_OUTDAI_2R_INFILT_1R_GAIN = 0x86 */
+#define DA7218_OUTDAI_2R_INFILT_1R_GAIN_SHIFT  0
+#define DA7218_OUTDAI_2R_INFILT_1R_GAIN_MASK   (0x1F << 0)
+
+/* DA7218_DMIX_OUTDAI_2R_INFILT_2L_GAIN = 0x87 */
+#define DA7218_OUTDAI_2R_INFILT_2L_GAIN_SHIFT  0
+#define DA7218_OUTDAI_2R_INFILT_2L_GAIN_MASK   (0x1F << 0)
+
+/* DA7218_DMIX_OUTDAI_2R_INFILT_2R_GAIN = 0x88 */
+#define DA7218_OUTDAI_2R_INFILT_2R_GAIN_SHIFT  0
+#define DA7218_OUTDAI_2R_INFILT_2R_GAIN_MASK   (0x1F << 0)
+
+/* DA7218_DMIX_OUTDAI_2R_TONEGEN_GAIN = 0x89 */
+#define DA7218_OUTDAI_2R_TONEGEN_GAIN_SHIFT    0
+#define DA7218_OUTDAI_2R_TONEGEN_GAIN_MASK     (0x1F << 0)
+
+/* DA7218_DMIX_OUTDAI_2R_INDAI_1L_GAIN = 0x8A */
+#define DA7218_OUTDAI_2R_INDAI_1L_GAIN_SHIFT   0
+#define DA7218_OUTDAI_2R_INDAI_1L_GAIN_MASK    (0x1F << 0)
+
+/* DA7218_DMIX_OUTDAI_2R_INDAI_1R_GAIN = 0x8B */
+#define DA7218_OUTDAI_2R_INDAI_1R_GAIN_SHIFT   0
+#define DA7218_OUTDAI_2R_INDAI_1R_GAIN_MASK    (0x1F << 0)
+
+/* DA7218_DAI_CTRL = 0x8C */
+#define DA7218_DAI_FORMAT_SHIFT                0
+#define DA7218_DAI_FORMAT_MASK         (0x3 << 0)
+#define DA7218_DAI_FORMAT_I2S          (0x0 << 0)
+#define DA7218_DAI_FORMAT_LEFT_J       (0x1 << 0)
+#define DA7218_DAI_FORMAT_RIGHT_J      (0x2 << 0)
+#define DA7218_DAI_FORMAT_DSP          (0x3 << 0)
+#define DA7218_DAI_WORD_LENGTH_SHIFT   2
+#define DA7218_DAI_WORD_LENGTH_MASK    (0x3 << 2)
+#define DA7218_DAI_WORD_LENGTH_S16_LE  (0x0 << 2)
+#define DA7218_DAI_WORD_LENGTH_S20_LE  (0x1 << 2)
+#define DA7218_DAI_WORD_LENGTH_S24_LE  (0x2 << 2)
+#define DA7218_DAI_WORD_LENGTH_S32_LE  (0x3 << 2)
+#define DA7218_DAI_CH_NUM_SHIFT                4
+#define DA7218_DAI_CH_NUM_MASK         (0x7 << 4)
+#define DA7218_DAI_CH_NUM_MAX          4
+#define DA7218_DAI_EN_SHIFT            7
+#define DA7218_DAI_EN_MASK             (0x1 << 7)
+
+/* DA7218_DAI_TDM_CTRL = 0x8D */
+#define DA7218_DAI_TDM_CH_EN_SHIFT     0
+#define DA7218_DAI_TDM_CH_EN_MASK      (0xF << 0)
+#define DA7218_DAI_TDM_MAX_SLOTS       4
+#define DA7218_DAI_OE_SHIFT            6
+#define DA7218_DAI_OE_MASK             (0x1 << 6)
+#define DA7218_DAI_TDM_MODE_EN_SHIFT   7
+#define DA7218_DAI_TDM_MODE_EN_MASK    (0x1 << 7)
+
+/* DA7218_DAI_OFFSET_LOWER = 0x8E */
+#define DA7218_DAI_OFFSET_LOWER_SHIFT  0
+#define DA7218_DAI_OFFSET_LOWER_MASK   (0xFF << 0)
+
+/* DA7218_DAI_OFFSET_UPPER = 0x8F */
+#define DA7218_DAI_OFFSET_UPPER_SHIFT  0
+#define DA7218_DAI_OFFSET_UPPER_MASK   (0x7 << 0)
+
+/* DA7218_DAI_CLK_MODE = 0x90 */
+#define DA7218_DAI_BCLKS_PER_WCLK_SHIFT        0
+#define DA7218_DAI_BCLKS_PER_WCLK_MASK (0x3 << 0)
+#define DA7218_DAI_BCLKS_PER_WCLK_32   (0x0 << 0)
+#define DA7218_DAI_BCLKS_PER_WCLK_64   (0x1 << 0)
+#define DA7218_DAI_BCLKS_PER_WCLK_128  (0x2 << 0)
+#define DA7218_DAI_BCLKS_PER_WCLK_256  (0x3 << 0)
+#define DA7218_DAI_CLK_POL_SHIFT       2
+#define DA7218_DAI_CLK_POL_MASK                (0x1 << 2)
+#define DA7218_DAI_CLK_POL_INV         (0x1 << 2)
+#define DA7218_DAI_WCLK_POL_SHIFT      3
+#define DA7218_DAI_WCLK_POL_MASK       (0x1 << 3)
+#define DA7218_DAI_WCLK_POL_INV                (0x1 << 3)
+#define DA7218_DAI_WCLK_TRI_STATE_SHIFT        4
+#define DA7218_DAI_WCLK_TRI_STATE_MASK (0x1 << 4)
+#define DA7218_DAI_CLK_EN_SHIFT                7
+#define DA7218_DAI_CLK_EN_MASK         (0x1 << 7)
+
+/* DA7218_PLL_CTRL = 0x91 */
+#define DA7218_PLL_INDIV_SHIFT         0
+#define DA7218_PLL_INDIV_MASK          (0x7 << 0)
+#define DA7218_PLL_INDIV_2_5_MHZ       (0x0 << 0)
+#define DA7218_PLL_INDIV_5_10_MHZ      (0x1 << 0)
+#define DA7218_PLL_INDIV_10_20_MHZ     (0x2 << 0)
+#define DA7218_PLL_INDIV_20_40_MHZ     (0x3 << 0)
+#define DA7218_PLL_INDIV_40_54_MHZ     (0x4 << 0)
+#define DA7218_PLL_INDIV_2_10_MHZ_VAL  2
+#define DA7218_PLL_INDIV_10_20_MHZ_VAL 4
+#define DA7218_PLL_INDIV_20_40_MHZ_VAL 8
+#define DA7218_PLL_INDIV_40_54_MHZ_VAL 16
+#define DA7218_PLL_MCLK_SQR_EN_SHIFT   4
+#define DA7218_PLL_MCLK_SQR_EN_MASK    (0x1 << 4)
+#define DA7218_PLL_MODE_SHIFT          6
+#define DA7218_PLL_MODE_MASK           (0x3 << 6)
+#define DA7218_PLL_MODE_BYPASS         (0x0 << 6)
+#define DA7218_PLL_MODE_NORMAL         (0x1 << 6)
+#define DA7218_PLL_MODE_SRM            (0x2 << 6)
+#define DA7218_PLL_MODE_32KHZ          (0x3 << 6)
+
+/* DA7218_PLL_FRAC_TOP = 0x92 */
+#define DA7218_PLL_FBDIV_FRAC_TOP_SHIFT        0
+#define DA7218_PLL_FBDIV_FRAC_TOP_MASK (0x1F << 0)
+
+/* DA7218_PLL_FRAC_BOT = 0x93 */
+#define DA7218_PLL_FBDIV_FRAC_BOT_SHIFT        0
+#define DA7218_PLL_FBDIV_FRAC_BOT_MASK (0xFF << 0)
+
+/* DA7218_PLL_INTEGER = 0x94 */
+#define DA7218_PLL_FBDIV_INTEGER_SHIFT 0
+#define DA7218_PLL_FBDIV_INTEGER_MASK  (0x7F << 0)
+
+/* DA7218_PLL_STATUS = 0x95 */
+#define DA7218_PLL_SRM_STATUS_SHIFT    0
+#define DA7218_PLL_SRM_STATUS_MASK     (0xFF << 0)
+#define DA7218_PLL_SRM_STATUS_SRM_LOCK (0x1 << 7)
+
+/* DA7218_PLL_REFOSC_CAL = 0x98 */
+#define DA7218_PLL_REFOSC_CAL_CTRL_SHIFT       0
+#define DA7218_PLL_REFOSC_CAL_CTRL_MASK                (0x1F << 0)
+#define DA7218_PLL_REFOSC_CAL_START_SHIFT      6
+#define DA7218_PLL_REFOSC_CAL_START_MASK       (0x1 << 6)
+#define DA7218_PLL_REFOSC_CAL_EN_SHIFT         7
+#define DA7218_PLL_REFOSC_CAL_EN_MASK          (0x1 << 7)
+
+/* DA7218_DAC_NG_CTRL = 0x9C */
+#define DA7218_DAC_NG_EN_SHIFT 7
+#define DA7218_DAC_NG_EN_MASK  (0x1 << 7)
+
+/* DA7218_DAC_NG_SETUP_TIME = 0x9D */
+#define DA7218_DAC_NG_SETUP_TIME_SHIFT 0
+#define DA7218_DAC_NG_SETUP_TIME_MASK  (0x3 << 0)
+#define DA7218_DAC_NG_SETUP_TIME_MAX   4
+#define DA7218_DAC_NG_RAMPUP_RATE_SHIFT        2
+#define DA7218_DAC_NG_RAMPUP_RATE_MASK (0x1 << 2)
+#define DA7218_DAC_NG_RAMPUP_RATE_MAX  2
+#define DA7218_DAC_NG_RAMPDN_RATE_SHIFT        3
+#define DA7218_DAC_NG_RAMPDN_RATE_MASK (0x1 << 3)
+#define DA7218_DAC_NG_RAMPDN_RATE_MAX  2
+
+/* DA7218_DAC_NG_OFF_THRESH = 0x9E */
+#define DA7218_DAC_NG_OFF_THRESHOLD_SHIFT      0
+#define DA7218_DAC_NG_OFF_THRESHOLD_MASK       (0x7 << 0)
+#define DA7218_DAC_NG_THRESHOLD_MAX            0x7
+
+/* DA7218_DAC_NG_ON_THRESH = 0x9F */
+#define DA7218_DAC_NG_ON_THRESHOLD_SHIFT       0
+#define DA7218_DAC_NG_ON_THRESHOLD_MASK                (0x7 << 0)
+
+/* DA7218_TONE_GEN_CFG1 = 0xA0 */
+#define DA7218_DTMF_REG_SHIFT          0
+#define DA7218_DTMF_REG_MASK           (0xF << 0)
+#define DA7218_DTMF_REG_MAX            16
+#define DA7218_DTMF_EN_SHIFT           4
+#define DA7218_DTMF_EN_MASK            (0x1 << 4)
+#define DA7218_START_STOPN_SHIFT       7
+#define DA7218_START_STOPN_MASK                (0x1 << 7)
+
+/* DA7218_TONE_GEN_CFG2 = 0xA1 */
+#define DA7218_SWG_SEL_SHIFT   0
+#define DA7218_SWG_SEL_MASK    (0x3 << 0)
+#define DA7218_SWG_SEL_MAX     4
+
+/* DA7218_TONE_GEN_FREQ1_L = 0xA2 */
+#define DA7218_FREQ1_L_SHIFT   0
+#define DA7218_FREQ1_L_MASK    (0xFF << 0)
+#define DA7218_FREQ_MAX                0xFFFF
+
+/* DA7218_TONE_GEN_FREQ1_U = 0xA3 */
+#define DA7218_FREQ1_U_SHIFT   0
+#define DA7218_FREQ1_U_MASK    (0xFF << 0)
+
+/* DA7218_TONE_GEN_FREQ2_L = 0xA4 */
+#define DA7218_FREQ2_L_SHIFT   0
+#define DA7218_FREQ2_L_MASK    (0xFF << 0)
+
+/* DA7218_TONE_GEN_FREQ2_U = 0xA5 */
+#define DA7218_FREQ2_U_SHIFT   0
+#define DA7218_FREQ2_U_MASK    (0xFF << 0)
+
+/* DA7218_TONE_GEN_CYCLES = 0xA6 */
+#define DA7218_BEEP_CYCLES_SHIFT       0
+#define DA7218_BEEP_CYCLES_MASK                (0x7 << 0)
+
+/* DA7218_TONE_GEN_ON_PER = 0xA7 */
+#define DA7218_BEEP_ON_PER_SHIFT       0
+#define DA7218_BEEP_ON_PER_MASK                (0x3F << 0)
+
+/* DA7218_TONE_GEN_OFF_PER = 0xA8 */
+#define DA7218_BEEP_OFF_PER_SHIFT      0
+#define DA7218_BEEP_OFF_PER_MASK       (0x3F << 0)
+#define DA7218_BEEP_ON_OFF_MAX         0x3F
+
+/* DA7218_CP_CTRL = 0xAC */
+#define DA7218_CP_MOD_SHIFT                    2
+#define DA7218_CP_MOD_MASK                     (0x3 << 2)
+#define DA7218_CP_MCHANGE_SHIFT                        4
+#define DA7218_CP_MCHANGE_MASK                 (0x3 << 4)
+#define DA7218_CP_MCHANGE_REL_MASK             0x3
+#define DA7218_CP_MCHANGE_MAX                  3
+#define DA7218_CP_MCHANGE_LARGEST_VOL          0x1
+#define DA7218_CP_MCHANGE_DAC_VOL              0x2
+#define DA7218_CP_MCHANGE_SIG_MAG              0x3
+#define DA7218_CP_SMALL_SWITCH_FREQ_EN_SHIFT   6
+#define DA7218_CP_SMALL_SWITCH_FREQ_EN_MASK    (0x1 << 6)
+#define DA7218_CP_EN_SHIFT                     7
+#define DA7218_CP_EN_MASK                      (0x1 << 7)
+
+/* DA7218_CP_DELAY = 0xAD */
+#define DA7218_CP_FCONTROL_SHIFT       0
+#define DA7218_CP_FCONTROL_MASK                (0x7 << 0)
+#define DA7218_CP_FCONTROL_MAX         6
+#define DA7218_CP_TAU_DELAY_SHIFT      3
+#define DA7218_CP_TAU_DELAY_MASK       (0x7 << 3)
+#define DA7218_CP_TAU_DELAY_MAX                8
+
+/* DA7218_CP_VOL_THRESHOLD1 = 0xAE */
+#define DA7218_CP_THRESH_VDD2_SHIFT    0
+#define DA7218_CP_THRESH_VDD2_MASK     (0x3F << 0)
+#define DA7218_CP_THRESH_VDD2_MAX      0x3F
+
+/* DA7218_MIC_1_CTRL = 0xB4 */
+#define DA7218_MIC_1_AMP_MUTE_EN_SHIFT 6
+#define DA7218_MIC_1_AMP_MUTE_EN_MASK  (0x1 << 6)
+#define DA7218_MIC_1_AMP_EN_SHIFT      7
+#define DA7218_MIC_1_AMP_EN_MASK       (0x1 << 7)
+
+/* DA7218_MIC_1_GAIN = 0xB5 */
+#define DA7218_MIC_1_AMP_GAIN_SHIFT    0
+#define DA7218_MIC_1_AMP_GAIN_MASK     (0x7 << 0)
+#define DA7218_MIC_AMP_GAIN_MAX                0x7
+
+/* DA7218_MIC_1_SELECT = 0xB7 */
+#define DA7218_MIC_1_AMP_IN_SEL_SHIFT  0
+#define DA7218_MIC_1_AMP_IN_SEL_MASK   (0x3 << 0)
+
+/* DA7218_MIC_2_CTRL = 0xB8 */
+#define DA7218_MIC_2_AMP_MUTE_EN_SHIFT 6
+#define DA7218_MIC_2_AMP_MUTE_EN_MASK  (0x1 << 6)
+#define DA7218_MIC_2_AMP_EN_SHIFT      7
+#define DA7218_MIC_2_AMP_EN_MASK       (0x1 << 7)
+
+/* DA7218_MIC_2_GAIN = 0xB9 */
+#define DA7218_MIC_2_AMP_GAIN_SHIFT    0
+#define DA7218_MIC_2_AMP_GAIN_MASK     (0x7 << 0)
+
+/* DA7218_MIC_2_SELECT = 0xBB */
+#define DA7218_MIC_2_AMP_IN_SEL_SHIFT  0
+#define DA7218_MIC_2_AMP_IN_SEL_MASK   (0x3 << 0)
+
+/* DA7218_IN_1_HPF_FILTER_CTRL = 0xBC */
+#define DA7218_IN_1_VOICE_HPF_CORNER_SHIFT     0
+#define DA7218_IN_1_VOICE_HPF_CORNER_MASK      (0x7 << 0)
+#define DA7218_IN_VOICE_HPF_CORNER_MAX         8
+#define DA7218_IN_1_VOICE_EN_SHIFT             3
+#define DA7218_IN_1_VOICE_EN_MASK              (0x1 << 3)
+#define DA7218_IN_1_AUDIO_HPF_CORNER_SHIFT     4
+#define DA7218_IN_1_AUDIO_HPF_CORNER_MASK      (0x3 << 4)
+#define DA7218_IN_1_HPF_EN_SHIFT               7
+#define DA7218_IN_1_HPF_EN_MASK                        (0x1 << 7)
+
+/* DA7218_IN_2_HPF_FILTER_CTRL = 0xBD */
+#define DA7218_IN_2_VOICE_HPF_CORNER_SHIFT     0
+#define DA7218_IN_2_VOICE_HPF_CORNER_MASK      (0x7 << 0)
+#define DA7218_IN_2_VOICE_EN_SHIFT             3
+#define DA7218_IN_2_VOICE_EN_MASK              (0x1 << 3)
+#define DA7218_IN_2_AUDIO_HPF_CORNER_SHIFT     4
+#define DA7218_IN_2_AUDIO_HPF_CORNER_MASK      (0x3 << 4)
+#define DA7218_IN_2_HPF_EN_SHIFT               7
+#define DA7218_IN_2_HPF_EN_MASK                        (0x1 << 7)
+
+/* DA7218_ADC_1_CTRL = 0xC0 */
+#define DA7218_ADC_1_AAF_EN_SHIFT      2
+#define DA7218_ADC_1_AAF_EN_MASK       (0x1 << 2)
+
+/* DA7218_ADC_2_CTRL = 0xC1 */
+#define DA7218_ADC_2_AAF_EN_SHIFT      2
+#define DA7218_ADC_2_AAF_EN_MASK       (0x1 << 2)
+
+/* DA7218_ADC_MODE = 0xC2 */
+#define DA7218_ADC_LP_MODE_SHIFT               0
+#define DA7218_ADC_LP_MODE_MASK                        (0x1 << 0)
+#define DA7218_ADC_LVLDET_MODE_SHIFT           1
+#define DA7218_ADC_LVLDET_MODE_MASK            (0x1 << 1)
+#define DA7218_ADC_LVLDET_AUTO_EXIT_SHIFT      2
+#define DA7218_ADC_LVLDET_AUTO_EXIT_MASK       (0x1 << 2)
+
+/* DA7218_MIXOUT_L_CTRL = 0xCC */
+#define DA7218_MIXOUT_L_AMP_EN_SHIFT   7
+#define DA7218_MIXOUT_L_AMP_EN_MASK    (0x1 << 7)
+
+/* DA7218_MIXOUT_L_GAIN = 0xCD */
+#define DA7218_MIXOUT_L_AMP_GAIN_SHIFT 0
+#define DA7218_MIXOUT_L_AMP_GAIN_MASK  (0x3 << 0)
+#define DA7218_MIXOUT_AMP_GAIN_MIN     0x1
+#define DA7218_MIXOUT_AMP_GAIN_MAX     0x3
+
+/* DA7218_MIXOUT_R_CTRL = 0xCE */
+#define DA7218_MIXOUT_R_AMP_EN_SHIFT   7
+#define DA7218_MIXOUT_R_AMP_EN_MASK    (0x1 << 7)
+
+/* DA7218_MIXOUT_R_GAIN = 0xCF */
+#define DA7218_MIXOUT_R_AMP_GAIN_SHIFT 0
+#define DA7218_MIXOUT_R_AMP_GAIN_MASK  (0x3 << 0)
+
+/* DA7218_HP_L_CTRL = 0xD0 */
+#define DA7218_HP_L_AMP_MIN_GAIN_EN_SHIFT      2
+#define DA7218_HP_L_AMP_MIN_GAIN_EN_MASK       (0x1 << 2)
+#define DA7218_HP_L_AMP_OE_SHIFT               3
+#define DA7218_HP_L_AMP_OE_MASK                        (0x1 << 3)
+#define DA7218_HP_L_AMP_ZC_EN_SHIFT            4
+#define DA7218_HP_L_AMP_ZC_EN_MASK             (0x1 << 4)
+#define DA7218_HP_L_AMP_RAMP_EN_SHIFT          5
+#define DA7218_HP_L_AMP_RAMP_EN_MASK           (0x1 << 5)
+#define DA7218_HP_L_AMP_MUTE_EN_SHIFT          6
+#define DA7218_HP_L_AMP_MUTE_EN_MASK           (0x1 << 6)
+#define DA7218_HP_L_AMP_EN_SHIFT               7
+#define DA7218_HP_L_AMP_EN_MASK                        (0x1 << 7)
+#define DA7218_HP_AMP_OE_MASK                  (0x1 << 3)
+
+/* DA7218_HP_L_GAIN = 0xD1 */
+#define DA7218_HP_L_AMP_GAIN_SHIFT     0
+#define DA7218_HP_L_AMP_GAIN_MASK      (0x3F << 0)
+#define DA7218_HP_AMP_GAIN_MIN         0x15
+#define DA7218_HP_AMP_GAIN_MAX         0x3F
+
+/* DA7218_HP_R_CTRL = 0xD2 */
+#define DA7218_HP_R_AMP_MIN_GAIN_EN_SHIFT      2
+#define DA7218_HP_R_AMP_MIN_GAIN_EN_MASK       (0x1 << 2)
+#define DA7218_HP_R_AMP_OE_SHIFT               3
+#define DA7218_HP_R_AMP_OE_MASK                        (0x1 << 3)
+#define DA7218_HP_R_AMP_ZC_EN_SHIFT            4
+#define DA7218_HP_R_AMP_ZC_EN_MASK             (0x1 << 4)
+#define DA7218_HP_R_AMP_RAMP_EN_SHIFT          5
+#define DA7218_HP_R_AMP_RAMP_EN_MASK           (0x1 << 5)
+#define DA7218_HP_R_AMP_MUTE_EN_SHIFT          6
+#define DA7218_HP_R_AMP_MUTE_EN_MASK           (0x1 << 6)
+#define DA7218_HP_R_AMP_EN_SHIFT               7
+#define DA7218_HP_R_AMP_EN_MASK                        (0x1 << 7)
+
+/* DA7218_HP_R_GAIN = 0xD3 */
+#define DA7218_HP_R_AMP_GAIN_SHIFT     0
+#define DA7218_HP_R_AMP_GAIN_MASK      (0x3F << 0)
+
+/* DA7218_HP_SNGL_CTRL = 0xD4 */
+#define DA7218_HP_AMP_STEREO_DETECT_STATUS_SHIFT       0
+#define DA7218_HP_AMP_STEREO_DETECT_STATUS_MASK                (0x1 << 0)
+#define DA7218_HPL_AMP_LOAD_DETECT_STATUS_SHIFT                1
+#define DA7218_HPL_AMP_LOAD_DETECT_STATUS_MASK         (0x1 << 1)
+#define DA7218_HPR_AMP_LOAD_DETECT_STATUS_SHIFT                2
+#define DA7218_HPR_AMP_LOAD_DETECT_STATUS_MASK         (0x1 << 2)
+#define DA7218_HP_AMP_LOAD_DETECT_EN_SHIFT             6
+#define DA7218_HP_AMP_LOAD_DETECT_EN_MASK              (0x1 << 6)
+#define DA7218_HP_AMP_STEREO_DETECT_EN_SHIFT           7
+#define DA7218_HP_AMP_STEREO_DETECT_EN_MASK            (0x1 << 7)
+
+/* DA7218_HP_DIFF_CTRL = 0xD5 */
+#define DA7218_HP_AMP_DIFF_MODE_EN_SHIFT       0
+#define DA7218_HP_AMP_DIFF_MODE_EN_MASK                (0x1 << 0)
+#define DA7218_HP_AMP_SINGLE_SUPPLY_EN_SHIFT   4
+#define DA7218_HP_AMP_SINGLE_SUPPLY_EN_MASK    (0x1 << 4)
+
+/* DA7218_HP_DIFF_UNLOCK = 0xD7 */
+#define DA7218_HP_DIFF_UNLOCK_SHIFT    0
+#define DA7218_HP_DIFF_UNLOCK_MASK     (0x1 << 0)
+#define DA7218_HP_DIFF_UNLOCK_VAL      0xC3
+
+/* DA7218_HPLDET_JACK = 0xD8 */
+#define DA7218_HPLDET_JACK_RATE_SHIFT          0
+#define DA7218_HPLDET_JACK_RATE_MASK           (0x7 << 0)
+#define DA7218_HPLDET_JACK_DEBOUNCE_SHIFT      3
+#define DA7218_HPLDET_JACK_DEBOUNCE_MASK       (0x3 << 3)
+#define DA7218_HPLDET_JACK_THR_SHIFT           5
+#define DA7218_HPLDET_JACK_THR_MASK            (0x3 << 5)
+#define DA7218_HPLDET_JACK_EN_SHIFT            7
+#define DA7218_HPLDET_JACK_EN_MASK             (0x1 << 7)
+
+/* DA7218_HPLDET_CTRL = 0xD9 */
+#define DA7218_HPLDET_COMP_INV_SHIFT           0
+#define DA7218_HPLDET_COMP_INV_MASK            (0x1 << 0)
+#define DA7218_HPLDET_HYST_EN_SHIFT            1
+#define DA7218_HPLDET_HYST_EN_MASK             (0x1 << 1)
+#define DA7218_HPLDET_DISCHARGE_EN_SHIFT       7
+#define DA7218_HPLDET_DISCHARGE_EN_MASK                (0x1 << 7)
+
+/* DA7218_HPLDET_TEST = 0xDA */
+#define DA7218_HPLDET_COMP_STS_SHIFT   4
+#define DA7218_HPLDET_COMP_STS_MASK    (0x1 << 4)
+
+/* DA7218_REFERENCES = 0xDC */
+#define DA7218_BIAS_EN_SHIFT   3
+#define DA7218_BIAS_EN_MASK    (0x1 << 3)
+
+/* DA7218_IO_CTRL = 0xE0 */
+#define DA7218_IO_VOLTAGE_LEVEL_SHIFT          0
+#define DA7218_IO_VOLTAGE_LEVEL_MASK           (0x1 << 0)
+#define DA7218_IO_VOLTAGE_LEVEL_2_5V_3_6V      0
+#define DA7218_IO_VOLTAGE_LEVEL_1_5V_2_5V      1
+
+/* DA7218_LDO_CTRL = 0xE1 */
+#define DA7218_LDO_LEVEL_SELECT_SHIFT  4
+#define DA7218_LDO_LEVEL_SELECT_MASK   (0x3 << 4)
+#define DA7218_LDO_EN_SHIFT            7
+#define DA7218_LDO_EN_MASK             (0x1 << 7)
+
+/* DA7218_SIDETONE_CTRL = 0xE4 */
+#define DA7218_SIDETONE_MUTE_EN_SHIFT  6
+#define DA7218_SIDETONE_MUTE_EN_MASK   (0x1 << 6)
+#define DA7218_SIDETONE_FILTER_EN_SHIFT        7
+#define DA7218_SIDETONE_FILTER_EN_MASK (0x1 << 7)
+
+/* DA7218_SIDETONE_IN_SELECT = 0xE5 */
+#define DA7218_SIDETONE_IN_SELECT_SHIFT        0
+#define DA7218_SIDETONE_IN_SELECT_MASK (0x3 << 0)
+#define DA7218_SIDETONE_IN_SELECT_MAX  4
+
+/* DA7218_SIDETONE_GAIN = 0xE6 */
+#define DA7218_SIDETONE_GAIN_SHIFT     0
+#define DA7218_SIDETONE_GAIN_MASK      (0x1F << 0)
+
+/* DA7218_DROUTING_ST_OUTFILT_1L = 0xE8 */
+#define DA7218_OUTFILT_ST_1L_SRC_SHIFT 0
+#define DA7218_OUTFILT_ST_1L_SRC_MASK  (0x7 << 0)
+#define DA7218_DMIX_ST_SRC_OUTFILT1L   0
+#define DA7218_DMIX_ST_SRC_OUTFILT1R   1
+#define DA7218_DMIX_ST_SRC_SIDETONE    2
+
+/* DA7218_DROUTING_ST_OUTFILT_1R = 0xE9 */
+#define DA7218_OUTFILT_ST_1R_SRC_SHIFT 0
+#define DA7218_OUTFILT_ST_1R_SRC_MASK  (0x7 << 0)
+
+/* DA7218_SIDETONE_BIQ_3STAGE_DATA = 0xEA */
+#define DA7218_SIDETONE_BIQ_3STAGE_DATA_SHIFT  0
+#define DA7218_SIDETONE_BIQ_3STAGE_DATA_MASK   (0xFF << 0)
+
+/* DA7218_SIDETONE_BIQ_3STAGE_ADDR = 0xEB */
+#define DA7218_SIDETONE_BIQ_3STAGE_ADDR_SHIFT  0
+#define DA7218_SIDETONE_BIQ_3STAGE_ADDR_MASK   (0x1F << 0)
+#define DA7218_SIDETONE_BIQ_3STAGE_CFG_SIZE    30
+
+/* DA7218_EVENT_STATUS = 0xEC */
+#define DA7218_HPLDET_JACK_STS_SHIFT   7
+#define DA7218_HPLDET_JACK_STS_MASK    (0x1 << 7)
+
+/* DA7218_EVENT = 0xED */
+#define DA7218_LVL_DET_EVENT_SHIFT     0
+#define DA7218_LVL_DET_EVENT_MASK      (0x1 << 0)
+#define DA7218_HPLDET_JACK_EVENT_SHIFT 7
+#define DA7218_HPLDET_JACK_EVENT_MASK  (0x1 << 7)
+
+/* DA7218_EVENT_MASK   = 0xEE */
+#define DA7218_LVL_DET_EVENT_MSK_SHIFT         0
+#define DA7218_LVL_DET_EVENT_MSK_MASK          (0x1 << 0)
+#define DA7218_HPLDET_JACK_EVENT_IRQ_MSK_SHIFT 7
+#define DA7218_HPLDET_JACK_EVENT_IRQ_MSK_MASK  (0x1 << 7)
+
+/* DA7218_DMIC_1_CTRL = 0xF0 */
+#define DA7218_DMIC_1_DATA_SEL_SHIFT   0
+#define DA7218_DMIC_1_DATA_SEL_MASK    (0x1 << 0)
+#define DA7218_DMIC_1_SAMPLEPHASE_SHIFT        1
+#define DA7218_DMIC_1_SAMPLEPHASE_MASK (0x1 << 1)
+#define DA7218_DMIC_1_CLK_RATE_SHIFT   2
+#define DA7218_DMIC_1_CLK_RATE_MASK    (0x1 << 2)
+#define DA7218_DMIC_1L_EN_SHIFT                6
+#define DA7218_DMIC_1L_EN_MASK         (0x1 << 6)
+#define DA7218_DMIC_1R_EN_SHIFT                7
+#define DA7218_DMIC_1R_EN_MASK         (0x1 << 7)
+
+/* DA7218_DMIC_2_CTRL = 0xF1 */
+#define DA7218_DMIC_2_DATA_SEL_SHIFT   0
+#define DA7218_DMIC_2_DATA_SEL_MASK    (0x1 << 0)
+#define DA7218_DMIC_2_SAMPLEPHASE_SHIFT        1
+#define DA7218_DMIC_2_SAMPLEPHASE_MASK (0x1 << 1)
+#define DA7218_DMIC_2_CLK_RATE_SHIFT   2
+#define DA7218_DMIC_2_CLK_RATE_MASK    (0x1 << 2)
+#define DA7218_DMIC_2L_EN_SHIFT                6
+#define DA7218_DMIC_2L_EN_MASK         (0x1 << 6)
+#define DA7218_DMIC_2R_EN_SHIFT                7
+#define DA7218_DMIC_2R_EN_MASK         (0x1 << 7)
+
+/* DA7218_IN_1L_GAIN = 0xF4 */
+#define DA7218_IN_1L_DIGITAL_GAIN_SHIFT        0
+#define DA7218_IN_1L_DIGITAL_GAIN_MASK (0x7F << 0)
+#define DA7218_IN_DIGITAL_GAIN_MAX     0x7F
+
+/* DA7218_IN_1R_GAIN = 0xF5 */
+#define DA7218_IN_1R_DIGITAL_GAIN_SHIFT        0
+#define DA7218_IN_1R_DIGITAL_GAIN_MASK (0x7F << 0)
+
+/* DA7218_IN_2L_GAIN = 0xF6 */
+#define DA7218_IN_2L_DIGITAL_GAIN_SHIFT        0
+#define DA7218_IN_2L_DIGITAL_GAIN_MASK (0x7F << 0)
+
+/* DA7218_IN_2R_GAIN = 0xF7 */
+#define DA7218_IN_2R_DIGITAL_GAIN_SHIFT        0
+#define DA7218_IN_2R_DIGITAL_GAIN_MASK (0x7F << 0)
+
+/* DA7218_OUT_1L_GAIN = 0xF8 */
+#define DA7218_OUT_1L_DIGITAL_GAIN_SHIFT       0
+#define DA7218_OUT_1L_DIGITAL_GAIN_MASK                (0xFF << 0)
+#define DA7218_OUT_DIGITAL_GAIN_MIN            0x0
+#define DA7218_OUT_DIGITAL_GAIN_MAX            0x97
+
+/* DA7218_OUT_1R_GAIN = 0xF9 */
+#define DA7218_OUT_1R_DIGITAL_GAIN_SHIFT       0
+#define DA7218_OUT_1R_DIGITAL_GAIN_MASK                (0xFF << 0)
+
+/* DA7218_MICBIAS_CTRL = 0xFC */
+#define DA7218_MICBIAS_1_LEVEL_SHIFT   0
+#define DA7218_MICBIAS_1_LEVEL_MASK    (0x7 << 0)
+#define DA7218_MICBIAS_1_LP_MODE_SHIFT 3
+#define DA7218_MICBIAS_1_LP_MODE_MASK  (0x1 << 3)
+#define DA7218_MICBIAS_2_LEVEL_SHIFT   4
+#define DA7218_MICBIAS_2_LEVEL_MASK    (0x7 << 4)
+#define DA7218_MICBIAS_2_LP_MODE_SHIFT 7
+#define DA7218_MICBIAS_2_LP_MODE_MASK  (0x1 << 7)
+
+/* DA7218_MICBIAS_EN = 0xFD */
+#define DA7218_MICBIAS_1_EN_SHIFT      0
+#define DA7218_MICBIAS_1_EN_MASK       (0x1 << 0)
+#define DA7218_MICBIAS_2_EN_SHIFT      4
+#define DA7218_MICBIAS_2_EN_MASK       (0x1 << 4)
+
+
+/*
+ * General defines & data
+ */
+
+/* Register inversion */
+#define DA7218_NO_INVERT       0
+#define DA7218_INVERT          1
+
+/* Byte related defines */
+#define DA7218_BYTE_SHIFT      8
+#define DA7218_BYTE_MASK       0xFF
+#define DA7218_2BYTE_SHIFT     16
+#define DA7218_2BYTE_MASK      0xFFFF
+
+/* PLL Output Frequencies */
+#define DA7218_PLL_FREQ_OUT_90316      90316800
+#define DA7218_PLL_FREQ_OUT_98304      98304000
+
+/* ALC Calibration */
+#define DA7218_ALC_CALIB_DELAY_MIN     2500
+#define DA7218_ALC_CALIB_DELAY_MAX     5000
+#define DA7218_ALC_CALIB_MAX_TRIES     5
+
+/* Ref Oscillator */
+#define DA7218_REF_OSC_CHECK_DELAY_MIN 5000
+#define DA7218_REF_OSC_CHECK_DELAY_MAX 10000
+#define DA7218_REF_OSC_CHECK_TRIES     4
+
+/* SRM */
+#define DA7218_SRM_CHECK_DELAY         50
+#define DA7218_SRM_CHECK_TRIES         8
+
+/* Mic Level Detect */
+#define DA7218_MIC_LVL_DET_DELAY       50
+
+enum da7218_biq_cfg {
+       DA7218_BIQ_CFG_DATA = 0,
+       DA7218_BIQ_CFG_ADDR,
+       DA7218_BIQ_CFG_SIZE,
+};
+
+enum da7218_clk_src {
+       DA7218_CLKSRC_MCLK = 0,
+       DA7218_CLKSRC_MCLK_SQR,
+};
+
+enum da7218_sys_clk {
+       DA7218_SYSCLK_MCLK = 0,
+       DA7218_SYSCLK_PLL,
+       DA7218_SYSCLK_PLL_SRM,
+       DA7218_SYSCLK_PLL_32KHZ
+};
+
+enum da7218_dev_id {
+       DA7217_DEV_ID = 0,
+       DA7218_DEV_ID,
+};
+
+/* Regulators */
+enum da7218_supplies {
+       DA7218_SUPPLY_VDD = 0,
+       DA7218_SUPPLY_VDDMIC,
+       DA7218_SUPPLY_VDDIO,
+       DA7218_NUM_SUPPLIES,
+};
+
+/* Private data */
+struct da7218_priv {
+       struct da7218_pdata *pdata;
+
+       struct regulator_bulk_data supplies[DA7218_NUM_SUPPLIES];
+       struct regmap *regmap;
+       int dev_id;
+
+       struct snd_soc_jack *jack;
+       int irq;
+
+       struct clk *mclk;
+       unsigned int mclk_rate;
+
+       bool hp_single_supply;
+       bool master;
+       u8 alc_en;
+       u8 in_filt_en;
+       u8 mic_lvl_det_en;
+
+       u8 biq_5stage_coeff[DA7218_OUT_1_BIQ_5STAGE_CFG_SIZE];
+       u8 stbiq_3stage_coeff[DA7218_SIDETONE_BIQ_3STAGE_CFG_SIZE];
+};
+
+/* HP detect control */
+int da7218_hpldet(struct snd_soc_codec *codec, struct snd_soc_jack *jack);
+
+#endif /* _DA7218_H */
index f238c1e8a69c16e92649b878edfe07b772c8cd59..81c0708b85c1569ad6e109dfac647c732d504b55 100644 (file)
@@ -968,10 +968,11 @@ static const struct snd_soc_dapm_route da7219_audio_map[] = {
        {"Mixin PGA", NULL, "Mic PGA"},
        {"ADC", NULL, "Mixin PGA"},
 
-       {"Sidetone Filter", NULL, "ADC"},
        {"Mixer In", NULL, "Mixer In Supply"},
        {"Mixer In", "Mic Switch", "ADC"},
 
+       {"Sidetone Filter", NULL, "Mixer In"},
+
        {"Tone Generator", NULL, "TONE"},
 
        DA7219_OUT_DAI_MUX_ROUTES("Out DAIL Mux"),
@@ -1073,11 +1074,8 @@ static int da7219_set_dai_pll(struct snd_soc_dai *codec_dai, int pll_id,
        u32 freq_ref;
        u64 frac_div;
 
-       /* Verify 32KHz, 2MHz - 54MHz MCLK provided, and set input divider */
-       if (da7219->mclk_rate == 32768) {
-               indiv_bits = DA7219_PLL_INDIV_2_5_MHZ;
-               indiv = DA7219_PLL_INDIV_2_5_MHZ_VAL;
-       } else if (da7219->mclk_rate < 2000000) {
+       /* Verify 2MHz - 54MHz MCLK provided, and set input divider */
+       if (da7219->mclk_rate < 2000000) {
                dev_err(codec->dev, "PLL input clock %d below valid range\n",
                        da7219->mclk_rate);
                return -EINVAL;
@@ -1118,9 +1116,6 @@ static int da7219_set_dai_pll(struct snd_soc_dai *codec_dai, int pll_id,
        case DA7219_SYSCLK_PLL_SRM:
                pll_ctrl |= DA7219_PLL_MODE_SRM;
                break;
-       case DA7219_SYSCLK_PLL_32KHZ:
-               pll_ctrl |= DA7219_PLL_MODE_32KHZ;
-               break;
        default:
                dev_err(codec->dev, "Invalid PLL config\n");
                return -EINVAL;
@@ -1161,18 +1156,44 @@ static int da7219_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt)
                return -EINVAL;
        }
 
-       switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
-       case SND_SOC_DAIFMT_NB_NF:
-               break;
-       case SND_SOC_DAIFMT_NB_IF:
-               dai_clk_mode |= DA7219_DAI_WCLK_POL_INV;
-               break;
-       case SND_SOC_DAIFMT_IB_NF:
-               dai_clk_mode |= DA7219_DAI_CLK_POL_INV;
+       switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+       case SND_SOC_DAIFMT_I2S:
+       case SND_SOC_DAIFMT_LEFT_J:
+       case SND_SOC_DAIFMT_RIGHT_J:
+               switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+               case SND_SOC_DAIFMT_NB_NF:
+                       break;
+               case SND_SOC_DAIFMT_NB_IF:
+                       dai_clk_mode |= DA7219_DAI_WCLK_POL_INV;
+                       break;
+               case SND_SOC_DAIFMT_IB_NF:
+                       dai_clk_mode |= DA7219_DAI_CLK_POL_INV;
+                       break;
+               case SND_SOC_DAIFMT_IB_IF:
+                       dai_clk_mode |= DA7219_DAI_WCLK_POL_INV |
+                                       DA7219_DAI_CLK_POL_INV;
+                       break;
+               default:
+                       return -EINVAL;
+               }
                break;
-       case SND_SOC_DAIFMT_IB_IF:
-               dai_clk_mode |= DA7219_DAI_WCLK_POL_INV |
-                               DA7219_DAI_CLK_POL_INV;
+       case SND_SOC_DAIFMT_DSP_B:
+               switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+               case SND_SOC_DAIFMT_NB_NF:
+                       dai_clk_mode |= DA7219_DAI_CLK_POL_INV;
+                       break;
+               case SND_SOC_DAIFMT_NB_IF:
+                       dai_clk_mode |= DA7219_DAI_WCLK_POL_INV |
+                                       DA7219_DAI_CLK_POL_INV;
+                       break;
+               case SND_SOC_DAIFMT_IB_NF:
+                       break;
+               case SND_SOC_DAIFMT_IB_IF:
+                       dai_clk_mode |= DA7219_DAI_WCLK_POL_INV;
+                       break;
+               default:
+                       return -EINVAL;
+               }
                break;
        default:
                return -EINVAL;
@@ -1306,7 +1327,7 @@ static int da7219_hw_params(struct snd_pcm_substream *substream,
        }
 
        channels = params_channels(params);
-       if ((channels < 1) | (channels > DA7219_DAI_CH_NUM_MAX)) {
+       if ((channels < 1) || (channels > DA7219_DAI_CH_NUM_MAX)) {
                dev_err(codec->dev,
                        "Invalid number of channels, only 1 to %d supported\n",
                        DA7219_DAI_CH_NUM_MAX);
@@ -1405,28 +1426,12 @@ static const struct of_device_id da7219_of_match[] = {
 };
 MODULE_DEVICE_TABLE(of, da7219_of_match);
 
-static enum da7219_ldo_lvl_sel da7219_of_ldo_lvl(struct snd_soc_codec *codec,
-                                                u32 val)
-{
-       switch (val) {
-       case 1050:
-               return DA7219_LDO_LVL_SEL_1_05V;
-       case 1100:
-               return DA7219_LDO_LVL_SEL_1_10V;
-       case 1200:
-               return DA7219_LDO_LVL_SEL_1_20V;
-       case 1400:
-               return DA7219_LDO_LVL_SEL_1_40V;
-       default:
-               dev_warn(codec->dev, "Invalid LDO level");
-               return DA7219_LDO_LVL_SEL_1_05V;
-       }
-}
-
 static enum da7219_micbias_voltage
        da7219_of_micbias_lvl(struct snd_soc_codec *codec, u32 val)
 {
        switch (val) {
+       case 1600:
+               return DA7219_MICBIAS_1_6V;
        case 1800:
                return DA7219_MICBIAS_1_8V;
        case 2000:
@@ -1469,9 +1474,6 @@ static struct da7219_pdata *da7219_of_to_pdata(struct snd_soc_codec *codec)
        if (!pdata)
                return NULL;
 
-       if (of_property_read_u32(np, "dlg,ldo-lvl", &of_val32) >= 0)
-               pdata->ldo_lvl_sel = da7219_of_ldo_lvl(codec, of_val32);
-
        if (of_property_read_u32(np, "dlg,micbias-lvl", &of_val32) >= 0)
                pdata->micbias_lvl = da7219_of_micbias_lvl(codec, of_val32);
        else
@@ -1516,24 +1518,13 @@ static int da7219_set_bias_level(struct snd_soc_codec *codec,
                        snd_soc_update_bits(codec, DA7219_REFERENCES,
                                            DA7219_BIAS_EN_MASK,
                                            DA7219_BIAS_EN_MASK);
-
-                       /* Enable Internal Digital LDO */
-                       snd_soc_update_bits(codec, DA7219_LDO_CTRL,
-                                           DA7219_LDO_EN_MASK,
-                                           DA7219_LDO_EN_MASK);
                }
                break;
        case SND_SOC_BIAS_OFF:
-               /* Only disable if jack detection not active */
-               if (!da7219->aad->jack) {
-                       /* Bypass Internal Digital LDO */
-                       snd_soc_update_bits(codec, DA7219_LDO_CTRL,
-                                           DA7219_LDO_EN_MASK, 0);
-
-                       /* Master bias */
+               /* Only disable master bias if jack detection not active */
+               if (!da7219->aad->jack)
                        snd_soc_update_bits(codec, DA7219_REFERENCES,
                                            DA7219_BIAS_EN_MASK, 0);
-               }
 
                /* MCLK */
                if (da7219->mclk)
@@ -1600,21 +1591,9 @@ static void da7219_handle_pdata(struct snd_soc_codec *codec)
        if (pdata) {
                u8 micbias_lvl = 0;
 
-               /* Internal LDO */
-               switch (pdata->ldo_lvl_sel) {
-               case DA7219_LDO_LVL_SEL_1_05V:
-               case DA7219_LDO_LVL_SEL_1_10V:
-               case DA7219_LDO_LVL_SEL_1_20V:
-               case DA7219_LDO_LVL_SEL_1_40V:
-                       snd_soc_update_bits(codec, DA7219_LDO_CTRL,
-                                           DA7219_LDO_LEVEL_SELECT_MASK,
-                                           (pdata->ldo_lvl_sel <<
-                                            DA7219_LDO_LEVEL_SELECT_SHIFT));
-                       break;
-               }
-
                /* Mic Bias voltages */
                switch (pdata->micbias_lvl) {
+               case DA7219_MICBIAS_1_6V:
                case DA7219_MICBIAS_1_8V:
                case DA7219_MICBIAS_2_0V:
                case DA7219_MICBIAS_2_2V:
@@ -1639,9 +1618,14 @@ static void da7219_handle_pdata(struct snd_soc_codec *codec)
        }
 }
 
+static struct reg_sequence da7219_rev_aa_patch[] = {
+       { DA7219_REFERENCES, 0x08 },
+};
+
 static int da7219_probe(struct snd_soc_codec *codec)
 {
        struct da7219_priv *da7219 = snd_soc_codec_get_drvdata(codec);
+       unsigned int rev;
        int ret;
 
        mutex_init(&da7219->lock);
@@ -1651,6 +1635,26 @@ static int da7219_probe(struct snd_soc_codec *codec)
        if (ret)
                return ret;
 
+       ret = regmap_read(da7219->regmap, DA7219_CHIP_REVISION, &rev);
+       if (ret) {
+               dev_err(codec->dev, "Failed to read chip revision: %d\n", ret);
+               goto err_disable_reg;
+       }
+
+       switch (rev & DA7219_CHIP_MINOR_MASK) {
+       case 0:
+               ret = regmap_register_patch(da7219->regmap, da7219_rev_aa_patch,
+                                           ARRAY_SIZE(da7219_rev_aa_patch));
+               if (ret) {
+                       dev_err(codec->dev, "Failed to register AA patch: %d\n",
+                               ret);
+                       goto err_disable_reg;
+               }
+               break;
+       default:
+               break;
+       }
+
        /* Handle DT/Platform data */
        if (codec->dev->of_node)
                da7219->pdata = da7219_of_to_pdata(codec);
@@ -1662,10 +1666,12 @@ static int da7219_probe(struct snd_soc_codec *codec)
        /* Check if MCLK provided */
        da7219->mclk = devm_clk_get(codec->dev, "mclk");
        if (IS_ERR(da7219->mclk)) {
-               if (PTR_ERR(da7219->mclk) != -ENOENT)
-                       return PTR_ERR(da7219->mclk);
-               else
+               if (PTR_ERR(da7219->mclk) != -ENOENT) {
+                       ret = PTR_ERR(da7219->mclk);
+                       goto err_disable_reg;
+               } else {
                        da7219->mclk = NULL;
+               }
        }
 
        /* Default PC counter to free-running */
@@ -1693,7 +1699,16 @@ static int da7219_probe(struct snd_soc_codec *codec)
        snd_soc_write(codec, DA7219_TONE_GEN_CYCLES, DA7219_BEEP_CYCLES_MASK);
 
        /* Initialise AAD block */
-       return da7219_aad_init(codec);
+       ret = da7219_aad_init(codec);
+       if (ret)
+               goto err_disable_reg;
+
+       return 0;
+
+err_disable_reg:
+       regulator_bulk_disable(DA7219_NUM_SUPPLIES, da7219->supplies);
+
+       return ret;
 }
 
 static int da7219_remove(struct snd_soc_codec *codec)
@@ -1776,7 +1791,7 @@ static struct reg_default da7219_reg_defaults[] = {
        { DA7219_DIG_ROUTING_DAC, 0x32 },
        { DA7219_DAI_OFFSET_LOWER, 0x00 },
        { DA7219_DAI_OFFSET_UPPER, 0x00 },
-       { DA7219_REFERENCES, 0x00 },
+       { DA7219_REFERENCES, 0x08 },
        { DA7219_MIXIN_L_SELECT, 0x00 },
        { DA7219_MIXIN_L_GAIN, 0x03 },
        { DA7219_ADC_L_GAIN, 0x6F },
@@ -1810,8 +1825,6 @@ static struct reg_default da7219_reg_defaults[] = {
        { DA7219_MIXOUT_R_CTRL, 0x10 },
        { DA7219_CHIP_ID1, 0x23 },
        { DA7219_CHIP_ID2, 0x93 },
-       { DA7219_CHIP_REVISION, 0x00 },
-       { DA7219_LDO_CTRL, 0x00 },
        { DA7219_IO_CTRL, 0x00 },
        { DA7219_GAIN_RAMP_CTRL, 0x00 },
        { DA7219_PC_COUNT, 0x02 },
index b514268c6c568de4bfb75eb9499cc969888143dd..5a787e738084194e3cdd88a8f75eb034fd2ab032 100644 (file)
@@ -85,7 +85,6 @@
 #define DA7219_CHIP_ID1                        0x81
 #define DA7219_CHIP_ID2                        0x82
 #define DA7219_CHIP_REVISION           0x83
-#define DA7219_LDO_CTRL                        0x90
 #define DA7219_IO_CTRL                 0x91
 #define DA7219_GAIN_RAMP_CTRL          0x92
 #define DA7219_PC_COUNT                        0x94
 #define DA7219_PLL_MODE_BYPASS         (0x0 << 6)
 #define DA7219_PLL_MODE_NORMAL         (0x1 << 6)
 #define DA7219_PLL_MODE_SRM            (0x2 << 6)
-#define DA7219_PLL_MODE_32KHZ          (0x3 << 6)
 
 /* DA7219_PLL_FRAC_TOP = 0x22 */
 #define DA7219_PLL_FBDIV_FRAC_TOP_SHIFT        0
 #define DA7219_CHIP_MAJOR_SHIFT        4
 #define DA7219_CHIP_MAJOR_MASK (0xF << 4)
 
-/* DA7219_LDO_CTRL = 0x90 */
-#define DA7219_LDO_LEVEL_SELECT_SHIFT  4
-#define DA7219_LDO_LEVEL_SELECT_MASK   (0x3 << 4)
-#define DA7219_LDO_EN_SHIFT            7
-#define DA7219_LDO_EN_MASK             (0x1 << 7)
-
 /* DA7219_IO_CTRL = 0x91 */
 #define DA7219_IO_VOLTAGE_LEVEL_SHIFT          0
 #define DA7219_IO_VOLTAGE_LEVEL_MASK           (0x1 << 0)
@@ -787,7 +779,6 @@ enum da7219_sys_clk {
        DA7219_SYSCLK_MCLK = 0,
        DA7219_SYSCLK_PLL,
        DA7219_SYSCLK_PLL_SRM,
-       DA7219_SYSCLK_PLL_32KHZ
 };
 
 /* Regulators */
index 969e337dc17c131413e43f666edd5b299fc11544..afa6c5db9dccc9b00f049f8421b04e3091a1bcfc 100644 (file)
@@ -85,7 +85,15 @@ static const DECLARE_TLV_DB_SCALE(pga_tlv, 0, 300, 0);
 static const DECLARE_TLV_DB_SCALE(bypass_tlv, -1500, 300, 0);
 static const DECLARE_TLV_DB_SCALE(mic_tlv, 0, 300, 0);
 
-static const int deemph_settings[] = { 0, 32000, 44100, 48000 };
+static const struct {
+       int rate;
+       unsigned int val;
+} deemph_settings[] = {
+       { 0,     ES8328_DACCONTROL6_DEEMPH_OFF },
+       { 32000, ES8328_DACCONTROL6_DEEMPH_32k },
+       { 44100, ES8328_DACCONTROL6_DEEMPH_44_1k },
+       { 48000, ES8328_DACCONTROL6_DEEMPH_48k },
+};
 
 static int es8328_set_deemph(struct snd_soc_codec *codec)
 {
@@ -97,21 +105,22 @@ static int es8328_set_deemph(struct snd_soc_codec *codec)
         * rate.
         */
        if (es8328->deemph) {
-               best = 1;
-               for (i = 2; i < ARRAY_SIZE(deemph_settings); i++) {
-                       if (abs(deemph_settings[i] - es8328->playback_fs) <
-                           abs(deemph_settings[best] - es8328->playback_fs))
+               best = 0;
+               for (i = 1; i < ARRAY_SIZE(deemph_settings); i++) {
+                       if (abs(deemph_settings[i].rate - es8328->playback_fs) <
+                           abs(deemph_settings[best].rate - es8328->playback_fs))
                                best = i;
                }
 
-               val = best << 1;
+               val = deemph_settings[best].val;
        } else {
-               val = 0;
+               val = ES8328_DACCONTROL6_DEEMPH_OFF;
        }
 
        dev_dbg(codec->dev, "Set deemphasis %d\n", val);
 
-       return snd_soc_update_bits(codec, ES8328_DACCONTROL6, 0x6, val);
+       return snd_soc_update_bits(codec, ES8328_DACCONTROL6,
+                       ES8328_DACCONTROL6_DEEMPH_MASK, val);
 }
 
 static int es8328_get_deemph(struct snd_kcontrol *kcontrol,
@@ -205,18 +214,18 @@ static const struct snd_kcontrol_new es8328_right_line_controls =
 
 /* Left Mixer */
 static const struct snd_kcontrol_new es8328_left_mixer_controls[] = {
-       SOC_DAPM_SINGLE("Playback Switch", ES8328_DACCONTROL17, 8, 1, 0),
-       SOC_DAPM_SINGLE("Left Bypass Switch", ES8328_DACCONTROL17, 7, 1, 0),
-       SOC_DAPM_SINGLE("Right Playback Switch", ES8328_DACCONTROL18, 8, 1, 0),
-       SOC_DAPM_SINGLE("Right Bypass Switch", ES8328_DACCONTROL18, 7, 1, 0),
+       SOC_DAPM_SINGLE("Playback Switch", ES8328_DACCONTROL17, 7, 1, 0),
+       SOC_DAPM_SINGLE("Left Bypass Switch", ES8328_DACCONTROL17, 6, 1, 0),
+       SOC_DAPM_SINGLE("Right Playback Switch", ES8328_DACCONTROL18, 7, 1, 0),
+       SOC_DAPM_SINGLE("Right Bypass Switch", ES8328_DACCONTROL18, 6, 1, 0),
 };
 
 /* Right Mixer */
 static const struct snd_kcontrol_new es8328_right_mixer_controls[] = {
-       SOC_DAPM_SINGLE("Left Playback Switch", ES8328_DACCONTROL19, 8, 1, 0),
-       SOC_DAPM_SINGLE("Left Bypass Switch", ES8328_DACCONTROL19, 7, 1, 0),
-       SOC_DAPM_SINGLE("Playback Switch", ES8328_DACCONTROL20, 8, 1, 0),
-       SOC_DAPM_SINGLE("Right Bypass Switch", ES8328_DACCONTROL20, 7, 1, 0),
+       SOC_DAPM_SINGLE("Left Playback Switch", ES8328_DACCONTROL19, 7, 1, 0),
+       SOC_DAPM_SINGLE("Left Bypass Switch", ES8328_DACCONTROL19, 6, 1, 0),
+       SOC_DAPM_SINGLE("Playback Switch", ES8328_DACCONTROL20, 7, 1, 0),
+       SOC_DAPM_SINGLE("Right Bypass Switch", ES8328_DACCONTROL20, 6, 1, 0),
 };
 
 static const char * const es8328_pga_sel[] = {
index cb36afe10c0ecdf0b51183bea6eb8446e01271d3..156c748c89c7e55d86421b27522b22f9b16d6f76 100644 (file)
@@ -153,6 +153,7 @@ int es8328_probe(struct device *dev, struct regmap *regmap);
 #define ES8328_DACCONTROL6_CLICKFREE (1 << 3)
 #define ES8328_DACCONTROL6_DAC_INVR (1 << 4)
 #define ES8328_DACCONTROL6_DAC_INVL (1 << 5)
+#define ES8328_DACCONTROL6_DEEMPH_MASK (3 << 6)
 #define ES8328_DACCONTROL6_DEEMPH_OFF (0 << 6)
 #define ES8328_DACCONTROL6_DEEMPH_32k (1 << 6)
 #define ES8328_DACCONTROL6_DEEMPH_44_1k (2 << 6)
diff --git a/sound/soc/codecs/hdac_hdmi.c b/sound/soc/codecs/hdac_hdmi.c
new file mode 100644 (file)
index 0000000..5a1ec0f
--- /dev/null
@@ -0,0 +1,697 @@
+/*
+ *  hdac_hdmi.c - ASoc HDA-HDMI codec driver for Intel platforms
+ *
+ *  Copyright (C) 2014-2015 Intel Corp
+ *  Author: Samreen Nilofer <samreen.nilofer@intel.com>
+ *         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/delay.h>
+#include <linux/module.h>
+#include <linux/pm_runtime.h>
+#include <linux/hdmi.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/hdaudio_ext.h>
+#include <sound/hda_i915.h>
+#include "../../hda/local.h"
+
+#define AMP_OUT_MUTE           0xb080
+#define AMP_OUT_UNMUTE         0xb000
+#define PIN_OUT                        (AC_PINCTL_OUT_EN)
+
+#define HDA_MAX_CONNECTIONS     32
+
+struct hdac_hdmi_cvt_params {
+       unsigned int channels_min;
+       unsigned int channels_max;
+       u32 rates;
+       u64 formats;
+       unsigned int maxbps;
+};
+
+struct hdac_hdmi_cvt {
+       struct list_head head;
+       hda_nid_t nid;
+       struct hdac_hdmi_cvt_params params;
+};
+
+struct hdac_hdmi_pin {
+       struct list_head head;
+       hda_nid_t nid;
+       int num_mux_nids;
+       hda_nid_t mux_nids[HDA_MAX_CONNECTIONS];
+};
+
+struct hdac_hdmi_dai_pin_map {
+       int dai_id;
+       struct hdac_hdmi_pin *pin;
+       struct hdac_hdmi_cvt *cvt;
+};
+
+struct hdac_hdmi_priv {
+       struct hdac_hdmi_dai_pin_map dai_map[3];
+       struct list_head pin_list;
+       struct list_head cvt_list;
+       int num_pin;
+       int num_cvt;
+};
+
+static inline struct hdac_ext_device *to_hda_ext_device(struct device *dev)
+{
+       struct hdac_device *hdac = dev_to_hdac_dev(dev);
+
+       return to_ehdac_device(hdac);
+}
+
+static int hdac_hdmi_setup_stream(struct hdac_ext_device *hdac,
+                               hda_nid_t cvt_nid, hda_nid_t pin_nid,
+                               u32 stream_tag, int format)
+{
+       unsigned int val;
+
+       dev_dbg(&hdac->hdac.dev, "cvt nid %d pnid %d stream %d format 0x%x\n",
+                       cvt_nid, pin_nid, stream_tag, format);
+
+       val = (stream_tag << 4);
+
+       snd_hdac_codec_write(&hdac->hdac, cvt_nid, 0,
+                               AC_VERB_SET_CHANNEL_STREAMID, val);
+       snd_hdac_codec_write(&hdac->hdac, cvt_nid, 0,
+                               AC_VERB_SET_STREAM_FORMAT, format);
+
+       return 0;
+}
+
+static void
+hdac_hdmi_set_dip_index(struct hdac_ext_device *hdac, hda_nid_t pin_nid,
+                               int packet_index, int byte_index)
+{
+       int val;
+
+       val = (packet_index << 5) | (byte_index & 0x1f);
+
+       snd_hdac_codec_write(&hdac->hdac, pin_nid, 0,
+                               AC_VERB_SET_HDMI_DIP_INDEX, val);
+}
+
+static int hdac_hdmi_setup_audio_infoframe(struct hdac_ext_device *hdac,
+                               hda_nid_t cvt_nid, hda_nid_t pin_nid)
+{
+       uint8_t buffer[HDMI_INFOFRAME_HEADER_SIZE + HDMI_AUDIO_INFOFRAME_SIZE];
+       struct hdmi_audio_infoframe frame;
+       u8 *dip = (u8 *)&frame;
+       int ret;
+       int i;
+
+       hdmi_audio_infoframe_init(&frame);
+
+       /* Default stereo for now */
+       frame.channels = 2;
+
+       /* setup channel count */
+       snd_hdac_codec_write(&hdac->hdac, cvt_nid, 0,
+                           AC_VERB_SET_CVT_CHAN_COUNT, frame.channels - 1);
+
+       ret = hdmi_audio_infoframe_pack(&frame, buffer, sizeof(buffer));
+       if (ret < 0)
+               return ret;
+
+       /* stop infoframe transmission */
+       hdac_hdmi_set_dip_index(hdac, pin_nid, 0x0, 0x0);
+       snd_hdac_codec_write(&hdac->hdac, pin_nid, 0,
+                       AC_VERB_SET_HDMI_DIP_XMIT, AC_DIPXMIT_DISABLE);
+
+
+       /*  Fill infoframe. Index auto-incremented */
+       hdac_hdmi_set_dip_index(hdac, pin_nid, 0x0, 0x0);
+       for (i = 0; i < sizeof(frame); i++)
+               snd_hdac_codec_write(&hdac->hdac, pin_nid, 0,
+                               AC_VERB_SET_HDMI_DIP_DATA, dip[i]);
+
+       /* Start infoframe */
+       hdac_hdmi_set_dip_index(hdac, pin_nid, 0x0, 0x0);
+       snd_hdac_codec_write(&hdac->hdac, pin_nid, 0,
+                       AC_VERB_SET_HDMI_DIP_XMIT, AC_DIPXMIT_BEST);
+
+       return 0;
+}
+
+static void hdac_hdmi_set_power_state(struct hdac_ext_device *edev,
+               struct hdac_hdmi_dai_pin_map *dai_map, unsigned int pwr_state)
+{
+       /* Power up pin widget */
+       if (!snd_hdac_check_power_state(&edev->hdac, dai_map->pin->nid,
+                                               pwr_state))
+               snd_hdac_codec_write(&edev->hdac, dai_map->pin->nid, 0,
+                       AC_VERB_SET_POWER_STATE, pwr_state);
+
+       /* Power up converter */
+       if (!snd_hdac_check_power_state(&edev->hdac, dai_map->cvt->nid,
+                                               pwr_state))
+               snd_hdac_codec_write(&edev->hdac, dai_map->cvt->nid, 0,
+                       AC_VERB_SET_POWER_STATE, pwr_state);
+}
+
+static int hdac_hdmi_playback_prepare(struct snd_pcm_substream *substream,
+                               struct snd_soc_dai *dai)
+{
+       struct hdac_ext_device *hdac = snd_soc_dai_get_drvdata(dai);
+       struct hdac_hdmi_priv *hdmi = hdac->private_data;
+       struct hdac_hdmi_dai_pin_map *dai_map;
+       struct hdac_ext_dma_params *dd;
+       int ret;
+
+       if (dai->id > 0) {
+               dev_err(&hdac->hdac.dev, "Only one dai supported as of now\n");
+               return -ENODEV;
+       }
+
+       dai_map = &hdmi->dai_map[dai->id];
+
+       dd = (struct hdac_ext_dma_params *)snd_soc_dai_get_dma_data(dai, substream);
+       dev_dbg(&hdac->hdac.dev, "stream tag from cpu dai %d format in cvt 0x%x\n",
+                       dd->stream_tag, dd->format);
+
+       ret = hdac_hdmi_setup_audio_infoframe(hdac, dai_map->cvt->nid,
+                                               dai_map->pin->nid);
+       if (ret < 0)
+               return ret;
+
+       return hdac_hdmi_setup_stream(hdac, dai_map->cvt->nid,
+                       dai_map->pin->nid, dd->stream_tag, dd->format);
+}
+
+static int hdac_hdmi_set_hw_params(struct snd_pcm_substream *substream,
+       struct snd_pcm_hw_params *hparams, struct snd_soc_dai *dai)
+{
+       struct hdac_ext_device *hdac = snd_soc_dai_get_drvdata(dai);
+       struct hdac_ext_dma_params *dd;
+
+       if (dai->id > 0) {
+               dev_err(&hdac->hdac.dev, "Only one dai supported as of now\n");
+               return -ENODEV;
+       }
+
+       dd = kzalloc(sizeof(*dd), GFP_KERNEL);
+       if (!dd)
+               return -ENOMEM;
+       dd->format = snd_hdac_calc_stream_format(params_rate(hparams),
+                       params_channels(hparams), params_format(hparams),
+                       24, 0);
+
+       snd_soc_dai_set_dma_data(dai, substream, (void *)dd);
+
+       return 0;
+}
+
+static int hdac_hdmi_playback_cleanup(struct snd_pcm_substream *substream,
+               struct snd_soc_dai *dai)
+{
+       struct hdac_ext_device *edev = snd_soc_dai_get_drvdata(dai);
+       struct hdac_ext_dma_params *dd;
+       struct hdac_hdmi_priv *hdmi = edev->private_data;
+       struct hdac_hdmi_dai_pin_map *dai_map;
+
+       dai_map = &hdmi->dai_map[dai->id];
+
+       snd_hdac_codec_write(&edev->hdac, dai_map->cvt->nid, 0,
+                               AC_VERB_SET_CHANNEL_STREAMID, 0);
+       snd_hdac_codec_write(&edev->hdac, dai_map->cvt->nid, 0,
+                               AC_VERB_SET_STREAM_FORMAT, 0);
+
+       dd = (struct hdac_ext_dma_params *)snd_soc_dai_get_dma_data(dai, substream);
+       snd_soc_dai_set_dma_data(dai, substream, NULL);
+
+       kfree(dd);
+
+       return 0;
+}
+
+static int hdac_hdmi_pcm_open(struct snd_pcm_substream *substream,
+                       struct snd_soc_dai *dai)
+{
+       struct hdac_ext_device *hdac = snd_soc_dai_get_drvdata(dai);
+       struct hdac_hdmi_priv *hdmi = hdac->private_data;
+       struct hdac_hdmi_dai_pin_map *dai_map;
+       int val;
+
+       if (dai->id > 0) {
+               dev_err(&hdac->hdac.dev, "Only one dai supported as of now\n");
+               return -ENODEV;
+       }
+
+       dai_map = &hdmi->dai_map[dai->id];
+
+       val = snd_hdac_codec_read(&hdac->hdac, dai_map->pin->nid, 0,
+                                       AC_VERB_GET_PIN_SENSE, 0);
+       dev_info(&hdac->hdac.dev, "Val for AC_VERB_GET_PIN_SENSE: %x\n", val);
+
+       if ((!(val & AC_PINSENSE_PRESENCE)) || (!(val & AC_PINSENSE_ELDV))) {
+               dev_err(&hdac->hdac.dev, "Monitor presence invalid with val: %x\n", val);
+               return -ENODEV;
+       }
+
+       hdac_hdmi_set_power_state(hdac, dai_map, AC_PWRST_D0);
+
+       snd_hdac_codec_write(&hdac->hdac, dai_map->pin->nid, 0,
+                       AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE);
+
+       snd_pcm_hw_constraint_step(substream->runtime, 0,
+                                  SNDRV_PCM_HW_PARAM_CHANNELS, 2);
+
+       return 0;
+}
+
+static void hdac_hdmi_pcm_close(struct snd_pcm_substream *substream,
+               struct snd_soc_dai *dai)
+{
+       struct hdac_ext_device *hdac = snd_soc_dai_get_drvdata(dai);
+       struct hdac_hdmi_priv *hdmi = hdac->private_data;
+       struct hdac_hdmi_dai_pin_map *dai_map;
+
+       dai_map = &hdmi->dai_map[dai->id];
+
+       hdac_hdmi_set_power_state(hdac, dai_map, AC_PWRST_D3);
+
+       snd_hdac_codec_write(&hdac->hdac, dai_map->pin->nid, 0,
+                       AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE);
+}
+
+static int
+hdac_hdmi_query_cvt_params(struct hdac_device *hdac, struct hdac_hdmi_cvt *cvt)
+{
+       int err;
+
+       /* Only stereo supported as of now */
+       cvt->params.channels_min = cvt->params.channels_max = 2;
+
+       err = snd_hdac_query_supported_pcm(hdac, cvt->nid,
+                       &cvt->params.rates,
+                       &cvt->params.formats,
+                       &cvt->params.maxbps);
+       if (err < 0)
+               dev_err(&hdac->dev,
+                       "Failed to query pcm params for nid %d: %d\n",
+                       cvt->nid, err);
+
+       return err;
+}
+
+static void hdac_hdmi_fill_widget_info(struct snd_soc_dapm_widget *w,
+                               enum snd_soc_dapm_type id,
+                               const char *wname, const char *stream)
+{
+       w->id = id;
+       w->name = wname;
+       w->sname = stream;
+       w->reg = SND_SOC_NOPM;
+       w->shift = 0;
+       w->kcontrol_news = NULL;
+       w->num_kcontrols = 0;
+       w->priv = NULL;
+}
+
+static void hdac_hdmi_fill_route(struct snd_soc_dapm_route *route,
+               const char *sink, const char *control, const char *src)
+{
+       route->sink = sink;
+       route->source = src;
+       route->control = control;
+       route->connected = NULL;
+}
+
+static void create_fill_widget_route_map(struct snd_soc_dapm_context *dapm,
+                                       struct hdac_hdmi_dai_pin_map *dai_map)
+{
+       struct snd_soc_dapm_route route[1];
+       struct snd_soc_dapm_widget widgets[2] = { {0} };
+
+       memset(&route, 0, sizeof(route));
+
+       hdac_hdmi_fill_widget_info(&widgets[0], snd_soc_dapm_output,
+                       "hif1 Output", NULL);
+       hdac_hdmi_fill_widget_info(&widgets[1], snd_soc_dapm_aif_in,
+                       "Coverter 1", "hif1");
+
+       hdac_hdmi_fill_route(&route[0], "hif1 Output", NULL, "Coverter 1");
+
+       snd_soc_dapm_new_controls(dapm, widgets, ARRAY_SIZE(widgets));
+       snd_soc_dapm_add_routes(dapm, route, ARRAY_SIZE(route));
+}
+
+static int hdac_hdmi_init_dai_map(struct hdac_ext_device *edev)
+{
+       struct hdac_hdmi_priv *hdmi = edev->private_data;
+       struct hdac_hdmi_dai_pin_map *dai_map = &hdmi->dai_map[0];
+       struct hdac_hdmi_cvt *cvt;
+       struct hdac_hdmi_pin *pin;
+
+       if (list_empty(&hdmi->cvt_list) || list_empty(&hdmi->pin_list))
+               return -EINVAL;
+
+       /*
+        * Currently on board only 1 pin and 1 converter is enabled for
+        * simplification, more will be added eventually
+        * So using fixed map for dai_id:pin:cvt
+        */
+       cvt = list_first_entry(&hdmi->cvt_list, struct hdac_hdmi_cvt, head);
+       pin = list_first_entry(&hdmi->pin_list, struct hdac_hdmi_pin, head);
+
+       dai_map->dai_id = 0;
+       dai_map->pin = pin;
+
+       dai_map->cvt = cvt;
+
+       /* Enable out path for this pin widget */
+       snd_hdac_codec_write(&edev->hdac, pin->nid, 0,
+                       AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT);
+
+       /* Enable transmission */
+       snd_hdac_codec_write(&edev->hdac, cvt->nid, 0,
+                       AC_VERB_SET_DIGI_CONVERT_1, 1);
+
+       /* Category Code (CC) to zero */
+       snd_hdac_codec_write(&edev->hdac, cvt->nid, 0,
+                       AC_VERB_SET_DIGI_CONVERT_2, 0);
+
+       snd_hdac_codec_write(&edev->hdac, pin->nid, 0,
+                       AC_VERB_SET_CONNECT_SEL, 0);
+
+       return 0;
+}
+
+static int hdac_hdmi_add_cvt(struct hdac_ext_device *edev, hda_nid_t nid)
+{
+       struct hdac_hdmi_priv *hdmi = edev->private_data;
+       struct hdac_hdmi_cvt *cvt;
+
+       cvt = kzalloc(sizeof(*cvt), GFP_KERNEL);
+       if (!cvt)
+               return -ENOMEM;
+
+       cvt->nid = nid;
+
+       list_add_tail(&cvt->head, &hdmi->cvt_list);
+       hdmi->num_cvt++;
+
+       return hdac_hdmi_query_cvt_params(&edev->hdac, cvt);
+}
+
+static int hdac_hdmi_add_pin(struct hdac_ext_device *edev, hda_nid_t nid)
+{
+       struct hdac_hdmi_priv *hdmi = edev->private_data;
+       struct hdac_hdmi_pin *pin;
+
+       pin = kzalloc(sizeof(*pin), GFP_KERNEL);
+       if (!pin)
+               return -ENOMEM;
+
+       pin->nid = nid;
+
+       list_add_tail(&pin->head, &hdmi->pin_list);
+       hdmi->num_pin++;
+
+       return 0;
+}
+
+/*
+ * Parse all nodes and store the cvt/pin nids in array
+ * Add one time initialization for pin and cvt widgets
+ */
+static int hdac_hdmi_parse_and_map_nid(struct hdac_ext_device *edev)
+{
+       hda_nid_t nid;
+       int i, num_nodes;
+       struct hdac_device *hdac = &edev->hdac;
+       struct hdac_hdmi_priv *hdmi = edev->private_data;
+       int ret;
+
+       num_nodes = snd_hdac_get_sub_nodes(hdac, hdac->afg, &nid);
+       if (!nid || num_nodes <= 0) {
+               dev_warn(&hdac->dev, "HDMI: failed to get afg sub nodes\n");
+               return -EINVAL;
+       }
+
+       hdac->num_nodes = num_nodes;
+       hdac->start_nid = nid;
+
+       for (i = 0; i < hdac->num_nodes; i++, nid++) {
+               unsigned int caps;
+               unsigned int type;
+
+               caps = get_wcaps(hdac, nid);
+               type = get_wcaps_type(caps);
+
+               if (!(caps & AC_WCAP_DIGITAL))
+                       continue;
+
+               switch (type) {
+
+               case AC_WID_AUD_OUT:
+                       ret = hdac_hdmi_add_cvt(edev, nid);
+                       if (ret < 0)
+                               return ret;
+                       break;
+
+               case AC_WID_PIN:
+                       ret = hdac_hdmi_add_pin(edev, nid);
+                       if (ret < 0)
+                               return ret;
+                       break;
+               }
+       }
+
+       hdac->end_nid = nid;
+
+       if (!hdmi->num_pin || !hdmi->num_cvt)
+               return -EIO;
+
+       return hdac_hdmi_init_dai_map(edev);
+}
+
+static int hdmi_codec_probe(struct snd_soc_codec *codec)
+{
+       struct hdac_ext_device *edev = snd_soc_codec_get_drvdata(codec);
+       struct hdac_hdmi_priv *hdmi = edev->private_data;
+       struct snd_soc_dapm_context *dapm =
+               snd_soc_component_get_dapm(&codec->component);
+
+       edev->scodec = codec;
+
+       create_fill_widget_route_map(dapm, &hdmi->dai_map[0]);
+
+       /* Imp: Store the card pointer in hda_codec */
+       edev->card = dapm->card->snd_card;
+
+       /*
+        * hdac_device core already sets the state to active and calls
+        * get_noresume. So enable runtime and set the device to suspend.
+        */
+       pm_runtime_enable(&edev->hdac.dev);
+       pm_runtime_put(&edev->hdac.dev);
+       pm_runtime_suspend(&edev->hdac.dev);
+
+       return 0;
+}
+
+static int hdmi_codec_remove(struct snd_soc_codec *codec)
+{
+       struct hdac_ext_device *edev = snd_soc_codec_get_drvdata(codec);
+
+       pm_runtime_disable(&edev->hdac.dev);
+       return 0;
+}
+
+static struct snd_soc_codec_driver hdmi_hda_codec = {
+       .probe          = hdmi_codec_probe,
+       .remove         = hdmi_codec_remove,
+       .idle_bias_off  = true,
+};
+
+static struct snd_soc_dai_ops hdmi_dai_ops = {
+       .startup = hdac_hdmi_pcm_open,
+       .shutdown = hdac_hdmi_pcm_close,
+       .hw_params = hdac_hdmi_set_hw_params,
+       .prepare = hdac_hdmi_playback_prepare,
+       .hw_free = hdac_hdmi_playback_cleanup,
+};
+
+static struct snd_soc_dai_driver hdmi_dais[] = {
+       {       .name = "intel-hdmi-hif1",
+               .playback = {
+                       .stream_name = "hif1",
+                       .channels_min = 2,
+                       .channels_max = 2,
+                       .rates = SNDRV_PCM_RATE_32000 |
+                               SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 |
+                               SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000 |
+                               SNDRV_PCM_RATE_176400 | SNDRV_PCM_RATE_192000,
+                       .formats = SNDRV_PCM_FMTBIT_S16_LE |
+                               SNDRV_PCM_FMTBIT_S20_3LE |
+                               SNDRV_PCM_FMTBIT_S24_LE |
+                               SNDRV_PCM_FMTBIT_S32_LE,
+
+               },
+               .ops = &hdmi_dai_ops,
+       },
+};
+
+static int hdac_hdmi_dev_probe(struct hdac_ext_device *edev)
+{
+       struct hdac_device *codec = &edev->hdac;
+       struct hdac_hdmi_priv *hdmi_priv;
+       int ret = 0;
+
+       hdmi_priv = devm_kzalloc(&codec->dev, sizeof(*hdmi_priv), GFP_KERNEL);
+       if (hdmi_priv == NULL)
+               return -ENOMEM;
+
+       edev->private_data = hdmi_priv;
+
+       dev_set_drvdata(&codec->dev, edev);
+
+       INIT_LIST_HEAD(&hdmi_priv->pin_list);
+       INIT_LIST_HEAD(&hdmi_priv->cvt_list);
+
+       ret = hdac_hdmi_parse_and_map_nid(edev);
+       if (ret < 0)
+               return ret;
+
+       /* ASoC specific initialization */
+       return snd_soc_register_codec(&codec->dev, &hdmi_hda_codec,
+                       hdmi_dais, ARRAY_SIZE(hdmi_dais));
+}
+
+static int hdac_hdmi_dev_remove(struct hdac_ext_device *edev)
+{
+       struct hdac_hdmi_priv *hdmi = edev->private_data;
+       struct hdac_hdmi_pin *pin, *pin_next;
+       struct hdac_hdmi_cvt *cvt, *cvt_next;
+
+       snd_soc_unregister_codec(&edev->hdac.dev);
+
+       list_for_each_entry_safe(cvt, cvt_next, &hdmi->cvt_list, head) {
+               list_del(&cvt->head);
+               kfree(cvt);
+       }
+
+       list_for_each_entry_safe(pin, pin_next, &hdmi->pin_list, head) {
+               list_del(&pin->head);
+               kfree(pin);
+       }
+
+       return 0;
+}
+
+#ifdef CONFIG_PM
+static int hdac_hdmi_runtime_suspend(struct device *dev)
+{
+       struct hdac_ext_device *edev = to_hda_ext_device(dev);
+       struct hdac_device *hdac = &edev->hdac;
+       struct hdac_bus *bus = hdac->bus;
+       int err;
+
+       dev_dbg(dev, "Enter: %s\n", __func__);
+
+       /* controller may not have been initialized for the first time */
+       if (!bus)
+               return 0;
+
+       /* Power down afg */
+       if (!snd_hdac_check_power_state(hdac, hdac->afg, AC_PWRST_D3))
+               snd_hdac_codec_write(hdac, hdac->afg, 0,
+                       AC_VERB_SET_POWER_STATE, AC_PWRST_D3);
+
+       err = snd_hdac_display_power(bus, false);
+       if (err < 0) {
+               dev_err(bus->dev, "Cannot turn on display power on i915\n");
+               return err;
+       }
+
+       return 0;
+}
+
+static int hdac_hdmi_runtime_resume(struct device *dev)
+{
+       struct hdac_ext_device *edev = to_hda_ext_device(dev);
+       struct hdac_device *hdac = &edev->hdac;
+       struct hdac_bus *bus = hdac->bus;
+       int err;
+
+       dev_dbg(dev, "Enter: %s\n", __func__);
+
+       /* controller may not have been initialized for the first time */
+       if (!bus)
+               return 0;
+
+       err = snd_hdac_display_power(bus, true);
+       if (err < 0) {
+               dev_err(bus->dev, "Cannot turn on display power on i915\n");
+               return err;
+       }
+
+       /* Power up afg */
+       if (!snd_hdac_check_power_state(hdac, hdac->afg, AC_PWRST_D0))
+               snd_hdac_codec_write(hdac, hdac->afg, 0,
+                       AC_VERB_SET_POWER_STATE, AC_PWRST_D0);
+
+       return 0;
+}
+#else
+#define hdac_hdmi_runtime_suspend NULL
+#define hdac_hdmi_runtime_resume NULL
+#endif
+
+static const struct dev_pm_ops hdac_hdmi_pm = {
+       SET_RUNTIME_PM_OPS(hdac_hdmi_runtime_suspend, hdac_hdmi_runtime_resume, NULL)
+};
+
+static const struct hda_device_id hdmi_list[] = {
+       HDA_CODEC_EXT_ENTRY(0x80862809, 0x100000, "Skylake HDMI", 0),
+       {}
+};
+
+MODULE_DEVICE_TABLE(hdaudio, hdmi_list);
+
+static struct hdac_ext_driver hdmi_driver = {
+       . hdac = {
+               .driver = {
+                       .name   = "HDMI HDA Codec",
+                       .pm = &hdac_hdmi_pm,
+               },
+               .id_table       = hdmi_list,
+       },
+       .probe          = hdac_hdmi_dev_probe,
+       .remove         = hdac_hdmi_dev_remove,
+};
+
+static int __init hdmi_init(void)
+{
+       return snd_hda_ext_driver_register(&hdmi_driver);
+}
+
+static void __exit hdmi_exit(void)
+{
+       snd_hda_ext_driver_unregister(&hdmi_driver);
+}
+
+module_init(hdmi_init);
+module_exit(hdmi_exit);
+
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("HDMI HD codec");
+MODULE_AUTHOR("Samreen Nilofer<samreen.nilofer@intel.com>");
+MODULE_AUTHOR("Subhransu S. Prusty<subhransu.s.prusty@intel.com>");
diff --git a/sound/soc/codecs/inno_rk3036.c b/sound/soc/codecs/inno_rk3036.c
new file mode 100644 (file)
index 0000000..9b6e884
--- /dev/null
@@ -0,0 +1,490 @@
+/*
+ * Driver of Inno codec for rk3036 by Rockchip Inc.
+ *
+ * Author: Rockchip Inc.
+ * Author: Zheng ShunQian<zhengsq@rock-chips.com>
+ */
+
+#include <sound/soc.h>
+#include <sound/tlv.h>
+#include <sound/soc-dapm.h>
+#include <sound/soc-dai.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+
+#include <linux/platform_device.h>
+#include <linux/of.h>
+#include <linux/clk.h>
+#include <linux/regmap.h>
+#include <linux/device.h>
+#include <linux/mfd/syscon.h>
+#include <linux/module.h>
+#include <linux/io.h>
+
+#include "inno_rk3036.h"
+
+struct rk3036_codec_priv {
+       void __iomem *base;
+       struct clk *pclk;
+       struct regmap *regmap;
+       struct device *dev;
+};
+
+static const DECLARE_TLV_DB_MINMAX(rk3036_codec_hp_tlv, -39, 0);
+
+static int rk3036_codec_antipop_info(struct snd_kcontrol *kcontrol,
+                                    struct snd_ctl_elem_info *uinfo)
+{
+       uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
+       uinfo->count = 2;
+       uinfo->value.integer.min = 0;
+       uinfo->value.integer.max = 1;
+
+       return 0;
+}
+
+static int rk3036_codec_antipop_get(struct snd_kcontrol *kcontrol,
+                                   struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
+       int val, ret, regval;
+
+       ret = snd_soc_component_read(component, INNO_R09, &regval);
+       if (ret)
+               return ret;
+       val = ((regval >> INNO_R09_HPL_ANITPOP_SHIFT) &
+              INNO_R09_HP_ANTIPOP_MSK) == INNO_R09_HP_ANTIPOP_ON;
+       ucontrol->value.integer.value[0] = val;
+
+       val = ((regval >> INNO_R09_HPR_ANITPOP_SHIFT) &
+              INNO_R09_HP_ANTIPOP_MSK) == INNO_R09_HP_ANTIPOP_ON;
+       ucontrol->value.integer.value[1] = val;
+
+       return 0;
+}
+
+static int rk3036_codec_antipop_put(struct snd_kcontrol *kcontrol,
+                                   struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
+       int val, ret, regmsk;
+
+       val = (ucontrol->value.integer.value[0] ?
+              INNO_R09_HP_ANTIPOP_ON : INNO_R09_HP_ANTIPOP_OFF) <<
+             INNO_R09_HPL_ANITPOP_SHIFT;
+       val |= (ucontrol->value.integer.value[1] ?
+               INNO_R09_HP_ANTIPOP_ON : INNO_R09_HP_ANTIPOP_OFF) <<
+              INNO_R09_HPR_ANITPOP_SHIFT;
+
+       regmsk = INNO_R09_HP_ANTIPOP_MSK << INNO_R09_HPL_ANITPOP_SHIFT |
+                INNO_R09_HP_ANTIPOP_MSK << INNO_R09_HPR_ANITPOP_SHIFT;
+
+       ret = snd_soc_component_update_bits(component, INNO_R09,
+                                           regmsk, val);
+       if (ret < 0)
+               return ret;
+
+       return 0;
+}
+
+#define SOC_RK3036_CODEC_ANTIPOP_DECL(xname) \
+{      .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
+       .info = rk3036_codec_antipop_info, .get = rk3036_codec_antipop_get, \
+       .put = rk3036_codec_antipop_put, }
+
+static const struct snd_kcontrol_new rk3036_codec_dapm_controls[] = {
+       SOC_DOUBLE_R_RANGE_TLV("Headphone Volume", INNO_R07, INNO_R08,
+               INNO_HP_GAIN_SHIFT, INNO_HP_GAIN_N39DB,
+               INNO_HP_GAIN_0DB, 0, rk3036_codec_hp_tlv),
+       SOC_DOUBLE("Zero Cross Switch", INNO_R06, INNO_R06_VOUTL_CZ_SHIFT,
+               INNO_R06_VOUTR_CZ_SHIFT, 1, 0),
+       SOC_DOUBLE("Headphone Switch", INNO_R09, INNO_R09_HPL_MUTE_SHIFT,
+               INNO_R09_HPR_MUTE_SHIFT, 1, 0),
+       SOC_RK3036_CODEC_ANTIPOP_DECL("Anti-pop Switch"),
+};
+
+static const struct snd_kcontrol_new rk3036_codec_hpl_mixer_controls[] = {
+       SOC_DAPM_SINGLE("DAC Left Out Switch", INNO_R09,
+                       INNO_R09_DACL_SWITCH_SHIFT, 1, 0),
+};
+
+static const struct snd_kcontrol_new rk3036_codec_hpr_mixer_controls[] = {
+       SOC_DAPM_SINGLE("DAC Right Out Switch", INNO_R09,
+                       INNO_R09_DACR_SWITCH_SHIFT, 1, 0),
+};
+
+static const struct snd_kcontrol_new rk3036_codec_hpl_switch_controls[] = {
+       SOC_DAPM_SINGLE("HP Left Out Switch", INNO_R05,
+                       INNO_R05_HPL_WORK_SHIFT, 1, 0),
+};
+
+static const struct snd_kcontrol_new rk3036_codec_hpr_switch_controls[] = {
+       SOC_DAPM_SINGLE("HP Right Out Switch", INNO_R05,
+                       INNO_R05_HPR_WORK_SHIFT, 1, 0),
+};
+
+static const struct snd_soc_dapm_widget rk3036_codec_dapm_widgets[] = {
+       SND_SOC_DAPM_SUPPLY_S("DAC PWR", 1, INNO_R06,
+                             INNO_R06_DAC_EN_SHIFT, 0, NULL, 0),
+       SND_SOC_DAPM_SUPPLY_S("DACL VREF", 2, INNO_R04,
+                             INNO_R04_DACL_VREF_SHIFT, 0, NULL, 0),
+       SND_SOC_DAPM_SUPPLY_S("DACR VREF", 2, INNO_R04,
+                             INNO_R04_DACR_VREF_SHIFT, 0, NULL, 0),
+       SND_SOC_DAPM_SUPPLY_S("DACL HiLo VREF", 3, INNO_R06,
+                             INNO_R06_DACL_HILO_VREF_SHIFT, 0, NULL, 0),
+       SND_SOC_DAPM_SUPPLY_S("DACR HiLo VREF", 3, INNO_R06,
+                             INNO_R06_DACR_HILO_VREF_SHIFT, 0, NULL, 0),
+       SND_SOC_DAPM_SUPPLY_S("DACR CLK", 3, INNO_R04,
+                             INNO_R04_DACR_CLK_SHIFT, 0, NULL, 0),
+       SND_SOC_DAPM_SUPPLY_S("DACL CLK", 3, INNO_R04,
+                             INNO_R04_DACL_CLK_SHIFT, 0, NULL, 0),
+
+       SND_SOC_DAPM_DAC("DACL", "Left Playback", INNO_R04,
+                        INNO_R04_DACL_SW_SHIFT, 0),
+       SND_SOC_DAPM_DAC("DACR", "Right Playback", INNO_R04,
+                        INNO_R04_DACR_SW_SHIFT, 0),
+
+       SND_SOC_DAPM_MIXER("Left Headphone Mixer", SND_SOC_NOPM, 0, 0,
+               rk3036_codec_hpl_mixer_controls,
+               ARRAY_SIZE(rk3036_codec_hpl_mixer_controls)),
+       SND_SOC_DAPM_MIXER("Right Headphone Mixer", SND_SOC_NOPM, 0, 0,
+               rk3036_codec_hpr_mixer_controls,
+               ARRAY_SIZE(rk3036_codec_hpr_mixer_controls)),
+
+       SND_SOC_DAPM_PGA("HP Left Out", INNO_R05,
+                        INNO_R05_HPL_EN_SHIFT, 0, NULL, 0),
+       SND_SOC_DAPM_PGA("HP Right Out", INNO_R05,
+                        INNO_R05_HPR_EN_SHIFT, 0, NULL, 0),
+
+       SND_SOC_DAPM_MIXER("HP Left Switch",  SND_SOC_NOPM, 0, 0,
+                          rk3036_codec_hpl_switch_controls,
+                          ARRAY_SIZE(rk3036_codec_hpl_switch_controls)),
+       SND_SOC_DAPM_MIXER("HP Right Switch",  SND_SOC_NOPM, 0, 0,
+                          rk3036_codec_hpr_switch_controls,
+                          ARRAY_SIZE(rk3036_codec_hpr_switch_controls)),
+
+       SND_SOC_DAPM_OUTPUT("HPL"),
+       SND_SOC_DAPM_OUTPUT("HPR"),
+};
+
+static const struct snd_soc_dapm_route rk3036_codec_dapm_routes[] = {
+       {"DACL VREF", NULL, "DAC PWR"},
+       {"DACR VREF", NULL, "DAC PWR"},
+       {"DACL HiLo VREF", NULL, "DAC PWR"},
+       {"DACR HiLo VREF", NULL, "DAC PWR"},
+       {"DACL CLK", NULL, "DAC PWR"},
+       {"DACR CLK", NULL, "DAC PWR"},
+
+       {"DACL", NULL, "DACL VREF"},
+       {"DACL", NULL, "DACL HiLo VREF"},
+       {"DACL", NULL, "DACL CLK"},
+       {"DACR", NULL, "DACR VREF"},
+       {"DACR", NULL, "DACR HiLo VREF"},
+       {"DACR", NULL, "DACR CLK"},
+
+       {"Left Headphone Mixer", "DAC Left Out Switch", "DACL"},
+       {"Right Headphone Mixer", "DAC Right Out Switch", "DACR"},
+       {"HP Left Out", NULL, "Left Headphone Mixer"},
+       {"HP Right Out", NULL, "Right Headphone Mixer"},
+
+       {"HP Left Switch", "HP Left Out Switch", "HP Left Out"},
+       {"HP Right Switch", "HP Right Out Switch", "HP Right Out"},
+
+       {"HPL", NULL, "HP Left Switch"},
+       {"HPR", NULL, "HP Right Switch"},
+};
+
+static int rk3036_codec_dai_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
+{
+       struct snd_soc_codec *codec = dai->codec;
+       unsigned int reg01_val = 0,  reg02_val = 0, reg03_val = 0;
+
+       dev_dbg(codec->dev, "rk3036_codec dai set fmt : %08x\n", fmt);
+
+       switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+       case SND_SOC_DAIFMT_CBS_CFS:
+               reg01_val |= INNO_R01_PINDIR_IN_SLAVE |
+                            INNO_R01_I2SMODE_SLAVE;
+               break;
+       case SND_SOC_DAIFMT_CBM_CFM:
+               reg01_val |= INNO_R01_PINDIR_OUT_MASTER |
+                            INNO_R01_I2SMODE_MASTER;
+               break;
+       default:
+               dev_err(codec->dev, "invalid fmt\n");
+               return -EINVAL;
+       }
+
+       switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+       case SND_SOC_DAIFMT_DSP_A:
+               reg02_val |= INNO_R02_DACM_PCM;
+               break;
+       case SND_SOC_DAIFMT_I2S:
+               reg02_val |= INNO_R02_DACM_I2S;
+               break;
+       case SND_SOC_DAIFMT_RIGHT_J:
+               reg02_val |= INNO_R02_DACM_RJM;
+               break;
+       case SND_SOC_DAIFMT_LEFT_J:
+               reg02_val |= INNO_R02_DACM_LJM;
+               break;
+       default:
+               dev_err(codec->dev, "set dai format failed\n");
+               return -EINVAL;
+       }
+
+       switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+       case SND_SOC_DAIFMT_NB_NF:
+               reg02_val |= INNO_R02_LRCP_NORMAL;
+               reg03_val |= INNO_R03_BCP_NORMAL;
+               break;
+       case SND_SOC_DAIFMT_IB_IF:
+               reg02_val |= INNO_R02_LRCP_REVERSAL;
+               reg03_val |= INNO_R03_BCP_REVERSAL;
+               break;
+       case SND_SOC_DAIFMT_IB_NF:
+               reg02_val |= INNO_R02_LRCP_REVERSAL;
+               reg03_val |= INNO_R03_BCP_NORMAL;
+               break;
+       case SND_SOC_DAIFMT_NB_IF:
+               reg02_val |= INNO_R02_LRCP_NORMAL;
+               reg03_val |= INNO_R03_BCP_REVERSAL;
+               break;
+       default:
+               dev_err(codec->dev, "set dai format failed\n");
+               return -EINVAL;
+       }
+
+       snd_soc_update_bits(codec, INNO_R01, INNO_R01_I2SMODE_MSK |
+                           INNO_R01_PINDIR_MSK, reg01_val);
+       snd_soc_update_bits(codec, INNO_R02, INNO_R02_LRCP_MSK |
+                           INNO_R02_DACM_MSK, reg02_val);
+       snd_soc_update_bits(codec, INNO_R03, INNO_R03_BCP_MSK, reg03_val);
+
+       return 0;
+}
+
+static int rk3036_codec_dai_hw_params(struct snd_pcm_substream *substream,
+                                     struct snd_pcm_hw_params *hw_params,
+                                     struct snd_soc_dai *dai)
+{
+       struct snd_soc_codec *codec = dai->codec;
+       unsigned int reg02_val = 0, reg03_val = 0;
+
+       switch (params_format(hw_params)) {
+       case SNDRV_PCM_FORMAT_S16_LE:
+               reg02_val |= INNO_R02_VWL_16BIT;
+               break;
+       case SNDRV_PCM_FORMAT_S20_3LE:
+               reg02_val |= INNO_R02_VWL_20BIT;
+               break;
+       case SNDRV_PCM_FORMAT_S24_LE:
+               reg02_val |= INNO_R02_VWL_24BIT;
+               break;
+       case SNDRV_PCM_FORMAT_S32_LE:
+               reg02_val |= INNO_R02_VWL_32BIT;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       reg02_val |= INNO_R02_LRCP_NORMAL;
+       reg03_val |= INNO_R03_FWL_32BIT | INNO_R03_DACR_WORK;
+
+       snd_soc_update_bits(codec, INNO_R02, INNO_R02_LRCP_MSK |
+                           INNO_R02_VWL_MSK, reg02_val);
+       snd_soc_update_bits(codec, INNO_R03, INNO_R03_DACR_MSK |
+                           INNO_R03_FWL_MSK, reg03_val);
+       return 0;
+}
+
+#define RK3036_CODEC_RATES (SNDRV_PCM_RATE_8000  | \
+                           SNDRV_PCM_RATE_16000 | \
+                           SNDRV_PCM_RATE_32000 | \
+                           SNDRV_PCM_RATE_44100 | \
+                           SNDRV_PCM_RATE_48000 | \
+                           SNDRV_PCM_RATE_96000)
+
+#define RK3036_CODEC_FMTS (SNDRV_PCM_FMTBIT_S16_LE  | \
+                          SNDRV_PCM_FMTBIT_S20_3LE | \
+                          SNDRV_PCM_FMTBIT_S24_LE  | \
+                          SNDRV_PCM_FMTBIT_S32_LE)
+
+static struct snd_soc_dai_ops rk3036_codec_dai_ops = {
+       .set_fmt        = rk3036_codec_dai_set_fmt,
+       .hw_params      = rk3036_codec_dai_hw_params,
+};
+
+static struct snd_soc_dai_driver rk3036_codec_dai_driver[] = {
+       {
+               .name = "rk3036-codec-dai",
+               .playback = {
+                       .stream_name = "Playback",
+                       .channels_min = 1,
+                       .channels_max = 2,
+                       .rates = RK3036_CODEC_RATES,
+                       .formats = RK3036_CODEC_FMTS,
+               },
+               .ops = &rk3036_codec_dai_ops,
+               .symmetric_rates = 1,
+       },
+};
+
+static void rk3036_codec_reset(struct snd_soc_codec *codec)
+{
+       snd_soc_write(codec, INNO_R00,
+                     INNO_R00_CSR_RESET | INNO_R00_CDCR_RESET);
+       snd_soc_write(codec, INNO_R00,
+                     INNO_R00_CSR_WORK | INNO_R00_CDCR_WORK);
+}
+
+static int rk3036_codec_probe(struct snd_soc_codec *codec)
+{
+       rk3036_codec_reset(codec);
+       return 0;
+}
+
+static int rk3036_codec_remove(struct snd_soc_codec *codec)
+{
+       rk3036_codec_reset(codec);
+       return 0;
+}
+
+static int rk3036_codec_set_bias_level(struct snd_soc_codec *codec,
+                                      enum snd_soc_bias_level level)
+{
+       switch (level) {
+       case SND_SOC_BIAS_STANDBY:
+               /* set a big current for capacitor charging. */
+               snd_soc_write(codec, INNO_R10, INNO_R10_MAX_CUR);
+               /* start precharge */
+               snd_soc_write(codec, INNO_R06, INNO_R06_DAC_PRECHARGE);
+
+               break;
+
+       case SND_SOC_BIAS_OFF:
+               /* set a big current for capacitor discharging. */
+               snd_soc_write(codec, INNO_R10, INNO_R10_MAX_CUR);
+               /* start discharge. */
+               snd_soc_write(codec, INNO_R06, INNO_R06_DAC_DISCHARGE);
+
+               break;
+       default:
+               break;
+       }
+
+       return 0;
+}
+
+static struct snd_soc_codec_driver rk3036_codec_driver = {
+       .probe                  = rk3036_codec_probe,
+       .remove                 = rk3036_codec_remove,
+       .set_bias_level         = rk3036_codec_set_bias_level,
+       .controls               = rk3036_codec_dapm_controls,
+       .num_controls           = ARRAY_SIZE(rk3036_codec_dapm_controls),
+       .dapm_routes            = rk3036_codec_dapm_routes,
+       .num_dapm_routes        = ARRAY_SIZE(rk3036_codec_dapm_routes),
+       .dapm_widgets           = rk3036_codec_dapm_widgets,
+       .num_dapm_widgets       = ARRAY_SIZE(rk3036_codec_dapm_widgets),
+};
+
+static const struct regmap_config rk3036_codec_regmap_config = {
+       .reg_bits = 32,
+       .reg_stride = 4,
+       .val_bits = 32,
+};
+
+#define GRF_SOC_CON0           0x00140
+#define GRF_ACODEC_SEL         (BIT(10) | BIT(16 + 10))
+
+static int rk3036_codec_platform_probe(struct platform_device *pdev)
+{
+       struct rk3036_codec_priv *priv;
+       struct device_node *of_node = pdev->dev.of_node;
+       struct resource *res;
+       void __iomem *base;
+       struct regmap *grf;
+       int ret;
+
+       priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
+       if (!priv)
+               return -ENOMEM;
+
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       base = devm_ioremap_resource(&pdev->dev, res);
+       if (IS_ERR(base))
+               return PTR_ERR(base);
+
+       priv->base = base;
+       priv->regmap = devm_regmap_init_mmio(&pdev->dev, priv->base,
+                                            &rk3036_codec_regmap_config);
+       if (IS_ERR(priv->regmap)) {
+               dev_err(&pdev->dev, "init regmap failed\n");
+               return PTR_ERR(priv->regmap);
+       }
+
+       grf = syscon_regmap_lookup_by_phandle(of_node, "rockchip,grf");
+       if (IS_ERR(grf)) {
+               dev_err(&pdev->dev, "needs 'rockchip,grf' property\n");
+               return PTR_ERR(grf);
+       }
+       ret = regmap_write(grf, GRF_SOC_CON0, GRF_ACODEC_SEL);
+       if (ret) {
+               dev_err(&pdev->dev, "Could not write to GRF: %d\n", ret);
+               return ret;
+       }
+
+       priv->pclk = devm_clk_get(&pdev->dev, "acodec_pclk");
+       if (IS_ERR(priv->pclk))
+               return PTR_ERR(priv->pclk);
+
+       ret = clk_prepare_enable(priv->pclk);
+       if (ret < 0) {
+               dev_err(&pdev->dev, "failed to enable clk\n");
+               return ret;
+       }
+
+       priv->dev = &pdev->dev;
+       dev_set_drvdata(&pdev->dev, priv);
+
+       ret = snd_soc_register_codec(&pdev->dev, &rk3036_codec_driver,
+                                    rk3036_codec_dai_driver,
+                                    ARRAY_SIZE(rk3036_codec_dai_driver));
+       if (ret) {
+               clk_disable_unprepare(priv->pclk);
+               dev_set_drvdata(&pdev->dev, NULL);
+       }
+
+       return ret;
+}
+
+static int rk3036_codec_platform_remove(struct platform_device *pdev)
+{
+       struct rk3036_codec_priv *priv = dev_get_drvdata(&pdev->dev);
+
+       snd_soc_unregister_codec(&pdev->dev);
+       clk_disable_unprepare(priv->pclk);
+
+       return 0;
+}
+
+static const struct of_device_id rk3036_codec_of_match[] = {
+       { .compatible = "rockchip,rk3036-codec", },
+       {}
+};
+MODULE_DEVICE_TABLE(of, rk3036_codec_of_match);
+
+static struct platform_driver rk3036_codec_platform_driver = {
+       .driver = {
+               .name = "rk3036-codec-platform",
+               .of_match_table = of_match_ptr(rk3036_codec_of_match),
+       },
+       .probe = rk3036_codec_platform_probe,
+       .remove = rk3036_codec_platform_remove,
+};
+
+module_platform_driver(rk3036_codec_platform_driver);
+
+MODULE_AUTHOR("Rockchip Inc.");
+MODULE_DESCRIPTION("Rockchip rk3036 codec driver");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/inno_rk3036.h b/sound/soc/codecs/inno_rk3036.h
new file mode 100644 (file)
index 0000000..da759c6
--- /dev/null
@@ -0,0 +1,123 @@
+/*
+ * Driver of Inno Codec for rk3036 by Rockchip Inc.
+ *
+ * Author: Zheng ShunQian<zhengsq@rock-chips.com>
+ */
+
+#ifndef _INNO_RK3036_CODEC_H
+#define _INNO_RK3036_CODEC_H
+
+/* codec registers */
+#define INNO_R00       0x00
+#define INNO_R01       0x0c
+#define INNO_R02       0x10
+#define INNO_R03       0x14
+#define INNO_R04       0x88
+#define INNO_R05       0x8c
+#define INNO_R06       0x90
+#define INNO_R07       0x94
+#define INNO_R08       0x98
+#define INNO_R09       0x9c
+#define INNO_R10       0xa0
+
+/* register bit filed */
+#define INNO_R00_CSR_RESET             (0x0 << 0) /*codec system reset*/
+#define INNO_R00_CSR_WORK              (0x1 << 0)
+#define INNO_R00_CDCR_RESET            (0x0 << 1) /*codec digital core reset*/
+#define INNO_R00_CDCR_WORK             (0x1 << 1)
+#define INNO_R00_PRB_DISABLE           (0x0 << 6) /*power reset bypass*/
+#define INNO_R00_PRB_ENABLE            (0x1 << 6)
+
+#define INNO_R01_I2SMODE_MSK           (0x1 << 4)
+#define INNO_R01_I2SMODE_SLAVE         (0x0 << 4)
+#define INNO_R01_I2SMODE_MASTER                (0x1 << 4)
+#define INNO_R01_PINDIR_MSK            (0x1 << 5)
+#define INNO_R01_PINDIR_IN_SLAVE       (0x0 << 5) /*direction of pin*/
+#define INNO_R01_PINDIR_OUT_MASTER     (0x1 << 5)
+
+#define INNO_R02_LRS_MSK               (0x1 << 2)
+#define INNO_R02_LRS_NORMAL            (0x0 << 2) /*DAC Left Right Swap*/
+#define INNO_R02_LRS_SWAP              (0x1 << 2)
+#define INNO_R02_DACM_MSK              (0x3 << 3)
+#define INNO_R02_DACM_PCM              (0x3 << 3) /*DAC Mode*/
+#define INNO_R02_DACM_I2S              (0x2 << 3)
+#define INNO_R02_DACM_LJM              (0x1 << 3)
+#define INNO_R02_DACM_RJM              (0x0 << 3)
+#define INNO_R02_VWL_MSK               (0x3 << 5)
+#define INNO_R02_VWL_32BIT             (0x3 << 5) /*1/2Frame Valid Word Len*/
+#define INNO_R02_VWL_24BIT             (0x2 << 5)
+#define INNO_R02_VWL_20BIT             (0x1 << 5)
+#define INNO_R02_VWL_16BIT             (0x0 << 5)
+#define INNO_R02_LRCP_MSK              (0x1 << 7)
+#define INNO_R02_LRCP_NORMAL           (0x0 << 7) /*Left Right Polarity*/
+#define INNO_R02_LRCP_REVERSAL         (0x1 << 7)
+
+#define INNO_R03_BCP_MSK               (0x1 << 0)
+#define INNO_R03_BCP_NORMAL            (0x0 << 0) /*DAC bit clock polarity*/
+#define INNO_R03_BCP_REVERSAL          (0x1 << 0)
+#define INNO_R03_DACR_MSK              (0x1 << 1)
+#define INNO_R03_DACR_RESET            (0x0 << 1) /*DAC Reset*/
+#define INNO_R03_DACR_WORK             (0x1 << 1)
+#define INNO_R03_FWL_MSK               (0x3 << 2)
+#define INNO_R03_FWL_32BIT             (0x3 << 2) /*1/2Frame Word Length*/
+#define INNO_R03_FWL_24BIT             (0x2 << 2)
+#define INNO_R03_FWL_20BIT             (0x1 << 2)
+#define INNO_R03_FWL_16BIT             (0x0 << 2)
+
+#define INNO_R04_DACR_SW_SHIFT         0
+#define INNO_R04_DACL_SW_SHIFT         1
+#define INNO_R04_DACR_CLK_SHIFT                2
+#define INNO_R04_DACL_CLK_SHIFT                3
+#define INNO_R04_DACR_VREF_SHIFT       4
+#define INNO_R04_DACL_VREF_SHIFT       5
+
+#define INNO_R05_HPR_EN_SHIFT          0
+#define INNO_R05_HPL_EN_SHIFT          1
+#define INNO_R05_HPR_WORK_SHIFT                2
+#define INNO_R05_HPL_WORK_SHIFT                3
+
+#define INNO_R06_VOUTR_CZ_SHIFT                0
+#define INNO_R06_VOUTL_CZ_SHIFT                1
+#define INNO_R06_DACR_HILO_VREF_SHIFT  2
+#define INNO_R06_DACL_HILO_VREF_SHIFT  3
+#define INNO_R06_DAC_EN_SHIFT          5
+
+#define INNO_R06_DAC_PRECHARGE         (0x0 << 4) /*PreCharge control for DAC*/
+#define INNO_R06_DAC_DISCHARGE         (0x1 << 4)
+
+#define INNO_HP_GAIN_SHIFT             0
+/* Gain of output, 1.5db step: -39db(0x0) ~ 0db(0x1a) ~ 6db(0x1f) */
+#define INNO_HP_GAIN_0DB               0x1a
+#define INNO_HP_GAIN_N39DB             0x0
+
+#define INNO_R09_HP_ANTIPOP_MSK                0x3
+#define INNO_R09_HP_ANTIPOP_OFF                0x1
+#define INNO_R09_HP_ANTIPOP_ON         0x2
+#define INNO_R09_HPR_ANITPOP_SHIFT     0
+#define INNO_R09_HPL_ANITPOP_SHIFT     2
+#define INNO_R09_HPR_MUTE_SHIFT                4
+#define INNO_R09_HPL_MUTE_SHIFT                5
+#define INNO_R09_DACR_SWITCH_SHIFT     6
+#define INNO_R09_DACL_SWITCH_SHIFT     7
+
+#define INNO_R10_CHARGE_SEL_CUR_400I_YES       (0x0 << 0)
+#define INNO_R10_CHARGE_SEL_CUR_400I_NO                (0x1 << 0)
+#define INNO_R10_CHARGE_SEL_CUR_260I_YES       (0x0 << 1)
+#define INNO_R10_CHARGE_SEL_CUR_260I_NO                (0x1 << 1)
+#define INNO_R10_CHARGE_SEL_CUR_130I_YES       (0x0 << 2)
+#define INNO_R10_CHARGE_SEL_CUR_130I_NO                (0x1 << 2)
+#define INNO_R10_CHARGE_SEL_CUR_100I_YES       (0x0 << 3)
+#define INNO_R10_CHARGE_SEL_CUR_100I_NO                (0x1 << 3)
+#define INNO_R10_CHARGE_SEL_CUR_050I_YES       (0x0 << 4)
+#define INNO_R10_CHARGE_SEL_CUR_050I_NO                (0x1 << 4)
+#define INNO_R10_CHARGE_SEL_CUR_027I_YES       (0x0 << 5)
+#define INNO_R10_CHARGE_SEL_CUR_027I_NO                (0x1 << 5)
+
+#define INNO_R10_MAX_CUR (INNO_R10_CHARGE_SEL_CUR_400I_YES | \
+                         INNO_R10_CHARGE_SEL_CUR_260I_YES | \
+                         INNO_R10_CHARGE_SEL_CUR_130I_YES | \
+                         INNO_R10_CHARGE_SEL_CUR_100I_YES | \
+                         INNO_R10_CHARGE_SEL_CUR_050I_YES | \
+                         INNO_R10_CHARGE_SEL_CUR_027I_YES)
+
+#endif
index f5e3dce2633a39a0a09a3ea3b5f2281a62db306d..5b1dfb1518fbeaa151da656fc5d3e1198ad681ed 100644 (file)
@@ -12,6 +12,7 @@
  * max98357a.c -- MAX98357A ALSA SoC Codec driver
  */
 
+#include <linux/acpi.h>
 #include <linux/device.h>
 #include <linux/err.h>
 #include <linux/gpio.h>
@@ -123,10 +124,19 @@ static const struct of_device_id max98357a_device_id[] = {
 MODULE_DEVICE_TABLE(of, max98357a_device_id);
 #endif
 
+#ifdef CONFIG_ACPI
+static const struct acpi_device_id max98357a_acpi_match[] = {
+       { "MX98357A", 0 },
+       {},
+};
+MODULE_DEVICE_TABLE(acpi, max98357a_acpi_match);
+#endif
+
 static struct platform_driver max98357a_platform_driver = {
        .driver = {
                .name = "max98357a",
                .of_match_table = of_match_ptr(max98357a_device_id),
+               .acpi_match_table = ACPI_PTR(max98357a_acpi_match),
        },
        .probe  = max98357a_platform_probe,
        .remove = max98357a_platform_remove,
index 7fc7b4e3f4442a52727e97d96a847c76ada6a58f..c1b87c5800b1d0980cf541e96a4d22ae76e9b32c 100644 (file)
@@ -1271,6 +1271,36 @@ static int nau8825_i2c_remove(struct i2c_client *client)
        return 0;
 }
 
+#ifdef CONFIG_PM_SLEEP
+static int nau8825_suspend(struct device *dev)
+{
+       struct i2c_client *client = to_i2c_client(dev);
+       struct nau8825 *nau8825 = dev_get_drvdata(dev);
+
+       disable_irq(client->irq);
+       regcache_cache_only(nau8825->regmap, true);
+       regcache_mark_dirty(nau8825->regmap);
+
+       return 0;
+}
+
+static int nau8825_resume(struct device *dev)
+{
+       struct i2c_client *client = to_i2c_client(dev);
+       struct nau8825 *nau8825 = dev_get_drvdata(dev);
+
+       regcache_cache_only(nau8825->regmap, false);
+       regcache_sync(nau8825->regmap);
+       enable_irq(client->irq);
+
+       return 0;
+}
+#endif
+
+static const struct dev_pm_ops nau8825_pm = {
+       SET_SYSTEM_SLEEP_PM_OPS(nau8825_suspend, nau8825_resume)
+};
+
 static const struct i2c_device_id nau8825_i2c_ids[] = {
        { "nau8825", 0 },
        { }
@@ -1297,6 +1327,7 @@ static struct i2c_driver nau8825_driver = {
                .name = "nau8825",
                .of_match_table = of_match_ptr(nau8825_of_ids),
                .acpi_match_table = ACPI_PTR(nau8825_acpi_match),
+               .pm = &nau8825_pm,
        },
        .probe = nau8825_i2c_probe,
        .remove = nau8825_i2c_remove,
diff --git a/sound/soc/codecs/pcm1792a.c b/sound/soc/codecs/pcm1792a.c
deleted file mode 100644 (file)
index 08bb486..0000000
+++ /dev/null
@@ -1,271 +0,0 @@
-/*
- * PCM1792A ASoC codec driver
- *
- * Copyright (c) Amarula Solutions B.V. 2013
- *
- *     Michael Trimarchi <michael@amarulasolutions.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.
- *
- * 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/slab.h>
-#include <linux/kernel.h>
-#include <linux/device.h>
-#include <linux/spi/spi.h>
-
-#include <sound/core.h>
-#include <sound/pcm.h>
-#include <sound/pcm_params.h>
-#include <sound/initval.h>
-#include <sound/soc.h>
-#include <sound/tlv.h>
-#include <linux/of.h>
-#include <linux/of_device.h>
-
-#include "pcm1792a.h"
-
-#define PCM1792A_DAC_VOL_LEFT  0x10
-#define PCM1792A_DAC_VOL_RIGHT 0x11
-#define PCM1792A_FMT_CONTROL   0x12
-#define PCM1792A_MODE_CONTROL  0x13
-#define PCM1792A_SOFT_MUTE     PCM1792A_FMT_CONTROL
-
-#define PCM1792A_FMT_MASK      0x70
-#define PCM1792A_FMT_SHIFT     4
-#define PCM1792A_MUTE_MASK     0x01
-#define PCM1792A_MUTE_SHIFT    0
-#define PCM1792A_ATLD_ENABLE   (1 << 7)
-
-static const struct reg_default pcm1792a_reg_defaults[] = {
-       { 0x10, 0xff },
-       { 0x11, 0xff },
-       { 0x12, 0x50 },
-       { 0x13, 0x00 },
-       { 0x14, 0x00 },
-       { 0x15, 0x01 },
-       { 0x16, 0x00 },
-       { 0x17, 0x00 },
-};
-
-static bool pcm1792a_accessible_reg(struct device *dev, unsigned int reg)
-{
-       return reg >= 0x10 && reg <= 0x17;
-}
-
-static bool pcm1792a_writeable_reg(struct device *dev, unsigned register reg)
-{
-       bool accessible;
-
-       accessible = pcm1792a_accessible_reg(dev, reg);
-
-       return accessible && reg != 0x16 && reg != 0x17;
-}
-
-struct pcm1792a_private {
-       struct regmap *regmap;
-       unsigned int format;
-       unsigned int rate;
-};
-
-static int pcm1792a_set_dai_fmt(struct snd_soc_dai *codec_dai,
-                             unsigned int format)
-{
-       struct snd_soc_codec *codec = codec_dai->codec;
-       struct pcm1792a_private *priv = snd_soc_codec_get_drvdata(codec);
-
-       priv->format = format;
-
-       return 0;
-}
-
-static int pcm1792a_digital_mute(struct snd_soc_dai *dai, int mute)
-{
-       struct snd_soc_codec *codec = dai->codec;
-       struct pcm1792a_private *priv = snd_soc_codec_get_drvdata(codec);
-       int ret;
-
-       ret = regmap_update_bits(priv->regmap, PCM1792A_SOFT_MUTE,
-                                PCM1792A_MUTE_MASK, !!mute);
-       if (ret < 0)
-               return ret;
-
-       return 0;
-}
-
-static int pcm1792a_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 pcm1792a_private *priv = snd_soc_codec_get_drvdata(codec);
-       int val = 0, ret;
-
-       priv->rate = params_rate(params);
-
-       switch (priv->format & SND_SOC_DAIFMT_FORMAT_MASK) {
-       case SND_SOC_DAIFMT_RIGHT_J:
-               switch (params_width(params)) {
-               case 24:
-               case 32:
-                       val = 2;
-                       break;
-               case 16:
-                       val = 0;
-                       break;
-               default:
-                       return -EINVAL;
-               }
-               break;
-       case SND_SOC_DAIFMT_I2S:
-               switch (params_width(params)) {
-               case 24:
-               case 32:
-                       val = 5;
-                       break;
-               case 16:
-                       val = 4;
-                       break;
-               default:
-                       return -EINVAL;
-               }
-               break;
-       default:
-               dev_err(codec->dev, "Invalid DAI format\n");
-               return -EINVAL;
-       }
-
-       val = val << PCM1792A_FMT_SHIFT | PCM1792A_ATLD_ENABLE;
-
-       ret = regmap_update_bits(priv->regmap, PCM1792A_FMT_CONTROL,
-                                PCM1792A_FMT_MASK | PCM1792A_ATLD_ENABLE, val);
-       if (ret < 0)
-               return ret;
-
-       return 0;
-}
-
-static const struct snd_soc_dai_ops pcm1792a_dai_ops = {
-       .set_fmt        = pcm1792a_set_dai_fmt,
-       .hw_params      = pcm1792a_hw_params,
-       .digital_mute   = pcm1792a_digital_mute,
-};
-
-static const DECLARE_TLV_DB_SCALE(pcm1792a_dac_tlv, -12000, 50, 1);
-
-static const struct snd_kcontrol_new pcm1792a_controls[] = {
-       SOC_DOUBLE_R_RANGE_TLV("DAC Playback Volume", PCM1792A_DAC_VOL_LEFT,
-                        PCM1792A_DAC_VOL_RIGHT, 0, 0xf, 0xff, 0,
-                        pcm1792a_dac_tlv),
-       SOC_SINGLE("DAC Invert Output Switch", PCM1792A_MODE_CONTROL, 7, 1, 0),
-       SOC_SINGLE("DAC Rolloff Filter Switch", PCM1792A_MODE_CONTROL, 1, 1, 0),
-};
-
-static const struct snd_soc_dapm_widget pcm1792a_dapm_widgets[] = {
-SND_SOC_DAPM_OUTPUT("IOUTL+"),
-SND_SOC_DAPM_OUTPUT("IOUTL-"),
-SND_SOC_DAPM_OUTPUT("IOUTR+"),
-SND_SOC_DAPM_OUTPUT("IOUTR-"),
-};
-
-static const struct snd_soc_dapm_route pcm1792a_dapm_routes[] = {
-       { "IOUTL+", NULL, "Playback" },
-       { "IOUTL-", NULL, "Playback" },
-       { "IOUTR+", NULL, "Playback" },
-       { "IOUTR-", NULL, "Playback" },
-};
-
-static struct snd_soc_dai_driver pcm1792a_dai = {
-       .name = "pcm1792a-hifi",
-       .playback = {
-               .stream_name = "Playback",
-               .channels_min = 2,
-               .channels_max = 2,
-               .rates = PCM1792A_RATES,
-               .formats = PCM1792A_FORMATS, },
-       .ops = &pcm1792a_dai_ops,
-};
-
-static const struct of_device_id pcm1792a_of_match[] = {
-       { .compatible = "ti,pcm1792a", },
-       { }
-};
-MODULE_DEVICE_TABLE(of, pcm1792a_of_match);
-
-static const struct regmap_config pcm1792a_regmap = {
-       .reg_bits               = 8,
-       .val_bits               = 8,
-       .max_register           = 23,
-       .reg_defaults           = pcm1792a_reg_defaults,
-       .num_reg_defaults       = ARRAY_SIZE(pcm1792a_reg_defaults),
-       .writeable_reg          = pcm1792a_writeable_reg,
-       .readable_reg           = pcm1792a_accessible_reg,
-};
-
-static struct snd_soc_codec_driver soc_codec_dev_pcm1792a = {
-       .controls               = pcm1792a_controls,
-       .num_controls           = ARRAY_SIZE(pcm1792a_controls),
-       .dapm_widgets           = pcm1792a_dapm_widgets,
-       .num_dapm_widgets       = ARRAY_SIZE(pcm1792a_dapm_widgets),
-       .dapm_routes            = pcm1792a_dapm_routes,
-       .num_dapm_routes        = ARRAY_SIZE(pcm1792a_dapm_routes),
-};
-
-static int pcm1792a_spi_probe(struct spi_device *spi)
-{
-       struct pcm1792a_private *pcm1792a;
-       int ret;
-
-       pcm1792a = devm_kzalloc(&spi->dev, sizeof(struct pcm1792a_private),
-                               GFP_KERNEL);
-       if (!pcm1792a)
-               return -ENOMEM;
-
-       spi_set_drvdata(spi, pcm1792a);
-
-       pcm1792a->regmap = devm_regmap_init_spi(spi, &pcm1792a_regmap);
-       if (IS_ERR(pcm1792a->regmap)) {
-               ret = PTR_ERR(pcm1792a->regmap);
-               dev_err(&spi->dev, "Failed to register regmap: %d\n", ret);
-               return ret;
-       }
-
-       return snd_soc_register_codec(&spi->dev,
-                       &soc_codec_dev_pcm1792a, &pcm1792a_dai, 1);
-}
-
-static int pcm1792a_spi_remove(struct spi_device *spi)
-{
-       snd_soc_unregister_codec(&spi->dev);
-       return 0;
-}
-
-static const struct spi_device_id pcm1792a_spi_ids[] = {
-       { "pcm1792a", 0 },
-       { },
-};
-MODULE_DEVICE_TABLE(spi, pcm1792a_spi_ids);
-
-static struct spi_driver pcm1792a_codec_driver = {
-       .driver = {
-               .name = "pcm1792a",
-               .of_match_table = of_match_ptr(pcm1792a_of_match),
-       },
-       .id_table = pcm1792a_spi_ids,
-       .probe = pcm1792a_spi_probe,
-       .remove = pcm1792a_spi_remove,
-};
-
-module_spi_driver(pcm1792a_codec_driver);
-
-MODULE_DESCRIPTION("ASoC PCM1792A driver");
-MODULE_AUTHOR("Michael Trimarchi <michael@amarulasolutions.com>");
-MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/pcm179x.c b/sound/soc/codecs/pcm179x.c
new file mode 100644 (file)
index 0000000..a56c7b7
--- /dev/null
@@ -0,0 +1,271 @@
+/*
+ * PCM179X ASoC codec driver
+ *
+ * Copyright (c) Amarula Solutions B.V. 2013
+ *
+ *     Michael Trimarchi <michael@amarulasolutions.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.
+ *
+ * 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/slab.h>
+#include <linux/kernel.h>
+#include <linux/device.h>
+#include <linux/spi/spi.h>
+
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/initval.h>
+#include <sound/soc.h>
+#include <sound/tlv.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+
+#include "pcm179x.h"
+
+#define PCM179X_DAC_VOL_LEFT   0x10
+#define PCM179X_DAC_VOL_RIGHT  0x11
+#define PCM179X_FMT_CONTROL    0x12
+#define PCM179X_MODE_CONTROL   0x13
+#define PCM179X_SOFT_MUTE      PCM179X_FMT_CONTROL
+
+#define PCM179X_FMT_MASK       0x70
+#define PCM179X_FMT_SHIFT      4
+#define PCM179X_MUTE_MASK      0x01
+#define PCM179X_MUTE_SHIFT     0
+#define PCM179X_ATLD_ENABLE    (1 << 7)
+
+static const struct reg_default pcm179x_reg_defaults[] = {
+       { 0x10, 0xff },
+       { 0x11, 0xff },
+       { 0x12, 0x50 },
+       { 0x13, 0x00 },
+       { 0x14, 0x00 },
+       { 0x15, 0x01 },
+       { 0x16, 0x00 },
+       { 0x17, 0x00 },
+};
+
+static bool pcm179x_accessible_reg(struct device *dev, unsigned int reg)
+{
+       return reg >= 0x10 && reg <= 0x17;
+}
+
+static bool pcm179x_writeable_reg(struct device *dev, unsigned register reg)
+{
+       bool accessible;
+
+       accessible = pcm179x_accessible_reg(dev, reg);
+
+       return accessible && reg != 0x16 && reg != 0x17;
+}
+
+struct pcm179x_private {
+       struct regmap *regmap;
+       unsigned int format;
+       unsigned int rate;
+};
+
+static int pcm179x_set_dai_fmt(struct snd_soc_dai *codec_dai,
+                             unsigned int format)
+{
+       struct snd_soc_codec *codec = codec_dai->codec;
+       struct pcm179x_private *priv = snd_soc_codec_get_drvdata(codec);
+
+       priv->format = format;
+
+       return 0;
+}
+
+static int pcm179x_digital_mute(struct snd_soc_dai *dai, int mute)
+{
+       struct snd_soc_codec *codec = dai->codec;
+       struct pcm179x_private *priv = snd_soc_codec_get_drvdata(codec);
+       int ret;
+
+       ret = regmap_update_bits(priv->regmap, PCM179X_SOFT_MUTE,
+                                PCM179X_MUTE_MASK, !!mute);
+       if (ret < 0)
+               return ret;
+
+       return 0;
+}
+
+static int pcm179x_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 pcm179x_private *priv = snd_soc_codec_get_drvdata(codec);
+       int val = 0, ret;
+
+       priv->rate = params_rate(params);
+
+       switch (priv->format & SND_SOC_DAIFMT_FORMAT_MASK) {
+       case SND_SOC_DAIFMT_RIGHT_J:
+               switch (params_width(params)) {
+               case 24:
+               case 32:
+                       val = 2;
+                       break;
+               case 16:
+                       val = 0;
+                       break;
+               default:
+                       return -EINVAL;
+               }
+               break;
+       case SND_SOC_DAIFMT_I2S:
+               switch (params_width(params)) {
+               case 24:
+               case 32:
+                       val = 5;
+                       break;
+               case 16:
+                       val = 4;
+                       break;
+               default:
+                       return -EINVAL;
+               }
+               break;
+       default:
+               dev_err(codec->dev, "Invalid DAI format\n");
+               return -EINVAL;
+       }
+
+       val = val << PCM179X_FMT_SHIFT | PCM179X_ATLD_ENABLE;
+
+       ret = regmap_update_bits(priv->regmap, PCM179X_FMT_CONTROL,
+                                PCM179X_FMT_MASK | PCM179X_ATLD_ENABLE, val);
+       if (ret < 0)
+               return ret;
+
+       return 0;
+}
+
+static const struct snd_soc_dai_ops pcm179x_dai_ops = {
+       .set_fmt        = pcm179x_set_dai_fmt,
+       .hw_params      = pcm179x_hw_params,
+       .digital_mute   = pcm179x_digital_mute,
+};
+
+static const DECLARE_TLV_DB_SCALE(pcm179x_dac_tlv, -12000, 50, 1);
+
+static const struct snd_kcontrol_new pcm179x_controls[] = {
+       SOC_DOUBLE_R_RANGE_TLV("DAC Playback Volume", PCM179X_DAC_VOL_LEFT,
+                        PCM179X_DAC_VOL_RIGHT, 0, 0xf, 0xff, 0,
+                        pcm179x_dac_tlv),
+       SOC_SINGLE("DAC Invert Output Switch", PCM179X_MODE_CONTROL, 7, 1, 0),
+       SOC_SINGLE("DAC Rolloff Filter Switch", PCM179X_MODE_CONTROL, 1, 1, 0),
+};
+
+static const struct snd_soc_dapm_widget pcm179x_dapm_widgets[] = {
+SND_SOC_DAPM_OUTPUT("IOUTL+"),
+SND_SOC_DAPM_OUTPUT("IOUTL-"),
+SND_SOC_DAPM_OUTPUT("IOUTR+"),
+SND_SOC_DAPM_OUTPUT("IOUTR-"),
+};
+
+static const struct snd_soc_dapm_route pcm179x_dapm_routes[] = {
+       { "IOUTL+", NULL, "Playback" },
+       { "IOUTL-", NULL, "Playback" },
+       { "IOUTR+", NULL, "Playback" },
+       { "IOUTR-", NULL, "Playback" },
+};
+
+static struct snd_soc_dai_driver pcm179x_dai = {
+       .name = "pcm179x-hifi",
+       .playback = {
+               .stream_name = "Playback",
+               .channels_min = 2,
+               .channels_max = 2,
+               .rates = PCM1792A_RATES,
+               .formats = PCM1792A_FORMATS, },
+       .ops = &pcm179x_dai_ops,
+};
+
+static const struct of_device_id pcm179x_of_match[] = {
+       { .compatible = "ti,pcm1792a", },
+       { }
+};
+MODULE_DEVICE_TABLE(of, pcm179x_of_match);
+
+static const struct regmap_config pcm179x_regmap = {
+       .reg_bits               = 8,
+       .val_bits               = 8,
+       .max_register           = 23,
+       .reg_defaults           = pcm179x_reg_defaults,
+       .num_reg_defaults       = ARRAY_SIZE(pcm179x_reg_defaults),
+       .writeable_reg          = pcm179x_writeable_reg,
+       .readable_reg           = pcm179x_accessible_reg,
+};
+
+static struct snd_soc_codec_driver soc_codec_dev_pcm179x = {
+       .controls               = pcm179x_controls,
+       .num_controls           = ARRAY_SIZE(pcm179x_controls),
+       .dapm_widgets           = pcm179x_dapm_widgets,
+       .num_dapm_widgets       = ARRAY_SIZE(pcm179x_dapm_widgets),
+       .dapm_routes            = pcm179x_dapm_routes,
+       .num_dapm_routes        = ARRAY_SIZE(pcm179x_dapm_routes),
+};
+
+static int pcm179x_spi_probe(struct spi_device *spi)
+{
+       struct pcm179x_private *pcm179x;
+       int ret;
+
+       pcm179x = devm_kzalloc(&spi->dev, sizeof(struct pcm179x_private),
+                               GFP_KERNEL);
+       if (!pcm179x)
+               return -ENOMEM;
+
+       spi_set_drvdata(spi, pcm179x);
+
+       pcm179x->regmap = devm_regmap_init_spi(spi, &pcm179x_regmap);
+       if (IS_ERR(pcm179x->regmap)) {
+               ret = PTR_ERR(pcm179x->regmap);
+               dev_err(&spi->dev, "Failed to register regmap: %d\n", ret);
+               return ret;
+       }
+
+       return snd_soc_register_codec(&spi->dev,
+                       &soc_codec_dev_pcm179x, &pcm179x_dai, 1);
+}
+
+static int pcm179x_spi_remove(struct spi_device *spi)
+{
+       snd_soc_unregister_codec(&spi->dev);
+       return 0;
+}
+
+static const struct spi_device_id pcm179x_spi_ids[] = {
+       { "pcm179x", 0 },
+       { },
+};
+MODULE_DEVICE_TABLE(spi, pcm179x_spi_ids);
+
+static struct spi_driver pcm179x_codec_driver = {
+       .driver = {
+               .name = "pcm179x",
+               .of_match_table = of_match_ptr(pcm179x_of_match),
+       },
+       .id_table = pcm179x_spi_ids,
+       .probe = pcm179x_spi_probe,
+       .remove = pcm179x_spi_remove,
+};
+
+module_spi_driver(pcm179x_codec_driver);
+
+MODULE_DESCRIPTION("ASoC PCM179X driver");
+MODULE_AUTHOR("Michael Trimarchi <michael@amarulasolutions.com>");
+MODULE_LICENSE("GPL");
similarity index 91%
rename from sound/soc/codecs/pcm1792a.h
rename to sound/soc/codecs/pcm179x.h
index 51d5470fee1673680ef3c1420aaa08b785ce103e..c6fdc062a497ef080ee3e4225ba90328e1c390cc 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * definitions for PCM1792A
+ * definitions for PCM179X
  *
  * Copyright 2013 Amarula Solutions
  *
@@ -14,8 +14,8 @@
  * GNU General Public License for more details.
  */
 
-#ifndef __PCM1792A_H__
-#define __PCM1792A_H__
+#ifndef __PCM179X_H__
+#define __PCM179X_H__
 
 #define PCM1792A_RATES (SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_8000_48000 | \
                        SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000 | \
diff --git a/sound/soc/codecs/pcm3168a-i2c.c b/sound/soc/codecs/pcm3168a-i2c.c
new file mode 100644 (file)
index 0000000..6feb090
--- /dev/null
@@ -0,0 +1,66 @@
+/*
+ * PCM3168A codec i2c driver
+ *
+ * Copyright (C) 2015 Imagination Technologies Ltd.
+ *
+ * Author: Damien Horsley <Damien.Horsley@imgtec.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.
+ */
+
+#include <linux/i2c.h>
+#include <linux/init.h>
+#include <linux/module.h>
+
+#include <sound/soc.h>
+
+#include "pcm3168a.h"
+
+static int pcm3168a_i2c_probe(struct i2c_client *i2c,
+                            const struct i2c_device_id *id)
+{
+       struct regmap *regmap;
+
+       regmap = devm_regmap_init_i2c(i2c, &pcm3168a_regmap);
+       if (IS_ERR(regmap))
+               return PTR_ERR(regmap);
+
+       return pcm3168a_probe(&i2c->dev, regmap);
+}
+
+static int pcm3168a_i2c_remove(struct i2c_client *i2c)
+{
+       pcm3168a_remove(&i2c->dev);
+
+       return 0;
+}
+
+static const struct i2c_device_id pcm3168a_i2c_id[] = {
+       { "pcm3168a", },
+       { }
+};
+MODULE_DEVICE_TABLE(i2c, pcm3168a_i2c_id);
+
+static const struct of_device_id pcm3168a_of_match[] = {
+       { .compatible = "ti,pcm3168a", },
+       { }
+};
+MODULE_DEVICE_TABLE(of, pcm3168a_of_match);
+
+static struct i2c_driver pcm3168a_i2c_driver = {
+       .probe          = pcm3168a_i2c_probe,
+       .remove         = pcm3168a_i2c_remove,
+       .id_table       = pcm3168a_i2c_id,
+       .driver         = {
+               .name   = "pcm3168a",
+               .of_match_table = pcm3168a_of_match,
+               .pm             = &pcm3168a_pm_ops,
+       },
+};
+module_i2c_driver(pcm3168a_i2c_driver);
+
+MODULE_DESCRIPTION("PCM3168A I2C codec driver");
+MODULE_AUTHOR("Damien Horsley <Damien.Horsley@imgtec.com>");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/codecs/pcm3168a-spi.c b/sound/soc/codecs/pcm3168a-spi.c
new file mode 100644 (file)
index 0000000..03945a2
--- /dev/null
@@ -0,0 +1,65 @@
+/*
+ * PCM3168A codec spi driver
+ *
+ * Copyright (C) 2015 Imagination Technologies Ltd.
+ *
+ * Author: Damien Horsley <Damien.Horsley@imgtec.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.
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/spi/spi.h>
+
+#include <sound/soc.h>
+
+#include "pcm3168a.h"
+
+static int pcm3168a_spi_probe(struct spi_device *spi)
+{
+       struct regmap *regmap;
+
+       regmap = devm_regmap_init_spi(spi, &pcm3168a_regmap);
+       if (IS_ERR(regmap))
+               return PTR_ERR(regmap);
+
+       return pcm3168a_probe(&spi->dev, regmap);
+}
+
+static int pcm3168a_spi_remove(struct spi_device *spi)
+{
+       pcm3168a_remove(&spi->dev);
+
+       return 0;
+}
+
+static const struct spi_device_id pcm3168a_spi_id[] = {
+       { "pcm3168a", },
+       { },
+};
+MODULE_DEVICE_TABLE(spi, pcm3168a_spi_id);
+
+static const struct of_device_id pcm3168a_of_match[] = {
+       { .compatible = "ti,pcm3168a", },
+       { }
+};
+MODULE_DEVICE_TABLE(of, pcm3168a_of_match);
+
+static struct spi_driver pcm3168a_spi_driver = {
+       .probe          = pcm3168a_spi_probe,
+       .remove         = pcm3168a_spi_remove,
+       .id_table       = pcm3168a_spi_id,
+       .driver = {
+               .name   = "pcm3168a",
+               .of_match_table = pcm3168a_of_match,
+               .pm             = &pcm3168a_pm_ops,
+       },
+};
+module_spi_driver(pcm3168a_spi_driver);
+
+MODULE_DESCRIPTION("PCM3168A SPI codec driver");
+MODULE_AUTHOR("Damien Horsley <Damien.Horsley@imgtec.com>");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/codecs/pcm3168a.c b/sound/soc/codecs/pcm3168a.c
new file mode 100644 (file)
index 0000000..44b268a
--- /dev/null
@@ -0,0 +1,767 @@
+/*
+ * PCM3168A codec driver
+ *
+ * Copyright (C) 2015 Imagination Technologies Ltd.
+ *
+ * Author: Damien Horsley <Damien.Horsley@imgtec.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.
+ */
+
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/module.h>
+#include <linux/pm_runtime.h>
+#include <linux/regulator/consumer.h>
+
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/tlv.h>
+
+#include "pcm3168a.h"
+
+#define PCM3168A_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | \
+                        SNDRV_PCM_FMTBIT_S24_3LE | \
+                        SNDRV_PCM_FMTBIT_S24_LE | \
+                        SNDRV_PCM_FMTBIT_S32_LE)
+
+#define PCM3168A_FMT_I2S               0x0
+#define PCM3168A_FMT_LEFT_J            0x1
+#define PCM3168A_FMT_RIGHT_J           0x2
+#define PCM3168A_FMT_RIGHT_J_16                0x3
+#define PCM3168A_FMT_DSP_A             0x4
+#define PCM3168A_FMT_DSP_B             0x5
+#define PCM3168A_FMT_DSP_MASK          0x4
+
+#define PCM3168A_NUM_SUPPLIES 6
+static const char *const pcm3168a_supply_names[PCM3168A_NUM_SUPPLIES] = {
+       "VDD1",
+       "VDD2",
+       "VCCAD1",
+       "VCCAD2",
+       "VCCDA1",
+       "VCCDA2"
+};
+
+struct pcm3168a_priv {
+       struct regulator_bulk_data supplies[PCM3168A_NUM_SUPPLIES];
+       struct regmap *regmap;
+       struct clk *scki;
+       bool adc_master_mode;
+       bool dac_master_mode;
+       unsigned long sysclk;
+       unsigned int adc_fmt;
+       unsigned int dac_fmt;
+};
+
+static const char *const pcm3168a_roll_off[] = { "Sharp", "Slow" };
+
+static SOC_ENUM_SINGLE_DECL(pcm3168a_d1_roll_off, PCM3168A_DAC_OP_FLT,
+               PCM3168A_DAC_FLT_SHIFT, pcm3168a_roll_off);
+static SOC_ENUM_SINGLE_DECL(pcm3168a_d2_roll_off, PCM3168A_DAC_OP_FLT,
+               PCM3168A_DAC_FLT_SHIFT + 1, pcm3168a_roll_off);
+static SOC_ENUM_SINGLE_DECL(pcm3168a_d3_roll_off, PCM3168A_DAC_OP_FLT,
+               PCM3168A_DAC_FLT_SHIFT + 2, pcm3168a_roll_off);
+static SOC_ENUM_SINGLE_DECL(pcm3168a_d4_roll_off, PCM3168A_DAC_OP_FLT,
+               PCM3168A_DAC_FLT_SHIFT + 3, pcm3168a_roll_off);
+
+static const char *const pcm3168a_volume_type[] = {
+               "Individual", "Master + Individual" };
+
+static SOC_ENUM_SINGLE_DECL(pcm3168a_dac_volume_type, PCM3168A_DAC_ATT_DEMP_ZF,
+               PCM3168A_DAC_ATMDDA_SHIFT, pcm3168a_volume_type);
+
+static const char *const pcm3168a_att_speed_mult[] = { "2048", "4096" };
+
+static SOC_ENUM_SINGLE_DECL(pcm3168a_dac_att_mult, PCM3168A_DAC_ATT_DEMP_ZF,
+               PCM3168A_DAC_ATSPDA_SHIFT, pcm3168a_att_speed_mult);
+
+static const char *const pcm3168a_demp[] = {
+               "Disabled", "48khz", "44.1khz", "32khz" };
+
+static SOC_ENUM_SINGLE_DECL(pcm3168a_dac_demp, PCM3168A_DAC_ATT_DEMP_ZF,
+               PCM3168A_DAC_DEMP_SHIFT, pcm3168a_demp);
+
+static const char *const pcm3168a_zf_func[] = {
+               "DAC 1/2/3/4 AND", "DAC 1/2/3/4 OR", "DAC 1/2/3 AND",
+               "DAC 1/2/3 OR", "DAC 4 AND", "DAC 4 OR" };
+
+static SOC_ENUM_SINGLE_DECL(pcm3168a_dac_zf_func, PCM3168A_DAC_ATT_DEMP_ZF,
+               PCM3168A_DAC_AZRO_SHIFT, pcm3168a_zf_func);
+
+static const char *const pcm3168a_pol[] = { "Active High", "Active Low" };
+
+static SOC_ENUM_SINGLE_DECL(pcm3168a_dac_zf_pol, PCM3168A_DAC_ATT_DEMP_ZF,
+               PCM3168A_DAC_ATSPDA_SHIFT, pcm3168a_pol);
+
+static const char *const pcm3168a_con[] = { "Differential", "Single-Ended" };
+
+static SOC_ENUM_DOUBLE_DECL(pcm3168a_adc1_con, PCM3168A_ADC_SEAD,
+                               0, 1, pcm3168a_con);
+static SOC_ENUM_DOUBLE_DECL(pcm3168a_adc2_con, PCM3168A_ADC_SEAD,
+                               2, 3, pcm3168a_con);
+static SOC_ENUM_DOUBLE_DECL(pcm3168a_adc3_con, PCM3168A_ADC_SEAD,
+                               4, 5, pcm3168a_con);
+
+static SOC_ENUM_SINGLE_DECL(pcm3168a_adc_volume_type, PCM3168A_ADC_ATT_OVF,
+               PCM3168A_ADC_ATMDAD_SHIFT, pcm3168a_volume_type);
+
+static SOC_ENUM_SINGLE_DECL(pcm3168a_adc_att_mult, PCM3168A_ADC_ATT_OVF,
+               PCM3168A_ADC_ATSPAD_SHIFT, pcm3168a_att_speed_mult);
+
+static SOC_ENUM_SINGLE_DECL(pcm3168a_adc_ov_pol, PCM3168A_ADC_ATT_OVF,
+               PCM3168A_ADC_OVFP_SHIFT, pcm3168a_pol);
+
+/* -100db to 0db, register values 0-54 cause mute */
+static const DECLARE_TLV_DB_SCALE(pcm3168a_dac_tlv, -10050, 50, 1);
+
+/* -100db to 20db, register values 0-14 cause mute */
+static const DECLARE_TLV_DB_SCALE(pcm3168a_adc_tlv, -10050, 50, 1);
+
+static const struct snd_kcontrol_new pcm3168a_snd_controls[] = {
+       SOC_SINGLE("DAC Power-Save Switch", PCM3168A_DAC_PWR_MST_FMT,
+                       PCM3168A_DAC_PSMDA_SHIFT, 1, 1),
+       SOC_ENUM("DAC1 Digital Filter roll-off", pcm3168a_d1_roll_off),
+       SOC_ENUM("DAC2 Digital Filter roll-off", pcm3168a_d2_roll_off),
+       SOC_ENUM("DAC3 Digital Filter roll-off", pcm3168a_d3_roll_off),
+       SOC_ENUM("DAC4 Digital Filter roll-off", pcm3168a_d4_roll_off),
+       SOC_DOUBLE("DAC1 Invert Switch", PCM3168A_DAC_INV, 0, 1, 1, 0),
+       SOC_DOUBLE("DAC2 Invert Switch", PCM3168A_DAC_INV, 2, 3, 1, 0),
+       SOC_DOUBLE("DAC3 Invert Switch", PCM3168A_DAC_INV, 4, 5, 1, 0),
+       SOC_DOUBLE("DAC4 Invert Switch", PCM3168A_DAC_INV, 6, 7, 1, 0),
+       SOC_DOUBLE_STS("DAC1 Zero Flag", PCM3168A_DAC_ZERO, 0, 1, 1, 0),
+       SOC_DOUBLE_STS("DAC2 Zero Flag", PCM3168A_DAC_ZERO, 2, 3, 1, 0),
+       SOC_DOUBLE_STS("DAC3 Zero Flag", PCM3168A_DAC_ZERO, 4, 5, 1, 0),
+       SOC_DOUBLE_STS("DAC4 Zero Flag", PCM3168A_DAC_ZERO, 6, 7, 1, 0),
+       SOC_ENUM("DAC Volume Control Type", pcm3168a_dac_volume_type),
+       SOC_ENUM("DAC Volume Rate Multiplier", pcm3168a_dac_att_mult),
+       SOC_ENUM("DAC De-Emphasis", pcm3168a_dac_demp),
+       SOC_ENUM("DAC Zero Flag Function", pcm3168a_dac_zf_func),
+       SOC_ENUM("DAC Zero Flag Polarity", pcm3168a_dac_zf_pol),
+       SOC_SINGLE_RANGE_TLV("Master Playback Volume",
+                       PCM3168A_DAC_VOL_MASTER, 0, 54, 255, 0,
+                       pcm3168a_dac_tlv),
+       SOC_DOUBLE_R_RANGE_TLV("DAC1 Playback Volume",
+                       PCM3168A_DAC_VOL_CHAN_START,
+                       PCM3168A_DAC_VOL_CHAN_START + 1,
+                       0, 54, 255, 0, pcm3168a_dac_tlv),
+       SOC_DOUBLE_R_RANGE_TLV("DAC2 Playback Volume",
+                       PCM3168A_DAC_VOL_CHAN_START + 2,
+                       PCM3168A_DAC_VOL_CHAN_START + 3,
+                       0, 54, 255, 0, pcm3168a_dac_tlv),
+       SOC_DOUBLE_R_RANGE_TLV("DAC3 Playback Volume",
+                       PCM3168A_DAC_VOL_CHAN_START + 4,
+                       PCM3168A_DAC_VOL_CHAN_START + 5,
+                       0, 54, 255, 0, pcm3168a_dac_tlv),
+       SOC_DOUBLE_R_RANGE_TLV("DAC4 Playback Volume",
+                       PCM3168A_DAC_VOL_CHAN_START + 6,
+                       PCM3168A_DAC_VOL_CHAN_START + 7,
+                       0, 54, 255, 0, pcm3168a_dac_tlv),
+       SOC_SINGLE("ADC1 High-Pass Filter Switch", PCM3168A_ADC_PWR_HPFB,
+                       PCM3168A_ADC_BYP_SHIFT, 1, 1),
+       SOC_SINGLE("ADC2 High-Pass Filter Switch", PCM3168A_ADC_PWR_HPFB,
+                       PCM3168A_ADC_BYP_SHIFT + 1, 1, 1),
+       SOC_SINGLE("ADC3 High-Pass Filter Switch", PCM3168A_ADC_PWR_HPFB,
+                       PCM3168A_ADC_BYP_SHIFT + 2, 1, 1),
+       SOC_ENUM("ADC1 Connection Type", pcm3168a_adc1_con),
+       SOC_ENUM("ADC2 Connection Type", pcm3168a_adc2_con),
+       SOC_ENUM("ADC3 Connection Type", pcm3168a_adc3_con),
+       SOC_DOUBLE("ADC1 Invert Switch", PCM3168A_ADC_INV, 0, 1, 1, 0),
+       SOC_DOUBLE("ADC2 Invert Switch", PCM3168A_ADC_INV, 2, 3, 1, 0),
+       SOC_DOUBLE("ADC3 Invert Switch", PCM3168A_ADC_INV, 4, 5, 1, 0),
+       SOC_DOUBLE("ADC1 Mute Switch", PCM3168A_ADC_MUTE, 0, 1, 1, 0),
+       SOC_DOUBLE("ADC2 Mute Switch", PCM3168A_ADC_MUTE, 2, 3, 1, 0),
+       SOC_DOUBLE("ADC3 Mute Switch", PCM3168A_ADC_MUTE, 4, 5, 1, 0),
+       SOC_DOUBLE_STS("ADC1 Overflow Flag", PCM3168A_ADC_OV, 0, 1, 1, 0),
+       SOC_DOUBLE_STS("ADC2 Overflow Flag", PCM3168A_ADC_OV, 2, 3, 1, 0),
+       SOC_DOUBLE_STS("ADC3 Overflow Flag", PCM3168A_ADC_OV, 4, 5, 1, 0),
+       SOC_ENUM("ADC Volume Control Type", pcm3168a_adc_volume_type),
+       SOC_ENUM("ADC Volume Rate Multiplier", pcm3168a_adc_att_mult),
+       SOC_ENUM("ADC Overflow Flag Polarity", pcm3168a_adc_ov_pol),
+       SOC_SINGLE_RANGE_TLV("Master Capture Volume",
+                       PCM3168A_ADC_VOL_MASTER, 0, 14, 255, 0,
+                       pcm3168a_adc_tlv),
+       SOC_DOUBLE_R_RANGE_TLV("ADC1 Capture Volume",
+                       PCM3168A_ADC_VOL_CHAN_START,
+                       PCM3168A_ADC_VOL_CHAN_START + 1,
+                       0, 14, 255, 0, pcm3168a_adc_tlv),
+       SOC_DOUBLE_R_RANGE_TLV("ADC2 Capture Volume",
+                       PCM3168A_ADC_VOL_CHAN_START + 2,
+                       PCM3168A_ADC_VOL_CHAN_START + 3,
+                       0, 14, 255, 0, pcm3168a_adc_tlv),
+       SOC_DOUBLE_R_RANGE_TLV("ADC3 Capture Volume",
+                       PCM3168A_ADC_VOL_CHAN_START + 4,
+                       PCM3168A_ADC_VOL_CHAN_START + 5,
+                       0, 14, 255, 0, pcm3168a_adc_tlv)
+};
+
+static const struct snd_soc_dapm_widget pcm3168a_dapm_widgets[] = {
+       SND_SOC_DAPM_DAC("DAC1", "Playback", PCM3168A_DAC_OP_FLT,
+                       PCM3168A_DAC_OPEDA_SHIFT, 1),
+       SND_SOC_DAPM_DAC("DAC2", "Playback", PCM3168A_DAC_OP_FLT,
+                       PCM3168A_DAC_OPEDA_SHIFT + 1, 1),
+       SND_SOC_DAPM_DAC("DAC3", "Playback", PCM3168A_DAC_OP_FLT,
+                       PCM3168A_DAC_OPEDA_SHIFT + 2, 1),
+       SND_SOC_DAPM_DAC("DAC4", "Playback", PCM3168A_DAC_OP_FLT,
+                       PCM3168A_DAC_OPEDA_SHIFT + 3, 1),
+
+       SND_SOC_DAPM_OUTPUT("AOUT1L"),
+       SND_SOC_DAPM_OUTPUT("AOUT1R"),
+       SND_SOC_DAPM_OUTPUT("AOUT2L"),
+       SND_SOC_DAPM_OUTPUT("AOUT2R"),
+       SND_SOC_DAPM_OUTPUT("AOUT3L"),
+       SND_SOC_DAPM_OUTPUT("AOUT3R"),
+       SND_SOC_DAPM_OUTPUT("AOUT4L"),
+       SND_SOC_DAPM_OUTPUT("AOUT4R"),
+
+       SND_SOC_DAPM_ADC("ADC1", "Capture", PCM3168A_ADC_PWR_HPFB,
+                       PCM3168A_ADC_PSVAD_SHIFT, 1),
+       SND_SOC_DAPM_ADC("ADC2", "Capture", PCM3168A_ADC_PWR_HPFB,
+                       PCM3168A_ADC_PSVAD_SHIFT + 1, 1),
+       SND_SOC_DAPM_ADC("ADC3", "Capture", PCM3168A_ADC_PWR_HPFB,
+                       PCM3168A_ADC_PSVAD_SHIFT + 2, 1),
+
+       SND_SOC_DAPM_INPUT("AIN1L"),
+       SND_SOC_DAPM_INPUT("AIN1R"),
+       SND_SOC_DAPM_INPUT("AIN2L"),
+       SND_SOC_DAPM_INPUT("AIN2R"),
+       SND_SOC_DAPM_INPUT("AIN3L"),
+       SND_SOC_DAPM_INPUT("AIN3R")
+};
+
+static const struct snd_soc_dapm_route pcm3168a_dapm_routes[] = {
+       /* Playback */
+       { "AOUT1L", NULL, "DAC1" },
+       { "AOUT1R", NULL, "DAC1" },
+
+       { "AOUT2L", NULL, "DAC2" },
+       { "AOUT2R", NULL, "DAC2" },
+
+       { "AOUT3L", NULL, "DAC3" },
+       { "AOUT3R", NULL, "DAC3" },
+
+       { "AOUT4L", NULL, "DAC4" },
+       { "AOUT4R", NULL, "DAC4" },
+
+       /* Capture */
+       { "ADC1", NULL, "AIN1L" },
+       { "ADC1", NULL, "AIN1R" },
+
+       { "ADC2", NULL, "AIN2L" },
+       { "ADC2", NULL, "AIN2R" },
+
+       { "ADC3", NULL, "AIN3L" },
+       { "ADC3", NULL, "AIN3R" }
+};
+
+static unsigned int pcm3168a_scki_ratios[] = {
+       768,
+       512,
+       384,
+       256,
+       192,
+       128
+};
+
+#define PCM3168A_NUM_SCKI_RATIOS_DAC   ARRAY_SIZE(pcm3168a_scki_ratios)
+#define PCM3168A_NUM_SCKI_RATIOS_ADC   (ARRAY_SIZE(pcm3168a_scki_ratios) - 2)
+
+#define PCM1368A_MAX_SYSCLK            36864000
+
+static int pcm3168a_reset(struct pcm3168a_priv *pcm3168a)
+{
+       int ret;
+
+       ret = regmap_write(pcm3168a->regmap, PCM3168A_RST_SMODE, 0);
+       if (ret)
+               return ret;
+
+       /* Internal reset is de-asserted after 3846 SCKI cycles */
+       msleep(DIV_ROUND_UP(3846 * 1000, pcm3168a->sysclk));
+
+       return regmap_write(pcm3168a->regmap, PCM3168A_RST_SMODE,
+                       PCM3168A_MRST_MASK | PCM3168A_SRST_MASK);
+}
+
+static int pcm3168a_digital_mute(struct snd_soc_dai *dai, int mute)
+{
+       struct snd_soc_codec *codec = dai->codec;
+       struct pcm3168a_priv *pcm3168a = snd_soc_codec_get_drvdata(codec);
+
+       regmap_write(pcm3168a->regmap, PCM3168A_DAC_MUTE, mute ? 0xff : 0);
+
+       return 0;
+}
+
+static int pcm3168a_set_dai_sysclk(struct snd_soc_dai *dai,
+                                 int clk_id, unsigned int freq, int dir)
+{
+       struct pcm3168a_priv *pcm3168a = snd_soc_codec_get_drvdata(dai->codec);
+
+       if (freq > PCM1368A_MAX_SYSCLK)
+               return -EINVAL;
+
+       pcm3168a->sysclk = freq;
+
+       return 0;
+}
+
+static int pcm3168a_set_dai_fmt(struct snd_soc_dai *dai,
+                              unsigned int format, bool dac)
+{
+       struct snd_soc_codec *codec = dai->codec;
+       struct pcm3168a_priv *pcm3168a = snd_soc_codec_get_drvdata(codec);
+       u32 fmt, reg, mask, shift;
+       bool master_mode;
+
+       switch (format & SND_SOC_DAIFMT_FORMAT_MASK) {
+       case SND_SOC_DAIFMT_LEFT_J:
+               fmt = PCM3168A_FMT_LEFT_J;
+               break;
+       case SND_SOC_DAIFMT_I2S:
+               fmt = PCM3168A_FMT_I2S;
+               break;
+       case SND_SOC_DAIFMT_RIGHT_J:
+               fmt = PCM3168A_FMT_RIGHT_J;
+               break;
+       case SND_SOC_DAIFMT_DSP_A:
+               fmt = PCM3168A_FMT_DSP_A;
+               break;
+       case SND_SOC_DAIFMT_DSP_B:
+               fmt = PCM3168A_FMT_DSP_B;
+               break;
+       default:
+               dev_err(codec->dev, "unsupported dai format\n");
+               return -EINVAL;
+       }
+
+       switch (format & SND_SOC_DAIFMT_MASTER_MASK) {
+       case SND_SOC_DAIFMT_CBS_CFS:
+               master_mode = false;
+               break;
+       case SND_SOC_DAIFMT_CBM_CFM:
+               master_mode = true;
+               break;
+       default:
+               dev_err(codec->dev, "unsupported master/slave mode\n");
+               return -EINVAL;
+       }
+
+       switch (format & SND_SOC_DAIFMT_INV_MASK) {
+       case SND_SOC_DAIFMT_NB_NF:
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       if (dac) {
+               reg = PCM3168A_DAC_PWR_MST_FMT;
+               mask = PCM3168A_DAC_FMT_MASK;
+               shift = PCM3168A_DAC_FMT_SHIFT;
+               pcm3168a->dac_master_mode = master_mode;
+               pcm3168a->dac_fmt = fmt;
+       } else {
+               reg = PCM3168A_ADC_MST_FMT;
+               mask = PCM3168A_ADC_FMTAD_MASK;
+               shift = PCM3168A_ADC_FMTAD_SHIFT;
+               pcm3168a->adc_master_mode = master_mode;
+               pcm3168a->adc_fmt = fmt;
+       }
+
+       regmap_update_bits(pcm3168a->regmap, reg, mask, fmt << shift);
+
+       return 0;
+}
+
+static int pcm3168a_set_dai_fmt_dac(struct snd_soc_dai *dai,
+                              unsigned int format)
+{
+       return pcm3168a_set_dai_fmt(dai, format, true);
+}
+
+static int pcm3168a_set_dai_fmt_adc(struct snd_soc_dai *dai,
+                              unsigned int format)
+{
+       return pcm3168a_set_dai_fmt(dai, format, false);
+}
+
+static int pcm3168a_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 pcm3168a_priv *pcm3168a = snd_soc_codec_get_drvdata(codec);
+       bool tx, master_mode;
+       u32 val, mask, shift, reg;
+       unsigned int rate, channels, fmt, ratio, max_ratio;
+       int i, min_frame_size;
+       snd_pcm_format_t format;
+
+       rate = params_rate(params);
+       format = params_format(params);
+       channels = params_channels(params);
+
+       ratio = pcm3168a->sysclk / rate;
+
+       tx = substream->stream == SNDRV_PCM_STREAM_PLAYBACK;
+       if (tx) {
+               max_ratio = PCM3168A_NUM_SCKI_RATIOS_DAC;
+               reg = PCM3168A_DAC_PWR_MST_FMT;
+               mask = PCM3168A_DAC_MSDA_MASK;
+               shift = PCM3168A_DAC_MSDA_SHIFT;
+               master_mode = pcm3168a->dac_master_mode;
+               fmt = pcm3168a->dac_fmt;
+       } else {
+               max_ratio = PCM3168A_NUM_SCKI_RATIOS_ADC;
+               reg = PCM3168A_ADC_MST_FMT;
+               mask = PCM3168A_ADC_MSAD_MASK;
+               shift = PCM3168A_ADC_MSAD_SHIFT;
+               master_mode = pcm3168a->adc_master_mode;
+               fmt = pcm3168a->adc_fmt;
+       }
+
+       for (i = 0; i < max_ratio; i++) {
+               if (pcm3168a_scki_ratios[i] == ratio)
+                       break;
+       }
+
+       if (i == max_ratio) {
+               dev_err(codec->dev, "unsupported sysclk ratio\n");
+               return -EINVAL;
+       }
+
+       min_frame_size = params_width(params) * 2;
+       switch (min_frame_size) {
+       case 32:
+               if (master_mode || (fmt != PCM3168A_FMT_RIGHT_J)) {
+                       dev_err(codec->dev, "32-bit frames are supported only for slave mode using right justified\n");
+                       return -EINVAL;
+               }
+               fmt = PCM3168A_FMT_RIGHT_J_16;
+               break;
+       case 48:
+               if (master_mode || (fmt & PCM3168A_FMT_DSP_MASK)) {
+                       dev_err(codec->dev, "48-bit frames not supported in master mode, or slave mode using DSP\n");
+                       return -EINVAL;
+               }
+               break;
+       case 64:
+               break;
+       default:
+               dev_err(codec->dev, "unsupported frame size: %d\n", min_frame_size);
+               return -EINVAL;
+       }
+
+       if (master_mode)
+               val = ((i + 1) << shift);
+       else
+               val = 0;
+
+       regmap_update_bits(pcm3168a->regmap, reg, mask, val);
+
+       if (tx) {
+               mask = PCM3168A_DAC_FMT_MASK;
+               shift = PCM3168A_DAC_FMT_SHIFT;
+       } else {
+               mask = PCM3168A_ADC_FMTAD_MASK;
+               shift = PCM3168A_ADC_FMTAD_SHIFT;
+       }
+
+       regmap_update_bits(pcm3168a->regmap, reg, mask, fmt << shift);
+
+       return 0;
+}
+
+static const struct snd_soc_dai_ops pcm3168a_dac_dai_ops = {
+       .set_fmt        = pcm3168a_set_dai_fmt_dac,
+       .set_sysclk     = pcm3168a_set_dai_sysclk,
+       .hw_params      = pcm3168a_hw_params,
+       .digital_mute   = pcm3168a_digital_mute
+};
+
+static const struct snd_soc_dai_ops pcm3168a_adc_dai_ops = {
+       .set_fmt        = pcm3168a_set_dai_fmt_adc,
+       .set_sysclk     = pcm3168a_set_dai_sysclk,
+       .hw_params      = pcm3168a_hw_params
+};
+
+static struct snd_soc_dai_driver pcm3168a_dais[] = {
+       {
+               .name = "pcm3168a-dac",
+               .playback = {
+                       .stream_name = "Playback",
+                       .channels_min = 1,
+                       .channels_max = 8,
+                       .rates = SNDRV_PCM_RATE_8000_192000,
+                       .formats = PCM3168A_FORMATS
+               },
+               .ops = &pcm3168a_dac_dai_ops
+       },
+       {
+               .name = "pcm3168a-adc",
+               .capture = {
+                       .stream_name = "Capture",
+                       .channels_min = 1,
+                       .channels_max = 6,
+                       .rates = SNDRV_PCM_RATE_8000_96000,
+                       .formats = PCM3168A_FORMATS
+               },
+               .ops = &pcm3168a_adc_dai_ops
+       },
+};
+
+static const struct reg_default pcm3168a_reg_default[] = {
+       { PCM3168A_RST_SMODE, PCM3168A_MRST_MASK | PCM3168A_SRST_MASK },
+       { PCM3168A_DAC_PWR_MST_FMT, 0x00 },
+       { PCM3168A_DAC_OP_FLT, 0x00 },
+       { PCM3168A_DAC_INV, 0x00 },
+       { PCM3168A_DAC_MUTE, 0x00 },
+       { PCM3168A_DAC_ZERO, 0x00 },
+       { PCM3168A_DAC_ATT_DEMP_ZF, 0x00 },
+       { PCM3168A_DAC_VOL_MASTER, 0xff },
+       { PCM3168A_DAC_VOL_CHAN_START, 0xff },
+       { PCM3168A_DAC_VOL_CHAN_START + 1, 0xff },
+       { PCM3168A_DAC_VOL_CHAN_START + 2, 0xff },
+       { PCM3168A_DAC_VOL_CHAN_START + 3, 0xff },
+       { PCM3168A_DAC_VOL_CHAN_START + 4, 0xff },
+       { PCM3168A_DAC_VOL_CHAN_START + 5, 0xff },
+       { PCM3168A_DAC_VOL_CHAN_START + 6, 0xff },
+       { PCM3168A_DAC_VOL_CHAN_START + 7, 0xff },
+       { PCM3168A_ADC_SMODE, 0x00 },
+       { PCM3168A_ADC_MST_FMT, 0x00 },
+       { PCM3168A_ADC_PWR_HPFB, 0x00 },
+       { PCM3168A_ADC_SEAD, 0x00 },
+       { PCM3168A_ADC_INV, 0x00 },
+       { PCM3168A_ADC_MUTE, 0x00 },
+       { PCM3168A_ADC_OV, 0x00 },
+       { PCM3168A_ADC_ATT_OVF, 0x00 },
+       { PCM3168A_ADC_VOL_MASTER, 0xd3 },
+       { PCM3168A_ADC_VOL_CHAN_START, 0xd3 },
+       { PCM3168A_ADC_VOL_CHAN_START + 1, 0xd3 },
+       { PCM3168A_ADC_VOL_CHAN_START + 2, 0xd3 },
+       { PCM3168A_ADC_VOL_CHAN_START + 3, 0xd3 },
+       { PCM3168A_ADC_VOL_CHAN_START + 4, 0xd3 },
+       { PCM3168A_ADC_VOL_CHAN_START + 5, 0xd3 }
+};
+
+static bool pcm3168a_readable_register(struct device *dev, unsigned int reg)
+{
+       if (reg >= PCM3168A_RST_SMODE)
+               return true;
+       else
+               return false;
+}
+
+static bool pcm3168a_volatile_register(struct device *dev, unsigned int reg)
+{
+       switch (reg) {
+       case PCM3168A_DAC_ZERO:
+       case PCM3168A_ADC_OV:
+               return true;
+       default:
+               return false;
+       }
+}
+
+static bool pcm3168a_writeable_register(struct device *dev, unsigned int reg)
+{
+       if (reg < PCM3168A_RST_SMODE)
+               return false;
+
+       switch (reg) {
+       case PCM3168A_DAC_ZERO:
+       case PCM3168A_ADC_OV:
+               return false;
+       default:
+               return true;
+       }
+}
+
+const struct regmap_config pcm3168a_regmap = {
+       .reg_bits = 8,
+       .val_bits = 8,
+
+       .max_register = PCM3168A_ADC_VOL_CHAN_START + 5,
+       .reg_defaults = pcm3168a_reg_default,
+       .num_reg_defaults = ARRAY_SIZE(pcm3168a_reg_default),
+       .readable_reg = pcm3168a_readable_register,
+       .volatile_reg = pcm3168a_volatile_register,
+       .writeable_reg = pcm3168a_writeable_register,
+       .cache_type = REGCACHE_FLAT
+};
+EXPORT_SYMBOL_GPL(pcm3168a_regmap);
+
+static const struct snd_soc_codec_driver pcm3168a_driver = {
+       .idle_bias_off = true,
+       .controls = pcm3168a_snd_controls,
+       .num_controls = ARRAY_SIZE(pcm3168a_snd_controls),
+       .dapm_widgets = pcm3168a_dapm_widgets,
+       .num_dapm_widgets = ARRAY_SIZE(pcm3168a_dapm_widgets),
+       .dapm_routes = pcm3168a_dapm_routes,
+       .num_dapm_routes = ARRAY_SIZE(pcm3168a_dapm_routes)
+};
+
+int pcm3168a_probe(struct device *dev, struct regmap *regmap)
+{
+       struct pcm3168a_priv *pcm3168a;
+       int ret, i;
+
+       pcm3168a = devm_kzalloc(dev, sizeof(*pcm3168a), GFP_KERNEL);
+       if (pcm3168a == NULL)
+               return -ENOMEM;
+
+       dev_set_drvdata(dev, pcm3168a);
+
+       pcm3168a->scki = devm_clk_get(dev, "scki");
+       if (IS_ERR(pcm3168a->scki)) {
+               ret = PTR_ERR(pcm3168a->scki);
+               if (ret != -EPROBE_DEFER)
+                       dev_err(dev, "failed to acquire clock 'scki': %d\n", ret);
+               return ret;
+       }
+
+       ret = clk_prepare_enable(pcm3168a->scki);
+       if (ret) {
+               dev_err(dev, "Failed to enable mclk: %d\n", ret);
+               return ret;
+       }
+
+       pcm3168a->sysclk = clk_get_rate(pcm3168a->scki);
+
+       for (i = 0; i < ARRAY_SIZE(pcm3168a->supplies); i++)
+               pcm3168a->supplies[i].supply = pcm3168a_supply_names[i];
+
+       ret = devm_regulator_bulk_get(dev,
+                       ARRAY_SIZE(pcm3168a->supplies), pcm3168a->supplies);
+       if (ret) {
+               if (ret != -EPROBE_DEFER)
+                       dev_err(dev, "failed to request supplies: %d\n", ret);
+               goto err_clk;
+       }
+
+       ret = regulator_bulk_enable(ARRAY_SIZE(pcm3168a->supplies),
+                                   pcm3168a->supplies);
+       if (ret) {
+               dev_err(dev, "failed to enable supplies: %d\n", ret);
+               goto err_clk;
+       }
+
+       pcm3168a->regmap = regmap;
+       if (IS_ERR(pcm3168a->regmap)) {
+               ret = PTR_ERR(pcm3168a->regmap);
+               dev_err(dev, "failed to allocate regmap: %d\n", ret);
+               goto err_regulator;
+       }
+
+       ret = pcm3168a_reset(pcm3168a);
+       if (ret) {
+               dev_err(dev, "Failed to reset device: %d\n", ret);
+               goto err_regulator;
+       }
+
+       pm_runtime_set_active(dev);
+       pm_runtime_enable(dev);
+       pm_runtime_idle(dev);
+
+       ret = snd_soc_register_codec(dev, &pcm3168a_driver, pcm3168a_dais,
+                       ARRAY_SIZE(pcm3168a_dais));
+       if (ret) {
+               dev_err(dev, "failed to register codec: %d\n", ret);
+               goto err_regulator;
+       }
+
+       return 0;
+
+err_regulator:
+       regulator_bulk_disable(ARRAY_SIZE(pcm3168a->supplies),
+                       pcm3168a->supplies);
+err_clk:
+       clk_disable_unprepare(pcm3168a->scki);
+
+       return ret;
+}
+EXPORT_SYMBOL_GPL(pcm3168a_probe);
+
+void pcm3168a_remove(struct device *dev)
+{
+       struct pcm3168a_priv *pcm3168a = dev_get_drvdata(dev);
+
+       snd_soc_unregister_codec(dev);
+       pm_runtime_disable(dev);
+       regulator_bulk_disable(ARRAY_SIZE(pcm3168a->supplies),
+                               pcm3168a->supplies);
+       clk_disable_unprepare(pcm3168a->scki);
+}
+EXPORT_SYMBOL_GPL(pcm3168a_remove);
+
+#ifdef CONFIG_PM
+static int pcm3168a_rt_resume(struct device *dev)
+{
+       struct pcm3168a_priv *pcm3168a = dev_get_drvdata(dev);
+       int ret;
+
+       ret = clk_prepare_enable(pcm3168a->scki);
+       if (ret) {
+               dev_err(dev, "Failed to enable mclk: %d\n", ret);
+               return ret;
+       }
+
+       ret = regulator_bulk_enable(ARRAY_SIZE(pcm3168a->supplies),
+                                   pcm3168a->supplies);
+       if (ret) {
+               dev_err(dev, "Failed to enable supplies: %d\n", ret);
+               goto err_clk;
+       }
+
+       ret = pcm3168a_reset(pcm3168a);
+       if (ret) {
+               dev_err(dev, "Failed to reset device: %d\n", ret);
+               goto err_regulator;
+       }
+
+       regcache_cache_only(pcm3168a->regmap, false);
+
+       regcache_mark_dirty(pcm3168a->regmap);
+
+       ret = regcache_sync(pcm3168a->regmap);
+       if (ret) {
+               dev_err(dev, "Failed to sync regmap: %d\n", ret);
+               goto err_regulator;
+       }
+
+       return 0;
+
+err_regulator:
+       regulator_bulk_disable(ARRAY_SIZE(pcm3168a->supplies),
+                              pcm3168a->supplies);
+err_clk:
+       clk_disable_unprepare(pcm3168a->scki);
+
+       return ret;
+}
+
+static int pcm3168a_rt_suspend(struct device *dev)
+{
+       struct pcm3168a_priv *pcm3168a = dev_get_drvdata(dev);
+
+       regcache_cache_only(pcm3168a->regmap, true);
+
+       regulator_bulk_disable(ARRAY_SIZE(pcm3168a->supplies),
+                              pcm3168a->supplies);
+
+       clk_disable_unprepare(pcm3168a->scki);
+
+       return 0;
+}
+#endif
+
+const struct dev_pm_ops pcm3168a_pm_ops = {
+       SET_RUNTIME_PM_OPS(pcm3168a_rt_suspend, pcm3168a_rt_resume, NULL)
+};
+EXPORT_SYMBOL_GPL(pcm3168a_pm_ops);
+
+MODULE_DESCRIPTION("PCM3168A codec driver");
+MODULE_AUTHOR("Damien Horsley <Damien.Horsley@imgtec.com>");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/codecs/pcm3168a.h b/sound/soc/codecs/pcm3168a.h
new file mode 100644 (file)
index 0000000..56c8332
--- /dev/null
@@ -0,0 +1,100 @@
+/*
+ * PCM3168A codec driver header
+ *
+ * Copyright (C) 2015 Imagination Technologies Ltd.
+ *
+ * Author: Damien Horsley <Damien.Horsley@imgtec.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.
+ */
+
+#ifndef __PCM3168A_H__
+#define __PCM3168A_H__
+
+extern const struct dev_pm_ops pcm3168a_pm_ops;
+extern const struct regmap_config pcm3168a_regmap;
+
+extern int pcm3168a_probe(struct device *dev, struct regmap *regmap);
+extern void pcm3168a_remove(struct device *dev);
+
+#define PCM3168A_RST_SMODE                     0x40
+#define PCM3168A_MRST_MASK                     0x80
+#define PCM3168A_SRST_MASK                     0x40
+#define PCM3168A_DAC_SRDA_SHIFT                        0
+#define PCM3168A_DAC_SRDA_MASK                 0x3
+
+#define PCM3168A_DAC_PWR_MST_FMT               0x41
+#define PCM3168A_DAC_PSMDA_SHIFT               7
+#define PCM3168A_DAC_PSMDA_MASK                        0x80
+#define PCM3168A_DAC_MSDA_SHIFT                        4
+#define PCM3168A_DAC_MSDA_MASK                 0x70
+#define PCM3168A_DAC_FMT_SHIFT                 0
+#define PCM3168A_DAC_FMT_MASK                  0xf
+
+#define PCM3168A_DAC_OP_FLT                    0x42
+#define PCM3168A_DAC_OPEDA_SHIFT               4
+#define PCM3168A_DAC_OPEDA_MASK                        0xf0
+#define PCM3168A_DAC_FLT_SHIFT                 0
+#define PCM3168A_DAC_FLT_MASK                  0xf
+
+#define PCM3168A_DAC_INV                       0x43
+
+#define PCM3168A_DAC_MUTE                      0x44
+
+#define PCM3168A_DAC_ZERO                      0x45
+
+#define PCM3168A_DAC_ATT_DEMP_ZF               0x46
+#define PCM3168A_DAC_ATMDDA_MASK               0x80
+#define PCM3168A_DAC_ATMDDA_SHIFT              7
+#define PCM3168A_DAC_ATSPDA_MASK               0x40
+#define PCM3168A_DAC_ATSPDA_SHIFT              6
+#define PCM3168A_DAC_DEMP_SHIFT                        4
+#define PCM3168A_DAC_DEMP_MASK                 0x30
+#define PCM3168A_DAC_AZRO_SHIFT                        1
+#define PCM3168A_DAC_AZRO_MASK                 0xe
+#define PCM3168A_DAC_ZREV_MASK                 0x1
+#define PCM3168A_DAC_ZREV_SHIFT                        0
+
+#define PCM3168A_DAC_VOL_MASTER                        0x47
+
+#define PCM3168A_DAC_VOL_CHAN_START            0x48
+
+#define PCM3168A_ADC_SMODE                     0x50
+#define PCM3168A_ADC_SRAD_SHIFT                        0
+#define PCM3168A_ADC_SRAD_MASK                 0x3
+
+#define PCM3168A_ADC_MST_FMT                   0x51
+#define PCM3168A_ADC_MSAD_SHIFT                        4
+#define PCM3168A_ADC_MSAD_MASK                 0x70
+#define PCM3168A_ADC_FMTAD_SHIFT               0
+#define PCM3168A_ADC_FMTAD_MASK                        0x7
+
+#define PCM3168A_ADC_PWR_HPFB                  0x52
+#define PCM3168A_ADC_PSVAD_SHIFT               4
+#define PCM3168A_ADC_PSVAD_MASK                        0x70
+#define PCM3168A_ADC_BYP_SHIFT                 0
+#define PCM3168A_ADC_BYP_MASK                  0x7
+
+#define PCM3168A_ADC_SEAD                      0x53
+
+#define PCM3168A_ADC_INV                       0x54
+
+#define PCM3168A_ADC_MUTE                      0x55
+
+#define PCM3168A_ADC_OV                                0x56
+
+#define PCM3168A_ADC_ATT_OVF                   0x57
+#define PCM3168A_ADC_ATMDAD_MASK               0x80
+#define PCM3168A_ADC_ATMDAD_SHIFT              7
+#define PCM3168A_ADC_ATSPAD_MASK               0x40
+#define PCM3168A_ADC_ATSPAD_SHIFT              6
+#define PCM3168A_ADC_OVFP_MASK                 0x1
+#define PCM3168A_ADC_OVFP_SHIFT                        0
+
+#define PCM3168A_ADC_VOL_MASTER                        0x58
+
+#define PCM3168A_ADC_VOL_CHAN_START            0x59
+
+#endif
index aca479fa767027174be48390fd0dc93c3802d022..1dc68ab08a1799e71ec17677c5b0da959d3cd40f 100644 (file)
@@ -80,8 +80,10 @@ int rl6231_calc_dmic_clk(int rate)
        }
 
        for (i = 0; i < ARRAY_SIZE(div); i++) {
-               /* find divider that gives DMIC frequency below 3MHz */
-               if (3000000 * div[i] >= rate)
+               if ((div[i] % 3) == 0)
+                       continue;
+               /* find divider that gives DMIC frequency below 3.072MHz */
+               if (3072000 * div[i] >= rate)
                        return i;
        }
 
index af2ed774b5529919486587e732ba6924dd39bb4a..bc08f0c5a5f69fe4a184ac86e611e4df56eabb5c 100644 (file)
@@ -1114,6 +1114,12 @@ static const struct dmi_system_id force_combo_jack_table[] = {
                        DMI_MATCH(DMI_BOARD_NAME, "Wilson Beach SDS")
                }
        },
+       {
+               .ident = "Intel Skylake RVP",
+               .matches = {
+                       DMI_MATCH(DMI_PRODUCT_NAME, "Skylake Client platform")
+               }
+       },
        { }
 };
 
index b3f795c60749b8f8473184f0872329d4578b8e48..30c6de62ae6c980584a1a5bdd9d637dcfc3d0338 100644 (file)
@@ -854,8 +854,6 @@ static int rt298_set_dai_sysclk(struct snd_soc_dai *dai,
        } else {
                snd_soc_update_bits(codec,
                        RT298_I2S_CTRL2, 0x0100, 0x0100);
-               snd_soc_update_bits(codec,
-                       RT298_PLL_CTRL, 0x4, 0x4);
                snd_soc_update_bits(codec,
                        RT298_PLL_CTRL1, 0x20, 0x0);
        }
diff --git a/sound/soc/codecs/rt5616.c b/sound/soc/codecs/rt5616.c
new file mode 100644 (file)
index 0000000..1c10d8e
--- /dev/null
@@ -0,0 +1,1381 @@
+/*
+ * rt5616.c  --  RT5616 ALSA SoC audio codec driver
+ *
+ * Copyright 2015 Realtek Semiconductor Corp.
+ * Author: Bard Liao <bardliao@realtek.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/moduleparam.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/pm.h>
+#include <linux/i2c.h>
+#include <linux/platform_device.h>
+#include <linux/spi/spi.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include <sound/initval.h>
+#include <sound/tlv.h>
+
+#include "rl6231.h"
+#include "rt5616.h"
+
+#define RT5616_PR_RANGE_BASE (0xff + 1)
+#define RT5616_PR_SPACING 0x100
+
+#define RT5616_PR_BASE (RT5616_PR_RANGE_BASE + (0 * RT5616_PR_SPACING))
+
+static const struct regmap_range_cfg rt5616_ranges[] = {
+       {
+               .name = "PR",
+               .range_min = RT5616_PR_BASE,
+               .range_max = RT5616_PR_BASE + 0xf8,
+               .selector_reg = RT5616_PRIV_INDEX,
+               .selector_mask = 0xff,
+               .selector_shift = 0x0,
+               .window_start = RT5616_PRIV_DATA,
+               .window_len = 0x1,
+       },
+};
+
+static const struct reg_sequence init_list[] = {
+       {RT5616_PR_BASE + 0x3d, 0x3e00},
+       {RT5616_PR_BASE + 0x25, 0x6110},
+       {RT5616_PR_BASE + 0x20, 0x611f},
+       {RT5616_PR_BASE + 0x21, 0x4040},
+       {RT5616_PR_BASE + 0x23, 0x0004},
+};
+#define RT5616_INIT_REG_LEN ARRAY_SIZE(init_list)
+
+static const struct reg_default rt5616_reg[] = {
+       { 0x00, 0x0021 },
+       { 0x02, 0xc8c8 },
+       { 0x03, 0xc8c8 },
+       { 0x05, 0x0000 },
+       { 0x0d, 0x0000 },
+       { 0x0f, 0x0808 },
+       { 0x19, 0xafaf },
+       { 0x1c, 0x2f2f },
+       { 0x1e, 0x0000 },
+       { 0x27, 0x7860 },
+       { 0x29, 0x8080 },
+       { 0x2a, 0x5252 },
+       { 0x3b, 0x0000 },
+       { 0x3c, 0x006f },
+       { 0x3d, 0x0000 },
+       { 0x3e, 0x006f },
+       { 0x45, 0x6000 },
+       { 0x4d, 0x0000 },
+       { 0x4e, 0x0000 },
+       { 0x4f, 0x0279 },
+       { 0x50, 0x0000 },
+       { 0x51, 0x0000 },
+       { 0x52, 0x0279 },
+       { 0x53, 0xf000 },
+       { 0x61, 0x0000 },
+       { 0x62, 0x0000 },
+       { 0x63, 0x00c0 },
+       { 0x64, 0x0000 },
+       { 0x65, 0x0000 },
+       { 0x66, 0x0000 },
+       { 0x70, 0x8000 },
+       { 0x73, 0x1104 },
+       { 0x74, 0x0c00 },
+       { 0x80, 0x0000 },
+       { 0x81, 0x0000 },
+       { 0x82, 0x0000 },
+       { 0x8b, 0x0600 },
+       { 0x8e, 0x0004 },
+       { 0x8f, 0x1100 },
+       { 0x90, 0x0000 },
+       { 0x91, 0x0000 },
+       { 0x92, 0x0000 },
+       { 0x93, 0x2000 },
+       { 0x94, 0x0200 },
+       { 0x95, 0x0000 },
+       { 0xb0, 0x2080 },
+       { 0xb1, 0x0000 },
+       { 0xb2, 0x0000 },
+       { 0xb4, 0x2206 },
+       { 0xb5, 0x1f00 },
+       { 0xb6, 0x0000 },
+       { 0xb7, 0x0000 },
+       { 0xbb, 0x0000 },
+       { 0xbc, 0x0000 },
+       { 0xbd, 0x0000 },
+       { 0xbe, 0x0000 },
+       { 0xbf, 0x0000 },
+       { 0xc0, 0x0100 },
+       { 0xc1, 0x0000 },
+       { 0xc2, 0x0000 },
+       { 0xc8, 0x0000 },
+       { 0xc9, 0x0000 },
+       { 0xca, 0x0000 },
+       { 0xcb, 0x0000 },
+       { 0xcc, 0x0000 },
+       { 0xcd, 0x0000 },
+       { 0xce, 0x0000 },
+       { 0xcf, 0x0013 },
+       { 0xd0, 0x0680 },
+       { 0xd1, 0x1c17 },
+       { 0xd3, 0xb320 },
+       { 0xd4, 0x0000 },
+       { 0xd6, 0x0000 },
+       { 0xd7, 0x0000 },
+       { 0xd9, 0x0809 },
+       { 0xda, 0x0000 },
+       { 0xfa, 0x0010 },
+       { 0xfb, 0x0000 },
+       { 0xfc, 0x0000 },
+       { 0xfe, 0x10ec },
+       { 0xff, 0x6281 },
+};
+
+struct rt5616_priv {
+       struct snd_soc_codec *codec;
+       struct delayed_work patch_work;
+       struct regmap *regmap;
+
+       int sysclk;
+       int sysclk_src;
+       int lrck[RT5616_AIFS];
+       int bclk[RT5616_AIFS];
+       int master[RT5616_AIFS];
+
+       int pll_src;
+       int pll_in;
+       int pll_out;
+
+};
+
+static bool rt5616_volatile_register(struct device *dev, unsigned int reg)
+{
+       int i;
+
+       for (i = 0; i < ARRAY_SIZE(rt5616_ranges); i++) {
+               if (reg >= rt5616_ranges[i].range_min &&
+                       reg <= rt5616_ranges[i].range_max) {
+                       return true;
+               }
+       }
+
+       switch (reg) {
+       case RT5616_RESET:
+       case RT5616_PRIV_DATA:
+       case RT5616_EQ_CTRL1:
+       case RT5616_DRC_AGC_1:
+       case RT5616_IRQ_CTRL2:
+       case RT5616_INT_IRQ_ST:
+       case RT5616_PGM_REG_ARR1:
+       case RT5616_PGM_REG_ARR3:
+       case RT5616_VENDOR_ID:
+       case RT5616_DEVICE_ID:
+               return true;
+       default:
+               return false;
+       }
+}
+
+static bool rt5616_readable_register(struct device *dev, unsigned int reg)
+{
+       int i;
+
+       for (i = 0; i < ARRAY_SIZE(rt5616_ranges); i++) {
+               if (reg >= rt5616_ranges[i].range_min &&
+                       reg <= rt5616_ranges[i].range_max) {
+                       return true;
+               }
+       }
+
+       switch (reg) {
+       case RT5616_RESET:
+       case RT5616_VERSION_ID:
+       case RT5616_VENDOR_ID:
+       case RT5616_DEVICE_ID:
+       case RT5616_HP_VOL:
+       case RT5616_LOUT_CTRL1:
+       case RT5616_LOUT_CTRL2:
+       case RT5616_IN1_IN2:
+       case RT5616_INL1_INR1_VOL:
+       case RT5616_DAC1_DIG_VOL:
+       case RT5616_ADC_DIG_VOL:
+       case RT5616_ADC_BST_VOL:
+       case RT5616_STO1_ADC_MIXER:
+       case RT5616_AD_DA_MIXER:
+       case RT5616_STO_DAC_MIXER:
+       case RT5616_REC_L1_MIXER:
+       case RT5616_REC_L2_MIXER:
+       case RT5616_REC_R1_MIXER:
+       case RT5616_REC_R2_MIXER:
+       case RT5616_HPO_MIXER:
+       case RT5616_OUT_L1_MIXER:
+       case RT5616_OUT_L2_MIXER:
+       case RT5616_OUT_L3_MIXER:
+       case RT5616_OUT_R1_MIXER:
+       case RT5616_OUT_R2_MIXER:
+       case RT5616_OUT_R3_MIXER:
+       case RT5616_LOUT_MIXER:
+       case RT5616_PWR_DIG1:
+       case RT5616_PWR_DIG2:
+       case RT5616_PWR_ANLG1:
+       case RT5616_PWR_ANLG2:
+       case RT5616_PWR_MIXER:
+       case RT5616_PWR_VOL:
+       case RT5616_PRIV_INDEX:
+       case RT5616_PRIV_DATA:
+       case RT5616_I2S1_SDP:
+       case RT5616_ADDA_CLK1:
+       case RT5616_ADDA_CLK2:
+       case RT5616_GLB_CLK:
+       case RT5616_PLL_CTRL1:
+       case RT5616_PLL_CTRL2:
+       case RT5616_HP_OVCD:
+       case RT5616_DEPOP_M1:
+       case RT5616_DEPOP_M2:
+       case RT5616_DEPOP_M3:
+       case RT5616_CHARGE_PUMP:
+       case RT5616_PV_DET_SPK_G:
+       case RT5616_MICBIAS:
+       case RT5616_A_JD_CTL1:
+       case RT5616_A_JD_CTL2:
+       case RT5616_EQ_CTRL1:
+       case RT5616_EQ_CTRL2:
+       case RT5616_WIND_FILTER:
+       case RT5616_DRC_AGC_1:
+       case RT5616_DRC_AGC_2:
+       case RT5616_DRC_AGC_3:
+       case RT5616_SVOL_ZC:
+       case RT5616_JD_CTRL1:
+       case RT5616_JD_CTRL2:
+       case RT5616_IRQ_CTRL1:
+       case RT5616_IRQ_CTRL2:
+       case RT5616_INT_IRQ_ST:
+       case RT5616_GPIO_CTRL1:
+       case RT5616_GPIO_CTRL2:
+       case RT5616_GPIO_CTRL3:
+       case RT5616_PGM_REG_ARR1:
+       case RT5616_PGM_REG_ARR2:
+       case RT5616_PGM_REG_ARR3:
+       case RT5616_PGM_REG_ARR4:
+       case RT5616_PGM_REG_ARR5:
+       case RT5616_SCB_FUNC:
+       case RT5616_SCB_CTRL:
+       case RT5616_BASE_BACK:
+       case RT5616_MP3_PLUS1:
+       case RT5616_MP3_PLUS2:
+       case RT5616_ADJ_HPF_CTRL1:
+       case RT5616_ADJ_HPF_CTRL2:
+       case RT5616_HP_CALIB_AMP_DET:
+       case RT5616_HP_CALIB2:
+       case RT5616_SV_ZCD1:
+       case RT5616_SV_ZCD2:
+       case RT5616_D_MISC:
+       case RT5616_DUMMY2:
+       case RT5616_DUMMY3:
+               return true;
+       default:
+               return false;
+       }
+}
+
+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);
+static const DECLARE_TLV_DB_SCALE(adc_vol_tlv, -17625, 375, 0);
+static const DECLARE_TLV_DB_SCALE(adc_bst_tlv, 0, 1200, 0);
+
+/* {0, +20, +24, +30, +35, +40, +44, +50, +52} dB */
+static unsigned int bst_tlv[] = {
+       TLV_DB_RANGE_HEAD(7),
+       0, 0, TLV_DB_SCALE_ITEM(0, 0, 0),
+       1, 1, TLV_DB_SCALE_ITEM(2000, 0, 0),
+       2, 2, TLV_DB_SCALE_ITEM(2400, 0, 0),
+       3, 5, TLV_DB_SCALE_ITEM(3000, 500, 0),
+       6, 6, TLV_DB_SCALE_ITEM(4400, 0, 0),
+       7, 7, TLV_DB_SCALE_ITEM(5000, 0, 0),
+       8, 8, TLV_DB_SCALE_ITEM(5200, 0, 0),
+};
+
+static const struct snd_kcontrol_new rt5616_snd_controls[] = {
+       /* Headphone Output Volume */
+       SOC_DOUBLE("HP Playback Switch", RT5616_HP_VOL,
+               RT5616_L_MUTE_SFT, RT5616_R_MUTE_SFT, 1, 1),
+       SOC_DOUBLE_TLV("HP Playback Volume", RT5616_HP_VOL,
+               RT5616_L_VOL_SFT, RT5616_R_VOL_SFT, 39, 1, out_vol_tlv),
+       /* OUTPUT Control */
+       SOC_DOUBLE("OUT Playback Switch", RT5616_LOUT_CTRL1,
+               RT5616_L_MUTE_SFT, RT5616_R_MUTE_SFT, 1, 1),
+       SOC_DOUBLE("OUT Channel Switch", RT5616_LOUT_CTRL1,
+               RT5616_VOL_L_SFT, RT5616_VOL_R_SFT, 1, 1),
+       SOC_DOUBLE_TLV("OUT Playback Volume", RT5616_LOUT_CTRL1,
+               RT5616_L_VOL_SFT, RT5616_R_VOL_SFT, 39, 1, out_vol_tlv),
+
+       /* DAC Digital Volume */
+       SOC_DOUBLE_TLV("DAC1 Playback Volume", RT5616_DAC1_DIG_VOL,
+                       RT5616_L_VOL_SFT, RT5616_R_VOL_SFT,
+                       175, 0, dac_vol_tlv),
+       /* IN1/IN2 Control */
+       SOC_SINGLE_TLV("IN1 Boost Volume", RT5616_IN1_IN2,
+               RT5616_BST_SFT1, 8, 0, bst_tlv),
+       SOC_SINGLE_TLV("IN2 Boost Volume", RT5616_IN1_IN2,
+               RT5616_BST_SFT2, 8, 0, bst_tlv),
+       /* INL/INR Volume Control */
+       SOC_DOUBLE_TLV("IN Capture Volume", RT5616_INL1_INR1_VOL,
+                       RT5616_INL_VOL_SFT, RT5616_INR_VOL_SFT,
+                       31, 1, in_vol_tlv),
+       /* ADC Digital Volume Control */
+       SOC_DOUBLE("ADC Capture Switch", RT5616_ADC_DIG_VOL,
+               RT5616_L_MUTE_SFT, RT5616_R_MUTE_SFT, 1, 1),
+       SOC_DOUBLE_TLV("ADC Capture Volume", RT5616_ADC_DIG_VOL,
+                       RT5616_L_VOL_SFT, RT5616_R_VOL_SFT,
+                       127, 0, adc_vol_tlv),
+
+       /* ADC Boost Volume Control */
+       SOC_DOUBLE_TLV("ADC Boost Volume", RT5616_ADC_BST_VOL,
+                       RT5616_ADC_L_BST_SFT, RT5616_ADC_R_BST_SFT,
+                       3, 0, adc_bst_tlv),
+};
+
+static int is_sys_clk_from_pll(struct snd_soc_dapm_widget *source,
+                        struct snd_soc_dapm_widget *sink)
+{
+       unsigned int val;
+
+       val = snd_soc_read(snd_soc_dapm_to_codec(source->dapm), RT5616_GLB_CLK);
+       val &= RT5616_SCLK_SRC_MASK;
+       if (val == RT5616_SCLK_SRC_PLL1)
+               return 1;
+       else
+               return 0;
+}
+
+/* Digital Mixer */
+static const struct snd_kcontrol_new rt5616_sto1_adc_l_mix[] = {
+       SOC_DAPM_SINGLE("ADC1 Switch", RT5616_STO1_ADC_MIXER,
+                       RT5616_M_STO1_ADC_L1_SFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5616_sto1_adc_r_mix[] = {
+       SOC_DAPM_SINGLE("ADC1 Switch", RT5616_STO1_ADC_MIXER,
+                       RT5616_M_STO1_ADC_R1_SFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5616_dac_l_mix[] = {
+       SOC_DAPM_SINGLE("Stereo ADC Switch", RT5616_AD_DA_MIXER,
+                       RT5616_M_ADCMIX_L_SFT, 1, 1),
+       SOC_DAPM_SINGLE("INF1 Switch", RT5616_AD_DA_MIXER,
+                       RT5616_M_IF1_DAC_L_SFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5616_dac_r_mix[] = {
+       SOC_DAPM_SINGLE("Stereo ADC Switch", RT5616_AD_DA_MIXER,
+                       RT5616_M_ADCMIX_R_SFT, 1, 1),
+       SOC_DAPM_SINGLE("INF1 Switch", RT5616_AD_DA_MIXER,
+                       RT5616_M_IF1_DAC_R_SFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5616_sto_dac_l_mix[] = {
+       SOC_DAPM_SINGLE("DAC L1 Switch", RT5616_STO_DAC_MIXER,
+                       RT5616_M_DAC_L1_MIXL_SFT, 1, 1),
+       SOC_DAPM_SINGLE("DAC R1 Switch", RT5616_STO_DAC_MIXER,
+                       RT5616_M_DAC_R1_MIXL_SFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5616_sto_dac_r_mix[] = {
+       SOC_DAPM_SINGLE("DAC R1 Switch", RT5616_STO_DAC_MIXER,
+                       RT5616_M_DAC_R1_MIXR_SFT, 1, 1),
+       SOC_DAPM_SINGLE("DAC L1 Switch", RT5616_STO_DAC_MIXER,
+                       RT5616_M_DAC_L1_MIXR_SFT, 1, 1),
+};
+
+/* Analog Input Mixer */
+static const struct snd_kcontrol_new rt5616_rec_l_mix[] = {
+       SOC_DAPM_SINGLE("INL1 Switch", RT5616_REC_L2_MIXER,
+                       RT5616_M_IN1_L_RM_L_SFT, 1, 1),
+       SOC_DAPM_SINGLE("BST2 Switch", RT5616_REC_L2_MIXER,
+                       RT5616_M_BST2_RM_L_SFT, 1, 1),
+       SOC_DAPM_SINGLE("BST1 Switch", RT5616_REC_L2_MIXER,
+                       RT5616_M_BST1_RM_L_SFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5616_rec_r_mix[] = {
+       SOC_DAPM_SINGLE("INR1 Switch", RT5616_REC_R2_MIXER,
+                       RT5616_M_IN1_R_RM_R_SFT, 1, 1),
+       SOC_DAPM_SINGLE("BST2 Switch", RT5616_REC_R2_MIXER,
+                       RT5616_M_BST2_RM_R_SFT, 1, 1),
+       SOC_DAPM_SINGLE("BST1 Switch", RT5616_REC_R2_MIXER,
+                       RT5616_M_BST1_RM_R_SFT, 1, 1),
+};
+
+/* Analog Output Mixer */
+
+static const struct snd_kcontrol_new rt5616_out_l_mix[] = {
+       SOC_DAPM_SINGLE("BST1 Switch", RT5616_OUT_L3_MIXER,
+                       RT5616_M_BST1_OM_L_SFT, 1, 1),
+       SOC_DAPM_SINGLE("BST2 Switch", RT5616_OUT_L3_MIXER,
+                       RT5616_M_BST2_OM_L_SFT, 1, 1),
+       SOC_DAPM_SINGLE("INL1 Switch", RT5616_OUT_L3_MIXER,
+                       RT5616_M_IN1_L_OM_L_SFT, 1, 1),
+       SOC_DAPM_SINGLE("REC MIXL Switch", RT5616_OUT_L3_MIXER,
+                       RT5616_M_RM_L_OM_L_SFT, 1, 1),
+       SOC_DAPM_SINGLE("DAC L1 Switch", RT5616_OUT_L3_MIXER,
+                       RT5616_M_DAC_L1_OM_L_SFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5616_out_r_mix[] = {
+       SOC_DAPM_SINGLE("BST2 Switch", RT5616_OUT_R3_MIXER,
+                       RT5616_M_BST2_OM_R_SFT, 1, 1),
+       SOC_DAPM_SINGLE("BST1 Switch", RT5616_OUT_R3_MIXER,
+                       RT5616_M_BST1_OM_R_SFT, 1, 1),
+       SOC_DAPM_SINGLE("INR1 Switch", RT5616_OUT_R3_MIXER,
+                       RT5616_M_IN1_R_OM_R_SFT, 1, 1),
+       SOC_DAPM_SINGLE("REC MIXR Switch", RT5616_OUT_R3_MIXER,
+                       RT5616_M_RM_R_OM_R_SFT, 1, 1),
+       SOC_DAPM_SINGLE("DAC R1 Switch", RT5616_OUT_R3_MIXER,
+                       RT5616_M_DAC_R1_OM_R_SFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5616_hpo_mix[] = {
+       SOC_DAPM_SINGLE("DAC1 Switch", RT5616_HPO_MIXER,
+                       RT5616_M_DAC1_HM_SFT, 1, 1),
+       SOC_DAPM_SINGLE("HPVOL Switch", RT5616_HPO_MIXER,
+                       RT5616_M_HPVOL_HM_SFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5616_lout_mix[] = {
+       SOC_DAPM_SINGLE("DAC L1 Switch", RT5616_LOUT_MIXER,
+                       RT5616_M_DAC_L1_LM_SFT, 1, 1),
+       SOC_DAPM_SINGLE("DAC R1 Switch", RT5616_LOUT_MIXER,
+                       RT5616_M_DAC_R1_LM_SFT, 1, 1),
+       SOC_DAPM_SINGLE("OUTVOL L Switch", RT5616_LOUT_MIXER,
+                       RT5616_M_OV_L_LM_SFT, 1, 1),
+       SOC_DAPM_SINGLE("OUTVOL R Switch", RT5616_LOUT_MIXER,
+                       RT5616_M_OV_R_LM_SFT, 1, 1),
+};
+
+static int rt5616_adc_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_POST_PMU:
+               snd_soc_update_bits(codec, RT5616_ADC_DIG_VOL,
+                               RT5616_L_MUTE | RT5616_R_MUTE, 0);
+               break;
+
+       case SND_SOC_DAPM_POST_PMD:
+               snd_soc_update_bits(codec, RT5616_ADC_DIG_VOL,
+                               RT5616_L_MUTE | RT5616_R_MUTE,
+                               RT5616_L_MUTE | RT5616_R_MUTE);
+               break;
+
+       default:
+               return 0;
+       }
+
+       return 0;
+}
+
+static int rt5616_charge_pump_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_POST_PMU:
+               /* depop parameters */
+               snd_soc_update_bits(codec, RT5616_DEPOP_M2,
+                       RT5616_DEPOP_MASK, RT5616_DEPOP_MAN);
+               snd_soc_update_bits(codec, RT5616_DEPOP_M1,
+                       RT5616_HP_CP_MASK | RT5616_HP_SG_MASK |
+                       RT5616_HP_CB_MASK, RT5616_HP_CP_PU |
+                       RT5616_HP_SG_DIS | RT5616_HP_CB_PU);
+               snd_soc_write(codec, RT5616_PR_BASE +
+                       RT5616_HP_DCC_INT1, 0x9f00);
+               /* headphone amp power on */
+               snd_soc_update_bits(codec, RT5616_PWR_ANLG1,
+                       RT5616_PWR_FV1 | RT5616_PWR_FV2, 0);
+               snd_soc_update_bits(codec, RT5616_PWR_VOL,
+                       RT5616_PWR_HV_L | RT5616_PWR_HV_R,
+                       RT5616_PWR_HV_L | RT5616_PWR_HV_R);
+               snd_soc_update_bits(codec, RT5616_PWR_ANLG1,
+                       RT5616_PWR_HP_L | RT5616_PWR_HP_R |
+                       RT5616_PWR_HA, RT5616_PWR_HP_L |
+                       RT5616_PWR_HP_R | RT5616_PWR_HA);
+               msleep(50);
+               snd_soc_update_bits(codec, RT5616_PWR_ANLG1,
+                       RT5616_PWR_FV1 | RT5616_PWR_FV2,
+                       RT5616_PWR_FV1 | RT5616_PWR_FV2);
+
+               snd_soc_update_bits(codec, RT5616_CHARGE_PUMP,
+                       RT5616_PM_HP_MASK, RT5616_PM_HP_HV);
+               snd_soc_update_bits(codec, RT5616_PR_BASE +
+                       RT5616_CHOP_DAC_ADC, 0x0200, 0x0200);
+               snd_soc_update_bits(codec, RT5616_DEPOP_M1,
+                       RT5616_HP_CO_MASK | RT5616_HP_SG_MASK,
+                       RT5616_HP_CO_EN | RT5616_HP_SG_EN);
+               break;
+       case SND_SOC_DAPM_PRE_PMD:
+               snd_soc_update_bits(codec, RT5616_PR_BASE +
+                       RT5616_CHOP_DAC_ADC, 0x0200, 0x0);
+               snd_soc_update_bits(codec, RT5616_DEPOP_M1,
+                       RT5616_HP_SG_MASK | RT5616_HP_L_SMT_MASK |
+                       RT5616_HP_R_SMT_MASK, RT5616_HP_SG_DIS |
+                       RT5616_HP_L_SMT_DIS | RT5616_HP_R_SMT_DIS);
+               /* headphone amp power down */
+               snd_soc_update_bits(codec, RT5616_DEPOP_M1,
+                       RT5616_SMT_TRIG_MASK | RT5616_HP_CD_PD_MASK |
+                       RT5616_HP_CO_MASK | RT5616_HP_CP_MASK |
+                       RT5616_HP_SG_MASK | RT5616_HP_CB_MASK,
+                       RT5616_SMT_TRIG_DIS | RT5616_HP_CD_PD_EN |
+                       RT5616_HP_CO_DIS | RT5616_HP_CP_PD |
+                       RT5616_HP_SG_EN | RT5616_HP_CB_PD);
+               snd_soc_update_bits(codec, RT5616_PWR_ANLG1,
+                       RT5616_PWR_HP_L | RT5616_PWR_HP_R |
+                       RT5616_PWR_HA, 0);
+               break;
+       default:
+               return 0;
+       }
+
+       return 0;
+}
+
+static int rt5616_hp_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_POST_PMU:
+               /* headphone unmute sequence */
+               snd_soc_update_bits(codec, RT5616_DEPOP_M3,
+                       RT5616_CP_FQ1_MASK | RT5616_CP_FQ2_MASK |
+                       RT5616_CP_FQ3_MASK,
+                       (RT5616_CP_FQ_192_KHZ << RT5616_CP_FQ1_SFT) |
+                       (RT5616_CP_FQ_12_KHZ << RT5616_CP_FQ2_SFT) |
+                       (RT5616_CP_FQ_192_KHZ << RT5616_CP_FQ3_SFT));
+               snd_soc_write(codec, RT5616_PR_BASE +
+                       RT5616_MAMP_INT_REG2, 0xfc00);
+               snd_soc_update_bits(codec, RT5616_DEPOP_M1,
+                       RT5616_SMT_TRIG_MASK, RT5616_SMT_TRIG_EN);
+               snd_soc_update_bits(codec, RT5616_DEPOP_M1,
+                       RT5616_RSTN_MASK, RT5616_RSTN_EN);
+               snd_soc_update_bits(codec, RT5616_DEPOP_M1,
+                       RT5616_RSTN_MASK | RT5616_HP_L_SMT_MASK |
+                       RT5616_HP_R_SMT_MASK, RT5616_RSTN_DIS |
+                       RT5616_HP_L_SMT_EN | RT5616_HP_R_SMT_EN);
+               snd_soc_update_bits(codec, RT5616_HP_VOL,
+                       RT5616_L_MUTE | RT5616_R_MUTE, 0);
+               msleep(100);
+               snd_soc_update_bits(codec, RT5616_DEPOP_M1,
+                       RT5616_HP_SG_MASK | RT5616_HP_L_SMT_MASK |
+                       RT5616_HP_R_SMT_MASK, RT5616_HP_SG_DIS |
+                       RT5616_HP_L_SMT_DIS | RT5616_HP_R_SMT_DIS);
+               msleep(20);
+               snd_soc_update_bits(codec, RT5616_HP_CALIB_AMP_DET,
+                       RT5616_HPD_PS_MASK, RT5616_HPD_PS_EN);
+               break;
+
+       case SND_SOC_DAPM_PRE_PMD:
+               /* headphone mute sequence */
+               snd_soc_update_bits(codec, RT5616_DEPOP_M3,
+                       RT5616_CP_FQ1_MASK | RT5616_CP_FQ2_MASK |
+                       RT5616_CP_FQ3_MASK,
+                       (RT5616_CP_FQ_96_KHZ << RT5616_CP_FQ1_SFT) |
+                       (RT5616_CP_FQ_12_KHZ << RT5616_CP_FQ2_SFT) |
+                       (RT5616_CP_FQ_96_KHZ << RT5616_CP_FQ3_SFT));
+               snd_soc_write(codec, RT5616_PR_BASE +
+                       RT5616_MAMP_INT_REG2, 0xfc00);
+               snd_soc_update_bits(codec, RT5616_DEPOP_M1,
+                       RT5616_HP_SG_MASK, RT5616_HP_SG_EN);
+               snd_soc_update_bits(codec, RT5616_DEPOP_M1,
+                       RT5616_RSTP_MASK, RT5616_RSTP_EN);
+               snd_soc_update_bits(codec, RT5616_DEPOP_M1,
+                       RT5616_RSTP_MASK | RT5616_HP_L_SMT_MASK |
+                       RT5616_HP_R_SMT_MASK, RT5616_RSTP_DIS |
+                       RT5616_HP_L_SMT_EN | RT5616_HP_R_SMT_EN);
+               snd_soc_update_bits(codec, RT5616_HP_CALIB_AMP_DET,
+                       RT5616_HPD_PS_MASK, RT5616_HPD_PS_DIS);
+               msleep(90);
+               snd_soc_update_bits(codec, RT5616_HP_VOL,
+                       RT5616_L_MUTE | RT5616_R_MUTE,
+                       RT5616_L_MUTE | RT5616_R_MUTE);
+               msleep(30);
+               break;
+
+       default:
+               return 0;
+       }
+
+       return 0;
+}
+
+static int rt5616_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_POST_PMU:
+               snd_soc_update_bits(codec, RT5616_PWR_ANLG1,
+                       RT5616_PWR_LM, RT5616_PWR_LM);
+               snd_soc_update_bits(codec, RT5616_LOUT_CTRL1,
+                       RT5616_L_MUTE | RT5616_R_MUTE, 0);
+               break;
+
+       case SND_SOC_DAPM_PRE_PMD:
+               snd_soc_update_bits(codec, RT5616_LOUT_CTRL1,
+                       RT5616_L_MUTE | RT5616_R_MUTE,
+                       RT5616_L_MUTE | RT5616_R_MUTE);
+               snd_soc_update_bits(codec, RT5616_PWR_ANLG1,
+                       RT5616_PWR_LM, 0);
+               break;
+
+       default:
+               return 0;
+       }
+
+       return 0;
+}
+
+static int rt5616_bst1_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_POST_PMU:
+               snd_soc_update_bits(codec, RT5616_PWR_ANLG2,
+                       RT5616_PWR_BST1_OP2, RT5616_PWR_BST1_OP2);
+               break;
+
+       case SND_SOC_DAPM_PRE_PMD:
+               snd_soc_update_bits(codec, RT5616_PWR_ANLG2,
+                       RT5616_PWR_BST1_OP2, 0);
+               break;
+
+       default:
+               return 0;
+       }
+
+       return 0;
+}
+
+static int rt5616_bst2_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_POST_PMU:
+               snd_soc_update_bits(codec, RT5616_PWR_ANLG2,
+                       RT5616_PWR_BST2_OP2, RT5616_PWR_BST2_OP2);
+               break;
+
+       case SND_SOC_DAPM_PRE_PMD:
+               snd_soc_update_bits(codec, RT5616_PWR_ANLG2,
+                       RT5616_PWR_BST2_OP2, 0);
+               break;
+
+       default:
+               return 0;
+       }
+
+       return 0;
+}
+
+static const struct snd_soc_dapm_widget rt5616_dapm_widgets[] = {
+       SND_SOC_DAPM_SUPPLY("PLL1", RT5616_PWR_ANLG2,
+                       RT5616_PWR_PLL_BIT, 0, NULL, 0),
+       /* Input Side */
+       /* micbias */
+       SND_SOC_DAPM_SUPPLY("LDO", RT5616_PWR_ANLG1,
+                       RT5616_PWR_LDO_BIT, 0, NULL, 0),
+       SND_SOC_DAPM_SUPPLY("micbias1", RT5616_PWR_ANLG2,
+                       RT5616_PWR_MB1_BIT, 0, NULL, 0),
+
+       /* Input Lines */
+       SND_SOC_DAPM_INPUT("MIC1"),
+       SND_SOC_DAPM_INPUT("MIC2"),
+
+       SND_SOC_DAPM_INPUT("IN1P"),
+       SND_SOC_DAPM_INPUT("IN2P"),
+       SND_SOC_DAPM_INPUT("IN2N"),
+
+       /* Boost */
+       SND_SOC_DAPM_PGA_E("BST1", RT5616_PWR_ANLG2,
+               RT5616_PWR_BST1_BIT, 0, NULL, 0, rt5616_bst1_event,
+               SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU),
+       SND_SOC_DAPM_PGA_E("BST2", RT5616_PWR_ANLG2,
+               RT5616_PWR_BST2_BIT, 0, NULL, 0, rt5616_bst2_event,
+               SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU),
+       /* Input Volume */
+       SND_SOC_DAPM_PGA("INL1 VOL", RT5616_PWR_VOL,
+               RT5616_PWR_IN1_L_BIT, 0, NULL, 0),
+       SND_SOC_DAPM_PGA("INR1 VOL", RT5616_PWR_VOL,
+               RT5616_PWR_IN1_R_BIT, 0, NULL, 0),
+       SND_SOC_DAPM_PGA("INL2 VOL", RT5616_PWR_VOL,
+               RT5616_PWR_IN2_L_BIT, 0, NULL, 0),
+       SND_SOC_DAPM_PGA("INR2 VOL", RT5616_PWR_VOL,
+               RT5616_PWR_IN2_R_BIT, 0, NULL, 0),
+
+       /* REC Mixer */
+       SND_SOC_DAPM_MIXER("RECMIXL", RT5616_PWR_MIXER, RT5616_PWR_RM_L_BIT, 0,
+                       rt5616_rec_l_mix, ARRAY_SIZE(rt5616_rec_l_mix)),
+       SND_SOC_DAPM_MIXER("RECMIXR", RT5616_PWR_MIXER, RT5616_PWR_RM_R_BIT, 0,
+                       rt5616_rec_r_mix, ARRAY_SIZE(rt5616_rec_r_mix)),
+       /* ADCs */
+       SND_SOC_DAPM_ADC_E("ADC L", NULL, RT5616_PWR_DIG1,
+               RT5616_PWR_ADC_L_BIT, 0, rt5616_adc_event,
+               SND_SOC_DAPM_POST_PMD | SND_SOC_DAPM_POST_PMU),
+       SND_SOC_DAPM_ADC_E("ADC R", NULL, RT5616_PWR_DIG1,
+               RT5616_PWR_ADC_R_BIT, 0, rt5616_adc_event,
+               SND_SOC_DAPM_POST_PMD | SND_SOC_DAPM_POST_PMU),
+
+       /* ADC Mixer */
+       SND_SOC_DAPM_SUPPLY("stereo1 filter", RT5616_PWR_DIG2,
+               RT5616_PWR_ADC_STO1_F_BIT, 0, NULL, 0),
+       SND_SOC_DAPM_MIXER("Stereo1 ADC MIXL", SND_SOC_NOPM, 0, 0,
+               rt5616_sto1_adc_l_mix, ARRAY_SIZE(rt5616_sto1_adc_l_mix)),
+       SND_SOC_DAPM_MIXER("Stereo1 ADC MIXR", SND_SOC_NOPM, 0, 0,
+               rt5616_sto1_adc_r_mix, ARRAY_SIZE(rt5616_sto1_adc_r_mix)),
+
+       /* Digital Interface */
+       SND_SOC_DAPM_SUPPLY("I2S1", RT5616_PWR_DIG1,
+               RT5616_PWR_I2S1_BIT, 0, NULL, 0),
+       SND_SOC_DAPM_PGA("IF1 DAC", SND_SOC_NOPM, 0, 0, NULL, 0),
+       SND_SOC_DAPM_PGA("IF1 DAC1 L", SND_SOC_NOPM, 0, 0, NULL, 0),
+       SND_SOC_DAPM_PGA("IF1 DAC1 R", SND_SOC_NOPM, 0, 0, NULL, 0),
+       SND_SOC_DAPM_PGA("IF1 ADC1", SND_SOC_NOPM, 0, 0, NULL, 0),
+
+       /* Digital Interface Select */
+
+       /* Audio Interface */
+       SND_SOC_DAPM_AIF_IN("AIF1RX", "AIF1 Playback", 0, SND_SOC_NOPM, 0, 0),
+       SND_SOC_DAPM_AIF_OUT("AIF1TX", "AIF1 Capture", 0, SND_SOC_NOPM, 0, 0),
+
+       /* Audio DSP */
+       SND_SOC_DAPM_PGA("Audio DSP", SND_SOC_NOPM, 0, 0, NULL, 0),
+
+       /* Output Side */
+       /* DAC mixer before sound effect  */
+       SND_SOC_DAPM_MIXER("DAC MIXL", SND_SOC_NOPM, 0, 0,
+               rt5616_dac_l_mix, ARRAY_SIZE(rt5616_dac_l_mix)),
+       SND_SOC_DAPM_MIXER("DAC MIXR", SND_SOC_NOPM, 0, 0,
+               rt5616_dac_r_mix, ARRAY_SIZE(rt5616_dac_r_mix)),
+
+       SND_SOC_DAPM_SUPPLY("Stero1 DAC Power", RT5616_PWR_DIG2,
+                       RT5616_PWR_DAC_STO1_F_BIT, 0, NULL, 0),
+
+       /* DAC Mixer */
+       SND_SOC_DAPM_MIXER("Stereo DAC MIXL", SND_SOC_NOPM, 0, 0,
+               rt5616_sto_dac_l_mix, ARRAY_SIZE(rt5616_sto_dac_l_mix)),
+       SND_SOC_DAPM_MIXER("Stereo DAC MIXR", SND_SOC_NOPM, 0, 0,
+               rt5616_sto_dac_r_mix, ARRAY_SIZE(rt5616_sto_dac_r_mix)),
+
+       /* DACs */
+       SND_SOC_DAPM_DAC("DAC L1", NULL, RT5616_PWR_DIG1,
+                       RT5616_PWR_DAC_L1_BIT, 0),
+       SND_SOC_DAPM_DAC("DAC R1", NULL, RT5616_PWR_DIG1,
+                       RT5616_PWR_DAC_R1_BIT, 0),
+       /* OUT Mixer */
+       SND_SOC_DAPM_MIXER("OUT MIXL", RT5616_PWR_MIXER, RT5616_PWR_OM_L_BIT,
+               0, rt5616_out_l_mix, ARRAY_SIZE(rt5616_out_l_mix)),
+       SND_SOC_DAPM_MIXER("OUT MIXR", RT5616_PWR_MIXER, RT5616_PWR_OM_R_BIT,
+               0, rt5616_out_r_mix, ARRAY_SIZE(rt5616_out_r_mix)),
+       /* Output Volume */
+       SND_SOC_DAPM_PGA("OUTVOL L", RT5616_PWR_VOL,
+               RT5616_PWR_OV_L_BIT, 0, NULL, 0),
+       SND_SOC_DAPM_PGA("OUTVOL R", RT5616_PWR_VOL,
+               RT5616_PWR_OV_R_BIT, 0, NULL, 0),
+       SND_SOC_DAPM_PGA("HPOVOL L", RT5616_PWR_VOL,
+               RT5616_PWR_HV_L_BIT, 0, NULL, 0),
+       SND_SOC_DAPM_PGA("HPOVOL R", RT5616_PWR_VOL,
+               RT5616_PWR_HV_R_BIT, 0, NULL, 0),
+       SND_SOC_DAPM_PGA("DAC 1", SND_SOC_NOPM,
+               0, 0, NULL, 0),
+       SND_SOC_DAPM_PGA("DAC 2", SND_SOC_NOPM,
+               0, 0, NULL, 0),
+       SND_SOC_DAPM_PGA("HPOVOL", SND_SOC_NOPM,
+               0, 0, NULL, 0),
+       SND_SOC_DAPM_PGA("INL1", RT5616_PWR_VOL,
+               RT5616_PWR_IN1_L_BIT, 0, NULL, 0),
+       SND_SOC_DAPM_PGA("INR1", RT5616_PWR_VOL,
+               RT5616_PWR_IN1_R_BIT, 0, NULL, 0),
+       SND_SOC_DAPM_PGA("INL2", RT5616_PWR_VOL,
+               RT5616_PWR_IN2_L_BIT, 0, NULL, 0),
+       SND_SOC_DAPM_PGA("INR2", RT5616_PWR_VOL,
+               RT5616_PWR_IN2_R_BIT, 0, NULL, 0),
+       /* HPO/LOUT/Mono Mixer */
+       SND_SOC_DAPM_MIXER("HPO MIX", SND_SOC_NOPM, 0, 0,
+               rt5616_hpo_mix, ARRAY_SIZE(rt5616_hpo_mix)),
+       SND_SOC_DAPM_MIXER("LOUT MIX", SND_SOC_NOPM, 0, 0,
+               rt5616_lout_mix, ARRAY_SIZE(rt5616_lout_mix)),
+
+       SND_SOC_DAPM_PGA_S("HP amp", 1, SND_SOC_NOPM, 0, 0,
+               rt5616_hp_event, SND_SOC_DAPM_PRE_PMD |
+               SND_SOC_DAPM_POST_PMU),
+       SND_SOC_DAPM_PGA_S("LOUT amp", 1, SND_SOC_NOPM, 0, 0,
+               rt5616_lout_event, SND_SOC_DAPM_PRE_PMD |
+               SND_SOC_DAPM_POST_PMU),
+
+       SND_SOC_DAPM_SUPPLY_S("Charge Pump", 1, SND_SOC_NOPM, 0, 0,
+               rt5616_charge_pump_event, SND_SOC_DAPM_POST_PMU |
+               SND_SOC_DAPM_PRE_PMD),
+
+       /* Output Lines */
+       SND_SOC_DAPM_OUTPUT("HPOL"),
+       SND_SOC_DAPM_OUTPUT("HPOR"),
+       SND_SOC_DAPM_OUTPUT("LOUTL"),
+       SND_SOC_DAPM_OUTPUT("LOUTR"),
+};
+
+static const struct snd_soc_dapm_route rt5616_dapm_routes[] = {
+       {"IN1P", NULL, "LDO"},
+       {"IN2P", NULL, "LDO"},
+
+       {"IN1P", NULL, "MIC1"},
+       {"IN2P", NULL, "MIC2"},
+       {"IN2N", NULL, "MIC2"},
+
+       {"BST1", NULL, "IN1P"},
+       {"BST2", NULL, "IN2P"},
+       {"BST2", NULL, "IN2N"},
+       {"BST1", NULL, "micbias1"},
+       {"BST2", NULL, "micbias1"},
+
+       {"INL1 VOL", NULL, "IN2P"},
+       {"INR1 VOL", NULL, "IN2N"},
+
+       {"RECMIXL", "INL1 Switch", "INL1 VOL"},
+       {"RECMIXL", "BST2 Switch", "BST2"},
+       {"RECMIXL", "BST1 Switch", "BST1"},
+
+       {"RECMIXR", "INR1 Switch", "INR1 VOL"},
+       {"RECMIXR", "BST2 Switch", "BST2"},
+       {"RECMIXR", "BST1 Switch", "BST1"},
+
+       {"ADC L", NULL, "RECMIXL"},
+       {"ADC R", NULL, "RECMIXR"},
+
+       {"Stereo1 ADC MIXL", "ADC1 Switch", "ADC L"},
+       {"Stereo1 ADC MIXL", NULL, "stereo1 filter"},
+       {"stereo1 filter", NULL, "PLL1", is_sys_clk_from_pll},
+
+       {"Stereo1 ADC MIXR", "ADC1 Switch", "ADC R"},
+       {"Stereo1 ADC MIXR", NULL, "stereo1 filter"},
+       {"stereo1 filter", NULL, "PLL1", is_sys_clk_from_pll},
+
+       {"IF1 ADC1", NULL, "Stereo1 ADC MIXL"},
+       {"IF1 ADC1", NULL, "Stereo1 ADC MIXR"},
+       {"IF1 ADC1", NULL, "I2S1"},
+
+       {"AIF1TX", NULL, "IF1 ADC1"},
+
+       {"IF1 DAC", NULL, "AIF1RX"},
+       {"IF1 DAC", NULL, "I2S1"},
+
+       {"IF1 DAC1 L", NULL, "IF1 DAC"},
+       {"IF1 DAC1 R", NULL, "IF1 DAC"},
+
+       {"DAC MIXL", "Stereo ADC Switch", "Stereo1 ADC MIXL"},
+       {"DAC MIXL", "INF1 Switch", "IF1 DAC1 L"},
+       {"DAC MIXR", "Stereo ADC Switch", "Stereo1 ADC MIXR"},
+       {"DAC MIXR", "INF1 Switch", "IF1 DAC1 R"},
+
+       {"Audio DSP", NULL, "DAC MIXL"},
+       {"Audio DSP", NULL, "DAC MIXR"},
+
+       {"Stereo DAC MIXL", "DAC L1 Switch", "Audio DSP"},
+       {"Stereo DAC MIXL", "DAC R1 Switch", "DAC MIXR"},
+       {"Stereo DAC MIXL", NULL, "Stero1 DAC Power"},
+       {"Stereo DAC MIXR", "DAC R1 Switch", "Audio DSP"},
+       {"Stereo DAC MIXR", "DAC L1 Switch", "DAC MIXL"},
+       {"Stereo DAC MIXR", NULL, "Stero1 DAC Power"},
+
+       {"DAC L1", NULL, "Stereo DAC MIXL"},
+       {"DAC L1", NULL, "PLL1", is_sys_clk_from_pll},
+       {"DAC R1", NULL, "Stereo DAC MIXR"},
+       {"DAC R1", NULL, "PLL1", is_sys_clk_from_pll},
+
+       {"OUT MIXL", "BST1 Switch", "BST1"},
+       {"OUT MIXL", "BST2 Switch", "BST2"},
+       {"OUT MIXL", "INL1 Switch", "INL1 VOL"},
+       {"OUT MIXL", "REC MIXL Switch", "RECMIXL"},
+       {"OUT MIXL", "DAC L1 Switch", "DAC L1"},
+
+       {"OUT MIXR", "BST2 Switch", "BST2"},
+       {"OUT MIXR", "BST1 Switch", "BST1"},
+       {"OUT MIXR", "INR1 Switch", "INR1 VOL"},
+       {"OUT MIXR", "REC MIXR Switch", "RECMIXR"},
+       {"OUT MIXR", "DAC R1 Switch", "DAC R1"},
+
+       {"HPOVOL L", NULL, "OUT MIXL"},
+       {"HPOVOL R", NULL, "OUT MIXR"},
+       {"OUTVOL L", NULL, "OUT MIXL"},
+       {"OUTVOL R", NULL, "OUT MIXR"},
+
+       {"DAC 1", NULL, "DAC L1"},
+       {"DAC 1", NULL, "DAC R1"},
+       {"HPOVOL", NULL, "HPOVOL L"},
+       {"HPOVOL", NULL, "HPOVOL R"},
+       {"HPO MIX", "DAC1 Switch", "DAC 1"},
+       {"HPO MIX", "HPVOL Switch", "HPOVOL"},
+
+       {"LOUT MIX", "DAC L1 Switch", "DAC L1"},
+       {"LOUT MIX", "DAC R1 Switch", "DAC R1"},
+       {"LOUT MIX", "OUTVOL L Switch", "OUTVOL L"},
+       {"LOUT MIX", "OUTVOL R Switch", "OUTVOL R"},
+
+       {"HP amp", NULL, "HPO MIX"},
+       {"HP amp", NULL, "Charge Pump"},
+       {"HPOL", NULL, "HP amp"},
+       {"HPOR", NULL, "HP amp"},
+
+       {"LOUT amp", NULL, "LOUT MIX"},
+       {"LOUT amp", NULL, "Charge Pump"},
+       {"LOUTL", NULL, "LOUT amp"},
+       {"LOUTR", NULL, "LOUT amp"},
+
+};
+
+static int rt5616_hw_params(struct snd_pcm_substream *substream,
+       struct snd_pcm_hw_params *params, struct snd_soc_dai *dai)
+{
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+       struct snd_soc_codec *codec = rtd->codec;
+       struct rt5616_priv *rt5616 = snd_soc_codec_get_drvdata(codec);
+       unsigned int val_len = 0, val_clk, mask_clk;
+       int pre_div, bclk_ms, frame_size;
+
+       rt5616->lrck[dai->id] = params_rate(params);
+
+       pre_div = rl6231_get_clk_info(rt5616->sysclk, rt5616->lrck[dai->id]);
+
+       if (pre_div < 0) {
+               dev_err(codec->dev, "Unsupported clock setting\n");
+               return -EINVAL;
+       }
+       frame_size = snd_soc_params_to_frame_size(params);
+       if (frame_size < 0) {
+               dev_err(codec->dev, "Unsupported frame size: %d\n", frame_size);
+               return -EINVAL;
+       }
+       bclk_ms = frame_size > 32 ? 1 : 0;
+       rt5616->bclk[dai->id] = rt5616->lrck[dai->id] * (32 << bclk_ms);
+
+       dev_dbg(dai->dev, "bclk is %dHz and lrck is %dHz\n",
+               rt5616->bclk[dai->id], rt5616->lrck[dai->id]);
+       dev_dbg(dai->dev, "bclk_ms is %d and pre_div is %d for iis %d\n",
+                               bclk_ms, pre_div, dai->id);
+
+       switch (params_format(params)) {
+       case SNDRV_PCM_FORMAT_S16_LE:
+               break;
+       case SNDRV_PCM_FORMAT_S20_3LE:
+               val_len |= RT5616_I2S_DL_20;
+               break;
+       case SNDRV_PCM_FORMAT_S24_LE:
+               val_len |= RT5616_I2S_DL_24;
+               break;
+       case SNDRV_PCM_FORMAT_S8:
+               val_len |= RT5616_I2S_DL_8;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       mask_clk = RT5616_I2S_PD1_MASK;
+       val_clk = pre_div << RT5616_I2S_PD1_SFT;
+       snd_soc_update_bits(codec, RT5616_I2S1_SDP,
+               RT5616_I2S_DL_MASK, val_len);
+       snd_soc_update_bits(codec, RT5616_ADDA_CLK1, mask_clk, val_clk);
+
+
+       return 0;
+}
+
+static int rt5616_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)
+{
+       struct snd_soc_codec *codec = dai->codec;
+       struct rt5616_priv *rt5616 = snd_soc_codec_get_drvdata(codec);
+       unsigned int reg_val = 0;
+
+       switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+       case SND_SOC_DAIFMT_CBM_CFM:
+               rt5616->master[dai->id] = 1;
+               break;
+       case SND_SOC_DAIFMT_CBS_CFS:
+               reg_val |= RT5616_I2S_MS_S;
+               rt5616->master[dai->id] = 0;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+       case SND_SOC_DAIFMT_NB_NF:
+               break;
+       case SND_SOC_DAIFMT_IB_NF:
+               reg_val |= RT5616_I2S_BP_INV;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+       case SND_SOC_DAIFMT_I2S:
+               break;
+       case SND_SOC_DAIFMT_LEFT_J:
+               reg_val |= RT5616_I2S_DF_LEFT;
+               break;
+       case SND_SOC_DAIFMT_DSP_A:
+               reg_val |= RT5616_I2S_DF_PCM_A;
+               break;
+       case SND_SOC_DAIFMT_DSP_B:
+               reg_val |= RT5616_I2S_DF_PCM_B;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       snd_soc_update_bits(codec, RT5616_I2S1_SDP,
+               RT5616_I2S_MS_MASK | RT5616_I2S_BP_MASK |
+               RT5616_I2S_DF_MASK, reg_val);
+
+
+       return 0;
+}
+
+static int rt5616_set_dai_sysclk(struct snd_soc_dai *dai,
+               int clk_id, unsigned int freq, int dir)
+{
+       struct snd_soc_codec *codec = dai->codec;
+       struct rt5616_priv *rt5616 = snd_soc_codec_get_drvdata(codec);
+       unsigned int reg_val = 0;
+
+       if (freq == rt5616->sysclk && clk_id == rt5616->sysclk_src)
+               return 0;
+
+       switch (clk_id) {
+       case RT5616_SCLK_S_MCLK:
+               reg_val |= RT5616_SCLK_SRC_MCLK;
+               break;
+       case RT5616_SCLK_S_PLL1:
+               reg_val |= RT5616_SCLK_SRC_PLL1;
+               break;
+       default:
+               dev_err(codec->dev, "Invalid clock id (%d)\n", clk_id);
+               return -EINVAL;
+       }
+       snd_soc_update_bits(codec, RT5616_GLB_CLK,
+               RT5616_SCLK_SRC_MASK, reg_val);
+       rt5616->sysclk = freq;
+       rt5616->sysclk_src = clk_id;
+
+       dev_dbg(dai->dev, "Sysclk is %dHz and clock id is %d\n", freq, clk_id);
+
+       return 0;
+}
+
+static int rt5616_set_dai_pll(struct snd_soc_dai *dai, int pll_id, int source,
+                       unsigned int freq_in, unsigned int freq_out)
+{
+       struct snd_soc_codec *codec = dai->codec;
+       struct rt5616_priv *rt5616 = snd_soc_codec_get_drvdata(codec);
+       struct rl6231_pll_code pll_code;
+       int ret;
+
+       if (source == rt5616->pll_src && freq_in == rt5616->pll_in &&
+           freq_out == rt5616->pll_out)
+               return 0;
+
+       if (!freq_in || !freq_out) {
+               dev_dbg(codec->dev, "PLL disabled\n");
+
+               rt5616->pll_in = 0;
+               rt5616->pll_out = 0;
+               snd_soc_update_bits(codec, RT5616_GLB_CLK,
+                       RT5616_SCLK_SRC_MASK, RT5616_SCLK_SRC_MCLK);
+               return 0;
+       }
+
+       switch (source) {
+       case RT5616_PLL1_S_MCLK:
+               snd_soc_update_bits(codec, RT5616_GLB_CLK,
+                       RT5616_PLL1_SRC_MASK, RT5616_PLL1_SRC_MCLK);
+               break;
+       case RT5616_PLL1_S_BCLK1:
+       case RT5616_PLL1_S_BCLK2:
+               snd_soc_update_bits(codec, RT5616_GLB_CLK,
+                       RT5616_PLL1_SRC_MASK, RT5616_PLL1_SRC_BCLK1);
+               break;
+       default:
+               dev_err(codec->dev, "Unknown PLL source %d\n", source);
+               return -EINVAL;
+       }
+
+       ret = rl6231_pll_calc(freq_in, freq_out, &pll_code);
+       if (ret < 0) {
+               dev_err(codec->dev, "Unsupport input clock %d\n", freq_in);
+               return ret;
+       }
+
+       dev_dbg(codec->dev, "bypass=%d m=%d n=%d k=%d\n",
+               pll_code.m_bp, (pll_code.m_bp ? 0 : pll_code.m_code),
+               pll_code.n_code, pll_code.k_code);
+
+       snd_soc_write(codec, RT5616_PLL_CTRL1,
+               pll_code.n_code << RT5616_PLL_N_SFT | pll_code.k_code);
+       snd_soc_write(codec, RT5616_PLL_CTRL2,
+               (pll_code.m_bp ? 0 : pll_code.m_code) << RT5616_PLL_M_SFT |
+               pll_code.m_bp << RT5616_PLL_M_BP_SFT);
+
+       rt5616->pll_in = freq_in;
+       rt5616->pll_out = freq_out;
+       rt5616->pll_src = source;
+
+       return 0;
+}
+
+static int rt5616_set_bias_level(struct snd_soc_codec *codec,
+                       enum snd_soc_bias_level level)
+{
+       switch (level) {
+       case SND_SOC_BIAS_STANDBY:
+               if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_OFF) {
+                       snd_soc_update_bits(codec, RT5616_PWR_ANLG1,
+                               RT5616_PWR_VREF1 | RT5616_PWR_MB |
+                               RT5616_PWR_BG | RT5616_PWR_VREF2,
+                               RT5616_PWR_VREF1 | RT5616_PWR_MB |
+                               RT5616_PWR_BG | RT5616_PWR_VREF2);
+                       mdelay(10);
+                       snd_soc_update_bits(codec, RT5616_PWR_ANLG1,
+                               RT5616_PWR_FV1 | RT5616_PWR_FV2,
+                               RT5616_PWR_FV1 | RT5616_PWR_FV2);
+                       snd_soc_update_bits(codec, RT5616_D_MISC,
+                               RT5616_D_GATE_EN, RT5616_D_GATE_EN);
+               }
+               break;
+
+       case SND_SOC_BIAS_OFF:
+               snd_soc_update_bits(codec, RT5616_D_MISC, RT5616_D_GATE_EN, 0);
+               snd_soc_write(codec, RT5616_PWR_DIG1, 0x0000);
+               snd_soc_write(codec, RT5616_PWR_DIG2, 0x0000);
+               snd_soc_write(codec, RT5616_PWR_VOL, 0x0000);
+               snd_soc_write(codec, RT5616_PWR_MIXER, 0x0000);
+               snd_soc_write(codec, RT5616_PWR_ANLG1, 0x0000);
+               snd_soc_write(codec, RT5616_PWR_ANLG2, 0x0000);
+               break;
+
+       default:
+               break;
+       }
+
+       return 0;
+}
+
+static int rt5616_probe(struct snd_soc_codec *codec)
+{
+       struct rt5616_priv *rt5616 = snd_soc_codec_get_drvdata(codec);
+
+       rt5616->codec = codec;
+
+       return 0;
+}
+
+#ifdef CONFIG_PM
+static int rt5616_suspend(struct snd_soc_codec *codec)
+{
+       struct rt5616_priv *rt5616 = snd_soc_codec_get_drvdata(codec);
+
+       regcache_cache_only(rt5616->regmap, true);
+       regcache_mark_dirty(rt5616->regmap);
+
+       return 0;
+}
+
+static int rt5616_resume(struct snd_soc_codec *codec)
+{
+       struct rt5616_priv *rt5616 = snd_soc_codec_get_drvdata(codec);
+
+       regcache_cache_only(rt5616->regmap, false);
+       regcache_sync(rt5616->regmap);
+       return 0;
+}
+#else
+#define rt5616_suspend NULL
+#define rt5616_resume NULL
+#endif
+
+#define RT5616_STEREO_RATES SNDRV_PCM_RATE_8000_96000
+#define RT5616_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE | \
+                       SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S8)
+
+
+struct snd_soc_dai_ops rt5616_aif_dai_ops = {
+       .hw_params = rt5616_hw_params,
+       .set_fmt = rt5616_set_dai_fmt,
+       .set_sysclk = rt5616_set_dai_sysclk,
+       .set_pll = rt5616_set_dai_pll,
+};
+
+struct snd_soc_dai_driver rt5616_dai[] = {
+       {
+               .name = "rt5616-aif1",
+               .id = RT5616_AIF1,
+               .playback = {
+                       .stream_name = "AIF1 Playback",
+                       .channels_min = 1,
+                       .channels_max = 2,
+                       .rates = RT5616_STEREO_RATES,
+                       .formats = RT5616_FORMATS,
+               },
+               .capture = {
+                       .stream_name = "AIF1 Capture",
+                       .channels_min = 1,
+                       .channels_max = 2,
+                       .rates = RT5616_STEREO_RATES,
+                       .formats = RT5616_FORMATS,
+               },
+               .ops = &rt5616_aif_dai_ops,
+       },
+};
+
+static struct snd_soc_codec_driver soc_codec_dev_rt5616 = {
+       .probe = rt5616_probe,
+       .suspend = rt5616_suspend,
+       .resume = rt5616_resume,
+       .set_bias_level = rt5616_set_bias_level,
+       .idle_bias_off = true,
+       .controls = rt5616_snd_controls,
+       .num_controls = ARRAY_SIZE(rt5616_snd_controls),
+       .dapm_widgets = rt5616_dapm_widgets,
+       .num_dapm_widgets = ARRAY_SIZE(rt5616_dapm_widgets),
+       .dapm_routes = rt5616_dapm_routes,
+       .num_dapm_routes = ARRAY_SIZE(rt5616_dapm_routes),
+};
+
+static const struct regmap_config rt5616_regmap = {
+       .reg_bits = 8,
+       .val_bits = 16,
+       .use_single_rw = true,
+       .max_register = RT5616_DEVICE_ID + 1 + (ARRAY_SIZE(rt5616_ranges) *
+                                              RT5616_PR_SPACING),
+       .volatile_reg = rt5616_volatile_register,
+       .readable_reg = rt5616_readable_register,
+       .cache_type = REGCACHE_RBTREE,
+       .reg_defaults = rt5616_reg,
+       .num_reg_defaults = ARRAY_SIZE(rt5616_reg),
+       .ranges = rt5616_ranges,
+       .num_ranges = ARRAY_SIZE(rt5616_ranges),
+};
+
+static const struct i2c_device_id rt5616_i2c_id[] = {
+       { "rt5616", 0 },
+       { }
+};
+MODULE_DEVICE_TABLE(i2c, rt5616_i2c_id);
+
+#if defined(CONFIG_OF)
+static const struct of_device_id rt5616_of_match[] = {
+       { .compatible = "realtek,rt5616", },
+       {},
+};
+MODULE_DEVICE_TABLE(of, rt5616_of_match);
+#endif
+
+static int rt5616_i2c_probe(struct i2c_client *i2c,
+                   const struct i2c_device_id *id)
+{
+       struct rt5616_priv *rt5616;
+       unsigned int val;
+       int ret;
+
+       rt5616 = devm_kzalloc(&i2c->dev, sizeof(struct rt5616_priv),
+                               GFP_KERNEL);
+       if (rt5616 == NULL)
+               return -ENOMEM;
+
+       i2c_set_clientdata(i2c, rt5616);
+
+       rt5616->regmap = devm_regmap_init_i2c(i2c, &rt5616_regmap);
+       if (IS_ERR(rt5616->regmap)) {
+               ret = PTR_ERR(rt5616->regmap);
+               dev_err(&i2c->dev, "Failed to allocate register map: %d\n",
+                       ret);
+               return ret;
+       }
+
+       regmap_read(rt5616->regmap, RT5616_DEVICE_ID, &val);
+       if (val != 0x6281) {
+               dev_err(&i2c->dev,
+                       "Device with ID register %#x is not rt5616\n",
+                       val);
+               return -ENODEV;
+       }
+       regmap_write(rt5616->regmap, RT5616_RESET, 0);
+       regmap_update_bits(rt5616->regmap, RT5616_PWR_ANLG1,
+               RT5616_PWR_VREF1 | RT5616_PWR_MB |
+               RT5616_PWR_BG | RT5616_PWR_VREF2,
+               RT5616_PWR_VREF1 | RT5616_PWR_MB |
+               RT5616_PWR_BG | RT5616_PWR_VREF2);
+       mdelay(10);
+       regmap_update_bits(rt5616->regmap, RT5616_PWR_ANLG1,
+               RT5616_PWR_FV1 | RT5616_PWR_FV2,
+               RT5616_PWR_FV1 | RT5616_PWR_FV2);
+
+       ret = regmap_register_patch(rt5616->regmap, init_list,
+                                   ARRAY_SIZE(init_list));
+       if (ret != 0)
+               dev_warn(&i2c->dev, "Failed to apply regmap patch: %d\n", ret);
+
+       regmap_update_bits(rt5616->regmap, RT5616_PWR_ANLG1,
+               RT5616_PWR_LDO_DVO_MASK, RT5616_PWR_LDO_DVO_1_2V);
+
+       return snd_soc_register_codec(&i2c->dev, &soc_codec_dev_rt5616,
+                       rt5616_dai, ARRAY_SIZE(rt5616_dai));
+
+}
+
+static int rt5616_i2c_remove(struct i2c_client *i2c)
+{
+       snd_soc_unregister_codec(&i2c->dev);
+
+       return 0;
+}
+
+static void rt5616_i2c_shutdown(struct i2c_client *client)
+{
+       struct rt5616_priv *rt5616 = i2c_get_clientdata(client);
+
+       regmap_write(rt5616->regmap, RT5616_HP_VOL, 0xc8c8);
+       regmap_write(rt5616->regmap, RT5616_LOUT_CTRL1, 0xc8c8);
+
+}
+
+static struct i2c_driver rt5616_i2c_driver = {
+       .driver = {
+               .name = "rt5616",
+               .of_match_table = of_match_ptr(rt5616_of_match),
+       },
+       .probe = rt5616_i2c_probe,
+       .remove = rt5616_i2c_remove,
+       .shutdown = rt5616_i2c_shutdown,
+       .id_table = rt5616_i2c_id,
+};
+module_i2c_driver(rt5616_i2c_driver);
+
+MODULE_DESCRIPTION("ASoC RT5616 driver");
+MODULE_AUTHOR("Bard Liao <bardliao@realtek.com>");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/rt5616.h b/sound/soc/codecs/rt5616.h
new file mode 100644 (file)
index 0000000..f88cddd
--- /dev/null
@@ -0,0 +1,1819 @@
+/*
+ * rt5616.h  --  RT5616 ALSA SoC audio driver
+ *
+ * Copyright 2011 Realtek Microelectronics
+ * Author: Johnny Hsu <johnnyhsu@realtek.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 __RT5616_H__
+#define __RT5616_H__
+
+/* Info */
+#define RT5616_RESET                           0x00
+#define RT5616_VERSION_ID                      0xfd
+#define RT5616_VENDOR_ID                       0xfe
+#define RT5616_DEVICE_ID                       0xff
+/*  I/O - Output */
+#define RT5616_HP_VOL                          0x02
+#define RT5616_LOUT_CTRL1                      0x03
+#define RT5616_LOUT_CTRL2                      0x05
+/* I/O - Input */
+#define RT5616_IN1_IN2                         0x0d
+#define RT5616_INL1_INR1_VOL                   0x0f
+/* I/O - ADC/DAC/DMIC */
+#define RT5616_DAC1_DIG_VOL                    0x19
+#define RT5616_ADC_DIG_VOL                     0x1c
+#define RT5616_ADC_BST_VOL                     0x1e
+/* Mixer - D-D */
+#define RT5616_STO1_ADC_MIXER                  0x27
+#define RT5616_AD_DA_MIXER                     0x29
+#define RT5616_STO_DAC_MIXER                   0x2a
+
+/* Mixer - ADC */
+#define RT5616_REC_L1_MIXER                    0x3b
+#define RT5616_REC_L2_MIXER                    0x3c
+#define RT5616_REC_R1_MIXER                    0x3d
+#define RT5616_REC_R2_MIXER                    0x3e
+/* Mixer - DAC */
+#define RT5616_HPO_MIXER                       0x45
+#define RT5616_OUT_L1_MIXER                    0x4d
+#define RT5616_OUT_L2_MIXER                    0x4e
+#define RT5616_OUT_L3_MIXER                    0x4f
+#define RT5616_OUT_R1_MIXER                    0x50
+#define RT5616_OUT_R2_MIXER                    0x51
+#define RT5616_OUT_R3_MIXER                    0x52
+#define RT5616_LOUT_MIXER                      0x53
+/* Power */
+#define RT5616_PWR_DIG1                                0x61
+#define RT5616_PWR_DIG2                                0x62
+#define RT5616_PWR_ANLG1                       0x63
+#define RT5616_PWR_ANLG2                       0x64
+#define RT5616_PWR_MIXER                       0x65
+#define RT5616_PWR_VOL                         0x66
+/* Private Register Control */
+#define RT5616_PRIV_INDEX                      0x6a
+#define RT5616_PRIV_DATA                       0x6c
+/* Format - ADC/DAC */
+#define RT5616_I2S1_SDP                                0x70
+#define RT5616_ADDA_CLK1                       0x73
+#define RT5616_ADDA_CLK2                       0x74
+
+/* Function - Analog */
+#define RT5616_GLB_CLK                         0x80
+#define RT5616_PLL_CTRL1                       0x81
+#define RT5616_PLL_CTRL2                       0x82
+#define RT5616_HP_OVCD                         0x8b
+#define RT5616_DEPOP_M1                                0x8e
+#define RT5616_DEPOP_M2                                0x8f
+#define RT5616_DEPOP_M3                                0x90
+#define RT5616_CHARGE_PUMP                     0x91
+#define RT5616_PV_DET_SPK_G                    0x92
+#define RT5616_MICBIAS                         0x93
+#define RT5616_A_JD_CTL1                       0x94
+#define RT5616_A_JD_CTL2                       0x95
+/* Function - Digital */
+#define RT5616_EQ_CTRL1                                0xb0
+#define RT5616_EQ_CTRL2                                0xb1
+#define RT5616_WIND_FILTER                     0xb2
+#define RT5616_DRC_AGC_1                       0xb4
+#define RT5616_DRC_AGC_2                       0xb5
+#define RT5616_DRC_AGC_3                       0xb6
+#define RT5616_SVOL_ZC                         0xb7
+#define RT5616_JD_CTRL1                                0xbb
+#define RT5616_JD_CTRL2                                0xbc
+#define RT5616_IRQ_CTRL1                       0xbd
+#define RT5616_IRQ_CTRL2                       0xbe
+#define RT5616_INT_IRQ_ST                      0xbf
+#define RT5616_GPIO_CTRL1                      0xc0
+#define RT5616_GPIO_CTRL2                      0xc1
+#define RT5616_GPIO_CTRL3                      0xc2
+#define RT5616_PGM_REG_ARR1                    0xc8
+#define RT5616_PGM_REG_ARR2                    0xc9
+#define RT5616_PGM_REG_ARR3                    0xca
+#define RT5616_PGM_REG_ARR4                    0xcb
+#define RT5616_PGM_REG_ARR5                    0xcc
+#define RT5616_SCB_FUNC                                0xcd
+#define RT5616_SCB_CTRL                                0xce
+#define RT5616_BASE_BACK                       0xcf
+#define RT5616_MP3_PLUS1                       0xd0
+#define RT5616_MP3_PLUS2                       0xd1
+#define RT5616_ADJ_HPF_CTRL1                   0xd3
+#define RT5616_ADJ_HPF_CTRL2                   0xd4
+#define RT5616_HP_CALIB_AMP_DET                        0xd6
+#define RT5616_HP_CALIB2                       0xd7
+#define RT5616_SV_ZCD1                         0xd9
+#define RT5616_SV_ZCD2                         0xda
+#define RT5616_D_MISC                          0xfa
+/* Dummy Register */
+#define RT5616_DUMMY2                          0xfb
+#define RT5616_DUMMY3                          0xfc
+
+
+/* Index of Codec Private Register definition */
+#define RT5616_BIAS_CUR1                       0x12
+#define RT5616_BIAS_CUR3                       0x14
+#define RT5616_CLSD_INT_REG1                   0x1c
+#define RT5616_MAMP_INT_REG2                   0x37
+#define RT5616_CHOP_DAC_ADC                    0x3d
+#define RT5616_3D_SPK                          0x63
+#define RT5616_WND_1                           0x6c
+#define RT5616_WND_2                           0x6d
+#define RT5616_WND_3                           0x6e
+#define RT5616_WND_4                           0x6f
+#define RT5616_WND_5                           0x70
+#define RT5616_WND_8                           0x73
+#define RT5616_DIP_SPK_INF                     0x75
+#define RT5616_HP_DCC_INT1                     0x77
+#define RT5616_EQ_BW_LOP                       0xa0
+#define RT5616_EQ_GN_LOP                       0xa1
+#define RT5616_EQ_FC_BP1                       0xa2
+#define RT5616_EQ_BW_BP1                       0xa3
+#define RT5616_EQ_GN_BP1                       0xa4
+#define RT5616_EQ_FC_BP2                       0xa5
+#define RT5616_EQ_BW_BP2                       0xa6
+#define RT5616_EQ_GN_BP2                       0xa7
+#define RT5616_EQ_FC_BP3                       0xa8
+#define RT5616_EQ_BW_BP3                       0xa9
+#define RT5616_EQ_GN_BP3                       0xaa
+#define RT5616_EQ_FC_BP4                       0xab
+#define RT5616_EQ_BW_BP4                       0xac
+#define RT5616_EQ_GN_BP4                       0xad
+#define RT5616_EQ_FC_HIP1                      0xae
+#define RT5616_EQ_GN_HIP1                      0xaf
+#define RT5616_EQ_FC_HIP2                      0xb0
+#define RT5616_EQ_BW_HIP2                      0xb1
+#define RT5616_EQ_GN_HIP2                      0xb2
+#define RT5616_EQ_PRE_VOL                      0xb3
+#define RT5616_EQ_PST_VOL                      0xb4
+
+
+/* global definition */
+#define RT5616_L_MUTE                          (0x1 << 15)
+#define RT5616_L_MUTE_SFT                      15
+#define RT5616_VOL_L_MUTE                      (0x1 << 14)
+#define RT5616_VOL_L_SFT                       14
+#define RT5616_R_MUTE                          (0x1 << 7)
+#define RT5616_R_MUTE_SFT                      7
+#define RT5616_VOL_R_MUTE                      (0x1 << 6)
+#define RT5616_VOL_R_SFT                       6
+#define RT5616_L_VOL_MASK                      (0x3f << 8)
+#define RT5616_L_VOL_SFT                       8
+#define RT5616_R_VOL_MASK                      (0x3f)
+#define RT5616_R_VOL_SFT                       0
+
+/* LOUT Control 2(0x05) */
+#define RT5616_EN_DFO                          (0x1 << 15)
+
+/* IN1 and IN2 Control (0x0d) */
+/* IN3 and IN4 Control (0x0e) */
+#define RT5616_BST_MASK1                       (0xf<<12)
+#define RT5616_BST_SFT1                                12
+#define RT5616_BST_MASK2                       (0xf<<8)
+#define RT5616_BST_SFT2                                8
+#define RT5616_IN_DF1                          (0x1 << 7)
+#define RT5616_IN_SFT1                         7
+#define RT5616_IN_DF2                          (0x1 << 6)
+#define RT5616_IN_SFT2                         6
+
+/* INL1 and INR1 Volume Control (0x0f) */
+#define RT5616_INL_VOL_MASK                    (0x1f << 8)
+#define RT5616_INL_VOL_SFT                     8
+#define RT5616_INR_SEL_MASK                    (0x1 << 7)
+#define RT5616_INR_SEL_SFT                     7
+#define RT5616_INR_SEL_IN4N                    (0x0 << 7)
+#define RT5616_INR_SEL_MONON                   (0x1 << 7)
+#define RT5616_INR_VOL_MASK                    (0x1f)
+#define RT5616_INR_VOL_SFT                     0
+
+/* DAC1 Digital Volume (0x19) */
+#define RT5616_DAC_L1_VOL_MASK                 (0xff << 8)
+#define RT5616_DAC_L1_VOL_SFT                  8
+#define RT5616_DAC_R1_VOL_MASK                 (0xff)
+#define RT5616_DAC_R1_VOL_SFT                  0
+
+/* DAC2 Digital Volume (0x1a) */
+#define RT5616_DAC_L2_VOL_MASK                 (0xff << 8)
+#define RT5616_DAC_L2_VOL_SFT                  8
+#define RT5616_DAC_R2_VOL_MASK                 (0xff)
+#define RT5616_DAC_R2_VOL_SFT                  0
+
+/* ADC Digital Volume Control (0x1c) */
+#define RT5616_ADC_L_VOL_MASK                  (0x7f << 8)
+#define RT5616_ADC_L_VOL_SFT                   8
+#define RT5616_ADC_R_VOL_MASK                  (0x7f)
+#define RT5616_ADC_R_VOL_SFT                   0
+
+/* Mono ADC Digital Volume Control (0x1d) */
+#define RT5616_M_MONO_ADC_L                    (0x1 << 15)
+#define RT5616_M_MONO_ADC_L_SFT                        15
+#define RT5616_MONO_ADC_L_VOL_MASK             (0x7f << 8)
+#define RT5616_MONO_ADC_L_VOL_SFT              8
+#define RT5616_M_MONO_ADC_R                    (0x1 << 7)
+#define RT5616_M_MONO_ADC_R_SFT                        7
+#define RT5616_MONO_ADC_R_VOL_MASK             (0x7f)
+#define RT5616_MONO_ADC_R_VOL_SFT              0
+
+/* ADC Boost Volume Control (0x1e) */
+#define RT5616_ADC_L_BST_MASK                  (0x3 << 14)
+#define RT5616_ADC_L_BST_SFT                   14
+#define RT5616_ADC_R_BST_MASK                  (0x3 << 12)
+#define RT5616_ADC_R_BST_SFT                   12
+#define RT5616_ADC_COMP_MASK                   (0x3 << 10)
+#define RT5616_ADC_COMP_SFT                    10
+
+/* Stereo ADC1 Mixer Control (0x27) */
+#define RT5616_M_STO1_ADC_L1                   (0x1 << 14)
+#define RT5616_M_STO1_ADC_L1_SFT               14
+#define RT5616_M_STO1_ADC_R1                   (0x1 << 6)
+#define RT5616_M_STO1_ADC_R1_SFT               6
+
+/* ADC Mixer to DAC Mixer Control (0x29) */
+#define RT5616_M_ADCMIX_L                      (0x1 << 15)
+#define RT5616_M_ADCMIX_L_SFT                  15
+#define RT5616_M_IF1_DAC_L                     (0x1 << 14)
+#define RT5616_M_IF1_DAC_L_SFT                 14
+#define RT5616_M_ADCMIX_R                      (0x1 << 7)
+#define RT5616_M_ADCMIX_R_SFT                  7
+#define RT5616_M_IF1_DAC_R                     (0x1 << 6)
+#define RT5616_M_IF1_DAC_R_SFT                 6
+
+/* Stereo DAC Mixer Control (0x2a) */
+#define RT5616_M_DAC_L1_MIXL                   (0x1 << 14)
+#define RT5616_M_DAC_L1_MIXL_SFT               14
+#define RT5616_DAC_L1_STO_L_VOL_MASK           (0x1 << 13)
+#define RT5616_DAC_L1_STO_L_VOL_SFT            13
+#define RT5616_M_DAC_R1_MIXL                   (0x1 << 9)
+#define RT5616_M_DAC_R1_MIXL_SFT               9
+#define RT5616_DAC_R1_STO_L_VOL_MASK           (0x1 << 8)
+#define RT5616_DAC_R1_STO_L_VOL_SFT            8
+#define RT5616_M_DAC_R1_MIXR                   (0x1 << 6)
+#define RT5616_M_DAC_R1_MIXR_SFT               6
+#define RT5616_DAC_R1_STO_R_VOL_MASK           (0x1 << 5)
+#define RT5616_DAC_R1_STO_R_VOL_SFT            5
+#define RT5616_M_DAC_L1_MIXR                   (0x1 << 1)
+#define RT5616_M_DAC_L1_MIXR_SFT               1
+#define RT5616_DAC_L1_STO_R_VOL_MASK           (0x1)
+#define RT5616_DAC_L1_STO_R_VOL_SFT            0
+
+/* DD Mixer Control (0x2b) */
+#define RT5616_M_STO_DD_L1                     (0x1 << 14)
+#define RT5616_M_STO_DD_L1_SFT                 14
+#define RT5616_STO_DD_L1_VOL_MASK              (0x1 << 13)
+#define RT5616_DAC_DD_L1_VOL_SFT               13
+#define RT5616_M_STO_DD_L2                     (0x1 << 12)
+#define RT5616_M_STO_DD_L2_SFT                 12
+#define RT5616_STO_DD_L2_VOL_MASK              (0x1 << 11)
+#define RT5616_STO_DD_L2_VOL_SFT               11
+#define RT5616_M_STO_DD_R2_L                   (0x1 << 10)
+#define RT5616_M_STO_DD_R2_L_SFT               10
+#define RT5616_STO_DD_R2_L_VOL_MASK            (0x1 << 9)
+#define RT5616_STO_DD_R2_L_VOL_SFT             9
+#define RT5616_M_STO_DD_R1                     (0x1 << 6)
+#define RT5616_M_STO_DD_R1_SFT                 6
+#define RT5616_STO_DD_R1_VOL_MASK              (0x1 << 5)
+#define RT5616_STO_DD_R1_VOL_SFT               5
+#define RT5616_M_STO_DD_R2                     (0x1 << 4)
+#define RT5616_M_STO_DD_R2_SFT                 4
+#define RT5616_STO_DD_R2_VOL_MASK              (0x1 << 3)
+#define RT5616_STO_DD_R2_VOL_SFT               3
+#define RT5616_M_STO_DD_L2_R                   (0x1 << 2)
+#define RT5616_M_STO_DD_L2_R_SFT               2
+#define RT5616_STO_DD_L2_R_VOL_MASK            (0x1 << 1)
+#define RT5616_STO_DD_L2_R_VOL_SFT             1
+
+/* Digital Mixer Control (0x2c) */
+#define RT5616_M_STO_L_DAC_L                   (0x1 << 15)
+#define RT5616_M_STO_L_DAC_L_SFT               15
+#define RT5616_STO_L_DAC_L_VOL_MASK            (0x1 << 14)
+#define RT5616_STO_L_DAC_L_VOL_SFT             14
+#define RT5616_M_DAC_L2_DAC_L                  (0x1 << 13)
+#define RT5616_M_DAC_L2_DAC_L_SFT              13
+#define RT5616_DAC_L2_DAC_L_VOL_MASK           (0x1 << 12)
+#define RT5616_DAC_L2_DAC_L_VOL_SFT            12
+#define RT5616_M_STO_R_DAC_R                   (0x1 << 11)
+#define RT5616_M_STO_R_DAC_R_SFT               11
+#define RT5616_STO_R_DAC_R_VOL_MASK            (0x1 << 10)
+#define RT5616_STO_R_DAC_R_VOL_SFT             10
+#define RT5616_M_DAC_R2_DAC_R                  (0x1 << 9)
+#define RT5616_M_DAC_R2_DAC_R_SFT              9
+#define RT5616_DAC_R2_DAC_R_VOL_MASK           (0x1 << 8)
+#define RT5616_DAC_R2_DAC_R_VOL_SFT            8
+
+/* DSP Path Control 1 (0x2d) */
+#define RT5616_RXDP_SRC_MASK                   (0x1 << 15)
+#define RT5616_RXDP_SRC_SFT                    15
+#define RT5616_RXDP_SRC_NOR                    (0x0 << 15)
+#define RT5616_RXDP_SRC_DIV3                   (0x1 << 15)
+#define RT5616_TXDP_SRC_MASK                   (0x1 << 14)
+#define RT5616_TXDP_SRC_SFT                    14
+#define RT5616_TXDP_SRC_NOR                    (0x0 << 14)
+#define RT5616_TXDP_SRC_DIV3                   (0x1 << 14)
+
+/* DSP Path Control 2 (0x2e) */
+#define RT5616_DAC_L2_SEL_MASK                 (0x3 << 14)
+#define RT5616_DAC_L2_SEL_SFT                  14
+#define RT5616_DAC_L2_SEL_IF2                  (0x0 << 14)
+#define RT5616_DAC_L2_SEL_IF3                  (0x1 << 14)
+#define RT5616_DAC_L2_SEL_TXDC                 (0x2 << 14)
+#define RT5616_DAC_L2_SEL_BASS                 (0x3 << 14)
+#define RT5616_DAC_R2_SEL_MASK                 (0x3 << 12)
+#define RT5616_DAC_R2_SEL_SFT                  12
+#define RT5616_DAC_R2_SEL_IF2                  (0x0 << 12)
+#define RT5616_DAC_R2_SEL_IF3                  (0x1 << 12)
+#define RT5616_DAC_R2_SEL_TXDC                 (0x2 << 12)
+#define RT5616_IF2_ADC_L_SEL_MASK              (0x1 << 11)
+#define RT5616_IF2_ADC_L_SEL_SFT               11
+#define RT5616_IF2_ADC_L_SEL_TXDP              (0x0 << 11)
+#define RT5616_IF2_ADC_L_SEL_PASS              (0x1 << 11)
+#define RT5616_IF2_ADC_R_SEL_MASK              (0x1 << 10)
+#define RT5616_IF2_ADC_R_SEL_SFT               10
+#define RT5616_IF2_ADC_R_SEL_TXDP              (0x0 << 10)
+#define RT5616_IF2_ADC_R_SEL_PASS              (0x1 << 10)
+#define RT5616_RXDC_SEL_MASK                   (0x3 << 8)
+#define RT5616_RXDC_SEL_SFT                    8
+#define RT5616_RXDC_SEL_NOR                    (0x0 << 8)
+#define RT5616_RXDC_SEL_L2R                    (0x1 << 8)
+#define RT5616_RXDC_SEL_R2L                    (0x2 << 8)
+#define RT5616_RXDC_SEL_SWAP                   (0x3 << 8)
+#define RT5616_RXDP_SEL_MASK                   (0x3 << 6)
+#define RT5616_RXDP_SEL_SFT                    6
+#define RT5616_RXDP_SEL_NOR                    (0x0 << 6)
+#define RT5616_RXDP_SEL_L2R                    (0x1 << 6)
+#define RT5616_RXDP_SEL_R2L                    (0x2 << 6)
+#define RT5616_RXDP_SEL_SWAP                   (0x3 << 6)
+#define RT5616_TXDC_SEL_MASK                   (0x3 << 4)
+#define RT5616_TXDC_SEL_SFT                    4
+#define RT5616_TXDC_SEL_NOR                    (0x0 << 4)
+#define RT5616_TXDC_SEL_L2R                    (0x1 << 4)
+#define RT5616_TXDC_SEL_R2L                    (0x2 << 4)
+#define RT5616_TXDC_SEL_SWAP                   (0x3 << 4)
+#define RT5616_TXDP_SEL_MASK                   (0x3 << 2)
+#define RT5616_TXDP_SEL_SFT                    2
+#define RT5616_TXDP_SEL_NOR                    (0x0 << 2)
+#define RT5616_TXDP_SEL_L2R                    (0x1 << 2)
+#define RT5616_TXDP_SEL_R2L                    (0x2 << 2)
+#define RT5616_TRXDP_SEL_SWAP                  (0x3 << 2)
+
+/* REC Left Mixer Control 1 (0x3b) */
+#define RT5616_G_LN_L2_RM_L_MASK               (0x7 << 13)
+#define RT5616_G_IN_L2_RM_L_SFT                        13
+#define RT5616_G_LN_L1_RM_L_MASK               (0x7 << 10)
+#define RT5616_G_IN_L1_RM_L_SFT                        10
+#define RT5616_G_BST3_RM_L_MASK                        (0x7 << 4)
+#define RT5616_G_BST3_RM_L_SFT                 4
+#define RT5616_G_BST2_RM_L_MASK                        (0x7 << 1)
+#define RT5616_G_BST2_RM_L_SFT                 1
+
+/* REC Left Mixer Control 2 (0x3c) */
+#define RT5616_G_BST1_RM_L_MASK                        (0x7 << 13)
+#define RT5616_G_BST1_RM_L_SFT                 13
+#define RT5616_G_OM_L_RM_L_MASK                        (0x7 << 10)
+#define RT5616_G_OM_L_RM_L_SFT                 10
+#define RT5616_M_IN2_L_RM_L                    (0x1 << 6)
+#define RT5616_M_IN2_L_RM_L_SFT                        6
+#define RT5616_M_IN1_L_RM_L                    (0x1 << 5)
+#define RT5616_M_IN1_L_RM_L_SFT                        5
+#define RT5616_M_BST3_RM_L                     (0x1 << 3)
+#define RT5616_M_BST3_RM_L_SFT                 3
+#define RT5616_M_BST2_RM_L                     (0x1 << 2)
+#define RT5616_M_BST2_RM_L_SFT                 2
+#define RT5616_M_BST1_RM_L                     (0x1 << 1)
+#define RT5616_M_BST1_RM_L_SFT                 1
+#define RT5616_M_OM_L_RM_L                     (0x1)
+#define RT5616_M_OM_L_RM_L_SFT                 0
+
+/* REC Right Mixer Control 1 (0x3d) */
+#define RT5616_G_IN2_R_RM_R_MASK               (0x7 << 13)
+#define RT5616_G_IN2_R_RM_R_SFT                        13
+#define RT5616_G_IN1_R_RM_R_MASK               (0x7 << 10)
+#define RT5616_G_IN1_R_RM_R_SFT                        10
+#define RT5616_G_BST3_RM_R_MASK                        (0x7 << 4)
+#define RT5616_G_BST3_RM_R_SFT                 4
+#define RT5616_G_BST2_RM_R_MASK                        (0x7 << 1)
+#define RT5616_G_BST2_RM_R_SFT                 1
+
+/* REC Right Mixer Control 2 (0x3e) */
+#define RT5616_G_BST1_RM_R_MASK                        (0x7 << 13)
+#define RT5616_G_BST1_RM_R_SFT                 13
+#define RT5616_G_OM_R_RM_R_MASK                        (0x7 << 10)
+#define RT5616_G_OM_R_RM_R_SFT                 10
+#define RT5616_M_IN2_R_RM_R                    (0x1 << 6)
+#define RT5616_M_IN2_R_RM_R_SFT                        6
+#define RT5616_M_IN1_R_RM_R                    (0x1 << 5)
+#define RT5616_M_IN1_R_RM_R_SFT                        5
+#define RT5616_M_BST3_RM_R                     (0x1 << 3)
+#define RT5616_M_BST3_RM_R_SFT                 3
+#define RT5616_M_BST2_RM_R                     (0x1 << 2)
+#define RT5616_M_BST2_RM_R_SFT                 2
+#define RT5616_M_BST1_RM_R                     (0x1 << 1)
+#define RT5616_M_BST1_RM_R_SFT                 1
+#define RT5616_M_OM_R_RM_R                     (0x1)
+#define RT5616_M_OM_R_RM_R_SFT                 0
+
+/* HPMIX Control (0x45) */
+#define RT5616_M_DAC1_HM                       (0x1 << 14)
+#define RT5616_M_DAC1_HM_SFT                   14
+#define RT5616_M_HPVOL_HM                      (0x1 << 13)
+#define RT5616_M_HPVOL_HM_SFT                  13
+#define RT5616_G_HPOMIX_MASK                   (0x1 << 12)
+#define RT5616_G_HPOMIX_SFT                    12
+
+/* SPK Left Mixer Control (0x46) */
+#define RT5616_G_RM_L_SM_L_MASK                        (0x3 << 14)
+#define RT5616_G_RM_L_SM_L_SFT                 14
+#define RT5616_G_IN_L_SM_L_MASK                        (0x3 << 12)
+#define RT5616_G_IN_L_SM_L_SFT                 12
+#define RT5616_G_DAC_L1_SM_L_MASK              (0x3 << 10)
+#define RT5616_G_DAC_L1_SM_L_SFT               10
+#define RT5616_G_DAC_L2_SM_L_MASK              (0x3 << 8)
+#define RT5616_G_DAC_L2_SM_L_SFT               8
+#define RT5616_G_OM_L_SM_L_MASK                        (0x3 << 6)
+#define RT5616_G_OM_L_SM_L_SFT                 6
+#define RT5616_M_RM_L_SM_L                     (0x1 << 5)
+#define RT5616_M_RM_L_SM_L_SFT                 5
+#define RT5616_M_IN_L_SM_L                     (0x1 << 4)
+#define RT5616_M_IN_L_SM_L_SFT                 4
+#define RT5616_M_DAC_L1_SM_L                   (0x1 << 3)
+#define RT5616_M_DAC_L1_SM_L_SFT               3
+#define RT5616_M_DAC_L2_SM_L                   (0x1 << 2)
+#define RT5616_M_DAC_L2_SM_L_SFT               2
+#define RT5616_M_OM_L_SM_L                     (0x1 << 1)
+#define RT5616_M_OM_L_SM_L_SFT                 1
+
+/* SPK Right Mixer Control (0x47) */
+#define RT5616_G_RM_R_SM_R_MASK                        (0x3 << 14)
+#define RT5616_G_RM_R_SM_R_SFT                 14
+#define RT5616_G_IN_R_SM_R_MASK                        (0x3 << 12)
+#define RT5616_G_IN_R_SM_R_SFT                 12
+#define RT5616_G_DAC_R1_SM_R_MASK              (0x3 << 10)
+#define RT5616_G_DAC_R1_SM_R_SFT               10
+#define RT5616_G_DAC_R2_SM_R_MASK              (0x3 << 8)
+#define RT5616_G_DAC_R2_SM_R_SFT               8
+#define RT5616_G_OM_R_SM_R_MASK                        (0x3 << 6)
+#define RT5616_G_OM_R_SM_R_SFT                 6
+#define RT5616_M_RM_R_SM_R                     (0x1 << 5)
+#define RT5616_M_RM_R_SM_R_SFT                 5
+#define RT5616_M_IN_R_SM_R                     (0x1 << 4)
+#define RT5616_M_IN_R_SM_R_SFT                 4
+#define RT5616_M_DAC_R1_SM_R                   (0x1 << 3)
+#define RT5616_M_DAC_R1_SM_R_SFT               3
+#define RT5616_M_DAC_R2_SM_R                   (0x1 << 2)
+#define RT5616_M_DAC_R2_SM_R_SFT               2
+#define RT5616_M_OM_R_SM_R                     (0x1 << 1)
+#define RT5616_M_OM_R_SM_R_SFT                 1
+
+/* SPOLMIX Control (0x48) */
+#define RT5616_M_DAC_R1_SPM_L                  (0x1 << 15)
+#define RT5616_M_DAC_R1_SPM_L_SFT              15
+#define RT5616_M_DAC_L1_SPM_L                  (0x1 << 14)
+#define RT5616_M_DAC_L1_SPM_L_SFT              14
+#define RT5616_M_SV_R_SPM_L                    (0x1 << 13)
+#define RT5616_M_SV_R_SPM_L_SFT                        13
+#define RT5616_M_SV_L_SPM_L                    (0x1 << 12)
+#define RT5616_M_SV_L_SPM_L_SFT                        12
+#define RT5616_M_BST1_SPM_L                    (0x1 << 11)
+#define RT5616_M_BST1_SPM_L_SFT                        11
+
+/* SPORMIX Control (0x49) */
+#define RT5616_M_DAC_R1_SPM_R                  (0x1 << 13)
+#define RT5616_M_DAC_R1_SPM_R_SFT              13
+#define RT5616_M_SV_R_SPM_R                    (0x1 << 12)
+#define RT5616_M_SV_R_SPM_R_SFT                        12
+#define RT5616_M_BST1_SPM_R                    (0x1 << 11)
+#define RT5616_M_BST1_SPM_R_SFT                        11
+
+/* SPOLMIX / SPORMIX Ratio Control (0x4a) */
+#define RT5616_SPO_CLSD_RATIO_MASK             (0x7)
+#define RT5616_SPO_CLSD_RATIO_SFT              0
+
+/* Mono Output Mixer Control (0x4c) */
+#define RT5616_M_DAC_R2_MM                     (0x1 << 15)
+#define RT5616_M_DAC_R2_MM_SFT                 15
+#define RT5616_M_DAC_L2_MM                     (0x1 << 14)
+#define RT5616_M_DAC_L2_MM_SFT                 14
+#define RT5616_M_OV_R_MM                       (0x1 << 13)
+#define RT5616_M_OV_R_MM_SFT                   13
+#define RT5616_M_OV_L_MM                       (0x1 << 12)
+#define RT5616_M_OV_L_MM_SFT                   12
+#define RT5616_M_BST1_MM                       (0x1 << 11)
+#define RT5616_M_BST1_MM_SFT                   11
+#define RT5616_G_MONOMIX_MASK                  (0x1 << 10)
+#define RT5616_G_MONOMIX_SFT                   10
+
+/* Output Left Mixer Control 1 (0x4d) */
+#define RT5616_G_BST2_OM_L_MASK                        (0x7 << 10)
+#define RT5616_G_BST2_OM_L_SFT                 10
+#define RT5616_G_BST1_OM_L_MASK                        (0x7 << 7)
+#define RT5616_G_BST1_OM_L_SFT                 7
+#define RT5616_G_IN1_L_OM_L_MASK               (0x7 << 4)
+#define RT5616_G_IN1_L_OM_L_SFT                        4
+#define RT5616_G_RM_L_OM_L_MASK                        (0x7 << 1)
+#define RT5616_G_RM_L_OM_L_SFT                 1
+
+/* Output Left Mixer Control 2 (0x4e) */
+#define RT5616_G_DAC_L1_OM_L_MASK              (0x7 << 7)
+#define RT5616_G_DAC_L1_OM_L_SFT               7
+#define RT5616_G_IN2_L_OM_L_MASK               (0x7 << 4)
+#define RT5616_G_IN2_L_OM_L_SFT                        4
+
+/* Output Left Mixer Control 3 (0x4f) */
+#define RT5616_M_IN2_L_OM_L                    (0x1 << 9)
+#define RT5616_M_IN2_L_OM_L_SFT                        9
+#define RT5616_M_BST2_OM_L                     (0x1 << 6)
+#define RT5616_M_BST2_OM_L_SFT                 6
+#define RT5616_M_BST1_OM_L                     (0x1 << 5)
+#define RT5616_M_BST1_OM_L_SFT                 5
+#define RT5616_M_IN1_L_OM_L                    (0x1 << 4)
+#define RT5616_M_IN1_L_OM_L_SFT                        4
+#define RT5616_M_RM_L_OM_L                     (0x1 << 3)
+#define RT5616_M_RM_L_OM_L_SFT                 3
+#define RT5616_M_DAC_L1_OM_L                   (0x1)
+#define RT5616_M_DAC_L1_OM_L_SFT               0
+
+/* Output Right Mixer Control 1 (0x50) */
+#define RT5616_G_BST2_OM_R_MASK                        (0x7 << 10)
+#define RT5616_G_BST2_OM_R_SFT                 10
+#define RT5616_G_BST1_OM_R_MASK                        (0x7 << 7)
+#define RT5616_G_BST1_OM_R_SFT                 7
+#define RT5616_G_IN1_R_OM_R_MASK               (0x7 << 4)
+#define RT5616_G_IN1_R_OM_R_SFT                        4
+#define RT5616_G_RM_R_OM_R_MASK                        (0x7 << 1)
+#define RT5616_G_RM_R_OM_R_SFT                 1
+
+/* Output Right Mixer Control 2 (0x51) */
+#define RT5616_G_DAC_R1_OM_R_MASK              (0x7 << 7)
+#define RT5616_G_DAC_R1_OM_R_SFT               7
+#define RT5616_G_IN2_R_OM_R_MASK               (0x7 << 4)
+#define RT5616_G_IN2_R_OM_R_SFT                        4
+
+/* Output Right Mixer Control 3 (0x52) */
+#define RT5616_M_IN2_R_OM_R                    (0x1 << 9)
+#define RT5616_M_IN2_R_OM_R_SFT                        9
+#define RT5616_M_BST2_OM_R                     (0x1 << 6)
+#define RT5616_M_BST2_OM_R_SFT                 6
+#define RT5616_M_BST1_OM_R                     (0x1 << 5)
+#define RT5616_M_BST1_OM_R_SFT                 5
+#define RT5616_M_IN1_R_OM_R                    (0x1 << 4)
+#define RT5616_M_IN1_R_OM_R_SFT                        4
+#define RT5616_M_RM_R_OM_R                     (0x1 << 3)
+#define RT5616_M_RM_R_OM_R_SFT                 3
+#define RT5616_M_DAC_R1_OM_R                   (0x1)
+#define RT5616_M_DAC_R1_OM_R_SFT               0
+
+/* LOUT Mixer Control (0x53) */
+#define RT5616_M_DAC_L1_LM                     (0x1 << 15)
+#define RT5616_M_DAC_L1_LM_SFT                 15
+#define RT5616_M_DAC_R1_LM                     (0x1 << 14)
+#define RT5616_M_DAC_R1_LM_SFT                 14
+#define RT5616_M_OV_L_LM                       (0x1 << 13)
+#define RT5616_M_OV_L_LM_SFT                   13
+#define RT5616_M_OV_R_LM                       (0x1 << 12)
+#define RT5616_M_OV_R_LM_SFT                   12
+#define RT5616_G_LOUTMIX_MASK                  (0x1 << 11)
+#define RT5616_G_LOUTMIX_SFT                   11
+
+/* Power Management for Digital 1 (0x61) */
+#define RT5616_PWR_I2S1                                (0x1 << 15)
+#define RT5616_PWR_I2S1_BIT                    15
+#define RT5616_PWR_I2S2                                (0x1 << 14)
+#define RT5616_PWR_I2S2_BIT                    14
+#define RT5616_PWR_DAC_L1                      (0x1 << 12)
+#define RT5616_PWR_DAC_L1_BIT                  12
+#define RT5616_PWR_DAC_R1                      (0x1 << 11)
+#define RT5616_PWR_DAC_R1_BIT                  11
+#define RT5616_PWR_ADC_L                       (0x1 << 2)
+#define RT5616_PWR_ADC_L_BIT                   2
+#define RT5616_PWR_ADC_R                       (0x1 << 1)
+#define RT5616_PWR_ADC_R_BIT                   1
+
+/* Power Management for Digital 2 (0x62) */
+#define RT5616_PWR_ADC_STO1_F                  (0x1 << 15)
+#define RT5616_PWR_ADC_STO1_F_BIT              15
+#define RT5616_PWR_DAC_STO1_F                  (0x1 << 11)
+#define RT5616_PWR_DAC_STO1_F_BIT              11
+
+/* Power Management for Analog 1 (0x63) */
+#define RT5616_PWR_VREF1                       (0x1 << 15)
+#define RT5616_PWR_VREF1_BIT                   15
+#define RT5616_PWR_FV1                         (0x1 << 14)
+#define RT5616_PWR_FV1_BIT                     14
+#define RT5616_PWR_MB                          (0x1 << 13)
+#define RT5616_PWR_MB_BIT                      13
+#define RT5616_PWR_LM                          (0x1 << 12)
+#define RT5616_PWR_LM_BIT                      12
+#define RT5616_PWR_BG                          (0x1 << 11)
+#define RT5616_PWR_BG_BIT                      11
+#define RT5616_PWR_HP_L                                (0x1 << 7)
+#define RT5616_PWR_HP_L_BIT                    7
+#define RT5616_PWR_HP_R                                (0x1 << 6)
+#define RT5616_PWR_HP_R_BIT                    6
+#define RT5616_PWR_HA                          (0x1 << 5)
+#define RT5616_PWR_HA_BIT                      5
+#define RT5616_PWR_VREF2                       (0x1 << 4)
+#define RT5616_PWR_VREF2_BIT                   4
+#define RT5616_PWR_FV2                         (0x1 << 3)
+#define RT5616_PWR_FV2_BIT                     3
+#define RT5616_PWR_LDO                         (0x1 << 2)
+#define RT5616_PWR_LDO_BIT                     2
+#define RT5616_PWR_LDO_DVO_MASK                        (0x3)
+#define RT5616_PWR_LDO_DVO_1_0V                        0
+#define RT5616_PWR_LDO_DVO_1_1V                        1
+#define RT5616_PWR_LDO_DVO_1_2V                        2
+#define RT5616_PWR_LDO_DVO_1_3V                        3
+
+/* Power Management for Analog 2 (0x64) */
+#define RT5616_PWR_BST1                                (0x1 << 15)
+#define RT5616_PWR_BST1_BIT                    15
+#define RT5616_PWR_BST2                                (0x1 << 14)
+#define RT5616_PWR_BST2_BIT                    14
+#define RT5616_PWR_MB1                         (0x1 << 11)
+#define RT5616_PWR_MB1_BIT                     11
+#define RT5616_PWR_PLL                         (0x1 << 9)
+#define RT5616_PWR_PLL_BIT                     9
+#define RT5616_PWR_BST1_OP2                    (0x1 << 5)
+#define RT5616_PWR_BST1_OP2_BIT                        5
+#define RT5616_PWR_BST2_OP2                    (0x1 << 4)
+#define RT5616_PWR_BST2_OP2_BIT                        4
+#define RT5616_PWR_BST3_OP2                    (0x1 << 3)
+#define RT5616_PWR_BST3_OP2_BIT                        3
+#define RT5616_PWR_JD_M                                (0x1 << 2)
+#define RT5616_PWM_JD_M_BIT                    2
+#define RT5616_PWR_JD2                         (0x1 << 1)
+#define RT5616_PWM_JD2_BIT                     1
+#define RT5616_PWR_JD3                         (0x1)
+#define RT5616_PWM_JD3_BIT                     0
+
+/* Power Management for Mixer (0x65) */
+#define RT5616_PWR_OM_L                                (0x1 << 15)
+#define RT5616_PWR_OM_L_BIT                    15
+#define RT5616_PWR_OM_R                                (0x1 << 14)
+#define RT5616_PWR_OM_R_BIT                    14
+#define RT5616_PWR_RM_L                                (0x1 << 11)
+#define RT5616_PWR_RM_L_BIT                    11
+#define RT5616_PWR_RM_R                                (0x1 << 10)
+#define RT5616_PWR_RM_R_BIT                    10
+
+/* Power Management for Volume (0x66) */
+#define RT5616_PWR_OV_L                                (0x1 << 13)
+#define RT5616_PWR_OV_L_BIT                    13
+#define RT5616_PWR_OV_R                                (0x1 << 12)
+#define RT5616_PWR_OV_R_BIT                    12
+#define RT5616_PWR_HV_L                                (0x1 << 11)
+#define RT5616_PWR_HV_L_BIT                    11
+#define RT5616_PWR_HV_R                                (0x1 << 10)
+#define RT5616_PWR_HV_R_BIT                    10
+#define RT5616_PWR_IN1_L                       (0x1 << 9)
+#define RT5616_PWR_IN1_L_BIT                   9
+#define RT5616_PWR_IN1_R                       (0x1 << 8)
+#define RT5616_PWR_IN1_R_BIT                   8
+#define RT5616_PWR_IN2_L                       (0x1 << 7)
+#define RT5616_PWR_IN2_L_BIT                   7
+#define RT5616_PWR_IN2_R                       (0x1 << 6)
+#define RT5616_PWR_IN2_R_BIT                   6
+
+/* I2S1/2/3 Audio Serial Data Port Control (0x70 0x71) */
+#define RT5616_I2S_MS_MASK                     (0x1 << 15)
+#define RT5616_I2S_MS_SFT                      15
+#define RT5616_I2S_MS_M                                (0x0 << 15)
+#define RT5616_I2S_MS_S                                (0x1 << 15)
+#define RT5616_I2S_O_CP_MASK                   (0x3 << 10)
+#define RT5616_I2S_O_CP_SFT                    10
+#define RT5616_I2S_O_CP_OFF                    (0x0 << 10)
+#define RT5616_I2S_O_CP_U_LAW                  (0x1 << 10)
+#define RT5616_I2S_O_CP_A_LAW                  (0x2 << 10)
+#define RT5616_I2S_I_CP_MASK                   (0x3 << 8)
+#define RT5616_I2S_I_CP_SFT                    8
+#define RT5616_I2S_I_CP_OFF                    (0x0 << 8)
+#define RT5616_I2S_I_CP_U_LAW                  (0x1 << 8)
+#define RT5616_I2S_I_CP_A_LAW                  (0x2 << 8)
+#define RT5616_I2S_BP_MASK                     (0x1 << 7)
+#define RT5616_I2S_BP_SFT                      7
+#define RT5616_I2S_BP_NOR                      (0x0 << 7)
+#define RT5616_I2S_BP_INV                      (0x1 << 7)
+#define RT5616_I2S_DL_MASK                     (0x3 << 2)
+#define RT5616_I2S_DL_SFT                      2
+#define RT5616_I2S_DL_16                       (0x0 << 2)
+#define RT5616_I2S_DL_20                       (0x1 << 2)
+#define RT5616_I2S_DL_24                       (0x2 << 2)
+#define RT5616_I2S_DL_8                                (0x3 << 2)
+#define RT5616_I2S_DF_MASK                     (0x3)
+#define RT5616_I2S_DF_SFT                      0
+#define RT5616_I2S_DF_I2S                      (0x0)
+#define RT5616_I2S_DF_LEFT                     (0x1)
+#define RT5616_I2S_DF_PCM_A                    (0x2)
+#define RT5616_I2S_DF_PCM_B                    (0x3)
+
+/* ADC/DAC Clock Control 1 (0x73) */
+#define RT5616_I2S_PD1_MASK                    (0x7 << 12)
+#define RT5616_I2S_PD1_SFT                     12
+#define RT5616_I2S_PD1_1                       (0x0 << 12)
+#define RT5616_I2S_PD1_2                       (0x1 << 12)
+#define RT5616_I2S_PD1_3                       (0x2 << 12)
+#define RT5616_I2S_PD1_4                       (0x3 << 12)
+#define RT5616_I2S_PD1_6                       (0x4 << 12)
+#define RT5616_I2S_PD1_8                       (0x5 << 12)
+#define RT5616_I2S_PD1_12                      (0x6 << 12)
+#define RT5616_I2S_PD1_16                      (0x7 << 12)
+#define RT5616_I2S_BCLK_MS2_MASK               (0x1 << 11)
+#define RT5616_DAC_OSR_MASK                    (0x3 << 2)
+#define RT5616_DAC_OSR_SFT                     2
+#define RT5616_DAC_OSR_128                     (0x0 << 2)
+#define RT5616_DAC_OSR_64                      (0x1 << 2)
+#define RT5616_DAC_OSR_32                      (0x2 << 2)
+#define RT5616_DAC_OSR_128_3                   (0x3 << 2)
+#define RT5616_ADC_OSR_MASK                    (0x3)
+#define RT5616_ADC_OSR_SFT                     0
+#define RT5616_ADC_OSR_128                     (0x0)
+#define RT5616_ADC_OSR_64                      (0x1)
+#define RT5616_ADC_OSR_32                      (0x2)
+#define RT5616_ADC_OSR_128_3                   (0x3)
+
+/* ADC/DAC Clock Control 2 (0x74) */
+#define RT5616_DAHPF_EN                                (0x1 << 11)
+#define RT5616_DAHPF_EN_SFT                    11
+#define RT5616_ADHPF_EN                                (0x1 << 10)
+#define RT5616_ADHPF_EN_SFT                    10
+
+/* TDM Control 1 (0x77) */
+#define RT5616_TDM_INTEL_SEL_MASK              (0x1 << 15)
+#define RT5616_TDM_INTEL_SEL_SFT               15
+#define RT5616_TDM_INTEL_SEL_64                        (0x0 << 15)
+#define RT5616_TDM_INTEL_SEL_50                        (0x1 << 15)
+#define RT5616_TDM_MODE_SEL_MASK               (0x1 << 14)
+#define RT5616_TDM_MODE_SEL_SFT                        14
+#define RT5616_TDM_MODE_SEL_NOR                        (0x0 << 14)
+#define RT5616_TDM_MODE_SEL_TDM                        (0x1 << 14)
+#define RT5616_TDM_CH_NUM_SEL_MASK             (0x3 << 12)
+#define RT5616_TDM_CH_NUM_SEL_SFT              12
+#define RT5616_TDM_CH_NUM_SEL_2                        (0x0 << 12)
+#define RT5616_TDM_CH_NUM_SEL_4                        (0x1 << 12)
+#define RT5616_TDM_CH_NUM_SEL_6                        (0x2 << 12)
+#define RT5616_TDM_CH_NUM_SEL_8                        (0x3 << 12)
+#define RT5616_TDM_CH_LEN_SEL_MASK             (0x3 << 10)
+#define RT5616_TDM_CH_LEN_SEL_SFT              10
+#define RT5616_TDM_CH_LEN_SEL_16               (0x0 << 10)
+#define RT5616_TDM_CH_LEN_SEL_20               (0x1 << 10)
+#define RT5616_TDM_CH_LEN_SEL_24               (0x2 << 10)
+#define RT5616_TDM_CH_LEN_SEL_32               (0x3 << 10)
+#define RT5616_TDM_ADC_SEL_MASK                        (0x1 << 9)
+#define RT5616_TDM_ADC_SEL_SFT                 9
+#define RT5616_TDM_ADC_SEL_NOR                 (0x0 << 9)
+#define RT5616_TDM_ADC_SEL_SWAP                        (0x1 << 9)
+#define RT5616_TDM_ADC_START_SEL_MASK          (0x1 << 8)
+#define RT5616_TDM_ADC_START_SEL_SFT           8
+#define RT5616_TDM_ADC_START_SEL_SL0           (0x0 << 8)
+#define RT5616_TDM_ADC_START_SEL_SL4           (0x1 << 8)
+#define RT5616_TDM_I2S_CH2_SEL_MASK            (0x3 << 6)
+#define RT5616_TDM_I2S_CH2_SEL_SFT             6
+#define RT5616_TDM_I2S_CH2_SEL_LR              (0x0 << 6)
+#define RT5616_TDM_I2S_CH2_SEL_RL              (0x1 << 6)
+#define RT5616_TDM_I2S_CH2_SEL_LL              (0x2 << 6)
+#define RT5616_TDM_I2S_CH2_SEL_RR              (0x3 << 6)
+#define RT5616_TDM_I2S_CH4_SEL_MASK            (0x3 << 4)
+#define RT5616_TDM_I2S_CH4_SEL_SFT             4
+#define RT5616_TDM_I2S_CH4_SEL_LR              (0x0 << 4)
+#define RT5616_TDM_I2S_CH4_SEL_RL              (0x1 << 4)
+#define RT5616_TDM_I2S_CH4_SEL_LL              (0x2 << 4)
+#define RT5616_TDM_I2S_CH4_SEL_RR              (0x3 << 4)
+#define RT5616_TDM_I2S_CH6_SEL_MASK            (0x3 << 2)
+#define RT5616_TDM_I2S_CH6_SEL_SFT             2
+#define RT5616_TDM_I2S_CH6_SEL_LR              (0x0 << 2)
+#define RT5616_TDM_I2S_CH6_SEL_RL              (0x1 << 2)
+#define RT5616_TDM_I2S_CH6_SEL_LL              (0x2 << 2)
+#define RT5616_TDM_I2S_CH6_SEL_RR              (0x3 << 2)
+#define RT5616_TDM_I2S_CH8_SEL_MASK            (0x3)
+#define RT5616_TDM_I2S_CH8_SEL_SFT             0
+#define RT5616_TDM_I2S_CH8_SEL_LR              (0x0)
+#define RT5616_TDM_I2S_CH8_SEL_RL              (0x1)
+#define RT5616_TDM_I2S_CH8_SEL_LL              (0x2)
+#define RT5616_TDM_I2S_CH8_SEL_RR              (0x3)
+
+/* TDM Control 2 (0x78) */
+#define RT5616_TDM_LRCK_POL_SEL_MASK           (0x1 << 15)
+#define RT5616_TDM_LRCK_POL_SEL_SFT            15
+#define RT5616_TDM_LRCK_POL_SEL_NOR            (0x0 << 15)
+#define RT5616_TDM_LRCK_POL_SEL_INV            (0x1 << 15)
+#define RT5616_TDM_CH_VAL_SEL_MASK             (0x1 << 14)
+#define RT5616_TDM_CH_VAL_SEL_SFT              14
+#define RT5616_TDM_CH_VAL_SEL_CH01             (0x0 << 14)
+#define RT5616_TDM_CH_VAL_SEL_CH0123           (0x1 << 14)
+#define RT5616_TDM_CH_VAL_EN                   (0x1 << 13)
+#define RT5616_TDM_CH_VAL_SFT                  13
+#define RT5616_TDM_LPBK_EN                     (0x1 << 12)
+#define RT5616_TDM_LPBK_SFT                    12
+#define RT5616_TDM_LRCK_PULSE_SEL_MASK         (0x1 << 11)
+#define RT5616_TDM_LRCK_PULSE_SEL_SFT          11
+#define RT5616_TDM_LRCK_PULSE_SEL_BCLK         (0x0 << 11)
+#define RT5616_TDM_LRCK_PULSE_SEL_CH           (0x1 << 11)
+#define RT5616_TDM_END_EDGE_SEL_MASK           (0x1 << 10)
+#define RT5616_TDM_END_EDGE_SEL_SFT            10
+#define RT5616_TDM_END_EDGE_SEL_POS            (0x0 << 10)
+#define RT5616_TDM_END_EDGE_SEL_NEG            (0x1 << 10)
+#define RT5616_TDM_END_EDGE_EN                 (0x1 << 9)
+#define RT5616_TDM_END_EDGE_EN_SFT             9
+#define RT5616_TDM_TRAN_EDGE_SEL_MASK          (0x1 << 8)
+#define RT5616_TDM_TRAN_EDGE_SEL_SFT           8
+#define RT5616_TDM_TRAN_EDGE_SEL_POS           (0x0 << 8)
+#define RT5616_TDM_TRAN_EDGE_SEL_NEG           (0x1 << 8)
+#define RT5616_M_TDM2_L                                (0x1 << 7)
+#define RT5616_M_TDM2_L_SFT                    7
+#define RT5616_M_TDM2_R                                (0x1 << 6)
+#define RT5616_M_TDM2_R_SFT                    6
+#define RT5616_M_TDM4_L                                (0x1 << 5)
+#define RT5616_M_TDM4_L_SFT                    5
+#define RT5616_M_TDM4_R                                (0x1 << 4)
+#define RT5616_M_TDM4_R_SFT                    4
+
+/* Global Clock Control (0x80) */
+#define RT5616_SCLK_SRC_MASK                   (0x3 << 14)
+#define RT5616_SCLK_SRC_SFT                    14
+#define RT5616_SCLK_SRC_MCLK                   (0x0 << 14)
+#define RT5616_SCLK_SRC_PLL1                   (0x1 << 14)
+#define RT5616_PLL1_SRC_MASK                   (0x3 << 12)
+#define RT5616_PLL1_SRC_SFT                    12
+#define RT5616_PLL1_SRC_MCLK                   (0x0 << 12)
+#define RT5616_PLL1_SRC_BCLK1                  (0x1 << 12)
+#define RT5616_PLL1_SRC_BCLK2                  (0x2 << 12)
+#define RT5616_PLL1_PD_MASK                    (0x1 << 3)
+#define RT5616_PLL1_PD_SFT                     3
+#define RT5616_PLL1_PD_1                       (0x0 << 3)
+#define RT5616_PLL1_PD_2                       (0x1 << 3)
+
+#define RT5616_PLL_INP_MAX                     40000000
+#define RT5616_PLL_INP_MIN                     256000
+/* PLL M/N/K Code Control 1 (0x81) */
+#define RT5616_PLL_N_MAX                       0x1ff
+#define RT5616_PLL_N_MASK                      (RT5616_PLL_N_MAX << 7)
+#define RT5616_PLL_N_SFT                       7
+#define RT5616_PLL_K_MAX                       0x1f
+#define RT5616_PLL_K_MASK                      (RT5616_PLL_K_MAX)
+#define RT5616_PLL_K_SFT                       0
+
+/* PLL M/N/K Code Control 2 (0x82) */
+#define RT5616_PLL_M_MAX                       0xf
+#define RT5616_PLL_M_MASK                      (RT5616_PLL_M_MAX << 12)
+#define RT5616_PLL_M_SFT                       12
+#define RT5616_PLL_M_BP                                (0x1 << 11)
+#define RT5616_PLL_M_BP_SFT                    11
+
+/* PLL tracking mode 1 (0x83) */
+#define RT5616_STO1_T_MASK                     (0x1 << 15)
+#define RT5616_STO1_T_SFT                      15
+#define RT5616_STO1_T_SCLK                     (0x0 << 15)
+#define RT5616_STO1_T_LRCK1                    (0x1 << 15)
+#define RT5616_STO2_T_MASK                     (0x1 << 12)
+#define RT5616_STO2_T_SFT                      12
+#define RT5616_STO2_T_I2S2                     (0x0 << 12)
+#define RT5616_STO2_T_LRCK2                    (0x1 << 12)
+#define RT5616_ASRC2_REF_MASK                  (0x1 << 11)
+#define RT5616_ASRC2_REF_SFT                   11
+#define RT5616_ASRC2_REF_LRCK2                 (0x0 << 11)
+#define RT5616_ASRC2_REF_LRCK1                 (0x1 << 11)
+#define RT5616_DMIC_1_M_MASK                   (0x1 << 9)
+#define RT5616_DMIC_1_M_SFT                    9
+#define RT5616_DMIC_1_M_NOR                    (0x0 << 9)
+#define RT5616_DMIC_1_M_ASYN                   (0x1 << 9)
+
+/* PLL tracking mode 2 (0x84) */
+#define RT5616_STO1_ASRC_EN                    (0x1 << 15)
+#define RT5616_STO1_ASRC_EN_SFT                        15
+#define RT5616_STO2_ASRC_EN                    (0x1 << 14)
+#define RT5616_STO2_ASRC_EN_SFT                        14
+#define RT5616_STO1_DAC_M_MASK                 (0x1 << 13)
+#define RT5616_STO1_DAC_M_SFT                  13
+#define RT5616_STO1_DAC_M_NOR                  (0x0 << 13)
+#define RT5616_STO1_DAC_M_ASRC                 (0x1 << 13)
+#define RT5616_STO2_DAC_M_MASK                 (0x1 << 12)
+#define RT5616_STO2_DAC_M_SFT                  12
+#define RT5616_STO2_DAC_M_NOR                  (0x0 << 12)
+#define RT5616_STO2_DAC_M_ASRC                 (0x1 << 12)
+#define RT5616_ADC_M_MASK                      (0x1 << 11)
+#define RT5616_ADC_M_SFT                       11
+#define RT5616_ADC_M_NOR                       (0x0 << 11)
+#define RT5616_ADC_M_ASRC                      (0x1 << 11)
+#define RT5616_I2S1_R_D_MASK                   (0x1 << 4)
+#define RT5616_I2S1_R_D_SFT                    4
+#define RT5616_I2S1_R_D_DIS                    (0x0 << 4)
+#define RT5616_I2S1_R_D_EN                     (0x1 << 4)
+#define RT5616_I2S2_R_D_MASK                   (0x1 << 3)
+#define RT5616_I2S2_R_D_SFT                    3
+#define RT5616_I2S2_R_D_DIS                    (0x0 << 3)
+#define RT5616_I2S2_R_D_EN                     (0x1 << 3)
+#define RT5616_PRE_SCLK_MASK                   (0x3)
+#define RT5616_PRE_SCLK_SFT                    0
+#define RT5616_PRE_SCLK_512                    (0x0)
+#define RT5616_PRE_SCLK_1024                   (0x1)
+#define RT5616_PRE_SCLK_2048                   (0x2)
+
+/* PLL tracking mode 3 (0x85) */
+#define RT5616_I2S1_RATE_MASK                  (0xf << 12)
+#define RT5616_I2S1_RATE_SFT                   12
+#define RT5616_I2S2_RATE_MASK                  (0xf << 8)
+#define RT5616_I2S2_RATE_SFT                   8
+#define RT5616_G_ASRC_LP_MASK                  (0x1 << 3)
+#define RT5616_G_ASRC_LP_SFT                   3
+#define RT5616_ASRC_LP_F_M                     (0x1 << 2)
+#define RT5616_ASRC_LP_F_SFT                   2
+#define RT5616_ASRC_LP_F_NOR                   (0x0 << 2)
+#define RT5616_ASRC_LP_F_SB                    (0x1 << 2)
+#define RT5616_FTK_PH_DET_MASK                 (0x3)
+#define RT5616_FTK_PH_DET_SFT                  0
+#define RT5616_FTK_PH_DET_DIV1                 (0x0)
+#define RT5616_FTK_PH_DET_DIV2                 (0x1)
+#define RT5616_FTK_PH_DET_DIV4                 (0x2)
+#define RT5616_FTK_PH_DET_DIV8                 (0x3)
+
+/*PLL tracking mode 6 (0x89) */
+#define RT5616_I2S1_PD_MASK                    (0x7 << 12)
+#define RT5616_I2S1_PD_SFT                     12
+#define RT5616_I2S2_PD_MASK                    (0x7 << 8)
+#define RT5616_I2S2_PD_SFT                     8
+
+/*PLL tracking mode 7 (0x8a) */
+#define RT5616_FSI1_RATE_MASK                  (0xf << 12)
+#define RT5616_FSI1_RATE_SFT                   12
+#define RT5616_FSI2_RATE_MASK                  (0xf << 8)
+#define RT5616_FSI2_RATE_SFT                   8
+
+/* HPOUT Over Current Detection (0x8b) */
+#define RT5616_HP_OVCD_MASK                    (0x1 << 10)
+#define RT5616_HP_OVCD_SFT                     10
+#define RT5616_HP_OVCD_DIS                     (0x0 << 10)
+#define RT5616_HP_OVCD_EN                      (0x1 << 10)
+#define RT5616_HP_OC_TH_MASK                   (0x3 << 8)
+#define RT5616_HP_OC_TH_SFT                    8
+#define RT5616_HP_OC_TH_90                     (0x0 << 8)
+#define RT5616_HP_OC_TH_105                    (0x1 << 8)
+#define RT5616_HP_OC_TH_120                    (0x2 << 8)
+#define RT5616_HP_OC_TH_135                    (0x3 << 8)
+
+/* Depop Mode Control 1 (0x8e) */
+#define RT5616_SMT_TRIG_MASK                   (0x1 << 15)
+#define RT5616_SMT_TRIG_SFT                    15
+#define RT5616_SMT_TRIG_DIS                    (0x0 << 15)
+#define RT5616_SMT_TRIG_EN                     (0x1 << 15)
+#define RT5616_HP_L_SMT_MASK                   (0x1 << 9)
+#define RT5616_HP_L_SMT_SFT                    9
+#define RT5616_HP_L_SMT_DIS                    (0x0 << 9)
+#define RT5616_HP_L_SMT_EN                     (0x1 << 9)
+#define RT5616_HP_R_SMT_MASK                   (0x1 << 8)
+#define RT5616_HP_R_SMT_SFT                    8
+#define RT5616_HP_R_SMT_DIS                    (0x0 << 8)
+#define RT5616_HP_R_SMT_EN                     (0x1 << 8)
+#define RT5616_HP_CD_PD_MASK                   (0x1 << 7)
+#define RT5616_HP_CD_PD_SFT                    7
+#define RT5616_HP_CD_PD_DIS                    (0x0 << 7)
+#define RT5616_HP_CD_PD_EN                     (0x1 << 7)
+#define RT5616_RSTN_MASK                       (0x1 << 6)
+#define RT5616_RSTN_SFT                                6
+#define RT5616_RSTN_DIS                                (0x0 << 6)
+#define RT5616_RSTN_EN                         (0x1 << 6)
+#define RT5616_RSTP_MASK                       (0x1 << 5)
+#define RT5616_RSTP_SFT                                5
+#define RT5616_RSTP_DIS                                (0x0 << 5)
+#define RT5616_RSTP_EN                         (0x1 << 5)
+#define RT5616_HP_CO_MASK                      (0x1 << 4)
+#define RT5616_HP_CO_SFT                       4
+#define RT5616_HP_CO_DIS                       (0x0 << 4)
+#define RT5616_HP_CO_EN                                (0x1 << 4)
+#define RT5616_HP_CP_MASK                      (0x1 << 3)
+#define RT5616_HP_CP_SFT                       3
+#define RT5616_HP_CP_PD                                (0x0 << 3)
+#define RT5616_HP_CP_PU                                (0x1 << 3)
+#define RT5616_HP_SG_MASK                      (0x1 << 2)
+#define RT5616_HP_SG_SFT                       2
+#define RT5616_HP_SG_DIS                       (0x0 << 2)
+#define RT5616_HP_SG_EN                                (0x1 << 2)
+#define RT5616_HP_DP_MASK                      (0x1 << 1)
+#define RT5616_HP_DP_SFT                       1
+#define RT5616_HP_DP_PD                                (0x0 << 1)
+#define RT5616_HP_DP_PU                                (0x1 << 1)
+#define RT5616_HP_CB_MASK                      (0x1)
+#define RT5616_HP_CB_SFT                       0
+#define RT5616_HP_CB_PD                                (0x0)
+#define RT5616_HP_CB_PU                                (0x1)
+
+/* Depop Mode Control 2 (0x8f) */
+#define RT5616_DEPOP_MASK                      (0x1 << 13)
+#define RT5616_DEPOP_SFT                       13
+#define RT5616_DEPOP_AUTO                      (0x0 << 13)
+#define RT5616_DEPOP_MAN                       (0x1 << 13)
+#define RT5616_RAMP_MASK                       (0x1 << 12)
+#define RT5616_RAMP_SFT                                12
+#define RT5616_RAMP_DIS                                (0x0 << 12)
+#define RT5616_RAMP_EN                         (0x1 << 12)
+#define RT5616_BPS_MASK                                (0x1 << 11)
+#define RT5616_BPS_SFT                         11
+#define RT5616_BPS_DIS                         (0x0 << 11)
+#define RT5616_BPS_EN                          (0x1 << 11)
+#define RT5616_FAST_UPDN_MASK                  (0x1 << 10)
+#define RT5616_FAST_UPDN_SFT                   10
+#define RT5616_FAST_UPDN_DIS                   (0x0 << 10)
+#define RT5616_FAST_UPDN_EN                    (0x1 << 10)
+#define RT5616_MRES_MASK                       (0x3 << 8)
+#define RT5616_MRES_SFT                                8
+#define RT5616_MRES_15MO                       (0x0 << 8)
+#define RT5616_MRES_25MO                       (0x1 << 8)
+#define RT5616_MRES_35MO                       (0x2 << 8)
+#define RT5616_MRES_45MO                       (0x3 << 8)
+#define RT5616_VLO_MASK                                (0x1 << 7)
+#define RT5616_VLO_SFT                         7
+#define RT5616_VLO_3V                          (0x0 << 7)
+#define RT5616_VLO_32V                         (0x1 << 7)
+#define RT5616_DIG_DP_MASK                     (0x1 << 6)
+#define RT5616_DIG_DP_SFT                      6
+#define RT5616_DIG_DP_DIS                      (0x0 << 6)
+#define RT5616_DIG_DP_EN                       (0x1 << 6)
+#define RT5616_DP_TH_MASK                      (0x3 << 4)
+#define RT5616_DP_TH_SFT                       4
+
+/* Depop Mode Control 3 (0x90) */
+#define RT5616_CP_SYS_MASK                     (0x7 << 12)
+#define RT5616_CP_SYS_SFT                      12
+#define RT5616_CP_FQ1_MASK                     (0x7 << 8)
+#define RT5616_CP_FQ1_SFT                      8
+#define RT5616_CP_FQ2_MASK                     (0x7 << 4)
+#define RT5616_CP_FQ2_SFT                      4
+#define RT5616_CP_FQ3_MASK                     (0x7)
+#define RT5616_CP_FQ3_SFT                      0
+#define RT5616_CP_FQ_1_5_KHZ                   0
+#define RT5616_CP_FQ_3_KHZ                     1
+#define RT5616_CP_FQ_6_KHZ                     2
+#define RT5616_CP_FQ_12_KHZ                    3
+#define RT5616_CP_FQ_24_KHZ                    4
+#define RT5616_CP_FQ_48_KHZ                    5
+#define RT5616_CP_FQ_96_KHZ                    6
+#define RT5616_CP_FQ_192_KHZ                   7
+
+/* HPOUT charge pump (0x91) */
+#define RT5616_OSW_L_MASK                      (0x1 << 11)
+#define RT5616_OSW_L_SFT                       11
+#define RT5616_OSW_L_DIS                       (0x0 << 11)
+#define RT5616_OSW_L_EN                                (0x1 << 11)
+#define RT5616_OSW_R_MASK                      (0x1 << 10)
+#define RT5616_OSW_R_SFT                       10
+#define RT5616_OSW_R_DIS                       (0x0 << 10)
+#define RT5616_OSW_R_EN                                (0x1 << 10)
+#define RT5616_PM_HP_MASK                      (0x3 << 8)
+#define RT5616_PM_HP_SFT                       8
+#define RT5616_PM_HP_LV                                (0x0 << 8)
+#define RT5616_PM_HP_MV                                (0x1 << 8)
+#define RT5616_PM_HP_HV                                (0x2 << 8)
+#define RT5616_IB_HP_MASK                      (0x3 << 6)
+#define RT5616_IB_HP_SFT                       6
+#define RT5616_IB_HP_125IL                     (0x0 << 6)
+#define RT5616_IB_HP_25IL                      (0x1 << 6)
+#define RT5616_IB_HP_5IL                       (0x2 << 6)
+#define RT5616_IB_HP_1IL                       (0x3 << 6)
+
+/* Micbias Control (0x93) */
+#define RT5616_MIC1_BS_MASK                    (0x1 << 15)
+#define RT5616_MIC1_BS_SFT                     15
+#define RT5616_MIC1_BS_9AV                     (0x0 << 15)
+#define RT5616_MIC1_BS_75AV                    (0x1 << 15)
+#define RT5616_MIC1_CLK_MASK                   (0x1 << 13)
+#define RT5616_MIC1_CLK_SFT                    13
+#define RT5616_MIC1_CLK_DIS                    (0x0 << 13)
+#define RT5616_MIC1_CLK_EN                     (0x1 << 13)
+#define RT5616_MIC1_OVCD_MASK                  (0x1 << 11)
+#define RT5616_MIC1_OVCD_SFT                   11
+#define RT5616_MIC1_OVCD_DIS                   (0x0 << 11)
+#define RT5616_MIC1_OVCD_EN                    (0x1 << 11)
+#define RT5616_MIC1_OVTH_MASK                  (0x3 << 9)
+#define RT5616_MIC1_OVTH_SFT                   9
+#define RT5616_MIC1_OVTH_600UA                 (0x0 << 9)
+#define RT5616_MIC1_OVTH_1500UA                        (0x1 << 9)
+#define RT5616_MIC1_OVTH_2000UA                        (0x2 << 9)
+#define RT5616_PWR_MB_MASK                     (0x1 << 5)
+#define RT5616_PWR_MB_SFT                      5
+#define RT5616_PWR_MB_PD                       (0x0 << 5)
+#define RT5616_PWR_MB_PU                       (0x1 << 5)
+#define RT5616_PWR_CLK12M_MASK                 (0x1 << 4)
+#define RT5616_PWR_CLK12M_SFT                  4
+#define RT5616_PWR_CLK12M_PD                   (0x0 << 4)
+#define RT5616_PWR_CLK12M_PU                   (0x1 << 4)
+
+/* Analog JD Control 1 (0x94) */
+#define RT5616_JD2_CMP_MASK                    (0x7 << 12)
+#define RT5616_JD2_CMP_SFT                     12
+#define RT5616_JD_PU                           (0x1 << 11)
+#define RT5616_JD_PU_SFT                       11
+#define RT5616_JD_PD                           (0x1 << 10)
+#define RT5616_JD_PD_SFT                       10
+#define RT5616_JD_MODE_SEL_MASK                        (0x3 << 8)
+#define RT5616_JD_MODE_SEL_SFT                 8
+#define RT5616_JD_MODE_SEL_M0                  (0x0 << 8)
+#define RT5616_JD_MODE_SEL_M1                  (0x1 << 8)
+#define RT5616_JD_MODE_SEL_M2                  (0x2 << 8)
+#define RT5616_JD_M_CMP                                (0x7 << 4)
+#define RT5616_JD_M_CMP_SFT                    4
+#define RT5616_JD_M_PU                         (0x1 << 3)
+#define RT5616_JD_M_PU_SFT                     3
+#define RT5616_JD_M_PD                         (0x1 << 2)
+#define RT5616_JD_M_PD_SFT                     2
+#define RT5616_JD_M_MODE_SEL_MASK              (0x3)
+#define RT5616_JD_M_MODE_SEL_SFT               0
+#define RT5616_JD_M_MODE_SEL_M0                        (0x0)
+#define RT5616_JD_M_MODE_SEL_M1                        (0x1)
+#define RT5616_JD_M_MODE_SEL_M2                        (0x2)
+
+/* Analog JD Control 2 (0x95) */
+#define RT5616_JD3_CMP_MASK                    (0x7 << 12)
+#define RT5616_JD3_CMP_SFT                     12
+
+/* EQ Control 1 (0xb0) */
+#define RT5616_EQ_SRC_MASK                     (0x1 << 15)
+#define RT5616_EQ_SRC_SFT                      15
+#define RT5616_EQ_SRC_DAC                      (0x0 << 15)
+#define RT5616_EQ_SRC_ADC                      (0x1 << 15)
+#define RT5616_EQ_UPD                          (0x1 << 14)
+#define RT5616_EQ_UPD_BIT                      14
+#define RT5616_EQ_CD_MASK                      (0x1 << 13)
+#define RT5616_EQ_CD_SFT                       13
+#define RT5616_EQ_CD_DIS                       (0x0 << 13)
+#define RT5616_EQ_CD_EN                                (0x1 << 13)
+#define RT5616_EQ_DITH_MASK                    (0x3 << 8)
+#define RT5616_EQ_DITH_SFT                     8
+#define RT5616_EQ_DITH_NOR                     (0x0 << 8)
+#define RT5616_EQ_DITH_LSB                     (0x1 << 8)
+#define RT5616_EQ_DITH_LSB_1                   (0x2 << 8)
+#define RT5616_EQ_DITH_LSB_2                   (0x3 << 8)
+#define RT5616_EQ_CD_F                         (0x1 << 7)
+#define RT5616_EQ_CD_F_BIT                     7
+#define RT5616_EQ_STA_HP2                      (0x1 << 6)
+#define RT5616_EQ_STA_HP2_BIT                  6
+#define RT5616_EQ_STA_HP1                      (0x1 << 5)
+#define RT5616_EQ_STA_HP1_BIT                  5
+#define RT5616_EQ_STA_BP4                      (0x1 << 4)
+#define RT5616_EQ_STA_BP4_BIT                  4
+#define RT5616_EQ_STA_BP3                      (0x1 << 3)
+#define RT5616_EQ_STA_BP3_BIT                  3
+#define RT5616_EQ_STA_BP2                      (0x1 << 2)
+#define RT5616_EQ_STA_BP2_BIT                  2
+#define RT5616_EQ_STA_BP1                      (0x1 << 1)
+#define RT5616_EQ_STA_BP1_BIT                  1
+#define RT5616_EQ_STA_LP                       (0x1)
+#define RT5616_EQ_STA_LP_BIT                   0
+
+/* EQ Control 2 (0xb1) */
+#define RT5616_EQ_HPF1_M_MASK                  (0x1 << 8)
+#define RT5616_EQ_HPF1_M_SFT                   8
+#define RT5616_EQ_HPF1_M_HI                    (0x0 << 8)
+#define RT5616_EQ_HPF1_M_1ST                   (0x1 << 8)
+#define RT5616_EQ_LPF1_M_MASK                  (0x1 << 7)
+#define RT5616_EQ_LPF1_M_SFT                   7
+#define RT5616_EQ_LPF1_M_LO                    (0x0 << 7)
+#define RT5616_EQ_LPF1_M_1ST                   (0x1 << 7)
+#define RT5616_EQ_HPF2_MASK                    (0x1 << 6)
+#define RT5616_EQ_HPF2_SFT                     6
+#define RT5616_EQ_HPF2_DIS                     (0x0 << 6)
+#define RT5616_EQ_HPF2_EN                      (0x1 << 6)
+#define RT5616_EQ_HPF1_MASK                    (0x1 << 5)
+#define RT5616_EQ_HPF1_SFT                     5
+#define RT5616_EQ_HPF1_DIS                     (0x0 << 5)
+#define RT5616_EQ_HPF1_EN                      (0x1 << 5)
+#define RT5616_EQ_BPF4_MASK                    (0x1 << 4)
+#define RT5616_EQ_BPF4_SFT                     4
+#define RT5616_EQ_BPF4_DIS                     (0x0 << 4)
+#define RT5616_EQ_BPF4_EN                      (0x1 << 4)
+#define RT5616_EQ_BPF3_MASK                    (0x1 << 3)
+#define RT5616_EQ_BPF3_SFT                     3
+#define RT5616_EQ_BPF3_DIS                     (0x0 << 3)
+#define RT5616_EQ_BPF3_EN                      (0x1 << 3)
+#define RT5616_EQ_BPF2_MASK                    (0x1 << 2)
+#define RT5616_EQ_BPF2_SFT                     2
+#define RT5616_EQ_BPF2_DIS                     (0x0 << 2)
+#define RT5616_EQ_BPF2_EN                      (0x1 << 2)
+#define RT5616_EQ_BPF1_MASK                    (0x1 << 1)
+#define RT5616_EQ_BPF1_SFT                     1
+#define RT5616_EQ_BPF1_DIS                     (0x0 << 1)
+#define RT5616_EQ_BPF1_EN                      (0x1 << 1)
+#define RT5616_EQ_LPF_MASK                     (0x1)
+#define RT5616_EQ_LPF_SFT                      0
+#define RT5616_EQ_LPF_DIS                      (0x0)
+#define RT5616_EQ_LPF_EN                       (0x1)
+#define RT5616_EQ_CTRL_MASK                    (0x7f)
+
+/* Memory Test (0xb2) */
+#define RT5616_MT_MASK                         (0x1 << 15)
+#define RT5616_MT_SFT                          15
+#define RT5616_MT_DIS                          (0x0 << 15)
+#define RT5616_MT_EN                           (0x1 << 15)
+
+/* DRC/AGC Control 1 (0xb4) */
+#define RT5616_DRC_AGC_P_MASK                  (0x1 << 15)
+#define RT5616_DRC_AGC_P_SFT                   15
+#define RT5616_DRC_AGC_P_DAC                   (0x0 << 15)
+#define RT5616_DRC_AGC_P_ADC                   (0x1 << 15)
+#define RT5616_DRC_AGC_MASK                    (0x1 << 14)
+#define RT5616_DRC_AGC_SFT                     14
+#define RT5616_DRC_AGC_DIS                     (0x0 << 14)
+#define RT5616_DRC_AGC_EN                      (0x1 << 14)
+#define RT5616_DRC_AGC_UPD                     (0x1 << 13)
+#define RT5616_DRC_AGC_UPD_BIT                 13
+#define RT5616_DRC_AGC_AR_MASK                 (0x1f << 8)
+#define RT5616_DRC_AGC_AR_SFT                  8
+#define RT5616_DRC_AGC_R_MASK                  (0x7 << 5)
+#define RT5616_DRC_AGC_R_SFT                   5
+#define RT5616_DRC_AGC_R_48K                   (0x1 << 5)
+#define RT5616_DRC_AGC_R_96K                   (0x2 << 5)
+#define RT5616_DRC_AGC_R_192K                  (0x3 << 5)
+#define RT5616_DRC_AGC_R_441K                  (0x5 << 5)
+#define RT5616_DRC_AGC_R_882K                  (0x6 << 5)
+#define RT5616_DRC_AGC_R_1764K                 (0x7 << 5)
+#define RT5616_DRC_AGC_RC_MASK                 (0x1f)
+#define RT5616_DRC_AGC_RC_SFT                  0
+
+/* DRC/AGC Control 2 (0xb5) */
+#define RT5616_DRC_AGC_POB_MASK                        (0x3f << 8)
+#define RT5616_DRC_AGC_POB_SFT                 8
+#define RT5616_DRC_AGC_CP_MASK                 (0x1 << 7)
+#define RT5616_DRC_AGC_CP_SFT                  7
+#define RT5616_DRC_AGC_CP_DIS                  (0x0 << 7)
+#define RT5616_DRC_AGC_CP_EN                   (0x1 << 7)
+#define RT5616_DRC_AGC_CPR_MASK                        (0x3 << 5)
+#define RT5616_DRC_AGC_CPR_SFT                 5
+#define RT5616_DRC_AGC_CPR_1_1                 (0x0 << 5)
+#define RT5616_DRC_AGC_CPR_1_2                 (0x1 << 5)
+#define RT5616_DRC_AGC_CPR_1_3                 (0x2 << 5)
+#define RT5616_DRC_AGC_CPR_1_4                 (0x3 << 5)
+#define RT5616_DRC_AGC_PRB_MASK                        (0x1f)
+#define RT5616_DRC_AGC_PRB_SFT                 0
+
+/* DRC/AGC Control 3 (0xb6) */
+#define RT5616_DRC_AGC_NGB_MASK                        (0xf << 12)
+#define RT5616_DRC_AGC_NGB_SFT                 12
+#define RT5616_DRC_AGC_TAR_MASK                        (0x1f << 7)
+#define RT5616_DRC_AGC_TAR_SFT                 7
+#define RT5616_DRC_AGC_NG_MASK                 (0x1 << 6)
+#define RT5616_DRC_AGC_NG_SFT                  6
+#define RT5616_DRC_AGC_NG_DIS                  (0x0 << 6)
+#define RT5616_DRC_AGC_NG_EN                   (0x1 << 6)
+#define RT5616_DRC_AGC_NGH_MASK                        (0x1 << 5)
+#define RT5616_DRC_AGC_NGH_SFT                 5
+#define RT5616_DRC_AGC_NGH_DIS                 (0x0 << 5)
+#define RT5616_DRC_AGC_NGH_EN                  (0x1 << 5)
+#define RT5616_DRC_AGC_NGT_MASK                        (0x1f)
+#define RT5616_DRC_AGC_NGT_SFT                 0
+
+/* Jack Detect Control 1 (0xbb) */
+#define RT5616_JD_MASK                         (0x7 << 13)
+#define RT5616_JD_SFT                          13
+#define RT5616_JD_DIS                          (0x0 << 13)
+#define RT5616_JD_GPIO1                                (0x1 << 13)
+#define RT5616_JD_GPIO2                                (0x2 << 13)
+#define RT5616_JD_GPIO3                                (0x3 << 13)
+#define RT5616_JD_GPIO4                                (0x4 << 13)
+#define RT5616_JD_GPIO5                                (0x5 << 13)
+#define RT5616_JD_GPIO6                                (0x6 << 13)
+#define RT5616_JD_HP_MASK                      (0x1 << 11)
+#define RT5616_JD_HP_SFT                       11
+#define RT5616_JD_HP_DIS                       (0x0 << 11)
+#define RT5616_JD_HP_EN                                (0x1 << 11)
+#define RT5616_JD_HP_TRG_MASK                  (0x1 << 10)
+#define RT5616_JD_HP_TRG_SFT                   10
+#define RT5616_JD_HP_TRG_LO                    (0x0 << 10)
+#define RT5616_JD_HP_TRG_HI                    (0x1 << 10)
+#define RT5616_JD_SPL_MASK                     (0x1 << 9)
+#define RT5616_JD_SPL_SFT                      9
+#define RT5616_JD_SPL_DIS                      (0x0 << 9)
+#define RT5616_JD_SPL_EN                       (0x1 << 9)
+#define RT5616_JD_SPL_TRG_MASK                 (0x1 << 8)
+#define RT5616_JD_SPL_TRG_SFT                  8
+#define RT5616_JD_SPL_TRG_LO                   (0x0 << 8)
+#define RT5616_JD_SPL_TRG_HI                   (0x1 << 8)
+#define RT5616_JD_SPR_MASK                     (0x1 << 7)
+#define RT5616_JD_SPR_SFT                      7
+#define RT5616_JD_SPR_DIS                      (0x0 << 7)
+#define RT5616_JD_SPR_EN                       (0x1 << 7)
+#define RT5616_JD_SPR_TRG_MASK                 (0x1 << 6)
+#define RT5616_JD_SPR_TRG_SFT                  6
+#define RT5616_JD_SPR_TRG_LO                   (0x0 << 6)
+#define RT5616_JD_SPR_TRG_HI                   (0x1 << 6)
+#define RT5616_JD_LO_MASK                      (0x1 << 3)
+#define RT5616_JD_LO_SFT                       3
+#define RT5616_JD_LO_DIS                       (0x0 << 3)
+#define RT5616_JD_LO_EN                                (0x1 << 3)
+#define RT5616_JD_LO_TRG_MASK                  (0x1 << 2)
+#define RT5616_JD_LO_TRG_SFT                   2
+#define RT5616_JD_LO_TRG_LO                    (0x0 << 2)
+#define RT5616_JD_LO_TRG_HI                    (0x1 << 2)
+
+/* Jack Detect Control 2 (0xbc) */
+#define RT5616_JD_TRG_SEL_MASK                 (0x7 << 9)
+#define RT5616_JD_TRG_SEL_SFT                  9
+#define RT5616_JD_TRG_SEL_GPIO                 (0x0 << 9)
+#define RT5616_JD_TRG_SEL_JD1_1                        (0x1 << 9)
+#define RT5616_JD_TRG_SEL_JD1_2                        (0x2 << 9)
+#define RT5616_JD_TRG_SEL_JD2                  (0x3 << 9)
+#define RT5616_JD_TRG_SEL_JD3                  (0x4 << 9)
+#define RT5616_JD3_IRQ_EN                      (0x1 << 8)
+#define RT5616_JD3_IRQ_EN_SFT                  8
+#define RT5616_JD3_EN_STKY                     (0x1 << 7)
+#define RT5616_JD3_EN_STKY_SFT                 7
+#define RT5616_JD3_INV                         (0x1 << 6)
+#define RT5616_JD3_INV_SFT                     6
+
+/* IRQ Control 1 (0xbd) */
+#define RT5616_IRQ_JD_MASK                     (0x1 << 15)
+#define RT5616_IRQ_JD_SFT                      15
+#define RT5616_IRQ_JD_BP                       (0x0 << 15)
+#define RT5616_IRQ_JD_NOR                      (0x1 << 15)
+#define RT5616_JD_STKY_MASK                    (0x1 << 13)
+#define RT5616_JD_STKY_SFT                     13
+#define RT5616_JD_STKY_DIS                     (0x0 << 13)
+#define RT5616_JD_STKY_EN                      (0x1 << 13)
+#define RT5616_JD_P_MASK                       (0x1 << 11)
+#define RT5616_JD_P_SFT                                11
+#define RT5616_JD_P_NOR                                (0x0 << 11)
+#define RT5616_JD_P_INV                                (0x1 << 11)
+#define RT5616_JD1_1_IRQ_EN                    (0x1 << 9)
+#define RT5616_JD1_1_IRQ_EN_SFT                        9
+#define RT5616_JD1_1_EN_STKY                   (0x1 << 8)
+#define RT5616_JD1_1_EN_STKY_SFT                       8
+#define RT5616_JD1_1_INV                       (0x1 << 7)
+#define RT5616_JD1_1_INV_SFT                   7
+#define RT5616_JD1_2_IRQ_EN                    (0x1 << 6)
+#define RT5616_JD1_2_IRQ_EN_SFT                        6
+#define RT5616_JD1_2_EN_STKY                   (0x1 << 5)
+#define RT5616_JD1_2_EN_STKY_SFT                       5
+#define RT5616_JD1_2_INV                       (0x1 << 4)
+#define RT5616_JD1_2_INV_SFT                   4
+#define RT5616_JD2_IRQ_EN                      (0x1 << 3)
+#define RT5616_JD2_IRQ_EN_SFT                  3
+#define RT5616_JD2_EN_STKY                     (0x1 << 2)
+#define RT5616_JD2_EN_STKY_SFT                 2
+#define RT5616_JD2_INV                         (0x1 << 1)
+#define RT5616_JD2_INV_SFT                     1
+
+/* IRQ Control 2 (0xbe) */
+#define RT5616_IRQ_MB1_OC_MASK                 (0x1 << 15)
+#define RT5616_IRQ_MB1_OC_SFT                  15
+#define RT5616_IRQ_MB1_OC_BP                   (0x0 << 15)
+#define RT5616_IRQ_MB1_OC_NOR                  (0x1 << 15)
+#define RT5616_MB1_OC_STKY_MASK                        (0x1 << 11)
+#define RT5616_MB1_OC_STKY_SFT                 11
+#define RT5616_MB1_OC_STKY_DIS                 (0x0 << 11)
+#define RT5616_MB1_OC_STKY_EN                  (0x1 << 11)
+#define RT5616_MB1_OC_P_MASK                   (0x1 << 7)
+#define RT5616_MB1_OC_P_SFT                    7
+#define RT5616_MB1_OC_P_NOR                    (0x0 << 7)
+#define RT5616_MB1_OC_P_INV                    (0x1 << 7)
+#define RT5616_MB2_OC_P_MASK                   (0x1 << 6)
+#define RT5616_MB1_OC_CLR                      (0x1 << 3)
+#define RT5616_MB1_OC_CLR_SFT                  3
+#define RT5616_STA_GPIO8                       (0x1)
+#define RT5616_STA_GPIO8_BIT                   0
+
+/* Internal Status and GPIO status (0xbf) */
+#define RT5616_STA_JD3                         (0x1 << 15)
+#define RT5616_STA_JD3_BIT                     15
+#define RT5616_STA_JD2                         (0x1 << 14)
+#define RT5616_STA_JD2_BIT                     14
+#define RT5616_STA_JD1_2                       (0x1 << 13)
+#define RT5616_STA_JD1_2_BIT                   13
+#define RT5616_STA_JD1_1                       (0x1 << 12)
+#define RT5616_STA_JD1_1_BIT                   12
+#define RT5616_STA_GP7                         (0x1 << 11)
+#define RT5616_STA_GP7_BIT                     11
+#define RT5616_STA_GP6                         (0x1 << 10)
+#define RT5616_STA_GP6_BIT                     10
+#define RT5616_STA_GP5                         (0x1 << 9)
+#define RT5616_STA_GP5_BIT                     9
+#define RT5616_STA_GP1                         (0x1 << 8)
+#define RT5616_STA_GP1_BIT                     8
+#define RT5616_STA_GP2                         (0x1 << 7)
+#define RT5616_STA_GP2_BIT                     7
+#define RT5616_STA_GP3                         (0x1 << 6)
+#define RT5616_STA_GP3_BIT                     6
+#define RT5616_STA_GP4                         (0x1 << 5)
+#define RT5616_STA_GP4_BIT                     5
+#define RT5616_STA_GP_JD                       (0x1 << 4)
+#define RT5616_STA_GP_JD_BIT                   4
+
+/* GPIO Control 1 (0xc0) */
+#define RT5616_GP1_PIN_MASK                    (0x1 << 15)
+#define RT5616_GP1_PIN_SFT                     15
+#define RT5616_GP1_PIN_GPIO1                   (0x0 << 15)
+#define RT5616_GP1_PIN_IRQ                     (0x1 << 15)
+#define RT5616_GP2_PIN_MASK                    (0x1 << 14)
+#define RT5616_GP2_PIN_SFT                     14
+#define RT5616_GP2_PIN_GPIO2                   (0x0 << 14)
+#define RT5616_GP2_PIN_DMIC1_SCL               (0x1 << 14)
+#define RT5616_GPIO_M_MASK                     (0x1 << 9)
+#define RT5616_GPIO_M_SFT                      9
+#define RT5616_GPIO_M_FLT                      (0x0 << 9)
+#define RT5616_GPIO_M_PH                       (0x1 << 9)
+#define RT5616_I2S2_SEL_MASK                   (0x1 << 8)
+#define RT5616_I2S2_SEL_SFT                    8
+#define RT5616_I2S2_SEL_I2S                    (0x0 << 8)
+#define RT5616_I2S2_SEL_GPIO                   (0x1 << 8)
+#define RT5616_GP5_PIN_MASK                    (0x1 << 7)
+#define RT5616_GP5_PIN_SFT                     7
+#define RT5616_GP5_PIN_GPIO5                   (0x0 << 7)
+#define RT5616_GP5_PIN_IRQ                     (0x1 << 7)
+#define RT5616_GP6_PIN_MASK                    (0x1 << 6)
+#define RT5616_GP6_PIN_SFT                     6
+#define RT5616_GP6_PIN_GPIO6                   (0x0 << 6)
+#define RT5616_GP6_PIN_DMIC_SDA                        (0x1 << 6)
+#define RT5616_GP7_PIN_MASK                    (0x1 << 5)
+#define RT5616_GP7_PIN_SFT                     5
+#define RT5616_GP7_PIN_GPIO7                   (0x0 << 5)
+#define RT5616_GP7_PIN_IRQ                     (0x1 << 5)
+#define RT5616_GP8_PIN_MASK                    (0x1 << 4)
+#define RT5616_GP8_PIN_SFT                     4
+#define RT5616_GP8_PIN_GPIO8                   (0x0 << 4)
+#define RT5616_GP8_PIN_DMIC_SDA                        (0x1 << 4)
+#define RT5616_GPIO_PDM_SEL_MASK               (0x1 << 3)
+#define RT5616_GPIO_PDM_SEL_SFT                        3
+#define RT5616_GPIO_PDM_SEL_GPIO               (0x0 << 3)
+#define RT5616_GPIO_PDM_SEL_PDM                        (0x1 << 3)
+
+/* GPIO Control 2 (0xc1) */
+#define RT5616_GP5_DR_MASK                     (0x1 << 14)
+#define RT5616_GP5_DR_SFT                      14
+#define RT5616_GP5_DR_IN                       (0x0 << 14)
+#define RT5616_GP5_DR_OUT                      (0x1 << 14)
+#define RT5616_GP5_OUT_MASK                    (0x1 << 13)
+#define RT5616_GP5_OUT_SFT                     13
+#define RT5616_GP5_OUT_LO                      (0x0 << 13)
+#define RT5616_GP5_OUT_HI                      (0x1 << 13)
+#define RT5616_GP5_P_MASK                      (0x1 << 12)
+#define RT5616_GP5_P_SFT                       12
+#define RT5616_GP5_P_NOR                       (0x0 << 12)
+#define RT5616_GP5_P_INV                       (0x1 << 12)
+#define RT5616_GP4_DR_MASK                     (0x1 << 11)
+#define RT5616_GP4_DR_SFT                      11
+#define RT5616_GP4_DR_IN                       (0x0 << 11)
+#define RT5616_GP4_DR_OUT                      (0x1 << 11)
+#define RT5616_GP4_OUT_MASK                    (0x1 << 10)
+#define RT5616_GP4_OUT_SFT                     10
+#define RT5616_GP4_OUT_LO                      (0x0 << 10)
+#define RT5616_GP4_OUT_HI                      (0x1 << 10)
+#define RT5616_GP4_P_MASK                      (0x1 << 9)
+#define RT5616_GP4_P_SFT                       9
+#define RT5616_GP4_P_NOR                       (0x0 << 9)
+#define RT5616_GP4_P_INV                       (0x1 << 9)
+#define RT5616_GP3_DR_MASK                     (0x1 << 8)
+#define RT5616_GP3_DR_SFT                      8
+#define RT5616_GP3_DR_IN                       (0x0 << 8)
+#define RT5616_GP3_DR_OUT                      (0x1 << 8)
+#define RT5616_GP3_OUT_MASK                    (0x1 << 7)
+#define RT5616_GP3_OUT_SFT                     7
+#define RT5616_GP3_OUT_LO                      (0x0 << 7)
+#define RT5616_GP3_OUT_HI                      (0x1 << 7)
+#define RT5616_GP3_P_MASK                      (0x1 << 6)
+#define RT5616_GP3_P_SFT                       6
+#define RT5616_GP3_P_NOR                       (0x0 << 6)
+#define RT5616_GP3_P_INV                       (0x1 << 6)
+#define RT5616_GP2_DR_MASK                     (0x1 << 5)
+#define RT5616_GP2_DR_SFT                      5
+#define RT5616_GP2_DR_IN                       (0x0 << 5)
+#define RT5616_GP2_DR_OUT                      (0x1 << 5)
+#define RT5616_GP2_OUT_MASK                    (0x1 << 4)
+#define RT5616_GP2_OUT_SFT                     4
+#define RT5616_GP2_OUT_LO                      (0x0 << 4)
+#define RT5616_GP2_OUT_HI                      (0x1 << 4)
+#define RT5616_GP2_P_MASK                      (0x1 << 3)
+#define RT5616_GP2_P_SFT                       3
+#define RT5616_GP2_P_NOR                       (0x0 << 3)
+#define RT5616_GP2_P_INV                       (0x1 << 3)
+#define RT5616_GP1_DR_MASK                     (0x1 << 2)
+#define RT5616_GP1_DR_SFT                      2
+#define RT5616_GP1_DR_IN                       (0x0 << 2)
+#define RT5616_GP1_DR_OUT                      (0x1 << 2)
+#define RT5616_GP1_OUT_MASK                    (0x1 << 1)
+#define RT5616_GP1_OUT_SFT                     1
+#define RT5616_GP1_OUT_LO                      (0x0 << 1)
+#define RT5616_GP1_OUT_HI                      (0x1 << 1)
+#define RT5616_GP1_P_MASK                      (0x1)
+#define RT5616_GP1_P_SFT                       0
+#define RT5616_GP1_P_NOR                       (0x0)
+#define RT5616_GP1_P_INV                       (0x1)
+
+/* GPIO Control 3 (0xc2) */
+#define RT5616_GP8_DR_MASK                     (0x1 << 8)
+#define RT5616_GP8_DR_SFT                      8
+#define RT5616_GP8_DR_IN                       (0x0 << 8)
+#define RT5616_GP8_DR_OUT                      (0x1 << 8)
+#define RT5616_GP8_OUT_MASK                    (0x1 << 7)
+#define RT5616_GP8_OUT_SFT                     7
+#define RT5616_GP8_OUT_LO                      (0x0 << 7)
+#define RT5616_GP8_OUT_HI                      (0x1 << 7)
+#define RT5616_GP8_P_MASK                      (0x1 << 6)
+#define RT5616_GP8_P_SFT                       6
+#define RT5616_GP8_P_NOR                       (0x0 << 6)
+#define RT5616_GP8_P_INV                       (0x1 << 6)
+#define RT5616_GP7_DR_MASK                     (0x1 << 5)
+#define RT5616_GP7_DR_SFT                      5
+#define RT5616_GP7_DR_IN                       (0x0 << 5)
+#define RT5616_GP7_DR_OUT                      (0x1 << 5)
+#define RT5616_GP7_OUT_MASK                    (0x1 << 4)
+#define RT5616_GP7_OUT_SFT                     4
+#define RT5616_GP7_OUT_LO                      (0x0 << 4)
+#define RT5616_GP7_OUT_HI                      (0x1 << 4)
+#define RT5616_GP7_P_MASK                      (0x1 << 3)
+#define RT5616_GP7_P_SFT                       3
+#define RT5616_GP7_P_NOR                       (0x0 << 3)
+#define RT5616_GP7_P_INV                       (0x1 << 3)
+#define RT5616_GP6_DR_MASK                     (0x1 << 2)
+#define RT5616_GP6_DR_SFT                      2
+#define RT5616_GP6_DR_IN                       (0x0 << 2)
+#define RT5616_GP6_DR_OUT                      (0x1 << 2)
+#define RT5616_GP6_OUT_MASK                    (0x1 << 1)
+#define RT5616_GP6_OUT_SFT                     1
+#define RT5616_GP6_OUT_LO                      (0x0 << 1)
+#define RT5616_GP6_OUT_HI                      (0x1 << 1)
+#define RT5616_GP6_P_MASK                      (0x1)
+#define RT5616_GP6_P_SFT                       0
+#define RT5616_GP6_P_NOR                       (0x0)
+#define RT5616_GP6_P_INV                       (0x1)
+
+/* Scramble Control (0xce) */
+#define RT5616_SCB_SWAP_MASK                   (0x1 << 15)
+#define RT5616_SCB_SWAP_SFT                    15
+#define RT5616_SCB_SWAP_DIS                    (0x0 << 15)
+#define RT5616_SCB_SWAP_EN                     (0x1 << 15)
+#define RT5616_SCB_MASK                                (0x1 << 14)
+#define RT5616_SCB_SFT                         14
+#define RT5616_SCB_DIS                         (0x0 << 14)
+#define RT5616_SCB_EN                          (0x1 << 14)
+
+/* Baseback Control (0xcf) */
+#define RT5616_BB_MASK                         (0x1 << 15)
+#define RT5616_BB_SFT                          15
+#define RT5616_BB_DIS                          (0x0 << 15)
+#define RT5616_BB_EN                           (0x1 << 15)
+#define RT5616_BB_CT_MASK                      (0x7 << 12)
+#define RT5616_BB_CT_SFT                       12
+#define RT5616_BB_CT_A                         (0x0 << 12)
+#define RT5616_BB_CT_B                         (0x1 << 12)
+#define RT5616_BB_CT_C                         (0x2 << 12)
+#define RT5616_BB_CT_D                         (0x3 << 12)
+#define RT5616_M_BB_L_MASK                     (0x1 << 9)
+#define RT5616_M_BB_L_SFT                      9
+#define RT5616_M_BB_R_MASK                     (0x1 << 8)
+#define RT5616_M_BB_R_SFT                      8
+#define RT5616_M_BB_HPF_L_MASK                 (0x1 << 7)
+#define RT5616_M_BB_HPF_L_SFT                  7
+#define RT5616_M_BB_HPF_R_MASK                 (0x1 << 6)
+#define RT5616_M_BB_HPF_R_SFT                  6
+#define RT5616_G_BB_BST_MASK                   (0x3f)
+#define RT5616_G_BB_BST_SFT                    0
+
+/* MP3 Plus Control 1 (0xd0) */
+#define RT5616_M_MP3_L_MASK                    (0x1 << 15)
+#define RT5616_M_MP3_L_SFT                     15
+#define RT5616_M_MP3_R_MASK                    (0x1 << 14)
+#define RT5616_M_MP3_R_SFT                     14
+#define RT5616_M_MP3_MASK                      (0x1 << 13)
+#define RT5616_M_MP3_SFT                       13
+#define RT5616_M_MP3_DIS                       (0x0 << 13)
+#define RT5616_M_MP3_EN                                (0x1 << 13)
+#define RT5616_EG_MP3_MASK                     (0x1f << 8)
+#define RT5616_EG_MP3_SFT                      8
+#define RT5616_MP3_HLP_MASK                    (0x1 << 7)
+#define RT5616_MP3_HLP_SFT                     7
+#define RT5616_MP3_HLP_DIS                     (0x0 << 7)
+#define RT5616_MP3_HLP_EN                      (0x1 << 7)
+#define RT5616_M_MP3_ORG_L_MASK                        (0x1 << 6)
+#define RT5616_M_MP3_ORG_L_SFT                 6
+#define RT5616_M_MP3_ORG_R_MASK                        (0x1 << 5)
+#define RT5616_M_MP3_ORG_R_SFT                 5
+
+/* MP3 Plus Control 2 (0xd1) */
+#define RT5616_MP3_WT_MASK                     (0x1 << 13)
+#define RT5616_MP3_WT_SFT                      13
+#define RT5616_MP3_WT_1_4                      (0x0 << 13)
+#define RT5616_MP3_WT_1_2                      (0x1 << 13)
+#define RT5616_OG_MP3_MASK                     (0x1f << 8)
+#define RT5616_OG_MP3_SFT                      8
+#define RT5616_HG_MP3_MASK                     (0x3f)
+#define RT5616_HG_MP3_SFT                      0
+
+/* 3D HP Control 1 (0xd2) */
+#define RT5616_3D_CF_MASK                      (0x1 << 15)
+#define RT5616_3D_CF_SFT                       15
+#define RT5616_3D_CF_DIS                       (0x0 << 15)
+#define RT5616_3D_CF_EN                                (0x1 << 15)
+#define RT5616_3D_HP_MASK                      (0x1 << 14)
+#define RT5616_3D_HP_SFT                       14
+#define RT5616_3D_HP_DIS                       (0x0 << 14)
+#define RT5616_3D_HP_EN                                (0x1 << 14)
+#define RT5616_3D_BT_MASK                      (0x1 << 13)
+#define RT5616_3D_BT_SFT                       13
+#define RT5616_3D_BT_DIS                       (0x0 << 13)
+#define RT5616_3D_BT_EN                                (0x1 << 13)
+#define RT5616_3D_1F_MIX_MASK                  (0x3 << 11)
+#define RT5616_3D_1F_MIX_SFT                   11
+#define RT5616_3D_HP_M_MASK                    (0x1 << 10)
+#define RT5616_3D_HP_M_SFT                     10
+#define RT5616_3D_HP_M_SUR                     (0x0 << 10)
+#define RT5616_3D_HP_M_FRO                     (0x1 << 10)
+#define RT5616_M_3D_HRTF_MASK                  (0x1 << 9)
+#define RT5616_M_3D_HRTF_SFT                   9
+#define RT5616_M_3D_D2H_MASK                   (0x1 << 8)
+#define RT5616_M_3D_D2H_SFT                    8
+#define RT5616_M_3D_D2R_MASK                   (0x1 << 7)
+#define RT5616_M_3D_D2R_SFT                    7
+#define RT5616_M_3D_REVB_MASK                  (0x1 << 6)
+#define RT5616_M_3D_REVB_SFT                   6
+
+/* Adjustable high pass filter control 1 (0xd3) */
+#define RT5616_2ND_HPF_MASK                    (0x1 << 15)
+#define RT5616_2ND_HPF_SFT                     15
+#define RT5616_2ND_HPF_DIS                     (0x0 << 15)
+#define RT5616_2ND_HPF_EN                      (0x1 << 15)
+#define RT5616_HPF_CF_L_MASK                   (0x7 << 12)
+#define RT5616_HPF_CF_L_SFT                    12
+#define RT5616_HPF_CF_R_MASK                   (0x7 << 8)
+#define RT5616_HPF_CF_R_SFT                    8
+#define RT5616_ZD_T_MASK                       (0x3 << 6)
+#define RT5616_ZD_T_SFT                                6
+#define RT5616_ZD_F_MASK                       (0x3 << 4)
+#define RT5616_ZD_F_SFT                                4
+#define RT5616_ZD_F_IM                         (0x0 << 4)
+#define RT5616_ZD_F_ZC_IM                      (0x1 << 4)
+#define RT5616_ZD_F_ZC_IOD                     (0x2 << 4)
+#define RT5616_ZD_F_UN                         (0x3 << 4)
+
+/* Adjustable high pass filter control 2 (0xd4) */
+#define RT5616_HPF_CF_L_NUM_MASK               (0x3f << 8)
+#define RT5616_HPF_CF_L_NUM_SFT                        8
+#define RT5616_HPF_CF_R_NUM_MASK               (0x3f)
+#define RT5616_HPF_CF_R_NUM_SFT                        0
+
+/* HP calibration control and Amp detection (0xd6) */
+#define RT5616_SI_DAC_MASK                     (0x1 << 11)
+#define RT5616_SI_DAC_SFT                      11
+#define RT5616_SI_DAC_AUTO                     (0x0 << 11)
+#define RT5616_SI_DAC_TEST                     (0x1 << 11)
+#define RT5616_DC_CAL_M_MASK                   (0x1 << 10)
+#define RT5616_DC_CAL_M_SFT                    10
+#define RT5616_DC_CAL_M_NOR                    (0x0 << 10)
+#define RT5616_DC_CAL_M_CAL                    (0x1 << 10)
+#define RT5616_DC_CAL_MASK                     (0x1 << 9)
+#define RT5616_DC_CAL_SFT                      9
+#define RT5616_DC_CAL_DIS                      (0x0 << 9)
+#define RT5616_DC_CAL_EN                       (0x1 << 9)
+#define RT5616_HPD_RCV_MASK                    (0x7 << 6)
+#define RT5616_HPD_RCV_SFT                     6
+#define RT5616_HPD_PS_MASK                     (0x1 << 5)
+#define RT5616_HPD_PS_SFT                      5
+#define RT5616_HPD_PS_DIS                      (0x0 << 5)
+#define RT5616_HPD_PS_EN                       (0x1 << 5)
+#define RT5616_CAL_M_MASK                      (0x1 << 4)
+#define RT5616_CAL_M_SFT                       4
+#define RT5616_CAL_M_DEP                       (0x0 << 4)
+#define RT5616_CAL_M_CAL                       (0x1 << 4)
+#define RT5616_CAL_MASK                                (0x1 << 3)
+#define RT5616_CAL_SFT                         3
+#define RT5616_CAL_DIS                         (0x0 << 3)
+#define RT5616_CAL_EN                          (0x1 << 3)
+#define RT5616_CAL_TEST_MASK                   (0x1 << 2)
+#define RT5616_CAL_TEST_SFT                    2
+#define RT5616_CAL_TEST_DIS                    (0x0 << 2)
+#define RT5616_CAL_TEST_EN                     (0x1 << 2)
+#define RT5616_CAL_P_MASK                      (0x3)
+#define RT5616_CAL_P_SFT                       0
+#define RT5616_CAL_P_NONE                      (0x0)
+#define RT5616_CAL_P_CAL                       (0x1)
+#define RT5616_CAL_P_DAC_CAL                   (0x2)
+
+/* Soft volume and zero cross control 1 (0xd9) */
+#define RT5616_SV_MASK                         (0x1 << 15)
+#define RT5616_SV_SFT                          15
+#define RT5616_SV_DIS                          (0x0 << 15)
+#define RT5616_SV_EN                           (0x1 << 15)
+#define RT5616_OUT_SV_MASK                     (0x1 << 13)
+#define RT5616_OUT_SV_SFT                      13
+#define RT5616_OUT_SV_DIS                      (0x0 << 13)
+#define RT5616_OUT_SV_EN                       (0x1 << 13)
+#define RT5616_HP_SV_MASK                      (0x1 << 12)
+#define RT5616_HP_SV_SFT                       12
+#define RT5616_HP_SV_DIS                       (0x0 << 12)
+#define RT5616_HP_SV_EN                                (0x1 << 12)
+#define RT5616_ZCD_DIG_MASK                    (0x1 << 11)
+#define RT5616_ZCD_DIG_SFT                     11
+#define RT5616_ZCD_DIG_DIS                     (0x0 << 11)
+#define RT5616_ZCD_DIG_EN                      (0x1 << 11)
+#define RT5616_ZCD_MASK                                (0x1 << 10)
+#define RT5616_ZCD_SFT                         10
+#define RT5616_ZCD_PD                          (0x0 << 10)
+#define RT5616_ZCD_PU                          (0x1 << 10)
+#define RT5616_M_ZCD_MASK                      (0x3f << 4)
+#define RT5616_M_ZCD_SFT                       4
+#define RT5616_M_ZCD_OM_L                      (0x1 << 7)
+#define RT5616_M_ZCD_OM_R                      (0x1 << 6)
+#define RT5616_M_ZCD_RM_L                      (0x1 << 5)
+#define RT5616_M_ZCD_RM_R                      (0x1 << 4)
+#define RT5616_SV_DLY_MASK                     (0xf)
+#define RT5616_SV_DLY_SFT                      0
+
+/* Soft volume and zero cross control 2 (0xda) */
+#define RT5616_ZCD_HP_MASK                     (0x1 << 15)
+#define RT5616_ZCD_HP_SFT                      15
+#define RT5616_ZCD_HP_DIS                      (0x0 << 15)
+#define RT5616_ZCD_HP_EN                       (0x1 << 15)
+
+/* Digital Misc Control (0xfa) */
+#define RT5616_I2S2_MS_SP_MASK                 (0x1 << 8)
+#define RT5616_I2S2_MS_SP_SEL                  8
+#define RT5616_I2S2_MS_SP_64                   (0x0 << 8)
+#define RT5616_I2S2_MS_SP_50                   (0x1 << 8)
+#define RT5616_CLK_DET_EN                      (0x1 << 3)
+#define RT5616_CLK_DET_EN_SFT                  3
+#define RT5616_AMP_DET_EN                      (0x1 << 1)
+#define RT5616_AMP_DET_EN_SFT                  1
+#define RT5616_D_GATE_EN                       (0x1)
+#define RT5616_D_GATE_EN_SFT                   0
+
+/* Codec Private Register definition */
+/* 3D Speaker Control (0x63) */
+#define RT5616_3D_SPK_MASK                     (0x1 << 15)
+#define RT5616_3D_SPK_SFT                      15
+#define RT5616_3D_SPK_DIS                      (0x0 << 15)
+#define RT5616_3D_SPK_EN                       (0x1 << 15)
+#define RT5616_3D_SPK_M_MASK                   (0x3 << 13)
+#define RT5616_3D_SPK_M_SFT                    13
+#define RT5616_3D_SPK_CG_MASK                  (0x1f << 8)
+#define RT5616_3D_SPK_CG_SFT                   8
+#define RT5616_3D_SPK_SG_MASK                  (0x1f)
+#define RT5616_3D_SPK_SG_SFT                   0
+
+/* Wind Noise Detection Control 1 (0x6c) */
+#define RT5616_WND_MASK                                (0x1 << 15)
+#define RT5616_WND_SFT                         15
+#define RT5616_WND_DIS                         (0x0 << 15)
+#define RT5616_WND_EN                          (0x1 << 15)
+
+/* Wind Noise Detection Control 2 (0x6d) */
+#define RT5616_WND_FC_NW_MASK                  (0x3f << 10)
+#define RT5616_WND_FC_NW_SFT                   10
+#define RT5616_WND_FC_WK_MASK                  (0x3f << 4)
+#define RT5616_WND_FC_WK_SFT                   4
+
+/* Wind Noise Detection Control 3 (0x6e) */
+#define RT5616_HPF_FC_MASK                     (0x3f << 6)
+#define RT5616_HPF_FC_SFT                      6
+#define RT5616_WND_FC_ST_MASK                  (0x3f)
+#define RT5616_WND_FC_ST_SFT                   0
+
+/* Wind Noise Detection Control 4 (0x6f) */
+#define RT5616_WND_TH_LO_MASK                  (0x3ff)
+#define RT5616_WND_TH_LO_SFT                   0
+
+/* Wind Noise Detection Control 5 (0x70) */
+#define RT5616_WND_TH_HI_MASK                  (0x3ff)
+#define RT5616_WND_TH_HI_SFT                   0
+
+/* Wind Noise Detection Control 8 (0x73) */
+#define RT5616_WND_WIND_MASK                   (0x1 << 13) /* Read-Only */
+#define RT5616_WND_WIND_SFT                    13
+#define RT5616_WND_STRONG_MASK                 (0x1 << 12) /* Read-Only */
+#define RT5616_WND_STRONG_SFT                  12
+enum {
+       RT5616_NO_WIND,
+       RT5616_BREEZE,
+       RT5616_STORM,
+};
+
+/* Dipole Speaker Interface (0x75) */
+#define RT5616_DP_ATT_MASK                     (0x3 << 14)
+#define RT5616_DP_ATT_SFT                      14
+#define RT5616_DP_SPK_MASK                     (0x1 << 10)
+#define RT5616_DP_SPK_SFT                      10
+#define RT5616_DP_SPK_DIS                      (0x0 << 10)
+#define RT5616_DP_SPK_EN                       (0x1 << 10)
+
+/* EQ Pre Volume Control (0xb3) */
+#define RT5616_EQ_PRE_VOL_MASK                 (0xffff)
+#define RT5616_EQ_PRE_VOL_SFT                  0
+
+/* EQ Post Volume Control (0xb4) */
+#define RT5616_EQ_PST_VOL_MASK                 (0xffff)
+#define RT5616_EQ_PST_VOL_SFT                  0
+
+/* System Clock Source */
+enum {
+       RT5616_SCLK_S_MCLK,
+       RT5616_SCLK_S_PLL1,
+};
+
+/* PLL1 Source */
+enum {
+       RT5616_PLL1_S_MCLK,
+       RT5616_PLL1_S_BCLK1,
+       RT5616_PLL1_S_BCLK2,
+};
+
+enum {
+       RT5616_AIF1,
+       RT5616_AIFS,
+};
+
+#endif /* __RT5616_H__ */
index f2beb1aa5763dfe99dc6de821f4c9367446773a7..11d032cdc65814126b426544e7fe0dd0214786ac 100644 (file)
@@ -488,6 +488,18 @@ static int is_sys_clk_from_pll(struct snd_soc_dapm_widget *source,
                return 0;
 }
 
+static int is_using_asrc(struct snd_soc_dapm_widget *source,
+                        struct snd_soc_dapm_widget *sink)
+{
+       struct snd_soc_codec *codec = snd_soc_dapm_to_codec(source->dapm);
+       struct rt5640_priv *rt5640 = snd_soc_codec_get_drvdata(codec);
+
+       if (!rt5640->asrc_en)
+               return 0;
+
+       return 1;
+}
+
 /* Digital Mixer */
 static const struct snd_kcontrol_new rt5640_sto_adc_l_mix[] = {
        SOC_DAPM_SINGLE("ADC1 Switch", RT5640_STO_ADC_MIXER,
@@ -1059,6 +1071,20 @@ static int rt5640_hp_post_event(struct snd_soc_dapm_widget *w,
 static const struct snd_soc_dapm_widget rt5640_dapm_widgets[] = {
        SND_SOC_DAPM_SUPPLY("PLL1", RT5640_PWR_ANLG2,
                        RT5640_PWR_PLL_BIT, 0, NULL, 0),
+
+       /* ASRC */
+       SND_SOC_DAPM_SUPPLY_S("Stereo Filter ASRC", 1, RT5640_ASRC_1,
+                        15, 0, NULL, 0),
+       SND_SOC_DAPM_SUPPLY_S("I2S2 Filter ASRC", 1, RT5640_ASRC_1,
+                        12, 0, NULL, 0),
+       SND_SOC_DAPM_SUPPLY_S("I2S2 ASRC", 1, RT5640_ASRC_1,
+                        11, 0, NULL, 0),
+       SND_SOC_DAPM_SUPPLY_S("DMIC1 ASRC", 1, RT5640_ASRC_1,
+                        9, 0, NULL, 0),
+       SND_SOC_DAPM_SUPPLY_S("DMIC2 ASRC", 1, RT5640_ASRC_1,
+                        8, 0, NULL, 0),
+
+
        /* Input Side */
        /* micbias */
        SND_SOC_DAPM_SUPPLY("LDO2", RT5640_PWR_ANLG1,
@@ -1319,6 +1345,12 @@ static const struct snd_soc_dapm_widget rt5639_specific_dapm_widgets[] = {
 };
 
 static const struct snd_soc_dapm_route rt5640_dapm_routes[] = {
+       { "I2S1", NULL, "Stereo Filter ASRC", is_using_asrc },
+       { "I2S2", NULL, "I2S2 ASRC", is_using_asrc },
+       { "I2S2", NULL, "I2S2 Filter ASRC", is_using_asrc },
+       { "DMIC1", NULL, "DMIC1 ASRC", is_using_asrc },
+       { "DMIC2", NULL, "DMIC2 ASRC", is_using_asrc },
+
        {"IN1P", NULL, "LDO2"},
        {"IN2P", NULL, "LDO2"},
        {"IN3P", NULL, "LDO2"},
@@ -1981,6 +2013,76 @@ int rt5640_dmic_enable(struct snd_soc_codec *codec,
 }
 EXPORT_SYMBOL_GPL(rt5640_dmic_enable);
 
+int rt5640_sel_asrc_clk_src(struct snd_soc_codec *codec,
+               unsigned int filter_mask, unsigned int clk_src)
+{
+       struct rt5640_priv *rt5640 = snd_soc_codec_get_drvdata(codec);
+       unsigned int asrc2_mask = 0;
+       unsigned int asrc2_value = 0;
+
+       switch (clk_src) {
+       case RT5640_CLK_SEL_SYS:
+       case RT5640_CLK_SEL_ASRC:
+               break;
+
+       default:
+               return -EINVAL;
+       }
+
+       if (!filter_mask)
+               return -EINVAL;
+
+       if (filter_mask & RT5640_DA_STEREO_FILTER) {
+               asrc2_mask |= RT5640_STO_DAC_M_MASK;
+               asrc2_value = (asrc2_value & ~RT5640_STO_DAC_M_MASK)
+                       | (clk_src << RT5640_STO_DAC_M_SFT);
+       }
+
+       if (filter_mask & RT5640_DA_MONO_L_FILTER) {
+               asrc2_mask |= RT5640_MDA_L_M_MASK;
+               asrc2_value = (asrc2_value & ~RT5640_MDA_L_M_MASK)
+                       | (clk_src << RT5640_MDA_L_M_SFT);
+       }
+
+       if (filter_mask & RT5640_DA_MONO_R_FILTER) {
+               asrc2_mask |= RT5640_MDA_R_M_MASK;
+               asrc2_value = (asrc2_value & ~RT5640_MDA_R_M_MASK)
+                       | (clk_src << RT5640_MDA_R_M_SFT);
+       }
+
+       if (filter_mask & RT5640_AD_STEREO_FILTER) {
+               asrc2_mask |= RT5640_ADC_M_MASK;
+               asrc2_value = (asrc2_value & ~RT5640_ADC_M_MASK)
+                       | (clk_src << RT5640_ADC_M_SFT);
+       }
+
+       if (filter_mask & RT5640_AD_MONO_L_FILTER) {
+               asrc2_mask |= RT5640_MAD_L_M_MASK;
+               asrc2_value = (asrc2_value & ~RT5640_MAD_L_M_MASK)
+                       | (clk_src << RT5640_MAD_L_M_SFT);
+       }
+
+       if (filter_mask & RT5640_AD_MONO_R_FILTER)  {
+               asrc2_mask |= RT5640_MAD_R_M_MASK;
+               asrc2_value = (asrc2_value & ~RT5640_MAD_R_M_MASK)
+                       | (clk_src << RT5640_MAD_R_M_SFT);
+       }
+
+       snd_soc_update_bits(codec, RT5640_ASRC_2,
+               asrc2_mask, asrc2_value);
+
+       if (snd_soc_read(codec, RT5640_ASRC_2)) {
+               rt5640->asrc_en = true;
+               snd_soc_update_bits(codec, RT5640_JD_CTRL, 0x3, 0x3);
+       } else {
+               rt5640->asrc_en = false;
+               snd_soc_update_bits(codec, RT5640_JD_CTRL, 0x3, 0x0);
+       }
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(rt5640_sel_asrc_clk_src);
+
 static int rt5640_probe(struct snd_soc_codec *codec)
 {
        struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
@@ -2175,6 +2277,7 @@ static const struct acpi_device_id rt5640_acpi_match[] = {
        { "INT33CA", 0 },
        { "10EC5640", 0 },
        { "10EC5642", 0 },
+       { "INTCCFFD", 0 },
        { },
 };
 MODULE_DEVICE_TABLE(acpi, rt5640_acpi_match);
index 3deb8babeabb691d37a314bb3ab19c84d5c9cd1f..83a7150ddc24eb637de10d1670eb8614ef0063c2 100644 (file)
 #define RT5640_DMIC_2_M_NOR                    (0x0 << 8)
 #define RT5640_DMIC_2_M_ASYN                   (0x1 << 8)
 
+/* ASRC clock source selection (0x84) */
+#define RT5640_CLK_SEL_SYS                     (0x0)
+#define RT5640_CLK_SEL_ASRC                    (0x1)
+
 /* ASRC Control 2 (0x84) */
 #define RT5640_MDA_L_M_MASK                    (0x1 << 15)
 #define RT5640_MDA_L_M_SFT                     15
@@ -2079,6 +2083,16 @@ enum {
        RT5640_DMIC2,
 };
 
+/* filter mask */
+enum {
+       RT5640_DA_STEREO_FILTER = 0x1,
+       RT5640_DA_MONO_L_FILTER = (0x1 << 1),
+       RT5640_DA_MONO_R_FILTER = (0x1 << 2),
+       RT5640_AD_STEREO_FILTER = (0x1 << 3),
+       RT5640_AD_MONO_L_FILTER = (0x1 << 4),
+       RT5640_AD_MONO_R_FILTER = (0x1 << 5),
+};
+
 struct rt5640_priv {
        struct snd_soc_codec *codec;
        struct rt5640_platform_data pdata;
@@ -2095,9 +2109,12 @@ struct rt5640_priv {
        int pll_out;
 
        bool hp_mute;
+       bool asrc_en;
 };
 
 int rt5640_dmic_enable(struct snd_soc_codec *codec,
                       bool dmic1_data_pin, bool dmic2_data_pin);
+int rt5640_sel_asrc_clk_src(struct snd_soc_codec *codec,
+               unsigned int filter_mask, unsigned int clk_src);
 
 #endif
index 28132375e4274a6e94e830c2fe1e8fcddd255747..c61d38b585fb06de6b6ca0f41370c3b78c10113c 100644 (file)
@@ -64,7 +64,6 @@ static const struct reg_sequence init_list[] = {
        {RT5645_PR_BASE + 0x21, 0x4040},
        {RT5645_PR_BASE + 0x23, 0x0004},
 };
-#define RT5645_INIT_REG_LEN ARRAY_SIZE(init_list)
 
 static const struct reg_sequence rt5650_init_list[] = {
        {0xf6,  0x0100},
@@ -226,6 +225,163 @@ static const struct reg_default rt5645_reg[] = {
        { 0xff, 0x6308 },
 };
 
+static const struct reg_default rt5650_reg[] = {
+       { 0x00, 0x0000 },
+       { 0x01, 0xc8c8 },
+       { 0x02, 0xc8c8 },
+       { 0x03, 0xc8c8 },
+       { 0x0a, 0x0002 },
+       { 0x0b, 0x2827 },
+       { 0x0c, 0xe000 },
+       { 0x0d, 0x0000 },
+       { 0x0e, 0x0000 },
+       { 0x0f, 0x0808 },
+       { 0x14, 0x3333 },
+       { 0x16, 0x4b00 },
+       { 0x18, 0x018b },
+       { 0x19, 0xafaf },
+       { 0x1a, 0xafaf },
+       { 0x1b, 0x0001 },
+       { 0x1c, 0x2f2f },
+       { 0x1d, 0x2f2f },
+       { 0x1e, 0x0000 },
+       { 0x20, 0x0000 },
+       { 0x27, 0x7060 },
+       { 0x28, 0x7070 },
+       { 0x29, 0x8080 },
+       { 0x2a, 0x5656 },
+       { 0x2b, 0x5454 },
+       { 0x2c, 0xaaa0 },
+       { 0x2d, 0x0000 },
+       { 0x2f, 0x1002 },
+       { 0x31, 0x5000 },
+       { 0x32, 0x0000 },
+       { 0x33, 0x0000 },
+       { 0x34, 0x0000 },
+       { 0x35, 0x0000 },
+       { 0x3b, 0x0000 },
+       { 0x3c, 0x007f },
+       { 0x3d, 0x0000 },
+       { 0x3e, 0x007f },
+       { 0x3f, 0x0000 },
+       { 0x40, 0x001f },
+       { 0x41, 0x0000 },
+       { 0x42, 0x001f },
+       { 0x45, 0x6000 },
+       { 0x46, 0x003e },
+       { 0x47, 0x003e },
+       { 0x48, 0xf807 },
+       { 0x4a, 0x0004 },
+       { 0x4d, 0x0000 },
+       { 0x4e, 0x0000 },
+       { 0x4f, 0x01ff },
+       { 0x50, 0x0000 },
+       { 0x51, 0x0000 },
+       { 0x52, 0x01ff },
+       { 0x53, 0xf000 },
+       { 0x56, 0x0111 },
+       { 0x57, 0x0064 },
+       { 0x58, 0xef0e },
+       { 0x59, 0xf0f0 },
+       { 0x5a, 0xef0e },
+       { 0x5b, 0xf0f0 },
+       { 0x5c, 0xef0e },
+       { 0x5d, 0xf0f0 },
+       { 0x5e, 0xf000 },
+       { 0x5f, 0x0000 },
+       { 0x61, 0x0300 },
+       { 0x62, 0x0000 },
+       { 0x63, 0x00c2 },
+       { 0x64, 0x0000 },
+       { 0x65, 0x0000 },
+       { 0x66, 0x0000 },
+       { 0x6a, 0x0000 },
+       { 0x6c, 0x0aaa },
+       { 0x70, 0x8000 },
+       { 0x71, 0x8000 },
+       { 0x72, 0x8000 },
+       { 0x73, 0x7770 },
+       { 0x74, 0x3e00 },
+       { 0x75, 0x2409 },
+       { 0x76, 0x000a },
+       { 0x77, 0x0c00 },
+       { 0x78, 0x0000 },
+       { 0x79, 0x0123 },
+       { 0x7a, 0x0123 },
+       { 0x80, 0x0000 },
+       { 0x81, 0x0000 },
+       { 0x82, 0x0000 },
+       { 0x83, 0x0000 },
+       { 0x84, 0x0000 },
+       { 0x85, 0x0000 },
+       { 0x8a, 0x0000 },
+       { 0x8e, 0x0004 },
+       { 0x8f, 0x1100 },
+       { 0x90, 0x0646 },
+       { 0x91, 0x0c06 },
+       { 0x93, 0x0000 },
+       { 0x94, 0x0200 },
+       { 0x95, 0x0000 },
+       { 0x9a, 0x2184 },
+       { 0x9b, 0x010a },
+       { 0x9c, 0x0aea },
+       { 0x9d, 0x000c },
+       { 0x9e, 0x0400 },
+       { 0xa0, 0xa0a8 },
+       { 0xa1, 0x0059 },
+       { 0xa2, 0x0001 },
+       { 0xae, 0x6000 },
+       { 0xaf, 0x0000 },
+       { 0xb0, 0x6000 },
+       { 0xb1, 0x0000 },
+       { 0xb2, 0x0000 },
+       { 0xb3, 0x001f },
+       { 0xb4, 0x020c },
+       { 0xb5, 0x1f00 },
+       { 0xb6, 0x0000 },
+       { 0xbb, 0x0000 },
+       { 0xbc, 0x0000 },
+       { 0xbd, 0x0000 },
+       { 0xbe, 0x0000 },
+       { 0xbf, 0x3100 },
+       { 0xc0, 0x0000 },
+       { 0xc1, 0x0000 },
+       { 0xc2, 0x0000 },
+       { 0xc3, 0x2000 },
+       { 0xcd, 0x0000 },
+       { 0xce, 0x0000 },
+       { 0xcf, 0x1813 },
+       { 0xd0, 0x0690 },
+       { 0xd1, 0x1c17 },
+       { 0xd3, 0xb320 },
+       { 0xd4, 0x0000 },
+       { 0xd6, 0x0400 },
+       { 0xd9, 0x0809 },
+       { 0xda, 0x0000 },
+       { 0xdb, 0x0003 },
+       { 0xdc, 0x0049 },
+       { 0xdd, 0x001b },
+       { 0xdf, 0x0008 },
+       { 0xe0, 0x4000 },
+       { 0xe6, 0x8000 },
+       { 0xe7, 0x0200 },
+       { 0xec, 0xb300 },
+       { 0xed, 0x0000 },
+       { 0xf0, 0x001f },
+       { 0xf1, 0x020c },
+       { 0xf2, 0x1f00 },
+       { 0xf3, 0x0000 },
+       { 0xf4, 0x4000 },
+       { 0xf8, 0x0000 },
+       { 0xf9, 0x0000 },
+       { 0xfa, 0x2060 },
+       { 0xfb, 0x4040 },
+       { 0xfc, 0x0000 },
+       { 0xfd, 0x0002 },
+       { 0xfe, 0x10ec },
+       { 0xff, 0x6308 },
+};
+
 struct rt5645_eq_param_s {
        unsigned short reg;
        unsigned short val;
@@ -245,9 +401,10 @@ struct rt5645_priv {
        struct snd_soc_jack *hp_jack;
        struct snd_soc_jack *mic_jack;
        struct snd_soc_jack *btn_jack;
-       struct delayed_work jack_detect_work;
+       struct delayed_work jack_detect_work, rcclock_work;
        struct regulator_bulk_data supplies[ARRAY_SIZE(rt5645_supply_names)];
        struct rt5645_eq_param_s *eq_param;
+       struct timer_list btn_check_timer;
 
        int codec_type;
        int sysclk;
@@ -565,12 +722,31 @@ static int rt5645_hweq_put(struct snd_kcontrol *kcontrol,
        .put = rt5645_hweq_put \
 }
 
+static int rt5645_spk_put_volsw(struct snd_kcontrol *kcontrol,
+               struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
+       struct rt5645_priv *rt5645 = snd_soc_component_get_drvdata(component);
+       int ret;
+
+       regmap_update_bits(rt5645->regmap, RT5645_MICBIAS,
+               RT5645_PWR_CLK25M_MASK, RT5645_PWR_CLK25M_PU);
+
+       ret = snd_soc_put_volsw(kcontrol, ucontrol);
+
+       mod_delayed_work(system_power_efficient_wq, &rt5645->rcclock_work,
+               msecs_to_jiffies(200));
+
+       return ret;
+}
+
 static const struct snd_kcontrol_new rt5645_snd_controls[] = {
        /* Speaker Output Volume */
        SOC_DOUBLE("Speaker Channel Switch", RT5645_SPK_VOL,
                RT5645_VOL_L_SFT, RT5645_VOL_R_SFT, 1, 1),
-       SOC_DOUBLE_TLV("Speaker Playback Volume", RT5645_SPK_VOL,
-               RT5645_L_VOL_SFT, RT5645_R_VOL_SFT, 39, 1, out_vol_tlv),
+       SOC_DOUBLE_EXT_TLV("Speaker Playback Volume", RT5645_SPK_VOL,
+               RT5645_L_VOL_SFT, RT5645_R_VOL_SFT, 39, 1, snd_soc_get_volsw,
+               rt5645_spk_put_volsw, out_vol_tlv),
 
        /* ClassD modulator Speaker Gain Ratio */
        SOC_SINGLE_TLV("Speaker ClassD Playback Volume", RT5645_SPO_CLSD_RATIO,
@@ -1498,7 +1674,7 @@ static void hp_amp_power(struct snd_soc_codec *codec, int on)
                                regmap_write(rt5645->regmap, RT5645_PR_BASE +
                                        RT5645_MAMP_INT_REG2, 0xfc00);
                                snd_soc_write(codec, RT5645_DEPOP_M2, 0x1140);
-                               msleep(40);
+                               msleep(70);
                                rt5645->hp_on = true;
                        } else {
                                /* depop parameters */
@@ -1646,9 +1822,13 @@ static int rt5645_spk_event(struct snd_soc_dapm_widget *w,
                        RT5645_PWR_CLS_D_L,
                        RT5645_PWR_CLS_D | RT5645_PWR_CLS_D_R |
                        RT5645_PWR_CLS_D_L);
+               snd_soc_update_bits(codec, RT5645_GEN_CTRL3,
+                       RT5645_DET_CLK_MASK, RT5645_DET_CLK_MODE1);
                break;
 
        case SND_SOC_DAPM_PRE_PMD:
+               snd_soc_update_bits(codec, RT5645_GEN_CTRL3,
+                       RT5645_DET_CLK_MASK, RT5645_DET_CLK_DIS);
                snd_soc_write(codec, RT5645_EQ_CTRL2, 0);
                snd_soc_update_bits(codec, RT5645_PWR_DIG1,
                        RT5645_PWR_CLS_D | RT5645_PWR_CLS_D_R |
@@ -2886,6 +3066,7 @@ static void rt5645_enable_push_button_irq(struct snd_soc_codec *codec,
                snd_soc_dapm_force_enable_pin(dapm, "ADC R power");
                snd_soc_dapm_sync(dapm);
 
+               snd_soc_update_bits(codec, RT5650_4BTN_IL_CMD1, 0x3, 0x3);
                snd_soc_update_bits(codec,
                                        RT5645_INT_IRQ_ST, 0x8, 0x8);
                snd_soc_update_bits(codec,
@@ -2954,7 +3135,7 @@ static int rt5645_jack_detect(struct snd_soc_codec *codec, int jack_insert)
                }
                if (rt5645->pdata.jd_invert)
                        regmap_update_bits(rt5645->regmap, RT5645_IRQ_CTRL2,
-                               RT5645_JD_1_1_MASK, RT5645_JD_1_1_INV);
+                               RT5645_JD_1_1_MASK, RT5645_JD_1_1_NOR);
        } else { /* jack out */
                rt5645->jack_type = 0;
 
@@ -2975,7 +3156,7 @@ static int rt5645_jack_detect(struct snd_soc_codec *codec, int jack_insert)
                snd_soc_dapm_sync(dapm);
                if (rt5645->pdata.jd_invert)
                        regmap_update_bits(rt5645->regmap, RT5645_IRQ_CTRL2,
-                               RT5645_JD_1_1_MASK, RT5645_JD_1_1_NOR);
+                               RT5645_JD_1_1_MASK, RT5645_JD_1_1_INV);
        }
 
        return rt5645->jack_type;
@@ -3099,6 +3280,12 @@ static void rt5645_jack_detect_work(struct work_struct *work)
                }
                if (btn_type == 0)/* button release */
                        report =  rt5645->jack_type;
+               else {
+                       if (rt5645->pdata.jd_invert) {
+                               mod_timer(&rt5645->btn_check_timer,
+                                       msecs_to_jiffies(100));
+                       }
+               }
 
                break;
        /* jack out */
@@ -3122,6 +3309,15 @@ static void rt5645_jack_detect_work(struct work_struct *work)
                                SND_JACK_BTN_2 | SND_JACK_BTN_3);
 }
 
+static void rt5645_rcclock_work(struct work_struct *work)
+{
+       struct rt5645_priv *rt5645 =
+               container_of(work, struct rt5645_priv, rcclock_work.work);
+
+       regmap_update_bits(rt5645->regmap, RT5645_MICBIAS,
+               RT5645_PWR_CLK25M_MASK, RT5645_PWR_CLK25M_PD);
+}
+
 static irqreturn_t rt5645_irq(int irq, void *data)
 {
        struct rt5645_priv *rt5645 = data;
@@ -3132,6 +3328,14 @@ static irqreturn_t rt5645_irq(int irq, void *data)
        return IRQ_HANDLED;
 }
 
+static void rt5645_btn_check_callback(unsigned long data)
+{
+       struct rt5645_priv *rt5645 = (struct rt5645_priv *)data;
+
+       queue_delayed_work(system_power_efficient_wq,
+                  &rt5645->jack_detect_work, msecs_to_jiffies(5));
+}
+
 static int rt5645_probe(struct snd_soc_codec *codec)
 {
        struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
@@ -3288,6 +3492,31 @@ static const struct regmap_config rt5645_regmap = {
        .num_ranges = ARRAY_SIZE(rt5645_ranges),
 };
 
+static const struct regmap_config rt5650_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,
+       .readable_reg = rt5645_readable_register,
+
+       .cache_type = REGCACHE_RBTREE,
+       .reg_defaults = rt5650_reg,
+       .num_reg_defaults = ARRAY_SIZE(rt5650_reg),
+       .ranges = rt5645_ranges,
+       .num_ranges = ARRAY_SIZE(rt5645_ranges),
+};
+
+static const struct regmap_config temp_regmap = {
+       .name="nocache",
+       .reg_bits = 8,
+       .val_bits = 16,
+       .use_single_rw = true,
+       .max_register = RT5645_VENDOR_ID2 + 1,
+       .cache_type = REGCACHE_NONE,
+};
+
 static const struct i2c_device_id rt5645_i2c_id[] = {
        { "rt5645", 0 },
        { "rt5650", 0 },
@@ -3296,7 +3525,7 @@ static const struct i2c_device_id rt5645_i2c_id[] = {
 MODULE_DEVICE_TABLE(i2c, rt5645_i2c_id);
 
 #ifdef CONFIG_ACPI
-static struct acpi_device_id rt5645_acpi_match[] = {
+static const struct acpi_device_id rt5645_acpi_match[] = {
        { "10EC5645", 0 },
        { "10EC5650", 0 },
        {},
@@ -3304,48 +3533,23 @@ static struct acpi_device_id rt5645_acpi_match[] = {
 MODULE_DEVICE_TABLE(acpi, rt5645_acpi_match);
 #endif
 
-static struct rt5645_platform_data *rt5645_pdata;
-
-static struct rt5645_platform_data strago_platform_data = {
+static struct rt5645_platform_data general_platform_data = {
        .dmic1_data_pin = RT5645_DMIC1_DISABLE,
        .dmic2_data_pin = RT5645_DMIC_DATA_IN2P,
        .jd_mode = 3,
 };
 
-static int strago_quirk_cb(const struct dmi_system_id *id)
-{
-       rt5645_pdata = &strago_platform_data;
-
-       return 1;
-}
-
 static const struct dmi_system_id dmi_platform_intel_braswell[] = {
        {
                .ident = "Intel Strago",
-               .callback = strago_quirk_cb,
                .matches = {
                        DMI_MATCH(DMI_PRODUCT_NAME, "Strago"),
                },
        },
        {
-               .ident = "Google Celes",
-               .callback = strago_quirk_cb,
+               .ident = "Google Chrome",
                .matches = {
-                       DMI_MATCH(DMI_PRODUCT_NAME, "Celes"),
-               },
-       },
-       {
-               .ident = "Google Ultima",
-               .callback = strago_quirk_cb,
-               .matches = {
-                       DMI_MATCH(DMI_PRODUCT_NAME, "Ultima"),
-               },
-       },
-       {
-               .ident = "Google Reks",
-               .callback = strago_quirk_cb,
-               .matches = {
-                       DMI_MATCH(DMI_PRODUCT_NAME, "Reks"),
+                       DMI_MATCH(DMI_SYS_VENDOR, "GOOGLE"),
                },
        },
        { }
@@ -3358,17 +3562,9 @@ static struct rt5645_platform_data buddy_platform_data = {
        .jd_invert = true,
 };
 
-static int buddy_quirk_cb(const struct dmi_system_id *id)
-{
-       rt5645_pdata = &buddy_platform_data;
-
-       return 1;
-}
-
 static struct dmi_system_id dmi_platform_intel_broadwell[] = {
        {
                .ident = "Chrome Buddy",
-               .callback = buddy_quirk_cb,
                .matches = {
                        DMI_MATCH(DMI_PRODUCT_NAME, "Buddy"),
                },
@@ -3376,6 +3572,16 @@ static struct dmi_system_id dmi_platform_intel_broadwell[] = {
        { }
 };
 
+static bool rt5645_check_dp(struct device *dev)
+{
+       if (device_property_present(dev, "realtek,in2-differential") ||
+               device_property_present(dev, "realtek,dmic1-data-pin") ||
+               device_property_present(dev, "realtek,dmic2-data-pin") ||
+               device_property_present(dev, "realtek,jd-mode"))
+               return true;
+
+       return false;
+}
 
 static int rt5645_parse_dt(struct rt5645_priv *rt5645, struct device *dev)
 {
@@ -3398,6 +3604,7 @@ static int rt5645_i2c_probe(struct i2c_client *i2c,
        struct rt5645_priv *rt5645;
        int ret, i;
        unsigned int val;
+       struct regmap *regmap;
 
        rt5645 = devm_kzalloc(&i2c->dev, sizeof(struct rt5645_priv),
                                GFP_KERNEL);
@@ -3409,11 +3616,12 @@ static int rt5645_i2c_probe(struct i2c_client *i2c,
 
        if (pdata)
                rt5645->pdata = *pdata;
-       else if (dmi_check_system(dmi_platform_intel_braswell) ||
-                       dmi_check_system(dmi_platform_intel_broadwell))
-               rt5645->pdata = *rt5645_pdata;
-       else
+       else if (dmi_check_system(dmi_platform_intel_broadwell))
+               rt5645->pdata = buddy_platform_data;
+       else if (rt5645_check_dp(&i2c->dev))
                rt5645_parse_dt(rt5645, &i2c->dev);
+       else if (dmi_check_system(dmi_platform_intel_braswell))
+               rt5645->pdata = general_platform_data;
 
        rt5645->gpiod_hp_det = devm_gpiod_get_optional(&i2c->dev, "hp-detect",
                                                       GPIOD_IN);
@@ -3423,14 +3631,6 @@ static int rt5645_i2c_probe(struct i2c_client *i2c,
                return PTR_ERR(rt5645->gpiod_hp_det);
        }
 
-       rt5645->regmap = devm_regmap_init_i2c(i2c, &rt5645_regmap);
-       if (IS_ERR(rt5645->regmap)) {
-               ret = PTR_ERR(rt5645->regmap);
-               dev_err(&i2c->dev, "Failed to allocate register map: %d\n",
-                       ret);
-               return ret;
-       }
-
        for (i = 0; i < ARRAY_SIZE(rt5645->supplies); i++)
                rt5645->supplies[i].supply = rt5645_supply_names[i];
 
@@ -3449,13 +3649,22 @@ static int rt5645_i2c_probe(struct i2c_client *i2c,
                return ret;
        }
 
-       regmap_read(rt5645->regmap, RT5645_VENDOR_ID2, &val);
+       regmap = devm_regmap_init_i2c(i2c, &temp_regmap);
+       if (IS_ERR(regmap)) {
+               ret = PTR_ERR(regmap);
+               dev_err(&i2c->dev, "Failed to allocate temp register map: %d\n",
+                       ret);
+               return ret;
+       }
+       regmap_read(regmap, RT5645_VENDOR_ID2, &val);
 
        switch (val) {
        case RT5645_DEVICE_ID:
+               rt5645->regmap = devm_regmap_init_i2c(i2c, &rt5645_regmap);
                rt5645->codec_type = CODEC_TYPE_RT5645;
                break;
        case RT5650_DEVICE_ID:
+               rt5645->regmap = devm_regmap_init_i2c(i2c, &rt5650_regmap);
                rt5645->codec_type = CODEC_TYPE_RT5650;
                break;
        default:
@@ -3466,6 +3675,13 @@ static int rt5645_i2c_probe(struct i2c_client *i2c,
                goto err_enable;
        }
 
+       if (IS_ERR(rt5645->regmap)) {
+               ret = PTR_ERR(rt5645->regmap);
+               dev_err(&i2c->dev, "Failed to allocate register map: %d\n",
+                       ret);
+               return ret;
+       }
+
        regmap_write(rt5645->regmap, RT5645_RESET, 0);
 
        ret = regmap_register_patch(rt5645->regmap, init_list,
@@ -3586,7 +3802,15 @@ static int rt5645_i2c_probe(struct i2c_client *i2c,
                }
        }
 
+       if (rt5645->pdata.jd_invert) {
+               regmap_update_bits(rt5645->regmap, RT5645_IRQ_CTRL2,
+                       RT5645_JD_1_1_MASK, RT5645_JD_1_1_INV);
+               setup_timer(&rt5645->btn_check_timer,
+                       rt5645_btn_check_callback, (unsigned long)rt5645);
+       }
+
        INIT_DELAYED_WORK(&rt5645->jack_detect_work, rt5645_jack_detect_work);
+       INIT_DELAYED_WORK(&rt5645->rcclock_work, rt5645_rcclock_work);
 
        if (rt5645->i2c->irq) {
                ret = request_threaded_irq(rt5645->i2c->irq, NULL, rt5645_irq,
@@ -3621,6 +3845,7 @@ static int rt5645_i2c_remove(struct i2c_client *i2c)
                free_irq(i2c->irq, rt5645);
 
        cancel_delayed_work_sync(&rt5645->jack_detect_work);
+       cancel_delayed_work_sync(&rt5645->rcclock_work);
 
        snd_soc_unregister_codec(&i2c->dev);
        regulator_bulk_disable(ARRAY_SIZE(rt5645->supplies), rt5645->supplies);
index 093e46d559fbab24aa05efc5c74a2e8488fa49d0..205e0715c99abad45e771c0504b92a512f5b6adf 100644 (file)
@@ -2122,6 +2122,10 @@ enum {
 /* General Control3 (0xfc) */
 #define RT5645_JD_PSV_MODE                     (0x1 << 12)
 #define RT5645_IRQ_CLK_GATE_CTRL               (0x1 << 11)
+#define RT5645_DET_CLK_MASK                    (0x3 << 9)
+#define RT5645_DET_CLK_DIS                     (0x0 << 9)
+#define RT5645_DET_CLK_MODE1                   (0x1 << 9)
+#define RT5645_DET_CLK_MODE2                   (0x2 << 9)
 #define RT5645_MICINDET_MANU                   (0x1 << 7)
 #define RT5645_RING2_SLEEVE_GND                        (0x1 << 5)
 
diff --git a/sound/soc/codecs/rt5659.c b/sound/soc/codecs/rt5659.c
new file mode 100644 (file)
index 0000000..820d8fa
--- /dev/null
@@ -0,0 +1,4223 @@
+/*
+ * rt5659.c  --  RT5659/RT5658 ALSA SoC audio codec driver
+ *
+ * Copyright 2015 Realtek Semiconductor Corp.
+ * Author: Bard Liao <bardliao@realtek.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/moduleparam.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/pm.h>
+#include <linux/i2c.h>
+#include <linux/platform_device.h>
+#include <linux/spi/spi.h>
+#include <linux/acpi.h>
+#include <linux/gpio.h>
+#include <linux/gpio/consumer.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/jack.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include <sound/initval.h>
+#include <sound/tlv.h>
+#include <sound/rt5659.h>
+
+#include "rl6231.h"
+#include "rt5659.h"
+
+static const struct reg_default rt5659_reg[] = {
+       { 0x0000, 0x0000 },
+       { 0x0001, 0x4848 },
+       { 0x0002, 0x8080 },
+       { 0x0003, 0xc8c8 },
+       { 0x0004, 0xc80a },
+       { 0x0005, 0x0000 },
+       { 0x0006, 0x0000 },
+       { 0x0007, 0x0103 },
+       { 0x0008, 0x0080 },
+       { 0x0009, 0x0000 },
+       { 0x000a, 0x0000 },
+       { 0x000c, 0x0000 },
+       { 0x000d, 0x0000 },
+       { 0x000f, 0x0808 },
+       { 0x0010, 0x3080 },
+       { 0x0011, 0x4a00 },
+       { 0x0012, 0x4e00 },
+       { 0x0015, 0x42c1 },
+       { 0x0016, 0x0000 },
+       { 0x0018, 0x000b },
+       { 0x0019, 0xafaf },
+       { 0x001a, 0xafaf },
+       { 0x001b, 0x0011 },
+       { 0x001c, 0x2f2f },
+       { 0x001d, 0x2f2f },
+       { 0x001e, 0x2f2f },
+       { 0x001f, 0x0000 },
+       { 0x0020, 0x0000 },
+       { 0x0021, 0x0000 },
+       { 0x0022, 0x5757 },
+       { 0x0023, 0x0039 },
+       { 0x0026, 0xc060 },
+       { 0x0027, 0xd8d8 },
+       { 0x0029, 0x8080 },
+       { 0x002a, 0xaaaa },
+       { 0x002b, 0xaaaa },
+       { 0x002c, 0x00af },
+       { 0x002d, 0x0000 },
+       { 0x002f, 0x1002 },
+       { 0x0031, 0x5000 },
+       { 0x0032, 0x0000 },
+       { 0x0033, 0x0000 },
+       { 0x0034, 0x0000 },
+       { 0x0035, 0x0000 },
+       { 0x0036, 0x0000 },
+       { 0x003a, 0x0000 },
+       { 0x003b, 0x0000 },
+       { 0x003c, 0x007f },
+       { 0x003d, 0x0000 },
+       { 0x003e, 0x007f },
+       { 0x0040, 0x0808 },
+       { 0x0046, 0x001f },
+       { 0x0047, 0x001f },
+       { 0x0048, 0x0003 },
+       { 0x0049, 0xe061 },
+       { 0x004a, 0x0000 },
+       { 0x004b, 0x031f },
+       { 0x004d, 0x0000 },
+       { 0x004e, 0x001f },
+       { 0x004f, 0x0000 },
+       { 0x0050, 0x001f },
+       { 0x0052, 0xf000 },
+       { 0x0053, 0x0111 },
+       { 0x0054, 0x0064 },
+       { 0x0055, 0x0080 },
+       { 0x0056, 0xef0e },
+       { 0x0057, 0xf0f0 },
+       { 0x0058, 0xef0e },
+       { 0x0059, 0xf0f0 },
+       { 0x005a, 0xef0e },
+       { 0x005b, 0xf0f0 },
+       { 0x005c, 0xf000 },
+       { 0x005d, 0x0000 },
+       { 0x005e, 0x1f2c },
+       { 0x005f, 0x1f2c },
+       { 0x0060, 0x2717 },
+       { 0x0061, 0x0000 },
+       { 0x0062, 0x0000 },
+       { 0x0063, 0x003e },
+       { 0x0064, 0x0000 },
+       { 0x0065, 0x0000 },
+       { 0x0066, 0x0000 },
+       { 0x0067, 0x0000 },
+       { 0x006a, 0x0000 },
+       { 0x006b, 0x0000 },
+       { 0x006c, 0x0000 },
+       { 0x006e, 0x0000 },
+       { 0x006f, 0x0000 },
+       { 0x0070, 0x8000 },
+       { 0x0071, 0x8000 },
+       { 0x0072, 0x8000 },
+       { 0x0073, 0x1110 },
+       { 0x0074, 0xfe00 },
+       { 0x0075, 0x2409 },
+       { 0x0076, 0x000a },
+       { 0x0077, 0x00f0 },
+       { 0x0078, 0x0000 },
+       { 0x0079, 0x0000 },
+       { 0x007a, 0x0123 },
+       { 0x007b, 0x8003 },
+       { 0x0080, 0x0000 },
+       { 0x0081, 0x0000 },
+       { 0x0082, 0x0000 },
+       { 0x0083, 0x0000 },
+       { 0x0084, 0x0000 },
+       { 0x0085, 0x0000 },
+       { 0x0086, 0x0008 },
+       { 0x0087, 0x0000 },
+       { 0x0088, 0x0000 },
+       { 0x0089, 0x0000 },
+       { 0x008a, 0x0000 },
+       { 0x008b, 0x0000 },
+       { 0x008c, 0x0003 },
+       { 0x008e, 0x0000 },
+       { 0x008f, 0x1000 },
+       { 0x0090, 0x0646 },
+       { 0x0091, 0x0c16 },
+       { 0x0092, 0x0073 },
+       { 0x0093, 0x0000 },
+       { 0x0094, 0x0080 },
+       { 0x0097, 0x0000 },
+       { 0x0098, 0x0000 },
+       { 0x0099, 0x0000 },
+       { 0x009a, 0x0000 },
+       { 0x009b, 0x0000 },
+       { 0x009c, 0x007f },
+       { 0x009d, 0x0000 },
+       { 0x009e, 0x007f },
+       { 0x009f, 0x0000 },
+       { 0x00a0, 0x0060 },
+       { 0x00a1, 0x90a1 },
+       { 0x00ae, 0x2000 },
+       { 0x00af, 0x0000 },
+       { 0x00b0, 0x2000 },
+       { 0x00b1, 0x0000 },
+       { 0x00b2, 0x0000 },
+       { 0x00b6, 0x0000 },
+       { 0x00b7, 0x0000 },
+       { 0x00b8, 0x0000 },
+       { 0x00b9, 0x0000 },
+       { 0x00ba, 0x0000 },
+       { 0x00bb, 0x0000 },
+       { 0x00be, 0x0000 },
+       { 0x00bf, 0x0000 },
+       { 0x00c0, 0x0000 },
+       { 0x00c1, 0x0000 },
+       { 0x00c2, 0x0000 },
+       { 0x00c3, 0x0000 },
+       { 0x00c4, 0x0003 },
+       { 0x00c5, 0x0000 },
+       { 0x00cb, 0xa02f },
+       { 0x00cc, 0x0000 },
+       { 0x00cd, 0x0e02 },
+       { 0x00d6, 0x0000 },
+       { 0x00d7, 0x2244 },
+       { 0x00d9, 0x0809 },
+       { 0x00da, 0x0000 },
+       { 0x00db, 0x0008 },
+       { 0x00dc, 0x00c0 },
+       { 0x00dd, 0x6724 },
+       { 0x00de, 0x3131 },
+       { 0x00df, 0x0008 },
+       { 0x00e0, 0x4000 },
+       { 0x00e1, 0x3131 },
+       { 0x00e4, 0x400c },
+       { 0x00e5, 0x8031 },
+       { 0x00ea, 0xb320 },
+       { 0x00eb, 0x0000 },
+       { 0x00ec, 0xb300 },
+       { 0x00ed, 0x0000 },
+       { 0x00f0, 0x0000 },
+       { 0x00f1, 0x0202 },
+       { 0x00f2, 0x0ddd },
+       { 0x00f3, 0x0ddd },
+       { 0x00f4, 0x0ddd },
+       { 0x00f6, 0x0000 },
+       { 0x00f7, 0x0000 },
+       { 0x00f8, 0x0000 },
+       { 0x00f9, 0x0000 },
+       { 0x00fa, 0x8000 },
+       { 0x00fb, 0x0000 },
+       { 0x00fc, 0x0000 },
+       { 0x00fd, 0x0001 },
+       { 0x00fe, 0x10ec },
+       { 0x00ff, 0x6311 },
+       { 0x0100, 0xaaaa },
+       { 0x010a, 0xaaaa },
+       { 0x010b, 0x00a0 },
+       { 0x010c, 0xaeae },
+       { 0x010d, 0xaaaa },
+       { 0x010e, 0xaaa8 },
+       { 0x010f, 0xa0aa },
+       { 0x0110, 0xe02a },
+       { 0x0111, 0xa702 },
+       { 0x0112, 0xaaaa },
+       { 0x0113, 0x2800 },
+       { 0x0116, 0x0000 },
+       { 0x0117, 0x0f00 },
+       { 0x011a, 0x0020 },
+       { 0x011b, 0x0011 },
+       { 0x011c, 0x0150 },
+       { 0x011d, 0x0000 },
+       { 0x011e, 0x0000 },
+       { 0x011f, 0x0000 },
+       { 0x0120, 0x0000 },
+       { 0x0121, 0x009b },
+       { 0x0122, 0x5014 },
+       { 0x0123, 0x0421 },
+       { 0x0124, 0x7cea },
+       { 0x0125, 0x0420 },
+       { 0x0126, 0x5550 },
+       { 0x0132, 0x0000 },
+       { 0x0133, 0x0000 },
+       { 0x0137, 0x5055 },
+       { 0x0138, 0x3700 },
+       { 0x0139, 0x79a1 },
+       { 0x013a, 0x2020 },
+       { 0x013b, 0x2020 },
+       { 0x013c, 0x2005 },
+       { 0x013e, 0x1f00 },
+       { 0x013f, 0x0000 },
+       { 0x0145, 0x0002 },
+       { 0x0146, 0x0000 },
+       { 0x0147, 0x0000 },
+       { 0x0148, 0x0000 },
+       { 0x0150, 0x1813 },
+       { 0x0151, 0x0690 },
+       { 0x0152, 0x1c17 },
+       { 0x0153, 0x6883 },
+       { 0x0154, 0xd3ce },
+       { 0x0155, 0x352d },
+       { 0x0156, 0x00eb },
+       { 0x0157, 0x3717 },
+       { 0x0158, 0x4c6a },
+       { 0x0159, 0xe41b },
+       { 0x015a, 0x2a13 },
+       { 0x015b, 0xb600 },
+       { 0x015c, 0xc730 },
+       { 0x015d, 0x35d4 },
+       { 0x015e, 0x00bf },
+       { 0x0160, 0x0ec0 },
+       { 0x0161, 0x0020 },
+       { 0x0162, 0x0080 },
+       { 0x0163, 0x0800 },
+       { 0x0164, 0x0000 },
+       { 0x0165, 0x0000 },
+       { 0x0166, 0x0000 },
+       { 0x0167, 0x001f },
+       { 0x0170, 0x4e80 },
+       { 0x0171, 0x0020 },
+       { 0x0172, 0x0080 },
+       { 0x0173, 0x0800 },
+       { 0x0174, 0x000c },
+       { 0x0175, 0x0000 },
+       { 0x0190, 0x3300 },
+       { 0x0191, 0x2200 },
+       { 0x0192, 0x0000 },
+       { 0x01b0, 0x4b38 },
+       { 0x01b1, 0x0000 },
+       { 0x01b2, 0x0000 },
+       { 0x01b3, 0x0000 },
+       { 0x01c0, 0x0045 },
+       { 0x01c1, 0x0540 },
+       { 0x01c2, 0x0000 },
+       { 0x01c3, 0x0030 },
+       { 0x01c7, 0x0000 },
+       { 0x01c8, 0x5757 },
+       { 0x01c9, 0x5757 },
+       { 0x01ca, 0x5757 },
+       { 0x01cb, 0x5757 },
+       { 0x01cc, 0x5757 },
+       { 0x01cd, 0x5757 },
+       { 0x01ce, 0x006f },
+       { 0x01da, 0x0000 },
+       { 0x01db, 0x0000 },
+       { 0x01de, 0x7d00 },
+       { 0x01df, 0x10c0 },
+       { 0x01e0, 0x06a1 },
+       { 0x01e1, 0x0000 },
+       { 0x01e2, 0x0000 },
+       { 0x01e3, 0x0000 },
+       { 0x01e4, 0x0001 },
+       { 0x01e6, 0x0000 },
+       { 0x01e7, 0x0000 },
+       { 0x01e8, 0x0000 },
+       { 0x01ea, 0x0000 },
+       { 0x01eb, 0x0000 },
+       { 0x01ec, 0x0000 },
+       { 0x01ed, 0x0000 },
+       { 0x01ee, 0x0000 },
+       { 0x01ef, 0x0000 },
+       { 0x01f0, 0x0000 },
+       { 0x01f1, 0x0000 },
+       { 0x01f2, 0x0000 },
+       { 0x01f6, 0x1e04 },
+       { 0x01f7, 0x01a1 },
+       { 0x01f8, 0x0000 },
+       { 0x01f9, 0x0000 },
+       { 0x01fa, 0x0002 },
+       { 0x01fb, 0x0000 },
+       { 0x01fc, 0x0000 },
+       { 0x01fd, 0x0000 },
+       { 0x01fe, 0x0000 },
+       { 0x0200, 0x066c },
+       { 0x0201, 0x7fff },
+       { 0x0202, 0x7fff },
+       { 0x0203, 0x0000 },
+       { 0x0204, 0x0000 },
+       { 0x0205, 0x0000 },
+       { 0x0206, 0x0000 },
+       { 0x0207, 0x0000 },
+       { 0x0208, 0x0000 },
+       { 0x0256, 0x0000 },
+       { 0x0257, 0x0000 },
+       { 0x0258, 0x0000 },
+       { 0x0259, 0x0000 },
+       { 0x025a, 0x0000 },
+       { 0x025b, 0x3333 },
+       { 0x025c, 0x3333 },
+       { 0x025d, 0x3333 },
+       { 0x025e, 0x0000 },
+       { 0x025f, 0x0000 },
+       { 0x0260, 0x0000 },
+       { 0x0261, 0x0022 },
+       { 0x0262, 0x0300 },
+       { 0x0265, 0x1e80 },
+       { 0x0266, 0x0131 },
+       { 0x0267, 0x0003 },
+       { 0x0268, 0x0000 },
+       { 0x0269, 0x0000 },
+       { 0x026a, 0x0000 },
+       { 0x026b, 0x0000 },
+       { 0x026c, 0x0000 },
+       { 0x026d, 0x0000 },
+       { 0x026e, 0x0000 },
+       { 0x026f, 0x0000 },
+       { 0x0270, 0x0000 },
+       { 0x0271, 0x0000 },
+       { 0x0272, 0x0000 },
+       { 0x0273, 0x0000 },
+       { 0x0280, 0x0000 },
+       { 0x0281, 0x0000 },
+       { 0x0282, 0x0418 },
+       { 0x0283, 0x7fff },
+       { 0x0284, 0x7000 },
+       { 0x0290, 0x01d0 },
+       { 0x0291, 0x0100 },
+       { 0x02fa, 0x0000 },
+       { 0x02fb, 0x0000 },
+       { 0x02fc, 0x0000 },
+       { 0x0300, 0x001f },
+       { 0x0301, 0x032c },
+       { 0x0302, 0x5f21 },
+       { 0x0303, 0x4000 },
+       { 0x0304, 0x4000 },
+       { 0x0305, 0x0600 },
+       { 0x0306, 0x8000 },
+       { 0x0307, 0x0700 },
+       { 0x0308, 0x001f },
+       { 0x0309, 0x032c },
+       { 0x030a, 0x5f21 },
+       { 0x030b, 0x4000 },
+       { 0x030c, 0x4000 },
+       { 0x030d, 0x0600 },
+       { 0x030e, 0x8000 },
+       { 0x030f, 0x0700 },
+       { 0x0310, 0x4560 },
+       { 0x0311, 0xa4a8 },
+       { 0x0312, 0x7418 },
+       { 0x0313, 0x0000 },
+       { 0x0314, 0x0006 },
+       { 0x0315, 0x00ff },
+       { 0x0316, 0xc400 },
+       { 0x0317, 0x4560 },
+       { 0x0318, 0xa4a8 },
+       { 0x0319, 0x7418 },
+       { 0x031a, 0x0000 },
+       { 0x031b, 0x0006 },
+       { 0x031c, 0x00ff },
+       { 0x031d, 0xc400 },
+       { 0x0320, 0x0f20 },
+       { 0x0321, 0x8700 },
+       { 0x0322, 0x7dc2 },
+       { 0x0323, 0xa178 },
+       { 0x0324, 0x5383 },
+       { 0x0325, 0x7dc2 },
+       { 0x0326, 0xa178 },
+       { 0x0327, 0x5383 },
+       { 0x0328, 0x003e },
+       { 0x0329, 0x02c1 },
+       { 0x032a, 0xd37d },
+       { 0x0330, 0x00a6 },
+       { 0x0331, 0x04c3 },
+       { 0x0332, 0x27c8 },
+       { 0x0333, 0xbf50 },
+       { 0x0334, 0x0045 },
+       { 0x0335, 0x2007 },
+       { 0x0336, 0x7418 },
+       { 0x0337, 0x0501 },
+       { 0x0338, 0x0000 },
+       { 0x0339, 0x0010 },
+       { 0x033a, 0x1010 },
+       { 0x0340, 0x0800 },
+       { 0x0341, 0x0800 },
+       { 0x0342, 0x0800 },
+       { 0x0343, 0x0800 },
+       { 0x0344, 0x0000 },
+       { 0x0345, 0x0000 },
+       { 0x0346, 0x0000 },
+       { 0x0347, 0x0000 },
+       { 0x0348, 0x0000 },
+       { 0x0349, 0x0000 },
+       { 0x034a, 0x0000 },
+       { 0x034b, 0x0000 },
+       { 0x034c, 0x0000 },
+       { 0x034d, 0x0000 },
+       { 0x034e, 0x0000 },
+       { 0x034f, 0x0000 },
+       { 0x0350, 0x0000 },
+       { 0x0351, 0x0000 },
+       { 0x0352, 0x0000 },
+       { 0x0353, 0x0000 },
+       { 0x0354, 0x0000 },
+       { 0x0355, 0x0000 },
+       { 0x0356, 0x0000 },
+       { 0x0357, 0x0000 },
+       { 0x0358, 0x0000 },
+       { 0x0359, 0x0000 },
+       { 0x035a, 0x0000 },
+       { 0x035b, 0x0000 },
+       { 0x035c, 0x0000 },
+       { 0x035d, 0x0000 },
+       { 0x035e, 0x2000 },
+       { 0x035f, 0x0000 },
+       { 0x0360, 0x2000 },
+       { 0x0361, 0x2000 },
+       { 0x0362, 0x0000 },
+       { 0x0363, 0x2000 },
+       { 0x0364, 0x0200 },
+       { 0x0365, 0x0000 },
+       { 0x0366, 0x0000 },
+       { 0x0367, 0x0000 },
+       { 0x0368, 0x0000 },
+       { 0x0369, 0x0000 },
+       { 0x036a, 0x0000 },
+       { 0x036b, 0x0000 },
+       { 0x036c, 0x0000 },
+       { 0x036d, 0x0000 },
+       { 0x036e, 0x0200 },
+       { 0x036f, 0x0000 },
+       { 0x0370, 0x0000 },
+       { 0x0371, 0x0000 },
+       { 0x0372, 0x0000 },
+       { 0x0373, 0x0000 },
+       { 0x0374, 0x0000 },
+       { 0x0375, 0x0000 },
+       { 0x0376, 0x0000 },
+       { 0x0377, 0x0000 },
+       { 0x03d0, 0x0000 },
+       { 0x03d1, 0x0000 },
+       { 0x03d2, 0x0000 },
+       { 0x03d3, 0x0000 },
+       { 0x03d4, 0x2000 },
+       { 0x03d5, 0x2000 },
+       { 0x03d6, 0x0000 },
+       { 0x03d7, 0x0000 },
+       { 0x03d8, 0x2000 },
+       { 0x03d9, 0x2000 },
+       { 0x03da, 0x2000 },
+       { 0x03db, 0x2000 },
+       { 0x03dc, 0x0000 },
+       { 0x03dd, 0x0000 },
+       { 0x03de, 0x0000 },
+       { 0x03df, 0x2000 },
+       { 0x03e0, 0x0000 },
+       { 0x03e1, 0x0000 },
+       { 0x03e2, 0x0000 },
+       { 0x03e3, 0x0000 },
+       { 0x03e4, 0x0000 },
+       { 0x03e5, 0x0000 },
+       { 0x03e6, 0x0000 },
+       { 0x03e7, 0x0000 },
+       { 0x03e8, 0x0000 },
+       { 0x03e9, 0x0000 },
+       { 0x03ea, 0x0000 },
+       { 0x03eb, 0x0000 },
+       { 0x03ec, 0x0000 },
+       { 0x03ed, 0x0000 },
+       { 0x03ee, 0x0000 },
+       { 0x03ef, 0x0000 },
+       { 0x03f0, 0x0800 },
+       { 0x03f1, 0x0800 },
+       { 0x03f2, 0x0800 },
+       { 0x03f3, 0x0800 },
+};
+
+static bool rt5659_volatile_register(struct device *dev, unsigned int reg)
+{
+       switch (reg) {
+       case RT5659_RESET:
+       case RT5659_EJD_CTRL_2:
+       case RT5659_SILENCE_CTRL:
+       case RT5659_DAC2_DIG_VOL:
+       case RT5659_HP_IMP_GAIN_2:
+       case RT5659_PDM_OUT_CTRL:
+       case RT5659_PDM_DATA_CTRL_1:
+       case RT5659_PDM_DATA_CTRL_4:
+       case RT5659_HAPTIC_GEN_CTRL_1:
+       case RT5659_HAPTIC_GEN_CTRL_3:
+       case RT5659_HAPTIC_LPF_CTRL_3:
+       case RT5659_CLK_DET:
+       case RT5659_MICBIAS_1:
+       case RT5659_ASRC_11:
+       case RT5659_ADC_EQ_CTRL_1:
+       case RT5659_DAC_EQ_CTRL_1:
+       case RT5659_INT_ST_1:
+       case RT5659_INT_ST_2:
+       case RT5659_GPIO_STA:
+       case RT5659_SINE_GEN_CTRL_1:
+       case RT5659_IL_CMD_1:
+       case RT5659_4BTN_IL_CMD_1:
+       case RT5659_PSV_IL_CMD_1:
+       case RT5659_AJD1_CTRL:
+       case RT5659_AJD2_AJD3_CTRL:
+       case RT5659_JD_CTRL_3:
+       case RT5659_VENDOR_ID:
+       case RT5659_VENDOR_ID_1:
+       case RT5659_DEVICE_ID:
+       case RT5659_MEMORY_TEST:
+       case RT5659_SOFT_RAMP_DEPOP_DAC_CLK_CTRL:
+       case RT5659_VOL_TEST:
+       case RT5659_STO_NG2_CTRL_1:
+       case RT5659_STO_NG2_CTRL_5:
+       case RT5659_STO_NG2_CTRL_6:
+       case RT5659_STO_NG2_CTRL_7:
+       case RT5659_MONO_NG2_CTRL_1:
+       case RT5659_MONO_NG2_CTRL_5:
+       case RT5659_MONO_NG2_CTRL_6:
+       case RT5659_HP_IMP_SENS_CTRL_1:
+       case RT5659_HP_IMP_SENS_CTRL_3:
+       case RT5659_HP_IMP_SENS_CTRL_4:
+       case RT5659_HP_CALIB_CTRL_1:
+       case RT5659_HP_CALIB_CTRL_9:
+       case RT5659_HP_CALIB_STA_1:
+       case RT5659_HP_CALIB_STA_2:
+       case RT5659_HP_CALIB_STA_3:
+       case RT5659_HP_CALIB_STA_4:
+       case RT5659_HP_CALIB_STA_5:
+       case RT5659_HP_CALIB_STA_6:
+       case RT5659_HP_CALIB_STA_7:
+       case RT5659_HP_CALIB_STA_8:
+       case RT5659_HP_CALIB_STA_9:
+       case RT5659_MONO_AMP_CALIB_CTRL_1:
+       case RT5659_MONO_AMP_CALIB_CTRL_3:
+       case RT5659_MONO_AMP_CALIB_STA_1:
+       case RT5659_MONO_AMP_CALIB_STA_2:
+       case RT5659_MONO_AMP_CALIB_STA_3:
+       case RT5659_MONO_AMP_CALIB_STA_4:
+       case RT5659_SPK_PWR_LMT_STA_1:
+       case RT5659_SPK_PWR_LMT_STA_2:
+       case RT5659_SPK_PWR_LMT_STA_3:
+       case RT5659_SPK_PWR_LMT_STA_4:
+       case RT5659_SPK_PWR_LMT_STA_5:
+       case RT5659_SPK_PWR_LMT_STA_6:
+       case RT5659_SPK_DC_CAILB_CTRL_1:
+       case RT5659_SPK_DC_CAILB_STA_1:
+       case RT5659_SPK_DC_CAILB_STA_2:
+       case RT5659_SPK_DC_CAILB_STA_3:
+       case RT5659_SPK_DC_CAILB_STA_4:
+       case RT5659_SPK_DC_CAILB_STA_5:
+       case RT5659_SPK_DC_CAILB_STA_6:
+       case RT5659_SPK_DC_CAILB_STA_7:
+       case RT5659_SPK_DC_CAILB_STA_8:
+       case RT5659_SPK_DC_CAILB_STA_9:
+       case RT5659_SPK_DC_CAILB_STA_10:
+       case RT5659_SPK_VDD_STA_1:
+       case RT5659_SPK_VDD_STA_2:
+       case RT5659_SPK_DC_DET_CTRL_1:
+       case RT5659_PURE_DC_DET_CTRL_1:
+       case RT5659_PURE_DC_DET_CTRL_2:
+       case RT5659_DRC1_PRIV_1:
+       case RT5659_DRC1_PRIV_4:
+       case RT5659_DRC1_PRIV_5:
+       case RT5659_DRC1_PRIV_6:
+       case RT5659_DRC1_PRIV_7:
+       case RT5659_DRC2_PRIV_1:
+       case RT5659_DRC2_PRIV_4:
+       case RT5659_DRC2_PRIV_5:
+       case RT5659_DRC2_PRIV_6:
+       case RT5659_DRC2_PRIV_7:
+       case RT5659_ALC_PGA_STA_1:
+       case RT5659_ALC_PGA_STA_2:
+       case RT5659_ALC_PGA_STA_3:
+               return true;
+       default:
+               return false;
+       }
+}
+
+static bool rt5659_readable_register(struct device *dev, unsigned int reg)
+{
+       switch (reg) {
+       case RT5659_RESET:
+       case RT5659_SPO_VOL:
+       case RT5659_HP_VOL:
+       case RT5659_LOUT:
+       case RT5659_MONO_OUT:
+       case RT5659_HPL_GAIN:
+       case RT5659_HPR_GAIN:
+       case RT5659_MONO_GAIN:
+       case RT5659_SPDIF_CTRL_1:
+       case RT5659_SPDIF_CTRL_2:
+       case RT5659_CAL_BST_CTRL:
+       case RT5659_IN1_IN2:
+       case RT5659_IN3_IN4:
+       case RT5659_INL1_INR1_VOL:
+       case RT5659_EJD_CTRL_1:
+       case RT5659_EJD_CTRL_2:
+       case RT5659_EJD_CTRL_3:
+       case RT5659_SILENCE_CTRL:
+       case RT5659_PSV_CTRL:
+       case RT5659_SIDETONE_CTRL:
+       case RT5659_DAC1_DIG_VOL:
+       case RT5659_DAC2_DIG_VOL:
+       case RT5659_DAC_CTRL:
+       case RT5659_STO1_ADC_DIG_VOL:
+       case RT5659_MONO_ADC_DIG_VOL:
+       case RT5659_STO2_ADC_DIG_VOL:
+       case RT5659_STO1_BOOST:
+       case RT5659_MONO_BOOST:
+       case RT5659_STO2_BOOST:
+       case RT5659_HP_IMP_GAIN_1:
+       case RT5659_HP_IMP_GAIN_2:
+       case RT5659_STO1_ADC_MIXER:
+       case RT5659_MONO_ADC_MIXER:
+       case RT5659_AD_DA_MIXER:
+       case RT5659_STO_DAC_MIXER:
+       case RT5659_MONO_DAC_MIXER:
+       case RT5659_DIG_MIXER:
+       case RT5659_A_DAC_MUX:
+       case RT5659_DIG_INF23_DATA:
+       case RT5659_PDM_OUT_CTRL:
+       case RT5659_PDM_DATA_CTRL_1:
+       case RT5659_PDM_DATA_CTRL_2:
+       case RT5659_PDM_DATA_CTRL_3:
+       case RT5659_PDM_DATA_CTRL_4:
+       case RT5659_SPDIF_CTRL:
+       case RT5659_REC1_GAIN:
+       case RT5659_REC1_L1_MIXER:
+       case RT5659_REC1_L2_MIXER:
+       case RT5659_REC1_R1_MIXER:
+       case RT5659_REC1_R2_MIXER:
+       case RT5659_CAL_REC:
+       case RT5659_REC2_L1_MIXER:
+       case RT5659_REC2_L2_MIXER:
+       case RT5659_REC2_R1_MIXER:
+       case RT5659_REC2_R2_MIXER:
+       case RT5659_SPK_L_MIXER:
+       case RT5659_SPK_R_MIXER:
+       case RT5659_SPO_AMP_GAIN:
+       case RT5659_ALC_BACK_GAIN:
+       case RT5659_MONOMIX_GAIN:
+       case RT5659_MONOMIX_IN_GAIN:
+       case RT5659_OUT_L_GAIN:
+       case RT5659_OUT_L_MIXER:
+       case RT5659_OUT_R_GAIN:
+       case RT5659_OUT_R_MIXER:
+       case RT5659_LOUT_MIXER:
+       case RT5659_HAPTIC_GEN_CTRL_1:
+       case RT5659_HAPTIC_GEN_CTRL_2:
+       case RT5659_HAPTIC_GEN_CTRL_3:
+       case RT5659_HAPTIC_GEN_CTRL_4:
+       case RT5659_HAPTIC_GEN_CTRL_5:
+       case RT5659_HAPTIC_GEN_CTRL_6:
+       case RT5659_HAPTIC_GEN_CTRL_7:
+       case RT5659_HAPTIC_GEN_CTRL_8:
+       case RT5659_HAPTIC_GEN_CTRL_9:
+       case RT5659_HAPTIC_GEN_CTRL_10:
+       case RT5659_HAPTIC_GEN_CTRL_11:
+       case RT5659_HAPTIC_LPF_CTRL_1:
+       case RT5659_HAPTIC_LPF_CTRL_2:
+       case RT5659_HAPTIC_LPF_CTRL_3:
+       case RT5659_PWR_DIG_1:
+       case RT5659_PWR_DIG_2:
+       case RT5659_PWR_ANLG_1:
+       case RT5659_PWR_ANLG_2:
+       case RT5659_PWR_ANLG_3:
+       case RT5659_PWR_MIXER:
+       case RT5659_PWR_VOL:
+       case RT5659_PRIV_INDEX:
+       case RT5659_CLK_DET:
+       case RT5659_PRIV_DATA:
+       case RT5659_PRE_DIV_1:
+       case RT5659_PRE_DIV_2:
+       case RT5659_I2S1_SDP:
+       case RT5659_I2S2_SDP:
+       case RT5659_I2S3_SDP:
+       case RT5659_ADDA_CLK_1:
+       case RT5659_ADDA_CLK_2:
+       case RT5659_DMIC_CTRL_1:
+       case RT5659_DMIC_CTRL_2:
+       case RT5659_TDM_CTRL_1:
+       case RT5659_TDM_CTRL_2:
+       case RT5659_TDM_CTRL_3:
+       case RT5659_TDM_CTRL_4:
+       case RT5659_TDM_CTRL_5:
+       case RT5659_GLB_CLK:
+       case RT5659_PLL_CTRL_1:
+       case RT5659_PLL_CTRL_2:
+       case RT5659_ASRC_1:
+       case RT5659_ASRC_2:
+       case RT5659_ASRC_3:
+       case RT5659_ASRC_4:
+       case RT5659_ASRC_5:
+       case RT5659_ASRC_6:
+       case RT5659_ASRC_7:
+       case RT5659_ASRC_8:
+       case RT5659_ASRC_9:
+       case RT5659_ASRC_10:
+       case RT5659_DEPOP_1:
+       case RT5659_DEPOP_2:
+       case RT5659_DEPOP_3:
+       case RT5659_HP_CHARGE_PUMP_1:
+       case RT5659_HP_CHARGE_PUMP_2:
+       case RT5659_MICBIAS_1:
+       case RT5659_MICBIAS_2:
+       case RT5659_ASRC_11:
+       case RT5659_ASRC_12:
+       case RT5659_ASRC_13:
+       case RT5659_REC_M1_M2_GAIN_CTRL:
+       case RT5659_RC_CLK_CTRL:
+       case RT5659_CLASSD_CTRL_1:
+       case RT5659_CLASSD_CTRL_2:
+       case RT5659_ADC_EQ_CTRL_1:
+       case RT5659_ADC_EQ_CTRL_2:
+       case RT5659_DAC_EQ_CTRL_1:
+       case RT5659_DAC_EQ_CTRL_2:
+       case RT5659_DAC_EQ_CTRL_3:
+       case RT5659_IRQ_CTRL_1:
+       case RT5659_IRQ_CTRL_2:
+       case RT5659_IRQ_CTRL_3:
+       case RT5659_IRQ_CTRL_4:
+       case RT5659_IRQ_CTRL_5:
+       case RT5659_IRQ_CTRL_6:
+       case RT5659_INT_ST_1:
+       case RT5659_INT_ST_2:
+       case RT5659_GPIO_CTRL_1:
+       case RT5659_GPIO_CTRL_2:
+       case RT5659_GPIO_CTRL_3:
+       case RT5659_GPIO_CTRL_4:
+       case RT5659_GPIO_CTRL_5:
+       case RT5659_GPIO_STA:
+       case RT5659_SINE_GEN_CTRL_1:
+       case RT5659_SINE_GEN_CTRL_2:
+       case RT5659_SINE_GEN_CTRL_3:
+       case RT5659_HP_AMP_DET_CTRL_1:
+       case RT5659_HP_AMP_DET_CTRL_2:
+       case RT5659_SV_ZCD_1:
+       case RT5659_SV_ZCD_2:
+       case RT5659_IL_CMD_1:
+       case RT5659_IL_CMD_2:
+       case RT5659_IL_CMD_3:
+       case RT5659_IL_CMD_4:
+       case RT5659_4BTN_IL_CMD_1:
+       case RT5659_4BTN_IL_CMD_2:
+       case RT5659_4BTN_IL_CMD_3:
+       case RT5659_PSV_IL_CMD_1:
+       case RT5659_PSV_IL_CMD_2:
+       case RT5659_ADC_STO1_HP_CTRL_1:
+       case RT5659_ADC_STO1_HP_CTRL_2:
+       case RT5659_ADC_MONO_HP_CTRL_1:
+       case RT5659_ADC_MONO_HP_CTRL_2:
+       case RT5659_AJD1_CTRL:
+       case RT5659_AJD2_AJD3_CTRL:
+       case RT5659_JD1_THD:
+       case RT5659_JD2_THD:
+       case RT5659_JD3_THD:
+       case RT5659_JD_CTRL_1:
+       case RT5659_JD_CTRL_2:
+       case RT5659_JD_CTRL_3:
+       case RT5659_JD_CTRL_4:
+       case RT5659_DIG_MISC:
+       case RT5659_DUMMY_2:
+       case RT5659_DUMMY_3:
+       case RT5659_VENDOR_ID:
+       case RT5659_VENDOR_ID_1:
+       case RT5659_DEVICE_ID:
+       case RT5659_DAC_ADC_DIG_VOL:
+       case RT5659_BIAS_CUR_CTRL_1:
+       case RT5659_BIAS_CUR_CTRL_2:
+       case RT5659_BIAS_CUR_CTRL_3:
+       case RT5659_BIAS_CUR_CTRL_4:
+       case RT5659_BIAS_CUR_CTRL_5:
+       case RT5659_BIAS_CUR_CTRL_6:
+       case RT5659_BIAS_CUR_CTRL_7:
+       case RT5659_BIAS_CUR_CTRL_8:
+       case RT5659_BIAS_CUR_CTRL_9:
+       case RT5659_BIAS_CUR_CTRL_10:
+       case RT5659_MEMORY_TEST:
+       case RT5659_VREF_REC_OP_FB_CAP_CTRL:
+       case RT5659_CLASSD_0:
+       case RT5659_CLASSD_1:
+       case RT5659_CLASSD_2:
+       case RT5659_CLASSD_3:
+       case RT5659_CLASSD_4:
+       case RT5659_CLASSD_5:
+       case RT5659_CLASSD_6:
+       case RT5659_CLASSD_7:
+       case RT5659_CLASSD_8:
+       case RT5659_CLASSD_9:
+       case RT5659_CLASSD_10:
+       case RT5659_CHARGE_PUMP_1:
+       case RT5659_CHARGE_PUMP_2:
+       case RT5659_DIG_IN_CTRL_1:
+       case RT5659_DIG_IN_CTRL_2:
+       case RT5659_PAD_DRIVING_CTRL:
+       case RT5659_SOFT_RAMP_DEPOP:
+       case RT5659_PLL:
+       case RT5659_CHOP_DAC:
+       case RT5659_CHOP_ADC:
+       case RT5659_CALIB_ADC_CTRL:
+       case RT5659_SOFT_RAMP_DEPOP_DAC_CLK_CTRL:
+       case RT5659_VOL_TEST:
+       case RT5659_TEST_MODE_CTRL_1:
+       case RT5659_TEST_MODE_CTRL_2:
+       case RT5659_TEST_MODE_CTRL_3:
+       case RT5659_TEST_MODE_CTRL_4:
+       case RT5659_BASSBACK_CTRL:
+       case RT5659_MP3_PLUS_CTRL_1:
+       case RT5659_MP3_PLUS_CTRL_2:
+       case RT5659_MP3_HPF_A1:
+       case RT5659_MP3_HPF_A2:
+       case RT5659_MP3_HPF_H0:
+       case RT5659_MP3_LPF_H0:
+       case RT5659_3D_SPK_CTRL:
+       case RT5659_3D_SPK_COEF_1:
+       case RT5659_3D_SPK_COEF_2:
+       case RT5659_3D_SPK_COEF_3:
+       case RT5659_3D_SPK_COEF_4:
+       case RT5659_3D_SPK_COEF_5:
+       case RT5659_3D_SPK_COEF_6:
+       case RT5659_3D_SPK_COEF_7:
+       case RT5659_STO_NG2_CTRL_1:
+       case RT5659_STO_NG2_CTRL_2:
+       case RT5659_STO_NG2_CTRL_3:
+       case RT5659_STO_NG2_CTRL_4:
+       case RT5659_STO_NG2_CTRL_5:
+       case RT5659_STO_NG2_CTRL_6:
+       case RT5659_STO_NG2_CTRL_7:
+       case RT5659_STO_NG2_CTRL_8:
+       case RT5659_MONO_NG2_CTRL_1:
+       case RT5659_MONO_NG2_CTRL_2:
+       case RT5659_MONO_NG2_CTRL_3:
+       case RT5659_MONO_NG2_CTRL_4:
+       case RT5659_MONO_NG2_CTRL_5:
+       case RT5659_MONO_NG2_CTRL_6:
+       case RT5659_MID_HP_AMP_DET:
+       case RT5659_LOW_HP_AMP_DET:
+       case RT5659_LDO_CTRL:
+       case RT5659_HP_DECROSS_CTRL_1:
+       case RT5659_HP_DECROSS_CTRL_2:
+       case RT5659_HP_DECROSS_CTRL_3:
+       case RT5659_HP_DECROSS_CTRL_4:
+       case RT5659_HP_IMP_SENS_CTRL_1:
+       case RT5659_HP_IMP_SENS_CTRL_2:
+       case RT5659_HP_IMP_SENS_CTRL_3:
+       case RT5659_HP_IMP_SENS_CTRL_4:
+       case RT5659_HP_IMP_SENS_MAP_1:
+       case RT5659_HP_IMP_SENS_MAP_2:
+       case RT5659_HP_IMP_SENS_MAP_3:
+       case RT5659_HP_IMP_SENS_MAP_4:
+       case RT5659_HP_IMP_SENS_MAP_5:
+       case RT5659_HP_IMP_SENS_MAP_6:
+       case RT5659_HP_IMP_SENS_MAP_7:
+       case RT5659_HP_IMP_SENS_MAP_8:
+       case RT5659_HP_LOGIC_CTRL_1:
+       case RT5659_HP_LOGIC_CTRL_2:
+       case RT5659_HP_CALIB_CTRL_1:
+       case RT5659_HP_CALIB_CTRL_2:
+       case RT5659_HP_CALIB_CTRL_3:
+       case RT5659_HP_CALIB_CTRL_4:
+       case RT5659_HP_CALIB_CTRL_5:
+       case RT5659_HP_CALIB_CTRL_6:
+       case RT5659_HP_CALIB_CTRL_7:
+       case RT5659_HP_CALIB_CTRL_9:
+       case RT5659_HP_CALIB_CTRL_10:
+       case RT5659_HP_CALIB_CTRL_11:
+       case RT5659_HP_CALIB_STA_1:
+       case RT5659_HP_CALIB_STA_2:
+       case RT5659_HP_CALIB_STA_3:
+       case RT5659_HP_CALIB_STA_4:
+       case RT5659_HP_CALIB_STA_5:
+       case RT5659_HP_CALIB_STA_6:
+       case RT5659_HP_CALIB_STA_7:
+       case RT5659_HP_CALIB_STA_8:
+       case RT5659_HP_CALIB_STA_9:
+       case RT5659_MONO_AMP_CALIB_CTRL_1:
+       case RT5659_MONO_AMP_CALIB_CTRL_2:
+       case RT5659_MONO_AMP_CALIB_CTRL_3:
+       case RT5659_MONO_AMP_CALIB_CTRL_4:
+       case RT5659_MONO_AMP_CALIB_CTRL_5:
+       case RT5659_MONO_AMP_CALIB_STA_1:
+       case RT5659_MONO_AMP_CALIB_STA_2:
+       case RT5659_MONO_AMP_CALIB_STA_3:
+       case RT5659_MONO_AMP_CALIB_STA_4:
+       case RT5659_SPK_PWR_LMT_CTRL_1:
+       case RT5659_SPK_PWR_LMT_CTRL_2:
+       case RT5659_SPK_PWR_LMT_CTRL_3:
+       case RT5659_SPK_PWR_LMT_STA_1:
+       case RT5659_SPK_PWR_LMT_STA_2:
+       case RT5659_SPK_PWR_LMT_STA_3:
+       case RT5659_SPK_PWR_LMT_STA_4:
+       case RT5659_SPK_PWR_LMT_STA_5:
+       case RT5659_SPK_PWR_LMT_STA_6:
+       case RT5659_FLEX_SPK_BST_CTRL_1:
+       case RT5659_FLEX_SPK_BST_CTRL_2:
+       case RT5659_FLEX_SPK_BST_CTRL_3:
+       case RT5659_FLEX_SPK_BST_CTRL_4:
+       case RT5659_SPK_EX_LMT_CTRL_1:
+       case RT5659_SPK_EX_LMT_CTRL_2:
+       case RT5659_SPK_EX_LMT_CTRL_3:
+       case RT5659_SPK_EX_LMT_CTRL_4:
+       case RT5659_SPK_EX_LMT_CTRL_5:
+       case RT5659_SPK_EX_LMT_CTRL_6:
+       case RT5659_SPK_EX_LMT_CTRL_7:
+       case RT5659_ADJ_HPF_CTRL_1:
+       case RT5659_ADJ_HPF_CTRL_2:
+       case RT5659_SPK_DC_CAILB_CTRL_1:
+       case RT5659_SPK_DC_CAILB_CTRL_2:
+       case RT5659_SPK_DC_CAILB_CTRL_3:
+       case RT5659_SPK_DC_CAILB_CTRL_4:
+       case RT5659_SPK_DC_CAILB_CTRL_5:
+       case RT5659_SPK_DC_CAILB_STA_1:
+       case RT5659_SPK_DC_CAILB_STA_2:
+       case RT5659_SPK_DC_CAILB_STA_3:
+       case RT5659_SPK_DC_CAILB_STA_4:
+       case RT5659_SPK_DC_CAILB_STA_5:
+       case RT5659_SPK_DC_CAILB_STA_6:
+       case RT5659_SPK_DC_CAILB_STA_7:
+       case RT5659_SPK_DC_CAILB_STA_8:
+       case RT5659_SPK_DC_CAILB_STA_9:
+       case RT5659_SPK_DC_CAILB_STA_10:
+       case RT5659_SPK_VDD_STA_1:
+       case RT5659_SPK_VDD_STA_2:
+       case RT5659_SPK_DC_DET_CTRL_1:
+       case RT5659_SPK_DC_DET_CTRL_2:
+       case RT5659_SPK_DC_DET_CTRL_3:
+       case RT5659_PURE_DC_DET_CTRL_1:
+       case RT5659_PURE_DC_DET_CTRL_2:
+       case RT5659_DUMMY_4:
+       case RT5659_DUMMY_5:
+       case RT5659_DUMMY_6:
+       case RT5659_DRC1_CTRL_1:
+       case RT5659_DRC1_CTRL_2:
+       case RT5659_DRC1_CTRL_3:
+       case RT5659_DRC1_CTRL_4:
+       case RT5659_DRC1_CTRL_5:
+       case RT5659_DRC1_CTRL_6:
+       case RT5659_DRC1_HARD_LMT_CTRL_1:
+       case RT5659_DRC1_HARD_LMT_CTRL_2:
+       case RT5659_DRC2_CTRL_1:
+       case RT5659_DRC2_CTRL_2:
+       case RT5659_DRC2_CTRL_3:
+       case RT5659_DRC2_CTRL_4:
+       case RT5659_DRC2_CTRL_5:
+       case RT5659_DRC2_CTRL_6:
+       case RT5659_DRC2_HARD_LMT_CTRL_1:
+       case RT5659_DRC2_HARD_LMT_CTRL_2:
+       case RT5659_DRC1_PRIV_1:
+       case RT5659_DRC1_PRIV_2:
+       case RT5659_DRC1_PRIV_3:
+       case RT5659_DRC1_PRIV_4:
+       case RT5659_DRC1_PRIV_5:
+       case RT5659_DRC1_PRIV_6:
+       case RT5659_DRC1_PRIV_7:
+       case RT5659_DRC2_PRIV_1:
+       case RT5659_DRC2_PRIV_2:
+       case RT5659_DRC2_PRIV_3:
+       case RT5659_DRC2_PRIV_4:
+       case RT5659_DRC2_PRIV_5:
+       case RT5659_DRC2_PRIV_6:
+       case RT5659_DRC2_PRIV_7:
+       case RT5659_MULTI_DRC_CTRL:
+       case RT5659_CROSS_OVER_1:
+       case RT5659_CROSS_OVER_2:
+       case RT5659_CROSS_OVER_3:
+       case RT5659_CROSS_OVER_4:
+       case RT5659_CROSS_OVER_5:
+       case RT5659_CROSS_OVER_6:
+       case RT5659_CROSS_OVER_7:
+       case RT5659_CROSS_OVER_8:
+       case RT5659_CROSS_OVER_9:
+       case RT5659_CROSS_OVER_10:
+       case RT5659_ALC_PGA_CTRL_1:
+       case RT5659_ALC_PGA_CTRL_2:
+       case RT5659_ALC_PGA_CTRL_3:
+       case RT5659_ALC_PGA_CTRL_4:
+       case RT5659_ALC_PGA_CTRL_5:
+       case RT5659_ALC_PGA_CTRL_6:
+       case RT5659_ALC_PGA_CTRL_7:
+       case RT5659_ALC_PGA_CTRL_8:
+       case RT5659_ALC_PGA_STA_1:
+       case RT5659_ALC_PGA_STA_2:
+       case RT5659_ALC_PGA_STA_3:
+       case RT5659_DAC_L_EQ_PRE_VOL:
+       case RT5659_DAC_R_EQ_PRE_VOL:
+       case RT5659_DAC_L_EQ_POST_VOL:
+       case RT5659_DAC_R_EQ_POST_VOL:
+       case RT5659_DAC_L_EQ_LPF1_A1:
+       case RT5659_DAC_L_EQ_LPF1_H0:
+       case RT5659_DAC_R_EQ_LPF1_A1:
+       case RT5659_DAC_R_EQ_LPF1_H0:
+       case RT5659_DAC_L_EQ_BPF2_A1:
+       case RT5659_DAC_L_EQ_BPF2_A2:
+       case RT5659_DAC_L_EQ_BPF2_H0:
+       case RT5659_DAC_R_EQ_BPF2_A1:
+       case RT5659_DAC_R_EQ_BPF2_A2:
+       case RT5659_DAC_R_EQ_BPF2_H0:
+       case RT5659_DAC_L_EQ_BPF3_A1:
+       case RT5659_DAC_L_EQ_BPF3_A2:
+       case RT5659_DAC_L_EQ_BPF3_H0:
+       case RT5659_DAC_R_EQ_BPF3_A1:
+       case RT5659_DAC_R_EQ_BPF3_A2:
+       case RT5659_DAC_R_EQ_BPF3_H0:
+       case RT5659_DAC_L_EQ_BPF4_A1:
+       case RT5659_DAC_L_EQ_BPF4_A2:
+       case RT5659_DAC_L_EQ_BPF4_H0:
+       case RT5659_DAC_R_EQ_BPF4_A1:
+       case RT5659_DAC_R_EQ_BPF4_A2:
+       case RT5659_DAC_R_EQ_BPF4_H0:
+       case RT5659_DAC_L_EQ_HPF1_A1:
+       case RT5659_DAC_L_EQ_HPF1_H0:
+       case RT5659_DAC_R_EQ_HPF1_A1:
+       case RT5659_DAC_R_EQ_HPF1_H0:
+       case RT5659_DAC_L_EQ_HPF2_A1:
+       case RT5659_DAC_L_EQ_HPF2_A2:
+       case RT5659_DAC_L_EQ_HPF2_H0:
+       case RT5659_DAC_R_EQ_HPF2_A1:
+       case RT5659_DAC_R_EQ_HPF2_A2:
+       case RT5659_DAC_R_EQ_HPF2_H0:
+       case RT5659_DAC_L_BI_EQ_BPF1_H0_1:
+       case RT5659_DAC_L_BI_EQ_BPF1_H0_2:
+       case RT5659_DAC_L_BI_EQ_BPF1_B1_1:
+       case RT5659_DAC_L_BI_EQ_BPF1_B1_2:
+       case RT5659_DAC_L_BI_EQ_BPF1_B2_1:
+       case RT5659_DAC_L_BI_EQ_BPF1_B2_2:
+       case RT5659_DAC_L_BI_EQ_BPF1_A1_1:
+       case RT5659_DAC_L_BI_EQ_BPF1_A1_2:
+       case RT5659_DAC_L_BI_EQ_BPF1_A2_1:
+       case RT5659_DAC_L_BI_EQ_BPF1_A2_2:
+       case RT5659_DAC_R_BI_EQ_BPF1_H0_1:
+       case RT5659_DAC_R_BI_EQ_BPF1_H0_2:
+       case RT5659_DAC_R_BI_EQ_BPF1_B1_1:
+       case RT5659_DAC_R_BI_EQ_BPF1_B1_2:
+       case RT5659_DAC_R_BI_EQ_BPF1_B2_1:
+       case RT5659_DAC_R_BI_EQ_BPF1_B2_2:
+       case RT5659_DAC_R_BI_EQ_BPF1_A1_1:
+       case RT5659_DAC_R_BI_EQ_BPF1_A1_2:
+       case RT5659_DAC_R_BI_EQ_BPF1_A2_1:
+       case RT5659_DAC_R_BI_EQ_BPF1_A2_2:
+       case RT5659_ADC_L_EQ_LPF1_A1:
+       case RT5659_ADC_R_EQ_LPF1_A1:
+       case RT5659_ADC_L_EQ_LPF1_H0:
+       case RT5659_ADC_R_EQ_LPF1_H0:
+       case RT5659_ADC_L_EQ_BPF1_A1:
+       case RT5659_ADC_R_EQ_BPF1_A1:
+       case RT5659_ADC_L_EQ_BPF1_A2:
+       case RT5659_ADC_R_EQ_BPF1_A2:
+       case RT5659_ADC_L_EQ_BPF1_H0:
+       case RT5659_ADC_R_EQ_BPF1_H0:
+       case RT5659_ADC_L_EQ_BPF2_A1:
+       case RT5659_ADC_R_EQ_BPF2_A1:
+       case RT5659_ADC_L_EQ_BPF2_A2:
+       case RT5659_ADC_R_EQ_BPF2_A2:
+       case RT5659_ADC_L_EQ_BPF2_H0:
+       case RT5659_ADC_R_EQ_BPF2_H0:
+       case RT5659_ADC_L_EQ_BPF3_A1:
+       case RT5659_ADC_R_EQ_BPF3_A1:
+       case RT5659_ADC_L_EQ_BPF3_A2:
+       case RT5659_ADC_R_EQ_BPF3_A2:
+       case RT5659_ADC_L_EQ_BPF3_H0:
+       case RT5659_ADC_R_EQ_BPF3_H0:
+       case RT5659_ADC_L_EQ_BPF4_A1:
+       case RT5659_ADC_R_EQ_BPF4_A1:
+       case RT5659_ADC_L_EQ_BPF4_A2:
+       case RT5659_ADC_R_EQ_BPF4_A2:
+       case RT5659_ADC_L_EQ_BPF4_H0:
+       case RT5659_ADC_R_EQ_BPF4_H0:
+       case RT5659_ADC_L_EQ_HPF1_A1:
+       case RT5659_ADC_R_EQ_HPF1_A1:
+       case RT5659_ADC_L_EQ_HPF1_H0:
+       case RT5659_ADC_R_EQ_HPF1_H0:
+       case RT5659_ADC_L_EQ_PRE_VOL:
+       case RT5659_ADC_R_EQ_PRE_VOL:
+       case RT5659_ADC_L_EQ_POST_VOL:
+       case RT5659_ADC_R_EQ_POST_VOL:
+               return true;
+       default:
+               return false;
+       }
+}
+
+static const DECLARE_TLV_DB_SCALE(hp_vol_tlv, -2325, 75, 0);
+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);
+static const DECLARE_TLV_DB_SCALE(adc_vol_tlv, -17625, 375, 0);
+static const DECLARE_TLV_DB_SCALE(adc_bst_tlv, 0, 1200, 0);
+static const DECLARE_TLV_DB_SCALE(in_bst_tlv, -1200, 75, 0);
+
+/* Interface data select */
+static const char * const rt5659_data_select[] = {
+       "L/R", "R/L", "L/L", "R/R"
+};
+
+static const SOC_ENUM_SINGLE_DECL(rt5659_if1_01_adc_enum,
+       RT5659_TDM_CTRL_2, RT5659_DS_ADC_SLOT01_SFT, rt5659_data_select);
+
+static const SOC_ENUM_SINGLE_DECL(rt5659_if1_23_adc_enum,
+       RT5659_TDM_CTRL_2, RT5659_DS_ADC_SLOT23_SFT, rt5659_data_select);
+
+static const SOC_ENUM_SINGLE_DECL(rt5659_if1_45_adc_enum,
+       RT5659_TDM_CTRL_2, RT5659_DS_ADC_SLOT45_SFT, rt5659_data_select);
+
+static const SOC_ENUM_SINGLE_DECL(rt5659_if1_67_adc_enum,
+       RT5659_TDM_CTRL_2, RT5659_DS_ADC_SLOT67_SFT, rt5659_data_select);
+
+static const SOC_ENUM_SINGLE_DECL(rt5659_if2_dac_enum,
+       RT5659_DIG_INF23_DATA, RT5659_IF2_DAC_SEL_SFT, rt5659_data_select);
+
+static const SOC_ENUM_SINGLE_DECL(rt5659_if2_adc_enum,
+       RT5659_DIG_INF23_DATA, RT5659_IF2_ADC_SEL_SFT, rt5659_data_select);
+
+static const SOC_ENUM_SINGLE_DECL(rt5659_if3_dac_enum,
+       RT5659_DIG_INF23_DATA, RT5659_IF3_DAC_SEL_SFT, rt5659_data_select);
+
+static const SOC_ENUM_SINGLE_DECL(rt5659_if3_adc_enum,
+       RT5659_DIG_INF23_DATA, RT5659_IF3_ADC_SEL_SFT, rt5659_data_select);
+
+static const struct snd_kcontrol_new rt5659_if1_01_adc_swap_mux =
+       SOC_DAPM_ENUM("IF1 01 ADC Swap Source", rt5659_if1_01_adc_enum);
+
+static const struct snd_kcontrol_new rt5659_if1_23_adc_swap_mux =
+       SOC_DAPM_ENUM("IF1 23 ADC1 Swap Source", rt5659_if1_23_adc_enum);
+
+static const struct snd_kcontrol_new rt5659_if1_45_adc_swap_mux =
+       SOC_DAPM_ENUM("IF1 45 ADC1 Swap Source", rt5659_if1_45_adc_enum);
+
+static const struct snd_kcontrol_new rt5659_if1_67_adc_swap_mux =
+       SOC_DAPM_ENUM("IF1 67 ADC1 Swap Source", rt5659_if1_67_adc_enum);
+
+static const struct snd_kcontrol_new rt5659_if2_dac_swap_mux =
+       SOC_DAPM_ENUM("IF2 DAC Swap Source", rt5659_if2_dac_enum);
+
+static const struct snd_kcontrol_new rt5659_if2_adc_swap_mux =
+       SOC_DAPM_ENUM("IF2 ADC Swap Source", rt5659_if2_adc_enum);
+
+static const struct snd_kcontrol_new rt5659_if3_dac_swap_mux =
+       SOC_DAPM_ENUM("IF3 DAC Swap Source", rt5659_if3_dac_enum);
+
+static const struct snd_kcontrol_new rt5659_if3_adc_swap_mux =
+       SOC_DAPM_ENUM("IF3 ADC Swap Source", rt5659_if3_adc_enum);
+
+static const char * const rt5659_asrc_clk_src[] = {
+       "clk_sysy_div_out", "clk_i2s1_track", "clk_i2s2_track",
+       "clk_i2s3_track", "clk_sys2", "clk_sys3"
+};
+
+static unsigned int rt5659_asrc_clk_map_values[] = {
+       0, 1, 2, 3, 5, 6,
+};
+
+static const SOC_VALUE_ENUM_SINGLE_DECL(
+       rt5659_da_sto_asrc_enum, RT5659_ASRC_2, RT5659_DA_STO_T_SFT, 0x7,
+       rt5659_asrc_clk_src, rt5659_asrc_clk_map_values);
+
+static const SOC_VALUE_ENUM_SINGLE_DECL(
+       rt5659_da_monol_asrc_enum, RT5659_ASRC_2, RT5659_DA_MONO_L_T_SFT, 0x7,
+       rt5659_asrc_clk_src, rt5659_asrc_clk_map_values);
+
+static const SOC_VALUE_ENUM_SINGLE_DECL(
+       rt5659_da_monor_asrc_enum, RT5659_ASRC_2, RT5659_DA_MONO_R_T_SFT, 0x7,
+       rt5659_asrc_clk_src, rt5659_asrc_clk_map_values);
+
+static const SOC_VALUE_ENUM_SINGLE_DECL(
+       rt5659_ad_sto1_asrc_enum, RT5659_ASRC_2, RT5659_AD_STO1_T_SFT, 0x7,
+       rt5659_asrc_clk_src, rt5659_asrc_clk_map_values);
+
+static const SOC_VALUE_ENUM_SINGLE_DECL(
+       rt5659_ad_sto2_asrc_enum, RT5659_ASRC_3, RT5659_AD_STO2_T_SFT, 0x7,
+       rt5659_asrc_clk_src, rt5659_asrc_clk_map_values);
+
+static const SOC_VALUE_ENUM_SINGLE_DECL(
+       rt5659_ad_monol_asrc_enum, RT5659_ASRC_3, RT5659_AD_MONO_L_T_SFT, 0x7,
+       rt5659_asrc_clk_src, rt5659_asrc_clk_map_values);
+
+static const SOC_VALUE_ENUM_SINGLE_DECL(
+       rt5659_ad_monor_asrc_enum, RT5659_ASRC_3, RT5659_AD_MONO_R_T_SFT, 0x7,
+       rt5659_asrc_clk_src, rt5659_asrc_clk_map_values);
+
+static int rt5659_hp_vol_put(struct snd_kcontrol *kcontrol,
+               struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
+       int ret = snd_soc_put_volsw(kcontrol, ucontrol);
+
+       if (snd_soc_read(codec, RT5659_STO_NG2_CTRL_1) & RT5659_NG2_EN) {
+               snd_soc_update_bits(codec, RT5659_STO_NG2_CTRL_1,
+                       RT5659_NG2_EN_MASK, RT5659_NG2_DIS);
+               snd_soc_update_bits(codec, RT5659_STO_NG2_CTRL_1,
+                       RT5659_NG2_EN_MASK, RT5659_NG2_EN);
+       }
+
+       return ret;
+}
+
+static void rt5659_enable_push_button_irq(struct snd_soc_codec *codec,
+       bool enable)
+{
+       struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
+
+       if (enable) {
+               snd_soc_write(codec, RT5659_4BTN_IL_CMD_1, 0x000b);
+
+               /* MICBIAS1 and Mic Det Power for button detect*/
+               snd_soc_dapm_force_enable_pin(dapm, "MICBIAS1");
+               snd_soc_dapm_force_enable_pin(dapm,
+                       "Mic Det Power");
+               snd_soc_dapm_sync(dapm);
+
+               snd_soc_update_bits(codec, RT5659_PWR_ANLG_2,
+                       RT5659_PWR_MB1, RT5659_PWR_MB1);
+               snd_soc_update_bits(codec, RT5659_PWR_VOL,
+                       RT5659_PWR_MIC_DET, RT5659_PWR_MIC_DET);
+
+               snd_soc_update_bits(codec, RT5659_IRQ_CTRL_2,
+                               RT5659_IL_IRQ_MASK, RT5659_IL_IRQ_EN);
+               snd_soc_update_bits(codec, RT5659_4BTN_IL_CMD_2,
+                               RT5659_4BTN_IL_MASK, RT5659_4BTN_IL_EN);
+       } else {
+               snd_soc_update_bits(codec, RT5659_4BTN_IL_CMD_2,
+                               RT5659_4BTN_IL_MASK, RT5659_4BTN_IL_DIS);
+               snd_soc_update_bits(codec, RT5659_IRQ_CTRL_2,
+                               RT5659_IL_IRQ_MASK, RT5659_IL_IRQ_DIS);
+               /* MICBIAS1 and Mic Det Power for button detect*/
+               snd_soc_dapm_disable_pin(dapm, "MICBIAS1");
+               snd_soc_dapm_disable_pin(dapm, "Mic Det Power");
+               snd_soc_dapm_sync(dapm);
+       }
+}
+
+/**
+ * rt5659_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 rt5659_headset_detect(struct snd_soc_codec *codec, int jack_insert)
+{
+       struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
+       int val, i = 0, sleep_time[5] = {300, 150, 100, 50, 30};
+       int reg_63;
+
+       struct rt5659_priv *rt5659 = snd_soc_codec_get_drvdata(codec);
+
+       if (jack_insert) {
+               snd_soc_dapm_force_enable_pin(dapm,
+                       "Mic Det Power");
+               snd_soc_dapm_sync(dapm);
+               reg_63 = snd_soc_read(codec, RT5659_PWR_ANLG_1);
+
+               snd_soc_update_bits(codec, RT5659_PWR_ANLG_1,
+                       RT5659_PWR_VREF2 | RT5659_PWR_MB,
+                       RT5659_PWR_VREF2 | RT5659_PWR_MB);
+               msleep(20);
+               snd_soc_update_bits(codec, RT5659_PWR_ANLG_1,
+                       RT5659_PWR_FV2, RT5659_PWR_FV2);
+
+               snd_soc_write(codec, RT5659_EJD_CTRL_2, 0x4160);
+               snd_soc_update_bits(codec, RT5659_EJD_CTRL_1,
+                       0x20, 0x0);
+               msleep(20);
+               snd_soc_update_bits(codec, RT5659_EJD_CTRL_1,
+                       0x20, 0x20);
+
+               while (i < 5) {
+                       msleep(sleep_time[i]);
+                       val = snd_soc_read(codec, RT5659_EJD_CTRL_2) & 0x0003;
+                       i++;
+                       if (val == 0x1 || val == 0x2 || val == 0x3)
+                               break;
+               }
+
+               switch (val) {
+               case 1:
+                       rt5659->jack_type = SND_JACK_HEADSET;
+                       rt5659_enable_push_button_irq(codec, true);
+                       break;
+               default:
+                       snd_soc_write(codec, RT5659_PWR_ANLG_1, reg_63);
+                       rt5659->jack_type = SND_JACK_HEADPHONE;
+                       snd_soc_dapm_disable_pin(dapm, "Mic Det Power");
+                       snd_soc_dapm_sync(dapm);
+                       break;
+               }
+       } else {
+               snd_soc_dapm_disable_pin(dapm, "Mic Det Power");
+               snd_soc_dapm_sync(dapm);
+               if (rt5659->jack_type == SND_JACK_HEADSET)
+                       rt5659_enable_push_button_irq(codec, false);
+               rt5659->jack_type = 0;
+       }
+
+       dev_dbg(codec->dev, "jack_type = %d\n", rt5659->jack_type);
+       return rt5659->jack_type;
+}
+
+static int rt5659_button_detect(struct snd_soc_codec *codec)
+{
+       int btn_type, val;
+
+       val = snd_soc_read(codec, RT5659_4BTN_IL_CMD_1);
+       btn_type = val & 0xfff0;
+       snd_soc_write(codec, RT5659_4BTN_IL_CMD_1, val);
+
+       return btn_type;
+}
+
+static irqreturn_t rt5659_irq(int irq, void *data)
+{
+       struct rt5659_priv *rt5659 = data;
+
+       queue_delayed_work(system_power_efficient_wq,
+                          &rt5659->jack_detect_work, msecs_to_jiffies(250));
+
+       return IRQ_HANDLED;
+}
+
+int rt5659_set_jack_detect(struct snd_soc_codec *codec,
+       struct snd_soc_jack *hs_jack)
+{
+       struct rt5659_priv *rt5659 = snd_soc_codec_get_drvdata(codec);
+
+       rt5659->hs_jack = hs_jack;
+
+       rt5659_irq(0, rt5659);
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(rt5659_set_jack_detect);
+
+static void rt5659_jack_detect_work(struct work_struct *work)
+{
+       struct rt5659_priv *rt5659 =
+               container_of(work, struct rt5659_priv, jack_detect_work.work);
+       int val, btn_type, report = 0;
+
+       if (!rt5659->codec)
+               return;
+
+       val = snd_soc_read(rt5659->codec, RT5659_INT_ST_1) & 0x0080;
+       if (!val) {
+               /* jack in */
+               if (rt5659->jack_type == 0) {
+                       /* jack was out, report jack type */
+                       report = rt5659_headset_detect(rt5659->codec, 1);
+               } else {
+                       /* jack is already in, report button event */
+                       report = SND_JACK_HEADSET;
+                       btn_type = rt5659_button_detect(rt5659->codec);
+                       /**
+                        * rt5659 can report three kinds of button behavior,
+                        * one click, double click and hold. However,
+                        * currently we will report button pressed/released
+                        * event. So all the three button behaviors are
+                        * treated as button pressed.
+                        */
+                       switch (btn_type) {
+                       case 0x8000:
+                       case 0x4000:
+                       case 0x2000:
+                               report |= SND_JACK_BTN_0;
+                               break;
+                       case 0x1000:
+                       case 0x0800:
+                       case 0x0400:
+                               report |= SND_JACK_BTN_1;
+                               break;
+                       case 0x0200:
+                       case 0x0100:
+                       case 0x0080:
+                               report |= SND_JACK_BTN_2;
+                               break;
+                       case 0x0040:
+                       case 0x0020:
+                       case 0x0010:
+                               report |= SND_JACK_BTN_3;
+                               break;
+                       case 0x0000: /* unpressed */
+                               break;
+                       default:
+                               btn_type = 0;
+                               dev_err(rt5659->codec->dev,
+                                       "Unexpected button code 0x%04x\n",
+                                       btn_type);
+                               break;
+                       }
+
+                       /* button release or spurious interrput*/
+                       if (btn_type == 0)
+                               report =  rt5659->jack_type;
+               }
+       } else {
+               /* jack out */
+               report = rt5659_headset_detect(rt5659->codec, 0);
+       }
+
+       snd_soc_jack_report(rt5659->hs_jack, report, SND_JACK_HEADSET |
+                           SND_JACK_BTN_0 | SND_JACK_BTN_1 |
+                           SND_JACK_BTN_2 | SND_JACK_BTN_3);
+}
+
+static const struct snd_kcontrol_new rt5659_snd_controls[] = {
+       /* Speaker Output Volume */
+       SOC_DOUBLE_TLV("Speaker Playback Volume", RT5659_SPO_VOL,
+               RT5659_L_VOL_SFT, RT5659_R_VOL_SFT, 39, 1, out_vol_tlv),
+
+       /* Headphone Output Volume */
+       SOC_DOUBLE_R_EXT_TLV("Headphone Playback Volume", RT5659_HPL_GAIN,
+               RT5659_HPR_GAIN, RT5659_G_HP_SFT, 31, 1, snd_soc_get_volsw,
+               rt5659_hp_vol_put, hp_vol_tlv),
+
+       /* Mono Output Volume */
+       SOC_SINGLE_TLV("Mono Playback Volume", RT5659_MONO_OUT,
+               RT5659_L_VOL_SFT, 39, 1, out_vol_tlv),
+
+       /* Output Volume */
+       SOC_DOUBLE_TLV("OUT Playback Volume", RT5659_LOUT,
+               RT5659_L_VOL_SFT, RT5659_R_VOL_SFT, 39, 1, out_vol_tlv),
+
+       /* DAC Digital Volume */
+       SOC_DOUBLE_TLV("DAC1 Playback Volume", RT5659_DAC1_DIG_VOL,
+               RT5659_L_VOL_SFT, RT5659_R_VOL_SFT, 175, 0, dac_vol_tlv),
+       SOC_DOUBLE("DAC1 Playback Switch", RT5659_AD_DA_MIXER,
+               RT5659_M_DAC1_L_SFT, RT5659_M_DAC1_R_SFT, 1, 1),
+
+       SOC_DOUBLE_TLV("DAC2 Playback Volume", RT5659_DAC2_DIG_VOL,
+               RT5659_L_VOL_SFT, RT5659_R_VOL_SFT, 175, 0, dac_vol_tlv),
+       SOC_DOUBLE("DAC2 Playback Switch", RT5659_DAC_CTRL,
+               RT5659_M_DAC2_L_VOL_SFT, RT5659_M_DAC2_R_VOL_SFT, 1, 1),
+
+       /* IN1/IN2/IN3/IN4 Volume */
+       SOC_SINGLE_TLV("IN1 Boost Volume", RT5659_IN1_IN2,
+               RT5659_BST1_SFT, 69, 0, in_bst_tlv),
+       SOC_SINGLE_TLV("IN2 Boost Volume", RT5659_IN1_IN2,
+               RT5659_BST2_SFT, 69, 0, in_bst_tlv),
+       SOC_SINGLE_TLV("IN3 Boost Volume", RT5659_IN3_IN4,
+               RT5659_BST3_SFT, 69, 0, in_bst_tlv),
+       SOC_SINGLE_TLV("IN4 Boost Volume", RT5659_IN3_IN4,
+               RT5659_BST4_SFT, 69, 0, in_bst_tlv),
+
+       /* INL/INR Volume Control */
+       SOC_DOUBLE_TLV("IN Capture Volume", RT5659_INL1_INR1_VOL,
+               RT5659_INL_VOL_SFT, RT5659_INR_VOL_SFT, 31, 1, in_vol_tlv),
+
+       /* ADC Digital Volume Control */
+       SOC_DOUBLE("STO1 ADC Capture Switch", RT5659_STO1_ADC_DIG_VOL,
+               RT5659_L_MUTE_SFT, RT5659_R_MUTE_SFT, 1, 1),
+       SOC_DOUBLE_TLV("STO1 ADC Capture Volume", RT5659_STO1_ADC_DIG_VOL,
+               RT5659_L_VOL_SFT, RT5659_R_VOL_SFT, 127, 0, adc_vol_tlv),
+       SOC_DOUBLE("Mono ADC Capture Switch", RT5659_MONO_ADC_DIG_VOL,
+               RT5659_L_MUTE_SFT, RT5659_R_MUTE_SFT, 1, 1),
+       SOC_DOUBLE_TLV("Mono ADC Capture Volume", RT5659_MONO_ADC_DIG_VOL,
+               RT5659_L_VOL_SFT, RT5659_R_VOL_SFT, 127, 0, adc_vol_tlv),
+       SOC_DOUBLE("STO2 ADC Capture Switch", RT5659_STO2_ADC_DIG_VOL,
+               RT5659_L_MUTE_SFT, RT5659_R_MUTE_SFT, 1, 1),
+       SOC_DOUBLE_TLV("STO2 ADC Capture Volume", RT5659_STO2_ADC_DIG_VOL,
+               RT5659_L_VOL_SFT, RT5659_R_VOL_SFT, 127, 0, adc_vol_tlv),
+
+       /* ADC Boost Volume Control */
+       SOC_DOUBLE_TLV("STO1 ADC Boost Gain Volume", RT5659_STO1_BOOST,
+               RT5659_STO1_ADC_L_BST_SFT, RT5659_STO1_ADC_R_BST_SFT,
+               3, 0, adc_bst_tlv),
+
+       SOC_DOUBLE_TLV("Mono ADC Boost Gain Volume", RT5659_MONO_BOOST,
+               RT5659_MONO_ADC_L_BST_SFT, RT5659_MONO_ADC_R_BST_SFT,
+               3, 0, adc_bst_tlv),
+
+       SOC_DOUBLE_TLV("STO2 ADC Boost Gain Volume", RT5659_STO2_BOOST,
+               RT5659_STO2_ADC_L_BST_SFT, RT5659_STO2_ADC_R_BST_SFT,
+               3, 0, adc_bst_tlv),
+
+       SOC_SINGLE("DAC IF1 DAC1 L Data Switch", RT5659_TDM_CTRL_4, 12, 7, 0),
+       SOC_SINGLE("DAC IF1 DAC1 R Data Switch", RT5659_TDM_CTRL_4, 8, 7, 0),
+       SOC_SINGLE("DAC IF1 DAC2 L Data Switch", RT5659_TDM_CTRL_4, 4, 7, 0),
+       SOC_SINGLE("DAC IF1 DAC2 R Data Switch", RT5659_TDM_CTRL_4, 0, 7, 0),
+};
+
+/**
+ * set_dmic_clk - Set parameter of dmic.
+ *
+ * @w: DAPM widget.
+ * @kcontrol: The kcontrol of this widget.
+ * @event: Event id.
+ *
+ * Choose dmic clock between 1MHz and 3MHz.
+ * It is better for clock to approximate 3MHz.
+ */
+static int set_dmic_clk(struct snd_soc_dapm_widget *w,
+       struct snd_kcontrol *kcontrol, int event)
+{
+       struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+       struct rt5659_priv *rt5659 = snd_soc_codec_get_drvdata(codec);
+       int pd, idx = -EINVAL;
+
+       pd = rl6231_get_pre_div(rt5659->regmap,
+               RT5659_ADDA_CLK_1, RT5659_I2S_PD1_SFT);
+       idx = rl6231_calc_dmic_clk(rt5659->sysclk / pd);
+
+       if (idx < 0)
+               dev_err(codec->dev, "Failed to set DMIC clock\n");
+       else {
+               snd_soc_update_bits(codec, RT5659_DMIC_CTRL_1,
+                       RT5659_DMIC_CLK_MASK, idx << RT5659_DMIC_CLK_SFT);
+       }
+       return idx;
+}
+
+static int set_adc_clk(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_POST_PMU:
+               snd_soc_update_bits(codec, RT5659_CHOP_ADC,
+                       RT5659_CKXEN_ADCC_MASK | RT5659_CKGEN_ADCC_MASK,
+                       RT5659_CKXEN_ADCC_MASK | RT5659_CKGEN_ADCC_MASK);
+               break;
+
+       case SND_SOC_DAPM_PRE_PMD:
+               snd_soc_update_bits(codec, RT5659_CHOP_ADC,
+                       RT5659_CKXEN_ADCC_MASK | RT5659_CKGEN_ADCC_MASK, 0);
+               break;
+
+       default:
+               return 0;
+       }
+
+       return 0;
+
+}
+
+static int rt5659_charge_pump_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_PMU:
+               /* Depop */
+               snd_soc_write(codec, RT5659_DEPOP_1, 0x0009);
+               break;
+       case SND_SOC_DAPM_POST_PMD:
+               snd_soc_write(codec, RT5659_HP_CHARGE_PUMP_1, 0x0c16);
+               break;
+       default:
+               return 0;
+       }
+
+       return 0;
+}
+
+static int is_sys_clk_from_pll(struct snd_soc_dapm_widget *w,
+                        struct snd_soc_dapm_widget *sink)
+{
+       unsigned int val;
+       struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+
+       val = snd_soc_read(codec, RT5659_GLB_CLK);
+       val &= RT5659_SCLK_SRC_MASK;
+       if (val == RT5659_SCLK_SRC_PLL1)
+               return 1;
+       else
+               return 0;
+}
+
+static int is_using_asrc(struct snd_soc_dapm_widget *w,
+                        struct snd_soc_dapm_widget *sink)
+{
+       unsigned int reg, shift, val;
+       struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+
+       switch (w->shift) {
+       case RT5659_ADC_MONO_R_ASRC_SFT:
+               reg = RT5659_ASRC_3;
+               shift = RT5659_AD_MONO_R_T_SFT;
+               break;
+       case RT5659_ADC_MONO_L_ASRC_SFT:
+               reg = RT5659_ASRC_3;
+               shift = RT5659_AD_MONO_L_T_SFT;
+               break;
+       case RT5659_ADC_STO1_ASRC_SFT:
+               reg = RT5659_ASRC_2;
+               shift = RT5659_AD_STO1_T_SFT;
+               break;
+       case RT5659_DAC_MONO_R_ASRC_SFT:
+               reg = RT5659_ASRC_2;
+               shift = RT5659_DA_MONO_R_T_SFT;
+               break;
+       case RT5659_DAC_MONO_L_ASRC_SFT:
+               reg = RT5659_ASRC_2;
+               shift = RT5659_DA_MONO_L_T_SFT;
+               break;
+       case RT5659_DAC_STO_ASRC_SFT:
+               reg = RT5659_ASRC_2;
+               shift = RT5659_DA_STO_T_SFT;
+               break;
+       default:
+               return 0;
+       }
+
+       val = (snd_soc_read(codec, reg) >> shift) & 0xf;
+       switch (val) {
+       case 1:
+       case 2:
+       case 3:
+               /* I2S_Pre_Div1 should be 1 in asrc mode */
+               snd_soc_update_bits(codec, RT5659_ADDA_CLK_1,
+                       RT5659_I2S_PD1_MASK, RT5659_I2S_PD1_2);
+               return 1;
+       default:
+               return 0;
+       }
+
+}
+
+/* Digital Mixer */
+static const struct snd_kcontrol_new rt5659_sto1_adc_l_mix[] = {
+       SOC_DAPM_SINGLE("ADC1 Switch", RT5659_STO1_ADC_MIXER,
+                       RT5659_M_STO1_ADC_L1_SFT, 1, 1),
+       SOC_DAPM_SINGLE("ADC2 Switch", RT5659_STO1_ADC_MIXER,
+                       RT5659_M_STO1_ADC_L2_SFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5659_sto1_adc_r_mix[] = {
+       SOC_DAPM_SINGLE("ADC1 Switch", RT5659_STO1_ADC_MIXER,
+                       RT5659_M_STO1_ADC_R1_SFT, 1, 1),
+       SOC_DAPM_SINGLE("ADC2 Switch", RT5659_STO1_ADC_MIXER,
+                       RT5659_M_STO1_ADC_R2_SFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5659_mono_adc_l_mix[] = {
+       SOC_DAPM_SINGLE("ADC1 Switch", RT5659_MONO_ADC_MIXER,
+                       RT5659_M_MONO_ADC_L1_SFT, 1, 1),
+       SOC_DAPM_SINGLE("ADC2 Switch", RT5659_MONO_ADC_MIXER,
+                       RT5659_M_MONO_ADC_L2_SFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5659_mono_adc_r_mix[] = {
+       SOC_DAPM_SINGLE("ADC1 Switch", RT5659_MONO_ADC_MIXER,
+                       RT5659_M_MONO_ADC_R1_SFT, 1, 1),
+       SOC_DAPM_SINGLE("ADC2 Switch", RT5659_MONO_ADC_MIXER,
+                       RT5659_M_MONO_ADC_R2_SFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5659_dac_l_mix[] = {
+       SOC_DAPM_SINGLE("Stereo ADC Switch", RT5659_AD_DA_MIXER,
+                       RT5659_M_ADCMIX_L_SFT, 1, 1),
+       SOC_DAPM_SINGLE("DAC1 Switch", RT5659_AD_DA_MIXER,
+                       RT5659_M_DAC1_L_SFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5659_dac_r_mix[] = {
+       SOC_DAPM_SINGLE("Stereo ADC Switch", RT5659_AD_DA_MIXER,
+                       RT5659_M_ADCMIX_R_SFT, 1, 1),
+       SOC_DAPM_SINGLE("DAC1 Switch", RT5659_AD_DA_MIXER,
+                       RT5659_M_DAC1_R_SFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5659_sto_dac_l_mix[] = {
+       SOC_DAPM_SINGLE("DAC L1 Switch", RT5659_STO_DAC_MIXER,
+                       RT5659_M_DAC_L1_STO_L_SFT, 1, 1),
+       SOC_DAPM_SINGLE("DAC R1 Switch", RT5659_STO_DAC_MIXER,
+                       RT5659_M_DAC_R1_STO_L_SFT, 1, 1),
+       SOC_DAPM_SINGLE("DAC L2 Switch", RT5659_STO_DAC_MIXER,
+                       RT5659_M_DAC_L2_STO_L_SFT, 1, 1),
+       SOC_DAPM_SINGLE("DAC R2 Switch", RT5659_STO_DAC_MIXER,
+                       RT5659_M_DAC_R2_STO_L_SFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5659_sto_dac_r_mix[] = {
+       SOC_DAPM_SINGLE("DAC L1 Switch", RT5659_STO_DAC_MIXER,
+                       RT5659_M_DAC_L1_STO_R_SFT, 1, 1),
+       SOC_DAPM_SINGLE("DAC R1 Switch", RT5659_STO_DAC_MIXER,
+                       RT5659_M_DAC_R1_STO_R_SFT, 1, 1),
+       SOC_DAPM_SINGLE("DAC L2 Switch", RT5659_STO_DAC_MIXER,
+                       RT5659_M_DAC_L2_STO_R_SFT, 1, 1),
+       SOC_DAPM_SINGLE("DAC R2 Switch", RT5659_STO_DAC_MIXER,
+                       RT5659_M_DAC_R2_STO_R_SFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5659_mono_dac_l_mix[] = {
+       SOC_DAPM_SINGLE("DAC L1 Switch", RT5659_MONO_DAC_MIXER,
+                       RT5659_M_DAC_L1_MONO_L_SFT, 1, 1),
+       SOC_DAPM_SINGLE("DAC R1 Switch", RT5659_MONO_DAC_MIXER,
+                       RT5659_M_DAC_R1_MONO_L_SFT, 1, 1),
+       SOC_DAPM_SINGLE("DAC L2 Switch", RT5659_MONO_DAC_MIXER,
+                       RT5659_M_DAC_L2_MONO_L_SFT, 1, 1),
+       SOC_DAPM_SINGLE("DAC R2 Switch", RT5659_MONO_DAC_MIXER,
+                       RT5659_M_DAC_R2_MONO_L_SFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5659_mono_dac_r_mix[] = {
+       SOC_DAPM_SINGLE("DAC L1 Switch", RT5659_MONO_DAC_MIXER,
+                       RT5659_M_DAC_L1_MONO_R_SFT, 1, 1),
+       SOC_DAPM_SINGLE("DAC R1 Switch", RT5659_MONO_DAC_MIXER,
+                       RT5659_M_DAC_R1_MONO_R_SFT, 1, 1),
+       SOC_DAPM_SINGLE("DAC L2 Switch", RT5659_MONO_DAC_MIXER,
+                       RT5659_M_DAC_L2_MONO_R_SFT, 1, 1),
+       SOC_DAPM_SINGLE("DAC R2 Switch", RT5659_MONO_DAC_MIXER,
+                       RT5659_M_DAC_R2_MONO_R_SFT, 1, 1),
+};
+
+/* Analog Input Mixer */
+static const struct snd_kcontrol_new rt5659_rec1_l_mix[] = {
+       SOC_DAPM_SINGLE("SPKVOLL Switch", RT5659_REC1_L2_MIXER,
+                       RT5659_M_SPKVOLL_RM1_L_SFT, 1, 1),
+       SOC_DAPM_SINGLE("INL Switch", RT5659_REC1_L2_MIXER,
+                       RT5659_M_INL_RM1_L_SFT, 1, 1),
+       SOC_DAPM_SINGLE("BST4 Switch", RT5659_REC1_L2_MIXER,
+                       RT5659_M_BST4_RM1_L_SFT, 1, 1),
+       SOC_DAPM_SINGLE("BST3 Switch", RT5659_REC1_L2_MIXER,
+                       RT5659_M_BST3_RM1_L_SFT, 1, 1),
+       SOC_DAPM_SINGLE("BST2 Switch", RT5659_REC1_L2_MIXER,
+                       RT5659_M_BST2_RM1_L_SFT, 1, 1),
+       SOC_DAPM_SINGLE("BST1 Switch", RT5659_REC1_L2_MIXER,
+                       RT5659_M_BST1_RM1_L_SFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5659_rec1_r_mix[] = {
+       SOC_DAPM_SINGLE("HPOVOLR Switch", RT5659_REC1_L2_MIXER,
+                       RT5659_M_HPOVOLR_RM1_R_SFT, 1, 1),
+       SOC_DAPM_SINGLE("INR Switch", RT5659_REC1_R2_MIXER,
+                       RT5659_M_INR_RM1_R_SFT, 1, 1),
+       SOC_DAPM_SINGLE("BST4 Switch", RT5659_REC1_R2_MIXER,
+                       RT5659_M_BST4_RM1_R_SFT, 1, 1),
+       SOC_DAPM_SINGLE("BST3 Switch", RT5659_REC1_R2_MIXER,
+                       RT5659_M_BST3_RM1_R_SFT, 1, 1),
+       SOC_DAPM_SINGLE("BST2 Switch", RT5659_REC1_R2_MIXER,
+                       RT5659_M_BST2_RM1_R_SFT, 1, 1),
+       SOC_DAPM_SINGLE("BST1 Switch", RT5659_REC1_R2_MIXER,
+                       RT5659_M_BST1_RM1_R_SFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5659_rec2_l_mix[] = {
+       SOC_DAPM_SINGLE("SPKVOLL Switch", RT5659_REC2_L2_MIXER,
+                       RT5659_M_SPKVOL_RM2_L_SFT, 1, 1),
+       SOC_DAPM_SINGLE("OUTVOLL Switch", RT5659_REC2_L2_MIXER,
+                       RT5659_M_OUTVOLL_RM2_L_SFT, 1, 1),
+       SOC_DAPM_SINGLE("BST4 Switch", RT5659_REC2_L2_MIXER,
+                       RT5659_M_BST4_RM2_L_SFT, 1, 1),
+       SOC_DAPM_SINGLE("BST3 Switch", RT5659_REC2_L2_MIXER,
+                       RT5659_M_BST3_RM2_L_SFT, 1, 1),
+       SOC_DAPM_SINGLE("BST2 Switch", RT5659_REC2_L2_MIXER,
+                       RT5659_M_BST2_RM2_L_SFT, 1, 1),
+       SOC_DAPM_SINGLE("BST1 Switch", RT5659_REC2_L2_MIXER,
+                       RT5659_M_BST1_RM2_L_SFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5659_rec2_r_mix[] = {
+       SOC_DAPM_SINGLE("MONOVOL Switch", RT5659_REC2_R2_MIXER,
+                       RT5659_M_MONOVOL_RM2_R_SFT, 1, 1),
+       SOC_DAPM_SINGLE("OUTVOLR Switch", RT5659_REC2_R2_MIXER,
+                       RT5659_M_OUTVOLR_RM2_R_SFT, 1, 1),
+       SOC_DAPM_SINGLE("BST4 Switch", RT5659_REC2_R2_MIXER,
+                       RT5659_M_BST4_RM2_R_SFT, 1, 1),
+       SOC_DAPM_SINGLE("BST3 Switch", RT5659_REC2_R2_MIXER,
+                       RT5659_M_BST3_RM2_R_SFT, 1, 1),
+       SOC_DAPM_SINGLE("BST2 Switch", RT5659_REC2_R2_MIXER,
+                       RT5659_M_BST2_RM2_R_SFT, 1, 1),
+       SOC_DAPM_SINGLE("BST1 Switch", RT5659_REC2_R2_MIXER,
+                       RT5659_M_BST1_RM2_R_SFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5659_spk_l_mix[] = {
+       SOC_DAPM_SINGLE("DAC L2 Switch", RT5659_SPK_L_MIXER,
+                       RT5659_M_DAC_L2_SM_L_SFT, 1, 1),
+       SOC_DAPM_SINGLE("BST1 Switch", RT5659_SPK_L_MIXER,
+                       RT5659_M_BST1_SM_L_SFT, 1, 1),
+       SOC_DAPM_SINGLE("INL Switch", RT5659_SPK_L_MIXER,
+                       RT5659_M_IN_L_SM_L_SFT, 1, 1),
+       SOC_DAPM_SINGLE("INR Switch", RT5659_SPK_L_MIXER,
+                       RT5659_M_IN_R_SM_L_SFT, 1, 1),
+       SOC_DAPM_SINGLE("BST3 Switch", RT5659_SPK_L_MIXER,
+                       RT5659_M_BST3_SM_L_SFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5659_spk_r_mix[] = {
+       SOC_DAPM_SINGLE("DAC R2 Switch", RT5659_SPK_R_MIXER,
+                       RT5659_M_DAC_R2_SM_R_SFT, 1, 1),
+       SOC_DAPM_SINGLE("BST4 Switch", RT5659_SPK_R_MIXER,
+                       RT5659_M_BST4_SM_R_SFT, 1, 1),
+       SOC_DAPM_SINGLE("INL Switch", RT5659_SPK_R_MIXER,
+                       RT5659_M_IN_L_SM_R_SFT, 1, 1),
+       SOC_DAPM_SINGLE("INR Switch", RT5659_SPK_R_MIXER,
+                       RT5659_M_IN_R_SM_R_SFT, 1, 1),
+       SOC_DAPM_SINGLE("BST3 Switch", RT5659_SPK_R_MIXER,
+                       RT5659_M_BST3_SM_R_SFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5659_monovol_mix[] = {
+       SOC_DAPM_SINGLE("DAC L2 Switch", RT5659_MONOMIX_IN_GAIN,
+                       RT5659_M_DAC_L2_MM_SFT, 1, 1),
+       SOC_DAPM_SINGLE("DAC R2 Switch", RT5659_MONOMIX_IN_GAIN,
+                       RT5659_M_DAC_R2_MM_SFT, 1, 1),
+       SOC_DAPM_SINGLE("BST1 Switch", RT5659_MONOMIX_IN_GAIN,
+                       RT5659_M_BST1_MM_SFT, 1, 1),
+       SOC_DAPM_SINGLE("BST2 Switch", RT5659_MONOMIX_IN_GAIN,
+                       RT5659_M_BST2_MM_SFT, 1, 1),
+       SOC_DAPM_SINGLE("BST3 Switch", RT5659_MONOMIX_IN_GAIN,
+                       RT5659_M_BST3_MM_SFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5659_out_l_mix[] = {
+       SOC_DAPM_SINGLE("DAC L2 Switch", RT5659_OUT_L_MIXER,
+                       RT5659_M_DAC_L2_OM_L_SFT, 1, 1),
+       SOC_DAPM_SINGLE("INL Switch", RT5659_OUT_L_MIXER,
+                       RT5659_M_IN_L_OM_L_SFT, 1, 1),
+       SOC_DAPM_SINGLE("BST1 Switch", RT5659_OUT_L_MIXER,
+                       RT5659_M_BST1_OM_L_SFT, 1, 1),
+       SOC_DAPM_SINGLE("BST2 Switch", RT5659_OUT_L_MIXER,
+                       RT5659_M_BST2_OM_L_SFT, 1, 1),
+       SOC_DAPM_SINGLE("BST3 Switch", RT5659_OUT_L_MIXER,
+                       RT5659_M_BST3_OM_L_SFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5659_out_r_mix[] = {
+       SOC_DAPM_SINGLE("DAC R2 Switch", RT5659_OUT_R_MIXER,
+                       RT5659_M_DAC_R2_OM_R_SFT, 1, 1),
+       SOC_DAPM_SINGLE("INR Switch", RT5659_OUT_R_MIXER,
+                       RT5659_M_IN_R_OM_R_SFT, 1, 1),
+       SOC_DAPM_SINGLE("BST2 Switch", RT5659_OUT_R_MIXER,
+                       RT5659_M_BST2_OM_R_SFT, 1, 1),
+       SOC_DAPM_SINGLE("BST3 Switch", RT5659_OUT_R_MIXER,
+                       RT5659_M_BST3_OM_R_SFT, 1, 1),
+       SOC_DAPM_SINGLE("BST4 Switch", RT5659_OUT_R_MIXER,
+                       RT5659_M_BST4_OM_R_SFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5659_spo_l_mix[] = {
+       SOC_DAPM_SINGLE("DAC L2 Switch", RT5659_SPO_AMP_GAIN,
+                       RT5659_M_DAC_L2_SPKOMIX_SFT, 1, 0),
+       SOC_DAPM_SINGLE("SPKVOL L Switch", RT5659_SPO_AMP_GAIN,
+                       RT5659_M_SPKVOLL_SPKOMIX_SFT, 1, 0),
+};
+
+static const struct snd_kcontrol_new rt5659_spo_r_mix[] = {
+       SOC_DAPM_SINGLE("DAC R2 Switch", RT5659_SPO_AMP_GAIN,
+                       RT5659_M_DAC_R2_SPKOMIX_SFT, 1, 0),
+       SOC_DAPM_SINGLE("SPKVOL R Switch", RT5659_SPO_AMP_GAIN,
+                       RT5659_M_SPKVOLR_SPKOMIX_SFT, 1, 0),
+};
+
+static const struct snd_kcontrol_new rt5659_mono_mix[] = {
+       SOC_DAPM_SINGLE("DAC L2 Switch", RT5659_MONOMIX_IN_GAIN,
+                       RT5659_M_DAC_L2_MA_SFT, 1, 1),
+       SOC_DAPM_SINGLE("MONOVOL Switch", RT5659_MONOMIX_IN_GAIN,
+                       RT5659_M_MONOVOL_MA_SFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5659_lout_l_mix[] = {
+       SOC_DAPM_SINGLE("DAC L2 Switch", RT5659_LOUT_MIXER,
+                       RT5659_M_DAC_L2_LM_SFT, 1, 1),
+       SOC_DAPM_SINGLE("OUTVOL L Switch", RT5659_LOUT_MIXER,
+                       RT5659_M_OV_L_LM_SFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5659_lout_r_mix[] = {
+       SOC_DAPM_SINGLE("DAC R2 Switch", RT5659_LOUT_MIXER,
+                       RT5659_M_DAC_R2_LM_SFT, 1, 1),
+       SOC_DAPM_SINGLE("OUTVOL R Switch", RT5659_LOUT_MIXER,
+                       RT5659_M_OV_R_LM_SFT, 1, 1),
+};
+
+/*DAC L2, DAC R2*/
+/*MX-1B [6:4], MX-1B [2:0]*/
+static const char * const rt5659_dac2_src[] = {
+       "IF1 DAC2", "IF2 DAC", "IF3 DAC", "Mono ADC MIX"
+};
+
+static const SOC_ENUM_SINGLE_DECL(
+       rt5659_dac_l2_enum, RT5659_DAC_CTRL,
+       RT5659_DAC_L2_SEL_SFT, rt5659_dac2_src);
+
+static const struct snd_kcontrol_new rt5659_dac_l2_mux =
+       SOC_DAPM_ENUM("DAC L2 Source", rt5659_dac_l2_enum);
+
+static const SOC_ENUM_SINGLE_DECL(
+       rt5659_dac_r2_enum, RT5659_DAC_CTRL,
+       RT5659_DAC_R2_SEL_SFT, rt5659_dac2_src);
+
+static const struct snd_kcontrol_new rt5659_dac_r2_mux =
+       SOC_DAPM_ENUM("DAC R2 Source", rt5659_dac_r2_enum);
+
+
+/* STO1 ADC1 Source */
+/* MX-26 [13] */
+static const char * const rt5659_sto1_adc1_src[] = {
+       "DAC MIX", "ADC"
+};
+
+static const SOC_ENUM_SINGLE_DECL(
+       rt5659_sto1_adc1_enum, RT5659_STO1_ADC_MIXER,
+       RT5659_STO1_ADC1_SRC_SFT, rt5659_sto1_adc1_src);
+
+static const struct snd_kcontrol_new rt5659_sto1_adc1_mux =
+       SOC_DAPM_ENUM("Stereo1 ADC1 Source", rt5659_sto1_adc1_enum);
+
+/* STO1 ADC Source */
+/* MX-26 [12] */
+static const char * const rt5659_sto1_adc_src[] = {
+       "ADC1", "ADC2"
+};
+
+static const SOC_ENUM_SINGLE_DECL(
+       rt5659_sto1_adc_enum, RT5659_STO1_ADC_MIXER,
+       RT5659_STO1_ADC_SRC_SFT, rt5659_sto1_adc_src);
+
+static const struct snd_kcontrol_new rt5659_sto1_adc_mux =
+       SOC_DAPM_ENUM("Stereo1 ADC Source", rt5659_sto1_adc_enum);
+
+/* STO1 ADC2 Source */
+/* MX-26 [11] */
+static const char * const rt5659_sto1_adc2_src[] = {
+       "DAC MIX", "DMIC"
+};
+
+static const SOC_ENUM_SINGLE_DECL(
+       rt5659_sto1_adc2_enum, RT5659_STO1_ADC_MIXER,
+       RT5659_STO1_ADC2_SRC_SFT, rt5659_sto1_adc2_src);
+
+static const struct snd_kcontrol_new rt5659_sto1_adc2_mux =
+       SOC_DAPM_ENUM("Stereo1 ADC2 Source", rt5659_sto1_adc2_enum);
+
+/* STO1 DMIC Source */
+/* MX-26 [8] */
+static const char * const rt5659_sto1_dmic_src[] = {
+       "DMIC1", "DMIC2"
+};
+
+static const SOC_ENUM_SINGLE_DECL(
+       rt5659_sto1_dmic_enum, RT5659_STO1_ADC_MIXER,
+       RT5659_STO1_DMIC_SRC_SFT, rt5659_sto1_dmic_src);
+
+static const struct snd_kcontrol_new rt5659_sto1_dmic_mux =
+       SOC_DAPM_ENUM("Stereo1 DMIC Source", rt5659_sto1_dmic_enum);
+
+
+/* MONO ADC L2 Source */
+/* MX-27 [12] */
+static const char * const rt5659_mono_adc_l2_src[] = {
+       "Mono DAC MIXL", "DMIC"
+};
+
+static const SOC_ENUM_SINGLE_DECL(
+       rt5659_mono_adc_l2_enum, RT5659_MONO_ADC_MIXER,
+       RT5659_MONO_ADC_L2_SRC_SFT, rt5659_mono_adc_l2_src);
+
+static const struct snd_kcontrol_new rt5659_mono_adc_l2_mux =
+       SOC_DAPM_ENUM("Mono ADC L2 Source", rt5659_mono_adc_l2_enum);
+
+
+/* MONO ADC L1 Source */
+/* MX-27 [11] */
+static const char * const rt5659_mono_adc_l1_src[] = {
+       "Mono DAC MIXL", "ADC"
+};
+
+static const SOC_ENUM_SINGLE_DECL(
+       rt5659_mono_adc_l1_enum, RT5659_MONO_ADC_MIXER,
+       RT5659_MONO_ADC_L1_SRC_SFT, rt5659_mono_adc_l1_src);
+
+static const struct snd_kcontrol_new rt5659_mono_adc_l1_mux =
+       SOC_DAPM_ENUM("Mono ADC L1 Source", rt5659_mono_adc_l1_enum);
+
+/* MONO ADC L Source, MONO ADC R Source*/
+/* MX-27 [10:9], MX-27 [2:1] */
+static const char * const rt5659_mono_adc_src[] = {
+       "ADC1 L", "ADC1 R", "ADC2 L", "ADC2 R"
+};
+
+static const SOC_ENUM_SINGLE_DECL(
+       rt5659_mono_adc_l_enum, RT5659_MONO_ADC_MIXER,
+       RT5659_MONO_ADC_L_SRC_SFT, rt5659_mono_adc_src);
+
+static const struct snd_kcontrol_new rt5659_mono_adc_l_mux =
+       SOC_DAPM_ENUM("Mono ADC L Source", rt5659_mono_adc_l_enum);
+
+static const SOC_ENUM_SINGLE_DECL(
+       rt5659_mono_adcr_enum, RT5659_MONO_ADC_MIXER,
+       RT5659_MONO_ADC_R_SRC_SFT, rt5659_mono_adc_src);
+
+static const struct snd_kcontrol_new rt5659_mono_adc_r_mux =
+       SOC_DAPM_ENUM("Mono ADC R Source", rt5659_mono_adcr_enum);
+
+/* MONO DMIC L Source */
+/* MX-27 [8] */
+static const char * const rt5659_mono_dmic_l_src[] = {
+       "DMIC1 L", "DMIC2 L"
+};
+
+static const SOC_ENUM_SINGLE_DECL(
+       rt5659_mono_dmic_l_enum, RT5659_MONO_ADC_MIXER,
+       RT5659_MONO_DMIC_L_SRC_SFT, rt5659_mono_dmic_l_src);
+
+static const struct snd_kcontrol_new rt5659_mono_dmic_l_mux =
+       SOC_DAPM_ENUM("Mono DMIC L Source", rt5659_mono_dmic_l_enum);
+
+/* MONO ADC R2 Source */
+/* MX-27 [4] */
+static const char * const rt5659_mono_adc_r2_src[] = {
+       "Mono DAC MIXR", "DMIC"
+};
+
+static const SOC_ENUM_SINGLE_DECL(
+       rt5659_mono_adc_r2_enum, RT5659_MONO_ADC_MIXER,
+       RT5659_MONO_ADC_R2_SRC_SFT, rt5659_mono_adc_r2_src);
+
+static const struct snd_kcontrol_new rt5659_mono_adc_r2_mux =
+       SOC_DAPM_ENUM("Mono ADC R2 Source", rt5659_mono_adc_r2_enum);
+
+/* MONO ADC R1 Source */
+/* MX-27 [3] */
+static const char * const rt5659_mono_adc_r1_src[] = {
+       "Mono DAC MIXR", "ADC"
+};
+
+static const SOC_ENUM_SINGLE_DECL(
+       rt5659_mono_adc_r1_enum, RT5659_MONO_ADC_MIXER,
+       RT5659_MONO_ADC_R1_SRC_SFT, rt5659_mono_adc_r1_src);
+
+static const struct snd_kcontrol_new rt5659_mono_adc_r1_mux =
+       SOC_DAPM_ENUM("Mono ADC R1 Source", rt5659_mono_adc_r1_enum);
+
+/* MONO DMIC R Source */
+/* MX-27 [0] */
+static const char * const rt5659_mono_dmic_r_src[] = {
+       "DMIC1 R", "DMIC2 R"
+};
+
+static const SOC_ENUM_SINGLE_DECL(
+       rt5659_mono_dmic_r_enum, RT5659_MONO_ADC_MIXER,
+       RT5659_MONO_DMIC_R_SRC_SFT, rt5659_mono_dmic_r_src);
+
+static const struct snd_kcontrol_new rt5659_mono_dmic_r_mux =
+       SOC_DAPM_ENUM("Mono DMIC R Source", rt5659_mono_dmic_r_enum);
+
+
+/* DAC R1 Source, DAC L1 Source*/
+/* MX-29 [11:10], MX-29 [9:8]*/
+static const char * const rt5659_dac1_src[] = {
+       "IF1 DAC1", "IF2 DAC", "IF3 DAC"
+};
+
+static const SOC_ENUM_SINGLE_DECL(
+       rt5659_dac_r1_enum, RT5659_AD_DA_MIXER,
+       RT5659_DAC1_R_SEL_SFT, rt5659_dac1_src);
+
+static const struct snd_kcontrol_new rt5659_dac_r1_mux =
+       SOC_DAPM_ENUM("DAC R1 Source", rt5659_dac_r1_enum);
+
+static const SOC_ENUM_SINGLE_DECL(
+       rt5659_dac_l1_enum, RT5659_AD_DA_MIXER,
+       RT5659_DAC1_L_SEL_SFT, rt5659_dac1_src);
+
+static const struct snd_kcontrol_new rt5659_dac_l1_mux =
+       SOC_DAPM_ENUM("DAC L1 Source", rt5659_dac_l1_enum);
+
+/* DAC Digital Mixer L Source, DAC Digital Mixer R Source*/
+/* MX-2C [6], MX-2C [4]*/
+static const char * const rt5659_dig_dac_mix_src[] = {
+       "Stereo DAC Mixer", "Mono DAC Mixer"
+};
+
+static const SOC_ENUM_SINGLE_DECL(
+       rt5659_dig_dac_mixl_enum, RT5659_DIG_MIXER,
+       RT5659_DAC_MIX_L_SFT, rt5659_dig_dac_mix_src);
+
+static const struct snd_kcontrol_new rt5659_dig_dac_mixl_mux =
+       SOC_DAPM_ENUM("DAC Digital Mixer L Source", rt5659_dig_dac_mixl_enum);
+
+static const SOC_ENUM_SINGLE_DECL(
+       rt5659_dig_dac_mixr_enum, RT5659_DIG_MIXER,
+       RT5659_DAC_MIX_R_SFT, rt5659_dig_dac_mix_src);
+
+static const struct snd_kcontrol_new rt5659_dig_dac_mixr_mux =
+       SOC_DAPM_ENUM("DAC Digital Mixer R Source", rt5659_dig_dac_mixr_enum);
+
+/* Analog DAC L1 Source, Analog DAC R1 Source*/
+/* MX-2D [3], MX-2D [2]*/
+static const char * const rt5659_alg_dac1_src[] = {
+       "DAC", "Stereo DAC Mixer"
+};
+
+static const SOC_ENUM_SINGLE_DECL(
+       rt5659_alg_dac_l1_enum, RT5659_A_DAC_MUX,
+       RT5659_A_DACL1_SFT, rt5659_alg_dac1_src);
+
+static const struct snd_kcontrol_new rt5659_alg_dac_l1_mux =
+       SOC_DAPM_ENUM("Analog DACL1 Source", rt5659_alg_dac_l1_enum);
+
+static const SOC_ENUM_SINGLE_DECL(
+       rt5659_alg_dac_r1_enum, RT5659_A_DAC_MUX,
+       RT5659_A_DACR1_SFT, rt5659_alg_dac1_src);
+
+static const struct snd_kcontrol_new rt5659_alg_dac_r1_mux =
+       SOC_DAPM_ENUM("Analog DACR1 Source", rt5659_alg_dac_r1_enum);
+
+/* Analog DAC LR Source, Analog DAC R2 Source*/
+/* MX-2D [1], MX-2D [0]*/
+static const char * const rt5659_alg_dac2_src[] = {
+       "Stereo DAC Mixer", "Mono DAC Mixer"
+};
+
+static const SOC_ENUM_SINGLE_DECL(
+       rt5659_alg_dac_l2_enum, RT5659_A_DAC_MUX,
+       RT5659_A_DACL2_SFT, rt5659_alg_dac2_src);
+
+static const struct snd_kcontrol_new rt5659_alg_dac_l2_mux =
+       SOC_DAPM_ENUM("Analog DAC L2 Source", rt5659_alg_dac_l2_enum);
+
+static const SOC_ENUM_SINGLE_DECL(
+       rt5659_alg_dac_r2_enum, RT5659_A_DAC_MUX,
+       RT5659_A_DACR2_SFT, rt5659_alg_dac2_src);
+
+static const struct snd_kcontrol_new rt5659_alg_dac_r2_mux =
+       SOC_DAPM_ENUM("Analog DAC R2 Source", rt5659_alg_dac_r2_enum);
+
+/* Interface2 ADC Data Input*/
+/* MX-2F [13:12] */
+static const char * const rt5659_if2_adc_in_src[] = {
+       "IF_ADC1", "IF_ADC2", "DAC_REF", "IF_ADC3"
+};
+
+static const SOC_ENUM_SINGLE_DECL(
+       rt5659_if2_adc_in_enum, RT5659_DIG_INF23_DATA,
+       RT5659_IF2_ADC_IN_SFT, rt5659_if2_adc_in_src);
+
+static const struct snd_kcontrol_new rt5659_if2_adc_in_mux =
+       SOC_DAPM_ENUM("IF2 ADC IN Source", rt5659_if2_adc_in_enum);
+
+/* Interface3 ADC Data Input*/
+/* MX-2F [1:0] */
+static const char * const rt5659_if3_adc_in_src[] = {
+       "IF_ADC1", "IF_ADC2", "DAC_REF", "Stereo2_ADC_L/R"
+};
+
+static const SOC_ENUM_SINGLE_DECL(
+       rt5659_if3_adc_in_enum, RT5659_DIG_INF23_DATA,
+       RT5659_IF3_ADC_IN_SFT, rt5659_if3_adc_in_src);
+
+static const struct snd_kcontrol_new rt5659_if3_adc_in_mux =
+       SOC_DAPM_ENUM("IF3 ADC IN Source", rt5659_if3_adc_in_enum);
+
+/* PDM 1 L/R*/
+/* MX-31 [15] [13] */
+static const char * const rt5659_pdm_src[] = {
+       "Mono DAC", "Stereo DAC"
+};
+
+static const SOC_ENUM_SINGLE_DECL(
+       rt5659_pdm_l_enum, RT5659_PDM_OUT_CTRL,
+       RT5659_PDM1_L_SFT, rt5659_pdm_src);
+
+static const struct snd_kcontrol_new rt5659_pdm_l_mux =
+       SOC_DAPM_ENUM("PDM L Source", rt5659_pdm_l_enum);
+
+static const SOC_ENUM_SINGLE_DECL(
+       rt5659_pdm_r_enum, RT5659_PDM_OUT_CTRL,
+       RT5659_PDM1_R_SFT, rt5659_pdm_src);
+
+static const struct snd_kcontrol_new rt5659_pdm_r_mux =
+       SOC_DAPM_ENUM("PDM R Source", rt5659_pdm_r_enum);
+
+/* SPDIF Output source*/
+/* MX-36 [1:0] */
+static const char * const rt5659_spdif_src[] = {
+       "IF1_DAC1", "IF1_DAC2", "IF2_DAC", "IF3_DAC"
+};
+
+static const SOC_ENUM_SINGLE_DECL(
+       rt5659_spdif_enum, RT5659_SPDIF_CTRL,
+       RT5659_SPDIF_SEL_SFT, rt5659_spdif_src);
+
+static const struct snd_kcontrol_new rt5659_spdif_mux =
+       SOC_DAPM_ENUM("SPDIF Source", rt5659_spdif_enum);
+
+/* I2S1 TDM ADCDAT Source */
+/* MX-78[4:0] */
+static const char * const rt5659_rx_adc_data_src[] = {
+       "AD1:AD2:DAC:NUL", "AD1:AD2:NUL:DAC", "AD1:DAC:AD2:NUL",
+       "AD1:DAC:NUL:AD2", "AD1:NUL:DAC:AD2", "AD1:NUL:AD2:DAC",
+       "AD2:AD1:DAC:NUL", "AD2:AD1:NUL:DAC", "AD2:DAC:AD1:NUL",
+       "AD2:DAC:NUL:AD1", "AD2:NUL:DAC:AD1", "AD1:NUL:AD1:DAC",
+       "DAC:AD1:AD2:NUL", "DAC:AD1:NUL:AD2", "DAC:AD2:AD1:NUL",
+       "DAC:AD2:NUL:AD1", "DAC:NUL:DAC:AD2", "DAC:NUL:AD2:DAC",
+       "NUL:AD1:AD2:DAC", "NUL:AD1:DAC:AD2", "NUL:AD2:AD1:DAC",
+       "NUL:AD2:DAC:AD1", "NUL:DAC:DAC:AD2", "NUL:DAC:AD2:DAC"
+};
+
+static const SOC_ENUM_SINGLE_DECL(
+       rt5659_rx_adc_data_enum, RT5659_TDM_CTRL_2,
+       RT5659_ADCDAT_SRC_SFT, rt5659_rx_adc_data_src);
+
+static const struct snd_kcontrol_new rt5659_rx_adc_dac_mux =
+       SOC_DAPM_ENUM("TDM ADCDAT Source", rt5659_rx_adc_data_enum);
+
+/* Out Volume Switch */
+static const struct snd_kcontrol_new spkvol_l_switch =
+       SOC_DAPM_SINGLE("Switch", RT5659_SPO_VOL, RT5659_VOL_L_SFT, 1, 1);
+
+static const struct snd_kcontrol_new spkvol_r_switch =
+       SOC_DAPM_SINGLE("Switch", RT5659_SPO_VOL, RT5659_VOL_R_SFT, 1, 1);
+
+static const struct snd_kcontrol_new monovol_switch =
+       SOC_DAPM_SINGLE("Switch", RT5659_MONO_OUT, RT5659_VOL_L_SFT, 1, 1);
+
+static const struct snd_kcontrol_new outvol_l_switch =
+       SOC_DAPM_SINGLE("Switch", RT5659_LOUT, RT5659_VOL_L_SFT, 1, 1);
+
+static const struct snd_kcontrol_new outvol_r_switch =
+       SOC_DAPM_SINGLE("Switch", RT5659_LOUT, RT5659_VOL_R_SFT, 1, 1);
+
+/* Out Switch */
+static const struct snd_kcontrol_new spo_switch =
+       SOC_DAPM_SINGLE("Switch", RT5659_CLASSD_2, RT5659_M_RF_DIG_SFT, 1, 1);
+
+static const struct snd_kcontrol_new mono_switch =
+       SOC_DAPM_SINGLE("Switch", RT5659_MONO_OUT, RT5659_L_MUTE_SFT, 1, 1);
+
+static const struct snd_kcontrol_new hpo_l_switch =
+       SOC_DAPM_SINGLE("Switch", RT5659_HP_VOL, RT5659_L_MUTE_SFT, 1, 1);
+
+static const struct snd_kcontrol_new hpo_r_switch =
+       SOC_DAPM_SINGLE("Switch", RT5659_HP_VOL, RT5659_R_MUTE_SFT, 1, 1);
+
+static const struct snd_kcontrol_new lout_l_switch =
+       SOC_DAPM_SINGLE("Switch", RT5659_LOUT, RT5659_L_MUTE_SFT, 1, 1);
+
+static const struct snd_kcontrol_new lout_r_switch =
+       SOC_DAPM_SINGLE("Switch", RT5659_LOUT, RT5659_R_MUTE_SFT, 1, 1);
+
+static const struct snd_kcontrol_new pdm_l_switch =
+       SOC_DAPM_SINGLE("Switch", RT5659_PDM_OUT_CTRL, RT5659_M_PDM1_L_SFT, 1,
+               1);
+
+static const struct snd_kcontrol_new pdm_r_switch =
+       SOC_DAPM_SINGLE("Switch", RT5659_PDM_OUT_CTRL, RT5659_M_PDM1_R_SFT, 1,
+               1);
+
+static int rt5659_spk_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_PMU:
+               snd_soc_update_bits(codec, RT5659_CLASSD_CTRL_1,
+                       RT5659_POW_CLSD_DB_MASK, RT5659_POW_CLSD_DB_EN);
+               snd_soc_update_bits(codec, RT5659_CLASSD_2,
+                       RT5659_M_RI_DIG, RT5659_M_RI_DIG);
+               snd_soc_write(codec, RT5659_CLASSD_1, 0x0803);
+               snd_soc_write(codec, RT5659_SPK_DC_CAILB_CTRL_3, 0x0000);
+               break;
+
+       case SND_SOC_DAPM_POST_PMD:
+               snd_soc_write(codec, RT5659_CLASSD_1, 0x0011);
+               snd_soc_update_bits(codec, RT5659_CLASSD_2,
+                       RT5659_M_RI_DIG, 0x0);
+               snd_soc_write(codec, RT5659_SPK_DC_CAILB_CTRL_3, 0x0003);
+               snd_soc_update_bits(codec, RT5659_CLASSD_CTRL_1,
+                       RT5659_POW_CLSD_DB_MASK, RT5659_POW_CLSD_DB_DIS);
+               break;
+
+       default:
+               return 0;
+       }
+
+       return 0;
+
+}
+
+static int rt5659_mono_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_PMU:
+               snd_soc_write(codec, RT5659_MONO_AMP_CALIB_CTRL_1, 0x1e00);
+               break;
+
+       case SND_SOC_DAPM_POST_PMD:
+               snd_soc_write(codec, RT5659_MONO_AMP_CALIB_CTRL_1, 0x1e04);
+               break;
+
+       default:
+               return 0;
+       }
+
+       return 0;
+
+}
+
+static int rt5659_hp_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_POST_PMU:
+               snd_soc_write(codec, RT5659_HP_CHARGE_PUMP_1, 0x0e1e);
+               snd_soc_update_bits(codec, RT5659_DEPOP_1, 0x0010, 0x0010);
+               break;
+
+       case SND_SOC_DAPM_PRE_PMD:
+               snd_soc_write(codec, RT5659_DEPOP_1, 0x0000);
+               break;
+
+       default:
+               return 0;
+       }
+
+       return 0;
+}
+
+static int set_dmic_power(struct snd_soc_dapm_widget *w,
+       struct snd_kcontrol *kcontrol, int event)
+{
+       switch (event) {
+       case SND_SOC_DAPM_POST_PMU:
+               /*Add delay to avoid pop noise*/
+               msleep(450);
+               break;
+
+       default:
+               return 0;
+       }
+
+       return 0;
+}
+
+static const struct snd_soc_dapm_widget rt5659_dapm_widgets[] = {
+       SND_SOC_DAPM_SUPPLY("LDO2", RT5659_PWR_ANLG_3, RT5659_PWR_LDO2_BIT, 0,
+               NULL, 0),
+       SND_SOC_DAPM_SUPPLY("PLL", RT5659_PWR_ANLG_3, RT5659_PWR_PLL_BIT, 0,
+               NULL, 0),
+       SND_SOC_DAPM_SUPPLY("Mic Det Power", RT5659_PWR_VOL,
+               RT5659_PWR_MIC_DET_BIT, 0, NULL, 0),
+       SND_SOC_DAPM_SUPPLY("Mono Vref", RT5659_PWR_ANLG_1,
+               RT5659_PWR_VREF3_BIT, 0, NULL, 0),
+
+       /* ASRC */
+       SND_SOC_DAPM_SUPPLY_S("I2S1 ASRC", 1, RT5659_ASRC_1,
+               RT5659_I2S1_ASRC_SFT, 0, NULL, 0),
+       SND_SOC_DAPM_SUPPLY_S("I2S2 ASRC", 1, RT5659_ASRC_1,
+               RT5659_I2S2_ASRC_SFT, 0, NULL, 0),
+       SND_SOC_DAPM_SUPPLY_S("I2S3 ASRC", 1, RT5659_ASRC_1,
+               RT5659_I2S3_ASRC_SFT, 0, NULL, 0),
+       SND_SOC_DAPM_SUPPLY_S("DAC STO ASRC", 1, RT5659_ASRC_1,
+               RT5659_DAC_STO_ASRC_SFT, 0, NULL, 0),
+       SND_SOC_DAPM_SUPPLY_S("DAC Mono L ASRC", 1, RT5659_ASRC_1,
+               RT5659_DAC_MONO_L_ASRC_SFT, 0, NULL, 0),
+       SND_SOC_DAPM_SUPPLY_S("DAC Mono R ASRC", 1, RT5659_ASRC_1,
+               RT5659_DAC_MONO_R_ASRC_SFT, 0, NULL, 0),
+       SND_SOC_DAPM_SUPPLY_S("ADC STO1 ASRC", 1, RT5659_ASRC_1,
+               RT5659_ADC_STO1_ASRC_SFT, 0, NULL, 0),
+       SND_SOC_DAPM_SUPPLY_S("ADC Mono L ASRC", 1, RT5659_ASRC_1,
+               RT5659_ADC_MONO_L_ASRC_SFT, 0, NULL, 0),
+       SND_SOC_DAPM_SUPPLY_S("ADC Mono R ASRC", 1, RT5659_ASRC_1,
+               RT5659_ADC_MONO_R_ASRC_SFT, 0, NULL, 0),
+
+       /* Input Side */
+       SND_SOC_DAPM_SUPPLY("MICBIAS1", RT5659_PWR_ANLG_2, RT5659_PWR_MB1_BIT,
+               0, NULL, 0),
+       SND_SOC_DAPM_SUPPLY("MICBIAS2", RT5659_PWR_ANLG_2, RT5659_PWR_MB2_BIT,
+               0, NULL, 0),
+       SND_SOC_DAPM_SUPPLY("MICBIAS3", RT5659_PWR_ANLG_2, RT5659_PWR_MB3_BIT,
+               0, NULL, 0),
+
+       /* Input Lines */
+       SND_SOC_DAPM_INPUT("DMIC L1"),
+       SND_SOC_DAPM_INPUT("DMIC R1"),
+       SND_SOC_DAPM_INPUT("DMIC L2"),
+       SND_SOC_DAPM_INPUT("DMIC R2"),
+
+       SND_SOC_DAPM_INPUT("IN1P"),
+       SND_SOC_DAPM_INPUT("IN1N"),
+       SND_SOC_DAPM_INPUT("IN2P"),
+       SND_SOC_DAPM_INPUT("IN2N"),
+       SND_SOC_DAPM_INPUT("IN3P"),
+       SND_SOC_DAPM_INPUT("IN3N"),
+       SND_SOC_DAPM_INPUT("IN4P"),
+       SND_SOC_DAPM_INPUT("IN4N"),
+
+       SND_SOC_DAPM_PGA("DMIC1", SND_SOC_NOPM, 0, 0, NULL, 0),
+       SND_SOC_DAPM_PGA("DMIC2", SND_SOC_NOPM, 0, 0, NULL, 0),
+
+       SND_SOC_DAPM_SUPPLY("DMIC CLK", SND_SOC_NOPM, 0, 0,
+               set_dmic_clk, SND_SOC_DAPM_PRE_PMU),
+       SND_SOC_DAPM_SUPPLY("DMIC1 Power", RT5659_DMIC_CTRL_1,
+               RT5659_DMIC_1_EN_SFT, 0, set_dmic_power, SND_SOC_DAPM_POST_PMU),
+       SND_SOC_DAPM_SUPPLY("DMIC2 Power", RT5659_DMIC_CTRL_1,
+               RT5659_DMIC_2_EN_SFT, 0, set_dmic_power, SND_SOC_DAPM_POST_PMU),
+
+       /* Boost */
+       SND_SOC_DAPM_PGA("BST1", RT5659_PWR_ANLG_2,
+               RT5659_PWR_BST1_P_BIT, 0, NULL, 0),
+       SND_SOC_DAPM_PGA("BST2", RT5659_PWR_ANLG_2,
+               RT5659_PWR_BST2_P_BIT, 0, NULL, 0),
+       SND_SOC_DAPM_PGA("BST3", RT5659_PWR_ANLG_2,
+               RT5659_PWR_BST3_P_BIT, 0, NULL, 0),
+       SND_SOC_DAPM_PGA("BST4", RT5659_PWR_ANLG_2,
+               RT5659_PWR_BST4_P_BIT, 0, NULL, 0),
+       SND_SOC_DAPM_SUPPLY("BST1 Power", RT5659_PWR_ANLG_2,
+               RT5659_PWR_BST1_BIT, 0, NULL, 0),
+       SND_SOC_DAPM_SUPPLY("BST2 Power", RT5659_PWR_ANLG_2,
+               RT5659_PWR_BST2_BIT, 0, NULL, 0),
+       SND_SOC_DAPM_SUPPLY("BST3 Power", RT5659_PWR_ANLG_2,
+               RT5659_PWR_BST3_BIT, 0, NULL, 0),
+       SND_SOC_DAPM_SUPPLY("BST4 Power", RT5659_PWR_ANLG_2,
+               RT5659_PWR_BST4_BIT, 0, NULL, 0),
+
+
+       /* Input Volume */
+       SND_SOC_DAPM_PGA("INL VOL", RT5659_PWR_VOL, RT5659_PWR_IN_L_BIT,
+               0, NULL, 0),
+       SND_SOC_DAPM_PGA("INR VOL", RT5659_PWR_VOL, RT5659_PWR_IN_R_BIT,
+               0, NULL, 0),
+
+       /* REC Mixer */
+       SND_SOC_DAPM_MIXER("RECMIX1L", RT5659_PWR_MIXER, RT5659_PWR_RM1_L_BIT,
+               0, rt5659_rec1_l_mix, ARRAY_SIZE(rt5659_rec1_l_mix)),
+       SND_SOC_DAPM_MIXER("RECMIX1R", RT5659_PWR_MIXER, RT5659_PWR_RM1_R_BIT,
+               0, rt5659_rec1_r_mix, ARRAY_SIZE(rt5659_rec1_r_mix)),
+       SND_SOC_DAPM_MIXER("RECMIX2L", RT5659_PWR_MIXER, RT5659_PWR_RM2_L_BIT,
+               0, rt5659_rec2_l_mix, ARRAY_SIZE(rt5659_rec2_l_mix)),
+       SND_SOC_DAPM_MIXER("RECMIX2R", RT5659_PWR_MIXER, RT5659_PWR_RM2_R_BIT,
+               0, rt5659_rec2_r_mix, ARRAY_SIZE(rt5659_rec2_r_mix)),
+
+       /* ADCs */
+       SND_SOC_DAPM_ADC("ADC1 L", NULL, SND_SOC_NOPM, 0, 0),
+       SND_SOC_DAPM_ADC("ADC1 R", NULL, SND_SOC_NOPM, 0, 0),
+       SND_SOC_DAPM_ADC("ADC2 L", NULL, SND_SOC_NOPM, 0, 0),
+       SND_SOC_DAPM_ADC("ADC2 R", NULL, SND_SOC_NOPM, 0, 0),
+
+       SND_SOC_DAPM_SUPPLY("ADC1 L Power", RT5659_PWR_DIG_1,
+               RT5659_PWR_ADC_L1_BIT, 0, NULL, 0),
+       SND_SOC_DAPM_SUPPLY("ADC1 R Power", RT5659_PWR_DIG_1,
+               RT5659_PWR_ADC_R1_BIT, 0, NULL, 0),
+       SND_SOC_DAPM_SUPPLY("ADC2 L Power", RT5659_PWR_DIG_2,
+               RT5659_PWR_ADC_L2_BIT, 0, NULL, 0),
+       SND_SOC_DAPM_SUPPLY("ADC2 R Power", RT5659_PWR_DIG_2,
+               RT5659_PWR_ADC_R2_BIT, 0, NULL, 0),
+       SND_SOC_DAPM_SUPPLY("ADC1 clock", SND_SOC_NOPM, 0, 0, set_adc_clk,
+               SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
+       SND_SOC_DAPM_SUPPLY("ADC2 clock", SND_SOC_NOPM, 0, 0, set_adc_clk,
+               SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
+
+       /* ADC Mux */
+       SND_SOC_DAPM_MUX("Stereo1 DMIC L Mux", SND_SOC_NOPM, 0, 0,
+               &rt5659_sto1_dmic_mux),
+       SND_SOC_DAPM_MUX("Stereo1 DMIC R Mux", SND_SOC_NOPM, 0, 0,
+               &rt5659_sto1_dmic_mux),
+       SND_SOC_DAPM_MUX("Stereo1 ADC L1 Mux", SND_SOC_NOPM, 0, 0,
+               &rt5659_sto1_adc1_mux),
+       SND_SOC_DAPM_MUX("Stereo1 ADC R1 Mux", SND_SOC_NOPM, 0, 0,
+               &rt5659_sto1_adc1_mux),
+       SND_SOC_DAPM_MUX("Stereo1 ADC L2 Mux", SND_SOC_NOPM, 0, 0,
+               &rt5659_sto1_adc2_mux),
+       SND_SOC_DAPM_MUX("Stereo1 ADC R2 Mux", SND_SOC_NOPM, 0, 0,
+               &rt5659_sto1_adc2_mux),
+       SND_SOC_DAPM_MUX("Stereo1 ADC L Mux", SND_SOC_NOPM, 0, 0,
+               &rt5659_sto1_adc_mux),
+       SND_SOC_DAPM_MUX("Stereo1 ADC R Mux", SND_SOC_NOPM, 0, 0,
+               &rt5659_sto1_adc_mux),
+       SND_SOC_DAPM_MUX("Mono ADC L2 Mux", SND_SOC_NOPM, 0, 0,
+               &rt5659_mono_adc_l2_mux),
+       SND_SOC_DAPM_MUX("Mono ADC R2 Mux", SND_SOC_NOPM, 0, 0,
+               &rt5659_mono_adc_r2_mux),
+       SND_SOC_DAPM_MUX("Mono ADC L1 Mux", SND_SOC_NOPM, 0, 0,
+               &rt5659_mono_adc_l1_mux),
+       SND_SOC_DAPM_MUX("Mono ADC R1 Mux", SND_SOC_NOPM, 0, 0,
+               &rt5659_mono_adc_r1_mux),
+       SND_SOC_DAPM_MUX("Mono DMIC L Mux", SND_SOC_NOPM, 0, 0,
+               &rt5659_mono_dmic_l_mux),
+       SND_SOC_DAPM_MUX("Mono DMIC R Mux", SND_SOC_NOPM, 0, 0,
+               &rt5659_mono_dmic_r_mux),
+       SND_SOC_DAPM_MUX("Mono ADC L Mux", SND_SOC_NOPM, 0, 0,
+               &rt5659_mono_adc_l_mux),
+       SND_SOC_DAPM_MUX("Mono ADC R Mux", SND_SOC_NOPM, 0, 0,
+               &rt5659_mono_adc_r_mux),
+       /* ADC Mixer */
+       SND_SOC_DAPM_SUPPLY("ADC Stereo1 Filter", RT5659_PWR_DIG_2,
+               RT5659_PWR_ADC_S1F_BIT, 0, NULL, 0),
+       SND_SOC_DAPM_SUPPLY("ADC Stereo2 Filter", RT5659_PWR_DIG_2,
+               RT5659_PWR_ADC_S2F_BIT, 0, NULL, 0),
+       SND_SOC_DAPM_MIXER("Stereo1 ADC MIXL", SND_SOC_NOPM,
+               0, 0, rt5659_sto1_adc_l_mix,
+               ARRAY_SIZE(rt5659_sto1_adc_l_mix)),
+       SND_SOC_DAPM_MIXER("Stereo1 ADC MIXR", SND_SOC_NOPM,
+               0, 0, rt5659_sto1_adc_r_mix,
+               ARRAY_SIZE(rt5659_sto1_adc_r_mix)),
+       SND_SOC_DAPM_SUPPLY("ADC Mono Left Filter", RT5659_PWR_DIG_2,
+               RT5659_PWR_ADC_MF_L_BIT, 0, NULL, 0),
+       SND_SOC_DAPM_MIXER("Mono ADC MIXL", RT5659_MONO_ADC_DIG_VOL,
+               RT5659_L_MUTE_SFT, 1, rt5659_mono_adc_l_mix,
+               ARRAY_SIZE(rt5659_mono_adc_l_mix)),
+       SND_SOC_DAPM_SUPPLY("ADC Mono Right Filter", RT5659_PWR_DIG_2,
+               RT5659_PWR_ADC_MF_R_BIT, 0, NULL, 0),
+       SND_SOC_DAPM_MIXER("Mono ADC MIXR", RT5659_MONO_ADC_DIG_VOL,
+               RT5659_R_MUTE_SFT, 1, rt5659_mono_adc_r_mix,
+               ARRAY_SIZE(rt5659_mono_adc_r_mix)),
+
+       /* ADC PGA */
+       SND_SOC_DAPM_PGA("IF_ADC1", SND_SOC_NOPM, 0, 0, NULL, 0),
+       SND_SOC_DAPM_PGA("IF_ADC2", SND_SOC_NOPM, 0, 0, NULL, 0),
+       SND_SOC_DAPM_PGA("IF_ADC3", SND_SOC_NOPM, 0, 0, NULL, 0),
+       SND_SOC_DAPM_PGA("IF1_ADC1", SND_SOC_NOPM, 0, 0, NULL, 0),
+       SND_SOC_DAPM_PGA("IF1_ADC2", SND_SOC_NOPM, 0, 0, NULL, 0),
+       SND_SOC_DAPM_PGA("IF1_ADC3", SND_SOC_NOPM, 0, 0, NULL, 0),
+       SND_SOC_DAPM_PGA("IF1_ADC4", SND_SOC_NOPM, 0, 0, NULL, 0),
+       SND_SOC_DAPM_PGA("Stereo2 ADC LR", SND_SOC_NOPM, 0, 0, NULL, 0),
+
+       SND_SOC_DAPM_PGA("Stereo1 ADC Volume L", RT5659_STO1_ADC_DIG_VOL,
+               RT5659_L_MUTE_SFT, 1, NULL, 0),
+       SND_SOC_DAPM_PGA("Stereo1 ADC Volume R", RT5659_STO1_ADC_DIG_VOL,
+               RT5659_R_MUTE_SFT, 1, NULL, 0),
+
+       /* Digital Interface */
+       SND_SOC_DAPM_SUPPLY("I2S1", RT5659_PWR_DIG_1, RT5659_PWR_I2S1_BIT,
+               0, NULL, 0),
+       SND_SOC_DAPM_PGA("IF1 DAC1", SND_SOC_NOPM, 0, 0, NULL, 0),
+       SND_SOC_DAPM_PGA("IF1 DAC2", SND_SOC_NOPM, 0, 0, NULL, 0),
+       SND_SOC_DAPM_PGA("IF1 DAC1 L", SND_SOC_NOPM, 0, 0, NULL, 0),
+       SND_SOC_DAPM_PGA("IF1 DAC1 R", SND_SOC_NOPM, 0, 0, NULL, 0),
+       SND_SOC_DAPM_PGA("IF1 DAC2 L", SND_SOC_NOPM, 0, 0, NULL, 0),
+       SND_SOC_DAPM_PGA("IF1 DAC2 R", SND_SOC_NOPM, 0, 0, NULL, 0),
+       SND_SOC_DAPM_PGA("IF1 ADC", SND_SOC_NOPM, 0, 0, NULL, 0),
+       SND_SOC_DAPM_PGA("IF1 ADC L", SND_SOC_NOPM, 0, 0, NULL, 0),
+       SND_SOC_DAPM_PGA("IF1 ADC R", SND_SOC_NOPM, 0, 0, NULL, 0),
+       SND_SOC_DAPM_SUPPLY("I2S2", RT5659_PWR_DIG_1, RT5659_PWR_I2S2_BIT, 0,
+               NULL, 0),
+       SND_SOC_DAPM_PGA("IF2 DAC", SND_SOC_NOPM, 0, 0, NULL, 0),
+       SND_SOC_DAPM_PGA("IF2 DAC L", SND_SOC_NOPM, 0, 0, NULL, 0),
+       SND_SOC_DAPM_PGA("IF2 DAC R", SND_SOC_NOPM, 0, 0, NULL, 0),
+       SND_SOC_DAPM_PGA("IF2 ADC", SND_SOC_NOPM, 0, 0, NULL, 0),
+       SND_SOC_DAPM_PGA("IF2 ADC1", SND_SOC_NOPM, 0, 0, NULL, 0),
+       SND_SOC_DAPM_PGA("IF2 ADC2", SND_SOC_NOPM, 0, 0, NULL, 0),
+       SND_SOC_DAPM_SUPPLY("I2S3", RT5659_PWR_DIG_1, RT5659_PWR_I2S3_BIT, 0,
+               NULL, 0),
+       SND_SOC_DAPM_PGA("IF3 DAC", SND_SOC_NOPM, 0, 0, NULL, 0),
+       SND_SOC_DAPM_PGA("IF3 DAC L", SND_SOC_NOPM, 0, 0, NULL, 0),
+       SND_SOC_DAPM_PGA("IF3 DAC R", SND_SOC_NOPM, 0, 0, NULL, 0),
+       SND_SOC_DAPM_PGA("IF3 ADC", SND_SOC_NOPM, 0, 0, NULL, 0),
+       SND_SOC_DAPM_PGA("IF3 ADC L", SND_SOC_NOPM, 0, 0, NULL, 0),
+       SND_SOC_DAPM_PGA("IF3 ADC R", SND_SOC_NOPM, 0, 0, NULL, 0),
+
+       /* Digital Interface Select */
+       SND_SOC_DAPM_PGA("TDM AD1:AD2:DAC", SND_SOC_NOPM, 0, 0, NULL, 0),
+       SND_SOC_DAPM_PGA("TDM AD2:DAC", SND_SOC_NOPM, 0, 0, NULL, 0),
+       SND_SOC_DAPM_MUX("TDM Data Mux", SND_SOC_NOPM, 0, 0,
+               &rt5659_rx_adc_dac_mux),
+       SND_SOC_DAPM_MUX("IF2 ADC Mux", SND_SOC_NOPM, 0, 0,
+               &rt5659_if2_adc_in_mux),
+       SND_SOC_DAPM_MUX("IF3 ADC Mux", SND_SOC_NOPM, 0, 0,
+               &rt5659_if3_adc_in_mux),
+       SND_SOC_DAPM_MUX("IF1 01 ADC Swap Mux", SND_SOC_NOPM, 0, 0,
+                       &rt5659_if1_01_adc_swap_mux),
+       SND_SOC_DAPM_MUX("IF1 23 ADC Swap Mux", SND_SOC_NOPM, 0, 0,
+                       &rt5659_if1_23_adc_swap_mux),
+       SND_SOC_DAPM_MUX("IF1 45 ADC Swap Mux", SND_SOC_NOPM, 0, 0,
+                       &rt5659_if1_45_adc_swap_mux),
+       SND_SOC_DAPM_MUX("IF1 67 ADC Swap Mux", SND_SOC_NOPM, 0, 0,
+                       &rt5659_if1_67_adc_swap_mux),
+       SND_SOC_DAPM_MUX("IF2 DAC Swap Mux", SND_SOC_NOPM, 0, 0,
+                       &rt5659_if2_dac_swap_mux),
+       SND_SOC_DAPM_MUX("IF2 ADC Swap Mux", SND_SOC_NOPM, 0, 0,
+                       &rt5659_if2_adc_swap_mux),
+       SND_SOC_DAPM_MUX("IF3 DAC Swap Mux", SND_SOC_NOPM, 0, 0,
+                       &rt5659_if3_dac_swap_mux),
+       SND_SOC_DAPM_MUX("IF3 ADC Swap Mux", SND_SOC_NOPM, 0, 0,
+                       &rt5659_if3_adc_swap_mux),
+
+       /* Audio Interface */
+       SND_SOC_DAPM_AIF_IN("AIF1RX", "AIF1 Playback", 0, SND_SOC_NOPM, 0, 0),
+       SND_SOC_DAPM_AIF_OUT("AIF1TX", "AIF1 Capture", 0, SND_SOC_NOPM, 0, 0),
+       SND_SOC_DAPM_AIF_IN("AIF2RX", "AIF2 Playback", 0, SND_SOC_NOPM, 0, 0),
+       SND_SOC_DAPM_AIF_OUT("AIF2TX", "AIF2 Capture", 0, SND_SOC_NOPM, 0, 0),
+       SND_SOC_DAPM_AIF_IN("AIF3RX", "AIF3 Playback", 0, SND_SOC_NOPM, 0, 0),
+       SND_SOC_DAPM_AIF_OUT("AIF3TX", "AIF3 Capture", 0, SND_SOC_NOPM, 0, 0),
+
+       /* Output Side */
+       /* DAC mixer before sound effect  */
+       SND_SOC_DAPM_MIXER("DAC1 MIXL", SND_SOC_NOPM, 0, 0,
+               rt5659_dac_l_mix, ARRAY_SIZE(rt5659_dac_l_mix)),
+       SND_SOC_DAPM_MIXER("DAC1 MIXR", SND_SOC_NOPM, 0, 0,
+               rt5659_dac_r_mix, ARRAY_SIZE(rt5659_dac_r_mix)),
+
+       /* DAC channel Mux */
+       SND_SOC_DAPM_MUX("DAC L1 Mux", SND_SOC_NOPM, 0, 0, &rt5659_dac_l1_mux),
+       SND_SOC_DAPM_MUX("DAC R1 Mux", SND_SOC_NOPM, 0, 0, &rt5659_dac_r1_mux),
+       SND_SOC_DAPM_MUX("DAC L2 Mux", SND_SOC_NOPM, 0, 0, &rt5659_dac_l2_mux),
+       SND_SOC_DAPM_MUX("DAC R2 Mux", SND_SOC_NOPM, 0, 0, &rt5659_dac_r2_mux),
+
+       SND_SOC_DAPM_MUX("DAC L1 Source", SND_SOC_NOPM, 0, 0,
+               &rt5659_alg_dac_l1_mux),
+       SND_SOC_DAPM_MUX("DAC R1 Source", SND_SOC_NOPM, 0, 0,
+               &rt5659_alg_dac_r1_mux),
+       SND_SOC_DAPM_MUX("DAC L2 Source", SND_SOC_NOPM, 0, 0,
+               &rt5659_alg_dac_l2_mux),
+       SND_SOC_DAPM_MUX("DAC R2 Source", SND_SOC_NOPM, 0, 0,
+               &rt5659_alg_dac_r2_mux),
+
+       /* DAC Mixer */
+       SND_SOC_DAPM_SUPPLY("DAC Stereo1 Filter", RT5659_PWR_DIG_2,
+               RT5659_PWR_DAC_S1F_BIT, 0, NULL, 0),
+       SND_SOC_DAPM_SUPPLY("DAC Mono Left Filter", RT5659_PWR_DIG_2,
+               RT5659_PWR_DAC_MF_L_BIT, 0, NULL, 0),
+       SND_SOC_DAPM_SUPPLY("DAC Mono Right Filter", RT5659_PWR_DIG_2,
+               RT5659_PWR_DAC_MF_R_BIT, 0, NULL, 0),
+       SND_SOC_DAPM_MIXER("Stereo DAC MIXL", SND_SOC_NOPM, 0, 0,
+               rt5659_sto_dac_l_mix, ARRAY_SIZE(rt5659_sto_dac_l_mix)),
+       SND_SOC_DAPM_MIXER("Stereo DAC MIXR", SND_SOC_NOPM, 0, 0,
+               rt5659_sto_dac_r_mix, ARRAY_SIZE(rt5659_sto_dac_r_mix)),
+       SND_SOC_DAPM_MIXER("Mono DAC MIXL", SND_SOC_NOPM, 0, 0,
+               rt5659_mono_dac_l_mix, ARRAY_SIZE(rt5659_mono_dac_l_mix)),
+       SND_SOC_DAPM_MIXER("Mono DAC MIXR", SND_SOC_NOPM, 0, 0,
+               rt5659_mono_dac_r_mix, ARRAY_SIZE(rt5659_mono_dac_r_mix)),
+       SND_SOC_DAPM_MUX("DAC MIXL", SND_SOC_NOPM, 0, 0,
+               &rt5659_dig_dac_mixl_mux),
+       SND_SOC_DAPM_MUX("DAC MIXR", SND_SOC_NOPM, 0, 0,
+               &rt5659_dig_dac_mixr_mux),
+
+       /* DACs */
+       SND_SOC_DAPM_SUPPLY_S("DAC L1 Power", 1, RT5659_PWR_DIG_1,
+               RT5659_PWR_DAC_L1_BIT, 0, NULL, 0),
+       SND_SOC_DAPM_SUPPLY_S("DAC R1 Power", 1, RT5659_PWR_DIG_1,
+               RT5659_PWR_DAC_R1_BIT, 0, NULL, 0),
+       SND_SOC_DAPM_DAC("DAC L1", NULL, SND_SOC_NOPM, 0, 0),
+       SND_SOC_DAPM_DAC("DAC R1", NULL, SND_SOC_NOPM, 0, 0),
+
+       SND_SOC_DAPM_SUPPLY("DAC L2 Power", RT5659_PWR_DIG_1,
+               RT5659_PWR_DAC_L2_BIT, 0, NULL, 0),
+       SND_SOC_DAPM_SUPPLY("DAC R2 Power", RT5659_PWR_DIG_1,
+               RT5659_PWR_DAC_R2_BIT, 0, NULL, 0),
+       SND_SOC_DAPM_DAC("DAC L2", NULL, SND_SOC_NOPM, 0, 0),
+       SND_SOC_DAPM_DAC("DAC R2", NULL, SND_SOC_NOPM, 0, 0),
+       SND_SOC_DAPM_PGA("DAC_REF", SND_SOC_NOPM, 0, 0, NULL, 0),
+
+       /* OUT Mixer */
+       SND_SOC_DAPM_MIXER("SPK MIXL", RT5659_PWR_MIXER, RT5659_PWR_SM_L_BIT,
+               0, rt5659_spk_l_mix, ARRAY_SIZE(rt5659_spk_l_mix)),
+       SND_SOC_DAPM_MIXER("SPK MIXR", RT5659_PWR_MIXER, RT5659_PWR_SM_R_BIT,
+               0, rt5659_spk_r_mix, ARRAY_SIZE(rt5659_spk_r_mix)),
+       SND_SOC_DAPM_MIXER("MONOVOL MIX", RT5659_PWR_MIXER, RT5659_PWR_MM_BIT,
+               0, rt5659_monovol_mix, ARRAY_SIZE(rt5659_monovol_mix)),
+       SND_SOC_DAPM_MIXER("OUT MIXL", RT5659_PWR_MIXER, RT5659_PWR_OM_L_BIT,
+               0, rt5659_out_l_mix, ARRAY_SIZE(rt5659_out_l_mix)),
+       SND_SOC_DAPM_MIXER("OUT MIXR", RT5659_PWR_MIXER, RT5659_PWR_OM_R_BIT,
+               0, rt5659_out_r_mix, ARRAY_SIZE(rt5659_out_r_mix)),
+
+       /* Output Volume */
+       SND_SOC_DAPM_SWITCH("SPKVOL L", RT5659_PWR_VOL, RT5659_PWR_SV_L_BIT, 0,
+               &spkvol_l_switch),
+       SND_SOC_DAPM_SWITCH("SPKVOL R", RT5659_PWR_VOL, RT5659_PWR_SV_R_BIT, 0,
+               &spkvol_r_switch),
+       SND_SOC_DAPM_SWITCH("MONOVOL", RT5659_PWR_VOL, RT5659_PWR_MV_BIT, 0,
+               &monovol_switch),
+       SND_SOC_DAPM_SWITCH("OUTVOL L", RT5659_PWR_VOL, RT5659_PWR_OV_L_BIT, 0,
+               &outvol_l_switch),
+       SND_SOC_DAPM_SWITCH("OUTVOL R", RT5659_PWR_VOL, RT5659_PWR_OV_R_BIT, 0,
+               &outvol_r_switch),
+
+       /* SPO/MONO/HPO/LOUT */
+       SND_SOC_DAPM_MIXER("SPO L MIX", SND_SOC_NOPM, 0, 0, rt5659_spo_l_mix,
+               ARRAY_SIZE(rt5659_spo_l_mix)),
+       SND_SOC_DAPM_MIXER("SPO R MIX", SND_SOC_NOPM, 0, 0, rt5659_spo_r_mix,
+               ARRAY_SIZE(rt5659_spo_r_mix)),
+       SND_SOC_DAPM_MIXER("Mono MIX", SND_SOC_NOPM, 0, 0, rt5659_mono_mix,
+               ARRAY_SIZE(rt5659_mono_mix)),
+       SND_SOC_DAPM_MIXER("LOUT L MIX", SND_SOC_NOPM, 0, 0, rt5659_lout_l_mix,
+               ARRAY_SIZE(rt5659_lout_l_mix)),
+       SND_SOC_DAPM_MIXER("LOUT R MIX", SND_SOC_NOPM, 0, 0, rt5659_lout_r_mix,
+               ARRAY_SIZE(rt5659_lout_r_mix)),
+
+       SND_SOC_DAPM_PGA_S("SPK Amp", 1, RT5659_PWR_DIG_1, RT5659_PWR_CLS_D_BIT,
+               0, rt5659_spk_event, SND_SOC_DAPM_POST_PMD |
+               SND_SOC_DAPM_PRE_PMU),
+       SND_SOC_DAPM_PGA_S("Mono Amp", 1, RT5659_PWR_ANLG_1, RT5659_PWR_MA_BIT,
+               0, rt5659_mono_event, SND_SOC_DAPM_POST_PMD |
+               SND_SOC_DAPM_PRE_PMU),
+       SND_SOC_DAPM_PGA_S("HP Amp", 1, SND_SOC_NOPM, 0, 0, rt5659_hp_event,
+               SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU),
+       SND_SOC_DAPM_PGA("LOUT Amp", SND_SOC_NOPM, 0, 0, NULL, 0),
+
+       SND_SOC_DAPM_SUPPLY("Charge Pump", SND_SOC_NOPM, 0, 0,
+               rt5659_charge_pump_event, SND_SOC_DAPM_PRE_PMU |
+               SND_SOC_DAPM_POST_PMD),
+
+       SND_SOC_DAPM_SWITCH("SPO Playback", SND_SOC_NOPM, 0, 0, &spo_switch),
+       SND_SOC_DAPM_SWITCH("Mono Playback", SND_SOC_NOPM, 0, 0,
+               &mono_switch),
+       SND_SOC_DAPM_SWITCH("HPO L Playback", SND_SOC_NOPM, 0, 0,
+               &hpo_l_switch),
+       SND_SOC_DAPM_SWITCH("HPO R Playback", SND_SOC_NOPM, 0, 0,
+               &hpo_r_switch),
+       SND_SOC_DAPM_SWITCH("LOUT L Playback", SND_SOC_NOPM, 0, 0,
+               &lout_l_switch),
+       SND_SOC_DAPM_SWITCH("LOUT R Playback", SND_SOC_NOPM, 0, 0,
+               &lout_r_switch),
+       SND_SOC_DAPM_SWITCH("PDM L Playback", SND_SOC_NOPM, 0, 0,
+               &pdm_l_switch),
+       SND_SOC_DAPM_SWITCH("PDM R Playback", SND_SOC_NOPM, 0, 0,
+               &pdm_r_switch),
+
+       /* PDM */
+       SND_SOC_DAPM_SUPPLY("PDM Power", RT5659_PWR_DIG_2,
+               RT5659_PWR_PDM1_BIT, 0, NULL, 0),
+       SND_SOC_DAPM_MUX("PDM L Mux", RT5659_PDM_OUT_CTRL,
+               RT5659_M_PDM1_L_SFT, 1, &rt5659_pdm_l_mux),
+       SND_SOC_DAPM_MUX("PDM R Mux", RT5659_PDM_OUT_CTRL,
+               RT5659_M_PDM1_R_SFT, 1, &rt5659_pdm_r_mux),
+
+       /* SPDIF */
+       SND_SOC_DAPM_MUX("SPDIF Mux", SND_SOC_NOPM, 0, 0, &rt5659_spdif_mux),
+
+       SND_SOC_DAPM_SUPPLY("SYS CLK DET", RT5659_CLK_DET, 3, 0, NULL, 0),
+       SND_SOC_DAPM_SUPPLY("CLKDET", RT5659_CLK_DET, 0, 0, NULL, 0),
+
+       /* Output Lines */
+       SND_SOC_DAPM_OUTPUT("HPOL"),
+       SND_SOC_DAPM_OUTPUT("HPOR"),
+       SND_SOC_DAPM_OUTPUT("SPOL"),
+       SND_SOC_DAPM_OUTPUT("SPOR"),
+       SND_SOC_DAPM_OUTPUT("LOUTL"),
+       SND_SOC_DAPM_OUTPUT("LOUTR"),
+       SND_SOC_DAPM_OUTPUT("MONOOUT"),
+       SND_SOC_DAPM_OUTPUT("PDML"),
+       SND_SOC_DAPM_OUTPUT("PDMR"),
+       SND_SOC_DAPM_OUTPUT("SPDIF"),
+};
+
+static const struct snd_soc_dapm_route rt5659_dapm_routes[] = {
+       /*PLL*/
+       { "ADC Stereo1 Filter", NULL, "PLL", is_sys_clk_from_pll },
+       { "ADC Stereo2 Filter", NULL, "PLL", is_sys_clk_from_pll },
+       { "ADC Mono Left Filter", NULL, "PLL", is_sys_clk_from_pll },
+       { "ADC Mono Right Filter", NULL, "PLL", is_sys_clk_from_pll },
+       { "DAC Stereo1 Filter", NULL, "PLL", is_sys_clk_from_pll },
+       { "DAC Mono Left Filter", NULL, "PLL", is_sys_clk_from_pll },
+       { "DAC Mono Right Filter", NULL, "PLL", is_sys_clk_from_pll },
+
+       /*ASRC*/
+       { "ADC Stereo1 Filter", NULL, "ADC STO1 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 },
+       { "DAC Mono Right Filter", NULL, "DAC Mono R ASRC", is_using_asrc },
+       { "DAC Stereo1 Filter", NULL, "DAC STO ASRC", is_using_asrc },
+
+       { "SYS CLK DET", NULL, "CLKDET" },
+
+       { "I2S1", NULL, "I2S1 ASRC" },
+       { "I2S2", NULL, "I2S2 ASRC" },
+       { "I2S3", NULL, "I2S3 ASRC" },
+
+       { "IN1P", NULL, "LDO2" },
+       { "IN2P", NULL, "LDO2" },
+       { "IN3P", NULL, "LDO2" },
+       { "IN4P", NULL, "LDO2" },
+
+       { "DMIC1", NULL, "DMIC L1" },
+       { "DMIC1", NULL, "DMIC R1" },
+       { "DMIC2", NULL, "DMIC L2" },
+       { "DMIC2", NULL, "DMIC R2" },
+
+       { "BST1", NULL, "IN1P" },
+       { "BST1", NULL, "IN1N" },
+       { "BST1", NULL, "BST1 Power" },
+       { "BST2", NULL, "IN2P" },
+       { "BST2", NULL, "IN2N" },
+       { "BST2", NULL, "BST2 Power" },
+       { "BST3", NULL, "IN3P" },
+       { "BST3", NULL, "IN3N" },
+       { "BST3", NULL, "BST3 Power" },
+       { "BST4", NULL, "IN4P" },
+       { "BST4", NULL, "IN4N" },
+       { "BST4", NULL, "BST4 Power" },
+
+       { "INL VOL", NULL, "IN2P" },
+       { "INR VOL", NULL, "IN2N" },
+
+       { "RECMIX1L", "SPKVOLL Switch", "SPKVOL L" },
+       { "RECMIX1L", "INL Switch", "INL VOL" },
+       { "RECMIX1L", "BST4 Switch", "BST4" },
+       { "RECMIX1L", "BST3 Switch", "BST3" },
+       { "RECMIX1L", "BST2 Switch", "BST2" },
+       { "RECMIX1L", "BST1 Switch", "BST1" },
+
+       { "RECMIX1R", "HPOVOLR Switch", "HPO R Playback" },
+       { "RECMIX1R", "INR Switch", "INR VOL" },
+       { "RECMIX1R", "BST4 Switch", "BST4" },
+       { "RECMIX1R", "BST3 Switch", "BST3" },
+       { "RECMIX1R", "BST2 Switch", "BST2" },
+       { "RECMIX1R", "BST1 Switch", "BST1" },
+
+       { "RECMIX2L", "SPKVOLL Switch", "SPKVOL L" },
+       { "RECMIX2L", "OUTVOLL Switch", "OUTVOL L" },
+       { "RECMIX2L", "BST4 Switch", "BST4" },
+       { "RECMIX2L", "BST3 Switch", "BST3" },
+       { "RECMIX2L", "BST2 Switch", "BST2" },
+       { "RECMIX2L", "BST1 Switch", "BST1" },
+
+       { "RECMIX2R", "MONOVOL Switch", "MONOVOL" },
+       { "RECMIX2R", "OUTVOLR Switch", "OUTVOL R" },
+       { "RECMIX2R", "BST4 Switch", "BST4" },
+       { "RECMIX2R", "BST3 Switch", "BST3" },
+       { "RECMIX2R", "BST2 Switch", "BST2" },
+       { "RECMIX2R", "BST1 Switch", "BST1" },
+
+       { "ADC1 L", NULL, "RECMIX1L" },
+       { "ADC1 L", NULL, "ADC1 L Power" },
+       { "ADC1 L", NULL, "ADC1 clock" },
+       { "ADC1 R", NULL, "RECMIX1R" },
+       { "ADC1 R", NULL, "ADC1 R Power" },
+       { "ADC1 R", NULL, "ADC1 clock" },
+
+       { "ADC2 L", NULL, "RECMIX2L" },
+       { "ADC2 L", NULL, "ADC2 L Power" },
+       { "ADC2 L", NULL, "ADC2 clock" },
+       { "ADC2 R", NULL, "RECMIX2R" },
+       { "ADC2 R", NULL, "ADC2 R Power" },
+       { "ADC2 R", NULL, "ADC2 clock" },
+
+       { "DMIC L1", NULL, "DMIC CLK" },
+       { "DMIC L1", NULL, "DMIC1 Power" },
+       { "DMIC R1", NULL, "DMIC CLK" },
+       { "DMIC R1", NULL, "DMIC1 Power" },
+       { "DMIC L2", NULL, "DMIC CLK" },
+       { "DMIC L2", NULL, "DMIC2 Power" },
+       { "DMIC R2", NULL, "DMIC CLK" },
+       { "DMIC R2", NULL, "DMIC2 Power" },
+
+       { "Stereo1 DMIC L Mux", "DMIC1", "DMIC L1" },
+       { "Stereo1 DMIC L Mux", "DMIC2", "DMIC L2" },
+
+       { "Stereo1 DMIC R Mux", "DMIC1", "DMIC R1" },
+       { "Stereo1 DMIC R Mux", "DMIC2", "DMIC R2" },
+
+       { "Mono DMIC L Mux", "DMIC1 L", "DMIC L1" },
+       { "Mono DMIC L Mux", "DMIC2 L", "DMIC L2" },
+
+       { "Mono DMIC R Mux", "DMIC1 R", "DMIC R1" },
+       { "Mono DMIC R Mux", "DMIC2 R", "DMIC R2" },
+
+       { "Stereo1 ADC L Mux", "ADC1", "ADC1 L" },
+       { "Stereo1 ADC L Mux", "ADC2", "ADC2 L" },
+       { "Stereo1 ADC R Mux", "ADC1", "ADC1 R" },
+       { "Stereo1 ADC R Mux", "ADC2", "ADC2 R" },
+
+       { "Stereo1 ADC L1 Mux", "ADC", "Stereo1 ADC L Mux" },
+       { "Stereo1 ADC L1 Mux", "DAC MIX", "DAC MIXL" },
+       { "Stereo1 ADC L2 Mux", "DMIC", "Stereo1 DMIC L Mux" },
+       { "Stereo1 ADC L2 Mux", "DAC MIX", "DAC MIXL" },
+
+       { "Stereo1 ADC R1 Mux", "ADC", "Stereo1 ADC R Mux" },
+       { "Stereo1 ADC R1 Mux", "DAC MIX", "DAC MIXR" },
+       { "Stereo1 ADC R2 Mux", "DMIC", "Stereo1 DMIC R Mux" },
+       { "Stereo1 ADC R2 Mux", "DAC MIX", "DAC MIXR" },
+
+       { "Mono ADC L Mux", "ADC1 L", "ADC1 L" },
+       { "Mono ADC L Mux", "ADC1 R", "ADC1 R" },
+       { "Mono ADC L Mux", "ADC2 L", "ADC2 L" },
+       { "Mono ADC L Mux", "ADC2 R", "ADC2 R" },
+
+       { "Mono ADC R Mux", "ADC1 L", "ADC1 L" },
+       { "Mono ADC R Mux", "ADC1 R", "ADC1 R" },
+       { "Mono ADC R Mux", "ADC2 L", "ADC2 L" },
+       { "Mono ADC R Mux", "ADC2 R", "ADC2 R" },
+
+       { "Mono ADC L2 Mux", "DMIC", "Mono DMIC L Mux" },
+       { "Mono ADC L2 Mux", "Mono DAC MIXL", "Mono DAC MIXL" },
+       { "Mono ADC L1 Mux", "Mono DAC MIXL", "Mono DAC MIXL" },
+       { "Mono ADC L1 Mux", "ADC",  "Mono ADC L Mux" },
+
+       { "Mono ADC R1 Mux", "Mono DAC MIXR", "Mono DAC MIXR" },
+       { "Mono ADC R1 Mux", "ADC", "Mono ADC R Mux" },
+       { "Mono ADC R2 Mux", "DMIC", "Mono DMIC R Mux" },
+       { "Mono ADC R2 Mux", "Mono DAC MIXR", "Mono DAC MIXR" },
+
+       { "Stereo1 ADC MIXL", "ADC1 Switch", "Stereo1 ADC L1 Mux" },
+       { "Stereo1 ADC MIXL", "ADC2 Switch", "Stereo1 ADC L2 Mux" },
+       { "Stereo1 ADC MIXL", NULL, "ADC Stereo1 Filter" },
+
+       { "Stereo1 ADC MIXR", "ADC1 Switch", "Stereo1 ADC R1 Mux" },
+       { "Stereo1 ADC MIXR", "ADC2 Switch", "Stereo1 ADC R2 Mux" },
+       { "Stereo1 ADC MIXR", NULL, "ADC Stereo1 Filter" },
+
+       { "Mono ADC MIXL", "ADC1 Switch", "Mono ADC L1 Mux" },
+       { "Mono ADC MIXL", "ADC2 Switch", "Mono ADC L2 Mux" },
+       { "Mono ADC MIXL", NULL, "ADC Mono Left Filter" },
+
+       { "Mono ADC MIXR", "ADC1 Switch", "Mono ADC R1 Mux" },
+       { "Mono ADC MIXR", "ADC2 Switch", "Mono ADC R2 Mux" },
+       { "Mono ADC MIXR", NULL, "ADC Mono Right Filter" },
+
+       { "Stereo1 ADC Volume L", NULL, "Stereo1 ADC MIXL" },
+       { "Stereo1 ADC Volume R", NULL, "Stereo1 ADC MIXR" },
+
+       { "IF_ADC1", NULL, "Stereo1 ADC Volume L" },
+       { "IF_ADC1", NULL, "Stereo1 ADC Volume R" },
+       { "IF_ADC2", NULL, "Mono ADC MIXL" },
+       { "IF_ADC2", NULL, "Mono ADC MIXR" },
+
+       { "TDM AD1:AD2:DAC", NULL, "IF_ADC1" },
+       { "TDM AD1:AD2:DAC", NULL, "IF_ADC2" },
+       { "TDM AD1:AD2:DAC", NULL, "DAC_REF" },
+       { "TDM AD2:DAC", NULL, "IF_ADC2" },
+       { "TDM AD2:DAC", NULL, "DAC_REF" },
+       { "TDM Data Mux", "AD1:AD2:DAC:NUL", "TDM AD1:AD2:DAC" },
+       { "TDM Data Mux", "AD1:AD2:NUL:DAC", "TDM AD1:AD2:DAC" },
+       { "TDM Data Mux", "AD1:DAC:AD2:NUL", "TDM AD1:AD2:DAC" },
+       { "TDM Data Mux", "AD1:DAC:NUL:AD2", "TDM AD1:AD2:DAC" },
+       { "TDM Data Mux", "AD1:NUL:DAC:AD2", "TDM AD1:AD2:DAC" },
+       { "TDM Data Mux", "AD1:NUL:AD2:DAC", "TDM AD1:AD2:DAC" },
+       { "TDM Data Mux", "AD2:AD1:DAC:NUL", "TDM AD1:AD2:DAC" },
+       { "TDM Data Mux", "AD2:AD1:NUL:DAC", "TDM AD1:AD2:DAC" },
+       { "TDM Data Mux", "AD2:DAC:AD1:NUL", "TDM AD1:AD2:DAC" },
+       { "TDM Data Mux", "AD2:DAC:NUL:AD1", "TDM AD1:AD2:DAC" },
+       { "TDM Data Mux", "AD2:NUL:DAC:AD1", "TDM AD1:AD2:DAC" },
+       { "TDM Data Mux", "AD1:NUL:AD1:DAC", "TDM AD1:AD2:DAC" },
+       { "TDM Data Mux", "DAC:AD1:AD2:NUL", "TDM AD1:AD2:DAC" },
+       { "TDM Data Mux", "DAC:AD1:NUL:AD2", "TDM AD1:AD2:DAC" },
+       { "TDM Data Mux", "DAC:AD2:AD1:NUL", "TDM AD1:AD2:DAC" },
+       { "TDM Data Mux", "DAC:AD2:NUL:AD1", "TDM AD1:AD2:DAC" },
+       { "TDM Data Mux", "DAC:NUL:DAC:AD2", "TDM AD2:DAC" },
+       { "TDM Data Mux", "DAC:NUL:AD2:DAC", "TDM AD2:DAC" },
+       { "TDM Data Mux", "NUL:AD1:AD2:DAC", "TDM AD1:AD2:DAC" },
+       { "TDM Data Mux", "NUL:AD1:DAC:AD2", "TDM AD1:AD2:DAC" },
+       { "TDM Data Mux", "NUL:AD2:AD1:DAC", "TDM AD1:AD2:DAC" },
+       { "TDM Data Mux", "NUL:AD2:DAC:AD1", "TDM AD1:AD2:DAC" },
+       { "TDM Data Mux", "NUL:DAC:DAC:AD2", "TDM AD2:DAC" },
+       { "TDM Data Mux", "NUL:DAC:AD2:DAC", "TDM AD2:DAC" },
+       { "IF1 01 ADC Swap Mux", "L/R", "TDM Data Mux" },
+       { "IF1 01 ADC Swap Mux", "R/L", "TDM Data Mux" },
+       { "IF1 01 ADC Swap Mux", "L/L", "TDM Data Mux" },
+       { "IF1 01 ADC Swap Mux", "R/R", "TDM Data Mux" },
+       { "IF1 23 ADC Swap Mux", "L/R", "TDM Data Mux" },
+       { "IF1 23 ADC Swap Mux", "R/L", "TDM Data Mux" },
+       { "IF1 23 ADC Swap Mux", "L/L", "TDM Data Mux" },
+       { "IF1 23 ADC Swap Mux", "R/R", "TDM Data Mux" },
+       { "IF1 45 ADC Swap Mux", "L/R", "TDM Data Mux" },
+       { "IF1 45 ADC Swap Mux", "R/L", "TDM Data Mux" },
+       { "IF1 45 ADC Swap Mux", "L/L", "TDM Data Mux" },
+       { "IF1 45 ADC Swap Mux", "R/R", "TDM Data Mux" },
+       { "IF1 67 ADC Swap Mux", "L/R", "TDM Data Mux" },
+       { "IF1 67 ADC Swap Mux", "R/L", "TDM Data Mux" },
+       { "IF1 67 ADC Swap Mux", "L/L", "TDM Data Mux" },
+       { "IF1 67 ADC Swap Mux", "R/R", "TDM Data Mux" },
+       { "IF1 ADC", NULL, "IF1 01 ADC Swap Mux" },
+       { "IF1 ADC", NULL, "IF1 23 ADC Swap Mux" },
+       { "IF1 ADC", NULL, "IF1 45 ADC Swap Mux" },
+       { "IF1 ADC", NULL, "IF1 67 ADC Swap Mux" },
+       { "IF1 ADC", NULL, "I2S1" },
+
+       { "IF2 ADC Mux", "IF_ADC1", "IF_ADC1" },
+       { "IF2 ADC Mux", "IF_ADC2", "IF_ADC2" },
+       { "IF2 ADC Mux", "IF_ADC3", "IF_ADC3" },
+       { "IF2 ADC Mux", "DAC_REF", "DAC_REF" },
+       { "IF2 ADC", NULL, "IF2 ADC Mux"},
+       { "IF2 ADC", NULL, "I2S2" },
+
+       { "IF3 ADC Mux", "IF_ADC1", "IF_ADC1" },
+       { "IF3 ADC Mux", "IF_ADC2", "IF_ADC2" },
+       { "IF3 ADC Mux", "Stereo2_ADC_L/R", "Stereo2 ADC LR" },
+       { "IF3 ADC Mux", "DAC_REF", "DAC_REF" },
+       { "IF3 ADC", NULL, "IF3 ADC Mux"},
+       { "IF3 ADC", NULL, "I2S3" },
+
+       { "AIF1TX", NULL, "IF1 ADC" },
+       { "IF2 ADC Swap Mux", "L/R", "IF2 ADC" },
+       { "IF2 ADC Swap Mux", "R/L", "IF2 ADC" },
+       { "IF2 ADC Swap Mux", "L/L", "IF2 ADC" },
+       { "IF2 ADC Swap Mux", "R/R", "IF2 ADC" },
+       { "AIF2TX", NULL, "IF2 ADC Swap Mux" },
+       { "IF3 ADC Swap Mux", "L/R", "IF3 ADC" },
+       { "IF3 ADC Swap Mux", "R/L", "IF3 ADC" },
+       { "IF3 ADC Swap Mux", "L/L", "IF3 ADC" },
+       { "IF3 ADC Swap Mux", "R/R", "IF3 ADC" },
+       { "AIF3TX", NULL, "IF3 ADC Swap Mux" },
+
+       { "IF1 DAC1", NULL, "AIF1RX" },
+       { "IF1 DAC2", NULL, "AIF1RX" },
+       { "IF2 DAC Swap Mux", "L/R", "AIF2RX" },
+       { "IF2 DAC Swap Mux", "R/L", "AIF2RX" },
+       { "IF2 DAC Swap Mux", "L/L", "AIF2RX" },
+       { "IF2 DAC Swap Mux", "R/R", "AIF2RX" },
+       { "IF2 DAC", NULL, "IF2 DAC Swap Mux" },
+       { "IF3 DAC Swap Mux", "L/R", "AIF3RX" },
+       { "IF3 DAC Swap Mux", "R/L", "AIF3RX" },
+       { "IF3 DAC Swap Mux", "L/L", "AIF3RX" },
+       { "IF3 DAC Swap Mux", "R/R", "AIF3RX" },
+       { "IF3 DAC", NULL, "IF3 DAC Swap Mux" },
+
+       { "IF1 DAC1", NULL, "I2S1" },
+       { "IF1 DAC2", NULL, "I2S1" },
+       { "IF2 DAC", NULL, "I2S2" },
+       { "IF3 DAC", NULL, "I2S3" },
+
+       { "IF1 DAC2 L", NULL, "IF1 DAC2" },
+       { "IF1 DAC2 R", NULL, "IF1 DAC2" },
+       { "IF1 DAC1 L", NULL, "IF1 DAC1" },
+       { "IF1 DAC1 R", NULL, "IF1 DAC1" },
+       { "IF2 DAC L", NULL, "IF2 DAC" },
+       { "IF2 DAC R", NULL, "IF2 DAC" },
+       { "IF3 DAC L", NULL, "IF3 DAC" },
+       { "IF3 DAC R", NULL, "IF3 DAC" },
+
+       { "DAC L1 Mux", "IF1 DAC1", "IF1 DAC1 L" },
+       { "DAC L1 Mux", "IF2 DAC", "IF2 DAC L" },
+       { "DAC L1 Mux", "IF3 DAC", "IF3 DAC L" },
+       { "DAC L1 Mux", NULL, "DAC Stereo1 Filter" },
+
+       { "DAC R1 Mux", "IF1 DAC1", "IF1 DAC1 R" },
+       { "DAC R1 Mux", "IF2 DAC", "IF2 DAC R" },
+       { "DAC R1 Mux", "IF3 DAC", "IF3 DAC R" },
+       { "DAC R1 Mux", NULL, "DAC Stereo1 Filter" },
+
+       { "DAC1 MIXL", "Stereo ADC Switch", "Stereo1 ADC Volume L" },
+       { "DAC1 MIXL", "DAC1 Switch", "DAC L1 Mux" },
+       { "DAC1 MIXR", "Stereo ADC Switch", "Stereo1 ADC Volume R" },
+       { "DAC1 MIXR", "DAC1 Switch", "DAC R1 Mux" },
+
+       { "DAC_REF", NULL, "DAC1 MIXL" },
+       { "DAC_REF", NULL, "DAC1 MIXR" },
+
+       { "DAC L2 Mux", "IF1 DAC2", "IF1 DAC2 L" },
+       { "DAC L2 Mux", "IF2 DAC", "IF2 DAC L" },
+       { "DAC L2 Mux", "IF3 DAC", "IF3 DAC L" },
+       { "DAC L2 Mux", "Mono ADC MIX", "Mono ADC MIXL" },
+       { "DAC L2 Mux", NULL, "DAC Mono Left Filter" },
+
+       { "DAC R2 Mux", "IF1 DAC2", "IF1 DAC2 R" },
+       { "DAC R2 Mux", "IF2 DAC", "IF2 DAC R" },
+       { "DAC R2 Mux", "IF3 DAC", "IF3 DAC R" },
+       { "DAC R2 Mux", "Mono ADC MIX", "Mono ADC MIXR" },
+       { "DAC R2 Mux", NULL, "DAC Mono Right Filter" },
+
+       { "Stereo DAC MIXL", "DAC L1 Switch", "DAC1 MIXL" },
+       { "Stereo DAC MIXL", "DAC R1 Switch", "DAC1 MIXR" },
+       { "Stereo DAC MIXL", "DAC L2 Switch", "DAC L2 Mux" },
+       { "Stereo DAC MIXL", "DAC R2 Switch", "DAC R2 Mux" },
+
+       { "Stereo DAC MIXR", "DAC R1 Switch", "DAC1 MIXR" },
+       { "Stereo DAC MIXR", "DAC L1 Switch", "DAC1 MIXL" },
+       { "Stereo DAC MIXR", "DAC L2 Switch", "DAC L2 Mux" },
+       { "Stereo DAC MIXR", "DAC R2 Switch", "DAC R2 Mux" },
+
+       { "Mono DAC MIXL", "DAC L1 Switch", "DAC1 MIXL" },
+       { "Mono DAC MIXL", "DAC R1 Switch", "DAC1 MIXR" },
+       { "Mono DAC MIXL", "DAC L2 Switch", "DAC L2 Mux" },
+       { "Mono DAC MIXL", "DAC R2 Switch", "DAC R2 Mux" },
+       { "Mono DAC MIXR", "DAC L1 Switch", "DAC1 MIXL" },
+       { "Mono DAC MIXR", "DAC R1 Switch", "DAC1 MIXR" },
+       { "Mono DAC MIXR", "DAC R2 Switch", "DAC R2 Mux" },
+       { "Mono DAC MIXR", "DAC L2 Switch", "DAC L2 Mux" },
+
+       { "DAC MIXL", "Stereo DAC Mixer", "Stereo DAC MIXL" },
+       { "DAC MIXL", "Mono DAC Mixer", "Mono DAC MIXL" },
+       { "DAC MIXR", "Stereo DAC Mixer", "Stereo DAC MIXR" },
+       { "DAC MIXR", "Mono DAC Mixer", "Mono DAC MIXR" },
+
+       { "DAC L1 Source", NULL, "DAC L1 Power" },
+       { "DAC L1 Source", "DAC", "DAC1 MIXL" },
+       { "DAC L1 Source", "Stereo DAC Mixer", "Stereo DAC MIXL" },
+       { "DAC R1 Source", NULL, "DAC R1 Power" },
+       { "DAC R1 Source", "DAC", "DAC1 MIXR" },
+       { "DAC R1 Source", "Stereo DAC Mixer", "Stereo DAC MIXR" },
+       { "DAC L2 Source", "Stereo DAC Mixer", "Stereo DAC MIXL" },
+       { "DAC L2 Source", "Mono DAC Mixer", "Mono DAC MIXL" },
+       { "DAC L2 Source", NULL, "DAC L2 Power" },
+       { "DAC R2 Source", "Stereo DAC Mixer", "Stereo DAC MIXR" },
+       { "DAC R2 Source", "Mono DAC Mixer", "Mono DAC MIXR" },
+       { "DAC R2 Source", NULL, "DAC R2 Power" },
+
+       { "DAC L1", NULL, "DAC L1 Source" },
+       { "DAC R1", NULL, "DAC R1 Source" },
+       { "DAC L2", NULL, "DAC L2 Source" },
+       { "DAC R2", NULL, "DAC R2 Source" },
+
+       { "SPK MIXL", "DAC L2 Switch", "DAC L2" },
+       { "SPK MIXL", "BST1 Switch", "BST1" },
+       { "SPK MIXL", "INL Switch", "INL VOL" },
+       { "SPK MIXL", "INR Switch", "INR VOL" },
+       { "SPK MIXL", "BST3 Switch", "BST3" },
+       { "SPK MIXR", "DAC R2 Switch", "DAC R2" },
+       { "SPK MIXR", "BST4 Switch", "BST4" },
+       { "SPK MIXR", "INL Switch", "INL VOL" },
+       { "SPK MIXR", "INR Switch", "INR VOL" },
+       { "SPK MIXR", "BST3 Switch", "BST3" },
+
+       { "MONOVOL MIX", "DAC L2 Switch", "DAC L2" },
+       { "MONOVOL MIX", "DAC R2 Switch", "DAC R2" },
+       { "MONOVOL MIX", "BST1 Switch", "BST1" },
+       { "MONOVOL MIX", "BST2 Switch", "BST2" },
+       { "MONOVOL MIX", "BST3 Switch", "BST3" },
+
+       { "OUT MIXL", "DAC L2 Switch", "DAC L2" },
+       { "OUT MIXL", "INL Switch", "INL VOL" },
+       { "OUT MIXL", "BST1 Switch", "BST1" },
+       { "OUT MIXL", "BST2 Switch", "BST2" },
+       { "OUT MIXL", "BST3 Switch", "BST3" },
+       { "OUT MIXR", "DAC R2 Switch", "DAC R2" },
+       { "OUT MIXR", "INR Switch", "INR VOL" },
+       { "OUT MIXR", "BST2 Switch", "BST2" },
+       { "OUT MIXR", "BST3 Switch", "BST3" },
+       { "OUT MIXR", "BST4 Switch", "BST4" },
+
+       { "SPKVOL L", "Switch", "SPK MIXL" },
+       { "SPKVOL R", "Switch", "SPK MIXR" },
+       { "SPO L MIX", "DAC L2 Switch", "DAC L2" },
+       { "SPO L MIX", "SPKVOL L Switch", "SPKVOL L" },
+       { "SPO R MIX", "DAC R2 Switch", "DAC R2" },
+       { "SPO R MIX", "SPKVOL R Switch", "SPKVOL R" },
+       { "SPK Amp", NULL, "SPO L MIX" },
+       { "SPK Amp", NULL, "SPO R MIX" },
+       { "SPK Amp", NULL, "SYS CLK DET" },
+       { "SPO Playback", "Switch", "SPK Amp" },
+       { "SPOL", NULL, "SPO Playback" },
+       { "SPOR", NULL, "SPO Playback" },
+
+       { "MONOVOL", "Switch", "MONOVOL MIX" },
+       { "Mono MIX", "DAC L2 Switch", "DAC L2" },
+       { "Mono MIX", "MONOVOL Switch", "MONOVOL" },
+       { "Mono Amp", NULL, "Mono MIX" },
+       { "Mono Amp", NULL, "Mono Vref" },
+       { "Mono Amp", NULL, "SYS CLK DET" },
+       { "Mono Playback", "Switch", "Mono Amp" },
+       { "MONOOUT", NULL, "Mono Playback" },
+
+       { "HP Amp", NULL, "DAC L1" },
+       { "HP Amp", NULL, "DAC R1" },
+       { "HP Amp", NULL, "Charge Pump" },
+       { "HP Amp", NULL, "SYS CLK DET" },
+       { "HPO L Playback", "Switch", "HP Amp"},
+       { "HPO R Playback", "Switch", "HP Amp"},
+       { "HPOL", NULL, "HPO L Playback" },
+       { "HPOR", NULL, "HPO R Playback" },
+
+       { "OUTVOL L", "Switch", "OUT MIXL" },
+       { "OUTVOL R", "Switch", "OUT MIXR" },
+       { "LOUT L MIX", "DAC L2 Switch", "DAC L2" },
+       { "LOUT L MIX", "OUTVOL L Switch", "OUTVOL L" },
+       { "LOUT R MIX", "DAC R2 Switch", "DAC R2" },
+       { "LOUT R MIX", "OUTVOL R Switch", "OUTVOL R" },
+       { "LOUT Amp", NULL, "LOUT L MIX" },
+       { "LOUT Amp", NULL, "LOUT R MIX" },
+       { "LOUT Amp", NULL, "SYS CLK DET" },
+       { "LOUT L Playback", "Switch", "LOUT Amp" },
+       { "LOUT R Playback", "Switch", "LOUT Amp" },
+       { "LOUTL", NULL, "LOUT L Playback" },
+       { "LOUTR", NULL, "LOUT R Playback" },
+
+       { "PDM L Mux", "Mono DAC", "Mono DAC MIXL" },
+       { "PDM L Mux", "Stereo DAC", "Stereo DAC MIXL" },
+       { "PDM L Mux", NULL, "PDM Power" },
+       { "PDM R Mux", "Mono DAC", "Mono DAC MIXR" },
+       { "PDM R Mux", "Stereo DAC", "Stereo DAC MIXR" },
+       { "PDM R Mux", NULL, "PDM Power" },
+       { "PDM L Playback", "Switch", "PDM L Mux" },
+       { "PDM R Playback", "Switch", "PDM R Mux" },
+       { "PDML", NULL, "PDM L Playback" },
+       { "PDMR", NULL, "PDM R Playback" },
+
+       { "SPDIF Mux", "IF3_DAC", "IF3 DAC" },
+       { "SPDIF Mux", "IF2_DAC", "IF2 DAC" },
+       { "SPDIF Mux", "IF1_DAC2", "IF1 DAC2" },
+       { "SPDIF Mux", "IF1_DAC1", "IF1 DAC1" },
+       { "SPDIF", NULL, "SPDIF Mux" },
+};
+
+static int rt5659_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 rt5659_priv *rt5659 = snd_soc_codec_get_drvdata(codec);
+       unsigned int val_len = 0, val_clk, mask_clk;
+       int pre_div, frame_size;
+
+       rt5659->lrck[dai->id] = params_rate(params);
+       pre_div = rl6231_get_clk_info(rt5659->sysclk, rt5659->lrck[dai->id]);
+       if (pre_div < 0) {
+               dev_err(codec->dev, "Unsupported clock setting %d for DAI %d\n",
+                       rt5659->lrck[dai->id], dai->id);
+               return -EINVAL;
+       }
+       frame_size = snd_soc_params_to_frame_size(params);
+       if (frame_size < 0) {
+               dev_err(codec->dev, "Unsupported frame size: %d\n", frame_size);
+               return -EINVAL;
+       }
+
+       dev_dbg(dai->dev, "lrck is %dHz and pre_div is %d for iis %d\n",
+                               rt5659->lrck[dai->id], pre_div, dai->id);
+
+       switch (params_width(params)) {
+       case 16:
+               break;
+       case 20:
+               val_len |= RT5659_I2S_DL_20;
+               break;
+       case 24:
+               val_len |= RT5659_I2S_DL_24;
+               break;
+       case 8:
+               val_len |= RT5659_I2S_DL_8;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       switch (dai->id) {
+       case RT5659_AIF1:
+               mask_clk = RT5659_I2S_PD1_MASK;
+               val_clk = pre_div << RT5659_I2S_PD1_SFT;
+               snd_soc_update_bits(codec, RT5659_I2S1_SDP,
+                       RT5659_I2S_DL_MASK, val_len);
+               break;
+       case RT5659_AIF2:
+               mask_clk = RT5659_I2S_PD2_MASK;
+               val_clk = pre_div << RT5659_I2S_PD2_SFT;
+               snd_soc_update_bits(codec, RT5659_I2S2_SDP,
+                       RT5659_I2S_DL_MASK, val_len);
+               break;
+       case RT5659_AIF3:
+               mask_clk = RT5659_I2S_PD3_MASK;
+               val_clk = pre_div << RT5659_I2S_PD3_SFT;
+               snd_soc_update_bits(codec, RT5659_I2S3_SDP,
+                       RT5659_I2S_DL_MASK, val_len);
+               break;
+       default:
+               dev_err(codec->dev, "Invalid dai->id: %d\n", dai->id);
+               return -EINVAL;
+       }
+
+       snd_soc_update_bits(codec, RT5659_ADDA_CLK_1, mask_clk, val_clk);
+
+       switch (rt5659->lrck[dai->id]) {
+       case 192000:
+               snd_soc_update_bits(codec, RT5659_ADDA_CLK_1,
+                       RT5659_DAC_OSR_MASK, RT5659_DAC_OSR_32);
+               break;
+       case 96000:
+               snd_soc_update_bits(codec, RT5659_ADDA_CLK_1,
+                       RT5659_DAC_OSR_MASK, RT5659_DAC_OSR_64);
+               break;
+       default:
+               snd_soc_update_bits(codec, RT5659_ADDA_CLK_1,
+                       RT5659_DAC_OSR_MASK, RT5659_DAC_OSR_128);
+               break;
+       }
+
+       return 0;
+}
+
+static int rt5659_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)
+{
+       struct snd_soc_codec *codec = dai->codec;
+       struct rt5659_priv *rt5659 = snd_soc_codec_get_drvdata(codec);
+       unsigned int reg_val = 0;
+
+       switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+       case SND_SOC_DAIFMT_CBM_CFM:
+               rt5659->master[dai->id] = 1;
+               break;
+       case SND_SOC_DAIFMT_CBS_CFS:
+               reg_val |= RT5659_I2S_MS_S;
+               rt5659->master[dai->id] = 0;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+       case SND_SOC_DAIFMT_NB_NF:
+               break;
+       case SND_SOC_DAIFMT_IB_NF:
+               reg_val |= RT5659_I2S_BP_INV;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+       case SND_SOC_DAIFMT_I2S:
+               break;
+       case SND_SOC_DAIFMT_LEFT_J:
+               reg_val |= RT5659_I2S_DF_LEFT;
+               break;
+       case SND_SOC_DAIFMT_DSP_A:
+               reg_val |= RT5659_I2S_DF_PCM_A;
+               break;
+       case SND_SOC_DAIFMT_DSP_B:
+               reg_val |= RT5659_I2S_DF_PCM_B;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       switch (dai->id) {
+       case RT5659_AIF1:
+               snd_soc_update_bits(codec, RT5659_I2S1_SDP,
+                       RT5659_I2S_MS_MASK | RT5659_I2S_BP_MASK |
+                       RT5659_I2S_DF_MASK, reg_val);
+               break;
+       case RT5659_AIF2:
+               snd_soc_update_bits(codec, RT5659_I2S2_SDP,
+                       RT5659_I2S_MS_MASK | RT5659_I2S_BP_MASK |
+                       RT5659_I2S_DF_MASK, reg_val);
+               break;
+       case RT5659_AIF3:
+               snd_soc_update_bits(codec, RT5659_I2S3_SDP,
+                       RT5659_I2S_MS_MASK | RT5659_I2S_BP_MASK |
+                       RT5659_I2S_DF_MASK, reg_val);
+               break;
+       default:
+               dev_err(codec->dev, "Invalid dai->id: %d\n", dai->id);
+               return -EINVAL;
+       }
+       return 0;
+}
+
+static int rt5659_set_dai_sysclk(struct snd_soc_dai *dai,
+               int clk_id, unsigned int freq, int dir)
+{
+       struct snd_soc_codec *codec = dai->codec;
+       struct rt5659_priv *rt5659 = snd_soc_codec_get_drvdata(codec);
+       unsigned int reg_val = 0;
+
+       if (freq == rt5659->sysclk && clk_id == rt5659->sysclk_src)
+               return 0;
+
+       switch (clk_id) {
+       case RT5659_SCLK_S_MCLK:
+               reg_val |= RT5659_SCLK_SRC_MCLK;
+               break;
+       case RT5659_SCLK_S_PLL1:
+               reg_val |= RT5659_SCLK_SRC_PLL1;
+               break;
+       case RT5659_SCLK_S_RCCLK:
+               reg_val |= RT5659_SCLK_SRC_RCCLK;
+               break;
+       default:
+               dev_err(codec->dev, "Invalid clock id (%d)\n", clk_id);
+               return -EINVAL;
+       }
+       snd_soc_update_bits(codec, RT5659_GLB_CLK,
+               RT5659_SCLK_SRC_MASK, reg_val);
+       rt5659->sysclk = freq;
+       rt5659->sysclk_src = clk_id;
+
+       dev_dbg(dai->dev, "Sysclk is %dHz and clock id is %d\n", freq, clk_id);
+
+       return 0;
+}
+
+static int rt5659_set_dai_pll(struct snd_soc_dai *dai, int pll_id, int Source,
+                       unsigned int freq_in, unsigned int freq_out)
+{
+       struct snd_soc_codec *codec = dai->codec;
+       struct rt5659_priv *rt5659 = snd_soc_codec_get_drvdata(codec);
+       struct rl6231_pll_code pll_code;
+       int ret;
+
+       if (Source == rt5659->pll_src && freq_in == rt5659->pll_in &&
+           freq_out == rt5659->pll_out)
+               return 0;
+
+       if (!freq_in || !freq_out) {
+               dev_dbg(codec->dev, "PLL disabled\n");
+
+               rt5659->pll_in = 0;
+               rt5659->pll_out = 0;
+               snd_soc_update_bits(codec, RT5659_GLB_CLK,
+                       RT5659_SCLK_SRC_MASK, RT5659_SCLK_SRC_MCLK);
+               return 0;
+       }
+
+       switch (Source) {
+       case RT5659_PLL1_S_MCLK:
+               snd_soc_update_bits(codec, RT5659_GLB_CLK,
+                       RT5659_PLL1_SRC_MASK, RT5659_PLL1_SRC_MCLK);
+               break;
+       case RT5659_PLL1_S_BCLK1:
+               snd_soc_update_bits(codec, RT5659_GLB_CLK,
+                               RT5659_PLL1_SRC_MASK, RT5659_PLL1_SRC_BCLK1);
+               break;
+       case RT5659_PLL1_S_BCLK2:
+               snd_soc_update_bits(codec, RT5659_GLB_CLK,
+                               RT5659_PLL1_SRC_MASK, RT5659_PLL1_SRC_BCLK2);
+               break;
+       case RT5659_PLL1_S_BCLK3:
+               snd_soc_update_bits(codec, RT5659_GLB_CLK,
+                               RT5659_PLL1_SRC_MASK, RT5659_PLL1_SRC_BCLK3);
+               break;
+       default:
+               dev_err(codec->dev, "Unknown PLL Source %d\n", Source);
+               return -EINVAL;
+       }
+
+       ret = rl6231_pll_calc(freq_in, freq_out, &pll_code);
+       if (ret < 0) {
+               dev_err(codec->dev, "Unsupport input clock %d\n", freq_in);
+               return ret;
+       }
+
+       dev_dbg(codec->dev, "bypass=%d m=%d n=%d k=%d\n",
+               pll_code.m_bp, (pll_code.m_bp ? 0 : pll_code.m_code),
+               pll_code.n_code, pll_code.k_code);
+
+       snd_soc_write(codec, RT5659_PLL_CTRL_1,
+               pll_code.n_code << RT5659_PLL_N_SFT | pll_code.k_code);
+       snd_soc_write(codec, RT5659_PLL_CTRL_2,
+               (pll_code.m_bp ? 0 : pll_code.m_code) << RT5659_PLL_M_SFT |
+               pll_code.m_bp << RT5659_PLL_M_BP_SFT);
+
+       rt5659->pll_in = freq_in;
+       rt5659->pll_out = freq_out;
+       rt5659->pll_src = Source;
+
+       return 0;
+}
+
+static int rt5659_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;
+
+       if (rx_mask || tx_mask)
+               val |= (1 << 15);
+
+       switch (slots) {
+       case 4:
+               val |= (1 << 10);
+               val |= (1 << 8);
+               break;
+       case 6:
+               val |= (2 << 10);
+               val |= (2 << 8);
+               break;
+       case 8:
+               val |= (3 << 10);
+               val |= (3 << 8);
+               break;
+       case 2:
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       switch (slot_width) {
+       case 20:
+               val |= (1 << 6);
+               val |= (1 << 4);
+               break;
+       case 24:
+               val |= (2 << 6);
+               val |= (2 << 4);
+               break;
+       case 32:
+               val |= (3 << 6);
+               val |= (3 << 4);
+               break;
+       case 16:
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       snd_soc_update_bits(codec, RT5659_TDM_CTRL_1, 0x8ff0, val);
+
+       return 0;
+}
+
+static int rt5659_set_bclk_ratio(struct snd_soc_dai *dai, unsigned int ratio)
+{
+       struct snd_soc_codec *codec = dai->codec;
+       struct rt5659_priv *rt5659 = snd_soc_codec_get_drvdata(codec);
+
+       dev_dbg(codec->dev, "%s ratio=%d\n", __func__, ratio);
+
+       rt5659->bclk[dai->id] = ratio;
+
+       if (ratio == 64) {
+               switch (dai->id) {
+               case RT5659_AIF2:
+                       snd_soc_update_bits(codec, RT5659_ADDA_CLK_1,
+                               RT5659_I2S_BCLK_MS2_MASK,
+                               RT5659_I2S_BCLK_MS2_64);
+                       break;
+               case RT5659_AIF3:
+                       snd_soc_update_bits(codec, RT5659_ADDA_CLK_1,
+                               RT5659_I2S_BCLK_MS3_MASK,
+                               RT5659_I2S_BCLK_MS3_64);
+                       break;
+               }
+       }
+
+       return 0;
+}
+
+static int rt5659_set_bias_level(struct snd_soc_codec *codec,
+                       enum snd_soc_bias_level level)
+{
+       struct rt5659_priv *rt5659 = snd_soc_codec_get_drvdata(codec);
+
+       switch (level) {
+       case SND_SOC_BIAS_PREPARE:
+               regmap_update_bits(rt5659->regmap, RT5659_DIG_MISC,
+                       RT5659_DIG_GATE_CTRL, RT5659_DIG_GATE_CTRL);
+               regmap_update_bits(rt5659->regmap, RT5659_PWR_DIG_1,
+                       RT5659_PWR_LDO, RT5659_PWR_LDO);
+               regmap_update_bits(rt5659->regmap, RT5659_PWR_ANLG_1,
+                       RT5659_PWR_MB | RT5659_PWR_VREF1 | RT5659_PWR_VREF2,
+                       RT5659_PWR_MB | RT5659_PWR_VREF1 | RT5659_PWR_VREF2);
+               msleep(20);
+               regmap_update_bits(rt5659->regmap, RT5659_PWR_ANLG_1,
+                       RT5659_PWR_FV1 | RT5659_PWR_FV2,
+                       RT5659_PWR_FV1 | RT5659_PWR_FV2);
+               break;
+
+       case SND_SOC_BIAS_OFF:
+               regmap_update_bits(rt5659->regmap, RT5659_PWR_DIG_1,
+                       RT5659_PWR_LDO, 0);
+               regmap_update_bits(rt5659->regmap, RT5659_PWR_ANLG_1,
+                       RT5659_PWR_MB | RT5659_PWR_VREF1 | RT5659_PWR_VREF2
+                       | RT5659_PWR_FV1 | RT5659_PWR_FV2,
+                       RT5659_PWR_MB | RT5659_PWR_VREF2);
+               regmap_update_bits(rt5659->regmap, RT5659_DIG_MISC,
+                       RT5659_DIG_GATE_CTRL, 0);
+               break;
+
+       default:
+               break;
+       }
+
+       return 0;
+}
+
+static int rt5659_probe(struct snd_soc_codec *codec)
+{
+       struct rt5659_priv *rt5659 = snd_soc_codec_get_drvdata(codec);
+
+       rt5659->codec = codec;
+
+       return 0;
+}
+
+static int rt5659_remove(struct snd_soc_codec *codec)
+{
+       struct rt5659_priv *rt5659 = snd_soc_codec_get_drvdata(codec);
+
+       regmap_write(rt5659->regmap, RT5659_RESET, 0);
+
+       return 0;
+}
+
+#ifdef CONFIG_PM
+static int rt5659_suspend(struct snd_soc_codec *codec)
+{
+       struct rt5659_priv *rt5659 = snd_soc_codec_get_drvdata(codec);
+
+       regcache_cache_only(rt5659->regmap, true);
+       regcache_mark_dirty(rt5659->regmap);
+       return 0;
+}
+
+static int rt5659_resume(struct snd_soc_codec *codec)
+{
+       struct rt5659_priv *rt5659 = snd_soc_codec_get_drvdata(codec);
+
+       regcache_cache_only(rt5659->regmap, false);
+       regcache_sync(rt5659->regmap);
+
+       return 0;
+}
+#else
+#define rt5659_suspend NULL
+#define rt5659_resume NULL
+#endif
+
+#define RT5659_STEREO_RATES SNDRV_PCM_RATE_8000_192000
+#define RT5659_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE | \
+               SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S8)
+
+static const struct snd_soc_dai_ops rt5659_aif_dai_ops = {
+       .hw_params = rt5659_hw_params,
+       .set_fmt = rt5659_set_dai_fmt,
+       .set_sysclk = rt5659_set_dai_sysclk,
+       .set_tdm_slot = rt5659_set_tdm_slot,
+       .set_pll = rt5659_set_dai_pll,
+       .set_bclk_ratio = rt5659_set_bclk_ratio,
+};
+
+static struct snd_soc_dai_driver rt5659_dai[] = {
+       {
+               .name = "rt5659-aif1",
+               .id = RT5659_AIF1,
+               .playback = {
+                       .stream_name = "AIF1 Playback",
+                       .channels_min = 1,
+                       .channels_max = 2,
+                       .rates = RT5659_STEREO_RATES,
+                       .formats = RT5659_FORMATS,
+               },
+               .capture = {
+                       .stream_name = "AIF1 Capture",
+                       .channels_min = 1,
+                       .channels_max = 2,
+                       .rates = RT5659_STEREO_RATES,
+                       .formats = RT5659_FORMATS,
+               },
+               .ops = &rt5659_aif_dai_ops,
+       },
+       {
+               .name = "rt5659-aif2",
+               .id = RT5659_AIF2,
+               .playback = {
+                       .stream_name = "AIF2 Playback",
+                       .channels_min = 1,
+                       .channels_max = 2,
+                       .rates = RT5659_STEREO_RATES,
+                       .formats = RT5659_FORMATS,
+               },
+               .capture = {
+                       .stream_name = "AIF2 Capture",
+                       .channels_min = 1,
+                       .channels_max = 2,
+                       .rates = RT5659_STEREO_RATES,
+                       .formats = RT5659_FORMATS,
+               },
+               .ops = &rt5659_aif_dai_ops,
+       },
+       {
+               .name = "rt5659-aif3",
+               .id = RT5659_AIF3,
+               .playback = {
+                       .stream_name = "AIF3 Playback",
+                       .channels_min = 1,
+                       .channels_max = 2,
+                       .rates = RT5659_STEREO_RATES,
+                       .formats = RT5659_FORMATS,
+               },
+               .capture = {
+                       .stream_name = "AIF3 Capture",
+                       .channels_min = 1,
+                       .channels_max = 2,
+                       .rates = RT5659_STEREO_RATES,
+                       .formats = RT5659_FORMATS,
+               },
+               .ops = &rt5659_aif_dai_ops,
+       },
+};
+
+static struct snd_soc_codec_driver soc_codec_dev_rt5659 = {
+       .probe = rt5659_probe,
+       .remove = rt5659_remove,
+       .suspend = rt5659_suspend,
+       .resume = rt5659_resume,
+       .set_bias_level = rt5659_set_bias_level,
+       .idle_bias_off = true,
+       .controls = rt5659_snd_controls,
+       .num_controls = ARRAY_SIZE(rt5659_snd_controls),
+       .dapm_widgets = rt5659_dapm_widgets,
+       .num_dapm_widgets = ARRAY_SIZE(rt5659_dapm_widgets),
+       .dapm_routes = rt5659_dapm_routes,
+       .num_dapm_routes = ARRAY_SIZE(rt5659_dapm_routes),
+};
+
+
+static const struct regmap_config rt5659_regmap = {
+       .reg_bits = 16,
+       .val_bits = 16,
+       .max_register = 0x0400,
+       .volatile_reg = rt5659_volatile_register,
+       .readable_reg = rt5659_readable_register,
+       .cache_type = REGCACHE_RBTREE,
+       .reg_defaults = rt5659_reg,
+       .num_reg_defaults = ARRAY_SIZE(rt5659_reg),
+};
+
+static const struct i2c_device_id rt5659_i2c_id[] = {
+       { "rt5658", 0 },
+       { "rt5659", 0 },
+       { }
+};
+MODULE_DEVICE_TABLE(i2c, rt5659_i2c_id);
+
+static int rt5659_parse_dt(struct rt5659_priv *rt5659, struct device *dev)
+{
+       rt5659->pdata.in1_diff = device_property_read_bool(dev,
+                                       "realtek,in1-differential");
+       rt5659->pdata.in3_diff = device_property_read_bool(dev,
+                                       "realtek,in3-differential");
+       rt5659->pdata.in4_diff = device_property_read_bool(dev,
+                                       "realtek,in4-differential");
+
+
+       device_property_read_u32(dev, "realtek,dmic1-data-pin",
+               &rt5659->pdata.dmic1_data_pin);
+       device_property_read_u32(dev, "realtek,dmic2-data-pin",
+               &rt5659->pdata.dmic2_data_pin);
+       device_property_read_u32(dev, "realtek,jd-src",
+               &rt5659->pdata.jd_src);
+
+       return 0;
+}
+
+static void rt5659_calibrate(struct rt5659_priv *rt5659)
+{
+       int value, count;
+
+       /* Calibrate HPO Start */
+       /* Fine tune HP Performance */
+       regmap_write(rt5659->regmap, RT5659_BIAS_CUR_CTRL_8, 0xa502);
+       regmap_write(rt5659->regmap, RT5659_CHOP_DAC, 0x3030);
+
+       regmap_write(rt5659->regmap, RT5659_PRE_DIV_1, 0xef00);
+       regmap_write(rt5659->regmap, RT5659_PRE_DIV_2, 0xeffc);
+       regmap_write(rt5659->regmap, RT5659_MICBIAS_2, 0x0280);
+       regmap_write(rt5659->regmap, RT5659_DIG_MISC, 0x0001);
+       regmap_write(rt5659->regmap, RT5659_GLB_CLK, 0x8000);
+
+       regmap_write(rt5659->regmap, RT5659_PWR_ANLG_1, 0xaa7e);
+       msleep(60);
+       regmap_write(rt5659->regmap, RT5659_PWR_ANLG_1, 0xfe7e);
+       msleep(50);
+       regmap_write(rt5659->regmap, RT5659_PWR_ANLG_3, 0x0004);
+       regmap_write(rt5659->regmap, RT5659_PWR_DIG_2, 0x0400);
+       msleep(50);
+       regmap_write(rt5659->regmap, RT5659_PWR_DIG_1, 0x0080);
+       usleep_range(10000, 10005);
+       regmap_write(rt5659->regmap, RT5659_DEPOP_1, 0x0009);
+       msleep(50);
+       regmap_write(rt5659->regmap, RT5659_PWR_DIG_1, 0x0f80);
+       msleep(50);
+       regmap_write(rt5659->regmap, RT5659_HP_CHARGE_PUMP_1, 0x0e16);
+       msleep(50);
+
+       /* Enalbe K ADC Power And Clock */
+       regmap_write(rt5659->regmap, RT5659_CAL_REC, 0x0505);
+       msleep(50);
+       regmap_write(rt5659->regmap, RT5659_PWR_ANLG_3, 0x0184);
+       regmap_write(rt5659->regmap, RT5659_CALIB_ADC_CTRL, 0x3c05);
+       regmap_write(rt5659->regmap, RT5659_HP_CALIB_CTRL_2, 0x20c1);
+
+       /* K Headphone */
+       regmap_write(rt5659->regmap, RT5659_HP_CALIB_CTRL_2, 0x2cc1);
+       regmap_write(rt5659->regmap, RT5659_HP_CALIB_CTRL_1, 0x5100);
+       regmap_write(rt5659->regmap, RT5659_HP_CALIB_CTRL_7, 0x0014);
+       regmap_write(rt5659->regmap, RT5659_HP_CALIB_CTRL_1, 0xd100);
+       msleep(60);
+
+       /* Manual K ADC Offset */
+       regmap_write(rt5659->regmap, RT5659_HP_CALIB_CTRL_2, 0x2cc1);
+       regmap_write(rt5659->regmap, RT5659_HP_CALIB_CTRL_1, 0x4900);
+       regmap_write(rt5659->regmap, RT5659_HP_CALIB_CTRL_7, 0x0016);
+       regmap_update_bits(rt5659->regmap, RT5659_HP_CALIB_CTRL_1,
+               0x8000, 0x8000);
+
+       count = 0;
+       while (true) {
+               regmap_read(rt5659->regmap, RT5659_HP_CALIB_CTRL_1, &value);
+               if (value & 0x8000)
+                       usleep_range(10000, 10005);
+               else
+                       break;
+
+               if (count > 30) {
+                       dev_err(rt5659->codec->dev,
+                               "HP Calibration 1 Failure\n");
+                       return;
+               }
+
+               count++;
+       }
+
+       /* Manual K Internal Path Offset */
+       regmap_write(rt5659->regmap, RT5659_HP_CALIB_CTRL_2, 0x2cc1);
+       regmap_write(rt5659->regmap, RT5659_HP_VOL, 0x0000);
+       regmap_write(rt5659->regmap, RT5659_HP_CALIB_CTRL_1, 0x4500);
+       regmap_write(rt5659->regmap, RT5659_HP_CALIB_CTRL_7, 0x001f);
+       regmap_update_bits(rt5659->regmap, RT5659_HP_CALIB_CTRL_1,
+               0x8000, 0x8000);
+
+       count = 0;
+       while (true) {
+               regmap_read(rt5659->regmap, RT5659_HP_CALIB_CTRL_1, &value);
+               if (value & 0x8000)
+                       usleep_range(10000, 10005);
+               else
+                       break;
+
+               if (count > 85) {
+                       dev_err(rt5659->codec->dev,
+                               "HP Calibration 2 Failure\n");
+                       return;
+               }
+
+               count++;
+       }
+
+       regmap_write(rt5659->regmap, RT5659_HP_CALIB_CTRL_7, 0x0000);
+       regmap_write(rt5659->regmap, RT5659_HP_CALIB_CTRL_2, 0x20c0);
+       /* Calibrate HPO End */
+
+       /* Calibrate SPO Start */
+       regmap_write(rt5659->regmap, RT5659_CLASSD_0, 0x2021);
+       regmap_write(rt5659->regmap, RT5659_CLASSD_CTRL_1, 0x0260);
+       regmap_write(rt5659->regmap, RT5659_PWR_MIXER, 0x3000);
+       regmap_write(rt5659->regmap, RT5659_PWR_VOL, 0xc000);
+       regmap_write(rt5659->regmap, RT5659_A_DAC_MUX, 0x000c);
+       regmap_write(rt5659->regmap, RT5659_DIG_MISC, 0x8000);
+       regmap_write(rt5659->regmap, RT5659_SPO_VOL, 0x0808);
+       regmap_write(rt5659->regmap, RT5659_SPK_L_MIXER, 0x001e);
+       regmap_write(rt5659->regmap, RT5659_SPK_R_MIXER, 0x001e);
+       regmap_write(rt5659->regmap, RT5659_CLASSD_1, 0x0803);
+       regmap_write(rt5659->regmap, RT5659_CLASSD_2, 0x0554);
+       regmap_write(rt5659->regmap, RT5659_SPO_AMP_GAIN, 0x1103);
+
+       /* Enalbe K ADC Power And Clock */
+       regmap_write(rt5659->regmap, RT5659_CAL_REC, 0x0909);
+       regmap_update_bits(rt5659->regmap, RT5659_HP_CALIB_CTRL_2, 0x0001,
+               0x0001);
+
+       /* Start Calibration */
+       regmap_write(rt5659->regmap, RT5659_SPK_DC_CAILB_CTRL_3, 0x0000);
+       regmap_write(rt5659->regmap, RT5659_CLASSD_0, 0x0021);
+       regmap_write(rt5659->regmap, RT5659_SPK_DC_CAILB_CTRL_1, 0x3e80);
+       regmap_update_bits(rt5659->regmap, RT5659_SPK_DC_CAILB_CTRL_1,
+               0x8000, 0x8000);
+
+       count = 0;
+       while (true) {
+               regmap_read(rt5659->regmap,
+                               RT5659_SPK_DC_CAILB_CTRL_1, &value);
+               if (value & 0x8000)
+                       usleep_range(10000, 10005);
+               else
+                       break;
+
+               if (count > 10) {
+                       dev_err(rt5659->codec->dev,
+                               "SPK Calibration Failure\n");
+                       return;
+               }
+
+               count++;
+       }
+       /* Calibrate SPO End */
+
+       /* Calibrate MONO Start */
+       regmap_write(rt5659->regmap, RT5659_DIG_MISC, 0x0000);
+       regmap_write(rt5659->regmap, RT5659_MONOMIX_IN_GAIN, 0x021f);
+       regmap_write(rt5659->regmap, RT5659_MONO_OUT, 0x480a);
+       /* MONO NG2 GAIN 5dB */
+       regmap_write(rt5659->regmap, RT5659_MONO_GAIN, 0x0003);
+       regmap_write(rt5659->regmap, RT5659_MONO_NG2_CTRL_5, 0x0009);
+
+       /* Start Calibration */
+       regmap_write(rt5659->regmap, RT5659_SPK_DC_CAILB_CTRL_3, 0x000f);
+       regmap_write(rt5659->regmap, RT5659_MONO_AMP_CALIB_CTRL_1, 0x1e00);
+       regmap_update_bits(rt5659->regmap, RT5659_MONO_AMP_CALIB_CTRL_1,
+               0x8000, 0x8000);
+
+       count = 0;
+       while (true) {
+               regmap_read(rt5659->regmap, RT5659_MONO_AMP_CALIB_CTRL_1,
+                       &value);
+               if (value & 0x8000)
+                       usleep_range(10000, 10005);
+               else
+                       break;
+
+               if (count > 35) {
+                       dev_err(rt5659->codec->dev,
+                               "Mono Calibration Failure\n");
+                       return;
+               }
+
+               count++;
+       }
+
+       regmap_write(rt5659->regmap, RT5659_SPK_DC_CAILB_CTRL_3, 0x0003);
+       /* Calibrate MONO End */
+
+       /* Power Off */
+       regmap_write(rt5659->regmap, RT5659_CAL_REC, 0x0808);
+       regmap_write(rt5659->regmap, RT5659_PWR_ANLG_3, 0x0000);
+       regmap_write(rt5659->regmap, RT5659_CALIB_ADC_CTRL, 0x2005);
+       regmap_write(rt5659->regmap, RT5659_HP_CALIB_CTRL_2, 0x20c0);
+       regmap_write(rt5659->regmap, RT5659_DEPOP_1, 0x0000);
+       regmap_write(rt5659->regmap, RT5659_CLASSD_1, 0x0011);
+       regmap_write(rt5659->regmap, RT5659_CLASSD_2, 0x0150);
+       regmap_write(rt5659->regmap, RT5659_PWR_ANLG_1, 0xfe3e);
+       regmap_write(rt5659->regmap, RT5659_MONO_OUT, 0xc80a);
+       regmap_write(rt5659->regmap, RT5659_MONO_AMP_CALIB_CTRL_1, 0x1e04);
+       regmap_write(rt5659->regmap, RT5659_PWR_MIXER, 0x0000);
+       regmap_write(rt5659->regmap, RT5659_PWR_VOL, 0x0000);
+       regmap_write(rt5659->regmap, RT5659_PWR_DIG_1, 0x0000);
+       regmap_write(rt5659->regmap, RT5659_PWR_DIG_2, 0x0000);
+       regmap_write(rt5659->regmap, RT5659_PWR_ANLG_1, 0x003e);
+       regmap_write(rt5659->regmap, RT5659_CLASSD_CTRL_1, 0x0060);
+       regmap_write(rt5659->regmap, RT5659_CLASSD_0, 0x2021);
+       regmap_write(rt5659->regmap, RT5659_GLB_CLK, 0x0000);
+       regmap_write(rt5659->regmap, RT5659_MICBIAS_2, 0x0080);
+       regmap_write(rt5659->regmap, RT5659_HP_VOL, 0x8080);
+       regmap_write(rt5659->regmap, RT5659_HP_CHARGE_PUMP_1, 0x0c16);
+}
+
+static int rt5659_i2c_probe(struct i2c_client *i2c,
+                   const struct i2c_device_id *id)
+{
+       struct rt5659_platform_data *pdata = dev_get_platdata(&i2c->dev);
+       struct rt5659_priv *rt5659;
+       int ret;
+       unsigned int val;
+
+       rt5659 = devm_kzalloc(&i2c->dev, sizeof(struct rt5659_priv),
+               GFP_KERNEL);
+
+       if (rt5659 == NULL)
+               return -ENOMEM;
+
+       rt5659->i2c = i2c;
+       i2c_set_clientdata(i2c, rt5659);
+
+       if (pdata)
+               rt5659->pdata = *pdata;
+       else
+               rt5659_parse_dt(rt5659, &i2c->dev);
+
+       rt5659->gpiod_ldo1_en = devm_gpiod_get_optional(&i2c->dev, "ldo1-en",
+                                                       GPIOD_OUT_HIGH);
+       if (IS_ERR(rt5659->gpiod_ldo1_en))
+               dev_warn(&i2c->dev, "Request ldo1-en GPIO failed\n");
+
+       rt5659->gpiod_reset = devm_gpiod_get_optional(&i2c->dev, "reset",
+                                                       GPIOD_OUT_HIGH);
+
+       /* Sleep for 300 ms miniumum */
+       usleep_range(300000, 350000);
+
+       rt5659->regmap = devm_regmap_init_i2c(i2c, &rt5659_regmap);
+       if (IS_ERR(rt5659->regmap)) {
+               ret = PTR_ERR(rt5659->regmap);
+               dev_err(&i2c->dev, "Failed to allocate register map: %d\n",
+                       ret);
+               return ret;
+       }
+
+       regmap_read(rt5659->regmap, RT5659_DEVICE_ID, &val);
+       if (val != DEVICE_ID) {
+               dev_err(&i2c->dev,
+                       "Device with ID register %x is not rt5659\n", val);
+               return -ENODEV;
+       }
+
+       regmap_write(rt5659->regmap, RT5659_RESET, 0);
+
+       rt5659_calibrate(rt5659);
+
+       /* line in diff mode*/
+       if (rt5659->pdata.in1_diff)
+               regmap_update_bits(rt5659->regmap, RT5659_IN1_IN2,
+                       RT5659_IN1_DF_MASK, RT5659_IN1_DF_MASK);
+       if (rt5659->pdata.in3_diff)
+               regmap_update_bits(rt5659->regmap, RT5659_IN3_IN4,
+                       RT5659_IN3_DF_MASK, RT5659_IN3_DF_MASK);
+       if (rt5659->pdata.in4_diff)
+               regmap_update_bits(rt5659->regmap, RT5659_IN3_IN4,
+                       RT5659_IN4_DF_MASK, RT5659_IN4_DF_MASK);
+
+       /* DMIC pin*/
+       if (rt5659->pdata.dmic1_data_pin != RT5659_DMIC1_NULL ||
+               rt5659->pdata.dmic2_data_pin != RT5659_DMIC2_NULL) {
+               regmap_update_bits(rt5659->regmap, RT5659_GPIO_CTRL_1,
+                       RT5659_GP2_PIN_MASK, RT5659_GP2_PIN_DMIC1_SCL);
+
+               switch (rt5659->pdata.dmic1_data_pin) {
+               case RT5659_DMIC1_DATA_IN2N:
+                       regmap_update_bits(rt5659->regmap, RT5659_DMIC_CTRL_1,
+                               RT5659_DMIC_1_DP_MASK, RT5659_DMIC_1_DP_IN2N);
+                       break;
+
+               case RT5659_DMIC1_DATA_GPIO5:
+                       regmap_update_bits(rt5659->regmap,
+                               RT5659_GPIO_CTRL_3,
+                               RT5659_I2S2_PIN_MASK,
+                               RT5659_I2S2_PIN_GPIO);
+                       regmap_update_bits(rt5659->regmap, RT5659_DMIC_CTRL_1,
+                               RT5659_DMIC_1_DP_MASK, RT5659_DMIC_1_DP_GPIO5);
+                       regmap_update_bits(rt5659->regmap, RT5659_GPIO_CTRL_1,
+                               RT5659_GP5_PIN_MASK, RT5659_GP5_PIN_DMIC1_SDA);
+                       break;
+
+               case RT5659_DMIC1_DATA_GPIO9:
+                       regmap_update_bits(rt5659->regmap, RT5659_DMIC_CTRL_1,
+                               RT5659_DMIC_1_DP_MASK, RT5659_DMIC_1_DP_GPIO9);
+                       regmap_update_bits(rt5659->regmap, RT5659_GPIO_CTRL_1,
+                               RT5659_GP9_PIN_MASK, RT5659_GP9_PIN_DMIC1_SDA);
+                       break;
+
+               case RT5659_DMIC1_DATA_GPIO11:
+                       regmap_update_bits(rt5659->regmap, RT5659_DMIC_CTRL_1,
+                               RT5659_DMIC_1_DP_MASK, RT5659_DMIC_1_DP_GPIO11);
+                       regmap_update_bits(rt5659->regmap, RT5659_GPIO_CTRL_1,
+                               RT5659_GP11_PIN_MASK,
+                               RT5659_GP11_PIN_DMIC1_SDA);
+                       break;
+
+               default:
+                       dev_dbg(&i2c->dev, "no DMIC1\n");
+                       break;
+               }
+
+               switch (rt5659->pdata.dmic2_data_pin) {
+               case RT5659_DMIC2_DATA_IN2P:
+                       regmap_update_bits(rt5659->regmap,
+                               RT5659_DMIC_CTRL_1,
+                               RT5659_DMIC_2_DP_MASK,
+                               RT5659_DMIC_2_DP_IN2P);
+                       break;
+
+               case RT5659_DMIC2_DATA_GPIO6:
+                       regmap_update_bits(rt5659->regmap,
+                               RT5659_DMIC_CTRL_1,
+                               RT5659_DMIC_2_DP_MASK,
+                               RT5659_DMIC_2_DP_GPIO6);
+                       regmap_update_bits(rt5659->regmap,
+                               RT5659_GPIO_CTRL_1,
+                               RT5659_GP6_PIN_MASK,
+                               RT5659_GP6_PIN_DMIC2_SDA);
+                       break;
+
+               case RT5659_DMIC2_DATA_GPIO10:
+                       regmap_update_bits(rt5659->regmap,
+                               RT5659_DMIC_CTRL_1,
+                               RT5659_DMIC_2_DP_MASK,
+                               RT5659_DMIC_2_DP_GPIO10);
+                       regmap_update_bits(rt5659->regmap,
+                               RT5659_GPIO_CTRL_1,
+                               RT5659_GP10_PIN_MASK,
+                               RT5659_GP10_PIN_DMIC2_SDA);
+                       break;
+
+               case RT5659_DMIC2_DATA_GPIO12:
+                       regmap_update_bits(rt5659->regmap,
+                               RT5659_DMIC_CTRL_1,
+                               RT5659_DMIC_2_DP_MASK,
+                               RT5659_DMIC_2_DP_GPIO12);
+                       regmap_update_bits(rt5659->regmap,
+                               RT5659_GPIO_CTRL_1,
+                               RT5659_GP12_PIN_MASK,
+                               RT5659_GP12_PIN_DMIC2_SDA);
+                       break;
+
+               default:
+                       dev_dbg(&i2c->dev, "no DMIC2\n");
+                       break;
+
+               }
+       } else {
+               regmap_update_bits(rt5659->regmap, RT5659_GPIO_CTRL_1,
+                       RT5659_GP2_PIN_MASK | RT5659_GP5_PIN_MASK |
+                       RT5659_GP9_PIN_MASK | RT5659_GP11_PIN_MASK |
+                       RT5659_GP6_PIN_MASK | RT5659_GP10_PIN_MASK |
+                       RT5659_GP12_PIN_MASK,
+                       RT5659_GP2_PIN_GPIO2 | RT5659_GP5_PIN_GPIO5 |
+                       RT5659_GP9_PIN_GPIO9 | RT5659_GP11_PIN_GPIO11 |
+                       RT5659_GP6_PIN_GPIO6 | RT5659_GP10_PIN_GPIO10 |
+                       RT5659_GP12_PIN_GPIO12);
+               regmap_update_bits(rt5659->regmap, RT5659_DMIC_CTRL_1,
+                       RT5659_DMIC_1_DP_MASK | RT5659_DMIC_2_DP_MASK,
+                       RT5659_DMIC_1_DP_IN2N | RT5659_DMIC_2_DP_IN2P);
+       }
+
+       switch (rt5659->pdata.jd_src) {
+       case RT5659_JD3:
+               regmap_write(rt5659->regmap, RT5659_EJD_CTRL_1, 0xa880);
+               regmap_write(rt5659->regmap, RT5659_RC_CLK_CTRL, 0x9000);
+               regmap_write(rt5659->regmap, RT5659_GPIO_CTRL_1, 0xc800);
+               regmap_update_bits(rt5659->regmap, RT5659_PWR_ANLG_1,
+                               RT5659_PWR_MB, RT5659_PWR_MB);
+               regmap_write(rt5659->regmap, RT5659_PWR_ANLG_2, 0x0001);
+               regmap_write(rt5659->regmap, RT5659_IRQ_CTRL_2, 0x0040);
+               break;
+       case RT5659_JD_NULL:
+               break;
+       default:
+               dev_warn(&i2c->dev, "Currently, support JD3 only\n");
+               break;
+       }
+
+       INIT_DELAYED_WORK(&rt5659->jack_detect_work, rt5659_jack_detect_work);
+
+       if (rt5659->i2c->irq) {
+               ret = request_threaded_irq(rt5659->i2c->irq, NULL, rt5659_irq,
+                       IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING
+                       | IRQF_ONESHOT, "rt5659", rt5659);
+               if (ret)
+                       dev_err(&i2c->dev, "Failed to reguest IRQ: %d\n", ret);
+
+       }
+
+       ret = snd_soc_register_codec(&i2c->dev, &soc_codec_dev_rt5659,
+                       rt5659_dai, ARRAY_SIZE(rt5659_dai));
+
+       if (ret) {
+               if (rt5659->i2c->irq)
+                       free_irq(rt5659->i2c->irq, rt5659);
+       }
+
+       return 0;
+}
+
+static int rt5659_i2c_remove(struct i2c_client *i2c)
+{
+       snd_soc_unregister_codec(&i2c->dev);
+
+       return 0;
+}
+
+void rt5659_i2c_shutdown(struct i2c_client *client)
+{
+       struct rt5659_priv *rt5659 = i2c_get_clientdata(client);
+
+       regmap_write(rt5659->regmap, RT5659_RESET, 0);
+}
+
+static const struct of_device_id rt5659_of_match[] = {
+       { .compatible = "realtek,rt5658", },
+       { .compatible = "realtek,rt5659", },
+       {},
+};
+
+static struct acpi_device_id rt5659_acpi_match[] = {
+               { "10EC5658", 0},
+               { "10EC5659", 0},
+               { },
+};
+MODULE_DEVICE_TABLE(acpi, rt5659_acpi_match);
+
+struct i2c_driver rt5659_i2c_driver = {
+       .driver = {
+               .name = "rt5659",
+               .owner = THIS_MODULE,
+               .of_match_table = rt5659_of_match,
+               .acpi_match_table = ACPI_PTR(rt5659_acpi_match),
+       },
+       .probe = rt5659_i2c_probe,
+       .remove = rt5659_i2c_remove,
+       .shutdown = rt5659_i2c_shutdown,
+       .id_table = rt5659_i2c_id,
+};
+module_i2c_driver(rt5659_i2c_driver);
+
+MODULE_DESCRIPTION("ASoC RT5659 driver");
+MODULE_AUTHOR("Bard Liao <bardliao@realtek.com>");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/codecs/rt5659.h b/sound/soc/codecs/rt5659.h
new file mode 100644 (file)
index 0000000..8f07ee9
--- /dev/null
@@ -0,0 +1,1819 @@
+/*
+ * rt5659.h  --  RT5659/RT5658 ALSA SoC audio driver
+ *
+ * Copyright 2015 Realtek Microelectronics
+ * Author: Bard Liao <bardliao@realtek.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 __RT5659_H__
+#define __RT5659_H__
+
+#include <sound/rt5659.h>
+
+#define DEVICE_ID 0x6311
+
+/* Info */
+#define RT5659_RESET                           0x0000
+#define RT5659_VENDOR_ID                       0x00fd
+#define RT5659_VENDOR_ID_1                     0x00fe
+#define RT5659_DEVICE_ID                       0x00ff
+/*  I/O - Output */
+#define RT5659_SPO_VOL                         0x0001
+#define RT5659_HP_VOL                          0x0002
+#define RT5659_LOUT                            0x0003
+#define RT5659_MONO_OUT                                0x0004
+#define RT5659_HPL_GAIN                                0x0005
+#define RT5659_HPR_GAIN                                0x0006
+#define RT5659_MONO_GAIN                       0x0007
+#define RT5659_SPDIF_CTRL_1                    0x0008
+#define RT5659_SPDIF_CTRL_2                    0x0009
+/* I/O - Input */
+#define RT5659_CAL_BST_CTRL                    0x000a
+#define RT5659_IN1_IN2                         0x000c
+#define RT5659_IN3_IN4                         0x000d
+#define RT5659_INL1_INR1_VOL                   0x000f
+/* I/O - Speaker */
+#define RT5659_EJD_CTRL_1                      0x0010
+#define RT5659_EJD_CTRL_2                      0x0011
+#define RT5659_EJD_CTRL_3                      0x0012
+#define RT5659_SILENCE_CTRL                    0x0015
+#define RT5659_PSV_CTRL                                0x0016
+/* I/O - Sidetone */
+#define RT5659_SIDETONE_CTRL                   0x0018
+/* I/O - ADC/DAC/DMIC */
+#define RT5659_DAC1_DIG_VOL                    0x0019
+#define RT5659_DAC2_DIG_VOL                    0x001a
+#define RT5659_DAC_CTRL                                0x001b
+#define RT5659_STO1_ADC_DIG_VOL                        0x001c
+#define RT5659_MONO_ADC_DIG_VOL                        0x001d
+#define RT5659_STO2_ADC_DIG_VOL                        0x001e
+#define RT5659_STO1_BOOST                      0x001f
+#define RT5659_MONO_BOOST                      0x0020
+#define RT5659_STO2_BOOST                      0x0021
+#define RT5659_HP_IMP_GAIN_1                   0x0022
+#define RT5659_HP_IMP_GAIN_2                   0x0023
+/* Mixer - D-D */
+#define RT5659_STO1_ADC_MIXER                  0x0026
+#define RT5659_MONO_ADC_MIXER                  0x0027
+#define RT5659_AD_DA_MIXER                     0x0029
+#define RT5659_STO_DAC_MIXER                   0x002a
+#define RT5659_MONO_DAC_MIXER                  0x002b
+#define RT5659_DIG_MIXER                       0x002c
+#define RT5659_A_DAC_MUX                       0x002d
+#define RT5659_DIG_INF23_DATA                  0x002f
+/* Mixer - PDM */
+#define RT5659_PDM_OUT_CTRL                    0x0031
+#define RT5659_PDM_DATA_CTRL_1                 0x0032
+#define RT5659_PDM_DATA_CTRL_2                 0x0033
+#define RT5659_PDM_DATA_CTRL_3                 0x0034
+#define RT5659_PDM_DATA_CTRL_4                 0x0035
+#define RT5659_SPDIF_CTRL                      0x0036
+
+/* Mixer - ADC */
+#define RT5659_REC1_GAIN                       0x003a
+#define RT5659_REC1_L1_MIXER                   0x003b
+#define RT5659_REC1_L2_MIXER                   0x003c
+#define RT5659_REC1_R1_MIXER                   0x003d
+#define RT5659_REC1_R2_MIXER                   0x003e
+#define RT5659_CAL_REC                         0x0040
+#define RT5659_REC2_L1_MIXER                   0x009b
+#define RT5659_REC2_L2_MIXER                   0x009c
+#define RT5659_REC2_R1_MIXER                   0x009d
+#define RT5659_REC2_R2_MIXER                   0x009e
+#define RT5659_RC_CLK_CTRL                     0x009f
+/* Mixer - DAC */
+#define RT5659_SPK_L_MIXER                     0x0046
+#define RT5659_SPK_R_MIXER                     0x0047
+#define RT5659_SPO_AMP_GAIN                    0x0048
+#define RT5659_ALC_BACK_GAIN                   0x0049
+#define RT5659_MONOMIX_GAIN                    0x004a
+#define RT5659_MONOMIX_IN_GAIN                 0x004b
+#define RT5659_OUT_L_GAIN                      0x004d
+#define RT5659_OUT_L_MIXER                     0x004e
+#define RT5659_OUT_R_GAIN                      0x004f
+#define RT5659_OUT_R_MIXER                     0x0050
+#define RT5659_LOUT_MIXER                      0x0052
+
+#define RT5659_HAPTIC_GEN_CTRL_1               0x0053
+#define RT5659_HAPTIC_GEN_CTRL_2               0x0054
+#define RT5659_HAPTIC_GEN_CTRL_3               0x0055
+#define RT5659_HAPTIC_GEN_CTRL_4               0x0056
+#define RT5659_HAPTIC_GEN_CTRL_5               0x0057
+#define RT5659_HAPTIC_GEN_CTRL_6               0x0058
+#define RT5659_HAPTIC_GEN_CTRL_7               0x0059
+#define RT5659_HAPTIC_GEN_CTRL_8               0x005a
+#define RT5659_HAPTIC_GEN_CTRL_9               0x005b
+#define RT5659_HAPTIC_GEN_CTRL_10              0x005c
+#define RT5659_HAPTIC_GEN_CTRL_11              0x005d
+#define RT5659_HAPTIC_LPF_CTRL_1               0x005e
+#define RT5659_HAPTIC_LPF_CTRL_2               0x005f
+#define RT5659_HAPTIC_LPF_CTRL_3               0x0060
+/* Power */
+#define RT5659_PWR_DIG_1                       0x0061
+#define RT5659_PWR_DIG_2                       0x0062
+#define RT5659_PWR_ANLG_1                      0x0063
+#define RT5659_PWR_ANLG_2                      0x0064
+#define RT5659_PWR_ANLG_3                      0x0065
+#define RT5659_PWR_MIXER                       0x0066
+#define RT5659_PWR_VOL                         0x0067
+/* Private Register Control */
+#define RT5659_PRIV_INDEX                      0x006a
+#define RT5659_CLK_DET                         0x006b
+#define RT5659_PRIV_DATA                       0x006c
+/* System Clock Pre Divider Gating Control */
+#define RT5659_PRE_DIV_1                       0x006e
+#define RT5659_PRE_DIV_2                       0x006f
+/* Format - ADC/DAC */
+#define RT5659_I2S1_SDP                                0x0070
+#define RT5659_I2S2_SDP                                0x0071
+#define RT5659_I2S3_SDP                                0x0072
+#define RT5659_ADDA_CLK_1                      0x0073
+#define RT5659_ADDA_CLK_2                      0x0074
+#define RT5659_DMIC_CTRL_1                     0x0075
+#define RT5659_DMIC_CTRL_2                     0x0076
+/* Format - TDM Control */
+#define RT5659_TDM_CTRL_1                      0x0077
+#define RT5659_TDM_CTRL_2                      0x0078
+#define RT5659_TDM_CTRL_3                      0x0079
+#define RT5659_TDM_CTRL_4                      0x007a
+#define RT5659_TDM_CTRL_5                      0x007b
+
+/* Function - Analog */
+#define RT5659_GLB_CLK                         0x0080
+#define RT5659_PLL_CTRL_1                      0x0081
+#define RT5659_PLL_CTRL_2                      0x0082
+#define RT5659_ASRC_1                          0x0083
+#define RT5659_ASRC_2                          0x0084
+#define RT5659_ASRC_3                          0x0085
+#define RT5659_ASRC_4                          0x0086
+#define RT5659_ASRC_5                          0x0087
+#define RT5659_ASRC_6                          0x0088
+#define RT5659_ASRC_7                          0x0089
+#define RT5659_ASRC_8                          0x008a
+#define RT5659_ASRC_9                          0x008b
+#define RT5659_ASRC_10                         0x008c
+#define RT5659_DEPOP_1                         0x008e
+#define RT5659_DEPOP_2                         0x008f
+#define RT5659_DEPOP_3                         0x0090
+#define RT5659_HP_CHARGE_PUMP_1                        0x0091
+#define RT5659_HP_CHARGE_PUMP_2                        0x0092
+#define RT5659_MICBIAS_1                       0x0093
+#define RT5659_MICBIAS_2                       0x0094
+#define RT5659_ASRC_11                         0x0097
+#define RT5659_ASRC_12                         0x0098
+#define RT5659_ASRC_13                         0x0099
+#define RT5659_REC_M1_M2_GAIN_CTRL             0x009a
+#define RT5659_CLASSD_CTRL_1                   0x00a0
+#define RT5659_CLASSD_CTRL_2                   0x00a1
+
+/* Function - Digital */
+#define RT5659_ADC_EQ_CTRL_1                   0x00ae
+#define RT5659_ADC_EQ_CTRL_2                   0x00af
+#define RT5659_DAC_EQ_CTRL_1                   0x00b0
+#define RT5659_DAC_EQ_CTRL_2                   0x00b1
+#define RT5659_DAC_EQ_CTRL_3                   0x00b2
+
+#define RT5659_IRQ_CTRL_1                      0x00b6
+#define RT5659_IRQ_CTRL_2                      0x00b7
+#define RT5659_IRQ_CTRL_3                      0x00b8
+#define RT5659_IRQ_CTRL_4                      0x00b9
+#define RT5659_IRQ_CTRL_5                      0x00ba
+#define RT5659_IRQ_CTRL_6                      0x00bb
+#define RT5659_INT_ST_1                                0x00be
+#define RT5659_INT_ST_2                                0x00bf
+#define RT5659_GPIO_CTRL_1                     0x00c0
+#define RT5659_GPIO_CTRL_2                     0x00c1
+#define RT5659_GPIO_CTRL_3                     0x00c2
+#define RT5659_GPIO_CTRL_4                     0x00c3
+#define RT5659_GPIO_CTRL_5                     0x00c4
+#define RT5659_GPIO_STA                                0x00c5
+#define RT5659_SINE_GEN_CTRL_1                 0x00cb
+#define RT5659_SINE_GEN_CTRL_2                 0x00cc
+#define RT5659_SINE_GEN_CTRL_3                 0x00cd
+#define RT5659_HP_AMP_DET_CTRL_1               0x00d6
+#define RT5659_HP_AMP_DET_CTRL_2               0x00d7
+#define RT5659_SV_ZCD_1                                0x00d9
+#define RT5659_SV_ZCD_2                                0x00da
+#define RT5659_IL_CMD_1                                0x00db
+#define RT5659_IL_CMD_2                                0x00dc
+#define RT5659_IL_CMD_3                                0x00dd
+#define RT5659_IL_CMD_4                                0x00de
+#define RT5659_4BTN_IL_CMD_1                   0x00df
+#define RT5659_4BTN_IL_CMD_2                   0x00e0
+#define RT5659_4BTN_IL_CMD_3                   0x00e1
+#define RT5659_PSV_IL_CMD_1                    0x00e4
+#define RT5659_PSV_IL_CMD_2                    0x00e5
+
+#define RT5659_ADC_STO1_HP_CTRL_1              0x00ea
+#define RT5659_ADC_STO1_HP_CTRL_2              0x00eb
+#define RT5659_ADC_MONO_HP_CTRL_1              0x00ec
+#define RT5659_ADC_MONO_HP_CTRL_2              0x00ed
+#define RT5659_AJD1_CTRL                       0x00f0
+#define RT5659_AJD2_AJD3_CTRL                  0x00f1
+#define RT5659_JD1_THD                         0x00f2
+#define RT5659_JD2_THD                         0x00f3
+#define RT5659_JD3_THD                         0x00f4
+#define RT5659_JD_CTRL_1                       0x00f6
+#define RT5659_JD_CTRL_2                       0x00f7
+#define RT5659_JD_CTRL_3                       0x00f8
+#define RT5659_JD_CTRL_4                       0x00f9
+/* General Control */
+#define RT5659_DIG_MISC                                0x00fa
+#define RT5659_DUMMY_2                         0x00fb
+#define RT5659_DUMMY_3                         0x00fc
+
+#define RT5659_DAC_ADC_DIG_VOL                 0x0100
+#define RT5659_BIAS_CUR_CTRL_1                 0x010a
+#define RT5659_BIAS_CUR_CTRL_2                 0x010b
+#define RT5659_BIAS_CUR_CTRL_3                 0x010c
+#define RT5659_BIAS_CUR_CTRL_4                 0x010d
+#define RT5659_BIAS_CUR_CTRL_5                 0x010e
+#define RT5659_BIAS_CUR_CTRL_6                 0x010f
+#define RT5659_BIAS_CUR_CTRL_7                 0x0110
+#define RT5659_BIAS_CUR_CTRL_8                 0x0111
+#define RT5659_BIAS_CUR_CTRL_9                 0x0112
+#define RT5659_BIAS_CUR_CTRL_10                        0x0113
+#define RT5659_MEMORY_TEST                     0x0116
+#define RT5659_VREF_REC_OP_FB_CAP_CTRL         0x0117
+#define RT5659_CLASSD_0                                0x011a
+#define RT5659_CLASSD_1                                0x011b
+#define RT5659_CLASSD_2                                0x011c
+#define RT5659_CLASSD_3                                0x011d
+#define RT5659_CLASSD_4                                0x011e
+#define RT5659_CLASSD_5                                0x011f
+#define RT5659_CLASSD_6                                0x0120
+#define RT5659_CLASSD_7                                0x0121
+#define RT5659_CLASSD_8                                0x0122
+#define RT5659_CLASSD_9                                0x0123
+#define RT5659_CLASSD_10                       0x0124
+#define RT5659_CHARGE_PUMP_1                   0x0125
+#define RT5659_CHARGE_PUMP_2                   0x0126
+#define RT5659_DIG_IN_CTRL_1                   0x0132
+#define RT5659_DIG_IN_CTRL_2                   0x0133
+#define RT5659_PAD_DRIVING_CTRL                        0x0137
+#define RT5659_SOFT_RAMP_DEPOP                 0x0138
+#define RT5659_PLL                             0x0139
+#define RT5659_CHOP_DAC                                0x013a
+#define RT5659_CHOP_ADC                                0x013b
+#define RT5659_CALIB_ADC_CTRL                  0x013c
+#define RT5659_SOFT_RAMP_DEPOP_DAC_CLK_CTRL    0x013e
+#define RT5659_VOL_TEST                                0x013f
+#define RT5659_TEST_MODE_CTRL_1                        0x0145
+#define RT5659_TEST_MODE_CTRL_2                        0x0146
+#define RT5659_TEST_MODE_CTRL_3                        0x0147
+#define RT5659_TEST_MODE_CTRL_4                        0x0148
+#define RT5659_BASSBACK_CTRL                   0x0150
+#define RT5659_MP3_PLUS_CTRL_1                 0x0151
+#define RT5659_MP3_PLUS_CTRL_2                 0x0152
+#define RT5659_MP3_HPF_A1                      0x0153
+#define RT5659_MP3_HPF_A2                      0x0154
+#define RT5659_MP3_HPF_H0                      0x0155
+#define RT5659_MP3_LPF_H0                      0x0156
+#define RT5659_3D_SPK_CTRL                     0x0157
+#define RT5659_3D_SPK_COEF_1                   0x0158
+#define RT5659_3D_SPK_COEF_2                   0x0159
+#define RT5659_3D_SPK_COEF_3                   0x015a
+#define RT5659_3D_SPK_COEF_4                   0x015b
+#define RT5659_3D_SPK_COEF_5                   0x015c
+#define RT5659_3D_SPK_COEF_6                   0x015d
+#define RT5659_3D_SPK_COEF_7                   0x015e
+#define RT5659_STO_NG2_CTRL_1                  0x0160
+#define RT5659_STO_NG2_CTRL_2                  0x0161
+#define RT5659_STO_NG2_CTRL_3                  0x0162
+#define RT5659_STO_NG2_CTRL_4                  0x0163
+#define RT5659_STO_NG2_CTRL_5                  0x0164
+#define RT5659_STO_NG2_CTRL_6                  0x0165
+#define RT5659_STO_NG2_CTRL_7                  0x0166
+#define RT5659_STO_NG2_CTRL_8                  0x0167
+#define RT5659_MONO_NG2_CTRL_1                 0x0170
+#define RT5659_MONO_NG2_CTRL_2                 0x0171
+#define RT5659_MONO_NG2_CTRL_3                 0x0172
+#define RT5659_MONO_NG2_CTRL_4                 0x0173
+#define RT5659_MONO_NG2_CTRL_5                 0x0174
+#define RT5659_MONO_NG2_CTRL_6                 0x0175
+#define RT5659_MID_HP_AMP_DET                  0x0190
+#define RT5659_LOW_HP_AMP_DET                  0x0191
+#define RT5659_LDO_CTRL                                0x0192
+#define RT5659_HP_DECROSS_CTRL_1               0x01b0
+#define RT5659_HP_DECROSS_CTRL_2               0x01b1
+#define RT5659_HP_DECROSS_CTRL_3               0x01b2
+#define RT5659_HP_DECROSS_CTRL_4               0x01b3
+#define RT5659_HP_IMP_SENS_CTRL_1              0x01c0
+#define RT5659_HP_IMP_SENS_CTRL_2              0x01c1
+#define RT5659_HP_IMP_SENS_CTRL_3              0x01c2
+#define RT5659_HP_IMP_SENS_CTRL_4              0x01c3
+#define RT5659_HP_IMP_SENS_MAP_1               0x01c7
+#define RT5659_HP_IMP_SENS_MAP_2               0x01c8
+#define RT5659_HP_IMP_SENS_MAP_3               0x01c9
+#define RT5659_HP_IMP_SENS_MAP_4               0x01ca
+#define RT5659_HP_IMP_SENS_MAP_5               0x01cb
+#define RT5659_HP_IMP_SENS_MAP_6               0x01cc
+#define RT5659_HP_IMP_SENS_MAP_7               0x01cd
+#define RT5659_HP_IMP_SENS_MAP_8               0x01ce
+#define RT5659_HP_LOGIC_CTRL_1                 0x01da
+#define RT5659_HP_LOGIC_CTRL_2                 0x01db
+#define RT5659_HP_CALIB_CTRL_1                 0x01de
+#define RT5659_HP_CALIB_CTRL_2                 0x01df
+#define RT5659_HP_CALIB_CTRL_3                 0x01e0
+#define RT5659_HP_CALIB_CTRL_4                 0x01e1
+#define RT5659_HP_CALIB_CTRL_5                 0x01e2
+#define RT5659_HP_CALIB_CTRL_6                 0x01e3
+#define RT5659_HP_CALIB_CTRL_7                 0x01e4
+#define RT5659_HP_CALIB_CTRL_9                 0x01e6
+#define RT5659_HP_CALIB_CTRL_10                        0x01e7
+#define RT5659_HP_CALIB_CTRL_11                        0x01e8
+#define RT5659_HP_CALIB_STA_1                  0x01ea
+#define RT5659_HP_CALIB_STA_2                  0x01eb
+#define RT5659_HP_CALIB_STA_3                  0x01ec
+#define RT5659_HP_CALIB_STA_4                  0x01ed
+#define RT5659_HP_CALIB_STA_5                  0x01ee
+#define RT5659_HP_CALIB_STA_6                  0x01ef
+#define RT5659_HP_CALIB_STA_7                  0x01f0
+#define RT5659_HP_CALIB_STA_8                  0x01f1
+#define RT5659_HP_CALIB_STA_9                  0x01f2
+#define RT5659_MONO_AMP_CALIB_CTRL_1           0x01f6
+#define RT5659_MONO_AMP_CALIB_CTRL_2           0x01f7
+#define RT5659_MONO_AMP_CALIB_CTRL_3           0x01f8
+#define RT5659_MONO_AMP_CALIB_CTRL_4           0x01f9
+#define RT5659_MONO_AMP_CALIB_CTRL_5           0x01fa
+#define RT5659_MONO_AMP_CALIB_STA_1            0x01fb
+#define RT5659_MONO_AMP_CALIB_STA_2            0x01fc
+#define RT5659_MONO_AMP_CALIB_STA_3            0x01fd
+#define RT5659_MONO_AMP_CALIB_STA_4            0x01fe
+#define RT5659_SPK_PWR_LMT_CTRL_1              0x0200
+#define RT5659_SPK_PWR_LMT_CTRL_2              0x0201
+#define RT5659_SPK_PWR_LMT_CTRL_3              0x0202
+#define RT5659_SPK_PWR_LMT_STA_1               0x0203
+#define RT5659_SPK_PWR_LMT_STA_2               0x0204
+#define RT5659_SPK_PWR_LMT_STA_3               0x0205
+#define RT5659_SPK_PWR_LMT_STA_4               0x0206
+#define RT5659_SPK_PWR_LMT_STA_5               0x0207
+#define RT5659_SPK_PWR_LMT_STA_6               0x0208
+#define RT5659_FLEX_SPK_BST_CTRL_1             0x0256
+#define RT5659_FLEX_SPK_BST_CTRL_2             0x0257
+#define RT5659_FLEX_SPK_BST_CTRL_3             0x0258
+#define RT5659_FLEX_SPK_BST_CTRL_4             0x0259
+#define RT5659_SPK_EX_LMT_CTRL_1               0x025a
+#define RT5659_SPK_EX_LMT_CTRL_2               0x025b
+#define RT5659_SPK_EX_LMT_CTRL_3               0x025c
+#define RT5659_SPK_EX_LMT_CTRL_4               0x025d
+#define RT5659_SPK_EX_LMT_CTRL_5               0x025e
+#define RT5659_SPK_EX_LMT_CTRL_6               0x025f
+#define RT5659_SPK_EX_LMT_CTRL_7               0x0260
+#define RT5659_ADJ_HPF_CTRL_1                  0x0261
+#define RT5659_ADJ_HPF_CTRL_2                  0x0262
+#define RT5659_SPK_DC_CAILB_CTRL_1             0x0265
+#define RT5659_SPK_DC_CAILB_CTRL_2             0x0266
+#define RT5659_SPK_DC_CAILB_CTRL_3             0x0267
+#define RT5659_SPK_DC_CAILB_CTRL_4             0x0268
+#define RT5659_SPK_DC_CAILB_CTRL_5             0x0269
+#define RT5659_SPK_DC_CAILB_STA_1              0x026a
+#define RT5659_SPK_DC_CAILB_STA_2              0x026b
+#define RT5659_SPK_DC_CAILB_STA_3              0x026c
+#define RT5659_SPK_DC_CAILB_STA_4              0x026d
+#define RT5659_SPK_DC_CAILB_STA_5              0x026e
+#define RT5659_SPK_DC_CAILB_STA_6              0x026f
+#define RT5659_SPK_DC_CAILB_STA_7              0x0270
+#define RT5659_SPK_DC_CAILB_STA_8              0x0271
+#define RT5659_SPK_DC_CAILB_STA_9              0x0272
+#define RT5659_SPK_DC_CAILB_STA_10             0x0273
+#define RT5659_SPK_VDD_STA_1                   0x0280
+#define RT5659_SPK_VDD_STA_2                   0x0281
+#define RT5659_SPK_DC_DET_CTRL_1               0x0282
+#define RT5659_SPK_DC_DET_CTRL_2               0x0283
+#define RT5659_SPK_DC_DET_CTRL_3               0x0284
+#define RT5659_PURE_DC_DET_CTRL_1              0x0290
+#define RT5659_PURE_DC_DET_CTRL_2              0x0291
+#define RT5659_DUMMY_4                         0x02fa
+#define RT5659_DUMMY_5                         0x02fb
+#define RT5659_DUMMY_6                         0x02fc
+#define RT5659_DRC1_CTRL_1                     0x0300
+#define RT5659_DRC1_CTRL_2                     0x0301
+#define RT5659_DRC1_CTRL_3                     0x0302
+#define RT5659_DRC1_CTRL_4                     0x0303
+#define RT5659_DRC1_CTRL_5                     0x0304
+#define RT5659_DRC1_CTRL_6                     0x0305
+#define RT5659_DRC1_HARD_LMT_CTRL_1            0x0306
+#define RT5659_DRC1_HARD_LMT_CTRL_2            0x0307
+#define RT5659_DRC2_CTRL_1                     0x0308
+#define RT5659_DRC2_CTRL_2                     0x0309
+#define RT5659_DRC2_CTRL_3                     0x030a
+#define RT5659_DRC2_CTRL_4                     0x030b
+#define RT5659_DRC2_CTRL_5                     0x030c
+#define RT5659_DRC2_CTRL_6                     0x030d
+#define RT5659_DRC2_HARD_LMT_CTRL_1            0x030e
+#define RT5659_DRC2_HARD_LMT_CTRL_2            0x030f
+#define RT5659_DRC1_PRIV_1                     0x0310
+#define RT5659_DRC1_PRIV_2                     0x0311
+#define RT5659_DRC1_PRIV_3                     0x0312
+#define RT5659_DRC1_PRIV_4                     0x0313
+#define RT5659_DRC1_PRIV_5                     0x0314
+#define RT5659_DRC1_PRIV_6                     0x0315
+#define RT5659_DRC1_PRIV_7                     0x0316
+#define RT5659_DRC2_PRIV_1                     0x0317
+#define RT5659_DRC2_PRIV_2                     0x0318
+#define RT5659_DRC2_PRIV_3                     0x0319
+#define RT5659_DRC2_PRIV_4                     0x031a
+#define RT5659_DRC2_PRIV_5                     0x031b
+#define RT5659_DRC2_PRIV_6                     0x031c
+#define RT5659_DRC2_PRIV_7                     0x031d
+#define RT5659_MULTI_DRC_CTRL                  0x0320
+#define RT5659_CROSS_OVER_1                    0x0321
+#define RT5659_CROSS_OVER_2                    0x0322
+#define RT5659_CROSS_OVER_3                    0x0323
+#define RT5659_CROSS_OVER_4                    0x0324
+#define RT5659_CROSS_OVER_5                    0x0325
+#define RT5659_CROSS_OVER_6                    0x0326
+#define RT5659_CROSS_OVER_7                    0x0327
+#define RT5659_CROSS_OVER_8                    0x0328
+#define RT5659_CROSS_OVER_9                    0x0329
+#define RT5659_CROSS_OVER_10                   0x032a
+#define RT5659_ALC_PGA_CTRL_1                  0x0330
+#define RT5659_ALC_PGA_CTRL_2                  0x0331
+#define RT5659_ALC_PGA_CTRL_3                  0x0332
+#define RT5659_ALC_PGA_CTRL_4                  0x0333
+#define RT5659_ALC_PGA_CTRL_5                  0x0334
+#define RT5659_ALC_PGA_CTRL_6                  0x0335
+#define RT5659_ALC_PGA_CTRL_7                  0x0336
+#define RT5659_ALC_PGA_CTRL_8                  0x0337
+#define RT5659_ALC_PGA_STA_1                   0x0338
+#define RT5659_ALC_PGA_STA_2                   0x0339
+#define RT5659_ALC_PGA_STA_3                   0x033a
+#define RT5659_DAC_L_EQ_PRE_VOL                        0x0340
+#define RT5659_DAC_R_EQ_PRE_VOL                        0x0341
+#define RT5659_DAC_L_EQ_POST_VOL               0x0342
+#define RT5659_DAC_R_EQ_POST_VOL               0x0343
+#define RT5659_DAC_L_EQ_LPF1_A1                        0x0344
+#define RT5659_DAC_L_EQ_LPF1_H0                        0x0345
+#define RT5659_DAC_R_EQ_LPF1_A1                        0x0346
+#define RT5659_DAC_R_EQ_LPF1_H0                        0x0347
+#define RT5659_DAC_L_EQ_BPF2_A1                        0x0348
+#define RT5659_DAC_L_EQ_BPF2_A2                        0x0349
+#define RT5659_DAC_L_EQ_BPF2_H0                        0x034a
+#define RT5659_DAC_R_EQ_BPF2_A1                        0x034b
+#define RT5659_DAC_R_EQ_BPF2_A2                        0x034c
+#define RT5659_DAC_R_EQ_BPF2_H0                        0x034d
+#define RT5659_DAC_L_EQ_BPF3_A1                        0x034e
+#define RT5659_DAC_L_EQ_BPF3_A2                        0x034f
+#define RT5659_DAC_L_EQ_BPF3_H0                        0x0350
+#define RT5659_DAC_R_EQ_BPF3_A1                        0x0351
+#define RT5659_DAC_R_EQ_BPF3_A2                        0x0352
+#define RT5659_DAC_R_EQ_BPF3_H0                        0x0353
+#define RT5659_DAC_L_EQ_BPF4_A1                        0x0354
+#define RT5659_DAC_L_EQ_BPF4_A2                        0x0355
+#define RT5659_DAC_L_EQ_BPF4_H0                        0x0356
+#define RT5659_DAC_R_EQ_BPF4_A1                        0x0357
+#define RT5659_DAC_R_EQ_BPF4_A2                        0x0358
+#define RT5659_DAC_R_EQ_BPF4_H0                        0x0359
+#define RT5659_DAC_L_EQ_HPF1_A1                        0x035a
+#define RT5659_DAC_L_EQ_HPF1_H0                        0x035b
+#define RT5659_DAC_R_EQ_HPF1_A1                        0x035c
+#define RT5659_DAC_R_EQ_HPF1_H0                        0x035d
+#define RT5659_DAC_L_EQ_HPF2_A1                        0x035e
+#define RT5659_DAC_L_EQ_HPF2_A2                        0x035f
+#define RT5659_DAC_L_EQ_HPF2_H0                        0x0360
+#define RT5659_DAC_R_EQ_HPF2_A1                        0x0361
+#define RT5659_DAC_R_EQ_HPF2_A2                        0x0362
+#define RT5659_DAC_R_EQ_HPF2_H0                        0x0363
+#define RT5659_DAC_L_BI_EQ_BPF1_H0_1           0x0364
+#define RT5659_DAC_L_BI_EQ_BPF1_H0_2           0x0365
+#define RT5659_DAC_L_BI_EQ_BPF1_B1_1           0x0366
+#define RT5659_DAC_L_BI_EQ_BPF1_B1_2           0x0367
+#define RT5659_DAC_L_BI_EQ_BPF1_B2_1           0x0368
+#define RT5659_DAC_L_BI_EQ_BPF1_B2_2           0x0369
+#define RT5659_DAC_L_BI_EQ_BPF1_A1_1           0x036a
+#define RT5659_DAC_L_BI_EQ_BPF1_A1_2           0x036b
+#define RT5659_DAC_L_BI_EQ_BPF1_A2_1           0x036c
+#define RT5659_DAC_L_BI_EQ_BPF1_A2_2           0x036d
+#define RT5659_DAC_R_BI_EQ_BPF1_H0_1           0x036e
+#define RT5659_DAC_R_BI_EQ_BPF1_H0_2           0x036f
+#define RT5659_DAC_R_BI_EQ_BPF1_B1_1           0x0370
+#define RT5659_DAC_R_BI_EQ_BPF1_B1_2           0x0371
+#define RT5659_DAC_R_BI_EQ_BPF1_B2_1           0x0372
+#define RT5659_DAC_R_BI_EQ_BPF1_B2_2           0x0373
+#define RT5659_DAC_R_BI_EQ_BPF1_A1_1           0x0374
+#define RT5659_DAC_R_BI_EQ_BPF1_A1_2           0x0375
+#define RT5659_DAC_R_BI_EQ_BPF1_A2_1           0x0376
+#define RT5659_DAC_R_BI_EQ_BPF1_A2_2           0x0377
+#define RT5659_ADC_L_EQ_LPF1_A1                        0x03d0
+#define RT5659_ADC_R_EQ_LPF1_A1                        0x03d1
+#define RT5659_ADC_L_EQ_LPF1_H0                        0x03d2
+#define RT5659_ADC_R_EQ_LPF1_H0                        0x03d3
+#define RT5659_ADC_L_EQ_BPF1_A1                        0x03d4
+#define RT5659_ADC_R_EQ_BPF1_A1                        0x03d5
+#define RT5659_ADC_L_EQ_BPF1_A2                        0x03d6
+#define RT5659_ADC_R_EQ_BPF1_A2                        0x03d7
+#define RT5659_ADC_L_EQ_BPF1_H0                        0x03d8
+#define RT5659_ADC_R_EQ_BPF1_H0                        0x03d9
+#define RT5659_ADC_L_EQ_BPF2_A1                        0x03da
+#define RT5659_ADC_R_EQ_BPF2_A1                        0x03db
+#define RT5659_ADC_L_EQ_BPF2_A2                        0x03dc
+#define RT5659_ADC_R_EQ_BPF2_A2                        0x03dd
+#define RT5659_ADC_L_EQ_BPF2_H0                        0x03de
+#define RT5659_ADC_R_EQ_BPF2_H0                        0x03df
+#define RT5659_ADC_L_EQ_BPF3_A1                        0x03e0
+#define RT5659_ADC_R_EQ_BPF3_A1                        0x03e1
+#define RT5659_ADC_L_EQ_BPF3_A2                        0x03e2
+#define RT5659_ADC_R_EQ_BPF3_A2                        0x03e3
+#define RT5659_ADC_L_EQ_BPF3_H0                        0x03e4
+#define RT5659_ADC_R_EQ_BPF3_H0                        0x03e5
+#define RT5659_ADC_L_EQ_BPF4_A1                        0x03e6
+#define RT5659_ADC_R_EQ_BPF4_A1                        0x03e7
+#define RT5659_ADC_L_EQ_BPF4_A2                        0x03e8
+#define RT5659_ADC_R_EQ_BPF4_A2                        0x03e9
+#define RT5659_ADC_L_EQ_BPF4_H0                        0x03ea
+#define RT5659_ADC_R_EQ_BPF4_H0                        0x03eb
+#define RT5659_ADC_L_EQ_HPF1_A1                        0x03ec
+#define RT5659_ADC_R_EQ_HPF1_A1                        0x03ed
+#define RT5659_ADC_L_EQ_HPF1_H0                        0x03ee
+#define RT5659_ADC_R_EQ_HPF1_H0                        0x03ef
+#define RT5659_ADC_L_EQ_PRE_VOL                        0x03f0
+#define RT5659_ADC_R_EQ_PRE_VOL                        0x03f1
+#define RT5659_ADC_L_EQ_POST_VOL               0x03f2
+#define RT5659_ADC_R_EQ_POST_VOL               0x03f3
+
+
+
+/* global definition */
+#define RT5659_L_MUTE                          (0x1 << 15)
+#define RT5659_L_MUTE_SFT                      15
+#define RT5659_VOL_L_MUTE                      (0x1 << 14)
+#define RT5659_VOL_L_SFT                       14
+#define RT5659_R_MUTE                          (0x1 << 7)
+#define RT5659_R_MUTE_SFT                      7
+#define RT5659_VOL_R_MUTE                      (0x1 << 6)
+#define RT5659_VOL_R_SFT                       6
+#define RT5659_L_VOL_MASK                      (0x3f << 8)
+#define RT5659_L_VOL_SFT                       8
+#define RT5659_R_VOL_MASK                      (0x3f)
+#define RT5659_R_VOL_SFT                       0
+
+/*Headphone Amp L/R Analog Gain and Digital NG2 Gain Control (0x0005 0x0006)*/
+#define RT5659_G_HP                            (0x1f << 8)
+#define RT5659_G_HP_SFT                                8
+#define RT5659_G_STO_DA_DMIX                   (0x1f)
+#define RT5659_G_STO_DA_SFT                    0
+
+/* IN1/IN2 Control (0x000c) */
+#define RT5659_IN1_DF_MASK                     (0x1 << 15)
+#define RT5659_IN1_DF                          15
+#define RT5659_BST1_MASK                       (0x7f << 8)
+#define RT5659_BST1_SFT                                8
+#define RT5659_BST2_MASK                       (0x7f)
+#define RT5659_BST2_SFT                                0
+
+/* IN3/IN4 Control (0x000d) */
+#define RT5659_IN3_DF_MASK                     (0x1 << 15)
+#define RT5659_IN3_DF                          15
+#define RT5659_BST3_MASK                       (0x7f << 8)
+#define RT5659_BST3_SFT                                8
+#define RT5659_IN4_DF_MASK                     (0x1 << 7)
+#define RT5659_IN4_DF                          7
+#define RT5659_BST4_MASK                       (0x7f)
+#define RT5659_BST4_SFT                                0
+
+/* INL and INR Volume Control (0x000f) */
+#define RT5659_INL_VOL_MASK                    (0x1f << 8)
+#define RT5659_INL_VOL_SFT                     8
+#define RT5659_INR_VOL_MASK                    (0x1f)
+#define RT5659_INR_VOL_SFT                     0
+
+/* Embeeded Jack and Type Detection Control 1 (0x0010) */
+#define RT5659_EMB_JD_EN                       (0x1 << 15)
+#define RT5659_EMB_JD_EN_SFT                   15
+#define RT5659_JD_MODE                         (0x1 << 13)
+#define RT5659_JD_MODE_SFT                     13
+#define RT5659_EXT_JD_EN                       (0x1 << 11)
+#define RT5659_EXT_JD_EN_SFT                   11
+#define RT5659_EXT_JD_DIG                      (0x1 << 9)
+
+/* Embeeded Jack and Type Detection Control 2 (0x0011) */
+#define RT5659_EXT_JD_SRC                      (0x7 << 4)
+#define RT5659_EXT_JD_SRC_SFT                  4
+#define RT5659_EXT_JD_SRC_GPIO_JD1             (0x0 << 4)
+#define RT5659_EXT_JD_SRC_GPIO_JD2             (0x1 << 4)
+#define RT5659_EXT_JD_SRC_JD1_1                        (0x2 << 4)
+#define RT5659_EXT_JD_SRC_JD1_2                        (0x3 << 4)
+#define RT5659_EXT_JD_SRC_JD2                  (0x4 << 4)
+#define RT5659_EXT_JD_SRC_JD3                  (0x5 << 4)
+#define RT5659_EXT_JD_SRC_MANUAL               (0x6 << 4)
+
+/* Slience Detection Control (0x0015) */
+#define RT5659_SIL_DET_MASK                    (0x1 << 15)
+#define RT5659_SIL_DET_DIS                     (0x0 << 15)
+#define RT5659_SIL_DET_EN                      (0x1 << 15)
+
+/* Sidetone Control (0x0018) */
+#define RT5659_ST_SEL_MASK                     (0x7 << 9)
+#define RT5659_ST_SEL_SFT                      9
+#define RT5659_ST_EN                           (0x1 << 6)
+#define RT5659_ST_EN_SFT                       6
+
+/* DAC1 Digital Volume (0x0019) */
+#define RT5659_DAC_L1_VOL_MASK                 (0xff << 8)
+#define RT5659_DAC_L1_VOL_SFT                  8
+#define RT5659_DAC_R1_VOL_MASK                 (0xff)
+#define RT5659_DAC_R1_VOL_SFT                  0
+
+/* DAC2 Digital Volume (0x001a) */
+#define RT5659_DAC_L2_VOL_MASK                 (0xff << 8)
+#define RT5659_DAC_L2_VOL_SFT                  8
+#define RT5659_DAC_R2_VOL_MASK                 (0xff)
+#define RT5659_DAC_R2_VOL_SFT                  0
+
+/* DAC2 Control (0x001b) */
+#define RT5659_M_DAC2_L_VOL                    (0x1 << 13)
+#define RT5659_M_DAC2_L_VOL_SFT                        13
+#define RT5659_M_DAC2_R_VOL                    (0x1 << 12)
+#define RT5659_M_DAC2_R_VOL_SFT                        12
+#define RT5659_DAC_L2_SEL_MASK                 (0x7 << 4)
+#define RT5659_DAC_L2_SEL_SFT                  4
+#define RT5659_DAC_R2_SEL_MASK                 (0x7 << 0)
+#define RT5659_DAC_R2_SEL_SFT                  0
+
+/* ADC Digital Volume Control (0x001c) */
+#define RT5659_ADC_L_VOL_MASK                  (0x7f << 8)
+#define RT5659_ADC_L_VOL_SFT                   8
+#define RT5659_ADC_R_VOL_MASK                  (0x7f)
+#define RT5659_ADC_R_VOL_SFT                   0
+
+/* Mono ADC Digital Volume Control (0x001d) */
+#define RT5659_MONO_ADC_L_VOL_MASK             (0x7f << 8)
+#define RT5659_MONO_ADC_L_VOL_SFT              8
+#define RT5659_MONO_ADC_R_VOL_MASK             (0x7f)
+#define RT5659_MONO_ADC_R_VOL_SFT              0
+
+/* Stereo1 ADC Boost Gain Control (0x001f) */
+#define RT5659_STO1_ADC_L_BST_MASK             (0x3 << 14)
+#define RT5659_STO1_ADC_L_BST_SFT              14
+#define RT5659_STO1_ADC_R_BST_MASK             (0x3 << 12)
+#define RT5659_STO1_ADC_R_BST_SFT              12
+
+/* Mono ADC Boost Gain Control (0x0020) */
+#define RT5659_MONO_ADC_L_BST_MASK             (0x3 << 14)
+#define RT5659_MONO_ADC_L_BST_SFT              14
+#define RT5659_MONO_ADC_R_BST_MASK             (0x3 << 12)
+#define RT5659_MONO_ADC_R_BST_SFT              12
+
+/* Stereo1 ADC Boost Gain Control (0x001f) */
+#define RT5659_STO2_ADC_L_BST_MASK             (0x3 << 14)
+#define RT5659_STO2_ADC_L_BST_SFT              14
+#define RT5659_STO2_ADC_R_BST_MASK             (0x3 << 12)
+#define RT5659_STO2_ADC_R_BST_SFT              12
+
+/* Stereo ADC Mixer Control (0x0026) */
+#define RT5659_M_STO1_ADC_L1                   (0x1 << 15)
+#define RT5659_M_STO1_ADC_L1_SFT               15
+#define RT5659_M_STO1_ADC_L2                   (0x1 << 14)
+#define RT5659_M_STO1_ADC_L2_SFT               14
+#define RT5659_STO1_ADC1_SRC_MASK              (0x1 << 13)
+#define RT5659_STO1_ADC1_SRC_SFT               13
+#define RT5659_STO1_ADC1_SRC_ADC               (0x1 << 13)
+#define RT5659_STO1_ADC1_SRC_DACMIX            (0x0 << 13)
+#define RT5659_STO1_ADC_SRC_MASK               (0x1 << 12)
+#define RT5659_STO1_ADC_SRC_SFT                        12
+#define RT5659_STO1_ADC_SRC_ADC1               (0x1 << 12)
+#define RT5659_STO1_ADC_SRC_ADC2               (0x0 << 12)
+#define RT5659_STO1_ADC2_SRC_MASK              (0x1 << 11)
+#define RT5659_STO1_ADC2_SRC_SFT               11
+#define RT5659_STO1_DMIC_SRC_MASK              (0x1 << 8)
+#define RT5659_STO1_DMIC_SRC_SFT               8
+#define RT5659_STO1_DMIC_SRC_DMIC2             (0x1 << 8)
+#define RT5659_STO1_DMIC_SRC_DMIC1             (0x0 << 8)
+#define RT5659_M_STO1_ADC_R1                   (0x1 << 6)
+#define RT5659_M_STO1_ADC_R1_SFT               6
+#define RT5659_M_STO1_ADC_R2                   (0x1 << 5)
+#define RT5659_M_STO1_ADC_R2_SFT               5
+
+/* Mono1 ADC Mixer control (0x0027) */
+#define RT5659_M_MONO_ADC_L1                   (0x1 << 15)
+#define RT5659_M_MONO_ADC_L1_SFT               15
+#define RT5659_M_MONO_ADC_L2                   (0x1 << 14)
+#define RT5659_M_MONO_ADC_L2_SFT               14
+#define RT5659_MONO_ADC_L2_SRC_MASK            (0x1 << 12)
+#define RT5659_MONO_ADC_L2_SRC_SFT             12
+#define RT5659_MONO_ADC_L1_SRC_MASK            (0x1 << 11)
+#define RT5659_MONO_ADC_L1_SRC_SFT             11
+#define RT5659_MONO_ADC_L_SRC_MASK             (0x3 << 9)
+#define RT5659_MONO_ADC_L_SRC_SFT              9
+#define RT5659_MONO_DMIC_L_SRC_MASK            (0x1 << 8)
+#define RT5659_MONO_DMIC_L_SRC_SFT             8
+#define RT5659_M_MONO_ADC_R1                   (0x1 << 7)
+#define RT5659_M_MONO_ADC_R1_SFT               7
+#define RT5659_M_MONO_ADC_R2                   (0x1 << 6)
+#define RT5659_M_MONO_ADC_R2_SFT               6
+#define RT5659_STO2_ADC_SRC_MASK               (0x1 << 5)
+#define RT5659_STO2_ADC_SRC_SFT                        5
+#define RT5659_MONO_ADC_R2_SRC_MASK            (0x1 << 4)
+#define RT5659_MONO_ADC_R2_SRC_SFT             4
+#define RT5659_MONO_ADC_R1_SRC_MASK            (0x1 << 3)
+#define RT5659_MONO_ADC_R1_SRC_SFT             3
+#define RT5659_MONO_ADC_R_SRC_MASK             (0x3 << 1)
+#define RT5659_MONO_ADC_R_SRC_SFT              1
+#define RT5659_MONO_DMIC_R_SRC_MASK            0x1
+#define RT5659_MONO_DMIC_R_SRC_SFT             0
+
+/* ADC Mixer to DAC Mixer Control (0x0029) */
+#define RT5659_M_ADCMIX_L                      (0x1 << 15)
+#define RT5659_M_ADCMIX_L_SFT                  15
+#define RT5659_M_DAC1_L                                (0x1 << 14)
+#define RT5659_M_DAC1_L_SFT                    14
+#define RT5659_DAC1_R_SEL_MASK                 (0x3 << 10)
+#define RT5659_DAC1_R_SEL_SFT                  10
+#define RT5659_DAC1_R_SEL_IF1                  (0x0 << 10)
+#define RT5659_DAC1_R_SEL_IF2                  (0x1 << 10)
+#define RT5659_DAC1_R_SEL_IF3                  (0x2 << 10)
+#define RT5659_DAC1_L_SEL_MASK                 (0x3 << 8)
+#define RT5659_DAC1_L_SEL_SFT                  8
+#define RT5659_DAC1_L_SEL_IF1                  (0x0 << 8)
+#define RT5659_DAC1_L_SEL_IF2                  (0x1 << 8)
+#define RT5659_DAC1_L_SEL_IF3                  (0x2 << 8)
+#define RT5659_M_ADCMIX_R                      (0x1 << 7)
+#define RT5659_M_ADCMIX_R_SFT                  7
+#define RT5659_M_DAC1_R                                (0x1 << 6)
+#define RT5659_M_DAC1_R_SFT                    6
+
+/* Stereo DAC Mixer Control (0x002a) */
+#define RT5659_M_DAC_L1_STO_L                  (0x1 << 15)
+#define RT5659_M_DAC_L1_STO_L_SFT              15
+#define RT5659_G_DAC_L1_STO_L_MASK             (0x1 << 14)
+#define RT5659_G_DAC_L1_STO_L_SFT              14
+#define RT5659_M_DAC_R1_STO_L                  (0x1 << 13)
+#define RT5659_M_DAC_R1_STO_L_SFT              13
+#define RT5659_G_DAC_R1_STO_L_MASK             (0x1 << 12)
+#define RT5659_G_DAC_R1_STO_L_SFT              12
+#define RT5659_M_DAC_L2_STO_L                  (0x1 << 11)
+#define RT5659_M_DAC_L2_STO_L_SFT              11
+#define RT5659_G_DAC_L2_STO_L_MASK             (0x1 << 10)
+#define RT5659_G_DAC_L2_STO_L_SFT              10
+#define RT5659_M_DAC_R2_STO_L                  (0x1 << 9)
+#define RT5659_M_DAC_R2_STO_L_SFT              9
+#define RT5659_G_DAC_R2_STO_L_MASK             (0x1 << 8)
+#define RT5659_G_DAC_R2_STO_L_SFT              8
+#define RT5659_M_DAC_L1_STO_R                  (0x1 << 7)
+#define RT5659_M_DAC_L1_STO_R_SFT              7
+#define RT5659_G_DAC_L1_STO_R_MASK             (0x1 << 6)
+#define RT5659_G_DAC_L1_STO_R_SFT              6
+#define RT5659_M_DAC_R1_STO_R                  (0x1 << 5)
+#define RT5659_M_DAC_R1_STO_R_SFT              5
+#define RT5659_G_DAC_R1_STO_R_MASK             (0x1 << 4)
+#define RT5659_G_DAC_R1_STO_R_SFT              4
+#define RT5659_M_DAC_L2_STO_R                  (0x1 << 3)
+#define RT5659_M_DAC_L2_STO_R_SFT              3
+#define RT5659_G_DAC_L2_STO_R_MASK             (0x1 << 2)
+#define RT5659_G_DAC_L2_STO_R_SFT              2
+#define RT5659_M_DAC_R2_STO_R                  (0x1 << 1)
+#define RT5659_M_DAC_R2_STO_R_SFT              1
+#define RT5659_G_DAC_R2_STO_R_MASK             (0x1)
+#define RT5659_G_DAC_R2_STO_R_SFT              0
+
+/* Mono DAC Mixer Control (0x002b) */
+#define RT5659_M_DAC_L1_MONO_L                 (0x1 << 15)
+#define RT5659_M_DAC_L1_MONO_L_SFT             15
+#define RT5659_G_DAC_L1_MONO_L_MASK            (0x1 << 14)
+#define RT5659_G_DAC_L1_MONO_L_SFT             14
+#define RT5659_M_DAC_R1_MONO_L                 (0x1 << 13)
+#define RT5659_M_DAC_R1_MONO_L_SFT             13
+#define RT5659_G_DAC_R1_MONO_L_MASK            (0x1 << 12)
+#define RT5659_G_DAC_R1_MONO_L_SFT             12
+#define RT5659_M_DAC_L2_MONO_L                 (0x1 << 11)
+#define RT5659_M_DAC_L2_MONO_L_SFT             11
+#define RT5659_G_DAC_L2_MONO_L_MASK            (0x1 << 10)
+#define RT5659_G_DAC_L2_MONO_L_SFT             10
+#define RT5659_M_DAC_R2_MONO_L                 (0x1 << 9)
+#define RT5659_M_DAC_R2_MONO_L_SFT             9
+#define RT5659_G_DAC_R2_MONO_L_MASK            (0x1 << 8)
+#define RT5659_G_DAC_R2_MONO_L_SFT             8
+#define RT5659_M_DAC_L1_MONO_R                 (0x1 << 7)
+#define RT5659_M_DAC_L1_MONO_R_SFT             7
+#define RT5659_G_DAC_L1_MONO_R_MASK            (0x1 << 6)
+#define RT5659_G_DAC_L1_MONO_R_SFT             6
+#define RT5659_M_DAC_R1_MONO_R                 (0x1 << 5)
+#define RT5659_M_DAC_R1_MONO_R_SFT             5
+#define RT5659_G_DAC_R1_MONO_R_MASK            (0x1 << 4)
+#define RT5659_G_DAC_R1_MONO_R_SFT             4
+#define RT5659_M_DAC_L2_MONO_R                 (0x1 << 3)
+#define RT5659_M_DAC_L2_MONO_R_SFT             3
+#define RT5659_G_DAC_L2_MONO_R_MASK            (0x1 << 2)
+#define RT5659_G_DAC_L2_MONO_R_SFT             2
+#define RT5659_M_DAC_R2_MONO_R                 (0x1 << 1)
+#define RT5659_M_DAC_R2_MONO_R_SFT             1
+#define RT5659_G_DAC_R2_MONO_R_MASK            (0x1)
+#define RT5659_G_DAC_R2_MONO_R_SFT             0
+
+/* Digital Mixer Control (0x002c) */
+#define RT5659_M_DAC_MIX_L                     (0x1 << 7)
+#define RT5659_M_DAC_MIX_L_SFT                 7
+#define RT5659_DAC_MIX_L_MASK                  (0x1 << 6)
+#define RT5659_DAC_MIX_L_SFT                   6
+#define RT5659_M_DAC_MIX_R                     (0x1 << 5)
+#define RT5659_M_DAC_MIX_R_SFT                 5
+#define RT5659_DAC_MIX_R_MASK                  (0x1 << 4)
+#define RT5659_DAC_MIX_R_SFT                   4
+
+/* Analog DAC Input Source Control (0x002d) */
+#define RT5659_A_DACL1_SEL                     (0x1 << 3)
+#define RT5659_A_DACL1_SFT                     3
+#define RT5659_A_DACR1_SEL                     (0x1 << 2)
+#define RT5659_A_DACR1_SFT                     2
+#define RT5659_A_DACL2_SEL                     (0x1 << 1)
+#define RT5659_A_DACL2_SFT                     1
+#define RT5659_A_DACR2_SEL                     (0x1 << 0)
+#define RT5659_A_DACR2_SFT                     0
+
+/* Digital Interface Data Control (0x002f) */
+#define RT5659_IF2_ADC3_IN_MASK                        (0x3 << 14)
+#define RT5659_IF2_ADC3_IN_SFT                 14
+#define RT5659_IF2_ADC_IN_MASK                 (0x3 << 12)
+#define RT5659_IF2_ADC_IN_SFT                  12
+#define RT5659_IF2_DAC_SEL_MASK                        (0x3 << 10)
+#define RT5659_IF2_DAC_SEL_SFT                 10
+#define RT5659_IF2_ADC_SEL_MASK                        (0x3 << 8)
+#define RT5659_IF2_ADC_SEL_SFT                 8
+#define RT5659_IF3_DAC_SEL_MASK                        (0x3 << 6)
+#define RT5659_IF3_DAC_SEL_SFT                 6
+#define RT5659_IF3_ADC_SEL_MASK                        (0x3 << 4)
+#define RT5659_IF3_ADC_SEL_SFT                 4
+#define RT5659_IF3_ADC_IN_MASK                 (0x3 << 0)
+#define RT5659_IF3_ADC_IN_SFT                  0
+
+/* PDM Output Control (0x0031) */
+#define RT5659_PDM1_L_MASK                     (0x1 << 15)
+#define RT5659_PDM1_L_SFT                      15
+#define RT5659_M_PDM1_L                                (0x1 << 14)
+#define RT5659_M_PDM1_L_SFT                    14
+#define RT5659_PDM1_R_MASK                     (0x1 << 13)
+#define RT5659_PDM1_R_SFT                      13
+#define RT5659_M_PDM1_R                                (0x1 << 12)
+#define RT5659_M_PDM1_R_SFT                    12
+#define RT5659_PDM2_BUSY                       (0x1 << 7)
+#define RT5659_PDM1_BUSY                       (0x1 << 6)
+#define RT5659_PDM_PATTERN                     (0x1 << 5)
+#define RT5659_PDM_GAIN                                (0x1 << 4)
+#define RT5659_PDM_DIV_MASK                    (0x3)
+
+/*S/PDIF Output Control (0x0036) */
+#define RT5659_SPDIF_SEL_MASK                  (0x3 << 0)
+#define RT5659_SPDIF_SEL_SFT                   0
+
+/* REC Left Mixer Control 2 (0x003c) */
+#define RT5659_M_BST1_RM1_L                    (0x1 << 5)
+#define RT5659_M_BST1_RM1_L_SFT                        5
+#define RT5659_M_BST2_RM1_L                    (0x1 << 4)
+#define RT5659_M_BST2_RM1_L_SFT                        4
+#define RT5659_M_BST3_RM1_L                    (0x1 << 3)
+#define RT5659_M_BST3_RM1_L_SFT                        3
+#define RT5659_M_BST4_RM1_L                    (0x1 << 2)
+#define RT5659_M_BST4_RM1_L_SFT                        2
+#define RT5659_M_INL_RM1_L                     (0x1 << 1)
+#define RT5659_M_INL_RM1_L_SFT                 1
+#define RT5659_M_SPKVOLL_RM1_L                 (0x1)
+#define RT5659_M_SPKVOLL_RM1_L_SFT             0
+
+/* REC Right Mixer Control 2 (0x003e) */
+#define RT5659_M_BST1_RM1_R                    (0x1 << 5)
+#define RT5659_M_BST1_RM1_R_SFT                        5
+#define RT5659_M_BST2_RM1_R                    (0x1 << 4)
+#define RT5659_M_BST2_RM1_R_SFT                        4
+#define RT5659_M_BST3_RM1_R                    (0x1 << 3)
+#define RT5659_M_BST3_RM1_R_SFT                        3
+#define RT5659_M_BST4_RM1_R                    (0x1 << 2)
+#define RT5659_M_BST4_RM1_R_SFT                        2
+#define RT5659_M_INR_RM1_R                     (0x1 << 1)
+#define RT5659_M_INR_RM1_R_SFT                 1
+#define RT5659_M_HPOVOLR_RM1_R                 (0x1)
+#define RT5659_M_HPOVOLR_RM1_R_SFT             0
+
+/* SPK Left Mixer Control (0x0046) */
+#define RT5659_M_BST3_SM_L                     (0x1 << 4)
+#define RT5659_M_BST3_SM_L_SFT                 4
+#define RT5659_M_IN_R_SM_L                     (0x1 << 3)
+#define RT5659_M_IN_R_SM_L_SFT                 3
+#define RT5659_M_IN_L_SM_L                     (0x1 << 2)
+#define RT5659_M_IN_L_SM_L_SFT                 2
+#define RT5659_M_BST1_SM_L                     (0x1 << 1)
+#define RT5659_M_BST1_SM_L_SFT                 1
+#define RT5659_M_DAC_L2_SM_L                   (0x1)
+#define RT5659_M_DAC_L2_SM_L_SFT               0
+
+/* SPK Right Mixer Control (0x0047) */
+#define RT5659_M_BST3_SM_R                     (0x1 << 4)
+#define RT5659_M_BST3_SM_R_SFT                 4
+#define RT5659_M_IN_R_SM_R                     (0x1 << 3)
+#define RT5659_M_IN_R_SM_R_SFT                 3
+#define RT5659_M_IN_L_SM_R                     (0x1 << 2)
+#define RT5659_M_IN_L_SM_R_SFT                 2
+#define RT5659_M_BST4_SM_R                     (0x1 << 1)
+#define RT5659_M_BST4_SM_R_SFT                 1
+#define RT5659_M_DAC_R2_SM_R                   (0x1)
+#define RT5659_M_DAC_R2_SM_R_SFT               0
+
+/* SPO Amp Input and Gain Control (0x0048) */
+#define RT5659_M_DAC_L2_SPKOMIX                        (0x1 << 13)
+#define RT5659_M_DAC_L2_SPKOMIX_SFT            13
+#define RT5659_M_SPKVOLL_SPKOMIX               (0x1 << 12)
+#define RT5659_M_SPKVOLL_SPKOMIX_SFT           12
+#define RT5659_M_DAC_R2_SPKOMIX                        (0x1 << 9)
+#define RT5659_M_DAC_R2_SPKOMIX_SFT            9
+#define RT5659_M_SPKVOLR_SPKOMIX               (0x1 << 8)
+#define RT5659_M_SPKVOLR_SPKOMIX_SFT           8
+
+/* MONOMIX Input and Gain Control (0x004b) */
+#define RT5659_M_MONOVOL_MA                    (0x1 << 9)
+#define RT5659_M_MONOVOL_MA_SFT                        9
+#define RT5659_M_DAC_L2_MA                     (0x1 << 8)
+#define RT5659_M_DAC_L2_MA_SFT                 8
+#define RT5659_M_BST3_MM                       (0x1 << 4)
+#define RT5659_M_BST3_MM_SFT                   4
+#define RT5659_M_BST2_MM                       (0x1 << 3)
+#define RT5659_M_BST2_MM_SFT                   3
+#define RT5659_M_BST1_MM                       (0x1 << 2)
+#define RT5659_M_BST1_MM_SFT                   2
+#define RT5659_M_DAC_R2_MM                     (0x1 << 1)
+#define RT5659_M_DAC_R2_MM_SFT                 1
+#define RT5659_M_DAC_L2_MM                     (0x1)
+#define RT5659_M_DAC_L2_MM_SFT                 0
+
+/* Output Left Mixer Control 1 (0x004d) */
+#define RT5659_G_BST3_OM_L_MASK                        (0x7 << 12)
+#define RT5659_G_BST3_OM_L_SFT                 12
+#define RT5659_G_BST2_OM_L_MASK                        (0x7 << 9)
+#define RT5659_G_BST2_OM_L_SFT                 9
+#define RT5659_G_BST1_OM_L_MASK                        (0x7 << 6)
+#define RT5659_G_BST1_OM_L_SFT                 6
+#define RT5659_G_IN_L_OM_L_MASK                        (0x7 << 3)
+#define RT5659_G_IN_L_OM_L_SFT                 3
+#define RT5659_G_DAC_L2_OM_L_MASK              (0x7 << 0)
+#define RT5659_G_DAC_L2_OM_L_SFT               0
+
+/* Output Left Mixer Input Control (0x004e) */
+#define RT5659_M_BST3_OM_L                     (0x1 << 4)
+#define RT5659_M_BST3_OM_L_SFT                 4
+#define RT5659_M_BST2_OM_L                     (0x1 << 3)
+#define RT5659_M_BST2_OM_L_SFT                 3
+#define RT5659_M_BST1_OM_L                     (0x1 << 2)
+#define RT5659_M_BST1_OM_L_SFT                 2
+#define RT5659_M_IN_L_OM_L                     (0x1 << 1)
+#define RT5659_M_IN_L_OM_L_SFT                 1
+#define RT5659_M_DAC_L2_OM_L                   (0x1)
+#define RT5659_M_DAC_L2_OM_L_SFT               0
+
+/* Output Right Mixer Input Control (0x0050) */
+#define RT5659_M_BST4_OM_R                     (0x1 << 4)
+#define RT5659_M_BST4_OM_R_SFT                 4
+#define RT5659_M_BST3_OM_R                     (0x1 << 3)
+#define RT5659_M_BST3_OM_R_SFT                 3
+#define RT5659_M_BST2_OM_R                     (0x1 << 2)
+#define RT5659_M_BST2_OM_R_SFT                 2
+#define RT5659_M_IN_R_OM_R                     (0x1 << 1)
+#define RT5659_M_IN_R_OM_R_SFT                 1
+#define RT5659_M_DAC_R2_OM_R                   (0x1)
+#define RT5659_M_DAC_R2_OM_R_SFT               0
+
+/* LOUT Mixer Control (0x0052) */
+#define RT5659_M_DAC_L2_LM                     (0x1 << 15)
+#define RT5659_M_DAC_L2_LM_SFT                 15
+#define RT5659_M_DAC_R2_LM                     (0x1 << 14)
+#define RT5659_M_DAC_R2_LM_SFT                 14
+#define RT5659_M_OV_L_LM                       (0x1 << 13)
+#define RT5659_M_OV_L_LM_SFT                   13
+#define RT5659_M_OV_R_LM                       (0x1 << 12)
+#define RT5659_M_OV_R_LM_SFT                   12
+
+/* Power Management for Digital 1 (0x0061) */
+#define RT5659_PWR_I2S1                                (0x1 << 15)
+#define RT5659_PWR_I2S1_BIT                    15
+#define RT5659_PWR_I2S2                                (0x1 << 14)
+#define RT5659_PWR_I2S2_BIT                    14
+#define RT5659_PWR_I2S3                                (0x1 << 13)
+#define RT5659_PWR_I2S3_BIT                    13
+#define RT5659_PWR_SPDIF                       (0x1 << 12)
+#define RT5659_PWR_SPDIF_BIT                   12
+#define RT5659_PWR_DAC_L1                      (0x1 << 11)
+#define RT5659_PWR_DAC_L1_BIT                  11
+#define RT5659_PWR_DAC_R1                      (0x1 << 10)
+#define RT5659_PWR_DAC_R1_BIT                  10
+#define RT5659_PWR_DAC_L2                      (0x1 << 9)
+#define RT5659_PWR_DAC_L2_BIT                  9
+#define RT5659_PWR_DAC_R2                      (0x1 << 8)
+#define RT5659_PWR_DAC_R2_BIT                  8
+#define RT5659_PWR_LDO                         (0x1 << 7)
+#define RT5659_PWR_LDO_BIT                     7
+#define RT5659_PWR_ADC_L1                      (0x1 << 4)
+#define RT5659_PWR_ADC_L1_BIT                  4
+#define RT5659_PWR_ADC_R1                      (0x1 << 3)
+#define RT5659_PWR_ADC_R1_BIT                  3
+#define RT5659_PWR_ADC_L2                      (0x1 << 2)
+#define RT5659_PWR_ADC_L2_BIT                  4
+#define RT5659_PWR_ADC_R2                      (0x1 << 1)
+#define RT5659_PWR_ADC_R2_BIT                  1
+#define RT5659_PWR_CLS_D                       (0x1)
+#define RT5659_PWR_CLS_D_BIT                   0
+
+/* Power Management for Digital 2 (0x0062) */
+#define RT5659_PWR_ADC_S1F                     (0x1 << 15)
+#define RT5659_PWR_ADC_S1F_BIT                 15
+#define RT5659_PWR_ADC_S2F                     (0x1 << 14)
+#define RT5659_PWR_ADC_S2F_BIT                 14
+#define RT5659_PWR_ADC_MF_L                    (0x1 << 13)
+#define RT5659_PWR_ADC_MF_L_BIT                        13
+#define RT5659_PWR_ADC_MF_R                    (0x1 << 12)
+#define RT5659_PWR_ADC_MF_R_BIT                        12
+#define RT5659_PWR_DAC_S1F                     (0x1 << 10)
+#define RT5659_PWR_DAC_S1F_BIT                 10
+#define RT5659_PWR_DAC_MF_L                    (0x1 << 9)
+#define RT5659_PWR_DAC_MF_L_BIT                        9
+#define RT5659_PWR_DAC_MF_R                    (0x1 << 8)
+#define RT5659_PWR_DAC_MF_R_BIT                        8
+#define RT5659_PWR_PDM1                                (0x1 << 7)
+#define RT5659_PWR_PDM1_BIT                    7
+
+/* Power Management for Analog 1 (0x0063) */
+#define RT5659_PWR_VREF1                       (0x1 << 15)
+#define RT5659_PWR_VREF1_BIT                   15
+#define RT5659_PWR_FV1                         (0x1 << 14)
+#define RT5659_PWR_FV1_BIT                     14
+#define RT5659_PWR_VREF2                       (0x1 << 13)
+#define RT5659_PWR_VREF2_BIT                   13
+#define RT5659_PWR_FV2                         (0x1 << 12)
+#define RT5659_PWR_FV2_BIT                     12
+#define RT5659_PWR_VREF3                       (0x1 << 11)
+#define RT5659_PWR_VREF3_BIT                   11
+#define RT5659_PWR_FV3                         (0x1 << 10)
+#define RT5659_PWR_FV3_BIT                     10
+#define RT5659_PWR_MB                          (0x1 << 9)
+#define RT5659_PWR_MB_BIT                      9
+#define RT5659_PWR_LM                          (0x1 << 8)
+#define RT5659_PWR_LM_BIT                      8
+#define RT5659_PWR_BG                          (0x1 << 7)
+#define RT5659_PWR_BG_BIT                      7
+#define RT5659_PWR_MA                          (0x1 << 6)
+#define RT5659_PWR_MA_BIT                      6
+#define RT5659_PWR_HA_L                                (0x1 << 5)
+#define RT5659_PWR_HA_L_BIT                    5
+#define RT5659_PWR_HA_R                                (0x1 << 4)
+#define RT5659_PWR_HA_R_BIT                    4
+
+/* Power Management for Analog 2 (0x0064) */
+#define RT5659_PWR_BST1                                (0x1 << 15)
+#define RT5659_PWR_BST1_BIT                    15
+#define RT5659_PWR_BST2                                (0x1 << 14)
+#define RT5659_PWR_BST2_BIT                    14
+#define RT5659_PWR_BST3                                (0x1 << 13)
+#define RT5659_PWR_BST3_BIT                    13
+#define RT5659_PWR_BST4                                (0x1 << 12)
+#define RT5659_PWR_BST4_BIT                    12
+#define RT5659_PWR_MB1                         (0x1 << 11)
+#define RT5659_PWR_MB1_BIT                     11
+#define RT5659_PWR_MB2                         (0x1 << 10)
+#define RT5659_PWR_MB2_BIT                     10
+#define RT5659_PWR_MB3                         (0x1 << 9)
+#define RT5659_PWR_MB3_BIT                     9
+#define RT5659_PWR_BST1_P                      (0x1 << 6)
+#define RT5659_PWR_BST1_P_BIT                  6
+#define RT5659_PWR_BST2_P                      (0x1 << 5)
+#define RT5659_PWR_BST2_P_BIT                  5
+#define RT5659_PWR_BST3_P                      (0x1 << 4)
+#define RT5659_PWR_BST3_P_BIT                  4
+#define RT5659_PWR_BST4_P                      (0x1 << 3)
+#define RT5659_PWR_BST4_P_BIT                  3
+#define RT5659_PWR_JD1                         (0x1 << 2)
+#define RT5659_PWR_JD1_BIT                     2
+#define RT5659_PWR_JD2                         (0x1 << 1)
+#define RT5659_PWR_JD2_BIT                     1
+#define RT5659_PWR_JD3                         (0x1)
+#define RT5659_PWR_JD3_BIT                     0
+
+/* Power Management for Analog 3 (0x0065) */
+#define RT5659_PWR_BST_L                       (0x1 << 8)
+#define RT5659_PWR_BST_L_BIT                   8
+#define RT5659_PWR_BST_R                       (0x1 << 7)
+#define RT5659_PWR_BST_R_BIT                   7
+#define RT5659_PWR_PLL                         (0x1 << 6)
+#define RT5659_PWR_PLL_BIT                     6
+#define RT5659_PWR_LDO5                                (0x1 << 5)
+#define RT5659_PWR_LDO5_BIT                    5
+#define RT5659_PWR_LDO4                                (0x1 << 4)
+#define RT5659_PWR_LDO4_BIT                    4
+#define RT5659_PWR_LDO3                                (0x1 << 3)
+#define RT5659_PWR_LDO3_BIT                    3
+#define RT5659_PWR_LDO2                                (0x1 << 2)
+#define RT5659_PWR_LDO2_BIT                    2
+#define RT5659_PWR_SVD                         (0x1 << 1)
+#define RT5659_PWR_SVD_BIT                     1
+
+/* Power Management for Mixer (0x0066) */
+#define RT5659_PWR_OM_L                                (0x1 << 15)
+#define RT5659_PWR_OM_L_BIT                    15
+#define RT5659_PWR_OM_R                                (0x1 << 14)
+#define RT5659_PWR_OM_R_BIT                    14
+#define RT5659_PWR_SM_L                                (0x1 << 13)
+#define RT5659_PWR_SM_L_BIT                    13
+#define RT5659_PWR_SM_R                                (0x1 << 12)
+#define RT5659_PWR_SM_R_BIT                    12
+#define RT5659_PWR_RM1_L                       (0x1 << 11)
+#define RT5659_PWR_RM1_L_BIT                   11
+#define RT5659_PWR_RM1_R                       (0x1 << 10)
+#define RT5659_PWR_RM1_R_BIT                   10
+#define RT5659_PWR_MM                          (0x1 << 8)
+#define RT5659_PWR_MM_BIT                      8
+#define RT5659_PWR_RM2_L                       (0x1 << 3)
+#define RT5659_PWR_RM2_L_BIT                   3
+#define RT5659_PWR_RM2_R                       (0x1 << 2)
+#define RT5659_PWR_RM2_R_BIT                   2
+
+/* Power Management for Volume (0x0067) */
+#define RT5659_PWR_SV_L                                (0x1 << 15)
+#define RT5659_PWR_SV_L_BIT                    15
+#define RT5659_PWR_SV_R                                (0x1 << 14)
+#define RT5659_PWR_SV_R_BIT                    14
+#define RT5659_PWR_OV_L                                (0x1 << 13)
+#define RT5659_PWR_OV_L_BIT                    13
+#define RT5659_PWR_OV_R                                (0x1 << 12)
+#define RT5659_PWR_OV_R_BIT                    12
+#define RT5659_PWR_IN_L                                (0x1 << 9)
+#define RT5659_PWR_IN_L_BIT                    9
+#define RT5659_PWR_IN_R                                (0x1 << 8)
+#define RT5659_PWR_IN_R_BIT                    8
+#define RT5659_PWR_MV                          (0x1 << 7)
+#define RT5659_PWR_MV_BIT                      7
+#define RT5659_PWR_MIC_DET                     (0x1 << 5)
+#define RT5659_PWR_MIC_DET_BIT                 5
+
+/* I2S1/2/3 Audio Serial Data Port Control (0x0070 0x0071 0x0072) */
+#define RT5659_I2S_MS_MASK                     (0x1 << 15)
+#define RT5659_I2S_MS_SFT                      15
+#define RT5659_I2S_MS_M                                (0x0 << 15)
+#define RT5659_I2S_MS_S                                (0x1 << 15)
+#define RT5659_I2S_O_CP_MASK                   (0x3 << 12)
+#define RT5659_I2S_O_CP_SFT                    12
+#define RT5659_I2S_O_CP_OFF                    (0x0 << 12)
+#define RT5659_I2S_O_CP_U_LAW                  (0x1 << 12)
+#define RT5659_I2S_O_CP_A_LAW                  (0x2 << 12)
+#define RT5659_I2S_I_CP_MASK                   (0x3 << 10)
+#define RT5659_I2S_I_CP_SFT                    10
+#define RT5659_I2S_I_CP_OFF                    (0x0 << 10)
+#define RT5659_I2S_I_CP_U_LAW                  (0x1 << 10)
+#define RT5659_I2S_I_CP_A_LAW                  (0x2 << 10)
+#define RT5659_I2S_BP_MASK                     (0x1 << 8)
+#define RT5659_I2S_BP_SFT                      8
+#define RT5659_I2S_BP_NOR                      (0x0 << 8)
+#define RT5659_I2S_BP_INV                      (0x1 << 8)
+#define RT5659_I2S_DL_MASK                     (0x3 << 4)
+#define RT5659_I2S_DL_SFT                      4
+#define RT5659_I2S_DL_16                       (0x0 << 4)
+#define RT5659_I2S_DL_20                       (0x1 << 4)
+#define RT5659_I2S_DL_24                       (0x2 << 4)
+#define RT5659_I2S_DL_8                                (0x3 << 4)
+#define RT5659_I2S_DF_MASK                     (0x7)
+#define RT5659_I2S_DF_SFT                      0
+#define RT5659_I2S_DF_I2S                      (0x0)
+#define RT5659_I2S_DF_LEFT                     (0x1)
+#define RT5659_I2S_DF_PCM_A                    (0x2)
+#define RT5659_I2S_DF_PCM_B                    (0x3)
+#define RT5659_I2S_DF_PCM_A_N                  (0x6)
+#define RT5659_I2S_DF_PCM_B_N                  (0x7)
+
+/* ADC/DAC Clock Control 1 (0x0073) */
+#define RT5659_I2S_PD1_MASK                    (0x7 << 12)
+#define RT5659_I2S_PD1_SFT                     12
+#define RT5659_I2S_PD1_1                       (0x0 << 12)
+#define RT5659_I2S_PD1_2                       (0x1 << 12)
+#define RT5659_I2S_PD1_3                       (0x2 << 12)
+#define RT5659_I2S_PD1_4                       (0x3 << 12)
+#define RT5659_I2S_PD1_6                       (0x4 << 12)
+#define RT5659_I2S_PD1_8                       (0x5 << 12)
+#define RT5659_I2S_PD1_12                      (0x6 << 12)
+#define RT5659_I2S_PD1_16                      (0x7 << 12)
+#define RT5659_I2S_BCLK_MS2_MASK               (0x1 << 11)
+#define RT5659_I2S_BCLK_MS2_SFT                        11
+#define RT5659_I2S_BCLK_MS2_32                 (0x0 << 11)
+#define RT5659_I2S_BCLK_MS2_64                 (0x1 << 11)
+#define RT5659_I2S_PD2_MASK                    (0x7 << 8)
+#define RT5659_I2S_PD2_SFT                     8
+#define RT5659_I2S_PD2_1                       (0x0 << 8)
+#define RT5659_I2S_PD2_2                       (0x1 << 8)
+#define RT5659_I2S_PD2_3                       (0x2 << 8)
+#define RT5659_I2S_PD2_4                       (0x3 << 8)
+#define RT5659_I2S_PD2_6                       (0x4 << 8)
+#define RT5659_I2S_PD2_8                       (0x5 << 8)
+#define RT5659_I2S_PD2_12                      (0x6 << 8)
+#define RT5659_I2S_PD2_16                      (0x7 << 8)
+#define RT5659_I2S_BCLK_MS3_MASK               (0x1 << 7)
+#define RT5659_I2S_BCLK_MS3_SFT                        7
+#define RT5659_I2S_BCLK_MS3_32                 (0x0 << 7)
+#define RT5659_I2S_BCLK_MS3_64                 (0x1 << 7)
+#define RT5659_I2S_PD3_MASK                    (0x7 << 4)
+#define RT5659_I2S_PD3_SFT                     4
+#define RT5659_I2S_PD3_1                       (0x0 << 4)
+#define RT5659_I2S_PD3_2                       (0x1 << 4)
+#define RT5659_I2S_PD3_3                       (0x2 << 4)
+#define RT5659_I2S_PD3_4                       (0x3 << 4)
+#define RT5659_I2S_PD3_6                       (0x4 << 4)
+#define RT5659_I2S_PD3_8                       (0x5 << 4)
+#define RT5659_I2S_PD3_12                      (0x6 << 4)
+#define RT5659_I2S_PD3_16                      (0x7 << 4)
+#define RT5659_DAC_OSR_MASK                    (0x3 << 2)
+#define RT5659_DAC_OSR_SFT                     2
+#define RT5659_DAC_OSR_128                     (0x0 << 2)
+#define RT5659_DAC_OSR_64                      (0x1 << 2)
+#define RT5659_DAC_OSR_32                      (0x2 << 2)
+#define RT5659_DAC_OSR_16                      (0x3 << 2)
+#define RT5659_ADC_OSR_MASK                    (0x3)
+#define RT5659_ADC_OSR_SFT                     0
+#define RT5659_ADC_OSR_128                     (0x0)
+#define RT5659_ADC_OSR_64                      (0x1)
+#define RT5659_ADC_OSR_32                      (0x2)
+#define RT5659_ADC_OSR_16                      (0x3)
+
+/* Digital Microphone Control (0x0075) */
+#define RT5659_DMIC_1_EN_MASK                  (0x1 << 15)
+#define RT5659_DMIC_1_EN_SFT                   15
+#define RT5659_DMIC_1_DIS                      (0x0 << 15)
+#define RT5659_DMIC_1_EN                       (0x1 << 15)
+#define RT5659_DMIC_2_EN_MASK                  (0x1 << 14)
+#define RT5659_DMIC_2_EN_SFT                   14
+#define RT5659_DMIC_2_DIS                      (0x0 << 14)
+#define RT5659_DMIC_2_EN                       (0x1 << 14)
+#define RT5659_DMIC_1L_LH_MASK                 (0x1 << 13)
+#define RT5659_DMIC_1L_LH_SFT                  13
+#define RT5659_DMIC_1L_LH_RISING               (0x0 << 13)
+#define RT5659_DMIC_1L_LH_FALLING              (0x1 << 13)
+#define RT5659_DMIC_1R_LH_MASK                 (0x1 << 12)
+#define RT5659_DMIC_1R_LH_SFT                  12
+#define RT5659_DMIC_1R_LH_RISING               (0x0 << 12)
+#define RT5659_DMIC_1R_LH_FALLING              (0x1 << 12)
+#define RT5659_DMIC_2_DP_MASK                  (0x3 << 10)
+#define RT5659_DMIC_2_DP_SFT                   10
+#define RT5659_DMIC_2_DP_GPIO6                 (0x0 << 10)
+#define RT5659_DMIC_2_DP_GPIO10                        (0x1 << 10)
+#define RT5659_DMIC_2_DP_GPIO12                        (0x2 << 10)
+#define RT5659_DMIC_2_DP_IN2P                  (0x3 << 10)
+#define RT5659_DMIC_CLK_MASK                   (0x7 << 5)
+#define RT5659_DMIC_CLK_SFT                    5
+#define RT5659_DMIC_1_DP_MASK                  (0x3 << 0)
+#define RT5659_DMIC_1_DP_SFT                   0
+#define RT5659_DMIC_1_DP_GPIO5                 (0x0 << 0)
+#define RT5659_DMIC_1_DP_GPIO9                 (0x1 << 0)
+#define RT5659_DMIC_1_DP_GPIO11                        (0x2 << 0)
+#define RT5659_DMIC_1_DP_IN2N                  (0x3 << 0)
+
+/* TDM control 1 (0x0078)*/
+#define RT5659_DS_ADC_SLOT01_SFT               14
+#define RT5659_DS_ADC_SLOT23_SFT               12
+#define RT5659_DS_ADC_SLOT45_SFT               10
+#define RT5659_DS_ADC_SLOT67_SFT               8
+#define RT5659_ADCDAT_SRC_MASK                 0x1f
+#define RT5659_ADCDAT_SRC_SFT                  0
+
+/* Global Clock Control (0x0080) */
+#define RT5659_SCLK_SRC_MASK                   (0x3 << 14)
+#define RT5659_SCLK_SRC_SFT                    14
+#define RT5659_SCLK_SRC_MCLK                   (0x0 << 14)
+#define RT5659_SCLK_SRC_PLL1                   (0x1 << 14)
+#define RT5659_SCLK_SRC_RCCLK                  (0x2 << 14)
+#define RT5659_PLL1_SRC_MASK                   (0x7 << 11)
+#define RT5659_PLL1_SRC_SFT                    11
+#define RT5659_PLL1_SRC_MCLK                   (0x0 << 11)
+#define RT5659_PLL1_SRC_BCLK1                  (0x1 << 11)
+#define RT5659_PLL1_SRC_BCLK2                  (0x2 << 11)
+#define RT5659_PLL1_SRC_BCLK3                  (0x3 << 11)
+#define RT5659_PLL1_PD_MASK                    (0x1 << 3)
+#define RT5659_PLL1_PD_SFT                     3
+#define RT5659_PLL1_PD_1                       (0x0 << 3)
+#define RT5659_PLL1_PD_2                       (0x1 << 3)
+
+#define RT5659_PLL_INP_MAX                     40000000
+#define RT5659_PLL_INP_MIN                     256000
+/* PLL M/N/K Code Control 1 (0x0081) */
+#define RT5659_PLL_N_MAX                       0x001ff
+#define RT5659_PLL_N_MASK                      (RT5659_PLL_N_MAX << 7)
+#define RT5659_PLL_N_SFT                       7
+#define RT5659_PLL_K_MAX                       0x001f
+#define RT5659_PLL_K_MASK                      (RT5659_PLL_K_MAX)
+#define RT5659_PLL_K_SFT                       0
+
+/* PLL M/N/K Code Control 2 (0x0082) */
+#define RT5659_PLL_M_MAX                       0x00f
+#define RT5659_PLL_M_MASK                      (RT5659_PLL_M_MAX << 12)
+#define RT5659_PLL_M_SFT                       12
+#define RT5659_PLL_M_BP                                (0x1 << 11)
+#define RT5659_PLL_M_BP_SFT                    11
+
+/* PLL tracking mode 1 (0x0083) */
+#define RT5659_I2S3_ASRC_MASK                  (0x1 << 13)
+#define RT5659_I2S3_ASRC_SFT                   13
+#define RT5659_I2S2_ASRC_MASK                  (0x1 << 12)
+#define RT5659_I2S2_ASRC_SFT                   12
+#define RT5659_I2S1_ASRC_MASK                  (0x1 << 11)
+#define RT5659_I2S1_ASRC_SFT                   11
+#define RT5659_DAC_STO_ASRC_MASK               (0x1 << 10)
+#define RT5659_DAC_STO_ASRC_SFT                        10
+#define RT5659_DAC_MONO_L_ASRC_MASK            (0x1 << 9)
+#define RT5659_DAC_MONO_L_ASRC_SFT             9
+#define RT5659_DAC_MONO_R_ASRC_MASK            (0x1 << 8)
+#define RT5659_DAC_MONO_R_ASRC_SFT             8
+#define RT5659_DMIC_STO1_ASRC_MASK             (0x1 << 7)
+#define RT5659_DMIC_STO1_ASRC_SFT              7
+#define RT5659_DMIC_MONO_L_ASRC_MASK           (0x1 << 5)
+#define RT5659_DMIC_MONO_L_ASRC_SFT            5
+#define RT5659_DMIC_MONO_R_ASRC_MASK           (0x1 << 4)
+#define RT5659_DMIC_MONO_R_ASRC_SFT            4
+#define RT5659_ADC_STO1_ASRC_MASK              (0x1 << 3)
+#define RT5659_ADC_STO1_ASRC_SFT               3
+#define RT5659_ADC_MONO_L_ASRC_MASK            (0x1 << 1)
+#define RT5659_ADC_MONO_L_ASRC_SFT             1
+#define RT5659_ADC_MONO_R_ASRC_MASK            (0x1)
+#define RT5659_ADC_MONO_R_ASRC_SFT             0
+
+/* PLL tracking mode 2 (0x0084)*/
+#define RT5659_DA_STO_T_MASK                   (0x7 << 12)
+#define RT5659_DA_STO_T_SFT                    12
+#define RT5659_DA_MONO_L_T_MASK                        (0x7 << 8)
+#define RT5659_DA_MONO_L_T_SFT                 8
+#define RT5659_DA_MONO_R_T_MASK                        (0x7 << 4)
+#define RT5659_DA_MONO_R_T_SFT                 4
+#define RT5659_AD_STO1_T_MASK                  (0x7)
+#define RT5659_AD_STO1_T_SFT                   0
+
+/* PLL tracking mode 3 (0x0085)*/
+#define RT5659_AD_STO2_T_MASK                  (0x7 << 8)
+#define RT5659_AD_STO2_T_SFT                   8
+#define RT5659_AD_MONO_L_T_MASK                        (0x7 << 4)
+#define RT5659_AD_MONO_L_T_SFT                 4
+#define RT5659_AD_MONO_R_T_MASK                        (0x7)
+#define RT5659_AD_MONO_R_T_SFT                 0
+
+/* ASRC Control 4 (0x0086) */
+#define RT5659_I2S1_RATE_MASK                  (0xf << 12)
+#define RT5659_I2S1_RATE_SFT                   12
+#define RT5659_I2S2_RATE_MASK                  (0xf << 8)
+#define RT5659_I2S2_RATE_SFT                   8
+#define RT5659_I2S3_RATE_MASK                  (0xf << 4)
+#define RT5659_I2S3_RATE_SFT                   4
+
+/* Depop Mode Control 1 (0x8e) */
+#define RT5659_SMT_TRIG_MASK                   (0x1 << 15)
+#define RT5659_SMT_TRIG_SFT                    15
+#define RT5659_SMT_TRIG_DIS                    (0x0 << 15)
+#define RT5659_SMT_TRIG_EN                     (0x1 << 15)
+#define RT5659_HP_L_SMT_MASK                   (0x1 << 9)
+#define RT5659_HP_L_SMT_SFT                    9
+#define RT5659_HP_L_SMT_DIS                    (0x0 << 9)
+#define RT5659_HP_L_SMT_EN                     (0x1 << 9)
+#define RT5659_HP_R_SMT_MASK                   (0x1 << 8)
+#define RT5659_HP_R_SMT_SFT                    8
+#define RT5659_HP_R_SMT_DIS                    (0x0 << 8)
+#define RT5659_HP_R_SMT_EN                     (0x1 << 8)
+#define RT5659_HP_CD_PD_MASK                   (0x1 << 7)
+#define RT5659_HP_CD_PD_SFT                    7
+#define RT5659_HP_CD_PD_DIS                    (0x0 << 7)
+#define RT5659_HP_CD_PD_EN                     (0x1 << 7)
+#define RT5659_RSTN_MASK                       (0x1 << 6)
+#define RT5659_RSTN_SFT                                6
+#define RT5659_RSTN_DIS                                (0x0 << 6)
+#define RT5659_RSTN_EN                         (0x1 << 6)
+#define RT5659_RSTP_MASK                       (0x1 << 5)
+#define RT5659_RSTP_SFT                                5
+#define RT5659_RSTP_DIS                                (0x0 << 5)
+#define RT5659_RSTP_EN                         (0x1 << 5)
+#define RT5659_HP_CO_MASK                      (0x1 << 4)
+#define RT5659_HP_CO_SFT                       4
+#define RT5659_HP_CO_DIS                       (0x0 << 4)
+#define RT5659_HP_CO_EN                                (0x1 << 4)
+#define RT5659_HP_CP_MASK                      (0x1 << 3)
+#define RT5659_HP_CP_SFT                       3
+#define RT5659_HP_CP_PD                                (0x0 << 3)
+#define RT5659_HP_CP_PU                                (0x1 << 3)
+#define RT5659_HP_SG_MASK                      (0x1 << 2)
+#define RT5659_HP_SG_SFT                       2
+#define RT5659_HP_SG_DIS                       (0x0 << 2)
+#define RT5659_HP_SG_EN                                (0x1 << 2)
+#define RT5659_HP_DP_MASK                      (0x1 << 1)
+#define RT5659_HP_DP_SFT                       1
+#define RT5659_HP_DP_PD                                (0x0 << 1)
+#define RT5659_HP_DP_PU                                (0x1 << 1)
+#define RT5659_HP_CB_MASK                      (0x1)
+#define RT5659_HP_CB_SFT                       0
+#define RT5659_HP_CB_PD                                (0x0)
+#define RT5659_HP_CB_PU                                (0x1)
+
+/* Depop Mode Control 2 (0x8f) */
+#define RT5659_DEPOP_MASK                      (0x1 << 13)
+#define RT5659_DEPOP_SFT                       13
+#define RT5659_DEPOP_AUTO                      (0x0 << 13)
+#define RT5659_DEPOP_MAN                       (0x1 << 13)
+#define RT5659_RAMP_MASK                       (0x1 << 12)
+#define RT5659_RAMP_SFT                                12
+#define RT5659_RAMP_DIS                                (0x0 << 12)
+#define RT5659_RAMP_EN                         (0x1 << 12)
+#define RT5659_BPS_MASK                                (0x1 << 11)
+#define RT5659_BPS_SFT                         11
+#define RT5659_BPS_DIS                         (0x0 << 11)
+#define RT5659_BPS_EN                          (0x1 << 11)
+#define RT5659_FAST_UPDN_MASK                  (0x1 << 10)
+#define RT5659_FAST_UPDN_SFT                   10
+#define RT5659_FAST_UPDN_DIS                   (0x0 << 10)
+#define RT5659_FAST_UPDN_EN                    (0x1 << 10)
+#define RT5659_MRES_MASK                       (0x3 << 8)
+#define RT5659_MRES_SFT                                8
+#define RT5659_MRES_15MO                       (0x0 << 8)
+#define RT5659_MRES_25MO                       (0x1 << 8)
+#define RT5659_MRES_35MO                       (0x2 << 8)
+#define RT5659_MRES_45MO                       (0x3 << 8)
+#define RT5659_VLO_MASK                                (0x1 << 7)
+#define RT5659_VLO_SFT                         7
+#define RT5659_VLO_3V                          (0x0 << 7)
+#define RT5659_VLO_32V                         (0x1 << 7)
+#define RT5659_DIG_DP_MASK                     (0x1 << 6)
+#define RT5659_DIG_DP_SFT                      6
+#define RT5659_DIG_DP_DIS                      (0x0 << 6)
+#define RT5659_DIG_DP_EN                       (0x1 << 6)
+#define RT5659_DP_TH_MASK                      (0x3 << 4)
+#define RT5659_DP_TH_SFT                       4
+
+/* Depop Mode Control 3 (0x90) */
+#define RT5659_CP_SYS_MASK                     (0x7 << 12)
+#define RT5659_CP_SYS_SFT                      12
+#define RT5659_CP_FQ1_MASK                     (0x7 << 8)
+#define RT5659_CP_FQ1_SFT                      8
+#define RT5659_CP_FQ2_MASK                     (0x7 << 4)
+#define RT5659_CP_FQ2_SFT                      4
+#define RT5659_CP_FQ3_MASK                     (0x7)
+#define RT5659_CP_FQ3_SFT                      0
+#define RT5659_CP_FQ_1_5_KHZ                   0
+#define RT5659_CP_FQ_3_KHZ                     1
+#define RT5659_CP_FQ_6_KHZ                     2
+#define RT5659_CP_FQ_12_KHZ                    3
+#define RT5659_CP_FQ_24_KHZ                    4
+#define RT5659_CP_FQ_48_KHZ                    5
+#define RT5659_CP_FQ_96_KHZ                    6
+#define RT5659_CP_FQ_192_KHZ                   7
+
+/* HPOUT charge pump 1 (0x0091) */
+#define RT5659_OSW_L_MASK                      (0x1 << 11)
+#define RT5659_OSW_L_SFT                       11
+#define RT5659_OSW_L_DIS                       (0x0 << 11)
+#define RT5659_OSW_L_EN                                (0x1 << 11)
+#define RT5659_OSW_R_MASK                      (0x1 << 10)
+#define RT5659_OSW_R_SFT                       10
+#define RT5659_OSW_R_DIS                       (0x0 << 10)
+#define RT5659_OSW_R_EN                                (0x1 << 10)
+#define RT5659_PM_HP_MASK                      (0x3 << 8)
+#define RT5659_PM_HP_SFT                       8
+#define RT5659_PM_HP_LV                                (0x0 << 8)
+#define RT5659_PM_HP_MV                                (0x1 << 8)
+#define RT5659_PM_HP_HV                                (0x2 << 8)
+#define RT5659_IB_HP_MASK                      (0x3 << 6)
+#define RT5659_IB_HP_SFT                       6
+#define RT5659_IB_HP_125IL                     (0x0 << 6)
+#define RT5659_IB_HP_25IL                      (0x1 << 6)
+#define RT5659_IB_HP_5IL                       (0x2 << 6)
+#define RT5659_IB_HP_1IL                       (0x3 << 6)
+
+/* PV detection and SPK gain control (0x92) */
+#define RT5659_PVDD_DET_MASK                   (0x1 << 15)
+#define RT5659_PVDD_DET_SFT                    15
+#define RT5659_PVDD_DET_DIS                    (0x0 << 15)
+#define RT5659_PVDD_DET_EN                     (0x1 << 15)
+#define RT5659_SPK_AG_MASK                     (0x1 << 14)
+#define RT5659_SPK_AG_SFT                      14
+#define RT5659_SPK_AG_DIS                      (0x0 << 14)
+#define RT5659_SPK_AG_EN                       (0x1 << 14)
+
+/* Micbias Control (0x93) */
+#define RT5659_MIC1_BS_MASK                    (0x1 << 15)
+#define RT5659_MIC1_BS_SFT                     15
+#define RT5659_MIC1_BS_9AV                     (0x0 << 15)
+#define RT5659_MIC1_BS_75AV                    (0x1 << 15)
+#define RT5659_MIC2_BS_MASK                    (0x1 << 14)
+#define RT5659_MIC2_BS_SFT                     14
+#define RT5659_MIC2_BS_9AV                     (0x0 << 14)
+#define RT5659_MIC2_BS_75AV                    (0x1 << 14)
+#define RT5659_MIC1_CLK_MASK                   (0x1 << 13)
+#define RT5659_MIC1_CLK_SFT                    13
+#define RT5659_MIC1_CLK_DIS                    (0x0 << 13)
+#define RT5659_MIC1_CLK_EN                     (0x1 << 13)
+#define RT5659_MIC2_CLK_MASK                   (0x1 << 12)
+#define RT5659_MIC2_CLK_SFT                    12
+#define RT5659_MIC2_CLK_DIS                    (0x0 << 12)
+#define RT5659_MIC2_CLK_EN                     (0x1 << 12)
+#define RT5659_MIC1_OVCD_MASK                  (0x1 << 11)
+#define RT5659_MIC1_OVCD_SFT                   11
+#define RT5659_MIC1_OVCD_DIS                   (0x0 << 11)
+#define RT5659_MIC1_OVCD_EN                    (0x1 << 11)
+#define RT5659_MIC1_OVTH_MASK                  (0x3 << 9)
+#define RT5659_MIC1_OVTH_SFT                   9
+#define RT5659_MIC1_OVTH_600UA                 (0x0 << 9)
+#define RT5659_MIC1_OVTH_1500UA                        (0x1 << 9)
+#define RT5659_MIC1_OVTH_2000UA                        (0x2 << 9)
+#define RT5659_MIC2_OVCD_MASK                  (0x1 << 8)
+#define RT5659_MIC2_OVCD_SFT                   8
+#define RT5659_MIC2_OVCD_DIS                   (0x0 << 8)
+#define RT5659_MIC2_OVCD_EN                    (0x1 << 8)
+#define RT5659_MIC2_OVTH_MASK                  (0x3 << 6)
+#define RT5659_MIC2_OVTH_SFT                   6
+#define RT5659_MIC2_OVTH_600UA                 (0x0 << 6)
+#define RT5659_MIC2_OVTH_1500UA                        (0x1 << 6)
+#define RT5659_MIC2_OVTH_2000UA                        (0x2 << 6)
+#define RT5659_PWR_MB_MASK                     (0x1 << 5)
+#define RT5659_PWR_MB_SFT                      5
+#define RT5659_PWR_MB_PD                       (0x0 << 5)
+#define RT5659_PWR_MB_PU                       (0x1 << 5)
+#define RT5659_PWR_CLK25M_MASK                 (0x1 << 4)
+#define RT5659_PWR_CLK25M_SFT                  4
+#define RT5659_PWR_CLK25M_PD                   (0x0 << 4)
+#define RT5659_PWR_CLK25M_PU                   (0x1 << 4)
+
+/* REC Mixer 2 Left Control 2 (0x009c) */
+#define RT5659_M_BST1_RM2_L                    (0x1 << 5)
+#define RT5659_M_BST1_RM2_L_SFT                        5
+#define RT5659_M_BST2_RM2_L                    (0x1 << 4)
+#define RT5659_M_BST2_RM2_L_SFT                        4
+#define RT5659_M_BST3_RM2_L                    (0x1 << 3)
+#define RT5659_M_BST3_RM2_L_SFT                        3
+#define RT5659_M_BST4_RM2_L                    (0x1 << 2)
+#define RT5659_M_BST4_RM2_L_SFT                        2
+#define RT5659_M_OUTVOLL_RM2_L                 (0x1 << 1)
+#define RT5659_M_OUTVOLL_RM2_L_SFT             1
+#define RT5659_M_SPKVOL_RM2_L                  (0x1)
+#define RT5659_M_SPKVOL_RM2_L_SFT              0
+
+/* REC Mixer 2 Right Control 2 (0x009e) */
+#define RT5659_M_BST1_RM2_R                    (0x1 << 5)
+#define RT5659_M_BST1_RM2_R_SFT                        5
+#define RT5659_M_BST2_RM2_R                    (0x1 << 4)
+#define RT5659_M_BST2_RM2_R_SFT                        4
+#define RT5659_M_BST3_RM2_R                    (0x1 << 3)
+#define RT5659_M_BST3_RM2_R_SFT                        3
+#define RT5659_M_BST4_RM2_R                    (0x1 << 2)
+#define RT5659_M_BST4_RM2_R_SFT                        2
+#define RT5659_M_OUTVOLR_RM2_R                 (0x1 << 1)
+#define RT5659_M_OUTVOLR_RM2_R_SFT             1
+#define RT5659_M_MONOVOL_RM2_R                 (0x1)
+#define RT5659_M_MONOVOL_RM2_R_SFT             0
+
+/* Class D Output Control (0x00a0) */
+#define RT5659_POW_CLSD_DB_MASK                        (0x1 << 9)
+#define RT5659_POW_CLSD_DB_EN                  (0x1 << 9)
+#define RT5659_POW_CLSD_DB_DIS                 (0x0 << 9)
+
+/* EQ Control 1 (0x00b0) */
+#define RT5659_EQ_SRC_DAC                      (0x0 << 15)
+#define RT5659_EQ_SRC_ADC                      (0x1 << 15)
+#define RT5659_EQ_UPD                          (0x1 << 14)
+#define RT5659_EQ_UPD_BIT                      14
+#define RT5659_EQ_CD_MASK                      (0x1 << 13)
+#define RT5659_EQ_CD_SFT                       13
+#define RT5659_EQ_CD_DIS                       (0x0 << 13)
+#define RT5659_EQ_CD_EN                                (0x1 << 13)
+#define RT5659_EQ_DITH_MASK                    (0x3 << 8)
+#define RT5659_EQ_DITH_SFT                     8
+#define RT5659_EQ_DITH_NOR                     (0x0 << 8)
+#define RT5659_EQ_DITH_LSB                     (0x1 << 8)
+#define RT5659_EQ_DITH_LSB_1                   (0x2 << 8)
+#define RT5659_EQ_DITH_LSB_2                   (0x3 << 8)
+
+/* IRQ Control 1 (0x00b7) */
+#define RT5659_JD1_1_EN_MASK                   (0x1 << 15)
+#define RT5659_JD1_1_EN_SFT                    15
+#define RT5659_JD1_1_DIS                       (0x0 << 15)
+#define RT5659_JD1_1_EN                                (0x1 << 15)
+#define RT5659_JD1_2_EN_MASK                   (0x1 << 12)
+#define RT5659_JD1_2_EN_SFT                    12
+#define RT5659_JD1_2_DIS                       (0x0 << 12)
+#define RT5659_JD1_2_EN                                (0x1 << 12)
+#define RT5659_IL_IRQ_MASK                     (0x1 << 3)
+#define RT5659_IL_IRQ_DIS                      (0x0 << 3)
+#define RT5659_IL_IRQ_EN                       (0x1 << 3)
+
+/* IRQ Control 5 (0x00ba) */
+#define RT5659_IRQ_JD_EN                       (0x1 << 3)
+#define RT5659_IRQ_JD_EN_SFT                   3
+
+/* GPIO Control 1 (0x00c0) */
+#define RT5659_GP1_PIN_MASK                    (0x1 << 15)
+#define RT5659_GP1_PIN_SFT                     15
+#define RT5659_GP1_PIN_GPIO1                   (0x0 << 15)
+#define RT5659_GP1_PIN_IRQ                     (0x1 << 15)
+#define RT5659_GP2_PIN_MASK                    (0x1 << 14)
+#define RT5659_GP2_PIN_SFT                     14
+#define RT5659_GP2_PIN_GPIO2                   (0x0 << 14)
+#define RT5659_GP2_PIN_DMIC1_SCL               (0x1 << 14)
+#define RT5659_GP3_PIN_MASK                    (0x1 << 13)
+#define RT5659_GP3_PIN_SFT                     13
+#define RT5659_GP3_PIN_GPIO3                   (0x0 << 13)
+#define RT5659_GP3_PIN_PDM_SCL                 (0x1 << 13)
+#define RT5659_GP4_PIN_MASK                    (0x1 << 12)
+#define RT5659_GP4_PIN_SFT                     12
+#define RT5659_GP4_PIN_GPIO4                   (0x0 << 12)
+#define RT5659_GP4_PIN_PDM_SDA                 (0x1 << 12)
+#define RT5659_GP5_PIN_MASK                    (0x1 << 11)
+#define RT5659_GP5_PIN_SFT                     11
+#define RT5659_GP5_PIN_GPIO5                   (0x0 << 11)
+#define RT5659_GP5_PIN_DMIC1_SDA               (0x1 << 11)
+#define RT5659_GP6_PIN_MASK                    (0x1 << 10)
+#define RT5659_GP6_PIN_SFT                     10
+#define RT5659_GP6_PIN_GPIO6                   (0x0 << 10)
+#define RT5659_GP6_PIN_DMIC2_SDA               (0x1 << 10)
+#define RT5659_GP7_PIN_MASK                    (0x1 << 9)
+#define RT5659_GP7_PIN_SFT                     9
+#define RT5659_GP7_PIN_GPIO7                   (0x0 << 9)
+#define RT5659_GP7_PIN_PDM_SCL                 (0x1 << 9)
+#define RT5659_GP8_PIN_MASK                    (0x1 << 8)
+#define RT5659_GP8_PIN_SFT                     8
+#define RT5659_GP8_PIN_GPIO8                   (0x0 << 8)
+#define RT5659_GP8_PIN_PDM_SDA                 (0x1 << 8)
+#define RT5659_GP9_PIN_MASK                    (0x1 << 7)
+#define RT5659_GP9_PIN_SFT                     7
+#define RT5659_GP9_PIN_GPIO9                   (0x0 << 7)
+#define RT5659_GP9_PIN_DMIC1_SDA               (0x1 << 7)
+#define RT5659_GP10_PIN_MASK                   (0x1 << 6)
+#define RT5659_GP10_PIN_SFT                    6
+#define RT5659_GP10_PIN_GPIO10                 (0x0 << 6)
+#define RT5659_GP10_PIN_DMIC2_SDA              (0x1 << 6)
+#define RT5659_GP11_PIN_MASK                   (0x1 << 5)
+#define RT5659_GP11_PIN_SFT                    5
+#define RT5659_GP11_PIN_GPIO11                 (0x0 << 5)
+#define RT5659_GP11_PIN_DMIC1_SDA              (0x1 << 5)
+#define RT5659_GP12_PIN_MASK                   (0x1 << 4)
+#define RT5659_GP12_PIN_SFT                    4
+#define RT5659_GP12_PIN_GPIO12                 (0x0 << 4)
+#define RT5659_GP12_PIN_DMIC2_SDA              (0x1 << 4)
+#define RT5659_GP13_PIN_MASK                   (0x3 << 2)
+#define RT5659_GP13_PIN_SFT                    2
+#define RT5659_GP13_PIN_GPIO13                 (0x0 << 2)
+#define RT5659_GP13_PIN_SPDIF_SDA              (0x1 << 2)
+#define RT5659_GP13_PIN_DMIC2_SCL              (0x2 << 2)
+#define RT5659_GP13_PIN_PDM_SCL                        (0x3 << 2)
+#define RT5659_GP15_PIN_MASK                   (0x3)
+#define RT5659_GP15_PIN_SFT                    0
+#define RT5659_GP15_PIN_GPIO15                 (0x0)
+#define RT5659_GP15_PIN_DMIC3_SCL              (0x1)
+#define RT5659_GP15_PIN_PDM_SDA                        (0x2)
+
+/* GPIO Control 2 (0x00c1)*/
+#define RT5659_GP1_PF_IN                       (0x0 << 2)
+#define RT5659_GP1_PF_OUT                      (0x1 << 2)
+#define RT5659_GP1_PF_MASK                     (0x1 << 2)
+#define RT5659_GP1_PF_SFT                      2
+
+/* GPIO Control 3 (0x00c2) */
+#define RT5659_I2S2_PIN_MASK                   (0x1 << 15)
+#define RT5659_I2S2_PIN_SFT                    15
+#define RT5659_I2S2_PIN_I2S                    (0x0 << 15)
+#define RT5659_I2S2_PIN_GPIO                   (0x1 << 15)
+
+/* Soft volume and zero cross control 1 (0x00d9) */
+#define RT5659_SV_MASK                         (0x1 << 15)
+#define RT5659_SV_SFT                          15
+#define RT5659_SV_DIS                          (0x0 << 15)
+#define RT5659_SV_EN                           (0x1 << 15)
+#define RT5659_OUT_SV_MASK                     (0x1 << 13)
+#define RT5659_OUT_SV_SFT                      13
+#define RT5659_OUT_SV_DIS                      (0x0 << 13)
+#define RT5659_OUT_SV_EN                       (0x1 << 13)
+#define RT5659_HP_SV_MASK                      (0x1 << 12)
+#define RT5659_HP_SV_SFT                       12
+#define RT5659_HP_SV_DIS                       (0x0 << 12)
+#define RT5659_HP_SV_EN                                (0x1 << 12)
+#define RT5659_ZCD_DIG_MASK                    (0x1 << 11)
+#define RT5659_ZCD_DIG_SFT                     11
+#define RT5659_ZCD_DIG_DIS                     (0x0 << 11)
+#define RT5659_ZCD_DIG_EN                      (0x1 << 11)
+#define RT5659_ZCD_MASK                                (0x1 << 10)
+#define RT5659_ZCD_SFT                         10
+#define RT5659_ZCD_PD                          (0x0 << 10)
+#define RT5659_ZCD_PU                          (0x1 << 10)
+#define RT5659_SV_DLY_MASK                     (0xf)
+#define RT5659_SV_DLY_SFT                      0
+
+/* Soft volume and zero cross control 2 (0x00da) */
+#define RT5659_ZCD_HP_MASK                     (0x1 << 15)
+#define RT5659_ZCD_HP_SFT                      15
+#define RT5659_ZCD_HP_DIS                      (0x0 << 15)
+#define RT5659_ZCD_HP_EN                       (0x1 << 15)
+
+/* 4 Button Inline Command Control 2 (0x00e0) */
+#define RT5659_4BTN_IL_MASK                    (0x1 << 15)
+#define RT5659_4BTN_IL_EN                      (0x1 << 15)
+#define RT5659_4BTN_IL_DIS                     (0x0 << 15)
+
+/* Analog JD Control 1 (0x00f0) */
+#define RT5659_JD1_MODE_MASK                   (0x3 << 0)
+#define RT5659_JD1_MODE_0                      (0x0 << 0)
+#define RT5659_JD1_MODE_1                      (0x1 << 0)
+#define RT5659_JD1_MODE_2                      (0x2 << 0)
+
+/* Jack Detect Control 3 (0x00f8) */
+#define RT5659_JD_TRI_HPO_SEL_MASK             (0x7)
+#define RT5659_JD_TRI_HPO_SEL_SFT              (0)
+#define RT5659_JD_HPO_GPIO_JD1                 (0x0)
+#define RT5659_JD_HPO_JD1_1                    (0x1)
+#define RT5659_JD_HPO_JD1_2                    (0x2)
+#define RT5659_JD_HPO_JD2                      (0x3)
+#define RT5659_JD_HPO_GPIO_JD2                 (0x4)
+#define RT5659_JD_HPO_JD3                      (0x5)
+#define RT5659_JD_HPO_JD_D                     (0x6)
+
+/* Digital Misc Control (0x00fa) */
+#define RT5659_AM_MASK                         (0x1 << 7)
+#define RT5659_AM_EN                           (0x1 << 7)
+#define RT5659_AM_DIS                          (0x1 << 7)
+#define RT5659_DIG_GATE_CTRL                   0x1
+#define RT5659_DIG_GATE_CTRL_SFT               (0)
+
+/* Chopper and Clock control for ADC (0x011c)*/
+#define RT5659_M_RF_DIG_MASK                   (0x1 << 12)
+#define RT5659_M_RF_DIG_SFT                    12
+#define RT5659_M_RI_DIG                                (0x1 << 11)
+
+/* Chopper and Clock control for DAC (0x013a)*/
+#define RT5659_CKXEN_DAC1_MASK                 (0x1 << 13)
+#define RT5659_CKXEN_DAC1_SFT                  13
+#define RT5659_CKGEN_DAC1_MASK                 (0x1 << 12)
+#define RT5659_CKGEN_DAC1_SFT                  12
+#define RT5659_CKXEN_DAC2_MASK                 (0x1 << 5)
+#define RT5659_CKXEN_DAC2_SFT                  5
+#define RT5659_CKGEN_DAC2_MASK                 (0x1 << 4)
+#define RT5659_CKGEN_DAC2_SFT                  4
+
+/* Chopper and Clock control for ADC (0x013b)*/
+#define RT5659_CKXEN_ADCC_MASK                 (0x1 << 13)
+#define RT5659_CKXEN_ADCC_SFT                  13
+#define RT5659_CKGEN_ADCC_MASK                 (0x1 << 12)
+#define RT5659_CKGEN_ADCC_SFT                  12
+
+/* Test Mode Control 1 (0x0145) */
+#define RT5659_AD2DA_LB_MASK                   (0x1 << 9)
+#define RT5659_AD2DA_LB_SFT                    9
+
+/* Stereo Noise Gate Control 1 (0x0160) */
+#define RT5659_NG2_EN_MASK                     (0x1 << 15)
+#define RT5659_NG2_EN                          (0x1 << 15)
+#define RT5659_NG2_DIS                         (0x0 << 15)
+
+/* System Clock Source */
+enum {
+       RT5659_SCLK_S_MCLK,
+       RT5659_SCLK_S_PLL1,
+       RT5659_SCLK_S_RCCLK,
+};
+
+/* PLL1 Source */
+enum {
+       RT5659_PLL1_S_MCLK,
+       RT5659_PLL1_S_BCLK1,
+       RT5659_PLL1_S_BCLK2,
+       RT5659_PLL1_S_BCLK3,
+       RT5659_PLL1_S_BCLK4,
+};
+
+enum {
+       RT5659_AIF1,
+       RT5659_AIF2,
+       RT5659_AIF3,
+       RT5659_AIF4,
+       RT5659_AIFS,
+};
+
+struct rt5659_pll_code {
+       bool m_bp;
+       int m_code;
+       int n_code;
+       int k_code;
+};
+
+struct rt5659_priv {
+       struct snd_soc_codec *codec;
+       struct rt5659_platform_data pdata;
+       struct regmap *regmap;
+       struct i2c_client *i2c;
+       struct gpio_desc *gpiod_ldo1_en;
+       struct gpio_desc *gpiod_reset;
+       struct snd_soc_jack *hs_jack;
+       struct delayed_work jack_detect_work;
+
+       int sysclk;
+       int sysclk_src;
+       int lrck[RT5659_AIFS];
+       int bclk[RT5659_AIFS];
+       int master[RT5659_AIFS];
+       int v_id;
+
+       int pll_src;
+       int pll_in;
+       int pll_out;
+
+       int jack_type;
+
+};
+
+int rt5659_set_jack_detect(struct snd_soc_codec *codec,
+       struct snd_soc_jack *hs_jack);
+
+#endif /* __RT5659_H__ */
index dc2b46236c5cb5cd7ba12ec5fd9f311868978983..3f1b0f1df8097ba9d47644b3dd74548642d3cf82 100644 (file)
 #define RT5670_SCLK_SRC_MCLK                   (0x0 << 14)
 #define RT5670_SCLK_SRC_PLL1                   (0x1 << 14)
 #define RT5670_SCLK_SRC_RCCLK                  (0x2 << 14) /* 15MHz */
-#define RT5670_PLL1_SRC_MASK                   (0x3 << 12)
-#define RT5670_PLL1_SRC_SFT                    12
-#define RT5670_PLL1_SRC_MCLK                   (0x0 << 12)
-#define RT5670_PLL1_SRC_BCLK1                  (0x1 << 12)
-#define RT5670_PLL1_SRC_BCLK2                  (0x2 << 12)
-#define RT5670_PLL1_SRC_BCLK3                  (0x3 << 12)
+#define RT5670_PLL1_SRC_MASK                   (0x7 << 11)
+#define RT5670_PLL1_SRC_SFT                    11
+#define RT5670_PLL1_SRC_MCLK                   (0x0 << 11)
+#define RT5670_PLL1_SRC_BCLK1                  (0x1 << 11)
+#define RT5670_PLL1_SRC_BCLK2                  (0x2 << 11)
+#define RT5670_PLL1_SRC_BCLK3                  (0x3 << 11)
 #define RT5670_PLL1_PD_MASK                    (0x1 << 3)
 #define RT5670_PLL1_PD_SFT                     3
 #define RT5670_PLL1_PD_1                       (0x0 << 3)
index b4cd7e3bf5f89f9ea940528f233f017151788a4b..967678e7f48ef19297e32734d11a336cb720caaa 100644 (file)
@@ -297,8 +297,6 @@ static bool rt5677_volatile_register(struct device *dev, unsigned int reg)
        case RT5677_HAP_GENE_CTRL2:
        case RT5677_PWR_DSP_ST:
        case RT5677_PRIV_DATA:
-       case RT5677_PLL1_CTRL2:
-       case RT5677_PLL2_CTRL2:
        case RT5677_ASRC_22:
        case RT5677_ASRC_23:
        case RT5677_VAD_CTRL5:
@@ -1386,90 +1384,90 @@ static const struct snd_kcontrol_new rt5677_dac_r_mix[] = {
 };
 
 static const struct snd_kcontrol_new rt5677_sto1_dac_l_mix[] = {
-       SOC_DAPM_SINGLE("ST L Switch", RT5677_STO1_DAC_MIXER,
+       SOC_DAPM_SINGLE_AUTODISABLE("ST L Switch", RT5677_STO1_DAC_MIXER,
                        RT5677_M_ST_DAC1_L_SFT, 1, 1),
-       SOC_DAPM_SINGLE("DAC1 L Switch", RT5677_STO1_DAC_MIXER,
+       SOC_DAPM_SINGLE_AUTODISABLE("DAC1 L Switch", RT5677_STO1_DAC_MIXER,
                        RT5677_M_DAC1_L_STO_L_SFT, 1, 1),
-       SOC_DAPM_SINGLE("DAC2 L Switch", RT5677_STO1_DAC_MIXER,
+       SOC_DAPM_SINGLE_AUTODISABLE("DAC2 L Switch", RT5677_STO1_DAC_MIXER,
                        RT5677_M_DAC2_L_STO_L_SFT, 1, 1),
-       SOC_DAPM_SINGLE("DAC1 R Switch", RT5677_STO1_DAC_MIXER,
+       SOC_DAPM_SINGLE_AUTODISABLE("DAC1 R Switch", RT5677_STO1_DAC_MIXER,
                        RT5677_M_DAC1_R_STO_L_SFT, 1, 1),
 };
 
 static const struct snd_kcontrol_new rt5677_sto1_dac_r_mix[] = {
-       SOC_DAPM_SINGLE("ST R Switch", RT5677_STO1_DAC_MIXER,
+       SOC_DAPM_SINGLE_AUTODISABLE("ST R Switch", RT5677_STO1_DAC_MIXER,
                        RT5677_M_ST_DAC1_R_SFT, 1, 1),
-       SOC_DAPM_SINGLE("DAC1 R Switch", RT5677_STO1_DAC_MIXER,
+       SOC_DAPM_SINGLE_AUTODISABLE("DAC1 R Switch", RT5677_STO1_DAC_MIXER,
                        RT5677_M_DAC1_R_STO_R_SFT, 1, 1),
-       SOC_DAPM_SINGLE("DAC2 R Switch", RT5677_STO1_DAC_MIXER,
+       SOC_DAPM_SINGLE_AUTODISABLE("DAC2 R Switch", RT5677_STO1_DAC_MIXER,
                        RT5677_M_DAC2_R_STO_R_SFT, 1, 1),
-       SOC_DAPM_SINGLE("DAC1 L Switch", RT5677_STO1_DAC_MIXER,
+       SOC_DAPM_SINGLE_AUTODISABLE("DAC1 L Switch", RT5677_STO1_DAC_MIXER,
                        RT5677_M_DAC1_L_STO_R_SFT, 1, 1),
 };
 
 static const struct snd_kcontrol_new rt5677_mono_dac_l_mix[] = {
-       SOC_DAPM_SINGLE("ST L Switch", RT5677_MONO_DAC_MIXER,
+       SOC_DAPM_SINGLE_AUTODISABLE("ST L Switch", RT5677_MONO_DAC_MIXER,
                        RT5677_M_ST_DAC2_L_SFT, 1, 1),
-       SOC_DAPM_SINGLE("DAC1 L Switch", RT5677_MONO_DAC_MIXER,
+       SOC_DAPM_SINGLE_AUTODISABLE("DAC1 L Switch", RT5677_MONO_DAC_MIXER,
                        RT5677_M_DAC1_L_MONO_L_SFT, 1, 1),
-       SOC_DAPM_SINGLE("DAC2 L Switch", RT5677_MONO_DAC_MIXER,
+       SOC_DAPM_SINGLE_AUTODISABLE("DAC2 L Switch", RT5677_MONO_DAC_MIXER,
                        RT5677_M_DAC2_L_MONO_L_SFT, 1, 1),
-       SOC_DAPM_SINGLE("DAC2 R Switch", RT5677_MONO_DAC_MIXER,
+       SOC_DAPM_SINGLE_AUTODISABLE("DAC2 R Switch", RT5677_MONO_DAC_MIXER,
                        RT5677_M_DAC2_R_MONO_L_SFT, 1, 1),
 };
 
 static const struct snd_kcontrol_new rt5677_mono_dac_r_mix[] = {
-       SOC_DAPM_SINGLE("ST R Switch", RT5677_MONO_DAC_MIXER,
+       SOC_DAPM_SINGLE_AUTODISABLE("ST R Switch", RT5677_MONO_DAC_MIXER,
                        RT5677_M_ST_DAC2_R_SFT, 1, 1),
-       SOC_DAPM_SINGLE("DAC1 R Switch", RT5677_MONO_DAC_MIXER,
+       SOC_DAPM_SINGLE_AUTODISABLE("DAC1 R Switch", RT5677_MONO_DAC_MIXER,
                        RT5677_M_DAC1_R_MONO_R_SFT, 1, 1),
-       SOC_DAPM_SINGLE("DAC2 R Switch", RT5677_MONO_DAC_MIXER,
+       SOC_DAPM_SINGLE_AUTODISABLE("DAC2 R Switch", RT5677_MONO_DAC_MIXER,
                        RT5677_M_DAC2_R_MONO_R_SFT, 1, 1),
-       SOC_DAPM_SINGLE("DAC2 L Switch", RT5677_MONO_DAC_MIXER,
+       SOC_DAPM_SINGLE_AUTODISABLE("DAC2 L Switch", RT5677_MONO_DAC_MIXER,
                        RT5677_M_DAC2_L_MONO_R_SFT, 1, 1),
 };
 
 static const struct snd_kcontrol_new rt5677_dd1_l_mix[] = {
-       SOC_DAPM_SINGLE("Sto DAC Mix L Switch", RT5677_DD1_MIXER,
+       SOC_DAPM_SINGLE_AUTODISABLE("Sto DAC Mix L Switch", RT5677_DD1_MIXER,
                        RT5677_M_STO_L_DD1_L_SFT, 1, 1),
-       SOC_DAPM_SINGLE("Mono DAC Mix L Switch", RT5677_DD1_MIXER,
+       SOC_DAPM_SINGLE_AUTODISABLE("Mono DAC Mix L Switch", RT5677_DD1_MIXER,
                        RT5677_M_MONO_L_DD1_L_SFT, 1, 1),
-       SOC_DAPM_SINGLE("DAC3 L Switch", RT5677_DD1_MIXER,
+       SOC_DAPM_SINGLE_AUTODISABLE("DAC3 L Switch", RT5677_DD1_MIXER,
                        RT5677_M_DAC3_L_DD1_L_SFT, 1, 1),
-       SOC_DAPM_SINGLE("DAC3 R Switch", RT5677_DD1_MIXER,
+       SOC_DAPM_SINGLE_AUTODISABLE("DAC3 R Switch", RT5677_DD1_MIXER,
                        RT5677_M_DAC3_R_DD1_L_SFT, 1, 1),
 };
 
 static const struct snd_kcontrol_new rt5677_dd1_r_mix[] = {
-       SOC_DAPM_SINGLE("Sto DAC Mix R Switch", RT5677_DD1_MIXER,
+       SOC_DAPM_SINGLE_AUTODISABLE("Sto DAC Mix R Switch", RT5677_DD1_MIXER,
                        RT5677_M_STO_R_DD1_R_SFT, 1, 1),
-       SOC_DAPM_SINGLE("Mono DAC Mix R Switch", RT5677_DD1_MIXER,
+       SOC_DAPM_SINGLE_AUTODISABLE("Mono DAC Mix R Switch", RT5677_DD1_MIXER,
                        RT5677_M_MONO_R_DD1_R_SFT, 1, 1),
-       SOC_DAPM_SINGLE("DAC3 R Switch", RT5677_DD1_MIXER,
+       SOC_DAPM_SINGLE_AUTODISABLE("DAC3 R Switch", RT5677_DD1_MIXER,
                        RT5677_M_DAC3_R_DD1_R_SFT, 1, 1),
-       SOC_DAPM_SINGLE("DAC3 L Switch", RT5677_DD1_MIXER,
+       SOC_DAPM_SINGLE_AUTODISABLE("DAC3 L Switch", RT5677_DD1_MIXER,
                        RT5677_M_DAC3_L_DD1_R_SFT, 1, 1),
 };
 
 static const struct snd_kcontrol_new rt5677_dd2_l_mix[] = {
-       SOC_DAPM_SINGLE("Sto DAC Mix L Switch", RT5677_DD2_MIXER,
+       SOC_DAPM_SINGLE_AUTODISABLE("Sto DAC Mix L Switch", RT5677_DD2_MIXER,
                        RT5677_M_STO_L_DD2_L_SFT, 1, 1),
-       SOC_DAPM_SINGLE("Mono DAC Mix L Switch", RT5677_DD2_MIXER,
+       SOC_DAPM_SINGLE_AUTODISABLE("Mono DAC Mix L Switch", RT5677_DD2_MIXER,
                        RT5677_M_MONO_L_DD2_L_SFT, 1, 1),
-       SOC_DAPM_SINGLE("DAC4 L Switch", RT5677_DD2_MIXER,
+       SOC_DAPM_SINGLE_AUTODISABLE("DAC4 L Switch", RT5677_DD2_MIXER,
                        RT5677_M_DAC4_L_DD2_L_SFT, 1, 1),
-       SOC_DAPM_SINGLE("DAC4 R Switch", RT5677_DD2_MIXER,
+       SOC_DAPM_SINGLE_AUTODISABLE("DAC4 R Switch", RT5677_DD2_MIXER,
                        RT5677_M_DAC4_R_DD2_L_SFT, 1, 1),
 };
 
 static const struct snd_kcontrol_new rt5677_dd2_r_mix[] = {
-       SOC_DAPM_SINGLE("Sto DAC Mix R Switch", RT5677_DD2_MIXER,
+       SOC_DAPM_SINGLE_AUTODISABLE("Sto DAC Mix R Switch", RT5677_DD2_MIXER,
                        RT5677_M_STO_R_DD2_R_SFT, 1, 1),
-       SOC_DAPM_SINGLE("Mono DAC Mix R Switch", RT5677_DD2_MIXER,
+       SOC_DAPM_SINGLE_AUTODISABLE("Mono DAC Mix R Switch", RT5677_DD2_MIXER,
                        RT5677_M_MONO_R_DD2_R_SFT, 1, 1),
-       SOC_DAPM_SINGLE("DAC4 R Switch", RT5677_DD2_MIXER,
+       SOC_DAPM_SINGLE_AUTODISABLE("DAC4 R Switch", RT5677_DD2_MIXER,
                        RT5677_M_DAC4_R_DD2_R_SFT, 1, 1),
-       SOC_DAPM_SINGLE("DAC4 L Switch", RT5677_DD2_MIXER,
+       SOC_DAPM_SINGLE_AUTODISABLE("DAC4 L Switch", RT5677_DD2_MIXER,
                        RT5677_M_DAC4_L_DD2_R_SFT, 1, 1),
 };
 
@@ -2596,6 +2594,21 @@ static int rt5677_vref_event(struct snd_soc_dapm_widget *w,
        return 0;
 }
 
+static int rt5677_filter_power_event(struct snd_soc_dapm_widget *w,
+       struct snd_kcontrol *kcontrol, int event)
+{
+       switch (event) {
+       case SND_SOC_DAPM_POST_PMU:
+               msleep(50);
+               break;
+
+       default:
+               return 0;
+       }
+
+       return 0;
+}
+
 static const struct snd_soc_dapm_widget rt5677_dapm_widgets[] = {
        SND_SOC_DAPM_SUPPLY("PLL1", RT5677_PWR_ANLG2, RT5677_PWR_PLL1_BIT,
                0, rt5677_set_pll1_event, SND_SOC_DAPM_PRE_PMU |
@@ -3072,19 +3085,26 @@ static const struct snd_soc_dapm_widget rt5677_dapm_widgets[] = {
 
        /* DAC Mixer */
        SND_SOC_DAPM_SUPPLY("dac stereo1 filter", RT5677_PWR_DIG2,
-               RT5677_PWR_DAC_S1F_BIT, 0, NULL, 0),
+               RT5677_PWR_DAC_S1F_BIT, 0, rt5677_filter_power_event,
+               SND_SOC_DAPM_POST_PMU),
        SND_SOC_DAPM_SUPPLY("dac mono2 left filter", RT5677_PWR_DIG2,
-               RT5677_PWR_DAC_M2F_L_BIT, 0, NULL, 0),
+               RT5677_PWR_DAC_M2F_L_BIT, 0, rt5677_filter_power_event,
+               SND_SOC_DAPM_POST_PMU),
        SND_SOC_DAPM_SUPPLY("dac mono2 right filter", RT5677_PWR_DIG2,
-               RT5677_PWR_DAC_M2F_R_BIT, 0, NULL, 0),
+               RT5677_PWR_DAC_M2F_R_BIT, 0, rt5677_filter_power_event,
+               SND_SOC_DAPM_POST_PMU),
        SND_SOC_DAPM_SUPPLY("dac mono3 left filter", RT5677_PWR_DIG2,
-               RT5677_PWR_DAC_M3F_L_BIT, 0, NULL, 0),
+               RT5677_PWR_DAC_M3F_L_BIT, 0, rt5677_filter_power_event,
+               SND_SOC_DAPM_POST_PMU),
        SND_SOC_DAPM_SUPPLY("dac mono3 right filter", RT5677_PWR_DIG2,
-               RT5677_PWR_DAC_M3F_R_BIT, 0, NULL, 0),
+               RT5677_PWR_DAC_M3F_R_BIT, 0, rt5677_filter_power_event,
+               SND_SOC_DAPM_POST_PMU),
        SND_SOC_DAPM_SUPPLY("dac mono4 left filter", RT5677_PWR_DIG2,
-               RT5677_PWR_DAC_M4F_L_BIT, 0, NULL, 0),
+               RT5677_PWR_DAC_M4F_L_BIT, 0, rt5677_filter_power_event,
+               SND_SOC_DAPM_POST_PMU),
        SND_SOC_DAPM_SUPPLY("dac mono4 right filter", RT5677_PWR_DIG2,
-               RT5677_PWR_DAC_M4F_R_BIT, 0, NULL, 0),
+               RT5677_PWR_DAC_M4F_R_BIT, 0, rt5677_filter_power_event,
+               SND_SOC_DAPM_POST_PMU),
 
        SND_SOC_DAPM_MIXER("Stereo DAC MIXL", SND_SOC_NOPM, 0, 0,
                rt5677_sto1_dac_l_mix, ARRAY_SIZE(rt5677_sto1_dac_l_mix)),
@@ -4766,7 +4786,7 @@ static int rt5677_remove(struct snd_soc_codec *codec)
 
        regmap_write(rt5677->regmap, RT5677_RESET, 0x10ec);
        gpiod_set_value_cansleep(rt5677->pow_ldo2, 0);
-       gpiod_set_value_cansleep(rt5677->reset_pin, 0);
+       gpiod_set_value_cansleep(rt5677->reset_pin, 1);
 
        return 0;
 }
@@ -4781,7 +4801,7 @@ static int rt5677_suspend(struct snd_soc_codec *codec)
                regcache_mark_dirty(rt5677->regmap);
 
                gpiod_set_value_cansleep(rt5677->pow_ldo2, 0);
-               gpiod_set_value_cansleep(rt5677->reset_pin, 0);
+               gpiod_set_value_cansleep(rt5677->reset_pin, 1);
        }
 
        return 0;
@@ -4792,8 +4812,11 @@ static int rt5677_resume(struct snd_soc_codec *codec)
        struct rt5677_priv *rt5677 = snd_soc_codec_get_drvdata(codec);
 
        if (!rt5677->dsp_vad_en) {
+               rt5677->pll_src = 0;
+               rt5677->pll_in = 0;
+               rt5677->pll_out = 0;
                gpiod_set_value_cansleep(rt5677->pow_ldo2, 1);
-               gpiod_set_value_cansleep(rt5677->reset_pin, 1);
+               gpiod_set_value_cansleep(rt5677->reset_pin, 0);
                if (rt5677->pow_ldo2 || rt5677->reset_pin)
                        msleep(10);
 
@@ -5138,7 +5161,7 @@ static int rt5677_i2c_probe(struct i2c_client *i2c,
                return ret;
        }
        rt5677->reset_pin = devm_gpiod_get_optional(&i2c->dev,
-                       "realtek,reset", GPIOD_OUT_HIGH);
+                       "realtek,reset", GPIOD_OUT_LOW);
        if (IS_ERR(rt5677->reset_pin)) {
                ret = PTR_ERR(rt5677->reset_pin);
                dev_err(&i2c->dev, "Failed to request RESET: %d\n", ret);
index f540f82b1f271ec4833d9ea43aa7f4567c0df712..08b40460663c2f28bd450261889cd365116f0bf9 100644 (file)
@@ -189,6 +189,7 @@ static int power_vag_event(struct snd_soc_dapm_widget *w,
        case SND_SOC_DAPM_POST_PMU:
                snd_soc_update_bits(codec, SGTL5000_CHIP_ANA_POWER,
                        SGTL5000_VAG_POWERUP, SGTL5000_VAG_POWERUP);
+               msleep(400);
                break;
 
        case SND_SOC_DAPM_PRE_PMD:
index 86b81a60ac52bb4750da5981d62a210815d515c4..e2e0bfa7ec20f9df40a3e4385e3edf44e3f0d15d 100644 (file)
@@ -309,7 +309,7 @@ static const struct snd_pcm_hw_constraint_list ssm2518_constraints_12288000 = {
        .count = ARRAY_SIZE(ssm2518_rates_12288000),
 };
 
-static unsigned int ssm2518_lookup_mcs(struct ssm2518 *ssm2518,
+static int ssm2518_lookup_mcs(struct ssm2518 *ssm2518,
        unsigned int rate)
 {
        const unsigned int *sysclks = NULL;
index 4cad8929d26221f952863ed52772abebcc03fca3..bc3de2e844e68b80d8bf96dcc5c66f96d1a82669 100644 (file)
@@ -1097,8 +1097,7 @@ static int twl6040_probe(struct snd_soc_codec *codec)
 {
        struct twl6040_data *priv;
        struct twl6040 *twl6040 = dev_get_drvdata(codec->dev->parent);
-       struct platform_device *pdev = container_of(codec->dev,
-                                                  struct platform_device, dev);
+       struct platform_device *pdev = to_platform_device(codec->dev);
        int ret = 0;
 
        priv = devm_kzalloc(codec->dev, sizeof(*priv), GFP_KERNEL);
index c04c0bc6f58ad434de2bbe5825be1b41182b1c24..6088d30962a953cab19ee561ee288cca142dfccf 100644 (file)
@@ -360,15 +360,13 @@ static int wm5110_hp_ev(struct snd_soc_dapm_widget *w,
 
 static int wm5110_clear_pga_volume(struct arizona *arizona, int output)
 {
-       struct reg_sequence clear_pga = {
-               ARIZONA_OUTPUT_PATH_CONFIG_1L + output * 4, 0x80
-       };
+       unsigned int reg = ARIZONA_OUTPUT_PATH_CONFIG_1L + output * 4;
        int ret;
 
-       ret = regmap_multi_reg_write_bypassed(arizona->regmap, &clear_pga, 1);
+       ret = regmap_write(arizona->regmap, reg, 0x80);
        if (ret)
                dev_err(arizona->dev, "Failed to clear PGA (0x%x): %d\n",
-                       clear_pga.reg, ret);
+                       reg, ret);
 
        return ret;
 }
@@ -439,18 +437,17 @@ static int wm5110_in_pga_get(struct snd_kcontrol *kcontrol,
 {
        struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
        struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
-       struct snd_soc_card *card = dapm->card;
        int ret;
 
        /*
         * PGA Volume is also used as part of the enable sequence, so
         * usage of it should be avoided whilst that is running.
         */
-       mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME);
+       snd_soc_dapm_mutex_lock(dapm);
 
        ret = snd_soc_get_volsw_range(kcontrol, ucontrol);
 
-       mutex_unlock(&card->dapm_mutex);
+       snd_soc_dapm_mutex_unlock(dapm);
 
        return ret;
 }
@@ -460,18 +457,17 @@ static int wm5110_in_pga_put(struct snd_kcontrol *kcontrol,
 {
        struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
        struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
-       struct snd_soc_card *card = dapm->card;
        int ret;
 
        /*
         * PGA Volume is also used as part of the enable sequence, so
         * usage of it should be avoided whilst that is running.
         */
-       mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME);
+       snd_soc_dapm_mutex_lock(dapm);
 
        ret = snd_soc_put_volsw_range(kcontrol, ucontrol);
 
-       mutex_unlock(&card->dapm_mutex);
+       snd_soc_dapm_mutex_unlock(dapm);
 
        return ret;
 }
@@ -575,6 +571,33 @@ static DECLARE_TLV_DB_SCALE(ng_tlv, -10200, 600, 0);
        SOC_SINGLE(name " NG SPKDAT2L Switch", base, 10, 1, 0), \
        SOC_SINGLE(name " NG SPKDAT2R Switch", base, 11, 1, 0)
 
+#define WM5110_RXANC_INPUT_ROUTES(widget, name) \
+       { widget, NULL, name " NG Mux" }, \
+       { name " NG Internal", NULL, "RXANC NG Clock" }, \
+       { name " NG Internal", NULL, name " Channel" }, \
+       { name " NG External", NULL, "RXANC NG External Clock" }, \
+       { name " NG External", NULL, name " Channel" }, \
+       { name " NG Mux", "None", name " Channel" }, \
+       { name " NG Mux", "Internal", name " NG Internal" }, \
+       { name " NG Mux", "External", name " NG External" }, \
+       { name " Channel", "Left", name " Left Input" }, \
+       { name " Channel", "Combine", name " Left Input" }, \
+       { name " Channel", "Right", name " Right Input" }, \
+       { name " Channel", "Combine", name " Right Input" }, \
+       { name " Left Input", "IN1", "IN1L PGA" }, \
+       { name " Right Input", "IN1", "IN1R PGA" }, \
+       { name " Left Input", "IN2", "IN2L PGA" }, \
+       { name " Right Input", "IN2", "IN2R PGA" }, \
+       { name " Left Input", "IN3", "IN3L PGA" }, \
+       { name " Right Input", "IN3", "IN3R PGA" }, \
+       { name " Left Input", "IN4", "IN4L PGA" }, \
+       { name " Right Input", "IN4", "IN4R PGA" }
+
+#define WM5110_RXANC_OUTPUT_ROUTES(widget, name) \
+       { widget, NULL, name " ANC Source" }, \
+       { name " ANC Source", "RXANCL", "RXANCL" }, \
+       { name " ANC Source", "RXANCR", "RXANCR" }
+
 static const struct snd_kcontrol_new wm5110_snd_controls[] = {
 SOC_ENUM("IN1 OSR", arizona_in_dmic_osr[0]),
 SOC_ENUM("IN2 OSR", arizona_in_dmic_osr[1]),
@@ -639,6 +662,15 @@ SOC_SINGLE_TLV("IN4R Digital Volume", ARIZONA_ADC_DIGITAL_VOLUME_4R,
 SOC_ENUM("Input Ramp Up", arizona_in_vi_ramp),
 SOC_ENUM("Input Ramp Down", arizona_in_vd_ramp),
 
+SND_SOC_BYTES("RXANC Coefficients", ARIZONA_ANC_COEFF_START,
+             ARIZONA_ANC_COEFF_END - ARIZONA_ANC_COEFF_START + 1),
+SND_SOC_BYTES("RXANCL Config", ARIZONA_FCL_FILTER_CONTROL, 1),
+SND_SOC_BYTES("RXANCL Coefficients", ARIZONA_FCL_COEFF_START,
+             ARIZONA_FCL_COEFF_END - ARIZONA_FCL_COEFF_START + 1),
+SND_SOC_BYTES("RXANCR Config", ARIZONA_FCR_FILTER_CONTROL, 1),
+SND_SOC_BYTES("RXANCR Coefficients", ARIZONA_FCR_COEFF_START,
+             ARIZONA_FCR_COEFF_END - ARIZONA_FCR_COEFF_START + 1),
+
 ARIZONA_MIXER_CONTROLS("EQ1", ARIZONA_EQ1MIX_INPUT_1_SOURCE),
 ARIZONA_MIXER_CONTROLS("EQ2", ARIZONA_EQ2MIX_INPUT_1_SOURCE),
 ARIZONA_MIXER_CONTROLS("EQ3", ARIZONA_EQ3MIX_INPUT_1_SOURCE),
@@ -995,6 +1027,31 @@ static const struct soc_enum wm5110_aec_loopback =
 static const struct snd_kcontrol_new wm5110_aec_loopback_mux =
        SOC_DAPM_ENUM("AEC Loopback", wm5110_aec_loopback);
 
+static const struct snd_kcontrol_new wm5110_anc_input_mux[] = {
+       SOC_DAPM_ENUM("RXANCL Input", arizona_anc_input_src[0]),
+       SOC_DAPM_ENUM("RXANCL Channel", arizona_anc_input_src[1]),
+       SOC_DAPM_ENUM("RXANCR Input", arizona_anc_input_src[2]),
+       SOC_DAPM_ENUM("RXANCR Channel", arizona_anc_input_src[3]),
+};
+
+static const struct snd_kcontrol_new wm5110_anc_ng_mux =
+       SOC_DAPM_ENUM("RXANC NG Source", arizona_anc_ng_enum);
+
+static const struct snd_kcontrol_new wm5110_output_anc_src[] = {
+       SOC_DAPM_ENUM("HPOUT1L ANC Source", arizona_output_anc_src[0]),
+       SOC_DAPM_ENUM("HPOUT1R ANC Source", arizona_output_anc_src[1]),
+       SOC_DAPM_ENUM("HPOUT2L ANC Source", arizona_output_anc_src[2]),
+       SOC_DAPM_ENUM("HPOUT2R ANC Source", arizona_output_anc_src[3]),
+       SOC_DAPM_ENUM("HPOUT3L ANC Source", arizona_output_anc_src[4]),
+       SOC_DAPM_ENUM("HPOUT3R ANC Source", arizona_output_anc_src[5]),
+       SOC_DAPM_ENUM("SPKOUTL ANC Source", arizona_output_anc_src[6]),
+       SOC_DAPM_ENUM("SPKOUTR ANC Source", arizona_output_anc_src[7]),
+       SOC_DAPM_ENUM("SPKDAT1L ANC Source", arizona_output_anc_src[8]),
+       SOC_DAPM_ENUM("SPKDAT1R ANC Source", arizona_output_anc_src[9]),
+       SOC_DAPM_ENUM("SPKDAT2L ANC Source", arizona_output_anc_src[10]),
+       SOC_DAPM_ENUM("SPKDAT2R ANC Source", arizona_output_anc_src[11]),
+};
+
 static const struct snd_soc_dapm_widget wm5110_dapm_widgets[] = {
 SND_SOC_DAPM_SUPPLY("SYSCLK", ARIZONA_SYSTEM_CLOCK_1, ARIZONA_SYSCLK_ENA_SHIFT,
                    0, wm5110_sysclk_ev, SND_SOC_DAPM_POST_PMU),
@@ -1185,6 +1242,65 @@ SND_SOC_DAPM_MUX("AEC Loopback", ARIZONA_DAC_AEC_CONTROL_1,
                       ARIZONA_AEC_LOOPBACK_ENA_SHIFT, 0,
                       &wm5110_aec_loopback_mux),
 
+SND_SOC_DAPM_SUPPLY("RXANC NG External Clock", SND_SOC_NOPM,
+                  ARIZONA_EXT_NG_SEL_SET_SHIFT, 0, arizona_anc_ev,
+                  SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
+SND_SOC_DAPM_PGA("RXANCL NG External", SND_SOC_NOPM, 0, 0, NULL, 0),
+SND_SOC_DAPM_PGA("RXANCR NG External", SND_SOC_NOPM, 0, 0, NULL, 0),
+
+SND_SOC_DAPM_SUPPLY("RXANC NG Clock", SND_SOC_NOPM,
+                  ARIZONA_CLK_NG_ENA_SET_SHIFT, 0, arizona_anc_ev,
+                  SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
+SND_SOC_DAPM_PGA("RXANCL NG Internal", SND_SOC_NOPM, 0, 0, NULL, 0),
+SND_SOC_DAPM_PGA("RXANCR NG Internal", SND_SOC_NOPM, 0, 0, NULL, 0),
+
+SND_SOC_DAPM_MUX("RXANCL Left Input", SND_SOC_NOPM, 0, 0,
+                &wm5110_anc_input_mux[0]),
+SND_SOC_DAPM_MUX("RXANCL Right Input", SND_SOC_NOPM, 0, 0,
+                &wm5110_anc_input_mux[0]),
+SND_SOC_DAPM_MUX("RXANCL Channel", SND_SOC_NOPM, 0, 0,
+                &wm5110_anc_input_mux[1]),
+SND_SOC_DAPM_MUX("RXANCL NG Mux", SND_SOC_NOPM, 0, 0, &wm5110_anc_ng_mux),
+SND_SOC_DAPM_MUX("RXANCR Left Input", SND_SOC_NOPM, 0, 0,
+                &wm5110_anc_input_mux[2]),
+SND_SOC_DAPM_MUX("RXANCR Right Input", SND_SOC_NOPM, 0, 0,
+                &wm5110_anc_input_mux[2]),
+SND_SOC_DAPM_MUX("RXANCR Channel", SND_SOC_NOPM, 0, 0,
+                &wm5110_anc_input_mux[3]),
+SND_SOC_DAPM_MUX("RXANCR NG Mux", SND_SOC_NOPM, 0, 0, &wm5110_anc_ng_mux),
+
+SND_SOC_DAPM_PGA_E("RXANCL", SND_SOC_NOPM, ARIZONA_CLK_L_ENA_SET_SHIFT,
+                  0, NULL, 0, arizona_anc_ev,
+                  SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
+SND_SOC_DAPM_PGA_E("RXANCR", SND_SOC_NOPM, ARIZONA_CLK_R_ENA_SET_SHIFT,
+                  0, NULL, 0, arizona_anc_ev,
+                  SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
+
+SND_SOC_DAPM_MUX("HPOUT1L ANC Source", SND_SOC_NOPM, 0, 0,
+                &wm5110_output_anc_src[0]),
+SND_SOC_DAPM_MUX("HPOUT1R ANC Source", SND_SOC_NOPM, 0, 0,
+                &wm5110_output_anc_src[1]),
+SND_SOC_DAPM_MUX("HPOUT2L ANC Source", SND_SOC_NOPM, 0, 0,
+                &wm5110_output_anc_src[2]),
+SND_SOC_DAPM_MUX("HPOUT2R ANC Source", SND_SOC_NOPM, 0, 0,
+                &wm5110_output_anc_src[3]),
+SND_SOC_DAPM_MUX("HPOUT3L ANC Source", SND_SOC_NOPM, 0, 0,
+                &wm5110_output_anc_src[4]),
+SND_SOC_DAPM_MUX("HPOUT3R ANC Source", SND_SOC_NOPM, 0, 0,
+                &wm5110_output_anc_src[5]),
+SND_SOC_DAPM_MUX("SPKOUTL ANC Source", SND_SOC_NOPM, 0, 0,
+                &wm5110_output_anc_src[6]),
+SND_SOC_DAPM_MUX("SPKOUTR ANC Source", SND_SOC_NOPM, 0, 0,
+                &wm5110_output_anc_src[7]),
+SND_SOC_DAPM_MUX("SPKDAT1L ANC Source", SND_SOC_NOPM, 0, 0,
+                &wm5110_output_anc_src[8]),
+SND_SOC_DAPM_MUX("SPKDAT1R ANC Source", SND_SOC_NOPM, 0, 0,
+                &wm5110_output_anc_src[9]),
+SND_SOC_DAPM_MUX("SPKDAT2L ANC Source", SND_SOC_NOPM, 0, 0,
+                &wm5110_output_anc_src[10]),
+SND_SOC_DAPM_MUX("SPKDAT2R ANC Source", SND_SOC_NOPM, 0, 0,
+                &wm5110_output_anc_src[11]),
+
 SND_SOC_DAPM_AIF_OUT("AIF1TX1", NULL, 0,
                     ARIZONA_AIF1_TX_ENABLES, ARIZONA_AIF1TX1_ENA_SHIFT, 0),
 SND_SOC_DAPM_AIF_OUT("AIF1TX2", NULL, 0,
@@ -1690,6 +1806,9 @@ static const struct snd_soc_dapm_route wm5110_dapm_routes[] = {
        { "Slim2 Capture", NULL, "SYSCLK" },
        { "Slim3 Capture", NULL, "SYSCLK" },
 
+       { "Voice Control DSP", NULL, "DSP3" },
+       { "Voice Control DSP", NULL, "SYSCLK" },
+
        { "IN1L PGA", NULL, "IN1L" },
        { "IN1R PGA", NULL, "IN1R" },
 
@@ -1838,6 +1957,22 @@ static const struct snd_soc_dapm_route wm5110_dapm_routes[] = {
        { "SPKDAT2L", NULL, "OUT6L" },
        { "SPKDAT2R", NULL, "OUT6R" },
 
+       WM5110_RXANC_INPUT_ROUTES("RXANCL", "RXANCL"),
+       WM5110_RXANC_INPUT_ROUTES("RXANCR", "RXANCR"),
+
+       WM5110_RXANC_OUTPUT_ROUTES("OUT1L", "HPOUT1L"),
+       WM5110_RXANC_OUTPUT_ROUTES("OUT1R", "HPOUT1R"),
+       WM5110_RXANC_OUTPUT_ROUTES("OUT2L", "HPOUT2L"),
+       WM5110_RXANC_OUTPUT_ROUTES("OUT2R", "HPOUT2R"),
+       WM5110_RXANC_OUTPUT_ROUTES("OUT3L", "HPOUT3L"),
+       WM5110_RXANC_OUTPUT_ROUTES("OUT3R", "HPOUT3R"),
+       WM5110_RXANC_OUTPUT_ROUTES("OUT4L", "SPKOUTL"),
+       WM5110_RXANC_OUTPUT_ROUTES("OUT4R", "SPKOUTR"),
+       WM5110_RXANC_OUTPUT_ROUTES("OUT5L", "SPKDAT1L"),
+       WM5110_RXANC_OUTPUT_ROUTES("OUT5R", "SPKDAT1R"),
+       WM5110_RXANC_OUTPUT_ROUTES("OUT6L", "SPKDAT2L"),
+       WM5110_RXANC_OUTPUT_ROUTES("OUT6R", "SPKDAT2R"),
+
        { "MICSUPP", NULL, "SYSCLK" },
 
        { "DRC1 Signal Activity", NULL, "DRC1L" },
@@ -1996,12 +2131,65 @@ static struct snd_soc_dai_driver wm5110_dai[] = {
                 },
                .ops = &arizona_simple_dai_ops,
        },
+       {
+               .name = "wm5110-cpu-voicectrl",
+               .capture = {
+                       .stream_name = "Voice Control CPU",
+                       .channels_min = 1,
+                       .channels_max = 1,
+                       .rates = WM5110_RATES,
+                       .formats = WM5110_FORMATS,
+               },
+               .compress_new = snd_soc_new_compress,
+       },
+       {
+               .name = "wm5110-dsp-voicectrl",
+               .capture = {
+                       .stream_name = "Voice Control DSP",
+                       .channels_min = 1,
+                       .channels_max = 1,
+                       .rates = WM5110_RATES,
+                       .formats = WM5110_FORMATS,
+               },
+       },
 };
 
+static int wm5110_open(struct snd_compr_stream *stream)
+{
+       struct snd_soc_pcm_runtime *rtd = stream->private_data;
+       struct wm5110_priv *priv = snd_soc_codec_get_drvdata(rtd->codec);
+       struct arizona *arizona = priv->core.arizona;
+       int n_adsp;
+
+       if (strcmp(rtd->codec_dai->name, "wm5110-dsp-voicectrl") == 0) {
+               n_adsp = 2;
+       } else {
+               dev_err(arizona->dev,
+                       "No suitable compressed stream for DAI '%s'\n",
+                       rtd->codec_dai->name);
+               return -EINVAL;
+       }
+
+       return wm_adsp_compr_open(&priv->core.adsp[n_adsp], stream);
+}
+
+static irqreturn_t wm5110_adsp2_irq(int irq, void *data)
+{
+       struct wm5110_priv *florida = data;
+       int ret;
+
+       ret = wm_adsp_compr_handle_irq(&florida->core.adsp[2]);
+       if (ret == -ENODEV)
+               return IRQ_NONE;
+
+       return IRQ_HANDLED;
+}
+
 static int wm5110_codec_probe(struct snd_soc_codec *codec)
 {
        struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
        struct wm5110_priv *priv = snd_soc_codec_get_drvdata(codec);
+       struct arizona *arizona = priv->core.arizona;
        int i, ret;
 
        priv->core.arizona->dapm = dapm;
@@ -2010,6 +2198,14 @@ static int wm5110_codec_probe(struct snd_soc_codec *codec)
        arizona_init_gpio(codec);
        arizona_init_mono(codec);
 
+       ret = arizona_request_irq(arizona, ARIZONA_IRQ_DSP_IRQ1,
+                                 "ADSP2 Compressed IRQ", wm5110_adsp2_irq,
+                                 priv);
+       if (ret != 0) {
+               dev_err(codec->dev, "Failed to request DSP IRQ: %d\n", ret);
+               return ret;
+       }
+
        for (i = 0; i < WM5110_NUM_ADSP; ++i) {
                ret = wm_adsp2_codec_probe(&priv->core.adsp[i], codec);
                if (ret)
@@ -2030,12 +2226,15 @@ err_adsp2_codec_probe:
        for (--i; i >= 0; --i)
                wm_adsp2_codec_remove(&priv->core.adsp[i], codec);
 
+       arizona_free_irq(arizona, ARIZONA_IRQ_DSP_IRQ1, priv);
+
        return ret;
 }
 
 static int wm5110_codec_remove(struct snd_soc_codec *codec)
 {
        struct wm5110_priv *priv = snd_soc_codec_get_drvdata(codec);
+       struct arizona *arizona = priv->core.arizona;
        int i;
 
        for (i = 0; i < WM5110_NUM_ADSP; ++i)
@@ -2043,6 +2242,8 @@ static int wm5110_codec_remove(struct snd_soc_codec *codec)
 
        priv->core.arizona->dapm = NULL;
 
+       arizona_free_irq(arizona, ARIZONA_IRQ_DSP_IRQ1, priv);
+
        return 0;
 }
 
@@ -2088,6 +2289,20 @@ static struct snd_soc_codec_driver soc_codec_dev_wm5110 = {
        .num_dapm_routes = ARRAY_SIZE(wm5110_dapm_routes),
 };
 
+static struct snd_compr_ops wm5110_compr_ops = {
+       .open = wm5110_open,
+       .free = wm_adsp_compr_free,
+       .set_params = wm_adsp_compr_set_params,
+       .get_caps = wm_adsp_compr_get_caps,
+       .trigger = wm_adsp_compr_trigger,
+       .pointer = wm_adsp_compr_pointer,
+       .copy = wm_adsp_compr_copy,
+};
+
+static struct snd_soc_platform_driver wm5110_compr_platform = {
+       .compr_ops = &wm5110_compr_ops,
+};
+
 static int wm5110_probe(struct platform_device *pdev)
 {
        struct arizona *arizona = dev_get_drvdata(pdev->dev.parent);
@@ -2148,8 +2363,21 @@ static int wm5110_probe(struct platform_device *pdev)
        pm_runtime_enable(&pdev->dev);
        pm_runtime_idle(&pdev->dev);
 
-       return snd_soc_register_codec(&pdev->dev, &soc_codec_dev_wm5110,
+       ret = snd_soc_register_platform(&pdev->dev, &wm5110_compr_platform);
+       if (ret < 0) {
+               dev_err(&pdev->dev, "Failed to register platform: %d\n", ret);
+               goto error;
+       }
+
+       ret = snd_soc_register_codec(&pdev->dev, &soc_codec_dev_wm5110,
                                      wm5110_dai, ARRAY_SIZE(wm5110_dai));
+       if (ret < 0) {
+               dev_err(&pdev->dev, "Failed to register codec: %d\n", ret);
+               snd_soc_unregister_platform(&pdev->dev);
+       }
+
+error:
+       return ret;
 }
 
 static int wm5110_remove(struct platform_device *pdev)
index e4cc41e6c23e333cbb771d6f1da91c19c5ff6079..2ed6419c181eab5cdcd6bc4b497c6b0226296cbe 100644 (file)
@@ -1804,7 +1804,7 @@ static int wm8903_gpio_get(struct gpio_chip *chip, unsigned offset)
 
        regmap_read(wm8903->regmap, WM8903_GPIO_CONTROL_1 + offset, &reg);
 
-       return (reg & WM8903_GP1_LVL_MASK) >> WM8903_GP1_LVL_SHIFT;
+       return !!((reg & WM8903_GP1_LVL_MASK) >> WM8903_GP1_LVL_SHIFT);
 }
 
 static int wm8903_gpio_direction_out(struct gpio_chip *chip,
index 2aa23f1b9e3ca132c12e826d980b5154ffbe1478..8172e499e6ed18f33e6f94b2bec1a1647d1c1788 100644 (file)
@@ -312,7 +312,7 @@ static bool wm8904_readable_register(struct device *dev, unsigned int reg)
        case WM8904_FLL_NCO_TEST_1:
                return true;
        default:
-               return true;
+               return false;
        }
 }
 
index 056375339ea32948207723b1affd84ebdd0b1730..5380798883b5d342df4dee0ffdd54e3b474ceac6 100644 (file)
@@ -229,7 +229,7 @@ SOC_DOUBLE_R_TLV("Capture Volume", WM8960_LINVOL, WM8960_RINVOL,
 SOC_DOUBLE_R("Capture Volume ZC Switch", WM8960_LINVOL, WM8960_RINVOL,
        6, 1, 0),
 SOC_DOUBLE_R("Capture Switch", WM8960_LINVOL, WM8960_RINVOL,
-       7, 1, 0),
+       7, 1, 1),
 
 SOC_SINGLE_TLV("Right Input Boost Mixer RINPUT3 Volume",
               WM8960_INBMIX1, 4, 7, 0, lineinboost_tlv),
index 39ebd7bf4f5306382c86fb49f3417dc3c908dcad..949f632fc3f85653ee9d1a7995839dadf5aeadf7 100644 (file)
@@ -131,7 +131,7 @@ static const struct reg_default wm8962_reg[] = {
        { 15, 0x6243 },   /* R15    - Software Reset */
 
        { 17, 0x007B },   /* R17    - ALC1 */
-
+       { 18, 0x0000 },   /* R18    - ALC2 */
        { 19, 0x1C32 },   /* R19    - ALC3 */
        { 20, 0x3200 },   /* R20    - Noise Gate */
        { 21, 0x00C0 },   /* R21    - Left ADC volume */
@@ -365,8 +365,8 @@ static const struct reg_default wm8962_reg[] = {
        { 16924, 0x0059 },   /* R16924 - HDBASS_PG_1 */
        { 16925, 0x999A },   /* R16925 - HDBASS_PG_0 */
 
-       { 17048, 0x0083 },   /* R17408 - HPF_C_1 */
-       { 17049, 0x98AD },   /* R17409 - HPF_C_0 */
+       { 17408, 0x0083 },   /* R17408 - HPF_C_1 */
+       { 17409, 0x98AD },   /* R17409 - HPF_C_0 */
 
        { 17920, 0x007F },   /* R17920 - ADCL_RETUNE_C1_1 */
        { 17921, 0xFFFF },   /* R17921 - ADCL_RETUNE_C1_0 */
@@ -794,7 +794,6 @@ static bool wm8962_volatile_register(struct device *dev, unsigned int reg)
        case WM8962_CLOCKING1:
        case WM8962_CLOCKING2:
        case WM8962_SOFTWARE_RESET:
-       case WM8962_ALC2:
        case WM8962_THERMAL_SHUTDOWN_STATUS:
        case WM8962_ADDITIONAL_CONTROL_4:
        case WM8962_DC_SERVO_6:
index 0a60677397b3dedb0b9652e112137e9b3c03f3d4..c284c7b6db8bfa028846936e82a624de8c1a95af 100644 (file)
@@ -574,6 +574,7 @@ static const struct regmap_config wm8974_regmap = {
        .max_register = WM8974_MONOMIX,
        .reg_defaults = wm8974_reg_defaults,
        .num_reg_defaults = ARRAY_SIZE(wm8974_reg_defaults),
+       .cache_type = REGCACHE_FLAT,
 };
 
 static int wm8974_probe(struct snd_soc_codec *codec)
@@ -631,9 +632,16 @@ static const struct i2c_device_id wm8974_i2c_id[] = {
 };
 MODULE_DEVICE_TABLE(i2c, wm8974_i2c_id);
 
+static const struct of_device_id wm8974_of_match[] = {
+       { .compatible = "wlf,wm8974", },
+       { }
+};
+MODULE_DEVICE_TABLE(of, wm8974_of_match);
+
 static struct i2c_driver wm8974_i2c_driver = {
        .driver = {
                .name = "wm8974",
+               .of_match_table = wm8974_of_match,
        },
        .probe =    wm8974_i2c_probe,
        .remove =   wm8974_i2c_remove,
index 8782dfb628abb30619716d6f90a9b88be27bb900..7719bc509e50b182a0c63b3280154bac4de277fe 100644 (file)
@@ -199,20 +199,20 @@ static const char * const wm8998_inmux_texts[] = {
        "B",
 };
 
-static const SOC_ENUM_SINGLE_DECL(wm8998_in1muxl_enum,
-                                 ARIZONA_ADC_DIGITAL_VOLUME_1L,
-                                 ARIZONA_IN1L_SRC_SHIFT,
-                                 wm8998_inmux_texts);
+static SOC_ENUM_SINGLE_DECL(wm8998_in1muxl_enum,
+                           ARIZONA_ADC_DIGITAL_VOLUME_1L,
+                           ARIZONA_IN1L_SRC_SHIFT,
+                           wm8998_inmux_texts);
 
-static const SOC_ENUM_SINGLE_DECL(wm8998_in1muxr_enum,
-                                 ARIZONA_ADC_DIGITAL_VOLUME_1R,
-                                 ARIZONA_IN1R_SRC_SHIFT,
-                                 wm8998_inmux_texts);
+static SOC_ENUM_SINGLE_DECL(wm8998_in1muxr_enum,
+                           ARIZONA_ADC_DIGITAL_VOLUME_1R,
+                           ARIZONA_IN1R_SRC_SHIFT,
+                           wm8998_inmux_texts);
 
-static const SOC_ENUM_SINGLE_DECL(wm8998_in2mux_enum,
-                                 ARIZONA_ADC_DIGITAL_VOLUME_2L,
-                                 ARIZONA_IN2L_SRC_SHIFT,
-                                 wm8998_inmux_texts);
+static SOC_ENUM_SINGLE_DECL(wm8998_in2mux_enum,
+                           ARIZONA_ADC_DIGITAL_VOLUME_2L,
+                           ARIZONA_IN2L_SRC_SHIFT,
+                           wm8998_inmux_texts);
 
 static const struct snd_kcontrol_new wm8998_in1mux[2] = {
        SOC_DAPM_ENUM_EXT("IN1L Mux", wm8998_in1muxl_enum,
@@ -522,17 +522,17 @@ static const unsigned int wm8998_aec_loopback_values[] = {
        0, 1, 2, 3, 4, 6, 7, 8, 9,
 };
 
-static const SOC_VALUE_ENUM_SINGLE_DECL(wm8998_aec1_loopback,
-                                       ARIZONA_DAC_AEC_CONTROL_1,
-                                       ARIZONA_AEC_LOOPBACK_SRC_SHIFT, 0xf,
-                                       wm8998_aec_loopback_texts,
-                                       wm8998_aec_loopback_values);
-
-static const SOC_VALUE_ENUM_SINGLE_DECL(wm8998_aec2_loopback,
-                                       ARIZONA_DAC_AEC_CONTROL_2,
-                                       ARIZONA_AEC_LOOPBACK_SRC_SHIFT, 0xf,
-                                       wm8998_aec_loopback_texts,
-                                       wm8998_aec_loopback_values);
+static SOC_VALUE_ENUM_SINGLE_DECL(wm8998_aec1_loopback,
+                                 ARIZONA_DAC_AEC_CONTROL_1,
+                                 ARIZONA_AEC_LOOPBACK_SRC_SHIFT, 0xf,
+                                 wm8998_aec_loopback_texts,
+                                 wm8998_aec_loopback_values);
+
+static SOC_VALUE_ENUM_SINGLE_DECL(wm8998_aec2_loopback,
+                                 ARIZONA_DAC_AEC_CONTROL_2,
+                                 ARIZONA_AEC_LOOPBACK_SRC_SHIFT, 0xf,
+                                 wm8998_aec_loopback_texts,
+                                 wm8998_aec_loopback_values);
 
 static const struct snd_kcontrol_new wm8998_aec_loopback_mux[] = {
        SOC_DAPM_ENUM("AEC1 Loopback", wm8998_aec1_loopback),
index 4083a5130cbd192a37fbfd8895b47b7cce2fc46f..79e143625ac3d9c14ca72f96dc11acb6a970efdb 100644 (file)
@@ -19,6 +19,7 @@
 #include <linux/slab.h>
 #include <linux/module.h>
 #include <linux/device.h>
+#include <linux/regmap.h>
 #include <sound/core.h>
 #include <sound/pcm.h>
 #include <sound/ac97_codec.h>
@@ -39,34 +40,6 @@ struct wm9713_priv {
        struct mutex lock;
 };
 
-static unsigned int ac97_read(struct snd_soc_codec *codec,
-       unsigned int reg);
-static int ac97_write(struct snd_soc_codec *codec,
-       unsigned int reg, unsigned int val);
-
-/*
- * WM9713 register cache
- * Reg 0x3c bit 15 is used by touch driver.
- */
-static const u16 wm9713_reg[] = {
-       0x6174, 0x8080, 0x8080, 0x8080,
-       0xc880, 0xe808, 0xe808, 0x0808,
-       0x00da, 0x8000, 0xd600, 0xaaa0,
-       0xaaa0, 0xaaa0, 0x0000, 0x0000,
-       0x0f0f, 0x0040, 0x0000, 0x7f00,
-       0x0405, 0x0410, 0xbb80, 0xbb80,
-       0x0000, 0xbb80, 0x0000, 0x4523,
-       0x0000, 0x2000, 0x7eff, 0xffff,
-       0x0000, 0x0000, 0x0080, 0x0000,
-       0x0000, 0x0000, 0xfffe, 0xffff,
-       0x0000, 0x0000, 0x0000, 0xfffe,
-       0x4000, 0x0000, 0x0000, 0x0000,
-       0xb032, 0x3e00, 0x0000, 0x0000,
-       0x0000, 0x0000, 0x0000, 0x0000,
-       0x0000, 0x0000, 0x0000, 0x0006,
-       0x0001, 0x0000, 0x574d, 0x4c13,
-};
-
 #define HPL_MIXER 0
 #define HPR_MIXER 1
 
@@ -220,18 +193,15 @@ static int wm9713_voice_shutdown(struct snd_soc_dapm_widget *w,
                                 struct snd_kcontrol *kcontrol, int event)
 {
        struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
-       u16 status, rate;
 
        if (WARN_ON(event != SND_SOC_DAPM_PRE_PMD))
                return -EINVAL;
 
        /* Gracefully shut down the voice interface. */
-       status = ac97_read(codec, AC97_EXTENDED_MID) | 0x1000;
-       rate = ac97_read(codec, AC97_HANDSET_RATE) & 0xF0FF;
-       ac97_write(codec, AC97_HANDSET_RATE, rate | 0x0200);
+       snd_soc_update_bits(codec, AC97_HANDSET_RATE, 0x0f00, 0x0200);
        schedule_timeout_interruptible(msecs_to_jiffies(1));
-       ac97_write(codec, AC97_HANDSET_RATE, rate | 0x0F00);
-       ac97_write(codec, AC97_EXTENDED_MID, status);
+       snd_soc_update_bits(codec, AC97_HANDSET_RATE, 0x0f00, 0x0f00);
+       snd_soc_update_bits(codec, AC97_EXTENDED_MID, 0x1000, 0x1000);
 
        return 0;
 }
@@ -674,39 +644,97 @@ static const struct snd_soc_dapm_route wm9713_audio_map[] = {
        {"Capture Mono Mux", "Right", "Right Capture Source"},
 };
 
-static unsigned int ac97_read(struct snd_soc_codec *codec,
-       unsigned int reg)
+static bool wm9713_readable_reg(struct device *dev, unsigned int reg)
 {
-       struct wm9713_priv *wm9713 = snd_soc_codec_get_drvdata(codec);
-       u16 *cache = codec->reg_cache;
-
-       if (reg == AC97_RESET || reg == AC97_GPIO_STATUS ||
-               reg == AC97_VENDOR_ID1 || reg == AC97_VENDOR_ID2 ||
-               reg == AC97_CD)
-               return soc_ac97_ops->read(wm9713->ac97, reg);
-       else {
-               reg = reg >> 1;
-
-               if (reg >= (ARRAY_SIZE(wm9713_reg)))
-                       return -EIO;
-
-               return cache[reg];
+       switch (reg) {
+       case AC97_RESET ... AC97_PCM_SURR_DAC_RATE:
+       case AC97_PCM_LR_ADC_RATE:
+       case AC97_CENTER_LFE_MASTER:
+       case AC97_SPDIF ... AC97_LINE1_LEVEL:
+       case AC97_GPIO_CFG ... 0x5c:
+       case AC97_CODEC_CLASS_REV ... AC97_PCI_SID:
+       case 0x74 ... AC97_VENDOR_ID2:
+               return true;
+       default:
+               return false;
        }
 }
 
-static int ac97_write(struct snd_soc_codec *codec, unsigned int reg,
-       unsigned int val)
+static bool wm9713_writeable_reg(struct device *dev, unsigned int reg)
 {
-       struct wm9713_priv *wm9713 = snd_soc_codec_get_drvdata(codec);
+       switch (reg) {
+       case AC97_VENDOR_ID1:
+       case AC97_VENDOR_ID2:
+               return false;
+       default:
+               return wm9713_readable_reg(dev, reg);
+       }
+}
 
-       u16 *cache = codec->reg_cache;
-       soc_ac97_ops->write(wm9713->ac97, reg, val);
-       reg = reg >> 1;
-       if (reg < (ARRAY_SIZE(wm9713_reg)))
-               cache[reg] = val;
+static const struct reg_default wm9713_reg_defaults[] = {
+       { 0x02, 0x8080 },       /* Speaker Output Volume */
+       { 0x04, 0x8080 },       /* Headphone Output Volume */
+       { 0x06, 0x8080 },       /* Out3/OUT4 Volume */
+       { 0x08, 0xc880 },       /* Mono Volume */
+       { 0x0a, 0xe808 },       /* LINEIN Volume */
+       { 0x0c, 0xe808 },       /* DAC PGA Volume */
+       { 0x0e, 0x0808 },       /* MIC PGA Volume */
+       { 0x10, 0x00da },       /* MIC Routing Control */
+       { 0x12, 0x8000 },       /* Record PGA Volume */
+       { 0x14, 0xd600 },       /* Record Routing */
+       { 0x16, 0xaaa0 },       /* PCBEEP Volume */
+       { 0x18, 0xaaa0 },       /* VxDAC Volume */
+       { 0x1a, 0xaaa0 },       /* AUXDAC Volume */
+       { 0x1c, 0x0000 },       /* Output PGA Mux */
+       { 0x1e, 0x0000 },       /* DAC 3D control */
+       { 0x20, 0x0f0f },       /* DAC Tone Control*/
+       { 0x22, 0x0040 },       /* MIC Input Select & Bias */
+       { 0x24, 0x0000 },       /* Output Volume Mapping & Jack */
+       { 0x26, 0x7f00 },       /* Powerdown Ctrl/Stat*/
+       { 0x28, 0x0405 },       /* Extended Audio ID */
+       { 0x2a, 0x0410 },       /* Extended Audio Start/Ctrl */
+       { 0x2c, 0xbb80 },       /* Audio DACs Sample Rate */
+       { 0x2e, 0xbb80 },       /* AUXDAC Sample Rate */
+       { 0x32, 0xbb80 },       /* Audio ADCs Sample Rate */
+       { 0x36, 0x4523 },       /* PCM codec control */
+       { 0x3a, 0x2000 },       /* SPDIF control */
+       { 0x3c, 0xfdff },       /* Powerdown 1 */
+       { 0x3e, 0xffff },       /* Powerdown 2 */
+       { 0x40, 0x0000 },       /* General Purpose */
+       { 0x42, 0x0000 },       /* Fast Power-Up Control */
+       { 0x44, 0x0080 },       /* MCLK/PLL Control */
+       { 0x46, 0x0000 },       /* MCLK/PLL Control */
+       { 0x4c, 0xfffe },       /* GPIO Pin Configuration */
+       { 0x4e, 0xffff },       /* GPIO Pin Polarity / Type */
+       { 0x50, 0x0000 },       /* GPIO Pin Sticky */
+       { 0x52, 0x0000 },       /* GPIO Pin Wake-Up */
+                               /* GPIO Pin Status */
+       { 0x56, 0xfffe },       /* GPIO Pin Sharing */
+       { 0x58, 0x4000 },       /* GPIO PullUp/PullDown */
+       { 0x5a, 0x0000 },       /* Additional Functions 1 */
+       { 0x5c, 0x0000 },       /* Additional Functions 2 */
+       { 0x60, 0xb032 },       /* ALC Control */
+       { 0x62, 0x3e00 },       /* ALC / Noise Gate Control */
+       { 0x64, 0x0000 },       /* AUXDAC input control */
+       { 0x74, 0x0000 },       /* Digitiser Reg 1 */
+       { 0x76, 0x0006 },       /* Digitiser Reg 2 */
+       { 0x78, 0x0001 },       /* Digitiser Reg 3 */
+       { 0x7a, 0x0000 },       /* Digitiser Read Back */
+};
 
-       return 0;
-}
+static const struct regmap_config wm9713_regmap_config = {
+       .reg_bits = 16,
+       .reg_stride = 2,
+       .val_bits = 16,
+       .max_register = 0x7e,
+       .cache_type = REGCACHE_RBTREE,
+
+       .reg_defaults = wm9713_reg_defaults,
+       .num_reg_defaults = ARRAY_SIZE(wm9713_reg_defaults),
+       .volatile_reg = regmap_ac97_default_volatile,
+       .readable_reg = wm9713_readable_reg,
+       .writeable_reg = wm9713_writeable_reg,
+};
 
 /* PLL divisors */
 struct _pll_div {
@@ -793,10 +821,8 @@ static int wm9713_set_pll(struct snd_soc_codec *codec,
        /* turn PLL off ? */
        if (freq_in == 0) {
                /* disable PLL power and select ext source */
-               reg = ac97_read(codec, AC97_HANDSET_RATE);
-               ac97_write(codec, AC97_HANDSET_RATE, reg | 0x0080);
-               reg = ac97_read(codec, AC97_EXTENDED_MID);
-               ac97_write(codec, AC97_EXTENDED_MID, reg | 0x0200);
+               snd_soc_update_bits(codec, AC97_HANDSET_RATE, 0x0080, 0x0080);
+               snd_soc_update_bits(codec, AC97_EXTENDED_MID, 0x0200, 0x0200);
                wm9713->pll_in = 0;
                return 0;
        }
@@ -806,7 +832,7 @@ static int wm9713_set_pll(struct snd_soc_codec *codec,
        if (pll_div.k == 0) {
                reg = (pll_div.n << 12) | (pll_div.lf << 11) |
                        (pll_div.divsel << 9) | (pll_div.divctl << 8);
-               ac97_write(codec, AC97_LINE1_LEVEL, reg);
+               snd_soc_write(codec, AC97_LINE1_LEVEL, reg);
        } else {
                /* write the fractional k to the reg 0x46 pages */
                reg2 = (pll_div.n << 12) | (pll_div.lf << 11) | (1 << 10) |
@@ -814,33 +840,31 @@ static int wm9713_set_pll(struct snd_soc_codec *codec,
 
                /* K [21:20] */
                reg = reg2 | (0x5 << 4) | (pll_div.k >> 20);
-               ac97_write(codec, AC97_LINE1_LEVEL, reg);
+               snd_soc_write(codec, AC97_LINE1_LEVEL, reg);
 
                /* K [19:16] */
                reg = reg2 | (0x4 << 4) | ((pll_div.k >> 16) & 0xf);
-               ac97_write(codec, AC97_LINE1_LEVEL, reg);
+               snd_soc_write(codec, AC97_LINE1_LEVEL, reg);
 
                /* K [15:12] */
                reg = reg2 | (0x3 << 4) | ((pll_div.k >> 12) & 0xf);
-               ac97_write(codec, AC97_LINE1_LEVEL, reg);
+               snd_soc_write(codec, AC97_LINE1_LEVEL, reg);
 
                /* K [11:8] */
                reg = reg2 | (0x2 << 4) | ((pll_div.k >> 8) & 0xf);
-               ac97_write(codec, AC97_LINE1_LEVEL, reg);
+               snd_soc_write(codec, AC97_LINE1_LEVEL, reg);
 
                /* K [7:4] */
                reg = reg2 | (0x1 << 4) | ((pll_div.k >> 4) & 0xf);
-               ac97_write(codec, AC97_LINE1_LEVEL, reg);
+               snd_soc_write(codec, AC97_LINE1_LEVEL, reg);
 
                reg = reg2 | (0x0 << 4) | (pll_div.k & 0xf); /* K [3:0] */
-               ac97_write(codec, AC97_LINE1_LEVEL, reg);
+               snd_soc_write(codec, AC97_LINE1_LEVEL, reg);
        }
 
        /* turn PLL on and select as source */
-       reg = ac97_read(codec, AC97_EXTENDED_MID);
-       ac97_write(codec, AC97_EXTENDED_MID, reg & 0xfdff);
-       reg = ac97_read(codec, AC97_HANDSET_RATE);
-       ac97_write(codec, AC97_HANDSET_RATE, reg & 0xff7f);
+       snd_soc_update_bits(codec, AC97_EXTENDED_MID, 0x0200, 0x0000);
+       snd_soc_update_bits(codec, AC97_HANDSET_RATE, 0x0080, 0x0000);
        wm9713->pll_in = freq_in;
 
        /* wait 10ms AC97 link frames for the link to stabilise */
@@ -863,10 +887,10 @@ static int wm9713_set_dai_tristate(struct snd_soc_dai *codec_dai,
        int tristate)
 {
        struct snd_soc_codec *codec = codec_dai->codec;
-       u16 reg = ac97_read(codec, AC97_CENTER_LFE_MASTER) & 0x9fff;
 
        if (tristate)
-               ac97_write(codec, AC97_CENTER_LFE_MASTER, reg);
+               snd_soc_update_bits(codec, AC97_CENTER_LFE_MASTER,
+                                   0x6000, 0x0000);
 
        return 0;
 }
@@ -879,36 +903,30 @@ static int wm9713_set_dai_clkdiv(struct snd_soc_dai *codec_dai,
                int div_id, int div)
 {
        struct snd_soc_codec *codec = codec_dai->codec;
-       u16 reg;
 
        switch (div_id) {
        case WM9713_PCMCLK_DIV:
-               reg = ac97_read(codec, AC97_HANDSET_RATE) & 0xf0ff;
-               ac97_write(codec, AC97_HANDSET_RATE, reg | div);
+               snd_soc_update_bits(codec, AC97_HANDSET_RATE, 0x0f00, div);
                break;
        case WM9713_CLKA_MULT:
-               reg = ac97_read(codec, AC97_HANDSET_RATE) & 0xfffd;
-               ac97_write(codec, AC97_HANDSET_RATE, reg | div);
+               snd_soc_update_bits(codec, AC97_HANDSET_RATE, 0x0002, div);
                break;
        case WM9713_CLKB_MULT:
-               reg = ac97_read(codec, AC97_HANDSET_RATE) & 0xfffb;
-               ac97_write(codec, AC97_HANDSET_RATE, reg | div);
+               snd_soc_update_bits(codec, AC97_HANDSET_RATE, 0x0004, div);
                break;
        case WM9713_HIFI_DIV:
-               reg = ac97_read(codec, AC97_HANDSET_RATE) & 0x8fff;
-               ac97_write(codec, AC97_HANDSET_RATE, reg | div);
+               snd_soc_update_bits(codec, AC97_HANDSET_RATE, 0x7000, div);
                break;
        case WM9713_PCMBCLK_DIV:
-               reg = ac97_read(codec, AC97_CENTER_LFE_MASTER) & 0xf1ff;
-               ac97_write(codec, AC97_CENTER_LFE_MASTER, reg | div);
+               snd_soc_update_bits(codec, AC97_CENTER_LFE_MASTER, 0x0e00, div);
                break;
        case WM9713_PCMCLK_PLL_DIV:
-               reg = ac97_read(codec, AC97_LINE1_LEVEL) & 0xff80;
-               ac97_write(codec, AC97_LINE1_LEVEL, reg | 0x60 | div);
+               snd_soc_update_bits(codec, AC97_LINE1_LEVEL,
+                                   0x007f, div | 0x60);
                break;
        case WM9713_HIFI_PLL_DIV:
-               reg = ac97_read(codec, AC97_LINE1_LEVEL) & 0xff80;
-               ac97_write(codec, AC97_LINE1_LEVEL, reg | 0x70 | div);
+               snd_soc_update_bits(codec, AC97_LINE1_LEVEL,
+                                   0x007f, div | 0x70);
                break;
        default:
                return -EINVAL;
@@ -921,7 +939,7 @@ static int wm9713_set_dai_fmt(struct snd_soc_dai *codec_dai,
                unsigned int fmt)
 {
        struct snd_soc_codec *codec = codec_dai->codec;
-       u16 gpio = ac97_read(codec, AC97_GPIO_CFG) & 0xffc5;
+       u16 gpio = snd_soc_read(codec, AC97_GPIO_CFG) & 0xffc5;
        u16 reg = 0x8000;
 
        /* clock masters */
@@ -974,8 +992,8 @@ static int wm9713_set_dai_fmt(struct snd_soc_dai *codec_dai,
                break;
        }
 
-       ac97_write(codec, AC97_GPIO_CFG, gpio);
-       ac97_write(codec, AC97_CENTER_LFE_MASTER, reg);
+       snd_soc_write(codec, AC97_GPIO_CFG, gpio);
+       snd_soc_write(codec, AC97_CENTER_LFE_MASTER, reg);
        return 0;
 }
 
@@ -984,24 +1002,24 @@ static int wm9713_pcm_hw_params(struct snd_pcm_substream *substream,
                                struct snd_soc_dai *dai)
 {
        struct snd_soc_codec *codec = dai->codec;
-       u16 reg = ac97_read(codec, AC97_CENTER_LFE_MASTER) & 0xfff3;
 
+       /* enable PCM interface in master mode */
        switch (params_width(params)) {
        case 16:
                break;
        case 20:
-               reg |= 0x0004;
+               snd_soc_update_bits(codec, AC97_CENTER_LFE_MASTER,
+                                   0x000c, 0x0004);
                break;
        case 24:
-               reg |= 0x0008;
+               snd_soc_update_bits(codec, AC97_CENTER_LFE_MASTER,
+                                   0x000c, 0x0008);
                break;
        case 32:
-               reg |= 0x000c;
+               snd_soc_update_bits(codec, AC97_CENTER_LFE_MASTER,
+                                   0x000c, 0x000c);
                break;
        }
-
-       /* enable PCM interface in master mode */
-       ac97_write(codec, AC97_CENTER_LFE_MASTER, reg);
        return 0;
 }
 
@@ -1011,17 +1029,15 @@ static int ac97_hifi_prepare(struct snd_pcm_substream *substream,
        struct snd_soc_codec *codec = dai->codec;
        struct snd_pcm_runtime *runtime = substream->runtime;
        int reg;
-       u16 vra;
 
-       vra = ac97_read(codec, AC97_EXTENDED_STATUS);
-       ac97_write(codec, AC97_EXTENDED_STATUS, vra | 0x1);
+       snd_soc_update_bits(codec, AC97_EXTENDED_STATUS, 0x0001, 0x0001);
 
        if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
                reg = AC97_PCM_FRONT_DAC_RATE;
        else
                reg = AC97_PCM_LR_ADC_RATE;
 
-       return ac97_write(codec, reg, runtime->rate);
+       return snd_soc_write(codec, reg, runtime->rate);
 }
 
 static int ac97_aux_prepare(struct snd_pcm_substream *substream,
@@ -1029,17 +1045,14 @@ static int ac97_aux_prepare(struct snd_pcm_substream *substream,
 {
        struct snd_soc_codec *codec = dai->codec;
        struct snd_pcm_runtime *runtime = substream->runtime;
-       u16 vra, xsle;
 
-       vra = ac97_read(codec, AC97_EXTENDED_STATUS);
-       ac97_write(codec, AC97_EXTENDED_STATUS, vra | 0x1);
-       xsle = ac97_read(codec, AC97_PCI_SID);
-       ac97_write(codec, AC97_PCI_SID, xsle | 0x8000);
+       snd_soc_update_bits(codec, AC97_EXTENDED_STATUS, 0x0001, 0x0001);
+       snd_soc_update_bits(codec, AC97_PCI_SID, 0x8000, 0x8000);
 
        if (substream->stream != SNDRV_PCM_STREAM_PLAYBACK)
                return -ENODEV;
 
-       return ac97_write(codec, AC97_PCM_SURR_DAC_RATE, runtime->rate);
+       return snd_soc_write(codec, AC97_PCM_SURR_DAC_RATE, runtime->rate);
 }
 
 #define WM9713_RATES (SNDRV_PCM_RATE_8000  |   \
@@ -1128,27 +1141,23 @@ static struct snd_soc_dai_driver wm9713_dai[] = {
 static int wm9713_set_bias_level(struct snd_soc_codec *codec,
                                 enum snd_soc_bias_level level)
 {
-       u16 reg;
-
        switch (level) {
        case SND_SOC_BIAS_ON:
                /* enable thermal shutdown */
-               reg = ac97_read(codec, AC97_EXTENDED_MID) & 0x1bff;
-               ac97_write(codec, AC97_EXTENDED_MID, reg);
+               snd_soc_update_bits(codec, AC97_EXTENDED_MID, 0xe400, 0x0000);
                break;
        case SND_SOC_BIAS_PREPARE:
                break;
        case SND_SOC_BIAS_STANDBY:
                /* enable master bias and vmid */
-               reg = ac97_read(codec, AC97_EXTENDED_MID) & 0x3bff;
-               ac97_write(codec, AC97_EXTENDED_MID, reg);
-               ac97_write(codec, AC97_POWERDOWN, 0x0000);
+               snd_soc_update_bits(codec, AC97_EXTENDED_MID, 0xc400, 0x0000);
+               snd_soc_write(codec, AC97_POWERDOWN, 0x0000);
                break;
        case SND_SOC_BIAS_OFF:
                /* disable everything including AC link */
-               ac97_write(codec, AC97_EXTENDED_MID, 0xffff);
-               ac97_write(codec, AC97_EXTENDED_MSTATUS, 0xffff);
-               ac97_write(codec, AC97_POWERDOWN, 0xffff);
+               snd_soc_write(codec, AC97_EXTENDED_MID, 0xffff);
+               snd_soc_write(codec, AC97_EXTENDED_MSTATUS, 0xffff);
+               snd_soc_write(codec, AC97_POWERDOWN, 0xffff);
                break;
        }
        return 0;
@@ -1156,16 +1165,14 @@ static int wm9713_set_bias_level(struct snd_soc_codec *codec,
 
 static int wm9713_soc_suspend(struct snd_soc_codec *codec)
 {
-       u16 reg;
-
        /* Disable everything except touchpanel - that will be handled
         * by the touch driver and left disabled if touch is not in
         * use. */
-       reg = ac97_read(codec, AC97_EXTENDED_MID);
-       ac97_write(codec, AC97_EXTENDED_MID, reg | 0x7fff);
-       ac97_write(codec, AC97_EXTENDED_MSTATUS, 0xffff);
-       ac97_write(codec, AC97_POWERDOWN, 0x6f00);
-       ac97_write(codec, AC97_POWERDOWN, 0xffff);
+       snd_soc_update_bits(codec, AC97_EXTENDED_MID, 0x7fff,
+                                0x7fff);
+       snd_soc_write(codec, AC97_EXTENDED_MSTATUS, 0xffff);
+       snd_soc_write(codec, AC97_POWERDOWN, 0x6f00);
+       snd_soc_write(codec, AC97_POWERDOWN, 0xffff);
 
        return 0;
 }
@@ -1173,8 +1180,7 @@ static int wm9713_soc_suspend(struct snd_soc_codec *codec)
 static int wm9713_soc_resume(struct snd_soc_codec *codec)
 {
        struct wm9713_priv *wm9713 = snd_soc_codec_get_drvdata(codec);
-       int i, ret;
-       u16 *cache = codec->reg_cache;
+       int ret;
 
        ret = snd_ac97_reset(wm9713->ac97, true, WM9713_VENDOR_ID,
                WM9713_VENDOR_ID_MASK);
@@ -1189,12 +1195,8 @@ static int wm9713_soc_resume(struct snd_soc_codec *codec)
 
        /* only synchronise the codec if warm reset failed */
        if (ret == 0) {
-               for (i = 2; i < ARRAY_SIZE(wm9713_reg) << 1; i += 2) {
-                       if (i == AC97_POWERDOWN || i == AC97_EXTENDED_MID ||
-                               i == AC97_EXTENDED_MSTATUS || i > 0x66)
-                               continue;
-                       soc_ac97_ops->write(wm9713->ac97, i, cache[i>>1]);
-               }
+               regcache_mark_dirty(codec->component.regmap);
+               snd_soc_cache_sync(codec);
        }
 
        return ret;
@@ -1203,16 +1205,23 @@ static int wm9713_soc_resume(struct snd_soc_codec *codec)
 static int wm9713_soc_probe(struct snd_soc_codec *codec)
 {
        struct wm9713_priv *wm9713 = snd_soc_codec_get_drvdata(codec);
-       int reg;
+       struct regmap *regmap;
 
        wm9713->ac97 = snd_soc_new_ac97_codec(codec, WM9713_VENDOR_ID,
                WM9713_VENDOR_ID_MASK);
        if (IS_ERR(wm9713->ac97))
                return PTR_ERR(wm9713->ac97);
 
+       regmap = devm_regmap_init_ac97(wm9713->ac97, &wm9713_regmap_config);
+       if (IS_ERR(regmap)) {
+               snd_soc_free_ac97_codec(wm9713->ac97);
+               return PTR_ERR(regmap);
+       }
+
+       snd_soc_codec_init_regmap(codec, regmap);
+
        /* unmute the adc - move to kcontrol */
-       reg = ac97_read(codec, AC97_CD) & 0x7fff;
-       ac97_write(codec, AC97_CD, reg);
+       snd_soc_update_bits(codec, AC97_CD, 0x7fff, 0x0000);
 
        return 0;
 }
@@ -1221,6 +1230,7 @@ static int wm9713_soc_remove(struct snd_soc_codec *codec)
 {
        struct wm9713_priv *wm9713 = snd_soc_codec_get_drvdata(codec);
 
+       snd_soc_codec_exit_regmap(codec);
        snd_soc_free_ac97_codec(wm9713->ac97);
        return 0;
 }
@@ -1230,13 +1240,7 @@ static struct snd_soc_codec_driver soc_codec_dev_wm9713 = {
        .remove =       wm9713_soc_remove,
        .suspend =      wm9713_soc_suspend,
        .resume =       wm9713_soc_resume,
-       .read = ac97_read,
-       .write = ac97_write,
        .set_bias_level = wm9713_set_bias_level,
-       .reg_cache_size = ARRAY_SIZE(wm9713_reg),
-       .reg_word_size = sizeof(u16),
-       .reg_cache_step = 2,
-       .reg_cache_default = wm9713_reg,
 
        .controls = wm9713_snd_ac97_controls,
        .num_controls = ARRAY_SIZE(wm9713_snd_ac97_controls),
index 0bb415a287239a939dfc11adfddbe85c1f2e7f8d..33806d487b8ae00711dddd4ec400393dbff59b1f 100644 (file)
@@ -201,27 +201,194 @@ static void wm_adsp_buf_free(struct list_head *list)
        }
 }
 
-#define WM_ADSP_NUM_FW 4
-
-#define WM_ADSP_FW_MBC_VSS 0
-#define WM_ADSP_FW_TX      1
-#define WM_ADSP_FW_TX_SPK  2
-#define WM_ADSP_FW_RX_ANC  3
+#define WM_ADSP_FW_MBC_VSS  0
+#define WM_ADSP_FW_HIFI     1
+#define WM_ADSP_FW_TX       2
+#define WM_ADSP_FW_TX_SPK   3
+#define WM_ADSP_FW_RX       4
+#define WM_ADSP_FW_RX_ANC   5
+#define WM_ADSP_FW_CTRL     6
+#define WM_ADSP_FW_ASR      7
+#define WM_ADSP_FW_TRACE    8
+#define WM_ADSP_FW_SPK_PROT 9
+#define WM_ADSP_FW_MISC     10
+
+#define WM_ADSP_NUM_FW      11
 
 static const char *wm_adsp_fw_text[WM_ADSP_NUM_FW] = {
-       [WM_ADSP_FW_MBC_VSS] = "MBC/VSS",
-       [WM_ADSP_FW_TX] =      "Tx",
-       [WM_ADSP_FW_TX_SPK] =  "Tx Speaker",
-       [WM_ADSP_FW_RX_ANC] =  "Rx ANC",
+       [WM_ADSP_FW_MBC_VSS] =  "MBC/VSS",
+       [WM_ADSP_FW_HIFI] =     "MasterHiFi",
+       [WM_ADSP_FW_TX] =       "Tx",
+       [WM_ADSP_FW_TX_SPK] =   "Tx Speaker",
+       [WM_ADSP_FW_RX] =       "Rx",
+       [WM_ADSP_FW_RX_ANC] =   "Rx ANC",
+       [WM_ADSP_FW_CTRL] =     "Voice Ctrl",
+       [WM_ADSP_FW_ASR] =      "ASR Assist",
+       [WM_ADSP_FW_TRACE] =    "Dbg Trace",
+       [WM_ADSP_FW_SPK_PROT] = "Protection",
+       [WM_ADSP_FW_MISC] =     "Misc",
+};
+
+struct wm_adsp_system_config_xm_hdr {
+       __be32 sys_enable;
+       __be32 fw_id;
+       __be32 fw_rev;
+       __be32 boot_status;
+       __be32 watchdog;
+       __be32 dma_buffer_size;
+       __be32 rdma[6];
+       __be32 wdma[8];
+       __be32 build_job_name[3];
+       __be32 build_job_number;
+};
+
+struct wm_adsp_alg_xm_struct {
+       __be32 magic;
+       __be32 smoothing;
+       __be32 threshold;
+       __be32 host_buf_ptr;
+       __be32 start_seq;
+       __be32 high_water_mark;
+       __be32 low_water_mark;
+       __be64 smoothed_power;
+};
+
+struct wm_adsp_buffer {
+       __be32 X_buf_base;              /* XM base addr of first X area */
+       __be32 X_buf_size;              /* Size of 1st X area in words */
+       __be32 X_buf_base2;             /* XM base addr of 2nd X area */
+       __be32 X_buf_brk;               /* Total X size in words */
+       __be32 Y_buf_base;              /* YM base addr of Y area */
+       __be32 wrap;                    /* Total size X and Y in words */
+       __be32 high_water_mark;         /* Point at which IRQ is asserted */
+       __be32 irq_count;               /* bits 1-31 count IRQ assertions */
+       __be32 irq_ack;                 /* acked IRQ count, bit 0 enables IRQ */
+       __be32 next_write_index;        /* word index of next write */
+       __be32 next_read_index;         /* word index of next read */
+       __be32 error;                   /* error if any */
+       __be32 oldest_block_index;      /* word index of oldest surviving */
+       __be32 requested_rewind;        /* how many blocks rewind was done */
+       __be32 reserved_space;          /* internal */
+       __be32 min_free;                /* min free space since stream start */
+       __be32 blocks_written[2];       /* total blocks written (64 bit) */
+       __be32 words_written[2];        /* total words written (64 bit) */
+};
+
+struct wm_adsp_compr_buf {
+       struct wm_adsp *dsp;
+
+       struct wm_adsp_buffer_region *regions;
+       u32 host_buf_ptr;
+
+       u32 error;
+       u32 irq_count;
+       int read_index;
+       int avail;
+};
+
+struct wm_adsp_compr {
+       struct wm_adsp *dsp;
+       struct wm_adsp_compr_buf *buf;
+
+       struct snd_compr_stream *stream;
+       struct snd_compressed_buffer size;
+
+       u32 *raw_buf;
+       unsigned int copied_total;
+};
+
+#define WM_ADSP_DATA_WORD_SIZE         3
+
+#define WM_ADSP_MIN_FRAGMENTS          1
+#define WM_ADSP_MAX_FRAGMENTS          256
+#define WM_ADSP_MIN_FRAGMENT_SIZE      (64 * WM_ADSP_DATA_WORD_SIZE)
+#define WM_ADSP_MAX_FRAGMENT_SIZE      (4096 * WM_ADSP_DATA_WORD_SIZE)
+
+#define WM_ADSP_ALG_XM_STRUCT_MAGIC    0x49aec7
+
+#define HOST_BUFFER_FIELD(field) \
+       (offsetof(struct wm_adsp_buffer, field) / sizeof(__be32))
+
+#define ALG_XM_FIELD(field) \
+       (offsetof(struct wm_adsp_alg_xm_struct, field) / sizeof(__be32))
+
+static int wm_adsp_buffer_init(struct wm_adsp *dsp);
+static int wm_adsp_buffer_free(struct wm_adsp *dsp);
+
+struct wm_adsp_buffer_region {
+       unsigned int offset;
+       unsigned int cumulative_size;
+       unsigned int mem_type;
+       unsigned int base_addr;
+};
+
+struct wm_adsp_buffer_region_def {
+       unsigned int mem_type;
+       unsigned int base_offset;
+       unsigned int size_offset;
 };
 
-static struct {
+static struct wm_adsp_buffer_region_def ez2control_regions[] = {
+       {
+               .mem_type = WMFW_ADSP2_XM,
+               .base_offset = HOST_BUFFER_FIELD(X_buf_base),
+               .size_offset = HOST_BUFFER_FIELD(X_buf_size),
+       },
+       {
+               .mem_type = WMFW_ADSP2_XM,
+               .base_offset = HOST_BUFFER_FIELD(X_buf_base2),
+               .size_offset = HOST_BUFFER_FIELD(X_buf_brk),
+       },
+       {
+               .mem_type = WMFW_ADSP2_YM,
+               .base_offset = HOST_BUFFER_FIELD(Y_buf_base),
+               .size_offset = HOST_BUFFER_FIELD(wrap),
+       },
+};
+
+struct wm_adsp_fw_caps {
+       u32 id;
+       struct snd_codec_desc desc;
+       int num_regions;
+       struct wm_adsp_buffer_region_def *region_defs;
+};
+
+static const struct wm_adsp_fw_caps ez2control_caps[] = {
+       {
+               .id = SND_AUDIOCODEC_BESPOKE,
+               .desc = {
+                       .max_ch = 1,
+                       .sample_rates = { 16000 },
+                       .num_sample_rates = 1,
+                       .formats = SNDRV_PCM_FMTBIT_S16_LE,
+               },
+               .num_regions = ARRAY_SIZE(ez2control_regions),
+               .region_defs = ez2control_regions,
+       },
+};
+
+static const struct {
        const char *file;
+       int compr_direction;
+       int num_caps;
+       const struct wm_adsp_fw_caps *caps;
 } wm_adsp_fw[WM_ADSP_NUM_FW] = {
-       [WM_ADSP_FW_MBC_VSS] = { .file = "mbc-vss" },
-       [WM_ADSP_FW_TX] =      { .file = "tx" },
-       [WM_ADSP_FW_TX_SPK] =  { .file = "tx-spk" },
-       [WM_ADSP_FW_RX_ANC] =  { .file = "rx-anc" },
+       [WM_ADSP_FW_MBC_VSS] =  { .file = "mbc-vss" },
+       [WM_ADSP_FW_HIFI] =     { .file = "hifi" },
+       [WM_ADSP_FW_TX] =       { .file = "tx" },
+       [WM_ADSP_FW_TX_SPK] =   { .file = "tx-spk" },
+       [WM_ADSP_FW_RX] =       { .file = "rx" },
+       [WM_ADSP_FW_RX_ANC] =   { .file = "rx-anc" },
+       [WM_ADSP_FW_CTRL] =     {
+               .file = "ctrl",
+               .compr_direction = SND_COMPRESS_CAPTURE,
+               .num_caps = ARRAY_SIZE(ez2control_caps),
+               .caps = ez2control_caps,
+       },
+       [WM_ADSP_FW_ASR] =      { .file = "asr" },
+       [WM_ADSP_FW_TRACE] =    { .file = "trace" },
+       [WM_ADSP_FW_SPK_PROT] = { .file = "spk-prot" },
+       [WM_ADSP_FW_MISC] =     { .file = "misc" },
 };
 
 struct wm_coeff_ctl_ops {
@@ -254,30 +421,24 @@ static void wm_adsp_debugfs_save_wmfwname(struct wm_adsp *dsp, const char *s)
 {
        char *tmp = kasprintf(GFP_KERNEL, "%s\n", s);
 
-       mutex_lock(&dsp->debugfs_lock);
        kfree(dsp->wmfw_file_name);
        dsp->wmfw_file_name = tmp;
-       mutex_unlock(&dsp->debugfs_lock);
 }
 
 static void wm_adsp_debugfs_save_binname(struct wm_adsp *dsp, const char *s)
 {
        char *tmp = kasprintf(GFP_KERNEL, "%s\n", s);
 
-       mutex_lock(&dsp->debugfs_lock);
        kfree(dsp->bin_file_name);
        dsp->bin_file_name = tmp;
-       mutex_unlock(&dsp->debugfs_lock);
 }
 
 static void wm_adsp_debugfs_clear(struct wm_adsp *dsp)
 {
-       mutex_lock(&dsp->debugfs_lock);
        kfree(dsp->wmfw_file_name);
        kfree(dsp->bin_file_name);
        dsp->wmfw_file_name = NULL;
        dsp->bin_file_name = NULL;
-       mutex_unlock(&dsp->debugfs_lock);
 }
 
 static ssize_t wm_adsp_debugfs_wmfw_read(struct file *file,
@@ -287,7 +448,7 @@ static ssize_t wm_adsp_debugfs_wmfw_read(struct file *file,
        struct wm_adsp *dsp = file->private_data;
        ssize_t ret;
 
-       mutex_lock(&dsp->debugfs_lock);
+       mutex_lock(&dsp->pwr_lock);
 
        if (!dsp->wmfw_file_name || !dsp->running)
                ret = 0;
@@ -296,7 +457,7 @@ static ssize_t wm_adsp_debugfs_wmfw_read(struct file *file,
                                              dsp->wmfw_file_name,
                                              strlen(dsp->wmfw_file_name));
 
-       mutex_unlock(&dsp->debugfs_lock);
+       mutex_unlock(&dsp->pwr_lock);
        return ret;
 }
 
@@ -307,7 +468,7 @@ static ssize_t wm_adsp_debugfs_bin_read(struct file *file,
        struct wm_adsp *dsp = file->private_data;
        ssize_t ret;
 
-       mutex_lock(&dsp->debugfs_lock);
+       mutex_lock(&dsp->pwr_lock);
 
        if (!dsp->bin_file_name || !dsp->running)
                ret = 0;
@@ -316,7 +477,7 @@ static ssize_t wm_adsp_debugfs_bin_read(struct file *file,
                                              dsp->bin_file_name,
                                              strlen(dsp->bin_file_name));
 
-       mutex_unlock(&dsp->debugfs_lock);
+       mutex_unlock(&dsp->pwr_lock);
        return ret;
 }
 
@@ -436,6 +597,7 @@ static int wm_adsp_fw_put(struct snd_kcontrol *kcontrol,
        struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
        struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
        struct wm_adsp *dsp = snd_soc_codec_get_drvdata(codec);
+       int ret = 0;
 
        if (ucontrol->value.integer.value[0] == dsp[e->shift_l].fw)
                return 0;
@@ -443,12 +605,16 @@ static int wm_adsp_fw_put(struct snd_kcontrol *kcontrol,
        if (ucontrol->value.integer.value[0] >= WM_ADSP_NUM_FW)
                return -EINVAL;
 
-       if (dsp[e->shift_l].running)
-               return -EBUSY;
+       mutex_lock(&dsp[e->shift_l].pwr_lock);
 
-       dsp[e->shift_l].fw = ucontrol->value.integer.value[0];
+       if (dsp[e->shift_l].running || dsp[e->shift_l].compr)
+               ret = -EBUSY;
+       else
+               dsp[e->shift_l].fw = ucontrol->value.integer.value[0];
 
-       return 0;
+       mutex_unlock(&dsp[e->shift_l].pwr_lock);
+
+       return ret;
 }
 
 static const struct soc_enum wm_adsp_fw_enum[] = {
@@ -523,10 +689,10 @@ static void wm_adsp2_show_fw_status(struct wm_adsp *dsp)
                 be16_to_cpu(scratch[3]));
 }
 
-static int wm_coeff_info(struct snd_kcontrol *kcontrol,
+static int wm_coeff_info(struct snd_kcontrol *kctl,
                         struct snd_ctl_elem_info *uinfo)
 {
-       struct wm_coeff_ctl *ctl = (struct wm_coeff_ctl *)kcontrol->private_value;
+       struct wm_coeff_ctl *ctl = (struct wm_coeff_ctl *)kctl->private_value;
 
        uinfo->type = SNDRV_CTL_ELEM_TYPE_BYTES;
        uinfo->count = ctl->len;
@@ -572,19 +738,24 @@ static int wm_coeff_write_control(struct wm_coeff_ctl *ctl,
        return 0;
 }
 
-static int wm_coeff_put(struct snd_kcontrol *kcontrol,
+static int wm_coeff_put(struct snd_kcontrol *kctl,
                        struct snd_ctl_elem_value *ucontrol)
 {
-       struct wm_coeff_ctl *ctl = (struct wm_coeff_ctl *)kcontrol->private_value;
+       struct wm_coeff_ctl *ctl = (struct wm_coeff_ctl *)kctl->private_value;
        char *p = ucontrol->value.bytes.data;
+       int ret = 0;
+
+       mutex_lock(&ctl->dsp->pwr_lock);
 
        memcpy(ctl->cache, p, ctl->len);
 
        ctl->set = 1;
-       if (!ctl->enabled)
-               return 0;
+       if (ctl->enabled)
+               ret = wm_coeff_write_control(ctl, p, ctl->len);
+
+       mutex_unlock(&ctl->dsp->pwr_lock);
 
-       return wm_coeff_write_control(ctl, p, ctl->len);
+       return ret;
 }
 
 static int wm_coeff_read_control(struct wm_coeff_ctl *ctl,
@@ -626,22 +797,30 @@ static int wm_coeff_read_control(struct wm_coeff_ctl *ctl,
        return 0;
 }
 
-static int wm_coeff_get(struct snd_kcontrol *kcontrol,
+static int wm_coeff_get(struct snd_kcontrol *kctl,
                        struct snd_ctl_elem_value *ucontrol)
 {
-       struct wm_coeff_ctl *ctl = (struct wm_coeff_ctl *)kcontrol->private_value;
+       struct wm_coeff_ctl *ctl = (struct wm_coeff_ctl *)kctl->private_value;
        char *p = ucontrol->value.bytes.data;
+       int ret = 0;
+
+       mutex_lock(&ctl->dsp->pwr_lock);
 
        if (ctl->flags & WMFW_CTL_FLAG_VOLATILE) {
                if (ctl->enabled)
-                       return wm_coeff_read_control(ctl, p, ctl->len);
+                       ret = wm_coeff_read_control(ctl, p, ctl->len);
                else
-                       return -EPERM;
+                       ret = -EPERM;
+       } else {
+               if (!ctl->flags && ctl->enabled)
+                       ret = wm_coeff_read_control(ctl, ctl->cache, ctl->len);
+
+               memcpy(p, ctl->cache, ctl->len);
        }
 
-       memcpy(p, ctl->cache, ctl->len);
+       mutex_unlock(&ctl->dsp->pwr_lock);
 
-       return 0;
+       return ret;
 }
 
 struct wmfw_ctl_work {
@@ -808,8 +987,7 @@ static int wm_adsp_create_control(struct wm_adsp *dsp,
                break;
        }
 
-       list_for_each_entry(ctl, &dsp->ctl_list,
-                           list) {
+       list_for_each_entry(ctl, &dsp->ctl_list, list) {
                if (!strcmp(ctl->name, name)) {
                        if (!ctl->enabled)
                                ctl->enabled = 1;
@@ -1088,7 +1266,7 @@ static int wm_adsp_load(struct wm_adsp *dsp)
                goto out_fw;
        }
 
-       header = (void*)&firmware->data[0];
+       header = (void *)&firmware->data[0];
 
        if (memcmp(&header->magic[0], "WMFW", 4) != 0) {
                adsp_err(dsp, "%s: invalid magic\n", file);
@@ -1168,7 +1346,7 @@ static int wm_adsp_load(struct wm_adsp *dsp)
                offset = le32_to_cpu(region->offset) & 0xffffff;
                type = be32_to_cpu(region->type) & 0xff;
                mem = wm_adsp_find_region(dsp, type);
-               
+
                switch (type) {
                case WMFW_NAME_TEXT:
                        region_name = "Firmware name";
@@ -1333,6 +1511,19 @@ static void *wm_adsp_read_algs(struct wm_adsp *dsp, size_t n_algs,
        return alg;
 }
 
+static struct wm_adsp_alg_region *
+       wm_adsp_find_alg_region(struct wm_adsp *dsp, int type, unsigned int id)
+{
+       struct wm_adsp_alg_region *alg_region;
+
+       list_for_each_entry(alg_region, &dsp->alg_regions, list) {
+               if (id == alg_region->alg && type == alg_region->type)
+                       return alg_region;
+       }
+
+       return NULL;
+}
+
 static struct wm_adsp_alg_region *wm_adsp_create_region(struct wm_adsp *dsp,
                                                        int type, __be32 id,
                                                        __be32 base)
@@ -1625,7 +1816,7 @@ static int wm_adsp_load_coeff(struct wm_adsp *dsp)
                goto out_fw;
        }
 
-       hdr = (void*)&firmware->data[0];
+       hdr = (void *)&firmware->data[0];
        if (memcmp(hdr->magic, "WMDR", 4) != 0) {
                adsp_err(dsp, "%s: invalid magic\n", file);
                goto out_fw;
@@ -1651,7 +1842,7 @@ static int wm_adsp_load_coeff(struct wm_adsp *dsp)
        blocks = 0;
        while (pos < firmware->size &&
               pos - firmware->size > sizeof(*blk)) {
-               blk = (void*)(&firmware->data[pos]);
+               blk = (void *)(&firmware->data[pos]);
 
                type = le16_to_cpu(blk->type);
                offset = le16_to_cpu(blk->offset);
@@ -1705,22 +1896,16 @@ static int wm_adsp_load_coeff(struct wm_adsp *dsp)
                                break;
                        }
 
-                       reg = 0;
-                       list_for_each_entry(alg_region,
-                                           &dsp->alg_regions, list) {
-                               if (le32_to_cpu(blk->id) == alg_region->alg &&
-                                   type == alg_region->type) {
-                                       reg = alg_region->base;
-                                       reg = wm_adsp_region_to_reg(mem,
-                                                                   reg);
-                                       reg += offset;
-                                       break;
-                               }
-                       }
-
-                       if (reg == 0)
+                       alg_region = wm_adsp_find_alg_region(dsp, type,
+                                               le32_to_cpu(blk->id));
+                       if (alg_region) {
+                               reg = alg_region->base;
+                               reg = wm_adsp_region_to_reg(mem, reg);
+                               reg += offset;
+                       } else {
                                adsp_err(dsp, "No %x for algorithm %x\n",
                                         type, le32_to_cpu(blk->id));
+                       }
                        break;
 
                default:
@@ -1778,9 +1963,8 @@ int wm_adsp1_init(struct wm_adsp *dsp)
 {
        INIT_LIST_HEAD(&dsp->alg_regions);
 
-#ifdef CONFIG_DEBUG_FS
-       mutex_init(&dsp->debugfs_lock);
-#endif
+       mutex_init(&dsp->pwr_lock);
+
        return 0;
 }
 EXPORT_SYMBOL_GPL(wm_adsp1_init);
@@ -1795,10 +1979,12 @@ int wm_adsp1_event(struct snd_soc_dapm_widget *w,
        struct wm_adsp_alg_region *alg_region;
        struct wm_coeff_ctl *ctl;
        int ret;
-       int val;
+       unsigned int val;
 
        dsp->card = codec->component.card;
 
+       mutex_lock(&dsp->pwr_lock);
+
        switch (event) {
        case SND_SOC_DAPM_POST_PMU:
                regmap_update_bits(dsp->regmap, dsp->base + ADSP1_CONTROL_30,
@@ -1808,12 +1994,12 @@ int wm_adsp1_event(struct snd_soc_dapm_widget *w,
                 * For simplicity set the DSP clock rate to be the
                 * SYSCLK rate rather than making it configurable.
                 */
-               if(dsp->sysclk_reg) {
+               if (dsp->sysclk_reg) {
                        ret = regmap_read(dsp->regmap, dsp->sysclk_reg, &val);
                        if (ret != 0) {
                                adsp_err(dsp, "Failed to read SYSCLK state: %d\n",
                                ret);
-                               return ret;
+                               goto err_mutex;
                        }
 
                        val = (val & dsp->sysclk_mask)
@@ -1825,31 +2011,31 @@ int wm_adsp1_event(struct snd_soc_dapm_widget *w,
                        if (ret != 0) {
                                adsp_err(dsp, "Failed to set clock rate: %d\n",
                                         ret);
-                               return ret;
+                               goto err_mutex;
                        }
                }
 
                ret = wm_adsp_load(dsp);
                if (ret != 0)
-                       goto err;
+                       goto err_ena;
 
                ret = wm_adsp1_setup_algs(dsp);
                if (ret != 0)
-                       goto err;
+                       goto err_ena;
 
                ret = wm_adsp_load_coeff(dsp);
                if (ret != 0)
-                       goto err;
+                       goto err_ena;
 
                /* Initialize caches for enabled and unset controls */
                ret = wm_coeff_init_control_caches(dsp);
                if (ret != 0)
-                       goto err;
+                       goto err_ena;
 
                /* Sync set controls */
                ret = wm_coeff_sync_controls(dsp);
                if (ret != 0)
-                       goto err;
+                       goto err_ena;
 
                /* Start the core running */
                regmap_update_bits(dsp->regmap, dsp->base + ADSP1_CONTROL_30,
@@ -1884,11 +2070,16 @@ int wm_adsp1_event(struct snd_soc_dapm_widget *w,
                break;
        }
 
+       mutex_unlock(&dsp->pwr_lock);
+
        return 0;
 
-err:
+err_ena:
        regmap_update_bits(dsp->regmap, dsp->base + ADSP1_CONTROL_30,
                           ADSP1_SYS_ENA, 0);
+err_mutex:
+       mutex_unlock(&dsp->pwr_lock);
+
        return ret;
 }
 EXPORT_SYMBOL_GPL(wm_adsp1_event);
@@ -1934,6 +2125,8 @@ static void wm_adsp2_boot_work(struct work_struct *work)
        int ret;
        unsigned int val;
 
+       mutex_lock(&dsp->pwr_lock);
+
        /*
         * For simplicity set the DSP clock rate to be the
         * SYSCLK rate rather than making it configurable.
@@ -1941,7 +2134,7 @@ static void wm_adsp2_boot_work(struct work_struct *work)
        ret = regmap_read(dsp->regmap, ARIZONA_SYSTEM_CLOCK_1, &val);
        if (ret != 0) {
                adsp_err(dsp, "Failed to read SYSCLK state: %d\n", ret);
-               return;
+               goto err_mutex;
        }
        val = (val & ARIZONA_SYSCLK_FREQ_MASK)
                >> ARIZONA_SYSCLK_FREQ_SHIFT;
@@ -1951,42 +2144,46 @@ static void wm_adsp2_boot_work(struct work_struct *work)
                                       ADSP2_CLK_SEL_MASK, val);
        if (ret != 0) {
                adsp_err(dsp, "Failed to set clock rate: %d\n", ret);
-               return;
+               goto err_mutex;
        }
 
        ret = wm_adsp2_ena(dsp);
        if (ret != 0)
-               return;
+               goto err_mutex;
 
        ret = wm_adsp_load(dsp);
        if (ret != 0)
-               goto err;
+               goto err_ena;
 
        ret = wm_adsp2_setup_algs(dsp);
        if (ret != 0)
-               goto err;
+               goto err_ena;
 
        ret = wm_adsp_load_coeff(dsp);
        if (ret != 0)
-               goto err;
+               goto err_ena;
 
        /* Initialize caches for enabled and unset controls */
        ret = wm_coeff_init_control_caches(dsp);
        if (ret != 0)
-               goto err;
+               goto err_ena;
 
        /* Sync set controls */
        ret = wm_coeff_sync_controls(dsp);
        if (ret != 0)
-               goto err;
+               goto err_ena;
 
        dsp->running = true;
 
+       mutex_unlock(&dsp->pwr_lock);
+
        return;
 
-err:
+err_ena:
        regmap_update_bits(dsp->regmap, dsp->base + ADSP2_CONTROL,
                           ADSP2_SYS_ENA | ADSP2_CORE_ENA | ADSP2_START, 0);
+err_mutex:
+       mutex_unlock(&dsp->pwr_lock);
 }
 
 int wm_adsp2_early_event(struct snd_soc_dapm_widget *w,
@@ -2033,12 +2230,18 @@ int wm_adsp2_event(struct snd_soc_dapm_widget *w,
                                         ADSP2_CORE_ENA | ADSP2_START);
                if (ret != 0)
                        goto err;
+
+               if (wm_adsp_fw[dsp->fw].num_caps != 0)
+                       ret = wm_adsp_buffer_init(dsp);
+
                break;
 
        case SND_SOC_DAPM_PRE_PMD:
                /* Log firmware state, it can be useful for analysis */
                wm_adsp2_show_fw_status(dsp);
 
+               mutex_lock(&dsp->pwr_lock);
+
                wm_adsp_debugfs_clear(dsp);
 
                dsp->fw_id = 0;
@@ -2065,6 +2268,11 @@ int wm_adsp2_event(struct snd_soc_dapm_widget *w,
                        kfree(alg_region);
                }
 
+               if (wm_adsp_fw[dsp->fw].num_caps != 0)
+                       wm_adsp_buffer_free(dsp);
+
+               mutex_unlock(&dsp->pwr_lock);
+
                adsp_dbg(dsp, "Shutdown complete\n");
                break;
 
@@ -2117,11 +2325,724 @@ int wm_adsp2_init(struct wm_adsp *dsp)
        INIT_LIST_HEAD(&dsp->ctl_list);
        INIT_WORK(&dsp->boot_work, wm_adsp2_boot_work);
 
-#ifdef CONFIG_DEBUG_FS
-       mutex_init(&dsp->debugfs_lock);
-#endif
+       mutex_init(&dsp->pwr_lock);
+
        return 0;
 }
 EXPORT_SYMBOL_GPL(wm_adsp2_init);
 
+int wm_adsp_compr_open(struct wm_adsp *dsp, struct snd_compr_stream *stream)
+{
+       struct wm_adsp_compr *compr;
+       int ret = 0;
+
+       mutex_lock(&dsp->pwr_lock);
+
+       if (wm_adsp_fw[dsp->fw].num_caps == 0) {
+               adsp_err(dsp, "Firmware does not support compressed API\n");
+               ret = -ENXIO;
+               goto out;
+       }
+
+       if (wm_adsp_fw[dsp->fw].compr_direction != stream->direction) {
+               adsp_err(dsp, "Firmware does not support stream direction\n");
+               ret = -EINVAL;
+               goto out;
+       }
+
+       if (dsp->compr) {
+               /* It is expect this limitation will be removed in future */
+               adsp_err(dsp, "Only a single stream supported per DSP\n");
+               ret = -EBUSY;
+               goto out;
+       }
+
+       compr = kzalloc(sizeof(*compr), GFP_KERNEL);
+       if (!compr) {
+               ret = -ENOMEM;
+               goto out;
+       }
+
+       compr->dsp = dsp;
+       compr->stream = stream;
+
+       dsp->compr = compr;
+
+       stream->runtime->private_data = compr;
+
+out:
+       mutex_unlock(&dsp->pwr_lock);
+
+       return ret;
+}
+EXPORT_SYMBOL_GPL(wm_adsp_compr_open);
+
+int wm_adsp_compr_free(struct snd_compr_stream *stream)
+{
+       struct wm_adsp_compr *compr = stream->runtime->private_data;
+       struct wm_adsp *dsp = compr->dsp;
+
+       mutex_lock(&dsp->pwr_lock);
+
+       dsp->compr = NULL;
+
+       kfree(compr->raw_buf);
+       kfree(compr);
+
+       mutex_unlock(&dsp->pwr_lock);
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(wm_adsp_compr_free);
+
+static int wm_adsp_compr_check_params(struct snd_compr_stream *stream,
+                                     struct snd_compr_params *params)
+{
+       struct wm_adsp_compr *compr = stream->runtime->private_data;
+       struct wm_adsp *dsp = compr->dsp;
+       const struct wm_adsp_fw_caps *caps;
+       const struct snd_codec_desc *desc;
+       int i, j;
+
+       if (params->buffer.fragment_size < WM_ADSP_MIN_FRAGMENT_SIZE ||
+           params->buffer.fragment_size > WM_ADSP_MAX_FRAGMENT_SIZE ||
+           params->buffer.fragments < WM_ADSP_MIN_FRAGMENTS ||
+           params->buffer.fragments > WM_ADSP_MAX_FRAGMENTS ||
+           params->buffer.fragment_size % WM_ADSP_DATA_WORD_SIZE) {
+               adsp_err(dsp, "Invalid buffer fragsize=%d fragments=%d\n",
+                        params->buffer.fragment_size,
+                        params->buffer.fragments);
+
+               return -EINVAL;
+       }
+
+       for (i = 0; i < wm_adsp_fw[dsp->fw].num_caps; i++) {
+               caps = &wm_adsp_fw[dsp->fw].caps[i];
+               desc = &caps->desc;
+
+               if (caps->id != params->codec.id)
+                       continue;
+
+               if (stream->direction == SND_COMPRESS_PLAYBACK) {
+                       if (desc->max_ch < params->codec.ch_out)
+                               continue;
+               } else {
+                       if (desc->max_ch < params->codec.ch_in)
+                               continue;
+               }
+
+               if (!(desc->formats & (1 << params->codec.format)))
+                       continue;
+
+               for (j = 0; j < desc->num_sample_rates; ++j)
+                       if (desc->sample_rates[j] == params->codec.sample_rate)
+                               return 0;
+       }
+
+       adsp_err(dsp, "Invalid params id=%u ch=%u,%u rate=%u fmt=%u\n",
+                params->codec.id, params->codec.ch_in, params->codec.ch_out,
+                params->codec.sample_rate, params->codec.format);
+       return -EINVAL;
+}
+
+static inline unsigned int wm_adsp_compr_frag_words(struct wm_adsp_compr *compr)
+{
+       return compr->size.fragment_size / WM_ADSP_DATA_WORD_SIZE;
+}
+
+int wm_adsp_compr_set_params(struct snd_compr_stream *stream,
+                            struct snd_compr_params *params)
+{
+       struct wm_adsp_compr *compr = stream->runtime->private_data;
+       unsigned int size;
+       int ret;
+
+       ret = wm_adsp_compr_check_params(stream, params);
+       if (ret)
+               return ret;
+
+       compr->size = params->buffer;
+
+       adsp_dbg(compr->dsp, "fragment_size=%d fragments=%d\n",
+                compr->size.fragment_size, compr->size.fragments);
+
+       size = wm_adsp_compr_frag_words(compr) * sizeof(*compr->raw_buf);
+       compr->raw_buf = kmalloc(size, GFP_DMA | GFP_KERNEL);
+       if (!compr->raw_buf)
+               return -ENOMEM;
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(wm_adsp_compr_set_params);
+
+int wm_adsp_compr_get_caps(struct snd_compr_stream *stream,
+                          struct snd_compr_caps *caps)
+{
+       struct wm_adsp_compr *compr = stream->runtime->private_data;
+       int fw = compr->dsp->fw;
+       int i;
+
+       if (wm_adsp_fw[fw].caps) {
+               for (i = 0; i < wm_adsp_fw[fw].num_caps; i++)
+                       caps->codecs[i] = wm_adsp_fw[fw].caps[i].id;
+
+               caps->num_codecs = i;
+               caps->direction = wm_adsp_fw[fw].compr_direction;
+
+               caps->min_fragment_size = WM_ADSP_MIN_FRAGMENT_SIZE;
+               caps->max_fragment_size = WM_ADSP_MAX_FRAGMENT_SIZE;
+               caps->min_fragments = WM_ADSP_MIN_FRAGMENTS;
+               caps->max_fragments = WM_ADSP_MAX_FRAGMENTS;
+       }
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(wm_adsp_compr_get_caps);
+
+static int wm_adsp_read_data_block(struct wm_adsp *dsp, int mem_type,
+                                  unsigned int mem_addr,
+                                  unsigned int num_words, u32 *data)
+{
+       struct wm_adsp_region const *mem = wm_adsp_find_region(dsp, mem_type);
+       unsigned int i, reg;
+       int ret;
+
+       if (!mem)
+               return -EINVAL;
+
+       reg = wm_adsp_region_to_reg(mem, mem_addr);
+
+       ret = regmap_raw_read(dsp->regmap, reg, data,
+                             sizeof(*data) * num_words);
+       if (ret < 0)
+               return ret;
+
+       for (i = 0; i < num_words; ++i)
+               data[i] = be32_to_cpu(data[i]) & 0x00ffffffu;
+
+       return 0;
+}
+
+static inline int wm_adsp_read_data_word(struct wm_adsp *dsp, int mem_type,
+                                        unsigned int mem_addr, u32 *data)
+{
+       return wm_adsp_read_data_block(dsp, mem_type, mem_addr, 1, data);
+}
+
+static int wm_adsp_write_data_word(struct wm_adsp *dsp, int mem_type,
+                                  unsigned int mem_addr, u32 data)
+{
+       struct wm_adsp_region const *mem = wm_adsp_find_region(dsp, mem_type);
+       unsigned int reg;
+
+       if (!mem)
+               return -EINVAL;
+
+       reg = wm_adsp_region_to_reg(mem, mem_addr);
+
+       data = cpu_to_be32(data & 0x00ffffffu);
+
+       return regmap_raw_write(dsp->regmap, reg, &data, sizeof(data));
+}
+
+static inline int wm_adsp_buffer_read(struct wm_adsp_compr_buf *buf,
+                                     unsigned int field_offset, u32 *data)
+{
+       return wm_adsp_read_data_word(buf->dsp, WMFW_ADSP2_XM,
+                                     buf->host_buf_ptr + field_offset, data);
+}
+
+static inline int wm_adsp_buffer_write(struct wm_adsp_compr_buf *buf,
+                                      unsigned int field_offset, u32 data)
+{
+       return wm_adsp_write_data_word(buf->dsp, WMFW_ADSP2_XM,
+                                      buf->host_buf_ptr + field_offset, data);
+}
+
+static int wm_adsp_buffer_locate(struct wm_adsp_compr_buf *buf)
+{
+       struct wm_adsp_alg_region *alg_region;
+       struct wm_adsp *dsp = buf->dsp;
+       u32 xmalg, addr, magic;
+       int i, ret;
+
+       alg_region = wm_adsp_find_alg_region(dsp, WMFW_ADSP2_XM, dsp->fw_id);
+       xmalg = sizeof(struct wm_adsp_system_config_xm_hdr) / sizeof(__be32);
+
+       addr = alg_region->base + xmalg + ALG_XM_FIELD(magic);
+       ret = wm_adsp_read_data_word(dsp, WMFW_ADSP2_XM, addr, &magic);
+       if (ret < 0)
+               return ret;
+
+       if (magic != WM_ADSP_ALG_XM_STRUCT_MAGIC)
+               return -EINVAL;
+
+       addr = alg_region->base + xmalg + ALG_XM_FIELD(host_buf_ptr);
+       for (i = 0; i < 5; ++i) {
+               ret = wm_adsp_read_data_word(dsp, WMFW_ADSP2_XM, addr,
+                                            &buf->host_buf_ptr);
+               if (ret < 0)
+                       return ret;
+
+               if (buf->host_buf_ptr)
+                       break;
+
+               usleep_range(1000, 2000);
+       }
+
+       if (!buf->host_buf_ptr)
+               return -EIO;
+
+       adsp_dbg(dsp, "host_buf_ptr=%x\n", buf->host_buf_ptr);
+
+       return 0;
+}
+
+static int wm_adsp_buffer_populate(struct wm_adsp_compr_buf *buf)
+{
+       const struct wm_adsp_fw_caps *caps = wm_adsp_fw[buf->dsp->fw].caps;
+       struct wm_adsp_buffer_region *region;
+       u32 offset = 0;
+       int i, ret;
+
+       for (i = 0; i < caps->num_regions; ++i) {
+               region = &buf->regions[i];
+
+               region->offset = offset;
+               region->mem_type = caps->region_defs[i].mem_type;
+
+               ret = wm_adsp_buffer_read(buf, caps->region_defs[i].base_offset,
+                                         &region->base_addr);
+               if (ret < 0)
+                       return ret;
+
+               ret = wm_adsp_buffer_read(buf, caps->region_defs[i].size_offset,
+                                         &offset);
+               if (ret < 0)
+                       return ret;
+
+               region->cumulative_size = offset;
+
+               adsp_dbg(buf->dsp,
+                        "region=%d type=%d base=%04x off=%04x size=%04x\n",
+                        i, region->mem_type, region->base_addr,
+                        region->offset, region->cumulative_size);
+       }
+
+       return 0;
+}
+
+static int wm_adsp_buffer_init(struct wm_adsp *dsp)
+{
+       struct wm_adsp_compr_buf *buf;
+       int ret;
+
+       buf = kzalloc(sizeof(*buf), GFP_KERNEL);
+       if (!buf)
+               return -ENOMEM;
+
+       buf->dsp = dsp;
+       buf->read_index = -1;
+       buf->irq_count = 0xFFFFFFFF;
+
+       ret = wm_adsp_buffer_locate(buf);
+       if (ret < 0) {
+               adsp_err(dsp, "Failed to acquire host buffer: %d\n", ret);
+               goto err_buffer;
+       }
+
+       buf->regions = kcalloc(wm_adsp_fw[dsp->fw].caps->num_regions,
+                              sizeof(*buf->regions), GFP_KERNEL);
+       if (!buf->regions) {
+               ret = -ENOMEM;
+               goto err_buffer;
+       }
+
+       ret = wm_adsp_buffer_populate(buf);
+       if (ret < 0) {
+               adsp_err(dsp, "Failed to populate host buffer: %d\n", ret);
+               goto err_regions;
+       }
+
+       dsp->buffer = buf;
+
+       return 0;
+
+err_regions:
+       kfree(buf->regions);
+err_buffer:
+       kfree(buf);
+       return ret;
+}
+
+static int wm_adsp_buffer_free(struct wm_adsp *dsp)
+{
+       if (dsp->buffer) {
+               kfree(dsp->buffer->regions);
+               kfree(dsp->buffer);
+
+               dsp->buffer = NULL;
+       }
+
+       return 0;
+}
+
+static inline int wm_adsp_compr_attached(struct wm_adsp_compr *compr)
+{
+       return compr->buf != NULL;
+}
+
+static int wm_adsp_compr_attach(struct wm_adsp_compr *compr)
+{
+       /*
+        * Note this will be more complex once each DSP can support multiple
+        * streams
+        */
+       if (!compr->dsp->buffer)
+               return -EINVAL;
+
+       compr->buf = compr->dsp->buffer;
+
+       return 0;
+}
+
+int wm_adsp_compr_trigger(struct snd_compr_stream *stream, int cmd)
+{
+       struct wm_adsp_compr *compr = stream->runtime->private_data;
+       struct wm_adsp *dsp = compr->dsp;
+       int ret = 0;
+
+       adsp_dbg(dsp, "Trigger: %d\n", cmd);
+
+       mutex_lock(&dsp->pwr_lock);
+
+       switch (cmd) {
+       case SNDRV_PCM_TRIGGER_START:
+               if (wm_adsp_compr_attached(compr))
+                       break;
+
+               ret = wm_adsp_compr_attach(compr);
+               if (ret < 0) {
+                       adsp_err(dsp, "Failed to link buffer and stream: %d\n",
+                                ret);
+                       break;
+               }
+
+               /* Trigger the IRQ at one fragment of data */
+               ret = wm_adsp_buffer_write(compr->buf,
+                                          HOST_BUFFER_FIELD(high_water_mark),
+                                          wm_adsp_compr_frag_words(compr));
+               if (ret < 0) {
+                       adsp_err(dsp, "Failed to set high water mark: %d\n",
+                                ret);
+                       break;
+               }
+               break;
+       case SNDRV_PCM_TRIGGER_STOP:
+               break;
+       default:
+               ret = -EINVAL;
+               break;
+       }
+
+       mutex_unlock(&dsp->pwr_lock);
+
+       return ret;
+}
+EXPORT_SYMBOL_GPL(wm_adsp_compr_trigger);
+
+static inline int wm_adsp_buffer_size(struct wm_adsp_compr_buf *buf)
+{
+       int last_region = wm_adsp_fw[buf->dsp->fw].caps->num_regions - 1;
+
+       return buf->regions[last_region].cumulative_size;
+}
+
+static int wm_adsp_buffer_update_avail(struct wm_adsp_compr_buf *buf)
+{
+       u32 next_read_index, next_write_index;
+       int write_index, read_index, avail;
+       int ret;
+
+       /* Only sync read index if we haven't already read a valid index */
+       if (buf->read_index < 0) {
+               ret = wm_adsp_buffer_read(buf,
+                               HOST_BUFFER_FIELD(next_read_index),
+                               &next_read_index);
+               if (ret < 0)
+                       return ret;
+
+               read_index = sign_extend32(next_read_index, 23);
+
+               if (read_index < 0) {
+                       adsp_dbg(buf->dsp, "Avail check on unstarted stream\n");
+                       return 0;
+               }
+
+               buf->read_index = read_index;
+       }
+
+       ret = wm_adsp_buffer_read(buf, HOST_BUFFER_FIELD(next_write_index),
+                       &next_write_index);
+       if (ret < 0)
+               return ret;
+
+       write_index = sign_extend32(next_write_index, 23);
+
+       avail = write_index - buf->read_index;
+       if (avail < 0)
+               avail += wm_adsp_buffer_size(buf);
+
+       adsp_dbg(buf->dsp, "readindex=0x%x, writeindex=0x%x, avail=%d\n",
+                buf->read_index, write_index, avail);
+
+       buf->avail = avail;
+
+       return 0;
+}
+
+int wm_adsp_compr_handle_irq(struct wm_adsp *dsp)
+{
+       struct wm_adsp_compr_buf *buf = dsp->buffer;
+       struct wm_adsp_compr *compr = dsp->compr;
+       int ret = 0;
+
+       mutex_lock(&dsp->pwr_lock);
+
+       if (!buf) {
+               adsp_err(dsp, "Spurious buffer IRQ\n");
+               ret = -ENODEV;
+               goto out;
+       }
+
+       adsp_dbg(dsp, "Handling buffer IRQ\n");
+
+       ret = wm_adsp_buffer_read(buf, HOST_BUFFER_FIELD(error), &buf->error);
+       if (ret < 0) {
+               adsp_err(dsp, "Failed to check buffer error: %d\n", ret);
+               goto out;
+       }
+       if (buf->error != 0) {
+               adsp_err(dsp, "Buffer error occurred: %d\n", buf->error);
+               ret = -EIO;
+               goto out;
+       }
+
+       ret = wm_adsp_buffer_read(buf, HOST_BUFFER_FIELD(irq_count),
+                                 &buf->irq_count);
+       if (ret < 0) {
+               adsp_err(dsp, "Failed to get irq_count: %d\n", ret);
+               goto out;
+       }
+
+       ret = wm_adsp_buffer_update_avail(buf);
+       if (ret < 0) {
+               adsp_err(dsp, "Error reading avail: %d\n", ret);
+               goto out;
+       }
+
+       if (compr->stream)
+               snd_compr_fragment_elapsed(compr->stream);
+
+out:
+       mutex_unlock(&dsp->pwr_lock);
+
+       return ret;
+}
+EXPORT_SYMBOL_GPL(wm_adsp_compr_handle_irq);
+
+static int wm_adsp_buffer_reenable_irq(struct wm_adsp_compr_buf *buf)
+{
+       if (buf->irq_count & 0x01)
+               return 0;
+
+       adsp_dbg(buf->dsp, "Enable IRQ(0x%x) for next fragment\n",
+                buf->irq_count);
+
+       buf->irq_count |= 0x01;
+
+       return wm_adsp_buffer_write(buf, HOST_BUFFER_FIELD(irq_ack),
+                                   buf->irq_count);
+}
+
+int wm_adsp_compr_pointer(struct snd_compr_stream *stream,
+                         struct snd_compr_tstamp *tstamp)
+{
+       struct wm_adsp_compr *compr = stream->runtime->private_data;
+       struct wm_adsp_compr_buf *buf = compr->buf;
+       struct wm_adsp *dsp = compr->dsp;
+       int ret = 0;
+
+       adsp_dbg(dsp, "Pointer request\n");
+
+       mutex_lock(&dsp->pwr_lock);
+
+       if (!compr->buf) {
+               ret = -ENXIO;
+               goto out;
+       }
+
+       if (compr->buf->error) {
+               ret = -EIO;
+               goto out;
+       }
+
+       if (buf->avail < wm_adsp_compr_frag_words(compr)) {
+               ret = wm_adsp_buffer_update_avail(buf);
+               if (ret < 0) {
+                       adsp_err(dsp, "Error reading avail: %d\n", ret);
+                       goto out;
+               }
+
+               /*
+                * If we really have less than 1 fragment available tell the
+                * DSP to inform us once a whole fragment is available.
+                */
+               if (buf->avail < wm_adsp_compr_frag_words(compr)) {
+                       ret = wm_adsp_buffer_reenable_irq(buf);
+                       if (ret < 0) {
+                               adsp_err(dsp,
+                                        "Failed to re-enable buffer IRQ: %d\n",
+                                        ret);
+                               goto out;
+                       }
+               }
+       }
+
+       tstamp->copied_total = compr->copied_total;
+       tstamp->copied_total += buf->avail * WM_ADSP_DATA_WORD_SIZE;
+
+out:
+       mutex_unlock(&dsp->pwr_lock);
+
+       return ret;
+}
+EXPORT_SYMBOL_GPL(wm_adsp_compr_pointer);
+
+static int wm_adsp_buffer_capture_block(struct wm_adsp_compr *compr, int target)
+{
+       struct wm_adsp_compr_buf *buf = compr->buf;
+       u8 *pack_in = (u8 *)compr->raw_buf;
+       u8 *pack_out = (u8 *)compr->raw_buf;
+       unsigned int adsp_addr;
+       int mem_type, nwords, max_read;
+       int i, j, ret;
+
+       /* Calculate read parameters */
+       for (i = 0; i < wm_adsp_fw[buf->dsp->fw].caps->num_regions; ++i)
+               if (buf->read_index < buf->regions[i].cumulative_size)
+                       break;
+
+       if (i == wm_adsp_fw[buf->dsp->fw].caps->num_regions)
+               return -EINVAL;
+
+       mem_type = buf->regions[i].mem_type;
+       adsp_addr = buf->regions[i].base_addr +
+                   (buf->read_index - buf->regions[i].offset);
+
+       max_read = wm_adsp_compr_frag_words(compr);
+       nwords = buf->regions[i].cumulative_size - buf->read_index;
+
+       if (nwords > target)
+               nwords = target;
+       if (nwords > buf->avail)
+               nwords = buf->avail;
+       if (nwords > max_read)
+               nwords = max_read;
+       if (!nwords)
+               return 0;
+
+       /* Read data from DSP */
+       ret = wm_adsp_read_data_block(buf->dsp, mem_type, adsp_addr,
+                                     nwords, compr->raw_buf);
+       if (ret < 0)
+               return ret;
+
+       /* Remove the padding bytes from the data read from the DSP */
+       for (i = 0; i < nwords; i++) {
+               for (j = 0; j < WM_ADSP_DATA_WORD_SIZE; j++)
+                       *pack_out++ = *pack_in++;
+
+               pack_in += sizeof(*(compr->raw_buf)) - WM_ADSP_DATA_WORD_SIZE;
+       }
+
+       /* update read index to account for words read */
+       buf->read_index += nwords;
+       if (buf->read_index == wm_adsp_buffer_size(buf))
+               buf->read_index = 0;
+
+       ret = wm_adsp_buffer_write(buf, HOST_BUFFER_FIELD(next_read_index),
+                                  buf->read_index);
+       if (ret < 0)
+               return ret;
+
+       /* update avail to account for words read */
+       buf->avail -= nwords;
+
+       return nwords;
+}
+
+static int wm_adsp_compr_read(struct wm_adsp_compr *compr,
+                             char __user *buf, size_t count)
+{
+       struct wm_adsp *dsp = compr->dsp;
+       int ntotal = 0;
+       int nwords, nbytes;
+
+       adsp_dbg(dsp, "Requested read of %zu bytes\n", count);
+
+       if (!compr->buf)
+               return -ENXIO;
+
+       if (compr->buf->error)
+               return -EIO;
+
+       count /= WM_ADSP_DATA_WORD_SIZE;
+
+       do {
+               nwords = wm_adsp_buffer_capture_block(compr, count);
+               if (nwords < 0) {
+                       adsp_err(dsp, "Failed to capture block: %d\n", nwords);
+                       return nwords;
+               }
+
+               nbytes = nwords * WM_ADSP_DATA_WORD_SIZE;
+
+               adsp_dbg(dsp, "Read %d bytes\n", nbytes);
+
+               if (copy_to_user(buf + ntotal, compr->raw_buf, nbytes)) {
+                       adsp_err(dsp, "Failed to copy data to user: %d, %d\n",
+                                ntotal, nbytes);
+                       return -EFAULT;
+               }
+
+               count -= nwords;
+               ntotal += nbytes;
+       } while (nwords > 0 && count > 0);
+
+       compr->copied_total += ntotal;
+
+       return ntotal;
+}
+
+int wm_adsp_compr_copy(struct snd_compr_stream *stream, char __user *buf,
+                      size_t count)
+{
+       struct wm_adsp_compr *compr = stream->runtime->private_data;
+       struct wm_adsp *dsp = compr->dsp;
+       int ret;
+
+       mutex_lock(&dsp->pwr_lock);
+
+       if (stream->direction == SND_COMPRESS_CAPTURE)
+               ret = wm_adsp_compr_read(compr, buf, count);
+       else
+               ret = -ENOTSUPP;
+
+       mutex_unlock(&dsp->pwr_lock);
+
+       return ret;
+}
+EXPORT_SYMBOL_GPL(wm_adsp_compr_copy);
+
 MODULE_LICENSE("GPL v2");
index 2d117cf0e95365202295fdf5c74ef0519ec40557..1a928ec547411b6d38bcec2718d2dcc09d1f6cac 100644 (file)
@@ -15,6 +15,7 @@
 
 #include <sound/soc.h>
 #include <sound/soc-dapm.h>
+#include <sound/compress_driver.h>
 
 #include "wmfw.h"
 
@@ -30,6 +31,9 @@ struct wm_adsp_alg_region {
        unsigned int base;
 };
 
+struct wm_adsp_compr;
+struct wm_adsp_compr_buf;
+
 struct wm_adsp {
        const char *part;
        int num;
@@ -45,8 +49,8 @@ struct wm_adsp {
 
        struct list_head alg_regions;
 
-       int fw_id;
-       int fw_id_version;
+       unsigned int fw_id;
+       unsigned int fw_id_version;
 
        const struct wm_adsp_region *mem;
        int num_mems;
@@ -59,9 +63,13 @@ struct wm_adsp {
 
        struct work_struct boot_work;
 
+       struct wm_adsp_compr *compr;
+       struct wm_adsp_compr_buf *buffer;
+
+       struct mutex pwr_lock;
+
 #ifdef CONFIG_DEBUG_FS
        struct dentry *debugfs_root;
-       struct mutex debugfs_lock;
        char *wmfw_file_name;
        char *bin_file_name;
 #endif
@@ -96,4 +104,18 @@ int wm_adsp2_early_event(struct snd_soc_dapm_widget *w,
 int wm_adsp2_event(struct snd_soc_dapm_widget *w,
                   struct snd_kcontrol *kcontrol, int event);
 
+extern int wm_adsp_compr_open(struct wm_adsp *dsp,
+                             struct snd_compr_stream *stream);
+extern int wm_adsp_compr_free(struct snd_compr_stream *stream);
+extern int wm_adsp_compr_set_params(struct snd_compr_stream *stream,
+                                   struct snd_compr_params *params);
+extern int wm_adsp_compr_get_caps(struct snd_compr_stream *stream,
+                                 struct snd_compr_caps *caps);
+extern int wm_adsp_compr_trigger(struct snd_compr_stream *stream, int cmd);
+extern int wm_adsp_compr_handle_irq(struct wm_adsp *dsp);
+extern int wm_adsp_compr_pointer(struct snd_compr_stream *stream,
+                                struct snd_compr_tstamp *tstamp);
+extern int wm_adsp_compr_copy(struct snd_compr_stream *stream,
+                             char __user *buf, size_t count);
+
 #endif
index 4495a40a94680600ff324bd035098ff3d73f594b..2ccb8bccc9d4cc4a79c6a94abe4dfb1566872737 100644 (file)
@@ -223,8 +223,8 @@ static void mcasp_start_tx(struct davinci_mcasp *mcasp)
 
        /* wait for XDATA to be cleared */
        cnt = 0;
-       while (!(mcasp_get_reg(mcasp, DAVINCI_MCASP_TXSTAT_REG) &
-                ~XRDATA) && (cnt < 100000))
+       while ((mcasp_get_reg(mcasp, DAVINCI_MCASP_TXSTAT_REG) & XRDATA) &&
+              (cnt < 100000))
                cnt++;
 
        /* Release TX state machine */
@@ -681,8 +681,8 @@ static int davinci_mcasp_set_tdm_slot(struct snd_soc_dai *dai,
        }
 
        mcasp->tdm_slots = slots;
-       mcasp->tdm_mask[SNDRV_PCM_STREAM_PLAYBACK] = rx_mask;
-       mcasp->tdm_mask[SNDRV_PCM_STREAM_CAPTURE] = tx_mask;
+       mcasp->tdm_mask[SNDRV_PCM_STREAM_PLAYBACK] = tx_mask;
+       mcasp->tdm_mask[SNDRV_PCM_STREAM_CAPTURE] = rx_mask;
        mcasp->slot_width = slot_width;
 
        return davinci_mcasp_set_ch_constraints(mcasp);
@@ -908,6 +908,14 @@ static int mcasp_i2s_hw_param(struct davinci_mcasp *mcasp, int stream,
                mcasp_set_bits(mcasp, DAVINCI_MCASP_RXFMT_REG, busel | RXORD);
                mcasp_mod_bits(mcasp, DAVINCI_MCASP_RXFMCTL_REG,
                               FSRMOD(total_slots), FSRMOD(0x1FF));
+               /*
+                * If McASP is set to be TX/RX synchronous and the playback is
+                * not running already we need to configure the TX slots in
+                * order to have correct FSX on the bus
+                */
+               if (mcasp_is_synchronous(mcasp) && !mcasp->channels)
+                       mcasp_mod_bits(mcasp, DAVINCI_MCASP_TXFMCTL_REG,
+                                      FSXMOD(total_slots), FSXMOD(0x1FF));
        }
 
        return 0;
index 6e6a70c5c2bdba8349e4652e53a672c7fb40d74e..ce664c239be32fda4d269aea1722bb14631e3b22 100644 (file)
@@ -18,6 +18,7 @@
 #include <linux/interrupt.h>
 #include <linux/module.h>
 #include <linux/slab.h>
+#include <linux/pm_runtime.h>
 #include <sound/designware_i2s.h>
 #include <sound/pcm.h>
 #include <sound/pcm_params.h>
@@ -93,7 +94,12 @@ struct dw_i2s_dev {
        struct clk *clk;
        int active;
        unsigned int capability;
+       unsigned int quirks;
+       unsigned int i2s_reg_comp1;
+       unsigned int i2s_reg_comp2;
        struct device *dev;
+       u32 ccr;
+       u32 xfer_resolution;
 
        /* data related to DMA transfers b/w i2s and DMAC */
        union dw_i2s_snd_dma_data play_dma_data;
@@ -213,31 +219,58 @@ static int dw_i2s_startup(struct snd_pcm_substream *substream,
        return 0;
 }
 
+static void dw_i2s_config(struct dw_i2s_dev *dev, int stream)
+{
+       u32 ch_reg, irq;
+       struct i2s_clk_config_data *config = &dev->config;
+
+
+       i2s_disable_channels(dev, stream);
+
+       for (ch_reg = 0; ch_reg < (config->chan_nr / 2); ch_reg++) {
+               if (stream == SNDRV_PCM_STREAM_PLAYBACK) {
+                       i2s_write_reg(dev->i2s_base, TCR(ch_reg),
+                                     dev->xfer_resolution);
+                       i2s_write_reg(dev->i2s_base, TFCR(ch_reg), 0x02);
+                       irq = i2s_read_reg(dev->i2s_base, IMR(ch_reg));
+                       i2s_write_reg(dev->i2s_base, IMR(ch_reg), irq & ~0x30);
+                       i2s_write_reg(dev->i2s_base, TER(ch_reg), 1);
+               } else {
+                       i2s_write_reg(dev->i2s_base, RCR(ch_reg),
+                                     dev->xfer_resolution);
+                       i2s_write_reg(dev->i2s_base, RFCR(ch_reg), 0x07);
+                       irq = i2s_read_reg(dev->i2s_base, IMR(ch_reg));
+                       i2s_write_reg(dev->i2s_base, IMR(ch_reg), irq & ~0x03);
+                       i2s_write_reg(dev->i2s_base, RER(ch_reg), 1);
+               }
+
+       }
+}
+
 static int dw_i2s_hw_params(struct snd_pcm_substream *substream,
                struct snd_pcm_hw_params *params, struct snd_soc_dai *dai)
 {
        struct dw_i2s_dev *dev = snd_soc_dai_get_drvdata(dai);
        struct i2s_clk_config_data *config = &dev->config;
-       u32 ccr, xfer_resolution, ch_reg, irq;
        int ret;
 
        switch (params_format(params)) {
        case SNDRV_PCM_FORMAT_S16_LE:
                config->data_width = 16;
-               ccr = 0x00;
-               xfer_resolution = 0x02;
+               dev->ccr = 0x00;
+               dev->xfer_resolution = 0x02;
                break;
 
        case SNDRV_PCM_FORMAT_S24_LE:
                config->data_width = 24;
-               ccr = 0x08;
-               xfer_resolution = 0x04;
+               dev->ccr = 0x08;
+               dev->xfer_resolution = 0x04;
                break;
 
        case SNDRV_PCM_FORMAT_S32_LE:
                config->data_width = 32;
-               ccr = 0x10;
-               xfer_resolution = 0x05;
+               dev->ccr = 0x10;
+               dev->xfer_resolution = 0x05;
                break;
 
        default:
@@ -258,27 +291,9 @@ static int dw_i2s_hw_params(struct snd_pcm_substream *substream,
                return -EINVAL;
        }
 
-       i2s_disable_channels(dev, substream->stream);
-
-       for (ch_reg = 0; ch_reg < (config->chan_nr / 2); ch_reg++) {
-               if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
-                       i2s_write_reg(dev->i2s_base, TCR(ch_reg),
-                                     xfer_resolution);
-                       i2s_write_reg(dev->i2s_base, TFCR(ch_reg), 0x02);
-                       irq = i2s_read_reg(dev->i2s_base, IMR(ch_reg));
-                       i2s_write_reg(dev->i2s_base, IMR(ch_reg), irq & ~0x30);
-                       i2s_write_reg(dev->i2s_base, TER(ch_reg), 1);
-               } else {
-                       i2s_write_reg(dev->i2s_base, RCR(ch_reg),
-                                     xfer_resolution);
-                       i2s_write_reg(dev->i2s_base, RFCR(ch_reg), 0x07);
-                       irq = i2s_read_reg(dev->i2s_base, IMR(ch_reg));
-                       i2s_write_reg(dev->i2s_base, IMR(ch_reg), irq & ~0x03);
-                       i2s_write_reg(dev->i2s_base, RER(ch_reg), 1);
-               }
-       }
+       dw_i2s_config(dev, substream->stream);
 
-       i2s_write_reg(dev->i2s_base, CCR, ccr);
+       i2s_write_reg(dev->i2s_base, CCR, dev->ccr);
 
        config->sample_rate = params_rate(params);
 
@@ -394,6 +409,23 @@ static const struct snd_soc_component_driver dw_i2s_component = {
 };
 
 #ifdef CONFIG_PM
+static int dw_i2s_runtime_suspend(struct device *dev)
+{
+       struct dw_i2s_dev *dw_dev = dev_get_drvdata(dev);
+
+       if (dw_dev->capability & DW_I2S_MASTER)
+               clk_disable(dw_dev->clk);
+       return 0;
+}
+
+static int dw_i2s_runtime_resume(struct device *dev)
+{
+       struct dw_i2s_dev *dw_dev = dev_get_drvdata(dev);
+
+       if (dw_dev->capability & DW_I2S_MASTER)
+               clk_enable(dw_dev->clk);
+       return 0;
+}
 
 static int dw_i2s_suspend(struct snd_soc_dai *dai)
 {
@@ -410,6 +442,11 @@ static int dw_i2s_resume(struct snd_soc_dai *dai)
 
        if (dev->capability & DW_I2S_MASTER)
                clk_enable(dev->clk);
+
+       if (dai->playback_active)
+               dw_i2s_config(dev, SNDRV_PCM_STREAM_PLAYBACK);
+       if (dai->capture_active)
+               dw_i2s_config(dev, SNDRV_PCM_STREAM_CAPTURE);
        return 0;
 }
 
@@ -459,10 +496,14 @@ static int dw_configure_dai(struct dw_i2s_dev *dev,
         * Read component parameter registers to extract
         * the I2S block's configuration.
         */
-       u32 comp1 = i2s_read_reg(dev->i2s_base, I2S_COMP_PARAM_1);
-       u32 comp2 = i2s_read_reg(dev->i2s_base, I2S_COMP_PARAM_2);
+       u32 comp1 = i2s_read_reg(dev->i2s_base, dev->i2s_reg_comp1);
+       u32 comp2 = i2s_read_reg(dev->i2s_base, dev->i2s_reg_comp2);
        u32 idx;
 
+       if (dev->capability & DWC_I2S_RECORD &&
+                       dev->quirks & DW_I2S_QUIRK_COMP_PARAM1)
+               comp1 = comp1 & ~BIT(5);
+
        if (COMP1_TX_ENABLED(comp1)) {
                dev_dbg(dev->dev, " designware: play supported\n");
                idx = COMP1_TX_WORDSIZE_0(comp1);
@@ -503,7 +544,7 @@ static int dw_configure_dai_by_pd(struct dw_i2s_dev *dev,
                                   struct resource *res,
                                   const struct i2s_platform_data *pdata)
 {
-       u32 comp1 = i2s_read_reg(dev->i2s_base, I2S_COMP_PARAM_1);
+       u32 comp1 = i2s_read_reg(dev->i2s_base, dev->i2s_reg_comp1);
        u32 idx = COMP1_APB_DATA_WIDTH(comp1);
        int ret;
 
@@ -607,6 +648,14 @@ static int dw_i2s_probe(struct platform_device *pdev)
        if (pdata) {
                dev->capability = pdata->cap;
                clk_id = NULL;
+               dev->quirks = pdata->quirks;
+               if (dev->quirks & DW_I2S_QUIRK_COMP_REG_OFFSET) {
+                       dev->i2s_reg_comp1 = pdata->i2s_reg_comp1;
+                       dev->i2s_reg_comp2 = pdata->i2s_reg_comp2;
+               } else {
+                       dev->i2s_reg_comp1 = I2S_COMP_PARAM_1;
+                       dev->i2s_reg_comp2 = I2S_COMP_PARAM_2;
+               }
                ret = dw_configure_dai_by_pd(dev, dw_i2s_dai, res, pdata);
        } else {
                clk_id = "i2sclk";
@@ -649,7 +698,7 @@ static int dw_i2s_probe(struct platform_device *pdev)
                        goto err_clk_disable;
                }
        }
-
+       pm_runtime_enable(&pdev->dev);
        return 0;
 
 err_clk_disable:
@@ -665,6 +714,7 @@ static int dw_i2s_remove(struct platform_device *pdev)
        if (dev->capability & DW_I2S_MASTER)
                clk_disable_unprepare(dev->clk);
 
+       pm_runtime_disable(&pdev->dev);
        return 0;
 }
 
@@ -677,12 +727,17 @@ static const struct of_device_id dw_i2s_of_match[] = {
 MODULE_DEVICE_TABLE(of, dw_i2s_of_match);
 #endif
 
+static const struct dev_pm_ops dwc_pm_ops = {
+       SET_RUNTIME_PM_OPS(dw_i2s_runtime_suspend, dw_i2s_runtime_resume, NULL)
+};
+
 static struct platform_driver dw_i2s_driver = {
        .probe          = dw_i2s_probe,
        .remove         = dw_i2s_remove,
        .driver         = {
                .name   = "designware-i2s",
                .of_match_table = of_match_ptr(dw_i2s_of_match),
+               .pm = &dwc_pm_ops,
        },
 };
 
index 19c302b0d763976fba1bc79b927f8b39e03dfc83..14dfdee05fd5ae842bebdd0092e47bd4bc88f605 100644 (file)
@@ -283,6 +283,8 @@ config SND_SOC_IMX_MC13783
 config SND_SOC_FSL_ASOC_CARD
        tristate "Generic ASoC Sound Card with ASRC support"
        depends on OF && I2C
+       # enforce SND_SOC_FSL_ASOC_CARD=m if SND_AC97_CODEC=m:
+       depends on SND_AC97_CODEC || SND_AC97_CODEC=n
        select SND_SOC_IMX_AUDMUX
        select SND_SOC_IMX_PCM_DMA
        select SND_SOC_FSL_ESAI
index 1b05d1c5d9fd50fe32eb9b65f4da1340db9170e5..562b3bd22d9ac1f86de0a7d08fe64d8145445db8 100644 (file)
@@ -107,6 +107,13 @@ static const struct snd_soc_dapm_route audio_map[] = {
        {"CPU-Capture",  NULL, "Capture"},
 };
 
+static const struct snd_soc_dapm_route audio_map_ac97[] = {
+       {"AC97 Playback",  NULL, "ASRC-Playback"},
+       {"Playback",  NULL, "AC97 Playback"},
+       {"ASRC-Capture",  NULL, "AC97 Capture"},
+       {"AC97 Capture",  NULL, "Capture"},
+};
+
 /* Add all possible widgets into here without being redundant */
 static const struct snd_soc_dapm_widget fsl_asoc_card_dapm_widgets[] = {
        SND_SOC_DAPM_LINE("Line Out Jack", NULL),
@@ -222,12 +229,15 @@ static int fsl_asoc_card_set_bias_level(struct snd_soc_card *card,
                                        enum snd_soc_bias_level level)
 {
        struct fsl_asoc_card_priv *priv = snd_soc_card_get_drvdata(card);
-       struct snd_soc_dai *codec_dai = card->rtd[0].codec_dai;
+       struct snd_soc_pcm_runtime *rtd;
+       struct snd_soc_dai *codec_dai;
        struct codec_priv *codec_priv = &priv->codec_priv;
        struct device *dev = card->dev;
        unsigned int pll_out;
        int ret;
 
+       rtd = snd_soc_get_pcm_runtime(card, card->dai_link[0].name);
+       codec_dai = rtd->codec_dai;
        if (dapm->dev != codec_dai->dev)
                return 0;
 
@@ -414,14 +424,16 @@ static int fsl_asoc_card_audmux_init(struct device_node *np,
 static int fsl_asoc_card_late_probe(struct snd_soc_card *card)
 {
        struct fsl_asoc_card_priv *priv = snd_soc_card_get_drvdata(card);
-       struct snd_soc_dai *codec_dai = card->rtd[0].codec_dai;
+       struct snd_soc_pcm_runtime *rtd = list_first_entry(
+                       &card->rtd_list, struct snd_soc_pcm_runtime, list);
+       struct snd_soc_dai *codec_dai = rtd->codec_dai;
        struct codec_priv *codec_priv = &priv->codec_priv;
        struct device *dev = card->dev;
        int ret;
 
        if (fsl_asoc_card_is_ac97(priv)) {
 #if IS_ENABLED(CONFIG_SND_AC97_CODEC)
-               struct snd_soc_codec *codec = card->rtd[0].codec;
+               struct snd_soc_codec *codec = rtd->codec;
                struct snd_ac97 *ac97 = snd_soc_codec_get_drvdata(codec);
 
                /*
@@ -574,7 +586,8 @@ static int fsl_asoc_card_probe(struct platform_device *pdev)
        priv->card.dev = &pdev->dev;
        priv->card.name = priv->name;
        priv->card.dai_link = priv->dai_link;
-       priv->card.dapm_routes = audio_map;
+       priv->card.dapm_routes = fsl_asoc_card_is_ac97(priv) ?
+                                audio_map_ac97 : audio_map;
        priv->card.late_probe = fsl_asoc_card_late_probe;
        priv->card.num_dapm_routes = ARRAY_SIZE(audio_map);
        priv->card.dapm_widgets = fsl_asoc_card_dapm_widgets;
index 9f087d4f73ed775bdfaf9bad8c562b26a657b47d..c1a0e01cb8e79e1007c4b9ef7117206e4c891882 100644 (file)
        dev_dbg(&asrc_priv->pdev->dev, "Pair %c: " fmt, 'A' + index, ##__VA_ARGS__)
 
 /* Sample rates are aligned with that defined in pcm.h file */
-static const u8 process_option[][8][2] = {
-       /* 32kHz 44.1kHz 48kHz   64kHz   88.2kHz 96kHz   176kHz  192kHz */
-       {{0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0},},      /* 5512Hz */
-       {{0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0},},      /* 8kHz */
-       {{0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0},},      /* 11025Hz */
-       {{0, 1}, {0, 1}, {0, 1}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0},},      /* 16kHz */
-       {{0, 1}, {0, 1}, {0, 1}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0},},      /* 22050Hz */
-       {{0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 0}, {0, 0}, {0, 0},},      /* 32kHz */
-       {{0, 2}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 0}, {0, 0},},      /* 44.1kHz */
-       {{0, 2}, {0, 2}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 0}, {0, 0},},      /* 48kHz */
-       {{1, 2}, {0, 2}, {0, 2}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 0},},      /* 64kHz */
-       {{1, 2}, {1, 2}, {1, 2}, {1, 1}, {1, 1}, {1, 1}, {1, 1}, {1, 1},},      /* 88.2kHz */
-       {{1, 2}, {1, 2}, {1, 2}, {1, 1}, {1, 1}, {1, 1}, {1, 1}, {1, 1},},      /* 96kHz */
-       {{2, 2}, {2, 2}, {2, 2}, {2, 1}, {2, 1}, {2, 1}, {2, 1}, {2, 1},},      /* 176kHz */
-       {{2, 2}, {2, 2}, {2, 2}, {2, 1}, {2, 1}, {2, 1}, {2, 1}, {2, 1},},      /* 192kHz */
+static const u8 process_option[][12][2] = {
+       /* 8kHz 11.025kHz 16kHz 22.05kHz 32kHz 44.1kHz 48kHz   64kHz   88.2kHz 96kHz   176kHz  192kHz */
+       {{0, 1}, {0, 1}, {0, 1}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0},},      /* 5512Hz */
+       {{0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0},},      /* 8kHz */
+       {{0, 2}, {0, 1}, {0, 1}, {0, 1}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0},},      /* 11025Hz */
+       {{1, 2}, {0, 2}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0},},      /* 16kHz */
+       {{1, 2}, {1, 2}, {0, 2}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0},},      /* 22050Hz */
+       {{1, 2}, {2, 1}, {2, 1}, {0, 2}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 0}, {0, 0}, {0, 0},},      /* 32kHz */
+       {{2, 2}, {2, 2}, {2, 1}, {2, 1}, {0, 2}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 0}, {0, 0},},      /* 44.1kHz */
+       {{2, 2}, {2, 2}, {2, 1}, {2, 1}, {0, 2}, {0, 2}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 0}, {0, 0},},      /* 48kHz */
+       {{2, 2}, {2, 2}, {2, 2}, {2, 1}, {1, 2}, {0, 2}, {0, 2}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 0},},      /* 64kHz */
+       {{2, 2}, {2, 2}, {2, 2}, {2, 2}, {1, 2}, {1, 2}, {1, 2}, {1, 1}, {1, 1}, {1, 1}, {1, 1}, {1, 1},},      /* 88.2kHz */
+       {{2, 2}, {2, 2}, {2, 2}, {2, 2}, {1, 2}, {1, 2}, {1, 2}, {1, 1}, {1, 1}, {1, 1}, {1, 1}, {1, 1},},      /* 96kHz */
+       {{2, 2}, {2, 2}, {2, 2}, {2, 2}, {2, 2}, {2, 2}, {2, 2}, {2, 1}, {2, 1}, {2, 1}, {2, 1}, {2, 1},},      /* 176kHz */
+       {{2, 2}, {2, 2}, {2, 2}, {2, 2}, {2, 2}, {2, 2}, {2, 2}, {2, 1}, {2, 1}, {2, 1}, {2, 1}, {2, 1},},      /* 192kHz */
 };
 
 /* Corresponding to process_option */
@@ -55,7 +55,7 @@ static int supported_input_rate[] = {
 };
 
 static int supported_asrc_rate[] = {
-       32000, 44100, 48000, 64000, 88200, 96000, 176400, 192000,
+       8000, 11025, 16000, 22050, 32000, 44100, 48000, 64000, 88200, 96000, 176400, 192000,
 };
 
 /**
@@ -286,6 +286,13 @@ static int fsl_asrc_config_pair(struct fsl_asrc_pair *pair)
                return -EINVAL;
        }
 
+       if ((outrate > 8000 && outrate < 30000) &&
+           (outrate/inrate > 24 || inrate/outrate > 8)) {
+               pair_err("exceed supported ratio range [1/24, 8] for \
+                               inrate/outrate: %d/%d\n", inrate, outrate);
+               return -EINVAL;
+       }
+
        /* Validate input and output clock sources */
        clk_index[IN] = clk_map[IN][config->inclk];
        clk_index[OUT] = clk_map[OUT][config->outclk];
@@ -447,7 +454,7 @@ static int fsl_asrc_dai_hw_params(struct snd_pcm_substream *substream,
                                  struct snd_soc_dai *dai)
 {
        struct fsl_asrc *asrc_priv = snd_soc_dai_get_drvdata(dai);
-       int width = snd_pcm_format_width(params_format(params));
+       int width = params_width(params);
        struct snd_pcm_runtime *runtime = substream->runtime;
        struct fsl_asrc_pair *pair = runtime->private_data;
        unsigned int channels = params_channels(params);
@@ -859,6 +866,10 @@ static int fsl_asrc_probe(struct platform_device *pdev)
                return PTR_ERR(asrc_priv->ipg_clk);
        }
 
+       asrc_priv->spba_clk = devm_clk_get(&pdev->dev, "spba");
+       if (IS_ERR(asrc_priv->spba_clk))
+               dev_warn(&pdev->dev, "failed to get spba clock\n");
+
        for (i = 0; i < ASRC_CLK_MAX_NUM; i++) {
                sprintf(tmp, "asrck_%x", i);
                asrc_priv->asrck_clk[i] = devm_clk_get(&pdev->dev, tmp);
@@ -939,6 +950,11 @@ static int fsl_asrc_runtime_resume(struct device *dev)
        ret = clk_prepare_enable(asrc_priv->ipg_clk);
        if (ret)
                goto disable_mem_clk;
+       if (!IS_ERR(asrc_priv->spba_clk)) {
+               ret = clk_prepare_enable(asrc_priv->spba_clk);
+               if (ret)
+                       goto disable_ipg_clk;
+       }
        for (i = 0; i < ASRC_CLK_MAX_NUM; i++) {
                ret = clk_prepare_enable(asrc_priv->asrck_clk[i]);
                if (ret)
@@ -950,6 +966,9 @@ static int fsl_asrc_runtime_resume(struct device *dev)
 disable_asrck_clk:
        for (i--; i >= 0; i--)
                clk_disable_unprepare(asrc_priv->asrck_clk[i]);
+       if (!IS_ERR(asrc_priv->spba_clk))
+               clk_disable_unprepare(asrc_priv->spba_clk);
+disable_ipg_clk:
        clk_disable_unprepare(asrc_priv->ipg_clk);
 disable_mem_clk:
        clk_disable_unprepare(asrc_priv->mem_clk);
@@ -963,6 +982,8 @@ static int fsl_asrc_runtime_suspend(struct device *dev)
 
        for (i = 0; i < ASRC_CLK_MAX_NUM; i++)
                clk_disable_unprepare(asrc_priv->asrck_clk[i]);
+       if (!IS_ERR(asrc_priv->spba_clk))
+               clk_disable_unprepare(asrc_priv->spba_clk);
        clk_disable_unprepare(asrc_priv->ipg_clk);
        clk_disable_unprepare(asrc_priv->mem_clk);
 
@@ -975,6 +996,9 @@ static int fsl_asrc_suspend(struct device *dev)
 {
        struct fsl_asrc *asrc_priv = dev_get_drvdata(dev);
 
+       regmap_read(asrc_priv->regmap, REG_ASRCFG,
+                   &asrc_priv->regcache_cfg);
+
        regcache_cache_only(asrc_priv->regmap, true);
        regcache_mark_dirty(asrc_priv->regmap);
 
@@ -995,6 +1019,10 @@ static int fsl_asrc_resume(struct device *dev)
        regcache_cache_only(asrc_priv->regmap, false);
        regcache_sync(asrc_priv->regmap);
 
+       regmap_update_bits(asrc_priv->regmap, REG_ASRCFG,
+                          ASRCFG_NDPRi_ALL_MASK | ASRCFG_POSTMODi_ALL_MASK |
+                          ASRCFG_PREMODi_ALL_MASK, asrc_priv->regcache_cfg);
+
        /* Restart enabled pairs */
        regmap_update_bits(asrc_priv->regmap, REG_ASRCTR,
                           ASRCTR_ASRCEi_ALL_MASK, asrctr);
index 4aed63c4b431b519f3bccaa8f138bfabd1dcb6bf..0f163abe4ba37d93bec022afd0842b20423f2361 100644 (file)
 #define ASRCFG_INIRQi                  (1 << ASRCFG_INIRQi_SHIFT(i))
 #define ASRCFG_NDPRi_SHIFT(i)          (18 + i)
 #define ASRCFG_NDPRi_MASK(i)           (1 << ASRCFG_NDPRi_SHIFT(i))
+#define ASRCFG_NDPRi_ALL_SHIFT         18
+#define ASRCFG_NDPRi_ALL_MASK          (7 << ASRCFG_NDPRi_ALL_SHIFT)
 #define ASRCFG_NDPRi                   (1 << ASRCFG_NDPRi_SHIFT(i))
 #define ASRCFG_POSTMODi_SHIFT(i)       (8 + (i << 2))
 #define ASRCFG_POSTMODi_WIDTH          2
 #define ASRCFG_POSTMODi_MASK(i)                (((1 << ASRCFG_POSTMODi_WIDTH) - 1) << ASRCFG_POSTMODi_SHIFT(i))
+#define ASRCFG_POSTMODi_ALL_MASK       (ASRCFG_POSTMODi_MASK(0) | ASRCFG_POSTMODi_MASK(1) | ASRCFG_POSTMODi_MASK(2))
 #define ASRCFG_POSTMOD(i, v)           ((v) << ASRCFG_POSTMODi_SHIFT(i))
 #define ASRCFG_POSTMODi_UP(i)          (0 << ASRCFG_POSTMODi_SHIFT(i))
 #define ASRCFG_POSTMODi_DCON(i)                (1 << ASRCFG_POSTMODi_SHIFT(i))
 #define ASRCFG_PREMODi_SHIFT(i)                (6 + (i << 2))
 #define ASRCFG_PREMODi_WIDTH           2
 #define ASRCFG_PREMODi_MASK(i)         (((1 << ASRCFG_PREMODi_WIDTH) - 1) << ASRCFG_PREMODi_SHIFT(i))
+#define ASRCFG_PREMODi_ALL_MASK                (ASRCFG_PREMODi_MASK(0) | ASRCFG_PREMODi_MASK(1) | ASRCFG_PREMODi_MASK(2))
 #define ASRCFG_PREMOD(i, v)            ((v) << ASRCFG_PREMODi_SHIFT(i))
 #define ASRCFG_PREMODi_UP(i)           (0 << ASRCFG_PREMODi_SHIFT(i))
 #define ASRCFG_PREMODi_DCON(i)         (1 << ASRCFG_PREMODi_SHIFT(i))
@@ -426,6 +430,7 @@ struct fsl_asrc_pair {
  * @paddr: physical address to the base address of registers
  * @mem_clk: clock source to access register
  * @ipg_clk: clock source to drive peripheral
+ * @spba_clk: SPBA clock (optional, depending on SoC design)
  * @asrck_clk: clock sources to driver ASRC internal logic
  * @lock: spin lock for resource protection
  * @pair: pair pointers
@@ -433,6 +438,7 @@ struct fsl_asrc_pair {
  * @channel_avail: non-occupied channel numbers
  * @asrc_rate: default sample rate for ASoC Back-Ends
  * @asrc_width: default sample width for ASoC Back-Ends
+ * @regcache_cfg: store register value of REG_ASRCFG
  */
 struct fsl_asrc {
        struct snd_dmaengine_dai_dma_data dma_params_rx;
@@ -442,6 +448,7 @@ struct fsl_asrc {
        unsigned long paddr;
        struct clk *mem_clk;
        struct clk *ipg_clk;
+       struct clk *spba_clk;
        struct clk *asrck_clk[ASRC_CLK_MAX_NUM];
        spinlock_t lock;
 
@@ -451,6 +458,8 @@ struct fsl_asrc {
 
        int asrc_rate;
        int asrc_width;
+
+       u32 regcache_cfg;
 };
 
 extern struct snd_soc_platform_driver fsl_asrc_platform;
index 59f234e51971e2abfe7597dc7ad783a5972fbc76..26a90e12ede44d613e5fa6094c0144aac279a12d 100644 (file)
@@ -35,6 +35,7 @@
  * @coreclk: clock source to access register
  * @extalclk: esai clock source to derive HCK, SCK and FS
  * @fsysclk: system clock source to derive HCK, SCK and FS
+ * @spbaclk: SPBA clock (optional, depending on SoC design)
  * @fifo_depth: depth of tx/rx FIFO
  * @slot_width: width of each DAI slot
  * @slots: number of slots
@@ -54,6 +55,7 @@ struct fsl_esai {
        struct clk *coreclk;
        struct clk *extalclk;
        struct clk *fsysclk;
+       struct clk *spbaclk;
        u32 fifo_depth;
        u32 slot_width;
        u32 slots;
@@ -469,6 +471,11 @@ static int fsl_esai_startup(struct snd_pcm_substream *substream,
        ret = clk_prepare_enable(esai_priv->coreclk);
        if (ret)
                return ret;
+       if (!IS_ERR(esai_priv->spbaclk)) {
+               ret = clk_prepare_enable(esai_priv->spbaclk);
+               if (ret)
+                       goto err_spbaclk;
+       }
        if (!IS_ERR(esai_priv->extalclk)) {
                ret = clk_prepare_enable(esai_priv->extalclk);
                if (ret)
@@ -499,6 +506,9 @@ err_fsysclk:
        if (!IS_ERR(esai_priv->extalclk))
                clk_disable_unprepare(esai_priv->extalclk);
 err_extalck:
+       if (!IS_ERR(esai_priv->spbaclk))
+               clk_disable_unprepare(esai_priv->spbaclk);
+err_spbaclk:
        clk_disable_unprepare(esai_priv->coreclk);
 
        return ret;
@@ -510,7 +520,7 @@ static int fsl_esai_hw_params(struct snd_pcm_substream *substream,
 {
        struct fsl_esai *esai_priv = snd_soc_dai_get_drvdata(dai);
        bool tx = substream->stream == SNDRV_PCM_STREAM_PLAYBACK;
-       u32 width = snd_pcm_format_width(params_format(params));
+       u32 width = params_width(params);
        u32 channels = params_channels(params);
        u32 pins = DIV_ROUND_UP(channels, esai_priv->slots);
        u32 slot_width = width;
@@ -564,6 +574,8 @@ static void fsl_esai_shutdown(struct snd_pcm_substream *substream,
                clk_disable_unprepare(esai_priv->fsysclk);
        if (!IS_ERR(esai_priv->extalclk))
                clk_disable_unprepare(esai_priv->extalclk);
+       if (!IS_ERR(esai_priv->spbaclk))
+               clk_disable_unprepare(esai_priv->spbaclk);
        clk_disable_unprepare(esai_priv->coreclk);
 }
 
@@ -653,21 +665,28 @@ static const struct snd_soc_component_driver fsl_esai_component = {
 };
 
 static const struct reg_default fsl_esai_reg_defaults[] = {
-       {0x8,  0x00000000},
-       {0x10, 0x00000000},
-       {0x18, 0x00000000},
-       {0x98, 0x00000000},
-       {0xd0, 0x00000000},
-       {0xd4, 0x00000000},
-       {0xd8, 0x00000000},
-       {0xdc, 0x00000000},
-       {0xe0, 0x00000000},
-       {0xe4, 0x0000ffff},
-       {0xe8, 0x0000ffff},
-       {0xec, 0x0000ffff},
-       {0xf0, 0x0000ffff},
-       {0xf8, 0x00000000},
-       {0xfc, 0x00000000},
+       {REG_ESAI_ETDR,  0x00000000},
+       {REG_ESAI_ECR,   0x00000000},
+       {REG_ESAI_TFCR,  0x00000000},
+       {REG_ESAI_RFCR,  0x00000000},
+       {REG_ESAI_TX0,   0x00000000},
+       {REG_ESAI_TX1,   0x00000000},
+       {REG_ESAI_TX2,   0x00000000},
+       {REG_ESAI_TX3,   0x00000000},
+       {REG_ESAI_TX4,   0x00000000},
+       {REG_ESAI_TX5,   0x00000000},
+       {REG_ESAI_TSR,   0x00000000},
+       {REG_ESAI_SAICR, 0x00000000},
+       {REG_ESAI_TCR,   0x00000000},
+       {REG_ESAI_TCCR,  0x00000000},
+       {REG_ESAI_RCR,   0x00000000},
+       {REG_ESAI_RCCR,  0x00000000},
+       {REG_ESAI_TSMA,  0x0000ffff},
+       {REG_ESAI_TSMB,  0x0000ffff},
+       {REG_ESAI_RSMA,  0x0000ffff},
+       {REG_ESAI_RSMB,  0x0000ffff},
+       {REG_ESAI_PRRC,  0x00000000},
+       {REG_ESAI_PCRC,  0x00000000},
 };
 
 static bool fsl_esai_readable_reg(struct device *dev, unsigned int reg)
@@ -705,17 +724,10 @@ static bool fsl_esai_readable_reg(struct device *dev, unsigned int reg)
 static bool fsl_esai_volatile_reg(struct device *dev, unsigned int reg)
 {
        switch (reg) {
-       case REG_ESAI_ETDR:
        case REG_ESAI_ERDR:
        case REG_ESAI_ESR:
        case REG_ESAI_TFSR:
        case REG_ESAI_RFSR:
-       case REG_ESAI_TX0:
-       case REG_ESAI_TX1:
-       case REG_ESAI_TX2:
-       case REG_ESAI_TX3:
-       case REG_ESAI_TX4:
-       case REG_ESAI_TX5:
        case REG_ESAI_RX0:
        case REG_ESAI_RX1:
        case REG_ESAI_RX2:
@@ -819,6 +831,11 @@ static int fsl_esai_probe(struct platform_device *pdev)
                dev_warn(&pdev->dev, "failed to get fsys clock: %ld\n",
                                PTR_ERR(esai_priv->fsysclk));
 
+       esai_priv->spbaclk = devm_clk_get(&pdev->dev, "spba");
+       if (IS_ERR(esai_priv->spbaclk))
+               dev_warn(&pdev->dev, "failed to get spba clock: %ld\n",
+                               PTR_ERR(esai_priv->spbaclk));
+
        irq = platform_get_irq(pdev, 0);
        if (irq < 0) {
                dev_err(&pdev->dev, "no irq for node %s\n", pdev->name);
index a4435f5e3be910447f9168b4708d19140f3c1f4f..fef264d27fd3378d726a77209647ccc8098ec6a0 100644 (file)
@@ -126,6 +126,17 @@ out:
                return IRQ_HANDLED;
 }
 
+static int fsl_sai_set_dai_tdm_slot(struct snd_soc_dai *cpu_dai, u32 tx_mask,
+                               u32 rx_mask, int slots, int slot_width)
+{
+       struct fsl_sai *sai = snd_soc_dai_get_drvdata(cpu_dai);
+
+       sai->slots = slots;
+       sai->slot_width = slot_width;
+
+       return 0;
+}
+
 static int fsl_sai_set_dai_sysclk_tr(struct snd_soc_dai *cpu_dai,
                int clk_id, unsigned int freq, int fsl_dir)
 {
@@ -354,13 +365,25 @@ static int fsl_sai_set_bclk(struct snd_soc_dai *dai, bool tx, u32 freq)
                return -EINVAL;
        }
 
-       if ((tx && sai->synchronous[TX]) || (!tx && !sai->synchronous[RX])) {
+       /*
+        * 1) For Asynchronous mode, we must set RCR2 register for capture, and
+        *    set TCR2 register for playback.
+        * 2) For Tx sync with Rx clock, we must set RCR2 register for playback
+        *    and capture.
+        * 3) For Rx sync with Tx clock, we must set TCR2 register for playback
+        *    and capture.
+        * 4) For Tx and Rx are both Synchronous with another SAI, we just
+        *    ignore it.
+        */
+       if ((sai->synchronous[TX] && !sai->synchronous[RX]) ||
+           (!tx && !sai->synchronous[RX])) {
                regmap_update_bits(sai->regmap, FSL_SAI_RCR2,
                                   FSL_SAI_CR2_MSEL_MASK,
                                   FSL_SAI_CR2_MSEL(sai->mclk_id[tx]));
                regmap_update_bits(sai->regmap, FSL_SAI_RCR2,
                                   FSL_SAI_CR2_DIV_MASK, savediv - 1);
-       } else {
+       } else if ((sai->synchronous[RX] && !sai->synchronous[TX]) ||
+                  (tx && !sai->synchronous[TX])) {
                regmap_update_bits(sai->regmap, FSL_SAI_TCR2,
                                   FSL_SAI_CR2_MSEL_MASK,
                                   FSL_SAI_CR2_MSEL(sai->mclk_id[tx]));
@@ -381,13 +404,21 @@ static int fsl_sai_hw_params(struct snd_pcm_substream *substream,
        struct fsl_sai *sai = snd_soc_dai_get_drvdata(cpu_dai);
        bool tx = substream->stream == SNDRV_PCM_STREAM_PLAYBACK;
        unsigned int channels = params_channels(params);
-       u32 word_width = snd_pcm_format_width(params_format(params));
+       u32 word_width = params_width(params);
        u32 val_cr4 = 0, val_cr5 = 0;
+       u32 slots = (channels == 1) ? 2 : channels;
+       u32 slot_width = word_width;
        int ret;
 
+       if (sai->slots)
+               slots = sai->slots;
+
+       if (sai->slot_width)
+               slot_width = sai->slot_width;
+
        if (!sai->is_slave_mode) {
                ret = fsl_sai_set_bclk(cpu_dai, tx,
-                       2 * word_width * params_rate(params));
+                               slots * slot_width * params_rate(params));
                if (ret)
                        return ret;
 
@@ -399,21 +430,49 @@ static int fsl_sai_hw_params(struct snd_pcm_substream *substream,
 
                        sai->mclk_streams |= BIT(substream->stream);
                }
-
        }
 
        if (!sai->is_dsp_mode)
-               val_cr4 |= FSL_SAI_CR4_SYWD(word_width);
+               val_cr4 |= FSL_SAI_CR4_SYWD(slot_width);
 
-       val_cr5 |= FSL_SAI_CR5_WNW(word_width);
-       val_cr5 |= FSL_SAI_CR5_W0W(word_width);
+       val_cr5 |= FSL_SAI_CR5_WNW(slot_width);
+       val_cr5 |= FSL_SAI_CR5_W0W(slot_width);
 
        if (sai->is_lsb_first)
                val_cr5 |= FSL_SAI_CR5_FBT(0);
        else
                val_cr5 |= FSL_SAI_CR5_FBT(word_width - 1);
 
-       val_cr4 |= FSL_SAI_CR4_FRSZ(channels);
+       val_cr4 |= FSL_SAI_CR4_FRSZ(slots);
+
+       /*
+        * For SAI master mode, when Tx(Rx) sync with Rx(Tx) clock, Rx(Tx) will
+        * generate bclk and frame clock for Tx(Rx), we should set RCR4(TCR4),
+        * RCR5(TCR5) and RMR(TMR) for playback(capture), or there will be sync
+        * error.
+        */
+
+       if (!sai->is_slave_mode) {
+               if (!sai->synchronous[TX] && sai->synchronous[RX] && !tx) {
+                       regmap_update_bits(sai->regmap, FSL_SAI_TCR4,
+                               FSL_SAI_CR4_SYWD_MASK | FSL_SAI_CR4_FRSZ_MASK,
+                               val_cr4);
+                       regmap_update_bits(sai->regmap, FSL_SAI_TCR5,
+                               FSL_SAI_CR5_WNW_MASK | FSL_SAI_CR5_W0W_MASK |
+                               FSL_SAI_CR5_FBT_MASK, val_cr5);
+                       regmap_write(sai->regmap, FSL_SAI_TMR,
+                               ~0UL - ((1 << channels) - 1));
+               } else if (!sai->synchronous[RX] && sai->synchronous[TX] && tx) {
+                       regmap_update_bits(sai->regmap, FSL_SAI_RCR4,
+                               FSL_SAI_CR4_SYWD_MASK | FSL_SAI_CR4_FRSZ_MASK,
+                               val_cr4);
+                       regmap_update_bits(sai->regmap, FSL_SAI_RCR5,
+                               FSL_SAI_CR5_WNW_MASK | FSL_SAI_CR5_W0W_MASK |
+                               FSL_SAI_CR5_FBT_MASK, val_cr5);
+                       regmap_write(sai->regmap, FSL_SAI_RMR,
+                               ~0UL - ((1 << channels) - 1));
+               }
+       }
 
        regmap_update_bits(sai->regmap, FSL_SAI_xCR4(tx),
                           FSL_SAI_CR4_SYWD_MASK | FSL_SAI_CR4_FRSZ_MASK,
@@ -454,7 +513,8 @@ static int fsl_sai_trigger(struct snd_pcm_substream *substream, int cmd,
         * Rx sync with Tx clocks: Clear SYNC for Tx, set it for Rx.
         * Tx sync with Rx clocks: Clear SYNC for Rx, set it for Tx.
         */
-       regmap_update_bits(sai->regmap, FSL_SAI_TCR2, FSL_SAI_CR2_SYNC, 0);
+       regmap_update_bits(sai->regmap, FSL_SAI_TCR2, FSL_SAI_CR2_SYNC,
+                          sai->synchronous[TX] ? FSL_SAI_CR2_SYNC : 0);
        regmap_update_bits(sai->regmap, FSL_SAI_RCR2, FSL_SAI_CR2_SYNC,
                           sai->synchronous[RX] ? FSL_SAI_CR2_SYNC : 0);
 
@@ -504,6 +564,24 @@ static int fsl_sai_trigger(struct snd_pcm_substream *substream, int cmd,
                                           FSL_SAI_CSR_FR, FSL_SAI_CSR_FR);
                        regmap_update_bits(sai->regmap, FSL_SAI_RCSR,
                                           FSL_SAI_CSR_FR, FSL_SAI_CSR_FR);
+
+                       /*
+                        * For sai master mode, after several open/close sai,
+                        * there will be no frame clock, and can't recover
+                        * anymore. Add software reset to fix this issue.
+                        * This is a hardware bug, and will be fix in the
+                        * next sai version.
+                        */
+                       if (!sai->is_slave_mode) {
+                               /* Software Reset for both Tx and Rx */
+                               regmap_write(sai->regmap,
+                                            FSL_SAI_TCSR, FSL_SAI_CSR_SR);
+                               regmap_write(sai->regmap,
+                                            FSL_SAI_RCSR, FSL_SAI_CSR_SR);
+                               /* Clear SR bit to finish the reset */
+                               regmap_write(sai->regmap, FSL_SAI_TCSR, 0);
+                               regmap_write(sai->regmap, FSL_SAI_RCSR, 0);
+                       }
                }
                break;
        default:
@@ -550,6 +628,7 @@ static void fsl_sai_shutdown(struct snd_pcm_substream *substream,
 static const struct snd_soc_dai_ops fsl_sai_pcm_dai_ops = {
        .set_sysclk     = fsl_sai_set_dai_sysclk,
        .set_fmt        = fsl_sai_set_dai_fmt,
+       .set_tdm_slot   = fsl_sai_set_dai_tdm_slot,
        .hw_params      = fsl_sai_hw_params,
        .hw_free        = fsl_sai_hw_free,
        .trigger        = fsl_sai_trigger,
@@ -608,6 +687,22 @@ static const struct snd_soc_component_driver fsl_component = {
        .name           = "fsl-sai",
 };
 
+static struct reg_default fsl_sai_reg_defaults[] = {
+       {FSL_SAI_TCR1, 0},
+       {FSL_SAI_TCR2, 0},
+       {FSL_SAI_TCR3, 0},
+       {FSL_SAI_TCR4, 0},
+       {FSL_SAI_TCR5, 0},
+       {FSL_SAI_TDR,  0},
+       {FSL_SAI_TMR,  0},
+       {FSL_SAI_RCR1, 0},
+       {FSL_SAI_RCR2, 0},
+       {FSL_SAI_RCR3, 0},
+       {FSL_SAI_RCR4, 0},
+       {FSL_SAI_RCR5, 0},
+       {FSL_SAI_RMR,  0},
+};
+
 static bool fsl_sai_readable_reg(struct device *dev, unsigned int reg)
 {
        switch (reg) {
@@ -641,13 +736,11 @@ static bool fsl_sai_volatile_reg(struct device *dev, unsigned int reg)
        case FSL_SAI_RCSR:
        case FSL_SAI_TFR:
        case FSL_SAI_RFR:
-       case FSL_SAI_TDR:
        case FSL_SAI_RDR:
                return true;
        default:
                return false;
        }
-
 }
 
 static bool fsl_sai_writeable_reg(struct device *dev, unsigned int reg)
@@ -680,6 +773,8 @@ static const struct regmap_config fsl_sai_regmap_config = {
        .val_bits = 32,
 
        .max_register = FSL_SAI_RMR,
+       .reg_defaults = fsl_sai_reg_defaults,
+       .num_reg_defaults = ARRAY_SIZE(fsl_sai_reg_defaults),
        .readable_reg = fsl_sai_readable_reg,
        .volatile_reg = fsl_sai_volatile_reg,
        .writeable_reg = fsl_sai_writeable_reg,
index b95fbc3f68ebbfcae42d95c64552e87bdeec78a4..d9ed7be8cb34c3d7421aefae728a5ee4decbaaf9 100644 (file)
@@ -143,6 +143,9 @@ struct fsl_sai {
 
        unsigned int mclk_id[2];
        unsigned int mclk_streams;
+       unsigned int slots;
+       unsigned int slot_width;
+
        struct snd_dmaengine_dai_dma_data dma_params_rx;
        struct snd_dmaengine_dai_dma_data dma_params_tx;
 };
index 3d59bb6719f2b6fea0d7ed7137940bac88d99d6b..151849f7986396b335863222e1a3e599557bcd62 100644 (file)
@@ -88,6 +88,7 @@ struct spdif_mixer_control {
  * @rxclk: rx clock sources for capture
  * @coreclk: core clock for register access via DMA
  * @sysclk: system clock for rx clock rate measurement
+ * @spbaclk: SPBA clock (optional, depending on SoC design)
  * @dma_params_tx: DMA parameters for transmit channel
  * @dma_params_rx: DMA parameters for receive channel
  */
@@ -106,6 +107,7 @@ struct fsl_spdif_priv {
        struct clk *rxclk;
        struct clk *coreclk;
        struct clk *sysclk;
+       struct clk *spbaclk;
        struct snd_dmaengine_dai_dma_data dma_params_tx;
        struct snd_dmaengine_dai_dma_data dma_params_rx;
        /* regcache for SRPC */
@@ -474,6 +476,14 @@ static int fsl_spdif_startup(struct snd_pcm_substream *substream,
                        return ret;
                }
 
+               if (!IS_ERR(spdif_priv->spbaclk)) {
+                       ret = clk_prepare_enable(spdif_priv->spbaclk);
+                       if (ret) {
+                               dev_err(&pdev->dev, "failed to enable spba clock\n");
+                               goto err_spbaclk;
+                       }
+               }
+
                ret = spdif_softreset(spdif_priv);
                if (ret) {
                        dev_err(&pdev->dev, "failed to soft reset\n");
@@ -515,6 +525,9 @@ disable_txclk:
        for (i--; i >= 0; i--)
                clk_disable_unprepare(spdif_priv->txclk[i]);
 err:
+       if (!IS_ERR(spdif_priv->spbaclk))
+               clk_disable_unprepare(spdif_priv->spbaclk);
+err_spbaclk:
        clk_disable_unprepare(spdif_priv->coreclk);
 
        return ret;
@@ -548,6 +561,8 @@ static void fsl_spdif_shutdown(struct snd_pcm_substream *substream,
                spdif_intr_status_clear(spdif_priv);
                regmap_update_bits(regmap, REG_SPDIF_SCR,
                                SCR_LOW_POWER, SCR_LOW_POWER);
+               if (!IS_ERR(spdif_priv->spbaclk))
+                       clk_disable_unprepare(spdif_priv->spbaclk);
                clk_disable_unprepare(spdif_priv->coreclk);
        }
 }
@@ -1006,12 +1021,14 @@ static const struct snd_soc_component_driver fsl_spdif_component = {
 
 /* FSL SPDIF REGMAP */
 static const struct reg_default fsl_spdif_reg_defaults[] = {
-       {0x0,  0x00000400},
-       {0x4,  0x00000000},
-       {0xc,  0x00000000},
-       {0x34, 0x00000000},
-       {0x38, 0x00000000},
-       {0x50, 0x00020f00},
+       {REG_SPDIF_SCR,    0x00000400},
+       {REG_SPDIF_SRCD,   0x00000000},
+       {REG_SPDIF_SIE,    0x00000000},
+       {REG_SPDIF_STL,    0x00000000},
+       {REG_SPDIF_STR,    0x00000000},
+       {REG_SPDIF_STCSCH, 0x00000000},
+       {REG_SPDIF_STCSCL, 0x00000000},
+       {REG_SPDIF_STC,    0x00020f00},
 };
 
 static bool fsl_spdif_readable_reg(struct device *dev, unsigned int reg)
@@ -1049,8 +1066,6 @@ static bool fsl_spdif_volatile_reg(struct device *dev, unsigned int reg)
        case REG_SPDIF_SRCSL:
        case REG_SPDIF_SRU:
        case REG_SPDIF_SRQ:
-       case REG_SPDIF_STL:
-       case REG_SPDIF_STR:
        case REG_SPDIF_SRFM:
                return true;
        default:
@@ -1261,6 +1276,10 @@ static int fsl_spdif_probe(struct platform_device *pdev)
                return PTR_ERR(spdif_priv->coreclk);
        }
 
+       spdif_priv->spbaclk = devm_clk_get(&pdev->dev, "spba");
+       if (IS_ERR(spdif_priv->spbaclk))
+               dev_warn(&pdev->dev, "no spba clock in devicetree\n");
+
        /* Select clock source for rx/tx clock */
        spdif_priv->rxclk = devm_clk_get(&pdev->dev, "rxtx1");
        if (IS_ERR(spdif_priv->rxclk)) {
index 95d2392303eb449bdcf5375872c9edd21aae36c7..40dfd8a3648408a2cc76bb6e4c4c3872c8e28ac3 100644 (file)
@@ -113,17 +113,17 @@ struct fsl_ssi_rxtx_reg_val {
 };
 
 static const struct reg_default fsl_ssi_reg_defaults[] = {
-       {0x10, 0x00000000},
-       {0x18, 0x00003003},
-       {0x1c, 0x00000200},
-       {0x20, 0x00000200},
-       {0x24, 0x00040000},
-       {0x28, 0x00040000},
-       {0x38, 0x00000000},
-       {0x48, 0x00000000},
-       {0x4c, 0x00000000},
-       {0x54, 0x00000000},
-       {0x58, 0x00000000},
+       {CCSR_SSI_SCR,     0x00000000},
+       {CCSR_SSI_SIER,    0x00003003},
+       {CCSR_SSI_STCR,    0x00000200},
+       {CCSR_SSI_SRCR,    0x00000200},
+       {CCSR_SSI_STCCR,   0x00040000},
+       {CCSR_SSI_SRCCR,   0x00040000},
+       {CCSR_SSI_SACNT,   0x00000000},
+       {CCSR_SSI_STMSK,   0x00000000},
+       {CCSR_SSI_SRMSK,   0x00000000},
+       {CCSR_SSI_SACCEN,  0x00000000},
+       {CCSR_SSI_SACCDIS, 0x00000000},
 };
 
 static bool fsl_ssi_readable_reg(struct device *dev, unsigned int reg)
@@ -146,6 +146,7 @@ static bool fsl_ssi_volatile_reg(struct device *dev, unsigned int reg)
        case CCSR_SSI_SRX1:
        case CCSR_SSI_SISR:
        case CCSR_SSI_SFCSR:
+       case CCSR_SSI_SACNT:
        case CCSR_SSI_SACADD:
        case CCSR_SSI_SACDAT:
        case CCSR_SSI_SATAG:
@@ -156,6 +157,21 @@ static bool fsl_ssi_volatile_reg(struct device *dev, unsigned int reg)
        }
 }
 
+static bool fsl_ssi_precious_reg(struct device *dev, unsigned int reg)
+{
+       switch (reg) {
+       case CCSR_SSI_SRX0:
+       case CCSR_SSI_SRX1:
+       case CCSR_SSI_SISR:
+       case CCSR_SSI_SACADD:
+       case CCSR_SSI_SACDAT:
+       case CCSR_SSI_SATAG:
+               return true;
+       default:
+               return false;
+       }
+}
+
 static bool fsl_ssi_writeable_reg(struct device *dev, unsigned int reg)
 {
        switch (reg) {
@@ -178,6 +194,7 @@ static const struct regmap_config fsl_ssi_regconfig = {
        .num_reg_defaults = ARRAY_SIZE(fsl_ssi_reg_defaults),
        .readable_reg = fsl_ssi_readable_reg,
        .volatile_reg = fsl_ssi_volatile_reg,
+       .precious_reg = fsl_ssi_precious_reg,
        .writeable_reg = fsl_ssi_writeable_reg,
        .cache_type = REGCACHE_RBTREE,
 };
@@ -239,8 +256,9 @@ struct fsl_ssi_private {
        unsigned int baudclk_streams;
        unsigned int bitclk_freq;
 
-       /*regcache for SFCSR*/
+       /* regcache for volatile regs */
        u32 regcache_sfcsr;
+       u32 regcache_sacnt;
 
        /* DMA params */
        struct snd_dmaengine_dai_dma_data dma_params_tx;
@@ -767,8 +785,7 @@ static int fsl_ssi_hw_params(struct snd_pcm_substream *substream,
        struct fsl_ssi_private *ssi_private = snd_soc_dai_get_drvdata(cpu_dai);
        struct regmap *regs = ssi_private->regs;
        unsigned int channels = params_channels(hw_params);
-       unsigned int sample_size =
-               snd_pcm_format_width(params_format(hw_params));
+       unsigned int sample_size = params_width(hw_params);
        u32 wl = CCSR_SSI_SxCCR_WL(sample_size);
        int ret;
        u32 scr_val;
@@ -1588,6 +1605,8 @@ static int fsl_ssi_suspend(struct device *dev)
 
        regmap_read(regs, CCSR_SSI_SFCSR,
                        &ssi_private->regcache_sfcsr);
+       regmap_read(regs, CCSR_SSI_SACNT,
+                       &ssi_private->regcache_sacnt);
 
        regcache_cache_only(regs, true);
        regcache_mark_dirty(regs);
@@ -1606,6 +1625,8 @@ static int fsl_ssi_resume(struct device *dev)
                        CCSR_SSI_SFCSR_RFWM1_MASK | CCSR_SSI_SFCSR_TFWM1_MASK |
                        CCSR_SSI_SFCSR_RFWM0_MASK | CCSR_SSI_SFCSR_TFWM0_MASK,
                        ssi_private->regcache_sfcsr);
+       regmap_write(regs, CCSR_SSI_SACNT,
+                       ssi_private->regcache_sacnt);
 
        return regcache_sync(regs);
 }
index 1fc01ed3279dbee0991a343c082aa6c9ea5f042b..f3d3d1ffa84e4257029495785ca88e72cb013533 100644 (file)
@@ -62,6 +62,8 @@ int imx_pcm_dma_init(struct platform_device *pdev, size_t size)
 
        config = devm_kzalloc(&pdev->dev,
                        sizeof(struct snd_dmaengine_pcm_config), GFP_KERNEL);
+       if (!config)
+               return -ENOMEM;
        *config = imx_dmaengine_pcm_config;
        if (size)
                config->prealloc_buffer_size = size;
index 7abf6a07957451235ee2863144d3a7377890f1fc..49d7513f429e5424ee3ea081178e087368e74896 100644 (file)
@@ -220,9 +220,9 @@ static int snd_imx_pcm_mmap(struct snd_pcm_substream *substream,
        ret = dma_mmap_writecombine(substream->pcm->card->dev, vma,
                runtime->dma_area, runtime->dma_addr, runtime->dma_bytes);
 
-       pr_debug("%s: ret: %d %p 0x%08x 0x%08x\n", __func__, ret,
+       pr_debug("%s: ret: %d %p %pad 0x%08x\n", __func__, ret,
                        runtime->dma_area,
-                       runtime->dma_addr,
+                       &runtime->dma_addr,
                        runtime->dma_bytes);
        return ret;
 }
index b38b98cae855d0d5529f00e50d379493a6d6f753..201a70d1027a4a91bddd6dbc6e8d304071b3dd8d 100644 (file)
@@ -69,13 +69,16 @@ static int imx_wm8962_set_bias_level(struct snd_soc_card *card,
                                        struct snd_soc_dapm_context *dapm,
                                        enum snd_soc_bias_level level)
 {
-       struct snd_soc_dai *codec_dai = card->rtd[0].codec_dai;
+       struct snd_soc_pcm_runtime *rtd;
+       struct snd_soc_dai *codec_dai;
        struct imx_priv *priv = &card_priv;
        struct imx_wm8962_data *data = snd_soc_card_get_drvdata(card);
        struct device *dev = &priv->pdev->dev;
        unsigned int pll_out;
        int ret;
 
+       rtd = snd_soc_get_pcm_runtime(card, card->dai_link[0].name);
+       codec_dai = rtd->codec_dai;
        if (dapm->dev != codec_dai->dev)
                return 0;
 
@@ -135,12 +138,15 @@ static int imx_wm8962_set_bias_level(struct snd_soc_card *card,
 
 static int imx_wm8962_late_probe(struct snd_soc_card *card)
 {
-       struct snd_soc_dai *codec_dai = card->rtd[0].codec_dai;
+       struct snd_soc_pcm_runtime *rtd;
+       struct snd_soc_dai *codec_dai;
        struct imx_priv *priv = &card_priv;
        struct imx_wm8962_data *data = snd_soc_card_get_drvdata(card);
        struct device *dev = &priv->pdev->dev;
        int ret;
 
+       rtd = snd_soc_get_pcm_runtime(card, card->dai_link[0].name);
+       codec_dai = rtd->codec_dai;
        ret = snd_soc_dai_set_sysclk(codec_dai, WM8962_SYSCLK_MCLK,
                        data->clk_frequency, SND_SOC_CLOCK_IN);
        if (ret < 0)
index 6f236f170cf5fe6c4369612ead1d4d4e6dd4f591..ddf49f30b23fc9a2faa3934c81c3712c5b2cc627 100644 (file)
@@ -189,8 +189,7 @@ static int mpc8610_hpcd_probe(struct platform_device *pdev)
 {
        struct device *dev = pdev->dev.parent;
        /* ssi_pdev is the platform device for the SSI node that probed us */
-       struct platform_device *ssi_pdev =
-               container_of(dev, struct platform_device, dev);
+       struct platform_device *ssi_pdev = to_platform_device(dev);
        struct device_node *np = ssi_pdev->dev.of_node;
        struct device_node *codec_np = NULL;
        struct mpc8610_hpcd_data *machine_data;
index 747aab0602bd21dc5402dadd8cb59c35f544fc06..a1f780ecadf54d4e679d39aac2803e24c8be39ec 100644 (file)
@@ -199,8 +199,7 @@ static int p1022_ds_probe(struct platform_device *pdev)
 {
        struct device *dev = pdev->dev.parent;
        /* ssi_pdev is the platform device for the SSI node that probed us */
-       struct platform_device *ssi_pdev =
-               container_of(dev, struct platform_device, dev);
+       struct platform_device *ssi_pdev = to_platform_device(dev);
        struct device_node *np = ssi_pdev->dev.of_node;
        struct device_node *codec_np = NULL;
        struct machine_data *mdata;
index 1dd49e5f967591737a5fd5a63e328949daaed496..d4d88a8cb9c066296e1254445704880f3e91b34e 100644 (file)
@@ -203,8 +203,7 @@ static int p1022_rdk_probe(struct platform_device *pdev)
 {
        struct device *dev = pdev->dev.parent;
        /* ssi_pdev is the platform device for the SSI node that probed us */
-       struct platform_device *ssi_pdev =
-               container_of(dev, struct platform_device, dev);
+       struct platform_device *ssi_pdev = to_platform_device(dev);
        struct device_node *np = ssi_pdev->dev.of_node;
        struct device_node *codec_np = NULL;
        struct machine_data *mdata;
index 54c33204541fdb23dc78c8e2e801f3075fc1fd11..1ded8811598ef4b05333e7b8e2204f72f0b8e142 100644 (file)
@@ -45,7 +45,7 @@ static int asoc_simple_card_startup(struct snd_pcm_substream *substream)
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
        struct simple_card_data *priv = snd_soc_card_get_drvdata(rtd->card);
        struct simple_dai_props *dai_props =
-               &priv->dai_props[rtd - rtd->card->rtd];
+               &priv->dai_props[rtd->num];
        int ret;
 
        ret = clk_prepare_enable(dai_props->cpu_dai.clk);
@@ -64,7 +64,7 @@ static void asoc_simple_card_shutdown(struct snd_pcm_substream *substream)
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
        struct simple_card_data *priv = snd_soc_card_get_drvdata(rtd->card);
        struct simple_dai_props *dai_props =
-               &priv->dai_props[rtd - rtd->card->rtd];
+               &priv->dai_props[rtd->num];
 
        clk_disable_unprepare(dai_props->cpu_dai.clk);
 
@@ -78,8 +78,7 @@ static int asoc_simple_card_hw_params(struct snd_pcm_substream *substream,
        struct snd_soc_dai *codec_dai = rtd->codec_dai;
        struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
        struct simple_card_data *priv = snd_soc_card_get_drvdata(rtd->card);
-       struct simple_dai_props *dai_props =
-               &priv->dai_props[rtd - rtd->card->rtd];
+       struct simple_dai_props *dai_props = &priv->dai_props[rtd->num];
        unsigned int mclk, mclk_fs = 0;
        int ret = 0;
 
@@ -174,10 +173,9 @@ static int asoc_simple_card_dai_init(struct snd_soc_pcm_runtime *rtd)
        struct snd_soc_dai *codec = rtd->codec_dai;
        struct snd_soc_dai *cpu = rtd->cpu_dai;
        struct simple_dai_props *dai_props;
-       int num, ret;
+       int ret;
 
-       num = rtd - rtd->card->rtd;
-       dai_props = &priv->dai_props[num];
+       dai_props = &priv->dai_props[rtd->num];
        ret = __asoc_simple_card_dai_init(codec, &dai_props->codec_dai);
        if (ret < 0)
                return ret;
diff --git a/sound/soc/img/Kconfig b/sound/soc/img/Kconfig
new file mode 100644 (file)
index 0000000..857a951
--- /dev/null
@@ -0,0 +1,52 @@
+config SND_SOC_IMG
+       bool "Audio support for Imagination Technologies designs"
+       help
+         Audio support for Imagination Technologies audio hardware
+
+config SND_SOC_IMG_I2S_IN
+       tristate "Imagination I2S Input Device Driver"
+       depends on SND_SOC_IMG
+       select SND_SOC_GENERIC_DMAENGINE_PCM
+       help
+         Say Y or M if you want to add support for I2S in driver for
+         Imagination Technologies I2S in device.
+
+config SND_SOC_IMG_I2S_OUT
+       tristate "Imagination I2S Output Device Driver"
+       depends on SND_SOC_IMG
+       select SND_SOC_GENERIC_DMAENGINE_PCM
+       help
+         Say Y or M if you want to add support for I2S out driver for
+         Imagination Technologies I2S out device.
+
+config SND_SOC_IMG_PARALLEL_OUT
+       tristate "Imagination Parallel Output Device Driver"
+       depends on SND_SOC_IMG
+       select SND_SOC_GENERIC_DMAENGINE_PCM
+       help
+         Say Y or M if you want to add support for parallel out driver for
+         Imagination Technologies parallel out device.
+
+config SND_SOC_IMG_SPDIF_IN
+       tristate "Imagination SPDIF Input Device Driver"
+       depends on SND_SOC_IMG
+       select SND_SOC_GENERIC_DMAENGINE_PCM
+       help
+         Say Y or M if you want to add support for SPDIF input driver for
+         Imagination Technologies SPDIF input device.
+
+config SND_SOC_IMG_SPDIF_OUT
+       tristate "Imagination SPDIF Output Device Driver"
+       depends on SND_SOC_IMG
+       select SND_SOC_GENERIC_DMAENGINE_PCM
+       help
+         Say Y or M if you want to add support for SPDIF out driver for
+         Imagination Technologies SPDIF out device.
+
+
+config SND_SOC_IMG_PISTACHIO_INTERNAL_DAC
+       tristate "Support for Pistachio SoC Internal DAC Driver"
+       depends on SND_SOC_IMG
+       help
+         Say Y or M if you want to add support for Pistachio internal DAC
+         driver for Imagination Technologies Pistachio internal DAC device.
diff --git a/sound/soc/img/Makefile b/sound/soc/img/Makefile
new file mode 100644 (file)
index 0000000..0508c1c
--- /dev/null
@@ -0,0 +1,7 @@
+obj-$(CONFIG_SND_SOC_IMG_I2S_IN) += img-i2s-in.o
+obj-$(CONFIG_SND_SOC_IMG_I2S_OUT) += img-i2s-out.o
+obj-$(CONFIG_SND_SOC_IMG_PARALLEL_OUT) += img-parallel-out.o
+obj-$(CONFIG_SND_SOC_IMG_SPDIF_IN) += img-spdif-in.o
+obj-$(CONFIG_SND_SOC_IMG_SPDIF_OUT) += img-spdif-out.o
+
+obj-$(CONFIG_SND_SOC_IMG_PISTACHIO_INTERNAL_DAC) += pistachio-internal-dac.o
diff --git a/sound/soc/img/img-i2s-in.c b/sound/soc/img/img-i2s-in.c
new file mode 100644 (file)
index 0000000..0389203
--- /dev/null
@@ -0,0 +1,516 @@
+/*
+ * IMG I2S input controller driver
+ *
+ * Copyright (C) 2015 Imagination Technologies Ltd.
+ *
+ * Author: Damien Horsley <Damien.Horsley@imgtec.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.
+ */
+
+#include <linux/clk.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/reset.h>
+
+#include <sound/core.h>
+#include <sound/dmaengine_pcm.h>
+#include <sound/initval.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+
+#define IMG_I2S_IN_RX_FIFO                     0x0
+
+#define IMG_I2S_IN_CTL                         0x4
+#define IMG_I2S_IN_CTL_ACTIVE_CHAN_MASK                0xfffffffc
+#define IMG_I2S_IN_CTL_ACTIVE_CH_SHIFT         2
+#define IMG_I2S_IN_CTL_16PACK_MASK             BIT(1)
+#define IMG_I2S_IN_CTL_ME_MASK                 BIT(0)
+
+#define IMG_I2S_IN_CH_CTL                      0x4
+#define IMG_I2S_IN_CH_CTL_CCDEL_MASK           0x38000
+#define IMG_I2S_IN_CH_CTL_CCDEL_SHIFT          15
+#define IMG_I2S_IN_CH_CTL_FEN_MASK             BIT(14)
+#define IMG_I2S_IN_CH_CTL_FMODE_MASK           BIT(13)
+#define IMG_I2S_IN_CH_CTL_16PACK_MASK          BIT(12)
+#define IMG_I2S_IN_CH_CTL_JUST_MASK            BIT(10)
+#define IMG_I2S_IN_CH_CTL_PACKH_MASK           BIT(9)
+#define IMG_I2S_IN_CH_CTL_CLK_TRANS_MASK       BIT(8)
+#define IMG_I2S_IN_CH_CTL_BLKP_MASK            BIT(7)
+#define IMG_I2S_IN_CH_CTL_FIFO_FLUSH_MASK      BIT(6)
+#define IMG_I2S_IN_CH_CTL_LRD_MASK             BIT(3)
+#define IMG_I2S_IN_CH_CTL_FW_MASK              BIT(2)
+#define IMG_I2S_IN_CH_CTL_SW_MASK              BIT(1)
+#define IMG_I2S_IN_CH_CTL_ME_MASK              BIT(0)
+
+#define IMG_I2S_IN_CH_STRIDE                   0x20
+
+struct img_i2s_in {
+       void __iomem *base;
+       struct clk *clk_sys;
+       struct snd_dmaengine_dai_dma_data dma_data;
+       struct device *dev;
+       unsigned int max_i2s_chan;
+       void __iomem *channel_base;
+       unsigned int active_channels;
+       struct snd_soc_dai_driver dai_driver;
+};
+
+static inline void img_i2s_in_writel(struct img_i2s_in *i2s, u32 val, u32 reg)
+{
+       writel(val, i2s->base + reg);
+}
+
+static inline u32 img_i2s_in_readl(struct img_i2s_in *i2s, u32 reg)
+{
+       return readl(i2s->base + reg);
+}
+
+static inline void img_i2s_in_ch_writel(struct img_i2s_in *i2s, u32 chan,
+                                       u32 val, u32 reg)
+{
+       writel(val, i2s->channel_base + (chan * IMG_I2S_IN_CH_STRIDE) + reg);
+}
+
+static inline u32 img_i2s_in_ch_readl(struct img_i2s_in *i2s, u32 chan,
+                                       u32 reg)
+{
+       return readl(i2s->channel_base + (chan * IMG_I2S_IN_CH_STRIDE) + reg);
+}
+
+static inline void img_i2s_in_ch_disable(struct img_i2s_in *i2s, u32 chan)
+{
+       u32 reg;
+
+       reg = img_i2s_in_ch_readl(i2s, chan, IMG_I2S_IN_CH_CTL);
+       reg &= ~IMG_I2S_IN_CH_CTL_ME_MASK;
+       img_i2s_in_ch_writel(i2s, chan, reg, IMG_I2S_IN_CH_CTL);
+}
+
+static inline void img_i2s_in_ch_enable(struct img_i2s_in *i2s, u32 chan)
+{
+       u32 reg;
+
+       reg = img_i2s_in_ch_readl(i2s, chan, IMG_I2S_IN_CH_CTL);
+       reg |= IMG_I2S_IN_CH_CTL_ME_MASK;
+       img_i2s_in_ch_writel(i2s, chan, reg, IMG_I2S_IN_CH_CTL);
+}
+
+static inline void img_i2s_in_disable(struct img_i2s_in *i2s)
+{
+       u32 reg;
+
+       reg = img_i2s_in_readl(i2s, IMG_I2S_IN_CTL);
+       reg &= ~IMG_I2S_IN_CTL_ME_MASK;
+       img_i2s_in_writel(i2s, reg, IMG_I2S_IN_CTL);
+}
+
+static inline void img_i2s_in_enable(struct img_i2s_in *i2s)
+{
+       u32 reg;
+
+       reg = img_i2s_in_readl(i2s, IMG_I2S_IN_CTL);
+       reg |= IMG_I2S_IN_CTL_ME_MASK;
+       img_i2s_in_writel(i2s, reg, IMG_I2S_IN_CTL);
+}
+
+static inline void img_i2s_in_flush(struct img_i2s_in *i2s)
+{
+       int i;
+       u32 reg;
+
+       for (i = 0; i < i2s->active_channels; i++) {
+               reg = img_i2s_in_ch_readl(i2s, i, IMG_I2S_IN_CH_CTL);
+               reg |= IMG_I2S_IN_CH_CTL_FIFO_FLUSH_MASK;
+               img_i2s_in_ch_writel(i2s, i, reg, IMG_I2S_IN_CH_CTL);
+               reg &= ~IMG_I2S_IN_CH_CTL_FIFO_FLUSH_MASK;
+               img_i2s_in_ch_writel(i2s, i, reg, IMG_I2S_IN_CH_CTL);
+       }
+}
+
+static int img_i2s_in_trigger(struct snd_pcm_substream *substream, int cmd,
+       struct snd_soc_dai *dai)
+{
+       struct img_i2s_in *i2s = snd_soc_dai_get_drvdata(dai);
+
+       switch (cmd) {
+       case SNDRV_PCM_TRIGGER_START:
+       case SNDRV_PCM_TRIGGER_RESUME:
+       case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+               img_i2s_in_enable(i2s);
+               break;
+
+       case SNDRV_PCM_TRIGGER_STOP:
+       case SNDRV_PCM_TRIGGER_SUSPEND:
+       case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+               img_i2s_in_disable(i2s);
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static int img_i2s_in_check_rate(struct img_i2s_in *i2s,
+               unsigned int sample_rate, unsigned int frame_size,
+               unsigned int *bclk_filter_enable,
+               unsigned int *bclk_filter_value)
+{
+       unsigned int bclk_freq, cur_freq;
+
+       bclk_freq = sample_rate * frame_size;
+
+       cur_freq = clk_get_rate(i2s->clk_sys);
+
+       if (cur_freq >= bclk_freq * 8) {
+               *bclk_filter_enable = 1;
+               *bclk_filter_value = 0;
+       } else if (cur_freq >= bclk_freq * 7) {
+               *bclk_filter_enable = 1;
+               *bclk_filter_value = 1;
+       } else if (cur_freq >= bclk_freq * 6) {
+               *bclk_filter_enable = 0;
+               *bclk_filter_value = 0;
+       } else {
+               dev_err(i2s->dev,
+                       "Sys clock rate %u insufficient for sample rate %u\n",
+                       cur_freq, sample_rate);
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static int img_i2s_in_hw_params(struct snd_pcm_substream *substream,
+       struct snd_pcm_hw_params *params, struct snd_soc_dai *dai)
+{
+       struct img_i2s_in *i2s = snd_soc_dai_get_drvdata(dai);
+       unsigned int rate, channels, i2s_channels, frame_size;
+       unsigned int bclk_filter_enable, bclk_filter_value;
+       int i, ret = 0;
+       u32 reg, control_mask, chan_control_mask;
+       u32 control_set = 0, chan_control_set = 0;
+       snd_pcm_format_t format;
+
+       rate = params_rate(params);
+       format = params_format(params);
+       channels = params_channels(params);
+       i2s_channels = channels / 2;
+
+       switch (format) {
+       case SNDRV_PCM_FORMAT_S32_LE:
+               frame_size = 64;
+               chan_control_set |= IMG_I2S_IN_CH_CTL_SW_MASK;
+               chan_control_set |= IMG_I2S_IN_CH_CTL_FW_MASK;
+               chan_control_set |= IMG_I2S_IN_CH_CTL_PACKH_MASK;
+               break;
+       case SNDRV_PCM_FORMAT_S24_LE:
+               frame_size = 64;
+               chan_control_set |= IMG_I2S_IN_CH_CTL_SW_MASK;
+               chan_control_set |= IMG_I2S_IN_CH_CTL_FW_MASK;
+               break;
+       case SNDRV_PCM_FORMAT_S16_LE:
+               frame_size = 32;
+               control_set |= IMG_I2S_IN_CTL_16PACK_MASK;
+               chan_control_set |= IMG_I2S_IN_CH_CTL_16PACK_MASK;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       if ((channels < 2) ||
+           (channels > (i2s->max_i2s_chan * 2)) ||
+           (channels % 2))
+               return -EINVAL;
+
+       control_set |= ((i2s_channels - 1) << IMG_I2S_IN_CTL_ACTIVE_CH_SHIFT);
+
+       ret = img_i2s_in_check_rate(i2s, rate, frame_size,
+                       &bclk_filter_enable, &bclk_filter_value);
+       if (ret < 0)
+               return ret;
+
+       if (bclk_filter_enable)
+               chan_control_set |= IMG_I2S_IN_CH_CTL_FEN_MASK;
+
+       if (bclk_filter_value)
+               chan_control_set |= IMG_I2S_IN_CH_CTL_FMODE_MASK;
+
+       control_mask = IMG_I2S_IN_CTL_16PACK_MASK |
+                      IMG_I2S_IN_CTL_ACTIVE_CHAN_MASK;
+
+       chan_control_mask = IMG_I2S_IN_CH_CTL_16PACK_MASK |
+                           IMG_I2S_IN_CH_CTL_FEN_MASK |
+                           IMG_I2S_IN_CH_CTL_FMODE_MASK |
+                           IMG_I2S_IN_CH_CTL_SW_MASK |
+                           IMG_I2S_IN_CH_CTL_FW_MASK |
+                           IMG_I2S_IN_CH_CTL_PACKH_MASK;
+
+       reg = img_i2s_in_readl(i2s, IMG_I2S_IN_CTL);
+       reg = (reg & ~control_mask) | control_set;
+       img_i2s_in_writel(i2s, reg, IMG_I2S_IN_CTL);
+
+       for (i = 0; i < i2s->active_channels; i++)
+               img_i2s_in_ch_disable(i2s, i);
+
+       for (i = 0; i < i2s->max_i2s_chan; i++) {
+               reg = img_i2s_in_ch_readl(i2s, i, IMG_I2S_IN_CH_CTL);
+               reg = (reg & ~chan_control_mask) | chan_control_set;
+               img_i2s_in_ch_writel(i2s, i, reg, IMG_I2S_IN_CH_CTL);
+       }
+
+       i2s->active_channels = i2s_channels;
+
+       img_i2s_in_flush(i2s);
+
+       for (i = 0; i < i2s->active_channels; i++)
+               img_i2s_in_ch_enable(i2s, i);
+
+       return 0;
+}
+
+static int img_i2s_in_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
+{
+       struct img_i2s_in *i2s = snd_soc_dai_get_drvdata(dai);
+       int i;
+       u32 chan_control_mask, lrd_set = 0, blkp_set = 0, chan_control_set = 0;
+       u32 reg;
+
+       switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+       case SND_SOC_DAIFMT_NB_NF:
+               lrd_set |= IMG_I2S_IN_CH_CTL_LRD_MASK;
+               break;
+       case SND_SOC_DAIFMT_NB_IF:
+               break;
+       case SND_SOC_DAIFMT_IB_NF:
+               lrd_set |= IMG_I2S_IN_CH_CTL_LRD_MASK;
+               blkp_set |= IMG_I2S_IN_CH_CTL_BLKP_MASK;
+               break;
+       case SND_SOC_DAIFMT_IB_IF:
+               blkp_set |= IMG_I2S_IN_CH_CTL_BLKP_MASK;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+       case SND_SOC_DAIFMT_I2S:
+               chan_control_set |= IMG_I2S_IN_CH_CTL_CLK_TRANS_MASK;
+               break;
+       case SND_SOC_DAIFMT_LEFT_J:
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+       case SND_SOC_DAIFMT_CBM_CFM:
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       chan_control_mask = IMG_I2S_IN_CH_CTL_CLK_TRANS_MASK;
+
+       for (i = 0; i < i2s->active_channels; i++)
+               img_i2s_in_ch_disable(i2s, i);
+
+       /*
+        * BLKP and LRD must be set during separate register writes
+        */
+       for (i = 0; i < i2s->max_i2s_chan; i++) {
+               reg = img_i2s_in_ch_readl(i2s, i, IMG_I2S_IN_CH_CTL);
+               reg = (reg & ~chan_control_mask) | chan_control_set;
+               img_i2s_in_ch_writel(i2s, i, reg, IMG_I2S_IN_CH_CTL);
+               reg = (reg & ~IMG_I2S_IN_CH_CTL_BLKP_MASK) | blkp_set;
+               img_i2s_in_ch_writel(i2s, i, reg, IMG_I2S_IN_CH_CTL);
+               reg = (reg & ~IMG_I2S_IN_CH_CTL_LRD_MASK) | lrd_set;
+               img_i2s_in_ch_writel(i2s, i, reg, IMG_I2S_IN_CH_CTL);
+       }
+
+       for (i = 0; i < i2s->active_channels; i++)
+               img_i2s_in_ch_enable(i2s, i);
+
+       return 0;
+}
+
+static const struct snd_soc_dai_ops img_i2s_in_dai_ops = {
+       .trigger = img_i2s_in_trigger,
+       .hw_params = img_i2s_in_hw_params,
+       .set_fmt = img_i2s_in_set_fmt
+};
+
+static int img_i2s_in_dai_probe(struct snd_soc_dai *dai)
+{
+       struct img_i2s_in *i2s = snd_soc_dai_get_drvdata(dai);
+
+       snd_soc_dai_init_dma_data(dai, NULL, &i2s->dma_data);
+
+       return 0;
+}
+
+static const struct snd_soc_component_driver img_i2s_in_component = {
+       .name = "img-i2s-in"
+};
+
+static int img_i2s_in_dma_prepare_slave_config(struct snd_pcm_substream *st,
+       struct snd_pcm_hw_params *params, struct dma_slave_config *sc)
+{
+       unsigned int i2s_channels = params_channels(params) / 2;
+       struct snd_soc_pcm_runtime *rtd = st->private_data;
+       struct snd_dmaengine_dai_dma_data *dma_data;
+       int ret;
+
+       dma_data = snd_soc_dai_get_dma_data(rtd->cpu_dai, st);
+
+       ret = snd_hwparams_to_dma_slave_config(st, params, sc);
+       if (ret)
+               return ret;
+
+       sc->src_addr = dma_data->addr;
+       sc->src_addr_width = dma_data->addr_width;
+       sc->src_maxburst = 4 * i2s_channels;
+
+       return 0;
+}
+
+static const struct snd_dmaengine_pcm_config img_i2s_in_dma_config = {
+       .prepare_slave_config = img_i2s_in_dma_prepare_slave_config
+};
+
+static int img_i2s_in_probe(struct platform_device *pdev)
+{
+       struct img_i2s_in *i2s;
+       struct resource *res;
+       void __iomem *base;
+       int ret, i;
+       struct reset_control *rst;
+       unsigned int max_i2s_chan_pow_2;
+       struct device *dev = &pdev->dev;
+
+       i2s = devm_kzalloc(dev, sizeof(*i2s), GFP_KERNEL);
+       if (!i2s)
+               return -ENOMEM;
+
+       platform_set_drvdata(pdev, i2s);
+
+       i2s->dev = dev;
+
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       base = devm_ioremap_resource(dev, res);
+       if (IS_ERR(base))
+               return PTR_ERR(base);
+
+       i2s->base = base;
+
+       if (of_property_read_u32(pdev->dev.of_node, "img,i2s-channels",
+                       &i2s->max_i2s_chan)) {
+               dev_err(dev, "No img,i2s-channels property\n");
+               return -EINVAL;
+       }
+
+       max_i2s_chan_pow_2 = 1 << get_count_order(i2s->max_i2s_chan);
+
+       i2s->channel_base = base + (max_i2s_chan_pow_2 * 0x20);
+
+       i2s->clk_sys = devm_clk_get(dev, "sys");
+       if (IS_ERR(i2s->clk_sys)) {
+               if (PTR_ERR(i2s->clk_sys) != -EPROBE_DEFER)
+                       dev_err(dev, "Failed to acquire clock 'sys'\n");
+               return PTR_ERR(i2s->clk_sys);
+       }
+
+       ret = clk_prepare_enable(i2s->clk_sys);
+       if (ret)
+               return ret;
+
+       i2s->active_channels = 1;
+       i2s->dma_data.addr = res->start + IMG_I2S_IN_RX_FIFO;
+       i2s->dma_data.addr_width = 4;
+
+       i2s->dai_driver.probe = img_i2s_in_dai_probe;
+       i2s->dai_driver.capture.channels_min = 2;
+       i2s->dai_driver.capture.channels_max = i2s->max_i2s_chan * 2;
+       i2s->dai_driver.capture.rates = SNDRV_PCM_RATE_8000_192000;
+       i2s->dai_driver.capture.formats = SNDRV_PCM_FMTBIT_S32_LE |
+               SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S16_LE;
+       i2s->dai_driver.ops = &img_i2s_in_dai_ops;
+
+       rst = devm_reset_control_get(dev, "rst");
+       if (IS_ERR(rst)) {
+               if (PTR_ERR(rst) == -EPROBE_DEFER) {
+                       ret = -EPROBE_DEFER;
+                       goto err_clk_disable;
+               }
+
+               dev_dbg(dev, "No top level reset found\n");
+
+               img_i2s_in_disable(i2s);
+
+               for (i = 0; i < i2s->max_i2s_chan; i++)
+                       img_i2s_in_ch_disable(i2s, i);
+       } else {
+               reset_control_assert(rst);
+               reset_control_deassert(rst);
+       }
+
+       img_i2s_in_writel(i2s, 0, IMG_I2S_IN_CTL);
+
+       for (i = 0; i < i2s->max_i2s_chan; i++)
+               img_i2s_in_ch_writel(i2s, i,
+                       (4 << IMG_I2S_IN_CH_CTL_CCDEL_SHIFT) |
+                       IMG_I2S_IN_CH_CTL_JUST_MASK |
+                       IMG_I2S_IN_CH_CTL_FW_MASK, IMG_I2S_IN_CH_CTL);
+
+       ret = devm_snd_soc_register_component(dev, &img_i2s_in_component,
+                                               &i2s->dai_driver, 1);
+       if (ret)
+               goto err_clk_disable;
+
+       ret = devm_snd_dmaengine_pcm_register(dev, &img_i2s_in_dma_config, 0);
+       if (ret)
+               goto err_clk_disable;
+
+       return 0;
+
+err_clk_disable:
+       clk_disable_unprepare(i2s->clk_sys);
+
+       return ret;
+}
+
+static int img_i2s_in_dev_remove(struct platform_device *pdev)
+{
+       struct img_i2s_in *i2s = platform_get_drvdata(pdev);
+
+       clk_disable_unprepare(i2s->clk_sys);
+
+       return 0;
+}
+
+static const struct of_device_id img_i2s_in_of_match[] = {
+       { .compatible = "img,i2s-in" },
+       {}
+};
+MODULE_DEVICE_TABLE(of, img_i2s_in_of_match);
+
+static struct platform_driver img_i2s_in_driver = {
+       .driver = {
+               .name = "img-i2s-in",
+               .of_match_table = img_i2s_in_of_match
+       },
+       .probe = img_i2s_in_probe,
+       .remove = img_i2s_in_dev_remove
+};
+module_platform_driver(img_i2s_in_driver);
+
+MODULE_AUTHOR("Damien Horsley <Damien.Horsley@imgtec.com>");
+MODULE_DESCRIPTION("IMG I2S Input Driver");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/img/img-i2s-out.c b/sound/soc/img/img-i2s-out.c
new file mode 100644 (file)
index 0000000..5f99713
--- /dev/null
@@ -0,0 +1,565 @@
+/*
+ * IMG I2S output controller driver
+ *
+ * Copyright (C) 2015 Imagination Technologies Ltd.
+ *
+ * Author: Damien Horsley <Damien.Horsley@imgtec.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.
+ */
+
+#include <linux/clk.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/reset.h>
+
+#include <sound/core.h>
+#include <sound/dmaengine_pcm.h>
+#include <sound/initval.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+
+#define IMG_I2S_OUT_TX_FIFO                    0x0
+
+#define IMG_I2S_OUT_CTL                                0x4
+#define IMG_I2S_OUT_CTL_DATA_EN_MASK           BIT(24)
+#define IMG_I2S_OUT_CTL_ACTIVE_CHAN_MASK       0xffe000
+#define IMG_I2S_OUT_CTL_ACTIVE_CHAN_SHIFT      13
+#define IMG_I2S_OUT_CTL_FRM_SIZE_MASK          BIT(8)
+#define IMG_I2S_OUT_CTL_MASTER_MASK            BIT(6)
+#define IMG_I2S_OUT_CTL_CLK_MASK               BIT(5)
+#define IMG_I2S_OUT_CTL_CLK_EN_MASK            BIT(4)
+#define IMG_I2S_OUT_CTL_FRM_CLK_POL_MASK       BIT(3)
+#define IMG_I2S_OUT_CTL_BCLK_POL_MASK          BIT(2)
+#define IMG_I2S_OUT_CTL_ME_MASK                        BIT(0)
+
+#define IMG_I2S_OUT_CH_CTL                     0x4
+#define IMG_I2S_OUT_CHAN_CTL_CH_MASK           BIT(11)
+#define IMG_I2S_OUT_CHAN_CTL_LT_MASK           BIT(10)
+#define IMG_I2S_OUT_CHAN_CTL_FMT_MASK          0xf0
+#define IMG_I2S_OUT_CHAN_CTL_FMT_SHIFT         4
+#define IMG_I2S_OUT_CHAN_CTL_JUST_MASK         BIT(3)
+#define IMG_I2S_OUT_CHAN_CTL_CLKT_MASK         BIT(1)
+#define IMG_I2S_OUT_CHAN_CTL_ME_MASK           BIT(0)
+
+#define IMG_I2S_OUT_CH_STRIDE                  0x20
+
+struct img_i2s_out {
+       void __iomem *base;
+       struct clk *clk_sys;
+       struct clk *clk_ref;
+       struct snd_dmaengine_dai_dma_data dma_data;
+       struct device *dev;
+       unsigned int max_i2s_chan;
+       void __iomem *channel_base;
+       bool force_clk_active;
+       unsigned int active_channels;
+       struct reset_control *rst;
+       struct snd_soc_dai_driver dai_driver;
+};
+
+static int img_i2s_out_suspend(struct device *dev)
+{
+       struct img_i2s_out *i2s = dev_get_drvdata(dev);
+
+       if (!i2s->force_clk_active)
+               clk_disable_unprepare(i2s->clk_ref);
+
+       return 0;
+}
+
+static int img_i2s_out_resume(struct device *dev)
+{
+       struct img_i2s_out *i2s = dev_get_drvdata(dev);
+       int ret;
+
+       if (!i2s->force_clk_active) {
+               ret = clk_prepare_enable(i2s->clk_ref);
+               if (ret) {
+                       dev_err(dev, "clk_enable failed: %d\n", ret);
+                       return ret;
+               }
+       }
+
+       return 0;
+}
+
+static inline void img_i2s_out_writel(struct img_i2s_out *i2s, u32 val,
+                                       u32 reg)
+{
+       writel(val, i2s->base + reg);
+}
+
+static inline u32 img_i2s_out_readl(struct img_i2s_out *i2s, u32 reg)
+{
+       return readl(i2s->base + reg);
+}
+
+static inline void img_i2s_out_ch_writel(struct img_i2s_out *i2s,
+                                       u32 chan, u32 val, u32 reg)
+{
+       writel(val, i2s->channel_base + (chan * IMG_I2S_OUT_CH_STRIDE) + reg);
+}
+
+static inline u32 img_i2s_out_ch_readl(struct img_i2s_out *i2s, u32 chan,
+                                       u32 reg)
+{
+       return readl(i2s->channel_base + (chan * IMG_I2S_OUT_CH_STRIDE) + reg);
+}
+
+static inline void img_i2s_out_ch_disable(struct img_i2s_out *i2s, u32 chan)
+{
+       u32 reg;
+
+       reg = img_i2s_out_ch_readl(i2s, chan, IMG_I2S_OUT_CH_CTL);
+       reg &= ~IMG_I2S_OUT_CHAN_CTL_ME_MASK;
+       img_i2s_out_ch_writel(i2s, chan, reg, IMG_I2S_OUT_CH_CTL);
+}
+
+static inline void img_i2s_out_ch_enable(struct img_i2s_out *i2s, u32 chan)
+{
+       u32 reg;
+
+       reg = img_i2s_out_ch_readl(i2s, chan, IMG_I2S_OUT_CH_CTL);
+       reg |= IMG_I2S_OUT_CHAN_CTL_ME_MASK;
+       img_i2s_out_ch_writel(i2s, chan, reg, IMG_I2S_OUT_CH_CTL);
+}
+
+static inline void img_i2s_out_disable(struct img_i2s_out *i2s)
+{
+       u32 reg;
+
+       reg = img_i2s_out_readl(i2s, IMG_I2S_OUT_CTL);
+       reg &= ~IMG_I2S_OUT_CTL_ME_MASK;
+       img_i2s_out_writel(i2s, reg, IMG_I2S_OUT_CTL);
+}
+
+static inline void img_i2s_out_enable(struct img_i2s_out *i2s)
+{
+       u32 reg;
+
+       reg = img_i2s_out_readl(i2s, IMG_I2S_OUT_CTL);
+       reg |= IMG_I2S_OUT_CTL_ME_MASK;
+       img_i2s_out_writel(i2s, reg, IMG_I2S_OUT_CTL);
+}
+
+static void img_i2s_out_reset(struct img_i2s_out *i2s)
+{
+       int i;
+       u32 core_ctl, chan_ctl;
+
+       core_ctl = img_i2s_out_readl(i2s, IMG_I2S_OUT_CTL) &
+                       ~IMG_I2S_OUT_CTL_ME_MASK &
+                       ~IMG_I2S_OUT_CTL_DATA_EN_MASK;
+
+       if (!i2s->force_clk_active)
+               core_ctl &= ~IMG_I2S_OUT_CTL_CLK_EN_MASK;
+
+       chan_ctl = img_i2s_out_ch_readl(i2s, 0, IMG_I2S_OUT_CH_CTL) &
+                       ~IMG_I2S_OUT_CHAN_CTL_ME_MASK;
+
+       reset_control_assert(i2s->rst);
+       reset_control_deassert(i2s->rst);
+
+       for (i = 0; i < i2s->max_i2s_chan; i++)
+               img_i2s_out_ch_writel(i2s, i, chan_ctl, IMG_I2S_OUT_CH_CTL);
+
+       for (i = 0; i < i2s->active_channels; i++)
+               img_i2s_out_ch_enable(i2s, i);
+
+       img_i2s_out_writel(i2s, core_ctl, IMG_I2S_OUT_CTL);
+       img_i2s_out_enable(i2s);
+}
+
+static int img_i2s_out_trigger(struct snd_pcm_substream *substream, int cmd,
+       struct snd_soc_dai *dai)
+{
+       struct img_i2s_out *i2s = snd_soc_dai_get_drvdata(dai);
+       u32 reg;
+
+       switch (cmd) {
+       case SNDRV_PCM_TRIGGER_START:
+       case SNDRV_PCM_TRIGGER_RESUME:
+       case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+               reg = img_i2s_out_readl(i2s, IMG_I2S_OUT_CTL);
+               if (!i2s->force_clk_active)
+                       reg |= IMG_I2S_OUT_CTL_CLK_EN_MASK;
+               reg |= IMG_I2S_OUT_CTL_DATA_EN_MASK;
+               img_i2s_out_writel(i2s, reg, IMG_I2S_OUT_CTL);
+               break;
+       case SNDRV_PCM_TRIGGER_STOP:
+       case SNDRV_PCM_TRIGGER_SUSPEND:
+       case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+               img_i2s_out_reset(i2s);
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static int img_i2s_out_hw_params(struct snd_pcm_substream *substream,
+       struct snd_pcm_hw_params *params, struct snd_soc_dai *dai)
+{
+       struct img_i2s_out *i2s = snd_soc_dai_get_drvdata(dai);
+       unsigned int channels, i2s_channels;
+       long pre_div_a, pre_div_b, diff_a, diff_b, rate, clk_rate;
+       int i;
+       u32 reg, control_mask, control_set = 0;
+       snd_pcm_format_t format;
+
+       rate = params_rate(params);
+       format = params_format(params);
+       channels = params_channels(params);
+       i2s_channels = channels / 2;
+
+       if (format != SNDRV_PCM_FORMAT_S32_LE)
+               return -EINVAL;
+
+       if ((channels < 2) ||
+           (channels > (i2s->max_i2s_chan * 2)) ||
+           (channels % 2))
+               return -EINVAL;
+
+       pre_div_a = clk_round_rate(i2s->clk_ref, rate * 256);
+       if (pre_div_a < 0)
+               return pre_div_a;
+       pre_div_b = clk_round_rate(i2s->clk_ref, rate * 384);
+       if (pre_div_b < 0)
+               return pre_div_b;
+
+       diff_a = abs((pre_div_a / 256) - rate);
+       diff_b = abs((pre_div_b / 384) - rate);
+
+       /* If diffs are equal, use lower clock rate */
+       if (diff_a > diff_b)
+               clk_set_rate(i2s->clk_ref, pre_div_b);
+       else
+               clk_set_rate(i2s->clk_ref, pre_div_a);
+
+       /*
+        * Another driver (eg alsa machine driver) may have rejected the above
+        * change. Get the current rate and set the register bit according to
+        * the new minimum diff
+        */
+       clk_rate = clk_get_rate(i2s->clk_ref);
+
+       diff_a = abs((clk_rate / 256) - rate);
+       diff_b = abs((clk_rate / 384) - rate);
+
+       if (diff_a > diff_b)
+               control_set |= IMG_I2S_OUT_CTL_CLK_MASK;
+
+       control_set |= ((i2s_channels - 1) <<
+                      IMG_I2S_OUT_CTL_ACTIVE_CHAN_SHIFT) &
+                      IMG_I2S_OUT_CTL_ACTIVE_CHAN_MASK;
+
+       control_mask = IMG_I2S_OUT_CTL_CLK_MASK |
+                      IMG_I2S_OUT_CTL_ACTIVE_CHAN_MASK;
+
+       img_i2s_out_disable(i2s);
+
+       reg = img_i2s_out_readl(i2s, IMG_I2S_OUT_CTL);
+       reg = (reg & ~control_mask) | control_set;
+       img_i2s_out_writel(i2s, reg, IMG_I2S_OUT_CTL);
+
+       for (i = 0; i < i2s_channels; i++)
+               img_i2s_out_ch_enable(i2s, i);
+
+       for (; i < i2s->max_i2s_chan; i++)
+               img_i2s_out_ch_disable(i2s, i);
+
+       img_i2s_out_enable(i2s);
+
+       i2s->active_channels = i2s_channels;
+
+       return 0;
+}
+
+static int img_i2s_out_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
+{
+       struct img_i2s_out *i2s = snd_soc_dai_get_drvdata(dai);
+       int i;
+       bool force_clk_active;
+       u32 chan_control_mask, control_mask, chan_control_set = 0;
+       u32 reg, control_set = 0;
+
+       force_clk_active = ((fmt & SND_SOC_DAIFMT_CLOCK_MASK) ==
+                       SND_SOC_DAIFMT_CONT);
+
+       if (force_clk_active)
+               control_set |= IMG_I2S_OUT_CTL_CLK_EN_MASK;
+
+       switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+       case SND_SOC_DAIFMT_CBM_CFM:
+               break;
+       case SND_SOC_DAIFMT_CBS_CFS:
+               control_set |= IMG_I2S_OUT_CTL_MASTER_MASK;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+       case SND_SOC_DAIFMT_NB_NF:
+               control_set |= IMG_I2S_OUT_CTL_BCLK_POL_MASK;
+               break;
+       case SND_SOC_DAIFMT_NB_IF:
+               control_set |= IMG_I2S_OUT_CTL_BCLK_POL_MASK;
+               control_set |= IMG_I2S_OUT_CTL_FRM_CLK_POL_MASK;
+               break;
+       case SND_SOC_DAIFMT_IB_NF:
+               break;
+       case SND_SOC_DAIFMT_IB_IF:
+               control_set |= IMG_I2S_OUT_CTL_FRM_CLK_POL_MASK;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+       case SND_SOC_DAIFMT_I2S:
+               chan_control_set |= IMG_I2S_OUT_CHAN_CTL_CLKT_MASK;
+               break;
+       case SND_SOC_DAIFMT_LEFT_J:
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       control_mask = IMG_I2S_OUT_CTL_CLK_EN_MASK |
+                      IMG_I2S_OUT_CTL_MASTER_MASK |
+                      IMG_I2S_OUT_CTL_BCLK_POL_MASK |
+                      IMG_I2S_OUT_CTL_FRM_CLK_POL_MASK;
+
+       chan_control_mask = IMG_I2S_OUT_CHAN_CTL_CLKT_MASK;
+
+       img_i2s_out_disable(i2s);
+
+       reg = img_i2s_out_readl(i2s, IMG_I2S_OUT_CTL);
+       reg = (reg & ~control_mask) | control_set;
+       img_i2s_out_writel(i2s, reg, IMG_I2S_OUT_CTL);
+
+       for (i = 0; i < i2s->active_channels; i++)
+               img_i2s_out_ch_disable(i2s, i);
+
+       for (i = 0; i < i2s->max_i2s_chan; i++) {
+               reg = img_i2s_out_ch_readl(i2s, i, IMG_I2S_OUT_CH_CTL);
+               reg = (reg & ~chan_control_mask) | chan_control_set;
+               img_i2s_out_ch_writel(i2s, i, reg, IMG_I2S_OUT_CH_CTL);
+       }
+
+       for (i = 0; i < i2s->active_channels; i++)
+               img_i2s_out_ch_enable(i2s, i);
+
+       img_i2s_out_enable(i2s);
+
+       i2s->force_clk_active = force_clk_active;
+
+       return 0;
+}
+
+static const struct snd_soc_dai_ops img_i2s_out_dai_ops = {
+       .trigger = img_i2s_out_trigger,
+       .hw_params = img_i2s_out_hw_params,
+       .set_fmt = img_i2s_out_set_fmt
+};
+
+static int img_i2s_out_dai_probe(struct snd_soc_dai *dai)
+{
+       struct img_i2s_out *i2s = snd_soc_dai_get_drvdata(dai);
+
+       snd_soc_dai_init_dma_data(dai, &i2s->dma_data, NULL);
+
+       return 0;
+}
+
+static const struct snd_soc_component_driver img_i2s_out_component = {
+       .name = "img-i2s-out"
+};
+
+static int img_i2s_out_dma_prepare_slave_config(struct snd_pcm_substream *st,
+       struct snd_pcm_hw_params *params, struct dma_slave_config *sc)
+{
+       unsigned int i2s_channels = params_channels(params) / 2;
+       struct snd_soc_pcm_runtime *rtd = st->private_data;
+       struct snd_dmaengine_dai_dma_data *dma_data;
+       int ret;
+
+       dma_data = snd_soc_dai_get_dma_data(rtd->cpu_dai, st);
+
+       ret = snd_hwparams_to_dma_slave_config(st, params, sc);
+       if (ret)
+               return ret;
+
+       sc->dst_addr = dma_data->addr;
+       sc->dst_addr_width = dma_data->addr_width;
+       sc->dst_maxburst = 4 * i2s_channels;
+
+       return 0;
+}
+
+static const struct snd_dmaengine_pcm_config img_i2s_out_dma_config = {
+       .prepare_slave_config = img_i2s_out_dma_prepare_slave_config
+};
+
+static int img_i2s_out_probe(struct platform_device *pdev)
+{
+       struct img_i2s_out *i2s;
+       struct resource *res;
+       void __iomem *base;
+       int i, ret;
+       unsigned int max_i2s_chan_pow_2;
+       u32 reg;
+       struct device *dev = &pdev->dev;
+
+       i2s = devm_kzalloc(&pdev->dev, sizeof(*i2s), GFP_KERNEL);
+       if (!i2s)
+               return -ENOMEM;
+
+       platform_set_drvdata(pdev, i2s);
+
+       i2s->dev = &pdev->dev;
+
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       base = devm_ioremap_resource(&pdev->dev, res);
+       if (IS_ERR(base))
+               return PTR_ERR(base);
+
+       i2s->base = base;
+
+       if (of_property_read_u32(pdev->dev.of_node, "img,i2s-channels",
+                       &i2s->max_i2s_chan)) {
+               dev_err(&pdev->dev, "No img,i2s-channels property\n");
+               return -EINVAL;
+       }
+
+       max_i2s_chan_pow_2 = 1 << get_count_order(i2s->max_i2s_chan);
+
+       i2s->channel_base = base + (max_i2s_chan_pow_2 * 0x20);
+
+       i2s->rst = devm_reset_control_get(&pdev->dev, "rst");
+       if (IS_ERR(i2s->rst)) {
+               if (PTR_ERR(i2s->rst) != -EPROBE_DEFER)
+                       dev_err(&pdev->dev, "No top level reset found\n");
+               return PTR_ERR(i2s->rst);
+       }
+
+       i2s->clk_sys = devm_clk_get(&pdev->dev, "sys");
+       if (IS_ERR(i2s->clk_sys)) {
+               if (PTR_ERR(i2s->clk_sys) != -EPROBE_DEFER)
+                       dev_err(dev, "Failed to acquire clock 'sys'\n");
+               return PTR_ERR(i2s->clk_sys);
+       }
+
+       i2s->clk_ref = devm_clk_get(&pdev->dev, "ref");
+       if (IS_ERR(i2s->clk_ref)) {
+               if (PTR_ERR(i2s->clk_ref) != -EPROBE_DEFER)
+                       dev_err(dev, "Failed to acquire clock 'ref'\n");
+               return PTR_ERR(i2s->clk_ref);
+       }
+
+       ret = clk_prepare_enable(i2s->clk_sys);
+       if (ret)
+               return ret;
+
+       reg = IMG_I2S_OUT_CTL_FRM_SIZE_MASK;
+       img_i2s_out_writel(i2s, reg, IMG_I2S_OUT_CTL);
+
+       reg = IMG_I2S_OUT_CHAN_CTL_JUST_MASK |
+               IMG_I2S_OUT_CHAN_CTL_LT_MASK |
+               IMG_I2S_OUT_CHAN_CTL_CH_MASK |
+               (8 << IMG_I2S_OUT_CHAN_CTL_FMT_SHIFT);
+
+       for (i = 0; i < i2s->max_i2s_chan; i++)
+               img_i2s_out_ch_writel(i2s, i, reg, IMG_I2S_OUT_CH_CTL);
+
+       img_i2s_out_reset(i2s);
+
+       pm_runtime_enable(&pdev->dev);
+       if (!pm_runtime_enabled(&pdev->dev)) {
+               ret = img_i2s_out_resume(&pdev->dev);
+               if (ret)
+                       goto err_pm_disable;
+       }
+
+       i2s->active_channels = 1;
+       i2s->dma_data.addr = res->start + IMG_I2S_OUT_TX_FIFO;
+       i2s->dma_data.addr_width = 4;
+       i2s->dma_data.maxburst = 4;
+
+       i2s->dai_driver.probe = img_i2s_out_dai_probe;
+       i2s->dai_driver.playback.channels_min = 2;
+       i2s->dai_driver.playback.channels_max = i2s->max_i2s_chan * 2;
+       i2s->dai_driver.playback.rates = SNDRV_PCM_RATE_8000_192000;
+       i2s->dai_driver.playback.formats = SNDRV_PCM_FMTBIT_S32_LE;
+       i2s->dai_driver.ops = &img_i2s_out_dai_ops;
+
+       ret = devm_snd_soc_register_component(&pdev->dev,
+                       &img_i2s_out_component, &i2s->dai_driver, 1);
+       if (ret)
+               goto err_suspend;
+
+       ret = devm_snd_dmaengine_pcm_register(&pdev->dev,
+                       &img_i2s_out_dma_config, 0);
+       if (ret)
+               goto err_suspend;
+
+       return 0;
+
+err_suspend:
+       if (!pm_runtime_status_suspended(&pdev->dev))
+               img_i2s_out_suspend(&pdev->dev);
+err_pm_disable:
+       pm_runtime_disable(&pdev->dev);
+       clk_disable_unprepare(i2s->clk_sys);
+
+       return ret;
+}
+
+static int img_i2s_out_dev_remove(struct platform_device *pdev)
+{
+       struct img_i2s_out *i2s = platform_get_drvdata(pdev);
+
+       pm_runtime_disable(&pdev->dev);
+       if (!pm_runtime_status_suspended(&pdev->dev))
+               img_i2s_out_suspend(&pdev->dev);
+
+       clk_disable_unprepare(i2s->clk_sys);
+
+       return 0;
+}
+
+static const struct of_device_id img_i2s_out_of_match[] = {
+       { .compatible = "img,i2s-out" },
+       {}
+};
+MODULE_DEVICE_TABLE(of, img_i2s_out_of_match);
+
+static const struct dev_pm_ops img_i2s_out_pm_ops = {
+       SET_RUNTIME_PM_OPS(img_i2s_out_suspend,
+                          img_i2s_out_resume, NULL)
+};
+
+static struct platform_driver img_i2s_out_driver = {
+       .driver = {
+               .name = "img-i2s-out",
+               .of_match_table = img_i2s_out_of_match,
+               .pm = &img_i2s_out_pm_ops
+       },
+       .probe = img_i2s_out_probe,
+       .remove = img_i2s_out_dev_remove
+};
+module_platform_driver(img_i2s_out_driver);
+
+MODULE_AUTHOR("Damien Horsley <Damien.Horsley@imgtec.com>");
+MODULE_DESCRIPTION("IMG I2S Output Driver");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/img/img-parallel-out.c b/sound/soc/img/img-parallel-out.c
new file mode 100644 (file)
index 0000000..c1610a0
--- /dev/null
@@ -0,0 +1,327 @@
+/*
+ * IMG parallel output controller driver
+ *
+ * Copyright (C) 2015 Imagination Technologies Ltd.
+ *
+ * Author: Damien Horsley <Damien.Horsley@imgtec.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.
+ */
+
+#include <linux/clk.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/reset.h>
+
+#include <sound/core.h>
+#include <sound/dmaengine_pcm.h>
+#include <sound/initval.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+
+#define IMG_PRL_OUT_TX_FIFO            0
+
+#define IMG_PRL_OUT_CTL                        0x4
+#define IMG_PRL_OUT_CTL_CH_MASK                BIT(4)
+#define IMG_PRL_OUT_CTL_PACKH_MASK     BIT(3)
+#define IMG_PRL_OUT_CTL_EDGE_MASK      BIT(2)
+#define IMG_PRL_OUT_CTL_ME_MASK                BIT(1)
+#define IMG_PRL_OUT_CTL_SRST_MASK      BIT(0)
+
+struct img_prl_out {
+       void __iomem *base;
+       struct clk *clk_sys;
+       struct clk *clk_ref;
+       struct snd_dmaengine_dai_dma_data dma_data;
+       struct device *dev;
+       struct reset_control *rst;
+};
+
+static int img_prl_out_suspend(struct device *dev)
+{
+       struct img_prl_out *prl = dev_get_drvdata(dev);
+
+       clk_disable_unprepare(prl->clk_ref);
+
+       return 0;
+}
+
+static int img_prl_out_resume(struct device *dev)
+{
+       struct img_prl_out *prl = dev_get_drvdata(dev);
+       int ret;
+
+       ret = clk_prepare_enable(prl->clk_ref);
+       if (ret) {
+               dev_err(dev, "clk_enable failed: %d\n", ret);
+               return ret;
+       }
+
+       return 0;
+}
+
+static inline void img_prl_out_writel(struct img_prl_out *prl,
+                               u32 val, u32 reg)
+{
+       writel(val, prl->base + reg);
+}
+
+static inline u32 img_prl_out_readl(struct img_prl_out *prl, u32 reg)
+{
+       return readl(prl->base + reg);
+}
+
+static void img_prl_out_reset(struct img_prl_out *prl)
+{
+       u32 ctl;
+
+       ctl = img_prl_out_readl(prl, IMG_PRL_OUT_CTL) &
+                       ~IMG_PRL_OUT_CTL_ME_MASK;
+
+       reset_control_assert(prl->rst);
+       reset_control_deassert(prl->rst);
+
+       img_prl_out_writel(prl, ctl, IMG_PRL_OUT_CTL);
+}
+
+static int img_prl_out_trigger(struct snd_pcm_substream *substream, int cmd,
+                       struct snd_soc_dai *dai)
+{
+       struct img_prl_out *prl = snd_soc_dai_get_drvdata(dai);
+       u32 reg;
+
+       switch (cmd) {
+       case SNDRV_PCM_TRIGGER_START:
+       case SNDRV_PCM_TRIGGER_RESUME:
+       case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+               reg = img_prl_out_readl(prl, IMG_PRL_OUT_CTL);
+               reg |= IMG_PRL_OUT_CTL_ME_MASK;
+               img_prl_out_writel(prl, reg, IMG_PRL_OUT_CTL);
+               break;
+       case SNDRV_PCM_TRIGGER_STOP:
+       case SNDRV_PCM_TRIGGER_SUSPEND:
+       case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+               img_prl_out_reset(prl);
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static int img_prl_out_hw_params(struct snd_pcm_substream *substream,
+       struct snd_pcm_hw_params *params, struct snd_soc_dai *dai)
+{
+       struct img_prl_out *prl = snd_soc_dai_get_drvdata(dai);
+       unsigned int rate, channels;
+       u32 reg, control_set = 0;
+       snd_pcm_format_t format;
+
+       rate = params_rate(params);
+       format = params_format(params);
+       channels = params_channels(params);
+
+       switch (params_format(params)) {
+       case SNDRV_PCM_FORMAT_S32_LE:
+               control_set |= IMG_PRL_OUT_CTL_PACKH_MASK;
+               break;
+       case SNDRV_PCM_FORMAT_S24_LE:
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       if (channels != 2)
+               return -EINVAL;
+
+       clk_set_rate(prl->clk_ref, rate * 256);
+
+       reg = img_prl_out_readl(prl, IMG_PRL_OUT_CTL);
+       reg = (reg & ~IMG_PRL_OUT_CTL_PACKH_MASK) | control_set;
+       img_prl_out_writel(prl, reg, IMG_PRL_OUT_CTL);
+
+       return 0;
+}
+
+static int img_prl_out_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
+{
+       struct img_prl_out *prl = snd_soc_dai_get_drvdata(dai);
+       u32 reg, control_set = 0;
+
+       switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+       case SND_SOC_DAIFMT_NB_NF:
+               break;
+       case SND_SOC_DAIFMT_NB_IF:
+               control_set |= IMG_PRL_OUT_CTL_EDGE_MASK;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       reg = img_prl_out_readl(prl, IMG_PRL_OUT_CTL);
+       reg = (reg & ~IMG_PRL_OUT_CTL_EDGE_MASK) | control_set;
+       img_prl_out_writel(prl, reg, IMG_PRL_OUT_CTL);
+
+       return 0;
+}
+
+static const struct snd_soc_dai_ops img_prl_out_dai_ops = {
+       .trigger = img_prl_out_trigger,
+       .hw_params = img_prl_out_hw_params,
+       .set_fmt = img_prl_out_set_fmt
+};
+
+static int img_prl_out_dai_probe(struct snd_soc_dai *dai)
+{
+       struct img_prl_out *prl = snd_soc_dai_get_drvdata(dai);
+
+       snd_soc_dai_init_dma_data(dai, &prl->dma_data, NULL);
+
+       return 0;
+}
+
+static struct snd_soc_dai_driver img_prl_out_dai = {
+       .probe = img_prl_out_dai_probe,
+       .playback = {
+               .channels_min = 2,
+               .channels_max = 2,
+               .rates = SNDRV_PCM_RATE_8000_192000,
+               .formats = SNDRV_PCM_FMTBIT_S32_LE | SNDRV_PCM_FMTBIT_S24_LE
+       },
+       .ops = &img_prl_out_dai_ops
+};
+
+static const struct snd_soc_component_driver img_prl_out_component = {
+       .name = "img-prl-out"
+};
+
+static int img_prl_out_probe(struct platform_device *pdev)
+{
+       struct img_prl_out *prl;
+       struct resource *res;
+       void __iomem *base;
+       int ret;
+       struct device *dev = &pdev->dev;
+
+       prl = devm_kzalloc(&pdev->dev, sizeof(*prl), GFP_KERNEL);
+       if (!prl)
+               return -ENOMEM;
+
+       platform_set_drvdata(pdev, prl);
+
+       prl->dev = &pdev->dev;
+
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       base = devm_ioremap_resource(&pdev->dev, res);
+       if (IS_ERR(base))
+               return PTR_ERR(base);
+
+       prl->base = base;
+
+       prl->rst = devm_reset_control_get(&pdev->dev, "rst");
+       if (IS_ERR(prl->rst)) {
+               if (PTR_ERR(prl->rst) != -EPROBE_DEFER)
+                       dev_err(&pdev->dev, "No top level reset found\n");
+               return PTR_ERR(prl->rst);
+       }
+
+       prl->clk_sys = devm_clk_get(&pdev->dev, "sys");
+       if (IS_ERR(prl->clk_sys)) {
+               if (PTR_ERR(prl->clk_sys) != -EPROBE_DEFER)
+                       dev_err(dev, "Failed to acquire clock 'sys'\n");
+               return PTR_ERR(prl->clk_sys);
+       }
+
+       prl->clk_ref = devm_clk_get(&pdev->dev, "ref");
+       if (IS_ERR(prl->clk_ref)) {
+               if (PTR_ERR(prl->clk_ref) != -EPROBE_DEFER)
+                       dev_err(dev, "Failed to acquire clock 'ref'\n");
+               return PTR_ERR(prl->clk_ref);
+       }
+
+       ret = clk_prepare_enable(prl->clk_sys);
+       if (ret)
+               return ret;
+
+       img_prl_out_writel(prl, IMG_PRL_OUT_CTL_EDGE_MASK, IMG_PRL_OUT_CTL);
+       img_prl_out_reset(prl);
+
+       pm_runtime_enable(&pdev->dev);
+       if (!pm_runtime_enabled(&pdev->dev)) {
+               ret = img_prl_out_resume(&pdev->dev);
+               if (ret)
+                       goto err_pm_disable;
+       }
+
+       prl->dma_data.addr = res->start + IMG_PRL_OUT_TX_FIFO;
+       prl->dma_data.addr_width = 4;
+       prl->dma_data.maxburst = 4;
+
+       ret = devm_snd_soc_register_component(&pdev->dev,
+                       &img_prl_out_component,
+                       &img_prl_out_dai, 1);
+       if (ret)
+               goto err_suspend;
+
+       ret = devm_snd_dmaengine_pcm_register(&pdev->dev, NULL, 0);
+       if (ret)
+               goto err_suspend;
+
+       return 0;
+
+err_suspend:
+       if (!pm_runtime_status_suspended(&pdev->dev))
+               img_prl_out_suspend(&pdev->dev);
+err_pm_disable:
+       pm_runtime_disable(&pdev->dev);
+       clk_disable_unprepare(prl->clk_sys);
+
+       return ret;
+}
+
+static int img_prl_out_dev_remove(struct platform_device *pdev)
+{
+       struct img_prl_out *prl = platform_get_drvdata(pdev);
+
+       pm_runtime_disable(&pdev->dev);
+       if (!pm_runtime_status_suspended(&pdev->dev))
+               img_prl_out_suspend(&pdev->dev);
+
+       clk_disable_unprepare(prl->clk_sys);
+
+       return 0;
+}
+
+static const struct of_device_id img_prl_out_of_match[] = {
+       { .compatible = "img,parallel-out" },
+       {}
+};
+MODULE_DEVICE_TABLE(of, img_prl_out_of_match);
+
+static const struct dev_pm_ops img_prl_out_pm_ops = {
+       SET_RUNTIME_PM_OPS(img_prl_out_suspend,
+                          img_prl_out_resume, NULL)
+};
+
+static struct platform_driver img_prl_out_driver = {
+       .driver = {
+               .name = "img-parallel-out",
+               .of_match_table = img_prl_out_of_match,
+               .pm = &img_prl_out_pm_ops
+       },
+       .probe = img_prl_out_probe,
+       .remove = img_prl_out_dev_remove
+};
+module_platform_driver(img_prl_out_driver);
+
+MODULE_AUTHOR("Damien Horsley <Damien.Horsley@imgtec.com>");
+MODULE_DESCRIPTION("IMG Parallel Output Driver");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/img/img-spdif-in.c b/sound/soc/img/img-spdif-in.c
new file mode 100644 (file)
index 0000000..4d9953d
--- /dev/null
@@ -0,0 +1,806 @@
+/*
+ * IMG SPDIF input controller driver
+ *
+ * Copyright (C) 2015 Imagination Technologies Ltd.
+ *
+ * Author: Damien Horsley <Damien.Horsley@imgtec.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.
+ */
+
+#include <linux/clk.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/reset.h>
+
+#include <sound/core.h>
+#include <sound/dmaengine_pcm.h>
+#include <sound/initval.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+
+#define IMG_SPDIF_IN_RX_FIFO_OFFSET            0
+
+#define IMG_SPDIF_IN_CTL                       0x4
+#define IMG_SPDIF_IN_CTL_LOCKLO_MASK           0xff
+#define IMG_SPDIF_IN_CTL_LOCKLO_SHIFT          0
+#define IMG_SPDIF_IN_CTL_LOCKHI_MASK           0xff00
+#define IMG_SPDIF_IN_CTL_LOCKHI_SHIFT          8
+#define IMG_SPDIF_IN_CTL_TRK_MASK              0xff0000
+#define IMG_SPDIF_IN_CTL_TRK_SHIFT             16
+#define IMG_SPDIF_IN_CTL_SRD_MASK              0x70000000
+#define IMG_SPDIF_IN_CTL_SRD_SHIFT             28
+#define IMG_SPDIF_IN_CTL_SRT_MASK              BIT(31)
+
+#define IMG_SPDIF_IN_STATUS                    0x8
+#define IMG_SPDIF_IN_STATUS_SAM_MASK           0x7000
+#define IMG_SPDIF_IN_STATUS_SAM_SHIFT          12
+#define IMG_SPDIF_IN_STATUS_LOCK_MASK          BIT(15)
+#define IMG_SPDIF_IN_STATUS_LOCK_SHIFT         15
+
+#define IMG_SPDIF_IN_CLKGEN                    0x1c
+#define IMG_SPDIF_IN_CLKGEN_NOM_MASK           0x3ff
+#define IMG_SPDIF_IN_CLKGEN_NOM_SHIFT          0
+#define IMG_SPDIF_IN_CLKGEN_HLD_MASK           0x3ff0000
+#define IMG_SPDIF_IN_CLKGEN_HLD_SHIFT          16
+
+#define IMG_SPDIF_IN_CSL                       0x20
+
+#define IMG_SPDIF_IN_CSH                       0x24
+#define IMG_SPDIF_IN_CSH_MASK                  0xff
+#define IMG_SPDIF_IN_CSH_SHIFT                 0
+
+#define IMG_SPDIF_IN_SOFT_RESET                        0x28
+#define IMG_SPDIF_IN_SOFT_RESET_MASK           BIT(0)
+
+#define IMG_SPDIF_IN_ACLKGEN_START             0x2c
+#define IMG_SPDIF_IN_ACLKGEN_NOM_MASK          0x3ff
+#define IMG_SPDIF_IN_ACLKGEN_NOM_SHIFT         0
+#define IMG_SPDIF_IN_ACLKGEN_HLD_MASK          0xffc00
+#define IMG_SPDIF_IN_ACLKGEN_HLD_SHIFT         10
+#define IMG_SPDIF_IN_ACLKGEN_TRK_MASK          0xff00000
+#define IMG_SPDIF_IN_ACLKGEN_TRK_SHIFT         20
+
+#define IMG_SPDIF_IN_NUM_ACLKGEN               4
+
+struct img_spdif_in {
+       spinlock_t lock;
+       void __iomem *base;
+       struct clk *clk_sys;
+       struct snd_dmaengine_dai_dma_data dma_data;
+       struct device *dev;
+       unsigned int trk;
+       bool multi_freq;
+       int lock_acquire;
+       int lock_release;
+       unsigned int single_freq;
+       unsigned int multi_freqs[IMG_SPDIF_IN_NUM_ACLKGEN];
+       bool active;
+
+       /* Write-only registers */
+       unsigned int aclkgen_regs[IMG_SPDIF_IN_NUM_ACLKGEN];
+};
+
+static inline void img_spdif_in_writel(struct img_spdif_in *spdif,
+                                       u32 val, u32 reg)
+{
+       writel(val, spdif->base + reg);
+}
+
+static inline u32 img_spdif_in_readl(struct img_spdif_in *spdif, u32 reg)
+{
+       return readl(spdif->base + reg);
+}
+
+static inline void img_spdif_in_aclkgen_writel(struct img_spdif_in *spdif,
+                                               u32 index)
+{
+       img_spdif_in_writel(spdif, spdif->aclkgen_regs[index],
+                       IMG_SPDIF_IN_ACLKGEN_START + (index * 0x4));
+}
+
+static int img_spdif_in_check_max_rate(struct img_spdif_in *spdif,
+               unsigned int sample_rate, unsigned long *actual_freq)
+{
+       unsigned long min_freq, freq_t;
+
+       /* Clock rate must be at least 24x the bit rate */
+       min_freq = sample_rate * 2 * 32 * 24;
+
+       freq_t = clk_get_rate(spdif->clk_sys);
+
+       if (freq_t < min_freq)
+               return -EINVAL;
+
+       *actual_freq = freq_t;
+
+       return 0;
+}
+
+static int img_spdif_in_do_clkgen_calc(unsigned int rate, unsigned int *pnom,
+               unsigned int *phld, unsigned long clk_rate)
+{
+       unsigned int ori, nom, hld;
+
+       /*
+        * Calculate oversampling ratio, nominal phase increment and hold
+        * increment for the given rate / frequency
+        */
+
+       if (!rate)
+               return -EINVAL;
+
+       ori = clk_rate / (rate * 64);
+
+       if (!ori)
+               return -EINVAL;
+
+       nom = (4096 / ori) + 1;
+       do
+               hld = 4096 - (--nom * (ori - 1));
+       while (hld < 120);
+
+       *pnom = nom;
+       *phld = hld;
+
+       return 0;
+}
+
+static int img_spdif_in_do_clkgen_single(struct img_spdif_in *spdif,
+               unsigned int rate)
+{
+       unsigned int nom, hld;
+       unsigned long flags, clk_rate;
+       int ret = 0;
+       u32 reg;
+
+       ret = img_spdif_in_check_max_rate(spdif, rate, &clk_rate);
+       if (ret)
+               return ret;
+
+       ret = img_spdif_in_do_clkgen_calc(rate, &nom, &hld, clk_rate);
+       if (ret)
+               return ret;
+
+       reg = (nom << IMG_SPDIF_IN_CLKGEN_NOM_SHIFT) &
+               IMG_SPDIF_IN_CLKGEN_NOM_MASK;
+       reg |= (hld << IMG_SPDIF_IN_CLKGEN_HLD_SHIFT) &
+               IMG_SPDIF_IN_CLKGEN_HLD_MASK;
+
+       spin_lock_irqsave(&spdif->lock, flags);
+
+       if (spdif->active) {
+               spin_unlock_irqrestore(&spdif->lock, flags);
+               return -EBUSY;
+       }
+
+       img_spdif_in_writel(spdif, reg, IMG_SPDIF_IN_CLKGEN);
+
+       spdif->single_freq = rate;
+
+       spin_unlock_irqrestore(&spdif->lock, flags);
+
+       return 0;
+}
+
+static int img_spdif_in_do_clkgen_multi(struct img_spdif_in *spdif,
+               unsigned int multi_freqs[])
+{
+       unsigned int nom, hld, rate, max_rate = 0;
+       unsigned long flags, clk_rate;
+       int i, ret = 0;
+       u32 reg, trk_reg, temp_regs[IMG_SPDIF_IN_NUM_ACLKGEN];
+
+       for (i = 0; i < IMG_SPDIF_IN_NUM_ACLKGEN; i++)
+               if (multi_freqs[i] > max_rate)
+                       max_rate = multi_freqs[i];
+
+       ret = img_spdif_in_check_max_rate(spdif, max_rate, &clk_rate);
+       if (ret)
+               return ret;
+
+       for (i = 0; i < IMG_SPDIF_IN_NUM_ACLKGEN; i++) {
+               rate = multi_freqs[i];
+
+               ret = img_spdif_in_do_clkgen_calc(rate, &nom, &hld, clk_rate);
+               if (ret)
+                       return ret;
+
+               reg = (nom << IMG_SPDIF_IN_ACLKGEN_NOM_SHIFT) &
+                       IMG_SPDIF_IN_ACLKGEN_NOM_MASK;
+               reg |= (hld << IMG_SPDIF_IN_ACLKGEN_HLD_SHIFT) &
+                       IMG_SPDIF_IN_ACLKGEN_HLD_MASK;
+               temp_regs[i] = reg;
+       }
+
+       spin_lock_irqsave(&spdif->lock, flags);
+
+       if (spdif->active) {
+               spin_unlock_irqrestore(&spdif->lock, flags);
+               return -EBUSY;
+       }
+
+       trk_reg = spdif->trk << IMG_SPDIF_IN_ACLKGEN_TRK_SHIFT;
+
+       for (i = 0; i < IMG_SPDIF_IN_NUM_ACLKGEN; i++) {
+               spdif->aclkgen_regs[i] = temp_regs[i] | trk_reg;
+               img_spdif_in_aclkgen_writel(spdif, i);
+       }
+
+       spdif->multi_freq = true;
+       spdif->multi_freqs[0] = multi_freqs[0];
+       spdif->multi_freqs[1] = multi_freqs[1];
+       spdif->multi_freqs[2] = multi_freqs[2];
+       spdif->multi_freqs[3] = multi_freqs[3];
+
+       spin_unlock_irqrestore(&spdif->lock, flags);
+
+       return 0;
+}
+
+static int img_spdif_in_iec958_info(struct snd_kcontrol *kcontrol,
+               struct snd_ctl_elem_info *uinfo)
+{
+       uinfo->type = SNDRV_CTL_ELEM_TYPE_IEC958;
+       uinfo->count = 1;
+
+       return 0;
+}
+
+static int img_spdif_in_get_status_mask(struct snd_kcontrol *kcontrol,
+                                      struct snd_ctl_elem_value *ucontrol)
+{
+       ucontrol->value.iec958.status[0] = 0xff;
+       ucontrol->value.iec958.status[1] = 0xff;
+       ucontrol->value.iec958.status[2] = 0xff;
+       ucontrol->value.iec958.status[3] = 0xff;
+       ucontrol->value.iec958.status[4] = 0xff;
+
+       return 0;
+}
+
+static int img_spdif_in_get_status(struct snd_kcontrol *kcontrol,
+                                 struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_dai *cpu_dai = snd_kcontrol_chip(kcontrol);
+       struct img_spdif_in *spdif = snd_soc_dai_get_drvdata(cpu_dai);
+       u32 reg;
+
+       reg = img_spdif_in_readl(spdif, IMG_SPDIF_IN_CSL);
+       ucontrol->value.iec958.status[0] = reg & 0xff;
+       ucontrol->value.iec958.status[1] = (reg >> 8) & 0xff;
+       ucontrol->value.iec958.status[2] = (reg >> 16) & 0xff;
+       ucontrol->value.iec958.status[3] = (reg >> 24) & 0xff;
+       reg = img_spdif_in_readl(spdif, IMG_SPDIF_IN_CSH);
+       ucontrol->value.iec958.status[4] = (reg & IMG_SPDIF_IN_CSH_MASK)
+               >> IMG_SPDIF_IN_CSH_SHIFT;
+
+       return 0;
+}
+
+static int img_spdif_in_info_multi_freq(struct snd_kcontrol *kcontrol,
+               struct snd_ctl_elem_info *uinfo)
+{
+       uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+       uinfo->count = IMG_SPDIF_IN_NUM_ACLKGEN;
+       uinfo->value.integer.min = 0;
+       uinfo->value.integer.max = LONG_MAX;
+
+       return 0;
+}
+
+static int img_spdif_in_get_multi_freq(struct snd_kcontrol *kcontrol,
+                                 struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_dai *cpu_dai = snd_kcontrol_chip(kcontrol);
+       struct img_spdif_in *spdif = snd_soc_dai_get_drvdata(cpu_dai);
+       unsigned long flags;
+
+       spin_lock_irqsave(&spdif->lock, flags);
+       if (spdif->multi_freq) {
+               ucontrol->value.integer.value[0] = spdif->multi_freqs[0];
+               ucontrol->value.integer.value[1] = spdif->multi_freqs[1];
+               ucontrol->value.integer.value[2] = spdif->multi_freqs[2];
+               ucontrol->value.integer.value[3] = spdif->multi_freqs[3];
+       } else {
+               ucontrol->value.integer.value[0] = 0;
+               ucontrol->value.integer.value[1] = 0;
+               ucontrol->value.integer.value[2] = 0;
+               ucontrol->value.integer.value[3] = 0;
+       }
+       spin_unlock_irqrestore(&spdif->lock, flags);
+
+       return 0;
+}
+
+static int img_spdif_in_set_multi_freq(struct snd_kcontrol *kcontrol,
+                                 struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_dai *cpu_dai = snd_kcontrol_chip(kcontrol);
+       struct img_spdif_in *spdif = snd_soc_dai_get_drvdata(cpu_dai);
+       unsigned int multi_freqs[IMG_SPDIF_IN_NUM_ACLKGEN];
+       bool multi_freq;
+       unsigned long flags;
+
+       if ((ucontrol->value.integer.value[0] == 0) &&
+                       (ucontrol->value.integer.value[1] == 0) &&
+                       (ucontrol->value.integer.value[2] == 0) &&
+                       (ucontrol->value.integer.value[3] == 0)) {
+               multi_freq = false;
+       } else {
+               multi_freqs[0] = ucontrol->value.integer.value[0];
+               multi_freqs[1] = ucontrol->value.integer.value[1];
+               multi_freqs[2] = ucontrol->value.integer.value[2];
+               multi_freqs[3] = ucontrol->value.integer.value[3];
+               multi_freq = true;
+       }
+
+       if (multi_freq)
+               return img_spdif_in_do_clkgen_multi(spdif, multi_freqs);
+
+       spin_lock_irqsave(&spdif->lock, flags);
+
+       if (spdif->active) {
+               spin_unlock_irqrestore(&spdif->lock, flags);
+               return -EBUSY;
+       }
+
+       spdif->multi_freq = false;
+
+       spin_unlock_irqrestore(&spdif->lock, flags);
+
+       return 0;
+}
+
+static int img_spdif_in_info_lock_freq(struct snd_kcontrol *kcontrol,
+               struct snd_ctl_elem_info *uinfo)
+{
+       uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+       uinfo->count = 1;
+       uinfo->value.integer.min = 0;
+       uinfo->value.integer.max = LONG_MAX;
+
+       return 0;
+}
+
+static int img_spdif_in_get_lock_freq(struct snd_kcontrol *kcontrol,
+                                 struct snd_ctl_elem_value *uc)
+{
+       struct snd_soc_dai *cpu_dai = snd_kcontrol_chip(kcontrol);
+       struct img_spdif_in *spdif = snd_soc_dai_get_drvdata(cpu_dai);
+       u32 reg;
+       int i;
+       unsigned long flags;
+
+       spin_lock_irqsave(&spdif->lock, flags);
+
+       reg = img_spdif_in_readl(spdif, IMG_SPDIF_IN_STATUS);
+       if (reg & IMG_SPDIF_IN_STATUS_LOCK_MASK) {
+               if (spdif->multi_freq) {
+                       i = ((reg & IMG_SPDIF_IN_STATUS_SAM_MASK) >>
+                                       IMG_SPDIF_IN_STATUS_SAM_SHIFT) - 1;
+                       uc->value.integer.value[0] = spdif->multi_freqs[i];
+               } else {
+                       uc->value.integer.value[0] = spdif->single_freq;
+               }
+       } else {
+               uc->value.integer.value[0] = 0;
+       }
+
+       spin_unlock_irqrestore(&spdif->lock, flags);
+
+       return 0;
+}
+
+static int img_spdif_in_info_trk(struct snd_kcontrol *kcontrol,
+               struct snd_ctl_elem_info *uinfo)
+{
+       uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+       uinfo->count = 1;
+       uinfo->value.integer.min = 0;
+       uinfo->value.integer.max = 255;
+
+       return 0;
+}
+
+static int img_spdif_in_get_trk(struct snd_kcontrol *kcontrol,
+                                 struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_dai *cpu_dai = snd_kcontrol_chip(kcontrol);
+       struct img_spdif_in *spdif = snd_soc_dai_get_drvdata(cpu_dai);
+
+       ucontrol->value.integer.value[0] = spdif->trk;
+
+       return 0;
+}
+
+static int img_spdif_in_set_trk(struct snd_kcontrol *kcontrol,
+                                 struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_dai *cpu_dai = snd_kcontrol_chip(kcontrol);
+       struct img_spdif_in *spdif = snd_soc_dai_get_drvdata(cpu_dai);
+       unsigned long flags;
+       int i;
+       u32 reg;
+
+       spin_lock_irqsave(&spdif->lock, flags);
+
+       if (spdif->active) {
+               spin_unlock_irqrestore(&spdif->lock, flags);
+               return -EBUSY;
+       }
+
+       spdif->trk = ucontrol->value.integer.value[0];
+
+       reg = img_spdif_in_readl(spdif, IMG_SPDIF_IN_CTL);
+       reg &= ~IMG_SPDIF_IN_CTL_TRK_MASK;
+       reg |= spdif->trk << IMG_SPDIF_IN_CTL_TRK_SHIFT;
+       img_spdif_in_writel(spdif, reg, IMG_SPDIF_IN_CTL);
+
+       for (i = 0; i < IMG_SPDIF_IN_NUM_ACLKGEN; i++) {
+               spdif->aclkgen_regs[i] = (spdif->aclkgen_regs[i] &
+                       ~IMG_SPDIF_IN_ACLKGEN_TRK_MASK) |
+                       (spdif->trk << IMG_SPDIF_IN_ACLKGEN_TRK_SHIFT);
+
+               img_spdif_in_aclkgen_writel(spdif, i);
+       }
+
+       spin_unlock_irqrestore(&spdif->lock, flags);
+
+       return 0;
+}
+
+static int img_spdif_in_info_lock(struct snd_kcontrol *kcontrol,
+               struct snd_ctl_elem_info *uinfo)
+{
+       uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+       uinfo->count = 1;
+       uinfo->value.integer.min = -128;
+       uinfo->value.integer.max = 127;
+
+       return 0;
+}
+
+static int img_spdif_in_get_lock_acquire(struct snd_kcontrol *kcontrol,
+                                 struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_dai *cpu_dai = snd_kcontrol_chip(kcontrol);
+       struct img_spdif_in *spdif = snd_soc_dai_get_drvdata(cpu_dai);
+
+       ucontrol->value.integer.value[0] = spdif->lock_acquire;
+
+       return 0;
+}
+
+static int img_spdif_in_set_lock_acquire(struct snd_kcontrol *kcontrol,
+                                 struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_dai *cpu_dai = snd_kcontrol_chip(kcontrol);
+       struct img_spdif_in *spdif = snd_soc_dai_get_drvdata(cpu_dai);
+       unsigned long flags;
+       u32 reg;
+
+       spin_lock_irqsave(&spdif->lock, flags);
+
+       if (spdif->active) {
+               spin_unlock_irqrestore(&spdif->lock, flags);
+               return -EBUSY;
+       }
+
+       spdif->lock_acquire = ucontrol->value.integer.value[0];
+
+       reg = img_spdif_in_readl(spdif, IMG_SPDIF_IN_CTL);
+       reg &= ~IMG_SPDIF_IN_CTL_LOCKHI_MASK;
+       reg |= (spdif->lock_acquire << IMG_SPDIF_IN_CTL_LOCKHI_SHIFT) &
+               IMG_SPDIF_IN_CTL_LOCKHI_MASK;
+       img_spdif_in_writel(spdif, reg, IMG_SPDIF_IN_CTL);
+
+       spin_unlock_irqrestore(&spdif->lock, flags);
+
+       return 0;
+}
+
+static int img_spdif_in_get_lock_release(struct snd_kcontrol *kcontrol,
+                                 struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_dai *cpu_dai = snd_kcontrol_chip(kcontrol);
+       struct img_spdif_in *spdif = snd_soc_dai_get_drvdata(cpu_dai);
+
+       ucontrol->value.integer.value[0] = spdif->lock_release;
+
+       return 0;
+}
+
+static int img_spdif_in_set_lock_release(struct snd_kcontrol *kcontrol,
+                                 struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_dai *cpu_dai = snd_kcontrol_chip(kcontrol);
+       struct img_spdif_in *spdif = snd_soc_dai_get_drvdata(cpu_dai);
+       unsigned long flags;
+       u32 reg;
+
+       spin_lock_irqsave(&spdif->lock, flags);
+
+       if (spdif->active) {
+               spin_unlock_irqrestore(&spdif->lock, flags);
+               return -EBUSY;
+       }
+
+       spdif->lock_release = ucontrol->value.integer.value[0];
+
+       reg = img_spdif_in_readl(spdif, IMG_SPDIF_IN_CTL);
+       reg &= ~IMG_SPDIF_IN_CTL_LOCKLO_MASK;
+       reg |= (spdif->lock_release << IMG_SPDIF_IN_CTL_LOCKLO_SHIFT) &
+               IMG_SPDIF_IN_CTL_LOCKLO_MASK;
+       img_spdif_in_writel(spdif, reg, IMG_SPDIF_IN_CTL);
+
+       spin_unlock_irqrestore(&spdif->lock, flags);
+
+       return 0;
+}
+
+static struct snd_kcontrol_new img_spdif_in_controls[] = {
+       {
+               .access = SNDRV_CTL_ELEM_ACCESS_READ,
+               .iface = SNDRV_CTL_ELEM_IFACE_PCM,
+               .name = SNDRV_CTL_NAME_IEC958("", CAPTURE, MASK),
+               .info = img_spdif_in_iec958_info,
+               .get = img_spdif_in_get_status_mask
+       },
+       {
+               .access = SNDRV_CTL_ELEM_ACCESS_READ |
+                       SNDRV_CTL_ELEM_ACCESS_VOLATILE,
+               .iface = SNDRV_CTL_ELEM_IFACE_PCM,
+               .name = SNDRV_CTL_NAME_IEC958("", CAPTURE, DEFAULT),
+               .info = img_spdif_in_iec958_info,
+               .get = img_spdif_in_get_status
+       },
+       {
+               .iface = SNDRV_CTL_ELEM_IFACE_PCM,
+               .name = "SPDIF In Multi Frequency Acquire",
+               .info = img_spdif_in_info_multi_freq,
+               .get = img_spdif_in_get_multi_freq,
+               .put = img_spdif_in_set_multi_freq
+       },
+       {
+               .access = SNDRV_CTL_ELEM_ACCESS_READ |
+                       SNDRV_CTL_ELEM_ACCESS_VOLATILE,
+               .iface = SNDRV_CTL_ELEM_IFACE_PCM,
+               .name = "SPDIF In Lock Frequency",
+               .info = img_spdif_in_info_lock_freq,
+               .get = img_spdif_in_get_lock_freq
+       },
+       {
+               .iface = SNDRV_CTL_ELEM_IFACE_PCM,
+               .name = "SPDIF In Lock TRK",
+               .info = img_spdif_in_info_trk,
+               .get = img_spdif_in_get_trk,
+               .put = img_spdif_in_set_trk
+       },
+       {
+               .iface = SNDRV_CTL_ELEM_IFACE_PCM,
+               .name = "SPDIF In Lock Acquire Threshold",
+               .info = img_spdif_in_info_lock,
+               .get = img_spdif_in_get_lock_acquire,
+               .put = img_spdif_in_set_lock_acquire
+       },
+       {
+               .iface = SNDRV_CTL_ELEM_IFACE_PCM,
+               .name = "SPDIF In Lock Release Threshold",
+               .info = img_spdif_in_info_lock,
+               .get = img_spdif_in_get_lock_release,
+               .put = img_spdif_in_set_lock_release
+       }
+};
+
+static int img_spdif_in_trigger(struct snd_pcm_substream *substream, int cmd,
+       struct snd_soc_dai *dai)
+{
+       unsigned long flags;
+       struct img_spdif_in *spdif = snd_soc_dai_get_drvdata(dai);
+       int ret = 0;
+       u32 reg;
+
+       spin_lock_irqsave(&spdif->lock, flags);
+
+       switch (cmd) {
+       case SNDRV_PCM_TRIGGER_START:
+       case SNDRV_PCM_TRIGGER_RESUME:
+       case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+               reg = img_spdif_in_readl(spdif, IMG_SPDIF_IN_CTL);
+               if (spdif->multi_freq)
+                       reg &= ~IMG_SPDIF_IN_CTL_SRD_MASK;
+               else
+                       reg |= (1UL << IMG_SPDIF_IN_CTL_SRD_SHIFT);
+               reg |= IMG_SPDIF_IN_CTL_SRT_MASK;
+               img_spdif_in_writel(spdif, reg, IMG_SPDIF_IN_CTL);
+               spdif->active = true;
+               break;
+       case SNDRV_PCM_TRIGGER_STOP:
+       case SNDRV_PCM_TRIGGER_SUSPEND:
+       case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+               reg = img_spdif_in_readl(spdif, IMG_SPDIF_IN_CTL);
+               reg &= ~IMG_SPDIF_IN_CTL_SRT_MASK;
+               img_spdif_in_writel(spdif, reg, IMG_SPDIF_IN_CTL);
+               spdif->active = false;
+               break;
+       default:
+               ret = -EINVAL;
+       }
+
+       spin_unlock_irqrestore(&spdif->lock, flags);
+
+       return ret;
+}
+
+static int img_spdif_in_hw_params(struct snd_pcm_substream *substream,
+       struct snd_pcm_hw_params *params, struct snd_soc_dai *dai)
+{
+       struct img_spdif_in *spdif = snd_soc_dai_get_drvdata(dai);
+       unsigned int rate, channels;
+       snd_pcm_format_t format;
+
+       rate = params_rate(params);
+       channels = params_channels(params);
+       format = params_format(params);
+
+       if (format != SNDRV_PCM_FORMAT_S32_LE)
+               return -EINVAL;
+
+       if (channels != 2)
+               return -EINVAL;
+
+       return img_spdif_in_do_clkgen_single(spdif, rate);
+}
+
+static const struct snd_soc_dai_ops img_spdif_in_dai_ops = {
+       .trigger = img_spdif_in_trigger,
+       .hw_params = img_spdif_in_hw_params
+};
+
+static int img_spdif_in_dai_probe(struct snd_soc_dai *dai)
+{
+       struct img_spdif_in *spdif = snd_soc_dai_get_drvdata(dai);
+
+       snd_soc_dai_init_dma_data(dai, NULL, &spdif->dma_data);
+
+       snd_soc_add_dai_controls(dai, img_spdif_in_controls,
+                       ARRAY_SIZE(img_spdif_in_controls));
+
+       return 0;
+}
+
+static struct snd_soc_dai_driver img_spdif_in_dai = {
+       .probe = img_spdif_in_dai_probe,
+       .capture = {
+               .channels_min = 2,
+               .channels_max = 2,
+               .rates = SNDRV_PCM_RATE_8000_192000,
+               .formats = SNDRV_PCM_FMTBIT_S32_LE
+       },
+       .ops = &img_spdif_in_dai_ops
+};
+
+static const struct snd_soc_component_driver img_spdif_in_component = {
+       .name = "img-spdif-in"
+};
+
+static int img_spdif_in_probe(struct platform_device *pdev)
+{
+       struct img_spdif_in *spdif;
+       struct resource *res;
+       void __iomem *base;
+       int ret;
+       struct reset_control *rst;
+       u32 reg;
+       struct device *dev = &pdev->dev;
+
+       spdif = devm_kzalloc(&pdev->dev, sizeof(*spdif), GFP_KERNEL);
+       if (!spdif)
+               return -ENOMEM;
+
+       platform_set_drvdata(pdev, spdif);
+
+       spdif->dev = &pdev->dev;
+
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       base = devm_ioremap_resource(&pdev->dev, res);
+       if (IS_ERR(base))
+               return PTR_ERR(base);
+
+       spdif->base = base;
+
+       spdif->clk_sys = devm_clk_get(dev, "sys");
+       if (IS_ERR(spdif->clk_sys)) {
+               if (PTR_ERR(spdif->clk_sys) != -EPROBE_DEFER)
+                       dev_err(dev, "Failed to acquire clock 'sys'\n");
+               return PTR_ERR(spdif->clk_sys);
+       }
+
+       ret = clk_prepare_enable(spdif->clk_sys);
+       if (ret)
+               return ret;
+
+       rst = devm_reset_control_get(&pdev->dev, "rst");
+       if (IS_ERR(rst)) {
+               if (PTR_ERR(rst) == -EPROBE_DEFER) {
+                       ret = -EPROBE_DEFER;
+                       goto err_clk_disable;
+               }
+               dev_dbg(dev, "No top level reset found\n");
+               img_spdif_in_writel(spdif, IMG_SPDIF_IN_SOFT_RESET_MASK,
+                               IMG_SPDIF_IN_SOFT_RESET);
+               img_spdif_in_writel(spdif, 0, IMG_SPDIF_IN_SOFT_RESET);
+       } else {
+               reset_control_assert(rst);
+               reset_control_deassert(rst);
+       }
+
+       spin_lock_init(&spdif->lock);
+
+       spdif->dma_data.addr = res->start + IMG_SPDIF_IN_RX_FIFO_OFFSET;
+       spdif->dma_data.addr_width = 4;
+       spdif->dma_data.maxburst = 4;
+       spdif->trk = 0x80;
+       spdif->lock_acquire = 4;
+       spdif->lock_release = -128;
+
+       reg = (spdif->lock_acquire << IMG_SPDIF_IN_CTL_LOCKHI_SHIFT) &
+               IMG_SPDIF_IN_CTL_LOCKHI_MASK;
+       reg |= (spdif->lock_release << IMG_SPDIF_IN_CTL_LOCKLO_SHIFT) &
+               IMG_SPDIF_IN_CTL_LOCKLO_MASK;
+       reg |= (spdif->trk << IMG_SPDIF_IN_CTL_TRK_SHIFT) &
+               IMG_SPDIF_IN_CTL_TRK_MASK;
+       img_spdif_in_writel(spdif, reg, IMG_SPDIF_IN_CTL);
+
+       ret = devm_snd_soc_register_component(&pdev->dev,
+                       &img_spdif_in_component, &img_spdif_in_dai, 1);
+       if (ret)
+               goto err_clk_disable;
+
+       ret = devm_snd_dmaengine_pcm_register(&pdev->dev, NULL, 0);
+       if (ret)
+               goto err_clk_disable;
+
+       return 0;
+
+err_clk_disable:
+       clk_disable_unprepare(spdif->clk_sys);
+
+       return ret;
+}
+
+static int img_spdif_in_dev_remove(struct platform_device *pdev)
+{
+       struct img_spdif_in *spdif = platform_get_drvdata(pdev);
+
+       clk_disable_unprepare(spdif->clk_sys);
+
+       return 0;
+}
+
+static const struct of_device_id img_spdif_in_of_match[] = {
+       { .compatible = "img,spdif-in" },
+       {}
+};
+MODULE_DEVICE_TABLE(of, img_spdif_in_of_match);
+
+static struct platform_driver img_spdif_in_driver = {
+       .driver = {
+               .name = "img-spdif-in",
+               .of_match_table = img_spdif_in_of_match
+       },
+       .probe = img_spdif_in_probe,
+       .remove = img_spdif_in_dev_remove
+};
+module_platform_driver(img_spdif_in_driver);
+
+MODULE_AUTHOR("Damien Horsley <Damien.Horsley@imgtec.com>");
+MODULE_DESCRIPTION("IMG SPDIF Input driver");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/img/img-spdif-out.c b/sound/soc/img/img-spdif-out.c
new file mode 100644 (file)
index 0000000..08f93a5
--- /dev/null
@@ -0,0 +1,441 @@
+/*
+ * IMG SPDIF output controller driver
+ *
+ * Copyright (C) 2015 Imagination Technologies Ltd.
+ *
+ * Author: Damien Horsley <Damien.Horsley@imgtec.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.
+ */
+
+#include <linux/clk.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/reset.h>
+
+#include <sound/core.h>
+#include <sound/dmaengine_pcm.h>
+#include <sound/initval.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+
+#define IMG_SPDIF_OUT_TX_FIFO          0x0
+
+#define IMG_SPDIF_OUT_CTL              0x4
+#define IMG_SPDIF_OUT_CTL_FS_MASK      BIT(4)
+#define IMG_SPDIF_OUT_CTL_CLK_MASK     BIT(2)
+#define IMG_SPDIF_OUT_CTL_SRT_MASK     BIT(0)
+
+#define IMG_SPDIF_OUT_CSL              0x14
+
+#define IMG_SPDIF_OUT_CSH_UV           0x18
+#define IMG_SPDIF_OUT_CSH_UV_CSH_SHIFT 0
+#define IMG_SPDIF_OUT_CSH_UV_CSH_MASK  0xff
+
+struct img_spdif_out {
+       spinlock_t lock;
+       void __iomem *base;
+       struct clk *clk_sys;
+       struct clk *clk_ref;
+       struct snd_dmaengine_dai_dma_data dma_data;
+       struct device *dev;
+       struct reset_control *rst;
+};
+
+static int img_spdif_out_suspend(struct device *dev)
+{
+       struct img_spdif_out *spdif = dev_get_drvdata(dev);
+
+       clk_disable_unprepare(spdif->clk_ref);
+
+       return 0;
+}
+
+static int img_spdif_out_resume(struct device *dev)
+{
+       struct img_spdif_out *spdif = dev_get_drvdata(dev);
+       int ret;
+
+       ret = clk_prepare_enable(spdif->clk_ref);
+       if (ret) {
+               dev_err(dev, "clk_enable failed: %d\n", ret);
+               return ret;
+       }
+
+       return 0;
+}
+
+static inline void img_spdif_out_writel(struct img_spdif_out *spdif, u32 val,
+                               u32 reg)
+{
+       writel(val, spdif->base + reg);
+}
+
+static inline u32 img_spdif_out_readl(struct img_spdif_out *spdif, u32 reg)
+{
+       return readl(spdif->base + reg);
+}
+
+static void img_spdif_out_reset(struct img_spdif_out *spdif)
+{
+       u32 ctl, status_low, status_high;
+
+       ctl = img_spdif_out_readl(spdif, IMG_SPDIF_OUT_CTL) &
+                       ~IMG_SPDIF_OUT_CTL_SRT_MASK;
+       status_low = img_spdif_out_readl(spdif, IMG_SPDIF_OUT_CSL);
+       status_high = img_spdif_out_readl(spdif, IMG_SPDIF_OUT_CSH_UV);
+
+       reset_control_assert(spdif->rst);
+       reset_control_deassert(spdif->rst);
+
+       img_spdif_out_writel(spdif, ctl, IMG_SPDIF_OUT_CTL);
+       img_spdif_out_writel(spdif, status_low, IMG_SPDIF_OUT_CSL);
+       img_spdif_out_writel(spdif, status_high, IMG_SPDIF_OUT_CSH_UV);
+}
+
+static int img_spdif_out_info(struct snd_kcontrol *kcontrol,
+                                       struct snd_ctl_elem_info *uinfo)
+{
+       uinfo->type = SNDRV_CTL_ELEM_TYPE_IEC958;
+       uinfo->count = 1;
+
+       return 0;
+}
+
+static int img_spdif_out_get_status_mask(struct snd_kcontrol *kcontrol,
+                                      struct snd_ctl_elem_value *ucontrol)
+{
+       ucontrol->value.iec958.status[0] = 0xff;
+       ucontrol->value.iec958.status[1] = 0xff;
+       ucontrol->value.iec958.status[2] = 0xff;
+       ucontrol->value.iec958.status[3] = 0xff;
+       ucontrol->value.iec958.status[4] = 0xff;
+
+       return 0;
+}
+
+static int img_spdif_out_get_status(struct snd_kcontrol *kcontrol,
+                                 struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_dai *cpu_dai = snd_kcontrol_chip(kcontrol);
+       struct img_spdif_out *spdif = snd_soc_dai_get_drvdata(cpu_dai);
+       u32 reg;
+       unsigned long flags;
+
+       spin_lock_irqsave(&spdif->lock, flags);
+
+       reg = img_spdif_out_readl(spdif, IMG_SPDIF_OUT_CSL);
+       ucontrol->value.iec958.status[0] = reg & 0xff;
+       ucontrol->value.iec958.status[1] = (reg >> 8) & 0xff;
+       ucontrol->value.iec958.status[2] = (reg >> 16) & 0xff;
+       ucontrol->value.iec958.status[3] = (reg >> 24) & 0xff;
+
+       reg = img_spdif_out_readl(spdif, IMG_SPDIF_OUT_CSH_UV);
+       ucontrol->value.iec958.status[4] =
+               (reg & IMG_SPDIF_OUT_CSH_UV_CSH_MASK) >>
+               IMG_SPDIF_OUT_CSH_UV_CSH_SHIFT;
+
+       spin_unlock_irqrestore(&spdif->lock, flags);
+
+       return 0;
+}
+
+static int img_spdif_out_set_status(struct snd_kcontrol *kcontrol,
+                                 struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_dai *cpu_dai = snd_kcontrol_chip(kcontrol);
+       struct img_spdif_out *spdif = snd_soc_dai_get_drvdata(cpu_dai);
+       u32 reg;
+       unsigned long flags;
+
+       reg = ((u32)ucontrol->value.iec958.status[3] << 24);
+       reg |= ((u32)ucontrol->value.iec958.status[2] << 16);
+       reg |= ((u32)ucontrol->value.iec958.status[1] << 8);
+       reg |= (u32)ucontrol->value.iec958.status[0];
+
+       spin_lock_irqsave(&spdif->lock, flags);
+
+       img_spdif_out_writel(spdif, reg, IMG_SPDIF_OUT_CSL);
+
+       reg = img_spdif_out_readl(spdif, IMG_SPDIF_OUT_CSH_UV);
+       reg &= ~IMG_SPDIF_OUT_CSH_UV_CSH_MASK;
+       reg |= (u32)ucontrol->value.iec958.status[4] <<
+                       IMG_SPDIF_OUT_CSH_UV_CSH_SHIFT;
+       img_spdif_out_writel(spdif, reg, IMG_SPDIF_OUT_CSH_UV);
+
+       spin_unlock_irqrestore(&spdif->lock, flags);
+
+       return 0;
+}
+
+static struct snd_kcontrol_new img_spdif_out_controls[] = {
+       {
+               .access = SNDRV_CTL_ELEM_ACCESS_READ,
+               .iface = SNDRV_CTL_ELEM_IFACE_PCM,
+               .name = SNDRV_CTL_NAME_IEC958("", PLAYBACK, MASK),
+               .info = img_spdif_out_info,
+               .get = img_spdif_out_get_status_mask
+       },
+       {
+               .iface = SNDRV_CTL_ELEM_IFACE_PCM,
+               .name = SNDRV_CTL_NAME_IEC958("", PLAYBACK, DEFAULT),
+               .info = img_spdif_out_info,
+               .get = img_spdif_out_get_status,
+               .put = img_spdif_out_set_status
+       }
+};
+
+static int img_spdif_out_trigger(struct snd_pcm_substream *substream, int cmd,
+                       struct snd_soc_dai *dai)
+{
+       struct img_spdif_out *spdif = snd_soc_dai_get_drvdata(dai);
+       u32 reg;
+       unsigned long flags;
+
+       switch (cmd) {
+       case SNDRV_PCM_TRIGGER_START:
+       case SNDRV_PCM_TRIGGER_RESUME:
+       case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+               reg = img_spdif_out_readl(spdif, IMG_SPDIF_OUT_CTL);
+               reg |= IMG_SPDIF_OUT_CTL_SRT_MASK;
+               img_spdif_out_writel(spdif, reg, IMG_SPDIF_OUT_CTL);
+               break;
+       case SNDRV_PCM_TRIGGER_STOP:
+       case SNDRV_PCM_TRIGGER_SUSPEND:
+       case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+               spin_lock_irqsave(&spdif->lock, flags);
+               img_spdif_out_reset(spdif);
+               spin_unlock_irqrestore(&spdif->lock, flags);
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static int img_spdif_out_hw_params(struct snd_pcm_substream *substream,
+       struct snd_pcm_hw_params *params, struct snd_soc_dai *dai)
+{
+       struct img_spdif_out *spdif = snd_soc_dai_get_drvdata(dai);
+       unsigned int channels;
+       long pre_div_a, pre_div_b, diff_a, diff_b, rate, clk_rate;
+       u32 reg;
+       snd_pcm_format_t format;
+
+       rate = params_rate(params);
+       format = params_format(params);
+       channels = params_channels(params);
+
+       dev_dbg(spdif->dev, "hw_params rate %ld channels %u format %u\n",
+                       rate, channels, format);
+
+       if (format != SNDRV_PCM_FORMAT_S32_LE)
+               return -EINVAL;
+
+       if (channels != 2)
+               return -EINVAL;
+
+       pre_div_a = clk_round_rate(spdif->clk_ref, rate * 256);
+       if (pre_div_a < 0)
+               return pre_div_a;
+       pre_div_b = clk_round_rate(spdif->clk_ref, rate * 384);
+       if (pre_div_b < 0)
+               return pre_div_b;
+
+       diff_a = abs((pre_div_a / 256) - rate);
+       diff_b = abs((pre_div_b / 384) - rate);
+
+       /* If diffs are equal, use lower clock rate */
+       if (diff_a > diff_b)
+               clk_set_rate(spdif->clk_ref, pre_div_b);
+       else
+               clk_set_rate(spdif->clk_ref, pre_div_a);
+
+       /*
+        * Another driver (eg machine driver) may have rejected the above
+        * change. Get the current rate and set the register bit according to
+        * the new min diff
+        */
+       clk_rate = clk_get_rate(spdif->clk_ref);
+
+       diff_a = abs((clk_rate / 256) - rate);
+       diff_b = abs((clk_rate / 384) - rate);
+
+       reg = img_spdif_out_readl(spdif, IMG_SPDIF_OUT_CTL);
+       if (diff_a <= diff_b)
+               reg &= ~IMG_SPDIF_OUT_CTL_CLK_MASK;
+       else
+               reg |= IMG_SPDIF_OUT_CTL_CLK_MASK;
+       img_spdif_out_writel(spdif, reg, IMG_SPDIF_OUT_CTL);
+
+       return 0;
+}
+
+static const struct snd_soc_dai_ops img_spdif_out_dai_ops = {
+       .trigger = img_spdif_out_trigger,
+       .hw_params = img_spdif_out_hw_params
+};
+
+static int img_spdif_out_dai_probe(struct snd_soc_dai *dai)
+{
+       struct img_spdif_out *spdif = snd_soc_dai_get_drvdata(dai);
+
+       snd_soc_dai_init_dma_data(dai, &spdif->dma_data, NULL);
+
+       snd_soc_add_dai_controls(dai, img_spdif_out_controls,
+                       ARRAY_SIZE(img_spdif_out_controls));
+
+       return 0;
+}
+
+static struct snd_soc_dai_driver img_spdif_out_dai = {
+       .probe = img_spdif_out_dai_probe,
+       .playback = {
+               .channels_min = 2,
+               .channels_max = 2,
+               .rates = SNDRV_PCM_RATE_8000_192000,
+               .formats = SNDRV_PCM_FMTBIT_S32_LE
+       },
+       .ops = &img_spdif_out_dai_ops
+};
+
+static const struct snd_soc_component_driver img_spdif_out_component = {
+       .name = "img-spdif-out"
+};
+
+static int img_spdif_out_probe(struct platform_device *pdev)
+{
+       struct img_spdif_out *spdif;
+       struct resource *res;
+       void __iomem *base;
+       int ret;
+       struct device *dev = &pdev->dev;
+
+       spdif = devm_kzalloc(&pdev->dev, sizeof(*spdif), GFP_KERNEL);
+       if (!spdif)
+               return -ENOMEM;
+
+       platform_set_drvdata(pdev, spdif);
+
+       spdif->dev = &pdev->dev;
+
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       base = devm_ioremap_resource(&pdev->dev, res);
+       if (IS_ERR(base))
+               return PTR_ERR(base);
+
+       spdif->base = base;
+
+       spdif->rst = devm_reset_control_get(&pdev->dev, "rst");
+       if (IS_ERR(spdif->rst)) {
+               if (PTR_ERR(spdif->rst) != -EPROBE_DEFER)
+                       dev_err(&pdev->dev, "No top level reset found\n");
+               return PTR_ERR(spdif->rst);
+       }
+
+       spdif->clk_sys = devm_clk_get(&pdev->dev, "sys");
+       if (IS_ERR(spdif->clk_sys)) {
+               if (PTR_ERR(spdif->clk_sys) != -EPROBE_DEFER)
+                       dev_err(dev, "Failed to acquire clock 'sys'\n");
+               return PTR_ERR(spdif->clk_sys);
+       }
+
+       spdif->clk_ref = devm_clk_get(&pdev->dev, "ref");
+       if (IS_ERR(spdif->clk_ref)) {
+               if (PTR_ERR(spdif->clk_ref) != -EPROBE_DEFER)
+                       dev_err(dev, "Failed to acquire clock 'ref'\n");
+               return PTR_ERR(spdif->clk_ref);
+       }
+
+       ret = clk_prepare_enable(spdif->clk_sys);
+       if (ret)
+               return ret;
+
+       img_spdif_out_writel(spdif, IMG_SPDIF_OUT_CTL_FS_MASK,
+                               IMG_SPDIF_OUT_CTL);
+
+       img_spdif_out_reset(spdif);
+
+       pm_runtime_enable(&pdev->dev);
+       if (!pm_runtime_enabled(&pdev->dev)) {
+               ret = img_spdif_out_resume(&pdev->dev);
+               if (ret)
+                       goto err_pm_disable;
+       }
+
+       spin_lock_init(&spdif->lock);
+
+       spdif->dma_data.addr = res->start + IMG_SPDIF_OUT_TX_FIFO;
+       spdif->dma_data.addr_width = 4;
+       spdif->dma_data.maxburst = 4;
+
+       ret = devm_snd_soc_register_component(&pdev->dev,
+                       &img_spdif_out_component,
+                       &img_spdif_out_dai, 1);
+       if (ret)
+               goto err_suspend;
+
+       ret = devm_snd_dmaengine_pcm_register(&pdev->dev, NULL, 0);
+       if (ret)
+               goto err_suspend;
+
+       dev_dbg(&pdev->dev, "Probe successful\n");
+
+       return 0;
+
+err_suspend:
+       if (!pm_runtime_status_suspended(&pdev->dev))
+               img_spdif_out_suspend(&pdev->dev);
+err_pm_disable:
+       pm_runtime_disable(&pdev->dev);
+       clk_disable_unprepare(spdif->clk_sys);
+
+       return ret;
+}
+
+static int img_spdif_out_dev_remove(struct platform_device *pdev)
+{
+       struct img_spdif_out *spdif = platform_get_drvdata(pdev);
+
+       pm_runtime_disable(&pdev->dev);
+       if (!pm_runtime_status_suspended(&pdev->dev))
+               img_spdif_out_suspend(&pdev->dev);
+
+       clk_disable_unprepare(spdif->clk_sys);
+
+       return 0;
+}
+
+static const struct of_device_id img_spdif_out_of_match[] = {
+       { .compatible = "img,spdif-out" },
+       {}
+};
+MODULE_DEVICE_TABLE(of, img_spdif_out_of_match);
+
+static const struct dev_pm_ops img_spdif_out_pm_ops = {
+       SET_RUNTIME_PM_OPS(img_spdif_out_suspend,
+                          img_spdif_out_resume, NULL)
+};
+
+static struct platform_driver img_spdif_out_driver = {
+       .driver = {
+               .name = "img-spdif-out",
+               .of_match_table = img_spdif_out_of_match,
+               .pm = &img_spdif_out_pm_ops
+       },
+       .probe = img_spdif_out_probe,
+       .remove = img_spdif_out_dev_remove
+};
+module_platform_driver(img_spdif_out_driver);
+
+MODULE_AUTHOR("Damien Horsley <Damien.Horsley@imgtec.com>");
+MODULE_DESCRIPTION("IMG SPDIF Output driver");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/img/pistachio-internal-dac.c b/sound/soc/img/pistachio-internal-dac.c
new file mode 100644 (file)
index 0000000..162a0fd
--- /dev/null
@@ -0,0 +1,287 @@
+/*
+ * Pistachio internal dac driver
+ *
+ * Copyright (C) 2015 Imagination Technologies Ltd.
+ *
+ * Author: Damien Horsley <Damien.Horsley@imgtec.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.
+ */
+
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/mfd/syscon.h>
+#include <linux/module.h>
+#include <linux/pm_runtime.h>
+#include <linux/regmap.h>
+#include <linux/regulator/consumer.h>
+
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+
+#define PISTACHIO_INTERNAL_DAC_CTRL                    0x40
+#define PISTACHIO_INTERNAL_DAC_CTRL_PWR_SEL_MASK       0x2
+#define PISTACHIO_INTERNAL_DAC_CTRL_PWRDN_MASK         0x1
+
+#define PISTACHIO_INTERNAL_DAC_SRST                    0x44
+#define PISTACHIO_INTERNAL_DAC_SRST_MASK               0x1
+
+#define PISTACHIO_INTERNAL_DAC_GTI_CTRL                        0x48
+#define PISTACHIO_INTERNAL_DAC_GTI_CTRL_ADDR_SHIFT     0
+#define PISTACHIO_INTERNAL_DAC_GTI_CTRL_ADDR_MASK      0xFFF
+#define PISTACHIO_INTERNAL_DAC_GTI_CTRL_WE_MASK                0x1000
+#define PISTACHIO_INTERNAL_DAC_GTI_CTRL_WDATA_SHIFT    13
+#define PISTACHIO_INTERNAL_DAC_GTI_CTRL_WDATA_MASK     0x1FE000
+
+#define PISTACHIO_INTERNAL_DAC_PWR                     0x1
+#define PISTACHIO_INTERNAL_DAC_PWR_MASK                        0x1
+
+#define PISTACHIO_INTERNAL_DAC_FORMATS (SNDRV_PCM_FMTBIT_S24_LE |  \
+                                       SNDRV_PCM_FMTBIT_S32_LE)
+
+/* codec private data */
+struct pistachio_internal_dac {
+       struct regmap *regmap;
+       struct regulator *supply;
+       bool mute;
+};
+
+static const struct snd_kcontrol_new pistachio_internal_dac_snd_controls[] = {
+       SOC_SINGLE("Playback Switch", PISTACHIO_INTERNAL_DAC_CTRL, 2, 1, 1)
+};
+
+static const struct snd_soc_dapm_widget pistachio_internal_dac_widgets[] = {
+       SND_SOC_DAPM_DAC("DAC", "Playback", SND_SOC_NOPM, 0, 0),
+       SND_SOC_DAPM_OUTPUT("AOUTL"),
+       SND_SOC_DAPM_OUTPUT("AOUTR"),
+};
+
+static const struct snd_soc_dapm_route pistachio_internal_dac_routes[] = {
+       { "AOUTL", NULL, "DAC" },
+       { "AOUTR", NULL, "DAC" },
+};
+
+static void pistachio_internal_dac_reg_writel(struct regmap *top_regs,
+                                               u32 val, u32 reg)
+{
+       regmap_update_bits(top_regs, PISTACHIO_INTERNAL_DAC_GTI_CTRL,
+                       PISTACHIO_INTERNAL_DAC_GTI_CTRL_ADDR_MASK,
+                       reg << PISTACHIO_INTERNAL_DAC_GTI_CTRL_ADDR_SHIFT);
+
+       regmap_update_bits(top_regs, PISTACHIO_INTERNAL_DAC_GTI_CTRL,
+                       PISTACHIO_INTERNAL_DAC_GTI_CTRL_WDATA_MASK,
+                       val << PISTACHIO_INTERNAL_DAC_GTI_CTRL_WDATA_SHIFT);
+
+       regmap_update_bits(top_regs, PISTACHIO_INTERNAL_DAC_GTI_CTRL,
+                       PISTACHIO_INTERNAL_DAC_GTI_CTRL_WE_MASK,
+                       PISTACHIO_INTERNAL_DAC_GTI_CTRL_WE_MASK);
+
+       regmap_update_bits(top_regs, PISTACHIO_INTERNAL_DAC_GTI_CTRL,
+                       PISTACHIO_INTERNAL_DAC_GTI_CTRL_WE_MASK, 0);
+}
+
+static void pistachio_internal_dac_pwr_off(struct pistachio_internal_dac *dac)
+{
+       regmap_update_bits(dac->regmap, PISTACHIO_INTERNAL_DAC_CTRL,
+               PISTACHIO_INTERNAL_DAC_CTRL_PWRDN_MASK,
+               PISTACHIO_INTERNAL_DAC_CTRL_PWRDN_MASK);
+
+       pistachio_internal_dac_reg_writel(dac->regmap, 0,
+                                       PISTACHIO_INTERNAL_DAC_PWR);
+}
+
+static void pistachio_internal_dac_pwr_on(struct pistachio_internal_dac *dac)
+{
+       regmap_update_bits(dac->regmap, PISTACHIO_INTERNAL_DAC_SRST,
+                       PISTACHIO_INTERNAL_DAC_SRST_MASK,
+                       PISTACHIO_INTERNAL_DAC_SRST_MASK);
+
+       regmap_update_bits(dac->regmap, PISTACHIO_INTERNAL_DAC_SRST,
+                       PISTACHIO_INTERNAL_DAC_SRST_MASK, 0);
+
+       pistachio_internal_dac_reg_writel(dac->regmap,
+                                       PISTACHIO_INTERNAL_DAC_PWR_MASK,
+                                       PISTACHIO_INTERNAL_DAC_PWR);
+
+       regmap_update_bits(dac->regmap, PISTACHIO_INTERNAL_DAC_CTRL,
+                       PISTACHIO_INTERNAL_DAC_CTRL_PWRDN_MASK, 0);
+}
+
+static struct snd_soc_dai_driver pistachio_internal_dac_dais[] = {
+       {
+               .name = "pistachio_internal_dac",
+               .playback = {
+                       .stream_name = "Playback",
+                       .channels_min = 2,
+                       .channels_max = 2,
+                       .rates = SNDRV_PCM_RATE_8000_48000,
+                       .formats = PISTACHIO_INTERNAL_DAC_FORMATS,
+               }
+       },
+};
+
+static int pistachio_internal_dac_codec_probe(struct snd_soc_codec *codec)
+{
+       struct pistachio_internal_dac *dac = snd_soc_codec_get_drvdata(codec);
+
+       snd_soc_codec_init_regmap(codec, dac->regmap);
+
+       return 0;
+}
+
+static const struct snd_soc_codec_driver pistachio_internal_dac_driver = {
+       .probe = pistachio_internal_dac_codec_probe,
+       .idle_bias_off = true,
+       .controls = pistachio_internal_dac_snd_controls,
+       .num_controls = ARRAY_SIZE(pistachio_internal_dac_snd_controls),
+       .dapm_widgets = pistachio_internal_dac_widgets,
+       .num_dapm_widgets = ARRAY_SIZE(pistachio_internal_dac_widgets),
+       .dapm_routes = pistachio_internal_dac_routes,
+       .num_dapm_routes = ARRAY_SIZE(pistachio_internal_dac_routes),
+};
+
+static int pistachio_internal_dac_probe(struct platform_device *pdev)
+{
+       struct pistachio_internal_dac *dac;
+       int ret, voltage;
+       struct device *dev = &pdev->dev;
+       u32 reg;
+
+       dac = devm_kzalloc(dev, sizeof(*dac), GFP_KERNEL);
+
+       if (!dac)
+               return -ENOMEM;
+
+       platform_set_drvdata(pdev, dac);
+
+       dac->regmap = syscon_regmap_lookup_by_phandle(pdev->dev.of_node,
+                                                           "img,cr-top");
+       if (IS_ERR(dac->regmap))
+               return PTR_ERR(dac->regmap);
+
+       dac->supply = devm_regulator_get(dev, "VDD");
+       if (IS_ERR(dac->supply)) {
+               ret = PTR_ERR(dac->supply);
+               if (ret != -EPROBE_DEFER)
+                       dev_err(dev, "failed to acquire supply 'VDD-supply': %d\n", ret);
+               return ret;
+       }
+
+       ret = regulator_enable(dac->supply);
+       if (ret) {
+               dev_err(dev, "failed to enable supply: %d\n", ret);
+               return ret;
+       }
+
+       voltage = regulator_get_voltage(dac->supply);
+
+       switch (voltage) {
+       case 1800000:
+               reg = 0;
+               break;
+       case 3300000:
+               reg = PISTACHIO_INTERNAL_DAC_CTRL_PWR_SEL_MASK;
+               break;
+       default:
+               dev_err(dev, "invalid voltage: %d\n", voltage);
+               ret = -EINVAL;
+               goto err_regulator;
+       }
+
+       regmap_update_bits(dac->regmap, PISTACHIO_INTERNAL_DAC_CTRL,
+                       PISTACHIO_INTERNAL_DAC_CTRL_PWR_SEL_MASK, reg);
+
+       pistachio_internal_dac_pwr_off(dac);
+       pistachio_internal_dac_pwr_on(dac);
+
+       pm_runtime_set_active(dev);
+       pm_runtime_enable(dev);
+       pm_runtime_idle(dev);
+
+       ret = snd_soc_register_codec(dev, &pistachio_internal_dac_driver,
+                       pistachio_internal_dac_dais,
+                       ARRAY_SIZE(pistachio_internal_dac_dais));
+       if (ret) {
+               dev_err(dev, "failed to register codec: %d\n", ret);
+               goto err_pwr;
+       }
+
+       return 0;
+
+err_pwr:
+       pm_runtime_disable(&pdev->dev);
+       pistachio_internal_dac_pwr_off(dac);
+err_regulator:
+       regulator_disable(dac->supply);
+
+       return ret;
+}
+
+static int pistachio_internal_dac_remove(struct platform_device *pdev)
+{
+       struct pistachio_internal_dac *dac = dev_get_drvdata(&pdev->dev);
+
+       snd_soc_unregister_codec(&pdev->dev);
+       pm_runtime_disable(&pdev->dev);
+       pistachio_internal_dac_pwr_off(dac);
+       regulator_disable(dac->supply);
+
+       return 0;
+}
+
+#ifdef CONFIG_PM
+static int pistachio_internal_dac_rt_resume(struct device *dev)
+{
+       struct pistachio_internal_dac *dac = dev_get_drvdata(dev);
+       int ret;
+
+       ret = regulator_enable(dac->supply);
+       if (ret) {
+               dev_err(dev, "failed to enable supply: %d\n", ret);
+               return ret;
+       }
+
+       pistachio_internal_dac_pwr_on(dac);
+
+       return 0;
+}
+
+static int pistachio_internal_dac_rt_suspend(struct device *dev)
+{
+       struct pistachio_internal_dac *dac = dev_get_drvdata(dev);
+
+       pistachio_internal_dac_pwr_off(dac);
+
+       regulator_disable(dac->supply);
+
+       return 0;
+}
+#endif
+
+static const struct dev_pm_ops pistachio_internal_dac_pm_ops = {
+       SET_RUNTIME_PM_OPS(pistachio_internal_dac_rt_suspend,
+                       pistachio_internal_dac_rt_resume, NULL)
+};
+
+static const struct of_device_id pistachio_internal_dac_of_match[] = {
+       { .compatible = "img,pistachio-internal-dac" },
+       {}
+};
+MODULE_DEVICE_TABLE(of, pistachio_internal_dac_of_match);
+
+static struct platform_driver pistachio_internal_dac_plat_driver = {
+       .driver = {
+               .name = "img-pistachio-internal-dac",
+               .of_match_table = pistachio_internal_dac_of_match,
+               .pm = &pistachio_internal_dac_pm_ops
+       },
+       .probe = pistachio_internal_dac_probe,
+       .remove = pistachio_internal_dac_remove
+};
+module_platform_driver(pistachio_internal_dac_plat_driver);
+
+MODULE_DESCRIPTION("Pistachio Internal DAC driver");
+MODULE_AUTHOR("Damien Horsley <Damien.Horsley@imgtec.com>");
+MODULE_LICENSE("GPL v2");
index 7b778ab85f8b41234487d0810f4c350f6dc09775..803f95e40679def6a185c3131f838b210914b6c2 100644 (file)
@@ -24,6 +24,7 @@ config SND_SST_IPC_PCI
 config SND_SST_IPC_ACPI
        tristate
        select SND_SST_IPC
+       select SND_SOC_INTEL_SST
        depends on ACPI
 
 config SND_SOC_INTEL_SST
@@ -43,7 +44,7 @@ config SND_SOC_INTEL_BAYTRAIL
 config SND_SOC_INTEL_HASWELL_MACH
        tristate "ASoC Audio DSP support for Intel Haswell Lynxpoint"
        depends on X86_INTEL_LPSS && I2C && I2C_DESIGNWARE_PLATFORM
-       depends on DW_DMAC_CORE
+       depends on DW_DMAC_CORE=y
        select SND_SOC_INTEL_SST
        select SND_SOC_INTEL_HASWELL
        select SND_SOC_RT5640
@@ -56,18 +57,19 @@ config SND_SOC_INTEL_HASWELL_MACH
 config SND_SOC_INTEL_BYT_RT5640_MACH
        tristate "ASoC Audio driver for Intel Baytrail with RT5640 codec"
        depends on X86_INTEL_LPSS && I2C
-       depends on DW_DMAC_CORE
+       depends on DW_DMAC_CORE=y && (SND_SOC_INTEL_BYTCR_RT5640_MACH = n)
        select SND_SOC_INTEL_SST
        select SND_SOC_INTEL_BAYTRAIL
        select SND_SOC_RT5640
        help
          This adds audio driver for Intel Baytrail platform based boards
-         with the RT5640 audio codec.
+         with the RT5640 audio codec. This driver is deprecated, use
+         SND_SOC_INTEL_BYTCR_RT5640_MACH instead for better functionality
 
 config SND_SOC_INTEL_BYT_MAX98090_MACH
        tristate "ASoC Audio driver for Intel Baytrail with MAX98090 codec"
        depends on X86_INTEL_LPSS && I2C
-       depends on DW_DMAC_CORE
+       depends on DW_DMAC_CORE=y
        select SND_SOC_INTEL_SST
        select SND_SOC_INTEL_BAYTRAIL
        select SND_SOC_MAX98090
@@ -79,7 +81,7 @@ config SND_SOC_INTEL_BROADWELL_MACH
        tristate "ASoC Audio DSP support for Intel Broadwell Wildcatpoint"
        depends on X86_INTEL_LPSS && I2C && DW_DMAC && \
                   I2C_DESIGNWARE_PLATFORM
-       depends on DW_DMAC_CORE
+       depends on DW_DMAC_CORE=y
        select SND_SOC_INTEL_SST
        select SND_SOC_INTEL_HASWELL
        select SND_SOC_RT286
@@ -90,14 +92,26 @@ config SND_SOC_INTEL_BROADWELL_MACH
          If unsure select "N".
 
 config SND_SOC_INTEL_BYTCR_RT5640_MACH
-       tristate "ASoC Audio DSP Support for MID BYT Platform"
+        tristate "ASoC Audio driver for Intel Baytrail and Baytrail-CR with RT5640 codec"
        depends on X86 && I2C
        select SND_SOC_RT5640
        select SND_SST_MFLD_PLATFORM
        select SND_SST_IPC_ACPI
        help
-         This adds support for ASoC machine driver for Intel(R) MID Baytrail platform
-          used as alsa device in audio substem in Intel(R) MID devices
+          This adds support for ASoC machine driver for Intel(R) Baytrail and Baytrail-CR
+          platforms with RT5640 audio codec.
+          Say Y if you have such a device
+          If unsure select "N".
+
+config SND_SOC_INTEL_BYTCR_RT5651_MACH
+        tristate "ASoC Audio driver for Intel Baytrail and Baytrail-CR with RT5651 codec"
+       depends on X86 && I2C
+       select SND_SOC_RT5651
+       select SND_SST_MFLD_PLATFORM
+       select SND_SST_IPC_ACPI
+       help
+          This adds support for ASoC machine driver for Intel(R) Baytrail and Baytrail-CR
+          platforms with RT5651 audio codec.
           Say Y if you have such a device
           If unsure select "N".
 
@@ -144,7 +158,7 @@ config SND_SOC_INTEL_SKYLAKE
 
 config SND_SOC_INTEL_SKL_RT286_MACH
        tristate "ASoC Audio driver for SKL with RT286 I2S mode"
-       depends on X86 && ACPI
+       depends on X86 && ACPI && I2C
        select SND_SOC_INTEL_SST
        select SND_SOC_INTEL_SKYLAKE
        select SND_SOC_RT286
@@ -154,3 +168,31 @@ config SND_SOC_INTEL_SKL_RT286_MACH
           with RT286 I2S audio codec.
           Say Y if you have such a device
           If unsure select "N".
+
+config SND_SOC_INTEL_SKL_NAU88L25_SSM4567_MACH
+       tristate "ASoC Audio driver for SKL with NAU88L25 and SSM4567 in I2S Mode"
+       depends on X86_INTEL_LPSS && I2C
+       select SND_SOC_INTEL_SST
+       select SND_SOC_INTEL_SKYLAKE
+       select SND_SOC_NAU8825
+       select SND_SOC_SSM4567
+       select SND_SOC_DMIC
+       help
+         This adds support for ASoC Onboard Codec I2S machine driver. This will
+         create an alsa sound card for NAU88L25 + SSM4567.
+         Say Y if you have such a device
+         If unsure select "N".
+
+config SND_SOC_INTEL_SKL_NAU88L25_MAX98357A_MACH
+       tristate "ASoC Audio driver for SKL with NAU88L25 and MAX98357A in I2S Mode"
+       depends on X86_INTEL_LPSS && I2C
+       select SND_SOC_INTEL_SST
+       select SND_SOC_INTEL_SKYLAKE
+       select SND_SOC_NAU8825
+       select SND_SOC_MAX98357A
+       select SND_SOC_DMIC
+       help
+         This adds support for ASoC Onboard Codec I2S machine driver. This will
+         create an alsa sound card for NAU88L25 + MAX98357A.
+         Say Y if you have such a device
+         If unsure select "N".
index d55388e082e18189b71693bacf3994fdc6372a7c..b97e6adcf1b268d993493508fdcab21640072af4 100644 (file)
@@ -443,7 +443,7 @@ static int sst_gain_get(struct snd_kcontrol *kcontrol,
                break;
 
        case SST_GAIN_MUTE:
-               ucontrol->value.integer.value[0] = gv->mute ? 1 : 0;
+               ucontrol->value.integer.value[0] = gv->mute ? 0 : 1;
                break;
 
        case SST_GAIN_RAMP_DURATION:
@@ -479,7 +479,7 @@ static int sst_gain_put(struct snd_kcontrol *kcontrol,
                break;
 
        case SST_GAIN_MUTE:
-               gv->mute = !!ucontrol->value.integer.value[0];
+               gv->mute = !ucontrol->value.integer.value[0];
                dev_dbg(cmpnt->dev, "%s: Mute %d\n", mc->pname, gv->mute);
                break;
 
@@ -1109,6 +1109,7 @@ static const struct snd_soc_dapm_route intercon[] = {
        {"media0_in", NULL, "Compress Playback"},
        {"media1_in", NULL, "Headset Playback"},
        {"media2_in", NULL, "pcm0_out"},
+       {"media3_in", NULL, "Deepbuffer Playback"},
 
        {"media0_out mix 0", "media0_in Switch", "media0_in"},
        {"media0_out mix 0", "media1_in Switch", "media1_in"},
index 93de8045d4e1ad2062e0c57f487dc1e2e1456fbb..e0113112f668d8c8d8a2fe8692b87d85d92181af 100644 (file)
@@ -28,6 +28,7 @@
 
 enum {
        MERR_DPCM_AUDIO = 0,
+       MERR_DPCM_DEEP_BUFFER,
        MERR_DPCM_COMPR,
 };
 
index 0487cfaac5385a5c8201fbb80cf1b28040e18c74..55c33dc76ce44e2bd3d24de843ff552bb9bfaa30 100644 (file)
@@ -98,6 +98,7 @@ static struct sst_dev_stream_map dpcm_strm_map[] = {
        {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},
+       {MERR_DPCM_DEEP_BUFFER, 0, SNDRV_PCM_STREAM_PLAYBACK, PIPE_MEDIA3_IN, SST_TASK_ID_MEDIA, 0},
 };
 
 static int sst_media_digital_mute(struct snd_soc_dai *dai, int mute, int stream)
@@ -500,14 +501,25 @@ static struct snd_soc_dai_driver sst_platform_dai[] = {
                .channels_min = SST_STEREO,
                .channels_max = SST_STEREO,
                .rates = SNDRV_PCM_RATE_44100|SNDRV_PCM_RATE_48000,
-               .formats = SNDRV_PCM_FMTBIT_S16_LE,
+               .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_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,
+               .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE,
+       },
+},
+{
+       .name = "deepbuffer-cpu-dai",
+       .ops = &sst_media_dai_ops,
+       .playback = {
+               .stream_name = "Deepbuffer Playback",
+               .channels_min = SST_STEREO,
+               .channels_max = SST_STEREO,
+               .rates = SNDRV_PCM_RATE_44100|SNDRV_PCM_RATE_48000,
+               .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE,
        },
 },
 {
@@ -516,10 +528,6 @@ static struct snd_soc_dai_driver sst_platform_dai[] = {
        .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 */
@@ -760,15 +768,15 @@ static int sst_platform_remove(struct platform_device *pdev)
 static int sst_soc_prepare(struct device *dev)
 {
        struct sst_data *drv = dev_get_drvdata(dev);
-       int i;
+       struct snd_soc_pcm_runtime *rtd;
 
        /* 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;
+       list_for_each_entry(rtd, &drv->soc_card->rtd_list, list) {
+               struct snd_soc_dai *dai = rtd->cpu_dai;
 
                if (dai->active) {
                        send_ssp_cmd(dai, dai->name, 0);
@@ -782,11 +790,11 @@ static int sst_soc_prepare(struct device *dev)
 static void sst_soc_complete(struct device *dev)
 {
        struct sst_data *drv = dev_get_drvdata(dev);
-       int i;
+       struct snd_soc_pcm_runtime *rtd;
 
        /* restart SSPs */
-       for (i = 0; i < drv->soc_card->num_rtd; i++) {
-               struct snd_soc_dai *dai = drv->soc_card->rtd[i].cpu_dai;
+       list_for_each_entry(rtd, &drv->soc_card->rtd_list, list) {
+               struct snd_soc_dai *dai = rtd->cpu_dai;
 
                if (dai->active) {
                        sst_handle_vb_timer(dai, true);
index bb19b5801466b4ed04cbc681c11911353ccab2cb..4fce03fc1870b55ba0a44c4999e266ed19ae7bbf 100644 (file)
 #include <acpi/acpi_bus.h>
 #include "../sst-mfld-platform.h"
 #include "../../common/sst-dsp.h"
+#include "../../common/sst-acpi.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
@@ -223,37 +214,16 @@ static int sst_platform_get_resources(struct intel_sst_drv *ctx)
        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 sst_acpi_mach *mach;
        struct platform_device *mdev;
        struct platform_device *plat_dev;
+       struct sst_platform_info *pdata;
        unsigned int dev_id;
 
        id = acpi_match_device(dev->driver->acpi_match_table, dev);
@@ -261,12 +231,13 @@ static int sst_acpi_probe(struct platform_device *pdev)
                return -ENODEV;
        dev_dbg(dev, "for %s", id->id);
 
-       mach = (struct sst_machines *)id->driver_data;
+       mach = (struct sst_acpi_mach *)id->driver_data;
        mach = sst_acpi_find_machine(mach);
        if (mach == NULL) {
                dev_err(dev, "No matching machine driver found\n");
                return -ENODEV;
        }
+       pdata = mach->pdata;
 
        ret = kstrtouint(id->id, 16, &dev_id);
        if (ret < 0) {
@@ -276,16 +247,23 @@ static int sst_acpi_probe(struct platform_device *pdev)
 
        dev_dbg(dev, "ACPI device id: %x\n", dev_id);
 
-       plat_dev = platform_device_register_data(dev, mach->pdata->platform, -1, NULL, 0);
+       plat_dev = platform_device_register_data(dev, pdata->platform, -1,
+                                               NULL, 0);
        if (IS_ERR(plat_dev)) {
-               dev_err(dev, "Failed to create machine device: %s\n", mach->pdata->platform);
+               dev_err(dev, "Failed to create machine device: %s\n",
+                       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);
+       /*
+        * Create platform device for sst machine driver,
+        * pass machine info as pdata
+        */
+       mdev = platform_device_register_data(dev, mach->drv_name, -1,
+                                       (const void *)mach, sizeof(*mach));
        if (IS_ERR(mdev)) {
-               dev_err(dev, "Failed to create machine device: %s\n", mach->machine);
+               dev_err(dev, "Failed to create machine device: %s\n",
+                       mach->drv_name);
                return PTR_ERR(mdev);
        }
 
@@ -294,8 +272,8 @@ static int sst_acpi_probe(struct platform_device *pdev)
                return ret;
 
        /* Fill sst platform data */
-       ctx->pdata = mach->pdata;
-       strcpy(ctx->firmware_name, mach->firmware);
+       ctx->pdata = pdata;
+       strcpy(ctx->firmware_name, mach->fw_filename);
 
        ret = sst_platform_get_resources(ctx);
        if (ret)
@@ -342,22 +320,28 @@ static int sst_acpi_remove(struct platform_device *pdev)
        return 0;
 }
 
-static struct sst_machines sst_acpi_bytcr[] = {
-       {"10EC5640", "T100", "bytt100_rt5640", NULL, "intel/fw_sst_0f28.bin",
+static struct sst_acpi_mach sst_acpi_bytcr[] = {
+       {"10EC5640", "bytcr_rt5640", "intel/fw_sst_0f28.bin", "bytcr_rt5640", NULL,
+                                               &byt_rvp_platform_data },
+       {"10EC5642", "bytcr_rt5640", "intel/fw_sst_0f28.bin", "bytcr_rt5640", NULL,
+                                               &byt_rvp_platform_data },
+       {"INTCCFFD", "bytcr_rt5640", "intel/fw_sst_0f28.bin", "bytcr_rt5640", NULL,
+                                               &byt_rvp_platform_data },
+       {"10EC5651", "bytcr_rt5651", "intel/fw_sst_0f28.bin", "bytcr_rt5651", NULL,
                                                &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",
+static struct sst_acpi_mach sst_acpi_chv[] = {
+       {"10EC5670", "cht-bsw-rt5672", "intel/fw_sst_22a8.bin", "cht-bsw", NULL,
+                                               &chv_platform_data },
+       {"10EC5645", "cht-bsw-rt5645", "intel/fw_sst_22a8.bin", "cht-bsw", NULL,
                                                &chv_platform_data },
-       {"10EC5645", "cht-bsw", "cht-bsw-rt5645", NULL, "intel/fw_sst_22a8.bin",
+       {"10EC5650", "cht-bsw-rt5645", "intel/fw_sst_22a8.bin", "cht-bsw", NULL,
                                                &chv_platform_data },
-       {"10EC5650", "cht-bsw", "cht-bsw-rt5645", NULL, "intel/fw_sst_22a8.bin",
+       {"193C9890", "cht-bsw-max98090", "intel/fw_sst_22a8.bin", "cht-bsw", NULL,
                                                &chv_platform_data },
-       {"193C9890", "cht-bsw", "cht-bsw-max98090", NULL,
-       "intel/fw_sst_22a8.bin", &chv_platform_data },
        {},
 };
 
index a74c64c7053cfa47f41fbd0abb6ec4b144b8f21a..4ccc80e5e8cc0a78aa2cbb805f5ed94c160c5fdf 100644 (file)
@@ -108,7 +108,7 @@ int sst_alloc_stream_mrfld(struct intel_sst_drv *sst_drv_ctx, void *params)
                        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);
+                       &alloc_param, &data, true, true, false, true);
 
        if (ret < 0) {
                dev_err(sst_drv_ctx->dev, "FW alloc failed ret %d\n", ret);
index 79547bec558bc218c505be5a68321497c9dfd70e..4765ad4745444b68929f4282271a6b5cdfe0a9be 100644 (file)
@@ -377,6 +377,8 @@ static int sst_byt_pcm_probe(struct snd_soc_platform *platform)
 
        priv_data = devm_kzalloc(platform->dev, sizeof(*priv_data),
                                 GFP_KERNEL);
+       if (!priv_data)
+               return -ENOMEM;
        priv_data->byt = plat_data->dsp;
        snd_soc_platform_set_drvdata(platform, priv_data);
 
index 371c4565cad8ae9be0574be0f4d60bd54d3d34bf..3310c0f9c356e93e88486f8dc21e77e7dca739d4 100644 (file)
@@ -3,17 +3,23 @@ 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-bytcr-rt5651-objs := bytcr_rt5651.o
 snd-soc-sst-cht-bsw-rt5672-objs := cht_bsw_rt5672.o
 snd-soc-sst-cht-bsw-rt5645-objs := cht_bsw_rt5645.o
 snd-soc-sst-cht-bsw-max98090_ti-objs := cht_bsw_max98090_ti.o
 snd-soc-skl_rt286-objs := skl_rt286.o
+snd-skl_nau88l25_max98357a-objs := skl_nau88l25_max98357a.o
+snd-soc-skl_nau88l25_ssm4567-objs := skl_nau88l25_ssm4567.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_BYTCR_RT5651_MACH) += snd-soc-sst-bytcr-rt5651.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
 obj-$(CONFIG_SND_SOC_INTEL_CHT_BSW_MAX98090_TI_MACH) += snd-soc-sst-cht-bsw-max98090_ti.o
 obj-$(CONFIG_SND_SOC_INTEL_SKL_RT286_MACH) += snd-soc-skl_rt286.o
+obj-$(CONFIG_SND_SOC_INTEL_SKL_NAU88L25_MAX98357A_MACH) += snd-skl_nau88l25_max98357a.o
+obj-$(CONFIG_SND_SOC_INTEL_SKL_NAU88L25_SSM4567_MACH) += snd-soc-skl_nau88l25_ssm4567.o
index 7a5c9a36c1db670081c70480e71e6d6b2a3ef538..9a1752df45a9feacf7687fdd65d8a276c7c9d9ab 100644 (file)
 #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 <linux/input.h>
 #include <sound/pcm.h>
 #include <sound/pcm_params.h>
 #include <sound/soc.h>
+#include <sound/jack.h>
 #include "../../codecs/rt5640.h"
 #include "../atom/sst-atom-controls.h"
+#include "../common/sst-acpi.h"
 
-static const struct snd_soc_dapm_widget byt_dapm_widgets[] = {
+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("Int Mic", NULL),
-       SND_SOC_DAPM_SPK("Ext Spk", NULL),
+       SND_SOC_DAPM_MIC("Internal Mic", NULL),
+       SND_SOC_DAPM_SPK("Speaker", 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"},
-
+static const struct snd_soc_dapm_route byt_rt5640_audio_map[] = {
        {"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"},
+
+       {"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,
 };
 
-static const struct snd_kcontrol_new byt_mc_controls[] = {
+#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("Int Mic"),
-       SOC_DAPM_PIN_SWITCH("Ext Spk"),
+       SOC_DAPM_PIN_SWITCH("Internal Mic"),
+       SOC_DAPM_PIN_SWITCH("Speaker"),
 };
 
-static int byt_aif1_hw_params(struct snd_pcm_substream *substream,
+static int byt_rt5640_aif1_hw_params(struct snd_pcm_substream *substream,
                                        struct snd_pcm_hw_params *params)
 {
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
@@ -92,7 +117,95 @@ static int byt_aif1_hw_params(struct snd_pcm_substream *substream,
        return 0;
 }
 
-static const struct snd_soc_pcm_stream byt_dai_params = {
+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),
+       },
+       {
+               .callback = byt_rt5640_quirk_cb,
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "HP ElitePad 1000 G2"),
+               },
+               .driver_data = (unsigned long *)BYT_RT5640_IN1_MAP,
+       },
+       {}
+};
+
+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;
+
+       rt5640_sel_asrc_clk_src(codec,
+                               RT5640_DA_STEREO_FILTER |
+                               RT5640_AD_STEREO_FILTER,
+                               RT5640_CLK_SEL_ASRC);
+
+       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 const struct snd_soc_pcm_stream byt_rt5640_dai_params = {
        .formats = SNDRV_PCM_FMTBIT_S24_LE,
        .rate_min = 48000,
        .rate_max = 48000,
@@ -100,13 +213,14 @@ static const struct snd_soc_pcm_stream byt_dai_params = {
        .channels_max = 2,
 };
 
-static int byt_codec_fixup(struct snd_soc_pcm_runtime *rtd,
+static int byt_rt5640_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);
+       int ret;
 
        /* The DSP will covert the FE rate to 48k, stereo, 24bits */
        rate->min = rate->max = 48000;
@@ -114,24 +228,46 @@ static int byt_codec_fixup(struct snd_soc_pcm_runtime *rtd,
 
        /* set SSP2 to 24-bit */
        params_set_format(params, SNDRV_PCM_FORMAT_S24_LE);
+
+       /*
+        * Default mode for SSP configuration is TDM 4 slot, override config
+        * with explicit setting to I2S 2ch 24-bit. The word length is set with
+        * dai_set_tdm_slot() since there is no other API exposed
+        */
+       ret = snd_soc_dai_set_fmt(rtd->cpu_dai,
+                                 SND_SOC_DAIFMT_I2S     |
+                                 SND_SOC_DAIFMT_NB_IF   |
+                                 SND_SOC_DAIFMT_CBS_CFS
+                                 );
+       if (ret < 0) {
+               dev_err(rtd->dev, "can't set format to I2S, err %d\n", ret);
+               return ret;
+       }
+
+       ret = snd_soc_dai_set_tdm_slot(rtd->cpu_dai, 0x3, 0x3, 2, 24);
+       if (ret < 0) {
+               dev_err(rtd->dev, "can't set I2S config, err %d\n", ret);
+               return ret;
+       }
+
        return 0;
 }
 
-static int byt_aif1_startup(struct snd_pcm_substream *substream)
+static int byt_rt5640_aif1_startup(struct snd_pcm_substream *substream)
 {
        return snd_pcm_hw_constraint_single(substream->runtime,
                        SNDRV_PCM_HW_PARAM_RATE, 48000);
 }
 
-static struct snd_soc_ops byt_aif1_ops = {
-       .startup = byt_aif1_startup,
+static struct snd_soc_ops byt_rt5640_aif1_ops = {
+       .startup = byt_rt5640_aif1_startup,
 };
 
-static struct snd_soc_ops byt_be_ssp2_ops = {
-       .hw_params = byt_aif1_hw_params,
+static struct snd_soc_ops byt_rt5640_be_ssp2_ops = {
+       .hw_params = byt_rt5640_aif1_hw_params,
 };
 
-static struct snd_soc_dai_link byt_dailink[] = {
+static struct snd_soc_dai_link byt_rt5640_dais[] = {
        [MERR_DPCM_AUDIO] = {
                .name = "Baytrail Audio Port",
                .stream_name = "Baytrail Audio",
@@ -143,7 +279,20 @@ static struct snd_soc_dai_link byt_dailink[] = {
                .dynamic = 1,
                .dpcm_playback = 1,
                .dpcm_capture = 1,
-               .ops = &byt_aif1_ops,
+               .ops = &byt_rt5640_aif1_ops,
+       },
+       [MERR_DPCM_DEEP_BUFFER] = {
+               .name = "Deep-Buffer Audio Port",
+               .stream_name = "Deep-Buffer Audio",
+               .cpu_dai_name = "deepbuffer-cpu-dai",
+               .codec_dai_name = "snd-soc-dummy-dai",
+               .codec_name = "snd-soc-dummy",
+               .platform_name = "sst-mfld-platform",
+               .ignore_suspend = 1,
+               .nonatomic = true,
+               .dynamic = 1,
+               .dpcm_playback = 1,
+               .ops = &byt_rt5640_aif1_ops,
        },
        [MERR_DPCM_COMPR] = {
                .name = "Baytrail Compressed Port",
@@ -161,58 +310,69 @@ static struct snd_soc_dai_link byt_dailink[] = {
                .platform_name = "sst-mfld-platform",
                .no_pcm = 1,
                .codec_dai_name = "rt5640-aif1",
-               .codec_name = "i2c-10EC5640:00",
+               .codec_name = "i2c-10EC5640:00", /* overwritten with HID */
                .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF
                                                | SND_SOC_DAIFMT_CBS_CFS,
-               .be_hw_params_fixup = byt_codec_fixup,
+               .be_hw_params_fixup = byt_rt5640_codec_fixup,
                .ignore_suspend = 1,
                .dpcm_playback = 1,
                .dpcm_capture = 1,
-               .ops = &byt_be_ssp2_ops,
+               .init = byt_rt5640_init,
+               .ops = &byt_rt5640_be_ssp2_ops,
        },
 };
 
 /* SoC card */
-static struct snd_soc_card snd_soc_card_byt = {
-       .name = "baytrailcraudio",
+static struct snd_soc_card byt_rt5640_card = {
+       .name = "bytcr-rt5640",
        .owner = THIS_MODULE,
-       .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),
+       .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 snd_byt_mc_probe(struct platform_device *pdev)
+static char byt_rt5640_codec_name[16]; /* i2c-<HID>:00 with HID being 8 chars */
+
+static int snd_byt_rt5640_mc_probe(struct platform_device *pdev)
 {
        int ret_val = 0;
+       struct sst_acpi_mach *mach;
 
        /* register the soc card */
-       snd_soc_card_byt.dev = &pdev->dev;
+       byt_rt5640_card.dev = &pdev->dev;
+       mach = byt_rt5640_card.dev->platform_data;
+
+       /* fixup codec name based on HID */
+       snprintf(byt_rt5640_codec_name, sizeof(byt_rt5640_codec_name),
+                "%s%s%s", "i2c-", mach->id, ":00");
+       byt_rt5640_dais[MERR_DPCM_COMPR+1].codec_name = byt_rt5640_codec_name;
+
+       ret_val = devm_snd_soc_register_card(&pdev->dev, &byt_rt5640_card);
 
-       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);
+               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);
+       platform_set_drvdata(pdev, &byt_rt5640_card);
        return ret_val;
 }
 
-static struct platform_driver snd_byt_mc_driver = {
+static struct platform_driver snd_byt_rt5640_mc_driver = {
        .driver = {
-               .name = "bytt100_rt5640",
+               .name = "bytcr_rt5640",
                .pm = &snd_soc_pm_ops,
        },
-       .probe = snd_byt_mc_probe,
+       .probe = snd_byt_rt5640_mc_probe,
 };
 
-module_platform_driver(snd_byt_mc_driver);
+module_platform_driver(snd_byt_rt5640_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");
+MODULE_ALIAS("platform:bytcr_rt5640");
diff --git a/sound/soc/intel/boards/bytcr_rt5651.c b/sound/soc/intel/boards/bytcr_rt5651.c
new file mode 100644 (file)
index 0000000..1c95ccc
--- /dev/null
@@ -0,0 +1,332 @@
+/*
+ *  bytcr_rt5651.c - ASoc Machine driver for Intel Byt CR platform
+ *  (derived from bytcr_rt5640.c)
+ *
+ *  Copyright (C) 2015 Intel Corp
+ *  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ *
+ *  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/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/rt5651.h"
+#include "../atom/sst-atom-controls.h"
+
+static const struct snd_soc_dapm_widget byt_rt5651_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_rt5651_audio_map[] = {
+       {"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"},
+
+       {"Headset Mic", NULL, "micbias1"}, /* lowercase for rt5651 */
+       {"IN2P", NULL, "Headset Mic"},
+       {"Headphone", NULL, "HPOL"},
+       {"Headphone", NULL, "HPOR"},
+       {"Speaker", NULL, "LOUTL"},
+       {"Speaker", NULL, "LOUTR"},
+};
+
+static const struct snd_soc_dapm_route byt_rt5651_intmic_dmic1_map[] = {
+       {"DMIC1", NULL, "Internal Mic"},
+};
+
+static const struct snd_soc_dapm_route byt_rt5651_intmic_dmic2_map[] = {
+       {"DMIC2", NULL, "Internal Mic"},
+};
+
+static const struct snd_soc_dapm_route byt_rt5651_intmic_in1_map[] = {
+       {"Internal Mic", NULL, "micbias1"},
+       {"IN1P", NULL, "Internal Mic"},
+};
+
+enum {
+       BYT_RT5651_DMIC1_MAP,
+       BYT_RT5651_DMIC2_MAP,
+       BYT_RT5651_IN1_MAP,
+};
+
+#define BYT_RT5651_MAP(quirk)  ((quirk) & 0xff)
+#define BYT_RT5651_DMIC_EN     BIT(16)
+
+static unsigned long byt_rt5651_quirk = BYT_RT5651_DMIC1_MAP |
+                                       BYT_RT5651_DMIC_EN;
+
+static const struct snd_kcontrol_new byt_rt5651_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_rt5651_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, RT5651_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, RT5651_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 dmi_system_id byt_rt5651_quirk_table[] = {
+       {}
+};
+
+static int byt_rt5651_init(struct snd_soc_pcm_runtime *runtime)
+{
+       int ret;
+       struct snd_soc_card *card = runtime->card;
+       const struct snd_soc_dapm_route *custom_map;
+       int num_routes;
+
+       card->dapm.idle_bias_off = true;
+
+       dmi_check_system(byt_rt5651_quirk_table);
+       switch (BYT_RT5651_MAP(byt_rt5651_quirk)) {
+       case BYT_RT5651_IN1_MAP:
+               custom_map = byt_rt5651_intmic_in1_map;
+               num_routes = ARRAY_SIZE(byt_rt5651_intmic_in1_map);
+               break;
+       case BYT_RT5651_DMIC2_MAP:
+               custom_map = byt_rt5651_intmic_dmic2_map;
+               num_routes = ARRAY_SIZE(byt_rt5651_intmic_dmic2_map);
+               break;
+       default:
+               custom_map = byt_rt5651_intmic_dmic1_map;
+               num_routes = ARRAY_SIZE(byt_rt5651_intmic_dmic1_map);
+       }
+
+       ret = snd_soc_add_card_controls(card, byt_rt5651_controls,
+                                       ARRAY_SIZE(byt_rt5651_controls));
+       if (ret) {
+               dev_err(card->dev, "unable to add card controls\n");
+               return ret;
+       }
+       snd_soc_dapm_ignore_suspend(&card->dapm, "Headphone");
+       snd_soc_dapm_ignore_suspend(&card->dapm, "Speaker");
+
+       return ret;
+}
+
+static const struct snd_soc_pcm_stream byt_rt5651_dai_params = {
+       .formats = SNDRV_PCM_FMTBIT_S24_LE,
+       .rate_min = 48000,
+       .rate_max = 48000,
+       .channels_min = 2,
+       .channels_max = 2,
+};
+
+static int byt_rt5651_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);
+       int ret;
+
+       /* 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);
+
+       /*
+        * Default mode for SSP configuration is TDM 4 slot, override config
+        * with explicit setting to I2S 2ch 24-bit. The word length is set with
+        * dai_set_tdm_slot() since there is no other API exposed
+        */
+       ret = snd_soc_dai_set_fmt(rtd->cpu_dai,
+                                 SND_SOC_DAIFMT_I2S     |
+                                 SND_SOC_DAIFMT_NB_IF   |
+                                 SND_SOC_DAIFMT_CBS_CFS
+                                 );
+
+       if (ret < 0) {
+               dev_err(rtd->dev, "can't set format to I2S, err %d\n", ret);
+               return ret;
+       }
+
+       ret = snd_soc_dai_set_tdm_slot(rtd->cpu_dai, 0x3, 0x3, 2, 24);
+       if (ret < 0) {
+               dev_err(rtd->dev, "can't set I2S config, err %d\n", ret);
+               return ret;
+       }
+
+       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_rt5651_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_rt5651_aif1_ops = {
+       .startup = byt_rt5651_aif1_startup,
+};
+
+static struct snd_soc_ops byt_rt5651_be_ssp2_ops = {
+       .hw_params = byt_rt5651_aif1_hw_params,
+};
+
+static struct snd_soc_dai_link byt_rt5651_dais[] = {
+       [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,
+               .nonatomic = true,
+               .dynamic = 1,
+               .dpcm_playback = 1,
+               .dpcm_capture = 1,
+               .ops = &byt_rt5651_aif1_ops,
+       },
+       [MERR_DPCM_DEEP_BUFFER] = {
+               .name = "Deep-Buffer Audio Port",
+               .stream_name = "Deep-Buffer Audio",
+               .cpu_dai_name = "deepbuffer-cpu-dai",
+               .codec_dai_name = "snd-soc-dummy-dai",
+               .codec_name = "snd-soc-dummy",
+               .platform_name = "sst-mfld-platform",
+               .ignore_suspend = 1,
+               .nonatomic = true,
+               .dynamic = 1,
+               .dpcm_playback = 1,
+               .ops = &byt_rt5651_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 = "rt5651-aif1",
+               .codec_name = "i2c-10EC5651:00",
+               .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF
+                                               | SND_SOC_DAIFMT_CBS_CFS,
+               .be_hw_params_fixup = byt_rt5651_codec_fixup,
+               .ignore_suspend = 1,
+               .nonatomic = true,
+               .dpcm_playback = 1,
+               .dpcm_capture = 1,
+               .init = byt_rt5651_init,
+               .ops = &byt_rt5651_be_ssp2_ops,
+       },
+};
+
+/* SoC card */
+static struct snd_soc_card byt_rt5651_card = {
+       .name = "bytcr-rt5651",
+       .owner = THIS_MODULE,
+       .dai_link = byt_rt5651_dais,
+       .num_links = ARRAY_SIZE(byt_rt5651_dais),
+       .dapm_widgets = byt_rt5651_widgets,
+       .num_dapm_widgets = ARRAY_SIZE(byt_rt5651_widgets),
+       .dapm_routes = byt_rt5651_audio_map,
+       .num_dapm_routes = ARRAY_SIZE(byt_rt5651_audio_map),
+       .fully_routed = true,
+};
+
+static int snd_byt_rt5651_mc_probe(struct platform_device *pdev)
+{
+       int ret_val = 0;
+
+       /* register the soc card */
+       byt_rt5651_card.dev = &pdev->dev;
+
+       ret_val = devm_snd_soc_register_card(&pdev->dev, &byt_rt5651_card);
+
+       if (ret_val) {
+               dev_err(&pdev->dev, "devm_snd_soc_register_card failed %d\n",
+                       ret_val);
+               return ret_val;
+       }
+       platform_set_drvdata(pdev, &byt_rt5651_card);
+       return ret_val;
+}
+
+static struct platform_driver snd_byt_rt5651_mc_driver = {
+       .driver = {
+               .name = "bytcr_rt5651",
+               .pm = &snd_soc_pm_ops,
+       },
+       .probe = snd_byt_rt5651_mc_probe,
+};
+
+module_platform_driver(snd_byt_rt5651_mc_driver);
+
+MODULE_DESCRIPTION("ASoC Intel(R) Baytrail CR Machine driver for RT5651");
+MODULE_AUTHOR("Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com>");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:bytcr_rt5651");
index 4e2fcf188dd1e0be1dce9a618929235f35bcb5a0..90588d6e64fc7869a4a4a210b0f188a01e7907b8 100644 (file)
@@ -41,12 +41,9 @@ struct cht_mc_private {
 
 static inline struct snd_soc_dai *cht_get_codec_dai(struct snd_soc_card *card)
 {
-       int i;
+       struct snd_soc_pcm_runtime *rtd;
 
-       for (i = 0; i < card->num_rtd; i++) {
-               struct snd_soc_pcm_runtime *rtd;
-
-               rtd = card->rtd + i;
+       list_for_each_entry(rtd, &card->rtd_list, list) {
                if (!strncmp(rtd->codec_dai->name, CHT_CODEC_DAI,
                             strlen(CHT_CODEC_DAI)))
                        return rtd->codec_dai;
@@ -235,6 +232,18 @@ static struct snd_soc_dai_link cht_dailink[] = {
                .dpcm_capture = 1,
                .ops = &cht_aif1_ops,
        },
+       [MERR_DPCM_DEEP_BUFFER] = {
+               .name = "Deep-Buffer Audio Port",
+               .stream_name = "Deep-Buffer Audio",
+               .cpu_dai_name = "deepbuffer-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,
+               .ops = &cht_aif1_ops,
+       },
        [MERR_DPCM_COMPR] = {
                .name = "Compressed Port",
                .stream_name = "Compress",
index 38d65a3529c4fc1fda0464d05057e0055b6afe35..2d3afddb0a2e8c83fef54b36eed42d7ff6b69878 100644 (file)
@@ -47,12 +47,9 @@ struct cht_mc_private {
 
 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;
+       struct snd_soc_pcm_runtime *rtd;
 
-               rtd = card->rtd + i;
+       list_for_each_entry(rtd, &card->rtd_list, list) {
                if (!strncmp(rtd->codec_dai->name, CHT_CODEC_DAI,
                             strlen(CHT_CODEC_DAI)))
                        return rtd->codec_dai;
@@ -263,6 +260,18 @@ static struct snd_soc_dai_link cht_dailink[] = {
                .dpcm_capture = 1,
                .ops = &cht_aif1_ops,
        },
+       [MERR_DPCM_DEEP_BUFFER] = {
+               .name = "Deep-Buffer Audio Port",
+               .stream_name = "Deep-Buffer Audio",
+               .cpu_dai_name = "deepbuffer-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,
+               .ops = &cht_aif1_ops,
+       },
        [MERR_DPCM_COMPR] = {
                .name = "Compressed Port",
                .stream_name = "Compress",
index 5621ccd92992d9f198bd5d0fd6149f06d0a3631a..2e5347f8f96c449f9fde65dc614f43439acd155b 100644 (file)
@@ -46,12 +46,9 @@ static struct snd_soc_jack_pin cht_bsw_headset_pins[] = {
 
 static inline struct snd_soc_dai *cht_get_codec_dai(struct snd_soc_card *card)
 {
-       int i;
+       struct snd_soc_pcm_runtime *rtd;
 
-       for (i = 0; i < card->num_rtd; i++) {
-               struct snd_soc_pcm_runtime *rtd;
-
-               rtd = card->rtd + i;
+       list_for_each_entry(rtd, &card->rtd_list, list) {
                if (!strncmp(rtd->codec_dai->name, CHT_CODEC_DAI,
                             strlen(CHT_CODEC_DAI)))
                        return rtd->codec_dai;
@@ -251,6 +248,18 @@ static struct snd_soc_dai_link cht_dailink[] = {
                .dpcm_capture = 1,
                .ops = &cht_aif1_ops,
        },
+       [MERR_DPCM_DEEP_BUFFER] = {
+               .name = "Deep-Buffer Audio Port",
+               .stream_name = "Deep-Buffer Audio",
+               .cpu_dai_name = "deepbuffer-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,
+               .ops = &cht_aif1_ops,
+       },
        [MERR_DPCM_COMPR] = {
                .name = "Compressed Port",
                .stream_name = "Compress",
diff --git a/sound/soc/intel/boards/skl_nau88l25_max98357a.c b/sound/soc/intel/boards/skl_nau88l25_max98357a.c
new file mode 100644 (file)
index 0000000..ab7da9c
--- /dev/null
@@ -0,0 +1,485 @@
+/*
+ * Intel Skylake I2S Machine Driver with MAXIM98357A
+ * and NAU88L25
+ *
+ * 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/module.h>
+#include <linux/platform_device.h>
+#include <sound/core.h>
+#include <sound/jack.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include "../../codecs/nau8825.h"
+
+#define SKL_NUVOTON_CODEC_DAI  "nau8825-hifi"
+#define SKL_MAXIM_CODEC_DAI "HiFi"
+
+static struct snd_soc_jack skylake_headset;
+static struct snd_soc_card skylake_audio_card;
+
+static inline struct snd_soc_dai *skl_get_codec_dai(struct snd_soc_card *card)
+{
+       struct snd_soc_pcm_runtime *rtd;
+
+       list_for_each_entry(rtd, &card->rtd_list, list) {
+
+               if (!strncmp(rtd->codec_dai->name, SKL_NUVOTON_CODEC_DAI,
+                            strlen(SKL_NUVOTON_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 = skl_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)) {
+               ret = snd_soc_dai_set_sysclk(codec_dai,
+                               NAU8825_CLK_MCLK, 24000000, SND_SOC_CLOCK_IN);
+               if (ret < 0) {
+                       dev_err(card->dev, "set sysclk err = %d\n", ret);
+                       return -EIO;
+               }
+       } else {
+               ret = snd_soc_dai_set_sysclk(codec_dai,
+                               NAU8825_CLK_INTERNAL, 0, SND_SOC_CLOCK_IN);
+               if (ret < 0) {
+                       dev_err(card->dev, "set sysclk err = %d\n", ret);
+                       return -EIO;
+               }
+       }
+
+       return ret;
+}
+
+static const struct snd_kcontrol_new skylake_controls[] = {
+       SOC_DAPM_PIN_SWITCH("Headphone Jack"),
+       SOC_DAPM_PIN_SWITCH("Headset Mic"),
+       SOC_DAPM_PIN_SWITCH("Spk"),
+};
+
+static const struct snd_soc_dapm_widget skylake_widgets[] = {
+       SND_SOC_DAPM_HP("Headphone Jack", NULL),
+       SND_SOC_DAPM_MIC("Headset Mic", NULL),
+       SND_SOC_DAPM_SPK("Spk", NULL),
+       SND_SOC_DAPM_MIC("SoC DMIC", NULL),
+       SND_SOC_DAPM_SINK("WoV Sink"),
+       SND_SOC_DAPM_SPK("DP", NULL),
+       SND_SOC_DAPM_SPK("HDMI", 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 skylake_map[] = {
+       /* HP jack connectors - unknown if we have jack detection */
+       { "Headphone Jack", NULL, "HPOL" },
+       { "Headphone Jack", NULL, "HPOR" },
+
+       /* speaker */
+       { "Spk", NULL, "Speaker" },
+
+       /* other jacks */
+       { "MIC", NULL, "Headset Mic" },
+       { "DMic", NULL, "SoC DMIC" },
+
+       {"WoV Sink", NULL, "hwd_in sink"},
+       {"HDMI", NULL, "hif5 Output"},
+       {"DP", NULL, "hif6 Output"},
+
+       /* CODEC BE connections */
+       { "HiFi Playback", NULL, "ssp0 Tx" },
+       { "ssp0 Tx", NULL, "codec0_out" },
+
+       { "Playback", NULL, "ssp1 Tx" },
+       { "ssp1 Tx", NULL, "codec1_out" },
+
+       { "codec0_in", NULL, "ssp1 Rx" },
+       { "ssp1 Rx", NULL, "Capture" },
+
+       /* DMIC */
+       { "dmic01_hifi", NULL, "DMIC01 Rx" },
+       { "DMIC01 Rx", NULL, "DMIC AIF" },
+       { "hifi1", NULL, "iDisp Tx"},
+       { "iDisp Tx", NULL, "iDisp_out"},
+       { "Headphone Jack", NULL, "Platform Clock" },
+       { "Headset Mic", NULL, "Platform Clock" },
+};
+
+static int skylake_ssp_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);
+       struct snd_mask *fmt = hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT);
+
+       /* The ADSP will covert the FE rate to 48k, stereo */
+       rate->min = rate->max = 48000;
+       channels->min = channels->max = 2;
+
+       /* set SSP0 to 24 bit */
+       snd_mask_none(fmt);
+       snd_mask_set(fmt, SNDRV_PCM_FORMAT_S24_LE);
+
+       return 0;
+}
+
+static int skylake_nau8825_codec_init(struct snd_soc_pcm_runtime *rtd)
+{
+       int ret;
+       struct snd_soc_codec *codec = rtd->codec;
+
+       /*
+        * Headset buttons map to the google Reference headset.
+        * These can be configured by userspace.
+        */
+       ret = snd_soc_card_jack_new(&skylake_audio_card, "Headset Jack",
+                       SND_JACK_HEADSET | SND_JACK_BTN_0 | SND_JACK_BTN_1 |
+                       SND_JACK_BTN_2 | SND_JACK_BTN_3, &skylake_headset,
+                       NULL, 0);
+       if (ret) {
+               dev_err(rtd->dev, "Headset Jack creation failed %d\n", ret);
+               return ret;
+       }
+
+       nau8825_enable_jack_detect(codec, &skylake_headset);
+
+       snd_soc_dapm_ignore_suspend(&rtd->card->dapm, "SoC DMIC");
+       snd_soc_dapm_ignore_suspend(&rtd->card->dapm, "WoV Sink");
+
+       return ret;
+}
+
+static int skylake_nau8825_fe_init(struct snd_soc_pcm_runtime *rtd)
+{
+       struct snd_soc_dapm_context *dapm;
+       struct snd_soc_component *component = rtd->cpu_dai->component;
+
+       dapm = snd_soc_component_get_dapm(component);
+       snd_soc_dapm_ignore_suspend(dapm, "Reference Capture");
+
+       return 0;
+}
+
+static unsigned int rates[] = {
+       48000,
+};
+
+static struct snd_pcm_hw_constraint_list constraints_rates = {
+       .count = ARRAY_SIZE(rates),
+       .list  = rates,
+       .mask = 0,
+};
+
+static unsigned int channels[] = {
+       2,
+};
+
+static struct snd_pcm_hw_constraint_list constraints_channels = {
+       .count = ARRAY_SIZE(channels),
+       .list = channels,
+       .mask = 0,
+};
+
+static int skl_fe_startup(struct snd_pcm_substream *substream)
+{
+       struct snd_pcm_runtime *runtime = substream->runtime;
+
+       /*
+        * On this platform for PCM device we support,
+        * 48Khz
+        * stereo
+        * 16 bit audio
+        */
+
+       runtime->hw.channels_max = 2;
+       snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS,
+                                          &constraints_channels);
+
+       runtime->hw.formats = SNDRV_PCM_FMTBIT_S16_LE;
+       snd_pcm_hw_constraint_msbits(runtime, 0, 16, 16);
+
+       snd_pcm_hw_constraint_list(runtime, 0,
+                               SNDRV_PCM_HW_PARAM_RATE, &constraints_rates);
+
+       return 0;
+}
+
+static const struct snd_soc_ops skylake_nau8825_fe_ops = {
+       .startup = skl_fe_startup,
+};
+
+static int skylake_nau8825_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,
+                       NAU8825_CLK_MCLK, 24000000, SND_SOC_CLOCK_IN);
+
+       if (ret < 0)
+               dev_err(rtd->dev, "snd_soc_dai_set_sysclk err = %d\n", ret);
+
+       return ret;
+}
+
+static struct snd_soc_ops skylake_nau8825_ops = {
+       .hw_params = skylake_nau8825_hw_params,
+};
+
+static int skylake_dmic_fixup(struct snd_soc_pcm_runtime *rtd,
+               struct snd_pcm_hw_params *params)
+{
+       struct snd_interval *channels = hw_param_interval(params,
+                               SNDRV_PCM_HW_PARAM_CHANNELS);
+
+       if (params_channels(params) == 2)
+               channels->min = channels->max = 2;
+       else
+               channels->min = channels->max = 4;
+
+       return 0;
+}
+
+static unsigned int channels_dmic[] = {
+       2, 4,
+};
+
+static struct snd_pcm_hw_constraint_list constraints_dmic_channels = {
+       .count = ARRAY_SIZE(channels_dmic),
+       .list = channels_dmic,
+       .mask = 0,
+};
+
+static int skylake_dmic_startup(struct snd_pcm_substream *substream)
+{
+       struct snd_pcm_runtime *runtime = substream->runtime;
+
+       runtime->hw.channels_max = 4;
+       snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS,
+                       &constraints_dmic_channels);
+
+       return snd_pcm_hw_constraint_list(substream->runtime, 0,
+                       SNDRV_PCM_HW_PARAM_RATE, &constraints_rates);
+}
+
+static struct snd_soc_ops skylake_dmic_ops = {
+       .startup = skylake_dmic_startup,
+};
+
+static unsigned int rates_16000[] = {
+       16000,
+};
+
+static struct snd_pcm_hw_constraint_list constraints_16000 = {
+       .count = ARRAY_SIZE(rates_16000),
+       .list  = rates_16000,
+};
+
+static int skylake_refcap_startup(struct snd_pcm_substream *substream)
+{
+       return snd_pcm_hw_constraint_list(substream->runtime, 0,
+                               SNDRV_PCM_HW_PARAM_RATE,
+                               &constraints_16000);
+}
+
+static struct snd_soc_ops skylaye_refcap_ops = {
+       .startup = skylake_refcap_startup,
+};
+
+/* skylake digital audio interface glue - connects codec <--> CPU */
+static struct snd_soc_dai_link skylake_dais[] = {
+       /* Front End DAI links */
+       {
+               .name = "Skl Audio Port",
+               .stream_name = "Audio",
+               .cpu_dai_name = "System Pin",
+               .platform_name = "0000:00:1f.3",
+               .dynamic = 1,
+               .codec_name = "snd-soc-dummy",
+               .codec_dai_name = "snd-soc-dummy-dai",
+               .nonatomic = 1,
+               .init = skylake_nau8825_fe_init,
+               .trigger = {
+                       SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST},
+               .dpcm_playback = 1,
+               .ops = &skylake_nau8825_fe_ops,
+       },
+       {
+               .name = "Skl Audio Capture Port",
+               .stream_name = "Audio Record",
+               .cpu_dai_name = "System Pin",
+               .platform_name = "0000:00:1f.3",
+               .dynamic = 1,
+               .codec_name = "snd-soc-dummy",
+               .codec_dai_name = "snd-soc-dummy-dai",
+               .nonatomic = 1,
+               .trigger = {
+                       SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST},
+               .dpcm_capture = 1,
+               .ops = &skylake_nau8825_fe_ops,
+       },
+       {
+               .name = "Skl Audio Reference cap",
+               .stream_name = "Wake on Voice",
+               .cpu_dai_name = "Reference Pin",
+               .codec_name = "snd-soc-dummy",
+               .codec_dai_name = "snd-soc-dummy-dai",
+               .platform_name = "0000:00:1f.3",
+               .init = NULL,
+               .dpcm_capture = 1,
+               .ignore_suspend = 1,
+               .nonatomic = 1,
+               .dynamic = 1,
+               .ops = &skylaye_refcap_ops,
+       },
+       {
+               .name = "Skl Audio DMIC cap",
+               .stream_name = "dmiccap",
+               .cpu_dai_name = "DMIC Pin",
+               .codec_name = "snd-soc-dummy",
+               .codec_dai_name = "snd-soc-dummy-dai",
+               .platform_name = "0000:00:1f.3",
+               .init = NULL,
+               .dpcm_capture = 1,
+               .nonatomic = 1,
+               .dynamic = 1,
+               .ops = &skylake_dmic_ops,
+       },
+       {
+               .name = "Skl HDMI Port",
+               .stream_name = "Hdmi",
+               .cpu_dai_name = "HDMI Pin",
+               .codec_name = "snd-soc-dummy",
+               .codec_dai_name = "snd-soc-dummy-dai",
+               .platform_name = "0000:00:1f.3",
+               .dpcm_playback = 1,
+               .init = NULL,
+               .nonatomic = 1,
+               .dynamic = 1,
+       },
+
+       /* Back End DAI links */
+       {
+               /* SSP0 - Codec */
+               .name = "SSP0-Codec",
+               .be_id = 0,
+               .cpu_dai_name = "SSP0 Pin",
+               .platform_name = "0000:00:1f.3",
+               .no_pcm = 1,
+               .codec_name = "MX98357A:00",
+               .codec_dai_name = SKL_MAXIM_CODEC_DAI,
+               .dai_fmt = SND_SOC_DAIFMT_I2S |
+                       SND_SOC_DAIFMT_NB_NF |
+                       SND_SOC_DAIFMT_CBS_CFS,
+               .ignore_pmdown_time = 1,
+               .be_hw_params_fixup = skylake_ssp_fixup,
+               .dpcm_playback = 1,
+       },
+       {
+               /* SSP1 - Codec */
+               .name = "SSP1-Codec",
+               .be_id = 0,
+               .cpu_dai_name = "SSP1 Pin",
+               .platform_name = "0000:00:1f.3",
+               .no_pcm = 1,
+               .codec_name = "i2c-10508825:00",
+               .codec_dai_name = SKL_NUVOTON_CODEC_DAI,
+               .init = skylake_nau8825_codec_init,
+               .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
+                       SND_SOC_DAIFMT_CBS_CFS,
+               .ignore_pmdown_time = 1,
+               .be_hw_params_fixup = skylake_ssp_fixup,
+               .ops = &skylake_nau8825_ops,
+               .dpcm_playback = 1,
+               .dpcm_capture = 1,
+       },
+       {
+               .name = "dmic01",
+               .be_id = 1,
+               .cpu_dai_name = "DMIC01 Pin",
+               .codec_name = "dmic-codec",
+               .codec_dai_name = "dmic-hifi",
+               .platform_name = "0000:00:1f.3",
+               .be_hw_params_fixup = skylake_dmic_fixup,
+               .ignore_suspend = 1,
+               .dpcm_capture = 1,
+               .no_pcm = 1,
+       },
+       {
+               .name = "iDisp",
+               .be_id = 3,
+               .cpu_dai_name = "iDisp Pin",
+               .codec_name = "ehdaudio0D2",
+               .codec_dai_name = "intel-hdmi-hifi1",
+               .platform_name = "0000:00:1f.3",
+               .dpcm_playback = 1,
+               .no_pcm = 1,
+       },
+};
+
+/* skylake audio machine driver for SPT + NAU88L25 */
+static struct snd_soc_card skylake_audio_card = {
+       .name = "sklnau8825max",
+       .owner = THIS_MODULE,
+       .dai_link = skylake_dais,
+       .num_links = ARRAY_SIZE(skylake_dais),
+       .controls = skylake_controls,
+       .num_controls = ARRAY_SIZE(skylake_controls),
+       .dapm_widgets = skylake_widgets,
+       .num_dapm_widgets = ARRAY_SIZE(skylake_widgets),
+       .dapm_routes = skylake_map,
+       .num_dapm_routes = ARRAY_SIZE(skylake_map),
+       .fully_routed = true,
+};
+
+static int skylake_audio_probe(struct platform_device *pdev)
+{
+       skylake_audio_card.dev = &pdev->dev;
+
+       return devm_snd_soc_register_card(&pdev->dev, &skylake_audio_card);
+}
+
+static struct platform_driver skylake_audio = {
+       .probe = skylake_audio_probe,
+       .driver = {
+               .name = "skl_nau88l25_max98357a_i2s",
+               .pm = &snd_soc_pm_ops,
+       },
+};
+
+module_platform_driver(skylake_audio)
+
+/* Module information */
+MODULE_DESCRIPTION("Audio Machine driver-NAU88L25 & MAX98357A in I2S mode");
+MODULE_AUTHOR("Rohit Ainapure <rohit.m.ainapure@intel.com");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:skl_nau88l25_max98357a_i2s");
diff --git a/sound/soc/intel/boards/skl_nau88l25_ssm4567.c b/sound/soc/intel/boards/skl_nau88l25_ssm4567.c
new file mode 100644 (file)
index 0000000..c071812
--- /dev/null
@@ -0,0 +1,536 @@
+/*
+ * Intel Skylake I2S Machine Driver for NAU88L25+SSM4567
+ *
+ * Copyright (C) 2015, Intel Corporation. All rights reserved.
+ *
+ * Modified from:
+ *   Intel Skylake I2S Machine Driver for NAU88L25 and SSM4567
+ *
+ *   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/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 "../../codecs/nau8825.h"
+
+#define SKL_NUVOTON_CODEC_DAI  "nau8825-hifi"
+#define SKL_SSM_CODEC_DAI      "ssm4567-hifi"
+
+static struct snd_soc_jack skylake_headset;
+static struct snd_soc_card skylake_audio_card;
+
+static inline struct snd_soc_dai *skl_get_codec_dai(struct snd_soc_card *card)
+{
+       struct snd_soc_pcm_runtime *rtd;
+
+       list_for_each_entry(rtd, &card->rtd_list, list) {
+
+               if (!strncmp(rtd->codec_dai->name, SKL_NUVOTON_CODEC_DAI,
+                            strlen(SKL_NUVOTON_CODEC_DAI)))
+                       return rtd->codec_dai;
+       }
+
+       return NULL;
+}
+
+static const struct snd_kcontrol_new skylake_controls[] = {
+       SOC_DAPM_PIN_SWITCH("Headphone Jack"),
+       SOC_DAPM_PIN_SWITCH("Headset Mic"),
+       SOC_DAPM_PIN_SWITCH("Left Speaker"),
+       SOC_DAPM_PIN_SWITCH("Right Speaker"),
+};
+
+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 = skl_get_codec_dai(card);
+       if (!codec_dai) {
+               dev_err(card->dev, "Codec dai not found\n");
+               return -EIO;
+       }
+
+       if (SND_SOC_DAPM_EVENT_ON(event)) {
+               ret = snd_soc_dai_set_sysclk(codec_dai,
+                               NAU8825_CLK_MCLK, 24000000, SND_SOC_CLOCK_IN);
+               if (ret < 0) {
+                       dev_err(card->dev, "set sysclk err = %d\n", ret);
+                       return -EIO;
+               }
+       } else {
+               ret = snd_soc_dai_set_sysclk(codec_dai,
+                               NAU8825_CLK_INTERNAL, 0, SND_SOC_CLOCK_IN);
+               if (ret < 0) {
+                       dev_err(card->dev, "set sysclk err = %d\n", ret);
+                       return -EIO;
+               }
+       }
+       return ret;
+}
+
+static const struct snd_soc_dapm_widget skylake_widgets[] = {
+       SND_SOC_DAPM_HP("Headphone Jack", NULL),
+       SND_SOC_DAPM_MIC("Headset Mic", NULL),
+       SND_SOC_DAPM_SPK("Left Speaker", NULL),
+       SND_SOC_DAPM_SPK("Right Speaker", NULL),
+       SND_SOC_DAPM_MIC("SoC DMIC", NULL),
+       SND_SOC_DAPM_SINK("WoV Sink"),
+       SND_SOC_DAPM_SPK("DP", NULL),
+       SND_SOC_DAPM_SPK("HDMI", 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 skylake_map[] = {
+       /* HP jack connectors - unknown if we have jack detection */
+       {"Headphone Jack", NULL, "HPOL"},
+       {"Headphone Jack", NULL, "HPOR"},
+
+       /* speaker */
+       {"Left Speaker", NULL, "Left OUT"},
+       {"Right Speaker", NULL, "Right OUT"},
+
+       /* other jacks */
+       {"MIC", NULL, "Headset Mic"},
+       {"DMic", NULL, "SoC DMIC"},
+
+       {"WoV Sink", NULL, "hwd_in sink"},
+
+       {"HDMI", NULL, "hif5 Output"},
+       {"DP", NULL, "hif6 Output"},
+       /* CODEC BE connections */
+       { "Left Playback", NULL, "ssp0 Tx"},
+       { "Right Playback", NULL, "ssp0 Tx"},
+       { "ssp0 Tx", NULL, "codec0_out"},
+
+       { "Playback", NULL, "ssp1 Tx"},
+       { "ssp1 Tx", NULL, "codec1_out"},
+
+       { "codec0_in", NULL, "ssp1 Rx" },
+       { "ssp1 Rx", NULL, "Capture" },
+
+       /* DMIC */
+       { "dmic01_hifi", NULL, "DMIC01 Rx" },
+       { "DMIC01 Rx", NULL, "DMIC AIF" },
+       { "hifi1", NULL, "iDisp Tx"},
+       { "iDisp Tx", NULL, "iDisp_out"},
+       { "Headphone Jack", NULL, "Platform Clock" },
+       { "Headset Mic", NULL, "Platform Clock" },
+};
+
+static struct snd_soc_codec_conf ssm4567_codec_conf[] = {
+       {
+               .dev_name = "i2c-INT343B:00",
+               .name_prefix = "Left",
+       },
+       {
+               .dev_name = "i2c-INT343B:01",
+               .name_prefix = "Right",
+       },
+};
+
+static struct snd_soc_dai_link_component ssm4567_codec_components[] = {
+       { /* Left */
+               .name = "i2c-INT343B:00",
+               .dai_name = SKL_SSM_CODEC_DAI,
+       },
+       { /* Right */
+               .name = "i2c-INT343B:01",
+               .dai_name = SKL_SSM_CODEC_DAI,
+       },
+};
+
+static int skylake_ssm4567_codec_init(struct snd_soc_pcm_runtime *rtd)
+{
+       int ret;
+
+       /* Slot 1 for left */
+       ret = snd_soc_dai_set_tdm_slot(rtd->codec_dais[0], 0x01, 0x01, 2, 48);
+       if (ret < 0)
+               return ret;
+
+       /* Slot 2 for right */
+       ret = snd_soc_dai_set_tdm_slot(rtd->codec_dais[1], 0x02, 0x02, 2, 48);
+       if (ret < 0)
+               return ret;
+
+       return ret;
+}
+
+static int skylake_nau8825_codec_init(struct snd_soc_pcm_runtime *rtd)
+{
+       int ret;
+       struct snd_soc_codec *codec = rtd->codec;
+
+       /*
+        * 4 buttons here map to the google Reference headset
+        * The use of these buttons can be decided by the user space.
+        */
+       ret = snd_soc_card_jack_new(&skylake_audio_card, "Headset Jack",
+               SND_JACK_HEADSET | SND_JACK_BTN_0 | SND_JACK_BTN_1 |
+               SND_JACK_BTN_2 | SND_JACK_BTN_3, &skylake_headset,
+               NULL, 0);
+       if (ret) {
+               dev_err(rtd->dev, "Headset Jack creation failed %d\n", ret);
+               return ret;
+       }
+
+       nau8825_enable_jack_detect(codec, &skylake_headset);
+
+       snd_soc_dapm_ignore_suspend(&rtd->card->dapm, "SoC DMIC");
+       snd_soc_dapm_ignore_suspend(&rtd->card->dapm, "WoV Sink");
+
+       return ret;
+}
+
+static int skylake_nau8825_fe_init(struct snd_soc_pcm_runtime *rtd)
+{
+       struct snd_soc_dapm_context *dapm;
+       struct snd_soc_component *component = rtd->cpu_dai->component;
+
+       dapm = snd_soc_component_get_dapm(component);
+       snd_soc_dapm_ignore_suspend(dapm, "Reference Capture");
+
+       return 0;
+}
+
+static unsigned int rates[] = {
+       48000,
+};
+
+static struct snd_pcm_hw_constraint_list constraints_rates = {
+       .count = ARRAY_SIZE(rates),
+       .list  = rates,
+       .mask = 0,
+};
+
+static unsigned int channels[] = {
+       2,
+};
+
+static struct snd_pcm_hw_constraint_list constraints_channels = {
+       .count = ARRAY_SIZE(channels),
+       .list = channels,
+       .mask = 0,
+};
+
+static int skl_fe_startup(struct snd_pcm_substream *substream)
+{
+       struct snd_pcm_runtime *runtime = substream->runtime;
+
+       /*
+        * on this platform for PCM device we support,
+        *      48Khz
+        *      stereo
+        *      16 bit audio
+        */
+
+       runtime->hw.channels_max = 2;
+       snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS,
+                                          &constraints_channels);
+
+       runtime->hw.formats = SNDRV_PCM_FMTBIT_S16_LE;
+       snd_pcm_hw_constraint_msbits(runtime, 0, 16, 16);
+
+       snd_pcm_hw_constraint_list(runtime, 0,
+                               SNDRV_PCM_HW_PARAM_RATE, &constraints_rates);
+
+       return 0;
+}
+
+static const struct snd_soc_ops skylake_nau8825_fe_ops = {
+       .startup = skl_fe_startup,
+};
+
+static int skylake_ssp_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);
+       struct snd_mask *fmt = hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT);
+
+       /* The ADSP will covert the FE rate to 48k, stereo */
+       rate->min = rate->max = 48000;
+       channels->min = channels->max = 2;
+
+       /* set SSP0 to 24 bit */
+       snd_mask_none(fmt);
+       snd_mask_set(fmt, SNDRV_PCM_FORMAT_S24_LE);
+       return 0;
+}
+
+static int skylake_dmic_fixup(struct snd_soc_pcm_runtime *rtd,
+                       struct snd_pcm_hw_params *params)
+{
+       struct snd_interval *channels = hw_param_interval(params,
+                                               SNDRV_PCM_HW_PARAM_CHANNELS);
+       if (params_channels(params) == 2)
+               channels->min = channels->max = 2;
+       else
+               channels->min = channels->max = 4;
+
+       return 0;
+}
+
+static int skylake_nau8825_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,
+                       NAU8825_CLK_MCLK, 24000000, SND_SOC_CLOCK_IN);
+
+       if (ret < 0)
+               dev_err(rtd->dev, "snd_soc_dai_set_sysclk err = %d\n", ret);
+
+       return ret;
+}
+
+static struct snd_soc_ops skylake_nau8825_ops = {
+       .hw_params = skylake_nau8825_hw_params,
+};
+
+static unsigned int channels_dmic[] = {
+       2, 4,
+};
+
+static struct snd_pcm_hw_constraint_list constraints_dmic_channels = {
+       .count = ARRAY_SIZE(channels_dmic),
+       .list = channels_dmic,
+       .mask = 0,
+};
+
+static int skylake_dmic_startup(struct snd_pcm_substream *substream)
+{
+       struct snd_pcm_runtime *runtime = substream->runtime;
+
+       runtime->hw.channels_max = 4;
+       snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS,
+                       &constraints_dmic_channels);
+
+       return snd_pcm_hw_constraint_list(substream->runtime, 0,
+                       SNDRV_PCM_HW_PARAM_RATE, &constraints_rates);
+}
+
+static struct snd_soc_ops skylake_dmic_ops = {
+       .startup = skylake_dmic_startup,
+};
+
+static unsigned int rates_16000[] = {
+       16000,
+};
+
+static struct snd_pcm_hw_constraint_list constraints_16000 = {
+       .count = ARRAY_SIZE(rates_16000),
+       .list  = rates_16000,
+};
+
+static int skylake_refcap_startup(struct snd_pcm_substream *substream)
+{
+       return snd_pcm_hw_constraint_list(substream->runtime, 0,
+                       SNDRV_PCM_HW_PARAM_RATE,
+                       &constraints_16000);
+}
+
+static struct snd_soc_ops skylaye_refcap_ops = {
+       .startup = skylake_refcap_startup,
+};
+
+/* skylake digital audio interface glue - connects codec <--> CPU */
+static struct snd_soc_dai_link skylake_dais[] = {
+       /* Front End DAI links */
+       {
+               .name = "Skl Audio Port",
+               .stream_name = "Audio",
+               .cpu_dai_name = "System Pin",
+               .platform_name = "0000:00:1f.3",
+               .dynamic = 1,
+               .codec_name = "snd-soc-dummy",
+               .codec_dai_name = "snd-soc-dummy-dai",
+               .nonatomic = 1,
+               .init = skylake_nau8825_fe_init,
+               .trigger = {
+                       SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST},
+               .dpcm_playback = 1,
+               .ops = &skylake_nau8825_fe_ops,
+       },
+       {
+               .name = "Skl Audio Capture Port",
+               .stream_name = "Audio Record",
+               .cpu_dai_name = "System Pin",
+               .platform_name = "0000:00:1f.3",
+               .dynamic = 1,
+               .codec_name = "snd-soc-dummy",
+               .codec_dai_name = "snd-soc-dummy-dai",
+               .nonatomic = 1,
+               .trigger = {
+                       SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST},
+               .dpcm_capture = 1,
+               .ops = &skylake_nau8825_fe_ops,
+       },
+       {
+               .name = "Skl Audio Reference cap",
+               .stream_name = "Wake on Voice",
+               .cpu_dai_name = "Reference Pin",
+               .codec_name = "snd-soc-dummy",
+               .codec_dai_name = "snd-soc-dummy-dai",
+               .platform_name = "0000:00:1f.3",
+               .init = NULL,
+               .dpcm_capture = 1,
+               .ignore_suspend = 1,
+               .nonatomic = 1,
+               .dynamic = 1,
+               .ops = &skylaye_refcap_ops,
+       },
+       {
+               .name = "Skl Audio DMIC cap",
+               .stream_name = "dmiccap",
+               .cpu_dai_name = "DMIC Pin",
+               .codec_name = "snd-soc-dummy",
+               .codec_dai_name = "snd-soc-dummy-dai",
+               .platform_name = "0000:00:1f.3",
+               .init = NULL,
+               .dpcm_capture = 1,
+               .nonatomic = 1,
+               .dynamic = 1,
+               .ops = &skylake_dmic_ops,
+       },
+       {
+               .name = "Skl HDMI Port",
+               .stream_name = "Hdmi",
+               .cpu_dai_name = "HDMI Pin",
+               .codec_name = "snd-soc-dummy",
+               .codec_dai_name = "snd-soc-dummy-dai",
+               .platform_name = "0000:00:1f.3",
+               .dpcm_playback = 1,
+               .init = NULL,
+               .nonatomic = 1,
+               .dynamic = 1,
+       },
+
+       /* Back End DAI links */
+       {
+               /* SSP0 - Codec */
+               .name = "SSP0-Codec",
+               .be_id = 0,
+               .cpu_dai_name = "SSP0 Pin",
+               .platform_name = "0000:00:1f.3",
+               .no_pcm = 1,
+               .codecs = ssm4567_codec_components,
+               .num_codecs = ARRAY_SIZE(ssm4567_codec_components),
+               .dai_fmt = SND_SOC_DAIFMT_DSP_A |
+                       SND_SOC_DAIFMT_IB_NF |
+                       SND_SOC_DAIFMT_CBS_CFS,
+               .init = skylake_ssm4567_codec_init,
+               .ignore_pmdown_time = 1,
+               .be_hw_params_fixup = skylake_ssp_fixup,
+               .dpcm_playback = 1,
+       },
+       {
+               /* SSP1 - Codec */
+               .name = "SSP1-Codec",
+               .be_id = 0,
+               .cpu_dai_name = "SSP1 Pin",
+               .platform_name = "0000:00:1f.3",
+               .no_pcm = 1,
+               .codec_name = "i2c-10508825:00",
+               .codec_dai_name = SKL_NUVOTON_CODEC_DAI,
+               .init = skylake_nau8825_codec_init,
+               .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
+                       SND_SOC_DAIFMT_CBS_CFS,
+               .ignore_pmdown_time = 1,
+               .be_hw_params_fixup = skylake_ssp_fixup,
+               .ops = &skylake_nau8825_ops,
+               .dpcm_playback = 1,
+               .dpcm_capture = 1,
+       },
+       {
+               .name = "dmic01",
+               .be_id = 1,
+               .cpu_dai_name = "DMIC01 Pin",
+               .codec_name = "dmic-codec",
+               .codec_dai_name = "dmic-hifi",
+               .platform_name = "0000:00:1f.3",
+               .ignore_suspend = 1,
+               .be_hw_params_fixup = skylake_dmic_fixup,
+               .dpcm_capture = 1,
+               .no_pcm = 1,
+       },
+       {
+               .name = "iDisp",
+               .be_id = 3,
+               .cpu_dai_name = "iDisp Pin",
+               .codec_name = "ehdaudio0D2",
+               .codec_dai_name = "intel-hdmi-hifi1",
+               .platform_name = "0000:00:1f.3",
+               .dpcm_playback = 1,
+               .no_pcm = 1,
+       },
+};
+
+/* skylake audio machine driver for SPT + NAU88L25 */
+static struct snd_soc_card skylake_audio_card = {
+       .name = "sklnau8825adi",
+       .owner = THIS_MODULE,
+       .dai_link = skylake_dais,
+       .num_links = ARRAY_SIZE(skylake_dais),
+       .controls = skylake_controls,
+       .num_controls = ARRAY_SIZE(skylake_controls),
+       .dapm_widgets = skylake_widgets,
+       .num_dapm_widgets = ARRAY_SIZE(skylake_widgets),
+       .dapm_routes = skylake_map,
+       .num_dapm_routes = ARRAY_SIZE(skylake_map),
+       .codec_conf = ssm4567_codec_conf,
+       .num_configs = ARRAY_SIZE(ssm4567_codec_conf),
+       .fully_routed = true,
+};
+
+static int skylake_audio_probe(struct platform_device *pdev)
+{
+       skylake_audio_card.dev = &pdev->dev;
+
+       return devm_snd_soc_register_card(&pdev->dev, &skylake_audio_card);
+}
+
+static struct platform_driver skylake_audio = {
+       .probe = skylake_audio_probe,
+       .driver = {
+               .name = "skl_nau88l25_ssm4567_i2s",
+               .pm = &snd_soc_pm_ops,
+       },
+};
+
+module_platform_driver(skylake_audio)
+
+/* Module information */
+MODULE_AUTHOR("Conrad Cooke  <conrad.cooke@intel.com>");
+MODULE_AUTHOR("Harsha Priya <harshapriya.n@intel.com>");
+MODULE_AUTHOR("Naveen M <naveen.m@intel.com>");
+MODULE_AUTHOR("Sathya Prakash M R <sathya.prakash.m.r@intel.com>");
+MODULE_AUTHOR("Yong Zhi <yong.zhi@intel.com>");
+MODULE_DESCRIPTION("Intel Audio Machine driver for SKL with NAU88L25 and SSM4567 in I2S Mode");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:skl_nau88l25_ssm4567_i2s");
index a73a431bd8b7283f6c9c417559bb8adcd0e1ac03..7396ddb427d8f95a3491d144f597fcb9f2e382d3 100644 (file)
@@ -52,6 +52,7 @@ static const struct snd_soc_dapm_widget skylake_widgets[] = {
        SND_SOC_DAPM_MIC("Mic Jack", NULL),
        SND_SOC_DAPM_MIC("DMIC2", NULL),
        SND_SOC_DAPM_MIC("SoC DMIC", NULL),
+       SND_SOC_DAPM_SINK("WoV Sink"),
 };
 
 static const struct snd_soc_dapm_route skylake_rt286_map[] = {
@@ -67,7 +68,9 @@ static const struct snd_soc_dapm_route skylake_rt286_map[] = {
 
        /* digital mics */
        {"DMIC1 Pin", NULL, "DMIC2"},
-       {"DMIC AIF", NULL, "SoC DMIC"},
+       {"DMic", NULL, "SoC DMIC"},
+
+       {"WoV Sink", NULL, "hwd_in sink"},
 
        /* CODEC BE connections */
        { "AIF1 Playback", NULL, "ssp0 Tx"},
@@ -79,13 +82,24 @@ static const struct snd_soc_dapm_route skylake_rt286_map[] = {
        { "ssp0 Rx", NULL, "AIF1 Capture" },
 
        { "dmic01_hifi", NULL, "DMIC01 Rx" },
-       { "DMIC01 Rx", NULL, "Capture" },
+       { "DMIC01 Rx", NULL, "DMIC AIF" },
 
        { "hif1", NULL, "iDisp Tx"},
        { "iDisp Tx", NULL, "iDisp_out"},
 
 };
 
+static int skylake_rt286_fe_init(struct snd_soc_pcm_runtime *rtd)
+{
+       struct snd_soc_dapm_context *dapm;
+       struct snd_soc_component *component = rtd->cpu_dai->component;
+
+       dapm = snd_soc_component_get_dapm(component);
+       snd_soc_dapm_ignore_suspend(dapm, "Reference Capture");
+
+       return 0;
+}
+
 static int skylake_rt286_codec_init(struct snd_soc_pcm_runtime *rtd)
 {
        struct snd_soc_codec *codec = rtd->codec;
@@ -101,9 +115,59 @@ static int skylake_rt286_codec_init(struct snd_soc_pcm_runtime *rtd)
 
        rt286_mic_detect(codec, &skylake_headset);
 
+       snd_soc_dapm_ignore_suspend(&rtd->card->dapm, "SoC DMIC");
+       snd_soc_dapm_ignore_suspend(&rtd->card->dapm, "WoV Sink");
+
        return 0;
 }
 
+static unsigned int rates[] = {
+       48000,
+};
+
+static struct snd_pcm_hw_constraint_list constraints_rates = {
+       .count = ARRAY_SIZE(rates),
+       .list  = rates,
+       .mask = 0,
+};
+
+static unsigned int channels[] = {
+       2,
+};
+
+static struct snd_pcm_hw_constraint_list constraints_channels = {
+       .count = ARRAY_SIZE(channels),
+       .list = channels,
+       .mask = 0,
+};
+
+static int skl_fe_startup(struct snd_pcm_substream *substream)
+{
+       struct snd_pcm_runtime *runtime = substream->runtime;
+
+       /*
+        * on this platform for PCM device we support,
+        *      48Khz
+        *      stereo
+        *      16 bit audio
+        */
+
+       runtime->hw.channels_max = 2;
+       snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS,
+                                          &constraints_channels);
+
+       runtime->hw.formats = SNDRV_PCM_FMTBIT_S16_LE;
+       snd_pcm_hw_constraint_msbits(runtime, 0, 16, 16);
+
+       snd_pcm_hw_constraint_list(runtime, 0,
+                               SNDRV_PCM_HW_PARAM_RATE, &constraints_rates);
+
+       return 0;
+}
+
+static const struct snd_soc_ops skylake_rt286_fe_ops = {
+       .startup = skl_fe_startup,
+};
 
 static int skylake_ssp0_fixup(struct snd_soc_pcm_runtime *rtd,
                        struct snd_pcm_hw_params *params)
@@ -112,12 +176,15 @@ static int skylake_ssp0_fixup(struct snd_soc_pcm_runtime *rtd,
                        SNDRV_PCM_HW_PARAM_RATE);
        struct snd_interval *channels = hw_param_interval(params,
                                                SNDRV_PCM_HW_PARAM_CHANNELS);
+       struct snd_mask *fmt = hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT);
 
        /* The output is 48KHz, stereo, 16bits */
        rate->min = rate->max = 48000;
        channels->min = channels->max = 2;
-       params_set_format(params, SNDRV_PCM_FORMAT_S16_LE);
 
+       /* set SSP0 to 24 bit */
+       snd_mask_none(fmt);
+       snd_mask_set(fmt, SNDRV_PCM_FORMAT_S24_LE);
        return 0;
 }
 
@@ -140,6 +207,42 @@ static struct snd_soc_ops skylake_rt286_ops = {
        .hw_params = skylake_rt286_hw_params,
 };
 
+static int skylake_dmic_fixup(struct snd_soc_pcm_runtime *rtd,
+                               struct snd_pcm_hw_params *params)
+{
+       struct snd_interval *channels = hw_param_interval(params,
+                                               SNDRV_PCM_HW_PARAM_CHANNELS);
+       channels->min = channels->max = 4;
+
+       return 0;
+}
+
+static unsigned int channels_dmic[] = {
+       2, 4,
+};
+
+static struct snd_pcm_hw_constraint_list constraints_dmic_channels = {
+       .count = ARRAY_SIZE(channels_dmic),
+       .list = channels_dmic,
+       .mask = 0,
+};
+
+static int skylake_dmic_startup(struct snd_pcm_substream *substream)
+{
+       struct snd_pcm_runtime *runtime = substream->runtime;
+
+       runtime->hw.channels_max = 4;
+       snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS,
+                                          &constraints_dmic_channels);
+
+       return snd_pcm_hw_constraint_list(substream->runtime, 0,
+                       SNDRV_PCM_HW_PARAM_RATE, &constraints_rates);
+}
+
+static struct snd_soc_ops skylake_dmic_ops = {
+       .startup = skylake_dmic_startup,
+};
+
 /* skylake digital audio interface glue - connects codec <--> CPU */
 static struct snd_soc_dai_link skylake_rt286_dais[] = {
        /* Front End DAI links */
@@ -152,11 +255,13 @@ static struct snd_soc_dai_link skylake_rt286_dais[] = {
                .dynamic = 1,
                .codec_name = "snd-soc-dummy",
                .codec_dai_name = "snd-soc-dummy-dai",
+               .init = skylake_rt286_fe_init,
                .trigger = {
                        SND_SOC_DPCM_TRIGGER_POST,
                        SND_SOC_DPCM_TRIGGER_POST
                },
                .dpcm_playback = 1,
+               .ops = &skylake_rt286_fe_ops,
        },
        {
                .name = "Skl Audio Capture Port",
@@ -172,6 +277,7 @@ static struct snd_soc_dai_link skylake_rt286_dais[] = {
                        SND_SOC_DPCM_TRIGGER_POST
                },
                .dpcm_capture = 1,
+               .ops = &skylake_rt286_fe_ops,
        },
        {
                .name = "Skl Audio Reference cap",
@@ -186,6 +292,19 @@ static struct snd_soc_dai_link skylake_rt286_dais[] = {
                .nonatomic = 1,
                .dynamic = 1,
        },
+       {
+               .name = "Skl Audio DMIC cap",
+               .stream_name = "dmiccap",
+               .cpu_dai_name = "DMIC Pin",
+               .codec_name = "snd-soc-dummy",
+               .codec_dai_name = "snd-soc-dummy-dai",
+               .platform_name = "0000:00:1f.3",
+               .init = NULL,
+               .dpcm_capture = 1,
+               .nonatomic = 1,
+               .dynamic = 1,
+               .ops = &skylake_dmic_ops,
+       },
 
        /* Back End DAI links */
        {
@@ -201,7 +320,6 @@ static struct snd_soc_dai_link skylake_rt286_dais[] = {
                .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 = skylake_ssp0_fixup,
                .ops = &skylake_rt286_ops,
@@ -215,6 +333,7 @@ static struct snd_soc_dai_link skylake_rt286_dais[] = {
                .codec_name = "dmic-codec",
                .codec_dai_name = "dmic-hifi",
                .platform_name = "0000:00:1f.3",
+               .be_hw_params_fixup = skylake_dmic_fixup,
                .ignore_suspend = 1,
                .dpcm_capture = 1,
                .no_pcm = 1,
@@ -247,6 +366,7 @@ static struct platform_driver skylake_audio = {
        .probe = skylake_audio_probe,
        .driver = {
                .name = "skl_alc286s_i2s",
+               .pm = &snd_soc_pm_ops,
        },
 };
 
index d9105584c51f5838a4ebbc360eb35ce91c56b1be..668fdeee195e2f0343047c41b0b5210d5bdc4c07 100644 (file)
@@ -1,11 +1,13 @@
 snd-soc-sst-dsp-objs := sst-dsp.o
-snd-soc-sst-acpi-objs := sst-acpi.o
+ifneq ($(CONFIG_SND_SST_IPC_ACPI),)
+snd-soc-sst-acpi-objs := sst-match-acpi.o
+else
+snd-soc-sst-acpi-objs := sst-acpi.o sst-match-acpi.o
+endif
+
 snd-soc-sst-ipc-objs := sst-ipc.o
 
-ifneq ($(CONFIG_DW_DMAC_CORE),)
-snd-soc-sst-dsp-objs += sst-firmware.o
-endif
+snd-soc-sst-dsp-$(CONFIG_DW_DMAC_CORE) += sst-firmware.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
-
index 67b6d3d52f57f69f4dd6fed65cc8546b694996ee..7a85c576dad33575efed4ca9eabb1ccf64970383 100644 (file)
 #include <linux/platform_device.h>
 
 #include "sst-dsp.h"
+#include "sst-acpi.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;
@@ -88,28 +79,6 @@ static void sst_acpi_fw_cb(const struct firmware *fw, void *context)
        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;
@@ -211,7 +180,7 @@ static int sst_acpi_remove(struct platform_device *pdev)
 }
 
 static struct sst_acpi_mach haswell_machines[] = {
-       { "INT33CA", "haswell-audio", "intel/IntcSST1.bin" },
+       { "INT33CA", "haswell-audio", "intel/IntcSST1.bin", NULL, NULL, NULL },
        {}
 };
 
@@ -229,7 +198,7 @@ static struct sst_acpi_desc sst_acpi_haswell_desc = {
 };
 
 static struct sst_acpi_mach broadwell_machines[] = {
-       { "INT343A", "broadwell-audio", "intel/IntcSST2.bin" },
+       { "INT343A", "broadwell-audio", "intel/IntcSST2.bin", NULL, NULL, NULL },
        {}
 };
 
@@ -247,8 +216,8 @@ static struct sst_acpi_desc sst_acpi_broadwell_desc = {
 };
 
 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" },
+       { "10EC5640", "byt-rt5640", "intel/fw_sst_0f28.bin-48kHz_i2s_master", NULL, NULL, NULL },
+       { "193C9890", "byt-max98090", "intel/fw_sst_0f28.bin-48kHz_i2s_master", NULL, NULL, NULL },
        {}
 };
 
diff --git a/sound/soc/intel/common/sst-acpi.h b/sound/soc/intel/common/sst-acpi.h
new file mode 100644 (file)
index 0000000..3ee3b7a
--- /dev/null
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2013-15, 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>
+
+/* acpi match */
+struct sst_acpi_mach *sst_acpi_find_machine(struct sst_acpi_mach *machines);
+
+/* 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;
+
+       /* board name */
+       const char *board;
+       void (*machine_quirk)(void);
+       void *pdata;
+};
index 2151652d37b72e33c556b11ea46af565747fd965..81aa1ed6420116dce01d6a5f12fbf36fa5bb961b 100644 (file)
@@ -243,7 +243,7 @@ struct sst_mem_block {
        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 */
+       const struct sst_block_ops *ops;/* block operations, if any */
 
        /* block status */
        u32 bytes_used;                 /* bytes in use by modules */
@@ -308,6 +308,8 @@ struct sst_dsp {
 
        /* SKL data */
 
+       const char *fw_name;
+
        /* To allocate CL dma buffers */
        struct skl_dsp_loader_ops dsp_ops;
        struct skl_dsp_fw_ops fw_ops;
@@ -376,8 +378,8 @@ 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);
+       u32 size, enum sst_mem_type type, const struct sst_block_ops *ops,
+       u32 index, void *private);
 void sst_mem_block_unregister_all(struct sst_dsp *dsp);
 
 /* Create/Free DMA resources */
index c9452e02e0dda6735238736a9e8d05267615abb0..b5bbdf4fe93a68443021f4a50ff2fa955ba1a1c5 100644 (file)
@@ -420,7 +420,7 @@ void sst_dsp_inbox_read(struct sst_dsp *sst, void *message, size_t bytes)
 }
 EXPORT_SYMBOL_GPL(sst_dsp_inbox_read);
 
-#if IS_ENABLED(CONFIG_DW_DMAC_CORE)
+#ifdef CONFIG_DW_DMAC_CORE
 struct sst_dsp *sst_dsp_new(struct device *dev,
        struct sst_dsp_device *sst_dev, struct sst_pdata *pdata)
 {
index 859f0de003391489b2da65c0195f62caa2e0b9ef..0b84c719ec4885b5ccb453f773190c800fdbe391 100644 (file)
@@ -216,7 +216,7 @@ struct sst_pdata {
        void *dsp;
 };
 
-#if IS_ENABLED(CONFIG_DW_DMAC_CORE)
+#ifdef CONFIG_DW_DMAC_CORE
 /* Initialization */
 struct sst_dsp *sst_dsp_new(struct device *dev,
        struct sst_dsp_device *sst_dev, struct sst_pdata *pdata);
index 1636a1eeb0021efa076674e3375db682c1cbb45b..ef4881e7753ab2a369874d75c3bb63824b078ef7 100644 (file)
@@ -51,8 +51,22 @@ struct sst_dma {
 
 static inline void sst_memcpy32(volatile void __iomem *dest, void *src, u32 bytes)
 {
+       u32 tmp = 0;
+       int i, m, n;
+       const u8 *src_byte = src;
+
+       m = bytes / 4;
+       n = bytes % 4;
+
        /* __iowrite32_copy use 32bit size values so divide by 4 */
-       __iowrite32_copy((void *)dest, src, bytes/4);
+       __iowrite32_copy((void *)dest, src, m);
+
+       if (n) {
+               for (i = 0; i < n; i++)
+                       tmp |= (u32)*(src_byte + m * 4 + i) << (i * 8);
+               __iowrite32_copy((void *)(dest + m * 4), &tmp, 1);
+       }
+
 }
 
 static void sst_dma_transfer_complete(void *arg)
@@ -1014,8 +1028,8 @@ 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)
+       u32 size, enum sst_mem_type type, const struct sst_block_ops *ops,
+       u32 index, void *private)
 {
        struct sst_mem_block *block;
 
diff --git a/sound/soc/intel/common/sst-match-acpi.c b/sound/soc/intel/common/sst-match-acpi.c
new file mode 100644 (file)
index 0000000..dd077e1
--- /dev/null
@@ -0,0 +1,43 @@
+/*
+ * sst_match_apci.c - SST (LPE) match for ACPI enumeration.
+ *
+ * Copyright (c) 2013-15, 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/acpi.h>
+#include <linux/device.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+
+#include "sst-acpi.h"
+
+static acpi_status sst_acpi_mach_match(acpi_handle handle, u32 level,
+                                      void *context, void **ret)
+{
+       *(bool *)context = true;
+       return AE_OK;
+}
+
+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;
+}
+EXPORT_SYMBOL_GPL(sst_acpi_find_machine);
index 7f94920c8a4d85c33734f71a0980c85614a5d5c2..b2bec36d074cf12b91039e189b775e0311c900ae 100644 (file)
@@ -607,7 +607,7 @@ static int hsw_block_disable(struct sst_mem_block *block)
        return 0;
 }
 
-static struct sst_block_ops sst_hsw_ops = {
+static const struct sst_block_ops sst_hsw_ops = {
        .enable = hsw_block_enable,
        .disable = hsw_block_disable,
 };
index b27f25f70730b32717b00105b8a1f090c51ba048..ac60f1301e2102543a24b09319dd8b3233702743 100644 (file)
@@ -778,7 +778,6 @@ static irqreturn_t hsw_irq_thread(int irq, void *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);
@@ -790,34 +789,30 @@ static irqreturn_t hsw_irq_thread(int irq, void *context)
        if (ipcx & SST_IPCX_DONE) {
 
                /* Handle Immediate reply from DSP Core */
-               handled = hsw_process_reply(hsw, ipcx);
+               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);
+               /* 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);
-               }
+               /* 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);
+               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);
+               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);
-               }
+               /* unmask busy interrupt */
+               sst_dsp_shim_update_bits_unlocked(sst, SST_IMRX,
+                       SST_IMRX_BUSY, 0);
        }
 
        spin_unlock_irqrestore(&sst->spinlock, flags);
index 50a109503a3fefbe41b1c153b8c96f975a4a6d1f..de6dac496a0d8b611d4662864597e58ee20330f3 100644 (file)
@@ -96,7 +96,7 @@ int skl_init_dsp(struct skl *skl)
        }
 
        ret = skl_sst_dsp_init(bus->dev, mmio_base, irq,
-                       loader_ops, &skl->skl_sst);
+                       skl->fw_name, loader_ops, &skl->skl_sst);
        if (ret < 0)
                return ret;
 
@@ -182,94 +182,6 @@ enum skl_bitdepth skl_get_bit_depth(int params)
        }
 }
 
-static u32 skl_create_channel_map(enum skl_ch_cfg ch_cfg)
-{
-       u32 config;
-
-       switch (ch_cfg) {
-       case SKL_CH_CFG_MONO:
-               config =  (0xFFFFFFF0 | SKL_CHANNEL_LEFT);
-               break;
-
-       case SKL_CH_CFG_STEREO:
-               config = (0xFFFFFF00 | SKL_CHANNEL_LEFT
-                       | (SKL_CHANNEL_RIGHT << 4));
-               break;
-
-       case SKL_CH_CFG_2_1:
-               config = (0xFFFFF000 | SKL_CHANNEL_LEFT
-                       | (SKL_CHANNEL_RIGHT << 4)
-                       | (SKL_CHANNEL_LFE << 8));
-               break;
-
-       case SKL_CH_CFG_3_0:
-               config =  (0xFFFFF000 | SKL_CHANNEL_LEFT
-                       | (SKL_CHANNEL_CENTER << 4)
-                       | (SKL_CHANNEL_RIGHT << 8));
-               break;
-
-       case SKL_CH_CFG_3_1:
-               config = (0xFFFF0000 | SKL_CHANNEL_LEFT
-                       | (SKL_CHANNEL_CENTER << 4)
-                       | (SKL_CHANNEL_RIGHT << 8)
-                       | (SKL_CHANNEL_LFE << 12));
-               break;
-
-       case SKL_CH_CFG_QUATRO:
-               config = (0xFFFF0000 | SKL_CHANNEL_LEFT
-                       | (SKL_CHANNEL_RIGHT << 4)
-                       | (SKL_CHANNEL_LEFT_SURROUND << 8)
-                       | (SKL_CHANNEL_RIGHT_SURROUND << 12));
-               break;
-
-       case SKL_CH_CFG_4_0:
-               config = (0xFFFF0000 | SKL_CHANNEL_LEFT
-                       | (SKL_CHANNEL_CENTER << 4)
-                       | (SKL_CHANNEL_RIGHT << 8)
-                       | (SKL_CHANNEL_CENTER_SURROUND << 12));
-               break;
-
-       case SKL_CH_CFG_5_0:
-               config = (0xFFF00000 | SKL_CHANNEL_LEFT
-                       | (SKL_CHANNEL_CENTER << 4)
-                       | (SKL_CHANNEL_RIGHT << 8)
-                       | (SKL_CHANNEL_LEFT_SURROUND << 12)
-                       | (SKL_CHANNEL_RIGHT_SURROUND << 16));
-               break;
-
-       case SKL_CH_CFG_5_1:
-               config = (0xFF000000 | SKL_CHANNEL_CENTER
-                       | (SKL_CHANNEL_LEFT << 4)
-                       | (SKL_CHANNEL_RIGHT << 8)
-                       | (SKL_CHANNEL_LEFT_SURROUND << 12)
-                       | (SKL_CHANNEL_RIGHT_SURROUND << 16)
-                       | (SKL_CHANNEL_LFE << 20));
-               break;
-
-       case SKL_CH_CFG_DUAL_MONO:
-               config = (0xFFFFFF00 | SKL_CHANNEL_LEFT
-                       | (SKL_CHANNEL_LEFT << 4));
-               break;
-
-       case SKL_CH_CFG_I2S_DUAL_STEREO_0:
-               config = (0xFFFFFF00 | SKL_CHANNEL_LEFT
-                       | (SKL_CHANNEL_RIGHT << 4));
-               break;
-
-       case SKL_CH_CFG_I2S_DUAL_STEREO_1:
-               config = (0xFFFF00FF | (SKL_CHANNEL_LEFT << 8)
-                       | (SKL_CHANNEL_RIGHT << 12));
-               break;
-
-       default:
-               config =  0xFFFFFFFF;
-               break;
-
-       }
-
-       return config;
-}
-
 /*
  * Each module in DSP expects a base module configuration, which consists of
  * PCM format information, which we calculate in driver and resource values
@@ -280,7 +192,7 @@ static void skl_set_base_module_format(struct skl_sst *ctx,
                        struct skl_module_cfg *mconfig,
                        struct skl_base_cfg *base_cfg)
 {
-       struct skl_module_fmt *format = &mconfig->in_fmt;
+       struct skl_module_fmt *format = &mconfig->in_fmt[0];
 
        base_cfg->audio_fmt.number_of_channels = (u8)format->channels;
 
@@ -293,14 +205,14 @@ static void skl_set_base_module_format(struct skl_sst *ctx,
                        format->bit_depth, format->valid_bit_depth,
                        format->ch_cfg);
 
-       base_cfg->audio_fmt.channel_map = skl_create_channel_map(
-                                       base_cfg->audio_fmt.ch_cfg);
+       base_cfg->audio_fmt.channel_map = format->ch_map;
 
-       base_cfg->audio_fmt.interleaving = SKL_INTERLEAVING_PER_CHANNEL;
+       base_cfg->audio_fmt.interleaving = format->interleaving_style;
 
        base_cfg->cps = mconfig->mcps;
        base_cfg->ibs = mconfig->ibs;
        base_cfg->obs = mconfig->obs;
+       base_cfg->is_pages = mconfig->mem_pages;
 }
 
 /*
@@ -399,7 +311,7 @@ static void skl_setup_out_format(struct skl_sst *ctx,
                        struct skl_module_cfg *mconfig,
                        struct skl_audio_data_format *out_fmt)
 {
-       struct skl_module_fmt *format = &mconfig->out_fmt;
+       struct skl_module_fmt *format = &mconfig->out_fmt[0];
 
        out_fmt->number_of_channels = (u8)format->channels;
        out_fmt->s_freq = format->s_freq;
@@ -407,8 +319,9 @@ static void skl_setup_out_format(struct skl_sst *ctx,
        out_fmt->valid_bit_depth = format->valid_bit_depth;
        out_fmt->ch_cfg = format->ch_cfg;
 
-       out_fmt->channel_map = skl_create_channel_map(out_fmt->ch_cfg);
-       out_fmt->interleaving = SKL_INTERLEAVING_PER_CHANNEL;
+       out_fmt->channel_map = format->ch_map;
+       out_fmt->interleaving = format->interleaving_style;
+       out_fmt->sample_type = format->sample_type;
 
        dev_dbg(ctx->dev, "copier out format chan=%d fre=%d bitdepth=%d\n",
                out_fmt->number_of_channels, format->s_freq, format->bit_depth);
@@ -423,7 +336,7 @@ static void skl_set_src_format(struct skl_sst *ctx,
                        struct skl_module_cfg *mconfig,
                        struct skl_src_module_cfg *src_mconfig)
 {
-       struct skl_module_fmt *fmt = &mconfig->out_fmt;
+       struct skl_module_fmt *fmt = &mconfig->out_fmt[0];
 
        skl_set_base_module_format(ctx, mconfig,
                (struct skl_base_cfg *)src_mconfig);
@@ -440,7 +353,7 @@ static void skl_set_updown_mixer_format(struct skl_sst *ctx,
                        struct skl_module_cfg *mconfig,
                        struct skl_up_down_mixer_cfg *mixer_mconfig)
 {
-       struct skl_module_fmt *fmt = &mconfig->out_fmt;
+       struct skl_module_fmt *fmt = &mconfig->out_fmt[0];
        int i = 0;
 
        skl_set_base_module_format(ctx, mconfig,
@@ -475,6 +388,47 @@ static void skl_set_copier_format(struct skl_sst *ctx,
        skl_setup_cpr_gateway_cfg(ctx, mconfig, cpr_mconfig);
 }
 
+/*
+ * Algo module are DSP pre processing modules. Algo module take base module
+ * configuration and params
+ */
+
+static void skl_set_algo_format(struct skl_sst *ctx,
+                       struct skl_module_cfg *mconfig,
+                       struct skl_algo_cfg *algo_mcfg)
+{
+       struct skl_base_cfg *base_cfg = (struct skl_base_cfg *)algo_mcfg;
+
+       skl_set_base_module_format(ctx, mconfig, base_cfg);
+
+       if (mconfig->formats_config.caps_size == 0)
+               return;
+
+       memcpy(algo_mcfg->params,
+                       mconfig->formats_config.caps,
+                       mconfig->formats_config.caps_size);
+
+}
+
+/*
+ * Mic select module allows selecting one or many input channels, thus
+ * acting as a demux.
+ *
+ * Mic select module take base module configuration and out-format
+ * configuration
+ */
+static void skl_set_base_outfmt_format(struct skl_sst *ctx,
+                       struct skl_module_cfg *mconfig,
+                       struct skl_base_outfmt_cfg *base_outfmt_mcfg)
+{
+       struct skl_audio_data_format *out_fmt = &base_outfmt_mcfg->out_fmt;
+       struct skl_base_cfg *base_cfg =
+                               (struct skl_base_cfg *)base_outfmt_mcfg;
+
+       skl_set_base_module_format(ctx, mconfig, base_cfg);
+       skl_setup_out_format(ctx, mconfig, out_fmt);
+}
+
 static u16 skl_get_module_param_size(struct skl_sst *ctx,
                        struct skl_module_cfg *mconfig)
 {
@@ -492,6 +446,14 @@ static u16 skl_get_module_param_size(struct skl_sst *ctx,
        case SKL_MODULE_TYPE_UPDWMIX:
                return sizeof(struct skl_up_down_mixer_cfg);
 
+       case SKL_MODULE_TYPE_ALGO:
+               param_size = sizeof(struct skl_base_cfg);
+               param_size += mconfig->formats_config.caps_size;
+               return param_size;
+
+       case SKL_MODULE_TYPE_BASE_OUTFMT:
+               return sizeof(struct skl_base_outfmt_cfg);
+
        default:
                /*
                 * return only base cfg when no specific module type is
@@ -538,6 +500,14 @@ static int skl_set_module_format(struct skl_sst *ctx,
                skl_set_updown_mixer_format(ctx, module_config, *param_data);
                break;
 
+       case SKL_MODULE_TYPE_ALGO:
+               skl_set_algo_format(ctx, module_config, *param_data);
+               break;
+
+       case SKL_MODULE_TYPE_BASE_OUTFMT:
+               skl_set_base_outfmt_format(ctx, module_config, *param_data);
+               break;
+
        default:
                skl_set_base_module_format(ctx, module_config, *param_data);
                break;
@@ -571,10 +541,10 @@ static int skl_get_queue_index(struct skl_module_pin *mpin,
  * In static, the pin_index is fixed based on module_id and instance id
  */
 static int skl_alloc_queue(struct skl_module_pin *mpin,
-                       struct skl_module_inst_id id, int max)
+                       struct skl_module_cfg *tgt_cfg, int max)
 {
        int i;
-
+       struct skl_module_inst_id id = tgt_cfg->id;
        /*
         * if pin in dynamic, find first free pin
         * otherwise find match module and instance id pin as topology will
@@ -583,16 +553,23 @@ static int skl_alloc_queue(struct skl_module_pin *mpin,
         */
        for (i = 0; i < max; i++)  {
                if (mpin[i].is_dynamic) {
-                       if (!mpin[i].in_use) {
+                       if (!mpin[i].in_use &&
+                               mpin[i].pin_state == SKL_PIN_UNBIND) {
+
                                mpin[i].in_use = true;
                                mpin[i].id.module_id = id.module_id;
                                mpin[i].id.instance_id = id.instance_id;
+                               mpin[i].tgt_mcfg = tgt_cfg;
                                return i;
                        }
                } else {
                        if (mpin[i].id.module_id == id.module_id &&
-                               mpin[i].id.instance_id == id.instance_id)
+                               mpin[i].id.instance_id == id.instance_id &&
+                               mpin[i].pin_state == SKL_PIN_UNBIND) {
+
+                               mpin[i].tgt_mcfg = tgt_cfg;
                                return i;
+                       }
                }
        }
 
@@ -606,6 +583,28 @@ static void skl_free_queue(struct skl_module_pin *mpin, int q_index)
                mpin[q_index].id.module_id = 0;
                mpin[q_index].id.instance_id = 0;
        }
+       mpin[q_index].pin_state = SKL_PIN_UNBIND;
+       mpin[q_index].tgt_mcfg = NULL;
+}
+
+/* Module state will be set to unint, if all the out pin state is UNBIND */
+
+static void skl_clear_module_state(struct skl_module_pin *mpin, int max,
+                                               struct skl_module_cfg *mcfg)
+{
+       int i;
+       bool found = false;
+
+       for (i = 0; i < max; i++)  {
+               if (mpin[i].pin_state == SKL_PIN_UNBIND)
+                       continue;
+               found = true;
+               break;
+       }
+
+       if (!found)
+               mcfg->m_state = SKL_MODULE_UNINIT;
+       return;
 }
 
 /*
@@ -615,7 +614,7 @@ static void skl_free_queue(struct skl_module_pin *mpin, int q_index)
  * invoke the DSP by sending IPC INIT_INSTANCE using ipc helper
  */
 int skl_init_module(struct skl_sst *ctx,
-                       struct skl_module_cfg *mconfig, char *param)
+                       struct skl_module_cfg *mconfig)
 {
        u16 module_config_size = 0;
        void *param_data = NULL;
@@ -682,37 +681,30 @@ int skl_unbind_modules(struct skl_sst *ctx,
        struct skl_module_inst_id dst_id = dst_mcfg->id;
        int in_max = dst_mcfg->max_in_queue;
        int out_max = src_mcfg->max_out_queue;
-       int src_index, dst_index;
+       int src_index, dst_index, src_pin_state, dst_pin_state;
 
        skl_dump_bind_info(ctx, src_mcfg, dst_mcfg);
 
-       if (src_mcfg->m_state != SKL_MODULE_BIND_DONE)
-               return 0;
-
-       /*
-        * if intra module unbind, check if both modules are BIND,
-        * then send unbind
-        */
-       if ((src_mcfg->pipe->ppl_id != dst_mcfg->pipe->ppl_id) &&
-                               dst_mcfg->m_state != SKL_MODULE_BIND_DONE)
-               return 0;
-       else if (src_mcfg->m_state < SKL_MODULE_INIT_DONE &&
-                                dst_mcfg->m_state < SKL_MODULE_INIT_DONE)
-               return 0;
-
        /* get src queue index */
        src_index = skl_get_queue_index(src_mcfg->m_out_pin, dst_id, out_max);
        if (src_index < 0)
                return -EINVAL;
 
-       msg.src_queue = src_mcfg->m_out_pin[src_index].pin_index;
+       msg.src_queue = src_index;
 
        /* get dst queue index */
        dst_index  = skl_get_queue_index(dst_mcfg->m_in_pin, src_id, in_max);
        if (dst_index < 0)
                return -EINVAL;
 
-       msg.dst_queue = dst_mcfg->m_in_pin[dst_index].pin_index;
+       msg.dst_queue = dst_index;
+
+       src_pin_state = src_mcfg->m_out_pin[src_index].pin_state;
+       dst_pin_state = dst_mcfg->m_in_pin[dst_index].pin_state;
+
+       if (src_pin_state != SKL_PIN_BIND_DONE ||
+               dst_pin_state != SKL_PIN_BIND_DONE)
+               return 0;
 
        msg.module_id = src_mcfg->id.module_id;
        msg.instance_id = src_mcfg->id.instance_id;
@@ -722,10 +714,15 @@ int skl_unbind_modules(struct skl_sst *ctx,
 
        ret = skl_ipc_bind_unbind(&ctx->ipc, &msg);
        if (!ret) {
-               src_mcfg->m_state = SKL_MODULE_UNINIT;
                /* free queue only if unbind is success */
                skl_free_queue(src_mcfg->m_out_pin, src_index);
                skl_free_queue(dst_mcfg->m_in_pin, dst_index);
+
+               /*
+                * check only if src module bind state, bind is
+                * always from src -> sink
+                */
+               skl_clear_module_state(src_mcfg->m_out_pin, out_max, src_mcfg);
        }
 
        return ret;
@@ -744,8 +741,6 @@ int skl_bind_modules(struct skl_sst *ctx,
 {
        int ret;
        struct skl_ipc_bind_unbind_msg msg;
-       struct skl_module_inst_id src_id = src_mcfg->id;
-       struct skl_module_inst_id dst_id = dst_mcfg->id;
        int in_max = dst_mcfg->max_in_queue;
        int out_max = src_mcfg->max_out_queue;
        int src_index, dst_index;
@@ -756,18 +751,18 @@ int skl_bind_modules(struct skl_sst *ctx,
                dst_mcfg->m_state < SKL_MODULE_INIT_DONE)
                return 0;
 
-       src_index = skl_alloc_queue(src_mcfg->m_out_pin, dst_id, out_max);
+       src_index = skl_alloc_queue(src_mcfg->m_out_pin, dst_mcfg, out_max);
        if (src_index < 0)
                return -EINVAL;
 
-       msg.src_queue = src_mcfg->m_out_pin[src_index].pin_index;
-       dst_index = skl_alloc_queue(dst_mcfg->m_in_pin, src_id, in_max);
+       msg.src_queue = src_index;
+       dst_index = skl_alloc_queue(dst_mcfg->m_in_pin, src_mcfg, in_max);
        if (dst_index < 0) {
                skl_free_queue(src_mcfg->m_out_pin, src_index);
                return -EINVAL;
        }
 
-       msg.dst_queue = dst_mcfg->m_in_pin[dst_index].pin_index;
+       msg.dst_queue = dst_index;
 
        dev_dbg(ctx->dev, "src queue = %d dst queue =%d\n",
                         msg.src_queue, msg.dst_queue);
@@ -782,6 +777,8 @@ int skl_bind_modules(struct skl_sst *ctx,
 
        if (!ret) {
                src_mcfg->m_state = SKL_MODULE_BIND_DONE;
+               src_mcfg->m_out_pin[src_index].pin_state = SKL_PIN_BIND_DONE;
+               dst_mcfg->m_in_pin[dst_index].pin_state = SKL_PIN_BIND_DONE;
        } else {
                /* error case , if IPC fails, clear the queue index */
                skl_free_queue(src_mcfg->m_out_pin, src_index);
@@ -852,6 +849,8 @@ int skl_delete_pipe(struct skl_sst *ctx, struct skl_pipe *pipe)
                ret = skl_ipc_delete_pipeline(&ctx->ipc, pipe->ppl_id);
                if (ret < 0)
                        dev_err(ctx->dev, "Failed to delete pipeline\n");
+
+               pipe->state = SKL_PIPE_INVALID;
        }
 
        return ret;
@@ -916,3 +915,30 @@ int skl_stop_pipe(struct skl_sst *ctx, struct skl_pipe *pipe)
 
        return 0;
 }
+
+/* Algo parameter set helper function */
+int skl_set_module_params(struct skl_sst *ctx, u32 *params, int size,
+                               u32 param_id, struct skl_module_cfg *mcfg)
+{
+       struct skl_ipc_large_config_msg msg;
+
+       msg.module_id = mcfg->id.module_id;
+       msg.instance_id = mcfg->id.instance_id;
+       msg.param_data_size = size;
+       msg.large_param_id = param_id;
+
+       return skl_ipc_set_large_config(&ctx->ipc, &msg, params);
+}
+
+int skl_get_module_params(struct skl_sst *ctx, u32 *params, int size,
+                         u32 param_id, struct skl_module_cfg *mcfg)
+{
+       struct skl_ipc_large_config_msg msg;
+
+       msg.module_id = mcfg->id.module_id;
+       msg.instance_id = mcfg->id.instance_id;
+       msg.param_data_size = size;
+       msg.large_param_id = param_id;
+
+       return skl_ipc_get_large_config(&ctx->ipc, &msg, params);
+}
index b0c7bd113aacfd59db229320f5227985010bb8f4..6e4b21cdb1bd9bff4b6606103bd41629c0ab2b7f 100644 (file)
@@ -55,7 +55,7 @@ void skl_nhlt_free(void *addr)
 
 static struct nhlt_specific_cfg *skl_get_specific_cfg(
                struct device *dev, struct nhlt_fmt *fmt,
-               u8 no_ch, u32 rate, u16 bps)
+               u8 no_ch, u32 rate, u16 bps, u8 linktype)
 {
        struct nhlt_specific_cfg *sp_config;
        struct wav_fmt *wfmt;
@@ -68,11 +68,17 @@ static struct nhlt_specific_cfg *skl_get_specific_cfg(
                wfmt = &fmt_config->fmt_ext.fmt;
                dev_dbg(dev, "ch=%d fmt=%d s_rate=%d\n", wfmt->channels,
                         wfmt->bits_per_sample, wfmt->samples_per_sec);
-               if (wfmt->channels == no_ch && wfmt->samples_per_sec == rate &&
-                                       wfmt->bits_per_sample == bps) {
+               if (wfmt->channels == no_ch && wfmt->bits_per_sample == bps) {
+                       /*
+                        * if link type is dmic ignore rate check as the blob is
+                        * generic for all rates
+                        */
                        sp_config = &fmt_config->config;
+                       if (linktype == NHLT_LINK_DMIC)
+                               return sp_config;
 
-                       return sp_config;
+                       if (wfmt->samples_per_sec == rate)
+                               return sp_config;
                }
 
                fmt_config = (struct nhlt_fmt_cfg *)(fmt_config->config.caps +
@@ -115,7 +121,7 @@ struct nhlt_specific_cfg
        struct device *dev = bus->dev;
        struct nhlt_specific_cfg *sp_config;
        struct nhlt_acpi_table *nhlt = (struct nhlt_acpi_table *)skl->nhlt;
-       u16 bps = num_ch * s_fmt;
+       u16 bps = (s_fmt == 16) ? 16 : 32;
        u8 j;
 
        dump_config(dev, instance, link_type, s_fmt, num_ch, s_rate, dirn, bps);
@@ -128,7 +134,8 @@ struct nhlt_specific_cfg
                if (skl_check_ep_match(dev, epnt, instance, link_type, dirn)) {
                        fmt = (struct nhlt_fmt *)(epnt->config.caps +
                                                 epnt->config.size);
-                       sp_config = skl_get_specific_cfg(dev, fmt, num_ch, s_rate, bps);
+                       sp_config = skl_get_specific_cfg(dev, fmt, num_ch,
+                                                       s_rate, bps, link_type);
                        if (sp_config)
                                return sp_config;
                }
index a2f94ce1679d0db2c23b3ccb0d0339afb46473cf..f3553258091a2bd7a78f2485aaee7c46fc667758 100644 (file)
 #include <sound/soc.h>
 #include "skl.h"
 #include "skl-topology.h"
+#include "skl-sst-dsp.h"
+#include "skl-sst-ipc.h"
 
 #define HDA_MONO 1
 #define HDA_STEREO 2
+#define HDA_QUAD 4
 
 static struct snd_pcm_hardware azx_pcm_hw = {
        .info =                 (SNDRV_PCM_INFO_MMAP |
@@ -35,16 +38,20 @@ static struct snd_pcm_hardware azx_pcm_hw = {
                                 SNDRV_PCM_INFO_BLOCK_TRANSFER |
                                 SNDRV_PCM_INFO_MMAP_VALID |
                                 SNDRV_PCM_INFO_PAUSE |
+                                SNDRV_PCM_INFO_RESUME |
                                 SNDRV_PCM_INFO_SYNC_START |
                                 SNDRV_PCM_INFO_HAS_WALL_CLOCK | /* legacy */
                                 SNDRV_PCM_INFO_HAS_LINK_ATIME |
                                 SNDRV_PCM_INFO_NO_PERIOD_WAKEUP),
-       .formats =              SNDRV_PCM_FMTBIT_S16_LE,
-       .rates =                SNDRV_PCM_RATE_48000,
-       .rate_min =             48000,
+       .formats =              SNDRV_PCM_FMTBIT_S16_LE |
+                               SNDRV_PCM_FMTBIT_S32_LE |
+                               SNDRV_PCM_FMTBIT_S24_LE,
+       .rates =                SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_16000 |
+                               SNDRV_PCM_RATE_8000,
+       .rate_min =             8000,
        .rate_max =             48000,
-       .channels_min =         2,
-       .channels_max =         2,
+       .channels_min =         1,
+       .channels_max =         HDA_QUAD,
        .buffer_bytes_max =     AZX_MAX_BUF_SIZE,
        .period_bytes_min =     128,
        .period_bytes_max =     AZX_MAX_BUF_SIZE / 2,
@@ -105,6 +112,31 @@ static enum hdac_ext_stream_type skl_get_host_stream_type(struct hdac_ext_bus *e
                return HDAC_EXT_STREAM_TYPE_COUPLED;
 }
 
+/*
+ * check if the stream opened is marked as ignore_suspend by machine, if so
+ * then enable suspend_active refcount
+ *
+ * The count supend_active does not need lock as it is used in open/close
+ * and suspend context
+ */
+static void skl_set_suspend_active(struct snd_pcm_substream *substream,
+                                        struct snd_soc_dai *dai, bool enable)
+{
+       struct hdac_ext_bus *ebus = dev_get_drvdata(dai->dev);
+       struct snd_soc_dapm_widget *w;
+       struct skl *skl = ebus_to_skl(ebus);
+
+       if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+               w = dai->playback_widget;
+       else
+               w = dai->capture_widget;
+
+       if (w->ignore_suspend && enable)
+               skl->supend_active++;
+       else if (w->ignore_suspend && !enable)
+               skl->supend_active--;
+}
+
 static int skl_pcm_open(struct snd_pcm_substream *substream,
                struct snd_soc_dai *dai)
 {
@@ -112,12 +144,8 @@ static int skl_pcm_open(struct snd_pcm_substream *substream,
        struct hdac_ext_stream *stream;
        struct snd_pcm_runtime *runtime = substream->runtime;
        struct skl_dma_params *dma_params;
-       int ret;
 
        dev_dbg(dai->dev, "%s: %s\n", __func__, dai->name);
-       ret = pm_runtime_get_sync(dai->dev);
-       if (ret < 0)
-               return ret;
 
        stream = snd_hdac_ext_stream_assign(ebus, substream,
                                        skl_get_host_stream_type(ebus));
@@ -146,6 +174,7 @@ static int skl_pcm_open(struct snd_pcm_substream *substream,
 
        dev_dbg(dai->dev, "stream tag set in dma params=%d\n",
                                 dma_params->stream_tag);
+       skl_set_suspend_active(substream, dai, true);
        snd_pcm_set_sync(substream);
 
        return 0;
@@ -185,10 +214,6 @@ static int skl_pcm_prepare(struct snd_pcm_substream *substream,
        int err;
 
        dev_dbg(dai->dev, "%s: %s\n", __func__, dai->name);
-       if (hdac_stream(stream)->prepared) {
-               dev_dbg(dai->dev, "already stream is prepared - returning\n");
-               return 0;
-       }
 
        format_val = skl_get_format(substream, dai);
        dev_dbg(dai->dev, "stream_tag=%d formatvalue=%d\n",
@@ -250,6 +275,7 @@ static void skl_pcm_close(struct snd_pcm_substream *substream,
        struct hdac_ext_stream *stream = get_hdac_ext_stream(substream);
        struct hdac_ext_bus *ebus = dev_get_drvdata(dai->dev);
        struct skl_dma_params *dma_params = NULL;
+       struct skl *skl = ebus_to_skl(ebus);
 
        dev_dbg(dai->dev, "%s: %s\n", __func__, dai->name);
 
@@ -261,9 +287,18 @@ static void skl_pcm_close(struct snd_pcm_substream *substream,
         * dma_params
         */
        snd_soc_dai_set_dma_data(dai, substream, NULL);
+       skl_set_suspend_active(substream, dai, false);
+
+       /*
+        * check if close is for "Reference Pin" and set back the
+        * CGCTL.MISCBDCGE if disabled by driver
+        */
+       if (!strncmp(dai->name, "Reference Pin", 13) &&
+                       skl->skl_sst->miscbdcg_disabled) {
+               skl->skl_sst->enable_miscbdcge(dai->dev, true);
+               skl->skl_sst->miscbdcg_disabled = false;
+       }
 
-       pm_runtime_mark_last_busy(dai->dev);
-       pm_runtime_put_autosuspend(dai->dev);
        kfree(dma_params);
 }
 
@@ -291,7 +326,53 @@ static int skl_be_hw_params(struct snd_pcm_substream *substream,
        p_params.ch = params_channels(params);
        p_params.s_freq = params_rate(params);
        p_params.stream = substream->stream;
-       skl_tplg_be_update_params(dai, &p_params);
+
+       return skl_tplg_be_update_params(dai, &p_params);
+}
+
+static int skl_decoupled_trigger(struct snd_pcm_substream *substream,
+               int cmd)
+{
+       struct hdac_ext_bus *ebus = get_bus_ctx(substream);
+       struct hdac_bus *bus = ebus_to_hbus(ebus);
+       struct hdac_ext_stream *stream;
+       int start;
+       unsigned long cookie;
+       struct hdac_stream *hstr;
+
+       stream = get_hdac_ext_stream(substream);
+       hstr = hdac_stream(stream);
+
+       if (!hstr->prepared)
+               return -EPIPE;
+
+       switch (cmd) {
+       case SNDRV_PCM_TRIGGER_START:
+       case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+       case SNDRV_PCM_TRIGGER_RESUME:
+               start = 1;
+               break;
+
+       case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+       case SNDRV_PCM_TRIGGER_SUSPEND:
+       case SNDRV_PCM_TRIGGER_STOP:
+               start = 0;
+               break;
+
+       default:
+               return -EINVAL;
+       }
+
+       spin_lock_irqsave(&bus->reg_lock, cookie);
+
+       if (start) {
+               snd_hdac_stream_start(hdac_stream(stream), true);
+               snd_hdac_stream_timecounter_init(hstr, 0);
+       } else {
+               snd_hdac_stream_stop(hdac_stream(stream));
+       }
+
+       spin_unlock_irqrestore(&bus->reg_lock, cookie);
 
        return 0;
 }
@@ -302,23 +383,72 @@ static int skl_pcm_trigger(struct snd_pcm_substream *substream, int cmd,
        struct skl *skl = get_skl_ctx(dai->dev);
        struct skl_sst *ctx = skl->skl_sst;
        struct skl_module_cfg *mconfig;
+       struct hdac_ext_bus *ebus = get_bus_ctx(substream);
+       struct hdac_ext_stream *stream = get_hdac_ext_stream(substream);
+       int ret;
 
        mconfig = skl_tplg_fe_get_cpr_module(dai, substream->stream);
        if (!mconfig)
                return -EIO;
 
        switch (cmd) {
-       case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
        case SNDRV_PCM_TRIGGER_RESUME:
+               skl_pcm_prepare(substream, dai);
+               /*
+                * enable DMA Resume enable bit for the stream, set the dpib
+                * & lpib position to resune before starting the DMA
+                */
+               snd_hdac_ext_stream_drsm_enable(ebus, true,
+                                       hdac_stream(stream)->index);
+               snd_hdac_ext_stream_set_dpibr(ebus, stream, stream->dpib);
+               snd_hdac_ext_stream_set_lpib(stream, stream->lpib);
+
+       case SNDRV_PCM_TRIGGER_START:
+       case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+               /*
+                * Start HOST DMA and Start FE Pipe.This is to make sure that
+                * there are no underrun/overrun in the case when the FE
+                * pipeline is started but there is a delay in starting the
+                * DMA channel on the host.
+                */
+               snd_hdac_ext_stream_decouple(ebus, stream, true);
+               ret = skl_decoupled_trigger(substream, cmd);
+               if (ret < 0)
+                       return ret;
                return skl_run_pipe(ctx, mconfig->pipe);
+               break;
 
        case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
        case SNDRV_PCM_TRIGGER_SUSPEND:
-               return skl_stop_pipe(ctx, mconfig->pipe);
+       case SNDRV_PCM_TRIGGER_STOP:
+               /*
+                * Stop FE Pipe first and stop DMA. This is to make sure that
+                * there are no underrun/overrun in the case if there is a delay
+                * between the two operations.
+                */
+               ret = skl_stop_pipe(ctx, mconfig->pipe);
+               if (ret < 0)
+                       return ret;
+
+               ret = skl_decoupled_trigger(substream, cmd);
+               if (cmd == SNDRV_PCM_TRIGGER_SUSPEND) {
+                       /* save the dpib and lpib positions */
+                       stream->dpib = readl(ebus->bus.remap_addr +
+                                       AZX_REG_VS_SDXDPIB_XBASE +
+                                       (AZX_REG_VS_SDXDPIB_XINTERVAL *
+                                       hdac_stream(stream)->index));
+
+                       stream->lpib = snd_hdac_stream_get_pos_lpib(
+                                                       hdac_stream(stream));
+                       snd_hdac_ext_stream_decouple(ebus, stream, false);
+               }
+               break;
 
        default:
-               return 0;
+               return -EINVAL;
        }
+
+       return 0;
 }
 
 static int skl_link_hw_params(struct snd_pcm_substream *substream,
@@ -352,9 +482,7 @@ static int skl_link_hw_params(struct snd_pcm_substream *substream,
        p_params.stream = substream->stream;
        p_params.link_dma_id = hdac_stream(link_dev)->stream_tag - 1;
 
-       skl_tplg_be_update_params(dai, &p_params);
-
-       return 0;
+       return skl_tplg_be_update_params(dai, &p_params);
 }
 
 static int skl_link_pcm_prepare(struct snd_pcm_substream *substream,
@@ -369,11 +497,6 @@ static int skl_link_pcm_prepare(struct snd_pcm_substream *substream,
        struct snd_soc_dai *codec_dai = rtd->codec_dai;
        struct hdac_ext_link *link;
 
-       if (link_dev->link_prepared) {
-               dev_dbg(dai->dev, "already stream is prepared - returning\n");
-               return 0;
-       }
-
        dma_params  = (struct skl_dma_params *)
                        snd_soc_dai_get_dma_data(codec_dai, substream);
        if (dma_params)
@@ -381,14 +504,15 @@ static int skl_link_pcm_prepare(struct snd_pcm_substream *substream,
        dev_dbg(dai->dev, "stream_tag=%d formatvalue=%d codec_dai_name=%s\n",
                        hdac_stream(link_dev)->stream_tag, format_val, codec_dai->name);
 
-       snd_hdac_ext_link_stream_reset(link_dev);
-
-       snd_hdac_ext_link_stream_setup(link_dev, format_val);
-
        link = snd_hdac_ext_bus_get_link(ebus, rtd->codec->component.name);
        if (!link)
                return -EINVAL;
 
+       snd_hdac_ext_bus_link_power_up(link);
+       snd_hdac_ext_link_stream_reset(link_dev);
+
+       snd_hdac_ext_link_stream_setup(link_dev, format_val);
+
        snd_hdac_ext_link_set_stream_id(link, hdac_stream(link_dev)->stream_tag);
        link_dev->link_prepared = 1;
 
@@ -400,12 +524,16 @@ static int skl_link_pcm_trigger(struct snd_pcm_substream *substream,
 {
        struct hdac_ext_stream *link_dev =
                                snd_soc_dai_get_dma_data(dai, substream);
+       struct hdac_ext_bus *ebus = get_bus_ctx(substream);
+       struct hdac_ext_stream *stream = get_hdac_ext_stream(substream);
 
        dev_dbg(dai->dev, "In %s cmd=%d\n", __func__, cmd);
        switch (cmd) {
+       case SNDRV_PCM_TRIGGER_RESUME:
+               skl_link_pcm_prepare(substream, dai);
        case SNDRV_PCM_TRIGGER_START:
        case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
-       case SNDRV_PCM_TRIGGER_RESUME:
+               snd_hdac_ext_stream_decouple(ebus, stream, true);
                snd_hdac_ext_link_stream_start(link_dev);
                break;
 
@@ -413,6 +541,8 @@ static int skl_link_pcm_trigger(struct snd_pcm_substream *substream,
        case SNDRV_PCM_TRIGGER_SUSPEND:
        case SNDRV_PCM_TRIGGER_STOP:
                snd_hdac_ext_link_stream_clear(link_dev);
+               if (cmd == SNDRV_PCM_TRIGGER_SUSPEND)
+                       snd_hdac_ext_stream_decouple(ebus, stream, false);
                break;
 
        default:
@@ -443,19 +573,6 @@ static int skl_link_hw_free(struct snd_pcm_substream *substream,
        return 0;
 }
 
-static int skl_be_startup(struct snd_pcm_substream *substream,
-               struct snd_soc_dai *dai)
-{
-       return pm_runtime_get_sync(dai->dev);
-}
-
-static void skl_be_shutdown(struct snd_pcm_substream *substream,
-               struct snd_soc_dai *dai)
-{
-       pm_runtime_mark_last_busy(dai->dev);
-       pm_runtime_put_autosuspend(dai->dev);
-}
-
 static struct snd_soc_dai_ops skl_pcm_dai_ops = {
        .startup = skl_pcm_open,
        .shutdown = skl_pcm_close,
@@ -466,24 +583,18 @@ static struct snd_soc_dai_ops skl_pcm_dai_ops = {
 };
 
 static struct snd_soc_dai_ops skl_dmic_dai_ops = {
-       .startup = skl_be_startup,
        .hw_params = skl_be_hw_params,
-       .shutdown = skl_be_shutdown,
 };
 
 static struct snd_soc_dai_ops skl_be_ssp_dai_ops = {
-       .startup = skl_be_startup,
        .hw_params = skl_be_hw_params,
-       .shutdown = skl_be_shutdown,
 };
 
 static struct snd_soc_dai_ops skl_link_dai_ops = {
-       .startup = skl_be_startup,
        .prepare = skl_link_pcm_prepare,
        .hw_params = skl_link_hw_params,
        .hw_free = skl_link_hw_free,
        .trigger = skl_link_pcm_trigger,
-       .shutdown = skl_be_shutdown,
 };
 
 static struct snd_soc_dai_driver skl_platform_dai[] = {
@@ -511,7 +622,7 @@ static struct snd_soc_dai_driver skl_platform_dai[] = {
        .capture = {
                .stream_name = "Reference Capture",
                .channels_min = HDA_MONO,
-               .channels_max = HDA_STEREO,
+               .channels_max = HDA_QUAD,
                .rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_16000,
                .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE,
        },
@@ -538,6 +649,18 @@ static struct snd_soc_dai_driver skl_platform_dai[] = {
                .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE,
        },
 },
+{
+       .name = "DMIC Pin",
+       .ops = &skl_pcm_dai_ops,
+       .capture = {
+               .stream_name = "DMIC Capture",
+               .channels_min = HDA_MONO,
+               .channels_max = HDA_QUAD,
+               .rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_16000,
+               .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE,
+       },
+},
+
 /* BE CPU  Dais */
 {
        .name = "SSP0 Pin",
@@ -557,6 +680,24 @@ static struct snd_soc_dai_driver skl_platform_dai[] = {
                .formats = SNDRV_PCM_FMTBIT_S16_LE,
        },
 },
+{
+       .name = "SSP1 Pin",
+       .ops = &skl_be_ssp_dai_ops,
+       .playback = {
+               .stream_name = "ssp1 Tx",
+               .channels_min = HDA_STEREO,
+               .channels_max = HDA_STEREO,
+               .rates = SNDRV_PCM_RATE_48000,
+               .formats = SNDRV_PCM_FMTBIT_S16_LE,
+       },
+       .capture = {
+               .stream_name = "ssp1 Rx",
+               .channels_min = HDA_STEREO,
+               .channels_max = HDA_STEREO,
+               .rates = SNDRV_PCM_RATE_48000,
+               .formats = SNDRV_PCM_FMTBIT_S16_LE,
+       },
+},
 {
        .name = "iDisp Pin",
        .ops = &skl_link_dai_ops,
@@ -573,8 +714,8 @@ static struct snd_soc_dai_driver skl_platform_dai[] = {
        .ops = &skl_dmic_dai_ops,
        .capture = {
                .stream_name = "DMIC01 Rx",
-               .channels_min = HDA_STEREO,
-               .channels_max = HDA_STEREO,
+               .channels_min = HDA_MONO,
+               .channels_max = HDA_QUAD,
                .rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_16000,
                .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE,
        },
@@ -688,66 +829,15 @@ static int skl_coupled_trigger(struct snd_pcm_substream *substream,
        return 0;
 }
 
-static int skl_decoupled_trigger(struct snd_pcm_substream *substream,
-               int cmd)
-{
-       struct hdac_ext_bus *ebus = get_bus_ctx(substream);
-       struct hdac_bus *bus = ebus_to_hbus(ebus);
-       struct snd_soc_pcm_runtime *rtd = snd_pcm_substream_chip(substream);
-       struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
-       struct hdac_ext_stream *stream;
-       int start;
-       unsigned long cookie;
-       struct hdac_stream *hstr;
-
-       dev_dbg(bus->dev, "In %s cmd=%d streamname=%s\n", __func__, cmd, cpu_dai->name);
-
-       stream = get_hdac_ext_stream(substream);
-       hstr = hdac_stream(stream);
-
-       if (!hstr->prepared)
-               return -EPIPE;
-
-       switch (cmd) {
-       case SNDRV_PCM_TRIGGER_START:
-       case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
-       case SNDRV_PCM_TRIGGER_RESUME:
-               start = 1;
-               break;
-
-       case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
-       case SNDRV_PCM_TRIGGER_SUSPEND:
-       case SNDRV_PCM_TRIGGER_STOP:
-               start = 0;
-               break;
-
-       default:
-               return -EINVAL;
-       }
-
-       spin_lock_irqsave(&bus->reg_lock, cookie);
-
-       if (start)
-               snd_hdac_stream_start(hdac_stream(stream), true);
-       else
-               snd_hdac_stream_stop(hdac_stream(stream));
-
-       if (start)
-               snd_hdac_stream_timecounter_init(hstr, 0);
-
-       spin_unlock_irqrestore(&bus->reg_lock, cookie);
-
-       return 0;
-}
 static int skl_platform_pcm_trigger(struct snd_pcm_substream *substream,
                                        int cmd)
 {
        struct hdac_ext_bus *ebus = get_bus_ctx(substream);
 
-       if (ebus->ppcap)
-               return skl_decoupled_trigger(substream, cmd);
-       else
+       if (!ebus->ppcap)
                return skl_coupled_trigger(substream, cmd);
+
+       return 0;
 }
 
 /* calculate runtime delay from LPIB */
@@ -789,7 +879,7 @@ static unsigned int skl_get_position(struct hdac_ext_stream *hstream,
 {
        struct hdac_stream *hstr = hdac_stream(hstream);
        struct snd_pcm_substream *substream = hstr->substream;
-       struct hdac_ext_bus *ebus = get_bus_ctx(substream);
+       struct hdac_ext_bus *ebus;
        unsigned int pos;
        int delay;
 
@@ -800,6 +890,7 @@ static unsigned int skl_get_position(struct hdac_ext_stream *hstream,
                pos = 0;
 
        if (substream->runtime) {
+               ebus = get_bus_ctx(substream);
                delay = skl_get_delay_from_lpib(ebus, hstream, pos)
                                                 + codec_delay;
                substream->runtime->delay += delay;
@@ -941,7 +1032,6 @@ int skl_platform_register(struct device *dev)
        struct skl *skl = ebus_to_skl(ebus);
 
        INIT_LIST_HEAD(&skl->ppl_list);
-       INIT_LIST_HEAD(&skl->dapm_path_list);
 
        ret = snd_soc_register_platform(dev, &skl_platform_drv);
        if (ret) {
index 44748ba98da29fcc1c8018181982a20d7e782ec7..da2329d17f4dfd3884cc524388aa1caaf2a42f45 100644 (file)
@@ -18,6 +18,7 @@
 #include <linux/device.h>
 #include <linux/mm.h>
 #include <linux/kthread.h>
+#include <linux/delay.h>
 #include "../common/sst-dsp.h"
 #include "../common/sst-dsp-priv.h"
 
@@ -33,6 +34,53 @@ void skl_cldma_int_disable(struct sst_dsp *ctx)
                        SKL_ADSP_REG_ADSPIC, SKL_ADSPIC_CL_DMA, 0);
 }
 
+static void skl_cldma_stream_run(struct sst_dsp  *ctx, bool enable)
+{
+       unsigned char val;
+       int timeout;
+
+       sst_dsp_shim_update_bits_unlocked(ctx,
+                       SKL_ADSP_REG_CL_SD_CTL,
+                       CL_SD_CTL_RUN_MASK, CL_SD_CTL_RUN(enable));
+
+       udelay(3);
+       timeout = 300;
+       do {
+               /* waiting for hardware to report that the stream Run bit set */
+               val = sst_dsp_shim_read(ctx, SKL_ADSP_REG_CL_SD_CTL) &
+                       CL_SD_CTL_RUN_MASK;
+               if (enable && val)
+                       break;
+               else if (!enable && !val)
+                       break;
+               udelay(3);
+       } while (--timeout);
+
+       if (timeout == 0)
+               dev_err(ctx->dev, "Failed to set Run bit=%d enable=%d\n", val, enable);
+}
+
+static void skl_cldma_stream_clear(struct sst_dsp  *ctx)
+{
+       /* make sure Run bit is cleared before setting stream register */
+       skl_cldma_stream_run(ctx, 0);
+
+       sst_dsp_shim_update_bits(ctx, SKL_ADSP_REG_CL_SD_CTL,
+                               CL_SD_CTL_IOCE_MASK, CL_SD_CTL_IOCE(0));
+       sst_dsp_shim_update_bits(ctx, SKL_ADSP_REG_CL_SD_CTL,
+                               CL_SD_CTL_FEIE_MASK, CL_SD_CTL_FEIE(0));
+       sst_dsp_shim_update_bits(ctx, SKL_ADSP_REG_CL_SD_CTL,
+                               CL_SD_CTL_DEIE_MASK, CL_SD_CTL_DEIE(0));
+       sst_dsp_shim_update_bits(ctx, SKL_ADSP_REG_CL_SD_CTL,
+                               CL_SD_CTL_STRM_MASK, CL_SD_CTL_STRM(0));
+
+       sst_dsp_shim_write(ctx, SKL_ADSP_REG_CL_SD_BDLPL, CL_SD_BDLPLBA(0));
+       sst_dsp_shim_write(ctx, SKL_ADSP_REG_CL_SD_BDLPU, 0);
+
+       sst_dsp_shim_write(ctx, SKL_ADSP_REG_CL_SD_CBL, 0);
+       sst_dsp_shim_write(ctx, SKL_ADSP_REG_CL_SD_LVI, 0);
+}
+
 /* Code loader helper APIs */
 static void skl_cldma_setup_bdle(struct sst_dsp *ctx,
                struct snd_dma_buffer *dmab_data,
@@ -68,6 +116,7 @@ static void skl_cldma_setup_controller(struct sst_dsp  *ctx,
                struct snd_dma_buffer *dmab_bdl, unsigned int max_size,
                u32 count)
 {
+       skl_cldma_stream_clear(ctx);
        sst_dsp_shim_write(ctx, SKL_ADSP_REG_CL_SD_BDLPL,
                        CL_SD_BDLPLBA(dmab_bdl->addr));
        sst_dsp_shim_write(ctx, SKL_ADSP_REG_CL_SD_BDLPU,
@@ -107,36 +156,13 @@ static void skl_cldma_cleanup_spb(struct sst_dsp  *ctx)
        sst_dsp_shim_write_unlocked(ctx, SKL_ADSP_REG_CL_SPBFIFO_SPIB, 0);
 }
 
-static void skl_cldma_trigger(struct sst_dsp  *ctx, bool enable)
-{
-       if (enable)
-               sst_dsp_shim_update_bits_unlocked(ctx,
-                       SKL_ADSP_REG_CL_SD_CTL,
-                       CL_SD_CTL_RUN_MASK, CL_SD_CTL_RUN(1));
-       else
-               sst_dsp_shim_update_bits_unlocked(ctx,
-                       SKL_ADSP_REG_CL_SD_CTL,
-                       CL_SD_CTL_RUN_MASK, CL_SD_CTL_RUN(0));
-}
-
 static void skl_cldma_cleanup(struct sst_dsp  *ctx)
 {
        skl_cldma_cleanup_spb(ctx);
+       skl_cldma_stream_clear(ctx);
 
-       sst_dsp_shim_update_bits(ctx, SKL_ADSP_REG_CL_SD_CTL,
-                               CL_SD_CTL_IOCE_MASK, CL_SD_CTL_IOCE(0));
-       sst_dsp_shim_update_bits(ctx, SKL_ADSP_REG_CL_SD_CTL,
-                               CL_SD_CTL_FEIE_MASK, CL_SD_CTL_FEIE(0));
-       sst_dsp_shim_update_bits(ctx, SKL_ADSP_REG_CL_SD_CTL,
-                               CL_SD_CTL_DEIE_MASK, CL_SD_CTL_DEIE(0));
-       sst_dsp_shim_update_bits(ctx, SKL_ADSP_REG_CL_SD_CTL,
-                               CL_SD_CTL_STRM_MASK, CL_SD_CTL_STRM(0));
-
-       sst_dsp_shim_write(ctx, SKL_ADSP_REG_CL_SD_BDLPL, CL_SD_BDLPLBA(0));
-       sst_dsp_shim_write(ctx, SKL_ADSP_REG_CL_SD_BDLPU, 0);
-
-       sst_dsp_shim_write(ctx, SKL_ADSP_REG_CL_SD_CBL, 0);
-       sst_dsp_shim_write(ctx, SKL_ADSP_REG_CL_SD_LVI, 0);
+       ctx->dsp_ops.free_dma_buf(ctx->dev, &ctx->cl_dev.dmab_data);
+       ctx->dsp_ops.free_dma_buf(ctx->dev, &ctx->cl_dev.dmab_bdl);
 }
 
 static int skl_cldma_wait_interruptible(struct sst_dsp *ctx)
@@ -164,7 +190,7 @@ cleanup:
 
 static void skl_cldma_stop(struct sst_dsp *ctx)
 {
-       ctx->cl_dev.ops.cl_trigger(ctx, false);
+       skl_cldma_stream_run(ctx, false);
 }
 
 static void skl_cldma_fill_buffer(struct sst_dsp *ctx, unsigned int size,
@@ -175,6 +201,21 @@ static void skl_cldma_fill_buffer(struct sst_dsp *ctx, unsigned int size,
                        ctx->cl_dev.dma_buffer_offset, trigger);
        dev_dbg(ctx->dev, "spib position: %d\n", ctx->cl_dev.curr_spib_pos);
 
+       /*
+        * Check if the size exceeds buffer boundary. If it exceeds
+        * max_buffer size, then copy till buffer size and then copy
+        * remaining buffer from the start of ring buffer.
+        */
+       if (ctx->cl_dev.dma_buffer_offset + size > ctx->cl_dev.bufsize) {
+               unsigned int size_b = ctx->cl_dev.bufsize -
+                                       ctx->cl_dev.dma_buffer_offset;
+               memcpy(ctx->cl_dev.dmab_data.area + ctx->cl_dev.dma_buffer_offset,
+                       curr_pos, size_b);
+               size -= size_b;
+               curr_pos += size_b;
+               ctx->cl_dev.dma_buffer_offset = 0;
+       }
+
        memcpy(ctx->cl_dev.dmab_data.area + ctx->cl_dev.dma_buffer_offset,
                        curr_pos, size);
 
@@ -291,7 +332,7 @@ int skl_cldma_prepare(struct sst_dsp *ctx)
        ctx->cl_dev.ops.cl_setup_controller = skl_cldma_setup_controller;
        ctx->cl_dev.ops.cl_setup_spb = skl_cldma_setup_spb;
        ctx->cl_dev.ops.cl_cleanup_spb = skl_cldma_cleanup_spb;
-       ctx->cl_dev.ops.cl_trigger = skl_cldma_trigger;
+       ctx->cl_dev.ops.cl_trigger = skl_cldma_stream_run;
        ctx->cl_dev.ops.cl_cleanup_controller = skl_cldma_cleanup;
        ctx->cl_dev.ops.cl_copy_to_dmabuf = skl_cldma_copy_to_buf;
        ctx->cl_dev.ops.cl_stop_dma = skl_cldma_stop;
index 6bfcef449bdc59a2b9c933642113aaedc642da40..cbb40751c37e297227edff2a9f411df2ec998c53 100644 (file)
@@ -58,9 +58,9 @@ struct sst_dsp_device;
 
 #define SKL_ADSP_MMIO_LEN              0x10000
 
-#define SKL_ADSP_W0_STAT_SZ            0x800
+#define SKL_ADSP_W0_STAT_SZ            0x1000
 
-#define SKL_ADSP_W0_UP_SZ              0x800
+#define SKL_ADSP_W0_UP_SZ              0x1000
 
 #define SKL_ADSP_W1_SZ                 0x1000
 
@@ -114,6 +114,9 @@ struct skl_dsp_fw_ops {
        int (*set_state_D0)(struct sst_dsp *ctx);
        int (*set_state_D3)(struct sst_dsp *ctx);
        unsigned int (*get_fw_errcode)(struct sst_dsp *ctx);
+       int (*load_mod)(struct sst_dsp *ctx, u16 mod_id, char *mod_name);
+       int (*unload_mod)(struct sst_dsp *ctx, u16 mod_id);
+
 };
 
 struct skl_dsp_loader_ops {
@@ -123,6 +126,17 @@ struct skl_dsp_loader_ops {
                struct snd_dma_buffer *dmab);
 };
 
+struct skl_load_module_info {
+       u16 mod_id;
+       const struct firmware *fw;
+};
+
+struct skl_module_table {
+       struct skl_load_module_info *mod_info;
+       unsigned int usage_cnt;
+       struct list_head list;
+};
+
 void skl_cldma_process_intr(struct sst_dsp *ctx);
 void skl_cldma_int_disable(struct sst_dsp *ctx);
 int skl_cldma_prepare(struct sst_dsp *ctx);
@@ -139,7 +153,8 @@ void skl_dsp_free(struct sst_dsp *dsp);
 
 int skl_dsp_boot(struct sst_dsp *ctx);
 int skl_sst_dsp_init(struct device *dev, void __iomem *mmio_base, int irq,
-               struct skl_dsp_loader_ops dsp_ops, struct skl_sst **dsp);
+               const char *fw_name, struct skl_dsp_loader_ops dsp_ops,
+               struct skl_sst **dsp);
 void skl_sst_dsp_cleanup(struct device *dev, struct skl_sst *ctx);
 
 #endif /*__SKL_SST_DSP_H__*/
index 3345ea0d44147e9fdb62275f73d1d0d6d64e0c5f..543460293b0046fd2dd132feefe03a83ca39f93c 100644 (file)
 
 #include "../common/sst-dsp.h"
 #include "../common/sst-dsp-priv.h"
+#include "skl.h"
 #include "skl-sst-dsp.h"
 #include "skl-sst-ipc.h"
+#include "sound/hdaudio_ext.h"
 
 
 #define IPC_IXC_STATUS_BITS            24
 #define IPC_SRC_QUEUE_MASK             0x7
 #define IPC_SRC_QUEUE(x)               (((x) & IPC_SRC_QUEUE_MASK) \
                                        << IPC_SRC_QUEUE_SHIFT)
+/* Load Module count */
+#define IPC_LOAD_MODULE_SHIFT          0
+#define IPC_LOAD_MODULE_MASK           0xFF
+#define IPC_LOAD_MODULE_CNT(x)         (((x) & IPC_LOAD_MODULE_MASK) \
+                                       << IPC_LOAD_MODULE_SHIFT)
 
 /* Save pipeline messgae extension register */
 #define IPC_DMA_ID_SHIFT               0
@@ -317,6 +324,19 @@ static int skl_ipc_process_notification(struct sst_generic_ipc *ipc,
                        wake_up(&skl->boot_wait);
                        break;
 
+               case IPC_GLB_NOTIFY_PHRASE_DETECTED:
+                       dev_dbg(ipc->dev, "***** Phrase Detected **********\n");
+
+                       /*
+                        * Per HW recomendation, After phrase detection,
+                        * clear the CGCTL.MISCBDCGE.
+                        *
+                        * This will be set back on stream closure
+                        */
+                       skl->enable_miscbdcge(ipc->dev, false);
+                       skl->miscbdcg_disabled = true;
+                       break;
+
                default:
                        dev_err(ipc->dev, "ipc: Unhandled error msg=%x",
                                                header.primary);
@@ -344,6 +364,8 @@ static void skl_ipc_process_reply(struct sst_generic_ipc *ipc,
        switch (reply) {
        case IPC_GLB_REPLY_SUCCESS:
                dev_info(ipc->dev, "ipc FW reply %x: success\n", header.primary);
+               /* copy the rx data from the mailbox */
+               sst_dsp_inbox_read(ipc->dsp, msg->rx_data, msg->rx_size);
                break;
 
        case IPC_GLB_REPLY_OUT_OF_MEMORY:
@@ -650,7 +672,7 @@ int skl_ipc_set_dx(struct sst_generic_ipc *ipc, u8 instance_id,
        dev_dbg(ipc->dev, "In %s primary =%x ext=%x\n", __func__,
                         header.primary, header.extension);
        ret = sst_ipc_tx_message_wait(ipc, *ipc_header,
-                               dx, sizeof(dx), NULL, 0);
+                               dx, sizeof(*dx), NULL, 0);
        if (ret < 0) {
                dev_err(ipc->dev, "ipc: set dx failed, err %d\n", ret);
                return ret;
@@ -728,6 +750,54 @@ int skl_ipc_bind_unbind(struct sst_generic_ipc *ipc,
 }
 EXPORT_SYMBOL_GPL(skl_ipc_bind_unbind);
 
+/*
+ * In order to load a module we need to send IPC to initiate that. DMA will
+ * performed to load the module memory. The FW supports multiple module load
+ * at single shot, so we can send IPC with N modules represented by
+ * module_cnt
+ */
+int skl_ipc_load_modules(struct sst_generic_ipc *ipc,
+                               u8 module_cnt, void *data)
+{
+       struct skl_ipc_header header = {0};
+       u64 *ipc_header = (u64 *)(&header);
+       int ret;
+
+       header.primary = IPC_MSG_TARGET(IPC_FW_GEN_MSG);
+       header.primary |= IPC_MSG_DIR(IPC_MSG_REQUEST);
+       header.primary |= IPC_GLB_TYPE(IPC_GLB_LOAD_MULTIPLE_MODS);
+       header.primary |= IPC_LOAD_MODULE_CNT(module_cnt);
+
+       ret = sst_ipc_tx_message_wait(ipc, *ipc_header, data,
+                               (sizeof(u16) * module_cnt), NULL, 0);
+       if (ret < 0)
+               dev_err(ipc->dev, "ipc: load modules failed :%d\n", ret);
+
+       return ret;
+}
+EXPORT_SYMBOL_GPL(skl_ipc_load_modules);
+
+int skl_ipc_unload_modules(struct sst_generic_ipc *ipc, u8 module_cnt,
+                                                       void *data)
+{
+       struct skl_ipc_header header = {0};
+       u64 *ipc_header = (u64 *)(&header);
+       int ret;
+
+       header.primary = IPC_MSG_TARGET(IPC_FW_GEN_MSG);
+       header.primary |= IPC_MSG_DIR(IPC_MSG_REQUEST);
+       header.primary |= IPC_GLB_TYPE(IPC_GLB_UNLOAD_MULTIPLE_MODS);
+       header.primary |= IPC_LOAD_MODULE_CNT(module_cnt);
+
+       ret = sst_ipc_tx_message_wait(ipc, *ipc_header, data,
+                               (sizeof(u16) * module_cnt), NULL, 0);
+       if (ret < 0)
+               dev_err(ipc->dev, "ipc: unload modules failed :%d\n", ret);
+
+       return ret;
+}
+EXPORT_SYMBOL_GPL(skl_ipc_unload_modules);
+
 int skl_ipc_set_large_config(struct sst_generic_ipc *ipc,
                struct skl_ipc_large_config_msg *msg, u32 *param)
 {
@@ -781,3 +851,54 @@ int skl_ipc_set_large_config(struct sst_generic_ipc *ipc,
        return ret;
 }
 EXPORT_SYMBOL_GPL(skl_ipc_set_large_config);
+
+int skl_ipc_get_large_config(struct sst_generic_ipc *ipc,
+               struct skl_ipc_large_config_msg *msg, u32 *param)
+{
+       struct skl_ipc_header header = {0};
+       u64 *ipc_header = (u64 *)(&header);
+       int ret = 0;
+       size_t sz_remaining, rx_size, data_offset;
+
+       header.primary = IPC_MSG_TARGET(IPC_MOD_MSG);
+       header.primary |= IPC_MSG_DIR(IPC_MSG_REQUEST);
+       header.primary |= IPC_GLB_TYPE(IPC_MOD_LARGE_CONFIG_GET);
+       header.primary |= IPC_MOD_INSTANCE_ID(msg->instance_id);
+       header.primary |= IPC_MOD_ID(msg->module_id);
+
+       header.extension = IPC_DATA_OFFSET_SZ(msg->param_data_size);
+       header.extension |= IPC_LARGE_PARAM_ID(msg->large_param_id);
+       header.extension |= IPC_FINAL_BLOCK(1);
+       header.extension |= IPC_INITIAL_BLOCK(1);
+
+       sz_remaining = msg->param_data_size;
+       data_offset = 0;
+
+       while (sz_remaining != 0) {
+               rx_size = sz_remaining > SKL_ADSP_W1_SZ
+                               ? SKL_ADSP_W1_SZ : sz_remaining;
+               if (rx_size == sz_remaining)
+                       header.extension |= IPC_FINAL_BLOCK(1);
+
+               ret = sst_ipc_tx_message_wait(ipc, *ipc_header, NULL, 0,
+                                             ((char *)param) + data_offset,
+                                             msg->param_data_size);
+               if (ret < 0) {
+                       dev_err(ipc->dev,
+                               "ipc: get large config fail, err: %d\n", ret);
+                       return ret;
+               }
+               sz_remaining -= rx_size;
+               data_offset = msg->param_data_size - sz_remaining;
+
+               /* clear the fields */
+               header.extension &= IPC_INITIAL_BLOCK_CLEAR;
+               header.extension &= IPC_DATA_OFFSET_SZ_CLEAR;
+               /* fill the fields */
+               header.extension |= IPC_INITIAL_BLOCK(1);
+               header.extension |= IPC_DATA_OFFSET_SZ(data_offset);
+       }
+
+       return ret;
+}
+EXPORT_SYMBOL_GPL(skl_ipc_get_large_config);
index f1a154e45dc343209b7a1adb8010f62313785bf8..d59d1ba62a430db7b7a2f3e44fc30ff7f8f85594 100644 (file)
@@ -55,6 +55,11 @@ struct skl_sst {
 
        /* IPC messaging */
        struct sst_generic_ipc ipc;
+
+       /* callback for miscbdge */
+       void (*enable_miscbdcge)(struct device *dev, bool enable);
+       /*Is CGCTL.MISCBDCGE disabled*/
+       bool miscbdcg_disabled;
 };
 
 struct skl_ipc_init_instance_msg {
@@ -108,12 +113,21 @@ int skl_ipc_init_instance(struct sst_generic_ipc *sst_ipc,
 int skl_ipc_bind_unbind(struct sst_generic_ipc *sst_ipc,
                struct skl_ipc_bind_unbind_msg *msg);
 
+int skl_ipc_load_modules(struct sst_generic_ipc *ipc,
+                               u8 module_cnt, void *data);
+
+int skl_ipc_unload_modules(struct sst_generic_ipc *ipc,
+                               u8 module_cnt, void *data);
+
 int skl_ipc_set_dx(struct sst_generic_ipc *ipc,
                u8 instance_id, u16 module_id, struct skl_ipc_dxstate_info *dx);
 
 int skl_ipc_set_large_config(struct sst_generic_ipc *ipc,
                struct skl_ipc_large_config_msg *msg, u32 *param);
 
+int skl_ipc_get_large_config(struct sst_generic_ipc *ipc,
+               struct skl_ipc_large_config_msg *msg, u32 *param);
+
 void skl_ipc_int_enable(struct sst_dsp *dsp);
 void skl_ipc_op_int_enable(struct sst_dsp *ctx);
 void skl_ipc_op_int_disable(struct sst_dsp *ctx);
index 3b83dc99f1d405ffd5ea65e1376cae6920a99e63..e26f4746afb7e58a306ea453da996c77571a5431 100644 (file)
@@ -19,6 +19,7 @@
 #include <linux/module.h>
 #include <linux/delay.h>
 #include <linux/device.h>
+#include <linux/err.h>
 #include "../common/sst-dsp.h"
 #include "../common/sst-dsp-priv.h"
 #include "../common/sst-ipc.h"
@@ -37,6 +38,8 @@
 #define SKL_INSTANCE_ID                0
 #define SKL_BASE_FW_MODULE_ID  0
 
+#define SKL_NUM_MODULES                1
+
 static bool skl_check_fw_status(struct sst_dsp *ctx, u32 status)
 {
        u32 cur_sts;
@@ -77,7 +80,7 @@ static int skl_load_base_firmware(struct sst_dsp *ctx)
        init_waitqueue_head(&skl->boot_wait);
 
        if (ctx->fw == NULL) {
-               ret = request_firmware(&ctx->fw, "dsp_fw_release.bin", ctx->dev);
+               ret = request_firmware(&ctx->fw, ctx->fw_name, ctx->dev);
                if (ret < 0) {
                        dev_err(ctx->dev, "Request firmware failed %d\n", ret);
                        skl_dsp_disable_core(ctx);
@@ -115,27 +118,28 @@ static int skl_load_base_firmware(struct sst_dsp *ctx)
                dev_err(ctx->dev,
                        "Timeout waiting for ROM init done, reg:0x%x\n", reg);
                ret = -EIO;
-               goto skl_load_base_firmware_failed;
+               goto transfer_firmware_failed;
        }
 
        ret = skl_transfer_firmware(ctx, ctx->fw->data, ctx->fw->size);
        if (ret < 0) {
                dev_err(ctx->dev, "Transfer firmware failed%d\n", ret);
-               goto skl_load_base_firmware_failed;
+               goto transfer_firmware_failed;
        } else {
                ret = wait_event_timeout(skl->boot_wait, skl->boot_complete,
                                        msecs_to_jiffies(SKL_IPC_BOOT_MSECS));
                if (ret == 0) {
                        dev_err(ctx->dev, "DSP boot failed, FW Ready timed-out\n");
                        ret = -EIO;
-                       goto skl_load_base_firmware_failed;
+                       goto transfer_firmware_failed;
                }
 
                dev_dbg(ctx->dev, "Download firmware successful%d\n", ret);
                skl_dsp_set_state_locked(ctx, SKL_DSP_RUNNING);
        }
        return 0;
-
+transfer_firmware_failed:
+       ctx->cl_dev.ops.cl_cleanup_controller(ctx);
 skl_load_base_firmware_failed:
        skl_dsp_disable_core(ctx);
        release_firmware(ctx->fw);
@@ -175,10 +179,15 @@ static int skl_set_dsp_D3(struct sst_dsp *ctx)
        dx.core_mask = SKL_DSP_CORE0_MASK;
        dx.dx_mask = SKL_IPC_D3_MASK;
        ret = skl_ipc_set_dx(&skl->ipc, SKL_INSTANCE_ID, SKL_BASE_FW_MODULE_ID, &dx);
-       if (ret < 0) {
-               dev_err(ctx->dev, "Failed to set DSP to D3 state\n");
-               return ret;
-       }
+       if (ret < 0)
+               dev_err(ctx->dev,
+                       "D3 request to FW failed, continuing reset: %d", ret);
+
+       /* disable Interrupt */
+       ctx->cl_dev.ops.cl_cleanup_controller(ctx);
+       skl_cldma_int_disable(ctx);
+       skl_ipc_op_int_disable(ctx);
+       skl_ipc_int_disable(ctx);
 
        ret = skl_dsp_disable_core(ctx);
        if (ret < 0) {
@@ -187,12 +196,6 @@ static int skl_set_dsp_D3(struct sst_dsp *ctx)
        }
        skl_dsp_set_state_locked(ctx, SKL_DSP_RESET);
 
-       /* disable Interrupt */
-       ctx->cl_dev.ops.cl_cleanup_controller(ctx);
-       skl_cldma_int_disable(ctx);
-       skl_ipc_op_int_disable(ctx);
-       skl_ipc_int_disable(ctx);
-
        return ret;
 }
 
@@ -201,11 +204,182 @@ static unsigned int skl_get_errorcode(struct sst_dsp *ctx)
         return sst_dsp_shim_read(ctx, SKL_ADSP_ERROR_CODE);
 }
 
+/*
+ * since get/set_module are called from DAPM context,
+ * we don't need lock for usage count
+ */
+static int skl_get_module(struct sst_dsp *ctx, u16 mod_id)
+{
+       struct skl_module_table *module;
+
+       list_for_each_entry(module, &ctx->module_list, list) {
+               if (module->mod_info->mod_id == mod_id)
+                       return ++module->usage_cnt;
+       }
+
+       return -EINVAL;
+}
+
+static int skl_put_module(struct sst_dsp *ctx, u16 mod_id)
+{
+       struct skl_module_table *module;
+
+       list_for_each_entry(module, &ctx->module_list, list) {
+               if (module->mod_info->mod_id == mod_id)
+                       return --module->usage_cnt;
+       }
+
+       return -EINVAL;
+}
+
+static struct skl_module_table *skl_fill_module_table(struct sst_dsp *ctx,
+                                               char *mod_name, int mod_id)
+{
+       const struct firmware *fw;
+       struct skl_module_table *skl_module;
+       unsigned int size;
+       int ret;
+
+       ret = request_firmware(&fw, mod_name, ctx->dev);
+       if (ret < 0) {
+               dev_err(ctx->dev, "Request Module %s failed :%d\n",
+                                                       mod_name, ret);
+               return NULL;
+       }
+
+       skl_module = devm_kzalloc(ctx->dev, sizeof(*skl_module), GFP_KERNEL);
+       if (skl_module == NULL) {
+               release_firmware(fw);
+               return NULL;
+       }
+
+       size = sizeof(*skl_module->mod_info);
+       skl_module->mod_info = devm_kzalloc(ctx->dev, size, GFP_KERNEL);
+       if (skl_module->mod_info == NULL) {
+               release_firmware(fw);
+               return NULL;
+       }
+
+       skl_module->mod_info->mod_id = mod_id;
+       skl_module->mod_info->fw = fw;
+       list_add(&skl_module->list, &ctx->module_list);
+
+       return skl_module;
+}
+
+/* get a module from it's unique ID */
+static struct skl_module_table *skl_module_get_from_id(
+                       struct sst_dsp *ctx, u16 mod_id)
+{
+       struct skl_module_table *module;
+
+       if (list_empty(&ctx->module_list)) {
+               dev_err(ctx->dev, "Module list is empty\n");
+               return NULL;
+       }
+
+       list_for_each_entry(module, &ctx->module_list, list) {
+               if (module->mod_info->mod_id == mod_id)
+                       return module;
+       }
+
+       return NULL;
+}
+
+static int skl_transfer_module(struct sst_dsp *ctx,
+                       struct skl_load_module_info *module)
+{
+       int ret;
+       struct skl_sst *skl = ctx->thread_context;
+
+       ret = ctx->cl_dev.ops.cl_copy_to_dmabuf(ctx, module->fw->data,
+                                                       module->fw->size);
+       if (ret < 0)
+               return ret;
+
+       ret = skl_ipc_load_modules(&skl->ipc, SKL_NUM_MODULES,
+                                               (void *)&module->mod_id);
+       if (ret < 0)
+               dev_err(ctx->dev, "Failed to Load module: %d\n", ret);
+
+       ctx->cl_dev.ops.cl_stop_dma(ctx);
+
+       return ret;
+}
+
+static int skl_load_module(struct sst_dsp *ctx, u16 mod_id, char *guid)
+{
+       struct skl_module_table *module_entry = NULL;
+       int ret = 0;
+       char mod_name[64]; /* guid str = 32 chars + 4 hyphens */
+
+       snprintf(mod_name, sizeof(mod_name), "%s%s%s",
+                       "intel/dsp_fw_", guid, ".bin");
+
+       module_entry = skl_module_get_from_id(ctx, mod_id);
+       if (module_entry == NULL) {
+               module_entry = skl_fill_module_table(ctx, mod_name, mod_id);
+               if (module_entry == NULL) {
+                       dev_err(ctx->dev, "Failed to Load module\n");
+                       return -EINVAL;
+               }
+       }
+
+       if (!module_entry->usage_cnt) {
+               ret = skl_transfer_module(ctx, module_entry->mod_info);
+               if (ret < 0) {
+                       dev_err(ctx->dev, "Failed to Load module\n");
+                       return ret;
+               }
+       }
+
+       ret = skl_get_module(ctx, mod_id);
+
+       return ret;
+}
+
+static int skl_unload_module(struct sst_dsp *ctx, u16 mod_id)
+{
+       int usage_cnt;
+       struct skl_sst *skl = ctx->thread_context;
+       int ret = 0;
+
+       usage_cnt = skl_put_module(ctx, mod_id);
+       if (usage_cnt < 0) {
+               dev_err(ctx->dev, "Module bad usage cnt!:%d\n", usage_cnt);
+               return -EIO;
+       }
+       ret = skl_ipc_unload_modules(&skl->ipc,
+                       SKL_NUM_MODULES, &mod_id);
+       if (ret < 0) {
+               dev_err(ctx->dev, "Failed to UnLoad module\n");
+               skl_get_module(ctx, mod_id);
+               return ret;
+       }
+
+       return ret;
+}
+
+static void skl_clear_module_table(struct sst_dsp *ctx)
+{
+       struct skl_module_table *module, *tmp;
+
+       if (list_empty(&ctx->module_list))
+               return;
+
+       list_for_each_entry_safe(module, tmp, &ctx->module_list, list) {
+               list_del(&module->list);
+               release_firmware(module->mod_info->fw);
+       }
+}
+
 static struct skl_dsp_fw_ops skl_fw_ops = {
        .set_state_D0 = skl_set_dsp_D0,
        .set_state_D3 = skl_set_dsp_D3,
        .load_fw = skl_load_base_firmware,
        .get_fw_errcode = skl_get_errorcode,
+       .load_mod = skl_load_module,
+       .unload_mod = skl_unload_module,
 };
 
 static struct sst_ops skl_ops = {
@@ -223,7 +397,7 @@ static struct sst_dsp_device skl_dev = {
 };
 
 int skl_sst_dsp_init(struct device *dev, void __iomem *mmio_base, int irq,
-               struct skl_dsp_loader_ops dsp_ops, struct skl_sst **dsp)
+               const char *fw_name, struct skl_dsp_loader_ops dsp_ops, struct skl_sst **dsp)
 {
        struct skl_sst *skl;
        struct sst_dsp *sst;
@@ -244,11 +418,13 @@ int skl_sst_dsp_init(struct device *dev, void __iomem *mmio_base, int irq,
 
        sst = skl->dsp;
 
+       sst->fw_name = fw_name;
        sst->addr.lpe = mmio_base;
        sst->addr.shim = mmio_base;
        sst_dsp_mailbox_init(sst, (SKL_ADSP_SRAM0_BASE + SKL_ADSP_W0_STAT_SZ),
                        SKL_ADSP_W0_UP_SZ, SKL_ADSP_SRAM1_BASE, SKL_ADSP_W1_SZ);
 
+       INIT_LIST_HEAD(&sst->module_list);
        sst->dsp_ops = dsp_ops;
        sst->fw_ops = skl_fw_ops;
 
@@ -259,23 +435,24 @@ int skl_sst_dsp_init(struct device *dev, void __iomem *mmio_base, int irq,
        ret = sst->fw_ops.load_fw(sst);
        if (ret < 0) {
                dev_err(dev, "Load base fw failed : %d", ret);
-               return ret;
+               goto cleanup;
        }
 
        if (dsp)
                *dsp = skl;
 
-       return 0;
+       return ret;
 
-       skl_ipc_free(&skl->ipc);
+cleanup:
+       skl_sst_dsp_cleanup(dev, skl);
        return ret;
 }
 EXPORT_SYMBOL_GPL(skl_sst_dsp_init);
 
 void skl_sst_dsp_cleanup(struct device *dev, struct skl_sst *ctx)
 {
+       skl_clear_module_table(ctx->dsp);
        skl_ipc_free(&ctx->ipc);
-       ctx->dsp->cl_dev.ops.cl_cleanup_controller(ctx->dsp);
        ctx->dsp->ops->free(ctx->dsp);
 }
 EXPORT_SYMBOL_GPL(skl_sst_dsp_cleanup);
index a7854c8fc523e832f6137437c6e7737cc5eee46c..4624556f486de34c396a327a0d279a57a1fdbf96 100644 (file)
@@ -26,6 +26,8 @@
 #include "skl-topology.h"
 #include "skl.h"
 #include "skl-tplg-interface.h"
+#include "../common/sst-dsp.h"
+#include "../common/sst-dsp-priv.h"
 
 #define SKL_CH_FIXUP_MASK              (1 << 0)
 #define SKL_RATE_FIXUP_MASK            (1 << 1)
@@ -129,17 +131,15 @@ static void skl_dump_mconfig(struct skl_sst *ctx,
 {
        dev_dbg(ctx->dev, "Dumping config\n");
        dev_dbg(ctx->dev, "Input Format:\n");
-       dev_dbg(ctx->dev, "channels = %d\n", mcfg->in_fmt.channels);
-       dev_dbg(ctx->dev, "s_freq = %d\n", mcfg->in_fmt.s_freq);
-       dev_dbg(ctx->dev, "ch_cfg = %d\n", mcfg->in_fmt.ch_cfg);
-       dev_dbg(ctx->dev, "valid bit depth = %d\n",
-                       mcfg->in_fmt.valid_bit_depth);
+       dev_dbg(ctx->dev, "channels = %d\n", mcfg->in_fmt[0].channels);
+       dev_dbg(ctx->dev, "s_freq = %d\n", mcfg->in_fmt[0].s_freq);
+       dev_dbg(ctx->dev, "ch_cfg = %d\n", mcfg->in_fmt[0].ch_cfg);
+       dev_dbg(ctx->dev, "valid bit depth = %d\n", mcfg->in_fmt[0].valid_bit_depth);
        dev_dbg(ctx->dev, "Output Format:\n");
-       dev_dbg(ctx->dev, "channels = %d\n", mcfg->out_fmt.channels);
-       dev_dbg(ctx->dev, "s_freq = %d\n", mcfg->out_fmt.s_freq);
-       dev_dbg(ctx->dev, "valid bit depth = %d\n",
-                       mcfg->out_fmt.valid_bit_depth);
-       dev_dbg(ctx->dev, "ch_cfg = %d\n", mcfg->out_fmt.ch_cfg);
+       dev_dbg(ctx->dev, "channels = %d\n", mcfg->out_fmt[0].channels);
+       dev_dbg(ctx->dev, "s_freq = %d\n", mcfg->out_fmt[0].s_freq);
+       dev_dbg(ctx->dev, "valid bit depth = %d\n", mcfg->out_fmt[0].valid_bit_depth);
+       dev_dbg(ctx->dev, "ch_cfg = %d\n", mcfg->out_fmt[0].ch_cfg);
 }
 
 static void skl_tplg_update_params(struct skl_module_fmt *fmt,
@@ -149,8 +149,24 @@ static void skl_tplg_update_params(struct skl_module_fmt *fmt,
                fmt->s_freq = params->s_freq;
        if (fixup & SKL_CH_FIXUP_MASK)
                fmt->channels = params->ch;
-       if (fixup & SKL_FMT_FIXUP_MASK)
-               fmt->valid_bit_depth = params->s_fmt;
+       if (fixup & SKL_FMT_FIXUP_MASK) {
+               fmt->valid_bit_depth = skl_get_bit_depth(params->s_fmt);
+
+               /*
+                * 16 bit is 16 bit container whereas 24 bit is in 32 bit
+                * container so update bit depth accordingly
+                */
+               switch (fmt->valid_bit_depth) {
+               case SKL_DEPTH_16BIT:
+                       fmt->bit_depth = fmt->valid_bit_depth;
+                       break;
+
+               default:
+                       fmt->bit_depth = SKL_DEPTH_32BIT;
+                       break;
+               }
+       }
+
 }
 
 /*
@@ -171,8 +187,9 @@ static void skl_tplg_update_params_fixup(struct skl_module_cfg *m_cfg,
        int in_fixup, out_fixup;
        struct skl_module_fmt *in_fmt, *out_fmt;
 
-       in_fmt = &m_cfg->in_fmt;
-       out_fmt = &m_cfg->out_fmt;
+       /* Fixups will be applied to pin 0 only */
+       in_fmt = &m_cfg->in_fmt[0];
+       out_fmt = &m_cfg->out_fmt[0];
 
        if (params->stream == SNDRV_PCM_STREAM_PLAYBACK) {
                if (is_fe) {
@@ -209,18 +226,25 @@ static void skl_tplg_update_buffer_size(struct skl_sst *ctx,
                                struct skl_module_cfg *mcfg)
 {
        int multiplier = 1;
+       struct skl_module_fmt *in_fmt, *out_fmt;
+
+
+       /* Since fixups is applied to pin 0 only, ibs, obs needs
+        * change for pin 0 only
+        */
+       in_fmt = &mcfg->in_fmt[0];
+       out_fmt = &mcfg->out_fmt[0];
 
        if (mcfg->m_type == SKL_MODULE_TYPE_SRCINT)
                multiplier = 5;
-
-       mcfg->ibs = (mcfg->in_fmt.s_freq / 1000) *
-                               (mcfg->in_fmt.channels) *
-                               (mcfg->in_fmt.bit_depth >> 3) *
+       mcfg->ibs = (in_fmt->s_freq / 1000) *
+                               (mcfg->in_fmt->channels) *
+                               (mcfg->in_fmt->bit_depth >> 3) *
                                multiplier;
 
-       mcfg->obs = (mcfg->out_fmt.s_freq / 1000) *
-                               (mcfg->out_fmt.channels) *
-                               (mcfg->out_fmt.bit_depth >> 3) *
+       mcfg->obs = (mcfg->out_fmt->s_freq / 1000) *
+                               (mcfg->out_fmt->channels) *
+                               (mcfg->out_fmt->bit_depth >> 3) *
                                multiplier;
 }
 
@@ -291,6 +315,83 @@ static int skl_tplg_alloc_pipe_widget(struct device *dev,
        return 0;
 }
 
+/*
+ * some modules can have multiple params set from user control and
+ * need to be set after module is initialized. If set_param flag is
+ * set module params will be done after module is initialised.
+ */
+static int skl_tplg_set_module_params(struct snd_soc_dapm_widget *w,
+                                               struct skl_sst *ctx)
+{
+       int i, ret;
+       struct skl_module_cfg *mconfig = w->priv;
+       const struct snd_kcontrol_new *k;
+       struct soc_bytes_ext *sb;
+       struct skl_algo_data *bc;
+       struct skl_specific_cfg *sp_cfg;
+
+       if (mconfig->formats_config.caps_size > 0 &&
+               mconfig->formats_config.set_params == SKL_PARAM_SET) {
+               sp_cfg = &mconfig->formats_config;
+               ret = skl_set_module_params(ctx, sp_cfg->caps,
+                                       sp_cfg->caps_size,
+                                       sp_cfg->param_id, mconfig);
+               if (ret < 0)
+                       return ret;
+       }
+
+       for (i = 0; i < w->num_kcontrols; i++) {
+               k = &w->kcontrol_news[i];
+               if (k->access & SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK) {
+                       sb = (void *) k->private_value;
+                       bc = (struct skl_algo_data *)sb->dobj.private;
+
+                       if (bc->set_params == SKL_PARAM_SET) {
+                               ret = skl_set_module_params(ctx,
+                                               (u32 *)bc->params, bc->max,
+                                               bc->param_id, mconfig);
+                               if (ret < 0)
+                                       return ret;
+                       }
+               }
+       }
+
+       return 0;
+}
+
+/*
+ * some module param can set from user control and this is required as
+ * when module is initailzed. if module param is required in init it is
+ * identifed by set_param flag. if set_param flag is not set, then this
+ * parameter needs to set as part of module init.
+ */
+static int skl_tplg_set_module_init_data(struct snd_soc_dapm_widget *w)
+{
+       const struct snd_kcontrol_new *k;
+       struct soc_bytes_ext *sb;
+       struct skl_algo_data *bc;
+       struct skl_module_cfg *mconfig = w->priv;
+       int i;
+
+       for (i = 0; i < w->num_kcontrols; i++) {
+               k = &w->kcontrol_news[i];
+               if (k->access & SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK) {
+                       sb = (struct soc_bytes_ext *)k->private_value;
+                       bc = (struct skl_algo_data *)sb->dobj.private;
+
+                       if (bc->set_params != SKL_PARAM_INIT)
+                               continue;
+
+                       mconfig->formats_config.caps = (u32 *)&bc->params;
+                       mconfig->formats_config.caps_size = bc->max;
+
+                       break;
+               }
+       }
+
+       return 0;
+}
+
 /*
  * Inside a pipe instance, we can have various modules. These modules need
  * to instantiated in DSP by invoking INIT_MODULE IPC, which is achieved by
@@ -313,12 +414,25 @@ skl_tplg_init_pipe_modules(struct skl *skl, struct skl_pipe *pipe)
                if (!skl_tplg_alloc_pipe_mcps(skl, mconfig))
                        return -ENOMEM;
 
+               if (mconfig->is_loadable && ctx->dsp->fw_ops.load_mod) {
+                       ret = ctx->dsp->fw_ops.load_mod(ctx->dsp,
+                               mconfig->id.module_id, mconfig->guid);
+                       if (ret < 0)
+                               return ret;
+               }
+
                /*
                 * apply fix/conversion to module params based on
                 * FE/BE params
                 */
                skl_tplg_update_module_params(w, ctx);
-               ret = skl_init_module(ctx, mconfig, NULL);
+
+               skl_tplg_set_module_init_data(w);
+               ret = skl_init_module(ctx, mconfig);
+               if (ret < 0)
+                       return ret;
+
+               ret = skl_tplg_set_module_params(w, ctx);
                if (ret < 0)
                        return ret;
        }
@@ -326,6 +440,24 @@ skl_tplg_init_pipe_modules(struct skl *skl, struct skl_pipe *pipe)
        return 0;
 }
 
+static int skl_tplg_unload_pipe_modules(struct skl_sst *ctx,
+        struct skl_pipe *pipe)
+{
+       struct skl_pipe_module *w_module = NULL;
+       struct skl_module_cfg *mconfig = NULL;
+
+       list_for_each_entry(w_module, &pipe->w_list, node) {
+               mconfig  = w_module->w->priv;
+
+               if (mconfig->is_loadable && ctx->dsp->fw_ops.unload_mod)
+                       return ctx->dsp->fw_ops.unload_mod(ctx->dsp,
+                                               mconfig->id.module_id);
+       }
+
+       /* no modules to unload in this path, so return */
+       return 0;
+}
+
 /*
  * Mixer module represents a pipeline. So in the Pre-PMU event of mixer we
  * need create the pipeline. So we do following:
@@ -397,41 +529,24 @@ static int skl_tplg_mixer_dapm_pre_pmu_event(struct snd_soc_dapm_widget *w,
        return 0;
 }
 
-/*
- * A PGA represents a module in a pipeline. So in the Pre-PMU event of PGA
- * we need to do following:
- *   - Bind to sink pipeline
- *      Since the sink pipes can be running and we don't get mixer event on
- *      connect for already running mixer, we need to find the sink pipes
- *      here and bind to them. This way dynamic connect works.
- *   - Start sink pipeline, if not running
- *   - Then run current pipe
- */
-static int skl_tplg_pga_dapm_pre_pmu_event(struct snd_soc_dapm_widget *w,
-                                                       struct skl *skl)
+static int skl_tplg_bind_sinks(struct snd_soc_dapm_widget *w,
+                               struct skl *skl,
+                               struct skl_module_cfg *src_mconfig)
 {
        struct snd_soc_dapm_path *p;
-       struct skl_dapm_path_list *path_list;
-       struct snd_soc_dapm_widget *source, *sink;
-       struct skl_module_cfg *src_mconfig, *sink_mconfig;
+       struct snd_soc_dapm_widget *sink = NULL, *next_sink = NULL;
+       struct skl_module_cfg *sink_mconfig;
        struct skl_sst *ctx = skl->skl_sst;
-       int ret = 0;
-
-       source = w;
-       src_mconfig = source->priv;
+       int ret;
 
-       /*
-        * find which sink it is connected to, bind with the sink,
-        * if sink is not started, start sink pipe first, then start
-        * this pipe
-        */
-       snd_soc_dapm_widget_for_each_source_path(w, p) {
+       snd_soc_dapm_widget_for_each_sink_path(w, p) {
                if (!p->connect)
                        continue;
 
                dev_dbg(ctx->dev, "%s: src widget=%s\n", __func__, w->name);
                dev_dbg(ctx->dev, "%s: sink widget=%s\n", __func__, p->sink->name);
 
+               next_sink = p->sink;
                /*
                 * here we will check widgets in sink pipelines, so that
                 * can be any widgets type and we are only interested if
@@ -441,7 +556,6 @@ static int skl_tplg_pga_dapm_pre_pmu_event(struct snd_soc_dapm_widget *w,
                                        is_skl_dsp_widget_type(p->sink)) {
 
                        sink = p->sink;
-                       src_mconfig = source->priv;
                        sink_mconfig = sink->priv;
 
                        /* Bind source to sink, mixin is always source */
@@ -451,32 +565,89 @@ static int skl_tplg_pga_dapm_pre_pmu_event(struct snd_soc_dapm_widget *w,
 
                        /* Start sinks pipe first */
                        if (sink_mconfig->pipe->state != SKL_PIPE_STARTED) {
-                               ret = skl_run_pipe(ctx, sink_mconfig->pipe);
+                               if (sink_mconfig->pipe->conn_type !=
+                                                       SKL_PIPE_CONN_TYPE_FE)
+                                       ret = skl_run_pipe(ctx,
+                                                       sink_mconfig->pipe);
                                if (ret)
                                        return ret;
                        }
-
-                       path_list = kzalloc(
-                                       sizeof(struct skl_dapm_path_list),
-                                       GFP_KERNEL);
-                       if (path_list == NULL)
-                               return -ENOMEM;
-
-                       /* Add connected path to one global list */
-                       path_list->dapm_path = p;
-                       list_add_tail(&path_list->node, &skl->dapm_path_list);
-                       break;
                }
        }
 
-       /* Start source pipe last after starting all sinks */
-       ret = skl_run_pipe(ctx, src_mconfig->pipe);
+       if (!sink)
+               return skl_tplg_bind_sinks(next_sink, skl, src_mconfig);
+
+       return 0;
+}
+
+/*
+ * A PGA represents a module in a pipeline. So in the Pre-PMU event of PGA
+ * we need to do following:
+ *   - Bind to sink pipeline
+ *      Since the sink pipes can be running and we don't get mixer event on
+ *      connect for already running mixer, we need to find the sink pipes
+ *      here and bind to them. This way dynamic connect works.
+ *   - Start sink pipeline, if not running
+ *   - Then run current pipe
+ */
+static int skl_tplg_pga_dapm_pre_pmu_event(struct snd_soc_dapm_widget *w,
+                                                               struct skl *skl)
+{
+       struct skl_module_cfg *src_mconfig;
+       struct skl_sst *ctx = skl->skl_sst;
+       int ret = 0;
+
+       src_mconfig = w->priv;
+
+       /*
+        * find which sink it is connected to, bind with the sink,
+        * if sink is not started, start sink pipe first, then start
+        * this pipe
+        */
+       ret = skl_tplg_bind_sinks(w, skl, src_mconfig);
        if (ret)
                return ret;
 
+       /* Start source pipe last after starting all sinks */
+       if (src_mconfig->pipe->conn_type != SKL_PIPE_CONN_TYPE_FE)
+               return skl_run_pipe(ctx, src_mconfig->pipe);
+
        return 0;
 }
 
+static struct snd_soc_dapm_widget *skl_get_src_dsp_widget(
+               struct snd_soc_dapm_widget *w, struct skl *skl)
+{
+       struct snd_soc_dapm_path *p;
+       struct snd_soc_dapm_widget *src_w = NULL;
+       struct skl_sst *ctx = skl->skl_sst;
+
+       snd_soc_dapm_widget_for_each_source_path(w, p) {
+               src_w = p->source;
+               if (!p->connect)
+                       continue;
+
+               dev_dbg(ctx->dev, "sink widget=%s\n", w->name);
+               dev_dbg(ctx->dev, "src widget=%s\n", p->source->name);
+
+               /*
+                * here we will check widgets in sink pipelines, so that can
+                * be any widgets type and we are only interested if they are
+                * ones used for SKL so check that first
+                */
+               if ((p->source->priv != NULL) &&
+                                       is_skl_dsp_widget_type(p->source)) {
+                       return p->source;
+               }
+       }
+
+       if (src_w != NULL)
+               return skl_get_src_dsp_widget(src_w, skl);
+
+       return NULL;
+}
+
 /*
  * in the Post-PMU event of mixer we need to do following:
  *   - Check if this pipe is running
@@ -490,7 +661,6 @@ static int skl_tplg_mixer_dapm_post_pmu_event(struct snd_soc_dapm_widget *w,
                                                        struct skl *skl)
 {
        int ret = 0;
-       struct snd_soc_dapm_path *p;
        struct snd_soc_dapm_widget *source, *sink;
        struct skl_module_cfg *src_mconfig, *sink_mconfig;
        struct skl_sst *ctx = skl->skl_sst;
@@ -504,32 +674,18 @@ static int skl_tplg_mixer_dapm_post_pmu_event(struct snd_soc_dapm_widget *w,
         * one more sink before this sink got connected, Since source is
         * started, bind this sink to source and start this pipe.
         */
-       snd_soc_dapm_widget_for_each_sink_path(w, p) {
-               if (!p->connect)
-                       continue;
-
-               dev_dbg(ctx->dev, "sink widget=%s\n", w->name);
-               dev_dbg(ctx->dev, "src widget=%s\n", p->source->name);
+       source = skl_get_src_dsp_widget(w, skl);
+       if (source != NULL) {
+               src_mconfig = source->priv;
+               sink_mconfig = sink->priv;
+               src_pipe_started = 1;
 
                /*
-                * here we will check widgets in sink pipelines, so that
-                * can be any widgets type and we are only interested if
-                * they are ones used for SKL so check that first
+                * check pipe state, then no need to bind or start the
+                * pipe
                 */
-               if ((p->source->priv != NULL) &&
-                                       is_skl_dsp_widget_type(p->source)) {
-                       source = p->source;
-                       src_mconfig = source->priv;
-                       sink_mconfig = sink->priv;
-                       src_pipe_started = 1;
-
-                       /*
-                        * check pipe state, then no need to bind or start
-                        * the pipe
-                        */
-                       if (src_mconfig->pipe->state != SKL_PIPE_STARTED)
-                               src_pipe_started = 0;
-               }
+               if (src_mconfig->pipe->state != SKL_PIPE_STARTED)
+                       src_pipe_started = 0;
        }
 
        if (src_pipe_started) {
@@ -537,7 +693,8 @@ static int skl_tplg_mixer_dapm_post_pmu_event(struct snd_soc_dapm_widget *w,
                if (ret)
                        return ret;
 
-               ret = skl_run_pipe(ctx, sink_mconfig->pipe);
+               if (sink_mconfig->pipe->conn_type != SKL_PIPE_CONN_TYPE_FE)
+                       ret = skl_run_pipe(ctx, sink_mconfig->pipe);
        }
 
        return ret;
@@ -552,52 +709,35 @@ static int skl_tplg_mixer_dapm_post_pmu_event(struct snd_soc_dapm_widget *w,
 static int skl_tplg_mixer_dapm_pre_pmd_event(struct snd_soc_dapm_widget *w,
                                                        struct skl *skl)
 {
-       struct snd_soc_dapm_widget *source, *sink;
        struct skl_module_cfg *src_mconfig, *sink_mconfig;
-       int ret = 0, path_found = 0;
-       struct skl_dapm_path_list *path_list, *tmp_list;
+       int ret = 0, i;
        struct skl_sst *ctx = skl->skl_sst;
 
-       sink = w;
-       sink_mconfig = sink->priv;
+       sink_mconfig = w->priv;
 
        /* Stop the pipe */
        ret = skl_stop_pipe(ctx, sink_mconfig->pipe);
        if (ret)
                return ret;
 
-       /*
-        * This list, dapm_path_list handling here does not need any locks
-        * as we are under dapm lock while handling widget events.
-        * List can be manipulated safely only under dapm widgets handler
-        * routines
-        */
-       list_for_each_entry_safe(path_list, tmp_list,
-                               &skl->dapm_path_list, node) {
-               if (path_list->dapm_path->sink == sink) {
-                       dev_dbg(ctx->dev, "Path found = %s\n",
-                                       path_list->dapm_path->name);
-                       source = path_list->dapm_path->source;
-                       src_mconfig = source->priv;
-                       path_found = 1;
-
-                       list_del(&path_list->node);
-                       kfree(path_list);
-                       break;
-               }
-       }
-
-       /*
-        * If path_found == 1, that means pmd for source pipe has
-        * not occurred, source is connected to some other sink.
-        * so its responsibility of sink to unbind itself from source.
-        */
-       if (path_found) {
-               ret = skl_stop_pipe(ctx, src_mconfig->pipe);
-               if (ret < 0)
-                       return ret;
+       for (i = 0; i < sink_mconfig->max_in_queue; i++) {
+               if (sink_mconfig->m_in_pin[i].pin_state == SKL_PIN_BIND_DONE) {
+                       src_mconfig = sink_mconfig->m_in_pin[i].tgt_mcfg;
+                       if (!src_mconfig)
+                               continue;
+                       /*
+                        * If path_found == 1, that means pmd for source
+                        * pipe has not occurred, source is connected to
+                        * some other sink. so its responsibility of sink
+                        * to unbind itself from source.
+                        */
+                       ret = skl_stop_pipe(ctx, src_mconfig->pipe);
+                       if (ret < 0)
+                               return ret;
 
-               ret = skl_unbind_modules(ctx, src_mconfig, sink_mconfig);
+                       ret = skl_unbind_modules(ctx,
+                                               src_mconfig, sink_mconfig);
+               }
        }
 
        return ret;
@@ -622,10 +762,12 @@ static int skl_tplg_mixer_dapm_post_pmd_event(struct snd_soc_dapm_widget *w,
        int ret = 0;
 
        skl_tplg_free_pipe_mcps(skl, mconfig);
+       skl_tplg_free_pipe_mem(skl, mconfig);
 
        list_for_each_entry(w_module, &s_pipe->w_list, node) {
                dst_module = w_module->w->priv;
 
+               skl_tplg_free_pipe_mcps(skl, dst_module);
                if (src_module == NULL) {
                        src_module = dst_module;
                        continue;
@@ -639,9 +781,8 @@ static int skl_tplg_mixer_dapm_post_pmd_event(struct snd_soc_dapm_widget *w,
        }
 
        ret = skl_delete_pipe(ctx, mconfig->pipe);
-       skl_tplg_free_pipe_mem(skl, mconfig);
 
-       return ret;
+       return skl_tplg_unload_pipe_modules(ctx, s_pipe);
 }
 
 /*
@@ -653,47 +794,34 @@ static int skl_tplg_mixer_dapm_post_pmd_event(struct snd_soc_dapm_widget *w,
 static int skl_tplg_pga_dapm_post_pmd_event(struct snd_soc_dapm_widget *w,
                                                                struct skl *skl)
 {
-       struct snd_soc_dapm_widget *source, *sink;
        struct skl_module_cfg *src_mconfig, *sink_mconfig;
-       int ret = 0, path_found = 0;
-       struct skl_dapm_path_list *path_list, *tmp_path_list;
+       int ret = 0, i;
        struct skl_sst *ctx = skl->skl_sst;
 
-       source = w;
-       src_mconfig = source->priv;
+       src_mconfig = w->priv;
 
-       skl_tplg_free_pipe_mcps(skl, src_mconfig);
        /* Stop the pipe since this is a mixin module */
        ret = skl_stop_pipe(ctx, src_mconfig->pipe);
        if (ret)
                return ret;
 
-       list_for_each_entry_safe(path_list, tmp_path_list, &skl->dapm_path_list, node) {
-               if (path_list->dapm_path->source == source) {
-                       dev_dbg(ctx->dev, "Path found = %s\n",
-                                       path_list->dapm_path->name);
-                       sink = path_list->dapm_path->sink;
-                       sink_mconfig = sink->priv;
-                       path_found = 1;
-
-                       list_del(&path_list->node);
-                       kfree(path_list);
-                       break;
+       for (i = 0; i < src_mconfig->max_out_queue; i++) {
+               if (src_mconfig->m_out_pin[i].pin_state == SKL_PIN_BIND_DONE) {
+                       sink_mconfig = src_mconfig->m_out_pin[i].tgt_mcfg;
+                       if (!sink_mconfig)
+                               continue;
+                       /*
+                        * This is a connecter and if path is found that means
+                        * unbind between source and sink has not happened yet
+                        */
+                       ret = skl_stop_pipe(ctx, sink_mconfig->pipe);
+                       if (ret < 0)
+                               return ret;
+                       ret = skl_unbind_modules(ctx, src_mconfig,
+                                                       sink_mconfig);
                }
        }
 
-       /*
-        * This is a connector and if path is found that means
-        * unbind between source and sink has not happened yet
-        */
-       if (path_found) {
-               ret = skl_stop_pipe(ctx, src_mconfig->pipe);
-               if (ret < 0)
-                       return ret;
-
-               ret = skl_unbind_modules(ctx, src_mconfig, sink_mconfig);
-       }
-
        return ret;
 }
 
@@ -774,6 +902,67 @@ static int skl_tplg_pga_event(struct snd_soc_dapm_widget *w,
        return 0;
 }
 
+static int skl_tplg_tlv_control_get(struct snd_kcontrol *kcontrol,
+                       unsigned int __user *data, unsigned int size)
+{
+       struct soc_bytes_ext *sb =
+                       (struct soc_bytes_ext *)kcontrol->private_value;
+       struct skl_algo_data *bc = (struct skl_algo_data *)sb->dobj.private;
+       struct snd_soc_dapm_widget *w = snd_soc_dapm_kcontrol_widget(kcontrol);
+       struct skl_module_cfg *mconfig = w->priv;
+       struct skl *skl = get_skl_ctx(w->dapm->dev);
+
+       if (w->power)
+               skl_get_module_params(skl->skl_sst, (u32 *)bc->params,
+                                     bc->max, bc->param_id, mconfig);
+
+       if (bc->params) {
+               if (copy_to_user(data, &bc->param_id, sizeof(u32)))
+                       return -EFAULT;
+               if (copy_to_user(data + 1, &size, sizeof(u32)))
+                       return -EFAULT;
+               if (copy_to_user(data + 2, bc->params, size))
+                       return -EFAULT;
+       }
+
+       return 0;
+}
+
+#define SKL_PARAM_VENDOR_ID 0xff
+
+static int skl_tplg_tlv_control_set(struct snd_kcontrol *kcontrol,
+                       const unsigned int __user *data, unsigned int size)
+{
+       struct snd_soc_dapm_widget *w = snd_soc_dapm_kcontrol_widget(kcontrol);
+       struct skl_module_cfg *mconfig = w->priv;
+       struct soc_bytes_ext *sb =
+                       (struct soc_bytes_ext *)kcontrol->private_value;
+       struct skl_algo_data *ac = (struct skl_algo_data *)sb->dobj.private;
+       struct skl *skl = get_skl_ctx(w->dapm->dev);
+
+       if (ac->params) {
+               /*
+                * if the param_is is of type Vendor, firmware expects actual
+                * parameter id and size from the control.
+                */
+               if (ac->param_id == SKL_PARAM_VENDOR_ID) {
+                       if (copy_from_user(ac->params, data, size))
+                               return -EFAULT;
+               } else {
+                       if (copy_from_user(ac->params,
+                                          data + 2 * sizeof(u32), size))
+                               return -EFAULT;
+               }
+
+               if (w->power)
+                       return skl_set_module_params(skl->skl_sst,
+                                               (u32 *)ac->params, ac->max,
+                                               ac->param_id, mconfig);
+       }
+
+       return 0;
+}
+
 /*
  * The FE params are passed by hw_params of the DAI.
  * On hw_params, the params are stored in Gateway module of the FE and we
@@ -790,9 +979,9 @@ int skl_tplg_update_pipe_params(struct device *dev,
        memcpy(pipe->p_params, params, sizeof(*params));
 
        if (params->stream == SNDRV_PCM_STREAM_PLAYBACK)
-               format = &mconfig->in_fmt;
+               format = &mconfig->in_fmt[0];
        else
-               format = &mconfig->out_fmt;
+               format = &mconfig->out_fmt[0];
 
        /* set the hw_params */
        format->s_freq = params->s_freq;
@@ -809,6 +998,7 @@ int skl_tplg_update_pipe_params(struct device *dev,
                break;
 
        case SKL_DEPTH_24BIT:
+       case SKL_DEPTH_32BIT:
                format->bit_depth = SKL_DEPTH_32BIT;
                break;
 
@@ -846,7 +1036,7 @@ skl_tplg_fe_get_cpr_module(struct snd_soc_dai *dai, int stream)
                w = dai->playback_widget;
                snd_soc_dapm_widget_for_each_sink_path(w, p) {
                        if (p->connect && p->sink->power &&
-                                       is_skl_dsp_widget_type(p->sink))
+                                       !is_skl_dsp_widget_type(p->sink))
                                continue;
 
                        if (p->sink->priv) {
@@ -859,7 +1049,7 @@ skl_tplg_fe_get_cpr_module(struct snd_soc_dai *dai, int stream)
                w = dai->capture_widget;
                snd_soc_dapm_widget_for_each_source_path(w, p) {
                        if (p->connect && p->source->power &&
-                                       is_skl_dsp_widget_type(p->source))
+                                       !is_skl_dsp_widget_type(p->source))
                                continue;
 
                        if (p->source->priv) {
@@ -920,6 +1110,9 @@ static int skl_tplg_be_fill_pipe_params(struct snd_soc_dai *dai,
 
        memcpy(pipe->p_params, params, sizeof(*params));
 
+       if (link_type == NHLT_LINK_HDA)
+               return 0;
+
        /* update the blob based on virtual bus_id*/
        cfg = skl_get_ep_blob(skl, mconfig->vbus_id, link_type,
                                        params->s_fmt, params->ch,
@@ -950,18 +1143,13 @@ static int skl_tplg_be_set_src_pipe_params(struct snd_soc_dai *dai,
                if (p->connect && is_skl_dsp_widget_type(p->source) &&
                                                p->source->priv) {
 
-                       if (!p->source->power) {
-                               ret = skl_tplg_be_fill_pipe_params(
-                                               dai, p->source->priv,
-                                               params);
-                               if (ret < 0)
-                                       return ret;
-                       } else {
-                               return -EBUSY;
-                       }
+                       ret = skl_tplg_be_fill_pipe_params(dai,
+                                               p->source->priv, params);
+                       if (ret < 0)
+                               return ret;
                } else {
-                       ret = skl_tplg_be_set_src_pipe_params(
-                                               dai, p->source, params);
+                       ret = skl_tplg_be_set_src_pipe_params(dai,
+                                               p->source, params);
                        if (ret < 0)
                                return ret;
                }
@@ -980,15 +1168,10 @@ static int skl_tplg_be_set_sink_pipe_params(struct snd_soc_dai *dai,
                if (p->connect && is_skl_dsp_widget_type(p->sink) &&
                                                p->sink->priv) {
 
-                       if (!p->sink->power) {
-                               ret = skl_tplg_be_fill_pipe_params(
-                                               dai, p->sink->priv, params);
-                               if (ret < 0)
-                                       return ret;
-                       } else {
-                               return -EBUSY;
-                       }
-
+                       ret = skl_tplg_be_fill_pipe_params(dai,
+                                               p->sink->priv, params);
+                       if (ret < 0)
+                               return ret;
                } else {
                        ret = skl_tplg_be_set_sink_pipe_params(
                                                dai, p->sink, params);
@@ -1030,6 +1213,11 @@ static const struct snd_soc_tplg_widget_events skl_tplg_widget_ops[] = {
        {SKL_PGA_EVENT, skl_tplg_pga_event},
 };
 
+static const struct snd_soc_tplg_bytes_ext_ops skl_tlv_ops[] = {
+       {SKL_CONTROL_TYPE_BYTE_TLV, skl_tplg_tlv_control_get,
+                                       skl_tplg_tlv_control_set},
+};
+
 /*
  * The topology binary passes the pin info for a module so initialize the pin
  * info passed into module instance
@@ -1045,6 +1233,7 @@ static void skl_fill_module_pin_info(struct skl_dfw_module_pin *dfw_pin,
                m_pin[i].id.instance_id = dfw_pin[i].instance_id;
                m_pin[i].in_use = false;
                m_pin[i].is_dynamic = is_dynamic;
+               m_pin[i].pin_state = SKL_PIN_UNBIND;
        }
 }
 
@@ -1092,6 +1281,24 @@ static struct skl_pipe *skl_tplg_add_pipe(struct device *dev,
        return ppl->pipe;
 }
 
+static void skl_tplg_fill_fmt(struct skl_module_fmt *dst_fmt,
+                               struct skl_dfw_module_fmt *src_fmt,
+                               int pins)
+{
+       int i;
+
+       for (i = 0; i < pins; i++) {
+               dst_fmt[i].channels  = src_fmt[i].channels;
+               dst_fmt[i].s_freq = src_fmt[i].freq;
+               dst_fmt[i].bit_depth = src_fmt[i].bit_depth;
+               dst_fmt[i].valid_bit_depth = src_fmt[i].valid_bit_depth;
+               dst_fmt[i].ch_cfg = src_fmt[i].ch_cfg;
+               dst_fmt[i].ch_map = src_fmt[i].ch_map;
+               dst_fmt[i].interleaving_style = src_fmt[i].interleaving_style;
+               dst_fmt[i].sample_type = src_fmt[i].sample_type;
+       }
+}
+
 /*
  * Topology core widget load callback
  *
@@ -1130,22 +1337,16 @@ static int skl_tplg_widget_load(struct snd_soc_component *cmpnt,
        mconfig->max_in_queue = dfw_config->max_in_queue;
        mconfig->max_out_queue = dfw_config->max_out_queue;
        mconfig->is_loadable = dfw_config->is_loadable;
-       mconfig->in_fmt.channels = dfw_config->in_fmt.channels;
-       mconfig->in_fmt.s_freq = dfw_config->in_fmt.freq;
-       mconfig->in_fmt.bit_depth = dfw_config->in_fmt.bit_depth;
-       mconfig->in_fmt.valid_bit_depth =
-                               dfw_config->in_fmt.valid_bit_depth;
-       mconfig->in_fmt.ch_cfg = dfw_config->in_fmt.ch_cfg;
-       mconfig->out_fmt.channels = dfw_config->out_fmt.channels;
-       mconfig->out_fmt.s_freq = dfw_config->out_fmt.freq;
-       mconfig->out_fmt.bit_depth = dfw_config->out_fmt.bit_depth;
-       mconfig->out_fmt.valid_bit_depth =
-                               dfw_config->out_fmt.valid_bit_depth;
-       mconfig->out_fmt.ch_cfg = dfw_config->out_fmt.ch_cfg;
+       skl_tplg_fill_fmt(mconfig->in_fmt, dfw_config->in_fmt,
+                                               MODULE_MAX_IN_PINS);
+       skl_tplg_fill_fmt(mconfig->out_fmt, dfw_config->out_fmt,
+                                               MODULE_MAX_OUT_PINS);
+
        mconfig->params_fixup = dfw_config->params_fixup;
        mconfig->converter = dfw_config->converter;
        mconfig->m_type = dfw_config->module_type;
        mconfig->vbus_id = dfw_config->vbus_id;
+       mconfig->mem_pages = dfw_config->mem_pages;
 
        pipe = skl_tplg_add_pipe(bus->dev, skl, &dfw_config->pipe);
        if (pipe)
@@ -1156,10 +1357,13 @@ static int skl_tplg_widget_load(struct snd_soc_component *cmpnt,
        mconfig->time_slot = dfw_config->time_slot;
        mconfig->formats_config.caps_size = dfw_config->caps.caps_size;
 
-       mconfig->m_in_pin = devm_kzalloc(bus->dev,
-                               (mconfig->max_in_queue) *
-                                       sizeof(*mconfig->m_in_pin),
-                               GFP_KERNEL);
+       if (dfw_config->is_loadable)
+               memcpy(mconfig->guid, dfw_config->uuid,
+                                       ARRAY_SIZE(dfw_config->uuid));
+
+       mconfig->m_in_pin = devm_kzalloc(bus->dev, (mconfig->max_in_queue) *
+                                               sizeof(*mconfig->m_in_pin),
+                                               GFP_KERNEL);
        if (!mconfig->m_in_pin)
                return -ENOMEM;
 
@@ -1188,7 +1392,9 @@ static int skl_tplg_widget_load(struct snd_soc_component *cmpnt,
                return -ENOMEM;
 
        memcpy(mconfig->formats_config.caps, dfw_config->caps.caps,
-                                        dfw_config->caps.caps_size);
+                                                dfw_config->caps.caps_size);
+       mconfig->formats_config.param_id = dfw_config->caps.param_id;
+       mconfig->formats_config.set_params = dfw_config->caps.set_params;
 
 bind_event:
        if (tplg_w->event_type == 0) {
@@ -1209,8 +1415,70 @@ bind_event:
        return 0;
 }
 
+static int skl_init_algo_data(struct device *dev, struct soc_bytes_ext *be,
+                                       struct snd_soc_tplg_bytes_control *bc)
+{
+       struct skl_algo_data *ac;
+       struct skl_dfw_algo_data *dfw_ac =
+                               (struct skl_dfw_algo_data *)bc->priv.data;
+
+       ac = devm_kzalloc(dev, sizeof(*ac), GFP_KERNEL);
+       if (!ac)
+               return -ENOMEM;
+
+       /* Fill private data */
+       ac->max = dfw_ac->max;
+       ac->param_id = dfw_ac->param_id;
+       ac->set_params = dfw_ac->set_params;
+
+       if (ac->max) {
+               ac->params = (char *) devm_kzalloc(dev, ac->max, GFP_KERNEL);
+               if (!ac->params)
+                       return -ENOMEM;
+
+               if (dfw_ac->params)
+                       memcpy(ac->params, dfw_ac->params, ac->max);
+       }
+
+       be->dobj.private  = ac;
+       return 0;
+}
+
+static int skl_tplg_control_load(struct snd_soc_component *cmpnt,
+                               struct snd_kcontrol_new *kctl,
+                               struct snd_soc_tplg_ctl_hdr *hdr)
+{
+       struct soc_bytes_ext *sb;
+       struct snd_soc_tplg_bytes_control *tplg_bc;
+       struct hdac_ext_bus *ebus  = snd_soc_component_get_drvdata(cmpnt);
+       struct hdac_bus *bus = ebus_to_hbus(ebus);
+
+       switch (hdr->ops.info) {
+       case SND_SOC_TPLG_CTL_BYTES:
+               tplg_bc = container_of(hdr,
+                               struct snd_soc_tplg_bytes_control, hdr);
+               if (kctl->access & SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK) {
+                       sb = (struct soc_bytes_ext *)kctl->private_value;
+                       if (tplg_bc->priv.size)
+                               return skl_init_algo_data(
+                                               bus->dev, sb, tplg_bc);
+               }
+               break;
+
+       default:
+               dev_warn(bus->dev, "Control load not supported %d:%d:%d\n",
+                       hdr->ops.get, hdr->ops.put, hdr->ops.info);
+               break;
+       }
+
+       return 0;
+}
+
 static struct snd_soc_tplg_ops skl_tplg_ops  = {
        .widget_load = skl_tplg_widget_load,
+       .control_load = skl_tplg_control_load,
+       .bytes_ext_ops = skl_tlv_ops,
+       .bytes_ext_ops_count = ARRAY_SIZE(skl_tlv_ops),
 };
 
 /* This will be read from topology manifest, currently defined here */
@@ -1248,5 +1516,7 @@ int skl_tplg_init(struct snd_soc_platform *platform, struct hdac_ext_bus *ebus)
        skl->resource.max_mcps = SKL_MAX_MCPS;
        skl->resource.max_mem = SKL_FW_MAX_MEM;
 
+       skl->tplg = fw;
+
        return 0;
 }
index 76053a8de41cf255bfe77d24673c320cf5d2fd0a..9aa2a2b6598a3ede5dff38f0570c5b16e30bcb70 100644 (file)
@@ -36,6 +36,9 @@
 /* Maximum number of coefficients up down mixer module */
 #define UP_DOWN_MIXER_MAX_COEFF                6
 
+#define MODULE_MAX_IN_PINS     8
+#define MODULE_MAX_OUT_PINS    8
+
 enum skl_channel_index {
        SKL_CHANNEL_LEFT = 0,
        SKL_CHANNEL_RIGHT = 1,
@@ -55,12 +58,6 @@ enum skl_bitdepth {
        SKL_DEPTH_INVALID
 };
 
-enum skl_interleaving {
-       /* [s1_ch1...s1_chN,...,sM_ch1...sM_chN] */
-       SKL_INTERLEAVING_PER_CHANNEL = 0,
-       /* [s1_ch1...sM_ch1,...,s1_chN...sM_chN] */
-       SKL_INTERLEAVING_PER_SAMPLE = 1,
-};
 
 enum skl_s_freq {
        SKL_FS_8000 = 8000,
@@ -143,6 +140,16 @@ struct skl_up_down_mixer_cfg {
        s32 coeff[UP_DOWN_MIXER_MAX_COEFF];
 } __packed;
 
+struct skl_algo_cfg {
+       struct skl_base_cfg  base_cfg;
+       char params[0];
+} __packed;
+
+struct skl_base_outfmt_cfg {
+       struct skl_base_cfg base_cfg;
+       struct skl_audio_data_format out_fmt;
+} __packed;
+
 enum skl_dma_type {
        SKL_DMA_HDA_HOST_OUTPUT_CLASS = 0,
        SKL_DMA_HDA_HOST_INPUT_CLASS = 1,
@@ -178,21 +185,34 @@ struct skl_module_fmt {
        u32 bit_depth;
        u32 valid_bit_depth;
        u32 ch_cfg;
+       u32 interleaving_style;
+       u32 sample_type;
+       u32 ch_map;
 };
 
+struct skl_module_cfg;
+
 struct skl_module_inst_id {
        u32 module_id;
        u32 instance_id;
 };
 
+enum skl_module_pin_state {
+       SKL_PIN_UNBIND = 0,
+       SKL_PIN_BIND_DONE = 1,
+};
+
 struct skl_module_pin {
        struct skl_module_inst_id id;
-       u8 pin_index;
        bool is_dynamic;
        bool in_use;
+       enum skl_module_pin_state pin_state;
+       struct skl_module_cfg *tgt_mcfg;
 };
 
 struct skl_specific_cfg {
+       u32 set_params;
+       u32 param_id;
        u32 caps_size;
        u32 *caps;
 };
@@ -238,9 +258,13 @@ enum skl_module_state {
 };
 
 struct skl_module_cfg {
+       char guid[SKL_UUID_STR_SZ];
        struct skl_module_inst_id id;
-       struct skl_module_fmt in_fmt;
-       struct skl_module_fmt out_fmt;
+       u8 domain;
+       bool homogenous_inputs;
+       bool homogenous_outputs;
+       struct skl_module_fmt in_fmt[MODULE_MAX_IN_PINS];
+       struct skl_module_fmt out_fmt[MODULE_MAX_OUT_PINS];
        u8 max_in_queue;
        u8 max_out_queue;
        u8 in_queue_mask;
@@ -258,6 +282,7 @@ struct skl_module_cfg {
        u32 params_fixup;
        u32 converter;
        u32 vbus_id;
+       u32 mem_pages;
        struct skl_module_pin *m_in_pin;
        struct skl_module_pin *m_out_pin;
        enum skl_module_type m_type;
@@ -267,13 +292,15 @@ struct skl_module_cfg {
        struct skl_specific_cfg formats_config;
 };
 
-struct skl_pipeline {
-       struct skl_pipe *pipe;
-       struct list_head node;
+struct skl_algo_data {
+       u32 param_id;
+       u32 set_params;
+       u32 max;
+       char *params;
 };
 
-struct skl_dapm_path_list {
-       struct snd_soc_dapm_path *dapm_path;
+struct skl_pipeline {
+       struct skl_pipe *pipe;
        struct list_head node;
 };
 
@@ -305,8 +332,7 @@ int skl_delete_pipe(struct skl_sst *ctx, struct skl_pipe *pipe);
 
 int skl_stop_pipe(struct skl_sst *ctx, struct skl_pipe *pipe);
 
-int skl_init_module(struct skl_sst *ctx, struct skl_module_cfg *module_config,
-       char *param);
+int skl_init_module(struct skl_sst *ctx, struct skl_module_cfg *module_config);
 
 int skl_bind_modules(struct skl_sst *ctx, struct skl_module_cfg
        *src_module, struct skl_module_cfg *dst_module);
@@ -314,5 +340,10 @@ int skl_bind_modules(struct skl_sst *ctx, struct skl_module_cfg
 int skl_unbind_modules(struct skl_sst *ctx, struct skl_module_cfg
        *src_module, struct skl_module_cfg *dst_module);
 
+int skl_set_module_params(struct skl_sst *ctx, u32 *params, int size,
+                       u32 param_id, struct skl_module_cfg *mcfg);
+int skl_get_module_params(struct skl_sst *ctx, u32 *params, int size,
+                         u32 param_id, struct skl_module_cfg *mcfg);
+
 enum skl_bitdepth skl_get_bit_depth(int params);
 #endif
index 2bc396d54cbed52fa257c1c499749eaed8ebc111..c9ae010b3cc8dc1df5a359a67987a44186e588cc 100644 (file)
  * Default types range from 0~12. type can range from 0 to 0xff
  * SST types start at higher to avoid any overlapping in future
  */
-#define SOC_CONTROL_TYPE_HDA_SST_ALGO_PARAMS   0x100
-#define SOC_CONTROL_TYPE_HDA_SST_MUX           0x101
-#define SOC_CONTROL_TYPE_HDA_SST_MIX           0x101
-#define SOC_CONTROL_TYPE_HDA_SST_BYTE          0x103
+#define SKL_CONTROL_TYPE_BYTE_TLV      0x100
 
 #define HDA_SST_CFG_MAX        900 /* size of copier cfg*/
 #define MAX_IN_QUEUE 8
 #define MAX_OUT_QUEUE 8
 
+#define SKL_UUID_STR_SZ 40
 /* Event types goes here */
 /* Reserve event type 0 for no event handlers */
 enum skl_event_types {
@@ -72,6 +70,7 @@ enum skl_ch_cfg {
        SKL_CH_CFG_DUAL_MONO = 9,
        SKL_CH_CFG_I2S_DUAL_STEREO_0 = 10,
        SKL_CH_CFG_I2S_DUAL_STEREO_1 = 11,
+       SKL_CH_CFG_4_CHANNEL = 12,
        SKL_CH_CFG_INVALID
 };
 
@@ -79,7 +78,9 @@ enum skl_module_type {
        SKL_MODULE_TYPE_MIXER = 0,
        SKL_MODULE_TYPE_COPIER,
        SKL_MODULE_TYPE_UPDWMIX,
-       SKL_MODULE_TYPE_SRCINT
+       SKL_MODULE_TYPE_SRCINT,
+       SKL_MODULE_TYPE_ALGO,
+       SKL_MODULE_TYPE_BASE_OUTFMT
 };
 
 enum skl_core_affinity {
@@ -110,6 +111,42 @@ enum skl_dev_type {
        SKL_DEVICE_NONE
 };
 
+/**
+ * enum skl_interleaving - interleaving style
+ *
+ * @SKL_INTERLEAVING_PER_CHANNEL: [s1_ch1...s1_chN,...,sM_ch1...sM_chN]
+ * @SKL_INTERLEAVING_PER_SAMPLE: [s1_ch1...sM_ch1,...,s1_chN...sM_chN]
+ */
+enum skl_interleaving {
+       SKL_INTERLEAVING_PER_CHANNEL = 0,
+       SKL_INTERLEAVING_PER_SAMPLE = 1,
+};
+
+enum skl_sample_type {
+       SKL_SAMPLE_TYPE_INT_MSB = 0,
+       SKL_SAMPLE_TYPE_INT_LSB = 1,
+       SKL_SAMPLE_TYPE_INT_SIGNED = 2,
+       SKL_SAMPLE_TYPE_INT_UNSIGNED = 3,
+       SKL_SAMPLE_TYPE_FLOAT = 4
+};
+
+enum module_pin_type {
+       /* All pins of the module takes same PCM inputs or outputs
+       * e.g. mixout
+       */
+       SKL_PIN_TYPE_HOMOGENEOUS,
+       /* All pins of the module takes different PCM inputs or outputs
+       * e.g mux
+       */
+       SKL_PIN_TYPE_HETEROGENEOUS,
+};
+
+enum skl_module_param_type {
+       SKL_PARAM_DEFAULT = 0,
+       SKL_PARAM_INIT,
+       SKL_PARAM_SET
+};
+
 struct skl_dfw_module_pin {
        u16 module_id;
        u16 instance_id;
@@ -121,9 +158,15 @@ struct skl_dfw_module_fmt {
        u32 bit_depth;
        u32 valid_bit_depth;
        u32 ch_cfg;
+       u32 interleaving_style;
+       u32 sample_type;
+       u32 ch_map;
 } __packed;
 
 struct skl_dfw_module_caps {
+       u32 set_params:2;
+       u32 rsvd:30;
+       u32 param_id;
        u32 caps_size;
        u32 caps[HDA_SST_CFG_MAX];
 };
@@ -131,41 +174,57 @@ struct skl_dfw_module_caps {
 struct skl_dfw_pipe {
        u8 pipe_id;
        u8 pipe_priority;
-       u16 conn_type;
-       u32 memory_pages;
+       u16 conn_type:4;
+       u16 rsvd:4;
+       u16 memory_pages:8;
 } __packed;
 
 struct skl_dfw_module {
+       char uuid[SKL_UUID_STR_SZ];
+
        u16 module_id;
        u16 instance_id;
        u32 max_mcps;
-       u8 core_id;
-       u8 max_in_queue;
-       u8 max_out_queue;
-       u8 is_loadable;
-       u8 conn_type;
-       u8 dev_type;
-       u8 hw_conn_type;
-       u8 time_slot;
+       u32 mem_pages;
        u32 obs;
        u32 ibs;
-       u32 params_fixup;
-       u32 converter;
-       u32 module_type;
        u32 vbus_id;
-       u8 is_dynamic_in_pin;
-       u8 is_dynamic_out_pin;
+
+       u32 max_in_queue:8;
+       u32 max_out_queue:8;
+       u32 time_slot:8;
+       u32 core_id:4;
+       u32 rsvd1:4;
+
+       u32 module_type:8;
+       u32 conn_type:4;
+       u32 dev_type:4;
+       u32 hw_conn_type:4;
+       u32 rsvd2:12;
+
+       u32 params_fixup:8;
+       u32 converter:8;
+       u32 input_pin_type:1;
+       u32 output_pin_type:1;
+       u32 is_dynamic_in_pin:1;
+       u32 is_dynamic_out_pin:1;
+       u32 is_loadable:1;
+       u32 rsvd3:11;
+
        struct skl_dfw_pipe pipe;
-       struct skl_dfw_module_fmt in_fmt;
-       struct skl_dfw_module_fmt out_fmt;
+       struct skl_dfw_module_fmt in_fmt[MAX_IN_QUEUE];
+       struct skl_dfw_module_fmt out_fmt[MAX_OUT_QUEUE];
        struct skl_dfw_module_pin in_pin[MAX_IN_QUEUE];
        struct skl_dfw_module_pin out_pin[MAX_OUT_QUEUE];
        struct skl_dfw_module_caps caps;
 } __packed;
 
 struct skl_dfw_algo_data {
+       u32 set_params:2;
+       u32 rsvd:30;
+       u32 param_id;
        u32 max;
-       char *params;
+       char params[0];
 } __packed;
 
 #endif
index 5319529aedf7ae5030dbf47ce9b6056512f05c2d..443a15de94b5fbc3813f126da74e4bb3781f6e15 100644 (file)
 #include <linux/pci.h>
 #include <linux/pm_runtime.h>
 #include <linux/platform_device.h>
+#include <linux/firmware.h>
 #include <sound/pcm.h>
+#include "../common/sst-acpi.h"
 #include "skl.h"
+#include "skl-sst-dsp.h"
+#include "skl-sst-ipc.h"
 
 /*
  * initialize the PCI registers
@@ -57,6 +61,49 @@ static void skl_init_pci(struct skl *skl)
        skl_update_pci_byte(skl->pci, AZX_PCIREG_TCSEL, 0x07, 0);
 }
 
+static void update_pci_dword(struct pci_dev *pci,
+                       unsigned int reg, u32 mask, u32 val)
+{
+       u32 data = 0;
+
+       pci_read_config_dword(pci, reg, &data);
+       data &= ~mask;
+       data |= (val & mask);
+       pci_write_config_dword(pci, reg, data);
+}
+
+/*
+ * skl_enable_miscbdcge - enable/dsiable CGCTL.MISCBDCGE bits
+ *
+ * @dev: device pointer
+ * @enable: enable/disable flag
+ */
+static void skl_enable_miscbdcge(struct device *dev, bool enable)
+{
+       struct pci_dev *pci = to_pci_dev(dev);
+       u32 val;
+
+       val = enable ? AZX_CGCTL_MISCBDCGE_MASK : 0;
+
+       update_pci_dword(pci, AZX_PCIREG_CGCTL, AZX_CGCTL_MISCBDCGE_MASK, val);
+}
+
+/*
+ * While performing reset, controller may not come back properly causing
+ * issues, so recommendation is to set CGCTL.MISCBDCGE to 0 then do reset
+ * (init chip) and then again set CGCTL.MISCBDCGE to 1
+ */
+static int skl_init_chip(struct hdac_bus *bus, bool full_reset)
+{
+       int ret;
+
+       skl_enable_miscbdcge(bus->dev, false);
+       ret = snd_hdac_bus_init_chip(bus, full_reset);
+       skl_enable_miscbdcge(bus->dev, true);
+
+       return ret;
+}
+
 /* called from IRQ */
 static void skl_stream_update(struct hdac_bus *bus, struct hdac_stream *hstr)
 {
@@ -129,6 +176,39 @@ static int skl_acquire_irq(struct hdac_ext_bus *ebus, int do_disconnect)
        return 0;
 }
 
+#ifdef CONFIG_PM
+static int _skl_suspend(struct hdac_ext_bus *ebus)
+{
+       struct skl *skl = ebus_to_skl(ebus);
+       struct hdac_bus *bus = ebus_to_hbus(ebus);
+       int ret;
+
+       snd_hdac_ext_bus_link_power_down_all(ebus);
+
+       ret = skl_suspend_dsp(skl);
+       if (ret < 0)
+               return ret;
+
+       snd_hdac_bus_stop_chip(bus);
+       skl_enable_miscbdcge(bus->dev, false);
+       snd_hdac_bus_enter_link_reset(bus);
+       skl_enable_miscbdcge(bus->dev, true);
+
+       return 0;
+}
+
+static int _skl_resume(struct hdac_ext_bus *ebus)
+{
+       struct skl *skl = ebus_to_skl(ebus);
+       struct hdac_bus *bus = ebus_to_hbus(ebus);
+
+       skl_init_pci(skl);
+       skl_init_chip(bus, true);
+
+       return skl_resume_dsp(skl);
+}
+#endif
+
 #ifdef CONFIG_PM_SLEEP
 /*
  * power management
@@ -137,26 +217,46 @@ static int skl_suspend(struct device *dev)
 {
        struct pci_dev *pci = to_pci_dev(dev);
        struct hdac_ext_bus *ebus = pci_get_drvdata(pci);
+       struct skl *skl  = ebus_to_skl(ebus);
        struct hdac_bus *bus = ebus_to_hbus(ebus);
 
-       snd_hdac_bus_stop_chip(bus);
-       snd_hdac_bus_enter_link_reset(bus);
-
-       return 0;
+       /*
+        * Do not suspend if streams which are marked ignore suspend are
+        * running, we need to save the state for these and continue
+        */
+       if (skl->supend_active) {
+               snd_hdac_ext_bus_link_power_down_all(ebus);
+               enable_irq_wake(bus->irq);
+               pci_save_state(pci);
+               pci_disable_device(pci);
+               return 0;
+       } else {
+               return _skl_suspend(ebus);
+       }
 }
 
 static int skl_resume(struct device *dev)
 {
        struct pci_dev *pci = to_pci_dev(dev);
        struct hdac_ext_bus *ebus = pci_get_drvdata(pci);
+       struct skl *skl  = ebus_to_skl(ebus);
        struct hdac_bus *bus = ebus_to_hbus(ebus);
-       struct skl *hda = ebus_to_skl(ebus);
-
-       skl_init_pci(hda);
+       int ret;
 
-       snd_hdac_bus_init_chip(bus, 1);
+       /*
+        * resume only when we are not in suspend active, otherwise need to
+        * restore the device
+        */
+       if (skl->supend_active) {
+               pci_restore_state(pci);
+               ret = pci_enable_device(pci);
+               snd_hdac_ext_bus_link_power_up_all(ebus);
+               disable_irq_wake(bus->irq);
+       } else {
+               ret = _skl_resume(ebus);
+       }
 
-       return 0;
+       return ret;
 }
 #endif /* CONFIG_PM_SLEEP */
 
@@ -166,24 +266,10 @@ static int skl_runtime_suspend(struct device *dev)
        struct pci_dev *pci = to_pci_dev(dev);
        struct hdac_ext_bus *ebus = pci_get_drvdata(pci);
        struct hdac_bus *bus = ebus_to_hbus(ebus);
-       struct skl *skl = ebus_to_skl(ebus);
-       int ret;
 
        dev_dbg(bus->dev, "in %s\n", __func__);
 
-       /* enable controller wake up event */
-       snd_hdac_chip_updatew(bus, WAKEEN, 0, STATESTS_INT_MASK);
-
-       snd_hdac_ext_bus_link_power_down_all(ebus);
-
-       ret = skl_suspend_dsp(skl);
-       if (ret < 0)
-               return ret;
-
-       snd_hdac_bus_stop_chip(bus);
-       snd_hdac_bus_enter_link_reset(bus);
-
-       return 0;
+       return _skl_suspend(ebus);
 }
 
 static int skl_runtime_resume(struct device *dev)
@@ -191,20 +277,10 @@ static int skl_runtime_resume(struct device *dev)
        struct pci_dev *pci = to_pci_dev(dev);
        struct hdac_ext_bus *ebus = pci_get_drvdata(pci);
        struct hdac_bus *bus = ebus_to_hbus(ebus);
-       struct skl *skl = ebus_to_skl(ebus);
-       int status;
 
        dev_dbg(bus->dev, "in %s\n", __func__);
 
-       /* Read STATESTS before controller reset */
-       status = snd_hdac_chip_readw(bus, STATESTS);
-
-       skl_init_pci(skl);
-       snd_hdac_bus_init_chip(bus, true);
-       /* disable controller Wake Up event */
-       snd_hdac_chip_updatew(bus, WAKEEN, STATESTS_INT_MASK, 0);
-
-       return skl_resume_dsp(skl);
+       return _skl_resume(ebus);
 }
 #endif /* CONFIG_PM */
 
@@ -241,6 +317,43 @@ static int skl_free(struct hdac_ext_bus *ebus)
        return 0;
 }
 
+static int skl_machine_device_register(struct skl *skl, void *driver_data)
+{
+       struct hdac_bus *bus = ebus_to_hbus(&skl->ebus);
+       struct platform_device *pdev;
+       struct sst_acpi_mach *mach = driver_data;
+       int ret;
+
+       mach = sst_acpi_find_machine(mach);
+       if (mach == NULL) {
+               dev_err(bus->dev, "No matching machine driver found\n");
+               return -ENODEV;
+       }
+       skl->fw_name = mach->fw_filename;
+
+       pdev = platform_device_alloc(mach->drv_name, -1);
+       if (pdev == NULL) {
+               dev_err(bus->dev, "platform device alloc failed\n");
+               return -EIO;
+       }
+
+       ret = platform_device_add(pdev);
+       if (ret) {
+               dev_err(bus->dev, "failed to add machine device\n");
+               platform_device_put(pdev);
+               return -EIO;
+       }
+       skl->i2s_dev = pdev;
+
+       return 0;
+}
+
+static void skl_machine_device_unregister(struct skl *skl)
+{
+       if (skl->i2s_dev)
+               platform_device_unregister(skl->i2s_dev);
+}
+
 static int skl_dmic_device_register(struct skl *skl)
 {
        struct hdac_bus *bus = ebus_to_hbus(&skl->ebus);
@@ -320,7 +433,7 @@ static int skl_codec_create(struct hdac_ext_bus *ebus)
                                 * back to the sanity state.
                                 */
                                snd_hdac_bus_stop_chip(bus);
-                               snd_hdac_bus_init_chip(bus, true);
+                               skl_init_chip(bus, true);
                        }
                }
        }
@@ -430,12 +543,11 @@ static int skl_first_init(struct hdac_ext_bus *ebus)
        /* initialize chip */
        skl_init_pci(skl);
 
-       snd_hdac_bus_init_chip(bus, true);
+       skl_init_chip(bus, true);
 
        /* codec detection */
        if (!bus->codec_mask) {
-               dev_err(bus->dev, "no codecs found!\n");
-               return -ENODEV;
+               dev_info(bus->dev, "no hda codecs found!\n");
        }
 
        return 0;
@@ -470,11 +582,18 @@ static int skl_probe(struct pci_dev *pci,
 
        /* check if dsp is there */
        if (ebus->ppcap) {
+               err = skl_machine_device_register(skl,
+                                 (void *)pci_id->driver_data);
+               if (err < 0)
+                       goto out_free;
+
                err = skl_init_dsp(skl);
                if (err < 0) {
                        dev_dbg(bus->dev, "error failed to register dsp\n");
-                       goto out_free;
+                       goto out_mach_free;
                }
+               skl->skl_sst->enable_miscbdcge = skl_enable_miscbdcge;
+
        }
        if (ebus->mlcap)
                snd_hdac_ext_bus_get_ml_capabilities(ebus);
@@ -508,6 +627,8 @@ out_dmic_free:
        skl_dmic_device_unregister(skl);
 out_dsp_free:
        skl_free_dsp(skl);
+out_mach_free:
+       skl_machine_device_unregister(skl);
 out_free:
        skl->init_failed = 1;
        skl_free(ebus);
@@ -520,20 +641,34 @@ static void skl_remove(struct pci_dev *pci)
        struct hdac_ext_bus *ebus = pci_get_drvdata(pci);
        struct skl *skl = ebus_to_skl(ebus);
 
+       if (skl->tplg)
+               release_firmware(skl->tplg);
+
        if (pci_dev_run_wake(pci))
                pm_runtime_get_noresume(&pci->dev);
        pci_dev_put(pci);
        skl_platform_unregister(&pci->dev);
        skl_free_dsp(skl);
+       skl_machine_device_unregister(skl);
        skl_dmic_device_unregister(skl);
        skl_free(ebus);
        dev_set_drvdata(&pci->dev, NULL);
 }
 
+static struct sst_acpi_mach sst_skl_devdata[] = {
+       { "INT343A", "skl_alc286s_i2s", "intel/dsp_fw_release.bin", NULL, NULL, NULL },
+       { "INT343B", "skl_nau88l25_ssm4567_i2s", "intel/dsp_fw_release.bin",
+                               NULL, NULL, NULL },
+       { "MX98357A", "skl_nau88l25_max98357a_i2s", "intel/dsp_fw_release.bin",
+                               NULL, NULL, NULL },
+       {}
+};
+
 /* PCI IDs */
 static const struct pci_device_id skl_ids[] = {
        /* Sunrise Point-LP */
-       { PCI_DEVICE(0x8086, 0x9d70), 0},
+       { PCI_DEVICE(0x8086, 0x9d70),
+               .driver_data = (unsigned long)&sst_skl_devdata},
        { 0, }
 };
 MODULE_DEVICE_TABLE(pci, skl_ids);
index dd2e79ae45a8e6294c2766ef5eff7f4fac37befe..8a08bb7279911fc7bb888e0d3dff42d19fddcede 100644 (file)
@@ -48,6 +48,9 @@
 #define AZX_REG_VS_SDXEFIFOS_XBASE     0x1094
 #define AZX_REG_VS_SDXEFIFOS_XINTERVAL 0x20
 
+#define AZX_PCIREG_CGCTL               0x48
+#define AZX_CGCTL_MISCBDCGE_MASK       (1 << 6)
+
 struct skl_dsp_resource {
        u32 max_mcps;
        u32 max_mem;
@@ -61,6 +64,7 @@ struct skl {
 
        unsigned int init_failed:1; /* delayed init failed */
        struct platform_device *dmic_dev;
+       struct platform_device *i2s_dev;
 
        void *nhlt; /* nhlt ptr */
        struct skl_sst *skl_sst; /* sst skl ctx */
@@ -68,6 +72,10 @@ struct skl {
        struct skl_dsp_resource resource;
        struct list_head ppl_list;
        struct list_head dapm_path_list;
+       const char *fw_name;
+       const struct firmware *tplg;
+
+       int supend_active;
 };
 
 #define skl_to_ebus(s) (&(s)->ebus)
index cc4393cb1130fb53338a6d766b513df94be3229a..9b1af1a7087480c95f931a3b9e020d0f33ac8e46 100644 (file)
@@ -92,7 +92,6 @@ struct mtk_afe_memif_data {
 struct mtk_afe_memif {
        unsigned int phys_buf_addr;
        int buffer_size;
-       unsigned int hw_ptr;            /* Previous IRQ's HW ptr */
        struct snd_pcm_substream *substream;
        const struct mtk_afe_memif_data *data;
        const struct mtk_afe_irq_data *irqdata;
index f5baf3c38863f4eda4e31f2af8c612a6c23f3493..08af9f5dc4ab2117bb81501b0381930f9cf483b5 100644 (file)
@@ -175,8 +175,17 @@ static snd_pcm_uframes_t mtk_afe_pcm_pointer
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
        struct mtk_afe *afe = snd_soc_platform_get_drvdata(rtd->platform);
        struct mtk_afe_memif *memif = &afe->memif[rtd->cpu_dai->id];
+       unsigned int hw_ptr;
+       int ret;
+
+       ret = regmap_read(afe->regmap, memif->data->reg_ofs_cur, &hw_ptr);
+       if (ret || hw_ptr == 0) {
+               dev_err(afe->dev, "%s hw_ptr err\n", __func__);
+               hw_ptr = memif->phys_buf_addr;
+       }
 
-       return bytes_to_frames(substream->runtime, memif->hw_ptr);
+       return bytes_to_frames(substream->runtime,
+                              hw_ptr - memif->phys_buf_addr);
 }
 
 static const struct snd_pcm_ops mtk_afe_pcm_ops = {
@@ -299,8 +308,6 @@ static int mtk_afe_dais_enable_clks(struct mtk_afe *afe,
                        dev_err(afe->dev, "Failed to enable m_ck\n");
                        return ret;
                }
-               regmap_update_bits(afe->regmap, AUDIO_TOP_CON0,
-                                  AUD_TCON0_PDN_22M | AUD_TCON0_PDN_24M, 0);
        }
 
        if (b_ck) {
@@ -340,12 +347,8 @@ static int mtk_afe_dais_set_clks(struct mtk_afe *afe,
 static void mtk_afe_dais_disable_clks(struct mtk_afe *afe,
                                      struct clk *m_ck, struct clk *b_ck)
 {
-       if (m_ck) {
-               regmap_update_bits(afe->regmap, AUDIO_TOP_CON0,
-                                  AUD_TCON0_PDN_22M | AUD_TCON0_PDN_24M,
-                                  AUD_TCON0_PDN_22M | AUD_TCON0_PDN_24M);
+       if (m_ck)
                clk_disable_unprepare(m_ck);
-       }
        if (b_ck)
                clk_disable_unprepare(b_ck);
 }
@@ -360,6 +363,8 @@ static int mtk_afe_i2s_startup(struct snd_pcm_substream *substream,
                return 0;
 
        mtk_afe_dais_enable_clks(afe, afe->clocks[MTK_CLK_I2S1_M], NULL);
+       regmap_update_bits(afe->regmap, AUDIO_TOP_CON0,
+                          AUD_TCON0_PDN_22M | AUD_TCON0_PDN_24M, 0);
        return 0;
 }
 
@@ -373,10 +378,10 @@ static void mtk_afe_i2s_shutdown(struct snd_pcm_substream *substream,
                return;
 
        mtk_afe_set_i2s_enable(afe, false);
+       regmap_update_bits(afe->regmap, AUDIO_TOP_CON0,
+                          AUD_TCON0_PDN_22M | AUD_TCON0_PDN_24M,
+                          AUD_TCON0_PDN_22M | AUD_TCON0_PDN_24M);
        mtk_afe_dais_disable_clks(afe, afe->clocks[MTK_CLK_I2S1_M], NULL);
-
-       /* disable AFE */
-       regmap_update_bits(afe->regmap, AFE_DAC_CON0, 0x1, 0);
 }
 
 static int mtk_afe_i2s_prepare(struct snd_pcm_substream *substream,
@@ -425,9 +430,6 @@ static void mtk_afe_hdmi_shutdown(struct snd_pcm_substream *substream,
 
        mtk_afe_dais_disable_clks(afe, afe->clocks[MTK_CLK_I2S3_M],
                                  afe->clocks[MTK_CLK_I2S3_B]);
-
-       /* disable AFE */
-       regmap_update_bits(afe->regmap, AFE_DAC_CON0, 0x1, 0);
 }
 
 static int mtk_afe_hdmi_prepare(struct snd_pcm_substream *substream,
@@ -603,7 +605,6 @@ static int mtk_afe_dais_hw_params(struct snd_pcm_substream *substream,
 
        memif->phys_buf_addr = substream->runtime->dma_addr;
        memif->buffer_size = substream->runtime->dma_bytes;
-       memif->hw_ptr = 0;
 
        /* start */
        regmap_write(afe->regmap,
@@ -672,17 +673,6 @@ static int mtk_afe_dais_hw_free(struct snd_pcm_substream *substream,
        return snd_pcm_lib_free_pages(substream);
 }
 
-static int mtk_afe_dais_prepare(struct snd_pcm_substream *substream,
-                               struct snd_soc_dai *dai)
-{
-       struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct mtk_afe *afe = snd_soc_platform_get_drvdata(rtd->platform);
-
-       /* enable AFE */
-       regmap_update_bits(afe->regmap, AFE_DAC_CON0, 0x1, 0x1);
-       return 0;
-}
-
 static int mtk_afe_dais_trigger(struct snd_pcm_substream *substream, int cmd,
                                struct snd_soc_dai *dai)
 {
@@ -738,7 +728,6 @@ static int mtk_afe_dais_trigger(struct snd_pcm_substream *substream, int cmd,
                /* and clear pending IRQ */
                regmap_write(afe->regmap, AFE_IRQ_CLR,
                             1 << memif->data->irq_clr_shift);
-               memif->hw_ptr = 0;
                return 0;
        default:
                return -EINVAL;
@@ -751,7 +740,6 @@ static const struct snd_soc_dai_ops mtk_afe_dai_ops = {
        .shutdown       = mtk_afe_dais_shutdown,
        .hw_params      = mtk_afe_dais_hw_params,
        .hw_free        = mtk_afe_dais_hw_free,
-       .prepare        = mtk_afe_dais_prepare,
        .trigger        = mtk_afe_dais_trigger,
 };
 
@@ -1082,7 +1070,7 @@ static const struct regmap_config mtk_afe_regmap_config = {
 static irqreturn_t mtk_afe_irq_handler(int irq, void *dev_id)
 {
        struct mtk_afe *afe = dev_id;
-       unsigned int reg_value, hw_ptr;
+       unsigned int reg_value;
        int i, ret;
 
        ret = regmap_read(afe->regmap, AFE_IRQ_STATUS, &reg_value);
@@ -1098,13 +1086,6 @@ static irqreturn_t mtk_afe_irq_handler(int irq, void *dev_id)
                if (!(reg_value & (1 << memif->data->irq_clr_shift)))
                        continue;
 
-               ret = regmap_read(afe->regmap, memif->data->reg_ofs_cur,
-                                 &hw_ptr);
-               if (ret || hw_ptr == 0) {
-                       dev_err(afe->dev, "%s hw_ptr err\n", __func__);
-                       hw_ptr = memif->phys_buf_addr;
-               }
-               memif->hw_ptr = hw_ptr - memif->phys_buf_addr;
                snd_pcm_period_elapsed(memif->substream);
        }
 
@@ -1119,6 +1100,9 @@ static int mtk_afe_runtime_suspend(struct device *dev)
 {
        struct mtk_afe *afe = dev_get_drvdata(dev);
 
+       /* disable AFE */
+       regmap_update_bits(afe->regmap, AFE_DAC_CON0, 0x1, 0);
+
        /* disable AFE clk */
        regmap_update_bits(afe->regmap, AUDIO_TOP_CON0,
                           AUD_TCON0_PDN_AFE, AUD_TCON0_PDN_AFE);
@@ -1165,6 +1149,9 @@ static int mtk_afe_runtime_resume(struct device *dev)
 
        /* unmask all IRQs */
        regmap_update_bits(afe->regmap, AFE_IRQ_MCU_EN, 0xff, 0xff);
+
+       /* enable AFE */
+       regmap_update_bits(afe->regmap, AFE_DAC_CON0, 0x1, 0x1);
        return 0;
 
 err_bck0:
index 584b2372339ef4e7f985ca0c11a77d300eb84888..f83cc2bc0fc41a3434e0dca238569e613e3bad22 100644 (file)
@@ -368,6 +368,8 @@ static int omap_hdmi_audio_probe(struct platform_device *pdev)
        card->owner = THIS_MODULE;
        card->dai_link =
                devm_kzalloc(dev, sizeof(*(card->dai_link)), GFP_KERNEL);
+       if (!card->dai_link)
+               return -ENOMEM;
        card->dai_link->name = card->name;
        card->dai_link->stream_name = card->name;
        card->dai_link->cpu_dai_name = dev_name(ad->dssdev);
index 6147e86e9b0fc2f0addc82a2374c7aa3f095bbb8..416ea646c3b1606b7bbc499c50bd447046f6a23b 100644 (file)
@@ -63,8 +63,7 @@ static int brownstone_wm8994_hw_params(struct snd_pcm_substream *substream,
                sysclk    = params_rate(params) * 512;
                sspa_mclk = params_rate(params) * 64;
        }
-       sspa_div = freq_out;
-       do_div(sspa_div, sspa_mclk);
+       sspa_div = freq_out / sspa_mclk;
 
        snd_soc_dai_set_sysclk(cpu_dai, MMP_SSPA_CLK_AUDIO, freq_out, 0);
        snd_soc_dai_set_pll(cpu_dai, MMP_SYSCLK, 0, freq_out, sysclk);
index 29bc60e85e92898e585a57202ad2540f4be61cae..5c8f9db50a47a0315f0dba8065549a527dfc43c4 100644 (file)
@@ -81,8 +81,12 @@ static int rear_amp_power(struct snd_soc_codec *codec, int power)
 static int rear_amp_event(struct snd_soc_dapm_widget *widget,
                          struct snd_kcontrol *kctl, int event)
 {
-       struct snd_soc_codec *codec = widget->dapm->card->rtd[0].codec;
+       struct snd_soc_card *card = widget->dapm->card;
+       struct snd_soc_pcm_runtime *rtd;
+       struct snd_soc_codec *codec;
 
+       rtd = snd_soc_get_pcm_runtime(card, card->dai_link[0].name);
+       codec = rtd->codec;
        return rear_amp_power(codec, SND_SOC_DAPM_EVENT_ON(event));
 }
 
index e5101e0d2d372262f8ecf7d0498240cba971b86f..00b6c9d039cfada651dad6e917be9318dc4ce762 100644 (file)
@@ -355,6 +355,7 @@ static struct regmap_config lpass_cpu_regmap_config = {
        .readable_reg = lpass_cpu_regmap_readable,
        .volatile_reg = lpass_cpu_regmap_volatile,
        .cache_type = REGCACHE_FLAT,
+       .val_format_endian = REGMAP_ENDIAN_LITTLE,
 };
 
 int asoc_qcom_lpass_cpu_platform_probe(struct platform_device *pdev)
index 58ee64594f075efb7327d1480113f1401e97f248..6561c4cc2eddbac035cec09ddd51dead9d3d8c22 100644 (file)
@@ -34,13 +34,7 @@ struct rk_i2s_dev {
 
        struct regmap *regmap;
 
-/*
- * Used to indicate the tx/rx status.
- * I2S controller hopes to start the tx and rx together,
- * also to stop them when they are both try to stop.
-*/
-       bool tx_start;
-       bool rx_start;
+       bool is_master_mode;
 };
 
 static int i2s_runtime_suspend(struct device *dev)
@@ -81,37 +75,29 @@ static void rockchip_snd_txctrl(struct rk_i2s_dev *i2s, int on)
                                   I2S_DMACR_TDE_ENABLE, I2S_DMACR_TDE_ENABLE);
 
                regmap_update_bits(i2s->regmap, I2S_XFER,
-                                  I2S_XFER_TXS_START | I2S_XFER_RXS_START,
-                                  I2S_XFER_TXS_START | I2S_XFER_RXS_START);
-
-               i2s->tx_start = true;
+                                  I2S_XFER_TXS_START,
+                                  I2S_XFER_TXS_START);
        } else {
-               i2s->tx_start = false;
-
                regmap_update_bits(i2s->regmap, I2S_DMACR,
                                   I2S_DMACR_TDE_ENABLE, I2S_DMACR_TDE_DISABLE);
 
-               if (!i2s->rx_start) {
-                       regmap_update_bits(i2s->regmap, I2S_XFER,
-                                          I2S_XFER_TXS_START |
-                                          I2S_XFER_RXS_START,
-                                          I2S_XFER_TXS_STOP |
-                                          I2S_XFER_RXS_STOP);
+               regmap_update_bits(i2s->regmap, I2S_XFER,
+                                  I2S_XFER_TXS_START,
+                                  I2S_XFER_TXS_STOP);
 
-                       regmap_update_bits(i2s->regmap, I2S_CLR,
-                                          I2S_CLR_TXC | I2S_CLR_RXC,
-                                          I2S_CLR_TXC | I2S_CLR_RXC);
+               regmap_update_bits(i2s->regmap, I2S_CLR,
+                                  I2S_CLR_TXC,
+                                  I2S_CLR_TXC);
 
-                       regmap_read(i2s->regmap, I2S_CLR, &val);
+               regmap_read(i2s->regmap, I2S_CLR, &val);
 
-                       /* Should wait for clear operation to finish */
-                       while (val) {
-                               regmap_read(i2s->regmap, I2S_CLR, &val);
-                               retry--;
-                               if (!retry) {
-                                       dev_warn(i2s->dev, "fail to clear\n");
-                                       break;
-                               }
+               /* Should wait for clear operation to finish */
+               while (val & I2S_CLR_TXC) {
+                       regmap_read(i2s->regmap, I2S_CLR, &val);
+                       retry--;
+                       if (!retry) {
+                               dev_warn(i2s->dev, "fail to clear\n");
+                               break;
                        }
                }
        }
@@ -127,37 +113,29 @@ static void rockchip_snd_rxctrl(struct rk_i2s_dev *i2s, int on)
                                   I2S_DMACR_RDE_ENABLE, I2S_DMACR_RDE_ENABLE);
 
                regmap_update_bits(i2s->regmap, I2S_XFER,
-                                  I2S_XFER_TXS_START | I2S_XFER_RXS_START,
-                                  I2S_XFER_TXS_START | I2S_XFER_RXS_START);
-
-               i2s->rx_start = true;
+                                  I2S_XFER_RXS_START,
+                                  I2S_XFER_RXS_START);
        } else {
-               i2s->rx_start = false;
-
                regmap_update_bits(i2s->regmap, I2S_DMACR,
                                   I2S_DMACR_RDE_ENABLE, I2S_DMACR_RDE_DISABLE);
 
-               if (!i2s->tx_start) {
-                       regmap_update_bits(i2s->regmap, I2S_XFER,
-                                          I2S_XFER_TXS_START |
-                                          I2S_XFER_RXS_START,
-                                          I2S_XFER_TXS_STOP |
-                                          I2S_XFER_RXS_STOP);
+               regmap_update_bits(i2s->regmap, I2S_XFER,
+                                  I2S_XFER_RXS_START,
+                                  I2S_XFER_RXS_STOP);
 
-                       regmap_update_bits(i2s->regmap, I2S_CLR,
-                                          I2S_CLR_TXC | I2S_CLR_RXC,
-                                          I2S_CLR_TXC | I2S_CLR_RXC);
+               regmap_update_bits(i2s->regmap, I2S_CLR,
+                                  I2S_CLR_RXC,
+                                  I2S_CLR_RXC);
 
-                       regmap_read(i2s->regmap, I2S_CLR, &val);
+               regmap_read(i2s->regmap, I2S_CLR, &val);
 
-                       /* Should wait for clear operation to finish */
-                       while (val) {
-                               regmap_read(i2s->regmap, I2S_CLR, &val);
-                               retry--;
-                               if (!retry) {
-                                       dev_warn(i2s->dev, "fail to clear\n");
-                                       break;
-                               }
+               /* Should wait for clear operation to finish */
+               while (val & I2S_CLR_RXC) {
+                       regmap_read(i2s->regmap, I2S_CLR, &val);
+                       retry--;
+                       if (!retry) {
+                               dev_warn(i2s->dev, "fail to clear\n");
+                               break;
                        }
                }
        }
@@ -174,9 +152,11 @@ static int rockchip_i2s_set_fmt(struct snd_soc_dai *cpu_dai,
        case SND_SOC_DAIFMT_CBS_CFS:
                /* Set source clock in Master mode */
                val = I2S_CKR_MSS_MASTER;
+               i2s->is_master_mode = true;
                break;
        case SND_SOC_DAIFMT_CBM_CFM:
                val = I2S_CKR_MSS_SLAVE;
+               i2s->is_master_mode = false;
                break;
        default:
                return -EINVAL;
@@ -228,6 +208,26 @@ static int rockchip_i2s_hw_params(struct snd_pcm_substream *substream,
        struct rk_i2s_dev *i2s = to_info(dai);
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
        unsigned int val = 0;
+       unsigned int mclk_rate, bclk_rate, div_bclk, div_lrck;
+
+       if (i2s->is_master_mode) {
+               mclk_rate = clk_get_rate(i2s->mclk);
+               bclk_rate = 2 * 32 * params_rate(params);
+               if (bclk_rate && mclk_rate % bclk_rate)
+                       return -EINVAL;
+
+               div_bclk = mclk_rate / bclk_rate;
+               div_lrck = bclk_rate / params_rate(params);
+               regmap_update_bits(i2s->regmap, I2S_CKR,
+                                  I2S_CKR_MDIV_MASK,
+                                  I2S_CKR_MDIV(div_bclk));
+
+               regmap_update_bits(i2s->regmap, I2S_CKR,
+                                  I2S_CKR_TSD_MASK |
+                                  I2S_CKR_RSD_MASK,
+                                  I2S_CKR_TSD(div_lrck) |
+                                  I2S_CKR_RSD(div_lrck));
+       }
 
        switch (params_format(params)) {
        case SNDRV_PCM_FORMAT_S8:
@@ -242,6 +242,9 @@ static int rockchip_i2s_hw_params(struct snd_pcm_substream *substream,
        case SNDRV_PCM_FORMAT_S24_LE:
                val |= I2S_TXCR_VDW(24);
                break;
+       case SNDRV_PCM_FORMAT_S32_LE:
+               val |= I2S_TXCR_VDW(32);
+               break;
        default:
                return -EINVAL;
        }
@@ -360,7 +363,8 @@ static struct snd_soc_dai_driver rockchip_i2s_dai = {
                .formats = (SNDRV_PCM_FMTBIT_S8 |
                            SNDRV_PCM_FMTBIT_S16_LE |
                            SNDRV_PCM_FMTBIT_S20_3LE |
-                           SNDRV_PCM_FMTBIT_S24_LE),
+                           SNDRV_PCM_FMTBIT_S24_LE |
+                           SNDRV_PCM_FMTBIT_S32_LE),
        },
        .capture = {
                .stream_name = "Capture",
@@ -370,7 +374,8 @@ static struct snd_soc_dai_driver rockchip_i2s_dai = {
                .formats = (SNDRV_PCM_FMTBIT_S8 |
                            SNDRV_PCM_FMTBIT_S16_LE |
                            SNDRV_PCM_FMTBIT_S20_3LE |
-                           SNDRV_PCM_FMTBIT_S24_LE),
+                           SNDRV_PCM_FMTBIT_S24_LE |
+                           SNDRV_PCM_FMTBIT_S32_LE),
        },
        .ops = &rockchip_i2s_dai_ops,
        .symmetric_rates = 1,
@@ -451,6 +456,7 @@ static int rockchip_i2s_probe(struct platform_device *pdev)
 {
        struct device_node *node = pdev->dev.of_node;
        struct rk_i2s_dev *i2s;
+       struct snd_soc_dai_driver *soc_dai;
        struct resource *res;
        void __iomem *regs;
        int ret;
@@ -511,17 +517,26 @@ static int rockchip_i2s_probe(struct platform_device *pdev)
                        goto err_pm_disable;
        }
 
-       /* refine capture channels */
+       soc_dai = devm_kzalloc(&pdev->dev,
+                              sizeof(*soc_dai), GFP_KERNEL);
+       if (!soc_dai)
+               return -ENOMEM;
+
+       memcpy(soc_dai, &rockchip_i2s_dai, sizeof(*soc_dai));
+       if (!of_property_read_u32(node, "rockchip,playback-channels", &val)) {
+               if (val >= 2 && val <= 8)
+                       soc_dai->playback.channels_max = val;
+       }
+
        if (!of_property_read_u32(node, "rockchip,capture-channels", &val)) {
                if (val >= 2 && val <= 8)
-                       rockchip_i2s_dai.capture.channels_max = val;
-               else
-                       rockchip_i2s_dai.capture.channels_max = 2;
+                       soc_dai->capture.channels_max = val;
        }
 
        ret = devm_snd_soc_register_component(&pdev->dev,
                                              &rockchip_i2s_component,
-                                             &rockchip_i2s_dai, 1);
+                                             soc_dai, 1);
+
        if (ret) {
                dev_err(&pdev->dev, "Could not register DAI\n");
                goto err_suspend;
index 26567b10393a5074e8d9b217f2dcd700834420dd..543610282cdb05c007b5fbe52b0c2f77435b3a83 100644 (file)
@@ -80,11 +80,17 @@ static int rk_aif1_hw_params(struct snd_pcm_substream *substream,
        switch (params_rate(params)) {
        case 8000:
        case 16000:
+       case 24000:
+       case 32000:
        case 48000:
+       case 64000:
        case 96000:
                mclk = 12288000;
                break;
+       case 11025:
+       case 22050:
        case 44100:
+       case 88200:
                mclk = 11289600;
                break;
        default:
index 68c62e4c23168a1e9e8656956ee9b83584892d18..440a8026346a3ed4004ed744f9600049c1c82a12 100644 (file)
@@ -79,11 +79,17 @@ static int rk_aif1_hw_params(struct snd_pcm_substream *substream,
        switch (params_rate(params)) {
        case 8000:
        case 16000:
+       case 24000:
+       case 32000:
        case 48000:
+       case 64000:
        case 96000:
                mclk = 12288000;
                break;
+       case 11025:
+       case 22050:
        case 44100:
+       case 88200:
                mclk = 11289600;
                break;
        default:
index a38a3029062c8296581af1209a176b53dde29f7c..5a806da89f42b49967ea52d15eac0f3348b7b873 100644 (file)
@@ -152,8 +152,10 @@ static int rk_spdif_trigger(struct snd_pcm_substream *substream,
        case SNDRV_PCM_TRIGGER_RESUME:
        case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
                ret = regmap_update_bits(spdif->regmap, SPDIF_DMACR,
-                                  SPDIF_DMACR_TDE_ENABLE,
-                                  SPDIF_DMACR_TDE_ENABLE);
+                                  SPDIF_DMACR_TDE_ENABLE |
+                                  SPDIF_DMACR_TDL_MASK,
+                                  SPDIF_DMACR_TDE_ENABLE |
+                                  SPDIF_DMACR_TDL(16));
 
                if (ret != 0)
                        return ret;
@@ -280,7 +282,7 @@ static int rk_spdif_probe(struct platform_device *pdev)
        int ret;
 
        match = of_match_node(rk_spdif_match, np);
-       if ((int) match->data == RK_SPDIF_RK3288) {
+       if (match->data == (void *)RK_SPDIF_RK3288) {
                struct regmap *grf;
 
                grf = syscon_regmap_lookup_by_phandle(np, "rockchip,grf");
index 07f86a21046a524b32687f7252b54affa5fce1f7..3ef12770ae124d705d59b1916e5c400210aa0bf5 100644 (file)
@@ -28,9 +28,9 @@
 #define SPDIF_CFGR_VDW(x)      (x << SPDIF_CFGR_VDW_SHIFT)
 #define SDPIF_CFGR_VDW_MASK    (0xf << SPDIF_CFGR_VDW_SHIFT)
 
-#define SPDIF_CFGR_VDW_16      SPDIF_CFGR_VDW(0x00)
-#define SPDIF_CFGR_VDW_20      SPDIF_CFGR_VDW(0x01)
-#define SPDIF_CFGR_VDW_24      SPDIF_CFGR_VDW(0x10)
+#define SPDIF_CFGR_VDW_16      SPDIF_CFGR_VDW(0x0)
+#define SPDIF_CFGR_VDW_20      SPDIF_CFGR_VDW(0x1)
+#define SPDIF_CFGR_VDW_24      SPDIF_CFGR_VDW(0x2)
 
 /*
  * DMACR
@@ -42,7 +42,7 @@
 
 #define SPDIF_DMACR_TDL_SHIFT  0
 #define SPDIF_DMACR_TDL(x)     ((x) << SPDIF_DMACR_TDL_SHIFT)
-#define SPDIF_DMACR_TDL_MASK   (0x1f << SDPIF_DMACR_TDL_SHIFT)
+#define SPDIF_DMACR_TDL_MASK   (0x1f << SPDIF_DMACR_TDL_SHIFT)
 
 /*
  * XFER
index 3744c9ed537041f6c14c005bd71977d51d4cc375..78baa26e938b5e783d4c5babdfeb3ec7914b5770 100644 (file)
@@ -1,8 +1,6 @@
 config SND_SOC_SAMSUNG
        tristate "ASoC support for Samsung"
        depends on (PLAT_SAMSUNG || ARCH_EXYNOS)
-       depends on S3C64XX_PL080 || !ARCH_S3C64XX
-       depends on S3C24XX_DMAC || !ARCH_S3C24XX
        select SND_SOC_GENERIC_DMAENGINE_PCM
        help
          Say Y or M if you want to add support for codecs attached to
index e4145509d63cb36fdec39069a9b487c9e16ee3c5..4a7a503fe13c121ea55c046772a5c43d4f1349f3 100644 (file)
@@ -324,7 +324,7 @@ static const struct snd_soc_component_driver s3c_ac97_component = {
 
 static int s3c_ac97_probe(struct platform_device *pdev)
 {
-       struct resource *mem_res, *dmatx_res, *dmarx_res, *dmamic_res, *irq_res;
+       struct resource *mem_res, *irq_res;
        struct s3c_audio_pdata *ac97_pdata;
        int ret;
 
@@ -335,24 +335,6 @@ static int s3c_ac97_probe(struct platform_device *pdev)
        }
 
        /* Check for availability of necessary resource */
-       dmatx_res = platform_get_resource(pdev, IORESOURCE_DMA, 0);
-       if (!dmatx_res) {
-               dev_err(&pdev->dev, "Unable to get AC97-TX dma resource\n");
-               return -ENXIO;
-       }
-
-       dmarx_res = platform_get_resource(pdev, IORESOURCE_DMA, 1);
-       if (!dmarx_res) {
-               dev_err(&pdev->dev, "Unable to get AC97-RX dma resource\n");
-               return -ENXIO;
-       }
-
-       dmamic_res = platform_get_resource(pdev, IORESOURCE_DMA, 2);
-       if (!dmamic_res) {
-               dev_err(&pdev->dev, "Unable to get AC97-MIC dma resource\n");
-               return -ENXIO;
-       }
-
        irq_res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
        if (!irq_res) {
                dev_err(&pdev->dev, "AC97 IRQ not provided!\n");
@@ -364,11 +346,11 @@ static int s3c_ac97_probe(struct platform_device *pdev)
        if (IS_ERR(s3c_ac97.regs))
                return PTR_ERR(s3c_ac97.regs);
 
-       s3c_ac97_pcm_out.channel = dmatx_res->start;
+       s3c_ac97_pcm_out.slave = ac97_pdata->dma_playback;
        s3c_ac97_pcm_out.dma_addr = mem_res->start + S3C_AC97_PCM_DATA;
-       s3c_ac97_pcm_in.channel = dmarx_res->start;
+       s3c_ac97_pcm_in.slave = ac97_pdata->dma_capture;
        s3c_ac97_pcm_in.dma_addr = mem_res->start + S3C_AC97_PCM_DATA;
-       s3c_ac97_mic_in.channel = dmamic_res->start;
+       s3c_ac97_mic_in.slave = ac97_pdata->dma_capture_mic;
        s3c_ac97_mic_in.dma_addr = mem_res->start + S3C_AC97_MIC_DATA;
 
        init_completion(&s3c_ac97.done);
@@ -406,7 +388,8 @@ static int s3c_ac97_probe(struct platform_device *pdev)
        if (ret)
                goto err5;
 
-       ret = samsung_asoc_dma_platform_register(&pdev->dev);
+       ret = samsung_asoc_dma_platform_register(&pdev->dev,
+                                                ac97_pdata->dma_filter);
        if (ret) {
                dev_err(&pdev->dev, "failed to get register DMA: %d\n", ret);
                goto err5;
index e5f05e62fa3c11f4fd3bf7f2465f353dd2b863c4..3dd246fa0059db268bb5d035829c85f78315f65e 100644 (file)
@@ -58,11 +58,16 @@ static int bells_set_bias_level(struct snd_soc_card *card,
                                struct snd_soc_dapm_context *dapm,
                                enum snd_soc_bias_level level)
 {
-       struct snd_soc_dai *codec_dai = card->rtd[DAI_DSP_CODEC].codec_dai;
-       struct snd_soc_codec *codec = codec_dai->codec;
+       struct snd_soc_pcm_runtime *rtd;
+       struct snd_soc_dai *codec_dai;
+       struct snd_soc_codec *codec;
        struct bells_drvdata *bells = card->drvdata;
        int ret;
 
+       rtd = snd_soc_get_pcm_runtime(card, card->dai_link[DAI_DSP_CODEC].name);
+       codec_dai = rtd->codec_dai;
+       codec = codec_dai->codec;
+
        if (dapm->dev != codec_dai->dev)
                return 0;
 
@@ -99,11 +104,16 @@ static int bells_set_bias_level_post(struct snd_soc_card *card,
                                     struct snd_soc_dapm_context *dapm,
                                     enum snd_soc_bias_level level)
 {
-       struct snd_soc_dai *codec_dai = card->rtd[DAI_DSP_CODEC].codec_dai;
-       struct snd_soc_codec *codec = codec_dai->codec;
+       struct snd_soc_pcm_runtime *rtd;
+       struct snd_soc_dai *codec_dai;
+       struct snd_soc_codec *codec;
        struct bells_drvdata *bells = card->drvdata;
        int ret;
 
+       rtd = snd_soc_get_pcm_runtime(card, card->dai_link[DAI_DSP_CODEC].name);
+       codec_dai = rtd->codec_dai;
+       codec = codec_dai->codec;
+
        if (dapm->dev != codec_dai->dev)
                return 0;
 
@@ -137,14 +147,22 @@ static int bells_set_bias_level_post(struct snd_soc_card *card,
 static int bells_late_probe(struct snd_soc_card *card)
 {
        struct bells_drvdata *bells = card->drvdata;
-       struct snd_soc_codec *wm0010 = card->rtd[DAI_AP_DSP].codec;
-       struct snd_soc_codec *codec = card->rtd[DAI_DSP_CODEC].codec;
-       struct snd_soc_dai *aif1_dai = card->rtd[DAI_DSP_CODEC].codec_dai;
+       struct snd_soc_pcm_runtime *rtd;
+       struct snd_soc_codec *wm0010;
+       struct snd_soc_codec *codec;
+       struct snd_soc_dai *aif1_dai;
        struct snd_soc_dai *aif2_dai;
        struct snd_soc_dai *aif3_dai;
        struct snd_soc_dai *wm9081_dai;
        int ret;
 
+       rtd = snd_soc_get_pcm_runtime(card, card->dai_link[DAI_AP_DSP].name);
+       wm0010 = rtd->codec;
+
+       rtd = snd_soc_get_pcm_runtime(card, card->dai_link[DAI_DSP_CODEC].name);
+       codec = rtd->codec;
+       aif1_dai = rtd->codec_dai;
+
        ret = snd_soc_codec_set_sysclk(codec, ARIZONA_CLK_SYSCLK,
                                       ARIZONA_CLK_SRC_FLL1,
                                       bells->sysclk_rate,
@@ -181,7 +199,8 @@ static int bells_late_probe(struct snd_soc_card *card)
                return ret;
        }
 
-       aif2_dai = card->rtd[DAI_CODEC_CP].cpu_dai;
+       rtd = snd_soc_get_pcm_runtime(card, card->dai_link[DAI_CODEC_CP].name);
+       aif2_dai = rtd->cpu_dai;
 
        ret = snd_soc_dai_set_sysclk(aif2_dai, ARIZONA_CLK_ASYNCCLK, 0, 0);
        if (ret != 0) {
@@ -192,8 +211,9 @@ static int bells_late_probe(struct snd_soc_card *card)
        if (card->num_rtd == DAI_CODEC_SUB)
                return 0;
 
-       aif3_dai = card->rtd[DAI_CODEC_SUB].cpu_dai;
-       wm9081_dai = card->rtd[DAI_CODEC_SUB].codec_dai;
+       rtd = snd_soc_get_pcm_runtime(card, card->dai_link[DAI_CODEC_SUB].name);
+       aif3_dai = rtd->cpu_dai;
+       wm9081_dai = rtd->codec_dai;
 
        ret = snd_soc_dai_set_sysclk(aif3_dai, ARIZONA_CLK_SYSCLK, 0, 0);
        if (ret != 0) {
index 0e85dcfec02347eed1c4ee88fbf3c79a9f0cb675..a7616cc9b39ee5a59221ddaaf5ed61859d253234 100644 (file)
 #define _S3C_AUDIO_H
 
 #include <sound/dmaengine_pcm.h>
+#include <linux/dmaengine.h>
 
 struct s3c_dma_params {
-       int channel;                            /* Channel ID */
+       void *slave;                            /* Channel ID */
        dma_addr_t dma_addr;
        int dma_size;                   /* Size of the DMA transfer */
        char *ch_name;
@@ -25,6 +26,7 @@ struct s3c_dma_params {
 void samsung_asoc_init_dma_data(struct snd_soc_dai *dai,
                                struct s3c_dma_params *playback,
                                struct s3c_dma_params *capture);
-int samsung_asoc_dma_platform_register(struct device *dev);
+int samsung_asoc_dma_platform_register(struct device *dev,
+                                      dma_filter_fn fn);
 
 #endif
index 506f5bf6d08265e6ff456cd9ca8a26d6782d4055..063125937311e9600f063a3cc8ddac308e876c7f 100644 (file)
 
 #include "dma.h"
 
-#ifdef CONFIG_ARCH_S3C64XX
-#define filter_fn pl08x_filter_id
-#elif defined(CONFIG_ARCH_S3C24XX)
-#define filter_fn s3c24xx_dma_filter
-#else
-#define filter_fn NULL
-#endif
-
-static const struct snd_dmaengine_pcm_config samsung_dmaengine_pcm_config = {
+static struct snd_dmaengine_pcm_config samsung_dmaengine_pcm_config = {
        .prepare_slave_config = snd_dmaengine_pcm_prepare_slave_config,
-       .compat_filter_fn = filter_fn,
 };
 
 void samsung_asoc_init_dma_data(struct snd_soc_dai *dai,
@@ -50,14 +41,14 @@ void samsung_asoc_init_dma_data(struct snd_soc_dai *dai,
 
        if (playback) {
                playback_data = &playback->dma_data;
-               playback_data->filter_data = (void *)playback->channel;
+               playback_data->filter_data = playback->slave;
                playback_data->chan_name = playback->ch_name;
                playback_data->addr = playback->dma_addr;
                playback_data->addr_width = playback->dma_size;
        }
        if (capture) {
                capture_data = &capture->dma_data;
-               capture_data->filter_data = (void *)capture->channel;
+               capture_data->filter_data = capture->slave;
                capture_data->chan_name = capture->ch_name;
                capture_data->addr = capture->dma_addr;
                capture_data->addr_width = capture->dma_size;
@@ -67,8 +58,11 @@ void samsung_asoc_init_dma_data(struct snd_soc_dai *dai,
 }
 EXPORT_SYMBOL_GPL(samsung_asoc_init_dma_data);
 
-int samsung_asoc_dma_platform_register(struct device *dev)
+int samsung_asoc_dma_platform_register(struct device *dev,
+                                      dma_filter_fn filter)
 {
+       samsung_dmaengine_pcm_config.compat_filter_fn = filter;
+
        return devm_snd_dmaengine_pcm_register(dev,
                        &samsung_dmaengine_pcm_config,
                        SND_DMAENGINE_PCM_FLAG_CUSTOM_CHANNEL_NAME |
index ea4ab374a2231d8a79799e821a90b6a759c2291e..84d9e77c0fbe1e8d5e737d26beb492c3ce85883b 100644 (file)
@@ -89,6 +89,7 @@ struct i2s_dai {
        struct s3c_dma_params dma_playback;
        struct s3c_dma_params dma_capture;
        struct s3c_dma_params idma_playback;
+       dma_filter_fn filter;
        u32     quirks;
        u32     suspend_i2smod;
        u32     suspend_i2scon;
@@ -1244,7 +1245,8 @@ static int samsung_i2s_probe(struct platform_device *pdev)
                if (ret != 0)
                        return ret;
 
-               return samsung_asoc_dma_platform_register(&pdev->dev);
+               return samsung_asoc_dma_platform_register(&pdev->dev,
+                                                         sec_dai->filter);
        }
 
        pri_dai = i2s_alloc_dai(pdev, false);
@@ -1257,27 +1259,15 @@ static int samsung_i2s_probe(struct platform_device *pdev)
        pri_dai->lock = &pri_dai->spinlock;
 
        if (!np) {
-               res = platform_get_resource(pdev, IORESOURCE_DMA, 0);
-               if (!res) {
-                       dev_err(&pdev->dev,
-                               "Unable to get I2S-TX dma resource\n");
-                       return -ENXIO;
-               }
-               pri_dai->dma_playback.channel = res->start;
-
-               res = platform_get_resource(pdev, IORESOURCE_DMA, 1);
-               if (!res) {
-                       dev_err(&pdev->dev,
-                               "Unable to get I2S-RX dma resource\n");
-                       return -ENXIO;
-               }
-               pri_dai->dma_capture.channel = res->start;
-
                if (i2s_pdata == NULL) {
                        dev_err(&pdev->dev, "Can't work without s3c_audio_pdata\n");
                        return -EINVAL;
                }
 
+               pri_dai->dma_playback.slave = i2s_pdata->dma_playback;
+               pri_dai->dma_capture.slave = i2s_pdata->dma_capture;
+               pri_dai->filter = i2s_pdata->dma_filter;
+
                if (&i2s_pdata->type)
                        i2s_cfg = &i2s_pdata->type.i2s;
 
@@ -1339,9 +1329,8 @@ static int samsung_i2s_probe(struct platform_device *pdev)
                sec_dai->dma_playback.ch_name = "tx-sec";
 
                if (!np) {
-                       res = platform_get_resource(pdev, IORESOURCE_DMA, 2);
-                       if (res)
-                               sec_dai->dma_playback.channel = res->start;
+                       sec_dai->dma_playback.slave = i2s_pdata->dma_play_sec;
+                       sec_dai->filter = i2s_pdata->dma_filter;
                }
 
                sec_dai->dma_playback.dma_size = 4;
@@ -1364,7 +1353,7 @@ static int samsung_i2s_probe(struct platform_device *pdev)
 
        pm_runtime_enable(&pdev->dev);
 
-       ret = samsung_asoc_dma_platform_register(&pdev->dev);
+       ret = samsung_asoc_dma_platform_register(&pdev->dev, pri_dai->filter);
        if (ret != 0)
                return ret;
 
index 31a820eb0ac37b52992cbc986a17ce11d3c42ca1..7cb204e649cabba1fb15c9f4ec9c02b0f9732789 100644 (file)
@@ -23,9 +23,13 @@ static int littlemill_set_bias_level(struct snd_soc_card *card,
                                          struct snd_soc_dapm_context *dapm,
                                          enum snd_soc_bias_level level)
 {
-       struct snd_soc_dai *aif1_dai = card->rtd[0].codec_dai;
+       struct snd_soc_pcm_runtime *rtd;
+       struct snd_soc_dai *aif1_dai;
        int ret;
 
+       rtd = snd_soc_get_pcm_runtime(card, card->dai_link[0].name);
+       aif1_dai = rtd->codec_dai;
+
        if (dapm->dev != aif1_dai->dev)
                return 0;
 
@@ -66,9 +70,13 @@ static int littlemill_set_bias_level_post(struct snd_soc_card *card,
                                               struct snd_soc_dapm_context *dapm,
                                               enum snd_soc_bias_level level)
 {
-       struct snd_soc_dai *aif1_dai = card->rtd[0].codec_dai;
+       struct snd_soc_pcm_runtime *rtd;
+       struct snd_soc_dai *aif1_dai;
        int ret;
 
+       rtd = snd_soc_get_pcm_runtime(card, card->dai_link[0].name);
+       aif1_dai = rtd->codec_dai;
+
        if (dapm->dev != aif1_dai->dev)
                return 0;
 
@@ -168,9 +176,13 @@ static int bbclk_ev(struct snd_soc_dapm_widget *w,
                    struct snd_kcontrol *kcontrol, int event)
 {
        struct snd_soc_card *card = w->dapm->card;
-       struct snd_soc_dai *aif2_dai = card->rtd[1].cpu_dai;
+       struct snd_soc_pcm_runtime *rtd;
+       struct snd_soc_dai *aif2_dai;
        int ret;
 
+       rtd = snd_soc_get_pcm_runtime(card, card->dai_link[1].name);
+       aif2_dai = rtd->cpu_dai;
+
        switch (event) {
        case SND_SOC_DAPM_PRE_PMU:
                ret = snd_soc_dai_set_pll(aif2_dai, WM8994_FLL2,
@@ -245,11 +257,19 @@ static struct snd_soc_jack littlemill_headset;
 
 static int littlemill_late_probe(struct snd_soc_card *card)
 {
-       struct snd_soc_codec *codec = card->rtd[0].codec;
-       struct snd_soc_dai *aif1_dai = card->rtd[0].codec_dai;
-       struct snd_soc_dai *aif2_dai = card->rtd[1].cpu_dai;
+       struct snd_soc_pcm_runtime *rtd;
+       struct snd_soc_codec *codec;
+       struct snd_soc_dai *aif1_dai;
+       struct snd_soc_dai *aif2_dai;
        int ret;
 
+       rtd = snd_soc_get_pcm_runtime(card, card->dai_link[0].name);
+       codec = rtd->codec;
+       aif1_dai = rtd->codec_dai;
+
+       rtd = snd_soc_get_pcm_runtime(card, card->dai_link[1].name);
+       aif2_dai = rtd->cpu_dai;
+
        ret = snd_soc_dai_set_sysclk(aif1_dai, WM8994_SYSCLK_MCLK2,
                                     32768, SND_SOC_CLOCK_IN);
        if (ret < 0)
index 596f1180a3698627844a0e8746e8d64bf0441f47..04217279fe258934e4d1614f39816856a2eb5165 100644 (file)
@@ -25,10 +25,15 @@ static struct snd_soc_dai_link odroidx2_dai[];
 
 static int odroidx2_late_probe(struct snd_soc_card *card)
 {
-       struct snd_soc_dai *codec_dai = card->rtd[0].codec_dai;
-       struct snd_soc_dai *cpu_dai = card->rtd[0].cpu_dai;
+       struct snd_soc_pcm_runtime *rtd;
+       struct snd_soc_dai *codec_dai;
+       struct snd_soc_dai *cpu_dai;
        int ret;
 
+       rtd = snd_soc_get_pcm_runtime(card, card->dai_link[0].name);
+       codec_dai = rtd->codec_dai;
+       cpu_dai = rtd->cpu_dai;
+
        ret = snd_soc_dai_set_sysclk(codec_dai, 0, MAX98090_MCLK,
                                                SND_SOC_CLOCK_IN);
 
index b320a9d3fbf82f6b49b9d6a8509c302c9a3ac86c..498f563a4c9cb2e7fb483c05f367ef348370bb5d 100644 (file)
@@ -486,8 +486,9 @@ static const struct snd_soc_component_driver s3c_pcm_component = {
 static int s3c_pcm_dev_probe(struct platform_device *pdev)
 {
        struct s3c_pcm_info *pcm;
-       struct resource *mem_res, *dmatx_res, *dmarx_res;
+       struct resource *mem_res;
        struct s3c_audio_pdata *pcm_pdata;
+       dma_filter_fn filter;
        int ret;
 
        /* Check for valid device index */
@@ -499,18 +500,6 @@ static int s3c_pcm_dev_probe(struct platform_device *pdev)
        pcm_pdata = pdev->dev.platform_data;
 
        /* Check for availability of necessary resource */
-       dmatx_res = platform_get_resource(pdev, IORESOURCE_DMA, 0);
-       if (!dmatx_res) {
-               dev_err(&pdev->dev, "Unable to get PCM-TX dma resource\n");
-               return -ENXIO;
-       }
-
-       dmarx_res = platform_get_resource(pdev, IORESOURCE_DMA, 1);
-       if (!dmarx_res) {
-               dev_err(&pdev->dev, "Unable to get PCM-RX dma resource\n");
-               return -ENXIO;
-       }
-
        mem_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
        if (!mem_res) {
                dev_err(&pdev->dev, "Unable to get register resource\n");
@@ -568,8 +557,12 @@ static int s3c_pcm_dev_probe(struct platform_device *pdev)
        s3c_pcm_stereo_out[pdev->id].dma_addr = mem_res->start
                                                        + S3C_PCM_TXFIFO;
 
-       s3c_pcm_stereo_in[pdev->id].channel = dmarx_res->start;
-       s3c_pcm_stereo_out[pdev->id].channel = dmatx_res->start;
+       filter = NULL;
+       if (pcm_pdata) {
+               s3c_pcm_stereo_in[pdev->id].slave = pcm_pdata->dma_capture;
+               s3c_pcm_stereo_out[pdev->id].slave = pcm_pdata->dma_playback;
+               filter = pcm_pdata->dma_filter;
+       }
 
        pcm->dma_capture = &s3c_pcm_stereo_in[pdev->id];
        pcm->dma_playback = &s3c_pcm_stereo_out[pdev->id];
@@ -583,7 +576,7 @@ static int s3c_pcm_dev_probe(struct platform_device *pdev)
                goto err5;
        }
 
-       ret = samsung_asoc_dma_platform_register(&pdev->dev);
+       ret = samsung_asoc_dma_platform_register(&pdev->dev, filter);
        if (ret) {
                dev_err(&pdev->dev, "failed to get register DMA: %d\n", ret);
                goto err5;
index 2b766d212ce0796a7dd5c9b54b7ad09668e0be02..204029d12f5b2f639f487ffe6ef591636fdf4746 100644 (file)
@@ -25,7 +25,6 @@
 #include <sound/soc.h>
 #include <sound/pcm_params.h>
 
-#include <mach/dma.h>
 #include <mach/gpio-samsung.h>
 #include <plat/gpio-cfg.h>
 
 #include "regs-i2s-v2.h"
 #include "s3c2412-i2s.h"
 
+#include <linux/platform_data/asoc-s3c.h>
+
 static struct s3c_dma_params s3c2412_i2s_pcm_stereo_out = {
-       .channel        = DMACH_I2S_OUT,
        .ch_name        = "tx",
        .dma_size       = 4,
 };
 
 static struct s3c_dma_params s3c2412_i2s_pcm_stereo_in = {
-       .channel        = DMACH_I2S_IN,
        .ch_name        = "rx",
        .dma_size       = 4,
 };
@@ -152,6 +151,12 @@ static int s3c2412_iis_dev_probe(struct platform_device *pdev)
 {
        int ret = 0;
        struct resource *res;
+       struct s3c_audio_pdata *pdata = dev_get_platdata(&pdev->dev);
+
+       if (!pdata) {
+               dev_err(&pdev->dev, "missing platform data");
+               return -ENXIO;
+       }
 
        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
        s3c2412_i2s.regs = devm_ioremap_resource(&pdev->dev, res);
@@ -159,7 +164,9 @@ static int s3c2412_iis_dev_probe(struct platform_device *pdev)
                return PTR_ERR(s3c2412_i2s.regs);
 
        s3c2412_i2s_pcm_stereo_out.dma_addr = res->start + S3C2412_IISTXD;
+       s3c2412_i2s_pcm_stereo_out.slave = pdata->dma_playback;
        s3c2412_i2s_pcm_stereo_in.dma_addr = res->start + S3C2412_IISRXD;
+       s3c2412_i2s_pcm_stereo_in.slave = pdata->dma_capture;
 
        ret = s3c_i2sv2_register_component(&pdev->dev, -1,
                                           &s3c2412_i2s_component,
@@ -169,7 +176,8 @@ static int s3c2412_iis_dev_probe(struct platform_device *pdev)
                return ret;
        }
 
-       ret = samsung_asoc_dma_platform_register(&pdev->dev);
+       ret = samsung_asoc_dma_platform_register(&pdev->dev,
+                                                pdata->dma_filter);
        if (ret)
                pr_err("failed to register the DMA: %d\n", ret);
 
index 5bf723689692fc52ffc5edce20f82e8d5cb4fc21..b3a475d73ba790c6d67bc21ebd271950e3c36f2c 100644 (file)
@@ -23,7 +23,6 @@
 #include <sound/soc.h>
 #include <sound/pcm_params.h>
 
-#include <mach/dma.h>
 #include <mach/gpio-samsung.h>
 #include <plat/gpio-cfg.h>
 #include "regs-iis.h"
 #include "dma.h"
 #include "s3c24xx-i2s.h"
 
+#include <linux/platform_data/asoc-s3c.h>
+
 static struct s3c_dma_params s3c24xx_i2s_pcm_stereo_out = {
-       .channel        = DMACH_I2S_OUT,
        .ch_name        = "tx",
        .dma_size       = 2,
 };
 
 static struct s3c_dma_params s3c24xx_i2s_pcm_stereo_in = {
-       .channel        = DMACH_I2S_IN,
        .ch_name        = "rx",
        .dma_size       = 2,
 };
@@ -454,6 +453,12 @@ static int s3c24xx_iis_dev_probe(struct platform_device *pdev)
 {
        int ret = 0;
        struct resource *res;
+       struct s3c_audio_pdata *pdata = dev_get_platdata(&pdev->dev);
+
+       if (!pdata) {
+               dev_err(&pdev->dev, "missing platform data");
+               return -ENXIO;
+       }
 
        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
        if (!res) {
@@ -465,7 +470,9 @@ static int s3c24xx_iis_dev_probe(struct platform_device *pdev)
                return PTR_ERR(s3c24xx_i2s.regs);
 
        s3c24xx_i2s_pcm_stereo_out.dma_addr = res->start + S3C2410_IISFIFO;
+       s3c24xx_i2s_pcm_stereo_out.slave = pdata->dma_playback;
        s3c24xx_i2s_pcm_stereo_in.dma_addr = res->start + S3C2410_IISFIFO;
+       s3c24xx_i2s_pcm_stereo_in.slave = pdata->dma_capture;
 
        ret = devm_snd_soc_register_component(&pdev->dev,
                        &s3c24xx_i2s_component, &s3c24xx_i2s_dai, 1);
@@ -474,7 +481,8 @@ static int s3c24xx_iis_dev_probe(struct platform_device *pdev)
                return ret;
        }
 
-       ret = samsung_asoc_dma_platform_register(&pdev->dev);
+       ret = samsung_asoc_dma_platform_register(&pdev->dev,
+                                                pdata->dma_filter);
        if (ret)
                pr_err("failed to register the dma: %d\n", ret);
 
index 07ce2cfa484503af827c19c478d2f123830126d9..d8ac907bbb0d76c2df3ca9900b1ae05b1140faa2 100644 (file)
@@ -35,10 +35,15 @@ static struct snd_soc_dai_link snow_dai[] = {
 
 static int snow_late_probe(struct snd_soc_card *card)
 {
-       struct snd_soc_dai *codec_dai = card->rtd[0].codec_dai;
-       struct snd_soc_dai *cpu_dai = card->rtd[0].cpu_dai;
+       struct snd_soc_pcm_runtime *rtd;
+       struct snd_soc_dai *codec_dai;
+       struct snd_soc_dai *cpu_dai;
        int ret;
 
+       rtd = snd_soc_get_pcm_runtime(card, card->dai_link[0].name);
+       codec_dai = rtd->codec_dai;
+       cpu_dai = rtd->cpu_dai;
+
        /* Set the MCLK rate for the codec */
        ret = snd_soc_dai_set_sysclk(codec_dai, 0,
                                        FIN_PLL_RATE, SND_SOC_CLOCK_IN);
index 36dbc0e96004095d1617d9a355af620e124567a9..4687f521197c5c46a7255873e94f9b0d67215d9a 100644 (file)
@@ -359,20 +359,15 @@ static const struct snd_soc_component_driver samsung_spdif_component = {
 static int spdif_probe(struct platform_device *pdev)
 {
        struct s3c_audio_pdata *spdif_pdata;
-       struct resource *mem_res, *dma_res;
+       struct resource *mem_res;
        struct samsung_spdif_info *spdif;
+       dma_filter_fn filter;
        int ret;
 
        spdif_pdata = pdev->dev.platform_data;
 
        dev_dbg(&pdev->dev, "Entered %s\n", __func__);
 
-       dma_res = platform_get_resource(pdev, IORESOURCE_DMA, 0);
-       if (!dma_res) {
-               dev_err(&pdev->dev, "Unable to get dma resource.\n");
-               return -ENXIO;
-       }
-
        mem_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
        if (!mem_res) {
                dev_err(&pdev->dev, "Unable to get register resource.\n");
@@ -432,11 +427,15 @@ static int spdif_probe(struct platform_device *pdev)
 
        spdif_stereo_out.dma_size = 2;
        spdif_stereo_out.dma_addr = mem_res->start + DATA_OUTBUF;
-       spdif_stereo_out.channel = dma_res->start;
+       filter = NULL;
+       if (spdif_pdata) {
+               spdif_stereo_out.slave = spdif_pdata->dma_playback;
+               filter = spdif_pdata->dma_filter;
+       }
 
        spdif->dma_playback = &spdif_stereo_out;
 
-       ret = samsung_asoc_dma_platform_register(&pdev->dev);
+       ret = samsung_asoc_dma_platform_register(&pdev->dev, filter);
        if (ret) {
                dev_err(&pdev->dev, "failed to register DMA: %d\n", ret);
                goto err4;
index d1ae21c5e25320e525a8431639e811e47c264a4e..083ef5e21b17f26b710de3bdf0c2523cf3e613f8 100644 (file)
@@ -25,9 +25,13 @@ static int speyside_set_bias_level(struct snd_soc_card *card,
                                   struct snd_soc_dapm_context *dapm,
                                   enum snd_soc_bias_level level)
 {
-       struct snd_soc_dai *codec_dai = card->rtd[1].codec_dai;
+       struct snd_soc_pcm_runtime *rtd;
+       struct snd_soc_dai *codec_dai;
        int ret;
 
+       rtd = snd_soc_get_pcm_runtime(card, card->dai_link[1].name);
+       codec_dai = rtd->codec_dai;
+
        if (dapm->dev != codec_dai->dev)
                return 0;
 
@@ -57,9 +61,13 @@ static int speyside_set_bias_level_post(struct snd_soc_card *card,
                                        struct snd_soc_dapm_context *dapm,
                                        enum snd_soc_bias_level level)
 {
-       struct snd_soc_dai *codec_dai = card->rtd[1].codec_dai;
+       struct snd_soc_pcm_runtime *rtd;
+       struct snd_soc_dai *codec_dai;
        int ret;
 
+       rtd = snd_soc_get_pcm_runtime(card, card->dai_link[1].name);
+       codec_dai = rtd->codec_dai;
+
        if (dapm->dev != codec_dai->dev)
                return 0;
 
index 85ccfb7188cb2d4b36101f14d0fa3dc024436f6f..3310eda7cf53b378c646b7dcdf83d66eb6c06baf 100644 (file)
@@ -23,9 +23,13 @@ static int tobermory_set_bias_level(struct snd_soc_card *card,
                                          struct snd_soc_dapm_context *dapm,
                                          enum snd_soc_bias_level level)
 {
-       struct snd_soc_dai *codec_dai = card->rtd[0].codec_dai;
+       struct snd_soc_pcm_runtime *rtd;
+       struct snd_soc_dai *codec_dai;
        int ret;
 
+       rtd = snd_soc_get_pcm_runtime(card, card->dai_link[0].name);
+       codec_dai = rtd->codec_dai;
+
        if (dapm->dev != codec_dai->dev)
                return 0;
 
@@ -62,9 +66,13 @@ static int tobermory_set_bias_level_post(struct snd_soc_card *card,
                                               struct snd_soc_dapm_context *dapm,
                                               enum snd_soc_bias_level level)
 {
-       struct snd_soc_dai *codec_dai = card->rtd[0].codec_dai;
+       struct snd_soc_pcm_runtime *rtd;
+       struct snd_soc_dai *codec_dai;
        int ret;
 
+       rtd = snd_soc_get_pcm_runtime(card, card->dai_link[0].name);
+       codec_dai = rtd->codec_dai;
+
        if (dapm->dev != codec_dai->dev)
                return 0;
 
@@ -170,10 +178,15 @@ static struct snd_soc_jack_pin tobermory_headset_pins[] = {
 
 static int tobermory_late_probe(struct snd_soc_card *card)
 {
-       struct snd_soc_codec *codec = card->rtd[0].codec;
-       struct snd_soc_dai *codec_dai = card->rtd[0].codec_dai;
+       struct snd_soc_pcm_runtime *rtd;
+       struct snd_soc_codec *codec;
+       struct snd_soc_dai *codec_dai;
        int ret;
 
+       rtd = snd_soc_get_pcm_runtime(card, card->dai_link[0].name);
+       codec = rtd->codec;
+       codec_dai = rtd->codec_dai;
+
        ret = snd_soc_dai_set_sysclk(codec_dai, WM8962_SYSCLK_MCLK,
                                     32768, SND_SOC_CLOCK_IN);
        if (ret < 0)
index 206d1edab07c1f8a8c91c1b69363b3bc057d38ec..c9902a6d6fa0b6a903a77c8dd6dd1ee46b0db160 100644 (file)
@@ -36,7 +36,6 @@ config SND_SOC_SH4_SIU
 
 config SND_SOC_RCAR
        tristate "R-Car series SRU/SCU/SSIU/SSI support"
-       depends on DMA_OF
        depends on COMMON_CLK
        select SND_SIMPLE_CARD
        select REGMAP_MMIO
index 0215c78cbddf5491712c9e4d9bbcdb8e1229fa10..ead520182e2684fb4c8109f913e4148ecb4b2227 100644 (file)
@@ -1362,15 +1362,18 @@ static int fsi_dma_push_start_stop(struct fsi_priv *fsi, struct fsi_stream *io,
 
 static int fsi_dma_probe(struct fsi_priv *fsi, struct fsi_stream *io, struct device *dev)
 {
-       dma_cap_mask_t mask;
        int is_play = fsi_stream_is_play(fsi, io);
 
+#ifdef CONFIG_SUPERH
+       dma_cap_mask_t mask;
        dma_cap_zero(mask);
        dma_cap_set(DMA_SLAVE, mask);
 
-       io->chan = dma_request_slave_channel_compat(mask,
-                               shdma_chan_filter, (void *)io->dma_id,
-                               dev, is_play ? "tx" : "rx");
+       io->chan = dma_request_channel(mask, shdma_chan_filter,
+                                      (void *)io->dma_id);
+#else
+       io->chan = dma_request_slave_channel(dev, is_play ? "tx" : "rx");
+#endif
        if (io->chan) {
                struct dma_slave_config cfg = {};
                int ret;
index 8b258501aa357e78630bdf73a4be091fa5fb1f6c..a89ddf75869531f17acfddafcf3fa895613c06aa 100644 (file)
@@ -1,4 +1,4 @@
-snd-soc-rcar-objs      := core.o gen.o dma.o adg.o ssi.o src.o ctu.o mix.o dvc.o
+snd-soc-rcar-objs      := core.o gen.o dma.o adg.o ssi.o ssiu.o src.o ctu.o mix.o dvc.o cmd.o
 obj-$(CONFIG_SND_SOC_RCAR)     += snd-soc-rcar.o
 
 snd-soc-rsrc-card-objs := rsrc-card.o
index 2a5b3a293cd243db3d4325b5f6a8e2b4e7041611..6d3ef366d53692c222b311662a83feb6a5b6d8e4 100644 (file)
@@ -68,8 +68,8 @@ static u32 rsnd_adg_calculate_rbgx(unsigned long div)
 
 static u32 rsnd_adg_ssi_ws_timing_gen2(struct rsnd_dai_stream *io)
 {
-       struct rsnd_mod *mod = rsnd_io_to_mod_ssi(io);
-       int id = rsnd_mod_id(mod);
+       struct rsnd_mod *ssi_mod = rsnd_io_to_mod_ssi(io);
+       int id = rsnd_mod_id(ssi_mod);
        int ws = id;
 
        if (rsnd_ssi_is_pin_sharing(io)) {
@@ -90,13 +90,13 @@ static u32 rsnd_adg_ssi_ws_timing_gen2(struct rsnd_dai_stream *io)
        return (0x6 + ws) << 8;
 }
 
-int rsnd_adg_set_cmd_timsel_gen2(struct rsnd_mod *mod,
+int rsnd_adg_set_cmd_timsel_gen2(struct rsnd_mod *cmd_mod,
                                 struct rsnd_dai_stream *io)
 {
-       struct rsnd_priv *priv = rsnd_mod_to_priv(mod);
+       struct rsnd_priv *priv = rsnd_mod_to_priv(cmd_mod);
        struct rsnd_adg *adg = rsnd_priv_to_adg(priv);
        struct rsnd_mod *adg_mod = rsnd_mod_get(adg);
-       int id = rsnd_mod_id(mod);
+       int id = rsnd_mod_id(cmd_mod);
        int shift = (id % 2) ? 16 : 0;
        u32 mask, val;
 
@@ -242,68 +242,6 @@ int rsnd_adg_set_convert_timing_gen2(struct rsnd_mod *src_mod,
        return rsnd_adg_set_src_timsel_gen2(src_mod, io, val);
 }
 
-int rsnd_adg_set_convert_clk_gen1(struct rsnd_priv *priv,
-                                 struct rsnd_mod *mod,
-                                 unsigned int src_rate,
-                                 unsigned int dst_rate)
-{
-       struct rsnd_adg *adg = rsnd_priv_to_adg(priv);
-       struct rsnd_mod *adg_mod = rsnd_mod_get(adg);
-       struct device *dev = rsnd_priv_to_dev(priv);
-       int idx, sel, div, shift;
-       u32 mask, val;
-       int id = rsnd_mod_id(mod);
-       unsigned int sel_rate [] = {
-               clk_get_rate(adg->clk[CLKA]),   /* 000: CLKA */
-               clk_get_rate(adg->clk[CLKB]),   /* 001: CLKB */
-               clk_get_rate(adg->clk[CLKC]),   /* 010: CLKC */
-               0,                              /* 011: MLBCLK (not used) */
-               adg->rbga_rate_for_441khz,      /* 100: RBGA */
-               adg->rbgb_rate_for_48khz,       /* 101: RBGB */
-       };
-
-       /* find div (= 1/128, 1/256, 1/512, 1/1024, 1/2048 */
-       for (sel = 0; sel < ARRAY_SIZE(sel_rate); sel++) {
-               for (div  = 128,        idx = 0;
-                    div <= 2048;
-                    div *= 2,          idx++) {
-                       if (src_rate == sel_rate[sel] / div) {
-                               val = (idx << 4) | sel;
-                               goto find_rate;
-                       }
-               }
-       }
-       dev_err(dev, "can't find convert src clk\n");
-       return -EINVAL;
-
-find_rate:
-       shift   = (id % 4) * 8;
-       mask    = 0xFF << shift;
-       val     = val << shift;
-
-       dev_dbg(dev, "adg convert src clk = %02x\n", val);
-
-       switch (id / 4) {
-       case 0:
-               rsnd_mod_bset(adg_mod, AUDIO_CLK_SEL3, mask, val);
-               break;
-       case 1:
-               rsnd_mod_bset(adg_mod, AUDIO_CLK_SEL4, mask, val);
-               break;
-       case 2:
-               rsnd_mod_bset(adg_mod, AUDIO_CLK_SEL5, mask, val);
-               break;
-       }
-
-       /*
-        * Gen1 doesn't need dst_rate settings,
-        * since it uses SSI WS pin.
-        * see also rsnd_src_set_route_if_gen1()
-        */
-
-       return 0;
-}
-
 static void rsnd_adg_set_ssi_clk(struct rsnd_mod *ssi_mod, u32 val)
 {
        struct rsnd_priv *priv = rsnd_mod_to_priv(ssi_mod);
@@ -337,20 +275,16 @@ static void rsnd_adg_set_ssi_clk(struct rsnd_mod *ssi_mod, u32 val)
        }
 }
 
-int rsnd_adg_ssi_clk_stop(struct rsnd_mod *mod)
+int rsnd_adg_ssi_clk_stop(struct rsnd_mod *ssi_mod)
 {
-       /*
-        * "mod" = "ssi" here.
-        * we can get "ssi id" from mod
-        */
-       rsnd_adg_set_ssi_clk(mod, 0);
+       rsnd_adg_set_ssi_clk(ssi_mod, 0);
 
        return 0;
 }
 
-int rsnd_adg_ssi_clk_try_start(struct rsnd_mod *mod, unsigned int rate)
+int rsnd_adg_ssi_clk_try_start(struct rsnd_mod *ssi_mod, unsigned int rate)
 {
-       struct rsnd_priv *priv = rsnd_mod_to_priv(mod);
+       struct rsnd_priv *priv = rsnd_mod_to_priv(ssi_mod);
        struct rsnd_adg *adg = rsnd_priv_to_adg(priv);
        struct device *dev = rsnd_priv_to_dev(priv);
        struct clk *clk;
@@ -394,14 +328,10 @@ int rsnd_adg_ssi_clk_try_start(struct rsnd_mod *mod, unsigned int rate)
 
 found_clock:
 
-       /*
-        * This "mod" = "ssi" here.
-        * we can get "ssi id" from mod
-        */
-       rsnd_adg_set_ssi_clk(mod, data);
+       rsnd_adg_set_ssi_clk(ssi_mod, data);
 
        dev_dbg(dev, "ADG: %s[%d] selects 0x%x for %d\n",
-               rsnd_mod_name(mod), rsnd_mod_id(mod),
+               rsnd_mod_name(ssi_mod), rsnd_mod_id(ssi_mod),
                data, rate);
 
        return 0;
@@ -418,15 +348,20 @@ static void rsnd_adg_get_clkin(struct rsnd_priv *priv,
                [CLKC]  = "clk_c",
                [CLKI]  = "clk_i",
        };
-       int i;
+       int i, ret;
 
        for (i = 0; i < CLKMAX; i++) {
                clk = devm_clk_get(dev, clk_name[i]);
                adg->clk[i] = IS_ERR(clk) ? NULL : clk;
        }
 
-       for_each_rsnd_clk(clk, adg, i)
+       for_each_rsnd_clk(clk, adg, i) {
+               ret = clk_prepare_enable(clk);
+               if (ret < 0)
+                       dev_warn(dev, "can't use clk %d\n", i);
+
                dev_dbg(dev, "clk %d : %p : %ld\n", i, clk, clk_get_rate(clk));
+       }
 }
 
 static void rsnd_adg_get_clkout(struct rsnd_priv *priv,
@@ -437,7 +372,7 @@ static void rsnd_adg_get_clkout(struct rsnd_priv *priv,
        struct device *dev = rsnd_priv_to_dev(priv);
        struct device_node *np = dev->of_node;
        u32 ckr, rbgx, rbga, rbgb;
-       u32 rate, req_rate, div;
+       u32 rate, req_rate = 0, div;
        uint32_t count = 0;
        unsigned long req_48kHz_rate, req_441kHz_rate;
        int i;
@@ -572,9 +507,7 @@ static void rsnd_adg_get_clkout(struct rsnd_priv *priv,
                ckr, rbga, rbgb);
 }
 
-int rsnd_adg_probe(struct platform_device *pdev,
-                  const struct rsnd_of_data *of_data,
-                  struct rsnd_priv *priv)
+int rsnd_adg_probe(struct rsnd_priv *priv)
 {
        struct rsnd_adg *adg;
        struct device *dev = rsnd_priv_to_dev(priv);
@@ -600,3 +533,14 @@ int rsnd_adg_probe(struct platform_device *pdev,
 
        return 0;
 }
+
+void rsnd_adg_remove(struct rsnd_priv *priv)
+{
+       struct rsnd_adg *adg = rsnd_priv_to_adg(priv);
+       struct clk *clk;
+       int i;
+
+       for_each_rsnd_clk(clk, adg, i) {
+               clk_disable_unprepare(clk);
+       }
+}
diff --git a/sound/soc/sh/rcar/cmd.c b/sound/soc/sh/rcar/cmd.c
new file mode 100644 (file)
index 0000000..cd1f064
--- /dev/null
@@ -0,0 +1,171 @@
+/*
+ * Renesas R-Car CMD support
+ *
+ * Copyright (C) 2015 Renesas Solutions Corp.
+ * Kuninori Morimoto <kuninori.morimoto.gx@renesas.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 "rsnd.h"
+
+struct rsnd_cmd {
+       struct rsnd_mod mod;
+};
+
+#define CMD_NAME "cmd"
+
+#define rsnd_cmd_nr(priv) ((priv)->cmd_nr)
+#define for_each_rsnd_cmd(pos, priv, i)                                        \
+       for ((i) = 0;                                                   \
+            ((i) < rsnd_cmd_nr(priv)) &&                               \
+                    ((pos) = (struct rsnd_cmd *)(priv)->cmd + i);      \
+            i++)
+
+static int rsnd_cmd_init(struct rsnd_mod *mod,
+                        struct rsnd_dai_stream *io,
+                        struct rsnd_priv *priv)
+{
+       struct rsnd_mod *dvc = rsnd_io_to_mod_dvc(io);
+       struct rsnd_mod *mix = rsnd_io_to_mod_mix(io);
+       struct rsnd_mod *src = rsnd_io_to_mod_src(io);
+       struct device *dev = rsnd_priv_to_dev(priv);
+       u32 data;
+
+       if (!mix && !dvc)
+               return 0;
+
+       if (mix) {
+               struct rsnd_dai *rdai;
+               int i;
+               u32 path[] = {
+                       [0] = 0,
+                       [1] = 1 << 0,
+                       [2] = 0,
+                       [3] = 0,
+                       [4] = 0,
+                       [5] = 1 << 8
+               };
+
+               /*
+                * it is assuming that integrater is well understanding about
+                * data path. Here doesn't check impossible connection,
+                * like src2 + src5
+                */
+               data = 0;
+               for_each_rsnd_dai(rdai, priv, i) {
+                       io = &rdai->playback;
+                       if (mix == rsnd_io_to_mod_mix(io))
+                               data |= path[rsnd_mod_id(src)];
+
+                       io = &rdai->capture;
+                       if (mix == rsnd_io_to_mod_mix(io))
+                               data |= path[rsnd_mod_id(src)];
+               }
+
+       } else {
+               u32 path[] = {
+                       [0] = 0x30000,
+                       [1] = 0x30001,
+                       [2] = 0x40000,
+                       [3] = 0x10000,
+                       [4] = 0x20000,
+                       [5] = 0x40100
+               };
+
+               data = path[rsnd_mod_id(src)];
+       }
+
+       dev_dbg(dev, "ctu/mix path = 0x%08x", data);
+
+       rsnd_mod_write(mod, CMD_ROUTE_SLCT, data);
+       rsnd_mod_write(mod, CMD_BUSIF_DALIGN, rsnd_get_dalign(mod, io));
+
+       rsnd_adg_set_cmd_timsel_gen2(mod, io);
+
+       return 0;
+}
+
+static int rsnd_cmd_start(struct rsnd_mod *mod,
+                         struct rsnd_dai_stream *io,
+                         struct rsnd_priv *priv)
+{
+       rsnd_mod_write(mod, CMD_CTRL, 0x10);
+
+       return 0;
+}
+
+static int rsnd_cmd_stop(struct rsnd_mod *mod,
+                        struct rsnd_dai_stream *io,
+                        struct rsnd_priv *priv)
+{
+       rsnd_mod_write(mod, CMD_CTRL, 0);
+
+       return 0;
+}
+
+static struct rsnd_mod_ops rsnd_cmd_ops = {
+       .name   = CMD_NAME,
+       .init   = rsnd_cmd_init,
+       .start  = rsnd_cmd_start,
+       .stop   = rsnd_cmd_stop,
+};
+
+int rsnd_cmd_attach(struct rsnd_dai_stream *io, int id)
+{
+       struct rsnd_priv *priv = rsnd_io_to_priv(io);
+       struct rsnd_mod *mod = rsnd_cmd_mod_get(priv, id);
+
+       return rsnd_dai_connect(mod, io, mod->type);
+}
+
+struct rsnd_mod *rsnd_cmd_mod_get(struct rsnd_priv *priv, int id)
+{
+       if (WARN_ON(id < 0 || id >= rsnd_cmd_nr(priv)))
+               id = 0;
+
+       return rsnd_mod_get((struct rsnd_cmd *)(priv->cmd) + id);
+}
+
+int rsnd_cmd_probe(struct rsnd_priv *priv)
+{
+       struct device *dev = rsnd_priv_to_dev(priv);
+       struct rsnd_cmd *cmd;
+       int i, nr, ret;
+
+       /* This driver doesn't support Gen1 at this point */
+       if (rsnd_is_gen1(priv))
+               return 0;
+
+       /* same number as DVC */
+       nr = priv->dvc_nr;
+       if (!nr)
+               return 0;
+
+       cmd = devm_kzalloc(dev, sizeof(*cmd) * nr, GFP_KERNEL);
+       if (!cmd)
+               return -ENOMEM;
+
+       priv->cmd_nr    = nr;
+       priv->cmd       = cmd;
+
+       for_each_rsnd_cmd(cmd, priv, i) {
+               ret = rsnd_mod_init(priv, rsnd_mod_get(cmd),
+                                   &rsnd_cmd_ops, NULL, RSND_MOD_CMD, i);
+               if (ret)
+                       return ret;
+       }
+
+       return 0;
+}
+
+void rsnd_cmd_remove(struct rsnd_priv *priv)
+{
+       struct rsnd_cmd *cmd;
+       int i;
+
+       for_each_rsnd_cmd(cmd, priv, i) {
+               rsnd_mod_quit(rsnd_mod_get(cmd));
+       }
+}
index deed48ef28b832821010f7192961aaa9af4ba84b..02b4b085b8d77f57398a13c35214a49445d1ed77 100644 (file)
 #define RSND_RATES SNDRV_PCM_RATE_8000_96000
 #define RSND_FMTS (SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S16_LE)
 
-static const struct rsnd_of_data rsnd_of_data_gen1 = {
-       .flags = RSND_GEN1,
-};
-
-static const struct rsnd_of_data rsnd_of_data_gen2 = {
-       .flags = RSND_GEN2,
-};
-
 static const struct of_device_id rsnd_of_match[] = {
-       { .compatible = "renesas,rcar_sound-gen1", .data = &rsnd_of_data_gen1 },
-       { .compatible = "renesas,rcar_sound-gen2", .data = &rsnd_of_data_gen2 },
-       { .compatible = "renesas,rcar_sound-gen3", .data = &rsnd_of_data_gen2 }, /* gen2 compatible */
+       { .compatible = "renesas,rcar_sound-gen1", .data = (void *)RSND_GEN1 },
+       { .compatible = "renesas,rcar_sound-gen2", .data = (void *)RSND_GEN2 },
+       { .compatible = "renesas,rcar_sound-gen3", .data = (void *)RSND_GEN2 }, /* gen2 compatible */
        {},
 };
 MODULE_DEVICE_TABLE(of, rsnd_of_match);
 
 /*
- *     rsnd_platform functions
+ *     rsnd_mod functions
  */
-#define rsnd_platform_call(priv, dai, func, param...)  \
-       (!(priv->info->func) ? 0 :              \
-        priv->info->func(param))
-
-#define rsnd_is_enable_path(io, name) \
-       ((io)->info ? (io)->info->name : NULL)
-#define rsnd_info_id(priv, io, name) \
-       ((io)->info->name - priv->info->name##_info)
-
 void rsnd_mod_make_sure(struct rsnd_mod *mod, enum rsnd_mod_type type)
 {
        if (mod->type != type) {
@@ -138,9 +121,6 @@ void rsnd_mod_make_sure(struct rsnd_mod *mod, enum rsnd_mod_type type)
        }
 }
 
-/*
- *     rsnd_mod functions
- */
 char *rsnd_mod_name(struct rsnd_mod *mod)
 {
        if (!mod || !mod->ops)
@@ -192,19 +172,16 @@ void rsnd_mod_interrupt(struct rsnd_mod *mod,
        struct rsnd_priv *priv = rsnd_mod_to_priv(mod);
        struct rsnd_dai_stream *io;
        struct rsnd_dai *rdai;
-       int i, j;
-
-       for_each_rsnd_dai(rdai, priv, j) {
+       int i;
 
-               for (i = 0; i < RSND_MOD_MAX; i++) {
-                       io = &rdai->playback;
-                       if (mod == io->mod[i])
-                               callback(mod, io);
+       for_each_rsnd_dai(rdai, priv, i) {
+               io = &rdai->playback;
+               if (mod == io->mod[mod->type])
+                       callback(mod, io);
 
-                       io = &rdai->capture;
-                       if (mod == io->mod[i])
-                               callback(mod, io);
-               }
+               io = &rdai->capture;
+               if (mod == io->mod[mod->type])
+                       callback(mod, io);
        }
 }
 
@@ -214,6 +191,43 @@ int rsnd_io_is_working(struct rsnd_dai_stream *io)
        return !!io->substream;
 }
 
+void rsnd_set_slot(struct rsnd_dai *rdai,
+                  int slots, int num)
+{
+       rdai->slots     = slots;
+       rdai->slots_num = num;
+}
+
+int rsnd_get_slot(struct rsnd_dai_stream *io)
+{
+       struct rsnd_dai *rdai = rsnd_io_to_rdai(io);
+
+       return rdai->slots;
+}
+
+int rsnd_get_slot_num(struct rsnd_dai_stream *io)
+{
+       struct rsnd_dai *rdai = rsnd_io_to_rdai(io);
+
+       return rdai->slots_num;
+}
+
+int rsnd_get_slot_width(struct rsnd_dai_stream *io)
+{
+       struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io);
+       int chan = runtime->channels;
+
+       /* Multi channel Mode */
+       if (rsnd_ssi_multi_slaves(io))
+               chan /= rsnd_get_slot_num(io);
+
+       /* TDM Extend Mode needs 8ch */
+       if (chan == 6)
+               chan = 8;
+
+       return chan;
+}
+
 /*
  *     ADINR function
  */
@@ -222,21 +236,17 @@ u32 rsnd_get_adinr_bit(struct rsnd_mod *mod, struct rsnd_dai_stream *io)
        struct rsnd_priv *priv = rsnd_mod_to_priv(mod);
        struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io);
        struct device *dev = rsnd_priv_to_dev(priv);
-       u32 adinr = runtime->channels;
 
        switch (runtime->sample_bits) {
        case 16:
-               adinr |= (8 << 16);
-               break;
+               return 8 << 16;
        case 32:
-               adinr |= (0 << 16);
-               break;
-       default:
-               dev_warn(dev, "not supported sample bits\n");
-               return 0;
+               return 0 << 16;
        }
 
-       return adinr;
+       dev_warn(dev, "not supported sample bits\n");
+
+       return 0;
 }
 
 u32 rsnd_get_adinr_chan(struct rsnd_mod *mod, struct rsnd_dai_stream *io)
@@ -267,13 +277,22 @@ u32 rsnd_get_adinr_chan(struct rsnd_mod *mod, struct rsnd_dai_stream *io)
  */
 u32 rsnd_get_dalign(struct rsnd_mod *mod, struct rsnd_dai_stream *io)
 {
-       struct rsnd_mod *src = rsnd_io_to_mod_src(io);
        struct rsnd_mod *ssi = rsnd_io_to_mod_ssi(io);
-       struct rsnd_mod *target = src ? src : ssi;
+       struct rsnd_mod *target;
        struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io);
        u32 val = 0x76543210;
        u32 mask = ~0;
 
+       if (rsnd_io_is_play(io)) {
+               struct rsnd_mod *src = rsnd_io_to_mod_src(io);
+
+               target = src ? src : ssi;
+       } else {
+               struct rsnd_mod *cmd = rsnd_io_to_mod_cmd(io);
+
+               target = cmd ? cmd : ssi;
+       }
+
        mask <<= runtime->channels * 4;
        val = val & mask;
 
@@ -300,20 +319,22 @@ u32 rsnd_get_dalign(struct rsnd_mod *mod, struct rsnd_dai_stream *io)
 /*
  *     rsnd_dai functions
  */
-#define rsnd_mod_call(mod, io, func, param...)                 \
+#define rsnd_mod_call(idx, io, func, param...)                 \
 ({                                                             \
        struct rsnd_priv *priv = rsnd_mod_to_priv(mod);         \
+       struct rsnd_mod *mod = (io)->mod[idx];                  \
        struct device *dev = rsnd_priv_to_dev(priv);            \
+       u32 *status = (io)->mod_status + idx;                   \
        u32 mask = 0xF << __rsnd_mod_shift_##func;                      \
-       u8 val  = (mod->status >> __rsnd_mod_shift_##func) & 0xF;       \
+       u8 val  = (*status >> __rsnd_mod_shift_##func) & 0xF;           \
        u8 add  = ((val + __rsnd_mod_add_##func) & 0xF);                \
        int ret = 0;                                                    \
        int call = (val == __rsnd_mod_call_##func) && (mod)->ops->func; \
-       mod->status = (mod->status & ~mask) +                           \
+       *status = (*status & ~mask) +                                   \
                (add << __rsnd_mod_shift_##func);                       \
        dev_dbg(dev, "%s[%d]\t0x%08x %s\n",                             \
                rsnd_mod_name(mod), rsnd_mod_id(mod),                   \
-               mod->status, call ? #func : "");                        \
+               *status, call ? #func : "");                            \
        if (call)                                                       \
                ret = (mod)->ops->func(mod, io, param);                 \
        ret;                                                            \
@@ -327,13 +348,14 @@ u32 rsnd_get_dalign(struct rsnd_mod *mod, struct rsnd_dai_stream *io)
                mod = (io)->mod[i];                             \
                if (!mod)                                       \
                        continue;                               \
-               ret |= rsnd_mod_call(mod, io, fn, param);       \
+               ret |= rsnd_mod_call(i, io, fn, param);         \
        }                                                       \
        ret;                                                    \
 })
 
-static int rsnd_dai_connect(struct rsnd_mod *mod,
-                           struct rsnd_dai_stream *io)
+int rsnd_dai_connect(struct rsnd_mod *mod,
+                    struct rsnd_dai_stream *io,
+                    enum rsnd_mod_type type)
 {
        struct rsnd_priv *priv;
        struct device *dev;
@@ -341,10 +363,13 @@ static int rsnd_dai_connect(struct rsnd_mod *mod,
        if (!mod)
                return -EIO;
 
+       if (io->mod[type])
+               return -EINVAL;
+
        priv = rsnd_mod_to_priv(mod);
        dev = rsnd_priv_to_dev(priv);
 
-       io->mod[mod->type] = mod;
+       io->mod[type] = mod;
 
        dev_dbg(dev, "%s[%d] is connected to io (%s)\n",
                rsnd_mod_name(mod), rsnd_mod_id(mod),
@@ -354,9 +379,10 @@ static int rsnd_dai_connect(struct rsnd_mod *mod,
 }
 
 static void rsnd_dai_disconnect(struct rsnd_mod *mod,
-                               struct rsnd_dai_stream *io)
+                               struct rsnd_dai_stream *io,
+                               enum rsnd_mod_type type)
 {
-       io->mod[mod->type] = NULL;
+       io->mod[type] = NULL;
 }
 
 struct rsnd_dai *rsnd_rdai_get(struct rsnd_priv *priv, int id)
@@ -469,7 +495,6 @@ static int rsnd_soc_dai_trigger(struct snd_pcm_substream *substream, int cmd,
        struct rsnd_priv *priv = rsnd_dai_to_priv(dai);
        struct rsnd_dai *rdai = rsnd_dai_to_rdai(dai);
        struct rsnd_dai_stream *io = rsnd_rdai_to_io(rdai, substream);
-       int ssi_id = rsnd_mod_id(rsnd_io_to_mod_ssi(io));
        int ret;
        unsigned long flags;
 
@@ -479,10 +504,6 @@ static int rsnd_soc_dai_trigger(struct snd_pcm_substream *substream, int cmd,
        case SNDRV_PCM_TRIGGER_START:
                rsnd_dai_stream_init(io, substream);
 
-               ret = rsnd_platform_call(priv, dai, start, ssi_id);
-               if (ret < 0)
-                       goto dai_trigger_end;
-
                ret = rsnd_dai_call(init, io, priv);
                if (ret < 0)
                        goto dai_trigger_end;
@@ -496,8 +517,6 @@ static int rsnd_soc_dai_trigger(struct snd_pcm_substream *substream, int cmd,
 
                ret |= rsnd_dai_call(quit, io, priv);
 
-               ret |= rsnd_platform_call(priv, dai, stop, ssi_id);
-
                rsnd_dai_stream_quit(io);
                break;
        default:
@@ -567,332 +586,157 @@ static int rsnd_soc_dai_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
        return 0;
 }
 
-static const struct snd_soc_dai_ops rsnd_soc_dai_ops = {
-       .trigger        = rsnd_soc_dai_trigger,
-       .set_fmt        = rsnd_soc_dai_set_fmt,
-};
-
-#define rsnd_path_add(priv, io, type)                          \
-({                                                             \
-       struct rsnd_mod *mod;                                   \
-       int ret = 0;                                            \
-       int id = -1;                                            \
-                                                               \
-       if (rsnd_is_enable_path(io, type)) {                    \
-               id = rsnd_info_id(priv, io, type);              \
-               if (id >= 0) {                                  \
-                       mod = rsnd_##type##_mod_get(priv, id);  \
-                       ret = rsnd_dai_connect(mod, io);        \
-               }                                               \
-       }                                                       \
-       ret;                                                    \
-})
-
-#define rsnd_path_remove(priv, io, type)                       \
-{                                                              \
-       struct rsnd_mod *mod;                                   \
-       int id = -1;                                            \
-                                                               \
-       if (rsnd_is_enable_path(io, type)) {                    \
-               id = rsnd_info_id(priv, io, type);              \
-               if (id >= 0) {                                  \
-                       mod = rsnd_##type##_mod_get(priv, id);  \
-                       rsnd_dai_disconnect(mod, io);           \
-               }                                               \
-       }                                                       \
-}
-
-void rsnd_path_parse(struct rsnd_priv *priv,
-                    struct rsnd_dai_stream *io)
+static int rsnd_soc_set_dai_tdm_slot(struct snd_soc_dai *dai,
+                                    u32 tx_mask, u32 rx_mask,
+                                    int slots, int slot_width)
 {
-       struct rsnd_mod *dvc = rsnd_io_to_mod_dvc(io);
-       struct rsnd_mod *mix = rsnd_io_to_mod_mix(io);
-       struct rsnd_mod *src = rsnd_io_to_mod_src(io);
-       struct rsnd_mod *cmd;
+       struct rsnd_priv *priv = rsnd_dai_to_priv(dai);
+       struct rsnd_dai *rdai = rsnd_dai_to_rdai(dai);
        struct device *dev = rsnd_priv_to_dev(priv);
-       u32 data;
 
-       /* Gen1 is not supported */
-       if (rsnd_is_gen1(priv))
-               return;
-
-       if (!mix && !dvc)
-               return;
-
-       if (mix) {
-               struct rsnd_dai *rdai;
-               int i;
-               u32 path[] = {
-                       [0] = 0,
-                       [1] = 1 << 0,
-                       [2] = 0,
-                       [3] = 0,
-                       [4] = 0,
-                       [5] = 1 << 8
-               };
-
-               /*
-                * it is assuming that integrater is well understanding about
-                * data path. Here doesn't check impossible connection,
-                * like src2 + src5
-                */
-               data = 0;
-               for_each_rsnd_dai(rdai, priv, i) {
-                       io = &rdai->playback;
-                       if (mix == rsnd_io_to_mod_mix(io))
-                               data |= path[rsnd_mod_id(src)];
-
-                       io = &rdai->capture;
-                       if (mix == rsnd_io_to_mod_mix(io))
-                               data |= path[rsnd_mod_id(src)];
-               }
-
-               /*
-                * We can't use ctu = rsnd_io_ctu() here.
-                * Since, ID of dvc/mix are 0 or 1 (= same as CMD number)
-                * but ctu IDs are 0 - 7 (= CTU00 - CTU13)
-                */
-               cmd = mix;
-       } else {
-               u32 path[] = {
-                       [0] = 0x30000,
-                       [1] = 0x30001,
-                       [2] = 0x40000,
-                       [3] = 0x10000,
-                       [4] = 0x20000,
-                       [5] = 0x40100
-               };
-
-               data = path[rsnd_mod_id(src)];
-
-               cmd = dvc;
+       switch (slots) {
+       case 6:
+               /* TDM Extend Mode */
+               rsnd_set_slot(rdai, slots, 1);
+               break;
+       default:
+               dev_err(dev, "unsupported TDM slots (%d)\n", slots);
+               return -EINVAL;
        }
 
-       dev_dbg(dev, "ctu/mix path = 0x%08x", data);
-
-       rsnd_mod_write(cmd, CMD_ROUTE_SLCT, data);
-
-       rsnd_mod_write(cmd, CMD_CTRL, 0x10);
+       return 0;
 }
 
-static int rsnd_path_init(struct rsnd_priv *priv,
-                         struct rsnd_dai *rdai,
-                         struct rsnd_dai_stream *io)
-{
-       int ret;
-
-       /*
-        * Gen1 is created by SRU/SSI, and this SRU is base module of
-        * Gen2's SCU/SSIU/SSI. (Gen2 SCU/SSIU came from SRU)
-        *
-        * Easy image is..
-        *      Gen1 SRU = Gen2 SCU + SSIU + etc
-        *
-        * Gen2 SCU path is very flexible, but, Gen1 SRU (SCU parts) is
-        * using fixed path.
-        */
-
-       /* SSI */
-       ret = rsnd_path_add(priv, io, ssi);
-       if (ret < 0)
-               return ret;
-
-       /* SRC */
-       ret = rsnd_path_add(priv, io, src);
-       if (ret < 0)
-               return ret;
+static const struct snd_soc_dai_ops rsnd_soc_dai_ops = {
+       .trigger        = rsnd_soc_dai_trigger,
+       .set_fmt        = rsnd_soc_dai_set_fmt,
+       .set_tdm_slot   = rsnd_soc_set_dai_tdm_slot,
+};
 
-       /* CTU */
-       ret = rsnd_path_add(priv, io, ctu);
-       if (ret < 0)
-               return ret;
+void rsnd_parse_connect_common(struct rsnd_dai *rdai,
+               struct rsnd_mod* (*mod_get)(struct rsnd_priv *priv, int id),
+               struct device_node *node,
+               struct device_node *playback,
+               struct device_node *capture)
+{
+       struct rsnd_priv *priv = rsnd_rdai_to_priv(rdai);
+       struct device_node *np;
+       struct rsnd_mod *mod;
+       int i;
 
-       /* MIX */
-       ret = rsnd_path_add(priv, io, mix);
-       if (ret < 0)
-               return ret;
+       if (!node)
+               return;
 
-       /* DVC */
-       ret = rsnd_path_add(priv, io, dvc);
-       if (ret < 0)
-               return ret;
+       i = 0;
+       for_each_child_of_node(node, np) {
+               mod = mod_get(priv, i);
+               if (np == playback)
+                       rsnd_dai_connect(mod, &rdai->playback, mod->type);
+               if (np == capture)
+                       rsnd_dai_connect(mod, &rdai->capture, mod->type);
+               i++;
+       }
 
-       return ret;
+       of_node_put(node);
 }
 
-static void rsnd_of_parse_dai(struct platform_device *pdev,
-                             const struct rsnd_of_data *of_data,
-                             struct rsnd_priv *priv)
+static int rsnd_dai_probe(struct rsnd_priv *priv)
 {
-       struct device_node *dai_node,   *dai_np;
-       struct device_node *ssi_node,   *ssi_np;
-       struct device_node *src_node,   *src_np;
-       struct device_node *ctu_node,   *ctu_np;
-       struct device_node *mix_node,   *mix_np;
-       struct device_node *dvc_node,   *dvc_np;
+       struct device_node *dai_node;
+       struct device_node *dai_np;
        struct device_node *playback, *capture;
-       struct rsnd_dai_platform_info *dai_info;
-       struct rcar_snd_info *info = rsnd_priv_to_info(priv);
-       struct device *dev = &pdev->dev;
-       int nr, i;
-       int dai_i, ssi_i, src_i, ctu_i, mix_i, dvc_i;
-
-       if (!of_data)
-               return;
-
-       dai_node = of_get_child_by_name(dev->of_node, "rcar_sound,dai");
-       if (!dai_node)
-               return;
+       struct rsnd_dai_stream *io_playback;
+       struct rsnd_dai_stream *io_capture;
+       struct snd_soc_dai_driver *rdrv, *drv;
+       struct rsnd_dai *rdai;
+       struct device *dev = rsnd_priv_to_dev(priv);
+       int nr, dai_i, io_i;
+       int ret;
 
+       dai_node = rsnd_dai_of_node(priv);
        nr = of_get_child_count(dai_node);
-       if (!nr)
-               return;
+       if (!nr) {
+               ret = -EINVAL;
+               goto rsnd_dai_probe_done;
+       }
 
-       dai_info = devm_kzalloc(dev,
-                               sizeof(struct rsnd_dai_platform_info) * nr,
-                               GFP_KERNEL);
-       if (!dai_info) {
-               dev_err(dev, "dai info allocation error\n");
-               return;
+       rdrv = devm_kzalloc(dev, sizeof(*rdrv) * nr, GFP_KERNEL);
+       rdai = devm_kzalloc(dev, sizeof(*rdai) * nr, GFP_KERNEL);
+       if (!rdrv || !rdai) {
+               ret = -ENOMEM;
+               goto rsnd_dai_probe_done;
        }
 
-       info->dai_info_nr       = nr;
-       info->dai_info          = dai_info;
-
-       ssi_node = of_get_child_by_name(dev->of_node, "rcar_sound,ssi");
-       src_node = of_get_child_by_name(dev->of_node, "rcar_sound,src");
-       ctu_node = of_get_child_by_name(dev->of_node, "rcar_sound,ctu");
-       mix_node = of_get_child_by_name(dev->of_node, "rcar_sound,mix");
-       dvc_node = of_get_child_by_name(dev->of_node, "rcar_sound,dvc");
-
-#define mod_parse(name)                                                        \
-if (name##_node) {                                                     \
-       struct rsnd_##name##_platform_info *name##_info;                \
-                                                                       \
-       name##_i = 0;                                                   \
-       for_each_child_of_node(name##_node, name##_np) {                \
-               name##_info = info->name##_info + name##_i;             \
-                                                                       \
-               if (name##_np == playback)                              \
-                       dai_info->playback.name = name##_info;          \
-               if (name##_np == capture)                               \
-                       dai_info->capture.name = name##_info;           \
-                                                                       \
-               name##_i++;                                             \
-       }                                                               \
-}
+       priv->rdai_nr   = nr;
+       priv->daidrv    = rdrv;
+       priv->rdai      = rdai;
 
        /*
         * parse all dai
         */
        dai_i = 0;
        for_each_child_of_node(dai_node, dai_np) {
-               dai_info = info->dai_info + dai_i;
-
-               for (i = 0;; i++) {
-
-                       playback = of_parse_phandle(dai_np, "playback", i);
-                       capture  = of_parse_phandle(dai_np, "capture", i);
+               rdai            = rsnd_rdai_get(priv, dai_i);
+               drv             = rdrv + dai_i;
+               io_playback     = &rdai->playback;
+               io_capture      = &rdai->capture;
+
+               snprintf(rdai->name, RSND_DAI_NAME_SIZE, "rsnd-dai.%d", dai_i);
+
+               rdai->priv      = priv;
+               drv->name       = rdai->name;
+               drv->ops        = &rsnd_soc_dai_ops;
+
+               snprintf(rdai->playback.name, RSND_DAI_NAME_SIZE,
+                        "DAI%d Playback", dai_i);
+               drv->playback.rates             = RSND_RATES;
+               drv->playback.formats           = RSND_FMTS;
+               drv->playback.channels_min      = 2;
+               drv->playback.channels_max      = 6;
+               drv->playback.stream_name       = rdai->playback.name;
+
+               snprintf(rdai->capture.name, RSND_DAI_NAME_SIZE,
+                        "DAI%d Capture", dai_i);
+               drv->capture.rates              = RSND_RATES;
+               drv->capture.formats            = RSND_FMTS;
+               drv->capture.channels_min       = 2;
+               drv->capture.channels_max       = 6;
+               drv->capture.stream_name        = rdai->capture.name;
+
+               rdai->playback.rdai             = rdai;
+               rdai->capture.rdai              = rdai;
+               rsnd_set_slot(rdai, 2, 1); /* default */
+
+               for (io_i = 0;; io_i++) {
+                       playback = of_parse_phandle(dai_np, "playback", io_i);
+                       capture  = of_parse_phandle(dai_np, "capture", io_i);
 
                        if (!playback && !capture)
                                break;
 
-                       mod_parse(ssi);
-                       mod_parse(src);
-                       mod_parse(ctu);
-                       mod_parse(mix);
-                       mod_parse(dvc);
+                       rsnd_parse_connect_ssi(rdai, playback, capture);
+                       rsnd_parse_connect_src(rdai, playback, capture);
+                       rsnd_parse_connect_ctu(rdai, playback, capture);
+                       rsnd_parse_connect_mix(rdai, playback, capture);
+                       rsnd_parse_connect_dvc(rdai, playback, capture);
 
                        of_node_put(playback);
                        of_node_put(capture);
                }
 
                dai_i++;
-       }
-}
-
-static int rsnd_dai_probe(struct platform_device *pdev,
-                         const struct rsnd_of_data *of_data,
-                         struct rsnd_priv *priv)
-{
-       struct snd_soc_dai_driver *drv;
-       struct rcar_snd_info *info = rsnd_priv_to_info(priv);
-       struct rsnd_dai *rdai;
-       struct rsnd_ssi_platform_info *pmod, *cmod;
-       struct device *dev = rsnd_priv_to_dev(priv);
-       int dai_nr;
-       int i;
-
-       rsnd_of_parse_dai(pdev, of_data, priv);
 
-       dai_nr = info->dai_info_nr;
-       if (!dai_nr) {
-               dev_err(dev, "no dai\n");
-               return -EIO;
+               dev_dbg(dev, "%s (%s/%s)\n", rdai->name,
+                       rsnd_io_to_mod_ssi(io_playback) ? "play"    : " -- ",
+                       rsnd_io_to_mod_ssi(io_capture) ? "capture" : "  --   ");
        }
 
-       drv  = devm_kzalloc(dev, sizeof(*drv)  * dai_nr, GFP_KERNEL);
-       rdai = devm_kzalloc(dev, sizeof(*rdai) * dai_nr, GFP_KERNEL);
-       if (!drv || !rdai) {
-               dev_err(dev, "dai allocate failed\n");
-               return -ENOMEM;
-       }
-
-       priv->rdai_nr   = dai_nr;
-       priv->daidrv    = drv;
-       priv->rdai      = rdai;
+       ret = 0;
 
-       for (i = 0; i < dai_nr; i++) {
+rsnd_dai_probe_done:
+       of_node_put(dai_node);
 
-               pmod = info->dai_info[i].playback.ssi;
-               cmod = info->dai_info[i].capture.ssi;
-
-               /*
-                *      init rsnd_dai
-                */
-               snprintf(rdai[i].name, RSND_DAI_NAME_SIZE, "rsnd-dai.%d", i);
-               rdai[i].priv = priv;
-
-               /*
-                *      init snd_soc_dai_driver
-                */
-               drv[i].name     = rdai[i].name;
-               drv[i].ops      = &rsnd_soc_dai_ops;
-               if (pmod) {
-                       snprintf(rdai[i].playback.name, RSND_DAI_NAME_SIZE,
-                                "DAI%d Playback", i);
-
-                       drv[i].playback.rates           = RSND_RATES;
-                       drv[i].playback.formats         = RSND_FMTS;
-                       drv[i].playback.channels_min    = 2;
-                       drv[i].playback.channels_max    = 2;
-                       drv[i].playback.stream_name     = rdai[i].playback.name;
-
-                       rdai[i].playback.info = &info->dai_info[i].playback;
-                       rdai[i].playback.rdai = rdai + i;
-                       rsnd_path_init(priv, &rdai[i], &rdai[i].playback);
-               }
-               if (cmod) {
-                       snprintf(rdai[i].capture.name, RSND_DAI_NAME_SIZE,
-                                "DAI%d Capture", i);
-
-                       drv[i].capture.rates            = RSND_RATES;
-                       drv[i].capture.formats          = RSND_FMTS;
-                       drv[i].capture.channels_min     = 2;
-                       drv[i].capture.channels_max     = 2;
-                       drv[i].capture.stream_name      = rdai[i].capture.name;
-
-                       rdai[i].capture.info = &info->dai_info[i].capture;
-                       rdai[i].capture.rdai = rdai + i;
-                       rsnd_path_init(priv, &rdai[i], &rdai[i].capture);
-               }
-
-               dev_dbg(dev, "%s (%s/%s)\n", rdai[i].name,
-                       pmod ? "play"    : " -- ",
-                       cmod ? "capture" : "  --   ");
-       }
-
-       return 0;
+       return ret;
 }
 
 /*
@@ -1033,14 +877,13 @@ static int __rsnd_kctrl_new(struct rsnd_mod *mod,
                            void (*update)(struct rsnd_dai_stream *io,
                                           struct rsnd_mod *mod))
 {
-       struct snd_soc_card *soc_card = rtd->card;
        struct snd_card *card = rtd->card->snd_card;
        struct snd_kcontrol *kctrl;
        struct snd_kcontrol_new knew = {
                .iface          = SNDRV_CTL_ELEM_IFACE_MIXER,
                .name           = name,
                .info           = rsnd_kctrl_info,
-               .index          = rtd - soc_card->rtd,
+               .index          = rtd->num,
                .get            = rsnd_kctrl_get,
                .put            = rsnd_kctrl_put,
                .private_value  = (unsigned long)cfg,
@@ -1077,10 +920,14 @@ int rsnd_kctrl_new_m(struct rsnd_mod *mod,
                     void (*update)(struct rsnd_dai_stream *io,
                                    struct rsnd_mod *mod),
                     struct rsnd_kctrl_cfg_m *_cfg,
+                    int ch_size,
                     u32 max)
 {
+       if (ch_size > RSND_DVC_CHANNELS)
+               return -EINVAL;
+
        _cfg->cfg.max   = max;
-       _cfg->cfg.size  = RSND_DVC_CHANNELS;
+       _cfg->cfg.size  = ch_size;
        _cfg->cfg.val   = _cfg->val;
        return __rsnd_kctrl_new(mod, io, rtd, name, &_cfg->cfg, update);
 }
@@ -1161,6 +1008,9 @@ static int rsnd_rdai_continuance_probe(struct rsnd_priv *priv,
 
        ret = rsnd_dai_call(probe, io, priv);
        if (ret == -EAGAIN) {
+               struct rsnd_mod *ssi_mod = rsnd_io_to_mod_ssi(io);
+               int i;
+
                /*
                 * Fallback to PIO mode
                 */
@@ -1175,10 +1025,12 @@ static int rsnd_rdai_continuance_probe(struct rsnd_priv *priv,
                rsnd_dai_call(remove, io, priv);
 
                /*
-                * remove SRC/DVC from DAI,
+                * remove all mod from io
+                * and, re connect ssi
                 */
-               rsnd_path_remove(priv, io, src);
-               rsnd_path_remove(priv, io, dvc);
+               for (i = 0; i < RSND_MOD_MAX; i++)
+                       rsnd_dai_disconnect((io)->mod[i], io, i);
+               rsnd_dai_connect(ssi_mod, io, RSND_MOD_SSI);
 
                /*
                 * fallback
@@ -1200,33 +1052,25 @@ static int rsnd_rdai_continuance_probe(struct rsnd_priv *priv,
  */
 static int rsnd_probe(struct platform_device *pdev)
 {
-       struct rcar_snd_info *info;
        struct rsnd_priv *priv;
        struct device *dev = &pdev->dev;
        struct rsnd_dai *rdai;
        const struct of_device_id *of_id = of_match_device(rsnd_of_match, dev);
-       const struct rsnd_of_data *of_data;
-       int (*probe_func[])(struct platform_device *pdev,
-                           const struct rsnd_of_data *of_data,
-                           struct rsnd_priv *priv) = {
+       int (*probe_func[])(struct rsnd_priv *priv) = {
                rsnd_gen_probe,
                rsnd_dma_probe,
                rsnd_ssi_probe,
+               rsnd_ssiu_probe,
                rsnd_src_probe,
                rsnd_ctu_probe,
                rsnd_mix_probe,
                rsnd_dvc_probe,
+               rsnd_cmd_probe,
                rsnd_adg_probe,
                rsnd_dai_probe,
        };
        int ret, i;
 
-       info = devm_kzalloc(&pdev->dev, sizeof(struct rcar_snd_info),
-                           GFP_KERNEL);
-       if (!info)
-               return -ENOMEM;
-       of_data = of_id->data;
-
        /*
         *      init priv data
         */
@@ -1237,14 +1081,14 @@ static int rsnd_probe(struct platform_device *pdev)
        }
 
        priv->pdev      = pdev;
-       priv->info      = info;
+       priv->flags     = (unsigned long)of_id->data;
        spin_lock_init(&priv->lock);
 
        /*
         *      init each module
         */
        for (i = 0; i < ARRAY_SIZE(probe_func); i++) {
-               ret = probe_func[i](pdev, of_data, priv);
+               ret = probe_func[i](priv);
                if (ret)
                        return ret;
        }
@@ -1297,13 +1141,15 @@ 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) = {
+       void (*remove_func[])(struct rsnd_priv *priv) = {
                rsnd_ssi_remove,
+               rsnd_ssiu_remove,
                rsnd_src_remove,
                rsnd_ctu_remove,
                rsnd_mix_remove,
                rsnd_dvc_remove,
+               rsnd_cmd_remove,
+               rsnd_adg_remove,
        };
        int ret = 0, i;
 
@@ -1315,7 +1161,7 @@ static int rsnd_remove(struct platform_device *pdev)
        }
 
        for (i = 0; i < ARRAY_SIZE(remove_func); i++)
-               remove_func[i](pdev, priv);
+               remove_func[i](priv);
 
        snd_soc_unregister_component(&pdev->dev);
        snd_soc_unregister_platform(&pdev->dev);
index 3cb214ab848be05ca345e0a976e2d1a2d6bdc65b..d53a225d19e9b724b2b326a32f5746c822e3c4b8 100644 (file)
@@ -13,7 +13,6 @@
 #define CTU_NAME "ctu"
 
 struct rsnd_ctu {
-       struct rsnd_ctu_platform_info *info; /* rcar_snd.h */
        struct rsnd_mod mod;
 };
 
@@ -24,6 +23,7 @@ struct rsnd_ctu {
                     ((pos) = (struct rsnd_ctu *)(priv)->ctu + i);      \
             i++)
 
+#define rsnd_ctu_get(priv, id) ((struct rsnd_ctu *)(priv->ctu) + id)
 #define rsnd_ctu_initialize_lock(mod)  __rsnd_ctu_initialize_lock(mod, 1)
 #define rsnd_ctu_initialize_unlock(mod)        __rsnd_ctu_initialize_lock(mod, 0)
 static void __rsnd_ctu_initialize_lock(struct rsnd_mod *mod, u32 enable)
@@ -31,6 +31,13 @@ static void __rsnd_ctu_initialize_lock(struct rsnd_mod *mod, u32 enable)
        rsnd_mod_write(mod, CTU_CTUIR, enable);
 }
 
+static int rsnd_ctu_probe_(struct rsnd_mod *mod,
+                          struct rsnd_dai_stream *io,
+                          struct rsnd_priv *priv)
+{
+       return rsnd_cmd_attach(io, rsnd_mod_id(mod) / 4);
+}
+
 static int rsnd_ctu_init(struct rsnd_mod *mod,
                         struct rsnd_dai_stream *io,
                         struct rsnd_priv *priv)
@@ -57,6 +64,7 @@ static int rsnd_ctu_quit(struct rsnd_mod *mod,
 
 static struct rsnd_mod_ops rsnd_ctu_ops = {
        .name           = CTU_NAME,
+       .probe          = rsnd_ctu_probe_,
        .init           = rsnd_ctu_init,
        .quit           = rsnd_ctu_quit,
 };
@@ -66,51 +74,13 @@ struct rsnd_mod *rsnd_ctu_mod_get(struct rsnd_priv *priv, int id)
        if (WARN_ON(id < 0 || id >= rsnd_ctu_nr(priv)))
                id = 0;
 
-       return rsnd_mod_get((struct rsnd_ctu *)(priv->ctu) + id);
+       return rsnd_mod_get(rsnd_ctu_get(priv, id));
 }
 
-static void rsnd_of_parse_ctu(struct platform_device *pdev,
-                      const struct rsnd_of_data *of_data,
-                      struct rsnd_priv *priv)
+int rsnd_ctu_probe(struct rsnd_priv *priv)
 {
        struct device_node *node;
-       struct rsnd_ctu_platform_info *ctu_info;
-       struct rcar_snd_info *info = rsnd_priv_to_info(priv);
-       struct device *dev = &pdev->dev;
-       int nr;
-
-       if (!of_data)
-               return;
-
-       node = of_get_child_by_name(dev->of_node, "rcar_sound,ctu");
-       if (!node)
-               return;
-
-       nr = of_get_child_count(node);
-       if (!nr)
-               goto rsnd_of_parse_ctu_end;
-
-       ctu_info = devm_kzalloc(dev,
-                               sizeof(struct rsnd_ctu_platform_info) * nr,
-                               GFP_KERNEL);
-       if (!ctu_info) {
-               dev_err(dev, "ctu info allocation error\n");
-               goto rsnd_of_parse_ctu_end;
-       }
-
-       info->ctu_info          = ctu_info;
-       info->ctu_info_nr       = nr;
-
-rsnd_of_parse_ctu_end:
-       of_node_put(node);
-
-}
-
-int rsnd_ctu_probe(struct platform_device *pdev,
-                  const struct rsnd_of_data *of_data,
-                  struct rsnd_priv *priv)
-{
-       struct rcar_snd_info *info = rsnd_priv_to_info(priv);
+       struct device_node *np;
        struct device *dev = rsnd_priv_to_dev(priv);
        struct rsnd_ctu *ctu;
        struct clk *clk;
@@ -121,20 +91,30 @@ int rsnd_ctu_probe(struct platform_device *pdev,
        if (rsnd_is_gen1(priv))
                return 0;
 
-       rsnd_of_parse_ctu(pdev, of_data, priv);
+       node = rsnd_ctu_of_node(priv);
+       if (!node)
+               return 0; /* not used is not error */
 
-       nr = info->ctu_info_nr;
-       if (!nr)
-               return 0;
+       nr = of_get_child_count(node);
+       if (!nr) {
+               ret = -EINVAL;
+               goto rsnd_ctu_probe_done;
+       }
 
        ctu = devm_kzalloc(dev, sizeof(*ctu) * nr, GFP_KERNEL);
-       if (!ctu)
-               return -ENOMEM;
+       if (!ctu) {
+               ret = -ENOMEM;
+               goto rsnd_ctu_probe_done;
+       }
 
        priv->ctu_nr    = nr;
        priv->ctu       = ctu;
 
-       for_each_rsnd_ctu(ctu, priv, i) {
+       i = 0;
+       ret = 0;
+       for_each_child_of_node(node, np) {
+               ctu = rsnd_ctu_get(priv, i);
+
                /*
                 * CTU00, CTU01, CTU02, CTU03 => CTU0
                 * CTU10, CTU11, CTU12, CTU13 => CTU1
@@ -143,22 +123,27 @@ int rsnd_ctu_probe(struct platform_device *pdev,
                         CTU_NAME, i / 4);
 
                clk = devm_clk_get(dev, name);
-               if (IS_ERR(clk))
-                       return PTR_ERR(clk);
-
-               ctu->info = &info->ctu_info[i];
+               if (IS_ERR(clk)) {
+                       ret = PTR_ERR(clk);
+                       goto rsnd_ctu_probe_done;
+               }
 
                ret = rsnd_mod_init(priv, rsnd_mod_get(ctu), &rsnd_ctu_ops,
                                    clk, RSND_MOD_CTU, i);
                if (ret)
-                       return ret;
+                       goto rsnd_ctu_probe_done;
+
+               i++;
        }
 
-       return 0;
+
+rsnd_ctu_probe_done:
+       of_node_put(node);
+
+       return ret;
 }
 
-void rsnd_ctu_remove(struct platform_device *pdev,
-                    struct rsnd_priv *priv)
+void rsnd_ctu_remove(struct rsnd_priv *priv)
 {
        struct rsnd_ctu *ctu;
        int i;
index 5d084d0409611dd67cf35bc00c2fed53b517862b..418e6fdd06a338b1aac03d585e1a353bd21bfc26 100644 (file)
 /* PDMACHCR */
 #define PDMACHCR_DE            (1 << 0)
 
+
+struct rsnd_dmaen {
+       struct dma_chan         *chan;
+};
+
+struct rsnd_dmapp {
+       int                     dmapp_id;
+       u32                     chcr;
+};
+
+struct rsnd_dma {
+       struct rsnd_mod         mod;
+       dma_addr_t              src_addr;
+       dma_addr_t              dst_addr;
+       union {
+               struct rsnd_dmaen en;
+               struct rsnd_dmapp pp;
+       } dma;
+};
+
 struct rsnd_dma_ctrl {
        void __iomem *base;
+       int dmaen_num;
        int dmapp_num;
 };
 
-struct rsnd_dma_ops {
-       char *name;
-       void (*start)(struct rsnd_dai_stream *io, struct rsnd_dma *dma);
-       void (*stop)(struct rsnd_dai_stream *io, struct rsnd_dma *dma);
-       int (*init)(struct rsnd_dai_stream *io, struct rsnd_dma *dma, int id,
-                   struct rsnd_mod *mod_from, struct rsnd_mod *mod_to);
-       void (*quit)(struct rsnd_dai_stream *io, struct rsnd_dma *dma);
-};
-
 #define rsnd_priv_to_dmac(p)   ((struct rsnd_dma_ctrl *)(p)->dma)
+#define rsnd_mod_to_dma(_mod) container_of((_mod), struct rsnd_dma, mod)
+#define rsnd_dma_to_dmaen(dma) (&(dma)->dma.en)
+#define rsnd_dma_to_dmapp(dma) (&(dma)->dma.pp)
 
 /*
  *             Audio DMAC
@@ -77,18 +92,24 @@ static void rsnd_dmaen_complete(void *data)
        rsnd_mod_interrupt(mod, __rsnd_dmaen_complete);
 }
 
-static void rsnd_dmaen_stop(struct rsnd_dai_stream *io, struct rsnd_dma *dma)
+static int rsnd_dmaen_stop(struct rsnd_mod *mod,
+                          struct rsnd_dai_stream *io,
+                          struct rsnd_priv *priv)
 {
+       struct rsnd_dma *dma = rsnd_mod_to_dma(mod);
        struct rsnd_dmaen *dmaen = rsnd_dma_to_dmaen(dma);
 
        dmaengine_terminate_all(dmaen->chan);
+
+       return 0;
 }
 
-static void rsnd_dmaen_start(struct rsnd_dai_stream *io, struct rsnd_dma *dma)
+static int rsnd_dmaen_start(struct rsnd_mod *mod,
+                           struct rsnd_dai_stream *io,
+                           struct rsnd_priv *priv)
 {
+       struct rsnd_dma *dma = rsnd_mod_to_dma(mod);
        struct rsnd_dmaen *dmaen = rsnd_dma_to_dmaen(dma);
-       struct rsnd_mod *mod = rsnd_dma_to_mod(dma);
-       struct rsnd_priv *priv = rsnd_mod_to_priv(mod);
        struct snd_pcm_substream *substream = io->substream;
        struct device *dev = rsnd_priv_to_dev(priv);
        struct dma_async_tx_descriptor *desc;
@@ -103,18 +124,20 @@ static void rsnd_dmaen_start(struct rsnd_dai_stream *io, struct rsnd_dma *dma)
 
        if (!desc) {
                dev_err(dev, "dmaengine_prep_slave_sg() fail\n");
-               return;
+               return -EIO;
        }
 
        desc->callback          = rsnd_dmaen_complete;
-       desc->callback_param    = mod;
+       desc->callback_param    = rsnd_mod_get(dma);
 
        if (dmaengine_submit(desc) < 0) {
                dev_err(dev, "dmaengine_submit() fail\n");
-               return;
+               return -EIO;
        }
 
        dma_async_issue_pending(dmaen->chan);
+
+       return 0;
 }
 
 struct dma_chan *rsnd_dma_request_channel(struct device_node *of_node,
@@ -152,12 +175,29 @@ static struct dma_chan *rsnd_dmaen_request_channel(struct rsnd_dai_stream *io,
                return rsnd_mod_dma_req(io, mod_to);
 }
 
-static int rsnd_dmaen_init(struct rsnd_dai_stream *io,
+static int rsnd_dmaen_remove(struct rsnd_mod *mod,
+                             struct rsnd_dai_stream *io,
+                             struct rsnd_priv *priv)
+{
+       struct rsnd_dma *dma = rsnd_mod_to_dma(mod);
+       struct rsnd_dmaen *dmaen = rsnd_dma_to_dmaen(dma);
+
+       if (dmaen->chan)
+               dma_release_channel(dmaen->chan);
+
+       dmaen->chan = NULL;
+
+       return 0;
+}
+
+static int rsnd_dmaen_attach(struct rsnd_dai_stream *io,
                           struct rsnd_dma *dma, int id,
                           struct rsnd_mod *mod_from, struct rsnd_mod *mod_to)
 {
+       struct rsnd_mod *mod = rsnd_mod_get(dma);
        struct rsnd_dmaen *dmaen = rsnd_dma_to_dmaen(dma);
        struct rsnd_priv *priv = rsnd_io_to_priv(io);
+       struct rsnd_dma_ctrl *dmac = rsnd_priv_to_dmac(priv);
        struct device *dev = rsnd_priv_to_dev(priv);
        struct dma_slave_config cfg = {};
        int is_play = rsnd_io_is_play(io);
@@ -191,18 +231,20 @@ static int rsnd_dmaen_init(struct rsnd_dai_stream *io,
        cfg.src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
        cfg.dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
 
-       dev_dbg(dev, "%s %pad -> %pad\n",
-               dma->ops->name,
+       dev_dbg(dev, "%s[%d] %pad -> %pad\n",
+               rsnd_mod_name(mod), rsnd_mod_id(mod),
                &cfg.src_addr, &cfg.dst_addr);
 
        ret = dmaengine_slave_config(dmaen->chan, &cfg);
        if (ret < 0)
-               goto rsnd_dma_init_err;
+               goto rsnd_dma_attach_err;
+
+       dmac->dmaen_num++;
 
        return 0;
 
-rsnd_dma_init_err:
-       rsnd_dma_quit(io, dma);
+rsnd_dma_attach_err:
+       rsnd_dmaen_remove(mod, io, priv);
 rsnd_dma_channel_err:
 
        /*
@@ -214,22 +256,11 @@ rsnd_dma_channel_err:
        return -EAGAIN;
 }
 
-static void rsnd_dmaen_quit(struct rsnd_dai_stream *io, struct rsnd_dma *dma)
-{
-       struct rsnd_dmaen *dmaen = rsnd_dma_to_dmaen(dma);
-
-       if (dmaen->chan)
-               dma_release_channel(dmaen->chan);
-
-       dmaen->chan = NULL;
-}
-
-static struct rsnd_dma_ops rsnd_dmaen_ops = {
+static struct rsnd_mod_ops rsnd_dmaen_ops = {
        .name   = "audmac",
        .start  = rsnd_dmaen_start,
        .stop   = rsnd_dmaen_stop,
-       .init   = rsnd_dmaen_init,
-       .quit   = rsnd_dmaen_quit,
+       .remove = rsnd_dmaen_remove,
 };
 
 /*
@@ -307,7 +338,7 @@ static u32 rsnd_dmapp_get_chcr(struct rsnd_dai_stream *io,
         (0x10 * rsnd_dma_to_dmapp(dma)->dmapp_id))
 static void rsnd_dmapp_write(struct rsnd_dma *dma, u32 data, u32 reg)
 {
-       struct rsnd_mod *mod = rsnd_dma_to_mod(dma);
+       struct rsnd_mod *mod = rsnd_mod_get(dma);
        struct rsnd_priv *priv = rsnd_mod_to_priv(mod);
        struct rsnd_dma_ctrl *dmac = rsnd_priv_to_dmac(priv);
        struct device *dev = rsnd_priv_to_dev(priv);
@@ -319,38 +350,48 @@ static void rsnd_dmapp_write(struct rsnd_dma *dma, u32 data, u32 reg)
 
 static u32 rsnd_dmapp_read(struct rsnd_dma *dma, u32 reg)
 {
-       struct rsnd_mod *mod = rsnd_dma_to_mod(dma);
+       struct rsnd_mod *mod = rsnd_mod_get(dma);
        struct rsnd_priv *priv = rsnd_mod_to_priv(mod);
        struct rsnd_dma_ctrl *dmac = rsnd_priv_to_dmac(priv);
 
        return ioread32(rsnd_dmapp_addr(dmac, dma, reg));
 }
 
-static void rsnd_dmapp_stop(struct rsnd_dai_stream *io, struct rsnd_dma *dma)
+static int rsnd_dmapp_stop(struct rsnd_mod *mod,
+                          struct rsnd_dai_stream *io,
+                          struct rsnd_priv *priv)
 {
+       struct rsnd_dma *dma = rsnd_mod_to_dma(mod);
        int i;
 
        rsnd_dmapp_write(dma, 0, PDMACHCR);
 
        for (i = 0; i < 1024; i++) {
                if (0 == rsnd_dmapp_read(dma, PDMACHCR))
-                       return;
+                       return 0;
                udelay(1);
        }
+
+       return -EIO;
 }
 
-static void rsnd_dmapp_start(struct rsnd_dai_stream *io, struct rsnd_dma *dma)
+static int rsnd_dmapp_start(struct rsnd_mod *mod,
+                           struct rsnd_dai_stream *io,
+                           struct rsnd_priv *priv)
 {
+       struct rsnd_dma *dma = rsnd_mod_to_dma(mod);
        struct rsnd_dmapp *dmapp = rsnd_dma_to_dmapp(dma);
 
        rsnd_dmapp_write(dma, dma->src_addr,    PDMASAR);
        rsnd_dmapp_write(dma, dma->dst_addr,    PDMADAR);
        rsnd_dmapp_write(dma, dmapp->chcr,      PDMACHCR);
+
+       return 0;
 }
 
-static int rsnd_dmapp_init(struct rsnd_dai_stream *io,
-                          struct rsnd_dma *dma, int id,
-                          struct rsnd_mod *mod_from, struct rsnd_mod *mod_to)
+static int rsnd_dmapp_attach(struct rsnd_dai_stream *io,
+                            struct rsnd_dma *dma, int id,
+                            struct rsnd_mod *mod_from, struct rsnd_mod *mod_to)
 {
        struct rsnd_dmapp *dmapp = rsnd_dma_to_dmapp(dma);
        struct rsnd_priv *priv = rsnd_io_to_priv(io);
@@ -362,19 +403,16 @@ static int rsnd_dmapp_init(struct rsnd_dai_stream *io,
 
        dmac->dmapp_num++;
 
-       rsnd_dmapp_stop(io, dma);
-
        dev_dbg(dev, "id/src/dst/chcr = %d/%pad/%pad/%08x\n",
                dmapp->dmapp_id, &dma->src_addr, &dma->dst_addr, dmapp->chcr);
 
        return 0;
 }
 
-static struct rsnd_dma_ops rsnd_dmapp_ops = {
+static struct rsnd_mod_ops rsnd_dmapp_ops = {
        .name   = "audmac-pp",
        .start  = rsnd_dmapp_start,
        .stop   = rsnd_dmapp_stop,
-       .init   = rsnd_dmapp_init,
        .quit   = rsnd_dmapp_stop,
 };
 
@@ -497,13 +535,12 @@ static dma_addr_t rsnd_dma_addr(struct rsnd_dai_stream *io,
 }
 
 #define MOD_MAX (RSND_MOD_MAX + 1) /* +Memory */
-static void rsnd_dma_of_path(struct rsnd_dma *dma,
+static void rsnd_dma_of_path(struct rsnd_mod *this,
                             struct rsnd_dai_stream *io,
                             int is_play,
                             struct rsnd_mod **mod_from,
                             struct rsnd_mod **mod_to)
 {
-       struct rsnd_mod *this = rsnd_dma_to_mod(dma);
        struct rsnd_mod *ssi = rsnd_io_to_mod_ssi(io);
        struct rsnd_mod *src = rsnd_io_to_mod_src(io);
        struct rsnd_mod *ctu = rsnd_io_to_mod_ctu(io);
@@ -513,7 +550,7 @@ static void rsnd_dma_of_path(struct rsnd_dma *dma,
        struct rsnd_mod *mod_start, *mod_end;
        struct rsnd_priv *priv = rsnd_mod_to_priv(this);
        struct device *dev = rsnd_priv_to_dev(priv);
-       int nr, i;
+       int nr, i, idx;
 
        if (!ssi)
                return;
@@ -542,23 +579,24 @@ static void rsnd_dma_of_path(struct rsnd_dma *dma,
        mod_start       = (is_play) ? NULL : ssi;
        mod_end         = (is_play) ? ssi  : NULL;
 
-       mod[0] = mod_start;
+       idx = 0;
+       mod[idx++] = mod_start;
        for (i = 1; i < nr; i++) {
                if (src) {
-                       mod[i] = src;
+                       mod[idx++] = src;
                        src = NULL;
                } else if (ctu) {
-                       mod[i] = ctu;
+                       mod[idx++] = ctu;
                        ctu = NULL;
                } else if (mix) {
-                       mod[i] = mix;
+                       mod[idx++] = mix;
                        mix = NULL;
                } else if (dvc) {
-                       mod[i] = dvc;
+                       mod[idx++] = dvc;
                        dvc = NULL;
                }
        }
-       mod[i] = mod_end;
+       mod[idx] = mod_end;
 
        /*
         *              | SSI | SRC |
@@ -567,8 +605,8 @@ static void rsnd_dma_of_path(struct rsnd_dma *dma,
         * !is_play     |  *  |  o  |
         */
        if ((this == ssi) == (is_play)) {
-               *mod_from       = mod[nr - 1];
-               *mod_to         = mod[nr];
+               *mod_from       = mod[idx - 1];
+               *mod_to         = mod[idx];
        } else {
                *mod_from       = mod[0];
                *mod_to         = mod[1];
@@ -576,7 +614,7 @@ static void rsnd_dma_of_path(struct rsnd_dma *dma,
 
        dev_dbg(dev, "module connection (this is %s[%d])\n",
                rsnd_mod_name(this), rsnd_mod_id(this));
-       for (i = 0; i <= nr; i++) {
+       for (i = 0; i <= idx; i++) {
                dev_dbg(dev, "  %s[%d]%s\n",
                       rsnd_mod_name(mod[i]), rsnd_mod_id(mod[i]),
                       (mod[i] == *mod_from) ? " from" :
@@ -584,36 +622,22 @@ static void rsnd_dma_of_path(struct rsnd_dma *dma,
        }
 }
 
-void rsnd_dma_stop(struct rsnd_dai_stream *io, struct rsnd_dma *dma)
-{
-       dma->ops->stop(io, dma);
-}
-
-void rsnd_dma_start(struct rsnd_dai_stream *io, struct rsnd_dma *dma)
-{
-       dma->ops->start(io, dma);
-}
-
-void rsnd_dma_quit(struct rsnd_dai_stream *io, struct rsnd_dma *dma)
-{
-       struct rsnd_mod *mod = rsnd_dma_to_mod(dma);
-       struct rsnd_priv *priv = rsnd_mod_to_priv(mod);
-       struct rsnd_dma_ctrl *dmac = rsnd_priv_to_dmac(priv);
-
-       if (!dmac)
-               return;
-
-       dma->ops->quit(io, dma);
-}
-
-int rsnd_dma_init(struct rsnd_dai_stream *io, struct rsnd_dma *dma, int id)
+struct rsnd_mod *rsnd_dma_attach(struct rsnd_dai_stream *io,
+                                struct rsnd_mod *mod, int id)
 {
+       struct rsnd_mod *dma_mod;
        struct rsnd_mod *mod_from = NULL;
        struct rsnd_mod *mod_to = NULL;
        struct rsnd_priv *priv = rsnd_io_to_priv(io);
        struct rsnd_dma_ctrl *dmac = rsnd_priv_to_dmac(priv);
+       struct rsnd_dma *dma;
        struct device *dev = rsnd_priv_to_dev(priv);
+       struct rsnd_mod_ops *ops;
+       enum rsnd_mod_type type;
+       int (*attach)(struct rsnd_dai_stream *io, struct rsnd_dma *dma, int id,
+                     struct rsnd_mod *mod_from, struct rsnd_mod *mod_to);
        int is_play = rsnd_io_is_play(io);
+       int ret, dma_id;
 
        /*
         * DMA failed. try to PIO mode
@@ -622,35 +646,64 @@ int rsnd_dma_init(struct rsnd_dai_stream *io, struct rsnd_dma *dma, int id)
         *      rsnd_rdai_continuance_probe()
         */
        if (!dmac)
-               return -EAGAIN;
+               return ERR_PTR(-EAGAIN);
 
-       rsnd_dma_of_path(dma, io, is_play, &mod_from, &mod_to);
+       dma = devm_kzalloc(dev, sizeof(*dma), GFP_KERNEL);
+       if (!dma)
+               return ERR_PTR(-ENOMEM);
+
+       rsnd_dma_of_path(mod, io, is_play, &mod_from, &mod_to);
 
        dma->src_addr = rsnd_dma_addr(io, mod_from, is_play, 1);
        dma->dst_addr = rsnd_dma_addr(io, mod_to,   is_play, 0);
 
        /* for Gen2 */
-       if (mod_from && mod_to)
-               dma->ops = &rsnd_dmapp_ops;
-       else
-               dma->ops = &rsnd_dmaen_ops;
+       if (mod_from && mod_to) {
+               ops     = &rsnd_dmapp_ops;
+               attach  = rsnd_dmapp_attach;
+               dma_id  = dmac->dmapp_num;
+               type    = RSND_MOD_AUDMAPP;
+       } else {
+               ops     = &rsnd_dmaen_ops;
+               attach  = rsnd_dmaen_attach;
+               dma_id  = dmac->dmaen_num;
+               type    = RSND_MOD_AUDMA;
+       }
 
        /* for Gen1, overwrite */
-       if (rsnd_is_gen1(priv))
-               dma->ops = &rsnd_dmaen_ops;
+       if (rsnd_is_gen1(priv)) {
+               ops     = &rsnd_dmaen_ops;
+               attach  = rsnd_dmaen_attach;
+               dma_id  = dmac->dmaen_num;
+               type    = RSND_MOD_AUDMA;
+       }
+
+       dma_mod = rsnd_mod_get(dma);
+
+       ret = rsnd_mod_init(priv, dma_mod,
+                           ops, NULL, type, dma_id);
+       if (ret < 0)
+               return ERR_PTR(ret);
 
-       dev_dbg(dev, "%s %s[%d] -> %s[%d]\n",
-               dma->ops->name,
+       dev_dbg(dev, "%s[%d] %s[%d] -> %s[%d]\n",
+               rsnd_mod_name(dma_mod), rsnd_mod_id(dma_mod),
                rsnd_mod_name(mod_from), rsnd_mod_id(mod_from),
                rsnd_mod_name(mod_to),   rsnd_mod_id(mod_to));
 
-       return dma->ops->init(io, dma, id, mod_from, mod_to);
+       ret = attach(io, dma, id, mod_from, mod_to);
+       if (ret < 0)
+               return ERR_PTR(ret);
+
+       ret = rsnd_dai_connect(dma_mod, io, type);
+       if (ret < 0)
+               return ERR_PTR(ret);
+
+       return rsnd_mod_get(dma);
 }
 
-int rsnd_dma_probe(struct platform_device *pdev,
-                  const struct rsnd_of_data *of_data,
-                  struct rsnd_priv *priv)
+int rsnd_dma_probe(struct rsnd_priv *priv)
 {
+       struct platform_device *pdev = rsnd_priv_to_pdev(priv);
        struct device *dev = rsnd_priv_to_dev(priv);
        struct rsnd_dma_ctrl *dmac;
        struct resource *res;
index 58f690900e6d36a704be976b5a440550df76726a..d45ffe496397f84b4f68adc3377699f2e94e2308 100644 (file)
@@ -15,7 +15,6 @@
 #define DVC_NAME "dvc"
 
 struct rsnd_dvc {
-       struct rsnd_dvc_platform_info *info; /* rcar_snd.h */
        struct rsnd_mod mod;
        struct rsnd_kctrl_cfg_m volume;
        struct rsnd_kctrl_cfg_m mute;
@@ -24,6 +23,7 @@ struct rsnd_dvc {
        struct rsnd_kctrl_cfg_s rdown;  /* Ramp Rate Down */
 };
 
+#define rsnd_dvc_get(priv, id) ((struct rsnd_dvc *)(priv->dvc) + id)
 #define rsnd_dvc_nr(priv) ((priv)->dvc_nr)
 #define rsnd_dvc_of_node(priv) \
        of_get_child_by_name(rsnd_priv_to_dev(priv)->of_node, "rcar_sound,dvc")
@@ -64,79 +64,142 @@ static const char * const dvc_ramp_rate[] = {
        "0.125 dB/8192 steps",   /* 10111 */
 };
 
-static void rsnd_dvc_soft_reset(struct rsnd_mod *mod)
+static void rsnd_dvc_activation(struct rsnd_mod *mod)
 {
        rsnd_mod_write(mod, DVC_SWRSR, 0);
        rsnd_mod_write(mod, DVC_SWRSR, 1);
 }
 
-#define rsnd_dvc_initialize_lock(mod)  __rsnd_dvc_initialize_lock(mod, 1)
-#define rsnd_dvc_initialize_unlock(mod)        __rsnd_dvc_initialize_lock(mod, 0)
-static void __rsnd_dvc_initialize_lock(struct rsnd_mod *mod, u32 enable)
+static void rsnd_dvc_halt(struct rsnd_mod *mod)
 {
-       rsnd_mod_write(mod, DVC_DVUIR, enable);
+       rsnd_mod_write(mod, DVC_DVUIR, 1);
+       rsnd_mod_write(mod, DVC_SWRSR, 0);
 }
 
-static void rsnd_dvc_volume_update(struct rsnd_dai_stream *io,
-                                  struct rsnd_mod *mod)
+#define rsnd_dvc_get_vrpdr(dvc) (dvc->rup.val << 8 | dvc->rdown.val)
+#define rsnd_dvc_get_vrdbr(dvc) (0x3ff - (dvc->volume.val[0] >> 13))
+
+static void rsnd_dvc_volume_parameter(struct rsnd_dai_stream *io,
+                                             struct rsnd_mod *mod)
 {
        struct rsnd_dvc *dvc = rsnd_mod_to_dvc(mod);
        u32 val[RSND_DVC_CHANNELS];
-       u32 dvucr = 0;
-       u32 mute = 0;
        int i;
 
-       for (i = 0; i < dvc->mute.cfg.size; i++)
-               mute |= (!!dvc->mute.cfg.val[i]) << i;
+       /* Enable Ramp */
+       if (dvc->ren.val)
+               for (i = 0; i < RSND_DVC_CHANNELS; i++)
+                       val[i] = dvc->volume.cfg.max;
+       else
+               for (i = 0; i < RSND_DVC_CHANNELS; i++)
+                       val[i] = dvc->volume.val[i];
 
-       /* Disable DVC Register access */
-       rsnd_mod_write(mod, DVC_DVUER, 0);
+       /* Enable Digital Volume */
+       rsnd_mod_write(mod, DVC_VOL0R, val[0]);
+       rsnd_mod_write(mod, DVC_VOL1R, val[1]);
+       rsnd_mod_write(mod, DVC_VOL2R, val[2]);
+       rsnd_mod_write(mod, DVC_VOL3R, val[3]);
+       rsnd_mod_write(mod, DVC_VOL4R, val[4]);
+       rsnd_mod_write(mod, DVC_VOL5R, val[5]);
+       rsnd_mod_write(mod, DVC_VOL6R, val[6]);
+       rsnd_mod_write(mod, DVC_VOL7R, val[7]);
+}
+
+static void rsnd_dvc_volume_init(struct rsnd_dai_stream *io,
+                                struct rsnd_mod *mod)
+{
+       struct rsnd_dvc *dvc = rsnd_mod_to_dvc(mod);
+       u32 adinr = 0;
+       u32 dvucr = 0;
+       u32 vrctr = 0;
+       u32 vrpdr = 0;
+       u32 vrdbr = 0;
+
+       adinr = rsnd_get_adinr_bit(mod, io) |
+               rsnd_get_adinr_chan(mod, io);
+
+       /* Enable Digital Volume, Zero Cross Mute Mode */
+       dvucr |= 0x101;
 
        /* Enable Ramp */
        if (dvc->ren.val) {
                dvucr |= 0x10;
 
-               /* Digital Volume Max */
-               for (i = 0; i < RSND_DVC_CHANNELS; i++)
-                       val[i] = dvc->volume.cfg.max;
-
-               rsnd_mod_write(mod, DVC_VRCTR, 0xff);
-               rsnd_mod_write(mod, DVC_VRPDR, dvc->rup.val << 8 |
-                                              dvc->rdown.val);
                /*
                 * FIXME !!
                 * use scale-downed Digital Volume
                 * as Volume Ramp
                 * 7F FFFF -> 3FF
                 */
-               rsnd_mod_write(mod, DVC_VRDBR,
-                              0x3ff - (dvc->volume.val[0] >> 13));
-
-       } else {
-               for (i = 0; i < RSND_DVC_CHANNELS; i++)
-                       val[i] = dvc->volume.val[i];
+               vrctr = 0xff;
+               vrpdr = rsnd_dvc_get_vrpdr(dvc);
+               vrdbr = rsnd_dvc_get_vrdbr(dvc);
        }
 
-       /* Enable Digital Volume */
-       dvucr |= 0x100;
-       rsnd_mod_write(mod, DVC_VOL0R, val[0]);
-       rsnd_mod_write(mod, DVC_VOL1R, val[1]);
+       /* Initialize operation */
+       rsnd_mod_write(mod, DVC_DVUIR, 1);
+
+       /* General Information */
+       rsnd_mod_write(mod, DVC_ADINR, adinr);
+       rsnd_mod_write(mod, DVC_DVUCR, dvucr);
+
+       /* Volume Ramp Parameter */
+       rsnd_mod_write(mod, DVC_VRCTR, vrctr);
+       rsnd_mod_write(mod, DVC_VRPDR, vrpdr);
+       rsnd_mod_write(mod, DVC_VRDBR, vrdbr);
+
+       /* Digital Volume Function Parameter */
+       rsnd_dvc_volume_parameter(io, mod);
+
+       /* cancel operation */
+       rsnd_mod_write(mod, DVC_DVUIR, 0);
+}
+
+static void rsnd_dvc_volume_update(struct rsnd_dai_stream *io,
+                                  struct rsnd_mod *mod)
+{
+       struct rsnd_dvc *dvc = rsnd_mod_to_dvc(mod);
+       u32 zcmcr = 0;
+       u32 vrpdr = 0;
+       u32 vrdbr = 0;
+       int i;
+
+       for (i = 0; i < dvc->mute.cfg.size; i++)
+               zcmcr |= (!!dvc->mute.cfg.val[i]) << i;
 
-       /*  Enable Mute */
-       if (mute) {
-               dvucr |= 0x1;
-               rsnd_mod_write(mod, DVC_ZCMCR, mute);
+       if (dvc->ren.val) {
+               vrpdr = rsnd_dvc_get_vrpdr(dvc);
+               vrdbr = rsnd_dvc_get_vrdbr(dvc);
        }
 
-       rsnd_mod_write(mod, DVC_DVUCR, dvucr);
+       /* Disable DVC Register access */
+       rsnd_mod_write(mod, DVC_DVUER, 0);
+
+       /* Zero Cross Mute Function */
+       rsnd_mod_write(mod, DVC_ZCMCR, zcmcr);
+
+       /* Volume Ramp Function */
+       rsnd_mod_write(mod, DVC_VRPDR, vrpdr);
+       rsnd_mod_write(mod, DVC_VRDBR, vrdbr);
+       /* add DVC_VRWTR here */
+
+       /* Digital Volume Function Parameter */
+       rsnd_dvc_volume_parameter(io, mod);
 
        /* Enable DVC Register access */
        rsnd_mod_write(mod, DVC_DVUER, 1);
 }
 
-static int rsnd_dvc_remove_gen2(struct rsnd_mod *mod,
-                               struct rsnd_dai_stream *io,
-                               struct rsnd_priv *priv)
+static int rsnd_dvc_probe_(struct rsnd_mod *mod,
+                          struct rsnd_dai_stream *io,
+                          struct rsnd_priv *priv)
+{
+       return rsnd_cmd_attach(io, rsnd_mod_id(mod));
+}
+
+static int rsnd_dvc_remove_(struct rsnd_mod *mod,
+                           struct rsnd_dai_stream *io,
+                           struct rsnd_priv *priv)
 {
        struct rsnd_dvc *dvc = rsnd_mod_to_dvc(mod);
 
@@ -155,19 +218,12 @@ static int rsnd_dvc_init(struct rsnd_mod *mod,
 {
        rsnd_mod_power_on(mod);
 
-       rsnd_dvc_soft_reset(mod);
-
-       rsnd_dvc_initialize_lock(mod);
-
-       rsnd_path_parse(priv, io);
+       rsnd_dvc_activation(mod);
 
-       rsnd_mod_write(mod, DVC_ADINR, rsnd_get_adinr_bit(mod, io));
+       rsnd_dvc_volume_init(io, mod);
 
-       /* ch0/ch1 Volume */
        rsnd_dvc_volume_update(io, mod);
 
-       rsnd_adg_set_cmd_timsel_gen2(mod, io);
-
        return 0;
 }
 
@@ -175,27 +231,9 @@ static int rsnd_dvc_quit(struct rsnd_mod *mod,
                         struct rsnd_dai_stream *io,
                         struct rsnd_priv *priv)
 {
-       rsnd_mod_power_off(mod);
+       rsnd_dvc_halt(mod);
 
-       return 0;
-}
-
-static int rsnd_dvc_start(struct rsnd_mod *mod,
-                         struct rsnd_dai_stream *io,
-                         struct rsnd_priv *priv)
-{
-       rsnd_dvc_initialize_unlock(mod);
-
-       rsnd_mod_write(mod, CMD_CTRL, 0x10);
-
-       return 0;
-}
-
-static int rsnd_dvc_stop(struct rsnd_mod *mod,
-                        struct rsnd_dai_stream *io,
-                        struct rsnd_priv *priv)
-{
-       rsnd_mod_write(mod, CMD_CTRL, 0);
+       rsnd_mod_power_off(mod);
 
        return 0;
 }
@@ -206,6 +244,7 @@ static int rsnd_dvc_pcm_new(struct rsnd_mod *mod,
 {
        struct rsnd_dvc *dvc = rsnd_mod_to_dvc(mod);
        int is_play = rsnd_io_is_play(io);
+       int slots = rsnd_get_slot(io);
        int ret;
 
        /* Volume */
@@ -213,7 +252,8 @@ static int rsnd_dvc_pcm_new(struct rsnd_mod *mod,
                        is_play ?
                        "DVC Out Playback Volume" : "DVC In Capture Volume",
                        rsnd_dvc_volume_update,
-                       &dvc->volume, 0x00800000 - 1);
+                       &dvc->volume, slots,
+                       0x00800000 - 1);
        if (ret < 0)
                return ret;
 
@@ -222,7 +262,8 @@ static int rsnd_dvc_pcm_new(struct rsnd_mod *mod,
                        is_play ?
                        "DVC Out Mute Switch" : "DVC In Mute Switch",
                        rsnd_dvc_volume_update,
-                       &dvc->mute, 1);
+                       &dvc->mute,  slots,
+                       1);
        if (ret < 0)
                return ret;
 
@@ -269,11 +310,10 @@ static struct dma_chan *rsnd_dvc_dma_req(struct rsnd_dai_stream *io,
 static struct rsnd_mod_ops rsnd_dvc_ops = {
        .name           = DVC_NAME,
        .dma_req        = rsnd_dvc_dma_req,
-       .remove         = rsnd_dvc_remove_gen2,
+       .probe          = rsnd_dvc_probe_,
+       .remove         = rsnd_dvc_remove_,
        .init           = rsnd_dvc_init,
        .quit           = rsnd_dvc_quit,
-       .start          = rsnd_dvc_start,
-       .stop           = rsnd_dvc_stop,
        .pcm_new        = rsnd_dvc_pcm_new,
 };
 
@@ -282,50 +322,13 @@ struct rsnd_mod *rsnd_dvc_mod_get(struct rsnd_priv *priv, int id)
        if (WARN_ON(id < 0 || id >= rsnd_dvc_nr(priv)))
                id = 0;
 
-       return rsnd_mod_get((struct rsnd_dvc *)(priv->dvc) + id);
+       return rsnd_mod_get(rsnd_dvc_get(priv, id));
 }
 
-static void rsnd_of_parse_dvc(struct platform_device *pdev,
-                             const struct rsnd_of_data *of_data,
-                             struct rsnd_priv *priv)
+int rsnd_dvc_probe(struct rsnd_priv *priv)
 {
        struct device_node *node;
-       struct rsnd_dvc_platform_info *dvc_info;
-       struct rcar_snd_info *info = rsnd_priv_to_info(priv);
-       struct device *dev = &pdev->dev;
-       int nr;
-
-       if (!of_data)
-               return;
-
-       node = of_get_child_by_name(dev->of_node, "rcar_sound,dvc");
-       if (!node)
-               return;
-
-       nr = of_get_child_count(node);
-       if (!nr)
-               goto rsnd_of_parse_dvc_end;
-
-       dvc_info = devm_kzalloc(dev,
-                               sizeof(struct rsnd_dvc_platform_info) * nr,
-                               GFP_KERNEL);
-       if (!dvc_info) {
-               dev_err(dev, "dvc info allocation error\n");
-               goto rsnd_of_parse_dvc_end;
-       }
-
-       info->dvc_info          = dvc_info;
-       info->dvc_info_nr       = nr;
-
-rsnd_of_parse_dvc_end:
-       of_node_put(node);
-}
-
-int rsnd_dvc_probe(struct platform_device *pdev,
-                  const struct rsnd_of_data *of_data,
-                  struct rsnd_priv *priv)
-{
-       struct rcar_snd_info *info = rsnd_priv_to_info(priv);
+       struct device_node *np;
        struct device *dev = rsnd_priv_to_dev(priv);
        struct rsnd_dvc *dvc;
        struct clk *clk;
@@ -336,40 +339,54 @@ int rsnd_dvc_probe(struct platform_device *pdev,
        if (rsnd_is_gen1(priv))
                return 0;
 
-       rsnd_of_parse_dvc(pdev, of_data, priv);
+       node = rsnd_dvc_of_node(priv);
+       if (!node)
+               return 0; /* not used is not error */
 
-       nr = info->dvc_info_nr;
-       if (!nr)
-               return 0;
+       nr = of_get_child_count(node);
+       if (!nr) {
+               ret = -EINVAL;
+               goto rsnd_dvc_probe_done;
+       }
 
        dvc     = devm_kzalloc(dev, sizeof(*dvc) * nr, GFP_KERNEL);
-       if (!dvc)
-               return -ENOMEM;
+       if (!dvc) {
+               ret = -ENOMEM;
+               goto rsnd_dvc_probe_done;
+       }
 
        priv->dvc_nr    = nr;
        priv->dvc       = dvc;
 
-       for_each_rsnd_dvc(dvc, priv, i) {
+       i = 0;
+       ret = 0;
+       for_each_child_of_node(node, np) {
+               dvc = rsnd_dvc_get(priv, i);
+
                snprintf(name, RSND_DVC_NAME_SIZE, "%s.%d",
                         DVC_NAME, i);
 
                clk = devm_clk_get(dev, name);
-               if (IS_ERR(clk))
-                       return PTR_ERR(clk);
-
-               dvc->info = &info->dvc_info[i];
+               if (IS_ERR(clk)) {
+                       ret = PTR_ERR(clk);
+                       goto rsnd_dvc_probe_done;
+               }
 
                ret = rsnd_mod_init(priv, rsnd_mod_get(dvc), &rsnd_dvc_ops,
                              clk, RSND_MOD_DVC, i);
                if (ret)
-                       return ret;
+                       goto rsnd_dvc_probe_done;
+
+               i++;
        }
 
-       return 0;
+rsnd_dvc_probe_done:
+       of_node_put(node);
+
+       return ret;
 }
 
-void rsnd_dvc_remove(struct platform_device *pdev,
-                    struct rsnd_priv *priv)
+void rsnd_dvc_remove(struct rsnd_priv *priv)
 {
        struct rsnd_dvc *dvc;
        int i;
index 76da7620904c982ee1946f7db9369c7065028133..ea24247eba73c2fffc8bfdb4c56f2c6d7c9268c5 100644 (file)
@@ -31,29 +31,33 @@ struct rsnd_gen {
 
        /* RSND_REG_MAX base */
        struct regmap_field *regs[RSND_REG_MAX];
+       const char *reg_name[RSND_REG_MAX];
 };
 
 #define rsnd_priv_to_gen(p)    ((struct rsnd_gen *)(p)->gen)
+#define rsnd_reg_name(gen, id) ((gen)->reg_name[id])
 
 struct rsnd_regmap_field_conf {
        int idx;
        unsigned int reg_offset;
        unsigned int id_offset;
+       const char *reg_name;
 };
 
-#define RSND_REG_SET(id, offset, _id_offset)   \
+#define RSND_REG_SET(id, offset, _id_offset, n)        \
 {                                              \
        .idx = id,                              \
        .reg_offset = offset,                   \
        .id_offset = _id_offset,                \
+       .reg_name = n,                          \
 }
 /* single address mapping */
 #define RSND_GEN_S_REG(id, offset)     \
-       RSND_REG_SET(RSND_REG_##id, offset, 0)
+       RSND_REG_SET(RSND_REG_##id, offset, 0, #id)
 
 /* multi address mapping */
 #define RSND_GEN_M_REG(id, offset, _id_offset) \
-       RSND_REG_SET(RSND_REG_##id, offset, _id_offset)
+       RSND_REG_SET(RSND_REG_##id, offset, _id_offset, #id)
 
 /*
  *             basic function
@@ -83,8 +87,9 @@ u32 rsnd_read(struct rsnd_priv *priv,
 
        regmap_fields_read(gen->regs[reg], rsnd_mod_id(mod), &val);
 
-       dev_dbg(dev, "r %s[%d] - %4d : %08x\n",
-               rsnd_mod_name(mod), rsnd_mod_id(mod), reg, val);
+       dev_dbg(dev, "r %s[%d] - %-18s (%4d) : %08x\n",
+               rsnd_mod_name(mod), rsnd_mod_id(mod),
+               rsnd_reg_name(gen, reg), reg, val);
 
        return val;
 }
@@ -99,10 +104,11 @@ void rsnd_write(struct rsnd_priv *priv,
        if (!rsnd_is_accessible_reg(priv, gen, reg))
                return;
 
-       dev_dbg(dev, "w %s[%d] - %4d : %08x\n",
-               rsnd_mod_name(mod), rsnd_mod_id(mod), reg, data);
-
        regmap_fields_write(gen->regs[reg], rsnd_mod_id(mod), data);
+
+       dev_dbg(dev, "w %s[%d] - %-18s (%4d) : %08x\n",
+               rsnd_mod_name(mod), rsnd_mod_id(mod),
+               rsnd_reg_name(gen, reg), reg, data);
 }
 
 void rsnd_force_write(struct rsnd_priv *priv,
@@ -115,10 +121,11 @@ void rsnd_force_write(struct rsnd_priv *priv,
        if (!rsnd_is_accessible_reg(priv, gen, reg))
                return;
 
-       dev_dbg(dev, "w %s[%d] - %4d : %08x\n",
-               rsnd_mod_name(mod), rsnd_mod_id(mod), reg, data);
-
        regmap_fields_force_write(gen->regs[reg], rsnd_mod_id(mod), data);
+
+       dev_dbg(dev, "w %s[%d] - %-18s (%4d) : %08x\n",
+               rsnd_mod_name(mod), rsnd_mod_id(mod),
+               rsnd_reg_name(gen, reg), reg, data);
 }
 
 void rsnd_bset(struct rsnd_priv *priv, struct rsnd_mod *mod,
@@ -130,11 +137,13 @@ void rsnd_bset(struct rsnd_priv *priv, struct rsnd_mod *mod,
        if (!rsnd_is_accessible_reg(priv, gen, reg))
                return;
 
-       dev_dbg(dev, "b %s[%d] - %4d : %08x/%08x\n",
-               rsnd_mod_name(mod), rsnd_mod_id(mod), reg, data, mask);
-
        regmap_fields_update_bits(gen->regs[reg], rsnd_mod_id(mod),
                                  mask, data);
+
+       dev_dbg(dev, "b %s[%d] - %-18s (%4d) : %08x/%08x\n",
+               rsnd_mod_name(mod), rsnd_mod_id(mod),
+               rsnd_reg_name(gen, reg), reg, data, mask);
+
 }
 
 phys_addr_t rsnd_gen_get_phy_addr(struct rsnd_priv *priv, int reg_id)
@@ -150,7 +159,7 @@ static int _rsnd_gen_regmap_init(struct rsnd_priv *priv,
                                 int id_size,
                                 int reg_id,
                                 const char *name,
-                                struct rsnd_regmap_field_conf *conf,
+                                const struct rsnd_regmap_field_conf *conf,
                                 int conf_size)
 {
        struct platform_device *pdev = rsnd_priv_to_pdev(priv);
@@ -203,6 +212,7 @@ static int _rsnd_gen_regmap_init(struct rsnd_priv *priv,
 
                /* RSND_REG_MAX base */
                gen->regs[conf[i].idx] = regs;
+               gen->reg_name[conf[i].idx] = conf[i].reg_name;
        }
 
        return 0;
@@ -211,31 +221,37 @@ static int _rsnd_gen_regmap_init(struct rsnd_priv *priv,
 /*
  *             Gen2
  */
-static int rsnd_gen2_probe(struct platform_device *pdev,
-                          struct rsnd_priv *priv)
+static int rsnd_gen2_probe(struct rsnd_priv *priv)
 {
-       struct rsnd_regmap_field_conf conf_ssiu[] = {
+       const static struct rsnd_regmap_field_conf conf_ssiu[] = {
                RSND_GEN_S_REG(SSI_MODE0,       0x800),
                RSND_GEN_S_REG(SSI_MODE1,       0x804),
+               RSND_GEN_S_REG(SSI_MODE2,       0x808),
+               RSND_GEN_S_REG(SSI_CONTROL,     0x810),
+
                /* FIXME: it needs SSI_MODE2/3 in the future */
                RSND_GEN_M_REG(SSI_BUSIF_MODE,  0x0,    0x80),
                RSND_GEN_M_REG(SSI_BUSIF_ADINR, 0x4,    0x80),
                RSND_GEN_M_REG(SSI_BUSIF_DALIGN,0x8,    0x80),
+               RSND_GEN_M_REG(SSI_MODE,        0xc,    0x80),
                RSND_GEN_M_REG(SSI_CTRL,        0x10,   0x80),
                RSND_GEN_M_REG(SSI_INT_ENABLE,  0x18,   0x80),
        };
-       struct rsnd_regmap_field_conf conf_scu[] = {
-               RSND_GEN_M_REG(SRC_BUSIF_MODE,  0x0,    0x20),
+
+       const static struct rsnd_regmap_field_conf conf_scu[] = {
+               RSND_GEN_M_REG(SRC_I_BUSIF_MODE,0x0,    0x20),
+               RSND_GEN_M_REG(SRC_O_BUSIF_MODE,0x4,    0x20),
                RSND_GEN_M_REG(SRC_BUSIF_DALIGN,0x8,    0x20),
                RSND_GEN_M_REG(SRC_ROUTE_MODE0, 0xc,    0x20),
                RSND_GEN_M_REG(SRC_CTRL,        0x10,   0x20),
                RSND_GEN_M_REG(SRC_INT_ENABLE0, 0x18,   0x20),
+               RSND_GEN_M_REG(CMD_BUSIF_DALIGN,0x188,  0x20),
                RSND_GEN_M_REG(CMD_ROUTE_SLCT,  0x18c,  0x20),
                RSND_GEN_M_REG(CMD_CTRL,        0x190,  0x20),
                RSND_GEN_S_REG(SCU_SYS_STATUS0, 0x1c8),
                RSND_GEN_S_REG(SCU_SYS_INT_EN0, 0x1cc),
                RSND_GEN_S_REG(SCU_SYS_STATUS1, 0x1d0),
-               RSND_GEN_S_REG(SCU_SYS_INT_EN1, 0x1c4),
+               RSND_GEN_S_REG(SCU_SYS_INT_EN1, 0x1d4),
                RSND_GEN_M_REG(SRC_SWRSR,       0x200,  0x40),
                RSND_GEN_M_REG(SRC_SRCIR,       0x204,  0x40),
                RSND_GEN_M_REG(SRC_ADINR,       0x214,  0x40),
@@ -266,9 +282,15 @@ static int rsnd_gen2_probe(struct platform_device *pdev,
                RSND_GEN_M_REG(DVC_VRDBR,       0xe20,  0x100),
                RSND_GEN_M_REG(DVC_VOL0R,       0xe28,  0x100),
                RSND_GEN_M_REG(DVC_VOL1R,       0xe2c,  0x100),
+               RSND_GEN_M_REG(DVC_VOL2R,       0xe30,  0x100),
+               RSND_GEN_M_REG(DVC_VOL3R,       0xe34,  0x100),
+               RSND_GEN_M_REG(DVC_VOL4R,       0xe38,  0x100),
+               RSND_GEN_M_REG(DVC_VOL5R,       0xe3c,  0x100),
+               RSND_GEN_M_REG(DVC_VOL6R,       0xe40,  0x100),
+               RSND_GEN_M_REG(DVC_VOL7R,       0xe44,  0x100),
                RSND_GEN_M_REG(DVC_DVUER,       0xe48,  0x100),
        };
-       struct rsnd_regmap_field_conf conf_adg[] = {
+       const static struct rsnd_regmap_field_conf conf_adg[] = {
                RSND_GEN_S_REG(BRRA,            0x00),
                RSND_GEN_S_REG(BRRB,            0x04),
                RSND_GEN_S_REG(SSICKR,          0x08),
@@ -288,7 +310,7 @@ static int rsnd_gen2_probe(struct platform_device *pdev,
                RSND_GEN_S_REG(SRCOUT_TIMSEL4,  0x58),
                RSND_GEN_S_REG(CMDOUT_TIMSEL,   0x5c),
        };
-       struct rsnd_regmap_field_conf conf_ssi[] = {
+       const static struct rsnd_regmap_field_conf conf_ssi[] = {
                RSND_GEN_M_REG(SSICR,           0x00,   0x40),
                RSND_GEN_M_REG(SSISR,           0x04,   0x40),
                RSND_GEN_M_REG(SSITDR,          0x08,   0x40),
@@ -317,65 +339,30 @@ static int rsnd_gen2_probe(struct platform_device *pdev,
  *             Gen1
  */
 
-static int rsnd_gen1_probe(struct platform_device *pdev,
-                          struct rsnd_priv *priv)
+static int rsnd_gen1_probe(struct rsnd_priv *priv)
 {
-       struct rsnd_regmap_field_conf conf_sru[] = {
-               RSND_GEN_S_REG(SRC_ROUTE_SEL,   0x00),
-               RSND_GEN_S_REG(SRC_TMG_SEL0,    0x08),
-               RSND_GEN_S_REG(SRC_TMG_SEL1,    0x0c),
-               RSND_GEN_S_REG(SRC_TMG_SEL2,    0x10),
-               RSND_GEN_S_REG(SRC_ROUTE_CTRL,  0xc0),
-               RSND_GEN_S_REG(SSI_MODE0,       0xD0),
-               RSND_GEN_S_REG(SSI_MODE1,       0xD4),
-               RSND_GEN_M_REG(SRC_BUSIF_MODE,  0x20,   0x4),
-               RSND_GEN_M_REG(SRC_ROUTE_MODE0, 0x50,   0x8),
-               RSND_GEN_M_REG(SRC_SWRSR,       0x200,  0x40),
-               RSND_GEN_M_REG(SRC_SRCIR,       0x204,  0x40),
-               RSND_GEN_M_REG(SRC_ADINR,       0x214,  0x40),
-               RSND_GEN_M_REG(SRC_IFSCR,       0x21c,  0x40),
-               RSND_GEN_M_REG(SRC_IFSVR,       0x220,  0x40),
-               RSND_GEN_M_REG(SRC_SRCCR,       0x224,  0x40),
-               RSND_GEN_M_REG(SRC_MNFSR,       0x228,  0x40),
-               /*
-                * ADD US
-                *
-                * SRC_STATUS
-                * SRC_INT_EN
-                * SCU_SYS_STATUS0
-                * SCU_SYS_STATUS1
-                * SCU_SYS_INT_EN0
-                * SCU_SYS_INT_EN1
-                */
-       };
-       struct rsnd_regmap_field_conf conf_adg[] = {
+       const static struct rsnd_regmap_field_conf conf_adg[] = {
                RSND_GEN_S_REG(BRRA,            0x00),
                RSND_GEN_S_REG(BRRB,            0x04),
                RSND_GEN_S_REG(SSICKR,          0x08),
                RSND_GEN_S_REG(AUDIO_CLK_SEL0,  0x0c),
                RSND_GEN_S_REG(AUDIO_CLK_SEL1,  0x10),
-               RSND_GEN_S_REG(AUDIO_CLK_SEL3,  0x18),
-               RSND_GEN_S_REG(AUDIO_CLK_SEL4,  0x1c),
-               RSND_GEN_S_REG(AUDIO_CLK_SEL5,  0x20),
        };
-       struct rsnd_regmap_field_conf conf_ssi[] = {
+       const static struct rsnd_regmap_field_conf conf_ssi[] = {
                RSND_GEN_M_REG(SSICR,           0x00,   0x40),
                RSND_GEN_M_REG(SSISR,           0x04,   0x40),
                RSND_GEN_M_REG(SSITDR,          0x08,   0x40),
                RSND_GEN_M_REG(SSIRDR,          0x0c,   0x40),
                RSND_GEN_M_REG(SSIWSR,          0x20,   0x40),
        };
-       int ret_sru;
        int ret_adg;
        int ret_ssi;
 
-       ret_sru  = rsnd_gen_regmap_init(priv, 9, RSND_GEN1_SRU, "sru", conf_sru);
        ret_adg  = rsnd_gen_regmap_init(priv, 9, RSND_GEN1_ADG, "adg", conf_adg);
        ret_ssi  = rsnd_gen_regmap_init(priv, 9, RSND_GEN1_SSI, "ssi", conf_ssi);
-       if (ret_sru  < 0 ||
-           ret_adg  < 0 ||
+       if (ret_adg  < 0 ||
            ret_ssi  < 0)
-               return ret_sru | ret_adg | ret_ssi;
+               return ret_adg | ret_ssi;
 
        return 0;
 }
@@ -383,28 +370,12 @@ static int rsnd_gen1_probe(struct platform_device *pdev,
 /*
  *             Gen
  */
-static void rsnd_of_parse_gen(struct platform_device *pdev,
-                             const struct rsnd_of_data *of_data,
-                             struct rsnd_priv *priv)
-{
-       struct rcar_snd_info *info = priv->info;
-
-       if (!of_data)
-               return;
-
-       info->flags = of_data->flags;
-}
-
-int rsnd_gen_probe(struct platform_device *pdev,
-                  const struct rsnd_of_data *of_data,
-                  struct rsnd_priv *priv)
+int rsnd_gen_probe(struct rsnd_priv *priv)
 {
        struct device *dev = rsnd_priv_to_dev(priv);
        struct rsnd_gen *gen;
        int ret;
 
-       rsnd_of_parse_gen(pdev, of_data, priv);
-
        gen = devm_kzalloc(dev, sizeof(*gen), GFP_KERNEL);
        if (!gen) {
                dev_err(dev, "GEN allocate failed\n");
@@ -415,9 +386,9 @@ int rsnd_gen_probe(struct platform_device *pdev,
 
        ret = -ENODEV;
        if (rsnd_is_gen1(priv))
-               ret = rsnd_gen1_probe(pdev, priv);
+               ret = rsnd_gen1_probe(priv);
        else if (rsnd_is_gen2(priv))
-               ret = rsnd_gen2_probe(pdev, priv);
+               ret = rsnd_gen2_probe(priv);
 
        if (ret < 0)
                dev_err(dev, "unknown generation R-Car sound device\n");
index 953dd0be9b6026d4b21e952c371c5b9ee3d65a08..65542b6a89e9e3452b312369035983c98b70077d 100644 (file)
 #define MIX_NAME "mix"
 
 struct rsnd_mix {
-       struct rsnd_mix_platform_info *info; /* rcar_snd.h */
        struct rsnd_mod mod;
 };
 
+#define rsnd_mix_get(priv, id) ((struct rsnd_mix *)(priv->mix) + id)
 #define rsnd_mix_nr(priv) ((priv)->mix_nr)
 #define for_each_rsnd_mix(pos, priv, i)                                        \
        for ((i) = 0;                                                   \
@@ -24,58 +24,77 @@ struct rsnd_mix {
                     ((pos) = (struct rsnd_mix *)(priv)->mix + i);      \
             i++)
 
-
-static void rsnd_mix_soft_reset(struct rsnd_mod *mod)
+static void rsnd_mix_activation(struct rsnd_mod *mod)
 {
        rsnd_mod_write(mod, MIX_SWRSR, 0);
        rsnd_mod_write(mod, MIX_SWRSR, 1);
 }
 
-#define rsnd_mix_initialize_lock(mod)  __rsnd_mix_initialize_lock(mod, 1)
-#define rsnd_mix_initialize_unlock(mod)        __rsnd_mix_initialize_lock(mod, 0)
-static void __rsnd_mix_initialize_lock(struct rsnd_mod *mod, u32 enable)
+static void rsnd_mix_halt(struct rsnd_mod *mod)
+{
+       rsnd_mod_write(mod, MIX_MIXIR, 1);
+       rsnd_mod_write(mod, MIX_SWRSR, 0);
+}
+
+static void rsnd_mix_volume_parameter(struct rsnd_dai_stream *io,
+                                     struct rsnd_mod *mod)
 {
-       rsnd_mod_write(mod, MIX_MIXIR, enable);
+       rsnd_mod_write(mod, MIX_MDBAR, 0);
+       rsnd_mod_write(mod, MIX_MDBBR, 0);
+       rsnd_mod_write(mod, MIX_MDBCR, 0);
+       rsnd_mod_write(mod, MIX_MDBDR, 0);
+}
+
+static void rsnd_mix_volume_init(struct rsnd_dai_stream *io,
+                                struct rsnd_mod *mod)
+{
+       rsnd_mod_write(mod, MIX_MIXIR, 1);
+
+       /* General Information */
+       rsnd_mod_write(mod, MIX_ADINR, rsnd_get_adinr_chan(mod, io));
+
+       /* volume step */
+       rsnd_mod_write(mod, MIX_MIXMR, 0);
+       rsnd_mod_write(mod, MIX_MVPDR, 0);
+
+       /* common volume parameter */
+       rsnd_mix_volume_parameter(io, mod);
+
+       rsnd_mod_write(mod, MIX_MIXIR, 0);
 }
 
 static void rsnd_mix_volume_update(struct rsnd_dai_stream *io,
                                  struct rsnd_mod *mod)
 {
-
        /* Disable MIX dB setting */
        rsnd_mod_write(mod, MIX_MDBER, 0);
 
-       rsnd_mod_write(mod, MIX_MDBAR, 0);
-       rsnd_mod_write(mod, MIX_MDBBR, 0);
-       rsnd_mod_write(mod, MIX_MDBCR, 0);
-       rsnd_mod_write(mod, MIX_MDBDR, 0);
+       /* common volume parameter */
+       rsnd_mix_volume_parameter(io, mod);
 
        /* Enable MIX dB setting */
        rsnd_mod_write(mod, MIX_MDBER, 1);
 }
 
+static int rsnd_mix_probe_(struct rsnd_mod *mod,
+                          struct rsnd_dai_stream *io,
+                          struct rsnd_priv *priv)
+{
+       return rsnd_cmd_attach(io, rsnd_mod_id(mod));
+}
+
 static int rsnd_mix_init(struct rsnd_mod *mod,
                         struct rsnd_dai_stream *io,
                         struct rsnd_priv *priv)
 {
        rsnd_mod_power_on(mod);
 
-       rsnd_mix_soft_reset(mod);
-
-       rsnd_mix_initialize_lock(mod);
-
-       rsnd_mod_write(mod, MIX_ADINR, rsnd_get_adinr_chan(mod, io));
-
-       rsnd_path_parse(priv, io);
+       rsnd_mix_activation(mod);
 
-       /* volume step */
-       rsnd_mod_write(mod, MIX_MIXMR, 0);
-       rsnd_mod_write(mod, MIX_MVPDR, 0);
+       rsnd_mix_volume_init(io, mod);
 
        rsnd_mix_volume_update(io, mod);
 
-       rsnd_mix_initialize_unlock(mod);
-
        return 0;
 }
 
@@ -83,6 +102,8 @@ static int rsnd_mix_quit(struct rsnd_mod *mod,
                         struct rsnd_dai_stream *io,
                         struct rsnd_priv *priv)
 {
+       rsnd_mix_halt(mod);
+
        rsnd_mod_power_off(mod);
 
        return 0;
@@ -90,6 +111,7 @@ static int rsnd_mix_quit(struct rsnd_mod *mod,
 
 static struct rsnd_mod_ops rsnd_mix_ops = {
        .name           = MIX_NAME,
+       .probe          = rsnd_mix_probe_,
        .init           = rsnd_mix_init,
        .quit           = rsnd_mix_quit,
 };
@@ -99,51 +121,13 @@ struct rsnd_mod *rsnd_mix_mod_get(struct rsnd_priv *priv, int id)
        if (WARN_ON(id < 0 || id >= rsnd_mix_nr(priv)))
                id = 0;
 
-       return rsnd_mod_get((struct rsnd_mix *)(priv->mix) + id);
+       return rsnd_mod_get(rsnd_mix_get(priv, id));
 }
 
-static void rsnd_of_parse_mix(struct platform_device *pdev,
-                             const struct rsnd_of_data *of_data,
-                             struct rsnd_priv *priv)
+int rsnd_mix_probe(struct rsnd_priv *priv)
 {
        struct device_node *node;
-       struct rsnd_mix_platform_info *mix_info;
-       struct rcar_snd_info *info = rsnd_priv_to_info(priv);
-       struct device *dev = &pdev->dev;
-       int nr;
-
-       if (!of_data)
-               return;
-
-       node = of_get_child_by_name(dev->of_node, "rcar_sound,mix");
-       if (!node)
-               return;
-
-       nr = of_get_child_count(node);
-       if (!nr)
-               goto rsnd_of_parse_mix_end;
-
-       mix_info = devm_kzalloc(dev,
-                               sizeof(struct rsnd_mix_platform_info) * nr,
-                               GFP_KERNEL);
-       if (!mix_info) {
-               dev_err(dev, "mix info allocation error\n");
-               goto rsnd_of_parse_mix_end;
-       }
-
-       info->mix_info          = mix_info;
-       info->mix_info_nr       = nr;
-
-rsnd_of_parse_mix_end:
-       of_node_put(node);
-
-}
-
-int rsnd_mix_probe(struct platform_device *pdev,
-                  const struct rsnd_of_data *of_data,
-                  struct rsnd_priv *priv)
-{
-       struct rcar_snd_info *info = rsnd_priv_to_info(priv);
+       struct device_node *np;
        struct device *dev = rsnd_priv_to_dev(priv);
        struct rsnd_mix *mix;
        struct clk *clk;
@@ -154,40 +138,54 @@ int rsnd_mix_probe(struct platform_device *pdev,
        if (rsnd_is_gen1(priv))
                return 0;
 
-       rsnd_of_parse_mix(pdev, of_data, priv);
+       node = rsnd_mix_of_node(priv);
+       if (!node)
+               return 0; /* not used is not error */
 
-       nr = info->mix_info_nr;
-       if (!nr)
-               return 0;
+       nr = of_get_child_count(node);
+       if (!nr) {
+               ret = -EINVAL;
+               goto rsnd_mix_probe_done;
+       }
 
        mix     = devm_kzalloc(dev, sizeof(*mix) * nr, GFP_KERNEL);
-       if (!mix)
-               return -ENOMEM;
+       if (!mix) {
+               ret = -ENOMEM;
+               goto rsnd_mix_probe_done;
+       }
 
        priv->mix_nr    = nr;
        priv->mix       = mix;
 
-       for_each_rsnd_mix(mix, priv, i) {
+       i = 0;
+       ret = 0;
+       for_each_child_of_node(node, np) {
+               mix = rsnd_mix_get(priv, i);
+
                snprintf(name, MIX_NAME_SIZE, "%s.%d",
                         MIX_NAME, i);
 
                clk = devm_clk_get(dev, name);
-               if (IS_ERR(clk))
-                       return PTR_ERR(clk);
-
-               mix->info = &info->mix_info[i];
+               if (IS_ERR(clk)) {
+                       ret = PTR_ERR(clk);
+                       goto rsnd_mix_probe_done;
+               }
 
                ret = rsnd_mod_init(priv, rsnd_mod_get(mix), &rsnd_mix_ops,
                                    clk, RSND_MOD_MIX, i);
                if (ret)
-                       return ret;
+                       goto rsnd_mix_probe_done;
+
+               i++;
        }
 
-       return 0;
+rsnd_mix_probe_done:
+       of_node_put(node);
+
+       return ret;
 }
 
-void rsnd_mix_remove(struct platform_device *pdev,
-                    struct rsnd_priv *priv)
+void rsnd_mix_remove(struct rsnd_priv *priv)
 {
        struct rsnd_mix *mix;
        int i;
diff --git a/sound/soc/sh/rcar/rcar_snd.h b/sound/soc/sh/rcar/rcar_snd.h
deleted file mode 100644 (file)
index d8e33d3..0000000
+++ /dev/null
@@ -1,117 +0,0 @@
-/*
- * Renesas R-Car SRU/SCU/SSIU/SSI support
- *
- * Copyright (C) 2013 Renesas Solutions Corp.
- * Kuninori Morimoto <kuninori.morimoto.gx@renesas.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 RCAR_SND_H
-#define RCAR_SND_H
-
-
-#define RSND_GEN1_SRU  0
-#define RSND_GEN1_ADG  1
-#define RSND_GEN1_SSI  2
-
-#define RSND_GEN2_SCU  0
-#define RSND_GEN2_ADG  1
-#define RSND_GEN2_SSIU 2
-#define RSND_GEN2_SSI  3
-
-#define RSND_BASE_MAX  4
-
-/*
- * flags
- *
- * 0xAB000000
- *
- * A : clock sharing settings
- * B : SSI direction
- */
-#define RSND_SSI_CLK_PIN_SHARE         (1 << 31)
-#define RSND_SSI_NO_BUSIF              (1 << 30) /* SSI+DMA without BUSIF */
-
-#define RSND_SSI(_dma_id, _irq, _flags)                \
-{ .dma_id = _dma_id, .irq = _irq, .flags = _flags }
-#define RSND_SSI_UNUSED \
-{ .dma_id = -1, .irq = -1, .flags = 0 }
-
-struct rsnd_ssi_platform_info {
-       int dma_id;
-       int irq;
-       u32 flags;
-};
-
-#define RSND_SRC(rate, _dma_id)                                                \
-{ .convert_rate = rate, .dma_id = _dma_id, }
-#define RSND_SRC_UNUSED                                \
-{ .convert_rate = 0, .dma_id = -1, }
-
-struct rsnd_src_platform_info {
-       u32 convert_rate; /* sampling rate convert */
-       int dma_id; /* for Gen2 SCU */
-       int irq;
-};
-
-/*
- * flags
- */
-struct rsnd_ctu_platform_info {
-       u32 flags;
-};
-
-struct rsnd_mix_platform_info {
-       u32 flags;
-};
-
-struct rsnd_dvc_platform_info {
-       u32 flags;
-};
-
-struct rsnd_dai_path_info {
-       struct rsnd_ssi_platform_info *ssi;
-       struct rsnd_src_platform_info *src;
-       struct rsnd_ctu_platform_info *ctu;
-       struct rsnd_mix_platform_info *mix;
-       struct rsnd_dvc_platform_info *dvc;
-};
-
-struct rsnd_dai_platform_info {
-       struct rsnd_dai_path_info playback;
-       struct rsnd_dai_path_info capture;
-};
-
-/*
- * flags
- *
- * 0x0000000A
- *
- * A : generation
- */
-#define RSND_GEN_MASK  (0xF << 0)
-#define RSND_GEN1      (1 << 0) /* fixme */
-#define RSND_GEN2      (2 << 0) /* fixme */
-
-struct rcar_snd_info {
-       u32 flags;
-       struct rsnd_ssi_platform_info *ssi_info;
-       int ssi_info_nr;
-       struct rsnd_src_platform_info *src_info;
-       int src_info_nr;
-       struct rsnd_ctu_platform_info *ctu_info;
-       int ctu_info_nr;
-       struct rsnd_mix_platform_info *mix_info;
-       int mix_info_nr;
-       struct rsnd_dvc_platform_info *dvc_info;
-       int dvc_info_nr;
-       struct rsnd_dai_platform_info *dai_info;
-       int dai_info_nr;
-       int (*start)(int id);
-       int (*stop)(int id);
-};
-
-#endif
index 08532987852516cea79ed04051bf9b7ba62f3e51..317dd793149a7feb5279e2f665385a564c594469 100644 (file)
 #include <sound/soc.h>
 #include <sound/pcm_params.h>
 
-#include "rcar_snd.h"
+#define RSND_GEN1_SRU  0
+#define RSND_GEN1_ADG  1
+#define RSND_GEN1_SSI  2
+
+#define RSND_GEN2_SCU  0
+#define RSND_GEN2_ADG  1
+#define RSND_GEN2_SSIU 2
+#define RSND_GEN2_SSI  3
+
+#define RSND_BASE_MAX  4
 
 /*
  *     pseudo register
  * see gen1/gen2 for detail
  */
 enum rsnd_reg {
-       /* SRU/SCU/SSIU */
+       /* SCU (SRC/SSIU/MIX/CTU/DVC) */
+       RSND_REG_SSI_MODE,              /* Gen2 only */
        RSND_REG_SSI_MODE0,
        RSND_REG_SSI_MODE1,
-       RSND_REG_SRC_BUSIF_MODE,
+       RSND_REG_SSI_MODE2,
+       RSND_REG_SSI_CONTROL,
+       RSND_REG_SSI_CTRL,              /* Gen2 only */
+       RSND_REG_SSI_BUSIF_MODE,        /* Gen2 only */
+       RSND_REG_SSI_BUSIF_ADINR,       /* Gen2 only */
+       RSND_REG_SSI_BUSIF_DALIGN,      /* Gen2 only */
+       RSND_REG_SSI_INT_ENABLE,        /* Gen2 only */
+       RSND_REG_SRC_I_BUSIF_MODE,
+       RSND_REG_SRC_O_BUSIF_MODE,
        RSND_REG_SRC_ROUTE_MODE0,
        RSND_REG_SRC_SWRSR,
        RSND_REG_SRC_SRCIR,
@@ -45,9 +63,29 @@ enum rsnd_reg {
        RSND_REG_SRC_IFSCR,
        RSND_REG_SRC_IFSVR,
        RSND_REG_SRC_SRCCR,
+       RSND_REG_SRC_CTRL,              /* Gen2 only */
+       RSND_REG_SRC_BSDSR,             /* Gen2 only */
+       RSND_REG_SRC_BSISR,             /* Gen2 only */
+       RSND_REG_SRC_INT_ENABLE0,       /* Gen2 only */
+       RSND_REG_SRC_BUSIF_DALIGN,      /* Gen2 only */
+       RSND_REG_SRCIN_TIMSEL0,         /* Gen2 only */
+       RSND_REG_SRCIN_TIMSEL1,         /* Gen2 only */
+       RSND_REG_SRCIN_TIMSEL2,         /* Gen2 only */
+       RSND_REG_SRCIN_TIMSEL3,         /* Gen2 only */
+       RSND_REG_SRCIN_TIMSEL4,         /* Gen2 only */
+       RSND_REG_SRCOUT_TIMSEL0,        /* Gen2 only */
+       RSND_REG_SRCOUT_TIMSEL1,        /* Gen2 only */
+       RSND_REG_SRCOUT_TIMSEL2,        /* Gen2 only */
+       RSND_REG_SRCOUT_TIMSEL3,        /* Gen2 only */
+       RSND_REG_SRCOUT_TIMSEL4,        /* Gen2 only */
        RSND_REG_SCU_SYS_STATUS0,
+       RSND_REG_SCU_SYS_STATUS1,       /* Gen2 only */
        RSND_REG_SCU_SYS_INT_EN0,
+       RSND_REG_SCU_SYS_INT_EN1,       /* Gen2 only */
+       RSND_REG_CMD_CTRL,              /* Gen2 only */
+       RSND_REG_CMD_BUSIF_DALIGN,      /* Gen2 only */
        RSND_REG_CMD_ROUTE_SLCT,
+       RSND_REG_CMDOUT_TIMSEL,         /* Gen2 only */
        RSND_REG_CTU_CTUIR,
        RSND_REG_CTU_ADINR,
        RSND_REG_MIX_SWRSR,
@@ -67,14 +105,25 @@ enum rsnd_reg {
        RSND_REG_DVC_ZCMCR,
        RSND_REG_DVC_VOL0R,
        RSND_REG_DVC_VOL1R,
+       RSND_REG_DVC_VOL2R,
+       RSND_REG_DVC_VOL3R,
+       RSND_REG_DVC_VOL4R,
+       RSND_REG_DVC_VOL5R,
+       RSND_REG_DVC_VOL6R,
+       RSND_REG_DVC_VOL7R,
        RSND_REG_DVC_DVUER,
+       RSND_REG_DVC_VRCTR,             /* Gen2 only */
+       RSND_REG_DVC_VRPDR,             /* Gen2 only */
+       RSND_REG_DVC_VRDBR,             /* Gen2 only */
 
        /* ADG */
        RSND_REG_BRRA,
        RSND_REG_BRRB,
        RSND_REG_SSICKR,
+       RSND_REG_DIV_EN,                /* Gen2 only */
        RSND_REG_AUDIO_CLK_SEL0,
        RSND_REG_AUDIO_CLK_SEL1,
+       RSND_REG_AUDIO_CLK_SEL2,        /* Gen2 only */
 
        /* SSI */
        RSND_REG_SSICR,
@@ -83,83 +132,9 @@ enum rsnd_reg {
        RSND_REG_SSIRDR,
        RSND_REG_SSIWSR,
 
-       /* SHARE see below */
-       RSND_REG_SHARE01,
-       RSND_REG_SHARE02,
-       RSND_REG_SHARE03,
-       RSND_REG_SHARE04,
-       RSND_REG_SHARE05,
-       RSND_REG_SHARE06,
-       RSND_REG_SHARE07,
-       RSND_REG_SHARE08,
-       RSND_REG_SHARE09,
-       RSND_REG_SHARE10,
-       RSND_REG_SHARE11,
-       RSND_REG_SHARE12,
-       RSND_REG_SHARE13,
-       RSND_REG_SHARE14,
-       RSND_REG_SHARE15,
-       RSND_REG_SHARE16,
-       RSND_REG_SHARE17,
-       RSND_REG_SHARE18,
-       RSND_REG_SHARE19,
-       RSND_REG_SHARE20,
-       RSND_REG_SHARE21,
-       RSND_REG_SHARE22,
-       RSND_REG_SHARE23,
-       RSND_REG_SHARE24,
-       RSND_REG_SHARE25,
-       RSND_REG_SHARE26,
-       RSND_REG_SHARE27,
-       RSND_REG_SHARE28,
-       RSND_REG_SHARE29,
-
        RSND_REG_MAX,
 };
 
-/* Gen1 only */
-#define RSND_REG_SRC_ROUTE_SEL         RSND_REG_SHARE01
-#define RSND_REG_SRC_TMG_SEL0          RSND_REG_SHARE02
-#define RSND_REG_SRC_TMG_SEL1          RSND_REG_SHARE03
-#define RSND_REG_SRC_TMG_SEL2          RSND_REG_SHARE04
-#define RSND_REG_SRC_ROUTE_CTRL                RSND_REG_SHARE05
-#define RSND_REG_SRC_MNFSR             RSND_REG_SHARE06
-#define RSND_REG_AUDIO_CLK_SEL3                RSND_REG_SHARE07
-#define RSND_REG_AUDIO_CLK_SEL4                RSND_REG_SHARE08
-#define RSND_REG_AUDIO_CLK_SEL5                RSND_REG_SHARE09
-
-/* Gen2 only */
-#define RSND_REG_SRC_CTRL              RSND_REG_SHARE01
-#define RSND_REG_SSI_CTRL              RSND_REG_SHARE02
-#define RSND_REG_SSI_BUSIF_MODE                RSND_REG_SHARE03
-#define RSND_REG_SSI_BUSIF_ADINR       RSND_REG_SHARE04
-#define RSND_REG_SSI_INT_ENABLE                RSND_REG_SHARE05
-#define RSND_REG_SRC_BSDSR             RSND_REG_SHARE06
-#define RSND_REG_SRC_BSISR             RSND_REG_SHARE07
-#define RSND_REG_DIV_EN                        RSND_REG_SHARE08
-#define RSND_REG_SRCIN_TIMSEL0         RSND_REG_SHARE09
-#define RSND_REG_SRCIN_TIMSEL1         RSND_REG_SHARE10
-#define RSND_REG_SRCIN_TIMSEL2         RSND_REG_SHARE11
-#define RSND_REG_SRCIN_TIMSEL3         RSND_REG_SHARE12
-#define RSND_REG_SRCIN_TIMSEL4         RSND_REG_SHARE13
-#define RSND_REG_SRCOUT_TIMSEL0                RSND_REG_SHARE14
-#define RSND_REG_SRCOUT_TIMSEL1                RSND_REG_SHARE15
-#define RSND_REG_SRCOUT_TIMSEL2                RSND_REG_SHARE16
-#define RSND_REG_SRCOUT_TIMSEL3                RSND_REG_SHARE17
-#define RSND_REG_SRCOUT_TIMSEL4                RSND_REG_SHARE18
-#define RSND_REG_AUDIO_CLK_SEL2                RSND_REG_SHARE19
-#define RSND_REG_CMD_CTRL              RSND_REG_SHARE20
-#define RSND_REG_CMDOUT_TIMSEL         RSND_REG_SHARE21
-#define RSND_REG_SSI_BUSIF_DALIGN      RSND_REG_SHARE22
-#define RSND_REG_DVC_VRCTR             RSND_REG_SHARE23
-#define RSND_REG_DVC_VRPDR             RSND_REG_SHARE24
-#define RSND_REG_DVC_VRDBR             RSND_REG_SHARE25
-#define RSND_REG_SCU_SYS_STATUS1       RSND_REG_SHARE26
-#define RSND_REG_SCU_SYS_INT_EN1       RSND_REG_SHARE27
-#define RSND_REG_SRC_INT_ENABLE0       RSND_REG_SHARE28
-#define RSND_REG_SRC_BUSIF_DALIGN      RSND_REG_SHARE29
-
-struct rsnd_of_data;
 struct rsnd_priv;
 struct rsnd_mod;
 struct rsnd_dai;
@@ -187,43 +162,13 @@ void rsnd_bset(struct rsnd_priv *priv, struct rsnd_mod *mod, enum rsnd_reg reg,
 u32 rsnd_get_adinr_bit(struct rsnd_mod *mod, struct rsnd_dai_stream *io);
 u32 rsnd_get_adinr_chan(struct rsnd_mod *mod, struct rsnd_dai_stream *io);
 u32 rsnd_get_dalign(struct rsnd_mod *mod, struct rsnd_dai_stream *io);
-void rsnd_path_parse(struct rsnd_priv *priv,
-                    struct rsnd_dai_stream *io);
 
 /*
  *     R-Car DMA
  */
-struct rsnd_dma;
-
-struct rsnd_dmaen {
-       struct dma_chan         *chan;
-};
-
-struct rsnd_dmapp {
-       int                     dmapp_id;
-       u32                     chcr;
-};
-
-struct rsnd_dma {
-       struct rsnd_dma_ops     *ops;
-       dma_addr_t              src_addr;
-       dma_addr_t              dst_addr;
-       union {
-               struct rsnd_dmaen en;
-               struct rsnd_dmapp pp;
-       } dma;
-};
-#define rsnd_dma_to_dmaen(dma) (&(dma)->dma.en)
-#define rsnd_dma_to_dmapp(dma) (&(dma)->dma.pp)
-#define rsnd_dma_to_mod(_dma) container_of((_dma), struct rsnd_mod, dma)
-
-void rsnd_dma_start(struct rsnd_dai_stream *io, struct rsnd_dma *dma);
-void rsnd_dma_stop(struct rsnd_dai_stream *io, struct rsnd_dma *dma);
-int rsnd_dma_init(struct rsnd_dai_stream *io, struct rsnd_dma *dma, int id);
-void rsnd_dma_quit(struct rsnd_dai_stream *io, struct rsnd_dma *dma);
-int rsnd_dma_probe(struct platform_device *pdev,
-                  const struct rsnd_of_data *of_data,
-                  struct rsnd_priv *priv);
+struct rsnd_mod *rsnd_dma_attach(struct rsnd_dai_stream *io,
+                              struct rsnd_mod *mod, int id);
+int rsnd_dma_probe(struct rsnd_priv *priv);
 struct dma_chan *rsnd_dma_request_channel(struct device_node *of_node,
                                          struct rsnd_mod *mod, char *name);
 
@@ -231,11 +176,19 @@ struct dma_chan *rsnd_dma_request_channel(struct device_node *of_node,
  *     R-Car sound mod
  */
 enum rsnd_mod_type {
-       RSND_MOD_DVC = 0,
+       RSND_MOD_AUDMAPP,
+       RSND_MOD_AUDMA,
+       RSND_MOD_DVC,
        RSND_MOD_MIX,
        RSND_MOD_CTU,
+       RSND_MOD_CMD,
        RSND_MOD_SRC,
+       RSND_MOD_SSIM3,         /* SSI multi 3 */
+       RSND_MOD_SSIM2,         /* SSI multi 2 */
+       RSND_MOD_SSIM1,         /* SSI multi 1 */
+       RSND_MOD_SSIP,          /* SSI parent */
        RSND_MOD_SSI,
+       RSND_MOD_SSIU,
        RSND_MOD_MAX,
 };
 
@@ -278,10 +231,8 @@ struct rsnd_mod {
        int id;
        enum rsnd_mod_type type;
        struct rsnd_mod_ops *ops;
-       struct rsnd_dma dma;
        struct rsnd_priv *priv;
        struct clk *clk;
-       u32 status;
 };
 /*
  * status
@@ -328,7 +279,6 @@ struct rsnd_mod {
 #define __rsnd_mod_call_hw_params      0
 
 #define rsnd_mod_to_priv(mod) ((mod)->priv)
-#define rsnd_mod_to_dma(mod) (&(mod)->dma)
 #define rsnd_mod_id(mod) ((mod) ? (mod)->id : -1)
 #define rsnd_mod_power_on(mod) clk_enable((mod)->clk)
 #define rsnd_mod_power_off(mod)        clk_disable((mod)->clk)
@@ -347,6 +297,17 @@ struct dma_chan *rsnd_mod_dma_req(struct rsnd_dai_stream *io,
 void rsnd_mod_interrupt(struct rsnd_mod *mod,
                        void (*callback)(struct rsnd_mod *mod,
                                         struct rsnd_dai_stream *io));
+void rsnd_parse_connect_common(struct rsnd_dai *rdai,
+               struct rsnd_mod* (*mod_get)(struct rsnd_priv *priv, int id),
+               struct device_node *node,
+               struct device_node *playback,
+               struct device_node *capture);
+
+void rsnd_set_slot(struct rsnd_dai *rdai,
+                  int slots, int slots_total);
+int rsnd_get_slot(struct rsnd_dai_stream *io);
+int rsnd_get_slot_width(struct rsnd_dai_stream *io);
+int rsnd_get_slot_num(struct rsnd_dai_stream *io);
 
 /*
  *     R-Car sound DAI
@@ -358,6 +319,7 @@ struct rsnd_dai_stream {
        struct rsnd_mod *mod[RSND_MOD_MAX];
        struct rsnd_dai_path_info *info; /* rcar_snd.h */
        struct rsnd_dai *rdai;
+       u32 mod_status[RSND_MOD_MAX];
        int byte_pos;
        int period_pos;
        int byte_per_period;
@@ -365,10 +327,12 @@ struct rsnd_dai_stream {
 };
 #define rsnd_io_to_mod(io, i)  ((i) < RSND_MOD_MAX ? (io)->mod[(i)] : NULL)
 #define rsnd_io_to_mod_ssi(io) rsnd_io_to_mod((io), RSND_MOD_SSI)
+#define rsnd_io_to_mod_ssip(io)        rsnd_io_to_mod((io), RSND_MOD_SSIP)
 #define rsnd_io_to_mod_src(io) rsnd_io_to_mod((io), RSND_MOD_SRC)
 #define rsnd_io_to_mod_ctu(io) rsnd_io_to_mod((io), RSND_MOD_CTU)
 #define rsnd_io_to_mod_mix(io) rsnd_io_to_mod((io), RSND_MOD_MIX)
 #define rsnd_io_to_mod_dvc(io) rsnd_io_to_mod((io), RSND_MOD_DVC)
+#define rsnd_io_to_mod_cmd(io) rsnd_io_to_mod((io), RSND_MOD_CMD)
 #define rsnd_io_to_rdai(io)    ((io)->rdai)
 #define rsnd_io_to_priv(io)    (rsnd_rdai_to_priv(rsnd_io_to_rdai(io)))
 #define rsnd_io_is_play(io)    (&rsnd_io_to_rdai(io)->playback == io)
@@ -382,6 +346,9 @@ struct rsnd_dai {
        struct rsnd_dai_stream capture;
        struct rsnd_priv *priv;
 
+       int slots;
+       int slots_num;
+
        unsigned int clk_master:1;
        unsigned int bit_clk_inv:1;
        unsigned int frm_clk_inv:1;
@@ -403,33 +370,28 @@ struct rsnd_dai *rsnd_rdai_get(struct rsnd_priv *priv, int id);
 bool rsnd_dai_pointer_update(struct rsnd_dai_stream *io, int cnt);
 void rsnd_dai_period_elapsed(struct rsnd_dai_stream *io);
 int rsnd_dai_pointer_offset(struct rsnd_dai_stream *io, int additional);
+int rsnd_dai_connect(struct rsnd_mod *mod,
+                    struct rsnd_dai_stream *io,
+                    enum rsnd_mod_type type);
+#define rsnd_dai_of_node(priv)                                         \
+       of_get_child_by_name(rsnd_priv_to_dev(priv)->of_node, "rcar_sound,dai")
 
 /*
  *     R-Car Gen1/Gen2
  */
-int rsnd_gen_probe(struct platform_device *pdev,
-                  const struct rsnd_of_data *of_data,
-                  struct rsnd_priv *priv);
+int rsnd_gen_probe(struct rsnd_priv *priv);
 void __iomem *rsnd_gen_reg_get(struct rsnd_priv *priv,
                               struct rsnd_mod *mod,
                               enum rsnd_reg reg);
 phys_addr_t rsnd_gen_get_phy_addr(struct rsnd_priv *priv, int reg_id);
 
-#define rsnd_is_gen1(s)                (((s)->info->flags & RSND_GEN_MASK) == RSND_GEN1)
-#define rsnd_is_gen2(s)                (((s)->info->flags & RSND_GEN_MASK) == RSND_GEN2)
-
 /*
  *     R-Car ADG
  */
 int rsnd_adg_ssi_clk_stop(struct rsnd_mod *mod);
 int rsnd_adg_ssi_clk_try_start(struct rsnd_mod *mod, unsigned int rate);
-int rsnd_adg_probe(struct platform_device *pdev,
-                  const struct rsnd_of_data *of_data,
-                  struct rsnd_priv *priv);
-int rsnd_adg_set_convert_clk_gen1(struct rsnd_priv *priv,
-                                 struct rsnd_mod *mod,
-                                 unsigned int src_rate,
-                                 unsigned int dst_rate);
+int rsnd_adg_probe(struct rsnd_priv *priv);
+void rsnd_adg_remove(struct rsnd_priv *priv);
 int rsnd_adg_set_convert_clk_gen2(struct rsnd_mod *mod,
                                  struct rsnd_dai_stream *io,
                                  unsigned int src_rate,
@@ -442,15 +404,14 @@ int rsnd_adg_set_cmd_timsel_gen2(struct rsnd_mod *mod,
 /*
  *     R-Car sound priv
  */
-struct rsnd_of_data {
-       u32 flags;
-};
-
 struct rsnd_priv {
 
        struct platform_device *pdev;
-       struct rcar_snd_info *info;
        spinlock_t lock;
+       unsigned long flags;
+#define RSND_GEN_MASK  (0xF << 0)
+#define RSND_GEN1      (1 << 0)
+#define RSND_GEN2      (2 << 0)
 
        /*
         * below value will be filled on rsnd_gen_probe()
@@ -473,6 +434,12 @@ struct rsnd_priv {
        void *ssi;
        int ssi_nr;
 
+       /*
+        * below value will be filled on rsnd_ssiu_probe()
+        */
+       void *ssiu;
+       int ssiu_nr;
+
        /*
         * below value will be filled on rsnd_src_probe()
         */
@@ -497,6 +464,12 @@ struct rsnd_priv {
        void *dvc;
        int dvc_nr;
 
+       /*
+        * below value will be filled on rsnd_cmd_probe()
+        */
+       void *cmd;
+       int cmd_nr;
+
        /*
         * below value will be filled on rsnd_dai_probe()
         */
@@ -507,7 +480,9 @@ struct rsnd_priv {
 
 #define rsnd_priv_to_pdev(priv)        ((priv)->pdev)
 #define rsnd_priv_to_dev(priv) (&(rsnd_priv_to_pdev(priv)->dev))
-#define rsnd_priv_to_info(priv)        ((priv)->info)
+
+#define rsnd_is_gen1(priv)     (((priv)->flags & RSND_GEN_MASK) == RSND_GEN1)
+#define rsnd_is_gen2(priv)     (((priv)->flags & RSND_GEN_MASK) == RSND_GEN2)
 
 /*
  *     rsnd_kctrl
@@ -523,7 +498,7 @@ struct rsnd_kctrl_cfg {
        struct snd_kcontrol *kctrl;
 };
 
-#define RSND_DVC_CHANNELS      2
+#define RSND_DVC_CHANNELS      8
 struct rsnd_kctrl_cfg_m {
        struct rsnd_kctrl_cfg cfg;
        u32 val[RSND_DVC_CHANNELS];
@@ -544,6 +519,7 @@ int rsnd_kctrl_new_m(struct rsnd_mod *mod,
                     void (*update)(struct rsnd_dai_stream *io,
                                    struct rsnd_mod *mod),
                     struct rsnd_kctrl_cfg_m *_cfg,
+                    int ch_size,
                     u32 max);
 int rsnd_kctrl_new_s(struct rsnd_mod *mod,
                     struct rsnd_dai_stream *io,
@@ -566,70 +542,93 @@ int rsnd_kctrl_new_e(struct rsnd_mod *mod,
 /*
  *     R-Car SSI
  */
-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);
+int rsnd_ssi_probe(struct rsnd_priv *priv);
+void rsnd_ssi_remove(struct rsnd_priv *priv);
 struct rsnd_mod *rsnd_ssi_mod_get(struct rsnd_priv *priv, int id);
 int rsnd_ssi_is_dma_mode(struct rsnd_mod *mod);
 int rsnd_ssi_use_busif(struct rsnd_dai_stream *io);
+u32 rsnd_ssi_multi_slaves(struct rsnd_dai_stream *io);
 
 #define rsnd_ssi_is_pin_sharing(io)    \
        __rsnd_ssi_is_pin_sharing(rsnd_io_to_mod_ssi(io))
 int __rsnd_ssi_is_pin_sharing(struct rsnd_mod *mod);
 
+#define rsnd_ssi_of_node(priv)                                         \
+       of_get_child_by_name(rsnd_priv_to_dev(priv)->of_node, "rcar_sound,ssi")
+void rsnd_parse_connect_ssi(struct rsnd_dai *rdai,
+                           struct device_node *playback,
+                           struct device_node *capture);
+
+/*
+ *     R-Car SSIU
+ */
+int rsnd_ssiu_attach(struct rsnd_dai_stream *io,
+                    struct rsnd_mod *mod);
+int rsnd_ssiu_probe(struct rsnd_priv *priv);
+void rsnd_ssiu_remove(struct rsnd_priv *priv);
+
 /*
  *     R-Car SRC
  */
-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);
+int rsnd_src_probe(struct rsnd_priv *priv);
+void rsnd_src_remove(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,
                                   struct snd_pcm_runtime *runtime);
-int rsnd_src_ssiu_start(struct rsnd_mod *ssi_mod,
-                       struct rsnd_dai_stream *io,
-                       int use_busif);
-int rsnd_src_ssiu_stop(struct rsnd_mod *ssi_mod,
-                      struct rsnd_dai_stream *io);
-int rsnd_src_ssi_irq_enable(struct rsnd_mod *ssi_mod);
-int rsnd_src_ssi_irq_disable(struct rsnd_mod *ssi_mod);
+#define rsnd_src_of_node(priv)                                         \
+       of_get_child_by_name(rsnd_priv_to_dev(priv)->of_node, "rcar_sound,src")
+#define rsnd_parse_connect_src(rdai, playback, capture)                        \
+       rsnd_parse_connect_common(rdai, rsnd_src_mod_get,               \
+                                 rsnd_src_of_node(rsnd_rdai_to_priv(rdai)), \
+                                                  playback, capture)
 
 /*
  *     R-Car CTU
  */
-int rsnd_ctu_probe(struct platform_device *pdev,
-                  const struct rsnd_of_data *of_data,
-                  struct rsnd_priv *priv);
-
-void rsnd_ctu_remove(struct platform_device *pdev,
-                    struct rsnd_priv *priv);
+int rsnd_ctu_probe(struct rsnd_priv *priv);
+void rsnd_ctu_remove(struct rsnd_priv *priv);
 struct rsnd_mod *rsnd_ctu_mod_get(struct rsnd_priv *priv, int id);
+#define rsnd_ctu_of_node(priv)                                         \
+       of_get_child_by_name(rsnd_priv_to_dev(priv)->of_node, "rcar_sound,ctu")
+#define rsnd_parse_connect_ctu(rdai, playback, capture)                        \
+       rsnd_parse_connect_common(rdai, rsnd_ctu_mod_get,               \
+                                 rsnd_ctu_of_node(rsnd_rdai_to_priv(rdai)), \
+                                                  playback, capture)
 
 /*
  *     R-Car MIX
  */
-int rsnd_mix_probe(struct platform_device *pdev,
-                  const struct rsnd_of_data *of_data,
-                  struct rsnd_priv *priv);
-
-void rsnd_mix_remove(struct platform_device *pdev,
-                    struct rsnd_priv *priv);
+int rsnd_mix_probe(struct rsnd_priv *priv);
+void rsnd_mix_remove(struct rsnd_priv *priv);
 struct rsnd_mod *rsnd_mix_mod_get(struct rsnd_priv *priv, int id);
+#define rsnd_mix_of_node(priv)                                         \
+       of_get_child_by_name(rsnd_priv_to_dev(priv)->of_node, "rcar_sound,mix")
+#define rsnd_parse_connect_mix(rdai, playback, capture)                        \
+       rsnd_parse_connect_common(rdai, rsnd_mix_mod_get,               \
+                                 rsnd_mix_of_node(rsnd_rdai_to_priv(rdai)), \
+                                                  playback, capture)
 
 /*
  *     R-Car DVC
  */
-int rsnd_dvc_probe(struct platform_device *pdev,
-                  const struct rsnd_of_data *of_data,
-                  struct rsnd_priv *priv);
-void rsnd_dvc_remove(struct platform_device *pdev,
-                    struct rsnd_priv *priv);
+int rsnd_dvc_probe(struct rsnd_priv *priv);
+void rsnd_dvc_remove(struct rsnd_priv *priv);
 struct rsnd_mod *rsnd_dvc_mod_get(struct rsnd_priv *priv, int id);
+#define rsnd_dvc_of_node(priv)                                         \
+       of_get_child_by_name(rsnd_priv_to_dev(priv)->of_node, "rcar_sound,dvc")
+#define rsnd_parse_connect_dvc(rdai, playback, capture)                        \
+       rsnd_parse_connect_common(rdai, rsnd_dvc_mod_get,               \
+                                 rsnd_dvc_of_node(rsnd_rdai_to_priv(rdai)), \
+                                                  playback, capture)
+
+/*
+ *     R-Car CMD
+ */
+int rsnd_cmd_probe(struct rsnd_priv *priv);
+void rsnd_cmd_remove(struct rsnd_priv *priv);
+int rsnd_cmd_attach(struct rsnd_dai_stream *io, int id);
+struct rsnd_mod *rsnd_cmd_mod_get(struct rsnd_priv *priv, int id);
 
 #ifdef DEBUG
 void rsnd_mod_make_sure(struct rsnd_mod *mod, enum rsnd_mod_type type);
index d61db9c385eafd3bc6fca47edad10bff696b3ba2..8a357fdf1077c91822d6699dcf79e7aa96574809 100644 (file)
@@ -48,8 +48,11 @@ MODULE_DEVICE_TABLE(of, rsrc_card_of_match);
 
 #define DAI_NAME_NUM   32
 struct rsrc_card_dai {
-       unsigned int fmt;
        unsigned int sysclk;
+       unsigned int tx_slot_mask;
+       unsigned int rx_slot_mask;
+       int slots;
+       int slot_width;
        struct clk *clk;
        char dai_name[DAI_NAME_NUM];
 };
@@ -75,7 +78,7 @@ static int rsrc_card_startup(struct snd_pcm_substream *substream)
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
        struct rsrc_card_priv *priv =   snd_soc_card_get_drvdata(rtd->card);
        struct rsrc_card_dai *dai_props =
-               rsrc_priv_to_props(priv, rtd - rtd->card->rtd);
+               rsrc_priv_to_props(priv, rtd->num);
 
        return clk_prepare_enable(dai_props->clk);
 }
@@ -85,7 +88,7 @@ static void rsrc_card_shutdown(struct snd_pcm_substream *substream)
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
        struct rsrc_card_priv *priv =   snd_soc_card_get_drvdata(rtd->card);
        struct rsrc_card_dai *dai_props =
-               rsrc_priv_to_props(priv, rtd - rtd->card->rtd);
+               rsrc_priv_to_props(priv, rtd->num);
 
        clk_disable_unprepare(dai_props->clk);
 }
@@ -101,7 +104,7 @@ static int rsrc_card_dai_init(struct snd_soc_pcm_runtime *rtd)
        struct snd_soc_dai *dai;
        struct snd_soc_dai_link *dai_link;
        struct rsrc_card_dai *dai_props;
-       int num = rtd - rtd->card->rtd;
+       int num = rtd->num;
        int ret;
 
        dai_link        = rsrc_priv_to_link(priv, num);
@@ -110,18 +113,22 @@ static int rsrc_card_dai_init(struct snd_soc_pcm_runtime *rtd)
                                rtd->cpu_dai :
                                rtd->codec_dai;
 
-       if (dai_props->fmt) {
-               ret = snd_soc_dai_set_fmt(dai, dai_props->fmt);
+       if (dai_props->sysclk) {
+               ret = snd_soc_dai_set_sysclk(dai, 0, dai_props->sysclk, 0);
                if (ret && ret != -ENOTSUPP) {
-                       dev_err(dai->dev, "set_fmt error\n");
+                       dev_err(dai->dev, "set_sysclk error\n");
                        goto err;
                }
        }
 
-       if (dai_props->sysclk) {
-               ret = snd_soc_dai_set_sysclk(dai, 0, dai_props->sysclk, 0);
+       if (dai_props->slots) {
+               ret = snd_soc_dai_set_tdm_slot(dai,
+                                              dai_props->tx_slot_mask,
+                                              dai_props->rx_slot_mask,
+                                              dai_props->slots,
+                                              dai_props->slot_width);
                if (ret && ret != -ENOTSUPP) {
-                       dev_err(dai->dev, "set_sysclk error\n");
+                       dev_err(dai->dev, "set_tdm_slot error\n");
                        goto err;
                }
        }
@@ -148,14 +155,13 @@ static int rsrc_card_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
 }
 
 static int rsrc_card_parse_daifmt(struct device_node *node,
-                                 struct device_node *np,
+                                 struct device_node *codec,
                                  struct rsrc_card_priv *priv,
-                                 int idx, bool is_fe)
+                                 struct snd_soc_dai_link *dai_link,
+                                 unsigned int *retfmt)
 {
-       struct rsrc_card_dai *dai_props = rsrc_priv_to_props(priv, idx);
        struct device_node *bitclkmaster = NULL;
        struct device_node *framemaster = NULL;
-       struct device_node *codec = is_fe ? NULL : np;
        unsigned int daifmt;
 
        daifmt = snd_soc_of_parse_daifmt(node, NULL,
@@ -172,11 +178,11 @@ static int rsrc_card_parse_daifmt(struct device_node *node,
                daifmt |= (codec == framemaster) ?
                        SND_SOC_DAIFMT_CBS_CFM : SND_SOC_DAIFMT_CBS_CFS;
 
-       dai_props->fmt  = daifmt;
-
        of_node_put(bitclkmaster);
        of_node_put(framemaster);
 
+       *retfmt = daifmt;
+
        return 0;
 }
 
@@ -198,6 +204,15 @@ static int rsrc_card_parse_links(struct device_node *np,
        if (ret)
                return ret;
 
+       /* Parse TDM slot */
+       ret = snd_soc_of_parse_tdm_slot(np,
+                                       &dai_props->tx_slot_mask,
+                                       &dai_props->rx_slot_mask,
+                                       &dai_props->slots,
+                                       &dai_props->slot_width);
+       if (ret)
+               return ret;
+
        if (is_fe) {
                /* BE is dummy */
                dai_link->codec_of_node         = NULL;
@@ -208,7 +223,9 @@ static int rsrc_card_parse_links(struct device_node *np,
                dai_link->dynamic               = 1;
                dai_link->dpcm_merged_format    = 1;
                dai_link->cpu_of_node           = args.np;
-               snd_soc_of_get_dai_name(np, &dai_link->cpu_dai_name);
+               ret = snd_soc_of_get_dai_name(np, &dai_link->cpu_dai_name);
+               if (ret < 0)
+                       return ret;
 
                /* set dai_name */
                snprintf(dai_props->dai_name, DAI_NAME_NUM, "fe.%s",
@@ -240,7 +257,9 @@ static int rsrc_card_parse_links(struct device_node *np,
                dai_link->no_pcm                = 1;
                dai_link->be_hw_params_fixup    = rsrc_card_be_hw_params_fixup;
                dai_link->codec_of_node         = args.np;
-               snd_soc_of_get_dai_name(np, &dai_link->codec_dai_name);
+               ret = snd_soc_of_get_dai_name(np, &dai_link->codec_dai_name);
+               if (ret < 0)
+                       return ret;
 
                /* additional name prefix */
                if (of_data) {
@@ -305,23 +324,16 @@ static int rsrc_card_parse_clk(struct device_node *np,
        return 0;
 }
 
-static int rsrc_card_dai_link_of(struct device_node *node,
-                                struct device_node *np,
-                                struct rsrc_card_priv *priv,
-                                int idx)
+static int rsrc_card_dai_sub_link_of(struct device_node *node,
+                                    struct device_node *np,
+                                    struct rsrc_card_priv *priv,
+                                    int idx, bool is_fe)
 {
        struct device *dev = rsrc_priv_to_dev(priv);
+       struct snd_soc_dai_link *dai_link = rsrc_priv_to_link(priv, idx);
        struct rsrc_card_dai *dai_props = rsrc_priv_to_props(priv, idx);
-       bool is_fe = false;
        int ret;
 
-       if (0 == strcmp(np->name, "cpu"))
-               is_fe = true;
-
-       ret = rsrc_card_parse_daifmt(node, np, priv, idx, is_fe);
-       if (ret < 0)
-               return ret;
-
        ret = rsrc_card_parse_links(np, priv, idx, is_fe);
        if (ret < 0)
                return ret;
@@ -332,12 +344,54 @@ static int rsrc_card_dai_link_of(struct device_node *node,
 
        dev_dbg(dev, "\t%s / %04x / %d\n",
                dai_props->dai_name,
-               dai_props->fmt,
+               dai_link->dai_fmt,
                dai_props->sysclk);
 
        return ret;
 }
 
+static int rsrc_card_dai_link_of(struct device_node *node,
+                                struct rsrc_card_priv *priv)
+{
+       struct snd_soc_dai_link *dai_link;
+       struct device_node *np;
+       unsigned int daifmt = 0;
+       int ret, i;
+       bool is_fe;
+
+       /* find 1st codec */
+       i = 0;
+       for_each_child_of_node(node, np) {
+               dai_link = rsrc_priv_to_link(priv, i);
+
+               if (strcmp(np->name, "codec") == 0) {
+                       ret = rsrc_card_parse_daifmt(node, np, priv,
+                                                    dai_link, &daifmt);
+                       if (ret < 0)
+                               return ret;
+                       break;
+               }
+               i++;
+       }
+
+       i = 0;
+       for_each_child_of_node(node, np) {
+               dai_link = rsrc_priv_to_link(priv, i);
+               dai_link->dai_fmt = daifmt;
+
+               is_fe = false;
+               if (strcmp(np->name, "cpu") == 0)
+                       is_fe = true;
+
+               ret = rsrc_card_dai_sub_link_of(node, np, priv, i, is_fe);
+               if (ret < 0)
+                       return ret;
+               i++;
+       }
+
+       return 0;
+}
+
 static int rsrc_card_parse_of(struct device_node *node,
                              struct rsrc_card_priv *priv,
                              struct device *dev)
@@ -345,9 +399,8 @@ static int rsrc_card_parse_of(struct device_node *node,
        const struct rsrc_card_of_data *of_data = rsrc_dev_to_of_data(dev);
        struct rsrc_card_dai *props;
        struct snd_soc_dai_link *links;
-       struct device_node *np;
        int ret;
-       int i, num;
+       int num;
 
        if (!node)
                return -EINVAL;
@@ -388,13 +441,9 @@ static int rsrc_card_parse_of(struct device_node *node,
                priv->snd_card.name ? priv->snd_card.name : "",
                priv->convert_rate);
 
-       i = 0;
-       for_each_child_of_node(node, np) {
-               ret = rsrc_card_dai_link_of(node, np, priv, i);
-               if (ret < 0)
-                       return ret;
-               i++;
-       }
+       ret = rsrc_card_dai_link_of(node, priv);
+       if (ret < 0)
+               return ret;
 
        if (!priv->snd_card.name)
                priv->snd_card.name = priv->snd_card.dai_link->name;
index 261b50217c48d94f0a66f44c513f685755ddae07..5eda056d9f20ed8ef3137da612c63ae9d2cba067 100644 (file)
 #define OUF_SRC(id)    ((1 << (id + 16)) | (1 << id))
 
 struct rsnd_src {
-       struct rsnd_src_platform_info *info; /* rcar_snd.h */
        struct rsnd_mod mod;
+       struct rsnd_mod *dma;
        struct rsnd_kctrl_cfg_s sen;  /* sync convert enable */
        struct rsnd_kctrl_cfg_s sync; /* sync convert */
        u32 convert_rate; /* sampling rate convert */
        int err;
+       int irq;
 };
 
 #define RSND_SRC_NAME_SIZE 16
 
+#define rsnd_src_get(priv, id) ((struct rsnd_src *)(priv->src) + id)
+#define rsnd_src_to_dma(src) ((src)->dma)
 #define rsnd_src_nr(priv) ((priv)->src_nr)
 #define rsnd_enable_sync_convert(src) ((src)->sen.val)
-#define rsnd_src_of_node(priv) \
-       of_get_child_by_name(rsnd_priv_to_dev(priv)->of_node, "rcar_sound,src")
 
 #define rsnd_mod_to_src(_mod)                          \
        container_of((_mod), struct rsnd_src, mod)
@@ -69,67 +70,16 @@ struct rsnd_src {
  *        |-----------------|
  */
 
-/*
- *     How to use SRC bypass mode for debugging
- *
- * SRC has bypass mode, and it is useful for debugging.
- * In Gen2 case,
- * SRCm_MODE controls whether SRC is used or not
- * SSI_MODE0 controls whether SSIU which receives SRC data
- * is used or not.
- * Both SRCm_MODE/SSI_MODE0 settings are needed if you use SRC,
- * but SRC bypass mode needs SSI_MODE0 only.
- *
- * This driver request
- * struct rsnd_src_platform_info {
- *     u32 convert_rate;
- *     int dma_id;
- * }
- *
- * rsnd_src_convert_rate() indicates
- * above convert_rate, and it controls
- * whether SRC is used or not.
- *
- * ex) doesn't use SRC
- * static struct rsnd_dai_platform_info rsnd_dai = {
- *     .playback = { .ssi = &rsnd_ssi[0], },
- * };
- *
- * ex) uses SRC
- * static struct rsnd_src_platform_info rsnd_src[] = {
- *     RSND_SCU(48000, 0),
- *     ...
- * };
- * static struct rsnd_dai_platform_info rsnd_dai = {
- *     .playback = { .ssi = &rsnd_ssi[0], .src = &rsnd_src[0] },
- * };
- *
- * ex) uses SRC bypass mode
- * static struct rsnd_src_platform_info rsnd_src[] = {
- *     RSND_SCU(0, 0),
- *     ...
- * };
- * static struct rsnd_dai_platform_info rsnd_dai = {
- *     .playback = { .ssi = &rsnd_ssi[0], .src = &rsnd_src[0] },
- * };
- *
- */
-
-/*
- *             Gen1/Gen2 common functions
- */
-static void rsnd_src_soft_reset(struct rsnd_mod *mod)
+static void rsnd_src_activation(struct rsnd_mod *mod)
 {
        rsnd_mod_write(mod, SRC_SWRSR, 0);
        rsnd_mod_write(mod, SRC_SWRSR, 1);
 }
 
-
-#define rsnd_src_initialize_lock(mod)  __rsnd_src_initialize_lock(mod, 1)
-#define rsnd_src_initialize_unlock(mod)        __rsnd_src_initialize_lock(mod, 0)
-static void __rsnd_src_initialize_lock(struct rsnd_mod *mod, u32 enable)
+static void rsnd_src_halt(struct rsnd_mod *mod)
 {
-       rsnd_mod_write(mod, SRC_SRCIR, enable);
+       rsnd_mod_write(mod, SRC_SRCIR, 1);
+       rsnd_mod_write(mod, SRC_SWRSR, 0);
 }
 
 static struct dma_chan *rsnd_src_dma_req(struct rsnd_dai_stream *io,
@@ -143,99 +93,6 @@ static struct dma_chan *rsnd_src_dma_req(struct rsnd_dai_stream *io,
                                        is_play ? "rx" : "tx");
 }
 
-int rsnd_src_ssiu_start(struct rsnd_mod *ssi_mod,
-                       struct rsnd_dai_stream *io,
-                       int use_busif)
-{
-       struct rsnd_dai *rdai = rsnd_io_to_rdai(io);
-       int ssi_id = rsnd_mod_id(ssi_mod);
-
-       /*
-        * SSI_MODE0
-        */
-       rsnd_mod_bset(ssi_mod, SSI_MODE0, (1 << ssi_id),
-                     !use_busif << ssi_id);
-
-       /*
-        * SSI_MODE1
-        */
-       if (rsnd_ssi_is_pin_sharing(io)) {
-               int shift = -1;
-               switch (ssi_id) {
-               case 1:
-                       shift = 0;
-                       break;
-               case 2:
-                       shift = 2;
-                       break;
-               case 4:
-                       shift = 16;
-                       break;
-               }
-
-               if (shift >= 0)
-                       rsnd_mod_bset(ssi_mod, SSI_MODE1,
-                                     0x3 << shift,
-                                     rsnd_rdai_is_clk_master(rdai) ?
-                                     0x2 << shift : 0x1 << shift);
-       }
-
-       /*
-        * DMA settings for SSIU
-        */
-       if (use_busif) {
-               u32 val = rsnd_get_dalign(ssi_mod, io);
-
-               rsnd_mod_write(ssi_mod, SSI_BUSIF_ADINR,
-                              rsnd_get_adinr_bit(ssi_mod, io));
-               rsnd_mod_write(ssi_mod, SSI_BUSIF_MODE,  1);
-               rsnd_mod_write(ssi_mod, SSI_CTRL, 0x1);
-
-               rsnd_mod_write(ssi_mod, SSI_BUSIF_DALIGN, val);
-       }
-
-       return 0;
-}
-
-int rsnd_src_ssiu_stop(struct rsnd_mod *ssi_mod,
-                      struct rsnd_dai_stream *io)
-{
-       /*
-        * DMA settings for SSIU
-        */
-       rsnd_mod_write(ssi_mod, SSI_CTRL, 0);
-
-       return 0;
-}
-
-int rsnd_src_ssi_irq_enable(struct rsnd_mod *ssi_mod)
-{
-       struct rsnd_priv *priv = rsnd_mod_to_priv(ssi_mod);
-
-       if (rsnd_is_gen1(priv))
-               return 0;
-
-       /* enable SSI interrupt if Gen2 */
-       rsnd_mod_write(ssi_mod, SSI_INT_ENABLE,
-                      rsnd_ssi_is_dma_mode(ssi_mod) ?
-                      0x0e000000 : 0x0f000000);
-
-       return 0;
-}
-
-int rsnd_src_ssi_irq_disable(struct rsnd_mod *ssi_mod)
-{
-       struct rsnd_priv *priv = rsnd_mod_to_priv(ssi_mod);
-
-       if (rsnd_is_gen1(priv))
-               return 0;
-
-       /* disable SSI interrupt if Gen2 */
-       rsnd_mod_write(ssi_mod, SSI_INT_ENABLE, 0x00000000);
-
-       return 0;
-}
-
 static u32 rsnd_src_convert_rate(struct rsnd_dai_stream *io,
                                 struct rsnd_src *src)
 {
@@ -283,34 +140,6 @@ unsigned int rsnd_src_get_ssi_rate(struct rsnd_priv *priv,
        return rate;
 }
 
-static int rsnd_src_set_convert_rate(struct rsnd_mod *mod,
-                                    struct rsnd_dai_stream *io)
-{
-       struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io);
-       struct rsnd_src *src = rsnd_mod_to_src(mod);
-       u32 convert_rate = rsnd_src_convert_rate(io, src);
-       u32 fsrate = 0;
-
-       if (convert_rate)
-               fsrate = 0x0400000 / convert_rate * runtime->rate;
-
-       /* Set channel number and output bit length */
-       rsnd_mod_write(mod, SRC_ADINR, rsnd_get_adinr_bit(mod, io));
-
-       /* Enable the initial value of IFS */
-       if (fsrate) {
-               rsnd_mod_write(mod, SRC_IFSCR, 1);
-
-               /* Set initial value of IFS */
-               rsnd_mod_write(mod, SRC_IFSVR, fsrate);
-       }
-
-       /* use DMA transfer */
-       rsnd_mod_write(mod, SRC_BUSIF_MODE, 1);
-
-       return 0;
-}
-
 static int rsnd_src_hw_params(struct rsnd_mod *mod,
                              struct rsnd_dai_stream *io,
                              struct snd_pcm_substream *substream,
@@ -319,9 +148,6 @@ static int rsnd_src_hw_params(struct rsnd_mod *mod,
        struct rsnd_src *src = rsnd_mod_to_src(mod);
        struct snd_soc_pcm_runtime *fe = substream->private_data;
 
-       /* default value (mainly for non-DT) */
-       src->convert_rate = src->info->convert_rate;
-
        /*
         * SRC assumes that it is used under DPCM if user want to use
         * sampling rate convert. Then, SRC should be FE.
@@ -347,250 +173,112 @@ static int rsnd_src_hw_params(struct rsnd_mod *mod,
        return 0;
 }
 
-static int rsnd_src_init(struct rsnd_mod *mod,
-                        struct rsnd_priv *priv)
-{
-       struct rsnd_src *src = rsnd_mod_to_src(mod);
-
-       rsnd_mod_power_on(mod);
-
-       rsnd_src_soft_reset(mod);
-
-       rsnd_src_initialize_lock(mod);
-
-       src->err = 0;
-
-       /* reset sync convert_rate */
-       src->sync.val = 0;
-
-       return 0;
-}
-
-static int rsnd_src_quit(struct rsnd_mod *mod,
-                        struct rsnd_dai_stream *io,
-                        struct rsnd_priv *priv)
+static void rsnd_src_set_convert_rate(struct rsnd_dai_stream *io,
+                                     struct rsnd_mod *mod)
 {
-       struct rsnd_src *src = rsnd_mod_to_src(mod);
+       struct rsnd_priv *priv = rsnd_mod_to_priv(mod);
        struct device *dev = rsnd_priv_to_dev(priv);
+       struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io);
+       struct rsnd_src *src = rsnd_mod_to_src(mod);
+       u32 convert_rate = rsnd_src_convert_rate(io, src);
+       u32 ifscr, fsrate, adinr;
+       u32 cr, route;
+       u32 bsdsr, bsisr;
+       uint ratio;
 
-       rsnd_mod_power_off(mod);
-
-       if (src->err)
-               dev_warn(dev, "%s[%d] under/over flow err = %d\n",
-                        rsnd_mod_name(mod), rsnd_mod_id(mod), src->err);
-
-       src->convert_rate = 0;
-
-       /* reset sync convert_rate */
-       src->sync.val = 0;
-
-       return 0;
-}
-
-static int rsnd_src_start(struct rsnd_mod *mod)
-{
-       rsnd_src_initialize_unlock(mod);
-
-       return 0;
-}
-
-static int rsnd_src_stop(struct rsnd_mod *mod)
-{
-       /* nothing to do */
-       return 0;
-}
+       if (!runtime)
+               return;
 
-/*
- *             Gen1 functions
- */
-static int rsnd_src_set_route_gen1(struct rsnd_dai_stream *io,
-                                  struct rsnd_mod *mod)
-{
-       struct src_route_config {
-               u32 mask;
-               int shift;
-       } routes[] = {
-               { 0xF,  0, }, /* 0 */
-               { 0xF,  4, }, /* 1 */
-               { 0xF,  8, }, /* 2 */
-               { 0x7, 12, }, /* 3 */
-               { 0x7, 16, }, /* 4 */
-               { 0x7, 20, }, /* 5 */
-               { 0x7, 24, }, /* 6 */
-               { 0x3, 28, }, /* 7 */
-               { 0x3, 30, }, /* 8 */
-       };
-       u32 mask;
-       u32 val;
-       int id;
+       /* 6 - 1/6 are very enough ratio for SRC_BSDSR */
+       if (!convert_rate)
+               ratio = 0;
+       else if (convert_rate > runtime->rate)
+               ratio = 100 * convert_rate / runtime->rate;
+       else
+               ratio = 100 * runtime->rate / convert_rate;
 
-       id = rsnd_mod_id(mod);
-       if (id < 0 || id >= ARRAY_SIZE(routes))
-               return -EIO;
+       if (ratio > 600) {
+               dev_err(dev, "FSO/FSI ratio error\n");
+               return;
+       }
 
        /*
-        * SRC_ROUTE_SELECT
+        *      SRC_ADINR
         */
-       val = rsnd_io_is_play(io) ? 0x1 : 0x2;
-       val = val               << routes[id].shift;
-       mask = routes[id].mask  << routes[id].shift;
-
-       rsnd_mod_bset(mod, SRC_ROUTE_SEL, mask, val);
-
-       return 0;
-}
-
-static int rsnd_src_set_convert_timing_gen1(struct rsnd_dai_stream *io,
-                                           struct rsnd_mod *mod)
-{
-       struct rsnd_priv *priv = rsnd_mod_to_priv(mod);
-       struct rsnd_src *src = rsnd_mod_to_src(mod);
-       struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io);
-       u32 convert_rate = rsnd_src_convert_rate(io, src);
-       u32 mask;
-       u32 val;
-       int shift;
-       int id = rsnd_mod_id(mod);
-       int ret;
+       adinr = rsnd_get_adinr_bit(mod, io) |
+               rsnd_get_adinr_chan(mod, io);
 
        /*
-        * SRC_TIMING_SELECT
+        *      SRC_IFSCR / SRC_IFSVR
         */
-       shift   = (id % 4) * 8;
-       mask    = 0x1F << shift;
+       ifscr = 0;
+       fsrate = 0;
+       if (convert_rate) {
+               ifscr = 1;
+               fsrate = 0x0400000 / convert_rate * runtime->rate;
+       }
 
        /*
-        * ADG is used as source clock if SRC was used,
-        * then, SSI WS is used as destination clock.
-        * SSI WS is used as source clock if SRC is not used
-        * (when playback, source/destination become reverse when capture)
+        *      SRC_SRCCR / SRC_ROUTE_MODE0
         */
-       ret = 0;
+       cr      = 0x00011110;
+       route   = 0x0;
        if (convert_rate) {
-               /* use ADG */
-               val = 0;
-               ret = rsnd_adg_set_convert_clk_gen1(priv, mod,
-                                                   runtime->rate,
-                                                   convert_rate);
-       } else if (8 == id) {
-               /* use SSI WS, but SRU8 is special */
-               val = id << shift;
-       } else {
-               /* use SSI WS */
-               val = (id + 1) << shift;
-       }
+               route   = 0x1;
 
-       if (ret < 0)
-               return ret;
+               if (rsnd_enable_sync_convert(src)) {
+                       cr |= 0x1;
+                       route |= rsnd_io_is_play(io) ?
+                               (0x1 << 24) : (0x1 << 25);
+               }
+       }
 
-       switch (id / 4) {
-       case 0:
-               rsnd_mod_bset(mod, SRC_TMG_SEL0, mask, val);
-               break;
-       case 1:
-               rsnd_mod_bset(mod, SRC_TMG_SEL1, mask, val);
+       /*
+        * SRC_BSDSR / SRC_BSISR
+        */
+       switch (rsnd_mod_id(mod)) {
+       case 5:
+       case 6:
+       case 7:
+       case 8:
+               bsdsr = 0x02400000; /* 6 - 1/6 */
+               bsisr = 0x00100060; /* 6 - 1/6 */
                break;
-       case 2:
-               rsnd_mod_bset(mod, SRC_TMG_SEL2, mask, val);
+       default:
+               bsdsr = 0x01800000; /* 6 - 1/6 */
+               bsisr = 0x00100060 ;/* 6 - 1/6 */
                break;
        }
 
-       return 0;
-}
-
-static int rsnd_src_set_convert_rate_gen1(struct rsnd_mod *mod,
-                                         struct rsnd_dai_stream *io)
-{
-       struct rsnd_src *src = rsnd_mod_to_src(mod);
-       int ret;
-
-       ret = rsnd_src_set_convert_rate(mod, io);
-       if (ret < 0)
-               return ret;
-
-       /* Select SRC mode (fixed value) */
-       rsnd_mod_write(mod, SRC_SRCCR, 0x00010110);
-
-       /* Set the restriction value of the FS ratio (98%) */
-       rsnd_mod_write(mod, SRC_MNFSR,
-                      rsnd_mod_read(mod, SRC_IFSVR) / 100 * 98);
-
-       /* Gen1/Gen2 are not compatible */
-       if (rsnd_src_convert_rate(io, src))
-               rsnd_mod_write(mod, SRC_ROUTE_MODE0, 1);
-
-       /* no SRC_BFSSR settings, since SRC_SRCCR::BUFMD is 0 */
-
-       return 0;
-}
-
-static int rsnd_src_init_gen1(struct rsnd_mod *mod,
-                             struct rsnd_dai_stream *io,
-                             struct rsnd_priv *priv)
-{
-       int ret;
-
-       ret = rsnd_src_init(mod, priv);
-       if (ret < 0)
-               return ret;
-
-       ret = rsnd_src_set_route_gen1(io, mod);
-       if (ret < 0)
-               return ret;
-
-       ret = rsnd_src_set_convert_rate_gen1(mod, io);
-       if (ret < 0)
-               return ret;
-
-       ret = rsnd_src_set_convert_timing_gen1(io, mod);
-       if (ret < 0)
-               return ret;
-
-       return 0;
-}
-
-static int rsnd_src_start_gen1(struct rsnd_mod *mod,
-                              struct rsnd_dai_stream *io,
-                              struct rsnd_priv *priv)
-{
-       int id = rsnd_mod_id(mod);
-
-       rsnd_mod_bset(mod, SRC_ROUTE_CTRL, (1 << id), (1 << id));
-
-       return rsnd_src_start(mod);
-}
-
-static int rsnd_src_stop_gen1(struct rsnd_mod *mod,
-                             struct rsnd_dai_stream *io,
-                             struct rsnd_priv *priv)
-{
-       int id = rsnd_mod_id(mod);
+       rsnd_mod_write(mod, SRC_SRCIR, 1);      /* initialize */
+       rsnd_mod_write(mod, SRC_ADINR, adinr);
+       rsnd_mod_write(mod, SRC_IFSCR, ifscr);
+       rsnd_mod_write(mod, SRC_IFSVR, fsrate);
+       rsnd_mod_write(mod, SRC_SRCCR, cr);
+       rsnd_mod_write(mod, SRC_BSDSR, bsdsr);
+       rsnd_mod_write(mod, SRC_BSISR, bsisr);
+       rsnd_mod_write(mod, SRC_SRCIR, 0);      /* cancel initialize */
 
-       rsnd_mod_bset(mod, SRC_ROUTE_CTRL, (1 << id), 0);
+       rsnd_mod_write(mod, SRC_ROUTE_MODE0, route);
+       rsnd_mod_write(mod, SRC_I_BUSIF_MODE, 1);
+       rsnd_mod_write(mod, SRC_O_BUSIF_MODE, 1);
+       rsnd_mod_write(mod, SRC_BUSIF_DALIGN, rsnd_get_dalign(mod, io));
 
-       return rsnd_src_stop(mod);
+       if (convert_rate)
+               rsnd_adg_set_convert_clk_gen2(mod, io,
+                                             runtime->rate,
+                                             convert_rate);
+       else
+               rsnd_adg_set_convert_timing_gen2(mod, io);
 }
 
-static struct rsnd_mod_ops rsnd_src_gen1_ops = {
-       .name   = SRC_NAME,
-       .dma_req = rsnd_src_dma_req,
-       .init   = rsnd_src_init_gen1,
-       .quit   = rsnd_src_quit,
-       .start  = rsnd_src_start_gen1,
-       .stop   = rsnd_src_stop_gen1,
-       .hw_params = rsnd_src_hw_params,
-};
-
-/*
- *             Gen2 functions
- */
-#define rsnd_src_irq_enable_gen2(mod)  rsnd_src_irq_ctrol_gen2(mod, 1)
-#define rsnd_src_irq_disable_gen2(mod) rsnd_src_irq_ctrol_gen2(mod, 0)
-static void rsnd_src_irq_ctrol_gen2(struct rsnd_mod *mod, int enable)
+#define rsnd_src_irq_enable(mod)  rsnd_src_irq_ctrol(mod, 1)
+#define rsnd_src_irq_disable(mod) rsnd_src_irq_ctrol(mod, 0)
+static void rsnd_src_irq_ctrol(struct rsnd_mod *mod, int enable)
 {
        struct rsnd_src *src = rsnd_mod_to_src(mod);
        u32 sys_int_val, int_val, sys_int_mask;
-       int irq = src->info->irq;
+       int irq = src->irq;
        int id = rsnd_mod_id(mod);
 
        sys_int_val =
@@ -600,7 +288,7 @@ static void rsnd_src_irq_ctrol_gen2(struct rsnd_mod *mod, int enable)
        /*
         * IRQ is not supported on non-DT
         * see
-        *      rsnd_src_probe_gen2()
+        *      rsnd_src_probe_()
         */
        if ((irq <= 0) || !enable) {
                sys_int_val = 0;
@@ -620,7 +308,7 @@ static void rsnd_src_irq_ctrol_gen2(struct rsnd_mod *mod, int enable)
        rsnd_mod_bset(mod, SCU_SYS_INT_EN1, sys_int_mask, sys_int_val);
 }
 
-static void rsnd_src_error_clear_gen2(struct rsnd_mod *mod)
+static void rsnd_src_status_clear(struct rsnd_mod *mod)
 {
        u32 val = OUF_SRC(rsnd_mod_id(mod));
 
@@ -628,7 +316,7 @@ static void rsnd_src_error_clear_gen2(struct rsnd_mod *mod)
        rsnd_mod_bset(mod, SCU_SYS_STATUS1, val, val);
 }
 
-static bool rsnd_src_error_record_gen2(struct rsnd_mod *mod)
+static bool rsnd_src_record_error(struct rsnd_mod *mod)
 {
        struct rsnd_src *src = rsnd_mod_to_src(mod);
        u32 val0, val1;
@@ -652,22 +340,16 @@ static bool rsnd_src_error_record_gen2(struct rsnd_mod *mod)
                ret = true;
        }
 
-       /* clear error static */
-       rsnd_src_error_clear_gen2(mod);
-
        return ret;
 }
 
-static int _rsnd_src_start_gen2(struct rsnd_mod *mod,
-                               struct rsnd_dai_stream *io)
+static int rsnd_src_start(struct rsnd_mod *mod,
+                         struct rsnd_dai_stream *io,
+                         struct rsnd_priv *priv)
 {
        struct rsnd_src *src = rsnd_mod_to_src(mod);
        u32 val;
 
-       val = rsnd_get_dalign(mod, io);
-
-       rsnd_mod_write(mod, SRC_BUSIF_DALIGN, val);
-
        /*
         * WORKAROUND
         *
@@ -678,251 +360,154 @@ static int _rsnd_src_start_gen2(struct rsnd_mod *mod,
 
        rsnd_mod_write(mod, SRC_CTRL, val);
 
-       rsnd_src_error_clear_gen2(mod);
-
-       rsnd_src_start(mod);
+       return 0;
+}
 
-       rsnd_src_irq_enable_gen2(mod);
+static int rsnd_src_stop(struct rsnd_mod *mod,
+                        struct rsnd_dai_stream *io,
+                        struct rsnd_priv *priv)
+{
+       /*
+        * stop SRC output only
+        * see rsnd_src_quit
+        */
+       rsnd_mod_write(mod, SRC_CTRL, 0x01);
 
        return 0;
 }
 
-static int _rsnd_src_stop_gen2(struct rsnd_mod *mod)
+static int rsnd_src_init(struct rsnd_mod *mod,
+                        struct rsnd_dai_stream *io,
+                        struct rsnd_priv *priv)
 {
-       rsnd_src_irq_disable_gen2(mod);
+       struct rsnd_src *src = rsnd_mod_to_src(mod);
 
-       rsnd_mod_write(mod, SRC_CTRL, 0);
+       rsnd_mod_power_on(mod);
 
-       rsnd_src_error_record_gen2(mod);
+       rsnd_src_activation(mod);
+
+       rsnd_src_set_convert_rate(io, mod);
+
+       rsnd_src_status_clear(mod);
+
+       rsnd_src_irq_enable(mod);
+
+       src->err = 0;
+
+       /* reset sync convert_rate */
+       src->sync.val = 0;
 
-       return rsnd_src_stop(mod);
+       return 0;
 }
 
-static void __rsnd_src_interrupt_gen2(struct rsnd_mod *mod,
-                                     struct rsnd_dai_stream *io)
+static int rsnd_src_quit(struct rsnd_mod *mod,
+                        struct rsnd_dai_stream *io,
+                        struct rsnd_priv *priv)
 {
-       struct rsnd_priv *priv = rsnd_mod_to_priv(mod);
+       struct rsnd_src *src = rsnd_mod_to_src(mod);
+       struct device *dev = rsnd_priv_to_dev(priv);
 
-       spin_lock(&priv->lock);
+       rsnd_src_irq_disable(mod);
 
-       /* ignore all cases if not working */
-       if (!rsnd_io_is_working(io))
-               goto rsnd_src_interrupt_gen2_out;
+       /* stop both out/in */
+       rsnd_mod_write(mod, SRC_CTRL, 0);
 
-       if (rsnd_src_error_record_gen2(mod)) {
-               struct rsnd_priv *priv = rsnd_mod_to_priv(mod);
-               struct rsnd_src *src = rsnd_mod_to_src(mod);
-               struct device *dev = rsnd_priv_to_dev(priv);
+       rsnd_src_halt(mod);
 
-               dev_dbg(dev, "%s[%d] restart\n",
-                       rsnd_mod_name(mod), rsnd_mod_id(mod));
-
-               _rsnd_src_stop_gen2(mod);
-               if (src->err < 1024)
-                       _rsnd_src_start_gen2(mod, io);
-               else
-                       dev_warn(dev, "no more SRC restart\n");
-       }
+       rsnd_mod_power_off(mod);
 
-rsnd_src_interrupt_gen2_out:
-       spin_unlock(&priv->lock);
-}
+       if (src->err)
+               dev_warn(dev, "%s[%d] under/over flow err = %d\n",
+                        rsnd_mod_name(mod), rsnd_mod_id(mod), src->err);
 
-static irqreturn_t rsnd_src_interrupt_gen2(int irq, void *data)
-{
-       struct rsnd_mod *mod = data;
+       src->convert_rate = 0;
 
-       rsnd_mod_interrupt(mod, __rsnd_src_interrupt_gen2);
+       /* reset sync convert_rate */
+       src->sync.val = 0;
 
-       return IRQ_HANDLED;
+       return 0;
 }
 
-static int rsnd_src_set_convert_rate_gen2(struct rsnd_mod *mod,
-                                         struct rsnd_dai_stream *io)
+static void __rsnd_src_interrupt(struct rsnd_mod *mod,
+                                struct rsnd_dai_stream *io)
 {
        struct rsnd_priv *priv = rsnd_mod_to_priv(mod);
-       struct device *dev = rsnd_priv_to_dev(priv);
-       struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io);
        struct rsnd_src *src = rsnd_mod_to_src(mod);
-       u32 convert_rate = rsnd_src_convert_rate(io, src);
-       u32 cr, route;
-       uint ratio;
-       int ret;
+       struct device *dev = rsnd_priv_to_dev(priv);
 
-       /* 6 - 1/6 are very enough ratio for SRC_BSDSR */
-       if (!convert_rate)
-               ratio = 0;
-       else if (convert_rate > runtime->rate)
-               ratio = 100 * convert_rate / runtime->rate;
-       else
-               ratio = 100 * runtime->rate / convert_rate;
+       spin_lock(&priv->lock);
 
-       if (ratio > 600) {
-               dev_err(dev, "FSO/FSI ratio error\n");
-               return -EINVAL;
-       }
+       /* ignore all cases if not working */
+       if (!rsnd_io_is_working(io))
+               goto rsnd_src_interrupt_out;
 
-       ret = rsnd_src_set_convert_rate(mod, io);
-       if (ret < 0)
-               return ret;
+       if (rsnd_src_record_error(mod)) {
 
-       cr      = 0x00011110;
-       route   = 0x0;
-       if (convert_rate) {
-               route   = 0x1;
+               dev_dbg(dev, "%s[%d] restart\n",
+                       rsnd_mod_name(mod), rsnd_mod_id(mod));
 
-               if (rsnd_enable_sync_convert(src)) {
-                       cr |= 0x1;
-                       route |= rsnd_io_is_play(io) ?
-                               (0x1 << 24) : (0x1 << 25);
-               }
+               rsnd_src_stop(mod, io, priv);
+               rsnd_src_start(mod, io, priv);
        }
 
-       rsnd_mod_write(mod, SRC_SRCCR, cr);
-       rsnd_mod_write(mod, SRC_ROUTE_MODE0, route);
+       if (src->err > 1024) {
+               rsnd_src_irq_disable(mod);
 
-       switch (rsnd_mod_id(mod)) {
-       case 5:
-       case 6:
-       case 7:
-       case 8:
-               rsnd_mod_write(mod, SRC_BSDSR, 0x02400000);
-               break;
-       default:
-               rsnd_mod_write(mod, SRC_BSDSR, 0x01800000);
-               break;
+               dev_warn(dev, "no more %s[%d] restart\n",
+                        rsnd_mod_name(mod), rsnd_mod_id(mod));
        }
 
-       rsnd_mod_write(mod, SRC_BSISR, 0x00100060);
+       rsnd_src_status_clear(mod);
+rsnd_src_interrupt_out:
 
-       return 0;
+       spin_unlock(&priv->lock);
 }
 
-static int rsnd_src_set_convert_timing_gen2(struct rsnd_dai_stream *io,
-                                           struct rsnd_mod *mod)
+static irqreturn_t rsnd_src_interrupt(int irq, void *data)
 {
-       struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io);
-       struct rsnd_src *src = rsnd_mod_to_src(mod);
-       u32 convert_rate = rsnd_src_convert_rate(io, src);
-       int ret;
+       struct rsnd_mod *mod = data;
 
-       if (convert_rate)
-               ret = rsnd_adg_set_convert_clk_gen2(mod, io,
-                                                   runtime->rate,
-                                                   convert_rate);
-       else
-               ret = rsnd_adg_set_convert_timing_gen2(mod, io);
+       rsnd_mod_interrupt(mod, __rsnd_src_interrupt);
 
-       return ret;
+       return IRQ_HANDLED;
 }
 
-static int rsnd_src_probe_gen2(struct rsnd_mod *mod,
-                              struct rsnd_dai_stream *io,
-                              struct rsnd_priv *priv)
+static int rsnd_src_probe_(struct rsnd_mod *mod,
+                          struct rsnd_dai_stream *io,
+                          struct rsnd_priv *priv)
 {
        struct rsnd_src *src = rsnd_mod_to_src(mod);
        struct device *dev = rsnd_priv_to_dev(priv);
-       int irq = src->info->irq;
+       int irq = src->irq;
        int ret;
 
        if (irq > 0) {
                /*
                 * IRQ is not supported on non-DT
                 * see
-                *      rsnd_src_irq_enable_gen2()
+                *      rsnd_src_irq_enable()
                 */
                ret = devm_request_irq(dev, irq,
-                                      rsnd_src_interrupt_gen2,
+                                      rsnd_src_interrupt,
                                       IRQF_SHARED,
                                       dev_name(dev), mod);
                if (ret)
                        return ret;
        }
 
-       ret = rsnd_dma_init(io,
-                           rsnd_mod_to_dma(mod),
-                           src->info->dma_id);
+       src->dma = rsnd_dma_attach(io, mod, 0);
+       if (IS_ERR(src->dma))
+               return PTR_ERR(src->dma);
 
        return ret;
 }
 
-static int rsnd_src_remove_gen2(struct rsnd_mod *mod,
-                               struct rsnd_dai_stream *io,
-                               struct rsnd_priv *priv)
-{
-       rsnd_dma_quit(io, rsnd_mod_to_dma(mod));
-
-       return 0;
-}
-
-static int rsnd_src_init_gen2(struct rsnd_mod *mod,
-                             struct rsnd_dai_stream *io,
-                             struct rsnd_priv *priv)
-{
-       int ret;
-
-       ret = rsnd_src_init(mod, priv);
-       if (ret < 0)
-               return ret;
-
-       ret = rsnd_src_set_convert_rate_gen2(mod, io);
-       if (ret < 0)
-               return ret;
-
-       ret = rsnd_src_set_convert_timing_gen2(io, mod);
-       if (ret < 0)
-               return ret;
-
-       return 0;
-}
-
-static int rsnd_src_start_gen2(struct rsnd_mod *mod,
-                              struct rsnd_dai_stream *io,
-                              struct rsnd_priv *priv)
-{
-       rsnd_dma_start(io, rsnd_mod_to_dma(mod));
-
-       return _rsnd_src_start_gen2(mod, io);
-}
-
-static int rsnd_src_stop_gen2(struct rsnd_mod *mod,
-                             struct rsnd_dai_stream *io,
-                             struct rsnd_priv *priv)
-{
-       int ret;
-
-       ret = _rsnd_src_stop_gen2(mod);
-
-       rsnd_dma_stop(io, rsnd_mod_to_dma(mod));
-
-       return ret;
-}
-
-static void rsnd_src_reconvert_update(struct rsnd_dai_stream *io,
-                                     struct rsnd_mod *mod)
-{
-       struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io);
-       struct rsnd_src *src = rsnd_mod_to_src(mod);
-       u32 convert_rate = rsnd_src_convert_rate(io, src);
-       u32 fsrate;
-
-       if (!runtime)
-               return;
-
-       if (!convert_rate)
-               convert_rate = runtime->rate;
-
-       fsrate = 0x0400000 / convert_rate * runtime->rate;
-
-       /* update IFS */
-       rsnd_mod_write(mod, SRC_IFSVR, fsrate);
-}
-
-static int rsnd_src_pcm_new_gen2(struct rsnd_mod *mod,
+static int rsnd_src_pcm_new(struct rsnd_mod *mod,
                            struct rsnd_dai_stream *io,
                            struct snd_soc_pcm_runtime *rtd)
 {
        struct rsnd_dai *rdai = rsnd_io_to_rdai(io);
+       struct rsnd_mod *dvc = rsnd_io_to_mod_dvc(io);
        struct rsnd_src *src = rsnd_mod_to_src(mod);
        int ret;
 
@@ -936,6 +521,12 @@ static int rsnd_src_pcm_new_gen2(struct rsnd_mod *mod,
        if (!rsnd_rdai_is_clk_master(rdai))
                return 0;
 
+       /*
+        * SRC In doesn't work if DVC was enabled
+        */
+       if (dvc && !rsnd_io_is_play(io))
+               return 0;
+
        /*
         * enable sync convert
         */
@@ -943,7 +534,7 @@ static int rsnd_src_pcm_new_gen2(struct rsnd_mod *mod,
                               rsnd_io_is_play(io) ?
                               "SRC Out Rate Switch" :
                               "SRC In Rate Switch",
-                              rsnd_src_reconvert_update,
+                              rsnd_src_set_convert_rate,
                               &src->sen, 1);
        if (ret < 0)
                return ret;
@@ -952,23 +543,22 @@ static int rsnd_src_pcm_new_gen2(struct rsnd_mod *mod,
                               rsnd_io_is_play(io) ?
                               "SRC Out Rate" :
                               "SRC In Rate",
-                              rsnd_src_reconvert_update,
+                              rsnd_src_set_convert_rate,
                               &src->sync, 192000);
 
        return ret;
 }
 
-static struct rsnd_mod_ops rsnd_src_gen2_ops = {
+static struct rsnd_mod_ops rsnd_src_ops = {
        .name   = SRC_NAME,
        .dma_req = rsnd_src_dma_req,
-       .probe  = rsnd_src_probe_gen2,
-       .remove = rsnd_src_remove_gen2,
-       .init   = rsnd_src_init_gen2,
+       .probe  = rsnd_src_probe_,
+       .init   = rsnd_src_init,
        .quit   = rsnd_src_quit,
-       .start  = rsnd_src_start_gen2,
-       .stop   = rsnd_src_stop_gen2,
+       .start  = rsnd_src_start,
+       .stop   = rsnd_src_stop,
        .hw_params = rsnd_src_hw_params,
-       .pcm_new = rsnd_src_pcm_new_gen2,
+       .pcm_new = rsnd_src_pcm_new,
 };
 
 struct rsnd_mod *rsnd_src_mod_get(struct rsnd_priv *priv, int id)
@@ -976,113 +566,78 @@ struct rsnd_mod *rsnd_src_mod_get(struct rsnd_priv *priv, int id)
        if (WARN_ON(id < 0 || id >= rsnd_src_nr(priv)))
                id = 0;
 
-       return rsnd_mod_get((struct rsnd_src *)(priv->src) + id);
+       return rsnd_mod_get(rsnd_src_get(priv, id));
 }
 
-static void rsnd_of_parse_src(struct platform_device *pdev,
-                             const struct rsnd_of_data *of_data,
-                             struct rsnd_priv *priv)
+int rsnd_src_probe(struct rsnd_priv *priv)
 {
-       struct device_node *src_node;
+       struct device_node *node;
        struct device_node *np;
-       struct rcar_snd_info *info = rsnd_priv_to_info(priv);
-       struct rsnd_src_platform_info *src_info;
-       struct device *dev = &pdev->dev;
-       int nr, i;
-
-       if (!of_data)
-               return;
-
-       src_node = rsnd_src_of_node(priv);
-       if (!src_node)
-               return;
-
-       nr = of_get_child_count(src_node);
-       if (!nr)
-               goto rsnd_of_parse_src_end;
-
-       src_info = devm_kzalloc(dev,
-                               sizeof(struct rsnd_src_platform_info) * nr,
-                               GFP_KERNEL);
-       if (!src_info) {
-               dev_err(dev, "src info allocation error\n");
-               goto rsnd_of_parse_src_end;
-       }
-
-       info->src_info          = src_info;
-       info->src_info_nr       = nr;
-
-       i = 0;
-       for_each_child_of_node(src_node, np) {
-               src_info[i].irq = irq_of_parse_and_map(np, 0);
-
-               i++;
-       }
-
-rsnd_of_parse_src_end:
-       of_node_put(src_node);
-}
-
-int rsnd_src_probe(struct platform_device *pdev,
-                  const struct rsnd_of_data *of_data,
-                  struct rsnd_priv *priv)
-{
-       struct rcar_snd_info *info = rsnd_priv_to_info(priv);
        struct device *dev = rsnd_priv_to_dev(priv);
        struct rsnd_src *src;
-       struct rsnd_mod_ops *ops;
        struct clk *clk;
        char name[RSND_SRC_NAME_SIZE];
        int i, nr, ret;
 
-       ops = NULL;
-       if (rsnd_is_gen1(priv)) {
-               ops = &rsnd_src_gen1_ops;
-               dev_warn(dev, "Gen1 support will be removed soon\n");
-       }
-       if (rsnd_is_gen2(priv))
-               ops = &rsnd_src_gen2_ops;
-       if (!ops) {
-               dev_err(dev, "unknown Generation\n");
-               return -EIO;
-       }
+       /* This driver doesn't support Gen1 at this point */
+       if (rsnd_is_gen1(priv))
+               return 0;
 
-       rsnd_of_parse_src(pdev, of_data, priv);
+       node = rsnd_src_of_node(priv);
+       if (!node)
+               return 0; /* not used is not error */
 
-       /*
-        * init SRC
-        */
-       nr      = info->src_info_nr;
-       if (!nr)
-               return 0;
+       nr = of_get_child_count(node);
+       if (!nr) {
+               ret = -EINVAL;
+               goto rsnd_src_probe_done;
+       }
 
        src     = devm_kzalloc(dev, sizeof(*src) * nr, GFP_KERNEL);
-       if (!src)
-               return -ENOMEM;
+       if (!src) {
+               ret = -ENOMEM;
+               goto rsnd_src_probe_done;
+       }
 
        priv->src_nr    = nr;
        priv->src       = src;
 
-       for_each_rsnd_src(src, priv, i) {
+       i = 0;
+       for_each_child_of_node(node, np) {
+               src = rsnd_src_get(priv, i);
+
                snprintf(name, RSND_SRC_NAME_SIZE, "%s.%d",
                         SRC_NAME, i);
 
-               clk = devm_clk_get(dev, name);
-               if (IS_ERR(clk))
-                       return PTR_ERR(clk);
+               src->irq = irq_of_parse_and_map(np, 0);
+               if (!src->irq) {
+                       ret = -EINVAL;
+                       goto rsnd_src_probe_done;
+               }
 
-               src->info = &info->src_info[i];
+               clk = devm_clk_get(dev, name);
+               if (IS_ERR(clk)) {
+                       ret = PTR_ERR(clk);
+                       goto rsnd_src_probe_done;
+               }
 
-               ret = rsnd_mod_init(priv, rsnd_mod_get(src), ops, clk, RSND_MOD_SRC, i);
+               ret = rsnd_mod_init(priv, rsnd_mod_get(src),
+                                   &rsnd_src_ops, clk, RSND_MOD_SRC, i);
                if (ret)
-                       return ret;
+                       goto rsnd_src_probe_done;
+
+               i++;
        }
 
-       return 0;
+       ret = 0;
+
+rsnd_src_probe_done:
+       of_node_put(node);
+
+       return ret;
 }
 
-void rsnd_src_remove(struct platform_device *pdev,
-                    struct rsnd_priv *priv)
+void rsnd_src_remove(struct rsnd_priv *priv)
 {
        struct rsnd_src *src;
        int i;
index 1427ec21bd7ee1f581ef3ef4109716e3175ee066..7ee89da4dd5fc3a36b62147acd95fc6b4724661b 100644 (file)
@@ -24,7 +24,9 @@
 #define        OIEN            (1 << 26)       /* Overflow Interrupt Enable */
 #define        IIEN            (1 << 25)       /* Idle Mode Interrupt Enable */
 #define        DIEN            (1 << 24)       /* Data Interrupt Enable */
-
+#define        CHNL_4          (1 << 22)       /* Channels */
+#define        CHNL_6          (2 << 22)       /* Channels */
+#define        CHNL_8          (3 << 22)       /* Channels */
 #define        DWL_8           (0 << 19)       /* Data Word Length */
 #define        DWL_16          (1 << 19)       /* Data Word Length */
 #define        DWL_18          (2 << 19)       /* Data Word Length */
@@ -39,6 +41,7 @@
 #define        SCKP            (1 << 13)       /* Serial Bit Clock Polarity */
 #define        SWSP            (1 << 12)       /* Serial WS Polarity */
 #define        SDTA            (1 << 10)       /* Serial Data Alignment */
+#define        PDTA            (1 <<  9)       /* Parallel Data Alignment */
 #define        DEL             (1 <<  8)       /* Serial Data Delay */
 #define        CKDV(v)         (v <<  4)       /* Serial Clock Division Ratio */
 #define        TRMD            (1 <<  1)       /* Transmit/Receive Mode Select */
  * SSIWSR
  */
 #define CONT           (1 << 8)        /* WS Continue Function */
+#define WS_MODE                (1 << 0)        /* WS Mode */
 
 #define SSI_NAME "ssi"
 
 struct rsnd_ssi {
-       struct rsnd_ssi_platform_info *info; /* rcar_snd.h */
        struct rsnd_ssi *parent;
        struct rsnd_mod mod;
+       struct rsnd_mod *dma;
 
+       u32 flags;
        u32 cr_own;
        u32 cr_clk;
+       u32 cr_mode;
+       u32 wsr;
        int chan;
+       int rate;
        int err;
+       int irq;
        unsigned int usrcnt;
 };
 
+/* flags */
+#define RSND_SSI_CLK_PIN_SHARE         (1 << 0)
+#define RSND_SSI_NO_BUSIF              (1 << 1) /* SSI+DMA without BUSIF */
+
 #define for_each_rsnd_ssi(pos, priv, i)                                        \
        for (i = 0;                                                     \
             (i < rsnd_ssi_nr(priv)) &&                                 \
                ((pos) = ((struct rsnd_ssi *)(priv)->ssi + i));         \
             i++)
 
+#define rsnd_ssi_get(priv, id) ((struct rsnd_ssi *)(priv->ssi) + id)
+#define rsnd_ssi_to_dma(mod) ((ssi)->dma)
 #define rsnd_ssi_nr(priv) ((priv)->ssi_nr)
 #define rsnd_mod_to_ssi(_mod) container_of((_mod), struct rsnd_ssi, mod)
-#define rsnd_ssi_pio_available(ssi) ((ssi)->info->irq > 0)
-#define rsnd_ssi_parent(ssi) ((ssi)->parent)
-#define rsnd_ssi_mode_flags(p) ((p)->info->flags)
-#define rsnd_ssi_dai_id(ssi) ((ssi)->info->dai_id)
-#define rsnd_ssi_of_node(priv) \
-       of_get_child_by_name(rsnd_priv_to_dev(priv)->of_node, "rcar_sound,ssi")
+#define rsnd_ssi_mode_flags(p) ((p)->flags)
+#define rsnd_ssi_is_parent(ssi, io) ((ssi) == rsnd_io_to_mod_ssip(io))
+#define rsnd_ssi_is_multi_slave(ssi, io) ((mod) != rsnd_io_to_mod_ssi(io))
 
 int rsnd_ssi_use_busif(struct rsnd_dai_stream *io)
 {
@@ -103,6 +115,16 @@ int rsnd_ssi_use_busif(struct rsnd_dai_stream *io)
        return use_busif;
 }
 
+static void rsnd_ssi_status_clear(struct rsnd_mod *mod)
+{
+       rsnd_mod_write(mod, SSISR, 0);
+}
+
+static u32 rsnd_ssi_status_get(struct rsnd_mod *mod)
+{
+       return rsnd_mod_read(mod, SSISR);
+}
+
 static void rsnd_ssi_status_check(struct rsnd_mod *mod,
                                  u32 bit)
 {
@@ -112,7 +134,7 @@ static void rsnd_ssi_status_check(struct rsnd_mod *mod,
        int i;
 
        for (i = 0; i < 1024; i++) {
-               status = rsnd_mod_read(mod, SSISR);
+               status = rsnd_ssi_status_get(mod);
                if (status & bit)
                        return;
 
@@ -122,13 +144,79 @@ static void rsnd_ssi_status_check(struct rsnd_mod *mod,
        dev_warn(dev, "status check failed\n");
 }
 
+static int rsnd_ssi_irq_enable(struct rsnd_mod *ssi_mod)
+{
+       struct rsnd_priv *priv = rsnd_mod_to_priv(ssi_mod);
+
+       if (rsnd_is_gen1(priv))
+               return 0;
+
+       /* enable SSI interrupt if Gen2 */
+       rsnd_mod_write(ssi_mod, SSI_INT_ENABLE,
+                      rsnd_ssi_is_dma_mode(ssi_mod) ?
+                      0x0e000000 : 0x0f000000);
+
+       return 0;
+}
+
+static int rsnd_ssi_irq_disable(struct rsnd_mod *ssi_mod)
+{
+       struct rsnd_priv *priv = rsnd_mod_to_priv(ssi_mod);
+
+       if (rsnd_is_gen1(priv))
+               return 0;
+
+       /* disable SSI interrupt if Gen2 */
+       rsnd_mod_write(ssi_mod, SSI_INT_ENABLE, 0x00000000);
+
+       return 0;
+}
+
+u32 rsnd_ssi_multi_slaves(struct rsnd_dai_stream *io)
+{
+       struct rsnd_mod *mod;
+       struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io);
+       struct rsnd_priv *priv = rsnd_io_to_priv(io);
+       struct device *dev = rsnd_priv_to_dev(priv);
+       enum rsnd_mod_type types[] = {
+               RSND_MOD_SSIM1,
+               RSND_MOD_SSIM2,
+               RSND_MOD_SSIM3,
+       };
+       int i, mask;
+
+       switch (runtime->channels) {
+       case 2: /* Multi channel is not needed for Stereo */
+               return 0;
+       case 6:
+               break;
+       default:
+               dev_err(dev, "unsupported channel\n");
+               return 0;
+       }
+
+       mask = 0;
+       for (i = 0; i < ARRAY_SIZE(types); i++) {
+               mod = rsnd_io_to_mod(io, types[i]);
+               if (!mod)
+                       continue;
+
+               mask |= 1 << rsnd_mod_id(mod);
+       }
+
+       return mask;
+}
+
 static int rsnd_ssi_master_clk_start(struct rsnd_ssi *ssi,
                                     struct rsnd_dai_stream *io)
 {
        struct rsnd_priv *priv = rsnd_io_to_priv(io);
        struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io);
        struct device *dev = rsnd_priv_to_dev(priv);
+       struct rsnd_dai *rdai = rsnd_io_to_rdai(io);
        struct rsnd_mod *mod = rsnd_mod_get(ssi);
+       struct rsnd_mod *ssi_parent_mod = rsnd_io_to_mod_ssip(io);
+       int slots = rsnd_get_slot_width(io);
        int j, ret;
        int ssi_clk_mul_table[] = {
                1, 2, 4, 8, 16, 6, 12,
@@ -136,6 +224,24 @@ static int rsnd_ssi_master_clk_start(struct rsnd_ssi *ssi,
        unsigned int main_rate;
        unsigned int rate = rsnd_src_get_ssi_rate(priv, io, runtime);
 
+       if (!rsnd_rdai_is_clk_master(rdai))
+               return 0;
+
+       if (ssi_parent_mod && !rsnd_ssi_is_parent(mod, io))
+               return 0;
+
+       if (rsnd_ssi_is_multi_slave(mod, io))
+               return 0;
+
+       if (ssi->usrcnt > 1) {
+               if (ssi->rate != rate) {
+                       dev_err(dev, "SSI parent/child should use same rate\n");
+                       return -EINVAL;
+               }
+
+               return 0;
+       }
+
        /*
         * Find best clock, and try to start ADG
         */
@@ -143,15 +249,18 @@ static int rsnd_ssi_master_clk_start(struct rsnd_ssi *ssi,
 
                /*
                 * this driver is assuming that
-                * system word is 64fs (= 2 x 32bit)
+                * system word is 32bit x slots
                 * see rsnd_ssi_init()
                 */
-               main_rate = rate * 32 * 2 * ssi_clk_mul_table[j];
+               main_rate = rate * 32 * slots * ssi_clk_mul_table[j];
 
                ret = rsnd_adg_ssi_clk_try_start(mod, main_rate);
                if (0 == ret) {
                        ssi->cr_clk     = FORCE | SWL_32 |
                                SCKD | SWSD | CKDV(j);
+                       ssi->wsr = CONT;
+
+                       ssi->rate = rate;
 
                        dev_dbg(dev, "%s[%d] outputs %u Hz\n",
                                rsnd_mod_name(mod),
@@ -165,113 +274,91 @@ static int rsnd_ssi_master_clk_start(struct rsnd_ssi *ssi,
        return -EIO;
 }
 
-static void rsnd_ssi_master_clk_stop(struct rsnd_ssi *ssi)
+static void rsnd_ssi_master_clk_stop(struct rsnd_ssi *ssi,
+                                    struct rsnd_dai_stream *io)
 {
+       struct rsnd_dai *rdai = rsnd_io_to_rdai(io);
        struct rsnd_mod *mod = rsnd_mod_get(ssi);
+       struct rsnd_mod *ssi_parent_mod = rsnd_io_to_mod_ssip(io);
+
+       if (!rsnd_rdai_is_clk_master(rdai))
+               return;
+
+       if (ssi_parent_mod && !rsnd_ssi_is_parent(mod, io))
+               return;
+
+       if (ssi->usrcnt > 1)
+               return;
+
+       ssi->cr_clk     = 0;
+       ssi->rate       = 0;
 
-       ssi->cr_clk = 0;
        rsnd_adg_ssi_clk_stop(mod);
 }
 
-static void rsnd_ssi_hw_start(struct rsnd_ssi *ssi,
-                             struct rsnd_dai_stream *io)
+static int rsnd_ssi_config_init(struct rsnd_ssi *ssi,
+                               struct rsnd_dai_stream *io)
 {
-       struct rsnd_priv *priv = rsnd_io_to_priv(io);
        struct rsnd_dai *rdai = rsnd_io_to_rdai(io);
-       struct device *dev = rsnd_priv_to_dev(priv);
-       struct rsnd_mod *mod = rsnd_mod_get(ssi);
+       struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io);
+       u32 cr_own;
        u32 cr_mode;
-       u32 cr;
+       u32 wsr;
+       int is_tdm;
 
-       if (0 == ssi->usrcnt) {
-               rsnd_mod_power_on(mod);
+       is_tdm = (rsnd_get_slot_width(io) >= 6) ? 1 : 0;
 
-               if (rsnd_rdai_is_clk_master(rdai)) {
-                       struct rsnd_ssi *ssi_parent = rsnd_ssi_parent(ssi);
+       /*
+        * always use 32bit system word.
+        * see also rsnd_ssi_master_clk_enable()
+        */
+       cr_own = FORCE | SWL_32 | PDTA;
 
-                       if (ssi_parent)
-                               rsnd_ssi_hw_start(ssi_parent, io);
-                       else
-                               rsnd_ssi_master_clk_start(ssi, io);
-               }
+       if (rdai->bit_clk_inv)
+               cr_own |= SCKP;
+       if (rdai->frm_clk_inv ^ is_tdm)
+               cr_own |= SWSP;
+       if (rdai->data_alignment)
+               cr_own |= SDTA;
+       if (rdai->sys_delay)
+               cr_own |= DEL;
+       if (rsnd_io_is_play(io))
+               cr_own |= TRMD;
+
+       switch (runtime->sample_bits) {
+       case 16:
+               cr_own |= DWL_16;
+               break;
+       case 32:
+               cr_own |= DWL_24;
+               break;
+       default:
+               return -EINVAL;
        }
 
-       if (rsnd_ssi_is_dma_mode(mod)) {
+       if (rsnd_ssi_is_dma_mode(rsnd_mod_get(ssi))) {
                cr_mode = UIEN | OIEN | /* over/under run */
                          DMEN;         /* DMA : enable DMA */
        } else {
                cr_mode = DIEN;         /* PIO : enable Data interrupt */
        }
 
-       cr  =   ssi->cr_own     |
-               ssi->cr_clk     |
-               cr_mode         |
-               EN;
-
-       rsnd_mod_write(mod, SSICR, cr);
-
-       /* enable WS continue */
-       if (rsnd_rdai_is_clk_master(rdai))
-               rsnd_mod_write(mod, SSIWSR, CONT);
-
-       /* clear error status */
-       rsnd_mod_write(mod, SSISR, 0);
-
-       ssi->usrcnt++;
-
-       dev_dbg(dev, "%s[%d] hw started\n",
-               rsnd_mod_name(mod), rsnd_mod_id(mod));
-}
-
-static void rsnd_ssi_hw_stop(struct rsnd_dai_stream *io, struct rsnd_ssi *ssi)
-{
-       struct rsnd_mod *mod = rsnd_mod_get(ssi);
-       struct rsnd_priv *priv = rsnd_mod_to_priv(mod);
-       struct rsnd_dai *rdai = rsnd_io_to_rdai(io);
-       struct device *dev = rsnd_priv_to_dev(priv);
-       u32 cr;
-
-       if (0 == ssi->usrcnt) {
-               dev_err(dev, "%s called without starting\n", __func__);
-               return;
+       /*
+        * TDM Extend Mode
+        * see
+        *      rsnd_ssiu_init_gen2()
+        */
+       wsr = ssi->wsr;
+       if (is_tdm) {
+               wsr     |= WS_MODE;
+               cr_own  |= CHNL_8;
        }
 
-       ssi->usrcnt--;
-
-       if (0 == ssi->usrcnt) {
-               /*
-                * disable all IRQ,
-                * and, wait all data was sent
-                */
-               cr  =   ssi->cr_own     |
-                       ssi->cr_clk;
-
-               rsnd_mod_write(mod, SSICR, cr | EN);
-               rsnd_ssi_status_check(mod, DIRQ);
+       ssi->cr_own     = cr_own;
+       ssi->cr_mode    = cr_mode;
+       ssi->wsr        = wsr;
 
-               /*
-                * disable SSI,
-                * and, wait idle state
-                */
-               rsnd_mod_write(mod, SSICR, cr); /* disabled all */
-               rsnd_ssi_status_check(mod, IIRQ);
-
-               if (rsnd_rdai_is_clk_master(rdai)) {
-                       struct rsnd_ssi *ssi_parent = rsnd_ssi_parent(ssi);
-
-                       if (ssi_parent)
-                               rsnd_ssi_hw_stop(io, ssi_parent);
-                       else
-                               rsnd_ssi_master_clk_stop(ssi);
-               }
-
-               rsnd_mod_power_off(mod);
-
-               ssi->chan = 0;
-       }
-
-       dev_dbg(dev, "%s[%d] hw stopped\n",
-               rsnd_mod_name(mod), rsnd_mod_id(mod));
+       return 0;
 }
 
 /*
@@ -282,49 +369,30 @@ static int rsnd_ssi_init(struct rsnd_mod *mod,
                         struct rsnd_priv *priv)
 {
        struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod);
-       struct rsnd_dai *rdai = rsnd_io_to_rdai(io);
-       struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io);
-       u32 cr;
+       int ret;
+
+       ssi->usrcnt++;
 
-       cr = FORCE;
+       rsnd_mod_power_on(mod);
 
-       /*
-        * always use 32bit system word for easy clock calculation.
-        * see also rsnd_ssi_master_clk_enable()
-        */
-       cr |= SWL_32;
+       ret = rsnd_ssi_master_clk_start(ssi, io);
+       if (ret < 0)
+               return ret;
 
-       /*
-        * init clock settings for SSICR
-        */
-       switch (runtime->sample_bits) {
-       case 16:
-               cr |= DWL_16;
-               break;
-       case 32:
-               cr |= DWL_24;
-               break;
-       default:
-               return -EIO;
-       }
+       if (rsnd_ssi_is_parent(mod, io))
+               return 0;
 
-       if (rdai->bit_clk_inv)
-               cr |= SCKP;
-       if (rdai->frm_clk_inv)
-               cr |= SWSP;
-       if (rdai->data_alignment)
-               cr |= SDTA;
-       if (rdai->sys_delay)
-               cr |= DEL;
-       if (rsnd_io_is_play(io))
-               cr |= TRMD;
+       ret = rsnd_ssi_config_init(ssi, io);
+       if (ret < 0)
+               return ret;
 
-       /*
-        * set ssi parameter
-        */
-       ssi->cr_own     = cr;
        ssi->err        = -1; /* ignore 1st error */
 
+       /* clear error status */
+       rsnd_ssi_status_clear(mod);
+
+       rsnd_ssi_irq_enable(mod);
+
        return 0;
 }
 
@@ -335,12 +403,29 @@ static int rsnd_ssi_quit(struct rsnd_mod *mod,
        struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod);
        struct device *dev = rsnd_priv_to_dev(priv);
 
-       if (ssi->err > 0)
-               dev_warn(dev, "%s[%d] under/over flow err = %d\n",
-                        rsnd_mod_name(mod), rsnd_mod_id(mod), ssi->err);
+       if (!ssi->usrcnt) {
+               dev_err(dev, "%s[%d] usrcnt error\n",
+                       rsnd_mod_name(mod), rsnd_mod_id(mod));
+               return -EIO;
+       }
+
+       if (!rsnd_ssi_is_parent(mod, io)) {
+               if (ssi->err > 0)
+                       dev_warn(dev, "%s[%d] under/over flow err = %d\n",
+                                rsnd_mod_name(mod), rsnd_mod_id(mod),
+                                ssi->err);
+
+               ssi->cr_own     = 0;
+               ssi->err        = 0;
+
+               rsnd_ssi_irq_disable(mod);
+       }
 
-       ssi->cr_own     = 0;
-       ssi->err        = 0;
+       rsnd_ssi_master_clk_stop(ssi, io);
+
+       rsnd_mod_power_off(mod);
+
+       ssi->usrcnt--;
 
        return 0;
 }
@@ -351,14 +436,13 @@ static int rsnd_ssi_hw_params(struct rsnd_mod *mod,
                              struct snd_pcm_hw_params *params)
 {
        struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod);
-       struct rsnd_ssi *ssi_parent = rsnd_ssi_parent(ssi);
        int chan = params_channels(params);
 
        /*
         * Already working.
         * It will happen if SSI has parent/child connection.
         */
-       if (ssi->usrcnt) {
+       if (ssi->usrcnt > 1) {
                /*
                 * it is error if child <-> parent SSI uses
                 * different channels.
@@ -367,39 +451,83 @@ static int rsnd_ssi_hw_params(struct rsnd_mod *mod,
                        return -EIO;
        }
 
-       /* It will be removed on rsnd_ssi_hw_stop */
        ssi->chan = chan;
-       if (ssi_parent)
-               return rsnd_ssi_hw_params(rsnd_mod_get(ssi_parent), io,
-                                         substream, params);
 
        return 0;
 }
 
-static void rsnd_ssi_record_error(struct rsnd_ssi *ssi, u32 status)
+static u32 rsnd_ssi_record_error(struct rsnd_ssi *ssi)
 {
        struct rsnd_mod *mod = rsnd_mod_get(ssi);
+       u32 status = rsnd_ssi_status_get(mod);
 
        /* under/over flow error */
-       if (status & (UIRQ | OIRQ)) {
+       if (status & (UIRQ | OIRQ))
                ssi->err++;
 
-               /* clear error status */
-               rsnd_mod_write(mod, SSISR, 0);
-       }
+       return status;
+}
+
+static int __rsnd_ssi_start(struct rsnd_mod *mod,
+                           struct rsnd_dai_stream *io,
+                           struct rsnd_priv *priv)
+{
+       struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod);
+       u32 cr;
+
+       cr  =   ssi->cr_own     |
+               ssi->cr_clk     |
+               ssi->cr_mode;
+
+       /*
+        * EN will be set via SSIU :: SSI_CONTROL
+        * if Multi channel mode
+        */
+       if (!rsnd_ssi_multi_slaves(io))
+               cr |= EN;
+
+       rsnd_mod_write(mod, SSICR, cr);
+       rsnd_mod_write(mod, SSIWSR, ssi->wsr);
+
+       return 0;
 }
 
 static int rsnd_ssi_start(struct rsnd_mod *mod,
                          struct rsnd_dai_stream *io,
                          struct rsnd_priv *priv)
+{
+       /*
+        * no limit to start
+        * see also
+        *      rsnd_ssi_stop
+        *      rsnd_ssi_interrupt
+        */
+       return __rsnd_ssi_start(mod, io, priv);
+}
+
+static int __rsnd_ssi_stop(struct rsnd_mod *mod,
+                          struct rsnd_dai_stream *io,
+                          struct rsnd_priv *priv)
 {
        struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod);
+       u32 cr;
 
-       rsnd_src_ssiu_start(mod, io, rsnd_ssi_use_busif(io));
+       /*
+        * disable all IRQ,
+        * and, wait all data was sent
+        */
+       cr  =   ssi->cr_own     |
+               ssi->cr_clk;
 
-       rsnd_ssi_hw_start(ssi, io);
+       rsnd_mod_write(mod, SSICR, cr | EN);
+       rsnd_ssi_status_check(mod, DIRQ);
 
-       rsnd_src_ssi_irq_enable(mod);
+       /*
+        * disable SSI,
+        * and, wait idle state
+        */
+       rsnd_mod_write(mod, SSICR, cr); /* disabled all */
+       rsnd_ssi_status_check(mod, IIRQ);
 
        return 0;
 }
@@ -410,15 +538,16 @@ static int rsnd_ssi_stop(struct rsnd_mod *mod,
 {
        struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod);
 
-       rsnd_src_ssi_irq_disable(mod);
-
-       rsnd_ssi_record_error(ssi, rsnd_mod_read(mod, SSISR));
-
-       rsnd_ssi_hw_stop(io, ssi);
-
-       rsnd_src_ssiu_stop(mod, io);
+       /*
+        * don't stop if not last user
+        * see also
+        *      rsnd_ssi_start
+        *      rsnd_ssi_interrupt
+        */
+       if (ssi->usrcnt > 1)
+               return 0;
 
-       return 0;
+       return __rsnd_ssi_stop(mod, io, priv);
 }
 
 static void __rsnd_ssi_interrupt(struct rsnd_mod *mod,
@@ -426,6 +555,7 @@ static void __rsnd_ssi_interrupt(struct rsnd_mod *mod,
 {
        struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod);
        struct rsnd_priv *priv = rsnd_mod_to_priv(mod);
+       struct device *dev = rsnd_priv_to_dev(priv);
        int is_dma = rsnd_ssi_is_dma_mode(mod);
        u32 status;
        bool elapsed = false;
@@ -436,7 +566,7 @@ static void __rsnd_ssi_interrupt(struct rsnd_mod *mod,
        if (!rsnd_io_is_working(io))
                goto rsnd_ssi_interrupt_out;
 
-       status = rsnd_mod_read(mod, SSISR);
+       status = rsnd_ssi_record_error(ssi);
 
        /* PIO only */
        if (!is_dma && (status & DIRQ)) {
@@ -459,23 +589,24 @@ static void __rsnd_ssi_interrupt(struct rsnd_mod *mod,
 
        /* DMA only */
        if (is_dma && (status & (UIRQ | OIRQ))) {
-               struct device *dev = rsnd_priv_to_dev(priv);
-
                /*
                 * restart SSI
                 */
                dev_dbg(dev, "%s[%d] restart\n",
                        rsnd_mod_name(mod), rsnd_mod_id(mod));
 
-               rsnd_ssi_stop(mod, io, priv);
-               if (ssi->err < 1024)
-                       rsnd_ssi_start(mod, io, priv);
-               else
-                       dev_warn(dev, "no more SSI restart\n");
+               __rsnd_ssi_stop(mod, io, priv);
+               __rsnd_ssi_start(mod, io, priv);
        }
 
-       rsnd_ssi_record_error(ssi, status);
+       if (ssi->err > 1024) {
+               rsnd_ssi_irq_disable(mod);
 
+               dev_warn(dev, "no more %s[%d] restart\n",
+                        rsnd_mod_name(mod), rsnd_mod_id(mod));
+       }
+
+       rsnd_ssi_status_clear(mod);
 rsnd_ssi_interrupt_out:
        spin_unlock(&priv->lock);
 
@@ -495,15 +626,49 @@ static irqreturn_t rsnd_ssi_interrupt(int irq, void *data)
 /*
  *             SSI PIO
  */
-static int rsnd_ssi_pio_probe(struct rsnd_mod *mod,
-                             struct rsnd_dai_stream *io,
-                             struct rsnd_priv *priv)
+static void rsnd_ssi_parent_attach(struct rsnd_mod *mod,
+                                  struct rsnd_dai_stream *io,
+                                  struct rsnd_priv *priv)
+{
+       if (!__rsnd_ssi_is_pin_sharing(mod))
+               return;
+
+       switch (rsnd_mod_id(mod)) {
+       case 1:
+       case 2:
+               rsnd_dai_connect(rsnd_ssi_mod_get(priv, 0), io, RSND_MOD_SSIP);
+               break;
+       case 4:
+               rsnd_dai_connect(rsnd_ssi_mod_get(priv, 3), io, RSND_MOD_SSIP);
+               break;
+       case 8:
+               rsnd_dai_connect(rsnd_ssi_mod_get(priv, 7), io, RSND_MOD_SSIP);
+               break;
+       }
+}
+
+static int rsnd_ssi_common_probe(struct rsnd_mod *mod,
+                                struct rsnd_dai_stream *io,
+                                struct rsnd_priv *priv)
 {
        struct device *dev = rsnd_priv_to_dev(priv);
        struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod);
        int ret;
 
-       ret = devm_request_irq(dev, ssi->info->irq,
+       /*
+        * SSIP/SSIU/IRQ are not needed on
+        * SSI Multi slaves
+        */
+       if (rsnd_ssi_is_multi_slave(mod, io))
+               return 0;
+
+       rsnd_ssi_parent_attach(mod, io, priv);
+
+       ret = rsnd_ssiu_attach(io, mod);
+       if (ret < 0)
+               return ret;
+
+       ret = devm_request_irq(dev, ssi->irq,
                               rsnd_ssi_interrupt,
                               IRQF_SHARED,
                               dev_name(dev), mod);
@@ -513,7 +678,7 @@ static int rsnd_ssi_pio_probe(struct rsnd_mod *mod,
 
 static struct rsnd_mod_ops rsnd_ssi_pio_ops = {
        .name   = SSI_NAME,
-       .probe  = rsnd_ssi_pio_probe,
+       .probe  = rsnd_ssi_common_probe,
        .init   = rsnd_ssi_init,
        .quit   = rsnd_ssi_quit,
        .start  = rsnd_ssi_start,
@@ -526,20 +691,23 @@ static int rsnd_ssi_dma_probe(struct rsnd_mod *mod,
                              struct rsnd_priv *priv)
 {
        struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod);
-       struct device *dev = rsnd_priv_to_dev(priv);
-       int dma_id = ssi->info->dma_id;
+       int dma_id = 0; /* not needed */
        int ret;
 
-       ret = devm_request_irq(dev, ssi->info->irq,
-                              rsnd_ssi_interrupt,
-                              IRQF_SHARED,
-                              dev_name(dev), mod);
+       /*
+        * SSIP/SSIU/IRQ/DMA are not needed on
+        * SSI Multi slaves
+        */
+       if (rsnd_ssi_is_multi_slave(mod, io))
+               return 0;
+
+       ret = rsnd_ssi_common_probe(mod, io, priv);
        if (ret)
                return ret;
 
-       ret = rsnd_dma_init(
-               io, rsnd_mod_to_dma(mod),
-               dma_id);
+       ssi->dma = rsnd_dma_attach(io, mod, dma_id);
+       if (IS_ERR(ssi->dma))
+               return PTR_ERR(ssi->dma);
 
        return ret;
 }
@@ -550,9 +718,7 @@ static int rsnd_ssi_dma_remove(struct rsnd_mod *mod,
 {
        struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod);
        struct device *dev = rsnd_priv_to_dev(priv);
-       int irq = ssi->info->irq;
-
-       rsnd_dma_quit(io, rsnd_mod_to_dma(mod));
+       int irq = ssi->irq;
 
        /* PIO will request IRQ again */
        devm_free_irq(dev, irq, mod);
@@ -581,32 +747,6 @@ static int rsnd_ssi_fallback(struct rsnd_mod *mod,
        return 0;
 }
 
-static int rsnd_ssi_dma_start(struct rsnd_mod *mod,
-                             struct rsnd_dai_stream *io,
-                             struct rsnd_priv *priv)
-{
-       struct rsnd_dma *dma = rsnd_mod_to_dma(mod);
-
-       rsnd_dma_start(io, dma);
-
-       rsnd_ssi_start(mod, io, priv);
-
-       return 0;
-}
-
-static int rsnd_ssi_dma_stop(struct rsnd_mod *mod,
-                            struct rsnd_dai_stream *io,
-                            struct rsnd_priv *priv)
-{
-       struct rsnd_dma *dma = rsnd_mod_to_dma(mod);
-
-       rsnd_ssi_stop(mod, io, priv);
-
-       rsnd_dma_stop(io, dma);
-
-       return 0;
-}
-
 static struct dma_chan *rsnd_ssi_dma_req(struct rsnd_dai_stream *io,
                                         struct rsnd_mod *mod)
 {
@@ -630,8 +770,8 @@ static struct rsnd_mod_ops rsnd_ssi_dma_ops = {
        .remove = rsnd_ssi_dma_remove,
        .init   = rsnd_ssi_init,
        .quit   = rsnd_ssi_quit,
-       .start  = rsnd_ssi_dma_start,
-       .stop   = rsnd_ssi_dma_stop,
+       .start  = rsnd_ssi_start,
+       .stop   = rsnd_ssi_stop,
        .fallback = rsnd_ssi_fallback,
        .hw_params = rsnd_ssi_hw_params,
 };
@@ -652,110 +792,76 @@ static struct rsnd_mod_ops rsnd_ssi_non_ops = {
 /*
  *             ssi mod function
  */
-struct rsnd_mod *rsnd_ssi_mod_get(struct rsnd_priv *priv, int id)
+static void rsnd_ssi_connect(struct rsnd_mod *mod,
+                            struct rsnd_dai_stream *io)
 {
-       if (WARN_ON(id < 0 || id >= rsnd_ssi_nr(priv)))
-               id = 0;
-
-       return rsnd_mod_get((struct rsnd_ssi *)(priv->ssi) + id);
-}
-
-int __rsnd_ssi_is_pin_sharing(struct rsnd_mod *mod)
-{
-       struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod);
-
-       return !!(rsnd_ssi_mode_flags(ssi) & RSND_SSI_CLK_PIN_SHARE);
-}
-
-static void rsnd_ssi_parent_setup(struct rsnd_priv *priv, struct rsnd_ssi *ssi)
-{
-       struct rsnd_mod *mod = rsnd_mod_get(ssi);
-
-       if (!__rsnd_ssi_is_pin_sharing(mod))
-               return;
+       struct rsnd_dai *rdai = rsnd_io_to_rdai(io);
+       enum rsnd_mod_type types[] = {
+               RSND_MOD_SSI,
+               RSND_MOD_SSIM1,
+               RSND_MOD_SSIM2,
+               RSND_MOD_SSIM3,
+       };
+       enum rsnd_mod_type type;
+       int i;
 
-       switch (rsnd_mod_id(mod)) {
-       case 1:
-       case 2:
-               ssi->parent = rsnd_mod_to_ssi(rsnd_ssi_mod_get(priv, 0));
-               break;
-       case 4:
-               ssi->parent = rsnd_mod_to_ssi(rsnd_ssi_mod_get(priv, 3));
-               break;
-       case 8:
-               ssi->parent = rsnd_mod_to_ssi(rsnd_ssi_mod_get(priv, 7));
-               break;
+       /* try SSI -> SSIM1 -> SSIM2 -> SSIM3 */
+       for (i = 0; i < ARRAY_SIZE(types); i++) {
+               type = types[i];
+               if (!rsnd_io_to_mod(io, type)) {
+                       rsnd_dai_connect(mod, io, type);
+                       rsnd_set_slot(rdai, 2 * (i + 1), (i + 1));
+                       return;
+               }
        }
 }
 
-
-static void rsnd_of_parse_ssi(struct platform_device *pdev,
-                             const struct rsnd_of_data *of_data,
-                             struct rsnd_priv *priv)
+void rsnd_parse_connect_ssi(struct rsnd_dai *rdai,
+                           struct device_node *playback,
+                           struct device_node *capture)
 {
+       struct rsnd_priv *priv = rsnd_rdai_to_priv(rdai);
        struct device_node *node;
        struct device_node *np;
-       struct rsnd_ssi_platform_info *ssi_info;
-       struct rcar_snd_info *info = rsnd_priv_to_info(priv);
-       struct device *dev = &pdev->dev;
-       int nr, i;
+       struct rsnd_mod *mod;
+       int i;
 
        node = rsnd_ssi_of_node(priv);
        if (!node)
                return;
 
-       nr = of_get_child_count(node);
-       if (!nr)
-               goto rsnd_of_parse_ssi_end;
-
-       ssi_info = devm_kzalloc(dev,
-                               sizeof(struct rsnd_ssi_platform_info) * nr,
-                               GFP_KERNEL);
-       if (!ssi_info) {
-               dev_err(dev, "ssi info allocation error\n");
-               goto rsnd_of_parse_ssi_end;
-       }
-
-       info->ssi_info          = ssi_info;
-       info->ssi_info_nr       = nr;
-
-       i = -1;
+       i = 0;
        for_each_child_of_node(node, np) {
+               mod = rsnd_ssi_mod_get(priv, i);
+               if (np == playback)
+                       rsnd_ssi_connect(mod, &rdai->playback);
+               if (np == capture)
+                       rsnd_ssi_connect(mod, &rdai->capture);
                i++;
+       }
 
-               ssi_info = info->ssi_info + i;
-
-               /*
-                * pin settings
-                */
-               if (of_get_property(np, "shared-pin", NULL))
-                       ssi_info->flags |= RSND_SSI_CLK_PIN_SHARE;
+       of_node_put(node);
+}
 
-               /*
-                * irq
-                */
-               ssi_info->irq = irq_of_parse_and_map(np, 0);
+struct rsnd_mod *rsnd_ssi_mod_get(struct rsnd_priv *priv, int id)
+{
+       if (WARN_ON(id < 0 || id >= rsnd_ssi_nr(priv)))
+               id = 0;
 
-               /*
-                * DMA
-                */
-               ssi_info->dma_id = of_get_property(np, "pio-transfer", NULL) ?
-                       0 : 1;
+       return rsnd_mod_get(rsnd_ssi_get(priv, id));
+}
 
-               if (of_get_property(np, "no-busif", NULL))
-                       ssi_info->flags |= RSND_SSI_NO_BUSIF;
-       }
+int __rsnd_ssi_is_pin_sharing(struct rsnd_mod *mod)
+{
+       struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod);
 
-rsnd_of_parse_ssi_end:
-       of_node_put(node);
+       return !!(rsnd_ssi_mode_flags(ssi) & RSND_SSI_CLK_PIN_SHARE);
 }
 
-int rsnd_ssi_probe(struct platform_device *pdev,
-                  const struct rsnd_of_data *of_data,
-                  struct rsnd_priv *priv)
+int rsnd_ssi_probe(struct rsnd_priv *priv)
 {
-       struct rcar_snd_info *info = rsnd_priv_to_info(priv);
-       struct rsnd_ssi_platform_info *pinfo;
+       struct device_node *node;
+       struct device_node *np;
        struct device *dev = rsnd_priv_to_dev(priv);
        struct rsnd_mod_ops *ops;
        struct clk *clk;
@@ -763,50 +869,73 @@ int rsnd_ssi_probe(struct platform_device *pdev,
        char name[RSND_SSI_NAME_SIZE];
        int i, nr, ret;
 
-       rsnd_of_parse_ssi(pdev, of_data, priv);
+       node = rsnd_ssi_of_node(priv);
+       if (!node)
+               return -EINVAL;
+
+       nr = of_get_child_count(node);
+       if (!nr) {
+               ret = -EINVAL;
+               goto rsnd_ssi_probe_done;
+       }
 
-       /*
-        *      init SSI
-        */
-       nr      = info->ssi_info_nr;
        ssi     = devm_kzalloc(dev, sizeof(*ssi) * nr, GFP_KERNEL);
-       if (!ssi)
-               return -ENOMEM;
+       if (!ssi) {
+               ret = -ENOMEM;
+               goto rsnd_ssi_probe_done;
+       }
 
        priv->ssi       = ssi;
        priv->ssi_nr    = nr;
 
-       for_each_rsnd_ssi(ssi, priv, i) {
-               pinfo = &info->ssi_info[i];
+       i = 0;
+       for_each_child_of_node(node, np) {
+               ssi = rsnd_ssi_get(priv, i);
 
                snprintf(name, RSND_SSI_NAME_SIZE, "%s.%d",
                         SSI_NAME, i);
 
                clk = devm_clk_get(dev, name);
-               if (IS_ERR(clk))
-                       return PTR_ERR(clk);
+               if (IS_ERR(clk)) {
+                       ret = PTR_ERR(clk);
+                       goto rsnd_ssi_probe_done;
+               }
 
-               ssi->info       = pinfo;
+               if (of_get_property(np, "shared-pin", NULL))
+                       ssi->flags |= RSND_SSI_CLK_PIN_SHARE;
+
+               if (of_get_property(np, "no-busif", NULL))
+                       ssi->flags |= RSND_SSI_NO_BUSIF;
+
+               ssi->irq = irq_of_parse_and_map(np, 0);
+               if (!ssi->irq) {
+                       ret = -EINVAL;
+                       goto rsnd_ssi_probe_done;
+               }
 
                ops = &rsnd_ssi_non_ops;
-               if (pinfo->dma_id > 0)
-                       ops = &rsnd_ssi_dma_ops;
-               else if (rsnd_ssi_pio_available(ssi))
+               if (of_get_property(np, "pio-transfer", NULL))
                        ops = &rsnd_ssi_pio_ops;
+               else
+                       ops = &rsnd_ssi_dma_ops;
 
                ret = rsnd_mod_init(priv, rsnd_mod_get(ssi), ops, clk,
                                    RSND_MOD_SSI, i);
                if (ret)
-                       return ret;
+                       goto rsnd_ssi_probe_done;
 
-               rsnd_ssi_parent_setup(priv, ssi);
+               i++;
        }
 
-       return 0;
+       ret = 0;
+
+rsnd_ssi_probe_done:
+       of_node_put(node);
+
+       return ret;
 }
 
-void rsnd_ssi_remove(struct platform_device *pdev,
-                    struct rsnd_priv *priv)
+void rsnd_ssi_remove(struct rsnd_priv *priv)
 {
        struct rsnd_ssi *ssi;
        int i;
diff --git a/sound/soc/sh/rcar/ssiu.c b/sound/soc/sh/rcar/ssiu.c
new file mode 100644 (file)
index 0000000..06d7282
--- /dev/null
@@ -0,0 +1,225 @@
+/*
+ * Renesas R-Car SSIU support
+ *
+ * Copyright (c) 2015 Kuninori Morimoto <kuninori.morimoto.gx@renesas.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 "rsnd.h"
+
+#define SSIU_NAME "ssiu"
+
+struct rsnd_ssiu {
+       struct rsnd_mod mod;
+};
+
+#define rsnd_ssiu_nr(priv) ((priv)->ssiu_nr)
+#define for_each_rsnd_ssiu(pos, priv, i)                               \
+       for (i = 0;                                                     \
+            (i < rsnd_ssiu_nr(priv)) &&                                \
+                    ((pos) = ((struct rsnd_ssiu *)(priv)->ssiu + i));  \
+            i++)
+
+static int rsnd_ssiu_init(struct rsnd_mod *mod,
+                         struct rsnd_dai_stream *io,
+                         struct rsnd_priv *priv)
+{
+       struct rsnd_dai *rdai = rsnd_io_to_rdai(io);
+       u32 multi_ssi_slaves = rsnd_ssi_multi_slaves(io);
+       int use_busif = rsnd_ssi_use_busif(io);
+       int id = rsnd_mod_id(mod);
+       u32 mask1, val1;
+       u32 mask2, val2;
+
+       /*
+        * SSI_MODE0
+        */
+       rsnd_mod_bset(mod, SSI_MODE0, (1 << id), !use_busif << id);
+
+       /*
+        * SSI_MODE1
+        */
+       mask1 = (1 << 4) | (1 << 20);   /* mask sync bit */
+       mask2 = (1 << 4);               /* mask sync bit */
+       val1  = val2  = 0;
+       if (rsnd_ssi_is_pin_sharing(io)) {
+               int shift = -1;
+
+               switch (id) {
+               case 1:
+                       shift = 0;
+                       break;
+               case 2:
+                       shift = 2;
+                       break;
+               case 4:
+                       shift = 16;
+                       break;
+               default:
+                       return -EINVAL;
+               }
+
+               mask1 |= 0x3 << shift;
+               val1 = rsnd_rdai_is_clk_master(rdai) ?
+                       0x2 << shift : 0x1 << shift;
+
+       } else if (multi_ssi_slaves) {
+
+               mask2 |= 0x00000007;
+               mask1 |= 0x0000000f;
+
+               switch (multi_ssi_slaves) {
+               case 0x0206: /* SSI0/1/2/9 */
+                       val2 = (1 << 4) | /* SSI0129 sync */
+                               (rsnd_rdai_is_clk_master(rdai) ? 0x2 : 0x1);
+                       /* fall through */
+               case 0x0006: /* SSI0/1/2 */
+                       val1 = rsnd_rdai_is_clk_master(rdai) ?
+                               0xa : 0x5;
+
+                       if (!val2)  /* SSI012 sync */
+                               val1 |= (1 << 4);
+               }
+       }
+
+       rsnd_mod_bset(mod, SSI_MODE1, mask1, val1);
+       rsnd_mod_bset(mod, SSI_MODE2, mask2, val2);
+
+       return 0;
+}
+
+static struct rsnd_mod_ops rsnd_ssiu_ops_gen1 = {
+       .name   = SSIU_NAME,
+       .init   = rsnd_ssiu_init,
+};
+
+static int rsnd_ssiu_init_gen2(struct rsnd_mod *mod,
+                              struct rsnd_dai_stream *io,
+                              struct rsnd_priv *priv)
+{
+       int ret;
+
+       ret = rsnd_ssiu_init(mod, io, priv);
+       if (ret < 0)
+               return ret;
+
+       if (rsnd_get_slot_width(io) >= 6) {
+               /*
+                * TDM Extend Mode
+                * see
+                *      rsnd_ssi_config_init()
+                */
+               rsnd_mod_write(mod, SSI_MODE, 0x1);
+       }
+
+       if (rsnd_ssi_use_busif(io)) {
+               u32 val = rsnd_get_dalign(mod, io);
+
+               rsnd_mod_write(mod, SSI_BUSIF_ADINR,
+                              rsnd_get_adinr_bit(mod, io) |
+                              rsnd_get_adinr_chan(mod, io));
+               rsnd_mod_write(mod, SSI_BUSIF_MODE,  1);
+               rsnd_mod_write(mod, SSI_BUSIF_DALIGN, val);
+       }
+
+       return 0;
+}
+
+static int rsnd_ssiu_start_gen2(struct rsnd_mod *mod,
+                               struct rsnd_dai_stream *io,
+                               struct rsnd_priv *priv)
+{
+       if (!rsnd_ssi_use_busif(io))
+               return 0;
+
+       rsnd_mod_write(mod, SSI_CTRL, 0x1);
+
+       if (rsnd_ssi_multi_slaves(io))
+               rsnd_mod_write(mod, SSI_CONTROL, 0x1);
+
+       return 0;
+}
+
+static int rsnd_ssiu_stop_gen2(struct rsnd_mod *mod,
+                              struct rsnd_dai_stream *io,
+                              struct rsnd_priv *priv)
+{
+       if (!rsnd_ssi_use_busif(io))
+               return 0;
+
+       rsnd_mod_write(mod, SSI_CTRL, 0);
+
+       if (rsnd_ssi_multi_slaves(io))
+               rsnd_mod_write(mod, SSI_CONTROL, 0);
+
+       return 0;
+}
+
+static struct rsnd_mod_ops rsnd_ssiu_ops_gen2 = {
+       .name   = SSIU_NAME,
+       .init   = rsnd_ssiu_init_gen2,
+       .start  = rsnd_ssiu_start_gen2,
+       .stop   = rsnd_ssiu_stop_gen2,
+};
+
+static struct rsnd_mod *rsnd_ssiu_mod_get(struct rsnd_priv *priv, int id)
+{
+       if (WARN_ON(id < 0 || id >= rsnd_ssiu_nr(priv)))
+               id = 0;
+
+       return rsnd_mod_get((struct rsnd_ssiu *)(priv->ssiu) + id);
+}
+
+int rsnd_ssiu_attach(struct rsnd_dai_stream *io,
+                    struct rsnd_mod *ssi_mod)
+{
+       struct rsnd_priv *priv = rsnd_io_to_priv(io);
+       struct rsnd_mod *mod = rsnd_ssiu_mod_get(priv, rsnd_mod_id(ssi_mod));
+
+       rsnd_mod_confirm_ssi(ssi_mod);
+
+       return rsnd_dai_connect(mod, io, mod->type);
+}
+
+int rsnd_ssiu_probe(struct rsnd_priv *priv)
+{
+       struct device *dev = rsnd_priv_to_dev(priv);
+       struct rsnd_ssiu *ssiu;
+       static struct rsnd_mod_ops *ops;
+       int i, nr, ret;
+
+       /* same number to SSI */
+       nr      = priv->ssi_nr;
+       ssiu    = devm_kzalloc(dev, sizeof(*ssiu) * nr, GFP_KERNEL);
+       if (!ssiu)
+               return -ENOMEM;
+
+       priv->ssiu      = ssiu;
+       priv->ssiu_nr   = nr;
+
+       if (rsnd_is_gen1(priv))
+               ops = &rsnd_ssiu_ops_gen1;
+       else
+               ops = &rsnd_ssiu_ops_gen2;
+
+       for_each_rsnd_ssiu(ssiu, priv, i) {
+               ret = rsnd_mod_init(priv, rsnd_mod_get(ssiu),
+                                   ops, NULL, RSND_MOD_SSIU, i);
+               if (ret)
+                       return ret;
+       }
+
+       return 0;
+}
+
+void rsnd_ssiu_remove(struct rsnd_priv *priv)
+{
+       struct rsnd_ssiu *ssiu;
+       int i;
+
+       for_each_rsnd_ssiu(ssiu, priv, i) {
+               rsnd_mod_quit(rsnd_mod_get(ssiu));
+       }
+}
index d40efc9fe0a9b4597511b2de2ad02712aa912043..733f5128eeff9f6b9049a901c9fa020a6a0f2c7e 100644 (file)
@@ -20,6 +20,7 @@
 #include <linux/delay.h>
 #include <linux/export.h>
 #include <linux/gpio.h>
+#include <linux/gpio/driver.h>
 #include <linux/init.h>
 #include <linux/of_gpio.h>
 #include <linux/of.h>
@@ -38,6 +39,14 @@ struct snd_ac97_reset_cfg {
        int gpio_reset;
 };
 
+struct snd_ac97_gpio_priv {
+#ifdef CONFIG_GPIOLIB
+       struct gpio_chip gpio_chip;
+#endif
+       unsigned int gpios_set;
+       struct snd_soc_codec *codec;
+};
+
 static struct snd_ac97_bus soc_ac97_bus = {
        .ops = NULL, /* Gets initialized in snd_soc_set_ac97_ops() */
 };
@@ -47,6 +56,117 @@ static void soc_ac97_device_release(struct device *dev)
        kfree(to_ac97_t(dev));
 }
 
+#ifdef CONFIG_GPIOLIB
+static inline struct snd_soc_codec *gpio_to_codec(struct gpio_chip *chip)
+{
+       struct snd_ac97_gpio_priv *gpio_priv =
+               container_of(chip, struct snd_ac97_gpio_priv, gpio_chip);
+
+       return gpio_priv->codec;
+}
+
+static int snd_soc_ac97_gpio_request(struct gpio_chip *chip, unsigned offset)
+{
+       if (offset >= AC97_NUM_GPIOS)
+               return -EINVAL;
+
+       return 0;
+}
+
+static int snd_soc_ac97_gpio_direction_in(struct gpio_chip *chip,
+                                         unsigned offset)
+{
+       struct snd_soc_codec *codec = gpio_to_codec(chip);
+
+       dev_dbg(codec->dev, "set gpio %d to output\n", offset);
+       return snd_soc_update_bits(codec, AC97_GPIO_CFG,
+                                  1 << offset, 1 << offset);
+}
+
+static int snd_soc_ac97_gpio_get(struct gpio_chip *chip, unsigned offset)
+{
+       struct snd_soc_codec *codec = gpio_to_codec(chip);
+       int ret;
+
+       ret = snd_soc_read(codec, AC97_GPIO_STATUS);
+       dev_dbg(codec->dev, "get gpio %d : %d\n", offset,
+               ret < 0 ? ret : ret & (1 << offset));
+
+       return ret < 0 ? ret : !!(ret & (1 << offset));
+}
+
+static void snd_soc_ac97_gpio_set(struct gpio_chip *chip, unsigned offset,
+                                 int value)
+{
+       struct snd_ac97_gpio_priv *gpio_priv =
+               container_of(chip, struct snd_ac97_gpio_priv, gpio_chip);
+       struct snd_soc_codec *codec = gpio_to_codec(chip);
+
+       gpio_priv->gpios_set &= ~(1 << offset);
+       gpio_priv->gpios_set |= (!!value) << offset;
+       snd_soc_write(codec, AC97_GPIO_STATUS, gpio_priv->gpios_set);
+       dev_dbg(codec->dev, "set gpio %d to %d\n", offset, !!value);
+}
+
+static int snd_soc_ac97_gpio_direction_out(struct gpio_chip *chip,
+                                    unsigned offset, int value)
+{
+       struct snd_soc_codec *codec = gpio_to_codec(chip);
+
+       dev_dbg(codec->dev, "set gpio %d to output\n", offset);
+       snd_soc_ac97_gpio_set(chip, offset, value);
+       return snd_soc_update_bits(codec, AC97_GPIO_CFG, 1 << offset, 0);
+}
+
+static struct gpio_chip snd_soc_ac97_gpio_chip = {
+       .label                  = "snd_soc_ac97",
+       .owner                  = THIS_MODULE,
+       .request                = snd_soc_ac97_gpio_request,
+       .direction_input        = snd_soc_ac97_gpio_direction_in,
+       .get                    = snd_soc_ac97_gpio_get,
+       .direction_output       = snd_soc_ac97_gpio_direction_out,
+       .set                    = snd_soc_ac97_gpio_set,
+       .can_sleep              = 1,
+};
+
+static int snd_soc_ac97_init_gpio(struct snd_ac97 *ac97,
+                                 struct snd_soc_codec *codec)
+{
+       struct snd_ac97_gpio_priv *gpio_priv;
+       int ret;
+
+       gpio_priv = devm_kzalloc(codec->dev, sizeof(*gpio_priv), GFP_KERNEL);
+       if (!gpio_priv)
+               return -ENOMEM;
+       ac97->gpio_priv = gpio_priv;
+       gpio_priv->codec = codec;
+       gpio_priv->gpio_chip = snd_soc_ac97_gpio_chip;
+       gpio_priv->gpio_chip.ngpio = AC97_NUM_GPIOS;
+       gpio_priv->gpio_chip.dev = codec->dev;
+       gpio_priv->gpio_chip.base = -1;
+
+       ret = gpiochip_add(&gpio_priv->gpio_chip);
+       if (ret != 0)
+               dev_err(codec->dev, "Failed to add GPIOs: %d\n", ret);
+       return ret;
+}
+
+static void snd_soc_ac97_free_gpio(struct snd_ac97 *ac97)
+{
+       gpiochip_remove(&ac97->gpio_priv->gpio_chip);
+}
+#else
+static int snd_soc_ac97_init_gpio(struct snd_ac97 *ac97,
+                                 struct snd_soc_codec *codec)
+{
+       return 0;
+}
+
+static void snd_soc_ac97_free_gpio(struct snd_ac97 *ac97)
+{
+}
+#endif
+
 /**
  * snd_soc_alloc_ac97_codec() - Allocate new a AC'97 device
  * @codec: The CODEC for which to create the AC'97 device
@@ -119,6 +239,10 @@ struct snd_ac97 *snd_soc_new_ac97_codec(struct snd_soc_codec *codec,
        if (ret)
                goto err_put_device;
 
+       ret = snd_soc_ac97_init_gpio(ac97, codec);
+       if (ret)
+               goto err_put_device;
+
        return ac97;
 
 err_put_device:
@@ -135,6 +259,7 @@ EXPORT_SYMBOL_GPL(snd_soc_new_ac97_codec);
  */
 void snd_soc_free_ac97_codec(struct snd_ac97 *ac97)
 {
+       snd_soc_ac97_free_gpio(ac97);
        device_del(&ac97->dev);
        ac97->bus = NULL;
        put_device(&ac97->dev);
index 12a9820feac1548d5c3d3cbc50e0a8cc2bfefc25..bb82bb966000afc4ac9a106cc867474fffb5266d 100644 (file)
@@ -630,6 +630,7 @@ int snd_soc_new_compress(struct snd_soc_pcm_runtime *rtd, int num)
        struct snd_pcm *be_pcm;
        char new_name[64];
        int ret = 0, direction = 0;
+       int playback = 0, capture = 0;
 
        if (rtd->num_codecs > 1) {
                dev_err(rtd->card->dev, "Multicodec not supported for compressed stream\n");
@@ -641,11 +642,27 @@ int snd_soc_new_compress(struct snd_soc_pcm_runtime *rtd, int num)
                        rtd->dai_link->stream_name, codec_dai->name, num);
 
        if (codec_dai->driver->playback.channels_min)
+               playback = 1;
+       if (codec_dai->driver->capture.channels_min)
+               capture = 1;
+
+       capture = capture && cpu_dai->driver->capture.channels_min;
+       playback = playback && cpu_dai->driver->playback.channels_min;
+
+       /*
+        * Compress devices are unidirectional so only one of the directions
+        * should be set, check for that (xor)
+        */
+       if (playback + capture != 1) {
+               dev_err(rtd->card->dev, "Invalid direction for compress P %d, C %d\n",
+                               playback, capture);
+               return -EINVAL;
+       }
+
+       if(playback)
                direction = SND_COMPRESS_PLAYBACK;
-       else if (codec_dai->driver->capture.channels_min)
-               direction = SND_COMPRESS_CAPTURE;
        else
-               return -EINVAL;
+               direction = SND_COMPRESS_CAPTURE;
 
        compr = kzalloc(sizeof(*compr), GFP_KERNEL);
        if (compr == NULL) {
index 24b096066a07205c88e377e28f94eacff1261f3e..790ee2bf1a474b394a286f650b2772c8d3436c05 100644 (file)
@@ -537,26 +537,75 @@ static inline void snd_soc_debugfs_exit(void)
 struct snd_pcm_substream *snd_soc_get_dai_substream(struct snd_soc_card *card,
                const char *dai_link, int stream)
 {
-       int i;
+       struct snd_soc_pcm_runtime *rtd;
 
-       for (i = 0; i < card->num_links; i++) {
-               if (card->rtd[i].dai_link->no_pcm &&
-                       !strcmp(card->rtd[i].dai_link->name, dai_link))
-                       return card->rtd[i].pcm->streams[stream].substream;
+       list_for_each_entry(rtd, &card->rtd_list, list) {
+               if (rtd->dai_link->no_pcm &&
+                       !strcmp(rtd->dai_link->name, dai_link))
+                       return rtd->pcm->streams[stream].substream;
        }
        dev_dbg(card->dev, "ASoC: failed to find dai link %s\n", dai_link);
        return NULL;
 }
 EXPORT_SYMBOL_GPL(snd_soc_get_dai_substream);
 
+static struct snd_soc_pcm_runtime *soc_new_pcm_runtime(
+       struct snd_soc_card *card, struct snd_soc_dai_link *dai_link)
+{
+       struct snd_soc_pcm_runtime *rtd;
+
+       rtd = kzalloc(sizeof(struct snd_soc_pcm_runtime), GFP_KERNEL);
+       if (!rtd)
+               return NULL;
+
+       rtd->card = card;
+       rtd->dai_link = dai_link;
+       rtd->codec_dais = kzalloc(sizeof(struct snd_soc_dai *) *
+                                       dai_link->num_codecs,
+                                       GFP_KERNEL);
+       if (!rtd->codec_dais) {
+               kfree(rtd);
+               return NULL;
+       }
+
+       return rtd;
+}
+
+static void soc_free_pcm_runtime(struct snd_soc_pcm_runtime *rtd)
+{
+       if (rtd && rtd->codec_dais)
+               kfree(rtd->codec_dais);
+       kfree(rtd);
+}
+
+static void soc_add_pcm_runtime(struct snd_soc_card *card,
+               struct snd_soc_pcm_runtime *rtd)
+{
+       list_add_tail(&rtd->list, &card->rtd_list);
+       rtd->num = card->num_rtd;
+       card->num_rtd++;
+}
+
+static void soc_remove_pcm_runtimes(struct snd_soc_card *card)
+{
+       struct snd_soc_pcm_runtime *rtd, *_rtd;
+
+       list_for_each_entry_safe(rtd, _rtd, &card->rtd_list, list) {
+               list_del(&rtd->list);
+               soc_free_pcm_runtime(rtd);
+       }
+
+       card->num_rtd = 0;
+}
+
 struct snd_soc_pcm_runtime *snd_soc_get_pcm_runtime(struct snd_soc_card *card,
                const char *dai_link)
 {
-       int i;
+       struct snd_soc_pcm_runtime *rtd;
 
-       for (i = 0; i < card->num_links; i++) {
-               if (!strcmp(card->rtd[i].dai_link->name, dai_link))
-                       return &card->rtd[i];
+       list_for_each_entry(rtd, &card->rtd_list, list) {
+               if (!strcmp(rtd->dai_link->name, dai_link))
+                       return rtd;
        }
        dev_dbg(card->dev, "ASoC: failed to find rtd %s\n", dai_link);
        return NULL;
@@ -578,7 +627,8 @@ int snd_soc_suspend(struct device *dev)
 {
        struct snd_soc_card *card = dev_get_drvdata(dev);
        struct snd_soc_codec *codec;
-       int i, j;
+       struct snd_soc_pcm_runtime *rtd;
+       int i;
 
        /* If the card is not initialized yet there is nothing to do */
        if (!card->instantiated)
@@ -595,13 +645,13 @@ int snd_soc_suspend(struct device *dev)
        snd_power_change_state(card->snd_card, SNDRV_CTL_POWER_D3hot);
 
        /* mute any active DACs */
-       for (i = 0; i < card->num_rtd; i++) {
+       list_for_each_entry(rtd, &card->rtd_list, list) {
 
-               if (card->rtd[i].dai_link->ignore_suspend)
+               if (rtd->dai_link->ignore_suspend)
                        continue;
 
-               for (j = 0; j < card->rtd[i].num_codecs; j++) {
-                       struct snd_soc_dai *dai = card->rtd[i].codec_dais[j];
+               for (i = 0; i < rtd->num_codecs; i++) {
+                       struct snd_soc_dai *dai = rtd->codec_dais[i];
                        struct snd_soc_dai_driver *drv = dai->driver;
 
                        if (drv->ops->digital_mute && dai->playback_active)
@@ -610,20 +660,20 @@ int snd_soc_suspend(struct device *dev)
        }
 
        /* suspend all pcms */
-       for (i = 0; i < card->num_rtd; i++) {
-               if (card->rtd[i].dai_link->ignore_suspend)
+       list_for_each_entry(rtd, &card->rtd_list, list) {
+               if (rtd->dai_link->ignore_suspend)
                        continue;
 
-               snd_pcm_suspend_all(card->rtd[i].pcm);
+               snd_pcm_suspend_all(rtd->pcm);
        }
 
        if (card->suspend_pre)
                card->suspend_pre(card);
 
-       for (i = 0; i < card->num_rtd; i++) {
-               struct snd_soc_dai *cpu_dai = card->rtd[i].cpu_dai;
+       list_for_each_entry(rtd, &card->rtd_list, list) {
+               struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
 
-               if (card->rtd[i].dai_link->ignore_suspend)
+               if (rtd->dai_link->ignore_suspend)
                        continue;
 
                if (cpu_dai->driver->suspend && !cpu_dai->driver->bus_control)
@@ -631,19 +681,19 @@ int snd_soc_suspend(struct device *dev)
        }
 
        /* close any waiting streams */
-       for (i = 0; i < card->num_rtd; i++)
-               flush_delayed_work(&card->rtd[i].delayed_work);
+       list_for_each_entry(rtd, &card->rtd_list, list)
+               flush_delayed_work(&rtd->delayed_work);
 
-       for (i = 0; i < card->num_rtd; i++) {
+       list_for_each_entry(rtd, &card->rtd_list, list) {
 
-               if (card->rtd[i].dai_link->ignore_suspend)
+               if (rtd->dai_link->ignore_suspend)
                        continue;
 
-               snd_soc_dapm_stream_event(&card->rtd[i],
+               snd_soc_dapm_stream_event(rtd,
                                          SNDRV_PCM_STREAM_PLAYBACK,
                                          SND_SOC_DAPM_STREAM_SUSPEND);
 
-               snd_soc_dapm_stream_event(&card->rtd[i],
+               snd_soc_dapm_stream_event(rtd,
                                          SNDRV_PCM_STREAM_CAPTURE,
                                          SND_SOC_DAPM_STREAM_SUSPEND);
        }
@@ -690,10 +740,10 @@ int snd_soc_suspend(struct device *dev)
                }
        }
 
-       for (i = 0; i < card->num_rtd; i++) {
-               struct snd_soc_dai *cpu_dai = card->rtd[i].cpu_dai;
+       list_for_each_entry(rtd, &card->rtd_list, list) {
+               struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
 
-               if (card->rtd[i].dai_link->ignore_suspend)
+               if (rtd->dai_link->ignore_suspend)
                        continue;
 
                if (cpu_dai->driver->suspend && cpu_dai->driver->bus_control)
@@ -717,8 +767,9 @@ static void soc_resume_deferred(struct work_struct *work)
 {
        struct snd_soc_card *card =
                        container_of(work, struct snd_soc_card, deferred_resume_work);
+       struct snd_soc_pcm_runtime *rtd;
        struct snd_soc_codec *codec;
-       int i, j;
+       int i;
 
        /* our power state is still SNDRV_CTL_POWER_D3hot from suspend time,
         * so userspace apps are blocked from touching us
@@ -733,10 +784,10 @@ static void soc_resume_deferred(struct work_struct *work)
                card->resume_pre(card);
 
        /* resume control bus DAIs */
-       for (i = 0; i < card->num_rtd; i++) {
-               struct snd_soc_dai *cpu_dai = card->rtd[i].cpu_dai;
+       list_for_each_entry(rtd, &card->rtd_list, list) {
+               struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
 
-               if (card->rtd[i].dai_link->ignore_suspend)
+               if (rtd->dai_link->ignore_suspend)
                        continue;
 
                if (cpu_dai->driver->resume && cpu_dai->driver->bus_control)
@@ -751,28 +802,28 @@ static void soc_resume_deferred(struct work_struct *work)
                }
        }
 
-       for (i = 0; i < card->num_rtd; i++) {
+       list_for_each_entry(rtd, &card->rtd_list, list) {
 
-               if (card->rtd[i].dai_link->ignore_suspend)
+               if (rtd->dai_link->ignore_suspend)
                        continue;
 
-               snd_soc_dapm_stream_event(&card->rtd[i],
+               snd_soc_dapm_stream_event(rtd,
                                          SNDRV_PCM_STREAM_PLAYBACK,
                                          SND_SOC_DAPM_STREAM_RESUME);
 
-               snd_soc_dapm_stream_event(&card->rtd[i],
+               snd_soc_dapm_stream_event(rtd,
                                          SNDRV_PCM_STREAM_CAPTURE,
                                          SND_SOC_DAPM_STREAM_RESUME);
        }
 
        /* unmute any active DACs */
-       for (i = 0; i < card->num_rtd; i++) {
+       list_for_each_entry(rtd, &card->rtd_list, list) {
 
-               if (card->rtd[i].dai_link->ignore_suspend)
+               if (rtd->dai_link->ignore_suspend)
                        continue;
 
-               for (j = 0; j < card->rtd[i].num_codecs; j++) {
-                       struct snd_soc_dai *dai = card->rtd[i].codec_dais[j];
+               for (i = 0; i < rtd->num_codecs; i++) {
+                       struct snd_soc_dai *dai = rtd->codec_dais[i];
                        struct snd_soc_dai_driver *drv = dai->driver;
 
                        if (drv->ops->digital_mute && dai->playback_active)
@@ -780,10 +831,10 @@ static void soc_resume_deferred(struct work_struct *work)
                }
        }
 
-       for (i = 0; i < card->num_rtd; i++) {
-               struct snd_soc_dai *cpu_dai = card->rtd[i].cpu_dai;
+       list_for_each_entry(rtd, &card->rtd_list, list) {
+               struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
 
-               if (card->rtd[i].dai_link->ignore_suspend)
+               if (rtd->dai_link->ignore_suspend)
                        continue;
 
                if (cpu_dai->driver->resume && !cpu_dai->driver->bus_control)
@@ -795,12 +846,12 @@ static void soc_resume_deferred(struct work_struct *work)
 
        dev_dbg(card->dev, "ASoC: resume work completed\n");
 
-       /* userspace can access us now we are back as we were before */
-       snd_power_change_state(card->snd_card, SNDRV_CTL_POWER_D0);
-
        /* Recheck all endpoints too, their state is affected by suspend */
        dapm_mark_endpoints_dirty(card);
        snd_soc_dapm_sync(&card->dapm);
+
+       /* userspace can access us now we are back as we were before */
+       snd_power_change_state(card->snd_card, SNDRV_CTL_POWER_D0);
 }
 
 /* powers up audio subsystem after a suspend */
@@ -808,15 +859,14 @@ int snd_soc_resume(struct device *dev)
 {
        struct snd_soc_card *card = dev_get_drvdata(dev);
        bool bus_control = false;
-       int i;
+       struct snd_soc_pcm_runtime *rtd;
 
        /* If the card is not initialized yet there is nothing to do */
        if (!card->instantiated)
                return 0;
 
        /* activate pins from sleep state */
-       for (i = 0; i < card->num_rtd; i++) {
-               struct snd_soc_pcm_runtime *rtd = &card->rtd[i];
+       list_for_each_entry(rtd, &card->rtd_list, list) {
                struct snd_soc_dai **codec_dais = rtd->codec_dais;
                struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
                int j;
@@ -837,8 +887,8 @@ int snd_soc_resume(struct device *dev)
         * have that problem and may take a substantial amount of time to resume
         * due to I/O costs and anti-pop so handle them out of line.
         */
-       for (i = 0; i < card->num_rtd; i++) {
-               struct snd_soc_dai *cpu_dai = card->rtd[i].cpu_dai;
+       list_for_each_entry(rtd, &card->rtd_list, list) {
+               struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
                bus_control |= cpu_dai->driver->bus_control;
        }
        if (bus_control) {
@@ -910,18 +960,41 @@ static struct snd_soc_dai *snd_soc_find_dai(
        return NULL;
 }
 
-static int soc_bind_dai_link(struct snd_soc_card *card, int num)
+static bool soc_is_dai_link_bound(struct snd_soc_card *card,
+               struct snd_soc_dai_link *dai_link)
 {
-       struct snd_soc_dai_link *dai_link = &card->dai_link[num];
-       struct snd_soc_pcm_runtime *rtd = &card->rtd[num];
+       struct snd_soc_pcm_runtime *rtd;
+
+       list_for_each_entry(rtd, &card->rtd_list, list) {
+               if (rtd->dai_link == dai_link)
+                       return true;
+       }
+
+       return false;
+}
+
+static int soc_bind_dai_link(struct snd_soc_card *card,
+       struct snd_soc_dai_link *dai_link)
+{
+       struct snd_soc_pcm_runtime *rtd;
        struct snd_soc_dai_link_component *codecs = dai_link->codecs;
        struct snd_soc_dai_link_component cpu_dai_component;
-       struct snd_soc_dai **codec_dais = rtd->codec_dais;
+       struct snd_soc_dai **codec_dais;
        struct snd_soc_platform *platform;
        const char *platform_name;
        int i;
 
-       dev_dbg(card->dev, "ASoC: binding %s at idx %d\n", dai_link->name, num);
+       dev_dbg(card->dev, "ASoC: binding %s\n", dai_link->name);
+
+       rtd = soc_new_pcm_runtime(card, dai_link);
+       if (!rtd)
+               return -ENOMEM;
+
+       if (soc_is_dai_link_bound(card, dai_link)) {
+               dev_dbg(card->dev, "ASoC: dai link %s already bound\n",
+                       dai_link->name);
+               return 0;
+       }
 
        cpu_dai_component.name = dai_link->cpu_name;
        cpu_dai_component.of_node = dai_link->cpu_of_node;
@@ -930,18 +1003,19 @@ static int soc_bind_dai_link(struct snd_soc_card *card, int num)
        if (!rtd->cpu_dai) {
                dev_err(card->dev, "ASoC: CPU DAI %s not registered\n",
                        dai_link->cpu_dai_name);
-               return -EPROBE_DEFER;
+               goto _err_defer;
        }
 
        rtd->num_codecs = dai_link->num_codecs;
 
        /* Find CODEC from registered CODECs */
+       codec_dais = rtd->codec_dais;
        for (i = 0; i < rtd->num_codecs; i++) {
                codec_dais[i] = snd_soc_find_dai(&codecs[i]);
                if (!codec_dais[i]) {
                        dev_err(card->dev, "ASoC: CODEC DAI %s not registered\n",
                                codecs[i].dai_name);
-                       return -EPROBE_DEFER;
+                       goto _err_defer;
                }
        }
 
@@ -973,9 +1047,12 @@ static int soc_bind_dai_link(struct snd_soc_card *card, int num)
                return -EPROBE_DEFER;
        }
 
-       card->num_rtd++;
-
+       soc_add_pcm_runtime(card, rtd);
        return 0;
+
+_err_defer:
+       soc_free_pcm_runtime(rtd);
+       return  -EPROBE_DEFER;
 }
 
 static void soc_remove_component(struct snd_soc_component *component)
@@ -1014,9 +1091,9 @@ static void soc_remove_dai(struct snd_soc_dai *dai, int order)
        }
 }
 
-static void soc_remove_link_dais(struct snd_soc_card *card, int num, int order)
+static void soc_remove_link_dais(struct snd_soc_card *card,
+               struct snd_soc_pcm_runtime *rtd, int order)
 {
-       struct snd_soc_pcm_runtime *rtd = &card->rtd[num];
        int i;
 
        /* unregister the rtd device */
@@ -1032,10 +1109,9 @@ static void soc_remove_link_dais(struct snd_soc_card *card, int num, int order)
        soc_remove_dai(rtd->cpu_dai, order);
 }
 
-static void soc_remove_link_components(struct snd_soc_card *card, int num,
-                                      int order)
+static void soc_remove_link_components(struct snd_soc_card *card,
+       struct snd_soc_pcm_runtime *rtd, int order)
 {
-       struct snd_soc_pcm_runtime *rtd = &card->rtd[num];
        struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
        struct snd_soc_platform *platform = rtd->platform;
        struct snd_soc_component *component;
@@ -1061,23 +1137,200 @@ static void soc_remove_link_components(struct snd_soc_card *card, int num,
 
 static void soc_remove_dai_links(struct snd_soc_card *card)
 {
-       int dai, order;
+       int order;
+       struct snd_soc_pcm_runtime *rtd;
+       struct snd_soc_dai_link *link, *_link;
 
        for (order = SND_SOC_COMP_ORDER_FIRST; order <= SND_SOC_COMP_ORDER_LAST;
                        order++) {
-               for (dai = 0; dai < card->num_rtd; dai++)
-                       soc_remove_link_dais(card, dai, order);
+               list_for_each_entry(rtd, &card->rtd_list, list)
+                       soc_remove_link_dais(card, rtd, order);
        }
 
        for (order = SND_SOC_COMP_ORDER_FIRST; order <= SND_SOC_COMP_ORDER_LAST;
                        order++) {
-               for (dai = 0; dai < card->num_rtd; dai++)
-                       soc_remove_link_components(card, dai, order);
+               list_for_each_entry(rtd, &card->rtd_list, list)
+                       soc_remove_link_components(card, rtd, order);
        }
 
-       card->num_rtd = 0;
+       list_for_each_entry_safe(link, _link, &card->dai_link_list, list) {
+               if (link->dobj.type == SND_SOC_DOBJ_DAI_LINK)
+                       dev_warn(card->dev, "Topology forgot to remove link %s?\n",
+                               link->name);
+
+               list_del(&link->list);
+               card->num_dai_links--;
+       }
+}
+
+static int snd_soc_init_multicodec(struct snd_soc_card *card,
+                                  struct snd_soc_dai_link *dai_link)
+{
+       /* Legacy codec/codec_dai link is a single entry in multicodec */
+       if (dai_link->codec_name || dai_link->codec_of_node ||
+           dai_link->codec_dai_name) {
+               dai_link->num_codecs = 1;
+
+               dai_link->codecs = devm_kzalloc(card->dev,
+                               sizeof(struct snd_soc_dai_link_component),
+                               GFP_KERNEL);
+               if (!dai_link->codecs)
+                       return -ENOMEM;
+
+               dai_link->codecs[0].name = dai_link->codec_name;
+               dai_link->codecs[0].of_node = dai_link->codec_of_node;
+               dai_link->codecs[0].dai_name = dai_link->codec_dai_name;
+       }
+
+       if (!dai_link->codecs) {
+               dev_err(card->dev, "ASoC: DAI link has no CODECs\n");
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static int soc_init_dai_link(struct snd_soc_card *card,
+                                  struct snd_soc_dai_link *link)
+{
+       int i, ret;
+
+       ret = snd_soc_init_multicodec(card, link);
+       if (ret) {
+               dev_err(card->dev, "ASoC: failed to init multicodec\n");
+               return ret;
+       }
+
+       for (i = 0; i < link->num_codecs; i++) {
+               /*
+                * Codec must be specified by 1 of name or OF node,
+                * not both or neither.
+                */
+               if (!!link->codecs[i].name ==
+                   !!link->codecs[i].of_node) {
+                       dev_err(card->dev, "ASoC: Neither/both codec name/of_node are set for %s\n",
+                               link->name);
+                       return -EINVAL;
+               }
+               /* Codec DAI name must be specified */
+               if (!link->codecs[i].dai_name) {
+                       dev_err(card->dev, "ASoC: codec_dai_name not set for %s\n",
+                               link->name);
+                       return -EINVAL;
+               }
+       }
+
+       /*
+        * Platform may be specified by either name or OF node, but
+        * can be left unspecified, and a dummy platform will be used.
+        */
+       if (link->platform_name && link->platform_of_node) {
+               dev_err(card->dev,
+                       "ASoC: Both platform name/of_node are set for %s\n",
+                       link->name);
+               return -EINVAL;
+       }
+
+       /*
+        * CPU device may be specified by either name or OF node, but
+        * can be left unspecified, and will be matched based on DAI
+        * name alone..
+        */
+       if (link->cpu_name && link->cpu_of_node) {
+               dev_err(card->dev,
+                       "ASoC: Neither/both cpu name/of_node are set for %s\n",
+                       link->name);
+               return -EINVAL;
+       }
+       /*
+        * At least one of CPU DAI name or CPU device name/node must be
+        * specified
+        */
+       if (!link->cpu_dai_name &&
+           !(link->cpu_name || link->cpu_of_node)) {
+               dev_err(card->dev,
+                       "ASoC: Neither cpu_dai_name nor cpu_name/of_node are set for %s\n",
+                       link->name);
+               return -EINVAL;
+       }
+
+       return 0;
 }
 
+/**
+ * snd_soc_add_dai_link - Add a DAI link dynamically
+ * @card: The ASoC card to which the DAI link is added
+ * @dai_link: The new DAI link to add
+ *
+ * This function adds a DAI link to the ASoC card's link list.
+ *
+ * Note: Topology can use this API to add DAI links when probing the
+ * topology component. And machine drivers can still define static
+ * DAI links in dai_link array.
+ */
+int snd_soc_add_dai_link(struct snd_soc_card *card,
+               struct snd_soc_dai_link *dai_link)
+{
+       if (dai_link->dobj.type
+           && dai_link->dobj.type != SND_SOC_DOBJ_DAI_LINK) {
+               dev_err(card->dev, "Invalid dai link type %d\n",
+                       dai_link->dobj.type);
+               return -EINVAL;
+       }
+
+       lockdep_assert_held(&client_mutex);
+       /* Notify the machine driver for extra initialization
+        * on the link created by topology.
+        */
+       if (dai_link->dobj.type && card->add_dai_link)
+               card->add_dai_link(card, dai_link);
+
+       list_add_tail(&dai_link->list, &card->dai_link_list);
+       card->num_dai_links++;
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(snd_soc_add_dai_link);
+
+/**
+ * snd_soc_remove_dai_link - Remove a DAI link from the list
+ * @card: The ASoC card that owns the link
+ * @dai_link: The DAI link to remove
+ *
+ * This function removes a DAI link from the ASoC card's link list.
+ *
+ * For DAI links previously added by topology, topology should
+ * remove them by using the dobj embedded in the link.
+ */
+void snd_soc_remove_dai_link(struct snd_soc_card *card,
+                            struct snd_soc_dai_link *dai_link)
+{
+       struct snd_soc_dai_link *link, *_link;
+
+       if (dai_link->dobj.type
+           && dai_link->dobj.type != SND_SOC_DOBJ_DAI_LINK) {
+               dev_err(card->dev, "Invalid dai link type %d\n",
+                       dai_link->dobj.type);
+               return;
+       }
+
+       lockdep_assert_held(&client_mutex);
+       /* Notify the machine driver for extra destruction
+        * on the link created by topology.
+        */
+       if (dai_link->dobj.type && card->remove_dai_link)
+               card->remove_dai_link(card, dai_link);
+
+       list_for_each_entry_safe(link, _link, &card->dai_link_list, list) {
+               if (link == dai_link) {
+                       list_del(&link->list);
+                       card->num_dai_links--;
+                       return;
+               }
+       }
+}
+EXPORT_SYMBOL_GPL(snd_soc_remove_dai_link);
+
 static void soc_set_name_prefix(struct snd_soc_card *card,
                                struct snd_soc_component *component)
 {
@@ -1160,6 +1413,16 @@ static int soc_probe_component(struct snd_soc_card *card,
                        component->name);
        }
 
+       /* machine specific init */
+       if (component->init) {
+               ret = component->init(component);
+               if (ret < 0) {
+                       dev_err(component->dev,
+                               "Failed to do machine specific init %d\n", ret);
+                       goto err_probe;
+               }
+       }
+
        if (component->controls)
                snd_soc_add_component_controls(component, component->controls,
                                     component->num_controls);
@@ -1220,10 +1483,10 @@ static int soc_post_component_init(struct snd_soc_pcm_runtime *rtd,
        return 0;
 }
 
-static int soc_probe_link_components(struct snd_soc_card *card, int num,
+static int soc_probe_link_components(struct snd_soc_card *card,
+                       struct snd_soc_pcm_runtime *rtd,
                                     int order)
 {
-       struct snd_soc_pcm_runtime *rtd = &card->rtd[num];
        struct snd_soc_platform *platform = rtd->platform;
        struct snd_soc_component *component;
        int i, ret;
@@ -1283,35 +1546,35 @@ static int soc_link_dai_widgets(struct snd_soc_card *card,
 {
        struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
        struct snd_soc_dai *codec_dai = rtd->codec_dai;
-       struct snd_soc_dapm_widget *play_w, *capture_w;
+       struct snd_soc_dapm_widget *sink, *source;
        int ret;
 
        if (rtd->num_codecs > 1)
                dev_warn(card->dev, "ASoC: Multiple codecs not supported yet\n");
 
        /* link the DAI widgets */
-       play_w = codec_dai->playback_widget;
-       capture_w = cpu_dai->capture_widget;
-       if (play_w && capture_w) {
+       sink = codec_dai->playback_widget;
+       source = cpu_dai->capture_widget;
+       if (sink && source) {
                ret = snd_soc_dapm_new_pcm(card, dai_link->params,
-                                          dai_link->num_params, capture_w,
-                                          play_w);
+                                          dai_link->num_params,
+                                          source, sink);
                if (ret != 0) {
                        dev_err(card->dev, "ASoC: Can't link %s to %s: %d\n",
-                               play_w->name, capture_w->name, ret);
+                               sink->name, source->name, ret);
                        return ret;
                }
        }
 
-       play_w = cpu_dai->playback_widget;
-       capture_w = codec_dai->capture_widget;
-       if (play_w && capture_w) {
+       sink = cpu_dai->playback_widget;
+       source = codec_dai->capture_widget;
+       if (sink && source) {
                ret = snd_soc_dapm_new_pcm(card, dai_link->params,
-                                          dai_link->num_params, capture_w,
-                                          play_w);
+                                          dai_link->num_params,
+                                          source, sink);
                if (ret != 0) {
                        dev_err(card->dev, "ASoC: Can't link %s to %s: %d\n",
-                               play_w->name, capture_w->name, ret);
+                               sink->name, source->name, ret);
                        return ret;
                }
        }
@@ -1319,15 +1582,15 @@ static int soc_link_dai_widgets(struct snd_soc_card *card,
        return 0;
 }
 
-static int soc_probe_link_dais(struct snd_soc_card *card, int num, int order)
+static int soc_probe_link_dais(struct snd_soc_card *card,
+               struct snd_soc_pcm_runtime *rtd, int order)
 {
-       struct snd_soc_dai_link *dai_link = &card->dai_link[num];
-       struct snd_soc_pcm_runtime *rtd = &card->rtd[num];
+       struct snd_soc_dai_link *dai_link = rtd->dai_link;
        struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
        int i, ret;
 
        dev_dbg(card->dev, "ASoC: probe %s dai link %d late %d\n",
-                       card->name, num, order);
+                       card->name, rtd->num, order);
 
        /* set default power off timeout */
        rtd->pmdown_time = pmdown_time;
@@ -1372,7 +1635,7 @@ static int soc_probe_link_dais(struct snd_soc_card *card, int num, int order)
 
        if (cpu_dai->driver->compress_new) {
                /*create compress_device"*/
-               ret = cpu_dai->driver->compress_new(rtd, num);
+               ret = cpu_dai->driver->compress_new(rtd, rtd->num);
                if (ret < 0) {
                        dev_err(card->dev, "ASoC: can't create compress %s\n",
                                         dai_link->stream_name);
@@ -1382,7 +1645,7 @@ static int soc_probe_link_dais(struct snd_soc_card *card, int num, int order)
 
                if (!dai_link->params) {
                        /* create the pcm */
-                       ret = soc_new_pcm(rtd, num);
+                       ret = soc_new_pcm(rtd, rtd->num);
                        if (ret < 0) {
                                dev_err(card->dev, "ASoC: can't create pcm %s :%d\n",
                                       dai_link->stream_name, ret);
@@ -1404,65 +1667,81 @@ static int soc_probe_link_dais(struct snd_soc_card *card, int num, int order)
 
 static int soc_bind_aux_dev(struct snd_soc_card *card, int num)
 {
-       struct snd_soc_pcm_runtime *rtd = &card->rtd_aux[num];
        struct snd_soc_aux_dev *aux_dev = &card->aux_dev[num];
-       const char *name = aux_dev->codec_name;
-
-       rtd->component = soc_find_component(aux_dev->codec_of_node, name);
-       if (!rtd->component) {
-               if (aux_dev->codec_of_node)
-                       name = of_node_full_name(aux_dev->codec_of_node);
-
-               dev_err(card->dev, "ASoC: %s not registered\n", name);
-               return -EPROBE_DEFER;
+       struct snd_soc_component *component;
+       const char *name;
+       struct device_node *codec_of_node;
+
+       if (aux_dev->codec_of_node || aux_dev->codec_name) {
+               /* codecs, usually analog devices */
+               name = aux_dev->codec_name;
+               codec_of_node = aux_dev->codec_of_node;
+               component = soc_find_component(codec_of_node, name);
+               if (!component) {
+                       if (codec_of_node)
+                               name = of_node_full_name(codec_of_node);
+                       goto err_defer;
+               }
+       } else if (aux_dev->name) {
+               /* generic components */
+               name = aux_dev->name;
+               component = soc_find_component(NULL, name);
+               if (!component)
+                       goto err_defer;
+       } else {
+               dev_err(card->dev, "ASoC: Invalid auxiliary device\n");
+               return -EINVAL;
        }
 
-       /*
-        * Some places still reference rtd->codec, so we have to keep that
-        * initialized if the component is a CODEC. Once all those references
-        * have been removed, this code can be removed as well.
-        */
-        rtd->codec = rtd->component->codec;
-
+       component->init = aux_dev->init;
+       list_add(&component->list_aux, &card->aux_comp_list);
        return 0;
+
+err_defer:
+       dev_err(card->dev, "ASoC: %s not registered\n", name);
+       return -EPROBE_DEFER;
 }
 
-static int soc_probe_aux_dev(struct snd_soc_card *card, int num)
+static int soc_probe_aux_devices(struct snd_soc_card *card)
 {
-       struct snd_soc_pcm_runtime *rtd = &card->rtd_aux[num];
-       struct snd_soc_aux_dev *aux_dev = &card->aux_dev[num];
+       struct snd_soc_component *comp;
+       int order;
        int ret;
 
-       ret = soc_probe_component(card, rtd->component);
-       if (ret < 0)
-               return ret;
-
-       /* do machine specific initialization */
-       if (aux_dev->init) {
-               ret = aux_dev->init(rtd->component);
-               if (ret < 0) {
-                       dev_err(card->dev, "ASoC: failed to init %s: %d\n",
-                               aux_dev->name, ret);
-                       return ret;
+       for (order = SND_SOC_COMP_ORDER_FIRST; order <= SND_SOC_COMP_ORDER_LAST;
+               order++) {
+               list_for_each_entry(comp, &card->aux_comp_list, list_aux) {
+                       if (comp->driver->probe_order == order) {
+                               ret = soc_probe_component(card, comp);
+                               if (ret < 0) {
+                                       dev_err(card->dev,
+                                               "ASoC: failed to probe aux component %s %d\n",
+                                               comp->name, ret);
+                                       return ret;
+                               }
+                       }
                }
        }
 
-       return soc_post_component_init(rtd, aux_dev->name);
+       return 0;
 }
 
-static void soc_remove_aux_dev(struct snd_soc_card *card, int num)
+static void soc_remove_aux_devices(struct snd_soc_card *card)
 {
-       struct snd_soc_pcm_runtime *rtd = &card->rtd_aux[num];
-       struct snd_soc_component *component = rtd->component;
+       struct snd_soc_component *comp, *_comp;
+       int order;
 
-       /* unregister the rtd device */
-       if (rtd->dev_registered) {
-               device_unregister(rtd->dev);
-               rtd->dev_registered = 0;
+       for (order = SND_SOC_COMP_ORDER_FIRST; order <= SND_SOC_COMP_ORDER_LAST;
+               order++) {
+               list_for_each_entry_safe(comp, _comp,
+                       &card->aux_comp_list, list_aux) {
+                       if (comp->driver->remove_order == order) {
+                               soc_remove_component(comp);
+                               /* remove it from the card's aux_comp_list */
+                               list_del(&comp->list_aux);
+                       }
+               }
        }
-
-       if (component)
-               soc_remove_component(component);
 }
 
 static int snd_soc_init_codec_cache(struct snd_soc_codec *codec)
@@ -1552,6 +1831,8 @@ EXPORT_SYMBOL_GPL(snd_soc_runtime_set_dai_fmt);
 static int snd_soc_instantiate_card(struct snd_soc_card *card)
 {
        struct snd_soc_codec *codec;
+       struct snd_soc_pcm_runtime *rtd;
+       struct snd_soc_dai_link *dai_link;
        int ret, i, order;
 
        mutex_lock(&client_mutex);
@@ -1559,7 +1840,7 @@ static int snd_soc_instantiate_card(struct snd_soc_card *card)
 
        /* bind DAIs */
        for (i = 0; i < card->num_links; i++) {
-               ret = soc_bind_dai_link(card, i);
+               ret = soc_bind_dai_link(card, &card->dai_link[i]);
                if (ret != 0)
                        goto base_error;
        }
@@ -1571,6 +1852,10 @@ static int snd_soc_instantiate_card(struct snd_soc_card *card)
                        goto base_error;
        }
 
+       /* add predefined DAI links to the list */
+       for (i = 0; i < card->num_links; i++)
+               snd_soc_add_dai_link(card, card->dai_link+i);
+
        /* initialize the register cache for each available codec */
        list_for_each_entry(codec, &codec_list, list) {
                if (codec->cache_init)
@@ -1624,8 +1909,8 @@ static int snd_soc_instantiate_card(struct snd_soc_card *card)
        /* probe all components used by DAI links on this card */
        for (order = SND_SOC_COMP_ORDER_FIRST; order <= SND_SOC_COMP_ORDER_LAST;
                        order++) {
-               for (i = 0; i < card->num_links; i++) {
-                       ret = soc_probe_link_components(card, i, order);
+               list_for_each_entry(rtd, &card->rtd_list, list) {
+                       ret = soc_probe_link_components(card, rtd, order);
                        if (ret < 0) {
                                dev_err(card->dev,
                                        "ASoC: failed to instantiate card %d\n",
@@ -1635,11 +1920,31 @@ static int snd_soc_instantiate_card(struct snd_soc_card *card)
                }
        }
 
+       /* probe auxiliary components */
+       ret = soc_probe_aux_devices(card);
+       if (ret < 0)
+               goto probe_dai_err;
+
+       /* Find new DAI links added during probing components and bind them.
+        * Components with topology may bring new DAIs and DAI links.
+        */
+       list_for_each_entry(dai_link, &card->dai_link_list, list) {
+               if (soc_is_dai_link_bound(card, dai_link))
+                       continue;
+
+               ret = soc_init_dai_link(card, dai_link);
+               if (ret)
+                       goto probe_dai_err;
+               ret = soc_bind_dai_link(card, dai_link);
+               if (ret)
+                       goto probe_dai_err;
+       }
+
        /* probe all DAI links on this card */
        for (order = SND_SOC_COMP_ORDER_FIRST; order <= SND_SOC_COMP_ORDER_LAST;
                        order++) {
-               for (i = 0; i < card->num_links; i++) {
-                       ret = soc_probe_link_dais(card, i, order);
+               list_for_each_entry(rtd, &card->rtd_list, list) {
+                       ret = soc_probe_link_dais(card, rtd, order);
                        if (ret < 0) {
                                dev_err(card->dev,
                                        "ASoC: failed to instantiate card %d\n",
@@ -1649,16 +1954,6 @@ static int snd_soc_instantiate_card(struct snd_soc_card *card)
                }
        }
 
-       for (i = 0; i < card->num_aux_devs; i++) {
-               ret = soc_probe_aux_dev(card, i);
-               if (ret < 0) {
-                       dev_err(card->dev,
-                               "ASoC: failed to add auxiliary devices %d\n",
-                               ret);
-                       goto probe_aux_dev_err;
-               }
-       }
-
        snd_soc_dapm_link_dai_widgets(card);
        snd_soc_dapm_connect_dai_link_widgets(card);
 
@@ -1718,8 +2013,7 @@ static int snd_soc_instantiate_card(struct snd_soc_card *card)
        return 0;
 
 probe_aux_dev_err:
-       for (i = 0; i < card->num_aux_devs; i++)
-               soc_remove_aux_dev(card, i);
+       soc_remove_aux_devices(card);
 
 probe_dai_err:
        soc_remove_dai_links(card);
@@ -1733,6 +2027,7 @@ card_probe_error:
        snd_card_free(card->snd_card);
 
 base_error:
+       soc_remove_pcm_runtimes(card);
        mutex_unlock(&card->mutex);
        mutex_unlock(&client_mutex);
 
@@ -1763,20 +2058,18 @@ static int soc_probe(struct platform_device *pdev)
 
 static int soc_cleanup_card_resources(struct snd_soc_card *card)
 {
-       int i;
+       struct snd_soc_pcm_runtime *rtd;
 
        /* make sure any delayed work runs */
-       for (i = 0; i < card->num_rtd; i++) {
-               struct snd_soc_pcm_runtime *rtd = &card->rtd[i];
+       list_for_each_entry(rtd, &card->rtd_list, list)
                flush_delayed_work(&rtd->delayed_work);
-       }
-
-       /* remove auxiliary devices */
-       for (i = 0; i < card->num_aux_devs; i++)
-               soc_remove_aux_dev(card, i);
 
        /* remove and free each DAI */
        soc_remove_dai_links(card);
+       soc_remove_pcm_runtimes(card);
+
+       /* remove auxiliary devices */
+       soc_remove_aux_devices(card);
 
        soc_cleanup_card_debugfs(card);
 
@@ -1803,29 +2096,26 @@ static int soc_remove(struct platform_device *pdev)
 int snd_soc_poweroff(struct device *dev)
 {
        struct snd_soc_card *card = dev_get_drvdata(dev);
-       int i;
+       struct snd_soc_pcm_runtime *rtd;
 
        if (!card->instantiated)
                return 0;
 
        /* Flush out pmdown_time work - we actually do want to run it
         * now, we're shutting down so no imminent restart. */
-       for (i = 0; i < card->num_rtd; i++) {
-               struct snd_soc_pcm_runtime *rtd = &card->rtd[i];
+       list_for_each_entry(rtd, &card->rtd_list, list)
                flush_delayed_work(&rtd->delayed_work);
-       }
 
        snd_soc_dapm_shutdown(card);
 
        /* deactivate pins to sleep state */
-       for (i = 0; i < card->num_rtd; i++) {
-               struct snd_soc_pcm_runtime *rtd = &card->rtd[i];
+       list_for_each_entry(rtd, &card->rtd_list, list) {
                struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
-               int j;
+               int i;
 
                pinctrl_pm_select_sleep_state(cpu_dai->dev);
-               for (j = 0; j < rtd->num_codecs; j++) {
-                       struct snd_soc_dai *codec_dai = rtd->codec_dais[j];
+               for (i = 0; i < rtd->num_codecs; i++) {
+                       struct snd_soc_dai *codec_dai = rtd->codec_dais[i];
                        pinctrl_pm_select_sleep_state(codec_dai->dev);
                }
        }
@@ -2301,33 +2591,6 @@ int snd_soc_dai_digital_mute(struct snd_soc_dai *dai, int mute,
 }
 EXPORT_SYMBOL_GPL(snd_soc_dai_digital_mute);
 
-static int snd_soc_init_multicodec(struct snd_soc_card *card,
-                                  struct snd_soc_dai_link *dai_link)
-{
-       /* Legacy codec/codec_dai link is a single entry in multicodec */
-       if (dai_link->codec_name || dai_link->codec_of_node ||
-           dai_link->codec_dai_name) {
-               dai_link->num_codecs = 1;
-
-               dai_link->codecs = devm_kzalloc(card->dev,
-                               sizeof(struct snd_soc_dai_link_component),
-                               GFP_KERNEL);
-               if (!dai_link->codecs)
-                       return -ENOMEM;
-
-               dai_link->codecs[0].name = dai_link->codec_name;
-               dai_link->codecs[0].of_node = dai_link->codec_of_node;
-               dai_link->codecs[0].dai_name = dai_link->codec_dai_name;
-       }
-
-       if (!dai_link->codecs) {
-               dev_err(card->dev, "ASoC: DAI link has no CODECs\n");
-               return -EINVAL;
-       }
-
-       return 0;
-}
-
 /**
  * snd_soc_register_card - Register a card with the ASoC core
  *
@@ -2336,7 +2599,8 @@ static int snd_soc_init_multicodec(struct snd_soc_card *card,
  */
 int snd_soc_register_card(struct snd_soc_card *card)
 {
-       int i, j, ret;
+       int i, ret;
+       struct snd_soc_pcm_runtime *rtd;
 
        if (!card->name || !card->dev)
                return -EINVAL;
@@ -2344,63 +2608,11 @@ int snd_soc_register_card(struct snd_soc_card *card)
        for (i = 0; i < card->num_links; i++) {
                struct snd_soc_dai_link *link = &card->dai_link[i];
 
-               ret = snd_soc_init_multicodec(card, link);
+               ret = soc_init_dai_link(card, link);
                if (ret) {
-                       dev_err(card->dev, "ASoC: failed to init multicodec\n");
-                       return ret;
-               }
-
-               for (j = 0; j < link->num_codecs; j++) {
-                       /*
-                        * Codec must be specified by 1 of name or OF node,
-                        * not both or neither.
-                        */
-                       if (!!link->codecs[j].name ==
-                           !!link->codecs[j].of_node) {
-                               dev_err(card->dev, "ASoC: Neither/both codec name/of_node are set for %s\n",
-                                       link->name);
-                               return -EINVAL;
-                       }
-                       /* Codec DAI name must be specified */
-                       if (!link->codecs[j].dai_name) {
-                               dev_err(card->dev, "ASoC: codec_dai_name not set for %s\n",
-                                       link->name);
-                               return -EINVAL;
-                       }
-               }
-
-               /*
-                * Platform may be specified by either name or OF node, but
-                * can be left unspecified, and a dummy platform will be used.
-                */
-               if (link->platform_name && link->platform_of_node) {
-                       dev_err(card->dev,
-                               "ASoC: Both platform name/of_node are set for %s\n",
-                               link->name);
-                       return -EINVAL;
-               }
-
-               /*
-                * CPU device may be specified by either name or OF node, but
-                * can be left unspecified, and will be matched based on DAI
-                * name alone..
-                */
-               if (link->cpu_name && link->cpu_of_node) {
-                       dev_err(card->dev,
-                               "ASoC: Neither/both cpu name/of_node are set for %s\n",
-                               link->name);
-                       return -EINVAL;
-               }
-               /*
-                * At least one of CPU DAI name or CPU device name/node must be
-                * specified
-                */
-               if (!link->cpu_dai_name &&
-                   !(link->cpu_name || link->cpu_of_node)) {
-                       dev_err(card->dev,
-                               "ASoC: Neither cpu_dai_name nor cpu_name/of_node are set for %s\n",
+                       dev_err(card->dev, "ASoC: failed to init link %s\n",
                                link->name);
-                       return -EINVAL;
+                       return ret;
                }
        }
 
@@ -2408,28 +2620,11 @@ int snd_soc_register_card(struct snd_soc_card *card)
 
        snd_soc_initialize_card_lists(card);
 
-       card->rtd = devm_kzalloc(card->dev,
-                                sizeof(struct snd_soc_pcm_runtime) *
-                                (card->num_links + card->num_aux_devs),
-                                GFP_KERNEL);
-       if (card->rtd == NULL)
-               return -ENOMEM;
-       card->num_rtd = 0;
-       card->rtd_aux = &card->rtd[card->num_links];
+       INIT_LIST_HEAD(&card->dai_link_list);
+       card->num_dai_links = 0;
 
-       for (i = 0; i < card->num_links; i++) {
-               card->rtd[i].card = card;
-               card->rtd[i].dai_link = &card->dai_link[i];
-               card->rtd[i].codec_dais = devm_kzalloc(card->dev,
-                                       sizeof(struct snd_soc_dai *) *
-                                       (card->rtd[i].dai_link->num_codecs),
-                                       GFP_KERNEL);
-               if (card->rtd[i].codec_dais == NULL)
-                       return -ENOMEM;
-       }
-
-       for (i = 0; i < card->num_aux_devs; i++)
-               card->rtd_aux[i].card = card;
+       INIT_LIST_HEAD(&card->rtd_list);
+       card->num_rtd = 0;
 
        INIT_LIST_HEAD(&card->dapm_dirty);
        INIT_LIST_HEAD(&card->dobj_list);
@@ -2442,8 +2637,7 @@ int snd_soc_register_card(struct snd_soc_card *card)
                return ret;
 
        /* deactivate pins to sleep state */
-       for (i = 0; i < card->num_rtd; i++) {
-               struct snd_soc_pcm_runtime *rtd = &card->rtd[i];
+       list_for_each_entry(rtd, &card->rtd_list, list)  {
                struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
                int j;
 
@@ -2558,6 +2752,56 @@ static void snd_soc_unregister_dais(struct snd_soc_component *component)
        }
 }
 
+/* Create a DAI and add it to the component's DAI list */
+static struct snd_soc_dai *soc_add_dai(struct snd_soc_component *component,
+       struct snd_soc_dai_driver *dai_drv,
+       bool legacy_dai_naming)
+{
+       struct device *dev = component->dev;
+       struct snd_soc_dai *dai;
+
+       dev_dbg(dev, "ASoC: dynamically register DAI %s\n", dev_name(dev));
+
+       dai = kzalloc(sizeof(struct snd_soc_dai), GFP_KERNEL);
+       if (dai == NULL)
+               return NULL;
+
+       /*
+        * Back in the old days when we still had component-less DAIs,
+        * instead of having a static name, component-less DAIs would
+        * inherit the name of the parent device so it is possible to
+        * register multiple instances of the DAI. We still need to keep
+        * the same naming style even though those DAIs are not
+        * component-less anymore.
+        */
+       if (legacy_dai_naming &&
+          (dai_drv->id == 0 || dai_drv->name == NULL)) {
+               dai->name = fmt_single_name(dev, &dai->id);
+       } else {
+               dai->name = fmt_multiple_name(dev, dai_drv);
+               if (dai_drv->id)
+                       dai->id = dai_drv->id;
+               else
+                       dai->id = component->num_dai;
+       }
+       if (dai->name == NULL) {
+               kfree(dai);
+               return NULL;
+       }
+
+       dai->component = component;
+       dai->dev = dev;
+       dai->driver = dai_drv;
+       if (!dai->driver->ops)
+               dai->driver->ops = &null_dai_ops;
+
+       list_add(&dai->list, &component->dai_list);
+       component->num_dai++;
+
+       dev_dbg(dev, "ASoC: Registered DAI '%s'\n", dai->name);
+       return dai;
+}
+
 /**
  * snd_soc_register_dais - Register a DAI with the ASoC core
  *
@@ -2579,58 +2823,66 @@ static int snd_soc_register_dais(struct snd_soc_component *component,
        dev_dbg(dev, "ASoC: dai register %s #%Zu\n", dev_name(dev), count);
 
        component->dai_drv = dai_drv;
-       component->num_dai = count;
 
        for (i = 0; i < count; i++) {
 
-               dai = kzalloc(sizeof(struct snd_soc_dai), GFP_KERNEL);
+               dai = soc_add_dai(component, dai_drv + i,
+                               count == 1 && legacy_dai_naming);
                if (dai == NULL) {
                        ret = -ENOMEM;
                        goto err;
                }
+       }
 
-               /*
-                * Back in the old days when we still had component-less DAIs,
-                * instead of having a static name, component-less DAIs would
-                * inherit the name of the parent device so it is possible to
-                * register multiple instances of the DAI. We still need to keep
-                * the same naming style even though those DAIs are not
-                * component-less anymore.
-                */
-               if (count == 1 && legacy_dai_naming &&
-                       (dai_drv[i].id == 0 || dai_drv[i].name == NULL)) {
-                       dai->name = fmt_single_name(dev, &dai->id);
-               } else {
-                       dai->name = fmt_multiple_name(dev, &dai_drv[i]);
-                       if (dai_drv[i].id)
-                               dai->id = dai_drv[i].id;
-                       else
-                               dai->id = i;
-               }
-               if (dai->name == NULL) {
-                       kfree(dai);
-                       ret = -ENOMEM;
-                       goto err;
-               }
+       return 0;
 
-               dai->component = component;
-               dai->dev = dev;
-               dai->driver = &dai_drv[i];
-               if (!dai->driver->ops)
-                       dai->driver->ops = &null_dai_ops;
+err:
+       snd_soc_unregister_dais(component);
 
-               list_add(&dai->list, &component->dai_list);
+       return ret;
+}
+
+/**
+ * snd_soc_register_dai - Register a DAI dynamically & create its widgets
+ *
+ * @component: The component the DAIs are registered for
+ * @dai_drv: DAI driver to use for the DAI
+ *
+ * Topology can use this API to register DAIs when probing a component.
+ * These DAIs's widgets will be freed in the card cleanup and the DAIs
+ * will be freed in the component cleanup.
+ */
+int snd_soc_register_dai(struct snd_soc_component *component,
+       struct snd_soc_dai_driver *dai_drv)
+{
+       struct snd_soc_dapm_context *dapm =
+               snd_soc_component_get_dapm(component);
+       struct snd_soc_dai *dai;
+       int ret;
 
-               dev_dbg(dev, "ASoC: Registered DAI '%s'\n", dai->name);
+       if (dai_drv->dobj.type != SND_SOC_DOBJ_PCM) {
+               dev_err(component->dev, "Invalid dai type %d\n",
+                       dai_drv->dobj.type);
+               return -EINVAL;
        }
 
-       return 0;
+       lockdep_assert_held(&client_mutex);
+       dai = soc_add_dai(component, dai_drv, false);
+       if (!dai)
+               return -ENOMEM;
 
-err:
-       snd_soc_unregister_dais(component);
+       /* Create the DAI widgets here. After adding DAIs, topology may
+        * also add routes that need these widgets as source or sink.
+        */
+       ret = snd_soc_dapm_new_dai_widgets(dapm, dai);
+       if (ret != 0) {
+               dev_err(component->dev,
+                       "Failed to create DAI widgets %d\n", ret);
+       }
 
        return ret;
 }
+EXPORT_SYMBOL_GPL(snd_soc_register_dai);
 
 static void snd_soc_component_seq_notifier(struct snd_soc_dapm_context *dapm,
        enum snd_soc_dapm_type type, int subseq)
index 016eba10b1ec2744a8b9b1b3492d6c0fa1c7a561..5a2812fa8946071014d54f9c18ae8311be56fe4e 100644 (file)
@@ -1300,7 +1300,7 @@ static int dapm_supply_check_power(struct snd_soc_dapm_widget *w)
 
 static int dapm_always_on_check_power(struct snd_soc_dapm_widget *w)
 {
-       return 1;
+       return w->connected;
 }
 
 static int dapm_seq_compare(struct snd_soc_dapm_widget *a,
@@ -2293,6 +2293,12 @@ void snd_soc_dapm_free_widget(struct snd_soc_dapm_widget *w)
        kfree(w);
 }
 
+void snd_soc_dapm_reset_cache(struct snd_soc_dapm_context *dapm)
+{
+       dapm->path_sink_cache.widget = NULL;
+       dapm->path_source_cache.widget = NULL;
+}
+
 /* free all dapm widgets and resources */
 static void dapm_free_widgets(struct snd_soc_dapm_context *dapm)
 {
@@ -2303,6 +2309,7 @@ static void dapm_free_widgets(struct snd_soc_dapm_context *dapm)
                        continue;
                snd_soc_dapm_free_widget(w);
        }
+       snd_soc_dapm_reset_cache(dapm);
 }
 
 static struct snd_soc_dapm_widget *dapm_find_widget(
@@ -3351,6 +3358,11 @@ snd_soc_dapm_new_control_unlocked(struct snd_soc_dapm_context *dapm,
                w->is_ep = SND_SOC_DAPM_EP_SOURCE;
                w->power_check = dapm_always_on_check_power;
                break;
+       case snd_soc_dapm_sink:
+               w->is_ep = SND_SOC_DAPM_EP_SINK;
+               w->power_check = dapm_always_on_check_power;
+               break;
+
        case snd_soc_dapm_mux:
        case snd_soc_dapm_demux:
        case snd_soc_dapm_switch:
@@ -3893,13 +3905,10 @@ static void soc_dapm_dai_stream_event(struct snd_soc_dai *dai, int stream,
 
 void snd_soc_dapm_connect_dai_link_widgets(struct snd_soc_card *card)
 {
-       struct snd_soc_pcm_runtime *rtd = card->rtd;
-       int i;
+       struct snd_soc_pcm_runtime *rtd;
 
        /* for each BE DAI link... */
-       for (i = 0; i < card->num_rtd; i++) {
-               rtd = &card->rtd[i];
-
+       list_for_each_entry(rtd, &card->rtd_list, list)  {
                /*
                 * dynamic FE links have no fixed DAI mapping.
                 * CODEC<->CODEC links have no direct connection.
index ecd38e52285a964d53fce4c5c0d4ae71fd4bc15d..a513a34a51d299a8bf7d9ef7799717ceb4a42430 100644 (file)
@@ -404,7 +404,7 @@ EXPORT_SYMBOL_GPL(snd_soc_get_volsw_sx);
 /**
  * snd_soc_put_volsw_sx - double mixer set callback
  * @kcontrol: mixer control
- * @uinfo: control element information
+ * @ucontrol: control element information
  *
  * Callback to set the value of a double mixer control that spans 2 registers.
  *
@@ -779,11 +779,11 @@ int snd_soc_bytes_tlv_callback(struct snd_kcontrol *kcontrol, int op_flag,
        switch (op_flag) {
        case SNDRV_CTL_TLV_OP_READ:
                if (params->get)
-                       ret = params->get(tlv, count);
+                       ret = params->get(kcontrol, tlv, count);
                break;
        case SNDRV_CTL_TLV_OP_WRITE:
                if (params->put)
-                       ret = params->put(tlv, count);
+                       ret = params->put(kcontrol, tlv, count);
                break;
        }
        return ret;
index c86dc96e8986f39cd08bcf7e92c63f49459d50f2..e898b427be7ee34961451b2d8b177848415436ed 100644 (file)
@@ -599,10 +599,15 @@ platform_err:
 out:
        mutex_unlock(&rtd->pcm_mutex);
 
-       pm_runtime_put(platform->dev);
-       for (i = 0; i < rtd->num_codecs; i++)
-               pm_runtime_put(rtd->codec_dais[i]->dev);
-       pm_runtime_put(cpu_dai->dev);
+       pm_runtime_mark_last_busy(platform->dev);
+       pm_runtime_put_autosuspend(platform->dev);
+       for (i = 0; i < rtd->num_codecs; i++) {
+               pm_runtime_mark_last_busy(rtd->codec_dais[i]->dev);
+               pm_runtime_put_autosuspend(rtd->codec_dais[i]->dev);
+       }
+
+       pm_runtime_mark_last_busy(cpu_dai->dev);
+       pm_runtime_put_autosuspend(cpu_dai->dev);
        for (i = 0; i < rtd->num_codecs; i++) {
                if (!rtd->codec_dais[i]->active)
                        pinctrl_pm_select_sleep_state(rtd->codec_dais[i]->dev);
@@ -706,10 +711,17 @@ static int soc_pcm_close(struct snd_pcm_substream *substream)
 
        mutex_unlock(&rtd->pcm_mutex);
 
-       pm_runtime_put(platform->dev);
-       for (i = 0; i < rtd->num_codecs; i++)
-               pm_runtime_put(rtd->codec_dais[i]->dev);
-       pm_runtime_put(cpu_dai->dev);
+       pm_runtime_mark_last_busy(platform->dev);
+       pm_runtime_put_autosuspend(platform->dev);
+
+       for (i = 0; i < rtd->num_codecs; i++) {
+               pm_runtime_mark_last_busy(rtd->codec_dais[i]->dev);
+               pm_runtime_put_autosuspend(rtd->codec_dais[i]->dev);
+       }
+
+       pm_runtime_mark_last_busy(cpu_dai->dev);
+       pm_runtime_put_autosuspend(cpu_dai->dev);
+
        for (i = 0; i < rtd->num_codecs; i++) {
                if (!rtd->codec_dais[i]->active)
                        pinctrl_pm_select_sleep_state(rtd->codec_dais[i]->dev);
@@ -1213,11 +1225,10 @@ static struct snd_soc_pcm_runtime *dpcm_get_be(struct snd_soc_card *card,
                struct snd_soc_dapm_widget *widget, int stream)
 {
        struct snd_soc_pcm_runtime *be;
-       int i, j;
+       int i;
 
        if (stream == SNDRV_PCM_STREAM_PLAYBACK) {
-               for (i = 0; i < card->num_links; i++) {
-                       be = &card->rtd[i];
+               list_for_each_entry(be, &card->rtd_list, list) {
 
                        if (!be->dai_link->no_pcm)
                                continue;
@@ -1225,16 +1236,15 @@ static struct snd_soc_pcm_runtime *dpcm_get_be(struct snd_soc_card *card,
                        if (be->cpu_dai->playback_widget == widget)
                                return be;
 
-                       for (j = 0; j < be->num_codecs; j++) {
-                               struct snd_soc_dai *dai = be->codec_dais[j];
+                       for (i = 0; i < be->num_codecs; i++) {
+                               struct snd_soc_dai *dai = be->codec_dais[i];
                                if (dai->playback_widget == widget)
                                        return be;
                        }
                }
        } else {
 
-               for (i = 0; i < card->num_links; i++) {
-                       be = &card->rtd[i];
+               list_for_each_entry(be, &card->rtd_list, list) {
 
                        if (!be->dai_link->no_pcm)
                                continue;
@@ -1242,8 +1252,8 @@ static struct snd_soc_pcm_runtime *dpcm_get_be(struct snd_soc_card *card,
                        if (be->cpu_dai->capture_widget == widget)
                                return be;
 
-                       for (j = 0; j < be->num_codecs; j++) {
-                               struct snd_soc_dai *dai = be->codec_dais[j];
+                       for (i = 0; i < be->num_codecs; i++) {
+                               struct snd_soc_dai *dai = be->codec_dais[i];
                                if (dai->capture_widget == widget)
                                        return be;
                        }
@@ -1616,6 +1626,56 @@ static void dpcm_set_fe_update_state(struct snd_soc_pcm_runtime *fe,
        snd_pcm_stream_unlock_irq(substream);
 }
 
+static int dpcm_apply_symmetry(struct snd_pcm_substream *fe_substream,
+                              int stream)
+{
+       struct snd_soc_dpcm *dpcm;
+       struct snd_soc_pcm_runtime *fe = fe_substream->private_data;
+       struct snd_soc_dai *fe_cpu_dai = fe->cpu_dai;
+       int err;
+
+       /* apply symmetry for FE */
+       if (soc_pcm_has_symmetry(fe_substream))
+               fe_substream->runtime->hw.info |= SNDRV_PCM_INFO_JOINT_DUPLEX;
+
+       /* Symmetry only applies if we've got an active stream. */
+       if (fe_cpu_dai->active) {
+               err = soc_pcm_apply_symmetry(fe_substream, fe_cpu_dai);
+               if (err < 0)
+                       return err;
+       }
+
+       /* apply symmetry for BE */
+       list_for_each_entry(dpcm, &fe->dpcm[stream].be_clients, list_be) {
+               struct snd_soc_pcm_runtime *be = dpcm->be;
+               struct snd_pcm_substream *be_substream =
+                       snd_soc_dpcm_get_substream(be, stream);
+               struct snd_soc_pcm_runtime *rtd = be_substream->private_data;
+               int i;
+
+               if (soc_pcm_has_symmetry(be_substream))
+                       be_substream->runtime->hw.info |= SNDRV_PCM_INFO_JOINT_DUPLEX;
+
+               /* Symmetry only applies if we've got an active stream. */
+               if (rtd->cpu_dai->active) {
+                       err = soc_pcm_apply_symmetry(be_substream, rtd->cpu_dai);
+                       if (err < 0)
+                               return err;
+               }
+
+               for (i = 0; i < rtd->num_codecs; i++) {
+                       if (rtd->codec_dais[i]->active) {
+                               err = soc_pcm_apply_symmetry(be_substream,
+                                                            rtd->codec_dais[i]);
+                               if (err < 0)
+                                       return err;
+                       }
+               }
+       }
+
+       return 0;
+}
+
 static int dpcm_fe_dai_startup(struct snd_pcm_substream *fe_substream)
 {
        struct snd_soc_pcm_runtime *fe = fe_substream->private_data;
@@ -1644,6 +1704,13 @@ static int dpcm_fe_dai_startup(struct snd_pcm_substream *fe_substream)
        dpcm_set_fe_runtime(fe_substream);
        snd_pcm_limit_hw_rates(runtime);
 
+       ret = dpcm_apply_symmetry(fe_substream, stream);
+       if (ret < 0) {
+               dev_err(fe->dev, "ASoC: failed to apply dpcm symmetry %d\n",
+                       ret);
+               goto unwind;
+       }
+
        dpcm_set_fe_update_state(fe, stream, SND_SOC_DPCM_UPDATE_NO);
        return 0;
 
@@ -2115,7 +2182,8 @@ int dpcm_be_dai_prepare(struct snd_soc_pcm_runtime *fe, int stream)
                        continue;
 
                if ((be->dpcm[stream].state != SND_SOC_DPCM_STATE_HW_PARAMS) &&
-                   (be->dpcm[stream].state != SND_SOC_DPCM_STATE_STOP))
+                   (be->dpcm[stream].state != SND_SOC_DPCM_STATE_STOP) &&
+                   (be->dpcm[stream].state != SND_SOC_DPCM_STATE_SUSPEND))
                        continue;
 
                dev_dbg(be->dev, "ASoC: prepare BE %s\n",
@@ -2343,12 +2411,12 @@ static int dpcm_run_old_update(struct snd_soc_pcm_runtime *fe, int stream)
  */
 int soc_dpcm_runtime_update(struct snd_soc_card *card)
 {
-       int i, old, new, paths;
+       struct snd_soc_pcm_runtime *fe;
+       int old, new, paths;
 
        mutex_lock_nested(&card->mutex, SND_SOC_CARD_CLASS_RUNTIME);
-       for (i = 0; i < card->num_rtd; i++) {
+       list_for_each_entry(fe, &card->rtd_list, list) {
                struct snd_soc_dapm_widget_list *list;
-               struct snd_soc_pcm_runtime *fe = &card->rtd[i];
 
                /* make sure link is FE */
                if (!fe->dai_link->dynamic)
index 8d7ec80af51b499738dc2032356896a08144078a..6963ba20991c10066fdad2ad65f3102fc5752424 100644 (file)
@@ -531,7 +531,7 @@ static int soc_tplg_kcontrol_bind_io(struct snd_soc_tplg_ctl_hdr *hdr,
                /* TLV bytes controls need standard kcontrol info handler,
                 * TLV callback and extended put/get handlers.
                 */
-               k->info = snd_soc_bytes_info;
+               k->info = snd_soc_bytes_info_ext;
                k->tlv.c = snd_soc_bytes_tlv_callback;
 
                ext_ops = tplg->bytes_ext_ops;
@@ -1805,6 +1805,7 @@ void snd_soc_tplg_widget_remove_all(struct snd_soc_dapm_context *dapm,
                snd_soc_tplg_widget_remove(w);
                snd_soc_dapm_free_widget(w);
        }
+       snd_soc_dapm_reset_cache(dapm);
 }
 EXPORT_SYMBOL_GPL(snd_soc_tplg_widget_remove_all);
 
index 843f037a317da31aecc0b1761ddde2dfa24a1334..7aca6b92f71863a41b33f9b9ff6dada0977daf47 100644 (file)
@@ -251,8 +251,7 @@ static void uni_player_set_channel_status(struct uniperif *player,
         * set one.
         */
        mutex_lock(&player->ctrl_lock);
-       if (runtime && (player->stream_settings.iec958.status[3]
-                                       == IEC958_AES3_CON_FS_NOTID)) {
+       if (runtime) {
                switch (runtime->rate) {
                case 22050:
                        player->stream_settings.iec958.status[3] =
@@ -669,6 +668,7 @@ static int uni_player_startup(struct snd_pcm_substream *substream,
 {
        struct sti_uniperiph_data *priv = snd_soc_dai_get_drvdata(dai);
        struct uniperif *player = priv->dai_data.uni;
+       player->substream = substream;
 
        player->clk_adj = 0;
 
@@ -950,6 +950,8 @@ static void uni_player_shutdown(struct snd_pcm_substream *substream,
        if (player->state != UNIPERIF_STATE_STOPPED)
                /* Stop the player */
                uni_player_stop(player);
+
+       player->substream = NULL;
 }
 
 static int uni_player_parse_dt_clk_glue(struct platform_device *pdev,
@@ -989,7 +991,7 @@ static int uni_player_parse_dt(struct platform_device *pdev,
        if (!info)
                return -ENOMEM;
 
-       if (of_property_read_u32(pnode, "version", &player->ver) ||
+       if (of_property_read_u32(pnode, "st,version", &player->ver) ||
            player->ver == SND_ST_UNIPERIF_VERSION_UNKNOWN) {
                dev_err(dev, "Unknown uniperipheral version ");
                return -EINVAL;
@@ -998,13 +1000,13 @@ static int uni_player_parse_dt(struct platform_device *pdev,
        if (player->ver >= SND_ST_UNIPERIF_VERSION_UNI_PLR_TOP_1_0)
                info->underflow_enabled = 1;
 
-       if (of_property_read_u32(pnode, "uniperiph-id", &info->id)) {
+       if (of_property_read_u32(pnode, "st,uniperiph-id", &info->id)) {
                dev_err(dev, "uniperipheral id not defined");
                return -EINVAL;
        }
 
        /* Read the device mode property */
-       if (of_property_read_string(pnode, "mode", &mode)) {
+       if (of_property_read_string(pnode, "st,mode", &mode)) {
                dev_err(dev, "uniperipheral mode not defined");
                return -EINVAL;
        }
index f791239a30872927b4c117f43ec457da6532b037..8a0eb20501694b16bf90991c3bbd71bce1461296 100644 (file)
@@ -316,7 +316,7 @@ static int uni_reader_parse_dt(struct platform_device *pdev,
        if (!info)
                return -ENOMEM;
 
-       if (of_property_read_u32(node, "version", &reader->ver) ||
+       if (of_property_read_u32(node, "st,version", &reader->ver) ||
            reader->ver == SND_ST_UNIPERIF_VERSION_UNKNOWN) {
                dev_err(&pdev->dev, "Unknown uniperipheral version ");
                return -EINVAL;
@@ -346,7 +346,6 @@ int uni_reader_init(struct platform_device *pdev,
        reader->hw = &uni_reader_pcm_hw;
        reader->dai_ops = &uni_reader_dai_ops;
 
-       dev_err(reader->dev, "%s: enter\n", __func__);
        ret = uni_reader_parse_dt(pdev, reader);
        if (ret < 0) {
                dev_err(reader->dev, "Failed to parse DeviceTree");
index bcbf4da168b637341cdd7f3a35b084ab576ede36..44f170c73b06a95a71d3b1a1680db37a8fb227f8 100644 (file)
@@ -2,6 +2,7 @@
  * Copyright 2014 Emilio López <emilio@elopez.com.ar>
  * Copyright 2014 Jon Smirl <jonsmirl@gmail.com>
  * Copyright 2015 Maxime Ripard <maxime.ripard@free-electrons.com>
+ * Copyright 2015 Adam Sampson <ats@offog.org>
  *
  * Based on the Allwinner SDK driver, released under the GPL.
  *
@@ -27,6 +28,7 @@
 #include <linux/of_address.h>
 #include <linux/clk.h>
 #include <linux/regmap.h>
+#include <linux/gpio/consumer.h>
 
 #include <sound/core.h>
 #include <sound/pcm.h>
@@ -69,6 +71,7 @@
 
 /* Codec ADC register offsets and bit fields */
 #define SUN4I_CODEC_ADC_FIFOC                  (0x1c)
+#define SUN4I_CODEC_ADC_FIFOC_ADC_FS                   (29)
 #define SUN4I_CODEC_ADC_FIFOC_EN_AD                    (28)
 #define SUN4I_CODEC_ADC_FIFOC_RX_FIFO_MODE             (24)
 #define SUN4I_CODEC_ADC_FIFOC_RX_TRIG_LEVEL            (8)
@@ -101,17 +104,14 @@ struct sun4i_codec {
        struct regmap   *regmap;
        struct clk      *clk_apb;
        struct clk      *clk_module;
+       struct gpio_desc *gpio_pa;
 
+       struct snd_dmaengine_dai_dma_data       capture_dma_data;
        struct snd_dmaengine_dai_dma_data       playback_dma_data;
 };
 
 static void sun4i_codec_start_playback(struct sun4i_codec *scodec)
 {
-       /*
-        * FIXME: according to the BSP, we might need to drive a PA
-        *        GPIO high here on some boards
-        */
-
        /* Flush TX FIFO */
        regmap_update_bits(scodec->regmap, SUN4I_CODEC_DAC_FIFOC,
                           BIT(SUN4I_CODEC_DAC_FIFOC_FIFO_FLUSH),
@@ -125,37 +125,50 @@ static void sun4i_codec_start_playback(struct sun4i_codec *scodec)
 
 static void sun4i_codec_stop_playback(struct sun4i_codec *scodec)
 {
-       /*
-        * FIXME: according to the BSP, we might need to drive a PA
-        *        GPIO low here on some boards
-        */
-
        /* Disable DAC DRQ */
        regmap_update_bits(scodec->regmap, SUN4I_CODEC_DAC_FIFOC,
                           BIT(SUN4I_CODEC_DAC_FIFOC_DAC_DRQ_EN),
                           0);
 }
 
+static void sun4i_codec_start_capture(struct sun4i_codec *scodec)
+{
+       /* Enable ADC DRQ */
+       regmap_update_bits(scodec->regmap, SUN4I_CODEC_ADC_FIFOC,
+                          BIT(SUN4I_CODEC_ADC_FIFOC_ADC_DRQ_EN),
+                          BIT(SUN4I_CODEC_ADC_FIFOC_ADC_DRQ_EN));
+}
+
+static void sun4i_codec_stop_capture(struct sun4i_codec *scodec)
+{
+       /* Disable ADC DRQ */
+       regmap_update_bits(scodec->regmap, SUN4I_CODEC_ADC_FIFOC,
+                          BIT(SUN4I_CODEC_ADC_FIFOC_ADC_DRQ_EN), 0);
+}
+
 static int sun4i_codec_trigger(struct snd_pcm_substream *substream, int cmd,
                               struct snd_soc_dai *dai)
 {
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
        struct sun4i_codec *scodec = snd_soc_card_get_drvdata(rtd->card);
 
-       if (substream->stream != SNDRV_PCM_STREAM_PLAYBACK)
-               return -ENOTSUPP;
-
        switch (cmd) {
        case SNDRV_PCM_TRIGGER_START:
        case SNDRV_PCM_TRIGGER_RESUME:
        case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
-               sun4i_codec_start_playback(scodec);
+               if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+                       sun4i_codec_start_playback(scodec);
+               else
+                       sun4i_codec_start_capture(scodec);
                break;
 
        case SNDRV_PCM_TRIGGER_STOP:
        case SNDRV_PCM_TRIGGER_SUSPEND:
        case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
-               sun4i_codec_stop_playback(scodec);
+               if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+                       sun4i_codec_stop_playback(scodec);
+               else
+                       sun4i_codec_stop_capture(scodec);
                break;
 
        default:
@@ -165,15 +178,54 @@ static int sun4i_codec_trigger(struct snd_pcm_substream *substream, int cmd,
        return 0;
 }
 
-static int sun4i_codec_prepare(struct snd_pcm_substream *substream,
-                              struct snd_soc_dai *dai)
+static int sun4i_codec_prepare_capture(struct snd_pcm_substream *substream,
+                                      struct snd_soc_dai *dai)
 {
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
        struct sun4i_codec *scodec = snd_soc_card_get_drvdata(rtd->card);
-       u32 val;
 
-       if (substream->stream != SNDRV_PCM_STREAM_PLAYBACK)
-               return -ENOTSUPP;
+
+       /* Flush RX FIFO */
+       regmap_update_bits(scodec->regmap, SUN4I_CODEC_ADC_FIFOC,
+                          BIT(SUN4I_CODEC_ADC_FIFOC_FIFO_FLUSH),
+                          BIT(SUN4I_CODEC_ADC_FIFOC_FIFO_FLUSH));
+
+
+       /* Set RX FIFO trigger level */
+       regmap_update_bits(scodec->regmap, SUN4I_CODEC_ADC_FIFOC,
+                          0xf << SUN4I_CODEC_ADC_FIFOC_RX_TRIG_LEVEL,
+                          0x7 << SUN4I_CODEC_ADC_FIFOC_RX_TRIG_LEVEL);
+
+       /*
+        * FIXME: Undocumented in the datasheet, but
+        *        Allwinner's code mentions that it is related
+        *        related to microphone gain
+        */
+       regmap_update_bits(scodec->regmap, SUN4I_CODEC_ADC_ACTL,
+                          0x3 << 25,
+                          0x1 << 25);
+
+       if (of_device_is_compatible(scodec->dev->of_node,
+                                   "allwinner,sun7i-a20-codec"))
+               /* FIXME: Undocumented bits */
+               regmap_update_bits(scodec->regmap, SUN4I_CODEC_DAC_TUNE,
+                                  0x3 << 8,
+                                  0x1 << 8);
+
+       /* Fill most significant bits with valid data MSB */
+       regmap_update_bits(scodec->regmap, SUN4I_CODEC_ADC_FIFOC,
+                          BIT(SUN4I_CODEC_ADC_FIFOC_RX_FIFO_MODE),
+                          BIT(SUN4I_CODEC_ADC_FIFOC_RX_FIFO_MODE));
+
+       return 0;
+}
+
+static int sun4i_codec_prepare_playback(struct snd_pcm_substream *substream,
+                                       struct snd_soc_dai *dai)
+{
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+       struct sun4i_codec *scodec = snd_soc_card_get_drvdata(rtd->card);
+       u32 val;
 
        /* Flush the TX FIFO */
        regmap_update_bits(scodec->regmap, SUN4I_CODEC_DAC_FIFOC,
@@ -202,6 +254,15 @@ static int sun4i_codec_prepare(struct snd_pcm_substream *substream,
                           0);
 
        return 0;
+};
+
+static int sun4i_codec_prepare(struct snd_pcm_substream *substream,
+                              struct snd_soc_dai *dai)
+{
+       if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+               return sun4i_codec_prepare_playback(substream, dai);
+
+       return sun4i_codec_prepare_capture(substream, dai);
 }
 
 static unsigned long sun4i_codec_get_mod_freq(struct snd_pcm_hw_params *params)
@@ -276,30 +337,32 @@ static int sun4i_codec_get_hw_rate(struct snd_pcm_hw_params *params)
        }
 }
 
-static int sun4i_codec_hw_params(struct snd_pcm_substream *substream,
-                                struct snd_pcm_hw_params *params,
-                                struct snd_soc_dai *dai)
+static int sun4i_codec_hw_params_capture(struct sun4i_codec *scodec,
+                                        struct snd_pcm_hw_params *params,
+                                        unsigned int hwrate)
 {
-       struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct sun4i_codec *scodec = snd_soc_card_get_drvdata(rtd->card);
-       unsigned long clk_freq;
-       int ret, hwrate;
-       u32 val;
-
-       if (substream->stream != SNDRV_PCM_STREAM_PLAYBACK)
-               return -ENOTSUPP;
+       /* Set ADC sample rate */
+       regmap_update_bits(scodec->regmap, SUN4I_CODEC_ADC_FIFOC,
+                          7 << SUN4I_CODEC_ADC_FIFOC_ADC_FS,
+                          hwrate << SUN4I_CODEC_ADC_FIFOC_ADC_FS);
 
-       clk_freq = sun4i_codec_get_mod_freq(params);
-       if (!clk_freq)
-               return -EINVAL;
+       /* Set the number of channels we want to use */
+       if (params_channels(params) == 1)
+               regmap_update_bits(scodec->regmap, SUN4I_CODEC_ADC_FIFOC,
+                                  BIT(SUN4I_CODEC_ADC_FIFOC_MONO_EN),
+                                  BIT(SUN4I_CODEC_ADC_FIFOC_MONO_EN));
+       else
+               regmap_update_bits(scodec->regmap, SUN4I_CODEC_ADC_FIFOC,
+                                  BIT(SUN4I_CODEC_ADC_FIFOC_MONO_EN), 0);
 
-       ret = clk_set_rate(scodec->clk_module, clk_freq);
-       if (ret)
-               return ret;
+       return 0;
+}
 
-       hwrate = sun4i_codec_get_hw_rate(params);
-       if (hwrate < 0)
-               return hwrate;
+static int sun4i_codec_hw_params_playback(struct sun4i_codec *scodec,
+                                         struct snd_pcm_hw_params *params,
+                                         unsigned int hwrate)
+{
+       u32 val;
 
        /* Set DAC sample rate */
        regmap_update_bits(scodec->regmap, SUN4I_CODEC_DAC_FIFOC,
@@ -344,6 +407,35 @@ static int sun4i_codec_hw_params(struct snd_pcm_substream *substream,
        return 0;
 }
 
+static int sun4i_codec_hw_params(struct snd_pcm_substream *substream,
+                                struct snd_pcm_hw_params *params,
+                                struct snd_soc_dai *dai)
+{
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+       struct sun4i_codec *scodec = snd_soc_card_get_drvdata(rtd->card);
+       unsigned long clk_freq;
+       int ret, hwrate;
+
+       clk_freq = sun4i_codec_get_mod_freq(params);
+       if (!clk_freq)
+               return -EINVAL;
+
+       ret = clk_set_rate(scodec->clk_module, clk_freq);
+       if (ret)
+               return ret;
+
+       hwrate = sun4i_codec_get_hw_rate(params);
+       if (hwrate < 0)
+               return hwrate;
+
+       if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+               return sun4i_codec_hw_params_playback(scodec, params,
+                                                     hwrate);
+
+       return sun4i_codec_hw_params_capture(scodec, params,
+                                            hwrate);
+}
+
 static int sun4i_codec_startup(struct snd_pcm_substream *substream,
                               struct snd_soc_dai *dai)
 {
@@ -394,6 +486,20 @@ static struct snd_soc_dai_driver sun4i_codec_dai = {
                                  SNDRV_PCM_FMTBIT_S32_LE,
                .sig_bits       = 24,
        },
+       .capture = {
+               .stream_name    = "Codec Capture",
+               .channels_min   = 1,
+               .channels_max   = 2,
+               .rate_min       = 8000,
+               .rate_max       = 192000,
+               .rates          = SNDRV_PCM_RATE_8000_48000 |
+                                 SNDRV_PCM_RATE_96000 |
+                                 SNDRV_PCM_RATE_192000 |
+                                 SNDRV_PCM_RATE_KNOT,
+               .formats        = SNDRV_PCM_FMTBIT_S16_LE |
+                                 SNDRV_PCM_FMTBIT_S32_LE,
+               .sig_bits       = 24,
+       },
 };
 
 /*** Codec ***/
@@ -404,7 +510,7 @@ static const struct snd_kcontrol_new sun4i_codec_pa_mute =
 static DECLARE_TLV_DB_SCALE(sun4i_codec_pa_volume_scale, -6300, 100, 1);
 
 static const struct snd_kcontrol_new sun4i_codec_widgets[] = {
-       SOC_SINGLE_TLV("PA Volume", SUN4I_CODEC_DAC_ACTL,
+       SOC_SINGLE_TLV("Power Amplifier Volume", SUN4I_CODEC_DAC_ACTL,
                       SUN4I_CODEC_DAC_ACTL_PA_VOL, 0x3F, 0,
                       sun4i_codec_pa_volume_scale),
 };
@@ -428,12 +534,23 @@ static const struct snd_kcontrol_new sun4i_codec_pa_mixer_controls[] = {
                        SUN4I_CODEC_DAC_ACTL_MIXPAS, 1, 0),
 };
 
-static const struct snd_soc_dapm_widget sun4i_codec_dapm_widgets[] = {
+static const struct snd_soc_dapm_widget sun4i_codec_codec_dapm_widgets[] = {
+       /* Digital parts of the ADCs */
+       SND_SOC_DAPM_SUPPLY("ADC", SUN4I_CODEC_ADC_FIFOC,
+                           SUN4I_CODEC_ADC_FIFOC_EN_AD, 0,
+                           NULL, 0),
+
        /* Digital parts of the DACs */
        SND_SOC_DAPM_SUPPLY("DAC", SUN4I_CODEC_DAC_DPC,
                            SUN4I_CODEC_DAC_DPC_EN_DA, 0,
                            NULL, 0),
 
+       /* Analog parts of the ADCs */
+       SND_SOC_DAPM_ADC("Left ADC", "Codec Capture", SUN4I_CODEC_ADC_ACTL,
+                        SUN4I_CODEC_ADC_ACTL_ADC_L_EN, 0),
+       SND_SOC_DAPM_ADC("Right ADC", "Codec Capture", SUN4I_CODEC_ADC_ACTL,
+                        SUN4I_CODEC_ADC_ACTL_ADC_R_EN, 0),
+
        /* Analog parts of the DACs */
        SND_SOC_DAPM_DAC("Left DAC", "Codec Playback", SUN4I_CODEC_DAC_ACTL,
                         SUN4I_CODEC_DAC_ACTL_DACAENL, 0),
@@ -452,23 +569,35 @@ static const struct snd_soc_dapm_widget sun4i_codec_dapm_widgets[] = {
        SND_SOC_DAPM_SUPPLY("Mixer Enable", SUN4I_CODEC_DAC_ACTL,
                            SUN4I_CODEC_DAC_ACTL_MIXEN, 0, NULL, 0),
 
-       /* Pre-Amplifier */
-       SND_SOC_DAPM_MIXER("Pre-Amplifier", SUN4I_CODEC_ADC_ACTL,
+       /* VMIC */
+       SND_SOC_DAPM_SUPPLY("VMIC", SUN4I_CODEC_ADC_ACTL,
+                           SUN4I_CODEC_ADC_ACTL_VMICEN, 0, NULL, 0),
+
+       /* Mic Pre-Amplifiers */
+       SND_SOC_DAPM_PGA("MIC1 Pre-Amplifier", SUN4I_CODEC_ADC_ACTL,
+                        SUN4I_CODEC_ADC_ACTL_PREG1EN, 0, NULL, 0),
+
+       /* Power Amplifier */
+       SND_SOC_DAPM_MIXER("Power Amplifier", SUN4I_CODEC_ADC_ACTL,
                           SUN4I_CODEC_ADC_ACTL_PA_EN, 0,
                           sun4i_codec_pa_mixer_controls,
                           ARRAY_SIZE(sun4i_codec_pa_mixer_controls)),
-       SND_SOC_DAPM_SWITCH("Pre-Amplifier Mute", SND_SOC_NOPM, 0, 0,
+       SND_SOC_DAPM_SWITCH("Power Amplifier Mute", SND_SOC_NOPM, 0, 0,
                            &sun4i_codec_pa_mute),
 
+       SND_SOC_DAPM_INPUT("Mic1"),
+
        SND_SOC_DAPM_OUTPUT("HP Right"),
        SND_SOC_DAPM_OUTPUT("HP Left"),
 };
 
-static const struct snd_soc_dapm_route sun4i_codec_dapm_routes[] = {
-       /* Left DAC Routes */
+static const struct snd_soc_dapm_route sun4i_codec_codec_dapm_routes[] = {
+       /* Left ADC / DAC Routes */
+       { "Left ADC", NULL, "ADC" },
        { "Left DAC", NULL, "DAC" },
 
-       /* Right DAC Routes */
+       /* Right ADC / DAC Routes */
+       { "Right ADC", NULL, "ADC" },
        { "Right DAC", NULL, "DAC" },
 
        /* Right Mixer Routes */
@@ -480,25 +609,31 @@ static const struct snd_soc_dapm_route sun4i_codec_dapm_routes[] = {
        { "Left Mixer", NULL, "Mixer Enable" },
        { "Left Mixer", "Left DAC Playback Switch", "Left DAC" },
 
-       /* Pre-Amplifier Mixer Routes */
-       { "Pre-Amplifier", "Mixer Playback Switch", "Left Mixer" },
-       { "Pre-Amplifier", "Mixer Playback Switch", "Right Mixer" },
-       { "Pre-Amplifier", "DAC Playback Switch", "Left DAC" },
-       { "Pre-Amplifier", "DAC Playback Switch", "Right DAC" },
-
-       /* PA -> HP path */
-       { "Pre-Amplifier Mute", "Switch", "Pre-Amplifier" },
-       { "HP Right", NULL, "Pre-Amplifier Mute" },
-       { "HP Left", NULL, "Pre-Amplifier Mute" },
+       /* Power Amplifier Routes */
+       { "Power Amplifier", "Mixer Playback Switch", "Left Mixer" },
+       { "Power Amplifier", "Mixer Playback Switch", "Right Mixer" },
+       { "Power Amplifier", "DAC Playback Switch", "Left DAC" },
+       { "Power Amplifier", "DAC Playback Switch", "Right DAC" },
+
+       /* Headphone Output Routes */
+       { "Power Amplifier Mute", "Switch", "Power Amplifier" },
+       { "HP Right", NULL, "Power Amplifier Mute" },
+       { "HP Left", NULL, "Power Amplifier Mute" },
+
+       /* Mic1 Routes */
+       { "Left ADC", NULL, "MIC1 Pre-Amplifier" },
+       { "Right ADC", NULL, "MIC1 Pre-Amplifier" },
+       { "MIC1 Pre-Amplifier", NULL, "Mic1"},
+       { "Mic1", NULL, "VMIC" },
 };
 
 static struct snd_soc_codec_driver sun4i_codec_codec = {
        .controls               = sun4i_codec_widgets,
        .num_controls           = ARRAY_SIZE(sun4i_codec_widgets),
-       .dapm_widgets           = sun4i_codec_dapm_widgets,
-       .num_dapm_widgets       = ARRAY_SIZE(sun4i_codec_dapm_widgets),
-       .dapm_routes            = sun4i_codec_dapm_routes,
-       .num_dapm_routes        = ARRAY_SIZE(sun4i_codec_dapm_routes),
+       .dapm_widgets           = sun4i_codec_codec_dapm_widgets,
+       .num_dapm_widgets       = ARRAY_SIZE(sun4i_codec_codec_dapm_widgets),
+       .dapm_routes            = sun4i_codec_codec_dapm_routes,
+       .num_dapm_routes        = ARRAY_SIZE(sun4i_codec_codec_dapm_routes),
 };
 
 static const struct snd_soc_component_driver sun4i_codec_component = {
@@ -515,7 +650,7 @@ static int sun4i_codec_dai_probe(struct snd_soc_dai *dai)
        struct sun4i_codec *scodec = snd_soc_card_get_drvdata(card);
 
        snd_soc_dai_init_dma_data(dai, &scodec->playback_dma_data,
-                                 NULL);
+                                 &scodec->capture_dma_data);
 
        return 0;
 }
@@ -531,6 +666,14 @@ static struct snd_soc_dai_driver dummy_cpu_dai = {
                .formats        = SUN4I_CODEC_FORMATS,
                .sig_bits       = 24,
        },
+       .capture = {
+               .stream_name    = "Capture",
+               .channels_min   = 1,
+               .channels_max   = 2,
+               .rates          = SUN4I_CODEC_RATES,
+               .formats        = SUN4I_CODEC_FORMATS,
+               .sig_bits       = 24,
+        },
 };
 
 static const struct regmap_config sun4i_codec_regmap_config = {
@@ -568,6 +711,27 @@ static struct snd_soc_dai_link *sun4i_codec_create_link(struct device *dev,
        return link;
 };
 
+static int sun4i_codec_spk_event(struct snd_soc_dapm_widget *w,
+                                struct snd_kcontrol *k, int event)
+{
+       struct sun4i_codec *scodec = snd_soc_card_get_drvdata(w->dapm->card);
+
+       if (scodec->gpio_pa)
+               gpiod_set_value_cansleep(scodec->gpio_pa,
+                                        !!SND_SOC_DAPM_EVENT_ON(event));
+
+       return 0;
+}
+
+static const struct snd_soc_dapm_widget sun4i_codec_card_dapm_widgets[] = {
+       SND_SOC_DAPM_SPK("Speaker", sun4i_codec_spk_event),
+};
+
+static const struct snd_soc_dapm_route sun4i_codec_card_dapm_routes[] = {
+       { "Speaker", NULL, "HP Right" },
+       { "Speaker", NULL, "HP Left" },
+};
+
 static struct snd_soc_card *sun4i_codec_create_card(struct device *dev)
 {
        struct snd_soc_card *card;
@@ -582,6 +746,10 @@ static struct snd_soc_card *sun4i_codec_create_card(struct device *dev)
 
        card->dev               = dev;
        card->name              = "sun4i-codec";
+       card->dapm_widgets      = sun4i_codec_card_dapm_widgets;
+       card->num_dapm_widgets  = ARRAY_SIZE(sun4i_codec_card_dapm_widgets);
+       card->dapm_routes       = sun4i_codec_card_dapm_routes;
+       card->num_dapm_routes   = ARRAY_SIZE(sun4i_codec_card_dapm_routes);
 
        return card;
 };
@@ -633,11 +801,25 @@ static int sun4i_codec_probe(struct platform_device *pdev)
                return -EINVAL;
        }
 
+       scodec->gpio_pa = devm_gpiod_get_optional(&pdev->dev, "allwinner,pa",
+                                                 GPIOD_OUT_LOW);
+       if (IS_ERR(scodec->gpio_pa)) {
+               ret = PTR_ERR(scodec->gpio_pa);
+               if (ret != -EPROBE_DEFER)
+                       dev_err(&pdev->dev, "Failed to get pa gpio: %d\n", ret);
+               return ret;
+       }
+
        /* DMA configuration for TX FIFO */
        scodec->playback_dma_data.addr = res->start + SUN4I_CODEC_DAC_TXDATA;
        scodec->playback_dma_data.maxburst = 4;
        scodec->playback_dma_data.addr_width = DMA_SLAVE_BUSWIDTH_2_BYTES;
 
+       /* DMA configuration for RX FIFO */
+       scodec->capture_dma_data.addr = res->start + SUN4I_CODEC_ADC_RXDATA;
+       scodec->capture_dma_data.maxburst = 4;
+       scodec->capture_dma_data.addr_width = DMA_SLAVE_BUSWIDTH_2_BYTES;
+
        ret = snd_soc_register_codec(&pdev->dev, &sun4i_codec_codec,
                                     &sun4i_codec_dai, 1);
        if (ret) {
index ba272e21a6fa3112e09f407e1b5747e985cca747..deb597f7c302b19a1a241784cb1b8f209a968c38 100644 (file)
@@ -101,12 +101,16 @@ static const struct snd_kcontrol_new tegra_alc5632_controls[] = {
 
 static int tegra_alc5632_asoc_init(struct snd_soc_pcm_runtime *rtd)
 {
+       int ret;
        struct tegra_alc5632 *machine = snd_soc_card_get_drvdata(rtd->card);
 
-       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));
+       ret = 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 (ret)
+               return ret;
 
        if (gpio_is_valid(machine->gpio_hp_det)) {
                tegra_alc5632_hp_jack_gpio.gpio = machine->gpio_hp_det;
index 21604009bc1a2df338e6696c83f78a3473174254..e485278e027a251189a16f77c3f24a2428bb2b7a 100644 (file)
@@ -199,7 +199,8 @@ static int tegra_wm8903_init(struct snd_soc_pcm_runtime *rtd)
 
 static int tegra_wm8903_remove(struct snd_soc_card *card)
 {
-       struct snd_soc_pcm_runtime *rtd = &(card->rtd[0]);
+       struct snd_soc_pcm_runtime *rtd =
+               snd_soc_get_pcm_runtime(card, card->dai_link[0].name);
        struct snd_soc_dai *codec_dai = rtd->codec_dai;
        struct snd_soc_codec *codec = codec_dai->codec;
        struct tegra_wm8903 *machine = snd_soc_card_get_drvdata(card);
index 7661616f36361d142144842bd6595994829edec4..5b4c58c3e2c5f6115d55ad194cd06f971e3fdb70 100644 (file)
@@ -174,6 +174,8 @@ struct snd_usb_midi_in_endpoint {
                u8 running_status_length;
        } ports[0x10];
        u8 seen_f5;
+       bool in_sysex;
+       u8 last_cin;
        u8 error_resubmit;
        int current_port;
 };
@@ -467,6 +469,39 @@ static void snd_usbmidi_maudio_broken_running_status_input(
                }
 }
 
+/*
+ * QinHeng CH345 is buggy: every second packet inside a SysEx has not CIN 4
+ * but the previously seen CIN, but still with three data bytes.
+ */
+static void ch345_broken_sysex_input(struct snd_usb_midi_in_endpoint *ep,
+                                    uint8_t *buffer, int buffer_length)
+{
+       unsigned int i, cin, length;
+
+       for (i = 0; i + 3 < buffer_length; i += 4) {
+               if (buffer[i] == 0 && i > 0)
+                       break;
+               cin = buffer[i] & 0x0f;
+               if (ep->in_sysex &&
+                   cin == ep->last_cin &&
+                   (buffer[i + 1 + (cin == 0x6)] & 0x80) == 0)
+                       cin = 0x4;
+#if 0
+               if (buffer[i + 1] == 0x90) {
+                       /*
+                        * Either a corrupted running status or a real note-on
+                        * message; impossible to detect reliably.
+                        */
+               }
+#endif
+               length = snd_usbmidi_cin_length[cin];
+               snd_usbmidi_input_data(ep, 0, &buffer[i + 1], length);
+               ep->in_sysex = cin == 0x4;
+               if (!ep->in_sysex)
+                       ep->last_cin = cin;
+       }
+}
+
 /*
  * CME protocol: like the standard protocol, but SysEx commands are sent as a
  * single USB packet preceded by a 0x0F byte.
@@ -660,6 +695,12 @@ static struct usb_protocol_ops snd_usbmidi_cme_ops = {
        .output_packet = snd_usbmidi_output_standard_packet,
 };
 
+static struct usb_protocol_ops snd_usbmidi_ch345_broken_sysex_ops = {
+       .input = ch345_broken_sysex_input,
+       .output = snd_usbmidi_standard_output,
+       .output_packet = snd_usbmidi_output_standard_packet,
+};
+
 /*
  * AKAI MPD16 protocol:
  *
@@ -1341,6 +1382,7 @@ static int snd_usbmidi_out_endpoint_create(struct snd_usb_midi *umidi,
                 * Various chips declare a packet size larger than 4 bytes, but
                 * do not actually work with larger packets:
                 */
+       case USB_ID(0x0a67, 0x5011): /* Medeli DD305 */
        case USB_ID(0x0a92, 0x1020): /* ESI M4U */
        case USB_ID(0x1430, 0x474b): /* RedOctane GH MIDI INTERFACE */
        case USB_ID(0x15ca, 0x0101): /* Textech USB Midi Cable */
@@ -2376,6 +2418,10 @@ int snd_usbmidi_create(struct snd_card *card,
                if (err < 0)
                        break;
 
+               err = snd_usbmidi_detect_per_port_endpoints(umidi, endpoints);
+               break;
+       case QUIRK_MIDI_CH345:
+               umidi->usb_protocol_ops = &snd_usbmidi_ch345_broken_sysex_ops;
                err = snd_usbmidi_detect_per_port_endpoints(umidi, endpoints);
                break;
        default:
index f494dced3c11e3a662b93d95df9ea53ff2767dfc..4f85757009b3e44e2246cc21f4387d0948056da3 100644 (file)
@@ -1354,6 +1354,8 @@ static void build_feature_ctl(struct mixer_build *state, void *raw_desc,
                }
        }
 
+       snd_usb_mixer_fu_apply_quirk(state->mixer, cval, unitid, kctl);
+
        range = (cval->max - cval->min) / cval->res;
        /*
         * Are there devices with volume range more than 255? I use a bit more
index 6a803eff87f71110049d9c39cb07025d2c64d828..ddca6547399b0103b37abbdf73cfa5c9e710a7fd 100644 (file)
@@ -348,13 +348,6 @@ static struct usbmix_name_map bose_companion5_map[] = {
        { 0 }   /* terminator */
 };
 
-/* Dragonfly DAC 1.2, the dB conversion factor is 1 instead of 256 */
-static struct usbmix_dB_map dragonfly_1_2_dB = {0, 5000};
-static struct usbmix_name_map dragonfly_1_2_map[] = {
-       { 7, NULL, .dB = &dragonfly_1_2_dB },
-       { 0 }   /* terminator */
-};
-
 /*
  * Control map entries
  */
@@ -470,11 +463,6 @@ static struct usbmix_ctl_map usbmix_ctl_maps[] = {
                .id = USB_ID(0x05a7, 0x1020),
                .map = bose_companion5_map,
        },
-       {
-               /* Dragonfly DAC 1.2 */
-               .id = USB_ID(0x21b4, 0x0081),
-               .map = dragonfly_1_2_map,
-       },
        { 0 } /* terminator */
 };
 
index fe91184ce83247d8b0360bab09e94c8f7cb720d8..0ce888dceed0ea24db7b677eeb93b05c728ab40a 100644 (file)
@@ -37,6 +37,7 @@
 #include <sound/control.h>
 #include <sound/hwdep.h>
 #include <sound/info.h>
+#include <sound/tlv.h>
 
 #include "usbaudio.h"
 #include "mixer.h"
@@ -1825,3 +1826,39 @@ void snd_usb_mixer_rc_memory_change(struct usb_mixer_interface *mixer,
        }
 }
 
+static void snd_dragonfly_quirk_db_scale(struct usb_mixer_interface *mixer,
+                                        struct snd_kcontrol *kctl)
+{
+       /* Approximation using 10 ranges based on output measurement on hw v1.2.
+        * This seems close to the cubic mapping e.g. alsamixer uses. */
+       static const DECLARE_TLV_DB_RANGE(scale,
+                0,  1, TLV_DB_MINMAX_ITEM(-5300, -4970),
+                2,  5, TLV_DB_MINMAX_ITEM(-4710, -4160),
+                6,  7, TLV_DB_MINMAX_ITEM(-3884, -3710),
+                8, 14, TLV_DB_MINMAX_ITEM(-3443, -2560),
+               15, 16, TLV_DB_MINMAX_ITEM(-2475, -2324),
+               17, 19, TLV_DB_MINMAX_ITEM(-2228, -2031),
+               20, 26, TLV_DB_MINMAX_ITEM(-1910, -1393),
+               27, 31, TLV_DB_MINMAX_ITEM(-1322, -1032),
+               32, 40, TLV_DB_MINMAX_ITEM(-968, -490),
+               41, 50, TLV_DB_MINMAX_ITEM(-441, 0),
+       );
+
+       usb_audio_info(mixer->chip, "applying DragonFly dB scale quirk\n");
+       kctl->tlv.p = scale;
+       kctl->vd[0].access |= SNDRV_CTL_ELEM_ACCESS_TLV_READ;
+       kctl->vd[0].access &= ~SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK;
+}
+
+void snd_usb_mixer_fu_apply_quirk(struct usb_mixer_interface *mixer,
+                                 struct usb_mixer_elem_info *cval, int unitid,
+                                 struct snd_kcontrol *kctl)
+{
+       switch (mixer->chip->usb_id) {
+       case USB_ID(0x21b4, 0x0081): /* AudioQuest DragonFly */
+               if (unitid == 7 && cval->min == 0 && cval->max == 50)
+                       snd_dragonfly_quirk_db_scale(mixer, kctl);
+               break;
+       }
+}
+
index bdbfab093816a59772353635fd38eae79ddb3b38..177c329cd4ddb792e144f4ecd945976e6ab9b1a4 100644 (file)
@@ -9,5 +9,9 @@ void snd_emuusb_set_samplerate(struct snd_usb_audio *chip,
 void snd_usb_mixer_rc_memory_change(struct usb_mixer_interface *mixer,
                                    int unitid);
 
+void snd_usb_mixer_fu_apply_quirk(struct usb_mixer_interface *mixer,
+                                 struct usb_mixer_elem_info *cval, int unitid,
+                                 struct snd_kcontrol *kctl);
+
 #endif /* SND_USB_MIXER_QUIRKS_H */
 
index 1a1e2e4df35e5809e7f7d81b405ca6dddf2f4311..c60a776e815d72f14b9b6345f2e8a0266f8ec1b6 100644 (file)
@@ -2829,6 +2829,17 @@ YAMAHA_DEVICE(0x7010, "UB99"),
        .idProduct = 0x1020,
 },
 
+/* QinHeng devices */
+{
+       USB_DEVICE(0x1a86, 0x752d),
+       .driver_info = (unsigned long) &(const struct snd_usb_audio_quirk) {
+               .vendor_name = "QinHeng",
+               .product_name = "CH345",
+               .ifnum = 1,
+               .type = QUIRK_MIDI_CH345
+       }
+},
+
 /* KeithMcMillen Stringport */
 {
        USB_DEVICE(0x1f38, 0x0001),
index 5ca80e7d30cd25bcc67cdf88509f46d39eec42e6..b6c0c8e3b450c5f0dd41ea308f61efe15b3446b8 100644 (file)
@@ -538,6 +538,7 @@ int snd_usb_create_quirk(struct snd_usb_audio *chip,
                [QUIRK_MIDI_CME] = create_any_midi_quirk,
                [QUIRK_MIDI_AKAI] = create_any_midi_quirk,
                [QUIRK_MIDI_FTDI] = create_any_midi_quirk,
+               [QUIRK_MIDI_CH345] = create_any_midi_quirk,
                [QUIRK_AUDIO_STANDARD_INTERFACE] = create_standard_audio_quirk,
                [QUIRK_AUDIO_FIXED_ENDPOINT] = create_fixed_stream_quirk,
                [QUIRK_AUDIO_EDIROL_UAXX] = create_uaxx_quirk,
@@ -1124,6 +1125,7 @@ bool snd_usb_get_sample_rate_quirk(struct snd_usb_audio *chip)
        case USB_ID(0x045E, 0x0779): /* MS Lifecam HD-3000 */
        case USB_ID(0x04D8, 0xFEEA): /* Benchmark DAC1 Pre */
        case USB_ID(0x074D, 0x3553): /* Outlaw RR2150 (Micronas UAC3553B) */
+       case USB_ID(0x21B4, 0x0081): /* AudioQuest DragonFly */
                return true;
        }
        return false;
index 15a12715bd05154bd9c0b4bbe7084f3df15022b2..b665d85555cb3aad0c9a621232f28d8e1f75344a 100644 (file)
@@ -95,6 +95,7 @@ enum quirk_type {
        QUIRK_MIDI_AKAI,
        QUIRK_MIDI_US122L,
        QUIRK_MIDI_FTDI,
+       QUIRK_MIDI_CH345,
        QUIRK_AUDIO_STANDARD_INTERFACE,
        QUIRK_AUDIO_FIXED_ENDPOINT,
        QUIRK_AUDIO_EDIROL_UAXX,
index d6f307dfb1a3c090dc94472f9761c377616ebb92..7dc820a8c1f11b0973605aab313e2ecaa75ca1a6 100644 (file)
@@ -32,6 +32,10 @@ help:
        @echo '  from the kernel command line to build and install one of'
        @echo '  the tools above'
        @echo ''
+       @echo '  $$ make tools/all'
+       @echo ''
+       @echo '  builds all tools.'
+       @echo ''
        @echo '  $$ make tools/install'
        @echo ''
        @echo '  installs all tools.'
@@ -77,6 +81,11 @@ tmon: FORCE
 freefall: FORCE
        $(call descend,laptop/$@)
 
+all: acpi cgroup cpupower hv firewire lguest \
+               perf selftests turbostat usb \
+               virtio vm net x86_energy_perf_policy \
+               tmon freefall
+
 acpi_install:
        $(call descend,power/$(@:_install=),install)
 
@@ -101,7 +110,7 @@ freefall_install:
 install: acpi_install cgroup_install cpupower_install hv_install firewire_install lguest_install \
                perf_install selftests_install turbostat_install usb_install \
                virtio_install vm_install net_install x86_energy_perf_policy_install \
-               tmon freefall_install
+               tmon_install freefall_install
 
 acpi_clean:
        $(call descend,power/acpi,clean)
index ee577ea03ba50f05a4b14379ddcd17a3f73593c0..ddf8880106524c1b2882122b3e5ed76f3c5cc3f6 100644 (file)
@@ -4,6 +4,9 @@ CC = gcc
 LEX = flex
 YACC = bison
 
+CFLAGS += -Wall -O2
+CFLAGS += -D__EXPORTED_HEADERS__ -I../../include/uapi -I../../include
+
 %.yacc.c: %.y
        $(YACC) -o $@ -d $<
 
@@ -12,15 +15,13 @@ YACC = bison
 
 all : bpf_jit_disasm bpf_dbg bpf_asm
 
-bpf_jit_disasm : CFLAGS = -Wall -O2 -DPACKAGE='bpf_jit_disasm'
+bpf_jit_disasm : CFLAGS += -DPACKAGE='bpf_jit_disasm'
 bpf_jit_disasm : LDLIBS = -lopcodes -lbfd -ldl
 bpf_jit_disasm : bpf_jit_disasm.o
 
-bpf_dbg : CFLAGS = -Wall -O2
 bpf_dbg : LDLIBS = -lreadline
 bpf_dbg : bpf_dbg.o
 
-bpf_asm : CFLAGS = -Wall -O2 -I.
 bpf_asm : LDLIBS =
 bpf_asm : bpf_asm.o bpf_exp.yacc.o bpf_exp.lex.o
 bpf_exp.lex.o : bpf_exp.yacc.c
index 0a945d2e8ca5b1bd319fa18537e7a4c57e3b7291..99d127fe9c35e500ca74ea871fd4373fcea15d68 100644 (file)
@@ -675,6 +675,7 @@ int cmd_inject(int argc, const char **argv, const char *prefix __maybe_unused)
                        .fork           = perf_event__repipe,
                        .exit           = perf_event__repipe,
                        .lost           = perf_event__repipe,
+                       .lost_samples   = perf_event__repipe,
                        .aux            = perf_event__repipe,
                        .itrace_start   = perf_event__repipe,
                        .context_switch = perf_event__repipe,
index 2853ad2bd43541b1291292f94a5c6f8a6804dd03..f256fac1e722527a18e585ed51a591c15c574207 100644 (file)
@@ -44,7 +44,7 @@
 struct report {
        struct perf_tool        tool;
        struct perf_session     *session;
-       bool                    force, use_tui, use_gtk, use_stdio;
+       bool                    use_tui, use_gtk, use_stdio;
        bool                    hide_unresolved;
        bool                    dont_use_callchains;
        bool                    show_full_info;
@@ -678,7 +678,7 @@ int cmd_report(int argc, const char **argv, const char *prefix __maybe_unused)
                   "file", "vmlinux pathname"),
        OPT_STRING(0, "kallsyms", &symbol_conf.kallsyms_name,
                   "file", "kallsyms pathname"),
-       OPT_BOOLEAN('f', "force", &report.force, "don't complain, do it"),
+       OPT_BOOLEAN('f', "force", &symbol_conf.force, "don't complain, do it"),
        OPT_BOOLEAN('m', "modules", &symbol_conf.use_modules,
                    "load module symbols - WARNING: use only with -k and LIVE kernel"),
        OPT_BOOLEAN('n', "show-nr-samples", &symbol_conf.show_nr_samples,
@@ -832,7 +832,7 @@ int cmd_report(int argc, const char **argv, const char *prefix __maybe_unused)
        }
 
        file.path  = input_name;
-       file.force = report.force;
+       file.force = symbol_conf.force;
 
 repeat:
        session = perf_session__new(&file, false, &report.tool);
index e5afb893604044f189da5a0f50962f990362e0da..fa9eb92c9e24a477e45623c1017a2791fc68dd07 100644 (file)
@@ -1430,7 +1430,6 @@ close_file_and_continue:
 
 struct popup_action {
        struct thread           *thread;
-       struct dso              *dso;
        struct map_symbol       ms;
        int                     socket;
 
@@ -1565,7 +1564,6 @@ add_dso_opt(struct hist_browser *browser, struct popup_action *act,
                return 0;
 
        act->ms.map = map;
-       act->dso = map->dso;
        act->fn = do_zoom_dso;
        return 1;
 }
@@ -1827,7 +1825,6 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events,
 
        while (1) {
                struct thread *thread = NULL;
-               struct dso *dso = NULL;
                struct map *map = NULL;
                int choice = 0;
                int socked_id = -1;
@@ -1839,8 +1836,6 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events,
                if (browser->he_selection != NULL) {
                        thread = hist_browser__selected_thread(browser);
                        map = browser->selection->map;
-                       if (map)
-                               dso = map->dso;
                        socked_id = browser->he_selection->socket;
                }
                switch (key) {
@@ -1874,7 +1869,7 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events,
                        hist_browser__dump(browser);
                        continue;
                case 'd':
-                       actions->dso = dso;
+                       actions->ms.map = map;
                        do_zoom_dso(browser, actions);
                        continue;
                case 'V':
index d909459fb54cb2e24ec8da304935fed8424c2026..217b5a60e2ab0e000fbd4ff75445665d08833ba6 100644 (file)
@@ -76,6 +76,7 @@ struct perf_tool build_id__mark_dso_hit_ops = {
        .exit   = perf_event__exit_del_thread,
        .attr            = perf_event__process_attr,
        .build_id        = perf_event__process_build_id,
+       .ordered_events  = true,
 };
 
 int build_id__sprintf(const u8 *build_id, int len, char *bf)
index 7c0c08386a1d9d6fb5e8cba6c838e5c3c1949bd7..425df5c86c9c9acc8a1cb9dd87540f677e885c5e 100644 (file)
@@ -933,6 +933,7 @@ static struct dso *__dso__findlink_by_longname(struct rb_root *root,
                /* Add new node and rebalance tree */
                rb_link_node(&dso->rb_node, parent, p);
                rb_insert_color(&dso->rb_node, root);
+               dso->root = root;
        }
        return NULL;
 }
@@ -945,15 +946,30 @@ static inline struct dso *__dso__find_by_longname(struct rb_root *root,
 
 void dso__set_long_name(struct dso *dso, const char *name, bool name_allocated)
 {
+       struct rb_root *root = dso->root;
+
        if (name == NULL)
                return;
 
        if (dso->long_name_allocated)
                free((char *)dso->long_name);
 
+       if (root) {
+               rb_erase(&dso->rb_node, root);
+               /*
+                * __dso__findlink_by_longname() isn't guaranteed to add it
+                * back, so a clean removal is required here.
+                */
+               RB_CLEAR_NODE(&dso->rb_node);
+               dso->root = NULL;
+       }
+
        dso->long_name           = name;
        dso->long_name_len       = strlen(name);
        dso->long_name_allocated = name_allocated;
+
+       if (root)
+               __dso__findlink_by_longname(root, dso, NULL);
 }
 
 void dso__set_short_name(struct dso *dso, const char *name, bool name_allocated)
@@ -1046,6 +1062,7 @@ struct dso *dso__new(const char *name)
                dso->kernel = DSO_TYPE_USER;
                dso->needs_swap = DSO_SWAP__UNSET;
                RB_CLEAR_NODE(&dso->rb_node);
+               dso->root = NULL;
                INIT_LIST_HEAD(&dso->node);
                INIT_LIST_HEAD(&dso->data.open_entry);
                pthread_mutex_init(&dso->lock, NULL);
index fc8db9c764acace9c905d5429d999e9c1401d0c4..45ec4d0a50eda2f8c3b3bc700e573ce89ed58fc8 100644 (file)
@@ -135,6 +135,7 @@ struct dso {
        pthread_mutex_t  lock;
        struct list_head node;
        struct rb_node   rb_node;       /* rbtree node sorted by long name */
+       struct rb_root   *root;         /* root of rbtree that rb_node is in */
        struct rb_root   symbols[MAP__NR_TYPES];
        struct rb_root   symbol_names[MAP__NR_TYPES];
        struct {
index 5ef90be2a2497a05731a5fb8d24af33a192f2011..8b303ff20289a8ffb4baff9e29292dd47e9068eb 100644 (file)
@@ -91,6 +91,7 @@ static void dsos__purge(struct dsos *dsos)
 
        list_for_each_entry_safe(pos, n, &dsos->head, node) {
                RB_CLEAR_NODE(&pos->rb_node);
+               pos->root = NULL;
                list_del_init(&pos->node);
                dso__put(pos);
        }
index bd8f03de5e408293a642478a795c6436143edbcf..05012bb178d7a8d75ebf4879438fbc0d6f774926 100644 (file)
@@ -1183,7 +1183,7 @@ static int add_probe_trace_event(Dwarf_Die *sc_die, struct probe_finder *pf)
                        container_of(pf, struct trace_event_finder, pf);
        struct perf_probe_point *pp = &pf->pev->point;
        struct probe_trace_event *tev;
-       struct perf_probe_arg *args;
+       struct perf_probe_arg *args = NULL;
        int ret, i;
 
        /* Check number of tevs */
@@ -1198,19 +1198,23 @@ static int add_probe_trace_event(Dwarf_Die *sc_die, struct probe_finder *pf)
        ret = convert_to_trace_point(&pf->sp_die, tf->mod, pf->addr,
                                     pp->retprobe, pp->function, &tev->point);
        if (ret < 0)
-               return ret;
+               goto end;
 
        tev->point.realname = strdup(dwarf_diename(sc_die));
-       if (!tev->point.realname)
-               return -ENOMEM;
+       if (!tev->point.realname) {
+               ret = -ENOMEM;
+               goto end;
+       }
 
        pr_debug("Probe point found: %s+%lu\n", tev->point.symbol,
                 tev->point.offset);
 
        /* Expand special probe argument if exist */
        args = zalloc(sizeof(struct perf_probe_arg) * MAX_PROBE_ARGS);
-       if (args == NULL)
-               return -ENOMEM;
+       if (args == NULL) {
+               ret = -ENOMEM;
+               goto end;
+       }
 
        ret = expand_probe_args(sc_die, pf, args);
        if (ret < 0)
@@ -1234,6 +1238,10 @@ static int add_probe_trace_event(Dwarf_Die *sc_die, struct probe_finder *pf)
        }
 
 end:
+       if (ret) {
+               clear_probe_trace_event(tev);
+               tf->ntevs--;
+       }
        free(args);
        return ret;
 }
@@ -1246,7 +1254,7 @@ int debuginfo__find_trace_events(struct debuginfo *dbg,
        struct trace_event_finder tf = {
                        .pf = {.pev = pev, .callback = add_probe_trace_event},
                        .max_tevs = probe_conf.max_probes, .mod = dbg->mod};
-       int ret;
+       int ret, i;
 
        /* Allocate result tevs array */
        *tevs = zalloc(sizeof(struct probe_trace_event) * tf.max_tevs);
@@ -1258,6 +1266,8 @@ int debuginfo__find_trace_events(struct debuginfo *dbg,
 
        ret = debuginfo__find_probes(dbg, &tf.pf);
        if (ret < 0) {
+               for (i = 0; i < tf.ntevs; i++)
+                       clear_probe_trace_event(&tf.tevs[i]);
                zfree(tevs);
                return ret;
        }
index b4cc7662677ec858cddf6dd90e906f75c5a14200..cd08027a6d2cdb9640734a5ba8eb20ade14f57f2 100644 (file)
@@ -654,19 +654,24 @@ static int dso__split_kallsyms_for_kcore(struct dso *dso, struct map *map,
        struct map_groups *kmaps = map__kmaps(map);
        struct map *curr_map;
        struct symbol *pos;
-       int count = 0, moved = 0;
+       int count = 0;
+       struct rb_root old_root = dso->symbols[map->type];
        struct rb_root *root = &dso->symbols[map->type];
        struct rb_node *next = rb_first(root);
 
        if (!kmaps)
                return -1;
 
+       *root = RB_ROOT;
+
        while (next) {
                char *module;
 
                pos = rb_entry(next, struct symbol, rb_node);
                next = rb_next(&pos->rb_node);
 
+               rb_erase_init(&pos->rb_node, &old_root);
+
                module = strchr(pos->name, '\t');
                if (module)
                        *module = '\0';
@@ -674,28 +679,21 @@ static int dso__split_kallsyms_for_kcore(struct dso *dso, struct map *map,
                curr_map = map_groups__find(kmaps, map->type, pos->start);
 
                if (!curr_map || (filter && filter(curr_map, pos))) {
-                       rb_erase_init(&pos->rb_node, root);
                        symbol__delete(pos);
-               } else {
-                       pos->start -= curr_map->start - curr_map->pgoff;
-                       if (pos->end)
-                               pos->end -= curr_map->start - curr_map->pgoff;
-                       if (curr_map->dso != map->dso) {
-                               rb_erase_init(&pos->rb_node, root);
-                               symbols__insert(
-                                       &curr_map->dso->symbols[curr_map->type],
-                                       pos);
-                               ++moved;
-                       } else {
-                               ++count;
-                       }
+                       continue;
                }
+
+               pos->start -= curr_map->start - curr_map->pgoff;
+               if (pos->end)
+                       pos->end -= curr_map->start - curr_map->pgoff;
+               symbols__insert(&curr_map->dso->symbols[curr_map->type], pos);
+               ++count;
        }
 
        /* Symbols have been adjusted */
        dso->adjust_symbols = 1;
 
-       return count + moved;
+       return count;
 }
 
 /*
@@ -1438,9 +1436,9 @@ int dso__load(struct dso *dso, struct map *map, symbol_filter_t filter)
                if (lstat(dso->name, &st) < 0)
                        goto out;
 
-               if (st.st_uid && (st.st_uid != geteuid())) {
+               if (!symbol_conf.force && st.st_uid && (st.st_uid != geteuid())) {
                        pr_warning("File %s not owned by current user or root, "
-                               "ignoring it.\n", dso->name);
+                                  "ignoring it (use -f to override).\n", dso->name);
                        goto out;
                }
 
index 40073c60b83d6b7e91fe2e3208f50210cf61f6ce..dcd786e364f2da1385c2f78803fe1770071ce609 100644 (file)
@@ -84,6 +84,7 @@ struct symbol_conf {
        unsigned short  priv_size;
        unsigned short  nr_events;
        bool            try_vmlinux_path,
+                       force,
                        ignore_vmlinux,
                        ignore_vmlinux_buildid,
                        show_kernel_path,
index d8e4b20b6d54cc14c25482279a2a652fe483a2f3..0dac7e05a6ac9e5f1500eca1cebbce2d900ab511 100644 (file)
@@ -1173,9 +1173,9 @@ dump_nhm_platform_info(void)
        unsigned long long msr;
        unsigned int ratio;
 
-       get_msr(base_cpu, MSR_NHM_PLATFORM_INFO, &msr);
+       get_msr(base_cpu, MSR_PLATFORM_INFO, &msr);
 
-       fprintf(stderr, "cpu%d: MSR_NHM_PLATFORM_INFO: 0x%08llx\n", base_cpu, msr);
+       fprintf(stderr, "cpu%d: MSR_PLATFORM_INFO: 0x%08llx\n", base_cpu, msr);
 
        ratio = (msr >> 40) & 0xFF;
        fprintf(stderr, "%d * %.0f = %.0f MHz max efficiency frequency\n",
@@ -1807,7 +1807,7 @@ void check_permissions()
  *
  * MSR_SMI_COUNT                   0x00000034
  *
- * MSR_NHM_PLATFORM_INFO           0x000000ce
+ * MSR_PLATFORM_INFO               0x000000ce
  * MSR_NHM_SNB_PKG_CST_CFG_CTL     0x000000e2
  *
  * MSR_PKG_C3_RESIDENCY            0x000003f8
@@ -1876,7 +1876,7 @@ int probe_nhm_msrs(unsigned int family, unsigned int model)
        get_msr(base_cpu, MSR_NHM_SNB_PKG_CST_CFG_CTL, &msr);
        pkg_cstate_limit = pkg_cstate_limits[msr & 0xF];
 
-       get_msr(base_cpu, MSR_NHM_PLATFORM_INFO, &msr);
+       get_msr(base_cpu, MSR_PLATFORM_INFO, &msr);
        base_ratio = (msr >> 8) & 0xFF;
 
        base_hz = base_ratio * bclk * 1000000;
index 40ab4476c80a2039ab543cc94b09725789b2fe57..51cf8256c6cda1b8c28cf4393496a77b63e0c171 100644 (file)
@@ -420,8 +420,7 @@ static struct nfit_test_resource *nfit_test_lookup(resource_size_t addr)
 
 static int nfit_test0_alloc(struct nfit_test *t)
 {
-       size_t nfit_size = sizeof(struct acpi_table_nfit)
-                       + sizeof(struct acpi_nfit_system_address) * NUM_SPA
+       size_t nfit_size = sizeof(struct acpi_nfit_system_address) * NUM_SPA
                        + sizeof(struct acpi_nfit_memory_map) * NUM_MEM
                        + sizeof(struct acpi_nfit_control_region) * NUM_DCR
                        + sizeof(struct acpi_nfit_data_region) * NUM_BDW
@@ -471,8 +470,7 @@ static int nfit_test0_alloc(struct nfit_test *t)
 
 static int nfit_test1_alloc(struct nfit_test *t)
 {
-       size_t nfit_size = sizeof(struct acpi_table_nfit)
-               + sizeof(struct acpi_nfit_system_address)
+       size_t nfit_size = sizeof(struct acpi_nfit_system_address)
                + sizeof(struct acpi_nfit_memory_map)
                + sizeof(struct acpi_nfit_control_region);
 
@@ -488,39 +486,24 @@ static int nfit_test1_alloc(struct nfit_test *t)
        return 0;
 }
 
-static void nfit_test_init_header(struct acpi_table_nfit *nfit, size_t size)
-{
-       memcpy(nfit->header.signature, ACPI_SIG_NFIT, 4);
-       nfit->header.length = size;
-       nfit->header.revision = 1;
-       memcpy(nfit->header.oem_id, "LIBND", 6);
-       memcpy(nfit->header.oem_table_id, "TEST", 5);
-       nfit->header.oem_revision = 1;
-       memcpy(nfit->header.asl_compiler_id, "TST", 4);
-       nfit->header.asl_compiler_revision = 1;
-}
-
 static void nfit_test0_setup(struct nfit_test *t)
 {
        struct nvdimm_bus_descriptor *nd_desc;
        struct acpi_nfit_desc *acpi_desc;
        struct acpi_nfit_memory_map *memdev;
        void *nfit_buf = t->nfit_buf;
-       size_t size = t->nfit_size;
        struct acpi_nfit_system_address *spa;
        struct acpi_nfit_control_region *dcr;
        struct acpi_nfit_data_region *bdw;
        struct acpi_nfit_flush_address *flush;
        unsigned int offset;
 
-       nfit_test_init_header(nfit_buf, size);
-
        /*
         * spa0 (interleave first half of dimm0 and dimm1, note storage
         * does not actually alias the related block-data-window
         * regions)
         */
-       spa = nfit_buf + sizeof(struct acpi_table_nfit);
+       spa = nfit_buf;
        spa->header.type = ACPI_NFIT_TYPE_SYSTEM_ADDRESS;
        spa->header.length = sizeof(*spa);
        memcpy(spa->range_guid, to_nfit_uuid(NFIT_SPA_PM), 16);
@@ -533,7 +516,7 @@ static void nfit_test0_setup(struct nfit_test *t)
         * does not actually alias the related block-data-window
         * regions)
         */
-       spa = nfit_buf + sizeof(struct acpi_table_nfit) + sizeof(*spa);
+       spa = nfit_buf + sizeof(*spa);
        spa->header.type = ACPI_NFIT_TYPE_SYSTEM_ADDRESS;
        spa->header.length = sizeof(*spa);
        memcpy(spa->range_guid, to_nfit_uuid(NFIT_SPA_PM), 16);
@@ -542,7 +525,7 @@ static void nfit_test0_setup(struct nfit_test *t)
        spa->length = SPA1_SIZE;
 
        /* spa2 (dcr0) dimm0 */
-       spa = nfit_buf + sizeof(struct acpi_table_nfit) + sizeof(*spa) * 2;
+       spa = nfit_buf + sizeof(*spa) * 2;
        spa->header.type = ACPI_NFIT_TYPE_SYSTEM_ADDRESS;
        spa->header.length = sizeof(*spa);
        memcpy(spa->range_guid, to_nfit_uuid(NFIT_SPA_DCR), 16);
@@ -551,7 +534,7 @@ static void nfit_test0_setup(struct nfit_test *t)
        spa->length = DCR_SIZE;
 
        /* spa3 (dcr1) dimm1 */
-       spa = nfit_buf + sizeof(struct acpi_table_nfit) + sizeof(*spa) * 3;
+       spa = nfit_buf + sizeof(*spa) * 3;
        spa->header.type = ACPI_NFIT_TYPE_SYSTEM_ADDRESS;
        spa->header.length = sizeof(*spa);
        memcpy(spa->range_guid, to_nfit_uuid(NFIT_SPA_DCR), 16);
@@ -560,7 +543,7 @@ static void nfit_test0_setup(struct nfit_test *t)
        spa->length = DCR_SIZE;
 
        /* spa4 (dcr2) dimm2 */
-       spa = nfit_buf + sizeof(struct acpi_table_nfit) + sizeof(*spa) * 4;
+       spa = nfit_buf + sizeof(*spa) * 4;
        spa->header.type = ACPI_NFIT_TYPE_SYSTEM_ADDRESS;
        spa->header.length = sizeof(*spa);
        memcpy(spa->range_guid, to_nfit_uuid(NFIT_SPA_DCR), 16);
@@ -569,7 +552,7 @@ static void nfit_test0_setup(struct nfit_test *t)
        spa->length = DCR_SIZE;
 
        /* spa5 (dcr3) dimm3 */
-       spa = nfit_buf + sizeof(struct acpi_table_nfit) + sizeof(*spa) * 5;
+       spa = nfit_buf + sizeof(*spa) * 5;
        spa->header.type = ACPI_NFIT_TYPE_SYSTEM_ADDRESS;
        spa->header.length = sizeof(*spa);
        memcpy(spa->range_guid, to_nfit_uuid(NFIT_SPA_DCR), 16);
@@ -578,7 +561,7 @@ static void nfit_test0_setup(struct nfit_test *t)
        spa->length = DCR_SIZE;
 
        /* spa6 (bdw for dcr0) dimm0 */
-       spa = nfit_buf + sizeof(struct acpi_table_nfit) + sizeof(*spa) * 6;
+       spa = nfit_buf + sizeof(*spa) * 6;
        spa->header.type = ACPI_NFIT_TYPE_SYSTEM_ADDRESS;
        spa->header.length = sizeof(*spa);
        memcpy(spa->range_guid, to_nfit_uuid(NFIT_SPA_BDW), 16);
@@ -587,7 +570,7 @@ static void nfit_test0_setup(struct nfit_test *t)
        spa->length = DIMM_SIZE;
 
        /* spa7 (bdw for dcr1) dimm1 */
-       spa = nfit_buf + sizeof(struct acpi_table_nfit) + sizeof(*spa) * 7;
+       spa = nfit_buf + sizeof(*spa) * 7;
        spa->header.type = ACPI_NFIT_TYPE_SYSTEM_ADDRESS;
        spa->header.length = sizeof(*spa);
        memcpy(spa->range_guid, to_nfit_uuid(NFIT_SPA_BDW), 16);
@@ -596,7 +579,7 @@ static void nfit_test0_setup(struct nfit_test *t)
        spa->length = DIMM_SIZE;
 
        /* spa8 (bdw for dcr2) dimm2 */
-       spa = nfit_buf + sizeof(struct acpi_table_nfit) + sizeof(*spa) * 8;
+       spa = nfit_buf + sizeof(*spa) * 8;
        spa->header.type = ACPI_NFIT_TYPE_SYSTEM_ADDRESS;
        spa->header.length = sizeof(*spa);
        memcpy(spa->range_guid, to_nfit_uuid(NFIT_SPA_BDW), 16);
@@ -605,7 +588,7 @@ static void nfit_test0_setup(struct nfit_test *t)
        spa->length = DIMM_SIZE;
 
        /* spa9 (bdw for dcr3) dimm3 */
-       spa = nfit_buf + sizeof(struct acpi_table_nfit) + sizeof(*spa) * 9;
+       spa = nfit_buf + sizeof(*spa) * 9;
        spa->header.type = ACPI_NFIT_TYPE_SYSTEM_ADDRESS;
        spa->header.length = sizeof(*spa);
        memcpy(spa->range_guid, to_nfit_uuid(NFIT_SPA_BDW), 16);
@@ -613,7 +596,7 @@ static void nfit_test0_setup(struct nfit_test *t)
        spa->address = t->dimm_dma[3];
        spa->length = DIMM_SIZE;
 
-       offset = sizeof(struct acpi_table_nfit) + sizeof(*spa) * 10;
+       offset = sizeof(*spa) * 10;
        /* mem-region0 (spa0, dimm0) */
        memdev = nfit_buf + offset;
        memdev->header.type = ACPI_NFIT_TYPE_MEMORY_MAP;
@@ -1100,15 +1083,13 @@ static void nfit_test0_setup(struct nfit_test *t)
 
 static void nfit_test1_setup(struct nfit_test *t)
 {
-       size_t size = t->nfit_size, offset;
+       size_t offset;
        void *nfit_buf = t->nfit_buf;
        struct acpi_nfit_memory_map *memdev;
        struct acpi_nfit_control_region *dcr;
        struct acpi_nfit_system_address *spa;
 
-       nfit_test_init_header(nfit_buf, size);
-
-       offset = sizeof(struct acpi_table_nfit);
+       offset = 0;
        /* spa0 (flat range with no bdw aliasing) */
        spa = nfit_buf + offset;
        spa->header.type = ACPI_NFIT_TYPE_SYSTEM_ADDRESS;
index 3224a049b196e87fd9fe23e0f20ea09c6ea04031..0558bb9ce0a6eadb92aba3a4880aadfa277e0d2c 100644 (file)
@@ -27,7 +27,7 @@ o The build system shall remain as simple as possible, avoiding any archive or
 o Where possible, any helper functions or other package-wide code shall be
   implemented in header files, avoiding the need to compile intermediate object
   files.
-o External dependendencies shall remain as minimal as possible. Currently gcc
+o External dependencies shall remain as minimal as possible. Currently gcc
   and glibc are the only dependencies.
 o Tests return 0 for success and < 0 for failure.
 
index e38cc54942dbf298dd1b880e3eabf5a9f2af29e6..882fe83a355442930a5fc1007a294eee6744b7cc 100644 (file)
@@ -492,6 +492,9 @@ TEST_SIGNAL(KILL_one_arg_six, SIGSYS)
        pid_t parent = getppid();
        int fd;
        void *map1, *map2;
+       int page_size = sysconf(_SC_PAGESIZE);
+
+       ASSERT_LT(0, page_size);
 
        ret = prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0);
        ASSERT_EQ(0, ret);
@@ -504,16 +507,16 @@ TEST_SIGNAL(KILL_one_arg_six, SIGSYS)
 
        EXPECT_EQ(parent, syscall(__NR_getppid));
        map1 = (void *)syscall(sysno,
-               NULL, PAGE_SIZE, PROT_READ, MAP_PRIVATE, fd, PAGE_SIZE);
+               NULL, page_size, PROT_READ, MAP_PRIVATE, fd, page_size);
        EXPECT_NE(MAP_FAILED, map1);
        /* mmap2() should never return. */
        map2 = (void *)syscall(sysno,
-                NULL, PAGE_SIZE, PROT_READ, MAP_PRIVATE, fd, 0x0C0FFEE);
+                NULL, page_size, PROT_READ, MAP_PRIVATE, fd, 0x0C0FFEE);
        EXPECT_EQ(MAP_FAILED, map2);
 
        /* The test failed, so clean up the resources. */
-       munmap(map1, PAGE_SIZE);
-       munmap(map2, PAGE_SIZE);
+       munmap(map1, page_size);
+       munmap(map2, page_size);
        close(fd);
 }
 
index 0a3da64638ceda0e94df98f9651fc241ae1f34c1..4db7d5691ba71b33d2bda8c85d634fe3781ae6d6 100644 (file)
@@ -110,4 +110,10 @@ static inline void free_page(unsigned long addr)
        (void) (&_min1 == &_min2);              \
        _min1 < _min2 ? _min1 : _min2; })
 
+/* TODO: empty stubs for now. Broken but enough for virtio_ring.c */
+#define list_add_tail(a, b) do {} while (0)
+#define list_del(a) do {} while (0)
+#define list_for_each_entry(a, b, c) while (0)
+/* end of stubs */
+
 #endif /* KERNEL_H */
index a3e07016a44017c8c9f25c5dd51e77a09152e127..ee125e714053a91a76658d417a46232349927450 100644 (file)
@@ -3,12 +3,6 @@
 #include <linux/scatterlist.h>
 #include <linux/kernel.h>
 
-/* TODO: empty stubs for now. Broken but enough for virtio_ring.c */
-#define list_add_tail(a, b) do {} while (0)
-#define list_del(a) do {} while (0)
-#define list_for_each_entry(a, b, c) while (0)
-/* end of stubs */
-
 struct virtio_device {
        void *dev;
        u64 features;
index 806d683ab10789a659edfe1c96d15bb08e107356..57a6964a1e355b8daa154adff9bd007c93f8374f 100644 (file)
@@ -40,33 +40,39 @@ static inline void __virtio_clear_bit(struct virtio_device *vdev,
 #define virtio_has_feature(dev, feature) \
        (__virtio_test_bit((dev), feature))
 
+static inline bool virtio_is_little_endian(struct virtio_device *vdev)
+{
+       return virtio_has_feature(vdev, VIRTIO_F_VERSION_1) ||
+               virtio_legacy_is_little_endian();
+}
+
+/* Memory accessors */
 static inline u16 virtio16_to_cpu(struct virtio_device *vdev, __virtio16 val)
 {
-       return __virtio16_to_cpu(virtio_has_feature(vdev, VIRTIO_F_VERSION_1), val);
+       return __virtio16_to_cpu(virtio_is_little_endian(vdev), val);
 }
 
 static inline __virtio16 cpu_to_virtio16(struct virtio_device *vdev, u16 val)
 {
-       return __cpu_to_virtio16(virtio_has_feature(vdev, VIRTIO_F_VERSION_1), val);
+       return __cpu_to_virtio16(virtio_is_little_endian(vdev), val);
 }
 
 static inline u32 virtio32_to_cpu(struct virtio_device *vdev, __virtio32 val)
 {
-       return __virtio32_to_cpu(virtio_has_feature(vdev, VIRTIO_F_VERSION_1), val);
+       return __virtio32_to_cpu(virtio_is_little_endian(vdev), val);
 }
 
 static inline __virtio32 cpu_to_virtio32(struct virtio_device *vdev, u32 val)
 {
-       return __cpu_to_virtio32(virtio_has_feature(vdev, VIRTIO_F_VERSION_1), val);
+       return __cpu_to_virtio32(virtio_is_little_endian(vdev), val);
 }
 
 static inline u64 virtio64_to_cpu(struct virtio_device *vdev, __virtio64 val)
 {
-       return __virtio64_to_cpu(virtio_has_feature(vdev, VIRTIO_F_VERSION_1), val);
+       return __virtio64_to_cpu(virtio_is_little_endian(vdev), val);
 }
 
 static inline __virtio64 cpu_to_virtio64(struct virtio_device *vdev, u64 val)
 {
-       return __cpu_to_virtio64(virtio_has_feature(vdev, VIRTIO_F_VERSION_1), val);
+       return __cpu_to_virtio64(virtio_is_little_endian(vdev), val);
 }
-
index bcf5ec760eb9287f5a0b5f99e95518eaed78f6a0..5a6016224bb9c9c4bbe5f7b28c37738f0edec5a3 100644 (file)
@@ -128,6 +128,7 @@ static const char * const page_flag_names[] = {
        [KPF_THP]               = "t:thp",
        [KPF_BALLOON]           = "o:balloon",
        [KPF_ZERO_PAGE]         = "z:zero_page",
+       [KPF_IDLE]              = "i:idle_page",
 
        [KPF_RESERVED]          = "r:reserved",
        [KPF_MLOCKED]           = "m:mlocked",
index 21a0ab2d891949768d25ff45796f189bad0881e5..69bca185c471d1dec971f02403ae9fd60851f5bd 100644 (file)
@@ -221,17 +221,23 @@ void kvm_timer_flush_hwstate(struct kvm_vcpu *vcpu)
        kvm_timer_update_state(vcpu);
 
        /*
-        * If we enter the guest with the virtual input level to the VGIC
-        * asserted, then we have already told the VGIC what we need to, and
-        * we don't need to exit from the guest until the guest deactivates
-        * the already injected interrupt, so therefore we should set the
-        * hardware active state to prevent unnecessary exits from the guest.
-        *
-        * Conversely, if the virtual input level is deasserted, then always
-        * clear the hardware active state to ensure that hardware interrupts
-        * from the timer triggers a guest exit.
-        */
-       if (timer->irq.level)
+       * If we enter the guest with the virtual input level to the VGIC
+       * asserted, then we have already told the VGIC what we need to, and
+       * we don't need to exit from the guest until the guest deactivates
+       * the already injected interrupt, so therefore we should set the
+       * hardware active state to prevent unnecessary exits from the guest.
+       *
+       * Also, if we enter the guest with the virtual timer interrupt active,
+       * then it must be active on the physical distributor, because we set
+       * the HW bit and the guest must be able to deactivate the virtual and
+       * physical interrupt at the same time.
+       *
+       * Conversely, if the virtual input level is deasserted and the virtual
+       * interrupt is not active, then always clear the hardware active state
+       * to ensure that hardware interrupts from the timer triggers a guest
+       * exit.
+       */
+       if (timer->irq.level || kvm_vgic_map_is_active(vcpu, timer->map))
                phys_active = true;
        else
                phys_active = false;
index 533538385d5d294ce16bae446cc7e2b1578d9b7d..7a2f449bd85d02d7f6571fa4f5b3091df81a04d9 100644 (file)
@@ -1096,6 +1096,27 @@ static void vgic_retire_lr(int lr_nr, struct kvm_vcpu *vcpu)
        vgic_set_lr(vcpu, lr_nr, vlr);
 }
 
+static bool dist_active_irq(struct kvm_vcpu *vcpu)
+{
+       struct vgic_dist *dist = &vcpu->kvm->arch.vgic;
+
+       return test_bit(vcpu->vcpu_id, dist->irq_active_on_cpu);
+}
+
+bool kvm_vgic_map_is_active(struct kvm_vcpu *vcpu, struct irq_phys_map *map)
+{
+       int i;
+
+       for (i = 0; i < vcpu->arch.vgic_cpu.nr_lr; i++) {
+               struct vgic_lr vlr = vgic_get_lr(vcpu, i);
+
+               if (vlr.irq == map->virt_irq && vlr.state & LR_STATE_ACTIVE)
+                       return true;
+       }
+
+       return vgic_irq_is_active(vcpu, map->virt_irq);
+}
+
 /*
  * An interrupt may have been disabled after being made pending on the
  * CPU interface (the classic case is a timer running while we're
@@ -1248,7 +1269,7 @@ static void __kvm_vgic_flush_hwstate(struct kvm_vcpu *vcpu)
         * may have been serviced from another vcpu. In all cases,
         * move along.
         */
-       if (!kvm_vgic_vcpu_pending_irq(vcpu) && !kvm_vgic_vcpu_active_irq(vcpu))
+       if (!kvm_vgic_vcpu_pending_irq(vcpu) && !dist_active_irq(vcpu))
                goto epilog;
 
        /* SGIs */
@@ -1396,25 +1417,13 @@ static bool vgic_process_maintenance(struct kvm_vcpu *vcpu)
 static bool vgic_sync_hwirq(struct kvm_vcpu *vcpu, int lr, struct vgic_lr vlr)
 {
        struct vgic_dist *dist = &vcpu->kvm->arch.vgic;
-       struct irq_phys_map *map;
-       bool phys_active;
        bool level_pending;
-       int ret;
 
        if (!(vlr.state & LR_HW))
                return false;
 
-       map = vgic_irq_map_search(vcpu, vlr.irq);
-       BUG_ON(!map);
-
-       ret = irq_get_irqchip_state(map->irq,
-                                   IRQCHIP_STATE_ACTIVE,
-                                   &phys_active);
-
-       WARN_ON(ret);
-
-       if (phys_active)
-               return 0;
+       if (vlr.state & LR_STATE_ACTIVE)
+               return false;
 
        spin_lock(&dist->lock);
        level_pending = process_queued_irq(vcpu, lr, vlr);
@@ -1479,17 +1488,6 @@ int kvm_vgic_vcpu_pending_irq(struct kvm_vcpu *vcpu)
        return test_bit(vcpu->vcpu_id, dist->irq_pending_on_cpu);
 }
 
-int kvm_vgic_vcpu_active_irq(struct kvm_vcpu *vcpu)
-{
-       struct vgic_dist *dist = &vcpu->kvm->arch.vgic;
-
-       if (!irqchip_in_kernel(vcpu->kvm))
-               return 0;
-
-       return test_bit(vcpu->vcpu_id, dist->irq_active_on_cpu);
-}
-
-
 void vgic_kick_vcpus(struct kvm *kvm)
 {
        struct kvm_vcpu *vcpu;