Merge tag 'asoc-v5.12' of https://git.kernel.org/pub/scm/linux/kernel/git/broonie...
authorTakashi Iwai <tiwai@suse.de>
Wed, 17 Feb 2021 20:16:27 +0000 (21:16 +0100)
committerTakashi Iwai <tiwai@suse.de>
Wed, 17 Feb 2021 20:16:27 +0000 (21:16 +0100)
ASoC: Updates for v5.12

Another quiet release in terms of features, though several of the
drivers got quite a bit of work and there were a lot of general changes
resulting from Morimoto-san's ongoing cleanup work.

 - As ever, lots of hard work by Morimoto-san cleaning up the code and
   making it more consistent.
 - Many improvements in the Intel drivers including a wide range of
   quirks and bug fixes.
 - A KUnit testsuite for the topology code.
 - Support for Ingenic JZ4760(B), Intel AlderLake-P, DT configured
   nVidia cards, Qualcomm lpass-rx-macro and lpass-tx-macro
 - Removal of obsolete SIRF prima/atlas, Txx9 and ZTE zx drivers.

1153 files changed:
.clang-format
.mailmap
Documentation/ABI/testing/sysfs-class-devlink
Documentation/ABI/testing/sysfs-devices-consumer
Documentation/ABI/testing/sysfs-devices-supplier
Documentation/ABI/testing/sysfs-driver-ufs
Documentation/Makefile
Documentation/admin-guide/device-mapper/dm-integrity.rst
Documentation/admin-guide/media/rkisp1.rst
Documentation/admin-guide/syscall-user-dispatch.rst
Documentation/asm-annotations.rst
Documentation/dev-tools/kasan.rst
Documentation/dev-tools/kunit/usage.rst
Documentation/devicetree/bindings/arm/cpus.yaml
Documentation/devicetree/bindings/display/bridge/sii902x.txt
Documentation/devicetree/bindings/display/mediatek/mediatek,disp.txt
Documentation/devicetree/bindings/extcon/wlf,arizona.yaml
Documentation/devicetree/bindings/hwmon/adi,ltc2947.yaml
Documentation/devicetree/bindings/hwmon/baikal,bt1-pvt.yaml
Documentation/devicetree/bindings/hwmon/ti,tmp513.yaml
Documentation/devicetree/bindings/i2c/i2c-gpio.yaml
Documentation/devicetree/bindings/i2c/snps,designware-i2c.yaml
Documentation/devicetree/bindings/iio/accel/bosch,bma255.yaml
Documentation/devicetree/bindings/iio/adc/adi,ad7192.yaml
Documentation/devicetree/bindings/iio/adc/maxim,max9611.yaml
Documentation/devicetree/bindings/iio/adc/st,stm32-adc.yaml
Documentation/devicetree/bindings/iio/adc/ti,palmas-gpadc.yaml
Documentation/devicetree/bindings/iio/dac/adi,ad5758.yaml
Documentation/devicetree/bindings/iio/health/maxim,max30100.yaml
Documentation/devicetree/bindings/input/adc-keys.txt
Documentation/devicetree/bindings/input/touchscreen/goodix.yaml
Documentation/devicetree/bindings/input/touchscreen/touchscreen.yaml
Documentation/devicetree/bindings/leds/richtek,rt8515.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/media/mediatek-jpeg-decoder.txt
Documentation/devicetree/bindings/media/mediatek-jpeg-encoder.txt
Documentation/devicetree/bindings/media/mediatek-mdp.txt
Documentation/devicetree/bindings/mmc/mmc-controller.yaml
Documentation/devicetree/bindings/mmc/mmc-pwrseq-simple.yaml
Documentation/devicetree/bindings/net/ethernet-controller.yaml
Documentation/devicetree/bindings/net/snps,dwmac.yaml
Documentation/devicetree/bindings/power/supply/battery.yaml
Documentation/devicetree/bindings/power/supply/bq2515x.yaml
Documentation/devicetree/bindings/regulator/dlg,da9121.yaml
Documentation/devicetree/bindings/regulator/fixed-regulator.yaml
Documentation/devicetree/bindings/rtc/rtc.yaml
Documentation/devicetree/bindings/serial/pl011.yaml
Documentation/devicetree/bindings/sound/audio-graph-port.yaml
Documentation/devicetree/bindings/sound/ingenic,codec.yaml
Documentation/devicetree/bindings/sound/intel,keembay-i2s.yaml
Documentation/devicetree/bindings/sound/mt8192-mt6359-rt1015-rt5682.yaml
Documentation/devicetree/bindings/sound/nvidia,tegra-audio-graph-card.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/sound/nvidia,tegra186-dspk.yaml
Documentation/devicetree/bindings/sound/nvidia,tegra210-admaif.yaml
Documentation/devicetree/bindings/sound/nvidia,tegra210-ahub.yaml
Documentation/devicetree/bindings/sound/nvidia,tegra210-dmic.yaml
Documentation/devicetree/bindings/sound/nvidia,tegra210-i2s.yaml
Documentation/devicetree/bindings/sound/qcom,lpass-rx-macro.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/sound/qcom,lpass-tx-macro.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/sound/renesas,rsnd.yaml
Documentation/devicetree/bindings/sound/rt5659.txt
Documentation/devicetree/bindings/sound/sgtl5000.yaml
Documentation/devicetree/bindings/sound/sirf-audio-codec.txt [deleted file]
Documentation/devicetree/bindings/sound/sirf-usp.txt [deleted file]
Documentation/devicetree/bindings/sound/st,stm32-i2s.yaml
Documentation/devicetree/bindings/sound/wm8962.txt
Documentation/devicetree/bindings/sound/zte,tdm.txt [deleted file]
Documentation/devicetree/bindings/sound/zte,zx-aud96p22.txt [deleted file]
Documentation/devicetree/bindings/sound/zte,zx-i2s.txt [deleted file]
Documentation/devicetree/bindings/sound/zte,zx-spdif.txt [deleted file]
Documentation/devicetree/bindings/usb/ti,j721e-usb.yaml
Documentation/devicetree/bindings/watchdog/watchdog.yaml
Documentation/filesystems/overlayfs.rst
Documentation/kbuild/gcc-plugins.rst
Documentation/kbuild/llvm.rst
Documentation/kbuild/makefiles.rst
Documentation/networking/ip-sysctl.rst
Documentation/networking/tls-offload.rst
Documentation/virt/kvm/api.rst
Documentation/virt/kvm/nested-vmx.rst
Documentation/virt/kvm/running-nested-guests.rst
MAINTAINERS
Makefile
arch/arm/boot/compressed/atags_to_fdt.c
arch/arm/boot/dts/imx6q-tbs2910.dts
arch/arm/boot/dts/imx6qdl-gw52xx.dtsi
arch/arm/boot/dts/imx6qdl-kontron-samx6i.dtsi
arch/arm/boot/dts/imx6qdl-sr-som.dtsi
arch/arm/boot/dts/imx7d-flex-concentrator.dts
arch/arm/boot/dts/lpc32xx.dtsi
arch/arm/boot/dts/omap3-gta04.dtsi
arch/arm/boot/dts/omap4-droid4-xt894.dts
arch/arm/boot/dts/ste-db8500.dtsi
arch/arm/boot/dts/ste-db8520.dtsi
arch/arm/boot/dts/ste-db9500.dtsi [new file with mode: 0644]
arch/arm/boot/dts/ste-snowball.dts
arch/arm/boot/dts/stm32mp15xx-dhcom-drc02.dtsi
arch/arm/boot/dts/stm32mp15xx-dhcom-picoitx.dtsi
arch/arm/boot/dts/stm32mp15xx-dhcom-som.dtsi
arch/arm/boot/dts/sun7i-a20-bananapro.dts
arch/arm/include/asm/kexec-internal.h [new file with mode: 0644]
arch/arm/include/debug/tegra.S
arch/arm/kernel/asm-offsets.c
arch/arm/kernel/machine_kexec.c
arch/arm/kernel/relocate_kernel.S
arch/arm/kernel/signal.c
arch/arm/mach-footbridge/dc21285.c
arch/arm/mach-imx/suspend-imx6.S
arch/arm/mach-omap1/board-osk.c
arch/arm/mach-omap2/Kconfig
arch/arm/mach-omap2/cpuidle44xx.c
arch/arm/mach-omap2/pdata-quirks.c
arch/arm64/boot/dts/amlogic/meson-axg.dtsi
arch/arm64/boot/dts/amlogic/meson-g12-common.dtsi
arch/arm64/boot/dts/amlogic/meson-gx.dtsi
arch/arm64/boot/dts/amlogic/meson-sm1-odroid-c4.dts
arch/arm64/boot/dts/broadcom/stingray/stingray-usb.dtsi
arch/arm64/boot/dts/freescale/fsl-ls1028a.dtsi
arch/arm64/boot/dts/freescale/fsl-ls1046a.dtsi
arch/arm64/boot/dts/freescale/imx8mn.dtsi
arch/arm64/boot/dts/freescale/imx8mp.dtsi
arch/arm64/boot/dts/qcom/sdm845-db845c.dts
arch/arm64/boot/dts/qcom/sdm850-lenovo-yoga-c630.dts
arch/arm64/boot/dts/rockchip/px30.dtsi
arch/arm64/boot/dts/rockchip/rk3328-nanopi-r2s.dts
arch/arm64/boot/dts/rockchip/rk3399-pinebook-pro.dts
arch/arm64/boot/dts/rockchip/rk3399.dtsi
arch/arm64/configs/defconfig
arch/arm64/include/asm/memory.h
arch/arm64/kernel/probes/kprobes.c
arch/arm64/kvm/arm.c
arch/arm64/kvm/hyp/nvhe/hyp-init.S
arch/arm64/kvm/hyp/nvhe/psci-relay.c
arch/arm64/kvm/pmu-emul.c
arch/arm64/kvm/sys_regs.c
arch/arm64/mm/fault.c
arch/arm64/mm/physaddr.c
arch/ia64/Makefile
arch/ia64/include/asm/sparsemem.h
arch/ia64/include/uapi/asm/cmpxchg.h
arch/ia64/kernel/time.c
arch/ia64/scripts/unwcheck.py
arch/mips/include/asm/highmem.h
arch/openrisc/include/asm/io.h
arch/openrisc/mm/ioremap.c
arch/parisc/Kconfig
arch/parisc/include/asm/irq.h
arch/parisc/kernel/entry.S
arch/powerpc/include/asm/exception-64s.h
arch/powerpc/include/asm/feature-fixups.h
arch/powerpc/include/asm/highmem.h
arch/powerpc/kernel/Makefile
arch/powerpc/kernel/entry_64.S
arch/powerpc/kernel/exceptions-64s.S
arch/powerpc/kernel/irq.c
arch/powerpc/kernel/vdso32/Makefile
arch/powerpc/kernel/vdso32/vdso32_wrapper.S [deleted file]
arch/powerpc/kernel/vdso32_wrapper.S [new file with mode: 0644]
arch/powerpc/kernel/vdso64/Makefile
arch/powerpc/kernel/vdso64/sigtramp.S
arch/powerpc/kernel/vdso64/vdso64.lds.S
arch/powerpc/kernel/vdso64/vdso64_wrapper.S [deleted file]
arch/powerpc/kernel/vdso64_wrapper.S [new file with mode: 0644]
arch/powerpc/kernel/vmlinux.lds.S
arch/powerpc/lib/feature-fixups.c
arch/powerpc/lib/sstep.c
arch/riscv/Kconfig
arch/riscv/include/asm/page.h
arch/riscv/include/asm/set_memory.h
arch/riscv/kernel/setup.c
arch/riscv/mm/init.c
arch/s390/boot/uv.c
arch/s390/include/asm/uv.h
arch/s390/kernel/uv.c
arch/sh/Kconfig
arch/sh/boards/mach-sh03/rtc.c
arch/sh/configs/landisk_defconfig
arch/sh/configs/microdev_defconfig
arch/sh/configs/sdk7780_defconfig
arch/sh/configs/sdk7786_defconfig
arch/sh/configs/se7750_defconfig
arch/sh/configs/sh03_defconfig
arch/sh/drivers/dma/Kconfig
arch/sh/include/asm/gpio.h
arch/sh/kernel/cpu/sh3/entry.S
arch/sh/mm/Kconfig
arch/sh/mm/asids-debugfs.c
arch/sh/mm/cache-debugfs.c
arch/sh/mm/pmb.c
arch/sparc/include/asm/highmem.h
arch/um/Kconfig
arch/um/drivers/ubd_kern.c
arch/um/drivers/virtio_uml.c
arch/um/include/asm/io.h
arch/um/include/asm/pgtable.h
arch/um/include/asm/set_memory.h [deleted file]
arch/um/include/shared/kern_util.h
arch/um/kernel/kmsg_dump.c
arch/um/kernel/process.c
arch/um/kernel/time.c
arch/um/kernel/tlb.c
arch/um/kernel/um_arch.c
arch/um/os-Linux/helper.c
arch/um/os-Linux/time.c
arch/x86/Makefile
arch/x86/entry/common.c
arch/x86/entry/thunk_64.S
arch/x86/hyperv/hv_init.c
arch/x86/include/asm/apic.h
arch/x86/include/asm/barrier.h
arch/x86/include/asm/entry-common.h
arch/x86/include/asm/fpu/api.h
arch/x86/include/asm/idtentry.h
arch/x86/include/asm/intel-family.h
arch/x86/include/asm/msr.h
arch/x86/include/asm/topology.h
arch/x86/kernel/apic/apic.c
arch/x86/kernel/apic/x2apic_cluster.c
arch/x86/kernel/apic/x2apic_phys.c
arch/x86/kernel/cpu/amd.c
arch/x86/kernel/cpu/intel.c
arch/x86/kernel/cpu/mce/core.c
arch/x86/kernel/cpu/topology.c
arch/x86/kernel/fpu/core.c
arch/x86/kernel/hw_breakpoint.c
arch/x86/kernel/sev-es.c
arch/x86/kernel/smpboot.c
arch/x86/kernel/step.c
arch/x86/kvm/cpuid.c
arch/x86/kvm/emulate.c
arch/x86/kvm/kvm_cache_regs.h
arch/x86/kvm/mmu.h
arch/x86/kvm/mmu/tdp_mmu.c
arch/x86/kvm/svm/nested.c
arch/x86/kvm/svm/sev.c
arch/x86/kvm/svm/svm.c
arch/x86/kvm/svm/svm.h
arch/x86/kvm/vmx/nested.c
arch/x86/kvm/vmx/pmu_intel.c
arch/x86/kvm/vmx/vmx.c
arch/x86/kvm/x86.c
arch/x86/kvm/x86.h
arch/x86/lib/mmx_32.c
arch/x86/mm/mem_encrypt.c
arch/x86/platform/efi/efi_64.c
arch/x86/xen/enlighten_pv.c
arch/x86/xen/smp_hvm.c
arch/x86/xen/xen-asm.S
block/bfq-iosched.c
block/blk-cgroup.c
block/blk-mq.h
block/genhd.c
block/partitions/core.c
crypto/asymmetric_keys/public_key.c
crypto/xor.c
drivers/acpi/arm64/iort.c
drivers/acpi/device_sysfs.c
drivers/acpi/nfit/core.c
drivers/acpi/scan.c
drivers/acpi/thermal.c
drivers/base/core.c
drivers/base/dd.c
drivers/base/platform.c
drivers/block/nbd.c
drivers/block/null_blk/zoned.c
drivers/block/xen-blkfront.c
drivers/bus/arm-integrator-lm.c
drivers/bus/simple-pm-bus.c
drivers/clk/imx/Kconfig
drivers/clk/mmp/clk-audio.c
drivers/clk/qcom/gcc-sc7180.c
drivers/clk/qcom/gcc-sm8250.c
drivers/counter/ti-eqep.c
drivers/crypto/Kconfig
drivers/crypto/marvell/cesa/cesa.h
drivers/firmware/efi/apple-properties.c
drivers/firmware/imx/Kconfig
drivers/gpio/Kconfig
drivers/gpio/gpio-mvebu.c
drivers/gpio/gpiolib-cdev.c
drivers/gpio/gpiolib.c
drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gpuvm.c
drivers/gpu/drm/amd/amdgpu/amdgpu_device.c
drivers/gpu/drm/amd/amdgpu/amdgpu_display.c
drivers/gpu/drm/amd/amdgpu/amdgpu_gem.c
drivers/gpu/drm/amd/amdgpu/amdgpu_object.c
drivers/gpu/drm/amd/amdgpu/gfx_v10_0.c
drivers/gpu/drm/amd/amdgpu/mmhub_v2_3.c
drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c
drivers/gpu/drm/amd/display/dc/clk_mgr/dcn30/dcn30_clk_mgr.c
drivers/gpu/drm/amd/display/dc/core/dc.c
drivers/gpu/drm/amd/display/dc/core/dc_link_dp.c
drivers/gpu/drm/amd/display/dc/dc_stream.h
drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer.c
drivers/gpu/drm/amd/display/dc/dcn20/dcn20_hwseq.c
drivers/gpu/drm/amd/display/dc/dcn20/dcn20_resource.c
drivers/gpu/drm/amd/display/dc/dcn21/dcn21_resource.c
drivers/gpu/drm/amd/display/dc/dcn30/Makefile
drivers/gpu/drm/amd/display/dc/dcn301/Makefile
drivers/gpu/drm/amd/display/dc/dcn302/Makefile
drivers/gpu/drm/amd/pm/inc/amdgpu_smu.h
drivers/gpu/drm/amd/pm/inc/smu_v11_0.h
drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c
drivers/gpu/drm/amd/pm/swsmu/smu11/arcturus_ppt.c
drivers/gpu/drm/amd/pm/swsmu/smu11/navi10_ppt.c
drivers/gpu/drm/amd/pm/swsmu/smu11/sienna_cichlid_ppt.c
drivers/gpu/drm/amd/pm/swsmu/smu11/smu_v11_0.c
drivers/gpu/drm/amd/pm/swsmu/smu11/vangogh_ppt.c
drivers/gpu/drm/amd/pm/swsmu/smu12/renoir_ppt.c
drivers/gpu/drm/bridge/lontium-lt9611uxc.c
drivers/gpu/drm/drm_atomic_helper.c
drivers/gpu/drm/drm_dp_mst_topology.c
drivers/gpu/drm/drm_gem_vram_helper.c
drivers/gpu/drm/drm_syncobj.c
drivers/gpu/drm/i915/display/intel_ddi.c
drivers/gpu/drm/i915/display/intel_display.c
drivers/gpu/drm/i915/display/intel_dp.c
drivers/gpu/drm/i915/display/intel_dp.h
drivers/gpu/drm/i915/display/intel_dp_link_training.c
drivers/gpu/drm/i915/display/intel_dp_link_training.h
drivers/gpu/drm/i915/display/intel_dp_mst.c
drivers/gpu/drm/i915/display/intel_hdcp.c
drivers/gpu/drm/i915/display/intel_overlay.c
drivers/gpu/drm/i915/display/intel_sprite.c
drivers/gpu/drm/i915/gem/i915_gem_domain.c
drivers/gpu/drm/i915/gem/i915_gem_object.h
drivers/gpu/drm/i915/gt/gen7_renderclear.c
drivers/gpu/drm/i915/gt/intel_breadcrumbs.c
drivers/gpu/drm/i915/gt/intel_ggtt.c
drivers/gpu/drm/i915/gt/intel_lrc.c
drivers/gpu/drm/i915/gt/intel_timeline.c
drivers/gpu/drm/i915/i915_active.c
drivers/gpu/drm/i915/i915_drv.h
drivers/gpu/drm/i915/i915_pmu.c
drivers/gpu/drm/i915/i915_request.h
drivers/gpu/drm/i915/selftests/i915_gem_gtt.c
drivers/gpu/drm/nouveau/dispnv50/base507c.c
drivers/gpu/drm/nouveau/dispnv50/base827c.c
drivers/gpu/drm/nouveau/dispnv50/disp.c
drivers/gpu/drm/nouveau/dispnv50/head917d.c
drivers/gpu/drm/nouveau/dispnv50/wndw.c
drivers/gpu/drm/nouveau/include/nvhw/class/cl917d.h
drivers/gpu/drm/nouveau/include/nvif/push.h
drivers/gpu/drm/nouveau/nouveau_bo.c
drivers/gpu/drm/nouveau/nouveau_svm.c
drivers/gpu/drm/ttm/ttm_pool.c
drivers/gpu/drm/vc4/vc4_hdmi.c
drivers/gpu/drm/vc4/vc4_hvs.c
drivers/gpu/drm/vc4/vc4_plane.c
drivers/hid/hid-multitouch.c
drivers/hid/wacom_sys.c
drivers/hid/wacom_wac.h
drivers/hwtracing/intel_th/pci.c
drivers/hwtracing/stm/heartbeat.c
drivers/i2c/busses/Kconfig
drivers/i2c/busses/i2c-imx.c
drivers/i2c/busses/i2c-mt65xx.c
drivers/i2c/busses/i2c-octeon-core.c
drivers/i2c/busses/i2c-tegra-bpmp.c
drivers/i2c/busses/i2c-tegra.c
drivers/iio/adc/ti_am335x_adc.c
drivers/iio/common/st_sensors/st_sensors_trigger.c
drivers/iio/dac/ad5504.c
drivers/iio/proximity/sx9310.c
drivers/iio/temperature/mlx90632.c
drivers/infiniband/hw/cxgb4/qp.c
drivers/infiniband/hw/hns/hns_roce_device.h
drivers/infiniband/hw/hns/hns_roce_qp.c
drivers/infiniband/hw/mlx5/main.c
drivers/infiniband/hw/usnic/usnic_ib_sysfs.c
drivers/infiniband/hw/vmw_pvrdma/pvrdma.h
drivers/infiniband/hw/vmw_pvrdma/pvrdma_cq.c
drivers/infiniband/sw/rxe/rxe_net.c
drivers/infiniband/sw/rxe/rxe_resp.c
drivers/input/joystick/xpad.c
drivers/input/misc/ariel-pwrbutton.c
drivers/input/serio/i8042-x86ia64io.h
drivers/input/touchscreen/goodix.c
drivers/input/touchscreen/ili210x.c
drivers/input/touchscreen/st1232.c
drivers/iommu/amd/amd_iommu.h
drivers/iommu/amd/amd_iommu_types.h
drivers/iommu/amd/init.c
drivers/iommu/intel/dmar.c
drivers/iommu/intel/iommu.c
drivers/irqchip/Kconfig
drivers/irqchip/irq-bcm2836.c
drivers/irqchip/irq-loongson-liointc.c
drivers/irqchip/irq-mips-cpu.c
drivers/irqchip/irq-sl28cpld.c
drivers/leds/Kconfig
drivers/leds/Makefile
drivers/leds/flash/Kconfig [new file with mode: 0644]
drivers/leds/flash/Makefile [new file with mode: 0644]
drivers/leds/flash/leds-rt8515.c [new file with mode: 0644]
drivers/leds/led-triggers.c
drivers/leds/leds-ariel.c
drivers/leds/leds-lm3533.c
drivers/lightnvm/core.c
drivers/md/bcache/features.h
drivers/md/dm-crypt.c
drivers/md/dm-integrity.c
drivers/md/dm-table.c
drivers/md/md.c
drivers/media/cec/platform/Makefile
drivers/media/common/videobuf2/videobuf2-v4l2.c
drivers/media/i2c/ccs-pll.c
drivers/media/i2c/ccs/ccs-data.c
drivers/media/pci/intel/ipu3/ipu3-cio2.c
drivers/media/platform/qcom/venus/core.c
drivers/media/platform/rcar-vin/rcar-core.c
drivers/media/platform/rockchip/rkisp1/rkisp1-dev.c
drivers/media/platform/rockchip/rkisp1/rkisp1-params.c
drivers/media/platform/rockchip/rkisp1/rkisp1-regs.h
drivers/media/platform/rockchip/rkisp1/rkisp1-stats.c
drivers/media/rc/ir-mce_kbd-decoder.c
drivers/media/rc/ite-cir.c
drivers/media/rc/rc-main.c
drivers/media/rc/serial_ir.c
drivers/media/v4l2-core/v4l2-common.c
drivers/mfd/arizona-core.c
drivers/mfd/arizona-i2c.c
drivers/mfd/arizona-spi.c
drivers/mfd/arizona.h
drivers/misc/cardreader/rtsx_pcr.c
drivers/misc/habanalabs/common/device.c
drivers/misc/habanalabs/common/firmware_if.c
drivers/misc/habanalabs/common/habanalabs.h
drivers/misc/habanalabs/common/habanalabs_ioctl.c
drivers/misc/habanalabs/common/memory.c
drivers/misc/habanalabs/common/mmu.c
drivers/misc/habanalabs/common/mmu_v1.c
drivers/misc/habanalabs/gaudi/gaudi.c
drivers/misc/habanalabs/goya/goya.c
drivers/mmc/core/queue.c
drivers/mmc/core/sdio_cis.c
drivers/mmc/host/sdhci-brcmstb.c
drivers/mmc/host/sdhci-of-dwcmshc.c
drivers/mmc/host/sdhci-pltfm.h
drivers/mmc/host/sdhci-xenon.c
drivers/mtd/nand/raw/gpmi-nand/gpmi-nand.c
drivers/mtd/nand/raw/intel-nand-controller.c
drivers/mtd/nand/raw/nandsim.c
drivers/mtd/nand/raw/omap2.c
drivers/mtd/nand/spi/core.c
drivers/net/arcnet/arc-rimi.c
drivers/net/arcnet/arcdevice.h
drivers/net/arcnet/arcnet.c
drivers/net/arcnet/com20020-isa.c
drivers/net/arcnet/com20020-pci.c
drivers/net/arcnet/com20020_cs.c
drivers/net/arcnet/com90io.c
drivers/net/arcnet/com90xx.c
drivers/net/can/dev.c
drivers/net/can/usb/peak_usb/pcan_usb_fd.c
drivers/net/can/vxcan.c
drivers/net/dsa/b53/b53_common.c
drivers/net/dsa/bcm_sf2.c
drivers/net/dsa/microchip/ksz8795.c
drivers/net/dsa/microchip/ksz_common.c
drivers/net/dsa/mv88e6xxx/chip.c
drivers/net/dsa/mv88e6xxx/global1_vtu.c
drivers/net/ethernet/broadcom/bcmsysport.c
drivers/net/ethernet/chelsio/inline_crypto/chtls/chtls_cm.c
drivers/net/ethernet/freescale/fec.h
drivers/net/ethernet/freescale/fec_main.c
drivers/net/ethernet/ibm/ibmvnic.c
drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c
drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.h
drivers/net/ethernet/intel/ice/ice.h
drivers/net/ethernet/intel/ice/ice_ethtool.c
drivers/net/ethernet/intel/ice/ice_ethtool_fdir.c
drivers/net/ethernet/intel/ice/ice_lib.c
drivers/net/ethernet/intel/ice/ice_main.c
drivers/net/ethernet/intel/ice/ice_txrx.c
drivers/net/ethernet/intel/igc/igc_ethtool.c
drivers/net/ethernet/intel/igc/igc_i225.c
drivers/net/ethernet/intel/igc/igc_mac.c
drivers/net/ethernet/marvell/mvpp2/mvpp2_prs.c
drivers/net/ethernet/marvell/octeontx2/af/rvu_cgx.c
drivers/net/ethernet/marvell/octeontx2/nic/otx2_common.c
drivers/net/ethernet/mellanox/mlx5/core/en/health.c
drivers/net/ethernet/mellanox/mlx5/core/en/tc_ct.c
drivers/net/ethernet/mellanox/mlx5/core/en_accel/ipsec_stats.c
drivers/net/ethernet/mellanox/mlx5/core/en_dcbnl.c
drivers/net/ethernet/mellanox/mlx5/core/en_ethtool.c
drivers/net/ethernet/mellanox/mlx5/core/en_main.c
drivers/net/ethernet/mellanox/mlx5/core/en_rep.c
drivers/net/ethernet/mellanox/mlx5/core/en_rx.c
drivers/net/ethernet/mellanox/mlx5/core/en_tc.c
drivers/net/ethernet/mellanox/mlx5/core/fs_core.c
drivers/net/ethernet/mellanox/mlx5/core/lib/mlx5.h
drivers/net/ethernet/mellanox/mlx5/core/pagealloc.c
drivers/net/ethernet/mellanox/mlxsw/spectrum_span.c
drivers/net/ethernet/mellanox/mlxsw/spectrum_span.h
drivers/net/ethernet/mscc/ocelot.c
drivers/net/ethernet/mscc/ocelot_net.c
drivers/net/ethernet/realtek/r8169_main.c
drivers/net/ethernet/renesas/sh_eth.c
drivers/net/ethernet/stmicro/stmmac/dwmac-intel-plat.c
drivers/net/ethernet/stmicro/stmmac/dwmac-intel.c
drivers/net/ipa/gsi.c
drivers/net/ipa/ipa_endpoint.c
drivers/net/ipa/ipa_mem.c
drivers/net/mdio/mdio-bitbang.c
drivers/net/team/team.c
drivers/net/usb/cdc_ether.c
drivers/net/usb/cdc_ncm.c
drivers/net/usb/qmi_wwan.c
drivers/net/wireless/intel/iwlwifi/cfg/22000.c
drivers/net/wireless/intel/iwlwifi/fw/acpi.c
drivers/net/wireless/intel/iwlwifi/fw/acpi.h
drivers/net/wireless/intel/iwlwifi/fw/pnvm.c
drivers/net/wireless/intel/iwlwifi/iwl-config.h
drivers/net/wireless/intel/iwlwifi/iwl-dbg-tlv.c
drivers/net/wireless/intel/iwlwifi/iwl-io.c
drivers/net/wireless/intel/iwlwifi/iwl-io.h
drivers/net/wireless/intel/iwlwifi/iwl-prph.h
drivers/net/wireless/intel/iwlwifi/mvm/d3.c
drivers/net/wireless/intel/iwlwifi/mvm/debugfs-vif.c
drivers/net/wireless/intel/iwlwifi/mvm/fw.c
drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c
drivers/net/wireless/intel/iwlwifi/mvm/ops.c
drivers/net/wireless/intel/iwlwifi/mvm/sta.c
drivers/net/wireless/intel/iwlwifi/mvm/tx.c
drivers/net/wireless/intel/iwlwifi/pcie/ctxt-info-gen3.c
drivers/net/wireless/intel/iwlwifi/pcie/drv.c
drivers/net/wireless/intel/iwlwifi/pcie/trans.c
drivers/net/wireless/intel/iwlwifi/pcie/tx.c
drivers/net/wireless/intel/iwlwifi/queue/tx.c
drivers/net/wireless/mediatek/mt76/mt7615/mcu.c
drivers/net/wireless/mediatek/mt76/mt7615/sdio_txrx.c
drivers/net/wireless/mediatek/mt76/mt7915/mcu.c
drivers/net/wireless/mediatek/mt7601u/dma.c
drivers/nvdimm/dimm_devs.c
drivers/nvdimm/namespace_devs.c
drivers/nvdimm/pmem.c
drivers/nvme/host/core.c
drivers/nvme/host/multipath.c
drivers/nvme/host/pci.c
drivers/nvme/host/rdma.c
drivers/nvme/host/tcp.c
drivers/nvme/target/admin-cmd.c
drivers/nvme/target/tcp.c
drivers/of/device.c
drivers/pci/pci.c
drivers/pci/pci.h
drivers/pci/pcie/aspm.c
drivers/phy/ingenic/Makefile
drivers/phy/mediatek/Kconfig
drivers/phy/motorola/phy-cpcap-usb.c
drivers/pinctrl/aspeed/pinctrl-aspeed-g6.c
drivers/pinctrl/mediatek/pinctrl-mtk-common-v2.c
drivers/pinctrl/nomadik/pinctrl-nomadik.c
drivers/pinctrl/pinctrl-ingenic.c
drivers/pinctrl/qcom/pinctrl-msm.c
drivers/pinctrl/qcom/pinctrl-msm.h
drivers/platform/surface/Kconfig
drivers/platform/surface/surface_gpe.c
drivers/platform/x86/amd-pmc.c
drivers/platform/x86/dell-wmi-sysman/sysman.c
drivers/platform/x86/hp-wmi.c
drivers/platform/x86/i2c-multi-instantiate.c
drivers/platform/x86/ideapad-laptop.c
drivers/platform/x86/intel-vbtn.c
drivers/platform/x86/thinkpad_acpi.c
drivers/platform/x86/touchscreen_dmi.c
drivers/regulator/core.c
drivers/rtc/rtc-cmos.c
drivers/rtc/rtc-mc146818-lib.c
drivers/s390/block/dasd_devmap.c
drivers/s390/block/dasd_eckd.c
drivers/s390/block/dasd_int.h
drivers/s390/crypto/vfio_ap_drv.c
drivers/s390/crypto/vfio_ap_ops.c
drivers/s390/crypto/vfio_ap_private.h
drivers/scsi/fnic/vnic_dev.c
drivers/scsi/ibmvscsi/ibmvfc.c
drivers/scsi/libfc/fc_exch.c
drivers/scsi/lpfc/lpfc_nvme.c
drivers/scsi/megaraid/megaraid_sas_base.c
drivers/scsi/qla2xxx/qla_os.c
drivers/scsi/scsi_transport_srp.c
drivers/scsi/ufs/Kconfig
drivers/scsi/ufs/ufshcd.c
drivers/sh/intc/core.c
drivers/sh/intc/virq-debugfs.c
drivers/soc/atmel/soc.c
drivers/soc/imx/Kconfig
drivers/soc/litex/Kconfig
drivers/soc/litex/litex_soc_ctrl.c
drivers/soc/sunxi/sunxi_mbus.c
drivers/soc/ti/omap_prm.c
drivers/spi/spi-altera.c
drivers/spi/spi-cadence.c
drivers/spi/spi-fsl-spi.c
drivers/spi/spidev.c
drivers/staging/media/hantro/hantro_v4l2.c
drivers/staging/media/sunxi/cedrus/cedrus_h264.c
drivers/staging/rtl8723bs/include/rtw_wifi_regd.h
drivers/staging/rtl8723bs/os_dep/ioctl_cfg80211.c
drivers/staging/rtl8723bs/os_dep/sdio_intf.c
drivers/staging/rtl8723bs/os_dep/wifi_regd.c
drivers/target/iscsi/iscsi_target_login.c
drivers/target/target_core_user.c
drivers/tee/optee/call.c
drivers/thunderbolt/acpi.c
drivers/thunderbolt/icm.c
drivers/tty/n_tty.c
drivers/tty/serial/mvebu-uart.c
drivers/tty/tty_io.c
drivers/usb/cdns3/cdns3-imx.c
drivers/usb/class/usblp.c
drivers/usb/dwc2/gadget.c
drivers/usb/dwc3/core.c
drivers/usb/gadget/legacy/ether.c
drivers/usb/gadget/udc/aspeed-vhub/epn.c
drivers/usb/gadget/udc/aspeed-vhub/hub.c
drivers/usb/gadget/udc/bdc/Kconfig
drivers/usb/gadget/udc/core.c
drivers/usb/gadget/udc/dummy_hcd.c
drivers/usb/host/ehci-hcd.c
drivers/usb/host/ehci-hub.c
drivers/usb/host/xhci-mtk-sch.c
drivers/usb/host/xhci-mtk.c
drivers/usb/host/xhci-mtk.h
drivers/usb/host/xhci-mvebu.c
drivers/usb/host/xhci-mvebu.h
drivers/usb/host/xhci-plat.c
drivers/usb/host/xhci-plat.h
drivers/usb/host/xhci-ring.c
drivers/usb/host/xhci-tegra.c
drivers/usb/host/xhci.c
drivers/usb/host/xhci.h
drivers/usb/renesas_usbhs/fifo.c
drivers/usb/serial/cp210x.c
drivers/usb/serial/option.c
drivers/vdpa/mlx5/core/mlx5_vdpa.h
drivers/vdpa/mlx5/core/mr.c
drivers/vdpa/mlx5/net/mlx5_vnet.c
drivers/xen/xenbus/xenbus_probe.c
fs/afs/main.c
fs/block_dev.c
fs/btrfs/backref.c
fs/btrfs/block-group.c
fs/btrfs/ctree.h
fs/btrfs/extent-tree.c
fs/btrfs/free-space-tree.c
fs/btrfs/send.c
fs/btrfs/transaction.c
fs/btrfs/volumes.c
fs/btrfs/volumes.h
fs/cachefiles/rdwr.c
fs/ceph/mds_client.c
fs/cifs/cifs_dfs_ref.c
fs/cifs/cifsfs.c
fs/cifs/cifsproto.h
fs/cifs/connect.c
fs/cifs/dfs_cache.c
fs/cifs/dir.c
fs/cifs/fs_context.c
fs/cifs/smb2pdu.h
fs/cifs/transport.c
fs/ecryptfs/inode.c
fs/fs-writeback.c
fs/hugetlbfs/inode.c
fs/io_uring.c
fs/kernfs/file.c
fs/nfs/pnfs.c
fs/nfsd/nfs3xdr.c
fs/overlayfs/copy_up.c
fs/overlayfs/dir.c
fs/overlayfs/file.c
fs/overlayfs/inode.c
fs/overlayfs/overlayfs.h
fs/overlayfs/ovl_entry.h
fs/overlayfs/readdir.c
fs/overlayfs/super.c
fs/overlayfs/util.c
fs/pipe.c
fs/proc/proc_sysctl.c
fs/udf/super.c
include/drm/drm_dp_mst_helper.h
include/linux/device.h
include/linux/entry-common.h
include/linux/hugetlb.h
include/linux/iommu.h
include/linux/irq.h
include/linux/kasan.h
include/linux/kprobes.h
include/linux/kthread.h
include/linux/ktime.h
include/linux/linkage.h
include/linux/mdio-bitbang.h
include/linux/mlx5/driver.h
include/linux/msi.h
include/linux/nvme.h
include/linux/platform_data/cros_ec_commands.h
include/linux/regulator/consumer.h
include/linux/sunrpc/xdr.h
include/linux/thread_info.h
include/linux/timekeeping32.h [deleted file]
include/linux/tracepoint.h
include/linux/tty.h
include/linux/usb/usbnet.h
include/linux/vmalloc.h
include/media/v4l2-common.h
include/net/cfg80211.h
include/net/inet_connection_sock.h
include/net/lapb.h
include/net/mac80211.h
include/net/netfilter/nf_tables.h
include/net/sch_generic.h
include/net/sock.h
include/net/tcp.h
include/net/udp.h
include/sound/dmaengine_pcm.h
include/sound/graph_card.h
include/sound/hdmi-codec.h
include/sound/rt5645.h
include/sound/soc-component.h
include/sound/soc-dai.h
include/sound/soc.h
include/sound/sof/ext_manifest.h
include/trace/events/sched.h
include/trace/events/sunrpc.h
include/uapi/linux/mrp_bridge.h
include/uapi/linux/prctl.h
include/uapi/linux/rkisp1-config.h
include/uapi/linux/rpl.h
include/uapi/linux/v4l2-subdev.h
include/uapi/rdma/vmw_pvrdma-abi.h
init/Kconfig
init/init_task.c
init/main.c
kernel/bpf/bpf_inode_storage.c
kernel/bpf/bpf_lsm.c
kernel/bpf/bpf_task_storage.c
kernel/bpf/btf.c
kernel/bpf/cgroup.c
kernel/bpf/helpers.c
kernel/bpf/preload/Makefile
kernel/bpf/syscall.c
kernel/bpf/verifier.c
kernel/dma/map_benchmark.c
kernel/entry/common.c
kernel/entry/syscall_user_dispatch.c
kernel/fork.c
kernel/futex.c
kernel/gcov/Kconfig
kernel/irq/manage.c
kernel/irq/msi.c
kernel/kexec_core.c
kernel/kprobes.c
kernel/kthread.c
kernel/locking/lockdep.c
kernel/locking/rtmutex.c
kernel/locking/rtmutex_common.h
kernel/power/swap.c
kernel/printk/printk.c
kernel/printk/printk_ringbuffer.c
kernel/sched/core.c
kernel/sched/sched.h
kernel/signal.c
kernel/smpboot.c
kernel/time/ntp.c
kernel/time/timekeeping.c
kernel/trace/fgraph.c
kernel/trace/trace_irqsoff.c
kernel/trace/trace_kprobe.c
kernel/workqueue.c
lib/Kconfig.ubsan
lib/cpumask.c
lib/ubsan.c
lib/ubsan.h
mm/compaction.c
mm/filemap.c
mm/highmem.c
mm/huge_memory.c
mm/hugetlb.c
mm/kasan/hw_tags.c
mm/kasan/init.c
mm/kasan/kasan.h
mm/memblock.c
mm/memcontrol.c
mm/memory-failure.c
mm/migrate.c
mm/page_alloc.c
mm/slub.c
net/bpf/test_run.c
net/bridge/br_private_mrp.h
net/ceph/auth_x.c
net/ceph/crypto.c
net/ceph/messenger_v1.c
net/ceph/messenger_v2.c
net/ceph/mon_client.c
net/ceph/osd_client.c
net/core/dev.c
net/core/devlink.c
net/core/gen_estimator.c
net/core/neighbour.c
net/core/skbuff.c
net/decnet/dn_route.c
net/hsr/hsr_main.h
net/ipv4/inet_connection_sock.c
net/ipv4/ip_tunnel.c
net/ipv4/netfilter/ipt_rpfilter.c
net/ipv4/tcp.c
net/ipv4/tcp_input.c
net/ipv4/tcp_ipv4.c
net/ipv4/tcp_output.c
net/ipv4/tcp_recovery.c
net/ipv4/tcp_timer.c
net/ipv4/udp.c
net/ipv4/udp_offload.c
net/ipv6/addrconf.c
net/ipv6/udp_offload.c
net/key/af_key.c
net/lapb/lapb_iface.c
net/lapb/lapb_out.c
net/lapb/lapb_timer.c
net/mac80211/debugfs.c
net/mac80211/driver-ops.c
net/mac80211/ieee80211_i.h
net/mac80211/iface.c
net/mac80211/rate.c
net/mac80211/rx.c
net/mac80211/spectmgmt.c
net/mac80211/tx.c
net/netfilter/nf_tables_api.c
net/netfilter/nft_dynset.c
net/nfc/nci/core.c
net/nfc/netlink.c
net/nfc/rawsock.c
net/rds/rdma.c
net/rxrpc/af_rxrpc.c
net/rxrpc/call_accept.c
net/sched/cls_flower.c
net/sched/cls_tcindex.c
net/sched/sch_api.c
net/sunrpc/auth_gss/auth_gss.c
net/sunrpc/auth_gss/auth_gss_internal.h [new file with mode: 0644]
net/sunrpc/auth_gss/gss_krb5_mech.c
net/sunrpc/svc_xprt.c
net/sunrpc/svcsock.c
net/switchdev/switchdev.c
net/vmw_vsock/af_vsock.c
net/wireless/reg.c
net/wireless/wext-core.c
net/xdp/xsk.c
net/xfrm/xfrm_input.c
net/xfrm/xfrm_policy.c
scripts/Makefile
scripts/bloat-o-meter
scripts/checkpatch.pl
scripts/clang-tools/gen_compile_commands.py
scripts/clang-tools/run-clang-tools.py
scripts/diffconfig
scripts/dummy-tools/gcc
scripts/jobserver-exec
scripts/kallsyms.c
scripts/kconfig/mconf-cfg.sh
security/commoncap.c
sound/core/pcm_dmaengine.c
sound/soc/Kconfig
sound/soc/Makefile
sound/soc/adi/axi-i2s.c
sound/soc/amd/acp3x-rt5682-max9836.c
sound/soc/atmel/atmel-i2s.c
sound/soc/atmel/atmel-pcm-pdc.c
sound/soc/atmel/mchp-i2s-mcc.c
sound/soc/au1x/i2sc.c
sound/soc/bcm/bcm2835-i2s.c
sound/soc/bcm/bcm63xx-i2s-whistler.c
sound/soc/bcm/cygnus-pcm.c
sound/soc/cirrus/ep93xx-i2s.c
sound/soc/codecs/Kconfig
sound/soc/codecs/Makefile
sound/soc/codecs/ab8500-codec.c
sound/soc/codecs/adau1372.c
sound/soc/codecs/adau1373.c
sound/soc/codecs/adau1701.c
sound/soc/codecs/adau17x1.c
sound/soc/codecs/ak4554.c
sound/soc/codecs/ak4613.c
sound/soc/codecs/ak4641.c
sound/soc/codecs/ak4642.c
sound/soc/codecs/alc5632.c
sound/soc/codecs/cpcap.c
sound/soc/codecs/cros_ec_codec.c
sound/soc/codecs/cs35l32.c
sound/soc/codecs/cs35l33.c
sound/soc/codecs/cs35l34.c
sound/soc/codecs/cs35l35.c
sound/soc/codecs/cs35l36.c
sound/soc/codecs/cs4234.c
sound/soc/codecs/cs4271.c
sound/soc/codecs/cs42l56.c
sound/soc/codecs/cs42l73.c
sound/soc/codecs/cs43130.c
sound/soc/codecs/cs4341.c
sound/soc/codecs/cs4349.c
sound/soc/codecs/cs47l15.c
sound/soc/codecs/cs47l24.c
sound/soc/codecs/cs47l35.c
sound/soc/codecs/cs47l85.c
sound/soc/codecs/cs47l90.c
sound/soc/codecs/cs47l92.c
sound/soc/codecs/cs53l30.c
sound/soc/codecs/cx2072x.c
sound/soc/codecs/da7210.c
sound/soc/codecs/da7213.c
sound/soc/codecs/da7218.c
sound/soc/codecs/da7219.c
sound/soc/codecs/da9055.c
sound/soc/codecs/es8316.c
sound/soc/codecs/es8328.c
sound/soc/codecs/hdmi-codec.c
sound/soc/codecs/inno_rk3036.c
sound/soc/codecs/jz4740.c
sound/soc/codecs/jz4760.c [new file with mode: 0644]
sound/soc/codecs/lm49453.c
sound/soc/codecs/lochnagar-sc.c
sound/soc/codecs/lpass-rx-macro.c [new file with mode: 0644]
sound/soc/codecs/lpass-tx-macro.c [new file with mode: 0644]
sound/soc/codecs/lpass-wsa-macro.c
sound/soc/codecs/max98373-sdw.c
sound/soc/codecs/max98373.c
sound/soc/codecs/max9860.c
sound/soc/codecs/max9867.c
sound/soc/codecs/mc13783.c
sound/soc/codecs/ml26124.c
sound/soc/codecs/mt6359.c
sound/soc/codecs/mt6660.c
sound/soc/codecs/nau8810.c
sound/soc/codecs/nau8822.c
sound/soc/codecs/rt1015.c
sound/soc/codecs/rt1015.h
sound/soc/codecs/rt1308-sdw.c
sound/soc/codecs/rt274.c
sound/soc/codecs/rt286.c
sound/soc/codecs/rt298.c
sound/soc/codecs/rt5645.c
sound/soc/codecs/rt5670.c
sound/soc/codecs/rt5682-i2c.c
sound/soc/codecs/rt5682-sdw.c
sound/soc/codecs/rt5682.c
sound/soc/codecs/rt5682.h
sound/soc/codecs/rt700-sdw.c
sound/soc/codecs/rt711-sdw.c
sound/soc/codecs/rt715-sdw.c
sound/soc/codecs/sgtl5000.c
sound/soc/codecs/sirf-audio-codec.c [deleted file]
sound/soc/codecs/ssm2602.c
sound/soc/codecs/tas2764.c
sound/soc/codecs/tas2770.c
sound/soc/codecs/tlv320adcx140.c
sound/soc/codecs/tlv320aic31xx.c
sound/soc/codecs/tlv320aic32x4.c
sound/soc/codecs/tlv320aic3x.c
sound/soc/codecs/tscs42xx.c
sound/soc/codecs/tscs454.c
sound/soc/codecs/wm5102.c
sound/soc/codecs/wm5110.c
sound/soc/codecs/wm8510.c
sound/soc/codecs/wm8731.c
sound/soc/codecs/wm8770.c
sound/soc/codecs/wm8804.c
sound/soc/codecs/wm8903.c
sound/soc/codecs/wm8904.c
sound/soc/codecs/wm8940.c
sound/soc/codecs/wm8960.c
sound/soc/codecs/wm8962.c
sound/soc/codecs/wm8974.c
sound/soc/codecs/wm8978.c
sound/soc/codecs/wm8983.c
sound/soc/codecs/wm8985.c
sound/soc/codecs/wm8988.c
sound/soc/codecs/wm8993.c
sound/soc/codecs/wm8994.c
sound/soc/codecs/wm8997.c
sound/soc/codecs/wm8998.c
sound/soc/codecs/wm9713.c
sound/soc/codecs/wm_adsp.c
sound/soc/codecs/wmfw.h
sound/soc/codecs/wsa881x.c
sound/soc/codecs/zl38060.c
sound/soc/codecs/zx_aud96p22.c [deleted file]
sound/soc/fsl/Kconfig
sound/soc/fsl/fsl_asrc.c
sound/soc/fsl/fsl_easrc.c
sound/soc/fsl/fsl_esai.c
sound/soc/fsl/fsl_micfil.c
sound/soc/fsl/fsl_sai.c
sound/soc/fsl/fsl_spdif.c
sound/soc/fsl/fsl_ssi.c
sound/soc/fsl/fsl_xcvr.c
sound/soc/generic/audio-graph-card.c
sound/soc/generic/simple-card-utils.c
sound/soc/intel/Kconfig
sound/soc/intel/boards/Kconfig
sound/soc/intel/boards/Makefile
sound/soc/intel/boards/bytcht_es8316.c
sound/soc/intel/boards/bytcr_rt5640.c
sound/soc/intel/boards/bytcr_rt5651.c
sound/soc/intel/boards/bytcr_wm5102.c [new file with mode: 0644]
sound/soc/intel/boards/cht_bsw_nau8824.c
sound/soc/intel/boards/sof_maxim_common.c
sound/soc/intel/boards/sof_rt5682.c
sound/soc/intel/boards/sof_sdw.c
sound/soc/intel/catpt/pcm.c
sound/soc/intel/common/soc-acpi-intel-adl-match.c
sound/soc/intel/common/soc-acpi-intel-bxt-match.c
sound/soc/intel/common/soc-acpi-intel-byt-match.c
sound/soc/intel/common/soc-acpi-intel-cfl-match.c
sound/soc/intel/common/soc-acpi-intel-cht-match.c
sound/soc/intel/common/soc-acpi-intel-cml-match.c
sound/soc/intel/common/soc-acpi-intel-cnl-match.c
sound/soc/intel/common/soc-acpi-intel-ehl-match.c
sound/soc/intel/common/soc-acpi-intel-glk-match.c
sound/soc/intel/common/soc-acpi-intel-hsw-bdw-match.c
sound/soc/intel/common/soc-acpi-intel-icl-match.c
sound/soc/intel/common/soc-acpi-intel-jsl-match.c
sound/soc/intel/common/soc-acpi-intel-kbl-match.c
sound/soc/intel/common/soc-acpi-intel-skl-match.c
sound/soc/intel/common/soc-acpi-intel-tgl-match.c
sound/soc/intel/common/soc-intel-quirks.h
sound/soc/intel/keembay/kmb_platform.c
sound/soc/intel/keembay/kmb_platform.h
sound/soc/intel/skylake/skl.c
sound/soc/jz4740/jz4740-i2s.c
sound/soc/kirkwood/kirkwood-dma.c
sound/soc/mediatek/Kconfig
sound/soc/mediatek/mt2701/mt2701-afe-pcm.c
sound/soc/mediatek/mt6797/mt6797-dai-pcm.c
sound/soc/mediatek/mt8173/mt8173-afe-pcm.c
sound/soc/mediatek/mt8183/mt8183-da7219-max98357.c
sound/soc/mediatek/mt8183/mt8183-dai-pcm.c
sound/soc/mediatek/mt8183/mt8183-mt6358-ts3a227-max98357.c
sound/soc/mediatek/mt8192/mt8192-afe-pcm.c
sound/soc/mediatek/mt8192/mt8192-dai-pcm.c
sound/soc/mediatek/mt8192/mt8192-dai-tdm.c
sound/soc/mediatek/mt8192/mt8192-mt6359-rt1015-rt5682.c
sound/soc/meson/aiu-fifo-i2s.c
sound/soc/meson/aiu-fifo-spdif.c
sound/soc/meson/aiu-fifo.c
sound/soc/pxa/pxa2xx-i2s.c
sound/soc/qcom/lpass-apq8016.c
sound/soc/qcom/lpass-cpu.c
sound/soc/qcom/lpass-lpaif-reg.h
sound/soc/qcom/lpass-sc7180.c
sound/soc/qcom/lpass.h
sound/soc/qcom/qdsp6/q6asm-dai.c
sound/soc/qcom/qdsp6/q6asm.c
sound/soc/qcom/qdsp6/q6routing.c
sound/soc/rockchip/rockchip_i2s.c
sound/soc/rockchip/rockchip_pdm.c
sound/soc/samsung/i2s.c
sound/soc/samsung/pcm.c
sound/soc/sh/rcar/core.c
sound/soc/sh/siu.h
sound/soc/sh/siu_pcm.c
sound/soc/sirf/Kconfig [deleted file]
sound/soc/sirf/Makefile [deleted file]
sound/soc/sirf/sirf-audio-port.c [deleted file]
sound/soc/sirf/sirf-audio.c [deleted file]
sound/soc/sirf/sirf-usp.c [deleted file]
sound/soc/sirf/sirf-usp.h [deleted file]
sound/soc/soc-component.c
sound/soc/soc-dapm.c
sound/soc/soc-pcm.c
sound/soc/soc-topology-test.c [new file with mode: 0644]
sound/soc/soc-topology.c
sound/soc/sof/core.c
sound/soc/sof/debug.c
sound/soc/sof/intel/hda-compress.c
sound/soc/sof/intel/hda-dsp.c
sound/soc/sof/intel/hda-loader.c
sound/soc/sof/intel/hda-pcm.c
sound/soc/sof/intel/hda-stream.c
sound/soc/sof/intel/hda-trace.c
sound/soc/sof/intel/hda.c
sound/soc/sof/intel/hda.h
sound/soc/sof/intel/tgl.c
sound/soc/sof/ipc.c
sound/soc/sof/loader.c
sound/soc/sof/ops.h
sound/soc/sof/pcm.c
sound/soc/sof/pm.c
sound/soc/sof/sof-pci-dev.c
sound/soc/sof/sof-priv.h
sound/soc/sof/topology.c
sound/soc/sprd/sprd-mcdt.c
sound/soc/stm/stm32_i2s.c
sound/soc/sunxi/sun4i-i2s.c
sound/soc/sunxi/sun8i-codec.c
sound/soc/tegra/Kconfig
sound/soc/tegra/Makefile
sound/soc/tegra/tegra186_dspk.c
sound/soc/tegra/tegra20_i2s.c
sound/soc/tegra/tegra210_dmic.c
sound/soc/tegra/tegra210_i2s.c
sound/soc/tegra/tegra30_ahub.c
sound/soc/tegra/tegra30_ahub.h
sound/soc/tegra/tegra30_i2s.c
sound/soc/tegra/tegra_audio_graph_card.c [new file with mode: 0644]
sound/soc/tegra/tegra_pcm.c
sound/soc/ti/davinci-mcasp.c
sound/soc/txx9/Kconfig [deleted file]
sound/soc/txx9/Makefile [deleted file]
sound/soc/txx9/txx9aclc-ac97.c [deleted file]
sound/soc/txx9/txx9aclc-generic.c [deleted file]
sound/soc/txx9/txx9aclc.c [deleted file]
sound/soc/txx9/txx9aclc.h [deleted file]
sound/soc/zte/Kconfig [deleted file]
sound/soc/zte/Makefile [deleted file]
sound/soc/zte/zx-i2s.c [deleted file]
sound/soc/zte/zx-spdif.c [deleted file]
sound/soc/zte/zx-tdm.c [deleted file]
tools/gpio/gpio-event-mon.c
tools/gpio/gpio-watch.c
tools/lib/bpf/btf.c
tools/lib/perf/evlist.c
tools/objtool/check.c
tools/objtool/elf.c
tools/perf/builtin-script.c
tools/perf/util/metricgroup.c
tools/power/x86/intel-speed-select/isst-config.c
tools/power/x86/turbostat/turbostat.c
tools/testing/kunit/kunit.py
tools/testing/kunit/kunit_config.py
tools/testing/kunit/kunit_json.py
tools/testing/kunit/kunit_kernel.py
tools/testing/kunit/kunit_parser.py
tools/testing/nvdimm/config_check.c
tools/testing/nvdimm/test/Kbuild
tools/testing/nvdimm/test/ndtest.c [new file with mode: 0644]
tools/testing/nvdimm/test/ndtest.h [new file with mode: 0644]
tools/testing/selftests/bpf/prog_tests/test_local_storage.c
tools/testing/selftests/bpf/progs/local_storage.c
tools/testing/selftests/bpf/test_verifier.c
tools/testing/selftests/bpf/verifier/spill_fill.c
tools/testing/selftests/dma/dma_map_benchmark.c
tools/testing/selftests/net/fib_tests.sh
tools/testing/selftests/net/forwarding/router_mpath_nh.sh
tools/testing/selftests/net/forwarding/router_multipath.sh
tools/testing/selftests/net/xfrm_policy.sh
tools/testing/selftests/powerpc/alignment/alignment_handler.c
tools/testing/selftests/powerpc/mm/pkey_exec_prot.c
tools/testing/selftests/powerpc/mm/pkey_siginfo.c
tools/testing/selftests/syscall_user_dispatch/sud_benchmark.c
tools/testing/selftests/syscall_user_dispatch/sud_test.c
virt/kvm/kvm_main.c

index 10dc5a9..01a341c 100644 (file)
@@ -122,6 +122,7 @@ ForEachMacros:
   - 'drm_for_each_bridge_in_chain'
   - 'drm_for_each_connector_iter'
   - 'drm_for_each_crtc'
+  - 'drm_for_each_crtc_reverse'
   - 'drm_for_each_encoder'
   - 'drm_for_each_encoder_mask'
   - 'drm_for_each_fb'
@@ -203,14 +204,13 @@ ForEachMacros:
   - 'for_each_matching_node'
   - 'for_each_matching_node_and_match'
   - 'for_each_member'
-  - 'for_each_mem_region'
-  - 'for_each_memblock_type'
   - 'for_each_memcg_cache_index'
   - 'for_each_mem_pfn_range'
   - '__for_each_mem_range'
   - 'for_each_mem_range'
   - '__for_each_mem_range_rev'
   - 'for_each_mem_range_rev'
+  - 'for_each_mem_region'
   - 'for_each_migratetype_order'
   - 'for_each_msi_entry'
   - 'for_each_msi_entry_safe'
@@ -276,10 +276,8 @@ ForEachMacros:
   - 'for_each_reserved_mem_range'
   - 'for_each_reserved_mem_region'
   - 'for_each_rtd_codec_dais'
-  - 'for_each_rtd_codec_dais_rollback'
   - 'for_each_rtd_components'
   - 'for_each_rtd_cpu_dais'
-  - 'for_each_rtd_cpu_dais_rollback'
   - 'for_each_rtd_dais'
   - 'for_each_set_bit'
   - 'for_each_set_bit_from'
@@ -298,6 +296,7 @@ ForEachMacros:
   - '__for_each_thread'
   - 'for_each_thread'
   - 'for_each_unicast_dest_pgid'
+  - 'for_each_vsi'
   - 'for_each_wakeup_source'
   - 'for_each_zone'
   - 'for_each_zone_zonelist'
@@ -330,6 +329,7 @@ ForEachMacros:
   - 'hlist_for_each_entry_rcu_bh'
   - 'hlist_for_each_entry_rcu_notrace'
   - 'hlist_for_each_entry_safe'
+  - 'hlist_for_each_entry_srcu'
   - '__hlist_for_each_rcu'
   - 'hlist_for_each_safe'
   - 'hlist_nulls_for_each_entry'
@@ -378,6 +378,7 @@ ForEachMacros:
   - 'list_for_each_entry_safe_continue'
   - 'list_for_each_entry_safe_from'
   - 'list_for_each_entry_safe_reverse'
+  - 'list_for_each_entry_srcu'
   - 'list_for_each_prev'
   - 'list_for_each_prev_safe'
   - 'list_for_each_safe'
@@ -411,6 +412,8 @@ ForEachMacros:
   - 'of_property_for_each_string'
   - 'of_property_for_each_u32'
   - 'pci_bus_for_each_resource'
+  - 'pcl_for_each_chunk'
+  - 'pcl_for_each_segment'
   - 'pcm_for_each_format'
   - 'ping_portaddr_for_each_entry'
   - 'plist_for_each'
index 632700c..d674968 100644 (file)
--- a/.mailmap
+++ b/.mailmap
@@ -9,9 +9,6 @@
 #
 # Please keep this list dictionary sorted.
 #
-# This comment is parsed by git-shortlog:
-# repo-abbrev: /pub/scm/linux/kernel/git/
-#
 Aaron Durbin <adurbin@google.com>
 Adam Oldham <oldhamca@gmail.com>
 Adam Radford <aradford@gmail.com>
@@ -55,6 +52,8 @@ Bart Van Assche <bvanassche@acm.org> <bart.vanassche@wdc.com>
 Ben Gardner <bgardner@wabtec.com>
 Ben M Cahill <ben.m.cahill@intel.com>
 Björn Steinbrink <B.Steinbrink@gmx.de>
+Björn Töpel <bjorn@kernel.org> <bjorn.topel@gmail.com>
+Björn Töpel <bjorn@kernel.org> <bjorn.topel@intel.com>
 Boris Brezillon <bbrezillon@kernel.org> <b.brezillon.dev@gmail.com>
 Boris Brezillon <bbrezillon@kernel.org> <b.brezillon@overkiz.com>
 Boris Brezillon <bbrezillon@kernel.org> <boris.brezillon@bootlin.com>
@@ -180,6 +179,8 @@ Kees Cook <keescook@chromium.org> <kees.cook@canonical.com>
 Kees Cook <keescook@chromium.org> <keescook@google.com>
 Kees Cook <keescook@chromium.org> <kees@outflux.net>
 Kees Cook <keescook@chromium.org> <kees@ubuntu.com>
+Keith Busch <kbusch@kernel.org> <keith.busch@intel.com>
+Keith Busch <kbusch@kernel.org> <keith.busch@linux.intel.com>
 Kenneth W Chen <kenneth.w.chen@intel.com>
 Konstantin Khlebnikov <koct9i@gmail.com> <khlebnikov@yandex-team.ru>
 Konstantin Khlebnikov <koct9i@gmail.com> <k.khlebnikov@samsung.com>
@@ -200,6 +201,8 @@ Li Yang <leoyang.li@nxp.com> <leoli@freescale.com>
 Li Yang <leoyang.li@nxp.com> <leo@zh-kernel.org>
 Lukasz Luba <lukasz.luba@arm.com> <l.luba@partner.samsung.com>
 Maciej W. Rozycki <macro@mips.com> <macro@imgtec.com>
+Manivannan Sadhasivam <mani@kernel.org> <manivannanece23@gmail.com>
+Manivannan Sadhasivam <mani@kernel.org> <manivannan.sadhasivam@linaro.org>
 Marcin Nowakowski <marcin.nowakowski@mips.com> <marcin.nowakowski@imgtec.com>
 Marc Zyngier <maz@kernel.org> <marc.zyngier@arm.com>
 Mark Brown <broonie@sirena.org.uk>
@@ -245,6 +248,7 @@ Morten Welinder <welinder@anemone.rentec.com>
 Morten Welinder <welinder@darter.rentec.com>
 Morten Welinder <welinder@troll.com>
 Mythri P K <mythripk@ti.com>
+Nathan Chancellor <nathan@kernel.org> <natechancellor@gmail.com>
 Nguyen Anh Quynh <aquynh@gmail.com>
 Nicolas Ferre <nicolas.ferre@microchip.com> <nicolas.ferre@atmel.com>
 Nicolas Pitre <nico@fluxnic.net> <nicolas.pitre@linaro.org>
@@ -335,6 +339,8 @@ Vinod Koul <vkoul@kernel.org> <vkoul@infradead.org>
 Viresh Kumar <vireshk@kernel.org> <viresh.kumar2@arm.com>
 Viresh Kumar <vireshk@kernel.org> <viresh.kumar@st.com>
 Viresh Kumar <vireshk@kernel.org> <viresh.linux@gmail.com>
+Viresh Kumar <viresh.kumar@linaro.org> <viresh.kumar@linaro.org>
+Viresh Kumar <viresh.kumar@linaro.org> <viresh.kumar@linaro.com>
 Vivien Didelot <vivien.didelot@gmail.com> <vivien.didelot@savoirfairelinux.com>
 Vlad Dogaru <ddvlad@gmail.com> <vlad.dogaru@intel.com>
 Vladimir Davydov <vdavydov.dev@gmail.com> <vdavydov@parallels.com>
index b662f74..8a21ce5 100644 (file)
@@ -5,8 +5,8 @@ Description:
                Provide a place in sysfs for the device link objects in the
                kernel at any given time.  The name of a device link directory,
                denoted as ... above, is of the form <supplier>--<consumer>
-               where <supplier> is the supplier device name and <consumer> is
-               the consumer device name.
+               where <supplier> is the supplier bus:device name and <consumer>
+               is the consumer bus:device name.
 
 What:          /sys/class/devlink/.../auto_remove_on
 Date:          May 2020
index 1f06d74..0809fda 100644 (file)
@@ -4,5 +4,6 @@ Contact:        Saravana Kannan <saravanak@google.com>
 Description:
                The /sys/devices/.../consumer:<consumer> are symlinks to device
                links where this device is the supplier. <consumer> denotes the
-               name of the consumer in that device link. There can be zero or
-               more of these symlinks for a given device.
+               name of the consumer in that device link and is of the form
+               bus:device name. There can be zero or more of these symlinks
+               for a given device.
index a919e0d..207f597 100644 (file)
@@ -4,5 +4,6 @@ Contact:        Saravana Kannan <saravanak@google.com>
 Description:
                The /sys/devices/.../supplier:<supplier> are symlinks to device
                links where this device is the consumer. <supplier> denotes the
-               name of the supplier in that device link. There can be zero or
-               more of these symlinks for a given device.
+               name of the supplier in that device link and is of the form
+               bus:device name. There can be zero or more of these symlinks
+               for a given device.
index adc0d0e..75ccc5c 100644 (file)
@@ -916,21 +916,25 @@ Date:             September 2014
 Contact:       Subhash Jadavani <subhashj@codeaurora.org>
 Description:   This entry could be used to set or show the UFS device
                runtime power management level. The current driver
-               implementation supports 6 levels with next target states:
+               implementation supports 7 levels with next target states:
 
                ==  ====================================================
-               0   an UFS device will stay active, an UIC link will
+               0   UFS device will stay active, UIC link will
                    stay active
-               1   an UFS device will stay active, an UIC link will
+               1   UFS device will stay active, UIC link will
                    hibernate
-               2   an UFS device will moved to sleep, an UIC link will
+               2   UFS device will be moved to sleep, UIC link will
                    stay active
-               3   an UFS device will moved to sleep, an UIC link will
+               3   UFS device will be moved to sleep, UIC link will
                    hibernate
-               4   an UFS device will be powered off, an UIC link will
+               4   UFS device will be powered off, UIC link will
                    hibernate
-               5   an UFS device will be powered off, an UIC link will
+               5   UFS device will be powered off, UIC link will
                    be powered off
+               6   UFS device will be moved to deep sleep, UIC link
+                   will be powered off. Note, deep sleep might not be
+                   supported in which case this value will not be
+                   accepted
                ==  ====================================================
 
 What:          /sys/bus/platform/drivers/ufshcd/*/rpm_target_dev_state
@@ -954,21 +958,25 @@ Date:             September 2014
 Contact:       Subhash Jadavani <subhashj@codeaurora.org>
 Description:   This entry could be used to set or show the UFS device
                system power management level. The current driver
-               implementation supports 6 levels with next target states:
+               implementation supports 7 levels with next target states:
 
                ==  ====================================================
-               0   an UFS device will stay active, an UIC link will
+               0   UFS device will stay active, UIC link will
                    stay active
-               1   an UFS device will stay active, an UIC link will
+               1   UFS device will stay active, UIC link will
                    hibernate
-               2   an UFS device will moved to sleep, an UIC link will
+               2   UFS device will be moved to sleep, UIC link will
                    stay active
-               3   an UFS device will moved to sleep, an UIC link will
+               3   UFS device will be moved to sleep, UIC link will
                    hibernate
-               4   an UFS device will be powered off, an UIC link will
+               4   UFS device will be powered off, UIC link will
                    hibernate
-               5   an UFS device will be powered off, an UIC link will
+               5   UFS device will be powered off, UIC link will
                    be powered off
+               6   UFS device will be moved to deep sleep, UIC link
+                   will be powered off. Note, deep sleep might not be
+                   supported in which case this value will not be
+                   accepted
                ==  ====================================================
 
 What:          /sys/bus/platform/drivers/ufshcd/*/spm_target_dev_state
index 61a7310..9c42dde 100644 (file)
@@ -75,7 +75,7 @@ quiet_cmd_sphinx = SPHINX  $@ --> file://$(abspath $(BUILDDIR)/$3/$4)
       cmd_sphinx = $(MAKE) BUILDDIR=$(abspath $(BUILDDIR)) $(build)=Documentation/userspace-api/media $2 && \
        PYTHONDONTWRITEBYTECODE=1 \
        BUILDDIR=$(abspath $(BUILDDIR)) SPHINX_CONF=$(abspath $(srctree)/$(src)/$5/$(SPHINX_CONF)) \
-       $(PYTHON) $(srctree)/scripts/jobserver-exec \
+       $(PYTHON3) $(srctree)/scripts/jobserver-exec \
        $(SHELL) $(srctree)/Documentation/sphinx/parallel-wrapper.sh \
        $(SPHINXBUILD) \
        -b $2 \
index 4e6f504..2cc5488 100644 (file)
@@ -177,14 +177,20 @@ bitmap_flush_interval:number
        The bitmap flush interval in milliseconds. The metadata buffers
        are synchronized when this interval expires.
 
+allow_discards
+       Allow block discard requests (a.k.a. TRIM) for the integrity device.
+       Discards are only allowed to devices using internal hash.
+
 fix_padding
        Use a smaller padding of the tag area that is more
        space-efficient. If this option is not present, large padding is
        used - that is for compatibility with older kernels.
 
-allow_discards
-       Allow block discard requests (a.k.a. TRIM) for the integrity device.
-       Discards are only allowed to devices using internal hash.
+legacy_recalculate
+       Allow recalculating of volumes with HMAC keys. This is disabled by
+       default for security reasons - an attacker could modify the volume,
+       set recalc_sector to zero, and the kernel would not detect the
+       modification.
 
 The journal mode (D/J), buffer_sectors, journal_watermark, commit_time and
 allow_discards can be changed when reloading the target (load an inactive
index 2267e4f..ccf4187 100644 (file)
@@ -13,6 +13,22 @@ This file documents the driver for the Rockchip ISP1 that is part of RK3288
 and RK3399 SoCs. The driver is located under drivers/staging/media/rkisp1
 and uses the Media-Controller API.
 
+Revisions
+=========
+
+There exist multiple smaller revisions to this ISP that got introduced in
+later SoCs. Revisions can be found in the enum :c:type:`rkisp1_cif_isp_version`
+in the UAPI and the revision of the ISP inside the running SoC can be read
+in the field hw_revision of struct media_device_info as returned by
+ioctl MEDIA_IOC_DEVICE_INFO.
+
+Versions in use are:
+
+- RKISP1_V10: used at least in rk3288 and rk3399
+- RKISP1_V11: declared in the original vendor code, but not used
+- RKISP1_V12: used at least in rk3326 and px30
+- RKISP1_V13: used at least in rk1808
+
 Topology
 ========
 .. _rkisp1_topology_graph:
index a380d65..6031495 100644 (file)
@@ -70,8 +70,8 @@ trampoline code on the vDSO, that trampoline is never intercepted.
 [selector] is a pointer to a char-sized region in the process memory
 region, that provides a quick way to enable disable syscall redirection
 thread-wide, without the need to invoke the kernel directly.  selector
-can be set to PR_SYS_DISPATCH_ON or PR_SYS_DISPATCH_OFF.  Any other
-value should terminate the program with a SIGSYS.
+can be set to SYSCALL_DISPATCH_FILTER_ALLOW or SYSCALL_DISPATCH_FILTER_BLOCK.
+Any other value should terminate the program with a SIGSYS.
 
 Security Notes
 --------------
index 32ea574..76424e0 100644 (file)
@@ -100,6 +100,11 @@ Instruction Macros
 ~~~~~~~~~~~~~~~~~~
 This section covers ``SYM_FUNC_*`` and ``SYM_CODE_*`` enumerated above.
 
+``objtool`` requires that all code must be contained in an ELF symbol. Symbol
+names that have a ``.L`` prefix do not emit symbol table entries. ``.L``
+prefixed symbols can be used within a code region, but should be avoided for
+denoting a range of code via ``SYM_*_START/END`` annotations.
+
 * ``SYM_FUNC_START`` and ``SYM_FUNC_START_LOCAL`` are supposed to be **the
   most frequent markings**. They are used for functions with standard calling
   conventions -- global and local. Like in C, they both align the functions to
index 0fc3fb1..1651d96 100644 (file)
@@ -160,29 +160,14 @@ intended for use in production as a security mitigation. Therefore it supports
 boot parameters that allow to disable KASAN competely or otherwise control
 particular KASAN features.
 
-The things that can be controlled are:
+- ``kasan=off`` or ``=on`` controls whether KASAN is enabled (default: ``on``).
 
-1. Whether KASAN is enabled at all.
-2. Whether KASAN collects and saves alloc/free stacks.
-3. Whether KASAN panics on a detected bug or not.
+- ``kasan.stacktrace=off`` or ``=on`` disables or enables alloc and free stack
+  traces collection (default: ``on`` for ``CONFIG_DEBUG_KERNEL=y``, otherwise
+  ``off``).
 
-The ``kasan.mode`` boot parameter allows to choose one of three main modes:
-
-- ``kasan.mode=off`` - KASAN is disabled, no tag checks are performed
-- ``kasan.mode=prod`` - only essential production features are enabled
-- ``kasan.mode=full`` - all KASAN features are enabled
-
-The chosen mode provides default control values for the features mentioned
-above. However it's also possible to override the default values by providing:
-
-- ``kasan.stacktrace=off`` or ``=on`` - enable alloc/free stack collection
-                                       (default: ``on`` for ``mode=full``,
-                                        otherwise ``off``)
-- ``kasan.fault=report`` or ``=panic`` - only print KASAN report or also panic
-                                        (default: ``report``)
-
-If ``kasan.mode`` parameter is not provided, it defaults to ``full`` when
-``CONFIG_DEBUG_KERNEL`` is enabled, and to ``prod`` otherwise.
+- ``kasan.fault=report`` or ``=panic`` controls whether to only print a KASAN
+  report or also panic the kernel (default: ``report``).
 
 For developers
 ~~~~~~~~~~~~~~
index d9fdc14..650f995 100644 (file)
@@ -522,6 +522,63 @@ There's more boilerplate involved, but it can:
   * E.g. if we wanted to also test ``sha256sum``, we could add a ``sha256``
     field and reuse ``cases``.
 
+* be converted to a "parameterized test", see below.
+
+Parameterized Testing
+~~~~~~~~~~~~~~~~~~~~~
+
+The table-driven testing pattern is common enough that KUnit has special
+support for it.
+
+Reusing the same ``cases`` array from above, we can write the test as a
+"parameterized test" with the following.
+
+.. code-block:: c
+
+       // This is copy-pasted from above.
+       struct sha1_test_case {
+               const char *str;
+               const char *sha1;
+       };
+       struct sha1_test_case cases[] = {
+               {
+                       .str = "hello world",
+                       .sha1 = "2aae6c35c94fcfb415dbe95f408b9ce91ee846ed",
+               },
+               {
+                       .str = "hello world!",
+                       .sha1 = "430ce34d020724ed75a196dfc2ad67c77772d169",
+               },
+       };
+
+       // Need a helper function to generate a name for each test case.
+       static void case_to_desc(const struct sha1_test_case *t, char *desc)
+       {
+               strcpy(desc, t->str);
+       }
+       // Creates `sha1_gen_params()` to iterate over `cases`.
+       KUNIT_ARRAY_PARAM(sha1, cases, case_to_desc);
+
+       // Looks no different from a normal test.
+       static void sha1_test(struct kunit *test)
+       {
+               // This function can just contain the body of the for-loop.
+               // The former `cases[i]` is accessible under test->param_value.
+               char out[40];
+               struct sha1_test_case *test_param = (struct sha1_test_case *)(test->param_value);
+
+               sha1sum(test_param->str, out);
+               KUNIT_EXPECT_STREQ_MSG(test, (char *)out, test_param->sha1,
+                                     "sha1sum(%s)", test_param->str);
+       }
+
+       // Instead of KUNIT_CASE, we use KUNIT_CASE_PARAM and pass in the
+       // function declared by KUNIT_ARRAY_PARAM.
+       static struct kunit_case sha1_test_cases[] = {
+               KUNIT_CASE_PARAM(sha1_test, sha1_gen_params),
+               {}
+       };
+
 .. _kunit-on-non-uml:
 
 KUnit on non-UML architectures
index 14cd727..f02fd10 100644 (file)
@@ -232,7 +232,6 @@ properties:
       by this cpu (see ./idle-states.yaml).
 
   capacity-dmips-mhz:
-    $ref: '/schemas/types.yaml#/definitions/uint32'
     description:
       u32 value representing CPU capacity (see ./cpu-capacity.txt) in
       DMIPS/MHz, relative to highest capacity-dmips-mhz
index 02c21b5..3bc760c 100644 (file)
@@ -40,7 +40,7 @@ Optional properties:
        documents on how to describe the way the sii902x device is
        connected to the rest of the audio system:
        Documentation/devicetree/bindings/sound/simple-card.yaml
-       Documentation/devicetree/bindings/sound/audio-graph-card.txt
+       Documentation/devicetree/bindings/sound/audio-graph-card.yaml
        Note: In case of the audio-graph-card binding the used port
        index should be 3.
 
index 33977e1..ed76332 100644 (file)
@@ -23,7 +23,7 @@ connected to.
 
 For a description of the display interface sink function blocks, see
 Documentation/devicetree/bindings/display/mediatek/mediatek,dsi.txt and
-Documentation/devicetree/bindings/display/mediatek/mediatek,dpi.txt.
+Documentation/devicetree/bindings/display/mediatek/mediatek,dpi.yaml.
 
 Required properties (all function blocks):
 - compatible: "mediatek,<chip>-disp-<function>", one of
@@ -61,7 +61,7 @@ Required properties (DMA function blocks):
        "mediatek,<chip>-disp-wdma"
   the supported chips are mt2701, mt8167 and mt8173.
 - larb: Should contain a phandle pointing to the local arbiter device as defined
-  in Documentation/devicetree/bindings/memory-controllers/mediatek,smi-larb.txt
+  in Documentation/devicetree/bindings/memory-controllers/mediatek,smi-larb.yaml
 - iommus: Should point to the respective IOMMU block with master port as
   argument, see Documentation/devicetree/bindings/iommu/mediatek,iommu.txt
   for details.
index 5fe784f..efdf59a 100644 (file)
@@ -85,7 +85,6 @@ properties:
   wlf,micd-timeout-ms:
     description:
       Timeout for microphone detection, specified in milliseconds.
-    $ref: "/schemas/types.yaml#/definitions/uint32"
 
   wlf,micd-force-micbias:
     description:
index eef6149..bf04151 100644 (file)
@@ -49,7 +49,6 @@ properties:
     description:
       This property controls the Accumulation Dead band which allows to set the
       level of current below which no accumulation takes place.
-    $ref: /schemas/types.yaml#/definitions/uint32
     maximum: 255
     default: 0
 
index 00a6511..5d3ce64 100644 (file)
@@ -73,11 +73,9 @@ properties:
     description: |
       Temperature sensor trimming factor. It can be used to manually adjust the
       temperature measurements within 7.130 degrees Celsius.
-    maxItems: 1
-    items:
-      default: 0
-      minimum: 0
-      maximum: 7130
+    default: 0
+    minimum: 0
+    maximum: 7130
 
 additionalProperties: false
 
index 8020d73..1502b22 100644 (file)
@@ -52,7 +52,6 @@ properties:
   ti,bus-range-microvolt:
     description: |
       This is the operating range of the bus voltage in microvolt
-    $ref: /schemas/types.yaml#/definitions/uint32
     enum: [16000000, 32000000]
     default: 32000000
 
index cc3aa2a..ff99344 100644 (file)
@@ -39,11 +39,9 @@ properties:
 
   i2c-gpio,delay-us:
     description: delay between GPIO operations (may depend on each platform)
-    $ref: /schemas/types.yaml#/definitions/uint32
 
   i2c-gpio,timeout-ms:
     description: timeout to get data
-    $ref: /schemas/types.yaml#/definitions/uint32
 
   # Deprecated properties, do not use in new device tree sources:
   gpios:
index c22b66b..d9293c5 100644 (file)
@@ -66,21 +66,18 @@ properties:
     default: 400000
 
   i2c-sda-hold-time-ns:
-    maxItems: 1
     description: |
       The property should contain the SDA hold time in nanoseconds. This option
       is only supported in hardware blocks version 1.11a or newer or on
       Microsemi SoCs.
 
   i2c-scl-falling-time-ns:
-    maxItems: 1
     description: |
       The property should contain the SCL falling time in nanoseconds.
       This value is used to compute the tLOW period.
     default: 300
 
   i2c-sda-falling-time-ns:
-    maxItems: 1
     description: |
       The property should contain the SDA falling time in nanoseconds.
       This value is used to compute the tHIGH period.
index 6eef348..c2efbb8 100644 (file)
@@ -16,8 +16,8 @@ description:
 properties:
   compatible:
     enum:
-      - bosch,bmc150
-      - bosch,bmi055
+      - bosch,bmc150_accel
+      - bosch,bmi055_accel
       - bosch,bma255
       - bosch,bma250e
       - bosch,bma222
index e0cc3b2..22b7ed3 100644 (file)
@@ -80,7 +80,7 @@ properties:
     type: boolean
 
   bipolar:
-    description: see Documentation/devicetree/bindings/iio/adc/adc.txt
+    description: see Documentation/devicetree/bindings/iio/adc/adc.yaml
     type: boolean
 
 required:
index 9475a9e..95774a5 100644 (file)
@@ -23,7 +23,6 @@ properties:
     maxItems: 1
 
   shunt-resistor-micro-ohms:
-    $ref: /schemas/types.yaml#/definitions/uint32
     description: |
       Value in micro Ohms of the shunt resistor connected between the RS+ and
       RS- inputs, across which the current is measured.  Value needed to compute
index 28417b3..517e329 100644 (file)
@@ -246,7 +246,6 @@ patternProperties:
           Resolution (bits) to use for conversions:
             - can be 6, 8, 10 or 12 on stm32f4
             - can be 8, 10, 12, 14 or 16 on stm32h7 and stm32mp1
-        $ref: /schemas/types.yaml#/definitions/uint32
 
       st,adc-channels:
         description: |
index 692dacd..7b89578 100644 (file)
@@ -42,7 +42,6 @@ properties:
     const: 1
 
   ti,channel0-current-microamp:
-    $ref: /schemas/types.yaml#/definitions/uint32
     description: Channel 0 current in uA.
     enum:
       - 0
@@ -51,7 +50,6 @@ properties:
       - 20
 
   ti,channel3-current-microamp:
-    $ref: /schemas/types.yaml#/definitions/uint32
     description: Channel 3 current in uA.
     enum:
       - 0
index 626ccb6..fd4edca 100644 (file)
@@ -46,31 +46,42 @@ properties:
       two properties must be present:
 
   adi,range-microvolt:
-    $ref: /schemas/types.yaml#/definitions/int32-array
     description: |
       Voltage output range specified as <minimum, maximum>
-    enum:
-      - [[0, 5000000]]
-      - [[0, 10000000]]
-      - [[-5000000, 5000000]]
-      - [[-10000000, 10000000]]
+    oneOf:
+      - items:
+          - const: 0
+          - enum: [5000000, 10000000]
+      - items:
+          - const: -5000000
+          - const: 5000000
+      - items:
+          - const: -10000000
+          - const: 10000000
 
   adi,range-microamp:
-    $ref: /schemas/types.yaml#/definitions/int32-array
     description: |
       Current output range specified as <minimum, maximum>
-    enum:
-      - [[0, 20000]]
-      - [[0, 24000]]
-      - [[4, 24000]]
-      - [[-20000, 20000]]
-      - [[-24000, 24000]]
-      - [[-1000, 22000]]
+    oneOf:
+      - items:
+          - const: 0
+          - enum: [20000, 24000]
+      - items:
+          - const: 4
+          - const: 24000
+      - items:
+          - const: -20000
+          - const: 20000
+      - items:
+          - const: -24000
+          - const: 24000
+      - items:
+          - const: -1000
+          - const: 22000
 
   reset-gpios: true
 
   adi,dc-dc-ilim-microamp:
-    $ref: /schemas/types.yaml#/definitions/uint32
     enum: [150000, 200000, 250000, 300000, 350000, 400000]
     description: |
       The dc-to-dc converter current limit.
index 64b8626..967778f 100644 (file)
@@ -21,7 +21,6 @@ properties:
     description: Connected to ADC_RDY pin.
 
   maxim,led-current-microamp:
-    $ref: /schemas/types.yaml#/definitions/uint32-array
     minItems: 2
     maxItems: 2
     description: |
index e551814..6c8be6a 100644 (file)
@@ -5,7 +5,8 @@ Required properties:
  - compatible: "adc-keys"
  - io-channels: Phandle to an ADC channel
  - io-channel-names = "buttons";
- - keyup-threshold-microvolt: Voltage at which all the keys are considered up.
+ - keyup-threshold-microvolt: Voltage above or equal to which all the keys are
+                             considered up.
 
 Optional properties:
        - poll-interval: Poll interval time in milliseconds
@@ -17,7 +18,12 @@ Each button (key) is represented as a sub-node of "adc-keys":
 Required subnode-properties:
        - label: Descriptive name of the key.
        - linux,code: Keycode to emit.
-       - press-threshold-microvolt: Voltage ADC input when this key is pressed.
+       - press-threshold-microvolt: voltage above or equal to which this key is
+                                    considered pressed.
+
+No two values of press-threshold-microvolt may be the same.
+All values of press-threshold-microvolt must be less than
+keyup-threshold-microvolt.
 
 Example:
 
@@ -47,3 +53,15 @@ Example:
                        press-threshold-microvolt = <500000>;
                };
        };
+
++--------------------------------+------------------------+
+| 2.000.000 <= value             | no key pressed         |
++--------------------------------+------------------------+
+| 1.500.000 <= value < 2.000.000 | KEY_VOLUMEUP pressed   |
++--------------------------------+------------------------+
+| 1.000.000 <= value < 1.500.000 | KEY_VOLUMEDOWN pressed |
++--------------------------------+------------------------+
+|   500.000 <= value < 1.000.000 | KEY_ENTER pressed      |
++--------------------------------+------------------------+
+|              value <   500.000 | no key pressed         |
++--------------------------------+------------------------+
index da5b0d8..93f2ce3 100644 (file)
@@ -26,6 +26,7 @@ properties:
       - goodix,gt927
       - goodix,gt9271
       - goodix,gt928
+      - goodix,gt9286
       - goodix,gt967
 
   reg:
index a771a15..046ace4 100644 (file)
@@ -70,11 +70,9 @@ properties:
 
   touchscreen-x-mm:
     description: horizontal length in mm of the touchscreen
-    $ref: /schemas/types.yaml#/definitions/uint32
 
   touchscreen-y-mm:
     description: vertical length in mm of the touchscreen
-    $ref: /schemas/types.yaml#/definitions/uint32
 
 dependencies:
   touchscreen-size-x: [ touchscreen-size-y ]
diff --git a/Documentation/devicetree/bindings/leds/richtek,rt8515.yaml b/Documentation/devicetree/bindings/leds/richtek,rt8515.yaml
new file mode 100644 (file)
index 0000000..68c328e
--- /dev/null
@@ -0,0 +1,111 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/leds/richtek,rt8515.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Richtek RT8515 1.5A dual channel LED driver
+
+maintainers:
+  - Linus Walleij <linus.walleij@linaro.org>
+
+description: |
+  The Richtek RT8515 is a dual channel (two mode) LED driver that
+  supports driving a white LED in flash or torch mode. The maximum
+  current for each mode is defined in hardware using two resistors
+  RFS and RTS.
+
+properties:
+  compatible:
+    const: richtek,rt8515
+
+  enf-gpios:
+    maxItems: 1
+    description: A connection to the 'ENF' (enable flash) pin.
+
+  ent-gpios:
+    maxItems: 1
+    description: A connection to the 'ENT' (enable torch) pin.
+
+  richtek,rfs-ohms:
+    minimum: 7680
+    maximum: 367000
+    description: The resistance value of the RFS resistor. This
+      resistors limits the maximum flash current. This must be set
+      for the property flash-max-microamp to work, the RFS resistor
+      defines the range of the dimmer setting (brightness) of the
+      flash LED.
+
+  richtek,rts-ohms:
+    minimum: 7680
+    maximum: 367000
+    description: The resistance value of the RTS resistor. This
+      resistors limits the maximum torch current. This must be set
+      for the property torch-max-microamp to work, the RTS resistor
+      defines the range of the dimmer setting (brightness) of the
+      torch LED.
+
+  led:
+    type: object
+    $ref: common.yaml#
+    properties:
+      function: true
+      color: true
+      flash-max-timeout-us: true
+
+      flash-max-microamp:
+        maximum: 700000
+        description: The maximum current for flash mode
+          is hardwired to the component using the RFS resistor to
+          ground. The maximum hardware current setting is calculated
+          according to the formula Imax = 5500 / RFS. The lowest
+          allowed resistance value is 7.86 kOhm giving an absolute
+          maximum current of 700mA. By setting this attribute in
+          the device tree, you can further restrict the maximum
+          current below the hardware limit. This requires the RFS
+          to be defined as it defines the maximum range.
+
+      led-max-microamp:
+        maximum: 700000
+        description: The maximum current for torch mode
+          is hardwired to the component using the RTS resistor to
+          ground. The maximum hardware current setting is calculated
+          according to the formula Imax = 5500 / RTS. The lowest
+          allowed resistance value is 7.86 kOhm giving an absolute
+          maximum current of 700mA. By setting this attribute in
+          the device tree, you can further restrict the maximum
+          current below the hardware limit. This requires the RTS
+          to be defined as it defines the maximum range.
+
+    additionalProperties: false
+
+required:
+  - compatible
+  - ent-gpios
+  - enf-gpios
+  - led
+
+additionalProperties: false
+
+examples:
+  - |
+    #include <dt-bindings/gpio/gpio.h>
+    #include <dt-bindings/leds/common.h>
+
+    led-controller {
+        compatible = "richtek,rt8515";
+        enf-gpios = <&gpio4 12 GPIO_ACTIVE_HIGH>;
+        ent-gpios = <&gpio4 13 GPIO_ACTIVE_HIGH>;
+        richtek,rfs-ohms = <16000>;
+        richtek,rts-ohms = <100000>;
+
+        led {
+            function = LED_FUNCTION_FLASH;
+            color = <LED_COLOR_ID_WHITE>;
+            flash-max-timeout-us = <250000>;
+            flash-max-microamp = <150000>;
+            led-max-microamp = <25000>;
+        };
+    };
+
+...
index 044b119..cf60c5a 100644 (file)
@@ -16,7 +16,7 @@ Required properties:
 - power-domains: a phandle to the power domain, see
   Documentation/devicetree/bindings/power/power_domain.txt for details.
 - mediatek,larb: must contain the local arbiters in the current Socs, see
-  Documentation/devicetree/bindings/memory-controllers/mediatek,smi-larb.txt
+  Documentation/devicetree/bindings/memory-controllers/mediatek,smi-larb.yaml
   for details.
 - iommus: should point to the respective IOMMU block with master port as
   argument, see Documentation/devicetree/bindings/iommu/mediatek,iommu.txt
index 736be7c..acfb503 100644 (file)
@@ -14,7 +14,7 @@ Required properties:
 - power-domains: a phandle to the power domain, see
   Documentation/devicetree/bindings/power/power_domain.txt for details.
 - mediatek,larb: must contain the local arbiters in the current SoCs, see
-  Documentation/devicetree/bindings/memory-controllers/mediatek,smi-larb.txt
+  Documentation/devicetree/bindings/memory-controllers/mediatek,smi-larb.yaml
   for details.
 - iommus: should point to the respective IOMMU block with master port as
   argument, see Documentation/devicetree/bindings/iommu/mediatek,iommu.txt
index 0d03e3a..f4798d0 100644 (file)
@@ -28,7 +28,7 @@ Required properties (DMA function blocks, child node):
   argument, see Documentation/devicetree/bindings/iommu/mediatek,iommu.txt
   for details.
 - mediatek,larb: must contain the local arbiters in the current Socs, see
-  Documentation/devicetree/bindings/memory-controllers/mediatek,smi-larb.txt
+  Documentation/devicetree/bindings/memory-controllers/mediatek,smi-larb.yaml
   for details.
 
 Example:
index 186f04b..e674bba 100644 (file)
@@ -259,7 +259,6 @@ properties:
       waiting for I/O signalling and card power supply to be stable,
       regardless of whether pwrseq-simple is used. Default to 10ms if
       no available.
-    $ref: /schemas/types.yaml#/definitions/uint32
     default: 10
 
   supports-cqe:
index 6cd5786..226fb19 100644 (file)
@@ -41,13 +41,11 @@ properties:
     description:
       Delay in ms after powering the card and de-asserting the
       reset-gpios (if any).
-    $ref: /schemas/types.yaml#/definitions/uint32
 
   power-off-delay-us:
     description:
       Delay in us after asserting the reset-gpios (if any)
       during power off of the card.
-    $ref: /schemas/types.yaml#/definitions/uint32
 
 required:
   - compatible
index 0965f65..dac4aad 100644 (file)
@@ -122,7 +122,6 @@ properties:
       such as flow control thresholds.
 
   rx-internal-delay-ps:
-    $ref: /schemas/types.yaml#/definitions/uint32
     description: |
       RGMII Receive Clock Delay defined in pico seconds.
       This is used for controllers that have configurable RX internal delays.
@@ -140,7 +139,6 @@ properties:
       is used for components that can have configurable fifo sizes.
 
   tx-internal-delay-ps:
-    $ref: /schemas/types.yaml#/definitions/uint32
     description: |
       RGMII Transmit Clock Delay defined in pico seconds.
       This is used for controllers that have configurable TX internal delays.
index dfbf5fe..0642b0f 100644 (file)
@@ -212,7 +212,6 @@ properties:
       Triplet of delays. The 1st cell is reset pre-delay in micro
       seconds. The 2nd cell is reset pulse in micro seconds. The 3rd
       cell is reset post-delay in micro seconds.
-    $ref: /schemas/types.yaml#/definitions/uint32-array
     minItems: 3
     maxItems: 3
 
index 0c7e2e4..c3b4b75 100644 (file)
@@ -83,21 +83,18 @@ properties:
       for each of the battery capacity lookup table.
 
   operating-range-celsius:
-    $ref: /schemas/types.yaml#/definitions/uint32-array
     description: operating temperature range of a battery
     items:
       - description: minimum temperature at which battery can operate
       - description: maximum temperature at which battery can operate
 
   ambient-celsius:
-    $ref: /schemas/types.yaml#/definitions/uint32-array
     description: safe range of ambient temperature
     items:
       - description: alert when ambient temperature is lower than this value
       - description: alert when ambient temperature is higher than this value
 
   alert-celsius:
-    $ref: /schemas/types.yaml#/definitions/uint32-array
     description: safe range of battery temperature
     items:
       - description: alert when battery temperature is lower than this value
index 75a5677..813d6af 100644 (file)
@@ -50,7 +50,6 @@ properties:
     maxItems: 1
 
   input-current-limit-microamp:
-    $ref: /schemas/types.yaml#/definitions/uint32
     description: Maximum input current in micro Amps.
     minimum: 50000
     maximum: 500000
index 6f2164f..228018c 100644 (file)
@@ -62,7 +62,6 @@ properties:
     description: IRQ line information.
 
   dlg,irq-polling-delay-passive-ms:
-    $ref: "/schemas/types.yaml#/definitions/uint32"
     minimum: 1000
     maximum: 10000
     description: |
index d3d0dc1..8850c01 100644 (file)
@@ -72,11 +72,9 @@ properties:
 
   startup-delay-us:
     description: startup time in microseconds
-    $ref: /schemas/types.yaml#/definitions/uint32
 
   off-on-delay-us:
     description: off delay time in microseconds
-    $ref: /schemas/types.yaml#/definitions/uint32
 
   enable-active-high:
     description:
index d30dc04..0ec3551 100644 (file)
@@ -27,7 +27,6 @@ properties:
       1: chargeable
 
   quartz-load-femtofarads:
-    $ref: /schemas/types.yaml#/definitions/uint32
     description:
       The capacitive load of the quartz(x-tal), expressed in femto
       Farad (fF). The default value shall be listed (if optional),
@@ -47,7 +46,6 @@ properties:
     deprecated: true
 
   trickle-resistor-ohms:
-    $ref: /schemas/types.yaml#/definitions/uint32
     description:
       Selected resistor for trickle charger. Should be given
       if trickle charger should be enabled.
index c23c93b..07fa6d2 100644 (file)
@@ -88,14 +88,12 @@ properties:
     description:
       Rate at which poll occurs when auto-poll is set.
       default 100ms.
-    $ref: /schemas/types.yaml#/definitions/uint32
     default: 100
 
   poll-timeout-ms:
     description:
       Poll timeout when auto-poll is set, default
       3000ms.
-    $ref: /schemas/types.yaml#/definitions/uint32
     default: 3000
 
 required:
index 2005014..766e910 100644 (file)
@@ -71,9 +71,6 @@ properties:
             description: CPU to Codec rate channels.
             $ref: /schemas/types.yaml#/definitions/uint32
 
-        required:
-          - remote-endpoint
-
   ports:
     description: multi OF-Graph subnode
     type: object
index eb4be86..97d5f38 100644 (file)
@@ -15,9 +15,14 @@ properties:
 
   compatible:
     oneOf:
-      - const: ingenic,jz4770-codec
-      - const: ingenic,jz4725b-codec
-      - const: ingenic,jz4740-codec
+      - enum:
+          - ingenic,jz4770-codec
+          - ingenic,jz4760-codec
+          - ingenic,jz4725b-codec
+          - ingenic,jz4740-codec
+      - items:
+          - const: ingenic,jz4760b-codec
+          - const: ingenic,jz4760-codec
 
   reg:
     maxItems: 1
index d346e61..6f71294 100644 (file)
@@ -18,6 +18,7 @@ properties:
     enum:
       - intel,keembay-i2s
       - intel,keembay-tdm
+      - intel,keembay-hdmi-i2s
 
   "#sound-dai-cells":
     const: 0
@@ -45,6 +46,16 @@ properties:
       - const: osc
       - const: apb_clk
 
+  dmas:
+    items:
+      - description: DMA TX channel
+      - description: DMA RX channel
+
+  dma-names:
+    items:
+      - const: tx
+      - const: rx
+
 required:
   - compatible
   - "#sound-dai-cells"
@@ -70,4 +81,6 @@ examples:
          interrupts = <GIC_SPI 120 IRQ_TYPE_LEVEL_HIGH>;
          clock-names = "osc", "apb_clk";
          clocks = <&scmi_clk KEEM_BAY_PSS_AUX_I2S3>, <&scmi_clk KEEM_BAY_PSS_I2S3>;
+         dmas = <&axi_dma0 29 &axi_dma0 33>;
+         dma-names = "tx", "rx";
      };
index 5465082..5a5b765 100644 (file)
@@ -23,6 +23,10 @@ properties:
     $ref: "/schemas/types.yaml#/definitions/phandle"
     description: The phandle of MT8192 ASoC platform.
 
+  mediatek,hdmi-codec:
+    $ref: "/schemas/types.yaml#/definitions/phandle"
+    description: The phandle of HDMI codec.
+
 additionalProperties: false
 
 required:
@@ -35,6 +39,7 @@ examples:
     sound: mt8192-sound {
         compatible = "mediatek,mt8192_mt6359_rt1015_rt5682";
         mediatek,platform = <&afe>;
+        mediatek,hdmi-codec = <&anx_bridge_dp>;
         pinctrl-names = "aud_clk_mosi_off",
                         "aud_clk_mosi_on";
         pinctrl-0 = <&aud_clk_mosi_off>;
diff --git a/Documentation/devicetree/bindings/sound/nvidia,tegra-audio-graph-card.yaml b/Documentation/devicetree/bindings/sound/nvidia,tegra-audio-graph-card.yaml
new file mode 100644 (file)
index 0000000..2499709
--- /dev/null
@@ -0,0 +1,190 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/sound/nvidia,tegra-audio-graph-card.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Audio Graph based Tegra sound card driver
+
+description: |
+  This is based on generic audio graph card driver along with additional
+  customizations for Tegra platforms. It uses the same bindings with
+  additional standard clock DT bindings required for Tegra.
+
+maintainers:
+  - Jon Hunter <jonathanh@nvidia.com>
+  - Sameer Pujar <spujar@nvidia.com>
+
+allOf:
+  - $ref: audio-graph.yaml#
+
+properties:
+  compatible:
+    enum:
+      - nvidia,tegra210-audio-graph-card
+      - nvidia,tegra186-audio-graph-card
+
+  clocks:
+    minItems: 2
+
+  clock-names:
+    minItems: 2
+    items:
+      - const: pll_a
+      - const: plla_out0
+
+  assigned-clocks:
+    minItems: 1
+    maxItems: 3
+
+  assigned-clock-parents:
+    minItems: 1
+    maxItems: 3
+
+  assigned-clock-rates:
+    minItems: 1
+    maxItems: 3
+
+  iommus:
+    maxItems: 1
+
+required:
+  - clocks
+  - clock-names
+  - assigned-clocks
+  - assigned-clock-parents
+
+unevaluatedProperties: false
+
+examples:
+  - |
+    #include<dt-bindings/clock/tegra210-car.h>
+
+    tegra_sound {
+        compatible = "nvidia,tegra210-audio-graph-card";
+
+        clocks = <&tegra_car TEGRA210_CLK_PLL_A>,
+                 <&tegra_car TEGRA210_CLK_PLL_A_OUT0>;
+        clock-names = "pll_a", "plla_out0";
+
+        assigned-clocks = <&tegra_car TEGRA210_CLK_PLL_A>,
+                          <&tegra_car TEGRA210_CLK_PLL_A_OUT0>,
+                          <&tegra_car TEGRA210_CLK_EXTERN1>;
+        assigned-clock-parents = <0>, <0>, <&tegra_car TEGRA210_CLK_PLL_A_OUT0>;
+        assigned-clock-rates = <368640000>, <49152000>, <12288000>;
+
+        dais = /* FE */
+               <&admaif1_port>,
+               /* Router */
+               <&xbar_i2s1_port>,
+               /* I/O DAP Ports */
+               <&i2s1_port>;
+
+        label = "jetson-tx1-ape";
+    };
+
+    // The ports are defined for AHUB and its child devices.
+    ahub@702d0800 {
+        compatible = "nvidia,tegra210-ahub";
+        reg = <0x702d0800 0x800>;
+        clocks = <&tegra_car TEGRA210_CLK_D_AUDIO>;
+        clock-names = "ahub";
+        assigned-clocks = <&tegra_car TEGRA210_CLK_D_AUDIO>;
+        assigned-clock-parents = <&tegra_car TEGRA210_CLK_PLL_A_OUT0>;
+        #address-cells = <1>;
+        #size-cells = <1>;
+        ranges = <0x702d0000 0x702d0000 0x0000e400>;
+
+        ports {
+            #address-cells = <1>;
+            #size-cells = <0>;
+
+            port@0 {
+                reg = <0x0>;
+                xbar_admaif1_ep: endpoint {
+                    remote-endpoint = <&admaif1_ep>;
+                };
+            };
+
+            // ...
+
+            xbar_i2s1_port: port@a {
+                reg = <0xa>;
+                xbar_i2s1_ep: endpoint {
+                    remote-endpoint = <&i2s1_cif_ep>;
+                };
+            };
+        };
+
+        admaif@702d0000 {
+            compatible = "nvidia,tegra210-admaif";
+            reg = <0x702d0000 0x800>;
+            dmas = <&adma 1>,  <&adma 1>,
+                   <&adma 2>,  <&adma 2>,
+                   <&adma 3>,  <&adma 3>,
+                   <&adma 4>,  <&adma 4>,
+                   <&adma 5>,  <&adma 5>,
+                   <&adma 6>,  <&adma 6>,
+                   <&adma 7>,  <&adma 7>,
+                   <&adma 8>,  <&adma 8>,
+                   <&adma 9>,  <&adma 9>,
+                   <&adma 10>, <&adma 10>;
+            dma-names = "rx1",  "tx1",
+                        "rx2",  "tx2",
+                        "rx3",  "tx3",
+                        "rx4",  "tx4",
+                        "rx5",  "tx5",
+                        "rx6",  "tx6",
+                        "rx7",  "tx7",
+                        "rx8",  "tx8",
+                        "rx9",  "tx9",
+                        "rx10", "tx10";
+
+            ports {
+                #address-cells = <1>;
+                #size-cells = <0>;
+
+                admaif1_port: port@0 {
+                    reg = <0x0>;
+                    admaif1_ep: endpoint {
+                        remote-endpoint = <&xbar_admaif1_ep>;
+                    };
+                };
+
+                // More ADMAIF ports to follow
+            };
+        };
+
+        i2s@702d1000 {
+            compatible = "nvidia,tegra210-i2s";
+            clocks = <&tegra_car TEGRA210_CLK_I2S0>;
+            clock-names = "i2s";
+            assigned-clocks = <&tegra_car TEGRA210_CLK_I2S0>;
+            assigned-clock-parents = <&tegra_car TEGRA210_CLK_PLL_A_OUT0>;
+            assigned-clock-rates = <1536000>;
+            reg = <0x702d1000 0x100>;
+
+            ports {
+                #address-cells = <1>;
+                #size-cells = <0>;
+
+                port@0 {
+                    reg = <0x0>;
+
+                    i2s1_cif_ep: endpoint {
+                        remote-endpoint = <&xbar_i2s1_ep>;
+                    };
+                };
+
+                i2s1_port: port@1 {
+                    reg = <0x1>;
+
+                    i2s1_dap: endpoint {
+                        dai-format = "i2s";
+                    };
+                };
+            };
+        };
+    };
+
+...
index ed2fb32..b8645d9 100644 (file)
@@ -17,6 +17,9 @@ maintainers:
   - Jon Hunter <jonathanh@nvidia.com>
   - Sameer Pujar <spujar@nvidia.com>
 
+allOf:
+  - $ref: audio-graph-port.yaml#
+
 properties:
   $nodename:
     pattern: "^dspk@[0-9a-f]*$"
@@ -55,6 +58,19 @@ properties:
       The name can be "DSPK1" or "DSPKx", where x depends on the maximum
       available instances on a Tegra SoC.
 
+  ports:
+    type: object
+    properties:
+      port@0:
+        description: |
+          DSPK ACIF (Audio Client Interface) port connected to the
+          corresponding AHUB (Audio Hub) ACIF port.
+
+      port@1:
+        description: |
+          DSPK DAP (Digital Audio Port) interface which can be connected
+          to external audio codec for playback.
+
 required:
   - compatible
   - reg
@@ -64,7 +80,7 @@ required:
   - assigned-clock-parents
   - sound-name-prefix
 
-additionalProperties: false
+unevaluatedProperties: false
 
 examples:
   - |
index c028b25..7cee772 100644 (file)
@@ -17,6 +17,9 @@ maintainers:
   - Jon Hunter <jonathanh@nvidia.com>
   - Sameer Pujar <spujar@nvidia.com>
 
+allOf:
+  - $ref: audio-graph-port.yaml#
+
 properties:
   $nodename:
     pattern: "^admaif@[0-9a-f]*$"
@@ -37,6 +40,14 @@ properties:
 
   dma-names: true
 
+  ports:
+    description: |
+      Contains list of ACIF (Audio CIF) port nodes for ADMAIF channels.
+      The number of port nodes depends on the number of ADMAIF channels
+      that SoC may have. These are interfaced with respective ACIF ports
+      in AHUB (Audio Hub). Each port is capable of data transfers in
+      both directions.
+
 if:
   properties:
     compatible:
@@ -81,7 +92,7 @@ required:
   - dmas
   - dma-names
 
-additionalProperties: false
+unevaluatedProperties: false
 
 examples:
   - |
index d772197..31f3e51 100644 (file)
@@ -17,6 +17,9 @@ maintainers:
   - Jon Hunter <jonathanh@nvidia.com>
   - Sameer Pujar <spujar@nvidia.com>
 
+allOf:
+  - $ref: audio-graph-port.yaml#
+
 properties:
   $nodename:
     pattern: "^ahub@[0-9a-f]*$"
@@ -56,6 +59,13 @@ properties:
 
   ranges: true
 
+  ports:
+    description: |
+      Contains list of ACIF (Audio CIF) port nodes for AHUB (Audio Hub).
+      These are connected to ACIF interfaces of AHUB clients. Thus the
+      number of port nodes depend on the number of clients that AHUB may
+      have depending on the SoC revision.
+
 required:
   - compatible
   - reg
@@ -67,8 +77,7 @@ required:
   - "#size-cells"
   - ranges
 
-additionalProperties:
-  type: object
+unevaluatedProperties: false
 
 examples:
   - |
index 2a3207b..89f4f47 100644 (file)
@@ -16,6 +16,9 @@ maintainers:
   - Jon Hunter <jonathanh@nvidia.com>
   - Sameer Pujar <spujar@nvidia.com>
 
+allOf:
+  - $ref: audio-graph-port.yaml#
+
 properties:
   $nodename:
     pattern: "^dmic@[0-9a-f]*$"
@@ -56,6 +59,19 @@ properties:
       The name can be "DMIC1" or "DMIC2" ... "DMICx", where x depends
       on the maximum available instances on a Tegra SoC.
 
+  ports:
+    type: object
+    properties:
+      port@0:
+        description: |
+          DMIC ACIF (Audio Client Interface) port connected to the
+          corresponding AHUB (Audio Hub) ACIF port.
+
+      port@1:
+        description: |
+          DMIC DAP (Digital Audio Port) interface which can be connected
+          to external audio codec for capture.
+
 required:
   - compatible
   - reg
@@ -64,7 +80,7 @@ required:
   - assigned-clocks
   - assigned-clock-parents
 
-additionalProperties: false
+unevaluatedProperties: false
 
 examples:
   - |
index dfc1bf7..5564603 100644 (file)
@@ -16,6 +16,9 @@ maintainers:
   - Jon Hunter <jonathanh@nvidia.com>
   - Sameer Pujar <spujar@nvidia.com>
 
+allOf:
+  - $ref: audio-graph-port.yaml#
+
 properties:
   $nodename:
     pattern: "^i2s@[0-9a-f]*$"
@@ -74,6 +77,19 @@ properties:
       The name can be "I2S1" or "I2S2" ... "I2Sx", where x depends
       on the maximum available instances on a Tegra SoC.
 
+  ports:
+    type: object
+    properties:
+      port@0:
+        description: |
+          I2S ACIF (Audio Client Interface) port connected to the
+          corresponding AHUB (Audio Hub) ACIF port.
+
+      port@1:
+        description: |
+          I2S DAP (Digital Audio Port) interface which can be connected
+          to external audio codec for playback or capture.
+
 required:
   - compatible
   - reg
@@ -82,7 +98,7 @@ required:
   - assigned-clocks
   - assigned-clock-parents
 
-additionalProperties: false
+unevaluatedProperties: false
 
 examples:
   - |
diff --git a/Documentation/devicetree/bindings/sound/qcom,lpass-rx-macro.yaml b/Documentation/devicetree/bindings/sound/qcom,lpass-rx-macro.yaml
new file mode 100644 (file)
index 0000000..443d556
--- /dev/null
@@ -0,0 +1,62 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/sound/qcom,lpass-rx-macro.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: LPASS(Low Power Audio Subsystem) RX Macro audio codec DT bindings
+
+maintainers:
+  - Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
+
+properties:
+  compatible:
+    const: qcom,sm8250-lpass-rx-macro
+
+  reg:
+    maxItems: 1
+
+  "#sound-dai-cells":
+    const: 1
+
+  '#clock-cells':
+    const: 0
+
+  clocks:
+    maxItems: 5
+
+  clock-names:
+    items:
+      - const: mclk
+      - const: npl
+      - const: macro
+      - const: dcodec
+      - const: fsgen
+
+  clock-output-names:
+    items:
+      - const: mclk
+
+required:
+  - compatible
+  - reg
+  - "#sound-dai-cells"
+
+additionalProperties: false
+
+examples:
+  - |
+    #include <dt-bindings/sound/qcom,q6afe.h>
+    codec@3200000 {
+      compatible = "qcom,sm8250-lpass-rx-macro";
+      reg = <0x3200000 0x1000>;
+      #sound-dai-cells = <1>;
+      #clock-cells = <0>;
+      clocks = <&audiocc 0>,
+               <&audiocc 1>,
+               <&q6afecc LPASS_HW_MACRO_VOTE LPASS_CLK_ATTRIBUTE_COUPLE_NO>,
+               <&q6afecc LPASS_HW_DCODEC_VOTE LPASS_CLK_ATTRIBUTE_COUPLE_NO>,
+               <&vamacro>;
+      clock-names = "mclk", "npl", "macro", "dcodec", "fsgen";
+      clock-output-names = "mclk";
+    };
diff --git a/Documentation/devicetree/bindings/sound/qcom,lpass-tx-macro.yaml b/Documentation/devicetree/bindings/sound/qcom,lpass-tx-macro.yaml
new file mode 100644 (file)
index 0000000..6b5ca02
--- /dev/null
@@ -0,0 +1,67 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/sound/qcom,lpass-tx-macro.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: LPASS(Low Power Audio Subsystem) TX Macro audio codec DT bindings
+
+maintainers:
+  - Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
+
+properties:
+  compatible:
+    const: qcom,sm8250-lpass-tx-macro
+
+  reg:
+    maxItems: 1
+
+  "#sound-dai-cells":
+    const: 1
+
+  '#clock-cells':
+    const: 0
+
+  clocks:
+    maxItems: 5
+
+  clock-names:
+    items:
+      - const: mclk
+      - const: npl
+      - const: macro
+      - const: dcodec
+      - const: fsgen
+
+  clock-output-names:
+    items:
+      - const: mclk
+
+  qcom,dmic-sample-rate:
+    description: dmic sample rate
+    $ref: /schemas/types.yaml#/definitions/uint32
+
+required:
+  - compatible
+  - reg
+  - "#sound-dai-cells"
+
+additionalProperties: false
+
+examples:
+  - |
+    #include <dt-bindings/sound/qcom,q6afe.h>
+    codec@3220000 {
+      compatible = "qcom,sm8250-lpass-tx-macro";
+      reg = <0x3220000 0x1000>;
+      #sound-dai-cells = <1>;
+      #clock-cells = <0>;
+      clocks = <&aoncc 0>,
+               <&aoncc 1>,
+               <&q6afecc LPASS_HW_MACRO_VOTE LPASS_CLK_ATTRIBUTE_COUPLE_NO>,
+               <&q6afecc LPASS_HW_DCODEC_VOTE LPASS_CLK_ATTRIBUTE_COUPLE_NO>,
+               <&vamacro>;
+      clock-names = "mclk", "npl", "macro", "dcodec", "fsgen";
+      clock-output-names = "mclk";
+      qcom,dmic-sample-rate = <600000>;
+    };
index 0fd37aa..2e10465 100644 (file)
@@ -404,7 +404,7 @@ examples:
         /* DAI base */
         rcar_sound,dai {
             dai0 {
-                playback = <&ssi5 &src5>;
+                playback = <&ssi5>, <&src5>;
                 capture  = <&ssi6>;
             };
             dai1 {
@@ -430,8 +430,8 @@ examples:
                 bitclock-master = <&rsnd_endpoint0>;
                 frame-master = <&rsnd_endpoint0>;
 
-                playback = <&ssi0 &src0 &dvc0>;
-                capture  = <&ssi1 &src1 &dvc1>;
+                playback = <&ssi0>, <&src0>, <&dvc0>;
+                capture  = <&ssi1>, <&src1>, <&dvc1>;
             };
         };
     };
index 56788f5..c473df5 100644 (file)
@@ -37,10 +37,21 @@ Optional properties:
 - realtek,jd-src
   0: No JD is used
   1: using JD3 as JD source
+  2: JD source for Intel HDA header
 
 - 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.
 
+- sound-name-prefix: Please refer to name-prefix.txt
+
+- ports: A Codec may have a single or multiple I2S interfaces. These
+  interfaces on Codec side can be described under 'ports' or 'port'.
+  When the SoC or host device is connected to multiple interfaces of
+  the Codec, the connectivity can be described using 'ports' property.
+  If a single interface is used, then 'port' can be used. The usage
+  depends on the platform or board design.
+  Please refer to Documentation/devicetree/bindings/graph.txt
+
 Pins on the device (for linking into audio routes) for RT5659/RT5658:
 
   * DMIC L1
index d116c17..70b4a88 100644 (file)
@@ -41,14 +41,12 @@ properties:
       values of 2k, 4k or 8k. If set to 0 it will be off. If this node is not
       mentioned or if the value is unknown, then micbias resistor is set to
       4k.
-    $ref: "/schemas/types.yaml#/definitions/uint32"
     enum: [ 0, 2, 4, 8 ]
 
   micbias-voltage-m-volts:
     description: The bias voltage to be used in mVolts. The voltage can take
       values from 1.25V to 3V by 250mV steps. If this node is not mentioned
       or the value is unknown, then the value is set to 1.25V.
-    $ref: "/schemas/types.yaml#/definitions/uint32"
     enum: [ 1250, 1500, 1750, 2000, 2250, 2500, 2750, 3000 ]
 
   lrclk-strength:
diff --git a/Documentation/devicetree/bindings/sound/sirf-audio-codec.txt b/Documentation/devicetree/bindings/sound/sirf-audio-codec.txt
deleted file mode 100644 (file)
index 062f5ec..0000000
+++ /dev/null
@@ -1,17 +0,0 @@
-SiRF internal audio CODEC
-
-Required properties:
-
-  - compatible : "sirf,atlas6-audio-codec" or "sirf,prima2-audio-codec"
-
-  - reg : the register address of the device.
-
-  - clocks: the clock of SiRF internal audio codec
-
-Example:
-
-audiocodec: audiocodec@b0040000 {
-       compatible = "sirf,atlas6-audio-codec";
-       reg = <0xb0040000 0x10000>;
-       clocks = <&clks 27>;
-};
diff --git a/Documentation/devicetree/bindings/sound/sirf-usp.txt b/Documentation/devicetree/bindings/sound/sirf-usp.txt
deleted file mode 100644 (file)
index 02f85b3..0000000
+++ /dev/null
@@ -1,27 +0,0 @@
-* SiRF SoC USP module
-
-Required properties:
-- compatible: "sirf,prima2-usp-pcm"
-- reg: Base address and size entries:
-- dmas: List of DMA controller phandle and DMA request line ordered pairs.
-- dma-names: Identifier string for each DMA request line in the dmas property.
-  These strings correspond 1:1 with the ordered pairs in dmas.
-
-  One of the DMA channels will be responsible for transmission (should be
-  named "tx") and one for reception (should be named "rx").
-
-- clocks: USP controller clock source
-- pinctrl-names: Must contain a "default" entry.
-- pinctrl-NNN: One property must exist for each entry in pinctrl-names.
-
-Example:
-usp0: usp@b0080000 {
-       compatible = "sirf,prima2-usp-pcm";
-       reg = <0xb0080000 0x10000>;
-       clocks = <&clks 28>;
-       dmas = <&dmac1 1>, <&dmac1 2>;
-       dma-names = "rx", "tx";
-       pinctrl-names = "default";
-       pinctrl-0 = <&usp0_only_utfs_pins_a>;
-};
-
index f324108..6feb5a0 100644 (file)
@@ -54,6 +54,10 @@ properties:
   resets:
     maxItems: 1
 
+  "#clock-cells":
+    description: Configure the I2S device as MCLK clock provider.
+    const: 0
+
 required:
   - compatible
   - "#sound-dai-cells"
index dcfa9a3..c36c649 100644 (file)
@@ -9,6 +9,9 @@ Required properties:
   - reg : the I2C address of the device.
 
 Optional properties:
+
+  - clocks : The clock source of the mclk
+
   - spk-mono: This is a boolean property. If present, the SPK_MONO bit
     of R51 (Class D Control 2) gets set, indicating that the speaker is
     in mono mode.
@@ -27,6 +30,7 @@ Example:
 wm8962: codec@1a {
        compatible = "wlf,wm8962";
        reg = <0x1a>;
+       clocks = <&clks IMX6QDL_CLK_CKO>;
 
        gpio-cfg = <
                0x0000 /* 0:Default */
diff --git a/Documentation/devicetree/bindings/sound/zte,tdm.txt b/Documentation/devicetree/bindings/sound/zte,tdm.txt
deleted file mode 100644 (file)
index 2a07ca6..0000000
+++ /dev/null
@@ -1,30 +0,0 @@
-ZTE TDM DAI driver
-
-Required properties:
-
-- compatible : should be one of the following.
-       * zte,zx296718-tdm
-- reg : physical base address of the controller and length of memory mapped
-    region.
-- clocks : Pairs of phandle and specifier referencing the controller's clocks.
-- clock-names: "wclk" for the wclk.
-               "pclk" for the pclk.
--#clock-cells: should be 1.
-- zte,tdm-dma-sysctrl : Reference to the sysctrl controller controlling
-    the dma. includes:
-       phandle of sysctrl.
-       register offset in sysctrl for control dma.
-       mask of the register that be written to sysctrl.
-
-Example:
-
-       tdm: tdm@1487000 {
-               compatible = "zte,zx296718-tdm";
-               reg = <0x01487000 0x1000>;
-               clocks = <&audiocrm AUDIO_TDM_WCLK>, <&audiocrm AUDIO_TDM_PCLK>;
-               clock-names = "wclk", "pclk";
-               #clock-cells = <1>;
-               pinctrl-names = "default";
-               pinctrl-0 = <&tdm_global_pin>;
-               zte,tdm-dma-sysctrl = <&sysctrl 0x10c 4>;
-       };
diff --git a/Documentation/devicetree/bindings/sound/zte,zx-aud96p22.txt b/Documentation/devicetree/bindings/sound/zte,zx-aud96p22.txt
deleted file mode 100644 (file)
index 41bb104..0000000
+++ /dev/null
@@ -1,24 +0,0 @@
-ZTE ZX AUD96P22 Audio Codec
-
-Required properties:
- - compatible: Must be "zte,zx-aud96p22"
- - #sound-dai-cells: Should be 0
- - reg: I2C bus slave address of AUD96P22
-
-Example:
-
-       i2c0: i2c@1486000 {
-               compatible = "zte,zx296718-i2c";
-               reg = <0x01486000 0x1000>;
-               interrupts = <GIC_SPI 35 IRQ_TYPE_LEVEL_HIGH>;
-               #address-cells = <1>;
-               #size-cells = <0>;
-               clocks = <&audiocrm AUDIO_I2C0_WCLK>;
-               clock-frequency = <1600000>;
-
-               aud96p22: codec@22 {
-                       compatible = "zte,zx-aud96p22";
-                       #sound-dai-cells = <0>;
-                       reg = <0x22>;
-               };
-       };
diff --git a/Documentation/devicetree/bindings/sound/zte,zx-i2s.txt b/Documentation/devicetree/bindings/sound/zte,zx-i2s.txt
deleted file mode 100644 (file)
index 3927251..0000000
+++ /dev/null
@@ -1,45 +0,0 @@
-ZTE ZX296702 I2S controller
-
-Required properties:
- - compatible : Must be one of:
-       "zte,zx296718-i2s", "zte,zx296702-i2s"
-       "zte,zx296702-i2s"
- - reg : Must contain I2S core's registers location and length
- - clocks : Pairs of phandle and specifier referencing the controller's clocks.
- - clock-names: "wclk" for the wclk, "pclk" for the pclk to the I2S interface.
- - dmas: Pairs of phandle and specifier for the DMA channel that is used by
-   the core. The core expects two dma channels for transmit.
- - dma-names : Must be "tx" and "rx"
-
-For more details on the 'dma', 'dma-names', 'clock' and 'clock-names' properties
-please check:
-       * resource-names.txt
-       * clock/clock-bindings.txt
-       * dma/dma.txt
-
-Example:
-       i2s0: i2s@b005000 {
-               #sound-dai-cells = <0>;
-               compatible = "zte,zx296718-i2s", "zte,zx296702-i2s";
-               reg = <0x0b005000 0x1000>;
-               clocks = <&audiocrm AUDIO_I2S0_WCLK>, <&audiocrm AUDIO_I2S0_PCLK>;
-               clock-names = "wclk", "pclk";
-               interrupts = <GIC_SPI 22 IRQ_TYPE_LEVEL_HIGH>;
-               dmas = <&dma 5>, <&dma 6>;
-               dma-names = "tx", "rx";
-       };
-
-       sound {
-               compatible = "simple-audio-card";
-               simple-audio-card,name = "zx296702_snd";
-               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 = <&i2s0>;
-               };
-
-               sndcodec: simple-audio-card,codec {
-                       sound-dai = <&acodec>;
-               };
-       };
diff --git a/Documentation/devicetree/bindings/sound/zte,zx-spdif.txt b/Documentation/devicetree/bindings/sound/zte,zx-spdif.txt
deleted file mode 100644 (file)
index 09231d7..0000000
+++ /dev/null
@@ -1,27 +0,0 @@
-ZTE ZX296702 SPDIF controller
-
-Required properties:
- - compatible : Must be "zte,zx296702-spdif"
- - reg : Must contain SPDIF core's registers location and length
- - clocks : Pairs of phandle and specifier referencing the controller's clocks.
- - clock-names: "tx" for the clock to the SPDIF interface.
- - dmas: Pairs of phandle and specifier for the DMA channel that is used by
-   the core. The core expects one dma channel for transmit.
- - dma-names : Must be "tx"
-
-For more details on the 'dma', 'dma-names', 'clock' and 'clock-names' properties
-please check:
-       * resource-names.txt
-       * clock/clock-bindings.txt
-       * dma/dma.txt
-
-Example:
-       spdif0: spdif0@b004000 {
-               compatible = "zte,zx296702-spdif";
-               reg = <0x0b004000 0x1000>;
-               clocks = <&lsp0clk ZX296702_SPDIF0_DIV>;
-               clock-names = "tx";
-               interrupts = <GIC_SPI 21 IRQ_TYPE_LEVEL_HIGH>;
-               dmas = <&dma 4>;
-               dma-names = "tx";
-       };
index 148b3fb..c80a835 100644 (file)
@@ -21,6 +21,8 @@ properties:
   reg:
     description: module registers
 
+  ranges: true
+
   power-domains:
     description:
       PM domain provider node and an args specifier containing
@@ -62,6 +64,8 @@ properties:
   '#size-cells':
     const: 2
 
+  dma-coherent: true
+
 patternProperties:
   "^usb@":
     type: object
index 4e2c26c..e3dfb02 100644 (file)
@@ -19,7 +19,6 @@ properties:
     pattern: "^watchdog(@.*|-[0-9a-f])?$"
 
   timeout-sec:
-    $ref: /schemas/types.yaml#/definitions/uint32
     description:
       Contains the watchdog timeout in seconds.
 
index 587a939..78240e2 100644 (file)
@@ -586,6 +586,14 @@ without significant effort.
 The advantage of mounting with the "volatile" option is that all forms of
 sync calls to the upper filesystem are omitted.
 
+In order to avoid a giving a false sense of safety, the syncfs (and fsync)
+semantics of volatile mounts are slightly different than that of the rest of
+VFS.  If any writeback error occurs on the upperdir's filesystem after a
+volatile mount takes place, all sync functions will return an error.  Once this
+condition is reached, the filesystem will not recover, and every subsequent sync
+call will return an error, even if the upperdir has not experience a new error
+since the last sync call.
+
 When overlay is mounted with "volatile" option, the directory
 "$workdir/work/incompat/volatile" is created.  During next mount, overlay
 checks for this directory and refuses to mount if present. This is a strong
index 4b1c10f..3349966 100644 (file)
@@ -11,16 +11,13 @@ compiler [1]_. They are useful for runtime instrumentation and static analysis.
 We can analyse, change and add further code during compilation via
 callbacks [2]_, GIMPLE [3]_, IPA [4]_ and RTL passes [5]_.
 
-The GCC plugin infrastructure of the kernel supports all gcc versions from
-4.5 to 6.0, building out-of-tree modules, cross-compilation and building in a
-separate directory.
-Plugin source files have to be compilable by both a C and a C++ compiler as well
-because gcc versions 4.5 and 4.6 are compiled by a C compiler,
-gcc-4.7 can be compiled by a C or a C++ compiler,
-and versions 4.8+ can only be compiled by a C++ compiler.
+The GCC plugin infrastructure of the kernel supports building out-of-tree
+modules, cross-compilation and building in a separate directory.
+Plugin source files have to be compilable by a C++ compiler.
 
-Currently the GCC plugin infrastructure supports only the x86, arm, arm64 and
-powerpc architectures.
+Currently the GCC plugin infrastructure supports only some architectures.
+Grep "select HAVE_GCC_PLUGINS" to find out which architectures support
+GCC plugins.
 
 This infrastructure was ported from grsecurity [6]_ and PaX [7]_.
 
@@ -47,20 +44,13 @@ Files
        This is a compatibility header for GCC plugins.
        It should be always included instead of individual gcc headers.
 
-**$(src)/scripts/gcc-plugin.sh**
-
-       This script checks the availability of the included headers in
-       gcc-common.h and chooses the proper host compiler to build the plugins
-       (gcc-4.7 can be built by either gcc or g++).
-
 **$(src)/scripts/gcc-plugins/gcc-generate-gimple-pass.h,
 $(src)/scripts/gcc-plugins/gcc-generate-ipa-pass.h,
 $(src)/scripts/gcc-plugins/gcc-generate-simple_ipa-pass.h,
 $(src)/scripts/gcc-plugins/gcc-generate-rtl-pass.h**
 
        These headers automatically generate the registration structures for
-       GIMPLE, SIMPLE_IPA, IPA and RTL passes. They support all gcc versions
-       from 4.5 to 6.0.
+       GIMPLE, SIMPLE_IPA, IPA and RTL passes.
        They should be preferred to creating the structures by hand.
 
 
@@ -68,21 +58,25 @@ Usage
 =====
 
 You must install the gcc plugin headers for your gcc version,
-e.g., on Ubuntu for gcc-4.9::
+e.g., on Ubuntu for gcc-10::
 
-       apt-get install gcc-4.9-plugin-dev
+       apt-get install gcc-10-plugin-dev
 
 Or on Fedora::
 
        dnf install gcc-plugin-devel
 
-Enable a GCC plugin based feature in the kernel config::
+Enable the GCC plugin infrastructure and some plugin(s) you want to use
+in the kernel config::
 
-       CONFIG_GCC_PLUGIN_CYC_COMPLEXITY = y
+       CONFIG_GCC_PLUGINS=y
+       CONFIG_GCC_PLUGIN_CYC_COMPLEXITY=y
+       CONFIG_GCC_PLUGIN_LATENT_ENTROPY=y
+       ...
 
-To compile only the plugin(s)::
+To compile the minimum tool set including the plugin(s)::
 
-       make gcc-plugins
+       make scripts
 
 or just run the kernel make and compile the whole kernel with
 the cyclomatic complexity GCC plugin.
@@ -91,7 +85,8 @@ the cyclomatic complexity GCC plugin.
 4. How to add a new GCC plugin
 ==============================
 
-The GCC plugins are in $(src)/scripts/gcc-plugins/. You can use a file or a directory
-here. It must be added to $(src)/scripts/gcc-plugins/Makefile,
-$(src)/scripts/Makefile.gcc-plugins and $(src)/arch/Kconfig.
+The GCC plugins are in scripts/gcc-plugins/. You need to put plugin source files
+right under scripts/gcc-plugins/. Creating subdirectories is not supported.
+It must be added to scripts/gcc-plugins/Makefile, scripts/Makefile.gcc-plugins
+and a relevant Kconfig file.
 See the cyc_complexity_plugin.c (CONFIG_GCC_PLUGIN_CYC_COMPLEXITY) GCC plugin.
index 21c8478..b18401d 100644 (file)
@@ -63,6 +63,50 @@ They can be enabled individually. The full list of the parameters: ::
 Currently, the integrated assembler is disabled by default. You can pass
 ``LLVM_IAS=1`` to enable it.
 
+Supported Architectures
+-----------------------
+
+LLVM does not target all of the architectures that Linux supports and
+just because a target is supported in LLVM does not mean that the kernel
+will build or work without any issues. Below is a general summary of
+architectures that currently work with ``CC=clang`` or ``LLVM=1``. Level
+of support corresponds to "S" values in the MAINTAINERS files. If an
+architecture is not present, it either means that LLVM does not target
+it or there are known issues. Using the latest stable version of LLVM or
+even the development tree will generally yield the best results.
+An architecture's ``defconfig`` is generally expected to work well,
+certain configurations may have problems that have not been uncovered
+yet. Bug reports are always welcome at the issue tracker below!
+
+.. list-table::
+   :widths: 10 10 10
+   :header-rows: 1
+
+   * - Architecture
+     - Level of support
+     - ``make`` command
+   * - arm
+     - Supported
+     - ``LLVM=1``
+   * - arm64
+     - Supported
+     - ``LLVM=1``
+   * - mips
+     - Maintained
+     - ``CC=clang``
+   * - powerpc
+     - Maintained
+     - ``CC=clang``
+   * - riscv
+     - Maintained
+     - ``CC=clang``
+   * - s390
+     - Maintained
+     - ``CC=clang``
+   * - x86
+     - Supported
+     - ``LLVM=1``
+
 Getting Help
 ------------
 
index 9f6a118..300d8ed 100644 (file)
@@ -755,7 +755,7 @@ more details, with real examples.
        bits on the scripts nonetheless.
 
        Kbuild provides variables $(CONFIG_SHELL), $(AWK), $(PERL),
-       $(PYTHON) and $(PYTHON3) to refer to interpreters for the respective
+       and $(PYTHON3) to refer to interpreters for the respective
        scripts.
 
        Example::
index dd2b12a..fa544e9 100644 (file)
@@ -1196,7 +1196,7 @@ icmp_errors_use_inbound_ifaddr - BOOLEAN
 
        If non-zero, the message will be sent with the primary address of
        the interface that received the packet that caused the icmp error.
-       This is the behaviour network many administrators will expect from
+       This is the behaviour many network administrators will expect from
        a router. And it can make debugging complicated network layouts
        much easier.
 
@@ -1807,12 +1807,24 @@ seg6_flowlabel - INTEGER
 ``conf/default/*``:
        Change the interface-specific default settings.
 
+       These settings would be used during creating new interfaces.
+
 
 ``conf/all/*``:
        Change all the interface-specific settings.
 
        [XXX:  Other special features than forwarding?]
 
+conf/all/disable_ipv6 - BOOLEAN
+       Changing this value is same as changing ``conf/default/disable_ipv6``
+       setting and also all per-interface ``disable_ipv6`` settings to the same
+       value.
+
+       Reading this value does not have any particular meaning. It does not say
+       whether IPv6 support is enabled or disabled. Returned value can be 1
+       also in the case when some interface has ``disable_ipv6`` set to 0 and
+       has configured IPv6 addresses.
+
 conf/all/forwarding - BOOLEAN
        Enable global IPv6 forwarding between all interfaces.
 
index 9af3334..5f0dea3 100644 (file)
@@ -534,3 +534,6 @@ offload. Hence, TLS TX device feature flag requires TX csum offload being set.
 Disabling the latter implies clearing the former. Disabling TX checksum offload
 should not affect old connections, and drivers should make sure checksum
 calculation does not break for them.
+Similarly, device-offloaded TLS decryption implies doing RXCSUM. If the user
+does not want to enable RX csum offload, TLS RX device feature is disabled
+as well.
index c136e25..99ceb97 100644 (file)
@@ -360,10 +360,9 @@ since the last call to this ioctl.  Bit 0 is the first page in the
 memory slot.  Ensure the entire structure is cleared to avoid padding
 issues.
 
-If KVM_CAP_MULTI_ADDRESS_SPACE is available, bits 16-31 specifies
-the address space for which you want to return the dirty bitmap.
-They must be less than the value that KVM_CHECK_EXTENSION returns for
-the KVM_CAP_MULTI_ADDRESS_SPACE capability.
+If KVM_CAP_MULTI_ADDRESS_SPACE is available, bits 16-31 of slot field specifies
+the address space for which you want to return the dirty bitmap.  See
+KVM_SET_USER_MEMORY_REGION for details on the usage of slot field.
 
 The bits in the dirty bitmap are cleared before the ioctl returns, unless
 KVM_CAP_MANUAL_DIRTY_LOG_PROTECT2 is enabled.  For more information,
@@ -1281,6 +1280,9 @@ field userspace_addr, which must point at user addressable memory for
 the entire memory slot size.  Any object may back this memory, including
 anonymous memory, ordinary files, and hugetlbfs.
 
+On architectures that support a form of address tagging, userspace_addr must
+be an untagged address.
+
 It is recommended that the lower 21 bits of guest_phys_addr and userspace_addr
 be identical.  This allows large pages in the guest to be backed by large
 pages in the host.
@@ -1333,7 +1335,7 @@ documentation when it pops into existence).
 
 :Capability: KVM_CAP_ENABLE_CAP_VM
 :Architectures: all
-:Type: vcpu ioctl
+:Type: vm ioctl
 :Parameters: struct kvm_enable_cap (in)
 :Returns: 0 on success; -1 on error
 
@@ -4432,7 +4434,7 @@ to I/O ports.
 :Capability: KVM_CAP_MANUAL_DIRTY_LOG_PROTECT2
 :Architectures: x86, arm, arm64, mips
 :Type: vm ioctl
-:Parameters: struct kvm_dirty_log (in)
+:Parameters: struct kvm_clear_dirty_log (in)
 :Returns: 0 on success, -1 on error
 
 ::
@@ -4459,10 +4461,9 @@ in KVM's dirty bitmap, and dirty tracking is re-enabled for that page
 (for example via write-protection, or by clearing the dirty bit in
 a page table entry).
 
-If KVM_CAP_MULTI_ADDRESS_SPACE is available, bits 16-31 specifies
-the address space for which you want to return the dirty bitmap.
-They must be less than the value that KVM_CHECK_EXTENSION returns for
-the KVM_CAP_MULTI_ADDRESS_SPACE capability.
+If KVM_CAP_MULTI_ADDRESS_SPACE is available, bits 16-31 of slot field specifies
+the address space for which you want to clear the dirty status.  See
+KVM_SET_USER_MEMORY_REGION for details on the usage of slot field.
 
 This ioctl is mostly useful when KVM_CAP_MANUAL_DIRTY_LOG_PROTECT2
 is enabled; for more information, see the description of the capability.
index 6ab4e35..ac2095d 100644 (file)
@@ -37,8 +37,10 @@ call L2.
 Running nested VMX
 ------------------
 
-The nested VMX feature is disabled by default. It can be enabled by giving
-the "nested=1" option to the kvm-intel module.
+The nested VMX feature is enabled by default since Linux kernel v4.20. For
+older Linux kernel, it can be enabled by giving the "nested=1" option to the
+kvm-intel module.
+
 
 No modifications are required to user space (qemu). However, qemu's default
 emulated CPU type (qemu64) does not list the "VMX" CPU feature, so it must be
index d0a1fc7..bd70c69 100644 (file)
@@ -74,7 +74,7 @@ few:
 Enabling "nested" (x86)
 -----------------------
 
-From Linux kernel v4.19 onwards, the ``nested`` KVM parameter is enabled
+From Linux kernel v4.20 onwards, the ``nested`` KVM parameter is enabled
 by default for Intel and AMD.  (Though your Linux distribution might
 override this default.)
 
index 605058e..667d038 100644 (file)
@@ -2616,8 +2616,8 @@ S:        Maintained
 F:     drivers/power/reset/keystone-reset.c
 
 ARM/TEXAS INSTRUMENTS K3 ARCHITECTURE
-M:     Tero Kristo <t-kristo@ti.com>
 M:     Nishanth Menon <nm@ti.com>
+M:     Tero Kristo <kristo@kernel.org>
 L:     linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
 S:     Supported
 F:     Documentation/devicetree/bindings/arm/ti/k3.yaml
@@ -3239,6 +3239,7 @@ L:        netdev@vger.kernel.org
 S:     Supported
 W:     http://sourceforge.net/projects/bonding/
 F:     drivers/net/bonding/
+F:     include/net/bonding.h
 F:     include/uapi/linux/if_bonding.h
 
 BOSCH SENSORTEC BMA400 ACCELEROMETER IIO DRIVER
@@ -3334,7 +3335,7 @@ F:        arch/riscv/net/
 X:     arch/riscv/net/bpf_jit_comp64.c
 
 BPF JIT for RISC-V (64-bit)
-M:     Björn Töpel <bjorn.topel@gmail.com>
+M:     Björn Töpel <bjorn@kernel.org>
 L:     netdev@vger.kernel.org
 L:     bpf@vger.kernel.org
 S:     Maintained
@@ -3411,7 +3412,7 @@ F:        Documentation/devicetree/bindings/pci/brcm,stb-pcie.yaml
 F:     drivers/pci/controller/pcie-brcmstb.c
 F:     drivers/staging/vc04_services
 N:     bcm2711
-N:     bcm2835
+N:     bcm283*
 
 BROADCOM BCM281XX/BCM11XXX/BCM216XX ARM ARCHITECTURE
 M:     Florian Fainelli <f.fainelli@gmail.com>
@@ -3879,7 +3880,7 @@ F:        Documentation/devicetree/bindings/mtd/cadence-nand-controller.txt
 F:     drivers/mtd/nand/raw/cadence-nand-controller.c
 
 CADENCE USB3 DRD IP DRIVER
-M:     Peter Chen <peter.chen@nxp.com>
+M:     Peter Chen <peter.chen@kernel.org>
 M:     Pawel Laszczak <pawell@cadence.com>
 R:     Roger Quadros <rogerq@kernel.org>
 R:     Aswath Govindraju <a-govindraju@ti.com>
@@ -4161,7 +4162,7 @@ S:        Maintained
 F:     Documentation/translations/zh_CN/
 
 CHIPIDEA USB HIGH SPEED DUAL ROLE CONTROLLER
-M:     Peter Chen <Peter.Chen@nxp.com>
+M:     Peter Chen <peter.chen@kernel.org>
 L:     linux-usb@vger.kernel.org
 S:     Maintained
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/peter.chen/usb.git
@@ -4303,7 +4304,7 @@ S:        Maintained
 F:     .clang-format
 
 CLANG/LLVM BUILD SUPPORT
-M:     Nathan Chancellor <natechancellor@gmail.com>
+M:     Nathan Chancellor <nathan@kernel.org>
 M:     Nick Desaulniers <ndesaulniers@google.com>
 L:     clang-built-linux@googlegroups.com
 S:     Supported
@@ -4311,7 +4312,9 @@ W:        https://clangbuiltlinux.github.io/
 B:     https://github.com/ClangBuiltLinux/linux/issues
 C:     irc://chat.freenode.net/clangbuiltlinux
 F:     Documentation/kbuild/llvm.rst
+F:     include/linux/compiler-clang.h
 F:     scripts/clang-tools/
+F:     scripts/clang-version.sh
 F:     scripts/lld-version.sh
 K:     \b(?i:clang|llvm)\b
 
@@ -6471,9 +6474,9 @@ S:        Maintained
 F:     drivers/edac/skx_*.[ch]
 
 EDAC-TI
-M:     Tero Kristo <t-kristo@ti.com>
+M:     Tero Kristo <kristo@kernel.org>
 L:     linux-edac@vger.kernel.org
-S:     Maintained
+S:     Odd Fixes
 F:     drivers/edac/ti_edac.c
 
 EDIROL UA-101/UA-1000 DRIVER
@@ -8431,11 +8434,8 @@ F:       drivers/i3c/
 F:     include/linux/i3c/
 
 IA64 (Itanium) PLATFORM
-M:     Tony Luck <tony.luck@intel.com>
-M:     Fenghua Yu <fenghua.yu@intel.com>
 L:     linux-ia64@vger.kernel.org
-S:     Odd Fixes
-T:     git git://git.kernel.org/pub/scm/linux/kernel/git/aegl/linux.git
+S:     Orphan
 F:     Documentation/ia64/
 F:     arch/ia64/
 
@@ -12413,6 +12413,7 @@ F:      tools/testing/selftests/net/ipsec.c
 NETWORKING [IPv4/IPv6]
 M:     "David S. Miller" <davem@davemloft.net>
 M:     Hideaki YOSHIFUJI <yoshfuji@linux-ipv6.org>
+M:     David Ahern <dsahern@kernel.org>
 L:     netdev@vger.kernel.org
 S:     Maintained
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/netdev/net.git
@@ -17571,7 +17572,7 @@ F:      include/linux/dma/k3-psil.h
 
 TEXAS INSTRUMENTS' SYSTEM CONTROL INTERFACE (TISCI) PROTOCOL DRIVER
 M:     Nishanth Menon <nm@ti.com>
-M:     Tero Kristo <t-kristo@ti.com>
+M:     Tero Kristo <kristo@kernel.org>
 M:     Santosh Shilimkar <ssantosh@kernel.org>
 L:     linux-arm-kernel@lists.infradead.org
 S:     Maintained
@@ -17715,9 +17716,9 @@ S:      Maintained
 F:     drivers/clk/clk-cdce706.c
 
 TI CLOCK DRIVER
-M:     Tero Kristo <t-kristo@ti.com>
+M:     Tero Kristo <kristo@kernel.org>
 L:     linux-omap@vger.kernel.org
-S:     Maintained
+S:     Odd Fixes
 F:     drivers/clk/ti/
 F:     include/linux/clk/ti.h
 
@@ -18420,7 +18421,7 @@ F:      Documentation/usb/ohci.rst
 F:     drivers/usb/host/ohci*
 
 USB OTG FSM (Finite State Machine)
-M:     Peter Chen <Peter.Chen@nxp.com>
+M:     Peter Chen <peter.chen@kernel.org>
 L:     linux-usb@vger.kernel.org
 S:     Maintained
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/peter.chen/usb.git
@@ -19424,7 +19425,7 @@ F:      drivers/net/ethernet/*/*/*xdp*
 K:     (?:\b|_)xdp(?:\b|_)
 
 XDP SOCKETS (AF_XDP)
-M:     Björn Töpel <bjorn.topel@intel.com>
+M:     Björn Töpel <bjorn@kernel.org>
 M:     Magnus Karlsson <magnus.karlsson@intel.com>
 R:     Jonathan Lemon <jonathan.lemon@gmail.com>
 L:     netdev@vger.kernel.org
index b0e4767..ade44ac 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -2,7 +2,7 @@
 VERSION = 5
 PATCHLEVEL = 11
 SUBLEVEL = 0
-EXTRAVERSION = -rc4
+EXTRAVERSION = -rc7
 NAME = Kleptomaniac Octopus
 
 # *DOCUMENTATION*
@@ -452,7 +452,6 @@ AWK         = awk
 INSTALLKERNEL  := installkernel
 DEPMOD         = depmod
 PERL           = perl
-PYTHON         = python
 PYTHON3                = python3
 CHECK          = sparse
 BASH           = bash
@@ -508,7 +507,7 @@ CLANG_FLAGS :=
 
 export ARCH SRCARCH CONFIG_SHELL BASH HOSTCC KBUILD_HOSTCFLAGS CROSS_COMPILE LD CC
 export CPP AR NM STRIP OBJCOPY OBJDUMP READELF PAHOLE RESOLVE_BTFIDS LEX YACC AWK INSTALLKERNEL
-export PERL PYTHON PYTHON3 CHECK CHECKFLAGS MAKE UTS_MACHINE HOSTCXX
+export PERL PYTHON3 CHECK CHECKFLAGS MAKE UTS_MACHINE HOSTCXX
 export KGZIP KBZIP2 KLZOP LZMA LZ4 XZ ZSTD
 export KBUILD_HOSTCXXFLAGS KBUILD_HOSTLDFLAGS KBUILD_HOSTLDLIBS LDFLAGS_MODULE
 
@@ -812,10 +811,12 @@ KBUILD_CFLAGS     += -ftrivial-auto-var-init=zero
 KBUILD_CFLAGS  += -enable-trivial-auto-var-init-zero-knowing-it-will-be-removed-from-clang
 endif
 
+DEBUG_CFLAGS   :=
+
 # Workaround for GCC versions < 5.0
 # https://gcc.gnu.org/bugzilla/show_bug.cgi?id=61801
 ifdef CONFIG_CC_IS_GCC
-DEBUG_CFLAGS   := $(call cc-ifversion, -lt, 0500, $(call cc-option, -fno-var-tracking-assignments))
+DEBUG_CFLAGS   += $(call cc-ifversion, -lt, 0500, $(call cc-option, -fno-var-tracking-assignments))
 endif
 
 ifdef CONFIG_DEBUG_INFO
@@ -948,12 +949,6 @@ KBUILD_CFLAGS   += $(call cc-option,-Werror=designated-init)
 # change __FILE__ to the relative path from the srctree
 KBUILD_CPPFLAGS += $(call cc-option,-fmacro-prefix-map=$(srctree)/=)
 
-# ensure -fcf-protection is disabled when using retpoline as it is
-# incompatible with -mindirect-branch=thunk-extern
-ifdef CONFIG_RETPOLINE
-KBUILD_CFLAGS += $(call cc-option,-fcf-protection=none)
-endif
-
 # include additional Makefiles when needed
 include-y                      := scripts/Makefile.extrawarn
 include-$(CONFIG_KASAN)                += scripts/Makefile.kasan
index 8452753..31927d2 100644 (file)
@@ -15,7 +15,8 @@ static int node_offset(void *fdt, const char *node_path)
 {
        int offset = fdt_path_offset(fdt, node_path);
        if (offset == -FDT_ERR_NOTFOUND)
-               offset = fdt_add_subnode(fdt, 0, node_path);
+               /* Add the node to root if not found, dropping the leading '/' */
+               offset = fdt_add_subnode(fdt, 0, node_path + 1);
        return offset;
 }
 
index 861e05d..343364d 100644 (file)
                stdout-path = &uart1;
        };
 
+       aliases {
+               mmc0 = &usdhc2;
+               mmc1 = &usdhc3;
+               mmc2 = &usdhc4;
+               /delete-property/ mmc3;
+       };
+
        memory@10000000 {
                device_type = "memory";
                reg = <0x10000000 0x80000000>;
index 736074f..959d8ac 100644 (file)
 
                        /* VDD_AUD_1P8: Audio codec */
                        reg_aud_1p8v: ldo3 {
-                               regulator-name = "vdd1p8";
+                               regulator-name = "vdd1p8a";
                                regulator-min-microvolt = <1800000>;
                                regulator-max-microvolt = <1800000>;
                                regulator-boot-on;
index d6df598..b167b33 100644 (file)
 
        lcd_backlight: lcd-backlight {
                compatible = "pwm-backlight";
-               pwms = <&pwm4 0 5000000>;
+               pwms = <&pwm4 0 5000000 0>;
                pwm-names = "LCD_BKLT_PWM";
 
                brightness-levels = <0 10 20 30 40 50 60 70 80 90 100>;
                i2c-gpio,delay-us = <2>; /* ~100 kHz */
                #address-cells = <1>;
                #size-cells = <0>;
-               status = "disabld";
+               status = "disabled";
        };
 
        i2c_cam: i2c-gpio-cam {
                i2c-gpio,delay-us = <2>; /* ~100 kHz */
                #address-cells = <1>;
                #size-cells = <0>;
-               status = "disabld";
+               status = "disabled";
        };
 };
 
index b065778..7e4e5fd 100644 (file)
@@ -53,7 +53,6 @@
 &fec {
        pinctrl-names = "default";
        pinctrl-0 = <&pinctrl_microsom_enet_ar8035>;
-       phy-handle = <&phy>;
        phy-mode = "rgmii-id";
        phy-reset-duration = <2>;
        phy-reset-gpios = <&gpio4 15 GPIO_ACTIVE_LOW>;
                #address-cells = <1>;
                #size-cells = <0>;
 
-               phy: ethernet-phy@0 {
+               /*
+                * The PHY can appear at either address 0 or 4 due to the
+                * configuration (LED) pin not being pulled sufficiently.
+                */
+               ethernet-phy@0 {
                        reg = <0>;
                        qca,clk-out-frequency = <125000000>;
                };
+
+               ethernet-phy@4 {
+                       reg = <4>;
+                       qca,clk-out-frequency = <125000000>;
+               };
        };
 };
 
index 84b0952..bd6b528 100644 (file)
                compatible = "nxp,pcf2127";
                reg = <0>;
                spi-max-frequency = <2000000>;
+               reset-source;
        };
 };
 
index 3a5cfb0..c87066d 100644 (file)
 
                                        clocks = <&xtal_32k>, <&xtal>;
                                        clock-names = "xtal_32k", "xtal";
-
-                                       assigned-clocks = <&clk LPC32XX_CLK_HCLK_PLL>;
-                                       assigned-clock-rates = <208000000>;
                                };
                        };
 
index c8745bc..7b8c18e 100644 (file)
                gpio-sck = <&gpio1 12 GPIO_ACTIVE_HIGH>;
                gpio-miso = <&gpio1 18 GPIO_ACTIVE_HIGH>;
                gpio-mosi = <&gpio1 20 GPIO_ACTIVE_HIGH>;
-               cs-gpios = <&gpio1 19 GPIO_ACTIVE_HIGH>;
+               cs-gpios = <&gpio1 19 GPIO_ACTIVE_LOW>;
                num-chipselects = <1>;
 
                /* lcd panel */
                        spi-max-frequency = <100000>;
                        spi-cpol;
                        spi-cpha;
-                       spi-cs-high;
 
                        backlight= <&backlight>;
                        label = "lcd";
index 3ea4c5b..e833c21 100644 (file)
                        debounce-interval = <10>;
                };
 
+               /*
+                * We use pad 0x4a100116 abe_dmic_din3.gpio_122 as the irq instead
+                * of the gpio interrupt to avoid lost events in deeper idle states.
+               */
                slider {
                        label = "Keypad Slide";
+                       interrupts-extended = <&omap4_pmx_core 0xd6>;
                        gpios = <&gpio4 26 GPIO_ACTIVE_HIGH>; /* gpio122 */
                        linux,input-type = <EV_SW>;
                        linux,code = <SW_KEYPAD_SLIDE>;
index d309fad..344d298 100644 (file)
                                            200000 0>;
                };
        };
+
+       reserved-memory {
+               #address-cells = <1>;
+               #size-cells = <1>;
+               ranges;
+
+               /* Modem trace memory */
+               ram@06000000 {
+                       reg = <0x06000000 0x00f00000>;
+                       no-map;
+               };
+
+               /* Modem shared memory */
+               ram@06f00000 {
+                       reg = <0x06f00000 0x00100000>;
+                       no-map;
+               };
+
+               /* Modem private memory */
+               ram@07000000 {
+                       reg = <0x07000000 0x01000000>;
+                       no-map;
+               };
+
+               /*
+                * Initial Secure Software ISSW memory
+                *
+                * This is probably only used if the kernel tries
+                * to actually call into trustzone to run secure
+                * applications, which the mainline kernel probably
+                * will not do on this old chipset. But you can never
+                * be too careful, so reserve this memory anyway.
+                */
+               ram@17f00000 {
+                       reg = <0x17f00000 0x00100000>;
+                       no-map;
+               };
+       };
 };
index 48bd872..287804e 100644 (file)
                                            200000 0>;
                };
        };
+
+       reserved-memory {
+               #address-cells = <1>;
+               #size-cells = <1>;
+               ranges;
+
+               /* Modem trace memory */
+               ram@06000000 {
+                       reg = <0x06000000 0x00f00000>;
+                       no-map;
+               };
+
+               /* Modem shared memory */
+               ram@06f00000 {
+                       reg = <0x06f00000 0x00100000>;
+                       no-map;
+               };
+
+               /* Modem private memory */
+               ram@07000000 {
+                       reg = <0x07000000 0x01000000>;
+                       no-map;
+               };
+
+               /*
+                * Initial Secure Software ISSW memory
+                *
+                * This is probably only used if the kernel tries
+                * to actually call into trustzone to run secure
+                * applications, which the mainline kernel probably
+                * will not do on this old chipset. But you can never
+                * be too careful, so reserve this memory anyway.
+                */
+               ram@17f00000 {
+                       reg = <0x17f00000 0x00100000>;
+                       no-map;
+               };
+       };
 };
diff --git a/arch/arm/boot/dts/ste-db9500.dtsi b/arch/arm/boot/dts/ste-db9500.dtsi
new file mode 100644 (file)
index 0000000..0afff70
--- /dev/null
@@ -0,0 +1,35 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#include "ste-dbx5x0.dtsi"
+
+/ {
+       cpus {
+               cpu@300 {
+                       /* cpufreq controls */
+                       operating-points = <1152000 0
+                                           800000 0
+                                           400000 0
+                                           200000 0>;
+               };
+       };
+
+       reserved-memory {
+               #address-cells = <1>;
+               #size-cells = <1>;
+               ranges;
+
+               /*
+                * Initial Secure Software ISSW memory
+                *
+                * This is probably only used if the kernel tries
+                * to actually call into trustzone to run secure
+                * applications, which the mainline kernel probably
+                * will not do on this old chipset. But you can never
+                * be too careful, so reserve this memory anyway.
+                */
+               ram@17f00000 {
+                       reg = <0x17f00000 0x00100000>;
+                       no-map;
+               };
+       };
+};
index be90e73..27d8a07 100644 (file)
@@ -4,7 +4,7 @@
  */
 
 /dts-v1/;
-#include "ste-db8500.dtsi"
+#include "ste-db9500.dtsi"
 #include "ste-href-ab8500.dtsi"
 #include "ste-href-family-pinctrl.dtsi"
 
index 62ab238..5088dd3 100644 (file)
@@ -33,9 +33,9 @@
         * during TX anyway and that it only controls drive enable DE
         * line. Hence, the RX is always enabled here.
         */
-       rs485-rx-en {
+       rs485-rx-en-hog {
                gpio-hog;
-               gpios = <8 GPIO_ACTIVE_HIGH>;
+               gpios = <8 0>;
                output-low;
                line-name = "rs485-rx-en";
        };
@@ -61,9 +61,9 @@
         * order to reset the Hub when USB bus is powered down, but
         * so far there is no such functionality.
         */
-       usb-hub {
+       usb-hub-hog {
                gpio-hog;
-               gpios = <2 GPIO_ACTIVE_HIGH>;
+               gpios = <2 0>;
                output-high;
                line-name = "usb-hub-reset";
        };
        };
 };
 
+&i2c4 {
+       touchscreen@49 {
+               status = "disabled";
+       };
+};
+
 &i2c5 {        /* TP7/TP8 */
        pinctrl-names = "default";
        pinctrl-0 = <&i2c5_pins_a>;
         * are used for on-board microSD slot instead.
         */
        /delete-property/broken-cd;
-       cd-gpios = <&gpioi 10 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>;
+       cd-gpios = <&gpioi 10 GPIO_ACTIVE_HIGH>;
        disable-wp;
 };
 
index 356150d..32700cc 100644 (file)
@@ -43,9 +43,9 @@
         * in order to turn on port power when USB bus is powered up, but so
         * far there is no such functionality.
         */
-       usb-port-power {
+       usb-port-power-hog {
                gpio-hog;
-               gpios = <13 GPIO_ACTIVE_LOW>;
+               gpios = <13 0>;
                output-low;
                line-name = "usb-port-power";
        };
index ac46ab3..daff531 100644 (file)
        pinctrl-0 = <&sdmmc1_b4_pins_a &sdmmc1_dir_pins_a>;
        pinctrl-1 = <&sdmmc1_b4_od_pins_a &sdmmc1_dir_pins_a>;
        pinctrl-2 = <&sdmmc1_b4_sleep_pins_a &sdmmc1_dir_sleep_pins_a>;
-       broken-cd;
+       cd-gpios = <&gpiog 1 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>;
+       disable-wp;
        st,sig-dir;
        st,neg-edge;
        st,use-ckin;
index 01ccff7..5740f94 100644 (file)
        pinctrl-names = "default";
        pinctrl-0 = <&gmac_rgmii_pins>;
        phy-handle = <&phy1>;
-       phy-mode = "rgmii";
+       phy-mode = "rgmii-id";
        phy-supply = <&reg_gmac_3v3>;
        status = "okay";
 };
diff --git a/arch/arm/include/asm/kexec-internal.h b/arch/arm/include/asm/kexec-internal.h
new file mode 100644 (file)
index 0000000..ecc2322
--- /dev/null
@@ -0,0 +1,12 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef _ARM_KEXEC_INTERNAL_H
+#define _ARM_KEXEC_INTERNAL_H
+
+struct kexec_relocate_data {
+       unsigned long kexec_start_address;
+       unsigned long kexec_indirection_page;
+       unsigned long kexec_mach_type;
+       unsigned long kexec_r2;
+};
+
+#endif
index 98daa7f..7454480 100644 (file)
 
                .align
 99:            .word   .
+#if defined(ZIMAGE)
+               .word   . + 4
+/*
+ * Storage for the state maintained by the macro.
+ *
+ * In the kernel proper, this data is located in arch/arm/mach-tegra/tegra.c.
+ * That's because this header is included from multiple files, and we only
+ * want a single copy of the data. In particular, the UART probing code above
+ * assumes it's running using physical addresses. This is true when this file
+ * is included from head.o, but not when included from debug.o. So we need
+ * to share the probe results between the two copies, rather than having
+ * to re-run the probing again later.
+ *
+ * In the decompressor, we put the storage right here, since common.c
+ * isn't included in the decompressor build. This storage data gets put in
+ * .text even though it's really data, since .data is discarded from the
+ * decompressor. Luckily, .text is writeable in the decompressor, unless
+ * CONFIG_ZBOOT_ROM. That dependency is handled in arch/arm/Kconfig.debug.
+ */
+               /* Debug UART initialization required */
+               .word   1
+               /* Debug UART physical address */
+               .word   0
+               /* Debug UART virtual address */
+               .word   0
+#else
                .word   tegra_uart_config
+#endif
                .ltorg
 
                /* Load previously selected UART address */
 
                .macro  waituarttxrdy,rd,rx
                .endm
-
-/*
- * Storage for the state maintained by the macros above.
- *
- * In the kernel proper, this data is located in arch/arm/mach-tegra/tegra.c.
- * That's because this header is included from multiple files, and we only
- * want a single copy of the data. In particular, the UART probing code above
- * assumes it's running using physical addresses. This is true when this file
- * is included from head.o, but not when included from debug.o. So we need
- * to share the probe results between the two copies, rather than having
- * to re-run the probing again later.
- *
- * In the decompressor, we put the symbol/storage right here, since common.c
- * isn't included in the decompressor build. This symbol gets put in .text
- * even though it's really data, since .data is discarded from the
- * decompressor. Luckily, .text is writeable in the decompressor, unless
- * CONFIG_ZBOOT_ROM. That dependency is handled in arch/arm/Kconfig.debug.
- */
-#if defined(ZIMAGE)
-tegra_uart_config:
-       /* Debug UART initialization required */
-       .word 1
-       /* Debug UART physical address */
-       .word 0
-       /* Debug UART virtual address */
-       .word 0
-#endif
index a1570c8..be8050b 100644 (file)
@@ -12,6 +12,7 @@
 #include <linux/mm.h>
 #include <linux/dma-mapping.h>
 #include <asm/cacheflush.h>
+#include <asm/kexec-internal.h>
 #include <asm/glue-df.h>
 #include <asm/glue-pf.h>
 #include <asm/mach/arch.h>
@@ -170,5 +171,9 @@ int main(void)
   DEFINE(MPU_RGN_PRBAR,        offsetof(struct mpu_rgn, prbar));
   DEFINE(MPU_RGN_PRLAR,        offsetof(struct mpu_rgn, prlar));
 #endif
+  DEFINE(KEXEC_START_ADDR,     offsetof(struct kexec_relocate_data, kexec_start_address));
+  DEFINE(KEXEC_INDIR_PAGE,     offsetof(struct kexec_relocate_data, kexec_indirection_page));
+  DEFINE(KEXEC_MACH_TYPE,      offsetof(struct kexec_relocate_data, kexec_mach_type));
+  DEFINE(KEXEC_R2,             offsetof(struct kexec_relocate_data, kexec_r2));
   return 0; 
 }
index 5d84ad3..2b09dad 100644 (file)
@@ -13,6 +13,7 @@
 #include <linux/of_fdt.h>
 #include <asm/mmu_context.h>
 #include <asm/cacheflush.h>
+#include <asm/kexec-internal.h>
 #include <asm/fncpy.h>
 #include <asm/mach-types.h>
 #include <asm/smp_plat.h>
 extern void relocate_new_kernel(void);
 extern const unsigned int relocate_new_kernel_size;
 
-extern unsigned long kexec_start_address;
-extern unsigned long kexec_indirection_page;
-extern unsigned long kexec_mach_type;
-extern unsigned long kexec_boot_atags;
-
 static atomic_t waiting_for_crash_ipi;
 
 /*
@@ -159,6 +155,7 @@ void (*kexec_reinit)(void);
 void machine_kexec(struct kimage *image)
 {
        unsigned long page_list, reboot_entry_phys;
+       struct kexec_relocate_data *data;
        void (*reboot_entry)(void);
        void *reboot_code_buffer;
 
@@ -174,18 +171,17 @@ void machine_kexec(struct kimage *image)
 
        reboot_code_buffer = page_address(image->control_code_page);
 
-       /* Prepare parameters for reboot_code_buffer*/
-       set_kernel_text_rw();
-       kexec_start_address = image->start;
-       kexec_indirection_page = page_list;
-       kexec_mach_type = machine_arch_type;
-       kexec_boot_atags = image->arch.kernel_r2;
-
        /* copy our kernel relocation code to the control code page */
        reboot_entry = fncpy(reboot_code_buffer,
                             &relocate_new_kernel,
                             relocate_new_kernel_size);
 
+       data = reboot_code_buffer + relocate_new_kernel_size;
+       data->kexec_start_address = image->start;
+       data->kexec_indirection_page = page_list;
+       data->kexec_mach_type = machine_arch_type;
+       data->kexec_r2 = image->arch.kernel_r2;
+
        /* get the identity mapping physical address for the reboot code */
        reboot_entry_phys = virt_to_idmap(reboot_entry);
 
index 72a0878..218d524 100644 (file)
@@ -5,14 +5,16 @@
 
 #include <linux/linkage.h>
 #include <asm/assembler.h>
+#include <asm/asm-offsets.h>
 #include <asm/kexec.h>
 
        .align  3       /* not needed for this code, but keeps fncpy() happy */
 
 ENTRY(relocate_new_kernel)
 
-       ldr     r0,kexec_indirection_page
-       ldr     r1,kexec_start_address
+       adr     r7, relocate_new_kernel_end
+       ldr     r0, [r7, #KEXEC_INDIR_PAGE]
+       ldr     r1, [r7, #KEXEC_START_ADDR]
 
        /*
         * If there is no indirection page (we are doing crashdumps)
@@ -57,34 +59,16 @@ ENTRY(relocate_new_kernel)
 
 2:
        /* Jump to relocated kernel */
-       mov lr,r1
-       mov r0,#0
-       ldr r1,kexec_mach_type
-       ldr r2,kexec_boot_atags
- ARM(  ret lr  )
- THUMB(        bx lr           )
-
-       .align
-
-       .globl kexec_start_address
-kexec_start_address:
-       .long   0x0
-
-       .globl kexec_indirection_page
-kexec_indirection_page:
-       .long   0x0
-
-       .globl kexec_mach_type
-kexec_mach_type:
-       .long   0x0
-
-       /* phy addr of the atags for the new kernel */
-       .globl kexec_boot_atags
-kexec_boot_atags:
-       .long   0x0
+       mov     lr, r1
+       mov     r0, #0
+       ldr     r1, [r7, #KEXEC_MACH_TYPE]
+       ldr     r2, [r7, #KEXEC_R2]
+ ARM(  ret     lr      )
+ THUMB(        bx      lr      )
 
 ENDPROC(relocate_new_kernel)
 
+       .align  3
 relocate_new_kernel_end:
 
        .globl relocate_new_kernel_size
index 9d2e916..a3a38d0 100644 (file)
@@ -693,18 +693,20 @@ struct page *get_signal_page(void)
 
        addr = page_address(page);
 
+       /* Poison the entire page */
+       memset32(addr, __opcode_to_mem_arm(0xe7fddef1),
+                PAGE_SIZE / sizeof(u32));
+
        /* Give the signal return code some randomness */
        offset = 0x200 + (get_random_int() & 0x7fc);
        signal_return_offset = offset;
 
-       /*
-        * Copy signal return handlers into the vector page, and
-        * set sigreturn to be a pointer to these.
-        */
+       /* Copy signal return handlers into the page */
        memcpy(addr + offset, sigreturn_codes, sizeof(sigreturn_codes));
 
-       ptr = (unsigned long)addr + offset;
-       flush_icache_range(ptr, ptr + sizeof(sigreturn_codes));
+       /* Flush out all instructions in this page */
+       ptr = (unsigned long)addr;
+       flush_icache_range(ptr, ptr + PAGE_SIZE);
 
        return page;
 }
index 416462e..f9713dc 100644 (file)
@@ -65,15 +65,15 @@ dc21285_read_config(struct pci_bus *bus, unsigned int devfn, int where,
        if (addr)
                switch (size) {
                case 1:
-                       asm("ldrb       %0, [%1, %2]"
+                       asm volatile("ldrb      %0, [%1, %2]"
                                : "=r" (v) : "r" (addr), "r" (where) : "cc");
                        break;
                case 2:
-                       asm("ldrh       %0, [%1, %2]"
+                       asm volatile("ldrh      %0, [%1, %2]"
                                : "=r" (v) : "r" (addr), "r" (where) : "cc");
                        break;
                case 4:
-                       asm("ldr        %0, [%1, %2]"
+                       asm volatile("ldr       %0, [%1, %2]"
                                : "=r" (v) : "r" (addr), "r" (where) : "cc");
                        break;
                }
@@ -99,17 +99,17 @@ dc21285_write_config(struct pci_bus *bus, unsigned int devfn, int where,
        if (addr)
                switch (size) {
                case 1:
-                       asm("strb       %0, [%1, %2]"
+                       asm volatile("strb      %0, [%1, %2]"
                                : : "r" (value), "r" (addr), "r" (where)
                                : "cc");
                        break;
                case 2:
-                       asm("strh       %0, [%1, %2]"
+                       asm volatile("strh      %0, [%1, %2]"
                                : : "r" (value), "r" (addr), "r" (where)
                                : "cc");
                        break;
                case 4:
-                       asm("str        %0, [%1, %2]"
+                       asm volatile("str       %0, [%1, %2]"
                                : : "r" (value), "r" (addr), "r" (where)
                                : "cc");
                        break;
index 1eabf2d..e06f946 100644 (file)
@@ -67,6 +67,7 @@
 #define MX6Q_CCM_CCR   0x0
 
        .align 3
+       .arm
 
        .macro  sync_l2_cache
 
index a720259..0a4c9b0 100644 (file)
@@ -203,6 +203,8 @@ static int osk_tps_setup(struct i2c_client *client, void *context)
         */
        gpio_request(OSK_TPS_GPIO_USB_PWR_EN, "n_vbus_en");
        gpio_direction_output(OSK_TPS_GPIO_USB_PWR_EN, 1);
+       /* Free the GPIO again as the driver will request it */
+       gpio_free(OSK_TPS_GPIO_USB_PWR_EN);
 
        /* Set GPIO 2 high so LED D3 is off by default */
        tps65010_set_gpio_out_value(GPIO2, HIGH);
index 4a59c16..4178c0e 100644 (file)
@@ -17,11 +17,10 @@ config ARCH_OMAP3
        bool "TI OMAP3"
        depends on ARCH_MULTI_V7
        select ARCH_OMAP2PLUS
-       select ARM_CPU_SUSPEND if PM
+       select ARM_CPU_SUSPEND
        select OMAP_HWMOD
        select OMAP_INTERCONNECT
-       select PM_OPP if PM
-       select PM if CPU_IDLE
+       select PM_OPP
        select SOC_HAS_OMAP2_SDRC
        select ARM_ERRATA_430973
 
@@ -30,7 +29,7 @@ config ARCH_OMAP4
        depends on ARCH_MULTI_V7
        select ARCH_OMAP2PLUS
        select ARCH_NEEDS_CPU_IDLE_COUPLED if SMP
-       select ARM_CPU_SUSPEND if PM
+       select ARM_CPU_SUSPEND
        select ARM_ERRATA_720789
        select ARM_GIC
        select HAVE_ARM_SCU if SMP
@@ -40,7 +39,7 @@ config ARCH_OMAP4
        select OMAP_INTERCONNECT_BARRIER
        select PL310_ERRATA_588369 if CACHE_L2X0
        select PL310_ERRATA_727915 if CACHE_L2X0
-       select PM_OPP if PM
+       select PM_OPP
        select PM if CPU_IDLE
        select ARM_ERRATA_754322
        select ARM_ERRATA_775420
@@ -50,7 +49,7 @@ config SOC_OMAP5
        bool "TI OMAP5"
        depends on ARCH_MULTI_V7
        select ARCH_OMAP2PLUS
-       select ARM_CPU_SUSPEND if PM
+       select ARM_CPU_SUSPEND
        select ARM_GIC
        select HAVE_ARM_SCU if SMP
        select HAVE_ARM_ARCH_TIMER
@@ -58,14 +57,14 @@ config SOC_OMAP5
        select OMAP_HWMOD
        select OMAP_INTERCONNECT
        select OMAP_INTERCONNECT_BARRIER
-       select PM_OPP if PM
+       select PM_OPP
        select ZONE_DMA if ARM_LPAE
 
 config SOC_AM33XX
        bool "TI AM33XX"
        depends on ARCH_MULTI_V7
        select ARCH_OMAP2PLUS
-       select ARM_CPU_SUSPEND if PM
+       select ARM_CPU_SUSPEND
 
 config SOC_AM43XX
        bool "TI AM43x"
@@ -79,13 +78,13 @@ config SOC_AM43XX
        select ARM_ERRATA_754322
        select ARM_ERRATA_775420
        select OMAP_INTERCONNECT
-       select ARM_CPU_SUSPEND if PM
+       select ARM_CPU_SUSPEND
 
 config SOC_DRA7XX
        bool "TI DRA7XX"
        depends on ARCH_MULTI_V7
        select ARCH_OMAP2PLUS
-       select ARM_CPU_SUSPEND if PM
+       select ARM_CPU_SUSPEND
        select ARM_GIC
        select HAVE_ARM_SCU if SMP
        select HAVE_ARM_ARCH_TIMER
@@ -94,7 +93,7 @@ config SOC_DRA7XX
        select OMAP_HWMOD
        select OMAP_INTERCONNECT
        select OMAP_INTERCONNECT_BARRIER
-       select PM_OPP if PM
+       select PM_OPP
        select ZONE_DMA if ARM_LPAE
        select PINCTRL_TI_IODELAY if OF && PINCTRL
 
@@ -112,9 +111,11 @@ config ARCH_OMAP2PLUS
        select OMAP_DM_TIMER
        select OMAP_GPMC
        select PINCTRL
-       select PM_GENERIC_DOMAINS if PM
-       select PM_GENERIC_DOMAINS_OF if PM
+       select PM
+       select PM_GENERIC_DOMAINS
+       select PM_GENERIC_DOMAINS_OF
        select RESET_CONTROLLER
+       select SIMPLE_PM_BUS
        select SOC_BUS
        select TI_SYSC
        select OMAP_IRQCHIP
@@ -140,7 +141,6 @@ config ARCH_OMAP2PLUS_TYPICAL
        select I2C_OMAP
        select MENELAUS if ARCH_OMAP2
        select NEON if CPU_V7
-       select PM
        select REGULATOR
        select REGULATOR_FIXED_VOLTAGE
        select TWL4030_CORE if ARCH_OMAP3 || ARCH_OMAP4
index c8d317f..de37027 100644 (file)
@@ -151,10 +151,10 @@ static int omap_enter_idle_coupled(struct cpuidle_device *dev,
                                 (cx->mpu_logic_state == PWRDM_POWER_OFF);
 
        /* Enter broadcast mode for periodic timers */
-       tick_broadcast_enable();
+       RCU_NONIDLE(tick_broadcast_enable());
 
        /* Enter broadcast mode for one-shot timers */
-       tick_broadcast_enter();
+       RCU_NONIDLE(tick_broadcast_enter());
 
        /*
         * Call idle CPU PM enter notifier chain so that
@@ -166,7 +166,7 @@ static int omap_enter_idle_coupled(struct cpuidle_device *dev,
 
        if (dev->cpu == 0) {
                pwrdm_set_logic_retst(mpu_pd, cx->mpu_logic_state);
-               omap_set_pwrdm_state(mpu_pd, cx->mpu_state);
+               RCU_NONIDLE(omap_set_pwrdm_state(mpu_pd, cx->mpu_state));
 
                /*
                 * Call idle CPU cluster PM enter notifier chain
@@ -178,7 +178,7 @@ static int omap_enter_idle_coupled(struct cpuidle_device *dev,
                                index = 0;
                                cx = state_ptr + index;
                                pwrdm_set_logic_retst(mpu_pd, cx->mpu_logic_state);
-                               omap_set_pwrdm_state(mpu_pd, cx->mpu_state);
+                               RCU_NONIDLE(omap_set_pwrdm_state(mpu_pd, cx->mpu_state));
                                mpuss_can_lose_context = 0;
                        }
                }
@@ -194,9 +194,9 @@ static int omap_enter_idle_coupled(struct cpuidle_device *dev,
                    mpuss_can_lose_context)
                        gic_dist_disable();
 
-               clkdm_deny_idle(cpu_clkdm[1]);
-               omap_set_pwrdm_state(cpu_pd[1], PWRDM_POWER_ON);
-               clkdm_allow_idle(cpu_clkdm[1]);
+               RCU_NONIDLE(clkdm_deny_idle(cpu_clkdm[1]));
+               RCU_NONIDLE(omap_set_pwrdm_state(cpu_pd[1], PWRDM_POWER_ON));
+               RCU_NONIDLE(clkdm_allow_idle(cpu_clkdm[1]));
 
                if (IS_PM44XX_ERRATUM(PM_OMAP4_ROM_SMP_BOOT_ERRATUM_GICD) &&
                    mpuss_can_lose_context) {
@@ -222,7 +222,7 @@ static int omap_enter_idle_coupled(struct cpuidle_device *dev,
        cpu_pm_exit();
 
 cpu_pm_out:
-       tick_broadcast_exit();
+       RCU_NONIDLE(tick_broadcast_exit());
 
 fail:
        cpuidle_coupled_parallel_barrier(dev, &abort_barrier);
index cd38bf0..2e3a109 100644 (file)
@@ -522,6 +522,7 @@ static struct of_dev_auxdata omap_auxdata_lookup[] = {
                       &dra7_ipu1_dsp_iommu_pdata),
 #endif
        /* Common auxdata */
+       OF_DEV_AUXDATA("simple-pm-bus", 0, NULL, omap_auxdata_lookup),
        OF_DEV_AUXDATA("ti,sysc", 0, NULL, &ti_sysc_pdata),
        OF_DEV_AUXDATA("pinctrl-single", 0, NULL, &pcs_pdata),
        OF_DEV_AUXDATA("ti,omap-prm-inst", 0, NULL, &ti_prm_pdata),
index ba1c6df..d945c84 100644 (file)
                                      "timing-adjustment";
                        rx-fifo-depth = <4096>;
                        tx-fifo-depth = <2048>;
-                       resets = <&reset RESET_ETHERNET>;
-                       reset-names = "stmmaceth";
                        power-domains = <&pwrc PWRC_AXG_ETHERNET_MEM_ID>;
                        status = "disabled";
                };
index 9c90d56..b858c5e 100644 (file)
                                      "timing-adjustment";
                        rx-fifo-depth = <4096>;
                        tx-fifo-depth = <2048>;
-                       resets = <&reset RESET_ETHERNET>;
-                       reset-names = "stmmaceth";
                        status = "disabled";
 
                        mdio0: mdio {
                                interrupts = <GIC_SPI 30 IRQ_TYPE_LEVEL_HIGH>;
                                dr_mode = "host";
                                snps,dis_u2_susphy_quirk;
-                               snps,quirk-frame-length-adjustment;
+                               snps,quirk-frame-length-adjustment = <0x20>;
                                snps,parkmode-disable-ss-quirk;
                        };
                };
index 726b91d..0edd137 100644 (file)
@@ -13,7 +13,6 @@
 #include <dt-bindings/interrupt-controller/irq.h>
 #include <dt-bindings/interrupt-controller/arm-gic.h>
 #include <dt-bindings/power/meson-gxbb-power.h>
-#include <dt-bindings/reset/amlogic,meson-gxbb-reset.h>
 #include <dt-bindings/thermal/thermal.h>
 
 / {
                        interrupt-names = "macirq";
                        rx-fifo-depth = <4096>;
                        tx-fifo-depth = <2048>;
-                       resets = <&reset RESET_ETHERNET>;
-                       reset-names = "stmmaceth";
                        power-domains = <&pwrc PWRC_GXBB_ETHERNET_MEM_ID>;
                        status = "disabled";
                };
index cf5a98f..a712273 100644 (file)
@@ -52,7 +52,7 @@
                regulator-min-microvolt = <3300000>;
                regulator-max-microvolt = <3300000>;
 
-               gpio = <&gpio_ao GPIOAO_3 GPIO_ACTIVE_HIGH>;
+               gpio = <&gpio_ao GPIOAO_3 GPIO_OPEN_DRAIN>;
                enable-active-high;
                regulator-always-on;
        };
index aef8f2b..5401a64 100644 (file)
@@ -4,11 +4,16 @@
  */
        usb {
                compatible = "simple-bus";
-               dma-ranges;
                #address-cells = <2>;
                #size-cells = <2>;
                ranges = <0x0 0x0 0x0 0x68500000 0x0 0x00400000>;
 
+               /*
+                * Internally, USB bus to the interconnect can only address up
+                * to 40-bit
+                */
+               dma-ranges = <0 0 0 0 0x100 0x0>;
+
                usbphy0: usb-phy@0 {
                        compatible = "brcm,sr-usb-combo-phy";
                        reg = <0x0 0x00000000 0x0 0x100>;
index 60ff19f..6c8a61c 100644 (file)
        reboot {
                compatible ="syscon-reboot";
                regmap = <&rst>;
-               offset = <0xb0>;
+               offset = <0>;
                mask = <0x02>;
        };
 
index 025e1f5..565934c 100644 (file)
 
                dcfg: dcfg@1ee0000 {
                        compatible = "fsl,ls1046a-dcfg", "syscon";
-                       reg = <0x0 0x1ee0000 0x0 0x10000>;
+                       reg = <0x0 0x1ee0000 0x0 0x1000>;
                        big-endian;
                };
 
index ee17902..2a79e89 100644 (file)
                        #size-cells = <1>;
                        ranges;
 
-                       spba: bus@30000000 {
+                       spba: spba-bus@30000000 {
                                compatible = "fsl,spba-bus", "simple-bus";
                                #address-cells = <1>;
                                #size-cells = <1>;
index ecccfbb..23f5a5e 100644 (file)
                                #gpio-cells = <2>;
                                interrupt-controller;
                                #interrupt-cells = <2>;
-                               gpio-ranges = <&iomuxc 0 56 26>, <&iomuxc 0 144 4>;
+                               gpio-ranges = <&iomuxc 0 56 26>, <&iomuxc 26 144 4>;
                        };
 
                        gpio4: gpio@30230000 {
index 7cc2365..c0b9381 100644 (file)
 &gcc {
        protected-clocks = <GCC_QSPI_CORE_CLK>,
                           <GCC_QSPI_CORE_CLK_SRC>,
-                          <GCC_QSPI_CNOC_PERIPH_AHB_CLK>;
+                          <GCC_QSPI_CNOC_PERIPH_AHB_CLK>,
+                          <GCC_LPASS_Q6_AXI_CLK>,
+                          <GCC_LPASS_SWAY_CLK>;
 };
 
 &gpu {
index 13fdd02..8b40f96 100644 (file)
 &gcc {
        protected-clocks = <GCC_QSPI_CORE_CLK>,
                           <GCC_QSPI_CORE_CLK_SRC>,
-                          <GCC_QSPI_CNOC_PERIPH_AHB_CLK>;
+                          <GCC_QSPI_CNOC_PERIPH_AHB_CLK>,
+                          <GCC_LPASS_Q6_AXI_CLK>,
+                          <GCC_LPASS_SWAY_CLK>;
 };
 
 &gpu {
 &i2c3 {
        status = "okay";
        clock-frequency = <400000>;
+       /* Overwrite pinctrl-0 from sdm845.dtsi */
+       pinctrl-0 = <&qup_i2c3_default &i2c3_hid_active>;
 
        tsel: hid@15 {
                compatible = "hid-over-i2c";
                hid-descr-addr = <0x1>;
 
                interrupts-extended = <&tlmm 37 IRQ_TYPE_LEVEL_HIGH>;
-
-               pinctrl-names = "default";
-               pinctrl-0 = <&i2c3_hid_active>;
        };
 
        tsc2: hid@2c {
                hid-descr-addr = <0x20>;
 
                interrupts-extended = <&tlmm 37 IRQ_TYPE_LEVEL_HIGH>;
-
-               pinctrl-names = "default";
-               pinctrl-0 = <&i2c3_hid_active>;
-
-               status = "disabled";
        };
 };
 
index 2695ea8..6419329 100644 (file)
        vopl_mmu: iommu@ff470f00 {
                compatible = "rockchip,iommu";
                reg = <0x0 0xff470f00 0x0 0x100>;
-               interrupts = <GIC_SPI 79 IRQ_TYPE_LEVEL_HIGH>;
+               interrupts = <GIC_SPI 78 IRQ_TYPE_LEVEL_HIGH>;
                interrupt-names = "vopl_mmu";
                clocks = <&cru ACLK_VOPL>, <&cru HCLK_VOPL>;
                clock-names = "aclk", "iface";
index 2ee07d1..1eecad7 100644 (file)
        cpu-supply = <&vdd_arm>;
 };
 
+&display_subsystem {
+       status = "disabled";
+};
+
 &gmac2io {
        assigned-clocks = <&cru SCLK_MAC2IO>, <&cru SCLK_MAC2IO_EXT>;
        assigned-clock-parents = <&gmac_clk>, <&gmac_clk>;
index 06d4833..219b750 100644 (file)
 &pcie0 {
        bus-scan-delay-ms = <1000>;
        ep-gpios = <&gpio2 RK_PD4 GPIO_ACTIVE_HIGH>;
-       max-link-speed = <2>;
        num-lanes = <4>;
        pinctrl-names = "default";
        pinctrl-0 = <&pcie_clkreqn_cpm>;
index f5dee5f..2551b23 100644 (file)
                reg = <0x0 0xf8000000 0x0 0x2000000>,
                      <0x0 0xfd000000 0x0 0x1000000>;
                reg-names = "axi-base", "apb-base";
+               device_type = "pci";
                #address-cells = <3>;
                #size-cells = <2>;
                #interrupt-cells = <1>;
                                <0 0 0 2 &pcie0_intc 1>,
                                <0 0 0 3 &pcie0_intc 2>,
                                <0 0 0 4 &pcie0_intc 3>;
-               linux,pci-domain = <0>;
                max-link-speed = <1>;
                msi-map = <0x0 &its 0x0 0x1000>;
                phys = <&pcie_phy 0>, <&pcie_phy 1>,
                compatible = "rockchip,rk3399-vdec";
                reg = <0x0 0xff660000 0x0 0x400>;
                interrupts = <GIC_SPI 116 IRQ_TYPE_LEVEL_HIGH 0>;
-               interrupt-names = "vdpu";
                clocks = <&cru ACLK_VDU>, <&cru HCLK_VDU>,
                         <&cru SCLK_VDU_CA>, <&cru SCLK_VDU_CORE>;
                clock-names = "axi", "ahb", "cabac", "core";
index 8383016..01aa3ee 100644 (file)
@@ -991,8 +991,6 @@ CONFIG_ARCH_TEGRA_210_SOC=y
 CONFIG_ARCH_TEGRA_186_SOC=y
 CONFIG_ARCH_TEGRA_194_SOC=y
 CONFIG_ARCH_TEGRA_234_SOC=y
-CONFIG_ARCH_K3_AM6_SOC=y
-CONFIG_ARCH_K3_J721E_SOC=y
 CONFIG_TI_SCI_PM_DOMAINS=y
 CONFIG_EXTCON_PTN5150=m
 CONFIG_EXTCON_USB_GPIO=y
@@ -1078,7 +1076,7 @@ CONFIG_INTERCONNECT=y
 CONFIG_INTERCONNECT_QCOM=y
 CONFIG_INTERCONNECT_QCOM_MSM8916=m
 CONFIG_INTERCONNECT_QCOM_OSM_L3=m
-CONFIG_INTERCONNECT_QCOM_SDM845=m
+CONFIG_INTERCONNECT_QCOM_SDM845=y
 CONFIG_INTERCONNECT_QCOM_SM8150=m
 CONFIG_INTERCONNECT_QCOM_SM8250=m
 CONFIG_EXT2_FS=y
index 18fce22..ff47327 100644 (file)
@@ -247,11 +247,13 @@ static inline const void *__tag_set(const void *addr, u8 tag)
 
 
 /*
- * The linear kernel range starts at the bottom of the virtual address space.
+ * Check whether an arbitrary address is within the linear map, which
+ * lives in the [PAGE_OFFSET, PAGE_END) interval at the bottom of the
+ * kernel's TTBR1 address range.
  */
-#define __is_lm_address(addr)  (((u64)(addr) & ~PAGE_OFFSET) < (PAGE_END - PAGE_OFFSET))
+#define __is_lm_address(addr)  (((u64)(addr) PAGE_OFFSET) < (PAGE_END - PAGE_OFFSET))
 
-#define __lm_to_phys(addr)     (((addr) & ~PAGE_OFFSET) + PHYS_OFFSET)
+#define __lm_to_phys(addr)     (((addr) PAGE_OFFSET) + PHYS_OFFSET)
 #define __kimg_to_phys(addr)   ((addr) - kimage_voffset)
 
 #define __virt_to_phys_nodebug(x) ({                                   \
@@ -330,7 +332,7 @@ static inline void *phys_to_virt(phys_addr_t x)
 #endif /* !CONFIG_SPARSEMEM_VMEMMAP || CONFIG_DEBUG_VIRTUAL */
 
 #define virt_addr_valid(addr)  ({                                      \
-       __typeof__(addr) __addr = addr;                                 \
+       __typeof__(addr) __addr = __tag_reset(addr);                    \
        __is_lm_address(__addr) && pfn_valid(virt_to_pfn(__addr));      \
 })
 
index 89c64ad..66aac28 100644 (file)
@@ -352,8 +352,8 @@ kprobe_breakpoint_ss_handler(struct pt_regs *regs, unsigned int esr)
        unsigned long addr = instruction_pointer(regs);
        struct kprobe *cur = kprobe_running();
 
-       if (cur && (kcb->kprobe_status == KPROBE_HIT_SS)
-           && ((unsigned long)&cur->ainsn.api.insn[1] == addr)) {
+       if (cur && (kcb->kprobe_status & (KPROBE_HIT_SS | KPROBE_REENTER)) &&
+           ((unsigned long)&cur->ainsn.api.insn[1] == addr)) {
                kprobes_restore_local_irqflag(kcb, regs);
                post_kprobe_handler(cur, kcb, regs);
 
index 04c4485..fe60d25 100644 (file)
@@ -1396,8 +1396,9 @@ static void cpu_init_hyp_mode(void)
         * Calculate the raw per-cpu offset without a translation from the
         * kernel's mapping to the linear mapping, and store it in tpidr_el2
         * so that we can use adr_l to access per-cpu variables in EL2.
+        * Also drop the KASAN tag which gets in the way...
         */
-       params->tpidr_el2 = (unsigned long)this_cpu_ptr_nvhe_sym(__per_cpu_start) -
+       params->tpidr_el2 = (unsigned long)kasan_reset_tag(this_cpu_ptr_nvhe_sym(__per_cpu_start)) -
                            (unsigned long)kvm_ksym_ref(CHOOSE_NVHE_SYM(__per_cpu_start));
 
        params->mair_el2 = read_sysreg(mair_el1);
index 31b060a..b17bf19 100644 (file)
@@ -47,6 +47,8 @@ __invalid:
        b       .
 
        /*
+        * Only uses x0..x3 so as to not clobber callee-saved SMCCC registers.
+        *
         * x0: SMCCC function ID
         * x1: struct kvm_nvhe_init_params PA
         */
@@ -70,9 +72,9 @@ __do_hyp_init:
        eret
 
 1:     mov     x0, x1
-       mov     x4, lr
-       bl      ___kvm_hyp_init
-       mov     lr, x4
+       mov     x3, lr
+       bl      ___kvm_hyp_init                 // Clobbers x0..x2
+       mov     lr, x3
 
        /* Hello, World! */
        mov     x0, #SMCCC_RET_SUCCESS
@@ -82,8 +84,8 @@ SYM_CODE_END(__kvm_hyp_init)
 /*
  * Initialize the hypervisor in EL2.
  *
- * Only uses x0..x3 so as to not clobber callee-saved SMCCC registers
- * and leave x4 for the caller.
+ * Only uses x0..x2 so as to not clobber callee-saved SMCCC registers
+ * and leave x3 for the caller.
  *
  * x0: struct kvm_nvhe_init_params PA
  */
@@ -112,9 +114,9 @@ alternative_else_nop_endif
        /*
         * Set the PS bits in TCR_EL2.
         */
-       ldr     x1, [x0, #NVHE_INIT_TCR_EL2]
-       tcr_compute_pa_size x1, #TCR_EL2_PS_SHIFT, x2, x3
-       msr     tcr_el2, x1
+       ldr     x0, [x0, #NVHE_INIT_TCR_EL2]
+       tcr_compute_pa_size x0, #TCR_EL2_PS_SHIFT, x1, x2
+       msr     tcr_el2, x0
 
        isb
 
@@ -193,7 +195,7 @@ SYM_CODE_START_LOCAL(__kvm_hyp_init_cpu)
 
        /* Enable MMU, set vectors and stack. */
        mov     x0, x28
-       bl      ___kvm_hyp_init                 // Clobbers x0..x3
+       bl      ___kvm_hyp_init                 // Clobbers x0..x2
 
        /* Leave idmap. */
        mov     x0, x29
index e394784..8e7128c 100644 (file)
@@ -77,12 +77,6 @@ static unsigned long psci_forward(struct kvm_cpu_context *host_ctxt)
                         cpu_reg(host_ctxt, 2), cpu_reg(host_ctxt, 3));
 }
 
-static __noreturn unsigned long psci_forward_noreturn(struct kvm_cpu_context *host_ctxt)
-{
-       psci_forward(host_ctxt);
-       hyp_panic(); /* unreachable */
-}
-
 static unsigned int find_cpu_id(u64 mpidr)
 {
        unsigned int i;
@@ -251,10 +245,13 @@ static unsigned long psci_0_2_handler(u64 func_id, struct kvm_cpu_context *host_
        case PSCI_0_2_FN_MIGRATE_INFO_TYPE:
        case PSCI_0_2_FN64_MIGRATE_INFO_UP_CPU:
                return psci_forward(host_ctxt);
+       /*
+        * SYSTEM_OFF/RESET should not return according to the spec.
+        * Allow it so as to stay robust to broken firmware.
+        */
        case PSCI_0_2_FN_SYSTEM_OFF:
        case PSCI_0_2_FN_SYSTEM_RESET:
-               psci_forward_noreturn(host_ctxt);
-               unreachable();
+               return psci_forward(host_ctxt);
        case PSCI_0_2_FN64_CPU_SUSPEND:
                return psci_cpu_suspend(func_id, host_ctxt);
        case PSCI_0_2_FN64_CPU_ON:
index 4ad66a5..247422a 100644 (file)
@@ -788,7 +788,7 @@ u64 kvm_pmu_get_pmceid(struct kvm_vcpu *vcpu, bool pmceid1)
 {
        unsigned long *bmap = vcpu->kvm->arch.pmu_filter;
        u64 val, mask = 0;
-       int base, i;
+       int base, i, nr_events;
 
        if (!pmceid1) {
                val = read_sysreg(pmceid0_el0);
@@ -801,13 +801,17 @@ u64 kvm_pmu_get_pmceid(struct kvm_vcpu *vcpu, bool pmceid1)
        if (!bmap)
                return val;
 
+       nr_events = kvm_pmu_event_mask(vcpu->kvm) + 1;
+
        for (i = 0; i < 32; i += 8) {
                u64 byte;
 
                byte = bitmap_get_value8(bmap, base + i);
                mask |= byte << i;
-               byte = bitmap_get_value8(bmap, 0x4000 + base + i);
-               mask |= byte << (32 + i);
+               if (nr_events >= (0x4000 + base + 32)) {
+                       byte = bitmap_get_value8(bmap, 0x4000 + base + i);
+                       mask |= byte << (32 + i);
+               }
        }
 
        return val & mask;
index 42ccc27..7c4f795 100644 (file)
  * 64bit interface.
  */
 
+#define reg_to_encoding(x)                                             \
+       sys_reg((u32)(x)->Op0, (u32)(x)->Op1,                           \
+               (u32)(x)->CRn, (u32)(x)->CRm, (u32)(x)->Op2)
+
 static bool read_from_write_only(struct kvm_vcpu *vcpu,
                                 struct sys_reg_params *params,
                                 const struct sys_reg_desc *r)
@@ -273,8 +277,7 @@ static bool trap_loregion(struct kvm_vcpu *vcpu,
                          const struct sys_reg_desc *r)
 {
        u64 val = read_sanitised_ftr_reg(SYS_ID_AA64MMFR1_EL1);
-       u32 sr = sys_reg((u32)r->Op0, (u32)r->Op1,
-                        (u32)r->CRn, (u32)r->CRm, (u32)r->Op2);
+       u32 sr = reg_to_encoding(r);
 
        if (!(val & (0xfUL << ID_AA64MMFR1_LOR_SHIFT))) {
                kvm_inject_undefined(vcpu);
@@ -590,6 +593,15 @@ static void reset_mpidr(struct kvm_vcpu *vcpu, const struct sys_reg_desc *r)
        vcpu_write_sys_reg(vcpu, (1ULL << 31) | mpidr, MPIDR_EL1);
 }
 
+static unsigned int pmu_visibility(const struct kvm_vcpu *vcpu,
+                                  const struct sys_reg_desc *r)
+{
+       if (kvm_vcpu_has_pmu(vcpu))
+               return 0;
+
+       return REG_HIDDEN;
+}
+
 static void reset_pmcr(struct kvm_vcpu *vcpu, const struct sys_reg_desc *r)
 {
        u64 pmcr, val;
@@ -613,9 +625,8 @@ static void reset_pmcr(struct kvm_vcpu *vcpu, const struct sys_reg_desc *r)
 static bool check_pmu_access_disabled(struct kvm_vcpu *vcpu, u64 flags)
 {
        u64 reg = __vcpu_sys_reg(vcpu, PMUSERENR_EL0);
-       bool enabled = kvm_vcpu_has_pmu(vcpu);
+       bool enabled = (reg & flags) || vcpu_mode_priv(vcpu);
 
-       enabled &= (reg & flags) || vcpu_mode_priv(vcpu);
        if (!enabled)
                kvm_inject_undefined(vcpu);
 
@@ -900,11 +911,6 @@ static bool access_pmswinc(struct kvm_vcpu *vcpu, struct sys_reg_params *p,
 static bool access_pmuserenr(struct kvm_vcpu *vcpu, struct sys_reg_params *p,
                             const struct sys_reg_desc *r)
 {
-       if (!kvm_vcpu_has_pmu(vcpu)) {
-               kvm_inject_undefined(vcpu);
-               return false;
-       }
-
        if (p->is_write) {
                if (!vcpu_mode_priv(vcpu)) {
                        kvm_inject_undefined(vcpu);
@@ -921,10 +927,6 @@ static bool access_pmuserenr(struct kvm_vcpu *vcpu, struct sys_reg_params *p,
        return true;
 }
 
-#define reg_to_encoding(x)                                             \
-       sys_reg((u32)(x)->Op0, (u32)(x)->Op1,                           \
-               (u32)(x)->CRn, (u32)(x)->CRm, (u32)(x)->Op2)
-
 /* Silly macro to expand the DBG{BCR,BVR,WVR,WCR}n_EL1 registers in one go */
 #define DBG_BCR_BVR_WCR_WVR_EL1(n)                                     \
        { SYS_DESC(SYS_DBGBVRn_EL1(n)),                                 \
@@ -936,15 +938,18 @@ static bool access_pmuserenr(struct kvm_vcpu *vcpu, struct sys_reg_params *p,
        { SYS_DESC(SYS_DBGWCRn_EL1(n)),                                 \
          trap_wcr, reset_wcr, 0, 0,  get_wcr, set_wcr }
 
+#define PMU_SYS_REG(r)                                         \
+       SYS_DESC(r), .reset = reset_unknown, .visibility = pmu_visibility
+
 /* Macro to expand the PMEVCNTRn_EL0 register */
 #define PMU_PMEVCNTR_EL0(n)                                            \
-       { SYS_DESC(SYS_PMEVCNTRn_EL0(n)),                                       \
-         access_pmu_evcntr, reset_unknown, (PMEVCNTR0_EL0 + n), }
+       { PMU_SYS_REG(SYS_PMEVCNTRn_EL0(n)),                            \
+         .access = access_pmu_evcntr, .reg = (PMEVCNTR0_EL0 + n), }
 
 /* Macro to expand the PMEVTYPERn_EL0 register */
 #define PMU_PMEVTYPER_EL0(n)                                           \
-       { SYS_DESC(SYS_PMEVTYPERn_EL0(n)),                                      \
-         access_pmu_evtyper, reset_unknown, (PMEVTYPER0_EL0 + n), }
+       { PMU_SYS_REG(SYS_PMEVTYPERn_EL0(n)),                           \
+         .access = access_pmu_evtyper, .reg = (PMEVTYPER0_EL0 + n), }
 
 static bool undef_access(struct kvm_vcpu *vcpu, struct sys_reg_params *p,
                         const struct sys_reg_desc *r)
@@ -1020,8 +1025,7 @@ static bool access_arch_timer(struct kvm_vcpu *vcpu,
 static u64 read_id_reg(const struct kvm_vcpu *vcpu,
                struct sys_reg_desc const *r, bool raz)
 {
-       u32 id = sys_reg((u32)r->Op0, (u32)r->Op1,
-                        (u32)r->CRn, (u32)r->CRm, (u32)r->Op2);
+       u32 id = reg_to_encoding(r);
        u64 val = raz ? 0 : read_sanitised_ftr_reg(id);
 
        if (id == SYS_ID_AA64PFR0_EL1) {
@@ -1062,8 +1066,7 @@ static u64 read_id_reg(const struct kvm_vcpu *vcpu,
 static unsigned int id_visibility(const struct kvm_vcpu *vcpu,
                                  const struct sys_reg_desc *r)
 {
-       u32 id = sys_reg((u32)r->Op0, (u32)r->Op1,
-                        (u32)r->CRn, (u32)r->CRm, (u32)r->Op2);
+       u32 id = reg_to_encoding(r);
 
        switch (id) {
        case SYS_ID_AA64ZFR0_EL1:
@@ -1486,8 +1489,10 @@ static const struct sys_reg_desc sys_reg_descs[] = {
        { SYS_DESC(SYS_FAR_EL1), access_vm_reg, reset_unknown, FAR_EL1 },
        { SYS_DESC(SYS_PAR_EL1), NULL, reset_unknown, PAR_EL1 },
 
-       { SYS_DESC(SYS_PMINTENSET_EL1), access_pminten, reset_unknown, PMINTENSET_EL1 },
-       { SYS_DESC(SYS_PMINTENCLR_EL1), access_pminten, reset_unknown, PMINTENSET_EL1 },
+       { PMU_SYS_REG(SYS_PMINTENSET_EL1),
+         .access = access_pminten, .reg = PMINTENSET_EL1 },
+       { PMU_SYS_REG(SYS_PMINTENCLR_EL1),
+         .access = access_pminten, .reg = PMINTENSET_EL1 },
 
        { SYS_DESC(SYS_MAIR_EL1), access_vm_reg, reset_unknown, MAIR_EL1 },
        { SYS_DESC(SYS_AMAIR_EL1), access_vm_reg, reset_amair_el1, AMAIR_EL1 },
@@ -1526,23 +1531,36 @@ static const struct sys_reg_desc sys_reg_descs[] = {
        { SYS_DESC(SYS_CSSELR_EL1), access_csselr, reset_unknown, CSSELR_EL1 },
        { SYS_DESC(SYS_CTR_EL0), access_ctr },
 
-       { SYS_DESC(SYS_PMCR_EL0), access_pmcr, reset_pmcr, PMCR_EL0 },
-       { SYS_DESC(SYS_PMCNTENSET_EL0), access_pmcnten, reset_unknown, PMCNTENSET_EL0 },
-       { SYS_DESC(SYS_PMCNTENCLR_EL0), access_pmcnten, reset_unknown, PMCNTENSET_EL0 },
-       { SYS_DESC(SYS_PMOVSCLR_EL0), access_pmovs, reset_unknown, PMOVSSET_EL0 },
-       { SYS_DESC(SYS_PMSWINC_EL0), access_pmswinc, reset_unknown, PMSWINC_EL0 },
-       { SYS_DESC(SYS_PMSELR_EL0), access_pmselr, reset_unknown, PMSELR_EL0 },
-       { SYS_DESC(SYS_PMCEID0_EL0), access_pmceid },
-       { SYS_DESC(SYS_PMCEID1_EL0), access_pmceid },
-       { SYS_DESC(SYS_PMCCNTR_EL0), access_pmu_evcntr, reset_unknown, PMCCNTR_EL0 },
-       { SYS_DESC(SYS_PMXEVTYPER_EL0), access_pmu_evtyper },
-       { SYS_DESC(SYS_PMXEVCNTR_EL0), access_pmu_evcntr },
+       { PMU_SYS_REG(SYS_PMCR_EL0), .access = access_pmcr,
+         .reset = reset_pmcr, .reg = PMCR_EL0 },
+       { PMU_SYS_REG(SYS_PMCNTENSET_EL0),
+         .access = access_pmcnten, .reg = PMCNTENSET_EL0 },
+       { PMU_SYS_REG(SYS_PMCNTENCLR_EL0),
+         .access = access_pmcnten, .reg = PMCNTENSET_EL0 },
+       { PMU_SYS_REG(SYS_PMOVSCLR_EL0),
+         .access = access_pmovs, .reg = PMOVSSET_EL0 },
+       { PMU_SYS_REG(SYS_PMSWINC_EL0),
+         .access = access_pmswinc, .reg = PMSWINC_EL0 },
+       { PMU_SYS_REG(SYS_PMSELR_EL0),
+         .access = access_pmselr, .reg = PMSELR_EL0 },
+       { PMU_SYS_REG(SYS_PMCEID0_EL0),
+         .access = access_pmceid, .reset = NULL },
+       { PMU_SYS_REG(SYS_PMCEID1_EL0),
+         .access = access_pmceid, .reset = NULL },
+       { PMU_SYS_REG(SYS_PMCCNTR_EL0),
+         .access = access_pmu_evcntr, .reg = PMCCNTR_EL0 },
+       { PMU_SYS_REG(SYS_PMXEVTYPER_EL0),
+         .access = access_pmu_evtyper, .reset = NULL },
+       { PMU_SYS_REG(SYS_PMXEVCNTR_EL0),
+         .access = access_pmu_evcntr, .reset = NULL },
        /*
         * PMUSERENR_EL0 resets as unknown in 64bit mode while it resets as zero
         * in 32bit mode. Here we choose to reset it as zero for consistency.
         */
-       { SYS_DESC(SYS_PMUSERENR_EL0), access_pmuserenr, reset_val, PMUSERENR_EL0, 0 },
-       { SYS_DESC(SYS_PMOVSSET_EL0), access_pmovs, reset_unknown, PMOVSSET_EL0 },
+       { PMU_SYS_REG(SYS_PMUSERENR_EL0), .access = access_pmuserenr,
+         .reset = reset_val, .reg = PMUSERENR_EL0, .val = 0 },
+       { PMU_SYS_REG(SYS_PMOVSSET_EL0),
+         .access = access_pmovs, .reg = PMOVSSET_EL0 },
 
        { SYS_DESC(SYS_TPIDR_EL0), NULL, reset_unknown, TPIDR_EL0 },
        { SYS_DESC(SYS_TPIDRRO_EL0), NULL, reset_unknown, TPIDRRO_EL0 },
@@ -1694,7 +1712,8 @@ static const struct sys_reg_desc sys_reg_descs[] = {
         * PMCCFILTR_EL0 resets as unknown in 64bit mode while it resets as zero
         * in 32bit mode. Here we choose to reset it as zero for consistency.
         */
-       { SYS_DESC(SYS_PMCCFILTR_EL0), access_pmu_evtyper, reset_val, PMCCFILTR_EL0, 0 },
+       { PMU_SYS_REG(SYS_PMCCFILTR_EL0), .access = access_pmu_evtyper,
+         .reset = reset_val, .reg = PMCCFILTR_EL0, .val = 0 },
 
        { SYS_DESC(SYS_DACR32_EL2), NULL, reset_unknown, DACR32_EL2 },
        { SYS_DESC(SYS_IFSR32_EL2), NULL, reset_unknown, IFSR32_EL2 },
index 3c40da4..35d75c6 100644 (file)
@@ -709,10 +709,11 @@ static int do_tag_check_fault(unsigned long far, unsigned int esr,
                              struct pt_regs *regs)
 {
        /*
-        * The architecture specifies that bits 63:60 of FAR_EL1 are UNKNOWN for tag
-        * check faults. Mask them out now so that userspace doesn't see them.
+        * The architecture specifies that bits 63:60 of FAR_EL1 are UNKNOWN
+        * for tag check faults. Set them to corresponding bits in the untagged
+        * address.
         */
-       far &= (1UL << 60) - 1;
+       far = (__untagged_addr(far) & ~MTE_TAG_MASK) | (far & MTE_TAG_MASK);
        do_bad_area(far, esr, regs);
        return 0;
 }
index 67a9ba9..cde44c1 100644 (file)
@@ -9,7 +9,7 @@
 
 phys_addr_t __virt_to_phys(unsigned long x)
 {
-       WARN(!__is_lm_address(x),
+       WARN(!__is_lm_address(__tag_reset(x)),
             "virt_to_phys used for non-linear address: %pK (%pS)\n",
              (void *)x,
              (void *)x);
index 703b1c4..45d5368 100644 (file)
@@ -69,7 +69,7 @@ vmlinux.bin: vmlinux FORCE
        $(call if_changed,objcopy)
 
 unwcheck: vmlinux
-       -$(Q)READELF=$(READELF) $(PYTHON) $(srctree)/arch/ia64/scripts/unwcheck.py $<
+       -$(Q)READELF=$(READELF) $(PYTHON3) $(srctree)/arch/ia64/scripts/unwcheck.py $<
 
 archclean:
 
index dd8c166..42ed524 100644 (file)
@@ -3,6 +3,7 @@
 #define _ASM_IA64_SPARSEMEM_H
 
 #ifdef CONFIG_SPARSEMEM
+#include <asm/page.h>
 /*
  * SECTION_SIZE_BITS            2^N: how big each section will be
  * MAX_PHYSMEM_BITS             2^N: how much memory we can have in that space
index d69c979..5d90307 100644 (file)
@@ -54,7 +54,7 @@ extern void ia64_xchg_called_with_bad_pointer(void);
 })
 
 #define xchg(ptr, x)                                                   \
-((__typeof__(*(ptr))) __xchg((unsigned long) (x), (ptr), sizeof(*(ptr))))
+({(__typeof__(*(ptr))) __xchg((unsigned long) (x), (ptr), sizeof(*(ptr)));})
 
 /*
  * Atomic compare and exchange.  Compare OLD with MEM, if identical,
index ed9fc3d..43e8050 100644 (file)
@@ -171,29 +171,34 @@ void vtime_account_hardirq(struct task_struct *tsk)
 static irqreturn_t
 timer_interrupt (int irq, void *dev_id)
 {
-       unsigned long cur_itm, new_itm, ticks;
+       unsigned long new_itm;
 
        if (cpu_is_offline(smp_processor_id())) {
                return IRQ_HANDLED;
        }
 
        new_itm = local_cpu_data->itm_next;
-       cur_itm = ia64_get_itc();
 
-       if (!time_after(cur_itm, new_itm)) {
+       if (!time_after(ia64_get_itc(), new_itm))
                printk(KERN_ERR "Oops: timer tick before it's due (itc=%lx,itm=%lx)\n",
-                      cur_itm, new_itm);
-               ticks = 1;
-       } else {
-               ticks = DIV_ROUND_UP(cur_itm - new_itm,
-                                    local_cpu_data->itm_delta);
-               new_itm += ticks * local_cpu_data->itm_delta;
-       }
+                      ia64_get_itc(), new_itm);
+
+       while (1) {
+               new_itm += local_cpu_data->itm_delta;
+
+               legacy_timer_tick(smp_processor_id() == time_keeper_id);
 
-       if (smp_processor_id() != time_keeper_id)
-               ticks = 0;
+               local_cpu_data->itm_next = new_itm;
 
-       legacy_timer_tick(ticks);
+               if (time_after(new_itm, ia64_get_itc()))
+                       break;
+
+               /*
+                * Allow IPIs to interrupt the timer loop.
+                */
+               local_irq_enable();
+               local_irq_disable();
+       }
 
        do {
                /*
index bfd1b67..9581742 100644 (file)
@@ -1,4 +1,4 @@
-#!/usr/bin/env python
+#!/usr/bin/env python3
 # SPDX-License-Identifier: GPL-2.0
 #
 # Usage: unwcheck.py FILE
index 19edf8e..292d042 100644 (file)
@@ -51,6 +51,7 @@ extern void kmap_flush_tlb(unsigned long addr);
 
 #define flush_cache_kmaps()    BUG_ON(cpu_has_dc_aliases)
 
+#define arch_kmap_local_set_pte(mm, vaddr, ptep, ptev) set_pte(ptep, ptev)
 #define arch_kmap_local_post_map(vaddr, pteval)        local_flush_tlb_one(vaddr)
 #define arch_kmap_local_post_unmap(vaddr)      local_flush_tlb_one(vaddr)
 
index 7d6b4a7..c298061 100644 (file)
@@ -31,7 +31,7 @@
 void __iomem *ioremap(phys_addr_t offset, unsigned long size);
 
 #define iounmap iounmap
-extern void iounmap(void *addr);
+extern void iounmap(void __iomem *addr);
 
 #include <asm-generic/io.h>
 
index 5aed97a..daae13a 100644 (file)
@@ -77,7 +77,7 @@ void __iomem *__ref ioremap(phys_addr_t addr, unsigned long size)
 }
 EXPORT_SYMBOL(ioremap);
 
-void iounmap(void *addr)
+void iounmap(void __iomem *addr)
 {
        /* If the page is from the fixmap pool then we just clear out
         * the fixmap mapping.
index 78b1762..2784621 100644 (file)
@@ -202,9 +202,8 @@ config PREFETCH
        depends on PA8X00 || PA7200
 
 config MLONGCALLS
-       bool "Enable the -mlong-calls compiler option for big kernels"
-       default y if !MODULES || UBSAN || FTRACE
-       default n
+       def_bool y if !MODULES || UBSAN || FTRACE
+       bool "Enable the -mlong-calls compiler option for big kernels" if MODULES && !UBSAN && !FTRACE
        depends on PA8X00
        help
          If you configure the kernel to include many drivers built-in instead
index 959e79c..378f63c 100644 (file)
@@ -47,7 +47,4 @@ extern unsigned long txn_affinity_addr(unsigned int irq, int cpu);
 extern int cpu_claim_irq(unsigned int irq, struct irq_chip *, void *);
 extern int cpu_check_affinity(struct irq_data *d, const struct cpumask *dest);
 
-/* soft power switch support (power.c) */
-extern struct tasklet_struct power_tasklet;
-
 #endif /* _ASM_PARISC_IRQ_H */
index beba981..4d37cc9 100644 (file)
@@ -997,10 +997,17 @@ intr_do_preempt:
        bb,<,n  %r20, 31 - PSW_SM_I, intr_restore
        nop
 
+       /* ssm PSW_SM_I done later in intr_restore */
+#ifdef CONFIG_MLONGCALLS
+       ldil    L%intr_restore, %r2
+       load32  preempt_schedule_irq, %r1
+       bv      %r0(%r1)
+       ldo     R%intr_restore(%r2), %r2
+#else
+       ldil    L%intr_restore, %r1
        BL      preempt_schedule_irq, %r2
-       nop
-
-       b,n     intr_restore            /* ssm PSW_SM_I done by intr_restore */
+       ldo     R%intr_restore(%r1), %r2
+#endif
 #endif /* CONFIG_PREEMPTION */
 
        /*
index 1d32b17..c1a8aac 100644 (file)
        nop;                                                            \
        nop;
 
+#define SCV_ENTRY_FLUSH_SLOT                                           \
+       SCV_ENTRY_FLUSH_FIXUP_SECTION;                                  \
+       nop;                                                            \
+       nop;                                                            \
+       nop;
+
 /*
  * r10 must be free to use, r13 must be paca
  */
        STF_ENTRY_BARRIER_SLOT;                                         \
        ENTRY_FLUSH_SLOT
 
+/*
+ * r10, ctr must be free to use, r13 must be paca
+ */
+#define SCV_INTERRUPT_TO_KERNEL                                                \
+       STF_ENTRY_BARRIER_SLOT;                                         \
+       SCV_ENTRY_FLUSH_SLOT
+
 /*
  * Macros for annotating the expected destination of (h)rfid
  *
index f6d2acb..ac605fc 100644 (file)
@@ -240,6 +240,14 @@ label##3:                                          \
        FTR_ENTRY_OFFSET 957b-958b;                     \
        .popsection;
 
+#define SCV_ENTRY_FLUSH_FIXUP_SECTION                  \
+957:                                                   \
+       .pushsection __scv_entry_flush_fixup,"a";       \
+       .align 2;                                       \
+958:                                                   \
+       FTR_ENTRY_OFFSET 957b-958b;                     \
+       .popsection;
+
 #define RFI_FLUSH_FIXUP_SECTION                                \
 951:                                                   \
        .pushsection __rfi_flush_fixup,"a";             \
@@ -273,10 +281,12 @@ label##3:                                         \
 
 extern long stf_barrier_fallback;
 extern long entry_flush_fallback;
+extern long scv_entry_flush_fallback;
 extern long __start___stf_entry_barrier_fixup, __stop___stf_entry_barrier_fixup;
 extern long __start___stf_exit_barrier_fixup, __stop___stf_exit_barrier_fixup;
 extern long __start___uaccess_flush_fixup, __stop___uaccess_flush_fixup;
 extern long __start___entry_flush_fixup, __stop___entry_flush_fixup;
+extern long __start___scv_entry_flush_fixup, __stop___scv_entry_flush_fixup;
 extern long __start___rfi_flush_fixup, __stop___rfi_flush_fixup;
 extern long __start___barrier_nospec_fixup, __stop___barrier_nospec_fixup;
 extern long __start__btb_flush_fixup, __stop__btb_flush_fixup;
index 80a5ae7..c0fcd1b 100644 (file)
@@ -58,6 +58,8 @@ extern pte_t *pkmap_page_table;
 
 #define flush_cache_kmaps()    flush_cache_all()
 
+#define arch_kmap_local_set_pte(mm, vaddr, ptep, ptev) \
+       __set_pte_at(mm, vaddr, ptep, ptev, 1)
 #define arch_kmap_local_post_map(vaddr, pteval)        \
        local_flush_tlb_page(NULL, vaddr)
 #define arch_kmap_local_post_unmap(vaddr)      \
index fe2ef59..79ee775 100644 (file)
@@ -51,7 +51,7 @@ obj-y                         += ptrace/
 obj-$(CONFIG_PPC64)            += setup_64.o \
                                   paca.o nvram_64.o note.o syscall_64.o
 obj-$(CONFIG_COMPAT)           += sys_ppc32.o signal_32.o
-obj-$(CONFIG_VDSO32)           += vdso32/
+obj-$(CONFIG_VDSO32)           += vdso32_wrapper.o
 obj-$(CONFIG_PPC_WATCHDOG)     += watchdog.o
 obj-$(CONFIG_HAVE_HW_BREAKPOINT)       += hw_breakpoint.o
 obj-$(CONFIG_PPC_DAWR)         += dawr.o
@@ -60,7 +60,7 @@ obj-$(CONFIG_PPC_BOOK3S_64)   += cpu_setup_power.o
 obj-$(CONFIG_PPC_BOOK3S_64)    += mce.o mce_power.o
 obj-$(CONFIG_PPC_BOOK3E_64)    += exceptions-64e.o idle_book3e.o
 obj-$(CONFIG_PPC_BARRIER_NOSPEC) += security.o
-obj-$(CONFIG_PPC64)            += vdso64/
+obj-$(CONFIG_PPC64)            += vdso64_wrapper.o
 obj-$(CONFIG_ALTIVEC)          += vecemu.o
 obj-$(CONFIG_PPC_BOOK3S_IDLE)  += idle_book3s.o
 procfs-y                       := proc_powerpc.o
index aa1af13..33ddfee 100644 (file)
@@ -75,7 +75,7 @@ BEGIN_FTR_SECTION
        bne     .Ltabort_syscall
 END_FTR_SECTION_IFSET(CPU_FTR_TM)
 #endif
-       INTERRUPT_TO_KERNEL
+       SCV_INTERRUPT_TO_KERNEL
        mr      r10,r1
        ld      r1,PACAKSAVE(r13)
        std     r10,0(r1)
index e02ad6f..6e53f76 100644 (file)
@@ -2993,6 +2993,25 @@ TRAMP_REAL_BEGIN(entry_flush_fallback)
        ld      r11,PACA_EXRFI+EX_R11(r13)
        blr
 
+/*
+ * The SCV entry flush happens with interrupts enabled, so it must disable
+ * to prevent EXRFI being clobbered by NMIs (e.g., soft_nmi_common). r10
+ * (containing LR) does not need to be preserved here because scv entry
+ * puts 0 in the pt_regs, CTR can be clobbered for the same reason.
+ */
+TRAMP_REAL_BEGIN(scv_entry_flush_fallback)
+       li      r10,0
+       mtmsrd  r10,1
+       lbz     r10,PACAIRQHAPPENED(r13)
+       ori     r10,r10,PACA_IRQ_HARD_DIS
+       stb     r10,PACAIRQHAPPENED(r13)
+       std     r11,PACA_EXRFI+EX_R11(r13)
+       L1D_DISPLACEMENT_FLUSH
+       ld      r11,PACA_EXRFI+EX_R11(r13)
+       li      r10,MSR_RI
+       mtmsrd  r10,1
+       blr
+
 TRAMP_REAL_BEGIN(rfi_flush_fallback)
        SET_SCRATCH0(r13);
        GET_PACA(r13);
index 6b1eca5..cc7a627 100644 (file)
@@ -180,13 +180,18 @@ void notrace restore_interrupts(void)
 
 void replay_soft_interrupts(void)
 {
+       struct pt_regs regs;
+
        /*
-        * We use local_paca rather than get_paca() to avoid all
-        * the debug_smp_processor_id() business in this low level
-        * function
+        * Be careful here, calling these interrupt handlers can cause
+        * softirqs to be raised, which they may run when calling irq_exit,
+        * which will cause local_irq_enable() to be run, which can then
+        * recurse into this function. Don't keep any state across
+        * interrupt handler calls which may change underneath us.
+        *
+        * We use local_paca rather than get_paca() to avoid all the
+        * debug_smp_processor_id() business in this low level function.
         */
-       unsigned char happened = local_paca->irq_happened;
-       struct pt_regs regs;
 
        ppc_save_regs(&regs);
        regs.softe = IRQS_ENABLED;
@@ -209,7 +214,7 @@ again:
         * This is a higher priority interrupt than the others, so
         * replay it first.
         */
-       if (IS_ENABLED(CONFIG_PPC_BOOK3S) && (happened & PACA_IRQ_HMI)) {
+       if (IS_ENABLED(CONFIG_PPC_BOOK3S) && (local_paca->irq_happened & PACA_IRQ_HMI)) {
                local_paca->irq_happened &= ~PACA_IRQ_HMI;
                regs.trap = 0xe60;
                handle_hmi_exception(&regs);
@@ -217,7 +222,7 @@ again:
                        hard_irq_disable();
        }
 
-       if (happened & PACA_IRQ_DEC) {
+       if (local_paca->irq_happened & PACA_IRQ_DEC) {
                local_paca->irq_happened &= ~PACA_IRQ_DEC;
                regs.trap = 0x900;
                timer_interrupt(&regs);
@@ -225,7 +230,7 @@ again:
                        hard_irq_disable();
        }
 
-       if (happened & PACA_IRQ_EE) {
+       if (local_paca->irq_happened & PACA_IRQ_EE) {
                local_paca->irq_happened &= ~PACA_IRQ_EE;
                regs.trap = 0x500;
                do_IRQ(&regs);
@@ -233,7 +238,7 @@ again:
                        hard_irq_disable();
        }
 
-       if (IS_ENABLED(CONFIG_PPC_DOORBELL) && (happened & PACA_IRQ_DBELL)) {
+       if (IS_ENABLED(CONFIG_PPC_DOORBELL) && (local_paca->irq_happened & PACA_IRQ_DBELL)) {
                local_paca->irq_happened &= ~PACA_IRQ_DBELL;
                if (IS_ENABLED(CONFIG_PPC_BOOK3E))
                        regs.trap = 0x280;
@@ -245,7 +250,7 @@ again:
        }
 
        /* Book3E does not support soft-masking PMI interrupts */
-       if (IS_ENABLED(CONFIG_PPC_BOOK3S) && (happened & PACA_IRQ_PMI)) {
+       if (IS_ENABLED(CONFIG_PPC_BOOK3S) && (local_paca->irq_happened & PACA_IRQ_PMI)) {
                local_paca->irq_happened &= ~PACA_IRQ_PMI;
                regs.trap = 0xf00;
                performance_monitor_exception(&regs);
@@ -253,8 +258,7 @@ again:
                        hard_irq_disable();
        }
 
-       happened = local_paca->irq_happened;
-       if (happened & ~PACA_IRQ_HARD_DIS) {
+       if (local_paca->irq_happened & ~PACA_IRQ_HARD_DIS) {
                /*
                 * We are responding to the next interrupt, so interrupt-off
                 * latencies should be reset here.
index 9cb6f52..7d9a6fe 100644 (file)
@@ -30,7 +30,7 @@ CC32FLAGS += -m32
 KBUILD_CFLAGS := $(filter-out -mcmodel=medium -mabi=elfv1 -mabi=elfv2 -mcall-aixdesc,$(KBUILD_CFLAGS))
 endif
 
-targets := $(obj-vdso32) vdso32.so.dbg
+targets := $(obj-vdso32) vdso32.so.dbg vgettimeofday.o
 obj-vdso32 := $(addprefix $(obj)/, $(obj-vdso32))
 
 GCOV_PROFILE := n
@@ -46,9 +46,6 @@ obj-y += vdso32_wrapper.o
 targets += vdso32.lds
 CPPFLAGS_vdso32.lds += -P -C -Upowerpc
 
-# Force dependency (incbin is bad)
-$(obj)/vdso32_wrapper.o : $(obj)/vdso32.so.dbg
-
 # link rule for the .so file, .lds has to be first
 $(obj)/vdso32.so.dbg: $(src)/vdso32.lds $(obj-vdso32) $(obj)/vgettimeofday.o FORCE
        $(call if_changed,vdso32ld_and_check)
diff --git a/arch/powerpc/kernel/vdso32/vdso32_wrapper.S b/arch/powerpc/kernel/vdso32/vdso32_wrapper.S
deleted file mode 100644 (file)
index 3f5ef03..0000000
+++ /dev/null
@@ -1,14 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 */
-#include <linux/linkage.h>
-#include <asm/page.h>
-
-       __PAGE_ALIGNED_DATA
-
-       .globl vdso32_start, vdso32_end
-       .balign PAGE_SIZE
-vdso32_start:
-       .incbin "arch/powerpc/kernel/vdso32/vdso32.so.dbg"
-       .balign PAGE_SIZE
-vdso32_end:
-
-       .previous
diff --git a/arch/powerpc/kernel/vdso32_wrapper.S b/arch/powerpc/kernel/vdso32_wrapper.S
new file mode 100644 (file)
index 0000000..3f5ef03
--- /dev/null
@@ -0,0 +1,14 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#include <linux/linkage.h>
+#include <asm/page.h>
+
+       __PAGE_ALIGNED_DATA
+
+       .globl vdso32_start, vdso32_end
+       .balign PAGE_SIZE
+vdso32_start:
+       .incbin "arch/powerpc/kernel/vdso32/vdso32.so.dbg"
+       .balign PAGE_SIZE
+vdso32_end:
+
+       .previous
index bf363ff..2813e3f 100644 (file)
@@ -17,7 +17,7 @@ endif
 
 # Build rules
 
-targets := $(obj-vdso64) vdso64.so.dbg
+targets := $(obj-vdso64) vdso64.so.dbg vgettimeofday.o
 obj-vdso64 := $(addprefix $(obj)/, $(obj-vdso64))
 
 GCOV_PROFILE := n
@@ -29,15 +29,9 @@ ccflags-y := -shared -fno-common -fno-builtin -nostdlib \
        -Wl,-soname=linux-vdso64.so.1 -Wl,--hash-style=both
 asflags-y := -D__VDSO64__ -s
 
-obj-y += vdso64_wrapper.o
 targets += vdso64.lds
 CPPFLAGS_vdso64.lds += -P -C -U$(ARCH)
 
-$(obj)/vgettimeofday.o: %.o: %.c FORCE
-
-# Force dependency (incbin is bad)
-$(obj)/vdso64_wrapper.o : $(obj)/vdso64.so.dbg
-
 # link rule for the .so file, .lds has to be first
 $(obj)/vdso64.so.dbg: $(src)/vdso64.lds $(obj-vdso64) $(obj)/vgettimeofday.o FORCE
        $(call if_changed,vdso64ld_and_check)
index bbf68cd..2d40675 100644 (file)
 
        .text
 
+/*
+ * __kernel_start_sigtramp_rt64 and __kernel_sigtramp_rt64 together
+ * are one function split in two parts. The kernel jumps to the former
+ * and the signal handler indirectly (by blr) returns to the latter.
+ * __kernel_sigtramp_rt64 needs to point to the return address so
+ * glibc can correctly identify the trampoline stack frame.
+ */
        .balign 8
        .balign IFETCH_ALIGN_BYTES
-V_FUNCTION_BEGIN(__kernel_sigtramp_rt64)
+V_FUNCTION_BEGIN(__kernel_start_sigtramp_rt64)
 .Lsigrt_start:
        bctrl   /* call the handler */
+V_FUNCTION_END(__kernel_start_sigtramp_rt64)
+V_FUNCTION_BEGIN(__kernel_sigtramp_rt64)
        addi    r1, r1, __SIGNAL_FRAMESIZE
        li      r0,__NR_rt_sigreturn
        sc
index 6164d1a..2f3c359 100644 (file)
@@ -131,4 +131,4 @@ VERSION
 /*
  * Make the sigreturn code visible to the kernel.
  */
-VDSO_sigtramp_rt64     = __kernel_sigtramp_rt64;
+VDSO_sigtramp_rt64     = __kernel_start_sigtramp_rt64;
diff --git a/arch/powerpc/kernel/vdso64/vdso64_wrapper.S b/arch/powerpc/kernel/vdso64/vdso64_wrapper.S
deleted file mode 100644 (file)
index 1d56d81..0000000
+++ /dev/null
@@ -1,14 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 */
-#include <linux/linkage.h>
-#include <asm/page.h>
-
-       __PAGE_ALIGNED_DATA
-
-       .globl vdso64_start, vdso64_end
-       .balign PAGE_SIZE
-vdso64_start:
-       .incbin "arch/powerpc/kernel/vdso64/vdso64.so.dbg"
-       .balign PAGE_SIZE
-vdso64_end:
-
-       .previous
diff --git a/arch/powerpc/kernel/vdso64_wrapper.S b/arch/powerpc/kernel/vdso64_wrapper.S
new file mode 100644 (file)
index 0000000..1d56d81
--- /dev/null
@@ -0,0 +1,14 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#include <linux/linkage.h>
+#include <asm/page.h>
+
+       __PAGE_ALIGNED_DATA
+
+       .globl vdso64_start, vdso64_end
+       .balign PAGE_SIZE
+vdso64_start:
+       .incbin "arch/powerpc/kernel/vdso64/vdso64.so.dbg"
+       .balign PAGE_SIZE
+vdso64_end:
+
+       .previous
index 4ab426b..72fa3c0 100644 (file)
@@ -145,6 +145,13 @@ SECTIONS
                __stop___entry_flush_fixup = .;
        }
 
+       . = ALIGN(8);
+       __scv_entry_flush_fixup : AT(ADDR(__scv_entry_flush_fixup) - LOAD_OFFSET) {
+               __start___scv_entry_flush_fixup = .;
+               *(__scv_entry_flush_fixup)
+               __stop___scv_entry_flush_fixup = .;
+       }
+
        . = ALIGN(8);
        __stf_exit_barrier_fixup : AT(ADDR(__stf_exit_barrier_fixup) - LOAD_OFFSET) {
                __start___stf_exit_barrier_fixup = .;
index 4782105..1fd31b4 100644 (file)
@@ -290,9 +290,6 @@ void do_entry_flush_fixups(enum l1d_flush_type types)
        long *start, *end;
        int i;
 
-       start = PTRRELOC(&__start___entry_flush_fixup);
-       end = PTRRELOC(&__stop___entry_flush_fixup);
-
        instrs[0] = 0x60000000; /* nop */
        instrs[1] = 0x60000000; /* nop */
        instrs[2] = 0x60000000; /* nop */
@@ -312,6 +309,8 @@ void do_entry_flush_fixups(enum l1d_flush_type types)
        if (types & L1D_FLUSH_MTTRIG)
                instrs[i++] = 0x7c12dba6; /* mtspr TRIG2,r0 (SPR #882) */
 
+       start = PTRRELOC(&__start___entry_flush_fixup);
+       end = PTRRELOC(&__stop___entry_flush_fixup);
        for (i = 0; start < end; start++, i++) {
                dest = (void *)start + *start;
 
@@ -328,6 +327,25 @@ void do_entry_flush_fixups(enum l1d_flush_type types)
                patch_instruction((struct ppc_inst *)(dest + 2), ppc_inst(instrs[2]));
        }
 
+       start = PTRRELOC(&__start___scv_entry_flush_fixup);
+       end = PTRRELOC(&__stop___scv_entry_flush_fixup);
+       for (; start < end; start++, i++) {
+               dest = (void *)start + *start;
+
+               pr_devel("patching dest %lx\n", (unsigned long)dest);
+
+               patch_instruction((struct ppc_inst *)dest, ppc_inst(instrs[0]));
+
+               if (types == L1D_FLUSH_FALLBACK)
+                       patch_branch((struct ppc_inst *)(dest + 1), (unsigned long)&scv_entry_flush_fallback,
+                                    BRANCH_SET_LINK);
+               else
+                       patch_instruction((struct ppc_inst *)(dest + 1), ppc_inst(instrs[1]));
+
+               patch_instruction((struct ppc_inst *)(dest + 2), ppc_inst(instrs[2]));
+       }
+
+
        printk(KERN_DEBUG "entry-flush: patched %d locations (%s flush)\n", i,
                (types == L1D_FLUSH_NONE)       ? "no" :
                (types == L1D_FLUSH_FALLBACK)   ? "fallback displacement" :
index bf7a7d6..ede093e 100644 (file)
@@ -818,13 +818,15 @@ void emulate_vsx_store(struct instruction_op *op, const union vsx_reg *reg,
                        break;
                if (rev) {
                        /* reverse 32 bytes */
-                       buf.d[0] = byterev_8(reg->d[3]);
-                       buf.d[1] = byterev_8(reg->d[2]);
-                       buf.d[2] = byterev_8(reg->d[1]);
-                       buf.d[3] = byterev_8(reg->d[0]);
-                       reg = &buf;
+                       union vsx_reg buf32[2];
+                       buf32[0].d[0] = byterev_8(reg[1].d[1]);
+                       buf32[0].d[1] = byterev_8(reg[1].d[0]);
+                       buf32[1].d[0] = byterev_8(reg[0].d[1]);
+                       buf32[1].d[1] = byterev_8(reg[0].d[0]);
+                       memcpy(mem, buf32, size);
+               } else {
+                       memcpy(mem, reg, size);
                }
-               memcpy(mem, reg, size);
                break;
        case 16:
                /* stxv, stxvx, stxvl, stxvll */
index e9e2c1f..e0a34eb 100644 (file)
@@ -252,8 +252,10 @@ choice
        default MAXPHYSMEM_128GB if 64BIT && CMODEL_MEDANY
 
        config MAXPHYSMEM_1GB
+               depends on 32BIT
                bool "1GiB"
        config MAXPHYSMEM_2GB
+               depends on 64BIT && CMODEL_MEDLOW
                bool "2GiB"
        config MAXPHYSMEM_128GB
                depends on 64BIT && CMODEL_MEDANY
index 2d50f76..64a675c 100644 (file)
@@ -135,7 +135,10 @@ extern phys_addr_t __phys_addr_symbol(unsigned long x);
 
 #endif /* __ASSEMBLY__ */
 
-#define virt_addr_valid(vaddr) (pfn_valid(virt_to_pfn(vaddr)))
+#define virt_addr_valid(vaddr) ({                                              \
+       unsigned long _addr = (unsigned long)vaddr;                             \
+       (unsigned long)(_addr) >= PAGE_OFFSET && pfn_valid(virt_to_pfn(_addr)); \
+})
 
 #define VM_DATA_DEFAULT_FLAGS  VM_DATA_FLAGS_NON_EXEC
 
index 211eb82..8b80c80 100644 (file)
@@ -32,14 +32,14 @@ bool kernel_page_present(struct page *page);
 
 #endif /* __ASSEMBLY__ */
 
-#ifdef CONFIG_ARCH_HAS_STRICT_KERNEL_RWX
+#ifdef CONFIG_STRICT_KERNEL_RWX
 #ifdef CONFIG_64BIT
 #define SECTION_ALIGN (1 << 21)
 #else
 #define SECTION_ALIGN (1 << 22)
 #endif
-#else /* !CONFIG_ARCH_HAS_STRICT_KERNEL_RWX */
+#else /* !CONFIG_STRICT_KERNEL_RWX */
 #define SECTION_ALIGN L1_CACHE_BYTES
-#endif /* CONFIG_ARCH_HAS_STRICT_KERNEL_RWX */
+#endif /* CONFIG_STRICT_KERNEL_RWX */
 
 #endif /* _ASM_RISCV_SET_MEMORY_H */
index 3fa3f26..c7c0655 100644 (file)
@@ -293,6 +293,8 @@ void free_initmem(void)
        unsigned long init_begin = (unsigned long)__init_begin;
        unsigned long init_end = (unsigned long)__init_end;
 
-       set_memory_rw_nx(init_begin, (init_end - init_begin) >> PAGE_SHIFT);
+       if (IS_ENABLED(CONFIG_STRICT_KERNEL_RWX))
+               set_memory_rw_nx(init_begin, (init_end - init_begin) >> PAGE_SHIFT);
+
        free_initmem_default(POISON_FREE_INITMEM);
 }
index 7cd4993..f9f9568 100644 (file)
@@ -196,7 +196,7 @@ void __init setup_bootmem(void)
        max_pfn = PFN_DOWN(dram_end);
        max_low_pfn = max_pfn;
        dma32_phys_limit = min(4UL * SZ_1G, (unsigned long)PFN_PHYS(max_low_pfn));
-       set_max_mapnr(max_low_pfn);
+       set_max_mapnr(max_low_pfn - ARCH_PFN_OFFSET);
 
 #ifdef CONFIG_BLK_DEV_INITRD
        setup_initrd();
index a15c033..87641dd 100644 (file)
@@ -35,7 +35,7 @@ void uv_query_info(void)
                uv_info.guest_cpu_stor_len = uvcb.cpu_stor_len;
                uv_info.max_sec_stor_addr = ALIGN(uvcb.max_guest_stor_addr, PAGE_SIZE);
                uv_info.max_num_sec_conf = uvcb.max_num_sec_conf;
-               uv_info.max_guest_cpus = uvcb.max_guest_cpus;
+               uv_info.max_guest_cpu_id = uvcb.max_guest_cpu_id;
        }
 
 #ifdef CONFIG_PROTECTED_VIRTUALIZATION_GUEST
index 0325fc0..7b98d4c 100644 (file)
@@ -96,7 +96,7 @@ struct uv_cb_qui {
        u32 max_num_sec_conf;
        u64 max_guest_stor_addr;
        u8  reserved88[158 - 136];
-       u16 max_guest_cpus;
+       u16 max_guest_cpu_id;
        u8  reserveda0[200 - 160];
 } __packed __aligned(8);
 
@@ -273,7 +273,7 @@ struct uv_info {
        unsigned long guest_cpu_stor_len;
        unsigned long max_sec_stor_addr;
        unsigned int max_num_sec_conf;
-       unsigned short max_guest_cpus;
+       unsigned short max_guest_cpu_id;
 };
 
 extern struct uv_info uv_info;
index 883bfed..b2d2ad1 100644 (file)
@@ -368,7 +368,7 @@ static ssize_t uv_query_max_guest_cpus(struct kobject *kobj,
                                       struct kobj_attribute *attr, char *page)
 {
        return scnprintf(page, PAGE_SIZE, "%d\n",
-                       uv_info.max_guest_cpus);
+                       uv_info.max_guest_cpu_id + 1);
 }
 
 static struct kobj_attribute uv_query_max_guest_cpus_attr =
index 5fa5802..52646f5 100644 (file)
@@ -29,7 +29,6 @@ config SUPERH
        select HAVE_ARCH_KGDB
        select HAVE_ARCH_SECCOMP_FILTER
        select HAVE_ARCH_TRACEHOOK
-       select HAVE_COPY_THREAD_TLS
        select HAVE_DEBUG_BUGVERBOSE
        select HAVE_DEBUG_KMEMLEAK
        select HAVE_DYNAMIC_FTRACE
index 8b23ed7..7fb4748 100644 (file)
@@ -11,7 +11,6 @@
 #include <linux/sched.h>
 #include <linux/time.h>
 #include <linux/bcd.h>
-#include <linux/rtc.h>
 #include <linux/spinlock.h>
 #include <linux/io.h>
 #include <linux/rtc.h>
index ba6ec04..e6c5ddf 100644 (file)
@@ -27,13 +27,12 @@ CONFIG_NETFILTER=y
 CONFIG_ATALK=m
 CONFIG_BLK_DEV_LOOP=y
 CONFIG_BLK_DEV_RAM=y
-CONFIG_IDE=y
-CONFIG_BLK_DEV_IDECD=y
-CONFIG_BLK_DEV_OFFBOARD=y
-CONFIG_BLK_DEV_GENERIC=y
-CONFIG_BLK_DEV_AEC62XX=y
+CONFIG_ATA=y
+CONFIG_ATA_GENERIC=y
+CONFIG_PATA_ATP867X=y
 CONFIG_SCSI=y
 CONFIG_BLK_DEV_SD=y
+CONFIG_BLK_DEV_SR=y
 CONFIG_SCSI_MULTI_LUN=y
 CONFIG_MD=y
 CONFIG_BLK_DEV_MD=m
index c65667d..e982519 100644 (file)
@@ -20,8 +20,6 @@ CONFIG_IP_PNP=y
 # CONFIG_IPV6 is not set
 # CONFIG_FW_LOADER is not set
 CONFIG_BLK_DEV_RAM=y
-CONFIG_IDE=y
-CONFIG_BLK_DEV_IDECD=y
 CONFIG_NETDEVICES=y
 CONFIG_NET_ETHERNET=y
 CONFIG_SMC91X=y
index d10a041..d00376e 100644 (file)
@@ -44,16 +44,14 @@ CONFIG_NET_SCHED=y
 CONFIG_PARPORT=y
 CONFIG_BLK_DEV_LOOP=y
 CONFIG_BLK_DEV_RAM=y
-CONFIG_IDE=y
-CONFIG_BLK_DEV_IDECD=y
-CONFIG_BLK_DEV_PLATFORM=y
-CONFIG_BLK_DEV_GENERIC=y
 CONFIG_BLK_DEV_SD=y
 CONFIG_BLK_DEV_SR=y
 CONFIG_CHR_DEV_SG=y
 CONFIG_SCSI_SPI_ATTRS=y
 CONFIG_SCSI_FC_ATTRS=y
 CONFIG_ATA=y
+CONFIG_ATA_GENERIC=y
+CONFIG_PATA_PLATFORM=y
 CONFIG_MD=y
 CONFIG_BLK_DEV_DM=y
 CONFIG_NETDEVICES=y
index 61bec46..4a44cac 100644 (file)
@@ -116,9 +116,6 @@ CONFIG_MTD_UBI_GLUEBI=m
 CONFIG_BLK_DEV_LOOP=y
 CONFIG_BLK_DEV_CRYPTOLOOP=y
 CONFIG_BLK_DEV_RAM=y
-CONFIG_IDE=y
-CONFIG_BLK_DEV_IDECD=y
-CONFIG_BLK_DEV_PLATFORM=y
 CONFIG_BLK_DEV_SD=y
 CONFIG_BLK_DEV_SR=y
 CONFIG_SCSI_MULTI_LUN=y
index 3f1c137..4defc76 100644 (file)
@@ -29,7 +29,6 @@ CONFIG_MTD_BLOCK=y
 CONFIG_MTD_CFI=y
 CONFIG_MTD_CFI_AMDSTD=y
 CONFIG_MTD_ROM=y
-CONFIG_IDE=y
 CONFIG_SCSI=y
 CONFIG_NETDEVICES=y
 CONFIG_NET_ETHERNET=y
index f0073ed..48b457d 100644 (file)
@@ -39,9 +39,6 @@ CONFIG_IP_PNP_RARP=y
 CONFIG_BLK_DEV_LOOP=y
 CONFIG_BLK_DEV_NBD=y
 CONFIG_BLK_DEV_RAM=y
-CONFIG_IDE=y
-CONFIG_BLK_DEV_IDECD=m
-CONFIG_BLK_DEV_IDETAPE=m
 CONFIG_SCSI=m
 CONFIG_BLK_DEV_SD=m
 CONFIG_BLK_DEV_SR=m
index d0de378..7d54f28 100644 (file)
@@ -63,8 +63,7 @@ config PVR2_DMA
 
 config G2_DMA
        tristate "G2 Bus DMA support"
-       depends on SH_DREAMCAST
-       select SH_DMA_API
+       depends on SH_DREAMCAST && SH_DMA_API
        help
          This enables support for the DMA controller for the Dreamcast's
          G2 bus. Drivers that want this will generally enable this on
index 3519188..d643250 100644 (file)
@@ -16,7 +16,6 @@
 #include <cpu/gpio.h>
 #endif
 
-#define ARCH_NR_GPIOS 512
 #include <asm-generic/gpio.h>
 
 #ifdef CONFIG_GPIOLIB
index 25eb809..e48b3dd 100644 (file)
@@ -14,7 +14,6 @@
 #include <cpu/mmu_context.h>
 #include <asm/page.h>
 #include <asm/cache.h>
-#include <asm/thread_info.h>
 
 ! NOTE:
 ! GNU as (as of 2.9.1) changes bf/s into bt/s and bra, when the address
index 703d306..77aa2f8 100644 (file)
@@ -105,7 +105,7 @@ config VSYSCALL
          (the default value) say Y.
 
 config NUMA
-       bool "Non Uniform Memory Access (NUMA) Support"
+       bool "Non-Uniform Memory Access (NUMA) Support"
        depends on MMU && SYS_SUPPORTS_NUMA
        select ARCH_WANT_NUMA_VARIABLE_LOCALITY
        default n
index 4c1ca19..d16d6f5 100644 (file)
@@ -26,7 +26,7 @@
 #include <asm/processor.h>
 #include <asm/mmu_context.h>
 
-static int asids_seq_show(struct seq_file *file, void *iter)
+static int asids_debugfs_show(struct seq_file *file, void *iter)
 {
        struct task_struct *p;
 
@@ -48,18 +48,7 @@ static int asids_seq_show(struct seq_file *file, void *iter)
        return 0;
 }
 
-static int asids_debugfs_open(struct inode *inode, struct file *file)
-{
-       return single_open(file, asids_seq_show, inode->i_private);
-}
-
-static const struct file_operations asids_debugfs_fops = {
-       .owner          = THIS_MODULE,
-       .open           = asids_debugfs_open,
-       .read           = seq_read,
-       .llseek         = seq_lseek,
-       .release        = single_release,
-};
+DEFINE_SHOW_ATTRIBUTE(asids_debugfs);
 
 static int __init asids_debugfs_init(void)
 {
index 17d7807..b0f1851 100644 (file)
@@ -22,7 +22,7 @@ enum cache_type {
        CACHE_TYPE_UNIFIED,
 };
 
-static int cache_seq_show(struct seq_file *file, void *iter)
+static int cache_debugfs_show(struct seq_file *file, void *iter)
 {
        unsigned int cache_type = (unsigned int)file->private;
        struct cache_info *cache;
@@ -94,18 +94,7 @@ static int cache_seq_show(struct seq_file *file, void *iter)
        return 0;
 }
 
-static int cache_debugfs_open(struct inode *inode, struct file *file)
-{
-       return single_open(file, cache_seq_show, inode->i_private);
-}
-
-static const struct file_operations cache_debugfs_fops = {
-       .owner          = THIS_MODULE,
-       .open           = cache_debugfs_open,
-       .read           = seq_read,
-       .llseek         = seq_lseek,
-       .release        = single_release,
-};
+DEFINE_SHOW_ATTRIBUTE(cache_debugfs);
 
 static int __init cache_debugfs_init(void)
 {
index b20aba6..68eb7cc 100644 (file)
@@ -812,7 +812,7 @@ bool __in_29bit_mode(void)
         return (__raw_readl(PMB_PASCR) & PASCR_SE) == 0;
 }
 
-static int pmb_seq_show(struct seq_file *file, void *iter)
+static int pmb_debugfs_show(struct seq_file *file, void *iter)
 {
        int i;
 
@@ -846,18 +846,7 @@ static int pmb_seq_show(struct seq_file *file, void *iter)
        return 0;
 }
 
-static int pmb_debugfs_open(struct inode *inode, struct file *file)
-{
-       return single_open(file, pmb_seq_show, NULL);
-}
-
-static const struct file_operations pmb_debugfs_fops = {
-       .owner          = THIS_MODULE,
-       .open           = pmb_debugfs_open,
-       .read           = seq_read,
-       .llseek         = seq_lseek,
-       .release        = single_release,
-};
+DEFINE_SHOW_ATTRIBUTE(pmb_debugfs);
 
 static int __init pmb_debugfs_init(void)
 {
index 8751162..c7b2e20 100644 (file)
@@ -50,10 +50,11 @@ extern pte_t *pkmap_page_table;
 
 #define flush_cache_kmaps()    flush_cache_all()
 
-/* FIXME: Use __flush_tlb_one(vaddr) instead of flush_cache_all() -- Anton */
-#define arch_kmap_local_post_map(vaddr, pteval)        flush_cache_all()
-#define arch_kmap_local_post_unmap(vaddr)      flush_cache_all()
-
+/* FIXME: Use __flush_*_one(vaddr) instead of flush_*_all() -- Anton */
+#define arch_kmap_local_pre_map(vaddr, pteval) flush_cache_all()
+#define arch_kmap_local_pre_unmap(vaddr)       flush_cache_all()
+#define arch_kmap_local_post_map(vaddr, pteval)        flush_tlb_all()
+#define arch_kmap_local_post_unmap(vaddr)      flush_tlb_all()
 
 #endif /* __KERNEL__ */
 
index 34d302d..c3030db 100644 (file)
@@ -15,7 +15,6 @@ config UML
        select HAVE_DEBUG_KMEMLEAK
        select HAVE_DEBUG_BUGVERBOSE
        select NO_DMA
-       select ARCH_HAS_SET_MEMORY
        select GENERIC_IRQ_SHOW
        select GENERIC_CPU_DEVICES
        select HAVE_GCC_PLUGINS
index 13b1fe6..8e0b43c 100644 (file)
@@ -375,11 +375,11 @@ break_loop:
                file = NULL;
 
        backing_file = strsep(&str, ",:");
-       if (*backing_file == '\0')
+       if (backing_file && *backing_file == '\0')
                backing_file = NULL;
 
        serial = strsep(&str, ",:");
-       if (*serial == '\0')
+       if (serial && *serial == '\0')
                serial = NULL;
 
        if (backing_file && ubd_dev->no_cow) {
@@ -1241,7 +1241,7 @@ static int __init ubd_driver_init(void){
                /* Letting ubd=sync be like using ubd#s= instead of ubd#= is
                 * enough. So use anyway the io thread. */
        }
-       stack = alloc_stack(0);
+       stack = alloc_stack(0, 0);
        io_pid = start_io_thread(stack + PAGE_SIZE - sizeof(void *),
                                 &thread_fd);
        if(io_pid < 0){
index 27e92d3..5d957b7 100644 (file)
@@ -1084,6 +1084,7 @@ static void virtio_uml_release_dev(struct device *d)
        }
 
        os_close_file(vu_dev->sock);
+       kfree(vu_dev);
 }
 
 /* Platform device */
@@ -1097,7 +1098,7 @@ static int virtio_uml_probe(struct platform_device *pdev)
        if (!pdata)
                return -EINVAL;
 
-       vu_dev = devm_kzalloc(&pdev->dev, sizeof(*vu_dev), GFP_KERNEL);
+       vu_dev = kzalloc(sizeof(*vu_dev), GFP_KERNEL);
        if (!vu_dev)
                return -ENOMEM;
 
index 96f77b5..cef03e3 100644 (file)
@@ -5,7 +5,7 @@
 #define ioremap ioremap
 static inline void __iomem *ioremap(phys_addr_t offset, size_t size)
 {
-       return (void __iomem *)(unsigned long)offset;
+       return NULL;
 }
 
 #define iounmap iounmap
index 39376bb..def3761 100644 (file)
@@ -55,15 +55,12 @@ extern unsigned long end_iomem;
 #define _PAGE_CHG_MASK (PAGE_MASK | _PAGE_ACCESSED | _PAGE_DIRTY)
 #define __PAGE_KERNEL_EXEC                                              \
         (_PAGE_PRESENT | _PAGE_RW | _PAGE_DIRTY | _PAGE_ACCESSED)
-#define __PAGE_KERNEL_RO                                               \
-        (_PAGE_PRESENT | _PAGE_DIRTY | _PAGE_ACCESSED)
 #define PAGE_NONE      __pgprot(_PAGE_PROTNONE | _PAGE_ACCESSED)
 #define PAGE_SHARED    __pgprot(_PAGE_PRESENT | _PAGE_RW | _PAGE_USER | _PAGE_ACCESSED)
 #define PAGE_COPY      __pgprot(_PAGE_PRESENT | _PAGE_USER | _PAGE_ACCESSED)
 #define PAGE_READONLY  __pgprot(_PAGE_PRESENT | _PAGE_USER | _PAGE_ACCESSED)
 #define PAGE_KERNEL    __pgprot(_PAGE_PRESENT | _PAGE_RW | _PAGE_DIRTY | _PAGE_ACCESSED)
 #define PAGE_KERNEL_EXEC       __pgprot(__PAGE_KERNEL_EXEC)
-#define PAGE_KERNEL_RO         __pgprot(__PAGE_KERNEL_RO)
 
 /*
  * The i386 can't do page protection for execute, and considers that the same
diff --git a/arch/um/include/asm/set_memory.h b/arch/um/include/asm/set_memory.h
deleted file mode 100644 (file)
index 24266c6..0000000
+++ /dev/null
@@ -1 +0,0 @@
-#include <asm-generic/set_memory.h>
index d8c279e..2888ec8 100644 (file)
@@ -19,7 +19,7 @@ extern int kmalloc_ok;
 #define UML_ROUND_UP(addr) \
        ((((unsigned long) addr) + PAGE_SIZE - 1) & PAGE_MASK)
 
-extern unsigned long alloc_stack(int atomic);
+extern unsigned long alloc_stack(int order, int atomic);
 extern void free_stack(unsigned long stack, int order);
 
 struct pt_regs;
index e4abac6..6516ef1 100644 (file)
@@ -1,6 +1,7 @@
 // SPDX-License-Identifier: GPL-2.0
 #include <linux/kmsg_dump.h>
 #include <linux/console.h>
+#include <linux/string.h>
 #include <shared/init.h>
 #include <shared/kern.h>
 #include <os.h>
@@ -16,8 +17,12 @@ static void kmsg_dumper_stdout(struct kmsg_dumper *dumper,
        if (!console_trylock())
                return;
 
-       for_each_console(con)
-               break;
+       for_each_console(con) {
+               if(strcmp(con->name, "tty") == 0 &&
+                  (con->flags & (CON_ENABLED | CON_CONSDEV)) != 0) {
+                       break;
+               }
+       }
 
        console_unlock();
 
index 2a986ec..81d508d 100644 (file)
@@ -32,7 +32,6 @@
 #include <os.h>
 #include <skas.h>
 #include <linux/time-internal.h>
-#include <asm/set_memory.h>
 
 /*
  * This is a per-cpu array.  A processor only modifies its entry and it only
@@ -63,18 +62,16 @@ void free_stack(unsigned long stack, int order)
        free_pages(stack, order);
 }
 
-unsigned long alloc_stack(int atomic)
+unsigned long alloc_stack(int order, int atomic)
 {
-       unsigned long addr;
+       unsigned long page;
        gfp_t flags = GFP_KERNEL;
 
        if (atomic)
                flags = GFP_ATOMIC;
-       addr = __get_free_pages(flags, 1);
+       page = __get_free_pages(flags, order);
 
-       set_memory_ro(addr, 1);
-
-       return addr + PAGE_SIZE;
+       return page;
 }
 
 static inline void set_current(struct task_struct *task)
index f4db89b..315248b 100644 (file)
@@ -535,6 +535,31 @@ invalid_number:
 
        return 1;
 }
+
+static void time_travel_set_start(void)
+{
+       if (time_travel_start_set)
+               return;
+
+       switch (time_travel_mode) {
+       case TT_MODE_EXTERNAL:
+               time_travel_start = time_travel_ext_req(UM_TIMETRAVEL_GET_TOD, -1);
+               /* controller gave us the *current* time, so adjust by that */
+               time_travel_ext_get_time();
+               time_travel_start -= time_travel_time;
+               break;
+       case TT_MODE_INFCPU:
+       case TT_MODE_BASIC:
+               if (!time_travel_start_set)
+                       time_travel_start = os_persistent_clock_emulation();
+               break;
+       case TT_MODE_OFF:
+               /* we just read the host clock with os_persistent_clock_emulation() */
+               break;
+       }
+
+       time_travel_start_set = true;
+}
 #else /* CONFIG_UML_TIME_TRAVEL_SUPPORT */
 #define time_travel_start_set 0
 #define time_travel_start 0
@@ -553,6 +578,10 @@ static void time_travel_set_interval(unsigned long long interval)
 {
 }
 
+static inline void time_travel_set_start(void)
+{
+}
+
 /* fail link if this actually gets used */
 extern u64 time_travel_ext_req(u32 op, u64 time);
 
@@ -731,6 +760,8 @@ void read_persistent_clock64(struct timespec64 *ts)
 {
        long long nsecs;
 
+       time_travel_set_start();
+
        if (time_travel_mode != TT_MODE_OFF)
                nsecs = time_travel_start + time_travel_time;
        else
@@ -742,25 +773,6 @@ void read_persistent_clock64(struct timespec64 *ts)
 
 void __init time_init(void)
 {
-#ifdef CONFIG_UML_TIME_TRAVEL_SUPPORT
-       switch (time_travel_mode) {
-       case TT_MODE_EXTERNAL:
-               time_travel_start = time_travel_ext_req(UM_TIMETRAVEL_GET_TOD, -1);
-               /* controller gave us the *current* time, so adjust by that */
-               time_travel_ext_get_time();
-               time_travel_start -= time_travel_time;
-               break;
-       case TT_MODE_INFCPU:
-       case TT_MODE_BASIC:
-               if (!time_travel_start_set)
-                       time_travel_start = os_persistent_clock_emulation();
-               break;
-       case TT_MODE_OFF:
-               /* we just read the host clock with os_persistent_clock_emulation() */
-               break;
-       }
-#endif
-
        timer_set_signal_handler();
        late_time_init = um_timer_setup;
 }
index 437d1f1..6177679 100644 (file)
@@ -608,57 +608,3 @@ void force_flush_all(void)
                vma = vma->vm_next;
        }
 }
-
-struct page_change_data {
-       unsigned int set_mask, clear_mask;
-};
-
-static int change_page_range(pte_t *ptep, unsigned long addr, void *data)
-{
-       struct page_change_data *cdata = data;
-       pte_t pte = READ_ONCE(*ptep);
-
-       pte_clear_bits(pte, cdata->clear_mask);
-       pte_set_bits(pte, cdata->set_mask);
-
-       set_pte(ptep, pte);
-       return 0;
-}
-
-static int change_memory(unsigned long start, unsigned long pages,
-                        unsigned int set_mask, unsigned int clear_mask)
-{
-       unsigned long size = pages * PAGE_SIZE;
-       struct page_change_data data;
-       int ret;
-
-       data.set_mask = set_mask;
-       data.clear_mask = clear_mask;
-
-       ret = apply_to_page_range(&init_mm, start, size, change_page_range,
-                                 &data);
-
-       flush_tlb_kernel_range(start, start + size);
-
-       return ret;
-}
-
-int set_memory_ro(unsigned long addr, int numpages)
-{
-       return change_memory(addr, numpages, 0, _PAGE_RW);
-}
-
-int set_memory_rw(unsigned long addr, int numpages)
-{
-       return change_memory(addr, numpages, _PAGE_RW, 0);
-}
-
-int set_memory_nx(unsigned long addr, int numpages)
-{
-       return -EOPNOTSUPP;
-}
-
-int set_memory_x(unsigned long addr, int numpages)
-{
-       return -EOPNOTSUPP;
-}
index 31d356b..80e2660 100644 (file)
@@ -26,7 +26,8 @@
 #include <mem_user.h>
 #include <os.h>
 
-#define DEFAULT_COMMAND_LINE "root=98:0"
+#define DEFAULT_COMMAND_LINE_ROOT "root=98:0"
+#define DEFAULT_COMMAND_LINE_CONSOLE "console=tty"
 
 /* Changed in add_arg and setup_arch, which run before SMP is started */
 static char __initdata command_line[COMMAND_LINE_SIZE] = { 0 };
@@ -109,7 +110,8 @@ unsigned long end_vm;
 int ncpus = 1;
 
 /* Set in early boot */
-static int have_root __initdata = 0;
+static int have_root __initdata;
+static int have_console __initdata;
 
 /* Set in uml_mem_setup and modified in linux_main */
 long long physmem_size = 32 * 1024 * 1024;
@@ -161,6 +163,17 @@ __uml_setup("debug", no_skas_debug_setup,
 "    this flag is not needed to run gdb on UML in skas mode\n\n"
 );
 
+static int __init uml_console_setup(char *line, int *add)
+{
+       have_console = 1;
+       return 0;
+}
+
+__uml_setup("console=", uml_console_setup,
+"console=<preferred console>\n"
+"    Specify the preferred console output driver\n\n"
+);
+
 static int __init Usage(char *line, int *add)
 {
        const char **p;
@@ -264,7 +277,10 @@ int __init linux_main(int argc, char **argv)
                        add_arg(argv[i]);
        }
        if (have_root == 0)
-               add_arg(DEFAULT_COMMAND_LINE);
+               add_arg(DEFAULT_COMMAND_LINE_ROOT);
+
+       if (have_console == 0)
+               add_arg(DEFAULT_COMMAND_LINE_CONSOLE);
 
        host_task_size = os_get_top_address();
        /*
index feb48d7..9fa6e41 100644 (file)
@@ -45,7 +45,7 @@ int run_helper(void (*pre_exec)(void *), void *pre_data, char **argv)
        unsigned long stack, sp;
        int pid, fds[2], ret, n;
 
-       stack = alloc_stack(__cant_sleep());
+       stack = alloc_stack(0, __cant_sleep());
        if (stack == 0)
                return -ENOMEM;
 
@@ -116,7 +116,7 @@ int run_helper_thread(int (*proc)(void *), void *arg, unsigned int flags,
        unsigned long stack, sp;
        int pid, status, err;
 
-       stack = alloc_stack(__cant_sleep());
+       stack = alloc_stack(0, __cant_sleep());
        if (stack == 0)
                return -ENOMEM;
 
index a61cbf7..6c5041c 100644 (file)
@@ -104,5 +104,18 @@ long long os_nsecs(void)
  */
 void os_idle_sleep(void)
 {
-       pause();
+       struct itimerspec its;
+       sigset_t set, old;
+
+       /* block SIGALRM while we analyze the timer state */
+       sigemptyset(&set);
+       sigaddset(&set, SIGALRM);
+       sigprocmask(SIG_BLOCK, &set, &old);
+
+       /* check the timer, and if it'll fire then wait for it */
+       timer_gettime(event_high_res_timer, &its);
+       if (its.it_value.tv_sec || its.it_value.tv_nsec)
+               sigsuspend(&old);
+       /* either way, restore the signal mask */
+       sigprocmask(SIG_UNBLOCK, &set, NULL);
 }
index 7116da3..5857917 100644 (file)
@@ -120,6 +120,9 @@ else
 
         KBUILD_CFLAGS += -mno-red-zone
         KBUILD_CFLAGS += -mcmodel=kernel
+
+       # Intel CET isn't enabled in the kernel
+       KBUILD_CFLAGS += $(call cc-option,-fcf-protection=none)
 endif
 
 ifdef CONFIG_X86_X32
index 18d8f17..0904f56 100644 (file)
@@ -73,10 +73,8 @@ static __always_inline void do_syscall_32_irqs_on(struct pt_regs *regs,
                                                  unsigned int nr)
 {
        if (likely(nr < IA32_NR_syscalls)) {
-               instrumentation_begin();
                nr = array_index_nospec(nr, IA32_NR_syscalls);
                regs->ax = ia32_sys_call_table[nr](regs);
-               instrumentation_end();
        }
 }
 
@@ -91,8 +89,11 @@ __visible noinstr void do_int80_syscall_32(struct pt_regs *regs)
         * or may not be necessary, but it matches the old asm behavior.
         */
        nr = (unsigned int)syscall_enter_from_user_mode(regs, nr);
+       instrumentation_begin();
 
        do_syscall_32_irqs_on(regs, nr);
+
+       instrumentation_end();
        syscall_exit_to_user_mode(regs);
 }
 
@@ -121,11 +122,12 @@ static noinstr bool __do_fast_syscall_32(struct pt_regs *regs)
                res = get_user(*(u32 *)&regs->bp,
                       (u32 __user __force *)(unsigned long)(u32)regs->sp);
        }
-       instrumentation_end();
 
        if (res) {
                /* User code screwed up. */
                regs->ax = -EFAULT;
+
+               instrumentation_end();
                syscall_exit_to_user_mode(regs);
                return false;
        }
@@ -135,6 +137,8 @@ static noinstr bool __do_fast_syscall_32(struct pt_regs *regs)
 
        /* Now this is just like a normal syscall. */
        do_syscall_32_irqs_on(regs, nr);
+
+       instrumentation_end();
        syscall_exit_to_user_mode(regs);
        return true;
 }
index ccd3287..496b11e 100644 (file)
@@ -10,7 +10,7 @@
 #include <asm/export.h>
 
        /* rdi: arg1 ... normal C conventions. rax is saved/restored. */
-       .macro THUNK name, func, put_ret_addr_in_rdi=0
+       .macro THUNK name, func
 SYM_FUNC_START_NOALIGN(\name)
        pushq %rbp
        movq %rsp, %rbp
@@ -25,13 +25,8 @@ SYM_FUNC_START_NOALIGN(\name)
        pushq %r10
        pushq %r11
 
-       .if \put_ret_addr_in_rdi
-       /* 8(%rbp) is return addr on stack */
-       movq 8(%rbp), %rdi
-       .endif
-
        call \func
-       jmp  .L_restore
+       jmp  __thunk_restore
 SYM_FUNC_END(\name)
        _ASM_NOKPROBE(\name)
        .endm
@@ -44,7 +39,7 @@ SYM_FUNC_END(\name)
 #endif
 
 #ifdef CONFIG_PREEMPTION
-SYM_CODE_START_LOCAL_NOALIGN(.L_restore)
+SYM_CODE_START_LOCAL_NOALIGN(__thunk_restore)
        popq %r11
        popq %r10
        popq %r9
@@ -56,6 +51,6 @@ SYM_CODE_START_LOCAL_NOALIGN(.L_restore)
        popq %rdi
        popq %rbp
        ret
-       _ASM_NOKPROBE(.L_restore)
-SYM_CODE_END(.L_restore)
+       _ASM_NOKPROBE(__thunk_restore)
+SYM_CODE_END(__thunk_restore)
 #endif
index 4638a52..6375967 100644 (file)
@@ -315,6 +315,25 @@ static struct syscore_ops hv_syscore_ops = {
        .resume         = hv_resume,
 };
 
+static void (* __initdata old_setup_percpu_clockev)(void);
+
+static void __init hv_stimer_setup_percpu_clockev(void)
+{
+       /*
+        * Ignore any errors in setting up stimer clockevents
+        * as we can run with the LAPIC timer as a fallback.
+        */
+       (void)hv_stimer_alloc();
+
+       /*
+        * Still register the LAPIC timer, because the direct-mode STIMER is
+        * not supported by old versions of Hyper-V. This also allows users
+        * to switch to LAPIC timer via /sys, if they want to.
+        */
+       if (old_setup_percpu_clockev)
+               old_setup_percpu_clockev();
+}
+
 /*
  * This function is to be invoked early in the boot sequence after the
  * hypervisor has been detected.
@@ -393,10 +412,14 @@ void __init hyperv_init(void)
        wrmsrl(HV_X64_MSR_HYPERCALL, hypercall_msr.as_uint64);
 
        /*
-        * Ignore any errors in setting up stimer clockevents
-        * as we can run with the LAPIC timer as a fallback.
+        * hyperv_init() is called before LAPIC is initialized: see
+        * apic_intr_mode_init() -> x86_platform.apic_post_init() and
+        * apic_bsp_setup() -> setup_local_APIC(). The direct-mode STIMER
+        * depends on LAPIC, so hv_stimer_alloc() should be called from
+        * x86_init.timers.setup_percpu_clockev.
         */
-       (void)hv_stimer_alloc();
+       old_setup_percpu_clockev = x86_init.timers.setup_percpu_clockev;
+       x86_init.timers.setup_percpu_clockev = hv_stimer_setup_percpu_clockev;
 
        hv_apic_init();
 
index 34cb3c1..412b51e 100644 (file)
@@ -197,16 +197,6 @@ static inline bool apic_needs_pit(void) { return true; }
 #endif /* !CONFIG_X86_LOCAL_APIC */
 
 #ifdef CONFIG_X86_X2APIC
-/*
- * Make previous memory operations globally visible before
- * sending the IPI through x2apic wrmsr. We need a serializing instruction or
- * mfence for this.
- */
-static inline void x2apic_wrmsr_fence(void)
-{
-       asm volatile("mfence" : : : "memory");
-}
-
 static inline void native_apic_msr_write(u32 reg, u32 v)
 {
        if (reg == APIC_DFR || reg == APIC_ID || reg == APIC_LDR ||
index 7f828fe..4819d5e 100644 (file)
@@ -84,4 +84,22 @@ do {                                                                 \
 
 #include <asm-generic/barrier.h>
 
+/*
+ * Make previous memory operations globally visible before
+ * a WRMSR.
+ *
+ * MFENCE makes writes visible, but only affects load/store
+ * instructions.  WRMSR is unfortunately not a load/store
+ * instruction and is unaffected by MFENCE.  The LFENCE ensures
+ * that the WRMSR is not reordered.
+ *
+ * Most WRMSRs are full serializing instructions themselves and
+ * do not require this barrier.  This is only required for the
+ * IA32_TSC_DEADLINE and X2APIC MSRs.
+ */
+static inline void weak_wrmsr_fence(void)
+{
+       asm volatile("mfence; lfence" : : : "memory");
+}
+
 #endif /* _ASM_X86_BARRIER_H */
index 6fe54b2..2b87b19 100644 (file)
@@ -43,8 +43,6 @@ static __always_inline void arch_check_user_regs(struct pt_regs *regs)
 }
 #define arch_check_user_regs arch_check_user_regs
 
-#define ARCH_SYSCALL_EXIT_WORK         (_TIF_SINGLESTEP)
-
 static inline void arch_exit_to_user_mode_prepare(struct pt_regs *regs,
                                                  unsigned long ti_work)
 {
index a5aba4a..67a4f1c 100644 (file)
  * Use kernel_fpu_begin/end() if you intend to use FPU in kernel context. It
  * disables preemption so be careful if you intend to use it for long periods
  * of time.
- * If you intend to use the FPU in softirq you need to check first with
+ * If you intend to use the FPU in irq/softirq you need to check first with
  * irq_fpu_usable() if it is possible.
  */
-extern void kernel_fpu_begin(void);
+
+/* Kernel FPU states to initialize in kernel_fpu_begin_mask() */
+#define KFPU_387       _BITUL(0)       /* 387 state will be initialized */
+#define KFPU_MXCSR     _BITUL(1)       /* MXCSR will be initialized */
+
+extern void kernel_fpu_begin_mask(unsigned int kfpu_mask);
 extern void kernel_fpu_end(void);
 extern bool irq_fpu_usable(void);
 extern void fpregs_mark_activate(void);
 
+/* Code that is unaware of kernel_fpu_begin_mask() can use this */
+static inline void kernel_fpu_begin(void)
+{
+       kernel_fpu_begin_mask(KFPU_387 | KFPU_MXCSR);
+}
+
 /*
  * Use fpregs_lock() while editing CPU's FPU registers or fpu->state.
  * A context switch will (and softirq might) save CPU's FPU registers to
index 247a60a..f656aab 100644 (file)
@@ -613,6 +613,7 @@ DECLARE_IDTENTRY_VC(X86_TRAP_VC,    exc_vmm_communication);
 
 #ifdef CONFIG_XEN_PV
 DECLARE_IDTENTRY_XENCB(X86_TRAP_OTHER, exc_xen_hypervisor_callback);
+DECLARE_IDTENTRY_RAW(X86_TRAP_OTHER,   exc_xen_unknown_trap);
 #endif
 
 /* Device interrupts common/spurious */
index 5e658ba..9abe842 100644 (file)
@@ -97,6 +97,7 @@
 
 #define        INTEL_FAM6_LAKEFIELD            0x8A
 #define INTEL_FAM6_ALDERLAKE           0x97
+#define INTEL_FAM6_ALDERLAKE_L         0x9A
 
 /* "Small Core" Processors (Atom) */
 
index 0b4920a..e16cccd 100644 (file)
@@ -86,7 +86,7 @@ static inline void do_trace_rdpmc(unsigned int msr, u64 val, int failed) {}
  * think of extending them - you will be slapped with a stinking trout or a frozen
  * shark will reach you, wherever you are! You've been warned.
  */
-static inline unsigned long long notrace __rdmsr(unsigned int msr)
+static __always_inline unsigned long long __rdmsr(unsigned int msr)
 {
        DECLARE_ARGS(val, low, high);
 
@@ -98,7 +98,7 @@ static inline unsigned long long notrace __rdmsr(unsigned int msr)
        return EAX_EDX_VAL(val, low, high);
 }
 
-static inline void notrace __wrmsr(unsigned int msr, u32 low, u32 high)
+static __always_inline void __wrmsr(unsigned int msr, u32 low, u32 high)
 {
        asm volatile("1: wrmsr\n"
                     "2:\n"
index 488a8e8..9239399 100644 (file)
@@ -110,6 +110,8 @@ extern const struct cpumask *cpu_coregroup_mask(int cpu);
 #define topology_die_id(cpu)                   (cpu_data(cpu).cpu_die_id)
 #define topology_core_id(cpu)                  (cpu_data(cpu).cpu_core_id)
 
+extern unsigned int __max_die_per_package;
+
 #ifdef CONFIG_SMP
 #define topology_die_cpumask(cpu)              (per_cpu(cpu_die_map, cpu))
 #define topology_core_cpumask(cpu)             (per_cpu(cpu_core_map, cpu))
@@ -118,8 +120,6 @@ extern const struct cpumask *cpu_coregroup_mask(int cpu);
 extern unsigned int __max_logical_packages;
 #define topology_max_packages()                        (__max_logical_packages)
 
-extern unsigned int __max_die_per_package;
-
 static inline int topology_max_die_per_package(void)
 {
        return __max_die_per_package;
index 6bd20c0..7f4c081 100644 (file)
@@ -41,6 +41,7 @@
 #include <asm/perf_event.h>
 #include <asm/x86_init.h>
 #include <linux/atomic.h>
+#include <asm/barrier.h>
 #include <asm/mpspec.h>
 #include <asm/i8259.h>
 #include <asm/proto.h>
@@ -477,6 +478,9 @@ static int lapic_next_deadline(unsigned long delta,
 {
        u64 tsc;
 
+       /* This MSR is special and need a special fence: */
+       weak_wrmsr_fence();
+
        tsc = rdtsc();
        wrmsrl(MSR_IA32_TSC_DEADLINE, tsc + (((u64) delta) * TSC_DIVISOR));
        return 0;
index df6adc5..f4da9bb 100644 (file)
@@ -29,7 +29,8 @@ static void x2apic_send_IPI(int cpu, int vector)
 {
        u32 dest = per_cpu(x86_cpu_to_logical_apicid, cpu);
 
-       x2apic_wrmsr_fence();
+       /* x2apic MSRs are special and need a special fence: */
+       weak_wrmsr_fence();
        __x2apic_send_IPI_dest(dest, vector, APIC_DEST_LOGICAL);
 }
 
@@ -41,7 +42,8 @@ __x2apic_send_IPI_mask(const struct cpumask *mask, int vector, int apic_dest)
        unsigned long flags;
        u32 dest;
 
-       x2apic_wrmsr_fence();
+       /* x2apic MSRs are special and need a special fence: */
+       weak_wrmsr_fence();
        local_irq_save(flags);
 
        tmpmsk = this_cpu_cpumask_var_ptr(ipi_mask);
index 0e4e819..6bde05a 100644 (file)
@@ -43,7 +43,8 @@ static void x2apic_send_IPI(int cpu, int vector)
 {
        u32 dest = per_cpu(x86_cpu_to_apicid, cpu);
 
-       x2apic_wrmsr_fence();
+       /* x2apic MSRs are special and need a special fence: */
+       weak_wrmsr_fence();
        __x2apic_send_IPI_dest(dest, vector, APIC_DEST_PHYSICAL);
 }
 
@@ -54,7 +55,8 @@ __x2apic_send_IPI_mask(const struct cpumask *mask, int vector, int apic_dest)
        unsigned long this_cpu;
        unsigned long flags;
 
-       x2apic_wrmsr_fence();
+       /* x2apic MSRs are special and need a special fence: */
+       weak_wrmsr_fence();
 
        local_irq_save(flags);
 
@@ -125,7 +127,8 @@ void __x2apic_send_IPI_shorthand(int vector, u32 which)
 {
        unsigned long cfg = __prepare_ICR(which, vector, 0);
 
-       x2apic_wrmsr_fence();
+       /* x2apic MSRs are special and need a special fence: */
+       weak_wrmsr_fence();
        native_x2apic_icr_write(cfg, 0);
 }
 
index f8ca66f..347a956 100644 (file)
@@ -542,12 +542,12 @@ static void bsp_init_amd(struct cpuinfo_x86 *c)
                u32 ecx;
 
                ecx = cpuid_ecx(0x8000001e);
-               nodes_per_socket = ((ecx >> 8) & 7) + 1;
+               __max_die_per_package = nodes_per_socket = ((ecx >> 8) & 7) + 1;
        } else if (boot_cpu_has(X86_FEATURE_NODEID_MSR)) {
                u64 value;
 
                rdmsrl(MSR_FAM10H_NODE_ID, value);
-               nodes_per_socket = ((value >> 3) & 7) + 1;
+               __max_die_per_package = nodes_per_socket = ((value >> 3) & 7) + 1;
        }
 
        if (!boot_cpu_has(X86_FEATURE_AMD_SSBD) &&
index 59a1e3c..816fdbe 100644 (file)
@@ -1159,6 +1159,7 @@ static const struct x86_cpu_id split_lock_cpu_ids[] __initconst = {
        X86_MATCH_INTEL_FAM6_MODEL(TIGERLAKE,           1),
        X86_MATCH_INTEL_FAM6_MODEL(SAPPHIRERAPIDS_X,    1),
        X86_MATCH_INTEL_FAM6_MODEL(ALDERLAKE,           1),
+       X86_MATCH_INTEL_FAM6_MODEL(ALDERLAKE_L,         1),
        {}
 };
 
index 13d3f1c..e133ce1 100644 (file)
@@ -1992,10 +1992,9 @@ static __always_inline void exc_machine_check_kernel(struct pt_regs *regs)
         * that out because it's an indirect call. Annotate it.
         */
        instrumentation_begin();
-       trace_hardirqs_off_finish();
+
        machine_check_vector(regs);
-       if (regs->flags & X86_EFLAGS_IF)
-               trace_hardirqs_on_prepare();
+
        instrumentation_end();
        irqentry_nmi_exit(regs, irq_state);
 }
@@ -2004,7 +2003,9 @@ static __always_inline void exc_machine_check_user(struct pt_regs *regs)
 {
        irqentry_enter_from_user_mode(regs);
        instrumentation_begin();
+
        machine_check_vector(regs);
+
        instrumentation_end();
        irqentry_exit_to_user_mode(regs);
 }
index 1068002..8678864 100644 (file)
 #define BITS_SHIFT_NEXT_LEVEL(eax)     ((eax) & 0x1f)
 #define LEVEL_MAX_SIBLINGS(ebx)                ((ebx) & 0xffff)
 
-#ifdef CONFIG_SMP
 unsigned int __max_die_per_package __read_mostly = 1;
 EXPORT_SYMBOL(__max_die_per_package);
 
+#ifdef CONFIG_SMP
 /*
  * Check if given CPUID extended toplogy "leaf" is implemented
  */
index eb86a2b..571220a 100644 (file)
@@ -121,7 +121,7 @@ int copy_fpregs_to_fpstate(struct fpu *fpu)
 }
 EXPORT_SYMBOL(copy_fpregs_to_fpstate);
 
-void kernel_fpu_begin(void)
+void kernel_fpu_begin_mask(unsigned int kfpu_mask)
 {
        preempt_disable();
 
@@ -141,13 +141,14 @@ void kernel_fpu_begin(void)
        }
        __cpu_invalidate_fpregs_state();
 
-       if (boot_cpu_has(X86_FEATURE_XMM))
+       /* Put sane initial values into the control registers. */
+       if (likely(kfpu_mask & KFPU_MXCSR) && boot_cpu_has(X86_FEATURE_XMM))
                ldmxcsr(MXCSR_DEFAULT);
 
-       if (boot_cpu_has(X86_FEATURE_FPU))
+       if (unlikely(kfpu_mask & KFPU_387) && boot_cpu_has(X86_FEATURE_FPU))
                asm volatile ("fninit");
 }
-EXPORT_SYMBOL_GPL(kernel_fpu_begin);
+EXPORT_SYMBOL_GPL(kernel_fpu_begin_mask);
 
 void kernel_fpu_end(void)
 {
index 03aa33b..668a4a6 100644 (file)
@@ -269,6 +269,20 @@ static inline bool within_cpu_entry(unsigned long addr, unsigned long end)
                        CPU_ENTRY_AREA_TOTAL_SIZE))
                return true;
 
+       /*
+        * When FSGSBASE is enabled, paranoid_entry() fetches the per-CPU
+        * GSBASE value via __per_cpu_offset or pcpu_unit_offsets.
+        */
+#ifdef CONFIG_SMP
+       if (within_area(addr, end, (unsigned long)__per_cpu_offset,
+                       sizeof(unsigned long) * nr_cpu_ids))
+               return true;
+#else
+       if (within_area(addr, end, (unsigned long)&pcpu_unit_offsets,
+                       sizeof(pcpu_unit_offsets)))
+               return true;
+#endif
+
        for_each_possible_cpu(cpu) {
                /* The original rw GDT is being used after load_direct_gdt() */
                if (within_area(addr, end, (unsigned long)get_cpu_gdt_rw(cpu),
@@ -293,6 +307,14 @@ static inline bool within_cpu_entry(unsigned long addr, unsigned long end)
                                (unsigned long)&per_cpu(cpu_tlbstate, cpu),
                                sizeof(struct tlb_state)))
                        return true;
+
+               /*
+                * When in guest (X86_FEATURE_HYPERVISOR), local_db_save()
+                * will read per-cpu cpu_dr7 before clear dr7 register.
+                */
+               if (within_area(addr, end, (unsigned long)&per_cpu(cpu_dr7, cpu),
+                               sizeof(cpu_dr7)))
+                       return true;
        }
 
        return false;
@@ -491,15 +513,12 @@ static int hw_breakpoint_handler(struct die_args *args)
        struct perf_event *bp;
        unsigned long *dr6_p;
        unsigned long dr6;
+       bool bpx;
 
        /* The DR6 value is pointed by args->err */
        dr6_p = (unsigned long *)ERR_PTR(args->err);
        dr6 = *dr6_p;
 
-       /* If it's a single step, TRAP bits are random */
-       if (dr6 & DR_STEP)
-               return NOTIFY_DONE;
-
        /* Do an early return if no trap bits are set in DR6 */
        if ((dr6 & DR_TRAP_BITS) == 0)
                return NOTIFY_DONE;
@@ -509,28 +528,29 @@ static int hw_breakpoint_handler(struct die_args *args)
                if (likely(!(dr6 & (DR_TRAP0 << i))))
                        continue;
 
+               bp = this_cpu_read(bp_per_reg[i]);
+               if (!bp)
+                       continue;
+
+               bpx = bp->hw.info.type == X86_BREAKPOINT_EXECUTE;
+
                /*
-                * The counter may be concurrently released but that can only
-                * occur from a call_rcu() path. We can then safely fetch
-                * the breakpoint, use its callback, touch its counter
-                * while we are in an rcu_read_lock() path.
+                * TF and data breakpoints are traps and can be merged, however
+                * instruction breakpoints are faults and will be raised
+                * separately.
+                *
+                * However DR6 can indicate both TF and instruction
+                * breakpoints. In that case take TF as that has precedence and
+                * delay the instruction breakpoint for the next exception.
                 */
-               rcu_read_lock();
+               if (bpx && (dr6 & DR_STEP))
+                       continue;
 
-               bp = this_cpu_read(bp_per_reg[i]);
                /*
                 * Reset the 'i'th TRAP bit in dr6 to denote completion of
                 * exception handling
                 */
                (*dr6_p) &= ~(DR_TRAP0 << i);
-               /*
-                * bp can be NULL due to lazy debug register switching
-                * or due to concurrent perf counter removing.
-                */
-               if (!bp) {
-                       rcu_read_unlock();
-                       break;
-               }
 
                perf_bp_event(bp, args->regs);
 
@@ -538,11 +558,10 @@ static int hw_breakpoint_handler(struct die_args *args)
                 * Set up resume flag to avoid breakpoint recursion when
                 * returning back to origin.
                 */
-               if (bp->hw.info.type == X86_BREAKPOINT_EXECUTE)
+               if (bpx)
                        args->regs->flags |= X86_EFLAGS_RF;
-
-               rcu_read_unlock();
        }
+
        /*
         * Further processing in do_debug() is needed for a) user-space
         * breakpoints (to generate signals) and b) when the system has
index 0bd1a0f..84c1821 100644 (file)
@@ -225,7 +225,7 @@ static inline u64 sev_es_rd_ghcb_msr(void)
        return __rdmsr(MSR_AMD64_SEV_ES_GHCB);
 }
 
-static inline void sev_es_wr_ghcb_msr(u64 val)
+static __always_inline void sev_es_wr_ghcb_msr(u64 val)
 {
        u32 low, high;
 
@@ -286,6 +286,12 @@ static enum es_result vc_write_mem(struct es_em_ctxt *ctxt,
        u16 d2;
        u8  d1;
 
+       /* If instruction ran in kernel mode and the I/O buffer is in kernel space */
+       if (!user_mode(ctxt->regs) && !access_ok(target, size)) {
+               memcpy(dst, buf, size);
+               return ES_OK;
+       }
+
        switch (size) {
        case 1:
                memcpy(&d1, buf, 1);
@@ -335,6 +341,12 @@ static enum es_result vc_read_mem(struct es_em_ctxt *ctxt,
        u16 d2;
        u8  d1;
 
+       /* If instruction ran in kernel mode and the I/O buffer is in kernel space */
+       if (!user_mode(ctxt->regs) && !access_ok(s, size)) {
+               memcpy(buf, src, size);
+               return ES_OK;
+       }
+
        switch (size) {
        case 1:
                if (get_user(d1, s))
index 8ca66af..117e24f 100644 (file)
@@ -56,6 +56,7 @@
 #include <linux/numa.h>
 #include <linux/pgtable.h>
 #include <linux/overflow.h>
+#include <linux/syscore_ops.h>
 
 #include <asm/acpi.h>
 #include <asm/desc.h>
@@ -2083,6 +2084,23 @@ static void init_counter_refs(void)
        this_cpu_write(arch_prev_mperf, mperf);
 }
 
+#ifdef CONFIG_PM_SLEEP
+static struct syscore_ops freq_invariance_syscore_ops = {
+       .resume = init_counter_refs,
+};
+
+static void register_freq_invariance_syscore_ops(void)
+{
+       /* Bail out if registered already. */
+       if (freq_invariance_syscore_ops.node.prev)
+               return;
+
+       register_syscore_ops(&freq_invariance_syscore_ops);
+}
+#else
+static inline void register_freq_invariance_syscore_ops(void) {}
+#endif
+
 static void init_freq_invariance(bool secondary, bool cppc_ready)
 {
        bool ret = false;
@@ -2109,6 +2127,7 @@ static void init_freq_invariance(bool secondary, bool cppc_ready)
        if (ret) {
                init_counter_refs();
                static_branch_enable(&arch_scale_freq_key);
+               register_freq_invariance_syscore_ops();
                pr_info("Estimated ratio of average max frequency by base frequency (times 1024): %llu\n", arch_max_freq_ratio);
        } else {
                pr_debug("Couldn't determine max cpu frequency, necessary for scale-invariant accounting.\n");
index 60d2c37..0f3c307 100644 (file)
@@ -127,12 +127,17 @@ static int enable_single_step(struct task_struct *child)
                regs->flags |= X86_EFLAGS_TF;
 
        /*
-        * Always set TIF_SINGLESTEP - this guarantees that
-        * we single-step system calls etc..  This will also
+        * Always set TIF_SINGLESTEP.  This will also
         * cause us to set TF when returning to user mode.
         */
        set_tsk_thread_flag(child, TIF_SINGLESTEP);
 
+       /*
+        * Ensure that a trap is triggered once stepping out of a system
+        * call prior to executing any user instruction.
+        */
+       set_task_syscall_work(child, SYSCALL_EXIT_TRAP);
+
        oflags = regs->flags;
 
        /* Set TF on the kernel stack.. */
@@ -230,6 +235,7 @@ void user_disable_single_step(struct task_struct *child)
 
        /* Always clear TIF_SINGLESTEP... */
        clear_tsk_thread_flag(child, TIF_SINGLESTEP);
+       clear_task_syscall_work(child, SYSCALL_EXIT_TRAP);
 
        /* But touch TF only if it was set by us.. */
        if (test_and_clear_tsk_thread_flag(child, TIF_FORCED_TF))
index 13036cf..38172ca 100644 (file)
@@ -321,7 +321,7 @@ int kvm_vcpu_ioctl_get_cpuid2(struct kvm_vcpu *vcpu,
        if (cpuid->nent < vcpu->arch.cpuid_nent)
                goto out;
        r = -EFAULT;
-       if (copy_to_user(entries, &vcpu->arch.cpuid_entries,
+       if (copy_to_user(entries, vcpu->arch.cpuid_entries,
                         vcpu->arch.cpuid_nent * sizeof(struct kvm_cpuid_entry2)))
                goto out;
        return 0;
index 56cae1f..66a0832 100644 (file)
@@ -2879,6 +2879,8 @@ static int em_sysenter(struct x86_emulate_ctxt *ctxt)
        ops->get_msr(ctxt, MSR_IA32_SYSENTER_ESP, &msr_data);
        *reg_write(ctxt, VCPU_REGS_RSP) = (efer & EFER_LMA) ? msr_data :
                                                              (u32)msr_data;
+       if (efer & EFER_LMA)
+               ctxt->mode = X86EMUL_MODE_PROT64;
 
        return X86EMUL_CONTINUE;
 }
index f15bc16..a889563 100644 (file)
@@ -9,31 +9,6 @@
        (X86_CR4_PVI | X86_CR4_DE | X86_CR4_PCE | X86_CR4_OSFXSR  \
         | X86_CR4_OSXMMEXCPT | X86_CR4_PGE | X86_CR4_TSD | X86_CR4_FSGSBASE)
 
-static inline bool kvm_register_is_available(struct kvm_vcpu *vcpu,
-                                            enum kvm_reg reg)
-{
-       return test_bit(reg, (unsigned long *)&vcpu->arch.regs_avail);
-}
-
-static inline bool kvm_register_is_dirty(struct kvm_vcpu *vcpu,
-                                        enum kvm_reg reg)
-{
-       return test_bit(reg, (unsigned long *)&vcpu->arch.regs_dirty);
-}
-
-static inline void kvm_register_mark_available(struct kvm_vcpu *vcpu,
-                                              enum kvm_reg reg)
-{
-       __set_bit(reg, (unsigned long *)&vcpu->arch.regs_avail);
-}
-
-static inline void kvm_register_mark_dirty(struct kvm_vcpu *vcpu,
-                                          enum kvm_reg reg)
-{
-       __set_bit(reg, (unsigned long *)&vcpu->arch.regs_avail);
-       __set_bit(reg, (unsigned long *)&vcpu->arch.regs_dirty);
-}
-
 #define BUILD_KVM_GPR_ACCESSORS(lname, uname)                                \
 static __always_inline unsigned long kvm_##lname##_read(struct kvm_vcpu *vcpu)\
 {                                                                            \
@@ -43,7 +18,6 @@ static __always_inline void kvm_##lname##_write(struct kvm_vcpu *vcpu,              \
                                                unsigned long val)            \
 {                                                                            \
        vcpu->arch.regs[VCPU_REGS_##uname] = val;                             \
-       kvm_register_mark_dirty(vcpu, VCPU_REGS_##uname);                     \
 }
 BUILD_KVM_GPR_ACCESSORS(rax, RAX)
 BUILD_KVM_GPR_ACCESSORS(rbx, RBX)
@@ -63,6 +37,31 @@ BUILD_KVM_GPR_ACCESSORS(r14, R14)
 BUILD_KVM_GPR_ACCESSORS(r15, R15)
 #endif
 
+static inline bool kvm_register_is_available(struct kvm_vcpu *vcpu,
+                                            enum kvm_reg reg)
+{
+       return test_bit(reg, (unsigned long *)&vcpu->arch.regs_avail);
+}
+
+static inline bool kvm_register_is_dirty(struct kvm_vcpu *vcpu,
+                                        enum kvm_reg reg)
+{
+       return test_bit(reg, (unsigned long *)&vcpu->arch.regs_dirty);
+}
+
+static inline void kvm_register_mark_available(struct kvm_vcpu *vcpu,
+                                              enum kvm_reg reg)
+{
+       __set_bit(reg, (unsigned long *)&vcpu->arch.regs_avail);
+}
+
+static inline void kvm_register_mark_dirty(struct kvm_vcpu *vcpu,
+                                          enum kvm_reg reg)
+{
+       __set_bit(reg, (unsigned long *)&vcpu->arch.regs_avail);
+       __set_bit(reg, (unsigned long *)&vcpu->arch.regs_dirty);
+}
+
 static inline unsigned long kvm_register_read(struct kvm_vcpu *vcpu, int reg)
 {
        if (WARN_ON_ONCE((unsigned int)reg >= NR_VCPU_REGS))
index 581925e..261be1d 100644 (file)
 #define PT32_ROOT_LEVEL 2
 #define PT32E_ROOT_LEVEL 3
 
-static inline u64 rsvd_bits(int s, int e)
+static __always_inline u64 rsvd_bits(int s, int e)
 {
+       BUILD_BUG_ON(__builtin_constant_p(e) && __builtin_constant_p(s) && e < s);
+
+       if (__builtin_constant_p(e))
+               BUILD_BUG_ON(e > 63);
+       else
+               e &= 63;
+
        if (e < s)
                return 0;
 
index 2ef8615..b56d604 100644 (file)
@@ -1049,8 +1049,8 @@ bool kvm_tdp_mmu_slot_set_dirty(struct kvm *kvm, struct kvm_memory_slot *slot)
 }
 
 /*
- * Clear non-leaf entries (and free associated page tables) which could
- * be replaced by large mappings, for GFNs within the slot.
+ * Clear leaf entries which could be replaced by large mappings, for
+ * GFNs within the slot.
  */
 static void zap_collapsible_spte_range(struct kvm *kvm,
                                       struct kvm_mmu_page *root,
@@ -1062,7 +1062,7 @@ static void zap_collapsible_spte_range(struct kvm *kvm,
 
        tdp_root_for_each_pte(iter, root, start, end) {
                if (!is_shadow_present_pte(iter.old_spte) ||
-                   is_last_spte(iter.old_spte, iter.level))
+                   !is_last_spte(iter.old_spte, iter.level))
                        continue;
 
                pfn = spte_to_pfn(iter.old_spte);
index cb4c6ee..db30670 100644 (file)
@@ -200,6 +200,9 @@ static bool svm_get_nested_state_pages(struct kvm_vcpu *vcpu)
 {
        struct vcpu_svm *svm = to_svm(vcpu);
 
+       if (WARN_ON(!is_guest_mode(vcpu)))
+               return true;
+
        if (!nested_svm_vmrun_msrpm(svm)) {
                vcpu->run->exit_reason = KVM_EXIT_INTERNAL_ERROR;
                vcpu->run->internal.suberror =
@@ -228,6 +231,7 @@ static bool nested_vmcb_check_controls(struct vmcb_control_area *control)
 
 static bool nested_vmcb_checks(struct vcpu_svm *svm, struct vmcb *vmcb12)
 {
+       struct kvm_vcpu *vcpu = &svm->vcpu;
        bool vmcb12_lma;
 
        if ((vmcb12->save.efer & EFER_SVME) == 0)
@@ -241,18 +245,10 @@ static bool nested_vmcb_checks(struct vcpu_svm *svm, struct vmcb *vmcb12)
 
        vmcb12_lma = (vmcb12->save.efer & EFER_LME) && (vmcb12->save.cr0 & X86_CR0_PG);
 
-       if (!vmcb12_lma) {
-               if (vmcb12->save.cr4 & X86_CR4_PAE) {
-                       if (vmcb12->save.cr3 & MSR_CR3_LEGACY_PAE_RESERVED_MASK)
-                               return false;
-               } else {
-                       if (vmcb12->save.cr3 & MSR_CR3_LEGACY_RESERVED_MASK)
-                               return false;
-               }
-       } else {
+       if (vmcb12_lma) {
                if (!(vmcb12->save.cr4 & X86_CR4_PAE) ||
                    !(vmcb12->save.cr0 & X86_CR0_PE) ||
-                   (vmcb12->save.cr3 & MSR_CR3_LONG_MBZ_MASK))
+                   (vmcb12->save.cr3 & vcpu->arch.cr3_lm_rsvd_bits))
                        return false;
        }
        if (!kvm_is_valid_cr4(&svm->vcpu, vmcb12->save.cr4))
index c8ffdbc..48017fe 100644 (file)
@@ -342,6 +342,8 @@ static struct page **sev_pin_memory(struct kvm *kvm, unsigned long uaddr,
        unsigned long first, last;
        int ret;
 
+       lockdep_assert_held(&kvm->lock);
+
        if (ulen == 0 || uaddr + ulen < uaddr)
                return ERR_PTR(-EINVAL);
 
@@ -1119,12 +1121,20 @@ int svm_register_enc_region(struct kvm *kvm,
        if (!region)
                return -ENOMEM;
 
+       mutex_lock(&kvm->lock);
        region->pages = sev_pin_memory(kvm, range->addr, range->size, &region->npages, 1);
        if (IS_ERR(region->pages)) {
                ret = PTR_ERR(region->pages);
+               mutex_unlock(&kvm->lock);
                goto e_free;
        }
 
+       region->uaddr = range->addr;
+       region->size = range->size;
+
+       list_add_tail(&region->list, &sev->regions_list);
+       mutex_unlock(&kvm->lock);
+
        /*
         * The guest may change the memory encryption attribute from C=0 -> C=1
         * or vice versa for this memory range. Lets make sure caches are
@@ -1133,13 +1143,6 @@ int svm_register_enc_region(struct kvm *kvm,
         */
        sev_clflush_pages(region->pages, region->npages);
 
-       region->uaddr = range->addr;
-       region->size = range->size;
-
-       mutex_lock(&kvm->lock);
-       list_add_tail(&region->list, &sev->regions_list);
-       mutex_unlock(&kvm->lock);
-
        return ret;
 
 e_free:
@@ -1415,16 +1418,13 @@ static void sev_es_sync_to_ghcb(struct vcpu_svm *svm)
         * to be returned:
         *   GPRs RAX, RBX, RCX, RDX
         *
-        * Copy their values to the GHCB if they are dirty.
+        * Copy their values, even if they may not have been written during the
+        * VM-Exit.  It's the guest's responsibility to not consume random data.
         */
-       if (kvm_register_is_dirty(vcpu, VCPU_REGS_RAX))
-               ghcb_set_rax(ghcb, vcpu->arch.regs[VCPU_REGS_RAX]);
-       if (kvm_register_is_dirty(vcpu, VCPU_REGS_RBX))
-               ghcb_set_rbx(ghcb, vcpu->arch.regs[VCPU_REGS_RBX]);
-       if (kvm_register_is_dirty(vcpu, VCPU_REGS_RCX))
-               ghcb_set_rcx(ghcb, vcpu->arch.regs[VCPU_REGS_RCX]);
-       if (kvm_register_is_dirty(vcpu, VCPU_REGS_RDX))
-               ghcb_set_rdx(ghcb, vcpu->arch.regs[VCPU_REGS_RDX]);
+       ghcb_set_rax(ghcb, vcpu->arch.regs[VCPU_REGS_RAX]);
+       ghcb_set_rbx(ghcb, vcpu->arch.regs[VCPU_REGS_RBX]);
+       ghcb_set_rcx(ghcb, vcpu->arch.regs[VCPU_REGS_RCX]);
+       ghcb_set_rdx(ghcb, vcpu->arch.regs[VCPU_REGS_RDX]);
 }
 
 static void sev_es_sync_from_ghcb(struct vcpu_svm *svm)
index 7ef1717..3442d44 100644 (file)
@@ -454,6 +454,11 @@ static int has_svm(void)
                return 0;
        }
 
+       if (sev_active()) {
+               pr_info("KVM is unsupported when running as an SEV guest\n");
+               return 0;
+       }
+
        return 1;
 }
 
@@ -3739,6 +3744,8 @@ static __no_kcsan fastpath_t svm_vcpu_run(struct kvm_vcpu *vcpu)
 {
        struct vcpu_svm *svm = to_svm(vcpu);
 
+       trace_kvm_entry(vcpu);
+
        svm->vmcb->save.rax = vcpu->arch.regs[VCPU_REGS_RAX];
        svm->vmcb->save.rsp = vcpu->arch.regs[VCPU_REGS_RSP];
        svm->vmcb->save.rip = vcpu->arch.regs[VCPU_REGS_RIP];
index 0fe874a..6e7d070 100644 (file)
@@ -403,9 +403,6 @@ static inline bool gif_set(struct vcpu_svm *svm)
 }
 
 /* svm.c */
-#define MSR_CR3_LEGACY_RESERVED_MASK           0xfe7U
-#define MSR_CR3_LEGACY_PAE_RESERVED_MASK       0x7U
-#define MSR_CR3_LONG_MBZ_MASK                  0xfff0000000000000U
 #define MSR_INVALID                            0xffffffffU
 
 extern int sev;
index 0fbb469..f2b9bfb 100644 (file)
@@ -3124,13 +3124,9 @@ static int nested_vmx_check_vmentry_hw(struct kvm_vcpu *vcpu)
        return 0;
 }
 
-static bool nested_get_vmcs12_pages(struct kvm_vcpu *vcpu)
+static bool nested_get_evmcs_page(struct kvm_vcpu *vcpu)
 {
-       struct vmcs12 *vmcs12 = get_vmcs12(vcpu);
        struct vcpu_vmx *vmx = to_vmx(vcpu);
-       struct kvm_host_map *map;
-       struct page *page;
-       u64 hpa;
 
        /*
         * hv_evmcs may end up being not mapped after migration (when
@@ -3153,6 +3149,17 @@ static bool nested_get_vmcs12_pages(struct kvm_vcpu *vcpu)
                }
        }
 
+       return true;
+}
+
+static bool nested_get_vmcs12_pages(struct kvm_vcpu *vcpu)
+{
+       struct vmcs12 *vmcs12 = get_vmcs12(vcpu);
+       struct vcpu_vmx *vmx = to_vmx(vcpu);
+       struct kvm_host_map *map;
+       struct page *page;
+       u64 hpa;
+
        if (nested_cpu_has2(vmcs12, SECONDARY_EXEC_VIRTUALIZE_APIC_ACCESSES)) {
                /*
                 * Translate L1 physical address to host physical
@@ -3221,6 +3228,18 @@ static bool nested_get_vmcs12_pages(struct kvm_vcpu *vcpu)
                exec_controls_setbit(vmx, CPU_BASED_USE_MSR_BITMAPS);
        else
                exec_controls_clearbit(vmx, CPU_BASED_USE_MSR_BITMAPS);
+
+       return true;
+}
+
+static bool vmx_get_nested_state_pages(struct kvm_vcpu *vcpu)
+{
+       if (!nested_get_evmcs_page(vcpu))
+               return false;
+
+       if (is_guest_mode(vcpu) && !nested_get_vmcs12_pages(vcpu))
+               return false;
+
        return true;
 }
 
@@ -6077,11 +6096,14 @@ static int vmx_get_nested_state(struct kvm_vcpu *vcpu,
        if (is_guest_mode(vcpu)) {
                sync_vmcs02_to_vmcs12(vcpu, vmcs12);
                sync_vmcs02_to_vmcs12_rare(vcpu, vmcs12);
-       } else if (!vmx->nested.need_vmcs12_to_shadow_sync) {
-               if (vmx->nested.hv_evmcs)
-                       copy_enlightened_to_vmcs12(vmx);
-               else if (enable_shadow_vmcs)
-                       copy_shadow_to_vmcs12(vmx);
+       } else  {
+               copy_vmcs02_to_vmcs12_rare(vcpu, get_vmcs12(vcpu));
+               if (!vmx->nested.need_vmcs12_to_shadow_sync) {
+                       if (vmx->nested.hv_evmcs)
+                               copy_enlightened_to_vmcs12(vmx);
+                       else if (enable_shadow_vmcs)
+                               copy_shadow_to_vmcs12(vmx);
+               }
        }
 
        BUILD_BUG_ON(sizeof(user_vmx_nested_state->vmcs12) < VMCS12_SIZE);
@@ -6602,7 +6624,7 @@ struct kvm_x86_nested_ops vmx_nested_ops = {
        .hv_timer_pending = nested_vmx_preemption_timer_pending,
        .get_state = vmx_get_nested_state,
        .set_state = vmx_set_nested_state,
-       .get_nested_state_pages = nested_get_vmcs12_pages,
+       .get_nested_state_pages = vmx_get_nested_state_pages,
        .write_log_dirty = nested_vmx_write_pml_buffer,
        .enable_evmcs = nested_enable_evmcs,
        .get_evmcs_version = nested_get_evmcs_version,
index a886a47..cdf5f34 100644 (file)
@@ -29,7 +29,7 @@ static struct kvm_event_hw_type_mapping intel_arch_events[] = {
        [4] = { 0x2e, 0x41, PERF_COUNT_HW_CACHE_MISSES },
        [5] = { 0xc4, 0x00, PERF_COUNT_HW_BRANCH_INSTRUCTIONS },
        [6] = { 0xc5, 0x00, PERF_COUNT_HW_BRANCH_MISSES },
-       [7] = { 0x00, 0x30, PERF_COUNT_HW_REF_CPU_CYCLES },
+       [7] = { 0x00, 0x03, PERF_COUNT_HW_REF_CPU_CYCLES },
 };
 
 /* mapping between fixed pmc index and intel_arch_events array */
@@ -345,7 +345,9 @@ static void intel_pmu_refresh(struct kvm_vcpu *vcpu)
 
        pmu->nr_arch_gp_counters = min_t(int, eax.split.num_counters,
                                         x86_pmu.num_counters_gp);
+       eax.split.bit_width = min_t(int, eax.split.bit_width, x86_pmu.bit_width_gp);
        pmu->counter_bitmask[KVM_PMC_GP] = ((u64)1 << eax.split.bit_width) - 1;
+       eax.split.mask_length = min_t(int, eax.split.mask_length, x86_pmu.events_mask_len);
        pmu->available_event_types = ~entry->ebx &
                                        ((1ull << eax.split.mask_length) - 1);
 
@@ -355,6 +357,8 @@ static void intel_pmu_refresh(struct kvm_vcpu *vcpu)
                pmu->nr_arch_fixed_counters =
                        min_t(int, edx.split.num_counters_fixed,
                              x86_pmu.num_counters_fixed);
+               edx.split.bit_width_fixed = min_t(int,
+                       edx.split.bit_width_fixed, x86_pmu.bit_width_fixed);
                pmu->counter_bitmask[KVM_PMC_FIXED] =
                        ((u64)1 << edx.split.bit_width_fixed) - 1;
        }
index 2af05d3..eb69fef 100644 (file)
@@ -6653,6 +6653,8 @@ reenter_guest:
        if (vmx->emulation_required)
                return EXIT_FASTPATH_NONE;
 
+       trace_kvm_entry(vcpu);
+
        if (vmx->ple_window_dirty) {
                vmx->ple_window_dirty = false;
                vmcs_write32(PLE_WINDOW, vmx->ple_window);
@@ -6858,11 +6860,20 @@ static int vmx_create_vcpu(struct kvm_vcpu *vcpu)
                switch (index) {
                case MSR_IA32_TSX_CTRL:
                        /*
-                        * No need to pass TSX_CTRL_CPUID_CLEAR through, so
-                        * let's avoid changing CPUID bits under the host
-                        * kernel's feet.
+                        * TSX_CTRL_CPUID_CLEAR is handled in the CPUID
+                        * interception.  Keep the host value unchanged to avoid
+                        * changing CPUID bits under the host kernel's feet.
+                        *
+                        * hle=0, rtm=0, tsx_ctrl=1 can be found with some
+                        * combinations of new kernel and old userspace.  If
+                        * those guests run on a tsx=off host, do allow guests
+                        * to use TSX_CTRL, but do not change the value on the
+                        * host so that TSX remains always disabled.
                         */
-                       vmx->guest_uret_msrs[j].mask = ~(u64)TSX_CTRL_CPUID_CLEAR;
+                       if (boot_cpu_has(X86_FEATURE_RTM))
+                               vmx->guest_uret_msrs[j].mask = ~(u64)TSX_CTRL_CPUID_CLEAR;
+                       else
+                               vmx->guest_uret_msrs[j].mask = 0;
                        break;
                default:
                        vmx->guest_uret_msrs[j].mask = -1ull;
index 9a8969a..1b404e4 100644 (file)
@@ -105,6 +105,7 @@ static u64 __read_mostly cr4_reserved_bits = CR4_RESERVED_BITS;
 
 static void update_cr8_intercept(struct kvm_vcpu *vcpu);
 static void process_nmi(struct kvm_vcpu *vcpu);
+static void process_smi(struct kvm_vcpu *vcpu);
 static void enter_smm(struct kvm_vcpu *vcpu);
 static void __kvm_set_rflags(struct kvm_vcpu *vcpu, unsigned long rflags);
 static void store_regs(struct kvm_vcpu *vcpu);
@@ -1393,16 +1394,24 @@ static u64 kvm_get_arch_capabilities(void)
        if (!boot_cpu_has_bug(X86_BUG_MDS))
                data |= ARCH_CAP_MDS_NO;
 
-       /*
-        * On TAA affected systems:
-        *      - nothing to do if TSX is disabled on the host.
-        *      - we emulate TSX_CTRL if present on the host.
-        *        This lets the guest use VERW to clear CPU buffers.
-        */
-       if (!boot_cpu_has(X86_FEATURE_RTM))
-               data &= ~(ARCH_CAP_TAA_NO | ARCH_CAP_TSX_CTRL_MSR);
-       else if (!boot_cpu_has_bug(X86_BUG_TAA))
+       if (!boot_cpu_has(X86_FEATURE_RTM)) {
+               /*
+                * If RTM=0 because the kernel has disabled TSX, the host might
+                * have TAA_NO or TSX_CTRL.  Clear TAA_NO (the guest sees RTM=0
+                * and therefore knows that there cannot be TAA) but keep
+                * TSX_CTRL: some buggy userspaces leave it set on tsx=on hosts,
+                * and we want to allow migrating those guests to tsx=off hosts.
+                */
+               data &= ~ARCH_CAP_TAA_NO;
+       } else if (!boot_cpu_has_bug(X86_BUG_TAA)) {
                data |= ARCH_CAP_TAA_NO;
+       } else {
+               /*
+                * Nothing to do here; we emulate TSX_CTRL if present on the
+                * host so the guest can choose between disabling TSX or
+                * using VERW to clear CPU buffers.
+                */
+       }
 
        return data;
 }
@@ -4230,6 +4239,9 @@ static void kvm_vcpu_ioctl_x86_get_vcpu_events(struct kvm_vcpu *vcpu,
 {
        process_nmi(vcpu);
 
+       if (kvm_check_request(KVM_REQ_SMI, vcpu))
+               process_smi(vcpu);
+
        /*
         * In guest mode, payload delivery should be deferred,
         * so that the L1 hypervisor can intercept #PF before
@@ -8802,9 +8814,7 @@ static int vcpu_enter_guest(struct kvm_vcpu *vcpu)
 
        if (kvm_request_pending(vcpu)) {
                if (kvm_check_request(KVM_REQ_GET_NESTED_STATE_PAGES, vcpu)) {
-                       if (WARN_ON_ONCE(!is_guest_mode(vcpu)))
-                               ;
-                       else if (unlikely(!kvm_x86_ops.nested_ops->get_nested_state_pages(vcpu))) {
+                       if (unlikely(!kvm_x86_ops.nested_ops->get_nested_state_pages(vcpu))) {
                                r = 0;
                                goto out;
                        }
@@ -8988,8 +8998,6 @@ static int vcpu_enter_guest(struct kvm_vcpu *vcpu)
                kvm_x86_ops.request_immediate_exit(vcpu);
        }
 
-       trace_kvm_entry(vcpu);
-
        fpregs_assert_state_consistent();
        if (test_thread_flag(TIF_NEED_FPU_LOAD))
                switch_fpu_return();
@@ -9616,6 +9624,8 @@ static bool kvm_is_valid_sregs(struct kvm_vcpu *vcpu, struct kvm_sregs *sregs)
                 */
                if (!(sregs->cr4 & X86_CR4_PAE) || !(sregs->efer & EFER_LMA))
                        return false;
+               if (sregs->cr3 & vcpu->arch.cr3_lm_rsvd_bits)
+                       return false;
        } else {
                /*
                 * Not in 64-bit mode: EFER.LMA is clear and the code
@@ -9993,6 +10003,7 @@ int kvm_arch_vcpu_create(struct kvm_vcpu *vcpu)
        fx_init(vcpu);
 
        vcpu->arch.maxphyaddr = cpuid_query_maxphyaddr(vcpu);
+       vcpu->arch.cr3_lm_rsvd_bits = rsvd_bits(cpuid_maxphyaddr(vcpu), 63);
 
        vcpu->arch.pat = MSR_IA32_CR_PAT_DEFAULT;
 
@@ -10494,7 +10505,7 @@ void __user * __x86_set_memory_region(struct kvm *kvm, int id, gpa_t gpa,
                        return 0;
 
                old_npages = slot->npages;
-               hva = 0;
+               hva = slot->userspace_addr;
        }
 
        for (i = 0; i < KVM_ADDRESS_SPACE_NUM; i++) {
@@ -11556,6 +11567,7 @@ int kvm_sev_es_string_io(struct kvm_vcpu *vcpu, unsigned int size,
 }
 EXPORT_SYMBOL_GPL(kvm_sev_es_string_io);
 
+EXPORT_TRACEPOINT_SYMBOL_GPL(kvm_entry);
 EXPORT_TRACEPOINT_SYMBOL_GPL(kvm_exit);
 EXPORT_TRACEPOINT_SYMBOL_GPL(kvm_fast_mmio);
 EXPORT_TRACEPOINT_SYMBOL_GPL(kvm_inj_virq);
index c5ee0f5..0f727b5 100644 (file)
@@ -425,6 +425,8 @@ bool kvm_msr_allowed(struct kvm_vcpu *vcpu, u32 index, u32 type);
                __reserved_bits |= X86_CR4_UMIP;        \
        if (!__cpu_has(__c, X86_FEATURE_VMX))           \
                __reserved_bits |= X86_CR4_VMXE;        \
+       if (!__cpu_has(__c, X86_FEATURE_PCID))          \
+               __reserved_bits |= X86_CR4_PCIDE;       \
        __reserved_bits;                                \
 })
 
index 4321fa0..419365c 100644 (file)
 #include <asm/fpu/api.h>
 #include <asm/asm.h>
 
+/*
+ * Use KFPU_387.  MMX instructions are not affected by MXCSR,
+ * but both AMD and Intel documentation states that even integer MMX
+ * operations will result in #MF if an exception is pending in FCW.
+ *
+ * EMMS is not needed afterwards because, after calling kernel_fpu_end(),
+ * any subsequent user of the 387 stack will reinitialize it using
+ * KFPU_387.
+ */
+
 void *_mmx_memcpy(void *to, const void *from, size_t len)
 {
        void *p;
@@ -37,7 +47,7 @@ void *_mmx_memcpy(void *to, const void *from, size_t len)
        p = to;
        i = len >> 6; /* len/64 */
 
-       kernel_fpu_begin();
+       kernel_fpu_begin_mask(KFPU_387);
 
        __asm__ __volatile__ (
                "1: prefetch (%0)\n"            /* This set is 28 bytes */
@@ -127,7 +137,7 @@ static void fast_clear_page(void *page)
 {
        int i;
 
-       kernel_fpu_begin();
+       kernel_fpu_begin_mask(KFPU_387);
 
        __asm__ __volatile__ (
                "  pxor %%mm0, %%mm0\n" : :
@@ -160,7 +170,7 @@ static void fast_copy_page(void *to, void *from)
 {
        int i;
 
-       kernel_fpu_begin();
+       kernel_fpu_begin_mask(KFPU_387);
 
        /*
         * maybe the prefetch stuff can go before the expensive fnsave...
@@ -247,7 +257,7 @@ static void fast_clear_page(void *page)
 {
        int i;
 
-       kernel_fpu_begin();
+       kernel_fpu_begin_mask(KFPU_387);
 
        __asm__ __volatile__ (
                "  pxor %%mm0, %%mm0\n" : :
@@ -282,7 +292,7 @@ static void fast_copy_page(void *to, void *from)
 {
        int i;
 
-       kernel_fpu_begin();
+       kernel_fpu_begin_mask(KFPU_387);
 
        __asm__ __volatile__ (
                "1: prefetch (%0)\n"
index c79e573..c3d5f02 100644 (file)
@@ -382,6 +382,7 @@ bool sev_active(void)
 {
        return sev_status & MSR_AMD64_SEV_ENABLED;
 }
+EXPORT_SYMBOL_GPL(sev_active);
 
 /* Needs to be called from non-instrumentable code */
 bool noinstr sev_es_active(void)
index e1e8d4e..8efd003 100644 (file)
@@ -115,31 +115,12 @@ void efi_sync_low_kernel_mappings(void)
        pud_t *pud_k, *pud_efi;
        pgd_t *efi_pgd = efi_mm.pgd;
 
-       /*
-        * We can share all PGD entries apart from the one entry that
-        * covers the EFI runtime mapping space.
-        *
-        * Make sure the EFI runtime region mappings are guaranteed to
-        * only span a single PGD entry and that the entry also maps
-        * other important kernel regions.
-        */
-       MAYBE_BUILD_BUG_ON(pgd_index(EFI_VA_END) != pgd_index(MODULES_END));
-       MAYBE_BUILD_BUG_ON((EFI_VA_START & PGDIR_MASK) !=
-                       (EFI_VA_END & PGDIR_MASK));
-
        pgd_efi = efi_pgd + pgd_index(PAGE_OFFSET);
        pgd_k = pgd_offset_k(PAGE_OFFSET);
 
        num_entries = pgd_index(EFI_VA_END) - pgd_index(PAGE_OFFSET);
        memcpy(pgd_efi, pgd_k, sizeof(pgd_t) * num_entries);
 
-       /*
-        * As with PGDs, we share all P4D entries apart from the one entry
-        * that covers the EFI runtime mapping space.
-        */
-       BUILD_BUG_ON(p4d_index(EFI_VA_END) != p4d_index(MODULES_END));
-       BUILD_BUG_ON((EFI_VA_START & P4D_MASK) != (EFI_VA_END & P4D_MASK));
-
        pgd_efi = efi_pgd + pgd_index(EFI_VA_END);
        pgd_k = pgd_offset_k(EFI_VA_END);
        p4d_efi = p4d_offset(pgd_efi, 0);
index 4409306..9a5a50c 100644 (file)
@@ -583,6 +583,13 @@ DEFINE_IDTENTRY_RAW(xenpv_exc_debug)
                exc_debug(regs);
 }
 
+DEFINE_IDTENTRY_RAW(exc_xen_unknown_trap)
+{
+       /* This should never happen and there is no way to handle it. */
+       pr_err("Unknown trap in Xen PV mode.");
+       BUG();
+}
+
 struct trap_array_entry {
        void (*orig)(void);
        void (*xen)(void);
@@ -631,6 +638,7 @@ static bool __ref get_trap_addr(void **addr, unsigned int ist)
 {
        unsigned int nr;
        bool ist_okay = false;
+       bool found = false;
 
        /*
         * Replace trap handler addresses by Xen specific ones.
@@ -645,6 +653,7 @@ static bool __ref get_trap_addr(void **addr, unsigned int ist)
                if (*addr == entry->orig) {
                        *addr = entry->xen;
                        ist_okay = entry->ist_okay;
+                       found = true;
                        break;
                }
        }
@@ -655,9 +664,13 @@ static bool __ref get_trap_addr(void **addr, unsigned int ist)
                nr = (*addr - (void *)early_idt_handler_array[0]) /
                     EARLY_IDT_HANDLER_SIZE;
                *addr = (void *)xen_early_idt_handler_array[nr];
+               found = true;
        }
 
-       if (WARN_ON(ist != 0 && !ist_okay))
+       if (!found)
+               *addr = (void *)xen_asm_exc_xen_unknown_trap;
+
+       if (WARN_ON(found && ist != 0 && !ist_okay))
                return false;
 
        return true;
index 056430a..6ff3c88 100644 (file)
@@ -74,7 +74,9 @@ void __init xen_hvm_smp_init(void)
        smp_ops.cpu_die = xen_hvm_cpu_die;
 
        if (!xen_have_vector_callback) {
+#ifdef CONFIG_PARAVIRT_SPINLOCKS
                nopvspin = true;
+#endif
                return;
        }
 
index 1cb0e84..53cf8aa 100644 (file)
@@ -178,6 +178,7 @@ xen_pv_trap asm_exc_simd_coprocessor_error
 #ifdef CONFIG_IA32_EMULATION
 xen_pv_trap entry_INT80_compat
 #endif
+xen_pv_trap asm_exc_xen_unknown_trap
 xen_pv_trap asm_exc_xen_hypervisor_callback
 
        __INIT
index 9e4eb0f..9e81d10 100644 (file)
@@ -6332,13 +6332,13 @@ static unsigned int bfq_update_depths(struct bfq_data *bfqd,
         * limit 'something'.
         */
        /* no more than 50% of tags for async I/O */
-       bfqd->word_depths[0][0] = max(bt->sb.depth >> 1, 1U);
+       bfqd->word_depths[0][0] = max((1U << bt->sb.shift) >> 1, 1U);
        /*
         * no more than 75% of tags for sync writes (25% extra tags
         * w.r.t. async I/O, to prevent async I/O from starving sync
         * writes)
         */
-       bfqd->word_depths[0][1] = max((bt->sb.depth * 3) >> 2, 1U);
+       bfqd->word_depths[0][1] = max(((1U << bt->sb.shift) * 3) >> 2, 1U);
 
        /*
         * In-word depths in case some bfq_queue is being weight-
@@ -6348,9 +6348,9 @@ static unsigned int bfq_update_depths(struct bfq_data *bfqd,
         * shortage.
         */
        /* no more than ~18% of tags for async I/O */
-       bfqd->word_depths[1][0] = max((bt->sb.depth * 3) >> 4, 1U);
+       bfqd->word_depths[1][0] = max(((1U << bt->sb.shift) * 3) >> 4, 1U);
        /* no more than ~37% of tags for sync writes (~20% extra tags) */
-       bfqd->word_depths[1][1] = max((bt->sb.depth * 6) >> 4, 1U);
+       bfqd->word_depths[1][1] = max(((1U << bt->sb.shift) * 6) >> 4, 1U);
 
        for (i = 0; i < 2; i++)
                for (j = 0; j < 2; j++)
index 031114d..4221a15 100644 (file)
@@ -1016,6 +1016,8 @@ static void blkcg_css_offline(struct cgroup_subsys_state *css)
  */
 void blkcg_destroy_blkgs(struct blkcg *blkcg)
 {
+       might_sleep();
+
        spin_lock_irq(&blkcg->lock);
 
        while (!hlist_empty(&blkcg->blkg_list)) {
@@ -1023,14 +1025,20 @@ void blkcg_destroy_blkgs(struct blkcg *blkcg)
                                                struct blkcg_gq, blkcg_node);
                struct request_queue *q = blkg->q;
 
-               if (spin_trylock(&q->queue_lock)) {
-                       blkg_destroy(blkg);
-                       spin_unlock(&q->queue_lock);
-               } else {
+               if (need_resched() || !spin_trylock(&q->queue_lock)) {
+                       /*
+                        * Given that the system can accumulate a huge number
+                        * of blkgs in pathological cases, check to see if we
+                        * need to rescheduling to avoid softlockup.
+                        */
                        spin_unlock_irq(&blkcg->lock);
-                       cpu_relax();
+                       cond_resched();
                        spin_lock_irq(&blkcg->lock);
+                       continue;
                }
+
+               blkg_destroy(blkg);
+               spin_unlock(&q->queue_lock);
        }
 
        spin_unlock_irq(&blkcg->lock);
index c1458d9..3616453 100644 (file)
@@ -304,7 +304,7 @@ static inline bool hctx_may_queue(struct blk_mq_hw_ctx *hctx,
                struct request_queue *q = hctx->queue;
                struct blk_mq_tag_set *set = q->tag_set;
 
-               if (!test_bit(BLK_MQ_S_TAG_ACTIVE, &q->queue_flags))
+               if (!test_bit(QUEUE_FLAG_HCTX_ACTIVE, &q->queue_flags))
                        return true;
                users = atomic_read(&set->active_queues_shared_sbitmap);
        } else {
index 419548e..9e741a4 100644 (file)
@@ -45,10 +45,11 @@ static void disk_release_events(struct gendisk *disk);
 void set_capacity(struct gendisk *disk, sector_t sectors)
 {
        struct block_device *bdev = disk->part0;
+       unsigned long flags;
 
-       spin_lock(&bdev->bd_size_lock);
+       spin_lock_irqsave(&bdev->bd_size_lock, flags);
        i_size_write(bdev->bd_inode, (loff_t)sectors << SECTOR_SHIFT);
-       spin_unlock(&bdev->bd_size_lock);
+       spin_unlock_irqrestore(&bdev->bd_size_lock, flags);
 }
 EXPORT_SYMBOL(set_capacity);
 
index e7d776d..4601a84 100644 (file)
@@ -88,9 +88,11 @@ static int (*check_part[])(struct parsed_partitions *) = {
 
 static void bdev_set_nr_sectors(struct block_device *bdev, sector_t sectors)
 {
-       spin_lock(&bdev->bd_size_lock);
+       unsigned long flags;
+
+       spin_lock_irqsave(&bdev->bd_size_lock, flags);
        i_size_write(bdev->bd_inode, (loff_t)sectors << SECTOR_SHIFT);
-       spin_unlock(&bdev->bd_size_lock);
+       spin_unlock_irqrestore(&bdev->bd_size_lock, flags);
 }
 
 static struct parsed_partitions *allocate_partitions(struct gendisk *hd)
@@ -384,7 +386,7 @@ static struct block_device *add_partition(struct gendisk *disk, int partno,
 
        err = blk_alloc_devt(bdev, &devt);
        if (err)
-               goto out_bdput;
+               goto out_put;
        pdev->devt = devt;
 
        /* delay uevent until 'holders' subdir is created */
index 8892908..788a4ba 100644 (file)
@@ -356,7 +356,8 @@ int public_key_verify_signature(const struct public_key *pkey,
        if (ret)
                goto error_free_key;
 
-       if (strcmp(sig->pkey_algo, "sm2") == 0 && sig->data_size) {
+       if (sig->pkey_algo && strcmp(sig->pkey_algo, "sm2") == 0 &&
+           sig->data_size) {
                ret = cert_sig_digest_update(sig, tfm);
                if (ret)
                        goto error_free_key;
index eacbf4f..8f899f8 100644 (file)
@@ -107,6 +107,8 @@ do_xor_speed(struct xor_block_template *tmpl, void *b1, void *b2)
        preempt_enable();
 
        // bytes/ns == GB/s, multiply by 1000 to get MB/s [not MiB/s]
+       if (!min)
+               min = 1;
        speed = (1000 * REPS * BENCH_SIZE) / (unsigned int)ktime_to_ns(min);
        tmpl->speed = speed;
 
index d4eac6d..2494138 100644 (file)
@@ -1107,6 +1107,11 @@ static int nc_dma_get_range(struct device *dev, u64 *size)
 
        ncomp = (struct acpi_iort_named_component *)node->node_data;
 
+       if (!ncomp->memory_address_limit) {
+               pr_warn(FW_BUG "Named component missing memory address limit\n");
+               return -EINVAL;
+       }
+
        *size = ncomp->memory_address_limit >= 64 ? U64_MAX :
                        1ULL<<ncomp->memory_address_limit;
 
@@ -1126,6 +1131,11 @@ static int rc_dma_get_range(struct device *dev, u64 *size)
 
        rc = (struct acpi_iort_root_complex *)node->node_data;
 
+       if (!rc->memory_address_limit) {
+               pr_warn(FW_BUG "Root complex missing memory address limit\n");
+               return -EINVAL;
+       }
+
        *size = rc->memory_address_limit >= 64 ? U64_MAX :
                        1ULL<<rc->memory_address_limit;
 
@@ -1173,8 +1183,8 @@ void iort_dma_setup(struct device *dev, u64 *dma_addr, u64 *dma_size)
                end = dmaaddr + size - 1;
                mask = DMA_BIT_MASK(ilog2(end) + 1);
                dev->bus_dma_limit = end;
-               dev->coherent_dma_mask = mask;
-               *dev->dma_mask = mask;
+               dev->coherent_dma_mask = min(dev->coherent_dma_mask, mask);
+               *dev->dma_mask = min(*dev->dma_mask, mask);
        }
 
        *dma_addr = dmaaddr;
index 96869f1..bfca116 100644 (file)
@@ -251,20 +251,12 @@ int __acpi_device_uevent_modalias(struct acpi_device *adev,
        if (add_uevent_var(env, "MODALIAS="))
                return -ENOMEM;
 
-       len = create_pnp_modalias(adev, &env->buf[env->buflen - 1],
-                                 sizeof(env->buf) - env->buflen);
-       if (len < 0)
-               return len;
-
-       env->buflen += len;
-       if (!adev->data.of_compatible)
-               return 0;
-
-       if (len > 0 && add_uevent_var(env, "MODALIAS="))
-               return -ENOMEM;
-
-       len = create_of_modalias(adev, &env->buf[env->buflen - 1],
-                                sizeof(env->buf) - env->buflen);
+       if (adev->data.of_compatible)
+               len = create_of_modalias(adev, &env->buf[env->buflen - 1],
+                                        sizeof(env->buf) - env->buflen);
+       else
+               len = create_pnp_modalias(adev, &env->buf[env->buflen - 1],
+                                         sizeof(env->buf) - env->buflen);
        if (len < 0)
                return len;
 
index b11b08a..8c5dde6 100644 (file)
@@ -2269,40 +2269,24 @@ static const struct attribute_group *acpi_nfit_region_attribute_groups[] = {
 
 /* enough info to uniquely specify an interleave set */
 struct nfit_set_info {
-       struct nfit_set_info_map {
-               u64 region_offset;
-               u32 serial_number;
-               u32 pad;
-       } mapping[0];
+       u64 region_offset;
+       u32 serial_number;
+       u32 pad;
 };
 
 struct nfit_set_info2 {
-       struct nfit_set_info_map2 {
-               u64 region_offset;
-               u32 serial_number;
-               u16 vendor_id;
-               u16 manufacturing_date;
-               u8  manufacturing_location;
-               u8  reserved[31];
-       } mapping[0];
+       u64 region_offset;
+       u32 serial_number;
+       u16 vendor_id;
+       u16 manufacturing_date;
+       u8 manufacturing_location;
+       u8 reserved[31];
 };
 
-static size_t sizeof_nfit_set_info(int num_mappings)
-{
-       return sizeof(struct nfit_set_info)
-               + num_mappings * sizeof(struct nfit_set_info_map);
-}
-
-static size_t sizeof_nfit_set_info2(int num_mappings)
-{
-       return sizeof(struct nfit_set_info2)
-               + num_mappings * sizeof(struct nfit_set_info_map2);
-}
-
 static int cmp_map_compat(const void *m0, const void *m1)
 {
-       const struct nfit_set_info_map *map0 = m0;
-       const struct nfit_set_info_map *map1 = m1;
+       const struct nfit_set_info *map0 = m0;
+       const struct nfit_set_info *map1 = m1;
 
        return memcmp(&map0->region_offset, &map1->region_offset,
                        sizeof(u64));
@@ -2310,8 +2294,8 @@ static int cmp_map_compat(const void *m0, const void *m1)
 
 static int cmp_map(const void *m0, const void *m1)
 {
-       const struct nfit_set_info_map *map0 = m0;
-       const struct nfit_set_info_map *map1 = m1;
+       const struct nfit_set_info *map0 = m0;
+       const struct nfit_set_info *map1 = m1;
 
        if (map0->region_offset < map1->region_offset)
                return -1;
@@ -2322,8 +2306,8 @@ static int cmp_map(const void *m0, const void *m1)
 
 static int cmp_map2(const void *m0, const void *m1)
 {
-       const struct nfit_set_info_map2 *map0 = m0;
-       const struct nfit_set_info_map2 *map1 = m1;
+       const struct nfit_set_info2 *map0 = m0;
+       const struct nfit_set_info2 *map1 = m1;
 
        if (map0->region_offset < map1->region_offset)
                return -1;
@@ -2361,22 +2345,22 @@ static int acpi_nfit_init_interleave_set(struct acpi_nfit_desc *acpi_desc,
                return -ENOMEM;
        import_guid(&nd_set->type_guid, spa->range_guid);
 
-       info = devm_kzalloc(dev, sizeof_nfit_set_info(nr), GFP_KERNEL);
+       info = devm_kcalloc(dev, nr, sizeof(*info), GFP_KERNEL);
        if (!info)
                return -ENOMEM;
 
-       info2 = devm_kzalloc(dev, sizeof_nfit_set_info2(nr), GFP_KERNEL);
+       info2 = devm_kcalloc(dev, nr, sizeof(*info2), GFP_KERNEL);
        if (!info2)
                return -ENOMEM;
 
        for (i = 0; i < nr; i++) {
                struct nd_mapping_desc *mapping = &ndr_desc->mapping[i];
-               struct nfit_set_info_map *map = &info->mapping[i];
-               struct nfit_set_info_map2 *map2 = &info2->mapping[i];
                struct nvdimm *nvdimm = mapping->nvdimm;
                struct nfit_mem *nfit_mem = nvdimm_provider_data(nvdimm);
-               struct acpi_nfit_memory_map *memdev = memdev_from_spa(acpi_desc,
-                               spa->range_index, i);
+               struct nfit_set_info *map = &info[i];
+               struct nfit_set_info2 *map2 = &info2[i];
+               struct acpi_nfit_memory_map *memdev =
+                       memdev_from_spa(acpi_desc, spa->range_index, i);
                struct acpi_nfit_control_region *dcr = nfit_mem->dcr;
 
                if (!memdev || !nfit_mem->dcr) {
@@ -2395,23 +2379,20 @@ static int acpi_nfit_init_interleave_set(struct acpi_nfit_desc *acpi_desc,
        }
 
        /* v1.1 namespaces */
-       sort(&info->mapping[0], nr, sizeof(struct nfit_set_info_map),
-                       cmp_map, NULL);
-       nd_set->cookie1 = nd_fletcher64(info, sizeof_nfit_set_info(nr), 0);
+       sort(info, nr, sizeof(*info), cmp_map, NULL);
+       nd_set->cookie1 = nd_fletcher64(info, sizeof(*info) * nr, 0);
 
        /* v1.2 namespaces */
-       sort(&info2->mapping[0], nr, sizeof(struct nfit_set_info_map2),
-                       cmp_map2, NULL);
-       nd_set->cookie2 = nd_fletcher64(info2, sizeof_nfit_set_info2(nr), 0);
+       sort(info2, nr, sizeof(*info2), cmp_map2, NULL);
+       nd_set->cookie2 = nd_fletcher64(info2, sizeof(*info2) * nr, 0);
 
        /* support v1.1 namespaces created with the wrong sort order */
-       sort(&info->mapping[0], nr, sizeof(struct nfit_set_info_map),
-                       cmp_map_compat, NULL);
-       nd_set->altcookie = nd_fletcher64(info, sizeof_nfit_set_info(nr), 0);
+       sort(info, nr, sizeof(*info), cmp_map_compat, NULL);
+       nd_set->altcookie = nd_fletcher64(info, sizeof(*info) * nr, 0);
 
        /* record the result of the sort for the mapping position */
        for (i = 0; i < nr; i++) {
-               struct nfit_set_info_map2 *map2 = &info2->mapping[i];
+               struct nfit_set_info2 *map2 = &info2[i];
                int j;
 
                for (j = 0; j < nr; j++) {
index 58ff363..22566b4 100644 (file)
@@ -586,6 +586,8 @@ static int acpi_get_device_data(acpi_handle handle, struct acpi_device **device,
        if (!device)
                return -EINVAL;
 
+       *device = NULL;
+
        status = acpi_get_data_full(handle, acpi_scan_drop_device,
                                    (void **)device, callback);
        if (ACPI_FAILURE(status) || !*device) {
@@ -2121,12 +2123,12 @@ void acpi_walk_dep_device_list(acpi_handle handle)
        list_for_each_entry_safe(dep, tmp, &acpi_dep_list, node) {
                if (dep->supplier == handle) {
                        acpi_bus_get_device(dep->consumer, &adev);
-                       if (!adev)
-                               continue;
 
-                       adev->dep_unmet--;
-                       if (!adev->dep_unmet)
-                               acpi_bus_attach(adev, true);
+                       if (adev) {
+                               adev->dep_unmet--;
+                               if (!adev->dep_unmet)
+                                       acpi_bus_attach(adev, true);
+                       }
 
                        list_del(&dep->node);
                        kfree(dep);
index 12c0ece..859b1de 100644 (file)
@@ -174,6 +174,8 @@ struct acpi_thermal {
        struct thermal_zone_device *thermal_zone;
        int kelvin_offset;      /* in millidegrees */
        struct work_struct thermal_check_work;
+       struct mutex thermal_check_lock;
+       refcount_t thermal_check_count;
 };
 
 /* --------------------------------------------------------------------------
@@ -495,14 +497,6 @@ static int acpi_thermal_get_trip_points(struct acpi_thermal *tz)
        return 0;
 }
 
-static void acpi_thermal_check(void *data)
-{
-       struct acpi_thermal *tz = data;
-
-       thermal_zone_device_update(tz->thermal_zone,
-                                  THERMAL_EVENT_UNSPECIFIED);
-}
-
 /* sys I/F for generic thermal sysfs support */
 
 static int thermal_get_temp(struct thermal_zone_device *thermal, int *temp)
@@ -900,6 +894,12 @@ static void acpi_thermal_unregister_thermal_zone(struct acpi_thermal *tz)
                                  Driver Interface
    -------------------------------------------------------------------------- */
 
+static void acpi_queue_thermal_check(struct acpi_thermal *tz)
+{
+       if (!work_pending(&tz->thermal_check_work))
+               queue_work(acpi_thermal_pm_queue, &tz->thermal_check_work);
+}
+
 static void acpi_thermal_notify(struct acpi_device *device, u32 event)
 {
        struct acpi_thermal *tz = acpi_driver_data(device);
@@ -910,17 +910,17 @@ static void acpi_thermal_notify(struct acpi_device *device, u32 event)
 
        switch (event) {
        case ACPI_THERMAL_NOTIFY_TEMPERATURE:
-               acpi_thermal_check(tz);
+               acpi_queue_thermal_check(tz);
                break;
        case ACPI_THERMAL_NOTIFY_THRESHOLDS:
                acpi_thermal_trips_update(tz, ACPI_TRIPS_REFRESH_THRESHOLDS);
-               acpi_thermal_check(tz);
+               acpi_queue_thermal_check(tz);
                acpi_bus_generate_netlink_event(device->pnp.device_class,
                                                  dev_name(&device->dev), event, 0);
                break;
        case ACPI_THERMAL_NOTIFY_DEVICES:
                acpi_thermal_trips_update(tz, ACPI_TRIPS_REFRESH_DEVICES);
-               acpi_thermal_check(tz);
+               acpi_queue_thermal_check(tz);
                acpi_bus_generate_netlink_event(device->pnp.device_class,
                                                  dev_name(&device->dev), event, 0);
                break;
@@ -1020,7 +1020,25 @@ static void acpi_thermal_check_fn(struct work_struct *work)
 {
        struct acpi_thermal *tz = container_of(work, struct acpi_thermal,
                                               thermal_check_work);
-       acpi_thermal_check(tz);
+
+       /*
+        * In general, it is not sufficient to check the pending bit, because
+        * subsequent instances of this function may be queued after one of them
+        * has started running (e.g. if _TMP sleeps).  Avoid bailing out if just
+        * one of them is running, though, because it may have done the actual
+        * check some time ago, so allow at least one of them to block on the
+        * mutex while another one is running the update.
+        */
+       if (!refcount_dec_not_one(&tz->thermal_check_count))
+               return;
+
+       mutex_lock(&tz->thermal_check_lock);
+
+       thermal_zone_device_update(tz->thermal_zone, THERMAL_EVENT_UNSPECIFIED);
+
+       refcount_inc(&tz->thermal_check_count);
+
+       mutex_unlock(&tz->thermal_check_lock);
 }
 
 static int acpi_thermal_add(struct acpi_device *device)
@@ -1052,6 +1070,8 @@ static int acpi_thermal_add(struct acpi_device *device)
        if (result)
                goto free_memory;
 
+       refcount_set(&tz->thermal_check_count, 3);
+       mutex_init(&tz->thermal_check_lock);
        INIT_WORK(&tz->thermal_check_work, acpi_thermal_check_fn);
 
        pr_info(PREFIX "%s [%s] (%ld C)\n", acpi_device_name(device),
@@ -1117,7 +1137,7 @@ static int acpi_thermal_resume(struct device *dev)
                tz->state.active |= tz->trips.active[i].flags.enabled;
        }
 
-       queue_work(acpi_thermal_pm_queue, &tz->thermal_check_work);
+       acpi_queue_thermal_check(tz);
 
        return AE_OK;
 }
index 14f1658..6eb4c7a 100644 (file)
@@ -208,6 +208,16 @@ int device_links_read_lock_held(void)
 #endif
 #endif /* !CONFIG_SRCU */
 
+static bool device_is_ancestor(struct device *dev, struct device *target)
+{
+       while (target->parent) {
+               target = target->parent;
+               if (dev == target)
+                       return true;
+       }
+       return false;
+}
+
 /**
  * device_is_dependent - Check if one device depends on another one
  * @dev: Device to check dependencies for.
@@ -221,7 +231,12 @@ int device_is_dependent(struct device *dev, void *target)
        struct device_link *link;
        int ret;
 
-       if (dev == target)
+       /*
+        * The "ancestors" check is needed to catch the case when the target
+        * device has not been completely initialized yet and it is still
+        * missing from the list of children of its parent device.
+        */
+       if (dev == target || device_is_ancestor(dev, target))
                return 1;
 
        ret = device_for_each_child(dev, target, device_is_dependent);
@@ -456,7 +471,9 @@ static int devlink_add_symlinks(struct device *dev,
        struct device *con = link->consumer;
        char *buf;
 
-       len = max(strlen(dev_name(sup)), strlen(dev_name(con)));
+       len = max(strlen(dev_bus_name(sup)) + strlen(dev_name(sup)),
+                 strlen(dev_bus_name(con)) + strlen(dev_name(con)));
+       len += strlen(":");
        len += strlen("supplier:") + 1;
        buf = kzalloc(len, GFP_KERNEL);
        if (!buf)
@@ -470,12 +487,12 @@ static int devlink_add_symlinks(struct device *dev,
        if (ret)
                goto err_con;
 
-       snprintf(buf, len, "consumer:%s", dev_name(con));
+       snprintf(buf, len, "consumer:%s:%s", dev_bus_name(con), dev_name(con));
        ret = sysfs_create_link(&sup->kobj, &link->link_dev.kobj, buf);
        if (ret)
                goto err_con_dev;
 
-       snprintf(buf, len, "supplier:%s", dev_name(sup));
+       snprintf(buf, len, "supplier:%s:%s", dev_bus_name(sup), dev_name(sup));
        ret = sysfs_create_link(&con->kobj, &link->link_dev.kobj, buf);
        if (ret)
                goto err_sup_dev;
@@ -483,7 +500,7 @@ static int devlink_add_symlinks(struct device *dev,
        goto out;
 
 err_sup_dev:
-       snprintf(buf, len, "consumer:%s", dev_name(con));
+       snprintf(buf, len, "consumer:%s:%s", dev_bus_name(con), dev_name(con));
        sysfs_remove_link(&sup->kobj, buf);
 err_con_dev:
        sysfs_remove_link(&link->link_dev.kobj, "consumer");
@@ -506,7 +523,9 @@ static void devlink_remove_symlinks(struct device *dev,
        sysfs_remove_link(&link->link_dev.kobj, "consumer");
        sysfs_remove_link(&link->link_dev.kobj, "supplier");
 
-       len = max(strlen(dev_name(sup)), strlen(dev_name(con)));
+       len = max(strlen(dev_bus_name(sup)) + strlen(dev_name(sup)),
+                 strlen(dev_bus_name(con)) + strlen(dev_name(con)));
+       len += strlen(":");
        len += strlen("supplier:") + 1;
        buf = kzalloc(len, GFP_KERNEL);
        if (!buf) {
@@ -514,9 +533,9 @@ static void devlink_remove_symlinks(struct device *dev,
                return;
        }
 
-       snprintf(buf, len, "supplier:%s", dev_name(sup));
+       snprintf(buf, len, "supplier:%s:%s", dev_bus_name(sup), dev_name(sup));
        sysfs_remove_link(&con->kobj, buf);
-       snprintf(buf, len, "consumer:%s", dev_name(con));
+       snprintf(buf, len, "consumer:%s:%s", dev_bus_name(con), dev_name(con));
        sysfs_remove_link(&sup->kobj, buf);
        kfree(buf);
 }
@@ -737,8 +756,9 @@ struct device_link *device_link_add(struct device *consumer,
 
        link->link_dev.class = &devlink_class;
        device_set_pm_not_required(&link->link_dev);
-       dev_set_name(&link->link_dev, "%s--%s",
-                    dev_name(supplier), dev_name(consumer));
+       dev_set_name(&link->link_dev, "%s:%s--%s:%s",
+                    dev_bus_name(supplier), dev_name(supplier),
+                    dev_bus_name(consumer), dev_name(consumer));
        if (device_register(&link->link_dev)) {
                put_device(consumer);
                put_device(supplier);
@@ -1808,9 +1828,7 @@ const char *dev_driver_string(const struct device *dev)
         * never change once they are set, so they don't need special care.
         */
        drv = READ_ONCE(dev->driver);
-       return drv ? drv->name :
-                       (dev->bus ? dev->bus->name :
-                       (dev->class ? dev->class->name : ""));
+       return drv ? drv->name : dev_bus_name(dev);
 }
 EXPORT_SYMBOL(dev_driver_string);
 
index 2f32f38..9179825 100644 (file)
@@ -370,13 +370,6 @@ static void driver_bound(struct device *dev)
 
        device_pm_check_callbacks(dev);
 
-       /*
-        * Reorder successfully probed devices to the end of the device list.
-        * This ensures that suspend/resume order matches probe order, which
-        * is usually what drivers rely on.
-        */
-       device_pm_move_to_tail(dev);
-
        /*
         * Make sure the device is no longer in one of the deferred lists and
         * kick off retrying all pending devices
@@ -619,6 +612,8 @@ dev_groups_failed:
        else if (drv->remove)
                drv->remove(dev);
 probe_failed:
+       kfree(dev->dma_range_map);
+       dev->dma_range_map = NULL;
        if (dev->bus)
                blocking_notifier_call_chain(&dev->bus->p->bus_notifier,
                                             BUS_NOTIFY_DRIVER_NOT_BOUND, dev);
index 95fd154..8456d83 100644 (file)
@@ -366,6 +366,8 @@ int devm_platform_get_irqs_affinity(struct platform_device *dev,
                return -ERANGE;
 
        nvec = platform_irq_count(dev);
+       if (nvec < 0)
+               return nvec;
 
        if (nvec < minvec)
                return -ENOSPC;
index 6727358..e6ea5d3 100644 (file)
@@ -1022,6 +1022,12 @@ static int nbd_add_socket(struct nbd_device *nbd, unsigned long arg,
        if (!sock)
                return err;
 
+       /*
+        * We need to make sure we don't get any errant requests while we're
+        * reallocating the ->socks array.
+        */
+       blk_mq_freeze_queue(nbd->disk->queue);
+
        if (!netlink && !nbd->task_setup &&
            !test_bit(NBD_RT_BOUND, &config->runtime_flags))
                nbd->task_setup = current;
@@ -1060,10 +1066,12 @@ static int nbd_add_socket(struct nbd_device *nbd, unsigned long arg,
        nsock->cookie = 0;
        socks[config->num_connections++] = nsock;
        atomic_inc(&config->live_connections);
+       blk_mq_unfreeze_queue(nbd->disk->queue);
 
        return 0;
 
 put_socket:
+       blk_mq_unfreeze_queue(nbd->disk->queue);
        sockfd_put(sock);
        return err;
 }
index 148b871..fce0a54 100644 (file)
@@ -6,7 +6,10 @@
 #define CREATE_TRACE_POINTS
 #include "trace.h"
 
-#define MB_TO_SECTS(mb) (((sector_t)mb * SZ_1M) >> SECTOR_SHIFT)
+static inline sector_t mb_to_sects(unsigned long mb)
+{
+       return ((sector_t)mb * SZ_1M) >> SECTOR_SHIFT;
+}
 
 static inline unsigned int null_zone_no(struct nullb_device *dev, sector_t sect)
 {
@@ -77,12 +80,11 @@ int null_init_zoned_dev(struct nullb_device *dev, struct request_queue *q)
                return -EINVAL;
        }
 
-       zone_capacity_sects = MB_TO_SECTS(dev->zone_capacity);
-       dev_capacity_sects = MB_TO_SECTS(dev->size);
-       dev->zone_size_sects = MB_TO_SECTS(dev->zone_size);
-       dev->nr_zones = dev_capacity_sects >> ilog2(dev->zone_size_sects);
-       if (dev_capacity_sects & (dev->zone_size_sects - 1))
-               dev->nr_zones++;
+       zone_capacity_sects = mb_to_sects(dev->zone_capacity);
+       dev_capacity_sects = mb_to_sects(dev->size);
+       dev->zone_size_sects = mb_to_sects(dev->zone_size);
+       dev->nr_zones = round_up(dev_capacity_sects, dev->zone_size_sects)
+               >> ilog2(dev->zone_size_sects);
 
        dev->zones = kvmalloc_array(dev->nr_zones, sizeof(struct nullb_zone),
                                    GFP_KERNEL | __GFP_ZERO);
index 5265975..e1c6798 100644 (file)
@@ -945,7 +945,8 @@ static void blkif_set_queue_limits(struct blkfront_info *info)
        if (info->feature_discard) {
                blk_queue_flag_set(QUEUE_FLAG_DISCARD, rq);
                blk_queue_max_discard_sectors(rq, get_capacity(gd));
-               rq->limits.discard_granularity = info->discard_granularity;
+               rq->limits.discard_granularity = info->discard_granularity ?:
+                                                info->physical_sector_size;
                rq->limits.discard_alignment = info->discard_alignment;
                if (info->feature_secdiscard)
                        blk_queue_flag_set(QUEUE_FLAG_SECERASE, rq);
@@ -2179,19 +2180,12 @@ static void blkfront_closing(struct blkfront_info *info)
 
 static void blkfront_setup_discard(struct blkfront_info *info)
 {
-       int err;
-       unsigned int discard_granularity;
-       unsigned int discard_alignment;
-
        info->feature_discard = 1;
-       err = xenbus_gather(XBT_NIL, info->xbdev->otherend,
-               "discard-granularity", "%u", &discard_granularity,
-               "discard-alignment", "%u", &discard_alignment,
-               NULL);
-       if (!err) {
-               info->discard_granularity = discard_granularity;
-               info->discard_alignment = discard_alignment;
-       }
+       info->discard_granularity = xenbus_read_unsigned(info->xbdev->otherend,
+                                                        "discard-granularity",
+                                                        0);
+       info->discard_alignment = xenbus_read_unsigned(info->xbdev->otherend,
+                                                      "discard-alignment", 0);
        info->feature_secdiscard =
                !!xenbus_read_unsigned(info->xbdev->otherend, "discard-secure",
                                       0);
index 845b6c4..2344d56 100644 (file)
@@ -54,6 +54,7 @@ static int integrator_lm_populate(int num, struct device *dev)
                        ret = of_platform_default_populate(child, NULL, dev);
                        if (ret) {
                                dev_err(dev, "failed to populate module\n");
+                               of_node_put(child);
                                return ret;
                        }
                }
index c5eb46c..01a3d0c 100644 (file)
@@ -16,6 +16,7 @@
 
 static int simple_pm_bus_probe(struct platform_device *pdev)
 {
+       const struct of_dev_auxdata *lookup = dev_get_platdata(&pdev->dev);
        struct device_node *np = pdev->dev.of_node;
 
        dev_dbg(&pdev->dev, "%s\n", __func__);
@@ -23,7 +24,7 @@ static int simple_pm_bus_probe(struct platform_device *pdev)
        pm_runtime_enable(&pdev->dev);
 
        if (np)
-               of_platform_populate(np, NULL, NULL, &pdev->dev);
+               of_platform_populate(np, NULL, lookup, &pdev->dev);
 
        return 0;
 }
index 3061896..47d9ec3 100644 (file)
@@ -6,8 +6,6 @@ config MXC_CLK
 
 config MXC_CLK_SCU
        tristate
-       depends on ARCH_MXC
-       depends on IMX_SCU && HAVE_ARM_SMCCC
 
 config CLK_IMX1
        def_bool SOC_IMX1
index eea69d4..7aa7f4a 100644 (file)
@@ -392,7 +392,8 @@ static int mmp2_audio_clk_remove(struct platform_device *pdev)
        return 0;
 }
 
-static int __maybe_unused mmp2_audio_clk_suspend(struct device *dev)
+#ifdef CONFIG_PM
+static int mmp2_audio_clk_suspend(struct device *dev)
 {
        struct mmp2_audio_clk *priv = dev_get_drvdata(dev);
 
@@ -404,7 +405,7 @@ static int __maybe_unused mmp2_audio_clk_suspend(struct device *dev)
        return 0;
 }
 
-static int __maybe_unused mmp2_audio_clk_resume(struct device *dev)
+static int mmp2_audio_clk_resume(struct device *dev)
 {
        struct mmp2_audio_clk *priv = dev_get_drvdata(dev);
 
@@ -415,6 +416,7 @@ static int __maybe_unused mmp2_audio_clk_resume(struct device *dev)
 
        return 0;
 }
+#endif
 
 static const struct dev_pm_ops mmp2_audio_clk_pm_ops = {
        SET_RUNTIME_PM_OPS(mmp2_audio_clk_suspend, mmp2_audio_clk_resume, NULL)
index d82d725..b05901b 100644 (file)
@@ -891,21 +891,6 @@ static struct clk_branch gcc_boot_rom_ahb_clk = {
        },
 };
 
-static struct clk_branch gcc_camera_ahb_clk = {
-       .halt_reg = 0xb008,
-       .halt_check = BRANCH_HALT,
-       .hwcg_reg = 0xb008,
-       .hwcg_bit = 1,
-       .clkr = {
-               .enable_reg = 0xb008,
-               .enable_mask = BIT(0),
-               .hw.init = &(struct clk_init_data){
-                       .name = "gcc_camera_ahb_clk",
-                       .ops = &clk_branch2_ops,
-               },
-       },
-};
-
 static struct clk_branch gcc_camera_hf_axi_clk = {
        .halt_reg = 0xb020,
        .halt_check = BRANCH_HALT,
@@ -2317,7 +2302,6 @@ static struct clk_regmap *gcc_sc7180_clocks[] = {
        [GCC_AGGRE_UFS_PHY_AXI_CLK] = &gcc_aggre_ufs_phy_axi_clk.clkr,
        [GCC_AGGRE_USB3_PRIM_AXI_CLK] = &gcc_aggre_usb3_prim_axi_clk.clkr,
        [GCC_BOOT_ROM_AHB_CLK] = &gcc_boot_rom_ahb_clk.clkr,
-       [GCC_CAMERA_AHB_CLK] = &gcc_camera_ahb_clk.clkr,
        [GCC_CAMERA_HF_AXI_CLK] = &gcc_camera_hf_axi_clk.clkr,
        [GCC_CAMERA_THROTTLE_HF_AXI_CLK] = &gcc_camera_throttle_hf_axi_clk.clkr,
        [GCC_CAMERA_XO_CLK] = &gcc_camera_xo_clk.clkr,
@@ -2519,11 +2503,12 @@ static int gcc_sc7180_probe(struct platform_device *pdev)
 
        /*
         * Keep the clocks always-ON
-        * GCC_CPUSS_GNOC_CLK, GCC_VIDEO_AHB_CLK, GCC_DISP_AHB_CLK
-        * GCC_GPU_CFG_AHB_CLK
+        * GCC_CPUSS_GNOC_CLK, GCC_VIDEO_AHB_CLK, GCC_CAMERA_AHB_CLK,
+        * GCC_DISP_AHB_CLK, GCC_GPU_CFG_AHB_CLK
         */
        regmap_update_bits(regmap, 0x48004, BIT(0), BIT(0));
        regmap_update_bits(regmap, 0x0b004, BIT(0), BIT(0));
+       regmap_update_bits(regmap, 0x0b008, BIT(0), BIT(0));
        regmap_update_bits(regmap, 0x0b00c, BIT(0), BIT(0));
        regmap_update_bits(regmap, 0x71004, BIT(0), BIT(0));
 
index 6cb6617..ab594a0 100644 (file)
@@ -722,7 +722,7 @@ static struct clk_rcg2 gcc_sdcc2_apps_clk_src = {
                .name = "gcc_sdcc2_apps_clk_src",
                .parent_data = gcc_parent_data_4,
                .num_parents = 5,
-               .ops = &clk_rcg2_ops,
+               .ops = &clk_rcg2_floor_ops,
        },
 };
 
@@ -745,7 +745,7 @@ static struct clk_rcg2 gcc_sdcc4_apps_clk_src = {
                .name = "gcc_sdcc4_apps_clk_src",
                .parent_data = gcc_parent_data_0,
                .num_parents = 3,
-               .ops = &clk_rcg2_ops,
+               .ops = &clk_rcg2_floor_ops,
        },
 };
 
index a60aee1..65df9ef 100644 (file)
@@ -235,36 +235,6 @@ static ssize_t ti_eqep_position_ceiling_write(struct counter_device *counter,
        return len;
 }
 
-static ssize_t ti_eqep_position_floor_read(struct counter_device *counter,
-                                          struct counter_count *count,
-                                          void *ext_priv, char *buf)
-{
-       struct ti_eqep_cnt *priv = counter->priv;
-       u32 qposinit;
-
-       regmap_read(priv->regmap32, QPOSINIT, &qposinit);
-
-       return sprintf(buf, "%u\n", qposinit);
-}
-
-static ssize_t ti_eqep_position_floor_write(struct counter_device *counter,
-                                           struct counter_count *count,
-                                           void *ext_priv, const char *buf,
-                                           size_t len)
-{
-       struct ti_eqep_cnt *priv = counter->priv;
-       int err;
-       u32 res;
-
-       err = kstrtouint(buf, 0, &res);
-       if (err < 0)
-               return err;
-
-       regmap_write(priv->regmap32, QPOSINIT, res);
-
-       return len;
-}
-
 static ssize_t ti_eqep_position_enable_read(struct counter_device *counter,
                                            struct counter_count *count,
                                            void *ext_priv, char *buf)
@@ -301,11 +271,6 @@ static struct counter_count_ext ti_eqep_position_ext[] = {
                .read   = ti_eqep_position_ceiling_read,
                .write  = ti_eqep_position_ceiling_write,
        },
-       {
-               .name   = "floor",
-               .read   = ti_eqep_position_floor_read,
-               .write  = ti_eqep_position_floor_write,
-       },
        {
                .name   = "enable",
                .read   = ti_eqep_position_enable_read,
index bbd5170..e535f28 100644 (file)
@@ -366,6 +366,7 @@ if CRYPTO_DEV_OMAP
 config CRYPTO_DEV_OMAP_SHAM
        tristate "Support for OMAP MD5/SHA1/SHA2 hw accelerator"
        depends on ARCH_OMAP2PLUS
+       select CRYPTO_ENGINE
        select CRYPTO_SHA1
        select CRYPTO_MD5
        select CRYPTO_SHA256
index fabfaac..fa56b45 100644 (file)
@@ -300,11 +300,11 @@ struct mv_cesa_tdma_desc {
        __le32 byte_cnt;
        union {
                __le32 src;
-               dma_addr_t src_dma;
+               u32 src_dma;
        };
        union {
                __le32 dst;
-               dma_addr_t dst_dma;
+               u32 dst_dma;
        };
        __le32 next_dma;
 
index 34f53d8..e192648 100644 (file)
@@ -3,8 +3,9 @@
  * apple-properties.c - EFI device properties on Macs
  * Copyright (C) 2016 Lukas Wunner <lukas@wunner.de>
  *
- * Note, all properties are considered as u8 arrays.
- * To get a value of any of them the caller must use device_property_read_u8_array().
+ * Properties are stored either as:
+ * u8 arrays which can be retrieved with device_property_read_u8_array() or
+ * booleans which can be queried with device_property_present().
  */
 
 #define pr_fmt(fmt) "apple-properties: " fmt
@@ -88,8 +89,12 @@ static void __init unmarshal_key_value_pairs(struct dev_header *dev_header,
 
                entry_data = ptr + key_len + sizeof(val_len);
                entry_len = val_len - sizeof(val_len);
-               entry[i] = PROPERTY_ENTRY_U8_ARRAY_LEN(key, entry_data,
-                                                      entry_len);
+               if (entry_len)
+                       entry[i] = PROPERTY_ENTRY_U8_ARRAY_LEN(key, entry_data,
+                                                              entry_len);
+               else
+                       entry[i] = PROPERTY_ENTRY_BOOL(key);
+
                if (dump_properties) {
                        dev_info(dev, "property: %s\n", key);
                        print_hex_dump(KERN_INFO, pr_fmt(), DUMP_PREFIX_OFFSET,
index 1d2e5b8..c027d99 100644 (file)
@@ -13,6 +13,7 @@ config IMX_DSP
 config IMX_SCU
        bool "IMX SCU Protocol driver"
        depends on IMX_MBOX
+       select SOC_BUS
        help
          The System Controller Firmware (SCFW) is a low-level system function
          which runs on a dedicated Cortex-M core to provide power, clock, and
index c70f46e..dea65d8 100644 (file)
@@ -521,7 +521,8 @@ config GPIO_SAMA5D2_PIOBU
 
 config GPIO_SIFIVE
        bool "SiFive GPIO support"
-       depends on OF_GPIO && IRQ_DOMAIN_HIERARCHY
+       depends on OF_GPIO
+       select IRQ_DOMAIN_HIERARCHY
        select GPIO_GENERIC
        select GPIOLIB_IRQCHIP
        select REGMAP_MMIO
@@ -597,6 +598,8 @@ config GPIO_TEGRA
        default ARCH_TEGRA
        depends on ARCH_TEGRA || COMPILE_TEST
        depends on OF_GPIO
+       select GPIOLIB_IRQCHIP
+       select IRQ_DOMAIN_HIERARCHY
        help
          Say yes here to support GPIO pins on NVIDIA Tegra SoCs.
 
index 672681a..a912a8f 100644 (file)
@@ -676,20 +676,17 @@ static void mvebu_pwm_get_state(struct pwm_chip *chip,
        else
                state->duty_cycle = 1;
 
+       val = (unsigned long long) u; /* on duration */
        regmap_read(mvpwm->regs, mvebu_pwmreg_blink_off_duration(mvpwm), &u);
-       val = (unsigned long long) u * NSEC_PER_SEC;
+       val += (unsigned long long) u; /* period = on + off duration */
+       val *= NSEC_PER_SEC;
        do_div(val, mvpwm->clk_rate);
-       if (val < state->duty_cycle) {
+       if (val > UINT_MAX)
+               state->period = UINT_MAX;
+       else if (val)
+               state->period = val;
+       else
                state->period = 1;
-       } else {
-               val -= state->duty_cycle;
-               if (val > UINT_MAX)
-                       state->period = UINT_MAX;
-               else if (val)
-                       state->period = val;
-               else
-                       state->period = 1;
-       }
 
        regmap_read(mvchip->regs, GPIO_BLINK_EN_OFF + mvchip->offset, &u);
        if (u)
index 12b679c..1631727 100644 (file)
@@ -776,6 +776,8 @@ static void edge_detector_stop(struct line *line)
        cancel_delayed_work_sync(&line->work);
        WRITE_ONCE(line->sw_debounced, 0);
        WRITE_ONCE(line->eflags, 0);
+       if (line->desc)
+               WRITE_ONCE(line->desc->debounce_period_us, 0);
        /* do not change line->level - see comment in debounced_value() */
 }
 
@@ -1979,6 +1981,21 @@ struct gpio_chardev_data {
 #endif
 };
 
+static int chipinfo_get(struct gpio_chardev_data *cdev, void __user *ip)
+{
+       struct gpio_device *gdev = cdev->gdev;
+       struct gpiochip_info chipinfo;
+
+       memset(&chipinfo, 0, sizeof(chipinfo));
+
+       strscpy(chipinfo.name, dev_name(&gdev->dev), sizeof(chipinfo.name));
+       strscpy(chipinfo.label, gdev->label, sizeof(chipinfo.label));
+       chipinfo.lines = gdev->ngpio;
+       if (copy_to_user(ip, &chipinfo, sizeof(chipinfo)))
+               return -EFAULT;
+       return 0;
+}
+
 #ifdef CONFIG_GPIO_CDEV_V1
 /*
  * returns 0 if the versions match, else the previously selected ABI version
@@ -1993,6 +2010,41 @@ static int lineinfo_ensure_abi_version(struct gpio_chardev_data *cdata,
 
        return abiv;
 }
+
+static int lineinfo_get_v1(struct gpio_chardev_data *cdev, void __user *ip,
+                          bool watch)
+{
+       struct gpio_desc *desc;
+       struct gpioline_info lineinfo;
+       struct gpio_v2_line_info lineinfo_v2;
+
+       if (copy_from_user(&lineinfo, ip, sizeof(lineinfo)))
+               return -EFAULT;
+
+       /* this doubles as a range check on line_offset */
+       desc = gpiochip_get_desc(cdev->gdev->chip, lineinfo.line_offset);
+       if (IS_ERR(desc))
+               return PTR_ERR(desc);
+
+       if (watch) {
+               if (lineinfo_ensure_abi_version(cdev, 1))
+                       return -EPERM;
+
+               if (test_and_set_bit(lineinfo.line_offset, cdev->watched_lines))
+                       return -EBUSY;
+       }
+
+       gpio_desc_to_lineinfo(desc, &lineinfo_v2);
+       gpio_v2_line_info_to_v1(&lineinfo_v2, &lineinfo);
+
+       if (copy_to_user(ip, &lineinfo, sizeof(lineinfo))) {
+               if (watch)
+                       clear_bit(lineinfo.line_offset, cdev->watched_lines);
+               return -EFAULT;
+       }
+
+       return 0;
+}
 #endif
 
 static int lineinfo_get(struct gpio_chardev_data *cdev, void __user *ip,
@@ -2030,6 +2082,22 @@ static int lineinfo_get(struct gpio_chardev_data *cdev, void __user *ip,
        return 0;
 }
 
+static int lineinfo_unwatch(struct gpio_chardev_data *cdev, void __user *ip)
+{
+       __u32 offset;
+
+       if (copy_from_user(&offset, ip, sizeof(offset)))
+               return -EFAULT;
+
+       if (offset >= cdev->gdev->ngpio)
+               return -EINVAL;
+
+       if (!test_and_clear_bit(offset, cdev->watched_lines))
+               return -EBUSY;
+
+       return 0;
+}
+
 /*
  * gpio_ioctl() - ioctl handler for the GPIO chardev
  */
@@ -2037,80 +2105,24 @@ static long gpio_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
 {
        struct gpio_chardev_data *cdev = file->private_data;
        struct gpio_device *gdev = cdev->gdev;
-       struct gpio_chip *gc = gdev->chip;
        void __user *ip = (void __user *)arg;
-       __u32 offset;
 
        /* We fail any subsequent ioctl():s when the chip is gone */
-       if (!gc)
+       if (!gdev->chip)
                return -ENODEV;
 
        /* Fill in the struct and pass to userspace */
        if (cmd == GPIO_GET_CHIPINFO_IOCTL) {
-               struct gpiochip_info chipinfo;
-
-               memset(&chipinfo, 0, sizeof(chipinfo));
-
-               strscpy(chipinfo.name, dev_name(&gdev->dev),
-                       sizeof(chipinfo.name));
-               strscpy(chipinfo.label, gdev->label,
-                       sizeof(chipinfo.label));
-               chipinfo.lines = gdev->ngpio;
-               if (copy_to_user(ip, &chipinfo, sizeof(chipinfo)))
-                       return -EFAULT;
-               return 0;
+               return chipinfo_get(cdev, ip);
 #ifdef CONFIG_GPIO_CDEV_V1
-       } else if (cmd == GPIO_GET_LINEINFO_IOCTL) {
-               struct gpio_desc *desc;
-               struct gpioline_info lineinfo;
-               struct gpio_v2_line_info lineinfo_v2;
-
-               if (copy_from_user(&lineinfo, ip, sizeof(lineinfo)))
-                       return -EFAULT;
-
-               /* this doubles as a range check on line_offset */
-               desc = gpiochip_get_desc(gc, lineinfo.line_offset);
-               if (IS_ERR(desc))
-                       return PTR_ERR(desc);
-
-               gpio_desc_to_lineinfo(desc, &lineinfo_v2);
-               gpio_v2_line_info_to_v1(&lineinfo_v2, &lineinfo);
-
-               if (copy_to_user(ip, &lineinfo, sizeof(lineinfo)))
-                       return -EFAULT;
-               return 0;
        } else if (cmd == GPIO_GET_LINEHANDLE_IOCTL) {
                return linehandle_create(gdev, ip);
        } else if (cmd == GPIO_GET_LINEEVENT_IOCTL) {
                return lineevent_create(gdev, ip);
-       } else if (cmd == GPIO_GET_LINEINFO_WATCH_IOCTL) {
-               struct gpio_desc *desc;
-               struct gpioline_info lineinfo;
-               struct gpio_v2_line_info lineinfo_v2;
-
-               if (copy_from_user(&lineinfo, ip, sizeof(lineinfo)))
-                       return -EFAULT;
-
-               /* this doubles as a range check on line_offset */
-               desc = gpiochip_get_desc(gc, lineinfo.line_offset);
-               if (IS_ERR(desc))
-                       return PTR_ERR(desc);
-
-               if (lineinfo_ensure_abi_version(cdev, 1))
-                       return -EPERM;
-
-               if (test_and_set_bit(lineinfo.line_offset, cdev->watched_lines))
-                       return -EBUSY;
-
-               gpio_desc_to_lineinfo(desc, &lineinfo_v2);
-               gpio_v2_line_info_to_v1(&lineinfo_v2, &lineinfo);
-
-               if (copy_to_user(ip, &lineinfo, sizeof(lineinfo))) {
-                       clear_bit(lineinfo.line_offset, cdev->watched_lines);
-                       return -EFAULT;
-               }
-
-               return 0;
+       } else if (cmd == GPIO_GET_LINEINFO_IOCTL ||
+                  cmd == GPIO_GET_LINEINFO_WATCH_IOCTL) {
+               return lineinfo_get_v1(cdev, ip,
+                                      cmd == GPIO_GET_LINEINFO_WATCH_IOCTL);
 #endif /* CONFIG_GPIO_CDEV_V1 */
        } else if (cmd == GPIO_V2_GET_LINEINFO_IOCTL ||
                   cmd == GPIO_V2_GET_LINEINFO_WATCH_IOCTL) {
@@ -2119,16 +2131,7 @@ static long gpio_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
        } else if (cmd == GPIO_V2_GET_LINE_IOCTL) {
                return linereq_create(gdev, ip);
        } else if (cmd == GPIO_GET_LINEINFO_UNWATCH_IOCTL) {
-               if (copy_from_user(&offset, ip, sizeof(offset)))
-                       return -EFAULT;
-
-               if (offset >= cdev->gdev->ngpio)
-                       return -EINVAL;
-
-               if (!test_and_clear_bit(offset, cdev->watched_lines))
-                       return -EBUSY;
-
-               return 0;
+               return lineinfo_unwatch(cdev, ip);
        }
        return -EINVAL;
 }
index b02cc2a..97eec8d 100644 (file)
@@ -603,7 +603,11 @@ int gpiochip_add_data_with_key(struct gpio_chip *gc, void *data,
                ret = gdev->id;
                goto err_free_gdev;
        }
-       dev_set_name(&gdev->dev, GPIOCHIP_NAME "%d", gdev->id);
+
+       ret = dev_set_name(&gdev->dev, GPIOCHIP_NAME "%d", gdev->id);
+       if (ret)
+               goto err_free_ida;
+
        device_initialize(&gdev->dev);
        dev_set_drvdata(&gdev->dev, gdev);
        if (gc->parent && gc->parent->driver)
@@ -617,7 +621,7 @@ int gpiochip_add_data_with_key(struct gpio_chip *gc, void *data,
        gdev->descs = kcalloc(gc->ngpio, sizeof(gdev->descs[0]), GFP_KERNEL);
        if (!gdev->descs) {
                ret = -ENOMEM;
-               goto err_free_ida;
+               goto err_free_dev_name;
        }
 
        if (gc->ngpio == 0) {
@@ -768,6 +772,8 @@ err_free_label:
        kfree_const(gdev->label);
 err_free_descs:
        kfree(gdev->descs);
+err_free_dev_name:
+       kfree(dev_name(&gdev->dev));
 err_free_ida:
        ida_free(&gpio_ida, gdev->id);
 err_free_gdev:
@@ -1489,6 +1495,9 @@ static int gpiochip_add_irqchip(struct gpio_chip *gc,
                type = IRQ_TYPE_NONE;
        }
 
+       if (gc->to_irq)
+               chip_warn(gc, "to_irq is redefined in %s and you shouldn't rely on it\n", __func__);
+
        gc->to_irq = gpiochip_to_irq;
        gc->irq.default_type = type;
        gc->irq.lock_key = lock_key;
@@ -2548,7 +2557,7 @@ int gpiod_get_array_value_complex(bool raw, bool can_sleep,
                struct gpio_chip *gc = desc_array[i]->gdev->chip;
                unsigned long fastpath[2 * BITS_TO_LONGS(FASTPATH_NGPIO)];
                unsigned long *mask, *bits;
-               int first, j, ret;
+               int first, j;
 
                if (likely(gc->ngpio <= FASTPATH_NGPIO)) {
                        mask = fastpath;
index 2d991da..d1ed4f8 100644 (file)
@@ -26,6 +26,7 @@
 #include <linux/sched/task.h>
 
 #include "amdgpu_object.h"
+#include "amdgpu_gem.h"
 #include "amdgpu_vm.h"
 #include "amdgpu_amdkfd.h"
 #include "amdgpu_dma_buf.h"
@@ -1152,7 +1153,7 @@ int amdgpu_amdkfd_gpuvm_alloc_memory_of_gpu(
        struct sg_table *sg = NULL;
        uint64_t user_addr = 0;
        struct amdgpu_bo *bo;
-       struct amdgpu_bo_param bp;
+       struct drm_gem_object *gobj;
        u32 domain, alloc_domain;
        u64 alloc_flags;
        int ret;
@@ -1220,19 +1221,14 @@ int amdgpu_amdkfd_gpuvm_alloc_memory_of_gpu(
        pr_debug("\tcreate BO VA 0x%llx size 0x%llx domain %s\n",
                        va, size, domain_string(alloc_domain));
 
-       memset(&bp, 0, sizeof(bp));
-       bp.size = size;
-       bp.byte_align = 1;
-       bp.domain = alloc_domain;
-       bp.flags = alloc_flags;
-       bp.type = bo_type;
-       bp.resv = NULL;
-       ret = amdgpu_bo_create(adev, &bp, &bo);
+       ret = amdgpu_gem_object_create(adev, size, 1, alloc_domain, alloc_flags,
+                                      bo_type, NULL, &gobj);
        if (ret) {
                pr_debug("Failed to create BO on domain %s. ret %d\n",
-                               domain_string(alloc_domain), ret);
+                        domain_string(alloc_domain), ret);
                goto err_bo_create;
        }
+       bo = gem_to_amdgpu_bo(gobj);
        if (bo_type == ttm_bo_type_sg) {
                bo->tbo.sg = sg;
                bo->tbo.ttm->sg = sg;
index 087afab..cab1eba 100644 (file)
@@ -81,7 +81,6 @@ MODULE_FIRMWARE("amdgpu/navi10_gpu_info.bin");
 MODULE_FIRMWARE("amdgpu/navi14_gpu_info.bin");
 MODULE_FIRMWARE("amdgpu/navi12_gpu_info.bin");
 MODULE_FIRMWARE("amdgpu/vangogh_gpu_info.bin");
-MODULE_FIRMWARE("amdgpu/green_sardine_gpu_info.bin");
 
 #define AMDGPU_RESUME_MS               2000
 
index f764803..48cb33e 100644 (file)
@@ -926,8 +926,10 @@ amdgpu_display_user_framebuffer_create(struct drm_device *dev,
                                       struct drm_file *file_priv,
                                       const struct drm_mode_fb_cmd2 *mode_cmd)
 {
-       struct drm_gem_object *obj;
        struct amdgpu_framebuffer *amdgpu_fb;
+       struct drm_gem_object *obj;
+       struct amdgpu_bo *bo;
+       uint32_t domains;
        int ret;
 
        obj = drm_gem_object_lookup(file_priv, mode_cmd->handles[0]);
@@ -938,7 +940,9 @@ amdgpu_display_user_framebuffer_create(struct drm_device *dev,
        }
 
        /* Handle is imported dma-buf, so cannot be migrated to VRAM for scanout */
-       if (obj->import_attach) {
+       bo = gem_to_amdgpu_bo(obj);
+       domains = amdgpu_display_supported_domains(drm_to_adev(dev), bo->flags);
+       if (obj->import_attach && !(domains & AMDGPU_GEM_DOMAIN_GTT)) {
                drm_dbg_kms(dev, "Cannot create framebuffer from imported dma_buf\n");
                return ERR_PTR(-EINVAL);
        }
index d0a1fee..174a73e 100644 (file)
@@ -269,8 +269,8 @@ int amdgpu_gem_create_ioctl(struct drm_device *dev, void *data,
                resv = vm->root.base.bo->tbo.base.resv;
        }
 
-retry:
        initial_domain = (u32)(0xffffffff & args->in.domains);
+retry:
        r = amdgpu_gem_object_create(adev, size, args->in.alignment,
                                     initial_domain,
                                     flags, ttm_bo_type_device, resv, &gobj);
index 25ec4d5..b4c8e5d 100644 (file)
@@ -897,7 +897,7 @@ int amdgpu_bo_pin_restricted(struct amdgpu_bo *bo, u32 domain,
                return -EINVAL;
 
        /* A shared bo cannot be migrated to VRAM */
-       if (bo->prime_shared_count) {
+       if (bo->prime_shared_count || bo->tbo.base.import_attach) {
                if (domain & AMDGPU_GEM_DOMAIN_GTT)
                        domain = AMDGPU_GEM_DOMAIN_GTT;
                else
index 619d34c..d86b42a 100644 (file)
 #define mmGCR_GENERAL_CNTL_Sienna_Cichlid                      0x1580
 #define mmGCR_GENERAL_CNTL_Sienna_Cichlid_BASE_IDX     0
 
+#define mmCGTS_TCC_DISABLE_Vangogh                0x5006
+#define mmCGTS_TCC_DISABLE_Vangogh_BASE_IDX       1
+#define mmCGTS_USER_TCC_DISABLE_Vangogh                0x5007
+#define mmCGTS_USER_TCC_DISABLE_Vangogh_BASE_IDX       1
 #define mmGOLDEN_TSC_COUNT_UPPER_Vangogh                0x0025
 #define mmGOLDEN_TSC_COUNT_UPPER_Vangogh_BASE_IDX       1
 #define mmGOLDEN_TSC_COUNT_LOWER_Vangogh                0x0026
 #define mmVGT_ESGS_RING_SIZE_Vangogh_BASE_IDX    1
 #define mmSPI_CONFIG_CNTL_Vangogh                0x2440
 #define mmSPI_CONFIG_CNTL_Vangogh_BASE_IDX       1
+#define mmGCR_GENERAL_CNTL_Vangogh               0x1580
+#define mmGCR_GENERAL_CNTL_Vangogh_BASE_IDX      0
 
 #define mmCP_HYP_PFP_UCODE_ADDR                        0x5814
 #define mmCP_HYP_PFP_UCODE_ADDR_BASE_IDX       1
@@ -3244,7 +3250,7 @@ static const struct soc15_reg_golden golden_settings_gc_10_3_vangogh[] =
        SOC15_REG_GOLDEN_VALUE(GC, 0, mmDB_DEBUG4, 0xffffffff, 0x00800000),
        SOC15_REG_GOLDEN_VALUE(GC, 0, mmDB_EXCEPTION_CONTROL, 0x7fff0f1f, 0x00b80000),
        SOC15_REG_GOLDEN_VALUE(GC, 0, mmGB_ADDR_CONFIG, 0x0c1807ff, 0x00000142),
-       SOC15_REG_GOLDEN_VALUE(GC, 0, mmGCR_GENERAL_CNTL, 0x1ff1ffff, 0x00000500),
+       SOC15_REG_GOLDEN_VALUE(GC, 0, mmGCR_GENERAL_CNTL_Vangogh, 0x1ff1ffff, 0x00000500),
        SOC15_REG_GOLDEN_VALUE(GC, 0, mmGL1_PIPE_STEER, 0x000000ff, 0x000000e4),
        SOC15_REG_GOLDEN_VALUE(GC, 0, mmGL2_PIPE_STEER_0, 0x77777777, 0x32103210),
        SOC15_REG_GOLDEN_VALUE(GC, 0, mmGL2_PIPE_STEER_1, 0x77777777, 0x32103210),
@@ -4934,8 +4940,18 @@ static void gfx_v10_0_tcp_harvest(struct amdgpu_device *adev)
 static void gfx_v10_0_get_tcc_info(struct amdgpu_device *adev)
 {
        /* TCCs are global (not instanced). */
-       uint32_t tcc_disable = RREG32_SOC15(GC, 0, mmCGTS_TCC_DISABLE) |
-                              RREG32_SOC15(GC, 0, mmCGTS_USER_TCC_DISABLE);
+       uint32_t tcc_disable;
+
+       switch (adev->asic_type) {
+       case CHIP_VANGOGH:
+               tcc_disable = RREG32_SOC15(GC, 0, mmCGTS_TCC_DISABLE_Vangogh) |
+                               RREG32_SOC15(GC, 0, mmCGTS_USER_TCC_DISABLE_Vangogh);
+               break;
+       default:
+               tcc_disable = RREG32_SOC15(GC, 0, mmCGTS_TCC_DISABLE) |
+                               RREG32_SOC15(GC, 0, mmCGTS_USER_TCC_DISABLE);
+               break;
+       }
 
        adev->gfx.config.tcc_disabled_mask =
                REG_GET_FIELD(tcc_disable, CGTS_TCC_DISABLE, TCC_DISABLE) |
index 07104a1..1961745 100644 (file)
@@ -491,12 +491,11 @@ mmhub_v2_3_update_medium_grain_clock_gating(struct amdgpu_device *adev,
 {
        uint32_t def, data, def1, data1;
 
-       def  = data  = RREG32_SOC15(MMHUB, 0, mmMM_ATC_L2_MISC_CG);
+       def  = data  = RREG32_SOC15(MMHUB, 0, mmMM_ATC_L2_CGTT_CLK_CTRL);
        def1 = data1 = RREG32_SOC15(MMHUB, 0, mmDAGB0_CNTL_MISC2);
 
        if (enable && (adev->cg_flags & AMD_CG_SUPPORT_MC_MGCG)) {
-               data |= MM_ATC_L2_MISC_CG__ENABLE_MASK;
-
+               data &= ~MM_ATC_L2_CGTT_CLK_CTRL__SOFT_OVERRIDE_MASK;
                data1 &= ~(DAGB0_CNTL_MISC2__DISABLE_WRREQ_CG_MASK |
                           DAGB0_CNTL_MISC2__DISABLE_WRRET_CG_MASK |
                           DAGB0_CNTL_MISC2__DISABLE_RDREQ_CG_MASK |
@@ -505,8 +504,7 @@ mmhub_v2_3_update_medium_grain_clock_gating(struct amdgpu_device *adev,
                           DAGB0_CNTL_MISC2__DISABLE_TLBRD_CG_MASK);
 
        } else {
-               data &= ~MM_ATC_L2_MISC_CG__ENABLE_MASK;
-
+               data |= MM_ATC_L2_CGTT_CLK_CTRL__SOFT_OVERRIDE_MASK;
                data1 |= (DAGB0_CNTL_MISC2__DISABLE_WRREQ_CG_MASK |
                          DAGB0_CNTL_MISC2__DISABLE_WRRET_CG_MASK |
                          DAGB0_CNTL_MISC2__DISABLE_RDREQ_CG_MASK |
@@ -516,7 +514,7 @@ mmhub_v2_3_update_medium_grain_clock_gating(struct amdgpu_device *adev,
        }
 
        if (def != data)
-               WREG32_SOC15(MMHUB, 0, mmMM_ATC_L2_MISC_CG, data);
+               WREG32_SOC15(MMHUB, 0, mmMM_ATC_L2_CGTT_CLK_CTRL, data);
        if (def1 != data1)
                WREG32_SOC15(MMHUB, 0, mmDAGB0_CNTL_MISC2, data1);
 }
@@ -525,17 +523,44 @@ static void
 mmhub_v2_3_update_medium_grain_light_sleep(struct amdgpu_device *adev,
                                           bool enable)
 {
-       uint32_t def, data;
-
-       def  = data  = RREG32_SOC15(MMHUB, 0, mmMM_ATC_L2_MISC_CG);
-
-       if (enable && (adev->cg_flags & AMD_CG_SUPPORT_MC_LS))
-               data |= MM_ATC_L2_MISC_CG__MEM_LS_ENABLE_MASK;
-       else
-               data &= ~MM_ATC_L2_MISC_CG__MEM_LS_ENABLE_MASK;
+       uint32_t def, data, def1, data1, def2, data2;
+
+       def  = data  = RREG32_SOC15(MMHUB, 0, mmMM_ATC_L2_CGTT_CLK_CTRL);
+       def1 = data1 = RREG32_SOC15(MMHUB, 0, mmDAGB0_WR_CGTT_CLK_CTRL);
+       def2 = data2 = RREG32_SOC15(MMHUB, 0, mmDAGB0_RD_CGTT_CLK_CTRL);
+
+       if (enable && (adev->cg_flags & AMD_CG_SUPPORT_MC_LS)) {
+               data &= ~MM_ATC_L2_CGTT_CLK_CTRL__MGLS_OVERRIDE_MASK;
+               data1 &= !(DAGB0_WR_CGTT_CLK_CTRL__LS_OVERRIDE_MASK |
+                       DAGB0_WR_CGTT_CLK_CTRL__LS_OVERRIDE_WRITE_MASK |
+                       DAGB0_WR_CGTT_CLK_CTRL__LS_OVERRIDE_READ_MASK |
+                       DAGB0_WR_CGTT_CLK_CTRL__LS_OVERRIDE_RETURN_MASK |
+                       DAGB0_WR_CGTT_CLK_CTRL__LS_OVERRIDE_REGISTER_MASK);
+               data2 &= !(DAGB0_RD_CGTT_CLK_CTRL__LS_OVERRIDE_MASK |
+                       DAGB0_RD_CGTT_CLK_CTRL__LS_OVERRIDE_WRITE_MASK |
+                       DAGB0_RD_CGTT_CLK_CTRL__LS_OVERRIDE_READ_MASK |
+                       DAGB0_RD_CGTT_CLK_CTRL__LS_OVERRIDE_RETURN_MASK |
+                       DAGB0_RD_CGTT_CLK_CTRL__LS_OVERRIDE_REGISTER_MASK);
+       } else {
+               data |= MM_ATC_L2_CGTT_CLK_CTRL__MGLS_OVERRIDE_MASK;
+               data1 |= (DAGB0_WR_CGTT_CLK_CTRL__LS_OVERRIDE_MASK |
+                       DAGB0_WR_CGTT_CLK_CTRL__LS_OVERRIDE_WRITE_MASK |
+                       DAGB0_WR_CGTT_CLK_CTRL__LS_OVERRIDE_READ_MASK |
+                       DAGB0_WR_CGTT_CLK_CTRL__LS_OVERRIDE_RETURN_MASK |
+                       DAGB0_WR_CGTT_CLK_CTRL__LS_OVERRIDE_REGISTER_MASK);
+               data2 |= (DAGB0_RD_CGTT_CLK_CTRL__LS_OVERRIDE_MASK |
+                       DAGB0_RD_CGTT_CLK_CTRL__LS_OVERRIDE_WRITE_MASK |
+                       DAGB0_RD_CGTT_CLK_CTRL__LS_OVERRIDE_READ_MASK |
+                       DAGB0_RD_CGTT_CLK_CTRL__LS_OVERRIDE_RETURN_MASK |
+                       DAGB0_RD_CGTT_CLK_CTRL__LS_OVERRIDE_REGISTER_MASK);
+       }
 
        if (def != data)
-               WREG32_SOC15(MMHUB, 0, mmMM_ATC_L2_MISC_CG, data);
+               WREG32_SOC15(MMHUB, 0, mmMM_ATC_L2_CGTT_CLK_CTRL, data);
+       if (def1 != data1)
+               WREG32_SOC15(MMHUB, 0, mmDAGB0_WR_CGTT_CLK_CTRL, data1);
+       if (def2 != data2)
+               WREG32_SOC15(MMHUB, 0, mmDAGB0_RD_CGTT_CLK_CTRL, data2);
 }
 
 static int mmhub_v2_3_set_clockgating(struct amdgpu_device *adev,
@@ -554,26 +579,39 @@ static int mmhub_v2_3_set_clockgating(struct amdgpu_device *adev,
 
 static void mmhub_v2_3_get_clockgating(struct amdgpu_device *adev, u32 *flags)
 {
-       int data, data1;
+       int data, data1, data2, data3;
 
        if (amdgpu_sriov_vf(adev))
                *flags = 0;
 
-       data  = RREG32_SOC15(MMHUB, 0, mmMM_ATC_L2_MISC_CG);
-       data1 = RREG32_SOC15(MMHUB, 0, mmDAGB0_CNTL_MISC2);
+       data = RREG32_SOC15(MMHUB, 0, mmDAGB0_CNTL_MISC2);
+       data1  = RREG32_SOC15(MMHUB, 0, mmMM_ATC_L2_CGTT_CLK_CTRL);
+       data2 = RREG32_SOC15(MMHUB, 0, mmDAGB0_WR_CGTT_CLK_CTRL);
+       data3 = RREG32_SOC15(MMHUB, 0, mmDAGB0_RD_CGTT_CLK_CTRL);
 
        /* AMD_CG_SUPPORT_MC_MGCG */
-       if ((data & MM_ATC_L2_MISC_CG__ENABLE_MASK) &&
-           !(data1 & (DAGB0_CNTL_MISC2__DISABLE_WRREQ_CG_MASK |
+       if (!(data & (DAGB0_CNTL_MISC2__DISABLE_WRREQ_CG_MASK |
                       DAGB0_CNTL_MISC2__DISABLE_WRRET_CG_MASK |
                       DAGB0_CNTL_MISC2__DISABLE_RDREQ_CG_MASK |
                       DAGB0_CNTL_MISC2__DISABLE_RDRET_CG_MASK |
                       DAGB0_CNTL_MISC2__DISABLE_TLBWR_CG_MASK |
-                      DAGB0_CNTL_MISC2__DISABLE_TLBRD_CG_MASK)))
-               *flags |= AMD_CG_SUPPORT_MC_MGCG;
+                      DAGB0_CNTL_MISC2__DISABLE_TLBRD_CG_MASK))
+               && !(data1 & MM_ATC_L2_CGTT_CLK_CTRL__SOFT_OVERRIDE_MASK)) {
+                       *flags |= AMD_CG_SUPPORT_MC_MGCG;
+       }
 
        /* AMD_CG_SUPPORT_MC_LS */
-       if (data & MM_ATC_L2_MISC_CG__MEM_LS_ENABLE_MASK)
+       if (!(data1 & MM_ATC_L2_CGTT_CLK_CTRL__MGLS_OVERRIDE_MASK)
+               && !(data2 & (DAGB0_WR_CGTT_CLK_CTRL__LS_OVERRIDE_MASK |
+                               DAGB0_WR_CGTT_CLK_CTRL__LS_OVERRIDE_WRITE_MASK |
+                               DAGB0_WR_CGTT_CLK_CTRL__LS_OVERRIDE_READ_MASK |
+                               DAGB0_WR_CGTT_CLK_CTRL__LS_OVERRIDE_RETURN_MASK |
+                               DAGB0_WR_CGTT_CLK_CTRL__LS_OVERRIDE_REGISTER_MASK))
+               && !(data3 & (DAGB0_RD_CGTT_CLK_CTRL__LS_OVERRIDE_MASK |
+                               DAGB0_RD_CGTT_CLK_CTRL__LS_OVERRIDE_WRITE_MASK |
+                               DAGB0_RD_CGTT_CLK_CTRL__LS_OVERRIDE_READ_MASK |
+                               DAGB0_RD_CGTT_CLK_CTRL__LS_OVERRIDE_RETURN_MASK |
+                               DAGB0_RD_CGTT_CLK_CTRL__LS_OVERRIDE_REGISTER_MASK)))
                *flags |= AMD_CG_SUPPORT_MC_LS;
 }
 
index c6da89d..961abf1 100644 (file)
@@ -1833,8 +1833,8 @@ static void emulated_link_detect(struct dc_link *link)
        link->type = dc_connection_none;
        prev_sink = link->local_sink;
 
-       if (prev_sink != NULL)
-               dc_sink_retain(prev_sink);
+       if (prev_sink)
+               dc_sink_release(prev_sink);
 
        switch (link->connector_signal) {
        case SIGNAL_TYPE_HDMI_TYPE_A: {
@@ -1934,7 +1934,7 @@ static void dm_gpureset_commit_state(struct dc_state *dc_state,
                dc_commit_updates_for_stream(
                        dm->dc, bundle->surface_updates,
                        dc_state->stream_status->plane_count,
-                       dc_state->streams[k], &bundle->stream_update, dc_state);
+                       dc_state->streams[k], &bundle->stream_update);
        }
 
 cleanup:
@@ -1965,8 +1965,7 @@ static void dm_set_dpms_off(struct dc_link *link)
 
        stream_update.stream = stream_state;
        dc_commit_updates_for_stream(stream_state->ctx->dc, NULL, 0,
-                                    stream_state, &stream_update,
-                                    stream_state->ctx->dc->current_state);
+                                    stream_state, &stream_update);
        mutex_unlock(&adev->dm.dc_lock);
 }
 
@@ -2330,8 +2329,10 @@ void amdgpu_dm_update_connector_after_detect(
                 * TODO: check if we still need the S3 mode update workaround.
                 * If yes, put it here.
                 */
-               if (aconnector->dc_sink)
+               if (aconnector->dc_sink) {
                        amdgpu_dm_update_freesync_caps(connector, NULL);
+                       dc_sink_release(aconnector->dc_sink);
+               }
 
                aconnector->dc_sink = sink;
                dc_sink_retain(aconnector->dc_sink);
@@ -2347,8 +2348,6 @@ void amdgpu_dm_update_connector_after_detect(
 
                        drm_connector_update_edid_property(connector,
                                                           aconnector->edid);
-                       drm_add_edid_modes(connector, aconnector->edid);
-
                        if (aconnector->dc_link->aux_mode)
                                drm_dp_cec_set_edid(&aconnector->dm_dp_aux.aux,
                                                    aconnector->edid);
@@ -7549,7 +7548,7 @@ static void amdgpu_dm_commit_planes(struct drm_atomic_state *state,
                                    struct drm_crtc *pcrtc,
                                    bool wait_for_vblank)
 {
-       uint32_t i;
+       int i;
        uint64_t timestamp_ns;
        struct drm_plane *plane;
        struct drm_plane_state *old_plane_state, *new_plane_state;
@@ -7590,7 +7589,7 @@ static void amdgpu_dm_commit_planes(struct drm_atomic_state *state,
                amdgpu_dm_commit_cursors(state);
 
        /* update planes when needed */
-       for_each_oldnew_plane_in_state(state, plane, old_plane_state, new_plane_state, i) {
+       for_each_oldnew_plane_in_state_reverse(state, plane, old_plane_state, new_plane_state, i) {
                struct drm_crtc *crtc = new_plane_state->crtc;
                struct drm_crtc_state *new_crtc_state;
                struct drm_framebuffer *fb = new_plane_state->fb;
@@ -7813,8 +7812,7 @@ static void amdgpu_dm_commit_planes(struct drm_atomic_state *state,
                                                     bundle->surface_updates,
                                                     planes_count,
                                                     acrtc_state->stream,
-                                                    &bundle->stream_update,
-                                                    dc_state);
+                                                    &bundle->stream_update);
 
                /**
                 * Enable or disable the interrupts on the backend.
@@ -8150,13 +8148,13 @@ static void amdgpu_dm_atomic_commit_tail(struct drm_atomic_state *state)
                struct dm_connector_state *dm_new_con_state = to_dm_connector_state(new_con_state);
                struct dm_connector_state *dm_old_con_state = to_dm_connector_state(old_con_state);
                struct amdgpu_crtc *acrtc = to_amdgpu_crtc(dm_new_con_state->base.crtc);
-               struct dc_surface_update dummy_updates[MAX_SURFACES];
+               struct dc_surface_update surface_updates[MAX_SURFACES];
                struct dc_stream_update stream_update;
                struct dc_info_packet hdr_packet;
                struct dc_stream_status *status = NULL;
                bool abm_changed, hdr_changed, scaling_changed;
 
-               memset(&dummy_updates, 0, sizeof(dummy_updates));
+               memset(&surface_updates, 0, sizeof(surface_updates));
                memset(&stream_update, 0, sizeof(stream_update));
 
                if (acrtc) {
@@ -8213,16 +8211,15 @@ static void amdgpu_dm_atomic_commit_tail(struct drm_atomic_state *state)
                 * To fix this, DC should permit updating only stream properties.
                 */
                for (j = 0; j < status->plane_count; j++)
-                       dummy_updates[j].surface = status->plane_states[0];
+                       surface_updates[j].surface = status->plane_states[j];
 
 
                mutex_lock(&dm->dc_lock);
                dc_commit_updates_for_stream(dm->dc,
-                                                    dummy_updates,
+                                               surface_updates,
                                                     status->plane_count,
                                                     dm_new_crtc_state->stream,
-                                                    &stream_update,
-                                                    dc_state);
+                                                    &stream_update);
                mutex_unlock(&dm->dc_lock);
        }
 
@@ -8359,14 +8356,14 @@ static int dm_force_atomic_commit(struct drm_connector *connector)
 
        ret = PTR_ERR_OR_ZERO(conn_state);
        if (ret)
-               goto err;
+               goto out;
 
        /* Attach crtc to drm_atomic_state*/
        crtc_state = drm_atomic_get_crtc_state(state, &disconnected_acrtc->base);
 
        ret = PTR_ERR_OR_ZERO(crtc_state);
        if (ret)
-               goto err;
+               goto out;
 
        /* force a restore */
        crtc_state->mode_changed = true;
@@ -8376,17 +8373,15 @@ static int dm_force_atomic_commit(struct drm_connector *connector)
 
        ret = PTR_ERR_OR_ZERO(plane_state);
        if (ret)
-               goto err;
-
+               goto out;
 
        /* Call commit internally with the state we just constructed */
        ret = drm_atomic_commit(state);
-       if (!ret)
-               return 0;
 
-err:
-       DRM_ERROR("Restoring old state failed with %i\n", ret);
+out:
        drm_atomic_state_put(state);
+       if (ret)
+               DRM_ERROR("Restoring old state failed with %i\n", ret);
 
        return ret;
 }
index 8ab0b90..f2d8cf3 100644 (file)
@@ -833,6 +833,9 @@ bool compute_mst_dsc_configs_for_state(struct drm_atomic_state *state,
                if (computed_streams[i])
                        continue;
 
+               if (dcn20_remove_stream_from_ctx(stream->ctx->dc, dc_state, stream) != DC_OK)
+                       return false;
+
                mutex_lock(&aconnector->mst_mgr.lock);
                if (!compute_mst_dsc_configs_for_link(state, dc_state, stream->link)) {
                        mutex_unlock(&aconnector->mst_mgr.lock);
@@ -850,7 +853,8 @@ bool compute_mst_dsc_configs_for_state(struct drm_atomic_state *state,
                stream = dc_state->streams[i];
 
                if (stream->timing.flags.DSC == 1)
-                       dc_stream_add_dsc_to_resource(stream->ctx->dc, dc_state, stream);
+                       if (dc_stream_add_dsc_to_resource(stream->ctx->dc, dc_state, stream) != DC_OK)
+                               return false;
        }
 
        return true;
index 5b466f4..ab98c25 100644 (file)
@@ -251,6 +251,7 @@ static void dcn3_update_clocks(struct clk_mgr *clk_mgr_base,
        struct dmcu *dmcu = clk_mgr_base->ctx->dc->res_pool->dmcu;
        bool force_reset = false;
        bool update_uclk = false;
+       bool p_state_change_support;
 
        if (dc->work_arounds.skip_clock_update || !clk_mgr->smu_present)
                return;
@@ -291,8 +292,9 @@ static void dcn3_update_clocks(struct clk_mgr *clk_mgr_base,
                clk_mgr_base->clks.socclk_khz = new_clocks->socclk_khz;
 
        clk_mgr_base->clks.prev_p_state_change_support = clk_mgr_base->clks.p_state_change_support;
-       if (should_update_pstate_support(safe_to_lower, new_clocks->p_state_change_support, clk_mgr_base->clks.p_state_change_support)) {
-               clk_mgr_base->clks.p_state_change_support = new_clocks->p_state_change_support;
+       p_state_change_support = new_clocks->p_state_change_support || (display_count == 0);
+       if (should_update_pstate_support(safe_to_lower, p_state_change_support, clk_mgr_base->clks.p_state_change_support)) {
+               clk_mgr_base->clks.p_state_change_support = p_state_change_support;
 
                /* to disable P-State switching, set UCLK min = max */
                if (!clk_mgr_base->clks.p_state_change_support)
index 58eb0d6..6cf1a5a 100644 (file)
@@ -2679,8 +2679,7 @@ void dc_commit_updates_for_stream(struct dc *dc,
                struct dc_surface_update *srf_updates,
                int surface_count,
                struct dc_stream_state *stream,
-               struct dc_stream_update *stream_update,
-               struct dc_state *state)
+               struct dc_stream_update *stream_update)
 {
        const struct dc_stream_status *stream_status;
        enum surface_update_type update_type;
@@ -2699,6 +2698,12 @@ void dc_commit_updates_for_stream(struct dc *dc,
 
 
        if (update_type >= UPDATE_TYPE_FULL) {
+               struct dc_plane_state *new_planes[MAX_SURFACES];
+
+               memset(new_planes, 0, sizeof(new_planes));
+
+               for (i = 0; i < surface_count; i++)
+                       new_planes[i] = srf_updates[i].surface;
 
                /* initialize scratch memory for building context */
                context = dc_create_state(dc);
@@ -2707,15 +2712,21 @@ void dc_commit_updates_for_stream(struct dc *dc,
                        return;
                }
 
-               dc_resource_state_copy_construct(state, context);
+               dc_resource_state_copy_construct(
+                               dc->current_state, context);
 
-               for (i = 0; i < dc->res_pool->pipe_count; i++) {
-                       struct pipe_ctx *new_pipe = &context->res_ctx.pipe_ctx[i];
-                       struct pipe_ctx *old_pipe = &dc->current_state->res_ctx.pipe_ctx[i];
+               /*remove old surfaces from context */
+               if (!dc_rem_all_planes_for_stream(dc, stream, context)) {
+                       DC_ERROR("Failed to remove streams for new validate context!\n");
+                       return;
+               }
 
-                       if (new_pipe->plane_state && new_pipe->plane_state != old_pipe->plane_state)
-                               new_pipe->plane_state->force_full_update = true;
+               /* add surface to context */
+               if (!dc_add_all_planes_for_stream(dc, stream, new_planes, surface_count, context)) {
+                       DC_ERROR("Failed to add streams for new validate context!\n");
+                       return;
                }
+
        }
 
 
index 1bd1a09..1e4794e 100644 (file)
@@ -892,13 +892,13 @@ static uint32_t translate_training_aux_read_interval(uint32_t dpcd_aux_read_inte
 
        switch (dpcd_aux_read_interval) {
        case 0x01:
-               aux_rd_interval_us = 400;
+               aux_rd_interval_us = 4000;
                break;
        case 0x02:
-               aux_rd_interval_us = 4000;
+               aux_rd_interval_us = 8000;
                break;
        case 0x03:
-               aux_rd_interval_us = 8000;
+               aux_rd_interval_us = 12000;
                break;
        case 0x04:
                aux_rd_interval_us = 16000;
@@ -2399,6 +2399,9 @@ static bool decide_dp_link_settings(struct dc_link *link, struct dc_link_setting
                        initial_link_setting;
        uint32_t link_bw;
 
+       if (req_bw > dc_link_bandwidth_kbps(link, &link->verified_link_cap))
+               return false;
+
        /* search for the minimum link setting that:
         * 1. is supported according to the link training result
         * 2. could support the b/w requested by the timing
@@ -3045,14 +3048,14 @@ bool dc_link_handle_hpd_rx_irq(struct dc_link *link, union hpd_irq_data *out_hpd
                for (i = 0; i < MAX_PIPES; i++) {
                        pipe_ctx = &link->dc->current_state->res_ctx.pipe_ctx[i];
                        if (pipe_ctx && pipe_ctx->stream && !pipe_ctx->stream->dpms_off &&
-                                       pipe_ctx->stream->link == link)
+                                       pipe_ctx->stream->link == link && !pipe_ctx->prev_odm_pipe)
                                core_link_disable_stream(pipe_ctx);
                }
 
                for (i = 0; i < MAX_PIPES; i++) {
                        pipe_ctx = &link->dc->current_state->res_ctx.pipe_ctx[i];
                        if (pipe_ctx && pipe_ctx->stream && !pipe_ctx->stream->dpms_off &&
-                                       pipe_ctx->stream->link == link)
+                                       pipe_ctx->stream->link == link && !pipe_ctx->prev_odm_pipe)
                                core_link_enable_stream(link->dc->current_state, pipe_ctx);
                }
 
index b791097..e243c01 100644 (file)
@@ -283,8 +283,7 @@ void dc_commit_updates_for_stream(struct dc *dc,
                struct dc_surface_update *srf_updates,
                int surface_count,
                struct dc_stream_state *stream,
-               struct dc_stream_update *stream_update,
-               struct dc_state *state);
+               struct dc_stream_update *stream_update);
 /*
  * Log the current stream state.
  */
index cfc130e..017b67b 100644 (file)
@@ -647,8 +647,13 @@ static void power_on_plane(
        if (REG(DC_IP_REQUEST_CNTL)) {
                REG_SET(DC_IP_REQUEST_CNTL, 0,
                                IP_REQUEST_EN, 1);
-               hws->funcs.dpp_pg_control(hws, plane_id, true);
-               hws->funcs.hubp_pg_control(hws, plane_id, true);
+
+               if (hws->funcs.dpp_pg_control)
+                       hws->funcs.dpp_pg_control(hws, plane_id, true);
+
+               if (hws->funcs.hubp_pg_control)
+                       hws->funcs.hubp_pg_control(hws, plane_id, true);
+
                REG_SET(DC_IP_REQUEST_CNTL, 0,
                                IP_REQUEST_EN, 0);
                DC_LOG_DEBUG(
@@ -1082,8 +1087,13 @@ void dcn10_plane_atomic_power_down(struct dc *dc,
        if (REG(DC_IP_REQUEST_CNTL)) {
                REG_SET(DC_IP_REQUEST_CNTL, 0,
                                IP_REQUEST_EN, 1);
-               hws->funcs.dpp_pg_control(hws, dpp->inst, false);
-               hws->funcs.hubp_pg_control(hws, hubp->inst, false);
+
+               if (hws->funcs.dpp_pg_control)
+                       hws->funcs.dpp_pg_control(hws, dpp->inst, false);
+
+               if (hws->funcs.hubp_pg_control)
+                       hws->funcs.hubp_pg_control(hws, hubp->inst, false);
+
                dpp->funcs->dpp_reset(dpp);
                REG_SET(DC_IP_REQUEST_CNTL, 0,
                                IP_REQUEST_EN, 0);
index cb822df..480d928 100644 (file)
@@ -1062,8 +1062,13 @@ static void dcn20_power_on_plane(
        if (REG(DC_IP_REQUEST_CNTL)) {
                REG_SET(DC_IP_REQUEST_CNTL, 0,
                                IP_REQUEST_EN, 1);
-               dcn20_dpp_pg_control(hws, pipe_ctx->plane_res.dpp->inst, true);
-               dcn20_hubp_pg_control(hws, pipe_ctx->plane_res.hubp->inst, true);
+
+               if (hws->funcs.dpp_pg_control)
+                       hws->funcs.dpp_pg_control(hws, pipe_ctx->plane_res.dpp->inst, true);
+
+               if (hws->funcs.hubp_pg_control)
+                       hws->funcs.hubp_pg_control(hws, pipe_ctx->plane_res.hubp->inst, true);
+
                REG_SET(DC_IP_REQUEST_CNTL, 0,
                                IP_REQUEST_EN, 0);
                DC_LOG_DEBUG(
index e04ecf0..5ed18ca 100644 (file)
@@ -2517,8 +2517,7 @@ struct pipe_ctx *dcn20_find_secondary_pipe(struct dc *dc,
                 * if this primary pipe has a bottom pipe in prev. state
                 * and if the bottom pipe is still available (which it should be),
                 * pick that pipe as secondary
-                * Same logic applies for ODM pipes. Since mpo is not allowed with odm
-                * check in else case.
+                * Same logic applies for ODM pipes
                 */
                if (dc->current_state->res_ctx.pipe_ctx[primary_pipe->pipe_idx].bottom_pipe) {
                        preferred_pipe_idx = dc->current_state->res_ctx.pipe_ctx[primary_pipe->pipe_idx].bottom_pipe->pipe_idx;
@@ -2526,7 +2525,9 @@ struct pipe_ctx *dcn20_find_secondary_pipe(struct dc *dc,
                                secondary_pipe = &res_ctx->pipe_ctx[preferred_pipe_idx];
                                secondary_pipe->pipe_idx = preferred_pipe_idx;
                        }
-               } else if (dc->current_state->res_ctx.pipe_ctx[primary_pipe->pipe_idx].next_odm_pipe) {
+               }
+               if (secondary_pipe == NULL &&
+                               dc->current_state->res_ctx.pipe_ctx[primary_pipe->pipe_idx].next_odm_pipe) {
                        preferred_pipe_idx = dc->current_state->res_ctx.pipe_ctx[primary_pipe->pipe_idx].next_odm_pipe->pipe_idx;
                        if (res_ctx->pipe_ctx[preferred_pipe_idx].stream == NULL) {
                                secondary_pipe = &res_ctx->pipe_ctx[preferred_pipe_idx];
index 1c88d2e..6743764 100644 (file)
@@ -296,7 +296,7 @@ struct _vcs_dpi_soc_bounding_box_st dcn2_1_soc = {
        .num_banks = 8,
        .num_chans = 4,
        .vmm_page_size_bytes = 4096,
-       .dram_clock_change_latency_us = 23.84,
+       .dram_clock_change_latency_us = 11.72,
        .return_bus_width_bytes = 64,
        .dispclk_dppclk_vco_speed_mhz = 3600,
        .xfc_bus_transport_time_us = 4,
@@ -906,6 +906,8 @@ enum dcn20_clk_src_array_id {
        DCN20_CLK_SRC_PLL0,
        DCN20_CLK_SRC_PLL1,
        DCN20_CLK_SRC_PLL2,
+       DCN20_CLK_SRC_PLL3,
+       DCN20_CLK_SRC_PLL4,
        DCN20_CLK_SRC_TOTAL_DCN21
 };
 
@@ -2030,6 +2032,14 @@ static bool dcn21_resource_construct(
                        dcn21_clock_source_create(ctx, ctx->dc_bios,
                                CLOCK_SOURCE_COMBO_PHY_PLL2,
                                &clk_src_regs[2], false);
+       pool->base.clock_sources[DCN20_CLK_SRC_PLL3] =
+                       dcn21_clock_source_create(ctx, ctx->dc_bios,
+                               CLOCK_SOURCE_COMBO_PHY_PLL3,
+                               &clk_src_regs[3], false);
+       pool->base.clock_sources[DCN20_CLK_SRC_PLL4] =
+                       dcn21_clock_source_create(ctx, ctx->dc_bios,
+                               CLOCK_SOURCE_COMBO_PHY_PLL4,
+                               &clk_src_regs[4], false);
 
        pool->base.clk_src_count = DCN20_CLK_SRC_TOTAL_DCN21;
 
index c20331e..dfd77b3 100644 (file)
@@ -32,8 +32,8 @@ DCN30 = dcn30_init.o dcn30_hubbub.o dcn30_hubp.o dcn30_dpp.o dcn30_optc.o \
 
 
 ifdef CONFIG_X86
-CFLAGS_$(AMDDALPATH)/dc/dcn30/dcn30_resource.o := -mhard-float -msse
-CFLAGS_$(AMDDALPATH)/dc/dcn30/dcn30_optc.o := -mhard-float -msse
+CFLAGS_$(AMDDALPATH)/dc/dcn30/dcn30_resource.o := -msse
+CFLAGS_$(AMDDALPATH)/dc/dcn30/dcn30_optc.o := -msse
 endif
 
 ifdef CONFIG_PPC64
@@ -45,6 +45,8 @@ ifdef CONFIG_CC_IS_GCC
 ifeq ($(call cc-ifversion, -lt, 0701, y), y)
 IS_OLD_GCC = 1
 endif
+CFLAGS_$(AMDDALPATH)/dc/dcn30/dcn30_resource.o += -mhard-float
+CFLAGS_$(AMDDALPATH)/dc/dcn30/dcn30_optc.o += -mhard-float
 endif
 
 ifdef CONFIG_X86
index 3ca7d91..0926471 100644 (file)
@@ -14,7 +14,7 @@ DCN301 = dcn301_init.o dcn301_resource.o dcn301_dccg.o \
                dcn301_dio_link_encoder.o dcn301_hwseq.o dcn301_panel_cntl.o dcn301_hubbub.o
 
 ifdef CONFIG_X86
-CFLAGS_$(AMDDALPATH)/dc/dcn301/dcn301_resource.o := -mhard-float -msse
+CFLAGS_$(AMDDALPATH)/dc/dcn301/dcn301_resource.o := -msse
 endif
 
 ifdef CONFIG_PPC64
@@ -25,6 +25,7 @@ ifdef CONFIG_CC_IS_GCC
 ifeq ($(call cc-ifversion, -lt, 0701, y), y)
 IS_OLD_GCC = 1
 endif
+CFLAGS_$(AMDDALPATH)/dc/dcn301/dcn301_resource.o += -mhard-float
 endif
 
 ifdef CONFIG_X86
index 8d4924b..101620a 100644 (file)
@@ -13,7 +13,7 @@
 DCN3_02 = dcn302_init.o dcn302_hwseq.o dcn302_resource.o
 
 ifdef CONFIG_X86
-CFLAGS_$(AMDDALPATH)/dc/dcn302/dcn302_resource.o := -mhard-float -msse
+CFLAGS_$(AMDDALPATH)/dc/dcn302/dcn302_resource.o := -msse
 endif
 
 ifdef CONFIG_PPC64
@@ -24,6 +24,7 @@ ifdef CONFIG_CC_IS_GCC
 ifeq ($(call cc-ifversion, -lt, 0701, y), y)
 IS_OLD_GCC = 1
 endif
+CFLAGS_$(AMDDALPATH)/dc/dcn302/dcn302_resource.o += -mhard-float
 endif
 
 ifdef CONFIG_X86
index 4bdbcce..0d797fa 100644 (file)
@@ -553,6 +553,7 @@ struct pptable_funcs {
                                             *clock_req);
        uint32_t (*get_fan_control_mode)(struct smu_context *smu);
        int (*set_fan_control_mode)(struct smu_context *smu, uint32_t mode);
+       int (*set_fan_speed_percent)(struct smu_context *smu, uint32_t speed);
        int (*set_fan_speed_rpm)(struct smu_context *smu, uint32_t speed);
        int (*set_xgmi_pstate)(struct smu_context *smu, uint32_t pstate);
        int (*gfx_off_control)(struct smu_context *smu, bool enable);
index 13de692..5d0b296 100644 (file)
@@ -203,6 +203,9 @@ int
 smu_v11_0_set_fan_control_mode(struct smu_context *smu,
                               uint32_t mode);
 
+int
+smu_v11_0_set_fan_speed_percent(struct smu_context *smu, uint32_t speed);
+
 int smu_v11_0_set_fan_speed_rpm(struct smu_context *smu,
                                       uint32_t speed);
 
index 8b867a6..e84c737 100644 (file)
@@ -2151,19 +2151,14 @@ int smu_get_fan_speed_percent(struct smu_context *smu, uint32_t *speed)
 int smu_set_fan_speed_percent(struct smu_context *smu, uint32_t speed)
 {
        int ret = 0;
-       uint32_t rpm;
 
        if (!smu->pm_enabled || !smu->adev->pm.dpm_enabled)
                return -EOPNOTSUPP;
 
        mutex_lock(&smu->mutex);
 
-       if (smu->ppt_funcs->set_fan_speed_rpm) {
-               if (speed > 100)
-                       speed = 100;
-               rpm = speed * smu->fan_max_rpm / 100;
-               ret = smu->ppt_funcs->set_fan_speed_rpm(smu, rpm);
-       }
+       if (smu->ppt_funcs->set_fan_speed_percent)
+               ret = smu->ppt_funcs->set_fan_speed_percent(smu, speed);
 
        mutex_unlock(&smu->mutex);
 
index cd7b411..16db0b5 100644 (file)
@@ -2326,6 +2326,7 @@ static const struct pptable_funcs arcturus_ppt_funcs = {
        .display_clock_voltage_request = smu_v11_0_display_clock_voltage_request,
        .get_fan_control_mode = smu_v11_0_get_fan_control_mode,
        .set_fan_control_mode = smu_v11_0_set_fan_control_mode,
+       .set_fan_speed_percent = smu_v11_0_set_fan_speed_percent,
        .set_fan_speed_rpm = smu_v11_0_set_fan_speed_rpm,
        .set_xgmi_pstate = smu_v11_0_set_xgmi_pstate,
        .gfx_off_control = smu_v11_0_gfx_off_control,
index 51e8312..cd7efa9 100644 (file)
@@ -2456,6 +2456,7 @@ static const struct pptable_funcs navi10_ppt_funcs = {
        .display_clock_voltage_request = smu_v11_0_display_clock_voltage_request,
        .get_fan_control_mode = smu_v11_0_get_fan_control_mode,
        .set_fan_control_mode = smu_v11_0_set_fan_control_mode,
+       .set_fan_speed_percent = smu_v11_0_set_fan_speed_percent,
        .set_fan_speed_rpm = smu_v11_0_set_fan_speed_rpm,
        .set_xgmi_pstate = smu_v11_0_set_xgmi_pstate,
        .gfx_off_control = smu_v11_0_gfx_off_control,
index 12b36eb..d68d3df 100644 (file)
@@ -2802,6 +2802,7 @@ static const struct pptable_funcs sienna_cichlid_ppt_funcs = {
        .display_clock_voltage_request = smu_v11_0_display_clock_voltage_request,
        .get_fan_control_mode = smu_v11_0_get_fan_control_mode,
        .set_fan_control_mode = smu_v11_0_set_fan_control_mode,
+       .set_fan_speed_percent = smu_v11_0_set_fan_speed_percent,
        .set_fan_speed_rpm = smu_v11_0_set_fan_speed_rpm,
        .set_xgmi_pstate = smu_v11_0_set_xgmi_pstate,
        .gfx_off_control = smu_v11_0_gfx_off_control,
index b279dbb..5aeb5f5 100644 (file)
@@ -1173,6 +1173,35 @@ smu_v11_0_set_fan_static_mode(struct smu_context *smu, uint32_t mode)
        return 0;
 }
 
+int
+smu_v11_0_set_fan_speed_percent(struct smu_context *smu, uint32_t speed)
+{
+       struct amdgpu_device *adev = smu->adev;
+       uint32_t duty100, duty;
+       uint64_t tmp64;
+
+       if (speed > 100)
+               speed = 100;
+
+       if (smu_v11_0_auto_fan_control(smu, 0))
+               return -EINVAL;
+
+       duty100 = REG_GET_FIELD(RREG32_SOC15(THM, 0, mmCG_FDO_CTRL1),
+                               CG_FDO_CTRL1, FMAX_DUTY100);
+       if (!duty100)
+               return -EINVAL;
+
+       tmp64 = (uint64_t)speed * duty100;
+       do_div(tmp64, 100);
+       duty = (uint32_t)tmp64;
+
+       WREG32_SOC15(THM, 0, mmCG_FDO_CTRL0,
+                    REG_SET_FIELD(RREG32_SOC15(THM, 0, mmCG_FDO_CTRL0),
+                                  CG_FDO_CTRL0, FDO_STATIC_DUTY, duty));
+
+       return smu_v11_0_set_fan_static_mode(smu, FDO_PWM_MODE_STATIC);
+}
+
 int
 smu_v11_0_set_fan_control_mode(struct smu_context *smu,
                               uint32_t mode)
@@ -1181,7 +1210,7 @@ smu_v11_0_set_fan_control_mode(struct smu_context *smu,
 
        switch (mode) {
        case AMD_FAN_CTRL_NONE:
-               ret = smu_v11_0_set_fan_speed_rpm(smu, smu->fan_max_rpm);
+               ret = smu_v11_0_set_fan_speed_percent(smu, 100);
                break;
        case AMD_FAN_CTRL_MANUAL:
                ret = smu_v11_0_auto_fan_control(smu, 0);
index 5c1482d..92ad2cd 100644 (file)
@@ -591,14 +591,17 @@ static ssize_t vangogh_get_gpu_metrics(struct smu_context *smu,
        gpu_metrics->average_socket_power = metrics.CurrentSocketPower;
        gpu_metrics->average_cpu_power = metrics.Power[0];
        gpu_metrics->average_soc_power = metrics.Power[1];
+       gpu_metrics->average_gfx_power = metrics.Power[2];
        memcpy(&gpu_metrics->average_core_power[0],
                &metrics.CorePower[0],
                sizeof(uint16_t) * 8);
 
        gpu_metrics->average_gfxclk_frequency = metrics.GfxclkFrequency;
        gpu_metrics->average_socclk_frequency = metrics.SocclkFrequency;
+       gpu_metrics->average_uclk_frequency = metrics.MemclkFrequency;
        gpu_metrics->average_fclk_frequency = metrics.MemclkFrequency;
        gpu_metrics->average_vclk_frequency = metrics.VclkFrequency;
+       gpu_metrics->average_dclk_frequency = metrics.DclkFrequency;
 
        memcpy(&gpu_metrics->current_coreclk[0],
                &metrics.CoreFrequency[0],
index f743685..9a96970 100644 (file)
@@ -1121,7 +1121,7 @@ static ssize_t renoir_get_gpu_metrics(struct smu_context *smu,
 static int renoir_gfx_state_change_set(struct smu_context *smu, uint32_t state)
 {
 
-       return smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_GpuChangeState, state, NULL);
+       return 0;
 }
 
 static const struct pptable_funcs renoir_ppt_funcs = {
index 0c98d27..fee2795 100644 (file)
@@ -14,6 +14,7 @@
 #include <linux/regmap.h>
 #include <linux/regulator/consumer.h>
 #include <linux/wait.h>
+#include <linux/workqueue.h>
 
 #include <sound/hdmi-codec.h>
 
@@ -36,6 +37,7 @@ struct lt9611uxc {
        struct mutex ocm_lock;
 
        struct wait_queue_head wq;
+       struct work_struct work;
 
        struct device_node *dsi0_node;
        struct device_node *dsi1_node;
@@ -52,6 +54,8 @@ struct lt9611uxc {
 
        bool hpd_supported;
        bool edid_read;
+       /* can be accessed from different threads, so protect this with ocm_lock */
+       bool hdmi_connected;
        uint8_t fw_version;
 };
 
@@ -143,21 +147,41 @@ static irqreturn_t lt9611uxc_irq_thread_handler(int irq, void *dev_id)
        if (irq_status)
                regmap_write(lt9611uxc->regmap, 0xb022, 0);
 
-       lt9611uxc_unlock(lt9611uxc);
-
-       if (irq_status & BIT(0))
+       if (irq_status & BIT(0)) {
                lt9611uxc->edid_read = !!(hpd_status & BIT(0));
+               wake_up_all(&lt9611uxc->wq);
+       }
 
        if (irq_status & BIT(1)) {
-               if (lt9611uxc->connector.dev)
-                       drm_kms_helper_hotplug_event(lt9611uxc->connector.dev);
-               else
-                       drm_bridge_hpd_notify(&lt9611uxc->bridge, !!(hpd_status & BIT(1)));
+               lt9611uxc->hdmi_connected = hpd_status & BIT(1);
+               schedule_work(&lt9611uxc->work);
        }
 
+       lt9611uxc_unlock(lt9611uxc);
+
        return IRQ_HANDLED;
 }
 
+static void lt9611uxc_hpd_work(struct work_struct *work)
+{
+       struct lt9611uxc *lt9611uxc = container_of(work, struct lt9611uxc, work);
+       bool connected;
+
+       if (lt9611uxc->connector.dev)
+               drm_kms_helper_hotplug_event(lt9611uxc->connector.dev);
+       else {
+
+               mutex_lock(&lt9611uxc->ocm_lock);
+               connected = lt9611uxc->hdmi_connected;
+               mutex_unlock(&lt9611uxc->ocm_lock);
+
+               drm_bridge_hpd_notify(&lt9611uxc->bridge,
+                                     connected ?
+                                     connector_status_connected :
+                                     connector_status_disconnected);
+       }
+}
+
 static void lt9611uxc_reset(struct lt9611uxc *lt9611uxc)
 {
        gpiod_set_value_cansleep(lt9611uxc->reset_gpio, 1);
@@ -445,18 +469,21 @@ static enum drm_connector_status lt9611uxc_bridge_detect(struct drm_bridge *brid
        struct lt9611uxc *lt9611uxc = bridge_to_lt9611uxc(bridge);
        unsigned int reg_val = 0;
        int ret;
-       int connected = 1;
+       bool connected = true;
+
+       lt9611uxc_lock(lt9611uxc);
 
        if (lt9611uxc->hpd_supported) {
-               lt9611uxc_lock(lt9611uxc);
                ret = regmap_read(lt9611uxc->regmap, 0xb023, &reg_val);
-               lt9611uxc_unlock(lt9611uxc);
 
                if (ret)
                        dev_err(lt9611uxc->dev, "failed to read hpd status: %d\n", ret);
                else
                        connected  = reg_val & BIT(1);
        }
+       lt9611uxc->hdmi_connected = connected;
+
+       lt9611uxc_unlock(lt9611uxc);
 
        return connected ?  connector_status_connected :
                                connector_status_disconnected;
@@ -465,7 +492,7 @@ static enum drm_connector_status lt9611uxc_bridge_detect(struct drm_bridge *brid
 static int lt9611uxc_wait_for_edid(struct lt9611uxc *lt9611uxc)
 {
        return wait_event_interruptible_timeout(lt9611uxc->wq, lt9611uxc->edid_read,
-                       msecs_to_jiffies(100));
+                       msecs_to_jiffies(500));
 }
 
 static int lt9611uxc_get_edid_block(void *data, u8 *buf, unsigned int block, size_t len)
@@ -503,7 +530,10 @@ static struct edid *lt9611uxc_bridge_get_edid(struct drm_bridge *bridge,
        ret = lt9611uxc_wait_for_edid(lt9611uxc);
        if (ret < 0) {
                dev_err(lt9611uxc->dev, "wait for EDID failed: %d\n", ret);
-               return ERR_PTR(ret);
+               return NULL;
+       } else if (ret == 0) {
+               dev_err(lt9611uxc->dev, "wait for EDID timeout\n");
+               return NULL;
        }
 
        return drm_do_get_edid(connector, lt9611uxc_get_edid_block, lt9611uxc);
@@ -926,6 +956,8 @@ retry:
        lt9611uxc->fw_version = ret;
 
        init_waitqueue_head(&lt9611uxc->wq);
+       INIT_WORK(&lt9611uxc->work, lt9611uxc_hpd_work);
+
        ret = devm_request_threaded_irq(dev, client->irq, NULL,
                                        lt9611uxc_irq_thread_handler,
                                        IRQF_ONESHOT, "lt9611uxc", lt9611uxc);
@@ -962,6 +994,7 @@ static int lt9611uxc_remove(struct i2c_client *client)
        struct lt9611uxc *lt9611uxc = i2c_get_clientdata(client);
 
        disable_irq(client->irq);
+       flush_scheduled_work();
        lt9611uxc_audio_exit(lt9611uxc);
        drm_bridge_remove(&lt9611uxc->bridge);
 
index ba15070..4a8cbec 100644 (file)
@@ -3021,7 +3021,7 @@ int drm_atomic_helper_set_config(struct drm_mode_set *set,
 
        ret = handle_conflicting_encoders(state, true);
        if (ret)
-               return ret;
+               goto fail;
 
        ret = drm_atomic_commit(state);
 
index 0401b2f..8781dee 100644 (file)
@@ -3629,14 +3629,26 @@ static int drm_dp_send_up_ack_reply(struct drm_dp_mst_topology_mgr *mgr,
        return 0;
 }
 
-static int drm_dp_get_vc_payload_bw(u8 dp_link_bw, u8  dp_link_count)
+/**
+ * drm_dp_get_vc_payload_bw - get the VC payload BW for an MST link
+ * @link_rate: link rate in 10kbits/s units
+ * @link_lane_count: lane count
+ *
+ * Calculate the total bandwidth of a MultiStream Transport link. The returned
+ * value is in units of PBNs/(timeslots/1 MTP). This value can be used to
+ * convert the number of PBNs required for a given stream to the number of
+ * timeslots this stream requires in each MTP.
+ */
+int drm_dp_get_vc_payload_bw(int link_rate, int link_lane_count)
 {
-       if (dp_link_bw == 0 || dp_link_count == 0)
-               DRM_DEBUG_KMS("invalid link bandwidth in DPCD: %x (link count: %d)\n",
-                             dp_link_bw, dp_link_count);
+       if (link_rate == 0 || link_lane_count == 0)
+               DRM_DEBUG_KMS("invalid link rate/lane count: (%d / %d)\n",
+                             link_rate, link_lane_count);
 
-       return dp_link_bw * dp_link_count / 2;
+       /* See DP v2.0 2.6.4.2, VCPayload_Bandwidth_for_OneTimeSlotPer_MTP_Allocation */
+       return link_rate * link_lane_count / 54000;
 }
+EXPORT_SYMBOL(drm_dp_get_vc_payload_bw);
 
 /**
  * drm_dp_read_mst_cap() - check whether or not a sink supports MST
@@ -3692,7 +3704,7 @@ int drm_dp_mst_topology_mgr_set_mst(struct drm_dp_mst_topology_mgr *mgr, bool ms
                        goto out_unlock;
                }
 
-               mgr->pbn_div = drm_dp_get_vc_payload_bw(mgr->dpcd[1],
+               mgr->pbn_div = drm_dp_get_vc_payload_bw(drm_dp_bw_code_to_link_rate(mgr->dpcd[1]),
                                                        mgr->dpcd[2] & DP_MAX_LANE_COUNT_MASK);
                if (mgr->pbn_div == 0) {
                        ret = -EINVAL;
index 02ca22e..0b232a7 100644 (file)
@@ -387,9 +387,16 @@ static int drm_gem_vram_kmap_locked(struct drm_gem_vram_object *gbo,
        if (gbo->vmap_use_count > 0)
                goto out;
 
-       ret = ttm_bo_vmap(&gbo->bo, &gbo->map);
-       if (ret)
-               return ret;
+       /*
+        * VRAM helpers unmap the BO only on demand. So the previous
+        * page mapping might still be around. Only vmap if the there's
+        * no mapping present.
+        */
+       if (dma_buf_map_is_null(&gbo->map)) {
+               ret = ttm_bo_vmap(&gbo->bo, &gbo->map);
+               if (ret)
+                       return ret;
+       }
 
 out:
        ++gbo->vmap_use_count;
@@ -577,6 +584,7 @@ static void drm_gem_vram_bo_driver_move_notify(struct drm_gem_vram_object *gbo,
                return;
 
        ttm_bo_vunmap(bo, &gbo->map);
+       dma_buf_map_clear(&gbo->map); /* explicitly clear mapping for next vmap call */
 }
 
 static int drm_gem_vram_bo_driver_move(struct drm_gem_vram_object *gbo,
index 6e74e67..3491460 100644 (file)
@@ -388,19 +388,18 @@ int drm_syncobj_find_fence(struct drm_file *file_private,
                return -ENOENT;
 
        *fence = drm_syncobj_fence_get(syncobj);
-       drm_syncobj_put(syncobj);
 
        if (*fence) {
                ret = dma_fence_chain_find_seqno(fence, point);
                if (!ret)
-                       return 0;
+                       goto out;
                dma_fence_put(*fence);
        } else {
                ret = -EINVAL;
        }
 
        if (!(flags & DRM_SYNCOBJ_WAIT_FLAGS_WAIT_FOR_SUBMIT))
-               return ret;
+               goto out;
 
        memset(&wait, 0, sizeof(wait));
        wait.task = current;
@@ -432,6 +431,9 @@ int drm_syncobj_find_fence(struct drm_file *file_private,
        if (wait.node.next)
                drm_syncobj_remove_wait(syncobj, &wait);
 
+out:
+       drm_syncobj_put(syncobj);
+
        return ret;
 }
 EXPORT_SYMBOL(drm_syncobj_find_fence);
index 92940a0..dc13d18 100644 (file)
@@ -2754,13 +2754,15 @@ static void icl_mg_phy_ddi_vswing_sequence(struct intel_encoder *encoder,
        int n_entries, ln;
        u32 val;
 
+       if (enc_to_dig_port(encoder)->tc_mode == TC_PORT_TBT_ALT)
+               return;
+
        ddi_translations = icl_get_mg_buf_trans(encoder, crtc_state, &n_entries);
-       /* The table does not have values for level 3 and level 9. */
-       if (level >= n_entries || level == 3 || level == 9) {
+       if (level >= n_entries) {
                drm_dbg_kms(&dev_priv->drm,
                            "DDI translation not found for level %d. Using %d instead.",
-                           level, n_entries - 2);
-               level = n_entries - 2;
+                           level, n_entries - 1);
+               level = n_entries - 1;
        }
 
        /* Set MG_TX_LINK_PARAMS cri_use_fs32 to 0. */
@@ -2891,6 +2893,9 @@ tgl_dkl_phy_ddi_vswing_sequence(struct intel_encoder *encoder,
        u32 val, dpcnt_mask, dpcnt_val;
        int n_entries, ln;
 
+       if (enc_to_dig_port(encoder)->tc_mode == TC_PORT_TBT_ALT)
+               return;
+
        ddi_translations = tgl_get_dkl_buf_trans(encoder, crtc_state, &n_entries);
 
        if (level >= n_entries)
@@ -3532,6 +3537,23 @@ static void intel_ddi_disable_fec_state(struct intel_encoder *encoder,
        intel_de_posting_read(dev_priv, dp_tp_ctl_reg(encoder, crtc_state));
 }
 
+static void intel_ddi_power_up_lanes(struct intel_encoder *encoder,
+                                    const struct intel_crtc_state *crtc_state)
+{
+       struct drm_i915_private *i915 = to_i915(encoder->base.dev);
+       struct intel_digital_port *dig_port = enc_to_dig_port(encoder);
+       enum phy phy = intel_port_to_phy(i915, encoder->port);
+
+       if (intel_phy_is_combo(i915, phy)) {
+               bool lane_reversal =
+                       dig_port->saved_port_bits & DDI_BUF_PORT_REVERSAL;
+
+               intel_combo_phy_power_up_lanes(i915, phy, false,
+                                              crtc_state->lane_count,
+                                              lane_reversal);
+       }
+}
+
 static void tgl_ddi_pre_enable_dp(struct intel_atomic_state *state,
                                  struct intel_encoder *encoder,
                                  const struct intel_crtc_state *crtc_state,
@@ -3621,14 +3643,7 @@ static void tgl_ddi_pre_enable_dp(struct intel_atomic_state *state,
         * 7.f Combo PHY: Configure PORT_CL_DW10 Static Power Down to power up
         * the used lanes of the DDI.
         */
-       if (intel_phy_is_combo(dev_priv, phy)) {
-               bool lane_reversal =
-                       dig_port->saved_port_bits & DDI_BUF_PORT_REVERSAL;
-
-               intel_combo_phy_power_up_lanes(dev_priv, phy, false,
-                                              crtc_state->lane_count,
-                                              lane_reversal);
-       }
+       intel_ddi_power_up_lanes(encoder, crtc_state);
 
        /*
         * 7.g Configure and enable DDI_BUF_CTL
@@ -3713,19 +3728,12 @@ static void hsw_ddi_pre_enable_dp(struct intel_atomic_state *state,
        else
                intel_prepare_dp_ddi_buffers(encoder, crtc_state);
 
-       if (intel_phy_is_combo(dev_priv, phy)) {
-               bool lane_reversal =
-                       dig_port->saved_port_bits & DDI_BUF_PORT_REVERSAL;
-
-               intel_combo_phy_power_up_lanes(dev_priv, phy, false,
-                                              crtc_state->lane_count,
-                                              lane_reversal);
-       }
+       intel_ddi_power_up_lanes(encoder, crtc_state);
 
        intel_ddi_init_dp_buf_reg(encoder, crtc_state);
        if (!is_mst)
                intel_dp_set_power(intel_dp, DP_SET_POWER_D0);
-       intel_dp_configure_protocol_converter(intel_dp);
+       intel_dp_configure_protocol_converter(intel_dp, crtc_state);
        intel_dp_sink_set_decompression_state(intel_dp, crtc_state,
                                              true);
        intel_dp_sink_set_fec_ready(intel_dp, crtc_state);
@@ -4206,6 +4214,8 @@ static void intel_enable_ddi_hdmi(struct intel_atomic_state *state,
                intel_de_write(dev_priv, reg, val);
        }
 
+       intel_ddi_power_up_lanes(encoder, crtc_state);
+
        /* In HDMI/DVI mode, the port width, and swing/emphasis values
         * are ignored so nothing special needs to be done besides
         * enabling the port.
index 53a00cf..61be6be 100644 (file)
@@ -2309,7 +2309,7 @@ intel_pin_and_fence_fb_obj(struct drm_framebuffer *fb,
                 */
                ret = i915_vma_pin_fence(vma);
                if (ret != 0 && INTEL_GEN(dev_priv) < 4) {
-                       i915_gem_object_unpin_from_display_plane(vma);
+                       i915_vma_unpin(vma);
                        vma = ERR_PTR(ret);
                        goto err;
                }
@@ -2327,12 +2327,9 @@ err:
 
 void intel_unpin_fb_vma(struct i915_vma *vma, unsigned long flags)
 {
-       i915_gem_object_lock(vma->obj, NULL);
        if (flags & PLANE_HAS_FENCE)
                i915_vma_unpin_fence(vma);
-       i915_gem_object_unpin_from_display_plane(vma);
-       i915_gem_object_unlock(vma->obj);
-
+       i915_vma_unpin(vma);
        i915_vma_put(vma);
 }
 
@@ -4807,6 +4804,8 @@ u32 glk_plane_color_ctl(const struct intel_crtc_state *crtc_state,
                        plane_color_ctl |= PLANE_COLOR_YUV_RANGE_CORRECTION_DISABLE;
        } else if (fb->format->is_yuv) {
                plane_color_ctl |= PLANE_COLOR_INPUT_CSC_ENABLE;
+               if (plane_state->hw.color_range == DRM_COLOR_YCBCR_FULL_RANGE)
+                       plane_color_ctl |= PLANE_COLOR_YUV_RANGE_CORRECTION_DISABLE;
        }
 
        return plane_color_ctl;
index 37f1a10..8a26307 100644 (file)
@@ -4014,7 +4014,8 @@ static void intel_dp_enable_port(struct intel_dp *intel_dp,
        intel_de_posting_read(dev_priv, intel_dp->output_reg);
 }
 
-void intel_dp_configure_protocol_converter(struct intel_dp *intel_dp)
+void intel_dp_configure_protocol_converter(struct intel_dp *intel_dp,
+                                          const struct intel_crtc_state *crtc_state)
 {
        struct drm_i915_private *i915 = dp_to_i915(intel_dp);
        u8 tmp;
@@ -4033,8 +4034,8 @@ void intel_dp_configure_protocol_converter(struct intel_dp *intel_dp)
                drm_dbg_kms(&i915->drm, "Failed to set protocol converter HDMI mode to %s\n",
                            enableddisabled(intel_dp->has_hdmi_sink));
 
-       tmp = intel_dp->dfp.ycbcr_444_to_420 ?
-               DP_CONVERSION_TO_YCBCR420_ENABLE : 0;
+       tmp = crtc_state->output_format == INTEL_OUTPUT_FORMAT_YCBCR444 &&
+               intel_dp->dfp.ycbcr_444_to_420 ? DP_CONVERSION_TO_YCBCR420_ENABLE : 0;
 
        if (drm_dp_dpcd_writeb(&intel_dp->aux,
                               DP_PROTOCOL_CONVERTER_CONTROL_1, tmp) != 1)
@@ -4088,7 +4089,7 @@ static void intel_enable_dp(struct intel_atomic_state *state,
        }
 
        intel_dp_set_power(intel_dp, DP_SET_POWER_D0);
-       intel_dp_configure_protocol_converter(intel_dp);
+       intel_dp_configure_protocol_converter(intel_dp, pipe_config);
        intel_dp_start_link_train(intel_dp, pipe_config);
        intel_dp_stop_link_train(intel_dp, pipe_config);
 
@@ -4636,24 +4637,6 @@ ivb_cpu_edp_set_signal_levels(struct intel_dp *intel_dp,
        intel_de_posting_read(dev_priv, intel_dp->output_reg);
 }
 
-void intel_dp_set_signal_levels(struct intel_dp *intel_dp,
-                               const struct intel_crtc_state *crtc_state)
-{
-       struct drm_i915_private *dev_priv = dp_to_i915(intel_dp);
-       u8 train_set = intel_dp->train_set[0];
-
-       drm_dbg_kms(&dev_priv->drm, "Using vswing level %d%s\n",
-                   train_set & DP_TRAIN_VOLTAGE_SWING_MASK,
-                   train_set & DP_TRAIN_MAX_SWING_REACHED ? " (max)" : "");
-       drm_dbg_kms(&dev_priv->drm, "Using pre-emphasis level %d%s\n",
-                   (train_set & DP_TRAIN_PRE_EMPHASIS_MASK) >>
-                   DP_TRAIN_PRE_EMPHASIS_SHIFT,
-                   train_set & DP_TRAIN_MAX_PRE_EMPHASIS_REACHED ?
-                   " (max)" : "");
-
-       intel_dp->set_signal_levels(intel_dp, crtc_state);
-}
-
 void
 intel_dp_program_link_training_pattern(struct intel_dp *intel_dp,
                                       const struct intel_crtc_state *crtc_state,
@@ -5702,7 +5685,7 @@ static void intel_dp_process_phy_request(struct intel_dp *intel_dp,
 
        intel_dp_autotest_phy_ddi_disable(intel_dp, crtc_state);
 
-       intel_dp_set_signal_levels(intel_dp, crtc_state);
+       intel_dp_set_signal_levels(intel_dp, crtc_state, DP_PHY_DPRX);
 
        intel_dp_phy_pattern_update(intel_dp, crtc_state);
 
index b871a09..6620f9e 100644 (file)
@@ -51,7 +51,8 @@ int intel_dp_get_link_train_fallback_values(struct intel_dp *intel_dp,
 int intel_dp_retrain_link(struct intel_encoder *encoder,
                          struct drm_modeset_acquire_ctx *ctx);
 void intel_dp_set_power(struct intel_dp *intel_dp, u8 mode);
-void intel_dp_configure_protocol_converter(struct intel_dp *intel_dp);
+void intel_dp_configure_protocol_converter(struct intel_dp *intel_dp,
+                                          const struct intel_crtc_state *crtc_state);
 void intel_dp_sink_set_decompression_state(struct intel_dp *intel_dp,
                                           const struct intel_crtc_state *crtc_state,
                                           bool enable);
@@ -95,9 +96,6 @@ void
 intel_dp_program_link_training_pattern(struct intel_dp *intel_dp,
                                       const struct intel_crtc_state *crtc_state,
                                       u8 dp_train_pat);
-void
-intel_dp_set_signal_levels(struct intel_dp *intel_dp,
-                          const struct intel_crtc_state *crtc_state);
 void intel_dp_compute_rate(struct intel_dp *intel_dp, int port_clock,
                           u8 *link_bw, u8 *rate_select);
 bool intel_dp_source_supports_hbr2(struct intel_dp *intel_dp);
index 91d3979..d8c6d70 100644 (file)
@@ -334,6 +334,27 @@ intel_dp_set_link_train(struct intel_dp *intel_dp,
        return drm_dp_dpcd_write(&intel_dp->aux, reg, buf, len) == len;
 }
 
+void intel_dp_set_signal_levels(struct intel_dp *intel_dp,
+                               const struct intel_crtc_state *crtc_state,
+                               enum drm_dp_phy dp_phy)
+{
+       struct drm_i915_private *dev_priv = dp_to_i915(intel_dp);
+       u8 train_set = intel_dp->train_set[0];
+       char phy_name[10];
+
+       drm_dbg_kms(&dev_priv->drm, "Using vswing level %d%s, pre-emphasis level %d%s, at %s\n",
+                   train_set & DP_TRAIN_VOLTAGE_SWING_MASK,
+                   train_set & DP_TRAIN_MAX_SWING_REACHED ? " (max)" : "",
+                   (train_set & DP_TRAIN_PRE_EMPHASIS_MASK) >>
+                   DP_TRAIN_PRE_EMPHASIS_SHIFT,
+                   train_set & DP_TRAIN_MAX_PRE_EMPHASIS_REACHED ?
+                   " (max)" : "",
+                   intel_dp_phy_name(dp_phy, phy_name, sizeof(phy_name)));
+
+       if (intel_dp_phy_is_downstream_of_source(intel_dp, dp_phy))
+               intel_dp->set_signal_levels(intel_dp, crtc_state);
+}
+
 static bool
 intel_dp_reset_link_train(struct intel_dp *intel_dp,
                          const struct intel_crtc_state *crtc_state,
@@ -341,7 +362,7 @@ intel_dp_reset_link_train(struct intel_dp *intel_dp,
                          u8 dp_train_pat)
 {
        memset(intel_dp->train_set, 0, sizeof(intel_dp->train_set));
-       intel_dp_set_signal_levels(intel_dp, crtc_state);
+       intel_dp_set_signal_levels(intel_dp, crtc_state, dp_phy);
        return intel_dp_set_link_train(intel_dp, crtc_state, dp_phy, dp_train_pat);
 }
 
@@ -355,7 +376,7 @@ intel_dp_update_link_train(struct intel_dp *intel_dp,
                            DP_TRAINING_LANE0_SET_PHY_REPEATER(dp_phy);
        int ret;
 
-       intel_dp_set_signal_levels(intel_dp, crtc_state);
+       intel_dp_set_signal_levels(intel_dp, crtc_state, dp_phy);
 
        ret = drm_dp_dpcd_write(&intel_dp->aux, reg,
                                intel_dp->train_set, crtc_state->lane_count);
index 86905aa..6a1f76b 100644 (file)
@@ -17,6 +17,9 @@ void intel_dp_get_adjust_train(struct intel_dp *intel_dp,
                               const struct intel_crtc_state *crtc_state,
                               enum drm_dp_phy dp_phy,
                               const u8 link_status[DP_LINK_STATUS_SIZE]);
+void intel_dp_set_signal_levels(struct intel_dp *intel_dp,
+                               const struct intel_crtc_state *crtc_state,
+                               enum drm_dp_phy dp_phy);
 void intel_dp_start_link_train(struct intel_dp *intel_dp,
                               const struct intel_crtc_state *crtc_state);
 void intel_dp_stop_link_train(struct intel_dp *intel_dp,
index 27f04ae..3286b23 100644 (file)
@@ -69,7 +69,9 @@ static int intel_dp_mst_compute_link_config(struct intel_encoder *encoder,
 
                slots = drm_dp_atomic_find_vcpi_slots(state, &intel_dp->mst_mgr,
                                                      connector->port,
-                                                     crtc_state->pbn, 0);
+                                                     crtc_state->pbn,
+                                                     drm_dp_get_vc_payload_bw(crtc_state->port_clock,
+                                                                              crtc_state->lane_count));
                if (slots == -EDEADLK)
                        return slots;
                if (slots >= 0)
index b2a4bbc..b9d8825 100644 (file)
@@ -2210,6 +2210,7 @@ void intel_hdcp_update_pipe(struct intel_atomic_state *state,
        if (content_protection_type_changed) {
                mutex_lock(&hdcp->mutex);
                hdcp->value = DRM_MODE_CONTENT_PROTECTION_DESIRED;
+               drm_connector_get(&connector->base);
                schedule_work(&hdcp->prop_work);
                mutex_unlock(&hdcp->mutex);
        }
@@ -2221,6 +2222,14 @@ void intel_hdcp_update_pipe(struct intel_atomic_state *state,
                desired_and_not_enabled =
                        hdcp->value != DRM_MODE_CONTENT_PROTECTION_ENABLED;
                mutex_unlock(&hdcp->mutex);
+               /*
+                * If HDCP already ENABLED and CP property is DESIRED, schedule
+                * prop_work to update correct CP property to user space.
+                */
+               if (!desired_and_not_enabled && !content_protection_type_changed) {
+                       drm_connector_get(&connector->base);
+                       schedule_work(&hdcp->prop_work);
+               }
        }
 
        if (desired_and_not_enabled || content_protection_type_changed)
index 52b4f61..0095c8c 100644 (file)
@@ -359,7 +359,7 @@ static void intel_overlay_release_old_vma(struct intel_overlay *overlay)
        intel_frontbuffer_flip_complete(overlay->i915,
                                        INTEL_FRONTBUFFER_OVERLAY(overlay->crtc->pipe));
 
-       i915_gem_object_unpin_from_display_plane(vma);
+       i915_vma_unpin(vma);
        i915_vma_put(vma);
 }
 
@@ -860,7 +860,7 @@ static int intel_overlay_do_put_image(struct intel_overlay *overlay,
        return 0;
 
 out_unpin:
-       i915_gem_object_unpin_from_display_plane(vma);
+       i915_vma_unpin(vma);
 out_pin_section:
        atomic_dec(&dev_priv->gpu_error.pending_fb_pin);
 
index 019a2d6..3da2544 100644 (file)
@@ -618,13 +618,19 @@ skl_program_scaler(struct intel_plane *plane,
 
 /* Preoffset values for YUV to RGB Conversion */
 #define PREOFF_YUV_TO_RGB_HI           0x1800
-#define PREOFF_YUV_TO_RGB_ME           0x1F00
+#define PREOFF_YUV_TO_RGB_ME           0x0000
 #define PREOFF_YUV_TO_RGB_LO           0x1800
 
 #define  ROFF(x)          (((x) & 0xffff) << 16)
 #define  GOFF(x)          (((x) & 0xffff) << 0)
 #define  BOFF(x)          (((x) & 0xffff) << 16)
 
+/*
+ * Programs the input color space conversion stage for ICL HDR planes.
+ * Note that it is assumed that this stage always happens after YUV
+ * range correction. Thus, the input to this stage is assumed to be
+ * in full-range YCbCr.
+ */
 static void
 icl_program_input_csc(struct intel_plane *plane,
                      const struct intel_crtc_state *crtc_state,
@@ -672,52 +678,7 @@ icl_program_input_csc(struct intel_plane *plane,
                        0x0, 0x7800, 0x7F10,
                },
        };
-
-       /* Matrix for Limited Range to Full Range Conversion */
-       static const u16 input_csc_matrix_lr[][9] = {
-               /*
-                * BT.601 Limted range YCbCr -> full range RGB
-                * The matrix required is :
-                * [1.164384, 0.000, 1.596027,
-                *  1.164384, -0.39175, -0.812813,
-                *  1.164384, 2.017232, 0.0000]
-                */
-               [DRM_COLOR_YCBCR_BT601] = {
-                       0x7CC8, 0x7950, 0x0,
-                       0x8D00, 0x7950, 0x9C88,
-                       0x0, 0x7950, 0x6810,
-               },
-               /*
-                * BT.709 Limited range YCbCr -> full range RGB
-                * The matrix required is :
-                * [1.164384, 0.000, 1.792741,
-                *  1.164384, -0.213249, -0.532909,
-                *  1.164384, 2.112402, 0.0000]
-                */
-               [DRM_COLOR_YCBCR_BT709] = {
-                       0x7E58, 0x7950, 0x0,
-                       0x8888, 0x7950, 0xADA8,
-                       0x0, 0x7950,  0x6870,
-               },
-               /*
-                * BT.2020 Limited range YCbCr -> full range RGB
-                * The matrix required is :
-                * [1.164, 0.000, 1.678,
-                *  1.164, -0.1873, -0.6504,
-                *  1.164, 2.1417, 0.0000]
-                */
-               [DRM_COLOR_YCBCR_BT2020] = {
-                       0x7D70, 0x7950, 0x0,
-                       0x8A68, 0x7950, 0xAC00,
-                       0x0, 0x7950, 0x6890,
-               },
-       };
-       const u16 *csc;
-
-       if (plane_state->hw.color_range == DRM_COLOR_YCBCR_FULL_RANGE)
-               csc = input_csc_matrix[plane_state->hw.color_encoding];
-       else
-               csc = input_csc_matrix_lr[plane_state->hw.color_encoding];
+       const u16 *csc = input_csc_matrix[plane_state->hw.color_encoding];
 
        intel_de_write_fw(dev_priv, PLANE_INPUT_CSC_COEFF(pipe, plane_id, 0),
                          ROFF(csc[0]) | GOFF(csc[1]));
@@ -734,14 +695,8 @@ icl_program_input_csc(struct intel_plane *plane,
 
        intel_de_write_fw(dev_priv, PLANE_INPUT_CSC_PREOFF(pipe, plane_id, 0),
                          PREOFF_YUV_TO_RGB_HI);
-       if (plane_state->hw.color_range == DRM_COLOR_YCBCR_FULL_RANGE)
-               intel_de_write_fw(dev_priv,
-                                 PLANE_INPUT_CSC_PREOFF(pipe, plane_id, 1),
-                                 0);
-       else
-               intel_de_write_fw(dev_priv,
-                                 PLANE_INPUT_CSC_PREOFF(pipe, plane_id, 1),
-                                 PREOFF_YUV_TO_RGB_ME);
+       intel_de_write_fw(dev_priv, PLANE_INPUT_CSC_PREOFF(pipe, plane_id, 1),
+                         PREOFF_YUV_TO_RGB_ME);
        intel_de_write_fw(dev_priv, PLANE_INPUT_CSC_PREOFF(pipe, plane_id, 2),
                          PREOFF_YUV_TO_RGB_LO);
        intel_de_write_fw(dev_priv,
index fcce690..3d435bf 100644 (file)
@@ -387,48 +387,6 @@ err:
        return vma;
 }
 
-static void i915_gem_object_bump_inactive_ggtt(struct drm_i915_gem_object *obj)
-{
-       struct drm_i915_private *i915 = to_i915(obj->base.dev);
-       struct i915_vma *vma;
-
-       if (list_empty(&obj->vma.list))
-               return;
-
-       mutex_lock(&i915->ggtt.vm.mutex);
-       spin_lock(&obj->vma.lock);
-       for_each_ggtt_vma(vma, obj) {
-               if (!drm_mm_node_allocated(&vma->node))
-                       continue;
-
-               GEM_BUG_ON(vma->vm != &i915->ggtt.vm);
-               list_move_tail(&vma->vm_link, &vma->vm->bound_list);
-       }
-       spin_unlock(&obj->vma.lock);
-       mutex_unlock(&i915->ggtt.vm.mutex);
-
-       if (i915_gem_object_is_shrinkable(obj)) {
-               unsigned long flags;
-
-               spin_lock_irqsave(&i915->mm.obj_lock, flags);
-
-               if (obj->mm.madv == I915_MADV_WILLNEED &&
-                   !atomic_read(&obj->mm.shrink_pin))
-                       list_move_tail(&obj->mm.link, &i915->mm.shrink_list);
-
-               spin_unlock_irqrestore(&i915->mm.obj_lock, flags);
-       }
-}
-
-void
-i915_gem_object_unpin_from_display_plane(struct i915_vma *vma)
-{
-       /* Bump the LRU to try and avoid premature eviction whilst flipping  */
-       i915_gem_object_bump_inactive_ggtt(vma->obj);
-
-       i915_vma_unpin(vma);
-}
-
 /**
  * Moves a single object to the CPU read, and possibly write domain.
  * @obj: object to act on
@@ -569,9 +527,6 @@ i915_gem_set_domain_ioctl(struct drm_device *dev, void *data,
        else
                err = i915_gem_object_set_to_cpu_domain(obj, write_domain);
 
-       /* And bump the LRU for this access */
-       i915_gem_object_bump_inactive_ggtt(obj);
-
        i915_gem_object_unlock(obj);
 
        if (write_domain)
index be14486..4556afe 100644 (file)
@@ -486,7 +486,6 @@ i915_gem_object_pin_to_display_plane(struct drm_i915_gem_object *obj,
                                     u32 alignment,
                                     const struct i915_ggtt_view *view,
                                     unsigned int flags);
-void i915_gem_object_unpin_from_display_plane(struct i915_vma *vma);
 
 void i915_gem_object_make_unshrinkable(struct drm_i915_gem_object *obj);
 void i915_gem_object_make_shrinkable(struct drm_i915_gem_object *obj);
index 9446537..e961ad6 100644 (file)
@@ -390,6 +390,16 @@ static void emit_batch(struct i915_vma * const vma,
                                                     &cb_kernel_ivb,
                                                     desc_count);
 
+       /* Reset inherited context registers */
+       gen7_emit_pipeline_invalidate(&cmds);
+       batch_add(&cmds, MI_LOAD_REGISTER_IMM(2));
+       batch_add(&cmds, i915_mmio_reg_offset(CACHE_MODE_0_GEN7));
+       batch_add(&cmds, 0xffff0000);
+       batch_add(&cmds, i915_mmio_reg_offset(CACHE_MODE_1));
+       batch_add(&cmds, 0xffff0000 | PIXEL_SUBSPAN_COLLECT_OPT_DISABLE);
+       gen7_emit_pipeline_flush(&cmds);
+
+       /* Switch to the media pipeline and our base address */
        gen7_emit_pipeline_invalidate(&cmds);
        batch_add(&cmds, PIPELINE_SELECT | PIPELINE_SELECT_MEDIA);
        batch_add(&cmds, MI_NOOP);
@@ -399,9 +409,11 @@ static void emit_batch(struct i915_vma * const vma,
        gen7_emit_state_base_address(&cmds, descriptors);
        gen7_emit_pipeline_invalidate(&cmds);
 
+       /* Set the clear-residual kernel state */
        gen7_emit_vfe_state(&cmds, bv, urb_size - 1, 0, 0);
        gen7_emit_interface_descriptor_load(&cmds, descriptors, desc_count);
 
+       /* Execute the kernel on all HW threads */
        for (i = 0; i < num_primitives(bv); i++)
                gen7_emit_media_object(&cmds, i);
 
index a24cc1f..1d17575 100644 (file)
@@ -134,11 +134,6 @@ static bool remove_signaling_context(struct intel_breadcrumbs *b,
        return true;
 }
 
-static inline bool __request_completed(const struct i915_request *rq)
-{
-       return i915_seqno_passed(__hwsp_seqno(rq), rq->fence.seqno);
-}
-
 __maybe_unused static bool
 check_signal_order(struct intel_context *ce, struct i915_request *rq)
 {
@@ -192,18 +187,6 @@ static void add_retire(struct intel_breadcrumbs *b, struct intel_timeline *tl)
                intel_engine_add_retire(b->irq_engine, tl);
 }
 
-static bool __signal_request(struct i915_request *rq)
-{
-       GEM_BUG_ON(test_bit(I915_FENCE_FLAG_SIGNAL, &rq->fence.flags));
-
-       if (!__dma_fence_signal(&rq->fence)) {
-               i915_request_put(rq);
-               return false;
-       }
-
-       return true;
-}
-
 static struct llist_node *
 slist_add(struct llist_node *node, struct llist_node *head)
 {
@@ -257,7 +240,7 @@ static void signal_irq_work(struct irq_work *work)
                list_for_each_entry_rcu(rq, &ce->signals, signal_link) {
                        bool release;
 
-                       if (!__request_completed(rq))
+                       if (!__i915_request_is_complete(rq))
                                break;
 
                        if (!test_and_clear_bit(I915_FENCE_FLAG_SIGNAL,
@@ -274,9 +257,11 @@ static void signal_irq_work(struct irq_work *work)
                        release = remove_signaling_context(b, ce);
                        spin_unlock(&ce->signal_lock);
 
-                       if (__signal_request(rq))
+                       if (__dma_fence_signal(&rq->fence))
                                /* We own signal_node now, xfer to local list */
                                signal = slist_add(&rq->signal_node, signal);
+                       else
+                               i915_request_put(rq);
 
                        if (release) {
                                add_retire(b, ce->timeline);
@@ -363,6 +348,17 @@ void intel_breadcrumbs_free(struct intel_breadcrumbs *b)
        kfree(b);
 }
 
+static void irq_signal_request(struct i915_request *rq,
+                              struct intel_breadcrumbs *b)
+{
+       if (!__dma_fence_signal(&rq->fence))
+               return;
+
+       i915_request_get(rq);
+       if (llist_add(&rq->signal_node, &b->signaled_requests))
+               irq_work_queue(&b->irq_work);
+}
+
 static void insert_breadcrumb(struct i915_request *rq)
 {
        struct intel_breadcrumbs *b = READ_ONCE(rq->engine)->breadcrumbs;
@@ -372,17 +368,13 @@ static void insert_breadcrumb(struct i915_request *rq)
        if (test_bit(I915_FENCE_FLAG_SIGNAL, &rq->fence.flags))
                return;
 
-       i915_request_get(rq);
-
        /*
         * If the request is already completed, we can transfer it
         * straight onto a signaled list, and queue the irq worker for
         * its signal completion.
         */
-       if (__request_completed(rq)) {
-               if (__signal_request(rq) &&
-                   llist_add(&rq->signal_node, &b->signaled_requests))
-                       irq_work_queue(&b->irq_work);
+       if (__i915_request_is_complete(rq)) {
+               irq_signal_request(rq, b);
                return;
        }
 
@@ -413,6 +405,8 @@ static void insert_breadcrumb(struct i915_request *rq)
                                break;
                }
        }
+
+       i915_request_get(rq);
        list_add_rcu(&rq->signal_link, pos);
        GEM_BUG_ON(!check_signal_order(ce, rq));
        GEM_BUG_ON(test_bit(DMA_FENCE_FLAG_SIGNALED_BIT, &rq->fence.flags));
@@ -453,19 +447,25 @@ bool i915_request_enable_breadcrumb(struct i915_request *rq)
 
 void i915_request_cancel_breadcrumb(struct i915_request *rq)
 {
+       struct intel_breadcrumbs *b = READ_ONCE(rq->engine)->breadcrumbs;
        struct intel_context *ce = rq->context;
        bool release;
 
-       if (!test_and_clear_bit(I915_FENCE_FLAG_SIGNAL, &rq->fence.flags))
+       spin_lock(&ce->signal_lock);
+       if (!test_and_clear_bit(I915_FENCE_FLAG_SIGNAL, &rq->fence.flags)) {
+               spin_unlock(&ce->signal_lock);
                return;
+       }
 
-       spin_lock(&ce->signal_lock);
        list_del_rcu(&rq->signal_link);
-       release = remove_signaling_context(rq->engine->breadcrumbs, ce);
+       release = remove_signaling_context(b, ce);
        spin_unlock(&ce->signal_lock);
        if (release)
                intel_context_put(ce);
 
+       if (__i915_request_is_complete(rq))
+               irq_signal_request(rq, b);
+
        i915_request_put(rq);
 }
 
index cf94525..db8c66d 100644 (file)
@@ -526,16 +526,39 @@ static int init_ggtt(struct i915_ggtt *ggtt)
 
        mutex_init(&ggtt->error_mutex);
        if (ggtt->mappable_end) {
-               /* Reserve a mappable slot for our lockless error capture */
-               ret = drm_mm_insert_node_in_range(&ggtt->vm.mm,
-                                                 &ggtt->error_capture,
-                                                 PAGE_SIZE, 0,
-                                                 I915_COLOR_UNEVICTABLE,
-                                                 0, ggtt->mappable_end,
-                                                 DRM_MM_INSERT_LOW);
-               if (ret)
-                       return ret;
+               /*
+                * Reserve a mappable slot for our lockless error capture.
+                *
+                * We strongly prefer taking address 0x0 in order to protect
+                * other critical buffers against accidental overwrites,
+                * as writing to address 0 is a very common mistake.
+                *
+                * Since 0 may already be in use by the system (e.g. the BIOS
+                * framebuffer), we let the reservation fail quietly and hope
+                * 0 remains reserved always.
+                *
+                * If we fail to reserve 0, and then fail to find any space
+                * for an error-capture, remain silent. We can afford not
+                * to reserve an error_capture node as we have fallback
+                * paths, and we trust that 0 will remain reserved. However,
+                * the only likely reason for failure to insert is a driver
+                * bug, which we expect to cause other failures...
+                */
+               ggtt->error_capture.size = I915_GTT_PAGE_SIZE;
+               ggtt->error_capture.color = I915_COLOR_UNEVICTABLE;
+               if (drm_mm_reserve_node(&ggtt->vm.mm, &ggtt->error_capture))
+                       drm_mm_insert_node_in_range(&ggtt->vm.mm,
+                                                   &ggtt->error_capture,
+                                                   ggtt->error_capture.size, 0,
+                                                   ggtt->error_capture.color,
+                                                   0, ggtt->mappable_end,
+                                                   DRM_MM_INSERT_LOW);
        }
+       if (drm_mm_node_allocated(&ggtt->error_capture))
+               drm_dbg(&ggtt->vm.i915->drm,
+                       "Reserved GGTT:[%llx, %llx] for use by error capture\n",
+                       ggtt->error_capture.start,
+                       ggtt->error_capture.start + ggtt->error_capture.size);
 
        /*
         * The upper portion of the GuC address space has a sizeable hole
@@ -548,9 +571,9 @@ static int init_ggtt(struct i915_ggtt *ggtt)
 
        /* Clear any non-preallocated blocks */
        drm_mm_for_each_hole(entry, &ggtt->vm.mm, hole_start, hole_end) {
-               drm_dbg_kms(&ggtt->vm.i915->drm,
-                           "clearing unused GTT space: [%lx, %lx]\n",
-                           hole_start, hole_end);
+               drm_dbg(&ggtt->vm.i915->drm,
+                       "clearing unused GTT space: [%lx, %lx]\n",
+                       hole_start, hole_end);
                ggtt->vm.clear_range(&ggtt->vm, hole_start,
                                     hole_end - hole_start);
        }
index 7614a3d..26c7d0a 100644 (file)
@@ -3988,6 +3988,9 @@ err:
 static void lrc_destroy_wa_ctx(struct intel_engine_cs *engine)
 {
        i915_vma_unpin_and_release(&engine->wa_ctx.vma, 0);
+
+       /* Called on error unwind, clear all flags to prevent further use */
+       memset(&engine->wa_ctx, 0, sizeof(engine->wa_ctx));
 }
 
 typedef u32 *(*wa_bb_func_t)(struct intel_engine_cs *engine, u32 *batch);
index 7ea94d2..8015964 100644 (file)
@@ -126,6 +126,10 @@ static void __rcu_cacheline_free(struct rcu_head *rcu)
        struct intel_timeline_cacheline *cl =
                container_of(rcu, typeof(*cl), rcu);
 
+       /* Must wait until after all *rq->hwsp are complete before removing */
+       i915_gem_object_unpin_map(cl->hwsp->vma->obj);
+       __idle_hwsp_free(cl->hwsp, ptr_unmask_bits(cl->vaddr, CACHELINE_BITS));
+
        i915_active_fini(&cl->active);
        kfree(cl);
 }
@@ -133,11 +137,6 @@ static void __rcu_cacheline_free(struct rcu_head *rcu)
 static void __idle_cacheline_free(struct intel_timeline_cacheline *cl)
 {
        GEM_BUG_ON(!i915_active_is_idle(&cl->active));
-
-       i915_gem_object_unpin_map(cl->hwsp->vma->obj);
-       i915_vma_put(cl->hwsp->vma);
-       __idle_hwsp_free(cl->hwsp, ptr_unmask_bits(cl->vaddr, CACHELINE_BITS));
-
        call_rcu(&cl->rcu, __rcu_cacheline_free);
 }
 
@@ -179,7 +178,6 @@ cacheline_alloc(struct intel_timeline_hwsp *hwsp, unsigned int cacheline)
                return ERR_CAST(vaddr);
        }
 
-       i915_vma_get(hwsp->vma);
        cl->hwsp = hwsp;
        cl->vaddr = page_pack_bits(vaddr, cacheline);
 
index 10a865f..9ed19b8 100644 (file)
@@ -631,24 +631,26 @@ static int flush_lazy_signals(struct i915_active *ref)
 
 int __i915_active_wait(struct i915_active *ref, int state)
 {
-       int err;
-
        might_sleep();
 
-       if (!i915_active_acquire_if_busy(ref))
-               return 0;
-
        /* Any fence added after the wait begins will not be auto-signaled */
-       err = flush_lazy_signals(ref);
-       i915_active_release(ref);
-       if (err)
-               return err;
+       if (i915_active_acquire_if_busy(ref)) {
+               int err;
 
-       if (!i915_active_is_idle(ref) &&
-           ___wait_var_event(ref, i915_active_is_idle(ref),
-                             state, 0, 0, schedule()))
-               return -EINTR;
+               err = flush_lazy_signals(ref);
+               i915_active_release(ref);
+               if (err)
+                       return err;
 
+               if (___wait_var_event(ref, i915_active_is_idle(ref),
+                                     state, 0, 0, schedule()))
+                       return -EINTR;
+       }
+
+       /*
+        * After the wait is complete, the caller may free the active.
+        * We have to flush any concurrent retirement before returning.
+        */
        flush_work(&ref->work);
        return 0;
 }
index 632c713..c6964f8 100644 (file)
@@ -1346,7 +1346,7 @@ intel_subplatform(const struct intel_runtime_info *info, enum intel_platform p)
 {
        const unsigned int pi = __platform_mask_index(info, p);
 
-       return info->platform_mask[pi] & INTEL_SUBPLATFORM_BITS;
+       return info->platform_mask[pi] & ((1 << INTEL_SUBPLATFORM_BITS) - 1);
 }
 
 static __always_inline bool
index d76685c..9856479 100644 (file)
@@ -184,13 +184,24 @@ static u64 get_rc6(struct intel_gt *gt)
        return val;
 }
 
-static void park_rc6(struct drm_i915_private *i915)
+static void init_rc6(struct i915_pmu *pmu)
 {
-       struct i915_pmu *pmu = &i915->pmu;
+       struct drm_i915_private *i915 = container_of(pmu, typeof(*i915), pmu);
+       intel_wakeref_t wakeref;
 
-       if (pmu->enable & config_enabled_mask(I915_PMU_RC6_RESIDENCY))
+       with_intel_runtime_pm(i915->gt.uncore->rpm, wakeref) {
                pmu->sample[__I915_SAMPLE_RC6].cur = __get_rc6(&i915->gt);
+               pmu->sample[__I915_SAMPLE_RC6_LAST_REPORTED].cur =
+                                       pmu->sample[__I915_SAMPLE_RC6].cur;
+               pmu->sleep_last = ktime_get();
+       }
+}
 
+static void park_rc6(struct drm_i915_private *i915)
+{
+       struct i915_pmu *pmu = &i915->pmu;
+
+       pmu->sample[__I915_SAMPLE_RC6].cur = __get_rc6(&i915->gt);
        pmu->sleep_last = ktime_get();
 }
 
@@ -201,6 +212,7 @@ static u64 get_rc6(struct intel_gt *gt)
        return __get_rc6(gt);
 }
 
+static void init_rc6(struct i915_pmu *pmu) { }
 static void park_rc6(struct drm_i915_private *i915) {}
 
 #endif
@@ -612,10 +624,8 @@ static void i915_pmu_enable(struct perf_event *event)
                container_of(event->pmu, typeof(*i915), pmu.base);
        unsigned int bit = event_enabled_bit(event);
        struct i915_pmu *pmu = &i915->pmu;
-       intel_wakeref_t wakeref;
        unsigned long flags;
 
-       wakeref = intel_runtime_pm_get(&i915->runtime_pm);
        spin_lock_irqsave(&pmu->lock, flags);
 
        /*
@@ -626,13 +636,6 @@ static void i915_pmu_enable(struct perf_event *event)
        GEM_BUG_ON(bit >= ARRAY_SIZE(pmu->enable_count));
        GEM_BUG_ON(pmu->enable_count[bit] == ~0);
 
-       if (pmu->enable_count[bit] == 0 &&
-           config_enabled_mask(I915_PMU_RC6_RESIDENCY) & BIT_ULL(bit)) {
-               pmu->sample[__I915_SAMPLE_RC6_LAST_REPORTED].cur = 0;
-               pmu->sample[__I915_SAMPLE_RC6].cur = __get_rc6(&i915->gt);
-               pmu->sleep_last = ktime_get();
-       }
-
        pmu->enable |= BIT_ULL(bit);
        pmu->enable_count[bit]++;
 
@@ -673,8 +676,6 @@ static void i915_pmu_enable(struct perf_event *event)
         * an existing non-zero value.
         */
        local64_set(&event->hw.prev_count, __i915_pmu_event_read(event));
-
-       intel_runtime_pm_put(&i915->runtime_pm, wakeref);
 }
 
 static void i915_pmu_disable(struct perf_event *event)
@@ -1130,6 +1131,7 @@ void i915_pmu_register(struct drm_i915_private *i915)
        hrtimer_init(&pmu->timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
        pmu->timer.function = i915_sample;
        pmu->cpuhp.cpu = -1;
+       init_rc6(pmu);
 
        if (!is_igp(i915)) {
                pmu->name = kasprintf(GFP_KERNEL,
index 620b6fa..92adfee 100644 (file)
@@ -434,7 +434,7 @@ static inline u32 hwsp_seqno(const struct i915_request *rq)
 
 static inline bool __i915_request_has_started(const struct i915_request *rq)
 {
-       return i915_seqno_passed(hwsp_seqno(rq), rq->fence.seqno - 1);
+       return i915_seqno_passed(__hwsp_seqno(rq), rq->fence.seqno - 1);
 }
 
 /**
@@ -465,11 +465,19 @@ static inline bool __i915_request_has_started(const struct i915_request *rq)
  */
 static inline bool i915_request_started(const struct i915_request *rq)
 {
+       bool result;
+
        if (i915_request_signaled(rq))
                return true;
 
-       /* Remember: started but may have since been preempted! */
-       return __i915_request_has_started(rq);
+       result = true;
+       rcu_read_lock(); /* the HWSP may be freed at runtime */
+       if (likely(!i915_request_signaled(rq)))
+               /* Remember: started but may have since been preempted! */
+               result = __i915_request_has_started(rq);
+       rcu_read_unlock();
+
+       return result;
 }
 
 /**
@@ -482,10 +490,16 @@ static inline bool i915_request_started(const struct i915_request *rq)
  */
 static inline bool i915_request_is_running(const struct i915_request *rq)
 {
+       bool result;
+
        if (!i915_request_is_active(rq))
                return false;
 
-       return __i915_request_has_started(rq);
+       rcu_read_lock();
+       result = __i915_request_has_started(rq) && i915_request_is_active(rq);
+       rcu_read_unlock();
+
+       return result;
 }
 
 /**
@@ -509,12 +523,25 @@ static inline bool i915_request_is_ready(const struct i915_request *rq)
        return !list_empty(&rq->sched.link);
 }
 
+static inline bool __i915_request_is_complete(const struct i915_request *rq)
+{
+       return i915_seqno_passed(__hwsp_seqno(rq), rq->fence.seqno);
+}
+
 static inline bool i915_request_completed(const struct i915_request *rq)
 {
+       bool result;
+
        if (i915_request_signaled(rq))
                return true;
 
-       return i915_seqno_passed(hwsp_seqno(rq), rq->fence.seqno);
+       result = true;
+       rcu_read_lock(); /* the HWSP may be freed at runtime */
+       if (likely(!i915_request_signaled(rq)))
+               result = __i915_request_is_complete(rq);
+       rcu_read_unlock();
+
+       return result;
 }
 
 static inline void i915_request_mark_complete(struct i915_request *rq)
index c53a222..713770f 100644 (file)
@@ -1880,7 +1880,7 @@ static int igt_cs_tlb(void *arg)
        vma = i915_vma_instance(out, vm, NULL);
        if (IS_ERR(vma)) {
                err = PTR_ERR(vma);
-               goto out_put_batch;
+               goto out_put_out;
        }
 
        err = i915_vma_pin(vma, 0, 0,
index 302d4e6..788db04 100644 (file)
@@ -88,7 +88,11 @@ base507c_image_set(struct nv50_wndw *wndw, struct nv50_wndw_atom *asyw)
                          NVVAL(NV507C, SET_CONVERSION, OFS, 0x64));
        } else {
                PUSH_MTHD(push, NV507C, SET_PROCESSING,
-                         NVDEF(NV507C, SET_PROCESSING, USE_GAIN_OFS, DISABLE));
+                         NVDEF(NV507C, SET_PROCESSING, USE_GAIN_OFS, DISABLE),
+
+                                       SET_CONVERSION,
+                         NVVAL(NV507C, SET_CONVERSION, GAIN, 0) |
+                         NVVAL(NV507C, SET_CONVERSION, OFS, 0));
        }
 
        PUSH_MTHD(push, NV507C, SURFACE_SET_OFFSET(0, 0), asyw->image.offset[0] >> 8);
index 18d3409..093d4ba 100644 (file)
@@ -49,7 +49,11 @@ base827c_image_set(struct nv50_wndw *wndw, struct nv50_wndw_atom *asyw)
                          NVVAL(NV827C, SET_CONVERSION, OFS, 0x64));
        } else {
                PUSH_MTHD(push, NV827C, SET_PROCESSING,
-                         NVDEF(NV827C, SET_PROCESSING, USE_GAIN_OFS, DISABLE));
+                         NVDEF(NV827C, SET_PROCESSING, USE_GAIN_OFS, DISABLE),
+
+                                       SET_CONVERSION,
+                         NVVAL(NV827C, SET_CONVERSION, GAIN, 0) |
+                         NVVAL(NV827C, SET_CONVERSION, OFS, 0));
        }
 
        PUSH_MTHD(push, NV827C, SURFACE_SET_OFFSET(0, 0), asyw->image.offset[0] >> 8,
index c636703..5f4f09a 100644 (file)
@@ -2663,6 +2663,14 @@ nv50_display_create(struct drm_device *dev)
        else
                nouveau_display(dev)->format_modifiers = disp50xx_modifiers;
 
+       if (disp->disp->object.oclass >= GK104_DISP) {
+               dev->mode_config.cursor_width = 256;
+               dev->mode_config.cursor_height = 256;
+       } else {
+               dev->mode_config.cursor_width = 64;
+               dev->mode_config.cursor_height = 64;
+       }
+
        /* create crtc objects to represent the hw heads */
        if (disp->disp->object.oclass >= GV100_DISP)
                crtcs = nvif_rd32(&device->object, 0x610060) & 0xff;
index a5d8274..ea9f866 100644 (file)
@@ -22,6 +22,7 @@
 #include "head.h"
 #include "core.h"
 
+#include "nvif/push.h"
 #include <nvif/push507c.h>
 
 #include <nvhw/class/cl917d.h>
@@ -73,6 +74,31 @@ head917d_base(struct nv50_head *head, struct nv50_head_atom *asyh)
        return 0;
 }
 
+static int
+head917d_curs_set(struct nv50_head *head, struct nv50_head_atom *asyh)
+{
+       struct nvif_push *push = nv50_disp(head->base.base.dev)->core->chan.push;
+       const int i = head->base.index;
+       int ret;
+
+       ret = PUSH_WAIT(push, 5);
+       if (ret)
+               return ret;
+
+       PUSH_MTHD(push, NV917D, HEAD_SET_CONTROL_CURSOR(i),
+                 NVDEF(NV917D, HEAD_SET_CONTROL_CURSOR, ENABLE, ENABLE) |
+                 NVVAL(NV917D, HEAD_SET_CONTROL_CURSOR, FORMAT, asyh->curs.format) |
+                 NVVAL(NV917D, HEAD_SET_CONTROL_CURSOR, SIZE, asyh->curs.layout) |
+                 NVVAL(NV917D, HEAD_SET_CONTROL_CURSOR, HOT_SPOT_X, 0) |
+                 NVVAL(NV917D, HEAD_SET_CONTROL_CURSOR, HOT_SPOT_Y, 0) |
+                 NVDEF(NV917D, HEAD_SET_CONTROL_CURSOR, COMPOSITION, ALPHA_BLEND),
+
+                               HEAD_SET_OFFSET_CURSOR(i), asyh->curs.offset >> 8);
+
+       PUSH_MTHD(push, NV917D, HEAD_SET_CONTEXT_DMA_CURSOR(i), asyh->curs.handle);
+       return 0;
+}
+
 int
 head917d_curs_layout(struct nv50_head *head, struct nv50_wndw_atom *asyw,
                     struct nv50_head_atom *asyh)
@@ -101,7 +127,7 @@ head917d = {
        .core_clr = head907d_core_clr,
        .curs_layout = head917d_curs_layout,
        .curs_format = head507d_curs_format,
-       .curs_set = head907d_curs_set,
+       .curs_set = head917d_curs_set,
        .curs_clr = head907d_curs_clr,
        .base = head917d_base,
        .ovly = head907d_ovly,
index ce45124..271de3a 100644 (file)
@@ -702,6 +702,11 @@ nv50_wndw_init(struct nv50_wndw *wndw)
        nvif_notify_get(&wndw->notify);
 }
 
+static const u64 nv50_cursor_format_modifiers[] = {
+       DRM_FORMAT_MOD_LINEAR,
+       DRM_FORMAT_MOD_INVALID,
+};
+
 int
 nv50_wndw_new_(const struct nv50_wndw_func *func, struct drm_device *dev,
               enum drm_plane_type type, const char *name, int index,
@@ -713,6 +718,7 @@ nv50_wndw_new_(const struct nv50_wndw_func *func, struct drm_device *dev,
        struct nvif_mmu *mmu = &drm->client.mmu;
        struct nv50_disp *disp = nv50_disp(dev);
        struct nv50_wndw *wndw;
+       const u64 *format_modifiers;
        int nformat;
        int ret;
 
@@ -728,10 +734,13 @@ nv50_wndw_new_(const struct nv50_wndw_func *func, struct drm_device *dev,
 
        for (nformat = 0; format[nformat]; nformat++);
 
-       ret = drm_universal_plane_init(dev, &wndw->plane, heads, &nv50_wndw,
-                                      format, nformat,
-                                      nouveau_display(dev)->format_modifiers,
-                                      type, "%s-%d", name, index);
+       if (type == DRM_PLANE_TYPE_CURSOR)
+               format_modifiers = nv50_cursor_format_modifiers;
+       else
+               format_modifiers = nouveau_display(dev)->format_modifiers;
+
+       ret = drm_universal_plane_init(dev, &wndw->plane, heads, &nv50_wndw, format, nformat,
+                                      format_modifiers, type, "%s-%d", name, index);
        if (ret) {
                kfree(*pwndw);
                *pwndw = NULL;
index 2a2612d..fb22372 100644 (file)
 #define NV917D_HEAD_SET_CONTROL_CURSOR_COMPOSITION_ALPHA_BLEND                  (0x00000000)
 #define NV917D_HEAD_SET_CONTROL_CURSOR_COMPOSITION_PREMULT_ALPHA_BLEND          (0x00000001)
 #define NV917D_HEAD_SET_CONTROL_CURSOR_COMPOSITION_XOR                          (0x00000002)
+#define NV917D_HEAD_SET_OFFSET_CURSOR(a)                                        (0x00000484 + (a)*0x00000300)
+#define NV917D_HEAD_SET_OFFSET_CURSOR_ORIGIN                                    31:0
+#define NV917D_HEAD_SET_CONTEXT_DMA_CURSOR(a)                                   (0x0000048C + (a)*0x00000300)
+#define NV917D_HEAD_SET_CONTEXT_DMA_CURSOR_HANDLE                               31:0
 #define NV917D_HEAD_SET_DITHER_CONTROL(a)                                       (0x000004A0 + (a)*0x00000300)
 #define NV917D_HEAD_SET_DITHER_CONTROL_ENABLE                                   0:0
 #define NV917D_HEAD_SET_DITHER_CONTROL_ENABLE_DISABLE                           (0x00000000)
index 168d769..6d3a8a3 100644 (file)
@@ -123,131 +123,131 @@ PUSH_KICK(struct nvif_push *push)
 } while(0)
 #endif
 
-#define PUSH_1(X,f,ds,n,c,o,p,s,mA,dA) do {                            \
-       PUSH_##o##_HDR((p), s, mA, (c)+(n));                           \
-       PUSH_##f(X, (p), X##mA, 1, o, (dA), ds, "");                   \
+#define PUSH_1(X,f,ds,n,o,p,s,mA,dA) do {                             \
+       PUSH_##o##_HDR((p), s, mA, (ds)+(n));                         \
+       PUSH_##f(X, (p), X##mA, 1, o, (dA), ds, "");                  \
 } while(0)
-#define PUSH_2(X,f,ds,n,c,o,p,s,mB,dB,mA,dA,a...) do {                 \
-       PUSH_ASSERT((mB) - (mA) == (1?PUSH_##o##_INC), "mthd1");       \
-       PUSH_1(X, DATA_, 1, ds, (c)+(n), o, (p), s, X##mA, (dA), ##a); \
-       PUSH_##f(X, (p), X##mB, 0, o, (dB), ds, "");                   \
+#define PUSH_2(X,f,ds,n,o,p,s,mB,dB,mA,dA,a...) do {                  \
+       PUSH_ASSERT((mB) - (mA) == (1?PUSH_##o##_INC), "mthd1");      \
+       PUSH_1(X, DATA_, 1, (ds) + (n), o, (p), s, X##mA, (dA), ##a); \
+       PUSH_##f(X, (p), X##mB, 0, o, (dB), ds, "");                  \
 } while(0)
-#define PUSH_3(X,f,ds,n,c,o,p,s,mB,dB,mA,dA,a...) do {                 \
-       PUSH_ASSERT((mB) - (mA) == (0?PUSH_##o##_INC), "mthd2");       \
-       PUSH_2(X, DATA_, 1, ds, (c)+(n), o, (p), s, X##mA, (dA), ##a); \
-       PUSH_##f(X, (p), X##mB, 0, o, (dB), ds, "");                   \
+#define PUSH_3(X,f,ds,n,o,p,s,mB,dB,mA,dA,a...) do {                  \
+       PUSH_ASSERT((mB) - (mA) == (0?PUSH_##o##_INC), "mthd2");      \
+       PUSH_2(X, DATA_, 1, (ds) + (n), o, (p), s, X##mA, (dA), ##a); \
+       PUSH_##f(X, (p), X##mB, 0, o, (dB), ds, "");                  \
 } while(0)
-#define PUSH_4(X,f,ds,n,c,o,p,s,mB,dB,mA,dA,a...) do {                 \
-       PUSH_ASSERT((mB) - (mA) == (0?PUSH_##o##_INC), "mthd3");       \
-       PUSH_3(X, DATA_, 1, ds, (c)+(n), o, (p), s, X##mA, (dA), ##a); \
-       PUSH_##f(X, (p), X##mB, 0, o, (dB), ds, "");                   \
+#define PUSH_4(X,f,ds,n,o,p,s,mB,dB,mA,dA,a...) do {                  \
+       PUSH_ASSERT((mB) - (mA) == (0?PUSH_##o##_INC), "mthd3");      \
+       PUSH_3(X, DATA_, 1, (ds) + (n), o, (p), s, X##mA, (dA), ##a); \
+       PUSH_##f(X, (p), X##mB, 0, o, (dB), ds, "");                  \
 } while(0)
-#define PUSH_5(X,f,ds,n,c,o,p,s,mB,dB,mA,dA,a...) do {                 \
-       PUSH_ASSERT((mB) - (mA) == (0?PUSH_##o##_INC), "mthd4");       \
-       PUSH_4(X, DATA_, 1, ds, (c)+(n), o, (p), s, X##mA, (dA), ##a); \
-       PUSH_##f(X, (p), X##mB, 0, o, (dB), ds, "");                   \
+#define PUSH_5(X,f,ds,n,o,p,s,mB,dB,mA,dA,a...) do {                  \
+       PUSH_ASSERT((mB) - (mA) == (0?PUSH_##o##_INC), "mthd4");      \
+       PUSH_4(X, DATA_, 1, (ds) + (n), o, (p), s, X##mA, (dA), ##a); \
+       PUSH_##f(X, (p), X##mB, 0, o, (dB), ds, "");                  \
 } while(0)
-#define PUSH_6(X,f,ds,n,c,o,p,s,mB,dB,mA,dA,a...) do {                 \
-       PUSH_ASSERT((mB) - (mA) == (0?PUSH_##o##_INC), "mthd5");       \
-       PUSH_5(X, DATA_, 1, ds, (c)+(n), o, (p), s, X##mA, (dA), ##a); \
-       PUSH_##f(X, (p), X##mB, 0, o, (dB), ds, "");                   \
+#define PUSH_6(X,f,ds,n,o,p,s,mB,dB,mA,dA,a...) do {                  \
+       PUSH_ASSERT((mB) - (mA) == (0?PUSH_##o##_INC), "mthd5");      \
+       PUSH_5(X, DATA_, 1, (ds) + (n), o, (p), s, X##mA, (dA), ##a); \
+       PUSH_##f(X, (p), X##mB, 0, o, (dB), ds, "");                  \
 } while(0)
-#define PUSH_7(X,f,ds,n,c,o,p,s,mB,dB,mA,dA,a...) do {                 \
-       PUSH_ASSERT((mB) - (mA) == (0?PUSH_##o##_INC), "mthd6");       \
-       PUSH_6(X, DATA_, 1, ds, (c)+(n), o, (p), s, X##mA, (dA), ##a); \
-       PUSH_##f(X, (p), X##mB, 0, o, (dB), ds, "");                   \
+#define PUSH_7(X,f,ds,n,o,p,s,mB,dB,mA,dA,a...) do {                  \
+       PUSH_ASSERT((mB) - (mA) == (0?PUSH_##o##_INC), "mthd6");      \
+       PUSH_6(X, DATA_, 1, (ds) + (n), o, (p), s, X##mA, (dA), ##a); \
+       PUSH_##f(X, (p), X##mB, 0, o, (dB), ds, "");                  \
 } while(0)
-#define PUSH_8(X,f,ds,n,c,o,p,s,mB,dB,mA,dA,a...) do {                 \
-       PUSH_ASSERT((mB) - (mA) == (0?PUSH_##o##_INC), "mthd7");       \
-       PUSH_7(X, DATA_, 1, ds, (c)+(n), o, (p), s, X##mA, (dA), ##a); \
-       PUSH_##f(X, (p), X##mB, 0, o, (dB), ds, "");                   \
+#define PUSH_8(X,f,ds,n,o,p,s,mB,dB,mA,dA,a...) do {                  \
+       PUSH_ASSERT((mB) - (mA) == (0?PUSH_##o##_INC), "mthd7");      \
+       PUSH_7(X, DATA_, 1, (ds) + (n), o, (p), s, X##mA, (dA), ##a); \
+       PUSH_##f(X, (p), X##mB, 0, o, (dB), ds, "");                  \
 } while(0)
-#define PUSH_9(X,f,ds,n,c,o,p,s,mB,dB,mA,dA,a...) do {                 \
-       PUSH_ASSERT((mB) - (mA) == (0?PUSH_##o##_INC), "mthd8");       \
-       PUSH_8(X, DATA_, 1, ds, (c)+(n), o, (p), s, X##mA, (dA), ##a); \
-       PUSH_##f(X, (p), X##mB, 0, o, (dB), ds, "");                   \
+#define PUSH_9(X,f,ds,n,o,p,s,mB,dB,mA,dA,a...) do {                  \
+       PUSH_ASSERT((mB) - (mA) == (0?PUSH_##o##_INC), "mthd8");      \
+       PUSH_8(X, DATA_, 1, (ds) + (n), o, (p), s, X##mA, (dA), ##a); \
+       PUSH_##f(X, (p), X##mB, 0, o, (dB), ds, "");                  \
 } while(0)
-#define PUSH_10(X,f,ds,n,c,o,p,s,mB,dB,mA,dA,a...) do {                \
-       PUSH_ASSERT((mB) - (mA) == (0?PUSH_##o##_INC), "mthd9");       \
-       PUSH_9(X, DATA_, 1, ds, (c)+(n), o, (p), s, X##mA, (dA), ##a); \
-       PUSH_##f(X, (p), X##mB, 0, o, (dB), ds, "");                   \
+#define PUSH_10(X,f,ds,n,o,p,s,mB,dB,mA,dA,a...) do {                 \
+       PUSH_ASSERT((mB) - (mA) == (0?PUSH_##o##_INC), "mthd9");      \
+       PUSH_9(X, DATA_, 1, (ds) + (n), o, (p), s, X##mA, (dA), ##a); \
+       PUSH_##f(X, (p), X##mB, 0, o, (dB), ds, "");                  \
 } while(0)
 
-#define PUSH_1D(X,o,p,s,mA,dA)                            \
-       PUSH_1(X, DATA_, 1, 1, 0, o, (p), s, X##mA, (dA))
-#define PUSH_2D(X,o,p,s,mA,dA,mB,dB)                      \
-       PUSH_2(X, DATA_, 1, 1, 0, o, (p), s, X##mB, (dB), \
-                                            X##mA, (dA))
-#define PUSH_3D(X,o,p,s,mA,dA,mB,dB,mC,dC)                \
-       PUSH_3(X, DATA_, 1, 1, 0, o, (p), s, X##mC, (dC), \
-                                            X##mB, (dB), \
-                                            X##mA, (dA))
-#define PUSH_4D(X,o,p,s,mA,dA,mB,dB,mC,dC,mD,dD)          \
-       PUSH_4(X, DATA_, 1, 1, 0, o, (p), s, X##mD, (dD), \
-                                            X##mC, (dC), \
-                                            X##mB, (dB), \
-                                            X##mA, (dA))
-#define PUSH_5D(X,o,p,s,mA,dA,mB,dB,mC,dC,mD,dD,mE,dE)    \
-       PUSH_5(X, DATA_, 1, 1, 0, o, (p), s, X##mE, (dE), \
-                                            X##mD, (dD), \
-                                            X##mC, (dC), \
-                                            X##mB, (dB), \
-                                            X##mA, (dA))
+#define PUSH_1D(X,o,p,s,mA,dA)                         \
+       PUSH_1(X, DATA_, 1, 0, o, (p), s, X##mA, (dA))
+#define PUSH_2D(X,o,p,s,mA,dA,mB,dB)                   \
+       PUSH_2(X, DATA_, 1, 0, o, (p), s, X##mB, (dB), \
+                                         X##mA, (dA))
+#define PUSH_3D(X,o,p,s,mA,dA,mB,dB,mC,dC)             \
+       PUSH_3(X, DATA_, 1, 0, o, (p), s, X##mC, (dC), \
+                                         X##mB, (dB), \
+                                         X##mA, (dA))
+#define PUSH_4D(X,o,p,s,mA,dA,mB,dB,mC,dC,mD,dD)       \
+       PUSH_4(X, DATA_, 1, 0, o, (p), s, X##mD, (dD), \
+                                         X##mC, (dC), \
+                                         X##mB, (dB), \
+                                         X##mA, (dA))
+#define PUSH_5D(X,o,p,s,mA,dA,mB,dB,mC,dC,mD,dD,mE,dE) \
+       PUSH_5(X, DATA_, 1, 0, o, (p), s, X##mE, (dE), \
+                                         X##mD, (dD), \
+                                         X##mC, (dC), \
+                                         X##mB, (dB), \
+                                         X##mA, (dA))
 #define PUSH_6D(X,o,p,s,mA,dA,mB,dB,mC,dC,mD,dD,mE,dE,mF,dF) \
-       PUSH_6(X, DATA_, 1, 1, 0, o, (p), s, X##mF, (dF),    \
-                                            X##mE, (dE),    \
-                                            X##mD, (dD),    \
-                                            X##mC, (dC),    \
-                                            X##mB, (dB),    \
-                                            X##mA, (dA))
+       PUSH_6(X, DATA_, 1, 0, o, (p), s, X##mF, (dF),       \
+                                         X##mE, (dE),       \
+                                         X##mD, (dD),       \
+                                         X##mC, (dC),       \
+                                         X##mB, (dB),       \
+                                         X##mA, (dA))
 #define PUSH_7D(X,o,p,s,mA,dA,mB,dB,mC,dC,mD,dD,mE,dE,mF,dF,mG,dG) \
-       PUSH_7(X, DATA_, 1, 1, 0, o, (p), s, X##mG, (dG),          \
-                                            X##mF, (dF),          \
-                                            X##mE, (dE),          \
-                                            X##mD, (dD),          \
-                                            X##mC, (dC),          \
-                                            X##mB, (dB),          \
-                                            X##mA, (dA))
+       PUSH_7(X, DATA_, 1, 0, o, (p), s, X##mG, (dG),             \
+                                         X##mF, (dF),             \
+                                         X##mE, (dE),             \
+                                         X##mD, (dD),             \
+                                         X##mC, (dC),             \
+                                         X##mB, (dB),             \
+                                         X##mA, (dA))
 #define PUSH_8D(X,o,p,s,mA,dA,mB,dB,mC,dC,mD,dD,mE,dE,mF,dF,mG,dG,mH,dH) \
-       PUSH_8(X, DATA_, 1, 1, 0, o, (p), s, X##mH, (dH),                \
-                                            X##mG, (dG),                \
-                                            X##mF, (dF),                \
-                                            X##mE, (dE),                \
-                                            X##mD, (dD),                \
-                                            X##mC, (dC),                \
-                                            X##mB, (dB),                \
-                                            X##mA, (dA))
+       PUSH_8(X, DATA_, 1, 0, o, (p), s, X##mH, (dH),                   \
+                                         X##mG, (dG),                   \
+                                         X##mF, (dF),                   \
+                                         X##mE, (dE),                   \
+                                         X##mD, (dD),                   \
+                                         X##mC, (dC),                   \
+                                         X##mB, (dB),                   \
+                                         X##mA, (dA))
 #define PUSH_9D(X,o,p,s,mA,dA,mB,dB,mC,dC,mD,dD,mE,dE,mF,dF,mG,dG,mH,dH,mI,dI) \
-       PUSH_9(X, DATA_, 1, 1, 0, o, (p), s, X##mI, (dI),                      \
-                                            X##mH, (dH),                      \
-                                            X##mG, (dG),                      \
-                                            X##mF, (dF),                      \
-                                            X##mE, (dE),                      \
-                                            X##mD, (dD),                      \
-                                            X##mC, (dC),                      \
-                                            X##mB, (dB),                      \
-                                            X##mA, (dA))
+       PUSH_9(X, DATA_, 1, 0, o, (p), s, X##mI, (dI),                         \
+                                         X##mH, (dH),                         \
+                                         X##mG, (dG),                         \
+                                         X##mF, (dF),                         \
+                                         X##mE, (dE),                         \
+                                         X##mD, (dD),                         \
+                                         X##mC, (dC),                         \
+                                         X##mB, (dB),                         \
+                                         X##mA, (dA))
 #define PUSH_10D(X,o,p,s,mA,dA,mB,dB,mC,dC,mD,dD,mE,dE,mF,dF,mG,dG,mH,dH,mI,dI,mJ,dJ) \
-       PUSH_10(X, DATA_, 1, 1, 0, o, (p), s, X##mJ, (dJ),                            \
-                                             X##mI, (dI),                            \
-                                             X##mH, (dH),                            \
-                                             X##mG, (dG),                            \
-                                             X##mF, (dF),                            \
-                                             X##mE, (dE),                            \
-                                             X##mD, (dD),                            \
-                                             X##mC, (dC),                            \
-                                             X##mB, (dB),                            \
-                                             X##mA, (dA))
+       PUSH_10(X, DATA_, 1, 0, o, (p), s, X##mJ, (dJ),                               \
+                                          X##mI, (dI),                               \
+                                          X##mH, (dH),                               \
+                                          X##mG, (dG),                               \
+                                          X##mF, (dF),                               \
+                                          X##mE, (dE),                               \
+                                          X##mD, (dD),                               \
+                                          X##mC, (dC),                               \
+                                          X##mB, (dB),                               \
+                                          X##mA, (dA))
 
-#define PUSH_1P(X,o,p,s,mA,dp,ds)                           \
-       PUSH_1(X, DATAp, ds, ds, 0, o, (p), s, X##mA, (dp))
-#define PUSH_2P(X,o,p,s,mA,dA,mB,dp,ds)                     \
-       PUSH_2(X, DATAp, ds, ds, 0, o, (p), s, X##mB, (dp), \
-                                              X##mA, (dA))
-#define PUSH_3P(X,o,p,s,mA,dA,mB,dB,mC,dp,ds)               \
-       PUSH_3(X, DATAp, ds, ds, 0, o, (p), s, X##mC, (dp), \
-                                              X##mB, (dB), \
-                                              X##mA, (dA))
+#define PUSH_1P(X,o,p,s,mA,dp,ds)                       \
+       PUSH_1(X, DATAp, ds, 0, o, (p), s, X##mA, (dp))
+#define PUSH_2P(X,o,p,s,mA,dA,mB,dp,ds)                 \
+       PUSH_2(X, DATAp, ds, 0, o, (p), s, X##mB, (dp), \
+                                          X##mA, (dA))
+#define PUSH_3P(X,o,p,s,mA,dA,mB,dB,mC,dp,ds)           \
+       PUSH_3(X, DATAp, ds, 0, o, (p), s, X##mC, (dp), \
+                                          X##mB, (dB), \
+                                          X##mA, (dA))
 
 #define PUSH_(A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,IMPL,...) IMPL
 #define PUSH(A...) PUSH_(A, PUSH_10P, PUSH_10D,          \
index c85b1af..7ea367a 100644 (file)
@@ -547,7 +547,7 @@ nouveau_bo_sync_for_device(struct nouveau_bo *nvbo)
 {
        struct nouveau_drm *drm = nouveau_bdev(nvbo->bo.bdev);
        struct ttm_tt *ttm_dma = (struct ttm_tt *)nvbo->bo.ttm;
-       int i;
+       int i, j;
 
        if (!ttm_dma)
                return;
@@ -556,10 +556,21 @@ nouveau_bo_sync_for_device(struct nouveau_bo *nvbo)
        if (nvbo->force_coherent)
                return;
 
-       for (i = 0; i < ttm_dma->num_pages; i++)
+       for (i = 0; i < ttm_dma->num_pages; ++i) {
+               struct page *p = ttm_dma->pages[i];
+               size_t num_pages = 1;
+
+               for (j = i + 1; j < ttm_dma->num_pages; ++j) {
+                       if (++p != ttm_dma->pages[j])
+                               break;
+
+                       ++num_pages;
+               }
                dma_sync_single_for_device(drm->dev->dev,
                                           ttm_dma->dma_address[i],
-                                          PAGE_SIZE, DMA_TO_DEVICE);
+                                          num_pages * PAGE_SIZE, DMA_TO_DEVICE);
+               i += num_pages;
+       }
 }
 
 void
@@ -567,7 +578,7 @@ nouveau_bo_sync_for_cpu(struct nouveau_bo *nvbo)
 {
        struct nouveau_drm *drm = nouveau_bdev(nvbo->bo.bdev);
        struct ttm_tt *ttm_dma = (struct ttm_tt *)nvbo->bo.ttm;
-       int i;
+       int i, j;
 
        if (!ttm_dma)
                return;
@@ -576,9 +587,21 @@ nouveau_bo_sync_for_cpu(struct nouveau_bo *nvbo)
        if (nvbo->force_coherent)
                return;
 
-       for (i = 0; i < ttm_dma->num_pages; i++)
+       for (i = 0; i < ttm_dma->num_pages; ++i) {
+               struct page *p = ttm_dma->pages[i];
+               size_t num_pages = 1;
+
+               for (j = i + 1; j < ttm_dma->num_pages; ++j) {
+                       if (++p != ttm_dma->pages[j])
+                               break;
+
+                       ++num_pages;
+               }
+
                dma_sync_single_for_cpu(drm->dev->dev, ttm_dma->dma_address[i],
-                                       PAGE_SIZE, DMA_FROM_DEVICE);
+                                       num_pages * PAGE_SIZE, DMA_FROM_DEVICE);
+               i += num_pages;
+       }
 }
 
 void nouveau_bo_add_io_reserve_lru(struct ttm_buffer_object *bo)
index 4f69e4c..1c3f890 100644 (file)
@@ -315,6 +315,10 @@ nouveau_svmm_init(struct drm_device *dev, void *data,
        struct drm_nouveau_svm_init *args = data;
        int ret;
 
+       /* We need to fail if svm is disabled */
+       if (!cli->drm->svm)
+               return -ENOSYS;
+
        /* Allocate tracking for SVM-enabled VMM. */
        if (!(svmm = kzalloc(sizeof(*svmm), GFP_KERNEL)))
                return -ENOMEM;
index 8cd776a..74bf1c8 100644 (file)
@@ -79,12 +79,13 @@ static struct page *ttm_pool_alloc_page(struct ttm_pool *pool, gfp_t gfp_flags,
        struct page *p;
        void *vaddr;
 
-       if (order) {
-               gfp_flags |= GFP_TRANSHUGE_LIGHT | __GFP_NORETRY |
+       /* Don't set the __GFP_COMP flag for higher order allocations.
+        * Mapping pages directly into an userspace process and calling
+        * put_page() on a TTM allocated page is illegal.
+        */
+       if (order)
+               gfp_flags |= __GFP_NOMEMALLOC | __GFP_NORETRY | __GFP_NOWARN |
                        __GFP_KSWAPD_RECLAIM;
-               gfp_flags &= ~__GFP_MOVABLE;
-               gfp_flags &= ~__GFP_COMP;
-       }
 
        if (!pool->use_dma_alloc) {
                p = alloc_pages(gfp_flags, order);
index 5551062..98cab0b 100644 (file)
@@ -1267,6 +1267,7 @@ static int vc4_hdmi_audio_init(struct vc4_hdmi *vc4_hdmi)
        card->dai_link = dai_link;
        card->num_links = 1;
        card->name = vc4_hdmi->variant->card_name;
+       card->driver_name = "vc4-hdmi";
        card->dev = dev;
        card->owner = THIS_MODULE;
 
index cccd341..3b72225 100644 (file)
@@ -620,11 +620,11 @@ static int vc4_hvs_bind(struct device *dev, struct device *master, void *data)
         * for now we just allocate globally.
         */
        if (!hvs->hvs5)
-               /* 96kB */
-               drm_mm_init(&hvs->lbm_mm, 0, 96 * 1024);
+               /* 48k words of 2x12-bit pixels */
+               drm_mm_init(&hvs->lbm_mm, 0, 48 * 1024);
        else
-               /* 70k words */
-               drm_mm_init(&hvs->lbm_mm, 0, 70 * 2 * 1024);
+               /* 60k words of 4x12-bit pixels */
+               drm_mm_init(&hvs->lbm_mm, 0, 60 * 1024);
 
        /* Upload filter kernels.  We only have the one for now, so we
         * keep it around for the lifetime of the driver.
index 6b39cc2..5612cab 100644 (file)
@@ -437,6 +437,7 @@ static void vc4_write_ppf(struct vc4_plane_state *vc4_state, u32 src, u32 dst)
 static u32 vc4_lbm_size(struct drm_plane_state *state)
 {
        struct vc4_plane_state *vc4_state = to_vc4_plane_state(state);
+       struct vc4_dev *vc4 = to_vc4_dev(state->plane->dev);
        u32 pix_per_line;
        u32 lbm;
 
@@ -472,7 +473,11 @@ static u32 vc4_lbm_size(struct drm_plane_state *state)
                lbm = pix_per_line * 16;
        }
 
-       lbm = roundup(lbm, 32);
+       /* Align it to 64 or 128 (hvs5) bytes */
+       lbm = roundup(lbm, vc4->hvs->hvs5 ? 128 : 64);
+
+       /* Each "word" of the LBM memory contains 2 or 4 (hvs5) pixels */
+       lbm /= vc4->hvs->hvs5 ? 4 : 2;
 
        return lbm;
 }
@@ -912,9 +917,9 @@ static int vc4_plane_mode_set(struct drm_plane *plane,
                if (!vc4_state->is_unity) {
                        vc4_dlist_write(vc4_state,
                                        VC4_SET_FIELD(vc4_state->crtc_w,
-                                                     SCALER_POS1_SCL_WIDTH) |
+                                                     SCALER5_POS1_SCL_WIDTH) |
                                        VC4_SET_FIELD(vc4_state->crtc_h,
-                                                     SCALER_POS1_SCL_HEIGHT));
+                                                     SCALER5_POS1_SCL_HEIGHT));
                }
 
                /* Position Word 2: Source Image Size */
index 0743ef5..8429ebe 100644 (file)
@@ -758,7 +758,8 @@ static int mt_touch_input_mapping(struct hid_device *hdev, struct hid_input *hi,
                        MT_STORE_FIELD(inrange_state);
                        return 1;
                case HID_DG_CONFIDENCE:
-                       if (cls->name == MT_CLS_WIN_8 &&
+                       if ((cls->name == MT_CLS_WIN_8 ||
+                            cls->name == MT_CLS_WIN_8_FORCE_MULTI_INPUT) &&
                                (field->application == HID_DG_TOUCHPAD ||
                                 field->application == HID_DG_TOUCHSCREEN))
                                app->quirks |= MT_QUIRK_CONFIDENCE;
index e8acd23..aa9e488 100644 (file)
@@ -147,9 +147,9 @@ static int wacom_wac_pen_serial_enforce(struct hid_device *hdev,
        }
 
        if (flush)
-               wacom_wac_queue_flush(hdev, &wacom_wac->pen_fifo);
+               wacom_wac_queue_flush(hdev, wacom_wac->pen_fifo);
        else if (insert)
-               wacom_wac_queue_insert(hdev, &wacom_wac->pen_fifo,
+               wacom_wac_queue_insert(hdev, wacom_wac->pen_fifo,
                                       raw_data, report_size);
 
        return insert && !flush;
@@ -1280,7 +1280,7 @@ static void wacom_devm_kfifo_release(struct device *dev, void *res)
 static int wacom_devm_kfifo_alloc(struct wacom *wacom)
 {
        struct wacom_wac *wacom_wac = &wacom->wacom_wac;
-       struct kfifo_rec_ptr_2 *pen_fifo = &wacom_wac->pen_fifo;
+       struct kfifo_rec_ptr_2 *pen_fifo;
        int error;
 
        pen_fifo = devres_alloc(wacom_devm_kfifo_release,
@@ -1297,6 +1297,7 @@ static int wacom_devm_kfifo_alloc(struct wacom *wacom)
        }
 
        devres_add(&wacom->hdev->dev, pen_fifo);
+       wacom_wac->pen_fifo = pen_fifo;
 
        return 0;
 }
index da612b6..195910d 100644 (file)
@@ -342,7 +342,7 @@ struct wacom_wac {
        struct input_dev *pen_input;
        struct input_dev *touch_input;
        struct input_dev *pad_input;
-       struct kfifo_rec_ptr_2 pen_fifo;
+       struct kfifo_rec_ptr_2 *pen_fifo;
        int pid;
        int num_contacts_left;
        u8 bt_features;
index 52acd77..251e75c 100644 (file)
@@ -268,6 +268,11 @@ static const struct pci_device_id intel_th_pci_id_table[] = {
                PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x7aa6),
                .driver_data = (kernel_ulong_t)&intel_th_2x,
        },
+       {
+               /* Alder Lake-P */
+               PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x51a6),
+               .driver_data = (kernel_ulong_t)&intel_th_2x,
+       },
        {
                /* Alder Lake CPU */
                PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x466f),
index 3e7df1c..81d7b21 100644 (file)
@@ -64,7 +64,7 @@ static void stm_heartbeat_unlink(struct stm_source_data *data)
 
 static int stm_heartbeat_init(void)
 {
-       int i, ret = -ENOMEM;
+       int i, ret;
 
        if (nr_devs < 0 || nr_devs > STM_HEARTBEAT_MAX)
                return -EINVAL;
@@ -72,8 +72,10 @@ static int stm_heartbeat_init(void)
        for (i = 0; i < nr_devs; i++) {
                stm_heartbeat[i].data.name =
                        kasprintf(GFP_KERNEL, "heartbeat.%d", i);
-               if (!stm_heartbeat[i].data.name)
+               if (!stm_heartbeat[i].data.name) {
+                       ret = -ENOMEM;
                        goto fail_unregister;
+               }
 
                stm_heartbeat[i].data.nr_chans  = 1;
                stm_heartbeat[i].data.link      = stm_heartbeat_link;
index d4d60ad..ab1f39a 100644 (file)
@@ -1013,6 +1013,7 @@ config I2C_SIRF
 config I2C_SPRD
        tristate "Spreadtrum I2C interface"
        depends on I2C=y && (ARCH_SPRD || COMPILE_TEST)
+       depends on COMMON_CLK
        help
          If you say yes to this option, support will be included for the
          Spreadtrum I2C interface.
index b444fbf..a8e8af5 100644 (file)
@@ -241,6 +241,19 @@ static struct imx_i2c_hwdata vf610_i2c_hwdata = {
 
 };
 
+static const struct platform_device_id imx_i2c_devtype[] = {
+       {
+               .name = "imx1-i2c",
+               .driver_data = (kernel_ulong_t)&imx1_i2c_hwdata,
+       }, {
+               .name = "imx21-i2c",
+               .driver_data = (kernel_ulong_t)&imx21_i2c_hwdata,
+       }, {
+               /* sentinel */
+       }
+};
+MODULE_DEVICE_TABLE(platform, imx_i2c_devtype);
+
 static const struct of_device_id i2c_imx_dt_ids[] = {
        { .compatible = "fsl,imx1-i2c", .data = &imx1_i2c_hwdata, },
        { .compatible = "fsl,imx21-i2c", .data = &imx21_i2c_hwdata, },
@@ -1330,7 +1343,11 @@ static int i2c_imx_probe(struct platform_device *pdev)
                return -ENOMEM;
 
        match = device_get_match_data(&pdev->dev);
-       i2c_imx->hwdata = match;
+       if (match)
+               i2c_imx->hwdata = match;
+       else
+               i2c_imx->hwdata = (struct imx_i2c_hwdata *)
+                               platform_get_device_id(pdev)->driver_data;
 
        /* Setup i2c_imx driver structure */
        strlcpy(i2c_imx->adapter.name, pdev->name, sizeof(i2c_imx->adapter.name));
@@ -1498,6 +1515,7 @@ static struct platform_driver i2c_imx_driver = {
                .of_match_table = i2c_imx_dt_ids,
                .acpi_match_table = i2c_imx_acpi_ids,
        },
+       .id_table = imx_i2c_devtype,
 };
 
 static int __init i2c_adap_imx_init(void)
index 0818d3e..2ffd2f3 100644 (file)
@@ -1275,7 +1275,8 @@ static int mtk_i2c_probe(struct platform_device *pdev)
        mtk_i2c_clock_disable(i2c);
 
        ret = devm_request_irq(&pdev->dev, irq, mtk_i2c_irq,
-                              IRQF_TRIGGER_NONE, I2C_DRV_NAME, i2c);
+                              IRQF_NO_SUSPEND | IRQF_TRIGGER_NONE,
+                              I2C_DRV_NAME, i2c);
        if (ret < 0) {
                dev_err(&pdev->dev,
                        "Request I2C IRQ %d fail\n", irq);
@@ -1302,7 +1303,16 @@ static int mtk_i2c_remove(struct platform_device *pdev)
 }
 
 #ifdef CONFIG_PM_SLEEP
-static int mtk_i2c_resume(struct device *dev)
+static int mtk_i2c_suspend_noirq(struct device *dev)
+{
+       struct mtk_i2c *i2c = dev_get_drvdata(dev);
+
+       i2c_mark_adapter_suspended(&i2c->adap);
+
+       return 0;
+}
+
+static int mtk_i2c_resume_noirq(struct device *dev)
 {
        int ret;
        struct mtk_i2c *i2c = dev_get_drvdata(dev);
@@ -1317,12 +1327,15 @@ static int mtk_i2c_resume(struct device *dev)
 
        mtk_i2c_clock_disable(i2c);
 
+       i2c_mark_adapter_resumed(&i2c->adap);
+
        return 0;
 }
 #endif
 
 static const struct dev_pm_ops mtk_i2c_pm = {
-       SET_SYSTEM_SLEEP_PM_OPS(NULL, mtk_i2c_resume)
+       SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(mtk_i2c_suspend_noirq,
+                                     mtk_i2c_resume_noirq)
 };
 
 static struct platform_driver mtk_i2c_driver = {
index d960790..845eda7 100644 (file)
@@ -347,7 +347,7 @@ static int octeon_i2c_read(struct octeon_i2c *i2c, int target,
                if (result)
                        return result;
                if (recv_len && i == 0) {
-                       if (data[i] > I2C_SMBUS_BLOCK_MAX + 1)
+                       if (data[i] > I2C_SMBUS_BLOCK_MAX)
                                return -EPROTO;
                        length += data[i];
                }
index ec7a7e9..c0c7d01 100644 (file)
@@ -80,7 +80,7 @@ static int tegra_bpmp_xlate_flags(u16 flags, u16 *out)
                flags &= ~I2C_M_RECV_LEN;
        }
 
-       return (flags != 0) ? -EINVAL : 0;
+       return 0;
 }
 
 /**
index 6f08c0c..8b113ae 100644 (file)
@@ -326,6 +326,8 @@ static void i2c_writel(struct tegra_i2c_dev *i2c_dev, u32 val, unsigned int reg)
        /* read back register to make sure that register writes completed */
        if (reg != I2C_TX_FIFO)
                readl_relaxed(i2c_dev->base + tegra_i2c_reg_addr(i2c_dev, reg));
+       else if (i2c_dev->is_vi)
+               readl_relaxed(i2c_dev->base + tegra_i2c_reg_addr(i2c_dev, I2C_INT_STATUS));
 }
 
 static u32 i2c_readl(struct tegra_i2c_dev *i2c_dev, unsigned int reg)
@@ -339,6 +341,21 @@ static void i2c_writesl(struct tegra_i2c_dev *i2c_dev, void *data,
        writesl(i2c_dev->base + tegra_i2c_reg_addr(i2c_dev, reg), data, len);
 }
 
+static void i2c_writesl_vi(struct tegra_i2c_dev *i2c_dev, void *data,
+                          unsigned int reg, unsigned int len)
+{
+       u32 *data32 = data;
+
+       /*
+        * VI I2C controller has known hardware bug where writes get stuck
+        * when immediate multiple writes happen to TX_FIFO register.
+        * Recommended software work around is to read I2C register after
+        * each write to TX_FIFO register to flush out the data.
+        */
+       while (len--)
+               i2c_writel(i2c_dev, *data32++, reg);
+}
+
 static void i2c_readsl(struct tegra_i2c_dev *i2c_dev, void *data,
                       unsigned int reg, unsigned int len)
 {
@@ -533,7 +550,7 @@ static int tegra_i2c_poll_register(struct tegra_i2c_dev *i2c_dev,
        void __iomem *addr = i2c_dev->base + tegra_i2c_reg_addr(i2c_dev, reg);
        u32 val;
 
-       if (!i2c_dev->atomic_mode)
+       if (!i2c_dev->atomic_mode && !in_irq())
                return readl_relaxed_poll_timeout(addr, val, !(val & mask),
                                                  delay_us, timeout_us);
 
@@ -811,7 +828,10 @@ static int tegra_i2c_fill_tx_fifo(struct tegra_i2c_dev *i2c_dev)
                i2c_dev->msg_buf_remaining = buf_remaining;
                i2c_dev->msg_buf = buf + words_to_transfer * BYTES_PER_FIFO_WORD;
 
-               i2c_writesl(i2c_dev, buf, I2C_TX_FIFO, words_to_transfer);
+               if (i2c_dev->is_vi)
+                       i2c_writesl_vi(i2c_dev, buf, I2C_TX_FIFO, words_to_transfer);
+               else
+                       i2c_writesl(i2c_dev, buf, I2C_TX_FIFO, words_to_transfer);
 
                buf += words_to_transfer * BYTES_PER_FIFO_WORD;
        }
index b11c8c4..e946903 100644 (file)
@@ -397,16 +397,12 @@ static int tiadc_iio_buffered_hardware_setup(struct device *dev,
        ret = devm_request_threaded_irq(dev, irq, pollfunc_th, pollfunc_bh,
                                flags, indio_dev->name, indio_dev);
        if (ret)
-               goto error_kfifo_free;
+               return ret;
 
        indio_dev->setup_ops = setup_ops;
        indio_dev->modes |= INDIO_BUFFER_SOFTWARE;
 
        return 0;
-
-error_kfifo_free:
-       iio_kfifo_free(indio_dev->buffer);
-       return ret;
 }
 
 static const char * const chan_name_ain[] = {
index 0507283..2dbd264 100644 (file)
  * @sdata: Sensor data.
  *
  * returns:
- * 0 - no new samples available
- * 1 - new samples available
- * negative - error or unknown
+ * false - no new samples available or read error
+ * true - new samples available
  */
-static int st_sensors_new_samples_available(struct iio_dev *indio_dev,
-                                           struct st_sensor_data *sdata)
+static bool st_sensors_new_samples_available(struct iio_dev *indio_dev,
+                                            struct st_sensor_data *sdata)
 {
        int ret, status;
 
        /* How would I know if I can't check it? */
        if (!sdata->sensor_settings->drdy_irq.stat_drdy.addr)
-               return -EINVAL;
+               return true;
 
        /* No scan mask, no interrupt */
        if (!indio_dev->active_scan_mask)
-               return 0;
+               return false;
 
        ret = regmap_read(sdata->regmap,
                          sdata->sensor_settings->drdy_irq.stat_drdy.addr,
                          &status);
        if (ret < 0) {
                dev_err(sdata->dev, "error checking samples available\n");
-               return ret;
+               return false;
        }
 
-       if (status & sdata->sensor_settings->drdy_irq.stat_drdy.mask)
-               return 1;
-
-       return 0;
+       return !!(status & sdata->sensor_settings->drdy_irq.stat_drdy.mask);
 }
 
 /**
@@ -180,9 +176,15 @@ int st_sensors_allocate_trigger(struct iio_dev *indio_dev,
 
        /* Tell the interrupt handler that we're dealing with edges */
        if (irq_trig == IRQF_TRIGGER_FALLING ||
-           irq_trig == IRQF_TRIGGER_RISING)
+           irq_trig == IRQF_TRIGGER_RISING) {
+               if (!sdata->sensor_settings->drdy_irq.stat_drdy.addr) {
+                       dev_err(&indio_dev->dev,
+                               "edge IRQ not supported w/o stat register.\n");
+                       err = -EOPNOTSUPP;
+                       goto iio_trigger_free;
+               }
                sdata->edge_irq = true;
-       else
+       } else {
                /*
                 * If we're not using edges (i.e. level interrupts) we
                 * just mask off the IRQ, handle one interrupt, then
@@ -190,6 +192,7 @@ int st_sensors_allocate_trigger(struct iio_dev *indio_dev,
                 * interrupt handler top half again and start over.
                 */
                irq_trig |= IRQF_ONESHOT;
+       }
 
        /*
         * If the interrupt pin is Open Drain, by definition this
index 28921b6..e9297c2 100644 (file)
@@ -187,9 +187,9 @@ static ssize_t ad5504_write_dac_powerdown(struct iio_dev *indio_dev,
                return ret;
 
        if (pwr_down)
-               st->pwr_down_mask |= (1 << chan->channel);
-       else
                st->pwr_down_mask &= ~(1 << chan->channel);
+       else
+               st->pwr_down_mask |= (1 << chan->channel);
 
        ret = ad5504_spi_write(st, AD5504_ADDR_CTRL,
                                AD5504_DAC_PWRDWN_MODE(st->pwr_down_mode) |
index a2f8209..37fd0b6 100644 (file)
@@ -601,7 +601,7 @@ static int sx9310_read_thresh(struct sx9310_data *data,
                return ret;
 
        regval = FIELD_GET(SX9310_REG_PROX_CTRL8_9_PTHRESH_MASK, regval);
-       if (regval > ARRAY_SIZE(sx9310_pthresh_codes))
+       if (regval >= ARRAY_SIZE(sx9310_pthresh_codes))
                return -EINVAL;
 
        *val = sx9310_pthresh_codes[regval];
@@ -1305,7 +1305,8 @@ sx9310_get_default_reg(struct sx9310_data *data, int i,
                if (ret)
                        break;
 
-               pos = min(max(ilog2(pos), 3), 10) - 3;
+               /* Powers of 2, except for a gap between 16 and 64 */
+               pos = clamp(ilog2(pos), 3, 11) - (pos >= 32 ? 4 : 3);
                reg_def->def &= ~SX9310_REG_PROX_CTRL7_AVGPOSFILT_MASK;
                reg_def->def |= FIELD_PREP(SX9310_REG_PROX_CTRL7_AVGPOSFILT_MASK,
                                           pos);
index 503fe54..608ccb1 100644 (file)
@@ -248,6 +248,12 @@ static int mlx90632_set_meas_type(struct regmap *regmap, u8 type)
        if (ret < 0)
                return ret;
 
+       /*
+        * Give the mlx90632 some time to reset properly before sending a new I2C command
+        * if this is not done, the following I2C command(s) will not be accepted.
+        */
+       usleep_range(150, 200);
+
        ret = regmap_write_bits(regmap, MLX90632_REG_CONTROL,
                                 (MLX90632_CFG_MTYP_MASK | MLX90632_CFG_PWR_MASK),
                                 (MLX90632_MTYP_STATUS(type) | MLX90632_PWR_STATUS_HALT));
index a740139..d109bb3 100644 (file)
@@ -2474,7 +2474,7 @@ int c4iw_ib_query_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr,
        init_attr->cap.max_send_wr = qhp->attr.sq_num_entries;
        init_attr->cap.max_recv_wr = qhp->attr.rq_num_entries;
        init_attr->cap.max_send_sge = qhp->attr.sq_max_sges;
-       init_attr->cap.max_recv_sge = qhp->attr.sq_max_sges;
+       init_attr->cap.max_recv_sge = qhp->attr.rq_max_sges;
        init_attr->cap.max_inline_data = T4_MAX_SEND_INLINE;
        init_attr->sq_sig_type = qhp->sq_sig_all ? IB_SIGNAL_ALL_WR : 0;
        return 0;
index 55d5386..ad82532 100644 (file)
@@ -532,7 +532,7 @@ struct hns_roce_qp_table {
        struct hns_roce_hem_table       sccc_table;
        struct mutex                    scc_mutex;
        struct hns_roce_bank bank[HNS_ROCE_QP_BANK_NUM];
-       spinlock_t bank_lock;
+       struct mutex bank_mutex;
 };
 
 struct hns_roce_cq_table {
index d8e2fe5..1116371 100644 (file)
@@ -209,7 +209,7 @@ static int alloc_qpn(struct hns_roce_dev *hr_dev, struct hns_roce_qp *hr_qp)
 
                hr_qp->doorbell_qpn = 1;
        } else {
-               spin_lock(&qp_table->bank_lock);
+               mutex_lock(&qp_table->bank_mutex);
                bankid = get_least_load_bankid_for_qp(qp_table->bank);
 
                ret = alloc_qpn_with_bankid(&qp_table->bank[bankid], bankid,
@@ -217,12 +217,12 @@ static int alloc_qpn(struct hns_roce_dev *hr_dev, struct hns_roce_qp *hr_qp)
                if (ret) {
                        ibdev_err(&hr_dev->ib_dev,
                                  "failed to alloc QPN, ret = %d\n", ret);
-                       spin_unlock(&qp_table->bank_lock);
+                       mutex_unlock(&qp_table->bank_mutex);
                        return ret;
                }
 
                qp_table->bank[bankid].inuse++;
-               spin_unlock(&qp_table->bank_lock);
+               mutex_unlock(&qp_table->bank_mutex);
 
                hr_qp->doorbell_qpn = (u32)num;
        }
@@ -408,9 +408,9 @@ static void free_qpn(struct hns_roce_dev *hr_dev, struct hns_roce_qp *hr_qp)
 
        ida_free(&hr_dev->qp_table.bank[bankid].ida, hr_qp->qpn >> 3);
 
-       spin_lock(&hr_dev->qp_table.bank_lock);
+       mutex_lock(&hr_dev->qp_table.bank_mutex);
        hr_dev->qp_table.bank[bankid].inuse--;
-       spin_unlock(&hr_dev->qp_table.bank_lock);
+       mutex_unlock(&hr_dev->qp_table.bank_mutex);
 }
 
 static int set_rq_size(struct hns_roce_dev *hr_dev, struct ib_qp_cap *cap,
@@ -1371,6 +1371,7 @@ int hns_roce_init_qp_table(struct hns_roce_dev *hr_dev)
        unsigned int i;
 
        mutex_init(&qp_table->scc_mutex);
+       mutex_init(&qp_table->bank_mutex);
        xa_init(&hr_dev->qp_table_xa);
 
        reserved_from_bot = hr_dev->caps.reserved_qps;
index d26f3f3..aabdc07 100644 (file)
@@ -3311,8 +3311,7 @@ static int mlx5_add_netdev_notifier(struct mlx5_ib_dev *dev, u8 port_num)
        int err;
 
        dev->port[port_num].roce.nb.notifier_call = mlx5_netdev_event;
-       err = register_netdevice_notifier_net(mlx5_core_net(dev->mdev),
-                                             &dev->port[port_num].roce.nb);
+       err = register_netdevice_notifier(&dev->port[port_num].roce.nb);
        if (err) {
                dev->port[port_num].roce.nb.notifier_call = NULL;
                return err;
@@ -3324,8 +3323,7 @@ static int mlx5_add_netdev_notifier(struct mlx5_ib_dev *dev, u8 port_num)
 static void mlx5_remove_netdev_notifier(struct mlx5_ib_dev *dev, u8 port_num)
 {
        if (dev->port[port_num].roce.nb.notifier_call) {
-               unregister_netdevice_notifier_net(mlx5_core_net(dev->mdev),
-                                                 &dev->port[port_num].roce.nb);
+               unregister_netdevice_notifier(&dev->port[port_num].roce.nb);
                dev->port[port_num].roce.nb.notifier_call = NULL;
        }
 }
index e59615a..586b0e5 100644 (file)
@@ -214,7 +214,7 @@ static ssize_t summary_show(struct usnic_ib_qp_grp *qp_grp, char *buf)
        struct usnic_vnic_res *vnic_res;
        int len;
 
-       len = sysfs_emit(buf, "QPN: %d State: (%s) PID: %u VF Idx: %hu ",
+       len = sysfs_emit(buf, "QPN: %d State: (%s) PID: %u VF Idx: %hu",
                         qp_grp->ibqp.qp_num,
                         usnic_ib_qp_grp_state_to_string(qp_grp->state),
                         qp_grp->owner_pid,
@@ -224,14 +224,13 @@ static ssize_t summary_show(struct usnic_ib_qp_grp *qp_grp, char *buf)
                res_chunk = qp_grp->res_chunk_list[i];
                for (j = 0; j < res_chunk->cnt; j++) {
                        vnic_res = res_chunk->res[j];
-                       len += sysfs_emit_at(
-                               buf, len, "%s[%d] ",
+                       len += sysfs_emit_at(buf, len, " %s[%d]",
                                usnic_vnic_res_type_to_str(vnic_res->type),
                                vnic_res->vnic_idx);
                }
        }
 
-       len = sysfs_emit_at(buf, len, "\n");
+       len += sysfs_emit_at(buf, len, "\n");
 
        return len;
 }
index c142f5e..de57f2f 100644 (file)
@@ -509,6 +509,20 @@ static inline int ib_send_flags_to_pvrdma(int flags)
        return flags & PVRDMA_MASK(PVRDMA_SEND_FLAGS_MAX);
 }
 
+static inline int pvrdma_network_type_to_ib(enum pvrdma_network_type type)
+{
+       switch (type) {
+       case PVRDMA_NETWORK_ROCE_V1:
+               return RDMA_NETWORK_ROCE_V1;
+       case PVRDMA_NETWORK_IPV4:
+               return RDMA_NETWORK_IPV4;
+       case PVRDMA_NETWORK_IPV6:
+               return RDMA_NETWORK_IPV6;
+       default:
+               return RDMA_NETWORK_IPV6;
+       }
+}
+
 void pvrdma_qp_cap_to_ib(struct ib_qp_cap *dst,
                         const struct pvrdma_qp_cap *src);
 void ib_qp_cap_to_pvrdma(struct pvrdma_qp_cap *dst,
index a119ac3..6aa40bd 100644 (file)
@@ -367,7 +367,7 @@ retry:
        wc->dlid_path_bits = cqe->dlid_path_bits;
        wc->port_num = cqe->port_num;
        wc->vendor_err = cqe->vendor_err;
-       wc->network_hdr_type = cqe->network_hdr_type;
+       wc->network_hdr_type = pvrdma_network_type_to_ib(cqe->network_hdr_type);
 
        /* Update shared ring state */
        pvrdma_idx_ring_inc(&cq->ring_state->rx.cons_head, cq->ibcq.cqe);
index c4b06ce..943914c 100644 (file)
@@ -8,6 +8,7 @@
 #include <linux/if_arp.h>
 #include <linux/netdevice.h>
 #include <linux/if.h>
+#include <linux/if_vlan.h>
 #include <net/udp_tunnel.h>
 #include <net/sch_generic.h>
 #include <linux/netfilter.h>
@@ -153,9 +154,14 @@ static int rxe_udp_encap_recv(struct sock *sk, struct sk_buff *skb)
 {
        struct udphdr *udph;
        struct net_device *ndev = skb->dev;
+       struct net_device *rdev = ndev;
        struct rxe_dev *rxe = rxe_get_dev_from_net(ndev);
        struct rxe_pkt_info *pkt = SKB_TO_PKT(skb);
 
+       if (!rxe && is_vlan_dev(rdev)) {
+               rdev = vlan_dev_real_dev(ndev);
+               rxe = rxe_get_dev_from_net(rdev);
+       }
        if (!rxe)
                goto drop;
 
index 5a09808..c7e3b6a 100644 (file)
@@ -872,6 +872,11 @@ static enum resp_states do_complete(struct rxe_qp *qp,
                        else
                                wc->network_hdr_type = RDMA_NETWORK_IPV6;
 
+                       if (is_vlan_dev(skb->dev)) {
+                               wc->wc_flags |= IB_WC_WITH_VLAN;
+                               wc->vlan_id = vlan_dev_vlan_id(skb->dev);
+                       }
+
                        if (pkt->mask & RXE_IMMDT_MASK) {
                                wc->wc_flags |= IB_WC_WITH_IMM;
                                wc->ex.imm_data = immdt_imm(pkt);
index 0687f0e..8cc8ca4 100644 (file)
@@ -215,9 +215,17 @@ static const struct xpad_device {
        { 0x0e6f, 0x0213, "Afterglow Gamepad for Xbox 360", 0, XTYPE_XBOX360 },
        { 0x0e6f, 0x021f, "Rock Candy Gamepad for Xbox 360", 0, XTYPE_XBOX360 },
        { 0x0e6f, 0x0246, "Rock Candy Gamepad for Xbox One 2015", 0, XTYPE_XBOXONE },
-       { 0x0e6f, 0x02ab, "PDP Controller for Xbox One", 0, XTYPE_XBOXONE },
+       { 0x0e6f, 0x02a0, "PDP Xbox One Controller", 0, XTYPE_XBOXONE },
+       { 0x0e6f, 0x02a1, "PDP Xbox One Controller", 0, XTYPE_XBOXONE },
+       { 0x0e6f, 0x02a2, "PDP Wired Controller for Xbox One - Crimson Red", 0, XTYPE_XBOXONE },
        { 0x0e6f, 0x02a4, "PDP Wired Controller for Xbox One - Stealth Series", 0, XTYPE_XBOXONE },
        { 0x0e6f, 0x02a6, "PDP Wired Controller for Xbox One - Camo Series", 0, XTYPE_XBOXONE },
+       { 0x0e6f, 0x02a7, "PDP Xbox One Controller", 0, XTYPE_XBOXONE },
+       { 0x0e6f, 0x02a8, "PDP Xbox One Controller", 0, XTYPE_XBOXONE },
+       { 0x0e6f, 0x02ab, "PDP Controller for Xbox One", 0, XTYPE_XBOXONE },
+       { 0x0e6f, 0x02ad, "PDP Wired Controller for Xbox One - Stealth Series", 0, XTYPE_XBOXONE },
+       { 0x0e6f, 0x02b3, "Afterglow Prismatic Wired Controller", 0, XTYPE_XBOXONE },
+       { 0x0e6f, 0x02b8, "Afterglow Prismatic Wired Controller", 0, XTYPE_XBOXONE },
        { 0x0e6f, 0x0301, "Logic3 Controller", 0, XTYPE_XBOX360 },
        { 0x0e6f, 0x0346, "Rock Candy Gamepad for Xbox One 2016", 0, XTYPE_XBOXONE },
        { 0x0e6f, 0x0401, "Logic3 Controller", 0, XTYPE_XBOX360 },
@@ -296,6 +304,9 @@ static const struct xpad_device {
        { 0x1bad, 0xfa01, "MadCatz GamePad", 0, XTYPE_XBOX360 },
        { 0x1bad, 0xfd00, "Razer Onza TE", 0, XTYPE_XBOX360 },
        { 0x1bad, 0xfd01, "Razer Onza", 0, XTYPE_XBOX360 },
+       { 0x20d6, 0x2001, "BDA Xbox Series X Wired Controller", 0, XTYPE_XBOXONE },
+       { 0x20d6, 0x281f, "PowerA Wired Controller For Xbox 360", 0, XTYPE_XBOX360 },
+       { 0x2e24, 0x0652, "Hyperkin Duke X-Box One pad", 0, XTYPE_XBOXONE },
        { 0x24c6, 0x5000, "Razer Atrox Arcade Stick", MAP_TRIGGERS_TO_BUTTONS, XTYPE_XBOX360 },
        { 0x24c6, 0x5300, "PowerA MINI PROEX Controller", 0, XTYPE_XBOX360 },
        { 0x24c6, 0x5303, "Xbox Airflo wired controller", 0, XTYPE_XBOX360 },
@@ -429,8 +440,12 @@ static const struct usb_device_id xpad_table[] = {
        XPAD_XBOX360_VENDOR(0x162e),            /* Joytech X-Box 360 controllers */
        XPAD_XBOX360_VENDOR(0x1689),            /* Razer Onza */
        XPAD_XBOX360_VENDOR(0x1bad),            /* Harminix Rock Band Guitar and Drums */
+       XPAD_XBOX360_VENDOR(0x20d6),            /* PowerA Controllers */
+       XPAD_XBOXONE_VENDOR(0x20d6),            /* PowerA Controllers */
        XPAD_XBOX360_VENDOR(0x24c6),            /* PowerA Controllers */
        XPAD_XBOXONE_VENDOR(0x24c6),            /* PowerA Controllers */
+       XPAD_XBOXONE_VENDOR(0x2e24),            /* Hyperkin Duke X-Box One pad */
+       XPAD_XBOX360_VENDOR(0x2f24),            /* GameSir Controllers */
        { }
 };
 
index eda86ab..17bbaac 100644 (file)
@@ -149,12 +149,6 @@ static const struct of_device_id ariel_pwrbutton_of_match[] = {
 };
 MODULE_DEVICE_TABLE(of, ariel_pwrbutton_of_match);
 
-static const struct spi_device_id ariel_pwrbutton_id_table[] = {
-       { "wyse-ariel-ec-input", 0 },
-       {}
-};
-MODULE_DEVICE_TABLE(spi, ariel_pwrbutton_id_table);
-
 static struct spi_driver ariel_pwrbutton_driver = {
        .driver = {
                .name = "dell-wyse-ariel-ec-input",
index 3a2dcf0..c74b020 100644 (file)
@@ -219,6 +219,8 @@ static const struct dmi_system_id __initconst i8042_dmi_noloop_table[] = {
                        DMI_MATCH(DMI_SYS_VENDOR, "PEGATRON CORPORATION"),
                        DMI_MATCH(DMI_PRODUCT_NAME, "C15B"),
                },
+       },
+       {
                .matches = {
                        DMI_MATCH(DMI_SYS_VENDOR, "ByteSpeed LLC"),
                        DMI_MATCH(DMI_PRODUCT_NAME, "ByteSpeed Laptop C15B"),
index 19765f1..c682b02 100644 (file)
@@ -157,6 +157,7 @@ static const struct goodix_chip_id goodix_chip_ids[] = {
        { .id = "5663", .data = &gt1x_chip_data },
        { .id = "5688", .data = &gt1x_chip_data },
        { .id = "917S", .data = &gt1x_chip_data },
+       { .id = "9286", .data = &gt1x_chip_data },
 
        { .id = "911", .data = &gt911_chip_data },
        { .id = "9271", .data = &gt911_chip_data },
@@ -1448,6 +1449,7 @@ static const struct of_device_id goodix_of_match[] = {
        { .compatible = "goodix,gt927" },
        { .compatible = "goodix,gt9271" },
        { .compatible = "goodix,gt928" },
+       { .compatible = "goodix,gt9286" },
        { .compatible = "goodix,gt967" },
        { }
 };
index 199cf3d..d8fccf0 100644 (file)
@@ -29,11 +29,13 @@ struct ili2xxx_chip {
                        void *buf, size_t len);
        int (*get_touch_data)(struct i2c_client *client, u8 *data);
        bool (*parse_touch_data)(const u8 *data, unsigned int finger,
-                                unsigned int *x, unsigned int *y);
+                                unsigned int *x, unsigned int *y,
+                                unsigned int *z);
        bool (*continue_polling)(const u8 *data, bool touch);
        unsigned int max_touches;
        unsigned int resolution;
        bool has_calibrate_reg;
+       bool has_pressure_reg;
 };
 
 struct ili210x {
@@ -82,7 +84,8 @@ static int ili210x_read_touch_data(struct i2c_client *client, u8 *data)
 
 static bool ili210x_touchdata_to_coords(const u8 *touchdata,
                                        unsigned int finger,
-                                       unsigned int *x, unsigned int *y)
+                                       unsigned int *x, unsigned int *y,
+                                       unsigned int *z)
 {
        if (touchdata[0] & BIT(finger))
                return false;
@@ -137,7 +140,8 @@ static int ili211x_read_touch_data(struct i2c_client *client, u8 *data)
 
 static bool ili211x_touchdata_to_coords(const u8 *touchdata,
                                        unsigned int finger,
-                                       unsigned int *x, unsigned int *y)
+                                       unsigned int *x, unsigned int *y,
+                                       unsigned int *z)
 {
        u32 data;
 
@@ -169,7 +173,8 @@ static const struct ili2xxx_chip ili211x_chip = {
 
 static bool ili212x_touchdata_to_coords(const u8 *touchdata,
                                        unsigned int finger,
-                                       unsigned int *x, unsigned int *y)
+                                       unsigned int *x, unsigned int *y,
+                                       unsigned int *z)
 {
        u16 val;
 
@@ -235,7 +240,8 @@ static int ili251x_read_touch_data(struct i2c_client *client, u8 *data)
 
 static bool ili251x_touchdata_to_coords(const u8 *touchdata,
                                        unsigned int finger,
-                                       unsigned int *x, unsigned int *y)
+                                       unsigned int *x, unsigned int *y,
+                                       unsigned int *z)
 {
        u16 val;
 
@@ -245,6 +251,7 @@ static bool ili251x_touchdata_to_coords(const u8 *touchdata,
 
        *x = val & 0x3fff;
        *y = get_unaligned_be16(touchdata + 1 + (finger * 5) + 2);
+       *z = touchdata[1 + (finger * 5) + 4];
 
        return true;
 }
@@ -261,6 +268,7 @@ static const struct ili2xxx_chip ili251x_chip = {
        .continue_polling       = ili251x_check_continue_polling,
        .max_touches            = 10,
        .has_calibrate_reg      = true,
+       .has_pressure_reg       = true,
 };
 
 static bool ili210x_report_events(struct ili210x *priv, u8 *touchdata)
@@ -268,14 +276,16 @@ static bool ili210x_report_events(struct ili210x *priv, u8 *touchdata)
        struct input_dev *input = priv->input;
        int i;
        bool contact = false, touch;
-       unsigned int x = 0, y = 0;
+       unsigned int x = 0, y = 0, z = 0;
 
        for (i = 0; i < priv->chip->max_touches; i++) {
-               touch = priv->chip->parse_touch_data(touchdata, i, &x, &y);
+               touch = priv->chip->parse_touch_data(touchdata, i, &x, &y, &z);
 
                input_mt_slot(input, i);
                if (input_mt_report_slot_state(input, MT_TOOL_FINGER, touch)) {
                        touchscreen_report_pos(input, &priv->prop, x, y, true);
+                       if (priv->chip->has_pressure_reg)
+                               input_report_abs(input, ABS_MT_PRESSURE, z);
                        contact = true;
                }
        }
@@ -437,6 +447,8 @@ static int ili210x_i2c_probe(struct i2c_client *client,
        max_xy = (chip->resolution ?: SZ_64K) - 1;
        input_set_abs_params(input, ABS_MT_POSITION_X, 0, max_xy, 0, 0);
        input_set_abs_params(input, ABS_MT_POSITION_Y, 0, max_xy, 0, 0);
+       if (priv->chip->has_pressure_reg)
+               input_set_abs_params(input, ABS_MT_PRESSURE, 0, 0xa, 0, 0);
        touchscreen_parse_properties(input, true, &priv->prop);
 
        error = input_mt_init_slots(input, priv->chip->max_touches,
index bda9676..b4e7bcb 100644 (file)
 #define ST1232_TS_NAME "st1232-ts"
 #define ST1633_TS_NAME "st1633-ts"
 
+#define REG_STATUS             0x01    /* Device Status | Error Code */
+
+#define STATUS_NORMAL          0x00
+#define STATUS_INIT            0x01
+#define STATUS_ERROR           0x02
+#define STATUS_AUTO_TUNING     0x03
+#define STATUS_IDLE            0x04
+#define STATUS_POWER_DOWN      0x05
+
+#define ERROR_NONE             0x00
+#define ERROR_INVALID_ADDRESS  0x10
+#define ERROR_INVALID_VALUE    0x20
+#define ERROR_INVALID_PLATFORM 0x30
+
 #define REG_XY_RESOLUTION      0x04
 #define REG_XY_COORDINATES     0x12
 #define ST_TS_MAX_FINGERS      10
@@ -47,7 +61,8 @@ struct st1232_ts_data {
        u8 *read_buf;
 };
 
-static int st1232_ts_read_data(struct st1232_ts_data *ts, u8 reg)
+static int st1232_ts_read_data(struct st1232_ts_data *ts, u8 reg,
+                              unsigned int n)
 {
        struct i2c_client *client = ts->client;
        struct i2c_msg msg[] = {
@@ -59,7 +74,7 @@ static int st1232_ts_read_data(struct st1232_ts_data *ts, u8 reg)
                {
                        .addr   = client->addr,
                        .flags  = I2C_M_RD | I2C_M_DMA_SAFE,
-                       .len    = ts->read_buf_len,
+                       .len    = n,
                        .buf    = ts->read_buf,
                }
        };
@@ -72,6 +87,22 @@ static int st1232_ts_read_data(struct st1232_ts_data *ts, u8 reg)
        return 0;
 }
 
+static int st1232_ts_wait_ready(struct st1232_ts_data *ts)
+{
+       unsigned int retries;
+       int error;
+
+       for (retries = 10; retries; retries--) {
+               error = st1232_ts_read_data(ts, REG_STATUS, 1);
+               if (!error && ts->read_buf[0] == (STATUS_NORMAL | ERROR_NONE))
+                       return 0;
+
+               usleep_range(1000, 2000);
+       }
+
+       return -ENXIO;
+}
+
 static int st1232_ts_read_resolution(struct st1232_ts_data *ts, u16 *max_x,
                                     u16 *max_y)
 {
@@ -79,14 +110,14 @@ static int st1232_ts_read_resolution(struct st1232_ts_data *ts, u16 *max_x,
        int error;
 
        /* select resolution register */
-       error = st1232_ts_read_data(ts, REG_XY_RESOLUTION);
+       error = st1232_ts_read_data(ts, REG_XY_RESOLUTION, 3);
        if (error)
                return error;
 
        buf = ts->read_buf;
 
-       *max_x = ((buf[0] & 0x0070) << 4) | buf[1];
-       *max_y = ((buf[0] & 0x0007) << 8) | buf[2];
+       *max_x = (((buf[0] & 0x0070) << 4) | buf[1]) - 1;
+       *max_y = (((buf[0] & 0x0007) << 8) | buf[2]) - 1;
 
        return 0;
 }
@@ -140,7 +171,7 @@ static irqreturn_t st1232_ts_irq_handler(int irq, void *dev_id)
        int count;
        int error;
 
-       error = st1232_ts_read_data(ts, REG_XY_COORDINATES);
+       error = st1232_ts_read_data(ts, REG_XY_COORDINATES, ts->read_buf_len);
        if (error)
                goto out;
 
@@ -251,6 +282,11 @@ static int st1232_ts_probe(struct i2c_client *client,
        input_dev->name = "st1232-touchscreen";
        input_dev->id.bustype = BUS_I2C;
 
+       /* Wait until device is ready */
+       error = st1232_ts_wait_ready(ts);
+       if (error)
+               return error;
+
        /* Read resolution from the chip */
        error = st1232_ts_read_resolution(ts, &max_x, &max_y);
        if (error) {
index 6b8cbdf..b4adab6 100644 (file)
@@ -84,12 +84,9 @@ static inline bool is_rd890_iommu(struct pci_dev *pdev)
               (pdev->device == PCI_DEVICE_ID_RD890_IOMMU);
 }
 
-static inline bool iommu_feature(struct amd_iommu *iommu, u64 f)
+static inline bool iommu_feature(struct amd_iommu *iommu, u64 mask)
 {
-       if (!(iommu->cap & (1 << IOMMU_CAP_EFR)))
-               return false;
-
-       return !!(iommu->features & f);
+       return !!(iommu->features & mask);
 }
 
 static inline u64 iommu_virt_to_phys(void *vaddr)
index 5535878..1a0495d 100644 (file)
 #define IOMMU_CAP_NPCACHE 26
 #define IOMMU_CAP_EFR     27
 
+/* IOMMU IVINFO */
+#define IOMMU_IVINFO_OFFSET     36
+#define IOMMU_IVINFO_EFRSUP     BIT(0)
+
 /* IOMMU Feature Reporting Field (for IVHD type 10h */
 #define IOMMU_FEAT_GASUP_SHIFT 6
 
index 6a1f704..83d8ab2 100644 (file)
@@ -257,6 +257,8 @@ static void init_device_table_dma(void);
 
 static bool amd_iommu_pre_enabled = true;
 
+static u32 amd_iommu_ivinfo __initdata;
+
 bool translation_pre_enabled(struct amd_iommu *iommu)
 {
        return (iommu->flags & AMD_IOMMU_FLAG_TRANS_PRE_ENABLED);
@@ -296,6 +298,18 @@ int amd_iommu_get_num_iommus(void)
        return amd_iommus_present;
 }
 
+/*
+ * For IVHD type 0x11/0x40, EFR is also available via IVHD.
+ * Default to IVHD EFR since it is available sooner
+ * (i.e. before PCI init).
+ */
+static void __init early_iommu_features_init(struct amd_iommu *iommu,
+                                            struct ivhd_header *h)
+{
+       if (amd_iommu_ivinfo & IOMMU_IVINFO_EFRSUP)
+               iommu->features = h->efr_reg;
+}
+
 /* Access to l1 and l2 indexed register spaces */
 
 static u32 iommu_read_l1(struct amd_iommu *iommu, u16 l1, u8 address)
@@ -1577,6 +1591,9 @@ static int __init init_iommu_one(struct amd_iommu *iommu, struct ivhd_header *h)
 
                if (h->efr_reg & BIT(IOMMU_EFR_XTSUP_SHIFT))
                        amd_iommu_xt_mode = IRQ_REMAP_X2APIC_MODE;
+
+               early_iommu_features_init(iommu, h);
+
                break;
        default:
                return -EINVAL;
@@ -1770,6 +1787,35 @@ static const struct attribute_group *amd_iommu_groups[] = {
        NULL,
 };
 
+/*
+ * Note: IVHD 0x11 and 0x40 also contains exact copy
+ * of the IOMMU Extended Feature Register [MMIO Offset 0030h].
+ * Default to EFR in IVHD since it is available sooner (i.e. before PCI init).
+ */
+static void __init late_iommu_features_init(struct amd_iommu *iommu)
+{
+       u64 features;
+
+       if (!(iommu->cap & (1 << IOMMU_CAP_EFR)))
+               return;
+
+       /* read extended feature bits */
+       features = readq(iommu->mmio_base + MMIO_EXT_FEATURES);
+
+       if (!iommu->features) {
+               iommu->features = features;
+               return;
+       }
+
+       /*
+        * Sanity check and warn if EFR values from
+        * IVHD and MMIO conflict.
+        */
+       if (features != iommu->features)
+               pr_warn(FW_WARN "EFR mismatch. Use IVHD EFR (%#llx : %#llx\n).",
+                       features, iommu->features);
+}
+
 static int __init iommu_init_pci(struct amd_iommu *iommu)
 {
        int cap_ptr = iommu->cap_ptr;
@@ -1789,8 +1835,7 @@ static int __init iommu_init_pci(struct amd_iommu *iommu)
        if (!(iommu->cap & (1 << IOMMU_CAP_IOTLB)))
                amd_iommu_iotlb_sup = false;
 
-       /* read extended feature bits */
-       iommu->features = readq(iommu->mmio_base + MMIO_EXT_FEATURES);
+       late_iommu_features_init(iommu);
 
        if (iommu_feature(iommu, FEATURE_GT)) {
                int glxval;
@@ -2607,6 +2652,11 @@ static void __init free_dma_resources(void)
        free_unity_maps();
 }
 
+static void __init ivinfo_init(void *ivrs)
+{
+       amd_iommu_ivinfo = *((u32 *)(ivrs + IOMMU_IVINFO_OFFSET));
+}
+
 /*
  * This is the hardware init function for AMD IOMMU in the system.
  * This function is called either from amd_iommu_init or from the interrupt
@@ -2661,6 +2711,8 @@ static int __init early_amd_iommu_init(void)
        if (ret)
                goto out;
 
+       ivinfo_init(ivrs_base);
+
        amd_iommu_target_ivhd_type = get_highest_supported_ivhd_type(ivrs_base);
        DUMP_printk("Using IVHD type %#x\n", amd_iommu_target_ivhd_type);
 
index 004feae..02e7c10 100644 (file)
@@ -1496,7 +1496,7 @@ void qi_flush_dev_iotlb_pasid(struct intel_iommu *iommu, u16 sid, u16 pfsid,
         * Max Invs Pending (MIP) is set to 0 for now until we have DIT in
         * ECAP.
         */
-       if (addr & GENMASK_ULL(size_order + VTD_PAGE_SHIFT, 0))
+       if (!IS_ALIGNED(addr, VTD_PAGE_SIZE << size_order))
                pr_warn_ratelimited("Invalidate non-aligned address %llx, order %d\n",
                                    addr, size_order);
 
index f665322..06b00b5 100644 (file)
@@ -5440,6 +5440,36 @@ intel_iommu_domain_set_attr(struct iommu_domain *domain,
        return ret;
 }
 
+static bool domain_use_flush_queue(void)
+{
+       struct dmar_drhd_unit *drhd;
+       struct intel_iommu *iommu;
+       bool r = true;
+
+       if (intel_iommu_strict)
+               return false;
+
+       /*
+        * The flush queue implementation does not perform page-selective
+        * invalidations that are required for efficient TLB flushes in virtual
+        * environments. The benefit of batching is likely to be much lower than
+        * the overhead of synchronizing the virtual and physical IOMMU
+        * page-tables.
+        */
+       rcu_read_lock();
+       for_each_active_iommu(iommu, drhd) {
+               if (!cap_caching_mode(iommu->cap))
+                       continue;
+
+               pr_warn_once("IOMMU batching is disabled due to virtualization");
+               r = false;
+               break;
+       }
+       rcu_read_unlock();
+
+       return r;
+}
+
 static int
 intel_iommu_domain_get_attr(struct iommu_domain *domain,
                            enum iommu_attr attr, void *data)
@@ -5450,7 +5480,7 @@ intel_iommu_domain_get_attr(struct iommu_domain *domain,
        case IOMMU_DOMAIN_DMA:
                switch (attr) {
                case DOMAIN_ATTR_DMA_USE_FLUSH_QUEUE:
-                       *(int *)data = !intel_iommu_strict;
+                       *(int *)data = domain_use_flush_queue();
                        return 0;
                default:
                        return -ENODEV;
index 94920a5..b147f22 100644 (file)
@@ -493,8 +493,9 @@ config TI_SCI_INTA_IRQCHIP
          TI System Controller, say Y here. Otherwise, say N.
 
 config TI_PRUSS_INTC
-       tristate "TI PRU-ICSS Interrupt Controller"
-       depends on ARCH_DAVINCI || SOC_AM33XX || SOC_AM43XX || SOC_DRA7XX || ARCH_KEYSTONE || ARCH_K3
+       tristate
+       depends on TI_PRUSS
+       default TI_PRUSS
        select IRQ_DOMAIN
        help
          This enables support for the PRU-ICSS Local Interrupt Controller
index 5f5eb88..25c9a9c 100644 (file)
@@ -167,7 +167,7 @@ static void bcm2836_arm_irqchip_handle_ipi(struct irq_desc *desc)
        chained_irq_exit(chip, desc);
 }
 
-static void bcm2836_arm_irqchip_ipi_eoi(struct irq_data *d)
+static void bcm2836_arm_irqchip_ipi_ack(struct irq_data *d)
 {
        int cpu = smp_processor_id();
 
@@ -195,7 +195,7 @@ static struct irq_chip bcm2836_arm_irqchip_ipi = {
        .name           = "IPI",
        .irq_mask       = bcm2836_arm_irqchip_dummy_op,
        .irq_unmask     = bcm2836_arm_irqchip_dummy_op,
-       .irq_eoi        = bcm2836_arm_irqchip_ipi_eoi,
+       .irq_ack        = bcm2836_arm_irqchip_ipi_ack,
        .ipi_send_mask  = bcm2836_arm_irqchip_ipi_send_mask,
 };
 
index 9ed1bc4..09b91b8 100644 (file)
@@ -142,8 +142,8 @@ static void liointc_resume(struct irq_chip_generic *gc)
 
 static const char * const parent_names[] = {"int0", "int1", "int2", "int3"};
 
-int __init liointc_of_init(struct device_node *node,
-                               struct device_node *parent)
+static int __init liointc_of_init(struct device_node *node,
+                                 struct device_node *parent)
 {
        struct irq_chip_generic *gc;
        struct irq_domain *domain;
index 95d4fd8..0bbb0b2 100644 (file)
@@ -197,6 +197,13 @@ static int mips_cpu_ipi_alloc(struct irq_domain *domain, unsigned int virq,
                if (ret)
                        return ret;
 
+               ret = irq_domain_set_hwirq_and_chip(domain->parent, virq + i, hwirq,
+                                                   &mips_mt_cpu_irq_controller,
+                                                   NULL);
+
+               if (ret)
+                       return ret;
+
                ret = irq_set_irq_type(virq + i, IRQ_TYPE_LEVEL_HIGH);
                if (ret)
                        return ret;
index 0aa50d0..fbb3544 100644 (file)
@@ -66,7 +66,7 @@ static int sl28cpld_intc_probe(struct platform_device *pdev)
        irqchip->chip.num_regs = 1;
        irqchip->chip.status_base = base + INTC_IP;
        irqchip->chip.mask_base = base + INTC_IE;
-       irqchip->chip.mask_invert = true,
+       irqchip->chip.mask_invert = true;
        irqchip->chip.ack_base = base + INTC_IP;
 
        return devm_regmap_add_irq_chip_fwnode(dev, dev_fwnode(dev),
index 849d3c5..6c1d8b6 100644 (file)
@@ -928,6 +928,9 @@ config LEDS_ACER_A500
          This option enables support for the Power Button LED of
          Acer Iconia Tab A500.
 
+comment "Flash and Torch LED drivers"
+source "drivers/leds/flash/Kconfig"
+
 comment "LED Triggers"
 source "drivers/leds/trigger/Kconfig"
 
index 73e603e..156c0b4 100644 (file)
@@ -103,5 +103,8 @@ obj-$(CONFIG_LEDS_SPI_BYTE)         += leds-spi-byte.o
 # LED Userspace Drivers
 obj-$(CONFIG_LEDS_USER)                        += uleds.o
 
+# Flash and Torch LED Drivers
+obj-$(CONFIG_LEDS_CLASS_FLASH)         += flash/
+
 # LED Triggers
 obj-$(CONFIG_LEDS_TRIGGERS)            += trigger/
diff --git a/drivers/leds/flash/Kconfig b/drivers/leds/flash/Kconfig
new file mode 100644 (file)
index 0000000..d21d273
--- /dev/null
@@ -0,0 +1,15 @@
+# SPDX-License-Identifier: GPL-2.0
+
+if LEDS_CLASS_FLASH
+
+config LEDS_RT8515
+       tristate "LED support for Richtek RT8515 flash/torch LED"
+       depends on GPIOLIB
+       help
+         This option enables support for the Richtek RT8515 flash
+         and torch LEDs found on some mobile phones.
+
+         To compile this driver as a module, choose M here: the module
+         will be called leds-rt8515.
+
+endif # LEDS_CLASS_FLASH
diff --git a/drivers/leds/flash/Makefile b/drivers/leds/flash/Makefile
new file mode 100644 (file)
index 0000000..e990e25
--- /dev/null
@@ -0,0 +1,3 @@
+# SPDX-License-Identifier: GPL-2.0
+
+obj-$(CONFIG_LEDS_RT8515)      += leds-rt8515.o
diff --git a/drivers/leds/flash/leds-rt8515.c b/drivers/leds/flash/leds-rt8515.c
new file mode 100644 (file)
index 0000000..590bfa1
--- /dev/null
@@ -0,0 +1,397 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * LED driver for Richtek RT8515 flash/torch white LEDs
+ * found on some Samsung mobile phones.
+ *
+ * This is a 1.5A Boost dual channel driver produced around 2011.
+ *
+ * The component lacks a datasheet, but in the schematic picture
+ * from the LG P970 service manual you can see the connections
+ * from the RT8515 to the LED, with two resistors connected
+ * from the pins "RFS" and "RTS" to ground.
+ *
+ * On the LG P970:
+ * RFS (resistance flash setting?) is 20 kOhm
+ * RTS (resistance torch setting?) is 39 kOhm
+ *
+ * Some sleuthing finds us the RT9387A which we have a datasheet for:
+ * https://static5.arrow.com/pdfs/2014/7/27/8/21/12/794/rtt_/manual/94download_ds.jspprt9387a.jspprt9387a.pdf
+ * This apparently works the same way so in theory this driver
+ * should cover RT9387A as well. This has not been tested, please
+ * update the compatibles if you add RT9387A support.
+ *
+ * Linus Walleij <linus.walleij@linaro.org>
+ */
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/gpio/consumer.h>
+#include <linux/led-class-flash.h>
+#include <linux/mod_devicetable.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/property.h>
+#include <linux/regulator/consumer.h>
+
+#include <media/v4l2-flash-led-class.h>
+
+/* We can provide 15-700 mA out to the LED */
+#define RT8515_MIN_IOUT_MA     15
+#define RT8515_MAX_IOUT_MA     700
+/* The maximum intensity is 1-16 for flash and 1-100 for torch */
+#define RT8515_FLASH_MAX       16
+#define RT8515_TORCH_MAX       100
+
+#define RT8515_TIMEOUT_US      250000U
+#define RT8515_MAX_TIMEOUT_US  300000U
+
+struct rt8515 {
+       struct led_classdev_flash fled;
+       struct device *dev;
+       struct v4l2_flash *v4l2_flash;
+       struct mutex lock;
+       struct regulator *reg;
+       struct gpio_desc *enable_torch;
+       struct gpio_desc *enable_flash;
+       struct timer_list powerdown_timer;
+       u32 max_timeout; /* Flash max timeout */
+       int flash_max_intensity;
+       int torch_max_intensity;
+};
+
+static struct rt8515 *to_rt8515(struct led_classdev_flash *fled)
+{
+       return container_of(fled, struct rt8515, fled);
+}
+
+static void rt8515_gpio_led_off(struct rt8515 *rt)
+{
+       gpiod_set_value(rt->enable_flash, 0);
+       gpiod_set_value(rt->enable_torch, 0);
+}
+
+static void rt8515_gpio_brightness_commit(struct gpio_desc *gpiod,
+                                         int brightness)
+{
+       int i;
+
+       /*
+        * Toggling a GPIO line with a small delay increases the
+        * brightness one step at a time.
+        */
+       for (i = 0; i < brightness; i++) {
+               gpiod_set_value(gpiod, 0);
+               udelay(1);
+               gpiod_set_value(gpiod, 1);
+               udelay(1);
+       }
+}
+
+/* This is setting the torch light level */
+static int rt8515_led_brightness_set(struct led_classdev *led,
+                                    enum led_brightness brightness)
+{
+       struct led_classdev_flash *fled = lcdev_to_flcdev(led);
+       struct rt8515 *rt = to_rt8515(fled);
+
+       mutex_lock(&rt->lock);
+
+       if (brightness == LED_OFF) {
+               /* Off */
+               rt8515_gpio_led_off(rt);
+       } else if (brightness < RT8515_TORCH_MAX) {
+               /* Step it up to movie mode brightness using the flash pin */
+               rt8515_gpio_brightness_commit(rt->enable_torch, brightness);
+       } else {
+               /* Max torch brightness requested */
+               gpiod_set_value(rt->enable_torch, 1);
+       }
+
+       mutex_unlock(&rt->lock);
+
+       return 0;
+}
+
+static int rt8515_led_flash_strobe_set(struct led_classdev_flash *fled,
+                                      bool state)
+{
+       struct rt8515 *rt = to_rt8515(fled);
+       struct led_flash_setting *timeout = &fled->timeout;
+       int brightness = rt->flash_max_intensity;
+
+       mutex_lock(&rt->lock);
+
+       if (state) {
+               /* Enable LED flash mode and set brightness */
+               rt8515_gpio_brightness_commit(rt->enable_flash, brightness);
+               /* Set timeout */
+               mod_timer(&rt->powerdown_timer,
+                         jiffies + usecs_to_jiffies(timeout->val));
+       } else {
+               del_timer_sync(&rt->powerdown_timer);
+               /* Turn the LED off */
+               rt8515_gpio_led_off(rt);
+       }
+
+       fled->led_cdev.brightness = LED_OFF;
+       /* After this the torch LED will be disabled */
+
+       mutex_unlock(&rt->lock);
+
+       return 0;
+}
+
+static int rt8515_led_flash_strobe_get(struct led_classdev_flash *fled,
+                                      bool *state)
+{
+       struct rt8515 *rt = to_rt8515(fled);
+
+       *state = timer_pending(&rt->powerdown_timer);
+
+       return 0;
+}
+
+static int rt8515_led_flash_timeout_set(struct led_classdev_flash *fled,
+                                       u32 timeout)
+{
+       /* The timeout is stored in the led-class-flash core */
+       return 0;
+}
+
+static const struct led_flash_ops rt8515_flash_ops = {
+       .strobe_set = rt8515_led_flash_strobe_set,
+       .strobe_get = rt8515_led_flash_strobe_get,
+       .timeout_set = rt8515_led_flash_timeout_set,
+};
+
+static void rt8515_powerdown_timer(struct timer_list *t)
+{
+       struct rt8515 *rt = from_timer(rt, t, powerdown_timer);
+
+       /* Turn the LED off */
+       rt8515_gpio_led_off(rt);
+}
+
+static void rt8515_init_flash_timeout(struct rt8515 *rt)
+{
+       struct led_classdev_flash *fled = &rt->fled;
+       struct led_flash_setting *s;
+
+       /* Init flash timeout setting */
+       s = &fled->timeout;
+       s->min = 1;
+       s->max = rt->max_timeout;
+       s->step = 1;
+       /*
+        * Set default timeout to RT8515_TIMEOUT_US except if
+        * max_timeout from DT is lower.
+        */
+       s->val = min(rt->max_timeout, RT8515_TIMEOUT_US);
+}
+
+#if IS_ENABLED(CONFIG_V4L2_FLASH_LED_CLASS)
+/* Configure the V2L2 flash subdevice */
+static void rt8515_init_v4l2_flash_config(struct rt8515 *rt,
+                                         struct v4l2_flash_config *v4l2_sd_cfg)
+{
+       struct led_classdev *led = &rt->fled.led_cdev;
+       struct led_flash_setting *s;
+
+       strscpy(v4l2_sd_cfg->dev_name, led->dev->kobj.name,
+               sizeof(v4l2_sd_cfg->dev_name));
+
+       /*
+        * Init flash intensity setting: this is a linear scale
+        * capped from the device tree max intensity setting
+        * 1..flash_max_intensity
+        */
+       s = &v4l2_sd_cfg->intensity;
+       s->min = 1;
+       s->max = rt->flash_max_intensity;
+       s->step = 1;
+       s->val = s->max;
+}
+
+static void rt8515_v4l2_flash_release(struct rt8515 *rt)
+{
+       v4l2_flash_release(rt->v4l2_flash);
+}
+
+#else
+static void rt8515_init_v4l2_flash_config(struct rt8515 *rt,
+                                         struct v4l2_flash_config *v4l2_sd_cfg)
+{
+}
+
+static void rt8515_v4l2_flash_release(struct rt8515 *rt)
+{
+}
+#endif
+
+static void rt8515_determine_max_intensity(struct rt8515 *rt,
+                                          struct fwnode_handle *led,
+                                          const char *resistance,
+                                          const char *max_ua_prop, int hw_max,
+                                          int *max_intensity_setting)
+{
+       u32 res = 0; /* Can't be 0 so 0 is undefined */
+       u32 ua;
+       u32 max_ma;
+       int max_intensity;
+       int ret;
+
+       fwnode_property_read_u32(rt->dev->fwnode, resistance, &res);
+       ret = fwnode_property_read_u32(led, max_ua_prop, &ua);
+
+       /* Missing info in DT, OK go with hardware maxima */
+       if (ret || res == 0) {
+               dev_err(rt->dev,
+                       "either %s or %s missing from DT, using HW max\n",
+                       resistance, max_ua_prop);
+               max_ma = RT8515_MAX_IOUT_MA;
+               max_intensity = hw_max;
+               goto out_assign_max;
+       }
+
+       /*
+        * Formula from the datasheet, this is the maximum current
+        * defined by the hardware.
+        */
+       max_ma = (5500 * 1000) / res;
+       /*
+        * Calculate max intensity (linear scaling)
+        * Formula is ((ua / 1000) / max_ma) * 100, then simplified
+        */
+       max_intensity = (ua / 10) / max_ma;
+
+       dev_info(rt->dev,
+                "current restricted from %u to %u mA, max intensity %d/100\n",
+                max_ma, (ua / 1000), max_intensity);
+
+out_assign_max:
+       dev_info(rt->dev, "max intensity %d/%d = %d mA\n",
+                max_intensity, hw_max, max_ma);
+       *max_intensity_setting = max_intensity;
+}
+
+static int rt8515_probe(struct platform_device *pdev)
+{
+       struct device *dev = &pdev->dev;
+       struct fwnode_handle *child;
+       struct rt8515 *rt;
+       struct led_classdev *led;
+       struct led_classdev_flash *fled;
+       struct led_init_data init_data = {};
+       struct v4l2_flash_config v4l2_sd_cfg = {};
+       int ret;
+
+       rt = devm_kzalloc(dev, sizeof(*rt), GFP_KERNEL);
+       if (!rt)
+               return -ENOMEM;
+
+       rt->dev = dev;
+       fled = &rt->fled;
+       led = &fled->led_cdev;
+
+       /* ENF - Enable Flash line */
+       rt->enable_flash = devm_gpiod_get(dev, "enf", GPIOD_OUT_LOW);
+       if (IS_ERR(rt->enable_flash))
+               return dev_err_probe(dev, PTR_ERR(rt->enable_flash),
+                                    "cannot get ENF (enable flash) GPIO\n");
+
+       /* ENT - Enable Torch line */
+       rt->enable_torch = devm_gpiod_get(dev, "ent", GPIOD_OUT_LOW);
+       if (IS_ERR(rt->enable_torch))
+               return dev_err_probe(dev, PTR_ERR(rt->enable_torch),
+                                    "cannot get ENT (enable torch) GPIO\n");
+
+       child = fwnode_get_next_available_child_node(dev->fwnode, NULL);
+       if (!child) {
+               dev_err(dev,
+                       "No fwnode child node found for connected LED.\n");
+               return -EINVAL;
+       }
+       init_data.fwnode = child;
+
+       rt8515_determine_max_intensity(rt, child, "richtek,rfs-ohms",
+                                      "flash-max-microamp",
+                                      RT8515_FLASH_MAX,
+                                      &rt->flash_max_intensity);
+       rt8515_determine_max_intensity(rt, child, "richtek,rts-ohms",
+                                      "led-max-microamp",
+                                      RT8515_TORCH_MAX,
+                                      &rt->torch_max_intensity);
+
+       ret = fwnode_property_read_u32(child, "flash-max-timeout-us",
+                                      &rt->max_timeout);
+       if (ret) {
+               rt->max_timeout = RT8515_MAX_TIMEOUT_US;
+               dev_warn(dev,
+                        "flash-max-timeout-us property missing\n");
+       }
+       timer_setup(&rt->powerdown_timer, rt8515_powerdown_timer, 0);
+       rt8515_init_flash_timeout(rt);
+
+       fled->ops = &rt8515_flash_ops;
+
+       led->max_brightness = rt->torch_max_intensity;
+       led->brightness_set_blocking = rt8515_led_brightness_set;
+       led->flags |= LED_CORE_SUSPENDRESUME | LED_DEV_CAP_FLASH;
+
+       mutex_init(&rt->lock);
+
+       platform_set_drvdata(pdev, rt);
+
+       ret = devm_led_classdev_flash_register_ext(dev, fled, &init_data);
+       if (ret) {
+               dev_err(dev, "can't register LED %s\n", led->name);
+               mutex_destroy(&rt->lock);
+               return ret;
+       }
+
+       rt8515_init_v4l2_flash_config(rt, &v4l2_sd_cfg);
+
+       /* Create a V4L2 Flash device if V4L2 flash is enabled */
+       rt->v4l2_flash = v4l2_flash_init(dev, child, fled, NULL, &v4l2_sd_cfg);
+       if (IS_ERR(rt->v4l2_flash)) {
+               ret = PTR_ERR(rt->v4l2_flash);
+               dev_err(dev, "failed to register V4L2 flash device (%d)\n",
+                       ret);
+               /*
+                * Continue without the V4L2 flash
+                * (we still have the classdev)
+                */
+       }
+
+       return 0;
+}
+
+static int rt8515_remove(struct platform_device *pdev)
+{
+       struct rt8515 *rt = platform_get_drvdata(pdev);
+
+       rt8515_v4l2_flash_release(rt);
+       del_timer_sync(&rt->powerdown_timer);
+       mutex_destroy(&rt->lock);
+
+       return 0;
+}
+
+static const struct of_device_id rt8515_match[] = {
+       { .compatible = "richtek,rt8515", },
+       { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, rt8515_match);
+
+static struct platform_driver rt8515_driver = {
+       .driver = {
+               .name  = "rt8515",
+               .of_match_table = rt8515_match,
+       },
+       .probe  = rt8515_probe,
+       .remove = rt8515_remove,
+};
+module_platform_driver(rt8515_driver);
+
+MODULE_AUTHOR("Linus Walleij <linus.walleij@linaro.org>");
+MODULE_DESCRIPTION("Richtek RT8515 LED driver");
+MODULE_LICENSE("GPL");
index 91da90c..4e7b78a 100644 (file)
@@ -378,14 +378,15 @@ void led_trigger_event(struct led_trigger *trig,
                        enum led_brightness brightness)
 {
        struct led_classdev *led_cdev;
+       unsigned long flags;
 
        if (!trig)
                return;
 
-       read_lock(&trig->leddev_list_lock);
+       read_lock_irqsave(&trig->leddev_list_lock, flags);
        list_for_each_entry(led_cdev, &trig->led_cdevs, trig_list)
                led_set_brightness(led_cdev, brightness);
-       read_unlock(&trig->leddev_list_lock);
+       read_unlock_irqrestore(&trig->leddev_list_lock, flags);
 }
 EXPORT_SYMBOL_GPL(led_trigger_event);
 
@@ -396,11 +397,12 @@ static void led_trigger_blink_setup(struct led_trigger *trig,
                             int invert)
 {
        struct led_classdev *led_cdev;
+       unsigned long flags;
 
        if (!trig)
                return;
 
-       read_lock(&trig->leddev_list_lock);
+       read_lock_irqsave(&trig->leddev_list_lock, flags);
        list_for_each_entry(led_cdev, &trig->led_cdevs, trig_list) {
                if (oneshot)
                        led_blink_set_oneshot(led_cdev, delay_on, delay_off,
@@ -408,7 +410,7 @@ static void led_trigger_blink_setup(struct led_trigger *trig,
                else
                        led_blink_set(led_cdev, delay_on, delay_off);
        }
-       read_unlock(&trig->leddev_list_lock);
+       read_unlock_irqrestore(&trig->leddev_list_lock, flags);
 }
 
 void led_trigger_blink(struct led_trigger *trig,
index bb68ba2..49e1bdd 100644 (file)
@@ -96,14 +96,14 @@ static int ariel_led_probe(struct platform_device *pdev)
                return -ENOMEM;
 
        leds[0].ec_index = EC_BLUE_LED;
-       leds[0].led_cdev.name = "blue:power",
+       leds[0].led_cdev.name = "blue:power";
        leds[0].led_cdev.default_trigger = "default-on";
 
        leds[1].ec_index = EC_AMBER_LED;
-       leds[1].led_cdev.name = "amber:status",
+       leds[1].led_cdev.name = "amber:status";
 
        leds[2].ec_index = EC_GREEN_LED;
-       leds[2].led_cdev.name = "green:status",
+       leds[2].led_cdev.name = "green:status";
        leds[2].led_cdev.default_trigger = "default-on";
 
        for (i = 0; i < NLEDS; i++) {
index b3edee7..9dd2058 100644 (file)
@@ -679,7 +679,7 @@ static int lm3533_led_probe(struct platform_device *pdev)
        led->cdev.brightness_get = lm3533_led_get;
        led->cdev.blink_set = lm3533_led_blink_set;
        led->cdev.brightness = LED_OFF;
-       led->cdev.groups = lm3533_led_attribute_groups,
+       led->cdev.groups = lm3533_led_attribute_groups;
        led->id = pdev->id;
 
        mutex_init(&led->mutex);
index c1bcac7..28ddcaa 100644 (file)
@@ -844,11 +844,10 @@ static int nvm_bb_chunk_sense(struct nvm_dev *dev, struct ppa_addr ppa)
        rqd.ppa_addr = generic_to_dev_addr(dev, ppa);
 
        ret = nvm_submit_io_sync_raw(dev, &rqd);
+       __free_page(page);
        if (ret)
                return ret;
 
-       __free_page(page);
-
        return rqd.error;
 }
 
index 84fc2c0..d1c8fd3 100644 (file)
@@ -33,6 +33,8 @@
 #define BCH_FEATURE_COMPAT_FUNCS(name, flagname) \
 static inline int bch_has_feature_##name(struct cache_sb *sb) \
 { \
+       if (sb->version < BCACHE_SB_VERSION_CDEV_WITH_FEATURES) \
+               return 0; \
        return (((sb)->feature_compat & \
                BCH##_FEATURE_COMPAT_##flagname) != 0); \
 } \
@@ -50,6 +52,8 @@ static inline void bch_clear_feature_##name(struct cache_sb *sb) \
 #define BCH_FEATURE_RO_COMPAT_FUNCS(name, flagname) \
 static inline int bch_has_feature_##name(struct cache_sb *sb) \
 { \
+       if (sb->version < BCACHE_SB_VERSION_CDEV_WITH_FEATURES) \
+               return 0; \
        return (((sb)->feature_ro_compat & \
                BCH##_FEATURE_RO_COMPAT_##flagname) != 0); \
 } \
@@ -67,6 +71,8 @@ static inline void bch_clear_feature_##name(struct cache_sb *sb) \
 #define BCH_FEATURE_INCOMPAT_FUNCS(name, flagname) \
 static inline int bch_has_feature_##name(struct cache_sb *sb) \
 { \
+       if (sb->version < BCACHE_SB_VERSION_CDEV_WITH_FEATURES) \
+               return 0; \
        return (((sb)->feature_incompat & \
                BCH##_FEATURE_INCOMPAT_##flagname) != 0); \
 } \
index 8c87471..5a55617 100644 (file)
@@ -1481,9 +1481,9 @@ static int crypt_alloc_req_skcipher(struct crypt_config *cc,
 static int crypt_alloc_req_aead(struct crypt_config *cc,
                                 struct convert_context *ctx)
 {
-       if (!ctx->r.req) {
-               ctx->r.req = mempool_alloc(&cc->req_pool, in_interrupt() ? GFP_ATOMIC : GFP_NOIO);
-               if (!ctx->r.req)
+       if (!ctx->r.req_aead) {
+               ctx->r.req_aead = mempool_alloc(&cc->req_pool, in_interrupt() ? GFP_ATOMIC : GFP_NOIO);
+               if (!ctx->r.req_aead)
                        return -ENOMEM;
        }
 
index 81df019..b64fede 100644 (file)
@@ -257,8 +257,9 @@ struct dm_integrity_c {
        bool journal_uptodate;
        bool just_formatted;
        bool recalculate_flag;
-       bool fix_padding;
        bool discard;
+       bool fix_padding;
+       bool legacy_recalculate;
 
        struct alg_spec internal_hash_alg;
        struct alg_spec journal_crypt_alg;
@@ -386,6 +387,14 @@ static int dm_integrity_failed(struct dm_integrity_c *ic)
        return READ_ONCE(ic->failed);
 }
 
+static bool dm_integrity_disable_recalculate(struct dm_integrity_c *ic)
+{
+       if ((ic->internal_hash_alg.key || ic->journal_mac_alg.key) &&
+           !ic->legacy_recalculate)
+               return true;
+       return false;
+}
+
 static commit_id_t dm_integrity_commit_id(struct dm_integrity_c *ic, unsigned i,
                                          unsigned j, unsigned char seq)
 {
@@ -3140,6 +3149,7 @@ static void dm_integrity_status(struct dm_target *ti, status_type_t type,
                arg_count += !!ic->journal_crypt_alg.alg_string;
                arg_count += !!ic->journal_mac_alg.alg_string;
                arg_count += (ic->sb->flags & cpu_to_le32(SB_FLAG_FIXED_PADDING)) != 0;
+               arg_count += ic->legacy_recalculate;
                DMEMIT("%s %llu %u %c %u", ic->dev->name, ic->start,
                       ic->tag_size, ic->mode, arg_count);
                if (ic->meta_dev)
@@ -3163,6 +3173,8 @@ static void dm_integrity_status(struct dm_target *ti, status_type_t type,
                }
                if ((ic->sb->flags & cpu_to_le32(SB_FLAG_FIXED_PADDING)) != 0)
                        DMEMIT(" fix_padding");
+               if (ic->legacy_recalculate)
+                       DMEMIT(" legacy_recalculate");
 
 #define EMIT_ALG(a, n)                                                 \
                do {                                                    \
@@ -3792,7 +3804,7 @@ static int dm_integrity_ctr(struct dm_target *ti, unsigned argc, char **argv)
        unsigned extra_args;
        struct dm_arg_set as;
        static const struct dm_arg _args[] = {
-               {0, 15, "Invalid number of feature args"},
+               {0, 16, "Invalid number of feature args"},
        };
        unsigned journal_sectors, interleave_sectors, buffer_sectors, journal_watermark, sync_msec;
        bool should_write_sb;
@@ -3940,6 +3952,8 @@ static int dm_integrity_ctr(struct dm_target *ti, unsigned argc, char **argv)
                        ic->discard = true;
                } else if (!strcmp(opt_string, "fix_padding")) {
                        ic->fix_padding = true;
+               } else if (!strcmp(opt_string, "legacy_recalculate")) {
+                       ic->legacy_recalculate = true;
                } else {
                        r = -EINVAL;
                        ti->error = "Invalid argument";
@@ -4235,6 +4249,20 @@ try_smaller_buffer:
                        r = -ENOMEM;
                        goto bad;
                }
+       } else {
+               if (ic->sb->flags & cpu_to_le32(SB_FLAG_RECALCULATING)) {
+                       ti->error = "Recalculate can only be specified with internal_hash";
+                       r = -EINVAL;
+                       goto bad;
+               }
+       }
+
+       if (ic->sb->flags & cpu_to_le32(SB_FLAG_RECALCULATING) &&
+           le64_to_cpu(ic->sb->recalc_sector) < ic->provided_data_sectors &&
+           dm_integrity_disable_recalculate(ic)) {
+               ti->error = "Recalculating with HMAC is disabled for security reasons - if you really need it, use the argument \"legacy_recalculate\"";
+               r = -EOPNOTSUPP;
+               goto bad;
        }
 
        ic->bufio = dm_bufio_client_create(ic->meta_dev ? ic->meta_dev->bdev : ic->dev->bdev,
index 188f412..4acf234 100644 (file)
@@ -363,14 +363,23 @@ int dm_get_device(struct dm_target *ti, const char *path, fmode_t mode,
 {
        int r;
        dev_t dev;
+       unsigned int major, minor;
+       char dummy;
        struct dm_dev_internal *dd;
        struct dm_table *t = ti->table;
 
        BUG_ON(!t);
 
-       dev = dm_get_dev_t(path);
-       if (!dev)
-               return -ENODEV;
+       if (sscanf(path, "%u:%u%c", &major, &minor, &dummy) == 2) {
+               /* Extract the major/minor numbers */
+               dev = MKDEV(major, minor);
+               if (MAJOR(dev) != major || MINOR(dev) != minor)
+                       return -EOVERFLOW;
+       } else {
+               dev = dm_get_dev_t(path);
+               if (!dev)
+                       return -ENODEV;
+       }
 
        dd = find_device(&t->devices, dev);
        if (!dd) {
index ca40942..0438445 100644 (file)
@@ -639,8 +639,10 @@ static void md_submit_flush_data(struct work_struct *ws)
         * could wait for this and below md_handle_request could wait for those
         * bios because of suspend check
         */
+       spin_lock_irq(&mddev->lock);
        mddev->prev_flush_start = mddev->start_flush;
        mddev->flush_bio = NULL;
+       spin_unlock_irq(&mddev->lock);
        wake_up(&mddev->sb_wait);
 
        if (bio->bi_iter.bi_size == 0) {
index 3a94715..ea6f8ee 100644 (file)
@@ -10,5 +10,6 @@ obj-$(CONFIG_CEC_MESON_AO)    += meson/
 obj-$(CONFIG_CEC_SAMSUNG_S5P)  += s5p/
 obj-$(CONFIG_CEC_SECO)         += seco/
 obj-$(CONFIG_CEC_STI)          += sti/
+obj-$(CONFIG_CEC_STM32)                += stm32/
 obj-$(CONFIG_CEC_TEGRA)                += tegra/
 
index 96d3b2b..3f61f58 100644 (file)
@@ -118,8 +118,7 @@ static int __verify_length(struct vb2_buffer *vb, const struct v4l2_buffer *b)
                                return -EINVAL;
                }
        } else {
-               length = (b->memory == VB2_MEMORY_USERPTR ||
-                         b->memory == VB2_MEMORY_DMABUF)
+               length = (b->memory == VB2_MEMORY_USERPTR)
                        ? b->length : vb->planes[0].length;
 
                if (b->bytesused > length)
index eb7b6f0..58ca47e 100644 (file)
@@ -772,14 +772,8 @@ int ccs_pll_calculate(struct device *dev, const struct ccs_pll_limits *lim,
 
        switch (pll->bus_type) {
        case CCS_PLL_BUS_TYPE_CSI2_DPHY:
-               /* CSI transfers 2 bits per clock per lane; thus times 2 */
-               op_sys_clk_freq_hz_sdr = pll->link_freq * 2
-                       * (pll->flags & CCS_PLL_FLAG_LANE_SPEED_MODEL ?
-                          1 : pll->csi2.lanes);
-               break;
        case CCS_PLL_BUS_TYPE_CSI2_CPHY:
-               op_sys_clk_freq_hz_sdr =
-                       pll->link_freq
+               op_sys_clk_freq_hz_sdr = pll->link_freq * 2
                        * (pll->flags & CCS_PLL_FLAG_LANE_SPEED_MODEL ?
                           1 : pll->csi2.lanes);
                break;
index 9a6097b..6555bd4 100644 (file)
@@ -152,7 +152,7 @@ static int ccs_data_parse_version(struct bin_container *bin,
        vv->version_major = ((u16)v->static_data_version_major[0] << 8) +
                v->static_data_version_major[1];
        vv->version_minor = ((u16)v->static_data_version_minor[0] << 8) +
-               v->static_data_version_major[1];
+               v->static_data_version_minor[1];
        vv->date_year =  ((u16)v->year[0] << 8) + v->year[1];
        vv->date_month = v->month;
        vv->date_day = v->day;
index 36e354e..6cada8a 100644 (file)
@@ -302,7 +302,7 @@ static int cio2_csi2_calc_timing(struct cio2_device *cio2, struct cio2_queue *q,
        if (!q->sensor)
                return -ENODEV;
 
-       freq = v4l2_get_link_rate(q->sensor->ctrl_handler, bpp, lanes);
+       freq = v4l2_get_link_freq(q->sensor->ctrl_handler, bpp, lanes);
        if (freq < 0) {
                dev_err(dev, "error %lld, invalid link_freq\n", freq);
                return freq;
index bdd293f..7233a73 100644 (file)
@@ -349,8 +349,10 @@ static void venus_core_shutdown(struct platform_device *pdev)
 {
        struct venus_core *core = platform_get_drvdata(pdev);
 
+       pm_runtime_get_sync(core->dev);
        venus_shutdown(core);
        venus_firmware_deinit(core);
+       pm_runtime_put_sync(core->dev);
 }
 
 static __maybe_unused int venus_runtime_suspend(struct device *dev)
index 98bff76..e48d666 100644 (file)
@@ -654,7 +654,7 @@ static int rvin_parallel_parse_of(struct rvin_dev *vin)
 out:
        fwnode_handle_put(fwnode);
 
-       return 0;
+       return ret;
 }
 
 static int rvin_parallel_init(struct rvin_dev *vin)
index 68da1ee..f7e9fd3 100644 (file)
 struct rkisp1_match_data {
        const char * const *clks;
        unsigned int size;
+       enum rkisp1_cif_isp_version isp_ver;
 };
 
 /* ----------------------------------------------------------------------------
@@ -411,15 +412,16 @@ static const char * const rk3399_isp_clks[] = {
        "hclk",
 };
 
-static const struct rkisp1_match_data rk3399_isp_clk_data = {
+static const struct rkisp1_match_data rk3399_isp_match_data = {
        .clks = rk3399_isp_clks,
        .size = ARRAY_SIZE(rk3399_isp_clks),
+       .isp_ver = RKISP1_V10,
 };
 
 static const struct of_device_id rkisp1_of_match[] = {
        {
                .compatible = "rockchip,rk3399-cif-isp",
-               .data = &rk3399_isp_clk_data,
+               .data = &rk3399_isp_match_data,
        },
        {},
 };
@@ -457,15 +459,15 @@ static void rkisp1_debug_init(struct rkisp1_device *rkisp1)
 
 static int rkisp1_probe(struct platform_device *pdev)
 {
-       const struct rkisp1_match_data *clk_data;
+       const struct rkisp1_match_data *match_data;
        struct device *dev = &pdev->dev;
        struct rkisp1_device *rkisp1;
        struct v4l2_device *v4l2_dev;
        unsigned int i;
        int ret, irq;
 
-       clk_data = of_device_get_match_data(&pdev->dev);
-       if (!clk_data)
+       match_data = of_device_get_match_data(&pdev->dev);
+       if (!match_data)
                return -ENODEV;
 
        rkisp1 = devm_kzalloc(dev, sizeof(*rkisp1), GFP_KERNEL);
@@ -494,15 +496,16 @@ static int rkisp1_probe(struct platform_device *pdev)
 
        rkisp1->irq = irq;
 
-       for (i = 0; i < clk_data->size; i++)
-               rkisp1->clks[i].id = clk_data->clks[i];
-       ret = devm_clk_bulk_get(dev, clk_data->size, rkisp1->clks);
+       for (i = 0; i < match_data->size; i++)
+               rkisp1->clks[i].id = match_data->clks[i];
+       ret = devm_clk_bulk_get(dev, match_data->size, rkisp1->clks);
        if (ret)
                return ret;
-       rkisp1->clk_size = clk_data->size;
+       rkisp1->clk_size = match_data->size;
 
        pm_runtime_enable(&pdev->dev);
 
+       rkisp1->media_dev.hw_revision = match_data->isp_ver;
        strscpy(rkisp1->media_dev.model, RKISP1_DRIVER_NAME,
                sizeof(rkisp1->media_dev.model));
        rkisp1->media_dev.dev = &pdev->dev;
index 6af4d55..aa5f457 100644 (file)
@@ -391,7 +391,7 @@ static void rkisp1_goc_config(struct rkisp1_params *params,
                                RKISP1_CIF_ISP_CTRL_ISP_GAMMA_OUT_ENA);
        rkisp1_write(params->rkisp1, arg->mode, RKISP1_CIF_ISP_GAMMA_OUT_MODE);
 
-       for (i = 0; i < RKISP1_CIF_ISP_GAMMA_OUT_MAX_SAMPLES; i++)
+       for (i = 0; i < RKISP1_CIF_ISP_GAMMA_OUT_MAX_SAMPLES_V10; i++)
                rkisp1_write(params->rkisp1, arg->gamma_y[i],
                             RKISP1_CIF_ISP_GAMMA_OUT_Y_0 + i * 4);
 }
@@ -589,7 +589,6 @@ static void rkisp1_hst_config(struct rkisp1_params *params,
                RKISP1_CIF_ISP_HIST_WEIGHT_22TO03,
                RKISP1_CIF_ISP_HIST_WEIGHT_13TO43,
                RKISP1_CIF_ISP_HIST_WEIGHT_04TO34,
-               RKISP1_CIF_ISP_HIST_WEIGHT_44,
        };
        const u8 *weight;
        unsigned int i;
@@ -622,6 +621,8 @@ static void rkisp1_hst_config(struct rkisp1_params *params,
                                                            weight[2],
                                                            weight[3]),
                                 hist_weight_regs[i]);
+
+       rkisp1_write(params->rkisp1, weight[0] & 0x1F, RKISP1_CIF_ISP_HIST_WEIGHT_44);
 }
 
 static void
index 8a8d960..fa33080 100644 (file)
 #define RKISP1_CIF_ISP_MAX_HIST_PREDIVIDER             0x0000007F
 #define RKISP1_CIF_ISP_HIST_ROW_NUM                    5
 #define RKISP1_CIF_ISP_HIST_COLUMN_NUM                 5
+#define RKISP1_CIF_ISP_HIST_GET_BIN(x)                 ((x) & 0x000FFFFF)
 
 /* AUTO FOCUS MEASUREMENT:  ISP_AFM_CTRL */
 #define RKISP1_ISP_AFM_CTRL_ENABLE                     BIT(0)
index 3ddab8f..c1d07a2 100644 (file)
@@ -203,7 +203,7 @@ static void rkisp1_stats_get_aec_meas(struct rkisp1_stats *stats,
        unsigned int i;
 
        pbuf->meas_type |= RKISP1_CIF_ISP_STAT_AUTOEXP;
-       for (i = 0; i < RKISP1_CIF_ISP_AE_MEAN_MAX; i++)
+       for (i = 0; i < RKISP1_CIF_ISP_AE_MEAN_MAX_V10; i++)
                pbuf->params.ae.exp_mean[i] =
                        (u8)rkisp1_read(rkisp1,
                                        RKISP1_CIF_ISP_EXP_MEAN_00 + i * 4);
@@ -233,10 +233,11 @@ static void rkisp1_stats_get_hst_meas(struct rkisp1_stats *stats,
        unsigned int i;
 
        pbuf->meas_type |= RKISP1_CIF_ISP_STAT_HIST;
-       for (i = 0; i < RKISP1_CIF_ISP_HIST_BIN_N_MAX; i++)
-               pbuf->params.hist.hist_bins[i] =
-                       (u8)rkisp1_read(rkisp1,
-                                       RKISP1_CIF_ISP_HIST_BIN_0 + i * 4);
+       for (i = 0; i < RKISP1_CIF_ISP_HIST_BIN_N_MAX_V10; i++) {
+               u32 reg_val = rkisp1_read(rkisp1, RKISP1_CIF_ISP_HIST_BIN_0 + i * 4);
+
+               pbuf->params.hist.hist_bins[i] = RKISP1_CIF_ISP_HIST_GET_BIN(reg_val);
+       }
 }
 
 static void rkisp1_stats_get_bls_meas(struct rkisp1_stats *stats,
index be8f275..1524dc0 100644 (file)
@@ -320,7 +320,7 @@ again:
                                data->body);
                        spin_lock(&data->keylock);
                        if (scancode) {
-                               delay = nsecs_to_jiffies(dev->timeout) +
+                               delay = usecs_to_jiffies(dev->timeout) +
                                        msecs_to_jiffies(100);
                                mod_timer(&data->rx_timeout, jiffies + delay);
                        } else {
index a905113..0c62295 100644 (file)
@@ -1551,7 +1551,7 @@ static int ite_probe(struct pnp_dev *pdev, const struct pnp_device_id
        rdev->s_rx_carrier_range = ite_set_rx_carrier_range;
        /* FIFO threshold is 17 bytes, so 17 * 8 samples minimum */
        rdev->min_timeout = 17 * 8 * ITE_BAUDRATE_DIVISOR *
-                           itdev->params.sample_period;
+                           itdev->params.sample_period / 1000;
        rdev->timeout = IR_DEFAULT_TIMEOUT;
        rdev->max_timeout = 10 * IR_DEFAULT_TIMEOUT;
        rdev->rx_resolution = ITE_BAUDRATE_DIVISOR *
index 1d811e5..1fd62c1 100644 (file)
@@ -737,7 +737,7 @@ static unsigned int repeat_period(int protocol)
 void rc_repeat(struct rc_dev *dev)
 {
        unsigned long flags;
-       unsigned int timeout = nsecs_to_jiffies(dev->timeout) +
+       unsigned int timeout = usecs_to_jiffies(dev->timeout) +
                msecs_to_jiffies(repeat_period(dev->last_protocol));
        struct lirc_scancode sc = {
                .scancode = dev->last_scancode, .rc_proto = dev->last_protocol,
@@ -855,7 +855,7 @@ void rc_keydown(struct rc_dev *dev, enum rc_proto protocol, u64 scancode,
        ir_do_keydown(dev, protocol, scancode, keycode, toggle);
 
        if (dev->keypressed) {
-               dev->keyup_jiffies = jiffies + nsecs_to_jiffies(dev->timeout) +
+               dev->keyup_jiffies = jiffies + usecs_to_jiffies(dev->timeout) +
                        msecs_to_jiffies(repeat_period(protocol));
                mod_timer(&dev->timer_keyup, dev->keyup_jiffies);
        }
@@ -1928,6 +1928,8 @@ int rc_register_device(struct rc_dev *dev)
                        goto out_raw;
        }
 
+       dev->registered = true;
+
        rc = device_add(&dev->dev);
        if (rc)
                goto out_rx_free;
@@ -1937,8 +1939,6 @@ int rc_register_device(struct rc_dev *dev)
                 dev->device_name ?: "Unspecified device", path ?: "N/A");
        kfree(path);
 
-       dev->registered = true;
-
        /*
         * once the the input device is registered in rc_setup_rx_device,
         * userspace can open the input device and rc_open() will be called
index 8cc28c9..96ae029 100644 (file)
@@ -385,7 +385,7 @@ static irqreturn_t serial_ir_irq_handler(int i, void *blah)
        } while (!(sinp(UART_IIR) & UART_IIR_NO_INT)); /* still pending ? */
 
        mod_timer(&serial_ir.timeout_timer,
-                 jiffies + nsecs_to_jiffies(serial_ir.rcdev->timeout));
+                 jiffies + usecs_to_jiffies(serial_ir.rcdev->timeout));
 
        ir_raw_event_handle(serial_ir.rcdev);
 
index 78007db..133d20e 100644 (file)
@@ -442,7 +442,7 @@ int v4l2_fill_pixfmt(struct v4l2_pix_format *pixfmt, u32 pixelformat,
 }
 EXPORT_SYMBOL_GPL(v4l2_fill_pixfmt);
 
-s64 v4l2_get_link_rate(struct v4l2_ctrl_handler *handler, unsigned int mul,
+s64 v4l2_get_link_freq(struct v4l2_ctrl_handler *handler, unsigned int mul,
                       unsigned int div)
 {
        struct v4l2_ctrl *ctrl;
@@ -473,4 +473,4 @@ s64 v4l2_get_link_rate(struct v4l2_ctrl_handler *handler, unsigned int mul,
 
        return freq > 0 ? freq : -EINVAL;
 }
-EXPORT_SYMBOL_GPL(v4l2_get_link_rate);
+EXPORT_SYMBOL_GPL(v4l2_get_link_freq);
index 000cb82..75f1bc6 100644 (file)
@@ -797,17 +797,6 @@ const struct dev_pm_ops arizona_pm_ops = {
 EXPORT_SYMBOL_GPL(arizona_pm_ops);
 
 #ifdef CONFIG_OF
-unsigned long arizona_of_get_type(struct device *dev)
-{
-       const struct of_device_id *id = of_match_device(arizona_of_match, dev);
-
-       if (id)
-               return (unsigned long)id->data;
-       else
-               return 0;
-}
-EXPORT_SYMBOL_GPL(arizona_of_get_type);
-
 static int arizona_of_get_core_pdata(struct arizona *arizona)
 {
        struct arizona_pdata *pdata = &arizona->pdata;
index 4b58e3a..5e83b73 100644 (file)
 static int arizona_i2c_probe(struct i2c_client *i2c,
                             const struct i2c_device_id *id)
 {
+       const void *match_data;
        struct arizona *arizona;
        const struct regmap_config *regmap_config = NULL;
-       unsigned long type;
+       unsigned long type = 0;
        int ret;
 
-       if (i2c->dev.of_node)
-               type = arizona_of_get_type(&i2c->dev);
-       else
+       match_data = device_get_match_data(&i2c->dev);
+       if (match_data)
+               type = (unsigned long)match_data;
+       else if (id)
                type = id->driver_data;
 
        switch (type) {
@@ -115,6 +117,7 @@ static struct i2c_driver arizona_i2c_driver = {
 
 module_i2c_driver(arizona_i2c_driver);
 
+MODULE_SOFTDEP("pre: arizona_ldo1");
 MODULE_DESCRIPTION("Arizona I2C bus interface");
 MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>");
 MODULE_LICENSE("GPL");
index 2633e14..24a2c75 100644 (file)
@@ -7,7 +7,10 @@
  * Author: Mark Brown <broonie@opensource.wolfsonmicro.com>
  */
 
+#include <linux/acpi.h>
 #include <linux/err.h>
+#include <linux/gpio/consumer.h>
+#include <linux/gpio/machine.h>
 #include <linux/module.h>
 #include <linux/pm_runtime.h>
 #include <linux/regmap.h>
 #include <linux/slab.h>
 #include <linux/spi/spi.h>
 #include <linux/of.h>
+#include <uapi/linux/input-event-codes.h>
 
 #include <linux/mfd/arizona/core.h>
 
 #include "arizona.h"
 
+#ifdef CONFIG_ACPI
+const struct acpi_gpio_params reset_gpios = { 1, 0, false };
+const struct acpi_gpio_params ldoena_gpios = { 2, 0, false };
+
+static const struct acpi_gpio_mapping arizona_acpi_gpios[] = {
+       { "reset-gpios", &reset_gpios, 1, },
+       { "wlf,ldoena-gpios", &ldoena_gpios, 1 },
+       { }
+};
+
+/*
+ * The ACPI resources for the device only describe external GPIO-s. They do
+ * not provide mappings for the GPIO-s coming from the Arizona codec itself.
+ */
+static const struct gpiod_lookup arizona_soc_gpios[] = {
+       { "arizona", 2, "wlf,spkvdd-ena", 0, GPIO_ACTIVE_HIGH },
+       { "arizona", 4, "wlf,micd-pol", 0, GPIO_ACTIVE_LOW },
+};
+
+/*
+ * The AOSP 3.5 mm Headset: Accessory Specification gives the following values:
+ * Function A Play/Pause:           0 ohm
+ * Function D Voice assistant:    135 ohm
+ * Function B Volume Up           240 ohm
+ * Function C Volume Down         470 ohm
+ * Minimum Mic DC resistance     1000 ohm
+ * Minimum Ear speaker impedance   16 ohm
+ * Note the first max value below must be less then the min. speaker impedance,
+ * to allow CTIA/OMTP detection to work. The other max values are the closest
+ * value from extcon-arizona.c:arizona_micd_levels halfway 2 button resistances.
+ */
+static const struct arizona_micd_range arizona_micd_aosp_ranges[] = {
+       { .max =  11, .key = KEY_PLAYPAUSE },
+       { .max = 186, .key = KEY_VOICECOMMAND },
+       { .max = 348, .key = KEY_VOLUMEUP },
+       { .max = 752, .key = KEY_VOLUMEDOWN },
+};
+
+static void arizona_spi_acpi_remove_lookup(void *lookup)
+{
+       gpiod_remove_lookup_table(lookup);
+}
+
+static int arizona_spi_acpi_probe(struct arizona *arizona)
+{
+       struct gpiod_lookup_table *lookup;
+       acpi_status status;
+       int ret;
+
+       /* Add mappings for the 2 ACPI declared GPIOs used for reset and ldo-ena */
+       devm_acpi_dev_add_driver_gpios(arizona->dev, arizona_acpi_gpios);
+
+       /* Add lookups for the SoCs own GPIOs used for micdet-polarity and spkVDD-enable */
+       lookup = devm_kzalloc(arizona->dev,
+                             struct_size(lookup, table, ARRAY_SIZE(arizona_soc_gpios) + 1),
+                             GFP_KERNEL);
+       if (!lookup)
+               return -ENOMEM;
+
+       lookup->dev_id = dev_name(arizona->dev);
+       memcpy(lookup->table, arizona_soc_gpios, sizeof(arizona_soc_gpios));
+
+       gpiod_add_lookup_table(lookup);
+       ret = devm_add_action_or_reset(arizona->dev, arizona_spi_acpi_remove_lookup, lookup);
+       if (ret)
+               return ret;
+
+       /* Enable 32KHz clock from SoC to codec for jack-detect */
+       status = acpi_evaluate_object(ACPI_HANDLE(arizona->dev), "CLKE", NULL, NULL);
+       if (ACPI_FAILURE(status))
+               dev_warn(arizona->dev, "Failed to enable 32KHz clk ACPI error %d\n", status);
+
+       /*
+        * Some DSDTs wrongly declare the IRQ trigger-type as IRQF_TRIGGER_FALLING
+        * The IRQ line will stay low when a new IRQ event happens between reading
+        * the IRQ status flags and acknowledging them. When the IRQ line stays
+        * low like this the IRQ will never trigger again when its type is set
+        * to IRQF_TRIGGER_FALLING. Correct the IRQ trigger-type to fix this.
+        *
+        * Note theoretically it is possible that some boards are not capable
+        * of handling active low level interrupts. In that case setting the
+        * flag to IRQF_TRIGGER_FALLING would not be a bug (and we would need
+        * to work around this) but so far all known usages of IRQF_TRIGGER_FALLING
+        * are a bug in the board's DSDT.
+        */
+       arizona->pdata.irq_flags = IRQF_TRIGGER_LOW;
+
+       /* Wait 200 ms after jack insertion */
+       arizona->pdata.micd_detect_debounce = 200;
+
+       /* Use standard AOSP values for headset-button mappings */
+       arizona->pdata.micd_ranges = arizona_micd_aosp_ranges;
+       arizona->pdata.num_micd_ranges = ARRAY_SIZE(arizona_micd_aosp_ranges);
+
+       return 0;
+}
+
+static const struct acpi_device_id arizona_acpi_match[] = {
+       {
+               .id = "WM510204",
+               .driver_data = WM5102,
+       },
+       {
+               .id = "WM510205",
+               .driver_data = WM5102,
+       },
+       { }
+};
+MODULE_DEVICE_TABLE(acpi, arizona_acpi_match);
+#else
+static int arizona_spi_acpi_probe(struct arizona *arizona)
+{
+       return -ENODEV;
+}
+#endif
+
 static int arizona_spi_probe(struct spi_device *spi)
 {
        const struct spi_device_id *id = spi_get_device_id(spi);
+       const void *match_data;
        struct arizona *arizona;
        const struct regmap_config *regmap_config = NULL;
-       unsigned long type;
+       unsigned long type = 0;
        int ret;
 
-       if (spi->dev.of_node)
-               type = arizona_of_get_type(&spi->dev);
-       else
+       match_data = device_get_match_data(&spi->dev);
+       if (match_data)
+               type = (unsigned long)match_data;
+       else if (id)
                type = id->driver_data;
 
        switch (type) {
@@ -75,6 +197,12 @@ static int arizona_spi_probe(struct spi_device *spi)
        arizona->dev = &spi->dev;
        arizona->irq = spi->irq;
 
+       if (has_acpi_companion(&spi->dev)) {
+               ret = arizona_spi_acpi_probe(arizona);
+               if (ret)
+                       return ret;
+       }
+
        return arizona_dev_init(arizona);
 }
 
@@ -102,6 +230,7 @@ static struct spi_driver arizona_spi_driver = {
                .name   = "arizona",
                .pm     = &arizona_pm_ops,
                .of_match_table = of_match_ptr(arizona_of_match),
+               .acpi_match_table = ACPI_PTR(arizona_acpi_match),
        },
        .probe          = arizona_spi_probe,
        .remove         = arizona_spi_remove,
@@ -110,6 +239,7 @@ static struct spi_driver arizona_spi_driver = {
 
 module_spi_driver(arizona_spi_driver);
 
+MODULE_SOFTDEP("pre: arizona_ldo1");
 MODULE_DESCRIPTION("Arizona SPI bus interface");
 MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>");
 MODULE_LICENSE("GPL");
index 995efc6..801cbbc 100644 (file)
@@ -50,13 +50,4 @@ int arizona_dev_exit(struct arizona *arizona);
 int arizona_irq_init(struct arizona *arizona);
 int arizona_irq_exit(struct arizona *arizona);
 
-#ifdef CONFIG_OF
-unsigned long arizona_of_get_type(struct device *dev);
-#else
-static inline unsigned long arizona_of_get_type(struct device *dev)
-{
-       return 0;
-}
-#endif
-
 #endif
index 2aa6648..5a491d2 100644 (file)
@@ -1512,6 +1512,7 @@ static int rtsx_pci_probe(struct pci_dev *pcidev,
        struct pcr_handle *handle;
        u32 base, len;
        int ret, i, bar = 0;
+       u8 val;
 
        dev_dbg(&(pcidev->dev),
                ": Realtek PCI-E Card Reader found at %s [%04x:%04x] (rev %x)\n",
@@ -1577,7 +1578,11 @@ static int rtsx_pci_probe(struct pci_dev *pcidev,
        pcr->host_cmds_addr = pcr->rtsx_resv_buf_addr;
        pcr->host_sg_tbl_ptr = pcr->rtsx_resv_buf + HOST_CMDS_BUF_LEN;
        pcr->host_sg_tbl_addr = pcr->rtsx_resv_buf_addr + HOST_CMDS_BUF_LEN;
-
+       rtsx_pci_read_register(pcr, ASPM_FORCE_CTL, &val);
+       if (val & FORCE_ASPM_CTL0 && val & FORCE_ASPM_CTL1)
+               pcr->aspm_enabled = false;
+       else
+               pcr->aspm_enabled = true;
        pcr->card_inserted = 0;
        pcr->card_removed = 0;
        INIT_DELAYED_WORK(&pcr->carddet_work, rtsx_pci_card_detect);
index 1456eab..69d04ec 100644 (file)
@@ -1037,7 +1037,7 @@ kill_processes:
 
        if (hard_reset) {
                /* Release kernel context */
-               if (hl_ctx_put(hdev->kernel_ctx) == 1)
+               if (hdev->kernel_ctx && hl_ctx_put(hdev->kernel_ctx) == 1)
                        hdev->kernel_ctx = NULL;
                hl_vm_fini(hdev);
                hl_mmu_fini(hdev);
@@ -1487,6 +1487,15 @@ void hl_device_fini(struct hl_device *hdev)
                }
        }
 
+       /* Disable PCI access from device F/W so it won't send us additional
+        * interrupts. We disable MSI/MSI-X at the halt_engines function and we
+        * can't have the F/W sending us interrupts after that. We need to
+        * disable the access here because if the device is marked disable, the
+        * message won't be send. Also, in case of heartbeat, the device CPU is
+        * marked as disable so this message won't be sent
+        */
+       hl_fw_send_pci_access_msg(hdev, CPUCP_PACKET_DISABLE_PCI_ACCESS);
+
        /* Mark device as disabled */
        hdev->disabled = true;
 
index 20f77f5..c9a1298 100644 (file)
@@ -402,6 +402,10 @@ int hl_fw_cpucp_pci_counters_get(struct hl_device *hdev,
        }
        counters->rx_throughput = result;
 
+       memset(&pkt, 0, sizeof(pkt));
+       pkt.ctl = cpu_to_le32(CPUCP_PACKET_PCIE_THROUGHPUT_GET <<
+                       CPUCP_PKT_CTL_OPCODE_SHIFT);
+
        /* Fetch PCI tx counter */
        pkt.index = cpu_to_le32(cpucp_pcie_throughput_tx);
        rc = hdev->asic_funcs->send_cpu_message(hdev, (u32 *) &pkt, sizeof(pkt),
@@ -414,6 +418,7 @@ int hl_fw_cpucp_pci_counters_get(struct hl_device *hdev,
        counters->tx_throughput = result;
 
        /* Fetch PCI replay counter */
+       memset(&pkt, 0, sizeof(pkt));
        pkt.ctl = cpu_to_le32(CPUCP_PACKET_PCIE_REPLAY_CNT_GET <<
                        CPUCP_PKT_CTL_OPCODE_SHIFT);
 
index e0d7f5f..60e16dc 100644 (file)
@@ -2182,6 +2182,7 @@ void hl_mmu_v1_set_funcs(struct hl_device *hdev, struct hl_mmu_funcs *mmu);
 int hl_mmu_va_to_pa(struct hl_ctx *ctx, u64 virt_addr, u64 *phys_addr);
 int hl_mmu_get_tlb_info(struct hl_ctx *ctx, u64 virt_addr,
                        struct hl_mmu_hop_info *hops);
+bool hl_is_dram_va(struct hl_device *hdev, u64 virt_addr);
 
 int hl_fw_load_fw_to_device(struct hl_device *hdev, const char *fw_name,
                                void __iomem *dst, u32 src_offset, u32 size);
index 12efbd9..d25892d 100644 (file)
@@ -133,6 +133,8 @@ static int hw_idle(struct hl_device *hdev, struct hl_info_args *args)
 
        hw_idle.is_idle = hdev->asic_funcs->is_device_idle(hdev,
                                        &hw_idle.busy_engines_mask_ext, NULL);
+       hw_idle.busy_engines_mask =
+                       lower_32_bits(hw_idle.busy_engines_mask_ext);
 
        return copy_to_user(out, &hw_idle,
                min((size_t) max_size, sizeof(hw_idle))) ? -EFAULT : 0;
index cbe9da4..5d4fbdc 100644 (file)
@@ -886,8 +886,10 @@ static void unmap_phys_pg_pack(struct hl_ctx *ctx, u64 vaddr,
 {
        struct hl_device *hdev = ctx->hdev;
        u64 next_vaddr, i;
+       bool is_host_addr;
        u32 page_size;
 
+       is_host_addr = !hl_is_dram_va(hdev, vaddr);
        page_size = phys_pg_pack->page_size;
        next_vaddr = vaddr;
 
@@ -900,9 +902,13 @@ static void unmap_phys_pg_pack(struct hl_ctx *ctx, u64 vaddr,
                /*
                 * unmapping on Palladium can be really long, so avoid a CPU
                 * soft lockup bug by sleeping a little between unmapping pages
+                *
+                * In addition, when unmapping host memory we pass through
+                * the Linux kernel to unpin the pages and that takes a long
+                * time. Therefore, sleep every 32K pages to avoid soft lockup
                 */
-               if (hdev->pldm)
-                       usleep_range(500, 1000);
+               if (hdev->pldm || (is_host_addr && (i & 0x7FFF) == 0))
+                       usleep_range(50, 200);
        }
 }
 
index 33ae953..28a4638 100644 (file)
@@ -9,7 +9,7 @@
 
 #include "habanalabs.h"
 
-static bool is_dram_va(struct hl_device *hdev, u64 virt_addr)
+bool hl_is_dram_va(struct hl_device *hdev, u64 virt_addr)
 {
        struct asic_fixed_properties *prop = &hdev->asic_prop;
 
@@ -156,7 +156,7 @@ int hl_mmu_unmap_page(struct hl_ctx *ctx, u64 virt_addr, u32 page_size,
        if (!hdev->mmu_enable)
                return 0;
 
-       is_dram_addr = is_dram_va(hdev, virt_addr);
+       is_dram_addr = hl_is_dram_va(hdev, virt_addr);
 
        if (is_dram_addr)
                mmu_prop = &prop->dmmu;
@@ -236,7 +236,7 @@ int hl_mmu_map_page(struct hl_ctx *ctx, u64 virt_addr, u64 phys_addr,
        if (!hdev->mmu_enable)
                return 0;
 
-       is_dram_addr = is_dram_va(hdev, virt_addr);
+       is_dram_addr = hl_is_dram_va(hdev, virt_addr);
 
        if (is_dram_addr)
                mmu_prop = &prop->dmmu;
index 2ce6ea8..06d8a44 100644 (file)
@@ -467,8 +467,16 @@ static void hl_mmu_v1_fini(struct hl_device *hdev)
 {
        /* MMU H/W fini was already done in device hw_fini() */
 
-       kvfree(hdev->mmu_priv.dr.mmu_shadow_hop0);
-       gen_pool_destroy(hdev->mmu_priv.dr.mmu_pgt_pool);
+       if (!ZERO_OR_NULL_PTR(hdev->mmu_priv.hr.mmu_shadow_hop0)) {
+               kvfree(hdev->mmu_priv.dr.mmu_shadow_hop0);
+               gen_pool_destroy(hdev->mmu_priv.dr.mmu_pgt_pool);
+       }
+
+       /* Make sure that if we arrive here again without init was called we
+        * won't cause kernel panic. This can happen for example if we fail
+        * during hard reset code at certain points
+        */
+       hdev->mmu_priv.dr.mmu_shadow_hop0 = NULL;
 }
 
 /**
index 8c09e44..b328dda 100644 (file)
@@ -4002,7 +4002,8 @@ static int gaudi_cb_mmap(struct hl_device *hdev, struct vm_area_struct *vma,
        vma->vm_flags |= VM_IO | VM_PFNMAP | VM_DONTEXPAND | VM_DONTDUMP |
                        VM_DONTCOPY | VM_NORESERVE;
 
-       rc = dma_mmap_coherent(hdev->dev, vma, cpu_addr, dma_addr, size);
+       rc = dma_mmap_coherent(hdev->dev, vma, cpu_addr,
+                               (dma_addr - HOST_PHYS_BASE), size);
        if (rc)
                dev_err(hdev->dev, "dma_mmap_coherent error %d", rc);
 
index b8b4aa6..63679a7 100644 (file)
@@ -2719,7 +2719,8 @@ static int goya_cb_mmap(struct hl_device *hdev, struct vm_area_struct *vma,
        vma->vm_flags |= VM_IO | VM_PFNMAP | VM_DONTEXPAND | VM_DONTDUMP |
                        VM_DONTCOPY | VM_NORESERVE;
 
-       rc = dma_mmap_coherent(hdev->dev, vma, cpu_addr, dma_addr, size);
+       rc = dma_mmap_coherent(hdev->dev, vma, cpu_addr,
+                               (dma_addr - HOST_PHYS_BASE), size);
        if (rc)
                dev_err(hdev->dev, "dma_mmap_coherent error %d", rc);
 
index de7cb03..002426e 100644 (file)
@@ -384,8 +384,10 @@ static void mmc_setup_queue(struct mmc_queue *mq, struct mmc_card *card)
                     "merging was advertised but not possible");
        blk_queue_max_segments(mq->queue, mmc_get_max_segments(host));
 
-       if (mmc_card_mmc(card))
+       if (mmc_card_mmc(card) && card->ext_csd.data_sector_size) {
                block_size = card->ext_csd.data_sector_size;
+               WARN_ON(block_size != 512 && block_size != 4096);
+       }
 
        blk_queue_logical_block_size(mq->queue, block_size);
        /*
index 44bea5e..b237735 100644 (file)
@@ -20,6 +20,8 @@
 #include "sdio_cis.h"
 #include "sdio_ops.h"
 
+#define SDIO_READ_CIS_TIMEOUT_MS  (10 * 1000) /* 10s */
+
 static int cistpl_vers_1(struct mmc_card *card, struct sdio_func *func,
                         const unsigned char *buf, unsigned size)
 {
@@ -274,6 +276,8 @@ static int sdio_read_cis(struct mmc_card *card, struct sdio_func *func)
 
        do {
                unsigned char tpl_code, tpl_link;
+               unsigned long timeout = jiffies +
+                       msecs_to_jiffies(SDIO_READ_CIS_TIMEOUT_MS);
 
                ret = mmc_io_rw_direct(card, 0, 0, ptr++, 0, &tpl_code);
                if (ret)
@@ -326,6 +330,8 @@ static int sdio_read_cis(struct mmc_card *card, struct sdio_func *func)
                        prev = &this->next;
 
                        if (ret == -ENOENT) {
+                               if (time_after(jiffies, timeout))
+                                       break;
                                /* warn about unknown tuples */
                                pr_warn_ratelimited("%s: queuing unknown"
                                       " CIS tuple 0x%02x (%u bytes)\n",
index bbf3496..f9780c6 100644 (file)
@@ -314,11 +314,7 @@ err_clk:
 
 static void sdhci_brcmstb_shutdown(struct platform_device *pdev)
 {
-       int ret;
-
-       ret = sdhci_pltfm_unregister(pdev);
-       if (ret)
-               dev_err(&pdev->dev, "failed to shutdown\n");
+       sdhci_pltfm_suspend(&pdev->dev);
 }
 
 MODULE_DEVICE_TABLE(of, sdhci_brcm_of_match);
index 4b67379..d90020e 100644 (file)
@@ -16,6 +16,8 @@
 
 #include "sdhci-pltfm.h"
 
+#define SDHCI_DWCMSHC_ARG2_STUFF       GENMASK(31, 16)
+
 /* DWCMSHC specific Mode Select value */
 #define DWCMSHC_CTRL_HS400             0x7
 
@@ -49,6 +51,29 @@ static void dwcmshc_adma_write_desc(struct sdhci_host *host, void **desc,
        sdhci_adma_write_desc(host, desc, addr, len, cmd);
 }
 
+static void dwcmshc_check_auto_cmd23(struct mmc_host *mmc,
+                                    struct mmc_request *mrq)
+{
+       struct sdhci_host *host = mmc_priv(mmc);
+
+       /*
+        * No matter V4 is enabled or not, ARGUMENT2 register is 32-bit
+        * block count register which doesn't support stuff bits of
+        * CMD23 argument on dwcmsch host controller.
+        */
+       if (mrq->sbc && (mrq->sbc->arg & SDHCI_DWCMSHC_ARG2_STUFF))
+               host->flags &= ~SDHCI_AUTO_CMD23;
+       else
+               host->flags |= SDHCI_AUTO_CMD23;
+}
+
+static void dwcmshc_request(struct mmc_host *mmc, struct mmc_request *mrq)
+{
+       dwcmshc_check_auto_cmd23(mmc, mrq);
+
+       sdhci_request(mmc, mrq);
+}
+
 static void dwcmshc_set_uhs_signaling(struct sdhci_host *host,
                                      unsigned int timing)
 {
@@ -133,6 +158,8 @@ static int dwcmshc_probe(struct platform_device *pdev)
 
        sdhci_get_of_property(pdev);
 
+       host->mmc_host_ops.request = dwcmshc_request;
+
        err = sdhci_add_host(host);
        if (err)
                goto err_clk;
index 6301b81..9bd717f 100644 (file)
@@ -111,8 +111,13 @@ static inline void *sdhci_pltfm_priv(struct sdhci_pltfm_host *host)
        return host->private;
 }
 
+extern const struct dev_pm_ops sdhci_pltfm_pmops;
+#ifdef CONFIG_PM_SLEEP
 int sdhci_pltfm_suspend(struct device *dev);
 int sdhci_pltfm_resume(struct device *dev);
-extern const struct dev_pm_ops sdhci_pltfm_pmops;
+#else
+static inline int sdhci_pltfm_suspend(struct device *dev) { return 0; }
+static inline int sdhci_pltfm_resume(struct device *dev) { return 0; }
+#endif
 
 #endif /* _DRIVERS_MMC_SDHCI_PLTFM_H */
index c67611f..d19eef5 100644 (file)
@@ -168,7 +168,12 @@ static void xenon_reset_exit(struct sdhci_host *host,
        /* Disable tuning request and auto-retuning again */
        xenon_retune_setup(host);
 
-       xenon_set_acg(host, true);
+       /*
+        * The ACG should be turned off at the early init time, in order
+        * to solve a possible issues with the 1.8V regulator stabilization.
+        * The feature is enabled in later stage.
+        */
+       xenon_set_acg(host, false);
 
        xenon_set_sdclk_off_idle(host, sdhc_id, false);
 
index 5cdf05b..3fa8c22 100644 (file)
@@ -1615,7 +1615,7 @@ static int gpmi_ecc_read_page_raw(struct nand_chip *chip, uint8_t *buf,
        /* Extract interleaved payload data and ECC bits */
        for (step = 0; step < nfc_geo->ecc_chunk_count; step++) {
                if (buf)
-                       nand_extract_bits(buf, step * eccsize, tmp_buf,
+                       nand_extract_bits(buf, step * eccsize * 8, tmp_buf,
                                          src_bit_off, eccsize * 8);
                src_bit_off += eccsize * 8;
 
index fdb112e..a304fda 100644 (file)
@@ -579,7 +579,7 @@ static int ebu_nand_probe(struct platform_device *pdev)
        struct device *dev = &pdev->dev;
        struct ebu_nand_controller *ebu_host;
        struct nand_chip *nand;
-       struct mtd_info *mtd = NULL;
+       struct mtd_info *mtd;
        struct resource *res;
        char *resname;
        int ret;
@@ -647,12 +647,13 @@ static int ebu_nand_probe(struct platform_device *pdev)
               ebu_host->ebu + EBU_ADDR_SEL(cs));
 
        nand_set_flash_node(&ebu_host->chip, dev->of_node);
+
+       mtd = nand_to_mtd(&ebu_host->chip);
        if (!mtd->name) {
                dev_err(ebu_host->dev, "NAND label property is mandatory\n");
                return -EINVAL;
        }
 
-       mtd = nand_to_mtd(&ebu_host->chip);
        mtd->dev.parent = dev;
        ebu_host->dev = dev;
 
index f2b9250..0750121 100644 (file)
@@ -2210,6 +2210,9 @@ static int ns_attach_chip(struct nand_chip *chip)
 {
        unsigned int eccsteps, eccbytes;
 
+       chip->ecc.engine_type = NAND_ECC_ENGINE_TYPE_SOFT;
+       chip->ecc.algo = bch ? NAND_ECC_ALGO_BCH : NAND_ECC_ALGO_HAMMING;
+
        if (!bch)
                return 0;
 
@@ -2233,8 +2236,6 @@ static int ns_attach_chip(struct nand_chip *chip)
                return -EINVAL;
        }
 
-       chip->ecc.engine_type = NAND_ECC_ENGINE_TYPE_SOFT;
-       chip->ecc.algo = NAND_ECC_ALGO_BCH;
        chip->ecc.size = 512;
        chip->ecc.strength = bch;
        chip->ecc.bytes = eccbytes;
@@ -2273,8 +2274,6 @@ static int __init ns_init_module(void)
        nsmtd       = nand_to_mtd(chip);
        nand_set_controller_data(chip, (void *)ns);
 
-       chip->ecc.engine_type = NAND_ECC_ENGINE_TYPE_SOFT;
-       chip->ecc.algo   = NAND_ECC_ALGO_HAMMING;
        /* The NAND_SKIP_BBTSCAN option is necessary for 'overridesize' */
        /* and 'badblocks' parameters to work */
        chip->options   |= NAND_SKIP_BBTSCAN;
index fbb9955..2c3e65c 100644 (file)
@@ -15,6 +15,7 @@
 #include <linux/jiffies.h>
 #include <linux/sched.h>
 #include <linux/mtd/mtd.h>
+#include <linux/mtd/nand-ecc-sw-bch.h>
 #include <linux/mtd/rawnand.h>
 #include <linux/mtd/partitions.h>
 #include <linux/omap-dma.h>
@@ -1866,18 +1867,19 @@ static const struct mtd_ooblayout_ops omap_ooblayout_ops = {
 static int omap_sw_ooblayout_ecc(struct mtd_info *mtd, int section,
                                 struct mtd_oob_region *oobregion)
 {
-       struct nand_chip *chip = mtd_to_nand(mtd);
+       struct nand_device *nand = mtd_to_nanddev(mtd);
+       const struct nand_ecc_sw_bch_conf *engine_conf = nand->ecc.ctx.priv;
        int off = BADBLOCK_MARKER_LENGTH;
 
-       if (section >= chip->ecc.steps)
+       if (section >= engine_conf->nsteps)
                return -ERANGE;
 
        /*
         * When SW correction is employed, one OMAP specific marker byte is
         * reserved after each ECC step.
         */
-       oobregion->offset = off + (section * (chip->ecc.bytes + 1));
-       oobregion->length = chip->ecc.bytes;
+       oobregion->offset = off + (section * (engine_conf->code_size + 1));
+       oobregion->length = engine_conf->code_size;
 
        return 0;
 }
@@ -1885,7 +1887,8 @@ static int omap_sw_ooblayout_ecc(struct mtd_info *mtd, int section,
 static int omap_sw_ooblayout_free(struct mtd_info *mtd, int section,
                                  struct mtd_oob_region *oobregion)
 {
-       struct nand_chip *chip = mtd_to_nand(mtd);
+       struct nand_device *nand = mtd_to_nanddev(mtd);
+       const struct nand_ecc_sw_bch_conf *engine_conf = nand->ecc.ctx.priv;
        int off = BADBLOCK_MARKER_LENGTH;
 
        if (section)
@@ -1895,7 +1898,7 @@ static int omap_sw_ooblayout_free(struct mtd_info *mtd, int section,
         * When SW correction is employed, one OMAP specific marker byte is
         * reserved after each ECC step.
         */
-       off += ((chip->ecc.bytes + 1) * chip->ecc.steps);
+       off += ((engine_conf->code_size + 1) * engine_conf->nsteps);
        if (off >= mtd->oobsize)
                return -ERANGE;
 
index 8ea545b..61d932c 100644 (file)
@@ -343,6 +343,7 @@ static int spinand_read_from_cache_op(struct spinand_device *spinand,
                                      const struct nand_page_io_req *req)
 {
        struct nand_device *nand = spinand_to_nand(spinand);
+       struct mtd_info *mtd = spinand_to_mtd(spinand);
        struct spi_mem_dirmap_desc *rdesc;
        unsigned int nbytes = 0;
        void *buf = NULL;
@@ -382,9 +383,16 @@ static int spinand_read_from_cache_op(struct spinand_device *spinand,
                memcpy(req->databuf.in, spinand->databuf + req->dataoffs,
                       req->datalen);
 
-       if (req->ooblen)
-               memcpy(req->oobbuf.in, spinand->oobbuf + req->ooboffs,
-                      req->ooblen);
+       if (req->ooblen) {
+               if (req->mode == MTD_OPS_AUTO_OOB)
+                       mtd_ooblayout_get_databytes(mtd, req->oobbuf.in,
+                                                   spinand->oobbuf,
+                                                   req->ooboffs,
+                                                   req->ooblen);
+               else
+                       memcpy(req->oobbuf.in, spinand->oobbuf + req->ooboffs,
+                              req->ooblen);
+       }
 
        return 0;
 }
index 98df38f..12d0854 100644 (file)
@@ -332,7 +332,7 @@ static int __init arc_rimi_init(void)
                dev->irq = 9;
 
        if (arcrimi_probe(dev)) {
-               free_netdev(dev);
+               free_arcdev(dev);
                return -EIO;
        }
 
@@ -349,7 +349,7 @@ static void __exit arc_rimi_exit(void)
        iounmap(lp->mem_start);
        release_mem_region(dev->mem_start, dev->mem_end - dev->mem_start + 1);
        free_irq(dev->irq, dev);
-       free_netdev(dev);
+       free_arcdev(dev);
 }
 
 #ifndef MODULE
index 22a49c6..5d4a4c7 100644 (file)
@@ -298,6 +298,10 @@ struct arcnet_local {
 
        int excnak_pending;    /* We just got an excesive nak interrupt */
 
+       /* RESET flag handling */
+       int reset_in_progress;
+       struct work_struct reset_work;
+
        struct {
                uint16_t sequence;      /* sequence number (incs with each packet) */
                __be16 aborted_seq;
@@ -350,7 +354,9 @@ void arcnet_dump_skb(struct net_device *dev, struct sk_buff *skb, char *desc)
 
 void arcnet_unregister_proto(struct ArcProto *proto);
 irqreturn_t arcnet_interrupt(int irq, void *dev_id);
+
 struct net_device *alloc_arcdev(const char *name);
+void free_arcdev(struct net_device *dev);
 
 int arcnet_open(struct net_device *dev);
 int arcnet_close(struct net_device *dev);
index e04efc0..d76dd7d 100644 (file)
@@ -387,10 +387,44 @@ static void arcnet_timer(struct timer_list *t)
        struct arcnet_local *lp = from_timer(lp, t, timer);
        struct net_device *dev = lp->dev;
 
-       if (!netif_carrier_ok(dev)) {
+       spin_lock_irq(&lp->lock);
+
+       if (!lp->reset_in_progress && !netif_carrier_ok(dev)) {
                netif_carrier_on(dev);
                netdev_info(dev, "link up\n");
        }
+
+       spin_unlock_irq(&lp->lock);
+}
+
+static void reset_device_work(struct work_struct *work)
+{
+       struct arcnet_local *lp;
+       struct net_device *dev;
+
+       lp = container_of(work, struct arcnet_local, reset_work);
+       dev = lp->dev;
+
+       /* Do not bring the network interface back up if an ifdown
+        * was already done.
+        */
+       if (!netif_running(dev) || !lp->reset_in_progress)
+               return;
+
+       rtnl_lock();
+
+       /* Do another check, in case of an ifdown that was triggered in
+        * the small race window between the exit condition above and
+        * acquiring RTNL.
+        */
+       if (!netif_running(dev) || !lp->reset_in_progress)
+               goto out;
+
+       dev_close(dev);
+       dev_open(dev, NULL);
+
+out:
+       rtnl_unlock();
 }
 
 static void arcnet_reply_tasklet(unsigned long data)
@@ -452,12 +486,25 @@ struct net_device *alloc_arcdev(const char *name)
                lp->dev = dev;
                spin_lock_init(&lp->lock);
                timer_setup(&lp->timer, arcnet_timer, 0);
+               INIT_WORK(&lp->reset_work, reset_device_work);
        }
 
        return dev;
 }
 EXPORT_SYMBOL(alloc_arcdev);
 
+void free_arcdev(struct net_device *dev)
+{
+       struct arcnet_local *lp = netdev_priv(dev);
+
+       /* Do not cancel this at ->ndo_close(), as the workqueue itself
+        * indirectly calls the ifdown path through dev_close().
+        */
+       cancel_work_sync(&lp->reset_work);
+       free_netdev(dev);
+}
+EXPORT_SYMBOL(free_arcdev);
+
 /* Open/initialize the board.  This is called sometime after booting when
  * the 'ifconfig' program is run.
  *
@@ -587,6 +634,10 @@ int arcnet_close(struct net_device *dev)
 
        /* shut down the card */
        lp->hw.close(dev);
+
+       /* reset counters */
+       lp->reset_in_progress = 0;
+
        module_put(lp->hw.owner);
        return 0;
 }
@@ -820,6 +871,9 @@ irqreturn_t arcnet_interrupt(int irq, void *dev_id)
 
        spin_lock_irqsave(&lp->lock, flags);
 
+       if (lp->reset_in_progress)
+               goto out;
+
        /* RESET flag was enabled - if device is not running, we must
         * clear it right away (but nothing else).
         */
@@ -852,11 +906,14 @@ irqreturn_t arcnet_interrupt(int irq, void *dev_id)
                if (status & RESETflag) {
                        arc_printk(D_NORMAL, dev, "spurious reset (status=%Xh)\n",
                                   status);
-                       arcnet_close(dev);
-                       arcnet_open(dev);
+
+                       lp->reset_in_progress = 1;
+                       netif_stop_queue(dev);
+                       netif_carrier_off(dev);
+                       schedule_work(&lp->reset_work);
 
                        /* get out of the interrupt handler! */
-                       break;
+                       goto out;
                }
                /* RX is inhibited - we must have received something.
                 * Prepare to receive into the next buffer.
@@ -1052,6 +1109,7 @@ irqreturn_t arcnet_interrupt(int irq, void *dev_id)
        udelay(1);
        lp->hw.intmask(dev, lp->intmask);
 
+out:
        spin_unlock_irqrestore(&lp->lock, flags);
        return retval;
 }
index f983c4c..be618e4 100644 (file)
@@ -169,7 +169,7 @@ static int __init com20020_init(void)
                dev->irq = 9;
 
        if (com20020isa_probe(dev)) {
-               free_netdev(dev);
+               free_arcdev(dev);
                return -EIO;
        }
 
@@ -182,7 +182,7 @@ static void __exit com20020_exit(void)
        unregister_netdev(my_dev);
        free_irq(my_dev->irq, my_dev);
        release_region(my_dev->base_addr, ARCNET_TOTAL_SIZE);
-       free_netdev(my_dev);
+       free_arcdev(my_dev);
 }
 
 #ifndef MODULE
index eb7f767..8bdc44b 100644 (file)
@@ -291,7 +291,7 @@ static void com20020pci_remove(struct pci_dev *pdev)
 
                unregister_netdev(dev);
                free_irq(dev->irq, dev);
-               free_netdev(dev);
+               free_arcdev(dev);
        }
 }
 
index cf607ff..9cc5eb6 100644 (file)
@@ -177,7 +177,7 @@ static void com20020_detach(struct pcmcia_device *link)
                dev = info->dev;
                if (dev) {
                        dev_dbg(&link->dev, "kfree...\n");
-                       free_netdev(dev);
+                       free_arcdev(dev);
                }
                dev_dbg(&link->dev, "kfree2...\n");
                kfree(info);
index cf214b7..3856b44 100644 (file)
@@ -396,7 +396,7 @@ static int __init com90io_init(void)
        err = com90io_probe(dev);
 
        if (err) {
-               free_netdev(dev);
+               free_arcdev(dev);
                return err;
        }
 
@@ -419,7 +419,7 @@ static void __exit com90io_exit(void)
 
        free_irq(dev->irq, dev);
        release_region(dev->base_addr, ARCNET_TOTAL_SIZE);
-       free_netdev(dev);
+       free_arcdev(dev);
 }
 
 module_init(com90io_init)
index 3dc3d53..d8dfb9e 100644 (file)
@@ -554,7 +554,7 @@ err_free_irq:
 err_release_mem:
        release_mem_region(dev->mem_start, dev->mem_end - dev->mem_start + 1);
 err_free_dev:
-       free_netdev(dev);
+       free_arcdev(dev);
        return -EIO;
 }
 
@@ -672,7 +672,7 @@ static void __exit com90xx_exit(void)
                release_region(dev->base_addr, ARCNET_TOTAL_SIZE);
                release_mem_region(dev->mem_start,
                                   dev->mem_end - dev->mem_start + 1);
-               free_netdev(dev);
+               free_arcdev(dev);
        }
 }
 
index 3486704..c73e2a6 100644 (file)
@@ -592,11 +592,11 @@ static void can_restart(struct net_device *dev)
 
        cf->can_id |= CAN_ERR_RESTARTED;
 
-       netif_rx_ni(skb);
-
        stats->rx_packets++;
        stats->rx_bytes += cf->len;
 
+       netif_rx_ni(skb);
+
 restart:
        netdev_dbg(dev, "restarted\n");
        priv->can_stats.restarts++;
@@ -1163,7 +1163,7 @@ static int can_fill_info(struct sk_buff *skb, const struct net_device *dev)
 {
        struct can_priv *priv = netdev_priv(dev);
        struct can_ctrlmode cm = {.flags = priv->ctrlmode};
-       struct can_berr_counter bec;
+       struct can_berr_counter bec = { };
        enum can_state state = priv->state;
 
        if (priv->do_get_state)
index 61631f4..f347ecc 100644 (file)
@@ -514,11 +514,11 @@ static int pcan_usb_fd_decode_canmsg(struct pcan_usb_fd_if *usb_if,
        else
                memcpy(cfd->data, rm->d, cfd->len);
 
-       peak_usb_netif_rx(skb, &usb_if->time_ref, le32_to_cpu(rm->ts_low));
-
        netdev->stats.rx_packets++;
        netdev->stats.rx_bytes += cfd->len;
 
+       peak_usb_netif_rx(skb, &usb_if->time_ref, le32_to_cpu(rm->ts_low));
+
        return 0;
 }
 
@@ -580,11 +580,11 @@ static int pcan_usb_fd_decode_status(struct pcan_usb_fd_if *usb_if,
        if (!skb)
                return -ENOMEM;
 
-       peak_usb_netif_rx(skb, &usb_if->time_ref, le32_to_cpu(sm->ts_low));
-
        netdev->stats.rx_packets++;
        netdev->stats.rx_bytes += cf->len;
 
+       peak_usb_netif_rx(skb, &usb_if->time_ref, le32_to_cpu(sm->ts_low));
+
        return 0;
 }
 
index fa47bab..f9a524c 100644 (file)
@@ -39,6 +39,7 @@ static netdev_tx_t vxcan_xmit(struct sk_buff *skb, struct net_device *dev)
        struct net_device *peer;
        struct canfd_frame *cfd = (struct canfd_frame *)skb->data;
        struct net_device_stats *peerstats, *srcstats = &dev->stats;
+       u8 len;
 
        if (can_dropped_invalid_skb(dev, skb))
                return NETDEV_TX_OK;
@@ -61,12 +62,13 @@ static netdev_tx_t vxcan_xmit(struct sk_buff *skb, struct net_device *dev)
        skb->dev        = peer;
        skb->ip_summed  = CHECKSUM_UNNECESSARY;
 
+       len = cfd->len;
        if (netif_rx_ni(skb) == NET_RX_SUCCESS) {
                srcstats->tx_packets++;
-               srcstats->tx_bytes += cfd->len;
+               srcstats->tx_bytes += len;
                peerstats = &peer->stats;
                peerstats->rx_packets++;
-               peerstats->rx_bytes += cfd->len;
+               peerstats->rx_bytes += len;
        }
 
 out_unlock:
index 288b5a5..95c7fa1 100644 (file)
@@ -1404,7 +1404,7 @@ int b53_vlan_prepare(struct dsa_switch *ds, int port,
            !(vlan->flags & BRIDGE_VLAN_INFO_UNTAGGED))
                return -EINVAL;
 
-       if (vlan->vid_end > dev->num_vlans)
+       if (vlan->vid_end >= dev->num_vlans)
                return -ERANGE;
 
        b53_enable_vlan(dev, true, ds->vlan_filtering);
index 1e9a0ad..4452267 100644 (file)
@@ -509,15 +509,19 @@ static int bcm_sf2_mdio_register(struct dsa_switch *ds)
        /* Find our integrated MDIO bus node */
        dn = of_find_compatible_node(NULL, NULL, "brcm,unimac-mdio");
        priv->master_mii_bus = of_mdio_find_bus(dn);
-       if (!priv->master_mii_bus)
+       if (!priv->master_mii_bus) {
+               of_node_put(dn);
                return -EPROBE_DEFER;
+       }
 
        get_device(&priv->master_mii_bus->dev);
        priv->master_mii_dn = dn;
 
        priv->slave_mii_bus = devm_mdiobus_alloc(ds->dev);
-       if (!priv->slave_mii_bus)
+       if (!priv->slave_mii_bus) {
+               of_node_put(dn);
                return -ENOMEM;
+       }
 
        priv->slave_mii_bus->priv = priv;
        priv->slave_mii_bus->name = "sf2 slave mii";
index c973db1..a4570ba 100644 (file)
@@ -1187,6 +1187,20 @@ static const struct ksz_chip_data ksz8795_switch_chips[] = {
                .port_cnt = 5,          /* total cpu and user ports */
        },
        {
+               /*
+                * WARNING
+                * =======
+                * KSZ8794 is similar to KSZ8795, except the port map
+                * contains a gap between external and CPU ports, the
+                * port map is NOT continuous. The per-port register
+                * map is shifted accordingly too, i.e. registers at
+                * offset 0x40 are NOT used on KSZ8794 and they ARE
+                * used on KSZ8795 for external port 3.
+                *           external  cpu
+                * KSZ8794   0,1,2      4
+                * KSZ8795   0,1,2,3    4
+                * KSZ8765   0,1,2,3    4
+                */
                .chip_id = 0x8794,
                .dev_name = "KSZ8794",
                .num_vlans = 4096,
@@ -1220,9 +1234,13 @@ static int ksz8795_switch_init(struct ksz_device *dev)
                        dev->num_vlans = chip->num_vlans;
                        dev->num_alus = chip->num_alus;
                        dev->num_statics = chip->num_statics;
-                       dev->port_cnt = chip->port_cnt;
+                       dev->port_cnt = fls(chip->cpu_ports);
+                       dev->cpu_port = fls(chip->cpu_ports) - 1;
+                       dev->phy_port_cnt = dev->port_cnt - 1;
                        dev->cpu_ports = chip->cpu_ports;
-
+                       dev->host_mask = chip->cpu_ports;
+                       dev->port_mask = (BIT(dev->phy_port_cnt) - 1) |
+                                        chip->cpu_ports;
                        break;
                }
        }
@@ -1231,17 +1249,9 @@ static int ksz8795_switch_init(struct ksz_device *dev)
        if (!dev->cpu_ports)
                return -ENODEV;
 
-       dev->port_mask = BIT(dev->port_cnt) - 1;
-       dev->port_mask |= dev->host_mask;
-
        dev->reg_mib_cnt = KSZ8795_COUNTER_NUM;
        dev->mib_cnt = ARRAY_SIZE(mib_names);
 
-       dev->phy_port_cnt = dev->port_cnt - 1;
-
-       dev->cpu_port = dev->port_cnt - 1;
-       dev->host_mask = BIT(dev->cpu_port);
-
        dev->ports = devm_kzalloc(dev->dev,
                                  dev->port_cnt * sizeof(struct ksz_port),
                                  GFP_KERNEL);
index cf74313..389abfd 100644 (file)
@@ -400,7 +400,7 @@ int ksz_switch_register(struct ksz_device *dev,
                gpiod_set_value_cansleep(dev->reset_gpio, 1);
                usleep_range(10000, 12000);
                gpiod_set_value_cansleep(dev->reset_gpio, 0);
-               usleep_range(100, 1000);
+               msleep(100);
        }
 
        mutex_init(&dev->dev_mutex);
@@ -434,7 +434,7 @@ int ksz_switch_register(struct ksz_device *dev,
                                if (of_property_read_u32(port, "reg",
                                                         &port_num))
                                        continue;
-                               if (port_num >= dev->port_cnt)
+                               if (!(dev->port_mask & BIT(port_num)))
                                        return -EINVAL;
                                of_get_phy_mode(port,
                                                &dev->ports[port_num].interface);
index eafe6be..54aa942 100644 (file)
@@ -1676,7 +1676,11 @@ static int mv88e6xxx_port_db_load_purge(struct mv88e6xxx_chip *chip, int port,
                if (!entry.portvec)
                        entry.state = 0;
        } else {
-               entry.portvec |= BIT(port);
+               if (state == MV88E6XXX_G1_ATU_DATA_STATE_UC_STATIC)
+                       entry.portvec = BIT(port);
+               else
+                       entry.portvec |= BIT(port);
+
                entry.state = state;
        }
 
index 66ddf67..7b96396 100644 (file)
@@ -351,6 +351,10 @@ int mv88e6250_g1_vtu_getnext(struct mv88e6xxx_chip *chip,
                if (err)
                        return err;
 
+               err = mv88e6185_g1_stu_data_read(chip, entry);
+               if (err)
+                       return err;
+
                /* VTU DBNum[3:0] are located in VTU Operation 3:0
                 * VTU DBNum[5:4] are located in VTU Operation 9:8
                 */
index b1ae9eb..0404aaf 100644 (file)
@@ -2503,8 +2503,10 @@ static int bcm_sysport_probe(struct platform_device *pdev)
        priv = netdev_priv(dev);
 
        priv->clk = devm_clk_get_optional(&pdev->dev, "sw_sysport");
-       if (IS_ERR(priv->clk))
-               return PTR_ERR(priv->clk);
+       if (IS_ERR(priv->clk)) {
+               ret = PTR_ERR(priv->clk);
+               goto err_free_netdev;
+       }
 
        /* Allocate number of TX rings */
        priv->tx_rings = devm_kcalloc(&pdev->dev, txq,
index e5cfbe1..19dc7dc 100644 (file)
@@ -1158,11 +1158,9 @@ static struct sock *chtls_recv_sock(struct sock *lsk,
 #endif
        }
        if (!n || !n->dev)
-               goto free_sk;
+               goto free_dst;
 
        ndev = n->dev;
-       if (!ndev)
-               goto free_dst;
        if (is_vlan_dev(ndev))
                ndev = vlan_dev_real_dev(ndev);
 
@@ -1250,7 +1248,8 @@ static struct sock *chtls_recv_sock(struct sock *lsk,
 free_csk:
        chtls_sock_release(&csk->kref);
 free_dst:
-       neigh_release(n);
+       if (n)
+               neigh_release(n);
        dst_release(dst);
 free_sk:
        inet_csk_prepare_forced_close(newsk);
index c527f4e..0602d5d 100644 (file)
@@ -462,6 +462,11 @@ struct bufdesc_ex {
  */
 #define FEC_QUIRK_CLEAR_SETUP_MII      (1 << 17)
 
+/* Some link partners do not tolerate the momentary reset of the REF_CLK
+ * frequency when the RNCTL register is cleared by hardware reset.
+ */
+#define FEC_QUIRK_NO_HARD_RESET                (1 << 18)
+
 struct bufdesc_prop {
        int qid;
        /* Address of Rx and Tx buffers */
index 04f24c6..9ebdb0e 100644 (file)
@@ -100,7 +100,8 @@ static const struct fec_devinfo fec_imx27_info = {
 static const struct fec_devinfo fec_imx28_info = {
        .quirks = FEC_QUIRK_ENET_MAC | FEC_QUIRK_SWAP_FRAME |
                  FEC_QUIRK_SINGLE_MDIO | FEC_QUIRK_HAS_RACC |
-                 FEC_QUIRK_HAS_FRREG | FEC_QUIRK_CLEAR_SETUP_MII,
+                 FEC_QUIRK_HAS_FRREG | FEC_QUIRK_CLEAR_SETUP_MII |
+                 FEC_QUIRK_NO_HARD_RESET,
 };
 
 static const struct fec_devinfo fec_imx6q_info = {
@@ -953,7 +954,8 @@ fec_restart(struct net_device *ndev)
         * For i.MX6SX SOC, enet use AXI bus, we use disable MAC
         * instead of reset MAC itself.
         */
-       if (fep->quirks & FEC_QUIRK_HAS_AVB) {
+       if (fep->quirks & FEC_QUIRK_HAS_AVB ||
+           ((fep->quirks & FEC_QUIRK_NO_HARD_RESET) && fep->link)) {
                writel(0, fep->hwp + FEC_ECNTRL);
        } else {
                writel(1, fep->hwp + FEC_ECNTRL);
@@ -2165,9 +2167,9 @@ static int fec_enet_mii_init(struct platform_device *pdev)
        fep->mii_bus->parent = &pdev->dev;
 
        err = of_mdiobus_register(fep->mii_bus, node);
-       of_node_put(node);
        if (err)
                goto err_out_free_mdiobus;
+       of_node_put(node);
 
        mii_cnt++;
 
@@ -2180,6 +2182,7 @@ static int fec_enet_mii_init(struct platform_device *pdev)
 err_out_free_mdiobus:
        mdiobus_free(fep->mii_bus);
 err_out:
+       of_node_put(node);
        return err;
 }
 
index 9778c83..f79034c 100644 (file)
@@ -5084,6 +5084,12 @@ static void ibmvnic_tasklet(struct tasklet_struct *t)
        while (!done) {
                /* Pull all the valid messages off the CRQ */
                while ((crq = ibmvnic_next_crq(adapter)) != NULL) {
+                       /* This barrier makes sure ibmvnic_next_crq()'s
+                        * crq->generic.first & IBMVNIC_CRQ_CMD_RSP is loaded
+                        * before ibmvnic_handle_crq()'s
+                        * switch(gen_crq->first) and switch(gen_crq->cmd).
+                        */
+                       dma_rmb();
                        ibmvnic_handle_crq(crq, adapter);
                        crq->generic.first = 0;
                }
@@ -5438,11 +5444,6 @@ static int ibmvnic_remove(struct vio_dev *dev)
        unsigned long flags;
 
        spin_lock_irqsave(&adapter->state_lock, flags);
-       if (test_bit(0, &adapter->resetting)) {
-               spin_unlock_irqrestore(&adapter->state_lock, flags);
-               return -EBUSY;
-       }
-
        adapter->state = VNIC_REMOVING;
        spin_unlock_irqrestore(&adapter->state_lock, flags);
 
index 21ee564..1b6ec9b 100644 (file)
@@ -55,12 +55,7 @@ static void i40e_vc_notify_vf_link_state(struct i40e_vf *vf)
 
        pfe.event = VIRTCHNL_EVENT_LINK_CHANGE;
        pfe.severity = PF_EVENT_SEVERITY_INFO;
-
-       /* Always report link is down if the VF queues aren't enabled */
-       if (!vf->queues_enabled) {
-               pfe.event_data.link_event.link_status = false;
-               pfe.event_data.link_event.link_speed = 0;
-       } else if (vf->link_forced) {
+       if (vf->link_forced) {
                pfe.event_data.link_event.link_status = vf->link_up;
                pfe.event_data.link_event.link_speed =
                        (vf->link_up ? i40e_virtchnl_link_speed(ls->link_speed) : 0);
@@ -70,7 +65,6 @@ static void i40e_vc_notify_vf_link_state(struct i40e_vf *vf)
                pfe.event_data.link_event.link_speed =
                        i40e_virtchnl_link_speed(ls->link_speed);
        }
-
        i40e_aq_send_msg_to_vf(hw, abs_vf_id, VIRTCHNL_OP_EVENT,
                               0, (u8 *)&pfe, sizeof(pfe), NULL);
 }
@@ -2443,8 +2437,6 @@ static int i40e_vc_enable_queues_msg(struct i40e_vf *vf, u8 *msg)
                }
        }
 
-       vf->queues_enabled = true;
-
 error_param:
        /* send the response to the VF */
        return i40e_vc_send_resp_to_vf(vf, VIRTCHNL_OP_ENABLE_QUEUES,
@@ -2466,9 +2458,6 @@ static int i40e_vc_disable_queues_msg(struct i40e_vf *vf, u8 *msg)
        struct i40e_pf *pf = vf->pf;
        i40e_status aq_ret = 0;
 
-       /* Immediately mark queues as disabled */
-       vf->queues_enabled = false;
-
        if (!test_bit(I40E_VF_STATE_ACTIVE, &vf->vf_states)) {
                aq_ret = I40E_ERR_PARAM;
                goto error_param;
@@ -4046,20 +4035,16 @@ int i40e_ndo_set_vf_mac(struct net_device *netdev, int vf_id, u8 *mac)
                goto error_param;
 
        vf = &pf->vf[vf_id];
-       vsi = pf->vsi[vf->lan_vsi_idx];
 
        /* When the VF is resetting wait until it is done.
         * It can take up to 200 milliseconds,
         * but wait for up to 300 milliseconds to be safe.
-        * If the VF is indeed in reset, the vsi pointer has
-        * to show on the newly loaded vsi under pf->vsi[id].
+        * Acquire the VSI pointer only after the VF has been
+        * properly initialized.
         */
        for (i = 0; i < 15; i++) {
-               if (test_bit(I40E_VF_STATE_INIT, &vf->vf_states)) {
-                       if (i > 0)
-                               vsi = pf->vsi[vf->lan_vsi_idx];
+               if (test_bit(I40E_VF_STATE_INIT, &vf->vf_states))
                        break;
-               }
                msleep(20);
        }
        if (!test_bit(I40E_VF_STATE_INIT, &vf->vf_states)) {
@@ -4068,6 +4053,7 @@ int i40e_ndo_set_vf_mac(struct net_device *netdev, int vf_id, u8 *mac)
                ret = -EAGAIN;
                goto error_param;
        }
+       vsi = pf->vsi[vf->lan_vsi_idx];
 
        if (is_multicast_ether_addr(mac)) {
                dev_err(&pf->pdev->dev,
index 5491215..091e32c 100644 (file)
@@ -98,7 +98,6 @@ struct i40e_vf {
        unsigned int tx_rate;   /* Tx bandwidth limit in Mbps */
        bool link_forced;
        bool link_up;           /* only valid if VF link is forced */
-       bool queues_enabled;    /* true if the VF queues are enabled */
        bool spoofchk;
        u16 num_vlan;
 
index 5672535..fa1e128 100644 (file)
@@ -68,7 +68,9 @@
 #define ICE_INT_NAME_STR_LEN   (IFNAMSIZ + 16)
 #define ICE_AQ_LEN             64
 #define ICE_MBXSQ_LEN          64
-#define ICE_MIN_MSIX           2
+#define ICE_MIN_LAN_TXRX_MSIX  1
+#define ICE_MIN_LAN_OICR_MSIX  1
+#define ICE_MIN_MSIX           (ICE_MIN_LAN_TXRX_MSIX + ICE_MIN_LAN_OICR_MSIX)
 #define ICE_FDIR_MSIX          1
 #define ICE_NO_VSI             0xffff
 #define ICE_VSI_MAP_CONTIG     0
index 9e8e953..69c113a 100644 (file)
@@ -3258,8 +3258,8 @@ ice_set_rxfh(struct net_device *netdev, const u32 *indir, const u8 *key,
  */
 static int ice_get_max_txq(struct ice_pf *pf)
 {
-       return min_t(int, num_online_cpus(),
-                    pf->hw.func_caps.common_cap.num_txq);
+       return min3(pf->num_lan_msix, (u16)num_online_cpus(),
+                   (u16)pf->hw.func_caps.common_cap.num_txq);
 }
 
 /**
@@ -3268,8 +3268,8 @@ static int ice_get_max_txq(struct ice_pf *pf)
  */
 static int ice_get_max_rxq(struct ice_pf *pf)
 {
-       return min_t(int, num_online_cpus(),
-                    pf->hw.func_caps.common_cap.num_rxq);
+       return min3(pf->num_lan_msix, (u16)num_online_cpus(),
+                   (u16)pf->hw.func_caps.common_cap.num_rxq);
 }
 
 /**
index 2d27f66..1927295 100644 (file)
@@ -1576,7 +1576,13 @@ ice_set_fdir_input_set(struct ice_vsi *vsi, struct ethtool_rx_flow_spec *fsp,
                       sizeof(struct in6_addr));
                input->ip.v6.l4_header = fsp->h_u.usr_ip6_spec.l4_4_bytes;
                input->ip.v6.tc = fsp->h_u.usr_ip6_spec.tclass;
-               input->ip.v6.proto = fsp->h_u.usr_ip6_spec.l4_proto;
+
+               /* if no protocol requested, use IPPROTO_NONE */
+               if (!fsp->m_u.usr_ip6_spec.l4_proto)
+                       input->ip.v6.proto = IPPROTO_NONE;
+               else
+                       input->ip.v6.proto = fsp->h_u.usr_ip6_spec.l4_proto;
+
                memcpy(input->mask.v6.dst_ip, fsp->m_u.usr_ip6_spec.ip6dst,
                       sizeof(struct in6_addr));
                memcpy(input->mask.v6.src_ip, fsp->m_u.usr_ip6_spec.ip6src,
index 3df6748..ad9c22a 100644 (file)
@@ -161,8 +161,9 @@ static void ice_vsi_set_num_qs(struct ice_vsi *vsi, u16 vf_id)
 
        switch (vsi->type) {
        case ICE_VSI_PF:
-               vsi->alloc_txq = min_t(int, ice_get_avail_txq_count(pf),
-                                      num_online_cpus());
+               vsi->alloc_txq = min3(pf->num_lan_msix,
+                                     ice_get_avail_txq_count(pf),
+                                     (u16)num_online_cpus());
                if (vsi->req_txq) {
                        vsi->alloc_txq = vsi->req_txq;
                        vsi->num_txq = vsi->req_txq;
@@ -174,8 +175,9 @@ static void ice_vsi_set_num_qs(struct ice_vsi *vsi, u16 vf_id)
                if (!test_bit(ICE_FLAG_RSS_ENA, pf->flags)) {
                        vsi->alloc_rxq = 1;
                } else {
-                       vsi->alloc_rxq = min_t(int, ice_get_avail_rxq_count(pf),
-                                              num_online_cpus());
+                       vsi->alloc_rxq = min3(pf->num_lan_msix,
+                                             ice_get_avail_rxq_count(pf),
+                                             (u16)num_online_cpus());
                        if (vsi->req_rxq) {
                                vsi->alloc_rxq = vsi->req_rxq;
                                vsi->num_rxq = vsi->req_rxq;
@@ -184,7 +186,9 @@ static void ice_vsi_set_num_qs(struct ice_vsi *vsi, u16 vf_id)
 
                pf->num_lan_rx = vsi->alloc_rxq;
 
-               vsi->num_q_vectors = max_t(int, vsi->alloc_rxq, vsi->alloc_txq);
+               vsi->num_q_vectors = min_t(int, pf->num_lan_msix,
+                                          max_t(int, vsi->alloc_rxq,
+                                                vsi->alloc_txq));
                break;
        case ICE_VSI_VF:
                vf = &pf->vf[vsi->vf_id];
index c52b9bb..e10ca89 100644 (file)
@@ -3430,18 +3430,14 @@ static int ice_ena_msix_range(struct ice_pf *pf)
        if (v_actual < v_budget) {
                dev_warn(dev, "not enough OS MSI-X vectors. requested = %d, obtained = %d\n",
                         v_budget, v_actual);
-/* 2 vectors each for LAN and RDMA (traffic + OICR), one for flow director */
-#define ICE_MIN_LAN_VECS 2
-#define ICE_MIN_RDMA_VECS 2
-#define ICE_MIN_VECS (ICE_MIN_LAN_VECS + ICE_MIN_RDMA_VECS + 1)
 
-               if (v_actual < ICE_MIN_LAN_VECS) {
+               if (v_actual < ICE_MIN_MSIX) {
                        /* error if we can't get minimum vectors */
                        pci_disable_msix(pf->pdev);
                        err = -ERANGE;
                        goto msix_err;
                } else {
-                       pf->num_lan_msix = ICE_MIN_LAN_VECS;
+                       pf->num_lan_msix = ICE_MIN_LAN_TXRX_MSIX;
                }
        }
 
@@ -4884,9 +4880,15 @@ static int ice_set_mac_address(struct net_device *netdev, void *pi)
                goto err_update_filters;
        }
 
-       /* Add filter for new MAC. If filter exists, just return success */
+       /* Add filter for new MAC. If filter exists, return success */
        status = ice_fltr_add_mac(vsi, mac, ICE_FWD_TO_VSI);
        if (status == ICE_ERR_ALREADY_EXISTS) {
+               /* Although this MAC filter is already present in hardware it's
+                * possible in some cases (e.g. bonding) that dev_addr was
+                * modified outside of the driver and needs to be restored back
+                * to this value.
+                */
+               memcpy(netdev->dev_addr, mac, netdev->addr_len);
                netdev_dbg(netdev, "filter for MAC %pM already exists\n", mac);
                return 0;
        }
index a2d0aad..b6fa83c 100644 (file)
@@ -1923,12 +1923,15 @@ int ice_tx_csum(struct ice_tx_buf *first, struct ice_tx_offload_params *off)
                                  ICE_TX_CTX_EIPT_IPV4_NO_CSUM;
                        l4_proto = ip.v4->protocol;
                } else if (first->tx_flags & ICE_TX_FLAGS_IPV6) {
+                       int ret;
+
                        tunnel |= ICE_TX_CTX_EIPT_IPV6;
                        exthdr = ip.hdr + sizeof(*ip.v6);
                        l4_proto = ip.v6->nexthdr;
-                       if (l4.hdr != exthdr)
-                               ipv6_skip_exthdr(skb, exthdr - skb->data,
-                                                &l4_proto, &frag_off);
+                       ret = ipv6_skip_exthdr(skb, exthdr - skb->data,
+                                              &l4_proto, &frag_off);
+                       if (ret < 0)
+                               return -1;
                }
 
                /* define outer transport */
index 61d331c..ec8cd69 100644 (file)
@@ -1675,12 +1675,18 @@ static int igc_ethtool_get_link_ksettings(struct net_device *netdev,
        cmd->base.phy_address = hw->phy.addr;
 
        /* advertising link modes */
-       ethtool_link_ksettings_add_link_mode(cmd, advertising, 10baseT_Half);
-       ethtool_link_ksettings_add_link_mode(cmd, advertising, 10baseT_Full);
-       ethtool_link_ksettings_add_link_mode(cmd, advertising, 100baseT_Half);
-       ethtool_link_ksettings_add_link_mode(cmd, advertising, 100baseT_Full);
-       ethtool_link_ksettings_add_link_mode(cmd, advertising, 1000baseT_Full);
-       ethtool_link_ksettings_add_link_mode(cmd, advertising, 2500baseT_Full);
+       if (hw->phy.autoneg_advertised & ADVERTISE_10_HALF)
+               ethtool_link_ksettings_add_link_mode(cmd, advertising, 10baseT_Half);
+       if (hw->phy.autoneg_advertised & ADVERTISE_10_FULL)
+               ethtool_link_ksettings_add_link_mode(cmd, advertising, 10baseT_Full);
+       if (hw->phy.autoneg_advertised & ADVERTISE_100_HALF)
+               ethtool_link_ksettings_add_link_mode(cmd, advertising, 100baseT_Half);
+       if (hw->phy.autoneg_advertised & ADVERTISE_100_FULL)
+               ethtool_link_ksettings_add_link_mode(cmd, advertising, 100baseT_Full);
+       if (hw->phy.autoneg_advertised & ADVERTISE_1000_FULL)
+               ethtool_link_ksettings_add_link_mode(cmd, advertising, 1000baseT_Full);
+       if (hw->phy.autoneg_advertised & ADVERTISE_2500_FULL)
+               ethtool_link_ksettings_add_link_mode(cmd, advertising, 2500baseT_Full);
 
        /* set autoneg settings */
        if (hw->mac.autoneg == 1) {
@@ -1708,7 +1714,8 @@ static int igc_ethtool_get_link_ksettings(struct net_device *netdev,
                                                     Asym_Pause);
        }
 
-       status = rd32(IGC_STATUS);
+       status = pm_runtime_suspended(&adapter->pdev->dev) ?
+                0 : rd32(IGC_STATUS);
 
        if (status & IGC_STATUS_LU) {
                if (status & IGC_STATUS_SPEED_1000) {
@@ -1792,6 +1799,12 @@ igc_ethtool_set_link_ksettings(struct net_device *netdev,
 
        ethtool_convert_link_mode_to_legacy_u32(&advertising,
                                                cmd->link_modes.advertising);
+       /* Converting to legacy u32 drops ETHTOOL_LINK_MODE_2500baseT_Full_BIT.
+        * We have to check this and convert it to ADVERTISE_2500_FULL
+        * (aka ETHTOOL_LINK_MODE_2500baseX_Full_BIT) explicitly.
+        */
+       if (ethtool_link_ksettings_test_link_mode(cmd, advertising, 2500baseT_Full))
+               advertising |= ADVERTISE_2500_FULL;
 
        if (cmd->base.autoneg == AUTONEG_ENABLE) {
                hw->mac.autoneg = 1;
index 8b67d9b..7ec04e4 100644 (file)
@@ -219,9 +219,9 @@ static s32 igc_write_nvm_srwr(struct igc_hw *hw, u16 offset, u16 words,
                              u16 *data)
 {
        struct igc_nvm_info *nvm = &hw->nvm;
+       s32 ret_val = -IGC_ERR_NVM;
        u32 attempts = 100000;
        u32 i, k, eewr = 0;
-       s32 ret_val = 0;
 
        /* A check for invalid values:  offset too large, too many words,
         * too many words for the offset, and not enough words.
@@ -229,7 +229,6 @@ static s32 igc_write_nvm_srwr(struct igc_hw *hw, u16 offset, u16 words,
        if (offset >= nvm->word_size || (words > (nvm->word_size - offset)) ||
            words == 0) {
                hw_dbg("nvm parameter(s) out of bounds\n");
-               ret_val = -IGC_ERR_NVM;
                goto out;
        }
 
index 09cd0ec..67b8ffd 100644 (file)
@@ -638,7 +638,7 @@ s32 igc_config_fc_after_link_up(struct igc_hw *hw)
        }
 
 out:
-       return 0;
+       return ret_val;
 }
 
 /**
index a30eb90..dd59008 100644 (file)
@@ -29,16 +29,16 @@ static int mvpp2_prs_hw_write(struct mvpp2 *priv, struct mvpp2_prs_entry *pe)
        /* Clear entry invalidation bit */
        pe->tcam[MVPP2_PRS_TCAM_INV_WORD] &= ~MVPP2_PRS_TCAM_INV_MASK;
 
-       /* Write tcam index - indirect access */
-       mvpp2_write(priv, MVPP2_PRS_TCAM_IDX_REG, pe->index);
-       for (i = 0; i < MVPP2_PRS_TCAM_WORDS; i++)
-               mvpp2_write(priv, MVPP2_PRS_TCAM_DATA_REG(i), pe->tcam[i]);
-
        /* Write sram index - indirect access */
        mvpp2_write(priv, MVPP2_PRS_SRAM_IDX_REG, pe->index);
        for (i = 0; i < MVPP2_PRS_SRAM_WORDS; i++)
                mvpp2_write(priv, MVPP2_PRS_SRAM_DATA_REG(i), pe->sram[i]);
 
+       /* Write tcam index - indirect access */
+       mvpp2_write(priv, MVPP2_PRS_TCAM_IDX_REG, pe->index);
+       for (i = 0; i < MVPP2_PRS_TCAM_WORDS; i++)
+               mvpp2_write(priv, MVPP2_PRS_TCAM_DATA_REG(i), pe->tcam[i]);
+
        return 0;
 }
 
index d298b93..6c6b411 100644 (file)
@@ -469,6 +469,9 @@ int rvu_mbox_handler_cgx_mac_addr_set(struct rvu *rvu,
        int pf = rvu_get_pf(req->hdr.pcifunc);
        u8 cgx_id, lmac_id;
 
+       if (!is_cgx_config_permitted(rvu, req->hdr.pcifunc))
+               return -EPERM;
+
        rvu_get_cgx_lmac_id(rvu->pf2cgxlmac_map[pf], &cgx_id, &lmac_id);
 
        cgx_lmac_addr_set(cgx_id, lmac_id, req->mac_addr);
@@ -485,6 +488,9 @@ int rvu_mbox_handler_cgx_mac_addr_get(struct rvu *rvu,
        int rc = 0, i;
        u64 cfg;
 
+       if (!is_cgx_config_permitted(rvu, req->hdr.pcifunc))
+               return -EPERM;
+
        rvu_get_cgx_lmac_id(rvu->pf2cgxlmac_map[pf], &cgx_id, &lmac_id);
 
        rsp->hdr.rc = rc;
index 73fb94d..e686943 100644 (file)
@@ -478,10 +478,11 @@ dma_addr_t __otx2_alloc_rbuf(struct otx2_nic *pfvf, struct otx2_pool *pool)
        dma_addr_t iova;
        u8 *buf;
 
-       buf = napi_alloc_frag(pool->rbsize);
+       buf = napi_alloc_frag(pool->rbsize + OTX2_ALIGN);
        if (unlikely(!buf))
                return -ENOMEM;
 
+       buf = PTR_ALIGN(buf, OTX2_ALIGN);
        iova = dma_map_single_attrs(pfvf->dev, buf, pool->rbsize,
                                    DMA_FROM_DEVICE, DMA_ATTR_SKIP_CPU_SYNC);
        if (unlikely(dma_mapping_error(pfvf->dev, iova))) {
index 718f8c0..84e501e 100644 (file)
@@ -273,7 +273,7 @@ int mlx5e_health_rsc_fmsg_dump(struct mlx5e_priv *priv, struct mlx5_rsc_key *key
 
        err = devlink_fmsg_binary_pair_nest_start(fmsg, "data");
        if (err)
-               return err;
+               goto free_page;
 
        cmd = mlx5_rsc_dump_cmd_create(mdev, key);
        if (IS_ERR(cmd)) {
index 072363e..6bc6b48 100644 (file)
@@ -167,6 +167,12 @@ static const struct rhashtable_params tuples_nat_ht_params = {
        .min_size = 16 * 1024,
 };
 
+static bool
+mlx5_tc_ct_entry_has_nat(struct mlx5_ct_entry *entry)
+{
+       return !!(entry->tuple_nat_node.next);
+}
+
 static int
 mlx5_tc_ct_rule_to_tuple(struct mlx5_ct_tuple *tuple, struct flow_rule *rule)
 {
@@ -911,13 +917,13 @@ mlx5_tc_ct_block_flow_offload_add(struct mlx5_ct_ft *ft,
 err_insert:
        mlx5_tc_ct_entry_del_rules(ct_priv, entry);
 err_rules:
-       rhashtable_remove_fast(&ct_priv->ct_tuples_nat_ht,
-                              &entry->tuple_nat_node, tuples_nat_ht_params);
+       if (mlx5_tc_ct_entry_has_nat(entry))
+               rhashtable_remove_fast(&ct_priv->ct_tuples_nat_ht,
+                                      &entry->tuple_nat_node, tuples_nat_ht_params);
 err_tuple_nat:
-       if (entry->tuple_node.next)
-               rhashtable_remove_fast(&ct_priv->ct_tuples_ht,
-                                      &entry->tuple_node,
-                                      tuples_ht_params);
+       rhashtable_remove_fast(&ct_priv->ct_tuples_ht,
+                              &entry->tuple_node,
+                              tuples_ht_params);
 err_tuple:
 err_set:
        kfree(entry);
@@ -932,7 +938,7 @@ mlx5_tc_ct_del_ft_entry(struct mlx5_tc_ct_priv *ct_priv,
 {
        mlx5_tc_ct_entry_del_rules(ct_priv, entry);
        mutex_lock(&ct_priv->shared_counter_lock);
-       if (entry->tuple_node.next)
+       if (mlx5_tc_ct_entry_has_nat(entry))
                rhashtable_remove_fast(&ct_priv->ct_tuples_nat_ht,
                                       &entry->tuple_nat_node,
                                       tuples_nat_ht_params);
index 6c5c54b..5cb9365 100644 (file)
@@ -76,7 +76,7 @@ static const struct counter_desc mlx5e_ipsec_sw_stats_desc[] = {
 
 static MLX5E_DECLARE_STATS_GRP_OP_NUM_STATS(ipsec_sw)
 {
-       return NUM_IPSEC_SW_COUNTERS;
+       return priv->ipsec ? NUM_IPSEC_SW_COUNTERS : 0;
 }
 
 static inline MLX5E_DECLARE_STATS_GRP_OP_UPDATE_STATS(ipsec_sw) {}
@@ -105,7 +105,7 @@ static MLX5E_DECLARE_STATS_GRP_OP_FILL_STATS(ipsec_sw)
 
 static MLX5E_DECLARE_STATS_GRP_OP_NUM_STATS(ipsec_hw)
 {
-       return (mlx5_fpga_ipsec_device_caps(priv->mdev)) ? NUM_IPSEC_HW_COUNTERS : 0;
+       return (priv->ipsec && mlx5_fpga_ipsec_device_caps(priv->mdev)) ? NUM_IPSEC_HW_COUNTERS : 0;
 }
 
 static MLX5E_DECLARE_STATS_GRP_OP_UPDATE_STATS(ipsec_hw)
index d20243d..f23c675 100644 (file)
@@ -1151,6 +1151,7 @@ static int mlx5e_set_trust_state(struct mlx5e_priv *priv, u8 trust_state)
 {
        struct mlx5e_channels new_channels = {};
        bool reset_channels = true;
+       bool opened;
        int err = 0;
 
        mutex_lock(&priv->state_lock);
@@ -1159,22 +1160,24 @@ static int mlx5e_set_trust_state(struct mlx5e_priv *priv, u8 trust_state)
        mlx5e_params_calc_trust_tx_min_inline_mode(priv->mdev, &new_channels.params,
                                                   trust_state);
 
-       if (!test_bit(MLX5E_STATE_OPENED, &priv->state)) {
-               priv->channels.params = new_channels.params;
+       opened = test_bit(MLX5E_STATE_OPENED, &priv->state);
+       if (!opened)
                reset_channels = false;
-       }
 
        /* Skip if tx_min_inline is the same */
        if (new_channels.params.tx_min_inline_mode ==
            priv->channels.params.tx_min_inline_mode)
                reset_channels = false;
 
-       if (reset_channels)
+       if (reset_channels) {
                err = mlx5e_safe_switch_channels(priv, &new_channels,
                                                 mlx5e_update_trust_state_hw,
                                                 &trust_state);
-       else
+       } else {
                err = mlx5e_update_trust_state_hw(priv, &trust_state);
+               if (!err && !opened)
+                       priv->channels.params = new_channels.params;
+       }
 
        mutex_unlock(&priv->state_lock);
 
index 2d37742..302001d 100644 (file)
@@ -447,12 +447,18 @@ int mlx5e_ethtool_set_channels(struct mlx5e_priv *priv,
                goto out;
        }
 
-       new_channels.params = priv->channels.params;
+       new_channels.params = *cur_params;
        new_channels.params.num_channels = count;
 
        if (!test_bit(MLX5E_STATE_OPENED, &priv->state)) {
+               struct mlx5e_params old_params;
+
+               old_params = *cur_params;
                *cur_params = new_channels.params;
                err = mlx5e_num_channels_changed(priv);
+               if (err)
+                       *cur_params = old_params;
+
                goto out;
        }
 
index 6a852b4..3fc7d18 100644 (file)
@@ -3614,18 +3614,23 @@ static int mlx5e_setup_tc_mqprio(struct mlx5e_priv *priv,
        new_channels.params.num_tc = tc ? tc : 1;
 
        if (!test_bit(MLX5E_STATE_OPENED, &priv->state)) {
+               struct mlx5e_params old_params;
+
+               old_params = priv->channels.params;
                priv->channels.params = new_channels.params;
+               err = mlx5e_num_channels_changed(priv);
+               if (err)
+                       priv->channels.params = old_params;
+
                goto out;
        }
 
        err = mlx5e_safe_switch_channels(priv, &new_channels,
                                         mlx5e_num_channels_changed_ctx, NULL);
-       if (err)
-               goto out;
 
-       priv->max_opened_tc = max_t(u8, priv->max_opened_tc,
-                                   new_channels.params.num_tc);
 out:
+       priv->max_opened_tc = max_t(u8, priv->max_opened_tc,
+                                   priv->channels.params.num_tc);
        mutex_unlock(&priv->state_lock);
        return err;
 }
@@ -3757,7 +3762,7 @@ static int set_feature_lro(struct net_device *netdev, bool enable)
        struct mlx5e_priv *priv = netdev_priv(netdev);
        struct mlx5_core_dev *mdev = priv->mdev;
        struct mlx5e_channels new_channels = {};
-       struct mlx5e_params *old_params;
+       struct mlx5e_params *cur_params;
        int err = 0;
        bool reset;
 
@@ -3770,8 +3775,8 @@ static int set_feature_lro(struct net_device *netdev, bool enable)
                goto out;
        }
 
-       old_params = &priv->channels.params;
-       if (enable && !MLX5E_GET_PFLAG(old_params, MLX5E_PFLAG_RX_STRIDING_RQ)) {
+       cur_params = &priv->channels.params;
+       if (enable && !MLX5E_GET_PFLAG(cur_params, MLX5E_PFLAG_RX_STRIDING_RQ)) {
                netdev_warn(netdev, "can't set LRO with legacy RQ\n");
                err = -EINVAL;
                goto out;
@@ -3779,18 +3784,23 @@ static int set_feature_lro(struct net_device *netdev, bool enable)
 
        reset = test_bit(MLX5E_STATE_OPENED, &priv->state);
 
-       new_channels.params = *old_params;
+       new_channels.params = *cur_params;
        new_channels.params.lro_en = enable;
 
-       if (old_params->rq_wq_type != MLX5_WQ_TYPE_CYCLIC) {
-               if (mlx5e_rx_mpwqe_is_linear_skb(mdev, old_params, NULL) ==
+       if (cur_params->rq_wq_type != MLX5_WQ_TYPE_CYCLIC) {
+               if (mlx5e_rx_mpwqe_is_linear_skb(mdev, cur_params, NULL) ==
                    mlx5e_rx_mpwqe_is_linear_skb(mdev, &new_channels.params, NULL))
                        reset = false;
        }
 
        if (!reset) {
-               *old_params = new_channels.params;
+               struct mlx5e_params old_params;
+
+               old_params = *cur_params;
+               *cur_params = new_channels.params;
                err = mlx5e_modify_tirs_lro(priv);
+               if (err)
+                       *cur_params = old_params;
                goto out;
        }
 
@@ -4067,9 +4077,16 @@ int mlx5e_change_mtu(struct net_device *netdev, int new_mtu,
        }
 
        if (!reset) {
+               unsigned int old_mtu = params->sw_mtu;
+
                params->sw_mtu = new_mtu;
-               if (preactivate)
-                       preactivate(priv, NULL);
+               if (preactivate) {
+                       err = preactivate(priv, NULL);
+                       if (err) {
+                               params->sw_mtu = old_mtu;
+                               goto out;
+                       }
+               }
                netdev->mtu = params->sw_mtu;
                goto out;
        }
@@ -5027,7 +5044,7 @@ static void mlx5e_build_nic_netdev(struct net_device *netdev)
            FT_CAP(modify_root) &&
            FT_CAP(identified_miss_table_mode) &&
            FT_CAP(flow_table_modify)) {
-#ifdef CONFIG_MLX5_ESWITCH
+#if IS_ENABLED(CONFIG_MLX5_CLS_ACT)
                netdev->hw_features      |= NETIF_F_HW_TC;
 #endif
 #ifdef CONFIG_MLX5_EN_ARFS
index 989c70c..f0ceae6 100644 (file)
@@ -737,7 +737,9 @@ static void mlx5e_build_rep_netdev(struct net_device *netdev)
 
        netdev->features       |= NETIF_F_NETNS_LOCAL;
 
+#if IS_ENABLED(CONFIG_MLX5_CLS_ACT)
        netdev->hw_features    |= NETIF_F_HW_TC;
+#endif
        netdev->hw_features    |= NETIF_F_SG;
        netdev->hw_features    |= NETIF_F_IP_CSUM;
        netdev->hw_features    |= NETIF_F_IPV6_CSUM;
index 7f5851c..ca4b558 100644 (file)
@@ -1262,8 +1262,10 @@ static void mlx5e_handle_rx_cqe(struct mlx5e_rq *rq, struct mlx5_cqe64 *cqe)
        mlx5e_complete_rx_cqe(rq, cqe, cqe_bcnt, skb);
 
        if (mlx5e_cqe_regb_chain(cqe))
-               if (!mlx5e_tc_update_skb(cqe, skb))
+               if (!mlx5e_tc_update_skb(cqe, skb)) {
+                       dev_kfree_skb_any(skb);
                        goto free_wqe;
+               }
 
        napi_gro_receive(rq->cq.napi, skb);
 
@@ -1316,8 +1318,10 @@ static void mlx5e_handle_rx_cqe_rep(struct mlx5e_rq *rq, struct mlx5_cqe64 *cqe)
        if (rep->vlan && skb_vlan_tag_present(skb))
                skb_vlan_pop(skb);
 
-       if (!mlx5e_rep_tc_update_skb(cqe, skb, &tc_priv))
+       if (!mlx5e_rep_tc_update_skb(cqe, skb, &tc_priv)) {
+               dev_kfree_skb_any(skb);
                goto free_wqe;
+       }
 
        napi_gro_receive(rq->cq.napi, skb);
 
@@ -1371,8 +1375,10 @@ static void mlx5e_handle_rx_cqe_mpwrq_rep(struct mlx5e_rq *rq, struct mlx5_cqe64
 
        mlx5e_complete_rx_cqe(rq, cqe, cqe_bcnt, skb);
 
-       if (!mlx5e_rep_tc_update_skb(cqe, skb, &tc_priv))
+       if (!mlx5e_rep_tc_update_skb(cqe, skb, &tc_priv)) {
+               dev_kfree_skb_any(skb);
                goto mpwrq_cqe_out;
+       }
 
        napi_gro_receive(rq->cq.napi, skb);
 
@@ -1528,8 +1534,10 @@ static void mlx5e_handle_rx_cqe_mpwrq(struct mlx5e_rq *rq, struct mlx5_cqe64 *cq
        mlx5e_complete_rx_cqe(rq, cqe, cqe_bcnt, skb);
 
        if (mlx5e_cqe_regb_chain(cqe))
-               if (!mlx5e_tc_update_skb(cqe, skb))
+               if (!mlx5e_tc_update_skb(cqe, skb)) {
+                       dev_kfree_skb_any(skb);
                        goto mpwrq_cqe_out;
+               }
 
        napi_gro_receive(rq->cq.napi, skb);
 
index 4cdf834..dd0bfba 100644 (file)
@@ -67,6 +67,7 @@
 #include "lib/geneve.h"
 #include "lib/fs_chains.h"
 #include "diag/en_tc_tracepoint.h"
+#include <asm/div64.h>
 
 #define nic_chains(priv) ((priv)->fs.tc.chains)
 #define MLX5_MH_ACT_SZ MLX5_UN_SZ_BYTES(set_add_copy_action_in_auto)
@@ -1162,6 +1163,9 @@ mlx5e_tc_offload_fdb_rules(struct mlx5_eswitch *esw,
        struct mlx5e_tc_mod_hdr_acts *mod_hdr_acts;
        struct mlx5_flow_handle *rule;
 
+       if (attr->flags & MLX5_ESW_ATTR_FLAG_SLOW_PATH)
+               return mlx5_eswitch_add_offloaded_rule(esw, spec, attr);
+
        if (flow_flag_test(flow, CT)) {
                mod_hdr_acts = &attr->parse_attr->mod_hdr_acts;
 
@@ -1192,6 +1196,9 @@ mlx5e_tc_unoffload_fdb_rules(struct mlx5_eswitch *esw,
 {
        flow_flag_clear(flow, OFFLOADED);
 
+       if (attr->flags & MLX5_ESW_ATTR_FLAG_SLOW_PATH)
+               goto offload_rule_0;
+
        if (flow_flag_test(flow, CT)) {
                mlx5_tc_ct_delete_flow(get_ct_priv(flow->priv), flow, attr);
                return;
@@ -1200,6 +1207,7 @@ mlx5e_tc_unoffload_fdb_rules(struct mlx5_eswitch *esw,
        if (attr->esw_attr->split_count)
                mlx5_eswitch_del_fwd_rule(esw, flow->rule[1], attr);
 
+offload_rule_0:
        mlx5_eswitch_del_offloaded_rule(esw, flow->rule[0], attr);
 }
 
@@ -2269,8 +2277,8 @@ static int __parse_cls_flower(struct mlx5e_priv *priv,
              BIT(FLOW_DISSECTOR_KEY_ENC_OPTS) |
              BIT(FLOW_DISSECTOR_KEY_MPLS))) {
                NL_SET_ERR_MSG_MOD(extack, "Unsupported key");
-               netdev_warn(priv->netdev, "Unsupported key used: 0x%x\n",
-                           dissector->used_keys);
+               netdev_dbg(priv->netdev, "Unsupported key used: 0x%x\n",
+                          dissector->used_keys);
                return -EOPNOTSUPP;
        }
 
@@ -5007,13 +5015,13 @@ errout:
        return err;
 }
 
-static int apply_police_params(struct mlx5e_priv *priv, u32 rate,
+static int apply_police_params(struct mlx5e_priv *priv, u64 rate,
                               struct netlink_ext_ack *extack)
 {
        struct mlx5e_rep_priv *rpriv = priv->ppriv;
        struct mlx5_eswitch *esw;
+       u32 rate_mbps = 0;
        u16 vport_num;
-       u32 rate_mbps;
        int err;
 
        vport_num = rpriv->rep->vport;
@@ -5030,7 +5038,11 @@ static int apply_police_params(struct mlx5e_priv *priv, u32 rate,
         * Moreover, if rate is non zero we choose to configure to a minimum of
         * 1 mbit/sec.
         */
-       rate_mbps = rate ? max_t(u32, (rate * 8 + 500000) / 1000000, 1) : 0;
+       if (rate) {
+               rate = (rate * BITS_PER_BYTE) + 500000;
+               rate_mbps = max_t(u32, do_div(rate, 1000000), 1);
+       }
+
        err = mlx5_esw_modify_vport_rate(esw, vport_num, rate_mbps);
        if (err)
                NL_SET_ERR_MSG_MOD(extack, "failed applying action to hardware");
index b899539..ee4d86c 100644 (file)
@@ -1141,6 +1141,7 @@ static struct mlx5_flow_table *__mlx5_create_flow_table(struct mlx5_flow_namespa
 destroy_ft:
        root->cmds->destroy_flow_table(root, ft);
 free_ft:
+       rhltable_destroy(&ft->fgs_hash);
        kfree(ft);
 unlock_root:
        mutex_unlock(&root->chain_lock);
@@ -1759,6 +1760,7 @@ search_again_locked:
                if (!fte_tmp)
                        continue;
                rule = add_rule_fg(g, spec, flow_act, dest, dest_num, fte_tmp);
+               /* No error check needed here, because insert_fte() is not called */
                up_write_ref_node(&fte_tmp->node, false);
                tree_put_node(&fte_tmp->node, false);
                kmem_cache_free(steering->ftes_cache, fte);
@@ -1811,6 +1813,8 @@ skip_search:
                up_write_ref_node(&g->node, false);
                rule = add_rule_fg(g, spec, flow_act, dest, dest_num, fte);
                up_write_ref_node(&fte->node, false);
+               if (IS_ERR(rule))
+                       tree_put_node(&fte->node, false);
                return rule;
        }
        rule = ERR_PTR(-ENOENT);
@@ -1909,6 +1913,8 @@ search_again_locked:
        up_write_ref_node(&g->node, false);
        rule = add_rule_fg(g, spec, flow_act, dest, dest_num, fte);
        up_write_ref_node(&fte->node, false);
+       if (IS_ERR(rule))
+               tree_put_node(&fte->node, false);
        tree_put_node(&g->node, false);
        return rule;
 
index 3a9fa62..d046db7 100644 (file)
@@ -90,4 +90,9 @@ int mlx5_create_encryption_key(struct mlx5_core_dev *mdev,
                               u32 key_type, u32 *p_key_id);
 void mlx5_destroy_encryption_key(struct mlx5_core_dev *mdev, u32 key_id);
 
+static inline struct net *mlx5_core_net(struct mlx5_core_dev *dev)
+{
+       return devlink_net(priv_to_devlink(dev));
+}
+
 #endif
index eb956ce..c0656d4 100644 (file)
@@ -58,7 +58,7 @@ struct fw_page {
        struct rb_node          rb_node;
        u64                     addr;
        struct page            *page;
-       u16                     func_id;
+       u32                     function;
        unsigned long           bitmask;
        struct list_head        list;
        unsigned                free_count;
@@ -74,12 +74,17 @@ enum {
        MLX5_NUM_4K_IN_PAGE             = PAGE_SIZE / MLX5_ADAPTER_PAGE_SIZE,
 };
 
-static struct rb_root *page_root_per_func_id(struct mlx5_core_dev *dev, u16 func_id)
+static u32 get_function(u16 func_id, bool ec_function)
+{
+       return (u32)func_id | (ec_function << 16);
+}
+
+static struct rb_root *page_root_per_function(struct mlx5_core_dev *dev, u32 function)
 {
        struct rb_root *root;
        int err;
 
-       root = xa_load(&dev->priv.page_root_xa, func_id);
+       root = xa_load(&dev->priv.page_root_xa, function);
        if (root)
                return root;
 
@@ -87,7 +92,7 @@ static struct rb_root *page_root_per_func_id(struct mlx5_core_dev *dev, u16 func
        if (!root)
                return ERR_PTR(-ENOMEM);
 
-       err = xa_insert(&dev->priv.page_root_xa, func_id, root, GFP_KERNEL);
+       err = xa_insert(&dev->priv.page_root_xa, function, root, GFP_KERNEL);
        if (err) {
                kfree(root);
                return ERR_PTR(err);
@@ -98,7 +103,7 @@ static struct rb_root *page_root_per_func_id(struct mlx5_core_dev *dev, u16 func
        return root;
 }
 
-static int insert_page(struct mlx5_core_dev *dev, u64 addr, struct page *page, u16 func_id)
+static int insert_page(struct mlx5_core_dev *dev, u64 addr, struct page *page, u32 function)
 {
        struct rb_node *parent = NULL;
        struct rb_root *root;
@@ -107,7 +112,7 @@ static int insert_page(struct mlx5_core_dev *dev, u64 addr, struct page *page, u
        struct fw_page *tfp;
        int i;
 
-       root = page_root_per_func_id(dev, func_id);
+       root = page_root_per_function(dev, function);
        if (IS_ERR(root))
                return PTR_ERR(root);
 
@@ -130,7 +135,7 @@ static int insert_page(struct mlx5_core_dev *dev, u64 addr, struct page *page, u
 
        nfp->addr = addr;
        nfp->page = page;
-       nfp->func_id = func_id;
+       nfp->function = function;
        nfp->free_count = MLX5_NUM_4K_IN_PAGE;
        for (i = 0; i < MLX5_NUM_4K_IN_PAGE; i++)
                set_bit(i, &nfp->bitmask);
@@ -143,14 +148,14 @@ static int insert_page(struct mlx5_core_dev *dev, u64 addr, struct page *page, u
 }
 
 static struct fw_page *find_fw_page(struct mlx5_core_dev *dev, u64 addr,
-                                   u32 func_id)
+                                   u32 function)
 {
        struct fw_page *result = NULL;
        struct rb_root *root;
        struct rb_node *tmp;
        struct fw_page *tfp;
 
-       root = xa_load(&dev->priv.page_root_xa, func_id);
+       root = xa_load(&dev->priv.page_root_xa, function);
        if (WARN_ON_ONCE(!root))
                return NULL;
 
@@ -194,14 +199,14 @@ static int mlx5_cmd_query_pages(struct mlx5_core_dev *dev, u16 *func_id,
        return err;
 }
 
-static int alloc_4k(struct mlx5_core_dev *dev, u64 *addr, u16 func_id)
+static int alloc_4k(struct mlx5_core_dev *dev, u64 *addr, u32 function)
 {
        struct fw_page *fp = NULL;
        struct fw_page *iter;
        unsigned n;
 
        list_for_each_entry(iter, &dev->priv.free_list, list) {
-               if (iter->func_id != func_id)
+               if (iter->function != function)
                        continue;
                fp = iter;
        }
@@ -231,7 +236,7 @@ static void free_fwp(struct mlx5_core_dev *dev, struct fw_page *fwp,
 {
        struct rb_root *root;
 
-       root = xa_load(&dev->priv.page_root_xa, fwp->func_id);
+       root = xa_load(&dev->priv.page_root_xa, fwp->function);
        if (WARN_ON_ONCE(!root))
                return;
 
@@ -244,12 +249,12 @@ static void free_fwp(struct mlx5_core_dev *dev, struct fw_page *fwp,
        kfree(fwp);
 }
 
-static void free_4k(struct mlx5_core_dev *dev, u64 addr, u32 func_id)
+static void free_4k(struct mlx5_core_dev *dev, u64 addr, u32 function)
 {
        struct fw_page *fwp;
        int n;
 
-       fwp = find_fw_page(dev, addr & MLX5_U64_4K_PAGE_MASK, func_id);
+       fwp = find_fw_page(dev, addr & MLX5_U64_4K_PAGE_MASK, function);
        if (!fwp) {
                mlx5_core_warn_rl(dev, "page not found\n");
                return;
@@ -263,7 +268,7 @@ static void free_4k(struct mlx5_core_dev *dev, u64 addr, u32 func_id)
                list_add(&fwp->list, &dev->priv.free_list);
 }
 
-static int alloc_system_page(struct mlx5_core_dev *dev, u16 func_id)
+static int alloc_system_page(struct mlx5_core_dev *dev, u32 function)
 {
        struct device *device = mlx5_core_dma_dev(dev);
        int nid = dev_to_node(device);
@@ -291,7 +296,7 @@ map:
                goto map;
        }
 
-       err = insert_page(dev, addr, page, func_id);
+       err = insert_page(dev, addr, page, function);
        if (err) {
                mlx5_core_err(dev, "failed to track allocated page\n");
                dma_unmap_page(device, addr, PAGE_SIZE, DMA_BIDIRECTIONAL);
@@ -328,6 +333,7 @@ static void page_notify_fail(struct mlx5_core_dev *dev, u16 func_id,
 static int give_pages(struct mlx5_core_dev *dev, u16 func_id, int npages,
                      int notify_fail, bool ec_function)
 {
+       u32 function = get_function(func_id, ec_function);
        u32 out[MLX5_ST_SZ_DW(manage_pages_out)] = {0};
        int inlen = MLX5_ST_SZ_BYTES(manage_pages_in);
        u64 addr;
@@ -345,10 +351,10 @@ static int give_pages(struct mlx5_core_dev *dev, u16 func_id, int npages,
 
        for (i = 0; i < npages; i++) {
 retry:
-               err = alloc_4k(dev, &addr, func_id);
+               err = alloc_4k(dev, &addr, function);
                if (err) {
                        if (err == -ENOMEM)
-                               err = alloc_system_page(dev, func_id);
+                               err = alloc_system_page(dev, function);
                        if (err)
                                goto out_4k;
 
@@ -384,7 +390,7 @@ retry:
 
 out_4k:
        for (i--; i >= 0; i--)
-               free_4k(dev, MLX5_GET64(manage_pages_in, in, pas[i]), func_id);
+               free_4k(dev, MLX5_GET64(manage_pages_in, in, pas[i]), function);
 out_free:
        kvfree(in);
        if (notify_fail)
@@ -392,14 +398,15 @@ out_free:
        return err;
 }
 
-static void release_all_pages(struct mlx5_core_dev *dev, u32 func_id,
+static void release_all_pages(struct mlx5_core_dev *dev, u16 func_id,
                              bool ec_function)
 {
+       u32 function = get_function(func_id, ec_function);
        struct rb_root *root;
        struct rb_node *p;
        int npages = 0;
 
-       root = xa_load(&dev->priv.page_root_xa, func_id);
+       root = xa_load(&dev->priv.page_root_xa, function);
        if (WARN_ON_ONCE(!root))
                return;
 
@@ -446,6 +453,7 @@ static int reclaim_pages_cmd(struct mlx5_core_dev *dev,
        struct rb_root *root;
        struct fw_page *fwp;
        struct rb_node *p;
+       bool ec_function;
        u32 func_id;
        u32 npages;
        u32 i = 0;
@@ -456,8 +464,9 @@ static int reclaim_pages_cmd(struct mlx5_core_dev *dev,
        /* No hard feelings, we want our pages back! */
        npages = MLX5_GET(manage_pages_in, in, input_num_entries);
        func_id = MLX5_GET(manage_pages_in, in, function_id);
+       ec_function = MLX5_GET(manage_pages_in, in, embedded_cpu_function);
 
-       root = xa_load(&dev->priv.page_root_xa, func_id);
+       root = xa_load(&dev->priv.page_root_xa, get_function(func_id, ec_function));
        if (WARN_ON_ONCE(!root))
                return -EEXIST;
 
@@ -473,9 +482,10 @@ static int reclaim_pages_cmd(struct mlx5_core_dev *dev,
        return 0;
 }
 
-static int reclaim_pages(struct mlx5_core_dev *dev, u32 func_id, int npages,
+static int reclaim_pages(struct mlx5_core_dev *dev, u16 func_id, int npages,
                         int *nclaimed, bool ec_function)
 {
+       u32 function = get_function(func_id, ec_function);
        int outlen = MLX5_ST_SZ_BYTES(manage_pages_out);
        u32 in[MLX5_ST_SZ_DW(manage_pages_in)] = {};
        int num_claimed;
@@ -514,7 +524,7 @@ static int reclaim_pages(struct mlx5_core_dev *dev, u32 func_id, int npages,
        }
 
        for (i = 0; i < num_claimed; i++)
-               free_4k(dev, MLX5_GET64(manage_pages_out, out, pas[i]), func_id);
+               free_4k(dev, MLX5_GET64(manage_pages_out, out, pas[i]), function);
 
        if (nclaimed)
                *nclaimed = num_claimed;
index c6c5826..1892cea 100644 (file)
@@ -157,6 +157,7 @@ mlxsw_sp1_span_entry_cpu_deconfigure(struct mlxsw_sp_span_entry *span_entry)
 
 static const
 struct mlxsw_sp_span_entry_ops mlxsw_sp1_span_entry_ops_cpu = {
+       .is_static = true,
        .can_handle = mlxsw_sp1_span_cpu_can_handle,
        .parms_set = mlxsw_sp1_span_entry_cpu_parms,
        .configure = mlxsw_sp1_span_entry_cpu_configure,
@@ -214,6 +215,7 @@ mlxsw_sp_span_entry_phys_deconfigure(struct mlxsw_sp_span_entry *span_entry)
 
 static const
 struct mlxsw_sp_span_entry_ops mlxsw_sp_span_entry_ops_phys = {
+       .is_static = true,
        .can_handle = mlxsw_sp_port_dev_check,
        .parms_set = mlxsw_sp_span_entry_phys_parms,
        .configure = mlxsw_sp_span_entry_phys_configure,
@@ -721,6 +723,7 @@ mlxsw_sp2_span_entry_cpu_deconfigure(struct mlxsw_sp_span_entry *span_entry)
 
 static const
 struct mlxsw_sp_span_entry_ops mlxsw_sp2_span_entry_ops_cpu = {
+       .is_static = true,
        .can_handle = mlxsw_sp2_span_cpu_can_handle,
        .parms_set = mlxsw_sp2_span_entry_cpu_parms,
        .configure = mlxsw_sp2_span_entry_cpu_configure,
@@ -1036,6 +1039,9 @@ static void mlxsw_sp_span_respin_work(struct work_struct *work)
                if (!refcount_read(&curr->ref_count))
                        continue;
 
+               if (curr->ops->is_static)
+                       continue;
+
                err = curr->ops->parms_set(mlxsw_sp, curr->to_dev, &sparms);
                if (err)
                        continue;
index d907718..aa1cd40 100644 (file)
@@ -60,6 +60,7 @@ struct mlxsw_sp_span_entry {
 };
 
 struct mlxsw_sp_span_entry_ops {
+       bool is_static;
        bool (*can_handle)(const struct net_device *to_dev);
        int (*parms_set)(struct mlxsw_sp *mlxsw_sp,
                         const struct net_device *to_dev,
index 0b9992b..ff87a0b 100644 (file)
@@ -60,14 +60,27 @@ int ocelot_mact_learn(struct ocelot *ocelot, int port,
                      const unsigned char mac[ETH_ALEN],
                      unsigned int vid, enum macaccess_entry_type type)
 {
+       u32 cmd = ANA_TABLES_MACACCESS_VALID |
+               ANA_TABLES_MACACCESS_DEST_IDX(port) |
+               ANA_TABLES_MACACCESS_ENTRYTYPE(type) |
+               ANA_TABLES_MACACCESS_MAC_TABLE_CMD(MACACCESS_CMD_LEARN);
+       unsigned int mc_ports;
+
+       /* Set MAC_CPU_COPY if the CPU port is used by a multicast entry */
+       if (type == ENTRYTYPE_MACv4)
+               mc_ports = (mac[1] << 8) | mac[2];
+       else if (type == ENTRYTYPE_MACv6)
+               mc_ports = (mac[0] << 8) | mac[1];
+       else
+               mc_ports = 0;
+
+       if (mc_ports & BIT(ocelot->num_phys_ports))
+               cmd |= ANA_TABLES_MACACCESS_MAC_CPU_COPY;
+
        ocelot_mact_select(ocelot, mac, vid);
 
        /* Issue a write command */
-       ocelot_write(ocelot, ANA_TABLES_MACACCESS_VALID |
-                            ANA_TABLES_MACACCESS_DEST_IDX(port) |
-                            ANA_TABLES_MACACCESS_ENTRYTYPE(type) |
-                            ANA_TABLES_MACACCESS_MAC_TABLE_CMD(MACACCESS_CMD_LEARN),
-                            ANA_TABLES_MACACCESS);
+       ocelot_write(ocelot, cmd, ANA_TABLES_MACACCESS);
 
        return ocelot_mact_wait_for_completion(ocelot);
 }
index 2bd2840..42230f9 100644 (file)
@@ -1042,10 +1042,8 @@ static int ocelot_netdevice_event(struct notifier_block *unused,
        struct net_device *dev = netdev_notifier_info_to_dev(ptr);
        int ret = 0;
 
-       if (!ocelot_netdevice_dev_check(dev))
-               return 0;
-
        if (event == NETDEV_PRECHANGEUPPER &&
+           ocelot_netdevice_dev_check(dev) &&
            netif_is_lag_master(info->upper_dev)) {
                struct netdev_lag_upper_info *lag_upper_info = info->upper_info;
                struct netlink_ext_ack *extack;
index a569abe..0d78408 100644 (file)
@@ -4046,17 +4046,72 @@ err_out:
        return -EIO;
 }
 
-static bool rtl_test_hw_pad_bug(struct rtl8169_private *tp)
+static bool rtl_skb_is_udp(struct sk_buff *skb)
+{
+       int no = skb_network_offset(skb);
+       struct ipv6hdr *i6h, _i6h;
+       struct iphdr *ih, _ih;
+
+       switch (vlan_get_protocol(skb)) {
+       case htons(ETH_P_IP):
+               ih = skb_header_pointer(skb, no, sizeof(_ih), &_ih);
+               return ih && ih->protocol == IPPROTO_UDP;
+       case htons(ETH_P_IPV6):
+               i6h = skb_header_pointer(skb, no, sizeof(_i6h), &_i6h);
+               return i6h && i6h->nexthdr == IPPROTO_UDP;
+       default:
+               return false;
+       }
+}
+
+#define RTL_MIN_PATCH_LEN      47
+
+/* see rtl8125_get_patch_pad_len() in r8125 vendor driver */
+static unsigned int rtl8125_quirk_udp_padto(struct rtl8169_private *tp,
+                                           struct sk_buff *skb)
 {
+       unsigned int padto = 0, len = skb->len;
+
+       if (rtl_is_8125(tp) && len < 128 + RTL_MIN_PATCH_LEN &&
+           rtl_skb_is_udp(skb) && skb_transport_header_was_set(skb)) {
+               unsigned int trans_data_len = skb_tail_pointer(skb) -
+                                             skb_transport_header(skb);
+
+               if (trans_data_len >= offsetof(struct udphdr, len) &&
+                   trans_data_len < RTL_MIN_PATCH_LEN) {
+                       u16 dest = ntohs(udp_hdr(skb)->dest);
+
+                       /* dest is a standard PTP port */
+                       if (dest == 319 || dest == 320)
+                               padto = len + RTL_MIN_PATCH_LEN - trans_data_len;
+               }
+
+               if (trans_data_len < sizeof(struct udphdr))
+                       padto = max_t(unsigned int, padto,
+                                     len + sizeof(struct udphdr) - trans_data_len);
+       }
+
+       return padto;
+}
+
+static unsigned int rtl_quirk_packet_padto(struct rtl8169_private *tp,
+                                          struct sk_buff *skb)
+{
+       unsigned int padto;
+
+       padto = rtl8125_quirk_udp_padto(tp, skb);
+
        switch (tp->mac_version) {
        case RTL_GIGA_MAC_VER_34:
        case RTL_GIGA_MAC_VER_60:
        case RTL_GIGA_MAC_VER_61:
        case RTL_GIGA_MAC_VER_63:
-               return true;
+               padto = max_t(unsigned int, padto, ETH_ZLEN);
        default:
-               return false;
+               break;
        }
+
+       return padto;
 }
 
 static void rtl8169_tso_csum_v1(struct sk_buff *skb, u32 *opts)
@@ -4128,9 +4183,10 @@ static bool rtl8169_tso_csum_v2(struct rtl8169_private *tp,
 
                opts[1] |= transport_offset << TCPHO_SHIFT;
        } else {
-               if (unlikely(skb->len < ETH_ZLEN && rtl_test_hw_pad_bug(tp)))
-                       /* eth_skb_pad would free the skb on error */
-                       return !__skb_put_padto(skb, ETH_ZLEN, false);
+               unsigned int padto = rtl_quirk_packet_padto(tp, skb);
+
+               /* skb_padto would free the skb on error */
+               return !__skb_put_padto(skb, padto, false);
        }
 
        return true;
@@ -4307,6 +4363,9 @@ static netdev_features_t rtl8169_features_check(struct sk_buff *skb,
                if (skb->len < ETH_ZLEN)
                        features &= ~NETIF_F_CSUM_MASK;
 
+               if (rtl_quirk_packet_padto(tp, skb))
+                       features &= ~NETIF_F_CSUM_MASK;
+
                if (transport_offset > TCPHO_MAX &&
                    rtl_chip_supports_csum_v2(tp))
                        features &= ~NETIF_F_CSUM_MASK;
@@ -4645,10 +4704,10 @@ static int rtl8169_close(struct net_device *dev)
 
        cancel_work_sync(&tp->wk.work);
 
-       phy_disconnect(tp->phydev);
-
        free_irq(pci_irq_vector(pdev, 0), tp);
 
+       phy_disconnect(tp->phydev);
+
        dma_free_coherent(&pdev->dev, R8169_RX_RING_BYTES, tp->RxDescArray,
                          tp->RxPhyAddr);
        dma_free_coherent(&pdev->dev, R8169_TX_RING_BYTES, tp->TxDescArray,
index c633046..590b088 100644 (file)
@@ -2606,10 +2606,10 @@ static int sh_eth_close(struct net_device *ndev)
        /* Free all the skbuffs in the Rx queue and the DMA buffer. */
        sh_eth_ring_free(ndev);
 
-       pm_runtime_put_sync(&mdp->pdev->dev);
-
        mdp->is_opened = 0;
 
+       pm_runtime_put(&mdp->pdev->dev);
+
        return 0;
 }
 
@@ -3034,6 +3034,28 @@ static int sh_mdio_release(struct sh_eth_private *mdp)
        return 0;
 }
 
+static int sh_mdiobb_read(struct mii_bus *bus, int phy, int reg)
+{
+       int res;
+
+       pm_runtime_get_sync(bus->parent);
+       res = mdiobb_read(bus, phy, reg);
+       pm_runtime_put(bus->parent);
+
+       return res;
+}
+
+static int sh_mdiobb_write(struct mii_bus *bus, int phy, int reg, u16 val)
+{
+       int res;
+
+       pm_runtime_get_sync(bus->parent);
+       res = mdiobb_write(bus, phy, reg, val);
+       pm_runtime_put(bus->parent);
+
+       return res;
+}
+
 /* MDIO bus init function */
 static int sh_mdio_init(struct sh_eth_private *mdp,
                        struct sh_eth_plat_data *pd)
@@ -3058,6 +3080,10 @@ static int sh_mdio_init(struct sh_eth_private *mdp,
        if (!mdp->mii_bus)
                return -ENOMEM;
 
+       /* Wrap accessors with Runtime PM-aware ops */
+       mdp->mii_bus->read = sh_mdiobb_read;
+       mdp->mii_bus->write = sh_mdiobb_write;
+
        /* Hook up MII support for ethtool */
        mdp->mii_bus->name = "sh_mii";
        mdp->mii_bus->parent = dev;
index 82b1c7a..ba0e4d2 100644 (file)
@@ -129,7 +129,7 @@ static int intel_eth_plat_probe(struct platform_device *pdev)
                                if (ret) {
                                        dev_err(&pdev->dev,
                                                "Failed to set tx_clk\n");
-                                       return ret;
+                                       goto err_remove_config_dt;
                                }
                        }
                }
@@ -143,7 +143,7 @@ static int intel_eth_plat_probe(struct platform_device *pdev)
                        if (ret) {
                                dev_err(&pdev->dev,
                                        "Failed to set clk_ptp_ref\n");
-                               return ret;
+                               goto err_remove_config_dt;
                        }
                }
        }
index 9a6a519..103d244 100644 (file)
@@ -375,6 +375,7 @@ static int ehl_pse0_common_data(struct pci_dev *pdev,
                                struct plat_stmmacenet_data *plat)
 {
        plat->bus_id = 2;
+       plat->addr64 = 32;
        return ehl_common_data(pdev, plat);
 }
 
@@ -406,6 +407,7 @@ static int ehl_pse1_common_data(struct pci_dev *pdev,
                                struct plat_stmmacenet_data *plat)
 {
        plat->bus_id = 3;
+       plat->addr64 = 32;
        return ehl_common_data(pdev, plat);
 }
 
index 14d9a79..34e5f21 100644 (file)
@@ -440,7 +440,7 @@ static void gsi_evt_ring_de_alloc_command(struct gsi *gsi, u32 evt_ring_id)
 static enum gsi_channel_state gsi_channel_state(struct gsi_channel *channel)
 {
        u32 channel_id = gsi_channel_id(channel);
-       void *virt = channel->gsi->virt;
+       void __iomem *virt = channel->gsi->virt;
        u32 val;
 
        val = ioread32(virt + GSI_CH_C_CNTXT_0_OFFSET(channel_id));
@@ -1373,7 +1373,7 @@ static int gsi_ring_alloc(struct gsi *gsi, struct gsi_ring *ring, u32 count)
        /* Hardware requires a 2^n ring size, with alignment equal to size */
        ring->virt = dma_alloc_coherent(dev, size, &addr, GFP_KERNEL);
        if (ring->virt && addr % size) {
-               dma_free_coherent(dev, size, ring->virt, ring->addr);
+               dma_free_coherent(dev, size, ring->virt, addr);
                dev_err(dev, "unable to alloc 0x%zx-aligned ring buffer\n",
                        size);
                return -EINVAL; /* Not a good error value, but distinct */
index 9f4be98..612afec 100644 (file)
@@ -588,7 +588,7 @@ static void ipa_endpoint_init_hdr_metadata_mask(struct ipa_endpoint *endpoint)
 
        /* Note that HDR_ENDIANNESS indicates big endian header fields */
        if (endpoint->data->qmap)
-               val = cpu_to_be32(IPA_ENDPOINT_QMAP_METADATA_MASK);
+               val = (__force u32)cpu_to_be32(IPA_ENDPOINT_QMAP_METADATA_MASK);
 
        iowrite32(val, endpoint->ipa->reg_virt + offset);
 }
@@ -1164,8 +1164,8 @@ static bool ipa_endpoint_status_skip(struct ipa_endpoint *endpoint,
                return true;
        if (!status->pkt_len)
                return true;
-       endpoint_id = u32_get_bits(status->endp_dst_idx,
-                                  IPA_STATUS_DST_IDX_FMASK);
+       endpoint_id = u8_get_bits(status->endp_dst_idx,
+                                 IPA_STATUS_DST_IDX_FMASK);
        if (endpoint_id != endpoint->endpoint_id)
                return true;
 
index 0cc3a33..f25029b 100644 (file)
@@ -336,7 +336,7 @@ static void ipa_imem_exit(struct ipa *ipa)
 
                size = iommu_unmap(domain, ipa->imem_iova, ipa->imem_size);
                if (size != ipa->imem_size)
-                       dev_warn(dev, "unmapped %zu IMEM bytes, expected %lu\n",
+                       dev_warn(dev, "unmapped %zu IMEM bytes, expected %zu\n",
                                 size, ipa->imem_size);
        } else {
                dev_err(dev, "couldn't get IPA IOMMU domain for IMEM\n");
@@ -440,7 +440,7 @@ static void ipa_smem_exit(struct ipa *ipa)
 
                size = iommu_unmap(domain, ipa->smem_iova, ipa->smem_size);
                if (size != ipa->smem_size)
-                       dev_warn(dev, "unmapped %zu SMEM bytes, expected %lu\n",
+                       dev_warn(dev, "unmapped %zu SMEM bytes, expected %zu\n",
                                 size, ipa->smem_size);
 
        } else {
index 5136275..d3915f8 100644 (file)
@@ -149,7 +149,7 @@ static int mdiobb_cmd_addr(struct mdiobb_ctrl *ctrl, int phy, u32 addr)
        return dev_addr;
 }
 
-static int mdiobb_read(struct mii_bus *bus, int phy, int reg)
+int mdiobb_read(struct mii_bus *bus, int phy, int reg)
 {
        struct mdiobb_ctrl *ctrl = bus->priv;
        int ret, i;
@@ -180,8 +180,9 @@ static int mdiobb_read(struct mii_bus *bus, int phy, int reg)
        mdiobb_get_bit(ctrl);
        return ret;
 }
+EXPORT_SYMBOL(mdiobb_read);
 
-static int mdiobb_write(struct mii_bus *bus, int phy, int reg, u16 val)
+int mdiobb_write(struct mii_bus *bus, int phy, int reg, u16 val)
 {
        struct mdiobb_ctrl *ctrl = bus->priv;
 
@@ -201,6 +202,7 @@ static int mdiobb_write(struct mii_bus *bus, int phy, int reg, u16 val)
        mdiobb_get_bit(ctrl);
        return 0;
 }
+EXPORT_SYMBOL(mdiobb_write);
 
 struct mii_bus *alloc_mdio_bitbang(struct mdiobb_ctrl *ctrl)
 {
index c19dac2..dd7917c 100644 (file)
@@ -992,7 +992,8 @@ static void __team_compute_features(struct team *team)
        unsigned int dst_release_flag = IFF_XMIT_DST_RELEASE |
                                        IFF_XMIT_DST_RELEASE_PERM;
 
-       list_for_each_entry(port, &team->port_list, list) {
+       rcu_read_lock();
+       list_for_each_entry_rcu(port, &team->port_list, list) {
                vlan_features = netdev_increment_features(vlan_features,
                                        port->dev->vlan_features,
                                        TEAM_VLAN_FEATURES);
@@ -1006,6 +1007,7 @@ static void __team_compute_features(struct team *team)
                if (port->dev->hard_header_len > max_hard_header_len)
                        max_hard_header_len = port->dev->hard_header_len;
        }
+       rcu_read_unlock();
 
        team->dev->vlan_features = vlan_features;
        team->dev->hw_enc_features = enc_features | NETIF_F_GSO_ENCAP_ALL |
@@ -1020,9 +1022,7 @@ static void __team_compute_features(struct team *team)
 
 static void team_compute_features(struct team *team)
 {
-       mutex_lock(&team->lock);
        __team_compute_features(team);
-       mutex_unlock(&team->lock);
        netdev_change_features(team->dev);
 }
 
index 6aaa067..a9b5510 100644 (file)
@@ -968,6 +968,12 @@ static const struct usb_device_id  products[] = {
                                      USB_CDC_SUBCLASS_ETHERNET,
                                      USB_CDC_PROTO_NONE),
        .driver_info = (unsigned long)&wwan_info,
+}, {
+       /* Cinterion PLS83/PLS63 modem by GEMALTO/THALES */
+       USB_DEVICE_AND_INTERFACE_INFO(0x1e2d, 0x0069, USB_CLASS_COMM,
+                                     USB_CDC_SUBCLASS_ETHERNET,
+                                     USB_CDC_PROTO_NONE),
+       .driver_info = (unsigned long)&wwan_info,
 }, {
        USB_INTERFACE_INFO(USB_CLASS_COMM, USB_CDC_SUBCLASS_ETHERNET,
                        USB_CDC_PROTO_NONE),
index 5a78848..291e76d 100644 (file)
@@ -1827,6 +1827,15 @@ cdc_ncm_speed_change(struct usbnet *dev,
        uint32_t rx_speed = le32_to_cpu(data->DLBitRRate);
        uint32_t tx_speed = le32_to_cpu(data->ULBitRate);
 
+       /* if the speed hasn't changed, don't report it.
+        * RTL8156 shipped before 2021 sends notification about every 32ms.
+        */
+       if (dev->rx_speed == rx_speed && dev->tx_speed == tx_speed)
+               return;
+
+       dev->rx_speed = rx_speed;
+       dev->tx_speed = tx_speed;
+
        /*
         * Currently the USB-NET API does not support reporting the actual
         * device speed. Do print it instead.
@@ -1867,7 +1876,8 @@ static void cdc_ncm_status(struct usbnet *dev, struct urb *urb)
                 * USB_CDC_NOTIFY_NETWORK_CONNECTION notification shall be
                 * sent by device after USB_CDC_NOTIFY_SPEED_CHANGE.
                 */
-               usbnet_link_change(dev, !!event->wValue, 0);
+               if (netif_carrier_ok(dev->net) != !!event->wValue)
+                       usbnet_link_change(dev, !!event->wValue, 0);
                break;
 
        case USB_CDC_NOTIFY_SPEED_CHANGE:
index af19513..cc48192 100644 (file)
@@ -1302,6 +1302,7 @@ static const struct usb_device_id products[] = {
        {QMI_FIXED_INTF(0x0b3c, 0xc00a, 6)},    /* Olivetti Olicard 160 */
        {QMI_FIXED_INTF(0x0b3c, 0xc00b, 4)},    /* Olivetti Olicard 500 */
        {QMI_FIXED_INTF(0x1e2d, 0x0060, 4)},    /* Cinterion PLxx */
+       {QMI_QUIRK_SET_DTR(0x1e2d, 0x006f, 8)}, /* Cinterion PLS83/PLS63 */
        {QMI_FIXED_INTF(0x1e2d, 0x0053, 4)},    /* Cinterion PHxx,PXxx */
        {QMI_FIXED_INTF(0x1e2d, 0x0063, 10)},   /* Cinterion ALASxx (1 RmNet) */
        {QMI_FIXED_INTF(0x1e2d, 0x0082, 4)},    /* Cinterion PHxx,PXxx (2 RmNet) */
index 7220fc8..8280092 100644 (file)
@@ -314,6 +314,7 @@ const struct iwl_cfg_trans_params iwl_ma_trans_cfg = {
 const char iwl_ax101_name[] = "Intel(R) Wi-Fi 6 AX101";
 const char iwl_ax200_name[] = "Intel(R) Wi-Fi 6 AX200 160MHz";
 const char iwl_ax201_name[] = "Intel(R) Wi-Fi 6 AX201 160MHz";
+const char iwl_ax203_name[] = "Intel(R) Wi-Fi 6 AX203";
 const char iwl_ax211_name[] = "Intel(R) Wi-Fi 6 AX211 160MHz";
 const char iwl_ax411_name[] = "Intel(R) Wi-Fi 6 AX411 160MHz";
 const char iwl_ma_name[] = "Intel(R) Wi-Fi 6";
@@ -340,6 +341,18 @@ const struct iwl_cfg iwl_qu_b0_hr1_b0 = {
        .num_rbds = IWL_NUM_RBDS_22000_HE,
 };
 
+const struct iwl_cfg iwl_qu_b0_hr_b0 = {
+       .fw_name_pre = IWL_QU_B_HR_B_FW_PRE,
+       IWL_DEVICE_22500,
+       /*
+        * This device doesn't support receiving BlockAck with a large bitmap
+        * so we need to restrict the size of transmitted aggregation to the
+        * HT size; mac80211 would otherwise pick the HE max (256) by default.
+        */
+       .max_tx_agg_size = IEEE80211_MAX_AMPDU_BUF_HT,
+       .num_rbds = IWL_NUM_RBDS_22000_HE,
+};
+
 const struct iwl_cfg iwl_ax201_cfg_qu_hr = {
        .name = "Intel(R) Wi-Fi 6 AX201 160MHz",
        .fw_name_pre = IWL_QU_B_HR_B_FW_PRE,
@@ -366,6 +379,18 @@ const struct iwl_cfg iwl_qu_c0_hr1_b0 = {
        .num_rbds = IWL_NUM_RBDS_22000_HE,
 };
 
+const struct iwl_cfg iwl_qu_c0_hr_b0 = {
+       .fw_name_pre = IWL_QU_C_HR_B_FW_PRE,
+       IWL_DEVICE_22500,
+       /*
+        * This device doesn't support receiving BlockAck with a large bitmap
+        * so we need to restrict the size of transmitted aggregation to the
+        * HT size; mac80211 would otherwise pick the HE max (256) by default.
+        */
+       .max_tx_agg_size = IEEE80211_MAX_AMPDU_BUF_HT,
+       .num_rbds = IWL_NUM_RBDS_22000_HE,
+};
+
 const struct iwl_cfg iwl_ax201_cfg_qu_c0_hr_b0 = {
        .name = "Intel(R) Wi-Fi 6 AX201 160MHz",
        .fw_name_pre = IWL_QU_C_HR_B_FW_PRE,
index 15248b0..d8b7776 100644 (file)
@@ -80,19 +80,45 @@ static void *iwl_acpi_get_dsm_object(struct device *dev, int rev, int func,
 }
 
 /*
- * Evaluate a DSM with no arguments and a single u8 return value (inside a
- * buffer object), verify and return that value.
+ * Generic function to evaluate a DSM with no arguments
+ * and an integer return value,
+ * (as an integer object or inside a buffer object),
+ * verify and assign the value in the "value" parameter.
+ * return 0 in success and the appropriate errno otherwise.
  */
-int iwl_acpi_get_dsm_u8(struct device *dev, int rev, int func)
+static int iwl_acpi_get_dsm_integer(struct device *dev, int rev, int func,
+                                   u64 *value, size_t expected_size)
 {
        union acpi_object *obj;
-       int ret;
+       int ret = 0;
 
        obj = iwl_acpi_get_dsm_object(dev, rev, func, NULL);
-       if (IS_ERR(obj))
+       if (IS_ERR(obj)) {
+               IWL_DEBUG_DEV_RADIO(dev,
+                                   "Failed to get  DSM object. func= %d\n",
+                                   func);
                return -ENOENT;
+       }
+
+       if (obj->type == ACPI_TYPE_INTEGER) {
+               *value = obj->integer.value;
+       } else if (obj->type == ACPI_TYPE_BUFFER) {
+               __le64 le_value = 0;
 
-       if (obj->type != ACPI_TYPE_BUFFER) {
+               if (WARN_ON_ONCE(expected_size > sizeof(le_value)))
+                       return -EINVAL;
+
+               /* if the buffer size doesn't match the expected size */
+               if (obj->buffer.length != expected_size)
+                       IWL_DEBUG_DEV_RADIO(dev,
+                                           "ACPI: DSM invalid buffer size, padding or truncating (%d)\n",
+                                           obj->buffer.length);
+
+                /* assuming LE from Intel BIOS spec */
+               memcpy(&le_value, obj->buffer.pointer,
+                      min_t(size_t, expected_size, (size_t)obj->buffer.length));
+               *value = le64_to_cpu(le_value);
+       } else {
                IWL_DEBUG_DEV_RADIO(dev,
                                    "ACPI: DSM method did not return a valid object, type=%d\n",
                                    obj->type);
@@ -100,15 +126,6 @@ int iwl_acpi_get_dsm_u8(struct device *dev, int rev, int func)
                goto out;
        }
 
-       if (obj->buffer.length != sizeof(u8)) {
-               IWL_DEBUG_DEV_RADIO(dev,
-                                   "ACPI: DSM method returned invalid buffer, length=%d\n",
-                                   obj->buffer.length);
-               ret = -EINVAL;
-               goto out;
-       }
-
-       ret = obj->buffer.pointer[0];
        IWL_DEBUG_DEV_RADIO(dev,
                            "ACPI: DSM method evaluated: func=%d, ret=%d\n",
                            func, ret);
@@ -116,6 +133,24 @@ out:
        ACPI_FREE(obj);
        return ret;
 }
+
+/*
+ * Evaluate a DSM with no arguments and a u8 return value,
+ */
+int iwl_acpi_get_dsm_u8(struct device *dev, int rev, int func, u8 *value)
+{
+       int ret;
+       u64 val;
+
+       ret = iwl_acpi_get_dsm_integer(dev, rev, func, &val, sizeof(u8));
+
+       if (ret < 0)
+               return ret;
+
+       /* cast val (u64) to be u8 */
+       *value = (u8)val;
+       return 0;
+}
 IWL_EXPORT_SYMBOL(iwl_acpi_get_dsm_u8);
 
 union acpi_object *iwl_acpi_get_wifi_pkg(struct device *dev,
index 042dd24..1cce30d 100644 (file)
@@ -1,7 +1,7 @@
 /* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */
 /*
  * Copyright (C) 2017 Intel Deutschland GmbH
- * Copyright (C) 2018-2020 Intel Corporation
+ * Copyright (C) 2018-2021 Intel Corporation
  */
 #ifndef __iwl_fw_acpi__
 #define __iwl_fw_acpi__
@@ -99,7 +99,7 @@ struct iwl_fw_runtime;
 
 void *iwl_acpi_get_object(struct device *dev, acpi_string method);
 
-int iwl_acpi_get_dsm_u8(struct device *dev, int rev, int func);
+int iwl_acpi_get_dsm_u8(struct device *dev, int rev, int func, u8 *value);
 
 union acpi_object *iwl_acpi_get_wifi_pkg(struct device *dev,
                                         union acpi_object *data,
@@ -159,7 +159,8 @@ static inline void *iwl_acpi_get_dsm_object(struct device *dev, int rev,
        return ERR_PTR(-ENOENT);
 }
 
-static inline int iwl_acpi_get_dsm_u8(struct device *dev, int rev, int func)
+static inline
+int iwl_acpi_get_dsm_u8(struct device *dev, int rev, int func, u8 *value)
 {
        return -ENOENT;
 }
index 6d8f7bf..895a907 100644 (file)
@@ -224,40 +224,46 @@ static int iwl_pnvm_parse(struct iwl_trans *trans, const u8 *data,
 int iwl_pnvm_load(struct iwl_trans *trans,
                  struct iwl_notif_wait_data *notif_wait)
 {
-       const struct firmware *pnvm;
        struct iwl_notification_wait pnvm_wait;
        static const u16 ntf_cmds[] = { WIDE_ID(REGULATORY_AND_NVM_GROUP,
                                                PNVM_INIT_COMPLETE_NTFY) };
-       char pnvm_name[64];
-       int ret;
 
        /* if the SKU_ID is empty, there's nothing to do */
        if (!trans->sku_id[0] && !trans->sku_id[1] && !trans->sku_id[2])
                return 0;
 
-       /* if we already have it, nothing to do either */
-       if (trans->pnvm_loaded)
-               return 0;
+       /* load from disk only if we haven't done it (or tried) before */
+       if (!trans->pnvm_loaded) {
+               const struct firmware *pnvm;
+               char pnvm_name[64];
+               int ret;
+
+               /*
+                * The prefix unfortunately includes a hyphen at the end, so
+                * don't add the dot here...
+                */
+               snprintf(pnvm_name, sizeof(pnvm_name), "%spnvm",
+                        trans->cfg->fw_name_pre);
+
+               /* ...but replace the hyphen with the dot here. */
+               if (strlen(trans->cfg->fw_name_pre) < sizeof(pnvm_name))
+                       pnvm_name[strlen(trans->cfg->fw_name_pre) - 1] = '.';
+
+               ret = firmware_request_nowarn(&pnvm, pnvm_name, trans->dev);
+               if (ret) {
+                       IWL_DEBUG_FW(trans, "PNVM file %s not found %d\n",
+                                    pnvm_name, ret);
+                       /*
+                        * Pretend we've loaded it - at least we've tried and
+                        * couldn't load it at all, so there's no point in
+                        * trying again over and over.
+                        */
+                       trans->pnvm_loaded = true;
+               } else {
+                       iwl_pnvm_parse(trans, pnvm->data, pnvm->size);
 
-       /*
-        * The prefix unfortunately includes a hyphen at the end, so
-        * don't add the dot here...
-        */
-       snprintf(pnvm_name, sizeof(pnvm_name), "%spnvm",
-                trans->cfg->fw_name_pre);
-
-       /* ...but replace the hyphen with the dot here. */
-       if (strlen(trans->cfg->fw_name_pre) < sizeof(pnvm_name))
-               pnvm_name[strlen(trans->cfg->fw_name_pre) - 1] = '.';
-
-       ret = firmware_request_nowarn(&pnvm, pnvm_name, trans->dev);
-       if (ret) {
-               IWL_DEBUG_FW(trans, "PNVM file %s not found %d\n",
-                            pnvm_name, ret);
-       } else {
-               iwl_pnvm_parse(trans, pnvm->data, pnvm->size);
-
-               release_firmware(pnvm);
+                       release_firmware(pnvm);
+               }
        }
 
        iwl_init_notification_wait(notif_wait, &pnvm_wait,
index 27cb040..86e1d57 100644 (file)
@@ -1,6 +1,6 @@
 /* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */
 /*
- * Copyright (C) 2005-2014, 2018-2020 Intel Corporation
+ * Copyright (C) 2005-2014, 2018-2021 Intel Corporation
  * Copyright (C) 2016-2017 Intel Deutschland GmbH
  */
 #ifndef __IWL_CONFIG_H__
@@ -445,7 +445,7 @@ struct iwl_cfg {
 #define IWL_CFG_CORES_BT_GNSS          0x5
 
 #define IWL_SUBDEVICE_RF_ID(subdevice) ((u16)((subdevice) & 0x00F0) >> 4)
-#define IWL_SUBDEVICE_NO_160(subdevice)        ((u16)((subdevice) & 0x0100) >> 9)
+#define IWL_SUBDEVICE_NO_160(subdevice)        ((u16)((subdevice) & 0x0200) >> 9)
 #define IWL_SUBDEVICE_CORES(subdevice) ((u16)((subdevice) & 0x1C00) >> 10)
 
 struct iwl_dev_info {
@@ -491,6 +491,7 @@ extern const char iwl9260_killer_1550_name[];
 extern const char iwl9560_killer_1550i_name[];
 extern const char iwl9560_killer_1550s_name[];
 extern const char iwl_ax200_name[];
+extern const char iwl_ax203_name[];
 extern const char iwl_ax201_name[];
 extern const char iwl_ax101_name[];
 extern const char iwl_ax200_killer_1650w_name[];
@@ -574,6 +575,8 @@ extern const struct iwl_cfg iwl9560_2ac_cfg_soc;
 extern const struct iwl_cfg iwl_qu_b0_hr1_b0;
 extern const struct iwl_cfg iwl_qu_c0_hr1_b0;
 extern const struct iwl_cfg iwl_quz_a0_hr1_b0;
+extern const struct iwl_cfg iwl_qu_b0_hr_b0;
+extern const struct iwl_cfg iwl_qu_c0_hr_b0;
 extern const struct iwl_cfg iwl_ax200_cfg_cc;
 extern const struct iwl_cfg iwl_ax201_cfg_qu_hr;
 extern const struct iwl_cfg iwl_ax201_cfg_qu_hr;
index a654147..a80a35a 100644 (file)
@@ -180,13 +180,6 @@ static int iwl_dbg_tlv_alloc_region(struct iwl_trans *trans,
        if (le32_to_cpu(tlv->length) < sizeof(*reg))
                return -EINVAL;
 
-       /* For safe using a string from FW make sure we have a
-        * null terminator
-        */
-       reg->name[IWL_FW_INI_MAX_NAME - 1] = 0;
-
-       IWL_DEBUG_FW(trans, "WRT: parsing region: %s\n", reg->name);
-
        if (id >= IWL_FW_INI_MAX_REGION_ID) {
                IWL_ERR(trans, "WRT: Invalid region id %u\n", id);
                return -EINVAL;
index 2ac20d0..2b7ef15 100644 (file)
@@ -150,16 +150,17 @@ u32 iwl_read_prph(struct iwl_trans *trans, u32 ofs)
 }
 IWL_EXPORT_SYMBOL(iwl_read_prph);
 
-void iwl_write_prph(struct iwl_trans *trans, u32 ofs, u32 val)
+void iwl_write_prph_delay(struct iwl_trans *trans, u32 ofs, u32 val, u32 delay_ms)
 {
        unsigned long flags;
 
        if (iwl_trans_grab_nic_access(trans, &flags)) {
+               mdelay(delay_ms);
                iwl_write_prph_no_grab(trans, ofs, val);
                iwl_trans_release_nic_access(trans, &flags);
        }
 }
-IWL_EXPORT_SYMBOL(iwl_write_prph);
+IWL_EXPORT_SYMBOL(iwl_write_prph_delay);
 
 int iwl_poll_prph_bit(struct iwl_trans *trans, u32 addr,
                      u32 bits, u32 mask, int timeout)
@@ -219,8 +220,8 @@ IWL_EXPORT_SYMBOL(iwl_clear_bits_prph);
 void iwl_force_nmi(struct iwl_trans *trans)
 {
        if (trans->trans_cfg->device_family < IWL_DEVICE_FAMILY_9000)
-               iwl_write_prph(trans, DEVICE_SET_NMI_REG,
-                              DEVICE_SET_NMI_VAL_DRV);
+               iwl_write_prph_delay(trans, DEVICE_SET_NMI_REG,
+                                    DEVICE_SET_NMI_VAL_DRV, 1);
        else if (trans->trans_cfg->device_family < IWL_DEVICE_FAMILY_AX210)
                iwl_write_umac_prph(trans, UREG_NIC_SET_NMI_DRIVER,
                                UREG_NIC_SET_NMI_DRIVER_NMI_FROM_DRIVER);
index 39bceee..3c21c0e 100644 (file)
@@ -1,6 +1,6 @@
 /* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */
 /*
- * Copyright (C) 2018-2019 Intel Corporation
+ * Copyright (C) 2018-2020 Intel Corporation
  */
 #ifndef __iwl_io_h__
 #define __iwl_io_h__
@@ -37,7 +37,13 @@ u32 iwl_read_prph_no_grab(struct iwl_trans *trans, u32 ofs);
 u32 iwl_read_prph(struct iwl_trans *trans, u32 ofs);
 void iwl_write_prph_no_grab(struct iwl_trans *trans, u32 ofs, u32 val);
 void iwl_write_prph64_no_grab(struct iwl_trans *trans, u64 ofs, u64 val);
-void iwl_write_prph(struct iwl_trans *trans, u32 ofs, u32 val);
+void iwl_write_prph_delay(struct iwl_trans *trans, u32 ofs,
+                         u32 val, u32 delay_ms);
+static inline void iwl_write_prph(struct iwl_trans *trans, u32 ofs, u32 val)
+{
+       iwl_write_prph_delay(trans, ofs, val, 0);
+}
+
 int iwl_poll_prph_bit(struct iwl_trans *trans, u32 addr,
                      u32 bits, u32 mask, int timeout);
 void iwl_set_bits_prph(struct iwl_trans *trans, u32 ofs, u32 mask);
index 0b03fde..1158e25 100644 (file)
 #define RADIO_RSP_ADDR_POS             (6)
 #define RADIO_RSP_RD_CMD               (3)
 
+/* LTR control (Qu only) */
+#define HPM_MAC_LTR_CSR                        0xa0348c
+#define HPM_MAC_LRT_ENABLE_ALL         0xf
+/* also uses CSR_LTR_* for values */
+#define HPM_UMAC_LTR                   0xa03480
+
 /* FW monitor */
 #define MON_BUFF_SAMPLE_CTL            (0xa03c00)
 #define MON_BUFF_BASE_ADDR             (0xa03c1c)
index c025188..df01897 100644 (file)
@@ -1,6 +1,6 @@
 // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
 /*
- * Copyright (C) 2012-2014, 2018-2020 Intel Corporation
+ * Copyright (C) 2012-2014, 2018-2021 Intel Corporation
  * Copyright (C) 2013-2015 Intel Mobile Communications GmbH
  * Copyright (C) 2016-2017 Intel Deutschland GmbH
  */
@@ -2032,8 +2032,6 @@ static int __iwl_mvm_resume(struct iwl_mvm *mvm, bool test)
 
        mutex_lock(&mvm->mutex);
 
-       clear_bit(IWL_MVM_STATUS_IN_D3, &mvm->status);
-
        /* get the BSS vif pointer again */
        vif = iwl_mvm_get_bss_vif(mvm);
        if (IS_ERR_OR_NULL(vif))
@@ -2148,6 +2146,8 @@ out_iterate:
                        iwl_mvm_d3_disconnect_iter, keep ? vif : NULL);
 
 out:
+       clear_bit(IWL_MVM_STATUS_IN_D3, &mvm->status);
+
        /* no need to reset the device in unified images, if successful */
        if (unified_image && !ret) {
                /* nothing else to do if we already sent D0I3_END_CMD */
index 573e469..38d0bfb 100644 (file)
@@ -459,7 +459,10 @@ static ssize_t iwl_dbgfs_os_device_timediff_read(struct file *file,
        const size_t bufsz = sizeof(buf);
        int pos = 0;
 
+       mutex_lock(&mvm->mutex);
        iwl_mvm_get_sync_time(mvm, &curr_gp2, &curr_os);
+       mutex_unlock(&mvm->mutex);
+
        do_div(curr_os, NSEC_PER_USEC);
        diff = curr_os - curr_gp2;
        pos += scnprintf(buf + pos, bufsz - pos, "diff=%lld\n", diff);
index 0637eb1..313e9f1 100644 (file)
@@ -1090,20 +1090,22 @@ static void iwl_mvm_tas_init(struct iwl_mvm *mvm)
 
 static u8 iwl_mvm_eval_dsm_indonesia_5g2(struct iwl_mvm *mvm)
 {
+       u8 value;
+
        int ret = iwl_acpi_get_dsm_u8((&mvm->fwrt)->dev, 0,
-                                     DSM_FUNC_ENABLE_INDONESIA_5G2);
+                                     DSM_FUNC_ENABLE_INDONESIA_5G2, &value);
 
        if (ret < 0)
                IWL_DEBUG_RADIO(mvm,
                                "Failed to evaluate DSM function ENABLE_INDONESIA_5G2, ret=%d\n",
                                ret);
 
-       else if (ret >= DSM_VALUE_INDONESIA_MAX)
+       else if (value >= DSM_VALUE_INDONESIA_MAX)
                IWL_DEBUG_RADIO(mvm,
-                               "DSM function ENABLE_INDONESIA_5G2 return invalid value, ret=%d\n",
-                               ret);
+                               "DSM function ENABLE_INDONESIA_5G2 return invalid value, value=%d\n",
+                               value);
 
-       else if (ret == DSM_VALUE_INDONESIA_ENABLE) {
+       else if (value == DSM_VALUE_INDONESIA_ENABLE) {
                IWL_DEBUG_RADIO(mvm,
                                "Evaluated DSM function ENABLE_INDONESIA_5G2: Enabling 5g2\n");
                return DSM_VALUE_INDONESIA_ENABLE;
@@ -1114,25 +1116,26 @@ static u8 iwl_mvm_eval_dsm_indonesia_5g2(struct iwl_mvm *mvm)
 
 static u8 iwl_mvm_eval_dsm_disable_srd(struct iwl_mvm *mvm)
 {
+       u8 value;
        int ret = iwl_acpi_get_dsm_u8((&mvm->fwrt)->dev, 0,
-                                     DSM_FUNC_DISABLE_SRD);
+                                     DSM_FUNC_DISABLE_SRD, &value);
 
        if (ret < 0)
                IWL_DEBUG_RADIO(mvm,
                                "Failed to evaluate DSM function DISABLE_SRD, ret=%d\n",
                                ret);
 
-       else if (ret >= DSM_VALUE_SRD_MAX)
+       else if (value >= DSM_VALUE_SRD_MAX)
                IWL_DEBUG_RADIO(mvm,
-                               "DSM function DISABLE_SRD return invalid value, ret=%d\n",
-                               ret);
+                               "DSM function DISABLE_SRD return invalid value, value=%d\n",
+                               value);
 
-       else if (ret == DSM_VALUE_SRD_PASSIVE) {
+       else if (value == DSM_VALUE_SRD_PASSIVE) {
                IWL_DEBUG_RADIO(mvm,
                                "Evaluated DSM function DISABLE_SRD: setting SRD to passive\n");
                return DSM_VALUE_SRD_PASSIVE;
 
-       } else if (ret == DSM_VALUE_SRD_DISABLE) {
+       } else if (value == DSM_VALUE_SRD_DISABLE) {
                IWL_DEBUG_RADIO(mvm,
                                "Evaluated DSM function DISABLE_SRD: disabling SRD\n");
                return DSM_VALUE_SRD_DISABLE;
index da32937..43ff040 100644 (file)
@@ -4194,6 +4194,9 @@ static void __iwl_mvm_unassign_vif_chanctx(struct iwl_mvm *mvm,
        iwl_mvm_binding_remove_vif(mvm, vif);
 
 out:
+       if (fw_has_capa(&mvm->fw->ucode_capa, IWL_UCODE_TLV_CAPA_CHANNEL_SWITCH_CMD) &&
+           switching_chanctx)
+               return;
        mvmvif->phy_ctxt = NULL;
        iwl_mvm_power_update_mac(mvm);
 }
index 98f62d7..61618f6 100644 (file)
@@ -791,6 +791,10 @@ iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg,
        if (!mvm->scan_cmd)
                goto out_free;
 
+       /* invalidate ids to prevent accidental removal of sta_id 0 */
+       mvm->aux_sta.sta_id = IWL_MVM_INVALID_STA;
+       mvm->snif_sta.sta_id = IWL_MVM_INVALID_STA;
+
        /* Set EBS as successful as long as not stated otherwise by the FW. */
        mvm->last_ebs_successful = true;
 
@@ -1205,6 +1209,7 @@ static void iwl_mvm_reprobe_wk(struct work_struct *wk)
        reprobe = container_of(wk, struct iwl_mvm_reprobe, work);
        if (device_reprobe(reprobe->dev))
                dev_err(reprobe->dev, "reprobe failed!\n");
+       put_device(reprobe->dev);
        kfree(reprobe);
        module_put(THIS_MODULE);
 }
@@ -1255,7 +1260,7 @@ void iwl_mvm_nic_restart(struct iwl_mvm *mvm, bool fw_error)
                        module_put(THIS_MODULE);
                        return;
                }
-               reprobe->dev = mvm->trans->dev;
+               reprobe->dev = get_device(mvm->trans->dev);
                INIT_WORK(&reprobe->work, iwl_mvm_reprobe_wk);
                schedule_work(&reprobe->work);
        } else if (test_bit(IWL_MVM_STATUS_HW_RESTART_REQUESTED,
index dc17441..578c353 100644 (file)
@@ -2057,6 +2057,9 @@ int iwl_mvm_rm_snif_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif)
 
        lockdep_assert_held(&mvm->mutex);
 
+       if (WARN_ON_ONCE(mvm->snif_sta.sta_id == IWL_MVM_INVALID_STA))
+               return -EINVAL;
+
        iwl_mvm_disable_txq(mvm, NULL, mvm->snif_queue, IWL_MAX_TID_COUNT, 0);
        ret = iwl_mvm_rm_sta_common(mvm, mvm->snif_sta.sta_id);
        if (ret)
@@ -2071,6 +2074,9 @@ int iwl_mvm_rm_aux_sta(struct iwl_mvm *mvm)
 
        lockdep_assert_held(&mvm->mutex);
 
+       if (WARN_ON_ONCE(mvm->aux_sta.sta_id == IWL_MVM_INVALID_STA))
+               return -EINVAL;
+
        iwl_mvm_disable_txq(mvm, NULL, mvm->aux_queue, IWL_MAX_TID_COUNT, 0);
        ret = iwl_mvm_rm_sta_common(mvm, mvm->aux_sta.sta_id);
        if (ret)
index a983c21..3712adc 100644 (file)
@@ -773,6 +773,7 @@ iwl_mvm_tx_tso_segment(struct sk_buff *skb, unsigned int num_subframes,
 
        next = skb_gso_segment(skb, netdev_flags);
        skb_shinfo(skb)->gso_size = mss;
+       skb_shinfo(skb)->gso_type = ipv4 ? SKB_GSO_TCPV4 : SKB_GSO_TCPV6;
        if (WARN_ON_ONCE(IS_ERR(next)))
                return -EINVAL;
        else if (next)
@@ -795,6 +796,8 @@ iwl_mvm_tx_tso_segment(struct sk_buff *skb, unsigned int num_subframes,
 
                if (tcp_payload_len > mss) {
                        skb_shinfo(tmp)->gso_size = mss;
+                       skb_shinfo(tmp)->gso_type = ipv4 ? SKB_GSO_TCPV4 :
+                                                          SKB_GSO_TCPV6;
                } else {
                        if (qos) {
                                u8 *qc;
index 36bf414..5b5134d 100644 (file)
@@ -75,6 +75,15 @@ int iwl_pcie_ctxt_info_gen3_init(struct iwl_trans *trans,
                                 const struct fw_img *fw)
 {
        struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
+       u32 ltr_val = CSR_LTR_LONG_VAL_AD_NO_SNOOP_REQ |
+                     u32_encode_bits(CSR_LTR_LONG_VAL_AD_SCALE_USEC,
+                                     CSR_LTR_LONG_VAL_AD_NO_SNOOP_SCALE) |
+                     u32_encode_bits(250,
+                                     CSR_LTR_LONG_VAL_AD_NO_SNOOP_VAL) |
+                     CSR_LTR_LONG_VAL_AD_SNOOP_REQ |
+                     u32_encode_bits(CSR_LTR_LONG_VAL_AD_SCALE_USEC,
+                                     CSR_LTR_LONG_VAL_AD_SNOOP_SCALE) |
+                     u32_encode_bits(250, CSR_LTR_LONG_VAL_AD_SNOOP_VAL);
        struct iwl_context_info_gen3 *ctxt_info_gen3;
        struct iwl_prph_scratch *prph_scratch;
        struct iwl_prph_scratch_ctrl_cfg *prph_sc_ctrl;
@@ -189,8 +198,10 @@ int iwl_pcie_ctxt_info_gen3_init(struct iwl_trans *trans,
        /* Allocate IML */
        iml_img = dma_alloc_coherent(trans->dev, trans->iml_len,
                                     &trans_pcie->iml_dma_addr, GFP_KERNEL);
-       if (!iml_img)
-               return -ENOMEM;
+       if (!iml_img) {
+               ret = -ENOMEM;
+               goto err_free_ctxt_info;
+       }
 
        memcpy(iml_img, trans->iml, trans->iml_len);
 
@@ -206,23 +217,19 @@ int iwl_pcie_ctxt_info_gen3_init(struct iwl_trans *trans,
        iwl_set_bit(trans, CSR_CTXT_INFO_BOOT_CTRL,
                    CSR_AUTO_FUNC_BOOT_ENA);
 
-       if (trans->trans_cfg->device_family == IWL_DEVICE_FAMILY_AX210) {
-               /*
-                * The firmware initializes this again later (to a smaller
-                * value), but for the boot process initialize the LTR to
-                * ~250 usec.
-                */
-               u32 val = CSR_LTR_LONG_VAL_AD_NO_SNOOP_REQ |
-                         u32_encode_bits(CSR_LTR_LONG_VAL_AD_SCALE_USEC,
-                                         CSR_LTR_LONG_VAL_AD_NO_SNOOP_SCALE) |
-                         u32_encode_bits(250,
-                                         CSR_LTR_LONG_VAL_AD_NO_SNOOP_VAL) |
-                         CSR_LTR_LONG_VAL_AD_SNOOP_REQ |
-                         u32_encode_bits(CSR_LTR_LONG_VAL_AD_SCALE_USEC,
-                                         CSR_LTR_LONG_VAL_AD_SNOOP_SCALE) |
-                         u32_encode_bits(250, CSR_LTR_LONG_VAL_AD_SNOOP_VAL);
-
-               iwl_write32(trans, CSR_LTR_LONG_VAL_AD, val);
+       /*
+        * To workaround hardware latency issues during the boot process,
+        * initialize the LTR to ~250 usec (see ltr_val above).
+        * The firmware initializes this again later (to a smaller value).
+        */
+       if ((trans->trans_cfg->device_family == IWL_DEVICE_FAMILY_AX210 ||
+            trans->trans_cfg->device_family == IWL_DEVICE_FAMILY_22000) &&
+           !trans->trans_cfg->integrated) {
+               iwl_write32(trans, CSR_LTR_LONG_VAL_AD, ltr_val);
+       } else if (trans->trans_cfg->integrated &&
+                  trans->trans_cfg->device_family == IWL_DEVICE_FAMILY_22000) {
+               iwl_write_prph(trans, HPM_MAC_LTR_CSR, HPM_MAC_LRT_ENABLE_ALL);
+               iwl_write_prph(trans, HPM_UMAC_LTR, ltr_val);
        }
 
        if (trans->trans_cfg->device_family >= IWL_DEVICE_FAMILY_AX210)
@@ -232,6 +239,11 @@ int iwl_pcie_ctxt_info_gen3_init(struct iwl_trans *trans,
 
        return 0;
 
+err_free_ctxt_info:
+       dma_free_coherent(trans->dev, sizeof(*trans_pcie->ctxt_info_gen3),
+                         trans_pcie->ctxt_info_gen3,
+                         trans_pcie->ctxt_info_dma_addr);
+       trans_pcie->ctxt_info_gen3 = NULL;
 err_free_prph_info:
        dma_free_coherent(trans->dev,
                          sizeof(*prph_info),
@@ -294,6 +306,9 @@ int iwl_trans_pcie_ctx_info_gen3_set_pnvm(struct iwl_trans *trans,
                return ret;
        }
 
+       if (WARN_ON(prph_sc_ctrl->pnvm_cfg.pnvm_size))
+               return -EBUSY;
+
        prph_sc_ctrl->pnvm_cfg.pnvm_base_addr =
                cpu_to_le64(trans_pcie->pnvm_dram.physical);
        prph_sc_ctrl->pnvm_cfg.pnvm_size =
index 9659826..ed3f5b7 100644 (file)
@@ -910,6 +910,11 @@ static const struct iwl_dev_info iwl_dev_info_table[] = {
                      IWL_CFG_RF_TYPE_HR1, IWL_CFG_ANY,
                      IWL_CFG_ANY, IWL_CFG_ANY,
                      iwl_qu_b0_hr1_b0, iwl_ax101_name),
+       _IWL_DEV_INFO(IWL_CFG_ANY, IWL_CFG_ANY,
+                     IWL_CFG_MAC_TYPE_QU, SILICON_C_STEP,
+                     IWL_CFG_RF_TYPE_HR2, IWL_CFG_ANY,
+                     IWL_CFG_ANY, IWL_CFG_ANY,
+                     iwl_qu_b0_hr_b0, iwl_ax203_name),
 
        /* Qu C step */
        _IWL_DEV_INFO(IWL_CFG_ANY, IWL_CFG_ANY,
@@ -917,6 +922,11 @@ static const struct iwl_dev_info iwl_dev_info_table[] = {
                      IWL_CFG_RF_TYPE_HR1, IWL_CFG_ANY,
                      IWL_CFG_ANY, IWL_CFG_ANY,
                      iwl_qu_c0_hr1_b0, iwl_ax101_name),
+       _IWL_DEV_INFO(IWL_CFG_ANY, IWL_CFG_ANY,
+                     IWL_CFG_MAC_TYPE_QU, SILICON_C_STEP,
+                     IWL_CFG_RF_TYPE_HR2, IWL_CFG_ANY,
+                     IWL_CFG_ANY, IWL_CFG_ANY,
+                     iwl_qu_c0_hr_b0, iwl_ax203_name),
 
        /* QuZ */
        _IWL_DEV_INFO(IWL_CFG_ANY, IWL_CFG_ANY,
index 285e0d5..ab93a84 100644 (file)
@@ -2107,7 +2107,8 @@ static int iwl_trans_pcie_read_mem(struct iwl_trans *trans, u32 addr,
 
        while (offs < dwords) {
                /* limit the time we spin here under lock to 1/2s */
-               ktime_t timeout = ktime_add_us(ktime_get(), 500 * USEC_PER_MSEC);
+               unsigned long end = jiffies + HZ / 2;
+               bool resched = false;
 
                if (iwl_trans_grab_nic_access(trans, &flags)) {
                        iwl_write32(trans, HBUS_TARG_MEM_RADDR,
@@ -2118,14 +2119,15 @@ static int iwl_trans_pcie_read_mem(struct iwl_trans *trans, u32 addr,
                                                        HBUS_TARG_MEM_RDAT);
                                offs++;
 
-                               /* calling ktime_get is expensive so
-                                * do it once in 128 reads
-                                */
-                               if (offs % 128 == 0 && ktime_after(ktime_get(),
-                                                                  timeout))
+                               if (time_after(jiffies, end)) {
+                                       resched = true;
                                        break;
+                               }
                        }
                        iwl_trans_release_nic_access(trans, &flags);
+
+                       if (resched)
+                               cond_resched();
                } else {
                        return -EBUSY;
                }
index 5dda001..83f4964 100644 (file)
@@ -201,6 +201,11 @@ static void iwl_pcie_txq_unmap(struct iwl_trans *trans, int txq_id)
        struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
        struct iwl_txq *txq = trans->txqs.txq[txq_id];
 
+       if (!txq) {
+               IWL_ERR(trans, "Trying to free a queue that wasn't allocated?\n");
+               return;
+       }
+
        spin_lock_bh(&txq->lock);
        while (txq->write_ptr != txq->read_ptr) {
                IWL_DEBUG_TX_REPLY(trans, "Q %d Free %d\n",
index 27eea90..7ff1bb0 100644 (file)
@@ -142,26 +142,25 @@ void iwl_txq_gen2_free_tfd(struct iwl_trans *trans, struct iwl_txq *txq)
         * idx is bounded by n_window
         */
        int idx = iwl_txq_get_cmd_index(txq, txq->read_ptr);
+       struct sk_buff *skb;
 
        lockdep_assert_held(&txq->lock);
 
+       if (!txq->entries)
+               return;
+
        iwl_txq_gen2_tfd_unmap(trans, &txq->entries[idx].meta,
                               iwl_txq_get_tfd(trans, txq, idx));
 
-       /* free SKB */
-       if (txq->entries) {
-               struct sk_buff *skb;
-
-               skb = txq->entries[idx].skb;
+       skb = txq->entries[idx].skb;
 
-               /* Can be called from irqs-disabled context
-                * If skb is not NULL, it means that the whole queue is being
-                * freed and that the queue is not empty - free the skb
-                */
-               if (skb) {
-                       iwl_op_mode_free_skb(trans->op_mode, skb);
-                       txq->entries[idx].skb = NULL;
-               }
+       /* Can be called from irqs-disabled context
+        * If skb is not NULL, it means that the whole queue is being
+        * freed and that the queue is not empty - free the skb
+        */
+       if (skb) {
+               iwl_op_mode_free_skb(trans->op_mode, skb);
+               txq->entries[idx].skb = NULL;
        }
 }
 
@@ -841,10 +840,8 @@ void iwl_txq_gen2_unmap(struct iwl_trans *trans, int txq_id)
                        int idx = iwl_txq_get_cmd_index(txq, txq->read_ptr);
                        struct sk_buff *skb = txq->entries[idx].skb;
 
-                       if (WARN_ON_ONCE(!skb))
-                               continue;
-
-                       iwl_txq_free_tso_page(trans, skb);
+                       if (!WARN_ON_ONCE(!skb))
+                               iwl_txq_free_tso_page(trans, skb);
                }
                iwl_txq_gen2_free_tfd(trans, txq);
                txq->read_ptr = iwl_txq_inc_wrap(trans, txq->read_ptr);
@@ -1494,28 +1491,28 @@ void iwl_txq_free_tfd(struct iwl_trans *trans, struct iwl_txq *txq)
         */
        int rd_ptr = txq->read_ptr;
        int idx = iwl_txq_get_cmd_index(txq, rd_ptr);
+       struct sk_buff *skb;
 
        lockdep_assert_held(&txq->lock);
 
+       if (!txq->entries)
+               return;
+
        /* We have only q->n_window txq->entries, but we use
         * TFD_QUEUE_SIZE_MAX tfds
         */
        iwl_txq_gen1_tfd_unmap(trans, &txq->entries[idx].meta, txq, rd_ptr);
 
        /* free SKB */
-       if (txq->entries) {
-               struct sk_buff *skb;
-
-               skb = txq->entries[idx].skb;
+       skb = txq->entries[idx].skb;
 
-               /* Can be called from irqs-disabled context
-                * If skb is not NULL, it means that the whole queue is being
-                * freed and that the queue is not empty - free the skb
-                */
-               if (skb) {
-                       iwl_op_mode_free_skb(trans->op_mode, skb);
-                       txq->entries[idx].skb = NULL;
-               }
+       /* Can be called from irqs-disabled context
+        * If skb is not NULL, it means that the whole queue is being
+        * freed and that the queue is not empty - free the skb
+        */
+       if (skb) {
+               iwl_op_mode_free_skb(trans->op_mode, skb);
+               txq->entries[idx].skb = NULL;
        }
 }
 
index a44b776..c135478 100644 (file)
@@ -231,7 +231,7 @@ mt7615_mcu_send_message(struct mt76_dev *mdev, struct sk_buff *skb,
                        int cmd, int *seq)
 {
        struct mt7615_dev *dev = container_of(mdev, struct mt7615_dev, mt76);
-       enum mt76_txq_id qid;
+       enum mt76_mcuq_id qid;
 
        mt7615_mcu_fill_msg(dev, skb, cmd, seq);
        if (test_bit(MT76_STATE_MCU_RUNNING, &dev->mphy.state))
index 13d77f8..9fb506f 100644 (file)
@@ -83,7 +83,7 @@ static int mt7663s_rx_run_queue(struct mt76_dev *dev, enum mt76_rxq_id qid,
 {
        struct mt76_queue *q = &dev->q_rx[qid];
        struct mt76_sdio *sdio = &dev->sdio;
-       int len = 0, err, i, order;
+       int len = 0, err, i;
        struct page *page;
        u8 *buf;
 
@@ -96,8 +96,7 @@ static int mt7663s_rx_run_queue(struct mt76_dev *dev, enum mt76_rxq_id qid,
        if (len > sdio->func->cur_blksize)
                len = roundup(len, sdio->func->cur_blksize);
 
-       order = get_order(len);
-       page = __dev_alloc_pages(GFP_KERNEL, order);
+       page = __dev_alloc_pages(GFP_KERNEL, get_order(len));
        if (!page)
                return -ENOMEM;
 
@@ -106,7 +105,7 @@ static int mt7663s_rx_run_queue(struct mt76_dev *dev, enum mt76_rxq_id qid,
        err = sdio_readsb(sdio->func, buf, MCR_WRDR(qid), len);
        if (err < 0) {
                dev_err(dev->dev, "sdio read data failed:%d\n", err);
-               __free_pages(page, order);
+               put_page(page);
                return err;
        }
 
@@ -123,7 +122,7 @@ static int mt7663s_rx_run_queue(struct mt76_dev *dev, enum mt76_rxq_id qid,
                if (q->queued + i + 1 == q->ndesc)
                        break;
        }
-       __free_pages(page, order);
+       put_page(page);
 
        spin_lock_bh(&q->lock);
        q->head = (q->head + i) % q->ndesc;
index 5fdd1a6..e211a2b 100644 (file)
@@ -256,7 +256,7 @@ mt7915_mcu_send_message(struct mt76_dev *mdev, struct sk_buff *skb,
        struct mt7915_dev *dev = container_of(mdev, struct mt7915_dev, mt76);
        struct mt7915_mcu_txd *mcu_txd;
        u8 seq, pkt_fmt, qidx;
-       enum mt76_txq_id txq;
+       enum mt76_mcuq_id qid;
        __le32 *txd;
        u32 val;
 
@@ -268,18 +268,18 @@ mt7915_mcu_send_message(struct mt76_dev *mdev, struct sk_buff *skb,
                seq = ++dev->mt76.mcu.msg_seq & 0xf;
 
        if (cmd == -MCU_CMD_FW_SCATTER) {
-               txq = MT_MCUQ_FWDL;
+               qid = MT_MCUQ_FWDL;
                goto exit;
        }
 
        mcu_txd = (struct mt7915_mcu_txd *)skb_push(skb, sizeof(*mcu_txd));
 
        if (test_bit(MT76_STATE_MCU_RUNNING, &dev->mphy.state)) {
-               txq = MT_MCUQ_WA;
+               qid = MT_MCUQ_WA;
                qidx = MT_TX_MCU_PORT_RX_Q0;
                pkt_fmt = MT_TX_TYPE_CMD;
        } else {
-               txq = MT_MCUQ_WM;
+               qid = MT_MCUQ_WM;
                qidx = MT_TX_MCU_PORT_RX_Q0;
                pkt_fmt = MT_TX_TYPE_CMD;
        }
@@ -326,7 +326,7 @@ exit:
        if (wait_seq)
                *wait_seq = seq;
 
-       return mt76_tx_queue_skb_raw(dev, mdev->q_mcu[txq], skb, 0);
+       return mt76_tx_queue_skb_raw(dev, mdev->q_mcu[qid], skb, 0);
 }
 
 static void
index 5f99054..af7d1ec 100644 (file)
@@ -152,8 +152,7 @@ mt7601u_rx_process_entry(struct mt7601u_dev *dev, struct mt7601u_dma_buf_rx *e)
 
        if (new_p) {
                /* we have one extra ref from the allocator */
-               __free_pages(e->p, MT_RX_ORDER);
-
+               put_page(e->p);
                e->p = new_p;
        }
 }
@@ -310,7 +309,6 @@ static int mt7601u_dma_submit_tx(struct mt7601u_dev *dev,
        }
 
        e = &q->e[q->end];
-       e->skb = skb;
        usb_fill_bulk_urb(e->urb, usb_dev, snd_pipe, skb->data, skb->len,
                          mt7601u_complete_tx, q);
        ret = usb_submit_urb(e->urb, GFP_ATOMIC);
@@ -328,6 +326,7 @@ static int mt7601u_dma_submit_tx(struct mt7601u_dev *dev,
 
        q->end = (q->end + 1) % q->entries;
        q->used++;
+       e->skb = skb;
 
        if (q->used >= q->entries)
                ieee80211_stop_queue(dev->hw, skb_get_queue_mapping(skb));
index b59032e..9d20857 100644 (file)
@@ -335,16 +335,16 @@ static ssize_t state_show(struct device *dev, struct device_attribute *attr,
 }
 static DEVICE_ATTR_RO(state);
 
-static ssize_t available_slots_show(struct device *dev,
-               struct device_attribute *attr, char *buf)
+static ssize_t __available_slots_show(struct nvdimm_drvdata *ndd, char *buf)
 {
-       struct nvdimm_drvdata *ndd = dev_get_drvdata(dev);
+       struct device *dev;
        ssize_t rc;
        u32 nfree;
 
        if (!ndd)
                return -ENXIO;
 
+       dev = ndd->dev;
        nvdimm_bus_lock(dev);
        nfree = nd_label_nfree(ndd);
        if (nfree - 1 > nfree) {
@@ -356,6 +356,18 @@ static ssize_t available_slots_show(struct device *dev,
        nvdimm_bus_unlock(dev);
        return rc;
 }
+
+static ssize_t available_slots_show(struct device *dev,
+                                   struct device_attribute *attr, char *buf)
+{
+       ssize_t rc;
+
+       nd_device_lock(dev);
+       rc = __available_slots_show(dev_get_drvdata(dev), buf);
+       nd_device_unlock(dev);
+
+       return rc;
+}
 static DEVICE_ATTR_RO(available_slots);
 
 __weak ssize_t security_show(struct device *dev,
index 6da67f4..2403b71 100644 (file)
@@ -1635,11 +1635,11 @@ static umode_t namespace_visible(struct kobject *kobj,
                return a->mode;
        }
 
-       if (a == &dev_attr_nstype.attr || a == &dev_attr_size.attr
-                       || a == &dev_attr_holder.attr
-                       || a == &dev_attr_holder_class.attr
-                       || a == &dev_attr_force_raw.attr
-                       || a == &dev_attr_mode.attr)
+       /* base is_namespace_io() attributes */
+       if (a == &dev_attr_nstype.attr || a == &dev_attr_size.attr ||
+           a == &dev_attr_holder.attr || a == &dev_attr_holder_class.attr ||
+           a == &dev_attr_force_raw.attr || a == &dev_attr_mode.attr ||
+           a == &dev_attr_resource.attr)
                return a->mode;
 
        return 0;
index 875076b..f33bdae 100644 (file)
@@ -23,7 +23,6 @@
 #include <linux/uio.h>
 #include <linux/dax.h>
 #include <linux/nd.h>
-#include <linux/backing-dev.h>
 #include <linux/mm.h>
 #include <asm/cacheflush.h>
 #include "pmem.h"
index 200bdd6..f13eb4d 100644 (file)
@@ -1543,8 +1543,21 @@ static int nvme_submit_io(struct nvme_ns *ns, struct nvme_user_io __user *uio)
        }
 
        length = (io.nblocks + 1) << ns->lba_shift;
-       meta_len = (io.nblocks + 1) * ns->ms;
-       metadata = nvme_to_user_ptr(io.metadata);
+
+       if ((io.control & NVME_RW_PRINFO_PRACT) &&
+           ns->ms == sizeof(struct t10_pi_tuple)) {
+               /*
+                * Protection information is stripped/inserted by the
+                * controller.
+                */
+               if (nvme_to_user_ptr(io.metadata))
+                       return -EINVAL;
+               meta_len = 0;
+               metadata = NULL;
+       } else {
+               meta_len = (io.nblocks + 1) * ns->ms;
+               metadata = nvme_to_user_ptr(io.metadata);
+       }
 
        if (ns->features & NVME_NS_EXT_LBAS) {
                length += meta_len;
@@ -3816,7 +3829,7 @@ static int nvme_init_ns_head(struct nvme_ns *ns, unsigned nsid,
                }
        }
 
-       list_add_tail(&ns->siblings, &head->list);
+       list_add_tail_rcu(&ns->siblings, &head->list);
        ns->head = head;
        mutex_unlock(&ctrl->subsys->lock);
        return 0;
index 9ac762b..282b7a4 100644 (file)
@@ -221,7 +221,7 @@ static struct nvme_ns *nvme_round_robin_path(struct nvme_ns_head *head,
        }
 
        for (ns = nvme_next_ns(head, old);
-            ns != old;
+            ns && ns != old;
             ns = nvme_next_ns(head, ns)) {
                if (nvme_path_is_disabled(ns))
                        continue;
index 50d9a20..6bad4d4 100644 (file)
@@ -23,6 +23,7 @@
 #include <linux/t10-pi.h>
 #include <linux/types.h>
 #include <linux/io-64-nonatomic-lo-hi.h>
+#include <linux/io-64-nonatomic-hi-lo.h>
 #include <linux/sed-opal.h>
 #include <linux/pci-p2pdma.h>
 
@@ -542,50 +543,71 @@ static inline bool nvme_pci_use_sgls(struct nvme_dev *dev, struct request *req)
        return true;
 }
 
-static void nvme_unmap_data(struct nvme_dev *dev, struct request *req)
+static void nvme_free_prps(struct nvme_dev *dev, struct request *req)
 {
-       struct nvme_iod *iod = blk_mq_rq_to_pdu(req);
        const int last_prp = NVME_CTRL_PAGE_SIZE / sizeof(__le64) - 1;
-       dma_addr_t dma_addr = iod->first_dma, next_dma_addr;
+       struct nvme_iod *iod = blk_mq_rq_to_pdu(req);
+       dma_addr_t dma_addr = iod->first_dma;
        int i;
 
-       if (iod->dma_len) {
-               dma_unmap_page(dev->dev, dma_addr, iod->dma_len,
-                              rq_dma_dir(req));
-               return;
+       for (i = 0; i < iod->npages; i++) {
+               __le64 *prp_list = nvme_pci_iod_list(req)[i];
+               dma_addr_t next_dma_addr = le64_to_cpu(prp_list[last_prp]);
+
+               dma_pool_free(dev->prp_page_pool, prp_list, dma_addr);
+               dma_addr = next_dma_addr;
        }
 
-       WARN_ON_ONCE(!iod->nents);
+}
 
-       if (is_pci_p2pdma_page(sg_page(iod->sg)))
-               pci_p2pdma_unmap_sg(dev->dev, iod->sg, iod->nents,
-                                   rq_dma_dir(req));
-       else
-               dma_unmap_sg(dev->dev, iod->sg, iod->nents, rq_dma_dir(req));
+static void nvme_free_sgls(struct nvme_dev *dev, struct request *req)
+{
+       const int last_sg = SGES_PER_PAGE - 1;
+       struct nvme_iod *iod = blk_mq_rq_to_pdu(req);
+       dma_addr_t dma_addr = iod->first_dma;
+       int i;
 
+       for (i = 0; i < iod->npages; i++) {
+               struct nvme_sgl_desc *sg_list = nvme_pci_iod_list(req)[i];
+               dma_addr_t next_dma_addr = le64_to_cpu((sg_list[last_sg]).addr);
 
-       if (iod->npages == 0)
-               dma_pool_free(dev->prp_small_pool, nvme_pci_iod_list(req)[0],
-                       dma_addr);
+               dma_pool_free(dev->prp_page_pool, sg_list, dma_addr);
+               dma_addr = next_dma_addr;
+       }
 
-       for (i = 0; i < iod->npages; i++) {
-               void *addr = nvme_pci_iod_list(req)[i];
+}
 
-               if (iod->use_sgl) {
-                       struct nvme_sgl_desc *sg_list = addr;
+static void nvme_unmap_sg(struct nvme_dev *dev, struct request *req)
+{
+       struct nvme_iod *iod = blk_mq_rq_to_pdu(req);
 
-                       next_dma_addr =
-                           le64_to_cpu((sg_list[SGES_PER_PAGE - 1]).addr);
-               } else {
-                       __le64 *prp_list = addr;
+       if (is_pci_p2pdma_page(sg_page(iod->sg)))
+               pci_p2pdma_unmap_sg(dev->dev, iod->sg, iod->nents,
+                                   rq_dma_dir(req));
+       else
+               dma_unmap_sg(dev->dev, iod->sg, iod->nents, rq_dma_dir(req));
+}
 
-                       next_dma_addr = le64_to_cpu(prp_list[last_prp]);
-               }
+static void nvme_unmap_data(struct nvme_dev *dev, struct request *req)
+{
+       struct nvme_iod *iod = blk_mq_rq_to_pdu(req);
 
-               dma_pool_free(dev->prp_page_pool, addr, dma_addr);
-               dma_addr = next_dma_addr;
+       if (iod->dma_len) {
+               dma_unmap_page(dev->dev, iod->first_dma, iod->dma_len,
+                              rq_dma_dir(req));
+               return;
        }
 
+       WARN_ON_ONCE(!iod->nents);
+
+       nvme_unmap_sg(dev, req);
+       if (iod->npages == 0)
+               dma_pool_free(dev->prp_small_pool, nvme_pci_iod_list(req)[0],
+                             iod->first_dma);
+       else if (iod->use_sgl)
+               nvme_free_sgls(dev, req);
+       else
+               nvme_free_prps(dev, req);
        mempool_free(iod->sg, dev->iod_mempool);
 }
 
@@ -661,7 +683,7 @@ static blk_status_t nvme_pci_setup_prps(struct nvme_dev *dev,
                        __le64 *old_prp_list = prp_list;
                        prp_list = dma_pool_alloc(pool, GFP_ATOMIC, &prp_dma);
                        if (!prp_list)
-                               return BLK_STS_RESOURCE;
+                               goto free_prps;
                        list[iod->npages++] = prp_list;
                        prp_list[0] = old_prp_list[i - 1];
                        old_prp_list[i - 1] = cpu_to_le64(prp_dma);
@@ -681,14 +703,14 @@ static blk_status_t nvme_pci_setup_prps(struct nvme_dev *dev,
                dma_addr = sg_dma_address(sg);
                dma_len = sg_dma_len(sg);
        }
-
 done:
        cmnd->dptr.prp1 = cpu_to_le64(sg_dma_address(iod->sg));
        cmnd->dptr.prp2 = cpu_to_le64(iod->first_dma);
-
        return BLK_STS_OK;
-
- bad_sgl:
+free_prps:
+       nvme_free_prps(dev, req);
+       return BLK_STS_RESOURCE;
+bad_sgl:
        WARN(DO_ONCE(nvme_print_sgl, iod->sg, iod->nents),
                        "Invalid SGL for payload:%d nents:%d\n",
                        blk_rq_payload_bytes(req), iod->nents);
@@ -760,7 +782,7 @@ static blk_status_t nvme_pci_setup_sgls(struct nvme_dev *dev,
 
                        sg_list = dma_pool_alloc(pool, GFP_ATOMIC, &sgl_dma);
                        if (!sg_list)
-                               return BLK_STS_RESOURCE;
+                               goto free_sgls;
 
                        i = 0;
                        nvme_pci_iod_list(req)[iod->npages++] = sg_list;
@@ -773,6 +795,9 @@ static blk_status_t nvme_pci_setup_sgls(struct nvme_dev *dev,
        } while (--entries > 0);
 
        return BLK_STS_OK;
+free_sgls:
+       nvme_free_sgls(dev, req);
+       return BLK_STS_RESOURCE;
 }
 
 static blk_status_t nvme_setup_prp_simple(struct nvme_dev *dev,
@@ -841,7 +866,7 @@ static blk_status_t nvme_map_data(struct nvme_dev *dev, struct request *req,
        sg_init_table(iod->sg, blk_rq_nr_phys_segments(req));
        iod->nents = blk_rq_map_sg(req->q, req, iod->sg);
        if (!iod->nents)
-               goto out;
+               goto out_free_sg;
 
        if (is_pci_p2pdma_page(sg_page(iod->sg)))
                nr_mapped = pci_p2pdma_map_sg_attrs(dev->dev, iod->sg,
@@ -850,16 +875,21 @@ static blk_status_t nvme_map_data(struct nvme_dev *dev, struct request *req,
                nr_mapped = dma_map_sg_attrs(dev->dev, iod->sg, iod->nents,
                                             rq_dma_dir(req), DMA_ATTR_NO_WARN);
        if (!nr_mapped)
-               goto out;
+               goto out_free_sg;
 
        iod->use_sgl = nvme_pci_use_sgls(dev, req);
        if (iod->use_sgl)
                ret = nvme_pci_setup_sgls(dev, req, &cmnd->rw, nr_mapped);
        else
                ret = nvme_pci_setup_prps(dev, req, &cmnd->rw);
-out:
        if (ret != BLK_STS_OK)
-               nvme_unmap_data(dev, req);
+               goto out_unmap_sg;
+       return BLK_STS_OK;
+
+out_unmap_sg:
+       nvme_unmap_sg(dev, req);
+out_free_sg:
+       mempool_free(iod->sg, dev->iod_mempool);
        return ret;
 }
 
@@ -1795,6 +1825,9 @@ static void nvme_map_cmb(struct nvme_dev *dev)
        if (dev->cmb_size)
                return;
 
+       if (NVME_CAP_CMBS(dev->ctrl.cap))
+               writel(NVME_CMBMSC_CRE, dev->bar + NVME_REG_CMBMSC);
+
        dev->cmbsz = readl(dev->bar + NVME_REG_CMBSZ);
        if (!dev->cmbsz)
                return;
@@ -1808,6 +1841,16 @@ static void nvme_map_cmb(struct nvme_dev *dev)
        if (offset > bar_size)
                return;
 
+       /*
+        * Tell the controller about the host side address mapping the CMB,
+        * and enable CMB decoding for the NVMe 1.4+ scheme:
+        */
+       if (NVME_CAP_CMBS(dev->ctrl.cap)) {
+               hi_lo_writeq(NVME_CMBMSC_CRE | NVME_CMBMSC_CMSE |
+                            (pci_bus_address(pdev, bar) + offset),
+                            dev->bar + NVME_REG_CMBMSC);
+       }
+
        /*
         * Controllers may support a CMB size larger than their BAR,
         * for example, due to being behind a bridge. Reduce the CMB to
@@ -3199,6 +3242,8 @@ static const struct pci_device_id nvme_id_table[] = {
        { PCI_DEVICE(0x144d, 0xa822),   /* Samsung PM1725a */
                .driver_data = NVME_QUIRK_DELAY_BEFORE_CHK_RDY |
                                NVME_QUIRK_IGNORE_DEV_SUBNQN, },
+       { PCI_DEVICE(0x1987, 0x5016),   /* Phison E16 */
+               .driver_data = NVME_QUIRK_IGNORE_DEV_SUBNQN, },
        { PCI_DEVICE(0x1d1d, 0x1f1f),   /* LighNVM qemu device */
                .driver_data = NVME_QUIRK_LIGHTNVM, },
        { PCI_DEVICE(0x1d1d, 0x2807),   /* CNEX WL */
@@ -3214,6 +3259,10 @@ static const struct pci_device_id nvme_id_table[] = {
                .driver_data = NVME_QUIRK_DISABLE_WRITE_ZEROES, },
        { PCI_DEVICE(0x15b7, 0x2001),   /*  Sandisk Skyhawk */
                .driver_data = NVME_QUIRK_DISABLE_WRITE_ZEROES, },
+       { PCI_DEVICE(0x1d97, 0x2263),   /* SPCC */
+               .driver_data = NVME_QUIRK_DISABLE_WRITE_ZEROES, },
+       { PCI_DEVICE(0x2646, 0x2263),   /* KINGSTON A2000 NVMe SSD  */
+               .driver_data = NVME_QUIRK_NO_DEEPEST_PS, },
        { PCI_DEVICE(PCI_VENDOR_ID_APPLE, 0x2001),
                .driver_data = NVME_QUIRK_SINGLE_VECTOR },
        { PCI_DEVICE(PCI_VENDOR_ID_APPLE, 0x2003) },
index cf6c49d..b7ce4f2 100644 (file)
@@ -97,6 +97,7 @@ struct nvme_rdma_queue {
        struct completion       cm_done;
        bool                    pi_support;
        int                     cq_size;
+       struct mutex            queue_lock;
 };
 
 struct nvme_rdma_ctrl {
@@ -579,6 +580,7 @@ static int nvme_rdma_alloc_queue(struct nvme_rdma_ctrl *ctrl,
        int ret;
 
        queue = &ctrl->queues[idx];
+       mutex_init(&queue->queue_lock);
        queue->ctrl = ctrl;
        if (idx && ctrl->ctrl.max_integrity_segments)
                queue->pi_support = true;
@@ -598,7 +600,8 @@ static int nvme_rdma_alloc_queue(struct nvme_rdma_ctrl *ctrl,
        if (IS_ERR(queue->cm_id)) {
                dev_info(ctrl->ctrl.device,
                        "failed to create CM ID: %ld\n", PTR_ERR(queue->cm_id));
-               return PTR_ERR(queue->cm_id);
+               ret = PTR_ERR(queue->cm_id);
+               goto out_destroy_mutex;
        }
 
        if (ctrl->ctrl.opts->mask & NVMF_OPT_HOST_TRADDR)
@@ -628,6 +631,8 @@ static int nvme_rdma_alloc_queue(struct nvme_rdma_ctrl *ctrl,
 out_destroy_cm_id:
        rdma_destroy_id(queue->cm_id);
        nvme_rdma_destroy_queue_ib(queue);
+out_destroy_mutex:
+       mutex_destroy(&queue->queue_lock);
        return ret;
 }
 
@@ -639,9 +644,10 @@ static void __nvme_rdma_stop_queue(struct nvme_rdma_queue *queue)
 
 static void nvme_rdma_stop_queue(struct nvme_rdma_queue *queue)
 {
-       if (!test_and_clear_bit(NVME_RDMA_Q_LIVE, &queue->flags))
-               return;
-       __nvme_rdma_stop_queue(queue);
+       mutex_lock(&queue->queue_lock);
+       if (test_and_clear_bit(NVME_RDMA_Q_LIVE, &queue->flags))
+               __nvme_rdma_stop_queue(queue);
+       mutex_unlock(&queue->queue_lock);
 }
 
 static void nvme_rdma_free_queue(struct nvme_rdma_queue *queue)
@@ -651,6 +657,7 @@ static void nvme_rdma_free_queue(struct nvme_rdma_queue *queue)
 
        nvme_rdma_destroy_queue_ib(queue);
        rdma_destroy_id(queue->cm_id);
+       mutex_destroy(&queue->queue_lock);
 }
 
 static void nvme_rdma_free_io_queues(struct nvme_rdma_ctrl *ctrl)
index 2166199..881d28e 100644 (file)
@@ -76,6 +76,7 @@ struct nvme_tcp_queue {
        struct work_struct      io_work;
        int                     io_cpu;
 
+       struct mutex            queue_lock;
        struct mutex            send_mutex;
        struct llist_head       req_list;
        struct list_head        send_list;
@@ -1219,6 +1220,7 @@ static void nvme_tcp_free_queue(struct nvme_ctrl *nctrl, int qid)
 
        sock_release(queue->sock);
        kfree(queue->pdu);
+       mutex_destroy(&queue->queue_lock);
 }
 
 static int nvme_tcp_init_connection(struct nvme_tcp_queue *queue)
@@ -1380,6 +1382,7 @@ static int nvme_tcp_alloc_queue(struct nvme_ctrl *nctrl,
        struct nvme_tcp_queue *queue = &ctrl->queues[qid];
        int ret, rcv_pdu_size;
 
+       mutex_init(&queue->queue_lock);
        queue->ctrl = ctrl;
        init_llist_head(&queue->req_list);
        INIT_LIST_HEAD(&queue->send_list);
@@ -1398,7 +1401,7 @@ static int nvme_tcp_alloc_queue(struct nvme_ctrl *nctrl,
        if (ret) {
                dev_err(nctrl->device,
                        "failed to create socket: %d\n", ret);
-               return ret;
+               goto err_destroy_mutex;
        }
 
        /* Single syn retry */
@@ -1507,6 +1510,8 @@ err_crypto:
 err_sock:
        sock_release(queue->sock);
        queue->sock = NULL;
+err_destroy_mutex:
+       mutex_destroy(&queue->queue_lock);
        return ret;
 }
 
@@ -1534,9 +1539,10 @@ static void nvme_tcp_stop_queue(struct nvme_ctrl *nctrl, int qid)
        struct nvme_tcp_ctrl *ctrl = to_tcp_ctrl(nctrl);
        struct nvme_tcp_queue *queue = &ctrl->queues[qid];
 
-       if (!test_and_clear_bit(NVME_TCP_Q_LIVE, &queue->flags))
-               return;
-       __nvme_tcp_stop_queue(queue);
+       mutex_lock(&queue->queue_lock);
+       if (test_and_clear_bit(NVME_TCP_Q_LIVE, &queue->flags))
+               __nvme_tcp_stop_queue(queue);
+       mutex_unlock(&queue->queue_lock);
 }
 
 static int nvme_tcp_start_queue(struct nvme_ctrl *nctrl, int idx)
index 8d90235..dc1ea46 100644 (file)
@@ -487,8 +487,10 @@ static void nvmet_execute_identify_ns(struct nvmet_req *req)
 
        /* return an all zeroed buffer if we can't find an active namespace */
        ns = nvmet_find_namespace(ctrl, req->cmd->identify.nsid);
-       if (!ns)
+       if (!ns) {
+               status = NVME_SC_INVALID_NS;
                goto done;
+       }
 
        nvmet_ns_revalidate(ns);
 
@@ -541,7 +543,9 @@ static void nvmet_execute_identify_ns(struct nvmet_req *req)
                id->nsattr |= (1 << 0);
        nvmet_put_namespace(ns);
 done:
-       status = nvmet_copy_to_sgl(req, 0, id, sizeof(*id));
+       if (!status)
+               status = nvmet_copy_to_sgl(req, 0, id, sizeof(*id));
+
        kfree(id);
 out:
        nvmet_req_complete(req, status);
index dc1f0f6..aacf06f 100644 (file)
@@ -305,7 +305,7 @@ static void nvmet_tcp_map_pdu_iovec(struct nvmet_tcp_cmd *cmd)
        length = cmd->pdu_len;
        cmd->nr_mapped = DIV_ROUND_UP(length, PAGE_SIZE);
        offset = cmd->rbytes_done;
-       cmd->sg_idx = DIV_ROUND_UP(offset, PAGE_SIZE);
+       cmd->sg_idx = offset / PAGE_SIZE;
        sg_offset = offset % PAGE_SIZE;
        sg = &cmd->req.sg[cmd->sg_idx];
 
@@ -318,6 +318,7 @@ static void nvmet_tcp_map_pdu_iovec(struct nvmet_tcp_cmd *cmd)
                length -= iov_len;
                sg = sg_next(sg);
                iov++;
+               sg_offset = 0;
        }
 
        iov_iter_kvec(&cmd->recv_msg.msg_iter, READ, cmd->iov,
index aedfaaa..1122daa 100644 (file)
@@ -162,9 +162,11 @@ int of_dma_configure_id(struct device *dev, struct device_node *np,
        mask = DMA_BIT_MASK(ilog2(end) + 1);
        dev->coherent_dma_mask &= mask;
        *dev->dma_mask &= mask;
-       /* ...but only set bus limit if we found valid dma-ranges earlier */
-       if (!ret)
+       /* ...but only set bus limit and range map if we found valid dma-ranges earlier */
+       if (!ret) {
                dev->bus_dma_limit = end;
+               dev->dma_range_map = map;
+       }
 
        coherent = of_dma_is_coherent(np);
        dev_dbg(dev, "device is%sdma coherent\n",
@@ -172,6 +174,9 @@ int of_dma_configure_id(struct device *dev, struct device_node *np,
 
        iommu = of_iommu_configure(dev, np, id);
        if (PTR_ERR(iommu) == -EPROBE_DEFER) {
+               /* Don't touch range map if it wasn't set from a valid dma-ranges */
+               if (!ret)
+                       dev->dma_range_map = NULL;
                kfree(map);
                return -EPROBE_DEFER;
        }
@@ -181,7 +186,6 @@ int of_dma_configure_id(struct device *dev, struct device_node *np,
 
        arch_setup_dma_ops(dev, dma_start, size, iommu, coherent);
 
-       dev->dma_range_map = map;
        return 0;
 }
 EXPORT_SYMBOL_GPL(of_dma_configure_id);
index b9fecc2..790393d 100644 (file)
@@ -1558,7 +1558,6 @@ int pci_save_state(struct pci_dev *dev)
                return i;
 
        pci_save_ltr_state(dev);
-       pci_save_aspm_l1ss_state(dev);
        pci_save_dpc_state(dev);
        pci_save_aer_state(dev);
        pci_save_ptm_state(dev);
@@ -1665,7 +1664,6 @@ void pci_restore_state(struct pci_dev *dev)
         * LTR itself (in the PCIe capability).
         */
        pci_restore_ltr_state(dev);
-       pci_restore_aspm_l1ss_state(dev);
 
        pci_restore_pcie_state(dev);
        pci_restore_pasid_state(dev);
@@ -3353,11 +3351,6 @@ void pci_allocate_cap_save_buffers(struct pci_dev *dev)
        if (error)
                pci_err(dev, "unable to allocate suspend buffer for LTR\n");
 
-       error = pci_add_ext_cap_save_buffer(dev, PCI_EXT_CAP_ID_L1SS,
-                                           2 * sizeof(u32));
-       if (error)
-               pci_err(dev, "unable to allocate suspend buffer for ASPM-L1SS\n");
-
        pci_allocate_vc_save_buffers(dev);
 }
 
index 5c59365..a7bdf0b 100644 (file)
@@ -582,15 +582,11 @@ void pcie_aspm_init_link_state(struct pci_dev *pdev);
 void pcie_aspm_exit_link_state(struct pci_dev *pdev);
 void pcie_aspm_pm_state_change(struct pci_dev *pdev);
 void pcie_aspm_powersave_config_link(struct pci_dev *pdev);
-void pci_save_aspm_l1ss_state(struct pci_dev *dev);
-void pci_restore_aspm_l1ss_state(struct pci_dev *dev);
 #else
 static inline void pcie_aspm_init_link_state(struct pci_dev *pdev) { }
 static inline void pcie_aspm_exit_link_state(struct pci_dev *pdev) { }
 static inline void pcie_aspm_pm_state_change(struct pci_dev *pdev) { }
 static inline void pcie_aspm_powersave_config_link(struct pci_dev *pdev) { }
-static inline void pci_save_aspm_l1ss_state(struct pci_dev *dev) { }
-static inline void pci_restore_aspm_l1ss_state(struct pci_dev *dev) { }
 #endif
 
 #ifdef CONFIG_PCIE_ECRC
index a08e7d6..ac0557a 100644 (file)
@@ -734,50 +734,6 @@ static void pcie_config_aspm_l1ss(struct pcie_link_state *link, u32 state)
                                PCI_L1SS_CTL1_L1SS_MASK, val);
 }
 
-void pci_save_aspm_l1ss_state(struct pci_dev *dev)
-{
-       int aspm_l1ss;
-       struct pci_cap_saved_state *save_state;
-       u32 *cap;
-
-       if (!pci_is_pcie(dev))
-               return;
-
-       aspm_l1ss = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_L1SS);
-       if (!aspm_l1ss)
-               return;
-
-       save_state = pci_find_saved_ext_cap(dev, PCI_EXT_CAP_ID_L1SS);
-       if (!save_state)
-               return;
-
-       cap = (u32 *)&save_state->cap.data[0];
-       pci_read_config_dword(dev, aspm_l1ss + PCI_L1SS_CTL1, cap++);
-       pci_read_config_dword(dev, aspm_l1ss + PCI_L1SS_CTL2, cap++);
-}
-
-void pci_restore_aspm_l1ss_state(struct pci_dev *dev)
-{
-       int aspm_l1ss;
-       struct pci_cap_saved_state *save_state;
-       u32 *cap;
-
-       if (!pci_is_pcie(dev))
-               return;
-
-       aspm_l1ss = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_L1SS);
-       if (!aspm_l1ss)
-               return;
-
-       save_state = pci_find_saved_ext_cap(dev, PCI_EXT_CAP_ID_L1SS);
-       if (!save_state)
-               return;
-
-       cap = (u32 *)&save_state->cap.data[0];
-       pci_write_config_dword(dev, aspm_l1ss + PCI_L1SS_CTL1, *cap++);
-       pci_write_config_dword(dev, aspm_l1ss + PCI_L1SS_CTL2, *cap++);
-}
-
 static void pcie_config_aspm_dev(struct pci_dev *pdev, u32 val)
 {
        pcie_capability_clear_and_set_word(pdev, PCI_EXP_LNKCTL,
index 65d5ea0..1cb158d 100644 (file)
@@ -1,2 +1,2 @@
 # SPDX-License-Identifier: GPL-2.0
-obj-y          += phy-ingenic-usb.o
+obj-$(CONFIG_PHY_INGENIC_USB)          += phy-ingenic-usb.o
index d38def4..55f8e6c 100644 (file)
@@ -49,7 +49,9 @@ config PHY_MTK_HDMI
 
 config PHY_MTK_MIPI_DSI
        tristate "MediaTek MIPI-DSI Driver"
-       depends on ARCH_MEDIATEK && OF
+       depends on ARCH_MEDIATEK || COMPILE_TEST
+       depends on COMMON_CLK
+       depends on OF
        select GENERIC_PHY
        help
          Support MIPI DSI for Mediatek SoCs.
index 442522b..4728e2b 100644 (file)
@@ -662,35 +662,42 @@ static int cpcap_usb_phy_probe(struct platform_device *pdev)
        generic_phy = devm_phy_create(ddata->dev, NULL, &ops);
        if (IS_ERR(generic_phy)) {
                error = PTR_ERR(generic_phy);
-               return PTR_ERR(generic_phy);
+               goto out_reg_disable;
        }
 
        phy_set_drvdata(generic_phy, ddata);
 
        phy_provider = devm_of_phy_provider_register(ddata->dev,
                                                     of_phy_simple_xlate);
-       if (IS_ERR(phy_provider))
-               return PTR_ERR(phy_provider);
+       if (IS_ERR(phy_provider)) {
+               error = PTR_ERR(phy_provider);
+               goto out_reg_disable;
+       }
 
        error = cpcap_usb_init_optional_pins(ddata);
        if (error)
-               return error;
+               goto out_reg_disable;
 
        cpcap_usb_init_optional_gpios(ddata);
 
        error = cpcap_usb_init_iio(ddata);
        if (error)
-               return error;
+               goto out_reg_disable;
 
        error = cpcap_usb_init_interrupts(pdev, ddata);
        if (error)
-               return error;
+               goto out_reg_disable;
 
        usb_add_phy_dev(&ddata->phy);
        atomic_set(&ddata->active, 1);
        schedule_delayed_work(&ddata->detect_work, msecs_to_jiffies(1));
 
        return 0;
+
+out_reg_disable:
+       regulator_disable(ddata->vusb);
+
+       return error;
 }
 
 static int cpcap_usb_phy_remove(struct platform_device *pdev)
index 34803a6..5c1a109 100644 (file)
@@ -347,7 +347,7 @@ FUNC_GROUP_DECL(RMII4, F24, E23, E24, E25, C25, C24, B26, B25, B24);
 
 #define D22 40
 SIG_EXPR_LIST_DECL_SESG(D22, SD1CLK, SD1, SIG_DESC_SET(SCU414, 8));
-SIG_EXPR_LIST_DECL_SEMG(D22, PWM8, PWM8G0, PWM8, SIG_DESC_SET(SCU414, 8));
+SIG_EXPR_LIST_DECL_SEMG(D22, PWM8, PWM8G0, PWM8, SIG_DESC_SET(SCU4B4, 8));
 PIN_DECL_2(D22, GPIOF0, SD1CLK, PWM8);
 GROUP_DECL(PWM8G0, D22);
 
index 7aeb552..72f17f2 100644 (file)
@@ -920,6 +920,10 @@ int mtk_pinconf_adv_pull_set(struct mtk_pinctrl *hw,
                        err = hw->soc->bias_set(hw, desc, pullup);
                        if (err)
                                return err;
+               } else if (hw->soc->bias_set_combo) {
+                       err = hw->soc->bias_set_combo(hw, desc, pullup, arg);
+                       if (err)
+                               return err;
                } else {
                        return -ENOTSUPP;
                }
index d4ea108..abfe11c 100644 (file)
@@ -949,7 +949,6 @@ static void nmk_gpio_dbg_show_one(struct seq_file *s,
        } else {
                int irq = chip->to_irq(chip, offset);
                const int pullidx = pull ? 1 : 0;
-               bool wake;
                int val;
                static const char * const pulls[] = {
                        "none        ",
index 53a6a24..3ea1634 100644 (file)
 #define JZ4740_GPIO_TRIG       0x70
 #define JZ4740_GPIO_FLAG       0x80
 
-#define JZ4760_GPIO_INT                0x10
-#define JZ4760_GPIO_PAT1       0x30
-#define JZ4760_GPIO_PAT0       0x40
-#define JZ4760_GPIO_FLAG       0x50
-#define JZ4760_GPIO_PEN                0x70
+#define JZ4770_GPIO_INT                0x10
+#define JZ4770_GPIO_PAT1       0x30
+#define JZ4770_GPIO_PAT0       0x40
+#define JZ4770_GPIO_FLAG       0x50
+#define JZ4770_GPIO_PEN                0x70
 
 #define X1830_GPIO_PEL                 0x110
 #define X1830_GPIO_PEH                 0x120
@@ -1688,8 +1688,8 @@ static inline bool ingenic_gpio_get_value(struct ingenic_gpio_chip *jzgc,
 static void ingenic_gpio_set_value(struct ingenic_gpio_chip *jzgc,
                                   u8 offset, int value)
 {
-       if (jzgc->jzpc->info->version >= ID_JZ4760)
-               ingenic_gpio_set_bit(jzgc, JZ4760_GPIO_PAT0, offset, !!value);
+       if (jzgc->jzpc->info->version >= ID_JZ4770)
+               ingenic_gpio_set_bit(jzgc, JZ4770_GPIO_PAT0, offset, !!value);
        else
                ingenic_gpio_set_bit(jzgc, JZ4740_GPIO_DATA, offset, !!value);
 }
@@ -1718,9 +1718,9 @@ static void irq_set_type(struct ingenic_gpio_chip *jzgc,
                break;
        }
 
-       if (jzgc->jzpc->info->version >= ID_JZ4760) {
-               reg1 = JZ4760_GPIO_PAT1;
-               reg2 = JZ4760_GPIO_PAT0;
+       if (jzgc->jzpc->info->version >= ID_JZ4770) {
+               reg1 = JZ4770_GPIO_PAT1;
+               reg2 = JZ4770_GPIO_PAT0;
        } else {
                reg1 = JZ4740_GPIO_TRIG;
                reg2 = JZ4740_GPIO_DIR;
@@ -1758,8 +1758,8 @@ static void ingenic_gpio_irq_enable(struct irq_data *irqd)
        struct ingenic_gpio_chip *jzgc = gpiochip_get_data(gc);
        int irq = irqd->hwirq;
 
-       if (jzgc->jzpc->info->version >= ID_JZ4760)
-               ingenic_gpio_set_bit(jzgc, JZ4760_GPIO_INT, irq, true);
+       if (jzgc->jzpc->info->version >= ID_JZ4770)
+               ingenic_gpio_set_bit(jzgc, JZ4770_GPIO_INT, irq, true);
        else
                ingenic_gpio_set_bit(jzgc, JZ4740_GPIO_SELECT, irq, true);
 
@@ -1774,8 +1774,8 @@ static void ingenic_gpio_irq_disable(struct irq_data *irqd)
 
        ingenic_gpio_irq_mask(irqd);
 
-       if (jzgc->jzpc->info->version >= ID_JZ4760)
-               ingenic_gpio_set_bit(jzgc, JZ4760_GPIO_INT, irq, false);
+       if (jzgc->jzpc->info->version >= ID_JZ4770)
+               ingenic_gpio_set_bit(jzgc, JZ4770_GPIO_INT, irq, false);
        else
                ingenic_gpio_set_bit(jzgc, JZ4740_GPIO_SELECT, irq, false);
 }
@@ -1799,8 +1799,8 @@ static void ingenic_gpio_irq_ack(struct irq_data *irqd)
                        irq_set_type(jzgc, irq, IRQ_TYPE_LEVEL_HIGH);
        }
 
-       if (jzgc->jzpc->info->version >= ID_JZ4760)
-               ingenic_gpio_set_bit(jzgc, JZ4760_GPIO_FLAG, irq, false);
+       if (jzgc->jzpc->info->version >= ID_JZ4770)
+               ingenic_gpio_set_bit(jzgc, JZ4770_GPIO_FLAG, irq, false);
        else
                ingenic_gpio_set_bit(jzgc, JZ4740_GPIO_DATA, irq, true);
 }
@@ -1856,8 +1856,8 @@ static void ingenic_gpio_irq_handler(struct irq_desc *desc)
 
        chained_irq_enter(irq_chip, desc);
 
-       if (jzgc->jzpc->info->version >= ID_JZ4760)
-               flag = ingenic_gpio_read_reg(jzgc, JZ4760_GPIO_FLAG);
+       if (jzgc->jzpc->info->version >= ID_JZ4770)
+               flag = ingenic_gpio_read_reg(jzgc, JZ4770_GPIO_FLAG);
        else
                flag = ingenic_gpio_read_reg(jzgc, JZ4740_GPIO_FLAG);
 
@@ -1938,9 +1938,9 @@ static int ingenic_gpio_get_direction(struct gpio_chip *gc, unsigned int offset)
        struct ingenic_pinctrl *jzpc = jzgc->jzpc;
        unsigned int pin = gc->base + offset;
 
-       if (jzpc->info->version >= ID_JZ4760) {
-               if (ingenic_get_pin_config(jzpc, pin, JZ4760_GPIO_INT) ||
-                   ingenic_get_pin_config(jzpc, pin, JZ4760_GPIO_PAT1))
+       if (jzpc->info->version >= ID_JZ4770) {
+               if (ingenic_get_pin_config(jzpc, pin, JZ4770_GPIO_INT) ||
+                   ingenic_get_pin_config(jzpc, pin, JZ4770_GPIO_PAT1))
                        return GPIO_LINE_DIRECTION_IN;
                return GPIO_LINE_DIRECTION_OUT;
        }
@@ -1991,20 +1991,20 @@ static int ingenic_pinmux_set_pin_fn(struct ingenic_pinctrl *jzpc,
                        'A' + offt, idx, func);
 
        if (jzpc->info->version >= ID_X1000) {
-               ingenic_shadow_config_pin(jzpc, pin, JZ4760_GPIO_INT, false);
+               ingenic_shadow_config_pin(jzpc, pin, JZ4770_GPIO_INT, false);
                ingenic_shadow_config_pin(jzpc, pin, GPIO_MSK, false);
-               ingenic_shadow_config_pin(jzpc, pin, JZ4760_GPIO_PAT1, func & 0x2);
-               ingenic_shadow_config_pin(jzpc, pin, JZ4760_GPIO_PAT0, func & 0x1);
+               ingenic_shadow_config_pin(jzpc, pin, JZ4770_GPIO_PAT1, func & 0x2);
+               ingenic_shadow_config_pin(jzpc, pin, JZ4770_GPIO_PAT0, func & 0x1);
                ingenic_shadow_config_pin_load(jzpc, pin);
-       } else if (jzpc->info->version >= ID_JZ4760) {
-               ingenic_config_pin(jzpc, pin, JZ4760_GPIO_INT, false);
+       } else if (jzpc->info->version >= ID_JZ4770) {
+               ingenic_config_pin(jzpc, pin, JZ4770_GPIO_INT, false);
                ingenic_config_pin(jzpc, pin, GPIO_MSK, false);
-               ingenic_config_pin(jzpc, pin, JZ4760_GPIO_PAT1, func & 0x2);
-               ingenic_config_pin(jzpc, pin, JZ4760_GPIO_PAT0, func & 0x1);
+               ingenic_config_pin(jzpc, pin, JZ4770_GPIO_PAT1, func & 0x2);
+               ingenic_config_pin(jzpc, pin, JZ4770_GPIO_PAT0, func & 0x1);
        } else {
                ingenic_config_pin(jzpc, pin, JZ4740_GPIO_FUNC, true);
                ingenic_config_pin(jzpc, pin, JZ4740_GPIO_TRIG, func & 0x2);
-               ingenic_config_pin(jzpc, pin, JZ4740_GPIO_SELECT, func > 0);
+               ingenic_config_pin(jzpc, pin, JZ4740_GPIO_SELECT, func & 0x1);
        }
 
        return 0;
@@ -2057,14 +2057,14 @@ static int ingenic_pinmux_gpio_set_direction(struct pinctrl_dev *pctldev,
                        'A' + offt, idx, input ? "in" : "out");
 
        if (jzpc->info->version >= ID_X1000) {
-               ingenic_shadow_config_pin(jzpc, pin, JZ4760_GPIO_INT, false);
+               ingenic_shadow_config_pin(jzpc, pin, JZ4770_GPIO_INT, false);
                ingenic_shadow_config_pin(jzpc, pin, GPIO_MSK, true);
-               ingenic_shadow_config_pin(jzpc, pin, JZ4760_GPIO_PAT1, input);
+               ingenic_shadow_config_pin(jzpc, pin, JZ4770_GPIO_PAT1, input);
                ingenic_shadow_config_pin_load(jzpc, pin);
-       } else if (jzpc->info->version >= ID_JZ4760) {
-               ingenic_config_pin(jzpc, pin, JZ4760_GPIO_INT, false);
+       } else if (jzpc->info->version >= ID_JZ4770) {
+               ingenic_config_pin(jzpc, pin, JZ4770_GPIO_INT, false);
                ingenic_config_pin(jzpc, pin, GPIO_MSK, true);
-               ingenic_config_pin(jzpc, pin, JZ4760_GPIO_PAT1, input);
+               ingenic_config_pin(jzpc, pin, JZ4770_GPIO_PAT1, input);
        } else {
                ingenic_config_pin(jzpc, pin, JZ4740_GPIO_SELECT, false);
                ingenic_config_pin(jzpc, pin, JZ4740_GPIO_DIR, !input);
@@ -2091,8 +2091,8 @@ static int ingenic_pinconf_get(struct pinctrl_dev *pctldev,
        unsigned int offt = pin / PINS_PER_GPIO_CHIP;
        bool pull;
 
-       if (jzpc->info->version >= ID_JZ4760)
-               pull = !ingenic_get_pin_config(jzpc, pin, JZ4760_GPIO_PEN);
+       if (jzpc->info->version >= ID_JZ4770)
+               pull = !ingenic_get_pin_config(jzpc, pin, JZ4770_GPIO_PEN);
        else
                pull = !ingenic_get_pin_config(jzpc, pin, JZ4740_GPIO_PULL_DIS);
 
@@ -2141,8 +2141,8 @@ static void ingenic_set_bias(struct ingenic_pinctrl *jzpc,
                                        REG_SET(X1830_GPIO_PEH), bias << idxh);
                }
 
-       } else if (jzpc->info->version >= ID_JZ4760) {
-               ingenic_config_pin(jzpc, pin, JZ4760_GPIO_PEN, !bias);
+       } else if (jzpc->info->version >= ID_JZ4770) {
+               ingenic_config_pin(jzpc, pin, JZ4770_GPIO_PEN, !bias);
        } else {
                ingenic_config_pin(jzpc, pin, JZ4740_GPIO_PULL_DIS, !bias);
        }
@@ -2151,8 +2151,8 @@ static void ingenic_set_bias(struct ingenic_pinctrl *jzpc,
 static void ingenic_set_output_level(struct ingenic_pinctrl *jzpc,
                                     unsigned int pin, bool high)
 {
-       if (jzpc->info->version >= ID_JZ4760)
-               ingenic_config_pin(jzpc, pin, JZ4760_GPIO_PAT0, high);
+       if (jzpc->info->version >= ID_JZ4770)
+               ingenic_config_pin(jzpc, pin, JZ4770_GPIO_PAT0, high);
        else
                ingenic_config_pin(jzpc, pin, JZ4740_GPIO_DATA, high);
 }
index e051aec..d70caec 100644 (file)
@@ -51,6 +51,7 @@
  * @dual_edge_irqs: Bitmap of irqs that need sw emulated dual edge
  *                  detection.
  * @skip_wake_irqs: Skip IRQs that are handled by wakeup interrupt controller
+ * @disabled_for_mux: These IRQs were disabled because we muxed away.
  * @soc:            Reference to soc_data of platform specific data.
  * @regs:           Base addresses for the TLMM tiles.
  * @phys_base:      Physical base address
@@ -72,6 +73,7 @@ struct msm_pinctrl {
        DECLARE_BITMAP(dual_edge_irqs, MAX_NR_GPIO);
        DECLARE_BITMAP(enabled_irqs, MAX_NR_GPIO);
        DECLARE_BITMAP(skip_wake_irqs, MAX_NR_GPIO);
+       DECLARE_BITMAP(disabled_for_mux, MAX_NR_GPIO);
 
        const struct msm_pinctrl_soc_data *soc;
        void __iomem *regs[MAX_NR_TILES];
@@ -96,6 +98,14 @@ MSM_ACCESSOR(intr_cfg)
 MSM_ACCESSOR(intr_status)
 MSM_ACCESSOR(intr_target)
 
+static void msm_ack_intr_status(struct msm_pinctrl *pctrl,
+                               const struct msm_pingroup *g)
+{
+       u32 val = g->intr_ack_high ? BIT(g->intr_status_bit) : 0;
+
+       msm_writel_intr_status(val, pctrl, g);
+}
+
 static int msm_get_groups_count(struct pinctrl_dev *pctldev)
 {
        struct msm_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev);
@@ -171,6 +181,10 @@ static int msm_pinmux_set_mux(struct pinctrl_dev *pctldev,
                              unsigned group)
 {
        struct msm_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev);
+       struct gpio_chip *gc = &pctrl->chip;
+       unsigned int irq = irq_find_mapping(gc->irq.domain, group);
+       struct irq_data *d = irq_get_irq_data(irq);
+       unsigned int gpio_func = pctrl->soc->gpio_func;
        const struct msm_pingroup *g;
        unsigned long flags;
        u32 val, mask;
@@ -187,6 +201,20 @@ static int msm_pinmux_set_mux(struct pinctrl_dev *pctldev,
        if (WARN_ON(i == g->nfuncs))
                return -EINVAL;
 
+       /*
+        * If an GPIO interrupt is setup on this pin then we need special
+        * handling.  Specifically interrupt detection logic will still see
+        * the pin twiddle even when we're muxed away.
+        *
+        * When we see a pin with an interrupt setup on it then we'll disable
+        * (mask) interrupts on it when we mux away until we mux back.  Note
+        * that disable_irq() refcounts and interrupts are disabled as long as
+        * at least one disable_irq() has been called.
+        */
+       if (d && i != gpio_func &&
+           !test_and_set_bit(d->hwirq, pctrl->disabled_for_mux))
+               disable_irq(irq);
+
        raw_spin_lock_irqsave(&pctrl->lock, flags);
 
        val = msm_readl_ctl(pctrl, g);
@@ -196,6 +224,20 @@ static int msm_pinmux_set_mux(struct pinctrl_dev *pctldev,
 
        raw_spin_unlock_irqrestore(&pctrl->lock, flags);
 
+       if (d && i == gpio_func &&
+           test_and_clear_bit(d->hwirq, pctrl->disabled_for_mux)) {
+               /*
+                * Clear interrupts detected while not GPIO since we only
+                * masked things.
+                */
+               if (d->parent_data && test_bit(d->hwirq, pctrl->skip_wake_irqs))
+                       irq_chip_set_parent_state(d, IRQCHIP_STATE_PENDING, false);
+               else
+                       msm_ack_intr_status(pctrl, g);
+
+               enable_irq(irq);
+       }
+
        return 0;
 }
 
@@ -210,8 +252,7 @@ static int msm_pinmux_request_gpio(struct pinctrl_dev *pctldev,
        if (!g->nfuncs)
                return 0;
 
-       /* For now assume function 0 is GPIO because it always is */
-       return msm_pinmux_set_mux(pctldev, g->funcs[0], offset);
+       return msm_pinmux_set_mux(pctldev, g->funcs[pctrl->soc->gpio_func], offset);
 }
 
 static const struct pinmux_ops msm_pinmux_ops = {
@@ -774,7 +815,7 @@ static void msm_gpio_irq_mask(struct irq_data *d)
        raw_spin_unlock_irqrestore(&pctrl->lock, flags);
 }
 
-static void msm_gpio_irq_clear_unmask(struct irq_data *d, bool status_clear)
+static void msm_gpio_irq_unmask(struct irq_data *d)
 {
        struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
        struct msm_pinctrl *pctrl = gpiochip_get_data(gc);
@@ -792,17 +833,6 @@ static void msm_gpio_irq_clear_unmask(struct irq_data *d, bool status_clear)
 
        raw_spin_lock_irqsave(&pctrl->lock, flags);
 
-       if (status_clear) {
-               /*
-                * clear the interrupt status bit before unmask to avoid
-                * any erroneous interrupts that would have got latched
-                * when the interrupt is not in use.
-                */
-               val = msm_readl_intr_status(pctrl, g);
-               val &= ~BIT(g->intr_status_bit);
-               msm_writel_intr_status(val, pctrl, g);
-       }
-
        val = msm_readl_intr_cfg(pctrl, g);
        val |= BIT(g->intr_raw_status_bit);
        val |= BIT(g->intr_enable_bit);
@@ -822,7 +852,7 @@ static void msm_gpio_irq_enable(struct irq_data *d)
                irq_chip_enable_parent(d);
 
        if (!test_bit(d->hwirq, pctrl->skip_wake_irqs))
-               msm_gpio_irq_clear_unmask(d, true);
+               msm_gpio_irq_unmask(d);
 }
 
 static void msm_gpio_irq_disable(struct irq_data *d)
@@ -837,11 +867,6 @@ static void msm_gpio_irq_disable(struct irq_data *d)
                msm_gpio_irq_mask(d);
 }
 
-static void msm_gpio_irq_unmask(struct irq_data *d)
-{
-       msm_gpio_irq_clear_unmask(d, false);
-}
-
 /**
  * msm_gpio_update_dual_edge_parent() - Prime next edge for IRQs handled by parent.
  * @d: The irq dta.
@@ -894,7 +919,6 @@ static void msm_gpio_irq_ack(struct irq_data *d)
        struct msm_pinctrl *pctrl = gpiochip_get_data(gc);
        const struct msm_pingroup *g;
        unsigned long flags;
-       u32 val;
 
        if (test_bit(d->hwirq, pctrl->skip_wake_irqs)) {
                if (test_bit(d->hwirq, pctrl->dual_edge_irqs))
@@ -906,12 +930,7 @@ static void msm_gpio_irq_ack(struct irq_data *d)
 
        raw_spin_lock_irqsave(&pctrl->lock, flags);
 
-       val = msm_readl_intr_status(pctrl, g);
-       if (g->intr_ack_high)
-               val |= BIT(g->intr_status_bit);
-       else
-               val &= ~BIT(g->intr_status_bit);
-       msm_writel_intr_status(val, pctrl, g);
+       msm_ack_intr_status(pctrl, g);
 
        if (test_bit(d->hwirq, pctrl->dual_edge_irqs))
                msm_gpio_update_dual_edge_pos(pctrl, g, d);
@@ -936,6 +955,7 @@ static int msm_gpio_irq_set_type(struct irq_data *d, unsigned int type)
        struct msm_pinctrl *pctrl = gpiochip_get_data(gc);
        const struct msm_pingroup *g;
        unsigned long flags;
+       bool was_enabled;
        u32 val;
 
        if (msm_gpio_needs_dual_edge_parent_workaround(d, type)) {
@@ -997,6 +1017,7 @@ static int msm_gpio_irq_set_type(struct irq_data *d, unsigned int type)
         * could cause the INTR_STATUS to be set for EDGE interrupts.
         */
        val = msm_readl_intr_cfg(pctrl, g);
+       was_enabled = val & BIT(g->intr_raw_status_bit);
        val |= BIT(g->intr_raw_status_bit);
        if (g->intr_detection_width == 2) {
                val &= ~(3 << g->intr_detection_bit);
@@ -1046,6 +1067,14 @@ static int msm_gpio_irq_set_type(struct irq_data *d, unsigned int type)
        }
        msm_writel_intr_cfg(val, pctrl, g);
 
+       /*
+        * The first time we set RAW_STATUS_EN it could trigger an interrupt.
+        * Clear the interrupt.  This is safe because we have
+        * IRQCHIP_SET_TYPE_MASKED.
+        */
+       if (!was_enabled)
+               msm_ack_intr_status(pctrl, g);
+
        if (test_bit(d->hwirq, pctrl->dual_edge_irqs))
                msm_gpio_update_dual_edge_pos(pctrl, g, d);
 
@@ -1099,16 +1128,11 @@ static int msm_gpio_irq_reqres(struct irq_data *d)
        }
 
        /*
-        * Clear the interrupt that may be pending before we enable
-        * the line.
-        * This is especially a problem with the GPIOs routed to the
-        * PDC. These GPIOs are direct-connect interrupts to the GIC.
-        * Disabling the interrupt line at the PDC does not prevent
-        * the interrupt from being latched at the GIC. The state at
-        * GIC needs to be cleared before enabling.
+        * The disable / clear-enable workaround we do in msm_pinmux_set_mux()
+        * only works if disable is not lazy since we only clear any bogus
+        * interrupt in hardware. Explicitly mark the interrupt as UNLAZY.
         */
-       if (d->parent_data && test_bit(d->hwirq, pctrl->skip_wake_irqs))
-               irq_chip_set_parent_state(d, IRQCHIP_STATE_PENDING, 0);
+       irq_set_status_flags(d->irq, IRQ_DISABLE_UNLAZY);
 
        return 0;
 out:
index 333f992..e31a516 100644 (file)
@@ -118,6 +118,7 @@ struct msm_gpio_wakeirq_map {
  * @wakeirq_dual_edge_errata: If true then GPIOs using the wakeirq_map need
  *                            to be aware that their parent can't handle dual
  *                            edge interrupts.
+ * @gpio_func: Which function number is GPIO (usually 0).
  */
 struct msm_pinctrl_soc_data {
        const struct pinctrl_pin_desc *pins;
@@ -134,6 +135,7 @@ struct msm_pinctrl_soc_data {
        const struct msm_gpio_wakeirq_map *wakeirq_map;
        unsigned int nwakeirq_map;
        bool wakeirq_dual_edge_errata;
+       unsigned int gpio_func;
 };
 
 extern const struct dev_pm_ops msm_pinctrl_dev_pm_ops;
index 33040b0..2c941cd 100644 (file)
@@ -5,6 +5,7 @@
 
 menuconfig SURFACE_PLATFORMS
        bool "Microsoft Surface Platform-Specific Device Drivers"
+       depends on ACPI
        default y
        help
          Say Y here to get to see options for platform-specific device drivers
@@ -29,20 +30,19 @@ config SURFACE3_WMI
 
 config SURFACE_3_BUTTON
        tristate "Power/home/volume buttons driver for Microsoft Surface 3 tablet"
-       depends on ACPI && KEYBOARD_GPIO && I2C
+       depends on KEYBOARD_GPIO && I2C
        help
          This driver handles the power/home/volume buttons on the Microsoft Surface 3 tablet.
 
 config SURFACE_3_POWER_OPREGION
        tristate "Surface 3 battery platform operation region support"
-       depends on ACPI && I2C
+       depends on I2C
        help
          This driver provides support for ACPI operation
          region of the Surface 3 battery platform driver.
 
 config SURFACE_GPE
        tristate "Surface GPE/Lid Support Driver"
-       depends on ACPI
        depends on DMI
        help
          This driver marks the GPEs related to the ACPI lid device found on
@@ -52,7 +52,7 @@ config SURFACE_GPE
 
 config SURFACE_PRO3_BUTTON
        tristate "Power/home/volume buttons driver for Microsoft Surface Pro 3/4 tablet"
-       depends on ACPI && INPUT
+       depends on INPUT
        help
          This driver handles the power/home/volume buttons on the Microsoft Surface Pro 3/4 tablet.
 
index e49e5d6..86f6991 100644 (file)
@@ -181,12 +181,12 @@ static int surface_lid_enable_wakeup(struct device *dev, bool enable)
        return 0;
 }
 
-static int surface_gpe_suspend(struct device *dev)
+static int __maybe_unused surface_gpe_suspend(struct device *dev)
 {
        return surface_lid_enable_wakeup(dev, true);
 }
 
-static int surface_gpe_resume(struct device *dev)
+static int __maybe_unused surface_gpe_resume(struct device *dev)
 {
        return surface_lid_enable_wakeup(dev, false);
 }
index 0102bf1..ef83425 100644 (file)
@@ -85,7 +85,7 @@ static inline void amd_pmc_reg_write(struct amd_pmc_dev *dev, int reg_offset, u3
        iowrite32(val, dev->regbase + reg_offset);
 }
 
-#if CONFIG_DEBUG_FS
+#ifdef CONFIG_DEBUG_FS
 static int smu_fw_info_show(struct seq_file *s, void *unused)
 {
        struct amd_pmc_dev *dev = s->private;
index dc6dd53..cb81010 100644 (file)
@@ -419,13 +419,17 @@ static int init_bios_attributes(int attr_type, const char *guid)
                return retval;
        /* need to use specific instance_id and guid combination to get right data */
        obj = get_wmiobj_pointer(instance_id, guid);
-       if (!obj)
+       if (!obj || obj->type != ACPI_TYPE_PACKAGE)
                return -ENODEV;
        elements = obj->package.elements;
 
        mutex_lock(&wmi_priv.mutex);
        while (elements) {
                /* sanity checking */
+               if (elements[ATTR_NAME].type != ACPI_TYPE_STRING) {
+                       pr_debug("incorrect element type\n");
+                       goto nextobj;
+               }
                if (strlen(elements[ATTR_NAME].string.pointer) == 0) {
                        pr_debug("empty attribute found\n");
                        goto nextobj;
index ecd4779..e94e592 100644 (file)
@@ -32,6 +32,10 @@ MODULE_LICENSE("GPL");
 MODULE_ALIAS("wmi:95F24279-4D7B-4334-9387-ACCDC67EF61C");
 MODULE_ALIAS("wmi:5FB7F034-2C63-45e9-BE91-3D44E2C707E4");
 
+static int enable_tablet_mode_sw = -1;
+module_param(enable_tablet_mode_sw, int, 0444);
+MODULE_PARM_DESC(enable_tablet_mode_sw, "Enable SW_TABLET_MODE reporting (-1=auto, 0=no, 1=yes)");
+
 #define HPWMI_EVENT_GUID "95F24279-4D7B-4334-9387-ACCDC67EF61C"
 #define HPWMI_BIOS_GUID "5FB7F034-2C63-45e9-BE91-3D44E2C707E4"
 
@@ -247,7 +251,8 @@ static int hp_wmi_perform_query(int query, enum hp_wmi_command command,
        ret = bios_return->return_code;
 
        if (ret) {
-               if (ret != HPWMI_RET_UNKNOWN_CMDTYPE)
+               if (ret != HPWMI_RET_UNKNOWN_COMMAND &&
+                   ret != HPWMI_RET_UNKNOWN_CMDTYPE)
                        pr_warn("query 0x%x returned error 0x%x\n", query, ret);
                goto out_free;
        }
@@ -653,10 +658,12 @@ static int __init hp_wmi_input_setup(void)
        }
 
        /* Tablet mode */
-       val = hp_wmi_hw_state(HPWMI_TABLET_MASK);
-       if (!(val < 0)) {
-               __set_bit(SW_TABLET_MODE, hp_wmi_input_dev->swbit);
-               input_report_switch(hp_wmi_input_dev, SW_TABLET_MODE, val);
+       if (enable_tablet_mode_sw > 0) {
+               val = hp_wmi_hw_state(HPWMI_TABLET_MASK);
+               if (val >= 0) {
+                       __set_bit(SW_TABLET_MODE, hp_wmi_input_dev->swbit);
+                       input_report_switch(hp_wmi_input_dev, SW_TABLET_MODE, val);
+               }
        }
 
        err = sparse_keymap_setup(hp_wmi_input_dev, hp_wmi_keymap, NULL);
index b457b0b..2cce825 100644 (file)
@@ -164,13 +164,29 @@ static const struct i2c_inst_data bsg2150_data[]  = {
        {}
 };
 
-static const struct i2c_inst_data int3515_data[]  = {
-       { "tps6598x", IRQ_RESOURCE_APIC, 0 },
-       { "tps6598x", IRQ_RESOURCE_APIC, 1 },
-       { "tps6598x", IRQ_RESOURCE_APIC, 2 },
-       { "tps6598x", IRQ_RESOURCE_APIC, 3 },
-       {}
-};
+/*
+ * Device with _HID INT3515 (TI PD controllers) has some unresolved interrupt
+ * issues. The most common problem seen is interrupt flood.
+ *
+ * There are at least two known causes. Firstly, on some boards, the
+ * I2CSerialBus resource index does not match the Interrupt resource, i.e. they
+ * are not one-to-one mapped like in the array below. Secondly, on some boards
+ * the IRQ line from the PD controller is not actually connected at all. But the
+ * interrupt flood is also seen on some boards where those are not a problem, so
+ * there are some other problems as well.
+ *
+ * Because of the issues with the interrupt, the device is disabled for now. If
+ * you wish to debug the issues, uncomment the below, and add an entry for the
+ * INT3515 device to the i2c_multi_instance_ids table.
+ *
+ * static const struct i2c_inst_data int3515_data[]  = {
+ *     { "tps6598x", IRQ_RESOURCE_APIC, 0 },
+ *     { "tps6598x", IRQ_RESOURCE_APIC, 1 },
+ *     { "tps6598x", IRQ_RESOURCE_APIC, 2 },
+ *     { "tps6598x", IRQ_RESOURCE_APIC, 3 },
+ *     { }
+ * };
+ */
 
 /*
  * Note new device-ids must also be added to i2c_multi_instantiate_ids in
@@ -179,7 +195,6 @@ static const struct i2c_inst_data int3515_data[]  = {
 static const struct acpi_device_id i2c_multi_inst_acpi_ids[] = {
        { "BSG1160", (unsigned long)bsg1160_data },
        { "BSG2150", (unsigned long)bsg2150_data },
-       { "INT3515", (unsigned long)int3515_data },
        { }
 };
 MODULE_DEVICE_TABLE(acpi, i2c_multi_inst_acpi_ids);
index 7598cd4..5b81baf 100644 (file)
@@ -92,6 +92,7 @@ struct ideapad_private {
        struct dentry *debug;
        unsigned long cfg;
        bool has_hw_rfkill_switch;
+       bool has_touchpad_switch;
        const char *fnesc_guid;
 };
 
@@ -535,7 +536,9 @@ static umode_t ideapad_is_visible(struct kobject *kobj,
        } else if (attr == &dev_attr_fn_lock.attr) {
                supported = acpi_has_method(priv->adev->handle, "HALS") &&
                        acpi_has_method(priv->adev->handle, "SALS");
-       } else
+       } else if (attr == &dev_attr_touchpad.attr)
+               supported = priv->has_touchpad_switch;
+       else
                supported = true;
 
        return supported ? attr->mode : 0;
@@ -867,6 +870,9 @@ static void ideapad_sync_touchpad_state(struct ideapad_private *priv)
 {
        unsigned long value;
 
+       if (!priv->has_touchpad_switch)
+               return;
+
        /* Without reading from EC touchpad LED doesn't switch state */
        if (!read_ec_data(priv->adev->handle, VPCCMD_R_TOUCHPAD, &value)) {
                /* Some IdeaPads don't really turn off touchpad - they only
@@ -989,6 +995,9 @@ static int ideapad_acpi_add(struct platform_device *pdev)
        priv->platform_device = pdev;
        priv->has_hw_rfkill_switch = dmi_check_system(hw_rfkill_list);
 
+       /* Most ideapads with ELAN0634 touchpad don't use EC touchpad switch */
+       priv->has_touchpad_switch = !acpi_dev_present("ELAN0634", NULL, -1);
+
        ret = ideapad_sysfs_init(priv);
        if (ret)
                return ret;
@@ -1006,6 +1015,10 @@ static int ideapad_acpi_add(struct platform_device *pdev)
        if (!priv->has_hw_rfkill_switch)
                write_ec_cmd(priv->adev->handle, VPCCMD_W_RF, 1);
 
+       /* The same for Touchpad */
+       if (!priv->has_touchpad_switch)
+               write_ec_cmd(priv->adev->handle, VPCCMD_W_TOUCHPAD, 1);
+
        for (i = 0; i < IDEAPAD_RFKILL_DEV_NUM; i++)
                if (test_bit(ideapad_rfk_data[i].cfgbit, &priv->cfg))
                        ideapad_register_rfkill(priv, i);
index 3b49a1f..30a9062 100644 (file)
@@ -207,19 +207,19 @@ static const struct dmi_system_id dmi_switches_allow_list[] = {
        {
                .matches = {
                        DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"),
-                       DMI_MATCH(DMI_PRODUCT_NAME, "HP Stream x360 Convertible PC 11"),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "HP Pavilion 13 x360 PC"),
                },
        },
        {
                .matches = {
-                       DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"),
-                       DMI_MATCH(DMI_PRODUCT_NAME, "HP Pavilion 13 x360 PC"),
+                       DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "Switch SA5-271"),
                },
        },
        {
                .matches = {
-                       DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
-                       DMI_MATCH(DMI_PRODUCT_NAME, "Switch SA5-271"),
+                       DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "Inspiron 7352"),
                },
        },
        {} /* Array terminator */
index e03df28..f3e8eca 100644 (file)
@@ -8783,6 +8783,7 @@ static const struct tpacpi_quirk fan_quirk_table[] __initconst = {
        TPACPI_Q_LNV3('N', '1', 'T', TPACPI_FAN_2CTL),  /* P71 */
        TPACPI_Q_LNV3('N', '1', 'U', TPACPI_FAN_2CTL),  /* P51 */
        TPACPI_Q_LNV3('N', '2', 'C', TPACPI_FAN_2CTL),  /* P52 / P72 */
+       TPACPI_Q_LNV3('N', '2', 'N', TPACPI_FAN_2CTL),  /* P53 / P73 */
        TPACPI_Q_LNV3('N', '2', 'E', TPACPI_FAN_2CTL),  /* P1 / X1 Extreme (1st gen) */
        TPACPI_Q_LNV3('N', '2', 'O', TPACPI_FAN_2CTL),  /* P1 / X1 Extreme (2nd gen) */
        TPACPI_Q_LNV3('N', '2', 'V', TPACPI_FAN_2CTL),  /* P1 / X1 Extreme (3nd gen) */
@@ -9951,9 +9952,9 @@ static int tpacpi_proxsensor_init(struct ibm_init_struct *iibm)
        if ((palm_err == -ENODEV) && (lap_err == -ENODEV))
                return 0;
        /* Otherwise, if there was an error return it */
-       if (palm_err && (palm_err != ENODEV))
+       if (palm_err && (palm_err != -ENODEV))
                return palm_err;
-       if (lap_err && (lap_err != ENODEV))
+       if (lap_err && (lap_err != -ENODEV))
                return lap_err;
 
        if (has_palmsensor) {
index 5783139..c4de932 100644 (file)
@@ -263,6 +263,16 @@ static const struct ts_dmi_data digma_citi_e200_data = {
        .properties     = digma_citi_e200_props,
 };
 
+static const struct property_entry estar_beauty_hd_props[] = {
+       PROPERTY_ENTRY_BOOL("touchscreen-swapped-x-y"),
+       { }
+};
+
+static const struct ts_dmi_data estar_beauty_hd_data = {
+       .acpi_name      = "GDIX1001:00",
+       .properties     = estar_beauty_hd_props,
+};
+
 static const struct property_entry gp_electronic_t701_props[] = {
        PROPERTY_ENTRY_U32("touchscreen-size-x", 960),
        PROPERTY_ENTRY_U32("touchscreen-size-y", 640),
@@ -942,6 +952,14 @@ const struct dmi_system_id touchscreen_dmi_table[] = {
                        DMI_MATCH(DMI_BOARD_NAME, "Cherry Trail CR"),
                },
        },
+       {
+               /* Estar Beauty HD (MID 7316R) */
+               .driver_data = (void *)&estar_beauty_hd_data,
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "Estar"),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "eSTAR BEAUTY HD Intel Quad core"),
+               },
+       },
        {
                /* GP-electronic T701 */
                .driver_data = (void *)&gp_electronic_t701_data,
index ca03d8e..67a768f 100644 (file)
@@ -1813,13 +1813,13 @@ static int regulator_resolve_supply(struct regulator_dev *rdev)
 {
        struct regulator_dev *r;
        struct device *dev = rdev->dev.parent;
-       int ret;
+       int ret = 0;
 
        /* No supply to resolve? */
        if (!rdev->supply_name)
                return 0;
 
-       /* Supply already resolved? */
+       /* Supply already resolved? (fast-path without locking contention) */
        if (rdev->supply)
                return 0;
 
@@ -1829,7 +1829,7 @@ static int regulator_resolve_supply(struct regulator_dev *rdev)
 
                /* Did the lookup explicitly defer for us? */
                if (ret == -EPROBE_DEFER)
-                       return ret;
+                       goto out;
 
                if (have_full_constraints()) {
                        r = dummy_regulator_rdev;
@@ -1837,15 +1837,18 @@ static int regulator_resolve_supply(struct regulator_dev *rdev)
                } else {
                        dev_err(dev, "Failed to resolve %s-supply for %s\n",
                                rdev->supply_name, rdev->desc->name);
-                       return -EPROBE_DEFER;
+                       ret = -EPROBE_DEFER;
+                       goto out;
                }
        }
 
        if (r == rdev) {
                dev_err(dev, "Supply for %s (%s) resolved to itself\n",
                        rdev->desc->name, rdev->supply_name);
-               if (!have_full_constraints())
-                       return -EINVAL;
+               if (!have_full_constraints()) {
+                       ret = -EINVAL;
+                       goto out;
+               }
                r = dummy_regulator_rdev;
                get_device(&r->dev);
        }
@@ -1859,7 +1862,8 @@ static int regulator_resolve_supply(struct regulator_dev *rdev)
        if (r->dev.parent && r->dev.parent != rdev->dev.parent) {
                if (!device_is_bound(r->dev.parent)) {
                        put_device(&r->dev);
-                       return -EPROBE_DEFER;
+                       ret = -EPROBE_DEFER;
+                       goto out;
                }
        }
 
@@ -1867,15 +1871,32 @@ static int regulator_resolve_supply(struct regulator_dev *rdev)
        ret = regulator_resolve_supply(r);
        if (ret < 0) {
                put_device(&r->dev);
-               return ret;
+               goto out;
+       }
+
+       /*
+        * Recheck rdev->supply with rdev->mutex lock held to avoid a race
+        * between rdev->supply null check and setting rdev->supply in
+        * set_supply() from concurrent tasks.
+        */
+       regulator_lock(rdev);
+
+       /* Supply just resolved by a concurrent task? */
+       if (rdev->supply) {
+               regulator_unlock(rdev);
+               put_device(&r->dev);
+               goto out;
        }
 
        ret = set_supply(rdev, r);
        if (ret < 0) {
+               regulator_unlock(rdev);
                put_device(&r->dev);
-               return ret;
+               goto out;
        }
 
+       regulator_unlock(rdev);
+
        /*
         * In set_machine_constraints() we may have turned this regulator on
         * but we couldn't propagate to the supply if it hadn't been resolved
@@ -1886,11 +1907,12 @@ static int regulator_resolve_supply(struct regulator_dev *rdev)
                if (ret < 0) {
                        _regulator_put(rdev->supply);
                        rdev->supply = NULL;
-                       return ret;
+                       goto out;
                }
        }
 
-       return 0;
+out:
+       return ret;
 }
 
 /* Internal regulator request function */
index 51e80bc..a701dae 100644 (file)
@@ -805,6 +805,14 @@ cmos_do_probe(struct device *dev, struct resource *ports, int rtc_irq)
 
        spin_lock_irq(&rtc_lock);
 
+       /* Ensure that the RTC is accessible. Bit 6 must be 0! */
+       if ((CMOS_READ(RTC_VALID) & 0x40) != 0) {
+               spin_unlock_irq(&rtc_lock);
+               dev_warn(dev, "not accessible\n");
+               retval = -ENXIO;
+               goto cleanup1;
+       }
+
        if (!(flags & CMOS_RTC_FLAGS_NOFREQ)) {
                /* force periodic irq to CMOS reset default of 1024Hz;
                 *
index 972a5b9..dcfaf09 100644 (file)
@@ -21,6 +21,13 @@ unsigned int mc146818_get_time(struct rtc_time *time)
 
 again:
        spin_lock_irqsave(&rtc_lock, flags);
+       /* Ensure that the RTC is accessible. Bit 6 must be 0! */
+       if (WARN_ON_ONCE((CMOS_READ(RTC_VALID) & 0x40) != 0)) {
+               spin_unlock_irqrestore(&rtc_lock, flags);
+               memset(time, 0xff, sizeof(*time));
+               return 0;
+       }
+
        /*
         * Check whether there is an update in progress during which the
         * readout is unspecified. The maximum update time is ~2ms. Poll
index 16bb135..03d27ee 100644 (file)
@@ -1874,18 +1874,26 @@ void dasd_path_create_kobjects(struct dasd_device *device)
 }
 EXPORT_SYMBOL(dasd_path_create_kobjects);
 
-/*
- * As we keep kobjects for the lifetime of a device, this function must not be
- * called anywhere but in the context of offlining a device.
- */
-void dasd_path_remove_kobj(struct dasd_device *device, int chp)
+static void dasd_path_remove_kobj(struct dasd_device *device, int chp)
 {
        if (device->path[chp].in_sysfs) {
                kobject_put(&device->path[chp].kobj);
                device->path[chp].in_sysfs = false;
        }
 }
-EXPORT_SYMBOL(dasd_path_remove_kobj);
+
+/*
+ * As we keep kobjects for the lifetime of a device, this function must not be
+ * called anywhere but in the context of offlining a device.
+ */
+void dasd_path_remove_kobjects(struct dasd_device *device)
+{
+       int i;
+
+       for (i = 0; i < 8; i++)
+               dasd_path_remove_kobj(device, i);
+}
+EXPORT_SYMBOL(dasd_path_remove_kobjects);
 
 int dasd_add_sysfs_files(struct ccw_device *cdev)
 {
index 3caa1ee..65eb87c 100644 (file)
@@ -1036,7 +1036,6 @@ static void dasd_eckd_clear_conf_data(struct dasd_device *device)
                device->path[i].ssid = 0;
                device->path[i].chpid = 0;
                dasd_path_notoper(device, i);
-               dasd_path_remove_kobj(device, i);
        }
 }
 
@@ -2173,6 +2172,7 @@ out_err2:
        device->block = NULL;
 out_err1:
        dasd_eckd_clear_conf_data(device);
+       dasd_path_remove_kobjects(device);
        kfree(device->private);
        device->private = NULL;
        return rc;
@@ -2191,6 +2191,7 @@ static void dasd_eckd_uncheck_device(struct dasd_device *device)
        private->vdsneq = NULL;
        private->gneq = NULL;
        dasd_eckd_clear_conf_data(device);
+       dasd_path_remove_kobjects(device);
 }
 
 static struct dasd_ccw_req *
index 3bc008f..b8a04c4 100644 (file)
@@ -858,7 +858,7 @@ int dasd_add_sysfs_files(struct ccw_device *);
 void dasd_remove_sysfs_files(struct ccw_device *);
 void dasd_path_create_kobj(struct dasd_device *, int);
 void dasd_path_create_kobjects(struct dasd_device *);
-void dasd_path_remove_kobj(struct dasd_device *, int);
+void dasd_path_remove_kobjects(struct dasd_device *);
 
 struct dasd_device *dasd_device_from_cdev(struct ccw_device *);
 struct dasd_device *dasd_device_from_cdev_locked(struct ccw_device *);
index be2520c..7dc72cb 100644 (file)
@@ -71,15 +71,11 @@ static int vfio_ap_queue_dev_probe(struct ap_device *apdev)
 static void vfio_ap_queue_dev_remove(struct ap_device *apdev)
 {
        struct vfio_ap_queue *q;
-       int apid, apqi;
 
        mutex_lock(&matrix_dev->lock);
        q = dev_get_drvdata(&apdev->device);
+       vfio_ap_mdev_reset_queue(q, 1);
        dev_set_drvdata(&apdev->device, NULL);
-       apid = AP_QID_CARD(q->apqn);
-       apqi = AP_QID_QUEUE(q->apqn);
-       vfio_ap_mdev_reset_queue(apid, apqi, 1);
-       vfio_ap_irq_disable(q);
        kfree(q);
        mutex_unlock(&matrix_dev->lock);
 }
index e0bde85..41fc2e4 100644 (file)
@@ -25,6 +25,7 @@
 #define VFIO_AP_MDEV_NAME_HWVIRT "VFIO AP Passthrough Device"
 
 static int vfio_ap_mdev_reset_queues(struct mdev_device *mdev);
+static struct vfio_ap_queue *vfio_ap_find_queue(int apqn);
 
 static int match_apqn(struct device *dev, const void *data)
 {
@@ -49,20 +50,15 @@ static struct vfio_ap_queue *vfio_ap_get_queue(
                                        int apqn)
 {
        struct vfio_ap_queue *q;
-       struct device *dev;
 
        if (!test_bit_inv(AP_QID_CARD(apqn), matrix_mdev->matrix.apm))
                return NULL;
        if (!test_bit_inv(AP_QID_QUEUE(apqn), matrix_mdev->matrix.aqm))
                return NULL;
 
-       dev = driver_find_device(&matrix_dev->vfio_ap_drv->driver, NULL,
-                                &apqn, match_apqn);
-       if (!dev)
-               return NULL;
-       q = dev_get_drvdata(dev);
-       q->matrix_mdev = matrix_mdev;
-       put_device(dev);
+       q = vfio_ap_find_queue(apqn);
+       if (q)
+               q->matrix_mdev = matrix_mdev;
 
        return q;
 }
@@ -119,13 +115,18 @@ static void vfio_ap_wait_for_irqclear(int apqn)
  */
 static void vfio_ap_free_aqic_resources(struct vfio_ap_queue *q)
 {
-       if (q->saved_isc != VFIO_AP_ISC_INVALID && q->matrix_mdev)
+       if (!q)
+               return;
+       if (q->saved_isc != VFIO_AP_ISC_INVALID &&
+           !WARN_ON(!(q->matrix_mdev && q->matrix_mdev->kvm))) {
                kvm_s390_gisc_unregister(q->matrix_mdev->kvm, q->saved_isc);
-       if (q->saved_pfn && q->matrix_mdev)
+               q->saved_isc = VFIO_AP_ISC_INVALID;
+       }
+       if (q->saved_pfn && !WARN_ON(!q->matrix_mdev)) {
                vfio_unpin_pages(mdev_dev(q->matrix_mdev->mdev),
                                 &q->saved_pfn, 1);
-       q->saved_pfn = 0;
-       q->saved_isc = VFIO_AP_ISC_INVALID;
+               q->saved_pfn = 0;
+       }
 }
 
 /**
@@ -144,7 +145,7 @@ static void vfio_ap_free_aqic_resources(struct vfio_ap_queue *q)
  * Returns if ap_aqic function failed with invalid, deconfigured or
  * checkstopped AP.
  */
-struct ap_queue_status vfio_ap_irq_disable(struct vfio_ap_queue *q)
+static struct ap_queue_status vfio_ap_irq_disable(struct vfio_ap_queue *q)
 {
        struct ap_qirq_ctrl aqic_gisa = {};
        struct ap_queue_status status;
@@ -1037,19 +1038,14 @@ static int vfio_ap_mdev_set_kvm(struct ap_matrix_mdev *matrix_mdev,
 {
        struct ap_matrix_mdev *m;
 
-       mutex_lock(&matrix_dev->lock);
-
        list_for_each_entry(m, &matrix_dev->mdev_list, node) {
-               if ((m != matrix_mdev) && (m->kvm == kvm)) {
-                       mutex_unlock(&matrix_dev->lock);
+               if ((m != matrix_mdev) && (m->kvm == kvm))
                        return -EPERM;
-               }
        }
 
        matrix_mdev->kvm = kvm;
        kvm_get_kvm(kvm);
        kvm->arch.crypto.pqap_hook = &matrix_mdev->pqap_hook;
-       mutex_unlock(&matrix_dev->lock);
 
        return 0;
 }
@@ -1083,79 +1079,118 @@ static int vfio_ap_mdev_iommu_notifier(struct notifier_block *nb,
        return NOTIFY_DONE;
 }
 
+static void vfio_ap_mdev_unset_kvm(struct ap_matrix_mdev *matrix_mdev)
+{
+       kvm_arch_crypto_clear_masks(matrix_mdev->kvm);
+       matrix_mdev->kvm->arch.crypto.pqap_hook = NULL;
+       vfio_ap_mdev_reset_queues(matrix_mdev->mdev);
+       kvm_put_kvm(matrix_mdev->kvm);
+       matrix_mdev->kvm = NULL;
+}
+
 static int vfio_ap_mdev_group_notifier(struct notifier_block *nb,
                                       unsigned long action, void *data)
 {
-       int ret;
+       int ret, notify_rc = NOTIFY_OK;
        struct ap_matrix_mdev *matrix_mdev;
 
        if (action != VFIO_GROUP_NOTIFY_SET_KVM)
                return NOTIFY_OK;
 
        matrix_mdev = container_of(nb, struct ap_matrix_mdev, group_notifier);
+       mutex_lock(&matrix_dev->lock);
 
        if (!data) {
-               matrix_mdev->kvm = NULL;
-               return NOTIFY_OK;
+               if (matrix_mdev->kvm)
+                       vfio_ap_mdev_unset_kvm(matrix_mdev);
+               goto notify_done;
        }
 
        ret = vfio_ap_mdev_set_kvm(matrix_mdev, data);
-       if (ret)
-               return NOTIFY_DONE;
+       if (ret) {
+               notify_rc = NOTIFY_DONE;
+               goto notify_done;
+       }
 
        /* If there is no CRYCB pointer, then we can't copy the masks */
-       if (!matrix_mdev->kvm->arch.crypto.crycbd)
-               return NOTIFY_DONE;
+       if (!matrix_mdev->kvm->arch.crypto.crycbd) {
+               notify_rc = NOTIFY_DONE;
+               goto notify_done;
+       }
 
        kvm_arch_crypto_set_masks(matrix_mdev->kvm, matrix_mdev->matrix.apm,
                                  matrix_mdev->matrix.aqm,
                                  matrix_mdev->matrix.adm);
 
-       return NOTIFY_OK;
+notify_done:
+       mutex_unlock(&matrix_dev->lock);
+       return notify_rc;
 }
 
-static void vfio_ap_irq_disable_apqn(int apqn)
+static struct vfio_ap_queue *vfio_ap_find_queue(int apqn)
 {
        struct device *dev;
-       struct vfio_ap_queue *q;
+       struct vfio_ap_queue *q = NULL;
 
        dev = driver_find_device(&matrix_dev->vfio_ap_drv->driver, NULL,
                                 &apqn, match_apqn);
        if (dev) {
                q = dev_get_drvdata(dev);
-               vfio_ap_irq_disable(q);
                put_device(dev);
        }
+
+       return q;
 }
 
-int vfio_ap_mdev_reset_queue(unsigned int apid, unsigned int apqi,
+int vfio_ap_mdev_reset_queue(struct vfio_ap_queue *q,
                             unsigned int retry)
 {
        struct ap_queue_status status;
+       int ret;
        int retry2 = 2;
-       int apqn = AP_MKQID(apid, apqi);
 
-       do {
-               status = ap_zapq(apqn);
-               switch (status.response_code) {
-               case AP_RESPONSE_NORMAL:
-                       while (!status.queue_empty && retry2--) {
-                               msleep(20);
-                               status = ap_tapq(apqn, NULL);
-                       }
-                       WARN_ON_ONCE(retry2 <= 0);
-                       return 0;
-               case AP_RESPONSE_RESET_IN_PROGRESS:
-               case AP_RESPONSE_BUSY:
+       if (!q)
+               return 0;
+
+retry_zapq:
+       status = ap_zapq(q->apqn);
+       switch (status.response_code) {
+       case AP_RESPONSE_NORMAL:
+               ret = 0;
+               break;
+       case AP_RESPONSE_RESET_IN_PROGRESS:
+               if (retry--) {
                        msleep(20);
-                       break;
-               default:
-                       /* things are really broken, give up */
-                       return -EIO;
+                       goto retry_zapq;
                }
-       } while (retry--);
+               ret = -EBUSY;
+               break;
+       case AP_RESPONSE_Q_NOT_AVAIL:
+       case AP_RESPONSE_DECONFIGURED:
+       case AP_RESPONSE_CHECKSTOPPED:
+               WARN_ON_ONCE(status.irq_enabled);
+               ret = -EBUSY;
+               goto free_resources;
+       default:
+               /* things are really broken, give up */
+               WARN(true, "PQAP/ZAPQ completed with invalid rc (%x)\n",
+                    status.response_code);
+               return -EIO;
+       }
+
+       /* wait for the reset to take effect */
+       while (retry2--) {
+               if (status.queue_empty && !status.irq_enabled)
+                       break;
+               msleep(20);
+               status = ap_tapq(q->apqn, NULL);
+       }
+       WARN_ON_ONCE(retry2 <= 0);
 
-       return -EBUSY;
+free_resources:
+       vfio_ap_free_aqic_resources(q);
+
+       return ret;
 }
 
 static int vfio_ap_mdev_reset_queues(struct mdev_device *mdev)
@@ -1163,13 +1198,15 @@ static int vfio_ap_mdev_reset_queues(struct mdev_device *mdev)
        int ret;
        int rc = 0;
        unsigned long apid, apqi;
+       struct vfio_ap_queue *q;
        struct ap_matrix_mdev *matrix_mdev = mdev_get_drvdata(mdev);
 
        for_each_set_bit_inv(apid, matrix_mdev->matrix.apm,
                             matrix_mdev->matrix.apm_max + 1) {
                for_each_set_bit_inv(apqi, matrix_mdev->matrix.aqm,
                                     matrix_mdev->matrix.aqm_max + 1) {
-                       ret = vfio_ap_mdev_reset_queue(apid, apqi, 1);
+                       q = vfio_ap_find_queue(AP_MKQID(apid, apqi));
+                       ret = vfio_ap_mdev_reset_queue(q, 1);
                        /*
                         * Regardless whether a queue turns out to be busy, or
                         * is not operational, we need to continue resetting
@@ -1177,7 +1214,6 @@ static int vfio_ap_mdev_reset_queues(struct mdev_device *mdev)
                         */
                        if (ret)
                                rc = ret;
-                       vfio_ap_irq_disable_apqn(AP_MKQID(apid, apqi));
                }
        }
 
@@ -1222,13 +1258,8 @@ static void vfio_ap_mdev_release(struct mdev_device *mdev)
        struct ap_matrix_mdev *matrix_mdev = mdev_get_drvdata(mdev);
 
        mutex_lock(&matrix_dev->lock);
-       if (matrix_mdev->kvm) {
-               kvm_arch_crypto_clear_masks(matrix_mdev->kvm);
-               matrix_mdev->kvm->arch.crypto.pqap_hook = NULL;
-               vfio_ap_mdev_reset_queues(mdev);
-               kvm_put_kvm(matrix_mdev->kvm);
-               matrix_mdev->kvm = NULL;
-       }
+       if (matrix_mdev->kvm)
+               vfio_ap_mdev_unset_kvm(matrix_mdev);
        mutex_unlock(&matrix_dev->lock);
 
        vfio_unregister_notifier(mdev_dev(mdev), VFIO_IOMMU_NOTIFY,
index f46dde5..28e9d99 100644 (file)
@@ -88,11 +88,6 @@ struct ap_matrix_mdev {
        struct mdev_device *mdev;
 };
 
-extern int vfio_ap_mdev_register(void);
-extern void vfio_ap_mdev_unregister(void);
-int vfio_ap_mdev_reset_queue(unsigned int apid, unsigned int apqi,
-                            unsigned int retry);
-
 struct vfio_ap_queue {
        struct ap_matrix_mdev *matrix_mdev;
        unsigned long saved_pfn;
@@ -100,5 +95,10 @@ struct vfio_ap_queue {
 #define VFIO_AP_ISC_INVALID 0xff
        unsigned char saved_isc;
 };
-struct ap_queue_status vfio_ap_irq_disable(struct vfio_ap_queue *q);
+
+int vfio_ap_mdev_register(void);
+void vfio_ap_mdev_unregister(void);
+int vfio_ap_mdev_reset_queue(struct vfio_ap_queue *q,
+                            unsigned int retry);
+
 #endif /* _VFIO_AP_PRIVATE_H_ */
index a2beee6..5988c30 100644 (file)
@@ -444,7 +444,8 @@ static int vnic_dev_init_devcmd2(struct vnic_dev *vdev)
        fetch_index = ioread32(&vdev->devcmd2->wq.ctrl->fetch_index);
        if (fetch_index == 0xFFFFFFFF) { /* check for hardware gone  */
                pr_err("error in devcmd2 init");
-               return -ENODEV;
+               err = -ENODEV;
+               goto err_free_wq;
        }
 
        /*
@@ -460,7 +461,7 @@ static int vnic_dev_init_devcmd2(struct vnic_dev *vdev)
        err = vnic_dev_alloc_desc_ring(vdev, &vdev->devcmd2->results_ring,
                        DEVCMD2_RING_SIZE, DEVCMD2_DESC_SIZE);
        if (err)
-               goto err_free_wq;
+               goto err_disable_wq;
 
        vdev->devcmd2->result =
                (struct devcmd2_result *) vdev->devcmd2->results_ring.descs;
@@ -481,8 +482,9 @@ static int vnic_dev_init_devcmd2(struct vnic_dev *vdev)
 
 err_free_desc_ring:
        vnic_dev_free_desc_ring(vdev, &vdev->devcmd2->results_ring);
-err_free_wq:
+err_disable_wq:
        vnic_wq_disable(&vdev->devcmd2->wq);
+err_free_wq:
        vnic_wq_free(&vdev->devcmd2->wq);
 err_free_devcmd2:
        kfree(vdev->devcmd2);
index 42e4d35..65f168c 100644 (file)
@@ -1744,7 +1744,7 @@ static int ibmvfc_queuecommand_lck(struct scsi_cmnd *cmnd,
                iu->pri_task_attr = IBMVFC_SIMPLE_TASK;
        }
 
-       vfc_cmd->correlation = cpu_to_be64(evt);
+       vfc_cmd->correlation = cpu_to_be64((u64)evt);
 
        if (likely(!(rc = ibmvfc_map_sg_data(cmnd, evt, vfc_cmd, vhost->dev))))
                return ibmvfc_send_event(evt, vhost, 0);
@@ -2418,7 +2418,7 @@ static int ibmvfc_abort_task_set(struct scsi_device *sdev)
                tmf->flags = cpu_to_be16((IBMVFC_NO_MEM_DESC | IBMVFC_TMF));
                evt->sync_iu = &rsp_iu;
 
-               tmf->correlation = cpu_to_be64(evt);
+               tmf->correlation = cpu_to_be64((u64)evt);
 
                init_completion(&evt->comp);
                rsp_rc = ibmvfc_send_event(evt, vhost, default_timeout);
@@ -3007,8 +3007,10 @@ static int ibmvfc_slave_configure(struct scsi_device *sdev)
        unsigned long flags = 0;
 
        spin_lock_irqsave(shost->host_lock, flags);
-       if (sdev->type == TYPE_DISK)
+       if (sdev->type == TYPE_DISK) {
                sdev->allow_restart = 1;
+               blk_queue_rq_timeout(sdev->request_queue, 120 * HZ);
+       }
        spin_unlock_irqrestore(shost->host_lock, flags);
        return 0;
 }
index d71afae..8410004 100644 (file)
@@ -1623,8 +1623,13 @@ static void fc_exch_recv_seq_resp(struct fc_exch_mgr *mp, struct fc_frame *fp)
                rc = fc_exch_done_locked(ep);
                WARN_ON(fc_seq_exch(sp) != ep);
                spin_unlock_bh(&ep->ex_lock);
-               if (!rc)
+               if (!rc) {
                        fc_exch_delete(ep);
+               } else {
+                       FC_EXCH_DBG(ep, "ep is completed already,"
+                                       "hence skip calling the resp\n");
+                       goto skip_resp;
+               }
        }
 
        /*
@@ -1643,6 +1648,7 @@ static void fc_exch_recv_seq_resp(struct fc_exch_mgr *mp, struct fc_frame *fp)
        if (!fc_invoke_resp(ep, sp, fp))
                fc_frame_free(fp);
 
+skip_resp:
        fc_exch_release(ep);
        return;
 rel:
@@ -1899,10 +1905,16 @@ static void fc_exch_reset(struct fc_exch *ep)
 
        fc_exch_hold(ep);
 
-       if (!rc)
+       if (!rc) {
                fc_exch_delete(ep);
+       } else {
+               FC_EXCH_DBG(ep, "ep is completed already,"
+                               "hence skip calling the resp\n");
+               goto skip_resp;
+       }
 
        fc_invoke_resp(ep, sp, ERR_PTR(-FC_EX_CLOSED));
+skip_resp:
        fc_seq_set_resp(sp, NULL, ep->arg);
        fc_exch_release(ep);
 }
index 1cb82fa..39d147e 100644 (file)
@@ -559,6 +559,9 @@ __lpfc_nvme_ls_req(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
                return -ENODEV;
        }
 
+       if (!vport->phba->sli4_hba.nvmels_wq)
+               return -ENOMEM;
+
        /*
         * there are two dma buf in the request, actually there is one and
         * the second one is just the start address + cmd size.
index af19209..63a4f48 100644 (file)
@@ -8244,11 +8244,9 @@ megasas_mgmt_fw_ioctl(struct megasas_instance *instance,
                        goto out;
                }
 
+               /* always store 64 bits regardless of addressing */
                sense_ptr = (void *)cmd->frame + ioc->sense_off;
-               if (instance->consistent_mask_64bit)
-                       put_unaligned_le64(sense_handle, sense_ptr);
-               else
-                       put_unaligned_le32(sense_handle, sense_ptr);
+               put_unaligned_le64(sense_handle, sense_ptr);
        }
 
        /*
index f80abe2..0e0fe5b 100644 (file)
@@ -42,7 +42,7 @@ MODULE_PARM_DESC(ql2xfulldump_on_mpifail,
 int ql2xenforce_iocb_limit = 1;
 module_param(ql2xenforce_iocb_limit, int, S_IRUGO | S_IWUSR);
 MODULE_PARM_DESC(ql2xenforce_iocb_limit,
-                "Enforce IOCB throttling, to avoid FW congestion. (default: 0)");
+                "Enforce IOCB throttling, to avoid FW congestion. (default: 1)");
 
 /*
  * CT6 CTX allocation cache
index cba1cf6..1e939a2 100644 (file)
@@ -541,7 +541,14 @@ int srp_reconnect_rport(struct srp_rport *rport)
        res = mutex_lock_interruptible(&rport->mutex);
        if (res)
                goto out;
-       scsi_target_block(&shost->shost_gendev);
+       if (rport->state != SRP_RPORT_FAIL_FAST)
+               /*
+                * sdev state must be SDEV_TRANSPORT_OFFLINE, transition
+                * to SDEV_BLOCK is illegal. Calling scsi_target_unblock()
+                * later is ok though, scsi_internal_device_unblock_nowait()
+                * treats SDEV_TRANSPORT_OFFLINE like SDEV_BLOCK.
+                */
+               scsi_target_block(&shost->shost_gendev);
        res = rport->state != SRP_RPORT_LOST ? i->f->reconnect(rport) : -ENODEV;
        pr_debug("%s (state %d): transport.reconnect() returned %d\n",
                 dev_name(&shost->shost_gendev), rport->state, res);
index 3f6dfed..b915b38 100644 (file)
@@ -72,6 +72,7 @@ config SCSI_UFS_DWC_TC_PCI
 config SCSI_UFSHCD_PLATFORM
        tristate "Platform bus based UFS Controller support"
        depends on SCSI_UFSHCD
+       depends on HAS_IOMEM
        help
        This selects the UFS host controller support. Select this if
        you have an UFS controller on Platform bus.
index e31d2c5..fb32d12 100644 (file)
@@ -3996,6 +3996,8 @@ int ufshcd_link_recovery(struct ufs_hba *hba)
        if (ret)
                dev_err(hba->dev, "%s: link recovery failed, err %d",
                        __func__, ret);
+       else
+               ufshcd_clear_ua_wluns(hba);
 
        return ret;
 }
@@ -4992,7 +4994,8 @@ ufshcd_transfer_rsp_status(struct ufs_hba *hba, struct ufshcd_lrb *lrbp)
                break;
        } /* end of switch */
 
-       if ((host_byte(result) != DID_OK) && !hba->silence_err_logs)
+       if ((host_byte(result) != DID_OK) &&
+           (host_byte(result) != DID_REQUEUE) && !hba->silence_err_logs)
                ufshcd_print_trs(hba, 1 << lrbp->task_tag, true);
        return result;
 }
@@ -6001,6 +6004,9 @@ skip_err_handling:
        ufshcd_scsi_unblock_requests(hba);
        ufshcd_err_handling_unprepare(hba);
        up(&hba->eh_sem);
+
+       if (!err && needs_reset)
+               ufshcd_clear_ua_wluns(hba);
 }
 
 /**
@@ -6295,9 +6301,13 @@ static irqreturn_t ufshcd_intr(int irq, void *__hba)
                intr_status = ufshcd_readl(hba, REG_INTERRUPT_STATUS);
        }
 
-       if (enabled_intr_status && retval == IRQ_NONE) {
-               dev_err(hba->dev, "%s: Unhandled interrupt 0x%08x\n",
-                                       __func__, intr_status);
+       if (enabled_intr_status && retval == IRQ_NONE &&
+                               !ufshcd_eh_in_progress(hba)) {
+               dev_err(hba->dev, "%s: Unhandled interrupt 0x%08x (0x%08x, 0x%08x)\n",
+                                       __func__,
+                                       intr_status,
+                                       hba->ufs_stats.last_intr_status,
+                                       enabled_intr_status);
                ufshcd_dump_regs(hba, 0, UFSHCI_REG_SPACE_SIZE, "host_regs: ");
        }
 
@@ -6341,7 +6351,10 @@ static int __ufshcd_issue_tm_cmd(struct ufs_hba *hba,
         * Even though we use wait_event() which sleeps indefinitely,
         * the maximum wait time is bounded by %TM_CMD_TIMEOUT.
         */
-       req = blk_get_request(q, REQ_OP_DRV_OUT, BLK_MQ_REQ_RESERVED);
+       req = blk_get_request(q, REQ_OP_DRV_OUT, 0);
+       if (IS_ERR(req))
+               return PTR_ERR(req);
+
        req->end_io_data = &wait;
        free_slot = req->tag;
        WARN_ON_ONCE(free_slot < 0 || free_slot >= hba->nutmrs);
@@ -6938,14 +6951,11 @@ static int ufshcd_host_reset_and_restore(struct ufs_hba *hba)
        ufshcd_set_clk_freq(hba, true);
 
        err = ufshcd_hba_enable(hba);
-       if (err)
-               goto out;
 
        /* Establish the link again and restore the device */
-       err = ufshcd_probe_hba(hba, false);
        if (!err)
-               ufshcd_clear_ua_wluns(hba);
-out:
+               err = ufshcd_probe_hba(hba, false);
+
        if (err)
                dev_err(hba->dev, "%s: Host init failed %d\n", __func__, err);
        ufshcd_update_evt_hist(hba, UFS_EVT_HOST_RESET, (u32)err);
@@ -7716,6 +7726,8 @@ static int ufshcd_add_lus(struct ufs_hba *hba)
        if (ret)
                goto out;
 
+       ufshcd_clear_ua_wluns(hba);
+
        /* Initialize devfreq after UFS device is detected */
        if (ufshcd_is_clkscaling_supported(hba)) {
                memcpy(&hba->clk_scaling.saved_pwr_info.info,
@@ -7917,8 +7929,6 @@ out:
                pm_runtime_put_sync(hba->dev);
                ufshcd_exit_clk_scaling(hba);
                ufshcd_hba_exit(hba);
-       } else {
-               ufshcd_clear_ua_wluns(hba);
        }
 }
 
@@ -8775,6 +8785,7 @@ enable_gating:
                ufshcd_resume_clkscaling(hba);
        hba->clk_gating.is_suspended = false;
        hba->dev_info.b_rpm_dev_flush_capable = false;
+       ufshcd_clear_ua_wluns(hba);
        ufshcd_release(hba);
 out:
        if (hba->dev_info.b_rpm_dev_flush_capable) {
@@ -8885,6 +8896,8 @@ static int ufshcd_resume(struct ufs_hba *hba, enum ufs_pm_op pm_op)
                cancel_delayed_work(&hba->rpm_dev_flush_recheck_work);
        }
 
+       ufshcd_clear_ua_wluns(hba);
+
        /* Schedule clock gating in case of no access to UFS device yet */
        ufshcd_release(hba);
 
index f8e070d..a14684f 100644 (file)
@@ -214,7 +214,7 @@ int __init register_intc_controller(struct intc_desc *desc)
                        d->window[k].phys = res->start;
                        d->window[k].size = resource_size(res);
                        d->window[k].virt = ioremap(res->start,
-                                                        resource_size(res));
+                                                   resource_size(res));
                        if (!d->window[k].virt)
                                goto err2;
                }
index 9e62ba9..939915a 100644 (file)
@@ -16,7 +16,7 @@
 #include <linux/debugfs.h>
 #include "internals.h"
 
-static int intc_irq_xlate_debug(struct seq_file *m, void *priv)
+static int intc_irq_xlate_show(struct seq_file *m, void *priv)
 {
        int i;
 
@@ -37,17 +37,7 @@ static int intc_irq_xlate_debug(struct seq_file *m, void *priv)
        return 0;
 }
 
-static int intc_irq_xlate_open(struct inode *inode, struct file *file)
-{
-       return single_open(file, intc_irq_xlate_debug, inode->i_private);
-}
-
-static const struct file_operations intc_irq_xlate_fops = {
-       .open = intc_irq_xlate_open,
-       .read = seq_read,
-       .llseek = seq_lseek,
-       .release = single_release,
-};
+DEFINE_SHOW_ATTRIBUTE(intc_irq_xlate);
 
 static int __init intc_irq_xlate_init(void)
 {
index c4472b6..698d21f 100644 (file)
@@ -271,8 +271,21 @@ struct soc_device * __init at91_soc_init(const struct at91_soc *socs)
        return soc_dev;
 }
 
+static const struct of_device_id at91_soc_allowed_list[] __initconst = {
+       { .compatible = "atmel,at91rm9200", },
+       { .compatible = "atmel,at91sam9", },
+       { .compatible = "atmel,sama5", },
+       { .compatible = "atmel,samv7", },
+       { }
+};
+
 static int __init atmel_soc_device_init(void)
 {
+       struct device_node *np = of_find_node_by_path("/");
+
+       if (!of_match_node(at91_soc_allowed_list, np))
+               return 0;
+
        at91_soc_init(socs);
 
        return 0;
index a9370f4..05812f8 100644 (file)
@@ -13,7 +13,7 @@ config SOC_IMX8M
        depends on ARCH_MXC || COMPILE_TEST
        default ARCH_MXC && ARM64
        select SOC_BUS
-       select ARM_GIC_V3 if ARCH_MXC
+       select ARM_GIC_V3 if ARCH_MXC && ARCH_MULTI_V7
        help
          If you say yes here you get support for the NXP i.MX8M family
          support, it will provide the SoC info like SoC family,
index 7c6b009..7a7c382 100644 (file)
@@ -8,6 +8,7 @@ config LITEX
 config LITEX_SOC_CONTROLLER
        tristate "Enable LiteX SoC Controller driver"
        depends on OF || COMPILE_TEST
+       depends on HAS_IOMEM
        select LITEX
        help
          This option enables the SoC Controller Driver which verifies
index 1217caf..9b07663 100644 (file)
@@ -140,12 +140,13 @@ struct litex_soc_ctrl_device {
        void __iomem *base;
 };
 
+#ifdef CONFIG_OF
 static const struct of_device_id litex_soc_ctrl_of_match[] = {
        {.compatible = "litex,soc-controller"},
        {},
 };
-
 MODULE_DEVICE_TABLE(of, litex_soc_ctrl_of_match);
+#endif /* CONFIG_OF */
 
 static int litex_soc_ctrl_probe(struct platform_device *pdev)
 {
index e9925c8..d90e4a2 100644 (file)
@@ -23,12 +23,7 @@ static const char * const sunxi_mbus_devices[] = {
        "allwinner,sun7i-a20-display-engine",
        "allwinner,sun8i-a23-display-engine",
        "allwinner,sun8i-a33-display-engine",
-       "allwinner,sun8i-a83t-display-engine",
-       "allwinner,sun8i-h3-display-engine",
-       "allwinner,sun8i-r40-display-engine",
-       "allwinner,sun8i-v3s-display-engine",
        "allwinner,sun9i-a80-display-engine",
-       "allwinner,sun50i-a64-display-engine",
 
        /*
         * And now we have the regular devices connected to the MBUS
index 77f0051..bf1468e 100644 (file)
@@ -860,6 +860,7 @@ static int omap_prm_reset_init(struct platform_device *pdev,
        const struct omap_rst_map *map;
        struct ti_prm_platform_data *pdata = dev_get_platdata(&pdev->dev);
        char buf[32];
+       u32 v;
 
        /*
         * Check if we have controllable resets. If either rstctrl is non-zero
@@ -907,6 +908,16 @@ static int omap_prm_reset_init(struct platform_device *pdev,
                map++;
        }
 
+       /* Quirk handling to assert rst_map_012 bits on reset and avoid errors */
+       if (prm->data->rstmap == rst_map_012) {
+               v = readl_relaxed(reset->prm->base + reset->prm->data->rstctrl);
+               if ((v & reset->mask) != reset->mask) {
+                       dev_dbg(&pdev->dev, "Asserting all resets: %08x\n", v);
+                       writel_relaxed(reset->mask, reset->prm->base +
+                                      reset->prm->data->rstctrl);
+               }
+       }
+
        return devm_reset_controller_register(&pdev->dev, &reset->rcdev);
 }
 
index cbc4c28..62ea0c9 100644 (file)
@@ -254,7 +254,8 @@ static int altera_spi_probe(struct platform_device *pdev)
                        dev_err(&pdev->dev,
                                "Invalid number of chipselect: %hu\n",
                                pdata->num_chipselect);
-                       return -EINVAL;
+                       err = -EINVAL;
+                       goto exit;
                }
 
                master->num_chipselect = pdata->num_chipselect;
index 70467b9..a3afd1b 100644 (file)
@@ -115,6 +115,7 @@ struct cdns_spi {
        void __iomem *regs;
        struct clk *ref_clk;
        struct clk *pclk;
+       unsigned int clk_rate;
        u32 speed_hz;
        const u8 *txbuf;
        u8 *rxbuf;
@@ -250,7 +251,7 @@ static void cdns_spi_config_clock_freq(struct spi_device *spi,
        u32 ctrl_reg, baud_rate_val;
        unsigned long frequency;
 
-       frequency = clk_get_rate(xspi->ref_clk);
+       frequency = xspi->clk_rate;
 
        ctrl_reg = cdns_spi_read(xspi, CDNS_SPI_CR);
 
@@ -558,8 +559,9 @@ static int cdns_spi_probe(struct platform_device *pdev)
        master->auto_runtime_pm = true;
        master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH;
 
+       xspi->clk_rate = clk_get_rate(xspi->ref_clk);
        /* Set to default valid value */
-       master->max_speed_hz = clk_get_rate(xspi->ref_clk) / 4;
+       master->max_speed_hz = xspi->clk_rate / 4;
        xspi->speed_hz = master->max_speed_hz;
 
        master->bits_per_word_mask = SPI_BPW_MASK(8);
index 9494257..6d8e0a0 100644 (file)
@@ -115,14 +115,13 @@ static void fsl_spi_chipselect(struct spi_device *spi, int value)
 {
        struct mpc8xxx_spi *mpc8xxx_spi = spi_master_get_devdata(spi->master);
        struct fsl_spi_platform_data *pdata;
-       bool pol = spi->mode & SPI_CS_HIGH;
        struct spi_mpc8xxx_cs   *cs = spi->controller_state;
 
        pdata = spi->dev.parent->parent->platform_data;
 
        if (value == BITBANG_CS_INACTIVE) {
                if (pdata->cs_control)
-                       pdata->cs_control(spi, !pol);
+                       pdata->cs_control(spi, false);
        }
 
        if (value == BITBANG_CS_ACTIVE) {
@@ -134,7 +133,7 @@ static void fsl_spi_chipselect(struct spi_device *spi, int value)
                fsl_spi_change_mode(spi);
 
                if (pdata->cs_control)
-                       pdata->cs_control(spi, pol);
+                       pdata->cs_control(spi, true);
        }
 }
 
index 859910e..8cb4d92 100644 (file)
@@ -682,6 +682,7 @@ static const struct of_device_id spidev_dt_ids[] = {
        { .compatible = "lwn,bk4" },
        { .compatible = "dh,dhcom-board" },
        { .compatible = "menlo,m53cpld" },
+       { .compatible = "cisco,spi-petra" },
        {},
 };
 MODULE_DEVICE_TABLE(of, spidev_dt_ids);
index b668a82..f5fbdbc 100644 (file)
@@ -367,7 +367,7 @@ hantro_reset_raw_fmt(struct hantro_ctx *ctx)
 
        hantro_reset_fmt(raw_fmt, raw_vpu_fmt);
        raw_fmt->width = encoded_fmt->width;
-       raw_fmt->width = encoded_fmt->width;
+       raw_fmt->height = encoded_fmt->height;
        if (ctx->is_encoder)
                hantro_set_fmt_out(ctx, raw_fmt);
        else
index 781c84a..de7442d 100644 (file)
@@ -203,7 +203,7 @@ static void _cedrus_write_ref_list(struct cedrus_ctx *ctx,
                position = cedrus_buf->codec.h264.position;
 
                sram_array[i] |= position << 1;
-               if (ref_list[i].fields & V4L2_H264_BOTTOM_FIELD_REF)
+               if (ref_list[i].fields == V4L2_H264_BOTTOM_FIELD_REF)
                        sram_array[i] |= BIT(0);
        }
 
index ab5a862..f798b0c 100644 (file)
@@ -20,9 +20,9 @@ enum country_code_type_t {
        COUNTRY_CODE_MAX
 };
 
-int rtw_regd_init(struct adapter *padapter,
-       void (*reg_notifier)(struct wiphy *wiphy,
-               struct regulatory_request *request));
+void rtw_regd_init(struct wiphy *wiphy,
+                  void (*reg_notifier)(struct wiphy *wiphy,
+                                       struct regulatory_request *request));
 void rtw_reg_notifier(struct wiphy *wiphy, struct regulatory_request *request);
 
 
index bf14172..1103231 100644 (file)
@@ -3211,9 +3211,6 @@ void rtw_cfg80211_init_wiphy(struct adapter *padapter)
                        rtw_cfg80211_init_ht_capab(&bands->ht_cap, NL80211_BAND_2GHZ, rf_type);
        }
 
-       /* init regulary domain */
-       rtw_regd_init(padapter, rtw_reg_notifier);
-
        /* copy mac_addr to wiphy */
        memcpy(wiphy->perm_addr, padapter->eeprompriv.mac_addr, ETH_ALEN);
 
@@ -3328,6 +3325,9 @@ int rtw_wdev_alloc(struct adapter *padapter, struct device *dev)
        *((struct adapter **)wiphy_priv(wiphy)) = padapter;
        rtw_cfg80211_preinit_wiphy(padapter, wiphy);
 
+       /* init regulary domain */
+       rtw_regd_init(wiphy, rtw_reg_notifier);
+
        ret = wiphy_register(wiphy);
        if (ret < 0) {
                DBG_8192C("Couldn't register wiphy device\n");
index b2208e5..301ffff 100644 (file)
@@ -339,8 +339,6 @@ static struct adapter *rtw_sdio_if1_init(struct dvobj_priv *dvobj, const struct
 
        padapter = rtw_netdev_priv(pnetdev);
 
-       rtw_wdev_alloc(padapter, dvobj_to_dev(dvobj));
-
        /* 3 3. init driver special setting, interface, OS and hardware relative */
 
        /* 4 3.1 set hardware operation functions */
@@ -378,6 +376,8 @@ static struct adapter *rtw_sdio_if1_init(struct dvobj_priv *dvobj, const struct
                goto free_hal_data;
        }
 
+       rtw_wdev_alloc(padapter, dvobj_to_dev(dvobj));
+
        /* 3 8. get WLan MAC address */
        /*  set mac addr */
        rtw_macaddr_cfg(&psdio->func->dev, padapter->eeprompriv.mac_addr);
index 578b9f7..2833fc6 100644 (file)
@@ -139,15 +139,11 @@ static void _rtw_regd_init_wiphy(struct rtw_regulatory *reg,
        _rtw_reg_apply_flags(wiphy);
 }
 
-int rtw_regd_init(struct adapter *padapter,
-                 void (*reg_notifier)(struct wiphy *wiphy,
-                                      struct regulatory_request *request))
+void rtw_regd_init(struct wiphy *wiphy,
+                  void (*reg_notifier)(struct wiphy *wiphy,
+                                       struct regulatory_request *request))
 {
-       struct wiphy *wiphy = padapter->rtw_wdev->wiphy;
-
        _rtw_regd_init_wiphy(NULL, wiphy, reg_notifier);
-
-       return 0;
 }
 
 void rtw_reg_notifier(struct wiphy *wiphy, struct regulatory_request *request)
index 893d1b4..1a9c504 100644 (file)
@@ -896,7 +896,7 @@ int iscsit_setup_np(
        else
                len = sizeof(struct sockaddr_in);
        /*
-        * Set SO_REUSEADDR, and disable Nagel Algorithm with TCP_NODELAY.
+        * Set SO_REUSEADDR, and disable Nagle Algorithm with TCP_NODELAY.
         */
        if (np->np_network_transport == ISCSI_TCP)
                tcp_sock_set_nodelay(sock->sk);
index 6b171ff..a5991df 100644 (file)
@@ -562,8 +562,6 @@ tcmu_get_block_page(struct tcmu_dev *udev, uint32_t dbi)
 
 static inline void tcmu_free_cmd(struct tcmu_cmd *tcmu_cmd)
 {
-       if (tcmu_cmd->se_cmd)
-               tcmu_cmd->se_cmd->priv = NULL;
        kfree(tcmu_cmd->dbi);
        kmem_cache_free(tcmu_cmd_cache, tcmu_cmd);
 }
@@ -1174,11 +1172,12 @@ tcmu_queue_cmd(struct se_cmd *se_cmd)
                return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE;
 
        mutex_lock(&udev->cmdr_lock);
-       se_cmd->priv = tcmu_cmd;
        if (!(se_cmd->transport_state & CMD_T_ABORTED))
                ret = queue_cmd_ring(tcmu_cmd, &scsi_ret);
        if (ret < 0)
                tcmu_free_cmd(tcmu_cmd);
+       else
+               se_cmd->priv = tcmu_cmd;
        mutex_unlock(&udev->cmdr_lock);
        return scsi_ret;
 }
@@ -1241,6 +1240,7 @@ tcmu_tmr_notify(struct se_device *se_dev, enum tcm_tmreq_table tmf,
 
                list_del_init(&cmd->queue_entry);
                tcmu_free_cmd(cmd);
+               se_cmd->priv = NULL;
                target_complete_cmd(se_cmd, SAM_STAT_TASK_ABORTED);
                unqueued = true;
        }
@@ -1332,6 +1332,7 @@ static void tcmu_handle_completion(struct tcmu_cmd *cmd, struct tcmu_cmd_entry *
        }
 
 done:
+       se_cmd->priv = NULL;
        if (read_len_valid) {
                pr_debug("read_len = %d\n", read_len);
                target_complete_cmd_with_length(cmd->se_cmd,
@@ -1478,6 +1479,7 @@ static void tcmu_check_expired_queue_cmd(struct tcmu_cmd *cmd)
        se_cmd = cmd->se_cmd;
        tcmu_free_cmd(cmd);
 
+       se_cmd->priv = NULL;
        target_complete_cmd(se_cmd, SAM_STAT_TASK_SET_FULL);
 }
 
@@ -1592,6 +1594,7 @@ static void run_qfull_queue(struct tcmu_dev *udev, bool fail)
                         * removed then LIO core will do the right thing and
                         * fail the retry.
                         */
+                       tcmu_cmd->se_cmd->priv = NULL;
                        target_complete_cmd(tcmu_cmd->se_cmd, SAM_STAT_BUSY);
                        tcmu_free_cmd(tcmu_cmd);
                        continue;
@@ -1605,6 +1608,7 @@ static void run_qfull_queue(struct tcmu_dev *udev, bool fail)
                         * Ignore scsi_ret for now. target_complete_cmd
                         * drops it.
                         */
+                       tcmu_cmd->se_cmd->priv = NULL;
                        target_complete_cmd(tcmu_cmd->se_cmd,
                                            SAM_STAT_CHECK_CONDITION);
                        tcmu_free_cmd(tcmu_cmd);
@@ -2212,6 +2216,7 @@ static void tcmu_reset_ring(struct tcmu_dev *udev, u8 err_level)
                if (!test_bit(TCMU_CMD_BIT_EXPIRED, &cmd->flags)) {
                        WARN_ON(!cmd->se_cmd);
                        list_del_init(&cmd->queue_entry);
+                       cmd->se_cmd->priv = NULL;
                        if (err_level == 1) {
                                /*
                                 * Userspace was not able to start the
index c981757..780d7c4 100644 (file)
@@ -7,6 +7,7 @@
 #include <linux/err.h>
 #include <linux/errno.h>
 #include <linux/mm.h>
+#include <linux/sched.h>
 #include <linux/slab.h>
 #include <linux/tee_drv.h>
 #include <linux/types.h>
@@ -148,7 +149,8 @@ u32 optee_do_call_with_arg(struct tee_context *ctx, phys_addr_t parg)
                         */
                        optee_cq_wait_for_completion(&optee->call_queue, &w);
                } else if (OPTEE_SMC_RETURN_IS_RPC(res.a0)) {
-                       might_sleep();
+                       if (need_resched())
+                               cond_resched();
                        param.a0 = res.a0;
                        param.a1 = res.a1;
                        param.a2 = res.a2;
index a5f988a..b5442f9 100644 (file)
@@ -56,7 +56,7 @@ static acpi_status tb_acpi_add_link(acpi_handle handle, u32 level, void *data,
         * managed with the xHCI and the SuperSpeed hub so we create the
         * link from xHCI instead.
         */
-       while (!dev_is_pci(dev))
+       while (dev && !dev_is_pci(dev))
                dev = dev->parent;
 
        if (!dev)
index 8b7f941..b8c4159 100644 (file)
@@ -2316,7 +2316,7 @@ static int icm_usb4_switch_nvm_authenticate_status(struct tb_switch *sw,
 
        if (auth && auth->reply.route_hi == sw->config.route_hi &&
            auth->reply.route_lo == sw->config.route_lo) {
-               tb_dbg(tb, "NVM_AUTH found for %llx flags 0x%#x status %#x\n",
+               tb_dbg(tb, "NVM_AUTH found for %llx flags %#x status %#x\n",
                       tb_route(sw), auth->reply.hdr.flags, auth->reply.status);
                if (auth->reply.hdr.flags & ICM_FLAGS_ERROR)
                        ret = -EIO;
index 319d68c..219e857 100644 (file)
@@ -2081,9 +2081,6 @@ static int canon_copy_from_read_buf(struct tty_struct *tty,
        return 0;
 }
 
-extern ssize_t redirected_tty_write(struct file *, const char __user *,
-                                                       size_t, loff_t *);
-
 /**
  *     job_control             -       check job control
  *     @tty: tty
@@ -2105,7 +2102,7 @@ static int job_control(struct tty_struct *tty, struct file *file)
        /* NOTE: not yet done after every sleep pending a thorough
           check of the logic of this change. -- jlc */
        /* don't stop on /dev/console */
-       if (file->f_op->write == redirected_tty_write)
+       if (file->f_op->write_iter == redirected_tty_write)
                return 0;
 
        return __tty_check_change(tty, SIGTTIN);
@@ -2309,7 +2306,7 @@ static ssize_t n_tty_write(struct tty_struct *tty, struct file *file,
        ssize_t retval = 0;
 
        /* Job control check -- must be done at start (POSIX.1 7.1.1.4). */
-       if (L_TOSTOP(tty) && file->f_op->write != redirected_tty_write) {
+       if (L_TOSTOP(tty) && file->f_op->write_iter != redirected_tty_write) {
                retval = tty_check_change(tty);
                if (retval)
                        return retval;
index 118b299..e0c00a1 100644 (file)
@@ -648,6 +648,14 @@ static void wait_for_xmitr(struct uart_port *port)
                                  (val & STAT_TX_RDY(port)), 1, 10000);
 }
 
+static void wait_for_xmite(struct uart_port *port)
+{
+       u32 val;
+
+       readl_poll_timeout_atomic(port->membase + UART_STAT, val,
+                                 (val & STAT_TX_EMP), 1, 10000);
+}
+
 static void mvebu_uart_console_putchar(struct uart_port *port, int ch)
 {
        wait_for_xmitr(port);
@@ -675,7 +683,7 @@ static void mvebu_uart_console_write(struct console *co, const char *s,
 
        uart_console_write(port, s, count, mvebu_uart_console_putchar);
 
-       wait_for_xmitr(port);
+       wait_for_xmite(port);
 
        if (ier)
                writel(ier, port->membase + UART_CTRL(port));
index 8034489..816e709 100644 (file)
@@ -143,12 +143,9 @@ LIST_HEAD(tty_drivers);                    /* linked list of tty drivers */
 DEFINE_MUTEX(tty_mutex);
 
 static ssize_t tty_read(struct file *, char __user *, size_t, loff_t *);
-static ssize_t tty_write(struct file *, const char __user *, size_t, loff_t *);
-ssize_t redirected_tty_write(struct file *, const char __user *,
-                                                       size_t, loff_t *);
+static ssize_t tty_write(struct kiocb *, struct iov_iter *);
 static __poll_t tty_poll(struct file *, poll_table *);
 static int tty_open(struct inode *, struct file *);
-long tty_ioctl(struct file *file, unsigned int cmd, unsigned long arg);
 #ifdef CONFIG_COMPAT
 static long tty_compat_ioctl(struct file *file, unsigned int cmd,
                                unsigned long arg);
@@ -438,8 +435,7 @@ static ssize_t hung_up_tty_read(struct file *file, char __user *buf,
        return 0;
 }
 
-static ssize_t hung_up_tty_write(struct file *file, const char __user *buf,
-                                size_t count, loff_t *ppos)
+static ssize_t hung_up_tty_write(struct kiocb *iocb, struct iov_iter *from)
 {
        return -EIO;
 }
@@ -478,7 +474,8 @@ static void tty_show_fdinfo(struct seq_file *m, struct file *file)
 static const struct file_operations tty_fops = {
        .llseek         = no_llseek,
        .read           = tty_read,
-       .write          = tty_write,
+       .write_iter     = tty_write,
+       .splice_write   = iter_file_splice_write,
        .poll           = tty_poll,
        .unlocked_ioctl = tty_ioctl,
        .compat_ioctl   = tty_compat_ioctl,
@@ -491,7 +488,8 @@ static const struct file_operations tty_fops = {
 static const struct file_operations console_fops = {
        .llseek         = no_llseek,
        .read           = tty_read,
-       .write          = redirected_tty_write,
+       .write_iter     = redirected_tty_write,
+       .splice_write   = iter_file_splice_write,
        .poll           = tty_poll,
        .unlocked_ioctl = tty_ioctl,
        .compat_ioctl   = tty_compat_ioctl,
@@ -503,7 +501,7 @@ static const struct file_operations console_fops = {
 static const struct file_operations hung_up_tty_fops = {
        .llseek         = no_llseek,
        .read           = hung_up_tty_read,
-       .write          = hung_up_tty_write,
+       .write_iter     = hung_up_tty_write,
        .poll           = hung_up_tty_poll,
        .unlocked_ioctl = hung_up_tty_ioctl,
        .compat_ioctl   = hung_up_tty_compat_ioctl,
@@ -606,9 +604,9 @@ static void __tty_hangup(struct tty_struct *tty, int exit_session)
        /* This breaks for file handles being sent over AF_UNIX sockets ? */
        list_for_each_entry(priv, &tty->tty_files, list) {
                filp = priv->file;
-               if (filp->f_op->write == redirected_tty_write)
+               if (filp->f_op->write_iter == redirected_tty_write)
                        cons_filp = filp;
-               if (filp->f_op->write != tty_write)
+               if (filp->f_op->write_iter != tty_write)
                        continue;
                closecount++;
                __tty_fasync(-1, filp, 0);      /* can't block */
@@ -901,9 +899,9 @@ static inline ssize_t do_tty_write(
        ssize_t (*write)(struct tty_struct *, struct file *, const unsigned char *, size_t),
        struct tty_struct *tty,
        struct file *file,
-       const char __user *buf,
-       size_t count)
+       struct iov_iter *from)
 {
+       size_t count = iov_iter_count(from);
        ssize_t ret, written = 0;
        unsigned int chunk;
 
@@ -955,14 +953,20 @@ static inline ssize_t do_tty_write(
                size_t size = count;
                if (size > chunk)
                        size = chunk;
+
                ret = -EFAULT;
-               if (copy_from_user(tty->write_buf, buf, size))
+               if (copy_from_iter(tty->write_buf, size, from) != size)
                        break;
+
                ret = write(tty, file, tty->write_buf, size);
                if (ret <= 0)
                        break;
+
+               /* FIXME! Have Al check this! */
+               if (ret != size)
+                       iov_iter_revert(from, size-ret);
+
                written += ret;
-               buf += ret;
                count -= ret;
                if (!count)
                        break;
@@ -1022,8 +1026,7 @@ void tty_write_message(struct tty_struct *tty, char *msg)
  *     write method will not be invoked in parallel for each device.
  */
 
-static ssize_t tty_write(struct file *file, const char __user *buf,
-                                               size_t count, loff_t *ppos)
+static ssize_t file_tty_write(struct file *file, struct kiocb *iocb, struct iov_iter *from)
 {
        struct tty_struct *tty = file_tty(file);
        struct tty_ldisc *ld;
@@ -1038,17 +1041,21 @@ static ssize_t tty_write(struct file *file, const char __user *buf,
                tty_err(tty, "missing write_room method\n");
        ld = tty_ldisc_ref_wait(tty);
        if (!ld)
-               return hung_up_tty_write(file, buf, count, ppos);
+               return hung_up_tty_write(iocb, from);
        if (!ld->ops->write)
                ret = -EIO;
        else
-               ret = do_tty_write(ld->ops->write, tty, file, buf, count);
+               ret = do_tty_write(ld->ops->write, tty, file, from);
        tty_ldisc_deref(ld);
        return ret;
 }
 
-ssize_t redirected_tty_write(struct file *file, const char __user *buf,
-                                               size_t count, loff_t *ppos)
+static ssize_t tty_write(struct kiocb *iocb, struct iov_iter *from)
+{
+       return file_tty_write(iocb->ki_filp, iocb, from);
+}
+
+ssize_t redirected_tty_write(struct kiocb *iocb, struct iov_iter *iter)
 {
        struct file *p = NULL;
 
@@ -1057,13 +1064,17 @@ ssize_t redirected_tty_write(struct file *file, const char __user *buf,
                p = get_file(redirect);
        spin_unlock(&redirect_lock);
 
+       /*
+        * We know the redirected tty is just another tty, we can can
+        * call file_tty_write() directly with that file pointer.
+        */
        if (p) {
                ssize_t res;
-               res = vfs_write(p, buf, count, &p->f_pos);
+               res = file_tty_write(p, iocb, iter);
                fput(p);
                return res;
        }
-       return tty_write(file, buf, count, ppos);
+       return tty_write(iocb, iter);
 }
 
 /*
@@ -2295,7 +2306,7 @@ static int tioccons(struct file *file)
 {
        if (!capable(CAP_SYS_ADMIN))
                return -EPERM;
-       if (file->f_op->write == redirected_tty_write) {
+       if (file->f_op->write_iter == redirected_tty_write) {
                struct file *f;
                spin_lock(&redirect_lock);
                f = redirect;
@@ -2305,6 +2316,12 @@ static int tioccons(struct file *file)
                        fput(f);
                return 0;
        }
+       if (file->f_op->write_iter != tty_write)
+               return -ENOTTY;
+       if (!(file->f_mode & FMODE_WRITE))
+               return -EBADF;
+       if (!(file->f_mode & FMODE_CAN_WRITE))
+               return -EINVAL;
        spin_lock(&redirect_lock);
        if (redirect) {
                spin_unlock(&redirect_lock);
index 22a56c4..7990fee 100644 (file)
@@ -185,7 +185,11 @@ static int cdns_imx_probe(struct platform_device *pdev)
        }
 
        data->num_clks = ARRAY_SIZE(imx_cdns3_core_clks);
-       data->clks = (struct clk_bulk_data *)imx_cdns3_core_clks;
+       data->clks = devm_kmemdup(dev, imx_cdns3_core_clks,
+                               sizeof(imx_cdns3_core_clks), GFP_KERNEL);
+       if (!data->clks)
+               return -ENOMEM;
+
        ret = devm_clk_bulk_get(dev, data->num_clks, data->clks);
        if (ret)
                return ret;
@@ -214,20 +218,16 @@ err:
        return ret;
 }
 
-static int cdns_imx_remove_core(struct device *dev, void *data)
-{
-       struct platform_device *pdev = to_platform_device(dev);
-
-       platform_device_unregister(pdev);
-
-       return 0;
-}
-
 static int cdns_imx_remove(struct platform_device *pdev)
 {
        struct device *dev = &pdev->dev;
+       struct cdns_imx *data = dev_get_drvdata(dev);
 
-       device_for_each_child(dev, NULL, cdns_imx_remove_core);
+       pm_runtime_get_sync(dev);
+       of_platform_depopulate(dev);
+       clk_bulk_disable_unprepare(data->num_clks, data->clks);
+       pm_runtime_disable(dev);
+       pm_runtime_put_noidle(dev);
        platform_set_drvdata(pdev, NULL);
 
        return 0;
index 134dc20..c9f6e97 100644 (file)
@@ -1329,14 +1329,17 @@ static int usblp_set_protocol(struct usblp *usblp, int protocol)
        if (protocol < USBLP_FIRST_PROTOCOL || protocol > USBLP_LAST_PROTOCOL)
                return -EINVAL;
 
-       alts = usblp->protocol[protocol].alt_setting;
-       if (alts < 0)
-               return -EINVAL;
-       r = usb_set_interface(usblp->dev, usblp->ifnum, alts);
-       if (r < 0) {
-               printk(KERN_ERR "usblp: can't set desired altsetting %d on interface %d\n",
-                       alts, usblp->ifnum);
-               return r;
+       /* Don't unnecessarily set the interface if there's a single alt. */
+       if (usblp->intf->num_altsetting > 1) {
+               alts = usblp->protocol[protocol].alt_setting;
+               if (alts < 0)
+                       return -EINVAL;
+               r = usb_set_interface(usblp->dev, usblp->ifnum, alts);
+               if (r < 0) {
+                       printk(KERN_ERR "usblp: can't set desired altsetting %d on interface %d\n",
+                               alts, usblp->ifnum);
+                       return r;
+               }
        }
 
        usblp->bidir = (usblp->protocol[protocol].epread != NULL);
index 0a0d111..ad4c943 100644 (file)
@@ -1543,7 +1543,6 @@ static void dwc2_hsotg_complete_oursetup(struct usb_ep *ep,
 static struct dwc2_hsotg_ep *ep_from_windex(struct dwc2_hsotg *hsotg,
                                            u32 windex)
 {
-       struct dwc2_hsotg_ep *ep;
        int dir = (windex & USB_DIR_IN) ? 1 : 0;
        int idx = windex & 0x7F;
 
@@ -1553,12 +1552,7 @@ static struct dwc2_hsotg_ep *ep_from_windex(struct dwc2_hsotg *hsotg,
        if (idx > hsotg->num_of_eps)
                return NULL;
 
-       ep = index_to_ep(hsotg, idx, dir);
-
-       if (idx && ep->dir_in != dir)
-               return NULL;
-
-       return ep;
+       return index_to_ep(hsotg, idx, dir);
 }
 
 /**
index 841daec..3101f0d 100644 (file)
@@ -1758,7 +1758,7 @@ static int dwc3_resume_common(struct dwc3 *dwc, pm_message_t msg)
                if (PMSG_IS_AUTO(msg))
                        break;
 
-               ret = dwc3_core_init(dwc);
+               ret = dwc3_core_init_for_resume(dwc);
                if (ret)
                        return ret;
 
index 30313b2..99c7fc0 100644 (file)
@@ -403,8 +403,10 @@ static int eth_bind(struct usb_composite_dev *cdev)
                struct usb_descriptor_header *usb_desc;
 
                usb_desc = usb_otg_descriptor_alloc(gadget);
-               if (!usb_desc)
+               if (!usb_desc) {
+                       status = -ENOMEM;
                        goto fail1;
+               }
                usb_otg_descriptor_init(gadget, usb_desc);
                otg_desc[0] = usb_desc;
                otg_desc[1] = NULL;
index 0bd6b20..02d8bfa 100644 (file)
@@ -420,7 +420,10 @@ static void ast_vhub_stop_active_req(struct ast_vhub_ep *ep,
        u32 state, reg, loops;
 
        /* Stop DMA activity */
-       writel(0, ep->epn.regs + AST_VHUB_EP_DMA_CTLSTAT);
+       if (ep->epn.desc_mode)
+               writel(VHUB_EP_DMA_CTRL_RESET, ep->epn.regs + AST_VHUB_EP_DMA_CTLSTAT);
+       else
+               writel(0, ep->epn.regs + AST_VHUB_EP_DMA_CTLSTAT);
 
        /* Wait for it to complete */
        for (loops = 0; loops < 1000; loops++) {
index 6497185..bfd8e77 100644 (file)
@@ -999,8 +999,10 @@ static int ast_vhub_of_parse_str_desc(struct ast_vhub *vhub,
                str_array[offset].s = NULL;
 
                ret = ast_vhub_str_alloc_add(vhub, &lang_str);
-               if (ret)
+               if (ret) {
+                       of_node_put(child);
                        break;
+               }
        }
 
        return ret;
index 3e88c76..fb01ff4 100644 (file)
@@ -17,7 +17,7 @@ if USB_BDC_UDC
 comment "Platform Support"
 config USB_BDC_PCI
        tristate "BDC support for PCIe based platforms"
-       depends on USB_PCI
+       depends on USB_PCI && BROKEN
        default USB_BDC_UDC
        help
                Enable support for platforms which have BDC connected through PCIe, such as Lego3 FPGA platform.
index 6a62bbd..ea114f9 100644 (file)
@@ -1529,10 +1529,13 @@ static ssize_t soft_connect_store(struct device *dev,
                struct device_attribute *attr, const char *buf, size_t n)
 {
        struct usb_udc          *udc = container_of(dev, struct usb_udc, dev);
+       ssize_t                 ret;
 
+       mutex_lock(&udc_lock);
        if (!udc->driver) {
                dev_err(dev, "soft-connect without a gadget driver\n");
-               return -EOPNOTSUPP;
+               ret = -EOPNOTSUPP;
+               goto out;
        }
 
        if (sysfs_streq(buf, "connect")) {
@@ -1543,10 +1546,14 @@ static ssize_t soft_connect_store(struct device *dev,
                usb_gadget_udc_stop(udc);
        } else {
                dev_err(dev, "unsupported command '%s'\n", buf);
-               return -EINVAL;
+               ret = -EINVAL;
+               goto out;
        }
 
-       return n;
+       ret = n;
+out:
+       mutex_unlock(&udc_lock);
+       return ret;
 }
 static DEVICE_ATTR_WO(soft_connect);
 
index 1a953f4..5706776 100644 (file)
@@ -2270,17 +2270,20 @@ static int dummy_hub_control(
                        }
                        fallthrough;
                case USB_PORT_FEAT_RESET:
+                       if (!(dum_hcd->port_status & USB_PORT_STAT_CONNECTION))
+                               break;
                        /* if it's already enabled, disable */
                        if (hcd->speed == HCD_USB3) {
-                               dum_hcd->port_status = 0;
                                dum_hcd->port_status =
                                        (USB_SS_PORT_STAT_POWER |
                                         USB_PORT_STAT_CONNECTION |
                                         USB_PORT_STAT_RESET);
-                       } else
+                       } else {
                                dum_hcd->port_status &= ~(USB_PORT_STAT_ENABLE
                                        | USB_PORT_STAT_LOW_SPEED
                                        | USB_PORT_STAT_HIGH_SPEED);
+                               dum_hcd->port_status |= USB_PORT_STAT_RESET;
+                       }
                        /*
                         * We want to reset device status. All but the
                         * Self powered feature
@@ -2292,7 +2295,8 @@ static int dummy_hub_control(
                         * interval? Is it still 50msec as for HS?
                         */
                        dum_hcd->re_timeout = jiffies + msecs_to_jiffies(50);
-                       fallthrough;
+                       set_link_state(dum_hcd);
+                       break;
                case USB_PORT_FEAT_C_CONNECTION:
                case USB_PORT_FEAT_C_RESET:
                case USB_PORT_FEAT_C_ENABLE:
index e358ae1..1926b32 100644 (file)
@@ -574,6 +574,7 @@ static int ehci_run (struct usb_hcd *hcd)
        struct ehci_hcd         *ehci = hcd_to_ehci (hcd);
        u32                     temp;
        u32                     hcc_params;
+       int                     rc;
 
        hcd->uses_new_polling = 1;
 
@@ -629,9 +630,20 @@ static int ehci_run (struct usb_hcd *hcd)
        down_write(&ehci_cf_port_reset_rwsem);
        ehci->rh_state = EHCI_RH_RUNNING;
        ehci_writel(ehci, FLAG_CF, &ehci->regs->configured_flag);
+
+       /* Wait until HC become operational */
        ehci_readl(ehci, &ehci->regs->command); /* unblock posted writes */
        msleep(5);
+       rc = ehci_handshake(ehci, &ehci->regs->status, STS_HALT, 0, 100 * 1000);
+
        up_write(&ehci_cf_port_reset_rwsem);
+
+       if (rc) {
+               ehci_err(ehci, "USB %x.%x, controller refused to start: %d\n",
+                        ((ehci->sbrn & 0xf0)>>4), (ehci->sbrn & 0x0f), rc);
+               return rc;
+       }
+
        ehci->last_periodic_enable = ktime_get_real();
 
        temp = HC_VERSION(ehci, ehci_readl(ehci, &ehci->caps->hc_capbase));
index 087402a..9f9ab5c 100644 (file)
@@ -345,6 +345,9 @@ static int ehci_bus_suspend (struct usb_hcd *hcd)
 
        unlink_empty_async_suspended(ehci);
 
+       /* Some Synopsys controllers mistakenly leave IAA turned on */
+       ehci_writel(ehci, STS_IAA, &ehci->regs->status);
+
        /* Any IAA cycle that started before the suspend is now invalid */
        end_iaa_cycle(ehci);
        ehci_handle_start_intr_unlinks(ehci);
index 45c54d5..b45e5bf 100644 (file)
@@ -200,6 +200,8 @@ static struct mu3h_sch_ep_info *create_sch_ep(struct usb_device *udev,
 
        sch_ep->sch_tt = tt;
        sch_ep->ep = ep;
+       INIT_LIST_HEAD(&sch_ep->endpoint);
+       INIT_LIST_HEAD(&sch_ep->tt_endpoint);
 
        return sch_ep;
 }
@@ -373,6 +375,7 @@ static void update_bus_bw(struct mu3h_sch_bw_info *sch_bw,
                                        sch_ep->bw_budget_table[j];
                }
        }
+       sch_ep->allocated = used;
 }
 
 static int check_sch_tt(struct usb_device *udev,
@@ -541,6 +544,22 @@ static int check_sch_bw(struct usb_device *udev,
        return 0;
 }
 
+static void destroy_sch_ep(struct usb_device *udev,
+       struct mu3h_sch_bw_info *sch_bw, struct mu3h_sch_ep_info *sch_ep)
+{
+       /* only release ep bw check passed by check_sch_bw() */
+       if (sch_ep->allocated)
+               update_bus_bw(sch_bw, sch_ep, 0);
+
+       list_del(&sch_ep->endpoint);
+
+       if (sch_ep->sch_tt) {
+               list_del(&sch_ep->tt_endpoint);
+               drop_tt(udev);
+       }
+       kfree(sch_ep);
+}
+
 static bool need_bw_sch(struct usb_host_endpoint *ep,
        enum usb_device_speed speed, int has_tt)
 {
@@ -583,6 +602,8 @@ int xhci_mtk_sch_init(struct xhci_hcd_mtk *mtk)
 
        mtk->sch_array = sch_array;
 
+       INIT_LIST_HEAD(&mtk->bw_ep_chk_list);
+
        return 0;
 }
 EXPORT_SYMBOL_GPL(xhci_mtk_sch_init);
@@ -601,19 +622,14 @@ int xhci_mtk_add_ep_quirk(struct usb_hcd *hcd, struct usb_device *udev,
        struct xhci_ep_ctx *ep_ctx;
        struct xhci_slot_ctx *slot_ctx;
        struct xhci_virt_device *virt_dev;
-       struct mu3h_sch_bw_info *sch_bw;
        struct mu3h_sch_ep_info *sch_ep;
-       struct mu3h_sch_bw_info *sch_array;
        unsigned int ep_index;
-       int bw_index;
-       int ret = 0;
 
        xhci = hcd_to_xhci(hcd);
        virt_dev = xhci->devs[udev->slot_id];
        ep_index = xhci_get_endpoint_index(&ep->desc);
        slot_ctx = xhci_get_slot_ctx(xhci, virt_dev->in_ctx);
        ep_ctx = xhci_get_ep_ctx(xhci, virt_dev->in_ctx, ep_index);
-       sch_array = mtk->sch_array;
 
        xhci_dbg(xhci, "%s() type:%d, speed:%d, mpkt:%d, dir:%d, ep:%p\n",
                __func__, usb_endpoint_type(&ep->desc), udev->speed,
@@ -632,35 +648,13 @@ int xhci_mtk_add_ep_quirk(struct usb_hcd *hcd, struct usb_device *udev,
                return 0;
        }
 
-       bw_index = get_bw_index(xhci, udev, ep);
-       sch_bw = &sch_array[bw_index];
-
        sch_ep = create_sch_ep(udev, ep, ep_ctx);
        if (IS_ERR_OR_NULL(sch_ep))
                return -ENOMEM;
 
        setup_sch_info(udev, ep_ctx, sch_ep);
 
-       ret = check_sch_bw(udev, sch_bw, sch_ep);
-       if (ret) {
-               xhci_err(xhci, "Not enough bandwidth!\n");
-               if (is_fs_or_ls(udev->speed))
-                       drop_tt(udev);
-
-               kfree(sch_ep);
-               return -ENOSPC;
-       }
-
-       list_add_tail(&sch_ep->endpoint, &sch_bw->bw_ep_list);
-
-       ep_ctx->reserved[0] |= cpu_to_le32(EP_BPKTS(sch_ep->pkts)
-               | EP_BCSCOUNT(sch_ep->cs_count) | EP_BBM(sch_ep->burst_mode));
-       ep_ctx->reserved[1] |= cpu_to_le32(EP_BOFFSET(sch_ep->offset)
-               | EP_BREPEAT(sch_ep->repeat));
-
-       xhci_dbg(xhci, " PKTS:%x, CSCOUNT:%x, BM:%x, OFFSET:%x, REPEAT:%x\n",
-                       sch_ep->pkts, sch_ep->cs_count, sch_ep->burst_mode,
-                       sch_ep->offset, sch_ep->repeat);
+       list_add_tail(&sch_ep->endpoint, &mtk->bw_ep_chk_list);
 
        return 0;
 }
@@ -675,7 +669,7 @@ void xhci_mtk_drop_ep_quirk(struct usb_hcd *hcd, struct usb_device *udev,
        struct xhci_virt_device *virt_dev;
        struct mu3h_sch_bw_info *sch_array;
        struct mu3h_sch_bw_info *sch_bw;
-       struct mu3h_sch_ep_info *sch_ep;
+       struct mu3h_sch_ep_info *sch_ep, *tmp;
        int bw_index;
 
        xhci = hcd_to_xhci(hcd);
@@ -694,17 +688,79 @@ void xhci_mtk_drop_ep_quirk(struct usb_hcd *hcd, struct usb_device *udev,
        bw_index = get_bw_index(xhci, udev, ep);
        sch_bw = &sch_array[bw_index];
 
-       list_for_each_entry(sch_ep, &sch_bw->bw_ep_list, endpoint) {
+       list_for_each_entry_safe(sch_ep, tmp, &sch_bw->bw_ep_list, endpoint) {
                if (sch_ep->ep == ep) {
-                       update_bus_bw(sch_bw, sch_ep, 0);
-                       list_del(&sch_ep->endpoint);
-                       if (is_fs_or_ls(udev->speed)) {
-                               list_del(&sch_ep->tt_endpoint);
-                               drop_tt(udev);
-                       }
-                       kfree(sch_ep);
+                       destroy_sch_ep(udev, sch_bw, sch_ep);
                        break;
                }
        }
 }
 EXPORT_SYMBOL_GPL(xhci_mtk_drop_ep_quirk);
+
+int xhci_mtk_check_bandwidth(struct usb_hcd *hcd, struct usb_device *udev)
+{
+       struct xhci_hcd_mtk *mtk = hcd_to_mtk(hcd);
+       struct xhci_hcd *xhci = hcd_to_xhci(hcd);
+       struct xhci_virt_device *virt_dev = xhci->devs[udev->slot_id];
+       struct mu3h_sch_bw_info *sch_bw;
+       struct mu3h_sch_ep_info *sch_ep, *tmp;
+       int bw_index, ret;
+
+       xhci_dbg(xhci, "%s() udev %s\n", __func__, dev_name(&udev->dev));
+
+       list_for_each_entry(sch_ep, &mtk->bw_ep_chk_list, endpoint) {
+               bw_index = get_bw_index(xhci, udev, sch_ep->ep);
+               sch_bw = &mtk->sch_array[bw_index];
+
+               ret = check_sch_bw(udev, sch_bw, sch_ep);
+               if (ret) {
+                       xhci_err(xhci, "Not enough bandwidth!\n");
+                       return -ENOSPC;
+               }
+       }
+
+       list_for_each_entry_safe(sch_ep, tmp, &mtk->bw_ep_chk_list, endpoint) {
+               struct xhci_ep_ctx *ep_ctx;
+               struct usb_host_endpoint *ep = sch_ep->ep;
+               unsigned int ep_index = xhci_get_endpoint_index(&ep->desc);
+
+               bw_index = get_bw_index(xhci, udev, ep);
+               sch_bw = &mtk->sch_array[bw_index];
+
+               list_move_tail(&sch_ep->endpoint, &sch_bw->bw_ep_list);
+
+               ep_ctx = xhci_get_ep_ctx(xhci, virt_dev->in_ctx, ep_index);
+               ep_ctx->reserved[0] |= cpu_to_le32(EP_BPKTS(sch_ep->pkts)
+                       | EP_BCSCOUNT(sch_ep->cs_count)
+                       | EP_BBM(sch_ep->burst_mode));
+               ep_ctx->reserved[1] |= cpu_to_le32(EP_BOFFSET(sch_ep->offset)
+                       | EP_BREPEAT(sch_ep->repeat));
+
+               xhci_dbg(xhci, " PKTS:%x, CSCOUNT:%x, BM:%x, OFFSET:%x, REPEAT:%x\n",
+                       sch_ep->pkts, sch_ep->cs_count, sch_ep->burst_mode,
+                       sch_ep->offset, sch_ep->repeat);
+       }
+
+       return xhci_check_bandwidth(hcd, udev);
+}
+EXPORT_SYMBOL_GPL(xhci_mtk_check_bandwidth);
+
+void xhci_mtk_reset_bandwidth(struct usb_hcd *hcd, struct usb_device *udev)
+{
+       struct xhci_hcd_mtk *mtk = hcd_to_mtk(hcd);
+       struct xhci_hcd *xhci = hcd_to_xhci(hcd);
+       struct mu3h_sch_bw_info *sch_bw;
+       struct mu3h_sch_ep_info *sch_ep, *tmp;
+       int bw_index;
+
+       xhci_dbg(xhci, "%s() udev %s\n", __func__, dev_name(&udev->dev));
+
+       list_for_each_entry_safe(sch_ep, tmp, &mtk->bw_ep_chk_list, endpoint) {
+               bw_index = get_bw_index(xhci, udev, sch_ep->ep);
+               sch_bw = &mtk->sch_array[bw_index];
+               destroy_sch_ep(udev, sch_bw, sch_ep);
+       }
+
+       xhci_reset_bandwidth(hcd, udev);
+}
+EXPORT_SYMBOL_GPL(xhci_mtk_reset_bandwidth);
index 8f321f3..fe010cc 100644 (file)
@@ -347,6 +347,8 @@ static void usb_wakeup_set(struct xhci_hcd_mtk *mtk, bool enable)
 static int xhci_mtk_setup(struct usb_hcd *hcd);
 static const struct xhci_driver_overrides xhci_mtk_overrides __initconst = {
        .reset = xhci_mtk_setup,
+       .check_bandwidth = xhci_mtk_check_bandwidth,
+       .reset_bandwidth = xhci_mtk_reset_bandwidth,
 };
 
 static struct hc_driver __read_mostly xhci_mtk_hc_driver;
index a93cfe8..cbb09df 100644 (file)
@@ -59,6 +59,7 @@ struct mu3h_sch_bw_info {
  * @ep_type: endpoint type
  * @maxpkt: max packet size of endpoint
  * @ep: address of usb_host_endpoint struct
+ * @allocated: the bandwidth is aready allocated from bus_bw
  * @offset: which uframe of the interval that transfer should be
  *             scheduled first time within the interval
  * @repeat: the time gap between two uframes that transfers are
@@ -86,6 +87,7 @@ struct mu3h_sch_ep_info {
        u32 ep_type;
        u32 maxpkt;
        void *ep;
+       bool allocated;
        /*
         * mtk xHCI scheduling information put into reserved DWs
         * in ep context
@@ -131,6 +133,7 @@ struct xhci_hcd_mtk {
        struct device *dev;
        struct usb_hcd *hcd;
        struct mu3h_sch_bw_info *sch_array;
+       struct list_head bw_ep_chk_list;
        struct mu3c_ippc_regs __iomem *ippc_regs;
        bool has_ippc;
        int num_u2_ports;
@@ -166,6 +169,8 @@ int xhci_mtk_add_ep_quirk(struct usb_hcd *hcd, struct usb_device *udev,
                struct usb_host_endpoint *ep);
 void xhci_mtk_drop_ep_quirk(struct usb_hcd *hcd, struct usb_device *udev,
                struct usb_host_endpoint *ep);
+int xhci_mtk_check_bandwidth(struct usb_hcd *hcd, struct usb_device *udev);
+void xhci_mtk_reset_bandwidth(struct usb_hcd *hcd, struct usb_device *udev);
 
 #else
 static inline int xhci_mtk_add_ep_quirk(struct usb_hcd *hcd,
@@ -179,6 +184,16 @@ static inline void xhci_mtk_drop_ep_quirk(struct usb_hcd *hcd,
 {
 }
 
+static inline int xhci_mtk_check_bandwidth(struct usb_hcd *hcd,
+               struct usb_device *udev)
+{
+       return 0;
+}
+
+static inline void xhci_mtk_reset_bandwidth(struct usb_hcd *hcd,
+               struct usb_device *udev)
+{
+}
 #endif
 
 #endif         /* _XHCI_MTK_H_ */
index 60651a5..8ca1a23 100644 (file)
@@ -8,6 +8,7 @@
 #include <linux/mbus.h>
 #include <linux/of.h>
 #include <linux/platform_device.h>
+#include <linux/phy/phy.h>
 
 #include <linux/usb.h>
 #include <linux/usb/hcd.h>
@@ -74,6 +75,47 @@ int xhci_mvebu_mbus_init_quirk(struct usb_hcd *hcd)
        return 0;
 }
 
+int xhci_mvebu_a3700_plat_setup(struct usb_hcd *hcd)
+{
+       struct xhci_hcd *xhci = hcd_to_xhci(hcd);
+       struct device *dev = hcd->self.controller;
+       struct phy *phy;
+       int ret;
+
+       /* Old bindings miss the PHY handle */
+       phy = of_phy_get(dev->of_node, "usb3-phy");
+       if (IS_ERR(phy) && PTR_ERR(phy) == -EPROBE_DEFER)
+               return -EPROBE_DEFER;
+       else if (IS_ERR(phy))
+               goto phy_out;
+
+       ret = phy_init(phy);
+       if (ret)
+               goto phy_put;
+
+       ret = phy_set_mode(phy, PHY_MODE_USB_HOST_SS);
+       if (ret)
+               goto phy_exit;
+
+       ret = phy_power_on(phy);
+       if (ret == -EOPNOTSUPP) {
+               /* Skip initializatin of XHCI PHY when it is unsupported by firmware */
+               dev_warn(dev, "PHY unsupported by firmware\n");
+               xhci->quirks |= XHCI_SKIP_PHY_INIT;
+       }
+       if (ret)
+               goto phy_exit;
+
+       phy_power_off(phy);
+phy_exit:
+       phy_exit(phy);
+phy_put:
+       of_phy_put(phy);
+phy_out:
+
+       return 0;
+}
+
 int xhci_mvebu_a3700_init_quirk(struct usb_hcd *hcd)
 {
        struct xhci_hcd *xhci = hcd_to_xhci(hcd);
index 3be0217..01bf3fc 100644 (file)
@@ -12,6 +12,7 @@ struct usb_hcd;
 
 #if IS_ENABLED(CONFIG_USB_XHCI_MVEBU)
 int xhci_mvebu_mbus_init_quirk(struct usb_hcd *hcd);
+int xhci_mvebu_a3700_plat_setup(struct usb_hcd *hcd);
 int xhci_mvebu_a3700_init_quirk(struct usb_hcd *hcd);
 #else
 static inline int xhci_mvebu_mbus_init_quirk(struct usb_hcd *hcd)
@@ -19,6 +20,11 @@ static inline int xhci_mvebu_mbus_init_quirk(struct usb_hcd *hcd)
        return 0;
 }
 
+static inline int xhci_mvebu_a3700_plat_setup(struct usb_hcd *hcd)
+{
+       return 0;
+}
+
 static inline int xhci_mvebu_a3700_init_quirk(struct usb_hcd *hcd)
 {
        return 0;
index 4d34f60..c1edcc9 100644 (file)
@@ -44,6 +44,16 @@ static void xhci_priv_plat_start(struct usb_hcd *hcd)
                priv->plat_start(hcd);
 }
 
+static int xhci_priv_plat_setup(struct usb_hcd *hcd)
+{
+       struct xhci_plat_priv *priv = hcd_to_xhci_priv(hcd);
+
+       if (!priv->plat_setup)
+               return 0;
+
+       return priv->plat_setup(hcd);
+}
+
 static int xhci_priv_init_quirk(struct usb_hcd *hcd)
 {
        struct xhci_plat_priv *priv = hcd_to_xhci_priv(hcd);
@@ -111,6 +121,7 @@ static const struct xhci_plat_priv xhci_plat_marvell_armada = {
 };
 
 static const struct xhci_plat_priv xhci_plat_marvell_armada3700 = {
+       .plat_setup = xhci_mvebu_a3700_plat_setup,
        .init_quirk = xhci_mvebu_a3700_init_quirk,
 };
 
@@ -330,7 +341,14 @@ static int xhci_plat_probe(struct platform_device *pdev)
 
        hcd->tpl_support = of_usb_host_tpl_support(sysdev->of_node);
        xhci->shared_hcd->tpl_support = hcd->tpl_support;
-       if (priv && (priv->quirks & XHCI_SKIP_PHY_INIT))
+
+       if (priv) {
+               ret = xhci_priv_plat_setup(hcd);
+               if (ret)
+                       goto disable_usb_phy;
+       }
+
+       if ((xhci->quirks & XHCI_SKIP_PHY_INIT) || (priv && (priv->quirks & XHCI_SKIP_PHY_INIT)))
                hcd->skip_phy_initialization = 1;
 
        if (priv && (priv->quirks & XHCI_SG_TRB_CACHE_SIZE_QUIRK))
index 1fb149d..561d0b7 100644 (file)
@@ -13,6 +13,7 @@
 struct xhci_plat_priv {
        const char *firmware_name;
        unsigned long long quirks;
+       int (*plat_setup)(struct usb_hcd *);
        void (*plat_start)(struct usb_hcd *);
        int (*init_quirk)(struct usb_hcd *);
        int (*suspend_quirk)(struct usb_hcd *);
index 5677b81..89c3be9 100644 (file)
@@ -699,11 +699,16 @@ static void xhci_unmap_td_bounce_buffer(struct xhci_hcd *xhci,
        dma_unmap_single(dev, seg->bounce_dma, ring->bounce_buf_len,
                         DMA_FROM_DEVICE);
        /* for in tranfers we need to copy the data from bounce to sg */
-       len = sg_pcopy_from_buffer(urb->sg, urb->num_sgs, seg->bounce_buf,
-                            seg->bounce_len, seg->bounce_offs);
-       if (len != seg->bounce_len)
-               xhci_warn(xhci, "WARN Wrong bounce buffer read length: %zu != %d\n",
-                               len, seg->bounce_len);
+       if (urb->num_sgs) {
+               len = sg_pcopy_from_buffer(urb->sg, urb->num_sgs, seg->bounce_buf,
+                                          seg->bounce_len, seg->bounce_offs);
+               if (len != seg->bounce_len)
+                       xhci_warn(xhci, "WARN Wrong bounce buffer read length: %zu != %d\n",
+                                 len, seg->bounce_len);
+       } else {
+               memcpy(urb->transfer_buffer + seg->bounce_offs, seg->bounce_buf,
+                      seg->bounce_len);
+       }
        seg->bounce_len = 0;
        seg->bounce_offs = 0;
 }
@@ -2931,6 +2936,8 @@ static void queue_trb(struct xhci_hcd *xhci, struct xhci_ring *ring,
        trb->field[0] = cpu_to_le32(field1);
        trb->field[1] = cpu_to_le32(field2);
        trb->field[2] = cpu_to_le32(field3);
+       /* make sure TRB is fully written before giving it to the controller */
+       wmb();
        trb->field[3] = cpu_to_le32(field4);
 
        trace_xhci_queue_trb(ring, trb);
@@ -3275,12 +3282,16 @@ static int xhci_align_td(struct xhci_hcd *xhci, struct urb *urb, u32 enqd_len,
 
        /* create a max max_pkt sized bounce buffer pointed to by last trb */
        if (usb_urb_dir_out(urb)) {
-               len = sg_pcopy_to_buffer(urb->sg, urb->num_sgs,
-                                  seg->bounce_buf, new_buff_len, enqd_len);
-               if (len != new_buff_len)
-                       xhci_warn(xhci,
-                               "WARN Wrong bounce buffer write length: %zu != %d\n",
-                               len, new_buff_len);
+               if (urb->num_sgs) {
+                       len = sg_pcopy_to_buffer(urb->sg, urb->num_sgs,
+                                                seg->bounce_buf, new_buff_len, enqd_len);
+                       if (len != new_buff_len)
+                               xhci_warn(xhci, "WARN Wrong bounce buffer write length: %zu != %d\n",
+                                         len, new_buff_len);
+               } else {
+                       memcpy(seg->bounce_buf, urb->transfer_buffer + enqd_len, new_buff_len);
+               }
+
                seg->bounce_dma = dma_map_single(dev, seg->bounce_buf,
                                                 max_pkt, DMA_TO_DEVICE);
        } else {
index 934be16..50bb91b 100644 (file)
@@ -623,6 +623,13 @@ static void tegra_xusb_mbox_handle(struct tegra_xusb *tegra,
                                                                     enable);
                        if (err < 0)
                                break;
+
+                       /*
+                        * wait 500us for LFPS detector to be disabled before
+                        * sending ACK
+                        */
+                       if (!enable)
+                               usleep_range(500, 1000);
                }
 
                if (err < 0) {
index e869405..345a221 100644 (file)
@@ -2985,7 +2985,7 @@ static void xhci_check_bw_drop_ep_streams(struct xhci_hcd *xhci,
  * else should be touching the xhci->devs[slot_id] structure, so we
  * don't need to take the xhci->lock for manipulating that.
  */
-static int xhci_check_bandwidth(struct usb_hcd *hcd, struct usb_device *udev)
+int xhci_check_bandwidth(struct usb_hcd *hcd, struct usb_device *udev)
 {
        int i;
        int ret = 0;
@@ -3083,7 +3083,7 @@ command_cleanup:
        return ret;
 }
 
-static void xhci_reset_bandwidth(struct usb_hcd *hcd, struct usb_device *udev)
+void xhci_reset_bandwidth(struct usb_hcd *hcd, struct usb_device *udev)
 {
        struct xhci_hcd *xhci;
        struct xhci_virt_device *virt_dev;
@@ -5510,6 +5510,10 @@ void xhci_init_driver(struct hc_driver *drv,
                        drv->reset = over->reset;
                if (over->start)
                        drv->start = over->start;
+               if (over->check_bandwidth)
+                       drv->check_bandwidth = over->check_bandwidth;
+               if (over->reset_bandwidth)
+                       drv->reset_bandwidth = over->reset_bandwidth;
        }
 }
 EXPORT_SYMBOL_GPL(xhci_init_driver);
index 25e57bc..07ff950 100644 (file)
@@ -1920,6 +1920,8 @@ struct xhci_driver_overrides {
        size_t extra_priv_size;
        int (*reset)(struct usb_hcd *hcd);
        int (*start)(struct usb_hcd *hcd);
+       int (*check_bandwidth)(struct usb_hcd *, struct usb_device *);
+       void (*reset_bandwidth)(struct usb_hcd *, struct usb_device *);
 };
 
 #define        XHCI_CFC_DELAY          10
@@ -2074,6 +2076,8 @@ int xhci_gen_setup(struct usb_hcd *hcd, xhci_get_quirks_t get_quirks);
 void xhci_shutdown(struct usb_hcd *hcd);
 void xhci_init_driver(struct hc_driver *drv,
                      const struct xhci_driver_overrides *over);
+int xhci_check_bandwidth(struct usb_hcd *hcd, struct usb_device *udev);
+void xhci_reset_bandwidth(struct usb_hcd *hcd, struct usb_device *udev);
 int xhci_disable_slot(struct xhci_hcd *xhci, u32 slot_id);
 int xhci_ext_cap_init(struct xhci_hcd *xhci);
 
index ac9a81a..e6fa137 100644 (file)
@@ -126,6 +126,7 @@ struct usbhs_pkt *usbhs_pkt_pop(struct usbhs_pipe *pipe, struct usbhs_pkt *pkt)
                }
 
                usbhs_pipe_clear_without_sequence(pipe, 0, 0);
+               usbhs_pipe_running(pipe, 0);
 
                __usbhsf_pkt_del(pkt);
        }
index fbb10df..7bec1e7 100644 (file)
@@ -61,6 +61,7 @@ static const struct usb_device_id id_table[] = {
        { USB_DEVICE(0x08e6, 0x5501) }, /* Gemalto Prox-PU/CU contactless smartcard reader */
        { USB_DEVICE(0x08FD, 0x000A) }, /* Digianswer A/S , ZigBee/802.15.4 MAC Device */
        { USB_DEVICE(0x0908, 0x01FF) }, /* Siemens RUGGEDCOM USB Serial Console */
+       { USB_DEVICE(0x0988, 0x0578) }, /* Teraoka AD2000 */
        { USB_DEVICE(0x0B00, 0x3070) }, /* Ingenico 3070 */
        { USB_DEVICE(0x0BED, 0x1100) }, /* MEI (TM) Cashflow-SC Bill/Voucher Acceptor */
        { USB_DEVICE(0x0BED, 0x1101) }, /* MEI series 2000 Combo Acceptor */
@@ -201,6 +202,7 @@ static const struct usb_device_id id_table[] = {
        { USB_DEVICE(0x1901, 0x0194) }, /* GE Healthcare Remote Alarm Box */
        { USB_DEVICE(0x1901, 0x0195) }, /* GE B850/B650/B450 CP2104 DP UART interface */
        { USB_DEVICE(0x1901, 0x0196) }, /* GE B850 CP2105 DP UART interface */
+       { USB_DEVICE(0x199B, 0xBA30) }, /* LORD WSDA-200-USB */
        { USB_DEVICE(0x19CF, 0x3000) }, /* Parrot NMEA GPS Flight Recorder */
        { USB_DEVICE(0x1ADB, 0x0001) }, /* Schweitzer Engineering C662 Cable */
        { USB_DEVICE(0x1B1C, 0x1C00) }, /* Corsair USB Dongle */
index 3fe9591..2049e66 100644 (file)
@@ -425,6 +425,8 @@ static void option_instat_callback(struct urb *urb);
 #define CINTERION_PRODUCT_AHXX_2RMNET          0x0084
 #define CINTERION_PRODUCT_AHXX_AUDIO           0x0085
 #define CINTERION_PRODUCT_CLS8                 0x00b0
+#define CINTERION_PRODUCT_MV31_MBIM            0x00b3
+#define CINTERION_PRODUCT_MV31_RMNET           0x00b7
 
 /* Olivetti products */
 #define OLIVETTI_VENDOR_ID                     0x0b3c
@@ -1914,6 +1916,10 @@ static const struct usb_device_id option_ids[] = {
        { USB_DEVICE(SIEMENS_VENDOR_ID, CINTERION_PRODUCT_HC25_MDMNET) },
        { USB_DEVICE(SIEMENS_VENDOR_ID, CINTERION_PRODUCT_HC28_MDM) }, /* HC28 enumerates with Siemens or Cinterion VID depending on FW revision */
        { USB_DEVICE(SIEMENS_VENDOR_ID, CINTERION_PRODUCT_HC28_MDMNET) },
+       { USB_DEVICE_INTERFACE_CLASS(CINTERION_VENDOR_ID, CINTERION_PRODUCT_MV31_MBIM, 0xff),
+         .driver_info = RSVD(3)},
+       { USB_DEVICE_INTERFACE_CLASS(CINTERION_VENDOR_ID, CINTERION_PRODUCT_MV31_RMNET, 0xff),
+         .driver_info = RSVD(0)},
        { USB_DEVICE(OLIVETTI_VENDOR_ID, OLIVETTI_PRODUCT_OLICARD100),
          .driver_info = RSVD(4) },
        { USB_DEVICE(OLIVETTI_VENDOR_ID, OLIVETTI_PRODUCT_OLICARD120),
index 5c92a57..08f742f 100644 (file)
@@ -15,6 +15,7 @@ struct mlx5_vdpa_direct_mr {
        struct sg_table sg_head;
        int log_size;
        int nsg;
+       int nent;
        struct list_head list;
        u64 offset;
 };
index 4b61956..d300f79 100644 (file)
@@ -25,17 +25,6 @@ static int get_octo_len(u64 len, int page_shift)
        return (npages + 1) / 2;
 }
 
-static void fill_sg(struct mlx5_vdpa_direct_mr *mr, void *in)
-{
-       struct scatterlist *sg;
-       __be64 *pas;
-       int i;
-
-       pas = MLX5_ADDR_OF(create_mkey_in, in, klm_pas_mtt);
-       for_each_sg(mr->sg_head.sgl, sg, mr->nsg, i)
-               (*pas) = cpu_to_be64(sg_dma_address(sg));
-}
-
 static void mlx5_set_access_mode(void *mkc, int mode)
 {
        MLX5_SET(mkc, mkc, access_mode_1_0, mode & 0x3);
@@ -45,10 +34,18 @@ static void mlx5_set_access_mode(void *mkc, int mode)
 static void populate_mtts(struct mlx5_vdpa_direct_mr *mr, __be64 *mtt)
 {
        struct scatterlist *sg;
+       int nsg = mr->nsg;
+       u64 dma_addr;
+       u64 dma_len;
+       int j = 0;
        int i;
 
-       for_each_sg(mr->sg_head.sgl, sg, mr->nsg, i)
-               mtt[i] = cpu_to_be64(sg_dma_address(sg));
+       for_each_sg(mr->sg_head.sgl, sg, mr->nent, i) {
+               for (dma_addr = sg_dma_address(sg), dma_len = sg_dma_len(sg);
+                    nsg && dma_len;
+                    nsg--, dma_addr += BIT(mr->log_size), dma_len -= BIT(mr->log_size))
+                       mtt[j++] = cpu_to_be64(dma_addr);
+       }
 }
 
 static int create_direct_mr(struct mlx5_vdpa_dev *mvdev, struct mlx5_vdpa_direct_mr *mr)
@@ -64,7 +61,6 @@ static int create_direct_mr(struct mlx5_vdpa_dev *mvdev, struct mlx5_vdpa_direct
                return -ENOMEM;
 
        MLX5_SET(create_mkey_in, in, uid, mvdev->res.uid);
-       fill_sg(mr, in);
        mkc = MLX5_ADDR_OF(create_mkey_in, in, memory_key_mkey_entry);
        MLX5_SET(mkc, mkc, lw, !!(mr->perm & VHOST_MAP_WO));
        MLX5_SET(mkc, mkc, lr, !!(mr->perm & VHOST_MAP_RO));
@@ -276,8 +272,8 @@ static int map_direct_mr(struct mlx5_vdpa_dev *mvdev, struct mlx5_vdpa_direct_mr
 done:
        mr->log_size = log_entity_size;
        mr->nsg = nsg;
-       err = dma_map_sg_attrs(dma, mr->sg_head.sgl, mr->nsg, DMA_BIDIRECTIONAL, 0);
-       if (!err)
+       mr->nent = dma_map_sg_attrs(dma, mr->sg_head.sgl, mr->nsg, DMA_BIDIRECTIONAL, 0);
+       if (!mr->nent)
                goto err_map;
 
        err = create_direct_mr(mvdev, mr);
index 88dde34..b5fe6d2 100644 (file)
@@ -87,6 +87,7 @@ struct mlx5_vq_restore_info {
        u64 device_addr;
        u64 driver_addr;
        u16 avail_index;
+       u16 used_index;
        bool ready;
        struct vdpa_callback cb;
        bool restore;
@@ -121,6 +122,7 @@ struct mlx5_vdpa_virtqueue {
        u32 virtq_id;
        struct mlx5_vdpa_net *ndev;
        u16 avail_idx;
+       u16 used_idx;
        int fw_state;
 
        /* keep last in the struct */
@@ -804,6 +806,7 @@ static int create_virtqueue(struct mlx5_vdpa_net *ndev, struct mlx5_vdpa_virtque
 
        obj_context = MLX5_ADDR_OF(create_virtio_net_q_in, in, obj_context);
        MLX5_SET(virtio_net_q_object, obj_context, hw_available_index, mvq->avail_idx);
+       MLX5_SET(virtio_net_q_object, obj_context, hw_used_index, mvq->used_idx);
        MLX5_SET(virtio_net_q_object, obj_context, queue_feature_bit_mask_12_3,
                 get_features_12_3(ndev->mvdev.actual_features));
        vq_ctx = MLX5_ADDR_OF(virtio_net_q_object, obj_context, virtio_q_context);
@@ -1022,6 +1025,7 @@ static int connect_qps(struct mlx5_vdpa_net *ndev, struct mlx5_vdpa_virtqueue *m
 struct mlx5_virtq_attr {
        u8 state;
        u16 available_index;
+       u16 used_index;
 };
 
 static int query_virtqueue(struct mlx5_vdpa_net *ndev, struct mlx5_vdpa_virtqueue *mvq,
@@ -1052,6 +1056,7 @@ static int query_virtqueue(struct mlx5_vdpa_net *ndev, struct mlx5_vdpa_virtqueu
        memset(attr, 0, sizeof(*attr));
        attr->state = MLX5_GET(virtio_net_q_object, obj_context, state);
        attr->available_index = MLX5_GET(virtio_net_q_object, obj_context, hw_available_index);
+       attr->used_index = MLX5_GET(virtio_net_q_object, obj_context, hw_used_index);
        kfree(out);
        return 0;
 
@@ -1535,6 +1540,16 @@ static void teardown_virtqueues(struct mlx5_vdpa_net *ndev)
        }
 }
 
+static void clear_virtqueues(struct mlx5_vdpa_net *ndev)
+{
+       int i;
+
+       for (i = ndev->mvdev.max_vqs - 1; i >= 0; i--) {
+               ndev->vqs[i].avail_idx = 0;
+               ndev->vqs[i].used_idx = 0;
+       }
+}
+
 /* TODO: cross-endian support */
 static inline bool mlx5_vdpa_is_little_endian(struct mlx5_vdpa_dev *mvdev)
 {
@@ -1610,6 +1625,7 @@ static int save_channel_info(struct mlx5_vdpa_net *ndev, struct mlx5_vdpa_virtqu
                return err;
 
        ri->avail_index = attr.available_index;
+       ri->used_index = attr.used_index;
        ri->ready = mvq->ready;
        ri->num_ent = mvq->num_ent;
        ri->desc_addr = mvq->desc_addr;
@@ -1654,6 +1670,7 @@ static void restore_channels_info(struct mlx5_vdpa_net *ndev)
                        continue;
 
                mvq->avail_idx = ri->avail_index;
+               mvq->used_idx = ri->used_index;
                mvq->ready = ri->ready;
                mvq->num_ent = ri->num_ent;
                mvq->desc_addr = ri->desc_addr;
@@ -1768,6 +1785,7 @@ static void mlx5_vdpa_set_status(struct vdpa_device *vdev, u8 status)
        if (!status) {
                mlx5_vdpa_info(mvdev, "performing device reset\n");
                teardown_driver(ndev);
+               clear_virtqueues(ndev);
                mlx5_vdpa_destroy_mr(&ndev->mvdev);
                ndev->mvdev.status = 0;
                ndev->mvdev.mlx_features = 0;
index c8f0282..18ffd05 100644 (file)
@@ -714,6 +714,23 @@ static bool xs_hvm_defer_init_for_callback(void)
 #endif
 }
 
+static int xenbus_probe_thread(void *unused)
+{
+       DEFINE_WAIT(w);
+
+       /*
+        * We actually just want to wait for *any* trigger of xb_waitq,
+        * and run xenbus_probe() the moment it occurs.
+        */
+       prepare_to_wait(&xb_waitq, &w, TASK_INTERRUPTIBLE);
+       schedule();
+       finish_wait(&xb_waitq, &w);
+
+       DPRINTK("probing");
+       xenbus_probe();
+       return 0;
+}
+
 static int __init xenbus_probe_initcall(void)
 {
        /*
@@ -725,6 +742,20 @@ static int __init xenbus_probe_initcall(void)
             !xs_hvm_defer_init_for_callback()))
                xenbus_probe();
 
+       /*
+        * For XS_LOCAL, spawn a thread which will wait for xenstored
+        * or a xenstore-stubdom to be started, then probe. It will be
+        * triggered when communication starts happening, by waiting
+        * on xb_waitq.
+        */
+       if (xen_store_domain_type == XS_LOCAL) {
+               struct task_struct *probe_task;
+
+               probe_task = kthread_run(xenbus_probe_thread, NULL,
+                                        "xenbus_probe");
+               if (IS_ERR(probe_task))
+                       return PTR_ERR(probe_task);
+       }
        return 0;
 }
 device_initcall(xenbus_probe_initcall);
index accdd89..b297525 100644 (file)
@@ -193,7 +193,7 @@ static int __init afs_init(void)
                goto error_cache;
 #endif
 
-       ret = register_pernet_subsys(&afs_net_ops);
+       ret = register_pernet_device(&afs_net_ops);
        if (ret < 0)
                goto error_net;
 
@@ -213,7 +213,7 @@ static int __init afs_init(void)
 error_proc:
        afs_fs_exit();
 error_fs:
-       unregister_pernet_subsys(&afs_net_ops);
+       unregister_pernet_device(&afs_net_ops);
 error_net:
 #ifdef CONFIG_AFS_FSCACHE
        fscache_unregister_netfs(&afs_cache_netfs);
@@ -244,7 +244,7 @@ static void __exit afs_exit(void)
 
        proc_remove(afs_proc_symlink);
        afs_fs_exit();
-       unregister_pernet_subsys(&afs_net_ops);
+       unregister_pernet_device(&afs_net_ops);
 #ifdef CONFIG_AFS_FSCACHE
        fscache_unregister_netfs(&afs_cache_netfs);
 #endif
index 3b8963e..235b504 100644 (file)
@@ -130,7 +130,15 @@ EXPORT_SYMBOL(truncate_bdev_range);
 
 static void set_init_blocksize(struct block_device *bdev)
 {
-       bdev->bd_inode->i_blkbits = blksize_bits(bdev_logical_block_size(bdev));
+       unsigned int bsize = bdev_logical_block_size(bdev);
+       loff_t size = i_size_read(bdev->bd_inode);
+
+       while (bsize < PAGE_SIZE) {
+               if (size & bsize)
+                       break;
+               bsize <<= 1;
+       }
+       bdev->bd_inode->i_blkbits = blksize_bits(bsize);
 }
 
 int set_blocksize(struct block_device *bdev, int size)
index 02d7d7b..9cadacf 100644 (file)
@@ -3117,7 +3117,7 @@ void btrfs_backref_error_cleanup(struct btrfs_backref_cache *cache,
                list_del_init(&lower->list);
                if (lower == node)
                        node = NULL;
-               btrfs_backref_free_node(cache, lower);
+               btrfs_backref_drop_node(cache, lower);
        }
 
        btrfs_backref_cleanup_node(cache, node);
index 52f2198..48ebc10 100644 (file)
@@ -673,7 +673,15 @@ static noinline void caching_thread(struct btrfs_work *work)
                wake_up(&caching_ctl->wait);
        }
 
-       if (btrfs_fs_compat_ro(fs_info, FREE_SPACE_TREE))
+       /*
+        * If we are in the transaction that populated the free space tree we
+        * can't actually cache from the free space tree as our commit root and
+        * real root are the same, so we could change the contents of the blocks
+        * while caching.  Instead do the slow caching in this case, and after
+        * the transaction has committed we will be safe.
+        */
+       if (btrfs_fs_compat_ro(fs_info, FREE_SPACE_TREE) &&
+           !(test_bit(BTRFS_FS_FREE_SPACE_TREE_UNTRUSTED, &fs_info->flags)))
                ret = load_free_space_tree(caching_ctl);
        else
                ret = load_extent_tree_free(caching_ctl);
@@ -2669,7 +2677,8 @@ again:
         * Go through delayed refs for all the stuff we've just kicked off
         * and then loop back (just once)
         */
-       ret = btrfs_run_delayed_refs(trans, 0);
+       if (!ret)
+               ret = btrfs_run_delayed_refs(trans, 0);
        if (!ret && loops == 0) {
                loops++;
                spin_lock(&cur_trans->dirty_bgs_lock);
index e6e3759..4debdbd 100644 (file)
@@ -563,6 +563,9 @@ enum {
 
        /* Indicate that we need to cleanup space cache v1 */
        BTRFS_FS_CLEANUP_SPACE_CACHE_V1,
+
+       /* Indicate that we can't trust the free space tree for caching yet */
+       BTRFS_FS_FREE_SPACE_TREE_UNTRUSTED,
 };
 
 /*
index d79b836..0c335da 100644 (file)
@@ -2602,8 +2602,6 @@ int btrfs_pin_extent_for_log_replay(struct btrfs_trans_handle *trans,
        struct btrfs_block_group *cache;
        int ret;
 
-       btrfs_add_excluded_extent(trans->fs_info, bytenr, num_bytes);
-
        cache = btrfs_lookup_block_group(trans->fs_info, bytenr);
        if (!cache)
                return -EINVAL;
@@ -2615,11 +2613,19 @@ int btrfs_pin_extent_for_log_replay(struct btrfs_trans_handle *trans,
         * the pinned extents.
         */
        btrfs_cache_block_group(cache, 1);
+       /*
+        * Make sure we wait until the cache is completely built in case it is
+        * missing or is invalid and therefore needs to be rebuilt.
+        */
+       ret = btrfs_wait_block_group_cache_done(cache);
+       if (ret)
+               goto out;
 
        pin_down_extent(trans, cache, bytenr, num_bytes, 0);
 
        /* remove us from the free space cache (if we're there at all) */
        ret = btrfs_remove_free_space(cache, bytenr, num_bytes);
+out:
        btrfs_put_block_group(cache);
        return ret;
 }
@@ -2629,50 +2635,22 @@ static int __exclude_logged_extent(struct btrfs_fs_info *fs_info,
 {
        int ret;
        struct btrfs_block_group *block_group;
-       struct btrfs_caching_control *caching_ctl;
 
        block_group = btrfs_lookup_block_group(fs_info, start);
        if (!block_group)
                return -EINVAL;
 
-       btrfs_cache_block_group(block_group, 0);
-       caching_ctl = btrfs_get_caching_control(block_group);
-
-       if (!caching_ctl) {
-               /* Logic error */
-               BUG_ON(!btrfs_block_group_done(block_group));
-               ret = btrfs_remove_free_space(block_group, start, num_bytes);
-       } else {
-               /*
-                * We must wait for v1 caching to finish, otherwise we may not
-                * remove our space.
-                */
-               btrfs_wait_space_cache_v1_finished(block_group, caching_ctl);
-               mutex_lock(&caching_ctl->mutex);
-
-               if (start >= caching_ctl->progress) {
-                       ret = btrfs_add_excluded_extent(fs_info, start,
-                                                       num_bytes);
-               } else if (start + num_bytes <= caching_ctl->progress) {
-                       ret = btrfs_remove_free_space(block_group,
-                                                     start, num_bytes);
-               } else {
-                       num_bytes = caching_ctl->progress - start;
-                       ret = btrfs_remove_free_space(block_group,
-                                                     start, num_bytes);
-                       if (ret)
-                               goto out_lock;
+       btrfs_cache_block_group(block_group, 1);
+       /*
+        * Make sure we wait until the cache is completely built in case it is
+        * missing or is invalid and therefore needs to be rebuilt.
+        */
+       ret = btrfs_wait_block_group_cache_done(block_group);
+       if (ret)
+               goto out;
 
-                       num_bytes = (start + num_bytes) -
-                               caching_ctl->progress;
-                       start = caching_ctl->progress;
-                       ret = btrfs_add_excluded_extent(fs_info, start,
-                                                       num_bytes);
-               }
-out_lock:
-               mutex_unlock(&caching_ctl->mutex);
-               btrfs_put_caching_control(caching_ctl);
-       }
+       ret = btrfs_remove_free_space(block_group, start, num_bytes);
+out:
        btrfs_put_block_group(block_group);
        return ret;
 }
@@ -2863,9 +2841,6 @@ int btrfs_finish_extent_commit(struct btrfs_trans_handle *trans)
                        mutex_unlock(&fs_info->unused_bg_unpin_mutex);
                        break;
                }
-               if (test_bit(BTRFS_FS_LOG_RECOVERING, &fs_info->flags))
-                       clear_extent_bits(&fs_info->excluded_extents, start,
-                                         end, EXTENT_UPTODATE);
 
                if (btrfs_test_opt(fs_info, DISCARD_SYNC))
                        ret = btrfs_discard_extent(fs_info, start,
@@ -5549,7 +5524,15 @@ int btrfs_drop_snapshot(struct btrfs_root *root, int update_ref, int for_reloc)
                                goto out_free;
                        }
 
-                       trans = btrfs_start_transaction(tree_root, 0);
+                      /*
+                       * Use join to avoid potential EINTR from transaction
+                       * start. See wait_reserve_ticket and the whole
+                       * reservation callchain.
+                       */
+                       if (for_reloc)
+                               trans = btrfs_join_transaction(tree_root);
+                       else
+                               trans = btrfs_start_transaction(tree_root, 0);
                        if (IS_ERR(trans)) {
                                err = PTR_ERR(trans);
                                goto out_free;
index e33a65b..a33bca9 100644 (file)
@@ -1150,6 +1150,7 @@ int btrfs_create_free_space_tree(struct btrfs_fs_info *fs_info)
                return PTR_ERR(trans);
 
        set_bit(BTRFS_FS_CREATING_FREE_SPACE_TREE, &fs_info->flags);
+       set_bit(BTRFS_FS_FREE_SPACE_TREE_UNTRUSTED, &fs_info->flags);
        free_space_root = btrfs_create_tree(trans,
                                            BTRFS_FREE_SPACE_TREE_OBJECTID);
        if (IS_ERR(free_space_root)) {
@@ -1171,11 +1172,18 @@ int btrfs_create_free_space_tree(struct btrfs_fs_info *fs_info)
        btrfs_set_fs_compat_ro(fs_info, FREE_SPACE_TREE);
        btrfs_set_fs_compat_ro(fs_info, FREE_SPACE_TREE_VALID);
        clear_bit(BTRFS_FS_CREATING_FREE_SPACE_TREE, &fs_info->flags);
+       ret = btrfs_commit_transaction(trans);
 
-       return btrfs_commit_transaction(trans);
+       /*
+        * Now that we've committed the transaction any reading of our commit
+        * root will be safe, so we can cache from the free space tree now.
+        */
+       clear_bit(BTRFS_FS_FREE_SPACE_TREE_UNTRUSTED, &fs_info->flags);
+       return ret;
 
 abort:
        clear_bit(BTRFS_FS_CREATING_FREE_SPACE_TREE, &fs_info->flags);
+       clear_bit(BTRFS_FS_FREE_SPACE_TREE_UNTRUSTED, &fs_info->flags);
        btrfs_abort_transaction(trans, ret);
        btrfs_end_transaction(trans);
        return ret;
index ae97f4d..78a3537 100644 (file)
@@ -5512,6 +5512,21 @@ static int clone_range(struct send_ctx *sctx,
                        break;
                offset += clone_len;
                clone_root->offset += clone_len;
+
+               /*
+                * If we are cloning from the file we are currently processing,
+                * and using the send root as the clone root, we must stop once
+                * the current clone offset reaches the current eof of the file
+                * at the receiver, otherwise we would issue an invalid clone
+                * operation (source range going beyond eof) and cause the
+                * receiver to fail. So if we reach the current eof, bail out
+                * and fallback to a regular write.
+                */
+               if (clone_root->root == sctx->send_root &&
+                   clone_root->ino == sctx->cur_ino &&
+                   clone_root->offset >= sctx->cur_inode_next_write_offset)
+                       break;
+
                data_offset += clone_len;
 next:
                path->slots[0]++;
index 8e0f7a1..6af7f2b 100644 (file)
@@ -2264,14 +2264,6 @@ int btrfs_commit_transaction(struct btrfs_trans_handle *trans)
         */
        btrfs_free_log_root_tree(trans, fs_info);
 
-       /*
-        * commit_fs_roots() can call btrfs_save_ino_cache(), which generates
-        * new delayed refs. Must handle them or qgroup can be wrong.
-        */
-       ret = btrfs_run_delayed_refs(trans, (unsigned long)-1);
-       if (ret)
-               goto unlock_tree_log;
-
        /*
         * Since fs roots are all committed, we can get a quite accurate
         * new_roots. So let's do quota accounting.
index b62be84..d6c24c8 100644 (file)
@@ -433,7 +433,7 @@ static struct btrfs_device *__alloc_device(struct btrfs_fs_info *fs_info)
 
        atomic_set(&dev->reada_in_flight, 0);
        atomic_set(&dev->dev_stats_ccnt, 0);
-       btrfs_device_data_ordered_init(dev, fs_info);
+       btrfs_device_data_ordered_init(dev);
        INIT_RADIX_TREE(&dev->reada_zones, GFP_NOFS & ~__GFP_DIRECT_RECLAIM);
        INIT_RADIX_TREE(&dev->reada_extents, GFP_NOFS & ~__GFP_DIRECT_RECLAIM);
        extent_io_tree_init(fs_info, &dev->alloc_state,
@@ -4317,6 +4317,8 @@ int btrfs_recover_balance(struct btrfs_fs_info *fs_info)
                btrfs_warn(fs_info,
        "balance: cannot set exclusive op status, resume manually");
 
+       btrfs_release_path(path);
+
        mutex_lock(&fs_info->balance_mutex);
        BUG_ON(fs_info->balance_ctl);
        spin_lock(&fs_info->balance_lock);
index 1997a46..c43663d 100644 (file)
@@ -39,10 +39,10 @@ struct btrfs_io_geometry {
 #if BITS_PER_LONG==32 && defined(CONFIG_SMP)
 #include <linux/seqlock.h>
 #define __BTRFS_NEED_DEVICE_DATA_ORDERED
-#define btrfs_device_data_ordered_init(device, info)                           \
-       seqcount_mutex_init(&device->data_seqcount, &info->chunk_mutex)
+#define btrfs_device_data_ordered_init(device) \
+       seqcount_init(&device->data_seqcount)
 #else
-#define btrfs_device_data_ordered_init(device, info) do { } while (0)
+#define btrfs_device_data_ordered_init(device) do { } while (0)
 #endif
 
 #define BTRFS_DEV_STATE_WRITEABLE      (0)
@@ -76,8 +76,7 @@ struct btrfs_device {
        blk_status_t last_flush_error;
 
 #ifdef __BTRFS_NEED_DEVICE_DATA_ORDERED
-       /* A seqcount_t with associated chunk_mutex (for lockdep) */
-       seqcount_mutex_t data_seqcount;
+       seqcount_t data_seqcount;
 #endif
 
        /* the internal btrfs device id */
@@ -168,9 +167,11 @@ btrfs_device_get_##name(const struct btrfs_device *dev)                    \
 static inline void                                                     \
 btrfs_device_set_##name(struct btrfs_device *dev, u64 size)            \
 {                                                                      \
+       preempt_disable();                                              \
        write_seqcount_begin(&dev->data_seqcount);                      \
        dev->name = size;                                               \
        write_seqcount_end(&dev->data_seqcount);                        \
+       preempt_enable();                                               \
 }
 #elif BITS_PER_LONG==32 && defined(CONFIG_PREEMPTION)
 #define BTRFS_DEVICE_GETSET_FUNCS(name)                                        \
index 8bda092..e027c71 100644 (file)
@@ -413,7 +413,6 @@ int cachefiles_read_or_alloc_page(struct fscache_retrieval *op,
 
        inode = d_backing_inode(object->backer);
        ASSERT(S_ISREG(inode->i_mode));
-       ASSERT(inode->i_mapping->a_ops->readpages);
 
        /* calculate the shift required to use bmap */
        shift = PAGE_SHIFT - inode->i_sb->s_blocksize_bits;
@@ -713,7 +712,6 @@ int cachefiles_read_or_alloc_pages(struct fscache_retrieval *op,
 
        inode = d_backing_inode(object->backer);
        ASSERT(S_ISREG(inode->i_mode));
-       ASSERT(inode->i_mapping->a_ops->readpages);
 
        /* calculate the shift required to use bmap */
        shift = PAGE_SHIFT - inode->i_sb->s_blocksize_bits;
index 8405870..d87bd85 100644 (file)
@@ -5038,7 +5038,7 @@ bad:
        return;
 }
 
-static struct ceph_connection *con_get(struct ceph_connection *con)
+static struct ceph_connection *mds_get_con(struct ceph_connection *con)
 {
        struct ceph_mds_session *s = con->private;
 
@@ -5047,7 +5047,7 @@ static struct ceph_connection *con_get(struct ceph_connection *con)
        return NULL;
 }
 
-static void con_put(struct ceph_connection *con)
+static void mds_put_con(struct ceph_connection *con)
 {
        struct ceph_mds_session *s = con->private;
 
@@ -5058,7 +5058,7 @@ static void con_put(struct ceph_connection *con)
  * if the client is unresponsive for long enough, the mds will kill
  * the session entirely.
  */
-static void peer_reset(struct ceph_connection *con)
+static void mds_peer_reset(struct ceph_connection *con)
 {
        struct ceph_mds_session *s = con->private;
        struct ceph_mds_client *mdsc = s->s_mdsc;
@@ -5067,7 +5067,7 @@ static void peer_reset(struct ceph_connection *con)
        send_mds_reconnect(mdsc, s);
 }
 
-static void dispatch(struct ceph_connection *con, struct ceph_msg *msg)
+static void mds_dispatch(struct ceph_connection *con, struct ceph_msg *msg)
 {
        struct ceph_mds_session *s = con->private;
        struct ceph_mds_client *mdsc = s->s_mdsc;
@@ -5125,8 +5125,8 @@ out:
  * Note: returned pointer is the address of a structure that's
  * managed separately.  Caller must *not* attempt to free it.
  */
-static struct ceph_auth_handshake *get_authorizer(struct ceph_connection *con,
-                                       int *proto, int force_new)
+static struct ceph_auth_handshake *
+mds_get_authorizer(struct ceph_connection *con, int *proto, int force_new)
 {
        struct ceph_mds_session *s = con->private;
        struct ceph_mds_client *mdsc = s->s_mdsc;
@@ -5142,7 +5142,7 @@ static struct ceph_auth_handshake *get_authorizer(struct ceph_connection *con,
        return auth;
 }
 
-static int add_authorizer_challenge(struct ceph_connection *con,
+static int mds_add_authorizer_challenge(struct ceph_connection *con,
                                    void *challenge_buf, int challenge_buf_len)
 {
        struct ceph_mds_session *s = con->private;
@@ -5153,7 +5153,7 @@ static int add_authorizer_challenge(struct ceph_connection *con,
                                            challenge_buf, challenge_buf_len);
 }
 
-static int verify_authorizer_reply(struct ceph_connection *con)
+static int mds_verify_authorizer_reply(struct ceph_connection *con)
 {
        struct ceph_mds_session *s = con->private;
        struct ceph_mds_client *mdsc = s->s_mdsc;
@@ -5165,7 +5165,7 @@ static int verify_authorizer_reply(struct ceph_connection *con)
                NULL, NULL, NULL, NULL);
 }
 
-static int invalidate_authorizer(struct ceph_connection *con)
+static int mds_invalidate_authorizer(struct ceph_connection *con)
 {
        struct ceph_mds_session *s = con->private;
        struct ceph_mds_client *mdsc = s->s_mdsc;
@@ -5288,15 +5288,15 @@ static int mds_check_message_signature(struct ceph_msg *msg)
 }
 
 static const struct ceph_connection_operations mds_con_ops = {
-       .get = con_get,
-       .put = con_put,
-       .dispatch = dispatch,
-       .get_authorizer = get_authorizer,
-       .add_authorizer_challenge = add_authorizer_challenge,
-       .verify_authorizer_reply = verify_authorizer_reply,
-       .invalidate_authorizer = invalidate_authorizer,
-       .peer_reset = peer_reset,
+       .get = mds_get_con,
+       .put = mds_put_con,
        .alloc_msg = mds_alloc_msg,
+       .dispatch = mds_dispatch,
+       .peer_reset = mds_peer_reset,
+       .get_authorizer = mds_get_authorizer,
+       .add_authorizer_challenge = mds_add_authorizer_challenge,
+       .verify_authorizer_reply = mds_verify_authorizer_reply,
+       .invalidate_authorizer = mds_invalidate_authorizer,
        .sign_message = mds_sign_message,
        .check_message_signature = mds_check_message_signature,
        .get_auth_request = mds_get_auth_request,
index e4c6ae4..6b1ce4e 100644 (file)
@@ -133,8 +133,9 @@ cifs_build_devname(char *nodename, const char *prepath)
  * Caller is responsible for freeing returned value if it is not error.
  */
 char *cifs_compose_mount_options(const char *sb_mountdata,
-                                  const char *fullpath,
-                                  const struct dfs_info3_param *ref)
+                                const char *fullpath,
+                                const struct dfs_info3_param *ref,
+                                char **devname)
 {
        int rc;
        char *name;
@@ -231,7 +232,10 @@ char *cifs_compose_mount_options(const char *sb_mountdata,
        strcat(mountdata, "ip=");
        strcat(mountdata, srvIP);
 
-       kfree(name);
+       if (devname)
+               *devname = name;
+       else
+               kfree(name);
 
        /*cifs_dbg(FYI, "%s: parent mountdata: %s\n", __func__, sb_mountdata);*/
        /*cifs_dbg(FYI, "%s: submount mountdata: %s\n", __func__, mountdata );*/
@@ -278,7 +282,7 @@ static struct vfsmount *cifs_dfs_do_mount(struct dentry *mntpt,
 
        /* strip first '\' from fullpath */
        mountdata = cifs_compose_mount_options(cifs_sb->ctx->mount_options,
-                                              fullpath + 1, NULL);
+                                              fullpath + 1, NULL, NULL);
        if (IS_ERR(mountdata)) {
                kfree(devname);
                return (struct vfsmount *)mountdata;
index ce0d003..e46da53 100644 (file)
@@ -822,7 +822,7 @@ cifs_smb3_do_mount(struct file_system_type *fs_type,
                goto out;
        }
 
-       rc = cifs_setup_volume_info(cifs_sb->ctx);
+       rc = cifs_setup_volume_info(cifs_sb->ctx, NULL, old_ctx->UNC);
        if (rc) {
                root = ERR_PTR(rc);
                goto out;
index 340ff81..32f7a01 100644 (file)
@@ -78,7 +78,8 @@ extern char *cifs_build_path_to_root(struct smb3_fs_context *ctx,
                                     int add_treename);
 extern char *build_wildcard_path_from_dentry(struct dentry *direntry);
 extern char *cifs_compose_mount_options(const char *sb_mountdata,
-               const char *fullpath, const struct dfs_info3_param *ref);
+               const char *fullpath, const struct dfs_info3_param *ref,
+               char **devname);
 /* extern void renew_parental_timestamps(struct dentry *direntry);*/
 extern struct mid_q_entry *AllocMidQEntry(const struct smb_hdr *smb_buffer,
                                        struct TCP_Server_Info *server);
@@ -89,6 +90,7 @@ extern void cifs_wake_up_task(struct mid_q_entry *mid);
 extern int cifs_handle_standard(struct TCP_Server_Info *server,
                                struct mid_q_entry *mid);
 extern int smb3_parse_devname(const char *devname, struct smb3_fs_context *ctx);
+extern int smb3_parse_opt(const char *options, const char *key, char **val);
 extern bool cifs_match_ipaddr(struct sockaddr *srcaddr, struct sockaddr *rhs);
 extern int cifs_discard_remaining_data(struct TCP_Server_Info *server);
 extern int cifs_call_async(struct TCP_Server_Info *server,
@@ -549,7 +551,7 @@ extern int SMBencrypt(unsigned char *passwd, const unsigned char *c8,
                        unsigned char *p24);
 
 extern int
-cifs_setup_volume_info(struct smb3_fs_context *ctx);
+cifs_setup_volume_info(struct smb3_fs_context *ctx, const char *mntopts, const char *devname);
 
 extern struct TCP_Server_Info *
 cifs_find_tcp_session(struct smb3_fs_context *ctx);
index 5d39129..10fe6d6 100644 (file)
@@ -2195,7 +2195,7 @@ cifs_get_tcon(struct cifs_ses *ses, struct smb3_fs_context *ctx)
        if (ses->server->capabilities & SMB2_GLOBAL_CAP_DIRECTORY_LEASING)
                tcon->nohandlecache = ctx->nohandlecache;
        else
-               tcon->nohandlecache = 1;
+               tcon->nohandlecache = true;
        tcon->nodelete = ctx->nodelete;
        tcon->local_lease = ctx->local_lease;
        INIT_LIST_HEAD(&tcon->pending_opens);
@@ -2628,7 +2628,7 @@ void reset_cifs_unix_caps(unsigned int xid, struct cifs_tcon *tcon,
        } else if (ctx)
                tcon->unix_ext = 1; /* Unix Extensions supported */
 
-       if (tcon->unix_ext == 0) {
+       if (!tcon->unix_ext) {
                cifs_dbg(FYI, "Unix extensions disabled so not set on reconnect\n");
                return;
        }
@@ -2972,17 +2972,20 @@ expand_dfs_referral(const unsigned int xid, struct cifs_ses *ses,
        rc = dfs_cache_find(xid, ses, cifs_sb->local_nls, cifs_remap(cifs_sb),
                            ref_path, &referral, NULL);
        if (!rc) {
+               char *fake_devname = NULL;
+
                mdata = cifs_compose_mount_options(cifs_sb->ctx->mount_options,
-                                                  full_path + 1, &referral);
+                                                  full_path + 1, &referral,
+                                                  &fake_devname);
                free_dfs_info_param(&referral);
 
                if (IS_ERR(mdata)) {
                        rc = PTR_ERR(mdata);
                        mdata = NULL;
                } else {
-                       smb3_cleanup_fs_context_contents(ctx);
-                       rc = cifs_setup_volume_info(ctx);
+                       rc = cifs_setup_volume_info(ctx, mdata, fake_devname);
                }
+               kfree(fake_devname);
                kfree(cifs_sb->ctx->mount_options);
                cifs_sb->ctx->mount_options = mdata;
        }
@@ -3036,6 +3039,7 @@ static int setup_dfs_tgt_conn(const char *path, const char *full_path,
        struct dfs_info3_param ref = {0};
        char *mdata = NULL;
        struct smb3_fs_context fake_ctx = {NULL};
+       char *fake_devname = NULL;
 
        cifs_dbg(FYI, "%s: dfs path: %s\n", __func__, path);
 
@@ -3044,16 +3048,18 @@ static int setup_dfs_tgt_conn(const char *path, const char *full_path,
                return rc;
 
        mdata = cifs_compose_mount_options(cifs_sb->ctx->mount_options,
-                                          full_path + 1, &ref);
+                                          full_path + 1, &ref,
+                                          &fake_devname);
        free_dfs_info_param(&ref);
 
        if (IS_ERR(mdata)) {
                rc = PTR_ERR(mdata);
                mdata = NULL;
        } else
-               rc = cifs_setup_volume_info(&fake_ctx);
+               rc = cifs_setup_volume_info(&fake_ctx, mdata, fake_devname);
 
        kfree(mdata);
+       kfree(fake_devname);
 
        if (!rc) {
                /*
@@ -3122,10 +3128,24 @@ static int do_dfs_failover(const char *path, const char *full_path, struct cifs_
  * we should pass a clone of the original context?
  */
 int
-cifs_setup_volume_info(struct smb3_fs_context *ctx)
+cifs_setup_volume_info(struct smb3_fs_context *ctx, const char *mntopts, const char *devname)
 {
        int rc = 0;
 
+       smb3_parse_devname(devname, ctx);
+
+       if (mntopts) {
+               char *ip;
+
+               cifs_dbg(FYI, "%s: mntopts=%s\n", __func__, mntopts);
+               rc = smb3_parse_opt(mntopts, "ip", &ip);
+               if (!rc && !cifs_convert_address((struct sockaddr *)&ctx->dstaddr, ip,
+                                                strlen(ip))) {
+                       cifs_dbg(VFS, "%s: failed to convert ip address\n", __func__);
+                       return -EINVAL;
+               }
+       }
+
        if (ctx->nullauth) {
                cifs_dbg(FYI, "Anonymous login\n");
                kfree(ctx->username);
index 0fdb0de..4950ab0 100644 (file)
@@ -1417,7 +1417,7 @@ static struct cifs_ses *find_root_ses(struct vol_info *vi,
        int rc;
        struct cache_entry *ce;
        struct dfs_info3_param ref = {0};
-       char *mdata = NULL;
+       char *mdata = NULL, *devname = NULL;
        struct TCP_Server_Info *server;
        struct cifs_ses *ses;
        struct smb3_fs_context ctx = {NULL};
@@ -1444,7 +1444,8 @@ static struct cifs_ses *find_root_ses(struct vol_info *vi,
 
        up_read(&htable_rw_lock);
 
-       mdata = cifs_compose_mount_options(vi->mntdata, rpath, &ref);
+       mdata = cifs_compose_mount_options(vi->mntdata, rpath, &ref,
+                                          &devname);
        free_dfs_info_param(&ref);
 
        if (IS_ERR(mdata)) {
@@ -1453,7 +1454,7 @@ static struct cifs_ses *find_root_ses(struct vol_info *vi,
                goto out;
        }
 
-       rc = cifs_setup_volume_info(&ctx);
+       rc = cifs_setup_volume_info(&ctx, NULL, devname);
 
        if (rc) {
                ses = ERR_PTR(rc);
@@ -1472,6 +1473,7 @@ out:
        smb3_cleanup_fs_context_contents(&ctx);
        kfree(mdata);
        kfree(rpath);
+       kfree(devname);
 
        return ses;
 }
index 68900f1..97ac363 100644 (file)
@@ -737,6 +737,7 @@ static int
 cifs_d_revalidate(struct dentry *direntry, unsigned int flags)
 {
        struct inode *inode;
+       int rc;
 
        if (flags & LOOKUP_RCU)
                return -ECHILD;
@@ -746,8 +747,25 @@ cifs_d_revalidate(struct dentry *direntry, unsigned int flags)
                if ((flags & LOOKUP_REVAL) && !CIFS_CACHE_READ(CIFS_I(inode)))
                        CIFS_I(inode)->time = 0; /* force reval */
 
-               if (cifs_revalidate_dentry(direntry))
-                       return 0;
+               rc = cifs_revalidate_dentry(direntry);
+               if (rc) {
+                       cifs_dbg(FYI, "cifs_revalidate_dentry failed with rc=%d", rc);
+                       switch (rc) {
+                       case -ENOENT:
+                       case -ESTALE:
+                               /*
+                                * Those errors mean the dentry is invalid
+                                * (file was deleted or recreated)
+                                */
+                               return 0;
+                       default:
+                               /*
+                                * Otherwise some unexpected error happened
+                                * report it as-is to VFS layer
+                                */
+                               return rc;
+                       }
+               }
                else {
                        /*
                         * If the inode wasn't known to be a dfs entry when
index 076bcad..5111aad 100644 (file)
@@ -175,8 +175,10 @@ const struct fs_parameter_spec smb3_fs_parameters[] = {
        fsparam_flag_no("exec", Opt_ignore),
        fsparam_flag_no("dev", Opt_ignore),
        fsparam_flag_no("mand", Opt_ignore),
+       fsparam_flag_no("auto", Opt_ignore),
        fsparam_string("cred", Opt_ignore),
        fsparam_string("credentials", Opt_ignore),
+       fsparam_string("prefixpath", Opt_ignore),
        {}
 };
 
@@ -399,6 +401,37 @@ cifs_parse_smb_version(char *value, struct smb3_fs_context *ctx, bool is_smb3)
        return 0;
 }
 
+int smb3_parse_opt(const char *options, const char *key, char **val)
+{
+       int rc = -ENOENT;
+       char *opts, *orig, *p;
+
+       orig = opts = kstrdup(options, GFP_KERNEL);
+       if (!opts)
+               return -ENOMEM;
+
+       while ((p = strsep(&opts, ","))) {
+               char *nval;
+
+               if (!*p)
+                       continue;
+               if (strncasecmp(p, key, strlen(key)))
+                       continue;
+               nval = strchr(p, '=');
+               if (nval) {
+                       if (nval == p)
+                               continue;
+                       *nval++ = 0;
+                       *val = kstrndup(nval, strlen(nval), GFP_KERNEL);
+                       rc = !*val ? -ENOMEM : 0;
+                       goto out;
+               }
+       }
+out:
+       kfree(orig);
+       return rc;
+}
+
 /*
  * Parse a devname into substrings and populate the ctx->UNC and ctx->prepath
  * fields with the result. Returns 0 on success and an error otherwise
@@ -531,7 +564,7 @@ static int smb3_fs_context_validate(struct fs_context *fc)
 
        if (ctx->rdma && ctx->vals->protocol_id < SMB30_PROT_ID) {
                cifs_dbg(VFS, "SMB Direct requires Version >=3.0\n");
-               return -1;
+               return -EOPNOTSUPP;
        }
 
 #ifndef CONFIG_KEYS
@@ -554,7 +587,7 @@ static int smb3_fs_context_validate(struct fs_context *fc)
        /* make sure UNC has a share name */
        if (strlen(ctx->UNC) < 3 || !strchr(ctx->UNC + 3, '\\')) {
                cifs_dbg(VFS, "Malformed UNC. Unable to find share name.\n");
-               return -1;
+               return -ENOENT;
        }
 
        if (!ctx->got_ip) {
@@ -568,7 +601,7 @@ static int smb3_fs_context_validate(struct fs_context *fc)
                if (!cifs_convert_address((struct sockaddr *)&ctx->dstaddr,
                                          &ctx->UNC[2], len)) {
                        pr_err("Unable to determine destination address\n");
-                       return -1;
+                       return -EHOSTUNREACH;
                }
        }
 
@@ -1263,7 +1296,7 @@ static int smb3_fs_context_parse_param(struct fs_context *fc,
        return 0;
 
  cifs_parse_mount_err:
-       return 1;
+       return -EINVAL;
 }
 
 int smb3_init_fs_context(struct fs_context *fc)
index d85edf5..a5a9e33 100644 (file)
@@ -286,7 +286,7 @@ struct smb2_negotiate_req {
        __le32 NegotiateContextOffset; /* SMB3.1.1 only. MBZ earlier */
        __le16 NegotiateContextCount;  /* SMB3.1.1 only. MBZ earlier */
        __le16 Reserved2;
-       __le16 Dialects[1]; /* One dialect (vers=) at a time for now */
+       __le16 Dialects[4]; /* BB expand this if autonegotiate > 4 dialects */
 } __packed;
 
 /* Dialects */
index e9abb41..4a2b836 100644 (file)
@@ -338,7 +338,7 @@ __smb_send_rqst(struct TCP_Server_Info *server, int num_rqst,
        if (ssocket == NULL)
                return -EAGAIN;
 
-       if (signal_pending(current)) {
+       if (fatal_signal_pending(current)) {
                cifs_dbg(FYI, "signal pending before send request\n");
                return -ERESTARTSYS;
        }
@@ -429,7 +429,7 @@ unmask:
 
        if (signal_pending(current) && (total_len != send_length)) {
                cifs_dbg(FYI, "signal is pending after attempt to send\n");
-               rc = -EINTR;
+               rc = -ERESTARTSYS;
        }
 
        /* uncork it */
@@ -666,10 +666,22 @@ wait_for_compound_request(struct TCP_Server_Info *server, int num,
 
        if (*credits < num) {
                /*
-                * Return immediately if not too many requests in flight since
-                * we will likely be stuck on waiting for credits.
+                * If the server is tight on resources or just gives us less
+                * credits for other reasons (e.g. requests are coming out of
+                * order and the server delays granting more credits until it
+                * processes a missing mid) and we exhausted most available
+                * credits there may be situations when we try to send
+                * a compound request but we don't have enough credits. At this
+                * point the client needs to decide if it should wait for
+                * additional credits or fail the request. If at least one
+                * request is in flight there is a high probability that the
+                * server will return enough credits to satisfy this compound
+                * request.
+                *
+                * Return immediately if no requests in flight since we will be
+                * stuck on waiting for credits.
                 */
-               if (server->in_flight < num - *credits) {
+               if (server->in_flight == 0) {
                        spin_unlock(&server->req_lock);
                        trace_smb3_insufficient_credits(server->CurrentMid,
                                        server->hostname, scredits, sin_flight);
index e23752d..58d0f71 100644 (file)
@@ -1016,15 +1016,19 @@ ecryptfs_setxattr(struct dentry *dentry, struct inode *inode,
 {
        int rc;
        struct dentry *lower_dentry;
+       struct inode *lower_inode;
 
        lower_dentry = ecryptfs_dentry_to_lower(dentry);
-       if (!(d_inode(lower_dentry)->i_opflags & IOP_XATTR)) {
+       lower_inode = d_inode(lower_dentry);
+       if (!(lower_inode->i_opflags & IOP_XATTR)) {
                rc = -EOPNOTSUPP;
                goto out;
        }
-       rc = vfs_setxattr(lower_dentry, name, value, size, flags);
+       inode_lock(lower_inode);
+       rc = __vfs_setxattr_locked(lower_dentry, name, value, size, flags, NULL);
+       inode_unlock(lower_inode);
        if (!rc && inode)
-               fsstack_copy_attr_all(inode, d_inode(lower_dentry));
+               fsstack_copy_attr_all(inode, lower_inode);
 out:
        return rc;
 }
index acfb558..c41cb88 100644 (file)
@@ -1474,21 +1474,25 @@ __writeback_single_inode(struct inode *inode, struct writeback_control *wbc)
        }
 
        /*
-        * Some filesystems may redirty the inode during the writeback
-        * due to delalloc, clear dirty metadata flags right before
-        * write_inode()
+        * If the inode has dirty timestamps and we need to write them, call
+        * mark_inode_dirty_sync() to notify the filesystem about it and to
+        * change I_DIRTY_TIME into I_DIRTY_SYNC.
         */
-       spin_lock(&inode->i_lock);
-
-       dirty = inode->i_state & I_DIRTY;
        if ((inode->i_state & I_DIRTY_TIME) &&
-           ((dirty & I_DIRTY_INODE) ||
-            wbc->sync_mode == WB_SYNC_ALL || wbc->for_sync ||
+           (wbc->sync_mode == WB_SYNC_ALL || wbc->for_sync ||
             time_after(jiffies, inode->dirtied_time_when +
                        dirtytime_expire_interval * HZ))) {
-               dirty |= I_DIRTY_TIME;
                trace_writeback_lazytime(inode);
+               mark_inode_dirty_sync(inode);
        }
+
+       /*
+        * Some filesystems may redirty the inode during the writeback
+        * due to delalloc, clear dirty metadata flags right before
+        * write_inode()
+        */
+       spin_lock(&inode->i_lock);
+       dirty = inode->i_state & I_DIRTY;
        inode->i_state &= ~dirty;
 
        /*
@@ -1509,8 +1513,6 @@ __writeback_single_inode(struct inode *inode, struct writeback_control *wbc)
 
        spin_unlock(&inode->i_lock);
 
-       if (dirty & I_DIRTY_TIME)
-               mark_inode_dirty_sync(inode);
        /* Don't write the inode if only I_DIRTY_PAGES was set */
        if (dirty & ~I_DIRTY_PAGES) {
                int err = write_inode(inode, wbc);
index b5c1097..21c20fd 100644 (file)
@@ -735,9 +735,10 @@ static long hugetlbfs_fallocate(struct file *file, int mode, loff_t offset,
 
                mutex_unlock(&hugetlb_fault_mutex_table[hash]);
 
+               set_page_huge_active(page);
                /*
                 * unlock_page because locked by add_to_page_cache()
-                * page_put due to reference from alloc_huge_page()
+                * put_page() due to reference from alloc_huge_page()
                 */
                unlock_page(page);
                put_page(page);
index 985a9e3..1f68105 100644 (file)
@@ -1025,6 +1025,8 @@ static ssize_t io_import_iovec(int rw, struct io_kiocb *req,
 static int io_setup_async_rw(struct io_kiocb *req, const struct iovec *iovec,
                             const struct iovec *fast_iov,
                             struct iov_iter *iter, bool force);
+static void io_req_drop_files(struct io_kiocb *req);
+static void io_req_task_queue(struct io_kiocb *req);
 
 static struct kmem_cache *req_cachep;
 
@@ -1048,8 +1050,7 @@ EXPORT_SYMBOL(io_uring_get_socket);
 
 static inline void io_clean_op(struct io_kiocb *req)
 {
-       if (req->flags & (REQ_F_NEED_CLEANUP | REQ_F_BUFFER_SELECTED |
-                         REQ_F_INFLIGHT))
+       if (req->flags & (REQ_F_NEED_CLEANUP | REQ_F_BUFFER_SELECTED))
                __io_clean_op(req);
 }
 
@@ -1069,14 +1070,21 @@ static bool io_match_task(struct io_kiocb *head,
 {
        struct io_kiocb *req;
 
-       if (task && head->task != task)
+       if (task && head->task != task) {
+               /* in terms of cancelation, always match if req task is dead */
+               if (head->task->flags & PF_EXITING)
+                       return true;
                return false;
+       }
        if (!files)
                return true;
 
        io_for_each_link(req, head) {
-               if ((req->flags & REQ_F_WORK_INITIALIZED) &&
-                   (req->work.flags & IO_WQ_WORK_FILES) &&
+               if (!(req->flags & REQ_F_WORK_INITIALIZED))
+                       continue;
+               if (req->file && req->file->f_op == &io_uring_fops)
+                       return true;
+               if ((req->work.flags & IO_WQ_WORK_FILES) &&
                    req->work.identity->files == files)
                        return true;
        }
@@ -1394,6 +1402,8 @@ static void io_req_clean_work(struct io_kiocb *req)
                        free_fs_struct(fs);
                req->work.flags &= ~IO_WQ_WORK_FS;
        }
+       if (req->flags & REQ_F_INFLIGHT)
+               io_req_drop_files(req);
 
        io_put_identity(req->task->io_uring, req);
 }
@@ -1503,11 +1513,14 @@ static bool io_grab_identity(struct io_kiocb *req)
                        return false;
                atomic_inc(&id->files->count);
                get_nsproxy(id->nsproxy);
-               req->flags |= REQ_F_INFLIGHT;
 
-               spin_lock_irq(&ctx->inflight_lock);
-               list_add(&req->inflight_entry, &ctx->inflight_list);
-               spin_unlock_irq(&ctx->inflight_lock);
+               if (!(req->flags & REQ_F_INFLIGHT)) {
+                       req->flags |= REQ_F_INFLIGHT;
+
+                       spin_lock_irq(&ctx->inflight_lock);
+                       list_add(&req->inflight_entry, &ctx->inflight_list);
+                       spin_unlock_irq(&ctx->inflight_lock);
+               }
                req->work.flags |= IO_WQ_WORK_FILES;
        }
        if (!(req->work.flags & IO_WQ_WORK_MM) &&
@@ -1622,18 +1635,11 @@ static void __io_queue_deferred(struct io_ring_ctx *ctx)
        do {
                struct io_defer_entry *de = list_first_entry(&ctx->defer_list,
                                                struct io_defer_entry, list);
-               struct io_kiocb *link;
 
                if (req_need_defer(de->req, de->seq))
                        break;
                list_del_init(&de->list);
-               /* punt-init is done before queueing for defer */
-               link = __io_queue_async_work(de->req);
-               if (link) {
-                       __io_queue_linked_timeout(link);
-                       /* drop submission reference */
-                       io_put_req_deferred(link, 1);
-               }
+               io_req_task_queue(de->req);
                kfree(de);
        } while (!list_empty(&ctx->defer_list));
 }
@@ -1767,12 +1773,13 @@ static bool __io_cqring_overflow_flush(struct io_ring_ctx *ctx, bool force,
        struct io_kiocb *req, *tmp;
        struct io_uring_cqe *cqe;
        unsigned long flags;
-       bool all_flushed;
+       bool all_flushed, posted;
        LIST_HEAD(list);
 
        if (!force && __io_cqring_events(ctx) == rings->cq_ring_entries)
                return false;
 
+       posted = false;
        spin_lock_irqsave(&ctx->completion_lock, flags);
        list_for_each_entry_safe(req, tmp, &ctx->cq_overflow_list, compl.list) {
                if (!io_match_task(req, tsk, files))
@@ -1792,6 +1799,7 @@ static bool __io_cqring_overflow_flush(struct io_ring_ctx *ctx, bool force,
                        WRITE_ONCE(ctx->rings->cq_overflow,
                                   ctx->cached_cq_overflow);
                }
+               posted = true;
        }
 
        all_flushed = list_empty(&ctx->cq_overflow_list);
@@ -1801,9 +1809,11 @@ static bool __io_cqring_overflow_flush(struct io_ring_ctx *ctx, bool force,
                ctx->rings->sq_flags &= ~IORING_SQ_CQ_OVERFLOW;
        }
 
-       io_commit_cqring(ctx);
+       if (posted)
+               io_commit_cqring(ctx);
        spin_unlock_irqrestore(&ctx->completion_lock, flags);
-       io_cqring_ev_posted(ctx);
+       if (posted)
+               io_cqring_ev_posted(ctx);
 
        while (!list_empty(&list)) {
                req = list_first_entry(&list, struct io_kiocb, compl.list);
@@ -2195,6 +2205,9 @@ static void __io_req_task_submit(struct io_kiocb *req)
        else
                __io_req_task_cancel(req, -EFAULT);
        mutex_unlock(&ctx->uring_lock);
+
+       if (ctx->flags & IORING_SETUP_SQPOLL)
+               io_sq_thread_drop_mm_files();
 }
 
 static void io_req_task_submit(struct callback_head *cb)
@@ -2270,6 +2283,8 @@ static void io_req_free_batch_finish(struct io_ring_ctx *ctx,
                struct io_uring_task *tctx = rb->task->io_uring;
 
                percpu_counter_sub(&tctx->inflight, rb->task_refs);
+               if (atomic_read(&tctx->in_idle))
+                       wake_up(&tctx->wait);
                put_task_struct_many(rb->task, rb->task_refs);
                rb->task = NULL;
        }
@@ -2288,6 +2303,8 @@ static void io_req_free_batch(struct req_batch *rb, struct io_kiocb *req)
                        struct io_uring_task *tctx = rb->task->io_uring;
 
                        percpu_counter_sub(&tctx->inflight, rb->task_refs);
+                       if (atomic_read(&tctx->in_idle))
+                               wake_up(&tctx->wait);
                        put_task_struct_many(rb->task, rb->task_refs);
                }
                rb->task = req->task;
@@ -3548,7 +3565,7 @@ static int io_read(struct io_kiocb *req, bool force_nonblock,
 
        /* read it all, or we did blocking attempt. no retry. */
        if (!iov_iter_count(iter) || !force_nonblock ||
-           (req->file->f_flags & O_NONBLOCK))
+           (req->file->f_flags & O_NONBLOCK) || !(req->flags & REQ_F_ISREG))
                goto done;
 
        io_size -= ret;
@@ -4468,7 +4485,6 @@ static int io_close_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe)
         * io_wq_work.flags, so initialize io_wq_work firstly.
         */
        io_req_init_async(req);
-       req->work.flags |= IO_WQ_WORK_NO_CANCEL;
 
        if (unlikely(req->ctx->flags & IORING_SETUP_IOPOLL))
                return -EINVAL;
@@ -4501,6 +4517,8 @@ static int io_close(struct io_kiocb *req, bool force_nonblock,
 
        /* if the file has a flush method, be safe and punt to async */
        if (close->put_file->f_op->flush && force_nonblock) {
+               /* not safe to cancel at this point */
+               req->work.flags |= IO_WQ_WORK_NO_CANCEL;
                /* was never set, but play safe */
                req->flags &= ~REQ_F_NOWAIT;
                /* avoid grabbing files - we don't need the files */
@@ -6157,8 +6175,10 @@ static void io_req_drop_files(struct io_kiocb *req)
        struct io_uring_task *tctx = req->task->io_uring;
        unsigned long flags;
 
-       put_files_struct(req->work.identity->files);
-       put_nsproxy(req->work.identity->nsproxy);
+       if (req->work.flags & IO_WQ_WORK_FILES) {
+               put_files_struct(req->work.identity->files);
+               put_nsproxy(req->work.identity->nsproxy);
+       }
        spin_lock_irqsave(&ctx->inflight_lock, flags);
        list_del(&req->inflight_entry);
        spin_unlock_irqrestore(&ctx->inflight_lock, flags);
@@ -6225,9 +6245,6 @@ static void __io_clean_op(struct io_kiocb *req)
                }
                req->flags &= ~REQ_F_NEED_CLEANUP;
        }
-
-       if (req->flags & REQ_F_INFLIGHT)
-               io_req_drop_files(req);
 }
 
 static int io_issue_sqe(struct io_kiocb *req, bool force_nonblock,
@@ -6446,6 +6463,16 @@ static struct file *io_file_get(struct io_submit_state *state,
                file = __io_file_get(state, fd);
        }
 
+       if (file && file->f_op == &io_uring_fops &&
+           !(req->flags & REQ_F_INFLIGHT)) {
+               io_req_init_async(req);
+               req->flags |= REQ_F_INFLIGHT;
+
+               spin_lock_irq(&ctx->inflight_lock);
+               list_add(&req->inflight_entry, &ctx->inflight_list);
+               spin_unlock_irq(&ctx->inflight_lock);
+       }
+
        return file;
 }
 
@@ -7245,14 +7272,18 @@ static int io_cqring_wait(struct io_ring_ctx *ctx, int min_events,
                                                TASK_INTERRUPTIBLE);
                /* make sure we run task_work before checking for signals */
                ret = io_run_task_work_sig();
-               if (ret > 0)
+               if (ret > 0) {
+                       finish_wait(&ctx->wait, &iowq.wq);
                        continue;
+               }
                else if (ret < 0)
                        break;
                if (io_should_wake(&iowq))
                        break;
-               if (test_bit(0, &ctx->cq_check_overflow))
+               if (test_bit(0, &ctx->cq_check_overflow)) {
+                       finish_wait(&ctx->wait, &iowq.wq);
                        continue;
+               }
                if (uts) {
                        timeout = schedule_timeout(timeout);
                        if (timeout == 0) {
@@ -8844,39 +8875,44 @@ static void io_cancel_defer_files(struct io_ring_ctx *ctx,
        }
 }
 
+static int io_uring_count_inflight(struct io_ring_ctx *ctx,
+                                  struct task_struct *task,
+                                  struct files_struct *files)
+{
+       struct io_kiocb *req;
+       int cnt = 0;
+
+       spin_lock_irq(&ctx->inflight_lock);
+       list_for_each_entry(req, &ctx->inflight_list, inflight_entry)
+               cnt += io_match_task(req, task, files);
+       spin_unlock_irq(&ctx->inflight_lock);
+       return cnt;
+}
+
 static void io_uring_cancel_files(struct io_ring_ctx *ctx,
                                  struct task_struct *task,
                                  struct files_struct *files)
 {
        while (!list_empty_careful(&ctx->inflight_list)) {
                struct io_task_cancel cancel = { .task = task, .files = files };
-               struct io_kiocb *req;
                DEFINE_WAIT(wait);
-               bool found = false;
-
-               spin_lock_irq(&ctx->inflight_lock);
-               list_for_each_entry(req, &ctx->inflight_list, inflight_entry) {
-                       if (req->task != task ||
-                           req->work.identity->files != files)
-                               continue;
-                       found = true;
-                       break;
-               }
-               if (found)
-                       prepare_to_wait(&task->io_uring->wait, &wait,
-                                       TASK_UNINTERRUPTIBLE);
-               spin_unlock_irq(&ctx->inflight_lock);
+               int inflight;
 
-               /* We need to keep going until we don't find a matching req */
-               if (!found)
+               inflight = io_uring_count_inflight(ctx, task, files);
+               if (!inflight)
                        break;
 
                io_wq_cancel_cb(ctx->io_wq, io_cancel_task_cb, &cancel, true);
                io_poll_remove_all(ctx, task, files);
                io_kill_timeouts(ctx, task, files);
+               io_cqring_overflow_flush(ctx, true, task, files);
                /* cancellations _may_ trigger task work */
                io_run_task_work();
-               schedule();
+
+               prepare_to_wait(&task->io_uring->wait, &wait,
+                               TASK_UNINTERRUPTIBLE);
+               if (inflight == io_uring_count_inflight(ctx, task, files))
+                       schedule();
                finish_wait(&task->io_uring->wait, &wait);
        }
 }
@@ -8914,8 +8950,6 @@ static void __io_uring_cancel_task_requests(struct io_ring_ctx *ctx,
 
 static void io_disable_sqo_submit(struct io_ring_ctx *ctx)
 {
-       WARN_ON_ONCE(ctx->sqo_task != current);
-
        mutex_lock(&ctx->uring_lock);
        ctx->sqo_dead = 1;
        mutex_unlock(&ctx->uring_lock);
@@ -8936,7 +8970,6 @@ static void io_uring_cancel_task_requests(struct io_ring_ctx *ctx,
        struct task_struct *task = current;
 
        if ((ctx->flags & IORING_SETUP_SQPOLL) && ctx->sq_data) {
-               /* for SQPOLL only sqo_task has task notes */
                io_disable_sqo_submit(ctx);
                task = ctx->sq_data->thread;
                atomic_inc(&task->io_uring->in_idle);
@@ -8946,19 +8979,12 @@ static void io_uring_cancel_task_requests(struct io_ring_ctx *ctx,
        io_cancel_defer_files(ctx, task, files);
        io_cqring_overflow_flush(ctx, true, task, files);
 
+       io_uring_cancel_files(ctx, task, files);
        if (!files)
                __io_uring_cancel_task_requests(ctx, task);
-       else
-               io_uring_cancel_files(ctx, task, files);
 
        if ((ctx->flags & IORING_SETUP_SQPOLL) && ctx->sq_data) {
                atomic_dec(&task->io_uring->in_idle);
-               /*
-                * If the files that are going away are the ones in the thread
-                * identity, clear them out.
-                */
-               if (task->io_uring->identity->files == files)
-                       task->io_uring->identity->files = NULL;
                io_sq_thread_unpark(ctx->sq_data);
        }
 }
@@ -9082,6 +9108,10 @@ void __io_uring_task_cancel(void)
        /* make sure overflow events are dropped */
        atomic_inc(&tctx->in_idle);
 
+       /* trigger io_disable_sqo_submit() */
+       if (tctx->sqpoll)
+               __io_uring_files_cancel(NULL);
+
        do {
                /* read completions before cancelations */
                inflight = tctx_inflight(tctx);
@@ -9092,16 +9122,15 @@ void __io_uring_task_cancel(void)
                prepare_to_wait(&tctx->wait, &wait, TASK_UNINTERRUPTIBLE);
 
                /*
-                * If we've seen completions, retry. This avoids a race where
-                * a completion comes in before we did prepare_to_wait().
+                * If we've seen completions, retry without waiting. This
+                * avoids a race where a completion comes in before we did
+                * prepare_to_wait().
                 */
-               if (inflight != tctx_inflight(tctx))
-                       continue;
-               schedule();
+               if (inflight == tctx_inflight(tctx))
+                       schedule();
                finish_wait(&tctx->wait, &wait);
        } while (1);
 
-       finish_wait(&tctx->wait, &wait);
        atomic_dec(&tctx->in_idle);
 
        io_uring_remove_task_files(tctx);
@@ -9112,6 +9141,9 @@ static int io_uring_flush(struct file *file, void *data)
        struct io_uring_task *tctx = current->io_uring;
        struct io_ring_ctx *ctx = file->private_data;
 
+       if (fatal_signal_pending(current) || (current->flags & PF_EXITING))
+               io_uring_cancel_task_requests(ctx, NULL);
+
        if (!tctx)
                return 0;
 
@@ -9128,7 +9160,10 @@ static int io_uring_flush(struct file *file, void *data)
 
        if (ctx->flags & IORING_SETUP_SQPOLL) {
                /* there is only one file note, which is owned by sqo_task */
-               WARN_ON_ONCE((ctx->sqo_task == current) ==
+               WARN_ON_ONCE(ctx->sqo_task != current &&
+                            xa_load(&tctx->xa, (unsigned long)file));
+               /* sqo_dead check is for when this happens after cancellation */
+               WARN_ON_ONCE(ctx->sqo_task == current && !ctx->sqo_dead &&
                             !xa_load(&tctx->xa, (unsigned long)file));
 
                io_disable_sqo_submit(ctx);
index f277d02..c757193 100644 (file)
@@ -14,6 +14,7 @@
 #include <linux/pagemap.h>
 #include <linux/sched/mm.h>
 #include <linux/fsnotify.h>
+#include <linux/uio.h>
 
 #include "kernfs-internal.h"
 
@@ -180,11 +181,10 @@ static const struct seq_operations kernfs_seq_ops = {
  * it difficult to use seq_file.  Implement simplistic custom buffering for
  * bin files.
  */
-static ssize_t kernfs_file_direct_read(struct kernfs_open_file *of,
-                                      char __user *user_buf, size_t count,
-                                      loff_t *ppos)
+static ssize_t kernfs_file_read_iter(struct kiocb *iocb, struct iov_iter *iter)
 {
-       ssize_t len = min_t(size_t, count, PAGE_SIZE);
+       struct kernfs_open_file *of = kernfs_of(iocb->ki_filp);
+       ssize_t len = min_t(size_t, iov_iter_count(iter), PAGE_SIZE);
        const struct kernfs_ops *ops;
        char *buf;
 
@@ -210,7 +210,7 @@ static ssize_t kernfs_file_direct_read(struct kernfs_open_file *of,
        of->event = atomic_read(&of->kn->attr.open->event);
        ops = kernfs_ops(of->kn);
        if (ops->read)
-               len = ops->read(of, buf, len, *ppos);
+               len = ops->read(of, buf, len, iocb->ki_pos);
        else
                len = -EINVAL;
 
@@ -220,12 +220,12 @@ static ssize_t kernfs_file_direct_read(struct kernfs_open_file *of,
        if (len < 0)
                goto out_free;
 
-       if (copy_to_user(user_buf, buf, len)) {
+       if (copy_to_iter(buf, len, iter) != len) {
                len = -EFAULT;
                goto out_free;
        }
 
-       *ppos += len;
+       iocb->ki_pos += len;
 
  out_free:
        if (buf == of->prealloc_buf)
@@ -235,31 +235,14 @@ static ssize_t kernfs_file_direct_read(struct kernfs_open_file *of,
        return len;
 }
 
-/**
- * kernfs_fop_read - kernfs vfs read callback
- * @file: file pointer
- * @user_buf: data to write
- * @count: number of bytes
- * @ppos: starting offset
- */
-static ssize_t kernfs_fop_read(struct file *file, char __user *user_buf,
-                              size_t count, loff_t *ppos)
+static ssize_t kernfs_fop_read_iter(struct kiocb *iocb, struct iov_iter *iter)
 {
-       struct kernfs_open_file *of = kernfs_of(file);
-
-       if (of->kn->flags & KERNFS_HAS_SEQ_SHOW)
-               return seq_read(file, user_buf, count, ppos);
-       else
-               return kernfs_file_direct_read(of, user_buf, count, ppos);
+       if (kernfs_of(iocb->ki_filp)->kn->flags & KERNFS_HAS_SEQ_SHOW)
+               return seq_read_iter(iocb, iter);
+       return kernfs_file_read_iter(iocb, iter);
 }
 
-/**
- * kernfs_fop_write - kernfs vfs write callback
- * @file: file pointer
- * @user_buf: data to write
- * @count: number of bytes
- * @ppos: starting offset
- *
+/*
  * Copy data in from userland and pass it to the matching kernfs write
  * operation.
  *
@@ -269,20 +252,18 @@ static ssize_t kernfs_fop_read(struct file *file, char __user *user_buf,
  * modify only the the value you're changing, then write entire buffer
  * back.
  */
-static ssize_t kernfs_fop_write(struct file *file, const char __user *user_buf,
-                               size_t count, loff_t *ppos)
+static ssize_t kernfs_fop_write_iter(struct kiocb *iocb, struct iov_iter *iter)
 {
-       struct kernfs_open_file *of = kernfs_of(file);
+       struct kernfs_open_file *of = kernfs_of(iocb->ki_filp);
+       ssize_t len = iov_iter_count(iter);
        const struct kernfs_ops *ops;
-       ssize_t len;
        char *buf;
 
        if (of->atomic_write_len) {
-               len = count;
                if (len > of->atomic_write_len)
                        return -E2BIG;
        } else {
-               len = min_t(size_t, count, PAGE_SIZE);
+               len = min_t(size_t, len, PAGE_SIZE);
        }
 
        buf = of->prealloc_buf;
@@ -293,7 +274,7 @@ static ssize_t kernfs_fop_write(struct file *file, const char __user *user_buf,
        if (!buf)
                return -ENOMEM;
 
-       if (copy_from_user(buf, user_buf, len)) {
+       if (copy_from_iter(buf, len, iter) != len) {
                len = -EFAULT;
                goto out_free;
        }
@@ -312,7 +293,7 @@ static ssize_t kernfs_fop_write(struct file *file, const char __user *user_buf,
 
        ops = kernfs_ops(of->kn);
        if (ops->write)
-               len = ops->write(of, buf, len, *ppos);
+               len = ops->write(of, buf, len, iocb->ki_pos);
        else
                len = -EINVAL;
 
@@ -320,7 +301,7 @@ static ssize_t kernfs_fop_write(struct file *file, const char __user *user_buf,
        mutex_unlock(&of->mutex);
 
        if (len > 0)
-               *ppos += len;
+               iocb->ki_pos += len;
 
 out_free:
        if (buf == of->prealloc_buf)
@@ -673,7 +654,7 @@ static int kernfs_fop_open(struct inode *inode, struct file *file)
 
        /*
         * Write path needs to atomic_write_len outside active reference.
-        * Cache it in open_file.  See kernfs_fop_write() for details.
+        * Cache it in open_file.  See kernfs_fop_write_iter() for details.
         */
        of->atomic_write_len = ops->atomic_write_len;
 
@@ -960,14 +941,16 @@ void kernfs_notify(struct kernfs_node *kn)
 EXPORT_SYMBOL_GPL(kernfs_notify);
 
 const struct file_operations kernfs_file_fops = {
-       .read           = kernfs_fop_read,
-       .write          = kernfs_fop_write,
+       .read_iter      = kernfs_fop_read_iter,
+       .write_iter     = kernfs_fop_write_iter,
        .llseek         = generic_file_llseek,
        .mmap           = kernfs_fop_mmap,
        .open           = kernfs_fop_open,
        .release        = kernfs_fop_release,
        .poll           = kernfs_fop_poll,
        .fsync          = noop_fsync,
+       .splice_read    = generic_file_splice_read,
+       .splice_write   = iter_file_splice_write,
 };
 
 /**
index 4f274f2..af64b4e 100644 (file)
@@ -324,6 +324,21 @@ pnfs_grab_inode_layout_hdr(struct pnfs_layout_hdr *lo)
        return NULL;
 }
 
+/*
+ * Compare 2 layout stateid sequence ids, to see which is newer,
+ * taking into account wraparound issues.
+ */
+static bool pnfs_seqid_is_newer(u32 s1, u32 s2)
+{
+       return (s32)(s1 - s2) > 0;
+}
+
+static void pnfs_barrier_update(struct pnfs_layout_hdr *lo, u32 newseq)
+{
+       if (pnfs_seqid_is_newer(newseq, lo->plh_barrier))
+               lo->plh_barrier = newseq;
+}
+
 static void
 pnfs_set_plh_return_info(struct pnfs_layout_hdr *lo, enum pnfs_iomode iomode,
                         u32 seq)
@@ -335,6 +350,7 @@ pnfs_set_plh_return_info(struct pnfs_layout_hdr *lo, enum pnfs_iomode iomode,
        if (seq != 0) {
                WARN_ON_ONCE(lo->plh_return_seq != 0 && lo->plh_return_seq != seq);
                lo->plh_return_seq = seq;
+               pnfs_barrier_update(lo, seq);
        }
 }
 
@@ -639,15 +655,6 @@ static int mark_lseg_invalid(struct pnfs_layout_segment *lseg,
        return rv;
 }
 
-/*
- * Compare 2 layout stateid sequence ids, to see which is newer,
- * taking into account wraparound issues.
- */
-static bool pnfs_seqid_is_newer(u32 s1, u32 s2)
-{
-       return (s32)(s1 - s2) > 0;
-}
-
 static bool
 pnfs_should_free_range(const struct pnfs_layout_range *lseg_range,
                 const struct pnfs_layout_range *recall_range)
@@ -984,8 +991,7 @@ pnfs_set_layout_stateid(struct pnfs_layout_hdr *lo, const nfs4_stateid *new,
                new_barrier = be32_to_cpu(new->seqid);
        else if (new_barrier == 0)
                return;
-       if (pnfs_seqid_is_newer(new_barrier, lo->plh_barrier))
-               lo->plh_barrier = new_barrier;
+       pnfs_barrier_update(lo, new_barrier);
 }
 
 static bool
@@ -994,7 +1000,7 @@ pnfs_layout_stateid_blocked(const struct pnfs_layout_hdr *lo,
 {
        u32 seqid = be32_to_cpu(stateid->seqid);
 
-       return !pnfs_seqid_is_newer(seqid, lo->plh_barrier);
+       return !pnfs_seqid_is_newer(seqid, lo->plh_barrier) && lo->plh_barrier;
 }
 
 /* lget is set to 1 if called from inside send_layoutget call chain */
@@ -1183,20 +1189,17 @@ pnfs_prepare_layoutreturn(struct pnfs_layout_hdr *lo,
                return false;
        set_bit(NFS_LAYOUT_RETURN, &lo->plh_flags);
        pnfs_get_layout_hdr(lo);
+       nfs4_stateid_copy(stateid, &lo->plh_stateid);
+       *cred = get_cred(lo->plh_lc_cred);
        if (test_bit(NFS_LAYOUT_RETURN_REQUESTED, &lo->plh_flags)) {
-               nfs4_stateid_copy(stateid, &lo->plh_stateid);
-               *cred = get_cred(lo->plh_lc_cred);
                if (lo->plh_return_seq != 0)
                        stateid->seqid = cpu_to_be32(lo->plh_return_seq);
                if (iomode != NULL)
                        *iomode = lo->plh_return_iomode;
                pnfs_clear_layoutreturn_info(lo);
-               return true;
-       }
-       nfs4_stateid_copy(stateid, &lo->plh_stateid);
-       *cred = get_cred(lo->plh_lc_cred);
-       if (iomode != NULL)
+       } else if (iomode != NULL)
                *iomode = IOMODE_ANY;
+       pnfs_barrier_update(lo, be32_to_cpu(stateid->seqid));
        return true;
 }
 
@@ -1909,6 +1912,11 @@ static void nfs_layoutget_end(struct pnfs_layout_hdr *lo)
                wake_up_var(&lo->plh_outstanding);
 }
 
+static bool pnfs_is_first_layoutget(struct pnfs_layout_hdr *lo)
+{
+       return test_bit(NFS_LAYOUT_FIRST_LAYOUTGET, &lo->plh_flags);
+}
+
 static void pnfs_clear_first_layoutget(struct pnfs_layout_hdr *lo)
 {
        unsigned long *bitlock = &lo->plh_flags;
@@ -2383,23 +2391,34 @@ pnfs_layout_process(struct nfs4_layoutget *lgp)
                goto out_forget;
        }
 
-       if (!pnfs_layout_is_valid(lo)) {
-               /* We have a completely new layout */
-               pnfs_set_layout_stateid(lo, &res->stateid, lgp->cred, true);
-       } else if (nfs4_stateid_match_other(&lo->plh_stateid, &res->stateid)) {
+       if (nfs4_stateid_match_other(&lo->plh_stateid, &res->stateid)) {
                /* existing state ID, make sure the sequence number matches. */
                if (pnfs_layout_stateid_blocked(lo, &res->stateid)) {
+                       if (!pnfs_layout_is_valid(lo) &&
+                           pnfs_is_first_layoutget(lo))
+                               lo->plh_barrier = 0;
                        dprintk("%s forget reply due to sequence\n", __func__);
                        goto out_forget;
                }
                pnfs_set_layout_stateid(lo, &res->stateid, lgp->cred, false);
-       } else {
+       } else if (pnfs_layout_is_valid(lo)) {
                /*
                 * We got an entirely new state ID.  Mark all segments for the
                 * inode invalid, and retry the layoutget
                 */
-               pnfs_mark_layout_stateid_invalid(lo, &free_me);
+               struct pnfs_layout_range range = {
+                       .iomode = IOMODE_ANY,
+                       .length = NFS4_MAX_UINT64,
+               };
+               pnfs_set_plh_return_info(lo, IOMODE_ANY, 0);
+               pnfs_mark_matching_lsegs_return(lo, &lo->plh_return_segs,
+                                               &range, 0);
                goto out_forget;
+       } else {
+               /* We have a completely new layout */
+               if (!pnfs_is_first_layoutget(lo))
+                       goto out_forget;
+               pnfs_set_layout_stateid(lo, &res->stateid, lgp->cred, true);
        }
 
        pnfs_get_lseg(lseg);
index 821db21..34b8802 100644 (file)
@@ -865,9 +865,14 @@ compose_entry_fh(struct nfsd3_readdirres *cd, struct svc_fh *fhp,
        if (isdotent(name, namlen)) {
                if (namlen == 2) {
                        dchild = dget_parent(dparent);
-                       /* filesystem root - cannot return filehandle for ".." */
+                       /*
+                        * Don't return filehandle for ".." if we're at
+                        * the filesystem or export root:
+                        */
                        if (dchild == dparent)
                                goto out;
+                       if (dparent == exp->ex_path.dentry)
+                               goto out;
                } else
                        dchild = dget(dparent);
        } else
index e5b616c..0fed532 100644 (file)
@@ -84,6 +84,14 @@ int ovl_copy_xattr(struct super_block *sb, struct dentry *old,
 
                if (ovl_is_private_xattr(sb, name))
                        continue;
+
+               error = security_inode_copy_up_xattr(name);
+               if (error < 0 && error != -EOPNOTSUPP)
+                       break;
+               if (error == 1) {
+                       error = 0;
+                       continue; /* Discard */
+               }
 retry:
                size = vfs_getxattr(old, name, value, value_size);
                if (size == -ERANGE)
@@ -107,13 +115,6 @@ retry:
                        goto retry;
                }
 
-               error = security_inode_copy_up_xattr(name);
-               if (error < 0 && error != -EOPNOTSUPP)
-                       break;
-               if (error == 1) {
-                       error = 0;
-                       continue; /* Discard */
-               }
                error = vfs_setxattr(new, name, value, size, 0);
                if (error) {
                        if (error != -EOPNOTSUPP || ovl_must_copy_xattr(name))
index 28a075b..d1efa3a 100644 (file)
@@ -992,8 +992,8 @@ static char *ovl_get_redirect(struct dentry *dentry, bool abs_redirect)
 
                buflen -= thislen;
                memcpy(&buf[buflen], name, thislen);
-               tmp = dget_dlock(d->d_parent);
                spin_unlock(&d->d_lock);
+               tmp = dget_parent(d);
 
                dput(d);
                d = tmp;
index bd9dd38..077d3ad 100644 (file)
@@ -398,8 +398,9 @@ static int ovl_fsync(struct file *file, loff_t start, loff_t end, int datasync)
        const struct cred *old_cred;
        int ret;
 
-       if (!ovl_should_sync(OVL_FS(file_inode(file)->i_sb)))
-               return 0;
+       ret = ovl_sync_status(OVL_FS(file_inode(file)->i_sb));
+       if (ret <= 0)
+               return ret;
 
        ret = ovl_real_fdget_meta(file, &real, !datasync);
        if (ret)
index d739e14..cf41bcb 100644 (file)
@@ -352,7 +352,9 @@ int ovl_xattr_set(struct dentry *dentry, struct inode *inode, const char *name,
                goto out;
 
        if (!value && !upperdentry) {
+               old_cred = ovl_override_creds(dentry->d_sb);
                err = vfs_getxattr(realdentry, name, NULL, 0);
+               revert_creds(old_cred);
                if (err < 0)
                        goto out_drop_write;
        }
index b487e48..cb4e2d6 100644 (file)
@@ -324,6 +324,7 @@ int ovl_check_metacopy_xattr(struct ovl_fs *ofs, struct dentry *dentry);
 bool ovl_is_metacopy_dentry(struct dentry *dentry);
 char *ovl_get_redirect_xattr(struct ovl_fs *ofs, struct dentry *dentry,
                             int padding);
+int ovl_sync_status(struct ovl_fs *ofs);
 
 static inline bool ovl_is_impuredir(struct super_block *sb,
                                    struct dentry *dentry)
index fbd5e27..63efee5 100644 (file)
@@ -81,6 +81,8 @@ struct ovl_fs {
        atomic_long_t last_ino;
        /* Whiteout dentry cache */
        struct dentry *whiteout;
+       /* r/o snapshot of upperdir sb's only taken on volatile mounts */
+       errseq_t errseq;
 };
 
 static inline struct vfsmount *ovl_upper_mnt(struct ovl_fs *ofs)
index 01620eb..f404a78 100644 (file)
@@ -865,7 +865,7 @@ struct file *ovl_dir_real_file(const struct file *file, bool want_upper)
 
        struct ovl_dir_file *od = file->private_data;
        struct dentry *dentry = file->f_path.dentry;
-       struct file *realfile = od->realfile;
+       struct file *old, *realfile = od->realfile;
 
        if (!OVL_TYPE_UPPER(ovl_path_type(dentry)))
                return want_upper ? NULL : realfile;
@@ -874,29 +874,20 @@ struct file *ovl_dir_real_file(const struct file *file, bool want_upper)
         * Need to check if we started out being a lower dir, but got copied up
         */
        if (!od->is_upper) {
-               struct inode *inode = file_inode(file);
-
                realfile = READ_ONCE(od->upperfile);
                if (!realfile) {
                        struct path upperpath;
 
                        ovl_path_upper(dentry, &upperpath);
                        realfile = ovl_dir_open_realfile(file, &upperpath);
+                       if (IS_ERR(realfile))
+                               return realfile;
 
-                       inode_lock(inode);
-                       if (!od->upperfile) {
-                               if (IS_ERR(realfile)) {
-                                       inode_unlock(inode);
-                                       return realfile;
-                               }
-                               smp_store_release(&od->upperfile, realfile);
-                       } else {
-                               /* somebody has beaten us to it */
-                               if (!IS_ERR(realfile))
-                                       fput(realfile);
-                               realfile = od->upperfile;
+                       old = cmpxchg_release(&od->upperfile, NULL, realfile);
+                       if (old) {
+                               fput(realfile);
+                               realfile = old;
                        }
-                       inode_unlock(inode);
                }
        }
 
@@ -909,8 +900,9 @@ static int ovl_dir_fsync(struct file *file, loff_t start, loff_t end,
        struct file *realfile;
        int err;
 
-       if (!ovl_should_sync(OVL_FS(file->f_path.dentry->d_sb)))
-               return 0;
+       err = ovl_sync_status(OVL_FS(file->f_path.dentry->d_sb));
+       if (err <= 0)
+               return err;
 
        realfile = ovl_dir_real_file(file, true);
        err = PTR_ERR_OR_ZERO(realfile);
index 2bd570c..d58b8f2 100644 (file)
@@ -264,11 +264,20 @@ static int ovl_sync_fs(struct super_block *sb, int wait)
        struct super_block *upper_sb;
        int ret;
 
-       if (!ovl_upper_mnt(ofs))
-               return 0;
+       ret = ovl_sync_status(ofs);
+       /*
+        * We have to always set the err, because the return value isn't
+        * checked in syncfs, and instead indirectly return an error via
+        * the sb's writeback errseq, which VFS inspects after this call.
+        */
+       if (ret < 0) {
+               errseq_set(&sb->s_wb_err, -EIO);
+               return -EIO;
+       }
+
+       if (!ret)
+               return ret;
 
-       if (!ovl_should_sync(ofs))
-               return 0;
        /*
         * Not called for sync(2) call or an emergency sync (SB_I_SKIP_SYNC).
         * All the super blocks will be iterated, including upper_sb.
@@ -1923,6 +1932,10 @@ static int ovl_fill_super(struct super_block *sb, void *data, int silent)
        unsigned int numlower;
        int err;
 
+       err = -EIO;
+       if (WARN_ON(sb->s_user_ns != current_user_ns()))
+               goto out;
+
        sb->s_d_op = &ovl_dentry_operations;
 
        err = -ENOMEM;
@@ -1989,6 +2002,8 @@ static int ovl_fill_super(struct super_block *sb, void *data, int silent)
        sb->s_op = &ovl_super_operations;
 
        if (ofs->config.upperdir) {
+               struct super_block *upper_sb;
+
                if (!ofs->config.workdir) {
                        pr_err("missing 'workdir'\n");
                        goto out_err;
@@ -1998,6 +2013,16 @@ static int ovl_fill_super(struct super_block *sb, void *data, int silent)
                if (err)
                        goto out_err;
 
+               upper_sb = ovl_upper_mnt(ofs)->mnt_sb;
+               if (!ovl_should_sync(ofs)) {
+                       ofs->errseq = errseq_sample(&upper_sb->s_wb_err);
+                       if (errseq_check(&upper_sb->s_wb_err, ofs->errseq)) {
+                               err = -EIO;
+                               pr_err("Cannot mount volatile when upperdir has an unseen error. Sync upperdir fs to clear state.\n");
+                               goto out_err;
+                       }
+               }
+
                err = ovl_get_workdir(sb, ofs, &upperpath);
                if (err)
                        goto out_err;
@@ -2005,9 +2030,8 @@ static int ovl_fill_super(struct super_block *sb, void *data, int silent)
                if (!ofs->workdir)
                        sb->s_flags |= SB_RDONLY;
 
-               sb->s_stack_depth = ovl_upper_mnt(ofs)->mnt_sb->s_stack_depth;
-               sb->s_time_gran = ovl_upper_mnt(ofs)->mnt_sb->s_time_gran;
-
+               sb->s_stack_depth = upper_sb->s_stack_depth;
+               sb->s_time_gran = upper_sb->s_time_gran;
        }
        oe = ovl_get_lowerstack(sb, splitlower, numlower, ofs, layers);
        err = PTR_ERR(oe);
index 6569031..9826b00 100644 (file)
@@ -962,3 +962,30 @@ err_free:
        kfree(buf);
        return ERR_PTR(res);
 }
+
+/*
+ * ovl_sync_status() - Check fs sync status for volatile mounts
+ *
+ * Returns 1 if this is not a volatile mount and a real sync is required.
+ *
+ * Returns 0 if syncing can be skipped because mount is volatile, and no errors
+ * have occurred on the upperdir since the mount.
+ *
+ * Returns -errno if it is a volatile mount, and the error that occurred since
+ * the last mount. If the error code changes, it'll return the latest error
+ * code.
+ */
+
+int ovl_sync_status(struct ovl_fs *ofs)
+{
+       struct vfsmount *mnt;
+
+       if (ovl_should_sync(ofs))
+               return 1;
+
+       mnt = ovl_upper_mnt(ofs);
+       if (!mnt)
+               return 0;
+
+       return errseq_check(&mnt->mnt_sb->s_wb_err, ofs->errseq);
+}
index c5989cf..39c9684 100644 (file)
--- a/fs/pipe.c
+++ b/fs/pipe.c
@@ -1206,6 +1206,7 @@ const struct file_operations pipefifo_fops = {
        .unlocked_ioctl = pipe_ioctl,
        .release        = pipe_release,
        .fasync         = pipe_fasync,
+       .splice_write   = iter_file_splice_write,
 };
 
 /*
index 3178992..d2018f7 100644 (file)
@@ -1770,6 +1770,12 @@ static int process_sysctl_arg(char *param, char *val,
                        return 0;
        }
 
+       if (!val)
+               return -EINVAL;
+       len = strlen(val);
+       if (len == 0)
+               return -EINVAL;
+
        /*
         * To set sysctl options, we use a temporary mount of proc, look up the
         * respective sys/ file and write to it. To avoid mounting it when no
@@ -1811,7 +1817,6 @@ static int process_sysctl_arg(char *param, char *val,
                                file, param, val);
                goto out;
        }
-       len = strlen(val);
        wret = kernel_write(file, val, len, &pos);
        if (wret < 0) {
                err = wret;
index 5bef3a6..d0df217 100644 (file)
@@ -705,6 +705,7 @@ static int udf_check_vsd(struct super_block *sb)
        struct buffer_head *bh = NULL;
        int nsr = 0;
        struct udf_sb_info *sbi;
+       loff_t session_offset;
 
        sbi = UDF_SB(sb);
        if (sb->s_blocksize < sizeof(struct volStructDesc))
@@ -712,7 +713,8 @@ static int udf_check_vsd(struct super_block *sb)
        else
                sectorsize = sb->s_blocksize;
 
-       sector += (((loff_t)sbi->s_session) << sb->s_blocksize_bits);
+       session_offset = (loff_t)sbi->s_session << sb->s_blocksize_bits;
+       sector += session_offset;
 
        udf_debug("Starting at sector %u (%lu byte sectors)\n",
                  (unsigned int)(sector >> sb->s_blocksize_bits),
@@ -757,8 +759,7 @@ static int udf_check_vsd(struct super_block *sb)
 
        if (nsr > 0)
                return 1;
-       else if (!bh && sector - (sbi->s_session << sb->s_blocksize_bits) ==
-                       VSD_FIRST_SECTOR_OFFSET)
+       else if (!bh && sector - session_offset == VSD_FIRST_SECTOR_OFFSET)
                return -1;
        else
                return 0;
index f5e92fe..bd1c399 100644 (file)
@@ -783,6 +783,7 @@ drm_dp_mst_detect_port(struct drm_connector *connector,
 
 struct edid *drm_dp_mst_get_edid(struct drm_connector *connector, struct drm_dp_mst_topology_mgr *mgr, struct drm_dp_mst_port *port);
 
+int drm_dp_get_vc_payload_bw(int link_rate, int link_lane_count);
 
 int drm_dp_calc_pbn_mode(int clock, int bpp, bool dsc);
 
index 89bb8b8..1779f90 100644 (file)
@@ -609,6 +609,18 @@ static inline const char *dev_name(const struct device *dev)
        return kobject_name(&dev->kobj);
 }
 
+/**
+ * dev_bus_name - Return a device's bus/class name, if at all possible
+ * @dev: struct device to get the bus/class name of
+ *
+ * Will return the name of the bus/class the device is attached to.  If it is
+ * not attached to a bus/class, an empty string will be returned.
+ */
+static inline const char *dev_bus_name(const struct device *dev)
+{
+       return dev->bus ? dev->bus->name : (dev->class ? dev->class->name : "");
+}
+
 __printf(2, 3) int dev_set_name(struct device *dev, const char *name, ...);
 
 #ifdef CONFIG_NUMA
index ca86a00..a104b29 100644 (file)
@@ -46,6 +46,7 @@
                                 SYSCALL_WORK_SYSCALL_TRACE |           \
                                 SYSCALL_WORK_SYSCALL_AUDIT |           \
                                 SYSCALL_WORK_SYSCALL_USER_DISPATCH |   \
+                                SYSCALL_WORK_SYSCALL_EXIT_TRAP |       \
                                 ARCH_SYSCALL_WORK_EXIT)
 
 /*
index ebca2ef..b5807f2 100644 (file)
@@ -770,6 +770,8 @@ static inline void huge_ptep_modify_prot_commit(struct vm_area_struct *vma,
 }
 #endif
 
+void set_page_huge_active(struct page *page);
+
 #else  /* CONFIG_HUGETLB_PAGE */
 struct hstate {};
 
index b3f0e20..efa9626 100644 (file)
@@ -616,7 +616,10 @@ static inline void dev_iommu_fwspec_set(struct device *dev,
 
 static inline void *dev_iommu_priv_get(struct device *dev)
 {
-       return dev->iommu->priv;
+       if (dev->iommu)
+               return dev->iommu->priv;
+       else
+               return NULL;
 }
 
 static inline void dev_iommu_priv_set(struct device *dev, void *priv)
index 4aeb1c4..2efde6a 100644 (file)
@@ -928,7 +928,7 @@ int __devm_irq_alloc_descs(struct device *dev, int irq, unsigned int from,
        __irq_alloc_descs(irq, from, cnt, node, THIS_MODULE, NULL)
 
 #define irq_alloc_desc(node)                   \
-       irq_alloc_descs(-1, 0, 1, node)
+       irq_alloc_descs(-1, 1, 1, node)
 
 #define irq_alloc_desc_at(at, node)            \
        irq_alloc_descs(at, at, 1, node)
@@ -943,7 +943,7 @@ int __devm_irq_alloc_descs(struct device *dev, int irq, unsigned int from,
        __devm_irq_alloc_descs(dev, irq, from, cnt, node, THIS_MODULE, NULL)
 
 #define devm_irq_alloc_desc(dev, node)                         \
-       devm_irq_alloc_descs(dev, -1, 0, 1, node)
+       devm_irq_alloc_descs(dev, -1, 1, 1, node)
 
 #define devm_irq_alloc_desc_at(dev, at, node)                  \
        devm_irq_alloc_descs(dev, at, at, 1, node)
index fe1ae73..0aea9e2 100644 (file)
@@ -333,6 +333,13 @@ static inline void *kasan_reset_tag(const void *addr)
        return (void *)arch_kasan_reset_tag(addr);
 }
 
+/**
+ * kasan_report - print a report about a bad memory access detected by KASAN
+ * @addr: address of the bad access
+ * @size: size of the bad access
+ * @is_write: whether the bad access is a write or a read
+ * @ip: instruction pointer for the accessibility check or the bad access itself
+ */
 bool kasan_report(unsigned long addr, size_t size,
                bool is_write, unsigned long ip);
 
index b3a36b0..1883a4a 100644 (file)
@@ -266,7 +266,7 @@ extern void kprobes_inc_nmissed_count(struct kprobe *p);
 extern bool arch_within_kprobe_blacklist(unsigned long addr);
 extern int arch_populate_kprobe_blacklist(void);
 extern bool arch_kprobe_on_func_entry(unsigned long offset);
-extern bool kprobe_on_func_entry(kprobe_opcode_t *addr, const char *sym, unsigned long offset);
+extern int kprobe_on_func_entry(kprobe_opcode_t *addr, const char *sym, unsigned long offset);
 
 extern bool within_kprobe_blacklist(unsigned long addr);
 extern int kprobe_add_ksym_blacklist(unsigned long entry);
index 65b81e0..2484ed9 100644 (file)
@@ -33,6 +33,9 @@ struct task_struct *kthread_create_on_cpu(int (*threadfn)(void *data),
                                          unsigned int cpu,
                                          const char *namefmt);
 
+void kthread_set_per_cpu(struct task_struct *k, int cpu);
+bool kthread_is_per_cpu(struct task_struct *k);
+
 /**
  * kthread_run - create and wake a thread.
  * @threadfn: the function to run until signal_pending(current).
index a12b552..73f20de 100644 (file)
@@ -230,6 +230,5 @@ static inline ktime_t ms_to_ktime(u64 ms)
 }
 
 # include <linux/timekeeping.h>
-# include <linux/timekeeping32.h>
 
 #endif
index 5bcfbd9..dbf8506 100644 (file)
  * Objtool generates debug info for both FUNC & CODE, but needs special
  * annotations for each CODE's start (to describe the actual stack frame).
  *
+ * Objtool requires that all code must be contained in an ELF symbol. Symbol
+ * names that have a  .L prefix do not emit symbol table entries. .L
+ * prefixed symbols can be used within a code region, but should be avoided for
+ * denoting a range of code via ``SYM_*_START/END`` annotations.
+ *
  * ALIAS -- does not generate debug info -- the aliased function will
  */
 
index 5d71e8a..aca4dc0 100644 (file)
@@ -35,6 +35,9 @@ struct mdiobb_ctrl {
        const struct mdiobb_ops *ops;
 };
 
+int mdiobb_read(struct mii_bus *bus, int phy, int reg);
+int mdiobb_write(struct mii_bus *bus, int phy, int reg, u16 val);
+
 /* The returned bus is not yet registered with the phy layer. */
 struct mii_bus *alloc_mdio_bitbang(struct mdiobb_ctrl *ctrl);
 
index f93bfe7..4672e12 100644 (file)
@@ -1209,22 +1209,4 @@ static inline bool mlx5_is_roce_enabled(struct mlx5_core_dev *dev)
        return val.vbool;
 }
 
-/**
- * mlx5_core_net - Provide net namespace of the mlx5_core_dev
- * @dev: mlx5 core device
- *
- * mlx5_core_net() returns the net namespace of mlx5 core device.
- * This can be called only in below described limited context.
- * (a) When a devlink instance for mlx5_core is registered and
- *     when devlink reload operation is disabled.
- *     or
- * (b) during devlink reload reload_down() and reload_up callbacks
- *     where it is ensured that devlink instance's net namespace is
- *     stable.
- */
-static inline struct net *mlx5_core_net(struct mlx5_core_dev *dev)
-{
-       return devlink_net(priv_to_devlink(dev));
-}
-
 #endif /* MLX5_DRIVER_H */
index 360a0a7..aef35fd 100644 (file)
@@ -178,6 +178,12 @@ struct msi_desc {
        list_for_each_entry((desc), dev_to_msi_list((dev)), list)
 #define for_each_msi_entry_safe(desc, tmp, dev)        \
        list_for_each_entry_safe((desc), (tmp), dev_to_msi_list((dev)), list)
+#define for_each_msi_vector(desc, __irq, dev)                          \
+       for_each_msi_entry((desc), (dev))                               \
+               if ((desc)->irq)                                        \
+                       for (__irq = (desc)->irq;                       \
+                            __irq < ((desc)->irq + (desc)->nvec_used); \
+                            __irq++)
 
 #ifdef CONFIG_IRQ_MSI_IOMMU
 static inline const void *msi_desc_get_iommu_cookie(struct msi_desc *desc)
index d925359..bfed36e 100644 (file)
@@ -116,6 +116,9 @@ enum {
        NVME_REG_BPMBL  = 0x0048,       /* Boot Partition Memory Buffer
                                         * Location
                                         */
+       NVME_REG_CMBMSC = 0x0050,       /* Controller Memory Buffer Memory
+                                        * Space Control
+                                        */
        NVME_REG_PMRCAP = 0x0e00,       /* Persistent Memory Capabilities */
        NVME_REG_PMRCTL = 0x0e04,       /* Persistent Memory Region Control */
        NVME_REG_PMRSTS = 0x0e08,       /* Persistent Memory Region Status */
@@ -135,6 +138,7 @@ enum {
 #define NVME_CAP_CSS(cap)      (((cap) >> 37) & 0xff)
 #define NVME_CAP_MPSMIN(cap)   (((cap) >> 48) & 0xf)
 #define NVME_CAP_MPSMAX(cap)   (((cap) >> 52) & 0xf)
+#define NVME_CAP_CMBS(cap)     (((cap) >> 57) & 0x1)
 
 #define NVME_CMB_BIR(cmbloc)   ((cmbloc) & 0x7)
 #define NVME_CMB_OFST(cmbloc)  (((cmbloc) >> 12) & 0xfffff)
@@ -192,6 +196,8 @@ enum {
        NVME_CSTS_SHST_OCCUR    = 1 << 2,
        NVME_CSTS_SHST_CMPLT    = 2 << 2,
        NVME_CSTS_SHST_MASK     = 3 << 2,
+       NVME_CMBMSC_CRE         = 1 << 0,
+       NVME_CMBMSC_CMSE        = 1 << 1,
 };
 
 struct nvme_id_power_state {
index 8637677..95889ad 100644 (file)
@@ -4600,6 +4600,7 @@ enum ec_codec_i2s_rx_subcmd {
        EC_CODEC_I2S_RX_SET_SAMPLE_DEPTH = 0x2,
        EC_CODEC_I2S_RX_SET_DAIFMT = 0x3,
        EC_CODEC_I2S_RX_SET_BCLK = 0x4,
+       EC_CODEC_I2S_RX_RESET = 0x5,
        EC_CODEC_I2S_RX_SUBCMD_COUNT,
 };
 
index 2024944..20e84a8 100644 (file)
@@ -331,6 +331,12 @@ regulator_get_exclusive(struct device *dev, const char *id)
        return ERR_PTR(-ENODEV);
 }
 
+static inline struct regulator *__must_check
+devm_regulator_get_exclusive(struct device *dev, const char *id)
+{
+       return ERR_PTR(-ENODEV);
+}
+
 static inline struct regulator *__must_check
 regulator_get_optional(struct device *dev, const char *id)
 {
@@ -486,6 +492,11 @@ static inline int regulator_get_voltage(struct regulator *regulator)
        return -EINVAL;
 }
 
+static inline int regulator_sync_voltage(struct regulator *regulator)
+{
+       return -EINVAL;
+}
+
 static inline int regulator_is_supported_voltage(struct regulator *regulator,
                                   int min_uV, int max_uV)
 {
@@ -578,6 +589,25 @@ static inline int devm_regulator_unregister_notifier(struct regulator *regulator
        return 0;
 }
 
+static inline int regulator_suspend_enable(struct regulator_dev *rdev,
+                                          suspend_state_t state)
+{
+       return -EINVAL;
+}
+
+static inline int regulator_suspend_disable(struct regulator_dev *rdev,
+                                           suspend_state_t state)
+{
+       return -EINVAL;
+}
+
+static inline int regulator_set_suspend_voltage(struct regulator *regulator,
+                                               int min_uV, int max_uV,
+                                               suspend_state_t state)
+{
+       return -EINVAL;
+}
+
 static inline void *regulator_get_drvdata(struct regulator *regulator)
 {
        return NULL;
index 19b6dea..b26213a 100644 (file)
@@ -25,8 +25,7 @@ struct rpc_rqst;
 #define XDR_QUADLEN(l)         (((l) + 3) >> 2)
 
 /*
- * Generic opaque `network object.' At the kernel level, this type
- * is used only by lockd.
+ * Generic opaque `network object.'
  */
 #define XDR_MAX_NETOBJ         1024
 struct xdr_netobj {
index c8a974c..9b2158c 100644 (file)
@@ -43,6 +43,7 @@ enum syscall_work_bit {
        SYSCALL_WORK_BIT_SYSCALL_EMU,
        SYSCALL_WORK_BIT_SYSCALL_AUDIT,
        SYSCALL_WORK_BIT_SYSCALL_USER_DISPATCH,
+       SYSCALL_WORK_BIT_SYSCALL_EXIT_TRAP,
 };
 
 #define SYSCALL_WORK_SECCOMP           BIT(SYSCALL_WORK_BIT_SECCOMP)
@@ -51,6 +52,7 @@ enum syscall_work_bit {
 #define SYSCALL_WORK_SYSCALL_EMU       BIT(SYSCALL_WORK_BIT_SYSCALL_EMU)
 #define SYSCALL_WORK_SYSCALL_AUDIT     BIT(SYSCALL_WORK_BIT_SYSCALL_AUDIT)
 #define SYSCALL_WORK_SYSCALL_USER_DISPATCH BIT(SYSCALL_WORK_BIT_SYSCALL_USER_DISPATCH)
+#define SYSCALL_WORK_SYSCALL_EXIT_TRAP BIT(SYSCALL_WORK_BIT_SYSCALL_EXIT_TRAP)
 #endif
 
 #include <asm/thread_info.h>
diff --git a/include/linux/timekeeping32.h b/include/linux/timekeeping32.h
deleted file mode 100644 (file)
index 266017f..0000000
+++ /dev/null
@@ -1,14 +0,0 @@
-#ifndef _LINUX_TIMEKEEPING32_H
-#define _LINUX_TIMEKEEPING32_H
-/*
- * These interfaces are all based on the old timespec type
- * and should get replaced with the timespec64 based versions
- * over time so we can remove the file here.
- */
-
-static inline unsigned long get_seconds(void)
-{
-       return ktime_get_real_seconds();
-}
-
-#endif
index 0f21617..966ed89 100644 (file)
@@ -307,11 +307,13 @@ static inline struct tracepoint *tracepoint_ptr_deref(tracepoint_ptr_t *p)
                                                                        \
                it_func_ptr =                                           \
                        rcu_dereference_raw((&__tracepoint_##_name)->funcs); \
-               do {                                                    \
-                       it_func = (it_func_ptr)->func;                  \
-                       __data = (it_func_ptr)->data;                   \
-                       ((void(*)(void *, proto))(it_func))(__data, args); \
-               } while ((++it_func_ptr)->func);                        \
+               if (it_func_ptr) {                                      \
+                       do {                                            \
+                               it_func = (it_func_ptr)->func;          \
+                               __data = (it_func_ptr)->data;           \
+                               ((void(*)(void *, proto))(it_func))(__data, args); \
+                       } while ((++it_func_ptr)->func);                \
+               }                                                       \
                return 0;                                               \
        }                                                               \
        DEFINE_STATIC_CALL(tp_func_##_name, __traceiter_##_name);
index c873f47..37803f3 100644 (file)
@@ -421,6 +421,7 @@ extern void tty_kclose(struct tty_struct *tty);
 extern int tty_dev_name_to_number(const char *name, dev_t *number);
 extern int tty_ldisc_lock(struct tty_struct *tty, unsigned long timeout);
 extern void tty_ldisc_unlock(struct tty_struct *tty);
+extern ssize_t redirected_tty_write(struct kiocb *, struct iov_iter *);
 #else
 static inline void tty_kref_put(struct tty_struct *tty)
 { }
index 88a7673..cfbfd6f 100644 (file)
@@ -81,6 +81,8 @@ struct usbnet {
 #              define EVENT_LINK_CHANGE        11
 #              define EVENT_SET_RX_MODE        12
 #              define EVENT_NO_IP_ALIGN        13
+       u32                     rx_speed;       /* in bps - NOT Mbps */
+       u32                     tx_speed;       /* in bps - NOT Mbps */
 };
 
 static inline struct usb_driver *driver_of(struct usb_interface *intf)
index 80c0181..cedcda6 100644 (file)
@@ -24,7 +24,8 @@ struct notifier_block;                /* in notifier.h */
 #define VM_UNINITIALIZED       0x00000020      /* vm_struct is not fully initialized */
 #define VM_NO_GUARD            0x00000040      /* don't add guard page */
 #define VM_KASAN               0x00000080      /* has allocated kasan shadow memory */
-#define VM_MAP_PUT_PAGES       0x00000100      /* put pages and free array in vfree */
+#define VM_FLUSH_RESET_PERMS   0x00000100      /* reset direct map and flush TLB on unmap, can't be freed in atomic context */
+#define VM_MAP_PUT_PAGES       0x00000200      /* put pages and free array in vfree */
 
 /*
  * VM_KASAN is used slighly differently depending on CONFIG_KASAN_VMALLOC.
@@ -37,12 +38,6 @@ struct notifier_block;               /* in notifier.h */
  * determine which allocations need the module shadow freed.
  */
 
-/*
- * Memory with VM_FLUSH_RESET_PERMS cannot be freed in an interrupt or with
- * vfree_atomic().
- */
-#define VM_FLUSH_RESET_PERMS   0x00000100      /* Reset direct map and flush TLB on unmap */
-
 /* bits [20..32] reserved for arch specific ioremap internals */
 
 /*
index be36cbd..3eb2022 100644 (file)
@@ -520,7 +520,7 @@ int v4l2_fill_pixfmt_mp(struct v4l2_pix_format_mplane *pixfmt, u32 pixelformat,
                        u32 width, u32 height);
 
 /**
- * v4l2_get_link_rate - Get link rate from transmitter
+ * v4l2_get_link_freq - Get link rate from transmitter
  *
  * @handler: The transmitter's control handler
  * @mul: The multiplier between pixel rate and link frequency. Bits per pixel on
@@ -537,7 +537,7 @@ int v4l2_fill_pixfmt_mp(struct v4l2_pix_format_mplane *pixfmt, u32 pixelformat,
  *     -ENOENT: Link frequency or pixel rate control not found
  *     -EINVAL: Invalid link frequency value
  */
-s64 v4l2_get_link_rate(struct v4l2_ctrl_handler *handler, unsigned int mul,
+s64 v4l2_get_link_freq(struct v4l2_ctrl_handler *handler, unsigned int mul,
                       unsigned int div);
 
 static inline u64 v4l2_buffer_get_timestamp(const struct v4l2_buffer *buf)
index 9a4bbcc..0d6f7ec 100644 (file)
@@ -1756,7 +1756,7 @@ struct cfg80211_sar_specs {
 
 
 /**
- * @struct cfg80211_sar_chan_ranges - sar frequency ranges
+ * struct cfg80211_sar_freq_ranges - sar frequency ranges
  * @start_freq:  start range edge frequency
  * @end_freq:    end range edge frequency
  */
@@ -3972,6 +3972,8 @@ struct mgmt_frame_regs {
  *     This callback may sleep.
  * @reset_tid_config: Reset TID specific configuration for the peer, for the
  *     given TIDs. This callback may sleep.
+ *
+ * @set_sar_specs: Update the SAR (TX power) settings.
  */
 struct cfg80211_ops {
        int     (*suspend)(struct wiphy *wiphy, struct cfg80211_wowlan *wow);
@@ -4929,6 +4931,7 @@ struct wiphy_iftype_akm_suites {
  * @max_data_retry_count: maximum supported per TID retry count for
  *     configuration through the %NL80211_TID_CONFIG_ATTR_RETRY_SHORT and
  *     %NL80211_TID_CONFIG_ATTR_RETRY_LONG attributes
+ * @sar_capa: SAR control capabilities
  */
 struct wiphy {
        /* assign these fields before you register the wiphy */
index 7338b38..111d777 100644 (file)
@@ -76,6 +76,8 @@ struct inet_connection_sock_af_ops {
  * @icsk_ext_hdr_len:     Network protocol overhead (IP/IPv6 options)
  * @icsk_ack:             Delayed ACK control data
  * @icsk_mtup;            MTU probing control data
+ * @icsk_probes_tstamp:    Probe timestamp (cleared by non-zero window ack)
+ * @icsk_user_timeout:    TCP_USER_TIMEOUT value
  */
 struct inet_connection_sock {
        /* inet_sock has to be the first member! */
@@ -129,6 +131,7 @@ struct inet_connection_sock {
 
                u32               probe_timestamp;
        } icsk_mtup;
+       u32                       icsk_probes_tstamp;
        u32                       icsk_user_timeout;
 
        u64                       icsk_ca_priv[104 / sizeof(u64)];
index ccc3d1f..eee7344 100644 (file)
@@ -92,6 +92,7 @@ struct lapb_cb {
        unsigned short          n2, n2count;
        unsigned short          t1, t2;
        struct timer_list       t1timer, t2timer;
+       bool                    t1timer_stop, t2timer_stop;
 
        /* Internal control information */
        struct sk_buff_head     write_queue;
@@ -103,6 +104,7 @@ struct lapb_cb {
        struct lapb_frame       frmr_data;
        unsigned char           frmr_type;
 
+       spinlock_t              lock;
        refcount_t              refcnt;
 };
 
index d315740..2bdbf62 100644 (file)
@@ -3880,6 +3880,7 @@ enum ieee80211_reconfig_type {
  *     This callback may sleep.
  * @sta_set_4addr: Called to notify the driver when a station starts/stops using
  *     4-address mode
+ * @set_sar_specs: Update the SAR (TX power) settings.
  */
 struct ieee80211_ops {
        void (*tx)(struct ieee80211_hw *hw,
index f4af836..4b6ecf5 100644 (file)
@@ -721,6 +721,8 @@ void *nft_set_elem_init(const struct nft_set *set,
                        const struct nft_set_ext_tmpl *tmpl,
                        const u32 *key, const u32 *key_end, const u32 *data,
                        u64 timeout, u64 expiration, gfp_t gfp);
+int nft_set_elem_expr_clone(const struct nft_ctx *ctx, struct nft_set *set,
+                           struct nft_expr *expr_array[]);
 void nft_set_elem_destroy(const struct nft_set *set, void *elem,
                          bool destroy_expr);
 
index 639e465..5b490b5 100644 (file)
@@ -1143,7 +1143,7 @@ static inline struct Qdisc *qdisc_replace(struct Qdisc *sch, struct Qdisc *new,
        old = *pold;
        *pold = new;
        if (old != NULL)
-               qdisc_tree_flush_backlog(old);
+               qdisc_purge_queue(old);
        sch_tree_unlock(sch);
 
        return old;
index bdc4323..129d200 100644 (file)
@@ -1921,10 +1921,13 @@ static inline void sk_set_txhash(struct sock *sk)
        sk->sk_txhash = net_tx_rndhash();
 }
 
-static inline void sk_rethink_txhash(struct sock *sk)
+static inline bool sk_rethink_txhash(struct sock *sk)
 {
-       if (sk->sk_txhash)
+       if (sk->sk_txhash) {
                sk_set_txhash(sk);
+               return true;
+       }
+       return false;
 }
 
 static inline struct dst_entry *
@@ -1947,12 +1950,10 @@ sk_dst_get(struct sock *sk)
        return dst;
 }
 
-static inline void dst_negative_advice(struct sock *sk)
+static inline void __dst_negative_advice(struct sock *sk)
 {
        struct dst_entry *ndst, *dst = __sk_dst_get(sk);
 
-       sk_rethink_txhash(sk);
-
        if (dst && dst->ops->negative_advice) {
                ndst = dst->ops->negative_advice(dst);
 
@@ -1964,6 +1965,12 @@ static inline void dst_negative_advice(struct sock *sk)
        }
 }
 
+static inline void dst_negative_advice(struct sock *sk)
+{
+       sk_rethink_txhash(sk);
+       __dst_negative_advice(sk);
+}
+
 static inline void
 __sk_dst_set(struct sock *sk, struct dst_entry *dst)
 {
index 78d13c8..25bbada 100644 (file)
@@ -630,6 +630,7 @@ static inline void tcp_clear_xmit_timers(struct sock *sk)
 
 unsigned int tcp_sync_mss(struct sock *sk, u32 pmtu);
 unsigned int tcp_current_mss(struct sock *sk);
+u32 tcp_clamp_probe0_to_user_timeout(const struct sock *sk, u32 when);
 
 /* Bound MSS / TSO packet size with the half of the window */
 static inline int tcp_bound_to_half_wnd(struct tcp_sock *tp, int pktsize)
@@ -2060,7 +2061,7 @@ void tcp_mark_skb_lost(struct sock *sk, struct sk_buff *skb);
 void tcp_newreno_mark_lost(struct sock *sk, bool snd_una_advanced);
 extern s32 tcp_rack_skb_timeout(struct tcp_sock *tp, struct sk_buff *skb,
                                u32 reo_wnd);
-extern void tcp_rack_mark_lost(struct sock *sk);
+extern bool tcp_rack_mark_lost(struct sock *sk);
 extern void tcp_rack_advance(struct tcp_sock *tp, u8 sacked, u32 end_seq,
                             u64 xmit_time);
 extern void tcp_rack_reo_timeout(struct sock *sk);
index 877832b..01351ba 100644 (file)
@@ -178,7 +178,7 @@ struct sk_buff *udp_gro_receive(struct list_head *head, struct sk_buff *skb,
 int udp_gro_complete(struct sk_buff *skb, int nhoff, udp_lookup_t lookup);
 
 struct sk_buff *__udp_gso_segment(struct sk_buff *gso_skb,
-                                 netdev_features_t features);
+                                 netdev_features_t features, bool is_ipv6);
 
 static inline struct udphdr *udp_gro_udphdr(struct sk_buff *skb)
 {
index 8c5e381..96666ef 100644 (file)
@@ -66,6 +66,9 @@ struct dma_chan *snd_dmaengine_pcm_get_chan(struct snd_pcm_substream *substream)
  * @chan_name: Custom channel name to use when requesting DMA channel.
  * @fifo_size: FIFO size of the DAI controller in bytes
  * @flags: PCM_DAI flags, only SND_DMAENGINE_PCM_DAI_FLAG_PACK for now
+ * @peripheral_config: peripheral configuration for programming peripheral
+ * for dmaengine transfer
+ * @peripheral_size: peripheral configuration buffer size
  */
 struct snd_dmaengine_dai_dma_data {
        dma_addr_t addr;
@@ -76,6 +79,8 @@ struct snd_dmaengine_dai_dma_data {
        const char *chan_name;
        unsigned int fifo_size;
        unsigned int flags;
+       void *peripheral_config;
+       size_t peripheral_size;
 };
 
 void snd_dmaengine_pcm_set_config_from_dai_data(
index bbb5a13..0137844 100644 (file)
@@ -9,8 +9,10 @@
 
 #include <sound/simple_card_utils.h>
 
-int graph_card_probe(struct snd_soc_card *card);
+int audio_graph_card_probe(struct snd_soc_card *card);
 
-int graph_parse_of(struct asoc_simple_priv *priv, struct device *dev);
+int audio_graph_parse_of(struct asoc_simple_priv *priv, struct device *dev);
+
+int audio_graph_remove(struct platform_device *pdev);
 
 #endif /* __GRAPH_CARD_H */
index b559708..4b3a1d3 100644 (file)
@@ -34,6 +34,11 @@ struct hdmi_codec_daifmt {
        unsigned int frame_clk_inv:1;
        unsigned int bit_clk_master:1;
        unsigned int frame_clk_master:1;
+       /* bit_fmt could be standard PCM format or
+        * IEC958 encoded format. ALSA IEC958 plugin will pass
+        * IEC958_SUBFRAME format to the underneath driver.
+        */
+       snd_pcm_format_t bit_fmt;
 };
 
 /*
index 39a77c7..710c95b 100644 (file)
@@ -22,6 +22,8 @@ struct rt5645_platform_data {
        bool level_trigger_irq;
        /* Invert JD1_1 status polarity */
        bool inv_jd1_1;
+       /* Invert HP detect status polarity */
+       bool inv_hp_pol;
 
        /* Value to asign to snd_soc_card.long_name */
        const char *long_name;
index 0bce41f..5b47768 100644 (file)
@@ -353,6 +353,12 @@ int snd_soc_component_test_bits(struct snd_soc_component *component,
                                unsigned int reg, unsigned int mask,
                                unsigned int value);
 
+unsigned int snd_soc_component_read_field(struct snd_soc_component *component,
+                                         unsigned int reg, unsigned int mask);
+int snd_soc_component_write_field(struct snd_soc_component *component,
+                                 unsigned int reg, unsigned int mask,
+                                 unsigned int val);
+
 /* component wide operations */
 int snd_soc_component_set_sysclk(struct snd_soc_component *component,
                                 int clk_id, int source,
index 34d0dbf..1358a0c 100644 (file)
@@ -353,9 +353,9 @@ struct snd_soc_dai_driver {
        /* DAI capabilities */
        struct snd_soc_pcm_stream capture;
        struct snd_soc_pcm_stream playback;
-       unsigned int symmetric_rates:1;
+       unsigned int symmetric_rate:1;
        unsigned int symmetric_channels:1;
-       unsigned int symmetric_samplebits:1;
+       unsigned int symmetric_sample_bits:1;
 
        /* probe ordering - for components with runtime dependencies */
        int probe_order;
index 3fa6c40..bd38015 100644 (file)
@@ -685,9 +685,9 @@ struct snd_soc_dai_link {
        unsigned int ignore_suspend:1;
 
        /* Symmetry requirements */
-       unsigned int symmetric_rates:1;
+       unsigned int symmetric_rate:1;
        unsigned int symmetric_channels:1;
-       unsigned int symmetric_samplebits:1;
+       unsigned int symmetric_sample_bits:1;
 
        /* Do not create a PCM for this DAI link (Backend link) */
        unsigned int no_pcm:1;
index 7abc4f0..2a7e055 100644 (file)
@@ -58,9 +58,9 @@ struct sof_ext_man_header {
 /* Extended manifest elements types */
 enum sof_ext_man_elem_type {
        SOF_EXT_MAN_ELEM_FW_VERSION             = 0,
-       SOF_EXT_MAN_ELEM_WINDOW                 = SOF_IPC_EXT_WINDOW,
-       SOF_EXT_MAN_ELEM_CC_VERSION             = SOF_IPC_EXT_CC_INFO,
-       SOF_EXT_MAN_ELEM_DBG_ABI                = SOF_IPC_EXT_USER_ABI_INFO,
+       SOF_EXT_MAN_ELEM_WINDOW                 = 1,
+       SOF_EXT_MAN_ELEM_CC_VERSION             = 2,
+       SOF_EXT_MAN_ELEM_DBG_ABI                = 4,
        SOF_EXT_MAN_ELEM_CONFIG_DATA            = 5, /**< ABI3.17 */
        SOF_EXT_MAN_ELEM_PLATFORM_CONFIG_DATA   = 6,
 };
index 5039af6..cbe3e15 100644 (file)
@@ -366,7 +366,7 @@ TRACE_EVENT(sched_process_wait,
 );
 
 /*
- * Tracepoint for do_fork:
+ * Tracepoint for kernel_clone:
  */
 TRACE_EVENT(sched_process_fork,
 
index 58994e0..6f89c27 100644 (file)
@@ -1424,13 +1424,61 @@ TRACE_EVENT(rpcb_unregister,
        )
 );
 
+/* Record an xdr_buf containing a fully-formed RPC message */
+DECLARE_EVENT_CLASS(svc_xdr_msg_class,
+       TP_PROTO(
+               const struct xdr_buf *xdr
+       ),
+
+       TP_ARGS(xdr),
+
+       TP_STRUCT__entry(
+               __field(u32, xid)
+               __field(const void *, head_base)
+               __field(size_t, head_len)
+               __field(const void *, tail_base)
+               __field(size_t, tail_len)
+               __field(unsigned int, page_len)
+               __field(unsigned int, msg_len)
+       ),
+
+       TP_fast_assign(
+               __be32 *p = (__be32 *)xdr->head[0].iov_base;
+
+               __entry->xid = be32_to_cpu(*p);
+               __entry->head_base = p;
+               __entry->head_len = xdr->head[0].iov_len;
+               __entry->tail_base = xdr->tail[0].iov_base;
+               __entry->tail_len = xdr->tail[0].iov_len;
+               __entry->page_len = xdr->page_len;
+               __entry->msg_len = xdr->len;
+       ),
+
+       TP_printk("xid=0x%08x head=[%p,%zu] page=%u tail=[%p,%zu] len=%u",
+               __entry->xid,
+               __entry->head_base, __entry->head_len, __entry->page_len,
+               __entry->tail_base, __entry->tail_len, __entry->msg_len
+       )
+);
+
+#define DEFINE_SVCXDRMSG_EVENT(name)                                   \
+               DEFINE_EVENT(svc_xdr_msg_class,                         \
+                               svc_xdr_##name,                         \
+                               TP_PROTO(                               \
+                                       const struct xdr_buf *xdr       \
+                               ),                                      \
+                               TP_ARGS(xdr))
+
+DEFINE_SVCXDRMSG_EVENT(recvfrom);
+
+/* Record an xdr_buf containing arbitrary data, tagged with an XID */
 DECLARE_EVENT_CLASS(svc_xdr_buf_class,
        TP_PROTO(
-               const struct svc_rqst *rqst,
+               __be32 xid,
                const struct xdr_buf *xdr
        ),
 
-       TP_ARGS(rqst, xdr),
+       TP_ARGS(xid, xdr),
 
        TP_STRUCT__entry(
                __field(u32, xid)
@@ -1443,7 +1491,7 @@ DECLARE_EVENT_CLASS(svc_xdr_buf_class,
        ),
 
        TP_fast_assign(
-               __entry->xid = be32_to_cpu(rqst->rq_xid);
+               __entry->xid = be32_to_cpu(xid);
                __entry->head_base = xdr->head[0].iov_base;
                __entry->head_len = xdr->head[0].iov_len;
                __entry->tail_base = xdr->tail[0].iov_base;
@@ -1463,12 +1511,11 @@ DECLARE_EVENT_CLASS(svc_xdr_buf_class,
                DEFINE_EVENT(svc_xdr_buf_class,                         \
                                svc_xdr_##name,                         \
                                TP_PROTO(                               \
-                                       const struct svc_rqst *rqst,    \
+                                       __be32 xid,                     \
                                        const struct xdr_buf *xdr       \
                                ),                                      \
-                               TP_ARGS(rqst, xdr))
+                               TP_ARGS(xid, xdr))
 
-DEFINE_SVCXDRBUF_EVENT(recvfrom);
 DEFINE_SVCXDRBUF_EVENT(sendto);
 
 /*
index 9744773..bd4424d 100644 (file)
@@ -71,90 +71,4 @@ enum br_mrp_sub_tlv_header_type {
        BR_MRP_SUB_TLV_HEADER_TEST_AUTO_MGR = 0x3,
 };
 
-struct br_mrp_tlv_hdr {
-       __u8 type;
-       __u8 length;
-};
-
-struct br_mrp_sub_tlv_hdr {
-       __u8 type;
-       __u8 length;
-};
-
-struct br_mrp_end_hdr {
-       struct br_mrp_tlv_hdr hdr;
-};
-
-struct br_mrp_common_hdr {
-       __be16 seq_id;
-       __u8 domain[MRP_DOMAIN_UUID_LENGTH];
-};
-
-struct br_mrp_ring_test_hdr {
-       __be16 prio;
-       __u8 sa[ETH_ALEN];
-       __be16 port_role;
-       __be16 state;
-       __be16 transitions;
-       __be32 timestamp;
-};
-
-struct br_mrp_ring_topo_hdr {
-       __be16 prio;
-       __u8 sa[ETH_ALEN];
-       __be16 interval;
-};
-
-struct br_mrp_ring_link_hdr {
-       __u8 sa[ETH_ALEN];
-       __be16 port_role;
-       __be16 interval;
-       __be16 blocked;
-};
-
-struct br_mrp_sub_opt_hdr {
-       __u8 type;
-       __u8 manufacture_data[MRP_MANUFACTURE_DATA_LENGTH];
-};
-
-struct br_mrp_test_mgr_nack_hdr {
-       __be16 prio;
-       __u8 sa[ETH_ALEN];
-       __be16 other_prio;
-       __u8 other_sa[ETH_ALEN];
-};
-
-struct br_mrp_test_prop_hdr {
-       __be16 prio;
-       __u8 sa[ETH_ALEN];
-       __be16 other_prio;
-       __u8 other_sa[ETH_ALEN];
-};
-
-struct br_mrp_oui_hdr {
-       __u8 oui[MRP_OUI_LENGTH];
-};
-
-struct br_mrp_in_test_hdr {
-       __be16 id;
-       __u8 sa[ETH_ALEN];
-       __be16 port_role;
-       __be16 state;
-       __be16 transitions;
-       __be32 timestamp;
-};
-
-struct br_mrp_in_topo_hdr {
-       __u8 sa[ETH_ALEN];
-       __be16 id;
-       __be16 interval;
-};
-
-struct br_mrp_in_link_hdr {
-       __u8 sa[ETH_ALEN];
-       __be16 port_role;
-       __be16 id;
-       __be16 interval;
-};
-
 #endif
index 90deb41..667f1ae 100644 (file)
@@ -251,5 +251,8 @@ struct prctl_mm_map {
 #define PR_SET_SYSCALL_USER_DISPATCH   59
 # define PR_SYS_DISPATCH_OFF           0
 # define PR_SYS_DISPATCH_ON            1
+/* The control values for the user space selector when dispatch is enabled */
+# define SYSCALL_DISPATCH_FILTER_ALLOW 0
+# define SYSCALL_DISPATCH_FILTER_BLOCK 1
 
 #endif /* _LINUX_PRCTL_H */
index 6e449e7..36e3efb 100644 (file)
 #define RKISP1_CIF_ISP_CTK_COEFF_MAX            0x100
 #define RKISP1_CIF_ISP_CTK_OFFSET_MAX           0x800
 
-#define RKISP1_CIF_ISP_AE_MEAN_MAX              25
-#define RKISP1_CIF_ISP_HIST_BIN_N_MAX           16
+#define RKISP1_CIF_ISP_AE_MEAN_MAX_V10         25
+#define RKISP1_CIF_ISP_AE_MEAN_MAX_V12         81
+#define RKISP1_CIF_ISP_AE_MEAN_MAX             RKISP1_CIF_ISP_AE_MEAN_MAX_V12
+
+#define RKISP1_CIF_ISP_HIST_BIN_N_MAX_V10      16
+#define RKISP1_CIF_ISP_HIST_BIN_N_MAX_V12      32
+#define RKISP1_CIF_ISP_HIST_BIN_N_MAX          RKISP1_CIF_ISP_HIST_BIN_N_MAX_V12
+
 #define RKISP1_CIF_ISP_AFM_MAX_WINDOWS          3
 #define RKISP1_CIF_ISP_DEGAMMA_CURVE_SIZE       17
 
@@ -86,7 +92,9 @@
  * Gamma out
  */
 /* Maximum number of color samples supported */
-#define RKISP1_CIF_ISP_GAMMA_OUT_MAX_SAMPLES       17
+#define RKISP1_CIF_ISP_GAMMA_OUT_MAX_SAMPLES_V10   17
+#define RKISP1_CIF_ISP_GAMMA_OUT_MAX_SAMPLES_V12   34
+#define RKISP1_CIF_ISP_GAMMA_OUT_MAX_SAMPLES       RKISP1_CIF_ISP_GAMMA_OUT_MAX_SAMPLES_V12
 
 /*
  * Lens shade correction
 /*
  * Histogram calculation
  */
-/* Last 3 values unused. */
-#define RKISP1_CIF_ISP_HISTOGRAM_WEIGHT_GRIDS_SIZE 28
+#define RKISP1_CIF_ISP_HISTOGRAM_WEIGHT_GRIDS_SIZE_V10 25
+#define RKISP1_CIF_ISP_HISTOGRAM_WEIGHT_GRIDS_SIZE_V12 81
+#define RKISP1_CIF_ISP_HISTOGRAM_WEIGHT_GRIDS_SIZE     RKISP1_CIF_ISP_HISTOGRAM_WEIGHT_GRIDS_SIZE_V12
 
 /*
  * Defect Pixel Cluster Correction
 #define RKISP1_CIF_ISP_STAT_AFM           (1U << 2)
 #define RKISP1_CIF_ISP_STAT_HIST          (1U << 3)
 
+/**
+ * enum rkisp1_cif_isp_version - ISP variants
+ *
+ * @RKISP1_V10: used at least in rk3288 and rk3399
+ * @RKISP1_V11: declared in the original vendor code, but not used
+ * @RKISP1_V12: used at least in rk3326 and px30
+ * @RKISP1_V13: used at least in rk1808
+ */
+enum rkisp1_cif_isp_version {
+       RKISP1_V10 = 10,
+       RKISP1_V11,
+       RKISP1_V12,
+       RKISP1_V13,
+};
+
 enum rkisp1_cif_isp_histogram_mode {
        RKISP1_CIF_ISP_HISTOGRAM_MODE_DISABLE,
        RKISP1_CIF_ISP_HISTOGRAM_MODE_RGB_COMBINED,
@@ -510,6 +534,15 @@ enum rkisp1_cif_isp_goc_mode {
  *
  * @mode: goc mode (from enum rkisp1_cif_isp_goc_mode)
  * @gamma_y: gamma out curve y-axis for all color components
+ *
+ * The number of entries of @gamma_y depends on the hardware revision
+ * as is reported by the hw_revision field of the struct media_device_info
+ * that is returned by ioctl MEDIA_IOC_DEVICE_INFO.
+ *
+ * Versions <= V11 have RKISP1_CIF_ISP_GAMMA_OUT_MAX_SAMPLES_V10
+ * entries, versions >= V12 have RKISP1_CIF_ISP_GAMMA_OUT_MAX_SAMPLES_V12
+ * entries. RKISP1_CIF_ISP_GAMMA_OUT_MAX_SAMPLES is equal to the maximum
+ * of the two.
  */
 struct rkisp1_cif_isp_goc_config {
        __u32 mode;
@@ -524,6 +557,15 @@ struct rkisp1_cif_isp_goc_config {
  *                       skipped
  * @meas_window: coordinates of the measure window
  * @hist_weight: weighting factor for sub-windows
+ *
+ * The number of entries of @hist_weight depends on the hardware revision
+ * as is reported by the hw_revision field of the struct media_device_info
+ * that is returned by ioctl MEDIA_IOC_DEVICE_INFO.
+ *
+ * Versions <= V11 have RKISP1_CIF_ISP_HISTOGRAM_WEIGHT_GRIDS_SIZE_V10
+ * entries, versions >= V12 have RKISP1_CIF_ISP_HISTOGRAM_WEIGHT_GRIDS_SIZE_V12
+ * entries. RKISP1_CIF_ISP_HISTOGRAM_WEIGHT_GRIDS_SIZE is equal to the maximum
+ * of the two.
  */
 struct rkisp1_cif_isp_hst_config {
        __u32 mode;
@@ -811,7 +853,15 @@ struct rkisp1_cif_isp_bls_meas_val {
  * @exp_mean: Mean luminance value of block xx
  * @bls_val:  BLS measured values
  *
- * Image is divided into 5x5 blocks.
+ * The number of entries of @exp_mean depends on the hardware revision
+ * as is reported by the hw_revision field of the struct media_device_info
+ * that is returned by ioctl MEDIA_IOC_DEVICE_INFO.
+ *
+ * Versions <= V11 have RKISP1_CIF_ISP_AE_MEAN_MAX_V10 entries,
+ * versions >= V12 have RKISP1_CIF_ISP_AE_MEAN_MAX_V12 entries.
+ * RKISP1_CIF_ISP_AE_MEAN_MAX is equal to the maximum of the two.
+ *
+ * Image is divided into 5x5 blocks on V10 and 9x9 blocks on V12.
  */
 struct rkisp1_cif_isp_ae_stat {
        __u8 exp_mean[RKISP1_CIF_ISP_AE_MEAN_MAX];
@@ -844,13 +894,29 @@ struct rkisp1_cif_isp_af_stat {
 /**
  * struct rkisp1_cif_isp_hist_stat - statistics histogram data
  *
- * @hist_bins: measured bin counters
+ * @hist_bins: measured bin counters. Each bin is a 20 bits unsigned fixed point
+ *            type. Bits 0-4 are the fractional part and bits 5-19 are the
+ *            integer part.
+ *
+ * The window of the measurements area is divided to 5x5 sub-windows for
+ * V10/V11 and to 9x9 sub-windows for V12. The histogram is then computed for
+ * each sub-window independently and the final result is a weighted average of
+ * the histogram measurements on all sub-windows. The window of the
+ * measurements area and the weight of each sub-window are configurable using
+ * struct @rkisp1_cif_isp_hst_config.
+ *
+ * The histogram contains 16 bins in V10/V11 and 32 bins in V12/V13.
+ *
+ * The number of entries of @hist_bins depends on the hardware revision
+ * as is reported by the hw_revision field of the struct media_device_info
+ * that is returned by ioctl MEDIA_IOC_DEVICE_INFO.
  *
- * Measurement window divided into 25 sub-windows, set
- * with ISP_HIST_XXX
+ * Versions <= V11 have RKISP1_CIF_ISP_HIST_BIN_N_MAX_V10 entries,
+ * versions >= V12 have RKISP1_CIF_ISP_HIST_BIN_N_MAX_V12 entries.
+ * RKISP1_CIF_ISP_HIST_BIN_N_MAX is equal to the maximum of the two.
  */
 struct rkisp1_cif_isp_hist_stat {
-       __u16 hist_bins[RKISP1_CIF_ISP_HIST_BIN_N_MAX];
+       __u32 hist_bins[RKISP1_CIF_ISP_HIST_BIN_N_MAX];
 };
 
 /**
index 1dccb55..708addd 100644 (file)
@@ -28,10 +28,10 @@ struct ipv6_rpl_sr_hdr {
                pad:4,
                reserved1:16;
 #elif defined(__BIG_ENDIAN_BITFIELD)
-       __u32   reserved:20,
+       __u32   cmpri:4,
+               cmpre:4,
                pad:4,
-               cmpri:4,
-               cmpre:4;
+               reserved:20;
 #else
 #error  "Please fix <asm/byteorder.h>"
 #endif
index 00850b9..a38454d 100644 (file)
@@ -176,7 +176,7 @@ struct v4l2_subdev_capability {
 };
 
 /* The v4l2 sub-device video device node is registered in read-only mode. */
-#define V4L2_SUBDEV_CAP_RO_SUBDEV              BIT(0)
+#define V4L2_SUBDEV_CAP_RO_SUBDEV              0x00000001
 
 /* Backwards compatibility define --- to be removed */
 #define v4l2_subdev_edid v4l2_edid
index f8b638c..901a4fd 100644 (file)
@@ -133,6 +133,13 @@ enum pvrdma_wc_flags {
        PVRDMA_WC_FLAGS_MAX             = PVRDMA_WC_WITH_NETWORK_HDR_TYPE,
 };
 
+enum pvrdma_network_type {
+       PVRDMA_NETWORK_IB,
+       PVRDMA_NETWORK_ROCE_V1 = PVRDMA_NETWORK_IB,
+       PVRDMA_NETWORK_IPV4,
+       PVRDMA_NETWORK_IPV6
+};
+
 struct pvrdma_alloc_ucontext_resp {
        __u32 qp_tab_size;
        __u32 reserved;
index b77c60f..29ad683 100644 (file)
@@ -76,7 +76,6 @@ config CC_HAS_ASM_INLINE
 
 config CONSTRUCTORS
        bool
-       depends on !UML
 
 config IRQ_WORK
        bool
index 8a992d7..3711cda 100644 (file)
@@ -198,7 +198,8 @@ struct task_struct init_task
        .lockdep_recursion = 0,
 #endif
 #ifdef CONFIG_FUNCTION_GRAPH_TRACER
-       .ret_stack      = NULL,
+       .ret_stack              = NULL,
+       .tracing_graph_pause    = ATOMIC_INIT(0),
 #endif
 #if defined(CONFIG_TRACING) && defined(CONFIG_PREEMPTION)
        .trace_recursion = 0,
index c68d784..a626e78 100644 (file)
@@ -1066,7 +1066,13 @@ asmlinkage __visible void __init __no_sanitize_address start_kernel(void)
 /* Call all constructor functions linked into the kernel. */
 static void __init do_ctors(void)
 {
-#ifdef CONFIG_CONSTRUCTORS
+/*
+ * For UML, the constructors have already been called by the
+ * normal setup code as it's just a normal ELF binary, so we
+ * cannot do it again - but we do need CONFIG_CONSTRUCTORS
+ * even on UML for modules.
+ */
+#if defined(CONFIG_CONSTRUCTORS) && !defined(CONFIG_UML)
        ctor_fn_t *fn = (ctor_fn_t *) __ctors_start;
 
        for (; fn < (ctor_fn_t *) __ctors_end; fn++)
index 6edff97..6639640 100644 (file)
@@ -125,8 +125,12 @@ static int bpf_fd_inode_storage_update_elem(struct bpf_map *map, void *key,
 
        fd = *(int *)key;
        f = fget_raw(fd);
-       if (!f || !inode_storage_ptr(f->f_inode))
+       if (!f)
+               return -EBADF;
+       if (!inode_storage_ptr(f->f_inode)) {
+               fput(f);
                return -EBADF;
+       }
 
        sdata = bpf_local_storage_update(f->f_inode,
                                         (struct bpf_local_storage_map *)map,
@@ -176,14 +180,14 @@ BPF_CALL_4(bpf_inode_storage_get, struct bpf_map *, map, struct inode *, inode,
         * bpf_local_storage_update expects the owner to have a
         * valid storage pointer.
         */
-       if (!inode_storage_ptr(inode))
+       if (!inode || !inode_storage_ptr(inode))
                return (unsigned long)NULL;
 
        sdata = inode_storage_lookup(inode, map, true);
        if (sdata)
                return (unsigned long)sdata->data;
 
-       /* This helper must only called from where the inode is gurranteed
+       /* This helper must only called from where the inode is guaranteed
         * to have a refcount and cannot be freed.
         */
        if (flags & BPF_LOCAL_STORAGE_GET_F_CREATE) {
@@ -200,7 +204,10 @@ BPF_CALL_4(bpf_inode_storage_get, struct bpf_map *, map, struct inode *, inode,
 BPF_CALL_2(bpf_inode_storage_delete,
           struct bpf_map *, map, struct inode *, inode)
 {
-       /* This helper must only called from where the inode is gurranteed
+       if (!inode)
+               return -EINVAL;
+
+       /* This helper must only called from where the inode is guaranteed
         * to have a refcount and cannot be freed.
         */
        return inode_storage_delete(inode, map);
index 70e5e0b..1622a44 100644 (file)
@@ -149,7 +149,11 @@ BTF_ID(func, bpf_lsm_file_ioctl)
 BTF_ID(func, bpf_lsm_file_lock)
 BTF_ID(func, bpf_lsm_file_open)
 BTF_ID(func, bpf_lsm_file_receive)
+
+#ifdef CONFIG_SECURITY_NETWORK
 BTF_ID(func, bpf_lsm_inet_conn_established)
+#endif /* CONFIG_SECURITY_NETWORK */
+
 BTF_ID(func, bpf_lsm_inode_create)
 BTF_ID(func, bpf_lsm_inode_free_security)
 BTF_ID(func, bpf_lsm_inode_getattr)
@@ -166,7 +170,11 @@ BTF_ID(func, bpf_lsm_inode_symlink)
 BTF_ID(func, bpf_lsm_inode_unlink)
 BTF_ID(func, bpf_lsm_kernel_module_request)
 BTF_ID(func, bpf_lsm_kernfs_init_security)
+
+#ifdef CONFIG_KEYS
 BTF_ID(func, bpf_lsm_key_free)
+#endif /* CONFIG_KEYS */
+
 BTF_ID(func, bpf_lsm_mmap_file)
 BTF_ID(func, bpf_lsm_netlink_send)
 BTF_ID(func, bpf_lsm_path_notify)
@@ -181,6 +189,8 @@ BTF_ID(func, bpf_lsm_sb_show_options)
 BTF_ID(func, bpf_lsm_sb_statfs)
 BTF_ID(func, bpf_lsm_sb_umount)
 BTF_ID(func, bpf_lsm_settime)
+
+#ifdef CONFIG_SECURITY_NETWORK
 BTF_ID(func, bpf_lsm_socket_accept)
 BTF_ID(func, bpf_lsm_socket_bind)
 BTF_ID(func, bpf_lsm_socket_connect)
@@ -195,6 +205,8 @@ BTF_ID(func, bpf_lsm_socket_recvmsg)
 BTF_ID(func, bpf_lsm_socket_sendmsg)
 BTF_ID(func, bpf_lsm_socket_shutdown)
 BTF_ID(func, bpf_lsm_socket_socketpair)
+#endif /* CONFIG_SECURITY_NETWORK */
+
 BTF_ID(func, bpf_lsm_syslog)
 BTF_ID(func, bpf_lsm_task_alloc)
 BTF_ID(func, bpf_lsm_task_getsecid)
index 4ef1959..e0da025 100644 (file)
@@ -218,7 +218,7 @@ BPF_CALL_4(bpf_task_storage_get, struct bpf_map *, map, struct task_struct *,
         * bpf_local_storage_update expects the owner to have a
         * valid storage pointer.
         */
-       if (!task_storage_ptr(task))
+       if (!task || !task_storage_ptr(task))
                return (unsigned long)NULL;
 
        sdata = task_storage_lookup(task, map, true);
@@ -243,6 +243,9 @@ BPF_CALL_4(bpf_task_storage_get, struct bpf_map *, map, struct task_struct *,
 BPF_CALL_2(bpf_task_storage_delete, struct bpf_map *, map, struct task_struct *,
           task)
 {
+       if (!task)
+               return -EINVAL;
+
        /* This helper must only be called from places where the lifetime of the task
         * is guaranteed. Either by being refcounted or by being protected
         * by an RCU read-side critical section.
index 8d6bdb4..84a36ee 100644 (file)
@@ -4172,7 +4172,7 @@ static int btf_parse_hdr(struct btf_verifier_env *env)
                return -ENOTSUPP;
        }
 
-       if (btf_data_size == hdr->hdr_len) {
+       if (!btf->base_btf && btf_data_size == hdr->hdr_len) {
                btf_verifier_log(env, "No data");
                return -EINVAL;
        }
index 6ec088a..6aa9e10 100644 (file)
@@ -1391,12 +1391,13 @@ int __cgroup_bpf_run_filter_setsockopt(struct sock *sk, int *level,
                if (ctx.optlen != 0) {
                        *optlen = ctx.optlen;
                        *kernel_optval = ctx.optval;
+                       /* export and don't free sockopt buf */
+                       return 0;
                }
        }
 
 out:
-       if (ret)
-               sockopt_free_buf(&ctx);
+       sockopt_free_buf(&ctx);
        return ret;
 }
 
@@ -1441,6 +1442,11 @@ int __cgroup_bpf_run_filter_getsockopt(struct sock *sk, int level,
                        goto out;
                }
 
+               if (ctx.optlen < 0) {
+                       ret = -EFAULT;
+                       goto out;
+               }
+
                if (copy_from_user(ctx.optval, optval,
                                   min(ctx.optlen, max_optlen)) != 0) {
                        ret = -EFAULT;
@@ -1458,7 +1464,7 @@ int __cgroup_bpf_run_filter_getsockopt(struct sock *sk, int level,
                goto out;
        }
 
-       if (ctx.optlen > max_optlen) {
+       if (ctx.optlen > max_optlen || ctx.optlen < 0) {
                ret = -EFAULT;
                goto out;
        }
index bd8a318..41ca280 100644 (file)
@@ -108,7 +108,7 @@ BPF_CALL_2(bpf_map_peek_elem, struct bpf_map *, map, void *, value)
 }
 
 const struct bpf_func_proto bpf_map_peek_elem_proto = {
-       .func           = bpf_map_pop_elem,
+       .func           = bpf_map_peek_elem,
        .gpl_only       = false,
        .ret_type       = RET_INTEGER,
        .arg1_type      = ARG_CONST_MAP_PTR,
index 23ee310..1951332 100644 (file)
@@ -4,8 +4,11 @@ LIBBPF_SRCS = $(srctree)/tools/lib/bpf/
 LIBBPF_A = $(obj)/libbpf.a
 LIBBPF_OUT = $(abspath $(obj))
 
+# Although not in use by libbpf's Makefile, set $(O) so that the "dummy" test
+# in tools/scripts/Makefile.include always succeeds when building the kernel
+# with $(O) pointing to a relative path, as in "make O=build bindeb-pkg".
 $(LIBBPF_A):
-       $(Q)$(MAKE) -C $(LIBBPF_SRCS) OUTPUT=$(LIBBPF_OUT)/ $(LIBBPF_OUT)/libbpf.a
+       $(Q)$(MAKE) -C $(LIBBPF_SRCS) O=$(LIBBPF_OUT)/ OUTPUT=$(LIBBPF_OUT)/ $(LIBBPF_OUT)/libbpf.a
 
 userccflags += -I $(srctree)/tools/include/ -I $(srctree)/tools/include/uapi \
        -I $(srctree)/tools/lib/ -Wno-unused-result
index c3bb03c..e5999d8 100644 (file)
@@ -2712,7 +2712,6 @@ out_unlock:
 out_put_prog:
        if (tgt_prog_fd && tgt_prog)
                bpf_prog_put(tgt_prog);
-       bpf_prog_put(prog);
        return err;
 }
 
@@ -2825,7 +2824,10 @@ static int bpf_raw_tracepoint_open(const union bpf_attr *attr)
                        tp_name = prog->aux->attach_func_name;
                        break;
                }
-               return bpf_tracing_prog_attach(prog, 0, 0);
+               err = bpf_tracing_prog_attach(prog, 0, 0);
+               if (err >= 0)
+                       return err;
+               goto out_put_prog;
        case BPF_PROG_TYPE_RAW_TRACEPOINT:
        case BPF_PROG_TYPE_RAW_TRACEPOINT_WRITABLE:
                if (strncpy_from_user(buf,
index 17270b8..e7368c5 100644 (file)
@@ -2217,6 +2217,8 @@ static bool is_spillable_regtype(enum bpf_reg_type type)
        case PTR_TO_RDWR_BUF:
        case PTR_TO_RDWR_BUF_OR_NULL:
        case PTR_TO_PERCPU_BTF_ID:
+       case PTR_TO_MEM:
+       case PTR_TO_MEM_OR_NULL:
                return true;
        default:
                return false;
@@ -5311,7 +5313,7 @@ static bool signed_add_overflows(s64 a, s64 b)
        return res < a;
 }
 
-static bool signed_add32_overflows(s64 a, s64 b)
+static bool signed_add32_overflows(s32 a, s32 b)
 {
        /* Do the add in u32, where overflow is well-defined */
        s32 res = (s32)((u32)a + (u32)b);
@@ -5321,7 +5323,7 @@ static bool signed_add32_overflows(s64 a, s64 b)
        return res < a;
 }
 
-static bool signed_sub_overflows(s32 a, s32 b)
+static bool signed_sub_overflows(s64 a, s64 b)
 {
        /* Do the sub in u64, where overflow is well-defined */
        s64 res = (s64)((u64)a - (u64)b);
@@ -5333,7 +5335,7 @@ static bool signed_sub_overflows(s32 a, s32 b)
 
 static bool signed_sub32_overflows(s32 a, s32 b)
 {
-       /* Do the sub in u64, where overflow is well-defined */
+       /* Do the sub in u32, where overflow is well-defined */
        s32 res = (s32)((u32)a - (u32)b);
 
        if (b < 0)
index b1496e7..da95df3 100644 (file)
@@ -36,7 +36,7 @@ struct map_benchmark {
        __s32 node; /* which numa node this benchmark will run on */
        __u32 dma_bits; /* DMA addressing capability */
        __u32 dma_dir; /* DMA data direction */
-       __u64 expansion[10];    /* For future use */
+       __u8 expansion[84];     /* For future use */
 };
 
 struct map_benchmark_data {
@@ -147,8 +147,10 @@ static int do_map_benchmark(struct map_benchmark_data *map)
        atomic64_set(&map->sum_sq_unmap, 0);
        atomic64_set(&map->loops, 0);
 
-       for (i = 0; i < threads; i++)
+       for (i = 0; i < threads; i++) {
+               get_task_struct(tsk[i]);
                wake_up_process(tsk[i]);
+       }
 
        msleep_interruptible(map->bparam.seconds * 1000);
 
@@ -183,6 +185,8 @@ static int do_map_benchmark(struct map_benchmark_data *map)
        }
 
 out:
+       for (i = 0; i < threads; i++)
+               put_task_struct(tsk[i]);
        put_device(map->dev);
        kfree(tsk);
        return ret;
index 3783416..f9d491b 100644 (file)
@@ -209,26 +209,18 @@ static void exit_to_user_mode_prepare(struct pt_regs *regs)
        lockdep_sys_exit();
 }
 
-#ifndef _TIF_SINGLESTEP
-static inline bool report_single_step(unsigned long work)
-{
-       return false;
-}
-#else
 /*
  * If SYSCALL_EMU is set, then the only reason to report is when
- * TIF_SINGLESTEP is set (i.e. PTRACE_SYSEMU_SINGLESTEP).  This syscall
+ * SINGLESTEP is set (i.e. PTRACE_SYSEMU_SINGLESTEP).  This syscall
  * instruction has been already reported in syscall_enter_from_user_mode().
  */
 static inline bool report_single_step(unsigned long work)
 {
-       if (!(work & SYSCALL_WORK_SYSCALL_EMU))
+       if (work & SYSCALL_WORK_SYSCALL_EMU)
                return false;
 
-       return !!(current_thread_info()->flags & _TIF_SINGLESTEP);
+       return work & SYSCALL_WORK_SYSCALL_EXIT_TRAP;
 }
-#endif
-
 
 static void syscall_exit_work(struct pt_regs *regs, unsigned long work)
 {
index b0338a5..c240302 100644 (file)
@@ -50,10 +50,10 @@ bool syscall_user_dispatch(struct pt_regs *regs)
                if (unlikely(__get_user(state, sd->selector)))
                        do_exit(SIGSEGV);
 
-               if (likely(state == PR_SYS_DISPATCH_OFF))
+               if (likely(state == SYSCALL_DISPATCH_FILTER_ALLOW))
                        return false;
 
-               if (state != PR_SYS_DISPATCH_ON)
+               if (state != SYSCALL_DISPATCH_FILTER_BLOCK)
                        do_exit(SIGSYS);
        }
 
index 37720a6..d66cd10 100644 (file)
@@ -819,9 +819,8 @@ void __init fork_init(void)
        init_task.signal->rlim[RLIMIT_SIGPENDING] =
                init_task.signal->rlim[RLIMIT_NPROC];
 
-       for (i = 0; i < UCOUNT_COUNTS; i++) {
+       for (i = 0; i < UCOUNT_COUNTS; i++)
                init_user_ns.ucount_max[i] = max_threads/2;
-       }
 
 #ifdef CONFIG_VMAP_STACK
        cpuhp_setup_state(CPUHP_BP_PREPARE_DYN, "fork:vm_stack_cache",
@@ -1654,9 +1653,8 @@ static inline void init_task_pid_links(struct task_struct *task)
 {
        enum pid_type type;
 
-       for (type = PIDTYPE_PID; type < PIDTYPE_MAX; ++type) {
+       for (type = PIDTYPE_PID; type < PIDTYPE_MAX; ++type)
                INIT_HLIST_NODE(&task->pid_links[type]);
-       }
 }
 
 static inline void
index c47d101..45a13eb 100644 (file)
@@ -763,6 +763,29 @@ static struct futex_pi_state *alloc_pi_state(void)
        return pi_state;
 }
 
+static void pi_state_update_owner(struct futex_pi_state *pi_state,
+                                 struct task_struct *new_owner)
+{
+       struct task_struct *old_owner = pi_state->owner;
+
+       lockdep_assert_held(&pi_state->pi_mutex.wait_lock);
+
+       if (old_owner) {
+               raw_spin_lock(&old_owner->pi_lock);
+               WARN_ON(list_empty(&pi_state->list));
+               list_del_init(&pi_state->list);
+               raw_spin_unlock(&old_owner->pi_lock);
+       }
+
+       if (new_owner) {
+               raw_spin_lock(&new_owner->pi_lock);
+               WARN_ON(!list_empty(&pi_state->list));
+               list_add(&pi_state->list, &new_owner->pi_state_list);
+               pi_state->owner = new_owner;
+               raw_spin_unlock(&new_owner->pi_lock);
+       }
+}
+
 static void get_pi_state(struct futex_pi_state *pi_state)
 {
        WARN_ON_ONCE(!refcount_inc_not_zero(&pi_state->refcount));
@@ -785,17 +808,11 @@ static void put_pi_state(struct futex_pi_state *pi_state)
         * and has cleaned up the pi_state already
         */
        if (pi_state->owner) {
-               struct task_struct *owner;
                unsigned long flags;
 
                raw_spin_lock_irqsave(&pi_state->pi_mutex.wait_lock, flags);
-               owner = pi_state->owner;
-               if (owner) {
-                       raw_spin_lock(&owner->pi_lock);
-                       list_del_init(&pi_state->list);
-                       raw_spin_unlock(&owner->pi_lock);
-               }
-               rt_mutex_proxy_unlock(&pi_state->pi_mutex, owner);
+               pi_state_update_owner(pi_state, NULL);
+               rt_mutex_proxy_unlock(&pi_state->pi_mutex);
                raw_spin_unlock_irqrestore(&pi_state->pi_mutex.wait_lock, flags);
        }
 
@@ -941,7 +958,8 @@ static inline void exit_pi_state_list(struct task_struct *curr) { }
  *     FUTEX_OWNER_DIED bit. See [4]
  *
  * [10] There is no transient state which leaves owner and user space
- *     TID out of sync.
+ *     TID out of sync. Except one error case where the kernel is denied
+ *     write access to the user address, see fixup_pi_state_owner().
  *
  *
  * Serialization and lifetime rules:
@@ -1521,26 +1539,15 @@ static int wake_futex_pi(u32 __user *uaddr, u32 uval, struct futex_pi_state *pi_
                        ret = -EINVAL;
        }
 
-       if (ret)
-               goto out_unlock;
-
-       /*
-        * This is a point of no return; once we modify the uval there is no
-        * going back and subsequent operations must not fail.
-        */
-
-       raw_spin_lock(&pi_state->owner->pi_lock);
-       WARN_ON(list_empty(&pi_state->list));
-       list_del_init(&pi_state->list);
-       raw_spin_unlock(&pi_state->owner->pi_lock);
-
-       raw_spin_lock(&new_owner->pi_lock);
-       WARN_ON(!list_empty(&pi_state->list));
-       list_add(&pi_state->list, &new_owner->pi_state_list);
-       pi_state->owner = new_owner;
-       raw_spin_unlock(&new_owner->pi_lock);
-
-       postunlock = __rt_mutex_futex_unlock(&pi_state->pi_mutex, &wake_q);
+       if (!ret) {
+               /*
+                * This is a point of no return; once we modified the uval
+                * there is no going back and subsequent operations must
+                * not fail.
+                */
+               pi_state_update_owner(pi_state, new_owner);
+               postunlock = __rt_mutex_futex_unlock(&pi_state->pi_mutex, &wake_q);
+       }
 
 out_unlock:
        raw_spin_unlock_irq(&pi_state->pi_mutex.wait_lock);
@@ -2323,18 +2330,13 @@ static void unqueue_me_pi(struct futex_q *q)
        spin_unlock(q->lock_ptr);
 }
 
-static int fixup_pi_state_owner(u32 __user *uaddr, struct futex_q *q,
-                               struct task_struct *argowner)
+static int __fixup_pi_state_owner(u32 __user *uaddr, struct futex_q *q,
+                                 struct task_struct *argowner)
 {
        struct futex_pi_state *pi_state = q->pi_state;
-       u32 uval, curval, newval;
        struct task_struct *oldowner, *newowner;
-       u32 newtid;
-       int ret, err = 0;
-
-       lockdep_assert_held(q->lock_ptr);
-
-       raw_spin_lock_irq(&pi_state->pi_mutex.wait_lock);
+       u32 uval, curval, newval, newtid;
+       int err = 0;
 
        oldowner = pi_state->owner;
 
@@ -2368,14 +2370,12 @@ retry:
                         * We raced against a concurrent self; things are
                         * already fixed up. Nothing to do.
                         */
-                       ret = 0;
-                       goto out_unlock;
+                       return 0;
                }
 
                if (__rt_mutex_futex_trylock(&pi_state->pi_mutex)) {
-                       /* We got the lock after all, nothing to fix. */
-                       ret = 0;
-                       goto out_unlock;
+                       /* We got the lock. pi_state is correct. Tell caller. */
+                       return 1;
                }
 
                /*
@@ -2402,8 +2402,7 @@ retry:
                         * We raced against a concurrent self; things are
                         * already fixed up. Nothing to do.
                         */
-                       ret = 0;
-                       goto out_unlock;
+                       return 1;
                }
                newowner = argowner;
        }
@@ -2433,22 +2432,9 @@ retry:
         * We fixed up user space. Now we need to fix the pi_state
         * itself.
         */
-       if (pi_state->owner != NULL) {
-               raw_spin_lock(&pi_state->owner->pi_lock);
-               WARN_ON(list_empty(&pi_state->list));
-               list_del_init(&pi_state->list);
-               raw_spin_unlock(&pi_state->owner->pi_lock);
-       }
+       pi_state_update_owner(pi_state, newowner);
 
-       pi_state->owner = newowner;
-
-       raw_spin_lock(&newowner->pi_lock);
-       WARN_ON(!list_empty(&pi_state->list));
-       list_add(&pi_state->list, &newowner->pi_state_list);
-       raw_spin_unlock(&newowner->pi_lock);
-       raw_spin_unlock_irq(&pi_state->pi_mutex.wait_lock);
-
-       return 0;
+       return argowner == current;
 
        /*
         * In order to reschedule or handle a page fault, we need to drop the
@@ -2469,17 +2455,16 @@ handle_err:
 
        switch (err) {
        case -EFAULT:
-               ret = fault_in_user_writeable(uaddr);
+               err = fault_in_user_writeable(uaddr);
                break;
 
        case -EAGAIN:
                cond_resched();
-               ret = 0;
+               err = 0;
                break;
 
        default:
                WARN_ON_ONCE(1);
-               ret = err;
                break;
        }
 
@@ -2489,17 +2474,44 @@ handle_err:
        /*
         * Check if someone else fixed it for us:
         */
-       if (pi_state->owner != oldowner) {
-               ret = 0;
-               goto out_unlock;
-       }
+       if (pi_state->owner != oldowner)
+               return argowner == current;
 
-       if (ret)
-               goto out_unlock;
+       /* Retry if err was -EAGAIN or the fault in succeeded */
+       if (!err)
+               goto retry;
 
-       goto retry;
+       /*
+        * fault_in_user_writeable() failed so user state is immutable. At
+        * best we can make the kernel state consistent but user state will
+        * be most likely hosed and any subsequent unlock operation will be
+        * rejected due to PI futex rule [10].
+        *
+        * Ensure that the rtmutex owner is also the pi_state owner despite
+        * the user space value claiming something different. There is no
+        * point in unlocking the rtmutex if current is the owner as it
+        * would need to wait until the next waiter has taken the rtmutex
+        * to guarantee consistent state. Keep it simple. Userspace asked
+        * for this wreckaged state.
+        *
+        * The rtmutex has an owner - either current or some other
+        * task. See the EAGAIN loop above.
+        */
+       pi_state_update_owner(pi_state, rt_mutex_owner(&pi_state->pi_mutex));
 
-out_unlock:
+       return err;
+}
+
+static int fixup_pi_state_owner(u32 __user *uaddr, struct futex_q *q,
+                               struct task_struct *argowner)
+{
+       struct futex_pi_state *pi_state = q->pi_state;
+       int ret;
+
+       lockdep_assert_held(q->lock_ptr);
+
+       raw_spin_lock_irq(&pi_state->pi_mutex.wait_lock);
+       ret = __fixup_pi_state_owner(uaddr, q, argowner);
        raw_spin_unlock_irq(&pi_state->pi_mutex.wait_lock);
        return ret;
 }
@@ -2523,8 +2535,6 @@ static long futex_wait_restart(struct restart_block *restart);
  */
 static int fixup_owner(u32 __user *uaddr, struct futex_q *q, int locked)
 {
-       int ret = 0;
-
        if (locked) {
                /*
                 * Got the lock. We might not be the anticipated owner if we
@@ -2535,8 +2545,8 @@ static int fixup_owner(u32 __user *uaddr, struct futex_q *q, int locked)
                 * stable state, anything else needs more attention.
                 */
                if (q->pi_state->owner != current)
-                       ret = fixup_pi_state_owner(uaddr, q, current);
-               return ret ? ret : locked;
+                       return fixup_pi_state_owner(uaddr, q, current);
+               return 1;
        }
 
        /*
@@ -2547,23 +2557,17 @@ static int fixup_owner(u32 __user *uaddr, struct futex_q *q, int locked)
         * Another speculative read; pi_state->owner == current is unstable
         * but needs our attention.
         */
-       if (q->pi_state->owner == current) {
-               ret = fixup_pi_state_owner(uaddr, q, NULL);
-               return ret;
-       }
+       if (q->pi_state->owner == current)
+               return fixup_pi_state_owner(uaddr, q, NULL);
 
        /*
         * Paranoia check. If we did not take the lock, then we should not be
-        * the owner of the rt_mutex.
+        * the owner of the rt_mutex. Warn and establish consistent state.
         */
-       if (rt_mutex_owner(&q->pi_state->pi_mutex) == current) {
-               printk(KERN_ERR "fixup_owner: ret = %d pi-mutex: %p "
-                               "pi-state %p\n", ret,
-                               q->pi_state->pi_mutex.owner,
-                               q->pi_state->owner);
-       }
+       if (WARN_ON_ONCE(rt_mutex_owner(&q->pi_state->pi_mutex) == current))
+               return fixup_pi_state_owner(uaddr, q, current);
 
-       return ret;
+       return 0;
 }
 
 /**
@@ -2771,7 +2775,6 @@ static int futex_lock_pi(u32 __user *uaddr, unsigned int flags,
                         ktime_t *time, int trylock)
 {
        struct hrtimer_sleeper timeout, *to;
-       struct futex_pi_state *pi_state = NULL;
        struct task_struct *exiting = NULL;
        struct rt_mutex_waiter rt_waiter;
        struct futex_hash_bucket *hb;
@@ -2907,23 +2910,8 @@ no_block:
        if (res)
                ret = (res < 0) ? res : 0;
 
-       /*
-        * If fixup_owner() faulted and was unable to handle the fault, unlock
-        * it and return the fault to userspace.
-        */
-       if (ret && (rt_mutex_owner(&q.pi_state->pi_mutex) == current)) {
-               pi_state = q.pi_state;
-               get_pi_state(pi_state);
-       }
-
        /* Unqueue and drop the lock */
        unqueue_me_pi(&q);
-
-       if (pi_state) {
-               rt_mutex_futex_unlock(&pi_state->pi_mutex);
-               put_pi_state(pi_state);
-       }
-
        goto out;
 
 out_unlock_put_key:
@@ -3183,7 +3171,6 @@ static int futex_wait_requeue_pi(u32 __user *uaddr, unsigned int flags,
                                 u32 __user *uaddr2)
 {
        struct hrtimer_sleeper timeout, *to;
-       struct futex_pi_state *pi_state = NULL;
        struct rt_mutex_waiter rt_waiter;
        struct futex_hash_bucket *hb;
        union futex_key key2 = FUTEX_KEY_INIT;
@@ -3261,16 +3248,17 @@ static int futex_wait_requeue_pi(u32 __user *uaddr, unsigned int flags,
                if (q.pi_state && (q.pi_state->owner != current)) {
                        spin_lock(q.lock_ptr);
                        ret = fixup_pi_state_owner(uaddr2, &q, current);
-                       if (ret && rt_mutex_owner(&q.pi_state->pi_mutex) == current) {
-                               pi_state = q.pi_state;
-                               get_pi_state(pi_state);
-                       }
                        /*
                         * Drop the reference to the pi state which
                         * the requeue_pi() code acquired for us.
                         */
                        put_pi_state(q.pi_state);
                        spin_unlock(q.lock_ptr);
+                       /*
+                        * Adjust the return value. It's either -EFAULT or
+                        * success (1) but the caller expects 0 for success.
+                        */
+                       ret = ret < 0 ? ret : 0;
                }
        } else {
                struct rt_mutex *pi_mutex;
@@ -3301,25 +3289,10 @@ static int futex_wait_requeue_pi(u32 __user *uaddr, unsigned int flags,
                if (res)
                        ret = (res < 0) ? res : 0;
 
-               /*
-                * If fixup_pi_state_owner() faulted and was unable to handle
-                * the fault, unlock the rt_mutex and return the fault to
-                * userspace.
-                */
-               if (ret && rt_mutex_owner(&q.pi_state->pi_mutex) == current) {
-                       pi_state = q.pi_state;
-                       get_pi_state(pi_state);
-               }
-
                /* Unqueue and drop the lock. */
                unqueue_me_pi(&q);
        }
 
-       if (pi_state) {
-               rt_mutex_futex_unlock(&pi_state->pi_mutex);
-               put_pi_state(pi_state);
-       }
-
        if (ret == -EINTR) {
                /*
                 * We've already been requeued, but cannot restart by calling
index 3110c77..f62de2d 100644 (file)
@@ -4,7 +4,7 @@ menu "GCOV-based kernel profiling"
 config GCOV_KERNEL
        bool "Enable gcov-based kernel profiling"
        depends on DEBUG_FS
-       select CONSTRUCTORS if !UML
+       select CONSTRUCTORS
        default n
        help
        This option enables gcov-based code profiling (e.g. for code coverage
index ab8567f..dec3f73 100644 (file)
@@ -2859,3 +2859,4 @@ bool irq_check_status_bit(unsigned int irq, unsigned int bitmask)
        rcu_read_unlock();
        return res;
 }
+EXPORT_SYMBOL_GPL(irq_check_status_bit);
index 2c0c4d6..b338d62 100644 (file)
@@ -402,7 +402,7 @@ int __msi_domain_alloc_irqs(struct irq_domain *domain, struct device *dev,
        struct msi_domain_ops *ops = info->ops;
        struct irq_data *irq_data;
        struct msi_desc *desc;
-       msi_alloc_info_t arg;
+       msi_alloc_info_t arg = { };
        int i, ret, virq;
        bool can_reserve;
 
@@ -436,22 +436,22 @@ int __msi_domain_alloc_irqs(struct irq_domain *domain, struct device *dev,
 
        can_reserve = msi_check_reservation_mode(domain, info, dev);
 
-       for_each_msi_entry(desc, dev) {
-               virq = desc->irq;
-               if (desc->nvec_used == 1)
-                       dev_dbg(dev, "irq %d for MSI\n", virq);
-               else
+       /*
+        * This flag is set by the PCI layer as we need to activate
+        * the MSI entries before the PCI layer enables MSI in the
+        * card. Otherwise the card latches a random msi message.
+        */
+       if (!(info->flags & MSI_FLAG_ACTIVATE_EARLY))
+               goto skip_activate;
+
+       for_each_msi_vector(desc, i, dev) {
+               if (desc->irq == i) {
+                       virq = desc->irq;
                        dev_dbg(dev, "irq [%d-%d] for MSI\n",
                                virq, virq + desc->nvec_used - 1);
-               /*
-                * This flag is set by the PCI layer as we need to activate
-                * the MSI entries before the PCI layer enables MSI in the
-                * card. Otherwise the card latches a random msi message.
-                */
-               if (!(info->flags & MSI_FLAG_ACTIVATE_EARLY))
-                       continue;
+               }
 
-               irq_data = irq_domain_get_irq_data(domain, desc->irq);
+               irq_data = irq_domain_get_irq_data(domain, i);
                if (!can_reserve) {
                        irqd_clr_can_reserve(irq_data);
                        if (domain->flags & IRQ_DOMAIN_MSI_NOMASK_QUIRK)
@@ -462,28 +462,24 @@ int __msi_domain_alloc_irqs(struct irq_domain *domain, struct device *dev,
                        goto cleanup;
        }
 
+skip_activate:
        /*
         * If these interrupts use reservation mode, clear the activated bit
         * so request_irq() will assign the final vector.
         */
        if (can_reserve) {
-               for_each_msi_entry(desc, dev) {
-                       irq_data = irq_domain_get_irq_data(domain, desc->irq);
+               for_each_msi_vector(desc, i, dev) {
+                       irq_data = irq_domain_get_irq_data(domain, i);
                        irqd_clr_activated(irq_data);
                }
        }
        return 0;
 
 cleanup:
-       for_each_msi_entry(desc, dev) {
-               struct irq_data *irqd;
-
-               if (desc->irq == virq)
-                       break;
-
-               irqd = irq_domain_get_irq_data(domain, desc->irq);
-               if (irqd_is_activated(irqd))
-                       irq_domain_deactivate_irq(irqd);
+       for_each_msi_vector(desc, i, dev) {
+               irq_data = irq_domain_get_irq_data(domain, i);
+               if (irqd_is_activated(irq_data))
+                       irq_domain_deactivate_irq(irq_data);
        }
        msi_domain_free_irqs(domain, dev);
        return ret;
index 4f8efc2..aa91958 100644 (file)
@@ -1134,7 +1134,6 @@ int kernel_kexec(void)
 
 #ifdef CONFIG_KEXEC_JUMP
        if (kexec_image->preserve_context) {
-               lock_system_sleep();
                pm_prepare_console();
                error = freeze_processes();
                if (error) {
@@ -1197,7 +1196,6 @@ int kernel_kexec(void)
                thaw_processes();
  Restore_console:
                pm_restore_console();
-               unlock_system_sleep();
        }
 #endif
 
index f7fb5d1..d5a3eb7 100644 (file)
@@ -1954,28 +1954,48 @@ bool __weak arch_kprobe_on_func_entry(unsigned long offset)
        return !offset;
 }
 
-bool kprobe_on_func_entry(kprobe_opcode_t *addr, const char *sym, unsigned long offset)
+/**
+ * kprobe_on_func_entry() -- check whether given address is function entry
+ * @addr: Target address
+ * @sym:  Target symbol name
+ * @offset: The offset from the symbol or the address
+ *
+ * This checks whether the given @addr+@offset or @sym+@offset is on the
+ * function entry address or not.
+ * This returns 0 if it is the function entry, or -EINVAL if it is not.
+ * And also it returns -ENOENT if it fails the symbol or address lookup.
+ * Caller must pass @addr or @sym (either one must be NULL), or this
+ * returns -EINVAL.
+ */
+int kprobe_on_func_entry(kprobe_opcode_t *addr, const char *sym, unsigned long offset)
 {
        kprobe_opcode_t *kp_addr = _kprobe_addr(addr, sym, offset);
 
        if (IS_ERR(kp_addr))
-               return false;
+               return PTR_ERR(kp_addr);
 
-       if (!kallsyms_lookup_size_offset((unsigned long)kp_addr, NULL, &offset) ||
-                                               !arch_kprobe_on_func_entry(offset))
-               return false;
+       if (!kallsyms_lookup_size_offset((unsigned long)kp_addr, NULL, &offset))
+               return -ENOENT;
 
-       return true;
+       if (!arch_kprobe_on_func_entry(offset))
+               return -EINVAL;
+
+       return 0;
 }
 
 int register_kretprobe(struct kretprobe *rp)
 {
-       int ret = 0;
+       int ret;
        struct kretprobe_instance *inst;
        int i;
        void *addr;
 
-       if (!kprobe_on_func_entry(rp->kp.addr, rp->kp.symbol_name, rp->kp.offset))
+       ret = kprobe_on_func_entry(rp->kp.addr, rp->kp.symbol_name, rp->kp.offset);
+       if (ret)
+               return ret;
+
+       /* If only rp->kp.addr is specified, check reregistering kprobes */
+       if (rp->kp.addr && check_kprobe_rereg(&rp->kp))
                return -EINVAL;
 
        if (kretprobe_blacklist_size) {
index a5eceec..1578973 100644 (file)
@@ -294,7 +294,7 @@ static int kthread(void *_create)
        do_exit(ret);
 }
 
-/* called from do_fork() to get node information for about to be created task */
+/* called from kernel_clone() to get node information for about to be created task */
 int tsk_fork_get_node(struct task_struct *tsk)
 {
 #ifdef CONFIG_NUMA
@@ -493,11 +493,36 @@ struct task_struct *kthread_create_on_cpu(int (*threadfn)(void *data),
                return p;
        kthread_bind(p, cpu);
        /* CPU hotplug need to bind once again when unparking the thread. */
-       set_bit(KTHREAD_IS_PER_CPU, &to_kthread(p)->flags);
        to_kthread(p)->cpu = cpu;
        return p;
 }
 
+void kthread_set_per_cpu(struct task_struct *k, int cpu)
+{
+       struct kthread *kthread = to_kthread(k);
+       if (!kthread)
+               return;
+
+       WARN_ON_ONCE(!(k->flags & PF_NO_SETAFFINITY));
+
+       if (cpu < 0) {
+               clear_bit(KTHREAD_IS_PER_CPU, &kthread->flags);
+               return;
+       }
+
+       kthread->cpu = cpu;
+       set_bit(KTHREAD_IS_PER_CPU, &kthread->flags);
+}
+
+bool kthread_is_per_cpu(struct task_struct *k)
+{
+       struct kthread *kthread = to_kthread(k);
+       if (!kthread)
+               return false;
+
+       return test_bit(KTHREAD_IS_PER_CPU, &kthread->flags);
+}
+
 /**
  * kthread_unpark - unpark a thread created by kthread_create().
  * @k:         thread created by kthread_create().
index c1418b4..bdaf482 100644 (file)
@@ -79,7 +79,7 @@ module_param(lock_stat, int, 0644);
 DEFINE_PER_CPU(unsigned int, lockdep_recursion);
 EXPORT_PER_CPU_SYMBOL_GPL(lockdep_recursion);
 
-static inline bool lockdep_enabled(void)
+static __always_inline bool lockdep_enabled(void)
 {
        if (!debug_locks)
                return false;
@@ -5271,12 +5271,15 @@ static void __lock_unpin_lock(struct lockdep_map *lock, struct pin_cookie cookie
 /*
  * Check whether we follow the irq-flags state precisely:
  */
-static void check_flags(unsigned long flags)
+static noinstr void check_flags(unsigned long flags)
 {
 #if defined(CONFIG_PROVE_LOCKING) && defined(CONFIG_DEBUG_LOCKDEP)
        if (!debug_locks)
                return;
 
+       /* Get the warning out..  */
+       instrumentation_begin();
+
        if (irqs_disabled_flags(flags)) {
                if (DEBUG_LOCKS_WARN_ON(lockdep_hardirqs_enabled())) {
                        printk("possible reason: unannotated irqs-off.\n");
@@ -5304,6 +5307,8 @@ static void check_flags(unsigned long flags)
 
        if (!debug_locks)
                print_irqtrace_events(current);
+
+       instrumentation_end();
 #endif
 }
 
index cfdd5b9..2f8cd61 100644 (file)
@@ -1716,8 +1716,7 @@ void rt_mutex_init_proxy_locked(struct rt_mutex *lock,
  * possible because it belongs to the pi_state which is about to be freed
  * and it is not longer visible to other tasks.
  */
-void rt_mutex_proxy_unlock(struct rt_mutex *lock,
-                          struct task_struct *proxy_owner)
+void rt_mutex_proxy_unlock(struct rt_mutex *lock)
 {
        debug_rt_mutex_proxy_unlock(lock);
        rt_mutex_set_owner(lock, NULL);
index d1d62f9..ca6fb48 100644 (file)
@@ -133,8 +133,7 @@ enum rtmutex_chainwalk {
 extern struct task_struct *rt_mutex_next_owner(struct rt_mutex *lock);
 extern void rt_mutex_init_proxy_locked(struct rt_mutex *lock,
                                       struct task_struct *proxy_owner);
-extern void rt_mutex_proxy_unlock(struct rt_mutex *lock,
-                                 struct task_struct *proxy_owner);
+extern void rt_mutex_proxy_unlock(struct rt_mutex *lock);
 extern void rt_mutex_init_waiter(struct rt_mutex_waiter *waiter);
 extern int __rt_mutex_start_proxy_lock(struct rt_mutex *lock,
                                     struct rt_mutex_waiter *waiter,
index c73f2e2..72e3305 100644 (file)
@@ -497,10 +497,10 @@ static int swap_writer_finish(struct swap_map_handle *handle,
                unsigned int flags, int error)
 {
        if (!error) {
-               flush_swap_writer(handle);
                pr_info("S");
                error = mark_swapfiles(handle, flags);
                pr_cont("|\n");
+               flush_swap_writer(handle);
        }
 
        if (error)
index ffdd0dc..5a95c68 100644 (file)
@@ -1291,11 +1291,16 @@ static size_t info_print_prefix(const struct printk_info  *info, bool syslog,
  * done:
  *
  *   - Add prefix for each line.
+ *   - Drop truncated lines that no longer fit into the buffer.
  *   - Add the trailing newline that has been removed in vprintk_store().
- *   - Drop truncated lines that do not longer fit into the buffer.
+ *   - Add a string terminator.
+ *
+ * Since the produced string is always terminated, the maximum possible
+ * return value is @r->text_buf_size - 1;
  *
  * Return: The length of the updated/prepared text, including the added
- * prefixes and the newline. The dropped line(s) are not counted.
+ * prefixes and the newline. The terminator is not counted. The dropped
+ * line(s) are not counted.
  */
 static size_t record_print_text(struct printk_record *r, bool syslog,
                                bool time)
@@ -1338,26 +1343,31 @@ static size_t record_print_text(struct printk_record *r, bool syslog,
 
                /*
                 * Truncate the text if there is not enough space to add the
-                * prefix and a trailing newline.
+                * prefix and a trailing newline and a terminator.
                 */
-               if (len + prefix_len + text_len + 1 > buf_size) {
+               if (len + prefix_len + text_len + 1 + 1 > buf_size) {
                        /* Drop even the current line if no space. */
-                       if (len + prefix_len + line_len + 1 > buf_size)
+                       if (len + prefix_len + line_len + 1 + 1 > buf_size)
                                break;
 
-                       text_len = buf_size - len - prefix_len - 1;
+                       text_len = buf_size - len - prefix_len - 1 - 1;
                        truncated = true;
                }
 
                memmove(text + prefix_len, text, text_len);
                memcpy(text, prefix, prefix_len);
 
+               /*
+                * Increment the prepared length to include the text and
+                * prefix that were just moved+copied. Also increment for the
+                * newline at the end of this line. If this is the last line,
+                * there is no newline, but it will be added immediately below.
+                */
                len += prefix_len + line_len + 1;
-
                if (text_len == line_len) {
                        /*
-                        * Add the trailing newline removed in
-                        * vprintk_store().
+                        * This is the last line. Add the trailing newline
+                        * removed in vprintk_store().
                         */
                        text[prefix_len + line_len] = '\n';
                        break;
@@ -1382,6 +1392,14 @@ static size_t record_print_text(struct printk_record *r, bool syslog,
                text_len -= line_len + 1;
        }
 
+       /*
+        * If a buffer was provided, it will be terminated. Space for the
+        * string terminator is guaranteed to be available. The terminator is
+        * not counted in the return value.
+        */
+       if (buf_size > 0)
+               r->text_buf[len] = 0;
+
        return len;
 }
 
@@ -3427,7 +3445,7 @@ bool kmsg_dump_get_buffer(struct kmsg_dumper *dumper, bool syslog,
        while (prb_read_valid_info(prb, seq, &info, &line_count)) {
                if (r.info->seq >= dumper->next_seq)
                        break;
-               l += get_record_print_text_size(&info, line_count, true, time);
+               l += get_record_print_text_size(&info, line_count, syslog, time);
                seq = r.info->seq + 1;
        }
 
@@ -3437,7 +3455,7 @@ bool kmsg_dump_get_buffer(struct kmsg_dumper *dumper, bool syslog,
                                                &info, &line_count)) {
                if (r.info->seq >= dumper->next_seq)
                        break;
-               l -= get_record_print_text_size(&info, line_count, true, time);
+               l -= get_record_print_text_size(&info, line_count, syslog, time);
                seq = r.info->seq + 1;
        }
 
index 6704f06..8a7b736 100644 (file)
@@ -1718,7 +1718,7 @@ static bool copy_data(struct prb_data_ring *data_ring,
 
        /* Caller interested in the line count? */
        if (line_count)
-               *line_count = count_lines(data, data_size);
+               *line_count = count_lines(data, len);
 
        /* Caller interested in the data content? */
        if (!buf || !buf_size)
index 15d2562..ff74fca 100644 (file)
@@ -1796,13 +1796,28 @@ static inline bool rq_has_pinned_tasks(struct rq *rq)
  */
 static inline bool is_cpu_allowed(struct task_struct *p, int cpu)
 {
+       /* When not in the task's cpumask, no point in looking further. */
        if (!cpumask_test_cpu(cpu, p->cpus_ptr))
                return false;
 
-       if (is_per_cpu_kthread(p) || is_migration_disabled(p))
+       /* migrate_disabled() must be allowed to finish. */
+       if (is_migration_disabled(p))
                return cpu_online(cpu);
 
-       return cpu_active(cpu);
+       /* Non kernel threads are not allowed during either online or offline. */
+       if (!(p->flags & PF_KTHREAD))
+               return cpu_active(cpu);
+
+       /* KTHREAD_IS_PER_CPU is always allowed. */
+       if (kthread_is_per_cpu(p))
+               return cpu_online(cpu);
+
+       /* Regular kernel threads don't get to stay during offline. */
+       if (cpu_rq(cpu)->balance_push)
+               return false;
+
+       /* But are allowed during online. */
+       return cpu_online(cpu);
 }
 
 /*
@@ -2327,7 +2342,9 @@ static int __set_cpus_allowed_ptr(struct task_struct *p,
 
        if (p->flags & PF_KTHREAD || is_migration_disabled(p)) {
                /*
-                * Kernel threads are allowed on online && !active CPUs.
+                * Kernel threads are allowed on online && !active CPUs,
+                * however, during cpu-hot-unplug, even these might get pushed
+                * away if not KTHREAD_IS_PER_CPU.
                 *
                 * Specifically, migration_disabled() tasks must not fail the
                 * cpumask_any_and_distribute() pick below, esp. so on
@@ -2371,16 +2388,6 @@ static int __set_cpus_allowed_ptr(struct task_struct *p,
 
        __do_set_cpus_allowed(p, new_mask, flags);
 
-       if (p->flags & PF_KTHREAD) {
-               /*
-                * For kernel threads that do indeed end up on online &&
-                * !active we want to ensure they are strict per-CPU threads.
-                */
-               WARN_ON(cpumask_intersects(new_mask, cpu_online_mask) &&
-                       !cpumask_intersects(new_mask, cpu_active_mask) &&
-                       p->nr_cpus_allowed != 1);
-       }
-
        return affine_move_task(rq, p, &rf, dest_cpu, flags);
 
 out:
@@ -3121,6 +3128,13 @@ bool cpus_share_cache(int this_cpu, int that_cpu)
 
 static inline bool ttwu_queue_cond(int cpu, int wake_flags)
 {
+       /*
+        * Do not complicate things with the async wake_list while the CPU is
+        * in hotplug state.
+        */
+       if (!cpu_active(cpu))
+               return false;
+
        /*
         * If the CPU does not share cache, then queue the task on the
         * remote rqs wakelist to avoid accessing remote data.
@@ -7276,8 +7290,14 @@ static void balance_push(struct rq *rq)
        /*
         * Both the cpu-hotplug and stop task are in this case and are
         * required to complete the hotplug process.
+        *
+        * XXX: the idle task does not match kthread_is_per_cpu() due to
+        * histerical raisins.
         */
-       if (is_per_cpu_kthread(push_task) || is_migration_disabled(push_task)) {
+       if (rq->idle == push_task ||
+           ((push_task->flags & PF_KTHREAD) && kthread_is_per_cpu(push_task)) ||
+           is_migration_disabled(push_task)) {
+
                /*
                 * If this is the idle task on the outgoing CPU try to wake
                 * up the hotplug control thread which might wait for the
@@ -7309,7 +7329,7 @@ static void balance_push(struct rq *rq)
        /*
         * At this point need_resched() is true and we'll take the loop in
         * schedule(). The next pick is obviously going to be the stop task
-        * which is_per_cpu_kthread() and will push this task away.
+        * which kthread_is_per_cpu() and will push this task away.
         */
        raw_spin_lock(&rq->lock);
 }
@@ -7320,10 +7340,13 @@ static void balance_push_set(int cpu, bool on)
        struct rq_flags rf;
 
        rq_lock_irqsave(rq, &rf);
-       if (on)
+       rq->balance_push = on;
+       if (on) {
+               WARN_ON_ONCE(rq->balance_callback);
                rq->balance_callback = &balance_push_callback;
-       else
+       } else if (rq->balance_callback == &balance_push_callback) {
                rq->balance_callback = NULL;
+       }
        rq_unlock_irqrestore(rq, &rf);
 }
 
@@ -7441,6 +7464,10 @@ int sched_cpu_activate(unsigned int cpu)
        struct rq *rq = cpu_rq(cpu);
        struct rq_flags rf;
 
+       /*
+        * Make sure that when the hotplug state machine does a roll-back
+        * we clear balance_push. Ideally that would happen earlier...
+        */
        balance_push_set(cpu, false);
 
 #ifdef CONFIG_SCHED_SMT
@@ -7483,17 +7510,27 @@ int sched_cpu_deactivate(unsigned int cpu)
        int ret;
 
        set_cpu_active(cpu, false);
+
+       /*
+        * From this point forward, this CPU will refuse to run any task that
+        * is not: migrate_disable() or KTHREAD_IS_PER_CPU, and will actively
+        * push those tasks away until this gets cleared, see
+        * sched_cpu_dying().
+        */
+       balance_push_set(cpu, true);
+
        /*
-        * We've cleared cpu_active_mask, wait for all preempt-disabled and RCU
-        * users of this state to go away such that all new such users will
-        * observe it.
+        * We've cleared cpu_active_mask / set balance_push, wait for all
+        * preempt-disabled and RCU users of this state to go away such that
+        * all new such users will observe it.
+        *
+        * Specifically, we rely on ttwu to no longer target this CPU, see
+        * ttwu_queue_cond() and is_cpu_allowed().
         *
         * Do sync before park smpboot threads to take care the rcu boost case.
         */
        synchronize_rcu();
 
-       balance_push_set(cpu, true);
-
        rq_lock_irqsave(rq, &rf);
        if (rq->rd) {
                update_rq_clock(rq);
@@ -7574,6 +7611,25 @@ static void calc_load_migrate(struct rq *rq)
                atomic_long_add(delta, &calc_load_tasks);
 }
 
+static void dump_rq_tasks(struct rq *rq, const char *loglvl)
+{
+       struct task_struct *g, *p;
+       int cpu = cpu_of(rq);
+
+       lockdep_assert_held(&rq->lock);
+
+       printk("%sCPU%d enqueued tasks (%u total):\n", loglvl, cpu, rq->nr_running);
+       for_each_process_thread(g, p) {
+               if (task_cpu(p) != cpu)
+                       continue;
+
+               if (!task_on_rq_queued(p))
+                       continue;
+
+               printk("%s\tpid: %d, name: %s\n", loglvl, p->pid, p->comm);
+       }
+}
+
 int sched_cpu_dying(unsigned int cpu)
 {
        struct rq *rq = cpu_rq(cpu);
@@ -7583,9 +7639,18 @@ int sched_cpu_dying(unsigned int cpu)
        sched_tick_stop(cpu);
 
        rq_lock_irqsave(rq, &rf);
-       BUG_ON(rq->nr_running != 1 || rq_has_pinned_tasks(rq));
+       if (rq->nr_running != 1 || rq_has_pinned_tasks(rq)) {
+               WARN(true, "Dying CPU not properly vacated!");
+               dump_rq_tasks(rq, KERN_WARNING);
+       }
        rq_unlock_irqrestore(rq, &rf);
 
+       /*
+        * Now that the CPU is offline, make sure we're welcome
+        * to new tasks once we come back up.
+        */
+       balance_push_set(cpu, false);
+
        calc_load_migrate(rq);
        update_max_interval();
        nohz_balance_exit_idle(rq);
index 12ada79..bb09988 100644 (file)
@@ -975,6 +975,7 @@ struct rq {
        unsigned long           cpu_capacity_orig;
 
        struct callback_head    *balance_callback;
+       unsigned char           balance_push;
 
        unsigned char           nohz_idle_balance;
        unsigned char           idle_balance;
index 5736c55..5ad8566 100644 (file)
@@ -2550,6 +2550,9 @@ bool get_signal(struct ksignal *ksig)
        struct signal_struct *signal = current->signal;
        int signr;
 
+       if (unlikely(current->task_works))
+               task_work_run();
+
        /*
         * For non-generic architectures, check for TIF_NOTIFY_SIGNAL so
         * that the arch handlers don't all have to do it. If we get here
@@ -3701,7 +3704,8 @@ static bool access_pidfd_pidns(struct pid *pid)
        return true;
 }
 
-static int copy_siginfo_from_user_any(kernel_siginfo_t *kinfo, siginfo_t *info)
+static int copy_siginfo_from_user_any(kernel_siginfo_t *kinfo,
+               siginfo_t __user *info)
 {
 #ifdef CONFIG_COMPAT
        /*
index 2efe1e2..f25208e 100644 (file)
@@ -188,6 +188,7 @@ __smpboot_create_thread(struct smp_hotplug_thread *ht, unsigned int cpu)
                kfree(td);
                return PTR_ERR(tsk);
        }
+       kthread_set_per_cpu(tsk, cpu);
        /*
         * Park the thread so that it could start right on the CPU
         * when it is available.
index 7404d38..5247afd 100644 (file)
@@ -498,11 +498,11 @@ out:
 static void sync_hw_clock(struct work_struct *work);
 static DECLARE_WORK(sync_work, sync_hw_clock);
 static struct hrtimer sync_hrtimer;
-#define SYNC_PERIOD_NS (11UL * 60 * NSEC_PER_SEC)
+#define SYNC_PERIOD_NS (11ULL * 60 * NSEC_PER_SEC)
 
 static enum hrtimer_restart sync_timer_callback(struct hrtimer *timer)
 {
-       queue_work(system_power_efficient_wq, &sync_work);
+       queue_work(system_freezable_power_efficient_wq, &sync_work);
 
        return HRTIMER_NORESTART;
 }
@@ -512,7 +512,7 @@ static void sched_sync_hw_clock(unsigned long offset_nsec, bool retry)
        ktime_t exp = ktime_set(ktime_get_real_seconds(), 0);
 
        if (retry)
-               exp = ktime_add_ns(exp, 2 * NSEC_PER_SEC - offset_nsec);
+               exp = ktime_add_ns(exp, 2ULL * NSEC_PER_SEC - offset_nsec);
        else
                exp = ktime_add_ns(exp, SYNC_PERIOD_NS - offset_nsec);
 
@@ -668,7 +668,7 @@ void ntp_notify_cmos_timer(void)
         * just a pointless work scheduled.
         */
        if (ntp_synced() && !hrtimer_is_queued(&sync_hrtimer))
-               queue_work(system_power_efficient_wq, &sync_work);
+               queue_work(system_freezable_power_efficient_wq, &sync_work);
 }
 
 static void __init ntp_init_cmos_sync(void)
index a45cedd..6aee576 100644 (file)
@@ -991,8 +991,7 @@ EXPORT_SYMBOL_GPL(ktime_get_seconds);
 /**
  * ktime_get_real_seconds - Get the seconds portion of CLOCK_REALTIME
  *
- * Returns the wall clock seconds since 1970. This replaces the
- * get_seconds() interface which is not y2038 safe on 32bit systems.
+ * Returns the wall clock seconds since 1970.
  *
  * For 64bit systems the fast access to tk->xtime_sec is preserved. On
  * 32bit systems the access must be protected with the sequence
index 73edb9e..29a6ebe 100644 (file)
@@ -394,7 +394,6 @@ static int alloc_retstack_tasklist(struct ftrace_ret_stack **ret_stack_list)
                }
 
                if (t->ret_stack == NULL) {
-                       atomic_set(&t->tracing_graph_pause, 0);
                        atomic_set(&t->trace_overrun, 0);
                        t->curr_ret_stack = -1;
                        t->curr_ret_depth = -1;
@@ -489,7 +488,6 @@ static DEFINE_PER_CPU(struct ftrace_ret_stack *, idle_ret_stack);
 static void
 graph_init_task(struct task_struct *t, struct ftrace_ret_stack *ret_stack)
 {
-       atomic_set(&t->tracing_graph_pause, 0);
        atomic_set(&t->trace_overrun, 0);
        t->ftrace_timestamp = 0;
        /* make curr_ret_stack visible before we add the ret_stack */
index d06aab4..6756379 100644 (file)
@@ -562,6 +562,8 @@ static int __irqsoff_tracer_init(struct trace_array *tr)
        /* non overwrite screws up the latency tracers */
        set_tracer_flag(tr, TRACE_ITER_OVERWRITE, 1);
        set_tracer_flag(tr, TRACE_ITER_LATENCY_FMT, 1);
+       /* without pause, we will produce garbage if another latency occurs */
+       set_tracer_flag(tr, TRACE_ITER_PAUSE_ON_TRACE, 1);
 
        tr->max_latency = 0;
        irqsoff_trace = tr;
@@ -583,11 +585,13 @@ static void __irqsoff_tracer_reset(struct trace_array *tr)
 {
        int lat_flag = save_flags & TRACE_ITER_LATENCY_FMT;
        int overwrite_flag = save_flags & TRACE_ITER_OVERWRITE;
+       int pause_flag = save_flags & TRACE_ITER_PAUSE_ON_TRACE;
 
        stop_irqsoff_tracer(tr, is_graph(tr));
 
        set_tracer_flag(tr, TRACE_ITER_LATENCY_FMT, lat_flag);
        set_tracer_flag(tr, TRACE_ITER_OVERWRITE, overwrite_flag);
+       set_tracer_flag(tr, TRACE_ITER_PAUSE_ON_TRACE, pause_flag);
        ftrace_reset_array_ops(tr);
 
        irqsoff_busy = false;
index e6fba17..56c7fbf 100644 (file)
@@ -221,9 +221,9 @@ bool trace_kprobe_on_func_entry(struct trace_event_call *call)
 {
        struct trace_kprobe *tk = trace_kprobe_primary_from_call(call);
 
-       return tk ? kprobe_on_func_entry(tk->rp.kp.addr,
+       return tk ? (kprobe_on_func_entry(tk->rp.kp.addr,
                        tk->rp.kp.addr ? NULL : tk->rp.kp.symbol_name,
-                       tk->rp.kp.addr ? 0 : tk->rp.kp.offset) : false;
+                       tk->rp.kp.addr ? 0 : tk->rp.kp.offset) == 0) : false;
 }
 
 bool trace_kprobe_error_injectable(struct trace_event_call *call)
@@ -828,9 +828,11 @@ static int trace_kprobe_create(int argc, const char *argv[])
                }
                if (is_return)
                        flags |= TPARG_FL_RETURN;
-               if (kprobe_on_func_entry(NULL, symbol, offset))
+               ret = kprobe_on_func_entry(NULL, symbol, offset);
+               if (ret == 0)
                        flags |= TPARG_FL_FENTRY;
-               if (offset && is_return && !(flags & TPARG_FL_FENTRY)) {
+               /* Defer the ENOENT case until register kprobe */
+               if (ret == -EINVAL && is_return) {
                        trace_probe_log_err(0, BAD_RETPROBE);
                        goto parse_error;
                }
index 9880b6c..894bb88 100644 (file)
@@ -1848,12 +1848,6 @@ static void worker_attach_to_pool(struct worker *worker,
 {
        mutex_lock(&wq_pool_attach_mutex);
 
-       /*
-        * set_cpus_allowed_ptr() will fail if the cpumask doesn't have any
-        * online CPUs.  It'll be re-applied when any of the CPUs come up.
-        */
-       set_cpus_allowed_ptr(worker->task, pool->attrs->cpumask);
-
        /*
         * The wq_pool_attach_mutex ensures %POOL_DISASSOCIATED remains
         * stable across this function.  See the comments above the flag
@@ -1861,6 +1855,11 @@ static void worker_attach_to_pool(struct worker *worker,
         */
        if (pool->flags & POOL_DISASSOCIATED)
                worker->flags |= WORKER_UNBOUND;
+       else
+               kthread_set_per_cpu(worker->task, pool->cpu);
+
+       if (worker->rescue_wq)
+               set_cpus_allowed_ptr(worker->task, pool->attrs->cpumask);
 
        list_add_tail(&worker->node, &pool->workers);
        worker->pool = pool;
@@ -1883,6 +1882,7 @@ static void worker_detach_from_pool(struct worker *worker)
 
        mutex_lock(&wq_pool_attach_mutex);
 
+       kthread_set_per_cpu(worker->task, -1);
        list_del(&worker->node);
        worker->pool = NULL;
 
@@ -4919,8 +4919,10 @@ static void unbind_workers(int cpu)
 
                raw_spin_unlock_irq(&pool->lock);
 
-               for_each_pool_worker(worker, pool)
-                       WARN_ON_ONCE(set_cpus_allowed_ptr(worker->task, cpu_active_mask) < 0);
+               for_each_pool_worker(worker, pool) {
+                       kthread_set_per_cpu(worker->task, -1);
+                       WARN_ON_ONCE(set_cpus_allowed_ptr(worker->task, cpu_possible_mask) < 0);
+               }
 
                mutex_unlock(&wq_pool_attach_mutex);
 
@@ -4972,9 +4974,11 @@ static void rebind_workers(struct worker_pool *pool)
         * of all workers first and then clear UNBOUND.  As we're called
         * from CPU_ONLINE, the following shouldn't fail.
         */
-       for_each_pool_worker(worker, pool)
+       for_each_pool_worker(worker, pool) {
+               kthread_set_per_cpu(worker->task, pool->cpu);
                WARN_ON_ONCE(set_cpus_allowed_ptr(worker->task,
                                                  pool->attrs->cpumask) < 0);
+       }
 
        raw_spin_lock_irq(&pool->lock);
 
index 8b635fd..3a0b1c9 100644 (file)
@@ -123,6 +123,7 @@ config UBSAN_SIGNED_OVERFLOW
 config UBSAN_UNSIGNED_OVERFLOW
        bool "Perform checking for unsigned arithmetic overflow"
        depends on $(cc-option,-fsanitize=unsigned-integer-overflow)
+       depends on !X86_32 # avoid excessive stack usage on x86-32/clang
        help
          This option enables -fsanitize=unsigned-integer-overflow which checks
          for overflow of any arithmetic operations with unsigned integers. This
index 3592402..c3c76b8 100644 (file)
@@ -6,7 +6,6 @@
 #include <linux/export.h>
 #include <linux/memblock.h>
 #include <linux/numa.h>
-#include <linux/sched/isolation.h>
 
 /**
  * cpumask_next - get the next cpu in a cpumask
@@ -206,27 +205,22 @@ void __init free_bootmem_cpumask_var(cpumask_var_t mask)
  */
 unsigned int cpumask_local_spread(unsigned int i, int node)
 {
-       int cpu, hk_flags;
-       const struct cpumask *mask;
+       int cpu;
 
-       hk_flags = HK_FLAG_DOMAIN | HK_FLAG_MANAGED_IRQ;
-       mask = housekeeping_cpumask(hk_flags);
        /* Wrap: we always want a cpu. */
-       i %= cpumask_weight(mask);
+       i %= num_online_cpus();
 
        if (node == NUMA_NO_NODE) {
-               for_each_cpu(cpu, mask) {
+               for_each_cpu(cpu, cpu_online_mask)
                        if (i-- == 0)
                                return cpu;
-               }
        } else {
                /* NUMA first. */
-               for_each_cpu_and(cpu, cpumask_of_node(node), mask) {
+               for_each_cpu_and(cpu, cpumask_of_node(node), cpu_online_mask)
                        if (i-- == 0)
                                return cpu;
-               }
 
-               for_each_cpu(cpu, mask) {
+               for_each_cpu(cpu, cpu_online_mask) {
                        /* Skip NUMA nodes, done above. */
                        if (cpumask_test_cpu(cpu, cpumask_of_node(node)))
                                continue;
index 3e3352f..bec38c6 100644 (file)
@@ -427,3 +427,34 @@ void __ubsan_handle_load_invalid_value(void *_data, void *val)
        ubsan_epilogue();
 }
 EXPORT_SYMBOL(__ubsan_handle_load_invalid_value);
+
+void __ubsan_handle_alignment_assumption(void *_data, unsigned long ptr,
+                                        unsigned long align,
+                                        unsigned long offset);
+void __ubsan_handle_alignment_assumption(void *_data, unsigned long ptr,
+                                        unsigned long align,
+                                        unsigned long offset)
+{
+       struct alignment_assumption_data *data = _data;
+       unsigned long real_ptr;
+
+       if (suppress_report(&data->location))
+               return;
+
+       ubsan_prologue(&data->location, "alignment-assumption");
+
+       if (offset)
+               pr_err("assumption of %lu byte alignment (with offset of %lu byte) for pointer of type %s failed",
+                      align, offset, data->type->type_name);
+       else
+               pr_err("assumption of %lu byte alignment for pointer of type %s failed",
+                      align, data->type->type_name);
+
+       real_ptr = ptr - offset;
+       pr_err("%saddress is %lu aligned, misalignment offset is %lu bytes",
+              offset ? "offset " : "", BIT(real_ptr ? __ffs(real_ptr) : 0),
+              real_ptr & (align - 1));
+
+       ubsan_epilogue();
+}
+EXPORT_SYMBOL(__ubsan_handle_alignment_assumption);
index 7b56c09..9a0b71c 100644 (file)
@@ -78,6 +78,12 @@ struct invalid_value_data {
        struct type_descriptor *type;
 };
 
+struct alignment_assumption_data {
+       struct source_location location;
+       struct source_location assumption_location;
+       struct type_descriptor *type;
+};
+
 #if defined(CONFIG_ARCH_SUPPORTS_INT128)
 typedef __int128 s_max;
 typedef unsigned __int128 u_max;
index e5acb97..190ccda 100644 (file)
@@ -1342,7 +1342,7 @@ fast_isolate_freepages(struct compact_control *cc)
 {
        unsigned int limit = min(1U, freelist_scan_limit(cc) >> 1);
        unsigned int nr_scanned = 0;
-       unsigned long low_pfn, min_pfn, high_pfn = 0, highest = 0;
+       unsigned long low_pfn, min_pfn, highest = 0;
        unsigned long nr_isolated = 0;
        unsigned long distance;
        struct page *page = NULL;
@@ -1387,6 +1387,7 @@ fast_isolate_freepages(struct compact_control *cc)
                struct page *freepage;
                unsigned long flags;
                unsigned int order_scanned = 0;
+               unsigned long high_pfn = 0;
 
                if (!area->nr_free)
                        continue;
index 5c9d564..aa0e0fb 100644 (file)
@@ -835,6 +835,7 @@ noinline int __add_to_page_cache_locked(struct page *page,
        XA_STATE(xas, &mapping->i_pages, offset);
        int huge = PageHuge(page);
        int error;
+       bool charged = false;
 
        VM_BUG_ON_PAGE(!PageLocked(page), page);
        VM_BUG_ON_PAGE(PageSwapBacked(page), page);
@@ -848,6 +849,7 @@ noinline int __add_to_page_cache_locked(struct page *page,
                error = mem_cgroup_charge(page, current->mm, gfp);
                if (error)
                        goto error;
+               charged = true;
        }
 
        gfp &= GFP_RECLAIM_MASK;
@@ -896,6 +898,8 @@ unlock:
 
        if (xas_error(&xas)) {
                error = xas_error(&xas);
+               if (charged)
+                       mem_cgroup_uncharge(page);
                goto error;
        }
 
index c3a9ea7..874b732 100644 (file)
@@ -473,6 +473,11 @@ static inline void *arch_kmap_local_high_get(struct page *page)
 }
 #endif
 
+#ifndef arch_kmap_local_set_pte
+#define arch_kmap_local_set_pte(mm, vaddr, ptep, ptev) \
+       set_pte_at(mm, vaddr, ptep, ptev)
+#endif
+
 /* Unmap a local mapping which was obtained by kmap_high_get() */
 static inline bool kmap_high_unmap_local(unsigned long vaddr)
 {
@@ -515,7 +520,7 @@ void *__kmap_local_pfn_prot(unsigned long pfn, pgprot_t prot)
        vaddr = __fix_to_virt(FIX_KMAP_BEGIN + idx);
        BUG_ON(!pte_none(*(kmap_pte - idx)));
        pteval = pfn_pte(pfn, prot);
-       set_pte_at(&init_mm, vaddr, kmap_pte - idx, pteval);
+       arch_kmap_local_set_pte(&init_mm, vaddr, kmap_pte - idx, pteval);
        arch_kmap_local_post_map(vaddr, pteval);
        current->kmap_ctrl.pteval[kmap_local_idx()] = pteval;
        preempt_enable();
index 9237976..91ca9b1 100644 (file)
@@ -2202,7 +2202,7 @@ void __split_huge_pmd(struct vm_area_struct *vma, pmd_t *pmd,
 {
        spinlock_t *ptl;
        struct mmu_notifier_range range;
-       bool was_locked = false;
+       bool do_unlock_page = false;
        pmd_t _pmd;
 
        mmu_notifier_range_init(&range, MMU_NOTIFY_CLEAR, 0, vma, vma->vm_mm,
@@ -2218,7 +2218,6 @@ void __split_huge_pmd(struct vm_area_struct *vma, pmd_t *pmd,
        VM_BUG_ON(freeze && !page);
        if (page) {
                VM_WARN_ON_ONCE(!PageLocked(page));
-               was_locked = true;
                if (page != pmd_page(*pmd))
                        goto out;
        }
@@ -2227,19 +2226,29 @@ repeat:
        if (pmd_trans_huge(*pmd)) {
                if (!page) {
                        page = pmd_page(*pmd);
-                       if (unlikely(!trylock_page(page))) {
-                               get_page(page);
-                               _pmd = *pmd;
-                               spin_unlock(ptl);
-                               lock_page(page);
-                               spin_lock(ptl);
-                               if (unlikely(!pmd_same(*pmd, _pmd))) {
-                                       unlock_page(page);
+                       /*
+                        * An anonymous page must be locked, to ensure that a
+                        * concurrent reuse_swap_page() sees stable mapcount;
+                        * but reuse_swap_page() is not used on shmem or file,
+                        * and page lock must not be taken when zap_pmd_range()
+                        * calls __split_huge_pmd() while i_mmap_lock is held.
+                        */
+                       if (PageAnon(page)) {
+                               if (unlikely(!trylock_page(page))) {
+                                       get_page(page);
+                                       _pmd = *pmd;
+                                       spin_unlock(ptl);
+                                       lock_page(page);
+                                       spin_lock(ptl);
+                                       if (unlikely(!pmd_same(*pmd, _pmd))) {
+                                               unlock_page(page);
+                                               put_page(page);
+                                               page = NULL;
+                                               goto repeat;
+                                       }
                                        put_page(page);
-                                       page = NULL;
-                                       goto repeat;
                                }
-                               put_page(page);
+                               do_unlock_page = true;
                        }
                }
                if (PageMlocked(page))
@@ -2249,7 +2258,7 @@ repeat:
        __split_huge_pmd_locked(vma, pmd, range.start, freeze);
 out:
        spin_unlock(ptl);
-       if (!was_locked && page)
+       if (do_unlock_page)
                unlock_page(page);
        /*
         * No need to double call mmu_notifier->invalidate_range() callback.
index 18f6ee3..4bdb58a 100644 (file)
@@ -79,6 +79,21 @@ DEFINE_SPINLOCK(hugetlb_lock);
 static int num_fault_mutexes;
 struct mutex *hugetlb_fault_mutex_table ____cacheline_aligned_in_smp;
 
+static inline bool PageHugeFreed(struct page *head)
+{
+       return page_private(head + 4) == -1UL;
+}
+
+static inline void SetPageHugeFreed(struct page *head)
+{
+       set_page_private(head + 4, -1UL);
+}
+
+static inline void ClearPageHugeFreed(struct page *head)
+{
+       set_page_private(head + 4, 0);
+}
+
 /* Forward declaration */
 static int hugetlb_acct_memory(struct hstate *h, long delta);
 
@@ -1028,6 +1043,7 @@ static void enqueue_huge_page(struct hstate *h, struct page *page)
        list_move(&page->lru, &h->hugepage_freelists[nid]);
        h->free_huge_pages++;
        h->free_huge_pages_node[nid]++;
+       SetPageHugeFreed(page);
 }
 
 static struct page *dequeue_huge_page_node_exact(struct hstate *h, int nid)
@@ -1044,6 +1060,7 @@ static struct page *dequeue_huge_page_node_exact(struct hstate *h, int nid)
 
                list_move(&page->lru, &h->hugepage_activelist);
                set_page_refcounted(page);
+               ClearPageHugeFreed(page);
                h->free_huge_pages--;
                h->free_huge_pages_node[nid]--;
                return page;
@@ -1344,12 +1361,11 @@ struct hstate *size_to_hstate(unsigned long size)
  */
 bool page_huge_active(struct page *page)
 {
-       VM_BUG_ON_PAGE(!PageHuge(page), page);
-       return PageHead(page) && PagePrivate(&page[1]);
+       return PageHeadHuge(page) && PagePrivate(&page[1]);
 }
 
 /* never called for tail page */
-static void set_page_huge_active(struct page *page)
+void set_page_huge_active(struct page *page)
 {
        VM_BUG_ON_PAGE(!PageHeadHuge(page), page);
        SetPagePrivate(&page[1]);
@@ -1505,6 +1521,7 @@ static void prep_new_huge_page(struct hstate *h, struct page *page, int nid)
        spin_lock(&hugetlb_lock);
        h->nr_huge_pages++;
        h->nr_huge_pages_node[nid]++;
+       ClearPageHugeFreed(page);
        spin_unlock(&hugetlb_lock);
 }
 
@@ -1755,6 +1772,7 @@ int dissolve_free_huge_page(struct page *page)
 {
        int rc = -EBUSY;
 
+retry:
        /* Not to disrupt normal path by vainly holding hugetlb_lock */
        if (!PageHuge(page))
                return 0;
@@ -1771,6 +1789,26 @@ int dissolve_free_huge_page(struct page *page)
                int nid = page_to_nid(head);
                if (h->free_huge_pages - h->resv_huge_pages == 0)
                        goto out;
+
+               /*
+                * We should make sure that the page is already on the free list
+                * when it is dissolved.
+                */
+               if (unlikely(!PageHugeFreed(head))) {
+                       spin_unlock(&hugetlb_lock);
+                       cond_resched();
+
+                       /*
+                        * Theoretically, we should return -EBUSY when we
+                        * encounter this race. In fact, we have a chance
+                        * to successfully dissolve the page if we do a
+                        * retry. Because the race window is quite small.
+                        * If we seize this opportunity, it is an optimization
+                        * for increasing the success rate of dissolving page.
+                        */
+                       goto retry;
+               }
+
                /*
                 * Move PageHWPoison flag from head page to the raw error page,
                 * which makes any subpages rather than the error page reusable.
@@ -2009,13 +2047,16 @@ retry:
 
        /* Free the needed pages to the hugetlb pool */
        list_for_each_entry_safe(page, tmp, &surplus_list, lru) {
+               int zeroed;
+
                if ((--needed) < 0)
                        break;
                /*
                 * This page is now managed by the hugetlb allocator and has
                 * no users -- drop the buddy allocator's reference.
                 */
-               VM_BUG_ON_PAGE(!put_page_testzero(page), page);
+               zeroed = put_page_testzero(page);
+               VM_BUG_ON_PAGE(!zeroed, page);
                enqueue_huge_page(h, page);
        }
 free:
@@ -5555,9 +5596,9 @@ bool isolate_huge_page(struct page *page, struct list_head *list)
 {
        bool ret = true;
 
-       VM_BUG_ON_PAGE(!PageHead(page), page);
        spin_lock(&hugetlb_lock);
-       if (!page_huge_active(page) || !get_page_unless_zero(page)) {
+       if (!PageHeadHuge(page) || !page_huge_active(page) ||
+           !get_page_unless_zero(page)) {
                ret = false;
                goto unlock;
        }
index 55bd6f0..e529428 100644 (file)
 
 #include "kasan.h"
 
-enum kasan_arg_mode {
-       KASAN_ARG_MODE_DEFAULT,
-       KASAN_ARG_MODE_OFF,
-       KASAN_ARG_MODE_PROD,
-       KASAN_ARG_MODE_FULL,
+enum kasan_arg {
+       KASAN_ARG_DEFAULT,
+       KASAN_ARG_OFF,
+       KASAN_ARG_ON,
 };
 
 enum kasan_arg_stacktrace {
@@ -38,7 +37,7 @@ enum kasan_arg_fault {
        KASAN_ARG_FAULT_PANIC,
 };
 
-static enum kasan_arg_mode kasan_arg_mode __ro_after_init;
+static enum kasan_arg kasan_arg __ro_after_init;
 static enum kasan_arg_stacktrace kasan_arg_stacktrace __ro_after_init;
 static enum kasan_arg_fault kasan_arg_fault __ro_after_init;
 
@@ -52,26 +51,24 @@ DEFINE_STATIC_KEY_FALSE(kasan_flag_stacktrace);
 /* Whether panic or disable tag checking on fault. */
 bool kasan_flag_panic __ro_after_init;
 
-/* kasan.mode=off/prod/full */
-static int __init early_kasan_mode(char *arg)
+/* kasan=off/on */
+static int __init early_kasan_flag(char *arg)
 {
        if (!arg)
                return -EINVAL;
 
        if (!strcmp(arg, "off"))
-               kasan_arg_mode = KASAN_ARG_MODE_OFF;
-       else if (!strcmp(arg, "prod"))
-               kasan_arg_mode = KASAN_ARG_MODE_PROD;
-       else if (!strcmp(arg, "full"))
-               kasan_arg_mode = KASAN_ARG_MODE_FULL;
+               kasan_arg = KASAN_ARG_OFF;
+       else if (!strcmp(arg, "on"))
+               kasan_arg = KASAN_ARG_ON;
        else
                return -EINVAL;
 
        return 0;
 }
-early_param("kasan.mode", early_kasan_mode);
+early_param("kasan", early_kasan_flag);
 
-/* kasan.stack=off/on */
+/* kasan.stacktrace=off/on */
 static int __init early_kasan_flag_stacktrace(char *arg)
 {
        if (!arg)
@@ -113,8 +110,8 @@ void kasan_init_hw_tags_cpu(void)
         * as this function is only called for MTE-capable hardware.
         */
 
-       /* If KASAN is disabled, do nothing. */
-       if (kasan_arg_mode == KASAN_ARG_MODE_OFF)
+       /* If KASAN is disabled via command line, don't initialize it. */
+       if (kasan_arg == KASAN_ARG_OFF)
                return;
 
        hw_init_tags(KASAN_TAG_MAX);
@@ -124,43 +121,28 @@ void kasan_init_hw_tags_cpu(void)
 /* kasan_init_hw_tags() is called once on boot CPU. */
 void __init kasan_init_hw_tags(void)
 {
-       /* If hardware doesn't support MTE, do nothing. */
+       /* If hardware doesn't support MTE, don't initialize KASAN. */
        if (!system_supports_mte())
                return;
 
-       /* Choose KASAN mode if kasan boot parameter is not provided. */
-       if (kasan_arg_mode == KASAN_ARG_MODE_DEFAULT) {
-               if (IS_ENABLED(CONFIG_DEBUG_KERNEL))
-                       kasan_arg_mode = KASAN_ARG_MODE_FULL;
-               else
-                       kasan_arg_mode = KASAN_ARG_MODE_PROD;
-       }
-
-       /* Preset parameter values based on the mode. */
-       switch (kasan_arg_mode) {
-       case KASAN_ARG_MODE_DEFAULT:
-               /* Shouldn't happen as per the check above. */
-               WARN_ON(1);
-               return;
-       case KASAN_ARG_MODE_OFF:
-               /* If KASAN is disabled, do nothing. */
+       /* If KASAN is disabled via command line, don't initialize it. */
+       if (kasan_arg == KASAN_ARG_OFF)
                return;
-       case KASAN_ARG_MODE_PROD:
-               static_branch_enable(&kasan_flag_enabled);
-               break;
-       case KASAN_ARG_MODE_FULL:
-               static_branch_enable(&kasan_flag_enabled);
-               static_branch_enable(&kasan_flag_stacktrace);
-               break;
-       }
 
-       /* Now, optionally override the presets. */
+       /* Enable KASAN. */
+       static_branch_enable(&kasan_flag_enabled);
 
        switch (kasan_arg_stacktrace) {
        case KASAN_ARG_STACKTRACE_DEFAULT:
+               /*
+                * Default to enabling stack trace collection for
+                * debug kernels.
+                */
+               if (IS_ENABLED(CONFIG_DEBUG_KERNEL))
+                       static_branch_enable(&kasan_flag_stacktrace);
                break;
        case KASAN_ARG_STACKTRACE_OFF:
-               static_branch_disable(&kasan_flag_stacktrace);
+               /* Do nothing, kasan_flag_stacktrace keeps its default value. */
                break;
        case KASAN_ARG_STACKTRACE_ON:
                static_branch_enable(&kasan_flag_stacktrace);
@@ -169,11 +151,16 @@ void __init kasan_init_hw_tags(void)
 
        switch (kasan_arg_fault) {
        case KASAN_ARG_FAULT_DEFAULT:
+               /*
+                * Default to no panic on report.
+                * Do nothing, kasan_flag_panic keeps its default value.
+                */
                break;
        case KASAN_ARG_FAULT_REPORT:
-               kasan_flag_panic = false;
+               /* Do nothing, kasan_flag_panic keeps its default value. */
                break;
        case KASAN_ARG_FAULT_PANIC:
+               /* Enable panic on report. */
                kasan_flag_panic = true;
                break;
        }
index 7ca0b92..c4605ac 100644 (file)
@@ -373,9 +373,10 @@ static void kasan_remove_pmd_table(pmd_t *pmd, unsigned long addr,
 
                if (kasan_pte_table(*pmd)) {
                        if (IS_ALIGNED(addr, PMD_SIZE) &&
-                           IS_ALIGNED(next, PMD_SIZE))
+                           IS_ALIGNED(next, PMD_SIZE)) {
                                pmd_clear(pmd);
-                       continue;
+                               continue;
+                       }
                }
                pte = pte_offset_kernel(pmd, addr);
                kasan_remove_pte_table(pte, addr, next);
@@ -398,9 +399,10 @@ static void kasan_remove_pud_table(pud_t *pud, unsigned long addr,
 
                if (kasan_pmd_table(*pud)) {
                        if (IS_ALIGNED(addr, PUD_SIZE) &&
-                           IS_ALIGNED(next, PUD_SIZE))
+                           IS_ALIGNED(next, PUD_SIZE)) {
                                pud_clear(pud);
-                       continue;
+                               continue;
+                       }
                }
                pmd = pmd_offset(pud, addr);
                pmd_base = pmd_offset(pud, 0);
@@ -424,9 +426,10 @@ static void kasan_remove_p4d_table(p4d_t *p4d, unsigned long addr,
 
                if (kasan_pud_table(*p4d)) {
                        if (IS_ALIGNED(addr, P4D_SIZE) &&
-                           IS_ALIGNED(next, P4D_SIZE))
+                           IS_ALIGNED(next, P4D_SIZE)) {
                                p4d_clear(p4d);
-                       continue;
+                               continue;
+                       }
                }
                pud = pud_offset(p4d, addr);
                kasan_remove_pud_table(pud, addr, next);
@@ -457,9 +460,10 @@ void kasan_remove_zero_shadow(void *start, unsigned long size)
 
                if (kasan_p4d_table(*pgd)) {
                        if (IS_ALIGNED(addr, PGDIR_SIZE) &&
-                           IS_ALIGNED(next, PGDIR_SIZE))
+                           IS_ALIGNED(next, PGDIR_SIZE)) {
                                pgd_clear(pgd);
-                       continue;
+                               continue;
+                       }
                }
 
                p4d = p4d_offset(pgd, addr);
@@ -482,7 +486,6 @@ int kasan_add_zero_shadow(void *start, unsigned long size)
 
        ret = kasan_populate_early_shadow(shadow_start, shadow_end);
        if (ret)
-               kasan_remove_zero_shadow(shadow_start,
-                                       size >> KASAN_SHADOW_SCALE_SHIFT);
+               kasan_remove_zero_shadow(start, size);
        return ret;
 }
index cc4d9e1..8c706e7 100644 (file)
@@ -209,7 +209,7 @@ bool check_memory_region(unsigned long addr, size_t size, bool write,
 
 static inline bool addr_has_metadata(const void *addr)
 {
-       return true;
+       return (is_vmalloc_addr(addr) || virt_addr_valid(addr));
 }
 
 #endif /* CONFIG_KASAN_GENERIC || CONFIG_KASAN_SW_TAGS */
index d24bcfa..8d9b5f1 100644 (file)
@@ -275,14 +275,6 @@ __memblock_find_range_top_down(phys_addr_t start, phys_addr_t end,
  *
  * Find @size free area aligned to @align in the specified range and node.
  *
- * When allocation direction is bottom-up, the @start should be greater
- * than the end of the kernel image. Otherwise, it will be trimmed. The
- * reason is that we want the bottom-up allocation just near the kernel
- * image so it is highly likely that the allocated memory and the kernel
- * will reside in the same node.
- *
- * If bottom-up allocation failed, will try to allocate memory top-down.
- *
  * Return:
  * Found address on success, 0 on failure.
  */
@@ -291,8 +283,6 @@ static phys_addr_t __init_memblock memblock_find_in_range_node(phys_addr_t size,
                                        phys_addr_t end, int nid,
                                        enum memblock_flags flags)
 {
-       phys_addr_t kernel_end, ret;
-
        /* pump up @end */
        if (end == MEMBLOCK_ALLOC_ACCESSIBLE ||
            end == MEMBLOCK_ALLOC_KASAN)
@@ -301,40 +291,13 @@ static phys_addr_t __init_memblock memblock_find_in_range_node(phys_addr_t size,
        /* avoid allocating the first page */
        start = max_t(phys_addr_t, start, PAGE_SIZE);
        end = max(start, end);
-       kernel_end = __pa_symbol(_end);
-
-       /*
-        * try bottom-up allocation only when bottom-up mode
-        * is set and @end is above the kernel image.
-        */
-       if (memblock_bottom_up() && end > kernel_end) {
-               phys_addr_t bottom_up_start;
-
-               /* make sure we will allocate above the kernel */
-               bottom_up_start = max(start, kernel_end);
 
-               /* ok, try bottom-up allocation first */
-               ret = __memblock_find_range_bottom_up(bottom_up_start, end,
-                                                     size, align, nid, flags);
-               if (ret)
-                       return ret;
-
-               /*
-                * we always limit bottom-up allocation above the kernel,
-                * but top-down allocation doesn't have the limit, so
-                * retrying top-down allocation may succeed when bottom-up
-                * allocation failed.
-                *
-                * bottom-up allocation is expected to be fail very rarely,
-                * so we use WARN_ONCE() here to see the stack trace if
-                * fail happens.
-                */
-               WARN_ONCE(IS_ENABLED(CONFIG_MEMORY_HOTREMOVE),
-                         "memblock: bottom-up allocation failed, memory hotremove may be affected\n");
-       }
-
-       return __memblock_find_range_top_down(start, end, size, align, nid,
-                                             flags);
+       if (memblock_bottom_up())
+               return __memblock_find_range_bottom_up(start, end, size, align,
+                                                      nid, flags);
+       else
+               return __memblock_find_range_top_down(start, end, size, align,
+                                                     nid, flags);
 }
 
 /**
@@ -1427,7 +1390,7 @@ phys_addr_t __init memblock_phys_alloc_range(phys_addr_t size,
 }
 
 /**
- * memblock_phys_alloc_try_nid - allocate a memory block from specified MUMA node
+ * memblock_phys_alloc_try_nid - allocate a memory block from specified NUMA node
  * @size: size of memory block to be allocated in bytes
  * @align: alignment of the region and block's size
  * @nid: nid of the free area to find, %NUMA_NO_NODE for any node
index 605f671..e2de77b 100644 (file)
@@ -3115,9 +3115,7 @@ void __memcg_kmem_uncharge(struct mem_cgroup *memcg, unsigned int nr_pages)
        if (!cgroup_subsys_on_dfl(memory_cgrp_subsys))
                page_counter_uncharge(&memcg->kmem, nr_pages);
 
-       page_counter_uncharge(&memcg->memory, nr_pages);
-       if (do_memsw_account())
-               page_counter_uncharge(&memcg->memsw, nr_pages);
+       refill_stock(memcg, nr_pages);
 }
 
 /**
index 04d9f15..e948163 100644 (file)
@@ -1885,6 +1885,12 @@ static int soft_offline_free_page(struct page *page)
        return rc;
 }
 
+static void put_ref_page(struct page *page)
+{
+       if (page)
+               put_page(page);
+}
+
 /**
  * soft_offline_page - Soft offline a page.
  * @pfn: pfn to soft-offline
@@ -1910,20 +1916,26 @@ static int soft_offline_free_page(struct page *page)
 int soft_offline_page(unsigned long pfn, int flags)
 {
        int ret;
-       struct page *page;
        bool try_again = true;
+       struct page *page, *ref_page = NULL;
+
+       WARN_ON_ONCE(!pfn_valid(pfn) && (flags & MF_COUNT_INCREASED));
 
        if (!pfn_valid(pfn))
                return -ENXIO;
+       if (flags & MF_COUNT_INCREASED)
+               ref_page = pfn_to_page(pfn);
+
        /* Only online pages can be soft-offlined (esp., not ZONE_DEVICE). */
        page = pfn_to_online_page(pfn);
-       if (!page)
+       if (!page) {
+               put_ref_page(ref_page);
                return -EIO;
+       }
 
        if (PageHWPoison(page)) {
                pr_info("%s: %#lx page already poisoned\n", __func__, pfn);
-               if (flags & MF_COUNT_INCREASED)
-                       put_page(page);
+               put_ref_page(ref_page);
                return 0;
        }
 
index ee5e612..20ca887 100644 (file)
@@ -402,6 +402,7 @@ int migrate_page_move_mapping(struct address_space *mapping,
        struct zone *oldzone, *newzone;
        int dirty;
        int expected_count = expected_page_refs(mapping, page) + extra_count;
+       int nr = thp_nr_pages(page);
 
        if (!mapping) {
                /* Anonymous page without mapping */
@@ -437,7 +438,7 @@ int migrate_page_move_mapping(struct address_space *mapping,
         */
        newpage->index = page->index;
        newpage->mapping = page->mapping;
-       page_ref_add(newpage, thp_nr_pages(page)); /* add cache reference */
+       page_ref_add(newpage, nr); /* add cache reference */
        if (PageSwapBacked(page)) {
                __SetPageSwapBacked(newpage);
                if (PageSwapCache(page)) {
@@ -459,7 +460,7 @@ int migrate_page_move_mapping(struct address_space *mapping,
        if (PageTransHuge(page)) {
                int i;
 
-               for (i = 1; i < HPAGE_PMD_NR; i++) {
+               for (i = 1; i < nr; i++) {
                        xas_next(&xas);
                        xas_store(&xas, newpage);
                }
@@ -470,7 +471,7 @@ int migrate_page_move_mapping(struct address_space *mapping,
         * to one less reference.
         * We know this isn't the last reference.
         */
-       page_ref_unfreeze(page, expected_count - thp_nr_pages(page));
+       page_ref_unfreeze(page, expected_count - nr);
 
        xas_unlock(&xas);
        /* Leave irq disabled to prevent preemption while updating stats */
@@ -493,17 +494,17 @@ int migrate_page_move_mapping(struct address_space *mapping,
                old_lruvec = mem_cgroup_lruvec(memcg, oldzone->zone_pgdat);
                new_lruvec = mem_cgroup_lruvec(memcg, newzone->zone_pgdat);
 
-               __dec_lruvec_state(old_lruvec, NR_FILE_PAGES);
-               __inc_lruvec_state(new_lruvec, NR_FILE_PAGES);
+               __mod_lruvec_state(old_lruvec, NR_FILE_PAGES, -nr);
+               __mod_lruvec_state(new_lruvec, NR_FILE_PAGES, nr);
                if (PageSwapBacked(page) && !PageSwapCache(page)) {
-                       __dec_lruvec_state(old_lruvec, NR_SHMEM);
-                       __inc_lruvec_state(new_lruvec, NR_SHMEM);
+                       __mod_lruvec_state(old_lruvec, NR_SHMEM, -nr);
+                       __mod_lruvec_state(new_lruvec, NR_SHMEM, nr);
                }
                if (dirty && mapping_can_writeback(mapping)) {
-                       __dec_node_state(oldzone->zone_pgdat, NR_FILE_DIRTY);
-                       __dec_zone_state(oldzone, NR_ZONE_WRITE_PENDING);
-                       __inc_node_state(newzone->zone_pgdat, NR_FILE_DIRTY);
-                       __inc_zone_state(newzone, NR_ZONE_WRITE_PENDING);
+                       __mod_lruvec_state(old_lruvec, NR_FILE_DIRTY, -nr);
+                       __mod_zone_page_state(oldzone, NR_ZONE_WRITE_PENDING, -nr);
+                       __mod_lruvec_state(new_lruvec, NR_FILE_DIRTY, nr);
+                       __mod_zone_page_state(newzone, NR_ZONE_WRITE_PENDING, nr);
                }
        }
        local_irq_enable();
@@ -1279,6 +1280,12 @@ static int unmap_and_move_huge_page(new_page_t get_new_page,
                return -ENOSYS;
        }
 
+       if (page_count(hpage) == 1) {
+               /* page was freed from under us. So we are done. */
+               putback_active_hugepage(hpage);
+               return MIGRATEPAGE_SUCCESS;
+       }
+
        new_hpage = get_new_page(hpage, private);
        if (!new_hpage)
                return -ENOMEM;
index 027f648..519a60d 100644 (file)
@@ -1207,8 +1207,10 @@ static void kernel_init_free_pages(struct page *page, int numpages)
        /* s390's use of memset() could override KASAN redzones. */
        kasan_disable_current();
        for (i = 0; i < numpages; i++) {
+               u8 tag = page_kasan_tag(page + i);
                page_kasan_tag_reset(page + i);
                clear_highpage(page + i);
+               page_kasan_tag_set(page + i, tag);
        }
        kasan_enable_current();
 }
index d9e4e10..7ecbbbe 100644 (file)
--- a/mm/slub.c
+++ b/mm/slub.c
@@ -2791,7 +2791,8 @@ static __always_inline void maybe_wipe_obj_freeptr(struct kmem_cache *s,
                                                   void *obj)
 {
        if (unlikely(slab_want_init_on_free(s)) && obj)
-               memset((void *)((char *)obj + s->offset), 0, sizeof(void *));
+               memset((void *)((char *)kasan_reset_tag(obj) + s->offset),
+                       0, sizeof(void *));
 }
 
 /*
@@ -2883,7 +2884,7 @@ redo:
                stat(s, ALLOC_FASTPATH);
        }
 
-       maybe_wipe_obj_freeptr(s, kasan_reset_tag(object));
+       maybe_wipe_obj_freeptr(s, object);
 
        if (unlikely(slab_want_init_on_alloc(gfpflags, s)) && object)
                memset(kasan_reset_tag(object), 0, s->object_size);
@@ -3329,7 +3330,7 @@ int kmem_cache_alloc_bulk(struct kmem_cache *s, gfp_t flags, size_t size,
                int j;
 
                for (j = 0; j < i; j++)
-                       memset(p[j], 0, s->object_size);
+                       memset(kasan_reset_tag(p[j]), 0, s->object_size);
        }
 
        /* memcg and kmem_cache debug support */
@@ -5624,10 +5625,8 @@ static int sysfs_slab_add(struct kmem_cache *s)
 
        s->kobj.kset = kset;
        err = kobject_init_and_add(&s->kobj, &slab_ktype, NULL, "%s", name);
-       if (err) {
-               kobject_put(&s->kobj);
+       if (err)
                goto out;
-       }
 
        err = sysfs_create_group(&s->kobj, &slab_attr_group);
        if (err)
index c1c30a9..8b796c4 100644 (file)
@@ -272,7 +272,8 @@ int bpf_prog_test_run_raw_tp(struct bpf_prog *prog,
            kattr->test.repeat)
                return -EINVAL;
 
-       if (ctx_size_in < prog->aux->max_ctx_offset)
+       if (ctx_size_in < prog->aux->max_ctx_offset ||
+           ctx_size_in > MAX_BPF_FUNC_ARGS * sizeof(u64))
                return -EINVAL;
 
        if ((kattr->test.flags & BPF_F_TEST_RUN_ON_CPU) == 0 && cpu != 0)
index 1883118..32a48e5 100644 (file)
@@ -88,4 +88,33 @@ int br_mrp_switchdev_send_in_test(struct net_bridge *br, struct br_mrp *mrp,
 int br_mrp_ring_port_open(struct net_device *dev, u8 loc);
 int br_mrp_in_port_open(struct net_device *dev, u8 loc);
 
+/* MRP protocol data units */
+struct br_mrp_tlv_hdr {
+       __u8 type;
+       __u8 length;
+};
+
+struct br_mrp_common_hdr {
+       __be16 seq_id;
+       __u8 domain[MRP_DOMAIN_UUID_LENGTH];
+};
+
+struct br_mrp_ring_test_hdr {
+       __be16 prio;
+       __u8 sa[ETH_ALEN];
+       __be16 port_role;
+       __be16 state;
+       __be16 transitions;
+       __be32 timestamp;
+} __attribute__((__packed__));
+
+struct br_mrp_in_test_hdr {
+       __be16 id;
+       __u8 sa[ETH_ALEN];
+       __be16 port_role;
+       __be16 state;
+       __be16 transitions;
+       __be32 timestamp;
+} __attribute__((__packed__));
+
 #endif /* _BR_PRIVATE_MRP_H */
index 9815cfe..ca44c32 100644 (file)
@@ -569,6 +569,34 @@ e_range:
        return -ERANGE;
 }
 
+static int decode_con_secret(void **p, void *end, u8 *con_secret,
+                            int *con_secret_len)
+{
+       int len;
+
+       ceph_decode_32_safe(p, end, len, bad);
+       ceph_decode_need(p, end, len, bad);
+
+       dout("%s len %d\n", __func__, len);
+       if (con_secret) {
+               if (len > CEPH_MAX_CON_SECRET_LEN) {
+                       pr_err("connection secret too big %d\n", len);
+                       goto bad_memzero;
+               }
+               memcpy(con_secret, *p, len);
+               *con_secret_len = len;
+       }
+       memzero_explicit(*p, len);
+       *p += len;
+       return 0;
+
+bad_memzero:
+       memzero_explicit(*p, len);
+bad:
+       pr_err("failed to decode connection secret\n");
+       return -EINVAL;
+}
+
 static int handle_auth_session_key(struct ceph_auth_client *ac,
                                   void **p, void *end,
                                   u8 *session_key, int *session_key_len,
@@ -612,17 +640,9 @@ static int handle_auth_session_key(struct ceph_auth_client *ac,
                dout("%s decrypted %d bytes\n", __func__, ret);
                dend = dp + ret;
 
-               ceph_decode_32_safe(&dp, dend, len, e_inval);
-               if (len > CEPH_MAX_CON_SECRET_LEN) {
-                       pr_err("connection secret too big %d\n", len);
-                       return -EINVAL;
-               }
-
-               dout("%s connection secret len %d\n", __func__, len);
-               if (con_secret) {
-                       memcpy(con_secret, dp, len);
-                       *con_secret_len = len;
-               }
+               ret = decode_con_secret(&dp, dend, con_secret, con_secret_len);
+               if (ret)
+                       return ret;
        }
 
        /* service tickets */
@@ -828,7 +848,6 @@ static int decrypt_authorizer_reply(struct ceph_crypto_key *secret,
 {
        void *dp, *dend;
        u8 struct_v;
-       int len;
        int ret;
 
        dp = *p + ceph_x_encrypt_offset();
@@ -843,17 +862,9 @@ static int decrypt_authorizer_reply(struct ceph_crypto_key *secret,
        ceph_decode_64_safe(&dp, dend, *nonce_plus_one, e_inval);
        dout("%s nonce_plus_one %llu\n", __func__, *nonce_plus_one);
        if (struct_v >= 2) {
-               ceph_decode_32_safe(&dp, dend, len, e_inval);
-               if (len > CEPH_MAX_CON_SECRET_LEN) {
-                       pr_err("connection secret too big %d\n", len);
-                       return -EINVAL;
-               }
-
-               dout("%s connection secret len %d\n", __func__, len);
-               if (con_secret) {
-                       memcpy(con_secret, dp, len);
-                       *con_secret_len = len;
-               }
+               ret = decode_con_secret(&dp, dend, con_secret, con_secret_len);
+               if (ret)
+                       return ret;
        }
 
        return 0;
index 4f75df4..92d89b3 100644 (file)
@@ -96,6 +96,7 @@ int ceph_crypto_key_decode(struct ceph_crypto_key *key, void **p, void *end)
        key->len = ceph_decode_16(p);
        ceph_decode_need(p, end, key->len, bad);
        ret = set_secret(key, *p);
+       memzero_explicit(*p, key->len);
        *p += key->len;
        return ret;
 
@@ -134,7 +135,7 @@ int ceph_crypto_key_unarmor(struct ceph_crypto_key *key, const char *inkey)
 void ceph_crypto_key_destroy(struct ceph_crypto_key *key)
 {
        if (key) {
-               kfree(key->key);
+               kfree_sensitive(key->key);
                key->key = NULL;
                if (key->tfm) {
                        crypto_free_sync_skcipher(key->tfm);
index 04f653b..2cb5ffd 100644 (file)
@@ -1100,7 +1100,7 @@ static int read_partial_message(struct ceph_connection *con)
                if (ret < 0)
                        return ret;
 
-               BUG_ON(!con->in_msg ^ skip);
+               BUG_ON((!con->in_msg) ^ skip);
                if (skip) {
                        /* skip this message */
                        dout("alloc_msg said skip message\n");
index c38d8de..cc40ce4 100644 (file)
@@ -689,11 +689,10 @@ static int verify_epilogue_crcs(struct ceph_connection *con, u32 front_crc,
 }
 
 static int setup_crypto(struct ceph_connection *con,
-                       u8 *session_key, int session_key_len,
-                       u8 *con_secret, int con_secret_len)
+                       const u8 *session_key, int session_key_len,
+                       const u8 *con_secret, int con_secret_len)
 {
        unsigned int noio_flag;
-       void *p;
        int ret;
 
        dout("%s con %p con_mode %d session_key_len %d con_secret_len %d\n",
@@ -751,15 +750,14 @@ static int setup_crypto(struct ceph_connection *con,
                return ret;
        }
 
-       p = con_secret;
-       WARN_ON((unsigned long)p & crypto_aead_alignmask(con->v2.gcm_tfm));
-       ret = crypto_aead_setkey(con->v2.gcm_tfm, p, CEPH_GCM_KEY_LEN);
+       WARN_ON((unsigned long)con_secret &
+               crypto_aead_alignmask(con->v2.gcm_tfm));
+       ret = crypto_aead_setkey(con->v2.gcm_tfm, con_secret, CEPH_GCM_KEY_LEN);
        if (ret) {
                pr_err("failed to set gcm key: %d\n", ret);
                return ret;
        }
 
-       p += CEPH_GCM_KEY_LEN;
        WARN_ON(crypto_aead_ivsize(con->v2.gcm_tfm) != CEPH_GCM_IV_LEN);
        ret = crypto_aead_setauthsize(con->v2.gcm_tfm, CEPH_GCM_TAG_LEN);
        if (ret) {
@@ -777,8 +775,11 @@ static int setup_crypto(struct ceph_connection *con,
        aead_request_set_callback(con->v2.gcm_req, CRYPTO_TFM_REQ_MAY_BACKLOG,
                                  crypto_req_done, &con->v2.gcm_wait);
 
-       memcpy(&con->v2.in_gcm_nonce, p, CEPH_GCM_IV_LEN);
-       memcpy(&con->v2.out_gcm_nonce, p + CEPH_GCM_IV_LEN, CEPH_GCM_IV_LEN);
+       memcpy(&con->v2.in_gcm_nonce, con_secret + CEPH_GCM_KEY_LEN,
+              CEPH_GCM_IV_LEN);
+       memcpy(&con->v2.out_gcm_nonce,
+              con_secret + CEPH_GCM_KEY_LEN + CEPH_GCM_IV_LEN,
+              CEPH_GCM_IV_LEN);
        return 0;  /* auth_x, secure mode */
 }
 
@@ -800,7 +801,7 @@ static int hmac_sha256(struct ceph_connection *con, const struct kvec *kvecs,
        desc->tfm = con->v2.hmac_tfm;
        ret = crypto_shash_init(desc);
        if (ret)
-               return ret;
+               goto out;
 
        for (i = 0; i < kvec_cnt; i++) {
                WARN_ON((unsigned long)kvecs[i].iov_base &
@@ -808,15 +809,14 @@ static int hmac_sha256(struct ceph_connection *con, const struct kvec *kvecs,
                ret = crypto_shash_update(desc, kvecs[i].iov_base,
                                          kvecs[i].iov_len);
                if (ret)
-                       return ret;
+                       goto out;
        }
 
        ret = crypto_shash_final(desc, hmac);
-       if (ret)
-               return ret;
 
+out:
        shash_desc_zero(desc);
-       return 0;  /* auth_x, both plain and secure modes */
+       return ret;  /* auth_x, both plain and secure modes */
 }
 
 static void gcm_inc_nonce(struct ceph_gcm_nonce *nonce)
@@ -2072,27 +2072,32 @@ static int process_auth_done(struct ceph_connection *con, void *p, void *end)
        if (con->state != CEPH_CON_S_V2_AUTH) {
                dout("%s con %p state changed to %d\n", __func__, con,
                     con->state);
-               return -EAGAIN;
+               ret = -EAGAIN;
+               goto out;
        }
 
        dout("%s con %p handle_auth_done ret %d\n", __func__, con, ret);
        if (ret)
-               return ret;
+               goto out;
 
        ret = setup_crypto(con, session_key, session_key_len, con_secret,
                           con_secret_len);
        if (ret)
-               return ret;
+               goto out;
 
        reset_out_kvecs(con);
        ret = prepare_auth_signature(con);
        if (ret) {
                pr_err("prepare_auth_signature failed: %d\n", ret);
-               return ret;
+               goto out;
        }
 
        con->state = CEPH_CON_S_V2_AUTH_SIGNATURE;
-       return 0;
+
+out:
+       memzero_explicit(session_key_buf, sizeof(session_key_buf));
+       memzero_explicit(con_secret_buf, sizeof(con_secret_buf));
+       return ret;
 
 bad:
        pr_err("failed to decode auth_done\n");
@@ -3436,6 +3441,8 @@ void ceph_con_v2_reset_protocol(struct ceph_connection *con)
        }
 
        con->v2.con_mode = CEPH_CON_MODE_UNKNOWN;
+       memzero_explicit(&con->v2.in_gcm_nonce, CEPH_GCM_IV_LEN);
+       memzero_explicit(&con->v2.out_gcm_nonce, CEPH_GCM_IV_LEN);
 
        if (con->v2.hmac_tfm) {
                crypto_free_shash(con->v2.hmac_tfm);
index b9d54ed..195ceb8 100644 (file)
@@ -1433,7 +1433,7 @@ static int mon_handle_auth_bad_method(struct ceph_connection *con,
 /*
  * handle incoming message
  */
-static void dispatch(struct ceph_connection *con, struct ceph_msg *msg)
+static void mon_dispatch(struct ceph_connection *con, struct ceph_msg *msg)
 {
        struct ceph_mon_client *monc = con->private;
        int type = le16_to_cpu(msg->hdr.type);
@@ -1565,21 +1565,21 @@ static void mon_fault(struct ceph_connection *con)
  * will come from the messenger workqueue, which is drained prior to
  * mon_client destruction.
  */
-static struct ceph_connection *con_get(struct ceph_connection *con)
+static struct ceph_connection *mon_get_con(struct ceph_connection *con)
 {
        return con;
 }
 
-static void con_put(struct ceph_connection *con)
+static void mon_put_con(struct ceph_connection *con)
 {
 }
 
 static const struct ceph_connection_operations mon_con_ops = {
-       .get = con_get,
-       .put = con_put,
-       .dispatch = dispatch,
-       .fault = mon_fault,
+       .get = mon_get_con,
+       .put = mon_put_con,
        .alloc_msg = mon_alloc_msg,
+       .dispatch = mon_dispatch,
+       .fault = mon_fault,
        .get_auth_request = mon_get_auth_request,
        .handle_auth_reply_more = mon_handle_auth_reply_more,
        .handle_auth_done = mon_handle_auth_done,
index 61229c5..ff8624a 100644 (file)
@@ -5412,7 +5412,7 @@ void ceph_osdc_cleanup(void)
 /*
  * handle incoming message
  */
-static void dispatch(struct ceph_connection *con, struct ceph_msg *msg)
+static void osd_dispatch(struct ceph_connection *con, struct ceph_msg *msg)
 {
        struct ceph_osd *osd = con->private;
        struct ceph_osd_client *osdc = osd->o_osdc;
@@ -5534,9 +5534,9 @@ static struct ceph_msg *alloc_msg_with_page_vector(struct ceph_msg_header *hdr)
        return m;
 }
 
-static struct ceph_msg *alloc_msg(struct ceph_connection *con,
-                                 struct ceph_msg_header *hdr,
-                                 int *skip)
+static struct ceph_msg *osd_alloc_msg(struct ceph_connection *con,
+                                     struct ceph_msg_header *hdr,
+                                     int *skip)
 {
        struct ceph_osd *osd = con->private;
        int type = le16_to_cpu(hdr->type);
@@ -5560,7 +5560,7 @@ static struct ceph_msg *alloc_msg(struct ceph_connection *con,
 /*
  * Wrappers to refcount containing ceph_osd struct
  */
-static struct ceph_connection *get_osd_con(struct ceph_connection *con)
+static struct ceph_connection *osd_get_con(struct ceph_connection *con)
 {
        struct ceph_osd *osd = con->private;
        if (get_osd(osd))
@@ -5568,7 +5568,7 @@ static struct ceph_connection *get_osd_con(struct ceph_connection *con)
        return NULL;
 }
 
-static void put_osd_con(struct ceph_connection *con)
+static void osd_put_con(struct ceph_connection *con)
 {
        struct ceph_osd *osd = con->private;
        put_osd(osd);
@@ -5582,8 +5582,8 @@ static void put_osd_con(struct ceph_connection *con)
  * Note: returned pointer is the address of a structure that's
  * managed separately.  Caller must *not* attempt to free it.
  */
-static struct ceph_auth_handshake *get_authorizer(struct ceph_connection *con,
-                                       int *proto, int force_new)
+static struct ceph_auth_handshake *
+osd_get_authorizer(struct ceph_connection *con, int *proto, int force_new)
 {
        struct ceph_osd *o = con->private;
        struct ceph_osd_client *osdc = o->o_osdc;
@@ -5599,7 +5599,7 @@ static struct ceph_auth_handshake *get_authorizer(struct ceph_connection *con,
        return auth;
 }
 
-static int add_authorizer_challenge(struct ceph_connection *con,
+static int osd_add_authorizer_challenge(struct ceph_connection *con,
                                    void *challenge_buf, int challenge_buf_len)
 {
        struct ceph_osd *o = con->private;
@@ -5610,7 +5610,7 @@ static int add_authorizer_challenge(struct ceph_connection *con,
                                            challenge_buf, challenge_buf_len);
 }
 
-static int verify_authorizer_reply(struct ceph_connection *con)
+static int osd_verify_authorizer_reply(struct ceph_connection *con)
 {
        struct ceph_osd *o = con->private;
        struct ceph_osd_client *osdc = o->o_osdc;
@@ -5622,7 +5622,7 @@ static int verify_authorizer_reply(struct ceph_connection *con)
                NULL, NULL, NULL, NULL);
 }
 
-static int invalidate_authorizer(struct ceph_connection *con)
+static int osd_invalidate_authorizer(struct ceph_connection *con)
 {
        struct ceph_osd *o = con->private;
        struct ceph_osd_client *osdc = o->o_osdc;
@@ -5731,18 +5731,18 @@ static int osd_check_message_signature(struct ceph_msg *msg)
 }
 
 static const struct ceph_connection_operations osd_con_ops = {
-       .get = get_osd_con,
-       .put = put_osd_con,
-       .dispatch = dispatch,
-       .get_authorizer = get_authorizer,
-       .add_authorizer_challenge = add_authorizer_challenge,
-       .verify_authorizer_reply = verify_authorizer_reply,
-       .invalidate_authorizer = invalidate_authorizer,
-       .alloc_msg = alloc_msg,
+       .get = osd_get_con,
+       .put = osd_put_con,
+       .alloc_msg = osd_alloc_msg,
+       .dispatch = osd_dispatch,
+       .fault = osd_fault,
        .reencode_message = osd_reencode_message,
+       .get_authorizer = osd_get_authorizer,
+       .add_authorizer_challenge = osd_add_authorizer_challenge,
+       .verify_authorizer_reply = osd_verify_authorizer_reply,
+       .invalidate_authorizer = osd_invalidate_authorizer,
        .sign_message = osd_sign_message,
        .check_message_signature = osd_check_message_signature,
-       .fault = osd_fault,
        .get_auth_request = osd_get_auth_request,
        .handle_auth_reply_more = osd_handle_auth_reply_more,
        .handle_auth_done = osd_handle_auth_done,
index c360bb5..a979b86 100644 (file)
@@ -9672,6 +9672,11 @@ static netdev_features_t netdev_fix_features(struct net_device *dev,
                }
        }
 
+       if ((features & NETIF_F_HW_TLS_RX) && !(features & NETIF_F_RXCSUM)) {
+               netdev_dbg(dev, "Dropping TLS RX HW offload feature since no RXCSUM feature.\n");
+               features &= ~NETIF_F_HW_TLS_RX;
+       }
+
        return features;
 }
 
index ee828e4..738d434 100644 (file)
@@ -4146,7 +4146,7 @@ out:
 static int devlink_nl_cmd_port_param_get_doit(struct sk_buff *skb,
                                              struct genl_info *info)
 {
-       struct devlink_port *devlink_port = info->user_ptr[0];
+       struct devlink_port *devlink_port = info->user_ptr[1];
        struct devlink_param_item *param_item;
        struct sk_buff *msg;
        int err;
@@ -4175,7 +4175,7 @@ static int devlink_nl_cmd_port_param_get_doit(struct sk_buff *skb,
 static int devlink_nl_cmd_port_param_set_doit(struct sk_buff *skb,
                                              struct genl_info *info)
 {
-       struct devlink_port *devlink_port = info->user_ptr[0];
+       struct devlink_port *devlink_port = info->user_ptr[1];
 
        return __devlink_nl_cmd_param_set_doit(devlink_port->devlink,
                                               devlink_port->index,
index 80dbf2f..8e582e2 100644 (file)
@@ -80,11 +80,11 @@ static void est_timer(struct timer_list *t)
        u64 rate, brate;
 
        est_fetch_counters(est, &b);
-       brate = (b.bytes - est->last_bytes) << (10 - est->ewma_log - est->intvl_log);
-       brate -= (est->avbps >> est->ewma_log);
+       brate = (b.bytes - est->last_bytes) << (10 - est->intvl_log);
+       brate = (brate >> est->ewma_log) - (est->avbps >> est->ewma_log);
 
-       rate = (b.packets - est->last_packets) << (10 - est->ewma_log - est->intvl_log);
-       rate -= (est->avpps >> est->ewma_log);
+       rate = (b.packets - est->last_packets) << (10 - est->intvl_log);
+       rate = (rate >> est->ewma_log) - (est->avpps >> est->ewma_log);
 
        write_seqcount_begin(&est->seq);
        est->avbps += brate;
@@ -143,6 +143,9 @@ int gen_new_estimator(struct gnet_stats_basic_packed *bstats,
        if (parm->interval < -2 || parm->interval > 3)
                return -EINVAL;
 
+       if (parm->ewma_log == 0 || parm->ewma_log >= 31)
+               return -EINVAL;
+
        est = kzalloc(sizeof(*est), GFP_KERNEL);
        if (!est)
                return -ENOBUFS;
index 277ed85..6d2d557 100644 (file)
@@ -1245,13 +1245,14 @@ static int __neigh_update(struct neighbour *neigh, const u8 *lladdr,
        old    = neigh->nud_state;
        err    = -EPERM;
 
-       if (!(flags & NEIGH_UPDATE_F_ADMIN) &&
-           (old & (NUD_NOARP | NUD_PERMANENT)))
-               goto out;
        if (neigh->dead) {
                NL_SET_ERR_MSG(extack, "Neighbor entry is now dead");
+               new = old;
                goto out;
        }
+       if (!(flags & NEIGH_UPDATE_F_ADMIN) &&
+           (old & (NUD_NOARP | NUD_PERMANENT)))
+               goto out;
 
        ext_learn_change = neigh_update_ext_learned(neigh, flags, &notify);
 
index c1a6f26..785daff 100644 (file)
@@ -437,7 +437,11 @@ struct sk_buff *__netdev_alloc_skb(struct net_device *dev, unsigned int len,
 
        len += NET_SKB_PAD;
 
-       if ((len > SKB_WITH_OVERHEAD(PAGE_SIZE)) ||
+       /* If requested length is either too small or too big,
+        * we use kmalloc() for skb->head allocation.
+        */
+       if (len <= SKB_WITH_OVERHEAD(1024) ||
+           len > SKB_WITH_OVERHEAD(PAGE_SIZE) ||
            (gfp_mask & (__GFP_DIRECT_RECLAIM | GFP_DMA))) {
                skb = __alloc_skb(len, gfp_mask, SKB_ALLOC_RX, NUMA_NO_NODE);
                if (!skb)
index 4cac31d..2193ae5 100644 (file)
@@ -1035,7 +1035,7 @@ source_ok:
                        fld.saddr = dnet_select_source(dev_out, 0,
                                                       RT_SCOPE_HOST);
                        if (!fld.daddr)
-                               goto out;
+                               goto done;
                }
                fld.flowidn_oif = LOOPBACK_IFINDEX;
                res.type = RTN_LOCAL;
index 7dc92ce..a9c30a6 100644 (file)
@@ -217,7 +217,10 @@ struct hsr_priv {
        u8 net_id;              /* for PRP, it occupies most significant 3 bits
                                 * of lan_id
                                 */
-       unsigned char           sup_multicast_addr[ETH_ALEN];
+       unsigned char           sup_multicast_addr[ETH_ALEN] __aligned(sizeof(u16));
+                               /* Align to u16 boundary to avoid unaligned access
+                                * in ether_addr_equal
+                                */
 #ifdef CONFIG_DEBUG_FS
        struct dentry *node_tbl_root;
 #endif
index fd8b880..6bd7ca0 100644 (file)
@@ -851,6 +851,7 @@ struct sock *inet_csk_clone_lock(const struct sock *sk,
                newicsk->icsk_retransmits = 0;
                newicsk->icsk_backoff     = 0;
                newicsk->icsk_probes_out  = 0;
+               newicsk->icsk_probes_tstamp = 0;
 
                /* Deinitialize accept_queue to trap illegal accesses. */
                memset(&newicsk->icsk_accept_queue, 0, sizeof(newicsk->icsk_accept_queue));
index 64594aa..76a420c 100644 (file)
@@ -317,7 +317,7 @@ static int ip_tunnel_bind_dev(struct net_device *dev)
        }
 
        dev->needed_headroom = t_hlen + hlen;
-       mtu -= (dev->hard_header_len + t_hlen);
+       mtu -= t_hlen;
 
        if (mtu < IPV4_MIN_MTU)
                mtu = IPV4_MIN_MTU;
@@ -347,7 +347,7 @@ static struct ip_tunnel *ip_tunnel_create(struct net *net,
        nt = netdev_priv(dev);
        t_hlen = nt->hlen + sizeof(struct iphdr);
        dev->min_mtu = ETH_MIN_MTU;
-       dev->max_mtu = IP_MAX_MTU - dev->hard_header_len - t_hlen;
+       dev->max_mtu = IP_MAX_MTU - t_hlen;
        ip_tunnel_add(itn, nt);
        return nt;
 
@@ -488,11 +488,10 @@ static int tnl_update_pmtu(struct net_device *dev, struct sk_buff *skb,
        int mtu;
 
        tunnel_hlen = md ? tunnel_hlen : tunnel->hlen;
-       pkt_size = skb->len - tunnel_hlen - dev->hard_header_len;
+       pkt_size = skb->len - tunnel_hlen;
 
        if (df)
-               mtu = dst_mtu(&rt->dst) - dev->hard_header_len
-                                       - sizeof(struct iphdr) - tunnel_hlen;
+               mtu = dst_mtu(&rt->dst) - (sizeof(struct iphdr) + tunnel_hlen);
        else
                mtu = skb_valid_dst(skb) ? dst_mtu(skb_dst(skb)) : dev->mtu;
 
@@ -972,7 +971,7 @@ int __ip_tunnel_change_mtu(struct net_device *dev, int new_mtu, bool strict)
 {
        struct ip_tunnel *tunnel = netdev_priv(dev);
        int t_hlen = tunnel->hlen + sizeof(struct iphdr);
-       int max_mtu = IP_MAX_MTU - dev->hard_header_len - t_hlen;
+       int max_mtu = IP_MAX_MTU - t_hlen;
 
        if (new_mtu < ETH_MIN_MTU)
                return -EINVAL;
@@ -1149,10 +1148,9 @@ int ip_tunnel_newlink(struct net_device *dev, struct nlattr *tb[],
 
        mtu = ip_tunnel_bind_dev(dev);
        if (tb[IFLA_MTU]) {
-               unsigned int max = IP_MAX_MTU - dev->hard_header_len - nt->hlen;
+               unsigned int max = IP_MAX_MTU - (nt->hlen + sizeof(struct iphdr));
 
-               mtu = clamp(dev->mtu, (unsigned int)ETH_MIN_MTU,
-                           (unsigned int)(max - sizeof(struct iphdr)));
+               mtu = clamp(dev->mtu, (unsigned int)ETH_MIN_MTU, max);
        }
 
        err = dev_set_mtu(dev, mtu);
index cc23f1c..8cd3224 100644 (file)
@@ -76,7 +76,7 @@ static bool rpfilter_mt(const struct sk_buff *skb, struct xt_action_param *par)
        flow.daddr = iph->saddr;
        flow.saddr = rpfilter_get_saddr(iph->daddr);
        flow.flowi4_mark = info->flags & XT_RPFILTER_VALID_MARK ? skb->mark : 0;
-       flow.flowi4_tos = RT_TOS(iph->tos);
+       flow.flowi4_tos = iph->tos & IPTOS_RT_MASK;
        flow.flowi4_scope = RT_SCOPE_UNIVERSE;
        flow.flowi4_oif = l3mdev_master_ifindex_rcu(xt_in(par));
 
index ed42d21..32545ec 100644 (file)
@@ -2937,6 +2937,7 @@ int tcp_disconnect(struct sock *sk, int flags)
 
        icsk->icsk_backoff = 0;
        icsk->icsk_probes_out = 0;
+       icsk->icsk_probes_tstamp = 0;
        icsk->icsk_rto = TCP_TIMEOUT_INIT;
        icsk->icsk_rto_min = TCP_RTO_MIN;
        icsk->icsk_delack_max = TCP_DELACK_MAX;
index c7e16b0..9b44caa 100644 (file)
@@ -2859,7 +2859,8 @@ static void tcp_identify_packet_loss(struct sock *sk, int *ack_flag)
        } else if (tcp_is_rack(sk)) {
                u32 prior_retrans = tp->retrans_out;
 
-               tcp_rack_mark_lost(sk);
+               if (tcp_rack_mark_lost(sk))
+                       *ack_flag &= ~FLAG_SET_XMIT_TIMER;
                if (prior_retrans > tp->retrans_out)
                        *ack_flag |= FLAG_LOST_RETRANS;
        }
@@ -3384,6 +3385,7 @@ static void tcp_ack_probe(struct sock *sk)
                return;
        if (!after(TCP_SKB_CB(head)->end_seq, tcp_wnd_end(tp))) {
                icsk->icsk_backoff = 0;
+               icsk->icsk_probes_tstamp = 0;
                inet_csk_clear_xmit_timer(sk, ICSK_TIME_PROBE0);
                /* Socket must be waked up by subsequent tcp_data_snd_check().
                 * This function is not for random using!
@@ -3391,8 +3393,8 @@ static void tcp_ack_probe(struct sock *sk)
        } else {
                unsigned long when = tcp_probe0_when(sk, TCP_RTO_MAX);
 
-               tcp_reset_xmit_timer(sk, ICSK_TIME_PROBE0,
-                                    when, TCP_RTO_MAX);
+               when = tcp_clamp_probe0_to_user_timeout(sk, when);
+               tcp_reset_xmit_timer(sk, ICSK_TIME_PROBE0, when, TCP_RTO_MAX);
        }
 }
 
@@ -3815,9 +3817,6 @@ static int tcp_ack(struct sock *sk, const struct sk_buff *skb, int flag)
 
        if (tp->tlp_high_seq)
                tcp_process_tlp_ack(sk, ack, flag);
-       /* If needed, reset TLP/RTO timer; RACK may later override this. */
-       if (flag & FLAG_SET_XMIT_TIMER)
-               tcp_set_xmit_timer(sk);
 
        if (tcp_ack_is_dubious(sk, flag)) {
                if (!(flag & (FLAG_SND_UNA_ADVANCED | FLAG_NOT_DUP))) {
@@ -3830,6 +3829,10 @@ static int tcp_ack(struct sock *sk, const struct sk_buff *skb, int flag)
                                      &rexmit);
        }
 
+       /* If needed, reset TLP/RTO timer when RACK doesn't set. */
+       if (flag & FLAG_SET_XMIT_TIMER)
+               tcp_set_xmit_timer(sk);
+
        if ((flag & FLAG_FORWARD_PROGRESS) || !(flag & FLAG_NOT_DUP))
                sk_dst_confirm(sk);
 
@@ -4396,10 +4399,9 @@ static void tcp_rcv_spurious_retrans(struct sock *sk, const struct sk_buff *skb)
         * The receiver remembers and reflects via DSACKs. Leverage the
         * DSACK state and change the txhash to re-route speculatively.
         */
-       if (TCP_SKB_CB(skb)->seq == tcp_sk(sk)->duplicate_sack[0].start_seq) {
-               sk_rethink_txhash(sk);
+       if (TCP_SKB_CB(skb)->seq == tcp_sk(sk)->duplicate_sack[0].start_seq &&
+           sk_rethink_txhash(sk))
                NET_INC_STATS(sock_net(sk), LINUX_MIB_TCPDUPLICATEDATAREHASH);
-       }
 }
 
 static void tcp_send_dupack(struct sock *sk, const struct sk_buff *skb)
index 58207c7..777306b 100644 (file)
@@ -1595,6 +1595,8 @@ struct sock *tcp_v4_syn_recv_sock(const struct sock *sk, struct sk_buff *skb,
                tcp_move_syn(newtp, req);
                ireq->ireq_opt = NULL;
        } else {
+               newinet->inet_opt = NULL;
+
                if (!req_unhash && found_dup_sk) {
                        /* This code path should only be executed in the
                         * syncookie case only
@@ -1602,8 +1604,6 @@ struct sock *tcp_v4_syn_recv_sock(const struct sock *sk, struct sk_buff *skb,
                        bh_unlock_sock(newsk);
                        sock_put(newsk);
                        newsk = NULL;
-               } else {
-                       newinet->inet_opt = NULL;
                }
        }
        return newsk;
@@ -1760,6 +1760,7 @@ int tcp_v4_early_demux(struct sk_buff *skb)
 bool tcp_add_backlog(struct sock *sk, struct sk_buff *skb)
 {
        u32 limit = READ_ONCE(sk->sk_rcvbuf) + READ_ONCE(sk->sk_sndbuf);
+       u32 tail_gso_size, tail_gso_segs;
        struct skb_shared_info *shinfo;
        const struct tcphdr *th;
        struct tcphdr *thtail;
@@ -1767,6 +1768,7 @@ bool tcp_add_backlog(struct sock *sk, struct sk_buff *skb)
        unsigned int hdrlen;
        bool fragstolen;
        u32 gso_segs;
+       u32 gso_size;
        int delta;
 
        /* In case all data was pulled from skb frags (in __pskb_pull_tail()),
@@ -1792,13 +1794,6 @@ bool tcp_add_backlog(struct sock *sk, struct sk_buff *skb)
         */
        th = (const struct tcphdr *)skb->data;
        hdrlen = th->doff * 4;
-       shinfo = skb_shinfo(skb);
-
-       if (!shinfo->gso_size)
-               shinfo->gso_size = skb->len - hdrlen;
-
-       if (!shinfo->gso_segs)
-               shinfo->gso_segs = 1;
 
        tail = sk->sk_backlog.tail;
        if (!tail)
@@ -1821,6 +1816,15 @@ bool tcp_add_backlog(struct sock *sk, struct sk_buff *skb)
                goto no_coalesce;
 
        __skb_pull(skb, hdrlen);
+
+       shinfo = skb_shinfo(skb);
+       gso_size = shinfo->gso_size ?: skb->len;
+       gso_segs = shinfo->gso_segs ?: 1;
+
+       shinfo = skb_shinfo(tail);
+       tail_gso_size = shinfo->gso_size ?: (tail->len - hdrlen);
+       tail_gso_segs = shinfo->gso_segs ?: 1;
+
        if (skb_try_coalesce(tail, skb, &fragstolen, &delta)) {
                TCP_SKB_CB(tail)->end_seq = TCP_SKB_CB(skb)->end_seq;
 
@@ -1847,11 +1851,8 @@ bool tcp_add_backlog(struct sock *sk, struct sk_buff *skb)
                }
 
                /* Not as strict as GRO. We only need to carry mss max value */
-               skb_shinfo(tail)->gso_size = max(shinfo->gso_size,
-                                                skb_shinfo(tail)->gso_size);
-
-               gso_segs = skb_shinfo(tail)->gso_segs + shinfo->gso_segs;
-               skb_shinfo(tail)->gso_segs = min_t(u32, gso_segs, 0xFFFF);
+               shinfo->gso_size = max(gso_size, tail_gso_size);
+               shinfo->gso_segs = min_t(u32, gso_segs + tail_gso_segs, 0xFFFF);
 
                sk->sk_backlog.len += delta;
                __NET_INC_STATS(sock_net(sk),
index f322e79..8478cf7 100644 (file)
@@ -4084,6 +4084,7 @@ void tcp_send_probe0(struct sock *sk)
                /* Cancel probe timer, if it is not required. */
                icsk->icsk_probes_out = 0;
                icsk->icsk_backoff = 0;
+               icsk->icsk_probes_tstamp = 0;
                return;
        }
 
@@ -4098,6 +4099,8 @@ void tcp_send_probe0(struct sock *sk)
                 */
                timeout = TCP_RESOURCE_PROBE_INTERVAL;
        }
+
+       timeout = tcp_clamp_probe0_to_user_timeout(sk, timeout);
        tcp_reset_xmit_timer(sk, ICSK_TIME_PROBE0, timeout, TCP_RTO_MAX);
 }
 
index 177307a..6f1b4ac 100644 (file)
@@ -96,13 +96,13 @@ static void tcp_rack_detect_loss(struct sock *sk, u32 *reo_timeout)
        }
 }
 
-void tcp_rack_mark_lost(struct sock *sk)
+bool tcp_rack_mark_lost(struct sock *sk)
 {
        struct tcp_sock *tp = tcp_sk(sk);
        u32 timeout;
 
        if (!tp->rack.advanced)
-               return;
+               return false;
 
        /* Reset the advanced flag to avoid unnecessary queue scanning */
        tp->rack.advanced = 0;
@@ -112,6 +112,7 @@ void tcp_rack_mark_lost(struct sock *sk)
                inet_csk_reset_xmit_timer(sk, ICSK_TIME_REO_TIMEOUT,
                                          timeout, inet_csk(sk)->icsk_rto);
        }
+       return !!timeout;
 }
 
 /* Record the most recently (re)sent time among the (s)acked packets
index 6c62b9e..4ef0807 100644 (file)
@@ -40,6 +40,24 @@ static u32 tcp_clamp_rto_to_user_timeout(const struct sock *sk)
        return min_t(u32, icsk->icsk_rto, msecs_to_jiffies(remaining));
 }
 
+u32 tcp_clamp_probe0_to_user_timeout(const struct sock *sk, u32 when)
+{
+       struct inet_connection_sock *icsk = inet_csk(sk);
+       u32 remaining;
+       s32 elapsed;
+
+       if (!icsk->icsk_user_timeout || !icsk->icsk_probes_tstamp)
+               return when;
+
+       elapsed = tcp_jiffies32 - icsk->icsk_probes_tstamp;
+       if (unlikely(elapsed < 0))
+               elapsed = 0;
+       remaining = msecs_to_jiffies(icsk->icsk_user_timeout) - elapsed;
+       remaining = max_t(u32, remaining, TCP_TIMEOUT_MIN);
+
+       return min_t(u32, remaining, when);
+}
+
 /**
  *  tcp_write_err() - close socket and save error info
  *  @sk:  The socket the error has appeared on.
@@ -219,14 +237,8 @@ static int tcp_write_timeout(struct sock *sk)
        int retry_until;
 
        if ((1 << sk->sk_state) & (TCPF_SYN_SENT | TCPF_SYN_RECV)) {
-               if (icsk->icsk_retransmits) {
-                       dst_negative_advice(sk);
-               } else {
-                       sk_rethink_txhash(sk);
-                       tp->timeout_rehash++;
-                       __NET_INC_STATS(sock_net(sk),
-                                       LINUX_MIB_TCPTIMEOUTREHASH);
-               }
+               if (icsk->icsk_retransmits)
+                       __dst_negative_advice(sk);
                retry_until = icsk->icsk_syn_retries ? : net->ipv4.sysctl_tcp_syn_retries;
                expired = icsk->icsk_retransmits >= retry_until;
        } else {
@@ -234,12 +246,7 @@ static int tcp_write_timeout(struct sock *sk)
                        /* Black hole detection */
                        tcp_mtu_probing(icsk, sk);
 
-                       dst_negative_advice(sk);
-               } else {
-                       sk_rethink_txhash(sk);
-                       tp->timeout_rehash++;
-                       __NET_INC_STATS(sock_net(sk),
-                                       LINUX_MIB_TCPTIMEOUTREHASH);
+                       __dst_negative_advice(sk);
                }
 
                retry_until = net->ipv4.sysctl_tcp_retries2;
@@ -270,6 +277,11 @@ static int tcp_write_timeout(struct sock *sk)
                return 1;
        }
 
+       if (sk_rethink_txhash(sk)) {
+               tp->timeout_rehash++;
+               __NET_INC_STATS(sock_net(sk), LINUX_MIB_TCPTIMEOUTREHASH);
+       }
+
        return 0;
 }
 
@@ -349,6 +361,7 @@ static void tcp_probe_timer(struct sock *sk)
 
        if (tp->packets_out || !skb) {
                icsk->icsk_probes_out = 0;
+               icsk->icsk_probes_tstamp = 0;
                return;
        }
 
@@ -360,13 +373,12 @@ static void tcp_probe_timer(struct sock *sk)
         * corresponding system limit. We also implement similar policy when
         * we use RTO to probe window in tcp_retransmit_timer().
         */
-       if (icsk->icsk_user_timeout) {
-               u32 elapsed = tcp_model_timeout(sk, icsk->icsk_probes_out,
-                                               tcp_probe0_base(sk));
-
-               if (elapsed >= icsk->icsk_user_timeout)
-                       goto abort;
-       }
+       if (!icsk->icsk_probes_tstamp)
+               icsk->icsk_probes_tstamp = tcp_jiffies32;
+       else if (icsk->icsk_user_timeout &&
+                (s32)(tcp_jiffies32 - icsk->icsk_probes_tstamp) >=
+                msecs_to_jiffies(icsk->icsk_user_timeout))
+               goto abort;
 
        max_probes = sock_net(sk)->ipv4.sysctl_tcp_retries2;
        if (sock_flag(sk, SOCK_DEAD)) {
index 7103b0a..69ea765 100644 (file)
@@ -2555,7 +2555,8 @@ int udp_v4_early_demux(struct sk_buff *skb)
                 */
                if (!inet_sk(sk)->inet_daddr && in_dev)
                        return ip_mc_validate_source(skb, iph->daddr,
-                                                    iph->saddr, iph->tos,
+                                                    iph->saddr,
+                                                    iph->tos & IPTOS_RT_MASK,
                                                     skb->dev, in_dev, &itag);
        }
        return 0;
index ff39e94..cfc8726 100644 (file)
@@ -187,8 +187,67 @@ out_unlock:
 }
 EXPORT_SYMBOL(skb_udp_tunnel_segment);
 
+static void __udpv4_gso_segment_csum(struct sk_buff *seg,
+                                    __be32 *oldip, __be32 *newip,
+                                    __be16 *oldport, __be16 *newport)
+{
+       struct udphdr *uh;
+       struct iphdr *iph;
+
+       if (*oldip == *newip && *oldport == *newport)
+               return;
+
+       uh = udp_hdr(seg);
+       iph = ip_hdr(seg);
+
+       if (uh->check) {
+               inet_proto_csum_replace4(&uh->check, seg, *oldip, *newip,
+                                        true);
+               inet_proto_csum_replace2(&uh->check, seg, *oldport, *newport,
+                                        false);
+               if (!uh->check)
+                       uh->check = CSUM_MANGLED_0;
+       }
+       *oldport = *newport;
+
+       csum_replace4(&iph->check, *oldip, *newip);
+       *oldip = *newip;
+}
+
+static struct sk_buff *__udpv4_gso_segment_list_csum(struct sk_buff *segs)
+{
+       struct sk_buff *seg;
+       struct udphdr *uh, *uh2;
+       struct iphdr *iph, *iph2;
+
+       seg = segs;
+       uh = udp_hdr(seg);
+       iph = ip_hdr(seg);
+
+       if ((udp_hdr(seg)->dest == udp_hdr(seg->next)->dest) &&
+           (udp_hdr(seg)->source == udp_hdr(seg->next)->source) &&
+           (ip_hdr(seg)->daddr == ip_hdr(seg->next)->daddr) &&
+           (ip_hdr(seg)->saddr == ip_hdr(seg->next)->saddr))
+               return segs;
+
+       while ((seg = seg->next)) {
+               uh2 = udp_hdr(seg);
+               iph2 = ip_hdr(seg);
+
+               __udpv4_gso_segment_csum(seg,
+                                        &iph2->saddr, &iph->saddr,
+                                        &uh2->source, &uh->source);
+               __udpv4_gso_segment_csum(seg,
+                                        &iph2->daddr, &iph->daddr,
+                                        &uh2->dest, &uh->dest);
+       }
+
+       return segs;
+}
+
 static struct sk_buff *__udp_gso_segment_list(struct sk_buff *skb,
-                                             netdev_features_t features)
+                                             netdev_features_t features,
+                                             bool is_ipv6)
 {
        unsigned int mss = skb_shinfo(skb)->gso_size;
 
@@ -198,11 +257,11 @@ static struct sk_buff *__udp_gso_segment_list(struct sk_buff *skb,
 
        udp_hdr(skb)->len = htons(sizeof(struct udphdr) + mss);
 
-       return skb;
+       return is_ipv6 ? skb : __udpv4_gso_segment_list_csum(skb);
 }
 
 struct sk_buff *__udp_gso_segment(struct sk_buff *gso_skb,
-                                 netdev_features_t features)
+                                 netdev_features_t features, bool is_ipv6)
 {
        struct sock *sk = gso_skb->sk;
        unsigned int sum_truesize = 0;
@@ -214,7 +273,7 @@ struct sk_buff *__udp_gso_segment(struct sk_buff *gso_skb,
        __be16 newlen;
 
        if (skb_shinfo(gso_skb)->gso_type & SKB_GSO_FRAGLIST)
-               return __udp_gso_segment_list(gso_skb, features);
+               return __udp_gso_segment_list(gso_skb, features, is_ipv6);
 
        mss = skb_shinfo(gso_skb)->gso_size;
        if (gso_skb->len <= sizeof(*uh) + mss)
@@ -328,7 +387,7 @@ static struct sk_buff *udp4_ufo_fragment(struct sk_buff *skb,
                goto out;
 
        if (skb_shinfo(skb)->gso_type & SKB_GSO_UDP_L4)
-               return __udp_gso_segment(skb, features);
+               return __udp_gso_segment(skb, features, false);
 
        mss = skb_shinfo(skb)->gso_size;
        if (unlikely(skb->len <= mss))
index eff2cac..9edc5bb 100644 (file)
@@ -2467,8 +2467,9 @@ static void addrconf_add_mroute(struct net_device *dev)
                .fc_ifindex = dev->ifindex,
                .fc_dst_len = 8,
                .fc_flags = RTF_UP,
-               .fc_type = RTN_UNICAST,
+               .fc_type = RTN_MULTICAST,
                .fc_nlinfo.nl_net = dev_net(dev),
+               .fc_protocol = RTPROT_KERNEL,
        };
 
        ipv6_addr_set(&cfg.fc_dst, htonl(0xFF000000), 0, 0, 0);
index c7bd7b1..faa823c 100644 (file)
@@ -42,7 +42,7 @@ static struct sk_buff *udp6_ufo_fragment(struct sk_buff *skb,
                        goto out;
 
                if (skb_shinfo(skb)->gso_type & SKB_GSO_UDP_L4)
-                       return __udp_gso_segment(skb, features);
+                       return __udp_gso_segment(skb, features, true);
 
                mss = skb_shinfo(skb)->gso_size;
                if (unlikely(skb->len <= mss))
index c12dbc5..ef9b4ac 100644 (file)
@@ -2902,7 +2902,7 @@ static int count_ah_combs(const struct xfrm_tmpl *t)
                        break;
                if (!aalg->pfkey_supported)
                        continue;
-               if (aalg_tmpl_set(t, aalg) && aalg->available)
+               if (aalg_tmpl_set(t, aalg))
                        sz += sizeof(struct sadb_comb);
        }
        return sz + sizeof(struct sadb_prop);
@@ -2920,7 +2920,7 @@ static int count_esp_combs(const struct xfrm_tmpl *t)
                if (!ealg->pfkey_supported)
                        continue;
 
-               if (!(ealg_tmpl_set(t, ealg) && ealg->available))
+               if (!(ealg_tmpl_set(t, ealg)))
                        continue;
 
                for (k = 1; ; k++) {
@@ -2931,7 +2931,7 @@ static int count_esp_combs(const struct xfrm_tmpl *t)
                        if (!aalg->pfkey_supported)
                                continue;
 
-                       if (aalg_tmpl_set(t, aalg) && aalg->available)
+                       if (aalg_tmpl_set(t, aalg))
                                sz += sizeof(struct sadb_comb);
                }
        }
index 4096188..0511bbe 100644 (file)
@@ -122,6 +122,8 @@ static struct lapb_cb *lapb_create_cb(void)
 
        timer_setup(&lapb->t1timer, NULL, 0);
        timer_setup(&lapb->t2timer, NULL, 0);
+       lapb->t1timer_stop = true;
+       lapb->t2timer_stop = true;
 
        lapb->t1      = LAPB_DEFAULT_T1;
        lapb->t2      = LAPB_DEFAULT_T2;
@@ -129,6 +131,8 @@ static struct lapb_cb *lapb_create_cb(void)
        lapb->mode    = LAPB_DEFAULT_MODE;
        lapb->window  = LAPB_DEFAULT_WINDOW;
        lapb->state   = LAPB_STATE_0;
+
+       spin_lock_init(&lapb->lock);
        refcount_set(&lapb->refcnt, 1);
 out:
        return lapb;
@@ -178,11 +182,23 @@ int lapb_unregister(struct net_device *dev)
                goto out;
        lapb_put(lapb);
 
+       /* Wait for other refs to "lapb" to drop */
+       while (refcount_read(&lapb->refcnt) > 2)
+               usleep_range(1, 10);
+
+       spin_lock_bh(&lapb->lock);
+
        lapb_stop_t1timer(lapb);
        lapb_stop_t2timer(lapb);
 
        lapb_clear_queues(lapb);
 
+       spin_unlock_bh(&lapb->lock);
+
+       /* Wait for running timers to stop */
+       del_timer_sync(&lapb->t1timer);
+       del_timer_sync(&lapb->t2timer);
+
        __lapb_remove_cb(lapb);
 
        lapb_put(lapb);
@@ -201,6 +217,8 @@ int lapb_getparms(struct net_device *dev, struct lapb_parms_struct *parms)
        if (!lapb)
                goto out;
 
+       spin_lock_bh(&lapb->lock);
+
        parms->t1      = lapb->t1 / HZ;
        parms->t2      = lapb->t2 / HZ;
        parms->n2      = lapb->n2;
@@ -219,6 +237,7 @@ int lapb_getparms(struct net_device *dev, struct lapb_parms_struct *parms)
        else
                parms->t2timer = (lapb->t2timer.expires - jiffies) / HZ;
 
+       spin_unlock_bh(&lapb->lock);
        lapb_put(lapb);
        rc = LAPB_OK;
 out:
@@ -234,6 +253,8 @@ int lapb_setparms(struct net_device *dev, struct lapb_parms_struct *parms)
        if (!lapb)
                goto out;
 
+       spin_lock_bh(&lapb->lock);
+
        rc = LAPB_INVALUE;
        if (parms->t1 < 1 || parms->t2 < 1 || parms->n2 < 1)
                goto out_put;
@@ -256,6 +277,7 @@ int lapb_setparms(struct net_device *dev, struct lapb_parms_struct *parms)
 
        rc = LAPB_OK;
 out_put:
+       spin_unlock_bh(&lapb->lock);
        lapb_put(lapb);
 out:
        return rc;
@@ -270,6 +292,8 @@ int lapb_connect_request(struct net_device *dev)
        if (!lapb)
                goto out;
 
+       spin_lock_bh(&lapb->lock);
+
        rc = LAPB_OK;
        if (lapb->state == LAPB_STATE_1)
                goto out_put;
@@ -285,24 +309,18 @@ int lapb_connect_request(struct net_device *dev)
 
        rc = LAPB_OK;
 out_put:
+       spin_unlock_bh(&lapb->lock);
        lapb_put(lapb);
 out:
        return rc;
 }
 EXPORT_SYMBOL(lapb_connect_request);
 
-int lapb_disconnect_request(struct net_device *dev)
+static int __lapb_disconnect_request(struct lapb_cb *lapb)
 {
-       struct lapb_cb *lapb = lapb_devtostruct(dev);
-       int rc = LAPB_BADTOKEN;
-
-       if (!lapb)
-               goto out;
-
        switch (lapb->state) {
        case LAPB_STATE_0:
-               rc = LAPB_NOTCONNECTED;
-               goto out_put;
+               return LAPB_NOTCONNECTED;
 
        case LAPB_STATE_1:
                lapb_dbg(1, "(%p) S1 TX DISC(1)\n", lapb->dev);
@@ -310,12 +328,10 @@ int lapb_disconnect_request(struct net_device *dev)
                lapb_send_control(lapb, LAPB_DISC, LAPB_POLLON, LAPB_COMMAND);
                lapb->state = LAPB_STATE_0;
                lapb_start_t1timer(lapb);
-               rc = LAPB_NOTCONNECTED;
-               goto out_put;
+               return LAPB_NOTCONNECTED;
 
        case LAPB_STATE_2:
-               rc = LAPB_OK;
-               goto out_put;
+               return LAPB_OK;
        }
 
        lapb_clear_queues(lapb);
@@ -328,8 +344,22 @@ int lapb_disconnect_request(struct net_device *dev)
        lapb_dbg(1, "(%p) S3 DISC(1)\n", lapb->dev);
        lapb_dbg(0, "(%p) S3 -> S2\n", lapb->dev);
 
-       rc = LAPB_OK;
-out_put:
+       return LAPB_OK;
+}
+
+int lapb_disconnect_request(struct net_device *dev)
+{
+       struct lapb_cb *lapb = lapb_devtostruct(dev);
+       int rc = LAPB_BADTOKEN;
+
+       if (!lapb)
+               goto out;
+
+       spin_lock_bh(&lapb->lock);
+
+       rc = __lapb_disconnect_request(lapb);
+
+       spin_unlock_bh(&lapb->lock);
        lapb_put(lapb);
 out:
        return rc;
@@ -344,6 +374,8 @@ int lapb_data_request(struct net_device *dev, struct sk_buff *skb)
        if (!lapb)
                goto out;
 
+       spin_lock_bh(&lapb->lock);
+
        rc = LAPB_NOTCONNECTED;
        if (lapb->state != LAPB_STATE_3 && lapb->state != LAPB_STATE_4)
                goto out_put;
@@ -352,6 +384,7 @@ int lapb_data_request(struct net_device *dev, struct sk_buff *skb)
        lapb_kick(lapb);
        rc = LAPB_OK;
 out_put:
+       spin_unlock_bh(&lapb->lock);
        lapb_put(lapb);
 out:
        return rc;
@@ -364,7 +397,9 @@ int lapb_data_received(struct net_device *dev, struct sk_buff *skb)
        int rc = LAPB_BADTOKEN;
 
        if (lapb) {
+               spin_lock_bh(&lapb->lock);
                lapb_data_input(lapb, skb);
+               spin_unlock_bh(&lapb->lock);
                lapb_put(lapb);
                rc = LAPB_OK;
        }
@@ -435,6 +470,8 @@ static int lapb_device_event(struct notifier_block *this, unsigned long event,
        if (!lapb)
                return NOTIFY_DONE;
 
+       spin_lock_bh(&lapb->lock);
+
        switch (event) {
        case NETDEV_UP:
                lapb_dbg(0, "(%p) Interface up: %s\n", dev, dev->name);
@@ -454,7 +491,7 @@ static int lapb_device_event(struct notifier_block *this, unsigned long event,
                break;
        case NETDEV_GOING_DOWN:
                if (netif_carrier_ok(dev))
-                       lapb_disconnect_request(dev);
+                       __lapb_disconnect_request(lapb);
                break;
        case NETDEV_DOWN:
                lapb_dbg(0, "(%p) Interface down: %s\n", dev, dev->name);
@@ -489,6 +526,7 @@ static int lapb_device_event(struct notifier_block *this, unsigned long event,
                break;
        }
 
+       spin_unlock_bh(&lapb->lock);
        lapb_put(lapb);
        return NOTIFY_DONE;
 }
index 7a4d071..a966d29 100644 (file)
@@ -82,7 +82,8 @@ void lapb_kick(struct lapb_cb *lapb)
                skb = skb_dequeue(&lapb->write_queue);
 
                do {
-                       if ((skbn = skb_clone(skb, GFP_ATOMIC)) == NULL) {
+                       skbn = skb_copy(skb, GFP_ATOMIC);
+                       if (!skbn) {
                                skb_queue_head(&lapb->write_queue, skb);
                                break;
                        }
index baa247f..0230b27 100644 (file)
@@ -40,6 +40,7 @@ void lapb_start_t1timer(struct lapb_cb *lapb)
        lapb->t1timer.function = lapb_t1timer_expiry;
        lapb->t1timer.expires  = jiffies + lapb->t1;
 
+       lapb->t1timer_stop = false;
        add_timer(&lapb->t1timer);
 }
 
@@ -50,16 +51,19 @@ void lapb_start_t2timer(struct lapb_cb *lapb)
        lapb->t2timer.function = lapb_t2timer_expiry;
        lapb->t2timer.expires  = jiffies + lapb->t2;
 
+       lapb->t2timer_stop = false;
        add_timer(&lapb->t2timer);
 }
 
 void lapb_stop_t1timer(struct lapb_cb *lapb)
 {
+       lapb->t1timer_stop = true;
        del_timer(&lapb->t1timer);
 }
 
 void lapb_stop_t2timer(struct lapb_cb *lapb)
 {
+       lapb->t2timer_stop = true;
        del_timer(&lapb->t2timer);
 }
 
@@ -72,16 +76,31 @@ static void lapb_t2timer_expiry(struct timer_list *t)
 {
        struct lapb_cb *lapb = from_timer(lapb, t, t2timer);
 
+       spin_lock_bh(&lapb->lock);
+       if (timer_pending(&lapb->t2timer)) /* A new timer has been set up */
+               goto out;
+       if (lapb->t2timer_stop) /* The timer has been stopped */
+               goto out;
+
        if (lapb->condition & LAPB_ACK_PENDING_CONDITION) {
                lapb->condition &= ~LAPB_ACK_PENDING_CONDITION;
                lapb_timeout_response(lapb);
        }
+
+out:
+       spin_unlock_bh(&lapb->lock);
 }
 
 static void lapb_t1timer_expiry(struct timer_list *t)
 {
        struct lapb_cb *lapb = from_timer(lapb, t, t1timer);
 
+       spin_lock_bh(&lapb->lock);
+       if (timer_pending(&lapb->t1timer)) /* A new timer has been set up */
+               goto out;
+       if (lapb->t1timer_stop) /* The timer has been stopped */
+               goto out;
+
        switch (lapb->state) {
 
                /*
@@ -108,7 +127,7 @@ static void lapb_t1timer_expiry(struct timer_list *t)
                                lapb->state = LAPB_STATE_0;
                                lapb_disconnect_indication(lapb, LAPB_TIMEDOUT);
                                lapb_dbg(0, "(%p) S1 -> S0\n", lapb->dev);
-                               return;
+                               goto out;
                        } else {
                                lapb->n2count++;
                                if (lapb->mode & LAPB_EXTENDED) {
@@ -132,7 +151,7 @@ static void lapb_t1timer_expiry(struct timer_list *t)
                                lapb->state = LAPB_STATE_0;
                                lapb_disconnect_confirmation(lapb, LAPB_TIMEDOUT);
                                lapb_dbg(0, "(%p) S2 -> S0\n", lapb->dev);
-                               return;
+                               goto out;
                        } else {
                                lapb->n2count++;
                                lapb_dbg(1, "(%p) S2 TX DISC(1)\n", lapb->dev);
@@ -150,7 +169,7 @@ static void lapb_t1timer_expiry(struct timer_list *t)
                                lapb_stop_t2timer(lapb);
                                lapb_disconnect_indication(lapb, LAPB_TIMEDOUT);
                                lapb_dbg(0, "(%p) S3 -> S0\n", lapb->dev);
-                               return;
+                               goto out;
                        } else {
                                lapb->n2count++;
                                lapb_requeue_frames(lapb);
@@ -167,7 +186,7 @@ static void lapb_t1timer_expiry(struct timer_list *t)
                                lapb->state = LAPB_STATE_0;
                                lapb_disconnect_indication(lapb, LAPB_TIMEDOUT);
                                lapb_dbg(0, "(%p) S4 -> S0\n", lapb->dev);
-                               return;
+                               goto out;
                        } else {
                                lapb->n2count++;
                                lapb_transmit_frmr(lapb);
@@ -176,4 +195,7 @@ static void lapb_t1timer_expiry(struct timer_list *t)
        }
 
        lapb_start_t1timer(lapb);
+
+out:
+       spin_unlock_bh(&lapb->lock);
 }
index 48f144f..9e723d9 100644 (file)
@@ -120,18 +120,17 @@ static ssize_t aqm_write(struct file *file,
 {
        struct ieee80211_local *local = file->private_data;
        char buf[100];
-       size_t len;
 
-       if (count > sizeof(buf))
+       if (count >= sizeof(buf))
                return -EINVAL;
 
        if (copy_from_user(buf, user_buf, count))
                return -EFAULT;
 
-       buf[sizeof(buf) - 1] = '\0';
-       len = strlen(buf);
-       if (len > 0 && buf[len-1] == '\n')
-               buf[len-1] = 0;
+       if (count && buf[count - 1] == '\n')
+               buf[count - 1] = '\0';
+       else
+               buf[count] = '\0';
 
        if (sscanf(buf, "fq_limit %u", &local->fq.limit) == 1)
                return count;
@@ -177,18 +176,17 @@ static ssize_t airtime_flags_write(struct file *file,
 {
        struct ieee80211_local *local = file->private_data;
        char buf[16];
-       size_t len;
 
-       if (count > sizeof(buf))
+       if (count >= sizeof(buf))
                return -EINVAL;
 
        if (copy_from_user(buf, user_buf, count))
                return -EFAULT;
 
-       buf[sizeof(buf) - 1] = 0;
-       len = strlen(buf);
-       if (len > 0 && buf[len - 1] == '\n')
-               buf[len - 1] = 0;
+       if (count && buf[count - 1] == '\n')
+               buf[count - 1] = '\0';
+       else
+               buf[count] = '\0';
 
        if (kstrtou16(buf, 0, &local->airtime_flags))
                return -EINVAL;
@@ -237,20 +235,19 @@ static ssize_t aql_txq_limit_write(struct file *file,
 {
        struct ieee80211_local *local = file->private_data;
        char buf[100];
-       size_t len;
        u32 ac, q_limit_low, q_limit_high, q_limit_low_old, q_limit_high_old;
        struct sta_info *sta;
 
-       if (count > sizeof(buf))
+       if (count >= sizeof(buf))
                return -EINVAL;
 
        if (copy_from_user(buf, user_buf, count))
                return -EFAULT;
 
-       buf[sizeof(buf) - 1] = 0;
-       len = strlen(buf);
-       if (len > 0 && buf[len - 1] == '\n')
-               buf[len - 1] = 0;
+       if (count && buf[count - 1] == '\n')
+               buf[count - 1] = '\0';
+       else
+               buf[count] = '\0';
 
        if (sscanf(buf, "%u %u %u", &ac, &q_limit_low, &q_limit_high) != 3)
                return -EINVAL;
@@ -306,18 +303,17 @@ static ssize_t force_tx_status_write(struct file *file,
 {
        struct ieee80211_local *local = file->private_data;
        char buf[3];
-       size_t len;
 
-       if (count > sizeof(buf))
+       if (count >= sizeof(buf))
                return -EINVAL;
 
        if (copy_from_user(buf, user_buf, count))
                return -EFAULT;
 
-       buf[sizeof(buf) - 1] = '\0';
-       len = strlen(buf);
-       if (len > 0 && buf[len - 1] == '\n')
-               buf[len - 1] = 0;
+       if (count && buf[count - 1] == '\n')
+               buf[count - 1] = '\0';
+       else
+               buf[count] = '\0';
 
        if (buf[0] == '0' && buf[1] == '\0')
                local->force_tx_status = 0;
index c9a8a24..48322e4 100644 (file)
@@ -125,8 +125,11 @@ int drv_sta_state(struct ieee80211_local *local,
        } else if (old_state == IEEE80211_STA_AUTH &&
                   new_state == IEEE80211_STA_ASSOC) {
                ret = drv_sta_add(local, sdata, &sta->sta);
-               if (ret == 0)
+               if (ret == 0) {
                        sta->uploaded = true;
+                       if (rcu_access_pointer(sta->sta.rates))
+                               drv_sta_rate_tbl_update(local, sdata, &sta->sta);
+               }
        } else if (old_state == IEEE80211_STA_ASSOC &&
                   new_state == IEEE80211_STA_AUTH) {
                drv_sta_remove(local, sdata, &sta->sta);
index 8bf9c0e..8e281c2 100644 (file)
@@ -1078,6 +1078,7 @@ enum queue_stop_reason {
        IEEE80211_QUEUE_STOP_REASON_FLUSH,
        IEEE80211_QUEUE_STOP_REASON_TDLS_TEARDOWN,
        IEEE80211_QUEUE_STOP_REASON_RESERVE_TID,
+       IEEE80211_QUEUE_STOP_REASON_IFTYPE_CHANGE,
 
        IEEE80211_QUEUE_STOP_REASONS,
 };
index 3b9ec4e..b31417f 100644 (file)
@@ -1617,6 +1617,10 @@ static int ieee80211_runtime_change_iftype(struct ieee80211_sub_if_data *sdata,
        if (ret)
                return ret;
 
+       ieee80211_stop_vif_queues(local, sdata,
+                                 IEEE80211_QUEUE_STOP_REASON_IFTYPE_CHANGE);
+       synchronize_net();
+
        ieee80211_do_stop(sdata, false);
 
        ieee80211_teardown_sdata(sdata);
@@ -1639,6 +1643,8 @@ static int ieee80211_runtime_change_iftype(struct ieee80211_sub_if_data *sdata,
        err = ieee80211_do_open(&sdata->wdev, false);
        WARN(err, "type change: do_open returned %d", err);
 
+       ieee80211_wake_vif_queues(local, sdata,
+                                 IEEE80211_QUEUE_STOP_REASON_IFTYPE_CHANGE);
        return ret;
 }
 
index 4592720..63652c3 100644 (file)
@@ -960,7 +960,8 @@ int rate_control_set_rates(struct ieee80211_hw *hw,
        if (old)
                kfree_rcu(old, rcu_head);
 
-       drv_sta_rate_tbl_update(hw_to_local(hw), sta->sdata, pubsta);
+       if (sta->uploaded)
+               drv_sta_rate_tbl_update(hw_to_local(hw), sta->sdata, pubsta);
 
        ieee80211_sta_set_expected_throughput(pubsta, sta_get_expected_throughput(sta));
 
index 13b9bcc..972895e 100644 (file)
@@ -4176,6 +4176,8 @@ void ieee80211_check_fast_rx(struct sta_info *sta)
 
        rcu_read_lock();
        key = rcu_dereference(sta->ptk[sta->ptk_idx]);
+       if (!key)
+               key = rcu_dereference(sdata->default_unicast_key);
        if (key) {
                switch (key->conf.cipher) {
                case WLAN_CIPHER_SUITE_TKIP:
index ae1cb2c..76747bf 100644 (file)
@@ -133,16 +133,20 @@ int ieee80211_parse_ch_switch_ie(struct ieee80211_sub_if_data *sdata,
        }
 
        if (wide_bw_chansw_ie) {
+               u8 new_seg1 = wide_bw_chansw_ie->new_center_freq_seg1;
                struct ieee80211_vht_operation vht_oper = {
                        .chan_width =
                                wide_bw_chansw_ie->new_channel_width,
                        .center_freq_seg0_idx =
                                wide_bw_chansw_ie->new_center_freq_seg0,
-                       .center_freq_seg1_idx =
-                               wide_bw_chansw_ie->new_center_freq_seg1,
+                       .center_freq_seg1_idx = new_seg1,
                        /* .basic_mcs_set doesn't matter */
                };
-               struct ieee80211_ht_operation ht_oper = {};
+               struct ieee80211_ht_operation ht_oper = {
+                       .operation_mode =
+                               cpu_to_le16(new_seg1 <<
+                                           IEEE80211_HT_OP_MODE_CCFS2_SHIFT),
+               };
 
                /* default, for the case of IEEE80211_VHT_CHANWIDTH_USE_HT,
                 * to the previously parsed chandef
index 6422da6..ebb3228 100644 (file)
@@ -649,7 +649,7 @@ ieee80211_tx_h_select_key(struct ieee80211_tx_data *tx)
                if (!skip_hw && tx->key &&
                    tx->key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE)
                        info->control.hw_key = &tx->key->conf;
-       } else if (!ieee80211_is_mgmt(hdr->frame_control) && tx->sta &&
+       } else if (ieee80211_is_data_present(hdr->frame_control) && tx->sta &&
                   test_sta_flag(tx->sta, WLAN_STA_USES_ENCRYPTION)) {
                return TX_DROP;
        }
@@ -3809,7 +3809,7 @@ void __ieee80211_schedule_txq(struct ieee80211_hw *hw,
                 * get immediately moved to the back of the list on the next
                 * call to ieee80211_next_txq().
                 */
-               if (txqi->txq.sta &&
+               if (txqi->txq.sta && local->airtime_flags &&
                    wiphy_ext_feature_isset(local->hw.wiphy,
                                            NL80211_EXT_FEATURE_AIRTIME_FAIRNESS))
                        list_add(&txqi->schedule_order,
@@ -4251,7 +4251,6 @@ netdev_tx_t ieee80211_subif_start_xmit_8023(struct sk_buff *skb,
        struct ethhdr *ehdr = (struct ethhdr *)skb->data;
        struct ieee80211_key *key;
        struct sta_info *sta;
-       bool offload = true;
 
        if (unlikely(skb->len < ETH_HLEN)) {
                kfree_skb(skb);
@@ -4267,18 +4266,22 @@ netdev_tx_t ieee80211_subif_start_xmit_8023(struct sk_buff *skb,
 
        if (unlikely(IS_ERR_OR_NULL(sta) || !sta->uploaded ||
            !test_sta_flag(sta, WLAN_STA_AUTHORIZED) ||
-               sdata->control_port_protocol == ehdr->h_proto))
-               offload = false;
-       else if ((key = rcu_dereference(sta->ptk[sta->ptk_idx])) &&
-                (!(key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE) ||
-                 key->conf.cipher == WLAN_CIPHER_SUITE_TKIP))
-               offload = false;
-
-       if (offload)
-               ieee80211_8023_xmit(sdata, dev, sta, key, skb);
-       else
-               ieee80211_subif_start_xmit(skb, dev);
+           sdata->control_port_protocol == ehdr->h_proto))
+               goto skip_offload;
+
+       key = rcu_dereference(sta->ptk[sta->ptk_idx]);
+       if (!key)
+               key = rcu_dereference(sdata->default_unicast_key);
+
+       if (key && (!(key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE) ||
+                   key->conf.cipher == WLAN_CIPHER_SUITE_TKIP))
+               goto skip_offload;
+
+       ieee80211_8023_xmit(sdata, dev, sta, key, skb);
+       goto out;
 
+skip_offload:
+       ieee80211_subif_start_xmit(skb, dev);
 out:
        rcu_read_unlock();
 
index 15c467f..8d3aa97 100644 (file)
@@ -5235,9 +5235,8 @@ static void nf_tables_set_elem_destroy(const struct nft_ctx *ctx,
        kfree(elem);
 }
 
-static int nft_set_elem_expr_clone(const struct nft_ctx *ctx,
-                                  struct nft_set *set,
-                                  struct nft_expr *expr_array[])
+int nft_set_elem_expr_clone(const struct nft_ctx *ctx, struct nft_set *set,
+                           struct nft_expr *expr_array[])
 {
        struct nft_expr *expr;
        int err, i, k;
index 0b053f7..d164ef9 100644 (file)
@@ -295,6 +295,12 @@ static int nft_dynset_init(const struct nft_ctx *ctx,
                        err = -EOPNOTSUPP;
                        goto err_expr_free;
                }
+       } else if (set->num_exprs > 0) {
+               err = nft_set_elem_expr_clone(ctx, set, priv->expr_array);
+               if (err < 0)
+                       return err;
+
+               priv->num_exprs = set->num_exprs;
        }
 
        nft_set_ext_prepare(&priv->tmpl);
@@ -306,8 +312,10 @@ static int nft_dynset_init(const struct nft_ctx *ctx,
                nft_dynset_ext_add_expr(priv);
 
        if (set->flags & NFT_SET_TIMEOUT) {
-               if (timeout || set->timeout)
+               if (timeout || set->timeout) {
+                       nft_set_ext_add(&priv->tmpl, NFT_SET_EXT_TIMEOUT);
                        nft_set_ext_add(&priv->tmpl, NFT_SET_EXT_EXPIRATION);
+               }
        }
 
        priv->timeout = timeout;
@@ -376,22 +384,25 @@ static int nft_dynset_dump(struct sk_buff *skb, const struct nft_expr *expr)
                         nf_jiffies64_to_msecs(priv->timeout),
                         NFTA_DYNSET_PAD))
                goto nla_put_failure;
-       if (priv->num_exprs == 1) {
-               if (nft_expr_dump(skb, NFTA_DYNSET_EXPR, priv->expr_array[0]))
-                       goto nla_put_failure;
-       } else if (priv->num_exprs > 1) {
-               struct nlattr *nest;
-
-               nest = nla_nest_start_noflag(skb, NFTA_DYNSET_EXPRESSIONS);
-               if (!nest)
-                       goto nla_put_failure;
-
-               for (i = 0; i < priv->num_exprs; i++) {
-                       if (nft_expr_dump(skb, NFTA_LIST_ELEM,
-                                         priv->expr_array[i]))
+       if (priv->set->num_exprs == 0) {
+               if (priv->num_exprs == 1) {
+                       if (nft_expr_dump(skb, NFTA_DYNSET_EXPR,
+                                         priv->expr_array[0]))
                                goto nla_put_failure;
+               } else if (priv->num_exprs > 1) {
+                       struct nlattr *nest;
+
+                       nest = nla_nest_start_noflag(skb, NFTA_DYNSET_EXPRESSIONS);
+                       if (!nest)
+                               goto nla_put_failure;
+
+                       for (i = 0; i < priv->num_exprs; i++) {
+                               if (nft_expr_dump(skb, NFTA_LIST_ELEM,
+                                                 priv->expr_array[i]))
+                                       goto nla_put_failure;
+                       }
+                       nla_nest_end(skb, nest);
                }
-               nla_nest_end(skb, nest);
        }
        if (nla_put_be32(skb, NFTA_DYNSET_FLAGS, htonl(flags)))
                goto nla_put_failure;
index e64727e..02a1f13 100644 (file)
@@ -508,7 +508,7 @@ static int nci_open_device(struct nci_dev *ndev)
                };
                unsigned long opt = 0;
 
-               if (!(ndev->nci_ver & NCI_VER_2_MASK))
+               if (ndev->nci_ver & NCI_VER_2_MASK)
                        opt = (unsigned long)&nci_init_v2_cmd;
 
                rc = __nci_request(ndev, nci_init_req, opt,
index 573b38a..e161ef2 100644 (file)
@@ -852,6 +852,7 @@ static int nfc_genl_stop_poll(struct sk_buff *skb, struct genl_info *info)
 
        if (!dev->polling) {
                device_unlock(&dev->dev);
+               nfc_put_device(dev);
                return -EINVAL;
        }
 
index 955c195..9c7eb84 100644 (file)
@@ -105,7 +105,7 @@ static int rawsock_connect(struct socket *sock, struct sockaddr *_addr,
        if (addr->target_idx > dev->target_next_idx - 1 ||
            addr->target_idx < dev->target_next_idx - dev->n_targets) {
                rc = -EINVAL;
-               goto error;
+               goto put_dev;
        }
 
        rc = nfc_activate_target(dev, addr->target_idx, addr->nfc_protocol);
index 1d0afb1..6f1a50d 100644 (file)
@@ -565,6 +565,9 @@ int rds_rdma_extra_size(struct rds_rdma_args *args,
        if (args->nr_local == 0)
                return -EINVAL;
 
+       if (args->nr_local > UIO_MAXIOV)
+               return -EMSGSIZE;
+
        iov->iov = kcalloc(args->nr_local,
                           sizeof(struct rds_iovec),
                           GFP_KERNEL);
index 0a2f481..41671af 100644 (file)
@@ -990,7 +990,7 @@ static int __init af_rxrpc_init(void)
                goto error_security;
        }
 
-       ret = register_pernet_subsys(&rxrpc_net_ops);
+       ret = register_pernet_device(&rxrpc_net_ops);
        if (ret)
                goto error_pernet;
 
@@ -1035,7 +1035,7 @@ error_key_type:
 error_sock:
        proto_unregister(&rxrpc_proto);
 error_proto:
-       unregister_pernet_subsys(&rxrpc_net_ops);
+       unregister_pernet_device(&rxrpc_net_ops);
 error_pernet:
        rxrpc_exit_security();
 error_security:
@@ -1057,7 +1057,7 @@ static void __exit af_rxrpc_exit(void)
        unregister_key_type(&key_type_rxrpc);
        sock_unregister(PF_RXRPC);
        proto_unregister(&rxrpc_proto);
-       unregister_pernet_subsys(&rxrpc_net_ops);
+       unregister_pernet_device(&rxrpc_net_ops);
        ASSERTCMP(atomic_read(&rxrpc_n_tx_skbs), ==, 0);
        ASSERTCMP(atomic_read(&rxrpc_n_rx_skbs), ==, 0);
 
index 382add7..1ae90fb 100644 (file)
@@ -197,6 +197,7 @@ void rxrpc_discard_prealloc(struct rxrpc_sock *rx)
        tail = b->peer_backlog_tail;
        while (CIRC_CNT(head, tail, size) > 0) {
                struct rxrpc_peer *peer = b->peer_backlog[tail];
+               rxrpc_put_local(peer->local);
                kfree(peer);
                tail = (tail + 1) & (size - 1);
        }
index 1319986..84f9325 100644 (file)
@@ -1272,6 +1272,10 @@ static int fl_set_enc_opt(struct nlattr **tb, struct fl_flow_key *key,
 
                nla_opt_msk = nla_data(tb[TCA_FLOWER_KEY_ENC_OPTS_MASK]);
                msk_depth = nla_len(tb[TCA_FLOWER_KEY_ENC_OPTS_MASK]);
+               if (!nla_ok(nla_opt_msk, msk_depth)) {
+                       NL_SET_ERR_MSG(extack, "Invalid nested attribute for masks");
+                       return -EINVAL;
+               }
        }
 
        nla_for_each_attr(nla_opt_key, nla_enc_key,
@@ -1307,9 +1311,6 @@ static int fl_set_enc_opt(struct nlattr **tb, struct fl_flow_key *key,
                                NL_SET_ERR_MSG(extack, "Key and mask miss aligned");
                                return -EINVAL;
                        }
-
-                       if (msk_depth)
-                               nla_opt_msk = nla_next(nla_opt_msk, &msk_depth);
                        break;
                case TCA_FLOWER_KEY_ENC_OPTS_VXLAN:
                        if (key->enc_opts.dst_opt_type) {
@@ -1340,9 +1341,6 @@ static int fl_set_enc_opt(struct nlattr **tb, struct fl_flow_key *key,
                                NL_SET_ERR_MSG(extack, "Key and mask miss aligned");
                                return -EINVAL;
                        }
-
-                       if (msk_depth)
-                               nla_opt_msk = nla_next(nla_opt_msk, &msk_depth);
                        break;
                case TCA_FLOWER_KEY_ENC_OPTS_ERSPAN:
                        if (key->enc_opts.dst_opt_type) {
@@ -1373,14 +1371,20 @@ static int fl_set_enc_opt(struct nlattr **tb, struct fl_flow_key *key,
                                NL_SET_ERR_MSG(extack, "Key and mask miss aligned");
                                return -EINVAL;
                        }
-
-                       if (msk_depth)
-                               nla_opt_msk = nla_next(nla_opt_msk, &msk_depth);
                        break;
                default:
                        NL_SET_ERR_MSG(extack, "Unknown tunnel option type");
                        return -EINVAL;
                }
+
+               if (!msk_depth)
+                       continue;
+
+               if (!nla_ok(nla_opt_msk, msk_depth)) {
+                       NL_SET_ERR_MSG(extack, "A mask attribute is invalid");
+                       return -EINVAL;
+               }
+               nla_opt_msk = nla_next(nla_opt_msk, &msk_depth);
        }
 
        return 0;
index 78bec34..c4007b9 100644 (file)
@@ -366,9 +366,13 @@ tcindex_set_parms(struct net *net, struct tcf_proto *tp, unsigned long base,
        if (tb[TCA_TCINDEX_MASK])
                cp->mask = nla_get_u16(tb[TCA_TCINDEX_MASK]);
 
-       if (tb[TCA_TCINDEX_SHIFT])
+       if (tb[TCA_TCINDEX_SHIFT]) {
                cp->shift = nla_get_u32(tb[TCA_TCINDEX_SHIFT]);
-
+               if (cp->shift > 16) {
+                       err = -EINVAL;
+                       goto errout;
+               }
+       }
        if (!cp->hash) {
                /* Hash not specified, use perfect hash if the upper limit
                 * of the hashing index is below the threshold.
index 51cb553..6fe4e5c 100644 (file)
@@ -412,7 +412,8 @@ struct qdisc_rate_table *qdisc_get_rtab(struct tc_ratespec *r,
 {
        struct qdisc_rate_table *rtab;
 
-       if (tab == NULL || r->rate == 0 || r->cell_log == 0 ||
+       if (tab == NULL || r->rate == 0 ||
+           r->cell_log == 0 || r->cell_log >= 32 ||
            nla_len(tab) != TC_RTAB_SIZE) {
                NL_SET_ERR_MSG(extack, "Invalid rate table parameters for searching");
                return NULL;
index 4ecc2a9..5f42aa5 100644 (file)
@@ -29,6 +29,7 @@
 #include <linux/uaccess.h>
 #include <linux/hashtable.h>
 
+#include "auth_gss_internal.h"
 #include "../netns.h"
 
 #include <trace/events/rpcgss.h>
@@ -125,35 +126,6 @@ gss_cred_set_ctx(struct rpc_cred *cred, struct gss_cl_ctx *ctx)
        clear_bit(RPCAUTH_CRED_NEW, &cred->cr_flags);
 }
 
-static const void *
-simple_get_bytes(const void *p, const void *end, void *res, size_t len)
-{
-       const void *q = (const void *)((const char *)p + len);
-       if (unlikely(q > end || q < p))
-               return ERR_PTR(-EFAULT);
-       memcpy(res, p, len);
-       return q;
-}
-
-static inline const void *
-simple_get_netobj(const void *p, const void *end, struct xdr_netobj *dest)
-{
-       const void *q;
-       unsigned int len;
-
-       p = simple_get_bytes(p, end, &len, sizeof(len));
-       if (IS_ERR(p))
-               return p;
-       q = (const void *)((const char *)p + len);
-       if (unlikely(q > end || q < p))
-               return ERR_PTR(-EFAULT);
-       dest->data = kmemdup(p, len, GFP_NOFS);
-       if (unlikely(dest->data == NULL))
-               return ERR_PTR(-ENOMEM);
-       dest->len = len;
-       return q;
-}
-
 static struct gss_cl_ctx *
 gss_cred_get_ctx(struct rpc_cred *cred)
 {
diff --git a/net/sunrpc/auth_gss/auth_gss_internal.h b/net/sunrpc/auth_gss/auth_gss_internal.h
new file mode 100644 (file)
index 0000000..f6d9631
--- /dev/null
@@ -0,0 +1,45 @@
+// SPDX-License-Identifier: BSD-3-Clause
+/*
+ * linux/net/sunrpc/auth_gss/auth_gss_internal.h
+ *
+ * Internal definitions for RPCSEC_GSS client authentication
+ *
+ * Copyright (c) 2000 The Regents of the University of Michigan.
+ * All rights reserved.
+ *
+ */
+#include <linux/err.h>
+#include <linux/string.h>
+#include <linux/sunrpc/xdr.h>
+
+static inline const void *
+simple_get_bytes(const void *p, const void *end, void *res, size_t len)
+{
+       const void *q = (const void *)((const char *)p + len);
+       if (unlikely(q > end || q < p))
+               return ERR_PTR(-EFAULT);
+       memcpy(res, p, len);
+       return q;
+}
+
+static inline const void *
+simple_get_netobj(const void *p, const void *end, struct xdr_netobj *dest)
+{
+       const void *q;
+       unsigned int len;
+
+       p = simple_get_bytes(p, end, &len, sizeof(len));
+       if (IS_ERR(p))
+               return p;
+       q = (const void *)((const char *)p + len);
+       if (unlikely(q > end || q < p))
+               return ERR_PTR(-EFAULT);
+       if (len) {
+               dest->data = kmemdup(p, len, GFP_NOFS);
+               if (unlikely(dest->data == NULL))
+                       return ERR_PTR(-ENOMEM);
+       } else
+               dest->data = NULL;
+       dest->len = len;
+       return q;
+}
index ae9acf3..1c092b0 100644 (file)
@@ -21,6 +21,8 @@
 #include <linux/sunrpc/xdr.h>
 #include <linux/sunrpc/gss_krb5_enctypes.h>
 
+#include "auth_gss_internal.h"
+
 #if IS_ENABLED(CONFIG_SUNRPC_DEBUG)
 # define RPCDBG_FACILITY       RPCDBG_AUTH
 #endif
@@ -143,35 +145,6 @@ get_gss_krb5_enctype(int etype)
        return NULL;
 }
 
-static const void *
-simple_get_bytes(const void *p, const void *end, void *res, int len)
-{
-       const void *q = (const void *)((const char *)p + len);
-       if (unlikely(q > end || q < p))
-               return ERR_PTR(-EFAULT);
-       memcpy(res, p, len);
-       return q;
-}
-
-static const void *
-simple_get_netobj(const void *p, const void *end, struct xdr_netobj *res)
-{
-       const void *q;
-       unsigned int len;
-
-       p = simple_get_bytes(p, end, &len, sizeof(len));
-       if (IS_ERR(p))
-               return p;
-       q = (const void *)((const char *)p + len);
-       if (unlikely(q > end || q < p))
-               return ERR_PTR(-EFAULT);
-       res->data = kmemdup(p, len, GFP_NOFS);
-       if (unlikely(res->data == NULL))
-               return ERR_PTR(-ENOMEM);
-       res->len = len;
-       return q;
-}
-
 static inline const void *
 get_key(const void *p, const void *end,
        struct krb5_ctx *ctx, struct crypto_sync_skcipher **res)
index 5fb9164..dcc50ae 100644 (file)
@@ -857,6 +857,7 @@ int svc_recv(struct svc_rqst *rqstp, long timeout)
        err = -EAGAIN;
        if (len <= 0)
                goto out_release;
+       trace_svc_xdr_recvfrom(&rqstp->rq_arg);
 
        clear_bit(XPT_OLD, &xprt->xpt_flags);
 
@@ -866,7 +867,6 @@ int svc_recv(struct svc_rqst *rqstp, long timeout)
 
        if (serv->sv_stats)
                serv->sv_stats->netcnt++;
-       trace_svc_xdr_recvfrom(rqstp, &rqstp->rq_arg);
        return len;
 out_release:
        rqstp->rq_res.len = 0;
@@ -904,7 +904,7 @@ int svc_send(struct svc_rqst *rqstp)
        xb->len = xb->head[0].iov_len +
                xb->page_len +
                xb->tail[0].iov_len;
-       trace_svc_xdr_sendto(rqstp, xb);
+       trace_svc_xdr_sendto(rqstp->rq_xid, xb);
        trace_svc_stats_latency(rqstp);
 
        len = xprt->xpt_ops->xpo_sendto(rqstp);
index c9766d0..5a809c6 100644 (file)
@@ -1113,14 +1113,15 @@ static int svc_tcp_sendmsg(struct socket *sock, struct msghdr *msg,
                unsigned int offset, len, remaining;
                struct bio_vec *bvec;
 
-               bvec = xdr->bvec;
-               offset = xdr->page_base;
+               bvec = xdr->bvec + (xdr->page_base >> PAGE_SHIFT);
+               offset = offset_in_page(xdr->page_base);
                remaining = xdr->page_len;
                flags = MSG_MORE | MSG_SENDPAGE_NOTLAST;
                while (remaining > 0) {
                        if (remaining <= PAGE_SIZE && tail->iov_len == 0)
                                flags = 0;
-                       len = min(remaining, bvec->bv_len);
+
+                       len = min(remaining, bvec->bv_len - offset);
                        ret = kernel_sendpage(sock, bvec->bv_page,
                                              bvec->bv_offset + offset,
                                              len, flags);
index 23d8685..2c1ffc9 100644 (file)
@@ -460,10 +460,11 @@ static int __switchdev_handle_port_obj_add(struct net_device *dev,
        extack = switchdev_notifier_info_to_extack(&port_obj_info->info);
 
        if (check_cb(dev)) {
-               /* This flag is only checked if the return value is success. */
-               port_obj_info->handled = true;
-               return add_cb(dev, port_obj_info->obj, port_obj_info->trans,
-                             extack);
+               err = add_cb(dev, port_obj_info->obj, port_obj_info->trans,
+                            extack);
+               if (err != -EOPNOTSUPP)
+                       port_obj_info->handled = true;
+               return err;
        }
 
        /* Switch ports might be stacked under e.g. a LAG. Ignore the
@@ -515,9 +516,10 @@ static int __switchdev_handle_port_obj_del(struct net_device *dev,
        int err = -EOPNOTSUPP;
 
        if (check_cb(dev)) {
-               /* This flag is only checked if the return value is success. */
-               port_obj_info->handled = true;
-               return del_cb(dev, port_obj_info->obj);
+               err = del_cb(dev, port_obj_info->obj);
+               if (err != -EOPNOTSUPP)
+                       port_obj_info->handled = true;
+               return err;
        }
 
        /* Switch ports might be stacked under e.g. a LAG. Ignore the
@@ -568,9 +570,10 @@ static int __switchdev_handle_port_attr_set(struct net_device *dev,
        int err = -EOPNOTSUPP;
 
        if (check_cb(dev)) {
-               port_attr_info->handled = true;
-               return set_cb(dev, port_attr_info->attr,
-                             port_attr_info->trans);
+               err = set_cb(dev, port_attr_info->attr, port_attr_info->trans);
+               if (err != -EOPNOTSUPP)
+                       port_attr_info->handled = true;
+               return err;
        }
 
        /* Switch ports might be stacked under e.g. a LAG. Ignore the
index b12d3a3..6894f21 100644 (file)
@@ -1014,9 +1014,12 @@ static __poll_t vsock_poll(struct file *file, struct socket *sock,
                        mask |= EPOLLOUT | EPOLLWRNORM | EPOLLWRBAND;
 
        } else if (sock->type == SOCK_STREAM) {
-               const struct vsock_transport *transport = vsk->transport;
+               const struct vsock_transport *transport;
+
                lock_sock(sk);
 
+               transport = vsk->transport;
+
                /* Listening sockets that have connections in their accept
                 * queue can be read.
                 */
@@ -1099,10 +1102,11 @@ static int vsock_dgram_sendmsg(struct socket *sock, struct msghdr *msg,
        err = 0;
        sk = sock->sk;
        vsk = vsock_sk(sk);
-       transport = vsk->transport;
 
        lock_sock(sk);
 
+       transport = vsk->transport;
+
        err = vsock_auto_bind(vsk);
        if (err)
                goto out;
@@ -1561,10 +1565,11 @@ static int vsock_stream_setsockopt(struct socket *sock,
        err = 0;
        sk = sock->sk;
        vsk = vsock_sk(sk);
-       transport = vsk->transport;
 
        lock_sock(sk);
 
+       transport = vsk->transport;
+
        switch (optname) {
        case SO_VM_SOCKETS_BUFFER_SIZE:
                COPY_IN(val);
@@ -1697,7 +1702,6 @@ static int vsock_stream_sendmsg(struct socket *sock, struct msghdr *msg,
 
        sk = sock->sk;
        vsk = vsock_sk(sk);
-       transport = vsk->transport;
        total_written = 0;
        err = 0;
 
@@ -1706,6 +1710,8 @@ static int vsock_stream_sendmsg(struct socket *sock, struct msghdr *msg,
 
        lock_sock(sk);
 
+       transport = vsk->transport;
+
        /* Callers should not provide a destination with stream sockets. */
        if (msg->msg_namelen) {
                err = sk->sk_state == TCP_ESTABLISHED ? -EISCONN : -EOPNOTSUPP;
@@ -1840,11 +1846,12 @@ vsock_stream_recvmsg(struct socket *sock, struct msghdr *msg, size_t len,
 
        sk = sock->sk;
        vsk = vsock_sk(sk);
-       transport = vsk->transport;
        err = 0;
 
        lock_sock(sk);
 
+       transport = vsk->transport;
+
        if (!transport || sk->sk_state != TCP_ESTABLISHED) {
                /* Recvmsg is supposed to return 0 if a peer performs an
                 * orderly shutdown. Differentiate between that case and when a
index bb72447..8114bba 100644 (file)
@@ -5,7 +5,7 @@
  * Copyright 2008-2011 Luis R. Rodriguez <mcgrof@qca.qualcomm.com>
  * Copyright 2013-2014  Intel Mobile Communications GmbH
  * Copyright      2017  Intel Deutschland GmbH
- * Copyright (C) 2018 - 2019 Intel Corporation
+ * Copyright (C) 2018 - 2021 Intel Corporation
  *
  * Permission to use, copy, modify, and/or distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
@@ -139,6 +139,11 @@ static const struct ieee80211_regdomain *get_cfg80211_regdom(void)
        return rcu_dereference_rtnl(cfg80211_regdomain);
 }
 
+/*
+ * Returns the regulatory domain associated with the wiphy.
+ *
+ * Requires either RTNL or RCU protection
+ */
 const struct ieee80211_regdomain *get_wiphy_regdom(struct wiphy *wiphy)
 {
        return rcu_dereference_rtnl(wiphy->regd);
@@ -2571,9 +2576,13 @@ void wiphy_apply_custom_regulatory(struct wiphy *wiphy,
        if (IS_ERR(new_regd))
                return;
 
+       rtnl_lock();
+
        tmp = get_wiphy_regdom(wiphy);
        rcu_assign_pointer(wiphy->regd, new_regd);
        rcu_free_regdom(tmp);
+
+       rtnl_unlock();
 }
 EXPORT_SYMBOL(wiphy_apply_custom_regulatory);
 
index 69102fd..76a80a4 100644 (file)
@@ -896,8 +896,9 @@ out:
 int call_commit_handler(struct net_device *dev)
 {
 #ifdef CONFIG_WIRELESS_EXT
-       if ((netif_running(dev)) &&
-          (dev->wireless_handlers->standard[0] != NULL))
+       if (netif_running(dev) &&
+           dev->wireless_handlers &&
+           dev->wireless_handlers->standard[0])
                /* Call the commit handler on the driver */
                return dev->wireless_handlers->standard[0](dev, NULL,
                                                           NULL, NULL);
index 8037b04..4a83117 100644 (file)
@@ -108,9 +108,9 @@ EXPORT_SYMBOL(xsk_get_pool_from_qid);
 
 void xsk_clear_pool_at_qid(struct net_device *dev, u16 queue_id)
 {
-       if (queue_id < dev->real_num_rx_queues)
+       if (queue_id < dev->num_rx_queues)
                dev->_rx[queue_id].pool = NULL;
-       if (queue_id < dev->real_num_tx_queues)
+       if (queue_id < dev->num_tx_queues)
                dev->_tx[queue_id].pool = NULL;
 }
 
index be6351e..1158cd0 100644 (file)
@@ -660,7 +660,7 @@ resume:
                /* only the first xfrm gets the encap type */
                encap_type = 0;
 
-               if (async && x->repl->recheck(x, skb, seq)) {
+               if (x->repl->recheck(x, skb, seq)) {
                        XFRM_INC_STATS(net, LINUX_MIB_XFRMINSTATESEQERROR);
                        goto drop_unlock;
                }
index d622c25..b74f28c 100644 (file)
@@ -793,15 +793,22 @@ static int xfrm_policy_addr_delta(const xfrm_address_t *a,
                                  const xfrm_address_t *b,
                                  u8 prefixlen, u16 family)
 {
+       u32 ma, mb, mask;
        unsigned int pdw, pbi;
        int delta = 0;
 
        switch (family) {
        case AF_INET:
-               if (sizeof(long) == 4 && prefixlen == 0)
-                       return ntohl(a->a4) - ntohl(b->a4);
-               return (ntohl(a->a4) & ((~0UL << (32 - prefixlen)))) -
-                      (ntohl(b->a4) & ((~0UL << (32 - prefixlen))));
+               if (prefixlen == 0)
+                       return 0;
+               mask = ~0U << (32 - prefixlen);
+               ma = ntohl(a->a4) & mask;
+               mb = ntohl(b->a4) & mask;
+               if (ma < mb)
+                       delta = -1;
+               else if (ma > mb)
+                       delta = 1;
+               break;
        case AF_INET6:
                pdw = prefixlen >> 5;
                pbi = prefixlen & 0x1f;
@@ -812,10 +819,13 @@ static int xfrm_policy_addr_delta(const xfrm_address_t *a,
                                return delta;
                }
                if (pbi) {
-                       u32 mask = ~0u << (32 - pbi);
-
-                       delta = (ntohl(a->a6[pdw]) & mask) -
-                               (ntohl(b->a6[pdw]) & mask);
+                       mask = ~0U << (32 - pbi);
+                       ma = ntohl(a->a6[pdw]) & mask;
+                       mb = ntohl(b->a6[pdw]) & mask;
+                       if (ma < mb)
+                               delta = -1;
+                       else if (ma > mb)
+                               delta = 1;
                }
                break;
        default:
@@ -3078,8 +3088,8 @@ struct dst_entry *xfrm_lookup_with_ifid(struct net *net,
                xflo.flags = flags;
 
                /* To accelerate a bit...  */
-               if ((dst_orig->flags & DST_NOXFRM) ||
-                   !net->xfrm.policy_count[XFRM_POLICY_OUT])
+               if (!if_id && ((dst_orig->flags & DST_NOXFRM) ||
+                              !net->xfrm.policy_count[XFRM_POLICY_OUT]))
                        goto nopol;
 
                xdst = xfrm_bundle_lookup(net, fl, family, dir, &xflo, if_id);
index b5418ec..9de3c03 100644 (file)
@@ -3,6 +3,9 @@
 # scripts contains sources for various helper programs used throughout
 # the kernel for the build process.
 
+CRYPTO_LIBS = $(shell pkg-config --libs libcrypto 2> /dev/null || echo -lcrypto)
+CRYPTO_CFLAGS = $(shell pkg-config --cflags libcrypto 2> /dev/null)
+
 hostprogs-always-$(CONFIG_BUILD_BIN2C)                 += bin2c
 hostprogs-always-$(CONFIG_KALLSYMS)                    += kallsyms
 hostprogs-always-$(BUILD_C_RECORDMCOUNT)               += recordmcount
@@ -14,8 +17,9 @@ hostprogs-always-$(CONFIG_SYSTEM_EXTRA_CERTIFICATE)   += insert-sys-cert
 
 HOSTCFLAGS_sorttable.o = -I$(srctree)/tools/include
 HOSTCFLAGS_asn1_compiler.o = -I$(srctree)/include
-HOSTLDLIBS_sign-file = -lcrypto
-HOSTLDLIBS_extract-cert = -lcrypto
+HOSTLDLIBS_sign-file = $(CRYPTO_LIBS)
+HOSTCFLAGS_extract-cert.o = $(CRYPTO_CFLAGS)
+HOSTLDLIBS_extract-cert = $(CRYPTO_LIBS)
 
 ifdef CONFIG_UNWINDER_ORC
 ifeq ($(ARCH),x86_64)
index 652e954..dcd8d87 100755 (executable)
@@ -1,4 +1,4 @@
-#!/usr/bin/env python
+#!/usr/bin/env python3
 #
 # Copyright 2004 Matt Mackall <mpm@selenic.com>
 #
index 92e888e..1afe3af 100755 (executable)
@@ -3390,13 +3390,6 @@ sub process {
                        }
                }
 
-# discourage the use of boolean for type definition attributes of Kconfig options
-               if ($realfile =~ /Kconfig/ &&
-                   $line =~ /^\+\s*\bboolean\b/) {
-                       WARN("CONFIG_TYPE_BOOLEAN",
-                            "Use of boolean is deprecated, please use bool instead.\n" . $herecurr);
-               }
-
                if (($realfile =~ /Makefile.*/ || $realfile =~ /Kbuild.*/) &&
                    ($line =~ /\+(EXTRA_[A-Z]+FLAGS).*/)) {
                        my $flag = $1;
index 1996370..8ddb5d0 100755 (executable)
@@ -1,4 +1,4 @@
-#!/usr/bin/env python
+#!/usr/bin/env python3
 # SPDX-License-Identifier: GPL-2.0
 #
 # Copyright (C) Google LLC, 2018
index fa7655c..f754415 100755 (executable)
@@ -1,4 +1,4 @@
-#!/usr/bin/env python
+#!/usr/bin/env python3
 # SPDX-License-Identifier: GPL-2.0
 #
 # Copyright (C) Google LLC, 2020
index 627eba5..d5da5fa 100755 (executable)
@@ -1,4 +1,4 @@
-#!/usr/bin/env python
+#!/usr/bin/env python3
 # SPDX-License-Identifier: GPL-2.0
 #
 # diffconfig - a tool to compare .config files.
index 33487e9..5c113ca 100755 (executable)
@@ -75,16 +75,12 @@ if arg_contain -S "$@"; then
        fi
 fi
 
-# For scripts/gcc-plugin.sh
+# To set GCC_PLUGINS
 if arg_contain -print-file-name=plugin "$@"; then
        plugin_dir=$(mktemp -d)
 
-       sed -n 's/.*#include "\(.*\)"/\1/p' $(dirname $0)/../gcc-plugins/gcc-common.h |
-       while read header
-       do
-               mkdir -p $plugin_dir/include/$(dirname $header)
-               touch $plugin_dir/include/$header
-       done
+       mkdir -p $plugin_dir/include
+       touch $plugin_dir/include/plugin-version.h
 
        echo $plugin_dir
        exit 0
index 0fdb31a..48d141e 100755 (executable)
@@ -1,4 +1,4 @@
-#!/usr/bin/env python
+#!/usr/bin/env python3
 # SPDX-License-Identifier: GPL-2.0+
 #
 # This determines how many parallel tasks "make" is expecting, as it is
index 7ecd2cc..54ad86d 100644 (file)
@@ -112,6 +112,12 @@ static bool is_ignored_symbol(const char *name, char type)
                "__crc_",               /* modversions */
                "__efistub_",           /* arm64 EFI stub namespace */
                "__kvm_nvhe_",          /* arm64 non-VHE KVM namespace */
+               "__AArch64ADRPThunk_",  /* arm64 lld */
+               "__ARMV5PILongThunk_",  /* arm lld */
+               "__ARMV7PILongThunk_",
+               "__ThumbV7PILongThunk_",
+               "__LA25Thunk_",         /* mips lld */
+               "__microLA25Thunk_",
                NULL
        };
 
index fcd4acd..b520e40 100755 (executable)
@@ -35,7 +35,7 @@ fi
 
 # As a final fallback before giving up, check if $HOSTCC knows of a default
 # ncurses installation (e.g. from a vendor-specific sysroot).
-if echo '#include <ncurses.h>' | "${HOSTCC}" -E - >/dev/null 2>&1; then
+if echo '#include <ncurses.h>' | ${HOSTCC} -E - >/dev/null 2>&1; then
        echo cflags=\"-D_GNU_SOURCE\"
        echo libs=\"-lncurses\"
        exit 0
index bacc111..26c1cb7 100644 (file)
@@ -371,10 +371,11 @@ int cap_inode_getsecurity(struct inode *inode, const char *name, void **buffer,
 {
        int size, ret;
        kuid_t kroot;
+       u32 nsmagic, magic;
        uid_t root, mappedroot;
        char *tmpbuf = NULL;
        struct vfs_cap_data *cap;
-       struct vfs_ns_cap_data *nscap;
+       struct vfs_ns_cap_data *nscap = NULL;
        struct dentry *dentry;
        struct user_namespace *fs_ns;
 
@@ -396,46 +397,61 @@ int cap_inode_getsecurity(struct inode *inode, const char *name, void **buffer,
        fs_ns = inode->i_sb->s_user_ns;
        cap = (struct vfs_cap_data *) tmpbuf;
        if (is_v2header((size_t) ret, cap)) {
-               /* If this is sizeof(vfs_cap_data) then we're ok with the
-                * on-disk value, so return that.  */
-               if (alloc)
-                       *buffer = tmpbuf;
-               else
-                       kfree(tmpbuf);
-               return ret;
-       } else if (!is_v3header((size_t) ret, cap)) {
-               kfree(tmpbuf);
-               return -EINVAL;
+               root = 0;
+       } else if (is_v3header((size_t) ret, cap)) {
+               nscap = (struct vfs_ns_cap_data *) tmpbuf;
+               root = le32_to_cpu(nscap->rootid);
+       } else {
+               size = -EINVAL;
+               goto out_free;
        }
 
-       nscap = (struct vfs_ns_cap_data *) tmpbuf;
-       root = le32_to_cpu(nscap->rootid);
        kroot = make_kuid(fs_ns, root);
 
        /* If the root kuid maps to a valid uid in current ns, then return
         * this as a nscap. */
        mappedroot = from_kuid(current_user_ns(), kroot);
        if (mappedroot != (uid_t)-1 && mappedroot != (uid_t)0) {
+               size = sizeof(struct vfs_ns_cap_data);
                if (alloc) {
-                       *buffer = tmpbuf;
+                       if (!nscap) {
+                               /* v2 -> v3 conversion */
+                               nscap = kzalloc(size, GFP_ATOMIC);
+                               if (!nscap) {
+                                       size = -ENOMEM;
+                                       goto out_free;
+                               }
+                               nsmagic = VFS_CAP_REVISION_3;
+                               magic = le32_to_cpu(cap->magic_etc);
+                               if (magic & VFS_CAP_FLAGS_EFFECTIVE)
+                                       nsmagic |= VFS_CAP_FLAGS_EFFECTIVE;
+                               memcpy(&nscap->data, &cap->data, sizeof(__le32) * 2 * VFS_CAP_U32);
+                               nscap->magic_etc = cpu_to_le32(nsmagic);
+                       } else {
+                               /* use allocated v3 buffer */
+                               tmpbuf = NULL;
+                       }
                        nscap->rootid = cpu_to_le32(mappedroot);
-               } else
-                       kfree(tmpbuf);
-               return size;
+                       *buffer = nscap;
+               }
+               goto out_free;
        }
 
        if (!rootid_owns_currentns(kroot)) {
-               kfree(tmpbuf);
-               return -EOPNOTSUPP;
+               size = -EOVERFLOW;
+               goto out_free;
        }
 
        /* This comes from a parent namespace.  Return as a v2 capability */
        size = sizeof(struct vfs_cap_data);
        if (alloc) {
-               *buffer = kmalloc(size, GFP_ATOMIC);
-               if (*buffer) {
-                       struct vfs_cap_data *cap = *buffer;
-                       __le32 nsmagic, magic;
+               if (nscap) {
+                       /* v3 -> v2 conversion */
+                       cap = kzalloc(size, GFP_ATOMIC);
+                       if (!cap) {
+                               size = -ENOMEM;
+                               goto out_free;
+                       }
                        magic = VFS_CAP_REVISION_2;
                        nsmagic = le32_to_cpu(nscap->magic_etc);
                        if (nsmagic & VFS_CAP_FLAGS_EFFECTIVE)
@@ -443,9 +459,12 @@ int cap_inode_getsecurity(struct inode *inode, const char *name, void **buffer,
                        memcpy(&cap->data, &nscap->data, sizeof(__le32) * 2 * VFS_CAP_U32);
                        cap->magic_etc = cpu_to_le32(magic);
                } else {
-                       size = -ENOMEM;
+                       /* use unconverted v2 */
+                       tmpbuf = NULL;
                }
+               *buffer = cap;
        }
+out_free:
        kfree(tmpbuf);
        return size;
 }
index 4d0e8fe..1fc2fa0 100644 (file)
@@ -125,6 +125,8 @@ void snd_dmaengine_pcm_set_config_from_dai_data(
        }
 
        slave_config->slave_id = dma_data->slave_id;
+       slave_config->peripheral_config = dma_data->peripheral_config;
+       slave_config->peripheral_size = dma_data->peripheral_size;
 }
 EXPORT_SYMBOL_GPL(snd_dmaengine_pcm_set_config_from_dai_data);
 
index 71a6fe8..640494f 100644 (file)
@@ -37,6 +37,23 @@ config SND_SOC_COMPRESS
 config SND_SOC_TOPOLOGY
        bool
 
+config SND_SOC_TOPOLOGY_KUNIT_TESTS
+       tristate "KUnit tests for SoC topology"
+       depends on KUNIT
+       depends on SND_SOC_TOPOLOGY
+       default KUNIT_ALL_TESTS
+       help
+         If you want to perform tests on ALSA SoC topology support say Y here.
+
+         This builds a module which can be later manually loaded to run KUNIT
+         test cases against soc-topology.c API. This should be primarily used
+         by developers to test their changes to ASoC.
+
+         Do note that it creates fake playback devices which do not interact
+         well with userspace. When running tests one may want to disable
+         userspace applications such as pulseaudio, to prevent unnecessary
+         problems.
+
 config SND_SOC_ACPI
        tristate
 
@@ -62,7 +79,6 @@ source "sound/soc/qcom/Kconfig"
 source "sound/soc/rockchip/Kconfig"
 source "sound/soc/samsung/Kconfig"
 source "sound/soc/sh/Kconfig"
-source "sound/soc/sirf/Kconfig"
 source "sound/soc/sof/Kconfig"
 source "sound/soc/spear/Kconfig"
 source "sound/soc/sprd/Kconfig"
@@ -71,12 +87,10 @@ source "sound/soc/stm/Kconfig"
 source "sound/soc/sunxi/Kconfig"
 source "sound/soc/tegra/Kconfig"
 source "sound/soc/ti/Kconfig"
-source "sound/soc/txx9/Kconfig"
 source "sound/soc/uniphier/Kconfig"
 source "sound/soc/ux500/Kconfig"
 source "sound/soc/xilinx/Kconfig"
 source "sound/soc/xtensa/Kconfig"
-source "sound/soc/zte/Kconfig"
 
 # Supported codecs
 source "sound/soc/codecs/Kconfig"
index ddbac3a..f56ad99 100644 (file)
@@ -7,6 +7,11 @@ ifneq ($(CONFIG_SND_SOC_TOPOLOGY),)
 snd-soc-core-objs += soc-topology.o
 endif
 
+ifneq ($(CONFIG_SND_SOC_TOPOLOGY_KUNIT_TESTS),)
+# snd-soc-test-objs := soc-topology-test.o
+obj-$(CONFIG_SND_SOC_TOPOLOGY_KUNIT_TESTS) := soc-topology-test.o
+endif
+
 ifneq ($(CONFIG_SND_SOC_GENERIC_DMAENGINE_PCM),)
 snd-soc-core-objs += soc-generic-dmaengine-pcm.o
 endif
@@ -45,7 +50,6 @@ obj-$(CONFIG_SND_SOC) += qcom/
 obj-$(CONFIG_SND_SOC)  += rockchip/
 obj-$(CONFIG_SND_SOC)  += samsung/
 obj-$(CONFIG_SND_SOC)  += sh/
-obj-$(CONFIG_SND_SOC)  += sirf/
 obj-$(CONFIG_SND_SOC)  += sof/
 obj-$(CONFIG_SND_SOC)  += spear/
 obj-$(CONFIG_SND_SOC)  += sprd/
@@ -54,9 +58,7 @@ obj-$(CONFIG_SND_SOC) += stm/
 obj-$(CONFIG_SND_SOC)  += sunxi/
 obj-$(CONFIG_SND_SOC)  += tegra/
 obj-$(CONFIG_SND_SOC)  += ti/
-obj-$(CONFIG_SND_SOC)  += txx9/
 obj-$(CONFIG_SND_SOC)  += uniphier/
 obj-$(CONFIG_SND_SOC)  += ux500/
 obj-$(CONFIG_SND_SOC)  += xilinx/
 obj-$(CONFIG_SND_SOC)  += xtensa/
-obj-$(CONFIG_SND_SOC)  += zte/
index 8c4dc82..aa08213 100644 (file)
@@ -156,7 +156,7 @@ static const struct snd_soc_dai_ops axi_i2s_dai_ops = {
 static struct snd_soc_dai_driver axi_i2s_dai = {
        .probe = axi_i2s_dai_probe,
        .ops = &axi_i2s_dai_ops,
-       .symmetric_rates = 1,
+       .symmetric_rate = 1,
 };
 
 static const struct snd_soc_component_driver axi_i2s_component = {
index 1a4e8ca..cea320a 100644 (file)
@@ -140,9 +140,7 @@ static int acp3x_1015_hw_params(struct snd_pcm_substream *substream,
        for_each_rtd_codec_dais(rtd, i, codec_dai) {
                if (strcmp(codec_dai->name, "rt1015-aif"))
                        continue;
-               ret = snd_soc_dai_set_bclk_ratio(codec_dai, 64);
-               if (ret < 0)
-                       return ret;
+
                ret = snd_soc_dai_set_pll(codec_dai, 0, RT1015_PLL_S_BCLK,
                                                64 * srate, 256 * srate);
                if (ret < 0)
index 232300d..7c6187e 100644 (file)
@@ -541,7 +541,7 @@ static struct snd_soc_dai_driver atmel_i2s_dai = {
                .formats = ATMEL_I2S_FORMATS,
        },
        .ops = &atmel_i2s_dai_ops,
-       .symmetric_rates = 1,
+       .symmetric_rate = 1,
 };
 
 static const struct snd_soc_component_driver atmel_i2s_component = {
index 704f700..3e7ea20 100644 (file)
 #include "atmel-pcm.h"
 
 
-static int atmel_pcm_preallocate_dma_buffer(struct snd_pcm *pcm,
-       int stream)
-{
-       struct snd_pcm_substream *substream = pcm->streams[stream].substream;
-       struct snd_dma_buffer *buf = &substream->dma_buffer;
-       size_t size = ATMEL_SSC_DMABUF_SIZE;
-
-       buf->dev.type = SNDRV_DMA_TYPE_DEV;
-       buf->dev.dev = pcm->card->dev;
-       buf->private_data = NULL;
-       buf->area = dma_alloc_coherent(pcm->card->dev, size,
-                       &buf->addr, GFP_KERNEL);
-       pr_debug("atmel-pcm: alloc dma buffer: area=%p, addr=%p, size=%zu\n",
-                       (void *)buf->area, (void *)(long)buf->addr, size);
-
-       if (!buf->area)
-               return -ENOMEM;
-
-       buf->bytes = size;
-       return 0;
-}
-
-static int atmel_pcm_mmap(struct snd_soc_component *component,
-                         struct snd_pcm_substream *substream,
-                         struct vm_area_struct *vma)
-{
-       return remap_pfn_range(vma, vma->vm_start,
-                      substream->dma_buffer.addr >> PAGE_SHIFT,
-                      vma->vm_end - vma->vm_start, vma->vm_page_prot);
-}
-
 static int atmel_pcm_new(struct snd_soc_component *component,
                         struct snd_soc_pcm_runtime *rtd)
 {
        struct snd_card *card = rtd->card->snd_card;
-       struct snd_pcm *pcm = rtd->pcm;
        int ret;
 
        ret = dma_coerce_mask_and_coherent(card->dev, DMA_BIT_MASK(32));
        if (ret)
                return ret;
 
-       if (pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream) {
-               pr_debug("atmel-pcm: allocating PCM playback DMA buffer\n");
-               ret = atmel_pcm_preallocate_dma_buffer(pcm,
-                       SNDRV_PCM_STREAM_PLAYBACK);
-               if (ret)
-                       goto out;
-       }
+       snd_pcm_set_managed_buffer_all(rtd->pcm, SNDRV_DMA_TYPE_DEV,
+                                      card->dev, ATMEL_SSC_DMABUF_SIZE,
+                                      ATMEL_SSC_DMABUF_SIZE);
 
-       if (pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream) {
-               pr_debug("atmel-pcm: allocating PCM capture DMA buffer\n");
-               ret = atmel_pcm_preallocate_dma_buffer(pcm,
-                       SNDRV_PCM_STREAM_CAPTURE);
-               if (ret)
-                       goto out;
-       }
- out:
-       return ret;
-}
-
-static void atmel_pcm_free(struct snd_soc_component *component,
-                          struct snd_pcm *pcm)
-{
-       struct snd_pcm_substream *substream;
-       struct snd_dma_buffer *buf;
-       int stream;
-
-       for (stream = 0; stream < 2; stream++) {
-               substream = pcm->streams[stream].substream;
-               if (!substream)
-                       continue;
-
-               buf = &substream->dma_buffer;
-               if (!buf->area)
-                       continue;
-               dma_free_coherent(pcm->card->dev, buf->bytes,
-                                 buf->area, buf->addr);
-               buf->area = NULL;
-       }
+       return 0;
 }
 
 /*--------------------------------------------------------------------------*\
@@ -210,9 +145,6 @@ static int atmel_pcm_hw_params(struct snd_soc_component *component,
        /* this may get called several times by oss emulation
         * with different params */
 
-       snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer);
-       runtime->dma_bytes = params_buffer_bytes(params);
-
        prtd->params = snd_soc_dai_get_dma_data(asoc_rtd_to_cpu(rtd, 0), substream);
        prtd->params->dma_intr_handler = atmel_pcm_dma_irq;
 
@@ -384,9 +316,7 @@ static const struct snd_soc_component_driver atmel_soc_platform = {
        .prepare        = atmel_pcm_prepare,
        .trigger        = atmel_pcm_trigger,
        .pointer        = atmel_pcm_pointer,
-       .mmap           = atmel_pcm_mmap,
        .pcm_construct  = atmel_pcm_new,
-       .pcm_destruct   = atmel_pcm_free,
 };
 
 int atmel_pcm_pdc_platform_register(struct device *dev)
index 04acc18..6d5ae18 100644 (file)
@@ -859,8 +859,8 @@ static struct snd_soc_dai_driver mchp_i2s_mcc_dai = {
                .formats = MCHP_I2SMCC_FORMATS,
        },
        .ops = &mchp_i2s_mcc_dai_ops,
-       .symmetric_rates = 1,
-       .symmetric_samplebits = 1,
+       .symmetric_rate = 1,
+       .symmetric_sample_bits = 1,
        .symmetric_channels = 1,
 };
 
index 7fd08fa..65bd39f 100644 (file)
@@ -210,7 +210,7 @@ static const struct snd_soc_dai_ops au1xi2s_dai_ops = {
 };
 
 static struct snd_soc_dai_driver au1xi2s_dai_driver = {
-       .symmetric_rates        = 1,
+       .symmetric_rate         = 1,
        .playback = {
                .rates          = AU1XI2SC_RATES,
                .formats        = AU1XI2SC_FMTS,
index c2f7631..3d668f4 100644 (file)
@@ -783,8 +783,8 @@ static struct snd_soc_dai_driver bcm2835_i2s_dai = {
                                | SNDRV_PCM_FMTBIT_S32_LE
                },
        .ops = &bcm2835_i2s_dai_ops,
-       .symmetric_rates = 1,
-       .symmetric_samplebits = 1,
+       .symmetric_rate = 1,
+       .symmetric_sample_bits = 1,
 };
 
 static bool bcm2835_i2s_volatile_reg(struct device *dev, unsigned int reg)
index 246a57a..527caf4 100644 (file)
@@ -212,7 +212,7 @@ static struct snd_soc_dai_driver bcm63xx_i2s_dai = {
                .formats = SNDRV_PCM_FMTBIT_S32_LE,
        },
        .ops = &bcm63xx_i2s_dai_ops,
-       .symmetric_rates = 1,
+       .symmetric_rate = 1,
        .symmetric_channels = 1,
 };
 
index 7ad0723..56b71b9 100644 (file)
@@ -636,36 +636,6 @@ static int cygnus_pcm_close(struct snd_soc_component *component,
        return 0;
 }
 
-static int cygnus_pcm_hw_params(struct snd_soc_component *component,
-                               struct snd_pcm_substream *substream,
-                               struct snd_pcm_hw_params *params)
-{
-       struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
-       struct snd_pcm_runtime *runtime = substream->runtime;
-       struct cygnus_aio_port *aio;
-
-       aio = cygnus_dai_get_dma_data(substream);
-       dev_dbg(asoc_rtd_to_cpu(rtd, 0)->dev, "%s  port %d\n", __func__, aio->portnum);
-
-       snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer);
-       runtime->dma_bytes = params_buffer_bytes(params);
-
-       return 0;
-}
-
-static int cygnus_pcm_hw_free(struct snd_soc_component *component,
-                             struct snd_pcm_substream *substream)
-{
-       struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
-       struct cygnus_aio_port *aio;
-
-       aio = cygnus_dai_get_dma_data(substream);
-       dev_dbg(asoc_rtd_to_cpu(rtd, 0)->dev, "%s  port %d\n", __func__, aio->portnum);
-
-       snd_pcm_set_runtime_buffer(substream, NULL);
-       return 0;
-}
-
 static int cygnus_pcm_prepare(struct snd_soc_component *component,
                              struct snd_pcm_substream *substream)
 {
@@ -730,87 +700,19 @@ static snd_pcm_uframes_t cygnus_pcm_pointer(struct snd_soc_component *component,
        return bytes_to_frames(substream->runtime, res);
 }
 
-static int cygnus_pcm_preallocate_dma_buffer(struct snd_pcm *pcm, int stream)
-{
-       struct snd_pcm_substream *substream = pcm->streams[stream].substream;
-       struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
-       struct snd_dma_buffer *buf = &substream->dma_buffer;
-       size_t size;
-
-       size = cygnus_pcm_hw.buffer_bytes_max;
-
-       buf->dev.type = SNDRV_DMA_TYPE_DEV;
-       buf->dev.dev = pcm->card->dev;
-       buf->private_data = NULL;
-       buf->area = dma_alloc_coherent(pcm->card->dev, size,
-                       &buf->addr, GFP_KERNEL);
-
-       dev_dbg(asoc_rtd_to_cpu(rtd, 0)->dev, "%s: size 0x%zx @ %pK\n",
-                               __func__, size, buf->area);
-
-       if (!buf->area) {
-               dev_err(asoc_rtd_to_cpu(rtd, 0)->dev, "%s: dma_alloc failed\n", __func__);
-               return -ENOMEM;
-       }
-       buf->bytes = size;
-
-       return 0;
-}
-
-static void cygnus_dma_free_dma_buffers(struct snd_soc_component *component,
-                                       struct snd_pcm *pcm)
-{
-       struct snd_pcm_substream *substream;
-       struct snd_dma_buffer *buf;
-
-       substream = pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream;
-       if (substream) {
-               buf = &substream->dma_buffer;
-               if (buf->area) {
-                       dma_free_coherent(pcm->card->dev, buf->bytes,
-                               buf->area, buf->addr);
-                       buf->area = NULL;
-               }
-       }
-
-       substream = pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream;
-       if (substream) {
-               buf = &substream->dma_buffer;
-               if (buf->area) {
-                       dma_free_coherent(pcm->card->dev, buf->bytes,
-                               buf->area, buf->addr);
-                       buf->area = NULL;
-               }
-       }
-}
-
 static int cygnus_dma_new(struct snd_soc_component *component,
                          struct snd_soc_pcm_runtime *rtd)
 {
+       size_t size = cygnus_pcm_hw.buffer_bytes_max;
        struct snd_card *card = rtd->card->snd_card;
-       struct snd_pcm *pcm = rtd->pcm;
-       int ret;
 
        if (!card->dev->dma_mask)
                card->dev->dma_mask = &cygnus_dma_dmamask;
        if (!card->dev->coherent_dma_mask)
                card->dev->coherent_dma_mask = DMA_BIT_MASK(32);
 
-       if (pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream) {
-               ret = cygnus_pcm_preallocate_dma_buffer(pcm,
-                               SNDRV_PCM_STREAM_PLAYBACK);
-               if (ret)
-                       return ret;
-       }
-
-       if (pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream) {
-               ret = cygnus_pcm_preallocate_dma_buffer(pcm,
-                               SNDRV_PCM_STREAM_CAPTURE);
-               if (ret) {
-                       cygnus_dma_free_dma_buffers(component, pcm);
-                       return ret;
-               }
-       }
+       snd_pcm_set_managed_buffer_all(rtd->pcm, SNDRV_DMA_TYPE_DEV,
+                                      card->dev, size, size);
 
        return 0;
 }
@@ -818,13 +720,10 @@ static int cygnus_dma_new(struct snd_soc_component *component,
 static struct snd_soc_component_driver cygnus_soc_platform = {
        .open           = cygnus_pcm_open,
        .close          = cygnus_pcm_close,
-       .hw_params      = cygnus_pcm_hw_params,
-       .hw_free        = cygnus_pcm_hw_free,
        .prepare        = cygnus_pcm_prepare,
        .trigger        = cygnus_pcm_trigger,
        .pointer        = cygnus_pcm_pointer,
        .pcm_construct  = cygnus_dma_new,
-       .pcm_destruct   = cygnus_dma_free_dma_buffers,
 };
 
 int cygnus_soc_platform_register(struct device *dev,
index 371708b..0d26550 100644 (file)
@@ -404,7 +404,7 @@ static const struct snd_soc_dai_ops ep93xx_i2s_dai_ops = {
 #define EP93XX_I2S_FORMATS (SNDRV_PCM_FMTBIT_S32_LE)
 
 static struct snd_soc_dai_driver ep93xx_i2s_dai = {
-       .symmetric_rates= 1,
+       .symmetric_rate = 1,
        .probe          = ep93xx_i2s_dai_probe,
        .playback       = {
                .channels_min   = 2,
index 9bf6bfd..e4cf14e 100644 (file)
@@ -104,6 +104,7 @@ config SND_SOC_ALL_CODECS
        imply SND_SOC_ISABELLE
        imply SND_SOC_JZ4740_CODEC
        imply SND_SOC_JZ4725B_CODEC
+       imply SND_SOC_JZ4760_CODEC
        imply SND_SOC_JZ4770_CODEC
        imply SND_SOC_LM4857
        imply SND_SOC_LM49453
@@ -227,6 +228,8 @@ config SND_SOC_ALL_CODECS
        imply SND_SOC_UDA1380
        imply SND_SOC_WCD9335
        imply SND_SOC_WCD934X
+       imply SND_SOC_LPASS_RX_MACRO
+       imply SND_SOC_LPASS_TX_MACRO
        imply SND_SOC_WL1273
        imply SND_SOC_WM0010
        imply SND_SOC_WM1250_EV1
@@ -712,7 +715,7 @@ config SND_SOC_CX2072X
          Enable support for Conexant CX20721 and CX20723 codec chips.
 
 config SND_SOC_JZ4740_CODEC
-       depends on MIPS || COMPILE_TEST
+       depends on MACH_INGENIC || COMPILE_TEST
        depends on OF
        select REGMAP_MMIO
        tristate "Ingenic JZ4740 internal CODEC"
@@ -724,7 +727,7 @@ config SND_SOC_JZ4740_CODEC
          will be called snd-soc-jz4740-codec.
 
 config SND_SOC_JZ4725B_CODEC
-       depends on MIPS || COMPILE_TEST
+       depends on MACH_INGENIC || COMPILE_TEST
        depends on OF
        select REGMAP
        tristate "Ingenic JZ4725B internal CODEC"
@@ -735,8 +738,20 @@ config SND_SOC_JZ4725B_CODEC
          This driver can also be built as a module. If so, the module
          will be called snd-soc-jz4725b-codec.
 
+config SND_SOC_JZ4760_CODEC
+        depends on MACH_INGENIC || COMPILE_TEST
+        depends on OF
+        select REGMAP
+        tristate "Ingenic JZ4760 internal CODEC"
+        help
+          Enable support for the internal CODEC found in the JZ4760 SoC
+          from Ingenic.
+
+          This driver can also be built as a module. If so, the module
+          will be called snd-soc-jz4760-codec.
+
 config SND_SOC_JZ4770_CODEC
-       depends on MIPS || COMPILE_TEST
+       depends on MACH_INGENIC || COMPILE_TEST
        depends on OF
        select REGMAP
        tristate "Ingenic JZ4770 internal CODEC"
@@ -1162,7 +1177,7 @@ config SND_SOC_RT5651
        depends on I2C
 
 config SND_SOC_RT5659
-       tristate
+       tristate "Realtek RT5658/RT5659 Codec"
        depends on I2C
 
 config SND_SOC_RT5660
@@ -1820,4 +1835,12 @@ config SND_SOC_LPASS_VA_MACRO
        depends on COMMON_CLK
        tristate "Qualcomm VA Macro in LPASS(Low Power Audio SubSystem)"
 
+config SND_SOC_LPASS_RX_MACRO
+       depends on COMMON_CLK
+       tristate "Qualcomm RX Macro in LPASS(Low Power Audio SubSystem)"
+
+config SND_SOC_LPASS_TX_MACRO
+       depends on COMMON_CLK
+       tristate "Qualcomm TX Macro in LPASS(Low Power Audio SubSystem)"
+
 endmenu
index d277f03..81357dc 100644 (file)
@@ -101,11 +101,14 @@ snd-soc-inno-rk3036-objs := inno_rk3036.o
 snd-soc-isabelle-objs := isabelle.o
 snd-soc-jz4740-codec-objs := jz4740.o
 snd-soc-jz4725b-codec-objs := jz4725b.o
+snd-soc-jz4760-codec-objs := jz4760.o
 snd-soc-jz4770-codec-objs := jz4770.o
 snd-soc-l3-objs := l3.o
 snd-soc-lm4857-objs := lm4857.o
 snd-soc-lm49453-objs := lm49453.o
 snd-soc-lochnagar-sc-objs := lochnagar-sc.o
+snd-soc-lpass-rx-macro-objs := lpass-rx-macro.o
+snd-soc-lpass-tx-macro-objs := lpass-tx-macro.o
 snd-soc-lpass-wsa-macro-objs := lpass-wsa-macro.o
 snd-soc-lpass-va-macro-objs := lpass-va-macro.o
 snd-soc-madera-objs := madera.o
@@ -201,7 +204,6 @@ snd-soc-sigmadsp-objs := sigmadsp.o
 snd-soc-sigmadsp-i2c-objs := sigmadsp-i2c.o
 snd-soc-sigmadsp-regmap-objs := sigmadsp-regmap.o
 snd-soc-si476x-objs := si476x.o
-snd-soc-sirf-audio-codec-objs := sirf-audio-codec.o
 snd-soc-spdif-tx-objs := spdif_transmitter.o
 snd-soc-spdif-rx-objs := spdif_receiver.o
 snd-soc-ssm2305-objs := ssm2305.o
@@ -302,7 +304,6 @@ snd-soc-wm9713-objs := wm9713.o
 snd-soc-wm-hubs-objs := wm_hubs.o
 snd-soc-wsa881x-objs := wsa881x.o
 snd-soc-zl38060-objs := zl38060.o
-snd-soc-zx-aud96p22-objs := zx_aud96p22.o
 # Amp
 snd-soc-max9877-objs := max9877.o
 snd-soc-max98504-objs := max98504.o
@@ -418,6 +419,7 @@ 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_JZ4725B_CODEC)    += snd-soc-jz4725b-codec.o
+obj-$(CONFIG_SND_SOC_JZ4760_CODEC)      += snd-soc-jz4760-codec.o
 obj-$(CONFIG_SND_SOC_JZ4770_CODEC)     += snd-soc-jz4770-codec.o
 obj-$(CONFIG_SND_SOC_L3)       += snd-soc-l3.o
 obj-$(CONFIG_SND_SOC_LM4857)   += snd-soc-lm4857.o
@@ -516,7 +518,6 @@ obj-$(CONFIG_SND_SOC_SIGMADSP_I2C)  += snd-soc-sigmadsp-i2c.o
 obj-$(CONFIG_SND_SOC_SIGMADSP_REGMAP)  += snd-soc-sigmadsp-regmap.o
 obj-$(CONFIG_SND_SOC_SI476X)   += snd-soc-si476x.o
 obj-$(CONFIG_SND_SOC_SPDIF)    += snd-soc-spdif-rx.o snd-soc-spdif-tx.o
-obj-$(CONFIG_SND_SOC_SIRF_AUDIO_CODEC) += sirf-audio-codec.o
 obj-$(CONFIG_SND_SOC_SSM2305)  += snd-soc-ssm2305.o
 obj-$(CONFIG_SND_SOC_SSM2518)  += snd-soc-ssm2518.o
 obj-$(CONFIG_SND_SOC_SSM2602)  += snd-soc-ssm2602.o
@@ -618,7 +619,6 @@ obj-$(CONFIG_SND_SOC_WM_ADSP)       += snd-soc-wm-adsp.o
 obj-$(CONFIG_SND_SOC_WM_HUBS)  += snd-soc-wm-hubs.o
 obj-$(CONFIG_SND_SOC_WSA881X)  += snd-soc-wsa881x.o
 obj-$(CONFIG_SND_SOC_ZL38060)  += snd-soc-zl38060.o
-obj-$(CONFIG_SND_SOC_ZX_AUD96P22) += snd-soc-zx-aud96p22.o
 
 # Amp
 obj-$(CONFIG_SND_SOC_MAX9877)  += snd-soc-max9877.o
@@ -627,6 +627,8 @@ obj-$(CONFIG_SND_SOC_SIMPLE_AMPLIFIER)      += snd-soc-simple-amplifier.o
 obj-$(CONFIG_SND_SOC_TPA6130A2)        += snd-soc-tpa6130a2.o
 obj-$(CONFIG_SND_SOC_LPASS_WSA_MACRO)  += snd-soc-lpass-wsa-macro.o
 obj-$(CONFIG_SND_SOC_LPASS_VA_MACRO)   += snd-soc-lpass-va-macro.o
+obj-$(CONFIG_SND_SOC_LPASS_RX_MACRO)   += snd-soc-lpass-rx-macro.o
+obj-$(CONFIG_SND_SOC_LPASS_TX_MACRO)   += snd-soc-lpass-tx-macro.o
 
 # Mux
 obj-$(CONFIG_SND_SOC_SIMPLE_MUX)       += snd-soc-simple-mux.o
index 31a8c41..c95f007 100644 (file)
@@ -2384,7 +2384,7 @@ static struct snd_soc_dai_driver ab8500_codec_dai[] = {
                        .formats = AB8500_SUPPORTED_FMT,
                },
                .ops = &ab8500_codec_ops,
-               .symmetric_rates = 1
+               .symmetric_rate = 1
        },
        {
                .name = "ab8500-codec-dai.1",
@@ -2397,7 +2397,7 @@ static struct snd_soc_dai_driver ab8500_codec_dai[] = {
                        .formats = AB8500_SUPPORTED_FMT,
                },
                .ops = &ab8500_codec_ops,
-               .symmetric_rates = 1
+               .symmetric_rate = 1
        }
 };
 
index 5ccbf1b..6811a8b 100644 (file)
@@ -890,7 +890,7 @@ static struct snd_soc_dai_driver adau1372_dai_driver = {
                .sig_bits = 24,
        },
        .ops = &adau1372_dai_ops,
-       .symmetric_rates = 1,
+       .symmetric_rate = 1,
 };
 
 static int adau1372_setup_pll(struct adau1372 *adau1372, unsigned int rate)
index e71fde0..9887aa6 100644 (file)
@@ -1205,7 +1205,7 @@ static struct snd_soc_dai_driver adau1373_dai_driver[] = {
                        .formats = ADAU1373_FORMATS,
                },
                .ops = &adau1373_dai_ops,
-               .symmetric_rates = 1,
+               .symmetric_rate = 1,
        },
        {
                .id = 1,
@@ -1225,7 +1225,7 @@ static struct snd_soc_dai_driver adau1373_dai_driver[] = {
                        .formats = ADAU1373_FORMATS,
                },
                .ops = &adau1373_dai_ops,
-               .symmetric_rates = 1,
+               .symmetric_rate = 1,
        },
        {
                .id = 2,
@@ -1245,7 +1245,7 @@ static struct snd_soc_dai_driver adau1373_dai_driver[] = {
                        .formats = ADAU1373_FORMATS,
                },
                .ops = &adau1373_dai_ops,
-               .symmetric_rates = 1,
+               .symmetric_rate = 1,
        },
 };
 
index 68130ea..5ce7469 100644 (file)
@@ -653,7 +653,7 @@ static struct snd_soc_dai_driver adau1701_dai = {
                .formats = ADAU1701_FORMATS,
        },
        .ops = &adau1701_dai_ops,
-       .symmetric_rates = 1,
+       .symmetric_rate = 1,
 };
 
 #ifdef CONFIG_OF
index 30e072c..546ee81 100644 (file)
@@ -1095,8 +1095,7 @@ void adau17x1_remove(struct device *dev)
 {
        struct adau *adau = dev_get_drvdata(dev);
 
-       if (adau->mclk)
-               clk_disable_unprepare(adau->mclk);
+       clk_disable_unprepare(adau->mclk);
 }
 EXPORT_SYMBOL_GPL(adau17x1_remove);
 
index 2fa83a1..8e60e2b 100644 (file)
@@ -56,7 +56,7 @@ static struct snd_soc_dai_driver ak4554_dai = {
                .rates = SNDRV_PCM_RATE_8000_48000,
                .formats = SNDRV_PCM_FMTBIT_S16_LE,
        },
-       .symmetric_rates = 1,
+       .symmetric_rate = 1,
 };
 
 static const struct snd_soc_component_driver soc_component_dev_ak4554 = {
index 8d663e8..fe208cf 100644 (file)
@@ -575,7 +575,7 @@ static struct snd_soc_dai_driver ak4613_dai = {
                .formats        = AK4613_PCM_FMTBIT,
        },
        .ops = &ak4613_dai_ops,
-       .symmetric_rates = 1,
+       .symmetric_rate = 1,
 };
 
 static int ak4613_suspend(struct snd_soc_component *component)
index 77004cd..04aef0e 100644 (file)
@@ -499,7 +499,7 @@ static struct snd_soc_dai_driver ak4641_dai[] = {
                .formats = AK4641_FORMATS,
        },
        .ops = &ak4641_i2s_dai_ops,
-       .symmetric_rates = 1,
+       .symmetric_rate = 1,
 },
 {
        .name = "ak4641-voice",
@@ -519,7 +519,7 @@ static struct snd_soc_dai_driver ak4641_dai[] = {
                .formats = AK4641_FORMATS,
        },
        .ops = &ak4641_pcm_dai_ops,
-       .symmetric_rates = 1,
+       .symmetric_rate = 1,
 },
 };
 
index 3532370..c49c58e 100644 (file)
@@ -516,7 +516,7 @@ static struct snd_soc_dai_driver ak4642_dai = {
                .rates = SNDRV_PCM_RATE_8000_48000,
                .formats = SNDRV_PCM_FMTBIT_S16_LE },
        .ops = &ak4642_dai_ops,
-       .symmetric_rates = 1,
+       .symmetric_rate = 1,
 };
 
 static int ak4642_suspend(struct snd_soc_component *component)
index bde5ded..7981388 100644 (file)
@@ -1032,7 +1032,7 @@ static struct snd_soc_dai_driver alc5632_dai = {
                .formats = ALC5632_FORMATS,},
 
        .ops = &alc5632_dai_ops,
-       .symmetric_rates = 1,
+       .symmetric_rate = 1,
 };
 
 #ifdef CONFIG_PM
index f046987..05bbacd 100644 (file)
 #include <sound/soc.h>
 #include <sound/tlv.h>
 
+/* Register 512 CPCAP_REG_VAUDIOC --- Audio Regulator and Bias Voltage */
+#define CPCAP_BIT_AUDIO_LOW_PWR           6
+#define CPCAP_BIT_AUD_LOWPWR_SPEED        5
+#define CPCAP_BIT_VAUDIOPRISTBY           4
+#define CPCAP_BIT_VAUDIO_MODE1            2
+#define CPCAP_BIT_VAUDIO_MODE0            1
+#define CPCAP_BIT_V_AUDIO_EN              0
+
 /* Register 513 CPCAP_REG_CC     --- CODEC */
 #define CPCAP_BIT_CDC_CLK2                15
 #define CPCAP_BIT_CDC_CLK1                14
@@ -221,6 +229,7 @@ struct cpcap_reg_info {
 };
 
 static const struct cpcap_reg_info cpcap_default_regs[] = {
+       { CPCAP_REG_VAUDIOC, 0x003F, 0x0000 },
        { CPCAP_REG_CC, 0xFFFF, 0x0000 },
        { CPCAP_REG_CC, 0xFFFF, 0x0000 },
        { CPCAP_REG_CDI, 0xBFFF, 0x0000 },
@@ -1264,12 +1273,12 @@ static int cpcap_voice_hw_params(struct snd_pcm_substream *substream,
 
        if (direction == SNDRV_PCM_STREAM_CAPTURE) {
                mask = 0x0000;
-               mask |= CPCAP_BIT_MIC1_RX_TIMESLOT0;
-               mask |= CPCAP_BIT_MIC1_RX_TIMESLOT1;
-               mask |= CPCAP_BIT_MIC1_RX_TIMESLOT2;
-               mask |= CPCAP_BIT_MIC2_TIMESLOT0;
-               mask |= CPCAP_BIT_MIC2_TIMESLOT1;
-               mask |= CPCAP_BIT_MIC2_TIMESLOT2;
+               mask |= BIT(CPCAP_BIT_MIC1_RX_TIMESLOT0);
+               mask |= BIT(CPCAP_BIT_MIC1_RX_TIMESLOT1);
+               mask |= BIT(CPCAP_BIT_MIC1_RX_TIMESLOT2);
+               mask |= BIT(CPCAP_BIT_MIC2_TIMESLOT0);
+               mask |= BIT(CPCAP_BIT_MIC2_TIMESLOT1);
+               mask |= BIT(CPCAP_BIT_MIC2_TIMESLOT2);
                val = 0x0000;
                if (channels >= 2)
                        val = BIT(CPCAP_BIT_MIC1_RX_TIMESLOT0);
@@ -1371,8 +1380,121 @@ static int cpcap_voice_set_dai_fmt(struct snd_soc_dai *codec_dai,
        return 0;
 }
 
-static int cpcap_voice_set_mute(struct snd_soc_dai *dai,
-                               int mute, int direction)
+
+/*
+ * Configure codec for voice call if requested.
+ *
+ * We can configure most with snd_soc_dai_set_sysclk(), snd_soc_dai_set_fmt()
+ * and snd_soc_dai_set_tdm_slot(). This function configures the rest of the
+ * cpcap related hardware as CPU is not involved in the voice call.
+ */
+static int cpcap_voice_call(struct cpcap_audio *cpcap, struct snd_soc_dai *dai,
+                           bool voice_call)
+{
+       int mask, err;
+
+       /* Modem to codec VAUDIO_MODE1 */
+       mask = BIT(CPCAP_BIT_VAUDIO_MODE1);
+       err = regmap_update_bits(cpcap->regmap, CPCAP_REG_VAUDIOC,
+                                mask, voice_call ? mask : 0);
+       if (err)
+               return err;
+
+       /* Clear MIC1_MUX for call */
+       mask = BIT(CPCAP_BIT_MIC1_MUX);
+       err = regmap_update_bits(cpcap->regmap, CPCAP_REG_TXI,
+                                mask, voice_call ? 0 : mask);
+       if (err)
+               return err;
+
+       /* Set MIC2_MUX for call */
+       mask = BIT(CPCAP_BIT_MB_ON1L) | BIT(CPCAP_BIT_MB_ON1R) |
+               BIT(CPCAP_BIT_MIC2_MUX) | BIT(CPCAP_BIT_MIC2_PGA_EN);
+       err = regmap_update_bits(cpcap->regmap, CPCAP_REG_TXI,
+                                mask, voice_call ? mask : 0);
+       if (err)
+               return err;
+
+       /* Enable LDSP for call */
+       mask = BIT(CPCAP_BIT_A2_LDSP_L_EN) | BIT(CPCAP_BIT_A2_LDSP_R_EN);
+       err = regmap_update_bits(cpcap->regmap, CPCAP_REG_RXOA,
+                                mask, voice_call ? mask : 0);
+       if (err)
+               return err;
+
+       /* Enable CPCAP_BIT_PGA_CDC_EN for call */
+       mask = BIT(CPCAP_BIT_PGA_CDC_EN);
+       err = regmap_update_bits(cpcap->regmap, CPCAP_REG_RXCOA,
+                                mask, voice_call ? mask : 0);
+       if (err)
+               return err;
+
+       /* Unmute voice for call */
+       if (dai) {
+               err = snd_soc_dai_digital_mute(dai, !voice_call,
+                                              SNDRV_PCM_STREAM_PLAYBACK);
+               if (err)
+                       return err;
+       }
+
+       /* Set modem to codec mic CDC and HPF for call */
+       mask = BIT(CPCAP_BIT_MIC2_CDC_EN) | BIT(CPCAP_BIT_CDC_EN_RX) |
+              BIT(CPCAP_BIT_AUDOHPF_1) | BIT(CPCAP_BIT_AUDOHPF_0) |
+              BIT(CPCAP_BIT_AUDIHPF_1) | BIT(CPCAP_BIT_AUDIHPF_0);
+       err = regmap_update_bits(cpcap->regmap, CPCAP_REG_CC,
+                                mask, voice_call ? mask : 0);
+       if (err)
+               return err;
+
+       /* Enable modem to codec CDC for call*/
+       mask = BIT(CPCAP_BIT_CDC_CLK_EN);
+       err = regmap_update_bits(cpcap->regmap, CPCAP_REG_CDI,
+                                mask, voice_call ? mask : 0);
+
+       return err;
+}
+
+static int cpcap_voice_set_tdm_slot(struct snd_soc_dai *dai,
+                                   unsigned int tx_mask, unsigned int rx_mask,
+                                   int slots, int slot_width)
+{
+       struct snd_soc_component *component = dai->component;
+       struct cpcap_audio *cpcap = snd_soc_component_get_drvdata(component);
+       int err, ts_mask, mask;
+       bool voice_call;
+
+       /*
+        * Primitive test for voice call, probably needs more checks
+        * later on for 16-bit calls detected, Bluetooth headset etc.
+        */
+       if (tx_mask == 0 && rx_mask == 1 && slot_width == 8)
+               voice_call = true;
+       else
+               voice_call = false;
+
+       ts_mask = 0x7 << CPCAP_BIT_MIC2_TIMESLOT0;
+       ts_mask |= 0x7 << CPCAP_BIT_MIC1_RX_TIMESLOT0;
+
+       mask = (tx_mask & 0x7) << CPCAP_BIT_MIC2_TIMESLOT0;
+       mask |= (rx_mask & 0x7) << CPCAP_BIT_MIC1_RX_TIMESLOT0;
+
+       err = regmap_update_bits(cpcap->regmap, CPCAP_REG_CDI,
+                                ts_mask, mask);
+       if (err)
+               return err;
+
+       err = cpcap_set_samprate(cpcap, CPCAP_DAI_VOICE, slot_width * 1000);
+       if (err)
+               return err;
+
+       err = cpcap_voice_call(cpcap, dai, voice_call);
+       if (err)
+               return err;
+
+       return 0;
+}
+
+static int cpcap_voice_set_mute(struct snd_soc_dai *dai, int mute, int direction)
 {
        struct snd_soc_component *component = dai->component;
        struct cpcap_audio *cpcap = snd_soc_component_get_drvdata(component);
@@ -1393,6 +1515,7 @@ static const struct snd_soc_dai_ops cpcap_dai_voice_ops = {
        .hw_params      = cpcap_voice_hw_params,
        .set_sysclk     = cpcap_voice_set_dai_sysclk,
        .set_fmt        = cpcap_voice_set_dai_fmt,
+       .set_tdm_slot   = cpcap_voice_set_tdm_slot,
        .mute_stream    = cpcap_voice_set_mute,
        .no_capture_mute = 1,
 };
index f33a2a9..c4772f8 100644 (file)
@@ -1011,6 +1011,18 @@ static int cros_ec_codec_platform_probe(struct platform_device *pdev)
        }
        priv->ec_capabilities = r.capabilities;
 
+       /* Reset EC codec i2s rx. */
+       p.cmd = EC_CODEC_I2S_RX_RESET;
+       ret = send_ec_host_command(priv->ec_device, EC_CMD_EC_CODEC_I2S_RX,
+                                  (uint8_t *)&p, sizeof(p), NULL, 0);
+       if (ret == -ENOPROTOOPT) {
+               dev_info(dev,
+                        "Missing reset command. Please update EC firmware.\n");
+       } else if (ret) {
+               dev_err(dev, "failed to EC_CODEC_I2S_RESET: %d\n", ret);
+               return ret;
+       }
+
        platform_set_drvdata(pdev, priv);
 
        ret = devm_snd_soc_register_component(dev, &i2s_rx_component_driver,
index 3a644a3..f406723 100644 (file)
@@ -194,7 +194,7 @@ static struct snd_soc_dai_driver cs35l32_dai[] = {
                        .formats = CS35L32_FORMATS,
                },
                .ops = &cs35l32_ops,
-               .symmetric_rates = 1,
+               .symmetric_rate = 1,
        }
 };
 
index 6042194..7ad7b73 100644 (file)
@@ -691,7 +691,7 @@ static struct snd_soc_dai_driver cs35l33_dai = {
                        .formats = CS35L33_FORMATS,
                },
                .ops = &cs35l33_ops,
-               .symmetric_rates = 1,
+               .symmetric_rate = 1,
 };
 
 static int cs35l33_set_hg_data(struct snd_soc_component *component,
index b792c00..110ee2d 100644 (file)
@@ -666,7 +666,7 @@ static struct snd_soc_dai_driver cs35l34_dai = {
                        .formats = CS35L34_FORMATS,
                },
                .ops = &cs35l34_ops,
-               .symmetric_rates = 1,
+               .symmetric_rate = 1,
 };
 
 static int cs35l34_boost_inductor(struct cs35l34_private *cs35l34,
index e330427..55d529a 100644 (file)
@@ -692,7 +692,7 @@ static struct snd_soc_dai_driver cs35l35_dai[] = {
                        .formats = CS35L35_FORMATS,
                },
                .ops = &cs35l35_ops,
-               .symmetric_rates = 1,
+               .symmetric_rate = 1,
        },
        {
                .name = "cs35l35-pdm",
index e9b5f76..4451ca9 100644 (file)
@@ -995,7 +995,7 @@ static struct snd_soc_dai_driver cs35l36_dai[] = {
                        .formats = CS35L36_TX_FORMATS,
                },
                .ops = &cs35l36_ops,
-               .symmetric_rates = 1,
+               .symmetric_rate = 1,
        },
 };
 
index 2ea8323..20126cc 100644 (file)
@@ -585,7 +585,7 @@ static struct snd_soc_dai_driver cs4234_dai[] = {
                        .formats = CS4234_FORMATS,
                },
                .ops = &cs4234_dai_ops,
-               .symmetric_rates = 1,
+               .symmetric_rate = 1,
        },
 };
 
index d43762a..7663f89 100644 (file)
@@ -481,7 +481,7 @@ static struct snd_soc_dai_driver cs4271_dai = {
                .formats        = CS4271_PCM_FORMATS,
        },
        .ops = &cs4271_dai_ops,
-       .symmetric_rates = 1,
+       .symmetric_rate = 1,
 };
 
 static int cs4271_reset(struct snd_soc_component *component)
index bb9599c..c44a5cd 100644 (file)
@@ -1250,6 +1250,7 @@ static int cs42l56_i2c_probe(struct i2c_client *i2c_client,
                dev_err(&i2c_client->dev,
                        "CS42L56 Device ID (%X). Expected %X\n",
                        devid, CS42L56_DEVID);
+               ret = -EINVAL;
                goto err_enable;
        }
        alpha_rev = reg & CS42L56_AREV_MASK;
@@ -1307,7 +1308,7 @@ static int cs42l56_i2c_probe(struct i2c_client *i2c_client,
        ret =  devm_snd_soc_register_component(&i2c_client->dev,
                        &soc_component_dev_cs42l56, &cs42l56_dai, 1);
        if (ret < 0)
-               return ret;
+               goto err_enable;
 
        return 0;
 
index 988ca7e..c3f974e 100644 (file)
@@ -1181,7 +1181,7 @@ static struct snd_soc_dai_driver cs42l73_dai[] = {
                        .formats = CS42L73_FORMATS,
                },
                .ops = &cs42l73_ops,
-               .symmetric_rates = 1,
+               .symmetric_rate = 1,
         },
        {
                .name = "cs42l73-asp",
@@ -1201,7 +1201,7 @@ static struct snd_soc_dai_driver cs42l73_dai[] = {
                        .formats = CS42L73_FORMATS,
                },
                .ops = &cs42l73_ops,
-               .symmetric_rates = 1,
+               .symmetric_rate = 1,
         },
        {
                .name = "cs42l73-vsp",
@@ -1221,7 +1221,7 @@ static struct snd_soc_dai_driver cs42l73_dai[] = {
                        .formats = CS42L73_FORMATS,
                },
                .ops = &cs42l73_ops,
-               .symmetric_rates = 1,
+               .symmetric_rate = 1,
         }
 };
 
index 7fb3442..80bc7c1 100644 (file)
@@ -1581,7 +1581,7 @@ static struct snd_soc_dai_driver cs43130_dai[] = {
                        .formats = CS43130_PCM_FORMATS,
                },
                .ops = &cs43130_pcm_ops,
-               .symmetric_rates = 1,
+               .symmetric_rate = 1,
        },
        {
                .name = "cs43130-asp-dop",
@@ -1594,7 +1594,7 @@ static struct snd_soc_dai_driver cs43130_dai[] = {
                        .formats = CS43130_DOP_FORMATS,
                },
                .ops = &cs43130_dop_ops,
-               .symmetric_rates = 1,
+               .symmetric_rate = 1,
        },
        {
                .name = "cs43130-xsp-dop",
@@ -1607,7 +1607,7 @@ static struct snd_soc_dai_driver cs43130_dai[] = {
                        .formats = CS43130_DOP_FORMATS,
                },
                .ops = &cs43130_dop_ops,
-               .symmetric_rates = 1,
+               .symmetric_rate = 1,
        },
        {
                .name = "cs43130-xsp-dsd",
index f566604..7d3e54d 100644 (file)
@@ -189,7 +189,7 @@ static struct snd_soc_dai_driver cs4341_dai = {
                                  SNDRV_PCM_FMTBIT_S24_LE,
        },
        .ops                    = &cs4341_dai_ops,
-       .symmetric_rates        = 1,
+       .symmetric_rate         = 1,
 };
 
 static const struct snd_soc_component_driver soc_component_cs4341 = {
index fd55263..786c69a 100644 (file)
@@ -250,7 +250,7 @@ static struct snd_soc_dai_driver cs4349_dai = {
                .formats        = CS4349_PCM_FORMATS,
        },
        .ops = &cs4349_dai_ops,
-       .symmetric_rates = 1,
+       .symmetric_rate = 1,
 };
 
 static const struct snd_soc_component_driver soc_component_dev_cs4349 = {
index 254f9d9..1ee8316 100644 (file)
@@ -1160,8 +1160,8 @@ static struct snd_soc_dai_driver cs47l15_dai[] = {
                        .formats = MADERA_FORMATS,
                 },
                .ops = &madera_dai_ops,
-               .symmetric_rates = 1,
-               .symmetric_samplebits = 1,
+               .symmetric_rate = 1,
+               .symmetric_sample_bits = 1,
        },
        {
                .name = "cs47l15-aif2",
@@ -1182,8 +1182,8 @@ static struct snd_soc_dai_driver cs47l15_dai[] = {
                        .formats = MADERA_FORMATS,
                 },
                .ops = &madera_dai_ops,
-               .symmetric_rates = 1,
-               .symmetric_samplebits = 1,
+               .symmetric_rate = 1,
+               .symmetric_sample_bits = 1,
        },
        {
                .name = "cs47l15-aif3",
@@ -1204,8 +1204,8 @@ static struct snd_soc_dai_driver cs47l15_dai[] = {
                        .formats = MADERA_FORMATS,
                 },
                .ops = &madera_dai_ops,
-               .symmetric_rates = 1,
-               .symmetric_samplebits = 1,
+               .symmetric_rate = 1,
+               .symmetric_sample_bits = 1,
        },
        {
                .name = "cs47l15-cpu-trace",
index f6d173d..eaabbb5 100644 (file)
@@ -977,8 +977,8 @@ static struct snd_soc_dai_driver cs47l24_dai[] = {
                         .formats = CS47L24_FORMATS,
                 },
                .ops = &arizona_dai_ops,
-               .symmetric_rates = 1,
-               .symmetric_samplebits = 1,
+               .symmetric_rate = 1,
+               .symmetric_sample_bits = 1,
        },
        {
                .name = "cs47l24-aif2",
@@ -999,8 +999,8 @@ static struct snd_soc_dai_driver cs47l24_dai[] = {
                         .formats = CS47L24_FORMATS,
                 },
                .ops = &arizona_dai_ops,
-               .symmetric_rates = 1,
-               .symmetric_samplebits = 1,
+               .symmetric_rate = 1,
+               .symmetric_sample_bits = 1,
        },
        {
                .name = "cs47l24-aif3",
@@ -1021,8 +1021,8 @@ static struct snd_soc_dai_driver cs47l24_dai[] = {
                         .formats = CS47L24_FORMATS,
                 },
                .ops = &arizona_dai_ops,
-               .symmetric_rates = 1,
-               .symmetric_samplebits = 1,
+               .symmetric_rate = 1,
+               .symmetric_sample_bits = 1,
        },
        {
                .name = "cs47l24-cpu-voicectrl",
index e967609..3f04a2a 100644 (file)
@@ -1368,8 +1368,8 @@ static struct snd_soc_dai_driver cs47l35_dai[] = {
                        .formats = MADERA_FORMATS,
                 },
                .ops = &madera_dai_ops,
-               .symmetric_rates = 1,
-               .symmetric_samplebits = 1,
+               .symmetric_rate = 1,
+               .symmetric_sample_bits = 1,
        },
        {
                .name = "cs47l35-aif2",
@@ -1390,8 +1390,8 @@ static struct snd_soc_dai_driver cs47l35_dai[] = {
                        .formats = MADERA_FORMATS,
                 },
                .ops = &madera_dai_ops,
-               .symmetric_rates = 1,
-               .symmetric_samplebits = 1,
+               .symmetric_rate = 1,
+               .symmetric_sample_bits = 1,
        },
        {
                .name = "cs47l35-aif3",
@@ -1412,8 +1412,8 @@ static struct snd_soc_dai_driver cs47l35_dai[] = {
                        .formats = MADERA_FORMATS,
                 },
                .ops = &madera_dai_ops,
-               .symmetric_rates = 1,
-               .symmetric_samplebits = 1,
+               .symmetric_rate = 1,
+               .symmetric_sample_bits = 1,
        },
        {
                .name = "cs47l35-slim1",
index 47b1646..748a180 100644 (file)
@@ -2269,8 +2269,8 @@ static struct snd_soc_dai_driver cs47l85_dai[] = {
                        .formats = MADERA_FORMATS,
                 },
                .ops = &madera_dai_ops,
-               .symmetric_rates = 1,
-               .symmetric_samplebits = 1,
+               .symmetric_rate = 1,
+               .symmetric_sample_bits = 1,
        },
        {
                .name = "cs47l85-aif2",
@@ -2291,8 +2291,8 @@ static struct snd_soc_dai_driver cs47l85_dai[] = {
                        .formats = MADERA_FORMATS,
                 },
                .ops = &madera_dai_ops,
-               .symmetric_rates = 1,
-               .symmetric_samplebits = 1,
+               .symmetric_rate = 1,
+               .symmetric_sample_bits = 1,
        },
        {
                .name = "cs47l85-aif3",
@@ -2313,8 +2313,8 @@ static struct snd_soc_dai_driver cs47l85_dai[] = {
                        .formats = MADERA_FORMATS,
                 },
                .ops = &madera_dai_ops,
-               .symmetric_rates = 1,
-               .symmetric_samplebits = 1,
+               .symmetric_rate = 1,
+               .symmetric_sample_bits = 1,
        },
        {
                .name = "cs47l85-aif4",
@@ -2335,8 +2335,8 @@ static struct snd_soc_dai_driver cs47l85_dai[] = {
                        .formats = MADERA_FORMATS,
                 },
                .ops = &madera_dai_ops,
-               .symmetric_rates = 1,
-               .symmetric_samplebits = 1,
+               .symmetric_rate = 1,
+               .symmetric_sample_bits = 1,
        },
        {
                .name = "cs47l85-slim1",
index 8838dd5..d2911c0 100644 (file)
@@ -2188,8 +2188,8 @@ static struct snd_soc_dai_driver cs47l90_dai[] = {
                        .formats = MADERA_FORMATS,
                 },
                .ops = &madera_dai_ops,
-               .symmetric_rates = 1,
-               .symmetric_samplebits = 1,
+               .symmetric_rate = 1,
+               .symmetric_sample_bits = 1,
        },
        {
                .name = "cs47l90-aif2",
@@ -2210,8 +2210,8 @@ static struct snd_soc_dai_driver cs47l90_dai[] = {
                        .formats = MADERA_FORMATS,
                 },
                .ops = &madera_dai_ops,
-               .symmetric_rates = 1,
-               .symmetric_samplebits = 1,
+               .symmetric_rate = 1,
+               .symmetric_sample_bits = 1,
        },
        {
                .name = "cs47l90-aif3",
@@ -2232,8 +2232,8 @@ static struct snd_soc_dai_driver cs47l90_dai[] = {
                        .formats = MADERA_FORMATS,
                 },
                .ops = &madera_dai_ops,
-               .symmetric_rates = 1,
-               .symmetric_samplebits = 1,
+               .symmetric_rate = 1,
+               .symmetric_sample_bits = 1,
        },
        {
                .name = "cs47l90-aif4",
@@ -2254,8 +2254,8 @@ static struct snd_soc_dai_driver cs47l90_dai[] = {
                        .formats = MADERA_FORMATS,
                 },
                .ops = &madera_dai_ops,
-               .symmetric_rates = 1,
-               .symmetric_samplebits = 1,
+               .symmetric_rate = 1,
+               .symmetric_sample_bits = 1,
        },
        {
                .name = "cs47l90-slim1",
index 52dc299..1a02804 100644 (file)
@@ -1704,8 +1704,8 @@ static struct snd_soc_dai_driver cs47l92_dai[] = {
                        .formats = MADERA_FORMATS,
                 },
                .ops = &madera_dai_ops,
-               .symmetric_rates = 1,
-               .symmetric_samplebits = 1,
+               .symmetric_rate = 1,
+               .symmetric_sample_bits = 1,
        },
        {
                .name = "cs47l92-aif2",
@@ -1726,8 +1726,8 @@ static struct snd_soc_dai_driver cs47l92_dai[] = {
                        .formats = MADERA_FORMATS,
                 },
                .ops = &madera_dai_ops,
-               .symmetric_rates = 1,
-               .symmetric_samplebits = 1,
+               .symmetric_rate = 1,
+               .symmetric_sample_bits = 1,
        },
        {
                .name = "cs47l92-aif3",
@@ -1748,8 +1748,8 @@ static struct snd_soc_dai_driver cs47l92_dai[] = {
                        .formats = MADERA_FORMATS,
                 },
                .ops = &madera_dai_ops,
-               .symmetric_rates = 1,
-               .symmetric_samplebits = 1,
+               .symmetric_rate = 1,
+               .symmetric_sample_bits = 1,
        },
        {
                .name = "cs47l92-slim1",
index ed22361..3d67cbf 100644 (file)
@@ -869,7 +869,7 @@ static struct snd_soc_dai_driver cs53l30_dai = {
                .formats = CS53L30_FORMATS,
        },
        .ops = &cs53l30_ops,
-       .symmetric_rates = 1,
+       .symmetric_rate = 1,
 };
 
 static int cs53l30_component_probe(struct snd_soc_component *component)
index 2f10991..8ab2281 100644 (file)
@@ -1572,7 +1572,7 @@ static struct snd_soc_dai_driver soc_codec_cx2072x_dai[] = {
                        .formats = CX2072X_FORMATS,
                },
                .ops = &cx2072x_dai_ops,
-               .symmetric_rates = 1,
+               .symmetric_rate = 1,
        },
        { /* plabayck only, return echo reference to Conexant DSP chip */
                .name = "cx2072x-dsp",
index 3d05c37..8af344b 100644 (file)
@@ -1059,7 +1059,7 @@ static struct snd_soc_dai_driver da7210_dai = {
                .formats = DA7210_FORMATS,
        },
        .ops = &da7210_dai_ops,
-       .symmetric_rates = 1,
+       .symmetric_rate = 1,
 };
 
 static int da7210_probe(struct snd_soc_component *component)
index 7240246..3ab8938 100644 (file)
@@ -1551,7 +1551,7 @@ static struct snd_soc_dai_driver da7213_dai = {
                .formats = DA7213_FORMATS,
        },
        .ops = &da7213_dai_ops,
-       .symmetric_rates = 1,
+       .symmetric_rate = 1,
 };
 
 static int da7213_set_auto_pll(struct snd_soc_component *component, bool enable)
index 2bfafbe..ea426d9 100644 (file)
@@ -2194,9 +2194,9 @@ static struct snd_soc_dai_driver da7218_dai = {
                .formats = DA7218_FORMATS,
        },
        .ops = &da7218_dai_ops,
-       .symmetric_rates = 1,
+       .symmetric_rate = 1,
        .symmetric_channels = 1,
-       .symmetric_samplebits = 1,
+       .symmetric_sample_bits = 1,
 };
 
 
@@ -2278,14 +2278,12 @@ static irqreturn_t da7218_irq_thread(int irq, void *data)
  * DT
  */
 
-#ifdef CONFIG_OF
 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);
-#endif
 
 static inline int da7218_of_get_id(struct device *dev)
 {
@@ -3311,7 +3309,7 @@ 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),
+               .of_match_table = da7218_of_match,
        },
        .probe          = da7218_i2c_probe,
        .id_table       = da7218_i2c_id,
index e9b45da..13009d0 100644 (file)
@@ -1692,9 +1692,9 @@ static struct snd_soc_dai_driver da7219_dai = {
                .formats = DA7219_FORMATS,
        },
        .ops = &da7219_dai_ops,
-       .symmetric_rates = 1,
+       .symmetric_rate = 1,
        .symmetric_channels = 1,
-       .symmetric_samplebits = 1,
+       .symmetric_sample_bits = 1,
 };
 
 
index aed92f6..a9676b2 100644 (file)
@@ -1347,7 +1347,7 @@ static struct snd_soc_dai_driver da9055_dai = {
                .formats = DA9055_FORMATS,
        },
        .ops = &da9055_dai_ops,
-       .symmetric_rates = 1,
+       .symmetric_rate = 1,
 };
 
 static int da9055_set_bias_level(struct snd_soc_component *component,
index f9ec5cf..d632055 100644 (file)
@@ -543,7 +543,7 @@ static struct snd_soc_dai_driver es8316_dai = {
                .formats = ES8316_FORMATS,
        },
        .ops = &es8316_ops,
-       .symmetric_rates = 1,
+       .symmetric_rate = 1,
 };
 
 static void es8316_enable_micbias_for_mic_gnd_short_detect(
@@ -681,6 +681,9 @@ static void es8316_disable_jack_detect(struct snd_soc_component *component)
 {
        struct es8316_priv *es8316 = snd_soc_component_get_drvdata(component);
 
+       if (!es8316->jack)
+               return; /* Already disabled (or never enabled) */
+
        disable_irq(es8316->irq);
 
        mutex_lock(&es8316->lock);
index 7e26231..9632afc 100644 (file)
@@ -715,7 +715,7 @@ static struct snd_soc_dai_driver es8328_dai = {
                .formats = ES8328_FORMATS,
        },
        .ops = &es8328_dai_ops,
-       .symmetric_rates = 1,
+       .symmetric_rate = 1,
 };
 
 static int es8328_suspend(struct snd_soc_component *component)
@@ -809,8 +809,7 @@ static void es8328_remove(struct snd_soc_component *component)
 
        es8328 = snd_soc_component_get_drvdata(component);
 
-       if (es8328->clk)
-               clk_disable_unprepare(es8328->clk);
+       clk_disable_unprepare(es8328->clk);
 
        regulator_bulk_disable(ARRAY_SIZE(es8328->supplies),
                               es8328->supplies);
index 0f3ac22..422539f 100644 (file)
@@ -489,6 +489,7 @@ static int hdmi_codec_hw_params(struct snd_pcm_substream *substream,
        hp.sample_rate = params_rate(params);
        hp.channels = params_channels(params);
 
+       cf->bit_fmt = params_format(params);
        return hcp->hcd.ops->hw_params(dai->dev->parent, hcp->hcd.data,
                                       cf, &hp);
 }
@@ -617,7 +618,8 @@ static const struct snd_soc_dai_ops hdmi_codec_spdif_dai_ops = {
                         SNDRV_PCM_FMTBIT_S20_3LE | SNDRV_PCM_FMTBIT_S20_3BE |\
                         SNDRV_PCM_FMTBIT_S24_3LE | SNDRV_PCM_FMTBIT_S24_3BE |\
                         SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S24_BE |\
-                        SNDRV_PCM_FMTBIT_S32_LE | SNDRV_PCM_FMTBIT_S32_BE)
+                        SNDRV_PCM_FMTBIT_S32_LE | SNDRV_PCM_FMTBIT_S32_BE |\
+                        SNDRV_PCM_FMTBIT_IEC958_SUBFRAME_LE)
 
 static int hdmi_codec_pcm_new(struct snd_soc_pcm_runtime *rtd,
                              struct snd_soc_dai *dai)
index 4dbce24..e05c4f2 100644 (file)
@@ -325,7 +325,7 @@ static struct snd_soc_dai_driver rk3036_codec_dai_driver[] = {
                        .formats = RK3036_CODEC_FMTS,
                },
                .ops = &rk3036_codec_dai_ops,
-               .symmetric_rates = 1,
+               .symmetric_rate = 1,
        },
 };
 
index 5e58bfe..081485f 100644 (file)
@@ -214,7 +214,7 @@ static struct snd_soc_dai_driver jz4740_codec_dai = {
                .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S8,
        },
        .ops = &jz4740_codec_dai_ops,
-       .symmetric_rates = 1,
+       .symmetric_rate = 1,
 };
 
 static void jz4740_codec_wakeup(struct regmap *regmap)
diff --git a/sound/soc/codecs/jz4760.c b/sound/soc/codecs/jz4760.c
new file mode 100644 (file)
index 0000000..e8f28cc
--- /dev/null
@@ -0,0 +1,889 @@
+// SPDX-License-Identifier: GPL-2.0
+//
+// Ingenic JZ4760 CODEC driver
+//
+// Copyright (C) 2021, Christophe Branchereau <cbranchereau@gmail.com>
+// Copyright (C) 2021, Paul Cercueil <paul@crapouillou.net>
+
+#include <linux/bitfield.h>
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/iopoll.h>
+#include <linux/module.h>
+#include <linux/regmap.h>
+#include <linux/time64.h>
+
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/soc-dai.h>
+#include <sound/soc-dapm.h>
+#include <sound/tlv.h>
+
+#define ICDC_RGADW_OFFSET              0x00
+#define ICDC_RGDATA_OFFSET             0x04
+
+/* ICDC internal register access control register(RGADW) */
+#define ICDC_RGADW_RGWR                        BIT(16)
+#define        ICDC_RGADW_RGADDR_MASK          GENMASK(14, 8)
+#define        ICDC_RGADW_RGDIN_MASK           GENMASK(7, 0)
+
+/* ICDC internal register data output register (RGDATA)*/
+#define ICDC_RGDATA_IRQ                        BIT(8)
+#define ICDC_RGDATA_RGDOUT_MASK                GENMASK(7, 0)
+
+/* Internal register space, accessed through regmap */
+enum {
+       JZ4760_CODEC_REG_SR,
+       JZ4760_CODEC_REG_AICR,
+       JZ4760_CODEC_REG_CR1,
+       JZ4760_CODEC_REG_CR2,
+       JZ4760_CODEC_REG_CR3,
+       JZ4760_CODEC_REG_CR4,
+       JZ4760_CODEC_REG_CCR1,
+       JZ4760_CODEC_REG_CCR2,
+       JZ4760_CODEC_REG_PMR1,
+       JZ4760_CODEC_REG_PMR2,
+       JZ4760_CODEC_REG_ICR,
+       JZ4760_CODEC_REG_IFR,
+       JZ4760_CODEC_REG_GCR1,
+       JZ4760_CODEC_REG_GCR2,
+       JZ4760_CODEC_REG_GCR3,
+       JZ4760_CODEC_REG_GCR4,
+       JZ4760_CODEC_REG_GCR5,
+       JZ4760_CODEC_REG_GCR6,
+       JZ4760_CODEC_REG_GCR7,
+       JZ4760_CODEC_REG_GCR8,
+       JZ4760_CODEC_REG_GCR9,
+       JZ4760_CODEC_REG_AGC1,
+       JZ4760_CODEC_REG_AGC2,
+       JZ4760_CODEC_REG_AGC3,
+       JZ4760_CODEC_REG_AGC4,
+       JZ4760_CODEC_REG_AGC5,
+       JZ4760_CODEC_REG_MIX1,
+       JZ4760_CODEC_REG_MIX2,
+};
+
+#define REG_AICR_DAC_ADWL_MASK         GENMASK(7, 6)
+#define REG_AICR_DAC_SERIAL            BIT(3)
+#define REG_AICR_DAC_I2S               BIT(1)
+
+#define REG_AICR_ADC_ADWL_MASK         GENMASK(5, 4)
+
+#define REG_AICR_ADC_SERIAL            BIT(2)
+#define REG_AICR_ADC_I2S               BIT(0)
+
+#define REG_CR1_HP_LOAD                        BIT(7)
+#define REG_CR1_HP_MUTE                        BIT(5)
+#define REG_CR1_LO_MUTE_OFFSET         4
+#define REG_CR1_BTL_MUTE_OFFSET                3
+#define REG_CR1_OUTSEL_OFFSET          0
+#define REG_CR1_OUTSEL_MASK            GENMASK(1, REG_CR1_OUTSEL_OFFSET)
+
+#define REG_CR2_DAC_MONO               BIT(7)
+#define REG_CR2_DAC_MUTE               BIT(5)
+#define REG_CR2_DAC_NOMAD              BIT(1)
+#define REG_CR2_DAC_RIGHT_ONLY         BIT(0)
+
+#define REG_CR3_ADC_INSEL_OFFSET       2
+#define REG_CR3_ADC_INSEL_MASK         GENMASK(3, REG_CR3_ADC_INSEL_OFFSET)
+#define REG_CR3_MICSTEREO_OFFSET       1
+#define REG_CR3_MICDIFF_OFFSET         0
+
+#define REG_CR4_ADC_HPF_OFFSET         7
+#define REG_CR4_ADC_RIGHT_ONLY         BIT(0)
+
+#define REG_CCR1_CRYSTAL_MASK          GENMASK(3, 0)
+
+#define REG_CCR2_DAC_FREQ_MASK         GENMASK(7, 4)
+#define REG_CCR2_ADC_FREQ_MASK         GENMASK(3, 0)
+
+#define REG_PMR1_SB                    BIT(7)
+#define REG_PMR1_SB_SLEEP              BIT(6)
+#define REG_PMR1_SB_AIP_OFFSET         5
+#define REG_PMR1_SB_LINE_OFFSET                4
+#define REG_PMR1_SB_MIC1_OFFSET                3
+#define REG_PMR1_SB_MIC2_OFFSET                2
+#define REG_PMR1_SB_BYPASS_OFFSET      1
+#define REG_PMR1_SB_MICBIAS_OFFSET     0
+
+#define REG_PMR2_SB_ADC_OFFSET         4
+#define REG_PMR2_SB_HP_OFFSET          3
+#define REG_PMR2_SB_BTL_OFFSET         2
+#define REG_PMR2_SB_LOUT_OFFSET                1
+#define REG_PMR2_SB_DAC_OFFSET         0
+
+#define REG_ICR_INT_FORM_MASK          GENMASK(7, 6)
+#define REG_ICR_ALL_MASK               GENMASK(5, 0)
+#define REG_ICR_JACK_MASK              BIT(5)
+#define REG_ICR_SCMC_MASK              BIT(4)
+#define REG_ICR_RUP_MASK               BIT(3)
+#define REG_ICR_RDO_MASK               BIT(2)
+#define REG_ICR_GUP_MASK               BIT(1)
+#define REG_ICR_GDO_MASK               BIT(0)
+
+#define REG_IFR_ALL_MASK               GENMASK(5, 0)
+#define REG_IFR_JACK                   BIT(6)
+#define REG_IFR_JACK_EVENT             BIT(5)
+#define REG_IFR_SCMC                   BIT(4)
+#define REG_IFR_RUP                    BIT(3)
+#define REG_IFR_RDO                    BIT(2)
+#define REG_IFR_GUP                    BIT(1)
+#define REG_IFR_GDO                    BIT(0)
+
+#define REG_GCR_GAIN_OFFSET            0
+#define REG_GCR_GAIN_MAX               0x1f
+
+#define REG_GCR_RL                     BIT(7)
+
+#define REG_GCR_GIM1_MASK              GENMASK(5, 3)
+#define REG_GCR_GIM2_MASK              GENMASK(2, 0)
+#define REG_GCR_GIM_GAIN_MAX           7
+
+#define REG_AGC1_EN                    BIT(7)
+#define REG_AGC1_TARGET_MASK           GENMASK(5, 2)
+
+#define REG_AGC2_NG_THR_MASK           GENMASK(6, 4)
+#define REG_AGC2_HOLD_MASK             GENMASK(3, 0)
+
+#define REG_AGC3_ATK_MASK              GENMASK(7, 4)
+#define REG_AGC3_DCY_MASK              GENMASK(3, 0)
+
+#define REG_AGC4_AGC_MAX_MASK          GENMASK(4, 0)
+
+#define REG_AGC5_AGC_MIN_MASK          GENMASK(4, 0)
+
+#define REG_MIX1_MIX_REC_MASK          GENMASK(7, 6)
+#define REG_MIX1_GIMIX_MASK            GENMASK(4, 0)
+
+#define REG_MIX2_DAC_MIX_MASK          GENMASK(7, 6)
+#define REG_MIX2_GOMIX_MASK            GENMASK(4, 0)
+
+/* codec private data */
+struct jz_codec {
+       struct device *dev;
+       struct regmap *regmap;
+       void __iomem *base;
+       struct clk *clk;
+};
+
+static int jz4760_codec_set_bias_level(struct snd_soc_component *codec,
+                                      enum snd_soc_bias_level level)
+{
+       struct jz_codec *jz_codec = snd_soc_component_get_drvdata(codec);
+       struct regmap *regmap = jz_codec->regmap;
+
+       switch (level) {
+       case SND_SOC_BIAS_PREPARE:
+               /* Reset all interrupt flags. */
+               regmap_write(regmap, JZ4760_CODEC_REG_IFR, REG_IFR_ALL_MASK);
+
+               regmap_clear_bits(regmap, JZ4760_CODEC_REG_PMR1, REG_PMR1_SB);
+               msleep(250);
+               regmap_clear_bits(regmap, JZ4760_CODEC_REG_PMR1, REG_PMR1_SB_SLEEP);
+               msleep(400);
+               break;
+       case SND_SOC_BIAS_STANDBY:
+               regmap_set_bits(regmap, JZ4760_CODEC_REG_PMR1, REG_PMR1_SB_SLEEP);
+               regmap_set_bits(regmap, JZ4760_CODEC_REG_PMR1, REG_PMR1_SB);
+               break;
+       default:
+               break;
+       }
+
+       return 0;
+}
+
+static int jz4760_codec_startup(struct snd_pcm_substream *substream,
+                               struct snd_soc_dai *dai)
+{
+       struct snd_soc_component *codec = dai->component;
+       struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(codec);
+       int ret;
+
+       /*
+        * SYSCLK output from the codec to the AIC is required to keep the
+        * DMA transfer going during playback when all audible outputs have
+        * been disabled.
+        */
+       if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+               ret = snd_soc_dapm_force_enable_pin(dapm, "SYSCLK");
+       return 0;
+}
+
+static void jz4760_codec_shutdown(struct snd_pcm_substream *substream,
+                                 struct snd_soc_dai *dai)
+{
+       struct snd_soc_component *codec = dai->component;
+       struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(codec);
+
+       if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+               snd_soc_dapm_disable_pin(dapm, "SYSCLK");
+}
+
+
+static int jz4760_codec_pcm_trigger(struct snd_pcm_substream *substream,
+                                   int cmd, struct snd_soc_dai *dai)
+{
+       struct snd_soc_component *codec = dai->component;
+       int ret = 0;
+
+       switch (cmd) {
+       case SNDRV_PCM_TRIGGER_START:
+       case SNDRV_PCM_TRIGGER_RESUME:
+       case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+               if (substream->stream != SNDRV_PCM_STREAM_PLAYBACK)
+                       snd_soc_component_force_bias_level(codec, SND_SOC_BIAS_ON);
+               break;
+       case SNDRV_PCM_TRIGGER_STOP:
+       case SNDRV_PCM_TRIGGER_SUSPEND:
+       case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+               /* do nothing */
+               break;
+       default:
+               ret = -EINVAL;
+       }
+
+       return ret;
+}
+
+static int jz4760_codec_mute_stream(struct snd_soc_dai *dai, int mute, int direction)
+{
+       struct snd_soc_component *codec = dai->component;
+       struct jz_codec *jz_codec = snd_soc_component_get_drvdata(codec);
+       unsigned int gain_bit = mute ? REG_IFR_GDO : REG_IFR_GUP;
+       unsigned int val, reg;
+       int change, err;
+
+       change = snd_soc_component_update_bits(codec, JZ4760_CODEC_REG_CR2,
+                                              REG_CR2_DAC_MUTE,
+                                              mute ? REG_CR2_DAC_MUTE : 0);
+       if (change == 1) {
+               regmap_read(jz_codec->regmap, JZ4760_CODEC_REG_PMR2, &val);
+
+               if (val & BIT(REG_PMR2_SB_DAC_OFFSET))
+                       return 1;
+
+               err = regmap_read_poll_timeout(jz_codec->regmap,
+                                              JZ4760_CODEC_REG_IFR,
+                                              val, val & gain_bit,
+                                              1000, 1 * USEC_PER_SEC);
+               if (err) {
+                       dev_err(jz_codec->dev,
+                               "Timeout while setting digital mute: %d", err);
+                       return err;
+               }
+
+               /* clear GUP/GDO flag */
+               regmap_write(jz_codec->regmap, JZ4760_CODEC_REG_IFR, gain_bit);
+       }
+
+       regmap_read(jz_codec->regmap, JZ4760_CODEC_REG_CR2, &reg);
+
+       return 0;
+}
+
+/* unit: 0.01dB */
+static const DECLARE_TLV_DB_MINMAX_MUTE(dac_tlv, -3100, 100);
+static const DECLARE_TLV_DB_SCALE(adc_tlv, 0, 100, 0);
+static const DECLARE_TLV_DB_MINMAX(out_tlv, -2500, 100);
+static const DECLARE_TLV_DB_SCALE(linein_tlv, -2500, 100, 0);
+
+/* Unconditional controls. */
+static const struct snd_kcontrol_new jz4760_codec_snd_controls[] = {
+       /* record gain control */
+       SOC_DOUBLE_R_TLV("PCM Capture Volume",
+                        JZ4760_CODEC_REG_GCR9, JZ4760_CODEC_REG_GCR8,
+                        REG_GCR_GAIN_OFFSET, REG_GCR_GAIN_MAX, 0, adc_tlv),
+
+       SOC_DOUBLE_R_TLV("Line In Bypass Playback Volume",
+                        JZ4760_CODEC_REG_GCR4, JZ4760_CODEC_REG_GCR3,
+                        REG_GCR_GAIN_OFFSET, REG_GCR_GAIN_MAX, 1, linein_tlv),
+
+       SOC_SINGLE("High-Pass Filter Capture Switch",
+                  JZ4760_CODEC_REG_CR4,
+                  REG_CR4_ADC_HPF_OFFSET, 1, 0),
+};
+
+static const struct snd_kcontrol_new jz4760_codec_pcm_playback_controls[] = {
+       {
+               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+               .name = "Volume",
+               .info = snd_soc_info_volsw,
+               .access = SNDRV_CTL_ELEM_ACCESS_TLV_READ
+                       | SNDRV_CTL_ELEM_ACCESS_READWRITE,
+               .tlv.p = dac_tlv,
+               .get = snd_soc_dapm_get_volsw,
+               .put = snd_soc_dapm_put_volsw,
+               .private_value = SOC_DOUBLE_R_VALUE(JZ4760_CODEC_REG_GCR6,
+                                                   JZ4760_CODEC_REG_GCR5,
+                                                   REG_GCR_GAIN_OFFSET,
+                                                   REG_GCR_GAIN_MAX, 1),
+       },
+};
+
+static const struct snd_kcontrol_new jz4760_codec_hp_playback_controls[] = {
+       {
+               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+               .name = "Volume",
+               .info = snd_soc_info_volsw,
+               .access = SNDRV_CTL_ELEM_ACCESS_TLV_READ
+                       | SNDRV_CTL_ELEM_ACCESS_READWRITE,
+               .tlv.p = out_tlv,
+               .get = snd_soc_dapm_get_volsw,
+               .put = snd_soc_dapm_put_volsw,
+               .private_value = SOC_DOUBLE_R_VALUE(JZ4760_CODEC_REG_GCR2,
+                                                   JZ4760_CODEC_REG_GCR1,
+                                                   REG_GCR_GAIN_OFFSET,
+                                                   REG_GCR_GAIN_MAX, 1),
+       },
+};
+
+static int hpout_event(struct snd_soc_dapm_widget *w,
+                      struct snd_kcontrol *kcontrol, int event)
+{
+       struct snd_soc_component *codec = snd_soc_dapm_to_component(w->dapm);
+       struct jz_codec *jz_codec = snd_soc_component_get_drvdata(codec);
+       unsigned int val;
+       int err;
+
+       switch (event) {
+       case SND_SOC_DAPM_PRE_PMU:
+               /* unmute HP */
+               regmap_clear_bits(jz_codec->regmap, JZ4760_CODEC_REG_CR1,
+                                 REG_CR1_HP_MUTE);
+               break;
+
+       case SND_SOC_DAPM_POST_PMU:
+               /* wait for ramp-up complete (RUP) */
+               err = regmap_read_poll_timeout(jz_codec->regmap,
+                                              JZ4760_CODEC_REG_IFR,
+                                              val, val & REG_IFR_RUP,
+                                              1000, 1 * USEC_PER_SEC);
+               if (err) {
+                       dev_err(jz_codec->dev, "RUP timeout: %d", err);
+                       return err;
+               }
+
+               /* clear RUP flag */
+               regmap_set_bits(jz_codec->regmap, JZ4760_CODEC_REG_IFR,
+                               REG_IFR_RUP);
+
+               break;
+
+       case SND_SOC_DAPM_POST_PMD:
+               /* mute HP */
+               regmap_set_bits(jz_codec->regmap, JZ4760_CODEC_REG_CR1,
+                               REG_CR1_HP_MUTE);
+
+               err = regmap_read_poll_timeout(jz_codec->regmap,
+                                              JZ4760_CODEC_REG_IFR,
+                                              val, val & REG_IFR_RDO,
+                                              1000, 1 * USEC_PER_SEC);
+               if (err) {
+                       dev_err(jz_codec->dev, "RDO timeout: %d", err);
+                       return err;
+               }
+
+               /* clear RDO flag */
+               regmap_set_bits(jz_codec->regmap, JZ4760_CODEC_REG_IFR,
+                               REG_IFR_RDO);
+
+               break;
+       }
+
+       return 0;
+}
+
+static const char * const jz4760_codec_hp_texts[] = {
+       "PCM", "Line In", "Mic 1", "Mic 2"
+};
+
+static const unsigned int jz4760_codec_hp_values[] = { 3, 2, 0, 1 };
+
+static SOC_VALUE_ENUM_SINGLE_DECL(jz4760_codec_hp_enum,
+                                 JZ4760_CODEC_REG_CR1,
+                                 REG_CR1_OUTSEL_OFFSET,
+                                 REG_CR1_OUTSEL_MASK >> REG_CR1_OUTSEL_OFFSET,
+                                 jz4760_codec_hp_texts,
+                                 jz4760_codec_hp_values);
+static const struct snd_kcontrol_new jz4760_codec_hp_source =
+                       SOC_DAPM_ENUM("Route", jz4760_codec_hp_enum);
+
+static const char * const jz4760_codec_cap_texts[] = {
+       "Line In", "Mic 1", "Mic 2"
+};
+
+static const unsigned int jz4760_codec_cap_values[] = { 2, 0, 1 };
+
+static SOC_VALUE_ENUM_SINGLE_DECL(jz4760_codec_cap_enum,
+                                 JZ4760_CODEC_REG_CR3,
+                                 REG_CR3_ADC_INSEL_OFFSET,
+                                 REG_CR3_ADC_INSEL_MASK >> REG_CR3_ADC_INSEL_OFFSET,
+                                 jz4760_codec_cap_texts,
+                                 jz4760_codec_cap_values);
+static const struct snd_kcontrol_new jz4760_codec_cap_source =
+                       SOC_DAPM_ENUM("Route", jz4760_codec_cap_enum);
+
+static const struct snd_kcontrol_new jz4760_codec_mic_controls[] = {
+       SOC_DAPM_SINGLE("Stereo Capture Switch", JZ4760_CODEC_REG_CR3,
+                       REG_CR3_MICSTEREO_OFFSET, 1, 0),
+};
+
+static const struct snd_kcontrol_new jz4760_codec_line_out_switch =
+       SOC_DAPM_SINGLE("Switch", JZ4760_CODEC_REG_CR1,
+                       REG_CR1_LO_MUTE_OFFSET, 0, 0);
+static const struct snd_kcontrol_new jz4760_codec_btl_out_switch =
+       SOC_DAPM_SINGLE("Switch", JZ4760_CODEC_REG_CR1,
+                       REG_CR1_BTL_MUTE_OFFSET, 0, 0);
+
+static const struct snd_soc_dapm_widget jz4760_codec_dapm_widgets[] = {
+       SND_SOC_DAPM_PGA_E("HP Out", JZ4760_CODEC_REG_PMR2,
+                          REG_PMR2_SB_HP_OFFSET, 1, NULL, 0, hpout_event,
+                          SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+                          SND_SOC_DAPM_POST_PMD),
+
+       SND_SOC_DAPM_SWITCH("Line Out", JZ4760_CODEC_REG_PMR2,
+                           REG_PMR2_SB_LOUT_OFFSET, 1,
+                           &jz4760_codec_line_out_switch),
+
+       SND_SOC_DAPM_SWITCH("BTL Out", JZ4760_CODEC_REG_PMR2,
+                           REG_PMR2_SB_BTL_OFFSET, 1,
+                           &jz4760_codec_btl_out_switch),
+
+       SND_SOC_DAPM_PGA("Line In", JZ4760_CODEC_REG_PMR1,
+                        REG_PMR1_SB_LINE_OFFSET, 1, NULL, 0),
+
+       SND_SOC_DAPM_MUX("Headphones Source", SND_SOC_NOPM, 0, 0,
+                        &jz4760_codec_hp_source),
+
+       SND_SOC_DAPM_MUX("Capture Source", SND_SOC_NOPM, 0, 0,
+                        &jz4760_codec_cap_source),
+
+       SND_SOC_DAPM_PGA("Mic 1", JZ4760_CODEC_REG_PMR1,
+                        REG_PMR1_SB_MIC1_OFFSET, 1, NULL, 0),
+
+       SND_SOC_DAPM_PGA("Mic 2", JZ4760_CODEC_REG_PMR1,
+                        REG_PMR1_SB_MIC2_OFFSET, 1, NULL, 0),
+
+       SND_SOC_DAPM_PGA("Mic Diff", JZ4760_CODEC_REG_CR3,
+                        REG_CR3_MICDIFF_OFFSET, 0, NULL, 0),
+
+       SND_SOC_DAPM_MIXER("Mic", SND_SOC_NOPM, 0, 0,
+                          jz4760_codec_mic_controls,
+                          ARRAY_SIZE(jz4760_codec_mic_controls)),
+
+       SND_SOC_DAPM_PGA("Line In Bypass", JZ4760_CODEC_REG_PMR1,
+                        REG_PMR1_SB_BYPASS_OFFSET, 1, NULL, 0),
+
+       SND_SOC_DAPM_ADC("ADC", "Capture", JZ4760_CODEC_REG_PMR2,
+                        REG_PMR2_SB_ADC_OFFSET, 1),
+
+       SND_SOC_DAPM_DAC("DAC", "Playback", JZ4760_CODEC_REG_PMR2,
+                        REG_PMR2_SB_DAC_OFFSET, 1),
+
+       SND_SOC_DAPM_MIXER("PCM Playback", SND_SOC_NOPM, 0, 0,
+                          jz4760_codec_pcm_playback_controls,
+                          ARRAY_SIZE(jz4760_codec_pcm_playback_controls)),
+
+       SND_SOC_DAPM_MIXER("Headphones Playback", SND_SOC_NOPM, 0, 0,
+                          jz4760_codec_hp_playback_controls,
+                          ARRAY_SIZE(jz4760_codec_hp_playback_controls)),
+
+       SND_SOC_DAPM_SUPPLY("MICBIAS", JZ4760_CODEC_REG_PMR1,
+                           REG_PMR1_SB_MICBIAS_OFFSET, 1, NULL, 0),
+
+       SND_SOC_DAPM_INPUT("MIC1P"),
+       SND_SOC_DAPM_INPUT("MIC1N"),
+       SND_SOC_DAPM_INPUT("MIC2P"),
+       SND_SOC_DAPM_INPUT("MIC2N"),
+
+       SND_SOC_DAPM_INPUT("LLINEIN"),
+       SND_SOC_DAPM_INPUT("RLINEIN"),
+
+       SND_SOC_DAPM_OUTPUT("LHPOUT"),
+       SND_SOC_DAPM_OUTPUT("RHPOUT"),
+
+       SND_SOC_DAPM_OUTPUT("LOUT"),
+       SND_SOC_DAPM_OUTPUT("ROUT"),
+
+       SND_SOC_DAPM_OUTPUT("BTLP"),
+       SND_SOC_DAPM_OUTPUT("BTLN"),
+
+       SND_SOC_DAPM_OUTPUT("SYSCLK"),
+};
+
+/* Unconditional routes. */
+static const struct snd_soc_dapm_route jz4760_codec_dapm_routes[] = {
+       { "Mic 1", NULL, "MIC1P" },
+       { "Mic Diff", NULL, "MIC1N" },
+       { "Mic 1", NULL, "Mic Diff" },
+       { "Mic 2", NULL, "MIC2P" },
+       { "Mic Diff", NULL, "MIC2N" },
+       { "Mic 2", NULL, "Mic Diff" },
+
+       { "Line In", NULL, "LLINEIN" },
+       { "Line In", NULL, "RLINEIN" },
+
+       { "Mic", "Stereo Capture Switch", "Mic 1" },
+       { "Mic", "Stereo Capture Switch", "Mic 2" },
+       { "Headphones Source", "Mic 1", "Mic" },
+       { "Headphones Source", "Mic 2", "Mic" },
+       { "Capture Source", "Mic 1", "Mic" },
+       { "Capture Source", "Mic 2", "Mic" },
+
+       { "Capture Source", "Line In", "Line In" },
+       { "Capture Source", "Mic 1", "Mic 1" },
+       { "Capture Source", "Mic 2", "Mic 2" },
+       { "ADC", NULL, "Capture Source" },
+
+       { "Line In Bypass", NULL, "Line In" },
+
+       { "Headphones Source", "Mic 1", "Mic 1" },
+       { "Headphones Source", "Mic 2", "Mic 2" },
+       { "Headphones Source", "Line In", "Line In Bypass" },
+       { "Headphones Source", "PCM", "Headphones Playback" },
+       { "HP Out", NULL, "Headphones Source" },
+
+       { "LHPOUT", NULL, "HP Out" },
+       { "RHPOUT", NULL, "HP Out" },
+       { "Line Out", "Switch", "HP Out" },
+
+       { "LOUT", NULL, "Line Out" },
+       { "ROUT", NULL, "Line Out" },
+       { "BTL Out", "Switch", "Line Out" },
+
+       { "BTLP", NULL, "BTL Out"},
+       { "BTLN", NULL, "BTL Out"},
+
+       { "PCM Playback", "Volume", "DAC" },
+       { "Headphones Playback", "Volume", "PCM Playback" },
+
+       { "SYSCLK", NULL, "DAC" },
+};
+
+static void jz4760_codec_codec_init_regs(struct snd_soc_component *codec)
+{
+       struct jz_codec *jz_codec = snd_soc_component_get_drvdata(codec);
+       struct regmap *regmap = jz_codec->regmap;
+
+       /* Collect updates for later sending. */
+       regcache_cache_only(regmap, true);
+
+       /* default Amp output to PCM */
+       regmap_set_bits(regmap, JZ4760_CODEC_REG_CR1, REG_CR1_OUTSEL_MASK);
+
+       /* Disable stereo mic */
+       regmap_clear_bits(regmap, JZ4760_CODEC_REG_CR3,
+                         BIT(REG_CR3_MICSTEREO_OFFSET));
+
+       /* Set mic 1 as default source for ADC */
+       regmap_clear_bits(regmap, JZ4760_CODEC_REG_CR3,
+                         REG_CR3_ADC_INSEL_MASK);
+
+       /* ADC/DAC: serial + i2s */
+       regmap_set_bits(regmap, JZ4760_CODEC_REG_AICR,
+                       REG_AICR_ADC_SERIAL | REG_AICR_ADC_I2S |
+                       REG_AICR_DAC_SERIAL | REG_AICR_DAC_I2S);
+
+       /* The generated IRQ is a high level */
+       regmap_clear_bits(regmap, JZ4760_CODEC_REG_ICR, REG_ICR_INT_FORM_MASK);
+       regmap_update_bits(regmap, JZ4760_CODEC_REG_ICR, REG_ICR_ALL_MASK,
+                          REG_ICR_JACK_MASK | REG_ICR_RUP_MASK |
+                          REG_ICR_RDO_MASK  | REG_ICR_GUP_MASK |
+                          REG_ICR_GDO_MASK);
+
+       /* 12M oscillator */
+       regmap_clear_bits(regmap, JZ4760_CODEC_REG_CCR1, REG_CCR1_CRYSTAL_MASK);
+
+       /* 0: 16ohm/220uF, 1: 10kohm/1uF */
+       regmap_clear_bits(regmap, JZ4760_CODEC_REG_CR1, REG_CR1_HP_LOAD);
+
+       /* default to NOMAD */
+       regmap_set_bits(jz_codec->regmap, JZ4760_CODEC_REG_CR2,
+                       REG_CR2_DAC_NOMAD);
+
+       /* disable automatic gain */
+       regmap_clear_bits(regmap, JZ4760_CODEC_REG_AGC1, REG_AGC1_EN);
+
+       /* Independent L/R DAC gain control */
+       regmap_clear_bits(regmap, JZ4760_CODEC_REG_GCR5,
+                         REG_GCR_RL);
+
+       /* Send collected updates. */
+       regcache_cache_only(regmap, false);
+       regcache_sync(regmap);
+}
+
+static int jz4760_codec_codec_probe(struct snd_soc_component *codec)
+{
+       struct jz_codec *jz_codec = snd_soc_component_get_drvdata(codec);
+
+       clk_prepare_enable(jz_codec->clk);
+
+       jz4760_codec_codec_init_regs(codec);
+
+       return 0;
+}
+
+static void jz4760_codec_codec_remove(struct snd_soc_component *codec)
+{
+       struct jz_codec *jz_codec = snd_soc_component_get_drvdata(codec);
+
+       clk_disable_unprepare(jz_codec->clk);
+}
+
+static const struct snd_soc_component_driver jz4760_codec_soc_codec_dev = {
+       .probe                  = jz4760_codec_codec_probe,
+       .remove                 = jz4760_codec_codec_remove,
+       .set_bias_level         = jz4760_codec_set_bias_level,
+       .controls               = jz4760_codec_snd_controls,
+       .num_controls           = ARRAY_SIZE(jz4760_codec_snd_controls),
+       .dapm_widgets           = jz4760_codec_dapm_widgets,
+       .num_dapm_widgets       = ARRAY_SIZE(jz4760_codec_dapm_widgets),
+       .dapm_routes            = jz4760_codec_dapm_routes,
+       .num_dapm_routes        = ARRAY_SIZE(jz4760_codec_dapm_routes),
+       .suspend_bias_off       = 1,
+       .use_pmdown_time        = 1,
+};
+
+static const unsigned int jz4760_codec_sample_rates[] = {
+       96000, 48000, 44100, 32000,
+       24000, 22050, 16000, 12000,
+       11025, 9600, 8000,
+};
+
+static int jz4760_codec_hw_params(struct snd_pcm_substream *substream,
+                                 struct snd_pcm_hw_params *params,
+                                 struct snd_soc_dai *dai)
+{
+       struct jz_codec *codec = snd_soc_component_get_drvdata(dai->component);
+       unsigned int rate, bit_width;
+
+       switch (params_format(params)) {
+       case SNDRV_PCM_FORMAT_S16_LE:
+               bit_width = 0;
+               break;
+       case SNDRV_PCM_FORMAT_S18_3LE:
+               bit_width = 1;
+               break;
+       case SNDRV_PCM_FORMAT_S20_3LE:
+               bit_width = 2;
+               break;
+       case SNDRV_PCM_FORMAT_S24_3LE:
+               bit_width = 3;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       for (rate = 0; rate < ARRAY_SIZE(jz4760_codec_sample_rates); rate++) {
+               if (jz4760_codec_sample_rates[rate] == params_rate(params))
+                       break;
+       }
+
+       if (rate == ARRAY_SIZE(jz4760_codec_sample_rates))
+               return -EINVAL;
+
+       if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+               regmap_update_bits(codec->regmap, JZ4760_CODEC_REG_AICR,
+                                  REG_AICR_DAC_ADWL_MASK,
+                                  FIELD_PREP(REG_AICR_DAC_ADWL_MASK, bit_width));
+               regmap_update_bits(codec->regmap, JZ4760_CODEC_REG_CCR2,
+                                  REG_CCR2_DAC_FREQ_MASK,
+                                  FIELD_PREP(REG_CCR2_DAC_FREQ_MASK, rate));
+       } else {
+               regmap_update_bits(codec->regmap, JZ4760_CODEC_REG_AICR,
+                                  REG_AICR_ADC_ADWL_MASK,
+                                  FIELD_PREP(REG_AICR_ADC_ADWL_MASK, bit_width));
+               regmap_update_bits(codec->regmap, JZ4760_CODEC_REG_CCR2,
+                                  REG_CCR2_ADC_FREQ_MASK,
+                                  FIELD_PREP(REG_CCR2_ADC_FREQ_MASK, rate));
+       }
+
+       return 0;
+}
+
+static const struct snd_soc_dai_ops jz4760_codec_dai_ops = {
+       .startup        = jz4760_codec_startup,
+       .shutdown       = jz4760_codec_shutdown,
+       .hw_params      = jz4760_codec_hw_params,
+       .trigger        = jz4760_codec_pcm_trigger,
+       .mute_stream    = jz4760_codec_mute_stream,
+       .no_capture_mute = 1,
+};
+
+#define JZ_CODEC_FORMATS (SNDRV_PCM_FMTBIT_S16_LE  | \
+                         SNDRV_PCM_FMTBIT_S18_3LE | \
+                         SNDRV_PCM_FMTBIT_S20_3LE | \
+                         SNDRV_PCM_FMTBIT_S24_3LE)
+
+static struct snd_soc_dai_driver jz4760_codec_dai = {
+       .name = "jz4760-hifi",
+       .playback = {
+               .stream_name = "Playback",
+               .channels_min = 2,
+               .channels_max = 2,
+               .rates = SNDRV_PCM_RATE_8000_96000,
+               .formats = JZ_CODEC_FORMATS,
+       },
+       .capture = {
+               .stream_name = "Capture",
+               .channels_min = 2,
+               .channels_max = 2,
+               .rates = SNDRV_PCM_RATE_8000_96000,
+               .formats = JZ_CODEC_FORMATS,
+       },
+       .ops = &jz4760_codec_dai_ops,
+};
+
+static bool jz4760_codec_volatile(struct device *dev, unsigned int reg)
+{
+       return reg == JZ4760_CODEC_REG_SR || reg == JZ4760_CODEC_REG_IFR;
+}
+
+static bool jz4760_codec_writeable(struct device *dev, unsigned int reg)
+{
+       switch (reg) {
+       case JZ4760_CODEC_REG_SR:
+               return false;
+       default:
+               return true;
+       }
+}
+
+static int jz4760_codec_io_wait(struct jz_codec *codec)
+{
+       u32 reg;
+
+       return readl_poll_timeout(codec->base + ICDC_RGADW_OFFSET, reg,
+                                 !(reg & ICDC_RGADW_RGWR),
+                                 1000, 1 * USEC_PER_SEC);
+}
+
+static int jz4760_codec_reg_read(void *context, unsigned int reg,
+                                unsigned int *val)
+{
+       struct jz_codec *codec = context;
+       unsigned int i;
+       u32 tmp;
+       int ret;
+
+       ret = jz4760_codec_io_wait(codec);
+       if (ret)
+               return ret;
+
+       tmp = readl(codec->base + ICDC_RGADW_OFFSET);
+       tmp &= ~ICDC_RGADW_RGADDR_MASK;
+       tmp |= FIELD_PREP(ICDC_RGADW_RGADDR_MASK, reg);
+       writel(tmp, codec->base + ICDC_RGADW_OFFSET);
+
+       /* wait 6+ cycles */
+       for (i = 0; i < 6; i++)
+               *val = readl(codec->base + ICDC_RGDATA_OFFSET) &
+                       ICDC_RGDATA_RGDOUT_MASK;
+
+       return 0;
+}
+
+static int jz4760_codec_reg_write(void *context, unsigned int reg,
+                                 unsigned int val)
+{
+       struct jz_codec *codec = context;
+       int ret;
+
+       ret = jz4760_codec_io_wait(codec);
+       if (ret)
+               return ret;
+
+       writel(ICDC_RGADW_RGWR | FIELD_PREP(ICDC_RGADW_RGADDR_MASK, reg) | val,
+              codec->base + ICDC_RGADW_OFFSET);
+
+       ret = jz4760_codec_io_wait(codec);
+       if (ret)
+               return ret;
+
+       return 0;
+}
+
+static const u8 jz4760_codec_reg_defaults[] = {
+       0x00, 0xFC, 0x1B, 0x20, 0x00, 0x80, 0x00, 0x00,
+       0xFF, 0x1F, 0x3F, 0x00, 0x06, 0x06, 0x06, 0x06,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x34, 0x07, 0x44,
+       0x1F, 0x00, 0x00, 0x00
+};
+
+static struct regmap_config jz4760_codec_regmap_config = {
+       .reg_bits = 7,
+       .val_bits = 8,
+
+       .max_register = JZ4760_CODEC_REG_MIX2,
+       .volatile_reg = jz4760_codec_volatile,
+       .writeable_reg = jz4760_codec_writeable,
+
+       .reg_read = jz4760_codec_reg_read,
+       .reg_write = jz4760_codec_reg_write,
+
+       .reg_defaults_raw = jz4760_codec_reg_defaults,
+       .num_reg_defaults_raw = ARRAY_SIZE(jz4760_codec_reg_defaults),
+       .cache_type = REGCACHE_FLAT,
+};
+
+static int jz4760_codec_probe(struct platform_device *pdev)
+{
+       struct device *dev = &pdev->dev;
+       struct jz_codec *codec;
+       int ret;
+
+       codec = devm_kzalloc(dev, sizeof(*codec), GFP_KERNEL);
+       if (!codec)
+               return -ENOMEM;
+
+       codec->dev = dev;
+
+       codec->base = devm_platform_ioremap_resource(pdev, 0);
+       if (IS_ERR(codec->base)) {
+               ret = PTR_ERR(codec->base);
+               dev_err(dev, "Failed to ioremap mmio memory: %d\n", ret);
+               return ret;
+       }
+
+       codec->regmap = devm_regmap_init(dev, NULL, codec,
+                                       &jz4760_codec_regmap_config);
+       if (IS_ERR(codec->regmap))
+               return PTR_ERR(codec->regmap);
+
+       codec->clk = devm_clk_get(dev, "aic");
+       if (IS_ERR(codec->clk))
+               return PTR_ERR(codec->clk);
+
+       platform_set_drvdata(pdev, codec);
+
+       ret = devm_snd_soc_register_component(dev, &jz4760_codec_soc_codec_dev,
+                                             &jz4760_codec_dai, 1);
+       if (ret) {
+               dev_err(dev, "Failed to register codec: %d\n", ret);
+               return ret;
+       }
+
+       return 0;
+}
+
+static const struct of_device_id jz4760_codec_of_matches[] = {
+       { .compatible = "ingenic,jz4760-codec", },
+       { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, jz4760_codec_of_matches);
+
+static struct platform_driver jz4760_codec_driver = {
+       .probe                  = jz4760_codec_probe,
+       .driver                 = {
+               .name           = "jz4760-codec",
+               .of_match_table = jz4760_codec_of_matches,
+       },
+};
+module_platform_driver(jz4760_codec_driver);
+
+MODULE_DESCRIPTION("JZ4760 SoC internal codec driver");
+MODULE_AUTHOR("Christophe Branchereau <cbranchereau@gmail.com>");
+MODULE_AUTHOR("Paul Cercueil <paul@crapouillou.net>");
+MODULE_LICENSE("GPL v2");
index 06ab61f..eb3dd0b 100644 (file)
@@ -1343,7 +1343,7 @@ static struct snd_soc_dai_driver lm49453_dai[] = {
                        .formats = LM49453_FORMATS,
                },
                .ops = &lm49453_headset_dai_ops,
-               .symmetric_rates = 1,
+               .symmetric_rate = 1,
        },
        {
                .name = "LM49453 Speaker",
index 3209b39..54426a9 100644 (file)
@@ -166,8 +166,8 @@ static struct snd_soc_dai_driver lochnagar_sc_dai[] = {
                        .formats = SNDRV_PCM_FMTBIT_S32_LE,
                },
                .ops = &lochnagar_sc_line_ops,
-               .symmetric_rates = true,
-               .symmetric_samplebits = true,
+               .symmetric_rate = true,
+               .symmetric_sample_bits = true,
        },
        {
                .name = "lochnagar-usb1",
@@ -186,8 +186,8 @@ static struct snd_soc_dai_driver lochnagar_sc_dai[] = {
                        .formats = SNDRV_PCM_FMTBIT_S32_LE,
                },
                .ops = &lochnagar_sc_usb_ops,
-               .symmetric_rates = true,
-               .symmetric_samplebits = true,
+               .symmetric_rate = true,
+               .symmetric_sample_bits = true,
        },
        {
                .name = "lochnagar-usb2",
@@ -206,8 +206,8 @@ static struct snd_soc_dai_driver lochnagar_sc_dai[] = {
                        .formats = SNDRV_PCM_FMTBIT_S32_LE,
                },
                .ops = &lochnagar_sc_usb_ops,
-               .symmetric_rates = true,
-               .symmetric_samplebits = true,
+               .symmetric_rate = true,
+               .symmetric_sample_bits = true,
        },
 };
 
diff --git a/sound/soc/codecs/lpass-rx-macro.c b/sound/soc/codecs/lpass-rx-macro.c
new file mode 100644 (file)
index 0000000..c9c21d2
--- /dev/null
@@ -0,0 +1,3599 @@
+// SPDX-License-Identifier: GPL-2.0-only
+// Copyright (c) 2018-2020, The Linux Foundation. All rights reserved.
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/platform_device.h>
+#include <linux/clk.h>
+#include <sound/soc.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc-dapm.h>
+#include <sound/tlv.h>
+#include <linux/of_clk.h>
+#include <linux/clk-provider.h>
+
+#define CDC_RX_TOP_TOP_CFG0            (0x0000)
+#define CDC_RX_TOP_SWR_CTRL            (0x0008)
+#define CDC_RX_TOP_DEBUG               (0x000C)
+#define CDC_RX_TOP_DEBUG_BUS           (0x0010)
+#define CDC_RX_TOP_DEBUG_EN0           (0x0014)
+#define CDC_RX_TOP_DEBUG_EN1           (0x0018)
+#define CDC_RX_TOP_DEBUG_EN2           (0x001C)
+#define CDC_RX_TOP_HPHL_COMP_WR_LSB    (0x0020)
+#define CDC_RX_TOP_HPHL_COMP_WR_MSB    (0x0024)
+#define CDC_RX_TOP_HPHL_COMP_LUT       (0x0028)
+#define CDC_RX_TOP_HPH_LUT_BYPASS_MASK BIT(7)
+#define CDC_RX_TOP_HPHL_COMP_RD_LSB    (0x002C)
+#define CDC_RX_TOP_HPHL_COMP_RD_MSB    (0x0030)
+#define CDC_RX_TOP_HPHR_COMP_WR_LSB    (0x0034)
+#define CDC_RX_TOP_HPHR_COMP_WR_MSB    (0x0038)
+#define CDC_RX_TOP_HPHR_COMP_LUT       (0x003C)
+#define CDC_RX_TOP_HPHR_COMP_RD_LSB    (0x0040)
+#define CDC_RX_TOP_HPHR_COMP_RD_MSB    (0x0044)
+#define CDC_RX_TOP_DSD0_DEBUG_CFG0     (0x0070)
+#define CDC_RX_TOP_DSD0_DEBUG_CFG1     (0x0074)
+#define CDC_RX_TOP_DSD0_DEBUG_CFG2     (0x0078)
+#define CDC_RX_TOP_DSD0_DEBUG_CFG3     (0x007C)
+#define CDC_RX_TOP_DSD1_DEBUG_CFG0     (0x0080)
+#define CDC_RX_TOP_DSD1_DEBUG_CFG1     (0x0084)
+#define CDC_RX_TOP_DSD1_DEBUG_CFG2     (0x0088)
+#define CDC_RX_TOP_DSD1_DEBUG_CFG3     (0x008C)
+#define CDC_RX_TOP_RX_I2S_CTL          (0x0090)
+#define CDC_RX_TOP_TX_I2S2_CTL         (0x0094)
+#define CDC_RX_TOP_I2S_CLK             (0x0098)
+#define CDC_RX_TOP_I2S_RESET           (0x009C)
+#define CDC_RX_TOP_I2S_MUX             (0x00A0)
+#define CDC_RX_CLK_RST_CTRL_MCLK_CONTROL       (0x0100)
+#define CDC_RX_CLK_MCLK_EN_MASK                BIT(0)
+#define CDC_RX_CLK_MCLK_ENABLE         BIT(0)
+#define CDC_RX_CLK_MCLK2_EN_MASK       BIT(1)
+#define CDC_RX_CLK_MCLK2_ENABLE                BIT(1)
+#define CDC_RX_CLK_RST_CTRL_FS_CNT_CONTROL     (0x0104)
+#define CDC_RX_FS_MCLK_CNT_EN_MASK     BIT(0)
+#define CDC_RX_FS_MCLK_CNT_ENABLE      BIT(0)
+#define CDC_RX_FS_MCLK_CNT_CLR_MASK    BIT(1)
+#define CDC_RX_FS_MCLK_CNT_CLR         BIT(1)
+#define CDC_RX_CLK_RST_CTRL_SWR_CONTROL        (0x0108)
+#define CDC_RX_SWR_CLK_EN_MASK         BIT(0)
+#define CDC_RX_SWR_RESET_MASK          BIT(1)
+#define CDC_RX_SWR_RESET               BIT(1)
+#define CDC_RX_CLK_RST_CTRL_DSD_CONTROL        (0x010C)
+#define CDC_RX_CLK_RST_CTRL_ASRC_SHARE_CONTROL (0x0110)
+#define CDC_RX_SOFTCLIP_CRC            (0x0140)
+#define CDC_RX_SOFTCLIP_CLK_EN_MASK    BIT(0)
+#define CDC_RX_SOFTCLIP_SOFTCLIP_CTRL  (0x0144)
+#define CDC_RX_SOFTCLIP_EN_MASK                BIT(0)
+#define CDC_RX_INP_MUX_RX_INT0_CFG0    (0x0180)
+#define CDC_RX_INTX_1_MIX_INP0_SEL_MASK        GENMASK(3, 0)
+#define CDC_RX_INTX_1_MIX_INP1_SEL_MASK        GENMASK(7, 4)
+#define CDC_RX_INP_MUX_RX_INT0_CFG1    (0x0184)
+#define CDC_RX_INTX_2_SEL_MASK         GENMASK(3, 0)
+#define CDC_RX_INTX_1_MIX_INP2_SEL_MASK        GENMASK(7, 4)
+#define CDC_RX_INP_MUX_RX_INT1_CFG0    (0x0188)
+#define CDC_RX_INP_MUX_RX_INT1_CFG1    (0x018C)
+#define CDC_RX_INP_MUX_RX_INT2_CFG0    (0x0190)
+#define CDC_RX_INP_MUX_RX_INT2_CFG1    (0x0194)
+#define CDC_RX_INP_MUX_RX_MIX_CFG4     (0x0198)
+#define CDC_RX_INP_MUX_RX_MIX_CFG5     (0x019C)
+#define CDC_RX_INP_MUX_SIDETONE_SRC_CFG0       (0x01A0)
+#define CDC_RX_CLSH_CRC                        (0x0200)
+#define CDC_RX_CLSH_CLK_EN_MASK                BIT(0)
+#define CDC_RX_CLSH_DLY_CTRL           (0x0204)
+#define CDC_RX_CLSH_DECAY_CTRL         (0x0208)
+#define CDC_RX_CLSH_DECAY_RATE_MASK    GENMASK(2, 0)
+#define CDC_RX_CLSH_HPH_V_PA           (0x020C)
+#define CDC_RX_CLSH_HPH_V_PA_MIN_MASK  GENMASK(5, 0)
+#define CDC_RX_CLSH_EAR_V_PA           (0x0210)
+#define CDC_RX_CLSH_HPH_V_HD           (0x0214)
+#define CDC_RX_CLSH_EAR_V_HD           (0x0218)
+#define CDC_RX_CLSH_K1_MSB             (0x021C)
+#define CDC_RX_CLSH_K1_MSB_COEFF_MASK  GENMASK(3, 0)
+#define CDC_RX_CLSH_K1_LSB             (0x0220)
+#define CDC_RX_CLSH_K2_MSB             (0x0224)
+#define CDC_RX_CLSH_K2_LSB             (0x0228)
+#define CDC_RX_CLSH_IDLE_CTRL          (0x022C)
+#define CDC_RX_CLSH_IDLE_HPH           (0x0230)
+#define CDC_RX_CLSH_IDLE_EAR           (0x0234)
+#define CDC_RX_CLSH_TEST0              (0x0238)
+#define CDC_RX_CLSH_TEST1              (0x023C)
+#define CDC_RX_CLSH_OVR_VREF           (0x0240)
+#define CDC_RX_CLSH_CLSG_CTL           (0x0244)
+#define CDC_RX_CLSH_CLSG_CFG1          (0x0248)
+#define CDC_RX_CLSH_CLSG_CFG2          (0x024C)
+#define CDC_RX_BCL_VBAT_PATH_CTL       (0x0280)
+#define CDC_RX_BCL_VBAT_CFG            (0x0284)
+#define CDC_RX_BCL_VBAT_ADC_CAL1       (0x0288)
+#define CDC_RX_BCL_VBAT_ADC_CAL2       (0x028C)
+#define CDC_RX_BCL_VBAT_ADC_CAL3       (0x0290)
+#define CDC_RX_BCL_VBAT_PK_EST1                (0x0294)
+#define CDC_RX_BCL_VBAT_PK_EST2                (0x0298)
+#define CDC_RX_BCL_VBAT_PK_EST3                (0x029C)
+#define CDC_RX_BCL_VBAT_RF_PROC1       (0x02A0)
+#define CDC_RX_BCL_VBAT_RF_PROC2       (0x02A4)
+#define CDC_RX_BCL_VBAT_TAC1           (0x02A8)
+#define CDC_RX_BCL_VBAT_TAC2           (0x02AC)
+#define CDC_RX_BCL_VBAT_TAC3           (0x02B0)
+#define CDC_RX_BCL_VBAT_TAC4           (0x02B4)
+#define CDC_RX_BCL_VBAT_GAIN_UPD1      (0x02B8)
+#define CDC_RX_BCL_VBAT_GAIN_UPD2      (0x02BC)
+#define CDC_RX_BCL_VBAT_GAIN_UPD3      (0x02C0)
+#define CDC_RX_BCL_VBAT_GAIN_UPD4      (0x02C4)
+#define CDC_RX_BCL_VBAT_GAIN_UPD5      (0x02C8)
+#define CDC_RX_BCL_VBAT_DEBUG1         (0x02CC)
+#define CDC_RX_BCL_VBAT_GAIN_UPD_MON   (0x02D0)
+#define CDC_RX_BCL_VBAT_GAIN_MON_VAL   (0x02D4)
+#define CDC_RX_BCL_VBAT_BAN            (0x02D8)
+#define CDC_RX_BCL_VBAT_BCL_GAIN_UPD1  (0x02DC)
+#define CDC_RX_BCL_VBAT_BCL_GAIN_UPD2  (0x02E0)
+#define CDC_RX_BCL_VBAT_BCL_GAIN_UPD3  (0x02E4)
+#define CDC_RX_BCL_VBAT_BCL_GAIN_UPD4  (0x02E8)
+#define CDC_RX_BCL_VBAT_BCL_GAIN_UPD5  (0x02EC)
+#define CDC_RX_BCL_VBAT_BCL_GAIN_UPD6  (0x02F0)
+#define CDC_RX_BCL_VBAT_BCL_GAIN_UPD7  (0x02F4)
+#define CDC_RX_BCL_VBAT_BCL_GAIN_UPD8  (0x02F8)
+#define CDC_RX_BCL_VBAT_BCL_GAIN_UPD9  (0x02FC)
+#define CDC_RX_BCL_VBAT_ATTN1          (0x0300)
+#define CDC_RX_BCL_VBAT_ATTN2          (0x0304)
+#define CDC_RX_BCL_VBAT_ATTN3          (0x0308)
+#define CDC_RX_BCL_VBAT_DECODE_CTL1    (0x030C)
+#define CDC_RX_BCL_VBAT_DECODE_CTL2    (0x0310)
+#define CDC_RX_BCL_VBAT_DECODE_CFG1    (0x0314)
+#define CDC_RX_BCL_VBAT_DECODE_CFG2    (0x0318)
+#define CDC_RX_BCL_VBAT_DECODE_CFG3    (0x031C)
+#define CDC_RX_BCL_VBAT_DECODE_CFG4    (0x0320)
+#define CDC_RX_BCL_VBAT_DECODE_ST      (0x0324)
+#define CDC_RX_INTR_CTRL_CFG           (0x0340)
+#define CDC_RX_INTR_CTRL_CLR_COMMIT    (0x0344)
+#define CDC_RX_INTR_CTRL_PIN1_MASK0    (0x0360)
+#define CDC_RX_INTR_CTRL_PIN1_STATUS0  (0x0368)
+#define CDC_RX_INTR_CTRL_PIN1_CLEAR0   (0x0370)
+#define CDC_RX_INTR_CTRL_PIN2_MASK0    (0x0380)
+#define CDC_RX_INTR_CTRL_PIN2_STATUS0  (0x0388)
+#define CDC_RX_INTR_CTRL_PIN2_CLEAR0   (0x0390)
+#define CDC_RX_INTR_CTRL_LEVEL0                (0x03C0)
+#define CDC_RX_INTR_CTRL_BYPASS0       (0x03C8)
+#define CDC_RX_INTR_CTRL_SET0          (0x03D0)
+#define CDC_RX_RXn_RX_PATH_CTL(n)      (0x0400 + 0x80 * n)
+#define CDC_RX_RX0_RX_PATH_CTL         (0x0400)
+#define CDC_RX_PATH_RESET_EN_MASK      BIT(6)
+#define CDC_RX_PATH_CLK_EN_MASK                BIT(5)
+#define CDC_RX_PATH_CLK_ENABLE         BIT(5)
+#define CDC_RX_PATH_PGA_MUTE_MASK      BIT(4)
+#define CDC_RX_PATH_PGA_MUTE_ENABLE    BIT(4)
+#define CDC_RX_PATH_PCM_RATE_MASK      GENMASK(3, 0)
+#define CDC_RX_RXn_RX_PATH_CFG0(n)     (0x0404 + 0x80 * n)
+#define CDC_RX_RXn_COMP_EN_MASK                BIT(1)
+#define CDC_RX_RX0_RX_PATH_CFG0                (0x0404)
+#define CDC_RX_RXn_CLSH_EN_MASK                BIT(6)
+#define CDC_RX_DLY_ZN_EN_MASK          BIT(3)
+#define CDC_RX_DLY_ZN_ENABLE           BIT(3)
+#define CDC_RX_RXn_HD2_EN_MASK         BIT(2)
+#define CDC_RX_RXn_RX_PATH_CFG1(n)     (0x0408 + 0x80 * n)
+#define CDC_RX_RXn_SIDETONE_EN_MASK    BIT(4)
+#define CDC_RX_RX0_RX_PATH_CFG1                (0x0408)
+#define CDC_RX_RX0_HPH_L_EAR_SEL_MASK  BIT(1)
+#define CDC_RX_RXn_RX_PATH_CFG2(n)     (0x040C + 0x80 * n)
+#define CDC_RX_RXn_HPF_CUT_FREQ_MASK   GENMASK(1, 0)
+#define CDC_RX_RX0_RX_PATH_CFG2                (0x040C)
+#define CDC_RX_RXn_RX_PATH_CFG3(n)     (0x0410 + 0x80 * n)
+#define CDC_RX_RX0_RX_PATH_CFG3                (0x0410)
+#define CDC_RX_DC_COEFF_SEL_MASK       GENMASK(1, 0)
+#define CDC_RX_DC_COEFF_SEL_TWO                0x2
+#define CDC_RX_RXn_RX_VOL_CTL(n)       (0x0414 + 0x80 * n)
+#define CDC_RX_RX0_RX_VOL_CTL          (0x0414)
+#define CDC_RX_RXn_RX_PATH_MIX_CTL(n)  (0x0418 + 0x80 * n)
+#define CDC_RX_RXn_MIX_PCM_RATE_MASK   GENMASK(3, 0)
+#define CDC_RX_RXn_MIX_RESET_MASK      BIT(6)
+#define CDC_RX_RXn_MIX_RESET           BIT(6)
+#define CDC_RX_RXn_MIX_CLK_EN_MASK     BIT(5)
+#define CDC_RX_RX0_RX_PATH_MIX_CTL     (0x0418)
+#define CDC_RX_RX0_RX_PATH_MIX_CFG     (0x041C)
+#define CDC_RX_RXn_RX_VOL_MIX_CTL(n)   (0x0420 + 0x80 * n)
+#define CDC_RX_RX0_RX_VOL_MIX_CTL      (0x0420)
+#define CDC_RX_RX0_RX_PATH_SEC1                (0x0424)
+#define CDC_RX_RX0_RX_PATH_SEC2                (0x0428)
+#define CDC_RX_RX0_RX_PATH_SEC3                (0x042C)
+#define CDC_RX_RX0_RX_PATH_SEC4                (0x0430)
+#define CDC_RX_RX0_RX_PATH_SEC7                (0x0434)
+#define CDC_RX_DSM_OUT_DELAY_SEL_MASK  GENMASK(2, 0)
+#define CDC_RX_DSM_OUT_DELAY_TWO_SAMPLE        0x2
+#define CDC_RX_RX0_RX_PATH_MIX_SEC0    (0x0438)
+#define CDC_RX_RX0_RX_PATH_MIX_SEC1    (0x043C)
+#define CDC_RX_RXn_RX_PATH_DSM_CTL(n)  (0x0440 + 0x80 * n)
+#define CDC_RX_RXn_DSM_CLK_EN_MASK     BIT(0)
+#define CDC_RX_RX0_RX_PATH_DSM_CTL     (0x0440)
+#define CDC_RX_RX0_RX_PATH_DSM_DATA1   (0x0444)
+#define CDC_RX_RX0_RX_PATH_DSM_DATA2   (0x0448)
+#define CDC_RX_RX0_RX_PATH_DSM_DATA3   (0x044C)
+#define CDC_RX_RX0_RX_PATH_DSM_DATA4   (0x0450)
+#define CDC_RX_RX0_RX_PATH_DSM_DATA5   (0x0454)
+#define CDC_RX_RX0_RX_PATH_DSM_DATA6   (0x0458)
+#define CDC_RX_RX1_RX_PATH_CTL         (0x0480)
+#define CDC_RX_RX1_RX_PATH_CFG0                (0x0484)
+#define CDC_RX_RX1_RX_PATH_CFG1                (0x0488)
+#define CDC_RX_RX1_RX_PATH_CFG2                (0x048C)
+#define CDC_RX_RX1_RX_PATH_CFG3                (0x0490)
+#define CDC_RX_RX1_RX_VOL_CTL          (0x0494)
+#define CDC_RX_RX1_RX_PATH_MIX_CTL     (0x0498)
+#define CDC_RX_RX1_RX_PATH_MIX_CFG     (0x049C)
+#define CDC_RX_RX1_RX_VOL_MIX_CTL      (0x04A0)
+#define CDC_RX_RX1_RX_PATH_SEC1                (0x04A4)
+#define CDC_RX_RX1_RX_PATH_SEC2                (0x04A8)
+#define CDC_RX_RX1_RX_PATH_SEC3                (0x04AC)
+#define CDC_RX_RXn_HD2_ALPHA_MASK      GENMASK(5, 2)
+#define CDC_RX_RX1_RX_PATH_SEC4                (0x04B0)
+#define CDC_RX_RX1_RX_PATH_SEC7                (0x04B4)
+#define CDC_RX_RX1_RX_PATH_MIX_SEC0    (0x04B8)
+#define CDC_RX_RX1_RX_PATH_MIX_SEC1    (0x04BC)
+#define CDC_RX_RX1_RX_PATH_DSM_CTL     (0x04C0)
+#define CDC_RX_RX1_RX_PATH_DSM_DATA1   (0x04C4)
+#define CDC_RX_RX1_RX_PATH_DSM_DATA2   (0x04C8)
+#define CDC_RX_RX1_RX_PATH_DSM_DATA3   (0x04CC)
+#define CDC_RX_RX1_RX_PATH_DSM_DATA4   (0x04D0)
+#define CDC_RX_RX1_RX_PATH_DSM_DATA5   (0x04D4)
+#define CDC_RX_RX1_RX_PATH_DSM_DATA6   (0x04D8)
+#define CDC_RX_RX2_RX_PATH_CTL         (0x0500)
+#define CDC_RX_RX2_RX_PATH_CFG0                (0x0504)
+#define CDC_RX_RX2_CLSH_EN_MASK                BIT(4)
+#define CDC_RX_RX2_DLY_Z_EN_MASK       BIT(3)
+#define CDC_RX_RX2_RX_PATH_CFG1                (0x0508)
+#define CDC_RX_RX2_RX_PATH_CFG2                (0x050C)
+#define CDC_RX_RX2_RX_PATH_CFG3                (0x0510)
+#define CDC_RX_RX2_RX_VOL_CTL          (0x0514)
+#define CDC_RX_RX2_RX_PATH_MIX_CTL     (0x0518)
+#define CDC_RX_RX2_RX_PATH_MIX_CFG     (0x051C)
+#define CDC_RX_RX2_RX_VOL_MIX_CTL      (0x0520)
+#define CDC_RX_RX2_RX_PATH_SEC0                (0x0524)
+#define CDC_RX_RX2_RX_PATH_SEC1                (0x0528)
+#define CDC_RX_RX2_RX_PATH_SEC2                (0x052C)
+#define CDC_RX_RX2_RX_PATH_SEC3                (0x0530)
+#define CDC_RX_RX2_RX_PATH_SEC4                (0x0534)
+#define CDC_RX_RX2_RX_PATH_SEC5                (0x0538)
+#define CDC_RX_RX2_RX_PATH_SEC6                (0x053C)
+#define CDC_RX_RX2_RX_PATH_SEC7                (0x0540)
+#define CDC_RX_RX2_RX_PATH_MIX_SEC0    (0x0544)
+#define CDC_RX_RX2_RX_PATH_MIX_SEC1    (0x0548)
+#define CDC_RX_RX2_RX_PATH_DSM_CTL     (0x054C)
+#define CDC_RX_IDLE_DETECT_PATH_CTL    (0x0780)
+#define CDC_RX_IDLE_DETECT_CFG0                (0x0784)
+#define CDC_RX_IDLE_DETECT_CFG1                (0x0788)
+#define CDC_RX_IDLE_DETECT_CFG2                (0x078C)
+#define CDC_RX_IDLE_DETECT_CFG3                (0x0790)
+#define CDC_RX_COMPANDERn_CTL0(n)      (0x0800 + 0x40 * n)
+#define CDC_RX_COMPANDERn_CLK_EN_MASK  BIT(0)
+#define CDC_RX_COMPANDERn_SOFT_RST_MASK        BIT(1)
+#define CDC_RX_COMPANDERn_HALT_MASK    BIT(2)
+#define CDC_RX_COMPANDER0_CTL0         (0x0800)
+#define CDC_RX_COMPANDER0_CTL1         (0x0804)
+#define CDC_RX_COMPANDER0_CTL2         (0x0808)
+#define CDC_RX_COMPANDER0_CTL3         (0x080C)
+#define CDC_RX_COMPANDER0_CTL4         (0x0810)
+#define CDC_RX_COMPANDER0_CTL5         (0x0814)
+#define CDC_RX_COMPANDER0_CTL6         (0x0818)
+#define CDC_RX_COMPANDER0_CTL7         (0x081C)
+#define CDC_RX_COMPANDER1_CTL0         (0x0840)
+#define CDC_RX_COMPANDER1_CTL1         (0x0844)
+#define CDC_RX_COMPANDER1_CTL2         (0x0848)
+#define CDC_RX_COMPANDER1_CTL3         (0x084C)
+#define CDC_RX_COMPANDER1_CTL4         (0x0850)
+#define CDC_RX_COMPANDER1_CTL5         (0x0854)
+#define CDC_RX_COMPANDER1_CTL6         (0x0858)
+#define CDC_RX_COMPANDER1_CTL7         (0x085C)
+#define CDC_RX_COMPANDER1_HPH_LOW_PWR_MODE_MASK        BIT(5)
+#define CDC_RX_SIDETONE_IIR0_IIR_PATH_CTL      (0x0A00)
+#define CDC_RX_SIDETONE_IIR0_IIR_GAIN_B1_CTL   (0x0A04)
+#define CDC_RX_SIDETONE_IIR0_IIR_GAIN_B2_CTL   (0x0A08)
+#define CDC_RX_SIDETONE_IIR0_IIR_GAIN_B3_CTL   (0x0A0C)
+#define CDC_RX_SIDETONE_IIR0_IIR_GAIN_B4_CTL   (0x0A10)
+#define CDC_RX_SIDETONE_IIR0_IIR_GAIN_B5_CTL   (0x0A14)
+#define CDC_RX_SIDETONE_IIR0_IIR_GAIN_B6_CTL   (0x0A18)
+#define CDC_RX_SIDETONE_IIR0_IIR_GAIN_B7_CTL   (0x0A1C)
+#define CDC_RX_SIDETONE_IIR0_IIR_GAIN_B8_CTL   (0x0A20)
+#define CDC_RX_SIDETONE_IIR0_IIR_CTL           (0x0A24)
+#define CDC_RX_SIDETONE_IIR0_IIR_GAIN_TIMER_CTL        (0x0A28)
+#define CDC_RX_SIDETONE_IIR0_IIR_COEF_B1_CTL   (0x0A2C)
+#define CDC_RX_SIDETONE_IIR0_IIR_COEF_B2_CTL   (0x0A30)
+#define CDC_RX_SIDETONE_IIR1_IIR_PATH_CTL      (0x0A80)
+#define CDC_RX_SIDETONE_IIR1_IIR_GAIN_B1_CTL   (0x0A84)
+#define CDC_RX_SIDETONE_IIR1_IIR_GAIN_B2_CTL   (0x0A88)
+#define CDC_RX_SIDETONE_IIR1_IIR_GAIN_B3_CTL   (0x0A8C)
+#define CDC_RX_SIDETONE_IIR1_IIR_GAIN_B4_CTL   (0x0A90)
+#define CDC_RX_SIDETONE_IIR1_IIR_GAIN_B5_CTL   (0x0A94)
+#define CDC_RX_SIDETONE_IIR1_IIR_GAIN_B6_CTL   (0x0A98)
+#define CDC_RX_SIDETONE_IIR1_IIR_GAIN_B7_CTL   (0x0A9C)
+#define CDC_RX_SIDETONE_IIR1_IIR_GAIN_B8_CTL   (0x0AA0)
+#define CDC_RX_SIDETONE_IIR1_IIR_CTL           (0x0AA4)
+#define CDC_RX_SIDETONE_IIR1_IIR_GAIN_TIMER_CTL        (0x0AA8)
+#define CDC_RX_SIDETONE_IIR1_IIR_COEF_B1_CTL   (0x0AAC)
+#define CDC_RX_SIDETONE_IIR1_IIR_COEF_B2_CTL   (0x0AB0)
+#define CDC_RX_IIR_INP_MUX_IIR0_MIX_CFG0       (0x0B00)
+#define CDC_RX_IIR_INP_MUX_IIR0_MIX_CFG1       (0x0B04)
+#define CDC_RX_IIR_INP_MUX_IIR0_MIX_CFG2       (0x0B08)
+#define CDC_RX_IIR_INP_MUX_IIR0_MIX_CFG3       (0x0B0C)
+#define CDC_RX_IIR_INP_MUX_IIR1_MIX_CFG0       (0x0B10)
+#define CDC_RX_IIR_INP_MUX_IIR1_MIX_CFG1       (0x0B14)
+#define CDC_RX_IIR_INP_MUX_IIR1_MIX_CFG2       (0x0B18)
+#define CDC_RX_IIR_INP_MUX_IIR1_MIX_CFG3       (0x0B1C)
+#define CDC_RX_SIDETONE_SRC0_ST_SRC_PATH_CTL   (0x0B40)
+#define CDC_RX_SIDETONE_SRC0_ST_SRC_PATH_CFG1  (0x0B44)
+#define CDC_RX_SIDETONE_SRC1_ST_SRC_PATH_CTL   (0x0B50)
+#define CDC_RX_SIDETONE_SRC1_ST_SRC_PATH_CFG1  (0x0B54)
+#define CDC_RX_EC_REF_HQ0_EC_REF_HQ_PATH_CTL   (0x0C00)
+#define CDC_RX_EC_REF_HQ0_EC_REF_HQ_CFG0       (0x0C04)
+#define CDC_RX_EC_REF_HQ1_EC_REF_HQ_PATH_CTL   (0x0C40)
+#define CDC_RX_EC_REF_HQ1_EC_REF_HQ_CFG0       (0x0C44)
+#define CDC_RX_EC_REF_HQ2_EC_REF_HQ_PATH_CTL   (0x0C80)
+#define CDC_RX_EC_REF_HQ2_EC_REF_HQ_CFG0       (0x0C84)
+#define CDC_RX_EC_ASRC0_CLK_RST_CTL            (0x0D00)
+#define CDC_RX_EC_ASRC0_CTL0                   (0x0D04)
+#define CDC_RX_EC_ASRC0_CTL1                   (0x0D08)
+#define CDC_RX_EC_ASRC0_FIFO_CTL               (0x0D0C)
+#define CDC_RX_EC_ASRC0_STATUS_FMIN_CNTR_LSB   (0x0D10)
+#define CDC_RX_EC_ASRC0_STATUS_FMIN_CNTR_MSB   (0x0D14)
+#define CDC_RX_EC_ASRC0_STATUS_FMAX_CNTR_LSB   (0x0D18)
+#define CDC_RX_EC_ASRC0_STATUS_FMAX_CNTR_MSB   (0x0D1C)
+#define CDC_RX_EC_ASRC0_STATUS_FIFO            (0x0D20)
+#define CDC_RX_EC_ASRC1_CLK_RST_CTL            (0x0D40)
+#define CDC_RX_EC_ASRC1_CTL0                   (0x0D44)
+#define CDC_RX_EC_ASRC1_CTL1                   (0x0D48)
+#define CDC_RX_EC_ASRC1_FIFO_CTL               (0x0D4C)
+#define CDC_RX_EC_ASRC1_STATUS_FMIN_CNTR_LSB   (0x0D50)
+#define CDC_RX_EC_ASRC1_STATUS_FMIN_CNTR_MSB   (0x0D54)
+#define CDC_RX_EC_ASRC1_STATUS_FMAX_CNTR_LSB   (0x0D58)
+#define CDC_RX_EC_ASRC1_STATUS_FMAX_CNTR_MSB   (0x0D5C)
+#define CDC_RX_EC_ASRC1_STATUS_FIFO            (0x0D60)
+#define CDC_RX_EC_ASRC2_CLK_RST_CTL            (0x0D80)
+#define CDC_RX_EC_ASRC2_CTL0                   (0x0D84)
+#define CDC_RX_EC_ASRC2_CTL1                   (0x0D88)
+#define CDC_RX_EC_ASRC2_FIFO_CTL               (0x0D8C)
+#define CDC_RX_EC_ASRC2_STATUS_FMIN_CNTR_LSB   (0x0D90)
+#define CDC_RX_EC_ASRC2_STATUS_FMIN_CNTR_MSB   (0x0D94)
+#define CDC_RX_EC_ASRC2_STATUS_FMAX_CNTR_LSB   (0x0D98)
+#define CDC_RX_EC_ASRC2_STATUS_FMAX_CNTR_MSB   (0x0D9C)
+#define CDC_RX_EC_ASRC2_STATUS_FIFO            (0x0DA0)
+#define CDC_RX_DSD0_PATH_CTL                   (0x0F00)
+#define CDC_RX_DSD0_CFG0                       (0x0F04)
+#define CDC_RX_DSD0_CFG1                       (0x0F08)
+#define CDC_RX_DSD0_CFG2                       (0x0F0C)
+#define CDC_RX_DSD1_PATH_CTL                   (0x0F80)
+#define CDC_RX_DSD1_CFG0                       (0x0F84)
+#define CDC_RX_DSD1_CFG1                       (0x0F88)
+#define CDC_RX_DSD1_CFG2                       (0x0F8C)
+#define RX_MAX_OFFSET                          (0x0F8C)
+
+#define MCLK_FREQ              9600000
+
+#define RX_MACRO_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |\
+                       SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000 |\
+                       SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_192000 |\
+                       SNDRV_PCM_RATE_384000)
+/* Fractional Rates */
+#define RX_MACRO_FRAC_RATES (SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_88200 |\
+                               SNDRV_PCM_RATE_176400 | SNDRV_PCM_RATE_352800)
+
+#define RX_MACRO_FORMATS (SNDRV_PCM_FMTBIT_S16_LE |\
+               SNDRV_PCM_FMTBIT_S24_LE |\
+               SNDRV_PCM_FMTBIT_S24_3LE | SNDRV_PCM_FMTBIT_S32_LE)
+
+#define RX_MACRO_ECHO_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |\
+                       SNDRV_PCM_RATE_48000)
+#define RX_MACRO_ECHO_FORMATS (SNDRV_PCM_FMTBIT_S16_LE |\
+               SNDRV_PCM_FMTBIT_S24_LE |\
+               SNDRV_PCM_FMTBIT_S24_3LE)
+
+#define RX_MACRO_MAX_DMA_CH_PER_PORT 2
+
+#define RX_MACRO_EC_MIX_TX0_MASK 0xf0
+#define RX_MACRO_EC_MIX_TX1_MASK 0x0f
+#define RX_MACRO_EC_MIX_TX2_MASK 0x0f
+
+#define COMP_MAX_COEFF 25
+#define RX_NUM_CLKS_MAX        5
+
+struct comp_coeff_val {
+       u8 lsb;
+       u8 msb;
+};
+
+enum {
+       HPH_ULP,
+       HPH_LOHIFI,
+       HPH_MODE_MAX,
+};
+
+static const struct comp_coeff_val comp_coeff_table[HPH_MODE_MAX][COMP_MAX_COEFF] = {
+       {
+               {0x40, 0x00},
+               {0x4C, 0x00},
+               {0x5A, 0x00},
+               {0x6B, 0x00},
+               {0x7F, 0x00},
+               {0x97, 0x00},
+               {0xB3, 0x00},
+               {0xD5, 0x00},
+               {0xFD, 0x00},
+               {0x2D, 0x01},
+               {0x66, 0x01},
+               {0xA7, 0x01},
+               {0xF8, 0x01},
+               {0x57, 0x02},
+               {0xC7, 0x02},
+               {0x4B, 0x03},
+               {0xE9, 0x03},
+               {0xA3, 0x04},
+               {0x7D, 0x05},
+               {0x90, 0x06},
+               {0xD1, 0x07},
+               {0x49, 0x09},
+               {0x00, 0x0B},
+               {0x01, 0x0D},
+               {0x59, 0x0F},
+       },
+       {
+               {0x40, 0x00},
+               {0x4C, 0x00},
+               {0x5A, 0x00},
+               {0x6B, 0x00},
+               {0x80, 0x00},
+               {0x98, 0x00},
+               {0xB4, 0x00},
+               {0xD5, 0x00},
+               {0xFE, 0x00},
+               {0x2E, 0x01},
+               {0x66, 0x01},
+               {0xA9, 0x01},
+               {0xF8, 0x01},
+               {0x56, 0x02},
+               {0xC4, 0x02},
+               {0x4F, 0x03},
+               {0xF0, 0x03},
+               {0xAE, 0x04},
+               {0x8B, 0x05},
+               {0x8E, 0x06},
+               {0xBC, 0x07},
+               {0x56, 0x09},
+               {0x0F, 0x0B},
+               {0x13, 0x0D},
+               {0x6F, 0x0F},
+       },
+};
+
+struct rx_macro_reg_mask_val {
+       u16 reg;
+       u8 mask;
+       u8 val;
+};
+
+enum {
+       INTERP_HPHL,
+       INTERP_HPHR,
+       INTERP_AUX,
+       INTERP_MAX
+};
+
+enum {
+       RX_MACRO_RX0,
+       RX_MACRO_RX1,
+       RX_MACRO_RX2,
+       RX_MACRO_RX3,
+       RX_MACRO_RX4,
+       RX_MACRO_RX5,
+       RX_MACRO_PORTS_MAX
+};
+
+enum {
+       RX_MACRO_COMP1, /* HPH_L */
+       RX_MACRO_COMP2, /* HPH_R */
+       RX_MACRO_COMP_MAX
+};
+
+enum {
+       RX_MACRO_EC0_MUX = 0,
+       RX_MACRO_EC1_MUX,
+       RX_MACRO_EC2_MUX,
+       RX_MACRO_EC_MUX_MAX,
+};
+
+enum {
+       INTn_1_INP_SEL_ZERO = 0,
+       INTn_1_INP_SEL_DEC0,
+       INTn_1_INP_SEL_DEC1,
+       INTn_1_INP_SEL_IIR0,
+       INTn_1_INP_SEL_IIR1,
+       INTn_1_INP_SEL_RX0,
+       INTn_1_INP_SEL_RX1,
+       INTn_1_INP_SEL_RX2,
+       INTn_1_INP_SEL_RX3,
+       INTn_1_INP_SEL_RX4,
+       INTn_1_INP_SEL_RX5,
+};
+
+enum {
+       INTn_2_INP_SEL_ZERO = 0,
+       INTn_2_INP_SEL_RX0,
+       INTn_2_INP_SEL_RX1,
+       INTn_2_INP_SEL_RX2,
+       INTn_2_INP_SEL_RX3,
+       INTn_2_INP_SEL_RX4,
+       INTn_2_INP_SEL_RX5,
+};
+
+enum {
+       INTERP_MAIN_PATH,
+       INTERP_MIX_PATH,
+};
+
+/* Codec supports 2 IIR filters */
+enum {
+       IIR0 = 0,
+       IIR1,
+       IIR_MAX,
+};
+
+/* Each IIR has 5 Filter Stages */
+enum {
+       BAND1 = 0,
+       BAND2,
+       BAND3,
+       BAND4,
+       BAND5,
+       BAND_MAX,
+};
+
+#define RX_MACRO_IIR_FILTER_SIZE       (sizeof(u32) * BAND_MAX)
+
+#define RX_MACRO_IIR_FILTER_CTL(xname, iidx, bidx) \
+{ \
+       .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
+       .info = rx_macro_iir_filter_info, \
+       .get = rx_macro_get_iir_band_audio_mixer, \
+       .put = rx_macro_put_iir_band_audio_mixer, \
+       .private_value = (unsigned long)&(struct wcd_iir_filter_ctl) { \
+               .iir_idx = iidx, \
+               .band_idx = bidx, \
+               .bytes_ext = {.max = RX_MACRO_IIR_FILTER_SIZE, }, \
+       } \
+}
+
+struct interp_sample_rate {
+       int sample_rate;
+       int rate_val;
+};
+
+static struct interp_sample_rate sr_val_tbl[] = {
+       {8000, 0x0}, {16000, 0x1}, {32000, 0x3}, {48000, 0x4}, {96000, 0x5},
+       {192000, 0x6}, {384000, 0x7}, {44100, 0x9}, {88200, 0xA},
+       {176400, 0xB}, {352800, 0xC},
+};
+
+enum {
+       RX_MACRO_AIF_INVALID = 0,
+       RX_MACRO_AIF1_PB,
+       RX_MACRO_AIF2_PB,
+       RX_MACRO_AIF3_PB,
+       RX_MACRO_AIF4_PB,
+       RX_MACRO_AIF_ECHO,
+       RX_MACRO_MAX_DAIS,
+};
+
+enum {
+       RX_MACRO_AIF1_CAP = 0,
+       RX_MACRO_AIF2_CAP,
+       RX_MACRO_AIF3_CAP,
+       RX_MACRO_MAX_AIF_CAP_DAIS
+};
+
+struct rx_macro {
+       struct device *dev;
+       int comp_enabled[RX_MACRO_COMP_MAX];
+       /* Main path clock users count */
+       int main_clk_users[INTERP_MAX];
+       int rx_port_value[RX_MACRO_PORTS_MAX];
+       u16 prim_int_users[INTERP_MAX];
+       int rx_mclk_users;
+       bool reset_swr;
+       int clsh_users;
+       int rx_mclk_cnt;
+       bool is_ear_mode_on;
+       bool hph_pwr_mode;
+       bool hph_hd2_mode;
+       struct snd_soc_component *component;
+       unsigned long active_ch_mask[RX_MACRO_MAX_DAIS];
+       unsigned long active_ch_cnt[RX_MACRO_MAX_DAIS];
+       u16 bit_width[RX_MACRO_MAX_DAIS];
+       int is_softclip_on;
+       int is_aux_hpf_on;
+       int softclip_clk_users;
+
+       struct regmap *regmap;
+       struct clk_bulk_data clks[RX_NUM_CLKS_MAX];
+       struct clk_hw hw;
+};
+#define to_rx_macro(_hw) container_of(_hw, struct rx_macro, hw)
+
+struct wcd_iir_filter_ctl {
+       unsigned int iir_idx;
+       unsigned int band_idx;
+       struct soc_bytes_ext bytes_ext;
+};
+
+static const DECLARE_TLV_DB_SCALE(digital_gain, -8400, 100, -8400);
+
+static const char * const rx_int_mix_mux_text[] = {
+       "ZERO", "RX0", "RX1", "RX2", "RX3", "RX4", "RX5"
+};
+
+static const char * const rx_prim_mix_text[] = {
+       "ZERO", "DEC0", "DEC1", "IIR0", "IIR1", "RX0", "RX1", "RX2",
+       "RX3", "RX4", "RX5"
+};
+
+static const char * const rx_sidetone_mix_text[] = {
+       "ZERO", "SRC0", "SRC1", "SRC_SUM"
+};
+
+static const char * const iir_inp_mux_text[] = {
+       "ZERO", "DEC0", "DEC1", "DEC2", "DEC3",
+       "RX0", "RX1", "RX2", "RX3", "RX4", "RX5"
+};
+
+static const char * const rx_int_dem_inp_mux_text[] = {
+       "NORMAL_DSM_OUT", "CLSH_DSM_OUT",
+};
+
+static const char * const rx_int0_1_interp_mux_text[] = {
+       "ZERO", "RX INT0_1 MIX1",
+};
+
+static const char * const rx_int1_1_interp_mux_text[] = {
+       "ZERO", "RX INT1_1 MIX1",
+};
+
+static const char * const rx_int2_1_interp_mux_text[] = {
+       "ZERO", "RX INT2_1 MIX1",
+};
+
+static const char * const rx_int0_2_interp_mux_text[] = {
+       "ZERO", "RX INT0_2 MUX",
+};
+
+static const char * const rx_int1_2_interp_mux_text[] = {
+       "ZERO", "RX INT1_2 MUX",
+};
+
+static const char * const rx_int2_2_interp_mux_text[] = {
+       "ZERO", "RX INT2_2 MUX",
+};
+
+static const char *const rx_macro_mux_text[] = {
+       "ZERO", "AIF1_PB", "AIF2_PB", "AIF3_PB", "AIF4_PB"
+};
+
+static const char *const rx_macro_hph_pwr_mode_text[] = {
+       "ULP", "LOHIFI"
+};
+
+static const char * const rx_echo_mux_text[] = {
+       "ZERO", "RX_MIX0", "RX_MIX1", "RX_MIX2"
+};
+
+static const struct soc_enum rx_macro_hph_pwr_mode_enum =
+               SOC_ENUM_SINGLE_EXT(2, rx_macro_hph_pwr_mode_text);
+static const struct soc_enum rx_mix_tx2_mux_enum =
+               SOC_ENUM_SINGLE(CDC_RX_INP_MUX_RX_MIX_CFG5, 0, 4, rx_echo_mux_text);
+static const struct soc_enum rx_mix_tx1_mux_enum =
+               SOC_ENUM_SINGLE(CDC_RX_INP_MUX_RX_MIX_CFG4, 0, 4, rx_echo_mux_text);
+static const struct soc_enum rx_mix_tx0_mux_enum =
+               SOC_ENUM_SINGLE(CDC_RX_INP_MUX_RX_MIX_CFG4, 4, 4, rx_echo_mux_text);
+
+static SOC_ENUM_SINGLE_DECL(rx_int0_2_enum, CDC_RX_INP_MUX_RX_INT0_CFG1, 0,
+                           rx_int_mix_mux_text);
+static SOC_ENUM_SINGLE_DECL(rx_int1_2_enum, CDC_RX_INP_MUX_RX_INT1_CFG1, 0,
+                           rx_int_mix_mux_text);
+static SOC_ENUM_SINGLE_DECL(rx_int2_2_enum, CDC_RX_INP_MUX_RX_INT2_CFG1, 0,
+                           rx_int_mix_mux_text);
+
+static SOC_ENUM_SINGLE_DECL(rx_int0_1_mix_inp0_enum, CDC_RX_INP_MUX_RX_INT0_CFG0, 0,
+                           rx_prim_mix_text);
+static SOC_ENUM_SINGLE_DECL(rx_int0_1_mix_inp1_enum, CDC_RX_INP_MUX_RX_INT0_CFG0, 4,
+                           rx_prim_mix_text);
+static SOC_ENUM_SINGLE_DECL(rx_int0_1_mix_inp2_enum, CDC_RX_INP_MUX_RX_INT0_CFG1, 4,
+                           rx_prim_mix_text);
+static SOC_ENUM_SINGLE_DECL(rx_int1_1_mix_inp0_enum, CDC_RX_INP_MUX_RX_INT1_CFG0, 0,
+                           rx_prim_mix_text);
+static SOC_ENUM_SINGLE_DECL(rx_int1_1_mix_inp1_enum, CDC_RX_INP_MUX_RX_INT1_CFG0, 4,
+                           rx_prim_mix_text);
+static SOC_ENUM_SINGLE_DECL(rx_int1_1_mix_inp2_enum, CDC_RX_INP_MUX_RX_INT1_CFG1, 4,
+                           rx_prim_mix_text);
+static SOC_ENUM_SINGLE_DECL(rx_int2_1_mix_inp0_enum, CDC_RX_INP_MUX_RX_INT2_CFG0, 0,
+                           rx_prim_mix_text);
+static SOC_ENUM_SINGLE_DECL(rx_int2_1_mix_inp1_enum, CDC_RX_INP_MUX_RX_INT2_CFG0, 4,
+                           rx_prim_mix_text);
+static SOC_ENUM_SINGLE_DECL(rx_int2_1_mix_inp2_enum, CDC_RX_INP_MUX_RX_INT2_CFG1, 4,
+                           rx_prim_mix_text);
+
+static SOC_ENUM_SINGLE_DECL(rx_int0_mix2_inp_enum, CDC_RX_INP_MUX_SIDETONE_SRC_CFG0, 2,
+                           rx_sidetone_mix_text);
+static SOC_ENUM_SINGLE_DECL(rx_int1_mix2_inp_enum, CDC_RX_INP_MUX_SIDETONE_SRC_CFG0, 4,
+                           rx_sidetone_mix_text);
+static SOC_ENUM_SINGLE_DECL(rx_int2_mix2_inp_enum, CDC_RX_INP_MUX_SIDETONE_SRC_CFG0, 6,
+                           rx_sidetone_mix_text);
+static SOC_ENUM_SINGLE_DECL(iir0_inp0_enum, CDC_RX_IIR_INP_MUX_IIR0_MIX_CFG0, 0,
+                           iir_inp_mux_text);
+static SOC_ENUM_SINGLE_DECL(iir0_inp1_enum, CDC_RX_IIR_INP_MUX_IIR0_MIX_CFG1, 0,
+                           iir_inp_mux_text);
+static SOC_ENUM_SINGLE_DECL(iir0_inp2_enum, CDC_RX_IIR_INP_MUX_IIR0_MIX_CFG2, 0,
+                           iir_inp_mux_text);
+static SOC_ENUM_SINGLE_DECL(iir0_inp3_enum, CDC_RX_IIR_INP_MUX_IIR0_MIX_CFG3, 0,
+                           iir_inp_mux_text);
+static SOC_ENUM_SINGLE_DECL(iir1_inp0_enum, CDC_RX_IIR_INP_MUX_IIR1_MIX_CFG0, 0,
+                           iir_inp_mux_text);
+static SOC_ENUM_SINGLE_DECL(iir1_inp1_enum, CDC_RX_IIR_INP_MUX_IIR1_MIX_CFG1, 0,
+                           iir_inp_mux_text);
+static SOC_ENUM_SINGLE_DECL(iir1_inp2_enum, CDC_RX_IIR_INP_MUX_IIR1_MIX_CFG2, 0,
+                           iir_inp_mux_text);
+static SOC_ENUM_SINGLE_DECL(iir1_inp3_enum, CDC_RX_IIR_INP_MUX_IIR1_MIX_CFG3, 0,
+                           iir_inp_mux_text);
+
+static SOC_ENUM_SINGLE_DECL(rx_int0_1_interp_enum, SND_SOC_NOPM, 0,
+                           rx_int0_1_interp_mux_text);
+static SOC_ENUM_SINGLE_DECL(rx_int1_1_interp_enum, SND_SOC_NOPM, 0,
+                           rx_int1_1_interp_mux_text);
+static SOC_ENUM_SINGLE_DECL(rx_int2_1_interp_enum, SND_SOC_NOPM, 0,
+                           rx_int2_1_interp_mux_text);
+static SOC_ENUM_SINGLE_DECL(rx_int0_2_interp_enum, SND_SOC_NOPM, 0,
+                           rx_int0_2_interp_mux_text);
+static SOC_ENUM_SINGLE_DECL(rx_int1_2_interp_enum, SND_SOC_NOPM, 0,
+                           rx_int1_2_interp_mux_text);
+static SOC_ENUM_SINGLE_DECL(rx_int2_2_interp_enum, SND_SOC_NOPM, 0,
+                           rx_int2_2_interp_mux_text);
+static SOC_ENUM_SINGLE_DECL(rx_int0_dem_inp_enum, CDC_RX_RX0_RX_PATH_CFG1, 0,
+                           rx_int_dem_inp_mux_text);
+static SOC_ENUM_SINGLE_DECL(rx_int1_dem_inp_enum, CDC_RX_RX1_RX_PATH_CFG1, 0,
+                           rx_int_dem_inp_mux_text);
+
+static SOC_ENUM_SINGLE_DECL(rx_macro_rx0_enum, SND_SOC_NOPM, 0, rx_macro_mux_text);
+static SOC_ENUM_SINGLE_DECL(rx_macro_rx1_enum, SND_SOC_NOPM, 0, rx_macro_mux_text);
+static SOC_ENUM_SINGLE_DECL(rx_macro_rx2_enum, SND_SOC_NOPM, 0, rx_macro_mux_text);
+static SOC_ENUM_SINGLE_DECL(rx_macro_rx3_enum, SND_SOC_NOPM, 0, rx_macro_mux_text);
+static SOC_ENUM_SINGLE_DECL(rx_macro_rx4_enum, SND_SOC_NOPM, 0, rx_macro_mux_text);
+static SOC_ENUM_SINGLE_DECL(rx_macro_rx5_enum, SND_SOC_NOPM, 0, rx_macro_mux_text);
+
+static const struct snd_kcontrol_new rx_mix_tx1_mux =
+               SOC_DAPM_ENUM("RX MIX TX1_MUX Mux", rx_mix_tx1_mux_enum);
+static const struct snd_kcontrol_new rx_mix_tx2_mux = 
+               SOC_DAPM_ENUM("RX MIX TX2_MUX Mux", rx_mix_tx2_mux_enum);
+static const struct snd_kcontrol_new rx_int0_2_mux =
+               SOC_DAPM_ENUM("rx_int0_2", rx_int0_2_enum);
+static const struct snd_kcontrol_new rx_int1_2_mux =
+               SOC_DAPM_ENUM("rx_int1_2", rx_int1_2_enum);
+static const struct snd_kcontrol_new rx_int2_2_mux =
+               SOC_DAPM_ENUM("rx_int2_2", rx_int2_2_enum);
+static const struct snd_kcontrol_new rx_int0_1_mix_inp0_mux =
+               SOC_DAPM_ENUM("rx_int0_1_mix_inp0", rx_int0_1_mix_inp0_enum);
+static const struct snd_kcontrol_new rx_int0_1_mix_inp1_mux =
+               SOC_DAPM_ENUM("rx_int0_1_mix_inp1", rx_int0_1_mix_inp1_enum);
+static const struct snd_kcontrol_new rx_int0_1_mix_inp2_mux =
+               SOC_DAPM_ENUM("rx_int0_1_mix_inp2", rx_int0_1_mix_inp2_enum);
+static const struct snd_kcontrol_new rx_int1_1_mix_inp0_mux =
+               SOC_DAPM_ENUM("rx_int1_1_mix_inp0", rx_int1_1_mix_inp0_enum);
+static const struct snd_kcontrol_new rx_int1_1_mix_inp1_mux =
+               SOC_DAPM_ENUM("rx_int1_1_mix_inp1", rx_int1_1_mix_inp1_enum);
+static const struct snd_kcontrol_new rx_int1_1_mix_inp2_mux =
+               SOC_DAPM_ENUM("rx_int1_1_mix_inp2", rx_int1_1_mix_inp2_enum);
+static const struct snd_kcontrol_new rx_int2_1_mix_inp0_mux =
+               SOC_DAPM_ENUM("rx_int2_1_mix_inp0", rx_int2_1_mix_inp0_enum);
+static const struct snd_kcontrol_new rx_int2_1_mix_inp1_mux =
+               SOC_DAPM_ENUM("rx_int2_1_mix_inp1", rx_int2_1_mix_inp1_enum);
+static const struct snd_kcontrol_new rx_int2_1_mix_inp2_mux =
+               SOC_DAPM_ENUM("rx_int2_1_mix_inp2", rx_int2_1_mix_inp2_enum);
+static const struct snd_kcontrol_new rx_int0_mix2_inp_mux =
+               SOC_DAPM_ENUM("rx_int0_mix2_inp", rx_int0_mix2_inp_enum);
+static const struct snd_kcontrol_new rx_int1_mix2_inp_mux =
+               SOC_DAPM_ENUM("rx_int1_mix2_inp", rx_int1_mix2_inp_enum);
+static const struct snd_kcontrol_new rx_int2_mix2_inp_mux =
+               SOC_DAPM_ENUM("rx_int2_mix2_inp", rx_int2_mix2_inp_enum);
+static const struct snd_kcontrol_new iir0_inp0_mux =
+               SOC_DAPM_ENUM("iir0_inp0", iir0_inp0_enum);
+static const struct snd_kcontrol_new iir0_inp1_mux =
+               SOC_DAPM_ENUM("iir0_inp1", iir0_inp1_enum);
+static const struct snd_kcontrol_new iir0_inp2_mux =
+               SOC_DAPM_ENUM("iir0_inp2", iir0_inp2_enum);
+static const struct snd_kcontrol_new iir0_inp3_mux =
+               SOC_DAPM_ENUM("iir0_inp3", iir0_inp3_enum);
+static const struct snd_kcontrol_new iir1_inp0_mux =
+               SOC_DAPM_ENUM("iir1_inp0", iir1_inp0_enum);
+static const struct snd_kcontrol_new iir1_inp1_mux =
+               SOC_DAPM_ENUM("iir1_inp1", iir1_inp1_enum);
+static const struct snd_kcontrol_new iir1_inp2_mux =
+               SOC_DAPM_ENUM("iir1_inp2", iir1_inp2_enum);
+static const struct snd_kcontrol_new iir1_inp3_mux =
+               SOC_DAPM_ENUM("iir1_inp3", iir1_inp3_enum);
+static const struct snd_kcontrol_new rx_int0_1_interp_mux =
+               SOC_DAPM_ENUM("rx_int0_1_interp", rx_int0_1_interp_enum);
+static const struct snd_kcontrol_new rx_int1_1_interp_mux =
+               SOC_DAPM_ENUM("rx_int1_1_interp", rx_int1_1_interp_enum);
+static const struct snd_kcontrol_new rx_int2_1_interp_mux =
+               SOC_DAPM_ENUM("rx_int2_1_interp", rx_int2_1_interp_enum);
+static const struct snd_kcontrol_new rx_int0_2_interp_mux =
+               SOC_DAPM_ENUM("rx_int0_2_interp", rx_int0_2_interp_enum);
+static const struct snd_kcontrol_new rx_int1_2_interp_mux =
+               SOC_DAPM_ENUM("rx_int1_2_interp", rx_int1_2_interp_enum);
+static const struct snd_kcontrol_new rx_int2_2_interp_mux =
+               SOC_DAPM_ENUM("rx_int2_2_interp", rx_int2_2_interp_enum);
+static const struct snd_kcontrol_new rx_mix_tx0_mux =
+               SOC_DAPM_ENUM("RX MIX TX0_MUX Mux", rx_mix_tx0_mux_enum);
+
+static const struct reg_default rx_defaults[] = {
+       /* RX Macro */
+       { CDC_RX_TOP_TOP_CFG0, 0x00 },
+       { CDC_RX_TOP_SWR_CTRL, 0x00 },
+       { CDC_RX_TOP_DEBUG, 0x00 },
+       { CDC_RX_TOP_DEBUG_BUS, 0x00 },
+       { CDC_RX_TOP_DEBUG_EN0, 0x00 },
+       { CDC_RX_TOP_DEBUG_EN1, 0x00 },
+       { CDC_RX_TOP_DEBUG_EN2, 0x00 },
+       { CDC_RX_TOP_HPHL_COMP_WR_LSB, 0x00 },
+       { CDC_RX_TOP_HPHL_COMP_WR_MSB, 0x00 },
+       { CDC_RX_TOP_HPHL_COMP_LUT, 0x00 },
+       { CDC_RX_TOP_HPHL_COMP_RD_LSB, 0x00 },
+       { CDC_RX_TOP_HPHL_COMP_RD_MSB, 0x00 },
+       { CDC_RX_TOP_HPHR_COMP_WR_LSB, 0x00 },
+       { CDC_RX_TOP_HPHR_COMP_WR_MSB, 0x00 },
+       { CDC_RX_TOP_HPHR_COMP_LUT, 0x00 },
+       { CDC_RX_TOP_HPHR_COMP_RD_LSB, 0x00 },
+       { CDC_RX_TOP_HPHR_COMP_RD_MSB, 0x00 },
+       { CDC_RX_TOP_DSD0_DEBUG_CFG0, 0x11 },
+       { CDC_RX_TOP_DSD0_DEBUG_CFG1, 0x20 },
+       { CDC_RX_TOP_DSD0_DEBUG_CFG2, 0x00 },
+       { CDC_RX_TOP_DSD0_DEBUG_CFG3, 0x00 },
+       { CDC_RX_TOP_DSD1_DEBUG_CFG0, 0x11 },
+       { CDC_RX_TOP_DSD1_DEBUG_CFG1, 0x20 },
+       { CDC_RX_TOP_DSD1_DEBUG_CFG2, 0x00 },
+       { CDC_RX_TOP_DSD1_DEBUG_CFG3, 0x00 },
+       { CDC_RX_TOP_RX_I2S_CTL, 0x0C },
+       { CDC_RX_TOP_TX_I2S2_CTL, 0x0C },
+       { CDC_RX_TOP_I2S_CLK, 0x0C },
+       { CDC_RX_TOP_I2S_RESET, 0x00 },
+       { CDC_RX_TOP_I2S_MUX, 0x00 },
+       { CDC_RX_CLK_RST_CTRL_MCLK_CONTROL, 0x00 },
+       { CDC_RX_CLK_RST_CTRL_FS_CNT_CONTROL, 0x00 },
+       { CDC_RX_CLK_RST_CTRL_SWR_CONTROL, 0x00 },
+       { CDC_RX_CLK_RST_CTRL_DSD_CONTROL, 0x00 },
+       { CDC_RX_CLK_RST_CTRL_ASRC_SHARE_CONTROL, 0x08 },
+       { CDC_RX_SOFTCLIP_CRC, 0x00 },
+       { CDC_RX_SOFTCLIP_SOFTCLIP_CTRL, 0x38 },
+       { CDC_RX_INP_MUX_RX_INT0_CFG0, 0x00 },
+       { CDC_RX_INP_MUX_RX_INT0_CFG1, 0x00 },
+       { CDC_RX_INP_MUX_RX_INT1_CFG0, 0x00 },
+       { CDC_RX_INP_MUX_RX_INT1_CFG1, 0x00 },
+       { CDC_RX_INP_MUX_RX_INT2_CFG0, 0x00 },
+       { CDC_RX_INP_MUX_RX_INT2_CFG1, 0x00 },
+       { CDC_RX_INP_MUX_RX_MIX_CFG4, 0x00 },
+       { CDC_RX_INP_MUX_RX_MIX_CFG5, 0x00 },
+       { CDC_RX_INP_MUX_SIDETONE_SRC_CFG0, 0x00 },
+       { CDC_RX_CLSH_CRC, 0x00 },
+       { CDC_RX_CLSH_DLY_CTRL, 0x03 },
+       { CDC_RX_CLSH_DECAY_CTRL, 0x02 },
+       { CDC_RX_CLSH_HPH_V_PA, 0x1C },
+       { CDC_RX_CLSH_EAR_V_PA, 0x39 },
+       { CDC_RX_CLSH_HPH_V_HD, 0x0C },
+       { CDC_RX_CLSH_EAR_V_HD, 0x0C },
+       { CDC_RX_CLSH_K1_MSB, 0x01 },
+       { CDC_RX_CLSH_K1_LSB, 0x00 },
+       { CDC_RX_CLSH_K2_MSB, 0x00 },
+       { CDC_RX_CLSH_K2_LSB, 0x80 },
+       { CDC_RX_CLSH_IDLE_CTRL, 0x00 },
+       { CDC_RX_CLSH_IDLE_HPH, 0x00 },
+       { CDC_RX_CLSH_IDLE_EAR, 0x00 },
+       { CDC_RX_CLSH_TEST0, 0x07 },
+       { CDC_RX_CLSH_TEST1, 0x00 },
+       { CDC_RX_CLSH_OVR_VREF, 0x00 },
+       { CDC_RX_CLSH_CLSG_CTL, 0x02 },
+       { CDC_RX_CLSH_CLSG_CFG1, 0x9A },
+       { CDC_RX_CLSH_CLSG_CFG2, 0x10 },
+       { CDC_RX_BCL_VBAT_PATH_CTL, 0x00 },
+       { CDC_RX_BCL_VBAT_CFG, 0x10 },
+       { CDC_RX_BCL_VBAT_ADC_CAL1, 0x00 },
+       { CDC_RX_BCL_VBAT_ADC_CAL2, 0x00 },
+       { CDC_RX_BCL_VBAT_ADC_CAL3, 0x04 },
+       { CDC_RX_BCL_VBAT_PK_EST1, 0xE0 },
+       { CDC_RX_BCL_VBAT_PK_EST2, 0x01 },
+       { CDC_RX_BCL_VBAT_PK_EST3, 0x40 },
+       { CDC_RX_BCL_VBAT_RF_PROC1, 0x2A },
+       { CDC_RX_BCL_VBAT_RF_PROC1, 0x00 },
+       { CDC_RX_BCL_VBAT_TAC1, 0x00 },
+       { CDC_RX_BCL_VBAT_TAC2, 0x18 },
+       { CDC_RX_BCL_VBAT_TAC3, 0x18 },
+       { CDC_RX_BCL_VBAT_TAC4, 0x03 },
+       { CDC_RX_BCL_VBAT_GAIN_UPD1, 0x01 },
+       { CDC_RX_BCL_VBAT_GAIN_UPD2, 0x00 },
+       { CDC_RX_BCL_VBAT_GAIN_UPD3, 0x00 },
+       { CDC_RX_BCL_VBAT_GAIN_UPD4, 0x64 },
+       { CDC_RX_BCL_VBAT_GAIN_UPD5, 0x01 },
+       { CDC_RX_BCL_VBAT_DEBUG1, 0x00 },
+       { CDC_RX_BCL_VBAT_GAIN_UPD_MON, 0x00 },
+       { CDC_RX_BCL_VBAT_GAIN_MON_VAL, 0x00 },
+       { CDC_RX_BCL_VBAT_BAN, 0x0C },
+       { CDC_RX_BCL_VBAT_BCL_GAIN_UPD1, 0x00 },
+       { CDC_RX_BCL_VBAT_BCL_GAIN_UPD2, 0x77 },
+       { CDC_RX_BCL_VBAT_BCL_GAIN_UPD3, 0x01 },
+       { CDC_RX_BCL_VBAT_BCL_GAIN_UPD4, 0x00 },
+       { CDC_RX_BCL_VBAT_BCL_GAIN_UPD5, 0x4B },
+       { CDC_RX_BCL_VBAT_BCL_GAIN_UPD6, 0x00 },
+       { CDC_RX_BCL_VBAT_BCL_GAIN_UPD7, 0x01 },
+       { CDC_RX_BCL_VBAT_BCL_GAIN_UPD8, 0x00 },
+       { CDC_RX_BCL_VBAT_BCL_GAIN_UPD9, 0x00 },
+       { CDC_RX_BCL_VBAT_ATTN1, 0x04 },
+       { CDC_RX_BCL_VBAT_ATTN2, 0x08 },
+       { CDC_RX_BCL_VBAT_ATTN3, 0x0C },
+       { CDC_RX_BCL_VBAT_DECODE_CTL1, 0xE0 },
+       { CDC_RX_BCL_VBAT_DECODE_CTL2, 0x00 },
+       { CDC_RX_BCL_VBAT_DECODE_CFG1, 0x00 },
+       { CDC_RX_BCL_VBAT_DECODE_CFG2, 0x00 },
+       { CDC_RX_BCL_VBAT_DECODE_CFG3, 0x00 },
+       { CDC_RX_BCL_VBAT_DECODE_CFG4, 0x00 },
+       { CDC_RX_BCL_VBAT_DECODE_ST, 0x00 },
+       { CDC_RX_INTR_CTRL_CFG, 0x00 },
+       { CDC_RX_INTR_CTRL_CLR_COMMIT, 0x00 },
+       { CDC_RX_INTR_CTRL_PIN1_MASK0, 0xFF },
+       { CDC_RX_INTR_CTRL_PIN1_STATUS0, 0x00 },
+       { CDC_RX_INTR_CTRL_PIN1_CLEAR0, 0x00 },
+       { CDC_RX_INTR_CTRL_PIN2_MASK0, 0xFF },
+       { CDC_RX_INTR_CTRL_PIN2_STATUS0, 0x00 },
+       { CDC_RX_INTR_CTRL_PIN2_CLEAR0, 0x00 },
+       { CDC_RX_INTR_CTRL_LEVEL0, 0x00 },
+       { CDC_RX_INTR_CTRL_BYPASS0, 0x00 },
+       { CDC_RX_INTR_CTRL_SET0, 0x00 },
+       { CDC_RX_RX0_RX_PATH_CTL, 0x04 },
+       { CDC_RX_RX0_RX_PATH_CFG0, 0x00 },
+       { CDC_RX_RX0_RX_PATH_CFG1, 0x64 },
+       { CDC_RX_RX0_RX_PATH_CFG2, 0x8F },
+       { CDC_RX_RX0_RX_PATH_CFG3, 0x00 },
+       { CDC_RX_RX0_RX_VOL_CTL, 0x00 },
+       { CDC_RX_RX0_RX_PATH_MIX_CTL, 0x04 },
+       { CDC_RX_RX0_RX_PATH_MIX_CFG, 0x7E },
+       { CDC_RX_RX0_RX_VOL_MIX_CTL, 0x00 },
+       { CDC_RX_RX0_RX_PATH_SEC1, 0x08 },
+       { CDC_RX_RX0_RX_PATH_SEC2, 0x00 },
+       { CDC_RX_RX0_RX_PATH_SEC3, 0x00 },
+       { CDC_RX_RX0_RX_PATH_SEC4, 0x00 },
+       { CDC_RX_RX0_RX_PATH_SEC7, 0x00 },
+       { CDC_RX_RX0_RX_PATH_MIX_SEC0, 0x08 },
+       { CDC_RX_RX0_RX_PATH_MIX_SEC1, 0x00 },
+       { CDC_RX_RX0_RX_PATH_DSM_CTL, 0x08 },
+       { CDC_RX_RX0_RX_PATH_DSM_DATA1, 0x00 },
+       { CDC_RX_RX0_RX_PATH_DSM_DATA2, 0x00 },
+       { CDC_RX_RX0_RX_PATH_DSM_DATA3, 0x00 },
+       { CDC_RX_RX0_RX_PATH_DSM_DATA4, 0x55 },
+       { CDC_RX_RX0_RX_PATH_DSM_DATA5, 0x55 },
+       { CDC_RX_RX0_RX_PATH_DSM_DATA6, 0x55 },
+       { CDC_RX_RX1_RX_PATH_CTL, 0x04 },
+       { CDC_RX_RX1_RX_PATH_CFG0, 0x00 },
+       { CDC_RX_RX1_RX_PATH_CFG1, 0x64 },
+       { CDC_RX_RX1_RX_PATH_CFG2, 0x8F },
+       { CDC_RX_RX1_RX_PATH_CFG3, 0x00 },
+       { CDC_RX_RX1_RX_VOL_CTL, 0x00 },
+       { CDC_RX_RX1_RX_PATH_MIX_CTL, 0x04 },
+       { CDC_RX_RX1_RX_PATH_MIX_CFG, 0x7E },
+       { CDC_RX_RX1_RX_VOL_MIX_CTL, 0x00 },
+       { CDC_RX_RX1_RX_PATH_SEC1, 0x08 },
+       { CDC_RX_RX1_RX_PATH_SEC2, 0x00 },
+       { CDC_RX_RX1_RX_PATH_SEC3, 0x00 },
+       { CDC_RX_RX1_RX_PATH_SEC4, 0x00 },
+       { CDC_RX_RX1_RX_PATH_SEC7, 0x00 },
+       { CDC_RX_RX1_RX_PATH_MIX_SEC0, 0x08 },
+       { CDC_RX_RX1_RX_PATH_MIX_SEC1, 0x00 },
+       { CDC_RX_RX1_RX_PATH_DSM_CTL, 0x08 },
+       { CDC_RX_RX1_RX_PATH_DSM_DATA1, 0x00 },
+       { CDC_RX_RX1_RX_PATH_DSM_DATA2, 0x00 },
+       { CDC_RX_RX1_RX_PATH_DSM_DATA3, 0x00 },
+       { CDC_RX_RX1_RX_PATH_DSM_DATA4, 0x55 },
+       { CDC_RX_RX1_RX_PATH_DSM_DATA5, 0x55 },
+       { CDC_RX_RX1_RX_PATH_DSM_DATA6, 0x55 },
+       { CDC_RX_RX2_RX_PATH_CTL, 0x04 },
+       { CDC_RX_RX2_RX_PATH_CFG0, 0x00 },
+       { CDC_RX_RX2_RX_PATH_CFG1, 0x64 },
+       { CDC_RX_RX2_RX_PATH_CFG2, 0x8F },
+       { CDC_RX_RX2_RX_PATH_CFG3, 0x00 },
+       { CDC_RX_RX2_RX_VOL_CTL, 0x00 },
+       { CDC_RX_RX2_RX_PATH_MIX_CTL, 0x04 },
+       { CDC_RX_RX2_RX_PATH_MIX_CFG, 0x7E },
+       { CDC_RX_RX2_RX_VOL_MIX_CTL, 0x00 },
+       { CDC_RX_RX2_RX_PATH_SEC0, 0x04 },
+       { CDC_RX_RX2_RX_PATH_SEC1, 0x08 },
+       { CDC_RX_RX2_RX_PATH_SEC2, 0x00 },
+       { CDC_RX_RX2_RX_PATH_SEC3, 0x00 },
+       { CDC_RX_RX2_RX_PATH_SEC4, 0x00 },
+       { CDC_RX_RX2_RX_PATH_SEC5, 0x00 },
+       { CDC_RX_RX2_RX_PATH_SEC6, 0x00 },
+       { CDC_RX_RX2_RX_PATH_SEC7, 0x00 },
+       { CDC_RX_RX2_RX_PATH_MIX_SEC0, 0x08 },
+       { CDC_RX_RX2_RX_PATH_MIX_SEC1, 0x00 },
+       { CDC_RX_RX2_RX_PATH_DSM_CTL, 0x00 },
+       { CDC_RX_IDLE_DETECT_PATH_CTL, 0x00 },
+       { CDC_RX_IDLE_DETECT_CFG0, 0x07 },
+       { CDC_RX_IDLE_DETECT_CFG1, 0x3C },
+       { CDC_RX_IDLE_DETECT_CFG2, 0x00 },
+       { CDC_RX_IDLE_DETECT_CFG3, 0x00 },
+       { CDC_RX_COMPANDER0_CTL0, 0x60 },
+       { CDC_RX_COMPANDER0_CTL1, 0xDB },
+       { CDC_RX_COMPANDER0_CTL2, 0xFF },
+       { CDC_RX_COMPANDER0_CTL3, 0x35 },
+       { CDC_RX_COMPANDER0_CTL4, 0xFF },
+       { CDC_RX_COMPANDER0_CTL5, 0x00 },
+       { CDC_RX_COMPANDER0_CTL6, 0x01 },
+       { CDC_RX_COMPANDER0_CTL7, 0x28 },
+       { CDC_RX_COMPANDER1_CTL0, 0x60 },
+       { CDC_RX_COMPANDER1_CTL1, 0xDB },
+       { CDC_RX_COMPANDER1_CTL2, 0xFF },
+       { CDC_RX_COMPANDER1_CTL3, 0x35 },
+       { CDC_RX_COMPANDER1_CTL4, 0xFF },
+       { CDC_RX_COMPANDER1_CTL5, 0x00 },
+       { CDC_RX_COMPANDER1_CTL6, 0x01 },
+       { CDC_RX_COMPANDER1_CTL7, 0x28 },
+       { CDC_RX_SIDETONE_IIR0_IIR_PATH_CTL, 0x00 },
+       { CDC_RX_SIDETONE_IIR0_IIR_GAIN_B1_CTL, 0x00 },
+       { CDC_RX_SIDETONE_IIR0_IIR_GAIN_B2_CTL, 0x00 },
+       { CDC_RX_SIDETONE_IIR0_IIR_GAIN_B3_CTL, 0x00 },
+       { CDC_RX_SIDETONE_IIR0_IIR_GAIN_B4_CTL, 0x00 },
+       { CDC_RX_SIDETONE_IIR0_IIR_GAIN_B5_CTL, 0x00 },
+       { CDC_RX_SIDETONE_IIR0_IIR_GAIN_B6_CTL, 0x00 },
+       { CDC_RX_SIDETONE_IIR0_IIR_GAIN_B7_CTL, 0x00 },
+       { CDC_RX_SIDETONE_IIR0_IIR_GAIN_B8_CTL, 0x00 },
+       { CDC_RX_SIDETONE_IIR0_IIR_CTL, 0x40 },
+       { CDC_RX_SIDETONE_IIR0_IIR_GAIN_TIMER_CTL, 0x00 },
+       { CDC_RX_SIDETONE_IIR0_IIR_COEF_B1_CTL, 0x00 },
+       { CDC_RX_SIDETONE_IIR0_IIR_COEF_B2_CTL, 0x00 },
+       { CDC_RX_SIDETONE_IIR1_IIR_PATH_CTL, 0x00 },
+       { CDC_RX_SIDETONE_IIR1_IIR_GAIN_B1_CTL, 0x00 },
+       { CDC_RX_SIDETONE_IIR1_IIR_GAIN_B2_CTL, 0x00 },
+       { CDC_RX_SIDETONE_IIR1_IIR_GAIN_B3_CTL, 0x00 },
+       { CDC_RX_SIDETONE_IIR1_IIR_GAIN_B4_CTL, 0x00 },
+       { CDC_RX_SIDETONE_IIR1_IIR_GAIN_B5_CTL, 0x00 },
+       { CDC_RX_SIDETONE_IIR1_IIR_GAIN_B6_CTL, 0x00 },
+       { CDC_RX_SIDETONE_IIR1_IIR_GAIN_B7_CTL, 0x00 },
+       { CDC_RX_SIDETONE_IIR1_IIR_GAIN_B8_CTL, 0x00 },
+       { CDC_RX_SIDETONE_IIR1_IIR_CTL, 0x40 },
+       { CDC_RX_SIDETONE_IIR1_IIR_GAIN_TIMER_CTL, 0x00 },
+       { CDC_RX_SIDETONE_IIR1_IIR_COEF_B1_CTL, 0x00 },
+       { CDC_RX_SIDETONE_IIR1_IIR_COEF_B2_CTL, 0x00 },
+       { CDC_RX_IIR_INP_MUX_IIR0_MIX_CFG0, 0x00 },
+       { CDC_RX_IIR_INP_MUX_IIR0_MIX_CFG1, 0x00 },
+       { CDC_RX_IIR_INP_MUX_IIR0_MIX_CFG2, 0x00 },
+       { CDC_RX_IIR_INP_MUX_IIR0_MIX_CFG3, 0x00 },
+       { CDC_RX_IIR_INP_MUX_IIR1_MIX_CFG0, 0x00 },
+       { CDC_RX_IIR_INP_MUX_IIR1_MIX_CFG1, 0x00 },
+       { CDC_RX_IIR_INP_MUX_IIR1_MIX_CFG2, 0x00 },
+       { CDC_RX_IIR_INP_MUX_IIR1_MIX_CFG3, 0x00 },
+       { CDC_RX_SIDETONE_SRC0_ST_SRC_PATH_CTL, 0x04 },
+       { CDC_RX_SIDETONE_SRC0_ST_SRC_PATH_CFG1, 0x00 },
+       { CDC_RX_SIDETONE_SRC1_ST_SRC_PATH_CTL, 0x04 },
+       { CDC_RX_SIDETONE_SRC1_ST_SRC_PATH_CFG1, 0x00 },
+       { CDC_RX_EC_REF_HQ0_EC_REF_HQ_PATH_CTL, 0x00 },
+       { CDC_RX_EC_REF_HQ0_EC_REF_HQ_CFG0, 0x01 },
+       { CDC_RX_EC_REF_HQ1_EC_REF_HQ_PATH_CTL, 0x00 },
+       { CDC_RX_EC_REF_HQ1_EC_REF_HQ_CFG0, 0x01 },
+       { CDC_RX_EC_REF_HQ2_EC_REF_HQ_PATH_CTL, 0x00 },
+       { CDC_RX_EC_REF_HQ2_EC_REF_HQ_CFG0, 0x01 },
+       { CDC_RX_EC_ASRC0_CLK_RST_CTL, 0x00 },
+       { CDC_RX_EC_ASRC0_CTL0, 0x00 },
+       { CDC_RX_EC_ASRC0_CTL1, 0x00 },
+       { CDC_RX_EC_ASRC0_FIFO_CTL, 0xA8 },
+       { CDC_RX_EC_ASRC0_STATUS_FMIN_CNTR_LSB, 0x00 },
+       { CDC_RX_EC_ASRC0_STATUS_FMIN_CNTR_MSB, 0x00 },
+       { CDC_RX_EC_ASRC0_STATUS_FMAX_CNTR_LSB, 0x00 },
+       { CDC_RX_EC_ASRC0_STATUS_FMAX_CNTR_MSB, 0x00 },
+       { CDC_RX_EC_ASRC0_STATUS_FIFO, 0x00 },
+       { CDC_RX_EC_ASRC1_CLK_RST_CTL, 0x00 },
+       { CDC_RX_EC_ASRC1_CTL0, 0x00 },
+       { CDC_RX_EC_ASRC1_CTL1, 0x00 },
+       { CDC_RX_EC_ASRC1_FIFO_CTL, 0xA8 },
+       { CDC_RX_EC_ASRC1_STATUS_FMIN_CNTR_LSB, 0x00 },
+       { CDC_RX_EC_ASRC1_STATUS_FMIN_CNTR_MSB, 0x00 },
+       { CDC_RX_EC_ASRC1_STATUS_FMAX_CNTR_LSB, 0x00 },
+       { CDC_RX_EC_ASRC1_STATUS_FMAX_CNTR_MSB, 0x00 },
+       { CDC_RX_EC_ASRC1_STATUS_FIFO, 0x00 },
+       { CDC_RX_EC_ASRC2_CLK_RST_CTL, 0x00 },
+       { CDC_RX_EC_ASRC2_CTL0, 0x00 },
+       { CDC_RX_EC_ASRC2_CTL1, 0x00 },
+       { CDC_RX_EC_ASRC2_FIFO_CTL, 0xA8 },
+       { CDC_RX_EC_ASRC2_STATUS_FMIN_CNTR_LSB, 0x00 },
+       { CDC_RX_EC_ASRC2_STATUS_FMIN_CNTR_MSB, 0x00 },
+       { CDC_RX_EC_ASRC2_STATUS_FMAX_CNTR_LSB, 0x00 },
+       { CDC_RX_EC_ASRC2_STATUS_FMAX_CNTR_MSB, 0x00 },
+       { CDC_RX_EC_ASRC2_STATUS_FIFO, 0x00 },
+       { CDC_RX_DSD0_PATH_CTL, 0x00 },
+       { CDC_RX_DSD0_CFG0, 0x00 },
+       { CDC_RX_DSD0_CFG1, 0x62 },
+       { CDC_RX_DSD0_CFG2, 0x96 },
+       { CDC_RX_DSD1_PATH_CTL, 0x00 },
+       { CDC_RX_DSD1_CFG0, 0x00 },
+       { CDC_RX_DSD1_CFG1, 0x62 },
+       { CDC_RX_DSD1_CFG2, 0x96 },
+};
+
+static bool rx_is_wronly_register(struct device *dev,
+                                       unsigned int reg)
+{
+       switch (reg) {
+       case CDC_RX_BCL_VBAT_GAIN_UPD_MON:
+       case CDC_RX_INTR_CTRL_CLR_COMMIT:
+       case CDC_RX_INTR_CTRL_PIN1_CLEAR0:
+       case CDC_RX_INTR_CTRL_PIN2_CLEAR0:
+               return true;
+       }
+
+       return false;
+}
+
+static bool rx_is_volatile_register(struct device *dev, unsigned int reg)
+{
+       /* Update volatile list for rx/tx macros */
+       switch (reg) {
+       case CDC_RX_TOP_HPHL_COMP_RD_LSB:
+       case CDC_RX_TOP_HPHL_COMP_WR_LSB:
+       case CDC_RX_TOP_HPHL_COMP_RD_MSB:
+       case CDC_RX_TOP_HPHL_COMP_WR_MSB:
+       case CDC_RX_TOP_HPHR_COMP_RD_LSB:
+       case CDC_RX_TOP_HPHR_COMP_WR_LSB:
+       case CDC_RX_TOP_HPHR_COMP_RD_MSB:
+       case CDC_RX_TOP_HPHR_COMP_WR_MSB:
+       case CDC_RX_TOP_DSD0_DEBUG_CFG2:
+       case CDC_RX_TOP_DSD1_DEBUG_CFG2:
+       case CDC_RX_BCL_VBAT_GAIN_MON_VAL:
+       case CDC_RX_BCL_VBAT_DECODE_ST:
+       case CDC_RX_INTR_CTRL_PIN1_STATUS0:
+       case CDC_RX_INTR_CTRL_PIN2_STATUS0:
+       case CDC_RX_COMPANDER0_CTL6:
+       case CDC_RX_COMPANDER1_CTL6:
+       case CDC_RX_EC_ASRC0_STATUS_FMIN_CNTR_LSB:
+       case CDC_RX_EC_ASRC0_STATUS_FMIN_CNTR_MSB:
+       case CDC_RX_EC_ASRC0_STATUS_FMAX_CNTR_LSB:
+       case CDC_RX_EC_ASRC0_STATUS_FMAX_CNTR_MSB:
+       case CDC_RX_EC_ASRC0_STATUS_FIFO:
+       case CDC_RX_EC_ASRC1_STATUS_FMIN_CNTR_LSB:
+       case CDC_RX_EC_ASRC1_STATUS_FMIN_CNTR_MSB:
+       case CDC_RX_EC_ASRC1_STATUS_FMAX_CNTR_LSB:
+       case CDC_RX_EC_ASRC1_STATUS_FMAX_CNTR_MSB:
+       case CDC_RX_EC_ASRC1_STATUS_FIFO:
+       case CDC_RX_EC_ASRC2_STATUS_FMIN_CNTR_LSB:
+       case CDC_RX_EC_ASRC2_STATUS_FMIN_CNTR_MSB:
+       case CDC_RX_EC_ASRC2_STATUS_FMAX_CNTR_LSB:
+       case CDC_RX_EC_ASRC2_STATUS_FMAX_CNTR_MSB:
+       case CDC_RX_EC_ASRC2_STATUS_FIFO:
+               return true;
+       }
+       return false;
+}
+
+static bool rx_is_rw_register(struct device *dev, unsigned int reg)
+{
+       switch (reg) {
+       case CDC_RX_TOP_TOP_CFG0:
+       case CDC_RX_TOP_SWR_CTRL:
+       case CDC_RX_TOP_DEBUG:
+       case CDC_RX_TOP_DEBUG_BUS:
+       case CDC_RX_TOP_DEBUG_EN0:
+       case CDC_RX_TOP_DEBUG_EN1:
+       case CDC_RX_TOP_DEBUG_EN2:
+       case CDC_RX_TOP_HPHL_COMP_WR_LSB:
+       case CDC_RX_TOP_HPHL_COMP_WR_MSB:
+       case CDC_RX_TOP_HPHL_COMP_LUT:
+       case CDC_RX_TOP_HPHR_COMP_WR_LSB:
+       case CDC_RX_TOP_HPHR_COMP_WR_MSB:
+       case CDC_RX_TOP_HPHR_COMP_LUT:
+       case CDC_RX_TOP_DSD0_DEBUG_CFG0:
+       case CDC_RX_TOP_DSD0_DEBUG_CFG1:
+       case CDC_RX_TOP_DSD0_DEBUG_CFG3:
+       case CDC_RX_TOP_DSD1_DEBUG_CFG0:
+       case CDC_RX_TOP_DSD1_DEBUG_CFG1:
+       case CDC_RX_TOP_DSD1_DEBUG_CFG3:
+       case CDC_RX_TOP_RX_I2S_CTL:
+       case CDC_RX_TOP_TX_I2S2_CTL:
+       case CDC_RX_TOP_I2S_CLK:
+       case CDC_RX_TOP_I2S_RESET:
+       case CDC_RX_TOP_I2S_MUX:
+       case CDC_RX_CLK_RST_CTRL_MCLK_CONTROL:
+       case CDC_RX_CLK_RST_CTRL_FS_CNT_CONTROL:
+       case CDC_RX_CLK_RST_CTRL_SWR_CONTROL:
+       case CDC_RX_CLK_RST_CTRL_DSD_CONTROL:
+       case CDC_RX_CLK_RST_CTRL_ASRC_SHARE_CONTROL:
+       case CDC_RX_SOFTCLIP_CRC:
+       case CDC_RX_SOFTCLIP_SOFTCLIP_CTRL:
+       case CDC_RX_INP_MUX_RX_INT0_CFG0:
+       case CDC_RX_INP_MUX_RX_INT0_CFG1:
+       case CDC_RX_INP_MUX_RX_INT1_CFG0:
+       case CDC_RX_INP_MUX_RX_INT1_CFG1:
+       case CDC_RX_INP_MUX_RX_INT2_CFG0:
+       case CDC_RX_INP_MUX_RX_INT2_CFG1:
+       case CDC_RX_INP_MUX_RX_MIX_CFG4:
+       case CDC_RX_INP_MUX_RX_MIX_CFG5:
+       case CDC_RX_INP_MUX_SIDETONE_SRC_CFG0:
+       case CDC_RX_CLSH_CRC:
+       case CDC_RX_CLSH_DLY_CTRL:
+       case CDC_RX_CLSH_DECAY_CTRL:
+       case CDC_RX_CLSH_HPH_V_PA:
+       case CDC_RX_CLSH_EAR_V_PA:
+       case CDC_RX_CLSH_HPH_V_HD:
+       case CDC_RX_CLSH_EAR_V_HD:
+       case CDC_RX_CLSH_K1_MSB:
+       case CDC_RX_CLSH_K1_LSB:
+       case CDC_RX_CLSH_K2_MSB:
+       case CDC_RX_CLSH_K2_LSB:
+       case CDC_RX_CLSH_IDLE_CTRL:
+       case CDC_RX_CLSH_IDLE_HPH:
+       case CDC_RX_CLSH_IDLE_EAR:
+       case CDC_RX_CLSH_TEST0:
+       case CDC_RX_CLSH_TEST1:
+       case CDC_RX_CLSH_OVR_VREF:
+       case CDC_RX_CLSH_CLSG_CTL:
+       case CDC_RX_CLSH_CLSG_CFG1:
+       case CDC_RX_CLSH_CLSG_CFG2:
+       case CDC_RX_BCL_VBAT_PATH_CTL:
+       case CDC_RX_BCL_VBAT_CFG:
+       case CDC_RX_BCL_VBAT_ADC_CAL1:
+       case CDC_RX_BCL_VBAT_ADC_CAL2:
+       case CDC_RX_BCL_VBAT_ADC_CAL3:
+       case CDC_RX_BCL_VBAT_PK_EST1:
+       case CDC_RX_BCL_VBAT_PK_EST2:
+       case CDC_RX_BCL_VBAT_PK_EST3:
+       case CDC_RX_BCL_VBAT_RF_PROC1:
+       case CDC_RX_BCL_VBAT_RF_PROC2:
+       case CDC_RX_BCL_VBAT_TAC1:
+       case CDC_RX_BCL_VBAT_TAC2:
+       case CDC_RX_BCL_VBAT_TAC3:
+       case CDC_RX_BCL_VBAT_TAC4:
+       case CDC_RX_BCL_VBAT_GAIN_UPD1:
+       case CDC_RX_BCL_VBAT_GAIN_UPD2:
+       case CDC_RX_BCL_VBAT_GAIN_UPD3:
+       case CDC_RX_BCL_VBAT_GAIN_UPD4:
+       case CDC_RX_BCL_VBAT_GAIN_UPD5:
+       case CDC_RX_BCL_VBAT_DEBUG1:
+       case CDC_RX_BCL_VBAT_BAN:
+       case CDC_RX_BCL_VBAT_BCL_GAIN_UPD1:
+       case CDC_RX_BCL_VBAT_BCL_GAIN_UPD2:
+       case CDC_RX_BCL_VBAT_BCL_GAIN_UPD3:
+       case CDC_RX_BCL_VBAT_BCL_GAIN_UPD4:
+       case CDC_RX_BCL_VBAT_BCL_GAIN_UPD5:
+       case CDC_RX_BCL_VBAT_BCL_GAIN_UPD6:
+       case CDC_RX_BCL_VBAT_BCL_GAIN_UPD7:
+       case CDC_RX_BCL_VBAT_BCL_GAIN_UPD8:
+       case CDC_RX_BCL_VBAT_BCL_GAIN_UPD9:
+       case CDC_RX_BCL_VBAT_ATTN1:
+       case CDC_RX_BCL_VBAT_ATTN2:
+       case CDC_RX_BCL_VBAT_ATTN3:
+       case CDC_RX_BCL_VBAT_DECODE_CTL1:
+       case CDC_RX_BCL_VBAT_DECODE_CTL2:
+       case CDC_RX_BCL_VBAT_DECODE_CFG1:
+       case CDC_RX_BCL_VBAT_DECODE_CFG2:
+       case CDC_RX_BCL_VBAT_DECODE_CFG3:
+       case CDC_RX_BCL_VBAT_DECODE_CFG4:
+       case CDC_RX_INTR_CTRL_CFG:
+       case CDC_RX_INTR_CTRL_PIN1_MASK0:
+       case CDC_RX_INTR_CTRL_PIN2_MASK0:
+       case CDC_RX_INTR_CTRL_LEVEL0:
+       case CDC_RX_INTR_CTRL_BYPASS0:
+       case CDC_RX_INTR_CTRL_SET0:
+       case CDC_RX_RX0_RX_PATH_CTL:
+       case CDC_RX_RX0_RX_PATH_CFG0:
+       case CDC_RX_RX0_RX_PATH_CFG1:
+       case CDC_RX_RX0_RX_PATH_CFG2:
+       case CDC_RX_RX0_RX_PATH_CFG3:
+       case CDC_RX_RX0_RX_VOL_CTL:
+       case CDC_RX_RX0_RX_PATH_MIX_CTL:
+       case CDC_RX_RX0_RX_PATH_MIX_CFG:
+       case CDC_RX_RX0_RX_VOL_MIX_CTL:
+       case CDC_RX_RX0_RX_PATH_SEC1:
+       case CDC_RX_RX0_RX_PATH_SEC2:
+       case CDC_RX_RX0_RX_PATH_SEC3:
+       case CDC_RX_RX0_RX_PATH_SEC4:
+       case CDC_RX_RX0_RX_PATH_SEC7:
+       case CDC_RX_RX0_RX_PATH_MIX_SEC0:
+       case CDC_RX_RX0_RX_PATH_MIX_SEC1:
+       case CDC_RX_RX0_RX_PATH_DSM_CTL:
+       case CDC_RX_RX0_RX_PATH_DSM_DATA1:
+       case CDC_RX_RX0_RX_PATH_DSM_DATA2:
+       case CDC_RX_RX0_RX_PATH_DSM_DATA3:
+       case CDC_RX_RX0_RX_PATH_DSM_DATA4:
+       case CDC_RX_RX0_RX_PATH_DSM_DATA5:
+       case CDC_RX_RX0_RX_PATH_DSM_DATA6:
+       case CDC_RX_RX1_RX_PATH_CTL:
+       case CDC_RX_RX1_RX_PATH_CFG0:
+       case CDC_RX_RX1_RX_PATH_CFG1:
+       case CDC_RX_RX1_RX_PATH_CFG2:
+       case CDC_RX_RX1_RX_PATH_CFG3:
+       case CDC_RX_RX1_RX_VOL_CTL:
+       case CDC_RX_RX1_RX_PATH_MIX_CTL:
+       case CDC_RX_RX1_RX_PATH_MIX_CFG:
+       case CDC_RX_RX1_RX_VOL_MIX_CTL:
+       case CDC_RX_RX1_RX_PATH_SEC1:
+       case CDC_RX_RX1_RX_PATH_SEC2:
+       case CDC_RX_RX1_RX_PATH_SEC3:
+       case CDC_RX_RX1_RX_PATH_SEC4:
+       case CDC_RX_RX1_RX_PATH_SEC7:
+       case CDC_RX_RX1_RX_PATH_MIX_SEC0:
+       case CDC_RX_RX1_RX_PATH_MIX_SEC1:
+       case CDC_RX_RX1_RX_PATH_DSM_CTL:
+       case CDC_RX_RX1_RX_PATH_DSM_DATA1:
+       case CDC_RX_RX1_RX_PATH_DSM_DATA2:
+       case CDC_RX_RX1_RX_PATH_DSM_DATA3:
+       case CDC_RX_RX1_RX_PATH_DSM_DATA4:
+       case CDC_RX_RX1_RX_PATH_DSM_DATA5:
+       case CDC_RX_RX1_RX_PATH_DSM_DATA6:
+       case CDC_RX_RX2_RX_PATH_CTL:
+       case CDC_RX_RX2_RX_PATH_CFG0:
+       case CDC_RX_RX2_RX_PATH_CFG1:
+       case CDC_RX_RX2_RX_PATH_CFG2:
+       case CDC_RX_RX2_RX_PATH_CFG3:
+       case CDC_RX_RX2_RX_VOL_CTL:
+       case CDC_RX_RX2_RX_PATH_MIX_CTL:
+       case CDC_RX_RX2_RX_PATH_MIX_CFG:
+       case CDC_RX_RX2_RX_VOL_MIX_CTL:
+       case CDC_RX_RX2_RX_PATH_SEC0:
+       case CDC_RX_RX2_RX_PATH_SEC1:
+       case CDC_RX_RX2_RX_PATH_SEC2:
+       case CDC_RX_RX2_RX_PATH_SEC3:
+       case CDC_RX_RX2_RX_PATH_SEC4:
+       case CDC_RX_RX2_RX_PATH_SEC5:
+       case CDC_RX_RX2_RX_PATH_SEC6:
+       case CDC_RX_RX2_RX_PATH_SEC7:
+       case CDC_RX_RX2_RX_PATH_MIX_SEC0:
+       case CDC_RX_RX2_RX_PATH_MIX_SEC1:
+       case CDC_RX_RX2_RX_PATH_DSM_CTL:
+       case CDC_RX_IDLE_DETECT_PATH_CTL:
+       case CDC_RX_IDLE_DETECT_CFG0:
+       case CDC_RX_IDLE_DETECT_CFG1:
+       case CDC_RX_IDLE_DETECT_CFG2:
+       case CDC_RX_IDLE_DETECT_CFG3:
+       case CDC_RX_COMPANDER0_CTL0:
+       case CDC_RX_COMPANDER0_CTL1:
+       case CDC_RX_COMPANDER0_CTL2:
+       case CDC_RX_COMPANDER0_CTL3:
+       case CDC_RX_COMPANDER0_CTL4:
+       case CDC_RX_COMPANDER0_CTL5:
+       case CDC_RX_COMPANDER0_CTL7:
+       case CDC_RX_COMPANDER1_CTL0:
+       case CDC_RX_COMPANDER1_CTL1:
+       case CDC_RX_COMPANDER1_CTL2:
+       case CDC_RX_COMPANDER1_CTL3:
+       case CDC_RX_COMPANDER1_CTL4:
+       case CDC_RX_COMPANDER1_CTL5:
+       case CDC_RX_COMPANDER1_CTL7:
+       case CDC_RX_SIDETONE_IIR0_IIR_PATH_CTL:
+       case CDC_RX_SIDETONE_IIR0_IIR_GAIN_B1_CTL:
+       case CDC_RX_SIDETONE_IIR0_IIR_GAIN_B2_CTL:
+       case CDC_RX_SIDETONE_IIR0_IIR_GAIN_B3_CTL:
+       case CDC_RX_SIDETONE_IIR0_IIR_GAIN_B4_CTL:
+       case CDC_RX_SIDETONE_IIR0_IIR_GAIN_B5_CTL:
+       case CDC_RX_SIDETONE_IIR0_IIR_GAIN_B6_CTL:
+       case CDC_RX_SIDETONE_IIR0_IIR_GAIN_B7_CTL:
+       case CDC_RX_SIDETONE_IIR0_IIR_GAIN_B8_CTL:
+       case CDC_RX_SIDETONE_IIR0_IIR_CTL:
+       case CDC_RX_SIDETONE_IIR0_IIR_GAIN_TIMER_CTL:
+       case CDC_RX_SIDETONE_IIR0_IIR_COEF_B1_CTL:
+       case CDC_RX_SIDETONE_IIR0_IIR_COEF_B2_CTL:
+       case CDC_RX_SIDETONE_IIR1_IIR_PATH_CTL:
+       case CDC_RX_SIDETONE_IIR1_IIR_GAIN_B1_CTL:
+       case CDC_RX_SIDETONE_IIR1_IIR_GAIN_B2_CTL:
+       case CDC_RX_SIDETONE_IIR1_IIR_GAIN_B3_CTL:
+       case CDC_RX_SIDETONE_IIR1_IIR_GAIN_B4_CTL:
+       case CDC_RX_SIDETONE_IIR1_IIR_GAIN_B5_CTL:
+       case CDC_RX_SIDETONE_IIR1_IIR_GAIN_B6_CTL:
+       case CDC_RX_SIDETONE_IIR1_IIR_GAIN_B7_CTL:
+       case CDC_RX_SIDETONE_IIR1_IIR_GAIN_B8_CTL:
+       case CDC_RX_SIDETONE_IIR1_IIR_CTL:
+       case CDC_RX_SIDETONE_IIR1_IIR_GAIN_TIMER_CTL:
+       case CDC_RX_SIDETONE_IIR1_IIR_COEF_B1_CTL:
+       case CDC_RX_SIDETONE_IIR1_IIR_COEF_B2_CTL:
+       case CDC_RX_IIR_INP_MUX_IIR0_MIX_CFG0:
+       case CDC_RX_IIR_INP_MUX_IIR0_MIX_CFG1:
+       case CDC_RX_IIR_INP_MUX_IIR0_MIX_CFG2:
+       case CDC_RX_IIR_INP_MUX_IIR0_MIX_CFG3:
+       case CDC_RX_IIR_INP_MUX_IIR1_MIX_CFG0:
+       case CDC_RX_IIR_INP_MUX_IIR1_MIX_CFG1:
+       case CDC_RX_IIR_INP_MUX_IIR1_MIX_CFG2:
+       case CDC_RX_IIR_INP_MUX_IIR1_MIX_CFG3:
+       case CDC_RX_SIDETONE_SRC0_ST_SRC_PATH_CTL:
+       case CDC_RX_SIDETONE_SRC0_ST_SRC_PATH_CFG1:
+       case CDC_RX_SIDETONE_SRC1_ST_SRC_PATH_CTL:
+       case CDC_RX_SIDETONE_SRC1_ST_SRC_PATH_CFG1:
+       case CDC_RX_EC_REF_HQ0_EC_REF_HQ_PATH_CTL:
+       case CDC_RX_EC_REF_HQ0_EC_REF_HQ_CFG0:
+       case CDC_RX_EC_REF_HQ1_EC_REF_HQ_PATH_CTL:
+       case CDC_RX_EC_REF_HQ1_EC_REF_HQ_CFG0:
+       case CDC_RX_EC_REF_HQ2_EC_REF_HQ_PATH_CTL:
+       case CDC_RX_EC_REF_HQ2_EC_REF_HQ_CFG0:
+       case CDC_RX_EC_ASRC0_CLK_RST_CTL:
+       case CDC_RX_EC_ASRC0_CTL0:
+       case CDC_RX_EC_ASRC0_CTL1:
+       case CDC_RX_EC_ASRC0_FIFO_CTL:
+       case CDC_RX_EC_ASRC1_CLK_RST_CTL:
+       case CDC_RX_EC_ASRC1_CTL0:
+       case CDC_RX_EC_ASRC1_CTL1:
+       case CDC_RX_EC_ASRC1_FIFO_CTL:
+       case CDC_RX_EC_ASRC2_CLK_RST_CTL:
+       case CDC_RX_EC_ASRC2_CTL0:
+       case CDC_RX_EC_ASRC2_CTL1:
+       case CDC_RX_EC_ASRC2_FIFO_CTL:
+       case CDC_RX_DSD0_PATH_CTL:
+       case CDC_RX_DSD0_CFG0:
+       case CDC_RX_DSD0_CFG1:
+       case CDC_RX_DSD0_CFG2:
+       case CDC_RX_DSD1_PATH_CTL:
+       case CDC_RX_DSD1_CFG0:
+       case CDC_RX_DSD1_CFG1:
+       case CDC_RX_DSD1_CFG2:
+               return true;
+       }
+
+       return false;
+}
+
+static bool rx_is_writeable_register(struct device *dev, unsigned int reg)
+{
+       bool ret;
+
+       ret = rx_is_rw_register(dev, reg);
+       if (!ret)
+               return rx_is_wronly_register(dev, reg);
+
+       return ret;
+}
+
+static bool rx_is_readable_register(struct device *dev, unsigned int reg)
+{
+       switch (reg) {
+       case CDC_RX_TOP_HPHL_COMP_RD_LSB:
+       case CDC_RX_TOP_HPHL_COMP_RD_MSB:
+       case CDC_RX_TOP_HPHR_COMP_RD_LSB:
+       case CDC_RX_TOP_HPHR_COMP_RD_MSB:
+       case CDC_RX_TOP_DSD0_DEBUG_CFG2:
+       case CDC_RX_TOP_DSD1_DEBUG_CFG2:
+       case CDC_RX_BCL_VBAT_GAIN_MON_VAL:
+       case CDC_RX_BCL_VBAT_DECODE_ST:
+       case CDC_RX_INTR_CTRL_PIN1_STATUS0:
+       case CDC_RX_INTR_CTRL_PIN2_STATUS0:
+       case CDC_RX_COMPANDER0_CTL6:
+       case CDC_RX_COMPANDER1_CTL6:
+       case CDC_RX_EC_ASRC0_STATUS_FMIN_CNTR_LSB:
+       case CDC_RX_EC_ASRC0_STATUS_FMIN_CNTR_MSB:
+       case CDC_RX_EC_ASRC0_STATUS_FMAX_CNTR_LSB:
+       case CDC_RX_EC_ASRC0_STATUS_FMAX_CNTR_MSB:
+       case CDC_RX_EC_ASRC0_STATUS_FIFO:
+       case CDC_RX_EC_ASRC1_STATUS_FMIN_CNTR_LSB:
+       case CDC_RX_EC_ASRC1_STATUS_FMIN_CNTR_MSB:
+       case CDC_RX_EC_ASRC1_STATUS_FMAX_CNTR_LSB:
+       case CDC_RX_EC_ASRC1_STATUS_FMAX_CNTR_MSB:
+       case CDC_RX_EC_ASRC1_STATUS_FIFO:
+       case CDC_RX_EC_ASRC2_STATUS_FMIN_CNTR_LSB:
+       case CDC_RX_EC_ASRC2_STATUS_FMIN_CNTR_MSB:
+       case CDC_RX_EC_ASRC2_STATUS_FMAX_CNTR_LSB:
+       case CDC_RX_EC_ASRC2_STATUS_FMAX_CNTR_MSB:
+       case CDC_RX_EC_ASRC2_STATUS_FIFO:
+               return true;
+       }
+
+       return rx_is_rw_register(dev, reg);
+}
+
+static const struct regmap_config rx_regmap_config = {
+       .name = "rx_macro",
+       .reg_bits = 16,
+       .val_bits = 32, /* 8 but with 32 bit read/write */
+       .reg_stride = 4,
+       .cache_type = REGCACHE_FLAT,
+       .reg_defaults = rx_defaults,
+       .num_reg_defaults = ARRAY_SIZE(rx_defaults),
+       .max_register = RX_MAX_OFFSET,
+       .writeable_reg = rx_is_writeable_register,
+       .volatile_reg = rx_is_volatile_register,
+       .readable_reg = rx_is_readable_register,
+};
+
+static int rx_macro_int_dem_inp_mux_put(struct snd_kcontrol *kcontrol,
+                                       struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_dapm_widget *widget = snd_soc_dapm_kcontrol_widget(kcontrol);
+       struct snd_soc_component *component = snd_soc_dapm_to_component(widget->dapm);
+       struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
+       unsigned short look_ahead_dly_reg;
+       unsigned int val;
+
+       val = ucontrol->value.enumerated.item[0];
+
+       if (e->reg == CDC_RX_RX0_RX_PATH_CFG1)
+               look_ahead_dly_reg = CDC_RX_RX0_RX_PATH_CFG0;
+       else if (e->reg == CDC_RX_RX1_RX_PATH_CFG1)
+               look_ahead_dly_reg = CDC_RX_RX1_RX_PATH_CFG0;
+
+       /* Set Look Ahead Delay */
+       if (val)
+               snd_soc_component_update_bits(component, look_ahead_dly_reg,
+                                             CDC_RX_DLY_ZN_EN_MASK,
+                                             CDC_RX_DLY_ZN_ENABLE);
+       else
+               snd_soc_component_update_bits(component, look_ahead_dly_reg,
+                                             CDC_RX_DLY_ZN_EN_MASK, 0);
+       /* Set DEM INP Select */
+       return snd_soc_dapm_put_enum_double(kcontrol, ucontrol);
+}
+
+static const struct snd_kcontrol_new rx_int0_dem_inp_mux =
+               SOC_DAPM_ENUM_EXT("rx_int0_dem_inp", rx_int0_dem_inp_enum,
+                 snd_soc_dapm_get_enum_double, rx_macro_int_dem_inp_mux_put);
+static const struct snd_kcontrol_new rx_int1_dem_inp_mux =
+               SOC_DAPM_ENUM_EXT("rx_int1_dem_inp", rx_int1_dem_inp_enum,
+                 snd_soc_dapm_get_enum_double, rx_macro_int_dem_inp_mux_put);
+
+static int rx_macro_set_prim_interpolator_rate(struct snd_soc_dai *dai,
+                                              int rate_reg_val, u32 sample_rate)
+{
+
+       u8 int_1_mix1_inp;
+       u32 j, port;
+       u16 int_mux_cfg0, int_mux_cfg1;
+       u16 int_fs_reg;
+       u8 inp0_sel, inp1_sel, inp2_sel;
+       struct snd_soc_component *component = dai->component;
+       struct rx_macro *rx = snd_soc_component_get_drvdata(component);
+
+       for_each_set_bit(port, &rx->active_ch_mask[dai->id], RX_MACRO_PORTS_MAX) {
+               int_1_mix1_inp = port;
+               int_mux_cfg0 = CDC_RX_INP_MUX_RX_INT0_CFG0;
+               /*
+                * Loop through all interpolator MUX inputs and find out
+                * to which interpolator input, the rx port
+                * is connected
+                */
+               for (j = 0; j < INTERP_MAX; j++) {
+                       int_mux_cfg1 = int_mux_cfg0 + 4;
+
+                       inp0_sel = snd_soc_component_read_field(component, int_mux_cfg0,
+                                                               CDC_RX_INTX_1_MIX_INP0_SEL_MASK);
+                       inp1_sel = snd_soc_component_read_field(component, int_mux_cfg0,
+                                                               CDC_RX_INTX_1_MIX_INP1_SEL_MASK);
+                       inp2_sel = snd_soc_component_read_field(component, int_mux_cfg1,
+                                                               CDC_RX_INTX_1_MIX_INP2_SEL_MASK);
+
+                       if ((inp0_sel == int_1_mix1_inp + INTn_1_INP_SEL_RX0) ||
+                           (inp1_sel == int_1_mix1_inp + INTn_1_INP_SEL_RX0) ||
+                           (inp2_sel == int_1_mix1_inp + INTn_1_INP_SEL_RX0)) {
+                               int_fs_reg = CDC_RX_RXn_RX_PATH_CTL(j);
+                               /* sample_rate is in Hz */
+                               snd_soc_component_update_bits(component, int_fs_reg,
+                                                             CDC_RX_PATH_PCM_RATE_MASK,
+                                                             rate_reg_val);
+                       }
+                       int_mux_cfg0 += 8;
+               }
+       }
+
+       return 0;
+}
+
+static int rx_macro_set_mix_interpolator_rate(struct snd_soc_dai *dai,
+                                             int rate_reg_val, u32 sample_rate)
+{
+
+       u8 int_2_inp;
+       u32 j, port;
+       u16 int_mux_cfg1, int_fs_reg;
+       u8 int_mux_cfg1_val;
+       struct snd_soc_component *component = dai->component;
+       struct rx_macro *rx = snd_soc_component_get_drvdata(component);
+
+       for_each_set_bit(port, &rx->active_ch_mask[dai->id], RX_MACRO_PORTS_MAX) {
+               int_2_inp = port;
+
+               int_mux_cfg1 = CDC_RX_INP_MUX_RX_INT0_CFG1;
+               for (j = 0; j < INTERP_MAX; j++) {
+                       int_mux_cfg1_val = snd_soc_component_read_field(component, int_mux_cfg1,
+                                                                       CDC_RX_INTX_2_SEL_MASK);
+
+                       if (int_mux_cfg1_val == int_2_inp + INTn_2_INP_SEL_RX0) {
+                               int_fs_reg = CDC_RX_RXn_RX_PATH_MIX_CTL(j);
+                               snd_soc_component_update_bits(component, int_fs_reg,
+                                                             CDC_RX_RXn_MIX_PCM_RATE_MASK,
+                                                             rate_reg_val);
+                       }
+                       int_mux_cfg1 += 8;
+               }
+       }
+       return 0;
+}
+
+static int rx_macro_set_interpolator_rate(struct snd_soc_dai *dai,
+                                         u32 sample_rate)
+{
+       int rate_val = 0;
+       int i, ret;
+
+       for (i = 0; i < ARRAY_SIZE(sr_val_tbl); i++)
+               if (sample_rate == sr_val_tbl[i].sample_rate)
+                       rate_val = sr_val_tbl[i].rate_val;
+
+       ret = rx_macro_set_prim_interpolator_rate(dai, rate_val, sample_rate);
+       if (ret)
+               return ret;
+
+       ret = rx_macro_set_mix_interpolator_rate(dai, rate_val, sample_rate);
+       if (ret)
+               return ret;
+
+       return ret;
+}
+
+static int rx_macro_hw_params(struct snd_pcm_substream *substream,
+                             struct snd_pcm_hw_params *params,
+                             struct snd_soc_dai *dai)
+{
+       struct snd_soc_component *component = dai->component;
+       struct rx_macro *rx = snd_soc_component_get_drvdata(component);
+       int ret;
+
+       switch (substream->stream) {
+       case SNDRV_PCM_STREAM_PLAYBACK:
+               ret = rx_macro_set_interpolator_rate(dai, params_rate(params));
+               if (ret) {
+                       dev_err(component->dev, "%s: cannot set sample rate: %u\n",
+                               __func__, params_rate(params));
+                       return ret;
+               }
+               rx->bit_width[dai->id] = params_width(params);
+               break;
+       default:
+               break;
+       }
+       return 0;
+}
+
+static int rx_macro_get_channel_map(struct snd_soc_dai *dai,
+                                   unsigned int *tx_num, unsigned int *tx_slot,
+                                   unsigned int *rx_num, unsigned int *rx_slot)
+{
+       struct snd_soc_component *component = dai->component;
+       struct rx_macro *rx = snd_soc_component_get_drvdata(component);
+       u16 val, mask = 0, cnt = 0, temp;
+
+       switch (dai->id) {
+       case RX_MACRO_AIF1_PB:
+       case RX_MACRO_AIF2_PB:
+       case RX_MACRO_AIF3_PB:
+       case RX_MACRO_AIF4_PB:
+               for_each_set_bit(temp, &rx->active_ch_mask[dai->id],
+                        RX_MACRO_PORTS_MAX) {
+                       mask |= (1 << temp);
+                       if (++cnt == RX_MACRO_MAX_DMA_CH_PER_PORT)
+                               break;
+               }
+               /*
+                * CDC_DMA_RX_0 port drives RX0/RX1 -- ch_mask 0x1/0x2/0x3
+                * CDC_DMA_RX_1 port drives RX2/RX3 -- ch_mask 0x1/0x2/0x3
+                * CDC_DMA_RX_2 port drives RX4     -- ch_mask 0x1
+                * CDC_DMA_RX_3 port drives RX5     -- ch_mask 0x1
+                * AIFn can pair to any CDC_DMA_RX_n port.
+                * In general, below convention is used::
+                * CDC_DMA_RX_0(AIF1)/CDC_DMA_RX_1(AIF2)/
+                * CDC_DMA_RX_2(AIF3)/CDC_DMA_RX_3(AIF4)
+                */
+               if (mask & 0x0C)
+                       mask = mask >> 2;
+               if ((mask & 0x10) || (mask & 0x20))
+                       mask = 0x1;
+               *rx_slot = mask;
+               *rx_num = rx->active_ch_cnt[dai->id];
+               break;
+       case RX_MACRO_AIF_ECHO:
+               val = snd_soc_component_read(component, CDC_RX_INP_MUX_RX_MIX_CFG4);
+               if (val & RX_MACRO_EC_MIX_TX0_MASK) {
+                       mask |= 0x1;
+                       cnt++;
+               }
+               if (val & RX_MACRO_EC_MIX_TX1_MASK) {
+                       mask |= 0x2;
+                       cnt++;
+               }
+               val = snd_soc_component_read(component,
+                       CDC_RX_INP_MUX_RX_MIX_CFG5);
+               if (val & RX_MACRO_EC_MIX_TX2_MASK) {
+                       mask |= 0x4;
+                       cnt++;
+               }
+               *tx_slot = mask;
+               *tx_num = cnt;
+               break;
+       default:
+               dev_err(component->dev, "%s: Invalid AIF\n", __func__);
+               break;
+       }
+       return 0;
+}
+
+static int rx_macro_digital_mute(struct snd_soc_dai *dai, int mute, int stream)
+{
+       struct snd_soc_component *component = dai->component;
+       uint16_t j, reg, mix_reg, dsm_reg;
+       u16 int_mux_cfg0, int_mux_cfg1;
+       u8 int_mux_cfg0_val, int_mux_cfg1_val;
+
+       switch (dai->id) {
+       case RX_MACRO_AIF1_PB:
+       case RX_MACRO_AIF2_PB:
+       case RX_MACRO_AIF3_PB:
+       case RX_MACRO_AIF4_PB:
+       for (j = 0; j < INTERP_MAX; j++) {
+               reg = CDC_RX_RXn_RX_PATH_CTL(j);
+               mix_reg = CDC_RX_RXn_RX_PATH_MIX_CTL(j);
+               dsm_reg = CDC_RX_RXn_RX_PATH_DSM_CTL(j);
+
+               if (mute) {
+                       snd_soc_component_update_bits(component, reg,
+                                                     CDC_RX_PATH_PGA_MUTE_MASK,
+                                                     CDC_RX_PATH_PGA_MUTE_ENABLE);
+                       snd_soc_component_update_bits(component, mix_reg,
+                                                     CDC_RX_PATH_PGA_MUTE_MASK,
+                                                     CDC_RX_PATH_PGA_MUTE_ENABLE);
+               } else {
+                       snd_soc_component_update_bits(component, reg,
+                                                     CDC_RX_PATH_PGA_MUTE_MASK, 0x0);
+                       snd_soc_component_update_bits(component, mix_reg,
+                                                     CDC_RX_PATH_PGA_MUTE_MASK, 0x0);
+               }
+
+               if (j == INTERP_AUX)
+                       dsm_reg = CDC_RX_RX2_RX_PATH_DSM_CTL;
+
+               int_mux_cfg0 = CDC_RX_INP_MUX_RX_INT0_CFG0 + j * 8;
+               int_mux_cfg1 = int_mux_cfg0 + 4;
+               int_mux_cfg0_val = snd_soc_component_read(component, int_mux_cfg0);
+               int_mux_cfg1_val = snd_soc_component_read(component, int_mux_cfg1);
+
+               if (snd_soc_component_read(component, dsm_reg) & 0x01) {
+                       if (int_mux_cfg0_val || (int_mux_cfg1_val & 0xF0))
+                               snd_soc_component_update_bits(component, reg, 0x20, 0x20);
+                       if (int_mux_cfg1_val & 0x0F) {
+                               snd_soc_component_update_bits(component, reg, 0x20, 0x20);
+                               snd_soc_component_update_bits(component, mix_reg, 0x20, 0x20);
+                       }
+               }
+       }
+               break;
+       default:
+               break;
+       }
+       return 0;
+}
+
+static struct snd_soc_dai_ops rx_macro_dai_ops = {
+       .hw_params = rx_macro_hw_params,
+       .get_channel_map = rx_macro_get_channel_map,
+       .mute_stream = rx_macro_digital_mute,
+};
+
+static struct snd_soc_dai_driver rx_macro_dai[] = {
+       {
+               .name = "rx_macro_rx1",
+               .id = RX_MACRO_AIF1_PB,
+               .playback = {
+                       .stream_name = "RX_MACRO_AIF1 Playback",
+                       .rates = RX_MACRO_RATES | RX_MACRO_FRAC_RATES,
+                       .formats = RX_MACRO_FORMATS,
+                       .rate_max = 384000,
+                       .rate_min = 8000,
+                       .channels_min = 1,
+                       .channels_max = 2,
+               },
+               .ops = &rx_macro_dai_ops,
+       },
+       {
+               .name = "rx_macro_rx2",
+               .id = RX_MACRO_AIF2_PB,
+               .playback = {
+                       .stream_name = "RX_MACRO_AIF2 Playback",
+                       .rates = RX_MACRO_RATES | RX_MACRO_FRAC_RATES,
+                       .formats = RX_MACRO_FORMATS,
+                       .rate_max = 384000,
+                       .rate_min = 8000,
+                       .channels_min = 1,
+                       .channels_max = 2,
+               },
+               .ops = &rx_macro_dai_ops,
+       },
+       {
+               .name = "rx_macro_rx3",
+               .id = RX_MACRO_AIF3_PB,
+               .playback = {
+                       .stream_name = "RX_MACRO_AIF3 Playback",
+                       .rates = RX_MACRO_RATES | RX_MACRO_FRAC_RATES,
+                       .formats = RX_MACRO_FORMATS,
+                       .rate_max = 384000,
+                       .rate_min = 8000,
+                       .channels_min = 1,
+                       .channels_max = 2,
+               },
+               .ops = &rx_macro_dai_ops,
+       },
+       {
+               .name = "rx_macro_rx4",
+               .id = RX_MACRO_AIF4_PB,
+               .playback = {
+                       .stream_name = "RX_MACRO_AIF4 Playback",
+                       .rates = RX_MACRO_RATES | RX_MACRO_FRAC_RATES,
+                       .formats = RX_MACRO_FORMATS,
+                       .rate_max = 384000,
+                       .rate_min = 8000,
+                       .channels_min = 1,
+                       .channels_max = 2,
+               },
+               .ops = &rx_macro_dai_ops,
+       },
+       {
+               .name = "rx_macro_echo",
+               .id = RX_MACRO_AIF_ECHO,
+               .capture = {
+                       .stream_name = "RX_AIF_ECHO Capture",
+                       .rates = RX_MACRO_ECHO_RATES,
+                       .formats = RX_MACRO_ECHO_FORMATS,
+                       .rate_max = 48000,
+                       .rate_min = 8000,
+                       .channels_min = 1,
+                       .channels_max = 3,
+               },
+               .ops = &rx_macro_dai_ops,
+       },
+};
+
+static void rx_macro_mclk_enable(struct rx_macro *rx, bool mclk_enable)
+{
+       struct regmap *regmap = rx->regmap;
+
+       if (mclk_enable) {
+               if (rx->rx_mclk_users == 0) {
+                       regmap_update_bits(regmap, CDC_RX_CLK_RST_CTRL_MCLK_CONTROL,
+                                          CDC_RX_CLK_MCLK_EN_MASK |
+                                          CDC_RX_CLK_MCLK2_EN_MASK,
+                                          CDC_RX_CLK_MCLK_ENABLE |
+                                          CDC_RX_CLK_MCLK2_ENABLE);
+                       regmap_update_bits(regmap, CDC_RX_CLK_RST_CTRL_FS_CNT_CONTROL,
+                                          CDC_RX_FS_MCLK_CNT_CLR_MASK, 0x00);
+                       regmap_update_bits(regmap, CDC_RX_CLK_RST_CTRL_FS_CNT_CONTROL,
+                                          CDC_RX_FS_MCLK_CNT_EN_MASK,
+                                          CDC_RX_FS_MCLK_CNT_ENABLE);
+                       regcache_mark_dirty(regmap);
+                       regcache_sync(regmap);
+               }
+               rx->rx_mclk_users++;
+       } else {
+               if (rx->rx_mclk_users <= 0) {
+                       dev_err(rx->dev, "%s: clock already disabled\n", __func__);
+                       rx->rx_mclk_users = 0;
+                       return;
+               }
+               rx->rx_mclk_users--;
+               if (rx->rx_mclk_users == 0) {
+                       regmap_update_bits(regmap, CDC_RX_CLK_RST_CTRL_FS_CNT_CONTROL,
+                                          CDC_RX_FS_MCLK_CNT_EN_MASK, 0x0);
+                       regmap_update_bits(regmap, CDC_RX_CLK_RST_CTRL_FS_CNT_CONTROL,
+                                          CDC_RX_FS_MCLK_CNT_CLR_MASK,
+                                          CDC_RX_FS_MCLK_CNT_CLR);
+                       regmap_update_bits(regmap, CDC_RX_CLK_RST_CTRL_MCLK_CONTROL,
+                                          CDC_RX_CLK_MCLK_EN_MASK |
+                                          CDC_RX_CLK_MCLK2_EN_MASK, 0x0);
+               }
+       }
+}
+
+static int rx_macro_mclk_event(struct snd_soc_dapm_widget *w,
+                              struct snd_kcontrol *kcontrol, int event)
+{
+       struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+       struct rx_macro *rx = snd_soc_component_get_drvdata(component);
+       int ret = 0;
+
+       switch (event) {
+       case SND_SOC_DAPM_PRE_PMU:
+               rx_macro_mclk_enable(rx, true);
+               break;
+       case SND_SOC_DAPM_POST_PMD:
+               rx_macro_mclk_enable(rx, false);
+               break;
+       default:
+               dev_err(component->dev, "%s: invalid DAPM event %d\n", __func__, event);
+               ret = -EINVAL;
+       }
+       return ret;
+}
+
+static bool rx_macro_adie_lb(struct snd_soc_component *component,
+                            int interp_idx)
+{
+       u16 int_mux_cfg0, int_mux_cfg1;
+       u8 int_n_inp0, int_n_inp1, int_n_inp2;
+
+       int_mux_cfg0 = CDC_RX_INP_MUX_RX_INT0_CFG0 + interp_idx * 8;
+       int_mux_cfg1 = int_mux_cfg0 + 4;
+
+       int_n_inp0 = snd_soc_component_read_field(component, int_mux_cfg0,
+                                                 CDC_RX_INTX_1_MIX_INP0_SEL_MASK);
+       int_n_inp1 = snd_soc_component_read_field(component, int_mux_cfg0,
+                                                 CDC_RX_INTX_1_MIX_INP1_SEL_MASK);
+       int_n_inp2 = snd_soc_component_read_field(component, int_mux_cfg1,
+                                                 CDC_RX_INTX_1_MIX_INP2_SEL_MASK);
+
+       if (int_n_inp0 == INTn_1_INP_SEL_DEC0 ||
+               int_n_inp0 == INTn_1_INP_SEL_DEC1 ||
+               int_n_inp0 == INTn_1_INP_SEL_IIR0 ||
+               int_n_inp0 == INTn_1_INP_SEL_IIR1)
+               return true;
+
+       if (int_n_inp1 == INTn_1_INP_SEL_DEC0 ||
+               int_n_inp1 == INTn_1_INP_SEL_DEC1 ||
+               int_n_inp1 == INTn_1_INP_SEL_IIR0 ||
+               int_n_inp1 == INTn_1_INP_SEL_IIR1)
+               return true;
+
+       if (int_n_inp2 == INTn_1_INP_SEL_DEC0 ||
+               int_n_inp2 == INTn_1_INP_SEL_DEC1 ||
+               int_n_inp2 == INTn_1_INP_SEL_IIR0 ||
+               int_n_inp2 == INTn_1_INP_SEL_IIR1)
+               return true;
+
+       return false;
+}
+
+static int rx_macro_enable_interp_clk(struct snd_soc_component *component,
+                                     int event, int interp_idx);
+static int rx_macro_enable_main_path(struct snd_soc_dapm_widget *w,
+                                       struct snd_kcontrol *kcontrol,
+                                       int event)
+{
+       struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+       u16 gain_reg, reg;
+
+       reg = CDC_RX_RXn_RX_PATH_CTL(w->shift);
+       gain_reg = CDC_RX_RXn_RX_VOL_CTL(w->shift);
+
+       switch (event) {
+       case SND_SOC_DAPM_PRE_PMU:
+               rx_macro_enable_interp_clk(component, event, w->shift);
+               if (rx_macro_adie_lb(component, w->shift))
+                       snd_soc_component_update_bits(component, reg,
+                                                     CDC_RX_PATH_CLK_EN_MASK,
+                                                     CDC_RX_PATH_CLK_ENABLE);
+               break;
+       case SND_SOC_DAPM_POST_PMU:
+               snd_soc_component_write(component, gain_reg,
+                       snd_soc_component_read(component, gain_reg));
+               break;
+       case SND_SOC_DAPM_POST_PMD:
+               rx_macro_enable_interp_clk(component, event, w->shift);
+               break;
+       }
+
+       return 0;
+}
+
+static int rx_macro_config_compander(struct snd_soc_component *component,
+                               struct rx_macro *rx,
+                               int comp, int event)
+{
+       u8 pcm_rate, val;
+
+       /* AUX does not have compander */
+       if (comp == INTERP_AUX)
+               return 0;
+
+       pcm_rate = snd_soc_component_read(component, CDC_RX_RXn_RX_PATH_CTL(comp)) & 0x0F;
+       if (pcm_rate < 0x06)
+               val = 0x03;
+       else if (pcm_rate < 0x08)
+               val = 0x01;
+       else if (pcm_rate < 0x0B)
+               val = 0x02;
+       else
+               val = 0x00;
+
+       if (SND_SOC_DAPM_EVENT_ON(event))
+               snd_soc_component_update_bits(component, CDC_RX_RXn_RX_PATH_CFG3(comp),
+                                             CDC_RX_DC_COEFF_SEL_MASK, val);
+
+       if (SND_SOC_DAPM_EVENT_OFF(event))
+               snd_soc_component_update_bits(component, CDC_RX_RXn_RX_PATH_CFG3(comp),
+                                             CDC_RX_DC_COEFF_SEL_MASK, 0x3);
+       if (!rx->comp_enabled[comp])
+               return 0;
+
+       if (SND_SOC_DAPM_EVENT_ON(event)) {
+               /* Enable Compander Clock */
+               snd_soc_component_write_field(component, CDC_RX_COMPANDERn_CTL0(comp),
+                                             CDC_RX_COMPANDERn_CLK_EN_MASK, 0x1);
+               snd_soc_component_write_field(component, CDC_RX_COMPANDERn_CTL0(comp),
+                                             CDC_RX_COMPANDERn_SOFT_RST_MASK, 0x1);
+               snd_soc_component_write_field(component, CDC_RX_COMPANDERn_CTL0(comp),
+                                             CDC_RX_COMPANDERn_SOFT_RST_MASK, 0x0);
+               snd_soc_component_write_field(component, CDC_RX_RXn_RX_PATH_CFG0(comp),
+                                             CDC_RX_RXn_COMP_EN_MASK, 0x1);
+       }
+
+       if (SND_SOC_DAPM_EVENT_OFF(event)) {
+               snd_soc_component_write_field(component, CDC_RX_COMPANDERn_CTL0(comp),
+                                             CDC_RX_COMPANDERn_HALT_MASK, 0x1);
+               snd_soc_component_write_field(component, CDC_RX_RXn_RX_PATH_CFG0(comp),
+                                             CDC_RX_RXn_COMP_EN_MASK, 0x0);
+               snd_soc_component_write_field(component, CDC_RX_COMPANDERn_CTL0(comp),
+                                             CDC_RX_COMPANDERn_CLK_EN_MASK, 0x0);
+               snd_soc_component_write_field(component, CDC_RX_COMPANDERn_CTL0(comp),
+                                             CDC_RX_COMPANDERn_HALT_MASK, 0x0);
+       }
+
+       return 0;
+}
+
+static int rx_macro_load_compander_coeff(struct snd_soc_component *component,
+                                        struct rx_macro *rx,
+                                        int comp, int event)
+{
+       u16 comp_coeff_lsb_reg, comp_coeff_msb_reg;
+       int i;
+       int hph_pwr_mode = HPH_LOHIFI;
+
+       if (!rx->comp_enabled[comp])
+               return 0;
+
+       if (comp == INTERP_HPHL) {
+               comp_coeff_lsb_reg = CDC_RX_TOP_HPHL_COMP_WR_LSB;
+               comp_coeff_msb_reg = CDC_RX_TOP_HPHL_COMP_WR_MSB;
+       } else if (comp == INTERP_HPHR) {
+               comp_coeff_lsb_reg = CDC_RX_TOP_HPHR_COMP_WR_LSB;
+               comp_coeff_msb_reg = CDC_RX_TOP_HPHR_COMP_WR_MSB;
+       } else {
+               /* compander coefficients are loaded only for hph path */
+               return 0;
+       }
+
+       hph_pwr_mode = rx->hph_pwr_mode;
+
+       if (SND_SOC_DAPM_EVENT_ON(event)) {
+               /* Load Compander Coeff */
+               for (i = 0; i < COMP_MAX_COEFF; i++) {
+                       snd_soc_component_write(component, comp_coeff_lsb_reg,
+                                       comp_coeff_table[hph_pwr_mode][i].lsb);
+                       snd_soc_component_write(component, comp_coeff_msb_reg,
+                                       comp_coeff_table[hph_pwr_mode][i].msb);
+               }
+       }
+
+       return 0;
+}
+
+static void rx_macro_enable_softclip_clk(struct snd_soc_component *component,
+                                        struct rx_macro *rx, bool enable)
+{
+       if (enable) {
+               if (rx->softclip_clk_users == 0)
+                       snd_soc_component_write_field(component, CDC_RX_SOFTCLIP_CRC,
+                                                     CDC_RX_SOFTCLIP_CLK_EN_MASK, 1);
+               rx->softclip_clk_users++;
+       } else {
+               rx->softclip_clk_users--;
+               if (rx->softclip_clk_users == 0)
+                       snd_soc_component_write_field(component, CDC_RX_SOFTCLIP_CRC,
+                                                     CDC_RX_SOFTCLIP_CLK_EN_MASK, 0);
+       }
+}
+
+static int rx_macro_config_softclip(struct snd_soc_component *component,
+                                   struct rx_macro *rx, int event)
+{
+
+       if (!rx->is_softclip_on)
+               return 0;
+
+       if (SND_SOC_DAPM_EVENT_ON(event)) {
+               /* Enable Softclip clock */
+               rx_macro_enable_softclip_clk(component, rx, true);
+               /* Enable Softclip control */
+               snd_soc_component_write_field(component, CDC_RX_SOFTCLIP_SOFTCLIP_CTRL,
+                                            CDC_RX_SOFTCLIP_EN_MASK, 0x01);
+       }
+
+       if (SND_SOC_DAPM_EVENT_OFF(event)) {
+               snd_soc_component_write_field(component, CDC_RX_SOFTCLIP_SOFTCLIP_CTRL,
+                                            CDC_RX_SOFTCLIP_EN_MASK, 0x0);
+               rx_macro_enable_softclip_clk(component, rx, false);
+       }
+
+       return 0;
+}
+
+static int rx_macro_config_aux_hpf(struct snd_soc_component *component,
+                                  struct rx_macro *rx, int event)
+{
+       if (SND_SOC_DAPM_EVENT_ON(event)) {
+               /* Update Aux HPF control */
+               if (!rx->is_aux_hpf_on)
+                       snd_soc_component_update_bits(component,
+                               CDC_RX_RX2_RX_PATH_CFG1, 0x04, 0x00);
+       }
+
+       if (SND_SOC_DAPM_EVENT_OFF(event)) {
+               /* Reset to default (HPF=ON) */
+               snd_soc_component_update_bits(component,
+                       CDC_RX_RX2_RX_PATH_CFG1, 0x04, 0x04);
+       }
+
+       return 0;
+}
+
+static inline void rx_macro_enable_clsh_block(struct rx_macro *rx, bool enable)
+{
+       if ((enable && ++rx->clsh_users == 1) || (!enable && --rx->clsh_users == 0))
+               snd_soc_component_update_bits(rx->component, CDC_RX_CLSH_CRC,
+                                            CDC_RX_CLSH_CLK_EN_MASK, enable);
+       if (rx->clsh_users < 0)
+               rx->clsh_users = 0;
+}
+
+static int rx_macro_config_classh(struct snd_soc_component *component,
+                               struct rx_macro *rx,
+                               int interp_n, int event)
+{
+       if (SND_SOC_DAPM_EVENT_OFF(event)) {
+               rx_macro_enable_clsh_block(rx, false);
+               return 0;
+       }
+
+       if (!SND_SOC_DAPM_EVENT_ON(event))
+               return 0;
+
+       rx_macro_enable_clsh_block(rx, true);
+       if (interp_n == INTERP_HPHL ||
+               interp_n == INTERP_HPHR) {
+               /*
+                * These K1 values depend on the Headphone Impedance
+                * For now it is assumed to be 16 ohm
+                */
+               snd_soc_component_write(component, CDC_RX_CLSH_K1_LSB, 0xc0);
+               snd_soc_component_write_field(component, CDC_RX_CLSH_K1_MSB,
+                                             CDC_RX_CLSH_K1_MSB_COEFF_MASK, 0);
+       }
+       switch (interp_n) {
+       case INTERP_HPHL:
+               if (rx->is_ear_mode_on)
+                       snd_soc_component_update_bits(component,
+                               CDC_RX_CLSH_HPH_V_PA,
+                               CDC_RX_CLSH_HPH_V_PA_MIN_MASK, 0x39);
+               else
+                       snd_soc_component_update_bits(component,
+                               CDC_RX_CLSH_HPH_V_PA,
+                               CDC_RX_CLSH_HPH_V_PA_MIN_MASK, 0x1c);
+               snd_soc_component_update_bits(component,
+                               CDC_RX_CLSH_DECAY_CTRL,
+                               CDC_RX_CLSH_DECAY_RATE_MASK, 0x0);
+               snd_soc_component_write_field(component,
+                               CDC_RX_RX0_RX_PATH_CFG0,
+                               CDC_RX_RXn_CLSH_EN_MASK, 0x1);
+               break;
+       case INTERP_HPHR:
+               if (rx->is_ear_mode_on)
+                       snd_soc_component_update_bits(component,
+                               CDC_RX_CLSH_HPH_V_PA,
+                               CDC_RX_CLSH_HPH_V_PA_MIN_MASK, 0x39);
+               else
+                       snd_soc_component_update_bits(component,
+                               CDC_RX_CLSH_HPH_V_PA,
+                               CDC_RX_CLSH_HPH_V_PA_MIN_MASK, 0x1c);
+               snd_soc_component_update_bits(component,
+                               CDC_RX_CLSH_DECAY_CTRL,
+                               CDC_RX_CLSH_DECAY_RATE_MASK, 0x0);
+               snd_soc_component_update_bits(component,
+                               CDC_RX_RX1_RX_PATH_CFG0,
+                               CDC_RX_RXn_CLSH_EN_MASK, 0x1);
+               break;
+       case INTERP_AUX:
+               snd_soc_component_update_bits(component,
+                               CDC_RX_RX2_RX_PATH_CFG0,
+                               CDC_RX_RX2_DLY_Z_EN_MASK, 1);
+               snd_soc_component_write_field(component,
+                               CDC_RX_RX2_RX_PATH_CFG0,
+                               CDC_RX_RX2_CLSH_EN_MASK, 1);
+               break;
+       }
+
+       return 0;
+}
+
+static void rx_macro_hd2_control(struct snd_soc_component *component,
+                                u16 interp_idx, int event)
+{
+       u16 hd2_scale_reg, hd2_enable_reg;
+
+       switch (interp_idx) {
+       case INTERP_HPHL:
+               hd2_scale_reg = CDC_RX_RX0_RX_PATH_SEC3;
+               hd2_enable_reg = CDC_RX_RX0_RX_PATH_CFG0;
+               break;
+       case INTERP_HPHR:
+               hd2_scale_reg = CDC_RX_RX1_RX_PATH_SEC3;
+               hd2_enable_reg = CDC_RX_RX1_RX_PATH_CFG0;
+               break;
+       }
+
+       if (hd2_enable_reg && SND_SOC_DAPM_EVENT_ON(event)) {
+               snd_soc_component_update_bits(component, hd2_scale_reg,
+                               CDC_RX_RXn_HD2_ALPHA_MASK, 0x14);
+               snd_soc_component_write_field(component, hd2_enable_reg,
+                                             CDC_RX_RXn_HD2_EN_MASK, 1);
+       }
+
+       if (hd2_enable_reg && SND_SOC_DAPM_EVENT_OFF(event)) {
+               snd_soc_component_write_field(component, hd2_enable_reg,
+                                             CDC_RX_RXn_HD2_EN_MASK, 0);
+               snd_soc_component_update_bits(component, hd2_scale_reg,
+                               CDC_RX_RXn_HD2_ALPHA_MASK, 0x0);
+       }
+}
+
+static int rx_macro_get_compander(struct snd_kcontrol *kcontrol,
+                              struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_component *component =
+                               snd_soc_kcontrol_component(kcontrol);
+       int comp = ((struct soc_mixer_control *) kcontrol->private_value)->shift;
+       struct rx_macro *rx = snd_soc_component_get_drvdata(component);
+
+       ucontrol->value.integer.value[0] = rx->comp_enabled[comp];
+       return 0;
+}
+
+static int rx_macro_set_compander(struct snd_kcontrol *kcontrol,
+                              struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+       int comp = ((struct soc_mixer_control *)  kcontrol->private_value)->shift;
+       int value = ucontrol->value.integer.value[0];
+       struct rx_macro *rx = snd_soc_component_get_drvdata(component);
+
+       rx->comp_enabled[comp] = value;
+
+       return 0;
+}
+
+static int rx_macro_mux_get(struct snd_kcontrol *kcontrol,
+                         struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_dapm_widget *widget = snd_soc_dapm_kcontrol_widget(kcontrol);
+       struct snd_soc_component *component = snd_soc_dapm_to_component(widget->dapm);
+       struct rx_macro *rx = snd_soc_component_get_drvdata(component);
+
+       ucontrol->value.integer.value[0] =
+                       rx->rx_port_value[widget->shift];
+       return 0;
+}
+
+static int rx_macro_mux_put(struct snd_kcontrol *kcontrol,
+                           struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_dapm_widget *widget = snd_soc_dapm_kcontrol_widget(kcontrol);
+       struct snd_soc_component *component = snd_soc_dapm_to_component(widget->dapm);
+       struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
+       struct snd_soc_dapm_update *update = NULL;
+       u32 rx_port_value = ucontrol->value.integer.value[0];
+       u32 aif_rst;
+       struct rx_macro *rx = snd_soc_component_get_drvdata(component);
+
+       aif_rst = rx->rx_port_value[widget->shift];
+       if (!rx_port_value) {
+               if (aif_rst == 0) {
+                       dev_err(component->dev, "%s:AIF reset already\n", __func__);
+                       return 0;
+               }
+               if (aif_rst > RX_MACRO_AIF4_PB) {
+                       dev_err(component->dev, "%s: Invalid AIF reset\n", __func__);
+                       return 0;
+               }
+       }
+       rx->rx_port_value[widget->shift] = rx_port_value;
+
+       switch (rx_port_value) {
+       case 0:
+               if (rx->active_ch_cnt[aif_rst]) {
+                       clear_bit(widget->shift,
+                               &rx->active_ch_mask[aif_rst]);
+                       rx->active_ch_cnt[aif_rst]--;
+               }
+               break;
+       case 1:
+       case 2:
+       case 3:
+       case 4:
+               set_bit(widget->shift,
+                       &rx->active_ch_mask[rx_port_value]);
+               rx->active_ch_cnt[rx_port_value]++;
+               break;
+       default:
+               dev_err(component->dev,
+                       "%s:Invalid AIF_ID for RX_MACRO MUX %d\n",
+                       __func__, rx_port_value);
+               goto err;
+       }
+
+       snd_soc_dapm_mux_update_power(widget->dapm, kcontrol,
+                                       rx_port_value, e, update);
+       return 0;
+err:
+       return -EINVAL;
+}
+
+static const struct snd_kcontrol_new rx_macro_rx0_mux =
+               SOC_DAPM_ENUM_EXT("rx_macro_rx0", rx_macro_rx0_enum,
+                 rx_macro_mux_get, rx_macro_mux_put);
+static const struct snd_kcontrol_new rx_macro_rx1_mux =
+               SOC_DAPM_ENUM_EXT("rx_macro_rx1", rx_macro_rx1_enum,
+                 rx_macro_mux_get, rx_macro_mux_put);
+static const struct snd_kcontrol_new rx_macro_rx2_mux =
+               SOC_DAPM_ENUM_EXT("rx_macro_rx2", rx_macro_rx2_enum,
+                 rx_macro_mux_get, rx_macro_mux_put);
+static const struct snd_kcontrol_new rx_macro_rx3_mux =
+               SOC_DAPM_ENUM_EXT("rx_macro_rx3", rx_macro_rx3_enum,
+                 rx_macro_mux_get, rx_macro_mux_put);
+static const struct snd_kcontrol_new rx_macro_rx4_mux =
+               SOC_DAPM_ENUM_EXT("rx_macro_rx4", rx_macro_rx4_enum,
+                 rx_macro_mux_get, rx_macro_mux_put);
+static const struct snd_kcontrol_new rx_macro_rx5_mux =
+               SOC_DAPM_ENUM_EXT("rx_macro_rx5", rx_macro_rx5_enum,
+                 rx_macro_mux_get, rx_macro_mux_put);
+
+static int rx_macro_get_ear_mode(struct snd_kcontrol *kcontrol,
+                              struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+       struct rx_macro *rx = snd_soc_component_get_drvdata(component);
+
+       ucontrol->value.integer.value[0] = rx->is_ear_mode_on;
+       return 0;
+}
+
+static int rx_macro_put_ear_mode(struct snd_kcontrol *kcontrol,
+                              struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+       struct rx_macro *rx = snd_soc_component_get_drvdata(component);
+
+       rx->is_ear_mode_on = (!ucontrol->value.integer.value[0] ? false : true);
+       return 0;
+}
+
+static int rx_macro_get_hph_hd2_mode(struct snd_kcontrol *kcontrol,
+                              struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+       struct rx_macro *rx = snd_soc_component_get_drvdata(component);
+
+       ucontrol->value.integer.value[0] = rx->hph_hd2_mode;
+       return 0;
+}
+
+static int rx_macro_put_hph_hd2_mode(struct snd_kcontrol *kcontrol,
+                              struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+       struct rx_macro *rx = snd_soc_component_get_drvdata(component);
+
+       rx->hph_hd2_mode = ucontrol->value.integer.value[0];
+       return 0;
+}
+
+static int rx_macro_get_hph_pwr_mode(struct snd_kcontrol *kcontrol,
+                              struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+       struct rx_macro *rx = snd_soc_component_get_drvdata(component);
+
+       ucontrol->value.integer.value[0] = rx->hph_pwr_mode;
+       return 0;
+}
+
+static int rx_macro_put_hph_pwr_mode(struct snd_kcontrol *kcontrol,
+                              struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+       struct rx_macro *rx = snd_soc_component_get_drvdata(component);
+
+       rx->hph_pwr_mode = ucontrol->value.integer.value[0];
+       return 0;
+}
+
+static int rx_macro_soft_clip_enable_get(struct snd_kcontrol *kcontrol,
+                                         struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+       struct rx_macro *rx = snd_soc_component_get_drvdata(component);
+
+       ucontrol->value.integer.value[0] = rx->is_softclip_on;
+
+       return 0;
+}
+
+static int rx_macro_soft_clip_enable_put(struct snd_kcontrol *kcontrol,
+                                         struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+       struct rx_macro *rx = snd_soc_component_get_drvdata(component);
+
+       rx->is_softclip_on = ucontrol->value.integer.value[0];
+
+       return 0;
+}
+
+static int rx_macro_aux_hpf_mode_get(struct snd_kcontrol *kcontrol,
+                                         struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+       struct rx_macro *rx = snd_soc_component_get_drvdata(component);
+
+       ucontrol->value.integer.value[0] = rx->is_aux_hpf_on;
+
+       return 0;
+}
+
+static int rx_macro_aux_hpf_mode_put(struct snd_kcontrol *kcontrol,
+                                         struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+       struct rx_macro *rx = snd_soc_component_get_drvdata(component);
+
+       rx->is_aux_hpf_on = ucontrol->value.integer.value[0];
+
+       return 0;
+}
+
+static int rx_macro_hphdelay_lutbypass(struct snd_soc_component *component,
+                                       struct rx_macro *rx,
+                                       u16 interp_idx, int event)
+{
+       u16 hph_lut_bypass_reg;
+       u16 hph_comp_ctrl7;
+
+       switch (interp_idx) {
+       case INTERP_HPHL:
+               hph_lut_bypass_reg = CDC_RX_TOP_HPHL_COMP_LUT;
+               hph_comp_ctrl7 = CDC_RX_COMPANDER0_CTL7;
+               break;
+       case INTERP_HPHR:
+               hph_lut_bypass_reg = CDC_RX_TOP_HPHR_COMP_LUT;
+               hph_comp_ctrl7 = CDC_RX_COMPANDER1_CTL7;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       if (hph_lut_bypass_reg && SND_SOC_DAPM_EVENT_ON(event)) {
+               if (interp_idx == INTERP_HPHL) {
+                       if (rx->is_ear_mode_on)
+                               snd_soc_component_write_field(component,
+                                       CDC_RX_RX0_RX_PATH_CFG1,
+                                       CDC_RX_RX0_HPH_L_EAR_SEL_MASK, 0x1);
+                       else
+                               snd_soc_component_write_field(component,
+                                       hph_lut_bypass_reg,
+                                       CDC_RX_TOP_HPH_LUT_BYPASS_MASK, 1);
+               } else {
+                       snd_soc_component_write_field(component, hph_lut_bypass_reg,
+                                       CDC_RX_TOP_HPH_LUT_BYPASS_MASK, 1);
+               }
+               if (rx->hph_pwr_mode)
+                       snd_soc_component_write_field(component, hph_comp_ctrl7,
+                                       CDC_RX_COMPANDER1_HPH_LOW_PWR_MODE_MASK, 0x0);
+       }
+
+       if (hph_lut_bypass_reg && SND_SOC_DAPM_EVENT_OFF(event)) {
+               snd_soc_component_write_field(component,
+                                       CDC_RX_RX0_RX_PATH_CFG1,
+                                       CDC_RX_RX0_HPH_L_EAR_SEL_MASK, 0x0);
+               snd_soc_component_update_bits(component, hph_lut_bypass_reg,
+                                       CDC_RX_TOP_HPH_LUT_BYPASS_MASK, 0);
+               snd_soc_component_write_field(component, hph_comp_ctrl7,
+                                       CDC_RX_COMPANDER1_HPH_LOW_PWR_MODE_MASK, 0x1);
+       }
+
+       return 0;
+}
+
+static int rx_macro_enable_interp_clk(struct snd_soc_component *component,
+                                     int event, int interp_idx)
+{
+       u16 main_reg, dsm_reg, rx_cfg2_reg;
+       struct rx_macro *rx = snd_soc_component_get_drvdata(component);
+
+       main_reg = CDC_RX_RXn_RX_PATH_CTL(interp_idx);
+       dsm_reg = CDC_RX_RXn_RX_PATH_DSM_CTL(interp_idx);
+       if (interp_idx == INTERP_AUX)
+               dsm_reg = CDC_RX_RX2_RX_PATH_DSM_CTL;
+       rx_cfg2_reg = CDC_RX_RXn_RX_PATH_CFG2(interp_idx);
+
+       if (SND_SOC_DAPM_EVENT_ON(event)) {
+               if (rx->main_clk_users[interp_idx] == 0) {
+                       /* Main path PGA mute enable */
+                       snd_soc_component_write_field(component, main_reg,
+                                                     CDC_RX_PATH_PGA_MUTE_MASK, 0x1);
+                       snd_soc_component_write_field(component, dsm_reg,
+                                                     CDC_RX_RXn_DSM_CLK_EN_MASK, 0x1);
+                       snd_soc_component_update_bits(component, rx_cfg2_reg,
+                                       CDC_RX_RXn_HPF_CUT_FREQ_MASK, 0x03);
+                       rx_macro_load_compander_coeff(component, rx, interp_idx, event);
+                       if (rx->hph_hd2_mode)
+                               rx_macro_hd2_control(component, interp_idx, event);
+                       rx_macro_hphdelay_lutbypass(component, rx, interp_idx, event);
+                       rx_macro_config_compander(component, rx, interp_idx, event);
+                       if (interp_idx == INTERP_AUX) {
+                               rx_macro_config_softclip(component, rx, event);
+                               rx_macro_config_aux_hpf(component, rx, event);
+                       }
+                       rx_macro_config_classh(component, rx, interp_idx, event);
+               }
+               rx->main_clk_users[interp_idx]++;
+       }
+
+       if (SND_SOC_DAPM_EVENT_OFF(event)) {
+               rx->main_clk_users[interp_idx]--;
+               if (rx->main_clk_users[interp_idx] <= 0) {
+                       rx->main_clk_users[interp_idx] = 0;
+                       /* Main path PGA mute enable */
+                       snd_soc_component_write_field(component, main_reg,
+                                                     CDC_RX_PATH_PGA_MUTE_MASK, 0x1);
+                       /* Clk Disable */
+                       snd_soc_component_write_field(component, dsm_reg,
+                                                     CDC_RX_RXn_DSM_CLK_EN_MASK, 0);
+                       snd_soc_component_write_field(component, main_reg,
+                                                     CDC_RX_PATH_CLK_EN_MASK, 0);
+                       /* Reset enable and disable */
+                       snd_soc_component_write_field(component, main_reg,
+                                                     CDC_RX_PATH_RESET_EN_MASK, 1);
+                       snd_soc_component_write_field(component, main_reg,
+                                                     CDC_RX_PATH_RESET_EN_MASK, 0);
+                       /* Reset rate to 48K*/
+                       snd_soc_component_update_bits(component, main_reg,
+                                                     CDC_RX_PATH_PCM_RATE_MASK,
+                                                     0x04);
+                       snd_soc_component_update_bits(component, rx_cfg2_reg,
+                                                     CDC_RX_RXn_HPF_CUT_FREQ_MASK, 0x00);
+                       rx_macro_config_classh(component, rx, interp_idx, event);
+                       rx_macro_config_compander(component, rx, interp_idx, event);
+                       if (interp_idx ==  INTERP_AUX) {
+                               rx_macro_config_softclip(component, rx, event);
+                               rx_macro_config_aux_hpf(component, rx, event);
+                       }
+                       rx_macro_hphdelay_lutbypass(component, rx, interp_idx, event);
+                       if (rx->hph_hd2_mode)
+                               rx_macro_hd2_control(component, interp_idx, event);
+               }
+       }
+
+       return rx->main_clk_users[interp_idx];
+}
+
+static int rx_macro_enable_mix_path(struct snd_soc_dapm_widget *w,
+                                   struct snd_kcontrol *kcontrol, int event)
+{
+       struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+       u16 gain_reg, mix_reg;
+
+       gain_reg = CDC_RX_RXn_RX_VOL_MIX_CTL(w->shift);
+       mix_reg = CDC_RX_RXn_RX_PATH_MIX_CTL(w->shift);
+
+       switch (event) {
+       case SND_SOC_DAPM_PRE_PMU:
+               rx_macro_enable_interp_clk(component, event, w->shift);
+               break;
+       case SND_SOC_DAPM_POST_PMU:
+               snd_soc_component_write(component, gain_reg,
+                                       snd_soc_component_read(component, gain_reg));
+               break;
+       case SND_SOC_DAPM_POST_PMD:
+               /* Clk Disable */
+               snd_soc_component_update_bits(component, mix_reg,
+                                             CDC_RX_RXn_MIX_CLK_EN_MASK, 0x00);
+               rx_macro_enable_interp_clk(component, event, w->shift);
+               /* Reset enable and disable */
+               snd_soc_component_update_bits(component, mix_reg,
+                                             CDC_RX_RXn_MIX_RESET_MASK,
+                                             CDC_RX_RXn_MIX_RESET);
+               snd_soc_component_update_bits(component, mix_reg,
+                                             CDC_RX_RXn_MIX_RESET_MASK, 0x00);
+               break;
+       }
+
+       return 0;
+}
+
+static int rx_macro_enable_rx_path_clk(struct snd_soc_dapm_widget *w,
+                                      struct snd_kcontrol *kcontrol, int event)
+{
+       struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+
+       switch (event) {
+       case SND_SOC_DAPM_PRE_PMU:
+               rx_macro_enable_interp_clk(component, event, w->shift);
+               snd_soc_component_write_field(component, CDC_RX_RXn_RX_PATH_CFG1(w->shift),
+                                             CDC_RX_RXn_SIDETONE_EN_MASK, 1);
+               snd_soc_component_write_field(component, CDC_RX_RXn_RX_PATH_CTL(w->shift),
+                                             CDC_RX_PATH_CLK_EN_MASK, 1);
+               break;
+       case SND_SOC_DAPM_POST_PMD:
+               snd_soc_component_write_field(component, CDC_RX_RXn_RX_PATH_CFG1(w->shift),
+                                             CDC_RX_RXn_SIDETONE_EN_MASK, 0);
+               rx_macro_enable_interp_clk(component, event, w->shift);
+               break;
+       default:
+               break;
+       };
+       return 0;
+}
+
+static int rx_macro_set_iir_gain(struct snd_soc_dapm_widget *w,
+                                struct snd_kcontrol *kcontrol, int event)
+{
+       struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+
+       switch (event) {
+       case SND_SOC_DAPM_POST_PMU: /* fall through */
+       case SND_SOC_DAPM_PRE_PMD:
+               if (strnstr(w->name, "IIR0", sizeof("IIR0"))) {
+                       snd_soc_component_write(component,
+                               CDC_RX_SIDETONE_IIR0_IIR_GAIN_B1_CTL,
+                       snd_soc_component_read(component,
+                               CDC_RX_SIDETONE_IIR0_IIR_GAIN_B1_CTL));
+                       snd_soc_component_write(component,
+                               CDC_RX_SIDETONE_IIR0_IIR_GAIN_B2_CTL,
+                       snd_soc_component_read(component,
+                               CDC_RX_SIDETONE_IIR0_IIR_GAIN_B2_CTL));
+                       snd_soc_component_write(component,
+                               CDC_RX_SIDETONE_IIR0_IIR_GAIN_B3_CTL,
+                       snd_soc_component_read(component,
+                               CDC_RX_SIDETONE_IIR0_IIR_GAIN_B3_CTL));
+                       snd_soc_component_write(component,
+                               CDC_RX_SIDETONE_IIR0_IIR_GAIN_B4_CTL,
+                       snd_soc_component_read(component,
+                               CDC_RX_SIDETONE_IIR0_IIR_GAIN_B4_CTL));
+               } else {
+                       snd_soc_component_write(component,
+                               CDC_RX_SIDETONE_IIR1_IIR_GAIN_B1_CTL,
+                       snd_soc_component_read(component,
+                               CDC_RX_SIDETONE_IIR1_IIR_GAIN_B1_CTL));
+                       snd_soc_component_write(component,
+                               CDC_RX_SIDETONE_IIR1_IIR_GAIN_B2_CTL,
+                       snd_soc_component_read(component,
+                               CDC_RX_SIDETONE_IIR1_IIR_GAIN_B2_CTL));
+                       snd_soc_component_write(component,
+                               CDC_RX_SIDETONE_IIR1_IIR_GAIN_B3_CTL,
+                       snd_soc_component_read(component,
+                               CDC_RX_SIDETONE_IIR1_IIR_GAIN_B3_CTL));
+                       snd_soc_component_write(component,
+                               CDC_RX_SIDETONE_IIR1_IIR_GAIN_B4_CTL,
+                       snd_soc_component_read(component,
+                               CDC_RX_SIDETONE_IIR1_IIR_GAIN_B4_CTL));
+               }
+               break;
+       }
+       return 0;
+}
+
+static uint32_t get_iir_band_coeff(struct snd_soc_component *component,
+                                  int iir_idx, int band_idx, int coeff_idx)
+{
+       u32 value;
+       int reg, b2_reg;
+
+       /* Address does not automatically update if reading */
+       reg = CDC_RX_SIDETONE_IIR0_IIR_COEF_B1_CTL + 16 * iir_idx;
+       b2_reg = CDC_RX_SIDETONE_IIR0_IIR_COEF_B2_CTL + 16 * iir_idx;
+
+       snd_soc_component_write(component, reg,
+                               ((band_idx * BAND_MAX + coeff_idx) *
+                                sizeof(uint32_t)) & 0x7F);
+
+       value = snd_soc_component_read(component, b2_reg);
+       snd_soc_component_write(component, reg,
+                               ((band_idx * BAND_MAX + coeff_idx)
+                                * sizeof(uint32_t) + 1) & 0x7F);
+
+       value |= (snd_soc_component_read(component, b2_reg) << 8);
+       snd_soc_component_write(component, reg,
+                               ((band_idx * BAND_MAX + coeff_idx)
+                                * sizeof(uint32_t) + 2) & 0x7F);
+
+       value |= (snd_soc_component_read(component, b2_reg) << 16);
+       snd_soc_component_write(component, reg,
+               ((band_idx * BAND_MAX + coeff_idx)
+               * sizeof(uint32_t) + 3) & 0x7F);
+
+       /* Mask bits top 2 bits since they are reserved */
+       value |= (snd_soc_component_read(component, b2_reg) << 24);
+       return value;
+}
+
+static void set_iir_band_coeff(struct snd_soc_component *component,
+                              int iir_idx, int band_idx, uint32_t value)
+{
+       int reg = CDC_RX_SIDETONE_IIR0_IIR_COEF_B2_CTL + 16 * iir_idx;
+
+       snd_soc_component_write(component, reg, (value & 0xFF));
+       snd_soc_component_write(component, reg, (value >> 8) & 0xFF);
+       snd_soc_component_write(component, reg, (value >> 16) & 0xFF);
+       /* Mask top 2 bits, 7-8 are reserved */
+       snd_soc_component_write(component, reg, (value >> 24) & 0x3F);
+}
+
+static int rx_macro_put_iir_band_audio_mixer(
+                                       struct snd_kcontrol *kcontrol,
+                                       struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_component *component =
+                       snd_soc_kcontrol_component(kcontrol);
+       struct wcd_iir_filter_ctl *ctl =
+                       (struct wcd_iir_filter_ctl *)kcontrol->private_value;
+       struct soc_bytes_ext *params = &ctl->bytes_ext;
+       int iir_idx = ctl->iir_idx;
+       int band_idx = ctl->band_idx;
+       u32 coeff[BAND_MAX];
+       int reg = CDC_RX_SIDETONE_IIR0_IIR_COEF_B1_CTL + 16 * iir_idx;
+
+       memcpy(&coeff[0], ucontrol->value.bytes.data, params->max);
+
+       /* Mask top bit it is reserved */
+       /* Updates addr automatically for each B2 write */
+       snd_soc_component_write(component, reg, (band_idx * BAND_MAX *
+                                                sizeof(uint32_t)) & 0x7F);
+
+       set_iir_band_coeff(component, iir_idx, band_idx, coeff[0]);
+       set_iir_band_coeff(component, iir_idx, band_idx, coeff[1]);
+       set_iir_band_coeff(component, iir_idx, band_idx, coeff[2]);
+       set_iir_band_coeff(component, iir_idx, band_idx, coeff[3]);
+       set_iir_band_coeff(component, iir_idx, band_idx, coeff[4]);
+
+       return 0;
+}
+
+static int rx_macro_get_iir_band_audio_mixer(struct snd_kcontrol *kcontrol,
+                                   struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_component *component =
+                       snd_soc_kcontrol_component(kcontrol);
+       struct wcd_iir_filter_ctl *ctl =
+                       (struct wcd_iir_filter_ctl *)kcontrol->private_value;
+       struct soc_bytes_ext *params = &ctl->bytes_ext;
+       int iir_idx = ctl->iir_idx;
+       int band_idx = ctl->band_idx;
+       u32 coeff[BAND_MAX];
+
+       coeff[0] = get_iir_band_coeff(component, iir_idx, band_idx, 0);
+       coeff[1] = get_iir_band_coeff(component, iir_idx, band_idx, 1);
+       coeff[2] = get_iir_band_coeff(component, iir_idx, band_idx, 2);
+       coeff[3] = get_iir_band_coeff(component, iir_idx, band_idx, 3);
+       coeff[4] = get_iir_band_coeff(component, iir_idx, band_idx, 4);
+
+       memcpy(ucontrol->value.bytes.data, &coeff[0], params->max);
+
+       return 0;
+}
+
+static int rx_macro_iir_filter_info(struct snd_kcontrol *kcontrol,
+                                  struct snd_ctl_elem_info *ucontrol)
+{
+       struct wcd_iir_filter_ctl *ctl =
+               (struct wcd_iir_filter_ctl *)kcontrol->private_value;
+       struct soc_bytes_ext *params = &ctl->bytes_ext;
+
+       ucontrol->type = SNDRV_CTL_ELEM_TYPE_BYTES;
+       ucontrol->count = params->max;
+
+       return 0;
+}
+
+static const struct snd_kcontrol_new rx_macro_snd_controls[] = {
+       SOC_SINGLE_S8_TLV("RX_RX0 Digital Volume", CDC_RX_RX0_RX_VOL_CTL,
+                         -84, 40, digital_gain),
+       SOC_SINGLE_S8_TLV("RX_RX1 Digital Volume", CDC_RX_RX1_RX_VOL_CTL,
+                         -84, 40, digital_gain),
+       SOC_SINGLE_S8_TLV("RX_RX2 Digital Volume", CDC_RX_RX2_RX_VOL_CTL,
+                         -84, 40, digital_gain),
+       SOC_SINGLE_S8_TLV("RX_RX0 Mix Digital Volume", CDC_RX_RX0_RX_VOL_MIX_CTL,
+                         -84, 40, digital_gain),
+       SOC_SINGLE_S8_TLV("RX_RX1 Mix Digital Volume", CDC_RX_RX1_RX_VOL_MIX_CTL,
+                         -84, 40, digital_gain),
+       SOC_SINGLE_S8_TLV("RX_RX2 Mix Digital Volume", CDC_RX_RX2_RX_VOL_MIX_CTL,
+                         -84, 40, digital_gain),
+
+       SOC_SINGLE_EXT("RX_COMP1 Switch", SND_SOC_NOPM, RX_MACRO_COMP1, 1, 0,
+               rx_macro_get_compander, rx_macro_set_compander),
+       SOC_SINGLE_EXT("RX_COMP2 Switch", SND_SOC_NOPM, RX_MACRO_COMP2, 1, 0,
+               rx_macro_get_compander, rx_macro_set_compander),
+
+       SOC_SINGLE_EXT("RX_EAR Mode Switch", SND_SOC_NOPM, 0, 1, 0,
+               rx_macro_get_ear_mode, rx_macro_put_ear_mode),
+
+       SOC_SINGLE_EXT("RX_HPH HD2 Mode Switch", SND_SOC_NOPM, 0, 1, 0,
+               rx_macro_get_hph_hd2_mode, rx_macro_put_hph_hd2_mode),
+
+       SOC_ENUM_EXT("RX_HPH PWR Mode", rx_macro_hph_pwr_mode_enum,
+               rx_macro_get_hph_pwr_mode, rx_macro_put_hph_pwr_mode),
+
+       SOC_SINGLE_EXT("RX_Softclip Switch", SND_SOC_NOPM, 0, 1, 0,
+                    rx_macro_soft_clip_enable_get,
+                    rx_macro_soft_clip_enable_put),
+       SOC_SINGLE_EXT("AUX_HPF Switch", SND_SOC_NOPM, 0, 1, 0,
+                       rx_macro_aux_hpf_mode_get,
+                       rx_macro_aux_hpf_mode_put),
+
+       SOC_SINGLE_S8_TLV("IIR0 INP0 Volume",
+               CDC_RX_SIDETONE_IIR0_IIR_GAIN_B1_CTL, -84, 40,
+               digital_gain),
+       SOC_SINGLE_S8_TLV("IIR0 INP1 Volume",
+               CDC_RX_SIDETONE_IIR0_IIR_GAIN_B2_CTL, -84, 40,
+               digital_gain),
+       SOC_SINGLE_S8_TLV("IIR0 INP2 Volume",
+               CDC_RX_SIDETONE_IIR0_IIR_GAIN_B3_CTL, -84, 40,
+               digital_gain),
+       SOC_SINGLE_S8_TLV("IIR0 INP3 Volume",
+               CDC_RX_SIDETONE_IIR0_IIR_GAIN_B4_CTL, -84, 40,
+               digital_gain),
+       SOC_SINGLE_S8_TLV("IIR1 INP0 Volume",
+               CDC_RX_SIDETONE_IIR1_IIR_GAIN_B1_CTL, -84, 40,
+               digital_gain),
+       SOC_SINGLE_S8_TLV("IIR1 INP1 Volume",
+               CDC_RX_SIDETONE_IIR1_IIR_GAIN_B2_CTL, -84, 40,
+               digital_gain),
+       SOC_SINGLE_S8_TLV("IIR1 INP2 Volume",
+               CDC_RX_SIDETONE_IIR1_IIR_GAIN_B3_CTL, -84, 40,
+               digital_gain),
+       SOC_SINGLE_S8_TLV("IIR1 INP3 Volume",
+               CDC_RX_SIDETONE_IIR1_IIR_GAIN_B4_CTL, -84, 40,
+               digital_gain),
+
+       SOC_SINGLE("IIR1 Band1 Switch", CDC_RX_SIDETONE_IIR0_IIR_CTL,
+                  0, 1, 0),
+       SOC_SINGLE("IIR1 Band2 Switch", CDC_RX_SIDETONE_IIR0_IIR_CTL,
+                  1, 1, 0),
+       SOC_SINGLE("IIR1 Band3 Switch", CDC_RX_SIDETONE_IIR0_IIR_CTL,
+                  2, 1, 0),
+       SOC_SINGLE("IIR1 Band4 Switch", CDC_RX_SIDETONE_IIR0_IIR_CTL,
+                  3, 1, 0),
+       SOC_SINGLE("IIR1 Band5 Switch", CDC_RX_SIDETONE_IIR0_IIR_CTL,
+                  4, 1, 0),
+       SOC_SINGLE("IIR2 Band1 Switch", CDC_RX_SIDETONE_IIR1_IIR_CTL,
+                  0, 1, 0),
+       SOC_SINGLE("IIR2 Band2 Switch", CDC_RX_SIDETONE_IIR1_IIR_CTL,
+                  1, 1, 0),
+       SOC_SINGLE("IIR2 Band3 Switch", CDC_RX_SIDETONE_IIR1_IIR_CTL,
+                  2, 1, 0),
+       SOC_SINGLE("IIR2 Band4 Switch", CDC_RX_SIDETONE_IIR1_IIR_CTL,
+                  3, 1, 0),
+       SOC_SINGLE("IIR2 Band5 Switch", CDC_RX_SIDETONE_IIR1_IIR_CTL,
+                  4, 1, 0),
+
+       RX_MACRO_IIR_FILTER_CTL("IIR0 Band1", IIR0, BAND1),
+       RX_MACRO_IIR_FILTER_CTL("IIR0 Band2", IIR0, BAND2),
+       RX_MACRO_IIR_FILTER_CTL("IIR0 Band3", IIR0, BAND3),
+       RX_MACRO_IIR_FILTER_CTL("IIR0 Band4", IIR0, BAND4),
+       RX_MACRO_IIR_FILTER_CTL("IIR0 Band5", IIR0, BAND5),
+
+       RX_MACRO_IIR_FILTER_CTL("IIR1 Band1", IIR1, BAND1),
+       RX_MACRO_IIR_FILTER_CTL("IIR1 Band2", IIR1, BAND2),
+       RX_MACRO_IIR_FILTER_CTL("IIR1 Band3", IIR1, BAND3),
+       RX_MACRO_IIR_FILTER_CTL("IIR1 Band4", IIR1, BAND4),
+       RX_MACRO_IIR_FILTER_CTL("IIR1 Band5", IIR1, BAND5),
+
+};
+
+static int rx_macro_enable_echo(struct snd_soc_dapm_widget *w,
+                               struct snd_kcontrol *kcontrol,
+                               int event)
+{
+       struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+       u16 val, ec_hq_reg;
+       int ec_tx;
+
+       val = snd_soc_component_read(component,
+                       CDC_RX_INP_MUX_RX_MIX_CFG4);
+       if (!(strcmp(w->name, "RX MIX TX0 MUX")))
+               ec_tx = ((val & 0xf0) >> 0x4) - 1;
+       else if (!(strcmp(w->name, "RX MIX TX1 MUX")))
+               ec_tx = (val & 0x0f) - 1;
+
+       val = snd_soc_component_read(component,
+                       CDC_RX_INP_MUX_RX_MIX_CFG5);
+       if (!(strcmp(w->name, "RX MIX TX2 MUX")))
+               ec_tx = (val & 0x0f) - 1;
+
+       if (ec_tx < 0 || (ec_tx >= RX_MACRO_EC_MUX_MAX)) {
+               dev_err(component->dev, "%s: EC mix control not set correctly\n",
+                       __func__);
+               return -EINVAL;
+       }
+       ec_hq_reg = CDC_RX_EC_REF_HQ0_EC_REF_HQ_PATH_CTL +
+                           0x40 * ec_tx;
+       snd_soc_component_update_bits(component, ec_hq_reg, 0x01, 0x01);
+       ec_hq_reg = CDC_RX_EC_REF_HQ0_EC_REF_HQ_CFG0 +
+                               0x40 * ec_tx;
+       /* default set to 48k */
+       snd_soc_component_update_bits(component, ec_hq_reg, 0x1E, 0x08);
+
+       return 0;
+}
+
+static const struct snd_soc_dapm_widget rx_macro_dapm_widgets[] = {
+       SND_SOC_DAPM_AIF_IN("RX AIF1 PB", "RX_MACRO_AIF1 Playback", 0,
+               SND_SOC_NOPM, 0, 0),
+
+       SND_SOC_DAPM_AIF_IN("RX AIF2 PB", "RX_MACRO_AIF2 Playback", 0,
+               SND_SOC_NOPM, 0, 0),
+
+       SND_SOC_DAPM_AIF_IN("RX AIF3 PB", "RX_MACRO_AIF3 Playback", 0,
+               SND_SOC_NOPM, 0, 0),
+
+       SND_SOC_DAPM_AIF_IN("RX AIF4 PB", "RX_MACRO_AIF4 Playback", 0,
+               SND_SOC_NOPM, 0, 0),
+
+       SND_SOC_DAPM_AIF_OUT("RX AIF_ECHO", "RX_AIF_ECHO Capture", 0,
+               SND_SOC_NOPM, 0, 0),
+
+       SND_SOC_DAPM_MUX("RX_MACRO RX0 MUX", SND_SOC_NOPM, RX_MACRO_RX0, 0,
+                        &rx_macro_rx0_mux),
+       SND_SOC_DAPM_MUX("RX_MACRO RX1 MUX", SND_SOC_NOPM, RX_MACRO_RX1, 0,
+                        &rx_macro_rx1_mux),
+       SND_SOC_DAPM_MUX("RX_MACRO RX2 MUX", SND_SOC_NOPM, RX_MACRO_RX2, 0,
+                        &rx_macro_rx2_mux),
+       SND_SOC_DAPM_MUX("RX_MACRO RX3 MUX", SND_SOC_NOPM, RX_MACRO_RX3, 0,
+                        &rx_macro_rx3_mux),
+       SND_SOC_DAPM_MUX("RX_MACRO RX4 MUX", SND_SOC_NOPM, RX_MACRO_RX4, 0,
+                        &rx_macro_rx4_mux),
+       SND_SOC_DAPM_MUX("RX_MACRO RX5 MUX", SND_SOC_NOPM, RX_MACRO_RX5, 0,
+                        &rx_macro_rx5_mux),
+
+       SND_SOC_DAPM_MIXER("RX_RX0", SND_SOC_NOPM, 0, 0, NULL, 0),
+       SND_SOC_DAPM_MIXER("RX_RX1", SND_SOC_NOPM, 0, 0, NULL, 0),
+       SND_SOC_DAPM_MIXER("RX_RX2", SND_SOC_NOPM, 0, 0, NULL, 0),
+       SND_SOC_DAPM_MIXER("RX_RX3", SND_SOC_NOPM, 0, 0, NULL, 0),
+       SND_SOC_DAPM_MIXER("RX_RX4", SND_SOC_NOPM, 0, 0, NULL, 0),
+       SND_SOC_DAPM_MIXER("RX_RX5", SND_SOC_NOPM, 0, 0, NULL, 0),
+
+       SND_SOC_DAPM_MUX("IIR0 INP0 MUX", SND_SOC_NOPM, 0, 0, &iir0_inp0_mux),
+       SND_SOC_DAPM_MUX("IIR0 INP1 MUX", SND_SOC_NOPM, 0, 0, &iir0_inp1_mux),
+       SND_SOC_DAPM_MUX("IIR0 INP2 MUX", SND_SOC_NOPM, 0, 0, &iir0_inp2_mux),
+       SND_SOC_DAPM_MUX("IIR0 INP3 MUX", SND_SOC_NOPM, 0, 0, &iir0_inp3_mux),
+       SND_SOC_DAPM_MUX("IIR1 INP0 MUX", SND_SOC_NOPM, 0, 0, &iir1_inp0_mux),
+       SND_SOC_DAPM_MUX("IIR1 INP1 MUX", SND_SOC_NOPM, 0, 0, &iir1_inp1_mux),
+       SND_SOC_DAPM_MUX("IIR1 INP2 MUX", SND_SOC_NOPM, 0, 0, &iir1_inp2_mux),
+       SND_SOC_DAPM_MUX("IIR1 INP3 MUX", SND_SOC_NOPM, 0, 0, &iir1_inp3_mux),
+
+       SND_SOC_DAPM_MUX_E("RX MIX TX0 MUX", SND_SOC_NOPM,
+                          RX_MACRO_EC0_MUX, 0,
+                          &rx_mix_tx0_mux, rx_macro_enable_echo,
+                          SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+       SND_SOC_DAPM_MUX_E("RX MIX TX1 MUX", SND_SOC_NOPM,
+                          RX_MACRO_EC1_MUX, 0,
+                          &rx_mix_tx1_mux, rx_macro_enable_echo,
+                          SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+       SND_SOC_DAPM_MUX_E("RX MIX TX2 MUX", SND_SOC_NOPM,
+                          RX_MACRO_EC2_MUX, 0,
+                          &rx_mix_tx2_mux, rx_macro_enable_echo,
+                          SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+
+       SND_SOC_DAPM_MIXER_E("IIR0", CDC_RX_SIDETONE_IIR0_IIR_PATH_CTL,
+               4, 0, NULL, 0, rx_macro_set_iir_gain,
+               SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
+       SND_SOC_DAPM_MIXER_E("IIR1", CDC_RX_SIDETONE_IIR1_IIR_PATH_CTL,
+               4, 0, NULL, 0, rx_macro_set_iir_gain,
+               SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
+       SND_SOC_DAPM_MIXER("SRC0", CDC_RX_SIDETONE_SRC0_ST_SRC_PATH_CTL,
+               4, 0, NULL, 0),
+       SND_SOC_DAPM_MIXER("SRC1", CDC_RX_SIDETONE_SRC1_ST_SRC_PATH_CTL,
+               4, 0, NULL, 0),
+
+       SND_SOC_DAPM_MUX("RX INT0 DEM MUX", SND_SOC_NOPM, 0, 0,
+                        &rx_int0_dem_inp_mux),
+       SND_SOC_DAPM_MUX("RX INT1 DEM MUX", SND_SOC_NOPM, 0, 0,
+                        &rx_int1_dem_inp_mux),
+
+       SND_SOC_DAPM_MUX_E("RX INT0_2 MUX", SND_SOC_NOPM, INTERP_HPHL, 0,
+               &rx_int0_2_mux, rx_macro_enable_mix_path,
+               SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+               SND_SOC_DAPM_POST_PMD),
+       SND_SOC_DAPM_MUX_E("RX INT1_2 MUX", SND_SOC_NOPM, INTERP_HPHR, 0,
+               &rx_int1_2_mux, rx_macro_enable_mix_path,
+               SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+               SND_SOC_DAPM_POST_PMD),
+       SND_SOC_DAPM_MUX_E("RX INT2_2 MUX", SND_SOC_NOPM, INTERP_AUX, 0,
+               &rx_int2_2_mux, rx_macro_enable_mix_path,
+               SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+               SND_SOC_DAPM_POST_PMD),
+
+       SND_SOC_DAPM_MUX("RX INT0_1 MIX1 INP0", SND_SOC_NOPM, 0, 0, &rx_int0_1_mix_inp0_mux),
+       SND_SOC_DAPM_MUX("RX INT0_1 MIX1 INP1", SND_SOC_NOPM, 0, 0, &rx_int0_1_mix_inp1_mux),
+       SND_SOC_DAPM_MUX("RX INT0_1 MIX1 INP2", SND_SOC_NOPM, 0, 0, &rx_int0_1_mix_inp2_mux),
+       SND_SOC_DAPM_MUX("RX INT1_1 MIX1 INP0", SND_SOC_NOPM, 0, 0, &rx_int1_1_mix_inp0_mux),
+       SND_SOC_DAPM_MUX("RX INT1_1 MIX1 INP1", SND_SOC_NOPM, 0, 0, &rx_int1_1_mix_inp1_mux),
+       SND_SOC_DAPM_MUX("RX INT1_1 MIX1 INP2", SND_SOC_NOPM, 0, 0, &rx_int1_1_mix_inp2_mux),
+       SND_SOC_DAPM_MUX("RX INT2_1 MIX1 INP0", SND_SOC_NOPM, 0, 0, &rx_int2_1_mix_inp0_mux),
+       SND_SOC_DAPM_MUX("RX INT2_1 MIX1 INP1", SND_SOC_NOPM, 0, 0, &rx_int2_1_mix_inp1_mux),
+       SND_SOC_DAPM_MUX("RX INT2_1 MIX1 INP2", SND_SOC_NOPM, 0, 0, &rx_int2_1_mix_inp2_mux),
+
+       SND_SOC_DAPM_MUX_E("RX INT0_1 INTERP", SND_SOC_NOPM, INTERP_HPHL, 0,
+               &rx_int0_1_interp_mux, rx_macro_enable_main_path,
+               SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+               SND_SOC_DAPM_POST_PMD),
+       SND_SOC_DAPM_MUX_E("RX INT1_1 INTERP", SND_SOC_NOPM, INTERP_HPHR, 0,
+               &rx_int1_1_interp_mux, rx_macro_enable_main_path,
+               SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+               SND_SOC_DAPM_POST_PMD),
+       SND_SOC_DAPM_MUX_E("RX INT2_1 INTERP", SND_SOC_NOPM, INTERP_AUX, 0,
+               &rx_int2_1_interp_mux, rx_macro_enable_main_path,
+               SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+               SND_SOC_DAPM_POST_PMD),
+
+       SND_SOC_DAPM_MUX("RX INT0_2 INTERP", SND_SOC_NOPM, 0, 0,
+                        &rx_int0_2_interp_mux),
+       SND_SOC_DAPM_MUX("RX INT1_2 INTERP", SND_SOC_NOPM, 0, 0,
+                        &rx_int1_2_interp_mux),
+       SND_SOC_DAPM_MUX("RX INT2_2 INTERP", SND_SOC_NOPM, 0, 0,
+                        &rx_int2_2_interp_mux),
+
+       SND_SOC_DAPM_MIXER("RX INT0_1 MIX1", SND_SOC_NOPM, 0, 0, NULL, 0),
+       SND_SOC_DAPM_MIXER("RX INT0 SEC MIX", SND_SOC_NOPM, 0, 0, NULL, 0),
+       SND_SOC_DAPM_MIXER("RX INT1_1 MIX1", SND_SOC_NOPM, 0, 0, NULL, 0),
+       SND_SOC_DAPM_MIXER("RX INT1 SEC MIX", SND_SOC_NOPM, 0, 0, NULL, 0),
+       SND_SOC_DAPM_MIXER("RX INT2_1 MIX1", SND_SOC_NOPM, 0, 0, NULL, 0),
+       SND_SOC_DAPM_MIXER("RX INT2 SEC MIX", SND_SOC_NOPM, 0, 0, NULL, 0),
+
+       SND_SOC_DAPM_MUX_E("RX INT0 MIX2 INP", SND_SOC_NOPM, INTERP_HPHL,
+               0, &rx_int0_mix2_inp_mux, rx_macro_enable_rx_path_clk,
+               SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+       SND_SOC_DAPM_MUX_E("RX INT1 MIX2 INP", SND_SOC_NOPM, INTERP_HPHR,
+               0, &rx_int1_mix2_inp_mux, rx_macro_enable_rx_path_clk,
+               SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+       SND_SOC_DAPM_MUX_E("RX INT2 MIX2 INP", SND_SOC_NOPM, INTERP_AUX,
+               0, &rx_int2_mix2_inp_mux, rx_macro_enable_rx_path_clk,
+               SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+
+       SND_SOC_DAPM_MIXER("RX INT0 MIX2", SND_SOC_NOPM, 0, 0, NULL, 0),
+       SND_SOC_DAPM_MIXER("RX INT1 MIX2", SND_SOC_NOPM, 0, 0, NULL, 0),
+       SND_SOC_DAPM_MIXER("RX INT2 MIX2", SND_SOC_NOPM, 0, 0, NULL, 0),
+
+       SND_SOC_DAPM_OUTPUT("HPHL_OUT"),
+       SND_SOC_DAPM_OUTPUT("HPHR_OUT"),
+       SND_SOC_DAPM_OUTPUT("AUX_OUT"),
+
+       SND_SOC_DAPM_INPUT("RX_TX DEC0_INP"),
+       SND_SOC_DAPM_INPUT("RX_TX DEC1_INP"),
+       SND_SOC_DAPM_INPUT("RX_TX DEC2_INP"),
+       SND_SOC_DAPM_INPUT("RX_TX DEC3_INP"),
+
+       SND_SOC_DAPM_SUPPLY_S("RX_MCLK", 0, SND_SOC_NOPM, 0, 0,
+       rx_macro_mclk_event, SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+};
+
+static const struct snd_soc_dapm_route rx_audio_map[] = {
+       {"RX AIF1 PB", NULL, "RX_MCLK"},
+       {"RX AIF2 PB", NULL, "RX_MCLK"},
+       {"RX AIF3 PB", NULL, "RX_MCLK"},
+       {"RX AIF4 PB", NULL, "RX_MCLK"},
+
+       {"RX_MACRO RX0 MUX", "AIF1_PB", "RX AIF1 PB"},
+       {"RX_MACRO RX1 MUX", "AIF1_PB", "RX AIF1 PB"},
+       {"RX_MACRO RX2 MUX", "AIF1_PB", "RX AIF1 PB"},
+       {"RX_MACRO RX3 MUX", "AIF1_PB", "RX AIF1 PB"},
+       {"RX_MACRO RX4 MUX", "AIF1_PB", "RX AIF1 PB"},
+       {"RX_MACRO RX5 MUX", "AIF1_PB", "RX AIF1 PB"},
+
+       {"RX_MACRO RX0 MUX", "AIF2_PB", "RX AIF2 PB"},
+       {"RX_MACRO RX1 MUX", "AIF2_PB", "RX AIF2 PB"},
+       {"RX_MACRO RX2 MUX", "AIF2_PB", "RX AIF2 PB"},
+       {"RX_MACRO RX3 MUX", "AIF2_PB", "RX AIF2 PB"},
+       {"RX_MACRO RX4 MUX", "AIF2_PB", "RX AIF2 PB"},
+       {"RX_MACRO RX5 MUX", "AIF2_PB", "RX AIF2 PB"},
+
+       {"RX_MACRO RX0 MUX", "AIF3_PB", "RX AIF3 PB"},
+       {"RX_MACRO RX1 MUX", "AIF3_PB", "RX AIF3 PB"},
+       {"RX_MACRO RX2 MUX", "AIF3_PB", "RX AIF3 PB"},
+       {"RX_MACRO RX3 MUX", "AIF3_PB", "RX AIF3 PB"},
+       {"RX_MACRO RX4 MUX", "AIF3_PB", "RX AIF3 PB"},
+       {"RX_MACRO RX5 MUX", "AIF3_PB", "RX AIF3 PB"},
+
+       {"RX_MACRO RX0 MUX", "AIF4_PB", "RX AIF4 PB"},
+       {"RX_MACRO RX1 MUX", "AIF4_PB", "RX AIF4 PB"},
+       {"RX_MACRO RX2 MUX", "AIF4_PB", "RX AIF4 PB"},
+       {"RX_MACRO RX3 MUX", "AIF4_PB", "RX AIF4 PB"},
+       {"RX_MACRO RX4 MUX", "AIF4_PB", "RX AIF4 PB"},
+       {"RX_MACRO RX5 MUX", "AIF4_PB", "RX AIF4 PB"},
+
+       {"RX_RX0", NULL, "RX_MACRO RX0 MUX"},
+       {"RX_RX1", NULL, "RX_MACRO RX1 MUX"},
+       {"RX_RX2", NULL, "RX_MACRO RX2 MUX"},
+       {"RX_RX3", NULL, "RX_MACRO RX3 MUX"},
+       {"RX_RX4", NULL, "RX_MACRO RX4 MUX"},
+       {"RX_RX5", NULL, "RX_MACRO RX5 MUX"},
+
+       {"RX INT0_1 MIX1 INP0", "RX0", "RX_RX0"},
+       {"RX INT0_1 MIX1 INP0", "RX1", "RX_RX1"},
+       {"RX INT0_1 MIX1 INP0", "RX2", "RX_RX2"},
+       {"RX INT0_1 MIX1 INP0", "RX3", "RX_RX3"},
+       {"RX INT0_1 MIX1 INP0", "RX4", "RX_RX4"},
+       {"RX INT0_1 MIX1 INP0", "RX5", "RX_RX5"},
+       {"RX INT0_1 MIX1 INP0", "IIR0", "IIR0"},
+       {"RX INT0_1 MIX1 INP0", "IIR1", "IIR1"},
+       {"RX INT0_1 MIX1 INP0", "DEC0", "RX_TX DEC0_INP"},
+       {"RX INT0_1 MIX1 INP0", "DEC1", "RX_TX DEC1_INP"},
+       {"RX INT0_1 MIX1 INP1", "RX0", "RX_RX0"},
+       {"RX INT0_1 MIX1 INP1", "RX1", "RX_RX1"},
+       {"RX INT0_1 MIX1 INP1", "RX2", "RX_RX2"},
+       {"RX INT0_1 MIX1 INP1", "RX3", "RX_RX3"},
+       {"RX INT0_1 MIX1 INP1", "RX4", "RX_RX4"},
+       {"RX INT0_1 MIX1 INP1", "RX5", "RX_RX5"},
+       {"RX INT0_1 MIX1 INP1", "IIR0", "IIR0"},
+       {"RX INT0_1 MIX1 INP1", "IIR1", "IIR1"},
+       {"RX INT0_1 MIX1 INP1", "DEC0", "RX_TX DEC0_INP"},
+       {"RX INT0_1 MIX1 INP1", "DEC1", "RX_TX DEC1_INP"},
+       {"RX INT0_1 MIX1 INP2", "RX0", "RX_RX0"},
+       {"RX INT0_1 MIX1 INP2", "RX1", "RX_RX1"},
+       {"RX INT0_1 MIX1 INP2", "RX2", "RX_RX2"},
+       {"RX INT0_1 MIX1 INP2", "RX3", "RX_RX3"},
+       {"RX INT0_1 MIX1 INP2", "RX4", "RX_RX4"},
+       {"RX INT0_1 MIX1 INP2", "RX5", "RX_RX5"},
+       {"RX INT0_1 MIX1 INP2", "IIR0", "IIR0"},
+       {"RX INT0_1 MIX1 INP2", "IIR1", "IIR1"},
+       {"RX INT0_1 MIX1 INP2", "DEC0", "RX_TX DEC0_INP"},
+       {"RX INT0_1 MIX1 INP2", "DEC1", "RX_TX DEC1_INP"},
+
+       {"RX INT1_1 MIX1 INP0", "RX0", "RX_RX0"},
+       {"RX INT1_1 MIX1 INP0", "RX1", "RX_RX1"},
+       {"RX INT1_1 MIX1 INP0", "RX2", "RX_RX2"},
+       {"RX INT1_1 MIX1 INP0", "RX3", "RX_RX3"},
+       {"RX INT1_1 MIX1 INP0", "RX4", "RX_RX4"},
+       {"RX INT1_1 MIX1 INP0", "RX5", "RX_RX5"},
+       {"RX INT1_1 MIX1 INP0", "IIR0", "IIR0"},
+       {"RX INT1_1 MIX1 INP0", "IIR1", "IIR1"},
+       {"RX INT1_1 MIX1 INP0", "DEC0", "RX_TX DEC0_INP"},
+       {"RX INT1_1 MIX1 INP0", "DEC1", "RX_TX DEC1_INP"},
+       {"RX INT1_1 MIX1 INP1", "RX0", "RX_RX0"},
+       {"RX INT1_1 MIX1 INP1", "RX1", "RX_RX1"},
+       {"RX INT1_1 MIX1 INP1", "RX2", "RX_RX2"},
+       {"RX INT1_1 MIX1 INP1", "RX3", "RX_RX3"},
+       {"RX INT1_1 MIX1 INP1", "RX4", "RX_RX4"},
+       {"RX INT1_1 MIX1 INP1", "RX5", "RX_RX5"},
+       {"RX INT1_1 MIX1 INP1", "IIR0", "IIR0"},
+       {"RX INT1_1 MIX1 INP1", "IIR1", "IIR1"},
+       {"RX INT1_1 MIX1 INP1", "DEC0", "RX_TX DEC0_INP"},
+       {"RX INT1_1 MIX1 INP1", "DEC1", "RX_TX DEC1_INP"},
+       {"RX INT1_1 MIX1 INP2", "RX0", "RX_RX0"},
+       {"RX INT1_1 MIX1 INP2", "RX1", "RX_RX1"},
+       {"RX INT1_1 MIX1 INP2", "RX2", "RX_RX2"},
+       {"RX INT1_1 MIX1 INP2", "RX3", "RX_RX3"},
+       {"RX INT1_1 MIX1 INP2", "RX4", "RX_RX4"},
+       {"RX INT1_1 MIX1 INP2", "RX5", "RX_RX5"},
+       {"RX INT1_1 MIX1 INP2", "IIR0", "IIR0"},
+       {"RX INT1_1 MIX1 INP2", "IIR1", "IIR1"},
+       {"RX INT1_1 MIX1 INP2", "DEC0", "RX_TX DEC0_INP"},
+       {"RX INT1_1 MIX1 INP2", "DEC1", "RX_TX DEC1_INP"},
+
+       {"RX INT2_1 MIX1 INP0", "RX0", "RX_RX0"},
+       {"RX INT2_1 MIX1 INP0", "RX1", "RX_RX1"},
+       {"RX INT2_1 MIX1 INP0", "RX2", "RX_RX2"},
+       {"RX INT2_1 MIX1 INP0", "RX3", "RX_RX3"},
+       {"RX INT2_1 MIX1 INP0", "RX4", "RX_RX4"},
+       {"RX INT2_1 MIX1 INP0", "RX5", "RX_RX5"},
+       {"RX INT2_1 MIX1 INP0", "IIR0", "IIR0"},
+       {"RX INT2_1 MIX1 INP0", "IIR1", "IIR1"},
+       {"RX INT2_1 MIX1 INP0", "DEC0", "RX_TX DEC0_INP"},
+       {"RX INT2_1 MIX1 INP0", "DEC1", "RX_TX DEC1_INP"},
+       {"RX INT2_1 MIX1 INP1", "RX0", "RX_RX0"},
+       {"RX INT2_1 MIX1 INP1", "RX1", "RX_RX1"},
+       {"RX INT2_1 MIX1 INP1", "RX2", "RX_RX2"},
+       {"RX INT2_1 MIX1 INP1", "RX3", "RX_RX3"},
+       {"RX INT2_1 MIX1 INP1", "RX4", "RX_RX4"},
+       {"RX INT2_1 MIX1 INP1", "RX5", "RX_RX5"},
+       {"RX INT2_1 MIX1 INP1", "IIR0", "IIR0"},
+       {"RX INT2_1 MIX1 INP1", "IIR1", "IIR1"},
+       {"RX INT2_1 MIX1 INP1", "DEC0", "RX_TX DEC0_INP"},
+       {"RX INT2_1 MIX1 INP1", "DEC1", "RX_TX DEC1_INP"},
+       {"RX INT2_1 MIX1 INP2", "RX0", "RX_RX0"},
+       {"RX INT2_1 MIX1 INP2", "RX1", "RX_RX1"},
+       {"RX INT2_1 MIX1 INP2", "RX2", "RX_RX2"},
+       {"RX INT2_1 MIX1 INP2", "RX3", "RX_RX3"},
+       {"RX INT2_1 MIX1 INP2", "RX4", "RX_RX4"},
+       {"RX INT2_1 MIX1 INP2", "RX5", "RX_RX5"},
+       {"RX INT2_1 MIX1 INP2", "IIR0", "IIR0"},
+       {"RX INT2_1 MIX1 INP2", "IIR1", "IIR1"},
+       {"RX INT2_1 MIX1 INP2", "DEC0", "RX_TX DEC0_INP"},
+       {"RX INT2_1 MIX1 INP2", "DEC1", "RX_TX DEC1_INP"},
+
+       {"RX INT0_1 MIX1", NULL, "RX INT0_1 MIX1 INP0"},
+       {"RX INT0_1 MIX1", NULL, "RX INT0_1 MIX1 INP1"},
+       {"RX INT0_1 MIX1", NULL, "RX INT0_1 MIX1 INP2"},
+       {"RX INT1_1 MIX1", NULL, "RX INT1_1 MIX1 INP0"},
+       {"RX INT1_1 MIX1", NULL, "RX INT1_1 MIX1 INP1"},
+       {"RX INT1_1 MIX1", NULL, "RX INT1_1 MIX1 INP2"},
+       {"RX INT2_1 MIX1", NULL, "RX INT2_1 MIX1 INP0"},
+       {"RX INT2_1 MIX1", NULL, "RX INT2_1 MIX1 INP1"},
+       {"RX INT2_1 MIX1", NULL, "RX INT2_1 MIX1 INP2"},
+
+       {"RX MIX TX0 MUX", "RX_MIX0", "RX INT0 SEC MIX"},
+       {"RX MIX TX0 MUX", "RX_MIX1", "RX INT1 SEC MIX"},
+       {"RX MIX TX0 MUX", "RX_MIX2", "RX INT2 SEC MIX"},
+       {"RX MIX TX1 MUX", "RX_MIX0", "RX INT0 SEC MIX"},
+       {"RX MIX TX1 MUX", "RX_MIX1", "RX INT1 SEC MIX"},
+       {"RX MIX TX1 MUX", "RX_MIX2", "RX INT2 SEC MIX"},
+       {"RX MIX TX2 MUX", "RX_MIX0", "RX INT0 SEC MIX"},
+       {"RX MIX TX2 MUX", "RX_MIX1", "RX INT1 SEC MIX"},
+       {"RX MIX TX2 MUX", "RX_MIX2", "RX INT2 SEC MIX"},
+       {"RX AIF_ECHO", NULL, "RX MIX TX0 MUX"},
+       {"RX AIF_ECHO", NULL, "RX MIX TX1 MUX"},
+       {"RX AIF_ECHO", NULL, "RX MIX TX2 MUX"},
+       {"RX AIF_ECHO", NULL, "RX_MCLK"},
+
+       /* Mixing path INT0 */
+       {"RX INT0_2 MUX", "RX0", "RX_RX0"},
+       {"RX INT0_2 MUX", "RX1", "RX_RX1"},
+       {"RX INT0_2 MUX", "RX2", "RX_RX2"},
+       {"RX INT0_2 MUX", "RX3", "RX_RX3"},
+       {"RX INT0_2 MUX", "RX4", "RX_RX4"},
+       {"RX INT0_2 MUX", "RX5", "RX_RX5"},
+       {"RX INT0_2 INTERP", NULL, "RX INT0_2 MUX"},
+       {"RX INT0 SEC MIX", NULL, "RX INT0_2 INTERP"},
+
+       /* Mixing path INT1 */
+       {"RX INT1_2 MUX", "RX0", "RX_RX0"},
+       {"RX INT1_2 MUX", "RX1", "RX_RX1"},
+       {"RX INT1_2 MUX", "RX2", "RX_RX2"},
+       {"RX INT1_2 MUX", "RX3", "RX_RX3"},
+       {"RX INT1_2 MUX", "RX4", "RX_RX4"},
+       {"RX INT1_2 MUX", "RX5", "RX_RX5"},
+       {"RX INT1_2 INTERP", NULL, "RX INT1_2 MUX"},
+       {"RX INT1 SEC MIX", NULL, "RX INT1_2 INTERP"},
+
+       /* Mixing path INT2 */
+       {"RX INT2_2 MUX", "RX0", "RX_RX0"},
+       {"RX INT2_2 MUX", "RX1", "RX_RX1"},
+       {"RX INT2_2 MUX", "RX2", "RX_RX2"},
+       {"RX INT2_2 MUX", "RX3", "RX_RX3"},
+       {"RX INT2_2 MUX", "RX4", "RX_RX4"},
+       {"RX INT2_2 MUX", "RX5", "RX_RX5"},
+       {"RX INT2_2 INTERP", NULL, "RX INT2_2 MUX"},
+       {"RX INT2 SEC MIX", NULL, "RX INT2_2 INTERP"},
+
+       {"RX INT0_1 INTERP", NULL, "RX INT0_1 MIX1"},
+       {"RX INT0 SEC MIX", NULL, "RX INT0_1 INTERP"},
+       {"RX INT0 MIX2", NULL, "RX INT0 SEC MIX"},
+       {"RX INT0 MIX2", NULL, "RX INT0 MIX2 INP"},
+       {"RX INT0 DEM MUX", "CLSH_DSM_OUT", "RX INT0 MIX2"},
+       {"HPHL_OUT", NULL, "RX INT0 DEM MUX"},
+       {"HPHL_OUT", NULL, "RX_MCLK"},
+
+       {"RX INT1_1 INTERP", NULL, "RX INT1_1 MIX1"},
+       {"RX INT1 SEC MIX", NULL, "RX INT1_1 INTERP"},
+       {"RX INT1 MIX2", NULL, "RX INT1 SEC MIX"},
+       {"RX INT1 MIX2", NULL, "RX INT1 MIX2 INP"},
+       {"RX INT1 DEM MUX", "CLSH_DSM_OUT", "RX INT1 MIX2"},
+       {"HPHR_OUT", NULL, "RX INT1 DEM MUX"},
+       {"HPHR_OUT", NULL, "RX_MCLK"},
+
+       {"RX INT2_1 INTERP", NULL, "RX INT2_1 MIX1"},
+
+       {"RX INT2 SEC MIX", NULL, "RX INT2_1 INTERP"},
+       {"RX INT2 MIX2", NULL, "RX INT2 SEC MIX"},
+       {"RX INT2 MIX2", NULL, "RX INT2 MIX2 INP"},
+       {"AUX_OUT", NULL, "RX INT2 MIX2"},
+       {"AUX_OUT", NULL, "RX_MCLK"},
+
+       {"IIR0", NULL, "RX_MCLK"},
+       {"IIR0", NULL, "IIR0 INP0 MUX"},
+       {"IIR0 INP0 MUX", "DEC0", "RX_TX DEC0_INP"},
+       {"IIR0 INP0 MUX", "DEC1", "RX_TX DEC1_INP"},
+       {"IIR0 INP0 MUX", "DEC2", "RX_TX DEC2_INP"},
+       {"IIR0 INP0 MUX", "DEC3", "RX_TX DEC3_INP"},
+       {"IIR0 INP0 MUX", "RX0", "RX_RX0"},
+       {"IIR0 INP0 MUX", "RX1", "RX_RX1"},
+       {"IIR0 INP0 MUX", "RX2", "RX_RX2"},
+       {"IIR0 INP0 MUX", "RX3", "RX_RX3"},
+       {"IIR0 INP0 MUX", "RX4", "RX_RX4"},
+       {"IIR0 INP0 MUX", "RX5", "RX_RX5"},
+       {"IIR0", NULL, "IIR0 INP1 MUX"},
+       {"IIR0 INP1 MUX", "DEC0", "RX_TX DEC0_INP"},
+       {"IIR0 INP1 MUX", "DEC1", "RX_TX DEC1_INP"},
+       {"IIR0 INP1 MUX", "DEC2", "RX_TX DEC2_INP"},
+       {"IIR0 INP1 MUX", "DEC3", "RX_TX DEC3_INP"},
+       {"IIR0 INP1 MUX", "RX0", "RX_RX0"},
+       {"IIR0 INP1 MUX", "RX1", "RX_RX1"},
+       {"IIR0 INP1 MUX", "RX2", "RX_RX2"},
+       {"IIR0 INP1 MUX", "RX3", "RX_RX3"},
+       {"IIR0 INP1 MUX", "RX4", "RX_RX4"},
+       {"IIR0 INP1 MUX", "RX5", "RX_RX5"},
+       {"IIR0", NULL, "IIR0 INP2 MUX"},
+       {"IIR0 INP2 MUX", "DEC0", "RX_TX DEC0_INP"},
+       {"IIR0 INP2 MUX", "DEC1", "RX_TX DEC1_INP"},
+       {"IIR0 INP2 MUX", "DEC2", "RX_TX DEC2_INP"},
+       {"IIR0 INP2 MUX", "DEC3", "RX_TX DEC3_INP"},
+       {"IIR0 INP2 MUX", "RX0", "RX_RX0"},
+       {"IIR0 INP2 MUX", "RX1", "RX_RX1"},
+       {"IIR0 INP2 MUX", "RX2", "RX_RX2"},
+       {"IIR0 INP2 MUX", "RX3", "RX_RX3"},
+       {"IIR0 INP2 MUX", "RX4", "RX_RX4"},
+       {"IIR0 INP2 MUX", "RX5", "RX_RX5"},
+       {"IIR0", NULL, "IIR0 INP3 MUX"},
+       {"IIR0 INP3 MUX", "DEC0", "RX_TX DEC0_INP"},
+       {"IIR0 INP3 MUX", "DEC1", "RX_TX DEC1_INP"},
+       {"IIR0 INP3 MUX", "DEC2", "RX_TX DEC2_INP"},
+       {"IIR0 INP3 MUX", "DEC3", "RX_TX DEC3_INP"},
+       {"IIR0 INP3 MUX", "RX0", "RX_RX0"},
+       {"IIR0 INP3 MUX", "RX1", "RX_RX1"},
+       {"IIR0 INP3 MUX", "RX2", "RX_RX2"},
+       {"IIR0 INP3 MUX", "RX3", "RX_RX3"},
+       {"IIR0 INP3 MUX", "RX4", "RX_RX4"},
+       {"IIR0 INP3 MUX", "RX5", "RX_RX5"},
+
+       {"IIR1", NULL, "RX_MCLK"},
+       {"IIR1", NULL, "IIR1 INP0 MUX"},
+       {"IIR1 INP0 MUX", "DEC0", "RX_TX DEC0_INP"},
+       {"IIR1 INP0 MUX", "DEC1", "RX_TX DEC1_INP"},
+       {"IIR1 INP0 MUX", "DEC2", "RX_TX DEC2_INP"},
+       {"IIR1 INP0 MUX", "DEC3", "RX_TX DEC3_INP"},
+       {"IIR1 INP0 MUX", "RX0", "RX_RX0"},
+       {"IIR1 INP0 MUX", "RX1", "RX_RX1"},
+       {"IIR1 INP0 MUX", "RX2", "RX_RX2"},
+       {"IIR1 INP0 MUX", "RX3", "RX_RX3"},
+       {"IIR1 INP0 MUX", "RX4", "RX_RX4"},
+       {"IIR1 INP0 MUX", "RX5", "RX_RX5"},
+       {"IIR1", NULL, "IIR1 INP1 MUX"},
+       {"IIR1 INP1 MUX", "DEC0", "RX_TX DEC0_INP"},
+       {"IIR1 INP1 MUX", "DEC1", "RX_TX DEC1_INP"},
+       {"IIR1 INP1 MUX", "DEC2", "RX_TX DEC2_INP"},
+       {"IIR1 INP1 MUX", "DEC3", "RX_TX DEC3_INP"},
+       {"IIR1 INP1 MUX", "RX0", "RX_RX0"},
+       {"IIR1 INP1 MUX", "RX1", "RX_RX1"},
+       {"IIR1 INP1 MUX", "RX2", "RX_RX2"},
+       {"IIR1 INP1 MUX", "RX3", "RX_RX3"},
+       {"IIR1 INP1 MUX", "RX4", "RX_RX4"},
+       {"IIR1 INP1 MUX", "RX5", "RX_RX5"},
+       {"IIR1", NULL, "IIR1 INP2 MUX"},
+       {"IIR1 INP2 MUX", "DEC0", "RX_TX DEC0_INP"},
+       {"IIR1 INP2 MUX", "DEC1", "RX_TX DEC1_INP"},
+       {"IIR1 INP2 MUX", "DEC2", "RX_TX DEC2_INP"},
+       {"IIR1 INP2 MUX", "DEC3", "RX_TX DEC3_INP"},
+       {"IIR1 INP2 MUX", "RX0", "RX_RX0"},
+       {"IIR1 INP2 MUX", "RX1", "RX_RX1"},
+       {"IIR1 INP2 MUX", "RX2", "RX_RX2"},
+       {"IIR1 INP2 MUX", "RX3", "RX_RX3"},
+       {"IIR1 INP2 MUX", "RX4", "RX_RX4"},
+       {"IIR1 INP2 MUX", "RX5", "RX_RX5"},
+       {"IIR1", NULL, "IIR1 INP3 MUX"},
+       {"IIR1 INP3 MUX", "DEC0", "RX_TX DEC0_INP"},
+       {"IIR1 INP3 MUX", "DEC1", "RX_TX DEC1_INP"},
+       {"IIR1 INP3 MUX", "DEC2", "RX_TX DEC2_INP"},
+       {"IIR1 INP3 MUX", "DEC3", "RX_TX DEC3_INP"},
+       {"IIR1 INP3 MUX", "RX0", "RX_RX0"},
+       {"IIR1 INP3 MUX", "RX1", "RX_RX1"},
+       {"IIR1 INP3 MUX", "RX2", "RX_RX2"},
+       {"IIR1 INP3 MUX", "RX3", "RX_RX3"},
+       {"IIR1 INP3 MUX", "RX4", "RX_RX4"},
+       {"IIR1 INP3 MUX", "RX5", "RX_RX5"},
+
+       {"SRC0", NULL, "IIR0"},
+       {"SRC1", NULL, "IIR1"},
+       {"RX INT0 MIX2 INP", "SRC0", "SRC0"},
+       {"RX INT0 MIX2 INP", "SRC1", "SRC1"},
+       {"RX INT1 MIX2 INP", "SRC0", "SRC0"},
+       {"RX INT1 MIX2 INP", "SRC1", "SRC1"},
+       {"RX INT2 MIX2 INP", "SRC0", "SRC0"},
+       {"RX INT2 MIX2 INP", "SRC1", "SRC1"},
+};
+
+static int rx_macro_component_probe(struct snd_soc_component *component)
+{
+       struct rx_macro *rx = snd_soc_component_get_drvdata(component);
+
+       snd_soc_component_init_regmap(component, rx->regmap);
+
+       snd_soc_component_update_bits(component, CDC_RX_RX0_RX_PATH_SEC7,
+                                     CDC_RX_DSM_OUT_DELAY_SEL_MASK,
+                                     CDC_RX_DSM_OUT_DELAY_TWO_SAMPLE);
+       snd_soc_component_update_bits(component, CDC_RX_RX1_RX_PATH_SEC7,
+                                     CDC_RX_DSM_OUT_DELAY_SEL_MASK,
+                                     CDC_RX_DSM_OUT_DELAY_TWO_SAMPLE);
+       snd_soc_component_update_bits(component, CDC_RX_RX2_RX_PATH_SEC7,
+                                     CDC_RX_DSM_OUT_DELAY_SEL_MASK,
+                                     CDC_RX_DSM_OUT_DELAY_TWO_SAMPLE);
+       snd_soc_component_update_bits(component, CDC_RX_RX0_RX_PATH_CFG3,
+                                     CDC_RX_DC_COEFF_SEL_MASK,
+                                     CDC_RX_DC_COEFF_SEL_TWO);
+       snd_soc_component_update_bits(component, CDC_RX_RX1_RX_PATH_CFG3,
+                                     CDC_RX_DC_COEFF_SEL_MASK,
+                                     CDC_RX_DC_COEFF_SEL_TWO);
+       snd_soc_component_update_bits(component, CDC_RX_RX2_RX_PATH_CFG3,
+                                     CDC_RX_DC_COEFF_SEL_MASK,
+                                     CDC_RX_DC_COEFF_SEL_TWO);
+
+       rx->component = component;
+
+       return 0;
+}
+
+static int swclk_gate_enable(struct clk_hw *hw)
+{
+       struct rx_macro *rx = to_rx_macro(hw);
+
+       rx_macro_mclk_enable(rx, true);
+       if (rx->reset_swr)
+               regmap_update_bits(rx->regmap, CDC_RX_CLK_RST_CTRL_SWR_CONTROL,
+                                  CDC_RX_SWR_RESET_MASK,
+                                  CDC_RX_SWR_RESET);
+
+       regmap_update_bits(rx->regmap, CDC_RX_CLK_RST_CTRL_SWR_CONTROL,
+                          CDC_RX_SWR_CLK_EN_MASK, 1);
+
+       if (rx->reset_swr)
+               regmap_update_bits(rx->regmap, CDC_RX_CLK_RST_CTRL_SWR_CONTROL,
+                                  CDC_RX_SWR_RESET_MASK, 0);
+       rx->reset_swr = false;
+
+       return 0;
+}
+
+static void swclk_gate_disable(struct clk_hw *hw)
+{
+       struct rx_macro *rx = to_rx_macro(hw);
+
+       regmap_update_bits(rx->regmap, CDC_RX_CLK_RST_CTRL_SWR_CONTROL, 
+                          CDC_RX_SWR_CLK_EN_MASK, 0);
+
+       rx_macro_mclk_enable(rx, false);
+}
+
+static int swclk_gate_is_enabled(struct clk_hw *hw)
+{
+       struct rx_macro *rx = to_rx_macro(hw);
+       int ret, val;
+
+       regmap_read(rx->regmap, CDC_RX_CLK_RST_CTRL_SWR_CONTROL, &val);
+       ret = val & BIT(0);
+
+       return ret;
+}
+
+static unsigned long swclk_recalc_rate(struct clk_hw *hw,
+                                      unsigned long parent_rate)
+{
+       return parent_rate / 2;
+}
+
+static const struct clk_ops swclk_gate_ops = {
+       .prepare = swclk_gate_enable,
+       .unprepare = swclk_gate_disable,
+       .is_enabled = swclk_gate_is_enabled,
+       .recalc_rate = swclk_recalc_rate,
+
+};
+
+static struct clk *rx_macro_register_mclk_output(struct rx_macro *rx)
+{
+       struct device *dev = rx->dev;
+       struct device_node *np = dev->of_node;
+       const char *parent_clk_name = NULL;
+       const char *clk_name = "lpass-rx-mclk";
+       struct clk_hw *hw;
+       struct clk_init_data init;
+       int ret;
+
+       parent_clk_name = __clk_get_name(rx->clks[2].clk);
+
+       init.name = clk_name;
+       init.ops = &swclk_gate_ops;
+       init.flags = 0;
+       init.parent_names = &parent_clk_name;
+       init.num_parents = 1;
+       rx->hw.init = &init;
+       hw = &rx->hw;
+       ret = clk_hw_register(rx->dev, hw);
+       if (ret)
+               return ERR_PTR(ret);
+
+       of_clk_add_provider(np, of_clk_src_simple_get, hw->clk);
+
+       return NULL;
+}
+
+static const struct snd_soc_component_driver rx_macro_component_drv = {
+       .name = "RX-MACRO",
+       .probe = rx_macro_component_probe,
+       .controls = rx_macro_snd_controls,
+       .num_controls = ARRAY_SIZE(rx_macro_snd_controls),
+       .dapm_widgets = rx_macro_dapm_widgets,
+       .num_dapm_widgets = ARRAY_SIZE(rx_macro_dapm_widgets),
+       .dapm_routes = rx_audio_map,
+       .num_dapm_routes = ARRAY_SIZE(rx_audio_map),
+};
+
+static int rx_macro_probe(struct platform_device *pdev)
+{
+       struct device *dev = &pdev->dev;
+       struct rx_macro *rx;
+       void __iomem *base;
+       int ret;
+
+       rx = devm_kzalloc(dev, sizeof(*rx), GFP_KERNEL);
+       if (!rx)
+               return -ENOMEM;
+
+       rx->clks[0].id = "macro";
+       rx->clks[1].id = "dcodec";
+       rx->clks[2].id = "mclk";
+       rx->clks[3].id = "npl";
+       rx->clks[4].id = "fsgen";
+
+       ret = devm_clk_bulk_get(dev, RX_NUM_CLKS_MAX, rx->clks);
+       if (ret) {
+               dev_err(dev, "Error getting RX Clocks (%d)\n", ret);
+               return ret;
+       }
+
+       base = devm_platform_ioremap_resource(pdev, 0);
+       if (IS_ERR(base))
+               return PTR_ERR(base);
+
+       rx->regmap = devm_regmap_init_mmio(dev, base, &rx_regmap_config);
+
+       dev_set_drvdata(dev, rx);
+
+       rx->reset_swr = true;
+       rx->dev = dev;
+
+       /* set MCLK and NPL rates */
+       clk_set_rate(rx->clks[2].clk, MCLK_FREQ);
+       clk_set_rate(rx->clks[3].clk, MCLK_FREQ);
+
+       ret = clk_bulk_prepare_enable(RX_NUM_CLKS_MAX, rx->clks);
+       if (ret)
+               return ret;
+
+       rx_macro_register_mclk_output(rx);
+
+       ret = devm_snd_soc_register_component(dev, &rx_macro_component_drv,
+                                             rx_macro_dai,
+                                             ARRAY_SIZE(rx_macro_dai));
+       if (ret)
+               clk_bulk_disable_unprepare(RX_NUM_CLKS_MAX, rx->clks);
+
+       return ret;
+}
+
+static int rx_macro_remove(struct platform_device *pdev)
+{
+       struct rx_macro *rx = dev_get_drvdata(&pdev->dev);
+
+       of_clk_del_provider(pdev->dev.of_node);
+       clk_bulk_disable_unprepare(RX_NUM_CLKS_MAX, rx->clks);
+       return 0;
+}
+
+static const struct of_device_id rx_macro_dt_match[] = {
+       { .compatible = "qcom,sm8250-lpass-rx-macro" },
+       { }
+};
+
+static struct platform_driver rx_macro_driver = {
+       .driver = {
+               .name = "rx_macro",
+               .owner = THIS_MODULE,
+               .of_match_table = rx_macro_dt_match,
+               .suppress_bind_attrs = true,
+       },
+       .probe = rx_macro_probe,
+       .remove = rx_macro_remove,
+};
+
+module_platform_driver(rx_macro_driver);
+
+MODULE_DESCRIPTION("RX macro driver");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/lpass-tx-macro.c b/sound/soc/codecs/lpass-tx-macro.c
new file mode 100644 (file)
index 0000000..36d7a64
--- /dev/null
@@ -0,0 +1,1862 @@
+// SPDX-License-Identifier: GPL-2.0-only
+// Copyright (c) 2018-2020, The Linux Foundation. All rights reserved.
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/clk.h>
+#include <linux/io.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include <sound/tlv.h>
+#include <linux/of_clk.h>
+#include <linux/clk-provider.h>
+
+#define CDC_TX_CLK_RST_CTRL_MCLK_CONTROL (0x0000)
+#define CDC_TX_MCLK_EN_MASK            BIT(0)
+#define CDC_TX_MCLK_ENABLE             BIT(0)
+#define CDC_TX_CLK_RST_CTRL_FS_CNT_CONTROL (0x0004)
+#define CDC_TX_FS_CNT_EN_MASK          BIT(0)
+#define CDC_TX_FS_CNT_ENABLE           BIT(0)
+#define CDC_TX_CLK_RST_CTRL_SWR_CONTROL        (0x0008)
+#define CDC_TX_SWR_RESET_MASK          BIT(1)
+#define CDC_TX_SWR_RESET_ENABLE                BIT(1)
+#define CDC_TX_SWR_CLK_EN_MASK         BIT(0)
+#define CDC_TX_SWR_CLK_ENABLE          BIT(0)
+#define CDC_TX_TOP_CSR_TOP_CFG0                (0x0080)
+#define CDC_TX_TOP_CSR_ANC_CFG         (0x0084)
+#define CDC_TX_TOP_CSR_SWR_CTRL                (0x0088)
+#define CDC_TX_TOP_CSR_FREQ_MCLK       (0x0090)
+#define CDC_TX_TOP_CSR_DEBUG_BUS       (0x0094)
+#define CDC_TX_TOP_CSR_DEBUG_EN                (0x0098)
+#define CDC_TX_TOP_CSR_TX_I2S_CTL      (0x00A4)
+#define CDC_TX_TOP_CSR_I2S_CLK         (0x00A8)
+#define CDC_TX_TOP_CSR_I2S_RESET       (0x00AC)
+#define CDC_TX_TOP_CSR_SWR_DMICn_CTL(n)        (0x00C0 + n * 0x4)
+#define CDC_TX_TOP_CSR_SWR_DMIC0_CTL   (0x00C0)
+#define CDC_TX_SWR_DMIC_CLK_SEL_MASK   GENMASK(3, 1)
+#define CDC_TX_TOP_CSR_SWR_DMIC1_CTL   (0x00C4)
+#define CDC_TX_TOP_CSR_SWR_DMIC2_CTL   (0x00C8)
+#define CDC_TX_TOP_CSR_SWR_DMIC3_CTL   (0x00CC)
+#define CDC_TX_TOP_CSR_SWR_AMIC0_CTL   (0x00D0)
+#define CDC_TX_TOP_CSR_SWR_AMIC1_CTL   (0x00D4)
+#define CDC_TX_INP_MUX_ADC_MUXn_CFG0(n)        (0x0100 + 0x8 * n)
+#define CDC_TX_MACRO_SWR_MIC_MUX_SEL_MASK GENMASK(3, 0)
+#define CDC_TX_INP_MUX_ADC_MUX0_CFG0   (0x0100)
+#define CDC_TX_INP_MUX_ADC_MUXn_CFG1(n)        (0x0104 + 0x8 * n)
+#define CDC_TX_INP_MUX_ADC_MUX0_CFG1   (0x0104)
+#define CDC_TX_INP_MUX_ADC_MUX1_CFG0   (0x0108)
+#define CDC_TX_INP_MUX_ADC_MUX1_CFG1   (0x010C)
+#define CDC_TX_INP_MUX_ADC_MUX2_CFG0   (0x0110)
+#define CDC_TX_INP_MUX_ADC_MUX2_CFG1   (0x0114)
+#define CDC_TX_INP_MUX_ADC_MUX3_CFG0   (0x0118)
+#define CDC_TX_INP_MUX_ADC_MUX3_CFG1   (0x011C)
+#define CDC_TX_INP_MUX_ADC_MUX4_CFG0   (0x0120)
+#define CDC_TX_INP_MUX_ADC_MUX4_CFG1   (0x0124)
+#define CDC_TX_INP_MUX_ADC_MUX5_CFG0   (0x0128)
+#define CDC_TX_INP_MUX_ADC_MUX5_CFG1   (0x012C)
+#define CDC_TX_INP_MUX_ADC_MUX6_CFG0   (0x0130)
+#define CDC_TX_INP_MUX_ADC_MUX6_CFG1   (0x0134)
+#define CDC_TX_INP_MUX_ADC_MUX7_CFG0   (0x0138)
+#define CDC_TX_INP_MUX_ADC_MUX7_CFG1   (0x013C)
+#define CDC_TX_ANC0_CLK_RESET_CTL      (0x0200)
+#define CDC_TX_ANC0_MODE_1_CTL         (0x0204)
+#define CDC_TX_ANC0_MODE_2_CTL         (0x0208)
+#define CDC_TX_ANC0_FF_SHIFT           (0x020C)
+#define CDC_TX_ANC0_FB_SHIFT           (0x0210)
+#define CDC_TX_ANC0_LPF_FF_A_CTL       (0x0214)
+#define CDC_TX_ANC0_LPF_FF_B_CTL       (0x0218)
+#define CDC_TX_ANC0_LPF_FB_CTL         (0x021C)
+#define CDC_TX_ANC0_SMLPF_CTL          (0x0220)
+#define CDC_TX_ANC0_DCFLT_SHIFT_CTL    (0x0224)
+#define CDC_TX_ANC0_IIR_ADAPT_CTL      (0x0228)
+#define CDC_TX_ANC0_IIR_COEFF_1_CTL    (0x022C)
+#define CDC_TX_ANC0_IIR_COEFF_2_CTL    (0x0230)
+#define CDC_TX_ANC0_FF_A_GAIN_CTL      (0x0234)
+#define CDC_TX_ANC0_FF_B_GAIN_CTL      (0x0238)
+#define CDC_TX_ANC0_FB_GAIN_CTL                (0x023C)
+#define CDC_TXn_TX_PATH_CTL(n)         (0x0400 + 0x80 * n)
+#define CDC_TXn_PCM_RATE_MASK          GENMASK(3, 0)
+#define CDC_TXn_PGA_MUTE_MASK          BIT(4)
+#define CDC_TXn_CLK_EN_MASK            BIT(5)
+#define CDC_TX0_TX_PATH_CTL            (0x0400)
+#define CDC_TXn_TX_PATH_CFG0(n)                (0x0404 + 0x80 * n)
+#define CDC_TX0_TX_PATH_CFG0           (0x0404)
+#define CDC_TXn_PH_EN_MASK             BIT(0)
+#define CDC_TXn_ADC_MODE_MASK          GENMASK(2, 1)
+#define CDC_TXn_HPF_CUT_FREQ_MASK      GENMASK(6, 5)
+#define CDC_TXn_ADC_DMIC_SEL_MASK      BIT(7)
+#define CDC_TX0_TX_PATH_CFG1           (0x0408)
+#define CDC_TXn_TX_VOL_CTL(n)          (0x040C + 0x80 * n)
+#define CDC_TX0_TX_VOL_CTL             (0x040C)
+#define CDC_TX0_TX_PATH_SEC0           (0x0410)
+#define CDC_TX0_TX_PATH_SEC1           (0x0414)
+#define CDC_TXn_TX_PATH_SEC2(n)                (0x0418 + 0x80 * n)
+#define CDC_TXn_HPF_F_CHANGE_MASK       BIT(1)
+#define CDC_TXn_HPF_ZERO_GATE_MASK      BIT(0)
+#define CDC_TX0_TX_PATH_SEC2           (0x0418)
+#define CDC_TX0_TX_PATH_SEC3           (0x041C)
+#define CDC_TX0_TX_PATH_SEC4           (0x0420)
+#define CDC_TX0_TX_PATH_SEC5           (0x0424)
+#define CDC_TX0_TX_PATH_SEC6           (0x0428)
+#define CDC_TX0_TX_PATH_SEC7           (0x042C)
+#define CDC_TX0_MBHC_CTL_EN_MASK       BIT(6)
+#define CDC_TX1_TX_PATH_CTL            (0x0480)
+#define CDC_TX1_TX_PATH_CFG0           (0x0484)
+#define CDC_TX1_TX_PATH_CFG1           (0x0488)
+#define CDC_TX1_TX_VOL_CTL             (0x048C)
+#define CDC_TX1_TX_PATH_SEC0           (0x0490)
+#define CDC_TX1_TX_PATH_SEC1           (0x0494)
+#define CDC_TX1_TX_PATH_SEC2           (0x0498)
+#define CDC_TX1_TX_PATH_SEC3           (0x049C)
+#define CDC_TX1_TX_PATH_SEC4           (0x04A0)
+#define CDC_TX1_TX_PATH_SEC5           (0x04A4)
+#define CDC_TX1_TX_PATH_SEC6           (0x04A8)
+#define CDC_TX2_TX_PATH_CTL            (0x0500)
+#define CDC_TX2_TX_PATH_CFG0           (0x0504)
+#define CDC_TX2_TX_PATH_CFG1           (0x0508)
+#define CDC_TX2_TX_VOL_CTL             (0x050C)
+#define CDC_TX2_TX_PATH_SEC0           (0x0510)
+#define CDC_TX2_TX_PATH_SEC1           (0x0514)
+#define CDC_TX2_TX_PATH_SEC2           (0x0518)
+#define CDC_TX2_TX_PATH_SEC3           (0x051C)
+#define CDC_TX2_TX_PATH_SEC4           (0x0520)
+#define CDC_TX2_TX_PATH_SEC5           (0x0524)
+#define CDC_TX2_TX_PATH_SEC6           (0x0528)
+#define CDC_TX3_TX_PATH_CTL            (0x0580)
+#define CDC_TX3_TX_PATH_CFG0           (0x0584)
+#define CDC_TX3_TX_PATH_CFG1           (0x0588)
+#define CDC_TX3_TX_VOL_CTL             (0x058C)
+#define CDC_TX3_TX_PATH_SEC0           (0x0590)
+#define CDC_TX3_TX_PATH_SEC1           (0x0594)
+#define CDC_TX3_TX_PATH_SEC2           (0x0598)
+#define CDC_TX3_TX_PATH_SEC3           (0x059C)
+#define CDC_TX3_TX_PATH_SEC4           (0x05A0)
+#define CDC_TX3_TX_PATH_SEC5           (0x05A4)
+#define CDC_TX3_TX_PATH_SEC6           (0x05A8)
+#define CDC_TX4_TX_PATH_CTL            (0x0600)
+#define CDC_TX4_TX_PATH_CFG0           (0x0604)
+#define CDC_TX4_TX_PATH_CFG1           (0x0608)
+#define CDC_TX4_TX_VOL_CTL             (0x060C)
+#define CDC_TX4_TX_PATH_SEC0           (0x0610)
+#define CDC_TX4_TX_PATH_SEC1           (0x0614)
+#define CDC_TX4_TX_PATH_SEC2           (0x0618)
+#define CDC_TX4_TX_PATH_SEC3           (0x061C)
+#define CDC_TX4_TX_PATH_SEC4           (0x0620)
+#define CDC_TX4_TX_PATH_SEC5           (0x0624)
+#define CDC_TX4_TX_PATH_SEC6           (0x0628)
+#define CDC_TX5_TX_PATH_CTL            (0x0680)
+#define CDC_TX5_TX_PATH_CFG0           (0x0684)
+#define CDC_TX5_TX_PATH_CFG1           (0x0688)
+#define CDC_TX5_TX_VOL_CTL             (0x068C)
+#define CDC_TX5_TX_PATH_SEC0           (0x0690)
+#define CDC_TX5_TX_PATH_SEC1           (0x0694)
+#define CDC_TX5_TX_PATH_SEC2           (0x0698)
+#define CDC_TX5_TX_PATH_SEC3           (0x069C)
+#define CDC_TX5_TX_PATH_SEC4           (0x06A0)
+#define CDC_TX5_TX_PATH_SEC5           (0x06A4)
+#define CDC_TX5_TX_PATH_SEC6           (0x06A8)
+#define CDC_TX6_TX_PATH_CTL            (0x0700)
+#define CDC_TX6_TX_PATH_CFG0           (0x0704)
+#define CDC_TX6_TX_PATH_CFG1           (0x0708)
+#define CDC_TX6_TX_VOL_CTL             (0x070C)
+#define CDC_TX6_TX_PATH_SEC0           (0x0710)
+#define CDC_TX6_TX_PATH_SEC1           (0x0714)
+#define CDC_TX6_TX_PATH_SEC2           (0x0718)
+#define CDC_TX6_TX_PATH_SEC3           (0x071C)
+#define CDC_TX6_TX_PATH_SEC4           (0x0720)
+#define CDC_TX6_TX_PATH_SEC5           (0x0724)
+#define CDC_TX6_TX_PATH_SEC6           (0x0728)
+#define CDC_TX7_TX_PATH_CTL            (0x0780)
+#define CDC_TX7_TX_PATH_CFG0           (0x0784)
+#define CDC_TX7_TX_PATH_CFG1           (0x0788)
+#define CDC_TX7_TX_VOL_CTL             (0x078C)
+#define CDC_TX7_TX_PATH_SEC0           (0x0790)
+#define CDC_TX7_TX_PATH_SEC1           (0x0794)
+#define CDC_TX7_TX_PATH_SEC2           (0x0798)
+#define CDC_TX7_TX_PATH_SEC3           (0x079C)
+#define CDC_TX7_TX_PATH_SEC4           (0x07A0)
+#define CDC_TX7_TX_PATH_SEC5           (0x07A4)
+#define CDC_TX7_TX_PATH_SEC6           (0x07A8)
+#define TX_MAX_OFFSET                  (0x07A8)
+
+#define TX_MACRO_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |\
+                       SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000 |\
+                       SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_192000)
+#define TX_MACRO_FORMATS (SNDRV_PCM_FMTBIT_S16_LE |\
+                       SNDRV_PCM_FMTBIT_S24_LE |\
+                       SNDRV_PCM_FMTBIT_S24_3LE)
+
+#define  CF_MIN_3DB_4HZ                        0x0
+#define  CF_MIN_3DB_75HZ               0x1
+#define  CF_MIN_3DB_150HZ              0x2
+#define        TX_ADC_MAX      5
+#define TX_ADC_TO_DMIC(n) ((n - TX_ADC_MAX)/2)
+#define NUM_DECIMATORS 8
+#define TX_NUM_CLKS_MAX        5
+#define TX_MACRO_DMIC_UNMUTE_DELAY_MS  40
+#define TX_MACRO_AMIC_UNMUTE_DELAY_MS  100
+#define TX_MACRO_DMIC_HPF_DELAY_MS     300
+#define TX_MACRO_AMIC_HPF_DELAY_MS     300
+#define MCLK_FREQ              9600000
+
+enum {
+       TX_MACRO_AIF_INVALID = 0,
+       TX_MACRO_AIF1_CAP,
+       TX_MACRO_AIF2_CAP,
+       TX_MACRO_AIF3_CAP,
+       TX_MACRO_MAX_DAIS
+};
+
+enum {
+       TX_MACRO_DEC0,
+       TX_MACRO_DEC1,
+       TX_MACRO_DEC2,
+       TX_MACRO_DEC3,
+       TX_MACRO_DEC4,
+       TX_MACRO_DEC5,
+       TX_MACRO_DEC6,
+       TX_MACRO_DEC7,
+       TX_MACRO_DEC_MAX,
+};
+
+enum {
+       TX_MACRO_CLK_DIV_2,
+       TX_MACRO_CLK_DIV_3,
+       TX_MACRO_CLK_DIV_4,
+       TX_MACRO_CLK_DIV_6,
+       TX_MACRO_CLK_DIV_8,
+       TX_MACRO_CLK_DIV_16,
+};
+
+enum {
+       MSM_DMIC,
+       SWR_MIC,
+       ANC_FB_TUNE1
+};
+
+struct tx_mute_work {
+       struct tx_macro *tx;
+       u32 decimator;
+       struct delayed_work dwork;
+};
+
+struct hpf_work {
+       struct tx_macro *tx;
+       u8 decimator;
+       u8 hpf_cut_off_freq;
+       struct delayed_work dwork;
+};
+
+struct tx_macro {
+       struct device *dev;
+       struct snd_soc_component *component;
+       struct hpf_work tx_hpf_work[NUM_DECIMATORS];
+       struct tx_mute_work tx_mute_dwork[NUM_DECIMATORS];
+       unsigned long active_ch_mask[TX_MACRO_MAX_DAIS];
+       unsigned long active_ch_cnt[TX_MACRO_MAX_DAIS];
+       unsigned long active_decimator[TX_MACRO_MAX_DAIS];
+       struct regmap *regmap;
+       struct clk_bulk_data clks[TX_NUM_CLKS_MAX];
+       struct clk_hw hw;
+       bool dec_active[NUM_DECIMATORS];
+       bool reset_swr;
+       int tx_mclk_users;
+       u16 dmic_clk_div;
+       bool bcs_enable;
+       int dec_mode[NUM_DECIMATORS];
+       bool bcs_clk_en;
+};
+#define to_tx_macro(_hw) container_of(_hw, struct tx_macro, hw)
+
+static const DECLARE_TLV_DB_SCALE(digital_gain, -8400, 100, -8400);
+
+static const struct reg_default tx_defaults[] = {
+       /* TX Macro */
+       { CDC_TX_CLK_RST_CTRL_MCLK_CONTROL, 0x00 },
+       { CDC_TX_CLK_RST_CTRL_FS_CNT_CONTROL, 0x00 },
+       { CDC_TX_CLK_RST_CTRL_SWR_CONTROL, 0x00},
+       { CDC_TX_TOP_CSR_TOP_CFG0, 0x00},
+       { CDC_TX_TOP_CSR_ANC_CFG, 0x00},
+       { CDC_TX_TOP_CSR_SWR_CTRL, 0x00},
+       { CDC_TX_TOP_CSR_FREQ_MCLK, 0x00},
+       { CDC_TX_TOP_CSR_DEBUG_BUS, 0x00},
+       { CDC_TX_TOP_CSR_DEBUG_EN, 0x00},
+       { CDC_TX_TOP_CSR_TX_I2S_CTL, 0x0C},
+       { CDC_TX_TOP_CSR_I2S_CLK, 0x00},
+       { CDC_TX_TOP_CSR_I2S_RESET, 0x00},
+       { CDC_TX_TOP_CSR_SWR_DMIC0_CTL, 0x00},
+       { CDC_TX_TOP_CSR_SWR_DMIC1_CTL, 0x00},
+       { CDC_TX_TOP_CSR_SWR_DMIC2_CTL, 0x00},
+       { CDC_TX_TOP_CSR_SWR_DMIC3_CTL, 0x00},
+       { CDC_TX_TOP_CSR_SWR_AMIC0_CTL, 0x00},
+       { CDC_TX_TOP_CSR_SWR_AMIC1_CTL, 0x00},
+       { CDC_TX_INP_MUX_ADC_MUX0_CFG0, 0x00},
+       { CDC_TX_INP_MUX_ADC_MUX0_CFG1, 0x00},
+       { CDC_TX_INP_MUX_ADC_MUX1_CFG0, 0x00},
+       { CDC_TX_INP_MUX_ADC_MUX1_CFG1, 0x00},
+       { CDC_TX_INP_MUX_ADC_MUX2_CFG0, 0x00},
+       { CDC_TX_INP_MUX_ADC_MUX2_CFG1, 0x00},
+       { CDC_TX_INP_MUX_ADC_MUX3_CFG0, 0x00},
+       { CDC_TX_INP_MUX_ADC_MUX3_CFG1, 0x00},
+       { CDC_TX_INP_MUX_ADC_MUX4_CFG0, 0x00},
+       { CDC_TX_INP_MUX_ADC_MUX4_CFG1, 0x00},
+       { CDC_TX_INP_MUX_ADC_MUX5_CFG0, 0x00},
+       { CDC_TX_INP_MUX_ADC_MUX5_CFG1, 0x00},
+       { CDC_TX_INP_MUX_ADC_MUX6_CFG0, 0x00},
+       { CDC_TX_INP_MUX_ADC_MUX6_CFG1, 0x00},
+       { CDC_TX_INP_MUX_ADC_MUX7_CFG0, 0x00},
+       { CDC_TX_INP_MUX_ADC_MUX7_CFG1, 0x00},
+       { CDC_TX_ANC0_CLK_RESET_CTL, 0x00},
+       { CDC_TX_ANC0_MODE_1_CTL, 0x00},
+       { CDC_TX_ANC0_MODE_2_CTL, 0x00},
+       { CDC_TX_ANC0_FF_SHIFT, 0x00},
+       { CDC_TX_ANC0_FB_SHIFT, 0x00},
+       { CDC_TX_ANC0_LPF_FF_A_CTL, 0x00},
+       { CDC_TX_ANC0_LPF_FF_B_CTL, 0x00},
+       { CDC_TX_ANC0_LPF_FB_CTL, 0x00},
+       { CDC_TX_ANC0_SMLPF_CTL, 0x00},
+       { CDC_TX_ANC0_DCFLT_SHIFT_CTL, 0x00},
+       { CDC_TX_ANC0_IIR_ADAPT_CTL, 0x00},
+       { CDC_TX_ANC0_IIR_COEFF_1_CTL, 0x00},
+       { CDC_TX_ANC0_IIR_COEFF_2_CTL, 0x00},
+       { CDC_TX_ANC0_FF_A_GAIN_CTL, 0x00},
+       { CDC_TX_ANC0_FF_B_GAIN_CTL, 0x00},
+       { CDC_TX_ANC0_FB_GAIN_CTL, 0x00},
+       { CDC_TX0_TX_PATH_CTL, 0x04},
+       { CDC_TX0_TX_PATH_CFG0, 0x10},
+       { CDC_TX0_TX_PATH_CFG1, 0x0B},
+       { CDC_TX0_TX_VOL_CTL, 0x00},
+       { CDC_TX0_TX_PATH_SEC0, 0x00},
+       { CDC_TX0_TX_PATH_SEC1, 0x00},
+       { CDC_TX0_TX_PATH_SEC2, 0x01},
+       { CDC_TX0_TX_PATH_SEC3, 0x3C},
+       { CDC_TX0_TX_PATH_SEC4, 0x20},
+       { CDC_TX0_TX_PATH_SEC5, 0x00},
+       { CDC_TX0_TX_PATH_SEC6, 0x00},
+       { CDC_TX0_TX_PATH_SEC7, 0x25},
+       { CDC_TX1_TX_PATH_CTL, 0x04},
+       { CDC_TX1_TX_PATH_CFG0, 0x10},
+       { CDC_TX1_TX_PATH_CFG1, 0x0B},
+       { CDC_TX1_TX_VOL_CTL, 0x00},
+       { CDC_TX1_TX_PATH_SEC0, 0x00},
+       { CDC_TX1_TX_PATH_SEC1, 0x00},
+       { CDC_TX1_TX_PATH_SEC2, 0x01},
+       { CDC_TX1_TX_PATH_SEC3, 0x3C},
+       { CDC_TX1_TX_PATH_SEC4, 0x20},
+       { CDC_TX1_TX_PATH_SEC5, 0x00},
+       { CDC_TX1_TX_PATH_SEC6, 0x00},
+       { CDC_TX2_TX_PATH_CTL, 0x04},
+       { CDC_TX2_TX_PATH_CFG0, 0x10},
+       { CDC_TX2_TX_PATH_CFG1, 0x0B},
+       { CDC_TX2_TX_VOL_CTL, 0x00},
+       { CDC_TX2_TX_PATH_SEC0, 0x00},
+       { CDC_TX2_TX_PATH_SEC1, 0x00},
+       { CDC_TX2_TX_PATH_SEC2, 0x01},
+       { CDC_TX2_TX_PATH_SEC3, 0x3C},
+       { CDC_TX2_TX_PATH_SEC4, 0x20},
+       { CDC_TX2_TX_PATH_SEC5, 0x00},
+       { CDC_TX2_TX_PATH_SEC6, 0x00},
+       { CDC_TX3_TX_PATH_CTL, 0x04},
+       { CDC_TX3_TX_PATH_CFG0, 0x10},
+       { CDC_TX3_TX_PATH_CFG1, 0x0B},
+       { CDC_TX3_TX_VOL_CTL, 0x00},
+       { CDC_TX3_TX_PATH_SEC0, 0x00},
+       { CDC_TX3_TX_PATH_SEC1, 0x00},
+       { CDC_TX3_TX_PATH_SEC2, 0x01},
+       { CDC_TX3_TX_PATH_SEC3, 0x3C},
+       { CDC_TX3_TX_PATH_SEC4, 0x20},
+       { CDC_TX3_TX_PATH_SEC5, 0x00},
+       { CDC_TX3_TX_PATH_SEC6, 0x00},
+       { CDC_TX4_TX_PATH_CTL, 0x04},
+       { CDC_TX4_TX_PATH_CFG0, 0x10},
+       { CDC_TX4_TX_PATH_CFG1, 0x0B},
+       { CDC_TX4_TX_VOL_CTL, 0x00},
+       { CDC_TX4_TX_PATH_SEC0, 0x00},
+       { CDC_TX4_TX_PATH_SEC1, 0x00},
+       { CDC_TX4_TX_PATH_SEC2, 0x01},
+       { CDC_TX4_TX_PATH_SEC3, 0x3C},
+       { CDC_TX4_TX_PATH_SEC4, 0x20},
+       { CDC_TX4_TX_PATH_SEC5, 0x00},
+       { CDC_TX4_TX_PATH_SEC6, 0x00},
+       { CDC_TX5_TX_PATH_CTL, 0x04},
+       { CDC_TX5_TX_PATH_CFG0, 0x10},
+       { CDC_TX5_TX_PATH_CFG1, 0x0B},
+       { CDC_TX5_TX_VOL_CTL, 0x00},
+       { CDC_TX5_TX_PATH_SEC0, 0x00},
+       { CDC_TX5_TX_PATH_SEC1, 0x00},
+       { CDC_TX5_TX_PATH_SEC2, 0x01},
+       { CDC_TX5_TX_PATH_SEC3, 0x3C},
+       { CDC_TX5_TX_PATH_SEC4, 0x20},
+       { CDC_TX5_TX_PATH_SEC5, 0x00},
+       { CDC_TX5_TX_PATH_SEC6, 0x00},
+       { CDC_TX6_TX_PATH_CTL, 0x04},
+       { CDC_TX6_TX_PATH_CFG0, 0x10},
+       { CDC_TX6_TX_PATH_CFG1, 0x0B},
+       { CDC_TX6_TX_VOL_CTL, 0x00},
+       { CDC_TX6_TX_PATH_SEC0, 0x00},
+       { CDC_TX6_TX_PATH_SEC1, 0x00},
+       { CDC_TX6_TX_PATH_SEC2, 0x01},
+       { CDC_TX6_TX_PATH_SEC3, 0x3C},
+       { CDC_TX6_TX_PATH_SEC4, 0x20},
+       { CDC_TX6_TX_PATH_SEC5, 0x00},
+       { CDC_TX6_TX_PATH_SEC6, 0x00},
+       { CDC_TX7_TX_PATH_CTL, 0x04},
+       { CDC_TX7_TX_PATH_CFG0, 0x10},
+       { CDC_TX7_TX_PATH_CFG1, 0x0B},
+       { CDC_TX7_TX_VOL_CTL, 0x00},
+       { CDC_TX7_TX_PATH_SEC0, 0x00},
+       { CDC_TX7_TX_PATH_SEC1, 0x00},
+       { CDC_TX7_TX_PATH_SEC2, 0x01},
+       { CDC_TX7_TX_PATH_SEC3, 0x3C},
+       { CDC_TX7_TX_PATH_SEC4, 0x20},
+       { CDC_TX7_TX_PATH_SEC5, 0x00},
+       { CDC_TX7_TX_PATH_SEC6, 0x00},
+};
+
+static bool tx_is_volatile_register(struct device *dev, unsigned int reg)
+{
+       /* Update volatile list for tx/tx macros */
+       switch (reg) {
+       case CDC_TX_TOP_CSR_SWR_DMIC0_CTL:
+       case CDC_TX_TOP_CSR_SWR_DMIC1_CTL:
+       case CDC_TX_TOP_CSR_SWR_DMIC2_CTL:
+       case CDC_TX_TOP_CSR_SWR_DMIC3_CTL:
+               return true;
+       }
+       return false;
+}
+
+static bool tx_is_rw_register(struct device *dev, unsigned int reg)
+{
+       switch (reg) {
+       case CDC_TX_CLK_RST_CTRL_MCLK_CONTROL:
+       case CDC_TX_CLK_RST_CTRL_FS_CNT_CONTROL:
+       case CDC_TX_CLK_RST_CTRL_SWR_CONTROL:
+       case CDC_TX_TOP_CSR_TOP_CFG0:
+       case CDC_TX_TOP_CSR_ANC_CFG:
+       case CDC_TX_TOP_CSR_SWR_CTRL:
+       case CDC_TX_TOP_CSR_FREQ_MCLK:
+       case CDC_TX_TOP_CSR_DEBUG_BUS:
+       case CDC_TX_TOP_CSR_DEBUG_EN:
+       case CDC_TX_TOP_CSR_TX_I2S_CTL:
+       case CDC_TX_TOP_CSR_I2S_CLK:
+       case CDC_TX_TOP_CSR_I2S_RESET:
+       case CDC_TX_TOP_CSR_SWR_DMIC0_CTL:
+       case CDC_TX_TOP_CSR_SWR_DMIC1_CTL:
+       case CDC_TX_TOP_CSR_SWR_DMIC2_CTL:
+       case CDC_TX_TOP_CSR_SWR_DMIC3_CTL:
+       case CDC_TX_TOP_CSR_SWR_AMIC0_CTL:
+       case CDC_TX_TOP_CSR_SWR_AMIC1_CTL:
+       case CDC_TX_ANC0_CLK_RESET_CTL:
+       case CDC_TX_ANC0_MODE_1_CTL:
+       case CDC_TX_ANC0_MODE_2_CTL:
+       case CDC_TX_ANC0_FF_SHIFT:
+       case CDC_TX_ANC0_FB_SHIFT:
+       case CDC_TX_ANC0_LPF_FF_A_CTL:
+       case CDC_TX_ANC0_LPF_FF_B_CTL:
+       case CDC_TX_ANC0_LPF_FB_CTL:
+       case CDC_TX_ANC0_SMLPF_CTL:
+       case CDC_TX_ANC0_DCFLT_SHIFT_CTL:
+       case CDC_TX_ANC0_IIR_ADAPT_CTL:
+       case CDC_TX_ANC0_IIR_COEFF_1_CTL:
+       case CDC_TX_ANC0_IIR_COEFF_2_CTL:
+       case CDC_TX_ANC0_FF_A_GAIN_CTL:
+       case CDC_TX_ANC0_FF_B_GAIN_CTL:
+       case CDC_TX_ANC0_FB_GAIN_CTL:
+       case CDC_TX_INP_MUX_ADC_MUX0_CFG0:
+       case CDC_TX_INP_MUX_ADC_MUX0_CFG1:
+       case CDC_TX_INP_MUX_ADC_MUX1_CFG0:
+       case CDC_TX_INP_MUX_ADC_MUX1_CFG1:
+       case CDC_TX_INP_MUX_ADC_MUX2_CFG0:
+       case CDC_TX_INP_MUX_ADC_MUX2_CFG1:
+       case CDC_TX_INP_MUX_ADC_MUX3_CFG0:
+       case CDC_TX_INP_MUX_ADC_MUX3_CFG1:
+       case CDC_TX_INP_MUX_ADC_MUX4_CFG0:
+       case CDC_TX_INP_MUX_ADC_MUX4_CFG1:
+       case CDC_TX_INP_MUX_ADC_MUX5_CFG0:
+       case CDC_TX_INP_MUX_ADC_MUX5_CFG1:
+       case CDC_TX_INP_MUX_ADC_MUX6_CFG0:
+       case CDC_TX_INP_MUX_ADC_MUX6_CFG1:
+       case CDC_TX_INP_MUX_ADC_MUX7_CFG0:
+       case CDC_TX_INP_MUX_ADC_MUX7_CFG1:
+       case CDC_TX0_TX_PATH_CTL:
+       case CDC_TX0_TX_PATH_CFG0:
+       case CDC_TX0_TX_PATH_CFG1:
+       case CDC_TX0_TX_VOL_CTL:
+       case CDC_TX0_TX_PATH_SEC0:
+       case CDC_TX0_TX_PATH_SEC1:
+       case CDC_TX0_TX_PATH_SEC2:
+       case CDC_TX0_TX_PATH_SEC3:
+       case CDC_TX0_TX_PATH_SEC4:
+       case CDC_TX0_TX_PATH_SEC5:
+       case CDC_TX0_TX_PATH_SEC6:
+       case CDC_TX0_TX_PATH_SEC7:
+       case CDC_TX1_TX_PATH_CTL:
+       case CDC_TX1_TX_PATH_CFG0:
+       case CDC_TX1_TX_PATH_CFG1:
+       case CDC_TX1_TX_VOL_CTL:
+       case CDC_TX1_TX_PATH_SEC0:
+       case CDC_TX1_TX_PATH_SEC1:
+       case CDC_TX1_TX_PATH_SEC2:
+       case CDC_TX1_TX_PATH_SEC3:
+       case CDC_TX1_TX_PATH_SEC4:
+       case CDC_TX1_TX_PATH_SEC5:
+       case CDC_TX1_TX_PATH_SEC6:
+       case CDC_TX2_TX_PATH_CTL:
+       case CDC_TX2_TX_PATH_CFG0:
+       case CDC_TX2_TX_PATH_CFG1:
+       case CDC_TX2_TX_VOL_CTL:
+       case CDC_TX2_TX_PATH_SEC0:
+       case CDC_TX2_TX_PATH_SEC1:
+       case CDC_TX2_TX_PATH_SEC2:
+       case CDC_TX2_TX_PATH_SEC3:
+       case CDC_TX2_TX_PATH_SEC4:
+       case CDC_TX2_TX_PATH_SEC5:
+       case CDC_TX2_TX_PATH_SEC6:
+       case CDC_TX3_TX_PATH_CTL:
+       case CDC_TX3_TX_PATH_CFG0:
+       case CDC_TX3_TX_PATH_CFG1:
+       case CDC_TX3_TX_VOL_CTL:
+       case CDC_TX3_TX_PATH_SEC0:
+       case CDC_TX3_TX_PATH_SEC1:
+       case CDC_TX3_TX_PATH_SEC2:
+       case CDC_TX3_TX_PATH_SEC3:
+       case CDC_TX3_TX_PATH_SEC4:
+       case CDC_TX3_TX_PATH_SEC5:
+       case CDC_TX3_TX_PATH_SEC6:
+       case CDC_TX4_TX_PATH_CTL:
+       case CDC_TX4_TX_PATH_CFG0:
+       case CDC_TX4_TX_PATH_CFG1:
+       case CDC_TX4_TX_VOL_CTL:
+       case CDC_TX4_TX_PATH_SEC0:
+       case CDC_TX4_TX_PATH_SEC1:
+       case CDC_TX4_TX_PATH_SEC2:
+       case CDC_TX4_TX_PATH_SEC3:
+       case CDC_TX4_TX_PATH_SEC4:
+       case CDC_TX4_TX_PATH_SEC5:
+       case CDC_TX4_TX_PATH_SEC6:
+       case CDC_TX5_TX_PATH_CTL:
+       case CDC_TX5_TX_PATH_CFG0:
+       case CDC_TX5_TX_PATH_CFG1:
+       case CDC_TX5_TX_VOL_CTL:
+       case CDC_TX5_TX_PATH_SEC0:
+       case CDC_TX5_TX_PATH_SEC1:
+       case CDC_TX5_TX_PATH_SEC2:
+       case CDC_TX5_TX_PATH_SEC3:
+       case CDC_TX5_TX_PATH_SEC4:
+       case CDC_TX5_TX_PATH_SEC5:
+       case CDC_TX5_TX_PATH_SEC6:
+       case CDC_TX6_TX_PATH_CTL:
+       case CDC_TX6_TX_PATH_CFG0:
+       case CDC_TX6_TX_PATH_CFG1:
+       case CDC_TX6_TX_VOL_CTL:
+       case CDC_TX6_TX_PATH_SEC0:
+       case CDC_TX6_TX_PATH_SEC1:
+       case CDC_TX6_TX_PATH_SEC2:
+       case CDC_TX6_TX_PATH_SEC3:
+       case CDC_TX6_TX_PATH_SEC4:
+       case CDC_TX6_TX_PATH_SEC5:
+       case CDC_TX6_TX_PATH_SEC6:
+       case CDC_TX7_TX_PATH_CTL:
+       case CDC_TX7_TX_PATH_CFG0:
+       case CDC_TX7_TX_PATH_CFG1:
+       case CDC_TX7_TX_VOL_CTL:
+       case CDC_TX7_TX_PATH_SEC0:
+       case CDC_TX7_TX_PATH_SEC1:
+       case CDC_TX7_TX_PATH_SEC2:
+       case CDC_TX7_TX_PATH_SEC3:
+       case CDC_TX7_TX_PATH_SEC4:
+       case CDC_TX7_TX_PATH_SEC5:
+       case CDC_TX7_TX_PATH_SEC6:
+               return true;
+       }
+
+       return false;
+}
+
+static const struct regmap_config tx_regmap_config = {
+       .name = "tx_macro",
+       .reg_bits = 16,
+       .val_bits = 32,
+       .reg_stride = 4,
+       .cache_type = REGCACHE_FLAT,
+       .max_register = TX_MAX_OFFSET,
+       .reg_defaults = tx_defaults,
+       .num_reg_defaults = ARRAY_SIZE(tx_defaults),
+       .writeable_reg = tx_is_rw_register,
+       .volatile_reg = tx_is_volatile_register,
+       .readable_reg = tx_is_rw_register,
+};
+
+static int tx_macro_mclk_enable(struct tx_macro *tx,
+                               bool mclk_enable)
+{
+       struct regmap *regmap = tx->regmap;
+
+       if (mclk_enable) {
+               if (tx->tx_mclk_users == 0) {
+                       /* 9.6MHz MCLK, set value 0x00 if other frequency */
+                       regmap_update_bits(regmap, CDC_TX_TOP_CSR_FREQ_MCLK, 0x01, 0x01);
+                       regmap_update_bits(regmap, CDC_TX_CLK_RST_CTRL_MCLK_CONTROL,
+                                          CDC_TX_MCLK_EN_MASK,
+                                          CDC_TX_MCLK_ENABLE);
+                       regmap_update_bits(regmap, CDC_TX_CLK_RST_CTRL_FS_CNT_CONTROL,
+                                          CDC_TX_FS_CNT_EN_MASK,
+                                          CDC_TX_FS_CNT_ENABLE);
+                       regcache_mark_dirty(regmap);
+                       regcache_sync(regmap);
+               }
+               tx->tx_mclk_users++;
+       } else {
+               if (tx->tx_mclk_users <= 0) {
+                       dev_err(tx->dev, "clock already disabled\n");
+                       tx->tx_mclk_users = 0;
+                       goto exit;
+               }
+               tx->tx_mclk_users--;
+               if (tx->tx_mclk_users == 0) {
+                       regmap_update_bits(regmap, CDC_TX_CLK_RST_CTRL_FS_CNT_CONTROL,
+                                          CDC_TX_FS_CNT_EN_MASK, 0x0);
+                       regmap_update_bits(regmap, CDC_TX_CLK_RST_CTRL_MCLK_CONTROL,
+                                          CDC_TX_MCLK_EN_MASK, 0x0);
+               }
+       }
+exit:
+       return 0;
+}
+
+static bool is_amic_enabled(struct snd_soc_component *component, int decimator)
+{
+       u16 adc_mux_reg, adc_reg, adc_n;
+
+       adc_mux_reg = CDC_TX_INP_MUX_ADC_MUXn_CFG1(decimator);
+
+       if (snd_soc_component_read(component, adc_mux_reg) & SWR_MIC) {
+               adc_reg = CDC_TX_INP_MUX_ADC_MUXn_CFG0(decimator);
+               adc_n = snd_soc_component_read_field(component, adc_reg,
+                                            CDC_TX_MACRO_SWR_MIC_MUX_SEL_MASK);
+               if (adc_n < TX_ADC_MAX)
+                       return true;
+       }
+
+       return false;
+}
+
+static void tx_macro_tx_hpf_corner_freq_callback(struct work_struct *work)
+{
+       struct delayed_work *hpf_delayed_work;
+       struct hpf_work *hpf_work;
+       struct tx_macro *tx;
+       struct snd_soc_component *component;
+       u16 dec_cfg_reg, hpf_gate_reg;
+       u8 hpf_cut_off_freq;
+
+       hpf_delayed_work = to_delayed_work(work);
+       hpf_work = container_of(hpf_delayed_work, struct hpf_work, dwork);
+       tx = hpf_work->tx;
+       component = tx->component;
+       hpf_cut_off_freq = hpf_work->hpf_cut_off_freq;
+
+       dec_cfg_reg = CDC_TXn_TX_PATH_CFG0(hpf_work->decimator);
+       hpf_gate_reg = CDC_TXn_TX_PATH_SEC2(hpf_work->decimator);
+
+       if (is_amic_enabled(component, hpf_work->decimator)) {
+               snd_soc_component_write_field(component,
+                               dec_cfg_reg,
+                               CDC_TXn_HPF_CUT_FREQ_MASK,
+                               hpf_cut_off_freq);
+               snd_soc_component_update_bits(component, hpf_gate_reg,
+                                             CDC_TXn_HPF_F_CHANGE_MASK |
+                                             CDC_TXn_HPF_ZERO_GATE_MASK,
+                                             0x02);
+               snd_soc_component_update_bits(component, hpf_gate_reg,
+                                             CDC_TXn_HPF_F_CHANGE_MASK |
+                                             CDC_TXn_HPF_ZERO_GATE_MASK,
+                                             0x01);
+       } else {
+               snd_soc_component_write_field(component, dec_cfg_reg,
+                                             CDC_TXn_HPF_CUT_FREQ_MASK,
+                                             hpf_cut_off_freq);
+               snd_soc_component_write_field(component, hpf_gate_reg,
+                                             CDC_TXn_HPF_F_CHANGE_MASK, 0x1);
+               /* Minimum 1 clk cycle delay is required as per HW spec */
+               usleep_range(1000, 1010);
+               snd_soc_component_write_field(component, hpf_gate_reg,
+                                             CDC_TXn_HPF_F_CHANGE_MASK, 0x0);
+       }
+}
+
+static void tx_macro_mute_update_callback(struct work_struct *work)
+{
+       struct tx_mute_work *tx_mute_dwork;
+       struct snd_soc_component *component;
+       struct tx_macro *tx;
+       struct delayed_work *delayed_work;
+       u8 decimator;
+
+       delayed_work = to_delayed_work(work);
+       tx_mute_dwork = container_of(delayed_work, struct tx_mute_work, dwork);
+       tx = tx_mute_dwork->tx;
+       component = tx->component;
+       decimator = tx_mute_dwork->decimator;
+
+       snd_soc_component_write_field(component, CDC_TXn_TX_PATH_CTL(decimator),
+                                     CDC_TXn_PGA_MUTE_MASK, 0x0);
+}
+
+static int tx_macro_mclk_event(struct snd_soc_dapm_widget *w,
+                              struct snd_kcontrol *kcontrol, int event)
+{
+       struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+       struct tx_macro *tx = snd_soc_component_get_drvdata(component);
+
+       switch (event) {
+       case SND_SOC_DAPM_PRE_PMU:
+               tx_macro_mclk_enable(tx, true);
+               break;
+       case SND_SOC_DAPM_POST_PMD:
+               tx_macro_mclk_enable(tx, false);
+               break;
+       default:
+               break;
+       }
+
+       return 0;
+}
+
+static int tx_macro_put_dec_enum(struct snd_kcontrol *kcontrol,
+                                struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_dapm_widget *widget = snd_soc_dapm_kcontrol_widget(kcontrol);
+       struct snd_soc_component *component = snd_soc_dapm_to_component(widget->dapm);
+       struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
+       unsigned int val, dmic;
+       u16 mic_sel_reg;
+       u16 dmic_clk_reg;
+       struct tx_macro *tx = snd_soc_component_get_drvdata(component);
+
+       val = ucontrol->value.enumerated.item[0];
+
+       switch (e->reg) {
+       case CDC_TX_INP_MUX_ADC_MUX0_CFG0:
+               mic_sel_reg = CDC_TX0_TX_PATH_CFG0;
+               break;
+       case CDC_TX_INP_MUX_ADC_MUX1_CFG0:
+               mic_sel_reg = CDC_TX1_TX_PATH_CFG0;
+               break;
+       case CDC_TX_INP_MUX_ADC_MUX2_CFG0:
+               mic_sel_reg = CDC_TX2_TX_PATH_CFG0;
+               break;
+       case CDC_TX_INP_MUX_ADC_MUX3_CFG0:
+               mic_sel_reg = CDC_TX3_TX_PATH_CFG0;
+               break;
+       case CDC_TX_INP_MUX_ADC_MUX4_CFG0:
+               mic_sel_reg = CDC_TX4_TX_PATH_CFG0;
+               break;
+       case CDC_TX_INP_MUX_ADC_MUX5_CFG0:
+               mic_sel_reg = CDC_TX5_TX_PATH_CFG0;
+               break;
+       case CDC_TX_INP_MUX_ADC_MUX6_CFG0:
+               mic_sel_reg = CDC_TX6_TX_PATH_CFG0;
+               break;
+       case CDC_TX_INP_MUX_ADC_MUX7_CFG0:
+               mic_sel_reg = CDC_TX7_TX_PATH_CFG0;
+               break;
+       }
+
+       if (val != 0) {
+               if (val < 5) {
+                       snd_soc_component_write_field(component, mic_sel_reg,
+                                                     CDC_TXn_ADC_DMIC_SEL_MASK, 0);
+               } else {
+                       snd_soc_component_write_field(component, mic_sel_reg,
+                                                     CDC_TXn_ADC_DMIC_SEL_MASK, 1);
+                       dmic = TX_ADC_TO_DMIC(val);
+                       dmic_clk_reg = CDC_TX_TOP_CSR_SWR_DMICn_CTL(dmic);
+                       snd_soc_component_write_field(component, dmic_clk_reg,
+                                               CDC_TX_SWR_DMIC_CLK_SEL_MASK,
+                                               tx->dmic_clk_div);
+               }
+       }
+
+       return snd_soc_dapm_put_enum_double(kcontrol, ucontrol);
+}
+
+static int tx_macro_tx_mixer_get(struct snd_kcontrol *kcontrol,
+                                struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_dapm_widget *widget = snd_soc_dapm_kcontrol_widget(kcontrol);
+       struct snd_soc_component *component = snd_soc_dapm_to_component(widget->dapm);
+       struct soc_mixer_control *mc = (struct soc_mixer_control *)kcontrol->private_value;
+       u32 dai_id = widget->shift;
+       u32 dec_id = mc->shift;
+       struct tx_macro *tx = snd_soc_component_get_drvdata(component);
+
+       if (test_bit(dec_id, &tx->active_ch_mask[dai_id]))
+               ucontrol->value.integer.value[0] = 1;
+       else
+               ucontrol->value.integer.value[0] = 0;
+
+       return 0;
+}
+
+static int tx_macro_tx_mixer_put(struct snd_kcontrol *kcontrol,
+                                struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_dapm_widget *widget = snd_soc_dapm_kcontrol_widget(kcontrol);
+       struct snd_soc_component *component = snd_soc_dapm_to_component(widget->dapm);
+       struct snd_soc_dapm_update *update = NULL;
+       struct soc_mixer_control *mc = (struct soc_mixer_control *)kcontrol->private_value;
+       u32 dai_id = widget->shift;
+       u32 dec_id = mc->shift;
+       u32 enable = ucontrol->value.integer.value[0];
+       struct tx_macro *tx = snd_soc_component_get_drvdata(component);
+
+       if (enable) {
+               set_bit(dec_id, &tx->active_ch_mask[dai_id]);
+               tx->active_ch_cnt[dai_id]++;
+               tx->active_decimator[dai_id] = dec_id;
+       } else {
+               tx->active_ch_cnt[dai_id]--;
+               clear_bit(dec_id, &tx->active_ch_mask[dai_id]);
+               tx->active_decimator[dai_id] = -1;
+       }
+       snd_soc_dapm_mixer_update_power(widget->dapm, kcontrol, enable, update);
+
+       return 0;
+}
+
+static int tx_macro_enable_dec(struct snd_soc_dapm_widget *w,
+                              struct snd_kcontrol *kcontrol, int event)
+{
+       struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+       unsigned int decimator;
+       u16 tx_vol_ctl_reg, dec_cfg_reg, hpf_gate_reg, tx_gain_ctl_reg;
+       u8 hpf_cut_off_freq;
+       int hpf_delay = TX_MACRO_DMIC_HPF_DELAY_MS;
+       int unmute_delay = TX_MACRO_DMIC_UNMUTE_DELAY_MS;
+       u16 adc_mux_reg, adc_reg, adc_n, dmic;
+       u16 dmic_clk_reg;
+       struct tx_macro *tx = snd_soc_component_get_drvdata(component);
+
+       decimator = w->shift;
+       tx_vol_ctl_reg = CDC_TXn_TX_PATH_CTL(decimator);
+       hpf_gate_reg = CDC_TXn_TX_PATH_SEC2(decimator);
+       dec_cfg_reg = CDC_TXn_TX_PATH_CFG0(decimator);
+       tx_gain_ctl_reg = CDC_TXn_TX_VOL_CTL(decimator);
+
+       switch (event) {
+       case SND_SOC_DAPM_PRE_PMU:
+               adc_mux_reg = CDC_TX_INP_MUX_ADC_MUXn_CFG1(decimator);
+               if (snd_soc_component_read(component, adc_mux_reg) & SWR_MIC) {
+                       adc_reg = CDC_TX_INP_MUX_ADC_MUXn_CFG0(decimator);
+                       adc_n = snd_soc_component_read(component, adc_reg) &
+                               CDC_TX_MACRO_SWR_MIC_MUX_SEL_MASK;
+                       if (adc_n >= TX_ADC_MAX) {
+                               dmic = TX_ADC_TO_DMIC(adc_n);
+                               dmic_clk_reg = CDC_TX_TOP_CSR_SWR_DMICn_CTL(dmic);
+
+                               snd_soc_component_write_field(component, dmic_clk_reg,
+                                                       CDC_TX_SWR_DMIC_CLK_SEL_MASK,
+                                                       tx->dmic_clk_div);
+                       }
+               }
+               snd_soc_component_write_field(component, dec_cfg_reg,
+                                             CDC_TXn_ADC_MODE_MASK,
+                                             tx->dec_mode[decimator]);
+               /* Enable TX PGA Mute */
+               snd_soc_component_write_field(component, tx_vol_ctl_reg,
+                                             CDC_TXn_PGA_MUTE_MASK, 0x1);
+               break;
+       case SND_SOC_DAPM_POST_PMU:
+               snd_soc_component_write_field(component, tx_vol_ctl_reg,
+                                            CDC_TXn_CLK_EN_MASK, 0x1);
+               if (!is_amic_enabled(component, decimator)) {
+                       snd_soc_component_update_bits(component, hpf_gate_reg, 0x01, 0x00);
+                       /* Minimum 1 clk cycle delay is required as per HW spec */
+                       usleep_range(1000, 1010);
+               }
+               hpf_cut_off_freq = snd_soc_component_read_field(component, dec_cfg_reg,
+                                                               CDC_TXn_HPF_CUT_FREQ_MASK);
+
+               tx->tx_hpf_work[decimator].hpf_cut_off_freq =
+                                               hpf_cut_off_freq;
+
+               if (hpf_cut_off_freq != CF_MIN_3DB_150HZ)
+                       snd_soc_component_write_field(component, dec_cfg_reg,
+                                                     CDC_TXn_HPF_CUT_FREQ_MASK,
+                                                     CF_MIN_3DB_150HZ);
+
+               if (is_amic_enabled(component, decimator)) {
+                       hpf_delay = TX_MACRO_AMIC_HPF_DELAY_MS;
+                       unmute_delay = TX_MACRO_AMIC_UNMUTE_DELAY_MS;
+               }
+               /* schedule work queue to Remove Mute */
+               queue_delayed_work(system_freezable_wq,
+                                  &tx->tx_mute_dwork[decimator].dwork,
+                                  msecs_to_jiffies(unmute_delay));
+               if (tx->tx_hpf_work[decimator].hpf_cut_off_freq != CF_MIN_3DB_150HZ) {
+                       queue_delayed_work(system_freezable_wq,
+                               &tx->tx_hpf_work[decimator].dwork,
+                               msecs_to_jiffies(hpf_delay));
+                       snd_soc_component_update_bits(component, hpf_gate_reg,
+                                             CDC_TXn_HPF_F_CHANGE_MASK |
+                                             CDC_TXn_HPF_ZERO_GATE_MASK,
+                                             0x02);
+                       if (!is_amic_enabled(component, decimator))
+                               snd_soc_component_update_bits(component, hpf_gate_reg,
+                                                     CDC_TXn_HPF_F_CHANGE_MASK |
+                                                     CDC_TXn_HPF_ZERO_GATE_MASK,
+                                                     0x00);
+                       snd_soc_component_update_bits(component, hpf_gate_reg,
+                                             CDC_TXn_HPF_F_CHANGE_MASK |
+                                             CDC_TXn_HPF_ZERO_GATE_MASK,
+                                             0x01);
+
+                       /*
+                        * 6ms delay is required as per HW spec
+                        */
+                       usleep_range(6000, 6010);
+               }
+               /* apply gain after decimator is enabled */
+               snd_soc_component_write(component, tx_gain_ctl_reg,
+                             snd_soc_component_read(component,
+                                       tx_gain_ctl_reg));
+               if (tx->bcs_enable) {
+                       snd_soc_component_update_bits(component, dec_cfg_reg,
+                                       0x01, 0x01);
+                       tx->bcs_clk_en = true;
+               }
+               break;
+       case SND_SOC_DAPM_PRE_PMD:
+               hpf_cut_off_freq =
+                       tx->tx_hpf_work[decimator].hpf_cut_off_freq;
+               snd_soc_component_write_field(component, tx_vol_ctl_reg,
+                                             CDC_TXn_PGA_MUTE_MASK, 0x1);
+               if (cancel_delayed_work_sync(
+                   &tx->tx_hpf_work[decimator].dwork)) {
+                       if (hpf_cut_off_freq != CF_MIN_3DB_150HZ) {
+                               snd_soc_component_write_field(
+                                               component, dec_cfg_reg,
+                                               CDC_TXn_HPF_CUT_FREQ_MASK,
+                                               hpf_cut_off_freq);
+                               if (is_amic_enabled(component, decimator))
+                                       snd_soc_component_update_bits(component,
+                                             hpf_gate_reg,
+                                             CDC_TXn_HPF_F_CHANGE_MASK |
+                                             CDC_TXn_HPF_ZERO_GATE_MASK,
+                                             0x02);
+                               else
+                                       snd_soc_component_update_bits(component,
+                                             hpf_gate_reg,
+                                             CDC_TXn_HPF_F_CHANGE_MASK |
+                                             CDC_TXn_HPF_ZERO_GATE_MASK,
+                                             0x03);
+
+                               /*
+                                * Minimum 1 clk cycle delay is required
+                                * as per HW spec
+                                */
+                               usleep_range(1000, 1010);
+                               snd_soc_component_update_bits(component, hpf_gate_reg,
+                                             CDC_TXn_HPF_F_CHANGE_MASK |
+                                             CDC_TXn_HPF_ZERO_GATE_MASK,
+                                             0x1);
+                       }
+               }
+               cancel_delayed_work_sync(&tx->tx_mute_dwork[decimator].dwork);
+               break;
+       case SND_SOC_DAPM_POST_PMD:
+               snd_soc_component_write_field(component, tx_vol_ctl_reg,
+                                             CDC_TXn_CLK_EN_MASK, 0x0);
+               snd_soc_component_write_field(component, dec_cfg_reg,
+                                             CDC_TXn_ADC_MODE_MASK, 0x0);
+               snd_soc_component_write_field(component, tx_vol_ctl_reg,
+                                             CDC_TXn_PGA_MUTE_MASK, 0x0);
+               if (tx->bcs_enable) {
+                       snd_soc_component_write_field(component, dec_cfg_reg,
+                                                     CDC_TXn_PH_EN_MASK, 0x0);
+                       snd_soc_component_write_field(component,
+                                                     CDC_TX0_TX_PATH_SEC7,
+                                                     CDC_TX0_MBHC_CTL_EN_MASK,
+                                                     0x0);
+                       tx->bcs_clk_en = false;
+               }
+               break;
+       }
+       return 0;
+}
+
+static int tx_macro_dec_mode_get(struct snd_kcontrol *kcontrol,
+                                struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+       struct tx_macro *tx = snd_soc_component_get_drvdata(component);
+       struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
+       int path = e->shift_l;
+
+       ucontrol->value.integer.value[0] = tx->dec_mode[path];
+
+       return 0;
+}
+
+static int tx_macro_dec_mode_put(struct snd_kcontrol *kcontrol,
+                                struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+       int value = ucontrol->value.integer.value[0];
+       struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
+       int path = e->shift_l;
+       struct tx_macro *tx = snd_soc_component_get_drvdata(component);
+
+       tx->dec_mode[path] = value;
+
+       return 0;
+}
+
+static int tx_macro_get_bcs(struct snd_kcontrol *kcontrol,
+                           struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+       struct tx_macro *tx = snd_soc_component_get_drvdata(component);
+
+       ucontrol->value.integer.value[0] = tx->bcs_enable;
+
+       return 0;
+}
+
+static int tx_macro_set_bcs(struct snd_kcontrol *kcontrol,
+                           struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+       int value = ucontrol->value.integer.value[0];
+       struct tx_macro *tx = snd_soc_component_get_drvdata(component);
+
+       tx->bcs_enable = value;
+
+       return 0;
+}
+
+static int tx_macro_hw_params(struct snd_pcm_substream *substream,
+                             struct snd_pcm_hw_params *params,
+                             struct snd_soc_dai *dai)
+{
+       struct snd_soc_component *component = dai->component;
+       u32 decimator, sample_rate;
+       int tx_fs_rate;
+       struct tx_macro *tx = snd_soc_component_get_drvdata(component);
+
+       sample_rate = params_rate(params);
+       switch (sample_rate) {
+       case 8000:
+               tx_fs_rate = 0;
+               break;
+       case 16000:
+               tx_fs_rate = 1;
+               break;
+       case 32000:
+               tx_fs_rate = 3;
+               break;
+       case 48000:
+               tx_fs_rate = 4;
+               break;
+       case 96000:
+               tx_fs_rate = 5;
+               break;
+       case 192000:
+               tx_fs_rate = 6;
+               break;
+       case 384000:
+               tx_fs_rate = 7;
+               break;
+       default:
+               dev_err(component->dev, "%s: Invalid TX sample rate: %d\n",
+                       __func__, params_rate(params));
+               return -EINVAL;
+       }
+
+       for_each_set_bit(decimator, &tx->active_ch_mask[dai->id], TX_MACRO_DEC_MAX)
+               snd_soc_component_update_bits(component, CDC_TXn_TX_PATH_CTL(decimator),
+                                             CDC_TXn_PCM_RATE_MASK,
+                                             tx_fs_rate);
+       return 0;
+}
+
+static int tx_macro_get_channel_map(struct snd_soc_dai *dai,
+                                   unsigned int *tx_num, unsigned int *tx_slot,
+                                   unsigned int *rx_num, unsigned int *rx_slot)
+{
+       struct snd_soc_component *component = dai->component;
+       struct tx_macro *tx = snd_soc_component_get_drvdata(component);
+
+       switch (dai->id) {
+       case TX_MACRO_AIF1_CAP:
+       case TX_MACRO_AIF2_CAP:
+       case TX_MACRO_AIF3_CAP:
+               *tx_slot = tx->active_ch_mask[dai->id];
+               *tx_num = tx->active_ch_cnt[dai->id];
+               break;
+       default:
+               break;
+       }
+       return 0;
+}
+
+static int tx_macro_digital_mute(struct snd_soc_dai *dai, int mute, int stream)
+{
+       struct snd_soc_component *component = dai->component;
+       struct tx_macro *tx = snd_soc_component_get_drvdata(component);
+       u16 decimator;
+
+       decimator = tx->active_decimator[dai->id];
+
+       if (mute)
+               snd_soc_component_write_field(component,
+                                             CDC_TXn_TX_PATH_CTL(decimator),
+                                             CDC_TXn_PGA_MUTE_MASK, 0x1);
+       else
+               snd_soc_component_update_bits(component,
+                                             CDC_TXn_TX_PATH_CTL(decimator),
+                                             CDC_TXn_PGA_MUTE_MASK, 0x0);
+
+       return 0;
+}
+
+static struct snd_soc_dai_ops tx_macro_dai_ops = {
+       .hw_params = tx_macro_hw_params,
+       .get_channel_map = tx_macro_get_channel_map,
+       .mute_stream = tx_macro_digital_mute,
+};
+
+static struct snd_soc_dai_driver tx_macro_dai[] = {
+       {
+               .name = "tx_macro_tx1",
+               .id = TX_MACRO_AIF1_CAP,
+               .capture = {
+                       .stream_name = "TX_AIF1 Capture",
+                       .rates = TX_MACRO_RATES,
+                       .formats = TX_MACRO_FORMATS,
+                       .rate_max = 192000,
+                       .rate_min = 8000,
+                       .channels_min = 1,
+                       .channels_max = 8,
+               },
+               .ops = &tx_macro_dai_ops,
+       },
+       {
+               .name = "tx_macro_tx2",
+               .id = TX_MACRO_AIF2_CAP,
+               .capture = {
+                       .stream_name = "TX_AIF2 Capture",
+                       .rates = TX_MACRO_RATES,
+                       .formats = TX_MACRO_FORMATS,
+                       .rate_max = 192000,
+                       .rate_min = 8000,
+                       .channels_min = 1,
+                       .channels_max = 8,
+               },
+               .ops = &tx_macro_dai_ops,
+       },
+       {
+               .name = "tx_macro_tx3",
+               .id = TX_MACRO_AIF3_CAP,
+               .capture = {
+                       .stream_name = "TX_AIF3 Capture",
+                       .rates = TX_MACRO_RATES,
+                       .formats = TX_MACRO_FORMATS,
+                       .rate_max = 192000,
+                       .rate_min = 8000,
+                       .channels_min = 1,
+                       .channels_max = 8,
+               },
+               .ops = &tx_macro_dai_ops,
+       },
+};
+
+static const char * const adc_mux_text[] = {
+       "MSM_DMIC", "SWR_MIC", "ANC_FB_TUNE1"
+};
+
+static SOC_ENUM_SINGLE_DECL(tx_dec0_enum, CDC_TX_INP_MUX_ADC_MUX0_CFG1,
+                  0, adc_mux_text);
+static SOC_ENUM_SINGLE_DECL(tx_dec1_enum, CDC_TX_INP_MUX_ADC_MUX1_CFG1,
+                  0, adc_mux_text);
+static SOC_ENUM_SINGLE_DECL(tx_dec2_enum, CDC_TX_INP_MUX_ADC_MUX2_CFG1,
+                  0, adc_mux_text);
+static SOC_ENUM_SINGLE_DECL(tx_dec3_enum, CDC_TX_INP_MUX_ADC_MUX3_CFG1,
+                  0, adc_mux_text);
+static SOC_ENUM_SINGLE_DECL(tx_dec4_enum, CDC_TX_INP_MUX_ADC_MUX4_CFG1,
+                  0, adc_mux_text);
+static SOC_ENUM_SINGLE_DECL(tx_dec5_enum, CDC_TX_INP_MUX_ADC_MUX5_CFG1,
+                  0, adc_mux_text);
+static SOC_ENUM_SINGLE_DECL(tx_dec6_enum, CDC_TX_INP_MUX_ADC_MUX6_CFG1,
+                  0, adc_mux_text);
+static SOC_ENUM_SINGLE_DECL(tx_dec7_enum, CDC_TX_INP_MUX_ADC_MUX7_CFG1,
+                  0, adc_mux_text);
+
+static const struct snd_kcontrol_new tx_dec0_mux = SOC_DAPM_ENUM("tx_dec0", tx_dec0_enum);
+static const struct snd_kcontrol_new tx_dec1_mux = SOC_DAPM_ENUM("tx_dec1", tx_dec1_enum);
+static const struct snd_kcontrol_new tx_dec2_mux = SOC_DAPM_ENUM("tx_dec2", tx_dec2_enum);
+static const struct snd_kcontrol_new tx_dec3_mux = SOC_DAPM_ENUM("tx_dec3", tx_dec3_enum);
+static const struct snd_kcontrol_new tx_dec4_mux = SOC_DAPM_ENUM("tx_dec4", tx_dec4_enum);
+static const struct snd_kcontrol_new tx_dec5_mux = SOC_DAPM_ENUM("tx_dec5", tx_dec5_enum);
+static const struct snd_kcontrol_new tx_dec6_mux = SOC_DAPM_ENUM("tx_dec6", tx_dec6_enum);
+static const struct snd_kcontrol_new tx_dec7_mux = SOC_DAPM_ENUM("tx_dec7", tx_dec7_enum);
+
+static const char * const smic_mux_text[] = {
+       "ZERO", "ADC0", "ADC1", "ADC2", "ADC3", "SWR_DMIC0",
+       "SWR_DMIC1", "SWR_DMIC2", "SWR_DMIC3", "SWR_DMIC4",
+       "SWR_DMIC5", "SWR_DMIC6", "SWR_DMIC7"
+};
+
+static SOC_ENUM_SINGLE_DECL(tx_smic0_enum, CDC_TX_INP_MUX_ADC_MUX0_CFG0,
+                       0, smic_mux_text);
+
+static SOC_ENUM_SINGLE_DECL(tx_smic1_enum, CDC_TX_INP_MUX_ADC_MUX1_CFG0,
+                       0, smic_mux_text);
+
+static SOC_ENUM_SINGLE_DECL(tx_smic2_enum, CDC_TX_INP_MUX_ADC_MUX2_CFG0,
+                       0, smic_mux_text);
+
+static SOC_ENUM_SINGLE_DECL(tx_smic3_enum, CDC_TX_INP_MUX_ADC_MUX3_CFG0,
+                       0, smic_mux_text);
+
+static SOC_ENUM_SINGLE_DECL(tx_smic4_enum, CDC_TX_INP_MUX_ADC_MUX4_CFG0,
+                       0, smic_mux_text);
+
+static SOC_ENUM_SINGLE_DECL(tx_smic5_enum, CDC_TX_INP_MUX_ADC_MUX5_CFG0,
+                       0, smic_mux_text);
+
+static SOC_ENUM_SINGLE_DECL(tx_smic6_enum, CDC_TX_INP_MUX_ADC_MUX6_CFG0,
+                       0, smic_mux_text);
+
+static SOC_ENUM_SINGLE_DECL(tx_smic7_enum, CDC_TX_INP_MUX_ADC_MUX7_CFG0,
+                       0, smic_mux_text);
+
+static const struct snd_kcontrol_new tx_smic0_mux = SOC_DAPM_ENUM_EXT("tx_smic0", tx_smic0_enum,
+                       snd_soc_dapm_get_enum_double, tx_macro_put_dec_enum);
+static const struct snd_kcontrol_new tx_smic1_mux = SOC_DAPM_ENUM_EXT("tx_smic1", tx_smic1_enum,
+                       snd_soc_dapm_get_enum_double, tx_macro_put_dec_enum);
+static const struct snd_kcontrol_new tx_smic2_mux = SOC_DAPM_ENUM_EXT("tx_smic2", tx_smic2_enum,
+                       snd_soc_dapm_get_enum_double, tx_macro_put_dec_enum);
+static const struct snd_kcontrol_new tx_smic3_mux = SOC_DAPM_ENUM_EXT("tx_smic3", tx_smic3_enum,
+                       snd_soc_dapm_get_enum_double, tx_macro_put_dec_enum);
+static const struct snd_kcontrol_new tx_smic4_mux = SOC_DAPM_ENUM_EXT("tx_smic4", tx_smic4_enum,
+                       snd_soc_dapm_get_enum_double, tx_macro_put_dec_enum);
+static const struct snd_kcontrol_new tx_smic5_mux = SOC_DAPM_ENUM_EXT("tx_smic5", tx_smic5_enum,
+                       snd_soc_dapm_get_enum_double, tx_macro_put_dec_enum);
+static const struct snd_kcontrol_new tx_smic6_mux = SOC_DAPM_ENUM_EXT("tx_smic6", tx_smic6_enum,
+                       snd_soc_dapm_get_enum_double, tx_macro_put_dec_enum);
+static const struct snd_kcontrol_new tx_smic7_mux = SOC_DAPM_ENUM_EXT("tx_smic7", tx_smic7_enum,
+                       snd_soc_dapm_get_enum_double, tx_macro_put_dec_enum);
+
+static const char * const dec_mode_mux_text[] = {
+       "ADC_DEFAULT", "ADC_LOW_PWR", "ADC_HIGH_PERF",
+};
+
+static const struct soc_enum dec_mode_mux_enum[] = {
+       SOC_ENUM_SINGLE(SND_SOC_NOPM, 0, ARRAY_SIZE(dec_mode_mux_text),
+                       dec_mode_mux_text),
+       SOC_ENUM_SINGLE(SND_SOC_NOPM, 1, ARRAY_SIZE(dec_mode_mux_text),
+                       dec_mode_mux_text),
+       SOC_ENUM_SINGLE(SND_SOC_NOPM, 2,  ARRAY_SIZE(dec_mode_mux_text),
+                       dec_mode_mux_text),
+       SOC_ENUM_SINGLE(SND_SOC_NOPM, 3, ARRAY_SIZE(dec_mode_mux_text),
+                       dec_mode_mux_text),
+       SOC_ENUM_SINGLE(SND_SOC_NOPM, 4, ARRAY_SIZE(dec_mode_mux_text),
+                       dec_mode_mux_text),
+       SOC_ENUM_SINGLE(SND_SOC_NOPM, 5, ARRAY_SIZE(dec_mode_mux_text),
+                       dec_mode_mux_text),
+       SOC_ENUM_SINGLE(SND_SOC_NOPM, 6, ARRAY_SIZE(dec_mode_mux_text),
+                       dec_mode_mux_text),
+       SOC_ENUM_SINGLE(SND_SOC_NOPM, 7, ARRAY_SIZE(dec_mode_mux_text),
+                       dec_mode_mux_text),
+};
+
+static const struct snd_kcontrol_new tx_aif1_cap_mixer[] = {
+       SOC_SINGLE_EXT("DEC0", SND_SOC_NOPM, TX_MACRO_DEC0, 1, 0,
+                       tx_macro_tx_mixer_get, tx_macro_tx_mixer_put),
+       SOC_SINGLE_EXT("DEC1", SND_SOC_NOPM, TX_MACRO_DEC1, 1, 0,
+                       tx_macro_tx_mixer_get, tx_macro_tx_mixer_put),
+       SOC_SINGLE_EXT("DEC2", SND_SOC_NOPM, TX_MACRO_DEC2, 1, 0,
+                       tx_macro_tx_mixer_get, tx_macro_tx_mixer_put),
+       SOC_SINGLE_EXT("DEC3", SND_SOC_NOPM, TX_MACRO_DEC3, 1, 0,
+                       tx_macro_tx_mixer_get, tx_macro_tx_mixer_put),
+       SOC_SINGLE_EXT("DEC4", SND_SOC_NOPM, TX_MACRO_DEC4, 1, 0,
+                       tx_macro_tx_mixer_get, tx_macro_tx_mixer_put),
+       SOC_SINGLE_EXT("DEC5", SND_SOC_NOPM, TX_MACRO_DEC5, 1, 0,
+                       tx_macro_tx_mixer_get, tx_macro_tx_mixer_put),
+       SOC_SINGLE_EXT("DEC6", SND_SOC_NOPM, TX_MACRO_DEC6, 1, 0,
+                       tx_macro_tx_mixer_get, tx_macro_tx_mixer_put),
+       SOC_SINGLE_EXT("DEC7", SND_SOC_NOPM, TX_MACRO_DEC7, 1, 0,
+                       tx_macro_tx_mixer_get, tx_macro_tx_mixer_put),
+};
+
+static const struct snd_kcontrol_new tx_aif2_cap_mixer[] = {
+       SOC_SINGLE_EXT("DEC0", SND_SOC_NOPM, TX_MACRO_DEC0, 1, 0,
+                       tx_macro_tx_mixer_get, tx_macro_tx_mixer_put),
+       SOC_SINGLE_EXT("DEC1", SND_SOC_NOPM, TX_MACRO_DEC1, 1, 0,
+                       tx_macro_tx_mixer_get, tx_macro_tx_mixer_put),
+       SOC_SINGLE_EXT("DEC2", SND_SOC_NOPM, TX_MACRO_DEC2, 1, 0,
+                       tx_macro_tx_mixer_get, tx_macro_tx_mixer_put),
+       SOC_SINGLE_EXT("DEC3", SND_SOC_NOPM, TX_MACRO_DEC3, 1, 0,
+                       tx_macro_tx_mixer_get, tx_macro_tx_mixer_put),
+       SOC_SINGLE_EXT("DEC4", SND_SOC_NOPM, TX_MACRO_DEC4, 1, 0,
+                       tx_macro_tx_mixer_get, tx_macro_tx_mixer_put),
+       SOC_SINGLE_EXT("DEC5", SND_SOC_NOPM, TX_MACRO_DEC5, 1, 0,
+                       tx_macro_tx_mixer_get, tx_macro_tx_mixer_put),
+       SOC_SINGLE_EXT("DEC6", SND_SOC_NOPM, TX_MACRO_DEC6, 1, 0,
+                       tx_macro_tx_mixer_get, tx_macro_tx_mixer_put),
+       SOC_SINGLE_EXT("DEC7", SND_SOC_NOPM, TX_MACRO_DEC7, 1, 0,
+                       tx_macro_tx_mixer_get, tx_macro_tx_mixer_put),
+};
+
+static const struct snd_kcontrol_new tx_aif3_cap_mixer[] = {
+       SOC_SINGLE_EXT("DEC0", SND_SOC_NOPM, TX_MACRO_DEC0, 1, 0,
+                       tx_macro_tx_mixer_get, tx_macro_tx_mixer_put),
+       SOC_SINGLE_EXT("DEC1", SND_SOC_NOPM, TX_MACRO_DEC1, 1, 0,
+                       tx_macro_tx_mixer_get, tx_macro_tx_mixer_put),
+       SOC_SINGLE_EXT("DEC2", SND_SOC_NOPM, TX_MACRO_DEC2, 1, 0,
+                       tx_macro_tx_mixer_get, tx_macro_tx_mixer_put),
+       SOC_SINGLE_EXT("DEC3", SND_SOC_NOPM, TX_MACRO_DEC3, 1, 0,
+                       tx_macro_tx_mixer_get, tx_macro_tx_mixer_put),
+       SOC_SINGLE_EXT("DEC4", SND_SOC_NOPM, TX_MACRO_DEC4, 1, 0,
+                       tx_macro_tx_mixer_get, tx_macro_tx_mixer_put),
+       SOC_SINGLE_EXT("DEC5", SND_SOC_NOPM, TX_MACRO_DEC5, 1, 0,
+                       tx_macro_tx_mixer_get, tx_macro_tx_mixer_put),
+       SOC_SINGLE_EXT("DEC6", SND_SOC_NOPM, TX_MACRO_DEC6, 1, 0,
+                       tx_macro_tx_mixer_get, tx_macro_tx_mixer_put),
+       SOC_SINGLE_EXT("DEC7", SND_SOC_NOPM, TX_MACRO_DEC7, 1, 0,
+                       tx_macro_tx_mixer_get, tx_macro_tx_mixer_put),
+};
+
+static const struct snd_soc_dapm_widget tx_macro_dapm_widgets[] = {
+       SND_SOC_DAPM_AIF_OUT("TX_AIF1 CAP", "TX_AIF1 Capture", 0,
+               SND_SOC_NOPM, TX_MACRO_AIF1_CAP, 0),
+
+       SND_SOC_DAPM_AIF_OUT("TX_AIF2 CAP", "TX_AIF2 Capture", 0,
+               SND_SOC_NOPM, TX_MACRO_AIF2_CAP, 0),
+
+       SND_SOC_DAPM_AIF_OUT("TX_AIF3 CAP", "TX_AIF3 Capture", 0,
+               SND_SOC_NOPM, TX_MACRO_AIF3_CAP, 0),
+
+       SND_SOC_DAPM_MIXER("TX_AIF1_CAP Mixer", SND_SOC_NOPM, TX_MACRO_AIF1_CAP, 0,
+               tx_aif1_cap_mixer, ARRAY_SIZE(tx_aif1_cap_mixer)),
+
+       SND_SOC_DAPM_MIXER("TX_AIF2_CAP Mixer", SND_SOC_NOPM, TX_MACRO_AIF2_CAP, 0,
+               tx_aif2_cap_mixer, ARRAY_SIZE(tx_aif2_cap_mixer)),
+
+       SND_SOC_DAPM_MIXER("TX_AIF3_CAP Mixer", SND_SOC_NOPM, TX_MACRO_AIF3_CAP, 0,
+               tx_aif3_cap_mixer, ARRAY_SIZE(tx_aif3_cap_mixer)),
+
+       SND_SOC_DAPM_MUX("TX SMIC MUX0", SND_SOC_NOPM, 0, 0, &tx_smic0_mux),
+       SND_SOC_DAPM_MUX("TX SMIC MUX1", SND_SOC_NOPM, 0, 0, &tx_smic1_mux),
+       SND_SOC_DAPM_MUX("TX SMIC MUX2", SND_SOC_NOPM, 0, 0, &tx_smic2_mux),
+       SND_SOC_DAPM_MUX("TX SMIC MUX3", SND_SOC_NOPM, 0, 0, &tx_smic3_mux),
+       SND_SOC_DAPM_MUX("TX SMIC MUX4", SND_SOC_NOPM, 0, 0, &tx_smic4_mux),
+       SND_SOC_DAPM_MUX("TX SMIC MUX5", SND_SOC_NOPM, 0, 0, &tx_smic5_mux),
+       SND_SOC_DAPM_MUX("TX SMIC MUX6", SND_SOC_NOPM, 0, 0, &tx_smic6_mux),
+       SND_SOC_DAPM_MUX("TX SMIC MUX7", SND_SOC_NOPM, 0, 0, &tx_smic7_mux),
+
+       SND_SOC_DAPM_INPUT("TX SWR_ADC0"),
+       SND_SOC_DAPM_INPUT("TX SWR_ADC1"),
+       SND_SOC_DAPM_INPUT("TX SWR_ADC2"),
+       SND_SOC_DAPM_INPUT("TX SWR_ADC3"),
+       SND_SOC_DAPM_INPUT("TX SWR_DMIC0"),
+       SND_SOC_DAPM_INPUT("TX SWR_DMIC1"),
+       SND_SOC_DAPM_INPUT("TX SWR_DMIC2"),
+       SND_SOC_DAPM_INPUT("TX SWR_DMIC3"),
+       SND_SOC_DAPM_INPUT("TX SWR_DMIC4"),
+       SND_SOC_DAPM_INPUT("TX SWR_DMIC5"),
+       SND_SOC_DAPM_INPUT("TX SWR_DMIC6"),
+       SND_SOC_DAPM_INPUT("TX SWR_DMIC7"),
+
+       SND_SOC_DAPM_MUX_E("TX DEC0 MUX", SND_SOC_NOPM,
+                          TX_MACRO_DEC0, 0,
+                          &tx_dec0_mux, tx_macro_enable_dec,
+                          SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+                          SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
+
+       SND_SOC_DAPM_MUX_E("TX DEC1 MUX", SND_SOC_NOPM,
+                          TX_MACRO_DEC1, 0,
+                          &tx_dec1_mux, tx_macro_enable_dec,
+                          SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+                          SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
+
+       SND_SOC_DAPM_MUX_E("TX DEC2 MUX", SND_SOC_NOPM,
+                          TX_MACRO_DEC2, 0,
+                          &tx_dec2_mux, tx_macro_enable_dec,
+                          SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+                          SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
+
+       SND_SOC_DAPM_MUX_E("TX DEC3 MUX", SND_SOC_NOPM,
+                          TX_MACRO_DEC3, 0,
+                          &tx_dec3_mux, tx_macro_enable_dec,
+                          SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+                          SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
+
+       SND_SOC_DAPM_MUX_E("TX DEC4 MUX", SND_SOC_NOPM,
+                          TX_MACRO_DEC4, 0,
+                          &tx_dec4_mux, tx_macro_enable_dec,
+                          SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+                          SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
+
+       SND_SOC_DAPM_MUX_E("TX DEC5 MUX", SND_SOC_NOPM,
+                          TX_MACRO_DEC5, 0,
+                          &tx_dec5_mux, tx_macro_enable_dec,
+                          SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+                          SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
+
+       SND_SOC_DAPM_MUX_E("TX DEC6 MUX", SND_SOC_NOPM,
+                          TX_MACRO_DEC6, 0,
+                          &tx_dec6_mux, tx_macro_enable_dec,
+                          SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+                          SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
+
+       SND_SOC_DAPM_MUX_E("TX DEC7 MUX", SND_SOC_NOPM,
+                          TX_MACRO_DEC7, 0,
+                          &tx_dec7_mux, tx_macro_enable_dec,
+                          SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+                          SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
+
+       SND_SOC_DAPM_SUPPLY_S("TX_MCLK", 0, SND_SOC_NOPM, 0, 0,
+       tx_macro_mclk_event, SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+
+       SND_SOC_DAPM_SUPPLY_S("TX_SWR_CLK", 0, SND_SOC_NOPM, 0, 0, NULL, 0),
+
+       SND_SOC_DAPM_SUPPLY_S("VA_SWR_CLK", 0, SND_SOC_NOPM, 0, 0,
+                       NULL, 0),
+};
+
+static const struct snd_soc_dapm_route tx_audio_map[] = {
+       {"TX_AIF1 CAP", NULL, "TX_MCLK"},
+       {"TX_AIF2 CAP", NULL, "TX_MCLK"},
+       {"TX_AIF3 CAP", NULL, "TX_MCLK"},
+
+       {"TX_AIF1 CAP", NULL, "TX_AIF1_CAP Mixer"},
+       {"TX_AIF2 CAP", NULL, "TX_AIF2_CAP Mixer"},
+       {"TX_AIF3 CAP", NULL, "TX_AIF3_CAP Mixer"},
+
+       {"TX_AIF1_CAP Mixer", "DEC0", "TX DEC0 MUX"},
+       {"TX_AIF1_CAP Mixer", "DEC1", "TX DEC1 MUX"},
+       {"TX_AIF1_CAP Mixer", "DEC2", "TX DEC2 MUX"},
+       {"TX_AIF1_CAP Mixer", "DEC3", "TX DEC3 MUX"},
+       {"TX_AIF1_CAP Mixer", "DEC4", "TX DEC4 MUX"},
+       {"TX_AIF1_CAP Mixer", "DEC5", "TX DEC5 MUX"},
+       {"TX_AIF1_CAP Mixer", "DEC6", "TX DEC6 MUX"},
+       {"TX_AIF1_CAP Mixer", "DEC7", "TX DEC7 MUX"},
+
+       {"TX_AIF2_CAP Mixer", "DEC0", "TX DEC0 MUX"},
+       {"TX_AIF2_CAP Mixer", "DEC1", "TX DEC1 MUX"},
+       {"TX_AIF2_CAP Mixer", "DEC2", "TX DEC2 MUX"},
+       {"TX_AIF2_CAP Mixer", "DEC3", "TX DEC3 MUX"},
+       {"TX_AIF2_CAP Mixer", "DEC4", "TX DEC4 MUX"},
+       {"TX_AIF2_CAP Mixer", "DEC5", "TX DEC5 MUX"},
+       {"TX_AIF2_CAP Mixer", "DEC6", "TX DEC6 MUX"},
+       {"TX_AIF2_CAP Mixer", "DEC7", "TX DEC7 MUX"},
+
+       {"TX_AIF3_CAP Mixer", "DEC0", "TX DEC0 MUX"},
+       {"TX_AIF3_CAP Mixer", "DEC1", "TX DEC1 MUX"},
+       {"TX_AIF3_CAP Mixer", "DEC2", "TX DEC2 MUX"},
+       {"TX_AIF3_CAP Mixer", "DEC3", "TX DEC3 MUX"},
+       {"TX_AIF3_CAP Mixer", "DEC4", "TX DEC4 MUX"},
+       {"TX_AIF3_CAP Mixer", "DEC5", "TX DEC5 MUX"},
+       {"TX_AIF3_CAP Mixer", "DEC6", "TX DEC6 MUX"},
+       {"TX_AIF3_CAP Mixer", "DEC7", "TX DEC7 MUX"},
+
+       {"TX DEC0 MUX", NULL, "TX_MCLK"},
+       {"TX DEC1 MUX", NULL, "TX_MCLK"},
+       {"TX DEC2 MUX", NULL, "TX_MCLK"},
+       {"TX DEC3 MUX", NULL, "TX_MCLK"},
+       {"TX DEC4 MUX", NULL, "TX_MCLK"},
+       {"TX DEC5 MUX", NULL, "TX_MCLK"},
+       {"TX DEC6 MUX", NULL, "TX_MCLK"},
+       {"TX DEC7 MUX", NULL, "TX_MCLK"},
+
+       {"TX DEC0 MUX", "SWR_MIC", "TX SMIC MUX0"},
+       {"TX SMIC MUX0", NULL, "TX_SWR_CLK"},
+       {"TX SMIC MUX0", "ADC0", "TX SWR_ADC0"},
+       {"TX SMIC MUX0", "ADC1", "TX SWR_ADC1"},
+       {"TX SMIC MUX0", "ADC2", "TX SWR_ADC2"},
+       {"TX SMIC MUX0", "ADC3", "TX SWR_ADC3"},
+       {"TX SMIC MUX0", "SWR_DMIC0", "TX SWR_DMIC0"},
+       {"TX SMIC MUX0", "SWR_DMIC1", "TX SWR_DMIC1"},
+       {"TX SMIC MUX0", "SWR_DMIC2", "TX SWR_DMIC2"},
+       {"TX SMIC MUX0", "SWR_DMIC3", "TX SWR_DMIC3"},
+       {"TX SMIC MUX0", "SWR_DMIC4", "TX SWR_DMIC4"},
+       {"TX SMIC MUX0", "SWR_DMIC5", "TX SWR_DMIC5"},
+       {"TX SMIC MUX0", "SWR_DMIC6", "TX SWR_DMIC6"},
+       {"TX SMIC MUX0", "SWR_DMIC7", "TX SWR_DMIC7"},
+
+       {"TX DEC1 MUX", "SWR_MIC", "TX SMIC MUX1"},
+       {"TX SMIC MUX1", NULL, "TX_SWR_CLK"},
+       {"TX SMIC MUX1", "ADC0", "TX SWR_ADC0"},
+       {"TX SMIC MUX1", "ADC1", "TX SWR_ADC1"},
+       {"TX SMIC MUX1", "ADC2", "TX SWR_ADC2"},
+       {"TX SMIC MUX1", "ADC3", "TX SWR_ADC3"},
+       {"TX SMIC MUX1", "SWR_DMIC0", "TX SWR_DMIC0"},
+       {"TX SMIC MUX1", "SWR_DMIC1", "TX SWR_DMIC1"},
+       {"TX SMIC MUX1", "SWR_DMIC2", "TX SWR_DMIC2"},
+       {"TX SMIC MUX1", "SWR_DMIC3", "TX SWR_DMIC3"},
+       {"TX SMIC MUX1", "SWR_DMIC4", "TX SWR_DMIC4"},
+       {"TX SMIC MUX1", "SWR_DMIC5", "TX SWR_DMIC5"},
+       {"TX SMIC MUX1", "SWR_DMIC6", "TX SWR_DMIC6"},
+       {"TX SMIC MUX1", "SWR_DMIC7", "TX SWR_DMIC7"},
+
+       {"TX DEC2 MUX", "SWR_MIC", "TX SMIC MUX2"},
+       {"TX SMIC MUX2", NULL, "TX_SWR_CLK"},
+       {"TX SMIC MUX2", "ADC0", "TX SWR_ADC0"},
+       {"TX SMIC MUX2", "ADC1", "TX SWR_ADC1"},
+       {"TX SMIC MUX2", "ADC2", "TX SWR_ADC2"},
+       {"TX SMIC MUX2", "ADC3", "TX SWR_ADC3"},
+       {"TX SMIC MUX2", "SWR_DMIC0", "TX SWR_DMIC0"},
+       {"TX SMIC MUX2", "SWR_DMIC1", "TX SWR_DMIC1"},
+       {"TX SMIC MUX2", "SWR_DMIC2", "TX SWR_DMIC2"},
+       {"TX SMIC MUX2", "SWR_DMIC3", "TX SWR_DMIC3"},
+       {"TX SMIC MUX2", "SWR_DMIC4", "TX SWR_DMIC4"},
+       {"TX SMIC MUX2", "SWR_DMIC5", "TX SWR_DMIC5"},
+       {"TX SMIC MUX2", "SWR_DMIC6", "TX SWR_DMIC6"},
+       {"TX SMIC MUX2", "SWR_DMIC7", "TX SWR_DMIC7"},
+
+       {"TX DEC3 MUX", "SWR_MIC", "TX SMIC MUX3"},
+       {"TX SMIC MUX3", NULL, "TX_SWR_CLK"},
+       {"TX SMIC MUX3", "ADC0", "TX SWR_ADC0"},
+       {"TX SMIC MUX3", "ADC1", "TX SWR_ADC1"},
+       {"TX SMIC MUX3", "ADC2", "TX SWR_ADC2"},
+       {"TX SMIC MUX3", "ADC3", "TX SWR_ADC3"},
+       {"TX SMIC MUX3", "SWR_DMIC0", "TX SWR_DMIC0"},
+       {"TX SMIC MUX3", "SWR_DMIC1", "TX SWR_DMIC1"},
+       {"TX SMIC MUX3", "SWR_DMIC2", "TX SWR_DMIC2"},
+       {"TX SMIC MUX3", "SWR_DMIC3", "TX SWR_DMIC3"},
+       {"TX SMIC MUX3", "SWR_DMIC4", "TX SWR_DMIC4"},
+       {"TX SMIC MUX3", "SWR_DMIC5", "TX SWR_DMIC5"},
+       {"TX SMIC MUX3", "SWR_DMIC6", "TX SWR_DMIC6"},
+       {"TX SMIC MUX3", "SWR_DMIC7", "TX SWR_DMIC7"},
+
+       {"TX DEC4 MUX", "SWR_MIC", "TX SMIC MUX4"},
+       {"TX SMIC MUX4", NULL, "TX_SWR_CLK"},
+       {"TX SMIC MUX4", "ADC0", "TX SWR_ADC0"},
+       {"TX SMIC MUX4", "ADC1", "TX SWR_ADC1"},
+       {"TX SMIC MUX4", "ADC2", "TX SWR_ADC2"},
+       {"TX SMIC MUX4", "ADC3", "TX SWR_ADC3"},
+       {"TX SMIC MUX4", "SWR_DMIC0", "TX SWR_DMIC0"},
+       {"TX SMIC MUX4", "SWR_DMIC1", "TX SWR_DMIC1"},
+       {"TX SMIC MUX4", "SWR_DMIC2", "TX SWR_DMIC2"},
+       {"TX SMIC MUX4", "SWR_DMIC3", "TX SWR_DMIC3"},
+       {"TX SMIC MUX4", "SWR_DMIC4", "TX SWR_DMIC4"},
+       {"TX SMIC MUX4", "SWR_DMIC5", "TX SWR_DMIC5"},
+       {"TX SMIC MUX4", "SWR_DMIC6", "TX SWR_DMIC6"},
+       {"TX SMIC MUX4", "SWR_DMIC7", "TX SWR_DMIC7"},
+
+       {"TX DEC5 MUX", "SWR_MIC", "TX SMIC MUX5"},
+       {"TX SMIC MUX5", NULL, "TX_SWR_CLK"},
+       {"TX SMIC MUX5", "ADC0", "TX SWR_ADC0"},
+       {"TX SMIC MUX5", "ADC1", "TX SWR_ADC1"},
+       {"TX SMIC MUX5", "ADC2", "TX SWR_ADC2"},
+       {"TX SMIC MUX5", "ADC3", "TX SWR_ADC3"},
+       {"TX SMIC MUX5", "SWR_DMIC0", "TX SWR_DMIC0"},
+       {"TX SMIC MUX5", "SWR_DMIC1", "TX SWR_DMIC1"},
+       {"TX SMIC MUX5", "SWR_DMIC2", "TX SWR_DMIC2"},
+       {"TX SMIC MUX5", "SWR_DMIC3", "TX SWR_DMIC3"},
+       {"TX SMIC MUX5", "SWR_DMIC4", "TX SWR_DMIC4"},
+       {"TX SMIC MUX5", "SWR_DMIC5", "TX SWR_DMIC5"},
+       {"TX SMIC MUX5", "SWR_DMIC6", "TX SWR_DMIC6"},
+       {"TX SMIC MUX5", "SWR_DMIC7", "TX SWR_DMIC7"},
+
+       {"TX DEC6 MUX", "SWR_MIC", "TX SMIC MUX6"},
+       {"TX SMIC MUX6", NULL, "TX_SWR_CLK"},
+       {"TX SMIC MUX6", "ADC0", "TX SWR_ADC0"},
+       {"TX SMIC MUX6", "ADC1", "TX SWR_ADC1"},
+       {"TX SMIC MUX6", "ADC2", "TX SWR_ADC2"},
+       {"TX SMIC MUX6", "ADC3", "TX SWR_ADC3"},
+       {"TX SMIC MUX6", "SWR_DMIC0", "TX SWR_DMIC0"},
+       {"TX SMIC MUX6", "SWR_DMIC1", "TX SWR_DMIC1"},
+       {"TX SMIC MUX6", "SWR_DMIC2", "TX SWR_DMIC2"},
+       {"TX SMIC MUX6", "SWR_DMIC3", "TX SWR_DMIC3"},
+       {"TX SMIC MUX6", "SWR_DMIC4", "TX SWR_DMIC4"},
+       {"TX SMIC MUX6", "SWR_DMIC5", "TX SWR_DMIC5"},
+       {"TX SMIC MUX6", "SWR_DMIC6", "TX SWR_DMIC6"},
+       {"TX SMIC MUX6", "SWR_DMIC7", "TX SWR_DMIC7"},
+
+       {"TX DEC7 MUX", "SWR_MIC", "TX SMIC MUX7"},
+       {"TX SMIC MUX7", NULL, "TX_SWR_CLK"},
+       {"TX SMIC MUX7", "ADC0", "TX SWR_ADC0"},
+       {"TX SMIC MUX7", "ADC1", "TX SWR_ADC1"},
+       {"TX SMIC MUX7", "ADC2", "TX SWR_ADC2"},
+       {"TX SMIC MUX7", "ADC3", "TX SWR_ADC3"},
+       {"TX SMIC MUX7", "SWR_DMIC0", "TX SWR_DMIC0"},
+       {"TX SMIC MUX7", "SWR_DMIC1", "TX SWR_DMIC1"},
+       {"TX SMIC MUX7", "SWR_DMIC2", "TX SWR_DMIC2"},
+       {"TX SMIC MUX7", "SWR_DMIC3", "TX SWR_DMIC3"},
+       {"TX SMIC MUX7", "SWR_DMIC4", "TX SWR_DMIC4"},
+       {"TX SMIC MUX7", "SWR_DMIC5", "TX SWR_DMIC5"},
+       {"TX SMIC MUX7", "SWR_DMIC6", "TX SWR_DMIC6"},
+       {"TX SMIC MUX7", "SWR_DMIC7", "TX SWR_DMIC7"},
+};
+
+static const struct snd_kcontrol_new tx_macro_snd_controls[] = {
+       SOC_SINGLE_S8_TLV("TX_DEC0 Volume",
+                         CDC_TX0_TX_VOL_CTL,
+                         -84, 40, digital_gain),
+       SOC_SINGLE_S8_TLV("TX_DEC1 Volume",
+                         CDC_TX1_TX_VOL_CTL,
+                         -84, 40, digital_gain),
+       SOC_SINGLE_S8_TLV("TX_DEC2 Volume",
+                         CDC_TX2_TX_VOL_CTL,
+                         -84, 40, digital_gain),
+       SOC_SINGLE_S8_TLV("TX_DEC3 Volume",
+                         CDC_TX3_TX_VOL_CTL,
+                         -84, 40, digital_gain),
+       SOC_SINGLE_S8_TLV("TX_DEC4 Volume",
+                         CDC_TX4_TX_VOL_CTL,
+                         -84, 40, digital_gain),
+       SOC_SINGLE_S8_TLV("TX_DEC5 Volume",
+                         CDC_TX5_TX_VOL_CTL,
+                         -84, 40, digital_gain),
+       SOC_SINGLE_S8_TLV("TX_DEC6 Volume",
+                         CDC_TX6_TX_VOL_CTL,
+                         -84, 40, digital_gain),
+       SOC_SINGLE_S8_TLV("TX_DEC7 Volume",
+                         CDC_TX7_TX_VOL_CTL,
+                         -84, 40, digital_gain),
+
+       SOC_ENUM_EXT("DEC0 MODE", dec_mode_mux_enum[0],
+                       tx_macro_dec_mode_get, tx_macro_dec_mode_put),
+
+       SOC_ENUM_EXT("DEC1 MODE", dec_mode_mux_enum[1],
+                       tx_macro_dec_mode_get, tx_macro_dec_mode_put),
+
+       SOC_ENUM_EXT("DEC2 MODE", dec_mode_mux_enum[2],
+                       tx_macro_dec_mode_get, tx_macro_dec_mode_put),
+
+       SOC_ENUM_EXT("DEC3 MODE", dec_mode_mux_enum[3],
+                       tx_macro_dec_mode_get, tx_macro_dec_mode_put),
+
+       SOC_ENUM_EXT("DEC4 MODE", dec_mode_mux_enum[4],
+                       tx_macro_dec_mode_get, tx_macro_dec_mode_put),
+
+       SOC_ENUM_EXT("DEC5 MODE", dec_mode_mux_enum[5],
+                       tx_macro_dec_mode_get, tx_macro_dec_mode_put),
+
+       SOC_ENUM_EXT("DEC6 MODE", dec_mode_mux_enum[6],
+                       tx_macro_dec_mode_get, tx_macro_dec_mode_put),
+
+       SOC_ENUM_EXT("DEC7 MODE", dec_mode_mux_enum[7],
+                       tx_macro_dec_mode_get, tx_macro_dec_mode_put),
+
+       SOC_SINGLE_EXT("DEC0_BCS Switch", SND_SOC_NOPM, 0, 1, 0,
+                      tx_macro_get_bcs, tx_macro_set_bcs),
+};
+
+static int tx_macro_component_probe(struct snd_soc_component *comp)
+{
+       struct tx_macro *tx = snd_soc_component_get_drvdata(comp);
+       int i;
+
+       snd_soc_component_init_regmap(comp, tx->regmap);
+
+       for (i = 0; i < NUM_DECIMATORS; i++) {
+               tx->tx_hpf_work[i].tx = tx;
+               tx->tx_hpf_work[i].decimator = i;
+               INIT_DELAYED_WORK(&tx->tx_hpf_work[i].dwork,
+                       tx_macro_tx_hpf_corner_freq_callback);
+       }
+
+       for (i = 0; i < NUM_DECIMATORS; i++) {
+               tx->tx_mute_dwork[i].tx = tx;
+               tx->tx_mute_dwork[i].decimator = i;
+               INIT_DELAYED_WORK(&tx->tx_mute_dwork[i].dwork,
+                         tx_macro_mute_update_callback);
+       }
+       tx->component = comp;
+
+       snd_soc_component_update_bits(comp, CDC_TX0_TX_PATH_SEC7, 0x3F,
+                                     0x0A);
+
+       return 0;
+}
+
+static int swclk_gate_enable(struct clk_hw *hw)
+{
+       struct tx_macro *tx = to_tx_macro(hw);
+       struct regmap *regmap = tx->regmap;
+
+       tx_macro_mclk_enable(tx, true);
+       if (tx->reset_swr)
+               regmap_update_bits(regmap, CDC_TX_CLK_RST_CTRL_SWR_CONTROL,
+                                  CDC_TX_SWR_RESET_MASK,
+                                  CDC_TX_SWR_RESET_ENABLE);
+
+       regmap_update_bits(regmap, CDC_TX_CLK_RST_CTRL_SWR_CONTROL,
+                          CDC_TX_SWR_CLK_EN_MASK,
+                          CDC_TX_SWR_CLK_ENABLE);
+       if (tx->reset_swr)
+               regmap_update_bits(regmap, CDC_TX_CLK_RST_CTRL_SWR_CONTROL,
+                                  CDC_TX_SWR_RESET_MASK, 0x0);
+       tx->reset_swr = false;
+
+       return 0;
+}
+
+static void swclk_gate_disable(struct clk_hw *hw)
+{
+       struct tx_macro *tx = to_tx_macro(hw);
+       struct regmap *regmap = tx->regmap;
+
+       regmap_update_bits(regmap, CDC_TX_CLK_RST_CTRL_SWR_CONTROL,
+                          CDC_TX_SWR_CLK_EN_MASK, 0x0);
+
+       tx_macro_mclk_enable(tx, false);
+}
+
+static int swclk_gate_is_enabled(struct clk_hw *hw)
+{
+       struct tx_macro *tx = to_tx_macro(hw);
+       int ret, val;
+
+       regmap_read(tx->regmap, CDC_TX_CLK_RST_CTRL_SWR_CONTROL, &val);
+       ret = val & BIT(0);
+
+       return ret;
+}
+
+static unsigned long swclk_recalc_rate(struct clk_hw *hw,
+                                      unsigned long parent_rate)
+{
+       return parent_rate / 2;
+}
+
+static const struct clk_ops swclk_gate_ops = {
+       .prepare = swclk_gate_enable,
+       .unprepare = swclk_gate_disable,
+       .is_enabled = swclk_gate_is_enabled,
+       .recalc_rate = swclk_recalc_rate,
+
+};
+
+static struct clk *tx_macro_register_mclk_output(struct tx_macro *tx)
+{
+       struct device *dev = tx->dev;
+       struct device_node *np = dev->of_node;
+       const char *parent_clk_name = NULL;
+       const char *clk_name = "lpass-tx-mclk";
+       struct clk_hw *hw;
+       struct clk_init_data init;
+       int ret;
+
+       parent_clk_name = __clk_get_name(tx->clks[2].clk);
+
+       init.name = clk_name;
+       init.ops = &swclk_gate_ops;
+       init.flags = 0;
+       init.parent_names = &parent_clk_name;
+       init.num_parents = 1;
+       tx->hw.init = &init;
+       hw = &tx->hw;
+       ret = clk_hw_register(tx->dev, hw);
+       if (ret)
+               return ERR_PTR(ret);
+
+       of_clk_add_provider(np, of_clk_src_simple_get, hw->clk);
+
+       return NULL;
+}
+
+static const struct snd_soc_component_driver tx_macro_component_drv = {
+       .name = "RX-MACRO",
+       .probe = tx_macro_component_probe,
+       .controls = tx_macro_snd_controls,
+       .num_controls = ARRAY_SIZE(tx_macro_snd_controls),
+       .dapm_widgets = tx_macro_dapm_widgets,
+       .num_dapm_widgets = ARRAY_SIZE(tx_macro_dapm_widgets),
+       .dapm_routes = tx_audio_map,
+       .num_dapm_routes = ARRAY_SIZE(tx_audio_map),
+};
+
+static int tx_macro_probe(struct platform_device *pdev)
+{
+       struct device *dev = &pdev->dev;
+       struct tx_macro *tx;
+       void __iomem *base;
+       int ret;
+
+       tx = devm_kzalloc(dev, sizeof(*tx), GFP_KERNEL);
+       if (!tx)
+               return -ENOMEM;
+
+       tx->clks[0].id = "macro";
+       tx->clks[1].id = "dcodec";
+       tx->clks[2].id = "mclk";
+       tx->clks[3].id = "npl";
+       tx->clks[4].id = "fsgen";
+
+       ret = devm_clk_bulk_get(dev, TX_NUM_CLKS_MAX, tx->clks);
+       if (ret) {
+               dev_err(dev, "Error getting RX Clocks (%d)\n", ret);
+               return ret;
+       }
+
+       base = devm_platform_ioremap_resource(pdev, 0);
+       if (IS_ERR(base))
+               return PTR_ERR(base);
+
+       tx->regmap = devm_regmap_init_mmio(dev, base, &tx_regmap_config);
+
+       dev_set_drvdata(dev, tx);
+
+       tx->reset_swr = true;
+       tx->dev = dev;
+
+       /* set MCLK and NPL rates */
+       clk_set_rate(tx->clks[2].clk, MCLK_FREQ);
+       clk_set_rate(tx->clks[3].clk, MCLK_FREQ);
+
+       ret = clk_bulk_prepare_enable(TX_NUM_CLKS_MAX, tx->clks);
+       if (ret)
+               return ret;
+
+       tx_macro_register_mclk_output(tx);
+
+       ret = devm_snd_soc_register_component(dev, &tx_macro_component_drv,
+                                             tx_macro_dai,
+                                             ARRAY_SIZE(tx_macro_dai));
+       if (ret)
+               goto err;
+       return ret;
+err:
+       clk_bulk_disable_unprepare(TX_NUM_CLKS_MAX, tx->clks);
+
+       return ret;
+}
+
+static int tx_macro_remove(struct platform_device *pdev)
+{
+       struct tx_macro *tx = dev_get_drvdata(&pdev->dev);
+
+       of_clk_del_provider(pdev->dev.of_node);
+
+       clk_bulk_disable_unprepare(TX_NUM_CLKS_MAX, tx->clks);
+
+       return 0;
+}
+
+static const struct of_device_id tx_macro_dt_match[] = {
+       { .compatible = "qcom,sm8250-lpass-tx-macro" },
+       { }
+};
+static struct platform_driver tx_macro_driver = {
+       .driver = {
+               .name = "tx_macro",
+               .of_match_table = tx_macro_dt_match,
+               .suppress_bind_attrs = true,
+       },
+       .probe = tx_macro_probe,
+       .remove = tx_macro_remove,
+};
+
+module_platform_driver(tx_macro_driver);
+
+MODULE_DESCRIPTION("TX macro driver");
+MODULE_LICENSE("GPL");
index 25f1df2..5ebcd93 100644 (file)
 #define CDC_WSA_TOP_I2S_CLK                    (0x00A4)
 #define CDC_WSA_TOP_I2S_RESET                  (0x00A8)
 #define CDC_WSA_RX_INP_MUX_RX_INT0_CFG0                (0x0100)
-#define CDC_WSA_RX_INTX_1_MIX_INP2_SEL_MASK    GENMASK(5, 3)
-#define CDC_WSA_RX_INTX_2_SEL_MASK             GENMASK(2, 0)
+#define CDC_WSA_RX_INTX_1_MIX_INP0_SEL_MASK    GENMASK(2, 0)
+#define CDC_WSA_RX_INTX_1_MIX_INP1_SEL_MASK    GENMASK(5, 3)
 #define CDC_WSA_RX_INP_MUX_RX_INT0_CFG1                (0x0104)
+#define CDC_WSA_RX_INTX_2_SEL_MASK             GENMASK(2, 0)
+#define CDC_WSA_RX_INTX_1_MIX_INP2_SEL_MASK    GENMASK(5, 3)
 #define CDC_WSA_RX_INP_MUX_RX_INT1_CFG0                (0x0108)
 #define CDC_WSA_RX_INP_MUX_RX_INT1_CFG1                (0x010C)
 #define CDC_WSA_RX_INP_MUX_RX_MIX_CFG0         (0x0110)
 #define NUM_INTERPOLATORS 2
 #define WSA_NUM_CLKS_MAX       5
 #define WSA_MACRO_MCLK_FREQ 19200000
-#define WSA_MACRO_MUX_INP_SHFT 0x3
-#define WSA_MACRO_MUX_INP_MASK1 0x07
 #define WSA_MACRO_MUX_INP_MASK2 0x38
 #define WSA_MACRO_MUX_CFG_OFFSET 0x8
 #define WSA_MACRO_MUX_CFG1_OFFSET 0x4
@@ -843,7 +843,6 @@ static int wsa_macro_set_prim_interpolator_rate(struct snd_soc_dai *dai,
        u32 j, port;
        u16 int_mux_cfg0, int_mux_cfg1;
        u16 int_fs_reg;
-       u8 int_mux_cfg0_val, int_mux_cfg1_val;
        u8 inp0_sel, inp1_sel, inp2_sel;
        struct snd_soc_component *component = dai->component;
        struct wsa_macro *wsa = snd_soc_component_get_drvdata(component);
@@ -865,15 +864,13 @@ static int wsa_macro_set_prim_interpolator_rate(struct snd_soc_dai *dai,
                 */
                for (j = 0; j < NUM_INTERPOLATORS; j++) {
                        int_mux_cfg1 = int_mux_cfg0 + WSA_MACRO_MUX_CFG1_OFFSET;
-                       int_mux_cfg0_val = snd_soc_component_read(component,
-                                                                 int_mux_cfg0);
-                       int_mux_cfg1_val = snd_soc_component_read(component,
-                                                                 int_mux_cfg1);
-                       inp0_sel = int_mux_cfg0_val & WSA_MACRO_MUX_INP_MASK1;
-                       inp1_sel = (int_mux_cfg0_val >> WSA_MACRO_MUX_INP_SHFT) &
-                                               WSA_MACRO_MUX_INP_MASK1;
-                       inp2_sel = (int_mux_cfg1_val >> WSA_MACRO_MUX_INP_SHFT) &
-                                               WSA_MACRO_MUX_INP_MASK1;
+                       inp0_sel = snd_soc_component_read_field(component, int_mux_cfg0, 
+                                                               CDC_WSA_RX_INTX_1_MIX_INP0_SEL_MASK);
+                       inp1_sel = snd_soc_component_read_field(component, int_mux_cfg0, 
+                                                               CDC_WSA_RX_INTX_1_MIX_INP1_SEL_MASK);
+                       inp2_sel = snd_soc_component_read_field(component, int_mux_cfg1,
+                                                               CDC_WSA_RX_INTX_1_MIX_INP2_SEL_MASK);
+
                        if ((inp0_sel == int_1_mix1_inp + INTn_1_INP_SEL_RX0) ||
                            (inp1_sel == int_1_mix1_inp + INTn_1_INP_SEL_RX0) ||
                            (inp2_sel == int_1_mix1_inp + INTn_1_INP_SEL_RX0)) {
@@ -912,9 +909,9 @@ static int wsa_macro_set_mix_interpolator_rate(struct snd_soc_dai *dai,
 
                int_mux_cfg1 = CDC_WSA_RX_INP_MUX_RX_INT0_CFG1;
                for (j = 0; j < NUM_INTERPOLATORS; j++) {
-                       int_mux_cfg1_val = snd_soc_component_read(component,
-                                                       int_mux_cfg1) &
-                                                       WSA_MACRO_MUX_INP_MASK1;
+                       int_mux_cfg1_val = snd_soc_component_read_field(component, int_mux_cfg1,
+                                                                       CDC_WSA_RX_INTX_2_SEL_MASK);
+
                        if (int_mux_cfg1_val == int_2_inp + INTn_2_INP_SEL_RX0) {
                                int_fs_reg = CDC_WSA_RX0_RX_PATH_MIX_CTL +
                                        WSA_MACRO_RX_PATH_OFFSET * j;
@@ -1410,25 +1407,25 @@ static bool wsa_macro_adie_lb(struct snd_soc_component *component,
                              int interp_idx)
 {
        u16 int_mux_cfg0,  int_mux_cfg1;
-       u8 int_mux_cfg0_val, int_mux_cfg1_val;
        u8 int_n_inp0, int_n_inp1, int_n_inp2;
 
        int_mux_cfg0 = CDC_WSA_RX_INP_MUX_RX_INT0_CFG0 + interp_idx * 8;
        int_mux_cfg1 = int_mux_cfg0 + 4;
-       int_mux_cfg0_val = snd_soc_component_read(component, int_mux_cfg0);
-       int_mux_cfg1_val = snd_soc_component_read(component, int_mux_cfg1);
 
-       int_n_inp0 = int_mux_cfg0_val & 0x0F;
+       int_n_inp0 = snd_soc_component_read_field(component, int_mux_cfg0,
+                                                 CDC_WSA_RX_INTX_1_MIX_INP0_SEL_MASK);
        if (int_n_inp0 == INTn_1_INP_SEL_DEC0 ||
                int_n_inp0 == INTn_1_INP_SEL_DEC1)
                return true;
 
-       int_n_inp1 = int_mux_cfg0_val >> 4;
+       int_n_inp1 = snd_soc_component_read_field(component, int_mux_cfg0,
+                                                 CDC_WSA_RX_INTX_1_MIX_INP1_SEL_MASK);
        if (int_n_inp1 == INTn_1_INP_SEL_DEC0 ||
                int_n_inp1 == INTn_1_INP_SEL_DEC1)
                return true;
 
-       int_n_inp2 = int_mux_cfg1_val >> 4;
+       int_n_inp2 = snd_soc_component_read_field(component, int_mux_cfg1,
+                                                 CDC_WSA_RX_INTX_1_MIX_INP2_SEL_MASK);
        if (int_n_inp2 == INTn_1_INP_SEL_DEC0 ||
                int_n_inp2 == INTn_1_INP_SEL_DEC1)
                return true;
index b8d471d..d8c4766 100644 (file)
@@ -262,6 +262,8 @@ static __maybe_unused int max98373_suspend(struct device *dev)
        return 0;
 }
 
+#define MAX98373_PROBE_TIMEOUT 5000
+
 static __maybe_unused int max98373_resume(struct device *dev)
 {
        struct sdw_slave *slave = dev_to_sdw_dev(dev);
@@ -275,7 +277,7 @@ static __maybe_unused int max98373_resume(struct device *dev)
                goto regmap_sync;
 
        time = wait_for_completion_timeout(&slave->initialization_complete,
-                                          msecs_to_jiffies(2000));
+                                          msecs_to_jiffies(MAX98373_PROBE_TIMEOUT));
        if (!time) {
                dev_err(dev, "Initialization not complete, timed out\n");
                return -ETIMEDOUT;
index 31d571d..746c829 100644 (file)
@@ -190,7 +190,7 @@ static int max98373_feedback_get(struct snd_kcontrol *kcontrol,
                }
        }
 
-       return snd_soc_put_volsw(kcontrol, ucontrol);
+       return snd_soc_get_volsw(kcontrol, ucontrol);
 }
 
 static const struct snd_kcontrol_new max98373_snd_controls[] = {
index d5925c4..dd29b18 100644 (file)
@@ -489,7 +489,7 @@ static struct snd_soc_dai_driver max9860_dai = {
                           SNDRV_PCM_FMTBIT_S32_LE,
        },
        .ops = &max9860_dai_ops,
-       .symmetric_rates = 1,
+       .symmetric_rate = 1,
 };
 
 static int max9860_set_bias_level(struct snd_soc_component *component,
index 512e6f2..09b2d73 100644 (file)
@@ -520,7 +520,7 @@ static struct snd_soc_dai_driver max9867_dai[] = {
                .formats = SNDRV_PCM_FMTBIT_S16_LE,
        },
        .ops = &max9867_dai_ops,
-       .symmetric_rates = 1,
+       .symmetric_rate = 1,
        }
 };
 
index 9e6a0cd..a210725 100644 (file)
@@ -712,7 +712,7 @@ static struct snd_soc_dai_driver mc13783_dai_sync[] = {
                        .formats = MC13783_FORMATS,
                },
                .ops = &mc13783_ops_sync,
-               .symmetric_rates = 1,
+               .symmetric_rate = 1,
        }
 };
 
index 70c17be..4d7c0be 100644 (file)
@@ -513,7 +513,7 @@ static struct snd_soc_dai_driver ml26124_dai = {
                .rates = ML26124_RATES,
                .formats = ML26124_FORMATS,},
        .ops = &ml26124_dai_ops,
-       .symmetric_rates = 1,
+       .symmetric_rate = 1,
 };
 
 static int ml26124_probe(struct snd_soc_component *component)
index 6de0d74..6f4b1da 100644 (file)
@@ -2754,7 +2754,8 @@ static int mt6359_parse_dt(struct mt6359_priv *priv)
        ret = of_property_read_u32(np, "mediatek,dmic-mode",
                                   &priv->dmic_one_wire_mode);
        if (ret) {
-               dev_warn(priv->dev, "%s() failed to read dmic-mode\n",
+               dev_info(priv->dev,
+                        "%s() failed to read dmic-mode, use default (0)\n",
                         __func__);
                priv->dmic_one_wire_mode = 0;
        }
@@ -2762,24 +2763,27 @@ static int mt6359_parse_dt(struct mt6359_priv *priv)
        ret = of_property_read_u32(np, "mediatek,mic-type-0",
                                   &priv->mux_select[MUX_MIC_TYPE_0]);
        if (ret) {
-               dev_warn(priv->dev, "%s() failed to read mic-type-0\n",
-                        __func__);
+               dev_info(priv->dev,
+                        "%s() failed to read mic-type-0, use default (%d)\n",
+                        __func__, MIC_TYPE_MUX_IDLE);
                priv->mux_select[MUX_MIC_TYPE_0] = MIC_TYPE_MUX_IDLE;
        }
 
        ret = of_property_read_u32(np, "mediatek,mic-type-1",
                                   &priv->mux_select[MUX_MIC_TYPE_1]);
        if (ret) {
-               dev_warn(priv->dev, "%s() failed to read mic-type-1\n",
-                        __func__);
+               dev_info(priv->dev,
+                        "%s() failed to read mic-type-1, use default (%d)\n",
+                        __func__, MIC_TYPE_MUX_IDLE);
                priv->mux_select[MUX_MIC_TYPE_1] = MIC_TYPE_MUX_IDLE;
        }
 
        ret = of_property_read_u32(np, "mediatek,mic-type-2",
                                   &priv->mux_select[MUX_MIC_TYPE_2]);
        if (ret) {
-               dev_warn(priv->dev, "%s() failed to read mic-type-2\n",
-                        __func__);
+               dev_info(priv->dev,
+                        "%s() failed to read mic-type-2, use default (%d)\n",
+                        __func__, MIC_TYPE_MUX_IDLE);
                priv->mux_select[MUX_MIC_TYPE_2] = MIC_TYPE_MUX_IDLE;
        }
 
index d179700..358c500 100644 (file)
@@ -404,9 +404,9 @@ static struct snd_soc_dai_driver mt6660_codec_dai = {
                .formats = STUB_FORMATS,
        },
        /* dai properties */
-       .symmetric_rates = 1,
+       .symmetric_rate = 1,
        .symmetric_channels = 1,
-       .symmetric_samplebits = 1,
+       .symmetric_sample_bits = 1,
        /* dai operations */
        .ops = &mt6660_component_aif_ops,
 };
index 33ebc63..13676b5 100644 (file)
@@ -837,7 +837,7 @@ static struct snd_soc_dai_driver nau8810_dai = {
                .formats = NAU8810_FORMATS,
        },
        .ops = &nau8810_ops,
-       .symmetric_rates = 1,
+       .symmetric_rate = 1,
 };
 
 static const struct regmap_config nau8810_regmap_config = {
index 609aeeb..5812339 100644 (file)
@@ -991,7 +991,7 @@ static struct snd_soc_dai_driver nau8822_dai = {
                .formats = NAU8822_FORMATS,
        },
        .ops = &nau8822_dai_ops,
-       .symmetric_rates = 1,
+       .symmetric_rate = 1,
 };
 
 static int nau8822_suspend(struct snd_soc_component *component)
index 32e6bcf..37b5795 100644 (file)
 #include <sound/initval.h>
 #include <sound/pcm.h>
 #include <sound/pcm_params.h>
+#include <sound/rt1015.h>
 #include <sound/soc-dapm.h>
 #include <sound/soc.h>
 #include <sound/tlv.h>
-#include <sound/rt1015.h>
 
 #include "rl6231.h"
 #include "rt1015.h"
@@ -444,10 +444,9 @@ static int rt1015_boost_mode_put(struct snd_kcontrol *kcontrol,
                snd_soc_kcontrol_component(kcontrol);
        struct rt1015_priv *rt1015 =
                snd_soc_component_get_drvdata(component);
+       int boost_mode = ucontrol->value.integer.value[0];
 
-       rt1015->boost_mode = ucontrol->value.integer.value[0];
-
-       switch (rt1015->boost_mode) {
+       switch (boost_mode) {
        case BYPASS:
                snd_soc_component_update_bits(component,
                        RT1015_SMART_BST_CTRL1, RT1015_ABST_AUTO_EN_MASK |
@@ -471,8 +470,11 @@ static int rt1015_boost_mode_put(struct snd_kcontrol *kcontrol,
                break;
        default:
                dev_err(component->dev, "Unknown boost control.\n");
+               return -EINVAL;
        }
 
+       rt1015->boost_mode = boost_mode;
+
        return 0;
 }
 
@@ -497,40 +499,20 @@ static void rt1015_calibrate(struct rt1015_priv *rt1015)
        snd_soc_dapm_mutex_lock(&component->dapm);
        regcache_cache_bypass(regmap, true);
 
-       regmap_write(regmap, RT1015_PWR9, 0xAA60);
-       regmap_write(regmap, RT1015_PWR_STATE_CTRL, 0x0089);
-       regmap_write(regmap, RT1015_PWR_STATE_CTRL, 0x008A);
-       regmap_write(regmap, RT1015_PWR_STATE_CTRL, 0x008C);
-       regmap_write(regmap, RT1015_PWR_STATE_CTRL, 0x008D);
-       regmap_write(regmap, RT1015_PWR4, 0x80B2);
-       regmap_write(regmap, RT1015_CLASSD_SEQ, 0x5797);
-       regmap_write(regmap, RT1015_CLSD_INTERNAL8, 0x2100);
-       regmap_write(regmap, RT1015_CLSD_INTERNAL9, 0x0100);
-       regmap_write(regmap, RT1015_PWR5, 0x2175);
-       regmap_write(regmap, RT1015_MIXER1, 0x005D);
-       regmap_write(regmap, RT1015_CLSD_INTERNAL1, 0x00A1);
-       regmap_write(regmap, RT1015_CLSD_INTERNAL2, 0x12F7);
-       regmap_write(regmap, RT1015_DC_CALIB_CLSD1, 0x1205);
-       msleep(200);
-       regmap_write(regmap, RT1015_CLSD_INTERNAL8, 0x2000);
-       regmap_write(regmap, RT1015_CLSD_INTERNAL9, 0x0180);
-       regmap_write(regmap, RT1015_CLSD_INTERNAL1, 0x00A1);
-       regmap_write(regmap, RT1015_DC_CALIB_CLSD1, 0x0A05);
-       msleep(200);
+       regmap_write(regmap, RT1015_CLK_DET, 0x0000);
        regmap_write(regmap, RT1015_PWR4, 0x00B2);
+       regmap_write(regmap, RT1015_PWR_STATE_CTRL, 0x0009);
+       msleep(100);
+       regmap_write(regmap, RT1015_PWR_STATE_CTRL, 0x000A);
+       msleep(100);
+       regmap_write(regmap, RT1015_PWR_STATE_CTRL, 0x000C);
+       msleep(100);
        regmap_write(regmap, RT1015_CLSD_INTERNAL8, 0x2028);
        regmap_write(regmap, RT1015_CLSD_INTERNAL9, 0x0140);
-       regmap_write(regmap, RT1015_PWR5, 0x0175);
-       regmap_write(regmap, RT1015_CLSD_INTERNAL1, 0x1721);
-       regmap_write(regmap, RT1015_CLASSD_SEQ, 0x570E);
-       regmap_write(regmap, RT1015_MIXER1, 0x203D);
-       regmap_write(regmap, RT1015_DC_CALIB_CLSD1, 0x5A01);
-       regmap_write(regmap, RT1015_CLSD_INTERNAL2, 0x12FF);
-       regmap_write(regmap, RT1015_GAT_BOOST, 0x0eFE);
-       regmap_write(regmap, RT1015_PWR_STATE_CTRL, 0x008E);
-       regmap_write(regmap, RT1015_PWR_STATE_CTRL, 0x0088);
+       regmap_write(regmap, RT1015_PWR_STATE_CTRL, 0x000D);
+       msleep(300);
+       regmap_write(regmap, RT1015_PWR_STATE_CTRL, 0x0008);
        regmap_write(regmap, RT1015_SYS_RST1, 0x05F5);
-       regmap_write(regmap, RT1015_SYS_RST2, 0x0b9a);
 
        regcache_cache_bypass(regmap, false);
        regcache_mark_dirty(regmap);
@@ -546,17 +528,19 @@ static int rt1015_bypass_boost_put(struct snd_kcontrol *kcontrol,
        struct rt1015_priv *rt1015 =
                snd_soc_component_get_drvdata(component);
 
-       if (!rt1015->dac_is_used) {
-               rt1015->bypass_boost = ucontrol->value.integer.value[0];
-               if (rt1015->bypass_boost == RT1015_Bypass_Boost &&
+       if (rt1015->dac_is_used) {
+               dev_err(component->dev, "DAC is being used!\n");
+               return -EBUSY;
+       }
+
+       rt1015->bypass_boost = ucontrol->value.integer.value[0];
+       if (rt1015->bypass_boost == RT1015_Bypass_Boost &&
                        !rt1015->cali_done) {
-                       rt1015_calibrate(rt1015);
-                       rt1015->cali_done = 1;
+               rt1015_calibrate(rt1015);
+               rt1015->cali_done = 1;
 
-                       regmap_write(rt1015->regmap, RT1015_MONO_DYNA_CTRL, 0x0010);
-               }
-       } else
-               dev_err(component->dev, "DAC is being used!\n");
+               regmap_write(rt1015->regmap, RT1015_MONO_DYNA_CTRL, 0x0010);
+       }
 
        return 0;
 }
@@ -566,15 +550,14 @@ static void rt1015_flush_work(struct work_struct *work)
        struct rt1015_priv *rt1015 = container_of(work, struct rt1015_priv,
                                                flush_work.work);
        struct snd_soc_component *component = rt1015->component;
-       unsigned int val, i = 0, count = 200;
+       unsigned int val, i;
 
-       while (i < count) {
+       for (i = 0; i < 200; ++i) {
                usleep_range(1000, 1500);
                dev_dbg(component->dev, "Flush DAC (retry:%u)\n", i);
                regmap_read(rt1015->regmap, RT1015_CLK_DET, &val);
                if (val & 0x800)
                        break;
-               i++;
        }
 
        regmap_write(rt1015->regmap, RT1015_SYS_RST1, 0x0597);
@@ -721,11 +704,11 @@ static int rt1015_hw_params(struct snd_pcm_substream *substream,
 {
        struct snd_soc_component *component = dai->component;
        struct rt1015_priv *rt1015 = snd_soc_component_get_drvdata(component);
-       int pre_div, bclk_ms, frame_size;
+       int pre_div, bclk_ms, frame_size, lrck;
        unsigned int val_len = 0;
 
-       rt1015->lrck = params_rate(params);
-       pre_div = rl6231_get_clk_info(rt1015->sysclk, rt1015->lrck);
+       lrck = params_rate(params);
+       pre_div = rl6231_get_clk_info(rt1015->sysclk, lrck);
        if (pre_div < 0) {
                dev_err(component->dev, "Unsupported clock rate\n");
                return -EINVAL;
@@ -739,13 +722,12 @@ static int rt1015_hw_params(struct snd_pcm_substream *substream,
        }
 
        bclk_ms = frame_size > 32;
-       rt1015->bclk = rt1015->lrck * (32 << bclk_ms);
 
        dev_dbg(component->dev, "bclk_ms is %d and pre_div is %d for iis %d\n",
                                bclk_ms, pre_div, dai->id);
 
        dev_dbg(component->dev, "lrck is %dHz and pre_div is %d for iis %d\n",
-                               rt1015->lrck, pre_div, dai->id);
+                               lrck, pre_div, dai->id);
 
        switch (params_width(params)) {
        case 16:
@@ -882,14 +864,6 @@ static int rt1015_set_component_pll(struct snd_soc_component *component,
                freq_out == rt1015->pll_out)
                return 0;
 
-       if (source == RT1015_PLL_S_BCLK) {
-               if (rt1015->bclk_ratio == 0) {
-                       dev_err(component->dev,
-                               "Can not support bclk ratio as 0.\n");
-                       return -EINVAL;
-               }
-       }
-
        switch (source) {
        case RT1015_PLL_S_MCLK:
                snd_soc_component_update_bits(component, RT1015_CLK2,
@@ -929,23 +903,6 @@ static int rt1015_set_component_pll(struct snd_soc_component *component,
        return 0;
 }
 
-static int rt1015_set_bclk_ratio(struct snd_soc_dai *dai, unsigned int ratio)
-{
-       struct snd_soc_component *component = dai->component;
-       struct rt1015_priv *rt1015 = snd_soc_component_get_drvdata(component);
-
-       dev_dbg(component->dev, "%s ratio=%d\n", __func__, ratio);
-
-       rt1015->bclk_ratio = ratio;
-
-       if (ratio == 50) {
-               dev_dbg(component->dev, "Unsupport bclk ratio\n");
-               return -EINVAL;
-       }
-
-       return 0;
-}
-
 static int rt1015_set_tdm_slot(struct snd_soc_dai *dai,
        unsigned int tx_mask, unsigned int rx_mask, int slots, int slot_width)
 {
@@ -1052,9 +1009,6 @@ static int rt1015_probe(struct snd_soc_component *component)
                snd_soc_component_get_drvdata(component);
 
        rt1015->component = component;
-       rt1015->bclk_ratio = 0;
-       rt1015->cali_done = 0;
-
        INIT_DELAYED_WORK(&rt1015->flush_work, rt1015_flush_work);
 
        return 0;
@@ -1075,7 +1029,6 @@ static void rt1015_remove(struct snd_soc_component *component)
 static struct snd_soc_dai_ops rt1015_aif_dai_ops = {
        .hw_params = rt1015_hw_params,
        .set_fmt = rt1015_set_dai_fmt,
-       .set_bclk_ratio = rt1015_set_bclk_ratio,
        .set_tdm_slot = rt1015_set_tdm_slot,
 };
 
@@ -1111,6 +1064,10 @@ static int rt1015_resume(struct snd_soc_component *component)
 
        regcache_cache_only(rt1015->regmap, false);
        regcache_sync(rt1015->regmap);
+
+       if (rt1015->cali_done)
+               rt1015_calibrate(rt1015);
+
        return 0;
 }
 #else
@@ -1183,9 +1140,8 @@ static int rt1015_i2c_probe(struct i2c_client *i2c,
        int ret;
        unsigned int val;
 
-       rt1015 = devm_kzalloc(&i2c->dev, sizeof(struct rt1015_priv),
-                               GFP_KERNEL);
-       if (rt1015 == NULL)
+       rt1015 = devm_kzalloc(&i2c->dev, sizeof(*rt1015), GFP_KERNEL);
+       if (!rt1015)
                return -ENOMEM;
 
        i2c_set_clientdata(i2c, rt1015);
index b6ea753..2aeaf65 100644 (file)
@@ -427,16 +427,11 @@ struct rt1015_priv {
        struct regmap *regmap;
        int sysclk;
        int sysclk_src;
-       int lrck;
-       int bclk;
-       int bclk_ratio;
-       int id;
        int pll_src;
        int pll_in;
        int pll_out;
        int boost_mode;
        int bypass_boost;
-       int amp_ver;
        int dac_is_used;
        int cali_done;
        int hw_config;
index ec5564f..afd2c3b 100644 (file)
@@ -701,7 +701,7 @@ static int __maybe_unused rt1308_dev_suspend(struct device *dev)
        return 0;
 }
 
-#define RT1308_PROBE_TIMEOUT 2000
+#define RT1308_PROBE_TIMEOUT 5000
 
 static int __maybe_unused rt1308_dev_resume(struct device *dev)
 {
index 70cf17c..0d3773c 100644 (file)
@@ -1056,7 +1056,7 @@ static struct snd_soc_dai_driver rt274_dai[] = {
                        .formats = RT274_FORMATS,
                },
                .ops = &rt274_aif_dai_ops,
-               .symmetric_rates = 1,
+               .symmetric_rate = 1,
        },
 };
 
index 5fb9653..8abe232 100644 (file)
@@ -1017,7 +1017,7 @@ static struct snd_soc_dai_driver rt286_dai[] = {
                        .formats = RT286_FORMATS,
                },
                .ops = &rt286_aif_dai_ops,
-               .symmetric_rates = 1,
+               .symmetric_rate = 1,
        },
        {
                .name = "rt286-aif2",
@@ -1037,7 +1037,7 @@ static struct snd_soc_dai_driver rt286_dai[] = {
                        .formats = RT286_FORMATS,
                },
                .ops = &rt286_aif_dai_ops,
-               .symmetric_rates = 1,
+               .symmetric_rate = 1,
        },
 
 };
index dc0273a..32cc9b6 100644 (file)
@@ -1084,7 +1084,7 @@ static struct snd_soc_dai_driver rt298_dai[] = {
                        .formats = RT298_FORMATS,
                },
                .ops = &rt298_aif_dai_ops,
-               .symmetric_rates = 1,
+               .symmetric_rate = 1,
        },
        {
                .name = "rt298-aif2",
@@ -1104,7 +1104,7 @@ static struct snd_soc_dai_driver rt298_dai[] = {
                        .formats = RT298_FORMATS,
                },
                .ops = &rt298_aif_dai_ops,
-               .symmetric_rates = 1,
+               .symmetric_rate = 1,
        },
 
 };
index 420003d..63a7e05 100644 (file)
@@ -34,6 +34,7 @@
 #define QUIRK_INV_JD1_1(q)     ((q) & 1)
 #define QUIRK_LEVEL_IRQ(q)     (((q) >> 1) & 1)
 #define QUIRK_IN2_DIFF(q)      (((q) >> 2) & 1)
+#define QUIRK_INV_HP_POL(q)    (((q) >> 3) & 1)
 #define QUIRK_JD_MODE(q)       (((q) >> 4) & 7)
 #define QUIRK_DMIC1_DATA_PIN(q)        (((q) >> 8) & 3)
 #define QUIRK_DMIC2_DATA_PIN(q)        (((q) >> 12) & 3)
@@ -42,6 +43,8 @@ static unsigned int quirk = -1;
 module_param(quirk, uint, 0444);
 MODULE_PARM_DESC(quirk, "RT5645 pdata quirk override");
 
+static const struct acpi_gpio_mapping *cht_rt5645_gpios;
+
 #define RT5645_DEVICE_ID 0x6308
 #define RT5650_DEVICE_ID 0x6419
 
@@ -435,7 +438,6 @@ struct rt5645_priv {
 
        int jack_type;
        bool en_button_func;
-       bool hp_on;
        int v_id;
 };
 
@@ -1645,6 +1647,7 @@ static void hp_amp_power(struct snd_soc_component *component, int on)
 {
        static int hp_amp_power_count;
        struct rt5645_priv *rt5645 = snd_soc_component_get_drvdata(component);
+       int i, val;
 
        if (on) {
                if (hp_amp_power_count <= 0) {
@@ -1655,7 +1658,13 @@ static void hp_amp_power(struct snd_soc_component *component, int on)
                                snd_soc_component_write(component, RT5645_DEPOP_M1, 0x000d);
                                regmap_write(rt5645->regmap, RT5645_PR_BASE +
                                        RT5645_HP_DCC_INT1, 0x9f01);
-                               msleep(20);
+                               for (i = 0; i < 20; i++) {
+                                       usleep_range(1000, 1500);
+                                       regmap_read(rt5645->regmap, RT5645_PR_BASE +
+                                               RT5645_HP_DCC_INT1, &val);
+                                       if (!(val & 0x8000))
+                                               break;
+                               }
                                snd_soc_component_update_bits(component, RT5645_DEPOP_M1,
                                        RT5645_HP_CO_MASK, RT5645_HP_CO_EN);
                                regmap_write(rt5645->regmap, RT5645_PR_BASE +
@@ -1665,7 +1674,6 @@ static void hp_amp_power(struct snd_soc_component *component, int on)
                                        RT5645_MAMP_INT_REG2, 0xfc00);
                                snd_soc_component_write(component, RT5645_DEPOP_M2, 0x1140);
                                msleep(90);
-                               rt5645->hp_on = true;
                        } else {
                                /* depop parameters */
                                snd_soc_component_update_bits(component, RT5645_DEPOP_M2,
@@ -1885,27 +1893,6 @@ static int rt5645_bst2_event(struct snd_soc_dapm_widget *w,
        return 0;
 }
 
-static int rt5650_hp_event(struct snd_soc_dapm_widget *w,
-               struct snd_kcontrol *k, int  event)
-{
-       struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
-       struct rt5645_priv *rt5645 = snd_soc_component_get_drvdata(component);
-
-       switch (event) {
-       case SND_SOC_DAPM_POST_PMU:
-               if (rt5645->hp_on) {
-                       msleep(100);
-                       rt5645->hp_on = false;
-               }
-               break;
-
-       default:
-               return 0;
-       }
-
-       return 0;
-}
-
 static int rt5645_set_micbias1_event(struct snd_soc_dapm_widget *w,
                struct snd_kcontrol *k, int  event)
 {
@@ -2242,7 +2229,6 @@ static const struct snd_soc_dapm_widget rt5645_dapm_widgets[] = {
        SND_SOC_DAPM_OUTPUT("PDM1R"),
        SND_SOC_DAPM_OUTPUT("SPOL"),
        SND_SOC_DAPM_OUTPUT("SPOR"),
-       SND_SOC_DAPM_POST("DAPM_POST", rt5650_hp_event),
 };
 
 static const struct snd_soc_dapm_widget rt5645_specific_dapm_widgets[] = {
@@ -3261,6 +3247,8 @@ static void rt5645_jack_detect_work(struct work_struct *work)
        case 0: /* Not using rt5645 JD */
                if (rt5645->gpiod_hp_det) {
                        gpio_state = gpiod_get_value(rt5645->gpiod_hp_det);
+                       if (rt5645->pdata.inv_hp_pol)
+                               gpio_state ^= 1;
                        dev_dbg(rt5645->component->dev, "gpio_state = %d\n",
                                gpio_state);
                        report = rt5645_jack_detect(rt5645->component, gpio_state);
@@ -3651,6 +3639,25 @@ static const struct rt5645_platform_data kahlee_platform_data = {
        .jd_mode = 3,
 };
 
+static const struct rt5645_platform_data ecs_ef20_platform_data = {
+       .dmic1_data_pin = RT5645_DMIC1_DISABLE,
+       .dmic2_data_pin = RT5645_DMIC_DATA_IN2P,
+       .inv_hp_pol = 1,
+};
+
+static const struct acpi_gpio_params ef20_hp_detect = { 1, 0, false };
+
+static const struct acpi_gpio_mapping cht_rt5645_ef20_gpios[] = {
+       { "hp-detect-gpios", &ef20_hp_detect, 1 },
+       { },
+};
+
+static int cht_rt5645_ef20_quirk_cb(const struct dmi_system_id *id)
+{
+       cht_rt5645_gpios = cht_rt5645_ef20_gpios;
+       return 1;
+}
+
 static const struct dmi_system_id dmi_platform_data[] = {
        {
                .ident = "Chrome Buddy",
@@ -3780,6 +3787,22 @@ static const struct dmi_system_id dmi_platform_data[] = {
                },
                .driver_data = (void *)&intel_braswell_platform_data,
        },
+       {
+               .ident = "EF20",
+               .callback = cht_rt5645_ef20_quirk_cb,
+               .matches = {
+                       DMI_MATCH(DMI_PRODUCT_NAME, "EF20"),
+               },
+               .driver_data = (void *)&ecs_ef20_platform_data,
+       },
+       {
+               .ident = "EF20EA",
+               .callback = cht_rt5645_ef20_quirk_cb,
+               .matches = {
+                       DMI_MATCH(DMI_PRODUCT_NAME, "EF20EA"),
+               },
+               .driver_data = (void *)&ecs_ef20_platform_data,
+       },
        { }
 };
 
@@ -3843,11 +3866,16 @@ static int rt5645_i2c_probe(struct i2c_client *i2c,
                rt5645->pdata.in2_diff = QUIRK_IN2_DIFF(quirk);
                rt5645->pdata.level_trigger_irq = QUIRK_LEVEL_IRQ(quirk);
                rt5645->pdata.inv_jd1_1 = QUIRK_INV_JD1_1(quirk);
+               rt5645->pdata.inv_hp_pol = QUIRK_INV_HP_POL(quirk);
                rt5645->pdata.jd_mode = QUIRK_JD_MODE(quirk);
                rt5645->pdata.dmic1_data_pin = QUIRK_DMIC1_DATA_PIN(quirk);
                rt5645->pdata.dmic2_data_pin = QUIRK_DMIC2_DATA_PIN(quirk);
        }
 
+       if (cht_rt5645_gpios && has_acpi_companion(&i2c->dev))
+               if (devm_acpi_dev_add_driver_gpios(&i2c->dev, cht_rt5645_gpios))
+                       dev_dbg(&i2c->dev, "Failed to add driver gpios\n");
+
        rt5645->gpiod_hp_det = devm_gpiod_get_optional(&i2c->dev, "hp-detect",
                                                       GPIOD_IN);
 
index a0c8f58..c29317e 100644 (file)
@@ -2741,7 +2741,7 @@ static struct snd_soc_dai_driver rt5670_dai[] = {
                        .formats = RT5670_FORMATS,
                },
                .ops = &rt5670_aif_dai_ops,
-               .symmetric_rates = 1,
+               .symmetric_rate = 1,
        },
        {
                .name = "rt5670-aif2",
@@ -2761,7 +2761,7 @@ static struct snd_soc_dai_driver rt5670_dai[] = {
                        .formats = RT5670_FORMATS,
                },
                .ops = &rt5670_aif_dai_ops,
-               .symmetric_rates = 1,
+               .symmetric_rate = 1,
        },
 };
 
index 37d1312..93c1603 100644 (file)
@@ -273,6 +273,9 @@ static void rt5682_i2c_shutdown(struct i2c_client *client)
 {
        struct rt5682_priv *rt5682 = i2c_get_clientdata(client);
 
+       cancel_delayed_work_sync(&rt5682->jack_detect_work);
+       cancel_delayed_work_sync(&rt5682->jd_check_work);
+
        rt5682_reset(rt5682);
 }
 
index 4d707e8..b49f1e1 100644 (file)
@@ -375,18 +375,12 @@ static int rt5682_sdw_init(struct device *dev, struct regmap *regmap,
 static int rt5682_io_init(struct device *dev, struct sdw_slave *slave)
 {
        struct rt5682_priv *rt5682 = dev_get_drvdata(dev);
-       int ret = 0;
+       int ret = 0, loop = 10;
        unsigned int val;
 
        if (rt5682->hw_init)
                return 0;
 
-       regmap_read(rt5682->regmap, RT5682_DEVICE_ID, &val);
-       if (val != DEVICE_ID) {
-               dev_err(dev, "Device with ID register %x is not rt5682\n", val);
-               return -ENODEV;
-       }
-
        /*
         * PM runtime is only enabled when a Slave reports as Attached
         */
@@ -406,6 +400,19 @@ static int rt5682_io_init(struct device *dev, struct sdw_slave *slave)
 
        pm_runtime_get_noresume(&slave->dev);
 
+       while (loop > 0) {
+               regmap_read(rt5682->regmap, RT5682_DEVICE_ID, &val);
+               if (val == DEVICE_ID)
+                       break;
+               dev_warn(dev, "Device with ID register %x is not rt5682\n", val);
+               usleep_range(30000, 30005);
+               loop--;
+       }
+       if (val != DEVICE_ID) {
+               dev_err(dev, "Device with ID register %x is not rt5682\n", val);
+               return -ENODEV;
+       }
+
        if (rt5682->first_hw_init) {
                regcache_cache_only(rt5682->regmap, false);
                regcache_cache_bypass(rt5682->regmap, true);
@@ -703,7 +710,7 @@ static int rt5682_sdw_remove(struct sdw_slave *slave)
        struct rt5682_priv *rt5682 = dev_get_drvdata(&slave->dev);
 
        if (rt5682 && rt5682->hw_init)
-               cancel_delayed_work(&rt5682->jack_detect_work);
+               cancel_delayed_work_sync(&rt5682->jack_detect_work);
 
        return 0;
 }
@@ -721,6 +728,8 @@ static int __maybe_unused rt5682_dev_suspend(struct device *dev)
        if (!rt5682->hw_init)
                return 0;
 
+       cancel_delayed_work_sync(&rt5682->jack_detect_work);
+
        regcache_cache_only(rt5682->regmap, true);
        regcache_mark_dirty(rt5682->regmap);
 
index 4d865ed..b306ac4 100644 (file)
@@ -953,6 +953,8 @@ int rt5682_headset_detect(struct snd_soc_component *component, int jack_insert)
                case 0x1:
                case 0x2:
                        rt5682->jack_type = SND_JACK_HEADSET;
+                       snd_soc_component_update_bits(component, RT5682_CBJ_CTRL_1,
+                               RT5682_FAST_OFF_MASK, RT5682_FAST_OFF_EN);
                        rt5682_enable_push_button_irq(component, true);
                        break;
                default:
@@ -982,6 +984,8 @@ int rt5682_headset_detect(struct snd_soc_component *component, int jack_insert)
                snd_soc_component_update_bits(component, RT5682_MICBIAS_2,
                        RT5682_PWR_CLK25M_MASK | RT5682_PWR_CLK1M_MASK,
                        RT5682_PWR_CLK25M_PD | RT5682_PWR_CLK1M_PD);
+               snd_soc_component_update_bits(component, RT5682_CBJ_CTRL_1,
+                       RT5682_FAST_OFF_MASK, RT5682_FAST_OFF_DIS);
 
                rt5682->jack_type = 0;
        }
@@ -1011,11 +1015,13 @@ static int rt5682_set_jack_detect(struct snd_soc_component *component,
        if (!rt5682->is_sdw) {
                switch (rt5682->pdata.jd_src) {
                case RT5682_JD1:
+                       snd_soc_component_update_bits(component,
+                               RT5682_CBJ_CTRL_5, 0x0700, 0x0600);
                        snd_soc_component_update_bits(component,
                                RT5682_CBJ_CTRL_2, RT5682_EXT_JD_SRC,
                                RT5682_EXT_JD_SRC_MANUAL);
                        snd_soc_component_write(component, RT5682_CBJ_CTRL_1,
-                               0xd042);
+                               0xd142);
                        snd_soc_component_update_bits(component,
                                RT5682_CBJ_CTRL_3, RT5682_CBJ_IN_BUF_EN,
                                RT5682_CBJ_IN_BUF_EN);
@@ -1848,8 +1854,6 @@ static const struct snd_soc_dapm_route rt5682_dapm_routes[] = {
 
        {"CLKDET SYS", NULL, "CLKDET"},
 
-       {"IN1P", NULL, "LDO2"},
-
        {"BST1 CBJ", NULL, "IN1P"},
 
        {"RECMIX1L", "CBJ Switch", "BST1 CBJ"},
@@ -2906,6 +2910,9 @@ static int rt5682_suspend(struct snd_soc_component *component)
 {
        struct rt5682_priv *rt5682 = snd_soc_component_get_drvdata(component);
 
+       if (rt5682->is_sdw)
+               return 0;
+
        regcache_cache_only(rt5682->regmap, true);
        regcache_mark_dirty(rt5682->regmap);
        return 0;
@@ -2915,6 +2922,9 @@ static int rt5682_resume(struct snd_soc_component *component)
 {
        struct rt5682_priv *rt5682 = snd_soc_component_get_drvdata(component);
 
+       if (rt5682->is_sdw)
+               return 0;
+
        regcache_cache_only(rt5682->regmap, false);
        regcache_sync(rt5682->regmap);
 
index 99b85cf..1f9c51a 100644 (file)
 #define RT5682_SAR_SOUR_TYPE                   (0x0)
 
 /* soundwire timeout */
-#define RT5682_PROBE_TIMEOUT                   2000
+#define RT5682_PROBE_TIMEOUT                   5000
 
 
 #define RT5682_STEREO_RATES SNDRV_PCM_RATE_8000_192000
index fb77e77..4001612 100644 (file)
@@ -462,8 +462,8 @@ static int rt700_sdw_remove(struct sdw_slave *slave)
        struct rt700_priv *rt700 = dev_get_drvdata(&slave->dev);
 
        if (rt700 && rt700->hw_init) {
-               cancel_delayed_work(&rt700->jack_detect_work);
-               cancel_delayed_work(&rt700->jack_btn_check_work);
+               cancel_delayed_work_sync(&rt700->jack_detect_work);
+               cancel_delayed_work_sync(&rt700->jack_btn_check_work);
        }
 
        return 0;
@@ -490,7 +490,7 @@ static int __maybe_unused rt700_dev_suspend(struct device *dev)
        return 0;
 }
 
-#define RT700_PROBE_TIMEOUT 2000
+#define RT700_PROBE_TIMEOUT 5000
 
 static int __maybe_unused rt700_dev_resume(struct device *dev)
 {
index fc7df79..2beb428 100644 (file)
@@ -463,8 +463,8 @@ static int rt711_sdw_remove(struct sdw_slave *slave)
        struct rt711_priv *rt711 = dev_get_drvdata(&slave->dev);
 
        if (rt711 && rt711->hw_init) {
-               cancel_delayed_work(&rt711->jack_detect_work);
-               cancel_delayed_work(&rt711->jack_btn_check_work);
+               cancel_delayed_work_sync(&rt711->jack_detect_work);
+               cancel_delayed_work_sync(&rt711->jack_btn_check_work);
                cancel_work_sync(&rt711->calibration_work);
        }
 
@@ -493,7 +493,7 @@ static int __maybe_unused rt711_dev_suspend(struct device *dev)
        return 0;
 }
 
-#define RT711_PROBE_TIMEOUT 2000
+#define RT711_PROBE_TIMEOUT 5000
 
 static int __maybe_unused rt711_dev_resume(struct device *dev)
 {
index 8f0aa1e..71dd3b9 100644 (file)
@@ -533,7 +533,7 @@ static int __maybe_unused rt715_dev_suspend(struct device *dev)
        return 0;
 }
 
-#define RT715_PROBE_TIMEOUT 2000
+#define RT715_PROBE_TIMEOUT 5000
 
 static int __maybe_unused rt715_dev_resume(struct device *dev)
 {
index 4d6ff81..73551e3 100644 (file)
@@ -1187,7 +1187,7 @@ static struct snd_soc_dai_driver sgtl5000_dai = {
                .formats = SGTL5000_FORMATS,
        },
        .ops = &sgtl5000_ops,
-       .symmetric_rates = 1,
+       .symmetric_rate = 1,
 };
 
 static bool sgtl5000_volatile(struct device *dev, unsigned int reg)
diff --git a/sound/soc/codecs/sirf-audio-codec.c b/sound/soc/codecs/sirf-audio-codec.c
deleted file mode 100644 (file)
index a061d78..0000000
+++ /dev/null
@@ -1,575 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-or-later
-/*
- * SiRF audio codec driver
- *
- * Copyright (c) 2011 Cambridge Silicon Radio Limited, a CSR plc group company.
- */
-
-#include <linux/module.h>
-#include <linux/platform_device.h>
-#include <linux/pm_runtime.h>
-#include <linux/of.h>
-#include <linux/of_device.h>
-#include <linux/clk.h>
-#include <linux/delay.h>
-#include <linux/io.h>
-#include <linux/regmap.h>
-#include <sound/core.h>
-#include <sound/pcm.h>
-#include <sound/pcm_params.h>
-#include <sound/initval.h>
-#include <sound/tlv.h>
-#include <sound/soc.h>
-#include <sound/dmaengine_pcm.h>
-
-#include "sirf-audio-codec.h"
-
-struct sirf_audio_codec {
-       struct clk *clk;
-       struct regmap *regmap;
-       u32 reg_ctrl0, reg_ctrl1;
-};
-
-static const char * const input_mode_mux[] = {"Single-ended",
-       "Differential"};
-
-static const struct soc_enum input_mode_mux_enum =
-       SOC_ENUM_SINGLE(AUDIO_IC_CODEC_CTRL1, 4, 2, input_mode_mux);
-
-static const struct snd_kcontrol_new sirf_audio_codec_input_mode_control =
-       SOC_DAPM_ENUM("Route", input_mode_mux_enum);
-
-static const DECLARE_TLV_DB_SCALE(playback_vol_tlv, -12400, 100, 0);
-static const DECLARE_TLV_DB_SCALE(capture_vol_tlv_prima2, 500, 100, 0);
-static const DECLARE_TLV_DB_RANGE(capture_vol_tlv_atlas6,
-       0, 7, TLV_DB_SCALE_ITEM(-100, 100, 0),
-       0x22, 0x3F, TLV_DB_SCALE_ITEM(700, 100, 0),
-);
-
-static struct snd_kcontrol_new volume_controls_atlas6[] = {
-       SOC_DOUBLE_TLV("Playback Volume", AUDIO_IC_CODEC_CTRL0, 21, 14,
-                       0x7F, 0, playback_vol_tlv),
-       SOC_DOUBLE_TLV("Capture Volume", AUDIO_IC_CODEC_CTRL1, 16, 10,
-                       0x3F, 0, capture_vol_tlv_atlas6),
-};
-
-static struct snd_kcontrol_new volume_controls_prima2[] = {
-       SOC_DOUBLE_TLV("Speaker Volume", AUDIO_IC_CODEC_CTRL0, 21, 14,
-                       0x7F, 0, playback_vol_tlv),
-       SOC_DOUBLE_TLV("Capture Volume", AUDIO_IC_CODEC_CTRL1, 15, 10,
-                       0x1F, 0, capture_vol_tlv_prima2),
-};
-
-static struct snd_kcontrol_new left_input_path_controls[] = {
-       SOC_DAPM_SINGLE("Line Left Switch", AUDIO_IC_CODEC_CTRL1, 6, 1, 0),
-       SOC_DAPM_SINGLE("Mic Left Switch", AUDIO_IC_CODEC_CTRL1, 3, 1, 0),
-};
-
-static struct snd_kcontrol_new right_input_path_controls[] = {
-       SOC_DAPM_SINGLE("Line Right Switch", AUDIO_IC_CODEC_CTRL1, 5, 1, 0),
-       SOC_DAPM_SINGLE("Mic Right Switch", AUDIO_IC_CODEC_CTRL1, 2, 1, 0),
-};
-
-static struct snd_kcontrol_new left_dac_to_hp_left_amp_switch_control =
-       SOC_DAPM_SINGLE("Switch", AUDIO_IC_CODEC_CTRL0, 9, 1, 0);
-
-static struct snd_kcontrol_new left_dac_to_hp_right_amp_switch_control =
-       SOC_DAPM_SINGLE("Switch", AUDIO_IC_CODEC_CTRL0, 8, 1, 0);
-
-static struct snd_kcontrol_new right_dac_to_hp_left_amp_switch_control =
-       SOC_DAPM_SINGLE("Switch", AUDIO_IC_CODEC_CTRL0, 7, 1, 0);
-
-static struct snd_kcontrol_new right_dac_to_hp_right_amp_switch_control =
-       SOC_DAPM_SINGLE("Switch", AUDIO_IC_CODEC_CTRL0, 6, 1, 0);
-
-static struct snd_kcontrol_new left_dac_to_speaker_lineout_switch_control =
-       SOC_DAPM_SINGLE("Switch", AUDIO_IC_CODEC_CTRL0, 11, 1, 0);
-
-static struct snd_kcontrol_new right_dac_to_speaker_lineout_switch_control =
-       SOC_DAPM_SINGLE("Switch", AUDIO_IC_CODEC_CTRL0, 10, 1, 0);
-
-/* After enable adc, Delay 200ms to avoid pop noise */
-static int adc_enable_delay_event(struct snd_soc_dapm_widget *w,
-               struct snd_kcontrol *kcontrol, int event)
-{
-       switch (event) {
-       case SND_SOC_DAPM_POST_PMU:
-               msleep(200);
-               break;
-       default:
-               break;
-       }
-
-       return 0;
-}
-
-static void enable_and_reset_codec(struct regmap *regmap,
-               u32 codec_enable_bits, u32 codec_reset_bits)
-{
-       regmap_update_bits(regmap, AUDIO_IC_CODEC_CTRL1,
-                       codec_enable_bits | codec_reset_bits,
-                       codec_enable_bits);
-       msleep(20);
-       regmap_update_bits(regmap, AUDIO_IC_CODEC_CTRL1,
-                       codec_reset_bits, codec_reset_bits);
-}
-
-static int atlas6_codec_enable_and_reset_event(struct snd_soc_dapm_widget *w,
-               struct snd_kcontrol *kcontrol, int event)
-{
-#define ATLAS6_CODEC_ENABLE_BITS (1 << 29)
-#define ATLAS6_CODEC_RESET_BITS (1 << 28)
-       struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
-       struct sirf_audio_codec *sirf_audio_codec = snd_soc_component_get_drvdata(component);
-       switch (event) {
-       case SND_SOC_DAPM_PRE_PMU:
-               enable_and_reset_codec(sirf_audio_codec->regmap,
-                       ATLAS6_CODEC_ENABLE_BITS, ATLAS6_CODEC_RESET_BITS);
-               break;
-       case SND_SOC_DAPM_POST_PMD:
-               regmap_update_bits(sirf_audio_codec->regmap,
-                       AUDIO_IC_CODEC_CTRL1, ATLAS6_CODEC_ENABLE_BITS, 0);
-               break;
-       default:
-               break;
-       }
-
-       return 0;
-}
-
-static int prima2_codec_enable_and_reset_event(struct snd_soc_dapm_widget *w,
-               struct snd_kcontrol *kcontrol, int event)
-{
-#define PRIMA2_CODEC_ENABLE_BITS (1 << 27)
-#define PRIMA2_CODEC_RESET_BITS (1 << 26)
-       struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
-       struct sirf_audio_codec *sirf_audio_codec = snd_soc_component_get_drvdata(component);
-       switch (event) {
-       case SND_SOC_DAPM_POST_PMU:
-               enable_and_reset_codec(sirf_audio_codec->regmap,
-                       PRIMA2_CODEC_ENABLE_BITS, PRIMA2_CODEC_RESET_BITS);
-               break;
-       case SND_SOC_DAPM_POST_PMD:
-               regmap_update_bits(sirf_audio_codec->regmap,
-                       AUDIO_IC_CODEC_CTRL1, PRIMA2_CODEC_ENABLE_BITS, 0);
-               break;
-       default:
-               break;
-       }
-
-       return 0;
-}
-
-static const struct snd_soc_dapm_widget atlas6_output_driver_dapm_widgets[] = {
-       SND_SOC_DAPM_OUT_DRV("HP Left Driver", AUDIO_IC_CODEC_CTRL1,
-                       25, 0, NULL, 0),
-       SND_SOC_DAPM_OUT_DRV("HP Right Driver", AUDIO_IC_CODEC_CTRL1,
-                       26, 0, NULL, 0),
-       SND_SOC_DAPM_OUT_DRV("Speaker Driver", AUDIO_IC_CODEC_CTRL1,
-                       27, 0, NULL, 0),
-};
-
-static const struct snd_soc_dapm_widget prima2_output_driver_dapm_widgets[] = {
-       SND_SOC_DAPM_OUT_DRV("HP Left Driver", AUDIO_IC_CODEC_CTRL1,
-                       23, 0, NULL, 0),
-       SND_SOC_DAPM_OUT_DRV("HP Right Driver", AUDIO_IC_CODEC_CTRL1,
-                       24, 0, NULL, 0),
-       SND_SOC_DAPM_OUT_DRV("Speaker Driver", AUDIO_IC_CODEC_CTRL1,
-                       25, 0, NULL, 0),
-};
-
-static const struct snd_soc_dapm_widget atlas6_codec_clock_dapm_widget =
-       SND_SOC_DAPM_SUPPLY("codecclk", SND_SOC_NOPM, 0, 0,
-                       atlas6_codec_enable_and_reset_event,
-                       SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD);
-
-static const struct snd_soc_dapm_widget prima2_codec_clock_dapm_widget =
-       SND_SOC_DAPM_SUPPLY("codecclk", SND_SOC_NOPM, 0, 0,
-                       prima2_codec_enable_and_reset_event,
-                       SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD);
-
-static const struct snd_soc_dapm_widget sirf_audio_codec_dapm_widgets[] = {
-       SND_SOC_DAPM_DAC("DAC left", NULL, AUDIO_IC_CODEC_CTRL0, 1, 0),
-       SND_SOC_DAPM_DAC("DAC right", NULL, AUDIO_IC_CODEC_CTRL0, 0, 0),
-       SND_SOC_DAPM_SWITCH("Left dac to hp left amp", SND_SOC_NOPM, 0, 0,
-                       &left_dac_to_hp_left_amp_switch_control),
-       SND_SOC_DAPM_SWITCH("Left dac to hp right amp", SND_SOC_NOPM, 0, 0,
-                       &left_dac_to_hp_right_amp_switch_control),
-       SND_SOC_DAPM_SWITCH("Right dac to hp left amp", SND_SOC_NOPM, 0, 0,
-                       &right_dac_to_hp_left_amp_switch_control),
-       SND_SOC_DAPM_SWITCH("Right dac to hp right amp", SND_SOC_NOPM, 0, 0,
-                       &right_dac_to_hp_right_amp_switch_control),
-       SND_SOC_DAPM_OUT_DRV("HP amp left driver", AUDIO_IC_CODEC_CTRL0, 3, 0,
-                       NULL, 0),
-       SND_SOC_DAPM_OUT_DRV("HP amp right driver", AUDIO_IC_CODEC_CTRL0, 3, 0,
-                       NULL, 0),
-
-       SND_SOC_DAPM_SWITCH("Left dac to speaker lineout", SND_SOC_NOPM, 0, 0,
-                       &left_dac_to_speaker_lineout_switch_control),
-       SND_SOC_DAPM_SWITCH("Right dac to speaker lineout", SND_SOC_NOPM, 0, 0,
-                       &right_dac_to_speaker_lineout_switch_control),
-       SND_SOC_DAPM_OUT_DRV("Speaker amp driver", AUDIO_IC_CODEC_CTRL0, 4, 0,
-                       NULL, 0),
-
-       SND_SOC_DAPM_OUTPUT("HPOUTL"),
-       SND_SOC_DAPM_OUTPUT("HPOUTR"),
-       SND_SOC_DAPM_OUTPUT("SPKOUT"),
-
-       SND_SOC_DAPM_ADC_E("ADC left", NULL, AUDIO_IC_CODEC_CTRL1, 8, 0,
-                       adc_enable_delay_event, SND_SOC_DAPM_POST_PMU),
-       SND_SOC_DAPM_ADC_E("ADC right", NULL, AUDIO_IC_CODEC_CTRL1, 7, 0,
-                       adc_enable_delay_event, SND_SOC_DAPM_POST_PMU),
-       SND_SOC_DAPM_MIXER("Left PGA mixer", AUDIO_IC_CODEC_CTRL1, 1, 0,
-               &left_input_path_controls[0],
-               ARRAY_SIZE(left_input_path_controls)),
-       SND_SOC_DAPM_MIXER("Right PGA mixer", AUDIO_IC_CODEC_CTRL1, 0, 0,
-               &right_input_path_controls[0],
-               ARRAY_SIZE(right_input_path_controls)),
-
-       SND_SOC_DAPM_MUX("Mic input mode mux", SND_SOC_NOPM, 0, 0,
-                       &sirf_audio_codec_input_mode_control),
-       SND_SOC_DAPM_MICBIAS("Mic Bias", AUDIO_IC_CODEC_PWR, 3, 0),
-       SND_SOC_DAPM_INPUT("MICIN1"),
-       SND_SOC_DAPM_INPUT("MICIN2"),
-       SND_SOC_DAPM_INPUT("LINEIN1"),
-       SND_SOC_DAPM_INPUT("LINEIN2"),
-
-       SND_SOC_DAPM_SUPPLY("HSL Phase Opposite", AUDIO_IC_CODEC_CTRL0,
-                       30, 0, NULL, 0),
-};
-
-static const struct snd_soc_dapm_route sirf_audio_codec_map[] = {
-       {"SPKOUT", NULL, "Speaker Driver"},
-       {"Speaker Driver", NULL, "Speaker amp driver"},
-       {"Speaker amp driver", NULL, "Left dac to speaker lineout"},
-       {"Speaker amp driver", NULL, "Right dac to speaker lineout"},
-       {"Left dac to speaker lineout", "Switch", "DAC left"},
-       {"Right dac to speaker lineout", "Switch", "DAC right"},
-       {"HPOUTL", NULL, "HP Left Driver"},
-       {"HPOUTR", NULL, "HP Right Driver"},
-       {"HP Left Driver", NULL, "HP amp left driver"},
-       {"HP Right Driver", NULL, "HP amp right driver"},
-       {"HP amp left driver", NULL, "Right dac to hp left amp"},
-       {"HP amp right driver", NULL , "Right dac to hp right amp"},
-       {"HP amp left driver", NULL, "Left dac to hp left amp"},
-       {"HP amp right driver", NULL , "Right dac to hp right amp"},
-       {"Right dac to hp left amp", "Switch", "DAC left"},
-       {"Right dac to hp right amp", "Switch", "DAC right"},
-       {"Left dac to hp left amp", "Switch", "DAC left"},
-       {"Left dac to hp right amp", "Switch", "DAC right"},
-       {"DAC left", NULL, "codecclk"},
-       {"DAC right", NULL, "codecclk"},
-       {"DAC left", NULL, "Playback"},
-       {"DAC right", NULL, "Playback"},
-       {"DAC left", NULL, "HSL Phase Opposite"},
-       {"DAC right", NULL, "HSL Phase Opposite"},
-
-       {"Capture", NULL, "ADC left"},
-       {"Capture", NULL, "ADC right"},
-       {"ADC left", NULL, "codecclk"},
-       {"ADC right", NULL, "codecclk"},
-       {"ADC left", NULL, "Left PGA mixer"},
-       {"ADC right", NULL, "Right PGA mixer"},
-       {"Left PGA mixer", "Line Left Switch", "LINEIN2"},
-       {"Right PGA mixer", "Line Right Switch", "LINEIN1"},
-       {"Left PGA mixer", "Mic Left Switch", "MICIN2"},
-       {"Right PGA mixer", "Mic Right Switch", "Mic input mode mux"},
-       {"Mic input mode mux", "Single-ended", "MICIN1"},
-       {"Mic input mode mux", "Differential", "MICIN1"},
-};
-
-static void sirf_audio_codec_tx_enable(struct sirf_audio_codec *sirf_audio_codec)
-{
-       regmap_update_bits(sirf_audio_codec->regmap, AUDIO_PORT_IC_TXFIFO_OP,
-               AUDIO_FIFO_RESET, AUDIO_FIFO_RESET);
-       regmap_update_bits(sirf_audio_codec->regmap, AUDIO_PORT_IC_TXFIFO_OP,
-               AUDIO_FIFO_RESET, ~AUDIO_FIFO_RESET);
-       regmap_write(sirf_audio_codec->regmap, AUDIO_PORT_IC_TXFIFO_INT_MSK, 0);
-       regmap_write(sirf_audio_codec->regmap, AUDIO_PORT_IC_TXFIFO_OP, 0);
-       regmap_update_bits(sirf_audio_codec->regmap, AUDIO_PORT_IC_TXFIFO_OP,
-               AUDIO_FIFO_START, AUDIO_FIFO_START);
-       regmap_update_bits(sirf_audio_codec->regmap,
-               AUDIO_PORT_IC_CODEC_TX_CTRL, IC_TX_ENABLE, IC_TX_ENABLE);
-}
-
-static void sirf_audio_codec_tx_disable(struct sirf_audio_codec *sirf_audio_codec)
-{
-       regmap_write(sirf_audio_codec->regmap, AUDIO_PORT_IC_TXFIFO_OP, 0);
-       regmap_update_bits(sirf_audio_codec->regmap,
-               AUDIO_PORT_IC_CODEC_TX_CTRL, IC_TX_ENABLE, ~IC_TX_ENABLE);
-}
-
-static void sirf_audio_codec_rx_enable(struct sirf_audio_codec *sirf_audio_codec,
-       int channels)
-{
-       regmap_update_bits(sirf_audio_codec->regmap, AUDIO_PORT_IC_RXFIFO_OP,
-               AUDIO_FIFO_RESET, AUDIO_FIFO_RESET);
-       regmap_update_bits(sirf_audio_codec->regmap, AUDIO_PORT_IC_RXFIFO_OP,
-               AUDIO_FIFO_RESET, ~AUDIO_FIFO_RESET);
-       regmap_write(sirf_audio_codec->regmap,
-               AUDIO_PORT_IC_RXFIFO_INT_MSK, 0);
-       regmap_write(sirf_audio_codec->regmap, AUDIO_PORT_IC_RXFIFO_OP, 0);
-       regmap_update_bits(sirf_audio_codec->regmap, AUDIO_PORT_IC_RXFIFO_OP,
-               AUDIO_FIFO_START, AUDIO_FIFO_START);
-       if (channels == 1)
-               regmap_update_bits(sirf_audio_codec->regmap,
-                       AUDIO_PORT_IC_CODEC_RX_CTRL,
-                       IC_RX_ENABLE_MONO, IC_RX_ENABLE_MONO);
-       else
-               regmap_update_bits(sirf_audio_codec->regmap,
-                       AUDIO_PORT_IC_CODEC_RX_CTRL,
-                       IC_RX_ENABLE_STEREO, IC_RX_ENABLE_STEREO);
-}
-
-static void sirf_audio_codec_rx_disable(struct sirf_audio_codec *sirf_audio_codec)
-{
-       regmap_update_bits(sirf_audio_codec->regmap,
-                       AUDIO_PORT_IC_CODEC_RX_CTRL,
-                       IC_RX_ENABLE_STEREO, ~IC_RX_ENABLE_STEREO);
-}
-
-static int sirf_audio_codec_trigger(struct snd_pcm_substream *substream,
-               int cmd,
-               struct snd_soc_dai *dai)
-{
-       struct snd_soc_component *component = dai->component;
-       struct sirf_audio_codec *sirf_audio_codec = snd_soc_component_get_drvdata(component);
-       int playback = substream->stream == SNDRV_PCM_STREAM_PLAYBACK;
-
-       /*
-        * This is a workaround, When stop playback,
-        * need disable HP amp, avoid the current noise.
-        */
-       switch (cmd) {
-       case SNDRV_PCM_TRIGGER_STOP:
-       case SNDRV_PCM_TRIGGER_SUSPEND:
-       case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
-               if (playback) {
-                       snd_soc_component_update_bits(component, AUDIO_IC_CODEC_CTRL0,
-                               IC_HSLEN | IC_HSREN, 0);
-                       sirf_audio_codec_tx_disable(sirf_audio_codec);
-               } else
-                       sirf_audio_codec_rx_disable(sirf_audio_codec);
-               break;
-       case SNDRV_PCM_TRIGGER_START:
-       case SNDRV_PCM_TRIGGER_RESUME:
-       case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
-               if (playback) {
-                       sirf_audio_codec_tx_enable(sirf_audio_codec);
-                       snd_soc_component_update_bits(component, AUDIO_IC_CODEC_CTRL0,
-                               IC_HSLEN | IC_HSREN, IC_HSLEN | IC_HSREN);
-               } else
-                       sirf_audio_codec_rx_enable(sirf_audio_codec,
-                               substream->runtime->channels);
-               break;
-       default:
-               return -EINVAL;
-       }
-
-       return 0;
-}
-
-static const struct snd_soc_dai_ops sirf_audio_codec_dai_ops = {
-       .trigger = sirf_audio_codec_trigger,
-};
-
-static struct snd_soc_dai_driver sirf_audio_codec_dai = {
-       .name = "sirf-audio-codec",
-       .playback = {
-               .stream_name = "Playback",
-               .channels_min = 2,
-               .channels_max = 2,
-               .rates = SNDRV_PCM_RATE_48000,
-               .formats = SNDRV_PCM_FMTBIT_S16_LE,
-       },
-       .capture = {
-               .stream_name = "Capture",
-               .channels_min = 1,
-               .channels_max = 2,
-               .rates = SNDRV_PCM_RATE_48000,
-               .formats = SNDRV_PCM_FMTBIT_S16_LE,
-       },
-       .ops = &sirf_audio_codec_dai_ops,
-};
-
-static int sirf_audio_codec_probe(struct snd_soc_component *component)
-{
-       struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
-
-       pm_runtime_enable(component->dev);
-
-       if (of_device_is_compatible(component->dev->of_node, "sirf,prima2-audio-codec")) {
-               snd_soc_dapm_new_controls(dapm,
-                       prima2_output_driver_dapm_widgets,
-                       ARRAY_SIZE(prima2_output_driver_dapm_widgets));
-               snd_soc_dapm_new_controls(dapm,
-                       &prima2_codec_clock_dapm_widget, 1);
-               return snd_soc_add_component_controls(component,
-                       volume_controls_prima2,
-                       ARRAY_SIZE(volume_controls_prima2));
-       }
-       if (of_device_is_compatible(component->dev->of_node, "sirf,atlas6-audio-codec")) {
-               snd_soc_dapm_new_controls(dapm,
-                       atlas6_output_driver_dapm_widgets,
-                       ARRAY_SIZE(atlas6_output_driver_dapm_widgets));
-               snd_soc_dapm_new_controls(dapm,
-                       &atlas6_codec_clock_dapm_widget, 1);
-               return snd_soc_add_component_controls(component,
-                       volume_controls_atlas6,
-                       ARRAY_SIZE(volume_controls_atlas6));
-       }
-
-       return -EINVAL;
-}
-
-static void sirf_audio_codec_remove(struct snd_soc_component *component)
-{
-       pm_runtime_disable(component->dev);
-}
-
-static const struct snd_soc_component_driver soc_codec_device_sirf_audio_codec = {
-       .probe                  = sirf_audio_codec_probe,
-       .remove                 = sirf_audio_codec_remove,
-       .dapm_widgets           = sirf_audio_codec_dapm_widgets,
-       .num_dapm_widgets       = ARRAY_SIZE(sirf_audio_codec_dapm_widgets),
-       .dapm_routes            = sirf_audio_codec_map,
-       .num_dapm_routes        = ARRAY_SIZE(sirf_audio_codec_map),
-       .use_pmdown_time        = 1,
-       .endianness             = 1,
-       .non_legacy_dai_naming  = 1,
-};
-
-static const struct of_device_id sirf_audio_codec_of_match[] = {
-       { .compatible = "sirf,prima2-audio-codec" },
-       { .compatible = "sirf,atlas6-audio-codec" },
-       {}
-};
-MODULE_DEVICE_TABLE(of, sirf_audio_codec_of_match);
-
-static const struct regmap_config sirf_audio_codec_regmap_config = {
-       .reg_bits = 32,
-       .reg_stride = 4,
-       .val_bits = 32,
-       .max_register = AUDIO_PORT_IC_RXFIFO_INT_MSK,
-       .cache_type = REGCACHE_NONE,
-};
-
-static int sirf_audio_codec_driver_probe(struct platform_device *pdev)
-{
-       int ret;
-       struct sirf_audio_codec *sirf_audio_codec;
-       void __iomem *base;
-
-       sirf_audio_codec = devm_kzalloc(&pdev->dev,
-               sizeof(struct sirf_audio_codec), GFP_KERNEL);
-       if (!sirf_audio_codec)
-               return -ENOMEM;
-
-       platform_set_drvdata(pdev, sirf_audio_codec);
-
-       base = devm_platform_ioremap_resource(pdev, 0);
-       if (IS_ERR(base))
-               return PTR_ERR(base);
-
-       sirf_audio_codec->regmap = devm_regmap_init_mmio(&pdev->dev, base,
-                                           &sirf_audio_codec_regmap_config);
-       if (IS_ERR(sirf_audio_codec->regmap))
-               return PTR_ERR(sirf_audio_codec->regmap);
-
-       sirf_audio_codec->clk = devm_clk_get(&pdev->dev, NULL);
-       if (IS_ERR(sirf_audio_codec->clk)) {
-               dev_err(&pdev->dev, "Get clock failed.\n");
-               return PTR_ERR(sirf_audio_codec->clk);
-       }
-
-       ret = clk_prepare_enable(sirf_audio_codec->clk);
-       if (ret) {
-               dev_err(&pdev->dev, "Enable clock failed.\n");
-               return ret;
-       }
-
-       ret = devm_snd_soc_register_component(&(pdev->dev),
-                       &soc_codec_device_sirf_audio_codec,
-                       &sirf_audio_codec_dai, 1);
-       if (ret) {
-               dev_err(&pdev->dev, "Register Audio Codec dai failed.\n");
-               goto err_clk_put;
-       }
-
-       /*
-        * Always open charge pump, if not, when the charge pump closed the
-        * adc will not stable
-        */
-       regmap_update_bits(sirf_audio_codec->regmap, AUDIO_IC_CODEC_CTRL0,
-               IC_CPFREQ, IC_CPFREQ);
-
-       if (of_device_is_compatible(pdev->dev.of_node, "sirf,atlas6-audio-codec"))
-               regmap_update_bits(sirf_audio_codec->regmap,
-                               AUDIO_IC_CODEC_CTRL0, IC_CPEN, IC_CPEN);
-       return 0;
-
-err_clk_put:
-       clk_disable_unprepare(sirf_audio_codec->clk);
-       return ret;
-}
-
-static int sirf_audio_codec_driver_remove(struct platform_device *pdev)
-{
-       struct sirf_audio_codec *sirf_audio_codec = platform_get_drvdata(pdev);
-
-       clk_disable_unprepare(sirf_audio_codec->clk);
-
-       return 0;
-}
-
-#ifdef CONFIG_PM_SLEEP
-static int sirf_audio_codec_suspend(struct device *dev)
-{
-       struct sirf_audio_codec *sirf_audio_codec = dev_get_drvdata(dev);
-
-       regmap_read(sirf_audio_codec->regmap, AUDIO_IC_CODEC_CTRL0,
-               &sirf_audio_codec->reg_ctrl0);
-       regmap_read(sirf_audio_codec->regmap, AUDIO_IC_CODEC_CTRL1,
-               &sirf_audio_codec->reg_ctrl1);
-       clk_disable_unprepare(sirf_audio_codec->clk);
-
-       return 0;
-}
-
-static int sirf_audio_codec_resume(struct device *dev)
-{
-       struct sirf_audio_codec *sirf_audio_codec = dev_get_drvdata(dev);
-       int ret;
-
-       ret = clk_prepare_enable(sirf_audio_codec->clk);
-       if (ret)
-               return ret;
-
-       regmap_write(sirf_audio_codec->regmap, AUDIO_IC_CODEC_CTRL0,
-               sirf_audio_codec->reg_ctrl0);
-       regmap_write(sirf_audio_codec->regmap, AUDIO_IC_CODEC_CTRL1,
-               sirf_audio_codec->reg_ctrl1);
-
-       return 0;
-}
-#endif
-
-static const struct dev_pm_ops sirf_audio_codec_pm_ops = {
-       SET_SYSTEM_SLEEP_PM_OPS(sirf_audio_codec_suspend, sirf_audio_codec_resume)
-};
-
-static struct platform_driver sirf_audio_codec_driver = {
-       .driver = {
-               .name = "sirf-audio-codec",
-               .of_match_table = sirf_audio_codec_of_match,
-               .pm = &sirf_audio_codec_pm_ops,
-       },
-       .probe = sirf_audio_codec_driver_probe,
-       .remove = sirf_audio_codec_driver_remove,
-};
-
-module_platform_driver(sirf_audio_codec_driver);
-
-MODULE_DESCRIPTION("SiRF audio codec driver");
-MODULE_AUTHOR("RongJun Ying <Rongjun.Ying@csr.com>");
-MODULE_LICENSE("GPL v2");
index 9051602..7964e92 100644 (file)
@@ -526,8 +526,8 @@ static struct snd_soc_dai_driver ssm2602_dai = {
                .rates = SSM2602_RATES,
                .formats = SSM2602_FORMATS,},
        .ops = &ssm2602_dai_ops,
-       .symmetric_rates = 1,
-       .symmetric_samplebits = 1,
+       .symmetric_rate = 1,
+       .symmetric_sample_bits = 1,
 };
 
 static int ssm2602_resume(struct snd_soc_component *component)
index 14a193e..8ff4d9e 100644 (file)
@@ -490,7 +490,7 @@ static struct snd_soc_dai_driver tas2764_dai_driver[] = {
                        .formats = TAS2764_FORMATS,
                },
                .ops = &tas2764_dai_ops,
-               .symmetric_rates = 1,
+               .symmetric_rate = 1,
        },
 };
 
index a91a0a3..15fca51 100644 (file)
@@ -499,7 +499,7 @@ static struct snd_soc_dai_driver tas2770_dai_driver[] = {
                        .formats    = TAS2770_FORMATS,
                },
                .ops = &tas2770_dai_ops,
-               .symmetric_rates = 1,
+               .symmetric_rate = 1,
        },
 };
 
index 3f027c8..32b120d 100644 (file)
@@ -1069,7 +1069,7 @@ static struct snd_soc_dai_driver adcx140_dai_driver[] = {
                        .formats         = ADCX140_FORMATS,
                },
                .ops = &adcx140_dai_ops,
-               .symmetric_rates = 1,
+               .symmetric_rate = 1,
        }
 };
 
index 5ac7ce2..51870d5 100644 (file)
@@ -1395,7 +1395,7 @@ static struct snd_soc_dai_driver dac31xx_dai_driver[] = {
                        .formats         = AIC31XX_FORMATS,
                },
                .ops = &aic31xx_dai_ops,
-               .symmetric_rates = 1,
+               .symmetric_rate = 1,
        }
 };
 
@@ -1417,7 +1417,7 @@ static struct snd_soc_dai_driver aic31xx_dai_driver[] = {
                        .formats         = AIC31XX_FORMATS,
                },
                .ops = &aic31xx_dai_ops,
-               .symmetric_rates = 1,
+               .symmetric_rate = 1,
        }
 };
 
index 9e3de9d..f04f88c 100644 (file)
@@ -916,7 +916,7 @@ static struct snd_soc_dai_driver aic32x4_dai = {
                        .rates = AIC32X4_RATES,
                        .formats = AIC32X4_FORMATS,},
        .ops = &aic32x4_ops,
-       .symmetric_rates = 1,
+       .symmetric_rate = 1,
 };
 
 static void aic32x4_setup_gpios(struct snd_soc_component *component)
index 6d066bc..db14441 100644 (file)
@@ -1503,7 +1503,7 @@ static struct snd_soc_dai_driver aic3x_dai = {
                .rates = AIC3X_RATES,
                .formats = AIC3X_FORMATS,},
        .ops = &aic3x_dai_ops,
-       .symmetric_rates = 1,
+       .symmetric_rate = 1,
 };
 
 static void aic3x_mono_init(struct snd_soc_component *component)
index 6200fab..fb861ba 100644 (file)
@@ -1397,9 +1397,9 @@ static struct snd_soc_dai_driver tscs42xx_dai = {
                .rates = TSCS42XX_RATES,
                .formats = TSCS42XX_FORMATS,},
        .ops = &tscs42xx_dai_ops,
-       .symmetric_rates = 1,
+       .symmetric_rate = 1,
        .symmetric_channels = 1,
-       .symmetric_samplebits = 1,
+       .symmetric_sample_bits = 1,
 };
 
 static const struct reg_sequence tscs42xx_patch[] = {
index cd1f1a5..1bafc9d 100644 (file)
@@ -3346,9 +3346,9 @@ static struct snd_soc_dai_driver tscs454_dais[] = {
                        .rates = TSCS454_RATES,
                        .formats = TSCS454_FORMATS,},
                .ops = &tscs454_dai1_ops,
-               .symmetric_rates = 1,
+               .symmetric_rate = 1,
                .symmetric_channels = 1,
-               .symmetric_samplebits = 1,
+               .symmetric_sample_bits = 1,
        },
        {
                .name = "tscs454-dai2",
@@ -3366,9 +3366,9 @@ static struct snd_soc_dai_driver tscs454_dais[] = {
                        .rates = TSCS454_RATES,
                        .formats = TSCS454_FORMATS,},
                .ops = &tscs454_dai23_ops,
-               .symmetric_rates = 1,
+               .symmetric_rate = 1,
                .symmetric_channels = 1,
-               .symmetric_samplebits = 1,
+               .symmetric_sample_bits = 1,
        },
        {
                .name = "tscs454-dai3",
@@ -3386,9 +3386,9 @@ static struct snd_soc_dai_driver tscs454_dais[] = {
                        .rates = TSCS454_RATES,
                        .formats = TSCS454_FORMATS,},
                .ops = &tscs454_dai23_ops,
-               .symmetric_rates = 1,
+               .symmetric_rate = 1,
                .symmetric_channels = 1,
-               .symmetric_samplebits = 1,
+               .symmetric_sample_bits = 1,
        },
 };
 
index 70d353b..fe33f2d 100644 (file)
@@ -1780,8 +1780,8 @@ static struct snd_soc_dai_driver wm5102_dai[] = {
                         .formats = WM5102_FORMATS,
                 },
                .ops = &arizona_dai_ops,
-               .symmetric_rates = 1,
-               .symmetric_samplebits = 1,
+               .symmetric_rate = 1,
+               .symmetric_sample_bits = 1,
        },
        {
                .name = "wm5102-aif2",
@@ -1802,8 +1802,8 @@ static struct snd_soc_dai_driver wm5102_dai[] = {
                         .formats = WM5102_FORMATS,
                 },
                .ops = &arizona_dai_ops,
-               .symmetric_rates = 1,
-               .symmetric_samplebits = 1,
+               .symmetric_rate = 1,
+               .symmetric_sample_bits = 1,
        },
        {
                .name = "wm5102-aif3",
@@ -1824,8 +1824,8 @@ static struct snd_soc_dai_driver wm5102_dai[] = {
                         .formats = WM5102_FORMATS,
                 },
                .ops = &arizona_dai_ops,
-               .symmetric_rates = 1,
-               .symmetric_samplebits = 1,
+               .symmetric_rate = 1,
+               .symmetric_sample_bits = 1,
        },
        {
                .name = "wm5102-slim1",
index 4238929..52c0a57 100644 (file)
@@ -2089,8 +2089,8 @@ static struct snd_soc_dai_driver wm5110_dai[] = {
                         .formats = WM5110_FORMATS,
                 },
                .ops = &arizona_dai_ops,
-               .symmetric_rates = 1,
-               .symmetric_samplebits = 1,
+               .symmetric_rate = 1,
+               .symmetric_sample_bits = 1,
        },
        {
                .name = "wm5110-aif2",
@@ -2111,8 +2111,8 @@ static struct snd_soc_dai_driver wm5110_dai[] = {
                         .formats = WM5110_FORMATS,
                 },
                .ops = &arizona_dai_ops,
-               .symmetric_rates = 1,
-               .symmetric_samplebits = 1,
+               .symmetric_rate = 1,
+               .symmetric_sample_bits = 1,
        },
        {
                .name = "wm5110-aif3",
@@ -2133,8 +2133,8 @@ static struct snd_soc_dai_driver wm5110_dai[] = {
                         .formats = WM5110_FORMATS,
                 },
                .ops = &arizona_dai_ops,
-               .symmetric_rates = 1,
-               .symmetric_samplebits = 1,
+               .symmetric_rate = 1,
+               .symmetric_sample_bits = 1,
        },
        {
                .name = "wm5110-slim1",
index 73c4a8b..a18e229 100644 (file)
@@ -569,7 +569,7 @@ static struct snd_soc_dai_driver wm8510_dai = {
                .rates = WM8510_RATES,
                .formats = WM8510_FORMATS,},
        .ops = &wm8510_dai_ops,
-       .symmetric_rates = 1,
+       .symmetric_rate = 1,
 };
 
 static int wm8510_probe(struct snd_soc_component *component)
index 304bf72..dcee7b2 100644 (file)
@@ -567,7 +567,7 @@ static struct snd_soc_dai_driver wm8731_dai = {
                .rates = WM8731_RATES,
                .formats = WM8731_FORMATS,},
        .ops = &wm8731_dai_ops,
-       .symmetric_rates = 1,
+       .symmetric_rate = 1,
 };
 
 static int wm8731_request_supplies(struct device *dev,
index 1176a6a..5f39406 100644 (file)
@@ -562,7 +562,7 @@ static struct snd_soc_dai_driver wm8770_dai = {
                .formats = WM8770_FORMATS
        },
        .ops = &wm8770_dai_ops,
-       .symmetric_rates = 1
+       .symmetric_rate = 1
 };
 
 static int wm8770_probe(struct snd_soc_component *component)
index 4ddb5e3..21bf0cf 100644 (file)
@@ -536,7 +536,7 @@ static struct snd_soc_dai_driver wm8804_dai = {
                .formats = WM8804_FORMATS,
        },
        .ops = &wm8804_dai_ops,
-       .symmetric_rates = 1
+       .symmetric_rate = 1
 };
 
 static const struct snd_soc_component_driver soc_component_dev_wm8804 = {
index 09f4980..026603a 100644 (file)
@@ -1760,7 +1760,7 @@ static struct snd_soc_dai_driver wm8903_dai = {
                 .formats = WM8903_FORMATS,
         },
        .ops = &wm8903_dai_ops,
-       .symmetric_rates = 1,
+       .symmetric_rate = 1,
 };
 
 static int wm8903_resume(struct snd_soc_component *component)
index 1c360ba..a02a77f 100644 (file)
@@ -1983,7 +1983,7 @@ static struct snd_soc_dai_driver wm8904_dai = {
                .formats = WM8904_FORMATS,
        },
        .ops = &wm8904_dai_ops,
-       .symmetric_rates = 1,
+       .symmetric_rate = 1,
 };
 
 static void wm8904_handle_retune_mobile_pdata(struct snd_soc_component *component)
index 016cd8a..440d048 100644 (file)
@@ -688,7 +688,7 @@ static struct snd_soc_dai_driver wm8940_dai = {
                .formats = WM8940_FORMATS,
        },
        .ops = &wm8940_dai_ops,
-       .symmetric_rates = 1,
+       .symmetric_rate = 1,
 };
 
 static int wm8940_probe(struct snd_soc_component *component)
index 660ec46..df35151 100644 (file)
@@ -1338,7 +1338,7 @@ static struct snd_soc_dai_driver wm8960_dai = {
                .rates = WM8960_RATES,
                .formats = WM8960_FORMATS,},
        .ops = &wm8960_dai_ops,
-       .symmetric_rates = 1,
+       .symmetric_rate = 1,
 };
 
 static int wm8960_probe(struct snd_soc_component *component)
index 3af4560..ce4666a 100644 (file)
@@ -2973,7 +2973,7 @@ static struct snd_soc_dai_driver wm8962_dai = {
                .formats = WM8962_FORMATS,
        },
        .ops = &wm8962_dai_ops,
-       .symmetric_rates = 1,
+       .symmetric_rate = 1,
 };
 
 static void wm8962_mic_work(struct work_struct *work)
index c86231d..fdc68ab 100644 (file)
@@ -643,7 +643,7 @@ static struct snd_soc_dai_driver wm8974_dai = {
                .rates = WM8974_RATES,
                .formats = WM8974_FORMATS,},
        .ops = &wm8974_ops,
-       .symmetric_rates = 1,
+       .symmetric_rate = 1,
 };
 
 static const struct regmap_config wm8974_regmap = {
index a7acb89..4b5ecd1 100644 (file)
@@ -918,7 +918,7 @@ static struct snd_soc_dai_driver wm8978_dai = {
                .formats = WM8978_FORMATS,
        },
        .ops = &wm8978_dai_ops,
-       .symmetric_rates = 1,
+       .symmetric_rate = 1,
 };
 
 static int wm8978_suspend(struct snd_soc_component *component)
index d1d2d40..d8ed22a 100644 (file)
@@ -971,7 +971,7 @@ static struct snd_soc_dai_driver wm8983_dai = {
                .formats = WM8983_FORMATS,
        },
        .ops = &wm8983_dai_ops,
-       .symmetric_rates = 1
+       .symmetric_rate = 1
 };
 
 static const struct snd_soc_component_driver soc_component_dev_wm8983 = {
index 3f27482..a7e0110 100644 (file)
@@ -1100,7 +1100,7 @@ static struct snd_soc_dai_driver wm8985_dai = {
                .formats = WM8985_FORMATS,
        },
        .ops = &wm8985_dai_ops,
-       .symmetric_rates = 1
+       .symmetric_rate = 1
 };
 
 static const struct snd_soc_component_driver soc_component_dev_wm8985 = {
index d2c2d0d..1d2f881 100644 (file)
@@ -787,7 +787,7 @@ static struct snd_soc_dai_driver wm8988_dai = {
                .formats = WM8988_FORMATS,
         },
        .ops = &wm8988_ops,
-       .symmetric_rates = 1,
+       .symmetric_rate = 1,
 };
 
 static int wm8988_probe(struct snd_soc_component *component)
index 9f31008..c4f4169 100644 (file)
@@ -1476,7 +1476,7 @@ static struct snd_soc_dai_driver wm8993_dai = {
                 .sig_bits = 24,
         },
        .ops = &wm8993_ops,
-       .symmetric_rates = 1,
+       .symmetric_rate = 1,
 };
 
 static int wm8993_probe(struct snd_soc_component *component)
index f578841..f117ec0 100644 (file)
@@ -4351,7 +4351,7 @@ static int wm8994_component_probe(struct snd_soc_component *component)
        }
        if ((reg & WM8994_GPN_FN_MASK) != WM8994_GP_FN_PIN_SPECIFIC) {
                wm8994->lrclk_shared[0] = 1;
-               wm8994_dai[0].symmetric_rates = 1;
+               wm8994_dai[0].symmetric_rate = 1;
        } else {
                wm8994->lrclk_shared[0] = 0;
        }
@@ -4363,7 +4363,7 @@ static int wm8994_component_probe(struct snd_soc_component *component)
        }
        if ((reg & WM8994_GPN_FN_MASK) != WM8994_GP_FN_PIN_SPECIFIC) {
                wm8994->lrclk_shared[1] = 1;
-               wm8994_dai[1].symmetric_rates = 1;
+               wm8994_dai[1].symmetric_rate = 1;
        } else {
                wm8994->lrclk_shared[1] = 0;
        }
index 229f298..99c3eba 100644 (file)
@@ -969,8 +969,8 @@ static struct snd_soc_dai_driver wm8997_dai[] = {
                         .formats = WM8997_FORMATS,
                 },
                .ops = &arizona_dai_ops,
-               .symmetric_rates = 1,
-               .symmetric_samplebits = 1,
+               .symmetric_rate = 1,
+               .symmetric_sample_bits = 1,
        },
        {
                .name = "wm8997-aif2",
@@ -991,8 +991,8 @@ static struct snd_soc_dai_driver wm8997_dai[] = {
                         .formats = WM8997_FORMATS,
                 },
                .ops = &arizona_dai_ops,
-               .symmetric_rates = 1,
-               .symmetric_samplebits = 1,
+               .symmetric_rate = 1,
+               .symmetric_sample_bits = 1,
        },
        {
                .name = "wm8997-slim1",
index 5413254..b6f717a 100644 (file)
@@ -1161,8 +1161,8 @@ static struct snd_soc_dai_driver wm8998_dai[] = {
                         .formats = WM8998_FORMATS,
                 },
                .ops = &arizona_dai_ops,
-               .symmetric_rates = 1,
-               .symmetric_samplebits = 1,
+               .symmetric_rate = 1,
+               .symmetric_sample_bits = 1,
        },
        {
                .name = "wm8998-aif2",
@@ -1183,8 +1183,8 @@ static struct snd_soc_dai_driver wm8998_dai[] = {
                         .formats = WM8998_FORMATS,
                 },
                .ops = &arizona_dai_ops,
-               .symmetric_rates = 1,
-               .symmetric_samplebits = 1,
+               .symmetric_rate = 1,
+               .symmetric_sample_bits = 1,
        },
        {
                .name = "wm8998-aif3",
@@ -1205,8 +1205,8 @@ static struct snd_soc_dai_driver wm8998_dai[] = {
                         .formats = WM8998_FORMATS,
                 },
                .ops = &arizona_dai_ops,
-               .symmetric_rates = 1,
-               .symmetric_samplebits = 1,
+               .symmetric_rate = 1,
+               .symmetric_sample_bits = 1,
        },
        {
                .name = "wm8998-slim1",
index f333e2f..e0ce32d 100644 (file)
@@ -1134,7 +1134,7 @@ static struct snd_soc_dai_driver wm9713_dai[] = {
                .rates = WM9713_PCM_RATES,
                .formats = WM9713_PCM_FORMATS,},
        .ops = &wm9713_dai_ops_voice,
-       .symmetric_rates = 1,
+       .symmetric_rate = 1,
        },
 };
 
index 985b2dc..070ca7d 100644 (file)
@@ -595,13 +595,6 @@ static const struct {
        [WM_ADSP_FW_MISC] =     { .file = "misc" },
 };
 
-struct wm_coeff_ctl_ops {
-       int (*xget)(struct snd_kcontrol *kcontrol,
-                   struct snd_ctl_elem_value *ucontrol);
-       int (*xput)(struct snd_kcontrol *kcontrol,
-                   struct snd_ctl_elem_value *ucontrol);
-};
-
 struct wm_coeff_ctl {
        const char *name;
        const char *fw_name;
@@ -609,7 +602,6 @@ struct wm_coeff_ctl {
        const char *subname;
        unsigned int subname_len;
        struct wm_adsp_alg_region alg_region;
-       struct wm_coeff_ctl_ops ops;
        struct wm_adsp *dsp;
        unsigned int enabled:1;
        struct list_head list;
@@ -619,7 +611,7 @@ struct wm_coeff_ctl {
        unsigned int set:1;
        struct soc_bytes_ext bytes_ext;
        unsigned int flags;
-       unsigned int type;
+       snd_ctl_elem_type_t type;
 };
 
 static const char *wm_adsp_mem_region_name(unsigned int type)
@@ -980,7 +972,7 @@ static int wm_coeff_write_acked_control(struct wm_coeff_ctl *ctl,
                                        unsigned int event_id)
 {
        struct wm_adsp *dsp = ctl->dsp;
-       u32 val = cpu_to_be32(event_id);
+       __be32 val = cpu_to_be32(event_id);
        unsigned int reg;
        int i, ret;
 
@@ -1420,7 +1412,7 @@ static int wm_adsp_create_control(struct wm_adsp *dsp,
                                  const struct wm_adsp_alg_region *alg_region,
                                  unsigned int offset, unsigned int len,
                                  const char *subname, unsigned int subname_len,
-                                 unsigned int flags, unsigned int type)
+                                 unsigned int flags, snd_ctl_elem_type_t type)
 {
        struct wm_coeff_ctl *ctl;
        struct wmfw_ctl_work *ctl_work;
@@ -1497,8 +1489,6 @@ static int wm_adsp_create_control(struct wm_adsp *dsp,
        }
        ctl->enabled = 1;
        ctl->set = 0;
-       ctl->ops.xget = wm_coeff_get;
-       ctl->ops.xput = wm_coeff_put;
        ctl->dsp = dsp;
 
        ctl->flags = flags;
@@ -1554,7 +1544,7 @@ struct wm_coeff_parsed_coeff {
        int mem_type;
        const u8 *name;
        int name_len;
-       int ctl_type;
+       snd_ctl_elem_type_t ctl_type;
        int flags;
        int len;
 };
@@ -1649,7 +1639,7 @@ static inline void wm_coeff_parse_coeff(struct wm_adsp *dsp, const u8 **data,
                blk->mem_type = le16_to_cpu(raw->hdr.type);
                blk->name = raw->name;
                blk->name_len = strlen(raw->name);
-               blk->ctl_type = le16_to_cpu(raw->ctl_type);
+               blk->ctl_type = (__force snd_ctl_elem_type_t)le16_to_cpu(raw->ctl_type);
                blk->flags = le16_to_cpu(raw->flags);
                blk->len = le32_to_cpu(raw->len);
                break;
@@ -1662,7 +1652,9 @@ static inline void wm_coeff_parse_coeff(struct wm_adsp *dsp, const u8 **data,
                                                      &blk->name);
                wm_coeff_parse_string(sizeof(u8), &tmp, NULL);
                wm_coeff_parse_string(sizeof(u16), &tmp, NULL);
-               blk->ctl_type = wm_coeff_parse_int(sizeof(raw->ctl_type), &tmp);
+               blk->ctl_type =
+                       (__force snd_ctl_elem_type_t)wm_coeff_parse_int(sizeof(raw->ctl_type),
+                                                                       &tmp);
                blk->flags = wm_coeff_parse_int(sizeof(raw->flags), &tmp);
                blk->len = wm_coeff_parse_int(sizeof(raw->len), &tmp);
 
@@ -3667,12 +3659,12 @@ int wm_adsp_compr_get_caps(struct snd_soc_component *component,
 }
 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)
+static int wm_adsp_read_raw_data_block(struct wm_adsp *dsp, int mem_type,
+                                      unsigned int mem_addr,
+                                      unsigned int num_words, __be32 *data)
 {
        struct wm_adsp_region const *mem = wm_adsp_find_region(dsp, mem_type);
-       unsigned int i, reg;
+       unsigned int reg;
        int ret;
 
        if (!mem)
@@ -3685,22 +3677,29 @@ static int wm_adsp_read_data_block(struct wm_adsp *dsp, int mem_type,
        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);
+       __be32 raw;
+       int ret;
+
+       ret = wm_adsp_read_raw_data_block(dsp, mem_type, mem_addr, 1, &raw);
+       if (ret < 0)
+               return ret;
+
+       *data = be32_to_cpu(raw) & 0x00ffffffu;
+
+       return 0;
 }
 
 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);
+       __be32 val = cpu_to_be32(data & 0x00ffffffu);
        unsigned int reg;
 
        if (!mem)
@@ -3708,9 +3707,7 @@ static int wm_adsp_write_data_word(struct wm_adsp *dsp, int mem_type,
 
        reg = dsp->ops->region_to_reg(mem, mem_addr);
 
-       data = cpu_to_be32(data & 0x00ffffffu);
-
-       return regmap_raw_write(dsp->regmap, reg, &data, sizeof(data));
+       return regmap_raw_write(dsp->regmap, reg, &val, sizeof(val));
 }
 
 static inline int wm_adsp_buffer_read(struct wm_adsp_compr_buf *buf,
@@ -3727,18 +3724,22 @@ static inline int wm_adsp_buffer_write(struct wm_adsp_compr_buf *buf,
                                       buf->host_buf_ptr + field_offset, data);
 }
 
-static void wm_adsp_remove_padding(u32 *buf, int nwords, int data_word_size)
+static void wm_adsp_remove_padding(u32 *buf, int nwords)
 {
-       u8 *pack_in = (u8 *)buf;
+       const __be32 *pack_in = (__be32 *)buf;
        u8 *pack_out = (u8 *)buf;
-       int i, j;
+       int i;
 
-       /* Remove the padding bytes from the data read from the DSP */
+       /*
+        * DSP words from the register map have pad bytes and the data bytes
+        * are in swapped order. This swaps back to the original little-endian
+        * order and strips the pad bytes.
+        */
        for (i = 0; i < nwords; i++) {
-               for (j = 0; j < data_word_size; j++)
-                       *pack_out++ = *pack_in++;
-
-               pack_in += sizeof(*buf) - data_word_size;
+               u32 word = be32_to_cpu(*pack_in++);
+               *pack_out++ = (u8)word;
+               *pack_out++ = (u8)(word >> 8);
+               *pack_out++ = (u8)(word >> 16);
        }
 }
 
@@ -3863,7 +3864,8 @@ static int wm_adsp_buffer_parse_coeff(struct wm_coeff_ctl *ctl)
 {
        struct wm_adsp_host_buf_coeff_v1 coeff_v1;
        struct wm_adsp_compr_buf *buf;
-       unsigned int val, reg;
+       unsigned int reg, version;
+       __be32 bufp;
        int ret, i;
 
        ret = wm_coeff_base_reg(ctl, &reg);
@@ -3871,17 +3873,17 @@ static int wm_adsp_buffer_parse_coeff(struct wm_coeff_ctl *ctl)
                return ret;
 
        for (i = 0; i < 5; ++i) {
-               ret = regmap_raw_read(ctl->dsp->regmap, reg, &val, sizeof(val));
+               ret = regmap_raw_read(ctl->dsp->regmap, reg, &bufp, sizeof(bufp));
                if (ret < 0)
                        return ret;
 
-               if (val)
+               if (bufp)
                        break;
 
                usleep_range(1000, 2000);
        }
 
-       if (!val) {
+       if (!bufp) {
                adsp_err(ctl->dsp, "Failed to acquire host buffer\n");
                return -EIO;
        }
@@ -3891,7 +3893,7 @@ static int wm_adsp_buffer_parse_coeff(struct wm_coeff_ctl *ctl)
                return -ENOMEM;
 
        buf->host_buf_mem_type = ctl->alg_region.type;
-       buf->host_buf_ptr = be32_to_cpu(val);
+       buf->host_buf_ptr = be32_to_cpu(bufp);
 
        ret = wm_adsp_buffer_populate(buf);
        if (ret < 0)
@@ -3911,31 +3913,25 @@ static int wm_adsp_buffer_parse_coeff(struct wm_coeff_ctl *ctl)
        if (ret < 0)
                return ret;
 
-       coeff_v1.versions = be32_to_cpu(coeff_v1.versions);
-       val = coeff_v1.versions & HOST_BUF_COEFF_COMPAT_VER_MASK;
-       val >>= HOST_BUF_COEFF_COMPAT_VER_SHIFT;
+       version = be32_to_cpu(coeff_v1.versions) & HOST_BUF_COEFF_COMPAT_VER_MASK;
+       version >>= HOST_BUF_COEFF_COMPAT_VER_SHIFT;
 
-       if (val > HOST_BUF_COEFF_SUPPORTED_COMPAT_VER) {
+       if (version > HOST_BUF_COEFF_SUPPORTED_COMPAT_VER) {
                adsp_err(ctl->dsp,
                         "Host buffer coeff ver %u > supported version %u\n",
-                        val, HOST_BUF_COEFF_SUPPORTED_COMPAT_VER);
+                        version, HOST_BUF_COEFF_SUPPORTED_COMPAT_VER);
                return -EINVAL;
        }
 
-       for (i = 0; i < ARRAY_SIZE(coeff_v1.name); i++)
-               coeff_v1.name[i] = be32_to_cpu(coeff_v1.name[i]);
-
-       wm_adsp_remove_padding((u32 *)&coeff_v1.name,
-                              ARRAY_SIZE(coeff_v1.name),
-                              WM_ADSP_DATA_WORD_SIZE);
+       wm_adsp_remove_padding((u32 *)&coeff_v1.name, ARRAY_SIZE(coeff_v1.name));
 
        buf->name = kasprintf(GFP_KERNEL, "%s-dsp-%s", ctl->dsp->part,
                              (char *)&coeff_v1.name);
 
        compr_dbg(buf, "host_buf_ptr=%x coeff version %u\n",
-                 buf->host_buf_ptr, val);
+                 buf->host_buf_ptr, version);
 
-       return val;
+       return version;
 }
 
 static int wm_adsp_buffer_init(struct wm_adsp *dsp)
@@ -4266,12 +4262,12 @@ static int wm_adsp_buffer_capture_block(struct wm_adsp_compr *compr, int target)
                return 0;
 
        /* Read data from DSP */
-       ret = wm_adsp_read_data_block(buf->dsp, mem_type, adsp_addr,
-                                     nwords, compr->raw_buf);
+       ret = wm_adsp_read_raw_data_block(buf->dsp, mem_type, adsp_addr,
+                                         nwords, (__be32 *)compr->raw_buf);
        if (ret < 0)
                return ret;
 
-       wm_adsp_remove_padding(compr->raw_buf, nwords, WM_ADSP_DATA_WORD_SIZE);
+       wm_adsp_remove_padding(compr->raw_buf, nwords);
 
        /* update read index to account for words read */
        buf->read_index += nwords;
index 7423272..f3d5160 100644 (file)
@@ -24,9 +24,9 @@
 #define WMFW_CTL_FLAG_READABLE    0x0001
 
 /* Non-ALSA coefficient types start at 0x1000 */
-#define WMFW_CTL_TYPE_ACKED       0x1000 /* acked control */
-#define WMFW_CTL_TYPE_HOSTEVENT   0x1001 /* event control */
-#define WMFW_CTL_TYPE_HOST_BUFFER 0x1002 /* host buffer pointer */
+#define WMFW_CTL_TYPE_ACKED       ((__force snd_ctl_elem_type_t)0x1000) /* acked control */
+#define WMFW_CTL_TYPE_HOSTEVENT   ((__force snd_ctl_elem_type_t)0x1001) /* event control */
+#define WMFW_CTL_TYPE_HOST_BUFFER ((__force snd_ctl_elem_type_t)0x1002) /* host buffer pointer */
 
 struct wmfw_header {
        char magic[4];
index 4530b74..db87e07 100644 (file)
@@ -640,6 +640,7 @@ static struct regmap_config wsa881x_regmap_config = {
        .val_bits = 8,
        .cache_type = REGCACHE_RBTREE,
        .reg_defaults = wsa881x_defaults,
+       .max_register = WSA881X_SPKR_STATUS3,
        .num_reg_defaults = ARRAY_SIZE(wsa881x_defaults),
        .volatile_reg = wsa881x_volatile_register,
        .readable_reg = wsa881x_readable_register,
index 42726dc..d21a723 100644 (file)
@@ -360,8 +360,8 @@ static struct snd_soc_dai_driver zl38_dai = {
                .formats = ZL38_FORMATS,
        },
        .ops = &zl38_dai_ops,
-       .symmetric_rates = 1,
-       .symmetric_samplebits = 1,
+       .symmetric_rate = 1,
+       .symmetric_sample_bits = 1,
        .symmetric_channels = 1,
 };
 
diff --git a/sound/soc/codecs/zx_aud96p22.c b/sound/soc/codecs/zx_aud96p22.c
deleted file mode 100644 (file)
index 16d44ef..0000000
+++ /dev/null
@@ -1,401 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-/*
- * Copyright (C) 2017 Sanechips Technology Co., Ltd.
- * Copyright 2017 Linaro Ltd.
- *
- * Author: Baoyou Xie <baoyou.xie@linaro.org>
- */
-
-#include <linux/gpio/consumer.h>
-#include <linux/i2c.h>
-#include <linux/module.h>
-#include <linux/regmap.h>
-#include <sound/pcm.h>
-#include <sound/pcm_params.h>
-#include <sound/soc.h>
-#include <sound/soc-dai.h>
-#include <sound/tlv.h>
-
-#define AUD96P22_RESET                 0x00
-#define RST_DAC_DPZ                    BIT(0)
-#define RST_ADC_DPZ                    BIT(1)
-#define AUD96P22_I2S1_CONFIG_0         0x03
-#define I2S1_MS_MODE                   BIT(3)
-#define I2S1_MODE_MASK                 0x7
-#define I2S1_MODE_RIGHT_J              0x0
-#define I2S1_MODE_I2S                  0x1
-#define I2S1_MODE_LEFT_J               0x2
-#define AUD96P22_PD_0                  0x15
-#define AUD96P22_PD_1                  0x16
-#define AUD96P22_PD_3                  0x18
-#define AUD96P22_PD_4                  0x19
-#define AUD96P22_MUTE_0                        0x1d
-#define AUD96P22_MUTE_2                        0x1f
-#define AUD96P22_MUTE_4                        0x21
-#define AUD96P22_RECVOL_0              0x24
-#define AUD96P22_RECVOL_1              0x25
-#define AUD96P22_PGA1VOL_0             0x26
-#define AUD96P22_PGA1VOL_1             0x27
-#define AUD96P22_LMVOL_0               0x34
-#define AUD96P22_LMVOL_1               0x35
-#define AUD96P22_HS1VOL_0              0x38
-#define AUD96P22_HS1VOL_1              0x39
-#define AUD96P22_PGA1SEL_0             0x47
-#define AUD96P22_PGA1SEL_1             0x48
-#define AUD96P22_LDR1SEL_0             0x59
-#define AUD96P22_LDR1SEL_1             0x60
-#define AUD96P22_LDR2SEL_0             0x5d
-#define AUD96P22_REG_MAX               0xfb
-
-struct aud96p22_priv {
-       struct regmap *regmap;
-};
-
-static int aud96p22_adc_event(struct snd_soc_dapm_widget *w,
-                             struct snd_kcontrol *kcontrol, int event)
-{
-       struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
-       struct aud96p22_priv *priv = snd_soc_component_get_drvdata(component);
-       struct regmap *regmap = priv->regmap;
-
-       if (event != SND_SOC_DAPM_POST_PMU)
-               return -EINVAL;
-
-       /* Assert/de-assert the bit to reset ADC data path  */
-       regmap_update_bits(regmap, AUD96P22_RESET, RST_ADC_DPZ, 0);
-       regmap_update_bits(regmap, AUD96P22_RESET, RST_ADC_DPZ, RST_ADC_DPZ);
-
-       return 0;
-}
-
-static int aud96p22_dac_event(struct snd_soc_dapm_widget *w,
-                             struct snd_kcontrol *kcontrol, int event)
-{
-       struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
-       struct aud96p22_priv *priv = snd_soc_component_get_drvdata(component);
-       struct regmap *regmap = priv->regmap;
-
-       if (event != SND_SOC_DAPM_POST_PMU)
-               return -EINVAL;
-
-       /* Assert/de-assert the bit to reset DAC data path  */
-       regmap_update_bits(regmap, AUD96P22_RESET, RST_DAC_DPZ, 0);
-       regmap_update_bits(regmap, AUD96P22_RESET, RST_DAC_DPZ, RST_DAC_DPZ);
-
-       return 0;
-}
-
-static const DECLARE_TLV_DB_SCALE(lm_tlv, -11550, 50, 0);
-static const DECLARE_TLV_DB_SCALE(hs_tlv, -3900, 300, 0);
-static const DECLARE_TLV_DB_SCALE(rec_tlv, -9550, 50, 0);
-static const DECLARE_TLV_DB_SCALE(pga_tlv, -1800, 100, 0);
-
-static const struct snd_kcontrol_new aud96p22_snd_controls[] = {
-       /* Volume control */
-       SOC_DOUBLE_R_TLV("Master Playback Volume", AUD96P22_LMVOL_0,
-                        AUD96P22_LMVOL_1, 0, 0xff, 0, lm_tlv),
-       SOC_DOUBLE_R_TLV("Headphone Volume", AUD96P22_HS1VOL_0,
-                        AUD96P22_HS1VOL_1, 0, 0xf, 0, hs_tlv),
-       SOC_DOUBLE_R_TLV("Master Capture Volume", AUD96P22_RECVOL_0,
-                        AUD96P22_RECVOL_1, 0, 0xff, 0, rec_tlv),
-       SOC_DOUBLE_R_TLV("Analogue Capture Volume", AUD96P22_PGA1VOL_0,
-                        AUD96P22_PGA1VOL_1, 0, 0x37, 0, pga_tlv),
-
-       /* Mute control */
-       SOC_DOUBLE("Master Playback Switch", AUD96P22_MUTE_2, 0, 1, 1, 1),
-       SOC_DOUBLE("Headphone Switch", AUD96P22_MUTE_2, 4, 5, 1, 1),
-       SOC_DOUBLE("Line Out Switch", AUD96P22_MUTE_4, 0, 1, 1, 1),
-       SOC_DOUBLE("Speaker Switch", AUD96P22_MUTE_4, 2, 3, 1, 1),
-       SOC_DOUBLE("Master Capture Switch", AUD96P22_MUTE_0, 0, 1, 1, 1),
-       SOC_DOUBLE("Analogue Capture Switch", AUD96P22_MUTE_0, 2, 3, 1, 1),
-};
-
-/* Input mux kcontrols */
-static const unsigned int ain_mux_values[] = {
-       0, 1, 3, 4, 5,
-};
-
-static const char * const ainl_mux_texts[] = {
-       "AINL1 differential",
-       "AINL1 single-ended",
-       "AINL3 single-ended",
-       "AINL2 differential",
-       "AINL2 single-ended",
-};
-
-static const char * const ainr_mux_texts[] = {
-       "AINR1 differential",
-       "AINR1 single-ended",
-       "AINR3 single-ended",
-       "AINR2 differential",
-       "AINR2 single-ended",
-};
-
-static SOC_VALUE_ENUM_SINGLE_DECL(ainl_mux_enum, AUD96P22_PGA1SEL_0,
-                                 0, 0x7, ainl_mux_texts, ain_mux_values);
-static SOC_VALUE_ENUM_SINGLE_DECL(ainr_mux_enum, AUD96P22_PGA1SEL_1,
-                                 0, 0x7, ainr_mux_texts, ain_mux_values);
-
-static const struct snd_kcontrol_new ainl_mux_kcontrol =
-                       SOC_DAPM_ENUM("AINL Mux", ainl_mux_enum);
-static const struct snd_kcontrol_new ainr_mux_kcontrol =
-                       SOC_DAPM_ENUM("AINR Mux", ainr_mux_enum);
-
-/* Output mixer kcontrols */
-static const struct snd_kcontrol_new ld1_left_kcontrols[] = {
-       SOC_DAPM_SINGLE("DACL LD1L Switch", AUD96P22_LDR1SEL_0, 0, 1, 0),
-       SOC_DAPM_SINGLE("AINL LD1L Switch", AUD96P22_LDR1SEL_0, 1, 1, 0),
-       SOC_DAPM_SINGLE("AINR LD1L Switch", AUD96P22_LDR1SEL_0, 2, 1, 0),
-};
-
-static const struct snd_kcontrol_new ld1_right_kcontrols[] = {
-       SOC_DAPM_SINGLE("DACR LD1R Switch", AUD96P22_LDR1SEL_1, 8, 1, 0),
-       SOC_DAPM_SINGLE("AINR LD1R Switch", AUD96P22_LDR1SEL_1, 9, 1, 0),
-       SOC_DAPM_SINGLE("AINL LD1R Switch", AUD96P22_LDR1SEL_1, 10, 1, 0),
-};
-
-static const struct snd_kcontrol_new ld2_kcontrols[] = {
-       SOC_DAPM_SINGLE("DACL LD2 Switch", AUD96P22_LDR2SEL_0, 0, 1, 0),
-       SOC_DAPM_SINGLE("AINL LD2 Switch", AUD96P22_LDR2SEL_0, 1, 1, 0),
-       SOC_DAPM_SINGLE("DACR LD2 Switch", AUD96P22_LDR2SEL_0, 2, 1, 0),
-};
-
-static const struct snd_soc_dapm_widget aud96p22_dapm_widgets[] = {
-       /* Overall power bit */
-       SND_SOC_DAPM_SUPPLY("POWER", AUD96P22_PD_0, 0, 0, NULL, 0),
-
-       /* Input pins */
-       SND_SOC_DAPM_INPUT("AINL1P"),
-       SND_SOC_DAPM_INPUT("AINL2P"),
-       SND_SOC_DAPM_INPUT("AINL3"),
-       SND_SOC_DAPM_INPUT("AINL1N"),
-       SND_SOC_DAPM_INPUT("AINL2N"),
-       SND_SOC_DAPM_INPUT("AINR2N"),
-       SND_SOC_DAPM_INPUT("AINR1N"),
-       SND_SOC_DAPM_INPUT("AINR3"),
-       SND_SOC_DAPM_INPUT("AINR2P"),
-       SND_SOC_DAPM_INPUT("AINR1P"),
-
-       /* Input muxes */
-       SND_SOC_DAPM_MUX("AINLMUX", AUD96P22_PD_1, 2, 0, &ainl_mux_kcontrol),
-       SND_SOC_DAPM_MUX("AINRMUX", AUD96P22_PD_1, 3, 0, &ainr_mux_kcontrol),
-
-       /* ADCs */
-       SND_SOC_DAPM_ADC_E("ADCL", "Capture Left", AUD96P22_PD_1, 0, 0,
-                          aud96p22_adc_event, SND_SOC_DAPM_POST_PMU),
-       SND_SOC_DAPM_ADC_E("ADCR", "Capture Right", AUD96P22_PD_1, 1, 0,
-                          aud96p22_adc_event, SND_SOC_DAPM_POST_PMU),
-
-       /* DACs */
-       SND_SOC_DAPM_DAC_E("DACL", "Playback Left", AUD96P22_PD_3, 0, 0,
-                          aud96p22_dac_event, SND_SOC_DAPM_POST_PMU),
-       SND_SOC_DAPM_DAC_E("DACR", "Playback Right", AUD96P22_PD_3, 1, 0,
-                          aud96p22_dac_event, SND_SOC_DAPM_POST_PMU),
-
-       /* Output mixers */
-       SND_SOC_DAPM_MIXER("LD1L", AUD96P22_PD_3, 6, 0, ld1_left_kcontrols,
-                          ARRAY_SIZE(ld1_left_kcontrols)),
-       SND_SOC_DAPM_MIXER("LD1R", AUD96P22_PD_3, 7, 0, ld1_right_kcontrols,
-                          ARRAY_SIZE(ld1_right_kcontrols)),
-       SND_SOC_DAPM_MIXER("LD2", AUD96P22_PD_4, 2, 0, ld2_kcontrols,
-                          ARRAY_SIZE(ld2_kcontrols)),
-
-       /* Headset power switch */
-       SND_SOC_DAPM_SUPPLY("HS1L", AUD96P22_PD_3, 4, 0, NULL, 0),
-       SND_SOC_DAPM_SUPPLY("HS1R", AUD96P22_PD_3, 5, 0, NULL, 0),
-
-       /* Output pins */
-       SND_SOC_DAPM_OUTPUT("HSOUTL"),
-       SND_SOC_DAPM_OUTPUT("LINEOUTL"),
-       SND_SOC_DAPM_OUTPUT("LINEOUTMP"),
-       SND_SOC_DAPM_OUTPUT("LINEOUTMN"),
-       SND_SOC_DAPM_OUTPUT("LINEOUTR"),
-       SND_SOC_DAPM_OUTPUT("HSOUTR"),
-};
-
-static const struct snd_soc_dapm_route aud96p22_dapm_routes[] = {
-       { "AINLMUX", "AINL1 differential", "AINL1N" },
-       { "AINLMUX", "AINL1 single-ended", "AINL1P" },
-       { "AINLMUX", "AINL3 single-ended", "AINL3" },
-       { "AINLMUX", "AINL2 differential", "AINL2N" },
-       { "AINLMUX", "AINL2 single-ended", "AINL2P" },
-
-       { "AINRMUX", "AINR1 differential", "AINR1N" },
-       { "AINRMUX", "AINR1 single-ended", "AINR1P" },
-       { "AINRMUX", "AINR3 single-ended", "AINR3" },
-       { "AINRMUX", "AINR2 differential", "AINR2N" },
-       { "AINRMUX", "AINR2 single-ended", "AINR2P" },
-
-       { "ADCL", NULL, "AINLMUX" },
-       { "ADCR", NULL, "AINRMUX" },
-
-       { "ADCL", NULL, "POWER" },
-       { "ADCR", NULL, "POWER" },
-       { "DACL", NULL, "POWER" },
-       { "DACR", NULL, "POWER" },
-
-       { "LD1L", "DACL LD1L Switch", "DACL" },
-       { "LD1L", "AINL LD1L Switch", "AINLMUX" },
-       { "LD1L", "AINR LD1L Switch", "AINRMUX" },
-
-       { "LD1R", "DACR LD1R Switch", "DACR" },
-       { "LD1R", "AINR LD1R Switch", "AINRMUX" },
-       { "LD1R", "AINL LD1R Switch", "AINLMUX" },
-
-       { "LD2", "DACL LD2 Switch", "DACL" },
-       { "LD2", "AINL LD2 Switch", "AINLMUX" },
-       { "LD2", "DACR LD2 Switch", "DACR" },
-
-       { "HSOUTL", NULL, "LD1L" },
-       { "HSOUTR", NULL, "LD1R" },
-       { "HSOUTL", NULL, "HS1L" },
-       { "HSOUTR", NULL, "HS1R" },
-
-       { "LINEOUTL", NULL, "LD1L" },
-       { "LINEOUTR", NULL, "LD1R" },
-
-       { "LINEOUTMP", NULL, "LD2" },
-       { "LINEOUTMN", NULL, "LD2" },
-};
-
-static const struct snd_soc_component_driver aud96p22_driver = {
-       .controls               = aud96p22_snd_controls,
-       .num_controls           = ARRAY_SIZE(aud96p22_snd_controls),
-       .dapm_widgets           = aud96p22_dapm_widgets,
-       .num_dapm_widgets       = ARRAY_SIZE(aud96p22_dapm_widgets),
-       .dapm_routes            = aud96p22_dapm_routes,
-       .num_dapm_routes        = ARRAY_SIZE(aud96p22_dapm_routes),
-       .idle_bias_on           = 1,
-       .use_pmdown_time        = 1,
-       .endianness             = 1,
-       .non_legacy_dai_naming  = 1,
-};
-
-static int aud96p22_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
-{
-       struct aud96p22_priv *priv = snd_soc_component_get_drvdata(dai->component);
-       struct regmap *regmap = priv->regmap;
-       unsigned int val;
-
-       /* Master/slave mode */
-       switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
-       case SND_SOC_DAIFMT_CBS_CFS:
-               val = 0;
-               break;
-       case SND_SOC_DAIFMT_CBM_CFM:
-               val = I2S1_MS_MODE;
-               break;
-       default:
-               return -EINVAL;
-       }
-
-       regmap_update_bits(regmap, AUD96P22_I2S1_CONFIG_0, I2S1_MS_MODE, val);
-
-       /* Audio format */
-       switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
-       case SND_SOC_DAIFMT_RIGHT_J:
-               val = I2S1_MODE_RIGHT_J;
-               break;
-       case SND_SOC_DAIFMT_I2S:
-               val = I2S1_MODE_I2S;
-               break;
-       case SND_SOC_DAIFMT_LEFT_J:
-               val = I2S1_MODE_LEFT_J;
-               break;
-       default:
-               return -EINVAL;
-       }
-
-       regmap_update_bits(regmap, AUD96P22_I2S1_CONFIG_0, I2S1_MODE_MASK, val);
-
-       return 0;
-}
-
-static const struct snd_soc_dai_ops aud96p22_dai_ops = {
-       .set_fmt = aud96p22_set_fmt,
-};
-
-#define AUD96P22_RATES SNDRV_PCM_RATE_8000_192000
-#define AUD96P22_FORMATS (\
-               SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S18_3LE | \
-               SNDRV_PCM_FMTBIT_S20_3LE | SNDRV_PCM_FMTBIT_S24_LE)
-
-static struct snd_soc_dai_driver aud96p22_dai = {
-       .name = "aud96p22-dai",
-       .playback = {
-               .stream_name = "Playback",
-               .channels_min = 1,
-               .channels_max = 2,
-               .rates = AUD96P22_RATES,
-               .formats = AUD96P22_FORMATS,
-       },
-       .capture = {
-               .stream_name = "Capture",
-               .channels_min = 1,
-               .channels_max = 2,
-               .rates = AUD96P22_RATES,
-               .formats = AUD96P22_FORMATS,
-       },
-       .ops = &aud96p22_dai_ops,
-};
-
-static const struct regmap_config aud96p22_regmap = {
-       .reg_bits = 8,
-       .val_bits = 8,
-       .max_register = AUD96P22_REG_MAX,
-       .cache_type = REGCACHE_RBTREE,
-};
-
-static int aud96p22_i2c_probe(struct i2c_client *i2c,
-                             const struct i2c_device_id *id)
-{
-       struct device *dev = &i2c->dev;
-       struct aud96p22_priv *priv;
-       int ret;
-
-       priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
-       if (priv == NULL)
-               return -ENOMEM;
-
-       priv->regmap = devm_regmap_init_i2c(i2c, &aud96p22_regmap);
-       if (IS_ERR(priv->regmap)) {
-               ret = PTR_ERR(priv->regmap);
-               dev_err(dev, "failed to init i2c regmap: %d\n", ret);
-               return ret;
-       }
-
-       i2c_set_clientdata(i2c, priv);
-
-       ret = devm_snd_soc_register_component(dev, &aud96p22_driver, &aud96p22_dai, 1);
-       if (ret) {
-               dev_err(dev, "failed to register component: %d\n", ret);
-               return ret;
-       }
-
-       return 0;
-}
-
-static int aud96p22_i2c_remove(struct i2c_client *i2c)
-{
-       return 0;
-}
-
-static const struct of_device_id aud96p22_dt_ids[] = {
-       { .compatible = "zte,zx-aud96p22", },
-       { }
-};
-MODULE_DEVICE_TABLE(of, aud96p22_dt_ids);
-
-static struct i2c_driver aud96p22_i2c_driver = {
-       .driver = {
-               .name = "zx_aud96p22",
-               .of_match_table = aud96p22_dt_ids,
-       },
-       .probe = aud96p22_i2c_probe,
-       .remove = aud96p22_i2c_remove,
-};
-module_i2c_driver(aud96p22_i2c_driver);
-
-MODULE_DESCRIPTION("ZTE ASoC AUD96P22 CODEC driver");
-MODULE_AUTHOR("Baoyou Xie <baoyou.xie@linaro.org>");
-MODULE_LICENSE("GPL v2");
index 84db0b7..d7f3003 100644 (file)
@@ -108,6 +108,7 @@ config SND_SOC_FSL_XCVR
 config SND_SOC_FSL_AUD2HTX
        tristate "AUDIO TO HDMI TX module support"
        depends on ARCH_MXC || COMPILE_TEST
+       select SND_SOC_IMX_PCM_DMA if SND_IMX_SOC != n
        help
          Say Y if you want to add AUDIO TO HDMI TX support for NXP.
 
index 02c81d2..c325c98 100644 (file)
@@ -1083,11 +1083,6 @@ static int fsl_asrc_probe(struct platform_device *pdev)
        }
 
        asrc_priv->soc = of_device_get_match_data(&pdev->dev);
-       if (!asrc_priv->soc) {
-               dev_err(&pdev->dev, "failed to get soc data\n");
-               return -ENODEV;
-       }
-
        asrc->use_edma = asrc_priv->soc->use_edma;
        asrc->get_dma_channel = fsl_asrc_get_dma_channel;
        asrc->request_pair = fsl_asrc_request_pair;
index 60951a8..636a702 100644 (file)
@@ -1530,7 +1530,7 @@ static int fsl_easrc_hw_free(struct snd_pcm_substream *substream,
        return 0;
 }
 
-static struct snd_soc_dai_ops fsl_easrc_dai_ops = {
+static const struct snd_soc_dai_ops fsl_easrc_dai_ops = {
        .startup = fsl_easrc_startup,
        .trigger = fsl_easrc_trigger,
        .hw_params = fsl_easrc_hw_params,
index 39637ca..08056fa 100644 (file)
 
 /**
  * struct fsl_esai_soc_data - soc specific data
- * @imx: for imx platform
  * @reset_at_xrun: flags for enable reset operaton
  */
 struct fsl_esai_soc_data {
-       bool imx;
        bool reset_at_xrun;
 };
 
@@ -86,17 +84,14 @@ struct fsl_esai {
 };
 
 static struct fsl_esai_soc_data fsl_esai_vf610 = {
-       .imx = false,
        .reset_at_xrun = true,
 };
 
 static struct fsl_esai_soc_data fsl_esai_imx35 = {
-       .imx = true,
        .reset_at_xrun = true,
 };
 
 static struct fsl_esai_soc_data fsl_esai_imx6ull = {
-       .imx = true,
        .reset_at_xrun = false,
 };
 
@@ -967,10 +962,6 @@ static int fsl_esai_probe(struct platform_device *pdev)
        snprintf(esai_priv->name, sizeof(esai_priv->name), "%pOFn", np);
 
        esai_priv->soc = of_device_get_match_data(&pdev->dev);
-       if (!esai_priv->soc) {
-               dev_err(&pdev->dev, "failed to get soc data\n");
-               return -ENODEV;
-       }
 
        /* Get the addresses and IRQ */
        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
@@ -1042,9 +1033,9 @@ static int fsl_esai_probe(struct platform_device *pdev)
 
        /* Implement full symmetry for synchronous mode */
        if (esai_priv->synchronous) {
-               fsl_esai_dai.symmetric_rates = 1;
+               fsl_esai_dai.symmetric_rate = 1;
                fsl_esai_dai.symmetric_channels = 1;
-               fsl_esai_dai.symmetric_samplebits = 1;
+               fsl_esai_dai.symmetric_sample_bits = 1;
        }
 
        dev_set_drvdata(&pdev->dev, esai_priv);
index efc5daf..5935af2 100644 (file)
@@ -381,7 +381,7 @@ static int fsl_micfil_set_dai_sysclk(struct snd_soc_dai *dai, int clk_id,
        return ret;
 }
 
-static struct snd_soc_dai_ops fsl_micfil_dai_ops = {
+static const struct snd_soc_dai_ops fsl_micfil_dai_ops = {
        .startup = fsl_micfil_startup,
        .trigger = fsl_micfil_trigger,
        .hw_params = fsl_micfil_hw_params,
@@ -637,7 +637,6 @@ static irqreturn_t micfil_err_isr(int irq, void *devid)
 static int fsl_micfil_probe(struct platform_device *pdev)
 {
        struct device_node *np = pdev->dev.of_node;
-       const struct of_device_id *of_id;
        struct fsl_micfil *micfil;
        struct resource *res;
        void __iomem *regs;
@@ -651,11 +650,7 @@ static int fsl_micfil_probe(struct platform_device *pdev)
        micfil->pdev = pdev;
        strncpy(micfil->name, np->name, sizeof(micfil->name) - 1);
 
-       of_id = of_match_device(fsl_micfil_dt_ids, &pdev->dev);
-       if (!of_id || !of_id->data)
-               return -EINVAL;
-
-       micfil->soc = of_id->data;
+       micfil->soc = of_device_get_match_data(&pdev->dev);
 
        /* ipg_clk is used to control the registers
         * ipg_clk_app is used to operate the filter
index f3d3d20..5e65b45 100644 (file)
@@ -1079,9 +1079,9 @@ static int fsl_sai_probe(struct platform_device *pdev)
        /* Sync Tx with Rx as default by following old DT binding */
        sai->synchronous[RX] = true;
        sai->synchronous[TX] = false;
-       sai->cpu_dai_drv.symmetric_rates = 1;
+       sai->cpu_dai_drv.symmetric_rate = 1;
        sai->cpu_dai_drv.symmetric_channels = 1;
-       sai->cpu_dai_drv.symmetric_samplebits = 1;
+       sai->cpu_dai_drv.symmetric_sample_bits = 1;
 
        if (of_find_property(np, "fsl,sai-synchronous-rx", NULL) &&
            of_find_property(np, "fsl,sai-asynchronous", NULL)) {
@@ -1098,9 +1098,9 @@ static int fsl_sai_probe(struct platform_device *pdev)
                /* Discard all settings for asynchronous mode */
                sai->synchronous[RX] = false;
                sai->synchronous[TX] = false;
-               sai->cpu_dai_drv.symmetric_rates = 0;
+               sai->cpu_dai_drv.symmetric_rate = 0;
                sai->cpu_dai_drv.symmetric_channels = 0;
-               sai->cpu_dai_drv.symmetric_samplebits = 0;
+               sai->cpu_dai_drv.symmetric_sample_bits = 0;
        }
 
        if (of_find_property(np, "fsl,sai-mclk-direction-output", NULL) &&
index 5fa178f..174e558 100644 (file)
@@ -1255,7 +1255,7 @@ static int fsl_spdif_probe_txclk(struct fsl_spdif_priv *spdif_priv,
 
        for (i = 0; i < STC_TXCLK_SRC_MAX; i++) {
                sprintf(tmp, "rxtx%d", i);
-               clk = devm_clk_get(&pdev->dev, tmp);
+               clk = devm_clk_get(dev, tmp);
                if (IS_ERR(clk)) {
                        dev_err(dev, "no rxtx%d clock in devicetree\n", i);
                        return PTR_ERR(clk);
@@ -1277,14 +1277,14 @@ static int fsl_spdif_probe_txclk(struct fsl_spdif_priv *spdif_priv,
                        break;
        }
 
-       dev_dbg(&pdev->dev, "use rxtx%d as tx clock source for %dHz sample rate\n",
+       dev_dbg(dev, "use rxtx%d as tx clock source for %dHz sample rate\n",
                        spdif_priv->txclk_src[index], rate[index]);
-       dev_dbg(&pdev->dev, "use txclk df %d for %dHz sample rate\n",
+       dev_dbg(dev, "use txclk df %d for %dHz sample rate\n",
                        spdif_priv->txclk_df[index], rate[index]);
        if (clk_is_match(spdif_priv->txclk[index], spdif_priv->sysclk))
-               dev_dbg(&pdev->dev, "use sysclk df %d for %dHz sample rate\n",
+               dev_dbg(dev, "use sysclk df %d for %dHz sample rate\n",
                                spdif_priv->sysclk_df[index], rate[index]);
-       dev_dbg(&pdev->dev, "the best rate for %dHz sample rate is %dHz\n",
+       dev_dbg(dev, "the best rate for %dHz sample rate is %dHz\n",
                        rate[index], spdif_priv->txrate[index]);
 
        return 0;
@@ -1305,10 +1305,6 @@ static int fsl_spdif_probe(struct platform_device *pdev)
        spdif_priv->pdev = pdev;
 
        spdif_priv->soc = of_device_get_match_data(&pdev->dev);
-       if (!spdif_priv->soc) {
-               dev_err(&pdev->dev, "failed to get soc data\n");
-               return -ENODEV;
-       }
 
        /* Initialize this copy of the CPU DAI driver structure */
        memcpy(&spdif_priv->cpu_dai_drv, &fsl_spdif_dai, sizeof(fsl_spdif_dai));
index 404be27..5781174 100644 (file)
@@ -1397,18 +1397,11 @@ static int fsl_ssi_probe_from_dt(struct fsl_ssi *ssi)
 {
        struct device *dev = ssi->dev;
        struct device_node *np = dev->of_node;
-       const struct of_device_id *of_id;
        const char *p, *sprop;
        const __be32 *iprop;
        u32 dmas[4];
        int ret;
 
-       of_id = of_match_device(fsl_ssi_ids, dev);
-       if (!of_id || !of_id->data)
-               return -EINVAL;
-
-       ssi->soc = of_id->data;
-
        ret = of_property_match_string(np, "clock-names", "ipg");
        /* Get error code if not found */
        ssi->has_ipg_clk_name = ret >= 0;
@@ -1492,6 +1485,7 @@ static int fsl_ssi_probe(struct platform_device *pdev)
                return -ENOMEM;
 
        ssi->dev = dev;
+       ssi->soc = of_device_get_match_data(&pdev->dev);
 
        /* Probe from DT */
        ret = fsl_ssi_probe_from_dt(ssi);
@@ -1537,9 +1531,9 @@ static int fsl_ssi_probe(struct platform_device *pdev)
 
        /* Set software limitations for synchronous mode except AC97 */
        if (ssi->synchronous && !fsl_ssi_is_ac97(ssi)) {
-               ssi->cpu_dai_drv.symmetric_rates = 1;
+               ssi->cpu_dai_drv.symmetric_rate = 1;
                ssi->cpu_dai_drv.symmetric_channels = 1;
-               ssi->cpu_dai_drv.symmetric_samplebits = 1;
+               ssi->cpu_dai_drv.symmetric_sample_bits = 1;
        }
 
        /*
index 3d58c88..6dd0a5f 100644 (file)
@@ -857,7 +857,7 @@ static struct snd_kcontrol_new fsl_xcvr_tx_ctls[] = {
        },
 };
 
-static struct snd_soc_dai_ops fsl_xcvr_dai_ops = {
+static const struct snd_soc_dai_ops fsl_xcvr_dai_ops = {
        .prepare = fsl_xcvr_prepare,
        .startup = fsl_xcvr_startup,
        .shutdown = fsl_xcvr_shutdown,
@@ -1130,16 +1130,11 @@ MODULE_DEVICE_TABLE(of, fsl_xcvr_dt_ids);
 static int fsl_xcvr_probe(struct platform_device *pdev)
 {
        struct device *dev = &pdev->dev;
-       const struct of_device_id *of_id;
        struct fsl_xcvr *xcvr;
        struct resource *ram_res, *regs_res, *rx_res, *tx_res;
        void __iomem *regs;
        int ret, irq;
 
-       of_id = of_match_device(fsl_xcvr_dt_ids, dev);
-       if (!of_id)
-               return -EINVAL;
-
        xcvr = devm_kzalloc(dev, sizeof(*xcvr), GFP_KERNEL);
        if (!xcvr)
                return -ENOMEM;
index 16a04a6..8c5cdcd 100644 (file)
@@ -532,7 +532,7 @@ static int graph_for_each_link(struct asoc_simple_priv *priv,
 static void graph_get_dais_count(struct asoc_simple_priv *priv,
                                 struct link_info *li);
 
-int graph_parse_of(struct asoc_simple_priv *priv, struct device *dev)
+int audio_graph_parse_of(struct asoc_simple_priv *priv, struct device *dev)
 {
        struct snd_soc_card *card = simple_priv_to_card(priv);
        struct link_info li;
@@ -608,7 +608,7 @@ err:
 
        return ret;
 }
-EXPORT_SYMBOL_GPL(graph_parse_of);
+EXPORT_SYMBOL_GPL(audio_graph_parse_of);
 
 static int graph_count_noml(struct asoc_simple_priv *priv,
                            struct device_node *cpu_ep,
@@ -705,7 +705,7 @@ static void graph_get_dais_count(struct asoc_simple_priv *priv,
                li->link, li->dais, li->conf);
 }
 
-int graph_card_probe(struct snd_soc_card *card)
+int audio_graph_card_probe(struct snd_soc_card *card)
 {
        struct asoc_simple_priv *priv = snd_soc_card_get_drvdata(card);
        int ret;
@@ -720,7 +720,7 @@ int graph_card_probe(struct snd_soc_card *card)
 
        return 0;
 }
-EXPORT_SYMBOL_GPL(graph_card_probe);
+EXPORT_SYMBOL_GPL(audio_graph_card_probe);
 
 static int graph_probe(struct platform_device *pdev)
 {
@@ -736,20 +736,21 @@ static int graph_probe(struct platform_device *pdev)
        card = simple_priv_to_card(priv);
        card->dapm_widgets      = graph_dapm_widgets;
        card->num_dapm_widgets  = ARRAY_SIZE(graph_dapm_widgets);
-       card->probe             = graph_card_probe;
+       card->probe             = audio_graph_card_probe;
 
        if (of_device_get_match_data(dev))
                priv->dpcm_selectable = 1;
 
-       return graph_parse_of(priv, dev);
+       return audio_graph_parse_of(priv, dev);
 }
 
-static int graph_remove(struct platform_device *pdev)
+int audio_graph_remove(struct platform_device *pdev)
 {
        struct snd_soc_card *card = platform_get_drvdata(pdev);
 
        return asoc_simple_clean_reference(card);
 }
+EXPORT_SYMBOL_GPL(audio_graph_remove);
 
 static const struct of_device_id graph_of_match[] = {
        { .compatible = "audio-graph-card", },
@@ -766,7 +767,7 @@ static struct platform_driver graph_card = {
                .of_match_table = graph_of_match,
        },
        .probe = graph_probe,
-       .remove = graph_remove,
+       .remove = audio_graph_remove,
 };
 module_platform_driver(graph_card);
 
index 6cada4c..ab31045 100644 (file)
@@ -172,16 +172,15 @@ int asoc_simple_parse_clk(struct device *dev,
         *  or device's module clock.
         */
        clk = devm_get_clk_from_child(dev, node, NULL);
-       if (!IS_ERR(clk)) {
-               simple_dai->sysclk = clk_get_rate(clk);
+       if (IS_ERR(clk))
+               clk = devm_get_clk_from_child(dev, dlc->of_node, NULL);
 
+       if (!IS_ERR(clk)) {
                simple_dai->clk = clk;
-       } else if (!of_property_read_u32(node, "system-clock-frequency", &val)) {
+               simple_dai->sysclk = clk_get_rate(clk);
+       } else if (!of_property_read_u32(node, "system-clock-frequency",
+                                        &val)) {
                simple_dai->sysclk = val;
-       } else {
-               clk = devm_get_clk_from_child(dev, dlc->of_node, NULL);
-               if (!IS_ERR(clk))
-                       simple_dai->sysclk = clk_get_rate(clk);
        }
 
        if (of_property_read_bool(node, "system-clock-direction-out"))
index 0c6404f..f3a4a90 100644 (file)
@@ -203,6 +203,8 @@ config SND_SOC_INTEL_KEEMBAY
        tristate "Keembay Platforms"
        depends on ARCH_KEEMBAY || COMPILE_TEST
        depends on COMMON_CLK
+       select SND_DMAENGINE_PCM
+       select SND_SOC_GENERIC_DMAENGINE_PCM
        help
          If you have a Intel Keembay platform then enable this option
          by saying Y or m.
index b58b9b6..d1d2812 100644 (file)
@@ -111,6 +111,18 @@ config SND_SOC_INTEL_BYTCR_RT5651_MACH
          Say Y or m if you have such a device. This is a recommended option.
          If unsure select "N".
 
+config SND_SOC_INTEL_BYTCR_WM5102_MACH
+       tristate "Baytrail and Baytrail-CR with WM5102 codec"
+       depends on MFD_ARIZONA && MFD_WM5102 && SPI_MASTER && ACPI
+       depends on X86_INTEL_LPSS || COMPILE_TEST
+       select SND_SOC_ACPI
+       select SND_SOC_WM5102
+       help
+         This adds support for ASoC machine driver for Intel(R) Baytrail and Baytrail-CR
+         platforms with WM5102 audio codec.
+         Say Y if you have such a device.
+         If unsure select "N".
+
 config SND_SOC_INTEL_CHT_BSW_RT5672_MACH
        tristate "Cherrytrail & Braswell with RT5672 codec"
        depends on I2C && ACPI
index 5f03e48..616c5fb 100644 (file)
@@ -10,6 +10,7 @@ snd-soc-sst-sof-wm8804-objs := sof_wm8804.o
 snd-soc-sst-glk-rt5682_max98357a-objs := glk_rt5682_max98357a.o hda_dsp_common.o
 snd-soc-sst-bytcr-rt5640-objs := bytcr_rt5640.o
 snd-soc-sst-bytcr-rt5651-objs := bytcr_rt5651.o
+snd-soc-sst-bytcr-wm5102-objs := bytcr_wm5102.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
@@ -51,6 +52,7 @@ obj-$(CONFIG_SND_SOC_INTEL_BDW_RT5650_MACH) += snd-soc-sst-bdw-rt5650-mach.o
 obj-$(CONFIG_SND_SOC_INTEL_BDW_RT5677_MACH) += snd-soc-sst-bdw-rt5677-mach.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_BYTCR_WM5102_MACH) += snd-soc-sst-bytcr-wm5102.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
index 892cf68..06df2d4 100644 (file)
@@ -331,9 +331,6 @@ static struct snd_soc_dai_link byt_cht_es8316_dais[] = {
 
                /* back ends */
        {
-               /* Only SSP2 has been tested here, so BYT-CR platforms that
-                * require SSP0 will not work.
-                */
                .name = "SSP2-Codec",
                .id = 0,
                .no_pcm = 1,
index 5520d7c..782f2b4 100644 (file)
@@ -35,6 +35,7 @@ enum {
        BYT_RT5640_DMIC2_MAP,
        BYT_RT5640_IN1_MAP,
        BYT_RT5640_IN3_MAP,
+       BYT_RT5640_NO_INTERNAL_MIC_MAP,
 };
 
 enum {
@@ -71,6 +72,7 @@ enum {
 #define BYT_RT5640_SSP0_AIF2           BIT(21)
 #define BYT_RT5640_MCLK_EN             BIT(22)
 #define BYT_RT5640_MCLK_25MHZ          BIT(23)
+#define BYT_RT5640_NO_SPEAKERS         BIT(24)
 
 #define BYTCR_INPUT_DEFAULTS                           \
        (BYT_RT5640_IN3_MAP |                           \
@@ -116,6 +118,9 @@ static void log_quirks(struct device *dev)
        case BYT_RT5640_IN3_MAP:
                dev_info(dev, "quirk IN3_MAP enabled\n");
                break;
+       case BYT_RT5640_NO_INTERNAL_MIC_MAP:
+               dev_info(dev, "quirk NO_INTERNAL_MIC_MAP enabled\n");
+               break;
        default:
                dev_err(dev, "quirk map 0x%x is not supported, microphone input will not work\n", map);
                break;
@@ -132,6 +137,8 @@ static void log_quirks(struct device *dev)
                dev_info(dev, "quirk JD_NOT_INV enabled\n");
        if (byt_rt5640_quirk & BYT_RT5640_MONO_SPEAKER)
                dev_info(dev, "quirk MONO_SPEAKER enabled\n");
+       if (byt_rt5640_quirk & BYT_RT5640_NO_SPEAKERS)
+               dev_info(dev, "quirk NO_SPEAKERS enabled\n");
        if (byt_rt5640_quirk & BYT_RT5640_DIFF_MIC)
                dev_info(dev, "quirk DIFF_MIC enabled\n");
        if (byt_rt5640_quirk & BYT_RT5640_SSP0_AIF1) {
@@ -399,6 +406,19 @@ static const struct dmi_system_id byt_rt5640_quirk_table[] = {
                                        BYT_RT5640_SSP0_AIF1 |
                                        BYT_RT5640_MCLK_EN),
        },
+       {       /* Acer One 10 S1002 */
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "One S1002"),
+               },
+               .driver_data = (void *)(BYT_RT5640_IN1_MAP |
+                                       BYT_RT5640_JD_SRC_JD2_IN4N |
+                                       BYT_RT5640_OVCD_TH_2000UA |
+                                       BYT_RT5640_OVCD_SF_0P75 |
+                                       BYT_RT5640_DIFF_MIC |
+                                       BYT_RT5640_SSP0_AIF2 |
+                                       BYT_RT5640_MCLK_EN),
+       },
        {
                .matches = {
                        DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
@@ -524,6 +544,16 @@ static const struct dmi_system_id byt_rt5640_quirk_table[] = {
                                        BYT_RT5640_MONO_SPEAKER |
                                        BYT_RT5640_MCLK_EN),
        },
+       {       /* Estar Beauty HD MID 7316R */
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "Estar"),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "eSTAR BEAUTY HD Intel Quad core"),
+               },
+               .driver_data = (void *)(BYTCR_INPUT_DEFAULTS |
+                                       BYT_RT5640_MONO_SPEAKER |
+                                       BYT_RT5640_SSP0_AIF1 |
+                                       BYT_RT5640_MCLK_EN),
+       },
        {
                .matches = {
                        DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"),
@@ -613,6 +643,15 @@ static const struct dmi_system_id byt_rt5640_quirk_table[] = {
                                        BYT_RT5640_SSP0_AIF1 |
                                        BYT_RT5640_MCLK_EN),
        },
+       {       /* Mele PCG03 Mini PC */
+               .matches = {
+                       DMI_EXACT_MATCH(DMI_BOARD_VENDOR, "Mini PC"),
+                       DMI_EXACT_MATCH(DMI_BOARD_NAME, "Mini PC"),
+               },
+               .driver_data = (void *)(BYT_RT5640_NO_INTERNAL_MIC_MAP |
+                                       BYT_RT5640_NO_SPEAKERS |
+                                       BYT_RT5640_SSP0_AIF1),
+       },
        {       /* MPMAN Converter 9, similar hw as the I.T.Works TW891 2-in-1 */
                .matches = {
                        DMI_MATCH(DMI_SYS_VENDOR, "MPMAN"),
@@ -798,6 +837,20 @@ static const struct dmi_system_id byt_rt5640_quirk_table[] = {
                                        BYT_RT5640_SSP0_AIF2 |
                                        BYT_RT5640_MCLK_EN),
        },
+       {       /* Voyo Winpad A15 */
+               .matches = {
+                       DMI_MATCH(DMI_BOARD_VENDOR, "AMI Corporation"),
+                       DMI_MATCH(DMI_BOARD_NAME, "Aptio CRB"),
+                       /* Above strings are too generic, also match on BIOS date */
+                       DMI_MATCH(DMI_BIOS_DATE, "11/20/2014"),
+               },
+               .driver_data = (void *)(BYT_RT5640_IN1_MAP |
+                                       BYT_RT5640_JD_SRC_JD2_IN4N |
+                                       BYT_RT5640_OVCD_TH_2000UA |
+                                       BYT_RT5640_OVCD_SF_0P75 |
+                                       BYT_RT5640_DIFF_MIC |
+                                       BYT_RT5640_MCLK_EN),
+       },
        {       /* Catch-all for generic Insyde tablets, must be last */
                .matches = {
                        DMI_MATCH(DMI_SYS_VENDOR, "Insyde"),
@@ -873,8 +926,8 @@ static int byt_rt5640_init(struct snd_soc_pcm_runtime *runtime)
        struct snd_soc_card *card = runtime->card;
        struct byt_rt5640_private *priv = snd_soc_card_get_drvdata(card);
        struct snd_soc_component *component = asoc_rtd_to_codec(runtime, 0)->component;
-       const struct snd_soc_dapm_route *custom_map;
-       int num_routes;
+       const struct snd_soc_dapm_route *custom_map = NULL;
+       int num_routes = 0;
        int ret;
 
        card->dapm.idle_bias_off = true;
@@ -909,13 +962,14 @@ static int byt_rt5640_init(struct snd_soc_pcm_runtime *runtime)
                custom_map = byt_rt5640_intmic_in3_map;
                num_routes = ARRAY_SIZE(byt_rt5640_intmic_in3_map);
                break;
+       case BYT_RT5640_DMIC1_MAP:
+               custom_map = byt_rt5640_intmic_dmic1_map;
+               num_routes = ARRAY_SIZE(byt_rt5640_intmic_dmic1_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);
@@ -946,7 +1000,7 @@ static int byt_rt5640_init(struct snd_soc_pcm_runtime *runtime)
                ret = snd_soc_dapm_add_routes(&card->dapm,
                                        byt_rt5640_mono_spk_map,
                                        ARRAY_SIZE(byt_rt5640_mono_spk_map));
-       } else {
+       } else if (!(byt_rt5640_quirk & BYT_RT5640_NO_SPEAKERS)) {
                ret = snd_soc_dapm_add_routes(&card->dapm,
                                        byt_rt5640_stereo_spk_map,
                                        ARRAY_SIZE(byt_rt5640_stereo_spk_map));
@@ -1187,7 +1241,8 @@ struct acpi_chan_package {   /* ACPICA seems to require 64 bit integers */
 static int snd_byt_rt5640_mc_probe(struct platform_device *pdev)
 {
        struct device *dev = &pdev->dev;
-       static const char * const map_name[] = { "dmic1", "dmic2", "in1", "in3" };
+       static const char * const map_name[] = { "dmic1", "dmic2", "in1", "in3", "none" };
+       __maybe_unused const char *spk_type;
        const struct dmi_system_id *dmi_id;
        struct byt_rt5640_private *priv;
        struct snd_soc_acpi_mach *mach;
@@ -1196,7 +1251,7 @@ static int snd_byt_rt5640_mc_probe(struct platform_device *pdev)
        bool sof_parent;
        int ret_val = 0;
        int dai_index = 0;
-       int i;
+       int i, cfg_spk;
 
        is_bytcr = false;
        priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
@@ -1335,16 +1390,24 @@ static int snd_byt_rt5640_mc_probe(struct platform_device *pdev)
                }
        }
 
+       if (byt_rt5640_quirk & BYT_RT5640_NO_SPEAKERS) {
+               cfg_spk = 0;
+               spk_type = "none";
+       } else if (byt_rt5640_quirk & BYT_RT5640_MONO_SPEAKER) {
+               cfg_spk = 1;
+               spk_type = "mono";
+       } else {
+               cfg_spk = 2;
+               spk_type = "stereo";
+       }
+
        snprintf(byt_rt5640_components, sizeof(byt_rt5640_components),
-                "cfg-spk:%s cfg-mic:%s",
-                (byt_rt5640_quirk & BYT_RT5640_MONO_SPEAKER) ? "1" : "2",
+                "cfg-spk:%d cfg-mic:%s", cfg_spk,
                 map_name[BYT_RT5640_MAP(byt_rt5640_quirk)]);
        byt_rt5640_card.components = byt_rt5640_components;
 #if !IS_ENABLED(CONFIG_SND_SOC_INTEL_USER_FRIENDLY_LONG_NAMES)
        snprintf(byt_rt5640_long_name, sizeof(byt_rt5640_long_name),
-                "bytcr-rt5640-%s-spk-%s-mic",
-                (byt_rt5640_quirk & BYT_RT5640_MONO_SPEAKER) ?
-                       "mono" : "stereo",
+                "bytcr-rt5640-%s-spk-%s-mic", spk_type,
                 map_name[BYT_RT5640_MAP(byt_rt5640_quirk)]);
        byt_rt5640_card.long_name = byt_rt5640_long_name;
 #endif
index f289ec8..148b7b1 100644 (file)
@@ -435,6 +435,19 @@ static const struct dmi_system_id byt_rt5651_quirk_table[] = {
                                        BYT_RT5651_SSP0_AIF1 |
                                        BYT_RT5651_MONO_SPEAKER),
        },
+       {
+               /* Jumper EZpad 7 */
+               .callback = byt_rt5651_quirk_cb,
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "Jumper"),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "EZpad"),
+                       /* Jumper12x.WJ2012.bsBKRCP05 with the version dropped */
+                       DMI_MATCH(DMI_BIOS_VERSION, "Jumper12x.WJ2012.bsBKRCP"),
+               },
+               .driver_data = (void *)(BYT_RT5651_DEFAULT_QUIRKS |
+                                       BYT_RT5651_IN2_MAP |
+                                       BYT_RT5651_JD_NOT_INV),
+       },
        {
                /* KIANO SlimNote 14.2 */
                .callback = byt_rt5651_quirk_cb,
diff --git a/sound/soc/intel/boards/bytcr_wm5102.c b/sound/soc/intel/boards/bytcr_wm5102.c
new file mode 100644 (file)
index 0000000..f38850e
--- /dev/null
@@ -0,0 +1,465 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ *  bytcr_wm5102.c - ASoc Machine driver for Intel Baytrail platforms with a
+ *                   Wolfson Microelectronics WM5102 codec
+ *
+ *  Copyright (C) 2020 Hans de Goede <hdegoede@redhat.com>
+ *  Loosely based on bytcr_rt5640.c which is:
+ *  Copyright (C) 2014-2020 Intel Corp
+ *  Author: Subhransu S. Prusty <subhransu.s.prusty@intel.com>
+ */
+
+#include <linux/acpi.h>
+#include <linux/clk.h>
+#include <linux/device.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/spi/spi.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/soc-acpi.h>
+#include "../../codecs/wm5102.h"
+#include "../atom/sst-atom-controls.h"
+
+#define MCLK_FREQ              25000000
+
+#define WM5102_MAX_SYSCLK_4K   49152000 /* max sysclk for 4K family */
+#define WM5102_MAX_SYSCLK_11025        45158400 /* max sysclk for 11.025K family */
+
+struct byt_wm5102_private {
+       struct clk *mclk;
+       struct gpio_desc *spkvdd_en_gpio;
+};
+
+static int byt_wm5102_spkvdd_power_event(struct snd_soc_dapm_widget *w,
+       struct snd_kcontrol *kcontrol, int event)
+{
+       struct snd_soc_card *card = w->dapm->card;
+       struct byt_wm5102_private *priv = snd_soc_card_get_drvdata(card);
+
+       gpiod_set_value_cansleep(priv->spkvdd_en_gpio,
+                                !!SND_SOC_DAPM_EVENT_ON(event));
+
+       return 0;
+}
+
+static int byt_wm5102_prepare_and_enable_pll1(struct snd_soc_dai *codec_dai, int rate)
+{
+       struct snd_soc_component *codec_component = codec_dai->component;
+       int sr_mult = ((rate % 4000) == 0) ?
+               (WM5102_MAX_SYSCLK_4K / rate) :
+               (WM5102_MAX_SYSCLK_11025 / rate);
+       int ret;
+
+       /* Reset FLL1 */
+       snd_soc_dai_set_pll(codec_dai, WM5102_FLL1_REFCLK, ARIZONA_FLL_SRC_NONE, 0, 0);
+       snd_soc_dai_set_pll(codec_dai, WM5102_FLL1, ARIZONA_FLL_SRC_NONE, 0, 0);
+
+       /* Configure the FLL1 PLL before selecting it */
+       ret = snd_soc_dai_set_pll(codec_dai, WM5102_FLL1, ARIZONA_CLK_SRC_MCLK1,
+                                 MCLK_FREQ, rate * sr_mult);
+       if (ret) {
+               dev_err(codec_component->dev, "Error setting PLL: %d\n", ret);
+               return ret;
+       }
+
+       ret = snd_soc_component_set_sysclk(codec_component, ARIZONA_CLK_SYSCLK,
+                                          ARIZONA_CLK_SRC_FLL1, rate * sr_mult,
+                                          SND_SOC_CLOCK_IN);
+       if (ret) {
+               dev_err(codec_component->dev, "Error setting SYSCLK: %d\n", ret);
+               return ret;
+       }
+
+       ret = snd_soc_dai_set_sysclk(codec_dai, ARIZONA_CLK_SYSCLK,
+                                    rate * 512, SND_SOC_CLOCK_IN);
+       if (ret) {
+               dev_err(codec_component->dev, "Error setting clock: %d\n", ret);
+               return ret;
+       }
+
+       return 0;
+}
+
+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;
+       struct byt_wm5102_private *priv = snd_soc_card_get_drvdata(card);
+       int ret;
+
+       codec_dai = snd_soc_card_get_codec_dai(card, "wm5102-aif1");
+       if (!codec_dai) {
+               dev_err(card->dev, "Error codec DAI not found\n");
+               return -EIO;
+       }
+
+       if (SND_SOC_DAPM_EVENT_ON(event)) {
+               ret = clk_prepare_enable(priv->mclk);
+               if (ret) {
+                       dev_err(card->dev, "Error enabling MCLK: %d\n", ret);
+                       return ret;
+               }
+               ret = byt_wm5102_prepare_and_enable_pll1(codec_dai, 48000);
+               if (ret) {
+                       dev_err(card->dev, "Error setting codec sysclk: %d\n", ret);
+                       return ret;
+               }
+       } else {
+               /*
+                * The WM5102 has a separate 32KHz clock for jack-detect
+                * so we can disable the PLL, followed by disabling the
+                * platform clock which is the source-clock for the PLL.
+                */
+               snd_soc_dai_set_pll(codec_dai, WM5102_FLL1, ARIZONA_FLL_SRC_NONE, 0, 0);
+               clk_disable_unprepare(priv->mclk);
+       }
+
+       return 0;
+}
+
+static const struct snd_soc_dapm_widget byt_wm5102_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),
+       SND_SOC_DAPM_SUPPLY("Platform Clock", SND_SOC_NOPM, 0, 0,
+                           platform_clock_control, SND_SOC_DAPM_PRE_PMU |
+                           SND_SOC_DAPM_POST_PMD),
+       SND_SOC_DAPM_SUPPLY("Speaker VDD", SND_SOC_NOPM, 0, 0,
+                           byt_wm5102_spkvdd_power_event,
+                           SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU),
+};
+
+static const struct snd_soc_dapm_route byt_wm5102_audio_map[] = {
+       {"Headphone", NULL, "Platform Clock"},
+       {"Headset Mic", NULL, "Platform Clock"},
+       {"Internal Mic", NULL, "Platform Clock"},
+       {"Speaker", NULL, "Platform Clock"},
+
+       {"Speaker", NULL, "SPKOUTLP"},
+       {"Speaker", NULL, "SPKOUTLN"},
+       {"Speaker", NULL, "SPKOUTRP"},
+       {"Speaker", NULL, "SPKOUTRN"},
+       {"Speaker", NULL, "Speaker VDD"},
+
+       {"Headphone", NULL, "HPOUT1L"},
+       {"Headphone", NULL, "HPOUT1R"},
+
+       {"Internal Mic", NULL, "MICBIAS3"},
+       {"IN3L", NULL, "Internal Mic"},
+
+       /*
+        * The Headset Mix uses MICBIAS1 or 2 depending on if a CTIA/OMTP Headset
+        * is connected, as the MICBIAS is applied after the CTIA/OMTP cross-switch.
+        */
+       {"Headset Mic", NULL, "MICBIAS1"},
+       {"Headset Mic", NULL, "MICBIAS2"},
+       {"IN1L", NULL, "Headset Mic"},
+
+       {"AIF1 Playback", NULL, "ssp0 Tx"},
+       {"ssp0 Tx", NULL, "modem_out"},
+
+       {"modem_in", NULL, "ssp0 Rx"},
+       {"ssp0 Rx", NULL, "AIF1 Capture"},
+};
+
+static const struct snd_kcontrol_new byt_wm5102_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_wm5102_init(struct snd_soc_pcm_runtime *runtime)
+{
+       struct snd_soc_card *card = runtime->card;
+       struct byt_wm5102_private *priv = snd_soc_card_get_drvdata(card);
+       int ret;
+
+       card->dapm.idle_bias_off = true;
+
+       ret = snd_soc_add_card_controls(card, byt_wm5102_controls,
+                                       ARRAY_SIZE(byt_wm5102_controls));
+       if (ret) {
+               dev_err(card->dev, "Error adding card controls: %d\n", ret);
+               return ret;
+       }
+
+       /*
+        * The firmware might enable the clock at boot (this information
+        * may or may not be reflected in the enable clock register).
+        * To change the rate we must disable the clock first to cover these
+        * cases. Due to common clock framework restrictions that do not allow
+        * to disable a clock that has not been enabled, we need to enable
+        * the clock first.
+        */
+       ret = clk_prepare_enable(priv->mclk);
+       if (!ret)
+               clk_disable_unprepare(priv->mclk);
+
+       ret = clk_set_rate(priv->mclk, MCLK_FREQ);
+       if (ret) {
+               dev_err(card->dev, "Error setting MCLK rate: %d\n", ret);
+               return ret;
+       }
+
+       return 0;
+}
+
+static const struct snd_soc_pcm_stream byt_wm5102_dai_params = {
+       .formats = SNDRV_PCM_FMTBIT_S16_LE,
+       .rate_min = 48000,
+       .rate_max = 48000,
+       .channels_min = 2,
+       .channels_max = 2,
+};
+
+static int byt_wm5102_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 */
+       rate->min = 48000;
+       rate->max = 48000;
+       channels->min = 2;
+       channels->max = 2;
+
+       /* set SSP0 to 16-bit */
+       params_set_format(params, SNDRV_PCM_FORMAT_S16_LE);
+
+       /*
+        * Default mode for SSP configuration is TDM 4 slot, override config
+        * with explicit setting to I2S 2ch 16-bit. The word length is set with
+        * dai_set_tdm_slot() since there is no other API exposed
+        */
+       ret = snd_soc_dai_set_fmt(asoc_rtd_to_cpu(rtd, 0),
+                                 SND_SOC_DAIFMT_I2S     |
+                                 SND_SOC_DAIFMT_NB_NF   |
+                                 SND_SOC_DAIFMT_CBS_CFS);
+       if (ret) {
+               dev_err(rtd->dev, "Error setting format to I2S: %d\n", ret);
+               return ret;
+       }
+
+       ret = snd_soc_dai_set_tdm_slot(asoc_rtd_to_cpu(rtd, 0), 0x3, 0x3, 2, 16);
+       if (ret) {
+               dev_err(rtd->dev, "Error setting I2S config: %d\n", ret);
+               return ret;
+       }
+
+       return 0;
+}
+
+static int byt_wm5102_aif1_startup(struct snd_pcm_substream *substream)
+{
+       return snd_pcm_hw_constraint_single(substream->runtime,
+                                           SNDRV_PCM_HW_PARAM_RATE, 48000);
+}
+
+static const struct snd_soc_ops byt_wm5102_aif1_ops = {
+       .startup = byt_wm5102_aif1_startup,
+};
+
+SND_SOC_DAILINK_DEF(dummy,
+       DAILINK_COMP_ARRAY(COMP_DUMMY()));
+
+SND_SOC_DAILINK_DEF(media,
+       DAILINK_COMP_ARRAY(COMP_CPU("media-cpu-dai")));
+
+SND_SOC_DAILINK_DEF(deepbuffer,
+       DAILINK_COMP_ARRAY(COMP_CPU("deepbuffer-cpu-dai")));
+
+SND_SOC_DAILINK_DEF(ssp0_port,
+       DAILINK_COMP_ARRAY(COMP_CPU("ssp0-port")));
+
+SND_SOC_DAILINK_DEF(ssp0_codec,
+       DAILINK_COMP_ARRAY(COMP_CODEC(
+       /*
+        * Note there is no need to overwrite the codec-name as is done in
+        * other bytcr machine drivers, because the codec is a MFD child-dev.
+        */
+       "wm5102-codec",
+       "wm5102-aif1")));
+
+SND_SOC_DAILINK_DEF(platform,
+       DAILINK_COMP_ARRAY(COMP_PLATFORM("sst-mfld-platform")));
+
+static struct snd_soc_dai_link byt_wm5102_dais[] = {
+       [MERR_DPCM_AUDIO] = {
+               .name = "Baytrail Audio Port",
+               .stream_name = "Baytrail Audio",
+               .nonatomic = true,
+               .dynamic = 1,
+               .dpcm_playback = 1,
+               .dpcm_capture = 1,
+               .ops = &byt_wm5102_aif1_ops,
+               SND_SOC_DAILINK_REG(media, dummy, platform),
+
+       },
+       [MERR_DPCM_DEEP_BUFFER] = {
+               .name = "Deep-Buffer Audio Port",
+               .stream_name = "Deep-Buffer Audio",
+               .nonatomic = true,
+               .dynamic = 1,
+               .dpcm_playback = 1,
+               .ops = &byt_wm5102_aif1_ops,
+               SND_SOC_DAILINK_REG(deepbuffer, dummy, platform),
+       },
+               /* back ends */
+       {
+               /*
+                * This must be named SSP2-Codec even though this machine driver
+                * always uses SSP0. Most machine drivers support both and dynamically
+                * update the dailink to point to SSP0 or SSP2, while keeping the name
+                * as "SSP2-Codec". The SOF tplg files hardcode the "SSP2-Codec" even
+                * in the byt-foo-ssp0.tplg versions because the other machine-drivers
+                * use "SSP2-Codec" even when SSP0 is used.
+                */
+               .name = "SSP2-Codec",
+               .id = 0,
+               .no_pcm = 1,
+               .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF
+                                               | SND_SOC_DAIFMT_CBS_CFS,
+               .be_hw_params_fixup = byt_wm5102_codec_fixup,
+               .nonatomic = true,
+               .dpcm_playback = 1,
+               .dpcm_capture = 1,
+               .init = byt_wm5102_init,
+               SND_SOC_DAILINK_REG(ssp0_port, ssp0_codec, platform),
+       },
+};
+
+/* use space before codec name to simplify card ID, and simplify driver name */
+#define SOF_CARD_NAME "bytcht wm5102" /* card name will be 'sof-bytcht wm5102' */
+#define SOF_DRIVER_NAME "SOF"
+
+#define CARD_NAME "bytcr-wm5102"
+#define DRIVER_NAME NULL /* card name will be used for driver name */
+
+/* SoC card */
+static struct snd_soc_card byt_wm5102_card = {
+       .owner = THIS_MODULE,
+       .dai_link = byt_wm5102_dais,
+       .num_links = ARRAY_SIZE(byt_wm5102_dais),
+       .dapm_widgets = byt_wm5102_widgets,
+       .num_dapm_widgets = ARRAY_SIZE(byt_wm5102_widgets),
+       .dapm_routes = byt_wm5102_audio_map,
+       .num_dapm_routes = ARRAY_SIZE(byt_wm5102_audio_map),
+       .fully_routed = true,
+};
+
+static int snd_byt_wm5102_mc_probe(struct platform_device *pdev)
+{
+       char codec_name[SND_ACPI_I2C_ID_LEN];
+       struct device *dev = &pdev->dev;
+       struct byt_wm5102_private *priv;
+       struct snd_soc_acpi_mach *mach;
+       const char *platform_name;
+       struct acpi_device *adev;
+       struct device *codec_dev;
+       bool sof_parent;
+       int ret;
+
+       priv = devm_kzalloc(dev, sizeof(*priv), GFP_ATOMIC);
+       if (!priv)
+               return -ENOMEM;
+
+       /* Get MCLK */
+       priv->mclk = devm_clk_get(dev, "pmc_plt_clk_3");
+       if (IS_ERR(priv->mclk))
+               return dev_err_probe(dev, PTR_ERR(priv->mclk), "getting pmc_plt_clk_3\n");
+
+       /*
+        * Get speaker VDD enable GPIO:
+        * 1. Get codec-device-name
+        * 2. Get codec-device
+        * 3. Get GPIO from codec-device
+        */
+       mach = dev->platform_data;
+       adev = acpi_dev_get_first_match_dev(mach->id, NULL, -1);
+       if (!adev) {
+               dev_err(dev, "Error cannot find acpi-dev for codec\n");
+               return -ENOENT;
+       }
+       snprintf(codec_name, sizeof(codec_name), "spi-%s", acpi_dev_name(adev));
+       put_device(&adev->dev);
+
+       codec_dev = bus_find_device_by_name(&spi_bus_type, NULL, codec_name);
+       if (!codec_dev)
+               return -EPROBE_DEFER;
+
+       /* Note no devm_ here since we call gpiod_get on codec_dev rather then dev */
+       priv->spkvdd_en_gpio = gpiod_get(codec_dev, "wlf,spkvdd-ena", GPIOD_OUT_LOW);
+       put_device(codec_dev);
+
+       if (IS_ERR(priv->spkvdd_en_gpio))
+               return dev_err_probe(dev, PTR_ERR(priv->spkvdd_en_gpio), "getting spkvdd-GPIO\n");
+
+       /* override platform name, if required */
+       byt_wm5102_card.dev = dev;
+       platform_name = mach->mach_params.platform;
+       ret = snd_soc_fixup_dai_links_platform_name(&byt_wm5102_card, platform_name);
+       if (ret)
+               goto out_put_gpio;
+
+       /* set card and driver name and pm-ops */
+       sof_parent = snd_soc_acpi_sof_parent(dev);
+       if (sof_parent) {
+               byt_wm5102_card.name = SOF_CARD_NAME;
+               byt_wm5102_card.driver_name = SOF_DRIVER_NAME;
+               dev->driver->pm = &snd_soc_pm_ops;
+       } else {
+               byt_wm5102_card.name = CARD_NAME;
+               byt_wm5102_card.driver_name = DRIVER_NAME;
+       }
+
+       snd_soc_card_set_drvdata(&byt_wm5102_card, priv);
+       ret = devm_snd_soc_register_card(dev, &byt_wm5102_card);
+       if (ret) {
+               dev_err_probe(dev, ret, "registering card\n");
+               goto out_put_gpio;
+       }
+
+       platform_set_drvdata(pdev, &byt_wm5102_card);
+       return 0;
+
+out_put_gpio:
+       gpiod_put(priv->spkvdd_en_gpio);
+       return ret;
+}
+
+static int snd_byt_wm5102_mc_remove(struct platform_device *pdev)
+{
+       struct snd_soc_card *card = platform_get_drvdata(pdev);
+       struct byt_wm5102_private *priv = snd_soc_card_get_drvdata(card);
+
+       gpiod_put(priv->spkvdd_en_gpio);
+       return 0;
+}
+
+static struct platform_driver snd_byt_wm5102_mc_driver = {
+       .driver = {
+               .name = "bytcr_wm5102",
+       },
+       .probe = snd_byt_wm5102_mc_probe,
+       .remove = snd_byt_wm5102_mc_remove,
+};
+
+module_platform_driver(snd_byt_wm5102_mc_driver);
+
+MODULE_DESCRIPTION("ASoC Baytrail with WM5102 codec machine driver");
+MODULE_AUTHOR("Hans de Goede <hdegoede@redhat.com>");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:bytcr_wm5102");
index fd5e25c..da5a5cb 100644 (file)
@@ -100,13 +100,6 @@ static int cht_codec_init(struct snd_soc_pcm_runtime *runtime)
        struct snd_soc_component *component = codec_dai->component;
        int ret, jack_type;
 
-       /* TDM 4 slots 24 bit, set Rx & Tx bitmask to 4 active slots */
-       ret = snd_soc_dai_set_tdm_slot(codec_dai, 0xf, 0x1, 4, 24);
-       if (ret < 0) {
-               dev_err(runtime->dev, "can't set codec TDM slot %d\n", ret);
-               return ret;
-       }
-
        /* NAU88L24 supports 4 butons headset detection
         * KEY_PLAYPAUSE
         * KEY_VOICECOMMAND
@@ -141,6 +134,7 @@ static int cht_codec_fixup(struct snd_soc_pcm_runtime *rtd,
                SNDRV_PCM_HW_PARAM_CHANNELS);
        struct snd_mask *fmt =
                hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT);
+       int ret;
 
        /* The DSP will covert the FE rate to 48k, stereo, 24bits */
        rate->min = rate->max = 48000;
@@ -150,6 +144,13 @@ static int cht_codec_fixup(struct snd_soc_pcm_runtime *rtd,
        snd_mask_none(fmt);
        params_set_format(params, SNDRV_PCM_FORMAT_S24_LE);
 
+       /* TDM 4 slots 24 bit, set Rx & Tx bitmask to 4 active slots */
+       ret = snd_soc_dai_set_tdm_slot(asoc_rtd_to_codec(rtd, 0), 0xf, 0x1, 4, 24);
+       if (ret < 0) {
+               dev_err(rtd->dev, "can't set codec TDM slot %d\n", ret);
+               return ret;
+       }
+
        return 0;
 }
 
index c2a9757..437d205 100644 (file)
@@ -63,6 +63,7 @@ int max98373_trigger(struct snd_pcm_substream *substream, int cmd)
 {
        struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
        struct snd_soc_dai *codec_dai;
+       struct snd_soc_dai *cpu_dai;
        int j;
        int ret = 0;
 
@@ -70,10 +71,10 @@ int max98373_trigger(struct snd_pcm_substream *substream, int cmd)
        if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
                return 0;
 
+       cpu_dai = asoc_rtd_to_cpu(rtd, 0);
        for_each_rtd_codec_dais(rtd, j, codec_dai) {
-               struct snd_soc_component *component = codec_dai->component;
                struct snd_soc_dapm_context *dapm =
-                               snd_soc_component_get_dapm(component);
+                               snd_soc_component_get_dapm(cpu_dai->component);
                char pin_name[MAX_98373_PIN_NAME];
 
                snprintf(pin_name, ARRAY_SIZE(pin_name), "%s Spk",
index 8b1ca2d..55505e2 100644 (file)
@@ -323,13 +323,6 @@ static int sof_rt1015_hw_params(struct snd_pcm_substream *substream,
                fs = 64;
 
        for_each_rtd_codec_dais(rtd, i, codec_dai) {
-               /* Set tdm/i2s1 master bclk ratio */
-               ret = snd_soc_dai_set_bclk_ratio(codec_dai, fs);
-               if (ret < 0) {
-                       dev_err(card->dev, "failed to set bclk ratio\n");
-                       return ret;
-               }
-
                ret = snd_soc_dai_set_pll(codec_dai, 0, RT1015_PLL_S_BCLK,
                                          params_rate(params) * fs,
                                          params_rate(params) * 256);
index 6d0d6ef..8adce64 100644 (file)
@@ -48,34 +48,14 @@ static int sof_sdw_quirk_cb(const struct dmi_system_id *id)
 }
 
 static const struct dmi_system_id sof_sdw_quirk_table[] = {
+       /* CometLake devices */
        {
                .callback = sof_sdw_quirk_cb,
                .matches = {
-                       DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"),
-                       DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0A32")
-               },
-               .driver_data = (void *)(SOF_RT711_JD_SRC_JD2 |
-                                       SOF_RT715_DAI_ID_FIX |
-                                       SOF_SDW_FOUR_SPK),
-       },
-       {
-               .callback = sof_sdw_quirk_cb,
-               .matches = {
-                       DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"),
-                       DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0A3E")
-               },
-               .driver_data = (void *)(SOF_RT711_JD_SRC_JD2 |
-                                       SOF_RT715_DAI_ID_FIX),
-       },
-       {
-               .callback = sof_sdw_quirk_cb,
-               .matches = {
-                       DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"),
-                       DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0A5E")
+                       DMI_MATCH(DMI_SYS_VENDOR, "Intel Corporation"),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "CometLake Client"),
                },
-               .driver_data = (void *)(SOF_RT711_JD_SRC_JD2 |
-                                       SOF_RT715_DAI_ID_FIX |
-                                       SOF_SDW_FOUR_SPK),
+               .driver_data = (void *)SOF_SDW_PCH_DMIC,
        },
        {
                .callback = sof_sdw_quirk_cb,
@@ -106,7 +86,7 @@ static const struct dmi_system_id sof_sdw_quirk_table[] = {
                                        SOF_RT715_DAI_ID_FIX |
                                        SOF_SDW_FOUR_SPK),
        },
-               {
+       {
                .callback = sof_sdw_quirk_cb,
                .matches = {
                        DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"),
@@ -116,6 +96,16 @@ static const struct dmi_system_id sof_sdw_quirk_table[] = {
                                        SOF_RT715_DAI_ID_FIX |
                                        SOF_SDW_FOUR_SPK),
        },
+       /* IceLake devices */
+       {
+               .callback = sof_sdw_quirk_cb,
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "Intel Corporation"),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "Ice Lake Client"),
+               },
+               .driver_data = (void *)SOF_SDW_PCH_DMIC,
+       },
+       /* TigerLake devices */
        {
                .callback = sof_sdw_quirk_cb,
                .matches = {
@@ -123,25 +113,31 @@ static const struct dmi_system_id sof_sdw_quirk_table[] = {
                        DMI_MATCH(DMI_PRODUCT_NAME,
                                  "Tiger Lake Client Platform"),
                },
-               .driver_data = (void *)(SOF_RT711_JD_SRC_JD1 |
-                               SOF_SDW_TGL_HDMI | SOF_SDW_PCH_DMIC |
-                               SOF_SSP_PORT(SOF_I2S_SSP2)),
+               .driver_data = (void *)(SOF_SDW_TGL_HDMI |
+                                       SOF_RT711_JD_SRC_JD1 |
+                                       SOF_SDW_PCH_DMIC |
+                                       SOF_SSP_PORT(SOF_I2S_SSP2)),
        },
        {
                .callback = sof_sdw_quirk_cb,
                .matches = {
-                       DMI_MATCH(DMI_SYS_VENDOR, "Intel Corporation"),
-                       DMI_MATCH(DMI_PRODUCT_NAME, "Ice Lake Client"),
+                       DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"),
+                       DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0A3E")
                },
-               .driver_data = (void *)SOF_SDW_PCH_DMIC,
+               .driver_data = (void *)(SOF_SDW_TGL_HDMI |
+                                       SOF_RT711_JD_SRC_JD2 |
+                                       SOF_RT715_DAI_ID_FIX),
        },
        {
                .callback = sof_sdw_quirk_cb,
                .matches = {
-                       DMI_MATCH(DMI_SYS_VENDOR, "Intel Corporation"),
-                       DMI_MATCH(DMI_PRODUCT_NAME, "CometLake Client"),
+                       DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"),
+                       DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0A5E")
                },
-               .driver_data = (void *)SOF_SDW_PCH_DMIC,
+               .driver_data = (void *)(SOF_SDW_TGL_HDMI |
+                                       SOF_RT711_JD_SRC_JD2 |
+                                       SOF_RT715_DAI_ID_FIX |
+                                       SOF_SDW_FOUR_SPK),
        },
        {
                .callback = sof_sdw_quirk_cb,
@@ -149,7 +145,8 @@ static const struct dmi_system_id sof_sdw_quirk_table[] = {
                        DMI_MATCH(DMI_SYS_VENDOR, "Google"),
                        DMI_MATCH(DMI_PRODUCT_NAME, "Volteer"),
                },
-               .driver_data = (void *)(SOF_SDW_TGL_HDMI | SOF_SDW_PCH_DMIC |
+               .driver_data = (void *)(SOF_SDW_TGL_HDMI |
+                                       SOF_SDW_PCH_DMIC |
                                        SOF_SDW_FOUR_SPK),
        },
        {
@@ -158,10 +155,38 @@ static const struct dmi_system_id sof_sdw_quirk_table[] = {
                        DMI_MATCH(DMI_SYS_VENDOR, "Google"),
                        DMI_MATCH(DMI_PRODUCT_NAME, "Ripto"),
                },
-               .driver_data = (void *)(SOF_SDW_TGL_HDMI | SOF_SDW_PCH_DMIC |
+               .driver_data = (void *)(SOF_SDW_TGL_HDMI |
+                                       SOF_SDW_PCH_DMIC |
+                                       SOF_SDW_FOUR_SPK),
+       },
+       {
+               /*
+                * this entry covers multiple HP SKUs. The family name
+                * does not seem robust enough, so we use a partial
+                * match that ignores the product name suffix
+                * (e.g. 15-eb1xxx, 14t-ea000 or 13-aw2xxx)
+                */
+               .callback = sof_sdw_quirk_cb,
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "HP"),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "HP Spectre x360 Convertible"),
+               },
+               .driver_data = (void *)(SOF_SDW_TGL_HDMI |
+                                       SOF_SDW_PCH_DMIC |
+                                       SOF_RT711_JD_SRC_JD2),
+       },
+       /* TigerLake-SDCA devices */
+       {
+               .callback = sof_sdw_quirk_cb,
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"),
+                       DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0A32")
+               },
+               .driver_data = (void *)(SOF_SDW_TGL_HDMI |
+                                       SOF_RT711_JD_SRC_JD2 |
+                                       SOF_RT715_DAI_ID_FIX |
                                        SOF_SDW_FOUR_SPK),
        },
-
        {}
 };
 
@@ -451,15 +476,14 @@ static int get_sdw_dailink_info(const struct snd_soc_acpi_link_adr *links,
        return 0;
 }
 
-static void init_dai_link(struct snd_soc_dai_link *dai_links, int be_id,
-                         char *name, int playback, int capture,
-                         struct snd_soc_dai_link_component *cpus,
-                         int cpus_num,
-                         struct snd_soc_dai_link_component *codecs,
-                         int codecs_num,
+static void init_dai_link(struct device *dev, struct snd_soc_dai_link *dai_links,
+                         int be_id, char *name, int playback, int capture,
+                         struct snd_soc_dai_link_component *cpus, int cpus_num,
+                         struct snd_soc_dai_link_component *codecs, int codecs_num,
                          int (*init)(struct snd_soc_pcm_runtime *rtd),
                          const struct snd_soc_ops *ops)
 {
+       dev_dbg(dev, "create dai link %s, id %d\n", name, be_id);
        dai_links->id = be_id;
        dai_links->name = name;
        dai_links->platforms = platform_component;
@@ -797,7 +821,7 @@ static int create_sdw_dailink(struct device *dev, int *be_index,
 
                playback = (stream == SNDRV_PCM_STREAM_PLAYBACK);
                capture = (stream == SNDRV_PCM_STREAM_CAPTURE);
-               init_dai_link(dai_links + *be_index, *be_index, name,
+               init_dai_link(dev, dai_links + *be_index, *be_index, name,
                              playback, capture,
                              cpus + *cpu_id, cpu_dai_num,
                              codecs, codec_num,
@@ -930,7 +954,7 @@ static int sof_card_dai_links_create(struct device *dev,
                ctx->idisp_codec = true;
 
        /* enable dmic01 & dmic16k */
-       dmic_num = (sof_sdw_quirk & SOF_SDW_PCH_DMIC) ? 2 : 0;
+       dmic_num = (sof_sdw_quirk & SOF_SDW_PCH_DMIC || mach_params->dmic_num) ? 2 : 0;
        comp_num += dmic_num;
 
        dev_dbg(dev, "sdw %d, ssp %d, dmic %d, hdmi %d", sdw_be_num, ssp_num,
@@ -1036,7 +1060,7 @@ SSP:
 
                playback = info->direction[SNDRV_PCM_STREAM_PLAYBACK];
                capture = info->direction[SNDRV_PCM_STREAM_CAPTURE];
-               init_dai_link(links + link_id, be_id, name,
+               init_dai_link(dev, links + link_id, be_id, name,
                              playback, capture,
                              cpus + cpu_id, 1,
                              ssp_components, 1,
@@ -1053,7 +1077,7 @@ DMIC:
        /* dmic */
        if (dmic_num > 0) {
                cpus[cpu_id].dai_name = "DMIC01 Pin";
-               init_dai_link(links + link_id, be_id, "dmic01",
+               init_dai_link(dev, links + link_id, be_id, "dmic01",
                              0, 1, // DMIC only supports capture
                              cpus + cpu_id, 1,
                              dmic_component, 1,
@@ -1061,7 +1085,7 @@ DMIC:
                INC_ID(be_id, cpu_id, link_id);
 
                cpus[cpu_id].dai_name = "DMIC16k Pin";
-               init_dai_link(links + link_id, be_id, "dmic16k",
+               init_dai_link(dev, links + link_id, be_id, "dmic16k",
                              0, 1, // DMIC only supports capture
                              cpus + cpu_id, 1,
                              dmic_component, 1,
@@ -1104,7 +1128,7 @@ DMIC:
                        return -ENOMEM;
 
                cpus[cpu_id].dai_name = cpu_name;
-               init_dai_link(links + link_id, be_id, name,
+               init_dai_link(dev, links + link_id, be_id, name,
                              1, 0, // HDMI only supports playback
                              cpus + cpu_id, 1,
                              idisp_components + i, 1,
@@ -1197,6 +1221,15 @@ static int mc_probe(struct platform_device *pdev)
        if (!card->components)
                return -ENOMEM;
 
+       if (mach->mach_params.dmic_num) {
+               card->components = devm_kasprintf(card->dev, GFP_KERNEL,
+                                                 "%s mic:dmic cfg-mics:%d",
+                                                 card->components,
+                                                 mach->mach_params.dmic_num);
+               if (!card->components)
+                       return -ENOMEM;
+       }
+
        card->long_name = sdw_card_long_name;
 
        /* Register the card */
index e5d54bb..ebb27da 100644 (file)
@@ -331,7 +331,7 @@ static int catpt_dai_apply_usettings(struct snd_soc_dai *dai,
 {
        struct catpt_dev *cdev = dev_get_drvdata(dai->dev);
        struct snd_soc_component *component = dai->component;
-       struct snd_kcontrol *pos, *kctl = NULL;
+       struct snd_kcontrol *pos;
        const char *name;
        int ret;
        u32 id = stream->info.stream_hw_id;
@@ -352,21 +352,19 @@ static int catpt_dai_apply_usettings(struct snd_soc_dai *dai,
                break;
        default:
                return 0;
-       };
+       }
 
        list_for_each_entry(pos, &component->card->snd_card->controls, list) {
                if (pos->private_data == component &&
-                   !strncmp(name, pos->id.name, sizeof(pos->id.name))) {
-                       kctl = pos;
+                   !strncmp(name, pos->id.name, sizeof(pos->id.name)))
                        break;
-               }
        }
-       if (!kctl)
+       if (list_entry_is_head(pos, &component->card->snd_card->controls, list))
                return -ENOENT;
 
        if (stream->template->type != CATPT_STRM_TYPE_LOOPBACK)
-               return catpt_set_dspvol(cdev, id, (long *)kctl->private_value);
-       ret = catpt_ipc_mute_loopback(cdev, id, *(bool *)kctl->private_value);
+               return catpt_set_dspvol(cdev, id, (long *)pos->private_value);
+       ret = catpt_ipc_mute_loopback(cdev, id, *(bool *)pos->private_value);
        if (ret)
                return CATPT_IPC_ERROR(ret);
        return 0;
index 06b233d..0aca340 100644 (file)
@@ -44,7 +44,6 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_adl_sdw_machines[] = {
                .link_mask = 0x1, /* link0 required */
                .links = adl_rvp,
                .drv_name = "sof_sdw",
-               .sof_fw_filename = "sof-adl.ri",
                .sof_tplg_filename = "sof-adl-rt711.tplg",
        },
        {},
index 32f77e2..398cc77 100644 (file)
@@ -85,6 +85,3 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_bxt_machines[] = {
        {},
 };
 EXPORT_SYMBOL_GPL(snd_soc_acpi_intel_bxt_machines);
-
-MODULE_LICENSE("GPL v2");
-MODULE_DESCRIPTION("Intel Common ACPI Match module");
index c348607..d1febbb 100644 (file)
@@ -154,6 +154,22 @@ struct snd_soc_acpi_mach  snd_soc_acpi_intel_baytrail_machines[] = {
                .sof_fw_filename = "sof-byt.ri",
                .sof_tplg_filename = "sof-byt-rt5651.tplg",
        },
+       {
+               .id = "WM510204",
+               .drv_name = "bytcr_wm5102",
+               .fw_filename = "intel/fw_sst_0f28.bin",
+               .board = "bytcr_wm5102",
+               .sof_fw_filename = "sof-byt.ri",
+               .sof_tplg_filename = "sof-byt-wm5102.tplg",
+       },
+       {
+               .id = "WM510205",
+               .drv_name = "bytcr_wm5102",
+               .fw_filename = "intel/fw_sst_0f28.bin",
+               .board = "bytcr_wm5102",
+               .sof_fw_filename = "sof-byt.ri",
+               .sof_tplg_filename = "sof-byt-wm5102.tplg",
+       },
        {
                .id = "DLGS7212",
                .drv_name = "bytcht_da7213",
@@ -233,6 +249,3 @@ struct snd_soc_acpi_mach  snd_soc_acpi_intel_baytrail_machines[] = {
        {},
 };
 EXPORT_SYMBOL_GPL(snd_soc_acpi_intel_baytrail_machines);
-
-MODULE_LICENSE("GPL v2");
-MODULE_DESCRIPTION("Intel Common ACPI Match module");
index 27b4b73..1733dfb 100644 (file)
@@ -18,6 +18,3 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_cfl_sdw_machines[] = {
        {}
 };
 EXPORT_SYMBOL_GPL(snd_soc_acpi_intel_cfl_sdw_machines);
-
-MODULE_LICENSE("GPL v2");
-MODULE_DESCRIPTION("Intel Common ACPI Match module");
index 2752dc9..2274242 100644 (file)
@@ -196,6 +196,3 @@ struct snd_soc_acpi_mach  snd_soc_acpi_intel_cherrytrail_machines[] = {
        {},
 };
 EXPORT_SYMBOL_GPL(snd_soc_acpi_intel_cherrytrail_machines);
-
-MODULE_LICENSE("GPL v2");
-MODULE_DESCRIPTION("Intel Common ACPI Match module");
index adddc91..2161b3b 100644 (file)
@@ -309,6 +309,3 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_cml_sdw_machines[] = {
        {}
 };
 EXPORT_SYMBOL_GPL(snd_soc_acpi_intel_cml_sdw_machines);
-
-MODULE_LICENSE("GPL v2");
-MODULE_DESCRIPTION("Intel Common ACPI Match module");
index b80f032..ec77a57 100644 (file)
@@ -63,6 +63,3 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_cnl_sdw_machines[] = {
        {}
 };
 EXPORT_SYMBOL_GPL(snd_soc_acpi_intel_cnl_sdw_machines);
-
-MODULE_LICENSE("GPL v2");
-MODULE_DESCRIPTION("Intel Common ACPI Match module");
index badafc1..6222708 100644 (file)
@@ -1,6 +1,6 @@
 // SPDX-License-Identifier: GPL-2.0-only
 /*
- * soc-apci-intel-ehl-match.c - tables and support for EHL ACPI enumeration.
+ * soc-acpi-intel-ehl-match.c - tables and support for EHL ACPI enumeration.
  *
  * Copyright (c) 2019, Intel Corporation.
  *
@@ -20,6 +20,3 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_ehl_machines[] = {
        {},
 };
 EXPORT_SYMBOL_GPL(snd_soc_acpi_intel_ehl_machines);
-
-MODULE_LICENSE("GPL v2");
-MODULE_DESCRIPTION("Intel Common ACPI Match module");
index 26cb3b1..6ceaab1 100644 (file)
@@ -43,6 +43,3 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_glk_machines[] = {
        {},
 };
 EXPORT_SYMBOL_GPL(snd_soc_acpi_intel_glk_machines);
-
-MODULE_LICENSE("GPL v2");
-MODULE_DESCRIPTION("Intel Common ACPI Match module");
index 3595855..fe343a9 100644 (file)
@@ -53,6 +53,3 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_broadwell_machines[] = {
        {}
 };
 EXPORT_SYMBOL_GPL(snd_soc_acpi_intel_broadwell_machines);
-
-MODULE_LICENSE("GPL v2");
-MODULE_DESCRIPTION("Intel Common ACPI Match module");
index 9a529a7..d38ff7d 100644 (file)
@@ -185,6 +185,3 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_icl_sdw_machines[] = {
        {},
 };
 EXPORT_SYMBOL_GPL(snd_soc_acpi_intel_icl_sdw_machines);
-
-MODULE_LICENSE("GPL v2");
-MODULE_DESCRIPTION("Intel Common ACPI Match module");
index 34f5fca..52238db 100644 (file)
@@ -63,6 +63,3 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_jsl_machines[] = {
        {},
 };
 EXPORT_SYMBOL_GPL(snd_soc_acpi_intel_jsl_machines);
-
-MODULE_LICENSE("GPL v2");
-MODULE_DESCRIPTION("Intel Common ACPI Match module");
index a4fbe67..47dadc9 100644 (file)
@@ -128,6 +128,3 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_kbl_machines[] = {
        {},
 };
 EXPORT_SYMBOL_GPL(snd_soc_acpi_intel_kbl_machines);
-
-MODULE_LICENSE("GPL v2");
-MODULE_DESCRIPTION("Intel Common ACPI Match module");
index 26f9ce1..961df8d 100644 (file)
@@ -42,6 +42,3 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_skl_machines[] = {
        {},
 };
 EXPORT_SYMBOL_GPL(snd_soc_acpi_intel_skl_machines);
-
-MODULE_LICENSE("GPL v2");
-MODULE_DESCRIPTION("Intel Common ACPI Match module");
index 98196e9..40f31c8 100644 (file)
@@ -1,6 +1,6 @@
 // SPDX-License-Identifier: GPL-2.0-only
 /*
- * soc-apci-intel-tgl-match.c - tables and support for ICL ACPI enumeration.
+ * soc-acpi-intel-tgl-match.c - tables and support for TGL ACPI enumeration.
  *
  * Copyright (c) 2019, Intel Corporation.
  *
@@ -205,6 +205,20 @@ static const struct snd_soc_acpi_link_adr tgl_rvp[] = {
        {}
 };
 
+static const struct snd_soc_acpi_link_adr tgl_hp[] = {
+       {
+               .mask = BIT(0),
+               .num_adr = ARRAY_SIZE(rt711_0_adr),
+               .adr_d = rt711_0_adr,
+       },
+       {
+               .mask = BIT(1),
+               .num_adr = ARRAY_SIZE(rt1308_1_single_adr),
+               .adr_d = rt1308_1_single_adr,
+       },
+       {}
+};
+
 static const struct snd_soc_acpi_link_adr tgl_chromebook_base[] = {
        {
                .mask = BIT(0),
@@ -358,14 +372,12 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_tgl_sdw_machines[] = {
                .link_mask = 0x7,
                .links = tgl_sdw_rt711_link1_rt1308_link2_rt715_link0,
                .drv_name = "sof_sdw",
-               .sof_fw_filename = "sof-tgl.ri",
                .sof_tplg_filename = "sof-tgl-rt715-rt711-rt1308-mono.tplg",
        },
        {
                .link_mask = 0xF, /* 4 active links required */
                .links = tgl_3_in_1_default,
                .drv_name = "sof_sdw",
-               .sof_fw_filename = "sof-tgl.ri",
                .sof_tplg_filename = "sof-tgl-rt711-rt1308-rt715.tplg",
        },
        {
@@ -377,40 +389,38 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_tgl_sdw_machines[] = {
                .link_mask = 0xF,
                .links = tgl_3_in_1_mono_amp,
                .drv_name = "sof_sdw",
-               .sof_fw_filename = "sof-tgl.ri",
                .sof_tplg_filename = "sof-tgl-rt711-rt1308-mono-rt715.tplg",
        },
        {
                .link_mask = 0xF, /* 4 active links required */
                .links = tgl_3_in_1_sdca,
                .drv_name = "sof_sdw",
-               .sof_fw_filename = "sof-tgl.ri",
                .sof_tplg_filename = "sof-tgl-rt711-rt1316-rt714.tplg",
        },
+       {
+               .link_mask = 0x3, /* rt711 on link 0 and 1 rt1308 on link 1 */
+               .links = tgl_hp,
+               .drv_name = "sof_sdw",
+               .sof_tplg_filename = "sof-tgl-rt711-rt1308.tplg",
+       },
        {
                .link_mask = 0x3, /* rt711 on link 0 and 2 rt1308s on link 1 */
                .links = tgl_rvp,
                .drv_name = "sof_sdw",
-               .sof_fw_filename = "sof-tgl.ri",
                .sof_tplg_filename = "sof-tgl-rt711-rt1308.tplg",
        },
        {
                .link_mask = 0x3, /* rt5682 on link0 & 2xmax98373 on link 1 */
                .links = tgl_chromebook_base,
                .drv_name = "sof_sdw",
-               .sof_fw_filename = "sof-tgl.ri",
                .sof_tplg_filename = "sof-tgl-sdw-max98373-rt5682.tplg",
        },
        {
                .link_mask = 0x1, /* this will only enable rt5682 for now */
                .links = tgl_chromebook_base,
                .drv_name = "sof_sdw",
-               .sof_fw_filename = "sof-tgl.ri",
                .sof_tplg_filename = "sof-tgl-rt5682.tplg",
        },
        {},
 };
 EXPORT_SYMBOL_GPL(snd_soc_acpi_intel_tgl_sdw_machines);
-
-MODULE_LICENSE("GPL v2");
-MODULE_DESCRIPTION("Intel Common ACPI Match module");
index b07df30..a93987a 100644 (file)
@@ -11,6 +11,7 @@
 
 #if IS_ENABLED(CONFIG_X86)
 
+#include <linux/dmi.h>
 #include <asm/cpu_device_id.h>
 #include <asm/intel-family.h>
 #include <asm/iosf_mbi.h>
@@ -38,12 +39,36 @@ SOC_INTEL_IS_CPU(cml, KABYLAKE_L);
 
 static inline bool soc_intel_is_byt_cr(struct platform_device *pdev)
 {
+       /*
+        * List of systems which:
+        * 1. Use a non CR version of the Bay Trail SoC
+        * 2. Contain at least 6 interrupt resources so that the
+        *    platform_get_resource(pdev, IORESOURCE_IRQ, 5) check below
+        *    succeeds
+        * 3. Despite 1. and 2. still have their IPC IRQ at index 0 rather then 5
+        *
+        * This needs to be here so that it can be shared between the SST and
+        * SOF drivers. We rely on the compiler to optimize this out in files
+        * where soc_intel_is_byt_cr is not used.
+        */
+       static const struct dmi_system_id force_bytcr_table[] = {
+               {       /* Lenovo Yoga Tablet 2 series */
+                       .matches = {
+                               DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
+                               DMI_MATCH(DMI_PRODUCT_FAMILY, "YOGATablet2"),
+                       },
+               },
+               {}
+       };
        struct device *dev = &pdev->dev;
        int status = 0;
 
        if (!soc_intel_is_byt())
                return false;
 
+       if (dmi_check_system(force_bytcr_table))
+               return true;
+
        if (iosf_mbi_available()) {
                u32 bios_status;
 
index 1c3748f..0fd1e8f 100644 (file)
@@ -5,11 +5,14 @@
 // Intel KeemBay Platform driver.
 //
 
+#include <linux/bitrev.h>
 #include <linux/clk.h>
+#include <linux/dma-mapping.h>
 #include <linux/io.h>
 #include <linux/module.h>
 #include <linux/of.h>
 #include <linux/of_device.h>
+#include <sound/dmaengine_pcm.h>
 #include <sound/pcm.h>
 #include <sound/pcm_params.h>
 #include <sound/soc.h>
@@ -37,7 +40,8 @@ static const struct snd_pcm_hardware kmb_pcm_hardware = {
        .rate_max = 48000,
        .formats = SNDRV_PCM_FMTBIT_S16_LE |
                   SNDRV_PCM_FMTBIT_S24_LE |
-                  SNDRV_PCM_FMTBIT_S32_LE,
+                  SNDRV_PCM_FMTBIT_S32_LE |
+                  SNDRV_PCM_FMTBIT_IEC958_SUBFRAME_LE,
        .channels_min = 2,
        .channels_max = 2,
        .buffer_bytes_max = BUFFER_BYTES_MAX,
@@ -48,6 +52,50 @@ static const struct snd_pcm_hardware kmb_pcm_hardware = {
        .fifo_size = 16,
 };
 
+/*
+ * Convert to ADV7511 HDMI hardware format.
+ * ADV7511 HDMI chip need parity bit replaced by block start bit and
+ * with the preamble bits left out.
+ * ALSA IEC958 subframe format:
+ * bit 0-3  = preamble (0x8 = block start)
+ *     4-7  = AUX (=0)
+ *     8-27 = audio data (without AUX if 24bit sample)
+ *     28   = validity
+ *     29   = user data
+ *     30   = channel status
+ *     31   = parity
+ *
+ * ADV7511 IEC958 subframe format:
+ * bit 0-23  = audio data
+ *     24    = validity
+ *     25    = user data
+ *     26    = channel status
+ *     27    = block start
+ *     28-31 = 0
+ * MSB to LSB bit reverse by software as hardware not supporting it.
+ */
+static void hdmi_reformat_iec958(struct snd_pcm_runtime *runtime,
+                                struct kmb_i2s_info *kmb_i2s,
+                                unsigned int tx_ptr)
+{
+       u32(*buf)[2] = (void *)runtime->dma_area;
+       unsigned long temp;
+       u32 i, j, sample;
+
+       for (i = 0; i < kmb_i2s->fifo_th; i++) {
+               j = 0;
+               do {
+                       temp = buf[tx_ptr][j];
+                       /* Replace parity with block start*/
+                       assign_bit(31, &temp, (BIT(3) & temp));
+                       sample = bitrev32(temp);
+                       buf[tx_ptr][j] = sample << 4;
+                       j++;
+               } while (j < 2);
+               tx_ptr++;
+       }
+}
+
 static unsigned int kmb_pcm_tx_fn(struct kmb_i2s_info *kmb_i2s,
                                  struct snd_pcm_runtime *runtime,
                                  unsigned int tx_ptr, bool *period_elapsed)
@@ -63,6 +111,8 @@ static unsigned int kmb_pcm_tx_fn(struct kmb_i2s_info *kmb_i2s,
                        writel(((u16(*)[2])buf)[tx_ptr][0], i2s_base + LRBR_LTHR(0));
                        writel(((u16(*)[2])buf)[tx_ptr][1], i2s_base + RRBR_RTHR(0));
                } else {
+                       if (kmb_i2s->iec958_fmt)
+                               hdmi_reformat_iec958(runtime, kmb_i2s, tx_ptr);
                        writel(((u32(*)[2])buf)[tx_ptr][0], i2s_base + LRBR_LTHR(0));
                        writel(((u32(*)[2])buf)[tx_ptr][1], i2s_base + RRBR_RTHR(0));
                }
@@ -233,6 +283,7 @@ static int kmb_pcm_trigger(struct snd_soc_component *component,
                        kmb_i2s->tx_substream = NULL;
                else
                        kmb_i2s->rx_substream = NULL;
+               kmb_i2s->iec958_fmt = false;
                break;
        default:
                return -EINVAL;
@@ -343,6 +394,53 @@ static const struct snd_soc_component_driver kmb_component = {
        .pointer        = kmb_pcm_pointer,
 };
 
+static const struct snd_soc_component_driver kmb_component_dma = {
+       .name           = "kmb",
+};
+
+static int kmb_probe(struct snd_soc_dai *cpu_dai)
+{
+       struct kmb_i2s_info *kmb_i2s = snd_soc_dai_get_drvdata(cpu_dai);
+
+       if (kmb_i2s->use_pio)
+               return 0;
+
+       snd_soc_dai_init_dma_data(cpu_dai, &kmb_i2s->play_dma_data,
+                                 &kmb_i2s->capture_dma_data);
+
+       return 0;
+}
+
+static inline void kmb_i2s_enable_dma(struct kmb_i2s_info *kmb_i2s, u32 stream)
+{
+       u32 dma_reg;
+
+       dma_reg = readl(kmb_i2s->i2s_base + I2S_DMACR);
+       /* Enable DMA handshake for stream */
+       if (stream == SNDRV_PCM_STREAM_PLAYBACK)
+               dma_reg |= I2S_DMAEN_TXBLOCK;
+       else
+               dma_reg |= I2S_DMAEN_RXBLOCK;
+
+       writel(dma_reg, kmb_i2s->i2s_base + I2S_DMACR);
+}
+
+static inline void kmb_i2s_disable_dma(struct kmb_i2s_info *kmb_i2s, u32 stream)
+{
+       u32 dma_reg;
+
+       dma_reg = readl(kmb_i2s->i2s_base + I2S_DMACR);
+       /* Disable DMA handshake for stream */
+       if (stream == SNDRV_PCM_STREAM_PLAYBACK) {
+               dma_reg &= ~I2S_DMAEN_TXBLOCK;
+               writel(1, kmb_i2s->i2s_base + I2S_RTXDMA);
+       } else {
+               dma_reg &= ~I2S_DMAEN_RXBLOCK;
+               writel(1, kmb_i2s->i2s_base + I2S_RRXDMA);
+       }
+       writel(dma_reg, kmb_i2s->i2s_base + I2S_DMACR);
+}
+
 static void kmb_i2s_start(struct kmb_i2s_info *kmb_i2s,
                          struct snd_pcm_substream *substream)
 {
@@ -356,7 +454,11 @@ static void kmb_i2s_start(struct kmb_i2s_info *kmb_i2s,
        else
                writel(1, kmb_i2s->i2s_base + IRER);
 
-       kmb_i2s_irq_trigger(kmb_i2s, substream->stream, config->chan_nr, true);
+       if (kmb_i2s->use_pio)
+               kmb_i2s_irq_trigger(kmb_i2s, substream->stream,
+                                   config->chan_nr, true);
+       else
+               kmb_i2s_enable_dma(kmb_i2s, substream->stream);
 
        if (kmb_i2s->clock_provider)
                writel(1, kmb_i2s->i2s_base + CER);
@@ -434,7 +536,8 @@ static int kmb_dai_trigger(struct snd_pcm_substream *substream,
                break;
        case SNDRV_PCM_TRIGGER_STOP:
                kmb_i2s->active--;
-               kmb_i2s_stop(kmb_i2s, substream);
+               if (kmb_i2s->use_pio)
+                       kmb_i2s_stop(kmb_i2s, substream);
                break;
        default:
                return  -EINVAL;
@@ -485,16 +588,25 @@ static int kmb_dai_hw_params(struct snd_pcm_substream *substream,
                config->data_width = 16;
                kmb_i2s->ccr = 0x00;
                kmb_i2s->xfer_resolution = 0x02;
+               kmb_i2s->play_dma_data.addr_width = DMA_SLAVE_BUSWIDTH_2_BYTES;
+               kmb_i2s->capture_dma_data.addr_width = DMA_SLAVE_BUSWIDTH_2_BYTES;
                break;
        case SNDRV_PCM_FORMAT_S24_LE:
                config->data_width = 32;
                kmb_i2s->ccr = 0x14;
                kmb_i2s->xfer_resolution = 0x05;
+               kmb_i2s->play_dma_data.addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
+               kmb_i2s->capture_dma_data.addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
                break;
+       case SNDRV_PCM_FORMAT_IEC958_SUBFRAME_LE:
+               kmb_i2s->iec958_fmt = true;
+               fallthrough;
        case SNDRV_PCM_FORMAT_S32_LE:
                config->data_width = 32;
                kmb_i2s->ccr = 0x10;
                kmb_i2s->xfer_resolution = 0x05;
+               kmb_i2s->play_dma_data.addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
+               kmb_i2s->capture_dma_data.addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
                break;
        default:
                dev_err(kmb_i2s->dev, "kmb: unsupported PCM fmt");
@@ -572,13 +684,78 @@ static int kmb_dai_prepare(struct snd_pcm_substream *substream,
        return 0;
 }
 
+static int kmb_dai_startup(struct snd_pcm_substream *substream,
+                          struct snd_soc_dai *cpu_dai)
+{
+       struct kmb_i2s_info *kmb_i2s = snd_soc_dai_get_drvdata(cpu_dai);
+       struct snd_dmaengine_dai_dma_data *dma_data;
+
+       if (kmb_i2s->use_pio)
+               return 0;
+
+       if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+               dma_data = &kmb_i2s->play_dma_data;
+       else
+               dma_data = &kmb_i2s->capture_dma_data;
+
+       snd_soc_dai_set_dma_data(cpu_dai, substream, dma_data);
+
+       return 0;
+}
+
+static int kmb_dai_hw_free(struct snd_pcm_substream *substream,
+                          struct snd_soc_dai *cpu_dai)
+{
+       struct kmb_i2s_info *kmb_i2s = snd_soc_dai_get_drvdata(cpu_dai);
+       /* I2S Programming sequence in Keem_Bay_VPU_DB_v1.1 */
+       if (kmb_i2s->use_pio)
+               kmb_i2s_clear_irqs(kmb_i2s, substream->stream);
+
+       if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+               writel(0, kmb_i2s->i2s_base + ITER);
+       else
+               writel(0, kmb_i2s->i2s_base + IRER);
+
+       if (kmb_i2s->use_pio)
+               kmb_i2s_irq_trigger(kmb_i2s, substream->stream, 8, false);
+       else
+               kmb_i2s_disable_dma(kmb_i2s, substream->stream);
+
+       if (!kmb_i2s->active) {
+               writel(0, kmb_i2s->i2s_base + CER);
+               writel(0, kmb_i2s->i2s_base + IER);
+       }
+
+       return 0;
+}
+
 static struct snd_soc_dai_ops kmb_dai_ops = {
+       .startup        = kmb_dai_startup,
        .trigger        = kmb_dai_trigger,
        .hw_params      = kmb_dai_hw_params,
+       .hw_free        = kmb_dai_hw_free,
        .prepare        = kmb_dai_prepare,
        .set_fmt        = kmb_set_dai_fmt,
 };
 
+static struct snd_soc_dai_driver intel_kmb_hdmi_dai[] = {
+       {
+               .name = "intel_kmb_hdmi_i2s",
+               .playback = {
+                       .channels_min = 2,
+                       .channels_max = 2,
+                       .rates = SNDRV_PCM_RATE_48000,
+                       .rate_min = 48000,
+                       .rate_max = 48000,
+                       .formats = (SNDRV_PCM_FMTBIT_S16_LE |
+                                   SNDRV_PCM_FMTBIT_S24_LE |
+                                   SNDRV_PCM_FMTBIT_IEC958_SUBFRAME_LE),
+               },
+               .ops = &kmb_dai_ops,
+               .probe = kmb_probe,
+       },
+};
+
 static struct snd_soc_dai_driver intel_kmb_i2s_dai[] = {
        {
                .name = "intel_kmb_i2s",
@@ -607,6 +784,7 @@ static struct snd_soc_dai_driver intel_kmb_i2s_dai[] = {
                                    SNDRV_PCM_FMTBIT_S16_LE),
                },
                .ops = &kmb_dai_ops,
+               .probe = kmb_probe,
        },
 };
 
@@ -626,21 +804,25 @@ static struct snd_soc_dai_driver intel_kmb_tdm_dai[] = {
                                    SNDRV_PCM_FMTBIT_S16_LE),
                },
                .ops = &kmb_dai_ops,
+               .probe = kmb_probe,
        },
 };
 
 static const struct of_device_id kmb_plat_of_match[] = {
        { .compatible = "intel,keembay-i2s", .data = &intel_kmb_i2s_dai},
+       { .compatible = "intel,keembay-hdmi-i2s", .data = &intel_kmb_hdmi_dai},
        { .compatible = "intel,keembay-tdm", .data = &intel_kmb_tdm_dai},
        {}
 };
 
 static int kmb_plat_dai_probe(struct platform_device *pdev)
 {
+       struct device_node *np = pdev->dev.of_node;
        struct snd_soc_dai_driver *kmb_i2s_dai;
        const struct of_device_id *match;
        struct device *dev = &pdev->dev;
        struct kmb_i2s_info *kmb_i2s;
+       struct resource *res;
        int ret, irq;
        u32 comp1_reg;
 
@@ -682,7 +864,7 @@ static int kmb_plat_dai_probe(struct platform_device *pdev)
                return PTR_ERR(kmb_i2s->clk_i2s);
        }
 
-       kmb_i2s->i2s_base = devm_platform_ioremap_resource(pdev, 0);
+       kmb_i2s->i2s_base = devm_platform_get_and_ioremap_resource(pdev, 0, &res);
        if (IS_ERR(kmb_i2s->i2s_base))
                return PTR_ERR(kmb_i2s->i2s_base);
 
@@ -692,22 +874,38 @@ static int kmb_plat_dai_probe(struct platform_device *pdev)
 
        kmb_i2s->dev = &pdev->dev;
 
-       irq = platform_get_irq_optional(pdev, 0);
-       if (irq > 0) {
-               ret = devm_request_irq(dev, irq, kmb_i2s_irq_handler, 0,
-                                      pdev->name, kmb_i2s);
-               if (ret < 0) {
-                       dev_err(dev, "failed to request irq\n");
-                       return ret;
-               }
-       }
-
        comp1_reg = readl(kmb_i2s->i2s_base + I2S_COMP_PARAM_1);
 
        kmb_i2s->fifo_th = (1 << COMP1_FIFO_DEPTH(comp1_reg)) / 2;
 
-       ret = devm_snd_soc_register_component(dev, &kmb_component,
-                                             kmb_i2s_dai, 1);
+       kmb_i2s->use_pio = !(of_property_read_bool(np, "dmas"));
+
+       if (kmb_i2s->use_pio) {
+               irq = platform_get_irq_optional(pdev, 0);
+               if (irq > 0) {
+                       ret = devm_request_irq(dev, irq, kmb_i2s_irq_handler, 0,
+                                              pdev->name, kmb_i2s);
+                       if (ret < 0) {
+                               dev_err(dev, "failed to request irq\n");
+                               return ret;
+                       }
+               }
+               ret = devm_snd_soc_register_component(dev, &kmb_component,
+                                                     kmb_i2s_dai, 1);
+       } else {
+               kmb_i2s->play_dma_data.addr = res->start + I2S_TXDMA;
+               kmb_i2s->capture_dma_data.addr = res->start + I2S_RXDMA;
+               ret = snd_dmaengine_pcm_register(&pdev->dev,
+                                                NULL, 0);
+               if (ret) {
+                       dev_err(&pdev->dev, "could not register dmaengine: %d\n",
+                               ret);
+                       return ret;
+               }
+               ret = devm_snd_soc_register_component(dev, &kmb_component_dma,
+                                                     kmb_i2s_dai, 1);
+       }
+
        if (ret) {
                dev_err(dev, "not able to register dai\n");
                return ret;
index 0c393e5..29be2cd 100644 (file)
@@ -12,6 +12,7 @@
 #include <linux/bits.h>
 #include <linux/bitfield.h>
 #include <linux/types.h>
+#include <sound/dmaengine_pcm.h>
 
 /* Register values with reference to KMB databook v1.1 */
 /* common register for all channel */
 #define DW_I2S_PROVIDER        BIT(3)
 
 #define I2S_RXDMA      0x01C0
+#define I2S_RRXDMA     0x01C4
 #define I2S_TXDMA      0x01C8
+#define I2S_RTXDMA     0x01CC
+#define I2S_DMACR      0x0200
+#define I2S_DMAEN_RXBLOCK      (1 << 16)
+#define I2S_DMAEN_TXBLOCK      (1 << 17)
 
 /*
  * struct i2s_clk_config_data - represent i2s clk configuration data
@@ -131,6 +137,9 @@ struct kmb_i2s_info {
        u32 xfer_resolution;
        u32 fifo_th;
        bool clock_provider;
+       /* data related to DMA transfers b/w i2s and DMAC */
+       struct snd_dmaengine_dai_dma_data play_dma_data;
+       struct snd_dmaengine_dai_dma_data capture_dma_data;
 
        struct i2s_clk_config_data config;
        int (*i2s_clk_cfg)(struct i2s_clk_config_data *config);
@@ -141,6 +150,7 @@ struct kmb_i2s_info {
        struct snd_pcm_substream *rx_substream;
        unsigned int tx_ptr;
        unsigned int rx_ptr;
+       bool iec958_fmt;
 };
 
 #endif /* KMB_PLATFORM_H_ */
index 8b99372..5b1a15e 100644 (file)
@@ -950,12 +950,8 @@ static int skl_first_init(struct hdac_bus *bus)
        bus->num_streams = cp_streams + pb_streams;
 
        /* allow 64bit DMA address if supported by H/W */
-       if (!dma_set_mask(bus->dev, DMA_BIT_MASK(64))) {
-               dma_set_coherent_mask(bus->dev, DMA_BIT_MASK(64));
-       } else {
-               dma_set_mask(bus->dev, DMA_BIT_MASK(32));
-               dma_set_coherent_mask(bus->dev, DMA_BIT_MASK(32));
-       }
+       if (dma_set_mask_and_coherent(bus->dev, DMA_BIT_MASK(64)))
+               dma_set_mask_and_coherent(bus->dev, DMA_BIT_MASK(32));
 
        /* initialize streams */
        snd_hdac_ext_stream_init_all
index 0a68f4c..52ba0e3 100644 (file)
@@ -455,7 +455,7 @@ static struct snd_soc_dai_driver jz4740_i2s_dai = {
                .rates = SNDRV_PCM_RATE_8000_48000,
                .formats = JZ4740_I2S_FMTS,
        },
-       .symmetric_rates = 1,
+       .symmetric_rate = 1,
        .ops = &jz4740_i2s_dai_ops,
 };
 
index e037826..c2a5933 100644 (file)
@@ -182,25 +182,6 @@ static int kirkwood_dma_close(struct snd_soc_component *component,
        return 0;
 }
 
-static int kirkwood_dma_hw_params(struct snd_soc_component *component,
-                                 struct snd_pcm_substream *substream,
-                                 struct snd_pcm_hw_params *params)
-{
-       struct snd_pcm_runtime *runtime = substream->runtime;
-
-       snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer);
-       runtime->dma_bytes = params_buffer_bytes(params);
-
-       return 0;
-}
-
-static int kirkwood_dma_hw_free(struct snd_soc_component *component,
-                               struct snd_pcm_substream *substream)
-{
-       snd_pcm_set_runtime_buffer(substream, NULL);
-       return 0;
-}
-
 static int kirkwood_dma_prepare(struct snd_soc_component *component,
                                struct snd_pcm_substream *substream)
 {
@@ -244,82 +225,28 @@ static snd_pcm_uframes_t kirkwood_dma_pointer(
        return count;
 }
 
-static int kirkwood_dma_preallocate_dma_buffer(struct snd_pcm *pcm,
-               int stream)
-{
-       struct snd_pcm_substream *substream = pcm->streams[stream].substream;
-       struct snd_dma_buffer *buf = &substream->dma_buffer;
-       size_t size = kirkwood_dma_snd_hw.buffer_bytes_max;
-
-       buf->dev.type = SNDRV_DMA_TYPE_DEV;
-       buf->dev.dev = pcm->card->dev;
-       buf->area = dma_alloc_coherent(pcm->card->dev, size,
-                       &buf->addr, GFP_KERNEL);
-       if (!buf->area)
-               return -ENOMEM;
-       buf->bytes = size;
-       buf->private_data = NULL;
-
-       return 0;
-}
-
 static int kirkwood_dma_new(struct snd_soc_component *component,
                            struct snd_soc_pcm_runtime *rtd)
 {
+       size_t size = kirkwood_dma_snd_hw.buffer_bytes_max;
        struct snd_card *card = rtd->card->snd_card;
-       struct snd_pcm *pcm = rtd->pcm;
        int ret;
 
        ret = dma_coerce_mask_and_coherent(card->dev, DMA_BIT_MASK(32));
        if (ret)
                return ret;
 
-       if (pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream) {
-               ret = kirkwood_dma_preallocate_dma_buffer(pcm,
-                               SNDRV_PCM_STREAM_PLAYBACK);
-               if (ret)
-                       return ret;
-       }
-
-       if (pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream) {
-               ret = kirkwood_dma_preallocate_dma_buffer(pcm,
-                               SNDRV_PCM_STREAM_CAPTURE);
-               if (ret)
-                       return ret;
-       }
+       snd_pcm_set_managed_buffer_all(rtd->pcm, SNDRV_DMA_TYPE_DEV,
+                                      card->dev, size, size);
 
        return 0;
 }
 
-static void kirkwood_dma_free_dma_buffers(struct snd_soc_component *component,
-                                         struct snd_pcm *pcm)
-{
-       struct snd_pcm_substream *substream;
-       struct snd_dma_buffer *buf;
-       int stream;
-
-       for (stream = 0; stream < 2; stream++) {
-               substream = pcm->streams[stream].substream;
-               if (!substream)
-                       continue;
-               buf = &substream->dma_buffer;
-               if (!buf->area)
-                       continue;
-
-               dma_free_coherent(pcm->card->dev, buf->bytes,
-                               buf->area, buf->addr);
-               buf->area = NULL;
-       }
-}
-
 const struct snd_soc_component_driver kirkwood_soc_component = {
        .name           = DRV_NAME,
        .open           = kirkwood_dma_open,
        .close          = kirkwood_dma_close,
-       .hw_params      = kirkwood_dma_hw_params,
-       .hw_free        = kirkwood_dma_hw_free,
        .prepare        = kirkwood_dma_prepare,
        .pointer        = kirkwood_dma_pointer,
        .pcm_construct  = kirkwood_dma_new,
-       .pcm_destruct   = kirkwood_dma_free_dma_buffers,
 };
index 8d3dcfb..effdb76 100644 (file)
@@ -172,7 +172,7 @@ config SND_SOC_MT8192
 config SND_SOC_MT8192_MT6359_RT1015_RT5682
        tristate "ASoC Audio driver for MT8192 with MT6359 RT1015 RT5682 codec"
        depends on I2C
-       depends on SND_SOC_MT8192
+       depends on SND_SOC_MT8192 && MTK_PMIC_WRAP
        select SND_SOC_MT6359
        select SND_SOC_RT1015
        select SND_SOC_RT1015P
index df29641..d5cffe7 100644 (file)
@@ -655,7 +655,7 @@ static struct snd_soc_dai_driver mt2701_afe_pcm_dais[] = {
 
                },
                .ops = &mt2701_afe_i2s_ops,
-               .symmetric_rates = 1,
+               .symmetric_rate = 1,
        },
        {
                .name = "I2S1",
@@ -679,7 +679,7 @@ static struct snd_soc_dai_driver mt2701_afe_pcm_dais[] = {
                                | SNDRV_PCM_FMTBIT_S32_LE)
                        },
                .ops = &mt2701_afe_i2s_ops,
-               .symmetric_rates = 1,
+               .symmetric_rate = 1,
        },
        {
                .name = "I2S2",
@@ -703,7 +703,7 @@ static struct snd_soc_dai_driver mt2701_afe_pcm_dais[] = {
                                | SNDRV_PCM_FMTBIT_S32_LE)
                        },
                .ops = &mt2701_afe_i2s_ops,
-               .symmetric_rates = 1,
+               .symmetric_rate = 1,
        },
        {
                .name = "I2S3",
@@ -727,7 +727,7 @@ static struct snd_soc_dai_driver mt2701_afe_pcm_dais[] = {
                                | SNDRV_PCM_FMTBIT_S32_LE)
                        },
                .ops = &mt2701_afe_i2s_ops,
-               .symmetric_rates = 1,
+               .symmetric_rate = 1,
        },
        {
                .name = "MRG BT",
@@ -749,7 +749,7 @@ static struct snd_soc_dai_driver mt2701_afe_pcm_dais[] = {
                        .formats = SNDRV_PCM_FMTBIT_S16_LE,
                },
                .ops = &mt2701_btmrg_ops,
-               .symmetric_rates = 1,
+               .symmetric_rate = 1,
        }
 };
 
index 3136f0b..51f736f 100644 (file)
@@ -270,8 +270,8 @@ static struct snd_soc_dai_driver mtk_dai_pcm_driver[] = {
                        .formats = MTK_PCM_FORMATS,
                },
                .ops = &mtk_dai_pcm_ops,
-               .symmetric_rates = 1,
-               .symmetric_samplebits = 1,
+               .symmetric_rate = 1,
+               .symmetric_sample_bits = 1,
        },
        {
                .name = "PCM 2",
@@ -291,8 +291,8 @@ static struct snd_soc_dai_driver mtk_dai_pcm_driver[] = {
                        .formats = MTK_PCM_FORMATS,
                },
                .ops = &mtk_dai_pcm_ops,
-               .symmetric_rates = 1,
-               .symmetric_samplebits = 1,
+               .symmetric_rate = 1,
+               .symmetric_sample_bits = 1,
        },
 };
 
index 7e7bda7..685f407 100644 (file)
@@ -571,7 +571,7 @@ static struct snd_soc_dai_driver mt8173_afe_pcm_dais[] = {
                        .formats = SNDRV_PCM_FMTBIT_S16_LE,
                },
                .ops = &mt8173_afe_i2s_ops,
-               .symmetric_rates = 1,
+               .symmetric_rate = 1,
        },
 };
 
index cfbd0c6..a4d26a6 100644 (file)
@@ -125,12 +125,6 @@ mt8183_da7219_rt1015_i2s_hw_params(struct snd_pcm_substream *substream,
        for_each_rtd_codec_dais(rtd, i, codec_dai) {
                if (!strcmp(codec_dai->component->name, RT1015_DEV0_NAME) ||
                    !strcmp(codec_dai->component->name, RT1015_DEV1_NAME)) {
-                       ret = snd_soc_dai_set_bclk_ratio(codec_dai, 64);
-                       if (ret) {
-                               dev_err(rtd->dev, "failed to set bclk ratio\n");
-                               return ret;
-                       }
-
                        ret = snd_soc_dai_set_pll(codec_dai, 0,
                                                  RT1015_PLL_S_BCLK,
                                                  rate * 64, rate * 256);
index bc3ba32..38ce0e3 100644 (file)
@@ -270,8 +270,8 @@ static struct snd_soc_dai_driver mtk_dai_pcm_driver[] = {
                        .formats = MTK_PCM_FORMATS,
                },
                .ops = &mtk_dai_pcm_ops,
-               .symmetric_rates = 1,
-               .symmetric_samplebits = 1,
+               .symmetric_rate = 1,
+               .symmetric_sample_bits = 1,
        },
        {
                .name = "PCM 2",
@@ -291,8 +291,8 @@ static struct snd_soc_dai_driver mtk_dai_pcm_driver[] = {
                        .formats = MTK_PCM_FORMATS,
                },
                .ops = &mtk_dai_pcm_ops,
-               .symmetric_rates = 1,
-               .symmetric_samplebits = 1,
+               .symmetric_rate = 1,
+               .symmetric_sample_bits = 1,
        },
 };
 
index 1ce3edd..271413e 100644 (file)
@@ -68,12 +68,6 @@ mt8183_mt6358_rt1015_i2s_hw_params(struct snd_pcm_substream *substream,
        int ret, i;
 
        for_each_rtd_codec_dais(rtd, i, codec_dai) {
-               ret = snd_soc_dai_set_bclk_ratio(codec_dai, 64);
-               if (ret < 0) {
-                       dev_err(card->dev, "failed to set bclk ratio\n");
-                       return ret;
-               }
-
                ret = snd_soc_dai_set_pll(codec_dai, 0, RT1015_PLL_S_BCLK,
                                rate * 64, rate * 256);
                if (ret < 0) {
@@ -123,6 +117,45 @@ static int mt8183_rt1015_i2s_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
        return 0;
 }
 
+static int
+mt8183_mt6358_startup(struct snd_pcm_substream *substream)
+{
+       static const unsigned int rates[] = {
+               48000,
+       };
+       static const struct snd_pcm_hw_constraint_list constraints_rates = {
+               .count = ARRAY_SIZE(rates),
+               .list  = rates,
+               .mask = 0,
+       };
+       static const unsigned int channels[] = {
+               2,
+       };
+       static const struct snd_pcm_hw_constraint_list constraints_channels = {
+               .count = ARRAY_SIZE(channels),
+               .list = channels,
+               .mask = 0,
+       };
+
+       struct snd_pcm_runtime *runtime = substream->runtime;
+
+       snd_pcm_hw_constraint_list(runtime, 0,
+                                  SNDRV_PCM_HW_PARAM_RATE, &constraints_rates);
+       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);
+
+       return 0;
+}
+
+static const struct snd_soc_ops mt8183_mt6358_ops = {
+       .startup = mt8183_mt6358_startup,
+};
+
 static int
 mt8183_mt6358_ts3a227_max98357_bt_sco_startup(
        struct snd_pcm_substream *substream)
@@ -362,6 +395,7 @@ static struct snd_soc_dai_link mt8183_mt6358_ts3a227_dai_links[] = {
                            SND_SOC_DPCM_TRIGGER_PRE},
                .dynamic = 1,
                .dpcm_playback = 1,
+               .ops = &mt8183_mt6358_ops,
                SND_SOC_DAILINK_REG(playback1),
        },
        {
@@ -409,6 +443,7 @@ static struct snd_soc_dai_link mt8183_mt6358_ts3a227_dai_links[] = {
                            SND_SOC_DPCM_TRIGGER_PRE},
                .dynamic = 1,
                .dpcm_capture = 1,
+               .ops = &mt8183_mt6358_ops,
                SND_SOC_DAILINK_REG(capture3),
        },
        {
index e7fec2d..7a1724f 100644 (file)
@@ -42,7 +42,7 @@ static const struct snd_pcm_hardware mt8192_afe_hardware = {
 static int mt8192_memif_fs(struct snd_pcm_substream *substream,
                           unsigned int rate)
 {
-       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+       struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
        struct snd_soc_component *component =
                snd_soc_rtdcom_lookup(rtd, AFE_PCM_NAME);
        struct mtk_base_afe *afe = snd_soc_component_get_drvdata(component);
@@ -59,7 +59,7 @@ static int mt8192_get_dai_fs(struct mtk_base_afe *afe,
 
 static int mt8192_irq_fs(struct snd_pcm_substream *substream, unsigned int rate)
 {
-       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+       struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
        struct snd_soc_component *component =
                snd_soc_rtdcom_lookup(rtd, AFE_PCM_NAME);
        struct mtk_base_afe *afe = snd_soc_component_get_drvdata(component);
index 6e94cfd..239e3f5 100644 (file)
@@ -360,8 +360,8 @@ static struct snd_soc_dai_driver mtk_dai_pcm_driver[] = {
                        .formats = MTK_PCM_FORMATS,
                },
                .ops = &mtk_dai_pcm_ops,
-               .symmetric_rates = 1,
-               .symmetric_samplebits = 1,
+               .symmetric_rate = 1,
+               .symmetric_sample_bits = 1,
        },
        {
                .name = "PCM 2",
@@ -381,8 +381,8 @@ static struct snd_soc_dai_driver mtk_dai_pcm_driver[] = {
                        .formats = MTK_PCM_FORMATS,
                },
                .ops = &mtk_dai_pcm_ops,
-               .symmetric_rates = 1,
-               .symmetric_samplebits = 1,
+               .symmetric_rate = 1,
+               .symmetric_sample_bits = 1,
        },
 };
 
index 8383536..f5de1d7 100644 (file)
@@ -738,7 +738,7 @@ static struct mtk_afe_tdm_priv *init_tdm_priv_data(struct mtk_base_afe *afe)
        if (!tdm_priv)
                return NULL;
 
-       tdm_priv->mclk_multiple = 128;
+       tdm_priv->mclk_multiple = 512;
        tdm_priv->bck_id = MT8192_I2S4_BCK;
        tdm_priv->mclk_id = MT8192_I2S4_MCK;
        tdm_priv->id = MT8192_DAI_TDM;
index ae2c748..a606133 100644 (file)
 #define RT5682_CODEC_DAI       "rt5682-aif1"
 #define RT5682_DEV0_NAME       "rt5682.1-001a"
 
-static struct snd_soc_jack headset_jack;
+struct mt8192_mt6359_priv {
+       struct snd_soc_jack headset_jack;
+       struct snd_soc_jack hdmi_jack;
+};
 
 static int mt8192_rt1015_i2s_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_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
        struct snd_soc_card *card = rtd->card;
        struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0);
        struct snd_soc_dai *codec_dai;
@@ -46,12 +49,6 @@ static int mt8192_rt1015_i2s_hw_params(struct snd_pcm_substream *substream,
        int ret, i;
 
        for_each_rtd_codec_dais(rtd, i, codec_dai) {
-               ret = snd_soc_dai_set_bclk_ratio(codec_dai, 64);
-               if (ret) {
-                       dev_err(card->dev, "failed to set bclk ratio\n");
-                       return ret;
-               }
-
                ret = snd_soc_dai_set_pll(codec_dai, 0,
                                          RT1015_PLL_S_BCLK,
                                          params_rate(params) * 64,
@@ -77,7 +74,7 @@ static int mt8192_rt1015_i2s_hw_params(struct snd_pcm_substream *substream,
 static int mt8192_rt5682_i2s_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_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
        struct snd_soc_card *card = rtd->card;
        struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0);
        struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0);
@@ -311,7 +308,8 @@ static int mt8192_rt5682_init(struct snd_soc_pcm_runtime *rtd)
 {
        struct snd_soc_component *cmpnt_codec =
                asoc_rtd_to_codec(rtd, 0)->component;
-       struct snd_soc_jack *jack = &headset_jack;
+       struct mt8192_mt6359_priv *priv = snd_soc_card_get_drvdata(rtd->card);
+       struct snd_soc_jack *jack = &priv->headset_jack;
        int ret;
 
        ret = snd_soc_card_jack_new(rtd->card, "Headset Jack",
@@ -329,14 +327,25 @@ static int mt8192_rt5682_init(struct snd_soc_pcm_runtime *rtd)
        snd_jack_set_key(jack->jack, SND_JACK_BTN_2, KEY_VOLUMEUP);
        snd_jack_set_key(jack->jack, SND_JACK_BTN_3, KEY_VOLUMEDOWN);
 
-       ret = snd_soc_component_set_jack(cmpnt_codec, jack, NULL);
+       return snd_soc_component_set_jack(cmpnt_codec, jack, NULL);
+};
+
+static int mt8192_mt6359_hdmi_init(struct snd_soc_pcm_runtime *rtd)
+{
+       struct snd_soc_component *cmpnt_codec =
+               asoc_rtd_to_codec(rtd, 0)->component;
+       struct mt8192_mt6359_priv *priv = snd_soc_card_get_drvdata(rtd->card);
+       int ret;
+
+       ret = snd_soc_card_jack_new(rtd->card, "HDMI Jack", SND_JACK_LINEOUT,
+                                   &priv->hdmi_jack, NULL, 0);
        if (ret) {
-               dev_err(rtd->dev, "Headset Jack set failed: %d\n", ret);
+               dev_err(rtd->dev, "HDMI Jack creation failed: %d\n", ret);
                return ret;
        }
 
-       return 0;
-};
+       return snd_soc_component_set_jack(cmpnt_codec, &priv->hdmi_jack, NULL);
+}
 
 static int mt8192_i2s_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
                                      struct snd_pcm_hw_params *params)
@@ -351,14 +360,8 @@ static int mt8192_i2s_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
 }
 
 static int
-mt8192_mt6359_rt1015_rt5682_cap1_startup(struct snd_pcm_substream *substream)
+mt8192_mt6359_cap1_startup(struct snd_pcm_substream *substream)
 {
-       struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_component *component =
-               snd_soc_rtdcom_lookup(rtd, AFE_PCM_NAME);
-       struct mtk_base_afe *afe = snd_soc_component_get_drvdata(component);
-       int ret;
-
        static const unsigned int channels[] = {
                1, 2, 4
        };
@@ -376,13 +379,15 @@ mt8192_mt6359_rt1015_rt5682_cap1_startup(struct snd_pcm_substream *substream)
                .mask = 0,
        };
 
+       struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
        struct snd_pcm_runtime *runtime = substream->runtime;
+       int ret;
 
        ret = snd_pcm_hw_constraint_list(runtime, 0,
                                         SNDRV_PCM_HW_PARAM_CHANNELS,
                                         &constraints_channels);
        if (ret < 0) {
-               dev_err(afe->dev, "hw_constraint_list channels failed\n");
+               dev_err(rtd->dev, "hw_constraint_list channels failed\n");
                return ret;
        }
 
@@ -390,15 +395,15 @@ mt8192_mt6359_rt1015_rt5682_cap1_startup(struct snd_pcm_substream *substream)
                                         SNDRV_PCM_HW_PARAM_RATE,
                                         &constraints_rates);
        if (ret < 0) {
-               dev_err(afe->dev, "hw_constraint_list rate failed\n");
+               dev_err(rtd->dev, "hw_constraint_list rate failed\n");
                return ret;
        }
 
        return 0;
 }
 
-static const struct snd_soc_ops mt8192_mt6359_rt1015_rt5682_capture1_ops = {
-       .startup = mt8192_mt6359_rt1015_rt5682_cap1_startup,
+static const struct snd_soc_ops mt8192_mt6359_capture1_ops = {
+       .startup = mt8192_mt6359_cap1_startup,
 };
 
 static int
@@ -656,7 +661,7 @@ SND_SOC_DAILINK_DEFS(pcm2,
 
 SND_SOC_DAILINK_DEFS(tdm,
                     DAILINK_COMP_ARRAY(COMP_CPU("TDM")),
-                    DAILINK_COMP_ARRAY(COMP_DUMMY()),
+                    DAILINK_COMP_ARRAY(COMP_CODEC(NULL, "i2s-hifi")),
                     DAILINK_COMP_ARRAY(COMP_EMPTY()));
 
 static struct snd_soc_dai_link mt8192_mt6359_dai_links[] = {
@@ -759,7 +764,7 @@ static struct snd_soc_dai_link mt8192_mt6359_dai_links[] = {
                            SND_SOC_DPCM_TRIGGER_PRE},
                .dynamic = 1,
                .dpcm_capture = 1,
-               .ops = &mt8192_mt6359_rt1015_rt5682_capture1_ops,
+               .ops = &mt8192_mt6359_capture1_ops,
                SND_SOC_DAILINK_REG(capture1),
        },
        {
@@ -994,8 +999,14 @@ static struct snd_soc_dai_link mt8192_mt6359_dai_links[] = {
        {
                .name = "TDM",
                .no_pcm = 1,
+               .dai_fmt = SND_SOC_DAIFMT_DSP_A |
+                          SND_SOC_DAIFMT_IB_NF |
+                          SND_SOC_DAIFMT_CBM_CFM,
                .dpcm_playback = 1,
                .ignore_suspend = 1,
+               .be_hw_params_fixup = mt8192_i2s_hw_params_fixup,
+               .ignore = 1,
+               .init = mt8192_mt6359_hdmi_init,
                SND_SOC_DAILINK_REG(tdm),
        },
 };
@@ -1006,6 +1017,7 @@ mt8192_mt6359_rt1015_rt5682_widgets[] = {
        SND_SOC_DAPM_SPK("Right Spk", NULL),
        SND_SOC_DAPM_HP("Headphone Jack", NULL),
        SND_SOC_DAPM_MIC("Headset Mic", NULL),
+       SND_SOC_DAPM_OUTPUT("TDM Out"),
 };
 
 static const struct snd_soc_dapm_route mt8192_mt6359_rt1015_rt5682_routes[] = {
@@ -1016,6 +1028,8 @@ static const struct snd_soc_dapm_route mt8192_mt6359_rt1015_rt5682_routes[] = {
        { "Headphone Jack", NULL, "HPOL" },
        { "Headphone Jack", NULL, "HPOR" },
        { "IN1P", NULL, "Headset Mic" },
+       /* TDM */
+       { "TDM Out", NULL, "TDM" },
 };
 
 static const struct snd_kcontrol_new mt8192_mt6359_rt1015_rt5682_controls[] = {
@@ -1089,10 +1103,11 @@ static struct snd_soc_card mt8192_mt6359_rt1015p_rt5682_card = {
 static int mt8192_mt6359_dev_probe(struct platform_device *pdev)
 {
        struct snd_soc_card *card;
-       struct device_node *platform_node;
+       struct device_node *platform_node, *hdmi_codec;
        int ret, i;
        struct snd_soc_dai_link *dai_link;
        const struct of_device_id *match;
+       struct mt8192_mt6359_priv *priv;
 
        platform_node = of_parse_phandle(pdev->dev.of_node,
                                         "mediatek,platform", 0);
@@ -1108,6 +1123,9 @@ static int mt8192_mt6359_dev_probe(struct platform_device *pdev)
        card = (struct snd_soc_card *)match->data;
        card->dev = &pdev->dev;
 
+       hdmi_codec = of_parse_phandle(pdev->dev.of_node,
+                                     "mediatek,hdmi-codec", 0);
+
        for_each_card_prelinks(card, i, dai_link) {
                if (strcmp(dai_link->name, "I2S3") == 0) {
                        if (card == &mt8192_mt6359_rt1015_rt5682_card) {
@@ -1134,10 +1152,20 @@ static int mt8192_mt6359_dev_probe(struct platform_device *pdev)
                        }
                }
 
+               if (hdmi_codec && strcmp(dai_link->name, "TDM") == 0) {
+                       dai_link->codecs->of_node = hdmi_codec;
+                       dai_link->ignore = 0;
+               }
+
                if (!dai_link->platforms->name)
                        dai_link->platforms->of_node = platform_node;
        }
 
+       priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
+       if (!priv)
+               return -ENOMEM;
+       snd_soc_card_set_drvdata(card, priv);
+
        ret = mt8192_afe_gpio_init(&pdev->dev);
        if (ret) {
                dev_err(&pdev->dev, "init gpio error %d\n", ret);
index d91b0d8..2388a2d 100644 (file)
@@ -124,7 +124,6 @@ const struct snd_soc_dai_ops aiu_fifo_i2s_dai_ops = {
        .trigger        = aiu_fifo_i2s_trigger,
        .prepare        = aiu_fifo_i2s_prepare,
        .hw_params      = aiu_fifo_i2s_hw_params,
-       .hw_free        = aiu_fifo_hw_free,
        .startup        = aiu_fifo_startup,
        .shutdown       = aiu_fifo_shutdown,
 };
index 44eb6fa..2fb30f8 100644 (file)
@@ -158,7 +158,6 @@ const struct snd_soc_dai_ops aiu_fifo_spdif_dai_ops = {
        .trigger        = fifo_spdif_trigger,
        .prepare        = fifo_spdif_prepare,
        .hw_params      = fifo_spdif_hw_params,
-       .hw_free        = aiu_fifo_hw_free,
        .startup        = aiu_fifo_startup,
        .shutdown       = aiu_fifo_shutdown,
 };
index aa88aae..4ad2326 100644 (file)
@@ -99,11 +99,6 @@ int aiu_fifo_hw_params(struct snd_pcm_substream *substream,
        struct snd_soc_component *component = dai->component;
        struct aiu_fifo *fifo = dai->playback_dma_data;
        dma_addr_t end;
-       int ret;
-
-       ret = snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(params));
-       if (ret < 0)
-               return ret;
 
        /* Setup the fifo boundaries */
        end = runtime->dma_addr + runtime->dma_bytes - fifo->fifo_block;
@@ -124,12 +119,6 @@ int aiu_fifo_hw_params(struct snd_pcm_substream *substream,
        return 0;
 }
 
-int aiu_fifo_hw_free(struct snd_pcm_substream *substream,
-                    struct snd_soc_dai *dai)
-{
-       return snd_pcm_lib_free_pages(substream);
-}
-
 static irqreturn_t aiu_fifo_isr(int irq, void *dev_id)
 {
        struct snd_pcm_substream *playback = dev_id;
@@ -187,15 +176,12 @@ void aiu_fifo_shutdown(struct snd_pcm_substream *substream,
 int aiu_fifo_pcm_new(struct snd_soc_pcm_runtime *rtd,
                     struct snd_soc_dai *dai)
 {
-       struct snd_pcm_substream *substream =
-               rtd->pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream;
        struct snd_card *card = rtd->card->snd_card;
        struct aiu_fifo *fifo = dai->playback_dma_data;
        size_t size = fifo->pcm->buffer_bytes_max;
 
-       snd_pcm_lib_preallocate_pages(substream,
-                                     SNDRV_DMA_TYPE_DEV,
-                                     card->dev, size, size);
+       snd_pcm_set_managed_buffer_all(rtd->pcm, SNDRV_DMA_TYPE_DEV,
+                                      card->dev, size, size);
 
        return 0;
 }
index 5301859..bcde4a9 100644 (file)
@@ -353,7 +353,7 @@ static struct snd_soc_dai_driver pxa_i2s_dai = {
                .rates = PXA2XX_I2S_RATES,
                .formats = SNDRV_PCM_FMTBIT_S16_LE,},
        .ops = &pxa_i2s_dai_ops,
-       .symmetric_rates = 1,
+       .symmetric_rate = 1,
 };
 
 static const struct snd_soc_component_driver pxa_i2s_component = {
index 8507ef8..3efa133 100644 (file)
@@ -250,7 +250,7 @@ static struct lpass_variant apq8016_data = {
        .micmode                = REG_FIELD_ID(0x1000, 4, 7, 4, 0x1000),
        .micmono                = REG_FIELD_ID(0x1000, 3, 3, 4, 0x1000),
        .wssrc                  = REG_FIELD_ID(0x1000, 2, 2, 4, 0x1000),
-       .bitwidth               = REG_FIELD_ID(0x1000, 0, 0, 4, 0x1000),
+       .bitwidth               = REG_FIELD_ID(0x1000, 0, 1, 4, 0x1000),
 
        .rdma_dyncclk           = REG_FIELD_ID(0x8400, 12, 12, 2, 0x1000),
        .rdma_bursten           = REG_FIELD_ID(0x8400, 11, 11, 2, 0x1000),
index 66b8343..c642e5f 100644 (file)
@@ -286,16 +286,12 @@ static int lpass_cpu_daiops_trigger(struct snd_pcm_substream *substream,
                        dev_err(dai->dev, "error writing to i2sctl reg: %d\n",
                                ret);
 
-               if (drvdata->bit_clk_state[id] == LPAIF_BIT_CLK_DISABLE) {
-                       ret = clk_enable(drvdata->mi2s_bit_clk[id]);
-                       if (ret) {
-                               dev_err(dai->dev, "error in enabling mi2s bit clk: %d\n", ret);
-                               clk_disable(drvdata->mi2s_osr_clk[id]);
-                               return ret;
-                       }
-                       drvdata->bit_clk_state[id] = LPAIF_BIT_CLK_ENABLE;
+               ret = clk_enable(drvdata->mi2s_bit_clk[id]);
+               if (ret) {
+                       dev_err(dai->dev, "error in enabling mi2s bit clk: %d\n", ret);
+                       clk_disable(drvdata->mi2s_osr_clk[id]);
+                       return ret;
                }
-
                break;
        case SNDRV_PCM_TRIGGER_STOP:
        case SNDRV_PCM_TRIGGER_SUSPEND:
@@ -310,10 +306,9 @@ static int lpass_cpu_daiops_trigger(struct snd_pcm_substream *substream,
                if (ret)
                        dev_err(dai->dev, "error writing to i2sctl reg: %d\n",
                                ret);
-               if (drvdata->bit_clk_state[id] == LPAIF_BIT_CLK_ENABLE) {
-                       clk_disable(drvdata->mi2s_bit_clk[dai->driver->id]);
-                       drvdata->bit_clk_state[id] = LPAIF_BIT_CLK_DISABLE;
-               }
+
+               clk_disable(drvdata->mi2s_bit_clk[dai->driver->id]);
+
                break;
        }
 
@@ -480,6 +475,7 @@ static bool lpass_cpu_regmap_volatile(struct device *dev, unsigned int reg)
 }
 
 static struct regmap_config lpass_cpu_regmap_config = {
+       .name = "lpass_cpu",
        .reg_bits = 32,
        .reg_stride = 4,
        .val_bits = 32,
@@ -599,7 +595,7 @@ static bool lpass_hdmi_regmap_writeable(struct device *dev, unsigned int reg)
                        return true;
        }
 
-       for (i = 0; i < v->rdma_channels; ++i) {
+       for (i = 0; i < v->hdmi_rdma_channels; ++i) {
                if (reg == LPAIF_HDMI_RDMACTL_REG(v, i))
                        return true;
                if (reg == LPAIF_HDMI_RDMABASE_REG(v, i))
@@ -645,7 +641,7 @@ static bool lpass_hdmi_regmap_readable(struct device *dev, unsigned int reg)
        if (reg == LPASS_HDMITX_APP_IRQSTAT_REG(v))
                return true;
 
-       for (i = 0; i < v->rdma_channels; ++i) {
+       for (i = 0; i < v->hdmi_rdma_channels; ++i) {
                if (reg == LPAIF_HDMI_RDMACTL_REG(v, i))
                        return true;
                if (reg == LPAIF_HDMI_RDMABASE_REG(v, i))
@@ -672,7 +668,7 @@ static bool lpass_hdmi_regmap_volatile(struct device *dev, unsigned int reg)
        if (reg == LPASS_HDMI_TX_LEGACY_ADDR(v))
                return true;
 
-       for (i = 0; i < v->rdma_channels; ++i) {
+       for (i = 0; i < v->hdmi_rdma_channels; ++i) {
                if (reg == LPAIF_HDMI_RDMACURR_REG(v, i))
                        return true;
        }
@@ -680,6 +676,7 @@ static bool lpass_hdmi_regmap_volatile(struct device *dev, unsigned int reg)
 }
 
 static struct regmap_config lpass_hdmi_regmap_config = {
+       .name = "lpass_hdmi",
        .reg_bits = 32,
        .reg_stride = 4,
        .val_bits = 32,
@@ -748,7 +745,6 @@ static void of_lpass_cpu_parse_dai_data(struct device *dev,
                }
                if (id == LPASS_DP_RX) {
                        data->hdmi_port_enable = 1;
-                       dev_err(dev, "HDMI Port is enabled: %d\n", id);
                } else {
                        data->mi2s_playback_sd_mode[id] =
                                of_lpass_cpu_parse_sd_lines(dev, node,
@@ -793,11 +789,8 @@ int asoc_qcom_lpass_cpu_platform_probe(struct platform_device *pdev)
        res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "lpass-lpaif");
 
        drvdata->lpaif = devm_ioremap_resource(dev, res);
-       if (IS_ERR((void const __force *)drvdata->lpaif)) {
-               dev_err(dev, "error mapping reg resource: %ld\n",
-                               PTR_ERR((void const __force *)drvdata->lpaif));
-               return PTR_ERR((void const __force *)drvdata->lpaif);
-       }
+       if (IS_ERR(drvdata->lpaif))
+               return PTR_ERR(drvdata->lpaif);
 
        lpass_cpu_regmap_config.max_register = LPAIF_WRDMAPER_REG(variant,
                                                variant->wrdma_channels +
@@ -815,14 +808,11 @@ int asoc_qcom_lpass_cpu_platform_probe(struct platform_device *pdev)
                res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "lpass-hdmiif");
 
                drvdata->hdmiif = devm_ioremap_resource(dev, res);
-               if (IS_ERR((void const __force *)drvdata->hdmiif)) {
-                       dev_err(dev, "error mapping reg resource: %ld\n",
-                                       PTR_ERR((void const __force *)drvdata->hdmiif));
-                       return PTR_ERR((void const __force *)drvdata->hdmiif);
-               }
+               if (IS_ERR(drvdata->hdmiif))
+                       return PTR_ERR(drvdata->hdmiif);
 
                lpass_hdmi_regmap_config.max_register = LPAIF_HDMI_RDMAPER_REG(variant,
-                                       variant->hdmi_rdma_channels);
+                                       variant->hdmi_rdma_channels - 1);
                drvdata->hdmiif_map = devm_regmap_init_mmio(dev, drvdata->hdmiif,
                                        &lpass_hdmi_regmap_config);
                if (IS_ERR(drvdata->hdmiif_map)) {
@@ -866,7 +856,6 @@ int asoc_qcom_lpass_cpu_platform_probe(struct platform_device *pdev)
                                PTR_ERR(drvdata->mi2s_bit_clk[dai_id]));
                        return PTR_ERR(drvdata->mi2s_bit_clk[dai_id]);
                }
-               drvdata->bit_clk_state[dai_id] = LPAIF_BIT_CLK_DISABLE;
        }
 
        /* Allocation for i2sctl regmap fields */
index baf72f1..2eb03ad 100644 (file)
@@ -60,9 +60,6 @@
 #define LPAIF_I2SCTL_BITWIDTH_24       1
 #define LPAIF_I2SCTL_BITWIDTH_32       2
 
-#define LPAIF_BIT_CLK_DISABLE          0
-#define LPAIF_BIT_CLK_ENABLE           1
-
 #define LPAIF_I2SCTL_RESET_STATE       0x003C0004
 #define LPAIF_DMACTL_RESET_STATE       0x00200000
 
index 735c9da..8c168d3 100644 (file)
@@ -171,7 +171,7 @@ static struct lpass_variant sc7180_data = {
        .rdma_channels          = 5,
        .hdmi_rdma_reg_base             = 0x64000,
        .hdmi_rdma_reg_stride   = 0x1000,
-       .hdmi_rdma_channels             = 3,
+       .hdmi_rdma_channels             = 4,
        .dmactl_audif_start     = 1,
        .wrdma_reg_base         = 0x18000,
        .wrdma_reg_stride       = 0x1000,
index 2d68af0..83b2e08 100644 (file)
@@ -68,7 +68,6 @@ struct lpass_data {
        unsigned int mi2s_playback_sd_mode[LPASS_MAX_MI2S_PORTS];
        unsigned int mi2s_capture_sd_mode[LPASS_MAX_MI2S_PORTS];
        int hdmi_port_enable;
-       int bit_clk_state[LPASS_MAX_MI2S_PORTS];
 
        /* low-power audio interface (LPAIF) registers */
        void __iomem *lpaif;
index c9ac9c1..9766725 100644 (file)
@@ -1233,6 +1233,25 @@ static void q6asm_dai_pcm_free(struct snd_soc_component *component,
        }
 }
 
+static const struct snd_soc_dapm_widget q6asm_dapm_widgets[] = {
+       SND_SOC_DAPM_AIF_IN("MM_DL1", "MultiMedia1 Playback", 0, SND_SOC_NOPM, 0, 0),
+       SND_SOC_DAPM_AIF_IN("MM_DL2", "MultiMedia2 Playback", 0, SND_SOC_NOPM, 0, 0),
+       SND_SOC_DAPM_AIF_IN("MM_DL3", "MultiMedia3 Playback", 0, SND_SOC_NOPM, 0, 0),
+       SND_SOC_DAPM_AIF_IN("MM_DL4", "MultiMedia4 Playback", 0, SND_SOC_NOPM, 0, 0),
+       SND_SOC_DAPM_AIF_IN("MM_DL5", "MultiMedia5 Playback", 0, SND_SOC_NOPM, 0, 0),
+       SND_SOC_DAPM_AIF_IN("MM_DL6", "MultiMedia6 Playback", 0, SND_SOC_NOPM, 0, 0),
+       SND_SOC_DAPM_AIF_IN("MM_DL7", "MultiMedia7 Playback", 0, SND_SOC_NOPM, 0, 0),
+       SND_SOC_DAPM_AIF_IN("MM_DL8", "MultiMedia8 Playback", 0, SND_SOC_NOPM, 0, 0),
+       SND_SOC_DAPM_AIF_OUT("MM_UL1", "MultiMedia1 Capture", 0, SND_SOC_NOPM, 0, 0),
+       SND_SOC_DAPM_AIF_OUT("MM_UL2", "MultiMedia2 Capture", 0, SND_SOC_NOPM, 0, 0),
+       SND_SOC_DAPM_AIF_OUT("MM_UL3", "MultiMedia3 Capture", 0, SND_SOC_NOPM, 0, 0),
+       SND_SOC_DAPM_AIF_OUT("MM_UL4", "MultiMedia4 Capture", 0, SND_SOC_NOPM, 0, 0),
+       SND_SOC_DAPM_AIF_OUT("MM_UL5", "MultiMedia5 Capture", 0, SND_SOC_NOPM, 0, 0),
+       SND_SOC_DAPM_AIF_OUT("MM_UL6", "MultiMedia6 Capture", 0, SND_SOC_NOPM, 0, 0),
+       SND_SOC_DAPM_AIF_OUT("MM_UL7", "MultiMedia7 Capture", 0, SND_SOC_NOPM, 0, 0),
+       SND_SOC_DAPM_AIF_OUT("MM_UL8", "MultiMedia8 Capture", 0, SND_SOC_NOPM, 0, 0),
+};
+
 static const struct snd_soc_component_driver q6asm_fe_dai_component = {
        .name           = DRV_NAME,
        .open           = q6asm_dai_open,
@@ -1245,6 +1264,8 @@ static const struct snd_soc_component_driver q6asm_fe_dai_component = {
        .pcm_construct  = q6asm_dai_pcm_new,
        .pcm_destruct   = q6asm_dai_pcm_free,
        .compress_ops   = &q6asm_dai_compress_ops,
+       .dapm_widgets   = q6asm_dapm_widgets,
+       .num_dapm_widgets = ARRAY_SIZE(q6asm_dapm_widgets),
 };
 
 static struct snd_soc_dai_driver q6asm_fe_dais_template[] = {
index a6618ef..36bf8bd 100644 (file)
@@ -491,7 +491,7 @@ static int __q6asm_memory_map_regions(struct audio_client *ac, int dir,
  *
  * @dir: direction of audio stream
  * @ac: audio client instanace
- * @phys: physcial address that needs mapping.
+ * @phys: physical address that needs mapping.
  * @period_sz: audio period size
  * @periods: number of periods
  *
index 53185e2..0a6b943 100644 (file)
@@ -713,24 +713,6 @@ static const struct snd_kcontrol_new mmul8_mixer_controls[] = {
        Q6ROUTING_TX_MIXERS(MSM_FRONTEND_DAI_MULTIMEDIA8) };
 
 static const struct snd_soc_dapm_widget msm_qdsp6_widgets[] = {
-       /* Frontend AIF */
-       SND_SOC_DAPM_AIF_IN("MM_DL1", "MultiMedia1 Playback", 0, 0, 0, 0),
-       SND_SOC_DAPM_AIF_IN("MM_DL2", "MultiMedia2 Playback", 0, 0, 0, 0),
-       SND_SOC_DAPM_AIF_IN("MM_DL3", "MultiMedia3 Playback", 0, 0, 0, 0),
-       SND_SOC_DAPM_AIF_IN("MM_DL4", "MultiMedia4 Playback", 0, 0, 0, 0),
-       SND_SOC_DAPM_AIF_IN("MM_DL5", "MultiMedia5 Playback", 0, 0, 0, 0),
-       SND_SOC_DAPM_AIF_IN("MM_DL6", "MultiMedia6 Playback", 0, 0, 0, 0),
-       SND_SOC_DAPM_AIF_IN("MM_DL7", "MultiMedia7 Playback", 0, 0, 0, 0),
-       SND_SOC_DAPM_AIF_IN("MM_DL8", "MultiMedia8 Playback", 0, 0, 0, 0),
-       SND_SOC_DAPM_AIF_OUT("MM_UL1", "MultiMedia1 Capture", 0, 0, 0, 0),
-       SND_SOC_DAPM_AIF_OUT("MM_UL2", "MultiMedia2 Capture", 0, 0, 0, 0),
-       SND_SOC_DAPM_AIF_OUT("MM_UL3", "MultiMedia3 Capture", 0, 0, 0, 0),
-       SND_SOC_DAPM_AIF_OUT("MM_UL4", "MultiMedia4 Capture", 0, 0, 0, 0),
-       SND_SOC_DAPM_AIF_OUT("MM_UL5", "MultiMedia5 Capture", 0, 0, 0, 0),
-       SND_SOC_DAPM_AIF_OUT("MM_UL6", "MultiMedia6 Capture", 0, 0, 0, 0),
-       SND_SOC_DAPM_AIF_OUT("MM_UL7", "MultiMedia7 Capture", 0, 0, 0, 0),
-       SND_SOC_DAPM_AIF_OUT("MM_UL8", "MultiMedia8 Capture", 0, 0, 0, 0),
-
        /* Mixer definitions */
        SND_SOC_DAPM_MIXER("HDMI Mixer", SND_SOC_NOPM, 0, 0,
                           hdmi_mixer_controls,
index eae287d..0740764 100644 (file)
@@ -373,7 +373,7 @@ static int rockchip_i2s_hw_params(struct snd_pcm_substream *substream,
                           I2S_DMACR_RDL(16));
 
        val = I2S_CKR_TRCM_TXRX;
-       if (dai->driver->symmetric_rates && rtd->dai_link->symmetric_rates)
+       if (dai->driver->symmetric_rate && rtd->dai_link->symmetric_rate)
                val = I2S_CKR_TRCM_TXONLY;
 
        regmap_update_bits(i2s->regmap, I2S_CKR,
@@ -471,7 +471,7 @@ static struct snd_soc_dai_driver rockchip_i2s_dai = {
                            SNDRV_PCM_FMTBIT_S32_LE),
        },
        .ops = &rockchip_i2s_dai_ops,
-       .symmetric_rates = 1,
+       .symmetric_rate = 1,
 };
 
 static const struct snd_soc_component_driver rockchip_i2s_component = {
index e5f7327..9295d64 100644 (file)
@@ -338,7 +338,7 @@ static struct snd_soc_dai_driver rockchip_pdm_dai = {
                .formats = ROCKCHIP_PDM_FORMATS,
        },
        .ops = &rockchip_pdm_dai_ops,
-       .symmetric_rates = 1,
+       .symmetric_rate = 1,
 };
 
 static const struct snd_soc_component_driver rockchip_pdm_component = {
index 4bdc268..b043183 100644 (file)
@@ -1175,7 +1175,7 @@ static int i2s_alloc_dais(struct samsung_i2s_priv *priv,
                dai_drv->probe = samsung_i2s_dai_probe;
                dai_drv->remove = samsung_i2s_dai_remove;
 
-               dai_drv->symmetric_rates = 1;
+               dai_drv->symmetric_rate = 1;
                dai_drv->ops = &samsung_i2s_dai_ops;
 
                dai_drv->playback.channels_min = 1;
index 6f50c7b..bfd76e9 100644 (file)
@@ -452,7 +452,7 @@ static int s3c_pcm_dai_probe(struct snd_soc_dai *dai)
 #define S3C_PCM_RATES  SNDRV_PCM_RATE_8000_96000
 
 #define S3C_PCM_DAI_DECLARE                    \
-       .symmetric_rates = 1,                                   \
+       .symmetric_rate = 1,                                    \
        .probe = s3c_pcm_dai_probe,                             \
        .ops = &s3c_pcm_dai_ops,                                \
        .playback = {                                           \
index 6dd5659..1029d8d 100644 (file)
@@ -1320,8 +1320,8 @@ static void __rsnd_dai_probe(struct rsnd_priv *priv,
 
        if (rsnd_ssi_is_pin_sharing(io_capture) ||
            rsnd_ssi_is_pin_sharing(io_playback)) {
-               /* should have symmetric_rates if pin sharing */
-               drv->symmetric_rates = 1;
+               /* should have symmetric_rate if pin sharing */
+               drv->symmetric_rate = 1;
        }
 
        dev_dbg(dev, "%s (%s/%s)\n", rdai->name,
index 6201840..a675c36 100644 (file)
@@ -169,7 +169,7 @@ static inline u32 siu_read32(u32 __iomem *addr)
 #define SIU_BRGBSEL    (0x108 / sizeof(u32))
 #define SIU_BRRB       (0x10c / sizeof(u32))
 
-extern struct snd_soc_component_driver siu_component;
+extern const struct snd_soc_component_driver siu_component;
 extern struct siu_info *siu_i2s_data;
 
 int siu_init_port(int port, struct siu_port **port_info, struct snd_card *card);
index 45c4320..4785886 100644 (file)
@@ -543,7 +543,7 @@ static void siu_pcm_free(struct snd_soc_component *component,
        dev_dbg(pcm->card->dev, "%s\n", __func__);
 }
 
-struct const snd_soc_component_driver siu_component = {
+const struct snd_soc_component_driver siu_component = {
        .name           = DRV_NAME,
        .open           = siu_pcm_open,
        .close          = siu_pcm_close,
diff --git a/sound/soc/sirf/Kconfig b/sound/soc/sirf/Kconfig
deleted file mode 100644 (file)
index 094a1c8..0000000
+++ /dev/null
@@ -1,21 +0,0 @@
-# SPDX-License-Identifier: GPL-2.0-only
-config SND_SOC_SIRF
-       tristate "SoC Audio for the SiRF SoC chips"
-       depends on ARCH_SIRF || COMPILE_TEST
-       select SND_SOC_GENERIC_DMAENGINE_PCM
-
-config SND_SOC_SIRF_AUDIO
-       tristate "SoC Audio support for SiRF internal audio codec"
-       depends on SND_SOC_SIRF
-       select SND_SOC_SIRF_AUDIO_CODEC
-       select SND_SOC_SIRF_AUDIO_PORT
-
-config SND_SOC_SIRF_AUDIO_PORT
-       select REGMAP_MMIO
-       tristate
-
-config SND_SOC_SIRF_USP
-       tristate "SoC Audio (I2S protocol) for SiRF SoC USP interface"
-       depends on SND_SOC_SIRF
-       select REGMAP_MMIO
-       tristate
diff --git a/sound/soc/sirf/Makefile b/sound/soc/sirf/Makefile
deleted file mode 100644 (file)
index 16ed119..0000000
+++ /dev/null
@@ -1,8 +0,0 @@
-# SPDX-License-Identifier: GPL-2.0
-snd-soc-sirf-audio-objs := sirf-audio.o
-snd-soc-sirf-audio-port-objs := sirf-audio-port.o
-snd-soc-sirf-usp-objs := sirf-usp.o
-
-obj-$(CONFIG_SND_SOC_SIRF_AUDIO) += snd-soc-sirf-audio.o
-obj-$(CONFIG_SND_SOC_SIRF_AUDIO_PORT) += snd-soc-sirf-audio-port.o
-obj-$(CONFIG_SND_SOC_SIRF_USP) += snd-soc-sirf-usp.o
diff --git a/sound/soc/sirf/sirf-audio-port.c b/sound/soc/sirf/sirf-audio-port.c
deleted file mode 100644 (file)
index 8be2f0b..0000000
+++ /dev/null
@@ -1,86 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-or-later
-/*
- * SiRF Audio port driver
- *
- * Copyright (c) 2011 Cambridge Silicon Radio Limited, a CSR plc group company.
- */
-#include <linux/module.h>
-#include <sound/soc.h>
-#include <sound/dmaengine_pcm.h>
-
-struct sirf_audio_port {
-       struct regmap *regmap;
-       struct snd_dmaengine_dai_dma_data playback_dma_data;
-       struct snd_dmaengine_dai_dma_data capture_dma_data;
-};
-
-
-static int sirf_audio_port_dai_probe(struct snd_soc_dai *dai)
-{
-       struct sirf_audio_port *port = snd_soc_dai_get_drvdata(dai);
-
-       snd_soc_dai_init_dma_data(dai, &port->playback_dma_data,
-                       &port->capture_dma_data);
-       return 0;
-}
-
-static struct snd_soc_dai_driver sirf_audio_port_dai = {
-       .probe = sirf_audio_port_dai_probe,
-       .name = "sirf-audio-port",
-       .id = 0,
-       .playback = {
-               .channels_min = 2,
-               .channels_max = 2,
-               .rates = SNDRV_PCM_RATE_48000,
-               .formats = SNDRV_PCM_FMTBIT_S16_LE,
-       },
-       .capture = {
-               .channels_min = 1,
-               .channels_max = 2,
-               .rates = SNDRV_PCM_RATE_48000,
-               .formats = SNDRV_PCM_FMTBIT_S16_LE,
-       },
-};
-
-static const struct snd_soc_component_driver sirf_audio_port_component = {
-       .name       = "sirf-audio-port",
-};
-
-static int sirf_audio_port_probe(struct platform_device *pdev)
-{
-       int ret;
-       struct sirf_audio_port *port;
-
-       port = devm_kzalloc(&pdev->dev,
-                       sizeof(struct sirf_audio_port), GFP_KERNEL);
-       if (!port)
-               return -ENOMEM;
-
-       ret = devm_snd_soc_register_component(&pdev->dev,
-                       &sirf_audio_port_component, &sirf_audio_port_dai, 1);
-       if (ret)
-               return ret;
-
-       platform_set_drvdata(pdev, port);
-       return devm_snd_dmaengine_pcm_register(&pdev->dev, NULL, 0);
-}
-
-static const struct of_device_id sirf_audio_port_of_match[] = {
-       { .compatible = "sirf,audio-port", },
-       {}
-};
-MODULE_DEVICE_TABLE(of, sirf_audio_port_of_match);
-
-static struct platform_driver sirf_audio_port_driver = {
-       .driver = {
-               .name = "sirf-audio-port",
-               .of_match_table = sirf_audio_port_of_match,
-       },
-       .probe = sirf_audio_port_probe,
-};
-
-module_platform_driver(sirf_audio_port_driver);
-
-MODULE_DESCRIPTION("SiRF Audio Port driver");
-MODULE_AUTHOR("RongJun Ying <Rongjun.Ying@csr.com>");
-MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/sirf/sirf-audio.c b/sound/soc/sirf/sirf-audio.c
deleted file mode 100644 (file)
index c923b67..0000000
+++ /dev/null
@@ -1,160 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-or-later
-/*
- * SiRF audio card driver
- *
- * Copyright (c) 2011 Cambridge Silicon Radio Limited, a CSR plc group company.
- */
-
-#include <linux/platform_device.h>
-#include <linux/module.h>
-#include <linux/of.h>
-#include <linux/gpio.h>
-#include <linux/of_gpio.h>
-#include <sound/core.h>
-#include <sound/pcm.h>
-#include <sound/soc.h>
-
-struct sirf_audio_card {
-       unsigned int            gpio_hp_pa;
-       unsigned int            gpio_spk_pa;
-};
-
-static int sirf_audio_hp_event(struct snd_soc_dapm_widget *w,
-                               struct snd_kcontrol *ctrl, int event)
-{
-       struct snd_soc_dapm_context *dapm = w->dapm;
-       struct snd_soc_card *card = dapm->card;
-       struct sirf_audio_card *sirf_audio_card = snd_soc_card_get_drvdata(card);
-       int on = !SND_SOC_DAPM_EVENT_OFF(event);
-
-       if (gpio_is_valid(sirf_audio_card->gpio_hp_pa))
-               gpio_set_value(sirf_audio_card->gpio_hp_pa, on);
-       return 0;
-}
-
-static int sirf_audio_spk_event(struct snd_soc_dapm_widget *w,
-                               struct snd_kcontrol *ctrl, int event)
-{
-       struct snd_soc_dapm_context *dapm = w->dapm;
-       struct snd_soc_card *card = dapm->card;
-       struct sirf_audio_card *sirf_audio_card = snd_soc_card_get_drvdata(card);
-       int on = !SND_SOC_DAPM_EVENT_OFF(event);
-
-       if (gpio_is_valid(sirf_audio_card->gpio_spk_pa))
-               gpio_set_value(sirf_audio_card->gpio_spk_pa, on);
-
-       return 0;
-}
-static const struct snd_soc_dapm_widget sirf_audio_dapm_widgets[] = {
-       SND_SOC_DAPM_HP("Hp", sirf_audio_hp_event),
-       SND_SOC_DAPM_SPK("Ext Spk", sirf_audio_spk_event),
-       SND_SOC_DAPM_MIC("Ext Mic", NULL),
-};
-
-static const struct snd_soc_dapm_route intercon[] = {
-       {"Hp", NULL, "HPOUTL"},
-       {"Hp", NULL, "HPOUTR"},
-       {"Ext Spk", NULL, "SPKOUT"},
-       {"MICIN1", NULL, "Mic Bias"},
-       {"Mic Bias", NULL, "Ext Mic"},
-};
-
-/* Digital audio interface glue - connects codec <--> CPU */
-SND_SOC_DAILINK_DEFS(sirf,
-       DAILINK_COMP_ARRAY(COMP_EMPTY()),
-       DAILINK_COMP_ARRAY(COMP_CODEC(NULL, "sirf-audio-codec")),
-       DAILINK_COMP_ARRAY(COMP_EMPTY()));
-
-static struct snd_soc_dai_link sirf_audio_dai_link[] = {
-       {
-               .name = "SiRF audio card",
-               .stream_name = "SiRF audio HiFi",
-               SND_SOC_DAILINK_REG(sirf),
-       },
-};
-
-/* Audio machine driver */
-static struct snd_soc_card snd_soc_sirf_audio_card = {
-       .name = "SiRF audio card",
-       .owner = THIS_MODULE,
-       .dai_link = sirf_audio_dai_link,
-       .num_links = ARRAY_SIZE(sirf_audio_dai_link),
-       .dapm_widgets = sirf_audio_dapm_widgets,
-       .num_dapm_widgets = ARRAY_SIZE(sirf_audio_dapm_widgets),
-       .dapm_routes = intercon,
-       .num_dapm_routes = ARRAY_SIZE(intercon),
-};
-
-static int sirf_audio_probe(struct platform_device *pdev)
-{
-       struct snd_soc_card *card = &snd_soc_sirf_audio_card;
-       struct sirf_audio_card *sirf_audio_card;
-       int ret;
-
-       sirf_audio_card = devm_kzalloc(&pdev->dev, sizeof(struct sirf_audio_card),
-                       GFP_KERNEL);
-       if (sirf_audio_card == NULL)
-               return -ENOMEM;
-
-       sirf_audio_dai_link[0].cpus->of_node =
-               of_parse_phandle(pdev->dev.of_node, "sirf,audio-platform", 0);
-       sirf_audio_dai_link[0].platforms->of_node =
-               of_parse_phandle(pdev->dev.of_node, "sirf,audio-platform", 0);
-       sirf_audio_dai_link[0].codecs->of_node =
-               of_parse_phandle(pdev->dev.of_node, "sirf,audio-codec", 0);
-       sirf_audio_card->gpio_spk_pa = of_get_named_gpio(pdev->dev.of_node,
-                       "spk-pa-gpios", 0);
-       sirf_audio_card->gpio_hp_pa =  of_get_named_gpio(pdev->dev.of_node,
-                       "hp-pa-gpios", 0);
-       if (gpio_is_valid(sirf_audio_card->gpio_spk_pa)) {
-               ret = devm_gpio_request_one(&pdev->dev,
-                               sirf_audio_card->gpio_spk_pa,
-                               GPIOF_OUT_INIT_LOW, "SPA_PA_SD");
-               if (ret) {
-                       dev_err(&pdev->dev,
-                               "Failed to request GPIO_%d for reset: %d\n",
-                               sirf_audio_card->gpio_spk_pa, ret);
-                       return ret;
-               }
-       }
-       if (gpio_is_valid(sirf_audio_card->gpio_hp_pa)) {
-               ret = devm_gpio_request_one(&pdev->dev,
-                               sirf_audio_card->gpio_hp_pa,
-                               GPIOF_OUT_INIT_LOW, "HP_PA_SD");
-               if (ret) {
-                       dev_err(&pdev->dev,
-                               "Failed to request GPIO_%d for reset: %d\n",
-                               sirf_audio_card->gpio_hp_pa, ret);
-                       return ret;
-               }
-       }
-
-       card->dev = &pdev->dev;
-       snd_soc_card_set_drvdata(card, sirf_audio_card);
-
-       ret = devm_snd_soc_register_card(&pdev->dev, card);
-       if (ret)
-               dev_err(&pdev->dev, "snd_soc_register_card() failed:%d\n", ret);
-
-       return ret;
-}
-
-static const struct of_device_id sirf_audio_of_match[] = {
-       {.compatible = "sirf,sirf-audio-card", },
-       { },
-};
-MODULE_DEVICE_TABLE(of, sirf_audio_of_match);
-
-static struct platform_driver sirf_audio_driver = {
-       .driver = {
-               .name = "sirf-audio-card",
-               .pm = &snd_soc_pm_ops,
-               .of_match_table = sirf_audio_of_match,
-       },
-       .probe = sirf_audio_probe,
-};
-module_platform_driver(sirf_audio_driver);
-
-MODULE_AUTHOR("RongJun Ying <RongJun.Ying@csr.com>");
-MODULE_DESCRIPTION("ALSA SoC SIRF audio card driver");
-MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/sirf/sirf-usp.c b/sound/soc/sirf/sirf-usp.c
deleted file mode 100644 (file)
index 2af0c6f..0000000
+++ /dev/null
@@ -1,435 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-or-later
-/*
- * SiRF USP in I2S/DSP mode
- *
- * Copyright (c) 2011 Cambridge Silicon Radio Limited, a CSR plc group company.
- */
-#include <linux/module.h>
-#include <linux/io.h>
-#include <linux/of.h>
-#include <linux/clk.h>
-#include <linux/pm_runtime.h>
-#include <sound/soc.h>
-#include <sound/pcm_params.h>
-#include <sound/dmaengine_pcm.h>
-
-#include "sirf-usp.h"
-
-struct sirf_usp {
-       struct regmap *regmap;
-       struct clk *clk;
-       u32 mode1_reg;
-       u32 mode2_reg;
-       int daifmt_format;
-       struct snd_dmaengine_dai_dma_data playback_dma_data;
-       struct snd_dmaengine_dai_dma_data capture_dma_data;
-};
-
-static void sirf_usp_tx_enable(struct sirf_usp *usp)
-{
-       regmap_update_bits(usp->regmap, USP_TX_FIFO_OP,
-               USP_TX_FIFO_RESET, USP_TX_FIFO_RESET);
-       regmap_write(usp->regmap, USP_TX_FIFO_OP, 0);
-
-       regmap_update_bits(usp->regmap, USP_TX_FIFO_OP,
-               USP_TX_FIFO_START, USP_TX_FIFO_START);
-
-       regmap_update_bits(usp->regmap, USP_TX_RX_ENABLE,
-               USP_TX_ENA, USP_TX_ENA);
-}
-
-static void sirf_usp_tx_disable(struct sirf_usp *usp)
-{
-       regmap_update_bits(usp->regmap, USP_TX_RX_ENABLE,
-               USP_TX_ENA, ~USP_TX_ENA);
-       /* FIFO stop */
-       regmap_write(usp->regmap, USP_TX_FIFO_OP, 0);
-}
-
-static void sirf_usp_rx_enable(struct sirf_usp *usp)
-{
-       regmap_update_bits(usp->regmap, USP_RX_FIFO_OP,
-               USP_RX_FIFO_RESET, USP_RX_FIFO_RESET);
-       regmap_write(usp->regmap, USP_RX_FIFO_OP, 0);
-
-       regmap_update_bits(usp->regmap, USP_RX_FIFO_OP,
-               USP_RX_FIFO_START, USP_RX_FIFO_START);
-
-       regmap_update_bits(usp->regmap, USP_TX_RX_ENABLE,
-               USP_RX_ENA, USP_RX_ENA);
-}
-
-static void sirf_usp_rx_disable(struct sirf_usp *usp)
-{
-       regmap_update_bits(usp->regmap, USP_TX_RX_ENABLE,
-               USP_RX_ENA, ~USP_RX_ENA);
-       /* FIFO stop */
-       regmap_write(usp->regmap, USP_RX_FIFO_OP, 0);
-}
-
-static int sirf_usp_pcm_dai_probe(struct snd_soc_dai *dai)
-{
-       struct sirf_usp *usp = snd_soc_dai_get_drvdata(dai);
-
-       snd_soc_dai_init_dma_data(dai, &usp->playback_dma_data,
-                       &usp->capture_dma_data);
-       return 0;
-}
-
-static int sirf_usp_pcm_set_dai_fmt(struct snd_soc_dai *dai,
-               unsigned int fmt)
-{
-       struct sirf_usp *usp = snd_soc_dai_get_drvdata(dai);
-
-       /* set master/slave audio interface */
-       switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
-       case SND_SOC_DAIFMT_CBM_CFM:
-               break;
-       default:
-               dev_err(dai->dev, "Only CBM and CFM supported\n");
-               return -EINVAL;
-       }
-
-       switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
-       case SND_SOC_DAIFMT_I2S:
-       case SND_SOC_DAIFMT_DSP_A:
-               usp->daifmt_format = (fmt & SND_SOC_DAIFMT_FORMAT_MASK);
-               break;
-       default:
-               dev_err(dai->dev, "Only I2S and DSP_A format supported\n");
-               return -EINVAL;
-       }
-
-       switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
-       case SND_SOC_DAIFMT_NB_NF:
-               break;
-       case SND_SOC_DAIFMT_IB_NF:
-               usp->daifmt_format |= (fmt & SND_SOC_DAIFMT_INV_MASK);
-               break;
-       default:
-               return -EINVAL;
-       }
-
-       return 0;
-}
-
-static void sirf_usp_i2s_init(struct sirf_usp *usp)
-{
-       /* Configure RISC mode */
-       regmap_update_bits(usp->regmap, USP_RISC_DSP_MODE,
-               USP_RISC_DSP_SEL, ~USP_RISC_DSP_SEL);
-
-       /*
-        * Configure DMA IO Length register
-        * Set no limit, USP can receive data continuously until it is diabled
-        */
-       regmap_write(usp->regmap, USP_TX_DMA_IO_LEN, 0);
-       regmap_write(usp->regmap, USP_RX_DMA_IO_LEN, 0);
-
-       /* Configure Mode2 register */
-       regmap_write(usp->regmap, USP_MODE2, (1 << USP_RXD_DELAY_LEN_OFFSET) |
-               (0 << USP_TXD_DELAY_LEN_OFFSET) |
-               USP_TFS_CLK_SLAVE_MODE | USP_RFS_CLK_SLAVE_MODE);
-
-       /* Configure Mode1 register */
-       regmap_write(usp->regmap, USP_MODE1,
-               USP_SYNC_MODE | USP_EN | USP_TXD_ACT_EDGE_FALLING |
-               USP_RFS_ACT_LEVEL_LOGIC1 | USP_TFS_ACT_LEVEL_LOGIC1 |
-               USP_TX_UFLOW_REPEAT_ZERO | USP_CLOCK_MODE_SLAVE);
-
-       /* Configure RX DMA IO Control register */
-       regmap_write(usp->regmap, USP_RX_DMA_IO_CTRL, 0);
-
-       /* Congiure RX FIFO Control register */
-       regmap_write(usp->regmap, USP_RX_FIFO_CTRL,
-               (USP_RX_FIFO_THRESHOLD << USP_RX_FIFO_THD_OFFSET) |
-               (USP_TX_RX_FIFO_WIDTH_DWORD << USP_RX_FIFO_WIDTH_OFFSET));
-
-       /* Congiure RX FIFO Level Check register */
-       regmap_write(usp->regmap, USP_RX_FIFO_LEVEL_CHK,
-               RX_FIFO_SC(0x04) | RX_FIFO_LC(0x0E) | RX_FIFO_HC(0x1B));
-
-       /* Configure TX DMA IO Control register*/
-       regmap_write(usp->regmap, USP_TX_DMA_IO_CTRL, 0);
-
-       /* Configure TX FIFO Control register */
-       regmap_write(usp->regmap, USP_TX_FIFO_CTRL,
-               (USP_TX_FIFO_THRESHOLD << USP_TX_FIFO_THD_OFFSET) |
-               (USP_TX_RX_FIFO_WIDTH_DWORD << USP_TX_FIFO_WIDTH_OFFSET));
-       /* Congiure TX FIFO Level Check register */
-       regmap_write(usp->regmap, USP_TX_FIFO_LEVEL_CHK,
-               TX_FIFO_SC(0x1B) | TX_FIFO_LC(0x0E) | TX_FIFO_HC(0x04));
-}
-
-static int sirf_usp_pcm_hw_params(struct snd_pcm_substream *substream,
-               struct snd_pcm_hw_params *params, struct snd_soc_dai *dai)
-{
-       struct sirf_usp *usp = snd_soc_dai_get_drvdata(dai);
-       u32 data_len, frame_len, shifter_len;
-
-       switch (params_format(params)) {
-       case SNDRV_PCM_FORMAT_S16_LE:
-               data_len = 16;
-               frame_len = 16;
-               break;
-       case SNDRV_PCM_FORMAT_S24_LE:
-               data_len = 24;
-               frame_len = 32;
-               break;
-       case SNDRV_PCM_FORMAT_S24_3LE:
-               data_len = 24;
-               frame_len = 24;
-               break;
-       default:
-               dev_err(dai->dev, "Format unsupported\n");
-               return -EINVAL;
-       }
-
-       shifter_len = data_len;
-
-       switch (usp->daifmt_format & SND_SOC_DAIFMT_FORMAT_MASK) {
-       case SND_SOC_DAIFMT_I2S:
-               regmap_update_bits(usp->regmap, USP_RX_FRAME_CTRL,
-                       USP_I2S_SYNC_CHG, USP_I2S_SYNC_CHG);
-               break;
-       case SND_SOC_DAIFMT_DSP_A:
-               regmap_update_bits(usp->regmap, USP_RX_FRAME_CTRL,
-                       USP_I2S_SYNC_CHG, 0);
-               frame_len = data_len * params_channels(params);
-               data_len = frame_len;
-               break;
-       default:
-               dev_err(dai->dev, "Only support I2S and DSP_A mode\n");
-               return -EINVAL;
-       }
-
-       switch (usp->daifmt_format & SND_SOC_DAIFMT_INV_MASK) {
-       case SND_SOC_DAIFMT_NB_NF:
-               break;
-       case SND_SOC_DAIFMT_IB_NF:
-               regmap_update_bits(usp->regmap, USP_MODE1,
-                       USP_RXD_ACT_EDGE_FALLING | USP_TXD_ACT_EDGE_FALLING,
-                       USP_RXD_ACT_EDGE_FALLING);
-               break;
-       default:
-               return -EINVAL;
-       }
-
-       if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
-               regmap_update_bits(usp->regmap, USP_TX_FRAME_CTRL,
-                       USP_TXC_DATA_LEN_MASK | USP_TXC_FRAME_LEN_MASK
-                       | USP_TXC_SHIFTER_LEN_MASK | USP_TXC_SLAVE_CLK_SAMPLE,
-                       ((data_len - 1) << USP_TXC_DATA_LEN_OFFSET)
-                       | ((frame_len - 1) << USP_TXC_FRAME_LEN_OFFSET)
-                       | ((shifter_len - 1) << USP_TXC_SHIFTER_LEN_OFFSET)
-                       | USP_TXC_SLAVE_CLK_SAMPLE);
-       else
-               regmap_update_bits(usp->regmap, USP_RX_FRAME_CTRL,
-                       USP_RXC_DATA_LEN_MASK | USP_RXC_FRAME_LEN_MASK
-                       | USP_RXC_SHIFTER_LEN_MASK | USP_SINGLE_SYNC_MODE,
-                       ((data_len - 1) << USP_RXC_DATA_LEN_OFFSET)
-                       | ((frame_len - 1) << USP_RXC_FRAME_LEN_OFFSET)
-                       | ((shifter_len - 1) << USP_RXC_SHIFTER_LEN_OFFSET)
-                       | USP_SINGLE_SYNC_MODE);
-
-       return 0;
-}
-
-static int sirf_usp_pcm_trigger(struct snd_pcm_substream *substream, int cmd,
-                               struct snd_soc_dai *dai)
-{
-       struct sirf_usp *usp = snd_soc_dai_get_drvdata(dai);
-
-       switch (cmd) {
-       case SNDRV_PCM_TRIGGER_START:
-       case SNDRV_PCM_TRIGGER_RESUME:
-       case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
-               if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
-                       sirf_usp_tx_enable(usp);
-               else
-                       sirf_usp_rx_enable(usp);
-               break;
-       case SNDRV_PCM_TRIGGER_STOP:
-       case SNDRV_PCM_TRIGGER_SUSPEND:
-       case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
-               if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
-                       sirf_usp_tx_disable(usp);
-               else
-                       sirf_usp_rx_disable(usp);
-               break;
-       }
-
-       return 0;
-}
-
-static const struct snd_soc_dai_ops sirf_usp_pcm_dai_ops = {
-       .trigger = sirf_usp_pcm_trigger,
-       .set_fmt = sirf_usp_pcm_set_dai_fmt,
-       .hw_params = sirf_usp_pcm_hw_params,
-};
-
-static struct snd_soc_dai_driver sirf_usp_pcm_dai = {
-       .probe = sirf_usp_pcm_dai_probe,
-       .name = "sirf-usp-pcm",
-       .id = 0,
-       .playback = {
-               .stream_name = "SiRF USP PCM Playback",
-               .channels_min = 1,
-               .channels_max = 2,
-               .rates = SNDRV_PCM_RATE_8000_192000,
-               .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE |
-                       SNDRV_PCM_FMTBIT_S24_3LE,
-       },
-       .capture = {
-               .stream_name = "SiRF USP PCM Capture",
-               .channels_min = 1,
-               .channels_max = 2,
-               .rates = SNDRV_PCM_RATE_8000_192000,
-               .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE |
-                       SNDRV_PCM_FMTBIT_S24_3LE,
-       },
-       .ops = &sirf_usp_pcm_dai_ops,
-};
-
-static int sirf_usp_pcm_runtime_suspend(struct device *dev)
-{
-       struct sirf_usp *usp = dev_get_drvdata(dev);
-
-       clk_disable_unprepare(usp->clk);
-       return 0;
-}
-
-static int sirf_usp_pcm_runtime_resume(struct device *dev)
-{
-       struct sirf_usp *usp = dev_get_drvdata(dev);
-       int ret;
-
-       ret = clk_prepare_enable(usp->clk);
-       if (ret) {
-               dev_err(dev, "clk_enable failed: %d\n", ret);
-               return ret;
-       }
-       sirf_usp_i2s_init(usp);
-       return 0;
-}
-
-#ifdef CONFIG_PM_SLEEP
-static int sirf_usp_pcm_suspend(struct device *dev)
-{
-       struct sirf_usp *usp = dev_get_drvdata(dev);
-
-       if (!pm_runtime_status_suspended(dev)) {
-               regmap_read(usp->regmap, USP_MODE1, &usp->mode1_reg);
-               regmap_read(usp->regmap, USP_MODE2, &usp->mode2_reg);
-               sirf_usp_pcm_runtime_suspend(dev);
-       }
-       return 0;
-}
-
-static int sirf_usp_pcm_resume(struct device *dev)
-{
-       struct sirf_usp *usp = dev_get_drvdata(dev);
-       int ret;
-
-       if (!pm_runtime_status_suspended(dev)) {
-               ret = sirf_usp_pcm_runtime_resume(dev);
-               if (ret)
-                       return ret;
-               regmap_write(usp->regmap, USP_MODE1, usp->mode1_reg);
-               regmap_write(usp->regmap, USP_MODE2, usp->mode2_reg);
-       }
-       return 0;
-}
-#endif
-
-static const struct snd_soc_component_driver sirf_usp_component = {
-       .name           = "sirf-usp",
-};
-
-static const struct regmap_config sirf_usp_regmap_config = {
-       .reg_bits = 32,
-       .reg_stride = 4,
-       .val_bits = 32,
-       .max_register = USP_RX_FIFO_DATA,
-       .cache_type = REGCACHE_NONE,
-};
-
-static int sirf_usp_pcm_probe(struct platform_device *pdev)
-{
-       int ret;
-       struct sirf_usp *usp;
-       void __iomem *base;
-
-       usp = devm_kzalloc(&pdev->dev, sizeof(struct sirf_usp),
-                       GFP_KERNEL);
-       if (!usp)
-               return -ENOMEM;
-
-       platform_set_drvdata(pdev, usp);
-
-       base = devm_platform_ioremap_resource(pdev, 0);
-       if (IS_ERR(base))
-               return PTR_ERR(base);
-       usp->regmap = devm_regmap_init_mmio(&pdev->dev, base,
-                                           &sirf_usp_regmap_config);
-       if (IS_ERR(usp->regmap))
-               return PTR_ERR(usp->regmap);
-
-       usp->clk = devm_clk_get(&pdev->dev, NULL);
-       if (IS_ERR(usp->clk)) {
-               dev_err(&pdev->dev, "Get clock failed.\n");
-               return PTR_ERR(usp->clk);
-       }
-
-       pm_runtime_enable(&pdev->dev);
-       if (!pm_runtime_enabled(&pdev->dev)) {
-               ret = sirf_usp_pcm_runtime_resume(&pdev->dev);
-               if (ret)
-                       return ret;
-       }
-
-       ret = devm_snd_soc_register_component(&pdev->dev, &sirf_usp_component,
-               &sirf_usp_pcm_dai, 1);
-       if (ret) {
-               dev_err(&pdev->dev, "Register Audio SoC dai failed.\n");
-               return ret;
-       }
-       return devm_snd_dmaengine_pcm_register(&pdev->dev, NULL, 0);
-}
-
-static int sirf_usp_pcm_remove(struct platform_device *pdev)
-{
-       if (!pm_runtime_enabled(&pdev->dev))
-               sirf_usp_pcm_runtime_suspend(&pdev->dev);
-       else
-               pm_runtime_disable(&pdev->dev);
-       return 0;
-}
-
-static const struct of_device_id sirf_usp_pcm_of_match[] = {
-       { .compatible = "sirf,prima2-usp-pcm", },
-       {}
-};
-MODULE_DEVICE_TABLE(of, sirf_usp_pcm_of_match);
-
-static const struct dev_pm_ops sirf_usp_pcm_pm_ops = {
-       SET_RUNTIME_PM_OPS(sirf_usp_pcm_runtime_suspend,
-               sirf_usp_pcm_runtime_resume, NULL)
-       SET_SYSTEM_SLEEP_PM_OPS(sirf_usp_pcm_suspend, sirf_usp_pcm_resume)
-};
-
-static struct platform_driver sirf_usp_pcm_driver = {
-       .driver = {
-               .name = "sirf-usp-pcm",
-               .of_match_table = sirf_usp_pcm_of_match,
-               .pm = &sirf_usp_pcm_pm_ops,
-       },
-       .probe = sirf_usp_pcm_probe,
-       .remove = sirf_usp_pcm_remove,
-};
-
-module_platform_driver(sirf_usp_pcm_driver);
-
-MODULE_DESCRIPTION("SiRF SoC USP PCM bus driver");
-MODULE_AUTHOR("RongJun Ying <Rongjun.Ying@csr.com>");
-MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/sirf/sirf-usp.h b/sound/soc/sirf/sirf-usp.h
deleted file mode 100644 (file)
index 08993b5..0000000
+++ /dev/null
@@ -1,292 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0-or-later */
-/*
- * arch/arm/mach-prima2/include/mach/sirfsoc_usp.h
- *
- * Copyright (c) 2011 Cambridge Silicon Radio Limited, a CSR plc group company.
- */
-
-#ifndef _SIRF_USP_H
-#define _SIRF_USP_H
-
-/* USP Registers */
-#define USP_MODE1              0x00
-#define USP_MODE2              0x04
-#define USP_TX_FRAME_CTRL      0x08
-#define USP_RX_FRAME_CTRL      0x0C
-#define USP_TX_RX_ENABLE       0x10
-#define USP_INT_ENABLE         0x14
-#define USP_INT_STATUS         0x18
-#define USP_PIN_IO_DATA                0x1C
-#define USP_RISC_DSP_MODE      0x20
-#define USP_AYSNC_PARAM_REG    0x24
-#define USP_IRDA_X_MODE_DIV    0x28
-#define USP_SM_CFG             0x2C
-#define USP_TX_DMA_IO_CTRL     0x100
-#define USP_TX_DMA_IO_LEN      0x104
-#define USP_TX_FIFO_CTRL       0x108
-#define USP_TX_FIFO_LEVEL_CHK  0x10C
-#define USP_TX_FIFO_OP         0x110
-#define USP_TX_FIFO_STATUS     0x114
-#define USP_TX_FIFO_DATA       0x118
-#define USP_RX_DMA_IO_CTRL     0x120
-#define USP_RX_DMA_IO_LEN      0x124
-#define USP_RX_FIFO_CTRL       0x128
-#define USP_RX_FIFO_LEVEL_CHK  0x12C
-#define USP_RX_FIFO_OP         0x130
-#define USP_RX_FIFO_STATUS     0x134
-#define USP_RX_FIFO_DATA       0x138
-
-/* USP MODE register-1 */
-#define USP_SYNC_MODE                  0x00000001
-#define USP_CLOCK_MODE_SLAVE           0x00000002
-#define USP_LOOP_BACK_EN               0x00000004
-#define USP_HPSIR_EN                   0x00000008
-#define USP_ENDIAN_CTRL_LSBF           0x00000010
-#define USP_EN                         0x00000020
-#define USP_RXD_ACT_EDGE_FALLING       0x00000040
-#define USP_TXD_ACT_EDGE_FALLING       0x00000080
-#define USP_RFS_ACT_LEVEL_LOGIC1       0x00000100
-#define USP_TFS_ACT_LEVEL_LOGIC1       0x00000200
-#define USP_SCLK_IDLE_MODE_TOGGLE      0x00000400
-#define USP_SCLK_IDLE_LEVEL_LOGIC1     0x00000800
-#define USP_SCLK_PIN_MODE_IO   0x00001000
-#define USP_RFS_PIN_MODE_IO    0x00002000
-#define USP_TFS_PIN_MODE_IO    0x00004000
-#define USP_RXD_PIN_MODE_IO    0x00008000
-#define USP_TXD_PIN_MODE_IO    0x00010000
-#define USP_SCLK_IO_MODE_INPUT 0x00020000
-#define USP_RFS_IO_MODE_INPUT  0x00040000
-#define USP_TFS_IO_MODE_INPUT  0x00080000
-#define USP_RXD_IO_MODE_INPUT  0x00100000
-#define USP_TXD_IO_MODE_INPUT  0x00200000
-#define USP_IRDA_WIDTH_DIV_MASK        0x3FC00000
-#define USP_IRDA_WIDTH_DIV_OFFSET      0
-#define USP_IRDA_IDLE_LEVEL_HIGH       0x40000000
-#define USP_TX_UFLOW_REPEAT_ZERO       0x80000000
-#define USP_TX_ENDIAN_MODE             0x00000020
-#define USP_RX_ENDIAN_MODE             0x00000020
-
-/* USP Mode Register-2 */
-#define USP_RXD_DELAY_LEN_MASK         0x000000FF
-#define USP_RXD_DELAY_LEN_OFFSET       0
-
-#define USP_TXD_DELAY_LEN_MASK         0x0000FF00
-#define USP_TXD_DELAY_LEN_OFFSET       8
-
-#define USP_ENA_CTRL_MODE              0x00010000
-#define USP_FRAME_CTRL_MODE            0x00020000
-#define USP_TFS_SOURCE_MODE             0x00040000
-#define USP_TFS_MS_MODE                 0x00080000
-#define USP_CLK_DIVISOR_MASK           0x7FE00000
-#define USP_CLK_DIVISOR_OFFSET         21
-
-#define USP_TFS_CLK_SLAVE_MODE         (1<<20)
-#define USP_RFS_CLK_SLAVE_MODE         (1<<19)
-
-#define USP_IRDA_DATA_WIDTH            0x80000000
-
-/* USP Transmit Frame Control Register */
-
-#define USP_TXC_DATA_LEN_MASK          0x000000FF
-#define USP_TXC_DATA_LEN_OFFSET                0
-
-#define USP_TXC_SYNC_LEN_MASK          0x0000FF00
-#define USP_TXC_SYNC_LEN_OFFSET                8
-
-#define USP_TXC_FRAME_LEN_MASK         0x00FF0000
-#define USP_TXC_FRAME_LEN_OFFSET       16
-
-#define USP_TXC_SHIFTER_LEN_MASK       0x1F000000
-#define USP_TXC_SHIFTER_LEN_OFFSET     24
-
-#define USP_TXC_SLAVE_CLK_SAMPLE       0x20000000
-
-#define USP_TXC_CLK_DIVISOR_MASK       0xC0000000
-#define USP_TXC_CLK_DIVISOR_OFFSET     30
-
-/* USP Receive Frame Control Register */
-
-#define USP_RXC_DATA_LEN_MASK          0x000000FF
-#define USP_RXC_DATA_LEN_OFFSET                0
-
-#define USP_RXC_FRAME_LEN_MASK         0x0000FF00
-#define USP_RXC_FRAME_LEN_OFFSET       8
-
-#define USP_RXC_SHIFTER_LEN_MASK       0x001F0000
-#define USP_RXC_SHIFTER_LEN_OFFSET     16
-
-#define USP_START_EDGE_MODE    0x00800000
-#define USP_I2S_SYNC_CHG       0x00200000
-
-#define USP_RXC_CLK_DIVISOR_MASK       0x0F000000
-#define USP_RXC_CLK_DIVISOR_OFFSET     24
-#define USP_SINGLE_SYNC_MODE           0x00400000
-
-/* Tx - RX Enable Register */
-
-#define USP_RX_ENA             0x00000001
-#define USP_TX_ENA             0x00000002
-
-/* USP Interrupt Enable and status Register */
-#define USP_RX_DONE_INT                        0x00000001
-#define USP_TX_DONE_INT                        0x00000002
-#define USP_RX_OFLOW_INT               0x00000004
-#define USP_TX_UFLOW_INT               0x00000008
-#define USP_RX_IO_DMA_INT              0x00000010
-#define USP_TX_IO_DMA_INT              0x00000020
-#define USP_RXFIFO_FULL_INT            0x00000040
-#define USP_TXFIFO_EMPTY_INT           0x00000080
-#define USP_RXFIFO_THD_INT             0x00000100
-#define USP_TXFIFO_THD_INT             0x00000200
-#define USP_UART_FRM_ERR_INT           0x00000400
-#define USP_RX_TIMEOUT_INT             0x00000800
-#define USP_TX_ALLOUT_INT              0x00001000
-#define USP_RXD_BREAK_INT              0x00008000
-
-/* All possible TX interruots */
-#define USP_TX_INTERRUPT               (USP_TX_DONE_INT|USP_TX_UFLOW_INT|\
-                                       USP_TX_IO_DMA_INT|\
-                                       USP_TXFIFO_EMPTY_INT|\
-                                       USP_TXFIFO_THD_INT)
-/* All possible RX interruots */
-#define USP_RX_INTERRUPT               (USP_RX_DONE_INT|USP_RX_OFLOW_INT|\
-                                       USP_RX_IO_DMA_INT|\
-                                       USP_RXFIFO_FULL_INT|\
-                                       USP_RXFIFO_THD_INT|\
-                                       USP_RX_TIMEOUT_INT)
-
-#define USP_INT_ALL        0x1FFF
-
-/* USP Pin I/O Data Register */
-
-#define USP_RFS_PIN_VALUE_MASK 0x00000001
-#define USP_TFS_PIN_VALUE_MASK 0x00000002
-#define USP_RXD_PIN_VALUE_MASK 0x00000004
-#define USP_TXD_PIN_VALUE_MASK 0x00000008
-#define USP_SCLK_PIN_VALUE_MASK        0x00000010
-
-/* USP RISC/DSP Mode Register */
-#define USP_RISC_DSP_SEL       0x00000001
-
-/* USP ASYNC PARAMETER Register*/
-
-#define USP_ASYNC_TIMEOUT_MASK 0x0000FFFF
-#define USP_ASYNC_TIMEOUT_OFFSET       0
-#define USP_ASYNC_TIMEOUT(x)   (((x)&USP_ASYNC_TIMEOUT_MASK) \
-                               <<USP_ASYNC_TIMEOUT_OFFSET)
-
-#define USP_ASYNC_DIV2_MASK            0x003F0000
-#define USP_ASYNC_DIV2_OFFSET          16
-
-/* USP TX DMA I/O MODE Register */
-#define USP_TX_MODE_IO                 0x00000001
-
-/* USP TX DMA I/O Length Register */
-#define USP_TX_DATA_LEN_MASK           0xFFFFFFFF
-#define USP_TX_DATA_LEN_OFFSET         0
-
-/* USP TX FIFO Control Register */
-#define USP_TX_FIFO_WIDTH_MASK         0x00000003
-#define USP_TX_FIFO_WIDTH_OFFSET       0
-
-#define USP_TX_FIFO_THD_MASK           0x000001FC
-#define USP_TX_FIFO_THD_OFFSET         2
-
-/* USP TX FIFO Level Check Register */
-#define USP_TX_FIFO_LEVEL_CHECK_MASK   0x1F
-#define USP_TX_FIFO_SC_OFFSET  0
-#define USP_TX_FIFO_LC_OFFSET  10
-#define USP_TX_FIFO_HC_OFFSET  20
-
-#define TX_FIFO_SC(x)          (((x) & USP_TX_FIFO_LEVEL_CHECK_MASK) \
-                               << USP_TX_FIFO_SC_OFFSET)
-#define TX_FIFO_LC(x)          (((x) & USP_TX_FIFO_LEVEL_CHECK_MASK) \
-                               << USP_TX_FIFO_LC_OFFSET)
-#define TX_FIFO_HC(x)          (((x) & USP_TX_FIFO_LEVEL_CHECK_MASK) \
-                               << USP_TX_FIFO_HC_OFFSET)
-
-/* USP TX FIFO Operation Register */
-#define USP_TX_FIFO_RESET              0x00000001
-#define USP_TX_FIFO_START              0x00000002
-
-/* USP TX FIFO Status Register */
-#define USP_TX_FIFO_LEVEL_MASK         0x0000007F
-#define USP_TX_FIFO_LEVEL_OFFSET       0
-
-#define USP_TX_FIFO_FULL               0x00000080
-#define USP_TX_FIFO_EMPTY              0x00000100
-
-/* USP TX FIFO Data Register */
-#define USP_TX_FIFO_DATA_MASK          0xFFFFFFFF
-#define USP_TX_FIFO_DATA_OFFSET                0
-
-/* USP RX DMA I/O MODE Register */
-#define USP_RX_MODE_IO                 0x00000001
-#define USP_RX_DMA_FLUSH               0x00000004
-
-/* USP RX DMA I/O Length Register */
-#define USP_RX_DATA_LEN_MASK           0xFFFFFFFF
-#define USP_RX_DATA_LEN_OFFSET         0
-
-/* USP RX FIFO Control Register */
-#define USP_RX_FIFO_WIDTH_MASK         0x00000003
-#define USP_RX_FIFO_WIDTH_OFFSET       0
-
-#define USP_RX_FIFO_THD_MASK           0x000001FC
-#define USP_RX_FIFO_THD_OFFSET         2
-
-/* USP RX FIFO Level Check Register */
-
-#define USP_RX_FIFO_LEVEL_CHECK_MASK   0x1F
-#define USP_RX_FIFO_SC_OFFSET  0
-#define USP_RX_FIFO_LC_OFFSET  10
-#define USP_RX_FIFO_HC_OFFSET  20
-
-#define RX_FIFO_SC(x)          (((x) & USP_RX_FIFO_LEVEL_CHECK_MASK) \
-                               << USP_RX_FIFO_SC_OFFSET)
-#define RX_FIFO_LC(x)          (((x) & USP_RX_FIFO_LEVEL_CHECK_MASK) \
-                               << USP_RX_FIFO_LC_OFFSET)
-#define RX_FIFO_HC(x)          (((x) & USP_RX_FIFO_LEVEL_CHECK_MASK) \
-                               << USP_RX_FIFO_HC_OFFSET)
-
-/* USP RX FIFO Operation Register */
-#define USP_RX_FIFO_RESET              0x00000001
-#define USP_RX_FIFO_START              0x00000002
-
-/* USP RX FIFO Status Register */
-
-#define USP_RX_FIFO_LEVEL_MASK         0x0000007F
-#define USP_RX_FIFO_LEVEL_OFFSET       0
-
-#define USP_RX_FIFO_FULL               0x00000080
-#define USP_RX_FIFO_EMPTY              0x00000100
-
-/* USP RX FIFO Data Register */
-
-#define USP_RX_FIFO_DATA_MASK          0xFFFFFFFF
-#define USP_RX_FIFO_DATA_OFFSET                0
-
-/*
- * When rx thd irq occur, sender just disable tx empty irq,
- * Remaining data in tx fifo wil also be sent out.
- */
-#define USP_FIFO_SIZE                  128
-#define USP_TX_FIFO_THRESHOLD          (USP_FIFO_SIZE/2)
-#define USP_RX_FIFO_THRESHOLD          (USP_FIFO_SIZE/2)
-
-/* FIFO_WIDTH for the USP_TX_FIFO_CTRL and USP_RX_FIFO_CTRL registers */
-#define USP_FIFO_WIDTH_BYTE  0x00
-#define USP_FIFO_WIDTH_WORD  0x01
-#define USP_FIFO_WIDTH_DWORD 0x02
-
-#define USP_ASYNC_DIV2          16
-
-#define USP_PLUGOUT_RETRY_CNT  2
-
-#define USP_TX_RX_FIFO_WIDTH_DWORD    2
-
-#define SIRF_USP_DIV_MCLK      0
-
-#define SIRF_USP_I2S_TFS_SYNC  0
-#define SIRF_USP_I2S_RFS_SYNC  1
-#endif
index 7605233..159bf88 100644 (file)
@@ -11,6 +11,7 @@
 #include <linux/module.h>
 #include <linux/pm_runtime.h>
 #include <sound/soc.h>
+#include <linux/bitops.h>
 
 #define soc_component_ret(dai, ret) _soc_component_ret(dai, __func__, ret)
 static inline int _soc_component_ret(struct snd_soc_component *component,
@@ -34,6 +35,18 @@ static inline int _soc_component_ret(struct snd_soc_component *component,
        return ret;
 }
 
+static inline int soc_component_field_shift(struct snd_soc_component *component,
+                                           unsigned int mask)
+{
+       if (!mask) {
+               dev_err(component->dev, "ASoC: error field mask is zero for %s\n",
+                       component->name);
+               return 0;
+       }
+
+       return (ffs(mask) - 1);
+}
+
 /*
  * We might want to check substream by using list.
  * In such case, we can update these macros.
@@ -839,6 +852,47 @@ int snd_soc_component_update_bits_async(struct snd_soc_component *component,
 }
 EXPORT_SYMBOL_GPL(snd_soc_component_update_bits_async);
 
+/**
+ * snd_soc_component_read_field() - Read register field value
+ * @component: Component to read from
+ * @reg: Register to read
+ * @mask: mask of the register field
+ *
+ * Return: read value of register field.
+ */
+unsigned int snd_soc_component_read_field(struct snd_soc_component *component,
+                                         unsigned int reg, unsigned int mask)
+{
+       unsigned int val;
+
+       val = snd_soc_component_read(component, reg);
+
+       val = (val & mask) >> soc_component_field_shift(component, mask);
+
+       return val;
+}
+EXPORT_SYMBOL_GPL(snd_soc_component_read_field);
+
+/**
+ * snd_soc_component_write_field() - write to register field
+ * @component: Component to write to
+ * @reg: Register to write
+ * @mask: mask of the register field to update
+ * @val: value of the field to write
+ *
+ * Return: 1 for change, otherwise 0.
+ */
+int snd_soc_component_write_field(struct snd_soc_component *component,
+                                 unsigned int reg, unsigned int mask,
+                                 unsigned int val)
+{
+
+       val = (val << soc_component_field_shift(component, mask)) & mask;
+
+       return snd_soc_component_update_bits(component, reg, mask, val);
+}
+EXPORT_SYMBOL_GPL(snd_soc_component_write_field);
+
 /**
  * snd_soc_component_async_complete() - Ensure asynchronous I/O has completed
  * @component: Component for which to wait
index 2b75d01..b005f9e 100644 (file)
@@ -2528,9 +2528,20 @@ static struct snd_soc_dapm_widget *dapm_find_widget(
 {
        struct snd_soc_dapm_widget *w;
        struct snd_soc_dapm_widget *fallback = NULL;
+       char prefixed_pin[80];
+       const char *pin_name;
+       const char *prefix = soc_dapm_prefix(dapm);
+
+       if (prefix) {
+               snprintf(prefixed_pin, sizeof(prefixed_pin), "%s %s",
+                        prefix, pin);
+               pin_name = prefixed_pin;
+       } else {
+               pin_name = pin;
+       }
 
        for_each_card_widgets(dapm->card, w) {
-               if (!strcmp(w->name, pin)) {
+               if (!strcmp(w->name, pin_name)) {
                        if (w->dapm == dapm)
                                return w;
                        else
index ee51dc7..14d85ca 100644 (file)
@@ -203,6 +203,34 @@ static inline void dpcm_remove_debugfs_state(struct snd_soc_dpcm *dpcm)
 }
 #endif
 
+/* Set FE's runtime_update state; the state is protected via PCM stream lock
+ * for avoiding the race with trigger callback.
+ * If the state is unset and a trigger is pending while the previous operation,
+ * process the pending trigger action here.
+ */
+static int dpcm_fe_dai_do_trigger(struct snd_pcm_substream *substream, int cmd);
+static void dpcm_set_fe_update_state(struct snd_soc_pcm_runtime *fe,
+                                    int stream, enum snd_soc_dpcm_update state)
+{
+       struct snd_pcm_substream *substream =
+               snd_soc_dpcm_get_substream(fe, stream);
+
+       snd_pcm_stream_lock_irq(substream);
+       if (state == SND_SOC_DPCM_UPDATE_NO && fe->dpcm[stream].trigger_pending) {
+               dpcm_fe_dai_do_trigger(substream,
+                                      fe->dpcm[stream].trigger_pending - 1);
+               fe->dpcm[stream].trigger_pending = 0;
+       }
+       fe->dpcm[stream].runtime_update = state;
+       snd_pcm_stream_unlock_irq(substream);
+}
+
+static void dpcm_set_be_update_state(struct snd_soc_pcm_runtime *be,
+                                    int stream, enum snd_soc_dpcm_update state)
+{
+       be->dpcm[stream].runtime_update = state;
+}
+
 /**
  * snd_soc_runtime_action() - Increment/Decrement active count for
  * PCM runtime components
@@ -301,59 +329,46 @@ int dpcm_dapm_stream_event(struct snd_soc_pcm_runtime *fe, int dir,
        return 0;
 }
 
+static void soc_pcm_set_dai_params(struct snd_soc_dai *dai,
+                                  struct snd_pcm_hw_params *params)
+{
+       if (params) {
+               dai->rate        = params_rate(params);
+               dai->channels    = params_channels(params);
+               dai->sample_bits = snd_pcm_format_physical_width(params_format(params));
+       } else {
+               dai->rate        = 0;
+               dai->channels    = 0;
+               dai->sample_bits = 0;
+       }
+}
+
 static int soc_pcm_apply_symmetry(struct snd_pcm_substream *substream,
                                        struct snd_soc_dai *soc_dai)
 {
        struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
        int ret;
 
-       if (soc_dai->rate && (soc_dai->driver->symmetric_rates ||
-                               rtd->dai_link->symmetric_rates)) {
-               dev_dbg(soc_dai->dev, "ASoC: Symmetry forces %dHz rate\n",
-                               soc_dai->rate);
-
-               ret = snd_pcm_hw_constraint_single(substream->runtime,
-                                               SNDRV_PCM_HW_PARAM_RATE,
-                                               soc_dai->rate);
-               if (ret < 0) {
-                       dev_err(soc_dai->dev,
-                               "ASoC: Unable to apply rate constraint: %d\n",
-                               ret);
-                       return ret;
-               }
-       }
-
-       if (soc_dai->channels && (soc_dai->driver->symmetric_channels ||
-                               rtd->dai_link->symmetric_channels)) {
-               dev_dbg(soc_dai->dev, "ASoC: Symmetry forces %d channel(s)\n",
-                               soc_dai->channels);
-
-               ret = snd_pcm_hw_constraint_single(substream->runtime,
-                                               SNDRV_PCM_HW_PARAM_CHANNELS,
-                                               soc_dai->channels);
-               if (ret < 0) {
-                       dev_err(soc_dai->dev,
-                               "ASoC: Unable to apply channel symmetry constraint: %d\n",
-                               ret);
-                       return ret;
-               }
-       }
-
-       if (soc_dai->sample_bits && (soc_dai->driver->symmetric_samplebits ||
-                               rtd->dai_link->symmetric_samplebits)) {
-               dev_dbg(soc_dai->dev, "ASoC: Symmetry forces %d sample bits\n",
-                               soc_dai->sample_bits);
-
-               ret = snd_pcm_hw_constraint_single(substream->runtime,
-                                               SNDRV_PCM_HW_PARAM_SAMPLE_BITS,
-                                               soc_dai->sample_bits);
-               if (ret < 0) {
-                       dev_err(soc_dai->dev,
-                               "ASoC: Unable to apply sample bits symmetry constraint: %d\n",
-                               ret);
-                       return ret;
-               }
-       }
+#define __soc_pcm_apply_symmetry(name, NAME)                           \
+       if (soc_dai->name && (soc_dai->driver->symmetric_##name ||      \
+                             rtd->dai_link->symmetric_##name)) {       \
+               dev_dbg(soc_dai->dev, "ASoC: Symmetry forces %s to %d\n",\
+                       #name, soc_dai->name);                          \
+                                                                       \
+               ret = snd_pcm_hw_constraint_single(substream->runtime,  \
+                                                  SNDRV_PCM_HW_PARAM_##NAME,\
+                                                  soc_dai->name);      \
+               if (ret < 0) {                                          \
+                       dev_err(soc_dai->dev,                           \
+                               "ASoC: Unable to apply %s constraint: %d\n",\
+                               #name, ret);                            \
+                       return ret;                                     \
+               }                                                       \
+       }
+
+       __soc_pcm_apply_symmetry(rate,          RATE);
+       __soc_pcm_apply_symmetry(channels,      CHANNELS);
+       __soc_pcm_apply_symmetry(sample_bits,   SAMPLE_BITS);
 
        return 0;
 }
@@ -362,61 +377,30 @@ static int soc_pcm_params_symmetry(struct snd_pcm_substream *substream,
                                struct snd_pcm_hw_params *params)
 {
        struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
+       struct snd_soc_dai d;
        struct snd_soc_dai *dai;
        struct snd_soc_dai *cpu_dai;
-       unsigned int rate, channels, sample_bits, symmetry, i;
-
-       rate = params_rate(params);
-       channels = params_channels(params);
-       sample_bits = snd_pcm_format_physical_width(params_format(params));
-
-       /* reject unmatched parameters when applying symmetry */
-       symmetry = rtd->dai_link->symmetric_rates;
-
-       for_each_rtd_cpu_dais(rtd, i, dai)
-               symmetry |= dai->driver->symmetric_rates;
-
-       if (symmetry) {
-               for_each_rtd_cpu_dais(rtd, i, cpu_dai) {
-                       if (cpu_dai->rate && cpu_dai->rate != rate) {
-                               dev_err(rtd->dev, "ASoC: unmatched rate symmetry: %d - %d\n",
-                                       cpu_dai->rate, rate);
-                               return -EINVAL;
-                       }
-               }
-       }
-
-       symmetry = rtd->dai_link->symmetric_channels;
+       unsigned int symmetry, i;
 
-       for_each_rtd_dais(rtd, i, dai)
-               symmetry |= dai->driver->symmetric_channels;
-
-       if (symmetry) {
-               for_each_rtd_cpu_dais(rtd, i, cpu_dai) {
-                       if (cpu_dai->channels &&
-                           cpu_dai->channels != channels) {
-                               dev_err(rtd->dev, "ASoC: unmatched channel symmetry: %d - %d\n",
-                                       cpu_dai->channels, channels);
-                               return -EINVAL;
+       soc_pcm_set_dai_params(&d, params);
+
+#define __soc_pcm_params_symmetry(name)                                        \
+       symmetry = rtd->dai_link->symmetric_##name;                     \
+       for_each_rtd_dais(rtd, i, dai)                                  \
+               symmetry |= dai->driver->symmetric_##name;              \
+                                                                       \
+       if (symmetry)                                                   \
+               for_each_rtd_cpu_dais(rtd, i, cpu_dai)                  \
+                       if (cpu_dai->name && cpu_dai->name != d.name) { \
+                               dev_err(rtd->dev, "ASoC: unmatched %s symmetry: %d - %d\n", \
+                                       #name, cpu_dai->name, d.name);  \
+                               return -EINVAL;                         \
                        }
-               }
-       }
 
-       symmetry = rtd->dai_link->symmetric_samplebits;
-
-       for_each_rtd_dais(rtd, i, dai)
-               symmetry |= dai->driver->symmetric_samplebits;
-
-       if (symmetry) {
-               for_each_rtd_cpu_dais(rtd, i, cpu_dai) {
-                       if (cpu_dai->sample_bits &&
-                           cpu_dai->sample_bits != sample_bits) {
-                               dev_err(rtd->dev, "ASoC: unmatched sample bits symmetry: %d - %d\n",
-                                       cpu_dai->sample_bits, sample_bits);
-                               return -EINVAL;
-                       }
-               }
-       }
+       /* reject unmatched parameters when applying symmetry */
+       __soc_pcm_params_symmetry(rate);
+       __soc_pcm_params_symmetry(channels);
+       __soc_pcm_params_symmetry(sample_bits);
 
        return 0;
 }
@@ -428,15 +412,15 @@ static bool soc_pcm_has_symmetry(struct snd_pcm_substream *substream)
        struct snd_soc_dai *dai;
        unsigned int symmetry, i;
 
-       symmetry = link->symmetric_rates ||
+       symmetry = link->symmetric_rate ||
                link->symmetric_channels ||
-               link->symmetric_samplebits;
+               link->symmetric_sample_bits;
 
        for_each_rtd_dais(rtd, i, dai)
                symmetry = symmetry ||
-                       dai->driver->symmetric_rates ||
+                       dai->driver->symmetric_rate ||
                        dai->driver->symmetric_channels ||
-                       dai->driver->symmetric_samplebits;
+                       dai->driver->symmetric_sample_bits;
 
        return symmetry;
 }
@@ -489,6 +473,42 @@ static void soc_pcm_apply_msb(struct snd_pcm_substream *substream)
        soc_pcm_set_msb(substream, cpu_bits);
 }
 
+static void soc_pcm_hw_init(struct snd_pcm_hardware *hw)
+{
+       hw->rates               = UINT_MAX;
+       hw->rate_min            = 0;
+       hw->rate_max            = UINT_MAX;
+       hw->channels_min        = 0;
+       hw->channels_max        = UINT_MAX;
+       hw->formats             = ULLONG_MAX;
+}
+
+static void soc_pcm_hw_update_rate(struct snd_pcm_hardware *hw,
+                                  struct snd_soc_pcm_stream *p)
+{
+       hw->rates = snd_pcm_rate_mask_intersect(hw->rates, p->rates);
+
+       /* setup hw->rate_min/max via hw->rates first */
+       snd_pcm_hw_limit_rates(hw);
+
+       /* update hw->rate_min/max by snd_soc_pcm_stream */
+       hw->rate_min = max(hw->rate_min, p->rate_min);
+       hw->rate_max = min_not_zero(hw->rate_max, p->rate_max);
+}
+
+static void soc_pcm_hw_update_chan(struct snd_pcm_hardware *hw,
+                                  struct snd_soc_pcm_stream *p)
+{
+       hw->channels_min = max(hw->channels_min, p->channels_min);
+       hw->channels_max = min(hw->channels_max, p->channels_max);
+}
+
+static void soc_pcm_hw_update_format(struct snd_pcm_hardware *hw,
+                                    struct snd_soc_pcm_stream *p)
+{
+       hw->formats &= p->formats;
+}
+
 /**
  * snd_soc_runtime_calc_hw() - Calculate hw limits for a PCM stream
  * @rtd: ASoC PCM runtime
@@ -505,14 +525,11 @@ int snd_soc_runtime_calc_hw(struct snd_soc_pcm_runtime *rtd,
        struct snd_soc_dai *cpu_dai;
        struct snd_soc_pcm_stream *codec_stream;
        struct snd_soc_pcm_stream *cpu_stream;
-       unsigned int chan_min = 0, chan_max = UINT_MAX;
        unsigned int cpu_chan_min = 0, cpu_chan_max = UINT_MAX;
-       unsigned int rate_min = 0, rate_max = UINT_MAX;
-       unsigned int cpu_rate_min = 0, cpu_rate_max = UINT_MAX;
-       unsigned int rates = UINT_MAX, cpu_rates = UINT_MAX;
-       u64 formats = ULLONG_MAX;
        int i;
 
+       soc_pcm_hw_init(hw);
+
        /* first calculate min/max only for CPUs in the DAI link */
        for_each_rtd_cpu_dais(rtd, i, cpu_dai) {
 
@@ -527,14 +544,12 @@ int snd_soc_runtime_calc_hw(struct snd_soc_pcm_runtime *rtd,
 
                cpu_stream = snd_soc_dai_get_pcm_stream(cpu_dai, stream);
 
-               cpu_chan_min = max(cpu_chan_min, cpu_stream->channels_min);
-               cpu_chan_max = min(cpu_chan_max, cpu_stream->channels_max);
-               cpu_rate_min = max(cpu_rate_min, cpu_stream->rate_min);
-               cpu_rate_max = min_not_zero(cpu_rate_max, cpu_stream->rate_max);
-               formats &= cpu_stream->formats;
-               cpu_rates = snd_pcm_rate_mask_intersect(cpu_stream->rates,
-                                                       cpu_rates);
+               soc_pcm_hw_update_chan(hw, cpu_stream);
+               soc_pcm_hw_update_rate(hw, cpu_stream);
+               soc_pcm_hw_update_format(hw, cpu_stream);
        }
+       cpu_chan_min = hw->channels_min;
+       cpu_chan_max = hw->channels_max;
 
        /* second calculate min/max only for CODECs in the DAI link */
        for_each_rtd_codec_dais(rtd, i, codec_dai) {
@@ -550,16 +565,13 @@ int snd_soc_runtime_calc_hw(struct snd_soc_pcm_runtime *rtd,
 
                codec_stream = snd_soc_dai_get_pcm_stream(codec_dai, stream);
 
-               chan_min = max(chan_min, codec_stream->channels_min);
-               chan_max = min(chan_max, codec_stream->channels_max);
-               rate_min = max(rate_min, codec_stream->rate_min);
-               rate_max = min_not_zero(rate_max, codec_stream->rate_max);
-               formats &= codec_stream->formats;
-               rates = snd_pcm_rate_mask_intersect(codec_stream->rates, rates);
+               soc_pcm_hw_update_chan(hw, codec_stream);
+               soc_pcm_hw_update_rate(hw, codec_stream);
+               soc_pcm_hw_update_format(hw, codec_stream);
        }
 
        /* Verify both a valid CPU DAI and a valid CODEC DAI were found */
-       if (!chan_min || !cpu_chan_min)
+       if (!hw->channels_min)
                return -EINVAL;
 
        /*
@@ -568,23 +580,10 @@ int snd_soc_runtime_calc_hw(struct snd_soc_pcm_runtime *rtd,
         * channel allocation be fixed up later
         */
        if (rtd->num_codecs > 1) {
-               chan_min = cpu_chan_min;
-               chan_max = cpu_chan_max;
+               hw->channels_min = cpu_chan_min;
+               hw->channels_max = cpu_chan_max;
        }
 
-       /* finally find a intersection between CODECs and CPUs */
-       hw->channels_min = max(chan_min, cpu_chan_min);
-       hw->channels_max = min(chan_max, cpu_chan_max);
-       hw->formats = formats;
-       hw->rates = snd_pcm_rate_mask_intersect(rates, cpu_rates);
-
-       snd_pcm_hw_limit_rates(hw);
-
-       hw->rate_min = max(hw->rate_min, cpu_rate_min);
-       hw->rate_min = max(hw->rate_min, rate_min);
-       hw->rate_max = min_not_zero(hw->rate_max, cpu_rate_max);
-       hw->rate_max = min_not_zero(hw->rate_max, rate_max);
-
        return 0;
 }
 EXPORT_SYMBOL_GPL(snd_soc_runtime_calc_hw);
@@ -870,11 +869,8 @@ static int soc_pcm_hw_clean(struct snd_pcm_substream *substream, int rollback)
        for_each_rtd_dais(rtd, i, dai) {
                int active = snd_soc_dai_stream_active(dai, substream->stream);
 
-               if (snd_soc_dai_active(dai) == 1) {
-                       dai->rate = 0;
-                       dai->channels = 0;
-                       dai->sample_bits = 0;
-               }
+               if (snd_soc_dai_active(dai) == 1)
+                       soc_pcm_set_dai_params(dai, NULL);
 
                if (active == 1)
                        snd_soc_dai_digital_mute(dai, 1, substream->stream);
@@ -971,11 +967,7 @@ static int soc_pcm_hw_params(struct snd_pcm_substream *substream,
                if(ret < 0)
                        goto out;
 
-               codec_dai->rate = params_rate(&codec_params);
-               codec_dai->channels = params_channels(&codec_params);
-               codec_dai->sample_bits = snd_pcm_format_physical_width(
-                                               params_format(&codec_params));
-
+               soc_pcm_set_dai_params(codec_dai, &codec_params);
                snd_soc_dapm_update_dai(substream, &codec_params, codec_dai);
        }
 
@@ -992,11 +984,7 @@ static int soc_pcm_hw_params(struct snd_pcm_substream *substream,
                        goto out;
 
                /* store the parameters for each DAI */
-               cpu_dai->rate = params_rate(params);
-               cpu_dai->channels = params_channels(params);
-               cpu_dai->sample_bits =
-                       snd_pcm_format_physical_width(params_format(params));
-
+               soc_pcm_set_dai_params(cpu_dai, params);
                snd_soc_dapm_update_dai(substream, params, cpu_dai);
        }
 
@@ -1335,7 +1323,7 @@ static int dpcm_prune_paths(struct snd_soc_pcm_runtime *fe, int stream,
                        stream ? "capture" : "playback",
                        dpcm->be->dai_link->name, fe->dai_link->name);
                dpcm->state = SND_SOC_DPCM_LINK_STATE_FREE;
-               dpcm->be->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_BE;
+               dpcm_set_be_update_state(dpcm->be, stream, SND_SOC_DPCM_UPDATE_BE);
                prune++;
        }
 
@@ -1371,8 +1359,8 @@ static int dpcm_add_paths(struct snd_soc_pcm_runtime *fe, int stream,
                /* is there a valid BE rtd for this widget */
                be = dpcm_get_be(card, widget, stream);
                if (!be) {
-                       dev_err(fe->dev, "ASoC: no BE found for %s\n",
-                                       widget->name);
+                       dev_dbg(fe->dev, "ASoC: no BE found for %s\n",
+                               widget->name);
                        continue;
                }
 
@@ -1390,7 +1378,7 @@ static int dpcm_add_paths(struct snd_soc_pcm_runtime *fe, int stream,
                        continue;
 
                /* new */
-               be->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_BE;
+               dpcm_set_be_update_state(be, stream, SND_SOC_DPCM_UPDATE_BE);
                new++;
        }
 
@@ -1418,8 +1406,7 @@ void dpcm_clear_pending_state(struct snd_soc_pcm_runtime *fe, int stream)
 
        spin_lock_irqsave(&fe->card->dpcm_lock, flags);
        for_each_dpcm_be(fe, stream, dpcm)
-               dpcm->be->dpcm[stream].runtime_update =
-                                               SND_SOC_DPCM_UPDATE_NO;
+               dpcm_set_be_update_state(dpcm->be, stream, SND_SOC_DPCM_UPDATE_NO);
        spin_unlock_irqrestore(&fe->card->dpcm_lock, flags);
 }
 
@@ -1542,21 +1529,21 @@ unwind:
 static void dpcm_init_runtime_hw(struct snd_pcm_runtime *runtime,
                                 struct snd_soc_pcm_stream *stream)
 {
-       runtime->hw.rate_min = stream->rate_min;
-       runtime->hw.rate_max = min_not_zero(stream->rate_max, UINT_MAX);
-       runtime->hw.channels_min = stream->channels_min;
-       runtime->hw.channels_max = stream->channels_max;
+       struct snd_pcm_hardware *hw = &runtime->hw;
+
+       soc_pcm_hw_update_rate(hw, stream);
+       soc_pcm_hw_update_chan(hw, stream);
        if (runtime->hw.formats)
                runtime->hw.formats &= stream->formats;
        else
                runtime->hw.formats = stream->formats;
-       runtime->hw.rates = stream->rates;
 }
 
 static void dpcm_runtime_merge_format(struct snd_pcm_substream *substream,
-                                     u64 *formats)
+                                     struct snd_pcm_runtime *runtime)
 {
        struct snd_soc_pcm_runtime *fe = asoc_substream_to_rtd(substream);
+       struct snd_pcm_hardware *hw = &runtime->hw;
        struct snd_soc_dpcm *dpcm;
        struct snd_soc_dai *dai;
        int stream = substream->stream;
@@ -1584,16 +1571,16 @@ static void dpcm_runtime_merge_format(struct snd_pcm_substream *substream,
 
                        codec_stream = snd_soc_dai_get_pcm_stream(dai, stream);
 
-                       *formats &= codec_stream->formats;
+                       soc_pcm_hw_update_format(hw, codec_stream);
                }
        }
 }
 
 static void dpcm_runtime_merge_chan(struct snd_pcm_substream *substream,
-                                   unsigned int *channels_min,
-                                   unsigned int *channels_max)
+                                   struct snd_pcm_runtime *runtime)
 {
        struct snd_soc_pcm_runtime *fe = asoc_substream_to_rtd(substream);
+       struct snd_pcm_hardware *hw = &runtime->hw;
        struct snd_soc_dpcm *dpcm;
        int stream = substream->stream;
 
@@ -1622,10 +1609,7 @@ static void dpcm_runtime_merge_chan(struct snd_pcm_substream *substream,
 
                        cpu_stream = snd_soc_dai_get_pcm_stream(dai, stream);
 
-                       *channels_min = max(*channels_min,
-                                           cpu_stream->channels_min);
-                       *channels_max = min(*channels_max,
-                                           cpu_stream->channels_max);
+                       soc_pcm_hw_update_chan(hw, cpu_stream);
                }
 
                /*
@@ -1635,20 +1619,16 @@ static void dpcm_runtime_merge_chan(struct snd_pcm_substream *substream,
                if (be->num_codecs == 1) {
                        codec_stream = snd_soc_dai_get_pcm_stream(asoc_rtd_to_codec(be, 0), stream);
 
-                       *channels_min = max(*channels_min,
-                                           codec_stream->channels_min);
-                       *channels_max = min(*channels_max,
-                                           codec_stream->channels_max);
+                       soc_pcm_hw_update_chan(hw, codec_stream);
                }
        }
 }
 
 static void dpcm_runtime_merge_rate(struct snd_pcm_substream *substream,
-                                   unsigned int *rates,
-                                   unsigned int *rate_min,
-                                   unsigned int *rate_max)
+                                   struct snd_pcm_runtime *runtime)
 {
        struct snd_soc_pcm_runtime *fe = asoc_substream_to_rtd(substream);
+       struct snd_pcm_hardware *hw = &runtime->hw;
        struct snd_soc_dpcm *dpcm;
        int stream = substream->stream;
 
@@ -1676,9 +1656,7 @@ static void dpcm_runtime_merge_rate(struct snd_pcm_substream *substream,
 
                        pcm = snd_soc_dai_get_pcm_stream(dai, stream);
 
-                       *rate_min = max(*rate_min, pcm->rate_min);
-                       *rate_max = min_not_zero(*rate_max, pcm->rate_max);
-                       *rates = snd_pcm_rate_mask_intersect(*rates, pcm->rates);
+                       soc_pcm_hw_update_rate(hw, pcm);
                }
        }
 }
@@ -1686,10 +1664,13 @@ static void dpcm_runtime_merge_rate(struct snd_pcm_substream *substream,
 static void dpcm_set_fe_runtime(struct snd_pcm_substream *substream)
 {
        struct snd_pcm_runtime *runtime = substream->runtime;
+       struct snd_pcm_hardware *hw = &runtime->hw;
        struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
        struct snd_soc_dai *cpu_dai;
        int i;
 
+       soc_pcm_hw_init(hw);
+
        for_each_rtd_cpu_dais(rtd, i, cpu_dai) {
                /*
                 * Skip CPUs which don't support the current stream
@@ -1703,34 +1684,9 @@ static void dpcm_set_fe_runtime(struct snd_pcm_substream *substream)
                                                   substream->stream));
        }
 
-       dpcm_runtime_merge_format(substream, &runtime->hw.formats);
-       dpcm_runtime_merge_chan(substream, &runtime->hw.channels_min,
-                               &runtime->hw.channels_max);
-       dpcm_runtime_merge_rate(substream, &runtime->hw.rates,
-                               &runtime->hw.rate_min, &runtime->hw.rate_max);
-}
-
-static int dpcm_fe_dai_do_trigger(struct snd_pcm_substream *substream, int cmd);
-
-/* Set FE's runtime_update state; the state is protected via PCM stream lock
- * for avoiding the race with trigger callback.
- * If the state is unset and a trigger is pending while the previous operation,
- * process the pending trigger action here.
- */
-static void dpcm_set_fe_update_state(struct snd_soc_pcm_runtime *fe,
-                                    int stream, enum snd_soc_dpcm_update state)
-{
-       struct snd_pcm_substream *substream =
-               snd_soc_dpcm_get_substream(fe, stream);
-
-       snd_pcm_stream_lock_irq(substream);
-       if (state == SND_SOC_DPCM_UPDATE_NO && fe->dpcm[stream].trigger_pending) {
-               dpcm_fe_dai_do_trigger(substream,
-                                      fe->dpcm[stream].trigger_pending - 1);
-               fe->dpcm[stream].trigger_pending = 0;
-       }
-       fe->dpcm[stream].runtime_update = state;
-       snd_pcm_stream_unlock_irq(substream);
+       dpcm_runtime_merge_format(substream, runtime);
+       dpcm_runtime_merge_chan(substream, runtime);
+       dpcm_runtime_merge_rate(substream, runtime);
 }
 
 static int dpcm_apply_symmetry(struct snd_pcm_substream *fe_substream,
@@ -1791,7 +1747,6 @@ static int dpcm_apply_symmetry(struct snd_pcm_substream *fe_substream,
 static int dpcm_fe_dai_startup(struct snd_pcm_substream *fe_substream)
 {
        struct snd_soc_pcm_runtime *fe = asoc_substream_to_rtd(fe_substream);
-       struct snd_pcm_runtime *runtime = fe_substream->runtime;
        int stream = fe_substream->stream, ret = 0;
 
        dpcm_set_fe_update_state(fe, stream, SND_SOC_DPCM_UPDATE_FE);
@@ -1814,7 +1769,6 @@ static int dpcm_fe_dai_startup(struct snd_pcm_substream *fe_substream)
        fe->dpcm[stream].state = SND_SOC_DPCM_STATE_OPEN;
 
        dpcm_set_fe_runtime(fe_substream);
-       snd_pcm_limit_hw_rates(runtime);
 
        ret = dpcm_apply_symmetry(fe_substream, stream);
        if (ret < 0)
@@ -2432,7 +2386,7 @@ static int dpcm_run_update_startup(struct snd_soc_pcm_runtime *fe, int stream)
                snd_soc_dpcm_get_substream(fe, stream);
        struct snd_soc_dpcm *dpcm;
        enum snd_soc_dpcm_trigger trigger = fe->dai_link->trigger[stream];
-       int ret;
+       int ret = 0;
        unsigned long flags;
 
        dev_dbg(fe->dev, "ASoC: runtime %s open on FE %s\n",
@@ -2440,8 +2394,13 @@ static int dpcm_run_update_startup(struct snd_soc_pcm_runtime *fe, int stream)
 
        /* Only start the BE if the FE is ready */
        if (fe->dpcm[stream].state == SND_SOC_DPCM_STATE_HW_FREE ||
-               fe->dpcm[stream].state == SND_SOC_DPCM_STATE_CLOSE)
-               return -EINVAL;
+               fe->dpcm[stream].state == SND_SOC_DPCM_STATE_CLOSE) {
+               ret = -EINVAL;
+               dev_err(fe->dev, "ASoC: FE %s is not ready %d\n",
+                       fe->dai_link->name, fe->dpcm[stream].state);
+               ret = -EINVAL;
+               goto disconnect;
+       }
 
        /* startup must always be called for new BEs */
        ret = dpcm_be_dai_startup(fe, stream);
@@ -2502,12 +2461,18 @@ hw_free:
 close:
        dpcm_be_dai_shutdown(fe, stream);
 disconnect:
-       /* disconnect any closed BEs */
+       /* disconnect any pending BEs */
        spin_lock_irqsave(&fe->card->dpcm_lock, flags);
        for_each_dpcm_be(fe, stream, dpcm) {
                struct snd_soc_pcm_runtime *be = dpcm->be;
-               if (be->dpcm[stream].state == SND_SOC_DPCM_STATE_CLOSE)
-                       dpcm->state = SND_SOC_DPCM_LINK_STATE_FREE;
+
+               /* is this op for this BE ? */
+               if (!snd_soc_dpcm_be_can_update(fe, be, stream))
+                       continue;
+
+               if (be->dpcm[stream].state == SND_SOC_DPCM_STATE_CLOSE ||
+                       be->dpcm[stream].state == SND_SOC_DPCM_STATE_NEW)
+                               dpcm->state = SND_SOC_DPCM_LINK_STATE_FREE;
        }
        spin_unlock_irqrestore(&fe->card->dpcm_lock, flags);
 
@@ -2671,15 +2636,11 @@ open_end:
        return ret;
 }
 
-/* create a new pcm */
-int soc_new_pcm(struct snd_soc_pcm_runtime *rtd, int num)
+static int soc_get_playback_capture(struct snd_soc_pcm_runtime *rtd,
+                                   int *playback, int *capture)
 {
        struct snd_soc_dai *codec_dai;
        struct snd_soc_dai *cpu_dai;
-       struct snd_soc_component *component;
-       struct snd_pcm *pcm;
-       char new_name[64];
-       int ret = 0, playback = 0, capture = 0;
        int stream;
        int i;
 
@@ -2695,12 +2656,11 @@ int soc_new_pcm(struct snd_soc_pcm_runtime *rtd, int num)
 
                        for_each_rtd_cpu_dais(rtd, i, cpu_dai) {
                                if (snd_soc_dai_stream_valid(cpu_dai, stream)) {
-                                       playback = 1;
+                                       *playback = 1;
                                        break;
                                }
                        }
-
-                       if (!playback) {
+                       if (!*playback) {
                                dev_err(rtd->card->dev,
                                        "No CPU DAIs support playback for stream %s\n",
                                        rtd->dai_link->stream_name);
@@ -2712,12 +2672,12 @@ int soc_new_pcm(struct snd_soc_pcm_runtime *rtd, int num)
 
                        for_each_rtd_cpu_dais(rtd, i, cpu_dai) {
                                if (snd_soc_dai_stream_valid(cpu_dai, stream)) {
-                                       capture = 1;
+                                       *capture = 1;
                                        break;
                                }
                        }
 
-                       if (!capture) {
+                       if (!*capture) {
                                dev_err(rtd->card->dev,
                                        "No CPU DAIs support capture for stream %s\n",
                                        rtd->dai_link->stream_name);
@@ -2744,36 +2704,46 @@ int soc_new_pcm(struct snd_soc_pcm_runtime *rtd, int num)
 
                        if (snd_soc_dai_stream_valid(codec_dai, SNDRV_PCM_STREAM_PLAYBACK) &&
                            snd_soc_dai_stream_valid(cpu_dai,   cpu_playback))
-                               playback = 1;
+                               *playback = 1;
                        if (snd_soc_dai_stream_valid(codec_dai, SNDRV_PCM_STREAM_CAPTURE) &&
                            snd_soc_dai_stream_valid(cpu_dai,   cpu_capture))
-                               capture = 1;
+                               *capture = 1;
                }
        }
 
        if (rtd->dai_link->playback_only) {
-               playback = 1;
-               capture = 0;
+               *playback = 1;
+               *capture = 0;
        }
 
        if (rtd->dai_link->capture_only) {
-               playback = 0;
-               capture = 1;
+               *playback = 0;
+               *capture = 1;
        }
 
+       return 0;
+}
+
+static int soc_create_pcm(struct snd_pcm **pcm,
+                         struct snd_soc_pcm_runtime *rtd,
+                         int playback, int capture, int num)
+{
+       char new_name[64];
+       int ret;
+
        /* create the PCM */
        if (rtd->dai_link->params) {
                snprintf(new_name, sizeof(new_name), "codec2codec(%s)",
                         rtd->dai_link->stream_name);
 
                ret = snd_pcm_new_internal(rtd->card->snd_card, new_name, num,
-                                          playback, capture, &pcm);
+                                          playback, capture, pcm);
        } else if (rtd->dai_link->no_pcm) {
                snprintf(new_name, sizeof(new_name), "(%s)",
                        rtd->dai_link->stream_name);
 
                ret = snd_pcm_new_internal(rtd->card->snd_card, new_name, num,
-                               playback, capture, &pcm);
+                               playback, capture, pcm);
        } else {
                if (rtd->dai_link->dynamic)
                        snprintf(new_name, sizeof(new_name), "%s (*)",
@@ -2785,7 +2755,7 @@ int soc_new_pcm(struct snd_soc_pcm_runtime *rtd, int num)
                                "multicodec" : asoc_rtd_to_codec(rtd, 0)->name, num);
 
                ret = snd_pcm_new(rtd->card->snd_card, new_name, num, playback,
-                       capture, &pcm);
+                       capture, pcm);
        }
        if (ret < 0) {
                dev_err(rtd->card->dev, "ASoC: can't create pcm %s for dailink %s: %d\n",
@@ -2794,14 +2764,33 @@ int soc_new_pcm(struct snd_soc_pcm_runtime *rtd, int num)
        }
        dev_dbg(rtd->card->dev, "ASoC: registered pcm #%d %s\n",num, new_name);
 
+       return 0;
+}
+
+/* create a new pcm */
+int soc_new_pcm(struct snd_soc_pcm_runtime *rtd, int num)
+{
+       struct snd_soc_component *component;
+       struct snd_pcm *pcm;
+       int ret = 0, playback = 0, capture = 0;
+       int i;
+
+       ret = soc_get_playback_capture(rtd, &playback, &capture);
+       if (ret < 0)
+               return ret;
+
+       ret = soc_create_pcm(&pcm, rtd, playback, capture, num);
+       if (ret < 0)
+               return ret;
+
        /* DAPM dai link stream work */
        if (rtd->dai_link->params)
                rtd->close_delayed_work_func = codec2codec_close_delayed_work;
        else
                rtd->close_delayed_work_func = snd_soc_close_delayed_work;
 
-       pcm->nonatomic = rtd->dai_link->nonatomic;
        rtd->pcm = pcm;
+       pcm->nonatomic = rtd->dai_link->nonatomic;
        pcm->private_data = rtd;
 
        if (rtd->dai_link->no_pcm || rtd->dai_link->params) {
@@ -2854,8 +2843,8 @@ int soc_new_pcm(struct snd_soc_pcm_runtime *rtd, int num)
 
        ret = snd_soc_pcm_component_new(rtd);
        if (ret < 0) {
-               dev_err(rtd->dev, "ASoC: pcm %s constructor failed for dailink %s: %d\n",
-                       new_name, rtd->dai_link->name, ret);
+               dev_err(rtd->dev, "ASoC: pcm constructor failed for dailink %s: %d\n",
+                       rtd->dai_link->name, ret);
                return ret;
        }
 
diff --git a/sound/soc/soc-topology-test.c b/sound/soc/soc-topology-test.c
new file mode 100644 (file)
index 0000000..ae39681
--- /dev/null
@@ -0,0 +1,843 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * soc-topology-test.c  --  ALSA SoC Topology Kernel Unit Tests
+ *
+ * Copyright(c) 2021 Intel Corporation. All rights reserved.
+ */
+
+#include <linux/firmware.h>
+#include <sound/core.h>
+#include <sound/soc.h>
+#include <sound/soc-topology.h>
+#include <kunit/test.h>
+
+/* ===== HELPER FUNCTIONS =================================================== */
+
+/*
+ * snd_soc_component needs device to operate on (primarily for prints), create
+ * fake one, as we don't register with PCI or anything else
+ * device_driver name is used in some of the prints (fmt_single_name) so
+ * we also mock up minimal one
+ */
+static struct device *test_dev;
+
+static struct device_driver test_drv = {
+       .name = "sound-soc-topology-test-driver",
+};
+
+static int snd_soc_tplg_test_init(struct kunit *test)
+{
+       test_dev = root_device_register("sound-soc-topology-test");
+       test_dev = get_device(test_dev);
+       if (!test_dev)
+               return -ENODEV;
+
+       test_dev->driver = &test_drv;
+
+       return 0;
+}
+
+static void snd_soc_tplg_test_exit(struct kunit *test)
+{
+       put_device(test_dev);
+       root_device_unregister(test_dev);
+}
+
+/*
+ * helper struct we use when registering component, as we load topology during
+ * component probe, we need to pass struct kunit somehow to probe function, so
+ * we can report test result
+ */
+struct kunit_soc_component {
+       struct kunit *kunit;
+       int expect; /* what result we expect when loading topology */
+       struct snd_soc_component comp;
+       struct snd_soc_card card;
+       struct firmware fw;
+};
+
+static int d_probe(struct snd_soc_component *component)
+{
+       struct kunit_soc_component *kunit_comp =
+                       container_of(component, struct kunit_soc_component, comp);
+       int ret;
+
+       ret = snd_soc_tplg_component_load(component, NULL, &kunit_comp->fw);
+       KUNIT_EXPECT_EQ_MSG(kunit_comp->kunit, kunit_comp->expect, ret,
+                           "Failed topology load");
+
+       return 0;
+}
+
+static void d_remove(struct snd_soc_component *component)
+{
+       struct kunit_soc_component *kunit_comp =
+                       container_of(component, struct kunit_soc_component, comp);
+       int ret;
+
+       ret = snd_soc_tplg_component_remove(component);
+       KUNIT_EXPECT_EQ(kunit_comp->kunit, 0, ret);
+}
+
+/*
+ * ASoC minimal boiler plate
+ */
+SND_SOC_DAILINK_DEF(dummy, DAILINK_COMP_ARRAY(COMP_DUMMY()));
+
+SND_SOC_DAILINK_DEF(platform, DAILINK_COMP_ARRAY(COMP_PLATFORM("sound-soc-topology-test")));
+
+static struct snd_soc_dai_link kunit_dai_links[] = {
+       {
+               .name = "KUNIT Audio Port",
+               .id = 0,
+               .stream_name = "Audio Playback/Capture",
+               .nonatomic = 1,
+               .dynamic = 1,
+               .trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST},
+               .dpcm_playback = 1,
+               .dpcm_capture = 1,
+               SND_SOC_DAILINK_REG(dummy, dummy, platform),
+       },
+};
+
+static const struct snd_soc_component_driver test_component = {
+       .name = "sound-soc-topology-test",
+       .probe = d_probe,
+       .remove = d_remove,
+       .non_legacy_dai_naming = 1,
+};
+
+/* ===== TOPOLOGY TEMPLATES ================================================= */
+
+// Structural representation of topology which can be generated with:
+// $ touch empty
+// $ alsatplg -c empty -o empty.tplg
+// $ xxd -i empty.tplg
+
+struct tplg_tmpl_001 {
+       struct snd_soc_tplg_hdr header;
+       struct snd_soc_tplg_manifest manifest;
+} __packed;
+
+static struct tplg_tmpl_001 tplg_tmpl_empty = {
+       .header = {
+               .magic = cpu_to_le32(SND_SOC_TPLG_MAGIC),
+               .abi = cpu_to_le32(5),
+               .version = 0,
+               .type = cpu_to_le32(SND_SOC_TPLG_TYPE_MANIFEST),
+               .size = cpu_to_le32(sizeof(struct snd_soc_tplg_hdr)),
+               .vendor_type = 0,
+               .payload_size = cpu_to_le32(sizeof(struct snd_soc_tplg_manifest)),
+               .index = 0,
+               .count = cpu_to_le32(1),
+       },
+
+       .manifest = {
+               .size = cpu_to_le32(sizeof(struct snd_soc_tplg_manifest)),
+               /* rest of fields is 0 */
+       },
+};
+
+// Structural representation of topology containing SectionPCM
+
+struct tplg_tmpl_002 {
+       struct snd_soc_tplg_hdr header;
+       struct snd_soc_tplg_manifest manifest;
+       struct snd_soc_tplg_hdr pcm_header;
+       struct snd_soc_tplg_pcm pcm;
+} __packed;
+
+static struct tplg_tmpl_002 tplg_tmpl_with_pcm = {
+       .header = {
+               .magic = cpu_to_le32(SND_SOC_TPLG_MAGIC),
+               .abi = cpu_to_le32(5),
+               .version = 0,
+               .type = cpu_to_le32(SND_SOC_TPLG_TYPE_MANIFEST),
+               .size = cpu_to_le32(sizeof(struct snd_soc_tplg_hdr)),
+               .vendor_type = 0,
+               .payload_size = cpu_to_le32(sizeof(struct snd_soc_tplg_manifest)),
+               .index = 0,
+               .count = cpu_to_le32(1),
+       },
+       .manifest = {
+               .size = cpu_to_le32(sizeof(struct snd_soc_tplg_manifest)),
+               .pcm_elems = cpu_to_le32(1),
+               /* rest of fields is 0 */
+       },
+       .pcm_header = {
+               .magic = cpu_to_le32(SND_SOC_TPLG_MAGIC),
+               .abi = cpu_to_le32(5),
+               .version = 0,
+               .type = cpu_to_le32(SND_SOC_TPLG_TYPE_PCM),
+               .size = cpu_to_le32(sizeof(struct snd_soc_tplg_hdr)),
+               .vendor_type = 0,
+               .payload_size = cpu_to_le32(sizeof(struct snd_soc_tplg_pcm)),
+               .index = 0,
+               .count = cpu_to_le32(1),
+       },
+       .pcm = {
+               .size = cpu_to_le32(sizeof(struct snd_soc_tplg_pcm)),
+               .pcm_name = "KUNIT Audio",
+               .dai_name = "kunit-audio-dai",
+               .pcm_id = 0,
+               .dai_id = 0,
+               .playback = cpu_to_le32(1),
+               .capture = cpu_to_le32(1),
+               .compress = 0,
+               .stream = {
+                       [0] = {
+                               .channels = cpu_to_le32(2),
+                       },
+                       [1] = {
+                               .channels = cpu_to_le32(2),
+                       },
+               },
+               .num_streams = 0,
+               .caps = {
+                       [0] = {
+                               .name = "kunit-audio-playback",
+                               .channels_min = cpu_to_le32(2),
+                               .channels_max = cpu_to_le32(2),
+                       },
+                       [1] = {
+                               .name = "kunit-audio-capture",
+                               .channels_min = cpu_to_le32(2),
+                               .channels_max = cpu_to_le32(2),
+                       },
+               },
+               .flag_mask = 0,
+               .flags = 0,
+               .priv = { 0 },
+       },
+};
+
+/* ===== TEST CASES ========================================================= */
+
+// TEST CASE
+// Test passing NULL component as parameter to snd_soc_tplg_component_load
+
+/*
+ * need to override generic probe function with one using NULL when calling
+ * topology load during component initialization, we don't need .remove
+ * handler as load should fail
+ */
+static int d_probe_null_comp(struct snd_soc_component *component)
+{
+       struct kunit_soc_component *kunit_comp =
+                       container_of(component, struct kunit_soc_component, comp);
+       int ret;
+
+       /* instead of passing component pointer as first argument, pass NULL here */
+       ret = snd_soc_tplg_component_load(NULL, NULL, &kunit_comp->fw);
+       KUNIT_EXPECT_EQ_MSG(kunit_comp->kunit, kunit_comp->expect, ret,
+                           "Failed topology load");
+
+       return 0;
+}
+
+static const struct snd_soc_component_driver test_component_null_comp = {
+       .name = "sound-soc-topology-test",
+       .probe = d_probe_null_comp,
+       .non_legacy_dai_naming = 1,
+};
+
+static void snd_soc_tplg_test_load_with_null_comp(struct kunit *test)
+{
+       struct kunit_soc_component *kunit_comp;
+       int ret;
+
+       /* prepare */
+       kunit_comp = kunit_kzalloc(test, sizeof(*kunit_comp), GFP_KERNEL);
+       KUNIT_EXPECT_NOT_ERR_OR_NULL(test, kunit_comp);
+       kunit_comp->kunit = test;
+       kunit_comp->expect = -EINVAL; /* expect failure */
+
+       kunit_comp->card.dev = test_dev,
+       kunit_comp->card.name = "kunit-card",
+       kunit_comp->card.owner = THIS_MODULE,
+       kunit_comp->card.dai_link = kunit_dai_links,
+       kunit_comp->card.num_links = ARRAY_SIZE(kunit_dai_links),
+       kunit_comp->card.fully_routed = true,
+
+       /* run test */
+       ret = snd_soc_register_card(&kunit_comp->card);
+       if (ret != 0 && ret != -EPROBE_DEFER)
+               KUNIT_FAIL(test, "Failed to register card");
+
+       ret = snd_soc_component_initialize(&kunit_comp->comp, &test_component_null_comp, test_dev);
+       KUNIT_EXPECT_EQ(test, 0, ret);
+
+       ret = snd_soc_add_component(&kunit_comp->comp, NULL, 0);
+       KUNIT_EXPECT_EQ(test, 0, ret);
+
+       /* cleanup */
+       ret = snd_soc_unregister_card(&kunit_comp->card);
+       KUNIT_EXPECT_EQ(test, 0, ret);
+
+       snd_soc_unregister_component(test_dev);
+}
+
+// TEST CASE
+// Test passing NULL ops as parameter to snd_soc_tplg_component_load
+
+/*
+ * NULL ops is default case, we pass empty topology (fw), so we don't have
+ * anything to parse and just do nothing, which results in return 0; from
+ * calling soc_tplg_dapm_complete in soc_tplg_process_headers
+ */
+static void snd_soc_tplg_test_load_with_null_ops(struct kunit *test)
+{
+       struct kunit_soc_component *kunit_comp;
+       int ret;
+
+       /* prepare */
+       kunit_comp = kunit_kzalloc(test, sizeof(*kunit_comp), GFP_KERNEL);
+       KUNIT_EXPECT_NOT_ERR_OR_NULL(test, kunit_comp);
+       kunit_comp->kunit = test;
+       kunit_comp->expect = 0; /* expect success */
+
+       kunit_comp->card.dev = test_dev,
+       kunit_comp->card.name = "kunit-card",
+       kunit_comp->card.owner = THIS_MODULE,
+       kunit_comp->card.dai_link = kunit_dai_links,
+       kunit_comp->card.num_links = ARRAY_SIZE(kunit_dai_links),
+       kunit_comp->card.fully_routed = true,
+
+       /* run test */
+       ret = snd_soc_register_card(&kunit_comp->card);
+       if (ret != 0 && ret != -EPROBE_DEFER)
+               KUNIT_FAIL(test, "Failed to register card");
+
+       ret = snd_soc_component_initialize(&kunit_comp->comp, &test_component, test_dev);
+       KUNIT_EXPECT_EQ(test, 0, ret);
+
+       ret = snd_soc_add_component(&kunit_comp->comp, NULL, 0);
+       KUNIT_EXPECT_EQ(test, 0, ret);
+
+       /* cleanup */
+       ret = snd_soc_unregister_card(&kunit_comp->card);
+       KUNIT_EXPECT_EQ(test, 0, ret);
+
+       snd_soc_unregister_component(test_dev);
+}
+
+// TEST CASE
+// Test passing NULL fw as parameter to snd_soc_tplg_component_load
+
+/*
+ * need to override generic probe function with one using NULL pointer to fw
+ * when calling topology load during component initialization, we don't need
+ * .remove handler as load should fail
+ */
+static int d_probe_null_fw(struct snd_soc_component *component)
+{
+       struct kunit_soc_component *kunit_comp =
+                       container_of(component, struct kunit_soc_component, comp);
+       int ret;
+
+       /* instead of passing fw pointer as third argument, pass NULL here */
+       ret = snd_soc_tplg_component_load(component, NULL, NULL);
+       KUNIT_EXPECT_EQ_MSG(kunit_comp->kunit, kunit_comp->expect, ret,
+                           "Failed topology load");
+
+       return 0;
+}
+
+static const struct snd_soc_component_driver test_component_null_fw = {
+       .name = "sound-soc-topology-test",
+       .probe = d_probe_null_fw,
+       .non_legacy_dai_naming = 1,
+};
+
+static void snd_soc_tplg_test_load_with_null_fw(struct kunit *test)
+{
+       struct kunit_soc_component *kunit_comp;
+       int ret;
+
+       /* prepare */
+       kunit_comp = kunit_kzalloc(test, sizeof(*kunit_comp), GFP_KERNEL);
+       KUNIT_EXPECT_NOT_ERR_OR_NULL(test, kunit_comp);
+       kunit_comp->kunit = test;
+       kunit_comp->expect = -EINVAL; /* expect failure */
+
+       kunit_comp->card.dev = test_dev,
+       kunit_comp->card.name = "kunit-card",
+       kunit_comp->card.owner = THIS_MODULE,
+       kunit_comp->card.dai_link = kunit_dai_links,
+       kunit_comp->card.num_links = ARRAY_SIZE(kunit_dai_links),
+       kunit_comp->card.fully_routed = true,
+
+       /* run test */
+       ret = snd_soc_register_card(&kunit_comp->card);
+       if (ret != 0 && ret != -EPROBE_DEFER)
+               KUNIT_FAIL(test, "Failed to register card");
+
+       ret = snd_soc_component_initialize(&kunit_comp->comp, &test_component_null_fw, test_dev);
+       KUNIT_EXPECT_EQ(test, 0, ret);
+
+       ret = snd_soc_add_component(&kunit_comp->comp, NULL, 0);
+       KUNIT_EXPECT_EQ(test, 0, ret);
+
+       /* cleanup */
+       ret = snd_soc_unregister_card(&kunit_comp->card);
+       KUNIT_EXPECT_EQ(test, 0, ret);
+
+       snd_soc_unregister_component(test_dev);
+}
+
+// TEST CASE
+// Test passing "empty" topology file
+static void snd_soc_tplg_test_load_empty_tplg(struct kunit *test)
+{
+       struct kunit_soc_component *kunit_comp;
+       struct tplg_tmpl_001 *data;
+       int size;
+       int ret;
+
+       /* prepare */
+       kunit_comp = kunit_kzalloc(test, sizeof(*kunit_comp), GFP_KERNEL);
+       KUNIT_EXPECT_NOT_ERR_OR_NULL(test, kunit_comp);
+       kunit_comp->kunit = test;
+       kunit_comp->expect = 0; /* expect success */
+
+       size = sizeof(tplg_tmpl_empty);
+       data = kunit_kzalloc(kunit_comp->kunit, size, GFP_KERNEL);
+       KUNIT_EXPECT_NOT_ERR_OR_NULL(kunit_comp->kunit, data);
+
+       memcpy(data, &tplg_tmpl_empty, sizeof(tplg_tmpl_empty));
+
+       kunit_comp->fw.data = (u8 *)data;
+       kunit_comp->fw.size = size;
+
+       kunit_comp->card.dev = test_dev,
+       kunit_comp->card.name = "kunit-card",
+       kunit_comp->card.owner = THIS_MODULE,
+       kunit_comp->card.dai_link = kunit_dai_links,
+       kunit_comp->card.num_links = ARRAY_SIZE(kunit_dai_links),
+       kunit_comp->card.fully_routed = true,
+
+       /* run test */
+       ret = snd_soc_register_card(&kunit_comp->card);
+       if (ret != 0 && ret != -EPROBE_DEFER)
+               KUNIT_FAIL(test, "Failed to register card");
+
+       ret = snd_soc_component_initialize(&kunit_comp->comp, &test_component, test_dev);
+       KUNIT_EXPECT_EQ(test, 0, ret);
+
+       ret = snd_soc_add_component(&kunit_comp->comp, NULL, 0);
+       KUNIT_EXPECT_EQ(test, 0, ret);
+
+       /* cleanup */
+       ret = snd_soc_unregister_card(&kunit_comp->card);
+       KUNIT_EXPECT_EQ(test, 0, ret);
+
+       snd_soc_unregister_component(test_dev);
+}
+
+// TEST CASE
+// Test "empty" topology file, but with bad "magic"
+// In theory we could loop through all possible bad values, but it takes too
+// long, so just use SND_SOC_TPLG_MAGIC + 1
+static void snd_soc_tplg_test_load_empty_tplg_bad_magic(struct kunit *test)
+{
+       struct kunit_soc_component *kunit_comp;
+       struct tplg_tmpl_001 *data;
+       int size;
+       int ret;
+
+       /* prepare */
+       kunit_comp = kunit_kzalloc(test, sizeof(*kunit_comp), GFP_KERNEL);
+       KUNIT_EXPECT_NOT_ERR_OR_NULL(test, kunit_comp);
+       kunit_comp->kunit = test;
+       kunit_comp->expect = -EINVAL; /* expect failure */
+
+       size = sizeof(tplg_tmpl_empty);
+       data = kunit_kzalloc(kunit_comp->kunit, size, GFP_KERNEL);
+       KUNIT_EXPECT_NOT_ERR_OR_NULL(kunit_comp->kunit, data);
+
+       memcpy(data, &tplg_tmpl_empty, sizeof(tplg_tmpl_empty));
+       /*
+        * override abi
+        * any value != magic number is wrong
+        */
+       data->header.magic = cpu_to_le32(SND_SOC_TPLG_MAGIC + 1);
+
+       kunit_comp->fw.data = (u8 *)data;
+       kunit_comp->fw.size = size;
+
+       kunit_comp->card.dev = test_dev,
+       kunit_comp->card.name = "kunit-card",
+       kunit_comp->card.owner = THIS_MODULE,
+       kunit_comp->card.dai_link = kunit_dai_links,
+       kunit_comp->card.num_links = ARRAY_SIZE(kunit_dai_links),
+       kunit_comp->card.fully_routed = true,
+
+       /* run test */
+       ret = snd_soc_register_card(&kunit_comp->card);
+       if (ret != 0 && ret != -EPROBE_DEFER)
+               KUNIT_FAIL(test, "Failed to register card");
+
+       ret = snd_soc_component_initialize(&kunit_comp->comp, &test_component, test_dev);
+       KUNIT_EXPECT_EQ(test, 0, ret);
+
+       ret = snd_soc_add_component(&kunit_comp->comp, NULL, 0);
+       KUNIT_EXPECT_EQ(test, 0, ret);
+
+       /* cleanup */
+       ret = snd_soc_unregister_card(&kunit_comp->card);
+       KUNIT_EXPECT_EQ(test, 0, ret);
+
+       snd_soc_unregister_component(test_dev);
+}
+
+// TEST CASE
+// Test "empty" topology file, but with bad "abi"
+// In theory we could loop through all possible bad values, but it takes too
+// long, so just use SND_SOC_TPLG_ABI_VERSION + 1
+static void snd_soc_tplg_test_load_empty_tplg_bad_abi(struct kunit *test)
+{
+       struct kunit_soc_component *kunit_comp;
+       struct tplg_tmpl_001 *data;
+       int size;
+       int ret;
+
+       /* prepare */
+       kunit_comp = kunit_kzalloc(test, sizeof(*kunit_comp), GFP_KERNEL);
+       KUNIT_EXPECT_NOT_ERR_OR_NULL(test, kunit_comp);
+       kunit_comp->kunit = test;
+       kunit_comp->expect = -EINVAL; /* expect failure */
+
+       size = sizeof(tplg_tmpl_empty);
+       data = kunit_kzalloc(kunit_comp->kunit, size, GFP_KERNEL);
+       KUNIT_EXPECT_NOT_ERR_OR_NULL(kunit_comp->kunit, data);
+
+       memcpy(data, &tplg_tmpl_empty, sizeof(tplg_tmpl_empty));
+       /*
+        * override abi
+        * any value != accepted range is wrong
+        */
+       data->header.abi = cpu_to_le32(SND_SOC_TPLG_ABI_VERSION + 1);
+
+       kunit_comp->fw.data = (u8 *)data;
+       kunit_comp->fw.size = size;
+
+       kunit_comp->card.dev = test_dev,
+       kunit_comp->card.name = "kunit-card",
+       kunit_comp->card.owner = THIS_MODULE,
+       kunit_comp->card.dai_link = kunit_dai_links,
+       kunit_comp->card.num_links = ARRAY_SIZE(kunit_dai_links),
+       kunit_comp->card.fully_routed = true,
+
+       /* run test */
+       ret = snd_soc_register_card(&kunit_comp->card);
+       if (ret != 0 && ret != -EPROBE_DEFER)
+               KUNIT_FAIL(test, "Failed to register card");
+
+       ret = snd_soc_component_initialize(&kunit_comp->comp, &test_component, test_dev);
+       KUNIT_EXPECT_EQ(test, 0, ret);
+
+       ret = snd_soc_add_component(&kunit_comp->comp, NULL, 0);
+       KUNIT_EXPECT_EQ(test, 0, ret);
+
+       /* cleanup */
+       ret = snd_soc_unregister_card(&kunit_comp->card);
+       KUNIT_EXPECT_EQ(test, 0, ret);
+
+       snd_soc_unregister_component(test_dev);
+}
+
+// TEST CASE
+// Test "empty" topology file, but with bad "size"
+// In theory we could loop through all possible bad values, but it takes too
+// long, so just use sizeof(struct snd_soc_tplg_hdr) + 1
+static void snd_soc_tplg_test_load_empty_tplg_bad_size(struct kunit *test)
+{
+       struct kunit_soc_component *kunit_comp;
+       struct tplg_tmpl_001 *data;
+       int size;
+       int ret;
+
+       /* prepare */
+       kunit_comp = kunit_kzalloc(test, sizeof(*kunit_comp), GFP_KERNEL);
+       KUNIT_EXPECT_NOT_ERR_OR_NULL(test, kunit_comp);
+       kunit_comp->kunit = test;
+       kunit_comp->expect = -EINVAL; /* expect failure */
+
+       size = sizeof(tplg_tmpl_empty);
+       data = kunit_kzalloc(kunit_comp->kunit, size, GFP_KERNEL);
+       KUNIT_EXPECT_NOT_ERR_OR_NULL(kunit_comp->kunit, data);
+
+       memcpy(data, &tplg_tmpl_empty, sizeof(tplg_tmpl_empty));
+       /*
+        * override size
+        * any value != struct size is wrong
+        */
+       data->header.size = cpu_to_le32(sizeof(struct snd_soc_tplg_hdr) + 1);
+
+       kunit_comp->fw.data = (u8 *)data;
+       kunit_comp->fw.size = size;
+
+       kunit_comp->card.dev = test_dev,
+       kunit_comp->card.name = "kunit-card",
+       kunit_comp->card.owner = THIS_MODULE,
+       kunit_comp->card.dai_link = kunit_dai_links,
+       kunit_comp->card.num_links = ARRAY_SIZE(kunit_dai_links),
+       kunit_comp->card.fully_routed = true,
+
+       /* run test */
+       ret = snd_soc_register_card(&kunit_comp->card);
+       if (ret != 0 && ret != -EPROBE_DEFER)
+               KUNIT_FAIL(test, "Failed to register card");
+
+       ret = snd_soc_component_initialize(&kunit_comp->comp, &test_component, test_dev);
+       KUNIT_EXPECT_EQ(test, 0, ret);
+
+       ret = snd_soc_add_component(&kunit_comp->comp, NULL, 0);
+       KUNIT_EXPECT_EQ(test, 0, ret);
+
+       /* cleanup */
+       ret = snd_soc_unregister_card(&kunit_comp->card);
+       KUNIT_EXPECT_EQ(test, 0, ret);
+
+       snd_soc_unregister_component(test_dev);
+}
+
+// TEST CASE
+// Test "empty" topology file, but with bad "payload_size"
+// In theory we could loop through all possible bad values, but it takes too
+// long, so just use the known wrong one
+static void snd_soc_tplg_test_load_empty_tplg_bad_payload_size(struct kunit *test)
+{
+       struct kunit_soc_component *kunit_comp;
+       struct tplg_tmpl_001 *data;
+       int size;
+       int ret;
+
+       /* prepare */
+       kunit_comp = kunit_kzalloc(test, sizeof(*kunit_comp), GFP_KERNEL);
+       KUNIT_EXPECT_NOT_ERR_OR_NULL(test, kunit_comp);
+       kunit_comp->kunit = test;
+       kunit_comp->expect = -EINVAL; /* expect failure */
+
+       size = sizeof(tplg_tmpl_empty);
+       data = kunit_kzalloc(kunit_comp->kunit, size, GFP_KERNEL);
+       KUNIT_EXPECT_NOT_ERR_OR_NULL(kunit_comp->kunit, data);
+
+       memcpy(data, &tplg_tmpl_empty, sizeof(tplg_tmpl_empty));
+       /*
+        * override payload size
+        * there is only explicit check for 0, so check with it, other values
+        * are handled by just not reading behind EOF
+        */
+       data->header.payload_size = 0;
+
+       kunit_comp->fw.data = (u8 *)data;
+       kunit_comp->fw.size = size;
+
+       kunit_comp->card.dev = test_dev,
+       kunit_comp->card.name = "kunit-card",
+       kunit_comp->card.owner = THIS_MODULE,
+       kunit_comp->card.dai_link = kunit_dai_links,
+       kunit_comp->card.num_links = ARRAY_SIZE(kunit_dai_links),
+       kunit_comp->card.fully_routed = true,
+
+       /* run test */
+       ret = snd_soc_register_card(&kunit_comp->card);
+       if (ret != 0 && ret != -EPROBE_DEFER)
+               KUNIT_FAIL(test, "Failed to register card");
+
+       ret = snd_soc_component_initialize(&kunit_comp->comp, &test_component, test_dev);
+       KUNIT_EXPECT_EQ(test, 0, ret);
+
+       ret = snd_soc_add_component(&kunit_comp->comp, NULL, 0);
+       KUNIT_EXPECT_EQ(test, 0, ret);
+
+       /* cleanup */
+       snd_soc_unregister_component(test_dev);
+
+       ret = snd_soc_unregister_card(&kunit_comp->card);
+       KUNIT_EXPECT_EQ(test, 0, ret);
+}
+
+// TEST CASE
+// Test passing topology file with PCM definition
+static void snd_soc_tplg_test_load_pcm_tplg(struct kunit *test)
+{
+       struct kunit_soc_component *kunit_comp;
+       u8 *data;
+       int size;
+       int ret;
+
+       /* prepare */
+       kunit_comp = kunit_kzalloc(test, sizeof(*kunit_comp), GFP_KERNEL);
+       KUNIT_EXPECT_NOT_ERR_OR_NULL(test, kunit_comp);
+       kunit_comp->kunit = test;
+       kunit_comp->expect = 0; /* expect success */
+
+       size = sizeof(tplg_tmpl_with_pcm);
+       data = kunit_kzalloc(kunit_comp->kunit, size, GFP_KERNEL);
+       KUNIT_EXPECT_NOT_ERR_OR_NULL(kunit_comp->kunit, data);
+
+       memcpy(data, &tplg_tmpl_with_pcm, sizeof(tplg_tmpl_with_pcm));
+
+       kunit_comp->fw.data = data;
+       kunit_comp->fw.size = size;
+
+       kunit_comp->card.dev = test_dev,
+       kunit_comp->card.name = "kunit-card",
+       kunit_comp->card.owner = THIS_MODULE,
+       kunit_comp->card.dai_link = kunit_dai_links,
+       kunit_comp->card.num_links = ARRAY_SIZE(kunit_dai_links),
+       kunit_comp->card.fully_routed = true,
+
+       /* run test */
+       ret = snd_soc_register_card(&kunit_comp->card);
+       if (ret != 0 && ret != -EPROBE_DEFER)
+               KUNIT_FAIL(test, "Failed to register card");
+
+       ret = snd_soc_component_initialize(&kunit_comp->comp, &test_component, test_dev);
+       KUNIT_EXPECT_EQ(test, 0, ret);
+
+       ret = snd_soc_add_component(&kunit_comp->comp, NULL, 0);
+       KUNIT_EXPECT_EQ(test, 0, ret);
+
+       snd_soc_unregister_component(test_dev);
+
+       /* cleanup */
+       ret = snd_soc_unregister_card(&kunit_comp->card);
+       KUNIT_EXPECT_EQ(test, 0, ret);
+}
+
+// TEST CASE
+// Test passing topology file with PCM definition
+// with component reload
+static void snd_soc_tplg_test_load_pcm_tplg_reload_comp(struct kunit *test)
+{
+       struct kunit_soc_component *kunit_comp;
+       u8 *data;
+       int size;
+       int ret;
+       int i;
+
+       /* prepare */
+       kunit_comp = kunit_kzalloc(test, sizeof(*kunit_comp), GFP_KERNEL);
+       KUNIT_EXPECT_NOT_ERR_OR_NULL(test, kunit_comp);
+       kunit_comp->kunit = test;
+       kunit_comp->expect = 0; /* expect success */
+
+       size = sizeof(tplg_tmpl_with_pcm);
+       data = kunit_kzalloc(kunit_comp->kunit, size, GFP_KERNEL);
+       KUNIT_EXPECT_NOT_ERR_OR_NULL(kunit_comp->kunit, data);
+
+       memcpy(data, &tplg_tmpl_with_pcm, sizeof(tplg_tmpl_with_pcm));
+
+       kunit_comp->fw.data = data;
+       kunit_comp->fw.size = size;
+
+       kunit_comp->card.dev = test_dev,
+       kunit_comp->card.name = "kunit-card",
+       kunit_comp->card.owner = THIS_MODULE,
+       kunit_comp->card.dai_link = kunit_dai_links,
+       kunit_comp->card.num_links = ARRAY_SIZE(kunit_dai_links),
+       kunit_comp->card.fully_routed = true,
+
+       /* run test */
+       ret = snd_soc_register_card(&kunit_comp->card);
+       if (ret != 0 && ret != -EPROBE_DEFER)
+               KUNIT_FAIL(test, "Failed to register card");
+
+       for (i = 0; i < 100; i++) {
+               ret = snd_soc_component_initialize(&kunit_comp->comp, &test_component, test_dev);
+               KUNIT_EXPECT_EQ(test, 0, ret);
+
+               ret = snd_soc_add_component(&kunit_comp->comp, NULL, 0);
+               KUNIT_EXPECT_EQ(test, 0, ret);
+
+               snd_soc_unregister_component(test_dev);
+       }
+
+       /* cleanup */
+       ret = snd_soc_unregister_card(&kunit_comp->card);
+       KUNIT_EXPECT_EQ(test, 0, ret);
+}
+
+// TEST CASE
+// Test passing topology file with PCM definition
+// with card reload
+static void snd_soc_tplg_test_load_pcm_tplg_reload_card(struct kunit *test)
+{
+       struct kunit_soc_component *kunit_comp;
+       u8 *data;
+       int size;
+       int ret;
+       int i;
+
+       /* prepare */
+       kunit_comp = kunit_kzalloc(test, sizeof(*kunit_comp), GFP_KERNEL);
+       KUNIT_EXPECT_NOT_ERR_OR_NULL(test, kunit_comp);
+       kunit_comp->kunit = test;
+       kunit_comp->expect = 0; /* expect success */
+
+       size = sizeof(tplg_tmpl_with_pcm);
+       data = kunit_kzalloc(kunit_comp->kunit, size, GFP_KERNEL);
+       KUNIT_EXPECT_NOT_ERR_OR_NULL(kunit_comp->kunit, data);
+
+       memcpy(data, &tplg_tmpl_with_pcm, sizeof(tplg_tmpl_with_pcm));
+
+       kunit_comp->fw.data = data;
+       kunit_comp->fw.size = size;
+
+       kunit_comp->card.dev = test_dev,
+       kunit_comp->card.name = "kunit-card",
+       kunit_comp->card.owner = THIS_MODULE,
+       kunit_comp->card.dai_link = kunit_dai_links,
+       kunit_comp->card.num_links = ARRAY_SIZE(kunit_dai_links),
+       kunit_comp->card.fully_routed = true,
+
+       /* run test */
+       ret = snd_soc_component_initialize(&kunit_comp->comp, &test_component, test_dev);
+       KUNIT_EXPECT_EQ(test, 0, ret);
+
+       ret = snd_soc_add_component(&kunit_comp->comp, NULL, 0);
+       KUNIT_EXPECT_EQ(test, 0, ret);
+
+       for (i = 0; i < 100; i++) {
+               ret = snd_soc_register_card(&kunit_comp->card);
+               if (ret != 0 && ret != -EPROBE_DEFER)
+                       KUNIT_FAIL(test, "Failed to register card");
+
+               ret = snd_soc_unregister_card(&kunit_comp->card);
+               KUNIT_EXPECT_EQ(test, 0, ret);
+       }
+
+       /* cleanup */
+       snd_soc_unregister_component(test_dev);
+}
+
+/* ===== KUNIT MODULE DEFINITIONS =========================================== */
+
+static struct kunit_case snd_soc_tplg_test_cases[] = {
+       KUNIT_CASE(snd_soc_tplg_test_load_with_null_comp),
+       KUNIT_CASE(snd_soc_tplg_test_load_with_null_ops),
+       KUNIT_CASE(snd_soc_tplg_test_load_with_null_fw),
+       KUNIT_CASE(snd_soc_tplg_test_load_empty_tplg),
+       KUNIT_CASE(snd_soc_tplg_test_load_empty_tplg_bad_magic),
+       KUNIT_CASE(snd_soc_tplg_test_load_empty_tplg_bad_abi),
+       KUNIT_CASE(snd_soc_tplg_test_load_empty_tplg_bad_size),
+       KUNIT_CASE(snd_soc_tplg_test_load_empty_tplg_bad_payload_size),
+       KUNIT_CASE(snd_soc_tplg_test_load_pcm_tplg),
+       KUNIT_CASE(snd_soc_tplg_test_load_pcm_tplg_reload_comp),
+       KUNIT_CASE(snd_soc_tplg_test_load_pcm_tplg_reload_card),
+       {}
+};
+
+static struct kunit_suite snd_soc_tplg_test_suite = {
+       .name = "snd_soc_tplg_test",
+       .init = snd_soc_tplg_test_init,
+       .exit = snd_soc_tplg_test_exit,
+       .test_cases = snd_soc_tplg_test_cases,
+};
+
+kunit_test_suites(&snd_soc_tplg_test_suite);
+
+MODULE_LICENSE("GPL");
index 22e7b4c..1b0cd33 100644 (file)
@@ -1672,7 +1672,7 @@ static void set_dai_flags(struct snd_soc_dai_driver *dai_drv,
                          unsigned int flag_mask, unsigned int flags)
 {
        if (flag_mask & SND_SOC_TPLG_DAI_FLGBIT_SYMMETRIC_RATES)
-               dai_drv->symmetric_rates =
+               dai_drv->symmetric_rate =
                        flags & SND_SOC_TPLG_DAI_FLGBIT_SYMMETRIC_RATES ? 1 : 0;
 
        if (flag_mask & SND_SOC_TPLG_DAI_FLGBIT_SYMMETRIC_CHANNELS)
@@ -1681,7 +1681,7 @@ static void set_dai_flags(struct snd_soc_dai_driver *dai_drv,
                        1 : 0;
 
        if (flag_mask & SND_SOC_TPLG_DAI_FLGBIT_SYMMETRIC_SAMPLEBITS)
-               dai_drv->symmetric_samplebits =
+               dai_drv->symmetric_sample_bits =
                        flags & SND_SOC_TPLG_DAI_FLGBIT_SYMMETRIC_SAMPLEBITS ?
                        1 : 0;
 }
@@ -1764,7 +1764,7 @@ static void set_link_flags(struct snd_soc_dai_link *link,
                unsigned int flag_mask, unsigned int flags)
 {
        if (flag_mask & SND_SOC_TPLG_LNK_FLGBIT_SYMMETRIC_RATES)
-               link->symmetric_rates =
+               link->symmetric_rate =
                        flags & SND_SOC_TPLG_LNK_FLGBIT_SYMMETRIC_RATES ? 1 : 0;
 
        if (flag_mask & SND_SOC_TPLG_LNK_FLGBIT_SYMMETRIC_CHANNELS)
@@ -1773,7 +1773,7 @@ static void set_link_flags(struct snd_soc_dai_link *link,
                        1 : 0;
 
        if (flag_mask & SND_SOC_TPLG_LNK_FLGBIT_SYMMETRIC_SAMPLEBITS)
-               link->symmetric_samplebits =
+               link->symmetric_sample_bits =
                        flags & SND_SOC_TPLG_LNK_FLGBIT_SYMMETRIC_SAMPLEBITS ?
                        1 : 0;
 
@@ -2660,8 +2660,14 @@ int snd_soc_tplg_component_load(struct snd_soc_component *comp,
        struct soc_tplg tplg;
        int ret;
 
-       /* component needs to exist to keep and reference data while parsing */
-       if (!comp)
+       /*
+        * check if we have sane parameters:
+        * comp - needs to exist to keep and reference data while parsing
+        * comp->dev - used for resource management and prints
+        * comp->card - used for setting card related parameters
+        * fw - we need it, as it is the very thing we parse
+        */
+       if (!comp || !comp->dev || !comp->card || !fw)
                return -EINVAL;
 
        /* setup parsing context */
@@ -2669,11 +2675,13 @@ int snd_soc_tplg_component_load(struct snd_soc_component *comp,
        tplg.fw = fw;
        tplg.dev = comp->dev;
        tplg.comp = comp;
-       tplg.ops = ops;
-       tplg.io_ops = ops->io_ops;
-       tplg.io_ops_count = ops->io_ops_count;
-       tplg.bytes_ext_ops = ops->bytes_ext_ops;
-       tplg.bytes_ext_ops_count = ops->bytes_ext_ops_count;
+       if (ops) {
+               tplg.ops = ops;
+               tplg.io_ops = ops->io_ops;
+               tplg.io_ops_count = ops->io_ops_count;
+               tplg.bytes_ext_ops = ops->bytes_ext_ops;
+               tplg.bytes_ext_ops_count = ops->bytes_ext_ops_count;
+       }
 
        ret = soc_tplg_load(&tplg);
        /* free the created components if fail to load topology */
index adc7c37..6d8f7d9 100644 (file)
@@ -246,6 +246,8 @@ static int sof_probe_continue(struct snd_sof_dev *sdev)
        if (plat_data->sof_probe_complete)
                plat_data->sof_probe_complete(sdev->dev);
 
+       sdev->probe_completed = true;
+
        return 0;
 
 fw_trace_err:
@@ -316,6 +318,7 @@ int snd_sof_device_probe(struct device *dev, struct snd_sof_pdata *plat_data)
        INIT_LIST_HEAD(&sdev->route_list);
        spin_lock_init(&sdev->ipc_lock);
        spin_lock_init(&sdev->hw_lock);
+       mutex_init(&sdev->power_state_access);
 
        if (IS_ENABLED(CONFIG_SND_SOC_SOF_PROBE_WORK_QUEUE))
                INIT_WORK(&sdev->probe_work, sof_probe_work);
@@ -339,6 +342,14 @@ int snd_sof_device_probe(struct device *dev, struct snd_sof_pdata *plat_data)
 }
 EXPORT_SYMBOL(snd_sof_device_probe);
 
+bool snd_sof_device_probe_completed(struct device *dev)
+{
+       struct snd_sof_dev *sdev = dev_get_drvdata(dev);
+
+       return sdev->probe_completed;
+}
+EXPORT_SYMBOL(snd_sof_device_probe_completed);
+
 int snd_sof_device_remove(struct device *dev)
 {
        struct snd_sof_dev *sdev = dev_get_drvdata(dev);
@@ -384,6 +395,14 @@ int snd_sof_device_remove(struct device *dev)
 }
 EXPORT_SYMBOL(snd_sof_device_remove);
 
+int snd_sof_device_shutdown(struct device *dev)
+{
+       struct snd_sof_dev *sdev = dev_get_drvdata(dev);
+
+       return snd_sof_shutdown(sdev);
+}
+EXPORT_SYMBOL(snd_sof_device_shutdown);
+
 MODULE_AUTHOR("Liam Girdwood");
 MODULE_DESCRIPTION("Sound Open Firmware (SOF) Core");
 MODULE_LICENSE("Dual BSD/GPL");
index 30213a1..715a374 100644 (file)
@@ -352,7 +352,7 @@ static ssize_t sof_dfsentry_write(struct file *file, const char __user *buffer,
        char *string;
        int ret;
 
-       string = kzalloc(count, GFP_KERNEL);
+       string = kzalloc(count+1, GFP_KERNEL);
        if (!string)
                return -ENOMEM;
 
index 53c0803..fe2f3f7 100644 (file)
@@ -25,7 +25,7 @@ int hda_probe_compr_assign(struct snd_sof_dev *sdev,
 {
        struct hdac_ext_stream *stream;
 
-       stream = hda_dsp_stream_get(sdev, cstream->direction);
+       stream = hda_dsp_stream_get(sdev, cstream->direction, 0);
        if (!stream)
                return -EBUSY;
 
@@ -82,7 +82,7 @@ int hda_probe_compr_set_params(struct snd_sof_dev *sdev,
 
        ret = hda_dsp_stream_hw_params(sdev, stream, dmab, NULL);
        if (ret < 0) {
-               dev_err(sdev->dev, "error: hdac prepare failed: %x\n", ret);
+               dev_err(sdev->dev, "error: hdac prepare failed: %d\n", ret);
                return ret;
        }
 
index 1c5e05b..5788fe3 100644 (file)
@@ -624,7 +624,7 @@ static int hda_suspend(struct snd_sof_dev *sdev, bool runtime_suspend)
 #endif
 
        /* power down DSP */
-       ret = hda_dsp_core_reset_power_down(sdev, chip->host_managed_cores_mask);
+       ret = snd_sof_dsp_core_power_down(sdev, chip->host_managed_cores_mask);
        if (ret < 0) {
                dev_err(sdev->dev,
                        "error: failed to power down core during suspend\n");
@@ -732,7 +732,7 @@ int hda_dsp_resume(struct snd_sof_dev *sdev)
                                ret = snd_hdac_ext_bus_link_power_up(hlink);
                                if (ret < 0) {
                                        dev_dbg(sdev->dev,
-                                               "error %x in %s: failed to power up links",
+                                               "error %d in %s: failed to power up links",
                                                ret, __func__);
                                        return ret;
                                }
@@ -802,11 +802,15 @@ int hda_dsp_runtime_idle(struct snd_sof_dev *sdev)
 
 int hda_dsp_runtime_suspend(struct snd_sof_dev *sdev)
 {
+       struct sof_intel_hda_dev *hda = sdev->pdata->hw_pdata;
        const struct sof_dsp_power_state target_state = {
                .state = SOF_DSP_PM_D3,
        };
        int ret;
 
+       /* cancel any attempt for DSP D0I3 */
+       cancel_delayed_work_sync(&hda->d0i3_work);
+
        /* stop hda controller and power dsp off */
        ret = hda_suspend(sdev, true);
        if (ret < 0)
@@ -930,19 +934,15 @@ void hda_dsp_d0i3_work(struct work_struct *work)
                                                      d0i3_work.work);
        struct hdac_bus *bus = &hdev->hbus.core;
        struct snd_sof_dev *sdev = dev_get_drvdata(bus->dev);
-       struct sof_dsp_power_state target_state;
+       struct sof_dsp_power_state target_state = {
+               .state = SOF_DSP_PM_D0,
+               .substate = SOF_HDA_DSP_PM_D0I3,
+       };
        int ret;
 
-       target_state.state = SOF_DSP_PM_D0;
-
        /* DSP can enter D0I3 iff only D0I3-compatible streams are active */
-       if (snd_sof_dsp_only_d0i3_compatible_stream_active(sdev))
-               target_state.substate = SOF_HDA_DSP_PM_D0I3;
-       else
-               target_state.substate = SOF_HDA_DSP_PM_D0I0;
-
-       /* remain in D0I0 */
-       if (target_state.substate == SOF_HDA_DSP_PM_D0I0)
+       if (!snd_sof_dsp_only_d0i3_compatible_stream_active(sdev))
+               /* remain in D0I0 */
                return;
 
        /* This can fail but error cannot be propagated */
index ed77369..fc25ee8 100644 (file)
@@ -35,7 +35,7 @@ static struct hdac_ext_stream *cl_stream_prepare(struct snd_sof_dev *sdev, unsig
        struct pci_dev *pci = to_pci_dev(sdev->dev);
        int ret;
 
-       dsp_stream = hda_dsp_stream_get(sdev, direction);
+       dsp_stream = hda_dsp_stream_get(sdev, direction, 0);
 
        if (!dsp_stream) {
                dev_err(sdev->dev, "error: no stream available\n");
@@ -47,7 +47,7 @@ static struct hdac_ext_stream *cl_stream_prepare(struct snd_sof_dev *sdev, unsig
        /* allocate DMA buffer */
        ret = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV_SG, &pci->dev, size, dmab);
        if (ret < 0) {
-               dev_err(sdev->dev, "error: memory alloc failed: %x\n", ret);
+               dev_err(sdev->dev, "error: memory alloc failed: %d\n", ret);
                goto error;
        }
 
@@ -58,13 +58,13 @@ static struct hdac_ext_stream *cl_stream_prepare(struct snd_sof_dev *sdev, unsig
        if (direction == SNDRV_PCM_STREAM_CAPTURE) {
                ret = hda_dsp_iccmax_stream_hw_params(sdev, dsp_stream, dmab, NULL);
                if (ret < 0) {
-                       dev_err(sdev->dev, "error: iccmax stream prepare failed: %x\n", ret);
+                       dev_err(sdev->dev, "error: iccmax stream prepare failed: %d\n", ret);
                        goto error;
                }
        } else {
                ret = hda_dsp_stream_hw_params(sdev, dsp_stream, dmab, NULL);
                if (ret < 0) {
-                       dev_err(sdev->dev, "error: hdac prepare failed: %x\n", ret);
+                       dev_err(sdev->dev, "error: hdac prepare failed: %d\n", ret);
                        goto error;
                }
                hda_dsp_stream_spib_config(sdev, dsp_stream, HDA_DSP_SPIB_ENABLE, size);
@@ -93,7 +93,7 @@ static int cl_dsp_init(struct snd_sof_dev *sdev, int stream_tag)
        int i;
 
        /* step 1: power up corex */
-       ret = hda_dsp_core_power_up(sdev, chip->host_managed_cores_mask);
+       ret = snd_sof_dsp_core_power_up(sdev, chip->host_managed_cores_mask);
        if (ret < 0) {
                if (hda->boot_iteration == HDA_FW_BOOT_ATTEMPTS)
                        dev_err(sdev->dev, "error: dsp core 0/1 power up failed\n");
@@ -147,8 +147,9 @@ static int cl_dsp_init(struct snd_sof_dev *sdev, int stream_tag)
                                       chip->ipc_ack_mask,
                                       chip->ipc_ack_mask);
 
-       /* step 5: power down corex */
-       ret = hda_dsp_core_power_down(sdev, chip->host_managed_cores_mask & ~(BIT(0)));
+       /* step 5: power down cores that are no longer needed */
+       ret = snd_sof_dsp_core_power_down(sdev, chip->host_managed_cores_mask &
+                                         ~(chip->init_core_mask));
        if (ret < 0) {
                if (hda->boot_iteration == HDA_FW_BOOT_ATTEMPTS)
                        dev_err(sdev->dev,
@@ -183,7 +184,7 @@ err:
                flags |= SOF_DBG_DUMP_FORCE_ERR_LEVEL;
 
        hda_dsp_dump(sdev, flags);
-       hda_dsp_core_reset_power_down(sdev, chip->host_managed_cores_mask);
+       snd_sof_dsp_core_power_down(sdev, chip->host_managed_cores_mask);
 
        return ret;
 }
index 5d35bb1..df00db8 100644 (file)
@@ -111,7 +111,7 @@ int hda_dsp_pcm_hw_params(struct snd_sof_dev *sdev,
 
        ret = hda_dsp_stream_hw_params(sdev, stream, dmab, params);
        if (ret < 0) {
-               dev_err(sdev->dev, "error: hdac prepare failed: %x\n", ret);
+               dev_err(sdev->dev, "error: hdac prepare failed: %d\n", ret);
                return ret;
        }
 
@@ -215,11 +215,25 @@ found:
 int hda_dsp_pcm_open(struct snd_sof_dev *sdev,
                     struct snd_pcm_substream *substream)
 {
+       struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
+       struct snd_soc_component *scomp = sdev->component;
        struct hdac_ext_stream *dsp_stream;
+       struct snd_sof_pcm *spcm;
        int direction = substream->stream;
+       u32 flags = 0;
+
+       spcm = snd_sof_find_spcm_dai(scomp, rtd);
+       if (!spcm) {
+               dev_err(sdev->dev, "error: can't find PCM with DAI ID %d\n", rtd->dai_link->id);
+               return -EINVAL;
+       }
 
-       dsp_stream = hda_dsp_stream_get(sdev, direction);
+       /* All playback and D0i3 compatible streams are DMI L1 capable */
+       if (direction == SNDRV_PCM_STREAM_PLAYBACK ||
+           spcm->stream[substream->stream].d0i3_compatible)
+               flags |= SOF_HDA_STREAM_DMI_L1_COMPATIBLE;
 
+       dsp_stream = hda_dsp_stream_get(sdev, direction, flags);
        if (!dsp_stream) {
                dev_err(sdev->dev, "error: no stream available\n");
                return -ENODEV;
index 0e09ede..40a3993 100644 (file)
@@ -155,7 +155,7 @@ int hda_dsp_stream_spib_config(struct snd_sof_dev *sdev,
 
 /* get next unused stream */
 struct hdac_ext_stream *
-hda_dsp_stream_get(struct snd_sof_dev *sdev, int direction)
+hda_dsp_stream_get(struct snd_sof_dev *sdev, int direction, u32 flags)
 {
        struct hdac_bus *bus = sof_to_bus(sdev);
        struct sof_intel_hda_stream *hda_stream;
@@ -183,18 +183,22 @@ hda_dsp_stream_get(struct snd_sof_dev *sdev, int direction)
        spin_unlock_irq(&bus->reg_lock);
 
        /* stream found ? */
-       if (!stream)
+       if (!stream) {
                dev_err(sdev->dev, "error: no free %s streams\n",
                        direction == SNDRV_PCM_STREAM_PLAYBACK ?
                        "playback" : "capture");
+               return stream;
+       }
+
+       hda_stream->flags = flags;
 
        /*
-        * Disable DMI Link L1 entry when capture stream is opened.
+        * Prevent DMI Link L1 entry for streams that don't support it.
         * Workaround to address a known issue with host DMA that results
         * in xruns during pause/release in capture scenarios.
         */
        if (!IS_ENABLED(CONFIG_SND_SOC_SOF_HDA_ALWAYS_ENABLE_DMI_L1))
-               if (stream && direction == SNDRV_PCM_STREAM_CAPTURE)
+               if (stream && !(flags & SOF_HDA_STREAM_DMI_L1_COMPATIBLE))
                        snd_sof_dsp_update_bits(sdev, HDA_DSP_HDA_BAR,
                                                HDA_VS_INTEL_EM2,
                                                HDA_VS_INTEL_EM2_L1SEN, 0);
@@ -206,37 +210,39 @@ hda_dsp_stream_get(struct snd_sof_dev *sdev, int direction)
 int hda_dsp_stream_put(struct snd_sof_dev *sdev, int direction, int stream_tag)
 {
        struct hdac_bus *bus = sof_to_bus(sdev);
+       struct sof_intel_hda_stream *hda_stream;
+       struct hdac_ext_stream *stream;
        struct hdac_stream *s;
-       bool active_capture_stream = false;
+       bool dmi_l1_enable = true;
        bool found = false;
 
        spin_lock_irq(&bus->reg_lock);
 
        /*
-        * close stream matching the stream tag
-        * and check if there are any open capture streams.
+        * close stream matching the stream tag and check if there are any open streams
+        * that are DMI L1 incompatible.
         */
        list_for_each_entry(s, &bus->stream_list, list) {
+               stream = stream_to_hdac_ext_stream(s);
+               hda_stream = container_of(stream, struct sof_intel_hda_stream, hda_stream);
+
                if (!s->opened)
                        continue;
 
                if (s->direction == direction && s->stream_tag == stream_tag) {
                        s->opened = false;
                        found = true;
-               } else if (s->direction == SNDRV_PCM_STREAM_CAPTURE) {
-                       active_capture_stream = true;
+               } else if (!(hda_stream->flags & SOF_HDA_STREAM_DMI_L1_COMPATIBLE)) {
+                       dmi_l1_enable = false;
                }
        }
 
        spin_unlock_irq(&bus->reg_lock);
 
-       /* Enable DMI L1 entry if there are no capture streams open */
-       if (!IS_ENABLED(CONFIG_SND_SOC_SOF_HDA_ALWAYS_ENABLE_DMI_L1))
-               if (!active_capture_stream)
-                       snd_sof_dsp_update_bits(sdev, HDA_DSP_HDA_BAR,
-                                               HDA_VS_INTEL_EM2,
-                                               HDA_VS_INTEL_EM2_L1SEN,
-                                               HDA_VS_INTEL_EM2_L1SEN);
+       /* Enable DMI L1 if permitted */
+       if (!IS_ENABLED(CONFIG_SND_SOC_SOF_HDA_ALWAYS_ENABLE_DMI_L1) && dmi_l1_enable)
+               snd_sof_dsp_update_bits(sdev, HDA_DSP_HDA_BAR, HDA_VS_INTEL_EM2,
+                                       HDA_VS_INTEL_EM2_L1SEN, HDA_VS_INTEL_EM2_L1SEN);
 
        if (!found) {
                dev_dbg(sdev->dev, "stream_tag %d not opened!\n", stream_tag);
index 1eb746d..29e3da3 100644 (file)
@@ -32,7 +32,7 @@ static int hda_dsp_trace_prepare(struct snd_sof_dev *sdev)
 
        ret = hda_dsp_stream_hw_params(sdev, stream, dmab, NULL);
        if (ret < 0)
-               dev_err(sdev->dev, "error: hdac prepare failed: %x\n", ret);
+               dev_err(sdev->dev, "error: hdac prepare failed: %d\n", ret);
 
        return ret;
 }
@@ -42,8 +42,8 @@ int hda_dsp_trace_init(struct snd_sof_dev *sdev, u32 *stream_tag)
        struct sof_intel_hda_dev *hda = sdev->pdata->hw_pdata;
        int ret;
 
-       hda->dtrace_stream = hda_dsp_stream_get(sdev,
-                                               SNDRV_PCM_STREAM_CAPTURE);
+       hda->dtrace_stream = hda_dsp_stream_get(sdev, SNDRV_PCM_STREAM_CAPTURE,
+                                               SOF_HDA_STREAM_DMI_L1_COMPATIBLE);
 
        if (!hda->dtrace_stream) {
                dev_err(sdev->dev,
@@ -59,7 +59,7 @@ int hda_dsp_trace_init(struct snd_sof_dev *sdev, u32 *stream_tag)
         */
        ret = hda_dsp_trace_prepare(sdev);
        if (ret < 0) {
-               dev_err(sdev->dev, "error: hdac trace init failed: %x\n", ret);
+               dev_err(sdev->dev, "error: hdac trace init failed: %d\n", ret);
                hda_dsp_stream_put(sdev, SNDRV_PCM_STREAM_CAPTURE, *stream_tag);
                hda->dtrace_stream = NULL;
                *stream_tag = 0;
index 509a9b2..0dc3a8c 100644 (file)
@@ -285,11 +285,13 @@ static char *hda_model;
 module_param(hda_model, charp, 0444);
 MODULE_PARM_DESC(hda_model, "Use the given HDA board model.");
 
-#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA)
+#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA) || IS_ENABLED(CONFIG_SND_SOC_SOF_INTEL_SOUNDWIRE)
 static int hda_dmic_num = -1;
 module_param_named(dmic_num, hda_dmic_num, int, 0444);
 MODULE_PARM_DESC(dmic_num, "SOF HDA DMIC number");
+#endif
 
+#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA)
 static bool hda_codec_use_common_hdmi = IS_ENABLED(CONFIG_SND_HDA_CODEC_HDMI);
 module_param_named(use_common_hdmi, hda_codec_use_common_hdmi, bool, 0444);
 MODULE_PARM_DESC(use_common_hdmi, "SOF HDA use common HDMI codec driver");
@@ -317,26 +319,6 @@ static const struct hda_dsp_msg_code hda_dsp_rom_msg[] = {
        {HDA_DSP_ROM_NULL_FW_ENTRY,     "error: null FW entry point"},
 };
 
-static void hda_dsp_get_status_skl(struct snd_sof_dev *sdev)
-{
-       u32 status;
-       int i;
-
-       status = snd_sof_dsp_read(sdev, HDA_DSP_BAR,
-                                 HDA_ADSP_FW_STATUS_SKL);
-
-       for (i = 0; i < ARRAY_SIZE(hda_dsp_rom_msg); i++) {
-               if (status == hda_dsp_rom_msg[i].code) {
-                       dev_err(sdev->dev, "%s - code %8.8x\n",
-                               hda_dsp_rom_msg[i].msg, status);
-                       return;
-               }
-       }
-
-       /* not for us, must be generic sof message */
-       dev_dbg(sdev->dev, "unknown ROM status value %8.8x\n", status);
-}
-
 static void hda_dsp_get_status(struct snd_sof_dev *sdev)
 {
        u32 status;
@@ -385,36 +367,6 @@ static void hda_dsp_get_registers(struct snd_sof_dev *sdev,
                       stack_words * sizeof(u32));
 }
 
-void hda_dsp_dump_skl(struct snd_sof_dev *sdev, u32 flags)
-{
-       struct sof_ipc_dsp_oops_xtensa xoops;
-       struct sof_ipc_panic_info panic_info;
-       u32 stack[HDA_DSP_STACK_DUMP_SIZE];
-       u32 status, panic;
-
-       /* try APL specific status message types first */
-       hda_dsp_get_status_skl(sdev);
-
-       /* now try generic SOF status messages */
-       status = snd_sof_dsp_read(sdev, HDA_DSP_BAR,
-                                 HDA_ADSP_ERROR_CODE_SKL);
-
-       /*TODO: Check: there is no define in spec, but it is used in the code*/
-       panic = snd_sof_dsp_read(sdev, HDA_DSP_BAR,
-                                HDA_ADSP_ERROR_CODE_SKL + 0x4);
-
-       if (sdev->fw_state == SOF_FW_BOOT_COMPLETE) {
-               hda_dsp_get_registers(sdev, &xoops, &panic_info, stack,
-                                     HDA_DSP_STACK_DUMP_SIZE);
-               snd_sof_get_status(sdev, status, panic, &xoops, &panic_info,
-                                  stack, HDA_DSP_STACK_DUMP_SIZE);
-       } else {
-               dev_err(sdev->dev, "error: status = 0x%8.8x panic = 0x%8.8x\n",
-                       status, panic);
-               hda_dsp_get_status_skl(sdev);
-       }
-}
-
 /* dump the first 8 dwords representing the extended ROM status */
 static void hda_dsp_dump_ext_rom_status(struct snd_sof_dev *sdev, u32 flags)
 {
@@ -555,7 +507,7 @@ static int hda_init(struct snd_sof_dev *sdev)
        return ret;
 }
 
-#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA)
+#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA) || IS_ENABLED(CONFIG_SND_SOC_SOF_INTEL_SOUNDWIRE)
 
 static int check_nhlt_dmic(struct snd_sof_dev *sdev)
 {
@@ -579,25 +531,76 @@ static const char *fixup_tplg_name(struct snd_sof_dev *sdev,
                                   const char *dmic_str)
 {
        const char *tplg_filename = NULL;
-       char *filename;
-       char *split_ext;
+       char *filename, *tmp;
+       const char *split_ext;
 
-       filename = devm_kstrdup(sdev->dev, sof_tplg_filename, GFP_KERNEL);
+       filename = kstrdup(sof_tplg_filename, GFP_KERNEL);
        if (!filename)
                return NULL;
 
        /* this assumes a .tplg extension */
-       split_ext = strsep(&filename, ".");
-       if (split_ext) {
+       tmp = filename;
+       split_ext = strsep(&tmp, ".");
+       if (split_ext)
                tplg_filename = devm_kasprintf(sdev->dev, GFP_KERNEL,
                                               "%s%s%s.tplg",
                                               split_ext, idisp_str, dmic_str);
-               if (!tplg_filename)
-                       return NULL;
-       }
+       kfree(filename);
+
        return tplg_filename;
 }
 
+static int dmic_topology_fixup(struct snd_sof_dev *sdev,
+                              const char **tplg_filename,
+                              const char *idisp_str,
+                              int *dmic_found)
+{
+       const char *default_tplg_filename = *tplg_filename;
+       const char *fixed_tplg_filename;
+       const char *dmic_str;
+       int dmic_num;
+
+       /* first check NHLT for DMICs */
+       dmic_num = check_nhlt_dmic(sdev);
+
+       /* allow for module parameter override */
+       if (hda_dmic_num != -1) {
+               dev_dbg(sdev->dev,
+                       "overriding DMICs detected in NHLT tables %d by kernel param %d\n",
+                       dmic_num, hda_dmic_num);
+               dmic_num = hda_dmic_num;
+       }
+
+       switch (dmic_num) {
+       case 1:
+               dmic_str = "-1ch";
+               break;
+       case 2:
+               dmic_str = "-2ch";
+               break;
+       case 3:
+               dmic_str = "-3ch";
+               break;
+       case 4:
+               dmic_str = "-4ch";
+               break;
+       default:
+               dmic_num = 0;
+               dmic_str = "";
+               break;
+       }
+
+       fixed_tplg_filename = fixup_tplg_name(sdev, default_tplg_filename,
+                                             idisp_str, dmic_str);
+       if (!fixed_tplg_filename)
+               return -ENOMEM;
+
+       dev_info(sdev->dev, "DMICs detected in NHLT tables: %d\n", dmic_num);
+       *dmic_found = dmic_num;
+       *tplg_filename = fixed_tplg_filename;
+
+       return 0;
+}
 #endif
 
 static int hda_init_caps(struct snd_sof_dev *sdev)
@@ -809,13 +812,9 @@ int hda_dsp_probe(struct snd_sof_dev *sdev)
        sdev->mailbox_bar = HDA_DSP_BAR;
 
        /* allow 64bit DMA address if supported by H/W */
-       if (!dma_set_mask(&pci->dev, DMA_BIT_MASK(64))) {
-               dev_dbg(sdev->dev, "DMA mask is 64 bit\n");
-               dma_set_coherent_mask(&pci->dev, DMA_BIT_MASK(64));
-       } else {
+       if (dma_set_mask_and_coherent(&pci->dev, DMA_BIT_MASK(64))) {
                dev_dbg(sdev->dev, "DMA mask is 32 bit\n");
-               dma_set_mask(&pci->dev, DMA_BIT_MASK(32));
-               dma_set_coherent_mask(&pci->dev, DMA_BIT_MASK(32));
+               dma_set_mask_and_coherent(&pci->dev, DMA_BIT_MASK(32));
        }
 
        /* init streams */
@@ -932,7 +931,7 @@ int hda_dsp_remove(struct snd_sof_dev *sdev)
 
        /* disable cores */
        if (chip)
-               hda_dsp_core_reset_power_down(sdev, chip->host_managed_cores_mask);
+               snd_sof_dsp_core_power_down(sdev, chip->host_managed_cores_mask);
 
        /* disable DSP */
        snd_sof_dsp_update_bits(sdev, HDA_DSP_PP_BAR, SOF_HDA_REG_PP_PPCTL,
@@ -967,9 +966,9 @@ static int hda_generic_machine_select(struct snd_sof_dev *sdev)
        struct snd_sof_pdata *pdata = sdev->pdata;
        const char *tplg_filename;
        const char *idisp_str;
-       const char *dmic_str;
        int dmic_num = 0;
        int codec_num = 0;
+       int ret;
        int i;
 
        /* codec detection */
@@ -994,10 +993,6 @@ static int hda_generic_machine_select(struct snd_sof_dev *sdev)
                if (!pdata->machine && codec_num <= 2) {
                        hda_mach = snd_soc_acpi_intel_hda_machines;
 
-                       /* topology: use the info from hda_machines */
-                       pdata->tplg_filename =
-                               hda_mach->sof_tplg_filename;
-
                        dev_info(bus->dev, "using HDA machine driver %s now\n",
                                 hda_mach->drv_name);
 
@@ -1006,42 +1001,13 @@ static int hda_generic_machine_select(struct snd_sof_dev *sdev)
                        else
                                idisp_str = "";
 
-                       /* first check NHLT for DMICs */
-                       dmic_num = check_nhlt_dmic(sdev);
-
-                       /* allow for module parameter override */
-                       if (hda_dmic_num != -1)
-                               dmic_num = hda_dmic_num;
-
-                       switch (dmic_num) {
-                       case 1:
-                               dmic_str = "-1ch";
-                               break;
-                       case 2:
-                               dmic_str = "-2ch";
-                               break;
-                       case 3:
-                               dmic_str = "-3ch";
-                               break;
-                       case 4:
-                               dmic_str = "-4ch";
-                               break;
-                       default:
-                               dmic_num = 0;
-                               dmic_str = "";
-                               break;
-                       }
-
-                       tplg_filename = pdata->tplg_filename;
-                       tplg_filename = fixup_tplg_name(sdev, tplg_filename,
-                                                       idisp_str, dmic_str);
-                       if (!tplg_filename)
-                               return -EINVAL;
-
-                       dev_info(bus->dev,
-                                "DMICs detected in NHLT tables: %d\n",
-                                dmic_num);
+                       /* topology: use the info from hda_machines */
+                       tplg_filename = hda_mach->sof_tplg_filename;
+                       ret = dmic_topology_fixup(sdev, &tplg_filename, idisp_str, &dmic_num);
+                       if (ret < 0)
+                               return ret;
 
+                       hda_mach->mach_params.dmic_num = dmic_num;
                        pdata->machine = hda_mach;
                        pdata->tplg_filename = tplg_filename;
                }
@@ -1053,7 +1019,6 @@ static int hda_generic_machine_select(struct snd_sof_dev *sdev)
                        &pdata->machine->mach_params;
                mach_params->codec_mask = bus->codec_mask;
                mach_params->common_hdmi_codec_drv = hda_codec_use_common_hdmi;
-               mach_params->dmic_num = dmic_num;
        }
 
        return 0;
@@ -1075,32 +1040,63 @@ static bool link_slaves_found(struct snd_sof_dev *sdev,
        struct sdw_intel_slave_id *ids = sdw->ids;
        int num_slaves = sdw->num_slaves;
        unsigned int part_id, link_id, unique_id, mfg_id;
-       int i, j;
+       int i, j, k;
 
        for (i = 0; i < link->num_adr; i++) {
                u64 adr = link->adr_d[i].adr;
+               int reported_part_count = 0;
 
                mfg_id = SDW_MFG_ID(adr);
                part_id = SDW_PART_ID(adr);
                link_id = SDW_DISCO_LINK_ID(adr);
+
+               for (j = 0; j < num_slaves; j++) {
+                       /* find out how many identical parts were reported on that link */
+                       if (ids[j].link_id == link_id &&
+                           ids[j].id.part_id == part_id &&
+                           ids[j].id.mfg_id == mfg_id)
+                               reported_part_count++;
+               }
+
                for (j = 0; j < num_slaves; j++) {
+                       int expected_part_count = 0;
+
                        if (ids[j].link_id != link_id ||
                            ids[j].id.part_id != part_id ||
                            ids[j].id.mfg_id != mfg_id)
                                continue;
-                       /*
-                        * we have to check unique id
-                        * if there is more than one
-                        * Slave on the link
-                        */
-                       unique_id = SDW_UNIQUE_ID(adr);
-                       if (link->num_adr == 1 ||
-                           ids[j].id.unique_id == SDW_IGNORED_UNIQUE_ID ||
-                           ids[j].id.unique_id == unique_id) {
-                               dev_dbg(bus->dev,
-                                       "found %x at link %d\n",
-                                       part_id, link_id);
-                               break;
+
+                       /* find out how many identical parts are expected */
+                       for (k = 0; k < link->num_adr; k++) {
+                               u64 adr2 = link->adr_d[i].adr;
+                               unsigned int part_id2, link_id2, mfg_id2;
+
+                               mfg_id2 = SDW_MFG_ID(adr2);
+                               part_id2 = SDW_PART_ID(adr2);
+                               link_id2 = SDW_DISCO_LINK_ID(adr2);
+
+                               if (link_id2 == link_id &&
+                                   part_id2 == part_id &&
+                                   mfg_id2 == mfg_id)
+                                       expected_part_count++;
+                       }
+
+                       if (reported_part_count == expected_part_count) {
+                               /*
+                                * we have to check unique id
+                                * if there is more than one
+                                * Slave on the link
+                                */
+                               unique_id = SDW_UNIQUE_ID(adr);
+                               if (reported_part_count == 1 ||
+                                   ids[j].id.unique_id == unique_id) {
+                                       dev_dbg(bus->dev, "found %x at link %d\n",
+                                               part_id, link_id);
+                                       break;
+                               }
+                       } else {
+                               dev_dbg(bus->dev, "part %x reported %d expected %d on link %d, skipping\n",
+                                       part_id, reported_part_count, expected_part_count, link_id);
                        }
                }
                if (j == num_slaves) {
@@ -1117,7 +1113,6 @@ static int hda_sdw_machine_select(struct snd_sof_dev *sdev)
 {
        struct snd_sof_pdata *pdata = sdev->pdata;
        const struct snd_soc_acpi_link_adr *link;
-       struct hdac_bus *bus = sof_to_bus(sdev);
        struct snd_soc_acpi_mach *mach;
        struct sof_intel_hda_dev *hdev;
        u32 link_mask;
@@ -1165,16 +1160,42 @@ static int hda_sdw_machine_select(struct snd_sof_dev *sdev)
                                break;
                }
                if (mach && mach->link_mask) {
-                       dev_dbg(bus->dev,
-                               "SoundWire machine driver %s topology %s\n",
-                               mach->drv_name,
-                               mach->sof_tplg_filename);
+                       int dmic_num = 0;
+
                        pdata->machine = mach;
                        mach->mach_params.links = mach->links;
                        mach->mach_params.link_mask = mach->link_mask;
                        mach->mach_params.platform = dev_name(sdev->dev);
-                       pdata->fw_filename = mach->sof_fw_filename;
+                       if (mach->sof_fw_filename)
+                               pdata->fw_filename = mach->sof_fw_filename;
+                       else
+                               pdata->fw_filename = pdata->desc->default_fw_filename;
                        pdata->tplg_filename = mach->sof_tplg_filename;
+
+                       /*
+                        * DMICs use up to 4 pins and are typically pin-muxed with SoundWire
+                        * link 2 and 3, thus we only try to enable dmics if all conditions
+                        * are true:
+                        * a) link 2 and 3 are not used by SoundWire
+                        * b) the NHLT table reports the presence of microphones
+                        */
+                       if (!(mach->link_mask & GENMASK(3, 2))) {
+                               const char *tplg_filename = mach->sof_tplg_filename;
+                               int ret;
+
+                               ret = dmic_topology_fixup(sdev, &tplg_filename, "", &dmic_num);
+
+                               if (ret < 0)
+                                       return ret;
+
+                               pdata->tplg_filename = tplg_filename;
+                       }
+                       mach->mach_params.dmic_num = dmic_num;
+
+                       dev_dbg(sdev->dev,
+                               "SoundWire machine driver %s topology %s\n",
+                               mach->drv_name,
+                               pdata->tplg_filename);
                } else {
                        dev_info(sdev->dev,
                                 "No SoundWire machine driver found\n");
index 1d9b38e..d1c38c3 100644 (file)
@@ -403,6 +403,9 @@ struct sof_intel_dsp_bdl {
 #define SOF_HDA_PLAYBACK               0
 #define SOF_HDA_CAPTURE                        1
 
+/* stream flags */
+#define SOF_HDA_STREAM_DMI_L1_COMPATIBLE       1
+
 /*
  * Time in ms for opportunistic D0I3 entry delay.
  * This has been deliberately chosen to be long to avoid race conditions.
@@ -472,6 +475,7 @@ struct sof_intel_hda_stream {
        struct hdac_ext_stream hda_stream;
        struct sof_intel_stream stream;
        int host_reserved; /* reserve host DMA channel */
+       u32 flags;
 };
 
 #define hstream_to_sof_hda_stream(hstream) \
@@ -514,7 +518,6 @@ int hda_dsp_runtime_suspend(struct snd_sof_dev *sdev);
 int hda_dsp_runtime_resume(struct snd_sof_dev *sdev);
 int hda_dsp_runtime_idle(struct snd_sof_dev *sdev);
 int hda_dsp_set_hw_params_upon_resume(struct snd_sof_dev *sdev);
-void hda_dsp_dump_skl(struct snd_sof_dev *sdev, u32 flags);
 void hda_dsp_dump(struct snd_sof_dev *sdev, u32 flags);
 void hda_ipc_dump(struct snd_sof_dev *sdev);
 void hda_ipc_irq_dump(struct snd_sof_dev *sdev);
@@ -563,7 +566,7 @@ bool hda_dsp_check_ipc_irq(struct snd_sof_dev *sdev);
 bool hda_dsp_check_stream_irq(struct snd_sof_dev *sdev);
 
 struct hdac_ext_stream *
-       hda_dsp_stream_get(struct snd_sof_dev *sdev, int direction);
+       hda_dsp_stream_get(struct snd_sof_dev *sdev, int direction, u32 flags);
 int hda_dsp_stream_put(struct snd_sof_dev *sdev, int direction, int stream_tag);
 int hda_dsp_stream_spib_config(struct snd_sof_dev *sdev,
                               struct hdac_ext_stream *stream,
index 2252ca3..419f05b 100644 (file)
@@ -22,9 +22,10 @@ static const struct snd_sof_debugfs_map tgl_dsp_debugfs[] = {
 
 /* Tigerlake ops */
 const struct snd_sof_dsp_ops sof_tgl_ops = {
-       /* probe and remove */
+       /* probe/remove/shutdown */
        .probe          = hda_dsp_probe,
        .remove         = hda_dsp_remove,
+       .shutdown       = hda_dsp_remove,
 
        /* Register IO */
        .write          = sof_io_write,
index fc13bb0..c2d07b7 100644 (file)
@@ -106,6 +106,8 @@ static void ipc_log_header(struct device *dev, u8 *text, u32 cmd)
                        str2 = "CLK_REQ"; break;
                case SOF_IPC_PM_CORE_ENABLE:
                        str2 = "CORE_ENABLE"; break;
+               case SOF_IPC_PM_GATE:
+                       str2 = "GATE"; break;
                default:
                        str2 = "unknown type"; break;
                }
@@ -796,7 +798,7 @@ int snd_sof_ipc_valid(struct snd_sof_dev *sdev)
                return -EINVAL;
        }
 
-       if (v->abi_version > SOF_ABI_VERSION) {
+       if (SOF_ABI_VERSION_MINOR(v->abi_version) > SOF_ABI_MINOR) {
                if (!IS_ENABLED(CONFIG_SND_SOC_SOF_STRICT_ABI_CHECKS)) {
                        dev_warn(sdev->dev, "warn: FW ABI is more recent than kernel\n");
                } else {
index 08a17ab..6efaf76 100644 (file)
@@ -731,6 +731,8 @@ int snd_sof_load_firmware_raw(struct snd_sof_dev *sdev)
        if (ret < 0) {
                dev_err(sdev->dev, "error: request firmware %s failed err: %d\n",
                        fw_filename, ret);
+               dev_err(sdev->dev,
+                       "you may need to download the firmware from https://github.com/thesofproject/sof-bin/\n");
                goto err;
        } else {
                dev_dbg(sdev->dev, "request_firmware %s successful\n",
@@ -811,7 +813,6 @@ EXPORT_SYMBOL(snd_sof_load_firmware);
 int snd_sof_run_firmware(struct snd_sof_dev *sdev)
 {
        int ret;
-       int init_core_mask;
 
        init_waitqueue_head(&sdev->boot_wait);
 
@@ -843,8 +844,6 @@ int snd_sof_run_firmware(struct snd_sof_dev *sdev)
                return ret;
        }
 
-       init_core_mask = ret;
-
        /*
         * now wait for the DSP to boot. There are 3 possible outcomes:
         * 1. Boot wait times out indicating FW boot failure.
@@ -874,9 +873,6 @@ int snd_sof_run_firmware(struct snd_sof_dev *sdev)
                return ret;
        }
 
-       /* fw boot is complete. Update the active cores mask */
-       sdev->enabled_cores_mask = init_core_mask;
-
        return 0;
 }
 EXPORT_SYMBOL(snd_sof_run_firmware);
index 95e748b..5099ad0 100644 (file)
@@ -37,6 +37,14 @@ static inline int snd_sof_remove(struct snd_sof_dev *sdev)
        return 0;
 }
 
+static inline int snd_sof_shutdown(struct snd_sof_dev *sdev)
+{
+       if (sof_ops(sdev)->shutdown)
+               return sof_ops(sdev)->shutdown(sdev);
+
+       return 0;
+}
+
 /* control */
 
 /*
@@ -68,19 +76,31 @@ static inline int snd_sof_dsp_reset(struct snd_sof_dev *sdev)
 static inline int snd_sof_dsp_core_power_up(struct snd_sof_dev *sdev,
                                            unsigned int core_mask)
 {
-       if (sof_ops(sdev)->core_power_up)
-               return sof_ops(sdev)->core_power_up(sdev, core_mask);
+       int ret = 0;
 
-       return 0;
+       core_mask &= ~sdev->enabled_cores_mask;
+       if (sof_ops(sdev)->core_power_up && core_mask) {
+               ret = sof_ops(sdev)->core_power_up(sdev, core_mask);
+               if (!ret)
+                       sdev->enabled_cores_mask |= core_mask;
+       }
+
+       return ret;
 }
 
 static inline int snd_sof_dsp_core_power_down(struct snd_sof_dev *sdev,
                                              unsigned int core_mask)
 {
-       if (sof_ops(sdev)->core_power_down)
-               return sof_ops(sdev)->core_power_down(sdev, core_mask);
+       int ret = 0;
 
-       return 0;
+       core_mask &= sdev->enabled_cores_mask;
+       if (sof_ops(sdev)->core_power_down && core_mask) {
+               ret = sof_ops(sdev)->core_power_down(sdev, core_mask);
+               if (!ret)
+                       sdev->enabled_cores_mask &= ~core_mask;
+       }
+
+       return ret;
 }
 
 /* pre/post fw load */
@@ -208,11 +228,16 @@ static inline int
 snd_sof_dsp_set_power_state(struct snd_sof_dev *sdev,
                            const struct sof_dsp_power_state *target_state)
 {
+       int ret = 0;
+
+       mutex_lock(&sdev->power_state_access);
+
        if (sof_ops(sdev)->set_power_state)
-               return sof_ops(sdev)->set_power_state(sdev, target_state);
+               ret = sof_ops(sdev)->set_power_state(sdev, target_state);
 
-       /* D0 substate is not supported, do nothing here. */
-       return 0;
+       mutex_unlock(&sdev->power_state_access);
+
+       return ret;
 }
 
 /* debug */
index 0dc39fb..61c3fe1 100644 (file)
@@ -707,7 +707,12 @@ int sof_pcm_dai_link_fixup(struct snd_soc_pcm_runtime *rtd, struct snd_pcm_hw_pa
                }
                break;
        case SOF_DAI_INTEL_ALH:
-               /* do nothing for ALH dai_link */
+               /*
+                * Dai could run with different channel count compared with
+                * front end, so get dai channel count from topology
+                */
+               channels->min = dai->dai_config->alh.channels;
+               channels->max = dai->dai_config->alh.channels;
                break;
        case SOF_DAI_IMX_ESAI:
                rate->min = dai->dai_config->esai.fsync_rate;
index c83fb62..fd26580 100644 (file)
@@ -256,7 +256,6 @@ suspend:
 
        /* reset FW state */
        sdev->fw_state = SOF_FW_BOOT_NOT_STARTED;
-       sdev->enabled_cores_mask = 0;
 
        return ret;
 }
index 215711a..fd1f0d8 100644 (file)
@@ -65,6 +65,13 @@ static const struct dmi_system_id community_key_platforms[] = {
                        DMI_MATCH(DMI_BOARD_NAME, "UP-APL01"),
                }
        },
+       {
+               .ident = "Up Extreme",
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "AAEON"),
+                       DMI_MATCH(DMI_BOARD_NAME, "UP-WHL01"),
+               }
+       },
        {
                .ident = "Google Chromebooks",
                .matches = {
@@ -213,7 +220,7 @@ static const struct sof_dev_desc icl_desc = {
 };
 #endif
 
-#if IS_ENABLED(CONFIG_SND_SOC_SOF_TIGERLAKE)
+#if IS_ENABLED(CONFIG_SND_SOC_SOF_TIGERLAKE) || IS_ENABLED(CONFIG_SND_SOC_SOF_ALDERLAKE)
 static const struct sof_dev_desc tgl_desc = {
        .machines               = snd_soc_acpi_intel_tgl_machines,
        .alt_machines           = snd_soc_acpi_intel_tgl_sdw_machines,
@@ -230,7 +237,9 @@ static const struct sof_dev_desc tgl_desc = {
        .nocodec_tplg_filename = "sof-tgl-nocodec.tplg",
        .ops = &sof_tgl_ops,
 };
+#endif
 
+#if IS_ENABLED(CONFIG_SND_SOC_SOF_TIGERLAKE)
 static const struct sof_dev_desc tglh_desc = {
        .machines               = snd_soc_acpi_intel_tgl_machines,
        .alt_machines           = snd_soc_acpi_intel_tgl_sdw_machines,
@@ -445,13 +454,19 @@ static void sof_pci_remove(struct pci_dev *pci)
        snd_sof_device_remove(&pci->dev);
 
        /* follow recommendation in pci-driver.c to increment usage counter */
-       if (!(sof_pci_debug & SOF_PCI_DISABLE_PM_RUNTIME))
+       if (snd_sof_device_probe_completed(&pci->dev) &&
+           !(sof_pci_debug & SOF_PCI_DISABLE_PM_RUNTIME))
                pm_runtime_get_noresume(&pci->dev);
 
        /* release pci regions and disable device */
        pci_release_regions(pci);
 }
 
+static void sof_pci_shutdown(struct pci_dev *pci)
+{
+       snd_sof_device_shutdown(&pci->dev);
+}
+
 /* PCI IDs */
 static const struct pci_device_id sof_pci_ids[] = {
 #if IS_ENABLED(CONFIG_SND_SOC_SOF_MERRIFIELD)
@@ -514,6 +529,8 @@ static const struct pci_device_id sof_pci_ids[] = {
 #if IS_ENABLED(CONFIG_SND_SOC_SOF_ALDERLAKE)
        { PCI_DEVICE(0x8086, 0x7ad0),
                .driver_data = (unsigned long)&adls_desc},
+       { PCI_DEVICE(0x8086, 0x51c8),
+               .driver_data = (unsigned long)&tgl_desc},
 #endif
        { 0, }
 };
@@ -525,6 +542,7 @@ static struct pci_driver snd_sof_pci_driver = {
        .id_table = sof_pci_ids,
        .probe = sof_pci_probe,
        .remove = sof_pci_remove,
+       .shutdown = sof_pci_shutdown,
        .driver = {
                .pm = &sof_pci_pm,
        },
index 68da8f7..ad0d7ba 100644 (file)
@@ -98,9 +98,10 @@ struct snd_sof_pdata;
  */
 struct snd_sof_dsp_ops {
 
-       /* probe and remove */
+       /* probe/remove/shutdown */
        int (*probe)(struct snd_sof_dev *sof_dev); /* mandatory */
        int (*remove)(struct snd_sof_dev *sof_dev); /* optional */
+       int (*shutdown)(struct snd_sof_dev *sof_dev); /* optional */
 
        /* DSP core boot / reset */
        int (*run)(struct snd_sof_dev *sof_dev); /* mandatory */
@@ -375,6 +376,8 @@ struct snd_sof_dev {
 
        /* current DSP power state */
        struct sof_dsp_power_state dsp_power_state;
+       /* mutex to protect the dsp_power_state access */
+       struct mutex power_state_access;
 
        /* Intended power target of system suspend */
        enum sof_system_suspend_state system_suspend_target;
@@ -386,6 +389,7 @@ struct snd_sof_dev {
 
        /* work queue in case the probe is implemented in two steps */
        struct work_struct probe_work;
+       bool probe_completed;
 
        /* DSP HW differentiation */
        struct snd_sof_pdata *pdata;
@@ -460,6 +464,8 @@ struct snd_sof_dev {
 
 int snd_sof_device_probe(struct device *dev, struct snd_sof_pdata *plat_data);
 int snd_sof_device_remove(struct device *dev);
+int snd_sof_device_shutdown(struct device *dev);
+bool snd_sof_device_probe_completed(struct device *dev);
 
 int snd_sof_runtime_suspend(struct device *dev);
 int snd_sof_runtime_resume(struct device *dev);
index b6b32a7..10f9962 100644 (file)
@@ -1073,7 +1073,7 @@ static int sof_control_load_volume(struct snd_soc_component *scomp,
        scontrol->cmd = SOF_CTRL_CMD_VOLUME;
 
        /* extract tlv data */
-       if (get_tlv_data(kc->tlv.p, tlv) < 0) {
+       if (!kc->tlv.p || get_tlv_data(kc->tlv.p, tlv) < 0) {
                dev_err(scomp->dev, "error: invalid TLV data\n");
                ret = -EINVAL;
                goto out_free;
@@ -1352,10 +1352,6 @@ static int sof_core_enable(struct snd_sof_dev *sdev, int core)
                        core, ret);
                goto err;
        }
-
-       /* update enabled cores mask */
-       sdev->enabled_cores_mask |= BIT(core);
-
        return ret;
 err:
        /* power down core if it is host managed and return the original error if this fails too */
@@ -2603,10 +2599,6 @@ static int sof_widget_unload(struct snd_soc_component *scomp,
                if (ret < 0)
                        dev_err(scomp->dev, "error: powering down pipeline schedule core %d\n",
                                pipeline->core);
-
-               /* update enabled cores mask */
-               sdev->enabled_cores_mask &= ~(1 << pipeline->core);
-
                break;
        default:
                break;
@@ -3666,7 +3658,7 @@ static int sof_manifest(struct snd_soc_component *scomp, int index,
                return -EINVAL;
        }
 
-       if (abi_version > SOF_ABI_VERSION) {
+       if (SOF_ABI_VERSION_MINOR(abi_version) > SOF_ABI_MINOR) {
                if (!IS_ENABLED(CONFIG_SND_SOC_SOF_STRICT_ABI_CHECKS)) {
                        dev_warn(scomp->dev, "warn: topology ABI is more recent than kernel\n");
                } else {
@@ -3740,6 +3732,8 @@ int snd_sof_load_topology(struct snd_soc_component *scomp, const char *file)
        if (ret < 0) {
                dev_err(scomp->dev, "error: tplg request firmware %s failed err: %d\n",
                        file, ret);
+               dev_err(scomp->dev,
+                       "you may need to download the firmware from https://github.com/thesofproject/sof-bin/\n");
                return ret;
        }
 
index f439e55..34b2ce7 100644 (file)
@@ -866,23 +866,23 @@ EXPORT_SYMBOL_GPL(sprd_mcdt_chan_dma_disable);
 struct sprd_mcdt_chan *sprd_mcdt_request_chan(u8 channel,
                                              enum sprd_mcdt_channel_type type)
 {
-       struct sprd_mcdt_chan *temp, *chan = NULL;
+       struct sprd_mcdt_chan *temp;
 
        mutex_lock(&sprd_mcdt_list_mutex);
 
        list_for_each_entry(temp, &sprd_mcdt_chan_list, list) {
                if (temp->type == type && temp->id == channel) {
-                       chan = temp;
+                       list_del_init(&temp->list);
                        break;
                }
        }
 
-       if (chan)
-               list_del(&chan->list);
+       if (list_entry_is_head(temp, &sprd_mcdt_chan_list, list))
+               temp = NULL;
 
        mutex_unlock(&sprd_mcdt_list_mutex);
 
-       return chan;
+       return temp;
 }
 EXPORT_SYMBOL_GPL(sprd_mcdt_request_chan);
 
index 7c4d63c..7d1672c 100644 (file)
@@ -8,6 +8,7 @@
 
 #include <linux/bitfield.h>
 #include <linux/clk.h>
+#include <linux/clk-provider.h>
 #include <linux/delay.h>
 #include <linux/module.h>
 #include <linux/of_irq.h>
@@ -196,6 +197,9 @@ enum i2s_datlen {
 #define STM32_I2S_IS_MASTER(x)         ((x)->ms_flg == I2S_MS_MASTER)
 #define STM32_I2S_IS_SLAVE(x)          ((x)->ms_flg == I2S_MS_SLAVE)
 
+#define STM32_I2S_NAME_LEN             32
+#define STM32_I2S_RATE_11K             11025
+
 /**
  * struct stm32_i2s_data - private data of I2S
  * @regmap_conf: I2S register map configuration pointer
@@ -206,6 +210,7 @@ enum i2s_datlen {
  * @dma_data_rx: dma configuration data for tx channel
  * @substream: PCM substream data pointer
  * @i2sclk: kernel clock feeding the I2S clock generator
+ * @i2smclk: master clock from I2S mclk provider
  * @pclk: peripheral clock driving bus interface
  * @x8kclk: I2S parent clock for sampling frequencies multiple of 8kHz
  * @x11kclk: I2S parent clock for sampling frequencies multiple of 11kHz
@@ -215,6 +220,9 @@ enum i2s_datlen {
  * @irq_lock: prevent race condition with IRQ
  * @mclk_rate: master clock frequency (Hz)
  * @fmt: DAI protocol
+ * @divider: prescaler division ratio
+ * @div: prescaler div field
+ * @odd: prescaler odd field
  * @refcount: keep count of opened streams on I2S
  * @ms_flg: master mode flag.
  */
@@ -227,6 +235,7 @@ struct stm32_i2s_data {
        struct snd_dmaengine_dai_dma_data dma_data_rx;
        struct snd_pcm_substream *substream;
        struct clk *i2sclk;
+       struct clk *i2smclk;
        struct clk *pclk;
        struct clk *x8kclk;
        struct clk *x11kclk;
@@ -236,10 +245,210 @@ struct stm32_i2s_data {
        spinlock_t irq_lock; /* used to prevent race condition with IRQ */
        unsigned int mclk_rate;
        unsigned int fmt;
+       unsigned int divider;
+       unsigned int div;
+       bool odd;
        int refcount;
        int ms_flg;
 };
 
+struct stm32_i2smclk_data {
+       struct clk_hw hw;
+       unsigned long freq;
+       struct stm32_i2s_data *i2s_data;
+};
+
+#define to_mclk_data(_hw) container_of(_hw, struct stm32_i2smclk_data, hw)
+
+static int stm32_i2s_calc_clk_div(struct stm32_i2s_data *i2s,
+                                 unsigned long input_rate,
+                                 unsigned long output_rate)
+{
+       unsigned int ratio, div, divider = 1;
+       bool odd;
+
+       ratio = DIV_ROUND_CLOSEST(input_rate, output_rate);
+
+       /* Check the parity of the divider */
+       odd = ratio & 0x1;
+
+       /* Compute the div prescaler */
+       div = ratio >> 1;
+
+       /* If div is 0 actual divider is 1 */
+       if (div) {
+               divider = ((2 * div) + odd);
+               dev_dbg(&i2s->pdev->dev, "Divider: 2*%d(div)+%d(odd) = %d\n",
+                       div, odd, divider);
+       }
+
+       /* Division by three is not allowed by I2S prescaler */
+       if ((div == 1 && odd) || div > I2S_CGFR_I2SDIV_MAX) {
+               dev_err(&i2s->pdev->dev, "Wrong divider setting\n");
+               return -EINVAL;
+       }
+
+       if (input_rate % divider)
+               dev_dbg(&i2s->pdev->dev,
+                       "Rate not accurate. requested (%ld), actual (%ld)\n",
+                       output_rate, input_rate / divider);
+
+       i2s->div = div;
+       i2s->odd = odd;
+       i2s->divider = divider;
+
+       return 0;
+}
+
+static int stm32_i2s_set_clk_div(struct stm32_i2s_data *i2s)
+{
+       u32 cgfr, cgfr_mask;
+
+       cgfr = I2S_CGFR_I2SDIV_SET(i2s->div) | (i2s->odd << I2S_CGFR_ODD_SHIFT);
+       cgfr_mask = I2S_CGFR_I2SDIV_MASK | I2S_CGFR_ODD;
+
+       return regmap_update_bits(i2s->regmap, STM32_I2S_CGFR_REG,
+                                 cgfr_mask, cgfr);
+}
+
+static int stm32_i2s_set_parent_clock(struct stm32_i2s_data *i2s,
+                                     unsigned int rate)
+{
+       struct platform_device *pdev = i2s->pdev;
+       struct clk *parent_clk;
+       int ret;
+
+       if (!(rate % STM32_I2S_RATE_11K))
+               parent_clk = i2s->x11kclk;
+       else
+               parent_clk = i2s->x8kclk;
+
+       ret = clk_set_parent(i2s->i2sclk, parent_clk);
+       if (ret)
+               dev_err(&pdev->dev,
+                       "Error %d setting i2sclk parent clock\n", ret);
+
+       return ret;
+}
+
+static long stm32_i2smclk_round_rate(struct clk_hw *hw, unsigned long rate,
+                                    unsigned long *prate)
+{
+       struct stm32_i2smclk_data *mclk = to_mclk_data(hw);
+       struct stm32_i2s_data *i2s = mclk->i2s_data;
+       int ret;
+
+       ret = stm32_i2s_calc_clk_div(i2s, *prate, rate);
+       if (ret)
+               return ret;
+
+       mclk->freq = *prate / i2s->divider;
+
+       return mclk->freq;
+}
+
+static unsigned long stm32_i2smclk_recalc_rate(struct clk_hw *hw,
+                                              unsigned long parent_rate)
+{
+       struct stm32_i2smclk_data *mclk = to_mclk_data(hw);
+
+       return mclk->freq;
+}
+
+static int stm32_i2smclk_set_rate(struct clk_hw *hw, unsigned long rate,
+                                 unsigned long parent_rate)
+{
+       struct stm32_i2smclk_data *mclk = to_mclk_data(hw);
+       struct stm32_i2s_data *i2s = mclk->i2s_data;
+       int ret;
+
+       ret = stm32_i2s_calc_clk_div(i2s, parent_rate, rate);
+       if (ret)
+               return ret;
+
+       ret = stm32_i2s_set_clk_div(i2s);
+       if (ret)
+               return ret;
+
+       mclk->freq = rate;
+
+       return 0;
+}
+
+static int stm32_i2smclk_enable(struct clk_hw *hw)
+{
+       struct stm32_i2smclk_data *mclk = to_mclk_data(hw);
+       struct stm32_i2s_data *i2s = mclk->i2s_data;
+
+       dev_dbg(&i2s->pdev->dev, "Enable master clock\n");
+
+       return regmap_update_bits(i2s->regmap, STM32_I2S_CGFR_REG,
+                                   I2S_CGFR_MCKOE, I2S_CGFR_MCKOE);
+}
+
+static void stm32_i2smclk_disable(struct clk_hw *hw)
+{
+       struct stm32_i2smclk_data *mclk = to_mclk_data(hw);
+       struct stm32_i2s_data *i2s = mclk->i2s_data;
+
+       dev_dbg(&i2s->pdev->dev, "Disable master clock\n");
+
+       regmap_update_bits(i2s->regmap, STM32_I2S_CGFR_REG, I2S_CGFR_MCKOE, 0);
+}
+
+static const struct clk_ops mclk_ops = {
+       .enable = stm32_i2smclk_enable,
+       .disable = stm32_i2smclk_disable,
+       .recalc_rate = stm32_i2smclk_recalc_rate,
+       .round_rate = stm32_i2smclk_round_rate,
+       .set_rate = stm32_i2smclk_set_rate,
+};
+
+static int stm32_i2s_add_mclk_provider(struct stm32_i2s_data *i2s)
+{
+       struct clk_hw *hw;
+       struct stm32_i2smclk_data *mclk;
+       struct device *dev = &i2s->pdev->dev;
+       const char *pname = __clk_get_name(i2s->i2sclk);
+       char *mclk_name, *p, *s = (char *)pname;
+       int ret, i = 0;
+
+       mclk = devm_kzalloc(dev, sizeof(*mclk), GFP_KERNEL);
+       if (!mclk)
+               return -ENOMEM;
+
+       mclk_name = devm_kcalloc(dev, sizeof(char),
+                                STM32_I2S_NAME_LEN, GFP_KERNEL);
+       if (!mclk_name)
+               return -ENOMEM;
+
+       /*
+        * Forge mclk clock name from parent clock name and suffix.
+        * String after "_" char is stripped in parent name.
+        */
+       p = mclk_name;
+       while (*s && *s != '_' && (i < (STM32_I2S_NAME_LEN - 7))) {
+               *p++ = *s++;
+               i++;
+       }
+       strcat(p, "_mclk");
+
+       mclk->hw.init = CLK_HW_INIT(mclk_name, pname, &mclk_ops, 0);
+       mclk->i2s_data = i2s;
+       hw = &mclk->hw;
+
+       dev_dbg(dev, "Register master clock %s\n", mclk_name);
+       ret = devm_clk_hw_register(&i2s->pdev->dev, hw);
+       if (ret) {
+               dev_err(dev, "mclk register fails with error %d\n", ret);
+               return ret;
+       }
+       i2s->i2smclk = hw->clk;
+
+       /* register mclk provider */
+       return devm_of_clk_add_hw_provider(dev, of_clk_hw_simple_get, hw);
+}
+
 static irqreturn_t stm32_i2s_isr(int irq, void *devid)
 {
        struct stm32_i2s_data *i2s = (struct stm32_i2s_data *)devid;
@@ -405,18 +614,46 @@ static int stm32_i2s_set_sysclk(struct snd_soc_dai *cpu_dai,
                                int clk_id, unsigned int freq, int dir)
 {
        struct stm32_i2s_data *i2s = snd_soc_dai_get_drvdata(cpu_dai);
+       int ret = 0;
 
-       dev_dbg(cpu_dai->dev, "I2S MCLK frequency is %uHz\n", freq);
+       dev_dbg(cpu_dai->dev, "I2S MCLK frequency is %uHz. mode: %s, dir: %s\n",
+               freq, STM32_I2S_IS_MASTER(i2s) ? "master" : "slave",
+               dir ? "output" : "input");
 
-       if ((dir == SND_SOC_CLOCK_OUT) && STM32_I2S_IS_MASTER(i2s)) {
-               i2s->mclk_rate = freq;
+       /* MCLK generation is available only in master mode */
+       if (dir == SND_SOC_CLOCK_OUT && STM32_I2S_IS_MASTER(i2s)) {
+               if (!i2s->i2smclk) {
+                       dev_dbg(cpu_dai->dev, "No MCLK registered\n");
+                       return 0;
+               }
 
-               /* Enable master clock if master mode and mclk-fs are set */
-               return regmap_update_bits(i2s->regmap, STM32_I2S_CGFR_REG,
-                                         I2S_CGFR_MCKOE, I2S_CGFR_MCKOE);
+               /* Assume shutdown if requested frequency is 0Hz */
+               if (!freq) {
+                       /* Release mclk rate only if rate was actually set */
+                       if (i2s->mclk_rate) {
+                               clk_rate_exclusive_put(i2s->i2smclk);
+                               i2s->mclk_rate = 0;
+                       }
+                       return regmap_update_bits(i2s->regmap,
+                                                 STM32_I2S_CGFR_REG,
+                                                 I2S_CGFR_MCKOE, 0);
+               }
+               /* If master clock is used, set parent clock now */
+               ret = stm32_i2s_set_parent_clock(i2s, freq);
+               if (ret)
+                       return ret;
+               ret = clk_set_rate_exclusive(i2s->i2smclk, freq);
+               if (ret) {
+                       dev_err(cpu_dai->dev, "Could not set mclk rate\n");
+                       return ret;
+               }
+               ret = regmap_update_bits(i2s->regmap, STM32_I2S_CGFR_REG,
+                                        I2S_CGFR_MCKOE, I2S_CGFR_MCKOE);
+               if (!ret)
+                       i2s->mclk_rate = freq;
        }
 
-       return 0;
+       return ret;
 }
 
 static int stm32_i2s_configure_clock(struct snd_soc_dai *cpu_dai,
@@ -424,11 +661,10 @@ static int stm32_i2s_configure_clock(struct snd_soc_dai *cpu_dai,
 {
        struct stm32_i2s_data *i2s = snd_soc_dai_get_drvdata(cpu_dai);
        unsigned long i2s_clock_rate;
-       unsigned int tmp, div, real_div, nb_bits, frame_len;
+       unsigned int nb_bits, frame_len;
        unsigned int rate = params_rate(params);
+       u32 cgfr;
        int ret;
-       u32 cgfr, cgfr_mask;
-       bool odd;
 
        if (!(rate % 11025))
                clk_set_parent(i2s->i2sclk, i2s->x11kclk);
@@ -449,7 +685,10 @@ static int stm32_i2s_configure_clock(struct snd_soc_dai *cpu_dai,
         *   dsp mode : div = i2s_clk / (nb_bits x ws)
         */
        if (i2s->mclk_rate) {
-               tmp = DIV_ROUND_CLOSEST(i2s_clock_rate, i2s->mclk_rate);
+               ret = stm32_i2s_calc_clk_div(i2s, i2s_clock_rate,
+                                            i2s->mclk_rate);
+               if (ret)
+                       return ret;
        } else {
                frame_len = 32;
                if ((i2s->fmt & SND_SOC_DAIFMT_FORMAT_MASK) ==
@@ -462,34 +701,13 @@ static int stm32_i2s_configure_clock(struct snd_soc_dai *cpu_dai,
                        return ret;
 
                nb_bits = frame_len * ((cgfr & I2S_CGFR_CHLEN) + 1);
-               tmp = DIV_ROUND_CLOSEST(i2s_clock_rate, (nb_bits * rate));
-       }
-
-       /* Check the parity of the divider */
-       odd = tmp & 0x1;
-
-       /* Compute the div prescaler */
-       div = tmp >> 1;
-
-       cgfr = I2S_CGFR_I2SDIV_SET(div) | (odd << I2S_CGFR_ODD_SHIFT);
-       cgfr_mask = I2S_CGFR_I2SDIV_MASK | I2S_CGFR_ODD;
-
-       real_div = ((2 * div) + odd);
-       dev_dbg(cpu_dai->dev, "I2S clk: %ld, SCLK: %d\n",
-               i2s_clock_rate, rate);
-       dev_dbg(cpu_dai->dev, "Divider: 2*%d(div)+%d(odd) = %d\n",
-               div, odd, real_div);
-
-       if (((div == 1) && odd) || (div > I2S_CGFR_I2SDIV_MAX)) {
-               dev_err(cpu_dai->dev, "Wrong divider setting\n");
-               return -EINVAL;
+               ret = stm32_i2s_calc_clk_div(i2s, i2s_clock_rate,
+                                            (nb_bits * rate));
+               if (ret)
+                       return ret;
        }
 
-       if (!div && !odd)
-               dev_warn(cpu_dai->dev, "real divider forced to 1\n");
-
-       ret = regmap_update_bits(i2s->regmap, STM32_I2S_CGFR_REG,
-                                cgfr_mask, cgfr);
+       ret = stm32_i2s_set_clk_div(i2s);
        if (ret < 0)
                return ret;
 
@@ -694,9 +912,6 @@ static void stm32_i2s_shutdown(struct snd_pcm_substream *substream,
        struct stm32_i2s_data *i2s = snd_soc_dai_get_drvdata(cpu_dai);
        unsigned long flags;
 
-       regmap_update_bits(i2s->regmap, STM32_I2S_CGFR_REG,
-                          I2S_CGFR_MCKOE, (unsigned int)~I2S_CGFR_MCKOE);
-
        clk_disable_unprepare(i2s->i2sclk);
 
        spin_lock_irqsave(&i2s->irq_lock, flags);
@@ -861,6 +1076,13 @@ static int stm32_i2s_parse_dt(struct platform_device *pdev,
                return PTR_ERR(i2s->x11kclk);
        }
 
+       /* Register mclk provider if requested */
+       if (of_find_property(np, "#clock-cells", NULL)) {
+               ret = stm32_i2s_add_mclk_provider(i2s);
+               if (ret < 0)
+                       return ret;
+       }
+
        /* Get irqs */
        irq = platform_get_irq(pdev, 0);
        if (irq < 0)
@@ -906,16 +1128,16 @@ static int stm32_i2s_probe(struct platform_device *pdev)
        if (!i2s)
                return -ENOMEM;
 
-       ret = stm32_i2s_parse_dt(pdev, i2s);
-       if (ret)
-               return ret;
-
        i2s->pdev = pdev;
        i2s->ms_flg = I2S_MS_NOT_SET;
        spin_lock_init(&i2s->lock_fd);
        spin_lock_init(&i2s->irq_lock);
        platform_set_drvdata(pdev, i2s);
 
+       ret = stm32_i2s_parse_dt(pdev, i2s);
+       if (ret)
+               return ret;
+
        ret = stm32_i2s_dais_init(pdev, i2s);
        if (ret)
                return ret;
index 4b8ca5b..78506c3 100644 (file)
@@ -1105,7 +1105,7 @@ static struct snd_soc_dai_driver sun4i_i2s_dai = {
                .formats = SUN4I_FORMATS,
        },
        .ops = &sun4i_i2s_dai_ops,
-       .symmetric_rates = 1,
+       .symmetric_rate = 1,
 };
 
 static const struct snd_soc_component_driver sun4i_i2s_component = {
index 180442c..460924f 100644 (file)
@@ -640,9 +640,9 @@ static struct snd_soc_dai_driver sun8i_codec_dais[] = {
                        .rates          = SUN8I_CODEC_PCM_RATES,
                        .formats        = SUN8I_CODEC_PCM_FORMATS,
                },
-               .symmetric_rates        = true,
+               .symmetric_rate         = true,
                .symmetric_channels     = true,
-               .symmetric_samplebits   = true,
+               .symmetric_sample_bits  = true,
        },
        {
                .name   = "sun8i-codec-aif2",
@@ -665,9 +665,9 @@ static struct snd_soc_dai_driver sun8i_codec_dais[] = {
                        .rates          = SUN8I_CODEC_PCM_RATES,
                        .formats        = SUN8I_CODEC_PCM_FORMATS,
                },
-               .symmetric_rates        = true,
+               .symmetric_rate         = true,
                .symmetric_channels     = true,
-               .symmetric_samplebits   = true,
+               .symmetric_sample_bits  = true,
        },
        {
                .name   = "sun8i-codec-aif3",
@@ -690,9 +690,9 @@ static struct snd_soc_dai_driver sun8i_codec_dais[] = {
                        .rates          = SUN8I_CODEC_PCM_RATES,
                        .formats        = SUN8I_CODEC_PCM_FORMATS,
                },
-               .symmetric_rates        = true,
+               .symmetric_rate         = true,
                .symmetric_channels     = true,
-               .symmetric_samplebits   = true,
+               .symmetric_sample_bits  = true,
        },
 };
 
index a62cc87..a4e6760 100644 (file)
@@ -9,9 +9,10 @@ config SND_SOC_TEGRA
        help
          Say Y or M here if you want support for SoC audio on Tegra.
 
+if SND_SOC_TEGRA
+
 config SND_SOC_TEGRA20_AC97
        tristate "Tegra20 AC97 interface"
-       depends on SND_SOC_TEGRA
        select SND_SOC_AC97_BUS
        select SND_SOC_TEGRA20_DAS
        help
@@ -21,7 +22,6 @@ config SND_SOC_TEGRA20_AC97
 
 config SND_SOC_TEGRA20_DAS
        tristate "Tegra20 DAS module"
-       depends on SND_SOC_TEGRA
        help
          Say Y or M if you want to add support for the Tegra20 DAS module.
          You will also need to select the individual machine drivers to
@@ -29,7 +29,6 @@ config SND_SOC_TEGRA20_DAS
 
 config SND_SOC_TEGRA20_I2S
        tristate "Tegra20 I2S interface"
-       depends on SND_SOC_TEGRA
        select SND_SOC_TEGRA20_DAS
        help
          Say Y or M if you want to add support for codecs attached to the
@@ -38,7 +37,6 @@ config SND_SOC_TEGRA20_I2S
 
 config SND_SOC_TEGRA20_SPDIF
        tristate "Tegra20 SPDIF interface"
-       depends on SND_SOC_TEGRA
        help
          Say Y or M if you want to add support for the Tegra20 SPDIF interface.
          You will also need to select the individual machine drivers to support
@@ -46,7 +44,6 @@ config SND_SOC_TEGRA20_SPDIF
 
 config SND_SOC_TEGRA30_AHUB
        tristate "Tegra30 AHUB module"
-       depends on SND_SOC_TEGRA
        help
          Say Y or M if you want to add support for the Tegra30 AHUB module.
          You will also need to select the individual machine drivers to
@@ -54,7 +51,6 @@ config SND_SOC_TEGRA30_AHUB
 
 config SND_SOC_TEGRA30_I2S
        tristate "Tegra30 I2S interface"
-       depends on SND_SOC_TEGRA
        select SND_SOC_TEGRA30_AHUB
        help
          Say Y or M if you want to add support for codecs attached to the
@@ -63,7 +59,6 @@ config SND_SOC_TEGRA30_I2S
 
 config SND_SOC_TEGRA210_AHUB
        tristate "Tegra210 AHUB module"
-       depends on SND_SOC_TEGRA
        help
          Config to enable Audio Hub (AHUB) module, which comprises of a
          switch called Audio Crossbar (AXBAR) used to configure or modify
@@ -73,7 +68,6 @@ config SND_SOC_TEGRA210_AHUB
 
 config SND_SOC_TEGRA210_DMIC
        tristate "Tegra210 DMIC module"
-       depends on SND_SOC_TEGRA
        help
          Config to enable the Digital MIC (DMIC) controller which is used
          to interface with Pulse Density Modulation (PDM) input devices.
@@ -84,7 +78,6 @@ config SND_SOC_TEGRA210_DMIC
 
 config SND_SOC_TEGRA210_I2S
        tristate "Tegra210 I2S module"
-       depends on SND_SOC_TEGRA
        help
          Config to enable the Inter-IC Sound (I2S) Controller which
          implements full-duplex and bidirectional and single direction
@@ -94,7 +87,6 @@ config SND_SOC_TEGRA210_I2S
 
 config SND_SOC_TEGRA186_DSPK
        tristate "Tegra186 DSPK module"
-       depends on SND_SOC_TEGRA
        help
          Config to enable the Digital Speaker Controller (DSPK) which
          converts the multi-bit Pulse Code Modulation (PCM) audio input to
@@ -107,7 +99,6 @@ config SND_SOC_TEGRA186_DSPK
 
 config SND_SOC_TEGRA210_ADMAIF
        tristate "Tegra210 ADMAIF module"
-       depends on SND_SOC_TEGRA
        help
          Config to enable ADMAIF which is the interface between ADMA and
          Audio Hub (AHUB). Each ADMA channel that sends/receives data to/
@@ -117,9 +108,18 @@ config SND_SOC_TEGRA210_ADMAIF
          channel. Buffer size is configurable for each ADMAIIF channel.
          Say Y or M if you want to add support for Tegra210 ADMAIF module.
 
+config SND_SOC_TEGRA_AUDIO_GRAPH_CARD
+       tristate "Audio Graph Card based Tegra driver"
+       depends on SND_AUDIO_GRAPH_CARD
+       help
+         Config to enable Tegra audio machine driver based on generic
+         audio graph driver. It is a thin driver written to customize
+         few things for Tegra audio. Most of the code is re-used from
+         audio graph driver and the same DT bindings are used.
+
 config SND_SOC_TEGRA_RT5640
        tristate "SoC Audio support for Tegra boards using an RT5640 codec"
-       depends on SND_SOC_TEGRA && I2C && GPIOLIB
+       depends on I2C && GPIOLIB
        select SND_SOC_RT5640
        help
          Say Y or M here if you want to add support for SoC audio on Tegra
@@ -127,7 +127,7 @@ config SND_SOC_TEGRA_RT5640
 
 config SND_SOC_TEGRA_WM8753
        tristate "SoC Audio support for Tegra boards using a WM8753 codec"
-       depends on SND_SOC_TEGRA && I2C && GPIOLIB
+       depends on I2C && GPIOLIB
        select SND_SOC_WM8753
        help
          Say Y or M here if you want to add support for SoC audio on Tegra
@@ -135,7 +135,7 @@ config SND_SOC_TEGRA_WM8753
 
 config SND_SOC_TEGRA_WM8903
        tristate "SoC Audio support for Tegra boards using a WM8903 codec"
-       depends on SND_SOC_TEGRA && I2C && GPIOLIB
+       depends on I2C && GPIOLIB
        select SND_SOC_WM8903
        help
          Say Y or M here if you want to add support for SoC audio on Tegra
@@ -144,7 +144,7 @@ config SND_SOC_TEGRA_WM8903
 
 config SND_SOC_TEGRA_WM9712
        tristate "SoC Audio support for Tegra boards using a WM9712 codec"
-       depends on SND_SOC_TEGRA && GPIOLIB
+       depends on GPIOLIB
        select SND_SOC_TEGRA20_AC97
        select SND_SOC_WM9712
        help
@@ -153,7 +153,7 @@ config SND_SOC_TEGRA_WM9712
 
 config SND_SOC_TEGRA_TRIMSLICE
        tristate "SoC Audio support for TrimSlice board"
-       depends on SND_SOC_TEGRA && I2C
+       depends on I2C
        select SND_SOC_TLV320AIC23_I2C
        help
          Say Y or M here if you want to add support for SoC audio on the
@@ -161,7 +161,7 @@ config SND_SOC_TEGRA_TRIMSLICE
 
 config SND_SOC_TEGRA_ALC5632
        tristate "SoC Audio support for Tegra boards using an ALC5632 codec"
-       depends on SND_SOC_TEGRA && I2C && GPIOLIB
+       depends on I2C && GPIOLIB
        select SND_SOC_ALC5632
        help
          Say Y or M here if you want to add support for SoC audio on the
@@ -169,7 +169,7 @@ config SND_SOC_TEGRA_ALC5632
 
 config SND_SOC_TEGRA_MAX98090
        tristate "SoC Audio support for Tegra boards using a MAX98090 codec"
-       depends on SND_SOC_TEGRA && I2C && GPIOLIB
+       depends on I2C && GPIOLIB
        select SND_SOC_MAX98090
        help
          Say Y or M here if you want to add support for SoC audio on Tegra
@@ -177,7 +177,7 @@ config SND_SOC_TEGRA_MAX98090
 
 config SND_SOC_TEGRA_RT5677
        tristate "SoC Audio support for Tegra boards using a RT5677 codec"
-       depends on SND_SOC_TEGRA && I2C && GPIOLIB
+       depends on I2C && GPIOLIB
        select SND_SOC_RT5677
        help
          Say Y or M here if you want to add support for SoC audio on Tegra
@@ -185,9 +185,11 @@ config SND_SOC_TEGRA_RT5677
 
 config SND_SOC_TEGRA_SGTL5000
        tristate "SoC Audio support for Tegra boards using a SGTL5000 codec"
-       depends on SND_SOC_TEGRA && I2C && GPIOLIB
+       depends on I2C && GPIOLIB
        select SND_SOC_SGTL5000
        help
          Say Y or M here if you want to add support for SoC audio on Tegra
          boards using the SGTL5000 codec, such as Apalis T30, Apalis TK1 or
          Colibri T30.
+
+endif
index 60040a0..b17dd6e 100644 (file)
@@ -38,6 +38,7 @@ snd-soc-tegra-trimslice-objs := trimslice.o
 snd-soc-tegra-alc5632-objs := tegra_alc5632.o
 snd-soc-tegra-max98090-objs := tegra_max98090.o
 snd-soc-tegra-sgtl5000-objs := tegra_sgtl5000.o
+snd-soc-tegra-audio-graph-card-objs := tegra_audio_graph_card.o
 
 obj-$(CONFIG_SND_SOC_TEGRA_RT5640) += snd-soc-tegra-rt5640.o
 obj-$(CONFIG_SND_SOC_TEGRA_RT5677) += snd-soc-tegra-rt5677.o
@@ -48,3 +49,4 @@ obj-$(CONFIG_SND_SOC_TEGRA_TRIMSLICE) += snd-soc-tegra-trimslice.o
 obj-$(CONFIG_SND_SOC_TEGRA_ALC5632) += snd-soc-tegra-alc5632.o
 obj-$(CONFIG_SND_SOC_TEGRA_MAX98090) += snd-soc-tegra-max98090.o
 obj-$(CONFIG_SND_SOC_TEGRA_SGTL5000) += snd-soc-tegra-sgtl5000.o
+obj-$(CONFIG_SND_SOC_TEGRA_AUDIO_GRAPH_CARD) += snd-soc-tegra-audio-graph-card.o
index 7d9948f..8ee9a77 100644 (file)
@@ -217,7 +217,7 @@ static struct snd_soc_dai_driver tegra186_dspk_dais[] = {
                           SNDRV_PCM_FMTBIT_S32_LE,
            },
            .ops = &tegra186_dspk_dai_ops,
-           .symmetric_rates = 1,
+           .symmetric_rate = 1,
        },
 };
 
index 005fc4e..d7a3d04 100644 (file)
@@ -260,7 +260,7 @@ static const struct snd_soc_dai_driver tegra20_i2s_dai_template = {
                .formats = SNDRV_PCM_FMTBIT_S16_LE,
        },
        .ops = &tegra20_i2s_dai_ops,
-       .symmetric_rates = 1,
+       .symmetric_rate = 1,
 };
 
 static const struct snd_soc_component_driver tegra20_i2s_component = {
index ead2c99..b096478 100644 (file)
@@ -228,7 +228,7 @@ static struct snd_soc_dai_driver tegra210_dmic_dais[] = {
                                   SNDRV_PCM_FMTBIT_S32_LE,
                },
                .ops = &tegra210_dmic_dai_ops,
-               .symmetric_rates = 1,
+               .symmetric_rate = 1,
        },
 };
 
index ca31ec9..45f31cc 100644 (file)
@@ -577,7 +577,7 @@ static struct snd_soc_dai_driver tegra210_i2s_dais[] = {
                                SNDRV_PCM_FMTBIT_S32_LE,
                },
                .ops = &tegra210_i2s_dai_ops,
-               .symmetric_rates = 1,
+               .symmetric_rate = 1,
        },
 };
 
index 156e3b9..9ef05ca 100644 (file)
@@ -45,8 +45,7 @@ static int tegra30_ahub_runtime_suspend(struct device *dev)
        regcache_cache_only(ahub->regmap_apbif, true);
        regcache_cache_only(ahub->regmap_ahub, true);
 
-       clk_disable_unprepare(ahub->clk_apbif);
-       clk_disable_unprepare(ahub->clk_d_audio);
+       clk_bulk_disable_unprepare(ahub->nclocks, ahub->clocks);
 
        return 0;
 }
@@ -66,22 +65,39 @@ static int tegra30_ahub_runtime_resume(struct device *dev)
 {
        int ret;
 
-       ret = clk_prepare_enable(ahub->clk_d_audio);
-       if (ret) {
-               dev_err(dev, "clk_enable d_audio failed: %d\n", ret);
+       ret = reset_control_assert(ahub->reset);
+       if (ret)
                return ret;
-       }
-       ret = clk_prepare_enable(ahub->clk_apbif);
-       if (ret) {
-               dev_err(dev, "clk_enable apbif failed: %d\n", ret);
-               clk_disable(ahub->clk_d_audio);
+
+       ret = clk_bulk_prepare_enable(ahub->nclocks, ahub->clocks);
+       if (ret)
                return ret;
-       }
+
+       usleep_range(10, 100);
+
+       ret = reset_control_deassert(ahub->reset);
+       if (ret)
+               goto disable_clocks;
 
        regcache_cache_only(ahub->regmap_apbif, false);
        regcache_cache_only(ahub->regmap_ahub, false);
+       regcache_mark_dirty(ahub->regmap_apbif);
+       regcache_mark_dirty(ahub->regmap_ahub);
+
+       ret = regcache_sync(ahub->regmap_apbif);
+       if (ret)
+               goto disable_clocks;
+
+       ret = regcache_sync(ahub->regmap_ahub);
+       if (ret)
+               goto disable_clocks;
 
        return 0;
+
+disable_clocks:
+       clk_bulk_disable_unprepare(ahub->nclocks, ahub->clocks);
+
+       return ret;
 }
 
 int tegra30_ahub_allocate_rx_fifo(enum tegra30_ahub_rxcif *rxcif,
@@ -337,6 +353,8 @@ static const struct {
        const char *rst_name;
        u32 mod_list_mask;
 } configlink_mods[] = {
+       { "d_audio", MOD_LIST_MASK_TEGRA30_OR_LATER },
+       { "apbif", MOD_LIST_MASK_TEGRA30_OR_LATER },
        { "i2s0", MOD_LIST_MASK_TEGRA30_OR_LATER },
        { "i2s1", MOD_LIST_MASK_TEGRA30_OR_LATER },
        { "i2s2", MOD_LIST_MASK_TEGRA30_OR_LATER },
@@ -526,7 +544,6 @@ static int tegra30_ahub_probe(struct platform_device *pdev)
        /*
         * The AHUB hosts a register bus: the "configlink". For this to
         * operate correctly, all devices on this bus must be out of reset.
-        * Ensure that here.
         */
        for (i = 0; i < ARRAY_SIZE(configlink_mods); i++) {
                if (!(configlink_mods[i].mod_list_mask &
@@ -542,10 +559,8 @@ static int tegra30_ahub_probe(struct platform_device *pdev)
                        return ret;
                }
 
-               ret = reset_control_deassert(rst);
+               /* just check presence of the reset control in DT */
                reset_control_put(rst);
-               if (ret)
-                       return ret;
        }
 
        ahub = devm_kzalloc(&pdev->dev, sizeof(struct tegra30_ahub),
@@ -557,18 +572,17 @@ static int tegra30_ahub_probe(struct platform_device *pdev)
        ahub->soc_data = soc_data;
        ahub->dev = &pdev->dev;
 
-       ahub->clk_d_audio = devm_clk_get(&pdev->dev, "d_audio");
-       if (IS_ERR(ahub->clk_d_audio)) {
-               dev_err(&pdev->dev, "Can't retrieve ahub d_audio clock\n");
-               ret = PTR_ERR(ahub->clk_d_audio);
-               return ret;
-       }
+       ahub->clocks[ahub->nclocks++].id = "apbif";
+       ahub->clocks[ahub->nclocks++].id = "d_audio";
 
-       ahub->clk_apbif = devm_clk_get(&pdev->dev, "apbif");
-       if (IS_ERR(ahub->clk_apbif)) {
-               dev_err(&pdev->dev, "Can't retrieve ahub apbif clock\n");
-               ret = PTR_ERR(ahub->clk_apbif);
+       ret = devm_clk_bulk_get(&pdev->dev, ahub->nclocks, ahub->clocks);
+       if (ret)
                return ret;
+
+       ahub->reset = devm_reset_control_array_get_exclusive(&pdev->dev);
+       if (IS_ERR(ahub->reset)) {
+               dev_err(&pdev->dev, "Can't get resets: %pe\n", ahub->reset);
+               return PTR_ERR(ahub->reset);
        }
 
        res0 = platform_get_resource(pdev, IORESOURCE_MEM, 0);
index 6889c5f..3b85244 100644 (file)
@@ -511,8 +511,9 @@ struct tegra30_ahub_soc_data {
 struct tegra30_ahub {
        const struct tegra30_ahub_soc_data *soc_data;
        struct device *dev;
-       struct clk *clk_d_audio;
-       struct clk *clk_apbif;
+       struct reset_control *reset;
+       struct clk_bulk_data clocks[2];
+       unsigned int nclocks;
        resource_size_t apbif_addr;
        struct regmap *regmap_apbif;
        struct regmap *regmap_ahub;
index db5a858..6740df5 100644 (file)
@@ -316,7 +316,7 @@ static const struct snd_soc_dai_driver tegra30_i2s_dai_template = {
                .formats = SNDRV_PCM_FMTBIT_S16_LE,
        },
        .ops = &tegra30_i2s_dai_ops,
-       .symmetric_rates = 1,
+       .symmetric_rate = 1,
 };
 
 static const struct snd_soc_component_driver tegra30_i2s_component = {
diff --git a/sound/soc/tegra/tegra_audio_graph_card.c b/sound/soc/tegra/tegra_audio_graph_card.c
new file mode 100644 (file)
index 0000000..ddedf18
--- /dev/null
@@ -0,0 +1,252 @@
+// SPDX-License-Identifier: GPL-2.0-only
+//
+// tegra_audio_graph_card.c - Audio Graph based Tegra Machine Driver
+//
+// Copyright (c) 2020-2021 NVIDIA CORPORATION.  All rights reserved.
+
+#include <linux/math64.h>
+#include <linux/module.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+#include <sound/graph_card.h>
+#include <sound/pcm_params.h>
+
+#define MAX_PLLA_OUT0_DIV 128
+
+#define simple_to_tegra_priv(simple) \
+               container_of(simple, struct tegra_audio_priv, simple)
+
+enum srate_type {
+       /*
+        * Sample rates multiple of 8000 Hz and below are supported:
+        * ( 8000, 16000, 32000, 48000, 96000, 192000 Hz )
+        */
+       x8_RATE,
+
+       /*
+        * Sample rates multiple of 11025 Hz and below are supported:
+        * ( 11025, 22050, 44100, 88200, 176400 Hz )
+        */
+       x11_RATE,
+
+       NUM_RATE_TYPE,
+};
+
+struct tegra_audio_priv {
+       struct asoc_simple_priv simple;
+       struct clk *clk_plla_out0;
+       struct clk *clk_plla;
+};
+
+/* Tegra audio chip data */
+struct tegra_audio_cdata {
+       unsigned int plla_rates[NUM_RATE_TYPE];
+       unsigned int plla_out0_rates[NUM_RATE_TYPE];
+};
+
+/* Setup PLL clock as per the given sample rate */
+static int tegra_audio_graph_update_pll(struct snd_pcm_substream *substream,
+                                       struct snd_pcm_hw_params *params)
+{
+       struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
+       struct asoc_simple_priv *simple = snd_soc_card_get_drvdata(rtd->card);
+       struct tegra_audio_priv *priv = simple_to_tegra_priv(simple);
+       struct device *dev = rtd->card->dev;
+       const struct tegra_audio_cdata *data = of_device_get_match_data(dev);
+       unsigned int plla_rate, plla_out0_rate, bclk;
+       unsigned int srate = params_rate(params);
+       int err;
+
+       switch (srate) {
+       case 11025:
+       case 22050:
+       case 44100:
+       case 88200:
+       case 176400:
+               plla_out0_rate = data->plla_out0_rates[x11_RATE];
+               plla_rate = data->plla_rates[x11_RATE];
+               break;
+       case 8000:
+       case 16000:
+       case 32000:
+       case 48000:
+       case 96000:
+       case 192000:
+               plla_out0_rate = data->plla_out0_rates[x8_RATE];
+               plla_rate = data->plla_rates[x8_RATE];
+               break;
+       default:
+               dev_err(rtd->card->dev, "Unsupported sample rate %u\n",
+                       srate);
+               return -EINVAL;
+       }
+
+       /*
+        * Below is the clock relation:
+        *
+        *      PLLA
+        *        |
+        *        |--> PLLA_OUT0
+        *                |
+        *                |---> I2S modules
+        *                |
+        *                |---> DMIC modules
+        *                |
+        *                |---> DSPK modules
+        *
+        *
+        * Default PLLA_OUT0 rate might be too high when I/O is running
+        * at minimum PCM configurations. This may result in incorrect
+        * clock rates and glitchy audio. The maximum divider is 128
+        * and any thing higher than that won't work. Thus reduce PLLA_OUT0
+        * to work for lower configurations.
+        *
+        * This problem is seen for I2S only, as DMIC and DSPK minimum
+        * clock requirements are under allowed divider limits.
+        */
+       bclk = srate * params_channels(params) * params_width(params);
+       if (div_u64(plla_out0_rate, bclk) > MAX_PLLA_OUT0_DIV)
+               plla_out0_rate >>= 1;
+
+       dev_dbg(rtd->card->dev,
+               "Update clock rates: PLLA(= %u Hz) and PLLA_OUT0(= %u Hz)\n",
+               plla_rate, plla_out0_rate);
+
+       /* Set PLLA rate */
+       err = clk_set_rate(priv->clk_plla, plla_rate);
+       if (err) {
+               dev_err(rtd->card->dev,
+                       "Can't set plla rate for %u, err: %d\n",
+                       plla_rate, err);
+               return err;
+       }
+
+       /* Set PLLA_OUT0 rate */
+       err = clk_set_rate(priv->clk_plla_out0, plla_out0_rate);
+       if (err) {
+               dev_err(rtd->card->dev,
+                       "Can't set plla_out0 rate %u, err: %d\n",
+                       plla_out0_rate, err);
+               return err;
+       }
+
+       return err;
+}
+
+static int tegra_audio_graph_hw_params(struct snd_pcm_substream *substream,
+                                      struct snd_pcm_hw_params *params)
+{
+       struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
+       struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0);
+       int err;
+
+       /*
+        * This gets called for each DAI link (FE or BE) when DPCM is used.
+        * We may not want to update PLLA rate for each call. So PLLA update
+        * must be restricted to external I/O links (I2S, DMIC or DSPK) since
+        * they actually depend on it. I/O modules update their clocks in
+        * hw_param() of their respective component driver and PLLA rate
+        * update here helps them to derive appropriate rates.
+        *
+        * TODO: When more HW accelerators get added (like sample rate
+        * converter, volume gain controller etc., which don't really
+        * depend on PLLA) we need a better way to filter here.
+        */
+       if (cpu_dai->driver->ops && rtd->dai_link->no_pcm) {
+               err = tegra_audio_graph_update_pll(substream, params);
+               if (err)
+                       return err;
+       }
+
+       return asoc_simple_hw_params(substream, params);
+}
+
+static const struct snd_soc_ops tegra_audio_graph_ops = {
+       .startup        = asoc_simple_startup,
+       .shutdown       = asoc_simple_shutdown,
+       .hw_params      = tegra_audio_graph_hw_params,
+};
+
+static int tegra_audio_graph_card_probe(struct snd_soc_card *card)
+{
+       struct asoc_simple_priv *simple = snd_soc_card_get_drvdata(card);
+       struct tegra_audio_priv *priv = simple_to_tegra_priv(simple);
+
+       priv->clk_plla = devm_clk_get(card->dev, "pll_a");
+       if (IS_ERR(priv->clk_plla)) {
+               dev_err(card->dev, "Can't retrieve clk pll_a\n");
+               return PTR_ERR(priv->clk_plla);
+       }
+
+       priv->clk_plla_out0 = devm_clk_get(card->dev, "plla_out0");
+       if (IS_ERR(priv->clk_plla_out0)) {
+               dev_err(card->dev, "Can't retrieve clk plla_out0\n");
+               return PTR_ERR(priv->clk_plla_out0);
+       }
+
+       return audio_graph_card_probe(card);
+}
+
+static int tegra_audio_graph_probe(struct platform_device *pdev)
+{
+       struct tegra_audio_priv *priv;
+       struct device *dev = &pdev->dev;
+       struct snd_soc_card *card;
+
+       priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
+       if (!priv)
+               return -ENOMEM;
+
+       card = simple_priv_to_card(&priv->simple);
+
+       card->probe = tegra_audio_graph_card_probe;
+
+       /* audio_graph_parse_of() depends on below */
+       card->component_chaining = 1;
+       priv->simple.ops = &tegra_audio_graph_ops;
+       priv->simple.force_dpcm = 1;
+
+       return audio_graph_parse_of(&priv->simple, dev);
+}
+
+static const struct tegra_audio_cdata tegra210_data = {
+       /* PLLA */
+       .plla_rates[x8_RATE] = 368640000,
+       .plla_rates[x11_RATE] = 338688000,
+       /* PLLA_OUT0 */
+       .plla_out0_rates[x8_RATE] = 49152000,
+       .plla_out0_rates[x11_RATE] = 45158400,
+};
+
+static const struct tegra_audio_cdata tegra186_data = {
+       /* PLLA */
+       .plla_rates[x8_RATE] = 245760000,
+       .plla_rates[x11_RATE] = 270950400,
+       /* PLLA_OUT0 */
+       .plla_out0_rates[x8_RATE] = 49152000,
+       .plla_out0_rates[x11_RATE] = 45158400,
+};
+
+static const struct of_device_id graph_of_tegra_match[] = {
+       { .compatible = "nvidia,tegra210-audio-graph-card",
+         .data = &tegra210_data },
+       { .compatible = "nvidia,tegra186-audio-graph-card",
+         .data = &tegra186_data },
+       {},
+};
+MODULE_DEVICE_TABLE(of, graph_of_tegra_match);
+
+static struct platform_driver tegra_audio_graph_card = {
+       .driver = {
+               .name = "tegra-audio-graph-card",
+               .pm = &snd_soc_pm_ops,
+               .of_match_table = graph_of_tegra_match,
+       },
+       .probe = tegra_audio_graph_probe,
+       .remove = audio_graph_remove,
+};
+module_platform_driver(tegra_audio_graph_card);
+
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("ASoC Tegra Audio Graph Sound Card");
+MODULE_AUTHOR("Sameer Pujar <spujar@nvidia.com>");
index b3f3651..573374b 100644 (file)
@@ -255,11 +255,7 @@ static int tegra_pcm_dma_allocate(struct snd_soc_pcm_runtime *rtd,
        struct snd_pcm *pcm = rtd->pcm;
        int ret;
 
-       ret = dma_set_mask(card->dev, DMA_BIT_MASK(32));
-       if (ret < 0)
-               return ret;
-
-       ret = dma_set_coherent_mask(card->dev, DMA_BIT_MASK(32));
+       ret = dma_set_mask_and_coherent(card->dev, DMA_BIT_MASK(32));
        if (ret < 0)
                return ret;
 
index 6247ec3..b942203 100644 (file)
@@ -1641,7 +1641,7 @@ static struct snd_soc_dai_driver davinci_mcasp_dai[] = {
                },
                .ops            = &davinci_mcasp_dai_ops,
 
-               .symmetric_rates        = 1,
+               .symmetric_rate         = 1,
        },
        {
                .name           = "davinci-mcasp.1",
diff --git a/sound/soc/txx9/Kconfig b/sound/soc/txx9/Kconfig
deleted file mode 100644 (file)
index d928edf..0000000
+++ /dev/null
@@ -1,30 +0,0 @@
-# SPDX-License-Identifier: GPL-2.0-only
-##
-## TXx9 ACLC
-##
-config SND_SOC_TXX9ACLC
-       tristate "SoC Audio for TXx9"
-       depends on HAS_TXX9_ACLC && TXX9_DMAC
-       help
-         This option enables support for the AC Link Controllers in TXx9 SoC.
-
-config HAS_TXX9_ACLC
-       bool
-
-config SND_SOC_TXX9ACLC_AC97
-       tristate
-       select AC97_BUS
-       select SND_AC97_CODEC
-       select SND_SOC_AC97_BUS
-
-
-##
-## Boards
-##
-config SND_SOC_TXX9ACLC_GENERIC
-       tristate "Generic TXx9 ACLC sound machine"
-       depends on SND_SOC_TXX9ACLC
-       select SND_SOC_TXX9ACLC_AC97
-       select SND_SOC_AC97_CODEC
-       help
-         This is a generic AC97 sound machine for use in TXx9 based systems.
diff --git a/sound/soc/txx9/Makefile b/sound/soc/txx9/Makefile
deleted file mode 100644 (file)
index 37ad833..0000000
+++ /dev/null
@@ -1,12 +0,0 @@
-# SPDX-License-Identifier: GPL-2.0
-# Platform
-snd-soc-txx9aclc-objs := txx9aclc.o
-snd-soc-txx9aclc-ac97-objs := txx9aclc-ac97.o
-
-obj-$(CONFIG_SND_SOC_TXX9ACLC) += snd-soc-txx9aclc.o
-obj-$(CONFIG_SND_SOC_TXX9ACLC_AC97) += snd-soc-txx9aclc-ac97.o
-
-# Machine
-snd-soc-txx9aclc-generic-objs := txx9aclc-generic.o
-
-obj-$(CONFIG_SND_SOC_TXX9ACLC_GENERIC) += snd-soc-txx9aclc-generic.o
diff --git a/sound/soc/txx9/txx9aclc-ac97.c b/sound/soc/txx9/txx9aclc-ac97.c
deleted file mode 100644 (file)
index d9e3484..0000000
+++ /dev/null
@@ -1,230 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-/*
- * TXx9 ACLC AC97 driver
- *
- * Copyright (C) 2009 Atsushi Nemoto
- *
- * Based on RBTX49xx patch from CELF patch archive.
- * (C) Copyright TOSHIBA CORPORATION 2004-2006
- */
-
-#include <linux/init.h>
-#include <linux/module.h>
-#include <linux/delay.h>
-#include <linux/interrupt.h>
-#include <linux/io.h>
-#include <linux/gfp.h>
-#include <asm/mach-tx39xx/ioremap.h> /* for TXX9_DIRECTMAP_BASE */
-#include <sound/core.h>
-#include <sound/pcm.h>
-#include <sound/soc.h>
-#include "txx9aclc.h"
-
-#define AC97_DIR       \
-       (SND_SOC_DAIDIR_PLAYBACK | SND_SOC_DAIDIR_CAPTURE)
-
-#define AC97_RATES     \
-       SNDRV_PCM_RATE_8000_48000
-
-#ifdef __BIG_ENDIAN
-#define AC97_FMTS      SNDRV_PCM_FMTBIT_S16_BE
-#else
-#define AC97_FMTS      SNDRV_PCM_FMTBIT_S16_LE
-#endif
-
-static DECLARE_WAIT_QUEUE_HEAD(ac97_waitq);
-
-/* REVISIT: How to find txx9aclc_drvdata from snd_ac97? */
-static struct txx9aclc_plat_drvdata *txx9aclc_drvdata;
-
-static int txx9aclc_regready(struct txx9aclc_plat_drvdata *drvdata)
-{
-       return __raw_readl(drvdata->base + ACINTSTS) & ACINT_REGACCRDY;
-}
-
-/* AC97 controller reads codec register */
-static unsigned short txx9aclc_ac97_read(struct snd_ac97 *ac97,
-                                        unsigned short reg)
-{
-       struct txx9aclc_plat_drvdata *drvdata = txx9aclc_drvdata;
-       void __iomem *base = drvdata->base;
-       u32 dat;
-
-       if (!(__raw_readl(base + ACINTSTS) & ACINT_CODECRDY(ac97->num)))
-               return 0xffff;
-       reg |= ac97->num << 7;
-       dat = (reg << ACREGACC_REG_SHIFT) | ACREGACC_READ;
-       __raw_writel(dat, base + ACREGACC);
-       __raw_writel(ACINT_REGACCRDY, base + ACINTEN);
-       if (!wait_event_timeout(ac97_waitq, txx9aclc_regready(txx9aclc_drvdata), HZ)) {
-               __raw_writel(ACINT_REGACCRDY, base + ACINTDIS);
-               printk(KERN_ERR "ac97 read timeout (reg %#x)\n", reg);
-               dat = 0xffff;
-               goto done;
-       }
-       dat = __raw_readl(base + ACREGACC);
-       if (((dat >> ACREGACC_REG_SHIFT) & 0xff) != reg) {
-               printk(KERN_ERR "reg mismatch %x with %x\n",
-                       dat, reg);
-               dat = 0xffff;
-               goto done;
-       }
-       dat = (dat >> ACREGACC_DAT_SHIFT) & 0xffff;
-done:
-       __raw_writel(ACINT_REGACCRDY, base + ACINTDIS);
-       return dat;
-}
-
-/* AC97 controller writes to codec register */
-static void txx9aclc_ac97_write(struct snd_ac97 *ac97, unsigned short reg,
-                               unsigned short val)
-{
-       struct txx9aclc_plat_drvdata *drvdata = txx9aclc_drvdata;
-       void __iomem *base = drvdata->base;
-
-       __raw_writel(((reg | (ac97->num << 7)) << ACREGACC_REG_SHIFT) |
-                    (val << ACREGACC_DAT_SHIFT),
-                    base + ACREGACC);
-       __raw_writel(ACINT_REGACCRDY, base + ACINTEN);
-       if (!wait_event_timeout(ac97_waitq, txx9aclc_regready(txx9aclc_drvdata), HZ)) {
-               printk(KERN_ERR
-                       "ac97 write timeout (reg %#x)\n", reg);
-       }
-       __raw_writel(ACINT_REGACCRDY, base + ACINTDIS);
-}
-
-static void txx9aclc_ac97_cold_reset(struct snd_ac97 *ac97)
-{
-       struct txx9aclc_plat_drvdata *drvdata = txx9aclc_drvdata;
-       void __iomem *base = drvdata->base;
-       u32 ready = ACINT_CODECRDY(ac97->num) | ACINT_REGACCRDY;
-
-       __raw_writel(ACCTL_ENLINK, base + ACCTLDIS);
-       udelay(1);
-       __raw_writel(ACCTL_ENLINK, base + ACCTLEN);
-       /* wait for primary codec ready status */
-       __raw_writel(ready, base + ACINTEN);
-       if (!wait_event_timeout(ac97_waitq,
-                               (__raw_readl(base + ACINTSTS) & ready) == ready,
-                               HZ)) {
-               dev_err(&ac97->dev, "primary codec is not ready "
-                       "(status %#x)\n",
-                       __raw_readl(base + ACINTSTS));
-       }
-       __raw_writel(ACINT_REGACCRDY, base + ACINTSTS);
-       __raw_writel(ready, base + ACINTDIS);
-}
-
-/* AC97 controller operations */
-static struct snd_ac97_bus_ops txx9aclc_ac97_ops = {
-       .read           = txx9aclc_ac97_read,
-       .write          = txx9aclc_ac97_write,
-       .reset          = txx9aclc_ac97_cold_reset,
-};
-
-static irqreturn_t txx9aclc_ac97_irq(int irq, void *dev_id)
-{
-       struct txx9aclc_plat_drvdata *drvdata = dev_id;
-       void __iomem *base = drvdata->base;
-
-       __raw_writel(__raw_readl(base + ACINTMSTS), base + ACINTDIS);
-       wake_up(&ac97_waitq);
-       return IRQ_HANDLED;
-}
-
-static int txx9aclc_ac97_probe(struct snd_soc_dai *dai)
-{
-       txx9aclc_drvdata = snd_soc_dai_get_drvdata(dai);
-       return 0;
-}
-
-static int txx9aclc_ac97_remove(struct snd_soc_dai *dai)
-{
-       struct txx9aclc_plat_drvdata *drvdata = snd_soc_dai_get_drvdata(dai);
-
-       /* disable AC-link */
-       __raw_writel(ACCTL_ENLINK, drvdata->base + ACCTLDIS);
-       txx9aclc_drvdata = NULL;
-       return 0;
-}
-
-static struct snd_soc_dai_driver txx9aclc_ac97_dai = {
-       .probe                  = txx9aclc_ac97_probe,
-       .remove                 = txx9aclc_ac97_remove,
-       .playback = {
-               .rates          = AC97_RATES,
-               .formats        = AC97_FMTS,
-               .channels_min   = 2,
-               .channels_max   = 2,
-       },
-       .capture = {
-               .rates          = AC97_RATES,
-               .formats        = AC97_FMTS,
-               .channels_min   = 2,
-               .channels_max   = 2,
-       },
-};
-
-static const struct snd_soc_component_driver txx9aclc_ac97_component = {
-       .name           = "txx9aclc-ac97",
-};
-
-static int txx9aclc_ac97_dev_probe(struct platform_device *pdev)
-{
-       struct txx9aclc_plat_drvdata *drvdata;
-       struct resource *r;
-       int err;
-       int irq;
-
-       irq = platform_get_irq(pdev, 0);
-       if (irq < 0)
-               return irq;
-
-       drvdata = devm_kzalloc(&pdev->dev, sizeof(*drvdata), GFP_KERNEL);
-       if (!drvdata)
-               return -ENOMEM;
-
-       r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       drvdata->base = devm_ioremap_resource(&pdev->dev, r);
-       if (IS_ERR(drvdata->base))
-               return PTR_ERR(drvdata->base);
-
-       platform_set_drvdata(pdev, drvdata);
-       drvdata->physbase = r->start;
-       if (sizeof(drvdata->physbase) > sizeof(r->start) &&
-           r->start >= TXX9_DIRECTMAP_BASE &&
-           r->start < TXX9_DIRECTMAP_BASE + 0x400000)
-               drvdata->physbase |= 0xf00000000ull;
-       err = devm_request_irq(&pdev->dev, irq, txx9aclc_ac97_irq,
-                              0, dev_name(&pdev->dev), drvdata);
-       if (err < 0)
-               return err;
-
-       err = snd_soc_set_ac97_ops(&txx9aclc_ac97_ops);
-       if (err < 0)
-               return err;
-
-       return devm_snd_soc_register_component(&pdev->dev, &txx9aclc_ac97_component,
-                                         &txx9aclc_ac97_dai, 1);
-}
-
-static int txx9aclc_ac97_dev_remove(struct platform_device *pdev)
-{
-       snd_soc_set_ac97_ops(NULL);
-       return 0;
-}
-
-static struct platform_driver txx9aclc_ac97_driver = {
-       .probe          = txx9aclc_ac97_dev_probe,
-       .remove         = txx9aclc_ac97_dev_remove,
-       .driver         = {
-               .name   = "txx9aclc-ac97",
-       },
-};
-
-module_platform_driver(txx9aclc_ac97_driver);
-
-MODULE_AUTHOR("Atsushi Nemoto <anemo@mba.ocn.ne.jp>");
-MODULE_DESCRIPTION("TXx9 ACLC AC97 driver");
-MODULE_LICENSE("GPL");
-MODULE_ALIAS("platform:txx9aclc-ac97");
diff --git a/sound/soc/txx9/txx9aclc-generic.c b/sound/soc/txx9/txx9aclc-generic.c
deleted file mode 100644 (file)
index d689372..0000000
+++ /dev/null
@@ -1,88 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-/*
- * Generic TXx9 ACLC machine driver
- *
- * Copyright (C) 2009 Atsushi Nemoto
- *
- * Based on RBTX49xx patch from CELF patch archive.
- * (C) Copyright TOSHIBA CORPORATION 2004-2006
- *
- * This is a very generic AC97 sound machine driver for boards which
- * have (AC97) audio at ACLC (e.g. RBTX49XX boards).
- */
-
-#include <linux/module.h>
-#include <linux/platform_device.h>
-#include <sound/core.h>
-#include <sound/pcm.h>
-#include <sound/soc.h>
-#include "txx9aclc.h"
-
-SND_SOC_DAILINK_DEFS(hifi,
-       DAILINK_COMP_ARRAY(COMP_CPU("txx9aclc-ac97")),
-       DAILINK_COMP_ARRAY(COMP_CODEC("ac97-codec", "ac97-hifi")),
-       DAILINK_COMP_ARRAY(COMP_PLATFORM("txx9aclc-pcm-audio")));
-
-static struct snd_soc_dai_link txx9aclc_generic_dai = {
-       .name = "AC97",
-       .stream_name = "AC97 HiFi",
-       SND_SOC_DAILINK_REG(hifi),
-};
-
-static struct snd_soc_card txx9aclc_generic_card = {
-       .name           = "Generic TXx9 ACLC Audio",
-       .owner          = THIS_MODULE,
-       .dai_link       = &txx9aclc_generic_dai,
-       .num_links      = 1,
-};
-
-static struct platform_device *soc_pdev;
-
-static int __init txx9aclc_generic_probe(struct platform_device *pdev)
-{
-       int ret;
-
-       soc_pdev = platform_device_alloc("soc-audio", -1);
-       if (!soc_pdev)
-               return -ENOMEM;
-       platform_set_drvdata(soc_pdev, &txx9aclc_generic_card);
-       ret = platform_device_add(soc_pdev);
-       if (ret) {
-               platform_device_put(soc_pdev);
-               return ret;
-       }
-
-       return 0;
-}
-
-static int __exit txx9aclc_generic_remove(struct platform_device *pdev)
-{
-       platform_device_unregister(soc_pdev);
-       return 0;
-}
-
-static struct platform_driver txx9aclc_generic_driver = {
-       .remove = __exit_p(txx9aclc_generic_remove),
-       .driver = {
-               .name = "txx9aclc-generic",
-       },
-};
-
-static int __init txx9aclc_generic_init(void)
-{
-       return platform_driver_probe(&txx9aclc_generic_driver,
-                                    txx9aclc_generic_probe);
-}
-
-static void __exit txx9aclc_generic_exit(void)
-{
-       platform_driver_unregister(&txx9aclc_generic_driver);
-}
-
-module_init(txx9aclc_generic_init);
-module_exit(txx9aclc_generic_exit);
-
-MODULE_AUTHOR("Atsushi Nemoto <anemo@mba.ocn.ne.jp>");
-MODULE_DESCRIPTION("Generic TXx9 ACLC ALSA SoC audio driver");
-MODULE_LICENSE("GPL");
-MODULE_ALIAS("platform:txx9aclc-generic");
diff --git a/sound/soc/txx9/txx9aclc.c b/sound/soc/txx9/txx9aclc.c
deleted file mode 100644 (file)
index 1d2d0d9..0000000
+++ /dev/null
@@ -1,422 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-/*
- * Generic TXx9 ACLC platform driver
- *
- * Copyright (C) 2009 Atsushi Nemoto
- *
- * Based on RBTX49xx patch from CELF patch archive.
- * (C) Copyright TOSHIBA CORPORATION 2004-2006
- */
-
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/platform_device.h>
-#include <linux/scatterlist.h>
-#include <linux/slab.h>
-#include <linux/dmaengine.h>
-#include <sound/core.h>
-#include <sound/pcm.h>
-#include <sound/pcm_params.h>
-#include <sound/soc.h>
-#include "txx9aclc.h"
-
-#define DRV_NAME "txx9aclc"
-
-static struct txx9aclc_soc_device {
-       struct txx9aclc_dmadata dmadata[2];
-} txx9aclc_soc_device;
-
-/* REVISIT: How to find txx9aclc_drvdata from snd_ac97? */
-static struct txx9aclc_plat_drvdata *txx9aclc_drvdata;
-
-static int txx9aclc_dma_init(struct txx9aclc_soc_device *dev,
-                            struct txx9aclc_dmadata *dmadata);
-
-static const struct snd_pcm_hardware txx9aclc_pcm_hardware = {
-       /*
-        * REVISIT: SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID
-        * needs more works for noncoherent MIPS.
-        */
-       .info             = SNDRV_PCM_INFO_INTERLEAVED |
-                           SNDRV_PCM_INFO_BATCH |
-                           SNDRV_PCM_INFO_PAUSE,
-       .period_bytes_min = 1024,
-       .period_bytes_max = 8 * 1024,
-       .periods_min      = 2,
-       .periods_max      = 4096,
-       .buffer_bytes_max = 32 * 1024,
-};
-
-static int txx9aclc_pcm_hw_params(struct snd_soc_component *component,
-                                 struct snd_pcm_substream *substream,
-                                 struct snd_pcm_hw_params *params)
-{
-       struct snd_pcm_runtime *runtime = substream->runtime;
-       struct txx9aclc_dmadata *dmadata = runtime->private_data;
-
-       dev_dbg(component->dev,
-               "runtime->dma_area = %#lx dma_addr = %#lx dma_bytes = %zd "
-               "runtime->min_align %ld\n",
-               (unsigned long)runtime->dma_area,
-               (unsigned long)runtime->dma_addr, runtime->dma_bytes,
-               runtime->min_align);
-       dev_dbg(component->dev,
-               "periods %d period_bytes %d stream %d\n",
-               params_periods(params), params_period_bytes(params),
-               substream->stream);
-
-       dmadata->substream = substream;
-       dmadata->pos = 0;
-       return 0;
-}
-
-static int txx9aclc_pcm_prepare(struct snd_soc_component *component,
-                               struct snd_pcm_substream *substream)
-{
-       struct snd_pcm_runtime *runtime = substream->runtime;
-       struct txx9aclc_dmadata *dmadata = runtime->private_data;
-
-       dmadata->dma_addr = runtime->dma_addr;
-       dmadata->buffer_bytes = snd_pcm_lib_buffer_bytes(substream);
-       dmadata->period_bytes = snd_pcm_lib_period_bytes(substream);
-
-       if (dmadata->buffer_bytes == dmadata->period_bytes) {
-               dmadata->frag_bytes = dmadata->period_bytes >> 1;
-               dmadata->frags = 2;
-       } else {
-               dmadata->frag_bytes = dmadata->period_bytes;
-               dmadata->frags = dmadata->buffer_bytes / dmadata->period_bytes;
-       }
-       dmadata->frag_count = 0;
-       dmadata->pos = 0;
-       return 0;
-}
-
-static void txx9aclc_dma_complete(void *arg)
-{
-       struct txx9aclc_dmadata *dmadata = arg;
-       unsigned long flags;
-
-       /* dma completion handler cannot submit new operations */
-       spin_lock_irqsave(&dmadata->dma_lock, flags);
-       if (dmadata->frag_count >= 0) {
-               dmadata->dmacount--;
-               if (!WARN_ON(dmadata->dmacount < 0))
-                       queue_work(system_highpri_wq, &dmadata->work);
-       }
-       spin_unlock_irqrestore(&dmadata->dma_lock, flags);
-}
-
-static struct dma_async_tx_descriptor *
-txx9aclc_dma_submit(struct txx9aclc_dmadata *dmadata, dma_addr_t buf_dma_addr)
-{
-       struct dma_chan *chan = dmadata->dma_chan;
-       struct dma_async_tx_descriptor *desc;
-       struct scatterlist sg;
-
-       sg_init_table(&sg, 1);
-       sg_set_page(&sg, pfn_to_page(PFN_DOWN(buf_dma_addr)),
-                   dmadata->frag_bytes, buf_dma_addr & (PAGE_SIZE - 1));
-       sg_dma_address(&sg) = buf_dma_addr;
-       desc = dmaengine_prep_slave_sg(chan, &sg, 1,
-               dmadata->substream->stream == SNDRV_PCM_STREAM_PLAYBACK ?
-               DMA_MEM_TO_DEV : DMA_DEV_TO_MEM,
-               DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
-       if (!desc) {
-               dev_err(&chan->dev->device, "cannot prepare slave dma\n");
-               return NULL;
-       }
-       desc->callback = txx9aclc_dma_complete;
-       desc->callback_param = dmadata;
-       dmaengine_submit(desc);
-       return desc;
-}
-
-#define NR_DMA_CHAIN           2
-
-static void txx9aclc_dma_work(struct work_struct *work)
-{
-       struct txx9aclc_dmadata *dmadata =
-               container_of(work, struct txx9aclc_dmadata, work);
-       struct dma_chan *chan = dmadata->dma_chan;
-       struct dma_async_tx_descriptor *desc;
-       struct snd_pcm_substream *substream = dmadata->substream;
-       u32 ctlbit = substream->stream == SNDRV_PCM_STREAM_PLAYBACK ?
-               ACCTL_AUDODMA : ACCTL_AUDIDMA;
-       int i;
-       unsigned long flags;
-
-       spin_lock_irqsave(&dmadata->dma_lock, flags);
-       if (dmadata->frag_count < 0) {
-               struct txx9aclc_plat_drvdata *drvdata = txx9aclc_drvdata;
-               void __iomem *base = drvdata->base;
-
-               spin_unlock_irqrestore(&dmadata->dma_lock, flags);
-               dmaengine_terminate_all(chan);
-               /* first time */
-               for (i = 0; i < NR_DMA_CHAIN; i++) {
-                       desc = txx9aclc_dma_submit(dmadata,
-                               dmadata->dma_addr + i * dmadata->frag_bytes);
-                       if (!desc)
-                               return;
-               }
-               dmadata->dmacount = NR_DMA_CHAIN;
-               dma_async_issue_pending(chan);
-               spin_lock_irqsave(&dmadata->dma_lock, flags);
-               __raw_writel(ctlbit, base + ACCTLEN);
-               dmadata->frag_count = NR_DMA_CHAIN % dmadata->frags;
-               spin_unlock_irqrestore(&dmadata->dma_lock, flags);
-               return;
-       }
-       if (WARN_ON(dmadata->dmacount >= NR_DMA_CHAIN)) {
-               spin_unlock_irqrestore(&dmadata->dma_lock, flags);
-               return;
-       }
-       while (dmadata->dmacount < NR_DMA_CHAIN) {
-               dmadata->dmacount++;
-               spin_unlock_irqrestore(&dmadata->dma_lock, flags);
-               desc = txx9aclc_dma_submit(dmadata,
-                       dmadata->dma_addr +
-                       dmadata->frag_count * dmadata->frag_bytes);
-               if (!desc)
-                       return;
-               dma_async_issue_pending(chan);
-
-               spin_lock_irqsave(&dmadata->dma_lock, flags);
-               dmadata->frag_count++;
-               dmadata->frag_count %= dmadata->frags;
-               dmadata->pos += dmadata->frag_bytes;
-               dmadata->pos %= dmadata->buffer_bytes;
-               if ((dmadata->frag_count * dmadata->frag_bytes) %
-                   dmadata->period_bytes == 0)
-                       snd_pcm_period_elapsed(substream);
-       }
-       spin_unlock_irqrestore(&dmadata->dma_lock, flags);
-}
-
-static int txx9aclc_pcm_trigger(struct snd_soc_component *component,
-                               struct snd_pcm_substream *substream, int cmd)
-{
-       struct txx9aclc_dmadata *dmadata = substream->runtime->private_data;
-       struct txx9aclc_plat_drvdata *drvdata = txx9aclc_drvdata;
-       void __iomem *base = drvdata->base;
-       unsigned long flags;
-       int ret = 0;
-       u32 ctlbit = substream->stream == SNDRV_PCM_STREAM_PLAYBACK ?
-               ACCTL_AUDODMA : ACCTL_AUDIDMA;
-
-       spin_lock_irqsave(&dmadata->dma_lock, flags);
-       switch (cmd) {
-       case SNDRV_PCM_TRIGGER_START:
-               dmadata->frag_count = -1;
-               queue_work(system_highpri_wq, &dmadata->work);
-               break;
-       case SNDRV_PCM_TRIGGER_STOP:
-       case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
-       case SNDRV_PCM_TRIGGER_SUSPEND:
-               __raw_writel(ctlbit, base + ACCTLDIS);
-               break;
-       case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
-       case SNDRV_PCM_TRIGGER_RESUME:
-               __raw_writel(ctlbit, base + ACCTLEN);
-               break;
-       default:
-               ret = -EINVAL;
-       }
-       spin_unlock_irqrestore(&dmadata->dma_lock, flags);
-       return ret;
-}
-
-static snd_pcm_uframes_t
-txx9aclc_pcm_pointer(struct snd_soc_component *component,
-                    struct snd_pcm_substream *substream)
-{
-       struct txx9aclc_dmadata *dmadata = substream->runtime->private_data;
-
-       return bytes_to_frames(substream->runtime, dmadata->pos);
-}
-
-static int txx9aclc_pcm_open(struct snd_soc_component *component,
-                            struct snd_pcm_substream *substream)
-{
-       struct txx9aclc_soc_device *dev = &txx9aclc_soc_device;
-       struct txx9aclc_dmadata *dmadata = &dev->dmadata[substream->stream];
-       int ret;
-
-       ret = snd_soc_set_runtime_hwparams(substream, &txx9aclc_pcm_hardware);
-       if (ret)
-               return ret;
-       /* ensure that buffer size is a multiple of period size */
-       ret = snd_pcm_hw_constraint_integer(substream->runtime,
-                                           SNDRV_PCM_HW_PARAM_PERIODS);
-       if (ret < 0)
-               return ret;
-       substream->runtime->private_data = dmadata;
-       return 0;
-}
-
-static int txx9aclc_pcm_close(struct snd_soc_component *component,
-                             struct snd_pcm_substream *substream)
-{
-       struct txx9aclc_dmadata *dmadata = substream->runtime->private_data;
-       struct dma_chan *chan = dmadata->dma_chan;
-
-       dmadata->frag_count = -1;
-       dmaengine_terminate_all(chan);
-       return 0;
-}
-
-static int txx9aclc_pcm_new(struct snd_soc_component *component,
-                           struct snd_soc_pcm_runtime *rtd)
-{
-       struct snd_card *card = rtd->card->snd_card;
-       struct snd_soc_dai *dai = asoc_rtd_to_cpu(rtd, 0);
-       struct snd_pcm *pcm = rtd->pcm;
-       struct platform_device *pdev = to_platform_device(component->dev);
-       struct txx9aclc_soc_device *dev;
-       struct resource *r;
-       int i;
-       int ret;
-
-       /* at this point onwards the AC97 component has probed and this will be valid */
-       dev = snd_soc_dai_get_drvdata(dai);
-
-       dev->dmadata[0].stream = SNDRV_PCM_STREAM_PLAYBACK;
-       dev->dmadata[1].stream = SNDRV_PCM_STREAM_CAPTURE;
-       for (i = 0; i < 2; i++) {
-               r = platform_get_resource(pdev, IORESOURCE_DMA, i);
-               if (!r) {
-                       ret = -EBUSY;
-                       goto exit;
-               }
-               dev->dmadata[i].dma_res = r;
-               ret = txx9aclc_dma_init(dev, &dev->dmadata[i]);
-               if (ret)
-                       goto exit;
-       }
-
-       snd_pcm_set_managed_buffer_all(pcm, SNDRV_DMA_TYPE_DEV,
-               card->dev, 64 * 1024, 4 * 1024 * 1024);
-       return 0;
-
-exit:
-       for (i = 0; i < 2; i++) {
-               if (dev->dmadata[i].dma_chan)
-                       dma_release_channel(dev->dmadata[i].dma_chan);
-               dev->dmadata[i].dma_chan = NULL;
-       }
-       return ret;
-}
-
-static bool filter(struct dma_chan *chan, void *param)
-{
-       struct txx9aclc_dmadata *dmadata = param;
-       char *devname;
-       bool found = false;
-
-       devname = kasprintf(GFP_KERNEL, "%s.%d", dmadata->dma_res->name,
-               (int)dmadata->dma_res->start);
-       if (strcmp(dev_name(chan->device->dev), devname) == 0) {
-               chan->private = &dmadata->dma_slave;
-               found = true;
-       }
-       kfree(devname);
-       return found;
-}
-
-static int txx9aclc_dma_init(struct txx9aclc_soc_device *dev,
-                            struct txx9aclc_dmadata *dmadata)
-{
-       struct txx9aclc_plat_drvdata *drvdata = txx9aclc_drvdata;
-       struct txx9dmac_slave *ds = &dmadata->dma_slave;
-       dma_cap_mask_t mask;
-
-       spin_lock_init(&dmadata->dma_lock);
-
-       ds->reg_width = sizeof(u32);
-       if (dmadata->stream == SNDRV_PCM_STREAM_PLAYBACK) {
-               ds->tx_reg = drvdata->physbase + ACAUDODAT;
-               ds->rx_reg = 0;
-       } else {
-               ds->tx_reg = 0;
-               ds->rx_reg = drvdata->physbase + ACAUDIDAT;
-       }
-
-       /* Try to grab a DMA channel */
-       dma_cap_zero(mask);
-       dma_cap_set(DMA_SLAVE, mask);
-       dmadata->dma_chan = dma_request_channel(mask, filter, dmadata);
-       if (!dmadata->dma_chan) {
-               printk(KERN_ERR
-                       "DMA channel for %s is not available\n",
-                       dmadata->stream == SNDRV_PCM_STREAM_PLAYBACK ?
-                       "playback" : "capture");
-               return -EBUSY;
-       }
-       INIT_WORK(&dmadata->work, txx9aclc_dma_work);
-       return 0;
-}
-
-static int txx9aclc_pcm_probe(struct snd_soc_component *component)
-{
-       snd_soc_component_set_drvdata(component, &txx9aclc_soc_device);
-       return 0;
-}
-
-static void txx9aclc_pcm_remove(struct snd_soc_component *component)
-{
-       struct txx9aclc_soc_device *dev = snd_soc_component_get_drvdata(component);
-       struct txx9aclc_plat_drvdata *drvdata = txx9aclc_drvdata;
-       void __iomem *base = drvdata->base;
-       int i;
-
-       /* disable all FIFO DMAs */
-       __raw_writel(ACCTL_AUDODMA | ACCTL_AUDIDMA, base + ACCTLDIS);
-       /* dummy R/W to clear pending DMAREQ if any */
-       __raw_writel(__raw_readl(base + ACAUDIDAT), base + ACAUDODAT);
-
-       for (i = 0; i < 2; i++) {
-               struct txx9aclc_dmadata *dmadata = &dev->dmadata[i];
-               struct dma_chan *chan = dmadata->dma_chan;
-
-               if (chan) {
-                       dmadata->frag_count = -1;
-                       dmaengine_terminate_all(chan);
-                       dma_release_channel(chan);
-               }
-               dev->dmadata[i].dma_chan = NULL;
-       }
-}
-
-static const struct snd_soc_component_driver txx9aclc_soc_component = {
-       .name           = DRV_NAME,
-       .probe          = txx9aclc_pcm_probe,
-       .remove         = txx9aclc_pcm_remove,
-       .open           = txx9aclc_pcm_open,
-       .close          = txx9aclc_pcm_close,
-       .hw_params      = txx9aclc_pcm_hw_params,
-       .prepare        = txx9aclc_pcm_prepare,
-       .trigger        = txx9aclc_pcm_trigger,
-       .pointer        = txx9aclc_pcm_pointer,
-       .pcm_construct  = txx9aclc_pcm_new,
-};
-
-static int txx9aclc_soc_platform_probe(struct platform_device *pdev)
-{
-       return devm_snd_soc_register_component(&pdev->dev,
-                                       &txx9aclc_soc_component, NULL, 0);
-}
-
-static struct platform_driver txx9aclc_pcm_driver = {
-       .driver = {
-                       .name = "txx9aclc-pcm-audio",
-       },
-
-       .probe = txx9aclc_soc_platform_probe,
-};
-
-module_platform_driver(txx9aclc_pcm_driver);
-
-MODULE_AUTHOR("Atsushi Nemoto <anemo@mba.ocn.ne.jp>");
-MODULE_DESCRIPTION("TXx9 ACLC Audio DMA driver");
-MODULE_LICENSE("GPL");
diff --git a/sound/soc/txx9/txx9aclc.h b/sound/soc/txx9/txx9aclc.h
deleted file mode 100644 (file)
index 37c691b..0000000
+++ /dev/null
@@ -1,71 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0-only */
-/*
- * TXx9 SoC AC Link Controller
- */
-
-#ifndef __TXX9ACLC_H
-#define __TXX9ACLC_H
-
-#include <linux/interrupt.h>
-#include <asm/txx9/dmac.h>
-
-#define ACCTLEN                        0x00    /* control enable */
-#define ACCTLDIS               0x04    /* control disable */
-#define   ACCTL_ENLINK         0x00000001      /* enable/disable AC-link */
-#define   ACCTL_AUDODMA                0x00000100      /* AUDODMA enable/disable */
-#define   ACCTL_AUDIDMA                0x00001000      /* AUDIDMA enable/disable */
-#define   ACCTL_AUDOEHLT       0x00010000      /* AUDO error halt
-                                                  enable/disable */
-#define   ACCTL_AUDIEHLT       0x00100000      /* AUDI error halt
-                                                  enable/disable */
-#define ACREGACC               0x08    /* codec register access */
-#define   ACREGACC_DAT_SHIFT   0       /* data field */
-#define   ACREGACC_REG_SHIFT   16      /* address field */
-#define   ACREGACC_CODECID_SHIFT       24      /* CODEC ID field */
-#define   ACREGACC_READ                0x80000000      /* CODEC read */
-#define   ACREGACC_WRITE       0x00000000      /* CODEC write */
-#define ACINTSTS               0x10    /* interrupt status */
-#define ACINTMSTS              0x14    /* interrupt masked status */
-#define ACINTEN                        0x18    /* interrupt enable */
-#define ACINTDIS               0x1c    /* interrupt disable */
-#define   ACINT_CODECRDY(n)    (0x00000001 << (n))     /* CODECn ready */
-#define   ACINT_REGACCRDY      0x00000010      /* ACREGACC ready */
-#define   ACINT_AUDOERR                0x00000100      /* AUDO underrun error */
-#define   ACINT_AUDIERR                0x00001000      /* AUDI overrun error */
-#define ACDMASTS               0x80    /* DMA request status */
-#define   ACDMA_AUDO           0x00000001      /* AUDODMA pending */
-#define   ACDMA_AUDI           0x00000010      /* AUDIDMA pending */
-#define ACAUDODAT              0xa0    /* audio out data */
-#define ACAUDIDAT              0xb0    /* audio in data */
-#define ACREVID                        0xfc    /* revision ID */
-
-struct txx9aclc_dmadata {
-       struct resource *dma_res;
-       struct txx9dmac_slave dma_slave;
-       struct dma_chan *dma_chan;
-       struct work_struct work;
-       spinlock_t dma_lock;
-       int stream; /* SNDRV_PCM_STREAM_PLAYBACK or SNDRV_PCM_STREAM_CAPTURE */
-       struct snd_pcm_substream *substream;
-       unsigned long pos;
-       dma_addr_t dma_addr;
-       unsigned long buffer_bytes;
-       unsigned long period_bytes;
-       unsigned long frag_bytes;
-       int frags;
-       int frag_count;
-       int dmacount;
-};
-
-struct txx9aclc_plat_drvdata {
-       void __iomem *base;
-       u64 physbase;
-};
-
-static inline struct txx9aclc_plat_drvdata *txx9aclc_get_plat_drvdata(
-       struct snd_soc_dai *dai)
-{
-       return dev_get_drvdata(dai->dev);
-}
-
-#endif /* __TXX9ACLC_H */
diff --git a/sound/soc/zte/Kconfig b/sound/soc/zte/Kconfig
deleted file mode 100644 (file)
index a23d4f1..0000000
+++ /dev/null
@@ -1,26 +0,0 @@
-# SPDX-License-Identifier: GPL-2.0-only
-config ZX_SPDIF
-       tristate "ZTE ZX SPDIF Driver Support"
-       depends on ARCH_ZX || COMPILE_TEST
-       depends on COMMON_CLK
-       select SND_SOC_GENERIC_DMAENGINE_PCM
-       help
-         Say Y or M if you want to add support for codecs attached to the
-         ZTE ZX SPDIF interface
-
-config ZX_I2S
-       tristate "ZTE ZX I2S Driver Support"
-       depends on ARCH_ZX || COMPILE_TEST
-       depends on COMMON_CLK
-       select SND_SOC_GENERIC_DMAENGINE_PCM
-       help
-         Say Y or M if you want to add support for codecs attached to the
-         ZTE ZX I2S interface
-
-config ZX_TDM
-       tristate "ZTE ZX TDM Driver Support"
-       depends on COMMON_CLK
-       select SND_SOC_GENERIC_DMAENGINE_PCM
-       help
-         Say Y or M if you want to add support for codecs attached to the
-         ZTE ZX TDM interface
diff --git a/sound/soc/zte/Makefile b/sound/soc/zte/Makefile
deleted file mode 100644 (file)
index 2f7cdef..0000000
+++ /dev/null
@@ -1,4 +0,0 @@
-# SPDX-License-Identifier: GPL-2.0-only
-obj-$(CONFIG_ZX_SPDIF) += zx-spdif.o
-obj-$(CONFIG_ZX_I2S)   += zx-i2s.o
-obj-$(CONFIG_ZX_TDM)   += zx-tdm.o
diff --git a/sound/soc/zte/zx-i2s.c b/sound/soc/zte/zx-i2s.c
deleted file mode 100644 (file)
index 1c1a44e..0000000
+++ /dev/null
@@ -1,452 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-/*
- * Copyright (C) 2015 Linaro
- *
- * Author: Jun Nie <jun.nie@linaro.org>
- */
-
-#include <linux/clk.h>
-#include <linux/device.h>
-#include <linux/init.h>
-#include <linux/io.h>
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <sound/pcm.h>
-#include <sound/pcm_params.h>
-#include <sound/soc.h>
-#include <sound/soc-dai.h>
-
-#include <sound/core.h>
-#include <sound/dmaengine_pcm.h>
-#include <sound/initval.h>
-
-#define ZX_I2S_PROCESS_CTRL    0x04
-#define ZX_I2S_TIMING_CTRL     0x08
-#define        ZX_I2S_FIFO_CTRL        0x0C
-#define        ZX_I2S_FIFO_STATUS      0x10
-#define ZX_I2S_INT_EN          0x14
-#define ZX_I2S_INT_STATUS      0x18
-#define ZX_I2S_DATA            0x1C
-#define ZX_I2S_FRAME_CNTR      0x20
-
-#define I2S_DEAGULT_FIFO_THRES (0x10)
-#define I2S_MAX_FIFO_THRES     (0x20)
-
-#define ZX_I2S_PROCESS_TX_EN   (1 << 0)
-#define ZX_I2S_PROCESS_TX_DIS  (0 << 0)
-#define ZX_I2S_PROCESS_RX_EN   (1 << 1)
-#define ZX_I2S_PROCESS_RX_DIS  (0 << 1)
-#define ZX_I2S_PROCESS_I2S_EN  (1 << 2)
-#define ZX_I2S_PROCESS_I2S_DIS (0 << 2)
-
-#define ZX_I2S_TIMING_MAST             (1 << 0)
-#define ZX_I2S_TIMING_SLAVE            (0 << 0)
-#define ZX_I2S_TIMING_MS_MASK          (1 << 0)
-#define ZX_I2S_TIMING_LOOP             (1 << 1)
-#define ZX_I2S_TIMING_NOR              (0 << 1)
-#define ZX_I2S_TIMING_LOOP_MASK                (1 << 1)
-#define ZX_I2S_TIMING_PTNR             (1 << 2)
-#define ZX_I2S_TIMING_NTPR             (0 << 2)
-#define ZX_I2S_TIMING_PHASE_MASK       (1 << 2)
-#define ZX_I2S_TIMING_TDM              (1 << 3)
-#define ZX_I2S_TIMING_I2S              (0 << 3)
-#define ZX_I2S_TIMING_TIMING_MASK      (1 << 3)
-#define ZX_I2S_TIMING_LONG_SYNC                (1 << 4)
-#define ZX_I2S_TIMING_SHORT_SYNC       (0 << 4)
-#define ZX_I2S_TIMING_SYNC_MASK                (1 << 4)
-#define ZX_I2S_TIMING_TEAK_EN          (1 << 5)
-#define ZX_I2S_TIMING_TEAK_DIS         (0 << 5)
-#define ZX_I2S_TIMING_TEAK_MASK                (1 << 5)
-#define ZX_I2S_TIMING_STD_I2S          (0 << 6)
-#define ZX_I2S_TIMING_MSB_JUSTIF       (1 << 6)
-#define ZX_I2S_TIMING_LSB_JUSTIF       (2 << 6)
-#define ZX_I2S_TIMING_ALIGN_MASK       (3 << 6)
-#define ZX_I2S_TIMING_CHN_MASK         (7 << 8)
-#define ZX_I2S_TIMING_CHN(x)           ((x - 1) << 8)
-#define ZX_I2S_TIMING_LANE_MASK                (3 << 11)
-#define ZX_I2S_TIMING_LANE(x)          ((x - 1) << 11)
-#define ZX_I2S_TIMING_TSCFG_MASK       (7 << 13)
-#define ZX_I2S_TIMING_TSCFG(x)         (x << 13)
-#define ZX_I2S_TIMING_TS_WIDTH_MASK    (0x1f << 16)
-#define ZX_I2S_TIMING_TS_WIDTH(x)      ((x - 1) << 16)
-#define ZX_I2S_TIMING_DATA_SIZE_MASK   (0x1f << 21)
-#define ZX_I2S_TIMING_DATA_SIZE(x)     ((x - 1) << 21)
-#define ZX_I2S_TIMING_CFG_ERR_MASK     (1 << 31)
-
-#define ZX_I2S_FIFO_CTRL_TX_RST                (1 << 0)
-#define ZX_I2S_FIFO_CTRL_TX_RST_MASK   (1 << 0)
-#define ZX_I2S_FIFO_CTRL_RX_RST                (1 << 1)
-#define ZX_I2S_FIFO_CTRL_RX_RST_MASK   (1 << 1)
-#define ZX_I2S_FIFO_CTRL_TX_DMA_EN     (1 << 4)
-#define ZX_I2S_FIFO_CTRL_TX_DMA_DIS    (0 << 4)
-#define ZX_I2S_FIFO_CTRL_TX_DMA_MASK   (1 << 4)
-#define ZX_I2S_FIFO_CTRL_RX_DMA_EN     (1 << 5)
-#define ZX_I2S_FIFO_CTRL_RX_DMA_DIS    (0 << 5)
-#define ZX_I2S_FIFO_CTRL_RX_DMA_MASK   (1 << 5)
-#define ZX_I2S_FIFO_CTRL_TX_THRES_MASK (0x1F << 8)
-#define ZX_I2S_FIFO_CTRL_RX_THRES_MASK (0x1F << 16)
-
-#define CLK_RAT (32 * 4)
-
-struct zx_i2s_info {
-       struct snd_dmaengine_dai_dma_data       dma_playback;
-       struct snd_dmaengine_dai_dma_data       dma_capture;
-       struct clk                              *dai_wclk;
-       struct clk                              *dai_pclk;
-       void __iomem                            *reg_base;
-       int                                     master;
-       resource_size_t                         mapbase;
-};
-
-static void zx_i2s_tx_en(void __iomem *base, bool on)
-{
-       unsigned long val;
-
-       val = readl_relaxed(base + ZX_I2S_PROCESS_CTRL);
-       if (on)
-               val |= ZX_I2S_PROCESS_TX_EN | ZX_I2S_PROCESS_I2S_EN;
-       else
-               val &= ~(ZX_I2S_PROCESS_TX_EN | ZX_I2S_PROCESS_I2S_EN);
-       writel_relaxed(val, base + ZX_I2S_PROCESS_CTRL);
-}
-
-static void zx_i2s_rx_en(void __iomem *base, bool on)
-{
-       unsigned long val;
-
-       val = readl_relaxed(base + ZX_I2S_PROCESS_CTRL);
-       if (on)
-               val |= ZX_I2S_PROCESS_RX_EN | ZX_I2S_PROCESS_I2S_EN;
-       else
-               val &= ~(ZX_I2S_PROCESS_RX_EN | ZX_I2S_PROCESS_I2S_EN);
-       writel_relaxed(val, base + ZX_I2S_PROCESS_CTRL);
-}
-
-static void zx_i2s_tx_dma_en(void __iomem *base, bool on)
-{
-       unsigned long val;
-
-       val = readl_relaxed(base + ZX_I2S_FIFO_CTRL);
-       val |= ZX_I2S_FIFO_CTRL_TX_RST | (I2S_DEAGULT_FIFO_THRES << 8);
-       if (on)
-               val |= ZX_I2S_FIFO_CTRL_TX_DMA_EN;
-       else
-               val &= ~ZX_I2S_FIFO_CTRL_TX_DMA_EN;
-       writel_relaxed(val, base + ZX_I2S_FIFO_CTRL);
-}
-
-static void zx_i2s_rx_dma_en(void __iomem *base, bool on)
-{
-       unsigned long val;
-
-       val = readl_relaxed(base + ZX_I2S_FIFO_CTRL);
-       val |= ZX_I2S_FIFO_CTRL_RX_RST | (I2S_DEAGULT_FIFO_THRES << 16);
-       if (on)
-               val |= ZX_I2S_FIFO_CTRL_RX_DMA_EN;
-       else
-               val &= ~ZX_I2S_FIFO_CTRL_RX_DMA_EN;
-       writel_relaxed(val, base + ZX_I2S_FIFO_CTRL);
-}
-
-#define ZX_I2S_RATES \
-       (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 | SNDRV_PCM_RATE_16000 | \
-        SNDRV_PCM_RATE_22050 | 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)
-
-#define ZX_I2S_FMTBIT \
-       (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE | \
-       SNDRV_PCM_FMTBIT_S32_LE)
-
-static int zx_i2s_dai_probe(struct snd_soc_dai *dai)
-{
-       struct zx_i2s_info *zx_i2s = dev_get_drvdata(dai->dev);
-
-       snd_soc_dai_set_drvdata(dai, zx_i2s);
-       zx_i2s->dma_playback.addr = zx_i2s->mapbase + ZX_I2S_DATA;
-       zx_i2s->dma_playback.maxburst = 16;
-       zx_i2s->dma_capture.addr = zx_i2s->mapbase + ZX_I2S_DATA;
-       zx_i2s->dma_capture.maxburst = 16;
-       snd_soc_dai_init_dma_data(dai, &zx_i2s->dma_playback,
-                                 &zx_i2s->dma_capture);
-       return 0;
-}
-
-static int zx_i2s_set_fmt(struct snd_soc_dai *cpu_dai, unsigned int fmt)
-{
-       struct zx_i2s_info *i2s = snd_soc_dai_get_drvdata(cpu_dai);
-       unsigned long val;
-
-       val = readl_relaxed(i2s->reg_base + ZX_I2S_TIMING_CTRL);
-       val &= ~(ZX_I2S_TIMING_TIMING_MASK | ZX_I2S_TIMING_ALIGN_MASK |
-                       ZX_I2S_TIMING_TEAK_MASK | ZX_I2S_TIMING_SYNC_MASK |
-                       ZX_I2S_TIMING_MS_MASK);
-
-       switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
-       case SND_SOC_DAIFMT_I2S:
-               val |= (ZX_I2S_TIMING_I2S | ZX_I2S_TIMING_STD_I2S);
-               break;
-       case SND_SOC_DAIFMT_LEFT_J:
-               val |= (ZX_I2S_TIMING_I2S | ZX_I2S_TIMING_MSB_JUSTIF);
-               break;
-       case SND_SOC_DAIFMT_RIGHT_J:
-               val |= (ZX_I2S_TIMING_I2S | ZX_I2S_TIMING_LSB_JUSTIF);
-               break;
-       default:
-               dev_err(cpu_dai->dev, "Unknown i2s timing\n");
-               return -EINVAL;
-       }
-
-       switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
-       case SND_SOC_DAIFMT_CBM_CFM:
-               /* Codec is master, and I2S is slave. */
-               i2s->master = 0;
-               val |= ZX_I2S_TIMING_SLAVE;
-               break;
-       case SND_SOC_DAIFMT_CBS_CFS:
-               /* Codec is slave, and I2S is master. */
-               i2s->master = 1;
-               val |= ZX_I2S_TIMING_MAST;
-               break;
-       default:
-               dev_err(cpu_dai->dev, "Unknown master/slave format\n");
-               return -EINVAL;
-       }
-
-       writel_relaxed(val, i2s->reg_base + ZX_I2S_TIMING_CTRL);
-       return 0;
-}
-
-static int zx_i2s_hw_params(struct snd_pcm_substream *substream,
-                           struct snd_pcm_hw_params *params,
-                           struct snd_soc_dai *socdai)
-{
-       struct zx_i2s_info *i2s = snd_soc_dai_get_drvdata(socdai);
-       struct snd_dmaengine_dai_dma_data *dma_data;
-       unsigned int lane, ch_num, len, ret = 0;
-       unsigned int ts_width = 32;
-       unsigned long val;
-       unsigned long chn_cfg;
-
-       dma_data = snd_soc_dai_get_dma_data(socdai, substream);
-       dma_data->addr_width = ts_width >> 3;
-
-       val = readl_relaxed(i2s->reg_base + ZX_I2S_TIMING_CTRL);
-       val &= ~(ZX_I2S_TIMING_TS_WIDTH_MASK | ZX_I2S_TIMING_DATA_SIZE_MASK |
-               ZX_I2S_TIMING_LANE_MASK | ZX_I2S_TIMING_CHN_MASK |
-               ZX_I2S_TIMING_TSCFG_MASK);
-
-       switch (params_format(params)) {
-       case SNDRV_PCM_FORMAT_S16_LE:
-               len = 16;
-               break;
-       case SNDRV_PCM_FORMAT_S24_LE:
-               len = 24;
-               break;
-       case SNDRV_PCM_FORMAT_S32_LE:
-               len = 32;
-               break;
-       default:
-               dev_err(socdai->dev, "Unknown data format\n");
-               return -EINVAL;
-       }
-       val |= ZX_I2S_TIMING_TS_WIDTH(ts_width) | ZX_I2S_TIMING_DATA_SIZE(len);
-
-       ch_num = params_channels(params);
-       switch (ch_num) {
-       case 1:
-               lane = 1;
-               chn_cfg = 2;
-               break;
-       case 2:
-       case 4:
-       case 6:
-       case 8:
-               lane = ch_num / 2;
-               chn_cfg = 3;
-               break;
-       default:
-               dev_err(socdai->dev, "Not support channel num %d\n", ch_num);
-               return -EINVAL;
-       }
-       val |= ZX_I2S_TIMING_LANE(lane);
-       val |= ZX_I2S_TIMING_TSCFG(chn_cfg);
-       val |= ZX_I2S_TIMING_CHN(ch_num);
-       writel_relaxed(val, i2s->reg_base + ZX_I2S_TIMING_CTRL);
-
-       if (i2s->master)
-               ret = clk_set_rate(i2s->dai_wclk,
-                               params_rate(params) * ch_num * CLK_RAT);
-
-       return ret;
-}
-
-static int zx_i2s_trigger(struct snd_pcm_substream *substream, int cmd,
-                         struct snd_soc_dai *dai)
-{
-       struct zx_i2s_info *zx_i2s = dev_get_drvdata(dai->dev);
-       int capture = (substream->stream == SNDRV_PCM_STREAM_CAPTURE);
-       int ret = 0;
-
-       switch (cmd) {
-       case SNDRV_PCM_TRIGGER_START:
-               if (capture)
-                       zx_i2s_rx_dma_en(zx_i2s->reg_base, true);
-               else
-                       zx_i2s_tx_dma_en(zx_i2s->reg_base, true);
-               fallthrough;
-       case SNDRV_PCM_TRIGGER_RESUME:
-       case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
-               if (capture)
-                       zx_i2s_rx_en(zx_i2s->reg_base, true);
-               else
-                       zx_i2s_tx_en(zx_i2s->reg_base, true);
-               break;
-
-       case SNDRV_PCM_TRIGGER_STOP:
-               if (capture)
-                       zx_i2s_rx_dma_en(zx_i2s->reg_base, false);
-               else
-                       zx_i2s_tx_dma_en(zx_i2s->reg_base, false);
-               fallthrough;
-       case SNDRV_PCM_TRIGGER_SUSPEND:
-       case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
-               if (capture)
-                       zx_i2s_rx_en(zx_i2s->reg_base, false);
-               else
-                       zx_i2s_tx_en(zx_i2s->reg_base, false);
-               break;
-
-       default:
-               ret = -EINVAL;
-               break;
-       }
-
-       return ret;
-}
-
-static int zx_i2s_startup(struct snd_pcm_substream *substream,
-                         struct snd_soc_dai *dai)
-{
-       struct zx_i2s_info *zx_i2s = dev_get_drvdata(dai->dev);
-       int ret;
-
-       ret = clk_prepare_enable(zx_i2s->dai_wclk);
-       if (ret)
-               return ret;
-
-       ret = clk_prepare_enable(zx_i2s->dai_pclk);
-       if (ret) {
-               clk_disable_unprepare(zx_i2s->dai_wclk);
-               return ret;
-       }
-
-       return ret;
-}
-
-static void zx_i2s_shutdown(struct snd_pcm_substream *substream,
-                           struct snd_soc_dai *dai)
-{
-       struct zx_i2s_info *zx_i2s = dev_get_drvdata(dai->dev);
-
-       clk_disable_unprepare(zx_i2s->dai_wclk);
-       clk_disable_unprepare(zx_i2s->dai_pclk);
-}
-
-static const struct snd_soc_dai_ops zx_i2s_dai_ops = {
-       .trigger        = zx_i2s_trigger,
-       .hw_params      = zx_i2s_hw_params,
-       .set_fmt        = zx_i2s_set_fmt,
-       .startup        = zx_i2s_startup,
-       .shutdown       = zx_i2s_shutdown,
-};
-
-static const struct snd_soc_component_driver zx_i2s_component = {
-       .name                   = "zx-i2s",
-};
-
-static struct snd_soc_dai_driver zx_i2s_dai = {
-       .name   = "zx-i2s-dai",
-       .id     = 0,
-       .probe  = zx_i2s_dai_probe,
-       .playback   = {
-               .channels_min   = 1,
-               .channels_max   = 8,
-               .rates          = ZX_I2S_RATES,
-               .formats        = ZX_I2S_FMTBIT,
-       },
-       .capture = {
-               .channels_min   = 1,
-               .channels_max   = 2,
-               .rates          = ZX_I2S_RATES,
-               .formats        = ZX_I2S_FMTBIT,
-       },
-       .ops    = &zx_i2s_dai_ops,
-};
-
-static int zx_i2s_probe(struct platform_device *pdev)
-{
-       struct resource *res;
-       struct zx_i2s_info *zx_i2s;
-       int ret;
-
-       zx_i2s = devm_kzalloc(&pdev->dev, sizeof(*zx_i2s), GFP_KERNEL);
-       if (!zx_i2s)
-               return -ENOMEM;
-
-       zx_i2s->dai_wclk = devm_clk_get(&pdev->dev, "wclk");
-       if (IS_ERR(zx_i2s->dai_wclk)) {
-               dev_err(&pdev->dev, "Fail to get wclk\n");
-               return PTR_ERR(zx_i2s->dai_wclk);
-       }
-
-       zx_i2s->dai_pclk = devm_clk_get(&pdev->dev, "pclk");
-       if (IS_ERR(zx_i2s->dai_pclk)) {
-               dev_err(&pdev->dev, "Fail to get pclk\n");
-               return PTR_ERR(zx_i2s->dai_pclk);
-       }
-
-       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       zx_i2s->mapbase = res->start;
-       zx_i2s->reg_base = devm_ioremap_resource(&pdev->dev, res);
-       if (IS_ERR(zx_i2s->reg_base)) {
-               dev_err(&pdev->dev, "ioremap failed!\n");
-               return PTR_ERR(zx_i2s->reg_base);
-       }
-
-       writel_relaxed(0, zx_i2s->reg_base + ZX_I2S_FIFO_CTRL);
-       platform_set_drvdata(pdev, zx_i2s);
-
-       ret = devm_snd_soc_register_component(&pdev->dev, &zx_i2s_component,
-                                             &zx_i2s_dai, 1);
-       if (ret) {
-               dev_err(&pdev->dev, "Register DAI failed: %d\n", ret);
-               return ret;
-       }
-
-       ret = devm_snd_dmaengine_pcm_register(&pdev->dev, NULL, 0);
-       if (ret)
-               dev_err(&pdev->dev, "Register platform PCM failed: %d\n", ret);
-
-       return ret;
-}
-
-static const struct of_device_id zx_i2s_dt_ids[] = {
-       { .compatible = "zte,zx296702-i2s", },
-       {}
-};
-MODULE_DEVICE_TABLE(of, zx_i2s_dt_ids);
-
-static struct platform_driver i2s_driver = {
-       .probe = zx_i2s_probe,
-       .driver = {
-               .name = "zx-i2s",
-               .of_match_table = zx_i2s_dt_ids,
-       },
-};
-
-module_platform_driver(i2s_driver);
-
-MODULE_AUTHOR("Jun Nie <jun.nie@linaro.org>");
-MODULE_DESCRIPTION("ZTE I2S SoC DAI");
-MODULE_LICENSE("GPL");
diff --git a/sound/soc/zte/zx-spdif.c b/sound/soc/zte/zx-spdif.c
deleted file mode 100644 (file)
index b4168bd..0000000
+++ /dev/null
@@ -1,363 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-/*
- * Copyright (C) 2015 Linaro
- *
- * Author: Jun Nie <jun.nie@linaro.org>
- */
-
-#include <linux/clk.h>
-#include <linux/device.h>
-#include <linux/dmaengine.h>
-#include <linux/init.h>
-#include <linux/io.h>
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/of_address.h>
-#include <sound/asoundef.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>
-#include <sound/soc-dai.h>
-
-#define ZX_CTRL                                0x04
-#define ZX_FIFOCTRL                    0x08
-#define ZX_INT_STATUS                  0x10
-#define ZX_INT_MASK                    0x14
-#define ZX_DATA                                0x18
-#define ZX_VALID_BIT                   0x1c
-#define ZX_CH_STA_1                    0x20
-#define ZX_CH_STA_2                    0x24
-#define ZX_CH_STA_3                    0x28
-#define ZX_CH_STA_4                    0x2c
-#define ZX_CH_STA_5                    0x30
-#define ZX_CH_STA_6                    0x34
-
-#define ZX_CTRL_MODA_16                        (0 << 6)
-#define ZX_CTRL_MODA_18                        BIT(6)
-#define ZX_CTRL_MODA_20                        (2 << 6)
-#define ZX_CTRL_MODA_24                        (3 << 6)
-#define ZX_CTRL_MODA_MASK              (3 << 6)
-
-#define ZX_CTRL_ENB                    BIT(4)
-#define ZX_CTRL_DNB                    (0 << 4)
-#define ZX_CTRL_ENB_MASK               BIT(4)
-
-#define ZX_CTRL_TX_OPEN                        BIT(0)
-#define ZX_CTRL_TX_CLOSE               (0 << 0)
-#define ZX_CTRL_TX_MASK                        BIT(0)
-
-#define ZX_CTRL_OPEN                   (ZX_CTRL_TX_OPEN | ZX_CTRL_ENB)
-#define ZX_CTRL_CLOSE                  (ZX_CTRL_TX_CLOSE | ZX_CTRL_DNB)
-
-#define ZX_CTRL_DOUBLE_TRACK           (0 << 8)
-#define ZX_CTRL_LEFT_TRACK             BIT(8)
-#define ZX_CTRL_RIGHT_TRACK            (2 << 8)
-#define ZX_CTRL_TRACK_MASK             (3 << 8)
-
-#define ZX_FIFOCTRL_TXTH_MASK          (0x1f << 8)
-#define ZX_FIFOCTRL_TXTH(x)            (x << 8)
-#define ZX_FIFOCTRL_TX_DMA_EN          BIT(2)
-#define ZX_FIFOCTRL_TX_DMA_DIS         (0 << 2)
-#define ZX_FIFOCTRL_TX_DMA_EN_MASK     BIT(2)
-#define ZX_FIFOCTRL_TX_FIFO_RST                BIT(0)
-#define ZX_FIFOCTRL_TX_FIFO_RST_MASK   BIT(0)
-
-#define ZX_VALID_DOUBLE_TRACK          (0 << 0)
-#define ZX_VALID_LEFT_TRACK            BIT(1)
-#define ZX_VALID_RIGHT_TRACK           (2 << 0)
-#define ZX_VALID_TRACK_MASK            (3 << 0)
-
-#define ZX_SPDIF_CLK_RAT               (2 * 32)
-
-struct zx_spdif_info {
-       struct snd_dmaengine_dai_dma_data       dma_data;
-       struct clk                              *dai_clk;
-       void __iomem                            *reg_base;
-       resource_size_t                         mapbase;
-};
-
-static int zx_spdif_dai_probe(struct snd_soc_dai *dai)
-{
-       struct zx_spdif_info *zx_spdif = dev_get_drvdata(dai->dev);
-
-       snd_soc_dai_set_drvdata(dai, zx_spdif);
-       zx_spdif->dma_data.addr = zx_spdif->mapbase + ZX_DATA;
-       zx_spdif->dma_data.maxburst = 8;
-       snd_soc_dai_init_dma_data(dai, &zx_spdif->dma_data, NULL);
-       return 0;
-}
-
-static int zx_spdif_chanstats(void __iomem *base, unsigned int rate)
-{
-       u32 cstas1;
-
-       switch (rate) {
-       case 22050:
-               cstas1 = IEC958_AES3_CON_FS_22050;
-               break;
-       case 24000:
-               cstas1 = IEC958_AES3_CON_FS_24000;
-               break;
-       case 32000:
-               cstas1 = IEC958_AES3_CON_FS_32000;
-               break;
-       case 44100:
-               cstas1 = IEC958_AES3_CON_FS_44100;
-               break;
-       case 48000:
-               cstas1 = IEC958_AES3_CON_FS_48000;
-               break;
-       case 88200:
-               cstas1 = IEC958_AES3_CON_FS_88200;
-               break;
-       case 96000:
-               cstas1 = IEC958_AES3_CON_FS_96000;
-               break;
-       case 176400:
-               cstas1 = IEC958_AES3_CON_FS_176400;
-               break;
-       case 192000:
-               cstas1 = IEC958_AES3_CON_FS_192000;
-               break;
-       default:
-               return -EINVAL;
-       }
-       cstas1 = cstas1 << 24;
-       cstas1 |= IEC958_AES0_CON_NOT_COPYRIGHT;
-
-       writel_relaxed(cstas1, base + ZX_CH_STA_1);
-       return 0;
-}
-
-static int zx_spdif_hw_params(struct snd_pcm_substream *substream,
-                             struct snd_pcm_hw_params *params,
-                             struct snd_soc_dai *socdai)
-{
-       struct zx_spdif_info *zx_spdif = dev_get_drvdata(socdai->dev);
-       struct zx_spdif_info *spdif = snd_soc_dai_get_drvdata(socdai);
-       struct snd_dmaengine_dai_dma_data *dma_data =
-               snd_soc_dai_get_dma_data(socdai, substream);
-       u32 val, ch_num, rate;
-       int ret;
-
-       dma_data->addr_width = params_width(params) >> 3;
-
-       val = readl_relaxed(zx_spdif->reg_base + ZX_CTRL);
-       val &= ~ZX_CTRL_MODA_MASK;
-       switch (params_format(params)) {
-       case SNDRV_PCM_FORMAT_S16_LE:
-               val |= ZX_CTRL_MODA_16;
-               break;
-
-       case SNDRV_PCM_FORMAT_S18_3LE:
-               val |= ZX_CTRL_MODA_18;
-               break;
-
-       case SNDRV_PCM_FORMAT_S20_3LE:
-               val |= ZX_CTRL_MODA_20;
-               break;
-
-       case SNDRV_PCM_FORMAT_S24_LE:
-               val |= ZX_CTRL_MODA_24;
-               break;
-       default:
-               dev_err(socdai->dev, "Format not support!\n");
-               return -EINVAL;
-       }
-
-       ch_num = params_channels(params);
-       if (ch_num == 2)
-               val |= ZX_CTRL_DOUBLE_TRACK;
-       else
-               val |= ZX_CTRL_LEFT_TRACK;
-       writel_relaxed(val, zx_spdif->reg_base + ZX_CTRL);
-
-       val = readl_relaxed(zx_spdif->reg_base + ZX_VALID_BIT);
-       val &= ~ZX_VALID_TRACK_MASK;
-       if (ch_num == 2)
-               val |= ZX_VALID_DOUBLE_TRACK;
-       else
-               val |= ZX_VALID_RIGHT_TRACK;
-       writel_relaxed(val, zx_spdif->reg_base + ZX_VALID_BIT);
-
-       rate = params_rate(params);
-       ret = zx_spdif_chanstats(zx_spdif->reg_base, rate);
-       if (ret)
-               return ret;
-       return clk_set_rate(spdif->dai_clk, rate * ch_num * ZX_SPDIF_CLK_RAT);
-}
-
-static void zx_spdif_cfg_tx(void __iomem *base, int on)
-{
-       u32 val;
-
-       val = readl_relaxed(base + ZX_CTRL);
-       val &= ~(ZX_CTRL_ENB_MASK | ZX_CTRL_TX_MASK);
-       val |= on ? ZX_CTRL_OPEN : ZX_CTRL_CLOSE;
-       writel_relaxed(val, base + ZX_CTRL);
-
-       val = readl_relaxed(base + ZX_FIFOCTRL);
-       val &= ~ZX_FIFOCTRL_TX_DMA_EN_MASK;
-       if (on)
-               val |= ZX_FIFOCTRL_TX_DMA_EN;
-       writel_relaxed(val, base + ZX_FIFOCTRL);
-}
-
-static int zx_spdif_trigger(struct snd_pcm_substream *substream, int cmd,
-                           struct snd_soc_dai *dai)
-{
-       u32 val;
-       struct zx_spdif_info *zx_spdif = dev_get_drvdata(dai->dev);
-       int  ret = 0;
-
-       switch (cmd) {
-       case SNDRV_PCM_TRIGGER_START:
-               val = readl_relaxed(zx_spdif->reg_base + ZX_FIFOCTRL);
-               val |= ZX_FIFOCTRL_TX_FIFO_RST;
-               writel_relaxed(val, zx_spdif->reg_base + ZX_FIFOCTRL);
-               fallthrough;
-       case SNDRV_PCM_TRIGGER_RESUME:
-       case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
-               zx_spdif_cfg_tx(zx_spdif->reg_base, true);
-               break;
-
-       case SNDRV_PCM_TRIGGER_STOP:
-       case SNDRV_PCM_TRIGGER_SUSPEND:
-       case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
-               zx_spdif_cfg_tx(zx_spdif->reg_base, false);
-               break;
-
-       default:
-               ret = -EINVAL;
-               break;
-       }
-
-       return ret;
-}
-
-static int zx_spdif_startup(struct snd_pcm_substream *substream,
-                           struct snd_soc_dai *dai)
-{
-       struct zx_spdif_info *zx_spdif = dev_get_drvdata(dai->dev);
-
-       return clk_prepare_enable(zx_spdif->dai_clk);
-}
-
-static void zx_spdif_shutdown(struct snd_pcm_substream *substream,
-                             struct snd_soc_dai *dai)
-{
-       struct zx_spdif_info *zx_spdif = dev_get_drvdata(dai->dev);
-
-       clk_disable_unprepare(zx_spdif->dai_clk);
-}
-
-#define ZX_RATES \
-       (SNDRV_PCM_RATE_22050 | 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)
-
-#define ZX_FORMAT \
-       (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S18_3LE \
-       | SNDRV_PCM_FMTBIT_S20_3LE | SNDRV_PCM_FMTBIT_S24_LE)
-
-static const struct snd_soc_dai_ops zx_spdif_dai_ops = {
-       .trigger        = zx_spdif_trigger,
-       .startup        = zx_spdif_startup,
-       .shutdown       = zx_spdif_shutdown,
-       .hw_params      = zx_spdif_hw_params,
-};
-
-static struct snd_soc_dai_driver zx_spdif_dai = {
-       .name = "spdif",
-       .id = 0,
-       .probe = zx_spdif_dai_probe,
-       .playback = {
-               .channels_min = 1,
-               .channels_max = 2,
-               .rates = ZX_RATES,
-               .formats = ZX_FORMAT,
-       },
-       .ops = &zx_spdif_dai_ops,
-};
-
-static const struct snd_soc_component_driver zx_spdif_component = {
-       .name   = "spdif",
-};
-
-static void zx_spdif_dev_init(void __iomem *base)
-{
-       u32 val;
-
-       writel_relaxed(0, base + ZX_CTRL);
-       writel_relaxed(0, base + ZX_INT_MASK);
-       writel_relaxed(0xf, base + ZX_INT_STATUS);
-       writel_relaxed(0x1, base + ZX_FIFOCTRL);
-
-       val = readl_relaxed(base + ZX_FIFOCTRL);
-       val &= ~(ZX_FIFOCTRL_TXTH_MASK | ZX_FIFOCTRL_TX_FIFO_RST_MASK);
-       val |= ZX_FIFOCTRL_TXTH(8);
-       writel_relaxed(val, base + ZX_FIFOCTRL);
-}
-
-static int zx_spdif_probe(struct platform_device *pdev)
-{
-       struct resource *res;
-       struct zx_spdif_info *zx_spdif;
-       int ret;
-
-       zx_spdif = devm_kzalloc(&pdev->dev, sizeof(*zx_spdif), GFP_KERNEL);
-       if (!zx_spdif)
-               return -ENOMEM;
-
-       zx_spdif->dai_clk = devm_clk_get(&pdev->dev, "tx");
-       if (IS_ERR(zx_spdif->dai_clk)) {
-               dev_err(&pdev->dev, "Fail to get clk\n");
-               return PTR_ERR(zx_spdif->dai_clk);
-       }
-
-       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       zx_spdif->mapbase = res->start;
-       zx_spdif->reg_base = devm_ioremap_resource(&pdev->dev, res);
-       if (IS_ERR(zx_spdif->reg_base)) {
-               return PTR_ERR(zx_spdif->reg_base);
-       }
-
-       zx_spdif_dev_init(zx_spdif->reg_base);
-       platform_set_drvdata(pdev, zx_spdif);
-
-       ret = devm_snd_soc_register_component(&pdev->dev, &zx_spdif_component,
-                                        &zx_spdif_dai, 1);
-       if (ret) {
-               dev_err(&pdev->dev, "Register DAI failed: %d\n", ret);
-               return ret;
-       }
-
-       ret = devm_snd_dmaengine_pcm_register(&pdev->dev, NULL, 0);
-       if (ret)
-               dev_err(&pdev->dev, "Register platform PCM failed: %d\n", ret);
-
-       return ret;
-}
-
-static const struct of_device_id zx_spdif_dt_ids[] = {
-       { .compatible = "zte,zx296702-spdif", },
-       {}
-};
-MODULE_DEVICE_TABLE(of, zx_spdif_dt_ids);
-
-static struct platform_driver spdif_driver = {
-       .probe = zx_spdif_probe,
-       .driver = {
-               .name = "zx-spdif",
-               .of_match_table = zx_spdif_dt_ids,
-       },
-};
-
-module_platform_driver(spdif_driver);
-
-MODULE_AUTHOR("Jun Nie <jun.nie@linaro.org>");
-MODULE_DESCRIPTION("ZTE SPDIF SoC DAI");
-MODULE_LICENSE("GPL");
diff --git a/sound/soc/zte/zx-tdm.c b/sound/soc/zte/zx-tdm.c
deleted file mode 100644 (file)
index 4f78718..0000000
+++ /dev/null
@@ -1,458 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-/*
- * ZTE's TDM driver
- *
- * Copyright (C) 2017 ZTE Ltd
- *
- * Author: Baoyou Xie <baoyou.xie@linaro.org>
- */
-
-#include <linux/clk.h>
-#include <linux/io.h>
-#include <linux/mfd/syscon.h>
-#include <linux/module.h>
-#include <sound/dmaengine_pcm.h>
-#include <sound/pcm_params.h>
-#include <sound/soc.h>
-#include <sound/soc-dai.h>
-
-#define        REG_TIMING_CTRL         0x04
-#define        REG_TX_FIFO_CTRL        0x0C
-#define        REG_RX_FIFO_CTRL        0x10
-#define REG_INT_EN             0x1C
-#define REG_INT_STATUS         0x20
-#define REG_DATABUF            0x24
-#define REG_TS_MASK0           0x44
-#define REG_PROCESS_CTRL       0x54
-
-#define FIFO_CTRL_TX_RST       BIT(0)
-#define FIFO_CTRL_RX_RST       BIT(0)
-#define DEAGULT_FIFO_THRES     GENMASK(4, 2)
-
-#define FIFO_CTRL_TX_DMA_EN    BIT(1)
-#define FIFO_CTRL_RX_DMA_EN    BIT(1)
-
-#define TX_FIFO_RST_MASK       BIT(0)
-#define RX_FIFO_RST_MASK       BIT(0)
-
-#define FIFOCTRL_TX_FIFO_RST   BIT(0)
-#define FIFOCTRL_RX_FIFO_RST   BIT(0)
-
-#define TXTH_MASK              GENMASK(5, 2)
-#define RXTH_MASK              GENMASK(5, 2)
-
-#define FIFOCTRL_THRESHOLD(x)  ((x) << 2)
-
-#define TIMING_MS_MASK         BIT(1)
-/*
- * 00: 8 clk cycles every timeslot
- * 01: 16 clk cycles every timeslot
- * 10: 32 clk cycles every timeslot
- */
-#define TIMING_SYNC_WIDTH_MASK GENMASK(6, 5)
-#define TIMING_WIDTH_SHIFT      5
-#define TIMING_DEFAULT_WIDTH    0
-#define TIMING_TS_WIDTH(x)     ((x) << TIMING_WIDTH_SHIFT)
-#define TIMING_WIDTH_FACTOR     8
-
-#define TIMING_MASTER_MODE     BIT(21)
-#define TIMING_LSB_FIRST       BIT(20)
-#define TIMING_TS_NUM(x)       (((x) - 1) << 7)
-#define TIMING_CLK_SEL_MASK    GENMASK(2, 0)
-#define TIMING_CLK_SEL_DEF     BIT(2)
-
-#define PROCESS_TX_EN          BIT(0)
-#define PROCESS_RX_EN          BIT(1)
-#define PROCESS_TDM_EN         BIT(2)
-#define PROCESS_DISABLE_ALL    0
-
-#define INT_DISABLE_ALL                0
-#define INT_STATUS_MASK                GENMASK(6, 0)
-
-struct zx_tdm_info {
-       struct snd_dmaengine_dai_dma_data       dma_playback;
-       struct snd_dmaengine_dai_dma_data       dma_capture;
-       resource_size_t                         phy_addr;
-       void __iomem                            *regbase;
-       struct clk                              *dai_wclk;
-       struct clk                              *dai_pclk;
-       int                                     master;
-       struct device                           *dev;
-};
-
-static inline u32 zx_tdm_readl(struct zx_tdm_info *tdm, u16 reg)
-{
-       return readl_relaxed(tdm->regbase + reg);
-}
-
-static inline void zx_tdm_writel(struct zx_tdm_info *tdm, u16 reg, u32 val)
-{
-       writel_relaxed(val, tdm->regbase + reg);
-}
-
-static void zx_tdm_tx_en(struct zx_tdm_info *tdm, bool on)
-{
-       unsigned long val;
-
-       val = zx_tdm_readl(tdm, REG_PROCESS_CTRL);
-       if (on)
-               val |= PROCESS_TX_EN | PROCESS_TDM_EN;
-       else
-               val &= ~(PROCESS_TX_EN | PROCESS_TDM_EN);
-       zx_tdm_writel(tdm, REG_PROCESS_CTRL, val);
-}
-
-static void zx_tdm_rx_en(struct zx_tdm_info *tdm, bool on)
-{
-       unsigned long val;
-
-       val = zx_tdm_readl(tdm, REG_PROCESS_CTRL);
-       if (on)
-               val |= PROCESS_RX_EN | PROCESS_TDM_EN;
-       else
-               val &= ~(PROCESS_RX_EN | PROCESS_TDM_EN);
-       zx_tdm_writel(tdm, REG_PROCESS_CTRL, val);
-}
-
-static void zx_tdm_tx_dma_en(struct zx_tdm_info *tdm, bool on)
-{
-       unsigned long val;
-
-       val = zx_tdm_readl(tdm, REG_TX_FIFO_CTRL);
-       val |= FIFO_CTRL_TX_RST | DEAGULT_FIFO_THRES;
-       if (on)
-               val |= FIFO_CTRL_TX_DMA_EN;
-       else
-               val &= ~FIFO_CTRL_TX_DMA_EN;
-       zx_tdm_writel(tdm, REG_TX_FIFO_CTRL, val);
-}
-
-static void zx_tdm_rx_dma_en(struct zx_tdm_info *tdm, bool on)
-{
-       unsigned long val;
-
-       val = zx_tdm_readl(tdm, REG_RX_FIFO_CTRL);
-       val |= FIFO_CTRL_RX_RST | DEAGULT_FIFO_THRES;
-       if (on)
-               val |= FIFO_CTRL_RX_DMA_EN;
-       else
-               val &= ~FIFO_CTRL_RX_DMA_EN;
-       zx_tdm_writel(tdm, REG_RX_FIFO_CTRL, val);
-}
-
-#define ZX_TDM_RATES   (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000)
-
-#define ZX_TDM_FMTBIT \
-       (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_MU_LAW | \
-       SNDRV_PCM_FMTBIT_A_LAW)
-
-static int zx_tdm_dai_probe(struct snd_soc_dai *dai)
-{
-       struct zx_tdm_info *zx_tdm = dev_get_drvdata(dai->dev);
-
-       snd_soc_dai_set_drvdata(dai, zx_tdm);
-       zx_tdm->dma_playback.addr = zx_tdm->phy_addr + REG_DATABUF;
-       zx_tdm->dma_playback.maxburst = 16;
-       zx_tdm->dma_capture.addr = zx_tdm->phy_addr + REG_DATABUF;
-       zx_tdm->dma_capture.maxburst = 16;
-       snd_soc_dai_init_dma_data(dai, &zx_tdm->dma_playback,
-                                 &zx_tdm->dma_capture);
-       return 0;
-}
-
-static int zx_tdm_set_fmt(struct snd_soc_dai *cpu_dai, unsigned int fmt)
-{
-       struct zx_tdm_info *tdm = snd_soc_dai_get_drvdata(cpu_dai);
-       unsigned long val;
-
-       val = zx_tdm_readl(tdm, REG_TIMING_CTRL);
-       val &= ~(TIMING_SYNC_WIDTH_MASK | TIMING_MS_MASK);
-       val |= TIMING_DEFAULT_WIDTH << TIMING_WIDTH_SHIFT;
-
-       switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
-       case SND_SOC_DAIFMT_CBM_CFM:
-               tdm->master = 1;
-               val |= TIMING_MASTER_MODE;
-               break;
-       case SND_SOC_DAIFMT_CBS_CFS:
-               tdm->master = 0;
-               val &= ~TIMING_MASTER_MODE;
-               break;
-       default:
-               dev_err(cpu_dai->dev, "Unknown master/slave format\n");
-               return -EINVAL;
-       }
-
-
-       zx_tdm_writel(tdm, REG_TIMING_CTRL, val);
-
-       return 0;
-}
-
-static int zx_tdm_hw_params(struct snd_pcm_substream *substream,
-                           struct snd_pcm_hw_params *params,
-                           struct snd_soc_dai *socdai)
-{
-       struct zx_tdm_info *tdm = snd_soc_dai_get_drvdata(socdai);
-       struct snd_dmaengine_dai_dma_data *dma_data;
-       unsigned int ts_width = TIMING_DEFAULT_WIDTH;
-       unsigned int ch_num = 32;
-       unsigned int mask = 0;
-       unsigned int ret = 0;
-       unsigned long val;
-
-       dma_data = snd_soc_dai_get_dma_data(socdai, substream);
-       dma_data->addr_width = ch_num >> 3;
-
-       switch (params_format(params)) {
-       case SNDRV_PCM_FORMAT_MU_LAW:
-       case SNDRV_PCM_FORMAT_A_LAW:
-       case SNDRV_PCM_FORMAT_S16_LE:
-               ts_width = 1;
-               break;
-       default:
-               dev_err(socdai->dev, "Unknown data format\n");
-               return -EINVAL;
-       }
-
-       val = zx_tdm_readl(tdm, REG_TIMING_CTRL);
-       val |= TIMING_TS_WIDTH(ts_width) | TIMING_TS_NUM(1);
-       zx_tdm_writel(tdm, REG_TIMING_CTRL, val);
-       zx_tdm_writel(tdm, REG_TS_MASK0, mask);
-
-       if (tdm->master)
-               ret = clk_set_rate(tdm->dai_wclk,
-                       params_rate(params) * TIMING_WIDTH_FACTOR * ch_num);
-
-       return ret;
-}
-
-static int zx_tdm_trigger(struct snd_pcm_substream *substream, int cmd,
-                         struct snd_soc_dai *dai)
-{
-       int capture = (substream->stream == SNDRV_PCM_STREAM_CAPTURE);
-       struct zx_tdm_info *zx_tdm = dev_get_drvdata(dai->dev);
-       unsigned int val;
-       int ret = 0;
-
-       switch (cmd) {
-       case SNDRV_PCM_TRIGGER_START:
-               if (capture) {
-                       val = zx_tdm_readl(zx_tdm, REG_RX_FIFO_CTRL);
-                       val |= FIFOCTRL_RX_FIFO_RST;
-                       zx_tdm_writel(zx_tdm, REG_RX_FIFO_CTRL, val);
-
-                       zx_tdm_rx_dma_en(zx_tdm, true);
-               } else {
-                       val = zx_tdm_readl(zx_tdm, REG_TX_FIFO_CTRL);
-                       val |= FIFOCTRL_TX_FIFO_RST;
-                       zx_tdm_writel(zx_tdm, REG_TX_FIFO_CTRL, val);
-
-                       zx_tdm_tx_dma_en(zx_tdm, true);
-               }
-               break;
-       case SNDRV_PCM_TRIGGER_RESUME:
-       case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
-               if (capture)
-                       zx_tdm_rx_en(zx_tdm, true);
-               else
-                       zx_tdm_tx_en(zx_tdm, true);
-               break;
-       case SNDRV_PCM_TRIGGER_STOP:
-               if (capture)
-                       zx_tdm_rx_dma_en(zx_tdm, false);
-               else
-                       zx_tdm_tx_dma_en(zx_tdm, false);
-               break;
-       case SNDRV_PCM_TRIGGER_SUSPEND:
-       case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
-               if (capture)
-                       zx_tdm_rx_en(zx_tdm, false);
-               else
-                       zx_tdm_tx_en(zx_tdm, false);
-               break;
-       default:
-               ret = -EINVAL;
-               break;
-       }
-
-       return ret;
-}
-
-static int zx_tdm_startup(struct snd_pcm_substream *substream,
-                         struct snd_soc_dai *dai)
-{
-       struct zx_tdm_info *zx_tdm = dev_get_drvdata(dai->dev);
-       int ret;
-
-       ret = clk_prepare_enable(zx_tdm->dai_wclk);
-       if (ret)
-               return ret;
-
-       ret = clk_prepare_enable(zx_tdm->dai_pclk);
-       if (ret) {
-               clk_disable_unprepare(zx_tdm->dai_wclk);
-               return ret;
-       }
-
-       return 0;
-}
-
-static void zx_tdm_shutdown(struct snd_pcm_substream *substream,
-                           struct snd_soc_dai *dai)
-{
-       struct zx_tdm_info *zx_tdm = dev_get_drvdata(dai->dev);
-
-       clk_disable_unprepare(zx_tdm->dai_pclk);
-       clk_disable_unprepare(zx_tdm->dai_wclk);
-}
-
-static const struct snd_soc_dai_ops zx_tdm_dai_ops = {
-       .trigger        = zx_tdm_trigger,
-       .hw_params      = zx_tdm_hw_params,
-       .set_fmt        = zx_tdm_set_fmt,
-       .startup        = zx_tdm_startup,
-       .shutdown       = zx_tdm_shutdown,
-};
-
-static const struct snd_soc_component_driver zx_tdm_component = {
-       .name                   = "zx-tdm",
-};
-
-static void zx_tdm_init_state(struct zx_tdm_info *tdm)
-{
-       unsigned int val;
-
-       zx_tdm_writel(tdm, REG_PROCESS_CTRL, PROCESS_DISABLE_ALL);
-
-       val = zx_tdm_readl(tdm, REG_TIMING_CTRL);
-       val |= TIMING_LSB_FIRST;
-       val &= ~TIMING_CLK_SEL_MASK;
-       val |= TIMING_CLK_SEL_DEF;
-       zx_tdm_writel(tdm, REG_TIMING_CTRL, val);
-
-       zx_tdm_writel(tdm, REG_INT_EN, INT_DISABLE_ALL);
-       /*
-        * write INT_STATUS register to clear it.
-        */
-       zx_tdm_writel(tdm, REG_INT_STATUS, INT_STATUS_MASK);
-       zx_tdm_writel(tdm, REG_RX_FIFO_CTRL, FIFOCTRL_RX_FIFO_RST);
-       zx_tdm_writel(tdm, REG_TX_FIFO_CTRL, FIFOCTRL_TX_FIFO_RST);
-
-       val = zx_tdm_readl(tdm, REG_RX_FIFO_CTRL);
-       val &= ~(RXTH_MASK | RX_FIFO_RST_MASK);
-       val |= FIFOCTRL_THRESHOLD(8);
-       zx_tdm_writel(tdm, REG_RX_FIFO_CTRL, val);
-
-       val = zx_tdm_readl(tdm, REG_TX_FIFO_CTRL);
-       val &= ~(TXTH_MASK | TX_FIFO_RST_MASK);
-       val |= FIFOCTRL_THRESHOLD(8);
-       zx_tdm_writel(tdm, REG_TX_FIFO_CTRL, val);
-}
-
-static struct snd_soc_dai_driver zx_tdm_dai = {
-       .name   = "zx-tdm-dai",
-       .id     = 0,
-       .probe  = zx_tdm_dai_probe,
-       .playback   = {
-               .channels_min   = 1,
-               .channels_max   = 4,
-               .rates          = ZX_TDM_RATES,
-               .formats        = ZX_TDM_FMTBIT,
-       },
-       .capture = {
-               .channels_min   = 1,
-               .channels_max   = 4,
-               .rates          = ZX_TDM_RATES,
-               .formats        = ZX_TDM_FMTBIT,
-       },
-       .ops    = &zx_tdm_dai_ops,
-};
-
-static int zx_tdm_probe(struct platform_device *pdev)
-{
-       struct of_phandle_args out_args;
-       unsigned int dma_reg_offset;
-       struct zx_tdm_info *zx_tdm;
-       unsigned int dma_mask;
-       struct resource *res;
-       struct regmap *regmap_sysctrl;
-       int ret;
-
-       zx_tdm = devm_kzalloc(&pdev->dev, sizeof(*zx_tdm), GFP_KERNEL);
-       if (!zx_tdm)
-               return -ENOMEM;
-
-       zx_tdm->dev = &pdev->dev;
-
-       zx_tdm->dai_wclk = devm_clk_get(&pdev->dev, "wclk");
-       if (IS_ERR(zx_tdm->dai_wclk)) {
-               dev_err(&pdev->dev, "Fail to get wclk\n");
-               return PTR_ERR(zx_tdm->dai_wclk);
-       }
-
-       zx_tdm->dai_pclk = devm_clk_get(&pdev->dev, "pclk");
-       if (IS_ERR(zx_tdm->dai_pclk)) {
-               dev_err(&pdev->dev, "Fail to get pclk\n");
-               return PTR_ERR(zx_tdm->dai_pclk);
-       }
-
-       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       zx_tdm->phy_addr = res->start;
-       zx_tdm->regbase = devm_ioremap_resource(&pdev->dev, res);
-       if (IS_ERR(zx_tdm->regbase))
-               return PTR_ERR(zx_tdm->regbase);
-
-       ret = of_parse_phandle_with_fixed_args(pdev->dev.of_node,
-                               "zte,tdm-dma-sysctrl", 2, 0, &out_args);
-       if (ret) {
-               dev_err(&pdev->dev, "Fail to get zte,tdm-dma-sysctrl\n");
-               return ret;
-       }
-
-       dma_reg_offset = out_args.args[0];
-       dma_mask = out_args.args[1];
-       regmap_sysctrl = syscon_node_to_regmap(out_args.np);
-       if (IS_ERR(regmap_sysctrl)) {
-               of_node_put(out_args.np);
-               return PTR_ERR(regmap_sysctrl);
-       }
-
-       regmap_update_bits(regmap_sysctrl, dma_reg_offset, dma_mask, dma_mask);
-       of_node_put(out_args.np);
-
-       zx_tdm_init_state(zx_tdm);
-       platform_set_drvdata(pdev, zx_tdm);
-
-       ret = devm_snd_soc_register_component(&pdev->dev, &zx_tdm_component,
-                                               &zx_tdm_dai, 1);
-       if (ret) {
-               dev_err(&pdev->dev, "Register DAI failed: %d\n", ret);
-               return ret;
-       }
-
-       ret = devm_snd_dmaengine_pcm_register(&pdev->dev, NULL, 0);
-       if (ret)
-               dev_err(&pdev->dev, "Register platform PCM failed: %d\n", ret);
-
-       return ret;
-}
-
-static const struct of_device_id zx_tdm_dt_ids[] = {
-       { .compatible = "zte,zx296718-tdm", },
-       {}
-};
-MODULE_DEVICE_TABLE(of, zx_tdm_dt_ids);
-
-static struct platform_driver tdm_driver = {
-       .probe = zx_tdm_probe,
-       .driver = {
-               .name = "zx-tdm",
-               .of_match_table = zx_tdm_dt_ids,
-       },
-};
-module_platform_driver(tdm_driver);
-
-MODULE_AUTHOR("Baoyou Xie <baoyou.xie@linaro.org>");
-MODULE_DESCRIPTION("ZTE TDM DAI driver");
-MODULE_LICENSE("GPL v2");
index cacd66a..a2b233f 100644 (file)
@@ -107,8 +107,8 @@ int monitor_device(const char *device_name,
                        ret = -EIO;
                        break;
                }
-               fprintf(stdout, "GPIO EVENT at %llu on line %d (%d|%d) ",
-                       event.timestamp_ns, event.offset, event.line_seqno,
+               fprintf(stdout, "GPIO EVENT at %" PRIu64 " on line %d (%d|%d) ",
+                       (uint64_t)event.timestamp_ns, event.offset, event.line_seqno,
                        event.seqno);
                switch (event.id) {
                case GPIO_V2_LINE_EVENT_RISING_EDGE:
index f229ec6..41e76d2 100644 (file)
@@ -10,6 +10,7 @@
 #include <ctype.h>
 #include <errno.h>
 #include <fcntl.h>
+#include <inttypes.h>
 #include <linux/gpio.h>
 #include <poll.h>
 #include <stdbool.h>
@@ -86,8 +87,8 @@ int main(int argc, char **argv)
                                return EXIT_FAILURE;
                        }
 
-                       printf("line %u: %s at %llu\n",
-                              chg.info.offset, event, chg.timestamp_ns);
+                       printf("line %u: %s at %" PRIu64 "\n",
+                              chg.info.offset, event, (uint64_t)chg.timestamp_ns);
                }
        }
 
index 3c3f2bc..9970a28 100644 (file)
@@ -240,11 +240,6 @@ static int btf_parse_hdr(struct btf *btf)
        }
 
        meta_left = btf->raw_size - sizeof(*hdr);
-       if (!meta_left) {
-               pr_debug("BTF has no data\n");
-               return -EINVAL;
-       }
-
        if (meta_left < hdr->str_off + hdr->str_len) {
                pr_debug("Invalid BTF total size:%u\n", btf->raw_size);
                return -EINVAL;
index cfcdbd7..17465d4 100644 (file)
@@ -367,21 +367,13 @@ static struct perf_mmap* perf_evlist__alloc_mmap(struct perf_evlist *evlist, boo
        return map;
 }
 
-static void perf_evlist__set_sid_idx(struct perf_evlist *evlist,
-                                    struct perf_evsel *evsel, int idx, int cpu,
-                                    int thread)
+static void perf_evsel__set_sid_idx(struct perf_evsel *evsel, int idx, int cpu, int thread)
 {
        struct perf_sample_id *sid = SID(evsel, cpu, thread);
 
        sid->idx = idx;
-       if (evlist->cpus && cpu >= 0)
-               sid->cpu = evlist->cpus->map[cpu];
-       else
-               sid->cpu = -1;
-       if (!evsel->system_wide && evlist->threads && thread >= 0)
-               sid->tid = perf_thread_map__pid(evlist->threads, thread);
-       else
-               sid->tid = -1;
+       sid->cpu = perf_cpu_map__cpu(evsel->cpus, cpu);
+       sid->tid = perf_thread_map__pid(evsel->threads, thread);
 }
 
 static struct perf_mmap*
@@ -500,8 +492,7 @@ mmap_per_evsel(struct perf_evlist *evlist, struct perf_evlist_mmap_ops *ops,
                        if (perf_evlist__id_add_fd(evlist, evsel, cpu, thread,
                                                   fd) < 0)
                                return -1;
-                       perf_evlist__set_sid_idx(evlist, evsel, idx, cpu,
-                                                thread);
+                       perf_evsel__set_sid_idx(evsel, idx, cpu, thread);
                }
        }
 
index 5f8d3ee..4bd3031 100644 (file)
@@ -2928,14 +2928,10 @@ int check(struct objtool_file *file)
        warnings += ret;
 
 out:
-       if (ret < 0) {
-               /*
-                *  Fatal error.  The binary is corrupt or otherwise broken in
-                *  some way, or objtool itself is broken.  Fail the kernel
-                *  build.
-                */
-               return ret;
-       }
-
+       /*
+        *  For now, don't fail the kernel build on fatal warnings.  These
+        *  errors are still fairly common due to the growing matrix of
+        *  supported toolchains and their recent pace of change.
+        */
        return 0;
 }
index be89c74..d8421e1 100644 (file)
@@ -380,8 +380,11 @@ static int read_symbols(struct elf *elf)
 
        symtab = find_section_by_name(elf, ".symtab");
        if (!symtab) {
-               WARN("missing symbol table");
-               return -1;
+               /*
+                * A missing symbol table is actually possible if it's an empty
+                * .o file.  This can happen for thunk_64.o.
+                */
+               return 0;
        }
 
        symtab_shndx = find_section_by_name(elf, ".symtab_shndx");
@@ -448,6 +451,13 @@ static int read_symbols(struct elf *elf)
                list_add(&sym->list, entry);
                elf_hash_add(elf->symbol_hash, &sym->hash, sym->idx);
                elf_hash_add(elf->symbol_name_hash, &sym->name_hash, str_hash(sym->name));
+
+               /*
+                * Don't store empty STT_NOTYPE symbols in the rbtree.  They
+                * can exist within a function, confusing the sorting.
+                */
+               if (!sym->len)
+                       rb_erase(&sym->node, &sym->sec->symbol_tree);
        }
 
        if (stats)
index edacfa9..42dad4a 100644 (file)
@@ -186,6 +186,7 @@ struct output_option {
 
 enum {
        OUTPUT_TYPE_SYNTH = PERF_TYPE_MAX,
+       OUTPUT_TYPE_OTHER,
        OUTPUT_TYPE_MAX
 };
 
@@ -283,6 +284,18 @@ static struct {
 
                .invalid_fields = PERF_OUTPUT_TRACE | PERF_OUTPUT_BPF_OUTPUT,
        },
+
+       [OUTPUT_TYPE_OTHER] = {
+               .user_set = false,
+
+               .fields = PERF_OUTPUT_COMM | PERF_OUTPUT_TID |
+                             PERF_OUTPUT_CPU | PERF_OUTPUT_TIME |
+                             PERF_OUTPUT_EVNAME | PERF_OUTPUT_IP |
+                             PERF_OUTPUT_SYM | PERF_OUTPUT_SYMOFFSET |
+                             PERF_OUTPUT_DSO | PERF_OUTPUT_PERIOD,
+
+               .invalid_fields = PERF_OUTPUT_TRACE | PERF_OUTPUT_BPF_OUTPUT,
+       },
 };
 
 struct evsel_script {
@@ -343,8 +356,11 @@ static inline int output_type(unsigned int type)
        case PERF_TYPE_SYNTH:
                return OUTPUT_TYPE_SYNTH;
        default:
-               return type;
+               if (type < PERF_TYPE_MAX)
+                       return type;
        }
+
+       return OUTPUT_TYPE_OTHER;
 }
 
 static inline unsigned int attr_type(unsigned int type)
index ee94d3e..e6d3452 100644 (file)
@@ -162,6 +162,14 @@ static bool contains_event(struct evsel **metric_events, int num_events,
        return false;
 }
 
+static bool evsel_same_pmu(struct evsel *ev1, struct evsel *ev2)
+{
+       if (!ev1->pmu_name || !ev2->pmu_name)
+               return false;
+
+       return !strcmp(ev1->pmu_name, ev2->pmu_name);
+}
+
 /**
  * Find a group of events in perf_evlist that correspond to those from a parsed
  * metric expression. Note, as find_evsel_group is called in the same order as
@@ -280,8 +288,7 @@ static struct evsel *find_evsel_group(struct evlist *perf_evlist,
                         */
                        if (!has_constraint &&
                            ev->leader != metric_events[i]->leader &&
-                           !strcmp(ev->leader->pmu_name,
-                                   metric_events[i]->leader->pmu_name))
+                           evsel_same_pmu(ev->leader, metric_events[i]->leader))
                                break;
                        if (!strcmp(metric_events[i]->name, ev->name)) {
                                set_bit(ev->idx, evlist_used);
@@ -766,7 +773,6 @@ int __weak arch_get_runtimeparam(struct pmu_event *pe __maybe_unused)
 struct metricgroup_add_iter_data {
        struct list_head *metric_list;
        const char *metric;
-       struct metric **m;
        struct expr_ids *ids;
        int *ret;
        bool *has_match;
@@ -1058,12 +1064,13 @@ static int metricgroup__add_metric_sys_event_iter(struct pmu_event *pe,
                                                  void *data)
 {
        struct metricgroup_add_iter_data *d = data;
+       struct metric *m = NULL;
        int ret;
 
        if (!match_pe_metric(pe, d->metric))
                return 0;
 
-       ret = add_metric(d->metric_list, pe, d->metric_no_group, d->m, NULL, d->ids);
+       ret = add_metric(d->metric_list, pe, d->metric_no_group, &m, NULL, d->ids);
        if (ret)
                return ret;
 
@@ -1114,7 +1121,6 @@ static int metricgroup__add_metric(const char *metric, bool metric_no_group,
                                .metric_list = &list,
                                .metric = metric,
                                .metric_no_group = metric_no_group,
-                               .m = &m,
                                .ids = &ids,
                                .has_match = &has_match,
                                .ret = &ret,
index 5390158..09cb3a6 100644 (file)
@@ -1249,6 +1249,8 @@ static void dump_isst_config(int arg)
        isst_ctdp_display_information_end(outf);
 }
 
+static void adjust_scaling_max_from_base_freq(int cpu);
+
 static void set_tdp_level_for_cpu(int cpu, void *arg1, void *arg2, void *arg3,
                                  void *arg4)
 {
@@ -1267,6 +1269,9 @@ static void set_tdp_level_for_cpu(int cpu, void *arg1, void *arg2, void *arg3,
                        int pkg_id = get_physical_package_id(cpu);
                        int die_id = get_physical_die_id(cpu);
 
+                       /* Wait for updated base frequencies */
+                       usleep(2000);
+
                        fprintf(stderr, "Option is set to online/offline\n");
                        ctdp_level.core_cpumask_size =
                                alloc_cpu_set(&ctdp_level.core_cpumask);
@@ -1283,6 +1288,7 @@ static void set_tdp_level_for_cpu(int cpu, void *arg1, void *arg2, void *arg3,
                                        if (CPU_ISSET_S(i, ctdp_level.core_cpumask_size, ctdp_level.core_cpumask)) {
                                                fprintf(stderr, "online cpu %d\n", i);
                                                set_cpu_online_offline(i, 1);
+                                               adjust_scaling_max_from_base_freq(i);
                                        } else {
                                                fprintf(stderr, "offline cpu %d\n", i);
                                                set_cpu_online_offline(i, 0);
@@ -1440,6 +1446,31 @@ static int set_cpufreq_scaling_min_max(int cpu, int max, int freq)
        return 0;
 }
 
+static int no_turbo(void)
+{
+       return parse_int_file(0, "/sys/devices/system/cpu/intel_pstate/no_turbo");
+}
+
+static void adjust_scaling_max_from_base_freq(int cpu)
+{
+       int base_freq, scaling_max_freq;
+
+       scaling_max_freq = parse_int_file(0, "/sys/devices/system/cpu/cpu%d/cpufreq/scaling_max_freq", cpu);
+       base_freq = get_cpufreq_base_freq(cpu);
+       if (scaling_max_freq < base_freq || no_turbo())
+               set_cpufreq_scaling_min_max(cpu, 1, base_freq);
+}
+
+static void adjust_scaling_min_from_base_freq(int cpu)
+{
+       int base_freq, scaling_min_freq;
+
+       scaling_min_freq = parse_int_file(0, "/sys/devices/system/cpu/cpu%d/cpufreq/scaling_min_freq", cpu);
+       base_freq = get_cpufreq_base_freq(cpu);
+       if (scaling_min_freq < base_freq)
+               set_cpufreq_scaling_min_max(cpu, 0, base_freq);
+}
+
 static int set_clx_pbf_cpufreq_scaling_min_max(int cpu)
 {
        struct isst_pkg_ctdp_level_info *ctdp_level;
@@ -1537,6 +1568,7 @@ static void set_scaling_min_to_cpuinfo_max(int cpu)
                        continue;
 
                set_cpufreq_scaling_min_max_from_cpuinfo(i, 1, 0);
+               adjust_scaling_min_from_base_freq(i);
        }
 }
 
index 389ea52..a7c4f07 100644 (file)
@@ -1834,12 +1834,15 @@ int get_mp(int cpu, struct msr_counter *mp, unsigned long long *counterp)
 int get_epb(int cpu)
 {
        char path[128 + PATH_BYTES];
+       unsigned long long msr;
        int ret, epb = -1;
        FILE *fp;
 
        sprintf(path, "/sys/devices/system/cpu/cpu%d/power/energy_perf_bias", cpu);
 
-       fp = fopen_or_die(path, "r");
+       fp = fopen(path, "r");
+       if (!fp)
+               goto msr_fallback;
 
        ret = fscanf(fp, "%d", &epb);
        if (ret != 1)
@@ -1848,6 +1851,11 @@ int get_epb(int cpu)
        fclose(fp);
 
        return epb;
+
+msr_fallback:
+       get_msr(cpu, MSR_IA32_ENERGY_PERF_BIAS, &msr);
+
+       return msr & 0xf;
 }
 
 void get_apic_id(struct thread_data *t)
index 21516e2..e808a47 100755 (executable)
@@ -43,9 +43,9 @@ class KunitStatus(Enum):
        BUILD_FAILURE = auto()
        TEST_FAILURE = auto()
 
-def get_kernel_root_path():
-       parts = sys.argv[0] if not __file__ else __file__
-       parts = os.path.realpath(parts).split('tools/testing/kunit')
+def get_kernel_root_path() -> str:
+       path = sys.argv[0] if not __file__ else __file__
+       parts = os.path.realpath(path).split('tools/testing/kunit')
        if len(parts) != 2:
                sys.exit(1)
        return parts[0]
@@ -171,7 +171,7 @@ def run_tests(linux: kunit_kernel.LinuxSourceTree,
                                exec_result.elapsed_time))
        return parse_result
 
-def add_common_opts(parser):
+def add_common_opts(parser) -> None:
        parser.add_argument('--build_dir',
                            help='As in the make command, it specifies the build '
                            'directory.',
@@ -183,13 +183,13 @@ def add_common_opts(parser):
                            help='Run all KUnit tests through allyesconfig',
                            action='store_true')
 
-def add_build_opts(parser):
+def add_build_opts(parser) -> None:
        parser.add_argument('--jobs',
                            help='As in the make command, "Specifies  the number of '
                            'jobs (commands) to run simultaneously."',
                            type=int, default=8, metavar='jobs')
 
-def add_exec_opts(parser):
+def add_exec_opts(parser) -> None:
        parser.add_argument('--timeout',
                            help='maximum number of seconds to allow for all tests '
                            'to run. This does not include time taken to build the '
@@ -198,7 +198,7 @@ def add_exec_opts(parser):
                            default=300,
                            metavar='timeout')
 
-def add_parse_opts(parser):
+def add_parse_opts(parser) -> None:
        parser.add_argument('--raw_output', help='don\'t format output from kernel',
                            action='store_true')
        parser.add_argument('--json',
@@ -256,10 +256,7 @@ def main(argv, linux=None):
                        os.mkdir(cli_args.build_dir)
 
                if not linux:
-                       linux = kunit_kernel.LinuxSourceTree()
-
-               linux.create_kunitconfig(cli_args.build_dir)
-               linux.read_kunitconfig(cli_args.build_dir)
+                       linux = kunit_kernel.LinuxSourceTree(cli_args.build_dir)
 
                request = KunitRequest(cli_args.raw_output,
                                       cli_args.timeout,
@@ -277,10 +274,7 @@ def main(argv, linux=None):
                        os.mkdir(cli_args.build_dir)
 
                if not linux:
-                       linux = kunit_kernel.LinuxSourceTree()
-
-               linux.create_kunitconfig(cli_args.build_dir)
-               linux.read_kunitconfig(cli_args.build_dir)
+                       linux = kunit_kernel.LinuxSourceTree(cli_args.build_dir)
 
                request = KunitConfigRequest(cli_args.build_dir,
                                             cli_args.make_options)
@@ -292,10 +286,7 @@ def main(argv, linux=None):
                        sys.exit(1)
        elif cli_args.subcommand == 'build':
                if not linux:
-                       linux = kunit_kernel.LinuxSourceTree()
-
-               linux.create_kunitconfig(cli_args.build_dir)
-               linux.read_kunitconfig(cli_args.build_dir)
+                       linux = kunit_kernel.LinuxSourceTree(cli_args.build_dir)
 
                request = KunitBuildRequest(cli_args.jobs,
                                            cli_args.build_dir,
@@ -309,10 +300,7 @@ def main(argv, linux=None):
                        sys.exit(1)
        elif cli_args.subcommand == 'exec':
                if not linux:
-                       linux = kunit_kernel.LinuxSourceTree()
-
-               linux.create_kunitconfig(cli_args.build_dir)
-               linux.read_kunitconfig(cli_args.build_dir)
+                       linux = kunit_kernel.LinuxSourceTree(cli_args.build_dir)
 
                exec_request = KunitExecRequest(cli_args.timeout,
                                                cli_args.build_dir,
index 02ffc3a..bdd6023 100644 (file)
@@ -8,6 +8,7 @@
 
 import collections
 import re
+from typing import List, Set
 
 CONFIG_IS_NOT_SET_PATTERN = r'^# CONFIG_(\w+) is not set$'
 CONFIG_PATTERN = r'^CONFIG_(\w+)=(\S+|".*")$'
@@ -30,10 +31,10 @@ class KconfigParseError(Exception):
 class Kconfig(object):
        """Represents defconfig or .config specified using the Kconfig language."""
 
-       def __init__(self):
-               self._entries = []
+       def __init__(self) -> None:
+               self._entries = []  # type: List[KconfigEntry]
 
-       def entries(self):
+       def entries(self) -> Set[KconfigEntry]:
                return set(self._entries)
 
        def add_entry(self, entry: KconfigEntry) -> None:
index 624b31b..f5cca5c 100644 (file)
@@ -13,7 +13,7 @@ import kunit_parser
 
 from kunit_parser import TestStatus
 
-def get_json_result(test_result, def_config, build_dir, json_path):
+def get_json_result(test_result, def_config, build_dir, json_path) -> str:
        sub_groups = []
 
        # Each test suite is mapped to a KernelCI sub_group
index 698358c..2076a5a 100644 (file)
@@ -11,6 +11,7 @@ import subprocess
 import os
 import shutil
 import signal
+from typing import Iterator
 
 from contextlib import ExitStack
 
@@ -39,7 +40,7 @@ class BuildError(Exception):
 class LinuxSourceTreeOperations(object):
        """An abstraction over command line operations performed on a source tree."""
 
-       def make_mrproper(self):
+       def make_mrproper(self) -> None:
                try:
                        subprocess.check_output(['make', 'mrproper'], stderr=subprocess.STDOUT)
                except OSError as e:
@@ -47,7 +48,7 @@ class LinuxSourceTreeOperations(object):
                except subprocess.CalledProcessError as e:
                        raise ConfigError(e.output.decode())
 
-       def make_olddefconfig(self, build_dir, make_options):
+       def make_olddefconfig(self, build_dir, make_options) -> None:
                command = ['make', 'ARCH=um', 'olddefconfig']
                if make_options:
                        command.extend(make_options)
@@ -60,7 +61,7 @@ class LinuxSourceTreeOperations(object):
                except subprocess.CalledProcessError as e:
                        raise ConfigError(e.output.decode())
 
-       def make_allyesconfig(self, build_dir, make_options):
+       def make_allyesconfig(self, build_dir, make_options) -> None:
                kunit_parser.print_with_timestamp(
                        'Enabling all CONFIGs for UML...')
                command = ['make', 'ARCH=um', 'allyesconfig']
@@ -82,7 +83,7 @@ class LinuxSourceTreeOperations(object):
                kunit_parser.print_with_timestamp(
                        'Starting Kernel with all configs takes a few minutes...')
 
-       def make(self, jobs, build_dir, make_options):
+       def make(self, jobs, build_dir, make_options) -> None:
                command = ['make', 'ARCH=um', '--jobs=' + str(jobs)]
                if make_options:
                        command.extend(make_options)
@@ -100,7 +101,7 @@ class LinuxSourceTreeOperations(object):
                if stderr:  # likely only due to build warnings
                        print(stderr.decode())
 
-       def linux_bin(self, params, timeout, build_dir):
+       def linux_bin(self, params, timeout, build_dir) -> None:
                """Runs the Linux UML binary. Must be named 'linux'."""
                linux_bin = get_file_path(build_dir, 'linux')
                outfile = get_outfile_path(build_dir)
@@ -110,41 +111,42 @@ class LinuxSourceTreeOperations(object):
                                                   stderr=subprocess.STDOUT)
                        process.wait(timeout)
 
-def get_kconfig_path(build_dir):
+def get_kconfig_path(build_dir) -> str:
        return get_file_path(build_dir, KCONFIG_PATH)
 
-def get_kunitconfig_path(build_dir):
+def get_kunitconfig_path(build_dir) -> str:
        return get_file_path(build_dir, KUNITCONFIG_PATH)
 
-def get_outfile_path(build_dir):
+def get_outfile_path(build_dir) -> str:
        return get_file_path(build_dir, OUTFILE_PATH)
 
 class LinuxSourceTree(object):
        """Represents a Linux kernel source tree with KUnit tests."""
 
-       def __init__(self):
-               self._ops = LinuxSourceTreeOperations()
+       def __init__(self, build_dir: str, load_config=True, defconfig=DEFAULT_KUNITCONFIG_PATH) -> None:
                signal.signal(signal.SIGINT, self.signal_handler)
 
-       def clean(self):
-               try:
-                       self._ops.make_mrproper()
-               except ConfigError as e:
-                       logging.error(e)
-                       return False
-               return True
+               self._ops = LinuxSourceTreeOperations()
+
+               if not load_config:
+                       return
 
-       def create_kunitconfig(self, build_dir, defconfig=DEFAULT_KUNITCONFIG_PATH):
                kunitconfig_path = get_kunitconfig_path(build_dir)
                if not os.path.exists(kunitconfig_path):
                        shutil.copyfile(defconfig, kunitconfig_path)
 
-       def read_kunitconfig(self, build_dir):
-               kunitconfig_path = get_kunitconfig_path(build_dir)
                self._kconfig = kunit_config.Kconfig()
                self._kconfig.read_from_file(kunitconfig_path)
 
-       def validate_config(self, build_dir):
+       def clean(self) -> bool:
+               try:
+                       self._ops.make_mrproper()
+               except ConfigError as e:
+                       logging.error(e)
+                       return False
+               return True
+
+       def validate_config(self, build_dir) -> bool:
                kconfig_path = get_kconfig_path(build_dir)
                validated_kconfig = kunit_config.Kconfig()
                validated_kconfig.read_from_file(kconfig_path)
@@ -158,7 +160,7 @@ class LinuxSourceTree(object):
                        return False
                return True
 
-       def build_config(self, build_dir, make_options):
+       def build_config(self, build_dir, make_options) -> bool:
                kconfig_path = get_kconfig_path(build_dir)
                if build_dir and not os.path.exists(build_dir):
                        os.mkdir(build_dir)
@@ -170,7 +172,7 @@ class LinuxSourceTree(object):
                        return False
                return self.validate_config(build_dir)
 
-       def build_reconfig(self, build_dir, make_options):
+       def build_reconfig(self, build_dir, make_options) -> bool:
                """Creates a new .config if it is not a subset of the .kunitconfig."""
                kconfig_path = get_kconfig_path(build_dir)
                if os.path.exists(kconfig_path):
@@ -186,7 +188,7 @@ class LinuxSourceTree(object):
                        print('Generating .config ...')
                        return self.build_config(build_dir, make_options)
 
-       def build_um_kernel(self, alltests, jobs, build_dir, make_options):
+       def build_um_kernel(self, alltests, jobs, build_dir, make_options) -> bool:
                try:
                        if alltests:
                                self._ops.make_allyesconfig(build_dir, make_options)
@@ -197,7 +199,7 @@ class LinuxSourceTree(object):
                        return False
                return self.validate_config(build_dir)
 
-       def run_kernel(self, args=[], build_dir='', timeout=None):
+       def run_kernel(self, args=[], build_dir='', timeout=None) -> Iterator[str]:
                args.extend(['mem=1G', 'console=tty'])
                self._ops.linux_bin(args, timeout, build_dir)
                outfile = get_outfile_path(build_dir)
@@ -206,6 +208,6 @@ class LinuxSourceTree(object):
                        for line in file:
                                yield line
 
-       def signal_handler(self, sig, frame):
+       def signal_handler(self, sig, frame) -> None:
                logging.error('Build interruption occurred. Cleaning console.')
                subprocess.call(['stty', 'sane'])
index 6614ec4..e8bcc13 100644 (file)
@@ -12,32 +12,32 @@ from collections import namedtuple
 from datetime import datetime
 from enum import Enum, auto
 from functools import reduce
-from typing import List, Optional, Tuple
+from typing import Iterable, Iterator, List, Optional, Tuple
 
 TestResult = namedtuple('TestResult', ['status','suites','log'])
 
 class TestSuite(object):
-       def __init__(self):
-               self.status = None
-               self.name = None
-               self.cases = []
+       def __init__(self) -> None:
+               self.status = TestStatus.SUCCESS
+               self.name = ''
+               self.cases = []  # type: List[TestCase]
 
-       def __str__(self):
-               return 'TestSuite(' + self.status + ',' + self.name + ',' + str(self.cases) + ')'
+       def __str__(self) -> str:
+               return 'TestSuite(' + str(self.status) + ',' + self.name + ',' + str(self.cases) + ')'
 
-       def __repr__(self):
+       def __repr__(self) -> str:
                return str(self)
 
 class TestCase(object):
-       def __init__(self):
-               self.status = None
+       def __init__(self) -> None:
+               self.status = TestStatus.SUCCESS
                self.name = ''
-               self.log = []
+               self.log = []  # type: List[str]
 
-       def __str__(self):
-               return 'TestCase(' + self.status + ',' + self.name + ',' + str(self.log) + ')'
+       def __str__(self) -> str:
+               return 'TestCase(' + str(self.status) + ',' + self.name + ',' + str(self.log) + ')'
 
-       def __repr__(self):
+       def __repr__(self) -> str:
                return str(self)
 
 class TestStatus(Enum):
@@ -51,7 +51,7 @@ kunit_start_re = re.compile(r'TAP version [0-9]+$')
 kunit_end_re = re.compile('(List of all partitions:|'
                          'Kernel panic - not syncing: VFS:)')
 
-def isolate_kunit_output(kernel_output):
+def isolate_kunit_output(kernel_output) -> Iterator[str]:
        started = False
        for line in kernel_output:
                line = line.rstrip()  # line always has a trailing \n
@@ -64,7 +64,7 @@ def isolate_kunit_output(kernel_output):
                elif started:
                        yield line[prefix_len:] if prefix_len > 0 else line
 
-def raw_output(kernel_output):
+def raw_output(kernel_output) -> None:
        for line in kernel_output:
                print(line.rstrip())
 
@@ -72,36 +72,36 @@ DIVIDER = '=' * 60
 
 RESET = '\033[0;0m'
 
-def red(text):
+def red(text) -> str:
        return '\033[1;31m' + text + RESET
 
-def yellow(text):
+def yellow(text) -> str:
        return '\033[1;33m' + text + RESET
 
-def green(text):
+def green(text) -> str:
        return '\033[1;32m' + text + RESET
 
-def print_with_timestamp(message):
+def print_with_timestamp(message) -> None:
        print('[%s] %s' % (datetime.now().strftime('%H:%M:%S'), message))
 
-def format_suite_divider(message):
+def format_suite_divider(message) -> str:
        return '======== ' + message + ' ========'
 
-def print_suite_divider(message):
+def print_suite_divider(message) -> None:
        print_with_timestamp(DIVIDER)
        print_with_timestamp(format_suite_divider(message))
 
-def print_log(log):
+def print_log(log) -> None:
        for m in log:
                print_with_timestamp(m)
 
 TAP_ENTRIES = re.compile(r'^(TAP|[\s]*ok|[\s]*not ok|[\s]*[0-9]+\.\.[0-9]+|[\s]*#).*$')
 
-def consume_non_diagnositic(lines: List[str]) -> None:
+def consume_non_diagnostic(lines: List[str]) -> None:
        while lines and not TAP_ENTRIES.match(lines[0]):
                lines.pop(0)
 
-def save_non_diagnositic(lines: List[str], test_case: TestCase) -> None:
+def save_non_diagnostic(lines: List[str], test_case: TestCase) -> None:
        while lines and not TAP_ENTRIES.match(lines[0]):
                test_case.log.append(lines[0])
                lines.pop(0)
@@ -113,7 +113,7 @@ OK_NOT_OK_SUBTEST = re.compile(r'^[\s]+(ok|not ok) [0-9]+ - (.*)$')
 OK_NOT_OK_MODULE = re.compile(r'^(ok|not ok) ([0-9]+) - (.*)$')
 
 def parse_ok_not_ok_test_case(lines: List[str], test_case: TestCase) -> bool:
-       save_non_diagnositic(lines, test_case)
+       save_non_diagnostic(lines, test_case)
        if not lines:
                test_case.status = TestStatus.TEST_CRASHED
                return True
@@ -139,7 +139,7 @@ SUBTEST_DIAGNOSTIC = re.compile(r'^[\s]+# (.*)$')
 DIAGNOSTIC_CRASH_MESSAGE = re.compile(r'^[\s]+# .*?: kunit test case crashed!$')
 
 def parse_diagnostic(lines: List[str], test_case: TestCase) -> bool:
-       save_non_diagnositic(lines, test_case)
+       save_non_diagnostic(lines, test_case)
        if not lines:
                return False
        line = lines[0]
@@ -155,7 +155,7 @@ def parse_diagnostic(lines: List[str], test_case: TestCase) -> bool:
 
 def parse_test_case(lines: List[str]) -> Optional[TestCase]:
        test_case = TestCase()
-       save_non_diagnositic(lines, test_case)
+       save_non_diagnostic(lines, test_case)
        while parse_diagnostic(lines, test_case):
                pass
        if parse_ok_not_ok_test_case(lines, test_case):
@@ -166,7 +166,7 @@ def parse_test_case(lines: List[str]) -> Optional[TestCase]:
 SUBTEST_HEADER = re.compile(r'^[\s]+# Subtest: (.*)$')
 
 def parse_subtest_header(lines: List[str]) -> Optional[str]:
-       consume_non_diagnositic(lines)
+       consume_non_diagnostic(lines)
        if not lines:
                return None
        match = SUBTEST_HEADER.match(lines[0])
@@ -179,7 +179,7 @@ def parse_subtest_header(lines: List[str]) -> Optional[str]:
 SUBTEST_PLAN = re.compile(r'[\s]+[0-9]+\.\.([0-9]+)')
 
 def parse_subtest_plan(lines: List[str]) -> Optional[int]:
-       consume_non_diagnositic(lines)
+       consume_non_diagnostic(lines)
        match = SUBTEST_PLAN.match(lines[0])
        if match:
                lines.pop(0)
@@ -202,7 +202,7 @@ def max_status(left: TestStatus, right: TestStatus) -> TestStatus:
 def parse_ok_not_ok_test_suite(lines: List[str],
                               test_suite: TestSuite,
                               expected_suite_index: int) -> bool:
-       consume_non_diagnositic(lines)
+       consume_non_diagnostic(lines)
        if not lines:
                test_suite.status = TestStatus.TEST_CRASHED
                return False
@@ -224,18 +224,17 @@ def parse_ok_not_ok_test_suite(lines: List[str],
        else:
                return False
 
-def bubble_up_errors(to_status, status_container_list) -> TestStatus:
-       status_list = map(to_status, status_container_list)
-       return reduce(max_status, status_list, TestStatus.SUCCESS)
+def bubble_up_errors(statuses: Iterable[TestStatus]) -> TestStatus:
+       return reduce(max_status, statuses, TestStatus.SUCCESS)
 
 def bubble_up_test_case_errors(test_suite: TestSuite) -> TestStatus:
-       max_test_case_status = bubble_up_errors(lambda x: x.status, test_suite.cases)
+       max_test_case_status = bubble_up_errors(x.status for x in test_suite.cases)
        return max_status(max_test_case_status, test_suite.status)
 
 def parse_test_suite(lines: List[str], expected_suite_index: int) -> Optional[TestSuite]:
        if not lines:
                return None
-       consume_non_diagnositic(lines)
+       consume_non_diagnostic(lines)
        test_suite = TestSuite()
        test_suite.status = TestStatus.SUCCESS
        name = parse_subtest_header(lines)
@@ -264,7 +263,7 @@ def parse_test_suite(lines: List[str], expected_suite_index: int) -> Optional[Te
 TAP_HEADER = re.compile(r'^TAP version 14$')
 
 def parse_tap_header(lines: List[str]) -> bool:
-       consume_non_diagnositic(lines)
+       consume_non_diagnostic(lines)
        if TAP_HEADER.match(lines[0]):
                lines.pop(0)
                return True
@@ -274,7 +273,7 @@ def parse_tap_header(lines: List[str]) -> bool:
 TEST_PLAN = re.compile(r'[0-9]+\.\.([0-9]+)')
 
 def parse_test_plan(lines: List[str]) -> Optional[int]:
-       consume_non_diagnositic(lines)
+       consume_non_diagnostic(lines)
        match = TEST_PLAN.match(lines[0])
        if match:
                lines.pop(0)
@@ -282,11 +281,11 @@ def parse_test_plan(lines: List[str]) -> Optional[int]:
        else:
                return None
 
-def bubble_up_suite_errors(test_suite_list: List[TestSuite]) -> TestStatus:
-       return bubble_up_errors(lambda x: x.status, test_suite_list)
+def bubble_up_suite_errors(test_suites: Iterable[TestSuite]) -> TestStatus:
+       return bubble_up_errors(x.status for x in test_suites)
 
 def parse_test_result(lines: List[str]) -> TestResult:
-       consume_non_diagnositic(lines)
+       consume_non_diagnostic(lines)
        if not lines or not parse_tap_header(lines):
                return TestResult(TestStatus.NO_TESTS, [], lines)
        expected_test_suite_num = parse_test_plan(lines)
index cac8910..3e3a5f5 100644 (file)
@@ -12,7 +12,8 @@ void check(void)
        BUILD_BUG_ON(!IS_MODULE(CONFIG_ND_BTT));
        BUILD_BUG_ON(!IS_MODULE(CONFIG_ND_PFN));
        BUILD_BUG_ON(!IS_MODULE(CONFIG_ND_BLK));
-       BUILD_BUG_ON(!IS_MODULE(CONFIG_ACPI_NFIT));
+       if (IS_ENABLED(CONFIG_ACPI_NFIT))
+               BUILD_BUG_ON(!IS_MODULE(CONFIG_ACPI_NFIT));
        BUILD_BUG_ON(!IS_MODULE(CONFIG_DEV_DAX));
        BUILD_BUG_ON(!IS_MODULE(CONFIG_DEV_DAX_PMEM));
 }
index 75baebf..197bcb2 100644 (file)
@@ -5,5 +5,9 @@ ccflags-y += -I$(srctree)/drivers/acpi/nfit/
 obj-m += nfit_test.o
 obj-m += nfit_test_iomap.o
 
-nfit_test-y := nfit.o
+ifeq  ($(CONFIG_ACPI_NFIT),m)
+       nfit_test-y := nfit.o
+else
+       nfit_test-y := ndtest.o
+endif
 nfit_test_iomap-y := iomap.o
diff --git a/tools/testing/nvdimm/test/ndtest.c b/tools/testing/nvdimm/test/ndtest.c
new file mode 100644 (file)
index 0000000..6862915
--- /dev/null
@@ -0,0 +1,1129 @@
+// SPDX-License-Identifier: GPL-2.0-only
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <linux/platform_device.h>
+#include <linux/device.h>
+#include <linux/module.h>
+#include <linux/genalloc.h>
+#include <linux/vmalloc.h>
+#include <linux/dma-mapping.h>
+#include <linux/list_sort.h>
+#include <linux/libnvdimm.h>
+#include <linux/ndctl.h>
+#include <nd-core.h>
+#include <linux/printk.h>
+#include <linux/seq_buf.h>
+
+#include "../watermark.h"
+#include "nfit_test.h"
+#include "ndtest.h"
+
+enum {
+       DIMM_SIZE = SZ_32M,
+       LABEL_SIZE = SZ_128K,
+       NUM_INSTANCES = 2,
+       NUM_DCR = 4,
+       NDTEST_MAX_MAPPING = 6,
+};
+
+#define NDTEST_SCM_DIMM_CMD_MASK          \
+       ((1ul << ND_CMD_GET_CONFIG_SIZE) | \
+        (1ul << ND_CMD_GET_CONFIG_DATA) | \
+        (1ul << ND_CMD_SET_CONFIG_DATA) | \
+        (1ul << ND_CMD_CALL))
+
+#define NFIT_DIMM_HANDLE(node, socket, imc, chan, dimm)                        \
+       (((node & 0xfff) << 16) | ((socket & 0xf) << 12)                \
+        | ((imc & 0xf) << 8) | ((chan & 0xf) << 4) | (dimm & 0xf))
+
+static DEFINE_SPINLOCK(ndtest_lock);
+static struct ndtest_priv *instances[NUM_INSTANCES];
+static struct class *ndtest_dimm_class;
+static struct gen_pool *ndtest_pool;
+
+static struct ndtest_dimm dimm_group1[] = {
+       {
+               .size = DIMM_SIZE,
+               .handle = NFIT_DIMM_HANDLE(0, 0, 0, 0, 0),
+               .uuid_str = "1e5c75d2-b618-11ea-9aa3-507b9ddc0f72",
+               .physical_id = 0,
+               .num_formats = 2,
+       },
+       {
+               .size = DIMM_SIZE,
+               .handle = NFIT_DIMM_HANDLE(0, 0, 0, 0, 1),
+               .uuid_str = "1c4d43ac-b618-11ea-be80-507b9ddc0f72",
+               .physical_id = 1,
+               .num_formats = 2,
+       },
+       {
+               .size = DIMM_SIZE,
+               .handle = NFIT_DIMM_HANDLE(0, 0, 1, 0, 0),
+               .uuid_str = "a9f17ffc-b618-11ea-b36d-507b9ddc0f72",
+               .physical_id = 2,
+               .num_formats = 2,
+       },
+       {
+               .size = DIMM_SIZE,
+               .handle = NFIT_DIMM_HANDLE(0, 0, 1, 0, 1),
+               .uuid_str = "b6b83b22-b618-11ea-8aae-507b9ddc0f72",
+               .physical_id = 3,
+               .num_formats = 2,
+       },
+       {
+               .size = DIMM_SIZE,
+               .handle = NFIT_DIMM_HANDLE(0, 1, 0, 0, 0),
+               .uuid_str = "bf9baaee-b618-11ea-b181-507b9ddc0f72",
+               .physical_id = 4,
+               .num_formats = 2,
+       },
+};
+
+static struct ndtest_dimm dimm_group2[] = {
+       {
+               .size = DIMM_SIZE,
+               .handle = NFIT_DIMM_HANDLE(1, 0, 0, 0, 0),
+               .uuid_str = "ca0817e2-b618-11ea-9db3-507b9ddc0f72",
+               .physical_id = 0,
+               .num_formats = 1,
+               .flags = PAPR_PMEM_UNARMED | PAPR_PMEM_EMPTY |
+                        PAPR_PMEM_SAVE_FAILED | PAPR_PMEM_SHUTDOWN_DIRTY |
+                        PAPR_PMEM_HEALTH_FATAL,
+       },
+};
+
+static struct ndtest_mapping region0_mapping[] = {
+       {
+               .dimm = 0,
+               .position = 0,
+               .start = 0,
+               .size = SZ_16M,
+       },
+       {
+               .dimm = 1,
+               .position = 1,
+               .start = 0,
+               .size = SZ_16M,
+       }
+};
+
+static struct ndtest_mapping region1_mapping[] = {
+       {
+               .dimm = 0,
+               .position = 0,
+               .start = SZ_16M,
+               .size = SZ_16M,
+       },
+       {
+               .dimm = 1,
+               .position = 1,
+               .start = SZ_16M,
+               .size = SZ_16M,
+       },
+       {
+               .dimm = 2,
+               .position = 2,
+               .start = SZ_16M,
+               .size = SZ_16M,
+       },
+       {
+               .dimm = 3,
+               .position = 3,
+               .start = SZ_16M,
+               .size = SZ_16M,
+       },
+};
+
+static struct ndtest_mapping region2_mapping[] = {
+       {
+               .dimm = 0,
+               .position = 0,
+               .start = 0,
+               .size = DIMM_SIZE,
+       },
+};
+
+static struct ndtest_mapping region3_mapping[] = {
+       {
+               .dimm = 1,
+               .start = 0,
+               .size = DIMM_SIZE,
+       }
+};
+
+static struct ndtest_mapping region4_mapping[] = {
+       {
+               .dimm = 2,
+               .start = 0,
+               .size = DIMM_SIZE,
+       }
+};
+
+static struct ndtest_mapping region5_mapping[] = {
+       {
+               .dimm = 3,
+               .start = 0,
+               .size = DIMM_SIZE,
+       }
+};
+
+static struct ndtest_region bus0_regions[] = {
+       {
+               .type = ND_DEVICE_NAMESPACE_PMEM,
+               .num_mappings = ARRAY_SIZE(region0_mapping),
+               .mapping = region0_mapping,
+               .size = DIMM_SIZE,
+               .range_index = 1,
+       },
+       {
+               .type = ND_DEVICE_NAMESPACE_PMEM,
+               .num_mappings = ARRAY_SIZE(region1_mapping),
+               .mapping = region1_mapping,
+               .size = DIMM_SIZE * 2,
+               .range_index = 2,
+       },
+       {
+               .type = ND_DEVICE_NAMESPACE_BLK,
+               .num_mappings = ARRAY_SIZE(region2_mapping),
+               .mapping = region2_mapping,
+               .size = DIMM_SIZE,
+               .range_index = 3,
+       },
+       {
+               .type = ND_DEVICE_NAMESPACE_BLK,
+               .num_mappings = ARRAY_SIZE(region3_mapping),
+               .mapping = region3_mapping,
+               .size = DIMM_SIZE,
+               .range_index = 4,
+       },
+       {
+               .type = ND_DEVICE_NAMESPACE_BLK,
+               .num_mappings = ARRAY_SIZE(region4_mapping),
+               .mapping = region4_mapping,
+               .size = DIMM_SIZE,
+               .range_index = 5,
+       },
+       {
+               .type = ND_DEVICE_NAMESPACE_BLK,
+               .num_mappings = ARRAY_SIZE(region5_mapping),
+               .mapping = region5_mapping,
+               .size = DIMM_SIZE,
+               .range_index = 6,
+       },
+};
+
+static struct ndtest_mapping region6_mapping[] = {
+       {
+               .dimm = 0,
+               .position = 0,
+               .start = 0,
+               .size = DIMM_SIZE,
+       },
+};
+
+static struct ndtest_region bus1_regions[] = {
+       {
+               .type = ND_DEVICE_NAMESPACE_IO,
+               .num_mappings = ARRAY_SIZE(region6_mapping),
+               .mapping = region6_mapping,
+               .size = DIMM_SIZE,
+               .range_index = 1,
+       },
+};
+
+static struct ndtest_config bus_configs[NUM_INSTANCES] = {
+       /* bus 1 */
+       {
+               .dimm_start = 0,
+               .dimm_count = ARRAY_SIZE(dimm_group1),
+               .dimms = dimm_group1,
+               .regions = bus0_regions,
+               .num_regions = ARRAY_SIZE(bus0_regions),
+       },
+       /* bus 2 */
+       {
+               .dimm_start = ARRAY_SIZE(dimm_group1),
+               .dimm_count = ARRAY_SIZE(dimm_group2),
+               .dimms = dimm_group2,
+               .regions = bus1_regions,
+               .num_regions = ARRAY_SIZE(bus1_regions),
+       },
+};
+
+static inline struct ndtest_priv *to_ndtest_priv(struct device *dev)
+{
+       struct platform_device *pdev = to_platform_device(dev);
+
+       return container_of(pdev, struct ndtest_priv, pdev);
+}
+
+static int ndtest_config_get(struct ndtest_dimm *p, unsigned int buf_len,
+                            struct nd_cmd_get_config_data_hdr *hdr)
+{
+       unsigned int len;
+
+       if ((hdr->in_offset + hdr->in_length) > LABEL_SIZE)
+               return -EINVAL;
+
+       hdr->status = 0;
+       len = min(hdr->in_length, LABEL_SIZE - hdr->in_offset);
+       memcpy(hdr->out_buf, p->label_area + hdr->in_offset, len);
+
+       return buf_len - len;
+}
+
+static int ndtest_config_set(struct ndtest_dimm *p, unsigned int buf_len,
+                            struct nd_cmd_set_config_hdr *hdr)
+{
+       unsigned int len;
+
+       if ((hdr->in_offset + hdr->in_length) > LABEL_SIZE)
+               return -EINVAL;
+
+       len = min(hdr->in_length, LABEL_SIZE - hdr->in_offset);
+       memcpy(p->label_area + hdr->in_offset, hdr->in_buf, len);
+
+       return buf_len - len;
+}
+
+static int ndtest_get_config_size(struct ndtest_dimm *dimm, unsigned int buf_len,
+                                 struct nd_cmd_get_config_size *size)
+{
+       size->status = 0;
+       size->max_xfer = 8;
+       size->config_size = dimm->config_size;
+
+       return 0;
+}
+
+static int ndtest_ctl(struct nvdimm_bus_descriptor *nd_desc,
+                     struct nvdimm *nvdimm, unsigned int cmd, void *buf,
+                     unsigned int buf_len, int *cmd_rc)
+{
+       struct ndtest_dimm *dimm;
+       int _cmd_rc;
+
+       if (!cmd_rc)
+               cmd_rc = &_cmd_rc;
+
+       *cmd_rc = 0;
+
+       if (!nvdimm)
+               return -EINVAL;
+
+       dimm = nvdimm_provider_data(nvdimm);
+       if (!dimm)
+               return -EINVAL;
+
+       switch (cmd) {
+       case ND_CMD_GET_CONFIG_SIZE:
+               *cmd_rc = ndtest_get_config_size(dimm, buf_len, buf);
+               break;
+       case ND_CMD_GET_CONFIG_DATA:
+               *cmd_rc = ndtest_config_get(dimm, buf_len, buf);
+               break;
+       case ND_CMD_SET_CONFIG_DATA:
+               *cmd_rc = ndtest_config_set(dimm, buf_len, buf);
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       /* Failures for a DIMM can be injected using fail_cmd and
+        * fail_cmd_code, see the device attributes below
+        */
+       if ((1 << cmd) & dimm->fail_cmd)
+               return dimm->fail_cmd_code ? dimm->fail_cmd_code : -EIO;
+
+       return 0;
+}
+
+static int ndtest_blk_do_io(struct nd_blk_region *ndbr, resource_size_t dpa,
+               void *iobuf, u64 len, int rw)
+{
+       struct ndtest_dimm *dimm = ndbr->blk_provider_data;
+       struct ndtest_blk_mmio *mmio = dimm->mmio;
+       struct nd_region *nd_region = &ndbr->nd_region;
+       unsigned int lane;
+
+       if (!mmio)
+               return -ENOMEM;
+
+       lane = nd_region_acquire_lane(nd_region);
+       if (rw)
+               memcpy(mmio->base + dpa, iobuf, len);
+       else {
+               memcpy(iobuf, mmio->base + dpa, len);
+               arch_invalidate_pmem(mmio->base + dpa, len);
+       }
+
+       nd_region_release_lane(nd_region, lane);
+
+       return 0;
+}
+
+static int ndtest_blk_region_enable(struct nvdimm_bus *nvdimm_bus,
+                                   struct device *dev)
+{
+       struct nd_blk_region *ndbr = to_nd_blk_region(dev);
+       struct nvdimm *nvdimm;
+       struct ndtest_dimm *dimm;
+       struct ndtest_blk_mmio *mmio;
+
+       nvdimm = nd_blk_region_to_dimm(ndbr);
+       dimm = nvdimm_provider_data(nvdimm);
+
+       nd_blk_region_set_provider_data(ndbr, dimm);
+       dimm->blk_region = to_nd_region(dev);
+
+       mmio = devm_kzalloc(dev, sizeof(struct ndtest_blk_mmio), GFP_KERNEL);
+       if (!mmio)
+               return -ENOMEM;
+
+       mmio->base = (void __iomem *) devm_nvdimm_memremap(
+               dev, dimm->address, 12, nd_blk_memremap_flags(ndbr));
+       if (!mmio->base) {
+               dev_err(dev, "%s failed to map blk dimm\n", nvdimm_name(nvdimm));
+               return -ENOMEM;
+       }
+       mmio->size = dimm->size;
+       mmio->base_offset = 0;
+
+       dimm->mmio = mmio;
+
+       return 0;
+}
+
+static struct nfit_test_resource *ndtest_resource_lookup(resource_size_t addr)
+{
+       int i;
+
+       for (i = 0; i < NUM_INSTANCES; i++) {
+               struct nfit_test_resource *n, *nfit_res = NULL;
+               struct ndtest_priv *t = instances[i];
+
+               if (!t)
+                       continue;
+               spin_lock(&ndtest_lock);
+               list_for_each_entry(n, &t->resources, list) {
+                       if (addr >= n->res.start && (addr < n->res.start
+                                               + resource_size(&n->res))) {
+                               nfit_res = n;
+                               break;
+                       } else if (addr >= (unsigned long) n->buf
+                                       && (addr < (unsigned long) n->buf
+                                               + resource_size(&n->res))) {
+                               nfit_res = n;
+                               break;
+                       }
+               }
+               spin_unlock(&ndtest_lock);
+               if (nfit_res)
+                       return nfit_res;
+       }
+
+       pr_warn("Failed to get resource\n");
+
+       return NULL;
+}
+
+static void ndtest_release_resource(void *data)
+{
+       struct nfit_test_resource *res  = data;
+
+       spin_lock(&ndtest_lock);
+       list_del(&res->list);
+       spin_unlock(&ndtest_lock);
+
+       if (resource_size(&res->res) >= DIMM_SIZE)
+               gen_pool_free(ndtest_pool, res->res.start,
+                               resource_size(&res->res));
+       vfree(res->buf);
+       kfree(res);
+}
+
+static void *ndtest_alloc_resource(struct ndtest_priv *p, size_t size,
+                                  dma_addr_t *dma)
+{
+       dma_addr_t __dma;
+       void *buf;
+       struct nfit_test_resource *res;
+       struct genpool_data_align data = {
+               .align = SZ_128M,
+       };
+
+       res = kzalloc(sizeof(*res), GFP_KERNEL);
+       if (!res)
+               return NULL;
+
+       buf = vmalloc(size);
+       if (size >= DIMM_SIZE)
+               __dma = gen_pool_alloc_algo(ndtest_pool, size,
+                                           gen_pool_first_fit_align, &data);
+       else
+               __dma = (unsigned long) buf;
+
+       if (!__dma)
+               goto buf_err;
+
+       INIT_LIST_HEAD(&res->list);
+       res->dev = &p->pdev.dev;
+       res->buf = buf;
+       res->res.start = __dma;
+       res->res.end = __dma + size - 1;
+       res->res.name = "NFIT";
+       spin_lock_init(&res->lock);
+       INIT_LIST_HEAD(&res->requests);
+       spin_lock(&ndtest_lock);
+       list_add(&res->list, &p->resources);
+       spin_unlock(&ndtest_lock);
+
+       if (dma)
+               *dma = __dma;
+
+       if (!devm_add_action(&p->pdev.dev, ndtest_release_resource, res))
+               return res->buf;
+
+buf_err:
+       if (__dma && size >= DIMM_SIZE)
+               gen_pool_free(ndtest_pool, __dma, size);
+       if (buf)
+               vfree(buf);
+       kfree(res);
+
+       return NULL;
+}
+
+static ssize_t range_index_show(struct device *dev,
+               struct device_attribute *attr, char *buf)
+{
+       struct nd_region *nd_region = to_nd_region(dev);
+       struct ndtest_region *region = nd_region_provider_data(nd_region);
+
+       return sprintf(buf, "%d\n", region->range_index);
+}
+static DEVICE_ATTR_RO(range_index);
+
+static struct attribute *ndtest_region_attributes[] = {
+       &dev_attr_range_index.attr,
+       NULL,
+};
+
+static const struct attribute_group ndtest_region_attribute_group = {
+       .name = "papr",
+       .attrs = ndtest_region_attributes,
+};
+
+static const struct attribute_group *ndtest_region_attribute_groups[] = {
+       &ndtest_region_attribute_group,
+       NULL,
+};
+
+static int ndtest_create_region(struct ndtest_priv *p,
+                               struct ndtest_region *region)
+{
+       struct nd_mapping_desc mappings[NDTEST_MAX_MAPPING];
+       struct nd_blk_region_desc ndbr_desc;
+       struct nd_interleave_set *nd_set;
+       struct nd_region_desc *ndr_desc;
+       struct resource res;
+       int i, ndimm = region->mapping[0].dimm;
+       u64 uuid[2];
+
+       memset(&res, 0, sizeof(res));
+       memset(&mappings, 0, sizeof(mappings));
+       memset(&ndbr_desc, 0, sizeof(ndbr_desc));
+       ndr_desc = &ndbr_desc.ndr_desc;
+
+       if (!ndtest_alloc_resource(p, region->size, &res.start))
+               return -ENOMEM;
+
+       res.end = res.start + region->size - 1;
+       ndr_desc->mapping = mappings;
+       ndr_desc->res = &res;
+       ndr_desc->provider_data = region;
+       ndr_desc->attr_groups = ndtest_region_attribute_groups;
+
+       if (uuid_parse(p->config->dimms[ndimm].uuid_str, (uuid_t *)uuid)) {
+               pr_err("failed to parse UUID\n");
+               return -ENXIO;
+       }
+
+       nd_set = devm_kzalloc(&p->pdev.dev, sizeof(*nd_set), GFP_KERNEL);
+       if (!nd_set)
+               return -ENOMEM;
+
+       nd_set->cookie1 = cpu_to_le64(uuid[0]);
+       nd_set->cookie2 = cpu_to_le64(uuid[1]);
+       nd_set->altcookie = nd_set->cookie1;
+       ndr_desc->nd_set = nd_set;
+
+       if (region->type == ND_DEVICE_NAMESPACE_BLK) {
+               mappings[0].start = 0;
+               mappings[0].size = DIMM_SIZE;
+               mappings[0].nvdimm = p->config->dimms[ndimm].nvdimm;
+
+               ndr_desc->mapping = &mappings[0];
+               ndr_desc->num_mappings = 1;
+               ndr_desc->num_lanes = 1;
+               ndbr_desc.enable = ndtest_blk_region_enable;
+               ndbr_desc.do_io = ndtest_blk_do_io;
+               region->region = nvdimm_blk_region_create(p->bus, ndr_desc);
+
+               goto done;
+       }
+
+       for (i = 0; i < region->num_mappings; i++) {
+               ndimm = region->mapping[i].dimm;
+               mappings[i].start = region->mapping[i].start;
+               mappings[i].size = region->mapping[i].size;
+               mappings[i].position = region->mapping[i].position;
+               mappings[i].nvdimm = p->config->dimms[ndimm].nvdimm;
+       }
+
+       ndr_desc->num_mappings = region->num_mappings;
+       region->region = nvdimm_pmem_region_create(p->bus, ndr_desc);
+
+done:
+       if (!region->region) {
+               dev_err(&p->pdev.dev, "Error registering region %pR\n",
+                       ndr_desc->res);
+               return -ENXIO;
+       }
+
+       return 0;
+}
+
+static int ndtest_init_regions(struct ndtest_priv *p)
+{
+       int i, ret = 0;
+
+       for (i = 0; i < p->config->num_regions; i++) {
+               ret = ndtest_create_region(p, &p->config->regions[i]);
+               if (ret)
+                       return ret;
+       }
+
+       return 0;
+}
+
+static void put_dimms(void *data)
+{
+       struct ndtest_priv *p = data;
+       int i;
+
+       for (i = 0; i < p->config->dimm_count; i++)
+               if (p->config->dimms[i].dev) {
+                       device_unregister(p->config->dimms[i].dev);
+                       p->config->dimms[i].dev = NULL;
+               }
+}
+
+static ssize_t handle_show(struct device *dev, struct device_attribute *attr,
+               char *buf)
+{
+       struct ndtest_dimm *dimm = dev_get_drvdata(dev);
+
+       return sprintf(buf, "%#x\n", dimm->handle);
+}
+static DEVICE_ATTR_RO(handle);
+
+static ssize_t fail_cmd_show(struct device *dev, struct device_attribute *attr,
+               char *buf)
+{
+       struct ndtest_dimm *dimm = dev_get_drvdata(dev);
+
+       return sprintf(buf, "%#x\n", dimm->fail_cmd);
+}
+
+static ssize_t fail_cmd_store(struct device *dev, struct device_attribute *attr,
+               const char *buf, size_t size)
+{
+       struct ndtest_dimm *dimm = dev_get_drvdata(dev);
+       unsigned long val;
+       ssize_t rc;
+
+       rc = kstrtol(buf, 0, &val);
+       if (rc)
+               return rc;
+
+       dimm->fail_cmd = val;
+
+       return size;
+}
+static DEVICE_ATTR_RW(fail_cmd);
+
+static ssize_t fail_cmd_code_show(struct device *dev, struct device_attribute *attr,
+               char *buf)
+{
+       struct ndtest_dimm *dimm = dev_get_drvdata(dev);
+
+       return sprintf(buf, "%d\n", dimm->fail_cmd_code);
+}
+
+static ssize_t fail_cmd_code_store(struct device *dev, struct device_attribute *attr,
+               const char *buf, size_t size)
+{
+       struct ndtest_dimm *dimm = dev_get_drvdata(dev);
+       unsigned long val;
+       ssize_t rc;
+
+       rc = kstrtol(buf, 0, &val);
+       if (rc)
+               return rc;
+
+       dimm->fail_cmd_code = val;
+       return size;
+}
+static DEVICE_ATTR_RW(fail_cmd_code);
+
+static struct attribute *dimm_attributes[] = {
+       &dev_attr_handle.attr,
+       &dev_attr_fail_cmd.attr,
+       &dev_attr_fail_cmd_code.attr,
+       NULL,
+};
+
+static struct attribute_group dimm_attribute_group = {
+       .attrs = dimm_attributes,
+};
+
+static const struct attribute_group *dimm_attribute_groups[] = {
+       &dimm_attribute_group,
+       NULL,
+};
+
+static ssize_t phys_id_show(struct device *dev,
+               struct device_attribute *attr, char *buf)
+{
+       struct nvdimm *nvdimm = to_nvdimm(dev);
+       struct ndtest_dimm *dimm = nvdimm_provider_data(nvdimm);
+
+       return sprintf(buf, "%#x\n", dimm->physical_id);
+}
+static DEVICE_ATTR_RO(phys_id);
+
+static ssize_t vendor_show(struct device *dev,
+                          struct device_attribute *attr, char *buf)
+{
+       return sprintf(buf, "0x1234567\n");
+}
+static DEVICE_ATTR_RO(vendor);
+
+static ssize_t id_show(struct device *dev,
+                      struct device_attribute *attr, char *buf)
+{
+       struct nvdimm *nvdimm = to_nvdimm(dev);
+       struct ndtest_dimm *dimm = nvdimm_provider_data(nvdimm);
+
+       return sprintf(buf, "%04x-%02x-%04x-%08x", 0xabcd,
+                      0xa, 2016, ~(dimm->handle));
+}
+static DEVICE_ATTR_RO(id);
+
+static ssize_t nvdimm_handle_show(struct device *dev,
+                                 struct device_attribute *attr, char *buf)
+{
+       struct nvdimm *nvdimm = to_nvdimm(dev);
+       struct ndtest_dimm *dimm = nvdimm_provider_data(nvdimm);
+
+       return sprintf(buf, "%#x\n", dimm->handle);
+}
+
+static struct device_attribute dev_attr_nvdimm_show_handle =  {
+       .attr   = { .name = "handle", .mode = 0444 },
+       .show   = nvdimm_handle_show,
+};
+
+static ssize_t subsystem_vendor_show(struct device *dev,
+               struct device_attribute *attr, char *buf)
+{
+       return sprintf(buf, "0x%04x\n", 0);
+}
+static DEVICE_ATTR_RO(subsystem_vendor);
+
+static ssize_t dirty_shutdown_show(struct device *dev,
+               struct device_attribute *attr, char *buf)
+{
+       return sprintf(buf, "%d\n", 42);
+}
+static DEVICE_ATTR_RO(dirty_shutdown);
+
+static ssize_t formats_show(struct device *dev,
+               struct device_attribute *attr, char *buf)
+{
+       struct nvdimm *nvdimm = to_nvdimm(dev);
+       struct ndtest_dimm *dimm = nvdimm_provider_data(nvdimm);
+
+       return sprintf(buf, "%d\n", dimm->num_formats);
+}
+static DEVICE_ATTR_RO(formats);
+
+static ssize_t format_show(struct device *dev,
+               struct device_attribute *attr, char *buf)
+{
+       struct nvdimm *nvdimm = to_nvdimm(dev);
+       struct ndtest_dimm *dimm = nvdimm_provider_data(nvdimm);
+
+       if (dimm->num_formats > 1)
+               return sprintf(buf, "0x201\n");
+
+       return sprintf(buf, "0x101\n");
+}
+static DEVICE_ATTR_RO(format);
+
+static ssize_t format1_show(struct device *dev, struct device_attribute *attr,
+                           char *buf)
+{
+       return sprintf(buf, "0x301\n");
+}
+static DEVICE_ATTR_RO(format1);
+
+static umode_t ndtest_nvdimm_attr_visible(struct kobject *kobj,
+                                       struct attribute *a, int n)
+{
+       struct device *dev = container_of(kobj, struct device, kobj);
+       struct nvdimm *nvdimm = to_nvdimm(dev);
+       struct ndtest_dimm *dimm = nvdimm_provider_data(nvdimm);
+
+       if (a == &dev_attr_format1.attr && dimm->num_formats <= 1)
+               return 0;
+
+       return a->mode;
+}
+
+static ssize_t flags_show(struct device *dev,
+                         struct device_attribute *attr, char *buf)
+{
+       struct nvdimm *nvdimm = to_nvdimm(dev);
+       struct ndtest_dimm *dimm = nvdimm_provider_data(nvdimm);
+       struct seq_buf s;
+       u64 flags;
+
+       flags = dimm->flags;
+
+       seq_buf_init(&s, buf, PAGE_SIZE);
+       if (flags & PAPR_PMEM_UNARMED_MASK)
+               seq_buf_printf(&s, "not_armed ");
+
+       if (flags & PAPR_PMEM_BAD_SHUTDOWN_MASK)
+               seq_buf_printf(&s, "flush_fail ");
+
+       if (flags & PAPR_PMEM_BAD_RESTORE_MASK)
+               seq_buf_printf(&s, "restore_fail ");
+
+       if (flags & PAPR_PMEM_SAVE_MASK)
+               seq_buf_printf(&s, "save_fail ");
+
+       if (flags & PAPR_PMEM_SMART_EVENT_MASK)
+               seq_buf_printf(&s, "smart_notify ");
+
+
+       if (seq_buf_used(&s))
+               seq_buf_printf(&s, "\n");
+
+       return seq_buf_used(&s);
+}
+static DEVICE_ATTR_RO(flags);
+
+static struct attribute *ndtest_nvdimm_attributes[] = {
+       &dev_attr_nvdimm_show_handle.attr,
+       &dev_attr_vendor.attr,
+       &dev_attr_id.attr,
+       &dev_attr_phys_id.attr,
+       &dev_attr_subsystem_vendor.attr,
+       &dev_attr_dirty_shutdown.attr,
+       &dev_attr_formats.attr,
+       &dev_attr_format.attr,
+       &dev_attr_format1.attr,
+       &dev_attr_flags.attr,
+       NULL,
+};
+
+static const struct attribute_group ndtest_nvdimm_attribute_group = {
+       .name = "papr",
+       .attrs = ndtest_nvdimm_attributes,
+       .is_visible = ndtest_nvdimm_attr_visible,
+};
+
+static const struct attribute_group *ndtest_nvdimm_attribute_groups[] = {
+       &ndtest_nvdimm_attribute_group,
+       NULL,
+};
+
+static int ndtest_dimm_register(struct ndtest_priv *priv,
+                               struct ndtest_dimm *dimm, int id)
+{
+       struct device *dev = &priv->pdev.dev;
+       unsigned long dimm_flags = dimm->flags;
+
+       if (dimm->num_formats > 1) {
+               set_bit(NDD_ALIASING, &dimm_flags);
+               set_bit(NDD_LABELING, &dimm_flags);
+       }
+
+       if (dimm->flags & PAPR_PMEM_UNARMED_MASK)
+               set_bit(NDD_UNARMED, &dimm_flags);
+
+       dimm->nvdimm = nvdimm_create(priv->bus, dimm,
+                                   ndtest_nvdimm_attribute_groups, dimm_flags,
+                                   NDTEST_SCM_DIMM_CMD_MASK, 0, NULL);
+       if (!dimm->nvdimm) {
+               dev_err(dev, "Error creating DIMM object for %pOF\n", priv->dn);
+               return -ENXIO;
+       }
+
+       dimm->dev = device_create_with_groups(ndtest_dimm_class,
+                                            &priv->pdev.dev,
+                                            0, dimm, dimm_attribute_groups,
+                                            "test_dimm%d", id);
+       if (!dimm->dev) {
+               pr_err("Could not create dimm device attributes\n");
+               return -ENOMEM;
+       }
+
+       return 0;
+}
+
+static int ndtest_nvdimm_init(struct ndtest_priv *p)
+{
+       struct ndtest_dimm *d;
+       void *res;
+       int i, id;
+
+       for (i = 0; i < p->config->dimm_count; i++) {
+               d = &p->config->dimms[i];
+               d->id = id = p->config->dimm_start + i;
+               res = ndtest_alloc_resource(p, LABEL_SIZE, NULL);
+               if (!res)
+                       return -ENOMEM;
+
+               d->label_area = res;
+               sprintf(d->label_area, "label%d", id);
+               d->config_size = LABEL_SIZE;
+
+               if (!ndtest_alloc_resource(p, d->size,
+                                          &p->dimm_dma[id]))
+                       return -ENOMEM;
+
+               if (!ndtest_alloc_resource(p, LABEL_SIZE,
+                                          &p->label_dma[id]))
+                       return -ENOMEM;
+
+               if (!ndtest_alloc_resource(p, LABEL_SIZE,
+                                          &p->dcr_dma[id]))
+                       return -ENOMEM;
+
+               d->address = p->dimm_dma[id];
+
+               ndtest_dimm_register(p, d, id);
+       }
+
+       return 0;
+}
+
+static ssize_t compatible_show(struct device *dev,
+                              struct device_attribute *attr, char *buf)
+{
+       return sprintf(buf, "nvdimm_test");
+}
+static DEVICE_ATTR_RO(compatible);
+
+static struct attribute *of_node_attributes[] = {
+       &dev_attr_compatible.attr,
+       NULL
+};
+
+static const struct attribute_group of_node_attribute_group = {
+       .name = "of_node",
+       .attrs = of_node_attributes,
+};
+
+static const struct attribute_group *ndtest_attribute_groups[] = {
+       &of_node_attribute_group,
+       NULL,
+};
+
+static int ndtest_bus_register(struct ndtest_priv *p)
+{
+       p->config = &bus_configs[p->pdev.id];
+
+       p->bus_desc.ndctl = ndtest_ctl;
+       p->bus_desc.module = THIS_MODULE;
+       p->bus_desc.provider_name = NULL;
+       p->bus_desc.attr_groups = ndtest_attribute_groups;
+
+       p->bus = nvdimm_bus_register(&p->pdev.dev, &p->bus_desc);
+       if (!p->bus) {
+               dev_err(&p->pdev.dev, "Error creating nvdimm bus %pOF\n", p->dn);
+               return -ENOMEM;
+       }
+
+       return 0;
+}
+
+static int ndtest_remove(struct platform_device *pdev)
+{
+       struct ndtest_priv *p = to_ndtest_priv(&pdev->dev);
+
+       nvdimm_bus_unregister(p->bus);
+       return 0;
+}
+
+static int ndtest_probe(struct platform_device *pdev)
+{
+       struct ndtest_priv *p;
+       int rc;
+
+       p = to_ndtest_priv(&pdev->dev);
+       if (ndtest_bus_register(p))
+               return -ENOMEM;
+
+       p->dcr_dma = devm_kcalloc(&p->pdev.dev, NUM_DCR,
+                                sizeof(dma_addr_t), GFP_KERNEL);
+       p->label_dma = devm_kcalloc(&p->pdev.dev, NUM_DCR,
+                                  sizeof(dma_addr_t), GFP_KERNEL);
+       p->dimm_dma = devm_kcalloc(&p->pdev.dev, NUM_DCR,
+                                 sizeof(dma_addr_t), GFP_KERNEL);
+
+       rc = ndtest_nvdimm_init(p);
+       if (rc)
+               goto err;
+
+       rc = ndtest_init_regions(p);
+       if (rc)
+               goto err;
+
+       rc = devm_add_action_or_reset(&pdev->dev, put_dimms, p);
+       if (rc)
+               goto err;
+
+       platform_set_drvdata(pdev, p);
+
+       return 0;
+
+err:
+       pr_err("%s:%d Failed nvdimm init\n", __func__, __LINE__);
+       return rc;
+}
+
+static const struct platform_device_id ndtest_id[] = {
+       { KBUILD_MODNAME },
+       { },
+};
+
+static struct platform_driver ndtest_driver = {
+       .probe = ndtest_probe,
+       .remove = ndtest_remove,
+       .driver = {
+               .name = KBUILD_MODNAME,
+       },
+       .id_table = ndtest_id,
+};
+
+static void ndtest_release(struct device *dev)
+{
+       struct ndtest_priv *p = to_ndtest_priv(dev);
+
+       kfree(p);
+}
+
+static void cleanup_devices(void)
+{
+       int i;
+
+       for (i = 0; i < NUM_INSTANCES; i++)
+               if (instances[i])
+                       platform_device_unregister(&instances[i]->pdev);
+
+       nfit_test_teardown();
+
+       if (ndtest_pool)
+               gen_pool_destroy(ndtest_pool);
+
+
+       if (ndtest_dimm_class)
+               class_destroy(ndtest_dimm_class);
+}
+
+static __init int ndtest_init(void)
+{
+       int rc, i;
+
+       pmem_test();
+       libnvdimm_test();
+       device_dax_test();
+       dax_pmem_test();
+       dax_pmem_core_test();
+#ifdef CONFIG_DEV_DAX_PMEM_COMPAT
+       dax_pmem_compat_test();
+#endif
+
+       nfit_test_setup(ndtest_resource_lookup, NULL);
+
+       ndtest_dimm_class = class_create(THIS_MODULE, "nfit_test_dimm");
+       if (IS_ERR(ndtest_dimm_class)) {
+               rc = PTR_ERR(ndtest_dimm_class);
+               goto err_register;
+       }
+
+       ndtest_pool = gen_pool_create(ilog2(SZ_4M), NUMA_NO_NODE);
+       if (!ndtest_pool) {
+               rc = -ENOMEM;
+               goto err_register;
+       }
+
+       if (gen_pool_add(ndtest_pool, SZ_4G, SZ_4G, NUMA_NO_NODE)) {
+               rc = -ENOMEM;
+               goto err_register;
+       }
+
+       /* Each instance can be taken as a bus, which can have multiple dimms */
+       for (i = 0; i < NUM_INSTANCES; i++) {
+               struct ndtest_priv *priv;
+               struct platform_device *pdev;
+
+               priv = kzalloc(sizeof(*priv), GFP_KERNEL);
+               if (!priv) {
+                       rc = -ENOMEM;
+                       goto err_register;
+               }
+
+               INIT_LIST_HEAD(&priv->resources);
+               pdev = &priv->pdev;
+               pdev->name = KBUILD_MODNAME;
+               pdev->id = i;
+               pdev->dev.release = ndtest_release;
+               rc = platform_device_register(pdev);
+               if (rc) {
+                       put_device(&pdev->dev);
+                       goto err_register;
+               }
+               get_device(&pdev->dev);
+
+               instances[i] = priv;
+       }
+
+       rc = platform_driver_register(&ndtest_driver);
+       if (rc)
+               goto err_register;
+
+       return 0;
+
+err_register:
+       pr_err("Error registering platform device\n");
+       cleanup_devices();
+
+       return rc;
+}
+
+static __exit void ndtest_exit(void)
+{
+       cleanup_devices();
+       platform_driver_unregister(&ndtest_driver);
+}
+
+module_init(ndtest_init);
+module_exit(ndtest_exit);
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("IBM Corporation");
diff --git a/tools/testing/nvdimm/test/ndtest.h b/tools/testing/nvdimm/test/ndtest.h
new file mode 100644 (file)
index 0000000..2c54c9c
--- /dev/null
@@ -0,0 +1,109 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+#ifndef NDTEST_H
+#define NDTEST_H
+
+#include <linux/platform_device.h>
+#include <linux/libnvdimm.h>
+
+/* SCM device is unable to persist memory contents */
+#define PAPR_PMEM_UNARMED                   (1ULL << (63 - 0))
+/* SCM device failed to persist memory contents */
+#define PAPR_PMEM_SHUTDOWN_DIRTY            (1ULL << (63 - 1))
+/* SCM device contents are not persisted from previous IPL */
+#define PAPR_PMEM_EMPTY                     (1ULL << (63 - 3))
+#define PAPR_PMEM_HEALTH_CRITICAL           (1ULL << (63 - 4))
+/* SCM device will be garded off next IPL due to failure */
+#define PAPR_PMEM_HEALTH_FATAL              (1ULL << (63 - 5))
+/* SCM contents cannot persist due to current platform health status */
+#define PAPR_PMEM_HEALTH_UNHEALTHY          (1ULL << (63 - 6))
+
+/* Bits status indicators for health bitmap indicating unarmed dimm */
+#define PAPR_PMEM_UNARMED_MASK (PAPR_PMEM_UNARMED |            \
+                               PAPR_PMEM_HEALTH_UNHEALTHY)
+
+#define PAPR_PMEM_SAVE_FAILED                (1ULL << (63 - 10))
+
+/* Bits status indicators for health bitmap indicating unflushed dimm */
+#define PAPR_PMEM_BAD_SHUTDOWN_MASK (PAPR_PMEM_SHUTDOWN_DIRTY)
+
+/* Bits status indicators for health bitmap indicating unrestored dimm */
+#define PAPR_PMEM_BAD_RESTORE_MASK  (PAPR_PMEM_EMPTY)
+
+/* Bit status indicators for smart event notification */
+#define PAPR_PMEM_SMART_EVENT_MASK (PAPR_PMEM_HEALTH_CRITICAL | \
+                                   PAPR_PMEM_HEALTH_FATAL |    \
+                                   PAPR_PMEM_HEALTH_UNHEALTHY)
+
+#define PAPR_PMEM_SAVE_MASK                (PAPR_PMEM_SAVE_FAILED)
+
+struct ndtest_config;
+
+struct ndtest_priv {
+       struct platform_device pdev;
+       struct device_node *dn;
+       struct list_head resources;
+       struct nvdimm_bus_descriptor bus_desc;
+       struct nvdimm_bus *bus;
+       struct ndtest_config *config;
+
+       dma_addr_t *dcr_dma;
+       dma_addr_t *label_dma;
+       dma_addr_t *dimm_dma;
+};
+
+struct ndtest_blk_mmio {
+       void __iomem *base;
+       u64 size;
+       u64 base_offset;
+       u32 line_size;
+       u32 num_lines;
+       u32 table_size;
+};
+
+struct ndtest_dimm {
+       struct device *dev;
+       struct nvdimm *nvdimm;
+       struct ndtest_blk_mmio *mmio;
+       struct nd_region *blk_region;
+
+       dma_addr_t address;
+       unsigned long long flags;
+       unsigned long config_size;
+       void *label_area;
+       char *uuid_str;
+
+       unsigned int size;
+       unsigned int handle;
+       unsigned int fail_cmd;
+       unsigned int physical_id;
+       unsigned int num_formats;
+       int id;
+       int fail_cmd_code;
+       u8 no_alias;
+};
+
+struct ndtest_mapping {
+       u64 start;
+       u64 size;
+       u8 position;
+       u8 dimm;
+};
+
+struct ndtest_region {
+       struct nd_region *region;
+       struct ndtest_mapping *mapping;
+       u64 size;
+       u8 type;
+       u8 num_mappings;
+       u8 range_index;
+};
+
+struct ndtest_config {
+       struct ndtest_dimm *dimms;
+       struct ndtest_region *regions;
+       unsigned int dimm_count;
+       unsigned int dimm_start;
+       u8 num_regions;
+};
+
+#endif /* NDTEST_H */
index c0fe73a..3bfcf00 100644 (file)
@@ -34,61 +34,6 @@ struct storage {
        struct bpf_spin_lock lock;
 };
 
-/* Copies an rm binary to a temp file. dest is a mkstemp template */
-static int copy_rm(char *dest)
-{
-       int fd_in, fd_out = -1, ret = 0;
-       struct stat stat;
-       char *buf = NULL;
-
-       fd_in = open("/bin/rm", O_RDONLY);
-       if (fd_in < 0)
-               return -errno;
-
-       fd_out = mkstemp(dest);
-       if (fd_out < 0) {
-               ret = -errno;
-               goto out;
-       }
-
-       ret = fstat(fd_in, &stat);
-       if (ret == -1) {
-               ret = -errno;
-               goto out;
-       }
-
-       buf = malloc(stat.st_blksize);
-       if (!buf) {
-               ret = -errno;
-               goto out;
-       }
-
-       while (ret = read(fd_in, buf, stat.st_blksize), ret > 0) {
-               ret = write(fd_out, buf, ret);
-               if (ret < 0) {
-                       ret = -errno;
-                       goto out;
-
-               }
-       }
-       if (ret < 0) {
-               ret = -errno;
-               goto out;
-
-       }
-
-       /* Set executable permission on the copied file */
-       ret = chmod(dest, 0100);
-       if (ret == -1)
-               ret = -errno;
-
-out:
-       free(buf);
-       close(fd_in);
-       close(fd_out);
-       return ret;
-}
-
 /* Fork and exec the provided rm binary and return the exit code of the
  * forked process and its pid.
  */
@@ -168,9 +113,11 @@ static bool check_syscall_operations(int map_fd, int obj_fd)
 
 void test_test_local_storage(void)
 {
-       char tmp_exec_path[PATH_MAX] = "/tmp/copy_of_rmXXXXXX";
+       char tmp_dir_path[64] = "/tmp/local_storageXXXXXX";
        int err, serv_sk = -1, task_fd = -1, rm_fd = -1;
        struct local_storage *skel = NULL;
+       char tmp_exec_path[64];
+       char cmd[256];
 
        skel = local_storage__open_and_load();
        if (CHECK(!skel, "skel_load", "lsm skeleton failed\n"))
@@ -189,18 +136,24 @@ void test_test_local_storage(void)
                                      task_fd))
                goto close_prog;
 
-       err = copy_rm(tmp_exec_path);
-       if (CHECK(err < 0, "copy_rm", "err %d errno %d\n", err, errno))
+       if (CHECK(!mkdtemp(tmp_dir_path), "mkdtemp",
+                 "unable to create tmpdir: %d\n", errno))
                goto close_prog;
 
+       snprintf(tmp_exec_path, sizeof(tmp_exec_path), "%s/copy_of_rm",
+                tmp_dir_path);
+       snprintf(cmd, sizeof(cmd), "cp /bin/rm %s", tmp_exec_path);
+       if (CHECK_FAIL(system(cmd)))
+               goto close_prog_rmdir;
+
        rm_fd = open(tmp_exec_path, O_RDONLY);
        if (CHECK(rm_fd < 0, "open", "failed to open %s err:%d, errno:%d",
                  tmp_exec_path, rm_fd, errno))
-               goto close_prog;
+               goto close_prog_rmdir;
 
        if (!check_syscall_operations(bpf_map__fd(skel->maps.inode_storage_map),
                                      rm_fd))
-               goto close_prog;
+               goto close_prog_rmdir;
 
        /* Sets skel->bss->monitored_pid to the pid of the forked child
         * forks a child process that executes tmp_exec_path and tries to
@@ -209,33 +162,36 @@ void test_test_local_storage(void)
         */
        err = run_self_unlink(&skel->bss->monitored_pid, tmp_exec_path);
        if (CHECK(err != EPERM, "run_self_unlink", "err %d want EPERM\n", err))
-               goto close_prog_unlink;
+               goto close_prog_rmdir;
 
        /* Set the process being monitored to be the current process */
        skel->bss->monitored_pid = getpid();
 
-       /* Remove the temporary created executable */
-       err = unlink(tmp_exec_path);
-       if (CHECK(err != 0, "unlink", "unable to unlink %s: %d", tmp_exec_path,
-                 errno))
-               goto close_prog_unlink;
+       /* Move copy_of_rm to a new location so that it triggers the
+        * inode_rename LSM hook with a new_dentry that has a NULL inode ptr.
+        */
+       snprintf(cmd, sizeof(cmd), "mv %s/copy_of_rm %s/check_null_ptr",
+                tmp_dir_path, tmp_dir_path);
+       if (CHECK_FAIL(system(cmd)))
+               goto close_prog_rmdir;
 
        CHECK(skel->data->inode_storage_result != 0, "inode_storage_result",
              "inode_local_storage not set\n");
 
        serv_sk = start_server(AF_INET6, SOCK_STREAM, NULL, 0, 0);
        if (CHECK(serv_sk < 0, "start_server", "failed to start server\n"))
-               goto close_prog;
+               goto close_prog_rmdir;
 
        CHECK(skel->data->sk_storage_result != 0, "sk_storage_result",
              "sk_local_storage not set\n");
 
        if (!check_syscall_operations(bpf_map__fd(skel->maps.sk_storage_map),
                                      serv_sk))
-               goto close_prog;
+               goto close_prog_rmdir;
 
-close_prog_unlink:
-       unlink(tmp_exec_path);
+close_prog_rmdir:
+       snprintf(cmd, sizeof(cmd), "rm -rf %s", tmp_dir_path);
+       system(cmd);
 close_prog:
        close(serv_sk);
        close(rm_fd);
index 3e3de13..95868bc 100644 (file)
@@ -50,7 +50,6 @@ int BPF_PROG(unlink_hook, struct inode *dir, struct dentry *victim)
        __u32 pid = bpf_get_current_pid_tgid() >> 32;
        struct local_storage *storage;
        bool is_self_unlink;
-       int err;
 
        if (pid != monitored_pid)
                return 0;
@@ -66,8 +65,27 @@ int BPF_PROG(unlink_hook, struct inode *dir, struct dentry *victim)
                        return -EPERM;
        }
 
-       storage = bpf_inode_storage_get(&inode_storage_map, victim->d_inode, 0,
-                                       BPF_LOCAL_STORAGE_GET_F_CREATE);
+       return 0;
+}
+
+SEC("lsm/inode_rename")
+int BPF_PROG(inode_rename, struct inode *old_dir, struct dentry *old_dentry,
+            struct inode *new_dir, struct dentry *new_dentry,
+            unsigned int flags)
+{
+       __u32 pid = bpf_get_current_pid_tgid() >> 32;
+       struct local_storage *storage;
+       int err;
+
+       /* new_dentry->d_inode can be NULL when the inode is renamed to a file
+        * that did not exist before. The helper should be able to handle this
+        * NULL pointer.
+        */
+       bpf_inode_storage_get(&inode_storage_map, new_dentry->d_inode, 0,
+                             BPF_LOCAL_STORAGE_GET_F_CREATE);
+
+       storage = bpf_inode_storage_get(&inode_storage_map, old_dentry->d_inode,
+                                       0, 0);
        if (!storage)
                return 0;
 
@@ -76,7 +94,7 @@ int BPF_PROG(unlink_hook, struct inode *dir, struct dentry *victim)
                inode_storage_result = -1;
        bpf_spin_unlock(&storage->lock);
 
-       err = bpf_inode_storage_delete(&inode_storage_map, victim->d_inode);
+       err = bpf_inode_storage_delete(&inode_storage_map, old_dentry->d_inode);
        if (!err)
                inode_storage_result = err;
 
@@ -133,37 +151,18 @@ int BPF_PROG(socket_post_create, struct socket *sock, int family, int type,
        return 0;
 }
 
-SEC("lsm/file_open")
-int BPF_PROG(file_open, struct file *file)
-{
-       __u32 pid = bpf_get_current_pid_tgid() >> 32;
-       struct local_storage *storage;
-
-       if (pid != monitored_pid)
-               return 0;
-
-       if (!file->f_inode)
-               return 0;
-
-       storage = bpf_inode_storage_get(&inode_storage_map, file->f_inode, 0,
-                                       BPF_LOCAL_STORAGE_GET_F_CREATE);
-       if (!storage)
-               return 0;
-
-       bpf_spin_lock(&storage->lock);
-       storage->value = DUMMY_STORAGE_VALUE;
-       bpf_spin_unlock(&storage->lock);
-       return 0;
-}
-
 /* This uses the local storage to remember the inode of the binary that a
  * process was originally executing.
  */
 SEC("lsm/bprm_committed_creds")
 void BPF_PROG(exec, struct linux_binprm *bprm)
 {
+       __u32 pid = bpf_get_current_pid_tgid() >> 32;
        struct local_storage *storage;
 
+       if (pid != monitored_pid)
+               return;
+
        storage = bpf_task_storage_get(&task_storage_map,
                                       bpf_get_current_task_btf(), 0,
                                       BPF_LOCAL_STORAGE_GET_F_CREATE);
@@ -172,4 +171,13 @@ void BPF_PROG(exec, struct linux_binprm *bprm)
                storage->exec_inode = bprm->file->f_inode;
                bpf_spin_unlock(&storage->lock);
        }
+
+       storage = bpf_inode_storage_get(&inode_storage_map, bprm->file->f_inode,
+                                       0, BPF_LOCAL_STORAGE_GET_F_CREATE);
+       if (!storage)
+               return;
+
+       bpf_spin_lock(&storage->lock);
+       storage->value = DUMMY_STORAGE_VALUE;
+       bpf_spin_unlock(&storage->lock);
 }
index 777a814..f8569f0 100644 (file)
@@ -50,7 +50,7 @@
 #define MAX_INSNS      BPF_MAXINSNS
 #define MAX_TEST_INSNS 1000000
 #define MAX_FIXUPS     8
-#define MAX_NR_MAPS    20
+#define MAX_NR_MAPS    21
 #define MAX_TEST_RUNS  8
 #define POINTER_VALUE  0xcafe4all
 #define TEST_DATA_LEN  64
@@ -87,6 +87,7 @@ struct bpf_test {
        int fixup_sk_storage_map[MAX_FIXUPS];
        int fixup_map_event_output[MAX_FIXUPS];
        int fixup_map_reuseport_array[MAX_FIXUPS];
+       int fixup_map_ringbuf[MAX_FIXUPS];
        const char *errstr;
        const char *errstr_unpriv;
        uint32_t insn_processed;
@@ -640,6 +641,7 @@ static void do_test_fixup(struct bpf_test *test, enum bpf_prog_type prog_type,
        int *fixup_sk_storage_map = test->fixup_sk_storage_map;
        int *fixup_map_event_output = test->fixup_map_event_output;
        int *fixup_map_reuseport_array = test->fixup_map_reuseport_array;
+       int *fixup_map_ringbuf = test->fixup_map_ringbuf;
 
        if (test->fill_helper) {
                test->fill_insns = calloc(MAX_TEST_INSNS, sizeof(struct bpf_insn));
@@ -817,6 +819,14 @@ static void do_test_fixup(struct bpf_test *test, enum bpf_prog_type prog_type,
                        fixup_map_reuseport_array++;
                } while (*fixup_map_reuseport_array);
        }
+       if (*fixup_map_ringbuf) {
+               map_fds[20] = create_map(BPF_MAP_TYPE_RINGBUF, 0,
+                                          0, 4096);
+               do {
+                       prog[*fixup_map_ringbuf].imm = map_fds[20];
+                       fixup_map_ringbuf++;
+               } while (*fixup_map_ringbuf);
+       }
 }
 
 struct libcap {
index 45d43bf..0b94389 100644 (file)
        .result = ACCEPT,
        .result_unpriv = ACCEPT,
 },
+{
+       "check valid spill/fill, ptr to mem",
+       .insns = {
+       /* reserve 8 byte ringbuf memory */
+       BPF_ST_MEM(BPF_DW, BPF_REG_10, -8, 0),
+       BPF_LD_MAP_FD(BPF_REG_1, 0),
+       BPF_MOV64_IMM(BPF_REG_2, 8),
+       BPF_MOV64_IMM(BPF_REG_3, 0),
+       BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0, BPF_FUNC_ringbuf_reserve),
+       /* store a pointer to the reserved memory in R6 */
+       BPF_MOV64_REG(BPF_REG_6, BPF_REG_0),
+       /* check whether the reservation was successful */
+       BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, 6),
+       /* spill R6(mem) into the stack */
+       BPF_STX_MEM(BPF_DW, BPF_REG_10, BPF_REG_6, -8),
+       /* fill it back in R7 */
+       BPF_LDX_MEM(BPF_DW, BPF_REG_7, BPF_REG_10, -8),
+       /* should be able to access *(R7) = 0 */
+       BPF_ST_MEM(BPF_DW, BPF_REG_7, 0, 0),
+       /* submit the reserved ringbuf memory */
+       BPF_MOV64_REG(BPF_REG_1, BPF_REG_7),
+       BPF_MOV64_IMM(BPF_REG_2, 0),
+       BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0, BPF_FUNC_ringbuf_submit),
+       BPF_MOV64_IMM(BPF_REG_0, 0),
+       BPF_EXIT_INSN(),
+       },
+       .fixup_map_ringbuf = { 1 },
+       .result = ACCEPT,
+       .result_unpriv = ACCEPT,
+},
 {
        "check corrupted spill/fill",
        .insns = {
index 7065163..537d659 100644 (file)
@@ -6,6 +6,7 @@
 #include <fcntl.h>
 #include <stdio.h>
 #include <stdlib.h>
+#include <string.h>
 #include <unistd.h>
 #include <sys/ioctl.h>
 #include <sys/mman.h>
@@ -35,7 +36,7 @@ struct map_benchmark {
        __s32 node; /* which numa node this benchmark will run on */
        __u32 dma_bits; /* DMA addressing capability */
        __u32 dma_dir; /* DMA data direction */
-       __u64 expansion[10];    /* For future use */
+       __u8 expansion[84];     /* For future use */
 };
 
 int main(int argc, char **argv)
@@ -102,6 +103,7 @@ int main(int argc, char **argv)
                exit(1);
        }
 
+       memset(&map, 0, sizeof(map));
        map.seconds = seconds;
        map.threads = threads;
        map.node = node;
index 84205c3..2b57077 100755 (executable)
@@ -1055,7 +1055,6 @@ ipv6_addr_metric_test()
 
        check_route6 "2001:db8:104::1 dev dummy2 proto kernel metric 260"
        log_test $? 0 "Set metric with peer route on local side"
-       log_test $? 0 "User specified metric on local address"
        check_route6 "2001:db8:104::2 dev dummy2 proto kernel metric 260"
        log_test $? 0 "Set metric with peer route on peer side"
 
index 388e449..76efb1f 100755 (executable)
@@ -203,7 +203,7 @@ multipath4_test()
        t0_rp12=$(link_stats_tx_packets_get $rp12)
        t0_rp13=$(link_stats_tx_packets_get $rp13)
 
-       ip vrf exec vrf-h1 $MZ -q -p 64 -A 192.0.2.2 -B 198.51.100.2 \
+       ip vrf exec vrf-h1 $MZ $h1 -q -p 64 -A 192.0.2.2 -B 198.51.100.2 \
                -d 1msec -t udp "sp=1024,dp=0-32768"
 
        t1_rp12=$(link_stats_tx_packets_get $rp12)
index 79a2099..464821c 100755 (executable)
@@ -178,7 +178,7 @@ multipath4_test()
        t0_rp12=$(link_stats_tx_packets_get $rp12)
        t0_rp13=$(link_stats_tx_packets_get $rp13)
 
-       ip vrf exec vrf-h1 $MZ -q -p 64 -A 192.0.2.2 -B 198.51.100.2 \
+       ip vrf exec vrf-h1 $MZ $h1 -q -p 64 -A 192.0.2.2 -B 198.51.100.2 \
               -d 1msec -t udp "sp=1024,dp=0-32768"
 
        t1_rp12=$(link_stats_tx_packets_get $rp12)
index 7a1bf94..bdf450e 100755 (executable)
@@ -202,7 +202,7 @@ check_xfrm() {
        # 1: iptables -m policy rule count != 0
        rval=$1
        ip=$2
-       lret=0
+       local lret=0
 
        ip netns exec ns1 ping -q -c 1 10.0.2.$ip > /dev/null
 
@@ -287,6 +287,47 @@ check_hthresh_repeat()
        return 0
 }
 
+# insert non-overlapping policies in a random order and check that
+# all of them can be fetched using the traffic selectors.
+check_random_order()
+{
+       local ns=$1
+       local log=$2
+
+       for i in $(seq 100); do
+               ip -net $ns xfrm policy flush
+               for j in $(seq 0 16 255 | sort -R); do
+                       ip -net $ns xfrm policy add dst $j.0.0.0/24 dir out priority 10 action allow
+               done
+               for j in $(seq 0 16 255); do
+                       if ! ip -net $ns xfrm policy get dst $j.0.0.0/24 dir out > /dev/null; then
+                               echo "FAIL: $log" 1>&2
+                               return 1
+                       fi
+               done
+       done
+
+       for i in $(seq 100); do
+               ip -net $ns xfrm policy flush
+               for j in $(seq 0 16 255 | sort -R); do
+                       local addr=$(printf "e000:0000:%02x00::/56" $j)
+                       ip -net $ns xfrm policy add dst $addr dir out priority 10 action allow
+               done
+               for j in $(seq 0 16 255); do
+                       local addr=$(printf "e000:0000:%02x00::/56" $j)
+                       if ! ip -net $ns xfrm policy get dst $addr dir out > /dev/null; then
+                               echo "FAIL: $log" 1>&2
+                               return 1
+                       fi
+               done
+       done
+
+       ip -net $ns xfrm policy flush
+
+       echo "PASS: $log"
+       return 0
+}
+
 #check for needed privileges
 if [ "$(id -u)" -ne 0 ];then
        echo "SKIP: Need root privileges"
@@ -438,6 +479,8 @@ check_exceptions "exceptions and block policies after htresh change to normal"
 
 check_hthresh_repeat "policies with repeated htresh change"
 
+check_random_order ns3 "policies inserted in random order"
+
 for i in 1 2 3 4;do ip netns del ns$i;done
 
 exit $ret
index cb53a8b..c25cf7c 100644 (file)
@@ -443,7 +443,6 @@ int test_alignment_handler_integer(void)
        LOAD_DFORM_TEST(ldu);
        LOAD_XFORM_TEST(ldx);
        LOAD_XFORM_TEST(ldux);
-       LOAD_DFORM_TEST(lmw);
        STORE_DFORM_TEST(stb);
        STORE_XFORM_TEST(stbx);
        STORE_DFORM_TEST(stbu);
@@ -462,7 +461,11 @@ int test_alignment_handler_integer(void)
        STORE_XFORM_TEST(stdx);
        STORE_DFORM_TEST(stdu);
        STORE_XFORM_TEST(stdux);
+
+#ifdef __BIG_ENDIAN__
+       LOAD_DFORM_TEST(lmw);
        STORE_DFORM_TEST(stmw);
+#endif
 
        return rc;
 }
index 9e5c7f3..0af4f02 100644 (file)
@@ -290,5 +290,5 @@ static int test(void)
 
 int main(void)
 {
-       test_harness(test, "pkey_exec_prot");
+       return test_harness(test, "pkey_exec_prot");
 }
index 4f815d7..2db76e5 100644 (file)
@@ -329,5 +329,5 @@ static int test(void)
 
 int main(void)
 {
-       test_harness(test, "pkey_siginfo");
+       return test_harness(test, "pkey_siginfo");
 }
index 6689f11..073a037 100644 (file)
@@ -22,6 +22,8 @@
 # define PR_SET_SYSCALL_USER_DISPATCH  59
 # define PR_SYS_DISPATCH_OFF   0
 # define PR_SYS_DISPATCH_ON    1
+# define SYSCALL_DISPATCH_FILTER_ALLOW 0
+# define SYSCALL_DISPATCH_FILTER_BLOCK 1
 #endif
 
 #ifdef __NR_syscalls
@@ -55,8 +57,8 @@ unsigned long trapped_call_count = 0;
 unsigned long native_call_count = 0;
 
 char selector;
-#define SYSCALL_BLOCK   (selector = PR_SYS_DISPATCH_ON)
-#define SYSCALL_UNBLOCK (selector = PR_SYS_DISPATCH_OFF)
+#define SYSCALL_BLOCK   (selector = SYSCALL_DISPATCH_FILTER_BLOCK)
+#define SYSCALL_UNBLOCK (selector = SYSCALL_DISPATCH_FILTER_ALLOW)
 
 #define CALIBRATION_STEP 100000
 #define CALIBRATE_TO_SECS 5
@@ -170,7 +172,7 @@ int main(void)
        syscall(MAGIC_SYSCALL_1);
 
 #ifdef TEST_BLOCKED_RETURN
-       if (selector == PR_SYS_DISPATCH_OFF) {
+       if (selector == SYSCALL_DISPATCH_FILTER_ALLOW) {
                fprintf(stderr, "Failed to return with selector blocked.\n");
                exit(-1);
        }
index 6498b05..b5d592d 100644 (file)
@@ -18,6 +18,8 @@
 # define PR_SET_SYSCALL_USER_DISPATCH  59
 # define PR_SYS_DISPATCH_OFF   0
 # define PR_SYS_DISPATCH_ON    1
+# define SYSCALL_DISPATCH_FILTER_ALLOW 0
+# define SYSCALL_DISPATCH_FILTER_BLOCK 1
 #endif
 
 #ifndef SYS_USER_DISPATCH
@@ -30,8 +32,8 @@
 # define MAGIC_SYSCALL_1 (0xff00)  /* Bad Linux syscall number */
 #endif
 
-#define SYSCALL_DISPATCH_ON(x) ((x) = 1)
-#define SYSCALL_DISPATCH_OFF(x) ((x) = 0)
+#define SYSCALL_DISPATCH_ON(x) ((x) = SYSCALL_DISPATCH_FILTER_BLOCK)
+#define SYSCALL_DISPATCH_OFF(x) ((x) = SYSCALL_DISPATCH_FILTER_ALLOW)
 
 /* Test Summary:
  *
@@ -56,7 +58,7 @@
 
 TEST_SIGNAL(dispatch_trigger_sigsys, SIGSYS)
 {
-       char sel = 0;
+       char sel = SYSCALL_DISPATCH_FILTER_ALLOW;
        struct sysinfo info;
        int ret;
 
@@ -79,7 +81,7 @@ TEST_SIGNAL(dispatch_trigger_sigsys, SIGSYS)
 
 TEST(bad_prctl_param)
 {
-       char sel = 0;
+       char sel = SYSCALL_DISPATCH_FILTER_ALLOW;
        int op;
 
        /* Invalid op */
@@ -220,7 +222,7 @@ TEST_SIGNAL(bad_selector, SIGSYS)
        sigset_t mask;
        struct sysinfo info;
 
-       glob_sel = 0;
+       glob_sel = SYSCALL_DISPATCH_FILTER_ALLOW;
        nr_syscalls_emulated = 0;
        si_code = 0;
        si_errno = 0;
@@ -288,7 +290,7 @@ TEST(direct_dispatch_range)
 {
        int ret = 0;
        struct sysinfo info;
-       char sel = 0;
+       char sel = SYSCALL_DISPATCH_FILTER_ALLOW;
 
        /*
         * Instead of calculating libc addresses; allow the entire
index fa9e361..8367d88 100644 (file)
@@ -1292,6 +1292,7 @@ int __kvm_set_memory_region(struct kvm *kvm,
                return -EINVAL;
        /* We can read the guest memory with __xxx_user() later on. */
        if ((mem->userspace_addr & (PAGE_SIZE - 1)) ||
+           (mem->userspace_addr != untagged_addr(mem->userspace_addr)) ||
             !access_ok((void __user *)(unsigned long)mem->userspace_addr,
                        mem->memory_size))
                return -EINVAL;