]> git.proxmox.com Git - mirror_ubuntu-artful-kernel.git/commitdiff
Merge remote-tracking branch 'asoc/topic/simple' into asoc-next
authorMark Brown <broonie@kernel.org>
Mon, 22 Jun 2015 09:24:35 +0000 (10:24 +0100)
committerMark Brown <broonie@kernel.org>
Mon, 22 Jun 2015 09:24:35 +0000 (10:24 +0100)
1460 files changed:
CREDITS
Documentation/ABI/testing/sysfs-devices-system-cpu
Documentation/IPMI.txt
Documentation/acpi/enumeration.txt
Documentation/acpi/gpio-properties.txt
Documentation/devicetree/bindings/arm/omap/l3-noc.txt
Documentation/devicetree/bindings/clock/silabs,si5351.txt
Documentation/devicetree/bindings/dma/fsl-mxs-dma.txt
Documentation/devicetree/bindings/input/touchscreen/tsc2005.txt
Documentation/devicetree/bindings/mtd/jedec,spi-nor.txt [new file with mode: 0644]
Documentation/devicetree/bindings/mtd/m25p80.txt [deleted file]
Documentation/devicetree/bindings/net/cdns-emac.txt
Documentation/devicetree/bindings/rtc/abracon,abx80x.txt [new file with mode: 0644]
Documentation/devicetree/bindings/sound/adi,adau1701.txt
Documentation/devicetree/bindings/sound/bt-sco.txt [new file with mode: 0644]
Documentation/devicetree/bindings/sound/gtm601.txt [new file with mode: 0644]
Documentation/devicetree/bindings/sound/max98090.txt
Documentation/devicetree/bindings/sound/mt8173-max98090.txt [new file with mode: 0644]
Documentation/devicetree/bindings/sound/mt8173-rt5650-rt5676.txt [new file with mode: 0644]
Documentation/devicetree/bindings/sound/mtk-afe-pcm.txt [new file with mode: 0644]
Documentation/devicetree/bindings/sound/qcom,apq8016-sbc.txt [new file with mode: 0644]
Documentation/devicetree/bindings/sound/qcom,lpass-cpu.txt
Documentation/devicetree/bindings/sound/renesas,rsnd.txt
Documentation/devicetree/bindings/sound/rt5645.txt [new file with mode: 0644]
Documentation/devicetree/bindings/sound/rt5677.txt
Documentation/devicetree/bindings/sound/tas571x.txt [new file with mode: 0644]
Documentation/devicetree/bindings/sound/wm8741.txt
Documentation/devicetree/bindings/sound/zte,zx-i2s.txt [new file with mode: 0644]
Documentation/devicetree/bindings/sound/zte,zx-spdif.txt [new file with mode: 0644]
Documentation/devicetree/bindings/usb/renesas_usbhs.txt
Documentation/devicetree/bindings/vendor-prefixes.txt
Documentation/hwmon/tmp401
Documentation/kasan.txt
Documentation/kernel-parameters.txt
Documentation/module-signing.txt
Documentation/networking/mpls-sysctl.txt
Documentation/networking/scaling.txt
Documentation/networking/udplite.txt
Documentation/powerpc/transactional_memory.txt
Documentation/serial/tty.txt
Documentation/target/tcmu-design.txt
Documentation/virtual/kvm/mmu.txt
MAINTAINERS
Makefile
arch/alpha/boot/Makefile
arch/alpha/boot/main.c
arch/alpha/boot/stdio.c [new file with mode: 0644]
arch/alpha/boot/tools/objstrip.c
arch/alpha/include/asm/types.h
arch/alpha/include/asm/unistd.h
arch/alpha/include/uapi/asm/unistd.h
arch/alpha/kernel/err_ev6.c
arch/alpha/kernel/irq.c
arch/alpha/kernel/osf_sys.c
arch/alpha/kernel/process.c
arch/alpha/kernel/smp.c
arch/alpha/kernel/srmcons.c
arch/alpha/kernel/sys_marvel.c
arch/alpha/kernel/systbls.S
arch/alpha/kernel/traps.c
arch/alpha/oprofile/op_model_ev4.c
arch/alpha/oprofile/op_model_ev5.c
arch/alpha/oprofile/op_model_ev6.c
arch/alpha/oprofile/op_model_ev67.c
arch/arc/Kconfig.debug
arch/arc/include/asm/atomic.h
arch/arc/mm/cache_arc700.c
arch/arm/boot/dts/Makefile
arch/arm/boot/dts/am335x-bone-common.dtsi
arch/arm/boot/dts/am335x-boneblack.dts
arch/arm/boot/dts/am335x-evmsk.dts
arch/arm/boot/dts/am35xx-clocks.dtsi
arch/arm/boot/dts/am437x-sk-evm.dts
arch/arm/boot/dts/am57xx-beagle-x15.dts
arch/arm/boot/dts/armada-375.dtsi
arch/arm/boot/dts/armada-38x.dtsi
arch/arm/boot/dts/armada-39x.dtsi
arch/arm/boot/dts/armada-xp-linksys-mamba.dts
arch/arm/boot/dts/armada-xp-openblocks-ax3-4.dts
arch/arm/boot/dts/dm816x.dtsi
arch/arm/boot/dts/dove-cubox.dts
arch/arm/boot/dts/dra7.dtsi
arch/arm/boot/dts/exynos4412-odroid-common.dtsi
arch/arm/boot/dts/exynos4412-trats2.dts
arch/arm/boot/dts/exynos5250-snow.dts
arch/arm/boot/dts/exynos5420-peach-pit.dts
arch/arm/boot/dts/exynos5420-trip-points.dtsi
arch/arm/boot/dts/exynos5420.dtsi
arch/arm/boot/dts/exynos5440-trip-points.dtsi
arch/arm/boot/dts/exynos5800-peach-pi.dts
arch/arm/boot/dts/imx23-olinuxino.dts
arch/arm/boot/dts/imx25.dtsi
arch/arm/boot/dts/imx27.dtsi
arch/arm/boot/dts/imx28.dtsi
arch/arm/boot/dts/imx6qdl-phytec-pfla02.dtsi
arch/arm/boot/dts/imx6qdl-sabreauto.dtsi
arch/arm/boot/dts/omap3-devkit8000.dts
arch/arm/boot/dts/omap3-n900.dts
arch/arm/boot/dts/omap3.dtsi
arch/arm/boot/dts/omap5.dtsi
arch/arm/boot/dts/r8a7791-koelsch.dts
arch/arm/boot/dts/ste-dbx5x0.dtsi
arch/arm/boot/dts/ste-href.dtsi
arch/arm/boot/dts/ste-snowball.dts
arch/arm/boot/dts/tegra124.dtsi
arch/arm/boot/dts/vexpress-v2p-ca15_a7.dts
arch/arm/boot/dts/vexpress-v2p-ca9.dts
arch/arm/boot/dts/zynq-7000.dtsi
arch/arm/configs/multi_v7_defconfig
arch/arm/configs/omap2plus_defconfig
arch/arm/include/asm/dma-iommu.h
arch/arm/include/asm/xen/page.h
arch/arm/kernel/entry-common.S
arch/arm/kernel/perf_event_cpu.c
arch/arm/mach-exynos/common.h
arch/arm/mach-exynos/exynos.c
arch/arm/mach-exynos/platsmp.c
arch/arm/mach-exynos/pm_domains.c
arch/arm/mach-exynos/suspend.c
arch/arm/mach-gemini/common.h
arch/arm/mach-gemini/reset.c
arch/arm/mach-imx/devices/platform-sdhci-esdhc-imx.c
arch/arm/mach-imx/gpc.c
arch/arm/mach-omap2/omap_hwmod.c
arch/arm/mach-omap2/omap_hwmod_43xx_data.c
arch/arm/mach-omap2/prcm43xx.h
arch/arm/mach-omap2/prm-regbits-34xx.h
arch/arm/mach-omap2/prm-regbits-44xx.h
arch/arm/mach-omap2/prminst44xx.c
arch/arm/mach-omap2/sleep34xx.S
arch/arm/mach-omap2/timer.c
arch/arm/mach-omap2/vc.c
arch/arm/mach-omap2/vc.h
arch/arm/mach-omap2/vc3xxx_data.c
arch/arm/mach-omap2/vc44xx_data.c
arch/arm/mach-pxa/Kconfig
arch/arm/mach-pxa/Makefile
arch/arm/mach-pxa/include/mach/lubbock.h
arch/arm/mach-pxa/include/mach/mainstone.h
arch/arm/mach-pxa/lubbock.c
arch/arm/mach-pxa/mainstone.c
arch/arm/mach-pxa/pxa_cplds_irqs.c [new file with mode: 0644]
arch/arm/mach-rockchip/pm.c
arch/arm/mach-rockchip/pm.h
arch/arm/mach-rockchip/rockchip.c
arch/arm/mm/dma-mapping.c
arch/arm/mm/mmu.c
arch/arm/mm/proc-arm1020.S
arch/arm/mm/proc-arm1020e.S
arch/arm/mm/proc-arm925.S
arch/arm/mm/proc-feroceon.S
arch/arm/net/bpf_jit_32.c
arch/arm/xen/enlighten.c
arch/arm/xen/mm.c
arch/arm64/Kconfig
arch/arm64/boot/dts/arm/juno-motherboard.dtsi
arch/arm64/boot/dts/mediatek/mt8173-evb.dts
arch/arm64/crypto/crc32-arm64.c
arch/arm64/crypto/sha1-ce-glue.c
arch/arm64/crypto/sha2-ce-glue.c
arch/arm64/include/asm/barrier.h
arch/arm64/kernel/alternative.c
arch/arm64/kernel/perf_event.c
arch/arm64/mm/dma-mapping.c
arch/arm64/mm/dump.c
arch/arm64/net/bpf_jit_comp.c
arch/blackfin/include/asm/io.h
arch/ia64/kernel/smpboot.c
arch/ia64/pci/pci.c
arch/m32r/kernel/smp.c
arch/mips/Makefile
arch/mips/ath79/prom.c
arch/mips/ath79/setup.c
arch/mips/cobalt/Makefile
arch/mips/configs/fuloong2e_defconfig
arch/mips/include/asm/elf.h
arch/mips/include/asm/pgtable-bits.h
arch/mips/include/asm/smp.h
arch/mips/include/asm/switch_to.h
arch/mips/kernel/cpu-probe.c
arch/mips/kernel/elf.c
arch/mips/kernel/irq.c
arch/mips/kernel/ptrace.c
arch/mips/kernel/smp-bmips.c
arch/mips/kernel/smp-cps.c
arch/mips/kernel/smp.c
arch/mips/kernel/traps.c
arch/mips/kvm/emulate.c
arch/mips/lib/strnlen_user.S
arch/mips/loongson/common/Makefile
arch/mips/loongson/loongson-3/smp.c
arch/mips/math-emu/cp1emu.c
arch/mips/mm/c-r4k.c
arch/mips/mm/tlb-r4k.c
arch/mips/net/bpf_jit.c
arch/mips/ralink/ill_acc.c
arch/mips/sgi-ip32/ip32-platform.c
arch/parisc/include/asm/elf.h
arch/parisc/kernel/process.c
arch/parisc/kernel/sys_parisc.c
arch/powerpc/include/uapi/asm/tm.h
arch/powerpc/kernel/eeh.c
arch/powerpc/kernel/entry_64.S
arch/powerpc/kernel/idle_power7.S
arch/powerpc/kernel/mce.c
arch/powerpc/kernel/vmlinux.lds.S
arch/powerpc/kvm/book3s_hv.c
arch/powerpc/kvm/book3s_xics.c
arch/powerpc/mm/hugetlbpage.c
arch/powerpc/mm/pgtable_64.c
arch/powerpc/platforms/powernv/pci-ioda.c
arch/powerpc/platforms/pseries/dlpar.c
arch/s390/Kconfig
arch/s390/crypto/crypt_s390.h
arch/s390/crypto/ghash_s390.c
arch/s390/crypto/prng.c
arch/s390/include/asm/kexec.h
arch/s390/include/asm/mmu.h
arch/s390/include/asm/mmu_context.h
arch/s390/include/asm/pgalloc.h
arch/s390/include/asm/pgtable.h
arch/s390/mm/hugetlbpage.c
arch/s390/mm/pgtable.c
arch/s390/net/bpf_jit.h
arch/s390/net/bpf_jit_comp.c
arch/score/lib/string.S
arch/sparc/include/asm/cpudata_64.h
arch/sparc/include/asm/pgtable_64.h
arch/sparc/include/asm/topology_64.h
arch/sparc/include/asm/trap_block.h
arch/sparc/kernel/entry.h
arch/sparc/kernel/leon_pci_grpci2.c
arch/sparc/kernel/mdesc.c
arch/sparc/kernel/pci.c
arch/sparc/kernel/setup_64.c
arch/sparc/kernel/smp_64.c
arch/sparc/kernel/vmlinux.lds.S
arch/sparc/mm/init_64.c
arch/tile/kernel/setup.c
arch/x86/boot/compressed/eboot.c
arch/x86/boot/compressed/misc.h
arch/x86/include/asm/hypervisor.h
arch/x86/include/asm/kvm_host.h
arch/x86/include/asm/ptrace.h
arch/x86/include/asm/pvclock.h
arch/x86/include/asm/segment.h
arch/x86/include/asm/spinlock.h
arch/x86/include/asm/xen/page.h
arch/x86/include/uapi/asm/msr-index.h
arch/x86/kernel/cpu/hypervisor.c
arch/x86/kernel/cpu/mcheck/mce.c
arch/x86/kernel/cpu/perf_event.c
arch/x86/kernel/cpu/perf_event.h
arch/x86/kernel/cpu/perf_event_intel.c
arch/x86/kernel/cpu/perf_event_intel_ds.c
arch/x86/kernel/cpu/perf_event_intel_pt.c
arch/x86/kernel/cpu/perf_event_intel_rapl.c
arch/x86/kernel/cpu/perf_event_intel_uncore.c
arch/x86/kernel/cpu/perf_event_intel_uncore.h
arch/x86/kernel/cpu/perf_event_intel_uncore_snb.c
arch/x86/kernel/cpu/perf_event_intel_uncore_snbep.c
arch/x86/kernel/head64.c
arch/x86/kernel/head_32.S
arch/x86/kernel/head_64.S
arch/x86/kernel/i387.c
arch/x86/kernel/process.c
arch/x86/kernel/pvclock.c
arch/x86/kvm/cpuid.c
arch/x86/kvm/cpuid.h
arch/x86/kvm/mmu.c
arch/x86/kvm/mmu.h
arch/x86/kvm/paging_tmpl.h
arch/x86/kvm/svm.c
arch/x86/kvm/vmx.c
arch/x86/kvm/x86.c
arch/x86/mm/ioremap.c
arch/x86/net/bpf_jit_comp.c
arch/x86/pci/acpi.c
arch/x86/vdso/Makefile
arch/x86/vdso/vclock_gettime.c
arch/x86/xen/enlighten.c
arch/x86/xen/suspend.c
arch/xtensa/include/asm/dma-mapping.h
block/blk-core.c
block/blk-mq.c
block/blk-sysfs.c
block/bounce.c
block/elevator.c
block/genhd.c
crypto/Kconfig
crypto/algif_aead.c
drivers/acpi/acpi_pnp.c
drivers/acpi/acpica/utglobal.c
drivers/acpi/osl.c
drivers/acpi/resource.c
drivers/acpi/sbs.c
drivers/acpi/sbshc.c
drivers/ata/Kconfig
drivers/ata/Makefile
drivers/ata/ahci.c
drivers/ata/ahci_mvebu.c
drivers/ata/ahci_st.c
drivers/ata/libahci.c
drivers/ata/libata-core.c
drivers/ata/libata-eh.c
drivers/ata/pata_octeon_cf.c
drivers/ata/pata_scc.c [deleted file]
drivers/base/cacheinfo.c
drivers/base/init.c
drivers/block/Kconfig
drivers/block/loop.c
drivers/block/nvme-core.c
drivers/block/nvme-scsi.c
drivers/block/rbd.c
drivers/block/xen-blkback/blkback.c
drivers/block/zram/zram_drv.c
drivers/bluetooth/ath3k.c
drivers/bluetooth/bt3c_cs.c
drivers/bluetooth/btbcm.c
drivers/bluetooth/btbcm.h
drivers/bluetooth/btusb.c
drivers/bluetooth/hci_ath.c
drivers/bus/arm-cci.c
drivers/bus/mips_cdmm.c
drivers/bus/mvebu-mbus.c
drivers/bus/omap_l3_noc.c
drivers/bus/omap_l3_noc.h
drivers/char/hw_random/bcm63xx-rng.c
drivers/char/ipmi/ipmi_msghandler.c
drivers/char/ipmi/ipmi_si_intf.c
drivers/char/ipmi/ipmi_ssif.c
drivers/clk/clk-si5351.c
drivers/clk/clk.c
drivers/clk/qcom/gcc-msm8916.c
drivers/clk/samsung/Makefile
drivers/clk/samsung/clk-exynos5420.c
drivers/clk/samsung/clk-exynos5433.c
drivers/cpuidle/cpuidle.c
drivers/dma/Kconfig
drivers/dma/at_xdmac.c
drivers/dma/dmaengine.c
drivers/dma/hsu/hsu.c
drivers/dma/pl330.c
drivers/dma/sh/rcar-dmac.c
drivers/dma/sh/usb-dmac.c
drivers/extcon/extcon-usb-gpio.c
drivers/firmware/dmi_scan.c
drivers/firmware/efi/runtime-map.c
drivers/firmware/iscsi_ibft.c
drivers/gpio/gpio-kempld.c
drivers/gpio/gpio-omap.c
drivers/gpio/gpiolib-acpi.c
drivers/gpio/gpiolib-sysfs.c
drivers/gpio/gpiolib.c
drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.c
drivers/gpu/drm/amd/amdkfd/kfd_topology.c
drivers/gpu/drm/drm_irq.c
drivers/gpu/drm/drm_plane_helper.c
drivers/gpu/drm/drm_sysfs.c
drivers/gpu/drm/exynos/exynos7_drm_decon.c
drivers/gpu/drm/exynos/exynos_dp_core.c
drivers/gpu/drm/exynos/exynos_drm_crtc.c
drivers/gpu/drm/exynos/exynos_drm_crtc.h
drivers/gpu/drm/exynos/exynos_drm_drv.h
drivers/gpu/drm/exynos/exynos_drm_fb.c
drivers/gpu/drm/exynos/exynos_drm_fimd.c
drivers/gpu/drm/exynos/exynos_drm_fimd.h [deleted file]
drivers/gpu/drm/exynos/exynos_drm_plane.c
drivers/gpu/drm/exynos/exynos_drm_vidi.c
drivers/gpu/drm/exynos/exynos_mixer.c
drivers/gpu/drm/i915/i915_debugfs.c
drivers/gpu/drm/i915/i915_drv.c
drivers/gpu/drm/i915/i915_gem.c
drivers/gpu/drm/i915/i915_reg.h
drivers/gpu/drm/i915/intel_display.c
drivers/gpu/drm/i915/intel_dp.c
drivers/gpu/drm/i915/intel_i2c.c
drivers/gpu/drm/i915/intel_lrc.c
drivers/gpu/drm/i915/intel_lvds.c
drivers/gpu/drm/i915/intel_pm.c
drivers/gpu/drm/i915/intel_ringbuffer.c
drivers/gpu/drm/i915/intel_sdvo.c
drivers/gpu/drm/i915/intel_uncore.c
drivers/gpu/drm/msm/adreno/adreno_gpu.c
drivers/gpu/drm/msm/dsi/dsi.c
drivers/gpu/drm/msm/dsi/dsi_host.c
drivers/gpu/drm/msm/dsi/dsi_manager.c
drivers/gpu/drm/msm/edp/edp_aux.c
drivers/gpu/drm/msm/edp/edp_connector.c
drivers/gpu/drm/msm/edp/edp_ctrl.c
drivers/gpu/drm/msm/mdp/mdp5/mdp5_cfg.c
drivers/gpu/drm/msm/mdp/mdp5/mdp5_cfg.h
drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.c
drivers/gpu/drm/msm/mdp/mdp5/mdp5_plane.c
drivers/gpu/drm/msm/msm_drv.c
drivers/gpu/drm/msm/msm_fb.c
drivers/gpu/drm/msm/msm_gem.c
drivers/gpu/drm/msm/msm_iommu.c
drivers/gpu/drm/msm/msm_ringbuffer.c
drivers/gpu/drm/nouveau/include/nvif/class.h
drivers/gpu/drm/nouveau/nvkm/engine/gr/gm204.c
drivers/gpu/drm/nouveau/nvkm/subdev/devinit/gf100.c
drivers/gpu/drm/nouveau/nvkm/subdev/devinit/gm107.c
drivers/gpu/drm/nouveau/nvkm/subdev/devinit/gm204.c
drivers/gpu/drm/nouveau/nvkm/subdev/devinit/nv50.h
drivers/gpu/drm/radeon/atombios_dp.c
drivers/gpu/drm/radeon/atombios_encoders.c
drivers/gpu/drm/radeon/cik.c
drivers/gpu/drm/radeon/dce3_1_afmt.c
drivers/gpu/drm/radeon/dce6_afmt.c
drivers/gpu/drm/radeon/evergreen_hdmi.c
drivers/gpu/drm/radeon/ni.c
drivers/gpu/drm/radeon/r600_hdmi.c
drivers/gpu/drm/radeon/radeon.h
drivers/gpu/drm/radeon/radeon_asic.c
drivers/gpu/drm/radeon/radeon_asic.h
drivers/gpu/drm/radeon/radeon_audio.c
drivers/gpu/drm/radeon/radeon_cs.c
drivers/gpu/drm/radeon/radeon_device.c
drivers/gpu/drm/radeon/radeon_dp_auxch.c
drivers/gpu/drm/radeon/radeon_dp_mst.c
drivers/gpu/drm/radeon/radeon_mn.c
drivers/gpu/drm/radeon/radeon_ttm.c
drivers/gpu/drm/radeon/radeon_uvd.c
drivers/gpu/drm/radeon/radeon_vce.c
drivers/gpu/drm/radeon/radeon_vm.c
drivers/gpu/drm/radeon/rv770d.h
drivers/gpu/drm/radeon/si.c
drivers/gpu/drm/radeon/si_dpm.c
drivers/gpu/drm/radeon/uvd_v1_0.c
drivers/gpu/drm/radeon/uvd_v2_2.c
drivers/gpu/drm/rockchip/rockchip_drm_vop.c
drivers/gpu/drm/tegra/drm.c
drivers/gpu/drm/vgem/Makefile
drivers/gpu/drm/vgem/vgem_dma_buf.c [deleted file]
drivers/gpu/drm/vgem/vgem_drv.c
drivers/gpu/drm/vgem/vgem_drv.h
drivers/hid/hid-ids.h
drivers/hid/hid-logitech-hidpp.c
drivers/hid/hid-sensor-hub.c
drivers/hid/i2c-hid/i2c-hid.c
drivers/hid/usbhid/hid-quirks.c
drivers/hid/wacom_wac.c
drivers/hwmon/nct6683.c
drivers/hwmon/nct6775.c
drivers/hwmon/ntc_thermistor.c
drivers/hwmon/tmp401.c
drivers/i2c/busses/i2c-hix5hd2.c
drivers/i2c/busses/i2c-s3c2410.c
drivers/ide/Kconfig
drivers/ide/Makefile
drivers/ide/scc_pata.c [deleted file]
drivers/iio/accel/mma9551_core.c
drivers/iio/accel/mma9553.c
drivers/iio/accel/st_accel_core.c
drivers/iio/adc/axp288_adc.c
drivers/iio/adc/cc10001_adc.c
drivers/iio/adc/mcp320x.c
drivers/iio/adc/qcom-spmi-vadc.c
drivers/iio/adc/twl6030-gpadc.c
drivers/iio/adc/xilinx-xadc-core.c
drivers/iio/adc/xilinx-xadc.h
drivers/iio/common/st_sensors/st_sensors_core.c
drivers/iio/gyro/st_gyro_core.c
drivers/iio/imu/adis16400.h
drivers/iio/imu/adis16400_buffer.c
drivers/iio/imu/adis16400_core.c
drivers/iio/kfifo_buf.c
drivers/iio/light/hid-sensor-prox.c
drivers/iio/magnetometer/st_magn_core.c
drivers/iio/pressure/bmp280.c
drivers/iio/pressure/hid-sensor-press.c
drivers/iio/pressure/st_pressure_core.c
drivers/infiniband/core/addr.c
drivers/infiniband/core/cm.c
drivers/infiniband/core/cm_msgs.h
drivers/infiniband/core/cma.c
drivers/infiniband/core/iwpm_msg.c
drivers/infiniband/core/iwpm_util.c
drivers/infiniband/core/iwpm_util.h
drivers/infiniband/core/umem_odp.c
drivers/infiniband/hw/cxgb4/cm.c
drivers/infiniband/hw/cxgb4/cq.c
drivers/infiniband/hw/cxgb4/device.c
drivers/infiniband/hw/cxgb4/iw_cxgb4.h
drivers/infiniband/hw/cxgb4/mem.c
drivers/infiniband/hw/cxgb4/qp.c
drivers/infiniband/hw/cxgb4/t4.h
drivers/infiniband/hw/cxgb4/t4fw_ri_api.h
drivers/infiniband/hw/ehca/ehca_mcast.c
drivers/infiniband/hw/mlx4/main.c
drivers/infiniband/hw/mlx5/qp.c
drivers/infiniband/hw/nes/nes.c
drivers/infiniband/hw/nes/nes_cm.c
drivers/infiniband/hw/ocrdma/ocrdma.h
drivers/infiniband/hw/ocrdma/ocrdma_ah.c
drivers/infiniband/hw/ocrdma/ocrdma_hw.c
drivers/infiniband/hw/ocrdma/ocrdma_sli.h
drivers/infiniband/hw/ocrdma/ocrdma_verbs.c
drivers/infiniband/hw/qib/qib.h
drivers/infiniband/hw/qib/qib_file_ops.c
drivers/infiniband/hw/qib/qib_iba6120.c
drivers/infiniband/hw/qib/qib_iba7220.c
drivers/infiniband/hw/qib/qib_iba7322.c
drivers/infiniband/hw/qib/qib_init.c
drivers/infiniband/hw/qib/qib_wc_x86_64.c
drivers/infiniband/ulp/ipoib/ipoib_cm.c
drivers/infiniband/ulp/isert/ib_isert.c
drivers/input/joydev.c
drivers/input/mouse/Kconfig
drivers/input/mouse/alps.c
drivers/input/mouse/elantech.c
drivers/input/mouse/synaptics.c
drivers/input/touchscreen/stmpe-ts.c
drivers/input/touchscreen/sx8654.c
drivers/iommu/amd_iommu.c
drivers/iommu/amd_iommu_v2.c
drivers/iommu/arm-smmu.c
drivers/iommu/intel-iommu.c
drivers/iommu/rockchip-iommu.c
drivers/irqchip/irq-gic-v3-its.c
drivers/irqchip/irq-gic.c
drivers/irqchip/irq-mips-gic.c
drivers/irqchip/irq-sunxi-nmi.c
drivers/irqchip/irq-tegra.c
drivers/lguest/core.c
drivers/md/bitmap.c
drivers/md/dm-crypt.c
drivers/md/dm-ioctl.c
drivers/md/dm-mpath.c
drivers/md/dm-table.c
drivers/md/dm.c
drivers/md/md.c
drivers/md/raid0.c
drivers/md/raid10.c
drivers/md/raid5.c
drivers/md/raid5.h
drivers/media/platform/marvell-ccic/mcam-core.c
drivers/media/platform/marvell-ccic/mcam-core.h
drivers/media/platform/soc_camera/rcar_vin.c
drivers/mfd/da9052-core.c
drivers/mmc/card/block.c
drivers/mmc/card/queue.c
drivers/mmc/card/queue.h
drivers/mmc/core/core.c
drivers/mmc/host/atmel-mci.c
drivers/mmc/host/dw_mmc.c
drivers/mmc/host/sh_mmcif.c
drivers/mtd/devices/m25p80.c
drivers/mtd/tests/readtest.c
drivers/mtd/ubi/block.c
drivers/net/bonding/bond_main.c
drivers/net/bonding/bond_options.c
drivers/net/bonding/bond_procfs.c
drivers/net/bonding/bonding_priv.h [new file with mode: 0644]
drivers/net/can/Kconfig
drivers/net/can/usb/kvaser_usb.c
drivers/net/can/xilinx_can.c
drivers/net/dsa/mv88e6xxx.c
drivers/net/ethernet/8390/etherh.c
drivers/net/ethernet/altera/altera_msgdmahw.h
drivers/net/ethernet/altera/altera_tse_main.c
drivers/net/ethernet/amd/Kconfig
drivers/net/ethernet/amd/xgbe/xgbe-drv.c
drivers/net/ethernet/apm/xgene/Kconfig
drivers/net/ethernet/arc/Kconfig
drivers/net/ethernet/atheros/atl1e/atl1e_hw.h
drivers/net/ethernet/broadcom/b44.c
drivers/net/ethernet/broadcom/bcmsysport.h
drivers/net/ethernet/broadcom/bgmac.c
drivers/net/ethernet/broadcom/bnx2x/bnx2x.h
drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c
drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.h
drivers/net/ethernet/broadcom/bnx2x/bnx2x_ethtool.c
drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c
drivers/net/ethernet/broadcom/bnx2x/bnx2x_stats.c
drivers/net/ethernet/broadcom/bnx2x/bnx2x_vfpf.c
drivers/net/ethernet/broadcom/genet/bcmmii.c
drivers/net/ethernet/broadcom/tg3.c
drivers/net/ethernet/brocade/bna/bfa_ioc.c
drivers/net/ethernet/brocade/bna/bnad.c
drivers/net/ethernet/brocade/bna/cna_fwimg.c
drivers/net/ethernet/cadence/macb.c
drivers/net/ethernet/cadence/macb.h
drivers/net/ethernet/chelsio/cxgb4/t4_hw.c
drivers/net/ethernet/cisco/enic/enic_ethtool.c
drivers/net/ethernet/cisco/enic/enic_main.c
drivers/net/ethernet/cisco/enic/vnic_rq.c
drivers/net/ethernet/emulex/benet/be_cmds.c
drivers/net/ethernet/emulex/benet/be_ethtool.c
drivers/net/ethernet/emulex/benet/be_main.c
drivers/net/ethernet/freescale/fec_main.c
drivers/net/ethernet/ibm/ehea/ehea_main.c
drivers/net/ethernet/ibm/emac/core.c
drivers/net/ethernet/ibm/emac/core.h
drivers/net/ethernet/ibm/ibmveth.c
drivers/net/ethernet/intel/e1000e/e1000.h
drivers/net/ethernet/intel/fm10k/fm10k_main.c
drivers/net/ethernet/intel/i40e/i40e.h
drivers/net/ethernet/intel/i40e/i40e_debugfs.c
drivers/net/ethernet/intel/i40e/i40e_main.c
drivers/net/ethernet/intel/i40e/i40e_txrx.c
drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c
drivers/net/ethernet/intel/i40evf/i40e_txrx.c
drivers/net/ethernet/intel/igb/igb_main.c
drivers/net/ethernet/intel/igb/igb_ptp.c
drivers/net/ethernet/intel/ixgbe/ixgbe_main.c
drivers/net/ethernet/intel/ixgbevf/ixgbevf_main.c
drivers/net/ethernet/marvell/pxa168_eth.c
drivers/net/ethernet/mellanox/mlx4/cmd.c
drivers/net/ethernet/mellanox/mlx4/en_ethtool.c
drivers/net/ethernet/mellanox/mlx4/en_netdev.c
drivers/net/ethernet/mellanox/mlx4/en_port.c
drivers/net/ethernet/mellanox/mlx4/en_rx.c
drivers/net/ethernet/mellanox/mlx4/en_tx.c
drivers/net/ethernet/mellanox/mlx4/fw.c
drivers/net/ethernet/mellanox/mlx4/mlx4_en.h
drivers/net/ethernet/mellanox/mlx4/resource_tracker.c
drivers/net/ethernet/myricom/myri10ge/myri10ge.c
drivers/net/ethernet/qlogic/netxen/netxen_nic_init.c
drivers/net/ethernet/qlogic/netxen/netxen_nic_main.c
drivers/net/ethernet/qualcomm/qca_spi.c
drivers/net/ethernet/realtek/r8169.c
drivers/net/ethernet/rocker/rocker.c
drivers/net/ethernet/sfc/rx.c
drivers/net/ethernet/smsc/smc91x.c
drivers/net/ethernet/smsc/smsc911x.c
drivers/net/ethernet/stmicro/stmmac/stmmac.h
drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c
drivers/net/ethernet/ti/netcp_ethss.c
drivers/net/ethernet/xilinx/ll_temac_main.c
drivers/net/hyperv/hyperv_net.h
drivers/net/hyperv/netvsc.c
drivers/net/hyperv/netvsc_drv.c
drivers/net/hyperv/rndis_filter.c
drivers/net/ieee802154/at86rf230.c
drivers/net/macvlan.c
drivers/net/phy/Kconfig
drivers/net/phy/amd-xgbe-phy.c
drivers/net/phy/bcm7xxx.c
drivers/net/phy/dp83640.c
drivers/net/phy/mdio-gpio.c
drivers/net/phy/mdio-mux-gpio.c
drivers/net/phy/micrel.c
drivers/net/phy/phy.c
drivers/net/ppp/ppp_mppe.c
drivers/net/ppp/pppoe.c
drivers/net/usb/cdc_ncm.c
drivers/net/usb/r8152.c
drivers/net/usb/usbnet.c
drivers/net/vxlan.c
drivers/net/wireless/ath/ath9k/xmit.c
drivers/net/wireless/brcm80211/brcmfmac/msgbuf.c
drivers/net/wireless/iwlwifi/Kconfig
drivers/net/wireless/iwlwifi/iwl-7000.c
drivers/net/wireless/iwlwifi/iwl-eeprom-parse.c
drivers/net/wireless/iwlwifi/iwl-eeprom-parse.h
drivers/net/wireless/iwlwifi/iwl-fw-file.h
drivers/net/wireless/iwlwifi/iwl-nvm-parse.c
drivers/net/wireless/iwlwifi/iwl-trans.h
drivers/net/wireless/iwlwifi/mvm/coex_legacy.c
drivers/net/wireless/iwlwifi/mvm/d3.c
drivers/net/wireless/iwlwifi/mvm/fw-api-power.h
drivers/net/wireless/iwlwifi/mvm/fw-api-scan.h
drivers/net/wireless/iwlwifi/mvm/fw-api.h
drivers/net/wireless/iwlwifi/mvm/fw.c
drivers/net/wireless/iwlwifi/mvm/mac80211.c
drivers/net/wireless/iwlwifi/mvm/mvm.h
drivers/net/wireless/iwlwifi/mvm/ops.c
drivers/net/wireless/iwlwifi/mvm/rs.c
drivers/net/wireless/iwlwifi/mvm/rx.c
drivers/net/wireless/iwlwifi/mvm/scan.c
drivers/net/wireless/iwlwifi/pcie/internal.h
drivers/net/wireless/iwlwifi/pcie/trans.c
drivers/net/wireless/iwlwifi/pcie/tx.c
drivers/net/wireless/rtlwifi/usb.c
drivers/net/xen-netback/netback.c
drivers/net/xen-netback/xenbus.c
drivers/net/xen-netfront.c
drivers/ntb/ntb_hw.c
drivers/of/base.c
drivers/of/dynamic.c
drivers/parisc/superio.c
drivers/pci/setup-bus.c
drivers/phy/Kconfig
drivers/phy/phy-core.c
drivers/phy/phy-omap-usb2.c
drivers/phy/phy-rcar-gen2.c
drivers/pinctrl/bcm/pinctrl-cygnus-gpio.c
drivers/pinctrl/core.c
drivers/pinctrl/core.h
drivers/pinctrl/devicetree.c
drivers/pinctrl/intel/pinctrl-cherryview.c
drivers/pinctrl/mediatek/pinctrl-mtk-common.c
drivers/pinctrl/meson/pinctrl-meson.c
drivers/pinctrl/meson/pinctrl-meson8b.c
drivers/pinctrl/mvebu/pinctrl-armada-370.c
drivers/pinctrl/qcom/pinctrl-spmi-gpio.c
drivers/pinctrl/qcom/pinctrl-spmi-mpp.c
drivers/platform/x86/ideapad-laptop.c
drivers/platform/x86/thinkpad_acpi.c
drivers/power/axp288_fuel_gauge.c
drivers/power/bq27x00_battery.c
drivers/power/collie_battery.c
drivers/power/reset/Kconfig
drivers/power/reset/at91-reset.c
drivers/power/reset/ltc2952-poweroff.c
drivers/pwm/pwm-img.c
drivers/regulator/arizona-ldo1.c
drivers/regulator/da9052-regulator.c
drivers/rtc/Kconfig
drivers/rtc/Makefile
drivers/rtc/rtc-abx80x.c [new file with mode: 0644]
drivers/rtc/rtc-armada38x.c
drivers/s390/char/con3215.c
drivers/s390/crypto/ap_bus.c
drivers/scsi/3w-9xxx.c
drivers/scsi/3w-9xxx.h
drivers/scsi/3w-sas.c
drivers/scsi/3w-sas.h
drivers/scsi/3w-xxxx.c
drivers/scsi/3w-xxxx.h
drivers/scsi/aha1542.c
drivers/scsi/be2iscsi/be.h
drivers/scsi/be2iscsi/be_cmds.c
drivers/scsi/be2iscsi/be_cmds.h
drivers/scsi/be2iscsi/be_iscsi.c
drivers/scsi/be2iscsi/be_iscsi.h
drivers/scsi/be2iscsi/be_main.c
drivers/scsi/be2iscsi/be_main.h
drivers/scsi/be2iscsi/be_mgmt.c
drivers/scsi/be2iscsi/be_mgmt.h
drivers/scsi/lpfc/lpfc_scsi.c
drivers/scsi/qla2xxx/tcm_qla2xxx.c
drivers/scsi/scsi_devinfo.c
drivers/scsi/scsi_scan.c
drivers/scsi/sd.c
drivers/scsi/storvsc_drv.c
drivers/sh/pm_runtime.c
drivers/soc/mediatek/Kconfig
drivers/soc/mediatek/mtk-pmic-wrap.c
drivers/spi/Kconfig
drivers/spi/spi-bcm2835.c
drivers/spi/spi-bitbang.c
drivers/spi/spi-fsl-cpm.c
drivers/spi/spi-fsl-espi.c
drivers/spi/spi-omap2-mcspi.c
drivers/spi/spi.c
drivers/ssb/driver_chipcommon_pmu.c
drivers/ssb/driver_pcicore.c
drivers/staging/gdm724x/gdm_mux.c
drivers/staging/media/omap4iss/Kconfig
drivers/staging/media/omap4iss/iss.c
drivers/staging/media/omap4iss/iss.h
drivers/staging/media/omap4iss/iss_csiphy.c
drivers/staging/ozwpan/ozhcd.c
drivers/staging/ozwpan/ozusbif.h
drivers/staging/ozwpan/ozusbsvc1.c
drivers/staging/rtl8712/rtl8712_led.c
drivers/staging/rtl8712/rtl871x_cmd.c
drivers/staging/rtl8712/rtl871x_ioctl_linux.c
drivers/staging/rtl8712/rtl871x_mlme.c
drivers/staging/rtl8712/rtl871x_pwrctrl.c
drivers/staging/rtl8712/rtl871x_sta_mgt.c
drivers/staging/sm750fb/sm750.c
drivers/staging/vt6655/card.c
drivers/staging/vt6655/card.h
drivers/staging/vt6655/device_main.c
drivers/staging/vt6656/rxtx.c
drivers/target/iscsi/iscsi_target.c
drivers/target/iscsi/iscsi_target_login.c
drivers/target/iscsi/iscsi_target_tpg.c
drivers/target/target_core_alua.c
drivers/target/target_core_configfs.c
drivers/target/target_core_device.c
drivers/target/target_core_file.c
drivers/target/target_core_iblock.c
drivers/target/target_core_internal.h
drivers/target/target_core_pr.c
drivers/target/target_core_pscsi.c
drivers/target/target_core_pscsi.h
drivers/target/target_core_rd.c
drivers/target/target_core_sbc.c
drivers/target/target_core_transport.c
drivers/target/target_core_user.c
drivers/target/target_core_xcopy.c
drivers/thermal/armada_thermal.c
drivers/thermal/intel_powerclamp.c
drivers/thermal/rockchip_thermal.c
drivers/thermal/thermal_core.h
drivers/thermal/ti-soc-thermal/dra752-thermal-data.c
drivers/thermal/ti-soc-thermal/omap5-thermal-data.c
drivers/thermal/ti-soc-thermal/ti-bandgap.c
drivers/thermal/ti-soc-thermal/ti-bandgap.h
drivers/tty/hvc/hvc_xen.c
drivers/tty/mips_ejtag_fdc.c
drivers/tty/n_gsm.c
drivers/tty/n_hdlc.c
drivers/tty/n_tty.c
drivers/tty/pty.c
drivers/tty/serial/8250/8250_omap.c
drivers/tty/serial/8250/8250_pci.c
drivers/tty/serial/amba-pl011.c
drivers/tty/serial/atmel_serial.c
drivers/tty/serial/earlycon.c
drivers/tty/serial/imx.c
drivers/tty/serial/of_serial.c
drivers/tty/serial/omap-serial.c
drivers/tty/serial/samsung.c
drivers/tty/serial/serial_core.c
drivers/tty/serial/uartlite.c
drivers/tty/serial/xilinx_uartps.c
drivers/tty/tty_buffer.c
drivers/tty/tty_ioctl.c
drivers/usb/chipidea/debug.c
drivers/usb/chipidea/otg_fsm.c
drivers/usb/class/cdc-acm.c
drivers/usb/core/quirks.c
drivers/usb/dwc3/core.h
drivers/usb/dwc3/dwc3-omap.c
drivers/usb/gadget/configfs.c
drivers/usb/gadget/function/f_fs.c
drivers/usb/gadget/function/f_hid.c
drivers/usb/gadget/function/f_midi.c
drivers/usb/gadget/function/f_uac1.c
drivers/usb/gadget/function/u_serial.c
drivers/usb/gadget/legacy/acm_ms.c
drivers/usb/gadget/legacy/audio.c
drivers/usb/gadget/legacy/cdc2.c
drivers/usb/gadget/legacy/dbgp.c
drivers/usb/gadget/legacy/ether.c
drivers/usb/gadget/legacy/g_ffs.c
drivers/usb/gadget/legacy/gmidi.c
drivers/usb/gadget/legacy/hid.c
drivers/usb/gadget/legacy/mass_storage.c
drivers/usb/gadget/legacy/multi.c
drivers/usb/gadget/legacy/ncm.c
drivers/usb/gadget/legacy/nokia.c
drivers/usb/gadget/legacy/printer.c
drivers/usb/gadget/legacy/serial.c
drivers/usb/gadget/legacy/tcm_usb_gadget.c
drivers/usb/gadget/legacy/webcam.c
drivers/usb/gadget/legacy/zero.c
drivers/usb/gadget/udc/at91_udc.c
drivers/usb/gadget/udc/atmel_usba_udc.c
drivers/usb/gadget/udc/fsl_udc_core.c
drivers/usb/gadget/udc/fusb300_udc.c
drivers/usb/gadget/udc/m66592-udc.c
drivers/usb/gadget/udc/r8a66597-udc.c
drivers/usb/gadget/udc/s3c2410_udc.c
drivers/usb/gadget/udc/udc-xilinx.c
drivers/usb/host/ehci-msm.c
drivers/usb/host/xhci-ring.c
drivers/usb/host/xhci.c
drivers/usb/host/xhci.h
drivers/usb/musb/musb_core.c
drivers/usb/phy/phy-ab8500-usb.c
drivers/usb/phy/phy-isp1301-omap.c
drivers/usb/phy/phy-tahvo.c
drivers/usb/renesas_usbhs/fifo.c
drivers/usb/serial/cp210x.c
drivers/usb/serial/ftdi_sio.c
drivers/usb/serial/ftdi_sio_ids.h
drivers/usb/serial/pl2303.c
drivers/usb/serial/pl2303.h
drivers/usb/serial/visor.c
drivers/usb/storage/uas-detect.h
drivers/usb/storage/uas.c
drivers/usb/storage/unusual_devs.h
drivers/usb/storage/usb.c
drivers/vfio/pci/vfio_pci.c
drivers/vfio/vfio.c
drivers/vhost/scsi.c
drivers/video/backlight/pwm_bl.c
drivers/virtio/virtio_pci_common.c
drivers/xen/events/events_2l.c
drivers/xen/events/events_base.c
drivers/xen/gntdev.c
drivers/xen/grant-table.c
drivers/xen/manage.c
drivers/xen/swiotlb-xen.c
drivers/xen/xen-pciback/conf_space.c
drivers/xen/xen-pciback/conf_space.h
drivers/xen/xen-pciback/conf_space_header.c
drivers/xen/xenbus/xenbus_probe.c
fs/binfmt_elf.c
fs/btrfs/backref.c
fs/btrfs/delayed-inode.c
fs/btrfs/extent-tree.c
fs/btrfs/extent_io.c
fs/btrfs/free-space-cache.c
fs/btrfs/inode.c
fs/btrfs/ioctl.c
fs/btrfs/ordered-data.c
fs/btrfs/volumes.c
fs/cifs/cifs_dfs_ref.c
fs/cifs/cifs_unicode.c
fs/cifs/cifsfs.c
fs/cifs/cifsproto.h
fs/cifs/cifssmb.c
fs/cifs/connect.c
fs/cifs/dir.c
fs/cifs/file.c
fs/cifs/inode.c
fs/cifs/link.c
fs/cifs/readdir.c
fs/cifs/smb1ops.c
fs/cifs/smb2pdu.c
fs/configfs/mount.c
fs/dcache.c
fs/efivarfs/super.c
fs/exec.c
fs/ext4/Kconfig
fs/ext4/crypto_fname.c
fs/ext4/crypto_key.c
fs/ext4/crypto_policy.c
fs/ext4/dir.c
fs/ext4/ext4.h
fs/ext4/ext4_crypto.h
fs/ext4/ext4_jbd2.c
fs/ext4/extents.c
fs/ext4/extents_status.c
fs/ext4/inode.c
fs/ext4/namei.c
fs/ext4/resize.c
fs/ext4/super.c
fs/ext4/symlink.c
fs/f2fs/data.c
fs/f2fs/f2fs.h
fs/f2fs/namei.c
fs/f2fs/super.c
fs/fhandle.c
fs/hostfs/hostfs_kern.c
fs/jbd2/recovery.c
fs/jbd2/revoke.c
fs/jbd2/transaction.c
fs/kernfs/dir.c
fs/namei.c
fs/namespace.c
fs/nfs/nfs4proc.c
fs/nfs/write.c
fs/nfsd/blocklayout.c
fs/nfsd/nfs4callback.c
fs/nfsd/nfs4state.c
fs/nfsd/state.h
fs/nfsd/xdr4.h
fs/nilfs2/btree.c
fs/ocfs2/dlm/dlmmaster.c
fs/omfs/bitmap.c
fs/omfs/inode.c
fs/overlayfs/copy_up.c
fs/overlayfs/dir.c
fs/overlayfs/super.c
fs/splice.c
fs/xfs/libxfs/xfs_attr_leaf.c
fs/xfs/libxfs/xfs_attr_leaf.h
fs/xfs/libxfs/xfs_bmap.c
fs/xfs/libxfs/xfs_ialloc.c
fs/xfs/xfs_attr_inactive.c
fs/xfs/xfs_file.c
fs/xfs/xfs_inode.c
fs/xfs/xfs_mount.c
include/acpi/actypes.h
include/drm/drm_pciids.h
include/dt-bindings/sound/apq8016-lpass.h [new file with mode: 0644]
include/dt-bindings/sound/audio-jack-events.h [new file with mode: 0644]
include/dt-bindings/sound/tas2552.h [new file with mode: 0644]
include/linux/backing-dev.h
include/linux/blk_types.h
include/linux/blkdev.h
include/linux/brcmphy.h
include/linux/compiler-gcc.h
include/linux/compiler-intel.h
include/linux/compiler.h
include/linux/cpumask.h
include/linux/ftrace_event.h
include/linux/gfp.h
include/linux/hid-sensor-hub.h
include/linux/intel-iommu.h
include/linux/irqchip/arm-gic.h
include/linux/kexec.h
include/linux/ktime.h
include/linux/libata.h
include/linux/memcontrol.h
include/linux/netdevice.h
include/linux/netfilter_bridge.h
include/linux/nilfs2_fs.h
include/linux/of.h
include/linux/pci_ids.h
include/linux/percpu_counter.h
include/linux/perf_event.h
include/linux/platform_data/si5351.h
include/linux/rhashtable.h
include/linux/rtnetlink.h
include/linux/sched.h
include/linux/sched/rt.h
include/linux/skbuff.h
include/linux/tcp.h
include/linux/tty.h
include/linux/uidgid.h
include/linux/usb_usual.h
include/linux/util_macros.h
include/net/bonding.h
include/net/cfg802154.h
include/net/codel.h
include/net/inet_connection_sock.h
include/net/mac80211.h
include/net/mac802154.h
include/net/request_sock.h
include/net/sctp/sctp.h
include/net/tcp.h
include/rdma/ib_addr.h
include/rdma/ib_cm.h
include/rdma/iw_portmap.h
include/scsi/scsi_devinfo.h
include/sound/designware_i2s.h
include/sound/dmaengine_pcm.h
include/sound/emu10k1.h
include/sound/hda_regmap.h
include/sound/rt5645.h
include/sound/soc-dapm.h
include/sound/soc-topology.h [new file with mode: 0644]
include/sound/soc.h
include/sound/spear_dma.h
include/sound/tlv.h
include/target/target_core_backend.h
include/target/target_core_configfs.h
include/target/target_core_fabric.h
include/trace/events/kmem.h
include/trace/events/writeback.h
include/uapi/linux/inet_diag.h
include/uapi/linux/mpls.h
include/uapi/linux/netfilter/nf_conntrack_tcp.h
include/uapi/linux/rtnetlink.h
include/uapi/linux/tcp.h
include/uapi/linux/virtio_balloon.h
include/uapi/linux/virtio_ring.h
include/uapi/rdma/rdma_netlink.h
include/uapi/sound/asoc.h [new file with mode: 0644]
include/uapi/sound/tlv.h [new file with mode: 0644]
include/xen/events.h
include/xen/grant_table.h
include/xen/xen-ops.h
init/do_mounts.c
kernel/Makefile
kernel/bpf/core.c
kernel/compat.c
kernel/events/core.c
kernel/events/ring_buffer.c
kernel/irq/dummychip.c
kernel/kexec.c
kernel/locking/lockdep.c
kernel/locking/lockdep_proc.c
kernel/locking/rtmutex.c
kernel/module.c
kernel/rcu/tree.c
kernel/sched/core.c
kernel/sched/fair.c
kernel/sched/idle.c
kernel/time/clockevents.c
kernel/time/hrtimer.c
kernel/trace/ring_buffer_benchmark.c
kernel/trace/trace_output.c
kernel/watchdog.c
lib/Kconfig.debug
lib/Kconfig.kasan
lib/cpumask.c
lib/find_last_bit.c [deleted file]
lib/mpi/longlong.h
lib/percpu_counter.c
lib/rhashtable.c
lib/string.c
lib/strnlen_user.c
lib/swiotlb.c
mm/backing-dev.c
mm/hwpoison-inject.c
mm/kmemleak.c
mm/memcontrol.c
mm/memory-failure.c
mm/memory_hotplug.c
mm/mempolicy.c
mm/page-writeback.c
mm/page_isolation.c
mm/zsmalloc.c
net/8021q/vlan.c
net/bluetooth/hci_core.c
net/bridge/br_fdb.c
net/bridge/br_mdb.c
net/bridge/br_multicast.c
net/bridge/br_netfilter.c
net/bridge/br_netlink.c
net/bridge/br_private.h
net/bridge/br_stp_timer.c
net/caif/caif_socket.c
net/ceph/osd_client.c
net/core/dev.c
net/core/net_namespace.c
net/core/rtnetlink.c
net/core/skbuff.c
net/core/sock.c
net/dccp/ipv4.c
net/dccp/ipv6.c
net/dccp/minisocks.c
net/dsa/dsa.c
net/ieee802154/Makefile
net/ieee802154/nl-phy.c
net/ieee802154/nl802154.c
net/ieee802154/rdev-ops.h
net/ieee802154/trace.c [new file with mode: 0644]
net/ieee802154/trace.h [new file with mode: 0644]
net/ipv4/esp4.c
net/ipv4/fib_trie.c
net/ipv4/inet_connection_sock.c
net/ipv4/inet_diag.c
net/ipv4/ip_vti.c
net/ipv4/netfilter/arp_tables.c
net/ipv4/netfilter/ip_tables.c
net/ipv4/ping.c
net/ipv4/route.c
net/ipv4/tcp.c
net/ipv4/tcp_cong.c
net/ipv4/tcp_dctcp.c
net/ipv4/tcp_fastopen.c
net/ipv4/tcp_illinois.c
net/ipv4/tcp_input.c
net/ipv4/tcp_ipv4.c
net/ipv4/tcp_minisocks.c
net/ipv4/tcp_output.c
net/ipv4/tcp_vegas.c
net/ipv4/tcp_vegas.h
net/ipv4/tcp_westwood.c
net/ipv4/udp.c
net/ipv6/addrconf_core.c
net/ipv6/esp6.c
net/ipv6/ip6_fib.c
net/ipv6/ip6_gre.c
net/ipv6/ip6_output.c
net/ipv6/ip6_vti.c
net/ipv6/netfilter/ip6_tables.c
net/ipv6/route.c
net/ipv6/tcp_ipv6.c
net/ipv6/udp.c
net/mac80211/cfg.c
net/mac80211/ieee80211_i.h
net/mac80211/iface.c
net/mac80211/key.c
net/mac80211/key.h
net/mac80211/rx.c
net/mac80211/sta_info.c
net/mac80211/util.c
net/mac80211/wep.c
net/mac802154/cfg.c
net/mac802154/ieee802154_i.h
net/mac802154/iface.c
net/mac802154/llsec.c
net/mac802154/main.c
net/mpls/af_mpls.c
net/mpls/internal.h
net/netfilter/Kconfig
net/netfilter/ipvs/ip_vs_ctl.c
net/netfilter/nf_conntrack_proto_tcp.c
net/netfilter/nf_tables_api.c
net/netfilter/nfnetlink_log.c
net/netfilter/nfnetlink_queue_core.c
net/netfilter/nft_reject.c
net/netfilter/nft_reject_inet.c
net/netlink/af_netlink.c
net/openvswitch/vport-netdev.c
net/packet/af_packet.c
net/rds/connection.c
net/rds/ib_cm.c
net/rds/tcp_connect.c
net/rds/tcp_listen.c
net/sched/act_connmark.c
net/sched/cls_api.c
net/sched/sch_api.c
net/sched/sch_codel.c
net/sched/sch_fq_codel.c
net/sched/sch_gred.c
net/sctp/auth.c
net/sunrpc/auth_gss/gss_rpc_xdr.c
net/switchdev/switchdev.c
net/tipc/bearer.c
net/tipc/link.c
net/tipc/server.c
net/tipc/socket.c
net/unix/af_unix.c
net/unix/garbage.c
net/wireless/wext-compat.c
net/xfrm/xfrm_input.c
net/xfrm/xfrm_replay.c
net/xfrm/xfrm_state.c
scripts/checkpatch.pl
scripts/gdb/linux/modules.py
sound/atmel/ac97c.c
sound/core/pcm_lib.c
sound/hda/hdac_regmap.c
sound/pci/emu10k1/emu10k1.c
sound/pci/emu10k1/emu10k1_callback.c
sound/pci/emu10k1/emu10k1_main.c
sound/pci/emu10k1/emupcm.c
sound/pci/emu10k1/memory.c
sound/pci/hda/hda_codec.c
sound/pci/hda/hda_generic.c
sound/pci/hda/hda_intel.c
sound/pci/hda/hda_local.h
sound/pci/hda/patch_conexant.c
sound/pci/hda/patch_realtek.c
sound/pci/hda/patch_sigmatel.c
sound/pci/hda/patch_via.c
sound/soc/Kconfig
sound/soc/Makefile
sound/soc/atmel/Kconfig
sound/soc/atmel/atmel-pcm-dma.c
sound/soc/atmel/sam9g20_wm8731.c
sound/soc/au1x/db1200.c
sound/soc/cirrus/ep93xx-pcm.c
sound/soc/codecs/88pm860x-codec.c
sound/soc/codecs/Kconfig
sound/soc/codecs/Makefile
sound/soc/codecs/ab8500-codec.c
sound/soc/codecs/ac97.c
sound/soc/codecs/ad1836.c
sound/soc/codecs/adau1373.c
sound/soc/codecs/adau1701.c
sound/soc/codecs/adau1761.c
sound/soc/codecs/adau1781.c
sound/soc/codecs/adau17x1.c
sound/soc/codecs/adau1977.c
sound/soc/codecs/adav80x.c
sound/soc/codecs/ak4535.c
sound/soc/codecs/ak4641.c
sound/soc/codecs/ak4642.c
sound/soc/codecs/ak4671.c
sound/soc/codecs/alc5623.c
sound/soc/codecs/alc5632.c
sound/soc/codecs/arizona.c
sound/soc/codecs/arizona.h
sound/soc/codecs/bt-sco.c
sound/soc/codecs/cq93vc.c
sound/soc/codecs/cs35l32.c
sound/soc/codecs/cs4265.c
sound/soc/codecs/cs42l52.c
sound/soc/codecs/cs42l56.c
sound/soc/codecs/cs42l73.c
sound/soc/codecs/cs42xx8.c
sound/soc/codecs/cx20442.c
sound/soc/codecs/da7213.c
sound/soc/codecs/da732x.c
sound/soc/codecs/da9055.c
sound/soc/codecs/es8328.c
sound/soc/codecs/isabelle.c
sound/soc/codecs/jz4740.c
sound/soc/codecs/lm4857.c
sound/soc/codecs/lm49453.c
sound/soc/codecs/max98088.c
sound/soc/codecs/max98090.c
sound/soc/codecs/max98095.c
sound/soc/codecs/max98357a.c
sound/soc/codecs/max9850.c
sound/soc/codecs/max98925.c
sound/soc/codecs/mc13783.c
sound/soc/codecs/ml26124.c
sound/soc/codecs/pcm512x.c
sound/soc/codecs/rl6347a.c [new file with mode: 0644]
sound/soc/codecs/rl6347a.h [new file with mode: 0644]
sound/soc/codecs/rt286.c
sound/soc/codecs/rt5631.c
sound/soc/codecs/rt5640.c
sound/soc/codecs/rt5645.c
sound/soc/codecs/rt5645.h
sound/soc/codecs/rt5651.c
sound/soc/codecs/rt5670.c
sound/soc/codecs/rt5677.c
sound/soc/codecs/rt5677.h
sound/soc/codecs/sgtl5000.c
sound/soc/codecs/sirf-audio-codec.c
sound/soc/codecs/sn95031.c
sound/soc/codecs/ssm2518.c
sound/soc/codecs/ssm2602.c
sound/soc/codecs/ssm4567.c
sound/soc/codecs/sta32x.c
sound/soc/codecs/sta350.c
sound/soc/codecs/sta529.c
sound/soc/codecs/stac9766.c
sound/soc/codecs/tas2552.c
sound/soc/codecs/tas2552.h
sound/soc/codecs/tas571x.c [new file with mode: 0644]
sound/soc/codecs/tas571x.h [new file with mode: 0644]
sound/soc/codecs/tfa9879.c
sound/soc/codecs/tlv320aic23.c
sound/soc/codecs/tlv320aic31xx.c
sound/soc/codecs/tlv320aic32x4.c
sound/soc/codecs/tlv320aic3x.c
sound/soc/codecs/tlv320dac33.c
sound/soc/codecs/ts3a227e.c
sound/soc/codecs/twl4030.c
sound/soc/codecs/twl6040.c
sound/soc/codecs/uda134x.c
sound/soc/codecs/uda1380.c
sound/soc/codecs/wm0010.c
sound/soc/codecs/wm1250-ev1.c
sound/soc/codecs/wm5100.c
sound/soc/codecs/wm5102.c
sound/soc/codecs/wm5110.c
sound/soc/codecs/wm8350.c
sound/soc/codecs/wm8400.c
sound/soc/codecs/wm8510.c
sound/soc/codecs/wm8523.c
sound/soc/codecs/wm8580.c
sound/soc/codecs/wm8711.c
sound/soc/codecs/wm8728.c
sound/soc/codecs/wm8731.c
sound/soc/codecs/wm8737.c
sound/soc/codecs/wm8741.c
sound/soc/codecs/wm8741.h
sound/soc/codecs/wm8750.c
sound/soc/codecs/wm8753.c
sound/soc/codecs/wm8770.c
sound/soc/codecs/wm8776.c
sound/soc/codecs/wm8804.c
sound/soc/codecs/wm8900.c
sound/soc/codecs/wm8903.c
sound/soc/codecs/wm8903.h
sound/soc/codecs/wm8904.c
sound/soc/codecs/wm8940.c
sound/soc/codecs/wm8955.c
sound/soc/codecs/wm8960.c
sound/soc/codecs/wm8961.c
sound/soc/codecs/wm8962.c
sound/soc/codecs/wm8971.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/wm8990.c
sound/soc/codecs/wm8991.c
sound/soc/codecs/wm8993.c
sound/soc/codecs/wm8994.c
sound/soc/codecs/wm8995.c
sound/soc/codecs/wm8996.c
sound/soc/codecs/wm8997.c
sound/soc/codecs/wm9081.c
sound/soc/codecs/wm9090.c
sound/soc/codecs/wm9712.c
sound/soc/codecs/wm9713.c
sound/soc/codecs/wm_adsp.c
sound/soc/codecs/wm_adsp.h
sound/soc/codecs/wm_hubs.c
sound/soc/codecs/wmfw.h
sound/soc/davinci/davinci-mcasp.c
sound/soc/davinci/davinci-mcasp.h
sound/soc/fsl/fsl_dma.c
sound/soc/fsl/fsl_sai.c
sound/soc/fsl/fsl_sai.h
sound/soc/fsl/fsl_spdif.c
sound/soc/fsl/fsl_ssi.c
sound/soc/fsl/imx-audmux.c
sound/soc/fsl/imx-mc13783.c
sound/soc/fsl/imx-wm8962.c
sound/soc/intel/Kconfig
sound/soc/intel/Makefile
sound/soc/intel/atom/sst-atom-controls.c
sound/soc/intel/atom/sst-atom-controls.h
sound/soc/intel/atom/sst-mfld-platform-pcm.c
sound/soc/intel/atom/sst-mfld-platform.h
sound/soc/intel/atom/sst/sst.c
sound/soc/intel/atom/sst/sst_acpi.c
sound/soc/intel/atom/sst/sst_drv_interface.c
sound/soc/intel/baytrail/sst-baytrail-ipc.c
sound/soc/intel/boards/Makefile
sound/soc/intel/boards/cht_bsw_max98090_ti.c [new file with mode: 0644]
sound/soc/intel/boards/cht_bsw_rt5645.c
sound/soc/intel/common/sst-acpi.c
sound/soc/intel/common/sst-ipc.c
sound/soc/intel/common/sst-ipc.h
sound/soc/intel/haswell/sst-haswell-ipc.c
sound/soc/intel/haswell/sst-haswell-pcm.c
sound/soc/mediatek/Kconfig [new file with mode: 0644]
sound/soc/mediatek/Makefile [new file with mode: 0644]
sound/soc/mediatek/mt8173-max98090.c [new file with mode: 0644]
sound/soc/mediatek/mt8173-rt5650-rt5676.c [new file with mode: 0644]
sound/soc/mediatek/mtk-afe-common.h [new file with mode: 0644]
sound/soc/mediatek/mtk-afe-pcm.c [new file with mode: 0644]
sound/soc/omap/Kconfig
sound/soc/omap/omap-twl4030.c
sound/soc/omap/rx51.c
sound/soc/pxa/brownstone.c
sound/soc/pxa/poodle.c
sound/soc/pxa/tosa.c
sound/soc/pxa/z2.c
sound/soc/qcom/Kconfig
sound/soc/qcom/Makefile
sound/soc/qcom/apq8016_sbc.c [new file with mode: 0644]
sound/soc/qcom/lpass-apq8016.c [new file with mode: 0644]
sound/soc/qcom/lpass-cpu.c
sound/soc/qcom/lpass-ipq806x.c [new file with mode: 0644]
sound/soc/qcom/lpass-lpaif-ipq806x.h [deleted file]
sound/soc/qcom/lpass-lpaif-reg.h [new file with mode: 0644]
sound/soc/qcom/lpass-platform.c
sound/soc/qcom/lpass.h
sound/soc/qcom/storm.c
sound/soc/samsung/Kconfig
sound/soc/samsung/i2s.c
sound/soc/samsung/lowland.c
sound/soc/samsung/s3c24xx-i2s.c
sound/soc/samsung/smartq_wm8987.c
sound/soc/samsung/smdk_wm8994.c
sound/soc/samsung/speyside.c
sound/soc/sh/rcar/core.c
sound/soc/sh/rcar/dma.c
sound/soc/sh/rcar/dvc.c
sound/soc/sh/rcar/rsnd.h
sound/soc/sh/rcar/rsrc-card.c
sound/soc/sh/rcar/src.c
sound/soc/sh/rcar/ssi.c
sound/soc/soc-core.c
sound/soc/soc-dapm.c
sound/soc/soc-generic-dmaengine-pcm.c
sound/soc/soc-jack.c
sound/soc/soc-pcm.c
sound/soc/soc-topology.c [new file with mode: 0644]
sound/soc/ux500/mop500_ab8500.c
sound/soc/ux500/ux500_pcm.c
sound/soc/zte/Kconfig [new file with mode: 0644]
sound/soc/zte/Makefile [new file with mode: 0644]
sound/soc/zte/zx296702-i2s.c [new file with mode: 0644]
sound/soc/zte/zx296702-spdif.c [new file with mode: 0644]
sound/synth/emux/emux_oss.c
sound/synth/emux/emux_seq.c
sound/usb/mixer.c
sound/usb/mixer_maps.c
sound/usb/quirks.c
tools/lib/api/Makefile
tools/lib/lockdep/Makefile
tools/lib/lockdep/uinclude/linux/kernel.h
tools/lib/traceevent/event-parse.c
tools/net/bpf_jit_disasm.c
tools/perf/Makefile
tools/perf/bench/futex-requeue.c
tools/perf/bench/numa.c
tools/perf/builtin-kmem.c
tools/perf/builtin-report.c
tools/perf/builtin-top.c
tools/perf/builtin-trace.c
tools/perf/util/probe-event.c
tools/perf/util/probe-finder.c
tools/power/x86/turbostat/turbostat.c
tools/testing/selftests/powerpc/pmu/Makefile
tools/testing/selftests/powerpc/tm/Makefile
tools/testing/selftests/x86/Makefile
tools/testing/selftests/x86/check_cc.sh [new file with mode: 0755]
tools/testing/selftests/x86/entry_from_vm86.c [new file with mode: 0644]
tools/testing/selftests/x86/run_x86_tests.sh [deleted file]
tools/testing/selftests/x86/trivial_32bit_program.c
tools/testing/selftests/x86/trivial_64bit_program.c [new file with mode: 0644]
tools/thermal/tmon/Makefile
tools/vm/Makefile

diff --git a/CREDITS b/CREDITS
index 40cc4bfb34dbec35f2a03f4946e7868fd829c8d1..ec7e6c7fdd1b9c93342d808d1c65d8807e63312f 100644 (file)
--- a/CREDITS
+++ b/CREDITS
@@ -3709,6 +3709,13 @@ N: Dirk Verworner
 D: Co-author of German book ``Linux-Kernel-Programmierung''
 D: Co-founder of Berlin Linux User Group
 
+N: Andrew Victor
+E: linux@maxim.org.za
+W: http://maxim.org.za/at91_26.html
+D: First maintainer of Atmel ARM-based SoC, aka AT91
+D: Introduced support for at91rm9200, the first chip of AT91 family
+S: South Africa
+
 N: Riku Voipio
 E: riku.voipio@iki.fi
 D: Author of PCA9532 LED and Fintek f75375s hwmon driver
index 99983e67c13c9f6aadff74c1969a4d27cede7d26..da95513571ea3e3e53263f6c91588fb58d50f3fb 100644 (file)
@@ -162,7 +162,7 @@ Description:        Discover CPUs in the same CPU frequency coordination domain
 What:          /sys/devices/system/cpu/cpu*/cache/index3/cache_disable_{0,1}
 Date:          August 2008
 KernelVersion: 2.6.27
-Contact:       discuss@x86-64.org
+Contact:       Linux kernel mailing list <linux-kernel@vger.kernel.org>
 Description:   Disable L3 cache indices
 
                These files exist in every CPU's cache/index3 directory. Each
index 653d5d739d7ff5b55dbcd8d606b5d7e1da51a99f..31d1d658827f082f66c88c3147e99be3321635cf 100644 (file)
@@ -505,7 +505,10 @@ at module load time (for a module) with:
 
 The addresses are normal I2C addresses.  The adapter is the string
 name of the adapter, as shown in /sys/class/i2c-adapter/i2c-<n>/name.
-It is *NOT* i2c-<n> itself.
+It is *NOT* i2c-<n> itself.  Also, the comparison is done ignoring
+spaces, so if the name is "This is an I2C chip" you can say
+adapter_name=ThisisanI2cchip.  This is because it's hard to pass in
+spaces in kernel parameters.
 
 The debug flags are bit flags for each BMC found, they are:
 IPMI messages: 1, driver state: 2, timing: 4, I2C probe: 8
index 750401f9134190a210c8c24089a08ca9cb16559c..15dfce708ebf6ec3263ac0d66ff2b6f3a57471d4 100644 (file)
@@ -253,7 +253,7 @@ input driver:
 GPIO support
 ~~~~~~~~~~~~
 ACPI 5 introduced two new resources to describe GPIO connections: GpioIo
-and GpioInt. These resources are used be used to pass GPIO numbers used by
+and GpioInt. These resources can be used to pass GPIO numbers used by
 the device to the driver. ACPI 5.1 extended this with _DSD (Device
 Specific Data) which made it possible to name the GPIOs among other things.
 
index ae36fcf86dc7213c8b1a72bb0e698f89e51c878f..f35dad11f0de78955a2e4661f8ef5c9d51eb27d9 100644 (file)
@@ -1,9 +1,9 @@
 _DSD Device Properties Related to GPIO
 --------------------------------------
 
-With the release of ACPI 5.1 and the _DSD configuration objecte names
-can finally be given to GPIOs (and other things as well) returned by
-_CRS.  Previously, we were only able to use an integer index to find
+With the release of ACPI 5.1, the _DSD configuration object finally
+allows names to be given to GPIOs (and other things as well) returned
+by _CRS.  Previously, we were only able to use an integer index to find
 the corresponding GPIO, which is pretty error prone (it depends on
 the _CRS output ordering, for example).
 
index 974624ea68f67d3f16df404bccb57f587ac8a82e..161448da959d26edeb19de7db2561564c4c473dc 100644 (file)
@@ -6,6 +6,7 @@ provided by Arteris.
 Required properties:
 - compatible : Should be "ti,omap3-l3-smx" for OMAP3 family
                Should be "ti,omap4-l3-noc" for OMAP4 family
+               Should be "ti,omap5-l3-noc" for OMAP5 family
               Should be "ti,dra7-l3-noc" for DRA7 family
                Should be "ti,am4372-l3-noc" for AM43 family
 - reg: Contains L3 register address range for each noc domain.
index c40711e8e8f7df7c27f74d1dcf418909a96bedf2..28b28309f53575e91752cba6453e5594ea985de3 100644 (file)
@@ -17,7 +17,8 @@ Required properties:
 - #clock-cells: from common clock binding; shall be set to 1.
 - clocks: from common clock binding; list of parent clock
   handles, shall be xtal reference clock or xtal and clkin for
-  si5351c only.
+  si5351c only. Corresponding clock input names are "xtal" and
+  "clkin" respectively.
 - #address-cells: shall be set to 1.
 - #size-cells: shall be set to 0.
 
@@ -71,6 +72,7 @@ i2c-master-node {
 
                /* connect xtal input to 25MHz reference */
                clocks = <&ref25>;
+               clock-names = "xtal";
 
                /* connect xtal input as source of pll0 and pll1 */
                silabs,pll-source = <0 0>, <1 0>;
index a4873e5e3e36de172c49f59108360e32aca9fefd..e30e184f50c727aa84d2284914581ce9927dba1c 100644 (file)
@@ -38,7 +38,7 @@ dma_apbx: dma-apbx@80024000 {
                      80 81 68 69
                      70 71 72 73
                      74 75 76 77>;
-       interrupt-names = "auart4-rx", "aurat4-tx", "spdif-tx", "empty",
+       interrupt-names = "auart4-rx", "auart4-tx", "spdif-tx", "empty",
                          "saif0", "saif1", "i2c0", "i2c1",
                          "auart0-rx", "auart0-tx", "auart1-rx", "auart1-tx",
                          "auart2-rx", "auart2-tx", "auart3-rx", "auart3-tx";
index 4b641c7bf1c252a3465aa7e028e18042cb7ad61b..09089a6d69ed8d1c9b29115e6abce75a6d1a2fcd 100644 (file)
@@ -32,8 +32,8 @@ Example:
                touchscreen-fuzz-x = <4>;
                touchscreen-fuzz-y = <7>;
                touchscreen-fuzz-pressure = <2>;
-               touchscreen-max-x = <4096>;
-               touchscreen-max-y = <4096>;
+               touchscreen-size-x = <4096>;
+               touchscreen-size-y = <4096>;
                touchscreen-max-pressure = <2048>;
 
                ti,x-plate-ohms = <280>;
diff --git a/Documentation/devicetree/bindings/mtd/jedec,spi-nor.txt b/Documentation/devicetree/bindings/mtd/jedec,spi-nor.txt
new file mode 100644 (file)
index 0000000..2bee681
--- /dev/null
@@ -0,0 +1,32 @@
+* MTD SPI driver for ST M25Pxx (and similar) serial flash chips
+
+Required properties:
+- #address-cells, #size-cells : Must be present if the device has sub-nodes
+  representing partitions.
+- compatible : May include a device-specific string consisting of the
+               manufacturer and name of the chip. Bear in mind the DT binding
+               is not Linux-only, but in case of Linux, see the "m25p_ids"
+               table in drivers/mtd/devices/m25p80.c for the list of supported
+               chips.
+               Must also include "jedec,spi-nor" for any SPI NOR flash that can
+               be identified by the JEDEC READ ID opcode (0x9F).
+- reg : Chip-Select number
+- spi-max-frequency : Maximum frequency of the SPI bus the chip can operate at
+
+Optional properties:
+- m25p,fast-read : Use the "fast read" opcode to read data from the chip instead
+                   of the usual "read" opcode. This opcode is not supported by
+                   all chips and support for it can not be detected at runtime.
+                   Refer to your chips' datasheet to check if this is supported
+                   by your chip.
+
+Example:
+
+       flash: m25p80@0 {
+               #address-cells = <1>;
+               #size-cells = <1>;
+               compatible = "spansion,m25p80", "jedec,spi-nor";
+               reg = <0>;
+               spi-max-frequency = <40000000>;
+               m25p,fast-read;
+       };
diff --git a/Documentation/devicetree/bindings/mtd/m25p80.txt b/Documentation/devicetree/bindings/mtd/m25p80.txt
deleted file mode 100644 (file)
index f20b111..0000000
+++ /dev/null
@@ -1,32 +0,0 @@
-* MTD SPI driver for ST M25Pxx (and similar) serial flash chips
-
-Required properties:
-- #address-cells, #size-cells : Must be present if the device has sub-nodes
-  representing partitions.
-- compatible : May include a device-specific string consisting of the
-               manufacturer and name of the chip. Bear in mind the DT binding
-               is not Linux-only, but in case of Linux, see the "m25p_ids"
-               table in drivers/mtd/devices/m25p80.c for the list of supported
-               chips.
-               Must also include "nor-jedec" for any SPI NOR flash that can be
-               identified by the JEDEC READ ID opcode (0x9F).
-- reg : Chip-Select number
-- spi-max-frequency : Maximum frequency of the SPI bus the chip can operate at
-
-Optional properties:
-- m25p,fast-read : Use the "fast read" opcode to read data from the chip instead
-                   of the usual "read" opcode. This opcode is not supported by
-                   all chips and support for it can not be detected at runtime.
-                   Refer to your chips' datasheet to check if this is supported
-                   by your chip.
-
-Example:
-
-       flash: m25p80@0 {
-               #address-cells = <1>;
-               #size-cells = <1>;
-               compatible = "spansion,m25p80", "nor-jedec";
-               reg = <0>;
-               spi-max-frequency = <40000000>;
-               m25p,fast-read;
-       };
index abd67c13d3442228834e7df36a53a71454132160..4451ee9732239b50d8329339eb57662e639c24b4 100644 (file)
@@ -3,7 +3,8 @@
 Required properties:
 - compatible: Should be "cdns,[<chip>-]{emac}"
   Use "cdns,at91rm9200-emac" Atmel at91rm9200 SoC.
-  or the generic form: "cdns,emac".
+  Use "cdns,zynq-gem" Xilinx Zynq-7xxx SoC.
+  Or the generic form: "cdns,emac".
 - reg: Address and length of the register set for the device
 - interrupts: Should contain macb interrupt
 - phy-mode: see ethernet.txt file in the same directory.
diff --git a/Documentation/devicetree/bindings/rtc/abracon,abx80x.txt b/Documentation/devicetree/bindings/rtc/abracon,abx80x.txt
new file mode 100644 (file)
index 0000000..be78968
--- /dev/null
@@ -0,0 +1,30 @@
+Abracon ABX80X I2C ultra low power RTC/Alarm chip
+
+The Abracon ABX80X family consist of the ab0801, ab0803, ab0804, ab0805, ab1801,
+ab1803, ab1804 and ab1805. The ab0805 is the superset of ab080x and the ab1805
+is the superset of ab180x.
+
+Required properties:
+
+ - "compatible": should one of:
+        "abracon,abx80x"
+        "abracon,ab0801"
+        "abracon,ab0803"
+        "abracon,ab0804"
+        "abracon,ab0805"
+        "abracon,ab1801"
+        "abracon,ab1803"
+        "abracon,ab1804"
+        "abracon,ab1805"
+       Using "abracon,abx80x" will enable chip autodetection.
+ - "reg": I2C bus address of the device
+
+Optional properties:
+
+The abx804 and abx805 have a trickle charger that is able to charge the
+connected battery or supercap. Both the following properties have to be defined
+and valid to enable charging:
+
+ - "abracon,tc-diode": should be "standard" (0.6V) or "schottky" (0.3V)
+ - "abracon,tc-resistor": should be <0>, <3>, <6> or <11>. 0 disables the output
+                          resistor, the other values are in ohm.
index 547a49b56a62e1bbce83da74ff4ed950f19c980d..0d1128ce2ea733d5cea0c369b4dc4969280a2d85 100644 (file)
@@ -20,6 +20,8 @@ Optional properties:
                        pin configurations as described in the datasheet,
                        table 53. Note that the value of this property has
                        to be prefixed with '/bits/ 8'.
+ - avdd-supply:        Power supply for AVDD, providing 3.3V
+ - dvdd-supply:        Power supply for DVDD, providing 3.3V
 
 Examples:
 
@@ -28,6 +30,8 @@ Examples:
                        compatible = "adi,adau1701";
                        reg = <0x34>;
                        reset-gpio = <&gpio 23 0>;
+                       avdd-supply = <&vdd_3v3_reg>;
+                       dvdd-supply = <&vdd_3v3_reg>;
                        adi,pll-mode-gpios = <&gpio 24 0 &gpio 25 0>;
                        adi,pin-config = /bits/ 8 <0x4 0x7 0x5 0x5 0x4 0x4
                                                    0x4 0x4 0x4 0x4 0x4 0x4>;
diff --git a/Documentation/devicetree/bindings/sound/bt-sco.txt b/Documentation/devicetree/bindings/sound/bt-sco.txt
new file mode 100644 (file)
index 0000000..29b8e5d
--- /dev/null
@@ -0,0 +1,13 @@
+Bluetooth-SCO audio CODEC
+
+This device support generic Bluetooth SCO link.
+
+Required properties:
+
+  - compatible : "delta,dfbmcs320"
+
+Example:
+
+codec: bt_sco {
+       compatible = "delta,dfbmcs320";
+};
diff --git a/Documentation/devicetree/bindings/sound/gtm601.txt b/Documentation/devicetree/bindings/sound/gtm601.txt
new file mode 100644 (file)
index 0000000..5efc8c0
--- /dev/null
@@ -0,0 +1,13 @@
+GTM601 UMTS modem audio interface CODEC
+
+This device has no configuration interface. Sample rate is fixed - 8kHz.
+
+Required properties:
+
+  - compatible : "option,gtm601"
+
+Example:
+
+codec: gtm601_codec {
+       compatible = "option,gtm601";
+};
index aa802a274520793a4ae3f46fa3edb8d55be1083c..4e3be6682c98c97c04ea6e8983edaca1beb22fbe 100644 (file)
@@ -18,6 +18,12 @@ Optional properties:
 
 - maxim,dmic-freq: Frequency at which to clock DMIC
 
+- maxim,micbias: Micbias voltage applies to the analog mic, valid voltages value are:
+       0 - 2.2v
+       1 - 2.55v
+       2 - 2.4v
+       3 - 2.8v
+
 Pins on the device (for linking into audio routes):
 
   * MIC1
diff --git a/Documentation/devicetree/bindings/sound/mt8173-max98090.txt b/Documentation/devicetree/bindings/sound/mt8173-max98090.txt
new file mode 100644 (file)
index 0000000..829bd26
--- /dev/null
@@ -0,0 +1,13 @@
+MT8173 with MAX98090 CODEC
+
+Required properties:
+- compatible : "mediatek,mt8173-max98090"
+- mediatek,audio-codec: the phandle of the MAX98090 audio codec
+
+Example:
+
+       sound {
+               compatible = "mediatek,mt8173-max98090";
+               mediatek,audio-codec = <&max98090>;
+       };
+
diff --git a/Documentation/devicetree/bindings/sound/mt8173-rt5650-rt5676.txt b/Documentation/devicetree/bindings/sound/mt8173-rt5650-rt5676.txt
new file mode 100644 (file)
index 0000000..61e98c9
--- /dev/null
@@ -0,0 +1,13 @@
+MT8173 with RT5650 RT5676 CODECS
+
+Required properties:
+- compatible : "mediatek,mt8173-rt5650-rt5676"
+- mediatek,audio-codec: the phandles of rt5650 and rt5676 codecs
+
+Example:
+
+       sound {
+               compatible = "mediatek,mt8173-rt5650-rt5676";
+               mediatek,audio-codec = <&rt5650 &rt5676>;
+       };
+
diff --git a/Documentation/devicetree/bindings/sound/mtk-afe-pcm.txt b/Documentation/devicetree/bindings/sound/mtk-afe-pcm.txt
new file mode 100644 (file)
index 0000000..e302c7f
--- /dev/null
@@ -0,0 +1,45 @@
+Mediatek AFE PCM controller
+
+Required properties:
+- compatible = "mediatek,mt8173-afe-pcm";
+- reg: register location and size
+- interrupts: Should contain AFE interrupt
+- clock-names: should have these clock names:
+               "infra_sys_audio_clk",
+               "top_pdn_audio",
+               "top_pdn_aud_intbus",
+               "bck0",
+               "bck1",
+               "i2s0_m",
+               "i2s1_m",
+               "i2s2_m",
+               "i2s3_m",
+               "i2s3_b";
+
+Example:
+
+       afe: mt8173-afe-pcm@11220000  {
+               compatible = "mediatek,mt8173-afe-pcm";
+               reg = <0 0x11220000 0 0x1000>;
+               interrupts = <GIC_SPI 134 IRQ_TYPE_EDGE_FALLING>;
+               clocks = <&infracfg INFRA_AUDIO>,
+                       <&topckgen TOP_AUDIO_SEL>,
+                       <&topckgen TOP_AUD_INTBUS_SEL>,
+                       <&topckgen TOP_APLL1_DIV0>,
+                       <&topckgen TOP_APLL2_DIV0>,
+                       <&topckgen TOP_I2S0_M_CK_SEL>,
+                       <&topckgen TOP_I2S1_M_CK_SEL>,
+                       <&topckgen TOP_I2S2_M_CK_SEL>,
+                       <&topckgen TOP_I2S3_M_CK_SEL>,
+                       <&topckgen TOP_I2S3_B_CK_SEL>;
+               clock-names = "infra_sys_audio_clk",
+                               "top_pdn_audio",
+                               "top_pdn_aud_intbus",
+                               "bck0",
+                               "bck1",
+                               "i2s0_m",
+                               "i2s1_m",
+                               "i2s2_m",
+                               "i2s3_m",
+                               "i2s3_b";
+       };
diff --git a/Documentation/devicetree/bindings/sound/qcom,apq8016-sbc.txt b/Documentation/devicetree/bindings/sound/qcom,apq8016-sbc.txt
new file mode 100644 (file)
index 0000000..4812936
--- /dev/null
@@ -0,0 +1,60 @@
+* Qualcomm Technologies APQ8016 SBC ASoC machine driver
+
+This node models the Qualcomm Technologies APQ8016 SBC ASoC machine driver
+
+Required properties:
+
+- compatible           : "qcom,apq8016-sbc-sndcard"
+
+- pinctrl-N            : One property must exist for each entry in
+                         pinctrl-names.  See ../pinctrl/pinctrl-bindings.txt
+                         for details of the property values.
+- pinctrl-names                : Must contain a "default" entry.
+- reg                  : Must contain an address for each entry in reg-names.
+- reg-names            : A list which must include the following entries:
+                               * "mic-iomux"
+                               * "spkr-iomux"
+- qcom,model           : Name of the sound card.
+
+Dai-link subnode properties and subnodes:
+
+Required dai-link subnodes:
+
+- cpu                                  : CPU   sub-node
+- codec                                        : CODEC sub-node
+
+Required CPU/CODEC subnodes properties:
+
+-link-name             : Name of the dai link.
+-sound-dai             : phandle and port of CPU/CODEC
+-capture-dai           : phandle and port of CPU/CODEC
+
+Example:
+
+sound: sound {
+       compatible = "qcom,apq8016-sbc-sndcard";
+       reg = <0x07702000 0x4>, <0x07702004 0x4>;
+       reg-names = "mic-iomux", "spkr-iomux";
+       qcom,model = "DB410c";
+
+       /* I2S - Internal codec */
+       internal-dai-link@0 {
+               cpu { /* PRIMARY */
+                       sound-dai = <&lpass MI2S_PRIMARY>;
+               };
+               codec {
+                       sound-dai = <&wcd_codec 0>;
+               };
+       };
+
+       /* External Primary or External Secondary -ADV7533 HDMI */
+       external-dai-link@0 {
+               link-name = "ADV7533";
+               cpu { /* QUAT */
+                       sound-dai = <&lpass MI2S_QUATERNARY>;
+               };
+               codec {
+                       sound-dai = <&adv_bridge 0>;
+               };
+       };
+};
index e00732dac9393e95f0530505c9f38127f58980a3..21c648328be9ad20bff726282187c4dc7df9d89d 100644 (file)
@@ -4,12 +4,21 @@ This node models the Qualcomm Technologies Low-Power Audio SubSystem (LPASS).
 
 Required properties:
 
-- compatible           : "qcom,lpass-cpu"
+- compatible           : "qcom,lpass-cpu" or "qcom,apq8016-lpass-cpu"
 - clocks               : Must contain an entry for each entry in clock-names.
 - clock-names          : A list which must include the following entries:
                                * "ahbix-clk"
                                * "mi2s-osr-clk"
                                * "mi2s-bit-clk"
+                       : required clocks for "qcom,lpass-cpu-apq8016"
+                               * "ahbix-clk"
+                               * "mi2s-bit-clk0"
+                               * "mi2s-bit-clk1"
+                               * "mi2s-bit-clk2"
+                               * "mi2s-bit-clk3"
+                               * "pcnoc-mport-clk"
+                               * "pcnoc-sway-clk"
+
 - interrupts           : Must contain an entry for each entry in
                          interrupt-names.
 - interrupt-names      : A list which must include the following entries:
@@ -22,6 +31,8 @@ Required properties:
 - reg-names            : A list which must include the following entries:
                                * "lpass-lpaif"
 
+
+
 Optional properties:
 
 - qcom,adsp            : Phandle for the audio DSP node
index f316ce1f214a03e396750652df9b911ee6df48ea..b6b3a786855f275b3463d8280db01af8262f6df3 100644 (file)
@@ -5,6 +5,7 @@ Required properties:
                                  "renesas,rcar_sound-gen1" if generation1, and
                                  "renesas,rcar_sound-gen2" if generation2
                                  Examples with soctypes are:
+                                   - "renesas,rcar_sound-r8a7778" (R-Car M1A)
                                    - "renesas,rcar_sound-r8a7790" (R-Car H2)
                                    - "renesas,rcar_sound-r8a7791" (R-Car M2-W)
 - reg                          : Should contain the register physical address.
@@ -47,7 +48,7 @@ DAI subnode properties:
 
 Example:
 
-rcar_sound: rcar_sound@ec500000 {
+rcar_sound: sound@ec500000 {
        #sound-dai-cells = <1>;
        compatible = "renesas,rcar_sound-r8a7791", "renesas,rcar_sound-gen2";
        reg =   <0 0xec500000 0 0x1000>, /* SCU */
diff --git a/Documentation/devicetree/bindings/sound/rt5645.txt b/Documentation/devicetree/bindings/sound/rt5645.txt
new file mode 100644 (file)
index 0000000..7cee1f5
--- /dev/null
@@ -0,0 +1,72 @@
+RT5650/RT5645 audio CODEC
+
+This device supports I2C only.
+
+Required properties:
+
+- compatible : One of "realtek,rt5645" or "realtek,rt5650".
+
+- reg : The I2C address of the device.
+
+- interrupts : The CODEC's interrupt output.
+
+Optional properties:
+
+- hp-detect-gpios:
+  a GPIO spec for the external headphone detect pin. If jd-mode = 0,
+  we will get the JD status by getting the value of hp-detect-gpios.
+
+- realtek,in2-differential
+  Boolean. Indicate MIC2 input are differential, rather than single-ended.
+
+- realtek,dmic1-data-pin
+  0: dmic1 is not used
+  1: using IN2P pin as dmic1 data pin
+  2: using GPIO6 pin as dmic1 data pin
+  3: using GPIO10 pin as dmic1 data pin
+  4: using GPIO12 pin as dmic1 data pin
+
+- realtek,dmic2-data-pin
+  0: dmic2 is not used
+  1: using IN2N pin as dmic2 data pin
+  2: using GPIO5 pin as dmic2 data pin
+  3: using GPIO11 pin as dmic2 data pin
+
+-- realtek,jd-mode : The JD mode of rt5645/rt5650
+   0 : rt5645/rt5650 JD function is not used
+   1 : Mode-0 (VDD=3.3V), two port jack detection
+   2 : Mode-1 (VDD=3.3V), one port jack detection
+   3 : Mode-2 (VDD=1.8V), one port jack detection
+
+Pins on the device (for linking into audio routes) for RT5645/RT5650:
+
+  * DMIC L1
+  * DMIC R1
+  * DMIC L2
+  * DMIC R2
+  * IN1P
+  * IN1N
+  * IN2P
+  * IN2N
+  * Haptic Generator
+  * HPOL
+  * HPOR
+  * LOUTL
+  * LOUTR
+  * PDM1L
+  * PDM1R
+  * SPOL
+  * SPOR
+
+Example:
+
+codec: rt5650@1a {
+       compatible = "realtek,rt5650";
+       reg = <0x1a>;
+       hp-detect-gpios = <&gpio 19 0>;
+       interrupt-parent = <&gpio>;
+       interrupts = <7 IRQ_TYPE_EDGE_FALLING>;
+       realtek,dmic-en = "true";
+       realtek,en-jd-func = "true";
+       realtek,jd-mode = <3>;
+};
\ No newline at end of file
index 740ff771aa8b319ceeb1b282635534859cdec1db..f07078997f87e0185cb3a2518893d97885ded472 100644 (file)
@@ -18,6 +18,7 @@ Required properties:
 Optional properties:
 
 - realtek,pow-ldo2-gpio : The GPIO that controls the CODEC's POW_LDO2 pin.
+- realtek,reset-gpio : The GPIO that controls the CODEC's RESET pin.
 
 - realtek,in1-differential
 - realtek,in2-differential
@@ -70,6 +71,7 @@ rt5677 {
 
        realtek,pow-ldo2-gpio =
                <&gpio TEGRA_GPIO(V, 3) GPIO_ACTIVE_HIGH>;
+       realtek,reset-gpio = <&gpio TEGRA_GPIO(BB, 3) GPIO_ACTIVE_LOW>;
        realtek,in1-differential = "true";
        realtek,gpio-config = /bits/ 8  <0 0 0 0 0 2>;   /* pull up GPIO6 */
        realtek,jd2-gpio = <3>;  /* Enables Jack detection for GPIO6 */
diff --git a/Documentation/devicetree/bindings/sound/tas571x.txt b/Documentation/devicetree/bindings/sound/tas571x.txt
new file mode 100644 (file)
index 0000000..0ac31d8
--- /dev/null
@@ -0,0 +1,41 @@
+Texas Instruments TAS5711/TAS5717/TAS5719 stereo power amplifiers
+
+The codec is controlled through an I2C interface.  It also has two other
+signals that can be wired up to GPIOs: reset (strongly recommended), and
+powerdown (optional).
+
+Required properties:
+
+- compatible: "ti,tas5711", "ti,tas5717", or "ti,tas5719"
+- reg: The I2C address of the device
+- #sound-dai-cells: must be equal to 0
+
+Optional properties:
+
+- reset-gpios: GPIO specifier for the TAS571x's active low reset line
+- pdn-gpios: GPIO specifier for the TAS571x's active low powerdown line
+- clocks: clock phandle for the MCLK input
+- clock-names: should be "mclk"
+- AVDD-supply: regulator phandle for the AVDD supply (all chips)
+- DVDD-supply: regulator phandle for the DVDD supply (all chips)
+- HPVDD-supply: regulator phandle for the HPVDD supply (5717/5719)
+- PVDD_AB-supply: regulator phandle for the PVDD_AB supply (5717/5719)
+- PVDD_CD-supply: regulator phandle for the PVDD_CD supply (5717/5719)
+- PVDD_A-supply: regulator phandle for the PVDD_A supply (5711)
+- PVDD_B-supply: regulator phandle for the PVDD_B supply (5711)
+- PVDD_C-supply: regulator phandle for the PVDD_C supply (5711)
+- PVDD_D-supply: regulator phandle for the PVDD_D supply (5711)
+
+Example:
+
+       tas5717: audio-codec@2a {
+               compatible = "ti,tas5717";
+               reg = <0x2a>;
+               #sound-dai-cells = <0>;
+
+               reset-gpios = <&gpio5 1 GPIO_ACTIVE_LOW>;
+               pdn-gpios = <&gpio5 2 GPIO_ACTIVE_LOW>;
+
+               clocks = <&clk_core CLK_I2S>;
+               clock-names = "mclk";
+       };
index 74bda58c1bcffb01cd1648f605cac031907a5ce3..a133154087194cb90a2056ba6f927d67b6e49ba4 100644 (file)
@@ -10,9 +10,20 @@ Required properties:
   - reg : the I2C address of the device for I2C, the chip select
           number for SPI.
 
+Optional properties:
+
+  - diff-mode: Differential output mode configuration. Default value for field
+    DIFF in register R8 (MODE_CONTROL_2). If absent, the default is 0, shall be:
+    0 = stereo
+    1 = mono left
+    2 = stereo reversed
+    3 = mono right
+
 Example:
 
 codec: wm8741@1a {
        compatible = "wlf,wm8741";
        reg = <0x1a>;
+
+       diff-mode = <3>;
 };
diff --git a/Documentation/devicetree/bindings/sound/zte,zx-i2s.txt b/Documentation/devicetree/bindings/sound/zte,zx-i2s.txt
new file mode 100644 (file)
index 0000000..7e5aa6f
--- /dev/null
@@ -0,0 +1,44 @@
+ZTE ZX296702 I2S controller
+
+Required properties:
+ - compatible : Must be "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: "tx" for the clock 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: i2s0@0b005000 {
+               #sound-dai-cells = <0>;
+               compatible = "zte,zx296702-i2s";
+               reg = <0x0b005000 0x1000>;
+               clocks = <&lsp0clk ZX296702_I2S0_DIV>;
+               clock-names = "tx";
+               interrupts = <GIC_SPI 22 IRQ_TYPE_LEVEL_HIGH>;
+               dmas = <&dma 5>, <&dma 6>;
+               dma-names = "tx", "rx";
+               status = "okay";
+       };
+
+       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
new file mode 100644 (file)
index 0000000..989544e
--- /dev/null
@@ -0,0 +1,28 @@
+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@0b004000 {
+               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";
+               status = "okay";
+       };
index dc2a18f0b3a10a9e1bd5814fc429fe9246b82ec7..ddbe304beb212238e859640905b83886e5164ac7 100644 (file)
@@ -15,10 +15,8 @@ Optional properties:
   - phys: phandle + phy specifier pair
   - phy-names: must be "usb"
   - dmas: Must contain a list of references to DMA specifiers.
-  - dma-names : Must contain a list of DMA names:
-   - tx0 ... tx<n>
-   - rx0 ... rx<n>
-    - This <n> means DnFIFO in USBHS module.
+  - dma-names : named "ch%d", where %d is the channel number ranging from zero
+                to the number of channels (DnFIFOs) minus one.
 
 Example:
        usbhs: usb@e6590000 {
index 80339192c93e2626f81eed30fe97ff147c86d746..b6969e477bf37e1a93fd9bb0e7f1e92247ab3dd1 100644 (file)
@@ -54,6 +54,7 @@ cosmic        Cosmic Circuits
 crystalfontz   Crystalfontz America, Inc.
 dallas Maxim Integrated Products (formerly Dallas Semiconductor)
 davicom        DAVICOM Semiconductor, Inc.
+delta  Delta Electronics, Inc.
 denx   Denx Software Engineering
 digi   Digi International Inc.
 digilent       Diglent, Inc.
index 8eb88e974055f62f2c9226bcd6d98b3e8e5ea908..711f75e189eba003e31a3f762fa16be04d1012d0 100644 (file)
@@ -20,7 +20,7 @@ Supported chips:
     Datasheet: http://focus.ti.com/docs/prod/folders/print/tmp432.html
   * Texas Instruments TMP435
     Prefix: 'tmp435'
-    Addresses scanned: I2C 0x37, 0x48 - 0x4f
+    Addresses scanned: I2C 0x48 - 0x4f
     Datasheet: http://focus.ti.com/docs/prod/folders/print/tmp435.html
 
 Authors:
index 092fc10961fede482be1f7983e72db0e6c8ec3a8..4692241789b1f608ebc2535ddef1a07722a3fb19 100644 (file)
@@ -9,7 +9,9 @@ a fast and comprehensive solution for finding use-after-free and out-of-bounds
 bugs.
 
 KASan uses compile-time instrumentation for checking every memory access,
-therefore you will need a certain version of GCC > 4.9.2
+therefore you will need a gcc version of 4.9.2 or later. KASan could detect out
+of bounds accesses to stack or global variables, but only if gcc 5.0 or later was
+used to built the kernel.
 
 Currently KASan is supported only for x86_64 architecture and requires that the
 kernel be built with the SLUB allocator.
@@ -23,8 +25,8 @@ To enable KASAN configure kernel with:
 
 and choose between CONFIG_KASAN_OUTLINE and CONFIG_KASAN_INLINE. Outline/inline
 is compiler instrumentation types. The former produces smaller binary the
-latter is 1.1 - 2 times faster. Inline instrumentation requires GCC 5.0 or
-latter.
+latter is 1.1 - 2 times faster. Inline instrumentation requires a gcc version
+of 5.0 or later.
 
 Currently KASAN works only with the SLUB memory allocator.
 For better bug detection and nicer report, enable CONFIG_STACKTRACE and put
index f6befa9855c128b193620cd83a0d654a9e5428df..6726139bd2899038e77ae15f9901351773dd324b 100644 (file)
@@ -1481,6 +1481,12 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
                        By default, super page will be supported if Intel IOMMU
                        has the capability. With this option, super page will
                        not be supported.
+               ecs_off [Default Off]
+                       By default, extended context tables will be supported if
+                       the hardware advertises that it has support both for the
+                       extended tables themselves, and also PASID support. With
+                       this option set, extended tables will not be used even
+                       on hardware which claims to support them.
 
        intel_idle.max_cstate=  [KNL,HW,ACPI,X86]
                        0       disables intel_idle and fall back on acpi_idle.
@@ -3787,6 +3793,8 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
                                        READ_CAPACITY_16 command);
                                f = NO_REPORT_OPCODES (don't use report opcodes
                                        command, uas only);
+                               g = MAX_SECTORS_240 (don't transfer more than
+                                       240 sectors at a time, uas only);
                                h = CAPACITY_HEURISTICS (decrease the
                                        reported device capacity by one
                                        sector if the number is odd);
index 09c2382ad0556b196a3b4bb941b9e86597e8ebc5..c72702ec1ded8b0b5d728e6cd0519a5862d2d3c7 100644 (file)
@@ -119,9 +119,9 @@ Most notably, in the x509.genkey file, the req_distinguished_name section
 should be altered from the default:
 
        [ req_distinguished_name ]
-       O = Magrathea
-       CN = Glacier signing key
-       emailAddress = slartibartfast@magrathea.h2g2
+       #O = Unspecified company
+       CN = Build time autogenerated kernel key
+       #emailAddress = unspecified.user@unspecified.company
 
 The generated RSA key size can also be set with:
 
index 639ddf0ece9b5fdd20bcc858c3067d4e20407163..9ed15f86c17c86ffa69fa3527e932b62f4b9ee20 100644 (file)
@@ -18,3 +18,12 @@ platform_labels - INTEGER
 
        Possible values: 0 - 1048575
        Default: 0
+
+conf/<interface>/input - BOOL
+       Control whether packets can be input on this interface.
+
+       If disabled, packets will be discarded without further
+       processing.
+
+       0 - disabled (default)
+       not 0 - enabled
index cbfac0949635c1d109930b051e6c4d96dc4c74d1..59f4db2a0c85c02df4f6cee3176ceb173333cac1 100644 (file)
@@ -282,7 +282,7 @@ following is true:
 
 - The current CPU's queue head counter >= the recorded tail counter
   value in rps_dev_flow[i]
-- The current CPU is unset (equal to RPS_NO_CPU)
+- The current CPU is unset (>= nr_cpu_ids)
 - The current CPU is offline
 
 After this check, the packet is sent to the (possibly updated) current
index d727a38291005f962848ed40a1ab11db4c167899..53a726855e49bfa4c313e46e15df1eec7cb610ae 100644 (file)
@@ -20,7 +20,7 @@
        files/UDP-Lite-HOWTO.txt
 
    o The Wireshark UDP-Lite WiKi (with capture files):
-       http://wiki.wireshark.org/Lightweight_User_Datagram_Protocol
+       https://wiki.wireshark.org/Lightweight_User_Datagram_Protocol
 
    o The Protocol Spec, RFC 3828, http://www.ietf.org/rfc/rfc3828.txt
 
index ba0a2a4a54ba1ffcb484786381b91f5113a62ad6..ded69794a5c09da762db7c4c61cc3d23e619d0fa 100644 (file)
@@ -74,23 +74,22 @@ Causes of transaction aborts
 Syscalls
 ========
 
-Syscalls made from within an active transaction will not be performed and the
-transaction will be doomed by the kernel with the failure code TM_CAUSE_SYSCALL
-| TM_CAUSE_PERSISTENT.
+Performing syscalls from within transaction is not recommended, and can lead
+to unpredictable results.
 
-Syscalls made from within a suspended transaction are performed as normal and
-the transaction is not explicitly doomed by the kernel.  However, what the
-kernel does to perform the syscall may result in the transaction being doomed
-by the hardware.  The syscall is performed in suspended mode so any side
-effects will be persistent, independent of transaction success or failure.  No
-guarantees are provided by the kernel about which syscalls will affect
-transaction success.
+Syscalls do not by design abort transactions, but beware: The kernel code will
+not be running in transactional state.  The effect of syscalls will always
+remain visible, but depending on the call they may abort your transaction as a
+side-effect, read soon-to-be-aborted transactional data that should not remain
+invisible, etc.  If you constantly retry a transaction that constantly aborts
+itself by calling a syscall, you'll have a livelock & make no progress.
 
-Care must be taken when relying on syscalls to abort during active transactions
-if the calls are made via a library.  Libraries may cache values (which may
-give the appearance of success) or perform operations that cause transaction
-failure before entering the kernel (which may produce different failure codes).
-Examples are glibc's getpid() and lazy symbol resolution.
+Simple syscalls (e.g. sigprocmask()) "could" be OK.  Even things like write()
+from, say, printf() should be OK as long as the kernel does not access any
+memory that was accessed transactionally.
+
+Consider any syscalls that happen to work as debug-only -- not recommended for
+production use.  Best to queue them up till after the transaction is over.
 
 
 Signals
@@ -177,7 +176,8 @@ kernel aborted a transaction:
  TM_CAUSE_RESCHED       Thread was rescheduled.
  TM_CAUSE_TLBI          Software TLB invalid.
  TM_CAUSE_FAC_UNAV      FP/VEC/VSX unavailable trap.
- TM_CAUSE_SYSCALL       Syscall from active transaction.
+ TM_CAUSE_SYSCALL       Currently unused; future syscalls that must abort
+                        transactions for consistency will use this.
  TM_CAUSE_SIGNAL        Signal delivered.
  TM_CAUSE_MISC          Currently unused.
  TM_CAUSE_ALIGNMENT     Alignment fault.
index 1e52d67d0abf5c8ccb86b6aa5d1170f509d73132..dbe6623fed1c286bd49277486492b2960428eff6 100644 (file)
@@ -198,6 +198,9 @@ TTY_IO_ERROR                If set, causes all subsequent userspace read/write
 
 TTY_OTHER_CLOSED       Device is a pty and the other side has closed.
 
+TTY_OTHER_DONE         Device is a pty and the other side has closed and
+                       all pending input processing has been completed.
+
 TTY_NO_WRITE_SPLIT     Prevent driver from splitting up writes into
                        smaller chunks.
 
index 43e94ea6d2cad8d0e17715a7ecf4d1e31b9b9e0e..263b907517ac2cd14e3b8472f4bc23f4aa8aae07 100644 (file)
@@ -15,8 +15,7 @@ Contents:
   a) Discovering and configuring TCMU uio devices
   b) Waiting for events on the device(s)
   c) Managing the command ring
-3) Command filtering and pass_level
-4) A final note
+3) A final note
 
 
 TCM Userspace Design
@@ -324,7 +323,7 @@ int handle_device_events(int fd, void *map)
   /* Process events from cmd ring until we catch up with cmd_head */
   while (ent != (void *)mb + mb->cmdr_off + mb->cmd_head) {
 
-    if (tcmu_hdr_get_op(&ent->hdr) == TCMU_OP_CMD) {
+    if (tcmu_hdr_get_op(ent->hdr.len_op) == TCMU_OP_CMD) {
       uint8_t *cdb = (void *)mb + ent->req.cdb_off;
       bool success = true;
 
@@ -339,8 +338,12 @@ int handle_device_events(int fd, void *map)
         ent->rsp.scsi_status = SCSI_CHECK_CONDITION;
       }
     }
+    else if (tcmu_hdr_get_op(ent->hdr.len_op) != TCMU_OP_PAD) {
+      /* Tell the kernel we didn't handle unknown opcodes */
+      ent->hdr.uflags |= TCMU_UFLAG_UNKNOWN_OP;
+    }
     else {
-      /* Do nothing for PAD entries */
+      /* Do nothing for PAD entries except update cmd_tail */
     }
 
     /* update cmd_tail */
@@ -360,28 +363,6 @@ int handle_device_events(int fd, void *map)
 }
 
 
-Command filtering and pass_level
---------------------------------
-
-TCMU supports a "pass_level" option with valid values of 0 or 1.  When
-the value is 0 (the default), nearly all SCSI commands received for
-the device are passed through to the handler. This allows maximum
-flexibility but increases the amount of code required by the handler,
-to support all mandatory SCSI commands. If pass_level is set to 1,
-then only IO-related commands are presented, and the rest are handled
-by LIO's in-kernel command emulation. The commands presented at level
-1 include all versions of:
-
-READ
-WRITE
-WRITE_VERIFY
-XDWRITEREAD
-WRITE_SAME
-COMPARE_AND_WRITE
-SYNCHRONIZE_CACHE
-UNMAP
-
-
 A final note
 ------------
 
index 53838d9c6295792501f2825175ac9c314c1a2fc7..c59bd9bc41efa984cfd5f0e17ac5fd6156acfca6 100644 (file)
@@ -169,6 +169,10 @@ Shadow pages contain the following information:
     Contains the value of cr4.smep && !cr0.wp for which the page is valid
     (pages for which this is true are different from other pages; see the
     treatment of cr0.wp=0 below).
+  role.smap_andnot_wp:
+    Contains the value of cr4.smap && !cr0.wp for which the page is valid
+    (pages for which this is true are different from other pages; see the
+    treatment of cr0.wp=0 below).
   gfn:
     Either the guest page table containing the translations shadowed by this
     page, or the base page frame for linear translations.  See role.direct.
@@ -344,10 +348,16 @@ on fault type:
 
 (user write faults generate a #PF)
 
-In the first case there is an additional complication if CR4.SMEP is
-enabled: since we've turned the page into a kernel page, the kernel may now
-execute it.  We handle this by also setting spte.nx.  If we get a user
-fetch or read fault, we'll change spte.u=1 and spte.nx=gpte.nx back.
+In the first case there are two additional complications:
+- if CR4.SMEP is enabled: since we've turned the page into a kernel page,
+  the kernel may now execute it.  We handle this by also setting spte.nx.
+  If we get a user fetch or read fault, we'll change spte.u=1 and
+  spte.nx=gpte.nx back.
+- if CR4.SMAP is disabled: since the page has been changed to a kernel
+  page, it can not be reused when CR4.SMAP is enabled. We set
+  CR4.SMAP && !CR0.WP into shadow page's role to avoid this case. Note,
+  here we do not care the case that CR4.SMAP is enabled since KVM will
+  directly inject #PF to guest due to failed permission check.
 
 To prevent an spte that was converted into a kernel page with cr0.wp=0
 from being written by the kernel after cr0.wp has changed to 1, we make
index 2e5bbc0d68b26e188e2d7e8154cf80e47fabdda1..8939e1b29f6d3a554f5103acc35c13f3253fa93e 100644 (file)
@@ -51,9 +51,9 @@ trivial patch so apply some common sense.
        or does something very odd once a month document it.
 
        PLEASE remember that submissions must be made under the terms
-       of the OSDL certificate of contribution and should include a
-       Signed-off-by: line.  The current version of this "Developer's
-       Certificate of Origin" (DCO) is listed in the file
+       of the Linux Foundation certificate of contribution and should
+       include a Signed-off-by: line.  The current version of this
+       "Developer's Certificate of Origin" (DCO) is listed in the file
        Documentation/SubmittingPatches.
 
 6.     Make sure you have the right to send any changes you make. If you
@@ -892,11 +892,10 @@ S:        Maintained
 F:     arch/arm/mach-alpine/
 
 ARM/ATMEL AT91RM9200 AND AT91SAM ARM ARCHITECTURES
-M:     Andrew Victor <linux@maxim.org.za>
 M:     Nicolas Ferre <nicolas.ferre@atmel.com>
+M:     Alexandre Belloni <alexandre.belloni@free-electrons.com>
 M:     Jean-Christophe Plagniol-Villard <plagnioj@jcrosoft.com>
 L:     linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
-W:     http://maxim.org.za/at91_26.html
 W:     http://www.linux4sam.org
 S:     Supported
 F:     arch/arm/mach-at91/
@@ -975,7 +974,7 @@ S:  Maintained
 ARM/CORTINA SYSTEMS GEMINI ARM ARCHITECTURE
 M:     Hans Ulli Kroll <ulli.kroll@googlemail.com>
 L:     linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
-T:     git git://git.berlios.de/gemini-board
+T:     git git://github.com/ulli-kroll/linux.git
 S:     Maintained
 F:     arch/arm/mach-gemini/
 
@@ -990,6 +989,12 @@ F: drivers/clocksource/timer-prima2.c
 F:     drivers/clocksource/timer-atlas7.c
 N:     [^a-z]sirf
 
+ARM/CONEXANT DIGICOLOR MACHINE SUPPORT
+M:     Baruch Siach <baruch@tkos.co.il>
+L:     linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
+S:     Maintained
+N:     digicolor
+
 ARM/EBSA110 MACHINE SUPPORT
 M:     Russell King <linux@arm.linux.org.uk>
 L:     linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
@@ -1188,7 +1193,7 @@ ARM/MAGICIAN MACHINE SUPPORT
 M:     Philipp Zabel <philipp.zabel@gmail.com>
 S:     Maintained
 
-ARM/Marvell Armada 370 and Armada XP SOC support
+ARM/Marvell Kirkwood and Armada 370, 375, 38x, XP SOC support
 M:     Jason Cooper <jason@lakedaemon.net>
 M:     Andrew Lunn <andrew@lunn.ch>
 M:     Gregory Clement <gregory.clement@free-electrons.com>
@@ -1197,12 +1202,17 @@ L:      linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
 S:     Maintained
 F:     arch/arm/mach-mvebu/
 F:     drivers/rtc/rtc-armada38x.c
+F:     arch/arm/boot/dts/armada*
+F:     arch/arm/boot/dts/kirkwood*
+
 
 ARM/Marvell Berlin SoC support
 M:     Sebastian Hesselbarth <sebastian.hesselbarth@gmail.com>
 L:     linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
 S:     Maintained
 F:     arch/arm/mach-berlin/
+F:     arch/arm/boot/dts/berlin*
+
 
 ARM/Marvell Dove/MV78xx0/Orion SOC support
 M:     Jason Cooper <jason@lakedaemon.net>
@@ -1215,6 +1225,9 @@ F:        arch/arm/mach-dove/
 F:     arch/arm/mach-mv78xx0/
 F:     arch/arm/mach-orion5x/
 F:     arch/arm/plat-orion/
+F:     arch/arm/boot/dts/dove*
+F:     arch/arm/boot/dts/orion5x*
+
 
 ARM/Orion SoC/Technologic Systems TS-78xx platform support
 M:     Alexander Clouter <alex@digriz.org.uk>
@@ -1366,6 +1379,7 @@ N:        rockchip
 
 ARM/SAMSUNG EXYNOS ARM ARCHITECTURES
 M:     Kukjin Kim <kgene@kernel.org>
+M:     Krzysztof Kozlowski <k.kozlowski@samsung.com>
 L:     linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
 L:     linux-samsung-soc@vger.kernel.org (moderated for non-subscribers)
 S:     Maintained
@@ -1439,9 +1453,10 @@ ARM/SOCFPGA ARCHITECTURE
 M:     Dinh Nguyen <dinguyen@opensource.altera.com>
 S:     Maintained
 F:     arch/arm/mach-socfpga/
+F:     arch/arm/boot/dts/socfpga*
+F:     arch/arm/configs/socfpga_defconfig
 W:     http://www.rocketboards.org
-T:     git://git.rocketboards.org/linux-socfpga.git
-T:     git://git.rocketboards.org/linux-socfpga-next.git
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/dinguyen/linux.git
 
 ARM/SOCFPGA CLOCK FRAMEWORK SUPPORT
 M:     Dinh Nguyen <dinguyen@opensource.altera.com>
@@ -1929,7 +1944,7 @@ S:        Maintained
 F:     drivers/net/wireless/b43legacy/
 
 BACKLIGHT CLASS/SUBSYSTEM
-M:     Jingoo Han <jg1.han@samsung.com>
+M:     Jingoo Han <jingoohan1@gmail.com>
 M:     Lee Jones <lee.jones@linaro.org>
 S:     Maintained
 F:     drivers/video/backlight/
@@ -2116,8 +2131,9 @@ S:        Supported
 F:     drivers/net/ethernet/broadcom/bnx2x/
 
 BROADCOM BCM281XX/BCM11XXX/BCM216XX ARM ARCHITECTURE
-M:     Christian Daudt <bcm@fixthebug.org>
 M:     Florian Fainelli <f.fainelli@gmail.com>
+M:     Ray Jui <rjui@broadcom.com>
+M:     Scott Branden <sbranden@broadcom.com>
 L:     bcm-kernel-feedback-list@broadcom.com
 T:     git git://github.com/broadcom/mach-bcm
 S:     Maintained
@@ -2168,7 +2184,6 @@ S:        Maintained
 F:     drivers/usb/gadget/udc/bcm63xx_udc.*
 
 BROADCOM BCM7XXX ARM ARCHITECTURE
-M:     Marc Carino <marc.ceeeee@gmail.com>
 M:     Brian Norris <computersforpeace@gmail.com>
 M:     Gregory Fong <gregory.0xf0@gmail.com>
 M:     Florian Fainelli <f.fainelli@gmail.com>
@@ -2412,7 +2427,6 @@ L:        linux-security-module@vger.kernel.org
 S:     Supported
 F:     include/linux/capability.h
 F:     include/uapi/linux/capability.h
-F:     security/capability.c
 F:     security/commoncap.c
 F:     kernel/capability.c
 
@@ -3413,6 +3427,13 @@ F:       drivers/gpu/drm/rcar-du/
 F:     drivers/gpu/drm/shmobile/
 F:     include/linux/platform_data/shmob_drm.h
 
+DRM DRIVERS FOR ROCKCHIP
+M:     Mark Yao <mark.yao@rock-chips.com>
+L:     dri-devel@lists.freedesktop.org
+S:     Maintained
+F:     drivers/gpu/drm/rockchip/
+F:     Documentation/devicetree/bindings/video/rockchip*
+
 DSBR100 USB FM RADIO DRIVER
 M:     Alexey Klimov <klimov.linux@gmail.com>
 L:     linux-media@vger.kernel.org
@@ -3803,10 +3824,11 @@ M:      David Woodhouse <dwmw2@infradead.org>
 L:     linux-embedded@vger.kernel.org
 S:     Maintained
 
-EMULEX LPFC FC SCSI DRIVER
-M:     James Smart <james.smart@emulex.com>
+EMULEX/AVAGO LPFC FC/FCOE SCSI DRIVER
+M:     James Smart <james.smart@avagotech.com>
+M:     Dick Kennedy <dick.kennedy@avagotech.com>
 L:     linux-scsi@vger.kernel.org
-W:     http://sourceforge.net/projects/lpfcxxxx
+W:     http://www.avagotech.com
 S:     Supported
 F:     drivers/scsi/lpfc/
 
@@ -3905,7 +3927,7 @@ F:        drivers/extcon/
 F:     Documentation/extcon/
 
 EXYNOS DP DRIVER
-M:     Jingoo Han <jg1.han@samsung.com>
+M:     Jingoo Han <jingoohan1@gmail.com>
 L:     dri-devel@lists.freedesktop.org
 S:     Maintained
 F:     drivers/gpu/drm/exynos/exynos_dp*
@@ -4364,11 +4386,10 @@ F:      fs/gfs2/
 F:     include/uapi/linux/gfs2_ondisk.h
 
 GIGASET ISDN DRIVERS
-M:     Hansjoerg Lipp <hjlipp@web.de>
-M:     Tilman Schmidt <tilman@imap.cc>
+M:     Paul Bolle <pebolle@tiscali.nl>
 L:     gigaset307x-common@lists.sourceforge.net
 W:     http://gigaset307x.sourceforge.net/
-S:     Maintained
+S:     Odd Fixes
 F:     Documentation/isdn/README.gigaset
 F:     drivers/isdn/gigaset/
 F:     include/uapi/linux/gigaset_dev.h
@@ -4515,7 +4536,7 @@ M:        Jean Delvare <jdelvare@suse.de>
 M:     Guenter Roeck <linux@roeck-us.net>
 L:     lm-sensors@lm-sensors.org
 W:     http://www.lm-sensors.org/
-T:     quilt kernel.org/pub/linux/kernel/people/jdelvare/linux-2.6/jdelvare-hwmon/
+T:     quilt http://jdelvare.nerim.net/devel/linux/jdelvare-hwmon/
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/groeck/linux-staging.git
 S:     Maintained
 F:     Documentation/hwmon/
@@ -5035,17 +5056,19 @@ S:      Orphan
 F:     drivers/video/fbdev/imsttfb.c
 
 INFINIBAND SUBSYSTEM
-M:     Roland Dreier <roland@kernel.org>
+M:     Doug Ledford <dledford@redhat.com>
 M:     Sean Hefty <sean.hefty@intel.com>
 M:     Hal Rosenstock <hal.rosenstock@gmail.com>
 L:     linux-rdma@vger.kernel.org
 W:     http://www.openfabrics.org/
 Q:     http://patchwork.kernel.org/project/linux-rdma/list/
-T:     git git://git.kernel.org/pub/scm/linux/kernel/git/roland/infiniband.git
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/dledford/rdma.git
 S:     Supported
 F:     Documentation/infiniband/
 F:     drivers/infiniband/
 F:     include/uapi/linux/if_infiniband.h
+F:     include/uapi/rdma/
+F:     include/rdma/
 
 INOTIFY
 M:     John McCutchan <john@johnmccutchan.com>
@@ -5798,6 +5821,7 @@ F:        drivers/scsi/53c700*
 LED SUBSYSTEM
 M:     Bryan Wu <cooloney@gmail.com>
 M:     Richard Purdie <rpurdie@rpsys.net>
+M:     Jacek Anaszewski <j.anaszewski@samsung.com>
 L:     linux-leds@vger.kernel.org
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/cooloney/linux-leds.git
 S:     Maintained
@@ -6943,6 +6967,17 @@ T:       git git://git.rocketboards.org/linux-socfpga-next.git
 S:     Maintained
 F:     arch/nios2/
 
+NOKIA N900 POWER SUPPLY DRIVERS
+M:     Pali Rohár <pali.rohar@gmail.com>
+S:     Maintained
+F:     include/linux/power/bq2415x_charger.h
+F:     include/linux/power/bq27x00_battery.h
+F:     include/linux/power/isp1704_charger.h
+F:     drivers/power/bq2415x_charger.c
+F:     drivers/power/bq27x00_battery.c
+F:     drivers/power/isp1704_charger.c
+F:     drivers/power/rx51_battery.c
+
 NTB DRIVER
 M:     Jon Mason <jdmason@kudzu.us>
 M:     Dave Jiang <dave.jiang@intel.com>
@@ -7531,7 +7566,7 @@ S:        Maintained
 F:     drivers/pci/host/*rcar*
 
 PCI DRIVER FOR SAMSUNG EXYNOS
-M:     Jingoo Han <jg1.han@samsung.com>
+M:     Jingoo Han <jingoohan1@gmail.com>
 L:     linux-pci@vger.kernel.org
 L:     linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
 L:     linux-samsung-soc@vger.kernel.org (moderated for non-subscribers)
@@ -7539,7 +7574,8 @@ S:        Maintained
 F:     drivers/pci/host/pci-exynos.c
 
 PCI DRIVER FOR SYNOPSIS DESIGNWARE
-M:     Jingoo Han <jg1.han@samsung.com>
+M:     Jingoo Han <jingoohan1@gmail.com>
+M:     Pratyush Anand <pratyush.anand@gmail.com>
 L:     linux-pci@vger.kernel.org
 S:     Maintained
 F:     drivers/pci/host/*designware*
@@ -7553,8 +7589,9 @@ F:        Documentation/devicetree/bindings/pci/host-generic-pci.txt
 F:     drivers/pci/host/pci-host-generic.c
 
 PCIE DRIVER FOR ST SPEAR13XX
+M:     Pratyush Anand <pratyush.anand@gmail.com>
 L:     linux-pci@vger.kernel.org
-S:     Orphan
+S:     Maintained
 F:     drivers/pci/host/*spear*
 
 PCMCIA SUBSYSTEM
@@ -8495,7 +8532,7 @@ S:        Supported
 F:     sound/soc/samsung/
 
 SAMSUNG FRAMEBUFFER DRIVER
-M:     Jingoo Han <jg1.han@samsung.com>
+M:     Jingoo Han <jingoohan1@gmail.com>
 L:     linux-fbdev@vger.kernel.org
 S:     Maintained
 F:     drivers/video/fbdev/s3c-fb.c
@@ -8794,16 +8831,19 @@ F:      drivers/misc/phantom.c
 F:     include/uapi/linux/phantom.h
 
 SERVER ENGINES 10Gbps iSCSI - BladeEngine 2 DRIVER
-M:     Jayamohan Kallickal <jayamohan.kallickal@emulex.com>
+M:     Jayamohan Kallickal <jayamohan.kallickal@avagotech.com>
+M:     Minh Tran <minh.tran@avagotech.com>
+M:     John Soni Jose <sony.john-n@avagotech.com>
 L:     linux-scsi@vger.kernel.org
-W:     http://www.emulex.com
+W:     http://www.avagotech.com
 S:     Supported
 F:     drivers/scsi/be2iscsi/
 
-SERVER ENGINES 10Gbps NIC - BladeEngine 2 DRIVER
-M:     Sathya Perla <sathya.perla@emulex.com>
-M:     Subbu Seetharaman <subbu.seetharaman@emulex.com>
-M:     Ajit Khaparde <ajit.khaparde@emulex.com>
+Emulex 10Gbps NIC BE2, BE3-R, Lancer, Skyhawk-R DRIVER
+M:     Sathya Perla <sathya.perla@avagotech.com>
+M:     Ajit Khaparde <ajit.khaparde@avagotech.com>
+M:     Padmanabh Ratnakar <padmanabh.ratnakar@avagotech.com>
+M:     Sriharsha Basavapatna <sriharsha.basavapatna@avagotech.com>
 L:     netdev@vger.kernel.org
 W:     http://www.emulex.com
 S:     Supported
@@ -9884,6 +9924,12 @@ L:       netdev@vger.kernel.org
 S:     Maintained
 F:     drivers/net/ethernet/ti/netcp*
 
+TI TAS571X FAMILY ASoC CODEC DRIVER
+M:     Kevin Cernekee <cernekee@chromium.org>
+L:     alsa-devel@alsa-project.org (moderated for non-subscribers)
+S:     Odd Fixes
+F:     sound/soc/codecs/tas571x*
+
 TI TWL4030 SERIES SOC CODEC DRIVER
 M:     Peter Ujfalusi <peter.ujfalusi@ti.com>
 L:     alsa-devel@alsa-project.org (moderated for non-subscribers)
@@ -10523,7 +10569,6 @@ F:      include/linux/virtio_console.h
 F:     include/uapi/linux/virtio_console.h
 
 VIRTIO CORE, NET AND BLOCK DRIVERS
-M:     Rusty Russell <rusty@rustcorp.com.au>
 M:     "Michael S. Tsirkin" <mst@redhat.com>
 L:     virtualization@lists.linux-foundation.org
 S:     Maintained
@@ -10550,8 +10595,7 @@ F:      drivers/virtio/virtio_input.c
 F:     include/uapi/linux/virtio_input.h
 
 VIA RHINE NETWORK DRIVER
-M:     Roger Luethi <rl@hellgate.ch>
-S:     Maintained
+S:     Orphan
 F:     drivers/net/ethernet/via/via-rhine.c
 
 VIA SD/MMC CARD CONTROLLER DRIVER
@@ -11031,6 +11075,7 @@ F:      drivers/media/pci/zoran/
 ZRAM COMPRESSED RAM BLOCK DEVICE DRVIER
 M:     Minchan Kim <minchan@kernel.org>
 M:     Nitin Gupta <ngupta@vflare.org>
+R:     Sergey Senozhatsky <sergey.senozhatsky.work@gmail.com>
 L:     linux-kernel@vger.kernel.org
 S:     Maintained
 F:     drivers/block/zram/
index 7ff1239f9cd2cbdd146092f342df412cad37d285..3ba504496cb2deb13b50d39d01ec11641502e342 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -1,7 +1,7 @@
 VERSION = 4
 PATCHLEVEL = 1
 SUBLEVEL = 0
-EXTRAVERSION = -rc1
+EXTRAVERSION = -rc8
 NAME = Hurr durr I'ma sheep
 
 # *DOCUMENTATION*
index cd143887380a26da88e8372828dc586ce3ff7b31..8399bd0e68e8e5cb7aba078cd40864d89b971eed 100644 (file)
@@ -14,6 +14,9 @@ targets               := vmlinux.gz vmlinux \
                   tools/bootpzh bootloader bootpheader bootpzheader 
 OBJSTRIP       := $(obj)/tools/objstrip
 
+HOSTCFLAGS     := -Wall -I$(objtree)/usr/include
+BOOTCFLAGS     += -I$(obj) -I$(srctree)/$(obj)
+
 # SRM bootable image.  Copy to offset 512 of a partition.
 $(obj)/bootimage: $(addprefix $(obj)/tools/,mkbb lxboot bootlx) $(obj)/vmlinux.nh
        ( cat $(obj)/tools/lxboot $(obj)/tools/bootlx $(obj)/vmlinux.nh ) > $@ 
@@ -96,13 +99,14 @@ $(obj)/tools/bootph: $(obj)/bootpheader $(OBJSTRIP) FORCE
 $(obj)/tools/bootpzh: $(obj)/bootpzheader $(OBJSTRIP) FORCE
        $(call if_changed,objstrip)
 
-LDFLAGS_bootloader   := -static -uvsprintf -T  #-N -relax
-LDFLAGS_bootpheader  := -static -uvsprintf -T  #-N -relax
-LDFLAGS_bootpzheader := -static -uvsprintf -T  #-N -relax
+LDFLAGS_bootloader   := -static -T # -N -relax
+LDFLAGS_bootloader   := -static -T # -N -relax
+LDFLAGS_bootpheader  := -static -T # -N -relax
+LDFLAGS_bootpzheader := -static -T # -N -relax
 
-OBJ_bootlx   := $(obj)/head.o $(obj)/main.o
-OBJ_bootph   := $(obj)/head.o $(obj)/bootp.o
-OBJ_bootpzh  := $(obj)/head.o $(obj)/bootpz.o $(obj)/misc.o
+OBJ_bootlx   := $(obj)/head.o $(obj)/stdio.o $(obj)/main.o
+OBJ_bootph   := $(obj)/head.o $(obj)/stdio.o $(obj)/bootp.o
+OBJ_bootpzh  := $(obj)/head.o $(obj)/stdio.o $(obj)/bootpz.o $(obj)/misc.o
 
 $(obj)/bootloader: $(obj)/bootloader.lds $(OBJ_bootlx) $(LIBS_Y) FORCE
        $(call if_changed,ld)
index 3baf2d1e908df5760f1304bab309ae70877eee03..dd6eb4a33582e63def4b015c0a1ad496889feacd 100644 (file)
@@ -19,7 +19,6 @@
 
 #include "ksize.h"
 
-extern int vsprintf(char *, const char *, va_list);
 extern unsigned long switch_to_osf_pal(unsigned long nr,
        struct pcb_struct * pcb_va, struct pcb_struct * pcb_pa,
        unsigned long *vptb);
diff --git a/arch/alpha/boot/stdio.c b/arch/alpha/boot/stdio.c
new file mode 100644 (file)
index 0000000..f844dae
--- /dev/null
@@ -0,0 +1,306 @@
+/*
+ * Copyright (C) Paul Mackerras 1997.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+#include <stdarg.h>
+#include <stddef.h>
+
+size_t strnlen(const char * s, size_t count)
+{
+       const char *sc;
+
+       for (sc = s; count-- && *sc != '\0'; ++sc)
+               /* nothing */;
+       return sc - s;
+}
+
+# define do_div(n, base) ({                                            \
+       unsigned int __base = (base);                                   \
+       unsigned int __rem;                                             \
+       __rem = ((unsigned long long)(n)) % __base;                     \
+       (n) = ((unsigned long long)(n)) / __base;                       \
+       __rem;                                                          \
+})
+
+
+static int skip_atoi(const char **s)
+{
+       int i, c;
+
+       for (i = 0; '0' <= (c = **s) && c <= '9'; ++*s)
+               i = i*10 + c - '0';
+       return i;
+}
+
+#define ZEROPAD        1               /* pad with zero */
+#define SIGN   2               /* unsigned/signed long */
+#define PLUS   4               /* show plus */
+#define SPACE  8               /* space if plus */
+#define LEFT   16              /* left justified */
+#define SPECIAL        32              /* 0x */
+#define LARGE  64              /* use 'ABCDEF' instead of 'abcdef' */
+
+static char * number(char * str, unsigned long long num, int base, int size, int precision, int type)
+{
+       char c,sign,tmp[66];
+       const char *digits="0123456789abcdefghijklmnopqrstuvwxyz";
+       int i;
+
+       if (type & LARGE)
+               digits = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
+       if (type & LEFT)
+               type &= ~ZEROPAD;
+       if (base < 2 || base > 36)
+               return 0;
+       c = (type & ZEROPAD) ? '0' : ' ';
+       sign = 0;
+       if (type & SIGN) {
+               if ((signed long long)num < 0) {
+                       sign = '-';
+                       num = - (signed long long)num;
+                       size--;
+               } else if (type & PLUS) {
+                       sign = '+';
+                       size--;
+               } else if (type & SPACE) {
+                       sign = ' ';
+                       size--;
+               }
+       }
+       if (type & SPECIAL) {
+               if (base == 16)
+                       size -= 2;
+               else if (base == 8)
+                       size--;
+       }
+       i = 0;
+       if (num == 0)
+               tmp[i++]='0';
+       else while (num != 0) {
+               tmp[i++] = digits[do_div(num, base)];
+       }
+       if (i > precision)
+               precision = i;
+       size -= precision;
+       if (!(type&(ZEROPAD+LEFT)))
+               while(size-->0)
+                       *str++ = ' ';
+       if (sign)
+               *str++ = sign;
+       if (type & SPECIAL) {
+               if (base==8)
+                       *str++ = '0';
+               else if (base==16) {
+                       *str++ = '0';
+                       *str++ = digits[33];
+               }
+       }
+       if (!(type & LEFT))
+               while (size-- > 0)
+                       *str++ = c;
+       while (i < precision--)
+               *str++ = '0';
+       while (i-- > 0)
+               *str++ = tmp[i];
+       while (size-- > 0)
+               *str++ = ' ';
+       return str;
+}
+
+int vsprintf(char *buf, const char *fmt, va_list args)
+{
+       int len;
+       unsigned long long num;
+       int i, base;
+       char * str;
+       const char *s;
+
+       int flags;              /* flags to number() */
+
+       int field_width;        /* width of output field */
+       int precision;          /* min. # of digits for integers; max
+                                  number of chars for from string */
+       int qualifier;          /* 'h', 'l', or 'L' for integer fields */
+                               /* 'z' support added 23/7/1999 S.H.    */
+                               /* 'z' changed to 'Z' --davidm 1/25/99 */
+
+
+       for (str=buf ; *fmt ; ++fmt) {
+               if (*fmt != '%') {
+                       *str++ = *fmt;
+                       continue;
+               }
+
+               /* process flags */
+               flags = 0;
+               repeat:
+                       ++fmt;          /* this also skips first '%' */
+                       switch (*fmt) {
+                               case '-': flags |= LEFT; goto repeat;
+                               case '+': flags |= PLUS; goto repeat;
+                               case ' ': flags |= SPACE; goto repeat;
+                               case '#': flags |= SPECIAL; goto repeat;
+                               case '0': flags |= ZEROPAD; goto repeat;
+                               }
+
+               /* get field width */
+               field_width = -1;
+               if ('0' <= *fmt && *fmt <= '9')
+                       field_width = skip_atoi(&fmt);
+               else if (*fmt == '*') {
+                       ++fmt;
+                       /* it's the next argument */
+                       field_width = va_arg(args, int);
+                       if (field_width < 0) {
+                               field_width = -field_width;
+                               flags |= LEFT;
+                       }
+               }
+
+               /* get the precision */
+               precision = -1;
+               if (*fmt == '.') {
+                       ++fmt;
+                       if ('0' <= *fmt && *fmt <= '9')
+                               precision = skip_atoi(&fmt);
+                       else if (*fmt == '*') {
+                               ++fmt;
+                               /* it's the next argument */
+                               precision = va_arg(args, int);
+                       }
+                       if (precision < 0)
+                               precision = 0;
+               }
+
+               /* get the conversion qualifier */
+               qualifier = -1;
+               if (*fmt == 'l' && *(fmt + 1) == 'l') {
+                       qualifier = 'q';
+                       fmt += 2;
+               } else if (*fmt == 'h' || *fmt == 'l' || *fmt == 'L'
+                       || *fmt == 'Z') {
+                       qualifier = *fmt;
+                       ++fmt;
+               }
+
+               /* default base */
+               base = 10;
+
+               switch (*fmt) {
+               case 'c':
+                       if (!(flags & LEFT))
+                               while (--field_width > 0)
+                                       *str++ = ' ';
+                       *str++ = (unsigned char) va_arg(args, int);
+                       while (--field_width > 0)
+                               *str++ = ' ';
+                       continue;
+
+               case 's':
+                       s = va_arg(args, char *);
+                       if (!s)
+                               s = "<NULL>";
+
+                       len = strnlen(s, precision);
+
+                       if (!(flags & LEFT))
+                               while (len < field_width--)
+                                       *str++ = ' ';
+                       for (i = 0; i < len; ++i)
+                               *str++ = *s++;
+                       while (len < field_width--)
+                               *str++ = ' ';
+                       continue;
+
+               case 'p':
+                       if (field_width == -1) {
+                               field_width = 2*sizeof(void *);
+                               flags |= ZEROPAD;
+                       }
+                       str = number(str,
+                               (unsigned long) va_arg(args, void *), 16,
+                               field_width, precision, flags);
+                       continue;
+
+
+               case 'n':
+                       if (qualifier == 'l') {
+                               long * ip = va_arg(args, long *);
+                               *ip = (str - buf);
+                       } else if (qualifier == 'Z') {
+                               size_t * ip = va_arg(args, size_t *);
+                               *ip = (str - buf);
+                       } else {
+                               int * ip = va_arg(args, int *);
+                               *ip = (str - buf);
+                       }
+                       continue;
+
+               case '%':
+                       *str++ = '%';
+                       continue;
+
+               /* integer number formats - set up the flags and "break" */
+               case 'o':
+                       base = 8;
+                       break;
+
+               case 'X':
+                       flags |= LARGE;
+               case 'x':
+                       base = 16;
+                       break;
+
+               case 'd':
+               case 'i':
+                       flags |= SIGN;
+               case 'u':
+                       break;
+
+               default:
+                       *str++ = '%';
+                       if (*fmt)
+                               *str++ = *fmt;
+                       else
+                               --fmt;
+                       continue;
+               }
+               if (qualifier == 'l') {
+                       num = va_arg(args, unsigned long);
+                       if (flags & SIGN)
+                               num = (signed long) num;
+               } else if (qualifier == 'q') {
+                       num = va_arg(args, unsigned long long);
+                       if (flags & SIGN)
+                               num = (signed long long) num;
+               } else if (qualifier == 'Z') {
+                       num = va_arg(args, size_t);
+               } else if (qualifier == 'h') {
+                       num = (unsigned short) va_arg(args, int);
+                       if (flags & SIGN)
+                               num = (signed short) num;
+               } else {
+                       num = va_arg(args, unsigned int);
+                       if (flags & SIGN)
+                               num = (signed int) num;
+               }
+               str = number(str, num, base, field_width, precision, flags);
+       }
+       *str = '\0';
+       return str-buf;
+}
+
+int sprintf(char * buf, const char *fmt, ...)
+{
+       va_list args;
+       int i;
+
+       va_start(args, fmt);
+       i=vsprintf(buf,fmt,args);
+       va_end(args);
+       return i;
+}
index 367d53d031fc04d51af471273a0256a5a08432c7..dee82695f48bad69b0d9cf81457196e321d2ff55 100644 (file)
@@ -27,6 +27,9 @@
 #include <linux/param.h>
 #ifdef __ELF__
 # include <linux/elf.h>
+# define elfhdr elf64_hdr
+# define elf_phdr elf64_phdr
+# define elf_check_arch(x) ((x)->e_machine == EM_ALPHA)
 #endif
 
 /* bootfile size must be multiple of BLOCK_SIZE: */
index f61e1a56c3787bcbd4a2ab093d1c58c7715fa6c4..4cb4b6d3452c0b3439c3aa3c0f928f74de09fb3a 100644 (file)
@@ -2,6 +2,5 @@
 #define _ALPHA_TYPES_H
 
 #include <asm-generic/int-ll64.h>
-#include <uapi/asm/types.h>
 
 #endif /* _ALPHA_TYPES_H */
index c509d306db4561ea65a40703b42e7f9bd078d352..a56e608db2f9e4aad716b96669de02c7571dc1df 100644 (file)
@@ -3,7 +3,7 @@
 
 #include <uapi/asm/unistd.h>
 
-#define NR_SYSCALLS                    511
+#define NR_SYSCALLS                    514
 
 #define __ARCH_WANT_OLD_READDIR
 #define __ARCH_WANT_STAT64
index d214a0358100b6ad82a63fce68bc6016eb9ddaa4..aa33bf5aacb6c1666203e38700939750c90cb5c5 100644 (file)
 #define __NR_sched_setattr             508
 #define __NR_sched_getattr             509
 #define __NR_renameat2                 510
+#define __NR_getrandom                 511
+#define __NR_memfd_create              512
+#define __NR_execveat                  513
 
 #endif /* _UAPI_ALPHA_UNISTD_H */
index 253cf1a87481e815ad9a724dde1fef51b5616d09..51267ac5729b9c7276a0e838357bfb8ffd29e7db 100644 (file)
@@ -6,7 +6,6 @@
  *     Error handling code supporting Alpha systems
  */
 
-#include <linux/init.h>
 #include <linux/sched.h>
 
 #include <asm/io.h>
index 7b2be251c30fb92981d4aef8cf4f8951bed24728..51f2c8654253f2bd6667ccff24c0db09a7f80ccc 100644 (file)
@@ -19,7 +19,6 @@
 #include <linux/ptrace.h>
 #include <linux/interrupt.h>
 #include <linux/random.h>
-#include <linux/init.h>
 #include <linux/irq.h>
 #include <linux/proc_fs.h>
 #include <linux/seq_file.h>
index e51f578636a5718d4f0e438b90b4b78a12b6b7da..36dc91ace83ae97069df82f5e3923a24275c6a9b 100644 (file)
@@ -1019,14 +1019,13 @@ SYSCALL_DEFINE2(osf_settimeofday, struct timeval32 __user *, tv,
        if (tv) {
                if (get_tv32((struct timeval *)&kts, tv))
                        return -EFAULT;
+               kts.tv_nsec *= 1000;
        }
        if (tz) {
                if (copy_from_user(&ktz, tz, sizeof(*tz)))
                        return -EFAULT;
        }
 
-       kts.tv_nsec *= 1000;
-
        return do_sys_settimeofday(tv ? &kts : NULL, tz ? &ktz : NULL);
 }
 
index 1941a07b5811f925aed82e853aab4efb081f74ca..84d13263ce46f193ef0b223466cea2f522ca109d 100644 (file)
@@ -236,12 +236,11 @@ release_thread(struct task_struct *dead_task)
 }
 
 /*
- * Copy an alpha thread..
+ * Copy architecture-specific thread state
  */
-
 int
 copy_thread(unsigned long clone_flags, unsigned long usp,
-           unsigned long arg,
+           unsigned long kthread_arg,
            struct task_struct *p)
 {
        extern void ret_from_fork(void);
@@ -262,7 +261,7 @@ copy_thread(unsigned long clone_flags, unsigned long usp,
                        sizeof(struct switch_stack) + sizeof(struct pt_regs));
                childstack->r26 = (unsigned long) ret_from_kernel_thread;
                childstack->r9 = usp;   /* function */
-               childstack->r10 = arg;
+               childstack->r10 = kthread_arg;
                childregs->hae = alpha_mv.hae_cache,
                childti->pcb.usp = 0;
                return 0;
index 99ac36d5de4efd10832804e82509e062606720e2..2f24447fef92071b0ba9b94d09f8ed1fdc25d2d1 100644 (file)
@@ -63,7 +63,6 @@ static struct {
 enum ipi_message_type {
        IPI_RESCHEDULE,
        IPI_CALL_FUNC,
-       IPI_CALL_FUNC_SINGLE,
        IPI_CPU_STOP,
 };
 
@@ -506,7 +505,6 @@ setup_profiling_timer(unsigned int multiplier)
        return -EINVAL;
 }
 
-\f
 static void
 send_ipi_message(const struct cpumask *to_whom, enum ipi_message_type operation)
 {
@@ -552,10 +550,6 @@ handle_ipi(struct pt_regs *regs)
                        generic_smp_call_function_interrupt();
                        break;
 
-               case IPI_CALL_FUNC_SINGLE:
-                       generic_smp_call_function_single_interrupt();
-                       break;
-
                case IPI_CPU_STOP:
                        halt();
 
@@ -606,7 +600,7 @@ void arch_send_call_function_ipi_mask(const struct cpumask *mask)
 
 void arch_send_call_function_single_ipi(int cpu)
 {
-       send_ipi_message(cpumask_of(cpu), IPI_CALL_FUNC_SINGLE);
+       send_ipi_message(cpumask_of(cpu), IPI_CALL_FUNC);
 }
 
 static void
index 6f01d9ad7b814700d8bd56094b13d3af3474cc11..72b59511e59aa350cc58d568cf896edba4f53602 100644 (file)
@@ -237,8 +237,7 @@ srmcons_init(void)
 
        return -ENODEV;
 }
-
-module_init(srmcons_init);
+device_initcall(srmcons_init);
 
 \f
 /*
index f21d61fab6787331d21571958185b637fc601bb7..24e41bd7d3c99060a7411c1c5774941249c89d72 100644 (file)
@@ -331,7 +331,7 @@ marvel_map_irq(const struct pci_dev *cdev, u8 slot, u8 pin)
        pci_read_config_byte(dev, PCI_INTERRUPT_LINE, &intline);
        irq = intline;
 
-       msi_loc = pci_find_capability(dev, PCI_CAP_ID_MSI);
+       msi_loc = dev->msi_cap;
        msg_ctl = 0;
        if (msi_loc) 
                pci_read_config_word(dev, msi_loc + PCI_MSI_FLAGS, &msg_ctl);
index 24789713f1eafb4757ec1084c32225ce88bf4ad4..9b62e3fd4f038a925657beb15de3de89f8548473 100644 (file)
@@ -529,6 +529,9 @@ sys_call_table:
        .quad sys_sched_setattr
        .quad sys_sched_getattr
        .quad sys_renameat2                     /* 510 */
+       .quad sys_getrandom
+       .quad sys_memfd_create
+       .quad sys_execveat
 
        .size sys_call_table, . - sys_call_table
        .type sys_call_table, @object
index 9c4c189eb22f5a9db2d2ae678756a5241b3e1ee5..74aceead06e98a391a1f0fc49f5486ef2562844c 100644 (file)
@@ -14,7 +14,6 @@
 #include <linux/tty.h>
 #include <linux/delay.h>
 #include <linux/module.h>
-#include <linux/init.h>
 #include <linux/kallsyms.h>
 #include <linux/ratelimit.h>
 
index 18aa9b4f94f1822be3e01ea0906fd2cf234c1205..086a0d5445c528b631cec10fd48c5643a4101f86 100644 (file)
@@ -8,7 +8,6 @@
  */
 
 #include <linux/oprofile.h>
-#include <linux/init.h>
 #include <linux/smp.h>
 #include <asm/ptrace.h>
 
index c32f8a0ad92543a0d6e6767e698f51da0972c17e..c300f5ef3482b82330d41c0b4d318362d76d4092 100644 (file)
@@ -8,7 +8,6 @@
  */
 
 #include <linux/oprofile.h>
-#include <linux/init.h>
 #include <linux/smp.h>
 #include <asm/ptrace.h>
 
index 1c84cc257fc7ec7a6c3df970722b381f0ed17ff3..02edf59716144e0939eb2933cfb303fa457ecbd7 100644 (file)
@@ -8,7 +8,6 @@
  */
 
 #include <linux/oprofile.h>
-#include <linux/init.h>
 #include <linux/smp.h>
 #include <asm/ptrace.h>
 
index 34a57a12655377727930f8abba88082f3afde149..adb1744d20f3845efb48a314e56784a5c5470a0a 100644 (file)
@@ -9,7 +9,6 @@
  */
 
 #include <linux/oprofile.h>
-#include <linux/init.h>
 #include <linux/smp.h>
 #include <asm/ptrace.h>
 
index a7fc0da25650ef8920e5cfc9f25d417a36081617..ff6a4b5ce92781442aa10f37537d0d6afb1d15f3 100644 (file)
@@ -2,19 +2,6 @@ menu "Kernel hacking"
 
 source "lib/Kconfig.debug"
 
-config EARLY_PRINTK
-       bool "Early printk" if EMBEDDED
-       default y
-       help
-         Write kernel log output directly into the VGA buffer or to a serial
-         port.
-
-         This is useful for kernel debugging when your machine crashes very
-         early before the console code is initialized. For normal operation
-         it is not recommended because it looks ugly and doesn't cooperate
-         with klogd/syslogd or the X server. You should normally N here,
-         unless you want to debug such a crash.
-
 config 16KSTACKS
        bool "Use 16Kb for kernel stacks instead of 8Kb"
        help
index 067551b6920af99fe733f1f13d4aee8b1903a77b..9917a45fc430d042a4f59006abf84ceedad1bca7 100644 (file)
@@ -99,7 +99,7 @@ static inline void atomic_##op(int i, atomic_t *v)                    \
        atomic_ops_unlock(flags);                                       \
 }
 
-#define ATOMIC_OP_RETURN(op, c_op)                                     \
+#define ATOMIC_OP_RETURN(op, c_op, asm_op)                             \
 static inline int atomic_##op##_return(int i, atomic_t *v)             \
 {                                                                      \
        unsigned long flags;                                            \
index 8c3a3e02ba92c8adbc368dba9a3cd283f32c3e72..12b2100db0731a2a9ce99ce1398ae4599eaca87a 100644 (file)
@@ -266,7 +266,7 @@ static inline void __cache_line_loop(unsigned long paddr, unsigned long vaddr,
  * Machine specific helpers for Entire D-Cache or Per Line ops
  */
 
-static unsigned int __before_dc_op(const int op)
+static inline unsigned int __before_dc_op(const int op)
 {
        unsigned int reg = reg;
 
@@ -284,7 +284,7 @@ static unsigned int __before_dc_op(const int op)
        return reg;
 }
 
-static void __after_dc_op(const int op, unsigned int reg)
+static inline void __after_dc_op(const int op, unsigned int reg)
 {
        if (op & OP_FLUSH)      /* flush / flush-n-inv both wait */
                while (read_aux_reg(ARC_REG_DC_CTRL) & DC_CTRL_FLUSH_STATUS);
index 86217db2937ab331666b710c1bd639c68caad516..992736b5229ba7bd06497feb35ecff5fc36ab232 100644 (file)
@@ -223,7 +223,7 @@ dtb-$(CONFIG_SOC_IMX25) += \
        imx25-eukrea-mbimxsd25-baseboard-dvi-vga.dtb \
        imx25-karo-tx25.dtb \
        imx25-pdk.dtb
-dtb-$(CONFIG_SOC_IMX31) += \
+dtb-$(CONFIG_SOC_IMX27) += \
        imx27-apf27.dtb \
        imx27-apf27dev.dtb \
        imx27-eukrea-mbimxsd27-baseboard.dtb \
index c3255e0c90aa829fc792f02d1265d413f3c6e624..dbb3f4d2bf84ebf4565555949053c94619ea161d 100644 (file)
 /include/ "tps65217.dtsi"
 
 &tps {
+       /*
+        * Configure pmic to enter OFF-state instead of SLEEP-state ("RTC-only
+        * mode") at poweroff.  Most BeagleBone versions do not support RTC-only
+        * mode and risk hardware damage if this mode is entered.
+        *
+        * For details, see linux-omap mailing list May 2015 thread
+        *      [PATCH] ARM: dts: am335x-bone* enable pmic-shutdown-controller
+        * In particular, messages:
+        *      http://www.spinics.net/lists/linux-omap/msg118585.html
+        *      http://www.spinics.net/lists/linux-omap/msg118615.html
+        *
+        * You can override this later with
+        *      &tps {  /delete-property/ ti,pmic-shutdown-controller;  }
+        * if you want to use RTC-only mode and made sure you are not affected
+        * by the hardware problems. (Tip: double-check by performing a current
+        * measurement after shutdown: it should be less than 1 mA.)
+        */
+       ti,pmic-shutdown-controller;
+
        regulators {
                dcdc1_reg: regulator@0 {
                        regulator-name = "vdds_dpr";
index 5c42d259fa68fbf29c98439306badd1d44987ee0..901739fcb85a37abba32822463caea432637d274 100644 (file)
@@ -80,7 +80,3 @@
                status = "okay";
        };
 };
-
-&rtc {
-       system-power-controller;
-};
index 87fc7a35e80261cad03261fd9cf8b047606fc286..156d05efcb70bf5af737cf67892691d41b84fb2b 100644 (file)
        wlcore: wlcore@2 {
                compatible = "ti,wl1271";
                reg = <2>;
-               interrupt-parent = <&gpio1>;
+               interrupt-parent = <&gpio0>;
                interrupts = <31 IRQ_TYPE_LEVEL_HIGH>; /* gpio 31 */
                ref-clock-frequency = <38400000>;
        };
index 518b8fde88b0c87005fe68e413cfee769befac07..18cc826e9db534714a1b4d8a3cfc497e43ffcc85 100644 (file)
@@ -12,7 +12,7 @@
                #clock-cells = <0>;
                compatible = "ti,am35xx-gate-clock";
                clocks = <&ipss_ick>;
-               reg = <0x059c>;
+               reg = <0x032c>;
                ti,bit-shift = <1>;
        };
 
@@ -20,7 +20,7 @@
                #clock-cells = <0>;
                compatible = "ti,gate-clock";
                clocks = <&rmii_ck>;
-               reg = <0x059c>;
+               reg = <0x032c>;
                ti,bit-shift = <9>;
        };
 
@@ -28,7 +28,7 @@
                #clock-cells = <0>;
                compatible = "ti,am35xx-gate-clock";
                clocks = <&ipss_ick>;
-               reg = <0x059c>;
+               reg = <0x032c>;
                ti,bit-shift = <2>;
        };
 
@@ -36,7 +36,7 @@
                #clock-cells = <0>;
                compatible = "ti,gate-clock";
                clocks = <&pclk_ck>;
-               reg = <0x059c>;
+               reg = <0x032c>;
                ti,bit-shift = <10>;
        };
 
@@ -44,7 +44,7 @@
                #clock-cells = <0>;
                compatible = "ti,am35xx-gate-clock";
                clocks = <&ipss_ick>;
-               reg = <0x059c>;
+               reg = <0x032c>;
                ti,bit-shift = <0>;
        };
 
@@ -52,7 +52,7 @@
                #clock-cells = <0>;
                compatible = "ti,gate-clock";
                clocks = <&sys_ck>;
-               reg = <0x059c>;
+               reg = <0x032c>;
                ti,bit-shift = <8>;
        };
 
@@ -60,7 +60,7 @@
                #clock-cells = <0>;
                compatible = "ti,am35xx-gate-clock";
                clocks = <&sys_ck>;
-               reg = <0x059c>;
+               reg = <0x032c>;
                ti,bit-shift = <3>;
        };
 };
index 8ae29c955c11d7f83f4423184a8ed61412b515dd..c17097d2c167d4718f76200f51e599d6605d144e 100644 (file)
@@ -49,7 +49,7 @@
                pinctrl-0 = <&matrix_keypad_pins>;
 
                debounce-delay-ms = <5>;
-               col-scan-delay-us = <1500>;
+               col-scan-delay-us = <5>;
 
                row-gpios = <&gpio5 5 GPIO_ACTIVE_HIGH          /* Bank5, pin5 */
                                &gpio5 6 GPIO_ACTIVE_HIGH>;     /* Bank5, pin6 */
                interrupt-parent = <&gpio0>;
                interrupts = <31 0>;
 
-               wake-gpios = <&gpio1 28 GPIO_ACTIVE_HIGH>;
+               reset-gpios = <&gpio1 28 GPIO_ACTIVE_LOW>;
 
                touchscreen-size-x = <480>;
                touchscreen-size-y = <272>;
index 15f198e4864d308196640f9ce5a8a190efe8ab9a..7128fad991ac3459ac5349b0219e893fab1830c8 100644 (file)
@@ -18,6 +18,7 @@
        aliases {
                rtc0 = &mcp_rtc;
                rtc1 = &tps659038_rtc;
+               rtc2 = &rtc;
        };
 
        memory {
@@ -83,7 +84,7 @@
        gpio_fan: gpio_fan {
                /* Based on 5v 500mA AFB02505HHB */
                compatible = "gpio-fan";
-               gpios =  <&tps659038_gpio 1 GPIO_ACTIVE_HIGH>;
+               gpios =  <&tps659038_gpio 2 GPIO_ACTIVE_HIGH>;
                gpio-fan,speed-map = <0     0>,
                                     <13000 1>;
                #cooling-cells = <2>;
 
        uart3_pins_default: uart3_pins_default {
                pinctrl-single,pins = <
-                       0x248 (PIN_INPUT_SLEW | MUX_MODE0) /* uart3_rxd.rxd */
-                       0x24c (PIN_INPUT_SLEW | MUX_MODE0) /* uart3_txd.txd */
+                       0x3f8 (PIN_INPUT_SLEW | MUX_MODE2) /* uart2_ctsn.uart3_rxd */
+                       0x3fc (PIN_INPUT_SLEW | MUX_MODE1) /* uart2_rtsn.uart3_txd */
                >;
        };
 
        mcp_rtc: rtc@6f {
                compatible = "microchip,mcp7941x";
                reg = <0x6f>;
-               interrupts = <GIC_SPI 2 IRQ_TYPE_LEVEL_LOW>;  /* IRQ_SYS_1N */
+               interrupts = <GIC_SPI 2 IRQ_TYPE_EDGE_RISING>;  /* IRQ_SYS_1N */
 
                pinctrl-names = "default";
                pinctrl-0 = <&mcp79410_pins_default>;
 &uart3 {
        status = "okay";
        interrupts-extended = <&crossbar_mpu GIC_SPI 69 IRQ_TYPE_LEVEL_HIGH>,
-                             <&dra7_pmx_core 0x248>;
+                             <&dra7_pmx_core 0x3f8>;
 
        pinctrl-names = "default";
        pinctrl-0 = <&uart3_pins_default>;
index c675257f2377f8797565871e38e77ba50fe7678b..f076ff856d8b8223466f3ec8536caaa1974186ca 100644 (file)
@@ -69,7 +69,7 @@
                mainpll: mainpll {
                        compatible = "fixed-clock";
                        #clock-cells = <0>;
-                       clock-frequency = <2000000000>;
+                       clock-frequency = <1000000000>;
                };
                /* 25 MHz reference crystal */
                refclk: oscillator {
index ed2dd8ba4080df7a7f85db89068de44cd693446b..218a2acd36e509b0de8e22dc207e06253b1163fe 100644 (file)
                mainpll: mainpll {
                        compatible = "fixed-clock";
                        #clock-cells = <0>;
-                       clock-frequency = <2000000000>;
+                       clock-frequency = <1000000000>;
                };
 
                /* 25 MHz reference crystal */
index 0e85fc15cedad84c1ea5ebea6db033a2ace60703..ecd1318109bac8fb5d1e29c96f7c30779d217fda 100644 (file)
                mainpll: mainpll {
                        compatible = "fixed-clock";
                        #clock-cells = <0>;
-                       clock-frequency = <2000000000>;
+                       clock-frequency = <1000000000>;
                };
        };
 };
index a2cf2154dcdb68d8374c2bea4b136fccaccb7aa2..fdd187c55aa5f78b5ab61d15dc12c1ad001990d2 100644 (file)
 
                internal-regs {
 
+                       rtc@10300 {
+                               /* No crystal connected to the internal RTC */
+                               status = "disabled";
+                       };
+
                        /* J10: VCC, NC, RX, NC, TX, GND  */
                        serial@12000 {
                                status = "okay";
index e3b08fb959e5f8ffc27977fa85d05c70a4d60792..990e8a2100f0f3cff6c50989761d6b78838e4bd8 100644 (file)
                };
 
                internal-regs {
+                       rtc@10300 {
+                               /* No crystal connected to the internal RTC */
+                               status = "disabled";
+                       };
                        serial@12000 {
                                status = "okay";
                        };
index de8427be830a32e24a01ace97f11303435528b7b..289806adb343806aefce22e63b6caa1d558741fb 100644 (file)
                        ti,hwmods = "usb_otg_hs";
 
                        usb0: usb@47401000 {
-                               compatible = "ti,musb-am33xx";
+                               compatible = "ti,musb-dm816";
                                reg = <0x47401400 0x400
                                       0x47401000 0x200>;
                                reg-names = "mc", "control";
                        };
 
                        usb1: usb@47401800 {
-                               compatible = "ti,musb-am33xx";
+                               compatible = "ti,musb-dm816";
                                reg = <0x47401c00 0x400
                                       0x47401800 0x200>;
                                reg-names = "mc", "control";
index aae7efc09b0bd1ecd66e72193c6aefe107008b9e..e6fa251e17b93b54f67bcd39b8da57476ddda519 100644 (file)
@@ -87,6 +87,7 @@
 
                /* connect xtal input to 25MHz reference */
                clocks = <&ref25>;
+               clock-names = "xtal";
 
                /* connect xtal input as source of pll0 and pll1 */
                silabs,pll-source = <0 0>, <1 0>;
index 5332b57b4950dbd61fac6ef7cb112c4cd44cffa7..f03a091cd0766b606d0f3a61a4ab03c870f3dfcf 100644 (file)
                        ti,clock-cycles = <16>;
 
                        reg = <0x4ae07ddc 0x4>, <0x4ae07de0 0x4>,
-                             <0x4ae06014 0x4>, <0x4a003b20 0x8>,
+                             <0x4ae06014 0x4>, <0x4a003b20 0xc>,
                              <0x4ae0c158 0x4>;
                        reg-names = "setup-address", "control-address",
                                    "int-address", "efuse-address",
                        ti,clock-cycles = <16>;
 
                        reg = <0x4ae07e34 0x4>, <0x4ae07e24 0x4>,
-                             <0x4ae06010 0x4>, <0x4a0025cc 0x8>,
+                             <0x4ae06010 0x4>, <0x4a0025cc 0xc>,
                              <0x4a002470 0x4>;
                        reg-names = "setup-address", "control-address",
                                    "int-address", "efuse-address",
                        ti,clock-cycles = <16>;
 
                        reg = <0x4ae07e30 0x4>, <0x4ae07e20 0x4>,
-                             <0x4ae06010 0x4>, <0x4a0025e0 0x8>,
+                             <0x4ae06010 0x4>, <0x4a0025e0 0xc>,
                              <0x4a00246c 0x4>;
                        reg-names = "setup-address", "control-address",
                                    "int-address", "efuse-address",
                        ti,clock-cycles = <16>;
 
                        reg = <0x4ae07de4 0x4>, <0x4ae07de8 0x4>,
-                             <0x4ae06010 0x4>, <0x4a003b08 0x8>,
+                             <0x4ae06010 0x4>, <0x4a003b08 0xc>,
                              <0x4ae0c154 0x4>;
                        reg-names = "setup-address", "control-address",
                                    "int-address", "efuse-address",
                        status = "disabled";
                };
 
-               rtc@48838000 {
+               rtc: rtc@48838000 {
                        compatible = "ti,am3352-rtc";
                        reg = <0x48838000 0x100>;
                        interrupts = <GIC_SPI 217 IRQ_TYPE_LEVEL_HIGH>,
index 8de12af7c276f427c7a8901b5411326b5fd8f20e..d6b49e5b32e9f35ed2a1378e1f7933997c5d4e85 100644 (file)
@@ -9,6 +9,7 @@
 
 #include <dt-bindings/sound/samsung-i2s.h>
 #include <dt-bindings/input/input.h>
+#include <dt-bindings/clock/maxim,max77686.h>
 #include "exynos4412.dtsi"
 
 / {
 
        rtc@10070000 {
                status = "okay";
+               clocks = <&clock CLK_RTC>, <&max77686 MAX77686_CLK_AP>;
+               clock-names = "rtc", "rtc_src";
        };
 
        g2d@10800000 {
index 173ffa479ad3cb03eb6e6742663fafaccacf9d53..792394dd0f2ab3ebf347af1e3f08d7ad330ee997 100644 (file)
 
                        display-timings {
                                timing-0 {
-                                       clock-frequency = <0>;
+                                       clock-frequency = <57153600>;
                                        hactive = <720>;
                                        vactive = <1280>;
                                        hfront-porch = <5>;
index 2657e842e5a5b68f6d840c70d5953e046608344f..1eca97ee4bd6320a3a3a44ede264e269041cd088 100644 (file)
        num-slots = <1>;
        broken-cd;
        cap-sdio-irq;
+       keep-power-in-suspend;
        card-detect-delay = <200>;
        samsung,dw-mshc-ciu-div = <3>;
        samsung,dw-mshc-sdr-timing = <2 3>;
index 0788d08fb43edd00b65f64864ab4a4476f7aaff6..146e71118a72b4eef98faf47f644c0216bbb5894 100644 (file)
        num-slots = <1>;
        broken-cd;
        cap-sdio-irq;
+       keep-power-in-suspend;
        card-detect-delay = <200>;
        clock-frequency = <400000000>;
        samsung,dw-mshc-ciu-div = <1>;
index 5d31fc14082360b41cc742ad3f549dc5d4f9013c..2180a0152c9bf9d78b8772af284d6445ad0b6ebd 100644 (file)
@@ -28,7 +28,7 @@ trips {
                type = "active";
        };
        cpu-crit-0 {
-               temperature = <1200000>; /* millicelsius */
+               temperature = <120000>; /* millicelsius */
                hysteresis = <0>; /* millicelsius */
                type = "critical";
        };
index f67b23f303c3904bfbf834e790a4bfd01f127ecd..45317538bbaeb48309d1b16c0e18beb8a7376639 100644 (file)
                clock-names = "dp";
                phys = <&dp_phy>;
                phy-names = "dp";
+               power-domains = <&disp_pd>;
        };
 
        mipi_phy: video-phy@10040714 {
index 48adfa8f4300b5c17d6bd43377568952c01b9593..356e963edf11e58f95c57f70be0661a6277cddd8 100644 (file)
@@ -18,7 +18,7 @@ trips {
                type = "active";
        };
        cpu-crit-0 {
-               temperature = <1050000>; /* millicelsius */
+               temperature = <105000>; /* millicelsius */
                hysteresis = <0>; /* millicelsius */
                type = "critical";
        };
index 412f41d62686f3ae966df4640d98988dc489c65f..02eb8b15374f3c84ef4b215f4d7da85d2e9f342a 100644 (file)
        num-slots = <1>;
        broken-cd;
        cap-sdio-irq;
+       keep-power-in-suspend;
        card-detect-delay = <200>;
        clock-frequency = <400000000>;
        samsung,dw-mshc-ciu-div = <1>;
index 7e6eef2488e807c12c36aaebfd3e64b076f7622f..82045398bf1fabdf47664290d636d78a38b23b14 100644 (file)
@@ -12,6 +12,7 @@
  */
 
 /dts-v1/;
+#include <dt-bindings/gpio/gpio.h>
 #include "imx23.dtsi"
 
 / {
@@ -93,6 +94,7 @@
 
        ahb@80080000 {
                usb0: usb@80080000 {
+                       dr_mode = "host";
                        vbus-supply = <&reg_usb0_vbus>;
                        status = "okay";
                };
 
                user {
                        label = "green";
-                       gpios = <&gpio2 1 1>;
+                       gpios = <&gpio2 1 GPIO_ACTIVE_HIGH>;
                };
        };
 };
index e4d3aecc4ed2c0fd61b1c68a93f20a24b808bd8c..677f81d9dcd529f92b6cf856464ec6595ef00509 100644 (file)
 
                        pwm4: pwm@53fc8000 {
                                compatible = "fsl,imx25-pwm", "fsl,imx27-pwm";
+                               #pwm-cells = <2>;
                                reg = <0x53fc8000 0x4000>;
                                clocks = <&clks 108>, <&clks 52>;
                                clock-names = "ipg", "per";
index 6951b66d1ab7b4cbe37dcf8944a7626213979827..bc215e4b75fd52c6e5b2e271b4a9e6265d442205 100644 (file)
 
                        fec: ethernet@1002b000 {
                                compatible = "fsl,imx27-fec";
-                               reg = <0x1002b000 0x4000>;
+                               reg = <0x1002b000 0x1000>;
                                interrupts = <50>;
                                clocks = <&clks IMX27_CLK_FEC_IPG_GATE>,
                                         <&clks IMX27_CLK_FEC_AHB_GATE>;
index 25e25f82fbaea4d9cc5bafa62ec93d1e0ba3f1c4..4e073e8547425ee189a6c91331ade03052e1d999 100644 (file)
                                              80 81 68 69
                                              70 71 72 73
                                              74 75 76 77>;
-                               interrupt-names = "auart4-rx", "aurat4-tx", "spdif-tx", "empty",
+                               interrupt-names = "auart4-rx", "auart4-tx", "spdif-tx", "empty",
                                                  "saif0", "saif1", "i2c0", "i2c1",
                                                  "auart0-rx", "auart0-tx", "auart1-rx", "auart1-tx",
                                                  "auart2-rx", "auart2-tx", "auart3-rx", "auart3-tx";
index 19cc269a08d4d7acdc3572821b32399ee584f824..1ce6133b67f5c65fefd2fe85d368ac455b199950 100644 (file)
@@ -31,6 +31,7 @@
                        regulator-min-microvolt = <5000000>;
                        regulator-max-microvolt = <5000000>;
                        gpio = <&gpio4 15 0>;
+                       enable-active-high;
                };
 
                reg_usb_h1_vbus: regulator@1 {
@@ -40,6 +41,7 @@
                        regulator-min-microvolt = <5000000>;
                        regulator-max-microvolt = <5000000>;
                        gpio = <&gpio1 0 0>;
+                       enable-active-high;
                };
        };
 
index 46b2fed7c319c891dde01d415521b7207702b45b..3b24b12651b2b86ee1a74d5baccca435778ddd3e 100644 (file)
 &i2c3 {
        pinctrl-names = "default";
        pinctrl-0 = <&pinctrl_i2c3>;
-       pinctrl-assert-gpios = <&gpio5 4 GPIO_ACTIVE_HIGH>;
        status = "okay";
 
        max7310_a: gpio@30 {
index 134d3f27a8ec5ae1f4f68982da4047dfcff13e13..921de6605f075d878f407d925a5652195bd2b41d 100644 (file)
        nand@0,0 {
                reg = <0 0 4>; /* CS0, offset 0, IO size 4 */
                nand-bus-width = <16>;
+               gpmc,device-width = <2>;
+               ti,nand-ecc-opt = "sw";
 
                gpmc,sync-clk-ps = <0>;
                gpmc,cs-on-ns = <0>;
index a29315833ecd3bfc1f1a7f86f7f3c5734453a00f..5f5e0f3d5b64fcb2283f72b9df923c793be7f75c 100644 (file)
                DRVDD-supply = <&vmmc2>;
                IOVDD-supply = <&vio>;
                DVDD-supply = <&vio>;
+
+               ai3x-micbias-vg = <1>;
        };
 
        tlv320aic3x_aux: tlv320aic3x@19 {
                DRVDD-supply = <&vmmc2>;
                IOVDD-supply = <&vio>;
                DVDD-supply = <&vio>;
+
+               ai3x-micbias-vg = <2>;
        };
 
        tsl2563: tsl2563@29 {
                touchscreen-fuzz-x = <4>;
                touchscreen-fuzz-y = <7>;
                touchscreen-fuzz-pressure = <2>;
-               touchscreen-max-x = <4096>;
-               touchscreen-max-y = <4096>;
+               touchscreen-size-x = <4096>;
+               touchscreen-size-y = <4096>;
                touchscreen-max-pressure = <2048>;
 
                ti,x-plate-ohms = <280>;
index d18a90f5eca3145e527926a5d2bbbb44c2d8b1c0..69a40cfc1f29dddbd515b4f821459442787d401a 100644 (file)
                };
 
                mmu_isp: mmu@480bd400 {
+                       #iommu-cells = <0>;
                        compatible = "ti,omap2-iommu";
                        reg = <0x480bd400 0x80>;
                        interrupts = <24>;
                };
 
                mmu_iva: mmu@5d000000 {
+                       #iommu-cells = <0>;
                        compatible = "ti,omap2-iommu";
                        reg = <0x5d000000 0x80>;
                        interrupts = <28>;
index efe5f737f39b42b7f01710abdd4e72d90bd53514..7d24ae0306b56845c80c2c783dd818033a3a6cd1 100644 (file)
         * hierarchy.
         */
        ocp {
-               compatible = "ti,omap4-l3-noc", "simple-bus";
+               compatible = "ti,omap5-l3-noc", "simple-bus";
                #address-cells = <1>;
                #size-cells = <1>;
                ranges;
index 74c3212f1f11e47e8319ab67a252853400b2c910..824ddab9c3adcbde11ac8ea62f339af6aa1b3ec6 100644 (file)
                compatible = "adi,adv7511w";
                reg = <0x39>;
                interrupt-parent = <&gpio3>;
-               interrupts = <29 IRQ_TYPE_EDGE_FALLING>;
+               interrupts = <29 IRQ_TYPE_LEVEL_LOW>;
 
                adi,input-depth = <8>;
                adi,input-colorspace = "rgb";
index bfd3f1c734b8d84dec4a622032e1b29efa07b83d..2201cd5da3bb95843278b27c8f855d540d154041 100644 (file)
                        status = "disabled";
                };
 
-               vmmci: regulator-gpio {
-                       compatible = "regulator-gpio";
-
-                       regulator-min-microvolt = <1800000>;
-                       regulator-max-microvolt = <2900000>;
-                       regulator-name = "mmci-reg";
-                       regulator-type = "voltage";
-
-                       startup-delay-us = <100>;
-                       enable-active-high;
-
-                       states = <1800000 0x1
-                                 2900000 0x0>;
-
-                       status = "disabled";
-               };
-
                mcde@a0350000 {
                        compatible = "stericsson,mcde";
                        reg = <0xa0350000 0x1000>, /* MCDE */
index bf8f0eddc2c020d03dda99adfdc32d453e254c14..744c1e3a744df1530ba53cd2a56029a9e9ac5d37 100644 (file)
                        pinctrl-1 = <&i2c3_sleep_mode>;
                };
 
+               vmmci: regulator-gpio {
+                       compatible = "regulator-gpio";
+
+                       regulator-min-microvolt = <1800000>;
+                       regulator-max-microvolt = <2900000>;
+                       regulator-name = "mmci-reg";
+                       regulator-type = "voltage";
+
+                       startup-delay-us = <100>;
+                       enable-active-high;
+
+                       states = <1800000 0x1
+                                 2900000 0x0>;
+               };
+
                // External Micro SD slot
                sdi0_per1@80126000 {
                        arm,primecell-periphid = <0x10480180>;
index 206826a855c0dc0e5025539e5a8930405c8cdd56..1bc84ebdccaa2fe119ebb9e542f88b64f017cea9 100644 (file)
                };
 
                vmmci: regulator-gpio {
+                       compatible = "regulator-gpio";
+
                        gpios = <&gpio7 4 0x4>;
                        enable-gpio = <&gpio6 25 0x4>;
+
+                       regulator-min-microvolt = <1800000>;
+                       regulator-max-microvolt = <2900000>;
+                       regulator-name = "mmci-reg";
+                       regulator-type = "voltage";
+
+                       startup-delay-us = <100>;
+                       enable-active-high;
+
+                       states = <1800000 0x1
+                                 2900000 0x0>;
                };
 
                // External Micro SD slot
index cf01c818b8ea41999f231f07211aec46a86e505c..13cc7ca5e031e5f1814697e8ead9546079f6d04e 100644 (file)
                         <&tegra_car TEGRA124_CLK_PLL_U>,
                         <&tegra_car TEGRA124_CLK_USBD>;
                clock-names = "reg", "pll_u", "utmi-pads";
-               resets = <&tegra_car 59>, <&tegra_car 22>;
+               resets = <&tegra_car 22>, <&tegra_car 22>;
                reset-names = "usb", "utmi-pads";
                nvidia,hssync-start-delay = <0>;
                nvidia,idle-wait-delay = <17>;
                nvidia,hssquelch-level = <2>;
                nvidia,hsdiscon-level = <5>;
                nvidia,xcvr-hsslew = <12>;
+               nvidia,has-utmi-pad-registers;
                status = "disabled";
        };
 
                         <&tegra_car TEGRA124_CLK_PLL_U>,
                         <&tegra_car TEGRA124_CLK_USBD>;
                clock-names = "reg", "pll_u", "utmi-pads";
-               resets = <&tegra_car 22>, <&tegra_car 22>;
+               resets = <&tegra_car 58>, <&tegra_car 22>;
                reset-names = "usb", "utmi-pads";
                nvidia,hssync-start-delay = <0>;
                nvidia,idle-wait-delay = <17>;
                nvidia,hssquelch-level = <2>;
                nvidia,hsdiscon-level = <5>;
                nvidia,xcvr-hsslew = <12>;
-               nvidia,has-utmi-pad-registers;
                status = "disabled";
        };
 
                         <&tegra_car TEGRA124_CLK_PLL_U>,
                         <&tegra_car TEGRA124_CLK_USBD>;
                clock-names = "reg", "pll_u", "utmi-pads";
-               resets = <&tegra_car 58>, <&tegra_car 22>;
+               resets = <&tegra_car 59>, <&tegra_car 22>;
                reset-names = "usb", "utmi-pads";
                nvidia,hssync-start-delay = <0>;
                nvidia,idle-wait-delay = <17>;
index 7a2aeacd62c0c2cb23b1247ce3b5ca6c55225d24..107395c32d8265863fecb711311def376ab500b6 100644 (file)
                compatible = "arm,cortex-a15-pmu";
                interrupts = <0 68 4>,
                             <0 69 4>;
+               interrupt-affinity = <&cpu0>, <&cpu1>;
        };
 
        oscclk6a: oscclk6a {
index 23662b5a5e9d84554f34eb0fc3edad1ef029f4e6..d949facba37641b3b36f337cd3eefce7932280d9 100644 (file)
                #address-cells = <1>;
                #size-cells = <0>;
 
-               cpu@0 {
+               A9_0: cpu@0 {
                        device_type = "cpu";
                        compatible = "arm,cortex-a9";
                        reg = <0>;
                        next-level-cache = <&L2>;
                };
 
-               cpu@1 {
+               A9_1: cpu@1 {
                        device_type = "cpu";
                        compatible = "arm,cortex-a9";
                        reg = <1>;
                        next-level-cache = <&L2>;
                };
 
-               cpu@2 {
+               A9_2: cpu@2 {
                        device_type = "cpu";
                        compatible = "arm,cortex-a9";
                        reg = <2>;
                        next-level-cache = <&L2>;
                };
 
-               cpu@3 {
+               A9_3: cpu@3 {
                        device_type = "cpu";
                        compatible = "arm,cortex-a9";
                        reg = <3>;
                compatible = "arm,pl310-cache";
                reg = <0x1e00a000 0x1000>;
                interrupts = <0 43 4>;
+               cache-unified;
                cache-level = <2>;
                arm,data-latency = <1 1 1>;
                arm,tag-latency = <1 1 1>;
                             <0 61 4>,
                             <0 62 4>,
                             <0 63 4>;
+               interrupt-affinity = <&A9_0>, <&A9_1>, <&A9_2>, <&A9_3>;
+
        };
 
        dcc {
index a5cd2eda3edf4fdb4d616999532d8f94da2d7bd3..9ea54b3dba09b7de9be7936ae0a755c4ed115a97 100644 (file)
                };
 
                gem0: ethernet@e000b000 {
-                       compatible = "cdns,gem";
+                       compatible = "cdns,zynq-gem";
                        reg = <0xe000b000 0x1000>;
                        status = "disabled";
                        interrupts = <0 22 4>;
                };
 
                gem1: ethernet@e000c000 {
-                       compatible = "cdns,gem";
+                       compatible = "cdns,zynq-gem";
                        reg = <0xe000c000 0x1000>;
                        status = "disabled";
                        interrupts = <0 45 4>;
index ab86655c1f4be22869742d274b157e5470a2bb0c..fbbb1915c6a95a81ac3edc58a6725f96c3c8b890 100644 (file)
@@ -39,11 +39,14 @@ CONFIG_ARCH_HIP04=y
 CONFIG_ARCH_KEYSTONE=y
 CONFIG_ARCH_MESON=y
 CONFIG_ARCH_MXC=y
+CONFIG_SOC_IMX50=y
 CONFIG_SOC_IMX51=y
 CONFIG_SOC_IMX53=y
 CONFIG_SOC_IMX6Q=y
 CONFIG_SOC_IMX6SL=y
+CONFIG_SOC_IMX6SX=y
 CONFIG_SOC_VF610=y
+CONFIG_SOC_LS1021A=y
 CONFIG_ARCH_OMAP3=y
 CONFIG_ARCH_OMAP4=y
 CONFIG_SOC_OMAP5=y
@@ -426,7 +429,7 @@ CONFIG_USB_EHCI_EXYNOS=y
 CONFIG_USB_EHCI_TEGRA=y
 CONFIG_USB_EHCI_HCD_STI=y
 CONFIG_USB_EHCI_HCD_PLATFORM=y
-CONFIG_USB_ISP1760_HCD=y
+CONFIG_USB_ISP1760=y
 CONFIG_USB_OHCI_HCD=y
 CONFIG_USB_OHCI_HCD_STI=y
 CONFIG_USB_OHCI_HCD_PLATFORM=y
index 9ff7b54b2a837aa509b46d71b38741b7ded2c25d..3743ca221d402ce5d89df72baca5b1500ebb799b 100644 (file)
@@ -393,7 +393,7 @@ CONFIG_TI_EDMA=y
 CONFIG_DMA_OMAP=y
 # CONFIG_IOMMU_SUPPORT is not set
 CONFIG_EXTCON=m
-CONFIG_EXTCON_GPIO=m
+CONFIG_EXTCON_USB_GPIO=m
 CONFIG_EXTCON_PALMAS=m
 CONFIG_TI_EMIF=m
 CONFIG_PWM=y
index 8e3fcb924db6f13fcf0c5c08f6c8bb6cdc28a36b..2ef282f96651fbac9daa8b614c697c8020d1715f 100644 (file)
@@ -25,7 +25,7 @@ struct dma_iommu_mapping {
 };
 
 struct dma_iommu_mapping *
-arm_iommu_create_mapping(struct bus_type *bus, dma_addr_t base, size_t size);
+arm_iommu_create_mapping(struct bus_type *bus, dma_addr_t base, u64 size);
 
 void arm_iommu_release_mapping(struct dma_iommu_mapping *mapping);
 
index 2f7e6ff67d51556218dbc4e9858442da6601df81..0b579b2f4e0e6490bb396c301cd2adf433e3b1ad 100644 (file)
@@ -110,5 +110,6 @@ static inline bool set_phys_to_machine(unsigned long pfn, unsigned long mfn)
 bool xen_arch_need_swiotlb(struct device *dev,
                           unsigned long pfn,
                           unsigned long mfn);
+unsigned long xen_get_swiotlb_free_pages(unsigned int order);
 
 #endif /* _ASM_ARM_XEN_PAGE_H */
index f8ccc21fa032354facead9735abf9f4eb0cb7eb2..4e7f40c577e6e4fe9df3dd677b0d146b1ceb13c2 100644 (file)
@@ -33,7 +33,9 @@ ret_fast_syscall:
  UNWIND(.fnstart       )
  UNWIND(.cantunwind    )
        disable_irq                             @ disable interrupts
-       ldr     r1, [tsk, #TI_FLAGS]
+       ldr     r1, [tsk, #TI_FLAGS]            @ re-check for syscall tracing
+       tst     r1, #_TIF_SYSCALL_WORK
+       bne     __sys_trace_return
        tst     r1, #_TIF_WORK_MASK
        bne     fast_work_pending
        asm_trace_hardirqs_on
index 91c7ba182dcdd9b9e84ce8f5222181b32922deaf..3b8c2833c5379aa36ca3a0a384bb740df3f3284a 100644 (file)
@@ -303,9 +303,15 @@ static int probe_current_pmu(struct arm_pmu *pmu)
 
 static int of_pmu_irq_cfg(struct platform_device *pdev)
 {
-       int i;
-       int *irqs = kcalloc(pdev->num_resources, sizeof(*irqs), GFP_KERNEL);
+       int i, irq;
+       int *irqs;
 
+       /* Don't bother with PPIs; they're already affine */
+       irq = platform_get_irq(pdev, 0);
+       if (irq >= 0 && irq_is_percpu(irq))
+               return 0;
+
+       irqs = kcalloc(pdev->num_resources, sizeof(*irqs), GFP_KERNEL);
        if (!irqs)
                return -ENOMEM;
 
@@ -317,7 +323,7 @@ static int of_pmu_irq_cfg(struct platform_device *pdev)
                                      i);
                if (!dn) {
                        pr_warn("Failed to parse %s/interrupt-affinity[%d]\n",
-                               of_node_full_name(dn), i);
+                               of_node_full_name(pdev->dev.of_node), i);
                        break;
                }
 
index acd5b560b72801c6e2e4b51baa5ca4c129f44b2d..5f5cd562c593ef5f6a9224254c146e7d3d0136a3 100644 (file)
@@ -159,6 +159,8 @@ extern void exynos_enter_aftr(void);
 
 extern struct cpuidle_exynos_data cpuidle_coupled_exynos_data;
 
+extern void exynos_set_delayed_reset_assertion(bool enable);
+
 extern void s5p_init_cpu(void __iomem *cpuid_addr);
 extern unsigned int samsung_rev(void);
 extern void __iomem *cpu_boot_reg_base(void);
index bcde0dd668df950f1918a66179715a56ec9578fa..5917a30eee33f286c80708dfb84cdd610bd2dd9d 100644 (file)
@@ -166,6 +166,33 @@ static void __init exynos_init_io(void)
        exynos_map_io();
 }
 
+/*
+ * Set or clear the USE_DELAYED_RESET_ASSERTION option. Used by smp code
+ * and suspend.
+ *
+ * This is necessary only on Exynos4 SoCs. When system is running
+ * USE_DELAYED_RESET_ASSERTION should be set so the ARM CLK clock down
+ * feature could properly detect global idle state when secondary CPU is
+ * powered down.
+ *
+ * However this should not be set when such system is going into suspend.
+ */
+void exynos_set_delayed_reset_assertion(bool enable)
+{
+       if (of_machine_is_compatible("samsung,exynos4")) {
+               unsigned int tmp, core_id;
+
+               for (core_id = 0; core_id < num_possible_cpus(); core_id++) {
+                       tmp = pmu_raw_readl(EXYNOS_ARM_CORE_OPTION(core_id));
+                       if (enable)
+                               tmp |= S5P_USE_DELAYED_RESET_ASSERTION;
+                       else
+                               tmp &= ~(S5P_USE_DELAYED_RESET_ASSERTION);
+                       pmu_raw_writel(tmp, EXYNOS_ARM_CORE_OPTION(core_id));
+               }
+       }
+}
+
 /*
  * Apparently, these SoCs are not able to wake-up from suspend using
  * the PMU. Too bad. Should they suddenly become capable of such a
index ebd135bb0995611517c1bce6d3b70deeeee37de4..a825bca2a2b699490809676cef6f66d4eb86fd21 100644 (file)
 
 extern void exynos4_secondary_startup(void);
 
-/*
- * Set or clear the USE_DELAYED_RESET_ASSERTION option, set on Exynos4 SoCs
- * during hot-(un)plugging CPUx.
- *
- * The feature can be cleared safely during first boot of secondary CPU.
- *
- * Exynos4 SoCs require setting USE_DELAYED_RESET_ASSERTION during powering
- * down a CPU so the CPU idle clock down feature could properly detect global
- * idle state when CPUx is off.
- */
-static void exynos_set_delayed_reset_assertion(u32 core_id, bool enable)
-{
-       if (soc_is_exynos4()) {
-               unsigned int tmp;
-
-               tmp = pmu_raw_readl(EXYNOS_ARM_CORE_OPTION(core_id));
-               if (enable)
-                       tmp |= S5P_USE_DELAYED_RESET_ASSERTION;
-               else
-                       tmp &= ~(S5P_USE_DELAYED_RESET_ASSERTION);
-               pmu_raw_writel(tmp, EXYNOS_ARM_CORE_OPTION(core_id));
-       }
-}
-
 #ifdef CONFIG_HOTPLUG_CPU
 static inline void cpu_leave_lowpower(u32 core_id)
 {
@@ -73,8 +49,6 @@ static inline void cpu_leave_lowpower(u32 core_id)
          : "=&r" (v)
          : "Ir" (CR_C), "Ir" (0x40)
          : "cc");
-
-        exynos_set_delayed_reset_assertion(core_id, false);
 }
 
 static inline void platform_do_lowpower(unsigned int cpu, int *spurious)
@@ -87,14 +61,6 @@ static inline void platform_do_lowpower(unsigned int cpu, int *spurious)
                /* Turn the CPU off on next WFI instruction. */
                exynos_cpu_power_down(core_id);
 
-               /*
-                * Exynos4 SoCs require setting
-                * USE_DELAYED_RESET_ASSERTION so the CPU idle
-                * clock down feature could properly detect
-                * global idle state when CPUx is off.
-                */
-               exynos_set_delayed_reset_assertion(core_id, true);
-
                wfi();
 
                if (pen_release == core_id) {
@@ -371,9 +337,6 @@ static int exynos_boot_secondary(unsigned int cpu, struct task_struct *idle)
                udelay(10);
        }
 
-       /* No harm if this is called during first boot of secondary CPU */
-       exynos_set_delayed_reset_assertion(core_id, false);
-
        /*
         * now the secondary core is starting up let it run its
         * calibrations, then wait for it to finish
@@ -420,6 +383,8 @@ static void __init exynos_smp_prepare_cpus(unsigned int max_cpus)
 
        exynos_sysram_init();
 
+       exynos_set_delayed_reset_assertion(true);
+
        if (read_cpuid_part() == ARM_CPU_PART_CORTEX_A9)
                scu_enable(scu_base_addr());
 
index cbe56b35aea000fe2ad5841851b5eb9a57a307d5..a9686535f9ed460706a41a99dc60d6d4f575ab3b 100644 (file)
@@ -188,7 +188,7 @@ no_clk:
                args.np = np;
                args.args_count = 0;
                child_domain = of_genpd_get_from_provider(&args);
-               if (!child_domain)
+               if (IS_ERR(child_domain))
                        continue;
 
                if (of_parse_phandle_with_args(np, "power-domains",
@@ -196,7 +196,7 @@ no_clk:
                        continue;
 
                parent_domain = of_genpd_get_from_provider(&args);
-               if (!parent_domain)
+               if (IS_ERR(parent_domain))
                        continue;
 
                if (pm_genpd_add_subdomain(parent_domain, child_domain))
index 3e6aea7f83af199d7c624372fb96549430504cc2..7d23ce04cad5201919a58aefccafc88e882dd844 100644 (file)
@@ -87,8 +87,8 @@ static unsigned int exynos_pmu_spare3;
 static u32 exynos_irqwake_intmask = 0xffffffff;
 
 static const struct exynos_wkup_irq exynos3250_wkup_irq[] = {
-       { 105, BIT(1) }, /* RTC alarm */
-       { 106, BIT(2) }, /* RTC tick */
+       { 73, BIT(1) }, /* RTC alarm */
+       { 74, BIT(2) }, /* RTC tick */
        { /* sentinel */ },
 };
 
@@ -342,6 +342,8 @@ static void exynos_pm_enter_sleep_mode(void)
 
 static void exynos_pm_prepare(void)
 {
+       exynos_set_delayed_reset_assertion(false);
+
        /* Set wake-up mask registers */
        exynos_pm_set_wakeup_mask();
 
@@ -482,6 +484,7 @@ early_wakeup:
 
        /* Clear SLEEP mode set in INFORM1 */
        pmu_raw_writel(0x0, S5P_INFORM1);
+       exynos_set_delayed_reset_assertion(true);
 }
 
 static void exynos3250_pm_resume(void)
@@ -723,8 +726,10 @@ void __init exynos_pm_init(void)
                return;
        }
 
-       if (WARN_ON(!of_find_property(np, "interrupt-controller", NULL)))
+       if (WARN_ON(!of_find_property(np, "interrupt-controller", NULL))) {
                pr_warn("Outdated DT detected, suspend/resume will NOT work\n");
+               return;
+       }
 
        pm_data = (const struct exynos_pm_data *) match->data;
 
index 38a45260a7c8b522dc3b8c163a19d4debe711ca9..dd883698ff7eafe977d2a220468d5aad876ce5ce 100644 (file)
@@ -12,6 +12,8 @@
 #ifndef __GEMINI_COMMON_H__
 #define __GEMINI_COMMON_H__
 
+#include <linux/reboot.h>
+
 struct mtd_partition;
 
 extern void gemini_map_io(void);
@@ -26,6 +28,6 @@ extern int platform_register_pflash(unsigned int size,
                                    struct mtd_partition *parts,
                                    unsigned int nr_parts);
 
-extern void gemini_restart(char mode, const char *cmd);
+extern void gemini_restart(enum reboot_mode mode, const char *cmd);
 
 #endif /* __GEMINI_COMMON_H__ */
index b26659759e2750bfef5f171b7d770905019e58ed..21a6d6d4f9c43d1ab8a608962761098bc847e35f 100644 (file)
@@ -14,7 +14,9 @@
 #include <mach/hardware.h>
 #include <mach/global_reg.h>
 
-void gemini_restart(char mode, const char *cmd)
+#include "common.h"
+
+void gemini_restart(enum reboot_mode mode, const char *cmd)
 {
        __raw_writel(RESET_GLOBAL | RESET_CPU1,
                     IO_ADDRESS(GEMINI_GLOBAL_BASE) + GLOBAL_RESET);
index fb8d4a2ad48c0629b3cfbbe7c2b76c6646c9b436..a5edd7d60266985472ac9de11e6fb9801f8eadeb 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2010 Pengutronix, Wolfram Sang <w.sang@pengutronix.de>
+ * Copyright (C) 2010 Pengutronix, Wolfram Sang <kernel@pengutronix.de>
  *
  * This program is free software; you can redistribute it and/or modify it under
  * the terms of the GNU General Public License version 2 as published by the
index 4d60005e9277ce8f33307f411dd5c0baa8a6ac7a..6d0893a3828eb6b57322ddd0e0df26ac7e32bd85 100644 (file)
@@ -280,9 +280,15 @@ void __init imx_gpc_check_dt(void)
        struct device_node *np;
 
        np = of_find_compatible_node(NULL, NULL, "fsl,imx6q-gpc");
-       if (WARN_ON(!np ||
-                   !of_find_property(np, "interrupt-controller", NULL)))
-               pr_warn("Outdated DT detected, system is about to crash!!!\n");
+       if (WARN_ON(!np))
+               return;
+
+       if (WARN_ON(!of_find_property(np, "interrupt-controller", NULL))) {
+               pr_warn("Outdated DT detected, suspend/resume will NOT work\n");
+
+               /* map GPC, so that at least CPUidle and WARs keep working */
+               gpc_base = of_iomap(np, 0);
+       }
 }
 
 #ifdef CONFIG_PM_GENERIC_DOMAINS
@@ -443,6 +449,10 @@ static int imx_gpc_probe(struct platform_device *pdev)
        struct regulator *pu_reg;
        int ret;
 
+       /* bail out if DT too old and doesn't provide the necessary info */
+       if (!of_property_read_bool(pdev->dev.of_node, "#power-domain-cells"))
+               return 0;
+
        pu_reg = devm_regulator_get_optional(&pdev->dev, "pu");
        if (PTR_ERR(pu_reg) == -ENODEV)
                pu_reg = NULL;
index 355b089368715427627dd39f1014ed7024ae8459..752969ff9de04f95ef8b9a695325901b6297cf78 100644 (file)
  */
 #define LINKS_PER_OCP_IF               2
 
+/*
+ * Address offset (in bytes) between the reset control and the reset
+ * status registers: 4 bytes on OMAP4
+ */
+#define OMAP4_RST_CTRL_ST_OFFSET       4
+
 /**
  * struct omap_hwmod_soc_ops - fn ptrs for some SoC-specific operations
  * @enable_module: function to enable a module (via MODULEMODE)
@@ -3016,10 +3022,12 @@ static int _omap4_deassert_hardreset(struct omap_hwmod *oh,
        if (ohri->st_shift)
                pr_err("omap_hwmod: %s: %s: hwmod data error: OMAP4 does not support st_shift\n",
                       oh->name, ohri->name);
-       return omap_prm_deassert_hardreset(ohri->rst_shift, 0,
+       return omap_prm_deassert_hardreset(ohri->rst_shift, ohri->rst_shift,
                                           oh->clkdm->pwrdm.ptr->prcm_partition,
                                           oh->clkdm->pwrdm.ptr->prcm_offs,
-                                          oh->prcm.omap4.rstctrl_offs, 0);
+                                          oh->prcm.omap4.rstctrl_offs,
+                                          oh->prcm.omap4.rstctrl_offs +
+                                          OMAP4_RST_CTRL_ST_OFFSET);
 }
 
 /**
@@ -3047,27 +3055,6 @@ static int _omap4_is_hardreset_asserted(struct omap_hwmod *oh,
                                              oh->prcm.omap4.rstctrl_offs);
 }
 
-/**
- * _am33xx_assert_hardreset - call AM33XX PRM hardreset fn with hwmod args
- * @oh: struct omap_hwmod * to assert hardreset
- * @ohri: hardreset line data
- *
- * Call am33xx_prminst_assert_hardreset() with parameters extracted
- * from the hwmod @oh and the hardreset line data @ohri.  Only
- * intended for use as an soc_ops function pointer.  Passes along the
- * return value from am33xx_prminst_assert_hardreset().  XXX This
- * function is scheduled for removal when the PRM code is moved into
- * drivers/.
- */
-static int _am33xx_assert_hardreset(struct omap_hwmod *oh,
-                                  struct omap_hwmod_rst_info *ohri)
-
-{
-       return omap_prm_assert_hardreset(ohri->rst_shift, 0,
-                                        oh->clkdm->pwrdm.ptr->prcm_offs,
-                                        oh->prcm.omap4.rstctrl_offs);
-}
-
 /**
  * _am33xx_deassert_hardreset - call AM33XX PRM hardreset fn with hwmod args
  * @oh: struct omap_hwmod * to deassert hardreset
@@ -3083,32 +3070,13 @@ static int _am33xx_assert_hardreset(struct omap_hwmod *oh,
 static int _am33xx_deassert_hardreset(struct omap_hwmod *oh,
                                     struct omap_hwmod_rst_info *ohri)
 {
-       return omap_prm_deassert_hardreset(ohri->rst_shift, ohri->st_shift, 0,
+       return omap_prm_deassert_hardreset(ohri->rst_shift, ohri->st_shift,
+                                          oh->clkdm->pwrdm.ptr->prcm_partition,
                                           oh->clkdm->pwrdm.ptr->prcm_offs,
                                           oh->prcm.omap4.rstctrl_offs,
                                           oh->prcm.omap4.rstst_offs);
 }
 
-/**
- * _am33xx_is_hardreset_asserted - call AM33XX PRM hardreset fn with hwmod args
- * @oh: struct omap_hwmod * to test hardreset
- * @ohri: hardreset line data
- *
- * Call am33xx_prminst_is_hardreset_asserted() with parameters
- * extracted from the hwmod @oh and the hardreset line data @ohri.
- * Only intended for use as an soc_ops function pointer.  Passes along
- * the return value from am33xx_prminst_is_hardreset_asserted().  XXX
- * This function is scheduled for removal when the PRM code is moved
- * into drivers/.
- */
-static int _am33xx_is_hardreset_asserted(struct omap_hwmod *oh,
-                                       struct omap_hwmod_rst_info *ohri)
-{
-       return omap_prm_is_hardreset_asserted(ohri->rst_shift, 0,
-                                             oh->clkdm->pwrdm.ptr->prcm_offs,
-                                             oh->prcm.omap4.rstctrl_offs);
-}
-
 /* Public functions */
 
 u32 omap_hwmod_read(struct omap_hwmod *oh, u16 reg_offs)
@@ -3908,21 +3876,13 @@ void __init omap_hwmod_init(void)
                soc_ops.init_clkdm = _init_clkdm;
                soc_ops.update_context_lost = _omap4_update_context_lost;
                soc_ops.get_context_lost = _omap4_get_context_lost;
-       } else if (soc_is_am43xx()) {
+       } else if (cpu_is_ti816x() || soc_is_am33xx() || soc_is_am43xx()) {
                soc_ops.enable_module = _omap4_enable_module;
                soc_ops.disable_module = _omap4_disable_module;
                soc_ops.wait_target_ready = _omap4_wait_target_ready;
                soc_ops.assert_hardreset = _omap4_assert_hardreset;
-               soc_ops.deassert_hardreset = _omap4_deassert_hardreset;
-               soc_ops.is_hardreset_asserted = _omap4_is_hardreset_asserted;
-               soc_ops.init_clkdm = _init_clkdm;
-       } else if (cpu_is_ti816x() || soc_is_am33xx()) {
-               soc_ops.enable_module = _omap4_enable_module;
-               soc_ops.disable_module = _omap4_disable_module;
-               soc_ops.wait_target_ready = _omap4_wait_target_ready;
-               soc_ops.assert_hardreset = _am33xx_assert_hardreset;
                soc_ops.deassert_hardreset = _am33xx_deassert_hardreset;
-               soc_ops.is_hardreset_asserted = _am33xx_is_hardreset_asserted;
+               soc_ops.is_hardreset_asserted = _omap4_is_hardreset_asserted;
                soc_ops.init_clkdm = _init_clkdm;
        } else {
                WARN(1, "omap_hwmod: unknown SoC type\n");
index e2223148ba4d37a0818fc65d19ddb00bdc49d56c..17e8004fc20f9e48c69722c32643f7684b7c9eb2 100644 (file)
@@ -544,6 +544,44 @@ static struct omap_hwmod am43xx_hdq1w_hwmod = {
        },
 };
 
+static struct omap_hwmod_class_sysconfig am43xx_vpfe_sysc = {
+       .rev_offs       = 0x0,
+       .sysc_offs      = 0x104,
+       .sysc_flags     = SYSC_HAS_MIDLEMODE | SYSC_HAS_SIDLEMODE,
+       .idlemodes      = (SIDLE_FORCE | SIDLE_NO | SIDLE_SMART |
+                               MSTANDBY_FORCE | MSTANDBY_SMART | MSTANDBY_NO),
+       .sysc_fields    = &omap_hwmod_sysc_type2,
+};
+
+static struct omap_hwmod_class am43xx_vpfe_hwmod_class = {
+       .name           = "vpfe",
+       .sysc           = &am43xx_vpfe_sysc,
+};
+
+static struct omap_hwmod am43xx_vpfe0_hwmod = {
+       .name           = "vpfe0",
+       .class          = &am43xx_vpfe_hwmod_class,
+       .clkdm_name     = "l3s_clkdm",
+       .prcm           = {
+               .omap4  = {
+                       .modulemode     = MODULEMODE_SWCTRL,
+                       .clkctrl_offs   = AM43XX_CM_PER_VPFE0_CLKCTRL_OFFSET,
+               },
+       },
+};
+
+static struct omap_hwmod am43xx_vpfe1_hwmod = {
+       .name           = "vpfe1",
+       .class          = &am43xx_vpfe_hwmod_class,
+       .clkdm_name     = "l3s_clkdm",
+       .prcm           = {
+               .omap4  = {
+                       .modulemode     = MODULEMODE_SWCTRL,
+                       .clkctrl_offs   = AM43XX_CM_PER_VPFE1_CLKCTRL_OFFSET,
+               },
+       },
+};
+
 /* Interfaces */
 static struct omap_hwmod_ocp_if am43xx_l3_main__l4_hs = {
        .master         = &am33xx_l3_main_hwmod,
@@ -825,6 +863,34 @@ static struct omap_hwmod_ocp_if am43xx_l4_ls__hdq1w = {
        .user           = OCP_USER_MPU | OCP_USER_SDMA,
 };
 
+static struct omap_hwmod_ocp_if am43xx_l3__vpfe0 = {
+       .master         = &am43xx_vpfe0_hwmod,
+       .slave          = &am33xx_l3_main_hwmod,
+       .clk            = "l3_gclk",
+       .user           = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+static struct omap_hwmod_ocp_if am43xx_l3__vpfe1 = {
+       .master         = &am43xx_vpfe1_hwmod,
+       .slave          = &am33xx_l3_main_hwmod,
+       .clk            = "l3_gclk",
+       .user           = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+static struct omap_hwmod_ocp_if am43xx_l4_ls__vpfe0 = {
+       .master         = &am33xx_l4_ls_hwmod,
+       .slave          = &am43xx_vpfe0_hwmod,
+       .clk            = "l4ls_gclk",
+       .user           = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+static struct omap_hwmod_ocp_if am43xx_l4_ls__vpfe1 = {
+       .master         = &am33xx_l4_ls_hwmod,
+       .slave          = &am43xx_vpfe1_hwmod,
+       .clk            = "l4ls_gclk",
+       .user           = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
 static struct omap_hwmod_ocp_if *am43xx_hwmod_ocp_ifs[] __initdata = {
        &am33xx_l4_wkup__synctimer,
        &am43xx_l4_ls__timer8,
@@ -925,6 +991,10 @@ static struct omap_hwmod_ocp_if *am43xx_hwmod_ocp_ifs[] __initdata = {
        &am43xx_l4_ls__dss_dispc,
        &am43xx_l4_ls__dss_rfbi,
        &am43xx_l4_ls__hdq1w,
+       &am43xx_l3__vpfe0,
+       &am43xx_l3__vpfe1,
+       &am43xx_l4_ls__vpfe0,
+       &am43xx_l4_ls__vpfe1,
        NULL,
 };
 
index 48df3b55057e4d346076ada24e6e7404a13a117a..d0261996db6d5e0e0f91f40e9429b4c9ea73a4c8 100644 (file)
 #define AM43XX_CM_PER_USBPHYOCP2SCP1_CLKCTRL_OFFSET    0x05C0
 #define AM43XX_CM_PER_DSS_CLKCTRL_OFFSET               0x0a20
 #define AM43XX_CM_PER_HDQ1W_CLKCTRL_OFFSET             0x04a0
-
+#define AM43XX_CM_PER_VPFE0_CLKCTRL_OFFSET             0x0068
+#define AM43XX_CM_PER_VPFE1_CLKCTRL_OFFSET             0x0070
 #endif
index cbefbd7cfdb5c02da2a9815f9662fe75879fe969..661d753df58469ecc84081ca3e2eef075de7d3cb 100644 (file)
 #define OMAP3430_VC_CMD_ONLP_SHIFT                     16
 #define OMAP3430_VC_CMD_RET_SHIFT                      8
 #define OMAP3430_VC_CMD_OFF_SHIFT                      0
+#define OMAP3430_SREN_MASK                             (1 << 4)
 #define OMAP3430_HSEN_MASK                             (1 << 3)
 #define OMAP3430_MCODE_MASK                            (0x7 << 0)
 #define OMAP3430_VALID_MASK                            (1 << 24)
index b1c7a33e00e74c36369b641a14c912110e17a23c..e794828dee553b2e943bc74b4ae819874c40455e 100644 (file)
@@ -35,6 +35,7 @@
 #define OMAP4430_GLOBAL_WARM_SW_RST_SHIFT                              1
 #define OMAP4430_GLOBAL_WUEN_MASK                                      (1 << 16)
 #define OMAP4430_HSMCODE_MASK                                          (0x7 << 0)
+#define OMAP4430_SRMODEEN_MASK                                         (1 << 4)
 #define OMAP4430_HSMODEEN_MASK                                         (1 << 3)
 #define OMAP4430_HSSCLL_SHIFT                                          24
 #define OMAP4430_ICEPICK_RST_SHIFT                                     9
index c4859c4d364692b575199f0287b4ee4751ccdee2..d0b15dbafa2efa01b1ba06531d1e163d0e70f16c 100644 (file)
@@ -87,12 +87,6 @@ u32 omap4_prminst_rmw_inst_reg_bits(u32 mask, u32 bits, u8 part, s16 inst,
        return v;
 }
 
-/*
- * Address offset (in bytes) between the reset control and the reset
- * status registers: 4 bytes on OMAP4
- */
-#define OMAP4_RST_CTRL_ST_OFFSET               4
-
 /**
  * omap4_prminst_is_hardreset_asserted - read the HW reset line state of
  * submodules contained in the hwmod module
@@ -141,11 +135,11 @@ int omap4_prminst_assert_hardreset(u8 shift, u8 part, s16 inst,
  * omap4_prminst_deassert_hardreset - deassert a submodule hardreset line and
  * wait
  * @shift: register bit shift corresponding to the reset line to deassert
- * @st_shift: status bit offset, not used for OMAP4+
+ * @st_shift: status bit offset corresponding to the reset line
  * @part: PRM partition
  * @inst: PRM instance offset
  * @rstctrl_offs: reset register offset
- * @st_offs: reset status register offset, not used for OMAP4+
+ * @rstst_offs: reset status register offset
  *
  * Some IPs like dsp, ipu or iva contain processors that require an HW
  * reset line to be asserted / deasserted in order to fully enable the
@@ -157,11 +151,11 @@ int omap4_prminst_assert_hardreset(u8 shift, u8 part, s16 inst,
  * of reset, or -EBUSY if the submodule did not exit reset promptly.
  */
 int omap4_prminst_deassert_hardreset(u8 shift, u8 st_shift, u8 part, s16 inst,
-                                    u16 rstctrl_offs, u16 st_offs)
+                                    u16 rstctrl_offs, u16 rstst_offs)
 {
        int c;
        u32 mask = 1 << shift;
-       u16 rstst_offs = rstctrl_offs + OMAP4_RST_CTRL_ST_OFFSET;
+       u32 st_mask = 1 << st_shift;
 
        /* Check the current status to avoid de-asserting the line twice */
        if (omap4_prminst_is_hardreset_asserted(shift, part, inst,
@@ -169,13 +163,13 @@ int omap4_prminst_deassert_hardreset(u8 shift, u8 st_shift, u8 part, s16 inst,
                return -EEXIST;
 
        /* Clear the reset status by writing 1 to the status bit */
-       omap4_prminst_rmw_inst_reg_bits(0xffffffff, mask, part, inst,
+       omap4_prminst_rmw_inst_reg_bits(0xffffffff, st_mask, part, inst,
                                        rstst_offs);
        /* de-assert the reset control line */
        omap4_prminst_rmw_inst_reg_bits(mask, 0, part, inst, rstctrl_offs);
        /* wait the status to be set */
-       omap_test_timeout(omap4_prminst_is_hardreset_asserted(shift, part, inst,
-                                                             rstst_offs),
+       omap_test_timeout(omap4_prminst_is_hardreset_asserted(st_shift, part,
+                                                             inst, rstst_offs),
                          MAX_MODULE_HARDRESET_WAIT, c);
 
        return (c == MAX_MODULE_HARDRESET_WAIT) ? -EBUSY : 0;
index d1dedc8195ed2569508e0d522301bdf535aefda8..eafd120b53f1bc15c82f2cc47dc8033e31ca566e 100644 (file)
@@ -203,23 +203,8 @@ save_context_wfi:
         */
        ldr     r1, kernel_flush
        blx     r1
-       /*
-        * The kernel doesn't interwork: v7_flush_dcache_all in particluar will
-        * always return in Thumb state when CONFIG_THUMB2_KERNEL is enabled.
-        * This sequence switches back to ARM.  Note that .align may insert a
-        * nop: bx pc needs to be word-aligned in order to work.
-        */
- THUMB(        .thumb          )
- THUMB(        .align          )
- THUMB(        bx      pc      )
- THUMB(        nop             )
-       .arm
-
        b       omap3_do_wfi
-
-/*
- * Local variables
- */
+ENDPROC(omap34xx_cpu_suspend)
 omap3_do_wfi_sram_addr:
        .word omap3_do_wfi_sram
 kernel_flush:
@@ -364,10 +349,7 @@ exit_nonoff_modes:
  * ===================================
  */
        ldmfd   sp!, {r4 - r11, pc}     @ restore regs and return
-
-/*
- * Local variables
- */
+ENDPROC(omap3_do_wfi)
 sdrc_power:
        .word   SDRC_POWER_V
 cm_idlest1_core:
index cef67af9e9b88aa50416c46cf4aab66769964437..cac46d852da18003a21fa3d66278e11e6cf51afc 100644 (file)
@@ -298,14 +298,11 @@ static int __init omap_dm_timer_init_one(struct omap_dm_timer *timer,
        if (IS_ERR(src))
                return PTR_ERR(src);
 
-       if (clk_get_parent(timer->fclk) != src) {
-               r = clk_set_parent(timer->fclk, src);
-               if (r < 0) {
-                       pr_warn("%s: %s cannot set source\n", __func__,
-                               oh->name);
-                       clk_put(src);
-                       return r;
-               }
+       r = clk_set_parent(timer->fclk, src);
+       if (r < 0) {
+               pr_warn("%s: %s cannot set source\n", __func__, oh->name);
+               clk_put(src);
+               return r;
        }
 
        clk_put(src);
index be9ef834fa81d56666f247dae2a598ef422ee15d..076fd20d7e5aa03adfa9d14ec15293e374ceaace 100644 (file)
@@ -316,7 +316,8 @@ static void __init omap3_vc_init_pmic_signaling(struct voltagedomain *voltdm)
         * idle. And we can also scale voltages to zero for off-idle.
         * Note that no actual voltage scaling during off-idle will
         * happen unless the board specific twl4030 PMIC scripts are
-        * loaded.
+        * loaded. See also omap_vc_i2c_init for comments regarding
+        * erratum i531.
         */
        val = voltdm->read(OMAP3_PRM_VOLTCTRL_OFFSET);
        if (!(val & OMAP3430_PRM_VOLTCTRL_SEL_OFF)) {
@@ -704,9 +705,16 @@ static void __init omap_vc_i2c_init(struct voltagedomain *voltdm)
                return;
        }
 
+       /*
+        * Note that for omap3 OMAP3430_SREN_MASK clears SREN to work around
+        * erratum i531 "Extra Power Consumed When Repeated Start Operation
+        * Mode Is Enabled on I2C Interface Dedicated for Smart Reflex (I2C4)".
+        * Otherwise I2C4 eventually leads into about 23mW extra power being
+        * consumed even during off idle using VMODE.
+        */
        i2c_high_speed = voltdm->pmic->i2c_high_speed;
        if (i2c_high_speed)
-               voltdm->rmw(vc->common->i2c_cfg_hsen_mask,
+               voltdm->rmw(vc->common->i2c_cfg_clear_mask,
                            vc->common->i2c_cfg_hsen_mask,
                            vc->common->i2c_cfg_reg);
 
index cdbdd78e755e2c60347ca66ca378d5895a9ab87e..89b83b7ff3ec5c34d4906f1504700c45c6a00abc 100644 (file)
@@ -34,6 +34,7 @@ struct voltagedomain;
  * @cmd_ret_shift: RET field shift in PRM_VC_CMD_VAL_* register
  * @cmd_off_shift: OFF field shift in PRM_VC_CMD_VAL_* register
  * @i2c_cfg_reg: I2C configuration register offset
+ * @i2c_cfg_clear_mask: high-speed mode bit clear mask in I2C config register
  * @i2c_cfg_hsen_mask: high-speed mode bit field mask in I2C config register
  * @i2c_mcode_mask: MCODE field mask for I2C config register
  *
@@ -52,6 +53,7 @@ struct omap_vc_common {
        u8 cmd_ret_shift;
        u8 cmd_off_shift;
        u8 i2c_cfg_reg;
+       u8 i2c_cfg_clear_mask;
        u8 i2c_cfg_hsen_mask;
        u8 i2c_mcode_mask;
 };
index 75bc4aa22b3a0963d0e6ed468fecc5e17257eef4..71d74c9172c15f0169203be438f6756b0a164965 100644 (file)
@@ -40,6 +40,7 @@ static struct omap_vc_common omap3_vc_common = {
        .cmd_onlp_shift  = OMAP3430_VC_CMD_ONLP_SHIFT,
        .cmd_ret_shift   = OMAP3430_VC_CMD_RET_SHIFT,
        .cmd_off_shift   = OMAP3430_VC_CMD_OFF_SHIFT,
+       .i2c_cfg_clear_mask = OMAP3430_SREN_MASK | OMAP3430_HSEN_MASK,
        .i2c_cfg_hsen_mask = OMAP3430_HSEN_MASK,
        .i2c_cfg_reg     = OMAP3_PRM_VC_I2C_CFG_OFFSET,
        .i2c_mcode_mask  = OMAP3430_MCODE_MASK,
index 085e5d6a04fd088c5422235478bb012861a96078..2abd5fa8a6972d2a435735c6419f750fbb37b567 100644 (file)
@@ -42,6 +42,7 @@ static const struct omap_vc_common omap4_vc_common = {
        .cmd_ret_shift = OMAP4430_RET_SHIFT,
        .cmd_off_shift = OMAP4430_OFF_SHIFT,
        .i2c_cfg_reg = OMAP4_PRM_VC_CFG_I2C_MODE_OFFSET,
+       .i2c_cfg_clear_mask = OMAP4430_SRMODEEN_MASK | OMAP4430_HSMODEEN_MASK,
        .i2c_cfg_hsen_mask = OMAP4430_HSMODEEN_MASK,
        .i2c_mcode_mask  = OMAP4430_HSMCODE_MASK,
 };
index 8896e71586f5e2255149db0ac4eb5cf90ece9e6b..f096836879634fb87897574a1476e26a196fb349 100644 (file)
@@ -691,4 +691,13 @@ config SHARPSL_PM_MAX1111
 config PXA310_ULPI
        bool
 
+config PXA_SYSTEMS_CPLDS
+       tristate "Motherboard cplds"
+       default ARCH_LUBBOCK || MACH_MAINSTONE
+       help
+         This driver supports the Lubbock and Mainstone multifunction chip
+         found on the pxa25x development platform system (Lubbock) and pxa27x
+         development platform system (Mainstone). This IO board supports the
+         interrupts handling, ethernet controller, flash chips, etc ...
+
 endif
index eb0bf7678a9909fdb473b791eb8f183877c73588..4087d334ecdfc6e36ace6ed23ce30fb9198ee6ef 100644 (file)
@@ -90,4 +90,5 @@ obj-$(CONFIG_MACH_RAUMFELD_CONNECTOR) += raumfeld.o
 obj-$(CONFIG_MACH_RAUMFELD_SPEAKER)    += raumfeld.o
 obj-$(CONFIG_MACH_ZIPIT2)      += z2.o
 
+obj-$(CONFIG_PXA_SYSTEMS_CPLDS)        += pxa_cplds_irqs.o
 obj-$(CONFIG_TOSA_BT)          += tosa-bt.o
index 958cd6af93842566308a33d11f1799dd78f332d9..1eecf794acd2e4ab0605f5904a6df23575322aad 100644 (file)
@@ -37,7 +37,9 @@
 #define LUB_GP                 __LUB_REG(LUBBOCK_FPGA_PHYS + 0x100)
 
 /* Board specific IRQs */
-#define LUBBOCK_IRQ(x)         (IRQ_BOARD_START + (x))
+#define LUBBOCK_NR_IRQS                IRQ_BOARD_START
+
+#define LUBBOCK_IRQ(x)         (LUBBOCK_NR_IRQS + (x))
 #define LUBBOCK_SD_IRQ         LUBBOCK_IRQ(0)
 #define LUBBOCK_SA1111_IRQ     LUBBOCK_IRQ(1)
 #define LUBBOCK_USB_IRQ                LUBBOCK_IRQ(2)  /* usb connect */
@@ -47,8 +49,7 @@
 #define LUBBOCK_USB_DISC_IRQ   LUBBOCK_IRQ(6)  /* usb disconnect */
 #define LUBBOCK_LAST_IRQ       LUBBOCK_IRQ(6)
 
-#define LUBBOCK_SA1111_IRQ_BASE        (IRQ_BOARD_START + 16)
-#define LUBBOCK_NR_IRQS                (IRQ_BOARD_START + 16 + 55)
+#define LUBBOCK_SA1111_IRQ_BASE        (LUBBOCK_NR_IRQS + 32)
 
 #ifndef __ASSEMBLY__
 extern void lubbock_set_misc_wr(unsigned int mask, unsigned int set);
index 1bfc4e822a4152439a1cd0220ee614147472edc6..e82a7d31104e02f5c21987d198fe229bad8afff5 100644 (file)
 #define MST_PCMCIA_PWR_VCC_50   0x4       /* voltage VCC = 5.0V */
 
 /* board specific IRQs */
-#define MAINSTONE_IRQ(x)       (IRQ_BOARD_START + (x))
+#define MAINSTONE_NR_IRQS      IRQ_BOARD_START
+
+#define MAINSTONE_IRQ(x)       (MAINSTONE_NR_IRQS + (x))
 #define MAINSTONE_MMC_IRQ      MAINSTONE_IRQ(0)
 #define MAINSTONE_USIM_IRQ     MAINSTONE_IRQ(1)
 #define MAINSTONE_USBC_IRQ     MAINSTONE_IRQ(2)
 #define MAINSTONE_S1_STSCHG_IRQ        MAINSTONE_IRQ(14)
 #define MAINSTONE_S1_IRQ       MAINSTONE_IRQ(15)
 
-#define MAINSTONE_NR_IRQS      (IRQ_BOARD_START + 16)
-
 #endif
index d8a1be619f21c7578bbde5fa37d00907fa80e353..4ac9ab80d24bdf147c23a4f31ab85d76cb4a82c5 100644 (file)
@@ -12,6 +12,7 @@
  *  published by the Free Software Foundation.
  */
 #include <linux/gpio.h>
+#include <linux/gpio/machine.h>
 #include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/init.h>
@@ -123,84 +124,6 @@ void lubbock_set_misc_wr(unsigned int mask, unsigned int set)
 }
 EXPORT_SYMBOL(lubbock_set_misc_wr);
 
-static unsigned long lubbock_irq_enabled;
-
-static void lubbock_mask_irq(struct irq_data *d)
-{
-       int lubbock_irq = (d->irq - LUBBOCK_IRQ(0));
-       LUB_IRQ_MASK_EN = (lubbock_irq_enabled &= ~(1 << lubbock_irq));
-}
-
-static void lubbock_unmask_irq(struct irq_data *d)
-{
-       int lubbock_irq = (d->irq - LUBBOCK_IRQ(0));
-       /* the irq can be acknowledged only if deasserted, so it's done here */
-       LUB_IRQ_SET_CLR &= ~(1 << lubbock_irq);
-       LUB_IRQ_MASK_EN = (lubbock_irq_enabled |= (1 << lubbock_irq));
-}
-
-static struct irq_chip lubbock_irq_chip = {
-       .name           = "FPGA",
-       .irq_ack        = lubbock_mask_irq,
-       .irq_mask       = lubbock_mask_irq,
-       .irq_unmask     = lubbock_unmask_irq,
-};
-
-static void lubbock_irq_handler(unsigned int irq, struct irq_desc *desc)
-{
-       unsigned long pending = LUB_IRQ_SET_CLR & lubbock_irq_enabled;
-       do {
-               /* clear our parent irq */
-               desc->irq_data.chip->irq_ack(&desc->irq_data);
-               if (likely(pending)) {
-                       irq = LUBBOCK_IRQ(0) + __ffs(pending);
-                       generic_handle_irq(irq);
-               }
-               pending = LUB_IRQ_SET_CLR & lubbock_irq_enabled;
-       } while (pending);
-}
-
-static void __init lubbock_init_irq(void)
-{
-       int irq;
-
-       pxa25x_init_irq();
-
-       /* setup extra lubbock irqs */
-       for (irq = LUBBOCK_IRQ(0); irq <= LUBBOCK_LAST_IRQ; irq++) {
-               irq_set_chip_and_handler(irq, &lubbock_irq_chip,
-                                        handle_level_irq);
-               set_irq_flags(irq, IRQF_VALID | IRQF_PROBE);
-       }
-
-       irq_set_chained_handler(PXA_GPIO_TO_IRQ(0), lubbock_irq_handler);
-       irq_set_irq_type(PXA_GPIO_TO_IRQ(0), IRQ_TYPE_EDGE_FALLING);
-}
-
-#ifdef CONFIG_PM
-
-static void lubbock_irq_resume(void)
-{
-       LUB_IRQ_MASK_EN = lubbock_irq_enabled;
-}
-
-static struct syscore_ops lubbock_irq_syscore_ops = {
-       .resume = lubbock_irq_resume,
-};
-
-static int __init lubbock_irq_device_init(void)
-{
-       if (machine_is_lubbock()) {
-               register_syscore_ops(&lubbock_irq_syscore_ops);
-               return 0;
-       }
-       return -ENODEV;
-}
-
-device_initcall(lubbock_irq_device_init);
-
-#endif
-
 static int lubbock_udc_is_connected(void)
 {
        return (LUB_MISC_RD & (1 << 9)) == 0;
@@ -383,11 +306,38 @@ static struct platform_device lubbock_flash_device[2] = {
        },
 };
 
+static struct resource lubbock_cplds_resources[] = {
+       [0] = {
+               .start  = LUBBOCK_FPGA_PHYS + 0xc0,
+               .end    = LUBBOCK_FPGA_PHYS + 0xe0 - 1,
+               .flags  = IORESOURCE_MEM,
+       },
+       [1] = {
+               .start  = PXA_GPIO_TO_IRQ(0),
+               .end    = PXA_GPIO_TO_IRQ(0),
+               .flags  = IORESOURCE_IRQ | IORESOURCE_IRQ_LOWEDGE,
+       },
+       [2] = {
+               .start  = LUBBOCK_IRQ(0),
+               .end    = LUBBOCK_IRQ(6),
+               .flags  = IORESOURCE_IRQ,
+       },
+};
+
+static struct platform_device lubbock_cplds_device = {
+       .name           = "pxa_cplds_irqs",
+       .id             = -1,
+       .resource       = &lubbock_cplds_resources[0],
+       .num_resources  = 3,
+};
+
+
 static struct platform_device *devices[] __initdata = {
        &sa1111_device,
        &smc91x_device,
        &lubbock_flash_device[0],
        &lubbock_flash_device[1],
+       &lubbock_cplds_device,
 };
 
 static struct pxafb_mode_info sharp_lm8v31_mode = {
@@ -648,7 +598,7 @@ MACHINE_START(LUBBOCK, "Intel DBPXA250 Development Platform (aka Lubbock)")
        /* Maintainer: MontaVista Software Inc. */
        .map_io         = lubbock_map_io,
        .nr_irqs        = LUBBOCK_NR_IRQS,
-       .init_irq       = lubbock_init_irq,
+       .init_irq       = pxa25x_init_irq,
        .handle_irq     = pxa25x_handle_irq,
        .init_time      = pxa_timer_init,
        .init_machine   = lubbock_init,
index 78b84c0dfc79e63f173e3d299ea397d59bcf2115..2c0658cf6be261f7a7a6ea89409b0d3f52e5f0eb 100644 (file)
@@ -13,6 +13,7 @@
  *  published by the Free Software Foundation.
  */
 #include <linux/gpio.h>
+#include <linux/gpio/machine.h>
 #include <linux/init.h>
 #include <linux/platform_device.h>
 #include <linux/syscore_ops.h>
@@ -122,92 +123,6 @@ static unsigned long mainstone_pin_config[] = {
        GPIO1_GPIO | WAKEUP_ON_EDGE_BOTH,
 };
 
-static unsigned long mainstone_irq_enabled;
-
-static void mainstone_mask_irq(struct irq_data *d)
-{
-       int mainstone_irq = (d->irq - MAINSTONE_IRQ(0));
-       MST_INTMSKENA = (mainstone_irq_enabled &= ~(1 << mainstone_irq));
-}
-
-static void mainstone_unmask_irq(struct irq_data *d)
-{
-       int mainstone_irq = (d->irq - MAINSTONE_IRQ(0));
-       /* the irq can be acknowledged only if deasserted, so it's done here */
-       MST_INTSETCLR &= ~(1 << mainstone_irq);
-       MST_INTMSKENA = (mainstone_irq_enabled |= (1 << mainstone_irq));
-}
-
-static struct irq_chip mainstone_irq_chip = {
-       .name           = "FPGA",
-       .irq_ack        = mainstone_mask_irq,
-       .irq_mask       = mainstone_mask_irq,
-       .irq_unmask     = mainstone_unmask_irq,
-};
-
-static void mainstone_irq_handler(unsigned int irq, struct irq_desc *desc)
-{
-       unsigned long pending = MST_INTSETCLR & mainstone_irq_enabled;
-       do {
-               /* clear useless edge notification */
-               desc->irq_data.chip->irq_ack(&desc->irq_data);
-               if (likely(pending)) {
-                       irq = MAINSTONE_IRQ(0) + __ffs(pending);
-                       generic_handle_irq(irq);
-               }
-               pending = MST_INTSETCLR & mainstone_irq_enabled;
-       } while (pending);
-}
-
-static void __init mainstone_init_irq(void)
-{
-       int irq;
-
-       pxa27x_init_irq();
-
-       /* setup extra Mainstone irqs */
-       for(irq = MAINSTONE_IRQ(0); irq <= MAINSTONE_IRQ(15); irq++) {
-               irq_set_chip_and_handler(irq, &mainstone_irq_chip,
-                                        handle_level_irq);
-               if (irq == MAINSTONE_IRQ(10) || irq == MAINSTONE_IRQ(14))
-                       set_irq_flags(irq, IRQF_VALID | IRQF_PROBE | IRQF_NOAUTOEN);
-               else
-                       set_irq_flags(irq, IRQF_VALID | IRQF_PROBE);
-       }
-       set_irq_flags(MAINSTONE_IRQ(8), 0);
-       set_irq_flags(MAINSTONE_IRQ(12), 0);
-
-       MST_INTMSKENA = 0;
-       MST_INTSETCLR = 0;
-
-       irq_set_chained_handler(PXA_GPIO_TO_IRQ(0), mainstone_irq_handler);
-       irq_set_irq_type(PXA_GPIO_TO_IRQ(0), IRQ_TYPE_EDGE_FALLING);
-}
-
-#ifdef CONFIG_PM
-
-static void mainstone_irq_resume(void)
-{
-       MST_INTMSKENA = mainstone_irq_enabled;
-}
-
-static struct syscore_ops mainstone_irq_syscore_ops = {
-       .resume = mainstone_irq_resume,
-};
-
-static int __init mainstone_irq_device_init(void)
-{
-       if (machine_is_mainstone())
-               register_syscore_ops(&mainstone_irq_syscore_ops);
-
-       return 0;
-}
-
-device_initcall(mainstone_irq_device_init);
-
-#endif
-
-
 static struct resource smc91x_resources[] = {
        [0] = {
                .start  = (MST_ETH_PHYS + 0x300),
@@ -487,11 +402,37 @@ static struct platform_device mst_gpio_keys_device = {
        },
 };
 
+static struct resource mst_cplds_resources[] = {
+       [0] = {
+               .start  = MST_FPGA_PHYS + 0xc0,
+               .end    = MST_FPGA_PHYS + 0xe0 - 1,
+               .flags  = IORESOURCE_MEM,
+       },
+       [1] = {
+               .start  = PXA_GPIO_TO_IRQ(0),
+               .end    = PXA_GPIO_TO_IRQ(0),
+               .flags  = IORESOURCE_IRQ | IORESOURCE_IRQ_LOWEDGE,
+       },
+       [2] = {
+               .start  = MAINSTONE_IRQ(0),
+               .end    = MAINSTONE_IRQ(15),
+               .flags  = IORESOURCE_IRQ,
+       },
+};
+
+static struct platform_device mst_cplds_device = {
+       .name           = "pxa_cplds_irqs",
+       .id             = -1,
+       .resource       = &mst_cplds_resources[0],
+       .num_resources  = 3,
+};
+
 static struct platform_device *platform_devices[] __initdata = {
        &smc91x_device,
        &mst_flash_device[0],
        &mst_flash_device[1],
        &mst_gpio_keys_device,
+       &mst_cplds_device,
 };
 
 static struct pxaohci_platform_data mainstone_ohci_platform_data = {
@@ -718,7 +659,7 @@ MACHINE_START(MAINSTONE, "Intel HCDDBBVA0 Development Platform (aka Mainstone)")
        .atag_offset    = 0x100,        /* BLOB boot parameter setting */
        .map_io         = mainstone_map_io,
        .nr_irqs        = MAINSTONE_NR_IRQS,
-       .init_irq       = mainstone_init_irq,
+       .init_irq       = pxa27x_init_irq,
        .handle_irq     = pxa27x_handle_irq,
        .init_time      = pxa_timer_init,
        .init_machine   = mainstone_init,
diff --git a/arch/arm/mach-pxa/pxa_cplds_irqs.c b/arch/arm/mach-pxa/pxa_cplds_irqs.c
new file mode 100644 (file)
index 0000000..2385052
--- /dev/null
@@ -0,0 +1,200 @@
+/*
+ * Intel Reference Systems cplds
+ *
+ * Copyright (C) 2014 Robert Jarzmik
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * Cplds motherboard driver, supporting lubbock and mainstone SoC board.
+ */
+
+#include <linux/bitops.h>
+#include <linux/gpio.h>
+#include <linux/gpio/consumer.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/irq.h>
+#include <linux/irqdomain.h>
+#include <linux/mfd/core.h>
+#include <linux/module.h>
+#include <linux/of_platform.h>
+
+#define FPGA_IRQ_MASK_EN 0x0
+#define FPGA_IRQ_SET_CLR 0x10
+
+#define CPLDS_NB_IRQ   32
+
+struct cplds {
+       void __iomem *base;
+       int irq;
+       unsigned int irq_mask;
+       struct gpio_desc *gpio0;
+       struct irq_domain *irqdomain;
+};
+
+static irqreturn_t cplds_irq_handler(int in_irq, void *d)
+{
+       struct cplds *fpga = d;
+       unsigned long pending;
+       unsigned int bit;
+
+       pending = readl(fpga->base + FPGA_IRQ_SET_CLR) & fpga->irq_mask;
+       for_each_set_bit(bit, &pending, CPLDS_NB_IRQ)
+               generic_handle_irq(irq_find_mapping(fpga->irqdomain, bit));
+
+       return IRQ_HANDLED;
+}
+
+static void cplds_irq_mask_ack(struct irq_data *d)
+{
+       struct cplds *fpga = irq_data_get_irq_chip_data(d);
+       unsigned int cplds_irq = irqd_to_hwirq(d);
+       unsigned int set, bit = BIT(cplds_irq);
+
+       fpga->irq_mask &= ~bit;
+       writel(fpga->irq_mask, fpga->base + FPGA_IRQ_MASK_EN);
+       set = readl(fpga->base + FPGA_IRQ_SET_CLR);
+       writel(set & ~bit, fpga->base + FPGA_IRQ_SET_CLR);
+}
+
+static void cplds_irq_unmask(struct irq_data *d)
+{
+       struct cplds *fpga = irq_data_get_irq_chip_data(d);
+       unsigned int cplds_irq = irqd_to_hwirq(d);
+       unsigned int bit = BIT(cplds_irq);
+
+       fpga->irq_mask |= bit;
+       writel(fpga->irq_mask, fpga->base + FPGA_IRQ_MASK_EN);
+}
+
+static struct irq_chip cplds_irq_chip = {
+       .name           = "pxa_cplds",
+       .irq_mask_ack   = cplds_irq_mask_ack,
+       .irq_unmask     = cplds_irq_unmask,
+       .flags          = IRQCHIP_MASK_ON_SUSPEND | IRQCHIP_SKIP_SET_WAKE,
+};
+
+static int cplds_irq_domain_map(struct irq_domain *d, unsigned int irq,
+                                  irq_hw_number_t hwirq)
+{
+       struct cplds *fpga = d->host_data;
+
+       irq_set_chip_and_handler(irq, &cplds_irq_chip, handle_level_irq);
+       irq_set_chip_data(irq, fpga);
+
+       return 0;
+}
+
+static const struct irq_domain_ops cplds_irq_domain_ops = {
+       .xlate = irq_domain_xlate_twocell,
+       .map = cplds_irq_domain_map,
+};
+
+static int cplds_resume(struct platform_device *pdev)
+{
+       struct cplds *fpga = platform_get_drvdata(pdev);
+
+       writel(fpga->irq_mask, fpga->base + FPGA_IRQ_MASK_EN);
+
+       return 0;
+}
+
+static int cplds_probe(struct platform_device *pdev)
+{
+       struct resource *res;
+       struct cplds *fpga;
+       int ret;
+       int base_irq;
+       unsigned long irqflags = 0;
+
+       fpga = devm_kzalloc(&pdev->dev, sizeof(*fpga), GFP_KERNEL);
+       if (!fpga)
+               return -ENOMEM;
+
+       res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+       if (res) {
+               fpga->irq = (unsigned int)res->start;
+               irqflags = res->flags;
+       }
+       if (!fpga->irq)
+               return -ENODEV;
+
+       base_irq = platform_get_irq(pdev, 1);
+       if (base_irq < 0)
+               base_irq = 0;
+
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       fpga->base = devm_ioremap_resource(&pdev->dev, res);
+       if (IS_ERR(fpga->base))
+               return PTR_ERR(fpga->base);
+
+       platform_set_drvdata(pdev, fpga);
+
+       writel(fpga->irq_mask, fpga->base + FPGA_IRQ_MASK_EN);
+       writel(0, fpga->base + FPGA_IRQ_SET_CLR);
+
+       ret = devm_request_irq(&pdev->dev, fpga->irq, cplds_irq_handler,
+                              irqflags, dev_name(&pdev->dev), fpga);
+       if (ret == -ENOSYS)
+               return -EPROBE_DEFER;
+
+       if (ret) {
+               dev_err(&pdev->dev, "couldn't request main irq%d: %d\n",
+                       fpga->irq, ret);
+               return ret;
+       }
+
+       irq_set_irq_wake(fpga->irq, 1);
+       fpga->irqdomain = irq_domain_add_linear(pdev->dev.of_node,
+                                              CPLDS_NB_IRQ,
+                                              &cplds_irq_domain_ops, fpga);
+       if (!fpga->irqdomain)
+               return -ENODEV;
+
+       if (base_irq) {
+               ret = irq_create_strict_mappings(fpga->irqdomain, base_irq, 0,
+                                                CPLDS_NB_IRQ);
+               if (ret) {
+                       dev_err(&pdev->dev, "couldn't create the irq mapping %d..%d\n",
+                               base_irq, base_irq + CPLDS_NB_IRQ);
+                       return ret;
+               }
+       }
+
+       return 0;
+}
+
+static int cplds_remove(struct platform_device *pdev)
+{
+       struct cplds *fpga = platform_get_drvdata(pdev);
+
+       irq_set_chip_and_handler(fpga->irq, NULL, NULL);
+
+       return 0;
+}
+
+static const struct of_device_id cplds_id_table[] = {
+       { .compatible = "intel,lubbock-cplds-irqs", },
+       { .compatible = "intel,mainstone-cplds-irqs", },
+       { }
+};
+MODULE_DEVICE_TABLE(of, cplds_id_table);
+
+static struct platform_driver cplds_driver = {
+       .driver         = {
+               .name   = "pxa_cplds_irqs",
+               .of_match_table = of_match_ptr(cplds_id_table),
+       },
+       .probe          = cplds_probe,
+       .remove         = cplds_remove,
+       .resume         = cplds_resume,
+};
+
+module_platform_driver(cplds_driver);
+
+MODULE_DESCRIPTION("PXA Cplds interrupts driver");
+MODULE_AUTHOR("Robert Jarzmik <robert.jarzmik@free.fr>");
+MODULE_LICENSE("GPL");
index b07d8860207323e302a86234f9bf7cbbeac827a4..b0dcbe28f78cbd9fd73b399655b3b08b59938c8b 100644 (file)
@@ -83,6 +83,13 @@ static void rk3288_slp_mode_set(int level)
                     SGRF_PCLK_WDT_GATE | SGRF_FAST_BOOT_EN
                     | SGRF_PCLK_WDT_GATE_WRITE | SGRF_FAST_BOOT_EN_WRITE);
 
+       /*
+        * The dapswjdp can not auto reset before resume, that cause it may
+        * access some illegal address during resume. Let's disable it before
+        * suspend, and the MASKROM will enable it back.
+        */
+       regmap_write(sgrf_regmap, RK3288_SGRF_CPU_CON0, SGRF_DAPDEVICEEN_WRITE);
+
        /* booting address of resuming system is from this register value */
        regmap_write(sgrf_regmap, RK3288_SGRF_FAST_BOOT_ADDR,
                     rk3288_bootram_phy);
index 03ff31d8282d07bd4fcd54dcde67b6ee7d7069ef..3e8d39c0c3d5f09c78d38a830f56f5bfe1990c26 100644 (file)
@@ -55,6 +55,10 @@ static inline void rockchip_suspend_init(void)
 #define SGRF_FAST_BOOT_EN              BIT(8)
 #define SGRF_FAST_BOOT_EN_WRITE                BIT(24)
 
+#define RK3288_SGRF_CPU_CON0           (0x40)
+#define SGRF_DAPDEVICEEN               BIT(0)
+#define SGRF_DAPDEVICEEN_WRITE         BIT(16)
+
 #define RK3288_CRU_MODE_CON            0x50
 #define RK3288_CRU_SEL0_CON            0x60
 #define RK3288_CRU_SEL1_CON            0x64
index d360ec044b66e0b990c03f2569da3e07dbffc59d..b6cf3b449428960d28590f5cdad6e331d2239080 100644 (file)
 #include "pm.h"
 
 #define RK3288_GRF_SOC_CON0 0x244
+#define RK3288_TIMER6_7_PHYS 0xff810000
 
 static void __init rockchip_timer_init(void)
 {
        if (of_machine_is_compatible("rockchip,rk3288")) {
                struct regmap *grf;
+               void __iomem *reg_base;
+
+               /*
+                * Most/all uboot versions for rk3288 don't enable timer7
+                * which is needed for the architected timer to work.
+                * So make sure it is running during early boot.
+                */
+               reg_base = ioremap(RK3288_TIMER6_7_PHYS, SZ_16K);
+               if (reg_base) {
+                       writel(0, reg_base + 0x30);
+                       writel(0xffffffff, reg_base + 0x20);
+                       writel(0xffffffff, reg_base + 0x24);
+                       writel(1, reg_base + 0x30);
+                       dsb();
+                       iounmap(reg_base);
+               } else {
+                       pr_err("rockchip: could not map timer7 registers\n");
+               }
 
                /*
                 * Disable auto jtag/sdmmc switching that causes issues
index 09c5fe3d30c2c220b6f17433111cff4898d0bd7c..7e7583ddd6076d7cc88fd7c8f9a53c71662263a2 100644 (file)
@@ -1878,7 +1878,7 @@ struct dma_map_ops iommu_coherent_ops = {
  * arm_iommu_attach_device function.
  */
 struct dma_iommu_mapping *
-arm_iommu_create_mapping(struct bus_type *bus, dma_addr_t base, size_t size)
+arm_iommu_create_mapping(struct bus_type *bus, dma_addr_t base, u64 size)
 {
        unsigned int bits = size >> PAGE_SHIFT;
        unsigned int bitmap_size = BITS_TO_LONGS(bits) * sizeof(long);
@@ -1886,6 +1886,10 @@ arm_iommu_create_mapping(struct bus_type *bus, dma_addr_t base, size_t size)
        int extensions = 1;
        int err = -ENOMEM;
 
+       /* currently only 32-bit DMA address space is supported */
+       if (size > DMA_BIT_MASK(32) + 1)
+               return ERR_PTR(-ERANGE);
+
        if (!bitmap_size)
                return ERR_PTR(-EINVAL);
 
@@ -2057,13 +2061,6 @@ static bool arm_setup_iommu_dma_ops(struct device *dev, u64 dma_base, u64 size,
        if (!iommu)
                return false;
 
-       /*
-        * currently arm_iommu_create_mapping() takes a max of size_t
-        * for size param. So check this limit for now.
-        */
-       if (size > SIZE_MAX)
-               return false;
-
        mapping = arm_iommu_create_mapping(dev->bus, dma_base, size);
        if (IS_ERR(mapping)) {
                pr_warn("Failed to create %llu-byte IOMMU mapping for device %s\n",
index 4e6ef896c6195db73f770957e9df619a0be05e06..7186382672b5eec605cba5ff491a7019914d304b 100644 (file)
@@ -1112,22 +1112,22 @@ void __init sanity_check_meminfo(void)
                        }
 
                        /*
-                        * Find the first non-section-aligned page, and point
+                        * Find the first non-pmd-aligned page, and point
                         * memblock_limit at it. This relies on rounding the
-                        * limit down to be section-aligned, which happens at
-                        * the end of this function.
+                        * limit down to be pmd-aligned, which happens at the
+                        * end of this function.
                         *
                         * With this algorithm, the start or end of almost any
-                        * bank can be non-section-aligned. The only exception
-                        * is that the start of the bank 0 must be section-
+                        * bank can be non-pmd-aligned. The only exception is
+                        * that the start of the bank 0 must be section-
                         * aligned, since otherwise memory would need to be
                         * allocated when mapping the start of bank 0, which
                         * occurs before any free memory is mapped.
                         */
                        if (!memblock_limit) {
-                               if (!IS_ALIGNED(block_start, SECTION_SIZE))
+                               if (!IS_ALIGNED(block_start, PMD_SIZE))
                                        memblock_limit = block_start;
-                               else if (!IS_ALIGNED(block_end, SECTION_SIZE))
+                               else if (!IS_ALIGNED(block_end, PMD_SIZE))
                                        memblock_limit = arm_lowmem_limit;
                        }
 
@@ -1137,12 +1137,12 @@ void __init sanity_check_meminfo(void)
        high_memory = __va(arm_lowmem_limit - 1) + 1;
 
        /*
-        * Round the memblock limit down to a section size.  This
+        * Round the memblock limit down to a pmd size.  This
         * helps to ensure that we will allocate memory from the
-        * last full section, which should be mapped.
+        * last full pmd, which should be mapped.
         */
        if (memblock_limit)
-               memblock_limit = round_down(memblock_limit, SECTION_SIZE);
+               memblock_limit = round_down(memblock_limit, PMD_SIZE);
        if (!memblock_limit)
                memblock_limit = arm_lowmem_limit;
 
index aa0519eed6986c9af3b9b560663ea6e7b04f7c1a..774ef1323554bd54ad74a5caa14155921906560d 100644 (file)
@@ -22,8 +22,6 @@
  *
  * These are the low level assembler for performing cache and TLB
  * functions on the arm1020.
- *
- *  CONFIG_CPU_ARM1020_CPU_IDLE -> nohlt
  */
 #include <linux/linkage.h>
 #include <linux/init.h>
index bff4c7f70fd6a992d0587b99f1303a08776988b7..ae3c27b71594d7d57cb40965efe9aecb07c82b9f 100644 (file)
@@ -22,8 +22,6 @@
  *
  * These are the low level assembler for performing cache and TLB
  * functions on the arm1020e.
- *
- *  CONFIG_CPU_ARM1020_CPU_IDLE -> nohlt
  */
 #include <linux/linkage.h>
 #include <linux/init.h>
index ede8c54ab4aa751d9619b6fec3248cac4255ee40..32a47cc19076c1eaef60ff4a523c89da81094455 100644 (file)
@@ -441,9 +441,6 @@ ENTRY(cpu_arm925_set_pte_ext)
        .type   __arm925_setup, #function
 __arm925_setup:
        mov     r0, #0
-#if defined(CONFIG_CPU_ICACHE_STREAMING_DISABLE)
-        orr     r0,r0,#1 << 7
-#endif
 
        /* Transparent on, D-cache clean & flush mode. See  NOTE2 above */
         orr     r0,r0,#1 << 1                  @ transparent mode on
index e494d6d6acbe8f38f316a586f474d7b7cfc3c0c0..92e08bf37aad940b8f7da40644ef88bcbf56aa31 100644 (file)
@@ -602,7 +602,6 @@ __\name\()_proc_info:
                PMD_SECT_AP_WRITE | \
                PMD_SECT_AP_READ
        initfn  __feroceon_setup, __\name\()_proc_info
-       .long __feroceon_setup
        .long   cpu_arch_name
        .long   cpu_elf_name
        .long   HWCAP_SWP|HWCAP_HALF|HWCAP_THUMB|HWCAP_FAST_MULT|HWCAP_EDSP
index e1268f90502682c75dfd7a98e6ed15272ea8d512..e0e23582c8b4e4687209a219c0d2bbc86b88bbd9 100644 (file)
@@ -54,6 +54,7 @@
 #define SEEN_DATA              (1 << (BPF_MEMWORDS + 3))
 
 #define FLAG_NEED_X_RESET      (1 << 0)
+#define FLAG_IMM_OVERFLOW      (1 << 1)
 
 struct jit_ctx {
        const struct bpf_prog *skf;
@@ -293,6 +294,15 @@ static u16 imm_offset(u32 k, struct jit_ctx *ctx)
        /* PC in ARM mode == address of the instruction + 8 */
        imm = offset - (8 + ctx->idx * 4);
 
+       if (imm & ~0xfff) {
+               /*
+                * literal pool is too far, signal it into flags. we
+                * can only detect it on the second pass unfortunately.
+                */
+               ctx->flags |= FLAG_IMM_OVERFLOW;
+               return 0;
+       }
+
        return imm;
 }
 
@@ -449,10 +459,21 @@ static inline void emit_udiv(u8 rd, u8 rm, u8 rn, struct jit_ctx *ctx)
                return;
        }
 #endif
-       if (rm != ARM_R0)
-               emit(ARM_MOV_R(ARM_R0, rm), ctx);
+
+       /*
+        * For BPF_ALU | BPF_DIV | BPF_K instructions, rm is ARM_R4
+        * (r_A) and rn is ARM_R0 (r_scratch) so load rn first into
+        * ARM_R1 to avoid accidentally overwriting ARM_R0 with rm
+        * before using it as a source for ARM_R1.
+        *
+        * For BPF_ALU | BPF_DIV | BPF_X rm is ARM_R4 (r_A) and rn is
+        * ARM_R5 (r_X) so there is no particular register overlap
+        * issues.
+        */
        if (rn != ARM_R1)
                emit(ARM_MOV_R(ARM_R1, rn), ctx);
+       if (rm != ARM_R0)
+               emit(ARM_MOV_R(ARM_R0, rm), ctx);
 
        ctx->seen |= SEEN_CALL;
        emit_mov_i(ARM_R3, (u32)jit_udiv, ctx);
@@ -855,6 +876,14 @@ b_epilogue:
                default:
                        return -1;
                }
+
+               if (ctx->flags & FLAG_IMM_OVERFLOW)
+                       /*
+                        * this instruction generated an overflow when
+                        * trying to access the literal pool, so
+                        * delegate this filter to the kernel interpreter.
+                        */
+                       return -1;
        }
 
        /* compute offsets only during the first pass */
@@ -917,7 +946,14 @@ void bpf_jit_compile(struct bpf_prog *fp)
        ctx.idx = 0;
 
        build_prologue(&ctx);
-       build_body(&ctx);
+       if (build_body(&ctx) < 0) {
+#if __LINUX_ARM_ARCH__ < 7
+               if (ctx.imm_count)
+                       kfree(ctx.imms);
+#endif
+               bpf_jit_binary_free(header);
+               goto out;
+       }
        build_epilogue(&ctx);
 
        flush_icache_range((u32)ctx.target, (u32)(ctx.target + ctx.idx));
index 224081ccc92fa6516cd67a95e4a5871aee6420a0..7d0f07020c809598c8a5ea292093d3676c083548 100644 (file)
@@ -272,6 +272,7 @@ void xen_arch_pre_suspend(void) { }
 void xen_arch_post_suspend(int suspend_cancelled) { }
 void xen_timer_resume(void) { }
 void xen_arch_resume(void) { }
+void xen_arch_suspend(void) { }
 
 
 /* In the hypervisor.S file. */
index 793551d15f1dac1a1241b23971a788b4c36702b6..498325074a06fa911a5cfa9f37137c7936f8b9c4 100644 (file)
@@ -4,6 +4,7 @@
 #include <linux/gfp.h>
 #include <linux/highmem.h>
 #include <linux/export.h>
+#include <linux/memblock.h>
 #include <linux/of_address.h>
 #include <linux/slab.h>
 #include <linux/types.h>
 #include <asm/xen/hypercall.h>
 #include <asm/xen/interface.h>
 
+unsigned long xen_get_swiotlb_free_pages(unsigned int order)
+{
+       struct memblock_region *reg;
+       gfp_t flags = __GFP_NOWARN;
+
+       for_each_memblock(memory, reg) {
+               if (reg->base < (phys_addr_t)0xffffffff) {
+                       flags |= __GFP_DMA;
+                       break;
+               }
+       }
+       return __get_free_pages(flags, order);
+}
+
 enum dma_cache_op {
        DMA_UNMAP,
        DMA_MAP,
index 4269dba63cf165d3590c16700896dc44726a898f..7796af4b1d6f65f6352ed40cd6dfcaf580cfd63d 100644 (file)
@@ -31,6 +31,7 @@ config ARM64
        select GENERIC_EARLY_IOREMAP
        select GENERIC_IRQ_PROBE
        select GENERIC_IRQ_SHOW
+       select GENERIC_IRQ_SHOW_LEVEL
        select GENERIC_PCI_IOMAP
        select GENERIC_SCHED_CLOCK
        select GENERIC_SMP_IDLE_THREAD
index c138b95a8356836929c0f2781c80933da4727953..351c95bda89e5215a9ca525171509bfb4f831bee 100644 (file)
                        clock-output-names = "juno_mb:clk25mhz";
                };
 
+               v2m_refclk1mhz: refclk1mhz {
+                       compatible = "fixed-clock";
+                       #clock-cells = <0>;
+                       clock-frequency = <1000000>;
+                       clock-output-names = "juno_mb:refclk1mhz";
+               };
+
+               v2m_refclk32khz: refclk32khz {
+                       compatible = "fixed-clock";
+                       #clock-cells = <0>;
+                       clock-frequency = <32768>;
+                       clock-output-names = "juno_mb:refclk32khz";
+               };
+
                motherboard {
                        compatible = "arm,vexpress,v2p-p1", "simple-bus";
                        #address-cells = <2>;  /* SMB chipselect number and offset */
                                #size-cells = <1>;
                                ranges = <0 3 0 0x200000>;
 
+                               v2m_sysctl: sysctl@020000 {
+                                       compatible = "arm,sp810", "arm,primecell";
+                                       reg = <0x020000 0x1000>;
+                                       clocks = <&v2m_refclk32khz>, <&v2m_refclk1mhz>, <&mb_clk24mhz>;
+                                       clock-names = "refclk", "timclk", "apb_pclk";
+                                       #clock-cells = <1>;
+                                       clock-output-names = "timerclken0", "timerclken1", "timerclken2", "timerclken3";
+                               };
+
                                mmci@050000 {
                                        compatible = "arm,pl180", "arm,primecell";
                                        reg = <0x050000 0x1000>;
                                        compatible = "arm,sp804", "arm,primecell";
                                        reg = <0x110000 0x10000>;
                                        interrupts = <9>;
-                                       clocks = <&mb_clk24mhz>, <&soc_smc50mhz>;
-                                       clock-names = "timclken1", "apb_pclk";
+                                       clocks = <&v2m_sysctl 0>, <&v2m_sysctl 1>, <&mb_clk24mhz>;
+                                       clock-names = "timclken1", "timclken2", "apb_pclk";
                                };
 
                                v2m_timer23: timer@120000 {
                                        compatible = "arm,sp804", "arm,primecell";
                                        reg = <0x120000 0x10000>;
                                        interrupts = <9>;
-                                       clocks = <&mb_clk24mhz>, <&soc_smc50mhz>;
-                                       clock-names = "timclken1", "apb_pclk";
+                                       clocks = <&v2m_sysctl 2>, <&v2m_sysctl 3>, <&mb_clk24mhz>;
+                                       clock-names = "timclken1", "timclken2", "apb_pclk";
                                };
 
                                rtc@170000 {
index 43d54017b779d4e211462b8bebe2604025bb08ea..d0ab012fa379eb97c6e43ebad83ee18185d2b598 100644 (file)
@@ -16,7 +16,8 @@
 #include "mt8173.dtsi"
 
 / {
-       model = "mediatek,mt8173-evb";
+       model = "MediaTek MT8173 evaluation board";
+       compatible = "mediatek,mt8173-evb", "mediatek,mt8173";
 
        aliases {
                serial0 = &uart0;
index 9499199924aebd4d6b27ced325d69918b641ddf3..6a37c3c6b11d39acc0db9d142652abcb18d21b9c 100644 (file)
@@ -147,13 +147,21 @@ static int chksum_final(struct shash_desc *desc, u8 *out)
 {
        struct chksum_desc_ctx *ctx = shash_desc_ctx(desc);
 
+       put_unaligned_le32(ctx->crc, out);
+       return 0;
+}
+
+static int chksumc_final(struct shash_desc *desc, u8 *out)
+{
+       struct chksum_desc_ctx *ctx = shash_desc_ctx(desc);
+
        put_unaligned_le32(~ctx->crc, out);
        return 0;
 }
 
 static int __chksum_finup(u32 crc, const u8 *data, unsigned int len, u8 *out)
 {
-       put_unaligned_le32(~crc32_arm64_le_hw(crc, data, len), out);
+       put_unaligned_le32(crc32_arm64_le_hw(crc, data, len), out);
        return 0;
 }
 
@@ -199,6 +207,14 @@ static int crc32_cra_init(struct crypto_tfm *tfm)
 {
        struct chksum_ctx *mctx = crypto_tfm_ctx(tfm);
 
+       mctx->key = 0;
+       return 0;
+}
+
+static int crc32c_cra_init(struct crypto_tfm *tfm)
+{
+       struct chksum_ctx *mctx = crypto_tfm_ctx(tfm);
+
        mctx->key = ~0;
        return 0;
 }
@@ -229,7 +245,7 @@ static struct shash_alg crc32c_alg = {
        .setkey                 =       chksum_setkey,
        .init                   =       chksum_init,
        .update                 =       chksumc_update,
-       .final                  =       chksum_final,
+       .final                  =       chksumc_final,
        .finup                  =       chksumc_finup,
        .digest                 =       chksumc_digest,
        .descsize               =       sizeof(struct chksum_desc_ctx),
@@ -241,7 +257,7 @@ static struct shash_alg crc32c_alg = {
                .cra_alignmask          =       0,
                .cra_ctxsize            =       sizeof(struct chksum_ctx),
                .cra_module             =       THIS_MODULE,
-               .cra_init               =       crc32_cra_init,
+               .cra_init               =       crc32c_cra_init,
        }
 };
 
index 114e7cc5de8c09b4eb75f6b11294e9c689d1ebbc..aefda9868627bde843227d1074e7cc9b17004298 100644 (file)
@@ -74,6 +74,9 @@ static int sha1_ce_finup(struct shash_desc *desc, const u8 *data,
 
 static int sha1_ce_final(struct shash_desc *desc, u8 *out)
 {
+       struct sha1_ce_state *sctx = shash_desc_ctx(desc);
+
+       sctx->finalize = 0;
        kernel_neon_begin_partial(16);
        sha1_base_do_finalize(desc, (sha1_block_fn *)sha1_ce_transform);
        kernel_neon_end();
index 1340e44c048beab91279b6dd317f10590a6f06b9..7cd587564a4176e902f12c7c7043b714caab48ea 100644 (file)
@@ -75,6 +75,9 @@ static int sha256_ce_finup(struct shash_desc *desc, const u8 *data,
 
 static int sha256_ce_final(struct shash_desc *desc, u8 *out)
 {
+       struct sha256_ce_state *sctx = shash_desc_ctx(desc);
+
+       sctx->finalize = 0;
        kernel_neon_begin_partial(28);
        sha256_base_do_finalize(desc, (sha256_block_fn *)sha2_ce_transform);
        kernel_neon_end();
index a5abb0062d6e943d67ca4ff5479e887194482367..71f19c4dc0dee8c8a74bbdea252f73432e0b1aa5 100644 (file)
@@ -65,6 +65,14 @@ do {                                                                 \
 do {                                                                   \
        compiletime_assert_atomic_type(*p);                             \
        switch (sizeof(*p)) {                                           \
+       case 1:                                                         \
+               asm volatile ("stlrb %w1, %0"                           \
+                               : "=Q" (*p) : "r" (v) : "memory");      \
+               break;                                                  \
+       case 2:                                                         \
+               asm volatile ("stlrh %w1, %0"                           \
+                               : "=Q" (*p) : "r" (v) : "memory");      \
+               break;                                                  \
        case 4:                                                         \
                asm volatile ("stlr %w1, %0"                            \
                                : "=Q" (*p) : "r" (v) : "memory");      \
@@ -81,6 +89,14 @@ do {                                                                 \
        typeof(*p) ___p1;                                               \
        compiletime_assert_atomic_type(*p);                             \
        switch (sizeof(*p)) {                                           \
+       case 1:                                                         \
+               asm volatile ("ldarb %w0, %1"                           \
+                       : "=r" (___p1) : "Q" (*p) : "memory");          \
+               break;                                                  \
+       case 2:                                                         \
+               asm volatile ("ldarh %w0, %1"                           \
+                       : "=r" (___p1) : "Q" (*p) : "memory");          \
+               break;                                                  \
        case 4:                                                         \
                asm volatile ("ldar %w0, %1"                            \
                        : "=r" (___p1) : "Q" (*p) : "memory");          \
index 21033bba939051b7db11e415983d7b10fcc485ca..28f8365edc4c43edd00043f38d89f8ae8be6476f 100644 (file)
@@ -24,7 +24,6 @@
 #include <asm/cacheflush.h>
 #include <asm/alternative.h>
 #include <asm/cpufeature.h>
-#include <asm/insn.h>
 #include <linux/stop_machine.h>
 
 extern struct alt_instr __alt_instructions[], __alt_instructions_end[];
@@ -34,48 +33,6 @@ struct alt_region {
        struct alt_instr *end;
 };
 
-/*
- * Decode the imm field of a b/bl instruction, and return the byte
- * offset as a signed value (so it can be used when computing a new
- * branch target).
- */
-static s32 get_branch_offset(u32 insn)
-{
-       s32 imm = aarch64_insn_decode_immediate(AARCH64_INSN_IMM_26, insn);
-
-       /* sign-extend the immediate before turning it into a byte offset */
-       return (imm << 6) >> 4;
-}
-
-static u32 get_alt_insn(u8 *insnptr, u8 *altinsnptr)
-{
-       u32 insn;
-
-       aarch64_insn_read(altinsnptr, &insn);
-
-       /* Stop the world on instructions we don't support... */
-       BUG_ON(aarch64_insn_is_cbz(insn));
-       BUG_ON(aarch64_insn_is_cbnz(insn));
-       BUG_ON(aarch64_insn_is_bcond(insn));
-       /* ... and there is probably more. */
-
-       if (aarch64_insn_is_b(insn) || aarch64_insn_is_bl(insn)) {
-               enum aarch64_insn_branch_type type;
-               unsigned long target;
-
-               if (aarch64_insn_is_b(insn))
-                       type = AARCH64_INSN_BRANCH_NOLINK;
-               else
-                       type = AARCH64_INSN_BRANCH_LINK;
-
-               target = (unsigned long)altinsnptr + get_branch_offset(insn);
-               insn = aarch64_insn_gen_branch_imm((unsigned long)insnptr,
-                                                  target, type);
-       }
-
-       return insn;
-}
-
 static int __apply_alternatives(void *alt_region)
 {
        struct alt_instr *alt;
@@ -83,9 +40,6 @@ static int __apply_alternatives(void *alt_region)
        u8 *origptr, *replptr;
 
        for (alt = region->begin; alt < region->end; alt++) {
-               u32 insn;
-               int i;
-
                if (!cpus_have_cap(alt->cpufeature))
                        continue;
 
@@ -95,12 +49,7 @@ static int __apply_alternatives(void *alt_region)
 
                origptr = (u8 *)&alt->orig_offset + alt->orig_offset;
                replptr = (u8 *)&alt->alt_offset + alt->alt_offset;
-
-               for (i = 0; i < alt->alt_len; i += sizeof(insn)) {
-                       insn = get_alt_insn(origptr + i, replptr + i);
-                       aarch64_insn_write(origptr + i, insn);
-               }
-
+               memcpy(origptr, replptr, alt->alt_len);
                flush_icache_range((uintptr_t)origptr,
                                   (uintptr_t)(origptr + alt->alt_len));
        }
index 195991dadc3772c67a084396d28aa2a7c8b2019e..cce18c85d2e8edc6edcf23d13ef13e99f6cbf835 100644 (file)
@@ -1310,11 +1310,16 @@ static const struct of_device_id armpmu_of_device_ids[] = {
 
 static int armpmu_device_probe(struct platform_device *pdev)
 {
-       int i, *irqs;
+       int i, irq, *irqs;
 
        if (!cpu_pmu)
                return -ENODEV;
 
+       /* Don't bother with PPIs; they're already affine */
+       irq = platform_get_irq(pdev, 0);
+       if (irq >= 0 && irq_is_percpu(irq))
+               return 0;
+
        irqs = kcalloc(pdev->num_resources, sizeof(*irqs), GFP_KERNEL);
        if (!irqs)
                return -ENOMEM;
@@ -1327,7 +1332,7 @@ static int armpmu_device_probe(struct platform_device *pdev)
                                      i);
                if (!dn) {
                        pr_warn("Failed to parse %s/interrupt-affinity[%d]\n",
-                               of_node_full_name(dn), i);
+                               of_node_full_name(pdev->dev.of_node), i);
                        break;
                }
 
index ef7d112f5ce0df9ca1c1a793301c2c1b3874e23f..b0bd4e5fd5cf9c2599ddbc509bccb233838638a4 100644 (file)
@@ -67,8 +67,7 @@ static void *__alloc_from_pool(size_t size, struct page **ret_page, gfp_t flags)
 
                *ret_page = phys_to_page(phys);
                ptr = (void *)val;
-               if (flags & __GFP_ZERO)
-                       memset(ptr, 0, size);
+               memset(ptr, 0, size);
        }
 
        return ptr;
@@ -105,7 +104,6 @@ static void *__dma_alloc_coherent(struct device *dev, size_t size,
                struct page *page;
                void *addr;
 
-               size = PAGE_ALIGN(size);
                page = dma_alloc_from_contiguous(dev, size >> PAGE_SHIFT,
                                                        get_order(size));
                if (!page)
@@ -113,8 +111,7 @@ static void *__dma_alloc_coherent(struct device *dev, size_t size,
 
                *dma_handle = phys_to_dma(dev, page_to_phys(page));
                addr = page_address(page);
-               if (flags & __GFP_ZERO)
-                       memset(addr, 0, size);
+               memset(addr, 0, size);
                return addr;
        } else {
                return swiotlb_alloc_coherent(dev, size, dma_handle, flags);
@@ -195,6 +192,8 @@ static void __dma_free(struct device *dev, size_t size,
 {
        void *swiotlb_addr = phys_to_virt(dma_to_phys(dev, dma_handle));
 
+       size = PAGE_ALIGN(size);
+
        if (!is_device_dma_coherent(dev)) {
                if (__free_from_pool(vaddr, size))
                        return;
index 74c256744b254e09c989cabcd9072aee93c9fd6d..f3d6221cd5bdd4c7bf59fd99c71415d3922e2572 100644 (file)
@@ -328,10 +328,12 @@ static int ptdump_init(void)
                        for (j = 0; j < pg_level[i].num; j++)
                                pg_level[i].mask |= pg_level[i].bits[j].mask;
 
+#ifdef CONFIG_SPARSEMEM_VMEMMAP
        address_markers[VMEMMAP_START_NR].start_address =
                                (unsigned long)virt_to_page(PAGE_OFFSET);
        address_markers[VMEMMAP_END_NR].start_address =
                                (unsigned long)virt_to_page(high_memory);
+#endif
 
        pe = debugfs_create_file("kernel_page_tables", 0400, NULL, NULL,
                                 &ptdump_fops);
index edba042b23259c6f4b642a842fc1a2eb740c59b3..dc6a4842683aa500b9a5fc3af41caec349472902 100644 (file)
@@ -487,7 +487,7 @@ emit_cond_jmp:
                        return -EINVAL;
                }
 
-               imm64 = (u64)insn1.imm << 32 | imm;
+               imm64 = (u64)insn1.imm << 32 | (u32)imm;
                emit_a64_mov_i64(dst, imm64, ctx);
 
                return 1;
index 4e8ad0523118d631ea24f6b9f8fd1c3ffb123194..6abebe82d4e93ed0329f271cd54e2af5c1bc38d2 100644 (file)
@@ -10,6 +10,7 @@
 #include <linux/compiler.h>
 #include <linux/types.h>
 #include <asm/byteorder.h>
+#include <asm/def_LPBlackfin.h>
 
 #define __raw_readb bfin_read8
 #define __raw_readw bfin_read16
index 15051e9c2c6f98f3f2e8743739f10b63f795be3a..b054c5c6e7137cf85ba00f8c60fa33b8719b0c07 100644 (file)
@@ -127,7 +127,7 @@ int smp_num_siblings = 1;
 volatile int ia64_cpu_to_sapicid[NR_CPUS];
 EXPORT_SYMBOL(ia64_cpu_to_sapicid);
 
-static volatile cpumask_t cpu_callin_map;
+static cpumask_t cpu_callin_map;
 
 struct smp_boot_data smp_boot_data __initdata;
 
@@ -477,6 +477,7 @@ do_boot_cpu (int sapicid, int cpu, struct task_struct *idle)
        for (timeout = 0; timeout < 100000; timeout++) {
                if (cpumask_test_cpu(cpu, &cpu_callin_map))
                        break;  /* It has booted */
+               barrier(); /* Make sure we re-read cpu_callin_map */
                udelay(100);
        }
        Dprintk("\n");
index d4e162d35b3467b9d7814769129237583f8cb100..7cc3be9fa7c65a0dd700dfd30c04cc7be822922d 100644 (file)
@@ -478,9 +478,16 @@ struct pci_bus *pci_acpi_scan_root(struct acpi_pci_root *root)
 
 int pcibios_root_bridge_prepare(struct pci_host_bridge *bridge)
 {
-       struct pci_controller *controller = bridge->bus->sysdata;
-
-       ACPI_COMPANION_SET(&bridge->dev, controller->companion);
+       /*
+        * We pass NULL as parent to pci_create_root_bus(), so if it is not NULL
+        * here, pci_create_root_bus() has been called by someone else and
+        * sysdata is likely to be different from what we expect.  Let it go in
+        * that case.
+        */
+       if (!bridge->dev.parent) {
+               struct pci_controller *controller = bridge->bus->sysdata;
+               ACPI_COMPANION_SET(&bridge->dev, controller->companion);
+       }
        return 0;
 }
 
index ce7aea34fdf410857799d9e17e092ff1aa1936e8..c18ddc74ef9a60c0ad8c338213d0f95239d972b9 100644 (file)
@@ -45,7 +45,7 @@ static volatile unsigned long flushcache_cpumask = 0;
 /*
  * For flush_tlb_others()
  */
-static volatile cpumask_t flush_cpumask;
+static cpumask_t flush_cpumask;
 static struct mm_struct *flush_mm;
 static struct vm_area_struct *flush_vma;
 static volatile unsigned long flush_va;
@@ -415,7 +415,7 @@ static void flush_tlb_others(cpumask_t cpumask, struct mm_struct *mm,
         */
        send_IPI_mask(&cpumask, INVALIDATE_TLB_IPI, 0);
 
-       while (!cpumask_empty((cpumask_t*)&flush_cpumask)) {
+       while (!cpumask_empty(&flush_cpumask)) {
                /* nothing. lockup detection does not belong here */
                mb();
        }
@@ -468,7 +468,7 @@ void smp_invalidate_interrupt(void)
                        __flush_tlb_page(va);
                }
        }
-       cpumask_clear_cpu(cpu_id, (cpumask_t*)&flush_cpumask);
+       cpumask_clear_cpu(cpu_id, &flush_cpumask);
 }
 
 /*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*/
index 5200f649dd4e3005423a81b4c608fc4ac49d2321..ae2dd59050f742c54c49b3f80925bbfc4e67fbbd 100644 (file)
@@ -277,7 +277,7 @@ LDFLAGS                     += -m $(ld-emul)
 ifdef CONFIG_MIPS
 CHECKFLAGS += $(shell $(CC) $(KBUILD_CFLAGS) -dM -E -x c /dev/null | \
        egrep -vw '__GNUC_(|MINOR_|PATCHLEVEL_)_' | \
-       sed -e "s/^\#define /-D'/" -e "s/ /'='/" -e "s/$$/'/")
+       sed -e "s/^\#define /-D'/" -e "s/ /'='/" -e "s/$$/'/" -e 's/\$$/&&/g')
 ifdef CONFIG_64BIT
 CHECKFLAGS             += -m64
 endif
index e1fe6305113612cf2943bff9307a9579a9da3f69..597899ad5438e3b551a0b190555546e3a0e5b218 100644 (file)
@@ -1,6 +1,7 @@
 /*
  *  Atheros AR71XX/AR724X/AR913X specific prom routines
  *
+ *  Copyright (C) 2015 Laurent Fasnacht <l@libres.ch>
  *  Copyright (C) 2008-2010 Gabor Juhos <juhosg@openwrt.org>
  *  Copyright (C) 2008 Imre Kaloz <kaloz@openwrt.org>
  *
@@ -25,12 +26,14 @@ void __init prom_init(void)
 {
        fw_init_cmdline();
 
+#ifdef CONFIG_BLK_DEV_INITRD
        /* Read the initrd address from the firmware environment */
        initrd_start = fw_getenvl("initrd_start");
        if (initrd_start) {
                initrd_start = KSEG0ADDR(initrd_start);
                initrd_end = initrd_start + fw_getenvl("initrd_size");
        }
+#endif
 }
 
 void __init prom_free_prom_memory(void)
index a73c93c3d44a1069149945cf2732aeed26c918bd..7fc8397d16f21d713ad3e073308f69c75dd88692 100644 (file)
@@ -225,7 +225,7 @@ void __init plat_time_init(void)
        ddr_clk_rate = ath79_get_sys_clk_rate("ddr");
        ref_clk_rate = ath79_get_sys_clk_rate("ref");
 
-       pr_info("Clocks: CPU:%lu.%03luMHz, DDR:%lu.%03luMHz, AHB:%lu.%03luMHz, Ref:%lu.%03luMHz",
+       pr_info("Clocks: CPU:%lu.%03luMHz, DDR:%lu.%03luMHz, AHB:%lu.%03luMHz, Ref:%lu.%03luMHz\n",
                cpu_clk_rate / 1000000, (cpu_clk_rate / 1000) % 1000,
                ddr_clk_rate / 1000000, (ddr_clk_rate / 1000) % 1000,
                ahb_clk_rate / 1000000, (ahb_clk_rate / 1000) % 1000,
index 558e94977942033dc8247bcc510ebb705aa9698a..68f0c5871adcdf51f40380ffbba09b1e5e52202c 100644 (file)
@@ -2,7 +2,6 @@
 # Makefile for the Cobalt micro systems family specific parts of the kernel
 #
 
-obj-y := buttons.o irq.o lcd.o led.o reset.o rtc.o serial.o setup.o time.o
+obj-y := buttons.o irq.o lcd.o led.o mtd.o reset.o rtc.o serial.o setup.o time.o
 
 obj-$(CONFIG_PCI)              += pci.o
-obj-$(CONFIG_MTD_PHYSMAP)      += mtd.o
index 002680648dcb22307f338f2db93af43c372a01ff..b2a577ebce0b08f79650d8ef2bb096fcb6d0a27e 100644 (file)
@@ -194,7 +194,7 @@ CONFIG_USB_WUSB_CBAF=m
 CONFIG_USB_C67X00_HCD=m
 CONFIG_USB_EHCI_HCD=y
 CONFIG_USB_EHCI_ROOT_HUB_TT=y
-CONFIG_USB_ISP1760_HCD=m
+CONFIG_USB_ISP1760=m
 CONFIG_USB_OHCI_HCD=y
 CONFIG_USB_UHCI_HCD=m
 CONFIG_USB_R8A66597_HCD=m
index a594d8ed96980cd1e96c8bf3eb593368203fe53c..f19e890b99d2744ae4984ea54e2ca9e5128ce7fe 100644 (file)
@@ -304,7 +304,7 @@ do {                                                                        \
                                                                        \
        current->thread.abi = &mips_abi;                                \
                                                                        \
-       current->thread.fpu.fcr31 = current_cpu_data.fpu_csr31;         \
+       current->thread.fpu.fcr31 = boot_cpu_data.fpu_csr31;            \
 } while (0)
 
 #endif /* CONFIG_32BIT */
@@ -366,7 +366,7 @@ do {                                                                        \
        else                                                            \
                current->thread.abi = &mips_abi;                        \
                                                                        \
-       current->thread.fpu.fcr31 = current_cpu_data.fpu_csr31;         \
+       current->thread.fpu.fcr31 = boot_cpu_data.fpu_csr31;            \
                                                                        \
        p = personality(current->personality);                          \
        if (p != PER_LINUX32 && p != PER_LINUX)                         \
index 18ae5ddef118c071e1240486e90f08be3e4b0871..c28a8499aec7f4fa18c5bd4c71922812d2ebf143 100644 (file)
 #define _PAGE_PRESENT_SHIFT    0
 #define _PAGE_PRESENT          (1 << _PAGE_PRESENT_SHIFT)
 /* R2 or later cores check for RI/XI support to determine _PAGE_READ */
-#ifdef CONFIG_CPU_MIPSR2
+#if defined(CONFIG_CPU_MIPSR2) || defined(CONFIG_CPU_MIPSR6)
 #define _PAGE_WRITE_SHIFT      (_PAGE_PRESENT_SHIFT + 1)
 #define _PAGE_WRITE            (1 << _PAGE_WRITE_SHIFT)
 #else
 #define _PAGE_SPLITTING                (1 << _PAGE_SPLITTING_SHIFT)
 
 /* Only R2 or newer cores have the XI bit */
-#ifdef CONFIG_CPU_MIPSR2
+#if defined(CONFIG_CPU_MIPSR2) || defined(CONFIG_CPU_MIPSR6)
 #define _PAGE_NO_EXEC_SHIFT    (_PAGE_SPLITTING_SHIFT + 1)
 #else
 #define _PAGE_GLOBAL_SHIFT     (_PAGE_SPLITTING_SHIFT + 1)
 #define _PAGE_GLOBAL           (1 << _PAGE_GLOBAL_SHIFT)
-#endif /* CONFIG_CPU_MIPSR2 */
+#endif /* CONFIG_CPU_MIPSR2 || CONFIG_CPU_MIPSR6 */
 
 #endif /* CONFIG_64BIT && CONFIG_MIPS_HUGE_TLB_SUPPORT */
 
-#ifdef CONFIG_CPU_MIPSR2
+#if defined(CONFIG_CPU_MIPSR2) || defined(CONFIG_CPU_MIPSR6)
 /* XI - page cannot be executed */
 #ifndef _PAGE_NO_EXEC_SHIFT
 #define _PAGE_NO_EXEC_SHIFT    (_PAGE_MODIFIED_SHIFT + 1)
 #define _PAGE_GLOBAL_SHIFT     (_PAGE_NO_READ_SHIFT + 1)
 #define _PAGE_GLOBAL           (1 << _PAGE_GLOBAL_SHIFT)
 
-#else  /* !CONFIG_CPU_MIPSR2 */
+#else  /* !CONFIG_CPU_MIPSR2 && !CONFIG_CPU_MIPSR6 */
 #define _PAGE_GLOBAL_SHIFT     (_PAGE_MODIFIED_SHIFT + 1)
 #define _PAGE_GLOBAL           (1 << _PAGE_GLOBAL_SHIFT)
-#endif /* CONFIG_CPU_MIPSR2 */
+#endif /* CONFIG_CPU_MIPSR2 || CONFIG_CPU_MIPSR6 */
 
 #define _PAGE_VALID_SHIFT      (_PAGE_GLOBAL_SHIFT + 1)
 #define _PAGE_VALID            (1 << _PAGE_VALID_SHIFT)
  */
 static inline uint64_t pte_to_entrylo(unsigned long pte_val)
 {
-#ifdef CONFIG_CPU_MIPSR2
+#if defined(CONFIG_CPU_MIPSR2) || defined(CONFIG_CPU_MIPSR6)
        if (cpu_has_rixi) {
                int sa;
 #ifdef CONFIG_32BIT
index bb02fac9b4fa0188e12b263376f3e1e08f83b022..2b25d1ba1ea037ca82212ec542a165e714ecf29c 100644 (file)
@@ -45,7 +45,7 @@ extern int __cpu_logical_map[NR_CPUS];
 #define SMP_DUMP               0x8
 #define SMP_ASK_C0COUNT                0x10
 
-extern volatile cpumask_t cpu_callin_map;
+extern cpumask_t cpu_callin_map;
 
 /* Mask of CPUs which are currently definitely operating coherently */
 extern cpumask_t cpu_coherent_mask;
index e92d6c4b5ed192305b0b1f1605481f745cfadb10..7163cd7fdd69a622892e4be83acbe0450e8f2af0 100644 (file)
@@ -104,7 +104,6 @@ do {                                                                        \
        if (test_and_clear_tsk_thread_flag(prev, TIF_USEDMSA))          \
                __fpsave = FP_SAVE_VECTOR;                              \
        (last) = resume(prev, next, task_thread_info(next), __fpsave);  \
-       disable_msa();                                                  \
 } while (0)
 
 #define finish_arch_switch(prev)                                       \
@@ -122,6 +121,7 @@ do {                                                                        \
        if (cpu_has_userlocal)                                          \
                write_c0_userlocal(current_thread_info()->tp_value);    \
        __restore_watch();                                              \
+       disable_msa();                                                  \
 } while (0)
 
 #endif /* _ASM_SWITCH_TO_H */
index e36515dcd3b29efcdb0014c7dfd4541805eb4e4c..209e5b76c1bce56f02ceeb1fdeffeccc6fe46bd8 100644 (file)
@@ -74,13 +74,12 @@ static inline void cpu_set_fpu_fcsr_mask(struct cpuinfo_mips *c)
 {
        unsigned long sr, mask, fcsr, fcsr0, fcsr1;
 
+       fcsr = c->fpu_csr31;
        mask = FPU_CSR_ALL_X | FPU_CSR_ALL_E | FPU_CSR_ALL_S | FPU_CSR_RM;
 
        sr = read_c0_status();
        __enable_fpu(FPU_AS_IS);
 
-       fcsr = read_32bit_cp1_register(CP1_STATUS);
-
        fcsr0 = fcsr & mask;
        write_32bit_cp1_register(CP1_STATUS, fcsr0);
        fcsr0 = read_32bit_cp1_register(CP1_STATUS);
index be4899f3c393275a992083d6f7e9f19c2fde5b87..4a4d9e067c89427fc34e990586f0e8237a9418ba 100644 (file)
@@ -76,14 +76,6 @@ int arch_elf_pt_proc(void *_ehdr, void *_phdr, struct file *elf,
 
        /* Lets see if this is an O32 ELF */
        if (ehdr32->e_ident[EI_CLASS] == ELFCLASS32) {
-               /* FR = 1 for N32 */
-               if (ehdr32->e_flags & EF_MIPS_ABI2)
-                       state->overall_fp_mode = FP_FR1;
-               else
-                       /* Set a good default FPU mode for O32 */
-                       state->overall_fp_mode = cpu_has_mips_r6 ?
-                               FP_FRE : FP_FR0;
-
                if (ehdr32->e_flags & EF_MIPS_FP64) {
                        /*
                         * Set MIPS_ABI_FP_OLD_64 for EF_MIPS_FP64. We will override it
@@ -104,9 +96,6 @@ int arch_elf_pt_proc(void *_ehdr, void *_phdr, struct file *elf,
                                  (char *)&abiflags,
                                  sizeof(abiflags));
        } else {
-               /* FR=1 is really the only option for 64-bit */
-               state->overall_fp_mode = FP_FR1;
-
                if (phdr64->p_type != PT_MIPS_ABIFLAGS)
                        return 0;
                if (phdr64->p_filesz < sizeof(abiflags))
@@ -137,6 +126,7 @@ int arch_check_elf(void *_ehdr, bool has_interpreter,
        struct elf32_hdr *ehdr = _ehdr;
        struct mode_req prog_req, interp_req;
        int fp_abi, interp_fp_abi, abi0, abi1, max_abi;
+       bool is_mips64;
 
        if (!config_enabled(CONFIG_MIPS_O32_FP64_SUPPORT))
                return 0;
@@ -152,10 +142,22 @@ int arch_check_elf(void *_ehdr, bool has_interpreter,
                abi0 = abi1 = fp_abi;
        }
 
-       /* ABI limits. O32 = FP_64A, N32/N64 = FP_SOFT */
-       max_abi = ((ehdr->e_ident[EI_CLASS] == ELFCLASS32) &&
-                  (!(ehdr->e_flags & EF_MIPS_ABI2))) ?
-               MIPS_ABI_FP_64A : MIPS_ABI_FP_SOFT;
+       is_mips64 = (ehdr->e_ident[EI_CLASS] == ELFCLASS64) ||
+                   (ehdr->e_flags & EF_MIPS_ABI2);
+
+       if (is_mips64) {
+               /* MIPS64 code always uses FR=1, thus the default is easy */
+               state->overall_fp_mode = FP_FR1;
+
+               /* Disallow access to the various FPXX & FP64 ABIs */
+               max_abi = MIPS_ABI_FP_SOFT;
+       } else {
+               /* Default to a mode capable of running code expecting FR=0 */
+               state->overall_fp_mode = cpu_has_mips_r6 ? FP_FRE : FP_FR0;
+
+               /* Allow all ABIs we know about */
+               max_abi = MIPS_ABI_FP_64A;
+       }
 
        if ((abi0 > max_abi && abi0 != MIPS_ABI_FP_UNKNOWN) ||
            (abi1 > max_abi && abi1 != MIPS_ABI_FP_UNKNOWN))
index d2bfbc2e8995fba3b6da1ad7a190f0d872ca6fbf..3c8a18a00a65fee62e7cc11068d3866b18b04fd1 100644 (file)
@@ -29,7 +29,7 @@
 int kgdb_early_setup;
 #endif
 
-static unsigned long irq_map[NR_IRQS / BITS_PER_LONG];
+static DECLARE_BITMAP(irq_map, NR_IRQS);
 
 int allocate_irqno(void)
 {
@@ -109,7 +109,7 @@ void __init init_IRQ(void)
 #endif
 }
 
-#ifdef DEBUG_STACKOVERFLOW
+#ifdef CONFIG_DEBUG_STACKOVERFLOW
 static inline void check_stack_overflow(void)
 {
        unsigned long sp;
index d544e774eea6b1b6e0f811099290600b1fc5b534..e933a309f2ea5fa4498153a9b6a3caa0af4a1587 100644 (file)
@@ -176,7 +176,7 @@ int ptrace_setfpregs(struct task_struct *child, __u32 __user *data)
 
        __get_user(value, data + 64);
        fcr31 = child->thread.fpu.fcr31;
-       mask = current_cpu_data.fpu_msk31;
+       mask = boot_cpu_data.fpu_msk31;
        child->thread.fpu.fcr31 = (value & ~mask) | (fcr31 & mask);
 
        /* FIR may not be written.  */
index fd528d7ea27867ffed69abf25d3c7b3f374b7f64..336708ae5c5b4c74b75416058feabb4bef5e30b1 100644 (file)
@@ -444,7 +444,7 @@ struct plat_smp_ops bmips5000_smp_ops = {
 static void bmips_wr_vec(unsigned long dst, char *start, char *end)
 {
        memcpy((void *)dst, start, end - start);
-       dma_cache_wback((unsigned long)start, end - start);
+       dma_cache_wback(dst, end - start);
        local_flush_icache_range(dst, dst + (end - start));
        instruction_hazard();
 }
index 7e011f95bb8e14785d447bf49bb1b8141cf0bc08..4251d390b5b66e0c20a7271659a280e448ca0ffe 100644 (file)
@@ -92,7 +92,7 @@ static void __init cps_smp_setup(void)
 #ifdef CONFIG_MIPS_MT_FPAFF
        /* If we have an FPU, enroll ourselves in the FPU-full mask */
        if (cpu_has_fpu)
-               cpu_set(0, mt_fpu_cpumask);
+               cpumask_set_cpu(0, &mt_fpu_cpumask);
 #endif /* CONFIG_MIPS_MT_FPAFF */
 }
 
index 193ace7955fb5eec377b666db534d76173a014c5..faa46ebd9ddae2fc43f20d6ff65f28688f665c4f 100644 (file)
@@ -43,7 +43,7 @@
 #include <asm/time.h>
 #include <asm/setup.h>
 
-volatile cpumask_t cpu_callin_map;     /* Bitmask of started secondaries */
+cpumask_t cpu_callin_map;              /* Bitmask of started secondaries */
 
 int __cpu_number_map[NR_CPUS];         /* Map physical to logical */
 EXPORT_SYMBOL(__cpu_number_map);
@@ -218,8 +218,10 @@ int __cpu_up(unsigned int cpu, struct task_struct *tidle)
        /*
         * Trust is futile.  We should really have timeouts ...
         */
-       while (!cpumask_test_cpu(cpu, &cpu_callin_map))
+       while (!cpumask_test_cpu(cpu, &cpu_callin_map)) {
                udelay(100);
+               schedule();
+       }
 
        synchronise_count_master(cpu);
        return 0;
index ba32e48d4697193f3410edd79153d392ab0d8311..d2d1c1933bc9f598efaa81735d132af1ff12adee 100644 (file)
@@ -269,7 +269,6 @@ static void __show_regs(const struct pt_regs *regs)
         */
        printk("epc   : %0*lx %pS\n", field, regs->cp0_epc,
               (void *) regs->cp0_epc);
-       printk("    %s\n", print_tainted());
        printk("ra    : %0*lx %pS\n", field, regs->regs[31],
               (void *) regs->regs[31]);
 
index 6230f376a44e7ab6f09041c4b805e54e59468489..d5fa3eaf39a106546f52d82ec3e5391302ef8dec 100644 (file)
@@ -2389,7 +2389,6 @@ enum emulation_result kvm_mips_complete_mmio_load(struct kvm_vcpu *vcpu,
 {
        unsigned long *gpr = &vcpu->arch.gprs[vcpu->arch.io_gpr];
        enum emulation_result er = EMULATE_DONE;
-       unsigned long curr_pc;
 
        if (run->mmio.len > sizeof(*gpr)) {
                kvm_err("Bad MMIO length: %d", run->mmio.len);
@@ -2397,11 +2396,6 @@ enum emulation_result kvm_mips_complete_mmio_load(struct kvm_vcpu *vcpu,
                goto done;
        }
 
-       /*
-        * Update PC and hold onto current PC in case there is
-        * an error and we want to rollback the PC
-        */
-       curr_pc = vcpu->arch.pc;
        er = update_pc(vcpu, vcpu->arch.pending_load_cause);
        if (er == EMULATE_FAIL)
                return er;
@@ -2415,7 +2409,7 @@ enum emulation_result kvm_mips_complete_mmio_load(struct kvm_vcpu *vcpu,
                if (vcpu->mmio_needed == 2)
                        *gpr = *(int16_t *) run->mmio.data;
                else
-                       *gpr = *(int16_t *) run->mmio.data;
+                       *gpr = *(uint16_t *)run->mmio.data;
 
                break;
        case 1:
index 7d12c0dded3ded2009f85ffd7ed7d6e52f645c0c..77e64942f0048c5aac366c0c80a6cf63f0c656d5 100644 (file)
@@ -34,7 +34,12 @@ LEAF(__strnlen_\func\()_asm)
 FEXPORT(__strnlen_\func\()_nocheck_asm)
        move            v0, a0
        PTR_ADDU        a1, a0                  # stop pointer
-1:     beq             v0, a1, 1f              # limit reached?
+1:
+#ifdef CONFIG_CPU_DADDI_WORKAROUNDS
+       .set            noat
+       li              AT, 1
+#endif
+       beq             v0, a1, 1f              # limit reached?
 .ifeqs "\func", "kernel"
        EX(lb, t0, (v0), .Lfault\@)
 .else
@@ -42,7 +47,13 @@ FEXPORT(__strnlen_\func\()_nocheck_asm)
 .endif
        .set            noreorder
        bnez            t0, 1b
-1:      PTR_ADDIU      v0, 1
+1:
+#ifndef CONFIG_CPU_DADDI_WORKAROUNDS
+        PTR_ADDIU      v0, 1
+#else
+        PTR_ADDU       v0, AT
+       .set            at
+#endif
        .set            reorder
        PTR_SUBU        v0, a0
        jr              ra
index e70c33fdb88153ac6bfdf12a4f632d3b3a26ccb9..f2e8153e44f536213e196002f005bb86da9ef72f 100644 (file)
@@ -3,15 +3,13 @@
 #
 
 obj-y += setup.o init.o cmdline.o env.o time.o reset.o irq.o \
-    bonito-irq.o mem.o machtype.o platform.o
+    bonito-irq.o mem.o machtype.o platform.o serial.o
 obj-$(CONFIG_PCI) += pci.o
 
 #
 # Serial port support
 #
 obj-$(CONFIG_EARLY_PRINTK) += early_printk.o
-loongson-serial-$(CONFIG_SERIAL_8250) := serial.o
-obj-y += $(loongson-serial-m) $(loongson-serial-y)
 obj-$(CONFIG_LOONGSON_UART_BASE) += uart_base.o
 obj-$(CONFIG_LOONGSON_MC146818) += rtc.o
 
index e3c68b5da18da4012de0aaed6363d5a5484d5e41..509877c6e9d908d7bac6110982c7208ab69204af 100644 (file)
@@ -272,7 +272,7 @@ void loongson3_ipi_interrupt(struct pt_regs *regs)
        if (action & SMP_ASK_C0COUNT) {
                BUG_ON(cpu != 0);
                c0count = read_c0_count();
-               for (i = 1; i < loongson_sysconf.nr_cpus; i++)
+               for (i = 1; i < num_possible_cpus(); i++)
                        per_cpu(core0_c0count, i) = c0count;
        }
 }
index d31c537ace1d11b7f742fd9ead71d3f273cfa2d3..22b9b2cb9219fa4e4eb7b9cc340125a4c9aa4053 100644 (file)
@@ -889,7 +889,7 @@ static inline void cop1_cfc(struct pt_regs *xcp, struct mips_fpu_struct *ctx,
                break;
 
        case FPCREG_RID:
-               value = current_cpu_data.fpu_id;
+               value = boot_cpu_data.fpu_id;
                break;
 
        default:
@@ -921,7 +921,7 @@ static inline void cop1_ctc(struct pt_regs *xcp, struct mips_fpu_struct *ctx,
                         (void *)xcp->cp0_epc, MIPSInst_RT(ir), value);
 
                /* Preserve read-only bits.  */
-               mask = current_cpu_data.fpu_msk31;
+               mask = boot_cpu_data.fpu_msk31;
                fcr31 = (value & ~mask) | (fcr31 & mask);
                break;
 
index 0dbb65a51ce5b1c2913cfec00571710e3a0ecb10..2e03ab1735911d202ce82c97b4911b5c1002ed70 100644 (file)
@@ -1372,7 +1372,7 @@ static int probe_scache(void)
        scache_size = addr;
        c->scache.linesz = 16 << ((config & R4K_CONF_SB) >> 22);
        c->scache.ways = 1;
-       c->dcache.waybit = 0;           /* does not matter */
+       c->scache.waybit = 0;           /* does not matter */
 
        return 1;
 }
index a27a088e6f9f830f7e3445abab6bae5cd8b60478..08318ecb803a08611adfd0025041c16526d097e2 100644 (file)
@@ -495,7 +495,7 @@ static void r4k_tlb_configure(void)
 
        if (cpu_has_rixi) {
                /*
-                * Enable the no read, no exec bits, and enable large virtual
+                * Enable the no read, no exec bits, and enable large physical
                 * address.
                 */
 #ifdef CONFIG_64BIT
index 5d6139390bf830adf503d67d004a5322d8eb7ad4..e23fdf2a9c80d2f0dbbb498343efb859c08f3b4e 100644 (file)
@@ -681,11 +681,7 @@ static unsigned int get_stack_depth(struct jit_ctx *ctx)
                sp_off += config_enabled(CONFIG_64BIT) ?
                        (ARGS_USED_BY_JIT + 1) * RSIZE : RSIZE;
 
-       /*
-        * Subtract the bytes for the last registers since we only care about
-        * the location on the stack pointer.
-        */
-       return sp_off - RSIZE;
+       return sp_off;
 }
 
 static void build_prologue(struct jit_ctx *ctx)
index e20b02e3ae28be201789dd260ab79a382be944f8..e10d10b9e82a98bf5e53382d88cbc98b769ef53c 100644 (file)
@@ -41,7 +41,7 @@ static irqreturn_t ill_acc_irq_handler(int irq, void *_priv)
                addr, (type >> ILL_ACC_OFF_S) & ILL_ACC_OFF_M,
                type & ILL_ACC_LEN_M);
 
-       rt_memc_w32(REG_ILL_ACC_TYPE, REG_ILL_ACC_TYPE);
+       rt_memc_w32(ILL_INT_STATUS, REG_ILL_ACC_TYPE);
 
        return IRQ_HANDLED;
 }
index 0134db2ad0a850ca5f2e07c912fe24e746dda902..5a2a82148d8d4f633c644f951ca87f252bdce09b 100644 (file)
@@ -130,9 +130,9 @@ struct platform_device ip32_rtc_device = {
        .resource               = ip32_rtc_resources,
 };
 
-+static int __init sgio2_rtc_devinit(void)
+static __init int sgio2_rtc_devinit(void)
 {
        return platform_device_register(&ip32_rtc_device);
 }
 
-device_initcall(sgio2_cmos_devinit);
+device_initcall(sgio2_rtc_devinit);
index 3391d061eccc02fb64ebff9211cb9146c9f50a1c..78c9fd32c5546b6ec91d591e853d89a761383c92 100644 (file)
@@ -348,6 +348,10 @@ struct pt_regs;    /* forward declaration... */
 
 #define ELF_HWCAP      0
 
+#define STACK_RND_MASK (is_32bit_task() ? \
+                               0x7ff >> (PAGE_SHIFT - 12) : \
+                               0x3ffff >> (PAGE_SHIFT - 12))
+
 struct mm_struct;
 extern unsigned long arch_randomize_brk(struct mm_struct *);
 #define arch_randomize_brk arch_randomize_brk
index 8a488c22a99f7bb3836fc93a23a31561a237fb86..809905a811ed72a543ad257c1394900a4b976af8 100644 (file)
@@ -181,9 +181,12 @@ int dump_task_fpu (struct task_struct *tsk, elf_fpregset_t *r)
        return 1;
 }
 
+/*
+ * Copy architecture-specific thread state
+ */
 int
 copy_thread(unsigned long clone_flags, unsigned long usp,
-           unsigned long arg, struct task_struct *p)
+           unsigned long kthread_arg, struct task_struct *p)
 {
        struct pt_regs *cregs = &(p->thread.regs);
        void *stack = task_stack_page(p);
@@ -195,11 +198,10 @@ copy_thread(unsigned long clone_flags, unsigned long usp,
        extern void * const child_return;
 
        if (unlikely(p->flags & PF_KTHREAD)) {
+               /* kernel thread */
                memset(cregs, 0, sizeof(struct pt_regs));
                if (!usp) /* idle thread */
                        return 0;
-
-               /* kernel thread */
                /* Must exit via ret_from_kernel_thread in order
                 * to call schedule_tail()
                 */
@@ -215,7 +217,7 @@ copy_thread(unsigned long clone_flags, unsigned long usp,
 #else
                cregs->gr[26] = usp;
 #endif
-               cregs->gr[25] = arg;
+               cregs->gr[25] = kthread_arg;
        } else {
                /* user thread */
                /* usp must be word aligned.  This also prevents users from
index e1ffea2f9a0b05ccda844969dcb7c519ab17077a..5aba01ac457ffc5d4823cf09c071f02f00a1d015 100644 (file)
@@ -77,6 +77,9 @@ static unsigned long mmap_upper_limit(void)
        if (stack_base > STACK_SIZE_MAX)
                stack_base = STACK_SIZE_MAX;
 
+       /* Add space for stack randomization. */
+       stack_base += (STACK_RND_MASK << PAGE_SHIFT);
+
        return PAGE_ALIGN(STACK_TOP - stack_base);
 }
 
index 5047659815a54ffd69037b245eebd9f6c64a679d..5d836b7c1176242ae2c943c0bcc81cf6bcb031cf 100644 (file)
@@ -11,7 +11,7 @@
 #define TM_CAUSE_RESCHED       0xde
 #define TM_CAUSE_TLBI          0xdc
 #define TM_CAUSE_FAC_UNAV      0xda
-#define TM_CAUSE_SYSCALL       0xd8
+#define TM_CAUSE_SYSCALL       0xd8  /* future use */
 #define TM_CAUSE_MISC          0xd6  /* future use */
 #define TM_CAUSE_SIGNAL                0xd4
 #define TM_CAUSE_ALIGNMENT     0xd2
index 44b480e3a5afd1998ce7f92afac532c8926a7aba..9ee61d15653d6ec46546b93ea72601072176e4b7 100644 (file)
@@ -749,21 +749,24 @@ int pcibios_set_pcie_reset_state(struct pci_dev *dev, enum pcie_reset_state stat
                eeh_unfreeze_pe(pe, false);
                eeh_pe_state_clear(pe, EEH_PE_CFG_BLOCKED);
                eeh_pe_dev_traverse(pe, eeh_restore_dev_state, dev);
+               eeh_pe_state_clear(pe, EEH_PE_ISOLATED);
                break;
        case pcie_hot_reset:
+               eeh_pe_state_mark(pe, EEH_PE_ISOLATED);
                eeh_ops->set_option(pe, EEH_OPT_FREEZE_PE);
                eeh_pe_dev_traverse(pe, eeh_disable_and_save_dev_state, dev);
                eeh_pe_state_mark(pe, EEH_PE_CFG_BLOCKED);
                eeh_ops->reset(pe, EEH_RESET_HOT);
                break;
        case pcie_warm_reset:
+               eeh_pe_state_mark(pe, EEH_PE_ISOLATED);
                eeh_ops->set_option(pe, EEH_OPT_FREEZE_PE);
                eeh_pe_dev_traverse(pe, eeh_disable_and_save_dev_state, dev);
                eeh_pe_state_mark(pe, EEH_PE_CFG_BLOCKED);
                eeh_ops->reset(pe, EEH_RESET_FUNDAMENTAL);
                break;
        default:
-               eeh_pe_state_clear(pe, EEH_PE_CFG_BLOCKED);
+               eeh_pe_state_clear(pe, EEH_PE_ISOLATED | EEH_PE_CFG_BLOCKED);
                return -EINVAL;
        };
 
@@ -1058,6 +1061,9 @@ void eeh_add_device_early(struct pci_dn *pdn)
        if (!edev || !eeh_enabled())
                return;
 
+       if (!eeh_has_flag(EEH_PROBE_MODE_DEVTREE))
+               return;
+
        /* USB Bus children of PCI devices will not have BUID's */
        phb = edev->phb;
        if (NULL == phb ||
@@ -1112,6 +1118,9 @@ void eeh_add_device_late(struct pci_dev *dev)
                return;
        }
 
+       if (eeh_has_flag(EEH_PROBE_MODE_DEV))
+               eeh_ops->probe(pdn, NULL);
+
        /*
         * The EEH cache might not be removed correctly because of
         * unbalanced kref to the device during unplug time, which
index 8ca9434c40e6a705e1eccb8e8ddcca727bf68044..afbc20019c2efba2b81b7cd6298941753d9776b5 100644 (file)
@@ -34,7 +34,6 @@
 #include <asm/ftrace.h>
 #include <asm/hw_irq.h>
 #include <asm/context_tracking.h>
-#include <asm/tm.h>
 
 /*
  * System calls.
@@ -146,24 +145,6 @@ END_FW_FTR_SECTION_IFSET(FW_FEATURE_SPLPAR)
        andi.   r11,r10,_TIF_SYSCALL_DOTRACE
        bne     syscall_dotrace
 .Lsyscall_dotrace_cont:
-#ifdef CONFIG_PPC_TRANSACTIONAL_MEM
-BEGIN_FTR_SECTION
-       b       1f
-END_FTR_SECTION_IFCLR(CPU_FTR_TM)
-       extrdi. r11, r12, 1, (63-MSR_TS_T_LG) /* transaction active? */
-       beq+    1f
-
-       /* Doom the transaction and don't perform the syscall: */
-       mfmsr   r11
-       li      r12, 1
-       rldimi  r11, r12, MSR_TM_LG, 63-MSR_TM_LG
-       mtmsrd  r11, 0
-       li      r11, (TM_CAUSE_SYSCALL|TM_CAUSE_PERSISTENT)
-       TABORT(R11)
-
-       b       .Lsyscall_exit
-1:
-#endif
        cmpldi  0,r0,NR_syscalls
        bge-    syscall_enosys
 
index eeaa0d5f69d5e60271ccca1790aaf98559ca92fa..ccde8f084ce426ab382964ec5e2eba389317be44 100644 (file)
@@ -501,9 +501,11 @@ BEGIN_FTR_SECTION
        CHECK_HMI_INTERRUPT
 END_FTR_SECTION_IFSET(CPU_FTR_HVMODE)
        ld      r1,PACAR1(r13)
+       ld      r6,_CCR(r1)
        ld      r4,_MSR(r1)
        ld      r5,_NIP(r1)
        addi    r1,r1,INT_FRAME_SIZE
+       mtcr    r6
        mtspr   SPRN_SRR1,r4
        mtspr   SPRN_SRR0,r5
        rfid
index 15c99b649b04cf2e946e2a612a3660dc50e6712c..b2eb4686bd8f40155bbb4a982549de0ae8de8567 100644 (file)
@@ -73,7 +73,7 @@ void save_mce_event(struct pt_regs *regs, long handled,
                    uint64_t nip, uint64_t addr)
 {
        uint64_t srr1;
-       int index = __this_cpu_inc_return(mce_nest_count);
+       int index = __this_cpu_inc_return(mce_nest_count) - 1;
        struct machine_check_event *mce = this_cpu_ptr(&mce_event[index]);
 
        /*
@@ -184,7 +184,7 @@ void machine_check_queue_event(void)
        if (!get_mce_event(&evt, MCE_EVENT_RELEASE))
                return;
 
-       index = __this_cpu_inc_return(mce_queue_count);
+       index = __this_cpu_inc_return(mce_queue_count) - 1;
        /* If queue is full, just return for now. */
        if (index >= MAX_MC_EVT) {
                __this_cpu_dec(mce_queue_count);
index f096e72262f41d121398f8fa27d5286bd8641bf4..1db685104ffc2b298375c9062590ae1c2f811db9 100644 (file)
@@ -213,6 +213,7 @@ SECTIONS
                *(.opd)
        }
 
+       . = ALIGN(256);
        .got : AT(ADDR(.got) - LOAD_OFFSET) {
                __toc_start = .;
 #ifndef CONFIG_RELOCATABLE
index 48d3c5d2ecc9ee83aab086715b3ffd6bf904d80a..df81caab738339c5b8dfe7c2def731bb9ba640d1 100644 (file)
@@ -1952,7 +1952,7 @@ static void post_guest_process(struct kvmppc_vcore *vc)
  */
 static noinline void kvmppc_run_core(struct kvmppc_vcore *vc)
 {
-       struct kvm_vcpu *vcpu;
+       struct kvm_vcpu *vcpu, *vnext;
        int i;
        int srcu_idx;
 
@@ -1982,7 +1982,8 @@ static noinline void kvmppc_run_core(struct kvmppc_vcore *vc)
         */
        if ((threads_per_core > 1) &&
            ((vc->num_threads > threads_per_subcore) || !on_primary_thread())) {
-               list_for_each_entry(vcpu, &vc->runnable_threads, arch.run_list) {
+               list_for_each_entry_safe(vcpu, vnext, &vc->runnable_threads,
+                                        arch.run_list) {
                        vcpu->arch.ret = -EBUSY;
                        kvmppc_remove_runnable(vc, vcpu);
                        wake_up(&vcpu->arch.cpu_run);
index 8f3e6cc54d95e1a5b170e8c149db536cbe042308..c6ca7db646735428fb14bde6af9ed1eb68b98351 100644 (file)
@@ -12,6 +12,7 @@
 #include <linux/err.h>
 #include <linux/gfp.h>
 #include <linux/anon_inodes.h>
+#include <linux/spinlock.h>
 
 #include <asm/uaccess.h>
 #include <asm/kvm_book3s.h>
@@ -20,7 +21,6 @@
 #include <asm/xics.h>
 #include <asm/debug.h>
 #include <asm/time.h>
-#include <asm/spinlock.h>
 
 #include <linux/debugfs.h>
 #include <linux/seq_file.h>
index 0ce968b00b7c665967ca3addc26d0cc04a72f729..3385e3d0506ec575f3eeebad77d2c65264a3acf3 100644 (file)
@@ -689,27 +689,34 @@ void hugetlb_free_pgd_range(struct mmu_gather *tlb,
 struct page *
 follow_huge_addr(struct mm_struct *mm, unsigned long address, int write)
 {
-       pte_t *ptep;
-       struct page *page;
+       pte_t *ptep, pte;
        unsigned shift;
        unsigned long mask, flags;
+       struct page *page = ERR_PTR(-EINVAL);
+
+       local_irq_save(flags);
+       ptep = find_linux_pte_or_hugepte(mm->pgd, address, &shift);
+       if (!ptep)
+               goto no_page;
+       pte = READ_ONCE(*ptep);
        /*
+        * Verify it is a huge page else bail.
         * Transparent hugepages are handled by generic code. We can skip them
         * here.
         */
-       local_irq_save(flags);
-       ptep = find_linux_pte_or_hugepte(mm->pgd, address, &shift);
+       if (!shift || pmd_trans_huge(__pmd(pte_val(pte))))
+               goto no_page;
 
-       /* Verify it is a huge page else bail. */
-       if (!ptep || !shift || pmd_trans_huge(*(pmd_t *)ptep)) {
-               local_irq_restore(flags);
-               return ERR_PTR(-EINVAL);
+       if (!pte_present(pte)) {
+               page = NULL;
+               goto no_page;
        }
        mask = (1UL << shift) - 1;
-       page = pte_page(*ptep);
+       page = pte_page(pte);
        if (page)
                page += (address & mask) / PAGE_SIZE;
 
+no_page:
        local_irq_restore(flags);
        return page;
 }
index 59daa5eeec2526ae481a5dda586c629a985813d7..6bfadf1aa5cbbfadbd7237e5f3da8ac8653a5651 100644 (file)
@@ -839,6 +839,17 @@ pmd_t pmdp_get_and_clear(struct mm_struct *mm,
         * hash fault look at them.
         */
        memset(pgtable, 0, PTE_FRAG_SIZE);
+       /*
+        * Serialize against find_linux_pte_or_hugepte which does lock-less
+        * lookup in page tables with local interrupts disabled. For huge pages
+        * it casts pmd_t to pte_t. Since format of pte_t is different from
+        * pmd_t we want to prevent transit from pmd pointing to page table
+        * to pmd pointing to huge page (and back) while interrupts are disabled.
+        * We clear pmd to possibly replace it with page table pointer in
+        * different code paths. So make sure we wait for the parallel
+        * find_linux_pte_or_hugepage to finish.
+        */
+       kick_all_cpus_sync();
        return old_pmd;
 }
 
index 920c252d1f49329616eddb2cf3ba4f2ec1f202b3..f8bc950efcae39a63f213290b65d36fec1667b60 100644 (file)
@@ -2693,7 +2693,6 @@ static void __init pnv_pci_init_ioda_phb(struct device_node *np,
                hose->last_busno = 0xff;
        }
        hose->private_data = phb;
-       hose->controller_ops = pnv_pci_controller_ops;
        phb->hub_id = hub_id;
        phb->opal_id = phb_id;
        phb->type = ioda_type;
@@ -2812,6 +2811,7 @@ static void __init pnv_pci_init_ioda_phb(struct device_node *np,
        pnv_pci_controller_ops.enable_device_hook = pnv_pci_enable_device_hook;
        pnv_pci_controller_ops.window_alignment = pnv_pci_window_alignment;
        pnv_pci_controller_ops.reset_secondary_bus = pnv_pci_reset_secondary_bus;
+       hose->controller_ops = pnv_pci_controller_ops;
 
 #ifdef CONFIG_PCI_IOV
        ppc_md.pcibios_fixup_sriov = pnv_pci_ioda_fixup_iov_resources;
index b4b11096ea8b74c3695c46deff77c25d2409f8f4..019d34aaf054bc843d6a2d5ac531e9207e6c42ab 100644 (file)
@@ -412,6 +412,10 @@ static ssize_t dlpar_cpu_probe(const char *buf, size_t count)
        if (rc)
                return -EINVAL;
 
+       rc = dlpar_acquire_drc(drc_index);
+       if (rc)
+               return -EINVAL;
+
        parent = of_find_node_by_path("/cpus");
        if (!parent)
                return -ENODEV;
@@ -422,12 +426,6 @@ static ssize_t dlpar_cpu_probe(const char *buf, size_t count)
 
        of_node_put(parent);
 
-       rc = dlpar_acquire_drc(drc_index);
-       if (rc) {
-               dlpar_free_cc_nodes(dn);
-               return -EINVAL;
-       }
-
        rc = dlpar_attach_node(dn);
        if (rc) {
                dlpar_release_drc(drc_index);
index 8e58c614c37d7203e39f389ab33e31b8542328c2..b06dc383926846c73e85a6c635ff0fac0a3ddcab 100644 (file)
@@ -115,7 +115,7 @@ config S390
        select HAVE_ARCH_SECCOMP_FILTER
        select HAVE_ARCH_TRACEHOOK
        select HAVE_ARCH_TRANSPARENT_HUGEPAGE
-       select HAVE_BPF_JIT if PACK_STACK && HAVE_MARCH_Z9_109_FEATURES
+       select HAVE_BPF_JIT if PACK_STACK && HAVE_MARCH_Z196_FEATURES
        select HAVE_CMPXCHG_DOUBLE
        select HAVE_CMPXCHG_LOCAL
        select HAVE_DEBUG_KMEMLEAK
index ba3b2aefddf55fa6dfa5a75f947273e0196a65e0..d9c4c313fbc61d5bbf73c8a3c7f88eb74c9d6cee 100644 (file)
@@ -3,9 +3,10 @@
  *
  * Support for s390 cryptographic instructions.
  *
- *   Copyright IBM Corp. 2003, 2007
+ *   Copyright IBM Corp. 2003, 2015
  *   Author(s): Thomas Spatzier
  *             Jan Glauber (jan.glauber@de.ibm.com)
+ *             Harald Freudenberger (freude@de.ibm.com)
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by the Free
 #define CRYPT_S390_MSA 0x1
 #define CRYPT_S390_MSA3        0x2
 #define CRYPT_S390_MSA4        0x4
+#define CRYPT_S390_MSA5        0x8
 
 /* s390 cryptographic operations */
 enum crypt_s390_operations {
-       CRYPT_S390_KM   = 0x0100,
-       CRYPT_S390_KMC  = 0x0200,
-       CRYPT_S390_KIMD = 0x0300,
-       CRYPT_S390_KLMD = 0x0400,
-       CRYPT_S390_KMAC = 0x0500,
-       CRYPT_S390_KMCTR = 0x0600
+       CRYPT_S390_KM    = 0x0100,
+       CRYPT_S390_KMC   = 0x0200,
+       CRYPT_S390_KIMD  = 0x0300,
+       CRYPT_S390_KLMD  = 0x0400,
+       CRYPT_S390_KMAC  = 0x0500,
+       CRYPT_S390_KMCTR = 0x0600,
+       CRYPT_S390_PPNO  = 0x0700
 };
 
 /*
@@ -138,6 +141,16 @@ enum crypt_s390_kmac_func {
        KMAC_TDEA_192 = CRYPT_S390_KMAC | 3
 };
 
+/*
+ * function codes for PPNO (PERFORM PSEUDORANDOM NUMBER
+ * OPERATION) instruction
+ */
+enum crypt_s390_ppno_func {
+       PPNO_QUERY            = CRYPT_S390_PPNO | 0,
+       PPNO_SHA512_DRNG_GEN  = CRYPT_S390_PPNO | 3,
+       PPNO_SHA512_DRNG_SEED = CRYPT_S390_PPNO | 0x83
+};
+
 /**
  * crypt_s390_km:
  * @func: the function code passed to KM; see crypt_s390_km_func
@@ -162,11 +175,11 @@ static inline int crypt_s390_km(long func, void *param,
        int ret;
 
        asm volatile(
-               "0:     .insn   rre,0xb92e0000,%3,%1 \n" /* KM opcode */
-               "1:     brc     1,0b \n" /* handle partial completion */
+               "0:     .insn   rre,0xb92e0000,%3,%1\n" /* KM opcode */
+               "1:     brc     1,0b\n" /* handle partial completion */
                "       la      %0,0\n"
                "2:\n"
-               EX_TABLE(0b,2b) EX_TABLE(1b,2b)
+               EX_TABLE(0b, 2b) EX_TABLE(1b, 2b)
                : "=d" (ret), "+a" (__src), "+d" (__src_len), "+a" (__dest)
                : "d" (__func), "a" (__param), "0" (-1) : "cc", "memory");
        if (ret < 0)
@@ -198,11 +211,11 @@ static inline int crypt_s390_kmc(long func, void *param,
        int ret;
 
        asm volatile(
-               "0:     .insn   rre,0xb92f0000,%3,%1 \n" /* KMC opcode */
-               "1:     brc     1,0b \n" /* handle partial completion */
+               "0:     .insn   rre,0xb92f0000,%3,%1\n" /* KMC opcode */
+               "1:     brc     1,0b\n" /* handle partial completion */
                "       la      %0,0\n"
                "2:\n"
-               EX_TABLE(0b,2b) EX_TABLE(1b,2b)
+               EX_TABLE(0b, 2b) EX_TABLE(1b, 2b)
                : "=d" (ret), "+a" (__src), "+d" (__src_len), "+a" (__dest)
                : "d" (__func), "a" (__param), "0" (-1) : "cc", "memory");
        if (ret < 0)
@@ -233,11 +246,11 @@ static inline int crypt_s390_kimd(long func, void *param,
        int ret;
 
        asm volatile(
-               "0:     .insn   rre,0xb93e0000,%1,%1 \n" /* KIMD opcode */
-               "1:     brc     1,0b \n" /* handle partial completion */
+               "0:     .insn   rre,0xb93e0000,%1,%1\n" /* KIMD opcode */
+               "1:     brc     1,0b\n" /* handle partial completion */
                "       la      %0,0\n"
                "2:\n"
-               EX_TABLE(0b,2b) EX_TABLE(1b,2b)
+               EX_TABLE(0b, 2b) EX_TABLE(1b, 2b)
                : "=d" (ret), "+a" (__src), "+d" (__src_len)
                : "d" (__func), "a" (__param), "0" (-1) : "cc", "memory");
        if (ret < 0)
@@ -267,11 +280,11 @@ static inline int crypt_s390_klmd(long func, void *param,
        int ret;
 
        asm volatile(
-               "0:     .insn   rre,0xb93f0000,%1,%1 \n" /* KLMD opcode */
-               "1:     brc     1,0b \n" /* handle partial completion */
+               "0:     .insn   rre,0xb93f0000,%1,%1\n" /* KLMD opcode */
+               "1:     brc     1,0b\n" /* handle partial completion */
                "       la      %0,0\n"
                "2:\n"
-               EX_TABLE(0b,2b) EX_TABLE(1b,2b)
+               EX_TABLE(0b, 2b) EX_TABLE(1b, 2b)
                : "=d" (ret), "+a" (__src), "+d" (__src_len)
                : "d" (__func), "a" (__param), "0" (-1) : "cc", "memory");
        if (ret < 0)
@@ -302,11 +315,11 @@ static inline int crypt_s390_kmac(long func, void *param,
        int ret;
 
        asm volatile(
-               "0:     .insn   rre,0xb91e0000,%1,%1 \n" /* KLAC opcode */
-               "1:     brc     1,0b \n" /* handle partial completion */
+               "0:     .insn   rre,0xb91e0000,%1,%1\n" /* KLAC opcode */
+               "1:     brc     1,0b\n" /* handle partial completion */
                "       la      %0,0\n"
                "2:\n"
-               EX_TABLE(0b,2b) EX_TABLE(1b,2b)
+               EX_TABLE(0b, 2b) EX_TABLE(1b, 2b)
                : "=d" (ret), "+a" (__src), "+d" (__src_len)
                : "d" (__func), "a" (__param), "0" (-1) : "cc", "memory");
        if (ret < 0)
@@ -340,11 +353,11 @@ static inline int crypt_s390_kmctr(long func, void *param, u8 *dest,
        int ret = -1;
 
        asm volatile(
-               "0:     .insn   rrf,0xb92d0000,%3,%1,%4,0 \n" /* KMCTR opcode */
-               "1:     brc     1,0b \n" /* handle partial completion */
+               "0:     .insn   rrf,0xb92d0000,%3,%1,%4,0\n" /* KMCTR opcode */
+               "1:     brc     1,0b\n" /* handle partial completion */
                "       la      %0,0\n"
                "2:\n"
-               EX_TABLE(0b,2b) EX_TABLE(1b,2b)
+               EX_TABLE(0b, 2b) EX_TABLE(1b, 2b)
                : "+d" (ret), "+a" (__src), "+d" (__src_len), "+a" (__dest),
                  "+a" (__ctr)
                : "d" (__func), "a" (__param) : "cc", "memory");
@@ -353,6 +366,47 @@ static inline int crypt_s390_kmctr(long func, void *param, u8 *dest,
        return (func & CRYPT_S390_FUNC_MASK) ? src_len - __src_len : __src_len;
 }
 
+/**
+ * crypt_s390_ppno:
+ * @func: the function code passed to PPNO; see crypt_s390_ppno_func
+ * @param: address of parameter block; see POP for details on each func
+ * @dest: address of destination memory area
+ * @dest_len: size of destination memory area in bytes
+ * @seed: address of seed data
+ * @seed_len: size of seed data in bytes
+ *
+ * Executes the PPNO (PERFORM PSEUDORANDOM NUMBER OPERATION)
+ * operation of the CPU.
+ *
+ * Returns -1 for failure, 0 for the query func, number of random
+ * bytes stored in dest buffer for generate function
+ */
+static inline int crypt_s390_ppno(long func, void *param,
+                                 u8 *dest, long dest_len,
+                                 const u8 *seed, long seed_len)
+{
+       register long  __func     asm("0") = func & CRYPT_S390_FUNC_MASK;
+       register void *__param    asm("1") = param;    /* param block (240 bytes) */
+       register u8   *__dest     asm("2") = dest;     /* buf for recv random bytes */
+       register long  __dest_len asm("3") = dest_len; /* requested random bytes */
+       register const u8 *__seed asm("4") = seed;     /* buf with seed data */
+       register long  __seed_len asm("5") = seed_len; /* bytes in seed buf */
+       int ret = -1;
+
+       asm volatile (
+               "0:     .insn   rre,0xb93c0000,%1,%5\n" /* PPNO opcode */
+               "1:     brc     1,0b\n"   /* handle partial completion */
+               "       la      %0,0\n"
+               "2:\n"
+               EX_TABLE(0b, 2b) EX_TABLE(1b, 2b)
+               : "+d" (ret), "+a"(__dest), "+d"(__dest_len)
+               : "d"(__func), "a"(__param), "a"(__seed), "d"(__seed_len)
+               : "cc", "memory");
+       if (ret < 0)
+               return ret;
+       return (func & CRYPT_S390_FUNC_MASK) ? dest_len - __dest_len : 0;
+}
+
 /**
  * crypt_s390_func_available:
  * @func: the function code of the specific function; 0 if op in general
@@ -373,6 +427,9 @@ static inline int crypt_s390_func_available(int func,
                return 0;
        if (facility_mask & CRYPT_S390_MSA4 && !test_facility(77))
                return 0;
+       if (facility_mask & CRYPT_S390_MSA5 && !test_facility(57))
+               return 0;
+
        switch (func & CRYPT_S390_OP_MASK) {
        case CRYPT_S390_KM:
                ret = crypt_s390_km(KM_QUERY, &status, NULL, NULL, 0);
@@ -390,8 +447,12 @@ static inline int crypt_s390_func_available(int func,
                ret = crypt_s390_kmac(KMAC_QUERY, &status, NULL, 0);
                break;
        case CRYPT_S390_KMCTR:
-               ret = crypt_s390_kmctr(KMCTR_QUERY, &status, NULL, NULL, 0,
-                                      NULL);
+               ret = crypt_s390_kmctr(KMCTR_QUERY, &status,
+                                      NULL, NULL, 0, NULL);
+               break;
+       case CRYPT_S390_PPNO:
+               ret = crypt_s390_ppno(PPNO_QUERY, &status,
+                                     NULL, 0, NULL, 0);
                break;
        default:
                return 0;
@@ -419,15 +480,14 @@ static inline int crypt_s390_pcc(long func, void *param)
        int ret = -1;
 
        asm volatile(
-               "0:     .insn   rre,0xb92c0000,0,0 \n" /* PCC opcode */
-               "1:     brc     1,0b \n" /* handle partial completion */
+               "0:     .insn   rre,0xb92c0000,0,0\n" /* PCC opcode */
+               "1:     brc     1,0b\n" /* handle partial completion */
                "       la      %0,0\n"
                "2:\n"
-               EX_TABLE(0b,2b) EX_TABLE(1b,2b)
+               EX_TABLE(0b, 2b) EX_TABLE(1b, 2b)
                : "+d" (ret)
                : "d" (__func), "a" (__param) : "cc", "memory");
        return ret;
 }
 
-
 #endif /* _CRYPTO_ARCH_S390_CRYPT_S390_H */
index 7940dc90e80bc6729371ab565bad743b1087ef72..b258110da952d320443d113cdcff38beb14ae432 100644 (file)
 #define GHASH_DIGEST_SIZE      16
 
 struct ghash_ctx {
-       u8 icv[16];
-       u8 key[16];
+       u8 key[GHASH_BLOCK_SIZE];
 };
 
 struct ghash_desc_ctx {
+       u8 icv[GHASH_BLOCK_SIZE];
+       u8 key[GHASH_BLOCK_SIZE];
        u8 buffer[GHASH_BLOCK_SIZE];
        u32 bytes;
 };
@@ -28,8 +29,10 @@ struct ghash_desc_ctx {
 static int ghash_init(struct shash_desc *desc)
 {
        struct ghash_desc_ctx *dctx = shash_desc_ctx(desc);
+       struct ghash_ctx *ctx = crypto_shash_ctx(desc->tfm);
 
        memset(dctx, 0, sizeof(*dctx));
+       memcpy(dctx->key, ctx->key, GHASH_BLOCK_SIZE);
 
        return 0;
 }
@@ -45,7 +48,6 @@ static int ghash_setkey(struct crypto_shash *tfm,
        }
 
        memcpy(ctx->key, key, GHASH_BLOCK_SIZE);
-       memset(ctx->icv, 0, GHASH_BLOCK_SIZE);
 
        return 0;
 }
@@ -54,7 +56,6 @@ static int ghash_update(struct shash_desc *desc,
                         const u8 *src, unsigned int srclen)
 {
        struct ghash_desc_ctx *dctx = shash_desc_ctx(desc);
-       struct ghash_ctx *ctx = crypto_shash_ctx(desc->tfm);
        unsigned int n;
        u8 *buf = dctx->buffer;
        int ret;
@@ -70,7 +71,7 @@ static int ghash_update(struct shash_desc *desc,
                src += n;
 
                if (!dctx->bytes) {
-                       ret = crypt_s390_kimd(KIMD_GHASH, ctx, buf,
+                       ret = crypt_s390_kimd(KIMD_GHASH, dctx, buf,
                                              GHASH_BLOCK_SIZE);
                        if (ret != GHASH_BLOCK_SIZE)
                                return -EIO;
@@ -79,7 +80,7 @@ static int ghash_update(struct shash_desc *desc,
 
        n = srclen & ~(GHASH_BLOCK_SIZE - 1);
        if (n) {
-               ret = crypt_s390_kimd(KIMD_GHASH, ctx, src, n);
+               ret = crypt_s390_kimd(KIMD_GHASH, dctx, src, n);
                if (ret != n)
                        return -EIO;
                src += n;
@@ -94,7 +95,7 @@ static int ghash_update(struct shash_desc *desc,
        return 0;
 }
 
-static int ghash_flush(struct ghash_ctx *ctx, struct ghash_desc_ctx *dctx)
+static int ghash_flush(struct ghash_desc_ctx *dctx)
 {
        u8 *buf = dctx->buffer;
        int ret;
@@ -104,24 +105,24 @@ static int ghash_flush(struct ghash_ctx *ctx, struct ghash_desc_ctx *dctx)
 
                memset(pos, 0, dctx->bytes);
 
-               ret = crypt_s390_kimd(KIMD_GHASH, ctx, buf, GHASH_BLOCK_SIZE);
+               ret = crypt_s390_kimd(KIMD_GHASH, dctx, buf, GHASH_BLOCK_SIZE);
                if (ret != GHASH_BLOCK_SIZE)
                        return -EIO;
+
+               dctx->bytes = 0;
        }
 
-       dctx->bytes = 0;
        return 0;
 }
 
 static int ghash_final(struct shash_desc *desc, u8 *dst)
 {
        struct ghash_desc_ctx *dctx = shash_desc_ctx(desc);
-       struct ghash_ctx *ctx = crypto_shash_ctx(desc->tfm);
        int ret;
 
-       ret = ghash_flush(ctx, dctx);
+       ret = ghash_flush(dctx);
        if (!ret)
-               memcpy(dst, ctx->icv, GHASH_BLOCK_SIZE);
+               memcpy(dst, dctx->icv, GHASH_BLOCK_SIZE);
        return ret;
 }
 
index 94a35a4c1b486c02200f6be510ecafd8a59701c6..9d5192c9496317d490a338e19a69718ef00741dd 100644 (file)
 /*
- * Copyright IBM Corp. 2006, 2007
+ * Copyright IBM Corp. 2006, 2015
  * Author(s): Jan Glauber <jan.glauber@de.ibm.com>
+ *           Harald Freudenberger <freude@de.ibm.com>
  * Driver for the s390 pseudo random number generator
  */
+
+#define KMSG_COMPONENT "prng"
+#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt
+
 #include <linux/fs.h>
+#include <linux/fips.h>
 #include <linux/init.h>
 #include <linux/kernel.h>
+#include <linux/device.h>
 #include <linux/miscdevice.h>
 #include <linux/module.h>
 #include <linux/moduleparam.h>
+#include <linux/mutex.h>
 #include <linux/random.h>
 #include <linux/slab.h>
 #include <asm/debug.h>
 #include <asm/uaccess.h>
+#include <asm/timex.h>
 
 #include "crypt_s390.h"
 
 MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Jan Glauber <jan.glauber@de.ibm.com>");
+MODULE_AUTHOR("IBM Corporation");
 MODULE_DESCRIPTION("s390 PRNG interface");
 
-static int prng_chunk_size = 256;
-module_param(prng_chunk_size, int, S_IRUSR | S_IRGRP | S_IROTH);
+
+#define PRNG_MODE_AUTO   0
+#define PRNG_MODE_TDES   1
+#define PRNG_MODE_SHA512  2
+
+static unsigned int prng_mode = PRNG_MODE_AUTO;
+module_param_named(mode, prng_mode, int, 0);
+MODULE_PARM_DESC(prng_mode, "PRNG mode: 0 - auto, 1 - TDES, 2 - SHA512");
+
+
+#define PRNG_CHUNKSIZE_TDES_MIN   8
+#define PRNG_CHUNKSIZE_TDES_MAX   (64*1024)
+#define PRNG_CHUNKSIZE_SHA512_MIN 64
+#define PRNG_CHUNKSIZE_SHA512_MAX (64*1024)
+
+static unsigned int prng_chunk_size = 256;
+module_param_named(chunksize, prng_chunk_size, int, 0);
 MODULE_PARM_DESC(prng_chunk_size, "PRNG read chunk size in bytes");
 
-static int prng_entropy_limit = 4096;
-module_param(prng_entropy_limit, int, S_IRUSR | S_IRGRP | S_IROTH | S_IWUSR);
-MODULE_PARM_DESC(prng_entropy_limit,
-       "PRNG add entropy after that much bytes were produced");
+
+#define PRNG_RESEED_LIMIT_TDES          4096
+#define PRNG_RESEED_LIMIT_TDES_LOWER    4096
+#define PRNG_RESEED_LIMIT_SHA512       100000
+#define PRNG_RESEED_LIMIT_SHA512_LOWER 10000
+
+static unsigned int prng_reseed_limit;
+module_param_named(reseed_limit, prng_reseed_limit, int, 0);
+MODULE_PARM_DESC(prng_reseed_limit, "PRNG reseed limit");
+
 
 /*
  * Any one who considers arithmetical methods of producing random digits is,
  * of course, in a state of sin. -- John von Neumann
  */
 
-struct s390_prng_data {
-       unsigned long count; /* how many bytes were produced */
-       char *buf;
+static int prng_errorflag;
+
+#define PRNG_GEN_ENTROPY_FAILED  1
+#define PRNG_SELFTEST_FAILED    2
+#define PRNG_INSTANTIATE_FAILED  3
+#define PRNG_SEED_FAILED        4
+#define PRNG_RESEED_FAILED      5
+#define PRNG_GEN_FAILED                 6
+
+struct prng_ws_s {
+       u8  parm_block[32];
+       u32 reseed_counter;
+       u64 byte_counter;
 };
 
-static struct s390_prng_data *p;
+struct ppno_ws_s {
+       u32 res;
+       u32 reseed_counter;
+       u64 stream_bytes;
+       u8  V[112];
+       u8  C[112];
+};
 
-/* copied from libica, use a non-zero initial parameter block */
-static unsigned char parm_block[32] = {
-0x0F,0x2B,0x8E,0x63,0x8C,0x8E,0xD2,0x52,0x64,0xB7,0xA0,0x7B,0x75,0x28,0xB8,0xF4,
-0x75,0x5F,0xD2,0xA6,0x8D,0x97,0x11,0xFF,0x49,0xD8,0x23,0xF3,0x7E,0x21,0xEC,0xA0,
+struct prng_data_s {
+       struct mutex mutex;
+       union {
+               struct prng_ws_s prngws;
+               struct ppno_ws_s ppnows;
+       };
+       u8 *buf;
+       u32 rest;
+       u8 *prev;
 };
 
-static int prng_open(struct inode *inode, struct file *file)
+static struct prng_data_s *prng_data;
+
+/* initial parameter block for tdes mode, copied from libica */
+static const u8 initial_parm_block[32] __initconst = {
+       0x0F, 0x2B, 0x8E, 0x63, 0x8C, 0x8E, 0xD2, 0x52,
+       0x64, 0xB7, 0xA0, 0x7B, 0x75, 0x28, 0xB8, 0xF4,
+       0x75, 0x5F, 0xD2, 0xA6, 0x8D, 0x97, 0x11, 0xFF,
+       0x49, 0xD8, 0x23, 0xF3, 0x7E, 0x21, 0xEC, 0xA0 };
+
+
+/*** helper functions ***/
+
+static int generate_entropy(u8 *ebuf, size_t nbytes)
 {
-       return nonseekable_open(inode, file);
+       int n, ret = 0;
+       u8 *pg, *h, hash[32];
+
+       pg = (u8 *) __get_free_page(GFP_KERNEL);
+       if (!pg) {
+               prng_errorflag = PRNG_GEN_ENTROPY_FAILED;
+               return -ENOMEM;
+       }
+
+       while (nbytes) {
+               /* fill page with urandom bytes */
+               get_random_bytes(pg, PAGE_SIZE);
+               /* exor page with stckf values */
+               for (n = 0; n < PAGE_SIZE / sizeof(u64); n++) {
+                       u64 *p = ((u64 *)pg) + n;
+                       *p ^= get_tod_clock_fast();
+               }
+               n = (nbytes < sizeof(hash)) ? nbytes : sizeof(hash);
+               if (n < sizeof(hash))
+                       h = hash;
+               else
+                       h = ebuf;
+               /* generate sha256 from this page */
+               if (crypt_s390_kimd(KIMD_SHA_256, h,
+                                   pg, PAGE_SIZE) != PAGE_SIZE) {
+                       prng_errorflag = PRNG_GEN_ENTROPY_FAILED;
+                       ret = -EIO;
+                       goto out;
+               }
+               if (n < sizeof(hash))
+                       memcpy(ebuf, hash, n);
+               ret += n;
+               ebuf += n;
+               nbytes -= n;
+       }
+
+out:
+       free_page((unsigned long)pg);
+       return ret;
 }
 
-static void prng_add_entropy(void)
+
+/*** tdes functions ***/
+
+static void prng_tdes_add_entropy(void)
 {
        __u64 entropy[4];
        unsigned int i;
        int ret;
 
        for (i = 0; i < 16; i++) {
-               ret = crypt_s390_kmc(KMC_PRNG, parm_block, (char *)entropy,
-                                    (char *)entropy, sizeof(entropy));
+               ret = crypt_s390_kmc(KMC_PRNG, prng_data->prngws.parm_block,
+                                    (char *)entropy, (char *)entropy,
+                                    sizeof(entropy));
                BUG_ON(ret < 0 || ret != sizeof(entropy));
-               memcpy(parm_block, entropy, sizeof(entropy));
+               memcpy(prng_data->prngws.parm_block, entropy, sizeof(entropy));
        }
 }
 
-static void prng_seed(int nbytes)
+
+static void prng_tdes_seed(int nbytes)
 {
        char buf[16];
        int i = 0;
 
-       BUG_ON(nbytes > 16);
+       BUG_ON(nbytes > sizeof(buf));
+
        get_random_bytes(buf, nbytes);
 
        /* Add the entropy */
        while (nbytes >= 8) {
-               *((__u64 *)parm_block) ^= *((__u64 *)(buf+i));
-               prng_add_entropy();
+               *((__u64 *)prng_data->prngws.parm_block) ^= *((__u64 *)(buf+i));
+               prng_tdes_add_entropy();
                i += 8;
                nbytes -= 8;
        }
-       prng_add_entropy();
+       prng_tdes_add_entropy();
+       prng_data->prngws.reseed_counter = 0;
+}
+
+
+static int __init prng_tdes_instantiate(void)
+{
+       int datalen;
+
+       pr_debug("prng runs in TDES mode with "
+                "chunksize=%d and reseed_limit=%u\n",
+                prng_chunk_size, prng_reseed_limit);
+
+       /* memory allocation, prng_data struct init, mutex init */
+       datalen = sizeof(struct prng_data_s) + prng_chunk_size;
+       prng_data = kzalloc(datalen, GFP_KERNEL);
+       if (!prng_data) {
+               prng_errorflag = PRNG_INSTANTIATE_FAILED;
+               return -ENOMEM;
+       }
+       mutex_init(&prng_data->mutex);
+       prng_data->buf = ((u8 *)prng_data) + sizeof(struct prng_data_s);
+       memcpy(prng_data->prngws.parm_block, initial_parm_block, 32);
+
+       /* initialize the PRNG, add 128 bits of entropy */
+       prng_tdes_seed(16);
+
+       return 0;
 }
 
-static ssize_t prng_read(struct file *file, char __user *ubuf, size_t nbytes,
-                        loff_t *ppos)
+
+static void prng_tdes_deinstantiate(void)
+{
+       pr_debug("The prng module stopped "
+                "after running in triple DES mode\n");
+       kzfree(prng_data);
+}
+
+
+/*** sha512 functions ***/
+
+static int __init prng_sha512_selftest(void)
 {
-       int chunk, n;
+       /* NIST DRBG testvector for Hash Drbg, Sha-512, Count #0 */
+       static const u8 seed[] __initconst = {
+               0x6b, 0x50, 0xa7, 0xd8, 0xf8, 0xa5, 0x5d, 0x7a,
+               0x3d, 0xf8, 0xbb, 0x40, 0xbc, 0xc3, 0xb7, 0x22,
+               0xd8, 0x70, 0x8d, 0xe6, 0x7f, 0xda, 0x01, 0x0b,
+               0x03, 0xc4, 0xc8, 0x4d, 0x72, 0x09, 0x6f, 0x8c,
+               0x3e, 0xc6, 0x49, 0xcc, 0x62, 0x56, 0xd9, 0xfa,
+               0x31, 0xdb, 0x7a, 0x29, 0x04, 0xaa, 0xf0, 0x25 };
+       static const u8 V0[] __initconst = {
+               0x00, 0xad, 0xe3, 0x6f, 0x9a, 0x01, 0xc7, 0x76,
+               0x61, 0x34, 0x35, 0xf5, 0x4e, 0x24, 0x74, 0x22,
+               0x21, 0x9a, 0x29, 0x89, 0xc7, 0x93, 0x2e, 0x60,
+               0x1e, 0xe8, 0x14, 0x24, 0x8d, 0xd5, 0x03, 0xf1,
+               0x65, 0x5d, 0x08, 0x22, 0x72, 0xd5, 0xad, 0x95,
+               0xe1, 0x23, 0x1e, 0x8a, 0xa7, 0x13, 0xd9, 0x2b,
+               0x5e, 0xbc, 0xbb, 0x80, 0xab, 0x8d, 0xe5, 0x79,
+               0xab, 0x5b, 0x47, 0x4e, 0xdd, 0xee, 0x6b, 0x03,
+               0x8f, 0x0f, 0x5c, 0x5e, 0xa9, 0x1a, 0x83, 0xdd,
+               0xd3, 0x88, 0xb2, 0x75, 0x4b, 0xce, 0x83, 0x36,
+               0x57, 0x4b, 0xf1, 0x5c, 0xca, 0x7e, 0x09, 0xc0,
+               0xd3, 0x89, 0xc6, 0xe0, 0xda, 0xc4, 0x81, 0x7e,
+               0x5b, 0xf9, 0xe1, 0x01, 0xc1, 0x92, 0x05, 0xea,
+               0xf5, 0x2f, 0xc6, 0xc6, 0xc7, 0x8f, 0xbc, 0xf4 };
+       static const u8 C0[] __initconst = {
+               0x00, 0xf4, 0xa3, 0xe5, 0xa0, 0x72, 0x63, 0x95,
+               0xc6, 0x4f, 0x48, 0xd0, 0x8b, 0x5b, 0x5f, 0x8e,
+               0x6b, 0x96, 0x1f, 0x16, 0xed, 0xbc, 0x66, 0x94,
+               0x45, 0x31, 0xd7, 0x47, 0x73, 0x22, 0xa5, 0x86,
+               0xce, 0xc0, 0x4c, 0xac, 0x63, 0xb8, 0x39, 0x50,
+               0xbf, 0xe6, 0x59, 0x6c, 0x38, 0x58, 0x99, 0x1f,
+               0x27, 0xa7, 0x9d, 0x71, 0x2a, 0xb3, 0x7b, 0xf9,
+               0xfb, 0x17, 0x86, 0xaa, 0x99, 0x81, 0xaa, 0x43,
+               0xe4, 0x37, 0xd3, 0x1e, 0x6e, 0xe5, 0xe6, 0xee,
+               0xc2, 0xed, 0x95, 0x4f, 0x53, 0x0e, 0x46, 0x8a,
+               0xcc, 0x45, 0xa5, 0xdb, 0x69, 0x0d, 0x81, 0xc9,
+               0x32, 0x92, 0xbc, 0x8f, 0x33, 0xe6, 0xf6, 0x09,
+               0x7c, 0x8e, 0x05, 0x19, 0x0d, 0xf1, 0xb6, 0xcc,
+               0xf3, 0x02, 0x21, 0x90, 0x25, 0xec, 0xed, 0x0e };
+       static const u8 random[] __initconst = {
+               0x95, 0xb7, 0xf1, 0x7e, 0x98, 0x02, 0xd3, 0x57,
+               0x73, 0x92, 0xc6, 0xa9, 0xc0, 0x80, 0x83, 0xb6,
+               0x7d, 0xd1, 0x29, 0x22, 0x65, 0xb5, 0xf4, 0x2d,
+               0x23, 0x7f, 0x1c, 0x55, 0xbb, 0x9b, 0x10, 0xbf,
+               0xcf, 0xd8, 0x2c, 0x77, 0xa3, 0x78, 0xb8, 0x26,
+               0x6a, 0x00, 0x99, 0x14, 0x3b, 0x3c, 0x2d, 0x64,
+               0x61, 0x1e, 0xee, 0xb6, 0x9a, 0xcd, 0xc0, 0x55,
+               0x95, 0x7c, 0x13, 0x9e, 0x8b, 0x19, 0x0c, 0x7a,
+               0x06, 0x95, 0x5f, 0x2c, 0x79, 0x7c, 0x27, 0x78,
+               0xde, 0x94, 0x03, 0x96, 0xa5, 0x01, 0xf4, 0x0e,
+               0x91, 0x39, 0x6a, 0xcf, 0x8d, 0x7e, 0x45, 0xeb,
+               0xdb, 0xb5, 0x3b, 0xbf, 0x8c, 0x97, 0x52, 0x30,
+               0xd2, 0xf0, 0xff, 0x91, 0x06, 0xc7, 0x61, 0x19,
+               0xae, 0x49, 0x8e, 0x7f, 0xbc, 0x03, 0xd9, 0x0f,
+               0x8e, 0x4c, 0x51, 0x62, 0x7a, 0xed, 0x5c, 0x8d,
+               0x42, 0x63, 0xd5, 0xd2, 0xb9, 0x78, 0x87, 0x3a,
+               0x0d, 0xe5, 0x96, 0xee, 0x6d, 0xc7, 0xf7, 0xc2,
+               0x9e, 0x37, 0xee, 0xe8, 0xb3, 0x4c, 0x90, 0xdd,
+               0x1c, 0xf6, 0xa9, 0xdd, 0xb2, 0x2b, 0x4c, 0xbd,
+               0x08, 0x6b, 0x14, 0xb3, 0x5d, 0xe9, 0x3d, 0xa2,
+               0xd5, 0xcb, 0x18, 0x06, 0x69, 0x8c, 0xbd, 0x7b,
+               0xbb, 0x67, 0xbf, 0xe3, 0xd3, 0x1f, 0xd2, 0xd1,
+               0xdb, 0xd2, 0xa1, 0xe0, 0x58, 0xa3, 0xeb, 0x99,
+               0xd7, 0xe5, 0x1f, 0x1a, 0x93, 0x8e, 0xed, 0x5e,
+               0x1c, 0x1d, 0xe2, 0x3a, 0x6b, 0x43, 0x45, 0xd3,
+               0x19, 0x14, 0x09, 0xf9, 0x2f, 0x39, 0xb3, 0x67,
+               0x0d, 0x8d, 0xbf, 0xb6, 0x35, 0xd8, 0xe6, 0xa3,
+               0x69, 0x32, 0xd8, 0x10, 0x33, 0xd1, 0x44, 0x8d,
+               0x63, 0xb4, 0x03, 0xdd, 0xf8, 0x8e, 0x12, 0x1b,
+               0x6e, 0x81, 0x9a, 0xc3, 0x81, 0x22, 0x6c, 0x13,
+               0x21, 0xe4, 0xb0, 0x86, 0x44, 0xf6, 0x72, 0x7c,
+               0x36, 0x8c, 0x5a, 0x9f, 0x7a, 0x4b, 0x3e, 0xe2 };
+
        int ret = 0;
-       int tmp;
+       u8 buf[sizeof(random)];
+       struct ppno_ws_s ws;
+
+       memset(&ws, 0, sizeof(ws));
+
+       /* initial seed */
+       ret = crypt_s390_ppno(PPNO_SHA512_DRNG_SEED,
+                             &ws, NULL, 0,
+                             seed, sizeof(seed));
+       if (ret < 0) {
+               pr_err("The prng self test seed operation for the "
+                      "SHA-512 mode failed with rc=%d\n", ret);
+               prng_errorflag = PRNG_SELFTEST_FAILED;
+               return -EIO;
+       }
+
+       /* check working states V and C */
+       if (memcmp(ws.V, V0, sizeof(V0)) != 0
+           || memcmp(ws.C, C0, sizeof(C0)) != 0) {
+               pr_err("The prng self test state test "
+                      "for the SHA-512 mode failed\n");
+               prng_errorflag = PRNG_SELFTEST_FAILED;
+               return -EIO;
+       }
+
+       /* generate random bytes */
+       ret = crypt_s390_ppno(PPNO_SHA512_DRNG_GEN,
+                             &ws, buf, sizeof(buf),
+                             NULL, 0);
+       if (ret < 0) {
+               pr_err("The prng self test generate operation for "
+                      "the SHA-512 mode failed with rc=%d\n", ret);
+               prng_errorflag = PRNG_SELFTEST_FAILED;
+               return -EIO;
+       }
+       ret = crypt_s390_ppno(PPNO_SHA512_DRNG_GEN,
+                             &ws, buf, sizeof(buf),
+                             NULL, 0);
+       if (ret < 0) {
+               pr_err("The prng self test generate operation for "
+                      "the SHA-512 mode failed with rc=%d\n", ret);
+               prng_errorflag = PRNG_SELFTEST_FAILED;
+               return -EIO;
+       }
+
+       /* check against expected data */
+       if (memcmp(buf, random, sizeof(random)) != 0) {
+               pr_err("The prng self test data test "
+                      "for the SHA-512 mode failed\n");
+               prng_errorflag = PRNG_SELFTEST_FAILED;
+               return -EIO;
+       }
+
+       return 0;
+}
+
+
+static int __init prng_sha512_instantiate(void)
+{
+       int ret, datalen;
+       u8 seed[64];
+
+       pr_debug("prng runs in SHA-512 mode "
+                "with chunksize=%d and reseed_limit=%u\n",
+                prng_chunk_size, prng_reseed_limit);
+
+       /* memory allocation, prng_data struct init, mutex init */
+       datalen = sizeof(struct prng_data_s) + prng_chunk_size;
+       if (fips_enabled)
+               datalen += prng_chunk_size;
+       prng_data = kzalloc(datalen, GFP_KERNEL);
+       if (!prng_data) {
+               prng_errorflag = PRNG_INSTANTIATE_FAILED;
+               return -ENOMEM;
+       }
+       mutex_init(&prng_data->mutex);
+       prng_data->buf = ((u8 *)prng_data) + sizeof(struct prng_data_s);
+
+       /* selftest */
+       ret = prng_sha512_selftest();
+       if (ret)
+               goto outfree;
+
+       /* generate initial seed bytestring, first 48 bytes of entropy */
+       ret = generate_entropy(seed, 48);
+       if (ret != 48)
+               goto outfree;
+       /* followed by 16 bytes of unique nonce */
+       get_tod_clock_ext(seed + 48);
+
+       /* initial seed of the ppno drng */
+       ret = crypt_s390_ppno(PPNO_SHA512_DRNG_SEED,
+                             &prng_data->ppnows, NULL, 0,
+                             seed, sizeof(seed));
+       if (ret < 0) {
+               prng_errorflag = PRNG_SEED_FAILED;
+               ret = -EIO;
+               goto outfree;
+       }
+
+       /* if fips mode is enabled, generate a first block of random
+          bytes for the FIPS 140-2 Conditional Self Test */
+       if (fips_enabled) {
+               prng_data->prev = prng_data->buf + prng_chunk_size;
+               ret = crypt_s390_ppno(PPNO_SHA512_DRNG_GEN,
+                                     &prng_data->ppnows,
+                                     prng_data->prev,
+                                     prng_chunk_size,
+                                     NULL, 0);
+               if (ret < 0 || ret != prng_chunk_size) {
+                       prng_errorflag = PRNG_GEN_FAILED;
+                       ret = -EIO;
+                       goto outfree;
+               }
+       }
+
+       return 0;
+
+outfree:
+       kfree(prng_data);
+       return ret;
+}
+
+
+static void prng_sha512_deinstantiate(void)
+{
+       pr_debug("The prng module stopped after running in SHA-512 mode\n");
+       kzfree(prng_data);
+}
+
+
+static int prng_sha512_reseed(void)
+{
+       int ret;
+       u8 seed[32];
+
+       /* generate 32 bytes of fresh entropy */
+       ret = generate_entropy(seed, sizeof(seed));
+       if (ret != sizeof(seed))
+               return ret;
+
+       /* do a reseed of the ppno drng with this bytestring */
+       ret = crypt_s390_ppno(PPNO_SHA512_DRNG_SEED,
+                             &prng_data->ppnows, NULL, 0,
+                             seed, sizeof(seed));
+       if (ret) {
+               prng_errorflag = PRNG_RESEED_FAILED;
+               return -EIO;
+       }
+
+       return 0;
+}
+
+
+static int prng_sha512_generate(u8 *buf, size_t nbytes)
+{
+       int ret;
+
+       /* reseed needed ? */
+       if (prng_data->ppnows.reseed_counter > prng_reseed_limit) {
+               ret = prng_sha512_reseed();
+               if (ret)
+                       return ret;
+       }
+
+       /* PPNO generate */
+       ret = crypt_s390_ppno(PPNO_SHA512_DRNG_GEN,
+                             &prng_data->ppnows, buf, nbytes,
+                             NULL, 0);
+       if (ret < 0 || ret != nbytes) {
+               prng_errorflag = PRNG_GEN_FAILED;
+               return -EIO;
+       }
+
+       /* FIPS 140-2 Conditional Self Test */
+       if (fips_enabled) {
+               if (!memcmp(prng_data->prev, buf, nbytes)) {
+                       prng_errorflag = PRNG_GEN_FAILED;
+                       return -EILSEQ;
+               }
+               memcpy(prng_data->prev, buf, nbytes);
+       }
+
+       return ret;
+}
+
+
+/*** file io functions ***/
+
+static int prng_open(struct inode *inode, struct file *file)
+{
+       return nonseekable_open(inode, file);
+}
+
+
+static ssize_t prng_tdes_read(struct file *file, char __user *ubuf,
+                             size_t nbytes, loff_t *ppos)
+{
+       int chunk, n, tmp, ret = 0;
+
+       /* lock prng_data struct */
+       if (mutex_lock_interruptible(&prng_data->mutex))
+               return -ERESTARTSYS;
 
-       /* nbytes can be arbitrary length, we split it into chunks */
        while (nbytes) {
-               /* same as in extract_entropy_user in random.c */
                if (need_resched()) {
                        if (signal_pending(current)) {
                                if (ret == 0)
                                        ret = -ERESTARTSYS;
                                break;
                        }
+                       /* give mutex free before calling schedule() */
+                       mutex_unlock(&prng_data->mutex);
                        schedule();
+                       /* occopy mutex again */
+                       if (mutex_lock_interruptible(&prng_data->mutex)) {
+                               if (ret == 0)
+                                       ret = -ERESTARTSYS;
+                               return ret;
+                       }
                }
 
                /*
@@ -112,12 +535,11 @@ static ssize_t prng_read(struct file *file, char __user *ubuf, size_t nbytes,
                /* PRNG only likes multiples of 8 bytes */
                n = (chunk + 7) & -8;
 
-               if (p->count > prng_entropy_limit)
-                       prng_seed(8);
+               if (prng_data->prngws.reseed_counter > prng_reseed_limit)
+                       prng_tdes_seed(8);
 
                /* if the CPU supports PRNG stckf is present too */
-               asm volatile(".insn     s,0xb27c0000,%0"
-                            : "=m" (*((unsigned long long *)p->buf)) : : "cc");
+               *((unsigned long long *)prng_data->buf) = get_tod_clock_fast();
 
                /*
                 * Beside the STCKF the input for the TDES-EDE is the output
@@ -132,35 +554,259 @@ static ssize_t prng_read(struct file *file, char __user *ubuf, size_t nbytes,
                 * Note: you can still get strict X9.17 conformity by setting
                 * prng_chunk_size to 8 bytes.
                */
-               tmp = crypt_s390_kmc(KMC_PRNG, parm_block, p->buf, p->buf, n);
-               BUG_ON((tmp < 0) || (tmp != n));
+               tmp = crypt_s390_kmc(KMC_PRNG, prng_data->prngws.parm_block,
+                                    prng_data->buf, prng_data->buf, n);
+               if (tmp < 0 || tmp != n) {
+                       ret = -EIO;
+                       break;
+               }
 
-               p->count += n;
+               prng_data->prngws.byte_counter += n;
+               prng_data->prngws.reseed_counter += n;
 
-               if (copy_to_user(ubuf, p->buf, chunk))
+               if (copy_to_user(ubuf, prng_data->buf, chunk))
                        return -EFAULT;
 
                nbytes -= chunk;
                ret += chunk;
                ubuf += chunk;
        }
+
+       /* unlock prng_data struct */
+       mutex_unlock(&prng_data->mutex);
+
        return ret;
 }
 
-static const struct file_operations prng_fops = {
+
+static ssize_t prng_sha512_read(struct file *file, char __user *ubuf,
+                               size_t nbytes, loff_t *ppos)
+{
+       int n, ret = 0;
+       u8 *p;
+
+       /* if errorflag is set do nothing and return 'broken pipe' */
+       if (prng_errorflag)
+               return -EPIPE;
+
+       /* lock prng_data struct */
+       if (mutex_lock_interruptible(&prng_data->mutex))
+               return -ERESTARTSYS;
+
+       while (nbytes) {
+               if (need_resched()) {
+                       if (signal_pending(current)) {
+                               if (ret == 0)
+                                       ret = -ERESTARTSYS;
+                               break;
+                       }
+                       /* give mutex free before calling schedule() */
+                       mutex_unlock(&prng_data->mutex);
+                       schedule();
+                       /* occopy mutex again */
+                       if (mutex_lock_interruptible(&prng_data->mutex)) {
+                               if (ret == 0)
+                                       ret = -ERESTARTSYS;
+                               return ret;
+                       }
+               }
+               if (prng_data->rest) {
+                       /* push left over random bytes from the previous read */
+                       p = prng_data->buf + prng_chunk_size - prng_data->rest;
+                       n = (nbytes < prng_data->rest) ?
+                               nbytes : prng_data->rest;
+                       prng_data->rest -= n;
+               } else {
+                       /* generate one chunk of random bytes into read buf */
+                       p = prng_data->buf;
+                       n = prng_sha512_generate(p, prng_chunk_size);
+                       if (n < 0) {
+                               ret = n;
+                               break;
+                       }
+                       if (nbytes < prng_chunk_size) {
+                               n = nbytes;
+                               prng_data->rest = prng_chunk_size - n;
+                       } else {
+                               n = prng_chunk_size;
+                               prng_data->rest = 0;
+                       }
+               }
+               if (copy_to_user(ubuf, p, n)) {
+                       ret = -EFAULT;
+                       break;
+               }
+               ubuf += n;
+               nbytes -= n;
+               ret += n;
+       }
+
+       /* unlock prng_data struct */
+       mutex_unlock(&prng_data->mutex);
+
+       return ret;
+}
+
+
+/*** sysfs stuff ***/
+
+static const struct file_operations prng_sha512_fops = {
+       .owner          = THIS_MODULE,
+       .open           = &prng_open,
+       .release        = NULL,
+       .read           = &prng_sha512_read,
+       .llseek         = noop_llseek,
+};
+static const struct file_operations prng_tdes_fops = {
        .owner          = THIS_MODULE,
        .open           = &prng_open,
        .release        = NULL,
-       .read           = &prng_read,
+       .read           = &prng_tdes_read,
        .llseek         = noop_llseek,
 };
 
-static struct miscdevice prng_dev = {
+static struct miscdevice prng_sha512_dev = {
+       .name   = "prandom",
+       .minor  = MISC_DYNAMIC_MINOR,
+       .fops   = &prng_sha512_fops,
+};
+static struct miscdevice prng_tdes_dev = {
        .name   = "prandom",
        .minor  = MISC_DYNAMIC_MINOR,
-       .fops   = &prng_fops,
+       .fops   = &prng_tdes_fops,
 };
 
+
+/* chunksize attribute (ro) */
+static ssize_t prng_chunksize_show(struct device *dev,
+                                  struct device_attribute *attr,
+                                  char *buf)
+{
+       return snprintf(buf, PAGE_SIZE, "%u\n", prng_chunk_size);
+}
+static DEVICE_ATTR(chunksize, 0444, prng_chunksize_show, NULL);
+
+/* counter attribute (ro) */
+static ssize_t prng_counter_show(struct device *dev,
+                                struct device_attribute *attr,
+                                char *buf)
+{
+       u64 counter;
+
+       if (mutex_lock_interruptible(&prng_data->mutex))
+               return -ERESTARTSYS;
+       if (prng_mode == PRNG_MODE_SHA512)
+               counter = prng_data->ppnows.stream_bytes;
+       else
+               counter = prng_data->prngws.byte_counter;
+       mutex_unlock(&prng_data->mutex);
+
+       return snprintf(buf, PAGE_SIZE, "%llu\n", counter);
+}
+static DEVICE_ATTR(byte_counter, 0444, prng_counter_show, NULL);
+
+/* errorflag attribute (ro) */
+static ssize_t prng_errorflag_show(struct device *dev,
+                                  struct device_attribute *attr,
+                                  char *buf)
+{
+       return snprintf(buf, PAGE_SIZE, "%d\n", prng_errorflag);
+}
+static DEVICE_ATTR(errorflag, 0444, prng_errorflag_show, NULL);
+
+/* mode attribute (ro) */
+static ssize_t prng_mode_show(struct device *dev,
+                             struct device_attribute *attr,
+                             char *buf)
+{
+       if (prng_mode == PRNG_MODE_TDES)
+               return snprintf(buf, PAGE_SIZE, "TDES\n");
+       else
+               return snprintf(buf, PAGE_SIZE, "SHA512\n");
+}
+static DEVICE_ATTR(mode, 0444, prng_mode_show, NULL);
+
+/* reseed attribute (w) */
+static ssize_t prng_reseed_store(struct device *dev,
+                                struct device_attribute *attr,
+                                const char *buf, size_t count)
+{
+       if (mutex_lock_interruptible(&prng_data->mutex))
+               return -ERESTARTSYS;
+       prng_sha512_reseed();
+       mutex_unlock(&prng_data->mutex);
+
+       return count;
+}
+static DEVICE_ATTR(reseed, 0200, NULL, prng_reseed_store);
+
+/* reseed limit attribute (rw) */
+static ssize_t prng_reseed_limit_show(struct device *dev,
+                                     struct device_attribute *attr,
+                                     char *buf)
+{
+       return snprintf(buf, PAGE_SIZE, "%u\n", prng_reseed_limit);
+}
+static ssize_t prng_reseed_limit_store(struct device *dev,
+                                      struct device_attribute *attr,
+                                      const char *buf, size_t count)
+{
+       unsigned limit;
+
+       if (sscanf(buf, "%u\n", &limit) != 1)
+               return -EINVAL;
+
+       if (prng_mode == PRNG_MODE_SHA512) {
+               if (limit < PRNG_RESEED_LIMIT_SHA512_LOWER)
+                       return -EINVAL;
+       } else {
+               if (limit < PRNG_RESEED_LIMIT_TDES_LOWER)
+                       return -EINVAL;
+       }
+
+       prng_reseed_limit = limit;
+
+       return count;
+}
+static DEVICE_ATTR(reseed_limit, 0644,
+                  prng_reseed_limit_show, prng_reseed_limit_store);
+
+/* strength attribute (ro) */
+static ssize_t prng_strength_show(struct device *dev,
+                                 struct device_attribute *attr,
+                                 char *buf)
+{
+       return snprintf(buf, PAGE_SIZE, "256\n");
+}
+static DEVICE_ATTR(strength, 0444, prng_strength_show, NULL);
+
+static struct attribute *prng_sha512_dev_attrs[] = {
+       &dev_attr_errorflag.attr,
+       &dev_attr_chunksize.attr,
+       &dev_attr_byte_counter.attr,
+       &dev_attr_mode.attr,
+       &dev_attr_reseed.attr,
+       &dev_attr_reseed_limit.attr,
+       &dev_attr_strength.attr,
+       NULL
+};
+static struct attribute *prng_tdes_dev_attrs[] = {
+       &dev_attr_chunksize.attr,
+       &dev_attr_byte_counter.attr,
+       &dev_attr_mode.attr,
+       NULL
+};
+
+static struct attribute_group prng_sha512_dev_attr_group = {
+       .attrs = prng_sha512_dev_attrs
+};
+static struct attribute_group prng_tdes_dev_attr_group = {
+       .attrs = prng_tdes_dev_attrs
+};
+
+
+/*** module init and exit ***/
+
 static int __init prng_init(void)
 {
        int ret;
@@ -169,43 +815,105 @@ static int __init prng_init(void)
        if (!crypt_s390_func_available(KMC_PRNG, CRYPT_S390_MSA))
                return -EOPNOTSUPP;
 
-       if (prng_chunk_size < 8)
-               return -EINVAL;
+       /* choose prng mode */
+       if (prng_mode != PRNG_MODE_TDES) {
+               /* check for MSA5 support for PPNO operations */
+               if (!crypt_s390_func_available(PPNO_SHA512_DRNG_GEN,
+                                              CRYPT_S390_MSA5)) {
+                       if (prng_mode == PRNG_MODE_SHA512) {
+                               pr_err("The prng module cannot "
+                                      "start in SHA-512 mode\n");
+                               return -EOPNOTSUPP;
+                       }
+                       prng_mode = PRNG_MODE_TDES;
+               } else
+                       prng_mode = PRNG_MODE_SHA512;
+       }
 
-       p = kmalloc(sizeof(struct s390_prng_data), GFP_KERNEL);
-       if (!p)
-               return -ENOMEM;
-       p->count = 0;
+       if (prng_mode == PRNG_MODE_SHA512) {
 
-       p->buf = kmalloc(prng_chunk_size, GFP_KERNEL);
-       if (!p->buf) {
-               ret = -ENOMEM;
-               goto out_free;
-       }
+               /* SHA512 mode */
 
-       /* initialize the PRNG, add 128 bits of entropy */
-       prng_seed(16);
+               if (prng_chunk_size < PRNG_CHUNKSIZE_SHA512_MIN
+                   || prng_chunk_size > PRNG_CHUNKSIZE_SHA512_MAX)
+                       return -EINVAL;
+               prng_chunk_size = (prng_chunk_size + 0x3f) & ~0x3f;
 
-       ret = misc_register(&prng_dev);
-       if (ret)
-               goto out_buf;
-       return 0;
+               if (prng_reseed_limit == 0)
+                       prng_reseed_limit = PRNG_RESEED_LIMIT_SHA512;
+               else if (prng_reseed_limit < PRNG_RESEED_LIMIT_SHA512_LOWER)
+                       return -EINVAL;
+
+               ret = prng_sha512_instantiate();
+               if (ret)
+                       goto out;
+
+               ret = misc_register(&prng_sha512_dev);
+               if (ret) {
+                       prng_sha512_deinstantiate();
+                       goto out;
+               }
+               ret = sysfs_create_group(&prng_sha512_dev.this_device->kobj,
+                                        &prng_sha512_dev_attr_group);
+               if (ret) {
+                       misc_deregister(&prng_sha512_dev);
+                       prng_sha512_deinstantiate();
+                       goto out;
+               }
 
-out_buf:
-       kfree(p->buf);
-out_free:
-       kfree(p);
+       } else {
+
+               /* TDES mode */
+
+               if (prng_chunk_size < PRNG_CHUNKSIZE_TDES_MIN
+                   || prng_chunk_size > PRNG_CHUNKSIZE_TDES_MAX)
+                       return -EINVAL;
+               prng_chunk_size = (prng_chunk_size + 0x07) & ~0x07;
+
+               if (prng_reseed_limit == 0)
+                       prng_reseed_limit = PRNG_RESEED_LIMIT_TDES;
+               else if (prng_reseed_limit < PRNG_RESEED_LIMIT_TDES_LOWER)
+                       return -EINVAL;
+
+               ret = prng_tdes_instantiate();
+               if (ret)
+                       goto out;
+
+               ret = misc_register(&prng_tdes_dev);
+               if (ret) {
+                       prng_tdes_deinstantiate();
+                       goto out;
+               }
+               ret = sysfs_create_group(&prng_tdes_dev.this_device->kobj,
+                                        &prng_tdes_dev_attr_group);
+               if (ret) {
+                       misc_deregister(&prng_tdes_dev);
+                       prng_tdes_deinstantiate();
+                       goto out;
+               }
+
+       }
+
+out:
        return ret;
 }
 
+
 static void __exit prng_exit(void)
 {
-       /* wipe me */
-       kzfree(p->buf);
-       kfree(p);
-
-       misc_deregister(&prng_dev);
+       if (prng_mode == PRNG_MODE_SHA512) {
+               sysfs_remove_group(&prng_sha512_dev.this_device->kobj,
+                                  &prng_sha512_dev_attr_group);
+               misc_deregister(&prng_sha512_dev);
+               prng_sha512_deinstantiate();
+       } else {
+               sysfs_remove_group(&prng_tdes_dev.this_device->kobj,
+                                  &prng_tdes_dev_attr_group);
+               misc_deregister(&prng_tdes_dev);
+               prng_tdes_deinstantiate();
+       }
 }
 
+
 module_init(prng_init);
 module_exit(prng_exit);
index 694bcd6bd927bff60bf76ceede7a222877e02999..2f924bc30e358542201bdde082ab6d0289f3403c 100644 (file)
@@ -26,6 +26,9 @@
 /* Not more than 2GB */
 #define KEXEC_CONTROL_MEMORY_LIMIT (1UL<<31)
 
+/* Allocate control page with GFP_DMA */
+#define KEXEC_CONTROL_MEMORY_GFP GFP_DMA
+
 /* Maximum address we can use for the crash control pages */
 #define KEXEC_CRASH_CONTROL_MEMORY_LIMIT (-1UL)
 
index a5e656260a70183dd4f3768c3be082fed5988603..d29ad9545b4187a18c660e1ad62922b052447478 100644 (file)
@@ -14,7 +14,9 @@ typedef struct {
        unsigned long asce_bits;
        unsigned long asce_limit;
        unsigned long vdso_base;
-       /* The mmu context has extended page tables. */
+       /* The mmu context allocates 4K page tables. */
+       unsigned int alloc_pgste:1;
+       /* The mmu context uses extended page tables. */
        unsigned int has_pgste:1;
        /* The mmu context uses storage keys. */
        unsigned int use_skey:1;
index d25d9ff10ba8fe2e2d7e53fea8c2a73b16facf61..fb1b93ea3e3fead0efde9f30e819c55eecb88da9 100644 (file)
@@ -20,8 +20,11 @@ static inline int init_new_context(struct task_struct *tsk,
        mm->context.flush_mm = 0;
        mm->context.asce_bits = _ASCE_TABLE_LENGTH | _ASCE_USER_BITS;
        mm->context.asce_bits |= _ASCE_TYPE_REGION3;
+#ifdef CONFIG_PGSTE
+       mm->context.alloc_pgste = page_table_allocate_pgste;
        mm->context.has_pgste = 0;
        mm->context.use_skey = 0;
+#endif
        mm->context.asce_limit = STACK_TOP_MAX;
        crst_table_init((unsigned long *) mm->pgd, pgd_entry_type(mm));
        return 0;
index 51e7fb634ebc1e6bab2bfdac3655443096296ad3..7b7858f158b4574b549ab99648f977a3e249068c 100644 (file)
@@ -21,6 +21,7 @@ void crst_table_free(struct mm_struct *, unsigned long *);
 unsigned long *page_table_alloc(struct mm_struct *);
 void page_table_free(struct mm_struct *, unsigned long *);
 void page_table_free_rcu(struct mmu_gather *, unsigned long *, unsigned long);
+extern int page_table_allocate_pgste;
 
 int set_guest_storage_key(struct mm_struct *mm, unsigned long addr,
                          unsigned long key, bool nq);
index 989cfae9e202cf1d5adfdd894af3324997aec65a..ef24a212eeb727b8d8df3326115ef17dbeb0a272 100644 (file)
 #define _ASM_S390_PGTABLE_H
 
 /*
- * The Linux memory management assumes a three-level page table setup. For
- * s390 31 bit we "fold" the mid level into the top-level page table, so
- * that we physically have the same two-level page table as the s390 mmu
- * expects in 31 bit mode. For s390 64 bit we use three of the five levels
- * the hardware provides (region first and region second tables are not
- * used).
+ * The Linux memory management assumes a three-level page table setup.
+ * For s390 64 bit we use up to four of the five levels the hardware
+ * provides (region first tables are not used).
  *
  * The "pgd_xxx()" functions are trivial for a folded two-level
  * setup: the pgd is never bad, and a pmd always exists (as it's folded
@@ -101,8 +98,8 @@ extern unsigned long zero_page_mask;
 
 #ifndef __ASSEMBLY__
 /*
- * The vmalloc and module area will always be on the topmost area of the kernel
- * mapping. We reserve 96MB (31bit) / 128GB (64bit) for vmalloc and modules.
+ * The vmalloc and module area will always be on the topmost area of the
+ * kernel mapping. We reserve 128GB (64bit) for vmalloc and modules.
  * On 64 bit kernels we have a 2GB area at the top of the vmalloc area where
  * modules will reside. That makes sure that inter module branches always
  * happen without trampolines and in addition the placement within a 2GB frame
@@ -131,38 +128,6 @@ static inline int is_module_addr(void *addr)
 }
 
 /*
- * A 31 bit pagetable entry of S390 has following format:
- *  |   PFRA          |    |  OS  |
- * 0                   0IP0
- * 00000000001111111111222222222233
- * 01234567890123456789012345678901
- *
- * I Page-Invalid Bit:    Page is not available for address-translation
- * P Page-Protection Bit: Store access not possible for page
- *
- * A 31 bit segmenttable entry of S390 has following format:
- *  |   P-table origin      |  |PTL
- * 0                         IC
- * 00000000001111111111222222222233
- * 01234567890123456789012345678901
- *
- * I Segment-Invalid Bit:    Segment is not available for address-translation
- * C Common-Segment Bit:     Segment is not private (PoP 3-30)
- * PTL Page-Table-Length:    Page-table length (PTL+1*16 entries -> up to 256)
- *
- * The 31 bit segmenttable origin of S390 has following format:
- *
- *  |S-table origin   |     | STL |
- * X                   **GPS
- * 00000000001111111111222222222233
- * 01234567890123456789012345678901
- *
- * X Space-Switch event:
- * G Segment-Invalid Bit:     *
- * P Private-Space Bit:       Segment is not private (PoP 3-30)
- * S Storage-Alteration:
- * STL Segment-Table-Length:  Segment-table length (STL+1*16 entries -> up to 2048)
- *
  * A 64 bit pagetable entry of S390 has following format:
  * |                    PFRA                         |0IPC|  OS  |
  * 0000000000111111111122222222223333333333444444444455555555556666
@@ -220,7 +185,6 @@ static inline int is_module_addr(void *addr)
 
 /* Software bits in the page table entry */
 #define _PAGE_PRESENT  0x001           /* SW pte present bit */
-#define _PAGE_TYPE     0x002           /* SW pte type bit */
 #define _PAGE_YOUNG    0x004           /* SW pte young bit */
 #define _PAGE_DIRTY    0x008           /* SW pte dirty bit */
 #define _PAGE_READ     0x010           /* SW pte read bit */
@@ -240,31 +204,34 @@ static inline int is_module_addr(void *addr)
  * table lock held.
  *
  * The following table gives the different possible bit combinations for
- * the pte hardware and software bits in the last 12 bits of a pte:
+ * the pte hardware and software bits in the last 12 bits of a pte
+ * (. unassigned bit, x don't care, t swap type):
  *
  *                             842100000000
  *                             000084210000
  *                             000000008421
- *                             .IR...wrdytp
- * empty                       .10...000000
- * swap                                .10...xxxx10
- * file                                .11...xxxxx0
- * prot-none, clean, old       .11...000001
- * prot-none, clean, young     .11...000101
- * prot-none, dirty, old       .10...001001
- * prot-none, dirty, young     .10...001101
- * read-only, clean, old       .11...010001
- * read-only, clean, young     .01...010101
- * read-only, dirty, old       .11...011001
- * read-only, dirty, young     .01...011101
- * read-write, clean, old      .11...110001
- * read-write, clean, young    .01...110101
- * read-write, dirty, old      .10...111001
- * read-write, dirty, young    .00...111101
+ *                             .IR.uswrdy.p
+ * empty                       .10.00000000
+ * swap                                .11..ttttt.0
+ * prot-none, clean, old       .11.xx0000.1
+ * prot-none, clean, young     .11.xx0001.1
+ * prot-none, dirty, old       .10.xx0010.1
+ * prot-none, dirty, young     .10.xx0011.1
+ * read-only, clean, old       .11.xx0100.1
+ * read-only, clean, young     .01.xx0101.1
+ * read-only, dirty, old       .11.xx0110.1
+ * read-only, dirty, young     .01.xx0111.1
+ * read-write, clean, old      .11.xx1100.1
+ * read-write, clean, young    .01.xx1101.1
+ * read-write, dirty, old      .10.xx1110.1
+ * read-write, dirty, young    .00.xx1111.1
+ * HW-bits: R read-only, I invalid
+ * SW-bits: p present, y young, d dirty, r read, w write, s special,
+ *         u unused, l large
  *
- * pte_present is true for the bit pattern .xx...xxxxx1, (pte & 0x001) == 0x001
- * pte_none    is true for the bit pattern .10...xxxx00, (pte & 0x603) == 0x400
- * pte_swap    is true for the bit pattern .10...xxxx10, (pte & 0x603) == 0x402
+ * pte_none    is true for the bit pattern .10.00000000, pte == 0x400
+ * pte_swap    is true for the bit pattern .11..ooooo.0, (pte & 0x201) == 0x200
+ * pte_present is true for the bit pattern .xx.xxxxxx.1, (pte & 0x001) == 0x001
  */
 
 /* Bits in the segment/region table address-space-control-element */
@@ -335,6 +302,8 @@ static inline int is_module_addr(void *addr)
  * read-write, dirty, young    11..0...0...11
  * The segment table origin is used to distinguish empty (origin==0) from
  * read-write, old segment table entries (origin!=0)
+ * HW-bits: R read-only, I invalid
+ * SW-bits: y young, d dirty, r read, w write
  */
 
 #define _SEGMENT_ENTRY_SPLIT_BIT 11    /* THP splitting bit number */
@@ -423,6 +392,15 @@ static inline int mm_has_pgste(struct mm_struct *mm)
        return 0;
 }
 
+static inline int mm_alloc_pgste(struct mm_struct *mm)
+{
+#ifdef CONFIG_PGSTE
+       if (unlikely(mm->context.alloc_pgste))
+               return 1;
+#endif
+       return 0;
+}
+
 /*
  * In the case that a guest uses storage keys
  * faults should no longer be backed by zero pages
@@ -516,7 +494,7 @@ static inline int pmd_large(pmd_t pmd)
        return (pmd_val(pmd) & _SEGMENT_ENTRY_LARGE) != 0;
 }
 
-static inline int pmd_pfn(pmd_t pmd)
+static inline unsigned long pmd_pfn(pmd_t pmd)
 {
        unsigned long origin_mask;
 
@@ -582,10 +560,9 @@ static inline int pte_none(pte_t pte)
 
 static inline int pte_swap(pte_t pte)
 {
-       /* Bit pattern: (pte & 0x603) == 0x402 */
-       return (pte_val(pte) & (_PAGE_INVALID | _PAGE_PROTECT |
-                               _PAGE_TYPE | _PAGE_PRESENT))
-               == (_PAGE_INVALID | _PAGE_TYPE);
+       /* Bit pattern: (pte & 0x201) == 0x200 */
+       return (pte_val(pte) & (_PAGE_PROTECT | _PAGE_PRESENT))
+               == _PAGE_PROTECT;
 }
 
 static inline int pte_special(pte_t pte)
@@ -1586,51 +1563,51 @@ static inline int has_transparent_hugepage(void)
 #endif /* CONFIG_TRANSPARENT_HUGEPAGE */
 
 /*
- * 31 bit swap entry format:
- * A page-table entry has some bits we have to treat in a special way.
- * Bits 0, 20 and bit 23 have to be zero, otherwise an specification
- * exception will occur instead of a page translation exception. The
- * specifiation exception has the bad habit not to store necessary
- * information in the lowcore.
- * Bits 21, 22, 30 and 31 are used to indicate the page type.
- * A swap pte is indicated by bit pattern (pte & 0x603) == 0x402
- * This leaves the bits 1-19 and bits 24-29 to store type and offset.
- * We use the 5 bits from 25-29 for the type and the 20 bits from 1-19
- * plus 24 for the offset.
- * 0|     offset        |0110|o|type |00|
- * 0 0000000001111111111 2222 2 22222 33
- * 0 1234567890123456789 0123 4 56789 01
- *
  * 64 bit swap entry format:
  * A page-table entry has some bits we have to treat in a special way.
  * Bits 52 and bit 55 have to be zero, otherwise an specification
  * exception will occur instead of a page translation exception. The
  * specifiation exception has the bad habit not to store necessary
  * information in the lowcore.
- * Bits 53, 54, 62 and 63 are used to indicate the page type.
- * A swap pte is indicated by bit pattern (pte & 0x603) == 0x402
- * This leaves the bits 0-51 and bits 56-61 to store type and offset.
- * We use the 5 bits from 57-61 for the type and the 53 bits from 0-51
- * plus 56 for the offset.
- * |                      offset                        |0110|o|type |00|
- *  0000000000111111111122222222223333333333444444444455 5555 5 55566 66
- *  0123456789012345678901234567890123456789012345678901 2345 6 78901 23
+ * Bits 54 and 63 are used to indicate the page type.
+ * A swap pte is indicated by bit pattern (pte & 0x201) == 0x200
+ * This leaves the bits 0-51 and bits 56-62 to store type and offset.
+ * We use the 5 bits from 57-61 for the type and the 52 bits from 0-51
+ * for the offset.
+ * |                     offset                        |01100|type |00|
+ * |0000000000111111111122222222223333333333444444444455|55555|55566|66|
+ * |0123456789012345678901234567890123456789012345678901|23456|78901|23|
  */
 
-#define __SWP_OFFSET_MASK (~0UL >> 11)
+#define __SWP_OFFSET_MASK      ((1UL << 52) - 1)
+#define __SWP_OFFSET_SHIFT     12
+#define __SWP_TYPE_MASK                ((1UL << 5) - 1)
+#define __SWP_TYPE_SHIFT       2
 
 static inline pte_t mk_swap_pte(unsigned long type, unsigned long offset)
 {
        pte_t pte;
-       offset &= __SWP_OFFSET_MASK;
-       pte_val(pte) = _PAGE_INVALID | _PAGE_TYPE | ((type & 0x1f) << 2) |
-               ((offset & 1UL) << 7) | ((offset & ~1UL) << 11);
+
+       pte_val(pte) = _PAGE_INVALID | _PAGE_PROTECT;
+       pte_val(pte) |= (offset & __SWP_OFFSET_MASK) << __SWP_OFFSET_SHIFT;
+       pte_val(pte) |= (type & __SWP_TYPE_MASK) << __SWP_TYPE_SHIFT;
        return pte;
 }
 
-#define __swp_type(entry)      (((entry).val >> 2) & 0x1f)
-#define __swp_offset(entry)    (((entry).val >> 11) | (((entry).val >> 7) & 1))
-#define __swp_entry(type,offset) ((swp_entry_t) { pte_val(mk_swap_pte((type),(offset))) })
+static inline unsigned long __swp_type(swp_entry_t entry)
+{
+       return (entry.val >> __SWP_TYPE_SHIFT) & __SWP_TYPE_MASK;
+}
+
+static inline unsigned long __swp_offset(swp_entry_t entry)
+{
+       return (entry.val >> __SWP_OFFSET_SHIFT) & __SWP_OFFSET_MASK;
+}
+
+static inline swp_entry_t __swp_entry(unsigned long type, unsigned long offset)
+{
+       return (swp_entry_t) { pte_val(mk_swap_pte(type, offset)) };
+}
 
 #define __pte_to_swp_entry(pte)        ((swp_entry_t) { pte_val(pte) })
 #define __swp_entry_to_pte(x)  ((pte_t) { (x).val })
index 210ffede0153130d40ce222a15c559057b114e1e..e617e74b7be22aade65168f2c103c32b18b18653 100644 (file)
@@ -14,20 +14,23 @@ static inline pmd_t __pte_to_pmd(pte_t pte)
 
        /*
         * Convert encoding               pte bits         pmd bits
-        *                              .IR...wrdytp    dy..R...I...wr
-        * empty                        .10...000000 -> 00..0...1...00
-        * prot-none, clean, old        .11...000001 -> 00..1...1...00
-        * prot-none, clean, young      .11...000101 -> 01..1...1...00
-        * prot-none, dirty, old        .10...001001 -> 10..1...1...00
-        * prot-none, dirty, young      .10...001101 -> 11..1...1...00
-        * read-only, clean, old        .11...010001 -> 00..1...1...01
-        * read-only, clean, young      .01...010101 -> 01..1...0...01
-        * read-only, dirty, old        .11...011001 -> 10..1...1...01
-        * read-only, dirty, young      .01...011101 -> 11..1...0...01
-        * read-write, clean, old       .11...110001 -> 00..0...1...11
-        * read-write, clean, young     .01...110101 -> 01..0...0...11
-        * read-write, dirty, old       .10...111001 -> 10..0...1...11
-        * read-write, dirty, young     .00...111101 -> 11..0...0...11
+        *                              lIR.uswrdy.p    dy..R...I...wr
+        * empty                        010.000000.0 -> 00..0...1...00
+        * prot-none, clean, old        111.000000.1 -> 00..1...1...00
+        * prot-none, clean, young      111.000001.1 -> 01..1...1...00
+        * prot-none, dirty, old        111.000010.1 -> 10..1...1...00
+        * prot-none, dirty, young      111.000011.1 -> 11..1...1...00
+        * read-only, clean, old        111.000100.1 -> 00..1...1...01
+        * read-only, clean, young      101.000101.1 -> 01..1...0...01
+        * read-only, dirty, old        111.000110.1 -> 10..1...1...01
+        * read-only, dirty, young      101.000111.1 -> 11..1...0...01
+        * read-write, clean, old       111.001100.1 -> 00..1...1...11
+        * read-write, clean, young     101.001101.1 -> 01..1...0...11
+        * read-write, dirty, old       110.001110.1 -> 10..0...1...11
+        * read-write, dirty, young     100.001111.1 -> 11..0...0...11
+        * HW-bits: R read-only, I invalid
+        * SW-bits: p present, y young, d dirty, r read, w write, s special,
+        *          u unused, l large
         */
        if (pte_present(pte)) {
                pmd_val(pmd) = pte_val(pte) & PAGE_MASK;
@@ -48,20 +51,23 @@ static inline pte_t __pmd_to_pte(pmd_t pmd)
 
        /*
         * Convert encoding                pmd bits         pte bits
-        *                              dy..R...I...wr    .IR...wrdytp
-        * empty                        00..0...1...00 -> .10...001100
-        * prot-none, clean, old        00..0...1...00 -> .10...000001
-        * prot-none, clean, young      01..0...1...00 -> .10...000101
-        * prot-none, dirty, old        10..0...1...00 -> .10...001001
-        * prot-none, dirty, young      11..0...1...00 -> .10...001101
-        * read-only, clean, old        00..1...1...01 -> .11...010001
-        * read-only, clean, young      01..1...1...01 -> .11...010101
-        * read-only, dirty, old        10..1...1...01 -> .11...011001
-        * read-only, dirty, young      11..1...1...01 -> .11...011101
-        * read-write, clean, old       00..0...1...11 -> .10...110001
-        * read-write, clean, young     01..0...1...11 -> .10...110101
-        * read-write, dirty, old       10..0...1...11 -> .10...111001
-        * read-write, dirty, young     11..0...1...11 -> .10...111101
+        *                              dy..R...I...wr    lIR.uswrdy.p
+        * empty                        00..0...1...00 -> 010.000000.0
+        * prot-none, clean, old        00..1...1...00 -> 111.000000.1
+        * prot-none, clean, young      01..1...1...00 -> 111.000001.1
+        * prot-none, dirty, old        10..1...1...00 -> 111.000010.1
+        * prot-none, dirty, young      11..1...1...00 -> 111.000011.1
+        * read-only, clean, old        00..1...1...01 -> 111.000100.1
+        * read-only, clean, young      01..1...0...01 -> 101.000101.1
+        * read-only, dirty, old        10..1...1...01 -> 111.000110.1
+        * read-only, dirty, young      11..1...0...01 -> 101.000111.1
+        * read-write, clean, old       00..1...1...11 -> 111.001100.1
+        * read-write, clean, young     01..1...0...11 -> 101.001101.1
+        * read-write, dirty, old       10..0...1...11 -> 110.001110.1
+        * read-write, dirty, young     11..0...0...11 -> 100.001111.1
+        * HW-bits: R read-only, I invalid
+        * SW-bits: p present, y young, d dirty, r read, w write, s special,
+        *          u unused, l large
         */
        if (pmd_present(pmd)) {
                pte_val(pte) = pmd_val(pmd) & _SEGMENT_ENTRY_ORIGIN_LARGE;
@@ -70,8 +76,8 @@ static inline pte_t __pmd_to_pte(pmd_t pmd)
                pte_val(pte) |= (pmd_val(pmd) & _SEGMENT_ENTRY_WRITE) << 4;
                pte_val(pte) |= (pmd_val(pmd) & _SEGMENT_ENTRY_INVALID) << 5;
                pte_val(pte) |= (pmd_val(pmd) & _SEGMENT_ENTRY_PROTECT);
-               pmd_val(pmd) |= (pte_val(pte) & _PAGE_DIRTY) << 10;
-               pmd_val(pmd) |= (pte_val(pte) & _PAGE_YOUNG) << 10;
+               pte_val(pte) |= (pmd_val(pmd) & _SEGMENT_ENTRY_DIRTY) >> 10;
+               pte_val(pte) |= (pmd_val(pmd) & _SEGMENT_ENTRY_YOUNG) >> 10;
        } else
                pte_val(pte) = _PAGE_INVALID;
        return pte;
index 33f5894591138ea75ec12b2e9d6cf64492b6ced3..b33f66110ca9401418f7d657b951d8bfb84d99c3 100644 (file)
@@ -18,6 +18,7 @@
 #include <linux/rcupdate.h>
 #include <linux/slab.h>
 #include <linux/swapops.h>
+#include <linux/sysctl.h>
 #include <linux/ksm.h>
 #include <linux/mman.h>
 
@@ -920,6 +921,40 @@ unsigned long get_guest_storage_key(struct mm_struct *mm, unsigned long addr)
 }
 EXPORT_SYMBOL(get_guest_storage_key);
 
+static int page_table_allocate_pgste_min = 0;
+static int page_table_allocate_pgste_max = 1;
+int page_table_allocate_pgste = 0;
+EXPORT_SYMBOL(page_table_allocate_pgste);
+
+static struct ctl_table page_table_sysctl[] = {
+       {
+               .procname       = "allocate_pgste",
+               .data           = &page_table_allocate_pgste,
+               .maxlen         = sizeof(int),
+               .mode           = S_IRUGO | S_IWUSR,
+               .proc_handler   = proc_dointvec,
+               .extra1         = &page_table_allocate_pgste_min,
+               .extra2         = &page_table_allocate_pgste_max,
+       },
+       { }
+};
+
+static struct ctl_table page_table_sysctl_dir[] = {
+       {
+               .procname       = "vm",
+               .maxlen         = 0,
+               .mode           = 0555,
+               .child          = page_table_sysctl,
+       },
+       { }
+};
+
+static int __init page_table_register_sysctl(void)
+{
+       return register_sysctl_table(page_table_sysctl_dir) ? 0 : -ENOMEM;
+}
+__initcall(page_table_register_sysctl);
+
 #else /* CONFIG_PGSTE */
 
 static inline int page_table_with_pgste(struct page *page)
@@ -963,7 +998,7 @@ unsigned long *page_table_alloc(struct mm_struct *mm)
        struct page *uninitialized_var(page);
        unsigned int mask, bit;
 
-       if (mm_has_pgste(mm))
+       if (mm_alloc_pgste(mm))
                return page_table_alloc_pgste(mm);
        /* Allocate fragments of a 4K page as 1K/2K page table */
        spin_lock_bh(&mm->context.list_lock);
@@ -1165,116 +1200,25 @@ static inline void thp_split_mm(struct mm_struct *mm)
 }
 #endif /* CONFIG_TRANSPARENT_HUGEPAGE */
 
-static unsigned long page_table_realloc_pmd(struct mmu_gather *tlb,
-                               struct mm_struct *mm, pud_t *pud,
-                               unsigned long addr, unsigned long end)
-{
-       unsigned long next, *table, *new;
-       struct page *page;
-       spinlock_t *ptl;
-       pmd_t *pmd;
-
-       pmd = pmd_offset(pud, addr);
-       do {
-               next = pmd_addr_end(addr, end);
-again:
-               if (pmd_none_or_clear_bad(pmd))
-                       continue;
-               table = (unsigned long *) pmd_deref(*pmd);
-               page = pfn_to_page(__pa(table) >> PAGE_SHIFT);
-               if (page_table_with_pgste(page))
-                       continue;
-               /* Allocate new page table with pgstes */
-               new = page_table_alloc_pgste(mm);
-               if (!new)
-                       return -ENOMEM;
-
-               ptl = pmd_lock(mm, pmd);
-               if (likely((unsigned long *) pmd_deref(*pmd) == table)) {
-                       /* Nuke pmd entry pointing to the "short" page table */
-                       pmdp_flush_lazy(mm, addr, pmd);
-                       pmd_clear(pmd);
-                       /* Copy ptes from old table to new table */
-                       memcpy(new, table, PAGE_SIZE/2);
-                       clear_table(table, _PAGE_INVALID, PAGE_SIZE/2);
-                       /* Establish new table */
-                       pmd_populate(mm, pmd, (pte_t *) new);
-                       /* Free old table with rcu, there might be a walker! */
-                       page_table_free_rcu(tlb, table, addr);
-                       new = NULL;
-               }
-               spin_unlock(ptl);
-               if (new) {
-                       page_table_free_pgste(new);
-                       goto again;
-               }
-       } while (pmd++, addr = next, addr != end);
-
-       return addr;
-}
-
-static unsigned long page_table_realloc_pud(struct mmu_gather *tlb,
-                                  struct mm_struct *mm, pgd_t *pgd,
-                                  unsigned long addr, unsigned long end)
-{
-       unsigned long next;
-       pud_t *pud;
-
-       pud = pud_offset(pgd, addr);
-       do {
-               next = pud_addr_end(addr, end);
-               if (pud_none_or_clear_bad(pud))
-                       continue;
-               next = page_table_realloc_pmd(tlb, mm, pud, addr, next);
-               if (unlikely(IS_ERR_VALUE(next)))
-                       return next;
-       } while (pud++, addr = next, addr != end);
-
-       return addr;
-}
-
-static unsigned long page_table_realloc(struct mmu_gather *tlb, struct mm_struct *mm,
-                                       unsigned long addr, unsigned long end)
-{
-       unsigned long next;
-       pgd_t *pgd;
-
-       pgd = pgd_offset(mm, addr);
-       do {
-               next = pgd_addr_end(addr, end);
-               if (pgd_none_or_clear_bad(pgd))
-                       continue;
-               next = page_table_realloc_pud(tlb, mm, pgd, addr, next);
-               if (unlikely(IS_ERR_VALUE(next)))
-                       return next;
-       } while (pgd++, addr = next, addr != end);
-
-       return 0;
-}
-
 /*
  * switch on pgstes for its userspace process (for kvm)
  */
 int s390_enable_sie(void)
 {
-       struct task_struct *tsk = current;
-       struct mm_struct *mm = tsk->mm;
-       struct mmu_gather tlb;
+       struct mm_struct *mm = current->mm;
 
        /* Do we have pgstes? if yes, we are done */
-       if (mm_has_pgste(tsk->mm))
+       if (mm_has_pgste(mm))
                return 0;
-
+       /* Fail if the page tables are 2K */
+       if (!mm_alloc_pgste(mm))
+               return -EINVAL;
        down_write(&mm->mmap_sem);
+       mm->context.has_pgste = 1;
        /* split thp mappings and disable thp for future mappings */
        thp_split_mm(mm);
-       /* Reallocate the page tables with pgstes */
-       tlb_gather_mmu(&tlb, mm, 0, TASK_SIZE);
-       if (!page_table_realloc(&tlb, mm, 0, TASK_SIZE))
-               mm->context.has_pgste = 1;
-       tlb_finish_mmu(&tlb, 0, TASK_SIZE);
        up_write(&mm->mmap_sem);
-       return mm->context.has_pgste ? 0 : -ENOMEM;
+       return 0;
 }
 EXPORT_SYMBOL_GPL(s390_enable_sie);
 
index ba8593a515baaa274d968aa64e6f54125238c032..de156ba3bd71c0d4db274a619c7c9fd6038c119c 100644 (file)
@@ -48,7 +48,9 @@ extern u8 sk_load_word[], sk_load_half[], sk_load_byte[];
  * We get 160 bytes stack space from calling function, but only use
  * 11 * 8 byte (old backchain + r15 - r6) for storing registers.
  */
-#define STK_OFF (MAX_BPF_STACK + 8 + 4 + 4 + (160 - 11 * 8))
+#define STK_SPACE      (MAX_BPF_STACK + 8 + 4 + 4 + 160)
+#define STK_160_UNUSED (160 - 11 * 8)
+#define STK_OFF                (STK_SPACE - STK_160_UNUSED)
 #define STK_OFF_TMP    160     /* Offset of tmp buffer on stack */
 #define STK_OFF_HLEN   168     /* Offset of SKB header length on stack */
 
index 7690dc8e1ab5bb619bb19ec1be1b12853e1b0589..55423d8be580113d045d30edbf86d26fb74340ff 100644 (file)
@@ -384,13 +384,16 @@ static void bpf_jit_prologue(struct bpf_jit *jit)
        }
        /* Setup stack and backchain */
        if (jit->seen & SEEN_STACK) {
-               /* lgr %bfp,%r15 (BPF frame pointer) */
-               EMIT4(0xb9040000, BPF_REG_FP, REG_15);
+               if (jit->seen & SEEN_FUNC)
+                       /* lgr %w1,%r15 (backchain) */
+                       EMIT4(0xb9040000, REG_W1, REG_15);
+               /* la %bfp,STK_160_UNUSED(%r15) (BPF frame pointer) */
+               EMIT4_DISP(0x41000000, BPF_REG_FP, REG_15, STK_160_UNUSED);
                /* aghi %r15,-STK_OFF */
                EMIT4_IMM(0xa70b0000, REG_15, -STK_OFF);
                if (jit->seen & SEEN_FUNC)
-                       /* stg %bfp,152(%r15) (backchain) */
-                       EMIT6_DISP_LH(0xe3000000, 0x0024, BPF_REG_FP, REG_0,
+                       /* stg %w1,152(%r15) (backchain) */
+                       EMIT6_DISP_LH(0xe3000000, 0x0024, REG_W1, REG_0,
                                      REG_15, 152);
        }
        /*
@@ -443,8 +446,11 @@ static void bpf_jit_epilogue(struct bpf_jit *jit)
 
 /*
  * Compile one eBPF instruction into s390x code
+ *
+ * NOTE: Use noinline because for gcov (-fprofile-arcs) gcc allocates a lot of
+ * stack space for the large switch statement.
  */
-static int bpf_jit_insn(struct bpf_jit *jit, struct bpf_prog *fp, int i)
+static noinline int bpf_jit_insn(struct bpf_jit *jit, struct bpf_prog *fp, int i)
 {
        struct bpf_insn *insn = &fp->insnsi[i];
        int jmp_off, last, insn_count = 1;
@@ -588,8 +594,8 @@ static int bpf_jit_insn(struct bpf_jit *jit, struct bpf_prog *fp, int i)
                EMIT4(0xb9160000, dst_reg, rc_reg);
                break;
        }
-       case BPF_ALU64 | BPF_DIV | BPF_X: /* dst = dst / (u32) src */
-       case BPF_ALU64 | BPF_MOD | BPF_X: /* dst = dst % (u32) src */
+       case BPF_ALU64 | BPF_DIV | BPF_X: /* dst = dst / src */
+       case BPF_ALU64 | BPF_MOD | BPF_X: /* dst = dst % src */
        {
                int rc_reg = BPF_OP(insn->code) == BPF_DIV ? REG_W1 : REG_W0;
 
@@ -602,10 +608,8 @@ static int bpf_jit_insn(struct bpf_jit *jit, struct bpf_prog *fp, int i)
                EMIT4_IMM(0xa7090000, REG_W0, 0);
                /* lgr %w1,%dst */
                EMIT4(0xb9040000, REG_W1, dst_reg);
-               /* llgfr %dst,%src (u32 cast) */
-               EMIT4(0xb9160000, dst_reg, src_reg);
                /* dlgr %w0,%dst */
-               EMIT4(0xb9870000, REG_W0, dst_reg);
+               EMIT4(0xb9870000, REG_W0, src_reg);
                /* lgr %dst,%rc */
                EMIT4(0xb9040000, dst_reg, rc_reg);
                break;
@@ -632,8 +636,8 @@ static int bpf_jit_insn(struct bpf_jit *jit, struct bpf_prog *fp, int i)
                EMIT4(0xb9160000, dst_reg, rc_reg);
                break;
        }
-       case BPF_ALU64 | BPF_DIV | BPF_K: /* dst = dst / (u32) imm */
-       case BPF_ALU64 | BPF_MOD | BPF_K: /* dst = dst % (u32) imm */
+       case BPF_ALU64 | BPF_DIV | BPF_K: /* dst = dst / imm */
+       case BPF_ALU64 | BPF_MOD | BPF_K: /* dst = dst % imm */
        {
                int rc_reg = BPF_OP(insn->code) == BPF_DIV ? REG_W1 : REG_W0;
 
@@ -649,7 +653,7 @@ static int bpf_jit_insn(struct bpf_jit *jit, struct bpf_prog *fp, int i)
                EMIT4(0xb9040000, REG_W1, dst_reg);
                /* dlg %w0,<d(imm)>(%l) */
                EMIT6_DISP_LH(0xe3000000, 0x0087, REG_W0, REG_0, REG_L,
-                             EMIT_CONST_U64((u32) imm));
+                             EMIT_CONST_U64(imm));
                /* lgr %dst,%rc */
                EMIT4(0xb9040000, dst_reg, rc_reg);
                break;
index 00b7d3a2fc60681253eb2e1c1b874e48bbd02a4a..16efa3ad037f7cffbdbb4a5ffcf57a5d25325648 100644 (file)
@@ -175,10 +175,10 @@ ENTRY(__clear_user)
        br      r3
 
        .section .fixup, "ax"
+99:
        br      r3
        .previous
        .section __ex_table, "a"
        .align  2
-99:
        .word   0b, 99b
        .previous
index a6e424d185d063bdddd43719e6a994fad6902c17..a6cfdabb6054aef28846342f49fdb2718e1263a5 100644 (file)
@@ -24,7 +24,8 @@ typedef struct {
        unsigned int    icache_line_size;
        unsigned int    ecache_size;
        unsigned int    ecache_line_size;
-       int             core_id;
+       unsigned short  sock_id;
+       unsigned short  core_id;
        int             proc_id;
 } cpuinfo_sparc;
 
index dc165ebdf05aef6086bf5d5c5b1dd3a85f686648..2a52c91d2c8acbf5f904e082400ba782d7279947 100644 (file)
@@ -308,12 +308,26 @@ static inline pte_t pte_modify(pte_t pte, pgprot_t prot)
        "       sllx            %1, 32, %1\n"
        "       or              %0, %1, %0\n"
        "       .previous\n"
+       "       .section        .sun_m7_2insn_patch, \"ax\"\n"
+       "       .word           661b\n"
+       "       sethi           %%uhi(%4), %1\n"
+       "       sethi           %%hi(%4), %0\n"
+       "       .word           662b\n"
+       "       or              %1, %%ulo(%4), %1\n"
+       "       or              %0, %%lo(%4), %0\n"
+       "       .word           663b\n"
+       "       sllx            %1, 32, %1\n"
+       "       or              %0, %1, %0\n"
+       "       .previous\n"
        : "=r" (mask), "=r" (tmp)
        : "i" (_PAGE_PADDR_4U | _PAGE_MODIFIED_4U | _PAGE_ACCESSED_4U |
               _PAGE_CP_4U | _PAGE_CV_4U | _PAGE_E_4U |
               _PAGE_SPECIAL | _PAGE_PMD_HUGE | _PAGE_SZALL_4U),
          "i" (_PAGE_PADDR_4V | _PAGE_MODIFIED_4V | _PAGE_ACCESSED_4V |
               _PAGE_CP_4V | _PAGE_CV_4V | _PAGE_E_4V |
+              _PAGE_SPECIAL | _PAGE_PMD_HUGE | _PAGE_SZALL_4V),
+         "i" (_PAGE_PADDR_4V | _PAGE_MODIFIED_4V | _PAGE_ACCESSED_4V |
+              _PAGE_CP_4V | _PAGE_E_4V |
               _PAGE_SPECIAL | _PAGE_PMD_HUGE | _PAGE_SZALL_4V));
 
        return __pte((pte_val(pte) & mask) | (pgprot_val(prot) & ~mask));
@@ -342,9 +356,15 @@ static inline pgprot_t pgprot_noncached(pgprot_t prot)
        "       andn            %0, %4, %0\n"
        "       or              %0, %5, %0\n"
        "       .previous\n"
+       "       .section        .sun_m7_2insn_patch, \"ax\"\n"
+       "       .word           661b\n"
+       "       andn            %0, %6, %0\n"
+       "       or              %0, %5, %0\n"
+       "       .previous\n"
        : "=r" (val)
        : "0" (val), "i" (_PAGE_CP_4U | _PAGE_CV_4U), "i" (_PAGE_E_4U),
-                    "i" (_PAGE_CP_4V | _PAGE_CV_4V), "i" (_PAGE_E_4V));
+                    "i" (_PAGE_CP_4V | _PAGE_CV_4V), "i" (_PAGE_E_4V),
+                    "i" (_PAGE_CP_4V));
 
        return __pgprot(val);
 }
index ed8f071132e4d0e045bd9ffe22ce90f6604e0e3a..d1761df5cca6fe2814c19a343274d2884a3cf0c4 100644 (file)
@@ -40,11 +40,12 @@ static inline int pcibus_to_node(struct pci_bus *pbus)
 #ifdef CONFIG_SMP
 #define topology_physical_package_id(cpu)      (cpu_data(cpu).proc_id)
 #define topology_core_id(cpu)                  (cpu_data(cpu).core_id)
-#define topology_core_cpumask(cpu)             (&cpu_core_map[cpu])
+#define topology_core_cpumask(cpu)             (&cpu_core_sib_map[cpu])
 #define topology_thread_cpumask(cpu)           (&per_cpu(cpu_sibling_map, cpu))
 #endif /* CONFIG_SMP */
 
 extern cpumask_t cpu_core_map[NR_CPUS];
+extern cpumask_t cpu_core_sib_map[NR_CPUS];
 static inline const struct cpumask *cpu_coregroup_mask(int cpu)
 {
         return &cpu_core_map[cpu];
index 6fd4436d32f06a59ed3113db3e6e52ddf3d3fa93..ec9c04de3664910d81b7a55bbb09084d5e235d39 100644 (file)
@@ -79,6 +79,8 @@ struct sun4v_2insn_patch_entry {
 };
 extern struct sun4v_2insn_patch_entry __sun4v_2insn_patch,
        __sun4v_2insn_patch_end;
+extern struct sun4v_2insn_patch_entry __sun_m7_2insn_patch,
+       __sun_m7_2insn_patch_end;
 
 
 #endif /* !(__ASSEMBLY__) */
index 07cc49e541f40ea2cacc1f952aa7e07dd4a4e69b..0f679421b468343c747ac48abd2046b7e6ce051e 100644 (file)
@@ -69,6 +69,8 @@ void sun4v_patch_1insn_range(struct sun4v_1insn_patch_entry *,
                             struct sun4v_1insn_patch_entry *);
 void sun4v_patch_2insn_range(struct sun4v_2insn_patch_entry *,
                             struct sun4v_2insn_patch_entry *);
+void sun_m7_patch_2insn_range(struct sun4v_2insn_patch_entry *,
+                            struct sun4v_2insn_patch_entry *);
 extern unsigned int dcache_parity_tl1_occurred;
 extern unsigned int icache_parity_tl1_occurred;
 
index 94e392bdee7dce5c984cc9f6f70307313a8f5a01..814fb1729b120bdeccbe2aacea958e7ae8add28d 100644 (file)
@@ -723,7 +723,6 @@ static int grpci2_of_probe(struct platform_device *ofdev)
                err = -ENOMEM;
                goto err1;
        }
-       memset(grpci2priv, 0, sizeof(*grpci2priv));
        priv->regs = regs;
        priv->irq = ofdev->archdata.irqs[0]; /* BASE IRQ */
        priv->irq_mode = (capability & STS_IRQMODE) >> STS_IRQMODE_BIT;
index 26c80e18d7b1b47bd74e9fce01bdb48eeb88fcbd..6f80936e0eea4d0dab82966b8f69cd7e6127b1dd 100644 (file)
@@ -614,45 +614,68 @@ static void fill_in_one_cache(cpuinfo_sparc *c, struct mdesc_handle *hp, u64 mp)
        }
 }
 
-static void mark_core_ids(struct mdesc_handle *hp, u64 mp, int core_id)
+static void find_back_node_value(struct mdesc_handle *hp, u64 node,
+                                char *srch_val,
+                                void (*func)(struct mdesc_handle *, u64, int),
+                                u64 val, int depth)
 {
-       u64 a;
-
-       mdesc_for_each_arc(a, hp, mp, MDESC_ARC_TYPE_BACK) {
-               u64 t = mdesc_arc_target(hp, a);
-               const char *name;
-               const u64 *id;
+       u64 arc;
 
-               name = mdesc_node_name(hp, t);
-               if (!strcmp(name, "cpu")) {
-                       id = mdesc_get_property(hp, t, "id", NULL);
-                       if (*id < NR_CPUS)
-                               cpu_data(*id).core_id = core_id;
-               } else {
-                       u64 j;
+       /* Since we have an estimate of recursion depth, do a sanity check. */
+       if (depth == 0)
+               return;
 
-                       mdesc_for_each_arc(j, hp, t, MDESC_ARC_TYPE_BACK) {
-                               u64 n = mdesc_arc_target(hp, j);
-                               const char *n_name;
+       mdesc_for_each_arc(arc, hp, node, MDESC_ARC_TYPE_BACK) {
+               u64 n = mdesc_arc_target(hp, arc);
+               const char *name = mdesc_node_name(hp, n);
 
-                               n_name = mdesc_node_name(hp, n);
-                               if (strcmp(n_name, "cpu"))
-                                       continue;
+               if (!strcmp(srch_val, name))
+                       (*func)(hp, n, val);
 
-                               id = mdesc_get_property(hp, n, "id", NULL);
-                               if (*id < NR_CPUS)
-                                       cpu_data(*id).core_id = core_id;
-                       }
-               }
+               find_back_node_value(hp, n, srch_val, func, val, depth-1);
        }
 }
 
+static void __mark_core_id(struct mdesc_handle *hp, u64 node,
+                          int core_id)
+{
+       const u64 *id = mdesc_get_property(hp, node, "id", NULL);
+
+       if (*id < num_possible_cpus())
+               cpu_data(*id).core_id = core_id;
+}
+
+static void __mark_sock_id(struct mdesc_handle *hp, u64 node,
+                          int sock_id)
+{
+       const u64 *id = mdesc_get_property(hp, node, "id", NULL);
+
+       if (*id < num_possible_cpus())
+               cpu_data(*id).sock_id = sock_id;
+}
+
+static void mark_core_ids(struct mdesc_handle *hp, u64 mp,
+                         int core_id)
+{
+       find_back_node_value(hp, mp, "cpu", __mark_core_id, core_id, 10);
+}
+
+static void mark_sock_ids(struct mdesc_handle *hp, u64 mp,
+                         int sock_id)
+{
+       find_back_node_value(hp, mp, "cpu", __mark_sock_id, sock_id, 10);
+}
+
 static void set_core_ids(struct mdesc_handle *hp)
 {
        int idx;
        u64 mp;
 
        idx = 1;
+
+       /* Identify unique cores by looking for cpus backpointed to by
+        * level 1 instruction caches.
+        */
        mdesc_for_each_node_by_name(hp, mp, "cache") {
                const u64 *level;
                const char *type;
@@ -667,11 +690,72 @@ static void set_core_ids(struct mdesc_handle *hp)
                        continue;
 
                mark_core_ids(hp, mp, idx);
+               idx++;
+       }
+}
+
+static int set_sock_ids_by_cache(struct mdesc_handle *hp, int level)
+{
+       u64 mp;
+       int idx = 1;
+       int fnd = 0;
+
+       /* Identify unique sockets by looking for cpus backpointed to by
+        * shared level n caches.
+        */
+       mdesc_for_each_node_by_name(hp, mp, "cache") {
+               const u64 *cur_lvl;
+
+               cur_lvl = mdesc_get_property(hp, mp, "level", NULL);
+               if (*cur_lvl != level)
+                       continue;
+
+               mark_sock_ids(hp, mp, idx);
+               idx++;
+               fnd = 1;
+       }
+       return fnd;
+}
+
+static void set_sock_ids_by_socket(struct mdesc_handle *hp, u64 mp)
+{
+       int idx = 1;
 
+       mdesc_for_each_node_by_name(hp, mp, "socket") {
+               u64 a;
+
+               mdesc_for_each_arc(a, hp, mp, MDESC_ARC_TYPE_FWD) {
+                       u64 t = mdesc_arc_target(hp, a);
+                       const char *name;
+                       const u64 *id;
+
+                       name = mdesc_node_name(hp, t);
+                       if (strcmp(name, "cpu"))
+                               continue;
+
+                       id = mdesc_get_property(hp, t, "id", NULL);
+                       if (*id < num_possible_cpus())
+                               cpu_data(*id).sock_id = idx;
+               }
                idx++;
        }
 }
 
+static void set_sock_ids(struct mdesc_handle *hp)
+{
+       u64 mp;
+
+       /* If machine description exposes sockets data use it.
+        * Otherwise fallback to use shared L3 or L2 caches.
+        */
+       mp = mdesc_node_by_name(hp, MDESC_NODE_NULL, "sockets");
+       if (mp != MDESC_NODE_NULL)
+               return set_sock_ids_by_socket(hp, mp);
+
+       if (!set_sock_ids_by_cache(hp, 3))
+               set_sock_ids_by_cache(hp, 2);
+}
+
 static void mark_proc_ids(struct mdesc_handle *hp, u64 mp, int proc_id)
 {
        u64 a;
@@ -707,7 +791,6 @@ static void __set_proc_ids(struct mdesc_handle *hp, const char *exec_unit_name)
                        continue;
 
                mark_proc_ids(hp, mp, idx);
-
                idx++;
        }
 }
@@ -900,6 +983,7 @@ void mdesc_fill_in_cpu_data(cpumask_t *mask)
 
        set_core_ids(hp);
        set_proc_ids(hp);
+       set_sock_ids(hp);
 
        mdesc_release(hp);
 
index 6f7251fd2eabc6b5b5790c2aa4486c84c042f814..c928bc64b4bac1b1c5eb88c71c348469796883c5 100644 (file)
@@ -1002,6 +1002,38 @@ static int __init pcibios_init(void)
 subsys_initcall(pcibios_init);
 
 #ifdef CONFIG_SYSFS
+
+#define SLOT_NAME_SIZE  11  /* Max decimal digits + null in u32 */
+
+static void pcie_bus_slot_names(struct pci_bus *pbus)
+{
+       struct pci_dev *pdev;
+       struct pci_bus *bus;
+
+       list_for_each_entry(pdev, &pbus->devices, bus_list) {
+               char name[SLOT_NAME_SIZE];
+               struct pci_slot *pci_slot;
+               const u32 *slot_num;
+               int len;
+
+               slot_num = of_get_property(pdev->dev.of_node,
+                                          "physical-slot#", &len);
+
+               if (slot_num == NULL || len != 4)
+                       continue;
+
+               snprintf(name, sizeof(name), "%u", slot_num[0]);
+               pci_slot = pci_create_slot(pbus, slot_num[0], name, NULL);
+
+               if (IS_ERR(pci_slot))
+                       pr_err("PCI: pci_create_slot returned %ld.\n",
+                              PTR_ERR(pci_slot));
+       }
+
+       list_for_each_entry(bus, &pbus->children, node)
+               pcie_bus_slot_names(bus);
+}
+
 static void pci_bus_slot_names(struct device_node *node, struct pci_bus *bus)
 {
        const struct pci_slot_names {
@@ -1053,18 +1085,29 @@ static int __init of_pci_slot_init(void)
 
        while ((pbus = pci_find_next_bus(pbus)) != NULL) {
                struct device_node *node;
+               struct pci_dev *pdev;
+
+               pdev = list_first_entry(&pbus->devices, struct pci_dev,
+                                       bus_list);
 
-               if (pbus->self) {
-                       /* PCI->PCI bridge */
-                       node = pbus->self->dev.of_node;
+               if (pdev && pci_is_pcie(pdev)) {
+                       pcie_bus_slot_names(pbus);
                } else {
-                       struct pci_pbm_info *pbm = pbus->sysdata;
 
-                       /* Host PCI controller */
-                       node = pbm->op->dev.of_node;
-               }
+                       if (pbus->self) {
+
+                               /* PCI->PCI bridge */
+                               node = pbus->self->dev.of_node;
+
+                       } else {
+                               struct pci_pbm_info *pbm = pbus->sysdata;
 
-               pci_bus_slot_names(node, pbus);
+                               /* Host PCI controller */
+                               node = pbm->op->dev.of_node;
+                       }
+
+                       pci_bus_slot_names(node, pbus);
+               }
        }
 
        return 0;
index c38d19fc27baac8821acc57cf2e42120b7d66a3e..f7b261749383b4992300ba4418b1d16ef7251360 100644 (file)
@@ -255,6 +255,24 @@ void sun4v_patch_2insn_range(struct sun4v_2insn_patch_entry *start,
        }
 }
 
+void sun_m7_patch_2insn_range(struct sun4v_2insn_patch_entry *start,
+                            struct sun4v_2insn_patch_entry *end)
+{
+       while (start < end) {
+               unsigned long addr = start->addr;
+
+               *(unsigned int *) (addr +  0) = start->insns[0];
+               wmb();
+               __asm__ __volatile__("flush     %0" : : "r" (addr +  0));
+
+               *(unsigned int *) (addr +  4) = start->insns[1];
+               wmb();
+               __asm__ __volatile__("flush     %0" : : "r" (addr +  4));
+
+               start++;
+       }
+}
+
 static void __init sun4v_patch(void)
 {
        extern void sun4v_hvapi_init(void);
@@ -267,6 +285,9 @@ static void __init sun4v_patch(void)
 
        sun4v_patch_2insn_range(&__sun4v_2insn_patch,
                                &__sun4v_2insn_patch_end);
+       if (sun4v_chip_type == SUN4V_CHIP_SPARC_M7)
+               sun_m7_patch_2insn_range(&__sun_m7_2insn_patch,
+                                        &__sun_m7_2insn_patch_end);
 
        sun4v_hvapi_init();
 }
index 61139d9924cae4a8fdf5d4d5366a31052ea29616..19cd08d1867285f059f768402e4df14c64d7871d 100644 (file)
@@ -60,8 +60,12 @@ DEFINE_PER_CPU(cpumask_t, cpu_sibling_map) = CPU_MASK_NONE;
 cpumask_t cpu_core_map[NR_CPUS] __read_mostly =
        { [0 ... NR_CPUS-1] = CPU_MASK_NONE };
 
+cpumask_t cpu_core_sib_map[NR_CPUS] __read_mostly = {
+       [0 ... NR_CPUS-1] = CPU_MASK_NONE };
+
 EXPORT_PER_CPU_SYMBOL(cpu_sibling_map);
 EXPORT_SYMBOL(cpu_core_map);
+EXPORT_SYMBOL(cpu_core_sib_map);
 
 static cpumask_t smp_commenced_mask;
 
@@ -1243,6 +1247,15 @@ void smp_fill_in_sib_core_maps(void)
                }
        }
 
+       for_each_present_cpu(i)  {
+               unsigned int j;
+
+               for_each_present_cpu(j)  {
+                       if (cpu_data(i).sock_id == cpu_data(j).sock_id)
+                               cpumask_set_cpu(j, &cpu_core_sib_map[i]);
+               }
+       }
+
        for_each_present_cpu(i) {
                unsigned int j;
 
index 09243057cb0b48f7fd1679129db63eb4094a8be6..f1a2f688b28a31fc47d2232f3ed10e9d95930223 100644 (file)
@@ -138,6 +138,11 @@ SECTIONS
                *(.pause_3insn_patch)
                __pause_3insn_patch_end = .;
        }
+       .sun_m7_2insn_patch : {
+               __sun_m7_2insn_patch = .;
+               *(.sun_m7_2insn_patch)
+               __sun_m7_2insn_patch_end = .;
+       }
        PERCPU_SECTION(SMP_CACHE_BYTES)
 
        . = ALIGN(PAGE_SIZE);
index 4ca0d6ba5ec8331c67f43f8515eb3737526208bb..559cb744112ccd608bf4288470398fb21350b0ce 100644 (file)
@@ -54,6 +54,7 @@
 #include "init_64.h"
 
 unsigned long kern_linear_pte_xor[4] __read_mostly;
+static unsigned long page_cache4v_flag;
 
 /* A bitmap, two bits for every 256MB of physical memory.  These two
  * bits determine what page size we use for kernel linear
@@ -1909,11 +1910,24 @@ static void __init sun4u_linear_pte_xor_finalize(void)
 
 static void __init sun4v_linear_pte_xor_finalize(void)
 {
+       unsigned long pagecv_flag;
+
+       /* Bit 9 of TTE is no longer CV bit on M7 processor and it instead
+        * enables MCD error. Do not set bit 9 on M7 processor.
+        */
+       switch (sun4v_chip_type) {
+       case SUN4V_CHIP_SPARC_M7:
+               pagecv_flag = 0x00;
+               break;
+       default:
+               pagecv_flag = _PAGE_CV_4V;
+               break;
+       }
 #ifndef CONFIG_DEBUG_PAGEALLOC
        if (cpu_pgsz_mask & HV_PGSZ_MASK_256MB) {
                kern_linear_pte_xor[1] = (_PAGE_VALID | _PAGE_SZ256MB_4V) ^
                        PAGE_OFFSET;
-               kern_linear_pte_xor[1] |= (_PAGE_CP_4V | _PAGE_CV_4V |
+               kern_linear_pte_xor[1] |= (_PAGE_CP_4V | pagecv_flag |
                                           _PAGE_P_4V | _PAGE_W_4V);
        } else {
                kern_linear_pte_xor[1] = kern_linear_pte_xor[0];
@@ -1922,7 +1936,7 @@ static void __init sun4v_linear_pte_xor_finalize(void)
        if (cpu_pgsz_mask & HV_PGSZ_MASK_2GB) {
                kern_linear_pte_xor[2] = (_PAGE_VALID | _PAGE_SZ2GB_4V) ^
                        PAGE_OFFSET;
-               kern_linear_pte_xor[2] |= (_PAGE_CP_4V | _PAGE_CV_4V |
+               kern_linear_pte_xor[2] |= (_PAGE_CP_4V | pagecv_flag |
                                           _PAGE_P_4V | _PAGE_W_4V);
        } else {
                kern_linear_pte_xor[2] = kern_linear_pte_xor[1];
@@ -1931,7 +1945,7 @@ static void __init sun4v_linear_pte_xor_finalize(void)
        if (cpu_pgsz_mask & HV_PGSZ_MASK_16GB) {
                kern_linear_pte_xor[3] = (_PAGE_VALID | _PAGE_SZ16GB_4V) ^
                        PAGE_OFFSET;
-               kern_linear_pte_xor[3] |= (_PAGE_CP_4V | _PAGE_CV_4V |
+               kern_linear_pte_xor[3] |= (_PAGE_CP_4V | pagecv_flag |
                                           _PAGE_P_4V | _PAGE_W_4V);
        } else {
                kern_linear_pte_xor[3] = kern_linear_pte_xor[2];
@@ -1958,6 +1972,13 @@ static phys_addr_t __init available_memory(void)
        return available;
 }
 
+#define _PAGE_CACHE_4U (_PAGE_CP_4U | _PAGE_CV_4U)
+#define _PAGE_CACHE_4V (_PAGE_CP_4V | _PAGE_CV_4V)
+#define __DIRTY_BITS_4U         (_PAGE_MODIFIED_4U | _PAGE_WRITE_4U | _PAGE_W_4U)
+#define __DIRTY_BITS_4V         (_PAGE_MODIFIED_4V | _PAGE_WRITE_4V | _PAGE_W_4V)
+#define __ACCESS_BITS_4U (_PAGE_ACCESSED_4U | _PAGE_READ_4U | _PAGE_R)
+#define __ACCESS_BITS_4V (_PAGE_ACCESSED_4V | _PAGE_READ_4V | _PAGE_R)
+
 /* We need to exclude reserved regions. This exclusion will include
  * vmlinux and initrd. To be more precise the initrd size could be used to
  * compute a new lower limit because it is freed later during initialization.
@@ -2034,6 +2055,25 @@ void __init paging_init(void)
        memset(swapper_4m_tsb, 0x40, sizeof(swapper_4m_tsb));
 #endif
 
+       /* TTE.cv bit on sparc v9 occupies the same position as TTE.mcde
+        * bit on M7 processor. This is a conflicting usage of the same
+        * bit. Enabling TTE.cv on M7 would turn on Memory Corruption
+        * Detection error on all pages and this will lead to problems
+        * later. Kernel does not run with MCD enabled and hence rest
+        * of the required steps to fully configure memory corruption
+        * detection are not taken. We need to ensure TTE.mcde is not
+        * set on M7 processor. Compute the value of cacheability
+        * flag for use later taking this into consideration.
+        */
+       switch (sun4v_chip_type) {
+       case SUN4V_CHIP_SPARC_M7:
+               page_cache4v_flag = _PAGE_CP_4V;
+               break;
+       default:
+               page_cache4v_flag = _PAGE_CACHE_4V;
+               break;
+       }
+
        if (tlb_type == hypervisor)
                sun4v_pgprot_init();
        else
@@ -2274,13 +2314,6 @@ void free_initrd_mem(unsigned long start, unsigned long end)
 }
 #endif
 
-#define _PAGE_CACHE_4U (_PAGE_CP_4U | _PAGE_CV_4U)
-#define _PAGE_CACHE_4V (_PAGE_CP_4V | _PAGE_CV_4V)
-#define __DIRTY_BITS_4U         (_PAGE_MODIFIED_4U | _PAGE_WRITE_4U | _PAGE_W_4U)
-#define __DIRTY_BITS_4V         (_PAGE_MODIFIED_4V | _PAGE_WRITE_4V | _PAGE_W_4V)
-#define __ACCESS_BITS_4U (_PAGE_ACCESSED_4U | _PAGE_READ_4U | _PAGE_R)
-#define __ACCESS_BITS_4V (_PAGE_ACCESSED_4V | _PAGE_READ_4V | _PAGE_R)
-
 pgprot_t PAGE_KERNEL __read_mostly;
 EXPORT_SYMBOL(PAGE_KERNEL);
 
@@ -2312,8 +2345,7 @@ int __meminit vmemmap_populate(unsigned long vstart, unsigned long vend,
                    _PAGE_P_4U | _PAGE_W_4U);
        if (tlb_type == hypervisor)
                pte_base = (_PAGE_VALID | _PAGE_SZ4MB_4V |
-                           _PAGE_CP_4V | _PAGE_CV_4V |
-                           _PAGE_P_4V | _PAGE_W_4V);
+                           page_cache4v_flag | _PAGE_P_4V | _PAGE_W_4V);
 
        pte_base |= _PAGE_PMD_HUGE;
 
@@ -2450,14 +2482,14 @@ static void __init sun4v_pgprot_init(void)
        int i;
 
        PAGE_KERNEL = __pgprot (_PAGE_PRESENT_4V | _PAGE_VALID |
-                               _PAGE_CACHE_4V | _PAGE_P_4V |
+                               page_cache4v_flag | _PAGE_P_4V |
                                __ACCESS_BITS_4V | __DIRTY_BITS_4V |
                                _PAGE_EXEC_4V);
        PAGE_KERNEL_LOCKED = PAGE_KERNEL;
 
        _PAGE_IE = _PAGE_IE_4V;
        _PAGE_E = _PAGE_E_4V;
-       _PAGE_CACHE = _PAGE_CACHE_4V;
+       _PAGE_CACHE = page_cache4v_flag;
 
 #ifdef CONFIG_DEBUG_PAGEALLOC
        kern_linear_pte_xor[0] = _PAGE_VALID ^ PAGE_OFFSET;
@@ -2465,8 +2497,8 @@ static void __init sun4v_pgprot_init(void)
        kern_linear_pte_xor[0] = (_PAGE_VALID | _PAGE_SZ4MB_4V) ^
                PAGE_OFFSET;
 #endif
-       kern_linear_pte_xor[0] |= (_PAGE_CP_4V | _PAGE_CV_4V |
-                                  _PAGE_P_4V | _PAGE_W_4V);
+       kern_linear_pte_xor[0] |= (page_cache4v_flag | _PAGE_P_4V |
+                                  _PAGE_W_4V);
 
        for (i = 1; i < 4; i++)
                kern_linear_pte_xor[i] = kern_linear_pte_xor[0];
@@ -2479,12 +2511,12 @@ static void __init sun4v_pgprot_init(void)
                             _PAGE_SZ4MB_4V | _PAGE_SZ512K_4V |
                             _PAGE_SZ64K_4V | _PAGE_SZ8K_4V);
 
-       page_none = _PAGE_PRESENT_4V | _PAGE_ACCESSED_4V | _PAGE_CACHE_4V;
-       page_shared = (_PAGE_VALID | _PAGE_PRESENT_4V | _PAGE_CACHE_4V |
+       page_none = _PAGE_PRESENT_4V | _PAGE_ACCESSED_4V | page_cache4v_flag;
+       page_shared = (_PAGE_VALID | _PAGE_PRESENT_4V | page_cache4v_flag |
                       __ACCESS_BITS_4V | _PAGE_WRITE_4V | _PAGE_EXEC_4V);
-       page_copy   = (_PAGE_VALID | _PAGE_PRESENT_4V | _PAGE_CACHE_4V |
+       page_copy   = (_PAGE_VALID | _PAGE_PRESENT_4V | page_cache4v_flag |
                       __ACCESS_BITS_4V | _PAGE_EXEC_4V);
-       page_readonly = (_PAGE_VALID | _PAGE_PRESENT_4V | _PAGE_CACHE_4V |
+       page_readonly = (_PAGE_VALID | _PAGE_PRESENT_4V | page_cache4v_flag |
                         __ACCESS_BITS_4V | _PAGE_EXEC_4V);
 
        page_exec_bit = _PAGE_EXEC_4V;
@@ -2542,7 +2574,7 @@ static unsigned long kern_large_tte(unsigned long paddr)
               _PAGE_EXEC_4U | _PAGE_L_4U | _PAGE_W_4U);
        if (tlb_type == hypervisor)
                val = (_PAGE_VALID | _PAGE_SZ4MB_4V |
-                      _PAGE_CP_4V | _PAGE_CV_4V | _PAGE_P_4V |
+                      page_cache4v_flag | _PAGE_P_4V |
                       _PAGE_EXEC_4V | _PAGE_W_4V);
 
        return val | paddr;
index 6873f006f7d04fb1e71f8e9be386854431acb513..d366675e4bf88ef10e18f53637abd314b69b3725 100644 (file)
@@ -774,7 +774,7 @@ static void __init zone_sizes_init(void)
                 * though, there'll be no lowmem, so we just alloc_bootmem
                 * the memmap.  There will be no percpu memory either.
                 */
-               if (i != 0 && cpumask_test_cpu(i, &isolnodes)) {
+               if (i != 0 && node_isset(i, isolnodes)) {
                        node_memmap_pfn[i] =
                                alloc_bootmem_pfn(0, memmap_size, 0);
                        BUG_ON(node_percpu[i] != 0);
index ef17683484e9b308e2cb89312258dfe1e62e2d72..48304b89b601fa92bbd8ee1f5e548b4c2ffcc2dc 100644 (file)
@@ -1109,6 +1109,8 @@ struct boot_params *make_boot_params(struct efi_config *c)
        if (!cmdline_ptr)
                goto fail;
        hdr->cmd_line_ptr = (unsigned long)cmdline_ptr;
+       /* Fill in upper bits of command line address, NOP on 32 bit  */
+       boot_params->ext_cmd_line_ptr = (u64)(unsigned long)cmdline_ptr >> 32;
 
        hdr->ramdisk_image = 0;
        hdr->ramdisk_size = 0;
index 89dd0d78013aaff6c889340e0e3caceb4c8f8c88..805d25ca5f1db1602498c7047025b973ac788b3c 100644 (file)
@@ -2,15 +2,14 @@
 #define BOOT_COMPRESSED_MISC_H
 
 /*
- * we have to be careful, because no indirections are allowed here, and
- * paravirt_ops is a kind of one. As it will only run in baremetal anyway,
- * we just keep it from happening
+ * Special hack: we have to be careful, because no indirections are allowed here,
+ * and paravirt_ops is a kind of one. As it will only run in baremetal anyway,
+ * we just keep it from happening. (This list needs to be extended when new
+ * paravirt and debugging variants are added.)
  */
 #undef CONFIG_PARAVIRT
+#undef CONFIG_PARAVIRT_SPINLOCKS
 #undef CONFIG_KASAN
-#ifdef CONFIG_X86_32
-#define _ASM_X86_DESC_H 1
-#endif
 
 #include <linux/linkage.h>
 #include <linux/screen_info.h>
index e42f758a0fbd9b14b38feaae9fbb3f1a2bfcd204..055ea9941dd5f671d116306a6544adf7a4f189bc 100644 (file)
@@ -50,7 +50,7 @@ extern const struct hypervisor_x86 *x86_hyper;
 /* Recognized hypervisors */
 extern const struct hypervisor_x86 x86_hyper_vmware;
 extern const struct hypervisor_x86 x86_hyper_ms_hyperv;
-extern const struct hypervisor_x86 x86_hyper_xen_hvm;
+extern const struct hypervisor_x86 x86_hyper_xen;
 extern const struct hypervisor_x86 x86_hyper_kvm;
 
 extern void init_hypervisor(struct cpuinfo_x86 *c);
index dea2e7e962e3e0648c9ecaaaffc5cb723b32f299..f4a555beef1908b78c9ad6992d4727d59d9c81ee 100644 (file)
@@ -207,6 +207,7 @@ union kvm_mmu_page_role {
                unsigned nxe:1;
                unsigned cr0_wp:1;
                unsigned smep_andnot_wp:1;
+               unsigned smap_andnot_wp:1;
        };
 };
 
@@ -400,6 +401,7 @@ struct kvm_vcpu_arch {
        struct kvm_mmu_memory_cache mmu_page_header_cache;
 
        struct fpu guest_fpu;
+       bool eager_fpu;
        u64 xcr0;
        u64 guest_supported_xcr0;
        u32 guest_xstate_size;
@@ -743,6 +745,7 @@ struct kvm_x86_ops {
        void (*cache_reg)(struct kvm_vcpu *vcpu, enum kvm_reg reg);
        unsigned long (*get_rflags)(struct kvm_vcpu *vcpu);
        void (*set_rflags)(struct kvm_vcpu *vcpu, unsigned long rflags);
+       void (*fpu_activate)(struct kvm_vcpu *vcpu);
        void (*fpu_deactivate)(struct kvm_vcpu *vcpu);
 
        void (*tlb_flush)(struct kvm_vcpu *vcpu);
index 19507ffa5d28e9ce3ddece3856dd9cde4446f7f8..5fabf1362942c65e5fc4327511e51487a14bd5d7 100644 (file)
@@ -107,7 +107,7 @@ static inline unsigned long regs_return_value(struct pt_regs *regs)
 static inline int user_mode(struct pt_regs *regs)
 {
 #ifdef CONFIG_X86_32
-       return (regs->cs & SEGMENT_RPL_MASK) == USER_RPL;
+       return ((regs->cs & SEGMENT_RPL_MASK) | (regs->flags & X86_VM_MASK)) >= USER_RPL;
 #else
        return !!(regs->cs & 3);
 #endif
index 25b1cc07d49668c8a40306bf2ec81e4e2a11988e..d6b078e9fa28a3f4588237cb9a122f5b5ce53162 100644 (file)
@@ -95,7 +95,6 @@ unsigned __pvclock_read_cycles(const struct pvclock_vcpu_time_info *src,
 
 struct pvclock_vsyscall_time_info {
        struct pvclock_vcpu_time_info pvti;
-       u32 migrate_count;
 } __attribute__((__aligned__(SMP_CACHE_BYTES)));
 
 #define PVTI_SIZE sizeof(struct pvclock_vsyscall_time_info)
index 5a9856eb12bad7edb0f9a333870e331f5677d588..7d5a1929d76b31bba69295e533e460ed50904cfd 100644 (file)
 #define TLS_SIZE                       (GDT_ENTRY_TLS_ENTRIES* 8)
 
 #ifdef __KERNEL__
+
+/*
+ * early_idt_handler_array is an array of entry points referenced in the
+ * early IDT.  For simplicity, it's a real array with one entry point
+ * every nine bytes.  That leaves room for an optional 'push $0' if the
+ * vector has no error code (two bytes), a 'push $vector_number' (two
+ * bytes), and a jump to the common entry code (up to five bytes).
+ */
+#define EARLY_IDT_HANDLER_SIZE 9
+
 #ifndef __ASSEMBLY__
 
-extern const char early_idt_handlers[NUM_EXCEPTION_VECTORS][2+2+5];
+extern const char early_idt_handler_array[NUM_EXCEPTION_VECTORS][EARLY_IDT_HANDLER_SIZE];
 #ifdef CONFIG_TRACING
-# define trace_early_idt_handlers early_idt_handlers
+# define trace_early_idt_handler_array early_idt_handler_array
 #endif
 
 /*
index cf87de3fc39000eb21028ab2597d5187978bda4a..64b611782ef0856f1744611936f76d6e8de1bb57 100644 (file)
@@ -169,7 +169,7 @@ static inline int arch_spin_is_contended(arch_spinlock_t *lock)
        struct __raw_tickets tmp = READ_ONCE(lock->tickets);
 
        tmp.head &= ~TICKET_SLOWPATH_FLAG;
-       return (tmp.tail - tmp.head) > TICKET_LOCK_INC;
+       return (__ticket_t)(tmp.tail - tmp.head) > TICKET_LOCK_INC;
 }
 #define arch_spin_is_contended arch_spin_is_contended
 
index 358dcd33891582a2da1d07d0b75a11333091a1a9..c44a5d53e464733509de6d3d6347cf9b89889c06 100644 (file)
@@ -269,4 +269,9 @@ static inline bool xen_arch_need_swiotlb(struct device *dev,
        return false;
 }
 
+static inline unsigned long xen_get_swiotlb_free_pages(unsigned int order)
+{
+       return __get_free_pages(__GFP_NOWARN, order);
+}
+
 #endif /* _ASM_X86_XEN_PAGE_H */
index c469490db4a8d4a0c7ac7e71b17053fbd62b12e4..3c6bb342a48f1ad123ba82261c517c18266227b6 100644 (file)
 #define MSR_CORE_C3_RESIDENCY          0x000003fc
 #define MSR_CORE_C6_RESIDENCY          0x000003fd
 #define MSR_CORE_C7_RESIDENCY          0x000003fe
+#define MSR_KNL_CORE_C6_RESIDENCY      0x000003ff
 #define MSR_PKG_C2_RESIDENCY           0x0000060d
 #define MSR_PKG_C8_RESIDENCY           0x00000630
 #define MSR_PKG_C9_RESIDENCY           0x00000631
index 36ce402a3fa5b311014b30e3dd8cac69d5f68a88..d820d8eae96be0b3daa0ec01d9f4a22bf1ad930e 100644 (file)
@@ -27,8 +27,8 @@
 
 static const __initconst struct hypervisor_x86 * const hypervisors[] =
 {
-#ifdef CONFIG_XEN_PVHVM
-       &x86_hyper_xen_hvm,
+#ifdef CONFIG_XEN
+       &x86_hyper_xen,
 #endif
        &x86_hyper_vmware,
        &x86_hyper_ms_hyperv,
index e535533d5ab89313ba51937ad8dd5740413f119e..20190bdac9d58ecabddd3cbe6692d0f52bb687ad 100644 (file)
@@ -708,6 +708,7 @@ static int mce_no_way_out(struct mce *m, char **msg, unsigned long *validp,
                          struct pt_regs *regs)
 {
        int i, ret = 0;
+       char *tmp;
 
        for (i = 0; i < mca_cfg.banks; i++) {
                m->status = mce_rdmsrl(MSR_IA32_MCx_STATUS(i));
@@ -716,9 +717,11 @@ static int mce_no_way_out(struct mce *m, char **msg, unsigned long *validp,
                        if (quirk_no_way_out)
                                quirk_no_way_out(i, m, regs);
                }
-               if (mce_severity(m, mca_cfg.tolerant, msg, true) >=
-                   MCE_PANIC_SEVERITY)
+
+               if (mce_severity(m, mca_cfg.tolerant, &tmp, true) >= MCE_PANIC_SEVERITY) {
+                       *msg = tmp;
                        ret = 1;
+               }
        }
        return ret;
 }
index 87848ebe2bb79a56625908c5a6af1b78055d70c9..4f7001f28936f74f9cc75ba6124ee54f76e0ebe4 100644 (file)
@@ -190,6 +190,7 @@ static bool check_hw_exists(void)
        u64 val, val_fail, val_new= ~0;
        int i, reg, reg_fail, ret = 0;
        int bios_fail = 0;
+       int reg_safe = -1;
 
        /*
         * Check to see if the BIOS enabled any of the counters, if so
@@ -204,6 +205,8 @@ static bool check_hw_exists(void)
                        bios_fail = 1;
                        val_fail = val;
                        reg_fail = reg;
+               } else {
+                       reg_safe = i;
                }
        }
 
@@ -221,12 +224,23 @@ static bool check_hw_exists(void)
                }
        }
 
+       /*
+        * If all the counters are enabled, the below test will always
+        * fail.  The tools will also become useless in this scenario.
+        * Just fail and disable the hardware counters.
+        */
+
+       if (reg_safe == -1) {
+               reg = reg_safe;
+               goto msr_fail;
+       }
+
        /*
         * Read the current value, change it and read it back to see if it
         * matches, this is needed to detect certain hardware emulators
         * (qemu/kvm) that don't trap on the MSR access and always return 0s.
         */
-       reg = x86_pmu_event_addr(0);
+       reg = x86_pmu_event_addr(reg_safe);
        if (rdmsrl_safe(reg, &val))
                goto msr_fail;
        val ^= 0xffffUL;
@@ -611,6 +625,7 @@ struct sched_state {
        int     event;          /* event index */
        int     counter;        /* counter index */
        int     unassigned;     /* number of events to be assigned left */
+       int     nr_gp;          /* number of GP counters used */
        unsigned long used[BITS_TO_LONGS(X86_PMC_IDX_MAX)];
 };
 
@@ -620,27 +635,29 @@ struct sched_state {
 struct perf_sched {
        int                     max_weight;
        int                     max_events;
-       struct perf_event       **events;
-       struct sched_state      state;
+       int                     max_gp;
        int                     saved_states;
+       struct event_constraint **constraints;
+       struct sched_state      state;
        struct sched_state      saved[SCHED_STATES_MAX];
 };
 
 /*
  * Initialize interator that runs through all events and counters.
  */
-static void perf_sched_init(struct perf_sched *sched, struct perf_event **events,
-                           int num, int wmin, int wmax)
+static void perf_sched_init(struct perf_sched *sched, struct event_constraint **constraints,
+                           int num, int wmin, int wmax, int gpmax)
 {
        int idx;
 
        memset(sched, 0, sizeof(*sched));
        sched->max_events       = num;
        sched->max_weight       = wmax;
-       sched->events           = events;
+       sched->max_gp           = gpmax;
+       sched->constraints      = constraints;
 
        for (idx = 0; idx < num; idx++) {
-               if (events[idx]->hw.constraint->weight == wmin)
+               if (constraints[idx]->weight == wmin)
                        break;
        }
 
@@ -687,7 +704,7 @@ static bool __perf_sched_find_counter(struct perf_sched *sched)
        if (sched->state.event >= sched->max_events)
                return false;
 
-       c = sched->events[sched->state.event]->hw.constraint;
+       c = sched->constraints[sched->state.event];
        /* Prefer fixed purpose counters */
        if (c->idxmsk64 & (~0ULL << INTEL_PMC_IDX_FIXED)) {
                idx = INTEL_PMC_IDX_FIXED;
@@ -696,11 +713,16 @@ static bool __perf_sched_find_counter(struct perf_sched *sched)
                                goto done;
                }
        }
+
        /* Grab the first unused counter starting with idx */
        idx = sched->state.counter;
        for_each_set_bit_from(idx, c->idxmsk, INTEL_PMC_IDX_FIXED) {
-               if (!__test_and_set_bit(idx, sched->state.used))
+               if (!__test_and_set_bit(idx, sched->state.used)) {
+                       if (sched->state.nr_gp++ >= sched->max_gp)
+                               return false;
+
                        goto done;
+               }
        }
 
        return false;
@@ -745,7 +767,7 @@ static bool perf_sched_next_event(struct perf_sched *sched)
                        if (sched->state.weight > sched->max_weight)
                                return false;
                }
-               c = sched->events[sched->state.event]->hw.constraint;
+               c = sched->constraints[sched->state.event];
        } while (c->weight != sched->state.weight);
 
        sched->state.counter = 0;       /* start with first counter */
@@ -756,12 +778,12 @@ static bool perf_sched_next_event(struct perf_sched *sched)
 /*
  * Assign a counter for each event.
  */
-int perf_assign_events(struct perf_event **events, int n,
-                       int wmin, int wmax, int *assign)
+int perf_assign_events(struct event_constraint **constraints, int n,
+                       int wmin, int wmax, int gpmax, int *assign)
 {
        struct perf_sched sched;
 
-       perf_sched_init(&sched, events, n, wmin, wmax);
+       perf_sched_init(&sched, constraints, n, wmin, wmax, gpmax);
 
        do {
                if (!perf_sched_find_counter(&sched))
@@ -788,9 +810,9 @@ int x86_schedule_events(struct cpu_hw_events *cpuc, int n, int *assign)
                x86_pmu.start_scheduling(cpuc);
 
        for (i = 0, wmin = X86_PMC_IDX_MAX, wmax = 0; i < n; i++) {
-               hwc = &cpuc->event_list[i]->hw;
+               cpuc->event_constraint[i] = NULL;
                c = x86_pmu.get_event_constraints(cpuc, i, cpuc->event_list[i]);
-               hwc->constraint = c;
+               cpuc->event_constraint[i] = c;
 
                wmin = min(wmin, c->weight);
                wmax = max(wmax, c->weight);
@@ -801,7 +823,7 @@ int x86_schedule_events(struct cpu_hw_events *cpuc, int n, int *assign)
         */
        for (i = 0; i < n; i++) {
                hwc = &cpuc->event_list[i]->hw;
-               c = hwc->constraint;
+               c = cpuc->event_constraint[i];
 
                /* never assigned */
                if (hwc->idx == -1)
@@ -821,9 +843,26 @@ int x86_schedule_events(struct cpu_hw_events *cpuc, int n, int *assign)
        }
 
        /* slow path */
-       if (i != n)
-               unsched = perf_assign_events(cpuc->event_list, n, wmin,
-                                            wmax, assign);
+       if (i != n) {
+               int gpmax = x86_pmu.num_counters;
+
+               /*
+                * Do not allow scheduling of more than half the available
+                * generic counters.
+                *
+                * This helps avoid counter starvation of sibling thread by
+                * ensuring at most half the counters cannot be in exclusive
+                * mode. There is no designated counters for the limits. Any
+                * N/2 counters can be used. This helps with events with
+                * specific counter constraints.
+                */
+               if (is_ht_workaround_enabled() && !cpuc->is_fake &&
+                   READ_ONCE(cpuc->excl_cntrs->exclusive_present))
+                       gpmax /= 2;
+
+               unsched = perf_assign_events(cpuc->event_constraint, n, wmin,
+                                            wmax, gpmax, assign);
+       }
 
        /*
         * In case of success (unsched = 0), mark events as committed,
@@ -840,7 +879,7 @@ int x86_schedule_events(struct cpu_hw_events *cpuc, int n, int *assign)
                        e = cpuc->event_list[i];
                        e->hw.flags |= PERF_X86_EVENT_COMMITTED;
                        if (x86_pmu.commit_scheduling)
-                               x86_pmu.commit_scheduling(cpuc, e, assign[i]);
+                               x86_pmu.commit_scheduling(cpuc, i, assign[i]);
                }
        }
 
@@ -1292,8 +1331,10 @@ static void x86_pmu_del(struct perf_event *event, int flags)
                x86_pmu.put_event_constraints(cpuc, event);
 
        /* Delete the array entry. */
-       while (++i < cpuc->n_events)
+       while (++i < cpuc->n_events) {
                cpuc->event_list[i-1] = cpuc->event_list[i];
+               cpuc->event_constraint[i-1] = cpuc->event_constraint[i];
+       }
        --cpuc->n_events;
 
        perf_event_update_userpage(event);
index 6ac5cb7a9e14839dcd0b622a91f0f0939133c81e..ef78516850fb0e3ef653ff97bad5152b46389787 100644 (file)
@@ -74,6 +74,7 @@ struct event_constraint {
 #define PERF_X86_EVENT_EXCL            0x0040 /* HT exclusivity on counter */
 #define PERF_X86_EVENT_DYNAMIC         0x0080 /* dynamic alloc'd constraint */
 #define PERF_X86_EVENT_RDPMC_ALLOWED   0x0100 /* grant rdpmc permission */
+#define PERF_X86_EVENT_EXCL_ACCT       0x0200 /* accounted EXCL event */
 
 
 struct amd_nb {
@@ -134,8 +135,6 @@ enum intel_excl_state_type {
 struct intel_excl_states {
        enum intel_excl_state_type init_state[X86_PMC_IDX_MAX];
        enum intel_excl_state_type state[X86_PMC_IDX_MAX];
-       int  num_alloc_cntrs;/* #counters allocated */
-       int  max_alloc_cntrs;/* max #counters allowed */
        bool sched_started; /* true if scheduling has started */
 };
 
@@ -144,6 +143,11 @@ struct intel_excl_cntrs {
 
        struct intel_excl_states states[2];
 
+       union {
+               u16     has_exclusive[2];
+               u32     exclusive_present;
+       };
+
        int             refcnt;         /* per-core: #HT threads */
        unsigned        core_id;        /* per-core: core id */
 };
@@ -172,7 +176,11 @@ struct cpu_hw_events {
                                             added in the current transaction */
        int                     assign[X86_PMC_IDX_MAX]; /* event to counter assignment */
        u64                     tags[X86_PMC_IDX_MAX];
+
        struct perf_event       *event_list[X86_PMC_IDX_MAX]; /* in enabled order */
+       struct event_constraint *event_constraint[X86_PMC_IDX_MAX];
+
+       int                     n_excl; /* the number of exclusive events */
 
        unsigned int            group_flag;
        int                     is_fake;
@@ -519,9 +527,7 @@ struct x86_pmu {
        void            (*put_event_constraints)(struct cpu_hw_events *cpuc,
                                                 struct perf_event *event);
 
-       void            (*commit_scheduling)(struct cpu_hw_events *cpuc,
-                                            struct perf_event *event,
-                                            int cntr);
+       void            (*commit_scheduling)(struct cpu_hw_events *cpuc, int idx, int cntr);
 
        void            (*start_scheduling)(struct cpu_hw_events *cpuc);
 
@@ -717,8 +723,8 @@ static inline void __x86_pmu_enable_event(struct hw_perf_event *hwc,
 
 void x86_pmu_enable_all(int added);
 
-int perf_assign_events(struct perf_event **events, int n,
-                       int wmin, int wmax, int *assign);
+int perf_assign_events(struct event_constraint **constraints, int n,
+                       int wmin, int wmax, int gpmax, int *assign);
 int x86_schedule_events(struct cpu_hw_events *cpuc, int n, int *assign);
 
 void x86_pmu_stop(struct perf_event *event, int flags);
@@ -929,4 +935,8 @@ static inline struct intel_shared_regs *allocate_shared_regs(int cpu)
        return NULL;
 }
 
+static inline int is_ht_workaround_enabled(void)
+{
+       return 0;
+}
 #endif /* CONFIG_CPU_SUP_INTEL */
index 219d3fb423a17a1bb30e99d565ab01de552f49e7..a1e35c9f06b9522af32b79cd4837f3a93a083f6b 100644 (file)
@@ -1134,7 +1134,7 @@ static __initconst const u64 slm_hw_cache_extra_regs
  [ C(LL  ) ] = {
        [ C(OP_READ) ] = {
                [ C(RESULT_ACCESS) ] = SLM_DMND_READ|SLM_LLC_ACCESS,
-               [ C(RESULT_MISS)   ] = SLM_DMND_READ|SLM_LLC_MISS,
+               [ C(RESULT_MISS)   ] = 0,
        },
        [ C(OP_WRITE) ] = {
                [ C(RESULT_ACCESS) ] = SLM_DMND_WRITE|SLM_LLC_ACCESS,
@@ -1184,8 +1184,7 @@ static __initconst const u64 slm_hw_cache_event_ids
        [ C(OP_READ) ] = {
                /* OFFCORE_RESPONSE.ANY_DATA.LOCAL_CACHE */
                [ C(RESULT_ACCESS) ] = 0x01b7,
-               /* OFFCORE_RESPONSE.ANY_DATA.ANY_LLC_MISS */
-               [ C(RESULT_MISS)   ] = 0x01b7,
+               [ C(RESULT_MISS)   ] = 0,
        },
        [ C(OP_WRITE) ] = {
                /* OFFCORE_RESPONSE.ANY_RFO.LOCAL_CACHE */
@@ -1217,7 +1216,7 @@ static __initconst const u64 slm_hw_cache_event_ids
  [ C(ITLB) ] = {
        [ C(OP_READ) ] = {
                [ C(RESULT_ACCESS) ] = 0x00c0, /* INST_RETIRED.ANY_P */
-               [ C(RESULT_MISS)   ] = 0x0282, /* ITLB.MISSES */
+               [ C(RESULT_MISS)   ] = 0x40205, /* PAGE_WALKS.I_SIDE_WALKS */
        },
        [ C(OP_WRITE) ] = {
                [ C(RESULT_ACCESS) ] = -1,
@@ -1924,7 +1923,6 @@ intel_start_scheduling(struct cpu_hw_events *cpuc)
        xl = &excl_cntrs->states[tid];
 
        xl->sched_started = true;
-       xl->num_alloc_cntrs = 0;
        /*
         * lock shared state until we are done scheduling
         * in stop_event_scheduling()
@@ -2001,6 +1999,11 @@ intel_get_excl_constraints(struct cpu_hw_events *cpuc, struct perf_event *event,
         * across HT threads
         */
        is_excl = c->flags & PERF_X86_EVENT_EXCL;
+       if (is_excl && !(event->hw.flags & PERF_X86_EVENT_EXCL_ACCT)) {
+               event->hw.flags |= PERF_X86_EVENT_EXCL_ACCT;
+               if (!cpuc->n_excl++)
+                       WRITE_ONCE(excl_cntrs->has_exclusive[tid], 1);
+       }
 
        /*
         * xl = state of current HT
@@ -2009,18 +2012,6 @@ intel_get_excl_constraints(struct cpu_hw_events *cpuc, struct perf_event *event,
        xl = &excl_cntrs->states[tid];
        xlo = &excl_cntrs->states[o_tid];
 
-       /*
-        * do not allow scheduling of more than max_alloc_cntrs
-        * which is set to half the available generic counters.
-        * this helps avoid counter starvation of sibling thread
-        * by ensuring at most half the counters cannot be in
-        * exclusive mode. There is not designated counters for the
-        * limits. Any N/2 counters can be used. This helps with
-        * events with specifix counter constraints
-        */
-       if (xl->num_alloc_cntrs++ == xl->max_alloc_cntrs)
-               return &emptyconstraint;
-
        cx = c;
 
        /*
@@ -2107,7 +2098,7 @@ static struct event_constraint *
 intel_get_event_constraints(struct cpu_hw_events *cpuc, int idx,
                            struct perf_event *event)
 {
-       struct event_constraint *c1 = event->hw.constraint;
+       struct event_constraint *c1 = cpuc->event_constraint[idx];
        struct event_constraint *c2;
 
        /*
@@ -2151,6 +2142,11 @@ static void intel_put_excl_constraints(struct cpu_hw_events *cpuc,
 
        xl = &excl_cntrs->states[tid];
        xlo = &excl_cntrs->states[o_tid];
+       if (hwc->flags & PERF_X86_EVENT_EXCL_ACCT) {
+               hwc->flags &= ~PERF_X86_EVENT_EXCL_ACCT;
+               if (!--cpuc->n_excl)
+                       WRITE_ONCE(excl_cntrs->has_exclusive[tid], 0);
+       }
 
        /*
         * put_constraint may be called from x86_schedule_events()
@@ -2189,8 +2185,6 @@ intel_put_shared_regs_event_constraints(struct cpu_hw_events *cpuc,
 static void intel_put_event_constraints(struct cpu_hw_events *cpuc,
                                        struct perf_event *event)
 {
-       struct event_constraint *c = event->hw.constraint;
-
        intel_put_shared_regs_event_constraints(cpuc, event);
 
        /*
@@ -2198,19 +2192,14 @@ static void intel_put_event_constraints(struct cpu_hw_events *cpuc,
         * all events are subject to and must call the
         * put_excl_constraints() routine
         */
-       if (c && cpuc->excl_cntrs)
+       if (cpuc->excl_cntrs)
                intel_put_excl_constraints(cpuc, event);
-
-       /* cleanup dynamic constraint */
-       if (c && (c->flags & PERF_X86_EVENT_DYNAMIC))
-               event->hw.constraint = NULL;
 }
 
-static void intel_commit_scheduling(struct cpu_hw_events *cpuc,
-                                   struct perf_event *event, int cntr)
+static void intel_commit_scheduling(struct cpu_hw_events *cpuc, int idx, int cntr)
 {
        struct intel_excl_cntrs *excl_cntrs = cpuc->excl_cntrs;
-       struct event_constraint *c = event->hw.constraint;
+       struct event_constraint *c = cpuc->event_constraint[idx];
        struct intel_excl_states *xlo, *xl;
        int tid = cpuc->excl_thread_id;
        int o_tid = 1 - tid;
@@ -2533,34 +2522,6 @@ ssize_t intel_event_sysfs_show(char *page, u64 config)
        return x86_event_sysfs_show(page, config, event);
 }
 
-static __initconst const struct x86_pmu core_pmu = {
-       .name                   = "core",
-       .handle_irq             = x86_pmu_handle_irq,
-       .disable_all            = x86_pmu_disable_all,
-       .enable_all             = core_pmu_enable_all,
-       .enable                 = core_pmu_enable_event,
-       .disable                = x86_pmu_disable_event,
-       .hw_config              = x86_pmu_hw_config,
-       .schedule_events        = x86_schedule_events,
-       .eventsel               = MSR_ARCH_PERFMON_EVENTSEL0,
-       .perfctr                = MSR_ARCH_PERFMON_PERFCTR0,
-       .event_map              = intel_pmu_event_map,
-       .max_events             = ARRAY_SIZE(intel_perfmon_event_map),
-       .apic                   = 1,
-       /*
-        * Intel PMCs cannot be accessed sanely above 32 bit width,
-        * so we install an artificial 1<<31 period regardless of
-        * the generic event period:
-        */
-       .max_period             = (1ULL << 31) - 1,
-       .get_event_constraints  = intel_get_event_constraints,
-       .put_event_constraints  = intel_put_event_constraints,
-       .event_constraints      = intel_core_event_constraints,
-       .guest_get_msrs         = core_guest_get_msrs,
-       .format_attrs           = intel_arch_formats_attr,
-       .events_sysfs_show      = intel_event_sysfs_show,
-};
-
 struct intel_shared_regs *allocate_shared_regs(int cpu)
 {
        struct intel_shared_regs *regs;
@@ -2668,8 +2629,6 @@ static void intel_pmu_cpu_starting(int cpu)
                cpuc->lbr_sel = &cpuc->shared_regs->regs[EXTRA_REG_LBR];
 
        if (x86_pmu.flags & PMU_FL_EXCL_CNTRS) {
-               int h = x86_pmu.num_counters >> 1;
-
                for_each_cpu(i, topology_thread_cpumask(cpu)) {
                        struct intel_excl_cntrs *c;
 
@@ -2683,11 +2642,6 @@ static void intel_pmu_cpu_starting(int cpu)
                }
                cpuc->excl_cntrs->core_id = core_id;
                cpuc->excl_cntrs->refcnt++;
-               /*
-                * set hard limit to half the number of generic counters
-                */
-               cpuc->excl_cntrs->states[0].max_alloc_cntrs = h;
-               cpuc->excl_cntrs->states[1].max_alloc_cntrs = h;
        }
 }
 
@@ -2743,6 +2697,44 @@ static struct attribute *intel_arch3_formats_attr[] = {
        NULL,
 };
 
+static __initconst const struct x86_pmu core_pmu = {
+       .name                   = "core",
+       .handle_irq             = x86_pmu_handle_irq,
+       .disable_all            = x86_pmu_disable_all,
+       .enable_all             = core_pmu_enable_all,
+       .enable                 = core_pmu_enable_event,
+       .disable                = x86_pmu_disable_event,
+       .hw_config              = x86_pmu_hw_config,
+       .schedule_events        = x86_schedule_events,
+       .eventsel               = MSR_ARCH_PERFMON_EVENTSEL0,
+       .perfctr                = MSR_ARCH_PERFMON_PERFCTR0,
+       .event_map              = intel_pmu_event_map,
+       .max_events             = ARRAY_SIZE(intel_perfmon_event_map),
+       .apic                   = 1,
+       /*
+        * Intel PMCs cannot be accessed sanely above 32-bit width,
+        * so we install an artificial 1<<31 period regardless of
+        * the generic event period:
+        */
+       .max_period             = (1ULL<<31) - 1,
+       .get_event_constraints  = intel_get_event_constraints,
+       .put_event_constraints  = intel_put_event_constraints,
+       .event_constraints      = intel_core_event_constraints,
+       .guest_get_msrs         = core_guest_get_msrs,
+       .format_attrs           = intel_arch_formats_attr,
+       .events_sysfs_show      = intel_event_sysfs_show,
+
+       /*
+        * Virtual (or funny metal) CPU can define x86_pmu.extra_regs
+        * together with PMU version 1 and thus be using core_pmu with
+        * shared_regs. We need following callbacks here to allocate
+        * it properly.
+        */
+       .cpu_prepare            = intel_pmu_cpu_prepare,
+       .cpu_starting           = intel_pmu_cpu_starting,
+       .cpu_dying              = intel_pmu_cpu_dying,
+};
+
 static __initconst const struct x86_pmu intel_pmu = {
        .name                   = "Intel",
        .handle_irq             = intel_pmu_handle_irq,
index 813f75d71175e3a117f13ec53efe6856a0508bec..7f73b3553e2ee03af8dd6283cf8b3182173d3a2d 100644 (file)
@@ -706,9 +706,9 @@ void intel_pmu_pebs_disable(struct perf_event *event)
 
        cpuc->pebs_enabled &= ~(1ULL << hwc->idx);
 
-       if (event->hw.constraint->flags & PERF_X86_EVENT_PEBS_LDLAT)
+       if (event->hw.flags & PERF_X86_EVENT_PEBS_LDLAT)
                cpuc->pebs_enabled &= ~(1ULL << (hwc->idx + 32));
-       else if (event->hw.constraint->flags & PERF_X86_EVENT_PEBS_ST)
+       else if (event->hw.flags & PERF_X86_EVENT_PEBS_ST)
                cpuc->pebs_enabled &= ~(1ULL << 63);
 
        if (cpuc->enabled)
index ffe666c2c6b58657b5895948a2e7d69f95223521..123ff1bb2f60363c9dc267329fb199dedecfde63 100644 (file)
@@ -151,7 +151,7 @@ static int __init pt_pmu_hw_init(void)
 
                de_attr->attr.attr.name = pt_caps[i].name;
 
-               sysfs_attr_init(&de_attrs->attr.attr);
+               sysfs_attr_init(&de_attr->attr.attr);
 
                de_attr->attr.attr.mode         = S_IRUGO;
                de_attr->attr.show              = pt_cap_show;
@@ -615,7 +615,8 @@ static int pt_buffer_reset_markers(struct pt_buffer *buf,
                                   struct perf_output_handle *handle)
 
 {
-       unsigned long idx, npages, end;
+       unsigned long head = local64_read(&buf->head);
+       unsigned long idx, npages, wakeup;
 
        if (buf->snapshot)
                return 0;
@@ -634,17 +635,26 @@ static int pt_buffer_reset_markers(struct pt_buffer *buf,
        buf->topa_index[buf->stop_pos]->stop = 0;
        buf->topa_index[buf->intr_pos]->intr = 0;
 
-       if (pt_cap_get(PT_CAP_topa_multiple_entries)) {
-               npages = (handle->size + 1) >> PAGE_SHIFT;
-               end = (local64_read(&buf->head) >> PAGE_SHIFT) + npages;
-               /*if (end > handle->wakeup >> PAGE_SHIFT)
-                 end = handle->wakeup >> PAGE_SHIFT;*/
-               idx = end & (buf->nr_pages - 1);
-               buf->stop_pos = idx;
-               idx = (local64_read(&buf->head) >> PAGE_SHIFT) + npages - 1;
-               idx &= buf->nr_pages - 1;
-               buf->intr_pos = idx;
-       }
+       /* how many pages till the STOP marker */
+       npages = handle->size >> PAGE_SHIFT;
+
+       /* if it's on a page boundary, fill up one more page */
+       if (!offset_in_page(head + handle->size + 1))
+               npages++;
+
+       idx = (head >> PAGE_SHIFT) + npages;
+       idx &= buf->nr_pages - 1;
+       buf->stop_pos = idx;
+
+       wakeup = handle->wakeup >> PAGE_SHIFT;
+
+       /* in the worst case, wake up the consumer one page before hard stop */
+       idx = (head >> PAGE_SHIFT) + npages - 1;
+       if (idx > wakeup)
+               idx = wakeup;
+
+       idx &= buf->nr_pages - 1;
+       buf->intr_pos = idx;
 
        buf->topa_index[buf->stop_pos]->stop = 1;
        buf->topa_index[buf->intr_pos]->intr = 1;
index 999289b94025623415693df205054e754e9a7d4b..358c54ad20d4084db807a05ae49def561aa4dd32 100644 (file)
@@ -722,6 +722,7 @@ static int __init rapl_pmu_init(void)
                break;
        case 60: /* Haswell */
        case 69: /* Haswell-Celeron */
+       case 61: /* Broadwell */
                rapl_cntr_mask = RAPL_IDX_HSW;
                rapl_pmu_events_group.attrs = rapl_events_hsw_attr;
                break;
index c635b8b49e931e7926efc3dc96475a8c577958e0..90b7c501c95ba021a7017efa71463cef26111c66 100644 (file)
@@ -365,9 +365,8 @@ static int uncore_assign_events(struct intel_uncore_box *box, int assign[], int
        bitmap_zero(used_mask, UNCORE_PMC_IDX_MAX);
 
        for (i = 0, wmin = UNCORE_PMC_IDX_MAX, wmax = 0; i < n; i++) {
-               hwc = &box->event_list[i]->hw;
                c = uncore_get_event_constraint(box, box->event_list[i]);
-               hwc->constraint = c;
+               box->event_constraint[i] = c;
                wmin = min(wmin, c->weight);
                wmax = max(wmax, c->weight);
        }
@@ -375,7 +374,7 @@ static int uncore_assign_events(struct intel_uncore_box *box, int assign[], int
        /* fastpath, try to reuse previous register */
        for (i = 0; i < n; i++) {
                hwc = &box->event_list[i]->hw;
-               c = hwc->constraint;
+               c = box->event_constraint[i];
 
                /* never assigned */
                if (hwc->idx == -1)
@@ -395,8 +394,8 @@ static int uncore_assign_events(struct intel_uncore_box *box, int assign[], int
        }
        /* slow path */
        if (i != n)
-               ret = perf_assign_events(box->event_list, n,
-                                        wmin, wmax, assign);
+               ret = perf_assign_events(box->event_constraint, n,
+                                        wmin, wmax, n, assign);
 
        if (!assign || ret) {
                for (i = 0; i < n; i++)
@@ -840,6 +839,7 @@ static int uncore_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id
        box->phys_id = phys_id;
        box->pci_dev = pdev;
        box->pmu = pmu;
+       uncore_box_init(box);
        pci_set_drvdata(pdev, box);
 
        raw_spin_lock(&uncore_box_lock);
@@ -1003,8 +1003,10 @@ static int uncore_cpu_starting(int cpu)
                        pmu = &type->pmus[j];
                        box = *per_cpu_ptr(pmu->box, cpu);
                        /* called by uncore_cpu_init? */
-                       if (box && box->phys_id >= 0)
+                       if (box && box->phys_id >= 0) {
+                               uncore_box_init(box);
                                continue;
+                       }
 
                        for_each_online_cpu(k) {
                                exist = *per_cpu_ptr(pmu->box, k);
@@ -1020,8 +1022,10 @@ static int uncore_cpu_starting(int cpu)
                                }
                        }
 
-                       if (box)
+                       if (box) {
                                box->phys_id = phys_id;
+                               uncore_box_init(box);
+                       }
                }
        }
        return 0;
index 6c8c1e7e69d85d3ad217eada0f0e55573c3daaf0..ceac8f5dc0184b531548e302e11ae981e753a7e9 100644 (file)
@@ -97,6 +97,7 @@ struct intel_uncore_box {
        atomic_t refcnt;
        struct perf_event *events[UNCORE_PMC_IDX_MAX];
        struct perf_event *event_list[UNCORE_PMC_IDX_MAX];
+       struct event_constraint *event_constraint[UNCORE_PMC_IDX_MAX];
        unsigned long active_mask[BITS_TO_LONGS(UNCORE_PMC_IDX_MAX)];
        u64 tags[UNCORE_PMC_IDX_MAX];
        struct pci_dev *pci_dev;
@@ -257,14 +258,6 @@ static inline int uncore_num_counters(struct intel_uncore_box *box)
        return box->pmu->type->num_counters;
 }
 
-static inline void uncore_box_init(struct intel_uncore_box *box)
-{
-       if (!test_and_set_bit(UNCORE_BOX_FLAG_INITIATED, &box->flags)) {
-               if (box->pmu->type->ops->init_box)
-                       box->pmu->type->ops->init_box(box);
-       }
-}
-
 static inline void uncore_disable_box(struct intel_uncore_box *box)
 {
        if (box->pmu->type->ops->disable_box)
@@ -273,8 +266,6 @@ static inline void uncore_disable_box(struct intel_uncore_box *box)
 
 static inline void uncore_enable_box(struct intel_uncore_box *box)
 {
-       uncore_box_init(box);
-
        if (box->pmu->type->ops->enable_box)
                box->pmu->type->ops->enable_box(box);
 }
@@ -297,6 +288,14 @@ static inline u64 uncore_read_counter(struct intel_uncore_box *box,
        return box->pmu->type->ops->read_counter(box, event);
 }
 
+static inline void uncore_box_init(struct intel_uncore_box *box)
+{
+       if (!test_and_set_bit(UNCORE_BOX_FLAG_INITIATED, &box->flags)) {
+               if (box->pmu->type->ops->init_box)
+                       box->pmu->type->ops->init_box(box);
+       }
+}
+
 static inline bool uncore_box_is_fake(struct intel_uncore_box *box)
 {
        return (box->phys_id < 0);
index 3001015b755c7e4dc2f540db36d3d1a88cb09bbf..4562e9e22c60600a89f706c3b8c3cfb269636060 100644 (file)
@@ -1,6 +1,13 @@
 /* Nehalem/SandBridge/Haswell uncore support */
 #include "perf_event_intel_uncore.h"
 
+/* Uncore IMC PCI IDs */
+#define PCI_DEVICE_ID_INTEL_SNB_IMC    0x0100
+#define PCI_DEVICE_ID_INTEL_IVB_IMC    0x0154
+#define PCI_DEVICE_ID_INTEL_IVB_E3_IMC 0x0150
+#define PCI_DEVICE_ID_INTEL_HSW_IMC    0x0c00
+#define PCI_DEVICE_ID_INTEL_HSW_U_IMC  0x0a04
+
 /* SNB event control */
 #define SNB_UNC_CTL_EV_SEL_MASK                        0x000000ff
 #define SNB_UNC_CTL_UMASK_MASK                 0x0000ff00
@@ -472,6 +479,10 @@ static const struct pci_device_id hsw_uncore_pci_ids[] = {
                PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_HSW_IMC),
                .driver_data = UNCORE_PCI_DEV_DATA(SNB_PCI_UNCORE_IMC, 0),
        },
+       { /* IMC */
+               PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_HSW_U_IMC),
+               .driver_data = UNCORE_PCI_DEV_DATA(SNB_PCI_UNCORE_IMC, 0),
+       },
        { /* end: all zeroes */ },
 };
 
@@ -502,6 +513,7 @@ static const struct imc_uncore_pci_dev desktop_imc_pci_ids[] = {
        IMC_DEV(IVB_IMC, &ivb_uncore_pci_driver),    /* 3rd Gen Core processor */
        IMC_DEV(IVB_E3_IMC, &ivb_uncore_pci_driver), /* Xeon E3-1200 v2/3rd Gen Core processor */
        IMC_DEV(HSW_IMC, &hsw_uncore_pci_driver),    /* 4th Gen Core Processor */
+       IMC_DEV(HSW_U_IMC, &hsw_uncore_pci_driver),  /* 4th Gen Core ULT Mobile Processor */
        {  /* end marker */ }
 };
 
index 12d9548457e7195a8a36b458e374cab9cabe5e07..6d6e85dd5849878e9caa379ef20eaab10b97559f 100644 (file)
                                ((1ULL << (n)) - 1)))
 
 /* Haswell-EP Ubox */
-#define HSWEP_U_MSR_PMON_CTR0                  0x705
-#define HSWEP_U_MSR_PMON_CTL0                  0x709
+#define HSWEP_U_MSR_PMON_CTR0                  0x709
+#define HSWEP_U_MSR_PMON_CTL0                  0x705
 #define HSWEP_U_MSR_PMON_FILTER                        0x707
 
 #define HSWEP_U_MSR_PMON_UCLK_FIXED_CTL                0x703
@@ -1914,7 +1914,7 @@ static struct intel_uncore_type hswep_uncore_cbox = {
        .name                   = "cbox",
        .num_counters           = 4,
        .num_boxes              = 18,
-       .perf_ctr_bits          = 44,
+       .perf_ctr_bits          = 48,
        .event_ctl              = HSWEP_C0_MSR_PMON_CTL0,
        .perf_ctr               = HSWEP_C0_MSR_PMON_CTR0,
        .event_mask             = SNBEP_CBO_MSR_PMON_RAW_EVENT_MASK,
index 2b55ee6db053c79fbe91a6119e613075be54111b..5a4668136e9892b6b8695d1d82edf86afbdea0a0 100644 (file)
@@ -167,7 +167,7 @@ asmlinkage __visible void __init x86_64_start_kernel(char * real_mode_data)
        clear_bss();
 
        for (i = 0; i < NUM_EXCEPTION_VECTORS; i++)
-               set_intr_gate(i, early_idt_handlers[i]);
+               set_intr_gate(i, early_idt_handler_array[i]);
        load_idt((const struct desc_ptr *)&idt_descr);
 
        copy_bootdata(__va(real_mode_data));
index d031bad9e07eadf3a80bc69a449cd13a44ed8080..53eeb226657caa6868c826dd4b1fb83a1bf514a0 100644 (file)
@@ -478,21 +478,22 @@ is486:
 __INIT
 setup_once:
        /*
-        * Set up a idt with 256 entries pointing to ignore_int,
-        * interrupt gates. It doesn't actually load idt - that needs
-        * to be done on each CPU. Interrupts are enabled elsewhere,
-        * when we can be relatively sure everything is ok.
+        * Set up a idt with 256 interrupt gates that push zero if there
+        * is no error code and then jump to early_idt_handler_common.
+        * It doesn't actually load the idt - that needs to be done on
+        * each CPU. Interrupts are enabled elsewhere, when we can be
+        * relatively sure everything is ok.
         */
 
        movl $idt_table,%edi
-       movl $early_idt_handlers,%eax
+       movl $early_idt_handler_array,%eax
        movl $NUM_EXCEPTION_VECTORS,%ecx
 1:
        movl %eax,(%edi)
        movl %eax,4(%edi)
        /* interrupt gate, dpl=0, present */
        movl $(0x8E000000 + __KERNEL_CS),2(%edi)
-       addl $9,%eax
+       addl $EARLY_IDT_HANDLER_SIZE,%eax
        addl $8,%edi
        loop 1b
 
@@ -524,26 +525,28 @@ setup_once:
        andl $0,setup_once_ref  /* Once is enough, thanks */
        ret
 
-ENTRY(early_idt_handlers)
+ENTRY(early_idt_handler_array)
        # 36(%esp) %eflags
        # 32(%esp) %cs
        # 28(%esp) %eip
        # 24(%rsp) error code
        i = 0
        .rept NUM_EXCEPTION_VECTORS
-       .if (EXCEPTION_ERRCODE_MASK >> i) & 1
-       ASM_NOP2
-       .else
+       .ifeq (EXCEPTION_ERRCODE_MASK >> i) & 1
        pushl $0                # Dummy error code, to make stack frame uniform
        .endif
        pushl $i                # 20(%esp) Vector number
-       jmp early_idt_handler
+       jmp early_idt_handler_common
        i = i + 1
+       .fill early_idt_handler_array + i*EARLY_IDT_HANDLER_SIZE - ., 1, 0xcc
        .endr
-ENDPROC(early_idt_handlers)
+ENDPROC(early_idt_handler_array)
        
-       /* This is global to keep gas from relaxing the jumps */
-ENTRY(early_idt_handler)
+early_idt_handler_common:
+       /*
+        * The stack is the hardware frame, an error code or zero, and the
+        * vector number.
+        */
        cld
 
        cmpl $2,(%esp)          # X86_TRAP_NMI
@@ -603,7 +606,7 @@ ex_entry:
 is_nmi:
        addl $8,%esp            /* drop vector number and error code */
        iret
-ENDPROC(early_idt_handler)
+ENDPROC(early_idt_handler_common)
 
 /* This is the default interrupt "handler" :-) */
        ALIGN
index ae6588b301c248b3c281a1e072802e6764e9ac44..df7e78057ae007dab28bf625f4cbbba25cf9bcd6 100644 (file)
@@ -321,26 +321,28 @@ bad_address:
        jmp bad_address
 
        __INIT
-       .globl early_idt_handlers
-early_idt_handlers:
+ENTRY(early_idt_handler_array)
        # 104(%rsp) %rflags
        #  96(%rsp) %cs
        #  88(%rsp) %rip
        #  80(%rsp) error code
        i = 0
        .rept NUM_EXCEPTION_VECTORS
-       .if (EXCEPTION_ERRCODE_MASK >> i) & 1
-       ASM_NOP2
-       .else
+       .ifeq (EXCEPTION_ERRCODE_MASK >> i) & 1
        pushq $0                # Dummy error code, to make stack frame uniform
        .endif
        pushq $i                # 72(%rsp) Vector number
-       jmp early_idt_handler
+       jmp early_idt_handler_common
        i = i + 1
+       .fill early_idt_handler_array + i*EARLY_IDT_HANDLER_SIZE - ., 1, 0xcc
        .endr
+ENDPROC(early_idt_handler_array)
 
-/* This is global to keep gas from relaxing the jumps */
-ENTRY(early_idt_handler)
+early_idt_handler_common:
+       /*
+        * The stack is the hardware frame, an error code or zero, and the
+        * vector number.
+        */
        cld
 
        cmpl $2,(%rsp)          # X86_TRAP_NMI
@@ -412,7 +414,7 @@ ENTRY(early_idt_handler)
 is_nmi:
        addq $16,%rsp           # drop vector number and error code
        INTERRUPT_RETURN
-ENDPROC(early_idt_handler)
+ENDPROC(early_idt_handler_common)
 
        __INITDATA
 
index 009183276bb738fbd28805256ccfaa04e063c364..6185d3141219019d82fa2ea56c4f2f5728b8d17a 100644 (file)
@@ -173,6 +173,21 @@ static void init_thread_xstate(void)
                xstate_size = sizeof(struct i387_fxsave_struct);
        else
                xstate_size = sizeof(struct i387_fsave_struct);
+
+       /*
+        * Quirk: we don't yet handle the XSAVES* instructions
+        * correctly, as we don't correctly convert between
+        * standard and compacted format when interfacing
+        * with user-space - so disable it for now.
+        *
+        * The difference is small: with recent CPUs the
+        * compacted format is only marginally smaller than
+        * the standard FPU state format.
+        *
+        * ( This is easy to backport while we are fixing
+        *   XSAVES* support. )
+        */
+       setup_clear_cpu_cap(X86_FEATURE_XSAVES);
 }
 
 /*
index 8213da62b1b79c1c37798b598494add6802881d7..6e338e3b1dc04cc69ab41c012fe5671cc25321cd 100644 (file)
@@ -57,7 +57,7 @@ __visible DEFINE_PER_CPU_SHARED_ALIGNED(struct tss_struct, cpu_tss) = {
        .io_bitmap              = { [0 ... IO_BITMAP_LONGS] = ~0 },
 #endif
 };
-EXPORT_PER_CPU_SYMBOL_GPL(cpu_tss);
+EXPORT_PER_CPU_SYMBOL(cpu_tss);
 
 #ifdef CONFIG_X86_64
 static DEFINE_PER_CPU(unsigned char, is_idle);
@@ -156,11 +156,13 @@ void flush_thread(void)
                /* FPU state will be reallocated lazily at the first use. */
                drop_fpu(tsk);
                free_thread_xstate(tsk);
-       } else if (!used_math()) {
-               /* kthread execs. TODO: cleanup this horror. */
-               if (WARN_ON(init_fpu(tsk)))
-                       force_sig(SIGKILL, tsk);
-               user_fpu_begin();
+       } else {
+               if (!tsk_used_math(tsk)) {
+                       /* kthread execs. TODO: cleanup this horror. */
+                       if (WARN_ON(init_fpu(tsk)))
+                               force_sig(SIGKILL, tsk);
+                       user_fpu_begin();
+               }
                restore_init_xstate();
        }
 }
index e5ecd20e72dd56d82447c94c17e6e85ae29eba90..2f355d229a587771680b28080d92fd06f345d7e7 100644 (file)
@@ -141,46 +141,7 @@ void pvclock_read_wallclock(struct pvclock_wall_clock *wall_clock,
        set_normalized_timespec(ts, now.tv_sec, now.tv_nsec);
 }
 
-static struct pvclock_vsyscall_time_info *pvclock_vdso_info;
-
-static struct pvclock_vsyscall_time_info *
-pvclock_get_vsyscall_user_time_info(int cpu)
-{
-       if (!pvclock_vdso_info) {
-               BUG();
-               return NULL;
-       }
-
-       return &pvclock_vdso_info[cpu];
-}
-
-struct pvclock_vcpu_time_info *pvclock_get_vsyscall_time_info(int cpu)
-{
-       return &pvclock_get_vsyscall_user_time_info(cpu)->pvti;
-}
-
 #ifdef CONFIG_X86_64
-static int pvclock_task_migrate(struct notifier_block *nb, unsigned long l,
-                               void *v)
-{
-       struct task_migration_notifier *mn = v;
-       struct pvclock_vsyscall_time_info *pvti;
-
-       pvti = pvclock_get_vsyscall_user_time_info(mn->from_cpu);
-
-       /* this is NULL when pvclock vsyscall is not initialized */
-       if (unlikely(pvti == NULL))
-               return NOTIFY_DONE;
-
-       pvti->migrate_count++;
-
-       return NOTIFY_DONE;
-}
-
-static struct notifier_block pvclock_migrate = {
-       .notifier_call = pvclock_task_migrate,
-};
-
 /*
  * Initialize the generic pvclock vsyscall state.  This will allocate
  * a/some page(s) for the per-vcpu pvclock information, set up a
@@ -194,17 +155,12 @@ int __init pvclock_init_vsyscall(struct pvclock_vsyscall_time_info *i,
 
        WARN_ON (size != PVCLOCK_VSYSCALL_NR_PAGES*PAGE_SIZE);
 
-       pvclock_vdso_info = i;
-
        for (idx = 0; idx <= (PVCLOCK_FIXMAP_END-PVCLOCK_FIXMAP_BEGIN); idx++) {
                __set_fixmap(PVCLOCK_FIXMAP_BEGIN + idx,
                             __pa(i) + (idx*PAGE_SIZE),
                             PAGE_KERNEL_VVAR);
        }
 
-
-       register_task_migration_notifier(&pvclock_migrate);
-
        return 0;
 }
 #endif
index 59b69f6a2844cdce101a69c3bb34eb7ccd30556f..1d08ad3582d07fd61cd03302eba547e3a997058b 100644 (file)
@@ -16,6 +16,8 @@
 #include <linux/module.h>
 #include <linux/vmalloc.h>
 #include <linux/uaccess.h>
+#include <asm/i387.h> /* For use_eager_fpu.  Ugh! */
+#include <asm/fpu-internal.h> /* For use_eager_fpu.  Ugh! */
 #include <asm/user.h>
 #include <asm/xsave.h>
 #include "cpuid.h"
@@ -95,6 +97,8 @@ int kvm_update_cpuid(struct kvm_vcpu *vcpu)
        if (best && (best->eax & (F(XSAVES) | F(XSAVEC))))
                best->ebx = xstate_required_size(vcpu->arch.xcr0, true);
 
+       vcpu->arch.eager_fpu = guest_cpuid_has_mpx(vcpu);
+
        /*
         * The existing code assumes virtual address is 48-bit in the canonical
         * address checks; exit if it is ever changed.
index c3b1ad9fca818befb9e5920f7eb7c0d2b703d245..496b3695d3d3c96fd2687b2b6bc013d9ee8d96e5 100644 (file)
@@ -117,4 +117,12 @@ static inline bool guest_cpuid_has_rtm(struct kvm_vcpu *vcpu)
        best = kvm_find_cpuid_entry(vcpu, 7, 0);
        return best && (best->ebx & bit(X86_FEATURE_RTM));
 }
+
+static inline bool guest_cpuid_has_mpx(struct kvm_vcpu *vcpu)
+{
+       struct kvm_cpuid_entry2 *best;
+
+       best = kvm_find_cpuid_entry(vcpu, 7, 0);
+       return best && (best->ebx & bit(X86_FEATURE_MPX));
+}
 #endif
index d43867c33bc4efee0c970e9602cd63616b4ec739..b73337634214c209e250051cd21e00bd2436fcd6 100644 (file)
@@ -3736,8 +3736,8 @@ static void reset_rsvds_bits_mask_ept(struct kvm_vcpu *vcpu,
        }
 }
 
-void update_permission_bitmask(struct kvm_vcpu *vcpu,
-               struct kvm_mmu *mmu, bool ept)
+static void update_permission_bitmask(struct kvm_vcpu *vcpu,
+                                     struct kvm_mmu *mmu, bool ept)
 {
        unsigned bit, byte, pfec;
        u8 map;
@@ -3918,6 +3918,7 @@ static void init_kvm_tdp_mmu(struct kvm_vcpu *vcpu)
 void kvm_init_shadow_mmu(struct kvm_vcpu *vcpu)
 {
        bool smep = kvm_read_cr4_bits(vcpu, X86_CR4_SMEP);
+       bool smap = kvm_read_cr4_bits(vcpu, X86_CR4_SMAP);
        struct kvm_mmu *context = &vcpu->arch.mmu;
 
        MMU_WARN_ON(VALID_PAGE(context->root_hpa));
@@ -3936,6 +3937,8 @@ void kvm_init_shadow_mmu(struct kvm_vcpu *vcpu)
        context->base_role.cr0_wp  = is_write_protection(vcpu);
        context->base_role.smep_andnot_wp
                = smep && !is_write_protection(vcpu);
+       context->base_role.smap_andnot_wp
+               = smap && !is_write_protection(vcpu);
 }
 EXPORT_SYMBOL_GPL(kvm_init_shadow_mmu);
 
@@ -4207,12 +4210,18 @@ void kvm_mmu_pte_write(struct kvm_vcpu *vcpu, gpa_t gpa,
                       const u8 *new, int bytes)
 {
        gfn_t gfn = gpa >> PAGE_SHIFT;
-       union kvm_mmu_page_role mask = { .word = 0 };
        struct kvm_mmu_page *sp;
        LIST_HEAD(invalid_list);
        u64 entry, gentry, *spte;
        int npte;
        bool remote_flush, local_flush, zap_page;
+       union kvm_mmu_page_role mask = { };
+
+       mask.cr0_wp = 1;
+       mask.cr4_pae = 1;
+       mask.nxe = 1;
+       mask.smep_andnot_wp = 1;
+       mask.smap_andnot_wp = 1;
 
        /*
         * If we don't have indirect shadow pages, it means no page is
@@ -4238,7 +4247,6 @@ void kvm_mmu_pte_write(struct kvm_vcpu *vcpu, gpa_t gpa,
        ++vcpu->kvm->stat.mmu_pte_write;
        kvm_mmu_audit(vcpu, AUDIT_PRE_PTE_WRITE);
 
-       mask.cr0_wp = mask.cr4_pae = mask.nxe = 1;
        for_each_gfn_indirect_valid_sp(vcpu->kvm, sp, gfn) {
                if (detect_write_misaligned(sp, gpa, bytes) ||
                      detect_write_flooding(sp)) {
index c7d65637c8518e55e3650b01d3b106cea9597962..0ada65ecddcf27ca619269d92435012c3f19790a 100644 (file)
@@ -71,8 +71,6 @@ enum {
 int handle_mmio_page_fault_common(struct kvm_vcpu *vcpu, u64 addr, bool direct);
 void kvm_init_shadow_mmu(struct kvm_vcpu *vcpu);
 void kvm_init_shadow_ept_mmu(struct kvm_vcpu *vcpu, bool execonly);
-void update_permission_bitmask(struct kvm_vcpu *vcpu, struct kvm_mmu *mmu,
-               bool ept);
 
 static inline unsigned int kvm_mmu_available_pages(struct kvm *kvm)
 {
@@ -166,6 +164,8 @@ static inline bool permission_fault(struct kvm_vcpu *vcpu, struct kvm_mmu *mmu,
        int index = (pfec >> 1) +
                    (smap >> (X86_EFLAGS_AC_BIT - PFERR_RSVD_BIT + 1));
 
+       WARN_ON(pfec & PFERR_RSVD_MASK);
+
        return (mmu->permissions[index] >> pte_access) & 1;
 }
 
index fd49c867b25a11927fc2f6ef4522e1ef9ee80c11..6e6d115fe9b542607c946cf57d1cc37ca948c923 100644 (file)
@@ -718,6 +718,13 @@ static int FNAME(page_fault)(struct kvm_vcpu *vcpu, gva_t addr, u32 error_code,
                                              mmu_is_nested(vcpu));
                if (likely(r != RET_MMIO_PF_INVALID))
                        return r;
+
+               /*
+                * page fault with PFEC.RSVD  = 1 is caused by shadow
+                * page fault, should not be used to walk guest page
+                * table.
+                */
+               error_code &= ~PFERR_RSVD_MASK;
        };
 
        r = mmu_topup_memory_caches(vcpu);
index ce741b8650f6ece694fb47e1750d153291a1803f..9afa233b5482f6a68addba2494916e9624e52566 100644 (file)
@@ -4381,6 +4381,7 @@ static struct kvm_x86_ops svm_x86_ops = {
        .cache_reg = svm_cache_reg,
        .get_rflags = svm_get_rflags,
        .set_rflags = svm_set_rflags,
+       .fpu_activate = svm_fpu_activate,
        .fpu_deactivate = svm_fpu_deactivate,
 
        .tlb_flush = svm_flush_tlb,
index f7b61687bd79facc3f6ed0339b68ecf3fcf43aed..2d73807f0d317f3c46a7aa42234a67d6894b20a2 100644 (file)
@@ -10185,6 +10185,7 @@ static struct kvm_x86_ops vmx_x86_ops = {
        .cache_reg = vmx_cache_reg,
        .get_rflags = vmx_get_rflags,
        .set_rflags = vmx_set_rflags,
+       .fpu_activate = vmx_fpu_activate,
        .fpu_deactivate = vmx_fpu_deactivate,
 
        .tlb_flush = vmx_flush_tlb,
index ed31c31b2485b1e06476f93ab7934b216ed1cacc..ea306adbbc13603591d46d3f062cc20cf1bc37d1 100644 (file)
@@ -702,8 +702,9 @@ EXPORT_SYMBOL_GPL(kvm_set_xcr);
 int kvm_set_cr4(struct kvm_vcpu *vcpu, unsigned long cr4)
 {
        unsigned long old_cr4 = kvm_read_cr4(vcpu);
-       unsigned long pdptr_bits = X86_CR4_PGE | X86_CR4_PSE |
-                                  X86_CR4_PAE | X86_CR4_SMEP;
+       unsigned long pdptr_bits = X86_CR4_PGE | X86_CR4_PSE | X86_CR4_PAE |
+                                  X86_CR4_SMEP | X86_CR4_SMAP;
+
        if (cr4 & CR4_RESERVED_BITS)
                return 1;
 
@@ -744,9 +745,6 @@ int kvm_set_cr4(struct kvm_vcpu *vcpu, unsigned long cr4)
            (!(cr4 & X86_CR4_PCIDE) && (old_cr4 & X86_CR4_PCIDE)))
                kvm_mmu_reset_context(vcpu);
 
-       if ((cr4 ^ old_cr4) & X86_CR4_SMAP)
-               update_permission_bitmask(vcpu, vcpu->arch.walk_mmu, false);
-
        if ((cr4 ^ old_cr4) & X86_CR4_OSXSAVE)
                kvm_update_cpuid(vcpu);
 
@@ -1669,12 +1667,28 @@ static int kvm_guest_time_update(struct kvm_vcpu *v)
                &guest_hv_clock, sizeof(guest_hv_clock))))
                return 0;
 
-       /*
-        * The interface expects us to write an even number signaling that the
-        * update is finished. Since the guest won't see the intermediate
-        * state, we just increase by 2 at the end.
+       /* This VCPU is paused, but it's legal for a guest to read another
+        * VCPU's kvmclock, so we really have to follow the specification where
+        * it says that version is odd if data is being modified, and even after
+        * it is consistent.
+        *
+        * Version field updates must be kept separate.  This is because
+        * kvm_write_guest_cached might use a "rep movs" instruction, and
+        * writes within a string instruction are weakly ordered.  So there
+        * are three writes overall.
+        *
+        * As a small optimization, only write the version field in the first
+        * and third write.  The vcpu->pv_time cache is still valid, because the
+        * version field is the first in the struct.
         */
-       vcpu->hv_clock.version = guest_hv_clock.version + 2;
+       BUILD_BUG_ON(offsetof(struct pvclock_vcpu_time_info, version) != 0);
+
+       vcpu->hv_clock.version = guest_hv_clock.version + 1;
+       kvm_write_guest_cached(v->kvm, &vcpu->pv_time,
+                               &vcpu->hv_clock,
+                               sizeof(vcpu->hv_clock.version));
+
+       smp_wmb();
 
        /* retain PVCLOCK_GUEST_STOPPED if set in guest copy */
        pvclock_flags = (guest_hv_clock.flags & PVCLOCK_GUEST_STOPPED);
@@ -1695,6 +1709,13 @@ static int kvm_guest_time_update(struct kvm_vcpu *v)
        kvm_write_guest_cached(v->kvm, &vcpu->pv_time,
                                &vcpu->hv_clock,
                                sizeof(vcpu->hv_clock));
+
+       smp_wmb();
+
+       vcpu->hv_clock.version++;
+       kvm_write_guest_cached(v->kvm, &vcpu->pv_time,
+                               &vcpu->hv_clock,
+                               sizeof(vcpu->hv_clock.version));
        return 0;
 }
 
@@ -6174,6 +6195,8 @@ void kvm_vcpu_reload_apic_access_page(struct kvm_vcpu *vcpu)
                return;
 
        page = gfn_to_page(vcpu->kvm, APIC_DEFAULT_PHYS_BASE >> PAGE_SHIFT);
+       if (is_error_page(page))
+               return;
        kvm_x86_ops->set_apic_access_page_addr(vcpu, page_to_phys(page));
 
        /*
@@ -7037,7 +7060,9 @@ void kvm_put_guest_fpu(struct kvm_vcpu *vcpu)
        fpu_save_init(&vcpu->arch.guest_fpu);
        __kernel_fpu_end();
        ++vcpu->stat.fpu_reload;
-       kvm_make_request(KVM_REQ_DEACTIVATE_FPU, vcpu);
+       if (!vcpu->arch.eager_fpu)
+               kvm_make_request(KVM_REQ_DEACTIVATE_FPU, vcpu);
+
        trace_kvm_fpu(0);
 }
 
@@ -7053,11 +7078,21 @@ void kvm_arch_vcpu_free(struct kvm_vcpu *vcpu)
 struct kvm_vcpu *kvm_arch_vcpu_create(struct kvm *kvm,
                                                unsigned int id)
 {
+       struct kvm_vcpu *vcpu;
+
        if (check_tsc_unstable() && atomic_read(&kvm->online_vcpus) != 0)
                printk_once(KERN_WARNING
                "kvm: SMP vm created on host with unstable TSC; "
                "guest TSC will not be reliable\n");
-       return kvm_x86_ops->vcpu_create(kvm, id);
+
+       vcpu = kvm_x86_ops->vcpu_create(kvm, id);
+
+       /*
+        * Activate fpu unconditionally in case the guest needs eager FPU.  It will be
+        * deactivated soon if it doesn't.
+        */
+       kvm_x86_ops->fpu_activate(vcpu);
+       return vcpu;
 }
 
 int kvm_arch_vcpu_setup(struct kvm_vcpu *vcpu)
index 5ead4d6cf3a7ae4173265924246415b8fa12d520..70e7444c68351641828b834fd9a9a4fc9cea3b65 100644 (file)
@@ -351,18 +351,20 @@ int arch_ioremap_pmd_supported(void)
  */
 void *xlate_dev_mem_ptr(phys_addr_t phys)
 {
-       void *addr;
-       unsigned long start = phys & PAGE_MASK;
+       unsigned long start  = phys &  PAGE_MASK;
+       unsigned long offset = phys & ~PAGE_MASK;
+       unsigned long vaddr;
 
        /* If page is RAM, we can use __va. Otherwise ioremap and unmap. */
        if (page_is_ram(start >> PAGE_SHIFT))
                return __va(phys);
 
-       addr = (void __force *)ioremap_cache(start, PAGE_SIZE);
-       if (addr)
-               addr = (void *)((unsigned long)addr | (phys & ~PAGE_MASK));
+       vaddr = (unsigned long)ioremap_cache(start, PAGE_SIZE);
+       /* Only add the offset on success and return NULL if the ioremap() failed: */
+       if (vaddr)
+               vaddr += offset;
 
-       return addr;
+       return (void *)vaddr;
 }
 
 void unxlate_dev_mem_ptr(phys_addr_t phys, void *addr)
index 987514396c1e443376bffe70e050b72f86509102..ddeff4844a100de83b52ef9dae9f42974666dc23 100644 (file)
@@ -559,6 +559,13 @@ static int do_jit(struct bpf_prog *bpf_prog, int *addrs, u8 *image,
                                if (is_ereg(dst_reg))
                                        EMIT1(0x41);
                                EMIT3(0xC1, add_1reg(0xC8, dst_reg), 8);
+
+                               /* emit 'movzwl eax, ax' */
+                               if (is_ereg(dst_reg))
+                                       EMIT3(0x45, 0x0F, 0xB7);
+                               else
+                                       EMIT2(0x0F, 0xB7);
+                               EMIT1(add_2reg(0xC0, dst_reg, dst_reg));
                                break;
                        case 32:
                                /* emit 'bswap eax' to swap lower 4 bytes */
@@ -577,6 +584,27 @@ static int do_jit(struct bpf_prog *bpf_prog, int *addrs, u8 *image,
                        break;
 
                case BPF_ALU | BPF_END | BPF_FROM_LE:
+                       switch (imm32) {
+                       case 16:
+                               /* emit 'movzwl eax, ax' to zero extend 16-bit
+                                * into 64 bit
+                                */
+                               if (is_ereg(dst_reg))
+                                       EMIT3(0x45, 0x0F, 0xB7);
+                               else
+                                       EMIT2(0x0F, 0xB7);
+                               EMIT1(add_2reg(0xC0, dst_reg, dst_reg));
+                               break;
+                       case 32:
+                               /* emit 'mov eax, eax' to clear upper 32-bits */
+                               if (is_ereg(dst_reg))
+                                       EMIT1(0x45);
+                               EMIT2(0x89, add_2reg(0xC0, dst_reg, dst_reg));
+                               break;
+                       case 64:
+                               /* nop */
+                               break;
+                       }
                        break;
 
                        /* ST: *(u8*)(dst_reg + off) = imm */
@@ -938,7 +966,12 @@ void bpf_int_jit_compile(struct bpf_prog *prog)
        }
        ctx.cleanup_addr = proglen;
 
-       for (pass = 0; pass < 10; pass++) {
+       /* JITed image shrinks with every pass and the loop iterates
+        * until the image stops shrinking. Very large bpf programs
+        * may converge on the last pass. In such case do one more
+        * pass to emit the final image
+        */
+       for (pass = 0; pass < 10 || image; pass++) {
                proglen = do_jit(prog, addrs, image, oldproglen, &ctx);
                if (proglen <= 0) {
                        image = NULL;
index e4695985f9de85778db5e084b37eda5719d3a82a..14a63ed6fe092cd3f512d155046942a28c3744e8 100644 (file)
@@ -325,6 +325,26 @@ static void release_pci_root_info(struct pci_host_bridge *bridge)
        kfree(info);
 }
 
+/*
+ * An IO port or MMIO resource assigned to a PCI host bridge may be
+ * consumed by the host bridge itself or available to its child
+ * bus/devices. The ACPI specification defines a bit (Producer/Consumer)
+ * to tell whether the resource is consumed by the host bridge itself,
+ * but firmware hasn't used that bit consistently, so we can't rely on it.
+ *
+ * On x86 and IA64 platforms, all IO port and MMIO resources are assumed
+ * to be available to child bus/devices except one special case:
+ *     IO port [0xCF8-0xCFF] is consumed by the host bridge itself
+ *     to access PCI configuration space.
+ *
+ * So explicitly filter out PCI CFG IO ports[0xCF8-0xCFF].
+ */
+static bool resource_is_pcicfg_ioport(struct resource *res)
+{
+       return (res->flags & IORESOURCE_IO) &&
+               res->start == 0xCF8 && res->end == 0xCFF;
+}
+
 static void probe_pci_root_info(struct pci_root_info *info,
                                struct acpi_device *device,
                                int busnum, int domain,
@@ -346,8 +366,8 @@ static void probe_pci_root_info(struct pci_root_info *info,
                        "no IO and memory resources present in _CRS\n");
        else
                resource_list_for_each_entry_safe(entry, tmp, list) {
-                       if ((entry->res->flags & IORESOURCE_WINDOW) == 0 ||
-                           (entry->res->flags & IORESOURCE_DISABLED))
+                       if ((entry->res->flags & IORESOURCE_DISABLED) ||
+                           resource_is_pcicfg_ioport(entry->res))
                                resource_list_destroy_entry(entry);
                        else
                                entry->res->name = info->name;
@@ -462,9 +482,16 @@ struct pci_bus *pci_acpi_scan_root(struct acpi_pci_root *root)
 
 int pcibios_root_bridge_prepare(struct pci_host_bridge *bridge)
 {
-       struct pci_sysdata *sd = bridge->bus->sysdata;
-
-       ACPI_COMPANION_SET(&bridge->dev, sd->companion);
+       /*
+        * We pass NULL as parent to pci_create_root_bus(), so if it is not NULL
+        * here, pci_create_root_bus() has been called by someone else and
+        * sysdata is likely to be different from what we expect.  Let it go in
+        * that case.
+        */
+       if (!bridge->dev.parent) {
+               struct pci_sysdata *sd = bridge->bus->sysdata;
+               ACPI_COMPANION_SET(&bridge->dev, sd->companion);
+       }
        return 0;
 }
 
index 275a3a8b78afa3221b78296d2a7e3c2945de512b..e97032069f88cdcc8f1c692bd63960fd8bda517d 100644 (file)
@@ -51,7 +51,7 @@ VDSO_LDFLAGS_vdso.lds = -m64 -Wl,-soname=linux-vdso.so.1 \
 $(obj)/vdso64.so.dbg: $(src)/vdso.lds $(vobjs) FORCE
        $(call if_changed,vdso)
 
-HOST_EXTRACFLAGS += -I$(srctree)/tools/include -I$(srctree)/include/uapi
+HOST_EXTRACFLAGS += -I$(srctree)/tools/include -I$(srctree)/include/uapi -I$(srctree)/arch/x86/include/uapi
 hostprogs-y                    += vdso2c
 
 quiet_cmd_vdso2c = VDSO2C  $@
index 40d2473836c923acc5705018bf3aebf50cfb12b8..9793322751e02f63ddba0d1b8fef5f21b0a4d502 100644 (file)
@@ -82,15 +82,18 @@ static notrace cycle_t vread_pvclock(int *mode)
        cycle_t ret;
        u64 last;
        u32 version;
-       u32 migrate_count;
        u8 flags;
        unsigned cpu, cpu1;
 
 
        /*
-        * When looping to get a consistent (time-info, tsc) pair, we
-        * also need to deal with the possibility we can switch vcpus,
-        * so make sure we always re-fetch time-info for the current vcpu.
+        * Note: hypervisor must guarantee that:
+        * 1. cpu ID number maps 1:1 to per-CPU pvclock time info.
+        * 2. that per-CPU pvclock time info is updated if the
+        *    underlying CPU changes.
+        * 3. that version is increased whenever underlying CPU
+        *    changes.
+        *
         */
        do {
                cpu = __getcpu() & VGETCPU_CPU_MASK;
@@ -99,27 +102,20 @@ static notrace cycle_t vread_pvclock(int *mode)
                 * __getcpu() calls (Gleb).
                 */
 
-               /* Make sure migrate_count will change if we leave the VCPU. */
-               do {
-                       pvti = get_pvti(cpu);
-                       migrate_count = pvti->migrate_count;
-
-                       cpu1 = cpu;
-                       cpu = __getcpu() & VGETCPU_CPU_MASK;
-               } while (unlikely(cpu != cpu1));
+               pvti = get_pvti(cpu);
 
                version = __pvclock_read_cycles(&pvti->pvti, &ret, &flags);
 
                /*
                 * Test we're still on the cpu as well as the version.
-                * - We must read TSC of pvti's VCPU.
-                * - KVM doesn't follow the versioning protocol, so data could
-                *   change before version if we left the VCPU.
+                * We could have been migrated just after the first
+                * vgetcpu but before fetching the version, so we
+                * wouldn't notice a version change.
                 */
-               smp_rmb();
-       } while (unlikely((pvti->pvti.version & 1) ||
-                         pvti->pvti.version != version ||
-                         pvti->migrate_count != migrate_count));
+               cpu1 = __getcpu() & VGETCPU_CPU_MASK;
+       } while (unlikely(cpu != cpu1 ||
+                         (pvti->pvti.version & 1) ||
+                         pvti->pvti.version != version));
 
        if (unlikely(!(flags & PVCLOCK_TSC_STABLE_BIT)))
                *mode = VCLOCK_NONE;
index 94578efd3067f0a0fd86c36c5b3be07eced3d509..46957ead3060eecb5e76b6f6daf3b498a6b6a5e9 100644 (file)
@@ -1760,6 +1760,9 @@ static struct notifier_block xen_hvm_cpu_notifier = {
 
 static void __init xen_hvm_guest_init(void)
 {
+       if (xen_pv_domain())
+               return;
+
        init_hvm_pv_info();
 
        xen_hvm_init_shared_info();
@@ -1775,6 +1778,7 @@ static void __init xen_hvm_guest_init(void)
        xen_hvm_init_time_ops();
        xen_hvm_init_mmu_ops();
 }
+#endif
 
 static bool xen_nopv = false;
 static __init int xen_parse_nopv(char *arg)
@@ -1784,14 +1788,11 @@ static __init int xen_parse_nopv(char *arg)
 }
 early_param("xen_nopv", xen_parse_nopv);
 
-static uint32_t __init xen_hvm_platform(void)
+static uint32_t __init xen_platform(void)
 {
        if (xen_nopv)
                return 0;
 
-       if (xen_pv_domain())
-               return 0;
-
        return xen_cpuid_base();
 }
 
@@ -1809,11 +1810,19 @@ bool xen_hvm_need_lapic(void)
 }
 EXPORT_SYMBOL_GPL(xen_hvm_need_lapic);
 
-const struct hypervisor_x86 x86_hyper_xen_hvm __refconst = {
-       .name                   = "Xen HVM",
-       .detect                 = xen_hvm_platform,
+static void xen_set_cpu_features(struct cpuinfo_x86 *c)
+{
+       if (xen_pv_domain())
+               clear_cpu_bug(c, X86_BUG_SYSRET_SS_ATTRS);
+}
+
+const struct hypervisor_x86 x86_hyper_xen = {
+       .name                   = "Xen",
+       .detect                 = xen_platform,
+#ifdef CONFIG_XEN_PVHVM
        .init_platform          = xen_hvm_guest_init,
+#endif
        .x2apic_available       = xen_x2apic_para_available,
+       .set_cpu_features       = xen_set_cpu_features,
 };
-EXPORT_SYMBOL(x86_hyper_xen_hvm);
-#endif
+EXPORT_SYMBOL(x86_hyper_xen);
index d9497698645a53b10ab4b62ddc98d12f4412a616..53b4c0811f4f64a72d286fcaa2a9cab9749bacc2 100644 (file)
@@ -88,7 +88,17 @@ static void xen_vcpu_notify_restore(void *data)
        tick_resume_local();
 }
 
+static void xen_vcpu_notify_suspend(void *data)
+{
+       tick_suspend_local();
+}
+
 void xen_arch_resume(void)
 {
        on_each_cpu(xen_vcpu_notify_restore, NULL, 1);
 }
+
+void xen_arch_suspend(void)
+{
+       on_each_cpu(xen_vcpu_notify_suspend, NULL, 1);
+}
index 172a02a6ad146fea24ab966cf46a3612434a03da..ba78ccf651e7764e9db92cfca37927a8d68e3892 100644 (file)
@@ -185,4 +185,17 @@ static inline int dma_get_sgtable(struct device *dev, struct sg_table *sgt,
        return -EINVAL;
 }
 
+static inline void *dma_alloc_attrs(struct device *dev, size_t size,
+                                   dma_addr_t *dma_handle, gfp_t flag,
+                                   struct dma_attrs *attrs)
+{
+       return NULL;
+}
+
+static inline void dma_free_attrs(struct device *dev, size_t size,
+                                 void *vaddr, dma_addr_t dma_handle,
+                                 struct dma_attrs *attrs)
+{
+}
+
 #endif /* _XTENSA_DMA_MAPPING_H */
index fd154b94447a25788f48d5e8cc04bc803d1efdb8..03b5f8d77f37b4cbad3a12f3a98f9c3ea63a50e7 100644 (file)
@@ -552,6 +552,8 @@ void blk_cleanup_queue(struct request_queue *q)
                q->queue_lock = &q->__queue_lock;
        spin_unlock_irq(lock);
 
+       bdi_destroy(&q->backing_dev_info);
+
        /* @q is and will stay empty, shutdown and put */
        blk_put_queue(q);
 }
@@ -732,6 +734,8 @@ blk_init_queue_node(request_fn_proc *rfn, spinlock_t *lock, int node_id)
 }
 EXPORT_SYMBOL(blk_init_queue_node);
 
+static void blk_queue_bio(struct request_queue *q, struct bio *bio);
+
 struct request_queue *
 blk_init_allocated_queue(struct request_queue *q, request_fn_proc *rfn,
                         spinlock_t *lock)
@@ -1576,7 +1580,7 @@ void init_request_from_bio(struct request *req, struct bio *bio)
        blk_rq_bio_prep(req->q, req, bio);
 }
 
-void blk_queue_bio(struct request_queue *q, struct bio *bio)
+static void blk_queue_bio(struct request_queue *q, struct bio *bio)
 {
        const bool sync = !!(bio->bi_rw & REQ_SYNC);
        struct blk_plug *plug;
@@ -1684,7 +1688,6 @@ out_unlock:
                spin_unlock_irq(q->queue_lock);
        }
 }
-EXPORT_SYMBOL_GPL(blk_queue_bio);      /* for device mapper only */
 
 /*
  * If bio->bi_dev is a partition, remap the location
index ade8a2d1b0aa8600ad31413b59db37392628bffc..594eea04266e6d05f7256255552a1c4c72c664f3 100644 (file)
@@ -677,8 +677,11 @@ static void blk_mq_rq_timer(unsigned long priv)
                data.next = blk_rq_timeout(round_jiffies_up(data.next));
                mod_timer(&q->timeout, data.next);
        } else {
-               queue_for_each_hw_ctx(q, hctx, i)
-                       blk_mq_tag_idle(hctx);
+               queue_for_each_hw_ctx(q, hctx, i) {
+                       /* the hctx may be unmapped, so check it here */
+                       if (blk_mq_hw_queue_mapped(hctx))
+                               blk_mq_tag_idle(hctx);
+               }
        }
 }
 
@@ -855,6 +858,16 @@ static void __blk_mq_run_hw_queue(struct blk_mq_hw_ctx *hctx)
                spin_lock(&hctx->lock);
                list_splice(&rq_list, &hctx->dispatch);
                spin_unlock(&hctx->lock);
+               /*
+                * the queue is expected stopped with BLK_MQ_RQ_QUEUE_BUSY, but
+                * it's possible the queue is stopped and restarted again
+                * before this. Queue restart will dispatch requests. And since
+                * requests in rq_list aren't added into hctx->dispatch yet,
+                * the requests in rq_list might get lost.
+                *
+                * blk_mq_run_hw_queue() already checks the STOPPED bit
+                **/
+               blk_mq_run_hw_queue(hctx, true);
        }
 }
 
@@ -1571,22 +1584,6 @@ static int blk_mq_hctx_cpu_offline(struct blk_mq_hw_ctx *hctx, int cpu)
        return NOTIFY_OK;
 }
 
-static int blk_mq_hctx_cpu_online(struct blk_mq_hw_ctx *hctx, int cpu)
-{
-       struct request_queue *q = hctx->queue;
-       struct blk_mq_tag_set *set = q->tag_set;
-
-       if (set->tags[hctx->queue_num])
-               return NOTIFY_OK;
-
-       set->tags[hctx->queue_num] = blk_mq_init_rq_map(set, hctx->queue_num);
-       if (!set->tags[hctx->queue_num])
-               return NOTIFY_STOP;
-
-       hctx->tags = set->tags[hctx->queue_num];
-       return NOTIFY_OK;
-}
-
 static int blk_mq_hctx_notify(void *data, unsigned long action,
                              unsigned int cpu)
 {
@@ -1594,12 +1591,16 @@ static int blk_mq_hctx_notify(void *data, unsigned long action,
 
        if (action == CPU_DEAD || action == CPU_DEAD_FROZEN)
                return blk_mq_hctx_cpu_offline(hctx, cpu);
-       else if (action == CPU_ONLINE || action == CPU_ONLINE_FROZEN)
-               return blk_mq_hctx_cpu_online(hctx, cpu);
+
+       /*
+        * In case of CPU online, tags may be reallocated
+        * in blk_mq_map_swqueue() after mapping is updated.
+        */
 
        return NOTIFY_OK;
 }
 
+/* hctx->ctxs will be freed in queue's release handler */
 static void blk_mq_exit_hctx(struct request_queue *q,
                struct blk_mq_tag_set *set,
                struct blk_mq_hw_ctx *hctx, unsigned int hctx_idx)
@@ -1618,7 +1619,6 @@ static void blk_mq_exit_hctx(struct request_queue *q,
 
        blk_mq_unregister_cpu_notifier(&hctx->cpu_notifier);
        blk_free_flush_queue(hctx->fq);
-       kfree(hctx->ctxs);
        blk_mq_free_bitmap(&hctx->ctx_map);
 }
 
@@ -1775,6 +1775,7 @@ static void blk_mq_map_swqueue(struct request_queue *q)
        unsigned int i;
        struct blk_mq_hw_ctx *hctx;
        struct blk_mq_ctx *ctx;
+       struct blk_mq_tag_set *set = q->tag_set;
 
        queue_for_each_hw_ctx(q, hctx, i) {
                cpumask_clear(hctx->cpumask);
@@ -1803,16 +1804,20 @@ static void blk_mq_map_swqueue(struct request_queue *q)
                 * disable it and free the request entries.
                 */
                if (!hctx->nr_ctx) {
-                       struct blk_mq_tag_set *set = q->tag_set;
-
                        if (set->tags[i]) {
                                blk_mq_free_rq_map(set, set->tags[i], i);
                                set->tags[i] = NULL;
-                               hctx->tags = NULL;
                        }
+                       hctx->tags = NULL;
                        continue;
                }
 
+               /* unmapped hw queue can be remapped after CPU topo changed */
+               if (!set->tags[i])
+                       set->tags[i] = blk_mq_init_rq_map(set, i);
+               hctx->tags = set->tags[i];
+               WARN_ON(!hctx->tags);
+
                /*
                 * Set the map size to the number of mapped software queues.
                 * This is more accurate and more efficient than looping
@@ -1886,8 +1891,12 @@ void blk_mq_release(struct request_queue *q)
        unsigned int i;
 
        /* hctx kobj stays in hctx */
-       queue_for_each_hw_ctx(q, hctx, i)
+       queue_for_each_hw_ctx(q, hctx, i) {
+               if (!hctx)
+                       continue;
+               kfree(hctx->ctxs);
                kfree(hctx);
+       }
 
        kfree(q->queue_hw_ctx);
 
@@ -2090,9 +2099,16 @@ static int blk_mq_queue_reinit_notify(struct notifier_block *nb,
         */
        list_for_each_entry(q, &all_q_list, all_q_node)
                blk_mq_freeze_queue_start(q);
-       list_for_each_entry(q, &all_q_list, all_q_node)
+       list_for_each_entry(q, &all_q_list, all_q_node) {
                blk_mq_freeze_queue_wait(q);
 
+               /*
+                * timeout handler can't touch hw queue during the
+                * reinitialization
+                */
+               del_timer_sync(&q->timeout);
+       }
+
        list_for_each_entry(q, &all_q_list, all_q_node)
                blk_mq_queue_reinit(q);
 
index faaf36ade7ebdc2fdd363f174978bfb5683a4f9a..2b8fd302f677a967d87994f8a7532aab8dfe6569 100644 (file)
@@ -522,8 +522,6 @@ static void blk_release_queue(struct kobject *kobj)
 
        blk_trace_shutdown(q);
 
-       bdi_destroy(&q->backing_dev_info);
-
        ida_simple_remove(&blk_queue_ida, q->id);
        call_rcu(&q->rcu_head, blk_free_queue_rcu);
 }
index ab21ba203d5c7744f4da2afbba85ed45dde86b98..ed9dd80671204bdebc4005544097fb05b6c90c62 100644 (file)
@@ -221,8 +221,8 @@ bounce:
                if (page_to_pfn(page) <= queue_bounce_pfn(q) && !force)
                        continue;
 
-               inc_zone_page_state(to->bv_page, NR_BOUNCE);
                to->bv_page = mempool_alloc(pool, q->bounce_gfp);
+               inc_zone_page_state(to->bv_page, NR_BOUNCE);
 
                if (rw == WRITE) {
                        char *vto, *vfrom;
index 59794d0d38e34604a24b6e7a63bf309570b2f8fb..8985038f398ce503261dc4a29390a63c9f7b5b44 100644 (file)
@@ -157,7 +157,7 @@ struct elevator_queue *elevator_alloc(struct request_queue *q,
 
        eq = kzalloc_node(sizeof(*eq), GFP_KERNEL, q->node);
        if (unlikely(!eq))
-               goto err;
+               return NULL;
 
        eq->type = e;
        kobject_init(&eq->kobj, &elv_ktype);
@@ -165,10 +165,6 @@ struct elevator_queue *elevator_alloc(struct request_queue *q,
        hash_init(eq->hash);
 
        return eq;
-err:
-       kfree(eq);
-       elevator_put(e);
-       return NULL;
 }
 EXPORT_SYMBOL(elevator_alloc);
 
index 0a536dc05f3b559d6d04c1e819d65290f96f7c35..ea982eadaf6380b974d6b1d39a7197085217ac91 100644 (file)
@@ -422,9 +422,9 @@ int blk_alloc_devt(struct hd_struct *part, dev_t *devt)
        /* allocate ext devt */
        idr_preload(GFP_KERNEL);
 
-       spin_lock(&ext_devt_lock);
+       spin_lock_bh(&ext_devt_lock);
        idx = idr_alloc(&ext_devt_idr, part, 0, NR_EXT_DEVT, GFP_NOWAIT);
-       spin_unlock(&ext_devt_lock);
+       spin_unlock_bh(&ext_devt_lock);
 
        idr_preload_end();
        if (idx < 0)
@@ -449,9 +449,9 @@ void blk_free_devt(dev_t devt)
                return;
 
        if (MAJOR(devt) == BLOCK_EXT_MAJOR) {
-               spin_lock(&ext_devt_lock);
+               spin_lock_bh(&ext_devt_lock);
                idr_remove(&ext_devt_idr, blk_mangle_minor(MINOR(devt)));
-               spin_unlock(&ext_devt_lock);
+               spin_unlock_bh(&ext_devt_lock);
        }
 }
 
@@ -653,7 +653,6 @@ void del_gendisk(struct gendisk *disk)
        disk->flags &= ~GENHD_FL_UP;
 
        sysfs_remove_link(&disk_to_dev(disk)->kobj, "bdi");
-       bdi_unregister(&disk->queue->backing_dev_info);
        blk_unregister_queue(disk);
        blk_unregister_region(disk_devt(disk), disk->minors);
 
@@ -691,13 +690,13 @@ struct gendisk *get_gendisk(dev_t devt, int *partno)
        } else {
                struct hd_struct *part;
 
-               spin_lock(&ext_devt_lock);
+               spin_lock_bh(&ext_devt_lock);
                part = idr_find(&ext_devt_idr, blk_mangle_minor(MINOR(devt)));
                if (part && get_disk(part_to_disk(part))) {
                        *partno = part->partno;
                        disk = part_to_disk(part);
                }
-               spin_unlock(&ext_devt_lock);
+               spin_unlock_bh(&ext_devt_lock);
        }
 
        return disk;
index 8aaf298a80e165f3fb5f83b1e00b8636cf9d08a3..362905e7c841ff55b204891e9e93748f2cfea96e 100644 (file)
@@ -1512,15 +1512,6 @@ config CRYPTO_USER_API_RNG
          This option enables the user-spaces interface for random
          number generator algorithms.
 
-config CRYPTO_USER_API_AEAD
-       tristate "User-space interface for AEAD cipher algorithms"
-       depends on NET
-       select CRYPTO_AEAD
-       select CRYPTO_USER_API
-       help
-         This option enables the user-spaces interface for AEAD
-         cipher algorithms.
-
 config CRYPTO_HASH_INFO
        bool
 
index 00a6fe166fed52863e5b6249858adeee5690a394..69abada22373f54b5dd434ba514e9c6c80c180e5 100644 (file)
@@ -33,7 +33,7 @@ struct aead_ctx {
        /*
         * RSGL_MAX_ENTRIES is an artificial limit where user space at maximum
         * can cause the kernel to allocate RSGL_MAX_ENTRIES * ALG_MAX_PAGES
-        * bytes
+        * pages
         */
 #define RSGL_MAX_ENTRIES ALG_MAX_PAGES
        struct af_alg_sgl rsgl[RSGL_MAX_ENTRIES];
@@ -435,11 +435,10 @@ static int aead_recvmsg(struct socket *sock, struct msghdr *msg, size_t ignored,
                if (err < 0)
                        goto unlock;
                usedpages += err;
-               /* chain the new scatterlist with initial list */
+               /* chain the new scatterlist with previous one */
                if (cnt)
-                       scatterwalk_crypto_chain(ctx->rsgl[0].sg,
-                                       ctx->rsgl[cnt].sg, 1,
-                                       sg_nents(ctx->rsgl[cnt-1].sg));
+                       af_alg_link_sg(&ctx->rsgl[cnt-1], &ctx->rsgl[cnt]);
+
                /* we do not need more iovecs as we have sufficient memory */
                if (outlen <= usedpages)
                        break;
index b193f842599902445015a219687310cdf3bfe9c9..ff6d8adc9cda69c4d0d1f9a22ff3481846020cbd 100644 (file)
@@ -304,6 +304,8 @@ static const struct acpi_device_id acpi_pnp_device_ids[] = {
        {"PNPb006"},
        /* cs423x-pnpbios */
        {"CSC0100"},
+       {"CSC0103"},
+       {"CSC0110"},
        {"CSC0000"},
        {"GIM0100"},            /* Guillemot Turtlebeach something appears to be cs4232 compatible */
        /* es18xx-pnpbios */
index a72685c1e819660768933e84abe9d1076c953bff..5e8df9177da44781ac07942d146e47b97e954cda 100644 (file)
@@ -102,19 +102,12 @@ const struct acpi_predefined_names acpi_gbl_pre_defined_names[] = {
        {"_SB_", ACPI_TYPE_DEVICE, NULL},
        {"_SI_", ACPI_TYPE_LOCAL_SCOPE, NULL},
        {"_TZ_", ACPI_TYPE_DEVICE, NULL},
-       /*
-        * March, 2015:
-        * The _REV object is in the process of being deprecated, because
-        * other ACPI implementations permanently return 2. Thus, it
-        * has little or no value. Return 2 for compatibility with
-        * other ACPI implementations.
-        */
-       {"_REV", ACPI_TYPE_INTEGER, ACPI_CAST_PTR(char, 2)},
+       {"_REV", ACPI_TYPE_INTEGER, (char *)ACPI_CA_SUPPORT_LEVEL},
        {"_OS_", ACPI_TYPE_STRING, ACPI_OS_NAME},
-       {"_GL_", ACPI_TYPE_MUTEX, ACPI_CAST_PTR(char, 1)},
+       {"_GL_", ACPI_TYPE_MUTEX, (char *)1},
 
 #if !defined (ACPI_NO_METHOD_EXECUTION) || defined (ACPI_CONSTANT_EVAL_ONLY)
-       {"_OSI", ACPI_TYPE_METHOD, ACPI_CAST_PTR(char, 1)},
+       {"_OSI", ACPI_TYPE_METHOD, (char *)1},
 #endif
 
        /* Table terminator */
index 39748bb3a5430111b8cf4723462eb837137b0213..7ccba395c9ddbeb7a6725b336d69d01abd4b82b1 100644 (file)
@@ -182,7 +182,7 @@ static void __init acpi_request_region (struct acpi_generic_address *gas,
                request_mem_region(addr, length, desc);
 }
 
-static int __init acpi_reserve_resources(void)
+static void __init acpi_reserve_resources(void)
 {
        acpi_request_region(&acpi_gbl_FADT.xpm1a_event_block, acpi_gbl_FADT.pm1_event_length,
                "ACPI PM1a_EVT_BLK");
@@ -211,10 +211,7 @@ static int __init acpi_reserve_resources(void)
        if (!(acpi_gbl_FADT.gpe1_block_length & 0x1))
                acpi_request_region(&acpi_gbl_FADT.xgpe1_block,
                               acpi_gbl_FADT.gpe1_block_length, "ACPI GPE1_BLK");
-
-       return 0;
 }
-device_initcall(acpi_reserve_resources);
 
 void acpi_os_printf(const char *fmt, ...)
 {
@@ -1845,6 +1842,7 @@ acpi_status __init acpi_os_initialize(void)
 
 acpi_status __init acpi_os_initialize1(void)
 {
+       acpi_reserve_resources();
        kacpid_wq = alloc_workqueue("kacpid", 0, 1);
        kacpi_notify_wq = alloc_workqueue("kacpi_notify", 0, 1);
        kacpi_hotplug_wq = alloc_ordered_workqueue("kacpi_hotplug", 0);
index 5589a6e2a02346e3b2ce48656b3facea1abfc621..8244f013f21095a9508e80ef01621e0ffbaab106 100644 (file)
@@ -573,7 +573,7 @@ EXPORT_SYMBOL_GPL(acpi_dev_get_resources);
  * @ares: Input ACPI resource object.
  * @types: Valid resource types of IORESOURCE_XXX
  *
- * This is a hepler function to support acpi_dev_get_resources(), which filters
+ * This is a helper function to support acpi_dev_get_resources(), which filters
  * ACPI resource objects according to resource types.
  */
 int acpi_dev_filter_resource_type(struct acpi_resource *ares,
index cd827625cf079207f36a2e2f2b86e00ae649faa4..01504c819e8f6692382a2b8138fb72a40bb50780 100644 (file)
@@ -684,7 +684,7 @@ static int acpi_sbs_add(struct acpi_device *device)
        if (!sbs_manager_broken) {
                result = acpi_manager_get_info(sbs);
                if (!result) {
-                       sbs->manager_present = 0;
+                       sbs->manager_present = 1;
                        for (id = 0; id < MAX_SBS_BAT; ++id)
                                if ((sbs->batteries_supported & (1 << id)))
                                        acpi_battery_add(sbs, id);
index 26e5b50605230e2e34a46d8118486fb1ba2eb939..bf034f8b7c1acde77f90ded7f39f70dbd636b7db 100644 (file)
@@ -14,6 +14,7 @@
 #include <linux/delay.h>
 #include <linux/module.h>
 #include <linux/interrupt.h>
+#include <linux/dmi.h>
 #include "sbshc.h"
 
 #define PREFIX "ACPI: "
@@ -87,6 +88,8 @@ enum acpi_smb_offset {
        ACPI_SMB_ALARM_DATA = 0x26,     /* 2 bytes alarm data */
 };
 
+static bool macbook;
+
 static inline int smb_hc_read(struct acpi_smb_hc *hc, u8 address, u8 *data)
 {
        return ec_read(hc->offset + address, data);
@@ -132,6 +135,8 @@ static int acpi_smbus_transaction(struct acpi_smb_hc *hc, u8 protocol,
        }
 
        mutex_lock(&hc->lock);
+       if (macbook)
+               udelay(5);
        if (smb_hc_read(hc, ACPI_SMB_PROTOCOL, &temp))
                goto end;
        if (temp) {
@@ -257,12 +262,29 @@ extern int acpi_ec_add_query_handler(struct acpi_ec *ec, u8 query_bit,
                              acpi_handle handle, acpi_ec_query_func func,
                              void *data);
 
+static int macbook_dmi_match(const struct dmi_system_id *d)
+{
+       pr_debug("Detected MacBook, enabling workaround\n");
+       macbook = true;
+       return 0;
+}
+
+static struct dmi_system_id acpi_smbus_dmi_table[] = {
+       { macbook_dmi_match, "Apple MacBook", {
+         DMI_MATCH(DMI_BOARD_VENDOR, "Apple"),
+         DMI_MATCH(DMI_PRODUCT_NAME, "MacBook") },
+       },
+       { },
+};
+
 static int acpi_smbus_hc_add(struct acpi_device *device)
 {
        int status;
        unsigned long long val;
        struct acpi_smb_hc *hc;
 
+       dmi_check_system(acpi_smbus_dmi_table);
+
        if (!device)
                return -EINVAL;
 
index 5f601553b9b043fff9ac80552ab55dbc4173c714..9dca4b995be0792b6c4f1920b9786cb6517a2b5f 100644 (file)
@@ -270,6 +270,7 @@ config ATA_PIIX
 config SATA_DWC
        tristate "DesignWare Cores SATA support"
        depends on 460EX
+       select DW_DMAC
        help
          This option enables support for the on-chip SATA controller of the
          AppliedMicro processor 460EX.
@@ -729,15 +730,6 @@ config PATA_SC1200
 
          If unsure, say N.
 
-config PATA_SCC
-       tristate "Toshiba's Cell Reference Set IDE support"
-       depends on PCI && PPC_CELLEB
-       help
-         This option enables support for the built-in IDE controller on
-         Toshiba Cell Reference Board.
-
-         If unsure, say N.
-
 config PATA_SCH
        tristate "Intel SCH PATA support"
        depends on PCI
index b67e995179a947bcdda7e5bf6f5d95275841ad49..40f7865f20a1dbf62123da6998fcef81fa9a2690 100644 (file)
@@ -75,7 +75,6 @@ obj-$(CONFIG_PATA_PDC_OLD)    += pata_pdc202xx_old.o
 obj-$(CONFIG_PATA_RADISYS)     += pata_radisys.o
 obj-$(CONFIG_PATA_RDC)         += pata_rdc.o
 obj-$(CONFIG_PATA_SC1200)      += pata_sc1200.o
-obj-$(CONFIG_PATA_SCC)         += pata_scc.o
 obj-$(CONFIG_PATA_SCH)         += pata_sch.o
 obj-$(CONFIG_PATA_SERVERWORKS) += pata_serverworks.o
 obj-$(CONFIG_PATA_SIL680)      += pata_sil680.o
index c7a92a743ed035e9af81ac779180fc65456a8390..65ee94454bbd2c92f1879386b19a346a5632794f 100644 (file)
@@ -66,6 +66,7 @@ enum board_ids {
        board_ahci_yes_fbs,
 
        /* board IDs for specific chipsets in alphabetical order */
+       board_ahci_avn,
        board_ahci_mcp65,
        board_ahci_mcp77,
        board_ahci_mcp89,
@@ -84,6 +85,8 @@ enum board_ids {
 static int ahci_init_one(struct pci_dev *pdev, const struct pci_device_id *ent);
 static int ahci_vt8251_hardreset(struct ata_link *link, unsigned int *class,
                                 unsigned long deadline);
+static int ahci_avn_hardreset(struct ata_link *link, unsigned int *class,
+                             unsigned long deadline);
 static void ahci_mcp89_apple_enable(struct pci_dev *pdev);
 static bool is_mcp89_apple(struct pci_dev *pdev);
 static int ahci_p5wdh_hardreset(struct ata_link *link, unsigned int *class,
@@ -107,6 +110,11 @@ static struct ata_port_operations ahci_p5wdh_ops = {
        .hardreset              = ahci_p5wdh_hardreset,
 };
 
+static struct ata_port_operations ahci_avn_ops = {
+       .inherits               = &ahci_ops,
+       .hardreset              = ahci_avn_hardreset,
+};
+
 static const struct ata_port_info ahci_port_info[] = {
        /* by features */
        [board_ahci] = {
@@ -151,6 +159,12 @@ static const struct ata_port_info ahci_port_info[] = {
                .port_ops       = &ahci_ops,
        },
        /* by chipsets */
+       [board_ahci_avn] = {
+               .flags          = AHCI_FLAG_COMMON,
+               .pio_mask       = ATA_PIO4,
+               .udma_mask      = ATA_UDMA6,
+               .port_ops       = &ahci_avn_ops,
+       },
        [board_ahci_mcp65] = {
                AHCI_HFLAGS     (AHCI_HFLAG_NO_FPDMA_AA | AHCI_HFLAG_NO_PMP |
                                 AHCI_HFLAG_YES_NCQ),
@@ -290,14 +304,14 @@ static const struct pci_device_id ahci_pci_tbl[] = {
        { PCI_VDEVICE(INTEL, 0x1f27), board_ahci }, /* Avoton RAID */
        { PCI_VDEVICE(INTEL, 0x1f2e), board_ahci }, /* Avoton RAID */
        { PCI_VDEVICE(INTEL, 0x1f2f), board_ahci }, /* Avoton RAID */
-       { PCI_VDEVICE(INTEL, 0x1f32), board_ahci }, /* Avoton AHCI */
-       { PCI_VDEVICE(INTEL, 0x1f33), board_ahci }, /* Avoton AHCI */
-       { PCI_VDEVICE(INTEL, 0x1f34), board_ahci }, /* Avoton RAID */
-       { PCI_VDEVICE(INTEL, 0x1f35), board_ahci }, /* Avoton RAID */
-       { PCI_VDEVICE(INTEL, 0x1f36), board_ahci }, /* Avoton RAID */
-       { PCI_VDEVICE(INTEL, 0x1f37), board_ahci }, /* Avoton RAID */
-       { PCI_VDEVICE(INTEL, 0x1f3e), board_ahci }, /* Avoton RAID */
-       { PCI_VDEVICE(INTEL, 0x1f3f), board_ahci }, /* Avoton RAID */
+       { PCI_VDEVICE(INTEL, 0x1f32), board_ahci_avn }, /* Avoton AHCI */
+       { PCI_VDEVICE(INTEL, 0x1f33), board_ahci_avn }, /* Avoton AHCI */
+       { PCI_VDEVICE(INTEL, 0x1f34), board_ahci_avn }, /* Avoton RAID */
+       { PCI_VDEVICE(INTEL, 0x1f35), board_ahci_avn }, /* Avoton RAID */
+       { PCI_VDEVICE(INTEL, 0x1f36), board_ahci_avn }, /* Avoton RAID */
+       { PCI_VDEVICE(INTEL, 0x1f37), board_ahci_avn }, /* Avoton RAID */
+       { PCI_VDEVICE(INTEL, 0x1f3e), board_ahci_avn }, /* Avoton RAID */
+       { PCI_VDEVICE(INTEL, 0x1f3f), board_ahci_avn }, /* Avoton RAID */
        { PCI_VDEVICE(INTEL, 0x2823), board_ahci }, /* Wellsburg RAID */
        { PCI_VDEVICE(INTEL, 0x2827), board_ahci }, /* Wellsburg RAID */
        { PCI_VDEVICE(INTEL, 0x8d02), board_ahci }, /* Wellsburg AHCI */
@@ -670,6 +684,79 @@ static int ahci_p5wdh_hardreset(struct ata_link *link, unsigned int *class,
        return rc;
 }
 
+/*
+ * ahci_avn_hardreset - attempt more aggressive recovery of Avoton ports.
+ *
+ * It has been observed with some SSDs that the timing of events in the
+ * link synchronization phase can leave the port in a state that can not
+ * be recovered by a SATA-hard-reset alone.  The failing signature is
+ * SStatus.DET stuck at 1 ("Device presence detected but Phy
+ * communication not established").  It was found that unloading and
+ * reloading the driver when this problem occurs allows the drive
+ * connection to be recovered (DET advanced to 0x3).  The critical
+ * component of reloading the driver is that the port state machines are
+ * reset by bouncing "port enable" in the AHCI PCS configuration
+ * register.  So, reproduce that effect by bouncing a port whenever we
+ * see DET==1 after a reset.
+ */
+static int ahci_avn_hardreset(struct ata_link *link, unsigned int *class,
+                             unsigned long deadline)
+{
+       const unsigned long *timing = sata_ehc_deb_timing(&link->eh_context);
+       struct ata_port *ap = link->ap;
+       struct ahci_port_priv *pp = ap->private_data;
+       struct ahci_host_priv *hpriv = ap->host->private_data;
+       u8 *d2h_fis = pp->rx_fis + RX_FIS_D2H_REG;
+       unsigned long tmo = deadline - jiffies;
+       struct ata_taskfile tf;
+       bool online;
+       int rc, i;
+
+       DPRINTK("ENTER\n");
+
+       ahci_stop_engine(ap);
+
+       for (i = 0; i < 2; i++) {
+               u16 val;
+               u32 sstatus;
+               int port = ap->port_no;
+               struct ata_host *host = ap->host;
+               struct pci_dev *pdev = to_pci_dev(host->dev);
+
+               /* clear D2H reception area to properly wait for D2H FIS */
+               ata_tf_init(link->device, &tf);
+               tf.command = ATA_BUSY;
+               ata_tf_to_fis(&tf, 0, 0, d2h_fis);
+
+               rc = sata_link_hardreset(link, timing, deadline, &online,
+                               ahci_check_ready);
+
+               if (sata_scr_read(link, SCR_STATUS, &sstatus) != 0 ||
+                               (sstatus & 0xf) != 1)
+                       break;
+
+               ata_link_printk(link, KERN_INFO, "avn bounce port%d\n",
+                               port);
+
+               pci_read_config_word(pdev, 0x92, &val);
+               val &= ~(1 << port);
+               pci_write_config_word(pdev, 0x92, val);
+               ata_msleep(ap, 1000);
+               val |= 1 << port;
+               pci_write_config_word(pdev, 0x92, val);
+               deadline += tmo;
+       }
+
+       hpriv->start_engine(ap);
+
+       if (online)
+               *class = ahci_dev_classify(ap);
+
+       DPRINTK("EXIT, rc=%d, class=%u\n", rc, *class);
+       return rc;
+}
+
+
 #ifdef CONFIG_PM
 static int ahci_pci_device_suspend(struct pci_dev *pdev, pm_message_t mesg)
 {
index 23716dd8a7ec3f569f82db531e1ed71bc330c7d6..5928d0746a270e7b6b2ee12a022b19ed731f03fe 100644 (file)
@@ -45,7 +45,7 @@ static void ahci_mvebu_mbus_config(struct ahci_host_priv *hpriv,
                writel((cs->mbus_attr << 8) |
                       (dram->mbus_dram_target_id << 4) | 1,
                       hpriv->mmio + AHCI_WINDOW_CTRL(i));
-               writel(cs->base, hpriv->mmio + AHCI_WINDOW_BASE(i));
+               writel(cs->base >> 16, hpriv->mmio + AHCI_WINDOW_BASE(i));
                writel(((cs->size - 1) & 0xffff0000),
                       hpriv->mmio + AHCI_WINDOW_SIZE(i));
        }
index ea0ff005b86ce702e4ccd0224c5b8f14c0fcfc89..8ff428fe8e0fa00659218f58f041cf948ae8327c 100644 (file)
@@ -37,7 +37,6 @@ struct st_ahci_drv_data {
        struct reset_control *pwr;
        struct reset_control *sw_rst;
        struct reset_control *pwr_rst;
-       struct ahci_host_priv *hpriv;
 };
 
 static void st_ahci_configure_oob(void __iomem *mmio)
@@ -55,9 +54,10 @@ static void st_ahci_configure_oob(void __iomem *mmio)
        writel(new_val, mmio + ST_AHCI_OOBR);
 }
 
-static int st_ahci_deassert_resets(struct device *dev)
+static int st_ahci_deassert_resets(struct ahci_host_priv *hpriv,
+                               struct device *dev)
 {
-       struct st_ahci_drv_data *drv_data = dev_get_drvdata(dev);
+       struct st_ahci_drv_data *drv_data = hpriv->plat_data;
        int err;
 
        if (drv_data->pwr) {
@@ -90,8 +90,8 @@ static int st_ahci_deassert_resets(struct device *dev)
 static void st_ahci_host_stop(struct ata_host *host)
 {
        struct ahci_host_priv *hpriv = host->private_data;
+       struct st_ahci_drv_data *drv_data = hpriv->plat_data;
        struct device *dev = host->dev;
-       struct st_ahci_drv_data *drv_data = dev_get_drvdata(dev);
        int err;
 
        if (drv_data->pwr) {
@@ -103,29 +103,30 @@ static void st_ahci_host_stop(struct ata_host *host)
        ahci_platform_disable_resources(hpriv);
 }
 
-static int st_ahci_probe_resets(struct platform_device *pdev)
+static int st_ahci_probe_resets(struct ahci_host_priv *hpriv,
+                               struct device *dev)
 {
-       struct st_ahci_drv_data *drv_data = platform_get_drvdata(pdev);
+       struct st_ahci_drv_data *drv_data = hpriv->plat_data;
 
-       drv_data->pwr = devm_reset_control_get(&pdev->dev, "pwr-dwn");
+       drv_data->pwr = devm_reset_control_get(dev, "pwr-dwn");
        if (IS_ERR(drv_data->pwr)) {
-               dev_info(&pdev->dev, "power reset control not defined\n");
+               dev_info(dev, "power reset control not defined\n");
                drv_data->pwr = NULL;
        }
 
-       drv_data->sw_rst = devm_reset_control_get(&pdev->dev, "sw-rst");
+       drv_data->sw_rst = devm_reset_control_get(dev, "sw-rst");
        if (IS_ERR(drv_data->sw_rst)) {
-               dev_info(&pdev->dev, "soft reset control not defined\n");
+               dev_info(dev, "soft reset control not defined\n");
                drv_data->sw_rst = NULL;
        }
 
-       drv_data->pwr_rst = devm_reset_control_get(&pdev->dev, "pwr-rst");
+       drv_data->pwr_rst = devm_reset_control_get(dev, "pwr-rst");
        if (IS_ERR(drv_data->pwr_rst)) {
-               dev_dbg(&pdev->dev, "power soft reset control not defined\n");
+               dev_dbg(dev, "power soft reset control not defined\n");
                drv_data->pwr_rst = NULL;
        }
 
-       return st_ahci_deassert_resets(&pdev->dev);
+       return st_ahci_deassert_resets(hpriv, dev);
 }
 
 static struct ata_port_operations st_ahci_port_ops = {
@@ -154,15 +155,12 @@ static int st_ahci_probe(struct platform_device *pdev)
        if (!drv_data)
                return -ENOMEM;
 
-       platform_set_drvdata(pdev, drv_data);
-
        hpriv = ahci_platform_get_resources(pdev);
        if (IS_ERR(hpriv))
                return PTR_ERR(hpriv);
+       hpriv->plat_data = drv_data;
 
-       drv_data->hpriv = hpriv;
-
-       err = st_ahci_probe_resets(pdev);
+       err = st_ahci_probe_resets(hpriv, &pdev->dev);
        if (err)
                return err;
 
@@ -170,7 +168,7 @@ static int st_ahci_probe(struct platform_device *pdev)
        if (err)
                return err;
 
-       st_ahci_configure_oob(drv_data->hpriv->mmio);
+       st_ahci_configure_oob(hpriv->mmio);
 
        err = ahci_platform_init_host(pdev, hpriv, &st_ahci_port_info,
                                      &ahci_platform_sht);
@@ -185,8 +183,9 @@ static int st_ahci_probe(struct platform_device *pdev)
 #ifdef CONFIG_PM_SLEEP
 static int st_ahci_suspend(struct device *dev)
 {
-       struct st_ahci_drv_data *drv_data = dev_get_drvdata(dev);
-       struct ahci_host_priv *hpriv = drv_data->hpriv;
+       struct ata_host *host = dev_get_drvdata(dev);
+       struct ahci_host_priv *hpriv = host->private_data;
+       struct st_ahci_drv_data *drv_data = hpriv->plat_data;
        int err;
 
        err = ahci_platform_suspend_host(dev);
@@ -208,21 +207,21 @@ static int st_ahci_suspend(struct device *dev)
 
 static int st_ahci_resume(struct device *dev)
 {
-       struct st_ahci_drv_data *drv_data = dev_get_drvdata(dev);
-       struct ahci_host_priv *hpriv = drv_data->hpriv;
+       struct ata_host *host = dev_get_drvdata(dev);
+       struct ahci_host_priv *hpriv = host->private_data;
        int err;
 
        err = ahci_platform_enable_resources(hpriv);
        if (err)
                return err;
 
-       err = st_ahci_deassert_resets(dev);
+       err = st_ahci_deassert_resets(hpriv, dev);
        if (err) {
                ahci_platform_disable_resources(hpriv);
                return err;
        }
 
-       st_ahci_configure_oob(drv_data->hpriv->mmio);
+       st_ahci_configure_oob(hpriv->mmio);
 
        return ahci_platform_resume_host(dev);
 }
index 61a9c07e0dff5b277dba35cfa135bac449f9ce84..287c4ba0219f7ced8c76af999dd1eeb3e5ed2639 100644 (file)
@@ -1707,8 +1707,7 @@ static void ahci_handle_port_interrupt(struct ata_port *ap,
        if (unlikely(resetting))
                status &= ~PORT_IRQ_BAD_PMP;
 
-       /* if LPM is enabled, PHYRDY doesn't mean anything */
-       if (ap->link.lpm_policy > ATA_LPM_MAX_POWER) {
+       if (sata_lpm_ignore_phy_events(&ap->link)) {
                status &= ~PORT_IRQ_PHYRDY;
                ahci_scr_write(&ap->link, SCR_ERROR, SERR_PHYRDY_CHG);
        }
index f6cb1f1b30b7466278d47dae09bc959db24dfef1..577849c6611ac5efa2c948c7b274dc894a19890d 100644 (file)
@@ -4235,7 +4235,7 @@ static const struct ata_blacklist_entry ata_device_blacklist [] = {
                                                ATA_HORKAGE_ZERO_AFTER_TRIM, },
        { "Crucial_CT*MX100*",          "MU01", ATA_HORKAGE_NO_NCQ_TRIM |
                                                ATA_HORKAGE_ZERO_AFTER_TRIM, },
-       { "Samsung SSD 850 PRO*",       NULL,   ATA_HORKAGE_NO_NCQ_TRIM |
+       { "Samsung SSD 8*",             NULL,   ATA_HORKAGE_NO_NCQ_TRIM |
                                                ATA_HORKAGE_ZERO_AFTER_TRIM, },
 
        /*
@@ -6752,6 +6752,38 @@ u32 ata_wait_register(struct ata_port *ap, void __iomem *reg, u32 mask, u32 val,
        return tmp;
 }
 
+/**
+ *     sata_lpm_ignore_phy_events - test if PHY event should be ignored
+ *     @link: Link receiving the event
+ *
+ *     Test whether the received PHY event has to be ignored or not.
+ *
+ *     LOCKING:
+ *     None:
+ *
+ *     RETURNS:
+ *     True if the event has to be ignored.
+ */
+bool sata_lpm_ignore_phy_events(struct ata_link *link)
+{
+       unsigned long lpm_timeout = link->last_lpm_change +
+                                   msecs_to_jiffies(ATA_TMOUT_SPURIOUS_PHY);
+
+       /* if LPM is enabled, PHYRDY doesn't mean anything */
+       if (link->lpm_policy > ATA_LPM_MAX_POWER)
+               return true;
+
+       /* ignore the first PHY event after the LPM policy changed
+        * as it is might be spurious
+        */
+       if ((link->flags & ATA_LFLAG_CHANGED) &&
+           time_before(jiffies, lpm_timeout))
+               return true;
+
+       return false;
+}
+EXPORT_SYMBOL_GPL(sata_lpm_ignore_phy_events);
+
 /*
  * Dummy port_ops
  */
index 07f41be38fbe556ffff9bd5efcacf8ed4538034e..cf0022ec07f2420c37fb8a52dc904530f0df2e38 100644 (file)
@@ -3597,6 +3597,9 @@ static int ata_eh_set_lpm(struct ata_link *link, enum ata_lpm_policy policy,
                }
        }
 
+       link->last_lpm_change = jiffies;
+       link->flags |= ATA_LFLAG_CHANGED;
+
        return 0;
 
 fail:
index 80a80548ad0a80acf28c3407e6a6048825f92af3..27245957eee3cd906f546d67853d2ebd6ce54d30 100644 (file)
@@ -1053,7 +1053,7 @@ static struct of_device_id octeon_cf_match[] = {
        },
        {},
 };
-MODULE_DEVICE_TABLE(of, octeon_i2c_match);
+MODULE_DEVICE_TABLE(of, octeon_cf_match);
 
 static struct platform_driver octeon_cf_driver = {
        .probe          = octeon_cf_probe,
diff --git a/drivers/ata/pata_scc.c b/drivers/ata/pata_scc.c
deleted file mode 100644 (file)
index 5cd60d6..0000000
+++ /dev/null
@@ -1,1110 +0,0 @@
-/*
- * Support for IDE interfaces on Celleb platform
- *
- * (C) Copyright 2006 TOSHIBA CORPORATION
- *
- * This code is based on drivers/ata/ata_piix.c:
- *  Copyright 2003-2005 Red Hat Inc
- *  Copyright 2003-2005 Jeff Garzik
- *  Copyright (C) 1998-1999 Andrzej Krzysztofowicz, Author and Maintainer
- *  Copyright (C) 1998-2000 Andre Hedrick <andre@linux-ide.org>
- *  Copyright (C) 2003 Red Hat Inc
- *
- * and drivers/ata/ahci.c:
- *  Copyright 2004-2005 Red Hat, Inc.
- *
- * and drivers/ata/libata-core.c:
- *  Copyright 2003-2004 Red Hat, Inc.  All rights reserved.
- *  Copyright 2003-2004 Jeff Garzik
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- */
-
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/pci.h>
-#include <linux/blkdev.h>
-#include <linux/delay.h>
-#include <linux/device.h>
-#include <scsi/scsi_host.h>
-#include <linux/libata.h>
-
-#define DRV_NAME               "pata_scc"
-#define DRV_VERSION            "0.3"
-
-#define PCI_DEVICE_ID_TOSHIBA_SCC_ATA          0x01b4
-
-/* PCI BARs */
-#define SCC_CTRL_BAR           0
-#define SCC_BMID_BAR           1
-
-/* offset of CTRL registers */
-#define SCC_CTL_PIOSHT         0x000
-#define SCC_CTL_PIOCT          0x004
-#define SCC_CTL_MDMACT         0x008
-#define SCC_CTL_MCRCST         0x00C
-#define SCC_CTL_SDMACT         0x010
-#define SCC_CTL_SCRCST         0x014
-#define SCC_CTL_UDENVT         0x018
-#define SCC_CTL_TDVHSEL        0x020
-#define SCC_CTL_MODEREG        0x024
-#define SCC_CTL_ECMODE         0xF00
-#define SCC_CTL_MAEA0          0xF50
-#define SCC_CTL_MAEC0          0xF54
-#define SCC_CTL_CCKCTRL        0xFF0
-
-/* offset of BMID registers */
-#define SCC_DMA_CMD            0x000
-#define SCC_DMA_STATUS         0x004
-#define SCC_DMA_TABLE_OFS      0x008
-#define SCC_DMA_INTMASK        0x010
-#define SCC_DMA_INTST          0x014
-#define SCC_DMA_PTERADD        0x018
-#define SCC_REG_CMD_ADDR       0x020
-#define SCC_REG_DATA           0x000
-#define SCC_REG_ERR            0x004
-#define SCC_REG_FEATURE        0x004
-#define SCC_REG_NSECT          0x008
-#define SCC_REG_LBAL           0x00C
-#define SCC_REG_LBAM           0x010
-#define SCC_REG_LBAH           0x014
-#define SCC_REG_DEVICE         0x018
-#define SCC_REG_STATUS         0x01C
-#define SCC_REG_CMD            0x01C
-#define SCC_REG_ALTSTATUS      0x020
-
-/* register value */
-#define TDVHSEL_MASTER         0x00000001
-#define TDVHSEL_SLAVE          0x00000004
-
-#define MODE_JCUSFEN           0x00000080
-
-#define ECMODE_VALUE           0x01
-
-#define CCKCTRL_ATARESET       0x00040000
-#define CCKCTRL_BUFCNT         0x00020000
-#define CCKCTRL_CRST           0x00010000
-#define CCKCTRL_OCLKEN         0x00000100
-#define CCKCTRL_ATACLKOEN      0x00000002
-#define CCKCTRL_LCLKEN         0x00000001
-
-#define QCHCD_IOS_SS           0x00000001
-
-#define QCHSD_STPDIAG          0x00020000
-
-#define INTMASK_MSK            0xD1000012
-#define INTSTS_SERROR          0x80000000
-#define INTSTS_PRERR           0x40000000
-#define INTSTS_RERR            0x10000000
-#define INTSTS_ICERR           0x01000000
-#define INTSTS_BMSINT          0x00000010
-#define INTSTS_BMHE            0x00000008
-#define INTSTS_IOIRQS          0x00000004
-#define INTSTS_INTRQ           0x00000002
-#define INTSTS_ACTEINT         0x00000001
-
-
-/* PIO transfer mode table */
-/* JCHST */
-static const unsigned long JCHSTtbl[2][7] = {
-       {0x0E, 0x05, 0x02, 0x03, 0x02, 0x00, 0x00},     /* 100MHz */
-       {0x13, 0x07, 0x04, 0x04, 0x03, 0x00, 0x00}      /* 133MHz */
-};
-
-/* JCHHT */
-static const unsigned long JCHHTtbl[2][7] = {
-       {0x0E, 0x02, 0x02, 0x02, 0x02, 0x00, 0x00},     /* 100MHz */
-       {0x13, 0x03, 0x03, 0x03, 0x03, 0x00, 0x00}      /* 133MHz */
-};
-
-/* JCHCT */
-static const unsigned long JCHCTtbl[2][7] = {
-       {0x1D, 0x1D, 0x1C, 0x0B, 0x06, 0x00, 0x00},     /* 100MHz */
-       {0x27, 0x26, 0x26, 0x0E, 0x09, 0x00, 0x00}      /* 133MHz */
-};
-
-/* DMA transfer mode  table */
-/* JCHDCTM/JCHDCTS */
-static const unsigned long JCHDCTxtbl[2][7] = {
-       {0x0A, 0x06, 0x04, 0x03, 0x01, 0x00, 0x00},     /* 100MHz */
-       {0x0E, 0x09, 0x06, 0x04, 0x02, 0x01, 0x00}      /* 133MHz */
-};
-
-/* JCSTWTM/JCSTWTS  */
-static const unsigned long JCSTWTxtbl[2][7] = {
-       {0x06, 0x04, 0x03, 0x02, 0x02, 0x02, 0x00},     /* 100MHz */
-       {0x09, 0x06, 0x04, 0x02, 0x02, 0x02, 0x02}      /* 133MHz */
-};
-
-/* JCTSS */
-static const unsigned long JCTSStbl[2][7] = {
-       {0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x00},     /* 100MHz */
-       {0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05}      /* 133MHz */
-};
-
-/* JCENVT */
-static const unsigned long JCENVTtbl[2][7] = {
-       {0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00},     /* 100MHz */
-       {0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02}      /* 133MHz */
-};
-
-/* JCACTSELS/JCACTSELM */
-static const unsigned long JCACTSELtbl[2][7] = {
-       {0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00},     /* 100MHz */
-       {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01}      /* 133MHz */
-};
-
-static const struct pci_device_id scc_pci_tbl[] = {
-       { PCI_VDEVICE(TOSHIBA_2, PCI_DEVICE_ID_TOSHIBA_SCC_ATA), 0},
-       { }     /* terminate list */
-};
-
-/**
- *     scc_set_piomode - Initialize host controller PATA PIO timings
- *     @ap: Port whose timings we are configuring
- *     @adev: um
- *
- *     Set PIO mode for device.
- *
- *     LOCKING:
- *     None (inherited from caller).
- */
-
-static void scc_set_piomode (struct ata_port *ap, struct ata_device *adev)
-{
-       unsigned int pio = adev->pio_mode - XFER_PIO_0;
-       void __iomem *ctrl_base = ap->host->iomap[SCC_CTRL_BAR];
-       void __iomem *cckctrl_port = ctrl_base + SCC_CTL_CCKCTRL;
-       void __iomem *piosht_port = ctrl_base + SCC_CTL_PIOSHT;
-       void __iomem *pioct_port = ctrl_base + SCC_CTL_PIOCT;
-       unsigned long reg;
-       int offset;
-
-       reg = in_be32(cckctrl_port);
-       if (reg & CCKCTRL_ATACLKOEN)
-               offset = 1;     /* 133MHz */
-       else
-               offset = 0;     /* 100MHz */
-
-       reg = JCHSTtbl[offset][pio] << 16 | JCHHTtbl[offset][pio];
-       out_be32(piosht_port, reg);
-       reg = JCHCTtbl[offset][pio];
-       out_be32(pioct_port, reg);
-}
-
-/**
- *     scc_set_dmamode - Initialize host controller PATA DMA timings
- *     @ap: Port whose timings we are configuring
- *     @adev: um
- *
- *     Set UDMA mode for device.
- *
- *     LOCKING:
- *     None (inherited from caller).
- */
-
-static void scc_set_dmamode (struct ata_port *ap, struct ata_device *adev)
-{
-       unsigned int udma = adev->dma_mode;
-       unsigned int is_slave = (adev->devno != 0);
-       u8 speed = udma;
-       void __iomem *ctrl_base = ap->host->iomap[SCC_CTRL_BAR];
-       void __iomem *cckctrl_port = ctrl_base + SCC_CTL_CCKCTRL;
-       void __iomem *mdmact_port = ctrl_base + SCC_CTL_MDMACT;
-       void __iomem *mcrcst_port = ctrl_base + SCC_CTL_MCRCST;
-       void __iomem *sdmact_port = ctrl_base + SCC_CTL_SDMACT;
-       void __iomem *scrcst_port = ctrl_base + SCC_CTL_SCRCST;
-       void __iomem *udenvt_port = ctrl_base + SCC_CTL_UDENVT;
-       void __iomem *tdvhsel_port = ctrl_base + SCC_CTL_TDVHSEL;
-       int offset, idx;
-
-       if (in_be32(cckctrl_port) & CCKCTRL_ATACLKOEN)
-               offset = 1;     /* 133MHz */
-       else
-               offset = 0;     /* 100MHz */
-
-       if (speed >= XFER_UDMA_0)
-               idx = speed - XFER_UDMA_0;
-       else
-               return;
-
-       if (is_slave) {
-               out_be32(sdmact_port, JCHDCTxtbl[offset][idx]);
-               out_be32(scrcst_port, JCSTWTxtbl[offset][idx]);
-               out_be32(tdvhsel_port,
-                        (in_be32(tdvhsel_port) & ~TDVHSEL_SLAVE) | (JCACTSELtbl[offset][idx] << 2));
-       } else {
-               out_be32(mdmact_port, JCHDCTxtbl[offset][idx]);
-               out_be32(mcrcst_port, JCSTWTxtbl[offset][idx]);
-               out_be32(tdvhsel_port,
-                        (in_be32(tdvhsel_port) & ~TDVHSEL_MASTER) | JCACTSELtbl[offset][idx]);
-       }
-       out_be32(udenvt_port,
-                JCTSStbl[offset][idx] << 16 | JCENVTtbl[offset][idx]);
-}
-
-unsigned long scc_mode_filter(struct ata_device *adev, unsigned long mask)
-{
-       /* errata A308 workaround: limit ATAPI UDMA mode to UDMA4 */
-       if (adev->class == ATA_DEV_ATAPI &&
-           (mask & (0xE0 << ATA_SHIFT_UDMA))) {
-               printk(KERN_INFO "%s: limit ATAPI UDMA to UDMA4\n", DRV_NAME);
-               mask &= ~(0xE0 << ATA_SHIFT_UDMA);
-       }
-       return mask;
-}
-
-/**
- *     scc_tf_load - send taskfile registers to host controller
- *     @ap: Port to which output is sent
- *     @tf: ATA taskfile register set
- *
- *     Note: Original code is ata_sff_tf_load().
- */
-
-static void scc_tf_load (struct ata_port *ap, const struct ata_taskfile *tf)
-{
-       struct ata_ioports *ioaddr = &ap->ioaddr;
-       unsigned int is_addr = tf->flags & ATA_TFLAG_ISADDR;
-
-       if (tf->ctl != ap->last_ctl) {
-               out_be32(ioaddr->ctl_addr, tf->ctl);
-               ap->last_ctl = tf->ctl;
-               ata_wait_idle(ap);
-       }
-
-       if (is_addr && (tf->flags & ATA_TFLAG_LBA48)) {
-               out_be32(ioaddr->feature_addr, tf->hob_feature);
-               out_be32(ioaddr->nsect_addr, tf->hob_nsect);
-               out_be32(ioaddr->lbal_addr, tf->hob_lbal);
-               out_be32(ioaddr->lbam_addr, tf->hob_lbam);
-               out_be32(ioaddr->lbah_addr, tf->hob_lbah);
-               VPRINTK("hob: feat 0x%X nsect 0x%X, lba 0x%X 0x%X 0x%X\n",
-                       tf->hob_feature,
-                       tf->hob_nsect,
-                       tf->hob_lbal,
-                       tf->hob_lbam,
-                       tf->hob_lbah);
-       }
-
-       if (is_addr) {
-               out_be32(ioaddr->feature_addr, tf->feature);
-               out_be32(ioaddr->nsect_addr, tf->nsect);
-               out_be32(ioaddr->lbal_addr, tf->lbal);
-               out_be32(ioaddr->lbam_addr, tf->lbam);
-               out_be32(ioaddr->lbah_addr, tf->lbah);
-               VPRINTK("feat 0x%X nsect 0x%X lba 0x%X 0x%X 0x%X\n",
-                       tf->feature,
-                       tf->nsect,
-                       tf->lbal,
-                       tf->lbam,
-                       tf->lbah);
-       }
-
-       if (tf->flags & ATA_TFLAG_DEVICE) {
-               out_be32(ioaddr->device_addr, tf->device);
-               VPRINTK("device 0x%X\n", tf->device);
-       }
-
-       ata_wait_idle(ap);
-}
-
-/**
- *     scc_check_status - Read device status reg & clear interrupt
- *     @ap: port where the device is
- *
- *     Note: Original code is ata_check_status().
- */
-
-static u8 scc_check_status (struct ata_port *ap)
-{
-       return in_be32(ap->ioaddr.status_addr);
-}
-
-/**
- *     scc_tf_read - input device's ATA taskfile shadow registers
- *     @ap: Port from which input is read
- *     @tf: ATA taskfile register set for storing input
- *
- *     Note: Original code is ata_sff_tf_read().
- */
-
-static void scc_tf_read (struct ata_port *ap, struct ata_taskfile *tf)
-{
-       struct ata_ioports *ioaddr = &ap->ioaddr;
-
-       tf->command = scc_check_status(ap);
-       tf->feature = in_be32(ioaddr->error_addr);
-       tf->nsect = in_be32(ioaddr->nsect_addr);
-       tf->lbal = in_be32(ioaddr->lbal_addr);
-       tf->lbam = in_be32(ioaddr->lbam_addr);
-       tf->lbah = in_be32(ioaddr->lbah_addr);
-       tf->device = in_be32(ioaddr->device_addr);
-
-       if (tf->flags & ATA_TFLAG_LBA48) {
-               out_be32(ioaddr->ctl_addr, tf->ctl | ATA_HOB);
-               tf->hob_feature = in_be32(ioaddr->error_addr);
-               tf->hob_nsect = in_be32(ioaddr->nsect_addr);
-               tf->hob_lbal = in_be32(ioaddr->lbal_addr);
-               tf->hob_lbam = in_be32(ioaddr->lbam_addr);
-               tf->hob_lbah = in_be32(ioaddr->lbah_addr);
-               out_be32(ioaddr->ctl_addr, tf->ctl);
-               ap->last_ctl = tf->ctl;
-       }
-}
-
-/**
- *     scc_exec_command - issue ATA command to host controller
- *     @ap: port to which command is being issued
- *     @tf: ATA taskfile register set
- *
- *     Note: Original code is ata_sff_exec_command().
- */
-
-static void scc_exec_command (struct ata_port *ap,
-                             const struct ata_taskfile *tf)
-{
-       DPRINTK("ata%u: cmd 0x%X\n", ap->print_id, tf->command);
-
-       out_be32(ap->ioaddr.command_addr, tf->command);
-       ata_sff_pause(ap);
-}
-
-/**
- *     scc_check_altstatus - Read device alternate status reg
- *     @ap: port where the device is
- */
-
-static u8 scc_check_altstatus (struct ata_port *ap)
-{
-       return in_be32(ap->ioaddr.altstatus_addr);
-}
-
-/**
- *     scc_dev_select - Select device 0/1 on ATA bus
- *     @ap: ATA channel to manipulate
- *     @device: ATA device (numbered from zero) to select
- *
- *     Note: Original code is ata_sff_dev_select().
- */
-
-static void scc_dev_select (struct ata_port *ap, unsigned int device)
-{
-       u8 tmp;
-
-       if (device == 0)
-               tmp = ATA_DEVICE_OBS;
-       else
-               tmp = ATA_DEVICE_OBS | ATA_DEV1;
-
-       out_be32(ap->ioaddr.device_addr, tmp);
-       ata_sff_pause(ap);
-}
-
-/**
- *     scc_set_devctl - Write device control reg
- *     @ap: port where the device is
- *     @ctl: value to write
- */
-
-static void scc_set_devctl(struct ata_port *ap, u8 ctl)
-{
-       out_be32(ap->ioaddr.ctl_addr, ctl);
-}
-
-/**
- *     scc_bmdma_setup - Set up PCI IDE BMDMA transaction
- *     @qc: Info associated with this ATA transaction.
- *
- *     Note: Original code is ata_bmdma_setup().
- */
-
-static void scc_bmdma_setup (struct ata_queued_cmd *qc)
-{
-       struct ata_port *ap = qc->ap;
-       unsigned int rw = (qc->tf.flags & ATA_TFLAG_WRITE);
-       u8 dmactl;
-       void __iomem *mmio = ap->ioaddr.bmdma_addr;
-
-       /* load PRD table addr */
-       out_be32(mmio + SCC_DMA_TABLE_OFS, ap->bmdma_prd_dma);
-
-       /* specify data direction, triple-check start bit is clear */
-       dmactl = in_be32(mmio + SCC_DMA_CMD);
-       dmactl &= ~(ATA_DMA_WR | ATA_DMA_START);
-       if (!rw)
-               dmactl |= ATA_DMA_WR;
-       out_be32(mmio + SCC_DMA_CMD, dmactl);
-
-       /* issue r/w command */
-       ap->ops->sff_exec_command(ap, &qc->tf);
-}
-
-/**
- *     scc_bmdma_start - Start a PCI IDE BMDMA transaction
- *     @qc: Info associated with this ATA transaction.
- *
- *     Note: Original code is ata_bmdma_start().
- */
-
-static void scc_bmdma_start (struct ata_queued_cmd *qc)
-{
-       struct ata_port *ap = qc->ap;
-       u8 dmactl;
-       void __iomem *mmio = ap->ioaddr.bmdma_addr;
-
-       /* start host DMA transaction */
-       dmactl = in_be32(mmio + SCC_DMA_CMD);
-       out_be32(mmio + SCC_DMA_CMD, dmactl | ATA_DMA_START);
-}
-
-/**
- *     scc_devchk - PATA device presence detection
- *     @ap: ATA channel to examine
- *     @device: Device to examine (starting at zero)
- *
- *     Note: Original code is ata_devchk().
- */
-
-static unsigned int scc_devchk (struct ata_port *ap,
-                               unsigned int device)
-{
-       struct ata_ioports *ioaddr = &ap->ioaddr;
-       u8 nsect, lbal;
-
-       ap->ops->sff_dev_select(ap, device);
-
-       out_be32(ioaddr->nsect_addr, 0x55);
-       out_be32(ioaddr->lbal_addr, 0xaa);
-
-       out_be32(ioaddr->nsect_addr, 0xaa);
-       out_be32(ioaddr->lbal_addr, 0x55);
-
-       out_be32(ioaddr->nsect_addr, 0x55);
-       out_be32(ioaddr->lbal_addr, 0xaa);
-
-       nsect = in_be32(ioaddr->nsect_addr);
-       lbal = in_be32(ioaddr->lbal_addr);
-
-       if ((nsect == 0x55) && (lbal == 0xaa))
-               return 1;       /* we found a device */
-
-       return 0;               /* nothing found */
-}
-
-/**
- *     scc_wait_after_reset - wait for devices to become ready after reset
- *
- *     Note: Original code is ata_sff_wait_after_reset
- */
-
-static int scc_wait_after_reset(struct ata_link *link, unsigned int devmask,
-                               unsigned long deadline)
-{
-       struct ata_port *ap = link->ap;
-       struct ata_ioports *ioaddr = &ap->ioaddr;
-       unsigned int dev0 = devmask & (1 << 0);
-       unsigned int dev1 = devmask & (1 << 1);
-       int rc, ret = 0;
-
-       /* Spec mandates ">= 2ms" before checking status.  We wait
-        * 150ms, because that was the magic delay used for ATAPI
-        * devices in Hale Landis's ATADRVR, for the period of time
-        * between when the ATA command register is written, and then
-        * status is checked.  Because waiting for "a while" before
-        * checking status is fine, post SRST, we perform this magic
-        * delay here as well.
-        *
-        * Old drivers/ide uses the 2mS rule and then waits for ready.
-        */
-       ata_msleep(ap, 150);
-
-       /* always check readiness of the master device */
-       rc = ata_sff_wait_ready(link, deadline);
-       /* -ENODEV means the odd clown forgot the D7 pulldown resistor
-        * and TF status is 0xff, bail out on it too.
-        */
-       if (rc)
-               return rc;
-
-       /* if device 1 was found in ata_devchk, wait for register
-        * access briefly, then wait for BSY to clear.
-        */
-       if (dev1) {
-               int i;
-
-               ap->ops->sff_dev_select(ap, 1);
-
-               /* Wait for register access.  Some ATAPI devices fail
-                * to set nsect/lbal after reset, so don't waste too
-                * much time on it.  We're gonna wait for !BSY anyway.
-                */
-               for (i = 0; i < 2; i++) {
-                       u8 nsect, lbal;
-
-                       nsect = in_be32(ioaddr->nsect_addr);
-                       lbal = in_be32(ioaddr->lbal_addr);
-                       if ((nsect == 1) && (lbal == 1))
-                               break;
-                       ata_msleep(ap, 50);     /* give drive a breather */
-               }
-
-               rc = ata_sff_wait_ready(link, deadline);
-               if (rc) {
-                       if (rc != -ENODEV)
-                               return rc;
-                       ret = rc;
-               }
-       }
-
-       /* is all this really necessary? */
-       ap->ops->sff_dev_select(ap, 0);
-       if (dev1)
-               ap->ops->sff_dev_select(ap, 1);
-       if (dev0)
-               ap->ops->sff_dev_select(ap, 0);
-
-       return ret;
-}
-
-/**
- *     scc_bus_softreset - PATA device software reset
- *
- *     Note: Original code is ata_bus_softreset().
- */
-
-static int scc_bus_softreset(struct ata_port *ap, unsigned int devmask,
-                                      unsigned long deadline)
-{
-       struct ata_ioports *ioaddr = &ap->ioaddr;
-
-       DPRINTK("ata%u: bus reset via SRST\n", ap->print_id);
-
-       /* software reset.  causes dev0 to be selected */
-       out_be32(ioaddr->ctl_addr, ap->ctl);
-       udelay(20);
-       out_be32(ioaddr->ctl_addr, ap->ctl | ATA_SRST);
-       udelay(20);
-       out_be32(ioaddr->ctl_addr, ap->ctl);
-
-       return scc_wait_after_reset(&ap->link, devmask, deadline);
-}
-
-/**
- *     scc_softreset - reset host port via ATA SRST
- *     @ap: port to reset
- *     @classes: resulting classes of attached devices
- *     @deadline: deadline jiffies for the operation
- *
- *     Note: Original code is ata_sff_softreset().
- */
-
-static int scc_softreset(struct ata_link *link, unsigned int *classes,
-                        unsigned long deadline)
-{
-       struct ata_port *ap = link->ap;
-       unsigned int slave_possible = ap->flags & ATA_FLAG_SLAVE_POSS;
-       unsigned int devmask = 0;
-       int rc;
-       u8 err;
-
-       DPRINTK("ENTER\n");
-
-       /* determine if device 0/1 are present */
-       if (scc_devchk(ap, 0))
-               devmask |= (1 << 0);
-       if (slave_possible && scc_devchk(ap, 1))
-               devmask |= (1 << 1);
-
-       /* select device 0 again */
-       ap->ops->sff_dev_select(ap, 0);
-
-       /* issue bus reset */
-       DPRINTK("about to softreset, devmask=%x\n", devmask);
-       rc = scc_bus_softreset(ap, devmask, deadline);
-       if (rc) {
-               ata_port_err(ap, "SRST failed (err_mask=0x%x)\n", rc);
-               return -EIO;
-       }
-
-       /* determine by signature whether we have ATA or ATAPI devices */
-       classes[0] = ata_sff_dev_classify(&ap->link.device[0],
-                                         devmask & (1 << 0), &err);
-       if (slave_possible && err != 0x81)
-               classes[1] = ata_sff_dev_classify(&ap->link.device[1],
-                                                 devmask & (1 << 1), &err);
-
-       DPRINTK("EXIT, classes[0]=%u [1]=%u\n", classes[0], classes[1]);
-       return 0;
-}
-
-/**
- *     scc_bmdma_stop - Stop PCI IDE BMDMA transfer
- *     @qc: Command we are ending DMA for
- */
-
-static void scc_bmdma_stop (struct ata_queued_cmd *qc)
-{
-       struct ata_port *ap = qc->ap;
-       void __iomem *ctrl_base = ap->host->iomap[SCC_CTRL_BAR];
-       void __iomem *bmid_base = ap->host->iomap[SCC_BMID_BAR];
-       u32 reg;
-
-       while (1) {
-               reg = in_be32(bmid_base + SCC_DMA_INTST);
-
-               if (reg & INTSTS_SERROR) {
-                       printk(KERN_WARNING "%s: SERROR\n", DRV_NAME);
-                       out_be32(bmid_base + SCC_DMA_INTST, INTSTS_SERROR|INTSTS_BMSINT);
-                       out_be32(bmid_base + SCC_DMA_CMD,
-                                in_be32(bmid_base + SCC_DMA_CMD) & ~ATA_DMA_START);
-                       continue;
-               }
-
-               if (reg & INTSTS_PRERR) {
-                       u32 maea0, maec0;
-                       maea0 = in_be32(ctrl_base + SCC_CTL_MAEA0);
-                       maec0 = in_be32(ctrl_base + SCC_CTL_MAEC0);
-                       printk(KERN_WARNING "%s: PRERR [addr:%x cmd:%x]\n", DRV_NAME, maea0, maec0);
-                       out_be32(bmid_base + SCC_DMA_INTST, INTSTS_PRERR|INTSTS_BMSINT);
-                       out_be32(bmid_base + SCC_DMA_CMD,
-                                in_be32(bmid_base + SCC_DMA_CMD) & ~ATA_DMA_START);
-                       continue;
-               }
-
-               if (reg & INTSTS_RERR) {
-                       printk(KERN_WARNING "%s: Response Error\n", DRV_NAME);
-                       out_be32(bmid_base + SCC_DMA_INTST, INTSTS_RERR|INTSTS_BMSINT);
-                       out_be32(bmid_base + SCC_DMA_CMD,
-                                in_be32(bmid_base + SCC_DMA_CMD) & ~ATA_DMA_START);
-                       continue;
-               }
-
-               if (reg & INTSTS_ICERR) {
-                       out_be32(bmid_base + SCC_DMA_CMD,
-                                in_be32(bmid_base + SCC_DMA_CMD) & ~ATA_DMA_START);
-                       printk(KERN_WARNING "%s: Illegal Configuration\n", DRV_NAME);
-                       out_be32(bmid_base + SCC_DMA_INTST, INTSTS_ICERR|INTSTS_BMSINT);
-                       continue;
-               }
-
-               if (reg & INTSTS_BMSINT) {
-                       unsigned int classes;
-                       unsigned long deadline = ata_deadline(jiffies, ATA_TMOUT_BOOT);
-                       printk(KERN_WARNING "%s: Internal Bus Error\n", DRV_NAME);
-                       out_be32(bmid_base + SCC_DMA_INTST, INTSTS_BMSINT);
-                       /* TBD: SW reset */
-                       scc_softreset(&ap->link, &classes, deadline);
-                       continue;
-               }
-
-               if (reg & INTSTS_BMHE) {
-                       out_be32(bmid_base + SCC_DMA_INTST, INTSTS_BMHE);
-                       continue;
-               }
-
-               if (reg & INTSTS_ACTEINT) {
-                       out_be32(bmid_base + SCC_DMA_INTST, INTSTS_ACTEINT);
-                       continue;
-               }
-
-               if (reg & INTSTS_IOIRQS) {
-                       out_be32(bmid_base + SCC_DMA_INTST, INTSTS_IOIRQS);
-                       continue;
-               }
-               break;
-       }
-
-       /* clear start/stop bit */
-       out_be32(bmid_base + SCC_DMA_CMD,
-                in_be32(bmid_base + SCC_DMA_CMD) & ~ATA_DMA_START);
-
-       /* one-PIO-cycle guaranteed wait, per spec, for HDMA1:0 transition */
-       ata_sff_dma_pause(ap);  /* dummy read */
-}
-
-/**
- *     scc_bmdma_status - Read PCI IDE BMDMA status
- *     @ap: Port associated with this ATA transaction.
- */
-
-static u8 scc_bmdma_status (struct ata_port *ap)
-{
-       void __iomem *mmio = ap->ioaddr.bmdma_addr;
-       u8 host_stat = in_be32(mmio + SCC_DMA_STATUS);
-       u32 int_status = in_be32(mmio + SCC_DMA_INTST);
-       struct ata_queued_cmd *qc = ata_qc_from_tag(ap, ap->link.active_tag);
-       static int retry = 0;
-
-       /* return if IOS_SS is cleared */
-       if (!(in_be32(mmio + SCC_DMA_CMD) & ATA_DMA_START))
-               return host_stat;
-
-       /* errata A252,A308 workaround: Step4 */
-       if ((scc_check_altstatus(ap) & ATA_ERR)
-                                       && (int_status & INTSTS_INTRQ))
-               return (host_stat | ATA_DMA_INTR);
-
-       /* errata A308 workaround Step5 */
-       if (int_status & INTSTS_IOIRQS) {
-               host_stat |= ATA_DMA_INTR;
-
-               /* We don't check ATAPI DMA because it is limited to UDMA4 */
-               if ((qc->tf.protocol == ATA_PROT_DMA &&
-                    qc->dev->xfer_mode > XFER_UDMA_4)) {
-                       if (!(int_status & INTSTS_ACTEINT)) {
-                               printk(KERN_WARNING "ata%u: operation failed (transfer data loss)\n",
-                                      ap->print_id);
-                               host_stat |= ATA_DMA_ERR;
-                               if (retry++)
-                                       ap->udma_mask &= ~(1 << qc->dev->xfer_mode);
-                       } else
-                               retry = 0;
-               }
-       }
-
-       return host_stat;
-}
-
-/**
- *     scc_data_xfer - Transfer data by PIO
- *     @dev: device for this I/O
- *     @buf: data buffer
- *     @buflen: buffer length
- *     @rw: read/write
- *
- *     Note: Original code is ata_sff_data_xfer().
- */
-
-static unsigned int scc_data_xfer (struct ata_device *dev, unsigned char *buf,
-                                  unsigned int buflen, int rw)
-{
-       struct ata_port *ap = dev->link->ap;
-       unsigned int words = buflen >> 1;
-       unsigned int i;
-       __le16 *buf16 = (__le16 *) buf;
-       void __iomem *mmio = ap->ioaddr.data_addr;
-
-       /* Transfer multiple of 2 bytes */
-       if (rw == READ)
-               for (i = 0; i < words; i++)
-                       buf16[i] = cpu_to_le16(in_be32(mmio));
-       else
-               for (i = 0; i < words; i++)
-                       out_be32(mmio, le16_to_cpu(buf16[i]));
-
-       /* Transfer trailing 1 byte, if any. */
-       if (unlikely(buflen & 0x01)) {
-               __le16 align_buf[1] = { 0 };
-               unsigned char *trailing_buf = buf + buflen - 1;
-
-               if (rw == READ) {
-                       align_buf[0] = cpu_to_le16(in_be32(mmio));
-                       memcpy(trailing_buf, align_buf, 1);
-               } else {
-                       memcpy(align_buf, trailing_buf, 1);
-                       out_be32(mmio, le16_to_cpu(align_buf[0]));
-               }
-               words++;
-       }
-
-       return words << 1;
-}
-
-/**
- *     scc_postreset - standard postreset callback
- *     @ap: the target ata_port
- *     @classes: classes of attached devices
- *
- *     Note: Original code is ata_sff_postreset().
- */
-
-static void scc_postreset(struct ata_link *link, unsigned int *classes)
-{
-       struct ata_port *ap = link->ap;
-
-       DPRINTK("ENTER\n");
-
-       /* is double-select really necessary? */
-       if (classes[0] != ATA_DEV_NONE)
-               ap->ops->sff_dev_select(ap, 1);
-       if (classes[1] != ATA_DEV_NONE)
-               ap->ops->sff_dev_select(ap, 0);
-
-       /* bail out if no device is present */
-       if (classes[0] == ATA_DEV_NONE && classes[1] == ATA_DEV_NONE) {
-               DPRINTK("EXIT, no device\n");
-               return;
-       }
-
-       /* set up device control */
-       out_be32(ap->ioaddr.ctl_addr, ap->ctl);
-
-       DPRINTK("EXIT\n");
-}
-
-/**
- *     scc_irq_clear - Clear PCI IDE BMDMA interrupt.
- *     @ap: Port associated with this ATA transaction.
- *
- *     Note: Original code is ata_bmdma_irq_clear().
- */
-
-static void scc_irq_clear (struct ata_port *ap)
-{
-       void __iomem *mmio = ap->ioaddr.bmdma_addr;
-
-       if (!mmio)
-               return;
-
-       out_be32(mmio + SCC_DMA_STATUS, in_be32(mmio + SCC_DMA_STATUS));
-}
-
-/**
- *     scc_port_start - Set port up for dma.
- *     @ap: Port to initialize
- *
- *     Allocate space for PRD table using ata_bmdma_port_start().
- *     Set PRD table address for PTERADD. (PRD Transfer End Read)
- */
-
-static int scc_port_start (struct ata_port *ap)
-{
-       void __iomem *mmio = ap->ioaddr.bmdma_addr;
-       int rc;
-
-       rc = ata_bmdma_port_start(ap);
-       if (rc)
-               return rc;
-
-       out_be32(mmio + SCC_DMA_PTERADD, ap->bmdma_prd_dma);
-       return 0;
-}
-
-/**
- *     scc_port_stop - Undo scc_port_start()
- *     @ap: Port to shut down
- *
- *     Reset PTERADD.
- */
-
-static void scc_port_stop (struct ata_port *ap)
-{
-       void __iomem *mmio = ap->ioaddr.bmdma_addr;
-
-       out_be32(mmio + SCC_DMA_PTERADD, 0);
-}
-
-static struct scsi_host_template scc_sht = {
-       ATA_BMDMA_SHT(DRV_NAME),
-};
-
-static struct ata_port_operations scc_pata_ops = {
-       .inherits               = &ata_bmdma_port_ops,
-
-       .set_piomode            = scc_set_piomode,
-       .set_dmamode            = scc_set_dmamode,
-       .mode_filter            = scc_mode_filter,
-
-       .sff_tf_load            = scc_tf_load,
-       .sff_tf_read            = scc_tf_read,
-       .sff_exec_command       = scc_exec_command,
-       .sff_check_status       = scc_check_status,
-       .sff_check_altstatus    = scc_check_altstatus,
-       .sff_dev_select         = scc_dev_select,
-       .sff_set_devctl         = scc_set_devctl,
-
-       .bmdma_setup            = scc_bmdma_setup,
-       .bmdma_start            = scc_bmdma_start,
-       .bmdma_stop             = scc_bmdma_stop,
-       .bmdma_status           = scc_bmdma_status,
-       .sff_data_xfer          = scc_data_xfer,
-
-       .cable_detect           = ata_cable_80wire,
-       .softreset              = scc_softreset,
-       .postreset              = scc_postreset,
-
-       .sff_irq_clear          = scc_irq_clear,
-
-       .port_start             = scc_port_start,
-       .port_stop              = scc_port_stop,
-};
-
-static struct ata_port_info scc_port_info[] = {
-       {
-               .flags          = ATA_FLAG_SLAVE_POSS,
-               .pio_mask       = ATA_PIO4,
-               /* No MWDMA */
-               .udma_mask      = ATA_UDMA6,
-               .port_ops       = &scc_pata_ops,
-       },
-};
-
-/**
- *     scc_reset_controller - initialize SCC PATA controller.
- */
-
-static int scc_reset_controller(struct ata_host *host)
-{
-       void __iomem *ctrl_base = host->iomap[SCC_CTRL_BAR];
-       void __iomem *bmid_base = host->iomap[SCC_BMID_BAR];
-       void __iomem *cckctrl_port = ctrl_base + SCC_CTL_CCKCTRL;
-       void __iomem *mode_port = ctrl_base + SCC_CTL_MODEREG;
-       void __iomem *ecmode_port = ctrl_base + SCC_CTL_ECMODE;
-       void __iomem *intmask_port = bmid_base + SCC_DMA_INTMASK;
-       void __iomem *dmastatus_port = bmid_base + SCC_DMA_STATUS;
-       u32 reg = 0;
-
-       out_be32(cckctrl_port, reg);
-       reg |= CCKCTRL_ATACLKOEN;
-       out_be32(cckctrl_port, reg);
-       reg |= CCKCTRL_LCLKEN | CCKCTRL_OCLKEN;
-       out_be32(cckctrl_port, reg);
-       reg |= CCKCTRL_CRST;
-       out_be32(cckctrl_port, reg);
-
-       for (;;) {
-               reg = in_be32(cckctrl_port);
-               if (reg & CCKCTRL_CRST)
-                       break;
-               udelay(5000);
-       }
-
-       reg |= CCKCTRL_ATARESET;
-       out_be32(cckctrl_port, reg);
-       out_be32(ecmode_port, ECMODE_VALUE);
-       out_be32(mode_port, MODE_JCUSFEN);
-       out_be32(intmask_port, INTMASK_MSK);
-
-       if (in_be32(dmastatus_port) & QCHSD_STPDIAG) {
-               printk(KERN_WARNING "%s: failed to detect 80c cable. (PDIAG# is high)\n", DRV_NAME);
-               return -EIO;
-       }
-
-       return 0;
-}
-
-/**
- *     scc_setup_ports - initialize ioaddr with SCC PATA port offsets.
- *     @ioaddr: IO address structure to be initialized
- *     @base: base address of BMID region
- */
-
-static void scc_setup_ports (struct ata_ioports *ioaddr, void __iomem *base)
-{
-       ioaddr->cmd_addr = base + SCC_REG_CMD_ADDR;
-       ioaddr->altstatus_addr = ioaddr->cmd_addr + SCC_REG_ALTSTATUS;
-       ioaddr->ctl_addr = ioaddr->cmd_addr + SCC_REG_ALTSTATUS;
-       ioaddr->bmdma_addr = base;
-       ioaddr->data_addr = ioaddr->cmd_addr + SCC_REG_DATA;
-       ioaddr->error_addr = ioaddr->cmd_addr + SCC_REG_ERR;
-       ioaddr->feature_addr = ioaddr->cmd_addr + SCC_REG_FEATURE;
-       ioaddr->nsect_addr = ioaddr->cmd_addr + SCC_REG_NSECT;
-       ioaddr->lbal_addr = ioaddr->cmd_addr + SCC_REG_LBAL;
-       ioaddr->lbam_addr = ioaddr->cmd_addr + SCC_REG_LBAM;
-       ioaddr->lbah_addr = ioaddr->cmd_addr + SCC_REG_LBAH;
-       ioaddr->device_addr = ioaddr->cmd_addr + SCC_REG_DEVICE;
-       ioaddr->status_addr = ioaddr->cmd_addr + SCC_REG_STATUS;
-       ioaddr->command_addr = ioaddr->cmd_addr + SCC_REG_CMD;
-}
-
-static int scc_host_init(struct ata_host *host)
-{
-       struct pci_dev *pdev = to_pci_dev(host->dev);
-       int rc;
-
-       rc = scc_reset_controller(host);
-       if (rc)
-               return rc;
-
-       rc = dma_set_mask(&pdev->dev, ATA_DMA_MASK);
-       if (rc)
-               return rc;
-       rc = dma_set_coherent_mask(&pdev->dev, ATA_DMA_MASK);
-       if (rc)
-               return rc;
-
-       scc_setup_ports(&host->ports[0]->ioaddr, host->iomap[SCC_BMID_BAR]);
-
-       pci_set_master(pdev);
-
-       return 0;
-}
-
-/**
- *     scc_init_one - Register SCC PATA device with kernel services
- *     @pdev: PCI device to register
- *     @ent: Entry in scc_pci_tbl matching with @pdev
- *
- *     LOCKING:
- *     Inherited from PCI layer (may sleep).
- *
- *     RETURNS:
- *     Zero on success, or -ERRNO value.
- */
-
-static int scc_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
-{
-       unsigned int board_idx = (unsigned int) ent->driver_data;
-       const struct ata_port_info *ppi[] = { &scc_port_info[board_idx], NULL };
-       struct ata_host *host;
-       int rc;
-
-       ata_print_version_once(&pdev->dev, DRV_VERSION);
-
-       host = ata_host_alloc_pinfo(&pdev->dev, ppi, 1);
-       if (!host)
-               return -ENOMEM;
-
-       rc = pcim_enable_device(pdev);
-       if (rc)
-               return rc;
-
-       rc = pcim_iomap_regions(pdev, (1 << SCC_CTRL_BAR) | (1 << SCC_BMID_BAR), DRV_NAME);
-       if (rc == -EBUSY)
-               pcim_pin_device(pdev);
-       if (rc)
-               return rc;
-       host->iomap = pcim_iomap_table(pdev);
-
-       ata_port_pbar_desc(host->ports[0], SCC_CTRL_BAR, -1, "ctrl");
-       ata_port_pbar_desc(host->ports[0], SCC_BMID_BAR, -1, "bmid");
-
-       rc = scc_host_init(host);
-       if (rc)
-               return rc;
-
-       return ata_host_activate(host, pdev->irq, ata_bmdma_interrupt,
-                                IRQF_SHARED, &scc_sht);
-}
-
-static struct pci_driver scc_pci_driver = {
-       .name                   = DRV_NAME,
-       .id_table               = scc_pci_tbl,
-       .probe                  = scc_init_one,
-       .remove                 = ata_pci_remove_one,
-#ifdef CONFIG_PM_SLEEP
-       .suspend                = ata_pci_device_suspend,
-       .resume                 = ata_pci_device_resume,
-#endif
-};
-
-module_pci_driver(scc_pci_driver);
-
-MODULE_AUTHOR("Toshiba corp");
-MODULE_DESCRIPTION("SCSI low-level driver for Toshiba SCC PATA controller");
-MODULE_LICENSE("GPL");
-MODULE_DEVICE_TABLE(pci, scc_pci_tbl);
-MODULE_VERSION(DRV_VERSION);
index 9c2ba1c97c4257016503a8ed4d2166ac19dea9c0..df0c66cb7ad3719016436dd7eb16ab1d3234568d 100644 (file)
@@ -179,7 +179,7 @@ static int detect_cache_attributes(unsigned int cpu)
 {
        int ret;
 
-       if (init_cache_level(cpu))
+       if (init_cache_level(cpu) || !cache_leaves(cpu))
                return -ENOENT;
 
        per_cpu_cacheinfo(cpu) = kcalloc(cache_leaves(cpu),
index da033d3bab3c69d14e55d63c4286632905120ae2..48c0e220acc0a1b8192ca6b523ad35ab7073eba7 100644 (file)
@@ -8,6 +8,7 @@
 #include <linux/device.h>
 #include <linux/init.h>
 #include <linux/memory.h>
+#include <linux/of.h>
 
 #include "base.h"
 
@@ -34,4 +35,5 @@ void __init driver_init(void)
        cpu_dev_init();
        memory_dev_init();
        container_dev_init();
+       of_core_init();
 }
index eb1fed5bd516ffac33c850eed47fad402250c686..3ccef9eba6f9dc53cecb785c23582cbdeb3b8618 100644 (file)
@@ -406,6 +406,7 @@ config BLK_DEV_RAM_DAX
 
 config BLK_DEV_PMEM
        tristate "Persistent memory block device support"
+       depends on HAS_IOMEM
        help
          Saying Y here will allow you to use a contiguous range of reserved
          memory as one or more persistent block devices.
index ae3fcb4199e9b7d85d2475d40ab4f209258a1cc5..d7173cb1ea76c206f1fcedbc96994e45901aa322 100644 (file)
@@ -1620,8 +1620,8 @@ out:
 
 static void loop_remove(struct loop_device *lo)
 {
-       del_gendisk(lo->lo_disk);
        blk_cleanup_queue(lo->lo_queue);
+       del_gendisk(lo->lo_disk);
        blk_mq_free_tag_set(&lo->tag_set);
        put_disk(lo->lo_disk);
        kfree(lo);
index 85b8036deaa3b7daaba5317ed746936a1f5183db..683dff272562b16d325df65495ad6a868cf45b14 100644 (file)
@@ -1750,6 +1750,7 @@ static int nvme_submit_io(struct nvme_ns *ns, struct nvme_user_io __user *uio)
        struct nvme_iod *iod;
        dma_addr_t meta_dma = 0;
        void *meta = NULL;
+       void __user *metadata;
 
        if (copy_from_user(&io, uio, sizeof(io)))
                return -EFAULT;
@@ -1763,6 +1764,8 @@ static int nvme_submit_io(struct nvme_ns *ns, struct nvme_user_io __user *uio)
                meta_len = 0;
        }
 
+       metadata = (void __user *)(unsigned long)io.metadata;
+
        write = io.opcode & 1;
 
        switch (io.opcode) {
@@ -1786,13 +1789,13 @@ static int nvme_submit_io(struct nvme_ns *ns, struct nvme_user_io __user *uio)
        if (meta_len) {
                meta = dma_alloc_coherent(&dev->pci_dev->dev, meta_len,
                                                &meta_dma, GFP_KERNEL);
+
                if (!meta) {
                        status = -ENOMEM;
                        goto unmap;
                }
                if (write) {
-                       if (copy_from_user(meta, (void __user *)io.metadata,
-                                                               meta_len)) {
+                       if (copy_from_user(meta, metadata, meta_len)) {
                                status = -EFAULT;
                                goto unmap;
                        }
@@ -1819,8 +1822,7 @@ static int nvme_submit_io(struct nvme_ns *ns, struct nvme_user_io __user *uio)
        nvme_free_iod(dev, iod);
        if (meta) {
                if (status == NVME_SC_SUCCESS && !write) {
-                       if (copy_to_user((void __user *)io.metadata, meta,
-                                                               meta_len))
+                       if (copy_to_user(metadata, meta, meta_len))
                                status = -EFAULT;
                }
                dma_free_coherent(&dev->pci_dev->dev, meta_len, meta, meta_dma);
index 6b736b00f63ebbbf01db7eb037695cbd77bca8c8..44f2514fb7755d0bdf9f4524ebbe5364a84af5a3 100644 (file)
@@ -944,7 +944,8 @@ static int nvme_trans_ext_inq_page(struct nvme_ns *ns, struct sg_io_hdr *hdr,
 static int nvme_trans_bdev_limits_page(struct nvme_ns *ns, struct sg_io_hdr *hdr,
                                        u8 *inq_response, int alloc_len)
 {
-       __be32 max_sectors = cpu_to_be32(queue_max_hw_sectors(ns->queue));
+       __be32 max_sectors = cpu_to_be32(
+               nvme_block_nr(ns, queue_max_hw_sectors(ns->queue)));
        __be32 max_discard = cpu_to_be32(ns->queue->limits.max_discard_sectors);
        __be32 discard_desc_count = cpu_to_be32(0x100);
 
@@ -2256,7 +2257,8 @@ static int nvme_trans_inquiry(struct nvme_ns *ns, struct sg_io_hdr *hdr,
        page_code = GET_INQ_PAGE_CODE(cmd);
        alloc_len = GET_INQ_ALLOC_LENGTH(cmd);
 
-       inq_response = kmalloc(alloc_len, GFP_KERNEL);
+       inq_response = kmalloc(max(alloc_len, STANDARD_INQUIRY_LENGTH),
+                               GFP_KERNEL);
        if (inq_response == NULL) {
                res = -ENOMEM;
                goto out_mem;
index 812523330a78d438e1397b29803f309b8e360211..ec6c5c6e1ac94b2bcbe0619a7fe62b9e7d0ce4a5 100644 (file)
@@ -2264,6 +2264,11 @@ static bool rbd_img_obj_end_request(struct rbd_obj_request *obj_request)
                        result, xferred);
                if (!img_request->result)
                        img_request->result = result;
+               /*
+                * Need to end I/O on the entire obj_request worth of
+                * bytes in case of error.
+                */
+               xferred = obj_request->length;
        }
 
        /* Image object requests don't own their page array */
index bd2b3bbbb22cf6fb1157845eafc3b2230375a4e3..713fc9ff11492766efcb7a4795b4a1750ceb9707 100644 (file)
@@ -265,17 +265,6 @@ static void put_persistent_gnt(struct xen_blkif *blkif,
        atomic_dec(&blkif->persistent_gnt_in_use);
 }
 
-static void free_persistent_gnts_unmap_callback(int result,
-                                               struct gntab_unmap_queue_data *data)
-{
-       struct completion *c = data->data;
-
-       /* BUG_ON used to reproduce existing behaviour,
-          but is this the best way to deal with this? */
-       BUG_ON(result);
-       complete(c);
-}
-
 static void free_persistent_gnts(struct xen_blkif *blkif, struct rb_root *root,
                                  unsigned int num)
 {
@@ -285,12 +274,7 @@ static void free_persistent_gnts(struct xen_blkif *blkif, struct rb_root *root,
        struct rb_node *n;
        int segs_to_unmap = 0;
        struct gntab_unmap_queue_data unmap_data;
-       struct completion unmap_completion;
 
-       init_completion(&unmap_completion);
-
-       unmap_data.data = &unmap_completion;
-       unmap_data.done = &free_persistent_gnts_unmap_callback;
        unmap_data.pages = pages;
        unmap_data.unmap_ops = unmap;
        unmap_data.kunmap_ops = NULL;
@@ -310,8 +294,7 @@ static void free_persistent_gnts(struct xen_blkif *blkif, struct rb_root *root,
                        !rb_next(&persistent_gnt->node)) {
 
                        unmap_data.count = segs_to_unmap;
-                       gnttab_unmap_refs_async(&unmap_data);
-                       wait_for_completion(&unmap_completion);
+                       BUG_ON(gnttab_unmap_refs_sync(&unmap_data));
 
                        put_free_pages(blkif, pages, segs_to_unmap);
                        segs_to_unmap = 0;
@@ -329,8 +312,13 @@ void xen_blkbk_unmap_purged_grants(struct work_struct *work)
        struct gnttab_unmap_grant_ref unmap[BLKIF_MAX_SEGMENTS_PER_REQUEST];
        struct page *pages[BLKIF_MAX_SEGMENTS_PER_REQUEST];
        struct persistent_gnt *persistent_gnt;
-       int ret, segs_to_unmap = 0;
+       int segs_to_unmap = 0;
        struct xen_blkif *blkif = container_of(work, typeof(*blkif), persistent_purge_work);
+       struct gntab_unmap_queue_data unmap_data;
+
+       unmap_data.pages = pages;
+       unmap_data.unmap_ops = unmap;
+       unmap_data.kunmap_ops = NULL;
 
        while(!list_empty(&blkif->persistent_purge_list)) {
                persistent_gnt = list_first_entry(&blkif->persistent_purge_list,
@@ -346,17 +334,16 @@ void xen_blkbk_unmap_purged_grants(struct work_struct *work)
                pages[segs_to_unmap] = persistent_gnt->page;
 
                if (++segs_to_unmap == BLKIF_MAX_SEGMENTS_PER_REQUEST) {
-                       ret = gnttab_unmap_refs(unmap, NULL, pages,
-                               segs_to_unmap);
-                       BUG_ON(ret);
+                       unmap_data.count = segs_to_unmap;
+                       BUG_ON(gnttab_unmap_refs_sync(&unmap_data));
                        put_free_pages(blkif, pages, segs_to_unmap);
                        segs_to_unmap = 0;
                }
                kfree(persistent_gnt);
        }
        if (segs_to_unmap > 0) {
-               ret = gnttab_unmap_refs(unmap, NULL, pages, segs_to_unmap);
-               BUG_ON(ret);
+               unmap_data.count = segs_to_unmap;
+               BUG_ON(gnttab_unmap_refs_sync(&unmap_data));
                put_free_pages(blkif, pages, segs_to_unmap);
        }
 }
index c94386aa563d618abf2d59a046b50b1607c3a20f..6e134f4759c0c9e98b93f221e7687004d4418342 100644 (file)
@@ -74,6 +74,27 @@ static inline struct zram *dev_to_zram(struct device *dev)
        return (struct zram *)dev_to_disk(dev)->private_data;
 }
 
+static ssize_t compact_store(struct device *dev,
+               struct device_attribute *attr, const char *buf, size_t len)
+{
+       unsigned long nr_migrated;
+       struct zram *zram = dev_to_zram(dev);
+       struct zram_meta *meta;
+
+       down_read(&zram->init_lock);
+       if (!init_done(zram)) {
+               up_read(&zram->init_lock);
+               return -EINVAL;
+       }
+
+       meta = zram->meta;
+       nr_migrated = zs_compact(meta->mem_pool);
+       atomic64_add(nr_migrated, &zram->stats.num_migrated);
+       up_read(&zram->init_lock);
+
+       return len;
+}
+
 static ssize_t disksize_show(struct device *dev,
                struct device_attribute *attr, char *buf)
 {
@@ -784,7 +805,9 @@ static void zram_reset_device(struct zram *zram)
        memset(&zram->stats, 0, sizeof(zram->stats));
        zram->disksize = 0;
        zram->max_comp_streams = 1;
+
        set_capacity(zram->disk, 0);
+       part_stat_set_all(&zram->disk->part0, 0);
 
        up_write(&zram->init_lock);
        /* I/O operation under all of CPU are done so let's free */
@@ -1038,6 +1061,7 @@ static const struct block_device_operations zram_devops = {
        .owner = THIS_MODULE
 };
 
+static DEVICE_ATTR_WO(compact);
 static DEVICE_ATTR_RW(disksize);
 static DEVICE_ATTR_RO(initstate);
 static DEVICE_ATTR_WO(reset);
@@ -1114,6 +1138,7 @@ static struct attribute *zram_disk_attrs[] = {
        &dev_attr_num_writes.attr,
        &dev_attr_failed_reads.attr,
        &dev_attr_failed_writes.attr,
+       &dev_attr_compact.attr,
        &dev_attr_invalid_io.attr,
        &dev_attr_notify_free.attr,
        &dev_attr_zero_pages.attr,
index 288547a3c566753d146e28924c7d3b023e8c0d3b..8c81af6dbe06365462b3c1d56481385a2db60881 100644 (file)
@@ -88,6 +88,7 @@ static const struct usb_device_id ath3k_table[] = {
        { USB_DEVICE(0x04CA, 0x3007) },
        { USB_DEVICE(0x04CA, 0x3008) },
        { USB_DEVICE(0x04CA, 0x300b) },
+       { USB_DEVICE(0x04CA, 0x300f) },
        { USB_DEVICE(0x04CA, 0x3010) },
        { USB_DEVICE(0x0930, 0x0219) },
        { USB_DEVICE(0x0930, 0x0220) },
@@ -104,6 +105,7 @@ static const struct usb_device_id ath3k_table[] = {
        { USB_DEVICE(0x0cf3, 0xe003) },
        { USB_DEVICE(0x0CF3, 0xE004) },
        { USB_DEVICE(0x0CF3, 0xE005) },
+       { USB_DEVICE(0x0CF3, 0xE006) },
        { USB_DEVICE(0x13d3, 0x3362) },
        { USB_DEVICE(0x13d3, 0x3375) },
        { USB_DEVICE(0x13d3, 0x3393) },
@@ -143,6 +145,7 @@ static const struct usb_device_id ath3k_blist_tbl[] = {
        { USB_DEVICE(0x04ca, 0x3007), .driver_info = BTUSB_ATH3012 },
        { USB_DEVICE(0x04ca, 0x3008), .driver_info = BTUSB_ATH3012 },
        { USB_DEVICE(0x04ca, 0x300b), .driver_info = BTUSB_ATH3012 },
+       { USB_DEVICE(0x04ca, 0x300f), .driver_info = BTUSB_ATH3012 },
        { USB_DEVICE(0x04ca, 0x3010), .driver_info = BTUSB_ATH3012 },
        { USB_DEVICE(0x0930, 0x0219), .driver_info = BTUSB_ATH3012 },
        { USB_DEVICE(0x0930, 0x0220), .driver_info = BTUSB_ATH3012 },
@@ -158,6 +161,7 @@ static const struct usb_device_id ath3k_blist_tbl[] = {
        { USB_DEVICE(0x0CF3, 0x817a), .driver_info = BTUSB_ATH3012 },
        { USB_DEVICE(0x0cf3, 0xe004), .driver_info = BTUSB_ATH3012 },
        { USB_DEVICE(0x0cf3, 0xe005), .driver_info = BTUSB_ATH3012 },
+       { USB_DEVICE(0x0cf3, 0xe006), .driver_info = BTUSB_ATH3012 },
        { USB_DEVICE(0x0cf3, 0xe003), .driver_info = BTUSB_ATH3012 },
        { USB_DEVICE(0x13d3, 0x3362), .driver_info = BTUSB_ATH3012 },
        { USB_DEVICE(0x13d3, 0x3375), .driver_info = BTUSB_ATH3012 },
index 4f7e8d400bc01a178bcbfcf499340b40545fb54f..6de97b3871b0f8cffe4d2c9b2b78eb5e87c48247 100644 (file)
@@ -227,7 +227,6 @@ static void bt3c_receive(struct bt3c_info *info)
        iobase = info->p_dev->resource[0]->start;
 
        avail = bt3c_read(iobase, 0x7006);
-       //printk("bt3c_cs: receiving %d bytes\n", avail);
 
        bt3c_address(iobase, 0x7480);
        while (size < avail) {
@@ -250,7 +249,6 @@ static void bt3c_receive(struct bt3c_info *info)
 
                        bt_cb(info->rx_skb)->pkt_type = inb(iobase + DATA_L);
                        inb(iobase + DATA_H);
-                       //printk("bt3c: PACKET_TYPE=%02x\n", bt_cb(info->rx_skb)->pkt_type);
 
                        switch (bt_cb(info->rx_skb)->pkt_type) {
 
@@ -364,7 +362,6 @@ static irqreturn_t bt3c_interrupt(int irq, void *dev_inst)
                        if (stat & 0x0001)
                                bt3c_receive(info);
                        if (stat & 0x0002) {
-                               //BT_ERR("Ack (stat=0x%04x)", stat);
                                clear_bit(XMIT_SENDING, &(info->tx_state));
                                bt3c_write_wakeup(info);
                        }
index d0741f3ed7ec36b49f1c50ff119fabc7368d3a9e..4bba86677adc64553fe8415d9b6812bfb3e1449d 100644 (file)
@@ -95,6 +95,78 @@ int btbcm_set_bdaddr(struct hci_dev *hdev, const bdaddr_t *bdaddr)
 }
 EXPORT_SYMBOL_GPL(btbcm_set_bdaddr);
 
+int btbcm_patchram(struct hci_dev *hdev, const char *firmware)
+{
+       const struct hci_command_hdr *cmd;
+       const struct firmware *fw;
+       const u8 *fw_ptr;
+       size_t fw_size;
+       struct sk_buff *skb;
+       u16 opcode;
+       int err;
+
+       err = request_firmware(&fw, firmware, &hdev->dev);
+       if (err < 0) {
+               BT_INFO("%s: BCM: Patch %s not found", hdev->name, firmware);
+               return err;
+       }
+
+       /* Start Download */
+       skb = __hci_cmd_sync(hdev, 0xfc2e, 0, NULL, HCI_INIT_TIMEOUT);
+       if (IS_ERR(skb)) {
+               err = PTR_ERR(skb);
+               BT_ERR("%s: BCM: Download Minidrv command failed (%d)",
+                      hdev->name, err);
+               goto done;
+       }
+       kfree_skb(skb);
+
+       /* 50 msec delay after Download Minidrv completes */
+       msleep(50);
+
+       fw_ptr = fw->data;
+       fw_size = fw->size;
+
+       while (fw_size >= sizeof(*cmd)) {
+               const u8 *cmd_param;
+
+               cmd = (struct hci_command_hdr *)fw_ptr;
+               fw_ptr += sizeof(*cmd);
+               fw_size -= sizeof(*cmd);
+
+               if (fw_size < cmd->plen) {
+                       BT_ERR("%s: BCM: Patch %s is corrupted", hdev->name,
+                              firmware);
+                       err = -EINVAL;
+                       goto done;
+               }
+
+               cmd_param = fw_ptr;
+               fw_ptr += cmd->plen;
+               fw_size -= cmd->plen;
+
+               opcode = le16_to_cpu(cmd->opcode);
+
+               skb = __hci_cmd_sync(hdev, opcode, cmd->plen, cmd_param,
+                                    HCI_INIT_TIMEOUT);
+               if (IS_ERR(skb)) {
+                       err = PTR_ERR(skb);
+                       BT_ERR("%s: BCM: Patch command %04x failed (%d)",
+                              hdev->name, opcode, err);
+                       goto done;
+               }
+               kfree_skb(skb);
+       }
+
+       /* 250 msec delay after Launch Ram completes */
+       msleep(250);
+
+done:
+       release_firmware(fw);
+       return err;
+}
+EXPORT_SYMBOL(btbcm_patchram);
+
 static int btbcm_reset(struct hci_dev *hdev)
 {
        struct sk_buff *skb;
@@ -198,12 +270,8 @@ static const struct {
 
 int btbcm_setup_patchram(struct hci_dev *hdev)
 {
-       const struct hci_command_hdr *cmd;
-       const struct firmware *fw;
-       const u8 *fw_ptr;
-       size_t fw_size;
        char fw_name[64];
-       u16 opcode, subver, rev, pid, vid;
+       u16 subver, rev, pid, vid;
        const char *hw_name = NULL;
        struct sk_buff *skb;
        struct hci_rp_read_local_version *ver;
@@ -273,74 +341,19 @@ int btbcm_setup_patchram(struct hci_dev *hdev)
                hw_name ? : "BCM", (subver & 0x7000) >> 13,
                (subver & 0x1f00) >> 8, (subver & 0x00ff), rev & 0x0fff);
 
-       err = request_firmware(&fw, fw_name, &hdev->dev);
-       if (err < 0) {
-               BT_INFO("%s: BCM: patch %s not found", hdev->name, fw_name);
+       err = btbcm_patchram(hdev, fw_name);
+       if (err == -ENOENT)
                return 0;
-       }
-
-       /* Start Download */
-       skb = __hci_cmd_sync(hdev, 0xfc2e, 0, NULL, HCI_INIT_TIMEOUT);
-       if (IS_ERR(skb)) {
-               err = PTR_ERR(skb);
-               BT_ERR("%s: BCM: Download Minidrv command failed (%d)",
-                      hdev->name, err);
-               goto reset;
-       }
-       kfree_skb(skb);
-
-       /* 50 msec delay after Download Minidrv completes */
-       msleep(50);
-
-       fw_ptr = fw->data;
-       fw_size = fw->size;
-
-       while (fw_size >= sizeof(*cmd)) {
-               const u8 *cmd_param;
-
-               cmd = (struct hci_command_hdr *)fw_ptr;
-               fw_ptr += sizeof(*cmd);
-               fw_size -= sizeof(*cmd);
-
-               if (fw_size < cmd->plen) {
-                       BT_ERR("%s: BCM: patch %s is corrupted", hdev->name,
-                              fw_name);
-                       err = -EINVAL;
-                       goto reset;
-               }
 
-               cmd_param = fw_ptr;
-               fw_ptr += cmd->plen;
-               fw_size -= cmd->plen;
-
-               opcode = le16_to_cpu(cmd->opcode);
-
-               skb = __hci_cmd_sync(hdev, opcode, cmd->plen, cmd_param,
-                                    HCI_INIT_TIMEOUT);
-               if (IS_ERR(skb)) {
-                       err = PTR_ERR(skb);
-                       BT_ERR("%s: BCM: patch command %04x failed (%d)",
-                              hdev->name, opcode, err);
-                       goto reset;
-               }
-               kfree_skb(skb);
-       }
-
-       /* 250 msec delay after Launch Ram completes */
-       msleep(250);
-
-reset:
        /* Reset */
        err = btbcm_reset(hdev);
        if (err)
-               goto done;
+               return err;
 
        /* Read Local Version Info */
        skb = btbcm_read_local_version(hdev);
-       if (IS_ERR(skb)) {
-               err = PTR_ERR(skb);
-               goto done;
-       }
+       if (IS_ERR(skb))
+               return PTR_ERR(skb);
 
        ver = (struct hci_rp_read_local_version *)skb->data;
        rev = le16_to_cpu(ver->hci_rev);
@@ -355,10 +368,7 @@ reset:
 
        set_bit(HCI_QUIRK_STRICT_DUPLICATE_FILTER, &hdev->quirks);
 
-done:
-       release_firmware(fw);
-
-       return err;
+       return 0;
 }
 EXPORT_SYMBOL_GPL(btbcm_setup_patchram);
 
index 34268ae3eb4607e16f5c9e017b23cb904a80b459..eb6ab5f9483d3b510ab6a2decfb1d694af8facb7 100644 (file)
@@ -25,6 +25,7 @@
 
 int btbcm_check_bdaddr(struct hci_dev *hdev);
 int btbcm_set_bdaddr(struct hci_dev *hdev, const bdaddr_t *bdaddr);
+int btbcm_patchram(struct hci_dev *hdev, const char *firmware);
 
 int btbcm_setup_patchram(struct hci_dev *hdev);
 int btbcm_setup_apple(struct hci_dev *hdev);
@@ -41,6 +42,11 @@ static inline int btbcm_set_bdaddr(struct hci_dev *hdev, const bdaddr_t *bdaddr)
        return -EOPNOTSUPP;
 }
 
+static inline int btbcm_patchram(struct hci_dev *hdev, const char *firmware)
+{
+       return -EOPNOTSUPP;
+}
+
 static inline int btbcm_setup_patchram(struct hci_dev *hdev)
 {
        return 0;
index de7b236eeae7777f71389ec42c233525d309aef2..3c10d4dfe9a790e6e34f12022b1bcc2321ac648c 100644 (file)
@@ -24,6 +24,7 @@
 #include <linux/module.h>
 #include <linux/usb.h>
 #include <linux/firmware.h>
+#include <asm/unaligned.h>
 
 #include <net/bluetooth/bluetooth.h>
 #include <net/bluetooth/hci_core.h>
@@ -57,6 +58,7 @@ static struct usb_driver btusb_driver;
 #define BTUSB_AMP              0x4000
 #define BTUSB_QCA_ROME         0x8000
 #define BTUSB_BCM_APPLE                0x10000
+#define BTUSB_REALTEK          0x20000
 
 static const struct usb_device_id btusb_table[] = {
        /* Generic Bluetooth USB device */
@@ -184,6 +186,7 @@ static const struct usb_device_id blacklist_table[] = {
        { USB_DEVICE(0x04ca, 0x3007), .driver_info = BTUSB_ATH3012 },
        { USB_DEVICE(0x04ca, 0x3008), .driver_info = BTUSB_ATH3012 },
        { USB_DEVICE(0x04ca, 0x300b), .driver_info = BTUSB_ATH3012 },
+       { USB_DEVICE(0x04ca, 0x300f), .driver_info = BTUSB_ATH3012 },
        { USB_DEVICE(0x04ca, 0x3010), .driver_info = BTUSB_ATH3012 },
        { USB_DEVICE(0x0930, 0x0219), .driver_info = BTUSB_ATH3012 },
        { USB_DEVICE(0x0930, 0x0220), .driver_info = BTUSB_ATH3012 },
@@ -200,6 +203,7 @@ static const struct usb_device_id blacklist_table[] = {
        { USB_DEVICE(0x0cf3, 0xe003), .driver_info = BTUSB_ATH3012 },
        { USB_DEVICE(0x0cf3, 0xe004), .driver_info = BTUSB_ATH3012 },
        { USB_DEVICE(0x0cf3, 0xe005), .driver_info = BTUSB_ATH3012 },
+       { USB_DEVICE(0x0cf3, 0xe006), .driver_info = BTUSB_ATH3012 },
        { USB_DEVICE(0x13d3, 0x3362), .driver_info = BTUSB_ATH3012 },
        { USB_DEVICE(0x13d3, 0x3375), .driver_info = BTUSB_ATH3012 },
        { USB_DEVICE(0x13d3, 0x3393), .driver_info = BTUSB_ATH3012 },
@@ -216,6 +220,7 @@ static const struct usb_device_id blacklist_table[] = {
        { USB_DEVICE(0x0489, 0xe03c), .driver_info = BTUSB_ATH3012 },
 
        /* QCA ROME chipset */
+       { USB_DEVICE(0x0cf3, 0xe007), .driver_info = BTUSB_QCA_ROME },
        { USB_DEVICE(0x0cf3, 0xe300), .driver_info = BTUSB_QCA_ROME },
        { USB_DEVICE(0x0cf3, 0xe360), .driver_info = BTUSB_QCA_ROME },
 
@@ -288,6 +293,28 @@ static const struct usb_device_id blacklist_table[] = {
        { USB_VENDOR_AND_INTERFACE_INFO(0x8087, 0xe0, 0x01, 0x01),
          .driver_info = BTUSB_IGNORE },
 
+       /* Realtek Bluetooth devices */
+       { USB_VENDOR_AND_INTERFACE_INFO(0x0bda, 0xe0, 0x01, 0x01),
+         .driver_info = BTUSB_REALTEK },
+
+       /* Additional Realtek 8723AE Bluetooth devices */
+       { USB_DEVICE(0x0930, 0x021d), .driver_info = BTUSB_REALTEK },
+       { USB_DEVICE(0x13d3, 0x3394), .driver_info = BTUSB_REALTEK },
+
+       /* Additional Realtek 8723BE Bluetooth devices */
+       { USB_DEVICE(0x0489, 0xe085), .driver_info = BTUSB_REALTEK },
+       { USB_DEVICE(0x0489, 0xe08b), .driver_info = BTUSB_REALTEK },
+       { USB_DEVICE(0x13d3, 0x3410), .driver_info = BTUSB_REALTEK },
+       { USB_DEVICE(0x13d3, 0x3416), .driver_info = BTUSB_REALTEK },
+       { USB_DEVICE(0x13d3, 0x3459), .driver_info = BTUSB_REALTEK },
+
+       /* Additional Realtek 8821AE Bluetooth devices */
+       { USB_DEVICE(0x0b05, 0x17dc), .driver_info = BTUSB_REALTEK },
+       { USB_DEVICE(0x13d3, 0x3414), .driver_info = BTUSB_REALTEK },
+       { USB_DEVICE(0x13d3, 0x3458), .driver_info = BTUSB_REALTEK },
+       { USB_DEVICE(0x13d3, 0x3461), .driver_info = BTUSB_REALTEK },
+       { USB_DEVICE(0x13d3, 0x3462), .driver_info = BTUSB_REALTEK },
+
        { }     /* Terminating entry */
 };
 
@@ -892,7 +919,7 @@ static int btusb_open(struct hci_dev *hdev)
         */
        if (data->setup_on_usb) {
                err = data->setup_on_usb(hdev);
-               if (err <0)
+               if (err < 0)
                        return err;
        }
 
@@ -1345,6 +1372,378 @@ static int btusb_setup_csr(struct hci_dev *hdev)
        return ret;
 }
 
+#define RTL_FRAG_LEN 252
+
+struct rtl_download_cmd {
+       __u8 index;
+       __u8 data[RTL_FRAG_LEN];
+} __packed;
+
+struct rtl_download_response {
+       __u8 status;
+       __u8 index;
+} __packed;
+
+struct rtl_rom_version_evt {
+       __u8 status;
+       __u8 version;
+} __packed;
+
+struct rtl_epatch_header {
+       __u8 signature[8];
+       __le32 fw_version;
+       __le16 num_patches;
+} __packed;
+
+#define RTL_EPATCH_SIGNATURE   "Realtech"
+#define RTL_ROM_LMP_3499       0x3499
+#define RTL_ROM_LMP_8723A      0x1200
+#define RTL_ROM_LMP_8723B      0x8723
+#define RTL_ROM_LMP_8821A      0x8821
+#define RTL_ROM_LMP_8761A      0x8761
+
+static int rtl_read_rom_version(struct hci_dev *hdev, u8 *version)
+{
+       struct rtl_rom_version_evt *rom_version;
+       struct sk_buff *skb;
+       int ret;
+
+       /* Read RTL ROM version command */
+       skb = __hci_cmd_sync(hdev, 0xfc6d, 0, NULL, HCI_INIT_TIMEOUT);
+       if (IS_ERR(skb)) {
+               BT_ERR("%s: Read ROM version failed (%ld)",
+                      hdev->name, PTR_ERR(skb));
+               return PTR_ERR(skb);
+       }
+
+       if (skb->len != sizeof(*rom_version)) {
+               BT_ERR("%s: RTL version event length mismatch", hdev->name);
+               kfree_skb(skb);
+               return -EIO;
+       }
+
+       rom_version = (struct rtl_rom_version_evt *)skb->data;
+       BT_INFO("%s: rom_version status=%x version=%x",
+               hdev->name, rom_version->status, rom_version->version);
+
+       ret = rom_version->status;
+       if (ret == 0)
+               *version = rom_version->version;
+
+       kfree_skb(skb);
+       return ret;
+}
+
+static int rtl8723b_parse_firmware(struct hci_dev *hdev, u16 lmp_subver,
+                                  const struct firmware *fw,
+                                  unsigned char **_buf)
+{
+       const u8 extension_sig[] = { 0x51, 0x04, 0xfd, 0x77 };
+       struct rtl_epatch_header *epatch_info;
+       unsigned char *buf;
+       int i, ret, len;
+       size_t min_size;
+       u8 opcode, length, data, rom_version = 0;
+       int project_id = -1;
+       const unsigned char *fwptr, *chip_id_base;
+       const unsigned char *patch_length_base, *patch_offset_base;
+       u32 patch_offset = 0;
+       u16 patch_length, num_patches;
+       const u16 project_id_to_lmp_subver[] = {
+               RTL_ROM_LMP_8723A,
+               RTL_ROM_LMP_8723B,
+               RTL_ROM_LMP_8821A,
+               RTL_ROM_LMP_8761A
+       };
+
+       ret = rtl_read_rom_version(hdev, &rom_version);
+       if (ret)
+               return -bt_to_errno(ret);
+
+       min_size = sizeof(struct rtl_epatch_header) + sizeof(extension_sig) + 3;
+       if (fw->size < min_size)
+               return -EINVAL;
+
+       fwptr = fw->data + fw->size - sizeof(extension_sig);
+       if (memcmp(fwptr, extension_sig, sizeof(extension_sig)) != 0) {
+               BT_ERR("%s: extension section signature mismatch", hdev->name);
+               return -EINVAL;
+       }
+
+       /* Loop from the end of the firmware parsing instructions, until
+        * we find an instruction that identifies the "project ID" for the
+        * hardware supported by this firwmare file.
+        * Once we have that, we double-check that that project_id is suitable
+        * for the hardware we are working with.
+        */
+       while (fwptr >= fw->data + (sizeof(struct rtl_epatch_header) + 3)) {
+               opcode = *--fwptr;
+               length = *--fwptr;
+               data = *--fwptr;
+
+               BT_DBG("check op=%x len=%x data=%x", opcode, length, data);
+
+               if (opcode == 0xff) /* EOF */
+                       break;
+
+               if (length == 0) {
+                       BT_ERR("%s: found instruction with length 0",
+                              hdev->name);
+                       return -EINVAL;
+               }
+
+               if (opcode == 0 && length == 1) {
+                       project_id = data;
+                       break;
+               }
+
+               fwptr -= length;
+       }
+
+       if (project_id < 0) {
+               BT_ERR("%s: failed to find version instruction", hdev->name);
+               return -EINVAL;
+       }
+
+       if (project_id >= ARRAY_SIZE(project_id_to_lmp_subver)) {
+               BT_ERR("%s: unknown project id %d", hdev->name, project_id);
+               return -EINVAL;
+       }
+
+       if (lmp_subver != project_id_to_lmp_subver[project_id]) {
+               BT_ERR("%s: firmware is for %x but this is a %x", hdev->name,
+                      project_id_to_lmp_subver[project_id], lmp_subver);
+               return -EINVAL;
+       }
+
+       epatch_info = (struct rtl_epatch_header *)fw->data;
+       if (memcmp(epatch_info->signature, RTL_EPATCH_SIGNATURE, 8) != 0) {
+               BT_ERR("%s: bad EPATCH signature", hdev->name);
+               return -EINVAL;
+       }
+
+       num_patches = le16_to_cpu(epatch_info->num_patches);
+       BT_DBG("fw_version=%x, num_patches=%d",
+              le32_to_cpu(epatch_info->fw_version), num_patches);
+
+       /* After the rtl_epatch_header there is a funky patch metadata section.
+        * Assuming 2 patches, the layout is:
+        * ChipID1 ChipID2 PatchLength1 PatchLength2 PatchOffset1 PatchOffset2
+        *
+        * Find the right patch for this chip.
+        */
+       min_size += 8 * num_patches;
+       if (fw->size < min_size)
+               return -EINVAL;
+
+       chip_id_base = fw->data + sizeof(struct rtl_epatch_header);
+       patch_length_base = chip_id_base + (sizeof(u16) * num_patches);
+       patch_offset_base = patch_length_base + (sizeof(u16) * num_patches);
+       for (i = 0; i < num_patches; i++) {
+               u16 chip_id = get_unaligned_le16(chip_id_base +
+                                                (i * sizeof(u16)));
+               if (chip_id == rom_version + 1) {
+                       patch_length = get_unaligned_le16(patch_length_base +
+                                                         (i * sizeof(u16)));
+                       patch_offset = get_unaligned_le32(patch_offset_base +
+                                                         (i * sizeof(u32)));
+                       break;
+               }
+       }
+
+       if (!patch_offset) {
+               BT_ERR("%s: didn't find patch for chip id %d",
+                      hdev->name, rom_version);
+               return -EINVAL;
+       }
+
+       BT_DBG("length=%x offset=%x index %d", patch_length, patch_offset, i);
+       min_size = patch_offset + patch_length;
+       if (fw->size < min_size)
+               return -EINVAL;
+
+       /* Copy the firmware into a new buffer and write the version at
+        * the end.
+        */
+       len = patch_length;
+       buf = kmemdup(fw->data + patch_offset, patch_length, GFP_KERNEL);
+       if (!buf)
+               return -ENOMEM;
+
+       memcpy(buf + patch_length - 4, &epatch_info->fw_version, 4);
+
+       *_buf = buf;
+       return len;
+}
+
+static int rtl_download_firmware(struct hci_dev *hdev,
+                                const unsigned char *data, int fw_len)
+{
+       struct rtl_download_cmd *dl_cmd;
+       int frag_num = fw_len / RTL_FRAG_LEN + 1;
+       int frag_len = RTL_FRAG_LEN;
+       int ret = 0;
+       int i;
+
+       dl_cmd = kmalloc(sizeof(struct rtl_download_cmd), GFP_KERNEL);
+       if (!dl_cmd)
+               return -ENOMEM;
+
+       for (i = 0; i < frag_num; i++) {
+               struct rtl_download_response *dl_resp;
+               struct sk_buff *skb;
+
+               BT_DBG("download fw (%d/%d)", i, frag_num);
+
+               dl_cmd->index = i;
+               if (i == (frag_num - 1)) {
+                       dl_cmd->index |= 0x80; /* data end */
+                       frag_len = fw_len % RTL_FRAG_LEN;
+               }
+               memcpy(dl_cmd->data, data, frag_len);
+
+               /* Send download command */
+               skb = __hci_cmd_sync(hdev, 0xfc20, frag_len + 1, dl_cmd,
+                                    HCI_INIT_TIMEOUT);
+               if (IS_ERR(skb)) {
+                       BT_ERR("%s: download fw command failed (%ld)",
+                              hdev->name, PTR_ERR(skb));
+                       ret = -PTR_ERR(skb);
+                       goto out;
+               }
+
+               if (skb->len != sizeof(*dl_resp)) {
+                       BT_ERR("%s: download fw event length mismatch",
+                              hdev->name);
+                       kfree_skb(skb);
+                       ret = -EIO;
+                       goto out;
+               }
+
+               dl_resp = (struct rtl_download_response *)skb->data;
+               if (dl_resp->status != 0) {
+                       kfree_skb(skb);
+                       ret = bt_to_errno(dl_resp->status);
+                       goto out;
+               }
+
+               kfree_skb(skb);
+               data += RTL_FRAG_LEN;
+       }
+
+out:
+       kfree(dl_cmd);
+       return ret;
+}
+
+static int btusb_setup_rtl8723a(struct hci_dev *hdev)
+{
+       struct btusb_data *data = dev_get_drvdata(&hdev->dev);
+       struct usb_device *udev = interface_to_usbdev(data->intf);
+       const struct firmware *fw;
+       int ret;
+
+       BT_INFO("%s: rtl: loading rtl_bt/rtl8723a_fw.bin", hdev->name);
+       ret = request_firmware(&fw, "rtl_bt/rtl8723a_fw.bin", &udev->dev);
+       if (ret < 0) {
+               BT_ERR("%s: Failed to load rtl_bt/rtl8723a_fw.bin", hdev->name);
+               return ret;
+       }
+
+       if (fw->size < 8) {
+               ret = -EINVAL;
+               goto out;
+       }
+
+       /* Check that the firmware doesn't have the epatch signature
+        * (which is only for RTL8723B and newer).
+        */
+       if (!memcmp(fw->data, RTL_EPATCH_SIGNATURE, 8)) {
+               BT_ERR("%s: unexpected EPATCH signature!", hdev->name);
+               ret = -EINVAL;
+               goto out;
+       }
+
+       ret = rtl_download_firmware(hdev, fw->data, fw->size);
+
+out:
+       release_firmware(fw);
+       return ret;
+}
+
+static int btusb_setup_rtl8723b(struct hci_dev *hdev, u16 lmp_subver,
+                               const char *fw_name)
+{
+       struct btusb_data *data = dev_get_drvdata(&hdev->dev);
+       struct usb_device *udev = interface_to_usbdev(data->intf);
+       unsigned char *fw_data = NULL;
+       const struct firmware *fw;
+       int ret;
+
+       BT_INFO("%s: rtl: loading %s", hdev->name, fw_name);
+       ret = request_firmware(&fw, fw_name, &udev->dev);
+       if (ret < 0) {
+               BT_ERR("%s: Failed to load %s", hdev->name, fw_name);
+               return ret;
+       }
+
+       ret = rtl8723b_parse_firmware(hdev, lmp_subver, fw, &fw_data);
+       if (ret < 0)
+               goto out;
+
+       ret = rtl_download_firmware(hdev, fw_data, ret);
+       kfree(fw_data);
+       if (ret < 0)
+               goto out;
+
+out:
+       release_firmware(fw);
+       return ret;
+}
+
+static int btusb_setup_realtek(struct hci_dev *hdev)
+{
+       struct sk_buff *skb;
+       struct hci_rp_read_local_version *resp;
+       u16 lmp_subver;
+
+       skb = btusb_read_local_version(hdev);
+       if (IS_ERR(skb))
+               return -PTR_ERR(skb);
+
+       resp = (struct hci_rp_read_local_version *)skb->data;
+       BT_INFO("%s: rtl: examining hci_ver=%02x hci_rev=%04x lmp_ver=%02x "
+               "lmp_subver=%04x", hdev->name, resp->hci_ver, resp->hci_rev,
+               resp->lmp_ver, resp->lmp_subver);
+
+       lmp_subver = le16_to_cpu(resp->lmp_subver);
+       kfree_skb(skb);
+
+       /* Match a set of subver values that correspond to stock firmware,
+        * which is not compatible with standard btusb.
+        * If matched, upload an alternative firmware that does conform to
+        * standard btusb. Once that firmware is uploaded, the subver changes
+        * to a different value.
+        */
+       switch (lmp_subver) {
+       case RTL_ROM_LMP_8723A:
+       case RTL_ROM_LMP_3499:
+               return btusb_setup_rtl8723a(hdev);
+       case RTL_ROM_LMP_8723B:
+               return btusb_setup_rtl8723b(hdev, lmp_subver,
+                                           "rtl_bt/rtl8723b_fw.bin");
+       case RTL_ROM_LMP_8821A:
+               return btusb_setup_rtl8723b(hdev, lmp_subver,
+                                           "rtl_bt/rtl8821a_fw.bin");
+       case RTL_ROM_LMP_8761A:
+               return btusb_setup_rtl8723b(hdev, lmp_subver,
+                                           "rtl_bt/rtl8761a_fw.bin");
+       default:
+               BT_INFO("rtl: assuming no firmware upload needed.");
+               return 0;
+       }
+}
+
 static const struct firmware *btusb_setup_intel_get_fw(struct hci_dev *hdev,
                                                       struct intel_version *ver)
 {
@@ -2577,7 +2976,7 @@ static int btusb_setup_qca(struct hci_dev *hdev)
        int i, err;
 
        err = btusb_qca_send_vendor_req(hdev, QCA_GET_TARGET_VERSION, &ver,
-                                       sizeof(ver));
+                                       sizeof(ver));
        if (err < 0)
                return err;
 
@@ -2776,6 +3175,9 @@ static int btusb_probe(struct usb_interface *intf,
                hdev->set_bdaddr = btusb_set_bdaddr_ath3012;
        }
 
+       if (id->driver_info & BTUSB_REALTEK)
+               hdev->setup = btusb_setup_realtek;
+
        if (id->driver_info & BTUSB_AMP) {
                /* AMP controllers do not support SCO packets */
                data->isoc = NULL;
index 1b3f8647ea2fd446e1a6f14979a27e399fb0dbf5..ec8fa0e0f03630c9646a60b831277477a249b010 100644 (file)
@@ -95,7 +95,6 @@ static void ath_hci_uart_work(struct work_struct *work)
        hci_uart_tx_wakeup(hu);
 }
 
-/* Initialize protocol */
 static int ath_open(struct hci_uart *hu)
 {
        struct ath_struct *ath;
@@ -116,8 +115,7 @@ static int ath_open(struct hci_uart *hu)
        return 0;
 }
 
-/* Flush protocol data */
-static int ath_flush(struct hci_uart *hu)
+static int ath_close(struct hci_uart *hu)
 {
        struct ath_struct *ath = hu->priv;
 
@@ -125,11 +123,17 @@ static int ath_flush(struct hci_uart *hu)
 
        skb_queue_purge(&ath->txq);
 
+       kfree_skb(ath->rx_skb);
+
+       cancel_work_sync(&ath->ctxtsw);
+
+       hu->priv = NULL;
+       kfree(ath);
+
        return 0;
 }
 
-/* Close protocol */
-static int ath_close(struct hci_uart *hu)
+static int ath_flush(struct hci_uart *hu)
 {
        struct ath_struct *ath = hu->priv;
 
@@ -137,19 +141,65 @@ static int ath_close(struct hci_uart *hu)
 
        skb_queue_purge(&ath->txq);
 
-       kfree_skb(ath->rx_skb);
+       return 0;
+}
 
-       cancel_work_sync(&ath->ctxtsw);
+static int ath_set_bdaddr(struct hci_dev *hdev, const bdaddr_t *bdaddr)
+{
+       struct sk_buff *skb;
+       u8 buf[10];
+       int err;
+
+       buf[0] = 0x01;
+       buf[1] = 0x01;
+       buf[2] = 0x00;
+       buf[3] = sizeof(bdaddr_t);
+       memcpy(buf + 4, bdaddr, sizeof(bdaddr_t));
+
+       skb = __hci_cmd_sync(hdev, 0xfc0b, sizeof(buf), buf, HCI_INIT_TIMEOUT);
+       if (IS_ERR(skb)) {
+               err = PTR_ERR(skb);
+               BT_ERR("%s: Change address command failed (%d)",
+                      hdev->name, err);
+               return err;
+       }
+       kfree_skb(skb);
 
-       hu->priv = NULL;
-       kfree(ath);
+       return 0;
+}
+
+static int ath_setup(struct hci_uart *hu)
+{
+       BT_DBG("hu %p", hu);
+
+       hu->hdev->set_bdaddr = ath_set_bdaddr;
 
        return 0;
 }
 
+static const struct h4_recv_pkt ath_recv_pkts[] = {
+       { H4_RECV_ACL,   .recv = hci_recv_frame },
+       { H4_RECV_SCO,   .recv = hci_recv_frame },
+       { H4_RECV_EVENT, .recv = hci_recv_frame },
+};
+
+static int ath_recv(struct hci_uart *hu, const void *data, int count)
+{
+       struct ath_struct *ath = hu->priv;
+
+       ath->rx_skb = h4_recv_buf(hu->hdev, ath->rx_skb, data, count,
+                                 ath_recv_pkts, ARRAY_SIZE(ath_recv_pkts));
+       if (IS_ERR(ath->rx_skb)) {
+               int err = PTR_ERR(ath->rx_skb);
+               BT_ERR("%s: Frame reassembly failed (%d)", hu->hdev->name, err);
+               return err;
+       }
+
+       return count;
+}
+
 #define HCI_OP_ATH_SLEEP 0xFC04
 
-/* Enqueue frame for transmittion */
 static int ath_enqueue(struct hci_uart *hu, struct sk_buff *skb)
 {
        struct ath_struct *ath = hu->priv;
@@ -159,8 +209,7 @@ static int ath_enqueue(struct hci_uart *hu, struct sk_buff *skb)
                return 0;
        }
 
-       /*
-        * Update power management enable flag with parameters of
+       /* Update power management enable flag with parameters of
         * HCI sleep enable vendor specific HCI command.
         */
        if (bt_cb(skb)->pkt_type == HCI_COMMAND_PKT) {
@@ -190,37 +239,16 @@ static struct sk_buff *ath_dequeue(struct hci_uart *hu)
        return skb_dequeue(&ath->txq);
 }
 
-static const struct h4_recv_pkt ath_recv_pkts[] = {
-       { H4_RECV_ACL,   .recv = hci_recv_frame },
-       { H4_RECV_SCO,   .recv = hci_recv_frame },
-       { H4_RECV_EVENT, .recv = hci_recv_frame },
-};
-
-/* Recv data */
-static int ath_recv(struct hci_uart *hu, const void *data, int count)
-{
-       struct ath_struct *ath = hu->priv;
-
-       ath->rx_skb = h4_recv_buf(hu->hdev, ath->rx_skb, data, count,
-                                 ath_recv_pkts, ARRAY_SIZE(ath_recv_pkts));
-       if (IS_ERR(ath->rx_skb)) {
-               int err = PTR_ERR(ath->rx_skb);
-               BT_ERR("%s: Frame reassembly failed (%d)", hu->hdev->name, err);
-               return err;
-       }
-
-       return count;
-}
-
 static const struct hci_uart_proto athp = {
        .id             = HCI_UART_ATH3K,
        .name           = "ATH3K",
        .open           = ath_open,
        .close          = ath_close,
+       .flush          = ath_flush,
+       .setup          = ath_setup,
        .recv           = ath_recv,
        .enqueue        = ath_enqueue,
        .dequeue        = ath_dequeue,
-       .flush          = ath_flush,
 };
 
 int __init ath_init(void)
index b854125e48311aa1e101c8ea9ab6ff0ec909753c..5340604b23a4e1b24b0c01bf3798dbc35fcda40a 100644 (file)
@@ -660,7 +660,7 @@ validate_group(struct perf_event *event)
                 * Initialise the fake PMU. We only need to populate the
                 * used_mask for the purposes of validation.
                 */
-               .used_mask = CPU_BITS_NONE,
+               .used_mask = { 0 },
        };
 
        if (!validate_event(event->pmu, &fake_pmu, leader))
index 5bd792c68f9b897ddbafe50a39c3bdb9b49306d6..ab3bde16ecb4443a2e63d8e327fa1db730294dff 100644 (file)
@@ -453,7 +453,7 @@ void __iomem *mips_cdmm_early_probe(unsigned int dev_type)
 
        /* Look for a specific device type */
        for (; drb < bus->drbs; drb += size + 1) {
-               acsr = readl(cdmm + drb * CDMM_DRB_SIZE);
+               acsr = __raw_readl(cdmm + drb * CDMM_DRB_SIZE);
                type = (acsr & CDMM_ACSR_DEVTYPE) >> CDMM_ACSR_DEVTYPE_SHIFT;
                if (type == dev_type)
                        return cdmm + drb * CDMM_DRB_SIZE;
@@ -500,7 +500,7 @@ static void mips_cdmm_bus_discover(struct mips_cdmm_bus *bus)
        bus->discovered = true;
        pr_info("cdmm%u discovery (%u blocks)\n", cpu, bus->drbs);
        for (; drb < bus->drbs; drb += size + 1) {
-               acsr = readl(cdmm + drb * CDMM_DRB_SIZE);
+               acsr = __raw_readl(cdmm + drb * CDMM_DRB_SIZE);
                type = (acsr & CDMM_ACSR_DEVTYPE) >> CDMM_ACSR_DEVTYPE_SHIFT;
                size = (acsr & CDMM_ACSR_DEVSIZE) >> CDMM_ACSR_DEVSIZE_SHIFT;
                rev  = (acsr & CDMM_ACSR_DEVREV)  >> CDMM_ACSR_DEVREV_SHIFT;
index fb9ec6221730a2d594f66d15e54471aea75cc750..6f047dcb94c22b3ea67349bf1c4b95be6b91037a 100644 (file)
@@ -58,7 +58,6 @@
 #include <linux/debugfs.h>
 #include <linux/log2.h>
 #include <linux/syscore_ops.h>
-#include <linux/memblock.h>
 
 /*
  * DDR target is the same on all platforms.
@@ -70,6 +69,7 @@
  */
 #define WIN_CTRL_OFF           0x0000
 #define   WIN_CTRL_ENABLE       BIT(0)
+/* Only on HW I/O coherency capable platforms */
 #define   WIN_CTRL_SYNCBARRIER  BIT(1)
 #define   WIN_CTRL_TGT_MASK     0xf0
 #define   WIN_CTRL_TGT_SHIFT    4
 
 /* Relative to mbusbridge_base */
 #define MBUS_BRIDGE_CTRL_OFF   0x0
-#define  MBUS_BRIDGE_SIZE_MASK  0xffff0000
 #define MBUS_BRIDGE_BASE_OFF   0x4
-#define  MBUS_BRIDGE_BASE_MASK  0xffff0000
 
 /* Maximum number of windows, for all known platforms */
 #define MBUS_WINS_MAX           20
@@ -323,8 +321,9 @@ static int mvebu_mbus_setup_window(struct mvebu_mbus_state *mbus,
        ctrl = ((size - 1) & WIN_CTRL_SIZE_MASK) |
                (attr << WIN_CTRL_ATTR_SHIFT)    |
                (target << WIN_CTRL_TGT_SHIFT)   |
-               WIN_CTRL_SYNCBARRIER             |
                WIN_CTRL_ENABLE;
+       if (mbus->hw_io_coherency)
+               ctrl |= WIN_CTRL_SYNCBARRIER;
 
        writel(base & WIN_BASE_LOW, addr + WIN_BASE_OFF);
        writel(ctrl, addr + WIN_CTRL_OFF);
@@ -577,106 +576,36 @@ static unsigned int armada_xp_mbus_win_remap_offset(int win)
                return MVEBU_MBUS_NO_REMAP;
 }
 
-/*
- * Use the memblock information to find the MBus bridge hole in the
- * physical address space.
- */
-static void __init
-mvebu_mbus_find_bridge_hole(uint64_t *start, uint64_t *end)
-{
-       struct memblock_region *r;
-       uint64_t s = 0;
-
-       for_each_memblock(memory, r) {
-               /*
-                * This part of the memory is above 4 GB, so we don't
-                * care for the MBus bridge hole.
-                */
-               if (r->base >= 0x100000000)
-                       continue;
-
-               /*
-                * The MBus bridge hole is at the end of the RAM under
-                * the 4 GB limit.
-                */
-               if (r->base + r->size > s)
-                       s = r->base + r->size;
-       }
-
-       *start = s;
-       *end = 0x100000000;
-}
-
 static void __init
 mvebu_mbus_default_setup_cpu_target(struct mvebu_mbus_state *mbus)
 {
        int i;
        int cs;
-       uint64_t mbus_bridge_base, mbus_bridge_end;
 
        mvebu_mbus_dram_info.mbus_dram_target_id = TARGET_DDR;
 
-       mvebu_mbus_find_bridge_hole(&mbus_bridge_base, &mbus_bridge_end);
-
        for (i = 0, cs = 0; i < 4; i++) {
-               u64 base = readl(mbus->sdramwins_base + DDR_BASE_CS_OFF(i));
-               u64 size = readl(mbus->sdramwins_base + DDR_SIZE_CS_OFF(i));
-               u64 end;
-               struct mbus_dram_window *w;
-
-               /* Ignore entries that are not enabled */
-               if (!(size & DDR_SIZE_ENABLED))
-                       continue;
-
-               /*
-                * Ignore entries whose base address is above 2^32,
-                * since devices cannot DMA to such high addresses
-                */
-               if (base & DDR_BASE_CS_HIGH_MASK)
-                       continue;
-
-               base = base & DDR_BASE_CS_LOW_MASK;
-               size = (size | ~DDR_SIZE_MASK) + 1;
-               end = base + size;
-
-               /*
-                * Adjust base/size of the current CS to make sure it
-                * doesn't overlap with the MBus bridge hole. This is
-                * particularly important for devices that do DMA from
-                * DRAM to a SRAM mapped in a MBus window, such as the
-                * CESA cryptographic engine.
-                */
+               u32 base = readl(mbus->sdramwins_base + DDR_BASE_CS_OFF(i));
+               u32 size = readl(mbus->sdramwins_base + DDR_SIZE_CS_OFF(i));
 
                /*
-                * The CS is fully enclosed inside the MBus bridge
-                * area, so ignore it.
+                * We only take care of entries for which the chip
+                * select is enabled, and that don't have high base
+                * address bits set (devices can only access the first
+                * 32 bits of the memory).
                 */
-               if (base >= mbus_bridge_base && end <= mbus_bridge_end)
-                       continue;
+               if ((size & DDR_SIZE_ENABLED) &&
+                   !(base & DDR_BASE_CS_HIGH_MASK)) {
+                       struct mbus_dram_window *w;
 
-               /*
-                * Beginning of CS overlaps with end of MBus, raise CS
-                * base address, and shrink its size.
-                */
-               if (base >= mbus_bridge_base && end > mbus_bridge_end) {
-                       size -= mbus_bridge_end - base;
-                       base = mbus_bridge_end;
+                       w = &mvebu_mbus_dram_info.cs[cs++];
+                       w->cs_index = i;
+                       w->mbus_attr = 0xf & ~(1 << i);
+                       if (mbus->hw_io_coherency)
+                               w->mbus_attr |= ATTR_HW_COHERENCY;
+                       w->base = base & DDR_BASE_CS_LOW_MASK;
+                       w->size = (size | ~DDR_SIZE_MASK) + 1;
                }
-
-               /*
-                * End of CS overlaps with beginning of MBus, shrink
-                * CS size.
-                */
-               if (base < mbus_bridge_base && end > mbus_bridge_base)
-                       size -= end - mbus_bridge_base;
-
-               w = &mvebu_mbus_dram_info.cs[cs++];
-               w->cs_index = i;
-               w->mbus_attr = 0xf & ~(1 << i);
-               if (mbus->hw_io_coherency)
-                       w->mbus_attr |= ATTR_HW_COHERENCY;
-               w->base = base;
-               w->size = size;
        }
        mvebu_mbus_dram_info.num_cs = cs;
 }
index 11f7982cbdb321ba26020b8c8a1495973ebb62e1..ebee57d715d2314df6b3ab0bff60cde656691a93 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * OMAP L3 Interconnect error handling driver
  *
- * Copyright (C) 2011-2014 Texas Instruments Incorporated - http://www.ti.com/
+ * Copyright (C) 2011-2015 Texas Instruments Incorporated - http://www.ti.com/
  *     Santosh Shilimkar <santosh.shilimkar@ti.com>
  *     Sricharan <r.sricharan@ti.com>
  *
@@ -233,7 +233,8 @@ static irqreturn_t l3_interrupt_handler(int irq, void *_l3)
 }
 
 static const struct of_device_id l3_noc_match[] = {
-       {.compatible = "ti,omap4-l3-noc", .data = &omap_l3_data},
+       {.compatible = "ti,omap4-l3-noc", .data = &omap4_l3_data},
+       {.compatible = "ti,omap5-l3-noc", .data = &omap5_l3_data},
        {.compatible = "ti,dra7-l3-noc", .data = &dra_l3_data},
        {.compatible = "ti,am4372-l3-noc", .data = &am4372_l3_data},
        {},
index 95254585db86aca1adc29091a28486fe821e7e53..73431f81da28c0036fba33b52a17641eee5e385a 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * OMAP L3 Interconnect  error handling driver header
  *
- * Copyright (C) 2011-2014 Texas Instruments Incorporated - http://www.ti.com/
+ * Copyright (C) 2011-2015 Texas Instruments Incorporated - http://www.ti.com/
  *     Santosh Shilimkar <santosh.shilimkar@ti.com>
  *     sricharan <r.sricharan@ti.com>
  *
@@ -175,16 +175,14 @@ static struct l3_flagmux_data omap_l3_flagmux_clk2 = {
 };
 
 
-static struct l3_target_data omap_l3_target_data_clk3[] = {
-       {0x0100, "EMUSS",},
-       {0x0300, "DEBUG SOURCE",},
-       {0x0,   "HOST CLK3",},
+static struct l3_target_data omap4_l3_target_data_clk3[] = {
+       {0x0100, "DEBUGSS",},
 };
 
-static struct l3_flagmux_data omap_l3_flagmux_clk3 = {
+static struct l3_flagmux_data omap4_l3_flagmux_clk3 = {
        .offset = 0x0200,
-       .l3_targ = omap_l3_target_data_clk3,
-       .num_targ_data = ARRAY_SIZE(omap_l3_target_data_clk3),
+       .l3_targ = omap4_l3_target_data_clk3,
+       .num_targ_data = ARRAY_SIZE(omap4_l3_target_data_clk3),
 };
 
 static struct l3_masters_data omap_l3_masters[] = {
@@ -215,21 +213,49 @@ static struct l3_masters_data omap_l3_masters[] = {
        { 0x32, "USBHOSTFS"}
 };
 
-static struct l3_flagmux_data *omap_l3_flagmux[] = {
+static struct l3_flagmux_data *omap4_l3_flagmux[] = {
        &omap_l3_flagmux_clk1,
        &omap_l3_flagmux_clk2,
-       &omap_l3_flagmux_clk3,
+       &omap4_l3_flagmux_clk3,
 };
 
-static const struct omap_l3 omap_l3_data = {
-       .l3_flagmux = omap_l3_flagmux,
-       .num_modules = ARRAY_SIZE(omap_l3_flagmux),
+static const struct omap_l3 omap4_l3_data = {
+       .l3_flagmux = omap4_l3_flagmux,
+       .num_modules = ARRAY_SIZE(omap4_l3_flagmux),
        .l3_masters = omap_l3_masters,
        .num_masters = ARRAY_SIZE(omap_l3_masters),
        /* The 6 MSBs of register field used to distinguish initiator */
        .mst_addr_mask = 0xFC,
 };
 
+/* OMAP5 data */
+static struct l3_target_data omap5_l3_target_data_clk3[] = {
+       {0x0100, "L3INSTR",},
+       {0x0300, "DEBUGSS",},
+       {0x0,    "HOSTCLK3",},
+};
+
+static struct l3_flagmux_data omap5_l3_flagmux_clk3 = {
+       .offset = 0x0200,
+       .l3_targ = omap5_l3_target_data_clk3,
+       .num_targ_data = ARRAY_SIZE(omap5_l3_target_data_clk3),
+};
+
+static struct l3_flagmux_data *omap5_l3_flagmux[] = {
+       &omap_l3_flagmux_clk1,
+       &omap_l3_flagmux_clk2,
+       &omap5_l3_flagmux_clk3,
+};
+
+static const struct omap_l3 omap5_l3_data = {
+       .l3_flagmux = omap5_l3_flagmux,
+       .num_modules = ARRAY_SIZE(omap5_l3_flagmux),
+       .l3_masters = omap_l3_masters,
+       .num_masters = ARRAY_SIZE(omap_l3_masters),
+       /* The 6 MSBs of register field used to distinguish initiator */
+       .mst_addr_mask = 0x7E0,
+};
+
 /* DRA7 data */
 static struct l3_target_data dra_l3_target_data_clk1[] = {
        {0x2a00, "AES1",},
@@ -274,7 +300,7 @@ static struct l3_flagmux_data dra_l3_flagmux_clk1 = {
 
 static struct l3_target_data dra_l3_target_data_clk2[] = {
        {0x0,   "HOST CLK1",},
-       {0x0,   "HOST CLK2",},
+       {0x800000, "HOST CLK2",},
        {0xdead, L3_TARGET_NOT_SUPPORTED,},
        {0x3400, "SHA2_2",},
        {0x0900, "BB2D",},
index d1494ecd9e116490dd5c5875387be7e6a2a92fde..4b31f1387f37fa9cbe8f09afc682df62aedab384 100644 (file)
@@ -57,7 +57,7 @@ static void bcm63xx_rng_cleanup(struct hwrng *rng)
        val &= ~RNG_EN;
        __raw_writel(val, priv->regs + RNG_CTRL);
 
-       clk_didsable_unprepare(prov->clk);
+       clk_disable_unprepare(priv->clk);
 }
 
 static int bcm63xx_rng_data_present(struct hwrng *rng, int wait)
@@ -97,14 +97,14 @@ static int bcm63xx_rng_probe(struct platform_device *pdev)
        priv->rng.name = pdev->name;
        priv->rng.init = bcm63xx_rng_init;
        priv->rng.cleanup = bcm63xx_rng_cleanup;
-       prov->rng.data_present = bcm63xx_rng_data_present;
+       priv->rng.data_present = bcm63xx_rng_data_present;
        priv->rng.data_read = bcm63xx_rng_data_read;
 
        priv->clk = devm_clk_get(&pdev->dev, "ipsec");
        if (IS_ERR(priv->clk)) {
-               error = PTR_ERR(priv->clk);
-               dev_err(&pdev->dev, "no clock for device: %d\n", error);
-               return error;
+               ret = PTR_ERR(priv->clk);
+               dev_err(&pdev->dev, "no clock for device: %d\n", ret);
+               return ret;
        }
 
        if (!devm_request_mem_region(&pdev->dev, r->start,
@@ -120,11 +120,11 @@ static int bcm63xx_rng_probe(struct platform_device *pdev)
                return -ENOMEM;
        }
 
-       error = devm_hwrng_register(&pdev->dev, &priv->rng);
-       if (error) {
+       ret = devm_hwrng_register(&pdev->dev, &priv->rng);
+       if (ret) {
                dev_err(&pdev->dev, "failed to register rng device: %d\n",
-                       error);
-               return error;
+                       ret);
+               return ret;
        }
 
        dev_info(&pdev->dev, "registered RNG driver\n");
index 9bb592872532b1853efb00930c001e54df5fa7ed..bf75f63617731595d958765b7c1582f79452f3cb 100644 (file)
@@ -2000,7 +2000,7 @@ static int smi_ipmb_proc_show(struct seq_file *m, void *v)
                seq_printf(m, " %x", intf->channels[i].address);
        seq_putc(m, '\n');
 
-       return seq_has_overflowed(m);
+       return 0;
 }
 
 static int smi_ipmb_proc_open(struct inode *inode, struct file *file)
@@ -2023,7 +2023,7 @@ static int smi_version_proc_show(struct seq_file *m, void *v)
                   ipmi_version_major(&intf->bmc->id),
                   ipmi_version_minor(&intf->bmc->id));
 
-       return seq_has_overflowed(m);
+       return 0;
 }
 
 static int smi_version_proc_open(struct inode *inode, struct file *file)
index 5e90a18afbafa23270aff3718a91f6c010524971..8a45e92ff60c7483349cf1819b9d0ebc576ebd44 100644 (file)
@@ -942,8 +942,7 @@ static void sender(void                *send_info,
                 * If we are running to completion, start it and run
                 * transactions until everything is clear.
                 */
-               smi_info->curr_msg = msg;
-               smi_info->waiting_msg = NULL;
+               smi_info->waiting_msg = msg;
 
                /*
                 * Run to completion means we are single-threaded, no
@@ -2244,7 +2243,7 @@ static int ipmi_pnp_probe(struct pnp_dev *dev,
        acpi_handle handle;
        acpi_status status;
        unsigned long long tmp;
-       int rv;
+       int rv = -EINVAL;
 
        acpi_dev = pnp_acpi_device(dev);
        if (!acpi_dev)
@@ -2262,8 +2261,10 @@ static int ipmi_pnp_probe(struct pnp_dev *dev,
 
        /* _IFT tells us the interface type: KCS, BT, etc */
        status = acpi_evaluate_integer(handle, "_IFT", NULL, &tmp);
-       if (ACPI_FAILURE(status))
+       if (ACPI_FAILURE(status)) {
+               dev_err(&dev->dev, "Could not find ACPI IPMI interface type\n");
                goto err_free;
+       }
 
        switch (tmp) {
        case 1:
@@ -2276,6 +2277,7 @@ static int ipmi_pnp_probe(struct pnp_dev *dev,
                info->si_type = SI_BT;
                break;
        case 4: /* SSIF, just ignore */
+               rv = -ENODEV;
                goto err_free;
        default:
                dev_info(&dev->dev, "unknown IPMI type %lld\n", tmp);
@@ -2336,7 +2338,7 @@ static int ipmi_pnp_probe(struct pnp_dev *dev,
 
 err_free:
        kfree(info);
-       return -EINVAL;
+       return rv;
 }
 
 static void ipmi_pnp_remove(struct pnp_dev *dev)
@@ -3080,7 +3082,7 @@ static int smi_type_proc_show(struct seq_file *m, void *v)
 
        seq_printf(m, "%s\n", si_to_str[smi->si_type]);
 
-       return seq_has_overflowed(m);
+       return 0;
 }
 
 static int smi_type_proc_open(struct inode *inode, struct file *file)
@@ -3153,7 +3155,7 @@ static int smi_params_proc_show(struct seq_file *m, void *v)
                   smi->irq,
                   smi->slave_addr);
 
-       return seq_has_overflowed(m);
+       return 0;
 }
 
 static int smi_params_proc_open(struct inode *inode, struct file *file)
index f40e3bd2c69c265400f1241900be8dddd26b51e8..207689c444a8155540b72280b9c402c027ac361b 100644 (file)
@@ -31,7 +31,6 @@
  * interface into the I2C driver, I believe.
  */
 
-#include <linux/version.h>
 #if defined(MODVERSIONS)
 #include <linux/modversions.h>
 #endif
@@ -166,6 +165,9 @@ enum ssif_stat_indexes {
        /* Number of watchdog pretimeouts. */
        SSIF_STAT_watchdog_pretimeouts,
 
+       /* Number of alers received. */
+       SSIF_STAT_alerts,
+
        /* Always add statistics before this value, it must be last. */
        SSIF_NUM_STATS
 };
@@ -214,7 +216,16 @@ struct ssif_info {
 #define WDT_PRE_TIMEOUT_INT    0x08
        unsigned char       msg_flags;
 
+       u8                  global_enables;
        bool                has_event_buffer;
+       bool                supports_alert;
+
+       /*
+        * Used to tell what we should do with alerts.  If we are
+        * waiting on a response, read the data immediately.
+        */
+       bool                got_alert;
+       bool                waiting_alert;
 
        /*
         * If set to true, this will request events the next time the
@@ -478,13 +489,13 @@ static int ipmi_ssif_thread(void *data)
 
                if (ssif_info->i2c_read_write == I2C_SMBUS_WRITE) {
                        result = i2c_smbus_write_block_data(
-                               ssif_info->client, SSIF_IPMI_REQUEST,
+                               ssif_info->client, ssif_info->i2c_command,
                                ssif_info->i2c_data[0],
                                ssif_info->i2c_data + 1);
                        ssif_info->done_handler(ssif_info, result, NULL, 0);
                } else {
                        result = i2c_smbus_read_block_data(
-                               ssif_info->client, SSIF_IPMI_RESPONSE,
+                               ssif_info->client, ssif_info->i2c_command,
                                ssif_info->i2c_data);
                        if (result < 0)
                                ssif_info->done_handler(ssif_info, result,
@@ -518,15 +529,12 @@ static int ssif_i2c_send(struct ssif_info *ssif_info,
 static void msg_done_handler(struct ssif_info *ssif_info, int result,
                             unsigned char *data, unsigned int len);
 
-static void retry_timeout(unsigned long data)
+static void start_get(struct ssif_info *ssif_info)
 {
-       struct ssif_info *ssif_info = (void *) data;
        int rv;
 
-       if (ssif_info->stopping)
-               return;
-
        ssif_info->rtc_us_timer = 0;
+       ssif_info->multi_pos = 0;
 
        rv = ssif_i2c_send(ssif_info, msg_done_handler, I2C_SMBUS_READ,
                          SSIF_IPMI_RESPONSE,
@@ -540,6 +548,46 @@ static void retry_timeout(unsigned long data)
        }
 }
 
+static void retry_timeout(unsigned long data)
+{
+       struct ssif_info *ssif_info = (void *) data;
+       unsigned long oflags, *flags;
+       bool waiting;
+
+       if (ssif_info->stopping)
+               return;
+
+       flags = ipmi_ssif_lock_cond(ssif_info, &oflags);
+       waiting = ssif_info->waiting_alert;
+       ssif_info->waiting_alert = false;
+       ipmi_ssif_unlock_cond(ssif_info, flags);
+
+       if (waiting)
+               start_get(ssif_info);
+}
+
+
+static void ssif_alert(struct i2c_client *client, unsigned int data)
+{
+       struct ssif_info *ssif_info = i2c_get_clientdata(client);
+       unsigned long oflags, *flags;
+       bool do_get = false;
+
+       ssif_inc_stat(ssif_info, alerts);
+
+       flags = ipmi_ssif_lock_cond(ssif_info, &oflags);
+       if (ssif_info->waiting_alert) {
+               ssif_info->waiting_alert = false;
+               del_timer(&ssif_info->retry_timer);
+               do_get = true;
+       } else if (ssif_info->curr_msg) {
+               ssif_info->got_alert = true;
+       }
+       ipmi_ssif_unlock_cond(ssif_info, flags);
+       if (do_get)
+               start_get(ssif_info);
+}
+
 static int start_resend(struct ssif_info *ssif_info);
 
 static void msg_done_handler(struct ssif_info *ssif_info, int result,
@@ -559,9 +607,12 @@ static void msg_done_handler(struct ssif_info *ssif_info, int result,
                if (ssif_info->retries_left > 0) {
                        ssif_inc_stat(ssif_info, receive_retries);
 
+                       flags = ipmi_ssif_lock_cond(ssif_info, &oflags);
+                       ssif_info->waiting_alert = true;
+                       ssif_info->rtc_us_timer = SSIF_MSG_USEC;
                        mod_timer(&ssif_info->retry_timer,
                                  jiffies + SSIF_MSG_JIFFIES);
-                       ssif_info->rtc_us_timer = SSIF_MSG_USEC;
+                       ipmi_ssif_unlock_cond(ssif_info, flags);
                        return;
                }
 
@@ -581,9 +632,9 @@ static void msg_done_handler(struct ssif_info *ssif_info, int result,
                ssif_inc_stat(ssif_info, received_message_parts);
 
                /* Remove the multi-part read marker. */
-               for (i = 0; i < (len-2); i++)
-                       ssif_info->data[i] = data[i+2];
                len -= 2;
+               for (i = 0; i < len; i++)
+                       ssif_info->data[i] = data[i+2];
                ssif_info->multi_len = len;
                ssif_info->multi_pos = 1;
 
@@ -610,9 +661,9 @@ static void msg_done_handler(struct ssif_info *ssif_info, int result,
                        goto continue_op;
                }
 
-               blocknum = data[ssif_info->multi_len];
+               blocknum = data[0];
 
-               if (ssif_info->multi_len+len-1 > IPMI_MAX_MSG_LENGTH) {
+               if (ssif_info->multi_len + len - 1 > IPMI_MAX_MSG_LENGTH) {
                        /* Received message too big, abort the operation. */
                        result = -E2BIG;
                        if (ssif_info->ssif_debug & SSIF_DEBUG_MSG)
@@ -622,15 +673,15 @@ static void msg_done_handler(struct ssif_info *ssif_info, int result,
                }
 
                /* Remove the blocknum from the data. */
-               for (i = 0; i < (len-1); i++)
-                       ssif_info->data[i+ssif_info->multi_len] = data[i+1];
                len--;
+               for (i = 0; i < len; i++)
+                       ssif_info->data[i + ssif_info->multi_len] = data[i + 1];
                ssif_info->multi_len += len;
                if (blocknum == 0xff) {
                        /* End of read */
                        len = ssif_info->multi_len;
                        data = ssif_info->data;
-               } else if ((blocknum+1) != ssif_info->multi_pos) {
+               } else if (blocknum + 1 != ssif_info->multi_pos) {
                        /*
                         * Out of sequence block, just abort.  Block
                         * numbers start at zero for the second block,
@@ -650,7 +701,7 @@ static void msg_done_handler(struct ssif_info *ssif_info, int result,
                        if (rv < 0) {
                                if (ssif_info->ssif_debug & SSIF_DEBUG_MSG)
                                        pr_info(PFX
-                                               "Error from i2c_non_blocking_op(2)\n");
+                                               "Error from ssif_i2c_send\n");
 
                                result = -EIO;
                        } else
@@ -830,7 +881,11 @@ static void msg_written_handler(struct ssif_info *ssif_info, int result,
        }
 
        if (ssif_info->multi_data) {
-               /* In the middle of a multi-data write. */
+               /*
+                * In the middle of a multi-data write.  See the comment
+                * in the SSIF_MULTI_n_PART case in the probe function
+                * for details on the intricacies of this.
+                */
                int left;
 
                ssif_inc_stat(ssif_info, sent_messages_parts);
@@ -864,15 +919,32 @@ static void msg_written_handler(struct ssif_info *ssif_info, int result,
                        msg_done_handler(ssif_info, -EIO, NULL, 0);
                }
        } else {
+               unsigned long oflags, *flags;
+               bool got_alert;
+
                ssif_inc_stat(ssif_info, sent_messages);
                ssif_inc_stat(ssif_info, sent_messages_parts);
 
-               /* Wait a jiffie then request the next message */
-               ssif_info->retries_left = SSIF_RECV_RETRIES;
-               ssif_info->rtc_us_timer = SSIF_MSG_PART_USEC;
-               mod_timer(&ssif_info->retry_timer,
-                         jiffies + SSIF_MSG_PART_JIFFIES);
-               return;
+               flags = ipmi_ssif_lock_cond(ssif_info, &oflags);
+               got_alert = ssif_info->got_alert;
+               if (got_alert) {
+                       ssif_info->got_alert = false;
+                       ssif_info->waiting_alert = false;
+               }
+
+               if (got_alert) {
+                       ipmi_ssif_unlock_cond(ssif_info, flags);
+                       /* The alert already happened, try now. */
+                       retry_timeout((unsigned long) ssif_info);
+               } else {
+                       /* Wait a jiffie then request the next message */
+                       ssif_info->waiting_alert = true;
+                       ssif_info->retries_left = SSIF_RECV_RETRIES;
+                       ssif_info->rtc_us_timer = SSIF_MSG_PART_USEC;
+                       mod_timer(&ssif_info->retry_timer,
+                                 jiffies + SSIF_MSG_PART_JIFFIES);
+                       ipmi_ssif_unlock_cond(ssif_info, flags);
+               }
        }
 }
 
@@ -881,6 +953,8 @@ static int start_resend(struct ssif_info *ssif_info)
        int rv;
        int command;
 
+       ssif_info->got_alert = false;
+
        if (ssif_info->data_len > 32) {
                command = SSIF_IPMI_MULTI_PART_REQUEST_START;
                ssif_info->multi_data = ssif_info->data;
@@ -915,7 +989,7 @@ static int start_send(struct ssif_info *ssif_info,
                return -E2BIG;
 
        ssif_info->retries_left = SSIF_SEND_RETRIES;
-       memcpy(ssif_info->data+1, data, len);
+       memcpy(ssif_info->data + 1, data, len);
        ssif_info->data_len = len;
        return start_resend(ssif_info);
 }
@@ -1200,7 +1274,7 @@ static int smi_type_proc_show(struct seq_file *m, void *v)
 {
        seq_puts(m, "ssif\n");
 
-       return seq_has_overflowed(m);
+       return 0;
 }
 
 static int smi_type_proc_open(struct inode *inode, struct file *file)
@@ -1243,6 +1317,8 @@ static int smi_stats_proc_show(struct seq_file *m, void *v)
                   ssif_get_stat(ssif_info, events));
        seq_printf(m, "watchdog_pretimeouts:   %u\n",
                   ssif_get_stat(ssif_info, watchdog_pretimeouts));
+       seq_printf(m, "alerts:                 %u\n",
+                  ssif_get_stat(ssif_info, alerts));
        return 0;
 }
 
@@ -1258,6 +1334,23 @@ static const struct file_operations smi_stats_proc_ops = {
        .release        = single_release,
 };
 
+static int strcmp_nospace(char *s1, char *s2)
+{
+       while (*s1 && *s2) {
+               while (isspace(*s1))
+                       s1++;
+               while (isspace(*s2))
+                       s2++;
+               if (*s1 > *s2)
+                       return 1;
+               if (*s1 < *s2)
+                       return -1;
+               s1++;
+               s2++;
+       }
+       return 0;
+}
+
 static struct ssif_addr_info *ssif_info_find(unsigned short addr,
                                             char *adapter_name,
                                             bool match_null_name)
@@ -1272,8 +1365,10 @@ restart:
                                        /* One is NULL and one is not */
                                        continue;
                                }
-                               if (strcmp(info->adapter_name, adapter_name))
-                                       /* Names to not match */
+                               if (adapter_name &&
+                                   strcmp_nospace(info->adapter_name,
+                                                  adapter_name))
+                                       /* Names do not match */
                                        continue;
                        }
                        found = info;
@@ -1306,6 +1401,12 @@ static bool check_acpi(struct ssif_info *ssif_info, struct device *dev)
        return false;
 }
 
+/*
+ * Global enables we care about.
+ */
+#define GLOBAL_ENABLES_MASK (IPMI_BMC_EVT_MSG_BUFF | IPMI_BMC_RCV_MSG_INTR | \
+                            IPMI_BMC_EVT_MSG_INTR)
+
 static int ssif_probe(struct i2c_client *client, const struct i2c_device_id *id)
 {
        unsigned char     msg[3];
@@ -1391,13 +1492,33 @@ static int ssif_probe(struct i2c_client *client, const struct i2c_device_id *id)
                        break;
 
                case SSIF_MULTI_2_PART:
-                       if (ssif_info->max_xmit_msg_size > 64)
-                               ssif_info->max_xmit_msg_size = 64;
+                       if (ssif_info->max_xmit_msg_size > 63)
+                               ssif_info->max_xmit_msg_size = 63;
                        if (ssif_info->max_recv_msg_size > 62)
                                ssif_info->max_recv_msg_size = 62;
                        break;
 
                case SSIF_MULTI_n_PART:
+                       /*
+                        * The specification is rather confusing at
+                        * this point, but I think I understand what
+                        * is meant.  At least I have a workable
+                        * solution.  With multi-part messages, you
+                        * cannot send a message that is a multiple of
+                        * 32-bytes in length, because the start and
+                        * middle messages are 32-bytes and the end
+                        * message must be at least one byte.  You
+                        * can't fudge on an extra byte, that would
+                        * screw up things like fru data writes.  So
+                        * we limit the length to 63 bytes.  That way
+                        * a 32-byte message gets sent as a single
+                        * part.  A larger message will be a 32-byte
+                        * start and the next message is always going
+                        * to be 1-31 bytes in length.  Not ideal, but
+                        * it should work.
+                        */
+                       if (ssif_info->max_xmit_msg_size > 63)
+                               ssif_info->max_xmit_msg_size = 63;
                        break;
 
                default:
@@ -1407,7 +1528,7 @@ static int ssif_probe(struct i2c_client *client, const struct i2c_device_id *id)
        } else {
  no_support:
                /* Assume no multi-part or PEC support */
-               pr_info(PFX "Error fetching SSIF: %d %d %2.2x, your system probably doesn't support this command so  using defaults\n",
+               pr_info(PFX "Error fetching SSIF: %d %d %2.2x, your system probably doesn't support this command so using defaults\n",
                       rv, len, resp[2]);
 
                ssif_info->max_xmit_msg_size = 32;
@@ -1436,6 +1557,8 @@ static int ssif_probe(struct i2c_client *client, const struct i2c_device_id *id)
                goto found;
        }
 
+       ssif_info->global_enables = resp[3];
+
        if (resp[3] & IPMI_BMC_EVT_MSG_BUFF) {
                ssif_info->has_event_buffer = true;
                /* buffer is already enabled, nothing to do. */
@@ -1444,18 +1567,37 @@ static int ssif_probe(struct i2c_client *client, const struct i2c_device_id *id)
 
        msg[0] = IPMI_NETFN_APP_REQUEST << 2;
        msg[1] = IPMI_SET_BMC_GLOBAL_ENABLES_CMD;
-       msg[2] = resp[3] | IPMI_BMC_EVT_MSG_BUFF;
+       msg[2] = ssif_info->global_enables | IPMI_BMC_EVT_MSG_BUFF;
        rv = do_cmd(client, 3, msg, &len, resp);
        if (rv || (len < 2)) {
-               pr_warn(PFX "Error getting global enables: %d %d %2.2x\n",
+               pr_warn(PFX "Error setting global enables: %d %d %2.2x\n",
                        rv, len, resp[2]);
                rv = 0; /* Not fatal */
                goto found;
        }
 
-       if (resp[2] == 0)
+       if (resp[2] == 0) {
                /* A successful return means the event buffer is supported. */
                ssif_info->has_event_buffer = true;
+               ssif_info->global_enables |= IPMI_BMC_EVT_MSG_BUFF;
+       }
+
+       msg[0] = IPMI_NETFN_APP_REQUEST << 2;
+       msg[1] = IPMI_SET_BMC_GLOBAL_ENABLES_CMD;
+       msg[2] = ssif_info->global_enables | IPMI_BMC_RCV_MSG_INTR;
+       rv = do_cmd(client, 3, msg, &len, resp);
+       if (rv || (len < 2)) {
+               pr_warn(PFX "Error setting global enables: %d %d %2.2x\n",
+                       rv, len, resp[2]);
+               rv = 0; /* Not fatal */
+               goto found;
+       }
+
+       if (resp[2] == 0) {
+               /* A successful return means the alert is supported. */
+               ssif_info->supports_alert = true;
+               ssif_info->global_enables |= IPMI_BMC_RCV_MSG_INTR;
+       }
 
  found:
        ssif_info->intf_num = atomic_inc_return(&next_intf);
@@ -1813,6 +1955,7 @@ static struct i2c_driver ssif_i2c_driver = {
        },
        .probe          = ssif_probe,
        .remove         = ssif_remove,
+       .alert          = ssif_alert,
        .id_table       = ssif_id,
        .detect         = ssif_detect
 };
@@ -1832,7 +1975,7 @@ static int init_ipmi_ssif(void)
                rv = new_ssif_client(addr[i], adapter_name[i],
                                     dbg[i], slave_addrs[i],
                                     SI_HARDCODED);
-               if (!rv)
+               if (rv)
                        pr_err(PFX
                               "Couldn't add hardcoded device at addr 0x%x\n",
                               addr[i]);
index 44ea107cfc6729818ea8a02dfd250f7e6a557967..30335d3b99afb197332505d5be045f2d5d75be4c 100644 (file)
@@ -1128,13 +1128,6 @@ static int si5351_dt_parse(struct i2c_client *client,
        if (!pdata)
                return -ENOMEM;
 
-       pdata->clk_xtal = of_clk_get(np, 0);
-       if (!IS_ERR(pdata->clk_xtal))
-               clk_put(pdata->clk_xtal);
-       pdata->clk_clkin = of_clk_get(np, 1);
-       if (!IS_ERR(pdata->clk_clkin))
-               clk_put(pdata->clk_clkin);
-
        /*
         * property silabs,pll-source : <num src>, [<..>]
         * allow to selectively set pll source
@@ -1328,8 +1321,22 @@ static int si5351_i2c_probe(struct i2c_client *client,
        i2c_set_clientdata(client, drvdata);
        drvdata->client = client;
        drvdata->variant = variant;
-       drvdata->pxtal = pdata->clk_xtal;
-       drvdata->pclkin = pdata->clk_clkin;
+       drvdata->pxtal = devm_clk_get(&client->dev, "xtal");
+       drvdata->pclkin = devm_clk_get(&client->dev, "clkin");
+
+       if (PTR_ERR(drvdata->pxtal) == -EPROBE_DEFER ||
+           PTR_ERR(drvdata->pclkin) == -EPROBE_DEFER)
+               return -EPROBE_DEFER;
+
+       /*
+        * Check for valid parent clock: VARIANT_A and VARIANT_B need XTAL,
+        *   VARIANT_C can have CLKIN instead.
+        */
+       if (IS_ERR(drvdata->pxtal) &&
+           (drvdata->variant != SI5351_VARIANT_C || IS_ERR(drvdata->pclkin))) {
+               dev_err(&client->dev, "missing parent clock\n");
+               return -EINVAL;
+       }
 
        drvdata->regmap = devm_regmap_init_i2c(client, &si5351_regmap_config);
        if (IS_ERR(drvdata->regmap)) {
@@ -1393,6 +1400,11 @@ static int si5351_i2c_probe(struct i2c_client *client,
                }
        }
 
+       if (!IS_ERR(drvdata->pxtal))
+               clk_prepare_enable(drvdata->pxtal);
+       if (!IS_ERR(drvdata->pclkin))
+               clk_prepare_enable(drvdata->pclkin);
+
        /* register xtal input clock gate */
        memset(&init, 0, sizeof(init));
        init.name = si5351_input_names[0];
@@ -1407,7 +1419,8 @@ static int si5351_i2c_probe(struct i2c_client *client,
        clk = devm_clk_register(&client->dev, &drvdata->xtal);
        if (IS_ERR(clk)) {
                dev_err(&client->dev, "unable to register %s\n", init.name);
-               return PTR_ERR(clk);
+               ret = PTR_ERR(clk);
+               goto err_clk;
        }
 
        /* register clkin input clock gate */
@@ -1425,7 +1438,8 @@ static int si5351_i2c_probe(struct i2c_client *client,
                if (IS_ERR(clk)) {
                        dev_err(&client->dev, "unable to register %s\n",
                                init.name);
-                       return PTR_ERR(clk);
+                       ret = PTR_ERR(clk);
+                       goto err_clk;
                }
        }
 
@@ -1447,7 +1461,8 @@ static int si5351_i2c_probe(struct i2c_client *client,
        clk = devm_clk_register(&client->dev, &drvdata->pll[0].hw);
        if (IS_ERR(clk)) {
                dev_err(&client->dev, "unable to register %s\n", init.name);
-               return -EINVAL;
+               ret = PTR_ERR(clk);
+               goto err_clk;
        }
 
        /* register PLLB or VXCO (Si5351B) */
@@ -1471,7 +1486,8 @@ static int si5351_i2c_probe(struct i2c_client *client,
        clk = devm_clk_register(&client->dev, &drvdata->pll[1].hw);
        if (IS_ERR(clk)) {
                dev_err(&client->dev, "unable to register %s\n", init.name);
-               return -EINVAL;
+               ret = PTR_ERR(clk);
+               goto err_clk;
        }
 
        /* register clk multisync and clk out divider */
@@ -1492,8 +1508,10 @@ static int si5351_i2c_probe(struct i2c_client *client,
                num_clocks * sizeof(*drvdata->onecell.clks), GFP_KERNEL);
 
        if (WARN_ON(!drvdata->msynth || !drvdata->clkout ||
-                   !drvdata->onecell.clks))
-               return -ENOMEM;
+                   !drvdata->onecell.clks)) {
+               ret = -ENOMEM;
+               goto err_clk;
+       }
 
        for (n = 0; n < num_clocks; n++) {
                drvdata->msynth[n].num = n;
@@ -1511,7 +1529,8 @@ static int si5351_i2c_probe(struct i2c_client *client,
                if (IS_ERR(clk)) {
                        dev_err(&client->dev, "unable to register %s\n",
                                init.name);
-                       return -EINVAL;
+                       ret = PTR_ERR(clk);
+                       goto err_clk;
                }
        }
 
@@ -1538,7 +1557,8 @@ static int si5351_i2c_probe(struct i2c_client *client,
                if (IS_ERR(clk)) {
                        dev_err(&client->dev, "unable to register %s\n",
                                init.name);
-                       return -EINVAL;
+                       ret = PTR_ERR(clk);
+                       goto err_clk;
                }
                drvdata->onecell.clks[n] = clk;
 
@@ -1557,10 +1577,17 @@ static int si5351_i2c_probe(struct i2c_client *client,
                                  &drvdata->onecell);
        if (ret) {
                dev_err(&client->dev, "unable to add clk provider\n");
-               return ret;
+               goto err_clk;
        }
 
        return 0;
+
+err_clk:
+       if (!IS_ERR(drvdata->pxtal))
+               clk_disable_unprepare(drvdata->pxtal);
+       if (!IS_ERR(drvdata->pclkin))
+               clk_disable_unprepare(drvdata->pclkin);
+       return ret;
 }
 
 static const struct i2c_device_id si5351_i2c_ids[] = {
index 459ce9da13e0631b41e6cafc5ed9a85523e5e1b7..5b0f41868b425672e6295ac6b30a52e43cf5730c 100644 (file)
@@ -1475,8 +1475,10 @@ static struct clk_core *__clk_set_parent_before(struct clk_core *clk,
         */
        if (clk->prepare_count) {
                clk_core_prepare(parent);
+               flags = clk_enable_lock();
                clk_core_enable(parent);
                clk_core_enable(clk);
+               clk_enable_unlock(flags);
        }
 
        /* update the clk tree topology */
@@ -1491,13 +1493,17 @@ static void __clk_set_parent_after(struct clk_core *core,
                                   struct clk_core *parent,
                                   struct clk_core *old_parent)
 {
+       unsigned long flags;
+
        /*
         * Finish the migration of prepare state and undo the changes done
         * for preventing a race with clk_enable().
         */
        if (core->prepare_count) {
+               flags = clk_enable_lock();
                clk_core_disable(core);
                clk_core_disable(old_parent);
+               clk_enable_unlock(flags);
                clk_core_unprepare(old_parent);
        }
 }
@@ -1525,8 +1531,10 @@ static int __clk_set_parent(struct clk_core *clk, struct clk_core *parent,
                clk_enable_unlock(flags);
 
                if (clk->prepare_count) {
+                       flags = clk_enable_lock();
                        clk_core_disable(clk);
                        clk_core_disable(parent);
+                       clk_enable_unlock(flags);
                        clk_core_unprepare(parent);
                }
                return ret;
index d3458474eb3a1ef6bbc67f919b60b725978e8aee..c66f7bc2ae87cde429121af226970c2c7fd973c4 100644 (file)
@@ -71,8 +71,8 @@ static const char *gcc_xo_gpll0_bimc[] = {
 static const struct parent_map gcc_xo_gpll0a_gpll1_gpll2a_map[] = {
        { P_XO, 0 },
        { P_GPLL0_AUX, 3 },
-       { P_GPLL2_AUX, 2 },
        { P_GPLL1, 1 },
+       { P_GPLL2_AUX, 2 },
 };
 
 static const char *gcc_xo_gpll0a_gpll1_gpll2a[] = {
@@ -1115,7 +1115,7 @@ static struct clk_rcg2 usb_hs_system_clk_src = {
 static const struct freq_tbl ftbl_gcc_venus0_vcodec0_clk[] = {
        F(100000000, P_GPLL0, 8, 0, 0),
        F(160000000, P_GPLL0, 5, 0, 0),
-       F(228570000, P_GPLL0, 5, 0, 0),
+       F(228570000, P_GPLL0, 3.5, 0, 0),
        { }
 };
 
index 17e9af7fe81fe0aad57ad6ec1c2a2ac05b2280dd..a17683b2cf276b03e287bd6959f217e7aacb7c5f 100644 (file)
@@ -10,7 +10,7 @@ obj-$(CONFIG_SOC_EXYNOS5250)  += clk-exynos5250.o
 obj-$(CONFIG_SOC_EXYNOS5260)   += clk-exynos5260.o
 obj-$(CONFIG_SOC_EXYNOS5410)   += clk-exynos5410.o
 obj-$(CONFIG_SOC_EXYNOS5420)   += clk-exynos5420.o
-obj-$(CONFIG_ARCH_EXYNOS5433)  += clk-exynos5433.o
+obj-$(CONFIG_ARCH_EXYNOS)      += clk-exynos5433.o
 obj-$(CONFIG_SOC_EXYNOS5440)   += clk-exynos5440.o
 obj-$(CONFIG_ARCH_EXYNOS)      += clk-exynos-audss.o
 obj-$(CONFIG_ARCH_EXYNOS)      += clk-exynos-clkout.o
index 07d666cc6a29b9f3567deec197756b5927f68ac7..bea4a173eef5e40e12a4a05f8f6ccb3310700814 100644 (file)
@@ -271,6 +271,7 @@ static const struct samsung_clk_reg_dump exynos5420_set_clksrc[] = {
        { .offset = SRC_MASK_PERIC0,            .value = 0x11111110, },
        { .offset = SRC_MASK_PERIC1,            .value = 0x11111100, },
        { .offset = SRC_MASK_ISP,               .value = 0x11111000, },
+       { .offset = GATE_BUS_TOP,               .value = 0xffffffff, },
        { .offset = GATE_BUS_DISP1,             .value = 0xffffffff, },
        { .offset = GATE_IP_PERIC,              .value = 0xffffffff, },
 };
index 387e3e39e63519d401cbfe87c949308d64db5897..9e04ae2bb4d74912f18976c305a1738756b19837 100644 (file)
@@ -748,7 +748,7 @@ static struct samsung_pll_rate_table exynos5443_pll_rates[] = {
        PLL_35XX_RATE(825000000U,  275, 4,  1),
        PLL_35XX_RATE(800000000U,  400, 6,  1),
        PLL_35XX_RATE(733000000U,  733, 12, 1),
-       PLL_35XX_RATE(700000000U,  360, 6,  1),
+       PLL_35XX_RATE(700000000U,  175, 3,  1),
        PLL_35XX_RATE(667000000U,  222, 4,  1),
        PLL_35XX_RATE(633000000U,  211, 4,  1),
        PLL_35XX_RATE(600000000U,  500, 5,  2),
@@ -760,14 +760,14 @@ static struct samsung_pll_rate_table exynos5443_pll_rates[] = {
        PLL_35XX_RATE(444000000U,  370, 5,  2),
        PLL_35XX_RATE(420000000U,  350, 5,  2),
        PLL_35XX_RATE(400000000U,  400, 6,  2),
-       PLL_35XX_RATE(350000000U,  360, 6,  2),
+       PLL_35XX_RATE(350000000U,  350, 6,  2),
        PLL_35XX_RATE(333000000U,  222, 4,  2),
        PLL_35XX_RATE(300000000U,  500, 5,  3),
        PLL_35XX_RATE(266000000U,  532, 6,  3),
        PLL_35XX_RATE(200000000U,  400, 6,  3),
        PLL_35XX_RATE(166000000U,  332, 6,  3),
        PLL_35XX_RATE(160000000U,  320, 6,  3),
-       PLL_35XX_RATE(133000000U,  552, 6,  4),
+       PLL_35XX_RATE(133000000U,  532, 6,  4),
        PLL_35XX_RATE(100000000U,  400, 6,  4),
        { /* sentinel */ }
 };
@@ -1490,7 +1490,7 @@ static struct samsung_gate_clock mif_gate_clks[] __initdata = {
 
        /* ENABLE_PCLK_MIF_SECURE_MONOTONIC_CNT */
        GATE(CLK_PCLK_MONOTONIC_CNT, "pclk_monotonic_cnt", "div_aclk_mif_133",
-                       ENABLE_PCLK_MIF_SECURE_RTC, 0, 0, 0),
+                       ENABLE_PCLK_MIF_SECURE_MONOTONIC_CNT, 0, 0, 0),
 
        /* ENABLE_PCLK_MIF_SECURE_RTC */
        GATE(CLK_PCLK_RTC, "pclk_rtc", "div_aclk_mif_133",
@@ -3665,7 +3665,7 @@ static struct samsung_gate_clock apollo_gate_clks[] __initdata = {
                        ENABLE_SCLK_APOLLO, 3, CLK_IGNORE_UNUSED, 0),
        GATE(CLK_SCLK_HPM_APOLLO, "sclk_hpm_apollo", "div_sclk_hpm_apollo",
                        ENABLE_SCLK_APOLLO, 1, CLK_IGNORE_UNUSED, 0),
-       GATE(CLK_SCLK_APOLLO, "sclk_apollo", "div_apollo_pll",
+       GATE(CLK_SCLK_APOLLO, "sclk_apollo", "div_apollo2",
                        ENABLE_SCLK_APOLLO, 0, CLK_IGNORE_UNUSED, 0),
 };
 
@@ -3927,7 +3927,7 @@ CLK_OF_DECLARE(exynos5433_cmu_atlas, "samsung,exynos5433-cmu-atlas",
 #define ENABLE_PCLK_MSCL                               0x0900
 #define ENABLE_PCLK_MSCL_SECURE_SMMU_M2MSCALER0                0x0904
 #define ENABLE_PCLK_MSCL_SECURE_SMMU_M2MSCALER1                0x0908
-#define ENABLE_PCLK_MSCL_SECURE_SMMU_JPEG              0x000c
+#define ENABLE_PCLK_MSCL_SECURE_SMMU_JPEG              0x090c
 #define ENABLE_SCLK_MSCL                               0x0a00
 #define ENABLE_IP_MSCL0                                        0x0b00
 #define ENABLE_IP_MSCL1                                        0x0b04
index 7a73a279e179a52b9ea209e00b3f61f797c4d4cb..61c417b9e53f8795175b29d71dfd201f15be151c 100644 (file)
@@ -158,9 +158,18 @@ int cpuidle_enter_state(struct cpuidle_device *dev, struct cpuidle_driver *drv,
        int entered_state;
 
        struct cpuidle_state *target_state = &drv->states[index];
+       bool broadcast = !!(target_state->flags & CPUIDLE_FLAG_TIMER_STOP);
        ktime_t time_start, time_end;
        s64 diff;
 
+       /*
+        * Tell the time framework to switch to a broadcast timer because our
+        * local timer will be shut down.  If a local timer is used from another
+        * CPU as a broadcast timer, this call may fail if it is not available.
+        */
+       if (broadcast && tick_broadcast_enter())
+               return -EBUSY;
+
        trace_cpu_idle_rcuidle(index, dev->cpu);
        time_start = ktime_get();
 
@@ -169,6 +178,13 @@ int cpuidle_enter_state(struct cpuidle_device *dev, struct cpuidle_driver *drv,
        time_end = ktime_get();
        trace_cpu_idle_rcuidle(PWR_EVENT_EXIT, dev->cpu);
 
+       if (broadcast) {
+               if (WARN_ON_ONCE(!irqs_disabled()))
+                       local_irq_disable();
+
+               tick_broadcast_exit();
+       }
+
        if (!cpuidle_state_is_coupled(dev, drv, entered_state))
                local_irq_enable();
 
index fd7ac13f2574ab0aab2ecf0c5f6b38019459da99..bda2cb06dc7a450c6e58e0145edba08acbc6f376 100644 (file)
@@ -437,6 +437,7 @@ config IMG_MDC_DMA
 
 config XGENE_DMA
        tristate "APM X-Gene DMA support"
+       depends on ARCH_XGENE || COMPILE_TEST
        select DMA_ENGINE
        select DMA_ENGINE_RAID
        select ASYNC_TX_ENABLE_CHANNEL_SWITCH
index 933e4b338459284465d7970e3ff7dbf0f37314b8..7992164ea9ec2849f6ac3691629c47cda30aeb28 100644 (file)
 #define AT_XDMAC_MBR_UBC_NDV3          (0x3 << 27)     /* Next Descriptor View 3 */
 
 #define AT_XDMAC_MAX_CHAN      0x20
+#define AT_XDMAC_MAX_CSIZE     16      /* 16 data */
+#define AT_XDMAC_MAX_DWIDTH    8       /* 64 bits */
 
 #define AT_XDMAC_DMA_BUSWIDTHS\
        (BIT(DMA_SLAVE_BUSWIDTH_UNDEFINED) |\
@@ -192,20 +194,17 @@ struct at_xdmac_chan {
        struct dma_chan                 chan;
        void __iomem                    *ch_regs;
        u32                             mask;           /* Channel Mask */
-       u32                             cfg[2];         /* Channel Configuration Register */
-       #define AT_XDMAC_DEV_TO_MEM_CFG 0               /* Predifined dev to mem channel conf */
-       #define AT_XDMAC_MEM_TO_DEV_CFG 1               /* Predifined mem to dev channel conf */
+       u32                             cfg;            /* Channel Configuration Register */
        u8                              perid;          /* Peripheral ID */
        u8                              perif;          /* Peripheral Interface */
        u8                              memif;          /* Memory Interface */
-       u32                             per_src_addr;
-       u32                             per_dst_addr;
        u32                             save_cc;
        u32                             save_cim;
        u32                             save_cnda;
        u32                             save_cndc;
        unsigned long                   status;
        struct tasklet_struct           tasklet;
+       struct dma_slave_config         sconfig;
 
        spinlock_t                      lock;
 
@@ -415,8 +414,9 @@ static dma_cookie_t at_xdmac_tx_submit(struct dma_async_tx_descriptor *tx)
        struct at_xdmac_desc    *desc = txd_to_at_desc(tx);
        struct at_xdmac_chan    *atchan = to_at_xdmac_chan(tx->chan);
        dma_cookie_t            cookie;
+       unsigned long           irqflags;
 
-       spin_lock_bh(&atchan->lock);
+       spin_lock_irqsave(&atchan->lock, irqflags);
        cookie = dma_cookie_assign(tx);
 
        dev_vdbg(chan2dev(tx->chan), "%s: atchan 0x%p, add desc 0x%p to xfers_list\n",
@@ -425,7 +425,7 @@ static dma_cookie_t at_xdmac_tx_submit(struct dma_async_tx_descriptor *tx)
        if (list_is_singular(&atchan->xfers_list))
                at_xdmac_start_xfer(atchan, desc);
 
-       spin_unlock_bh(&atchan->lock);
+       spin_unlock_irqrestore(&atchan->lock, irqflags);
        return cookie;
 }
 
@@ -494,61 +494,94 @@ static struct dma_chan *at_xdmac_xlate(struct of_phandle_args *dma_spec,
        return chan;
 }
 
+static int at_xdmac_compute_chan_conf(struct dma_chan *chan,
+                                     enum dma_transfer_direction direction)
+{
+       struct at_xdmac_chan    *atchan = to_at_xdmac_chan(chan);
+       int                     csize, dwidth;
+
+       if (direction == DMA_DEV_TO_MEM) {
+               atchan->cfg =
+                       AT91_XDMAC_DT_PERID(atchan->perid)
+                       | AT_XDMAC_CC_DAM_INCREMENTED_AM
+                       | AT_XDMAC_CC_SAM_FIXED_AM
+                       | AT_XDMAC_CC_DIF(atchan->memif)
+                       | AT_XDMAC_CC_SIF(atchan->perif)
+                       | AT_XDMAC_CC_SWREQ_HWR_CONNECTED
+                       | AT_XDMAC_CC_DSYNC_PER2MEM
+                       | AT_XDMAC_CC_MBSIZE_SIXTEEN
+                       | AT_XDMAC_CC_TYPE_PER_TRAN;
+               csize = ffs(atchan->sconfig.src_maxburst) - 1;
+               if (csize < 0) {
+                       dev_err(chan2dev(chan), "invalid src maxburst value\n");
+                       return -EINVAL;
+               }
+               atchan->cfg |= AT_XDMAC_CC_CSIZE(csize);
+               dwidth = ffs(atchan->sconfig.src_addr_width) - 1;
+               if (dwidth < 0) {
+                       dev_err(chan2dev(chan), "invalid src addr width value\n");
+                       return -EINVAL;
+               }
+               atchan->cfg |= AT_XDMAC_CC_DWIDTH(dwidth);
+       } else if (direction == DMA_MEM_TO_DEV) {
+               atchan->cfg =
+                       AT91_XDMAC_DT_PERID(atchan->perid)
+                       | AT_XDMAC_CC_DAM_FIXED_AM
+                       | AT_XDMAC_CC_SAM_INCREMENTED_AM
+                       | AT_XDMAC_CC_DIF(atchan->perif)
+                       | AT_XDMAC_CC_SIF(atchan->memif)
+                       | AT_XDMAC_CC_SWREQ_HWR_CONNECTED
+                       | AT_XDMAC_CC_DSYNC_MEM2PER
+                       | AT_XDMAC_CC_MBSIZE_SIXTEEN
+                       | AT_XDMAC_CC_TYPE_PER_TRAN;
+               csize = ffs(atchan->sconfig.dst_maxburst) - 1;
+               if (csize < 0) {
+                       dev_err(chan2dev(chan), "invalid src maxburst value\n");
+                       return -EINVAL;
+               }
+               atchan->cfg |= AT_XDMAC_CC_CSIZE(csize);
+               dwidth = ffs(atchan->sconfig.dst_addr_width) - 1;
+               if (dwidth < 0) {
+                       dev_err(chan2dev(chan), "invalid dst addr width value\n");
+                       return -EINVAL;
+               }
+               atchan->cfg |= AT_XDMAC_CC_DWIDTH(dwidth);
+       }
+
+       dev_dbg(chan2dev(chan), "%s: cfg=0x%08x\n", __func__, atchan->cfg);
+
+       return 0;
+}
+
+/*
+ * Only check that maxburst and addr width values are supported by the
+ * the controller but not that the configuration is good to perform the
+ * transfer since we don't know the direction at this stage.
+ */
+static int at_xdmac_check_slave_config(struct dma_slave_config *sconfig)
+{
+       if ((sconfig->src_maxburst > AT_XDMAC_MAX_CSIZE)
+           || (sconfig->dst_maxburst > AT_XDMAC_MAX_CSIZE))
+               return -EINVAL;
+
+       if ((sconfig->src_addr_width > AT_XDMAC_MAX_DWIDTH)
+           || (sconfig->dst_addr_width > AT_XDMAC_MAX_DWIDTH))
+               return -EINVAL;
+
+       return 0;
+}
+
 static int at_xdmac_set_slave_config(struct dma_chan *chan,
                                      struct dma_slave_config *sconfig)
 {
        struct at_xdmac_chan    *atchan = to_at_xdmac_chan(chan);
-       u8 dwidth;
-       int csize;
 
-       atchan->cfg[AT_XDMAC_DEV_TO_MEM_CFG] =
-               AT91_XDMAC_DT_PERID(atchan->perid)
-               | AT_XDMAC_CC_DAM_INCREMENTED_AM
-               | AT_XDMAC_CC_SAM_FIXED_AM
-               | AT_XDMAC_CC_DIF(atchan->memif)
-               | AT_XDMAC_CC_SIF(atchan->perif)
-               | AT_XDMAC_CC_SWREQ_HWR_CONNECTED
-               | AT_XDMAC_CC_DSYNC_PER2MEM
-               | AT_XDMAC_CC_MBSIZE_SIXTEEN
-               | AT_XDMAC_CC_TYPE_PER_TRAN;
-       csize = at_xdmac_csize(sconfig->src_maxburst);
-       if (csize < 0) {
-               dev_err(chan2dev(chan), "invalid src maxburst value\n");
+       if (at_xdmac_check_slave_config(sconfig)) {
+               dev_err(chan2dev(chan), "invalid slave configuration\n");
                return -EINVAL;
        }
-       atchan->cfg[AT_XDMAC_DEV_TO_MEM_CFG] |= AT_XDMAC_CC_CSIZE(csize);
-       dwidth = ffs(sconfig->src_addr_width) - 1;
-       atchan->cfg[AT_XDMAC_DEV_TO_MEM_CFG] |= AT_XDMAC_CC_DWIDTH(dwidth);
-
-
-       atchan->cfg[AT_XDMAC_MEM_TO_DEV_CFG] =
-               AT91_XDMAC_DT_PERID(atchan->perid)
-               | AT_XDMAC_CC_DAM_FIXED_AM
-               | AT_XDMAC_CC_SAM_INCREMENTED_AM
-               | AT_XDMAC_CC_DIF(atchan->perif)
-               | AT_XDMAC_CC_SIF(atchan->memif)
-               | AT_XDMAC_CC_SWREQ_HWR_CONNECTED
-               | AT_XDMAC_CC_DSYNC_MEM2PER
-               | AT_XDMAC_CC_MBSIZE_SIXTEEN
-               | AT_XDMAC_CC_TYPE_PER_TRAN;
-       csize = at_xdmac_csize(sconfig->dst_maxburst);
-       if (csize < 0) {
-               dev_err(chan2dev(chan), "invalid src maxburst value\n");
-               return -EINVAL;
-       }
-       atchan->cfg[AT_XDMAC_MEM_TO_DEV_CFG] |= AT_XDMAC_CC_CSIZE(csize);
-       dwidth = ffs(sconfig->dst_addr_width) - 1;
-       atchan->cfg[AT_XDMAC_MEM_TO_DEV_CFG] |= AT_XDMAC_CC_DWIDTH(dwidth);
-
-       /* Src and dst addr are needed to configure the link list descriptor. */
-       atchan->per_src_addr = sconfig->src_addr;
-       atchan->per_dst_addr = sconfig->dst_addr;
 
-       dev_dbg(chan2dev(chan),
-               "%s: cfg[dev2mem]=0x%08x, cfg[mem2dev]=0x%08x, per_src_addr=0x%08x, per_dst_addr=0x%08x\n",
-               __func__, atchan->cfg[AT_XDMAC_DEV_TO_MEM_CFG],
-               atchan->cfg[AT_XDMAC_MEM_TO_DEV_CFG],
-               atchan->per_src_addr, atchan->per_dst_addr);
+       memcpy(&atchan->sconfig, sconfig, sizeof(atchan->sconfig));
 
        return 0;
 }
@@ -563,6 +596,8 @@ at_xdmac_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl,
        struct scatterlist      *sg;
        int                     i;
        unsigned int            xfer_size = 0;
+       unsigned long           irqflags;
+       struct dma_async_tx_descriptor  *ret = NULL;
 
        if (!sgl)
                return NULL;
@@ -578,7 +613,10 @@ at_xdmac_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl,
                 flags);
 
        /* Protect dma_sconfig field that can be modified by set_slave_conf. */
-       spin_lock_bh(&atchan->lock);
+       spin_lock_irqsave(&atchan->lock, irqflags);
+
+       if (at_xdmac_compute_chan_conf(chan, direction))
+               goto spin_unlock;
 
        /* Prepare descriptors. */
        for_each_sg(sgl, sg, sg_len, i) {
@@ -589,8 +627,7 @@ at_xdmac_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl,
                mem = sg_dma_address(sg);
                if (unlikely(!len)) {
                        dev_err(chan2dev(chan), "sg data length is zero\n");
-                       spin_unlock_bh(&atchan->lock);
-                       return NULL;
+                       goto spin_unlock;
                }
                dev_dbg(chan2dev(chan), "%s: * sg%d len=%u, mem=0x%08x\n",
                         __func__, i, len, mem);
@@ -600,20 +637,18 @@ at_xdmac_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl,
                        dev_err(chan2dev(chan), "can't get descriptor\n");
                        if (first)
                                list_splice_init(&first->descs_list, &atchan->free_descs_list);
-                       spin_unlock_bh(&atchan->lock);
-                       return NULL;
+                       goto spin_unlock;
                }
 
                /* Linked list descriptor setup. */
                if (direction == DMA_DEV_TO_MEM) {
-                       desc->lld.mbr_sa = atchan->per_src_addr;
+                       desc->lld.mbr_sa = atchan->sconfig.src_addr;
                        desc->lld.mbr_da = mem;
-                       desc->lld.mbr_cfg = atchan->cfg[AT_XDMAC_DEV_TO_MEM_CFG];
                } else {
                        desc->lld.mbr_sa = mem;
-                       desc->lld.mbr_da = atchan->per_dst_addr;
-                       desc->lld.mbr_cfg = atchan->cfg[AT_XDMAC_MEM_TO_DEV_CFG];
+                       desc->lld.mbr_da = atchan->sconfig.dst_addr;
                }
+               desc->lld.mbr_cfg = atchan->cfg;
                dwidth = at_xdmac_get_dwidth(desc->lld.mbr_cfg);
                fixed_dwidth = IS_ALIGNED(len, 1 << dwidth)
                               ? at_xdmac_get_dwidth(desc->lld.mbr_cfg)
@@ -645,13 +680,15 @@ at_xdmac_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl,
                xfer_size += len;
        }
 
-       spin_unlock_bh(&atchan->lock);
 
        first->tx_dma_desc.flags = flags;
        first->xfer_size = xfer_size;
        first->direction = direction;
+       ret = &first->tx_dma_desc;
 
-       return &first->tx_dma_desc;
+spin_unlock:
+       spin_unlock_irqrestore(&atchan->lock, irqflags);
+       return ret;
 }
 
 static struct dma_async_tx_descriptor *
@@ -664,6 +701,7 @@ at_xdmac_prep_dma_cyclic(struct dma_chan *chan, dma_addr_t buf_addr,
        struct at_xdmac_desc    *first = NULL, *prev = NULL;
        unsigned int            periods = buf_len / period_len;
        int                     i;
+       unsigned long           irqflags;
 
        dev_dbg(chan2dev(chan), "%s: buf_addr=%pad, buf_len=%zd, period_len=%zd, dir=%s, flags=0x%lx\n",
                __func__, &buf_addr, buf_len, period_len,
@@ -679,32 +717,34 @@ at_xdmac_prep_dma_cyclic(struct dma_chan *chan, dma_addr_t buf_addr,
                return NULL;
        }
 
+       if (at_xdmac_compute_chan_conf(chan, direction))
+               return NULL;
+
        for (i = 0; i < periods; i++) {
                struct at_xdmac_desc    *desc = NULL;
 
-               spin_lock_bh(&atchan->lock);
+               spin_lock_irqsave(&atchan->lock, irqflags);
                desc = at_xdmac_get_desc(atchan);
                if (!desc) {
                        dev_err(chan2dev(chan), "can't get descriptor\n");
                        if (first)
                                list_splice_init(&first->descs_list, &atchan->free_descs_list);
-                       spin_unlock_bh(&atchan->lock);
+                       spin_unlock_irqrestore(&atchan->lock, irqflags);
                        return NULL;
                }
-               spin_unlock_bh(&atchan->lock);
+               spin_unlock_irqrestore(&atchan->lock, irqflags);
                dev_dbg(chan2dev(chan),
                        "%s: desc=0x%p, tx_dma_desc.phys=%pad\n",
                        __func__, desc, &desc->tx_dma_desc.phys);
 
                if (direction == DMA_DEV_TO_MEM) {
-                       desc->lld.mbr_sa = atchan->per_src_addr;
+                       desc->lld.mbr_sa = atchan->sconfig.src_addr;
                        desc->lld.mbr_da = buf_addr + i * period_len;
-                       desc->lld.mbr_cfg = atchan->cfg[AT_XDMAC_DEV_TO_MEM_CFG];
                } else {
                        desc->lld.mbr_sa = buf_addr + i * period_len;
-                       desc->lld.mbr_da = atchan->per_dst_addr;
-                       desc->lld.mbr_cfg = atchan->cfg[AT_XDMAC_MEM_TO_DEV_CFG];
+                       desc->lld.mbr_da = atchan->sconfig.dst_addr;
                }
+               desc->lld.mbr_cfg = atchan->cfg;
                desc->lld.mbr_ubc = AT_XDMAC_MBR_UBC_NDV1
                        | AT_XDMAC_MBR_UBC_NDEN
                        | AT_XDMAC_MBR_UBC_NSEN
@@ -766,6 +806,7 @@ at_xdmac_prep_dma_memcpy(struct dma_chan *chan, dma_addr_t dest, dma_addr_t src,
                                        | AT_XDMAC_CC_SIF(0)
                                        | AT_XDMAC_CC_MBSIZE_SIXTEEN
                                        | AT_XDMAC_CC_TYPE_MEM_TRAN;
+       unsigned long           irqflags;
 
        dev_dbg(chan2dev(chan), "%s: src=%pad, dest=%pad, len=%zd, flags=0x%lx\n",
                __func__, &src, &dest, len, flags);
@@ -798,9 +839,9 @@ at_xdmac_prep_dma_memcpy(struct dma_chan *chan, dma_addr_t dest, dma_addr_t src,
 
                dev_dbg(chan2dev(chan), "%s: remaining_size=%zu\n", __func__, remaining_size);
 
-               spin_lock_bh(&atchan->lock);
+               spin_lock_irqsave(&atchan->lock, irqflags);
                desc = at_xdmac_get_desc(atchan);
-               spin_unlock_bh(&atchan->lock);
+               spin_unlock_irqrestore(&atchan->lock, irqflags);
                if (!desc) {
                        dev_err(chan2dev(chan), "can't get descriptor\n");
                        if (first)
@@ -886,6 +927,7 @@ at_xdmac_tx_status(struct dma_chan *chan, dma_cookie_t cookie,
        int                     residue;
        u32                     cur_nda, mask, value;
        u8                      dwidth = 0;
+       unsigned long           flags;
 
        ret = dma_cookie_status(chan, cookie, txstate);
        if (ret == DMA_COMPLETE)
@@ -894,7 +936,7 @@ at_xdmac_tx_status(struct dma_chan *chan, dma_cookie_t cookie,
        if (!txstate)
                return ret;
 
-       spin_lock_bh(&atchan->lock);
+       spin_lock_irqsave(&atchan->lock, flags);
 
        desc = list_first_entry(&atchan->xfers_list, struct at_xdmac_desc, xfer_node);
 
@@ -904,8 +946,7 @@ at_xdmac_tx_status(struct dma_chan *chan, dma_cookie_t cookie,
         */
        if (!desc->active_xfer) {
                dma_set_residue(txstate, desc->xfer_size);
-               spin_unlock_bh(&atchan->lock);
-               return ret;
+               goto spin_unlock;
        }
 
        residue = desc->xfer_size;
@@ -936,14 +977,14 @@ at_xdmac_tx_status(struct dma_chan *chan, dma_cookie_t cookie,
        }
        residue += at_xdmac_chan_read(atchan, AT_XDMAC_CUBC) << dwidth;
 
-       spin_unlock_bh(&atchan->lock);
-
        dma_set_residue(txstate, residue);
 
        dev_dbg(chan2dev(chan),
                 "%s: desc=0x%p, tx_dma_desc.phys=%pad, tx_status=%d, cookie=%d, residue=%d\n",
                 __func__, desc, &desc->tx_dma_desc.phys, ret, cookie, residue);
 
+spin_unlock:
+       spin_unlock_irqrestore(&atchan->lock, flags);
        return ret;
 }
 
@@ -964,8 +1005,9 @@ static void at_xdmac_remove_xfer(struct at_xdmac_chan *atchan,
 static void at_xdmac_advance_work(struct at_xdmac_chan *atchan)
 {
        struct at_xdmac_desc    *desc;
+       unsigned long           flags;
 
-       spin_lock_bh(&atchan->lock);
+       spin_lock_irqsave(&atchan->lock, flags);
 
        /*
         * If channel is enabled, do nothing, advance_work will be triggered
@@ -980,7 +1022,7 @@ static void at_xdmac_advance_work(struct at_xdmac_chan *atchan)
                        at_xdmac_start_xfer(atchan, desc);
        }
 
-       spin_unlock_bh(&atchan->lock);
+       spin_unlock_irqrestore(&atchan->lock, flags);
 }
 
 static void at_xdmac_handle_cyclic(struct at_xdmac_chan *atchan)
@@ -1116,12 +1158,13 @@ static int at_xdmac_device_config(struct dma_chan *chan,
 {
        struct at_xdmac_chan    *atchan = to_at_xdmac_chan(chan);
        int ret;
+       unsigned long           flags;
 
        dev_dbg(chan2dev(chan), "%s\n", __func__);
 
-       spin_lock_bh(&atchan->lock);
+       spin_lock_irqsave(&atchan->lock, flags);
        ret = at_xdmac_set_slave_config(chan, config);
-       spin_unlock_bh(&atchan->lock);
+       spin_unlock_irqrestore(&atchan->lock, flags);
 
        return ret;
 }
@@ -1130,18 +1173,19 @@ static int at_xdmac_device_pause(struct dma_chan *chan)
 {
        struct at_xdmac_chan    *atchan = to_at_xdmac_chan(chan);
        struct at_xdmac         *atxdmac = to_at_xdmac(atchan->chan.device);
+       unsigned long           flags;
 
        dev_dbg(chan2dev(chan), "%s\n", __func__);
 
        if (test_and_set_bit(AT_XDMAC_CHAN_IS_PAUSED, &atchan->status))
                return 0;
 
-       spin_lock_bh(&atchan->lock);
+       spin_lock_irqsave(&atchan->lock, flags);
        at_xdmac_write(atxdmac, AT_XDMAC_GRWS, atchan->mask);
        while (at_xdmac_chan_read(atchan, AT_XDMAC_CC)
               & (AT_XDMAC_CC_WRIP | AT_XDMAC_CC_RDIP))
                cpu_relax();
-       spin_unlock_bh(&atchan->lock);
+       spin_unlock_irqrestore(&atchan->lock, flags);
 
        return 0;
 }
@@ -1150,18 +1194,19 @@ static int at_xdmac_device_resume(struct dma_chan *chan)
 {
        struct at_xdmac_chan    *atchan = to_at_xdmac_chan(chan);
        struct at_xdmac         *atxdmac = to_at_xdmac(atchan->chan.device);
+       unsigned long           flags;
 
        dev_dbg(chan2dev(chan), "%s\n", __func__);
 
-       spin_lock_bh(&atchan->lock);
+       spin_lock_irqsave(&atchan->lock, flags);
        if (!at_xdmac_chan_is_paused(atchan)) {
-               spin_unlock_bh(&atchan->lock);
+               spin_unlock_irqrestore(&atchan->lock, flags);
                return 0;
        }
 
        at_xdmac_write(atxdmac, AT_XDMAC_GRWR, atchan->mask);
        clear_bit(AT_XDMAC_CHAN_IS_PAUSED, &atchan->status);
-       spin_unlock_bh(&atchan->lock);
+       spin_unlock_irqrestore(&atchan->lock, flags);
 
        return 0;
 }
@@ -1171,10 +1216,11 @@ static int at_xdmac_device_terminate_all(struct dma_chan *chan)
        struct at_xdmac_desc    *desc, *_desc;
        struct at_xdmac_chan    *atchan = to_at_xdmac_chan(chan);
        struct at_xdmac         *atxdmac = to_at_xdmac(atchan->chan.device);
+       unsigned long           flags;
 
        dev_dbg(chan2dev(chan), "%s\n", __func__);
 
-       spin_lock_bh(&atchan->lock);
+       spin_lock_irqsave(&atchan->lock, flags);
        at_xdmac_write(atxdmac, AT_XDMAC_GD, atchan->mask);
        while (at_xdmac_read(atxdmac, AT_XDMAC_GS) & atchan->mask)
                cpu_relax();
@@ -1184,7 +1230,7 @@ static int at_xdmac_device_terminate_all(struct dma_chan *chan)
                at_xdmac_remove_xfer(atchan, desc);
 
        clear_bit(AT_XDMAC_CHAN_IS_CYCLIC, &atchan->status);
-       spin_unlock_bh(&atchan->lock);
+       spin_unlock_irqrestore(&atchan->lock, flags);
 
        return 0;
 }
@@ -1194,8 +1240,9 @@ static int at_xdmac_alloc_chan_resources(struct dma_chan *chan)
        struct at_xdmac_chan    *atchan = to_at_xdmac_chan(chan);
        struct at_xdmac_desc    *desc;
        int                     i;
+       unsigned long           flags;
 
-       spin_lock_bh(&atchan->lock);
+       spin_lock_irqsave(&atchan->lock, flags);
 
        if (at_xdmac_chan_is_enabled(atchan)) {
                dev_err(chan2dev(chan),
@@ -1226,7 +1273,7 @@ static int at_xdmac_alloc_chan_resources(struct dma_chan *chan)
        dev_dbg(chan2dev(chan), "%s: allocated %d descriptors\n", __func__, i);
 
 spin_unlock:
-       spin_unlock_bh(&atchan->lock);
+       spin_unlock_irqrestore(&atchan->lock, flags);
        return i;
 }
 
index 0e035a8cf40146ccf191d3e26418dc04ed7da0b8..3ddfd1f6c23c0f0f891ed11d6f68cbcaaa3c6e03 100644 (file)
@@ -487,7 +487,11 @@ int dma_get_slave_caps(struct dma_chan *chan, struct dma_slave_caps *caps)
        caps->directions = device->directions;
        caps->residue_granularity = device->residue_granularity;
 
-       caps->cmd_pause = !!device->device_pause;
+       /*
+        * Some devices implement only pause (e.g. to get residuum) but no
+        * resume. However cmd_pause is advertised as pause AND resume.
+        */
+       caps->cmd_pause = !!(device->device_pause && device->device_resume);
        caps->cmd_terminate = !!device->device_terminate_all;
 
        return 0;
@@ -571,11 +575,15 @@ struct dma_chan *dma_get_any_slave_channel(struct dma_device *device)
 
        chan = private_candidate(&mask, device, NULL, NULL);
        if (chan) {
+               dma_cap_set(DMA_PRIVATE, device->cap_mask);
+               device->privatecnt++;
                err = dma_chan_get(chan);
                if (err) {
                        pr_debug("%s: failed to get %s: (%d)\n",
                                __func__, dma_chan_name(chan), err);
                        chan = NULL;
+                       if (--device->privatecnt == 0)
+                               dma_cap_clear(DMA_PRIVATE, device->cap_mask);
                }
        }
 
index 9b84def7a35373a45cf18efc9d53939bcc86baf0..f42f71e37e73767a55078aef4c81bcd238b02db1 100644 (file)
@@ -384,7 +384,10 @@ static int hsu_dma_terminate_all(struct dma_chan *chan)
        spin_lock_irqsave(&hsuc->vchan.lock, flags);
 
        hsu_dma_stop_channel(hsuc);
-       hsuc->desc = NULL;
+       if (hsuc->desc) {
+               hsu_dma_desc_free(&hsuc->desc->vdesc);
+               hsuc->desc = NULL;
+       }
 
        vchan_get_all_descriptors(&hsuc->vchan, &head);
        spin_unlock_irqrestore(&hsuc->vchan.lock, flags);
index a7d9d3029b145dfa29babeee33022bc1f7354d52..340f9e607cd8b90dfe75add027c18bd26d67f1e0 100644 (file)
@@ -2127,6 +2127,7 @@ static int pl330_terminate_all(struct dma_chan *chan)
        struct pl330_dmac *pl330 = pch->dmac;
        LIST_HEAD(list);
 
+       pm_runtime_get_sync(pl330->ddma.dev);
        spin_lock_irqsave(&pch->lock, flags);
        spin_lock(&pl330->lock);
        _stop(pch->thread);
@@ -2151,6 +2152,8 @@ static int pl330_terminate_all(struct dma_chan *chan)
        list_splice_tail_init(&pch->work_list, &pl330->desc_pool);
        list_splice_tail_init(&pch->completed_list, &pl330->desc_pool);
        spin_unlock_irqrestore(&pch->lock, flags);
+       pm_runtime_mark_last_busy(pl330->ddma.dev);
+       pm_runtime_put_autosuspend(pl330->ddma.dev);
 
        return 0;
 }
index a18d16cc479559e2ca7719eebe8755c7a64d242b..e0302c784ba48039d411c75fb1a40451107fc5ab 100644 (file)
@@ -465,6 +465,7 @@ static dma_cookie_t rcar_dmac_tx_submit(struct dma_async_tx_descriptor *tx)
 static int rcar_dmac_desc_alloc(struct rcar_dmac_chan *chan, gfp_t gfp)
 {
        struct rcar_dmac_desc_page *page;
+       unsigned long flags;
        LIST_HEAD(list);
        unsigned int i;
 
@@ -482,10 +483,10 @@ static int rcar_dmac_desc_alloc(struct rcar_dmac_chan *chan, gfp_t gfp)
                list_add_tail(&desc->node, &list);
        }
 
-       spin_lock_irq(&chan->lock);
+       spin_lock_irqsave(&chan->lock, flags);
        list_splice_tail(&list, &chan->desc.free);
        list_add_tail(&page->node, &chan->desc.pages);
-       spin_unlock_irq(&chan->lock);
+       spin_unlock_irqrestore(&chan->lock, flags);
 
        return 0;
 }
@@ -516,6 +517,7 @@ static void rcar_dmac_desc_put(struct rcar_dmac_chan *chan,
 static void rcar_dmac_desc_recycle_acked(struct rcar_dmac_chan *chan)
 {
        struct rcar_dmac_desc *desc, *_desc;
+       unsigned long flags;
        LIST_HEAD(list);
 
        /*
@@ -524,9 +526,9 @@ static void rcar_dmac_desc_recycle_acked(struct rcar_dmac_chan *chan)
         * list_for_each_entry_safe, isn't safe if we release the channel lock
         * around the rcar_dmac_desc_put() call.
         */
-       spin_lock_irq(&chan->lock);
+       spin_lock_irqsave(&chan->lock, flags);
        list_splice_init(&chan->desc.wait, &list);
-       spin_unlock_irq(&chan->lock);
+       spin_unlock_irqrestore(&chan->lock, flags);
 
        list_for_each_entry_safe(desc, _desc, &list, node) {
                if (async_tx_test_ack(&desc->async_tx)) {
@@ -539,9 +541,9 @@ static void rcar_dmac_desc_recycle_acked(struct rcar_dmac_chan *chan)
                return;
 
        /* Put the remaining descriptors back in the wait list. */
-       spin_lock_irq(&chan->lock);
+       spin_lock_irqsave(&chan->lock, flags);
        list_splice(&list, &chan->desc.wait);
-       spin_unlock_irq(&chan->lock);
+       spin_unlock_irqrestore(&chan->lock, flags);
 }
 
 /*
@@ -556,12 +558,13 @@ static void rcar_dmac_desc_recycle_acked(struct rcar_dmac_chan *chan)
 static struct rcar_dmac_desc *rcar_dmac_desc_get(struct rcar_dmac_chan *chan)
 {
        struct rcar_dmac_desc *desc;
+       unsigned long flags;
        int ret;
 
        /* Recycle acked descriptors before attempting allocation. */
        rcar_dmac_desc_recycle_acked(chan);
 
-       spin_lock_irq(&chan->lock);
+       spin_lock_irqsave(&chan->lock, flags);
 
        while (list_empty(&chan->desc.free)) {
                /*
@@ -570,17 +573,17 @@ static struct rcar_dmac_desc *rcar_dmac_desc_get(struct rcar_dmac_chan *chan)
                 * allocated descriptors. If the allocation fails return an
                 * error.
                 */
-               spin_unlock_irq(&chan->lock);
+               spin_unlock_irqrestore(&chan->lock, flags);
                ret = rcar_dmac_desc_alloc(chan, GFP_NOWAIT);
                if (ret < 0)
                        return NULL;
-               spin_lock_irq(&chan->lock);
+               spin_lock_irqsave(&chan->lock, flags);
        }
 
        desc = list_first_entry(&chan->desc.free, struct rcar_dmac_desc, node);
        list_del(&desc->node);
 
-       spin_unlock_irq(&chan->lock);
+       spin_unlock_irqrestore(&chan->lock, flags);
 
        return desc;
 }
@@ -593,6 +596,7 @@ static struct rcar_dmac_desc *rcar_dmac_desc_get(struct rcar_dmac_chan *chan)
 static int rcar_dmac_xfer_chunk_alloc(struct rcar_dmac_chan *chan, gfp_t gfp)
 {
        struct rcar_dmac_desc_page *page;
+       unsigned long flags;
        LIST_HEAD(list);
        unsigned int i;
 
@@ -606,10 +610,10 @@ static int rcar_dmac_xfer_chunk_alloc(struct rcar_dmac_chan *chan, gfp_t gfp)
                list_add_tail(&chunk->node, &list);
        }
 
-       spin_lock_irq(&chan->lock);
+       spin_lock_irqsave(&chan->lock, flags);
        list_splice_tail(&list, &chan->desc.chunks_free);
        list_add_tail(&page->node, &chan->desc.pages);
-       spin_unlock_irq(&chan->lock);
+       spin_unlock_irqrestore(&chan->lock, flags);
 
        return 0;
 }
@@ -627,9 +631,10 @@ static struct rcar_dmac_xfer_chunk *
 rcar_dmac_xfer_chunk_get(struct rcar_dmac_chan *chan)
 {
        struct rcar_dmac_xfer_chunk *chunk;
+       unsigned long flags;
        int ret;
 
-       spin_lock_irq(&chan->lock);
+       spin_lock_irqsave(&chan->lock, flags);
 
        while (list_empty(&chan->desc.chunks_free)) {
                /*
@@ -638,18 +643,18 @@ rcar_dmac_xfer_chunk_get(struct rcar_dmac_chan *chan)
                 * allocated descriptors. If the allocation fails return an
                 * error.
                 */
-               spin_unlock_irq(&chan->lock);
+               spin_unlock_irqrestore(&chan->lock, flags);
                ret = rcar_dmac_xfer_chunk_alloc(chan, GFP_NOWAIT);
                if (ret < 0)
                        return NULL;
-               spin_lock_irq(&chan->lock);
+               spin_lock_irqsave(&chan->lock, flags);
        }
 
        chunk = list_first_entry(&chan->desc.chunks_free,
                                 struct rcar_dmac_xfer_chunk, node);
        list_del(&chunk->node);
 
-       spin_unlock_irq(&chan->lock);
+       spin_unlock_irqrestore(&chan->lock, flags);
 
        return chunk;
 }
index f705798ce3eb1129151a2d5472067b845f947781..ebd8a5f398b08ee2bc883ccb06a7752657eb4877 100644 (file)
@@ -673,6 +673,7 @@ static struct dma_chan *usb_dmac_of_xlate(struct of_phandle_args *dma_spec,
  * Power management
  */
 
+#ifdef CONFIG_PM
 static int usb_dmac_runtime_suspend(struct device *dev)
 {
        struct usb_dmac *dmac = dev_get_drvdata(dev);
@@ -690,6 +691,7 @@ static int usb_dmac_runtime_resume(struct device *dev)
 
        return usb_dmac_init(dmac);
 }
+#endif /* CONFIG_PM */
 
 static const struct dev_pm_ops usb_dmac_pm = {
        SET_RUNTIME_PM_OPS(usb_dmac_runtime_suspend, usb_dmac_runtime_resume,
index de67fce189840eee2d75ad42e23f862103d7540b..e45d1f13f4458e9130d8f052494b33b1a11a9c60 100644 (file)
@@ -119,6 +119,18 @@ static int usb_extcon_probe(struct platform_device *pdev)
                return PTR_ERR(info->id_gpiod);
        }
 
+       info->edev = devm_extcon_dev_allocate(dev, usb_extcon_cable);
+       if (IS_ERR(info->edev)) {
+               dev_err(dev, "failed to allocate extcon device\n");
+               return -ENOMEM;
+       }
+
+       ret = devm_extcon_dev_register(dev, info->edev);
+       if (ret < 0) {
+               dev_err(dev, "failed to register extcon device\n");
+               return ret;
+       }
+
        ret = gpiod_set_debounce(info->id_gpiod,
                                 USB_GPIO_DEBOUNCE_MS * 1000);
        if (ret < 0)
@@ -142,18 +154,6 @@ static int usb_extcon_probe(struct platform_device *pdev)
                return ret;
        }
 
-       info->edev = devm_extcon_dev_allocate(dev, usb_extcon_cable);
-       if (IS_ERR(info->edev)) {
-               dev_err(dev, "failed to allocate extcon device\n");
-               return -ENOMEM;
-       }
-
-       ret = devm_extcon_dev_register(dev, info->edev);
-       if (ret < 0) {
-               dev_err(dev, "failed to register extcon device\n");
-               return ret;
-       }
-
        platform_set_drvdata(pdev, info);
        device_init_wakeup(dev, 1);
 
index 6e45a43ffe8476686bcaee1157a7acc641fc3e6b..97b1616aa391819c0579d12efcca286cfa1c7075 100644 (file)
@@ -499,19 +499,19 @@ static int __init dmi_present(const u8 *buf)
        buf += 16;
 
        if (memcmp(buf, "_DMI_", 5) == 0 && dmi_checksum(buf, 15)) {
+               if (smbios_ver)
+                       dmi_ver = smbios_ver;
+               else
+                       dmi_ver = (buf[14] & 0xF0) << 4 | (buf[14] & 0x0F);
                dmi_num = get_unaligned_le16(buf + 12);
                dmi_len = get_unaligned_le16(buf + 6);
                dmi_base = get_unaligned_le32(buf + 8);
 
                if (dmi_walk_early(dmi_decode) == 0) {
                        if (smbios_ver) {
-                               dmi_ver = smbios_ver;
-                               pr_info("SMBIOS %d.%d%s present.\n",
-                                       dmi_ver >> 8, dmi_ver & 0xFF,
-                                       (dmi_ver < 0x0300) ? "" : ".x");
+                               pr_info("SMBIOS %d.%d present.\n",
+                                      dmi_ver >> 8, dmi_ver & 0xFF);
                        } else {
-                               dmi_ver = (buf[14] & 0xF0) << 4 |
-                                          (buf[14] & 0x0F);
                                pr_info("Legacy DMI %d.%d present.\n",
                                       dmi_ver >> 8, dmi_ver & 0xFF);
                        }
index 87b8e3b900d2195bc44ae471003db4ad610b7d77..5c55227a34c8fd8ba0b95a6babfb28e4726da8fe 100644 (file)
@@ -120,7 +120,8 @@ add_sysfs_runtime_map_entry(struct kobject *kobj, int nr)
        entry = kzalloc(sizeof(*entry), GFP_KERNEL);
        if (!entry) {
                kset_unregister(map_kset);
-               return entry;
+               map_kset = NULL;
+               return ERR_PTR(-ENOMEM);
        }
 
        memcpy(&entry->md, efi_runtime_map + nr * efi_memdesc_size,
@@ -132,6 +133,7 @@ add_sysfs_runtime_map_entry(struct kobject *kobj, int nr)
        if (ret) {
                kobject_put(&entry->kobj);
                kset_unregister(map_kset);
+               map_kset = NULL;
                return ERR_PTR(ret);
        }
 
@@ -195,8 +197,6 @@ out_add_entry:
                entry = *(map_entries + j);
                kobject_put(&entry->kobj);
        }
-       if (map_kset)
-               kset_unregister(map_kset);
 out:
        return ret;
 }
index 071c2c969eec06ad929ecfb871c614297a615e9e..72791232e46ba44ff474cf7dadff5ccb433d7348 100644 (file)
@@ -186,8 +186,20 @@ struct ibft_kobject {
 
 static struct iscsi_boot_kset *boot_kset;
 
+/* fully null address */
 static const char nulls[16];
 
+/* IPv4-mapped IPv6 ::ffff:0.0.0.0 */
+static const char mapped_nulls[16] = { 0x00, 0x00, 0x00, 0x00,
+                                       0x00, 0x00, 0x00, 0x00,
+                                       0x00, 0x00, 0xff, 0xff,
+                                       0x00, 0x00, 0x00, 0x00 };
+
+static int address_not_null(u8 *ip)
+{
+       return (memcmp(ip, nulls, 16) && memcmp(ip, mapped_nulls, 16));
+}
+
 /*
  * Helper functions to parse data properly.
  */
@@ -445,7 +457,7 @@ static umode_t ibft_check_nic_for(void *data, int type)
                rc = S_IRUGO;
                break;
        case ISCSI_BOOT_ETH_IP_ADDR:
-               if (memcmp(nic->ip_addr, nulls, sizeof(nic->ip_addr)))
+               if (address_not_null(nic->ip_addr))
                        rc = S_IRUGO;
                break;
        case ISCSI_BOOT_ETH_SUBNET_MASK:
@@ -456,21 +468,19 @@ static umode_t ibft_check_nic_for(void *data, int type)
                rc = S_IRUGO;
                break;
        case ISCSI_BOOT_ETH_GATEWAY:
-               if (memcmp(nic->gateway, nulls, sizeof(nic->gateway)))
+               if (address_not_null(nic->gateway))
                        rc = S_IRUGO;
                break;
        case ISCSI_BOOT_ETH_PRIMARY_DNS:
-               if (memcmp(nic->primary_dns, nulls,
-                          sizeof(nic->primary_dns)))
+               if (address_not_null(nic->primary_dns))
                        rc = S_IRUGO;
                break;
        case ISCSI_BOOT_ETH_SECONDARY_DNS:
-               if (memcmp(nic->secondary_dns, nulls,
-                          sizeof(nic->secondary_dns)))
+               if (address_not_null(nic->secondary_dns))
                        rc = S_IRUGO;
                break;
        case ISCSI_BOOT_ETH_DHCP:
-               if (memcmp(nic->dhcp, nulls, sizeof(nic->dhcp)))
+               if (address_not_null(nic->dhcp))
                        rc = S_IRUGO;
                break;
        case ISCSI_BOOT_ETH_VLAN:
@@ -536,23 +546,19 @@ static umode_t __init ibft_check_initiator_for(void *data, int type)
                rc = S_IRUGO;
                break;
        case ISCSI_BOOT_INI_ISNS_SERVER:
-               if (memcmp(init->isns_server, nulls,
-                          sizeof(init->isns_server)))
+               if (address_not_null(init->isns_server))
                        rc = S_IRUGO;
                break;
        case ISCSI_BOOT_INI_SLP_SERVER:
-               if (memcmp(init->slp_server, nulls,
-                          sizeof(init->slp_server)))
+               if (address_not_null(init->slp_server))
                        rc = S_IRUGO;
                break;
        case ISCSI_BOOT_INI_PRI_RADIUS_SERVER:
-               if (memcmp(init->pri_radius_server, nulls,
-                          sizeof(init->pri_radius_server)))
+               if (address_not_null(init->pri_radius_server))
                        rc = S_IRUGO;
                break;
        case ISCSI_BOOT_INI_SEC_RADIUS_SERVER:
-               if (memcmp(init->sec_radius_server, nulls,
-                          sizeof(init->sec_radius_server)))
+               if (address_not_null(init->sec_radius_server))
                        rc = S_IRUGO;
                break;
        case ISCSI_BOOT_INI_INITIATOR_NAME:
index 6b8115f342085bb3b25f78ad8c13ed6ce10a9d7b..83f281dda1e0f41fc4be3c8d2cb4e02407ab837d 100644 (file)
@@ -117,7 +117,7 @@ static int kempld_gpio_get_direction(struct gpio_chip *chip, unsigned offset)
                = container_of(chip, struct kempld_gpio_data, chip);
        struct kempld_device_data *pld = gpio->pld;
 
-       return kempld_gpio_get_bit(pld, KEMPLD_GPIO_DIR_NUM(offset), offset);
+       return !kempld_gpio_get_bit(pld, KEMPLD_GPIO_DIR_NUM(offset), offset);
 }
 
 static int kempld_gpio_pincount(struct kempld_device_data *pld)
index cd1d5bf48f36e8a490e6a99fbafdf98c4b2abadf..b232397ad7ec1599ffda494f73fdc02fe8e83875 100644 (file)
@@ -1054,38 +1054,8 @@ static void omap_gpio_mod_init(struct gpio_bank *bank)
                dev_err(bank->dev, "Could not get gpio dbck\n");
 }
 
-static void
-omap_mpuio_alloc_gc(struct gpio_bank *bank, unsigned int irq_start,
-                   unsigned int num)
-{
-       struct irq_chip_generic *gc;
-       struct irq_chip_type *ct;
-
-       gc = irq_alloc_generic_chip("MPUIO", 1, irq_start, bank->base,
-                                   handle_simple_irq);
-       if (!gc) {
-               dev_err(bank->dev, "Memory alloc failed for gc\n");
-               return;
-       }
-
-       ct = gc->chip_types;
-
-       /* NOTE: No ack required, reading IRQ status clears it. */
-       ct->chip.irq_mask = irq_gc_mask_set_bit;
-       ct->chip.irq_unmask = irq_gc_mask_clr_bit;
-       ct->chip.irq_set_type = omap_gpio_irq_type;
-
-       if (bank->regs->wkup_en)
-               ct->chip.irq_set_wake = omap_gpio_wake_enable;
-
-       ct->regs.mask = OMAP_MPUIO_GPIO_INT / bank->stride;
-       irq_setup_generic_chip(gc, IRQ_MSK(num), IRQ_GC_INIT_MASK_CACHE,
-                              IRQ_NOREQUEST | IRQ_NOPROBE, 0);
-}
-
 static int omap_gpio_chip_init(struct gpio_bank *bank, struct irq_chip *irqc)
 {
-       int j;
        static int gpio;
        int irq_base = 0;
        int ret;
@@ -1132,6 +1102,15 @@ static int omap_gpio_chip_init(struct gpio_bank *bank, struct irq_chip *irqc)
        }
 #endif
 
+       /* MPUIO is a bit different, reading IRQ status clears it */
+       if (bank->is_mpuio) {
+               irqc->irq_ack = dummy_irq_chip.irq_ack;
+               irqc->irq_mask = irq_gc_mask_set_bit;
+               irqc->irq_unmask = irq_gc_mask_clr_bit;
+               if (!bank->regs->wkup_en)
+                       irqc->irq_set_wake = NULL;
+       }
+
        ret = gpiochip_irqchip_add(&bank->chip, irqc,
                                   irq_base, omap_gpio_irq_handler,
                                   IRQ_TYPE_NONE);
@@ -1145,15 +1124,6 @@ static int omap_gpio_chip_init(struct gpio_bank *bank, struct irq_chip *irqc)
        gpiochip_set_chained_irqchip(&bank->chip, irqc,
                                     bank->irq, omap_gpio_irq_handler);
 
-       for (j = 0; j < bank->width; j++) {
-               int irq = irq_find_mapping(bank->chip.irqdomain, j);
-               if (bank->is_mpuio) {
-                       omap_mpuio_alloc_gc(bank, irq, bank->width);
-                       irq_set_chip_and_handler(irq, NULL, NULL);
-                       set_irq_flags(irq, 0);
-               }
-       }
-
        return 0;
 }
 
index d2303d50f56141c527c9d8b82c956c6c8169e239..725d16138b740e27a39d151ec5f7bfdedb9a969b 100644 (file)
@@ -550,7 +550,7 @@ acpi_gpio_adr_space_handler(u32 function, acpi_physical_address address,
 
        length = min(agpio->pin_table_length, (u16)(pin_index + bits));
        for (i = pin_index; i < length; ++i) {
-               unsigned pin = agpio->pin_table[i];
+               int pin = agpio->pin_table[i];
                struct acpi_gpio_connection *conn;
                struct gpio_desc *desc;
                bool found;
index 7722ed53bd651faae15692621d099551ef9bf308..af3bc7a8033bdcbaa2e93602bb107fbe12968d35 100644 (file)
@@ -551,6 +551,7 @@ static struct class gpio_class = {
  */
 int gpiod_export(struct gpio_desc *desc, bool direction_may_change)
 {
+       struct gpio_chip        *chip;
        unsigned long           flags;
        int                     status;
        const char              *ioname = NULL;
@@ -568,8 +569,16 @@ int gpiod_export(struct gpio_desc *desc, bool direction_may_change)
                return -EINVAL;
        }
 
+       chip = desc->chip;
+
        mutex_lock(&sysfs_lock);
 
+       /* check if chip is being removed */
+       if (!chip || !chip->exported) {
+               status = -ENODEV;
+               goto fail_unlock;
+       }
+
        spin_lock_irqsave(&gpio_lock, flags);
        if (!test_bit(FLAG_REQUESTED, &desc->flags) ||
             test_bit(FLAG_EXPORT, &desc->flags)) {
@@ -783,12 +792,15 @@ void gpiochip_unexport(struct gpio_chip *chip)
 {
        int                     status;
        struct device           *dev;
+       struct gpio_desc *desc;
+       unsigned int i;
 
        mutex_lock(&sysfs_lock);
        dev = class_find_device(&gpio_class, NULL, chip, match_export);
        if (dev) {
                put_device(dev);
                device_unregister(dev);
+               /* prevent further gpiod exports */
                chip->exported = false;
                status = 0;
        } else
@@ -797,6 +809,13 @@ void gpiochip_unexport(struct gpio_chip *chip)
 
        if (status)
                chip_dbg(chip, "%s: status %d\n", __func__, status);
+
+       /* unregister gpiod class devices owned by sysfs */
+       for (i = 0; i < chip->ngpio; i++) {
+               desc = &chip->desc[i];
+               if (test_and_clear_bit(FLAG_SYSFS, &desc->flags))
+                       gpiod_free(desc);
+       }
 }
 
 static int __init gpiolib_sysfs_init(void)
index 59eaa23767d8dca5bddf740fa90a24c9699c4a0b..6bc612b8a49fcf859261173e00d0e7389d7d2b05 100644 (file)
@@ -53,6 +53,11 @@ static DEFINE_MUTEX(gpio_lookup_lock);
 static LIST_HEAD(gpio_lookup_list);
 LIST_HEAD(gpio_chips);
 
+
+static void gpiochip_free_hogs(struct gpio_chip *chip);
+static void gpiochip_irqchip_remove(struct gpio_chip *gpiochip);
+
+
 static inline void desc_set_label(struct gpio_desc *d, const char *label)
 {
        d->label = label;
@@ -297,6 +302,7 @@ int gpiochip_add(struct gpio_chip *chip)
 
 err_remove_chip:
        acpi_gpiochip_remove(chip);
+       gpiochip_free_hogs(chip);
        of_gpiochip_remove(chip);
        spin_lock_irqsave(&gpio_lock, flags);
        list_del(&chip->list);
@@ -313,10 +319,6 @@ err_free_descs:
 }
 EXPORT_SYMBOL_GPL(gpiochip_add);
 
-/* Forward-declaration */
-static void gpiochip_irqchip_remove(struct gpio_chip *gpiochip);
-static void gpiochip_free_hogs(struct gpio_chip *chip);
-
 /**
  * gpiochip_remove() - unregister a gpio_chip
  * @chip: the chip to unregister
index 69af73f153103075f00c9344f836bd7eb3b24668..596ee5cd3b842df597c57ee890d16a97ec8cc9ae 100644 (file)
@@ -430,9 +430,10 @@ static int unregister_process_nocpsch(struct device_queue_manager *dqm,
 
        BUG_ON(!dqm || !qpd);
 
-       BUG_ON(!list_empty(&qpd->queues_list));
+       pr_debug("In func %s\n", __func__);
 
-       pr_debug("kfd: In func %s\n", __func__);
+       pr_debug("qpd->queues_list is %s\n",
+                       list_empty(&qpd->queues_list) ? "empty" : "not empty");
 
        retval = 0;
        mutex_lock(&dqm->lock);
@@ -882,6 +883,8 @@ static int create_queue_cpsch(struct device_queue_manager *dqm, struct queue *q,
                return -ENOMEM;
        }
 
+       init_sdma_vm(dqm, q, qpd);
+
        retval = mqd->init_mqd(mqd, &q->mqd, &q->mqd_mem_obj,
                                &q->gart_mqd_addr, &q->properties);
        if (retval != 0)
index 661c6605d31b39033a42a5d4297e1684ed734011..c25728bc388a2be7134cb3e6b895a7a39d4189a2 100644 (file)
@@ -684,8 +684,6 @@ static ssize_t node_show(struct kobject *kobj, struct attribute *attr,
                        dev->node_props.cpu_core_id_base);
        sysfs_show_32bit_prop(buffer, "simd_id_base",
                        dev->node_props.simd_id_base);
-       sysfs_show_32bit_prop(buffer, "capability",
-                       dev->node_props.capability);
        sysfs_show_32bit_prop(buffer, "max_waves_per_simd",
                        dev->node_props.max_waves_per_simd);
        sysfs_show_32bit_prop(buffer, "lds_size_in_kb",
@@ -728,14 +726,16 @@ static ssize_t node_show(struct kobject *kobj, struct attribute *attr,
                sysfs_show_32bit_prop(buffer, "max_engine_clk_fcompute",
                        dev->gpu->kfd2kgd->get_max_engine_clock_in_mhz(
                                        dev->gpu->kgd));
+
                sysfs_show_64bit_prop(buffer, "local_mem_size",
-                       dev->gpu->kfd2kgd->get_vmem_size(
-                                       dev->gpu->kgd));
+                               (unsigned long long int) 0);
 
                sysfs_show_32bit_prop(buffer, "fw_version",
                        dev->gpu->kfd2kgd->get_fw_version(
                                                dev->gpu->kgd,
                                                KGD_ENGINE_MEC1));
+               sysfs_show_32bit_prop(buffer, "capability",
+                               dev->node_props.capability);
        }
 
        return sysfs_show_32bit_prop(buffer, "max_engine_clk_ccompute",
index c8a34476570a4e95bd1c2abb67660fa5f5b57620..af9662e582727ba403cc829bc89ae9a4e3878b3b 100644 (file)
@@ -131,12 +131,11 @@ static void drm_update_vblank_count(struct drm_device *dev, int crtc)
 
        /* Reinitialize corresponding vblank timestamp if high-precision query
         * available. Skip this step if query unsupported or failed. Will
-        * reinitialize delayed at next vblank interrupt in that case.
+        * reinitialize delayed at next vblank interrupt in that case and
+        * assign 0 for now, to mark the vblanktimestamp as invalid.
         */
-       if (rc) {
-               tslot = atomic_read(&vblank->count) + diff;
-               vblanktimestamp(dev, crtc, tslot) = t_vblank;
-       }
+       tslot = atomic_read(&vblank->count) + diff;
+       vblanktimestamp(dev, crtc, tslot) = rc ? t_vblank : (struct timeval) {0, 0};
 
        smp_mb__before_atomic();
        atomic_add(diff, &vblank->count);
index 40c1db9ad7c3fac84365cc331ec67661e902abb5..2f0ed11024eb8322676e000066a238e55b0dcb9b 100644 (file)
@@ -465,6 +465,9 @@ int drm_plane_helper_commit(struct drm_plane *plane,
                if (!crtc[i])
                        continue;
 
+               if (crtc[i]->cursor == plane)
+                       continue;
+
                /* There's no other way to figure out whether the crtc is running. */
                ret = drm_crtc_vblank_get(crtc[i]);
                if (ret == 0) {
index ffc305fc20768c29af6883eeb2d70553839cfa6e..eb7e61078a5b6f1088489b49b42b32abe8ffca42 100644 (file)
@@ -217,7 +217,7 @@ static ssize_t status_store(struct device *device,
 
        mutex_unlock(&dev->mode_config.mutex);
 
-       return ret;
+       return ret ? ret : count;
 }
 
 static ssize_t status_show(struct device *device,
index 1f7e33f59de69e3ecf6c4f4ac865c1746d491d8d..6714e5b193ead813ab44f77d0f890f5cd359491f 100644 (file)
@@ -91,7 +91,7 @@ static void decon_wait_for_vblank(struct exynos_drm_crtc *crtc)
 
 static void decon_clear_channel(struct decon_context *ctx)
 {
-       int win, ch_enabled = 0;
+       unsigned int win, ch_enabled = 0;
 
        DRM_DEBUG_KMS("%s\n", __FILE__);
 
@@ -710,7 +710,7 @@ static void decon_dpms(struct exynos_drm_crtc *crtc, int mode)
        }
 }
 
-static struct exynos_drm_crtc_ops decon_crtc_ops = {
+static const struct exynos_drm_crtc_ops decon_crtc_ops = {
        .dpms = decon_dpms,
        .mode_fixup = decon_mode_fixup,
        .commit = decon_commit,
index 1dbfba58f9091b70aac969a55e270d844ea5fb05..30feb7d066244bfa078e36a518293a9195c3437c 100644 (file)
@@ -32,7 +32,6 @@
 #include <drm/bridge/ptn3460.h>
 
 #include "exynos_dp_core.h"
-#include "exynos_drm_fimd.h"
 
 #define ctx_from_connector(c)  container_of(c, struct exynos_dp_device, \
                                        connector)
@@ -196,7 +195,7 @@ static int exynos_dp_read_edid(struct exynos_dp_device *dp)
                }
        }
 
-       dev_err(dp->dev, "EDID Read success!\n");
+       dev_dbg(dp->dev, "EDID Read success!\n");
        return 0;
 }
 
@@ -1066,6 +1065,8 @@ static void exynos_dp_phy_exit(struct exynos_dp_device *dp)
 
 static void exynos_dp_poweron(struct exynos_dp_device *dp)
 {
+       struct exynos_drm_crtc *crtc = dp_to_crtc(dp);
+
        if (dp->dpms_mode == DRM_MODE_DPMS_ON)
                return;
 
@@ -1076,7 +1077,8 @@ static void exynos_dp_poweron(struct exynos_dp_device *dp)
                }
        }
 
-       fimd_dp_clock_enable(dp_to_crtc(dp), true);
+       if (crtc->ops->clock_enable)
+               crtc->ops->clock_enable(dp_to_crtc(dp), true);
 
        clk_prepare_enable(dp->clock);
        exynos_dp_phy_init(dp);
@@ -1087,6 +1089,8 @@ static void exynos_dp_poweron(struct exynos_dp_device *dp)
 
 static void exynos_dp_poweroff(struct exynos_dp_device *dp)
 {
+       struct exynos_drm_crtc *crtc = dp_to_crtc(dp);
+
        if (dp->dpms_mode != DRM_MODE_DPMS_ON)
                return;
 
@@ -1102,7 +1106,8 @@ static void exynos_dp_poweroff(struct exynos_dp_device *dp)
        exynos_dp_phy_exit(dp);
        clk_disable_unprepare(dp->clock);
 
-       fimd_dp_clock_enable(dp_to_crtc(dp), false);
+       if (crtc->ops->clock_enable)
+               crtc->ops->clock_enable(dp_to_crtc(dp), false);
 
        if (dp->panel) {
                if (drm_panel_unprepare(dp->panel))
index eb49195cec5c2396831ebfbf37e42bb5fa54ed81..9006b947e03c0a431141144c7ed21ae88b14f02b 100644 (file)
@@ -238,11 +238,11 @@ static struct drm_crtc_funcs exynos_crtc_funcs = {
 };
 
 struct exynos_drm_crtc *exynos_drm_crtc_create(struct drm_device *drm_dev,
-                                              struct drm_plane *plane,
-                                              int pipe,
-                                              enum exynos_drm_output_type type,
-                                              struct exynos_drm_crtc_ops *ops,
-                                              void *ctx)
+                                       struct drm_plane *plane,
+                                       int pipe,
+                                       enum exynos_drm_output_type type,
+                                       const struct exynos_drm_crtc_ops *ops,
+                                       void *ctx)
 {
        struct exynos_drm_crtc *exynos_crtc;
        struct exynos_drm_private *private = drm_dev->dev_private;
index 0ecd8fc45cff3349afe5d5858a713da124e30944..0f3aa70818e31059bfc6369c258dcd326fa07d53 100644 (file)
 #include "exynos_drm_drv.h"
 
 struct exynos_drm_crtc *exynos_drm_crtc_create(struct drm_device *drm_dev,
-                                              struct drm_plane *plane,
-                                              int pipe,
-                                              enum exynos_drm_output_type type,
-                                              struct exynos_drm_crtc_ops *ops,
-                                              void *context);
+                                       struct drm_plane *plane,
+                                       int pipe,
+                                       enum exynos_drm_output_type type,
+                                       const struct exynos_drm_crtc_ops *ops,
+                                       void *context);
 int exynos_drm_crtc_enable_vblank(struct drm_device *dev, int pipe);
 void exynos_drm_crtc_disable_vblank(struct drm_device *dev, int pipe);
 void exynos_drm_crtc_finish_pageflip(struct drm_device *dev, int pipe);
index e12ecb5d5d9aa01a7618eafb8930b5dc552cb14e..29e3fb78c615fa7ad58ee21a1c7c0ad19bd6ffd3 100644 (file)
@@ -71,13 +71,6 @@ enum exynos_drm_output_type {
  * @dma_addr: array of bus(accessed by dma) address to the memory region
  *           allocated for a overlay.
  * @zpos: order of overlay layer(z position).
- * @index_color: if using color key feature then this value would be used
- *                     as index color.
- * @default_win: a window to be enabled.
- * @color_key: color key on or off.
- * @local_path: in case of lcd type, local path mode on or off.
- * @transparency: transparency on or off.
- * @activated: activated or not.
  * @enabled: enabled or not.
  * @resume: to resume or not.
  *
@@ -108,13 +101,7 @@ struct exynos_drm_plane {
        uint32_t pixel_format;
        dma_addr_t dma_addr[MAX_FB_BUFFER];
        unsigned int zpos;
-       unsigned int index_color;
 
-       bool default_win:1;
-       bool color_key:1;
-       bool local_path:1;
-       bool transparency:1;
-       bool activated:1;
        bool enabled:1;
        bool resume:1;
 };
@@ -181,6 +168,10 @@ struct exynos_drm_display {
  * @win_disable: disable hardware specific overlay.
  * @te_handler: trigger to transfer video image at the tearing effect
  *     synchronization signal if there is a page flip request.
+ * @clock_enable: optional function enabling/disabling display domain clock,
+ *     called from exynos-dp driver before powering up (with
+ *     'enable' argument as true) and after powering down (with
+ *     'enable' as false).
  */
 struct exynos_drm_crtc;
 struct exynos_drm_crtc_ops {
@@ -195,6 +186,7 @@ struct exynos_drm_crtc_ops {
        void (*win_commit)(struct exynos_drm_crtc *crtc, unsigned int zpos);
        void (*win_disable)(struct exynos_drm_crtc *crtc, unsigned int zpos);
        void (*te_handler)(struct exynos_drm_crtc *crtc);
+       void (*clock_enable)(struct exynos_drm_crtc *crtc, bool enable);
 };
 
 /*
@@ -221,7 +213,7 @@ struct exynos_drm_crtc {
        unsigned int                    dpms;
        wait_queue_head_t               pending_flip_queue;
        struct drm_pending_vblank_event *event;
-       struct exynos_drm_crtc_ops      *ops;
+       const struct exynos_drm_crtc_ops        *ops;
        void                            *ctx;
 };
 
index 929cb03a8eab15d6daee766016dc59070130a240..142eb4e3f59ea5501805cc56bed7cbef4106ae7b 100644 (file)
@@ -171,43 +171,6 @@ exynos_drm_framebuffer_init(struct drm_device *dev,
        return &exynos_fb->fb;
 }
 
-static u32 exynos_drm_format_num_buffers(struct drm_mode_fb_cmd2 *mode_cmd)
-{
-       unsigned int cnt = 0;
-
-       if (mode_cmd->pixel_format != DRM_FORMAT_NV12)
-               return drm_format_num_planes(mode_cmd->pixel_format);
-
-       while (cnt != MAX_FB_BUFFER) {
-               if (!mode_cmd->handles[cnt])
-                       break;
-               cnt++;
-       }
-
-       /*
-        * check if NV12 or NV12M.
-        *
-        * NV12
-        * handles[0] = base1, offsets[0] = 0
-        * handles[1] = base1, offsets[1] = Y_size
-        *
-        * NV12M
-        * handles[0] = base1, offsets[0] = 0
-        * handles[1] = base2, offsets[1] = 0
-        */
-       if (cnt == 2) {
-               /*
-                * in case of NV12 format, offsets[1] is not 0 and
-                * handles[0] is same as handles[1].
-                */
-               if (mode_cmd->offsets[1] &&
-                       mode_cmd->handles[0] == mode_cmd->handles[1])
-                       cnt = 1;
-       }
-
-       return cnt;
-}
-
 static struct drm_framebuffer *
 exynos_user_fb_create(struct drm_device *dev, struct drm_file *file_priv,
                      struct drm_mode_fb_cmd2 *mode_cmd)
@@ -230,7 +193,7 @@ exynos_user_fb_create(struct drm_device *dev, struct drm_file *file_priv,
 
        drm_helper_mode_fill_fb_struct(&exynos_fb->fb, mode_cmd);
        exynos_fb->exynos_gem_obj[0] = to_exynos_gem_obj(obj);
-       exynos_fb->buf_cnt = exynos_drm_format_num_buffers(mode_cmd);
+       exynos_fb->buf_cnt = drm_format_num_planes(mode_cmd->pixel_format);
 
        DRM_DEBUG_KMS("buf_cnt = %d\n", exynos_fb->buf_cnt);
 
index 9819fa6a9e2a41867da1ddaab9fb052dc0a74310..a0edab833148adf2abf99a3cde1d60eee6d5619b 100644 (file)
@@ -33,7 +33,6 @@
 #include "exynos_drm_crtc.h"
 #include "exynos_drm_plane.h"
 #include "exynos_drm_iommu.h"
-#include "exynos_drm_fimd.h"
 
 /*
  * FIMD stands for Fully Interactive Mobile Display and
@@ -216,7 +215,7 @@ static void fimd_wait_for_vblank(struct exynos_drm_crtc *crtc)
                DRM_DEBUG_KMS("vblank wait timed out.\n");
 }
 
-static void fimd_enable_video_output(struct fimd_context *ctx, int win,
+static void fimd_enable_video_output(struct fimd_context *ctx, unsigned int win,
                                        bool enable)
 {
        u32 val = readl(ctx->regs + WINCON(win));
@@ -229,7 +228,8 @@ static void fimd_enable_video_output(struct fimd_context *ctx, int win,
        writel(val, ctx->regs + WINCON(win));
 }
 
-static void fimd_enable_shadow_channel_path(struct fimd_context *ctx, int win,
+static void fimd_enable_shadow_channel_path(struct fimd_context *ctx,
+                                               unsigned int win,
                                                bool enable)
 {
        u32 val = readl(ctx->regs + SHADOWCON);
@@ -244,7 +244,7 @@ static void fimd_enable_shadow_channel_path(struct fimd_context *ctx, int win,
 
 static void fimd_clear_channel(struct fimd_context *ctx)
 {
-       int win, ch_enabled = 0;
+       unsigned int win, ch_enabled = 0;
 
        DRM_DEBUG_KMS("%s\n", __FILE__);
 
@@ -946,7 +946,24 @@ static void fimd_te_handler(struct exynos_drm_crtc *crtc)
                drm_handle_vblank(ctx->drm_dev, ctx->pipe);
 }
 
-static struct exynos_drm_crtc_ops fimd_crtc_ops = {
+static void fimd_dp_clock_enable(struct exynos_drm_crtc *crtc, bool enable)
+{
+       struct fimd_context *ctx = crtc->ctx;
+       u32 val;
+
+       /*
+        * Only Exynos 5250, 5260, 5410 and 542x requires enabling DP/MIE
+        * clock. On these SoCs the bootloader may enable it but any
+        * power domain off/on will reset it to disable state.
+        */
+       if (ctx->driver_data != &exynos5_fimd_driver_data)
+               return;
+
+       val = enable ? DP_MIE_CLK_DP_ENABLE : DP_MIE_CLK_DISABLE;
+       writel(DP_MIE_CLK_DP_ENABLE, ctx->regs + DP_MIE_CLKCON);
+}
+
+static const struct exynos_drm_crtc_ops fimd_crtc_ops = {
        .dpms = fimd_dpms,
        .mode_fixup = fimd_mode_fixup,
        .commit = fimd_commit,
@@ -956,6 +973,7 @@ static struct exynos_drm_crtc_ops fimd_crtc_ops = {
        .win_commit = fimd_win_commit,
        .win_disable = fimd_win_disable,
        .te_handler = fimd_te_handler,
+       .clock_enable = fimd_dp_clock_enable,
 };
 
 static irqreturn_t fimd_irq_handler(int irq, void *dev_id)
@@ -1025,12 +1043,7 @@ static int fimd_bind(struct device *dev, struct device *master, void *data)
        if (ctx->display)
                exynos_drm_create_enc_conn(drm_dev, ctx->display);
 
-       ret = fimd_iommu_attach_devices(ctx, drm_dev);
-       if (ret)
-               return ret;
-
-       return 0;
-
+       return fimd_iommu_attach_devices(ctx, drm_dev);
 }
 
 static void fimd_unbind(struct device *dev, struct device *master,
@@ -1192,24 +1205,6 @@ static int fimd_remove(struct platform_device *pdev)
        return 0;
 }
 
-void fimd_dp_clock_enable(struct exynos_drm_crtc *crtc, bool enable)
-{
-       struct fimd_context *ctx = crtc->ctx;
-       u32 val;
-
-       /*
-        * Only Exynos 5250, 5260, 5410 and 542x requires enabling DP/MIE
-        * clock. On these SoCs the bootloader may enable it but any
-        * power domain off/on will reset it to disable state.
-        */
-       if (ctx->driver_data != &exynos5_fimd_driver_data)
-               return;
-
-       val = enable ? DP_MIE_CLK_DP_ENABLE : DP_MIE_CLK_DISABLE;
-       writel(DP_MIE_CLK_DP_ENABLE, ctx->regs + DP_MIE_CLKCON);
-}
-EXPORT_SYMBOL_GPL(fimd_dp_clock_enable);
-
 struct platform_driver fimd_driver = {
        .probe          = fimd_probe,
        .remove         = fimd_remove,
diff --git a/drivers/gpu/drm/exynos/exynos_drm_fimd.h b/drivers/gpu/drm/exynos/exynos_drm_fimd.h
deleted file mode 100644 (file)
index b4fcaa5..0000000
+++ /dev/null
@@ -1,15 +0,0 @@
-/*
- * Copyright (c) 2015 Samsung Electronics Co., Ltd.
- *
- * This program is free software; you can redistribute  it and/or modify it
- * under  the terms of  the GNU General  Public License as published by the
- * Free Software Foundation;  either version 2 of the  License, or (at your
- * option) any later version.
- */
-
-#ifndef _EXYNOS_DRM_FIMD_H_
-#define _EXYNOS_DRM_FIMD_H_
-
-extern void fimd_dp_clock_enable(struct exynos_drm_crtc *crtc, bool enable);
-
-#endif /* _EXYNOS_DRM_FIMD_H_ */
index 13ea3349363b153a8225aece3acc3e70a05dbe51..b1180fbe754690f700c124bdd50f72adb28d2295 100644 (file)
@@ -76,7 +76,7 @@ int exynos_check_plane(struct drm_plane *plane, struct drm_framebuffer *fb)
                        return -EFAULT;
                }
 
-               exynos_plane->dma_addr[i] = buffer->dma_addr;
+               exynos_plane->dma_addr[i] = buffer->dma_addr + fb->offsets[i];
 
                DRM_DEBUG_KMS("buffer: %d, dma_addr = 0x%lx\n",
                                i, (unsigned long)exynos_plane->dma_addr[i]);
index 27e84ec21694d587f26a78d258c216d52bd450ea..1b3479a8db5f08dd2b3c1c4fa0de5758d2ae7b26 100644 (file)
@@ -217,7 +217,7 @@ static int vidi_ctx_initialize(struct vidi_context *ctx,
        return 0;
 }
 
-static struct exynos_drm_crtc_ops vidi_crtc_ops = {
+static const struct exynos_drm_crtc_ops vidi_crtc_ops = {
        .dpms = vidi_dpms,
        .enable_vblank = vidi_enable_vblank,
        .disable_vblank = vidi_disable_vblank,
index fbec750574e64a3158b232d15ef309b29ed5340c..8874c1fcb3ab778b7faa82b0cedf1e47a7c2cd7c 100644 (file)
 #define MIXER_WIN_NR           3
 #define MIXER_DEFAULT_WIN      0
 
+/* The pixelformats that are natively supported by the mixer. */
+#define MXR_FORMAT_RGB565      4
+#define MXR_FORMAT_ARGB1555    5
+#define MXR_FORMAT_ARGB4444    6
+#define MXR_FORMAT_ARGB8888    7
+
 struct mixer_resources {
        int                     irq;
        void __iomem            *mixer_regs;
@@ -327,7 +333,8 @@ static void mixer_cfg_rgb_fmt(struct mixer_context *ctx, unsigned int height)
        mixer_reg_writemask(res, MXR_CFG, val, MXR_CFG_RGB_FMT_MASK);
 }
 
-static void mixer_cfg_layer(struct mixer_context *ctx, int win, bool enable)
+static void mixer_cfg_layer(struct mixer_context *ctx, unsigned int win,
+                               bool enable)
 {
        struct mixer_resources *res = &ctx->mixer_res;
        u32 val = enable ? ~0 : 0;
@@ -359,8 +366,6 @@ static void mixer_run(struct mixer_context *ctx)
        struct mixer_resources *res = &ctx->mixer_res;
 
        mixer_reg_writemask(res, MXR_STATUS, ~0, MXR_STATUS_REG_RUN);
-
-       mixer_regs_dump(ctx);
 }
 
 static void mixer_stop(struct mixer_context *ctx)
@@ -373,16 +378,13 @@ static void mixer_stop(struct mixer_context *ctx)
        while (!(mixer_reg_read(res, MXR_STATUS) & MXR_STATUS_REG_IDLE) &&
                        --timeout)
                usleep_range(10000, 12000);
-
-       mixer_regs_dump(ctx);
 }
 
-static void vp_video_buffer(struct mixer_context *ctx, int win)
+static void vp_video_buffer(struct mixer_context *ctx, unsigned int win)
 {
        struct mixer_resources *res = &ctx->mixer_res;
        unsigned long flags;
        struct exynos_drm_plane *plane;
-       unsigned int buf_num = 1;
        dma_addr_t luma_addr[2], chroma_addr[2];
        bool tiled_mode = false;
        bool crcb_mode = false;
@@ -393,27 +395,18 @@ static void vp_video_buffer(struct mixer_context *ctx, int win)
        switch (plane->pixel_format) {
        case DRM_FORMAT_NV12:
                crcb_mode = false;
-               buf_num = 2;
                break;
-       /* TODO: single buffer format NV12, NV21 */
+       case DRM_FORMAT_NV21:
+               crcb_mode = true;
+               break;
        default:
-               /* ignore pixel format at disable time */
-               if (!plane->dma_addr[0])
-                       break;
-
                DRM_ERROR("pixel format for vp is wrong [%d].\n",
                                plane->pixel_format);
                return;
        }
 
-       if (buf_num == 2) {
-               luma_addr[0] = plane->dma_addr[0];
-               chroma_addr[0] = plane->dma_addr[1];
-       } else {
-               luma_addr[0] = plane->dma_addr[0];
-               chroma_addr[0] = plane->dma_addr[0]
-                       + (plane->pitch * plane->fb_height);
-       }
+       luma_addr[0] = plane->dma_addr[0];
+       chroma_addr[0] = plane->dma_addr[1];
 
        if (plane->scan_flag & DRM_MODE_FLAG_INTERLACE) {
                ctx->interlace = true;
@@ -484,6 +477,7 @@ static void vp_video_buffer(struct mixer_context *ctx, int win)
        mixer_vsync_set_update(ctx, true);
        spin_unlock_irqrestore(&res->reg_slock, flags);
 
+       mixer_regs_dump(ctx);
        vp_regs_dump(ctx);
 }
 
@@ -518,7 +512,7 @@ fail:
        return -ENOTSUPP;
 }
 
-static void mixer_graph_buffer(struct mixer_context *ctx, int win)
+static void mixer_graph_buffer(struct mixer_context *ctx, unsigned int win)
 {
        struct mixer_resources *res = &ctx->mixer_res;
        unsigned long flags;
@@ -531,20 +525,27 @@ static void mixer_graph_buffer(struct mixer_context *ctx, int win)
 
        plane = &ctx->planes[win];
 
-       #define RGB565 4
-       #define ARGB1555 5
-       #define ARGB4444 6
-       #define ARGB8888 7
+       switch (plane->pixel_format) {
+       case DRM_FORMAT_XRGB4444:
+               fmt = MXR_FORMAT_ARGB4444;
+               break;
 
-       switch (plane->bpp) {
-       case 16:
-               fmt = ARGB4444;
+       case DRM_FORMAT_XRGB1555:
+               fmt = MXR_FORMAT_ARGB1555;
                break;
-       case 32:
-               fmt = ARGB8888;
+
+       case DRM_FORMAT_RGB565:
+               fmt = MXR_FORMAT_RGB565;
+               break;
+
+       case DRM_FORMAT_XRGB8888:
+       case DRM_FORMAT_ARGB8888:
+               fmt = MXR_FORMAT_ARGB8888;
                break;
+
        default:
-               fmt = ARGB8888;
+               DRM_DEBUG_KMS("pixelformat unsupported by mixer\n");
+               return;
        }
 
        /* check if mixer supports requested scaling setup */
@@ -617,6 +618,8 @@ static void mixer_graph_buffer(struct mixer_context *ctx, int win)
 
        mixer_vsync_set_update(ctx, true);
        spin_unlock_irqrestore(&res->reg_slock, flags);
+
+       mixer_regs_dump(ctx);
 }
 
 static void vp_win_reset(struct mixer_context *ctx)
@@ -1070,6 +1073,7 @@ static void mixer_poweroff(struct mixer_context *ctx)
        mutex_unlock(&ctx->mixer_mutex);
 
        mixer_stop(ctx);
+       mixer_regs_dump(ctx);
        mixer_window_suspend(ctx);
 
        ctx->int_en = mixer_reg_read(res, MXR_INT_EN);
@@ -1126,7 +1130,7 @@ int mixer_check_mode(struct drm_display_mode *mode)
        return -EINVAL;
 }
 
-static struct exynos_drm_crtc_ops mixer_crtc_ops = {
+static const struct exynos_drm_crtc_ops mixer_crtc_ops = {
        .dpms                   = mixer_dpms,
        .enable_vblank          = mixer_enable_vblank,
        .disable_vblank         = mixer_disable_vblank,
@@ -1156,7 +1160,7 @@ static struct mixer_drv_data exynos4210_mxr_drv_data = {
        .has_sclk = 1,
 };
 
-static struct platform_device_id mixer_driver_types[] = {
+static const struct platform_device_id mixer_driver_types[] = {
        {
                .name           = "s5p-mixer",
                .driver_data    = (unsigned long)&exynos4210_mxr_drv_data,
index 007c7d7d82950f597bb05ef8388fb1696ef72b38..dc55c51964ab501720f02ae682118ce12a51f0ff 100644 (file)
@@ -1667,12 +1667,15 @@ static int i915_sr_status(struct seq_file *m, void *unused)
 
        if (HAS_PCH_SPLIT(dev))
                sr_enabled = I915_READ(WM1_LP_ILK) & WM1_LP_SR_EN;
-       else if (IS_CRESTLINE(dev) || IS_I945G(dev) || IS_I945GM(dev))
+       else if (IS_CRESTLINE(dev) || IS_G4X(dev) ||
+                IS_I945G(dev) || IS_I945GM(dev))
                sr_enabled = I915_READ(FW_BLC_SELF) & FW_BLC_SELF_EN;
        else if (IS_I915GM(dev))
                sr_enabled = I915_READ(INSTPM) & INSTPM_SELF_EN;
        else if (IS_PINEVIEW(dev))
                sr_enabled = I915_READ(DSPFW3) & PINEVIEW_SELF_REFRESH_EN;
+       else if (IS_VALLEYVIEW(dev))
+               sr_enabled = I915_READ(FW_BLC_SELF_VLV) & FW_CSPWRDWNEN;
 
        intel_runtime_pm_put(dev_priv);
 
index c302ffb5a16814b41086abe52a25c7f7debd40a8..a19d2c71e20505aba9ca25158d6e5acd6ba6f920 100644 (file)
@@ -699,6 +699,16 @@ static int i915_drm_resume(struct drm_device *dev)
        intel_init_pch_refclk(dev);
        drm_mode_config_reset(dev);
 
+       /*
+        * Interrupts have to be enabled before any batches are run. If not the
+        * GPU will hang. i915_gem_init_hw() will initiate batches to
+        * update/restore the context.
+        *
+        * Modeset enabling in intel_modeset_init_hw() also needs working
+        * interrupts.
+        */
+       intel_runtime_pm_enable_interrupts(dev_priv);
+
        mutex_lock(&dev->struct_mutex);
        if (i915_gem_init_hw(dev)) {
                DRM_ERROR("failed to re-initialize GPU, declaring wedged!\n");
@@ -706,9 +716,6 @@ static int i915_drm_resume(struct drm_device *dev)
        }
        mutex_unlock(&dev->struct_mutex);
 
-       /* We need working interrupts for modeset enabling ... */
-       intel_runtime_pm_enable_interrupts(dev_priv);
-
        intel_modeset_init_hw(dev);
 
        spin_lock_irq(&dev_priv->irq_lock);
index 53394f998a1f9429f87b78598a69e232a48d5b38..851b585987f9aebeaff662844f5d5d356bbc5e6f 100644 (file)
@@ -2656,9 +2656,6 @@ void i915_gem_reset(struct drm_device *dev)
 void
 i915_gem_retire_requests_ring(struct intel_engine_cs *ring)
 {
-       if (list_empty(&ring->request_list))
-               return;
-
        WARN_ON(i915_verify_lists(ring->dev));
 
        /* Retire requests first as we use it above for the early return.
index 3da1af46625c73a5a24c996b56e94c6f0b637526..773d1d24e604ccc74b92552d07264bb1b3991938 100644 (file)
@@ -6074,6 +6074,8 @@ enum skl_disp_power_wells {
 #define  GTFIFOCTL                             0x120008
 #define    GT_FIFO_FREE_ENTRIES_MASK           0x7f
 #define    GT_FIFO_NUM_RESERVED_ENTRIES                20
+#define    GT_FIFO_CTL_BLOCK_ALL_POLICY_STALL  (1 << 12)
+#define    GT_FIFO_CTL_RC6_POLICY_STALL                (1 << 11)
 
 #define  HSW_IDICR                             0x9008
 #define    IDIHASHMSK(x)                       (((x) & 0x3f) << 16)
index d547d9c8dda2226909fcdbc5193dde4e2013246a..d0f3cbc87474c1ff9aff408fd692426a7e70c5d4 100644 (file)
@@ -13635,9 +13635,6 @@ static const struct intel_dmi_quirk intel_dmi_quirks[] = {
 };
 
 static struct intel_quirk intel_quirks[] = {
-       /* HP Mini needs pipe A force quirk (LP: #322104) */
-       { 0x27ae, 0x103c, 0x361a, quirk_pipea_force },
-
        /* Toshiba Protege R-205, S-209 needs pipe A force quirk */
        { 0x2592, 0x1179, 0x0001, quirk_pipea_force },
 
index d0237102c27ecf1323e39ee1d67cee07e3760f60..d714a4b5711e4e7fa390ec6b659d2683ef41f585 100644 (file)
@@ -880,10 +880,8 @@ intel_dp_aux_ch(struct intel_dp *intel_dp,
                                      DP_AUX_CH_CTL_RECEIVE_ERROR))
                                continue;
                        if (status & DP_AUX_CH_CTL_DONE)
-                               break;
+                               goto done;
                }
-               if (status & DP_AUX_CH_CTL_DONE)
-                       break;
        }
 
        if ((status & DP_AUX_CH_CTL_DONE) == 0) {
@@ -892,6 +890,7 @@ intel_dp_aux_ch(struct intel_dp *intel_dp,
                goto out;
        }
 
+done:
        /* Check for timeout or receive error.
         * Timeouts occur when the sink is not connected
         */
@@ -1348,7 +1347,7 @@ intel_dp_compute_config(struct intel_encoder *encoder,
 
        pipe_config->has_dp_encoder = true;
        pipe_config->has_drrs = false;
-       pipe_config->has_audio = intel_dp->has_audio;
+       pipe_config->has_audio = intel_dp->has_audio && port != PORT_A;
 
        if (is_edp(intel_dp) && intel_connector->panel.fixed_mode) {
                intel_fixed_panel_mode(intel_connector->panel.fixed_mode,
@@ -2211,8 +2210,8 @@ static void intel_dp_get_config(struct intel_encoder *encoder,
        int dotclock;
 
        tmp = I915_READ(intel_dp->output_reg);
-       if (tmp & DP_AUDIO_OUTPUT_ENABLE)
-               pipe_config->has_audio = true;
+
+       pipe_config->has_audio = tmp & DP_AUDIO_OUTPUT_ENABLE && port != PORT_A;
 
        if ((port == PORT_A) || !HAS_PCH_CPT(dev)) {
                if (tmp & DP_SYNC_HS_HIGH)
@@ -3812,7 +3811,8 @@ intel_dp_get_dpcd(struct intel_dp *intel_dp)
                        if (val == 0)
                                break;
 
-                       intel_dp->sink_rates[i] = val * 200;
+                       /* Value read is in kHz while drm clock is saved in deca-kHz */
+                       intel_dp->sink_rates[i] = (val * 200) / 10;
                }
                intel_dp->num_sink_rates = i;
        }
index 56e437e3158021a09641d188affc6129f0b1eda8..ae628001fd97873b67f99fb0128167858948afe6 100644 (file)
@@ -435,7 +435,7 @@ gmbus_xfer(struct i2c_adapter *adapter,
                                               struct intel_gmbus,
                                               adapter);
        struct drm_i915_private *dev_priv = bus->dev_priv;
-       int i, reg_offset;
+       int i = 0, inc, try = 0, reg_offset;
        int ret = 0;
 
        intel_aux_display_runtime_get(dev_priv);
@@ -448,12 +448,14 @@ gmbus_xfer(struct i2c_adapter *adapter,
 
        reg_offset = dev_priv->gpio_mmio_base;
 
+retry:
        I915_WRITE(GMBUS0 + reg_offset, bus->reg0);
 
-       for (i = 0; i < num; i++) {
+       for (; i < num; i += inc) {
+               inc = 1;
                if (gmbus_is_index_read(msgs, i, num)) {
                        ret = gmbus_xfer_index_read(dev_priv, &msgs[i]);
-                       i += 1;  /* set i to the index of the read xfer */
+                       inc = 2; /* an index read is two msgs */
                } else if (msgs[i].flags & I2C_M_RD) {
                        ret = gmbus_xfer_read(dev_priv, &msgs[i], 0);
                } else {
@@ -525,6 +527,18 @@ clear_err:
                         adapter->name, msgs[i].addr,
                         (msgs[i].flags & I2C_M_RD) ? 'r' : 'w', msgs[i].len);
 
+       /*
+        * Passive adapters sometimes NAK the first probe. Retry the first
+        * message once on -ENXIO for GMBUS transfers; the bit banging algorithm
+        * has retries internally. See also the retry loop in
+        * drm_do_probe_ddc_edid, which bails out on the first -ENXIO.
+        */
+       if (ret == -ENXIO && i == 0 && try++ == 0) {
+               DRM_DEBUG_KMS("GMBUS [%s] NAK on first message, retry\n",
+                             adapter->name);
+               goto retry;
+       }
+
        goto out;
 
 timeout:
index 09df74b8e917b1dac90d460be50d1c4c5152881c..424e6219778712dcaf0e7c5c1ae7c51709fce6ba 100644 (file)
@@ -1134,6 +1134,12 @@ static int gen8_init_common_ring(struct intel_engine_cs *ring)
        I915_WRITE_IMR(ring, ~(ring->irq_enable_mask | ring->irq_keep_mask));
        I915_WRITE(RING_HWSTAM(ring->mmio_base), 0xffffffff);
 
+       if (ring->status_page.obj) {
+               I915_WRITE(RING_HWS_PGA(ring->mmio_base),
+                          (u32)ring->status_page.gfx_addr);
+               POSTING_READ(RING_HWS_PGA(ring->mmio_base));
+       }
+
        I915_WRITE(RING_MODE_GEN7(ring),
                   _MASKED_BIT_DISABLE(GFX_REPLAY_MODE) |
                   _MASKED_BIT_ENABLE(GFX_RUN_LIST_ENABLE));
index 5abda1d2c0182ad9f4bec4ad7e9fa4c640cb9d32..fbcc7dff0d630f3292efa80d881a859954c91266 100644 (file)
@@ -813,12 +813,28 @@ static int intel_dual_link_lvds_callback(const struct dmi_system_id *id)
 static const struct dmi_system_id intel_dual_link_lvds[] = {
        {
                .callback = intel_dual_link_lvds_callback,
-               .ident = "Apple MacBook Pro (Core i5/i7 Series)",
+               .ident = "Apple MacBook Pro 15\" (2010)",
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "MacBookPro6,2"),
+               },
+       },
+       {
+               .callback = intel_dual_link_lvds_callback,
+               .ident = "Apple MacBook Pro 15\" (2011)",
                .matches = {
                        DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."),
                        DMI_MATCH(DMI_PRODUCT_NAME, "MacBookPro8,2"),
                },
        },
+       {
+               .callback = intel_dual_link_lvds_callback,
+               .ident = "Apple MacBook Pro 15\" (2012)",
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "MacBookPro9,1"),
+               },
+       },
        { }     /* terminating entry */
 };
 
@@ -848,6 +864,11 @@ static bool compute_is_dual_link_lvds(struct intel_lvds_encoder *lvds_encoder)
        if (i915.lvds_channel_mode > 0)
                return i915.lvds_channel_mode == 2;
 
+       /* single channel LVDS is limited to 112 MHz */
+       if (lvds_encoder->attached_connector->base.panel.fixed_mode->clock
+           > 112999)
+               return true;
+
        if (dmi_check_system(intel_dual_link_lvds))
                return true;
 
@@ -1111,6 +1132,8 @@ void intel_lvds_init(struct drm_device *dev)
 out:
        mutex_unlock(&dev->mode_config.mutex);
 
+       intel_panel_init(&intel_connector->panel, fixed_mode, downclock_mode);
+
        lvds_encoder->is_dual_link = compute_is_dual_link_lvds(lvds_encoder);
        DRM_DEBUG_KMS("detected %s-link lvds configuration\n",
                      lvds_encoder->is_dual_link ? "dual" : "single");
@@ -1125,7 +1148,6 @@ out:
        }
        drm_connector_register(connector);
 
-       intel_panel_init(&intel_connector->panel, fixed_mode, downclock_mode);
        intel_panel_setup_backlight(connector, INVALID_PIPE);
 
        return;
index fa4ccb346389e2369effb3b3c48f6f211afa4832..555b896d2bdadec44aebc821a2f7fd9a09d58441 100644 (file)
@@ -2045,22 +2045,20 @@ static void ilk_compute_wm_parameters(struct drm_crtc *crtc,
        p->pipe_htotal = intel_crtc->config->base.adjusted_mode.crtc_htotal;
        p->pixel_rate = ilk_pipe_pixel_rate(dev, crtc);
 
-       if (crtc->primary->state->fb) {
-               p->pri.enabled = true;
+       if (crtc->primary->state->fb)
                p->pri.bytes_per_pixel =
                        crtc->primary->state->fb->bits_per_pixel / 8;
-       } else {
-               p->pri.enabled = false;
-               p->pri.bytes_per_pixel = 0;
-       }
+       else
+               p->pri.bytes_per_pixel = 4;
+
+       p->cur.bytes_per_pixel = 4;
+       /*
+        * TODO: for now, assume primary and cursor planes are always enabled.
+        * Setting them to false makes the screen flicker.
+        */
+       p->pri.enabled = true;
+       p->cur.enabled = true;
 
-       if (crtc->cursor->state->fb) {
-               p->cur.enabled = true;
-               p->cur.bytes_per_pixel = 4;
-       } else {
-               p->cur.enabled = false;
-               p->cur.bytes_per_pixel = 0;
-       }
        p->pri.horiz_pixels = intel_crtc->config->pipe_src_w;
        p->cur.horiz_pixels = intel_crtc->base.cursor->state->crtc_w;
 
index 441e2502b88946ff2d7455a9f26cc32faa87d8fc..005b5e04de4d74d13eee87af223c9e22687f6d35 100644 (file)
@@ -901,13 +901,6 @@ static int chv_init_workarounds(struct intel_engine_cs *ring)
                            GEN6_WIZ_HASHING_MASK,
                            GEN6_WIZ_HASHING_16x4);
 
-       if (INTEL_REVID(dev) == SKL_REVID_C0 ||
-           INTEL_REVID(dev) == SKL_REVID_D0)
-               /* WaBarrierPerformanceFixDisable:skl */
-               WA_SET_BIT_MASKED(HDC_CHICKEN0,
-                                 HDC_FENCE_DEST_SLM_DISABLE |
-                                 HDC_BARRIER_PERFORMANCE_DISABLE);
-
        return 0;
 }
 
@@ -1024,6 +1017,13 @@ static int skl_init_workarounds(struct intel_engine_cs *ring)
                WA_SET_BIT_MASKED(HIZ_CHICKEN,
                                  BDW_HIZ_POWER_COMPILER_CLOCK_GATING_DISABLE);
 
+       if (INTEL_REVID(dev) == SKL_REVID_C0 ||
+           INTEL_REVID(dev) == SKL_REVID_D0)
+               /* WaBarrierPerformanceFixDisable:skl */
+               WA_SET_BIT_MASKED(HDC_CHICKEN0,
+                                 HDC_FENCE_DEST_SLM_DISABLE |
+                                 HDC_BARRIER_PERFORMANCE_DISABLE);
+
        return skl_tune_iz_hashing(ring);
 }
 
index e87d2f418de4f381d50471494e5fe8050de4bdb2..987b81f31b0e693cfe7d505b2f66eecc7eac6539 100644 (file)
@@ -2550,7 +2550,7 @@ intel_sdvo_analog_init(struct intel_sdvo *intel_sdvo, int device)
 
        DRM_DEBUG_KMS("initialising analog device %d\n", device);
 
-       intel_sdvo_connector = kzalloc(sizeof(*intel_sdvo_connector), GFP_KERNEL);
+       intel_sdvo_connector = intel_sdvo_connector_alloc();
        if (!intel_sdvo_connector)
                return false;
 
index ab5cc94588e10d1ac1ac81e3330073ea92d17ac7..ff2a74651dd48561c0170427ca9b89f3db54c9d4 100644 (file)
@@ -360,6 +360,14 @@ static void __intel_uncore_early_sanitize(struct drm_device *dev,
                __raw_i915_write32(dev_priv, GTFIFODBG,
                                   __raw_i915_read32(dev_priv, GTFIFODBG));
 
+       /* WaDisableShadowRegForCpd:chv */
+       if (IS_CHERRYVIEW(dev)) {
+               __raw_i915_write32(dev_priv, GTFIFOCTL,
+                                  __raw_i915_read32(dev_priv, GTFIFOCTL) |
+                                  GT_FIFO_CTL_BLOCK_ALL_POLICY_STALL |
+                                  GT_FIFO_CTL_RC6_POLICY_STALL);
+       }
+
        intel_uncore_forcewake_reset(dev, restore_forcewake);
 }
 
index 94a5bee69fe724c94542bc5181e4309e78b78300..bbdcab0a56c1734d672457623d0eb071b881ceda 100644 (file)
@@ -384,7 +384,7 @@ void adreno_gpu_cleanup(struct adreno_gpu *gpu)
        if (gpu->memptrs_bo) {
                if (gpu->memptrs_iova)
                        msm_gem_put_iova(gpu->memptrs_bo, gpu->base.id);
-               drm_gem_object_unreference(gpu->memptrs_bo);
+               drm_gem_object_unreference_unlocked(gpu->memptrs_bo);
        }
        release_firmware(gpu->pm4);
        release_firmware(gpu->pfp);
index 28d1f95a90ccf0c87b10b26818ce0d14f106d1b9..ad50b80225f5b95d7f90252ea4ba086109a730d7 100644 (file)
@@ -177,6 +177,11 @@ int msm_dsi_modeset_init(struct msm_dsi *msm_dsi, struct drm_device *dev,
                goto fail;
        }
 
+       for (i = 0; i < MSM_DSI_ENCODER_NUM; i++) {
+               encoders[i]->bridge = msm_dsi->bridge;
+               msm_dsi->encoders[i] = encoders[i];
+       }
+
        msm_dsi->connector = msm_dsi_manager_connector_init(msm_dsi->id);
        if (IS_ERR(msm_dsi->connector)) {
                ret = PTR_ERR(msm_dsi->connector);
@@ -185,11 +190,6 @@ int msm_dsi_modeset_init(struct msm_dsi *msm_dsi, struct drm_device *dev,
                goto fail;
        }
 
-       for (i = 0; i < MSM_DSI_ENCODER_NUM; i++) {
-               encoders[i]->bridge = msm_dsi->bridge;
-               msm_dsi->encoders[i] = encoders[i];
-       }
-
        priv->bridges[priv->num_bridges++]       = msm_dsi->bridge;
        priv->connectors[priv->num_connectors++] = msm_dsi->connector;
 
index 956b22492c9a8f81db4ad38abc1a4edbb477bd38..649d20d29f9298a8852e6d0368008becb348fe03 100644 (file)
@@ -1023,7 +1023,7 @@ static int dsi_short_read1_resp(u8 *buf, const struct mipi_dsi_msg *msg)
                *data = buf[1]; /* strip out dcs type */
                return 1;
        } else {
-               pr_err("%s: read data does not match with rx_buf len %d\n",
+               pr_err("%s: read data does not match with rx_buf len %zu\n",
                        __func__, msg->rx_len);
                return -EINVAL;
        }
@@ -1040,7 +1040,7 @@ static int dsi_short_read2_resp(u8 *buf, const struct mipi_dsi_msg *msg)
                data[1] = buf[2];
                return 2;
        } else {
-               pr_err("%s: read data does not match with rx_buf len %d\n",
+               pr_err("%s: read data does not match with rx_buf len %zu\n",
                        __func__, msg->rx_len);
                return -EINVAL;
        }
@@ -1093,7 +1093,6 @@ static int dsi_cmd_dma_rx(struct msm_dsi_host *msm_host,
 {
        u32 *lp, *temp, data;
        int i, j = 0, cnt;
-       bool ack_error = false;
        u32 read_cnt;
        u8 reg[16];
        int repeated_bytes = 0;
@@ -1105,15 +1104,10 @@ static int dsi_cmd_dma_rx(struct msm_dsi_host *msm_host,
        if (cnt > 4)
                cnt = 4; /* 4 x 32 bits registers only */
 
-       /* Calculate real read data count */
-       read_cnt = dsi_read(msm_host, 0x1d4) >> 16;
-
-       ack_error = (rx_byte == 4) ?
-               (read_cnt == 8) : /* short pkt + 4-byte error pkt */
-               (read_cnt == (pkt_size + 6 + 4)); /* long pkt+4-byte error pkt*/
-
-       if (ack_error)
-               read_cnt -= 4; /* Remove 4 byte error pkt */
+       if (rx_byte == 4)
+               read_cnt = 4;
+       else
+               read_cnt = pkt_size + 6;
 
        /*
         * In case of multiple reads from the panel, after the first read, there
@@ -1215,7 +1209,7 @@ static void dsi_err_worker(struct work_struct *work)
                container_of(work, struct msm_dsi_host, err_work);
        u32 status = msm_host->err_work_state;
 
-       pr_err("%s: status=%x\n", __func__, status);
+       pr_err_ratelimited("%s: status=%x\n", __func__, status);
        if (status & DSI_ERR_STATE_MDP_FIFO_UNDERFLOW)
                dsi_sw_reset_restore(msm_host);
 
@@ -1797,6 +1791,7 @@ int msm_dsi_host_cmd_rx(struct mipi_dsi_host *host,
        case MIPI_DSI_RX_ACKNOWLEDGE_AND_ERROR_REPORT:
                pr_err("%s: rx ACK_ERR_PACLAGE\n", __func__);
                ret = 0;
+               break;
        case MIPI_DSI_RX_GENERIC_SHORT_READ_RESPONSE_1BYTE:
        case MIPI_DSI_RX_DCS_SHORT_READ_RESPONSE_1BYTE:
                ret = dsi_short_read1_resp(buf, msg);
index ee3ebcaa33f52f09cfe46dc34be7b7894b2753fa..0a40f3c64e8b3d05ce78af069f97851f8561c502 100644 (file)
@@ -462,7 +462,7 @@ struct drm_connector *msm_dsi_manager_connector_init(u8 id)
        struct msm_dsi *msm_dsi = dsi_mgr_get_dsi(id);
        struct drm_connector *connector = NULL;
        struct dsi_connector *dsi_connector;
-       int ret;
+       int ret, i;
 
        dsi_connector = devm_kzalloc(msm_dsi->dev->dev,
                                sizeof(*dsi_connector), GFP_KERNEL);
@@ -495,6 +495,10 @@ struct drm_connector *msm_dsi_manager_connector_init(u8 id)
        if (ret)
                goto fail;
 
+       for (i = 0; i < MSM_DSI_ENCODER_NUM; i++)
+               drm_mode_connector_attach_encoder(connector,
+                                               msm_dsi->encoders[i]);
+
        return connector;
 
 fail:
index 5f5a84f6074c73469a3a7e19e37fc1d5f55edab2..208f9d47f82ece1a98d7ea7d1bde3281ca1838c1 100644 (file)
@@ -132,7 +132,7 @@ ssize_t edp_aux_transfer(struct drm_dp_aux *drm_aux, struct drm_dp_aux_msg *msg)
        /* msg sanity check */
        if ((native && (msg->size > AUX_CMD_NATIVE_MAX)) ||
                (msg->size > AUX_CMD_I2C_MAX)) {
-               pr_err("%s: invalid msg: size(%d), request(%x)\n",
+               pr_err("%s: invalid msg: size(%zu), request(%x)\n",
                        __func__, msg->size, msg->request);
                return -EINVAL;
        }
@@ -155,7 +155,7 @@ ssize_t edp_aux_transfer(struct drm_dp_aux *drm_aux, struct drm_dp_aux_msg *msg)
                 */
                edp_write(aux->base + REG_EDP_AUX_TRANS_CTRL, 0);
                msm_edp_aux_ctrl(aux, 1);
-               pr_err("%s: aux timeout, %d\n", __func__, ret);
+               pr_err("%s: aux timeout, %zd\n", __func__, ret);
                goto unlock_exit;
        }
        DBG("completion");
index d8812e84da54332388ea9acad7d44403c27178e8..b4d1b469862a4c0281156f578492b8de43b2765e 100644 (file)
@@ -151,6 +151,8 @@ struct drm_connector *msm_edp_connector_init(struct msm_edp *edp)
        if (ret)
                goto fail;
 
+       drm_mode_connector_attach_encoder(connector, edp->encoder);
+
        return connector;
 
 fail:
index 0ec5abdba5c421b4a7604c4fa1b70ff8e3c129f9..29e52d7c61c06873c712254dd3ba4c14c0284f2d 100644 (file)
@@ -1149,12 +1149,13 @@ int msm_edp_ctrl_init(struct msm_edp *edp)
        ctrl->aux = msm_edp_aux_init(dev, ctrl->base, &ctrl->drm_aux);
        if (!ctrl->aux || !ctrl->drm_aux) {
                pr_err("%s:failed to init aux\n", __func__);
-               return ret;
+               return -ENOMEM;
        }
 
        ctrl->phy = msm_edp_phy_init(dev, ctrl->base);
        if (!ctrl->phy) {
                pr_err("%s:failed to init phy\n", __func__);
+               ret = -ENOMEM;
                goto err_destory_aux;
        }
 
index e001e6b2296a2ebd5cf602fbf0e3ba89f49ecf0d..8b9a7931b1624365dac35be9ca492b04967487b0 100644 (file)
@@ -72,14 +72,13 @@ const struct mdp5_cfg_hw msm8x74_config = {
                .base = { 0x12d00, 0x12e00, 0x12f00 },
        },
        .intf = {
-               .count = 4,
                .base = { 0x12500, 0x12700, 0x12900, 0x12b00 },
-       },
-       .intfs = {
-               [0] = INTF_eDP,
-               [1] = INTF_DSI,
-               [2] = INTF_DSI,
-               [3] = INTF_HDMI,
+               .connect = {
+                       [0] = INTF_eDP,
+                       [1] = INTF_DSI,
+                       [2] = INTF_DSI,
+                       [3] = INTF_HDMI,
+               },
        },
        .max_clk = 200000000,
 };
@@ -142,14 +141,13 @@ const struct mdp5_cfg_hw apq8084_config = {
                .base = { 0x12f00, 0x13000, 0x13100, 0x13200 },
        },
        .intf = {
-               .count = 5,
                .base = { 0x12500, 0x12700, 0x12900, 0x12b00, 0x12d00 },
-       },
-       .intfs = {
-               [0] = INTF_eDP,
-               [1] = INTF_DSI,
-               [2] = INTF_DSI,
-               [3] = INTF_HDMI,
+               .connect = {
+                       [0] = INTF_eDP,
+                       [1] = INTF_DSI,
+                       [2] = INTF_DSI,
+                       [3] = INTF_HDMI,
+               },
        },
        .max_clk = 320000000,
 };
@@ -196,10 +194,12 @@ const struct mdp5_cfg_hw msm8x16_config = {
 
        },
        .intf = {
-               .count = 1, /* INTF_1 */
-               .base = { 0x6B800 },
+               .base = { 0x00000, 0x6b800 },
+               .connect = {
+                       [0] = INTF_DISABLED,
+                       [1] = INTF_DSI,
+               },
        },
-       /* TODO enable .intfs[] with [1] = INTF_DSI, once DSI is implemented */
        .max_clk = 320000000,
 };
 
index 3a551b0892d847e50fb48054bfb6c409887fd40b..69349abe59f2a4a614a9a9379b5c26f232087a3c 100644 (file)
@@ -59,6 +59,11 @@ struct mdp5_smp_block {
 
 #define MDP5_INTF_NUM_MAX      5
 
+struct mdp5_intf_block {
+       uint32_t base[MAX_BASES];
+       u32 connect[MDP5_INTF_NUM_MAX]; /* array of enum mdp5_intf_type */
+};
+
 struct mdp5_cfg_hw {
        char  *name;
 
@@ -72,9 +77,7 @@ struct mdp5_cfg_hw {
        struct mdp5_sub_block dspp;
        struct mdp5_sub_block ad;
        struct mdp5_sub_block pp;
-       struct mdp5_sub_block intf;
-
-       u32 intfs[MDP5_INTF_NUM_MAX]; /* array of enum mdp5_intf_type */
+       struct mdp5_intf_block intf;
 
        uint32_t max_clk;
 };
index dfa8beb9343aaa171110adabb49c549e4143c0da..bbacf9d2b7383cc12d21bfeb48327c4b04604f56 100644 (file)
@@ -206,8 +206,8 @@ static struct drm_encoder *construct_encoder(struct mdp5_kms *mdp5_kms,
 
 static int get_dsi_id_from_intf(const struct mdp5_cfg_hw *hw_cfg, int intf_num)
 {
-       const int intf_cnt = hw_cfg->intf.count;
-       const u32 *intfs = hw_cfg->intfs;
+       const enum mdp5_intf_type *intfs = hw_cfg->intf.connect;
+       const int intf_cnt = ARRAY_SIZE(hw_cfg->intf.connect);
        int id = 0, i;
 
        for (i = 0; i < intf_cnt; i++) {
@@ -228,7 +228,7 @@ static int modeset_init_intf(struct mdp5_kms *mdp5_kms, int intf_num)
        struct msm_drm_private *priv = dev->dev_private;
        const struct mdp5_cfg_hw *hw_cfg =
                                        mdp5_cfg_get_hw_config(mdp5_kms->cfg);
-       enum mdp5_intf_type intf_type = hw_cfg->intfs[intf_num];
+       enum mdp5_intf_type intf_type = hw_cfg->intf.connect[intf_num];
        struct drm_encoder *encoder;
        int ret = 0;
 
@@ -365,7 +365,7 @@ static int modeset_init(struct mdp5_kms *mdp5_kms)
        /* Construct encoders and modeset initialize connector devices
         * for each external display interface.
         */
-       for (i = 0; i < ARRAY_SIZE(hw_cfg->intfs); i++) {
+       for (i = 0; i < ARRAY_SIZE(hw_cfg->intf.connect); i++) {
                ret = modeset_init_intf(mdp5_kms, i);
                if (ret)
                        goto fail;
@@ -514,8 +514,8 @@ struct msm_kms *mdp5_kms_init(struct drm_device *dev)
         */
        mdp5_enable(mdp5_kms);
        for (i = 0; i < MDP5_INTF_NUM_MAX; i++) {
-               if (!config->hw->intf.base[i] ||
-                               mdp5_cfg_intf_is_virtual(config->hw->intfs[i]))
+               if (mdp5_cfg_intf_is_virtual(config->hw->intf.connect[i]) ||
+                               !config->hw->intf.base[i])
                        continue;
                mdp5_write(mdp5_kms, REG_MDP5_INTF_TIMING_ENGINE_EN(i), 0);
        }
index 18a3d203b17439c2be3f0b0c72e033ed3996ae86..57b8f56ae9d06fb458266181a8344858e381e6b5 100644 (file)
@@ -273,7 +273,7 @@ static void set_scanout_locked(struct drm_plane *plane,
        mdp5_write(mdp5_kms, REG_MDP5_PIPE_SRC2_ADDR(pipe),
                        msm_framebuffer_iova(fb, mdp5_kms->id, 2));
        mdp5_write(mdp5_kms, REG_MDP5_PIPE_SRC3_ADDR(pipe),
-                       msm_framebuffer_iova(fb, mdp5_kms->id, 4));
+                       msm_framebuffer_iova(fb, mdp5_kms->id, 3));
 
        plane->fb = fb;
 }
index 47f4dd407671970fc247c4a9999dcccc03202c8e..c80a6bee2b18f373c9f2191bebbbb44e82db7663 100644 (file)
 
 static void msm_fb_output_poll_changed(struct drm_device *dev)
 {
+#ifdef CONFIG_DRM_MSM_FBDEV
        struct msm_drm_private *priv = dev->dev_private;
        if (priv->fbdev)
                drm_fb_helper_hotplug_event(priv->fbdev);
+#endif
 }
 
 static const struct drm_mode_config_funcs mode_config_funcs = {
@@ -94,7 +96,7 @@ void __iomem *msm_ioremap(struct platform_device *pdev, const char *name,
        }
 
        if (reglog)
-               printk(KERN_DEBUG "IO:region %s %08x %08lx\n", dbgname, (u32)ptr, size);
+               printk(KERN_DEBUG "IO:region %s %p %08lx\n", dbgname, ptr, size);
 
        return ptr;
 }
@@ -102,7 +104,7 @@ void __iomem *msm_ioremap(struct platform_device *pdev, const char *name,
 void msm_writel(u32 data, void __iomem *addr)
 {
        if (reglog)
-               printk(KERN_DEBUG "IO:W %08x %08x\n", (u32)addr, data);
+               printk(KERN_DEBUG "IO:W %p %08x\n", addr, data);
        writel(data, addr);
 }
 
@@ -110,7 +112,7 @@ u32 msm_readl(const void __iomem *addr)
 {
        u32 val = readl(addr);
        if (reglog)
-               printk(KERN_ERR "IO:R %08x %08x\n", (u32)addr, val);
+               printk(KERN_ERR "IO:R %p %08x\n", addr, val);
        return val;
 }
 
@@ -143,8 +145,8 @@ static int msm_unload(struct drm_device *dev)
        if (gpu) {
                mutex_lock(&dev->struct_mutex);
                gpu->funcs->pm_suspend(gpu);
-               gpu->funcs->destroy(gpu);
                mutex_unlock(&dev->struct_mutex);
+               gpu->funcs->destroy(gpu);
        }
 
        if (priv->vram.paddr) {
@@ -177,7 +179,7 @@ static int get_mdp_ver(struct platform_device *pdev)
        const struct of_device_id *match;
        match = of_match_node(match_types, dev->of_node);
        if (match)
-               return (int)match->data;
+               return (int)(unsigned long)match->data;
 #endif
        return 4;
 }
@@ -216,7 +218,7 @@ static int msm_init_vram(struct drm_device *dev)
                if (ret)
                        return ret;
                size = r.end - r.start;
-               DRM_INFO("using VRAM carveout: %lx@%08x\n", size, r.start);
+               DRM_INFO("using VRAM carveout: %lx@%pa\n", size, &r.start);
        } else
 #endif
 
@@ -283,10 +285,6 @@ static int msm_load(struct drm_device *dev, unsigned long flags)
 
        drm_mode_config_init(dev);
 
-       ret = msm_init_vram(dev);
-       if (ret)
-               goto fail;
-
        platform_set_drvdata(pdev, dev);
 
        /* Bind all our sub-components: */
@@ -294,6 +292,10 @@ static int msm_load(struct drm_device *dev, unsigned long flags)
        if (ret)
                return ret;
 
+       ret = msm_init_vram(dev);
+       if (ret)
+               goto fail;
+
        switch (get_mdp_ver(pdev)) {
        case 4:
                kms = mdp4_kms_init(dev);
@@ -419,9 +421,11 @@ static void msm_preclose(struct drm_device *dev, struct drm_file *file)
 
 static void msm_lastclose(struct drm_device *dev)
 {
+#ifdef CONFIG_DRM_MSM_FBDEV
        struct msm_drm_private *priv = dev->dev_private;
        if (priv->fbdev)
                drm_fb_helper_restore_fbdev_mode_unlocked(priv->fbdev);
+#endif
 }
 
 static irqreturn_t msm_irq(int irq, void *arg)
index 6b573e612f270bcbcc9e1d92cd3e3318fc80cb98..121713281417a92fc2270c7f907a082a1e0c4a87 100644 (file)
@@ -172,8 +172,8 @@ struct drm_framebuffer *msm_framebuffer_init(struct drm_device *dev,
 {
        struct msm_drm_private *priv = dev->dev_private;
        struct msm_kms *kms = priv->kms;
-       struct msm_framebuffer *msm_fb;
-       struct drm_framebuffer *fb = NULL;
+       struct msm_framebuffer *msm_fb = NULL;
+       struct drm_framebuffer *fb;
        const struct msm_format *format;
        int ret, i, n;
        unsigned int hsub, vsub;
@@ -239,8 +239,7 @@ struct drm_framebuffer *msm_framebuffer_init(struct drm_device *dev,
        return fb;
 
 fail:
-       if (fb)
-               msm_framebuffer_destroy(fb);
+       kfree(msm_fb);
 
        return ERR_PTR(ret);
 }
index 479d8af72bcb77d822ea92614ea3b91601e9ac6d..52839769eb6c091ba9f64a73e72d89191a3615cb 100644 (file)
@@ -483,7 +483,7 @@ void msm_gem_describe(struct drm_gem_object *obj, struct seq_file *m)
        uint64_t off = drm_vma_node_start(&obj->vma_node);
 
        WARN_ON(!mutex_is_locked(&dev->struct_mutex));
-       seq_printf(m, "%08x: %c(r=%u,w=%u) %2d (%2d) %08llx %p %d\n",
+       seq_printf(m, "%08x: %c(r=%u,w=%u) %2d (%2d) %08llx %p %zu\n",
                        msm_obj->flags, is_active(msm_obj) ? 'A' : 'I',
                        msm_obj->read_fence, msm_obj->write_fence,
                        obj->name, obj->refcount.refcount.counter,
index 7acdaa5688b77e89f3afa786da19903d0d0c7b6d..7ac2f1997e4a4cbe4e57003f001928bba8a2c490 100644 (file)
@@ -60,7 +60,7 @@ static int msm_iommu_map(struct msm_mmu *mmu, uint32_t iova,
                u32 pa = sg_phys(sg) - sg->offset;
                size_t bytes = sg->length + sg->offset;
 
-               VERB("map[%d]: %08x %08x(%x)", i, iova, pa, bytes);
+               VERB("map[%d]: %08x %08x(%zx)", i, iova, pa, bytes);
 
                ret = iommu_map(domain, da, pa, bytes, prot);
                if (ret)
@@ -99,7 +99,7 @@ static int msm_iommu_unmap(struct msm_mmu *mmu, uint32_t iova,
                if (unmapped < bytes)
                        return unmapped;
 
-               VERB("unmap[%d]: %08x(%x)", i, iova, bytes);
+               VERB("unmap[%d]: %08x(%zx)", i, iova, bytes);
 
                BUG_ON(!PAGE_ALIGNED(bytes));
 
index 8171537dd7d127f9c104bb9417bf5b71a4bf91d8..1f14b908b22136117eb2b37179d05abfedce2b13 100644 (file)
@@ -56,6 +56,6 @@ fail:
 void msm_ringbuffer_destroy(struct msm_ringbuffer *ring)
 {
        if (ring->bo)
-               drm_gem_object_unreference(ring->bo);
+               drm_gem_object_unreference_unlocked(ring->bo);
        kfree(ring);
 }
index 0b5af0fe86598c613f923b2a74e1a81e065dbd89..64f8b2f687d29bb206ae1fe461706fbf1be3fe12 100644 (file)
@@ -14,7 +14,7 @@
 
 #define FERMI_TWOD_A                                                 0x0000902d
 
-#define FERMI_MEMORY_TO_MEMORY_FORMAT_A                              0x0000903d
+#define FERMI_MEMORY_TO_MEMORY_FORMAT_A                              0x00009039
 
 #define KEPLER_INLINE_TO_MEMORY_A                                    0x0000a040
 #define KEPLER_INLINE_TO_MEMORY_B                                    0x0000a140
index 2f5eadd12a9b611b5d6c790d1ea8bd39a7606736..fdb1dcf16a595ad6adabb27fd1db86c7b4797b9b 100644 (file)
@@ -329,7 +329,6 @@ gm204_gr_init(struct nvkm_object *object)
        nv_mask(priv, 0x419cc0, 0x00000008, 0x00000008);
 
        for (gpc = 0; gpc < priv->gpc_nr; gpc++) {
-       printk(KERN_ERR "ppc %d %d\n", gpc, priv->ppc_nr[gpc]);
                for (ppc = 0; ppc < priv->ppc_nr[gpc]; ppc++)
                        nv_wr32(priv, PPC_UNIT(gpc, ppc, 0x038), 0xc0000000);
                nv_wr32(priv, GPC_UNIT(gpc, 0x0420), 0xc0000000);
index e8778c67578ee41bcc490eca56b544137ea1ef53..c61102f708055ecf739077e1a1436dcd12ff70cb 100644 (file)
@@ -90,12 +90,14 @@ gf100_devinit_disable(struct nvkm_devinit *devinit)
        return disable;
 }
 
-static int
+int
 gf100_devinit_ctor(struct nvkm_object *parent, struct nvkm_object *engine,
                   struct nvkm_oclass *oclass, void *data, u32 size,
                   struct nvkm_object **pobject)
 {
+       struct nvkm_devinit_impl *impl = (void *)oclass;
        struct nv50_devinit_priv *priv;
+       u64 disable;
        int ret;
 
        ret = nvkm_devinit_create(parent, engine, oclass, &priv);
@@ -103,7 +105,8 @@ gf100_devinit_ctor(struct nvkm_object *parent, struct nvkm_object *engine,
        if (ret)
                return ret;
 
-       if (nv_rd32(priv, 0x022500) & 0x00000001)
+       disable = impl->disable(&priv->base);
+       if (disable & (1ULL << NVDEV_ENGINE_DISP))
                priv->base.post = true;
 
        return 0;
index b345a53e881dc6e0f84fa188dfb32d50c90a675e..87ca0ece37b4209114ed36fb8260907e922d4ba4 100644 (file)
@@ -48,7 +48,7 @@ struct nvkm_oclass *
 gm107_devinit_oclass = &(struct nvkm_devinit_impl) {
        .base.handle = NV_SUBDEV(DEVINIT, 0x07),
        .base.ofuncs = &(struct nvkm_ofuncs) {
-               .ctor = nv50_devinit_ctor,
+               .ctor = gf100_devinit_ctor,
                .dtor = _nvkm_devinit_dtor,
                .init = nv50_devinit_init,
                .fini = _nvkm_devinit_fini,
index 535172c5f1ad0fda328eff542db8024afac00c02..1076fcf0d71614e89cf279234da7412557dc17ed 100644 (file)
@@ -161,7 +161,7 @@ struct nvkm_oclass *
 gm204_devinit_oclass = &(struct nvkm_devinit_impl) {
        .base.handle = NV_SUBDEV(DEVINIT, 0x07),
        .base.ofuncs = &(struct nvkm_ofuncs) {
-               .ctor = nv50_devinit_ctor,
+               .ctor = gf100_devinit_ctor,
                .dtor = _nvkm_devinit_dtor,
                .init = nv50_devinit_init,
                .fini = _nvkm_devinit_fini,
index b882b65ff3cd2031ae6e9ccf18b1987b972846d3..9243521c80ac22de306f8b1c7113260765ebd12a 100644 (file)
@@ -15,6 +15,9 @@ int  nv50_devinit_pll_set(struct nvkm_devinit *, u32, u32);
 
 int  gt215_devinit_pll_set(struct nvkm_devinit *, u32, u32);
 
+int  gf100_devinit_ctor(struct nvkm_object *, struct nvkm_object *,
+                       struct nvkm_oclass *, void *, u32,
+                       struct nvkm_object **);
 int  gf100_devinit_pll_set(struct nvkm_devinit *, u32, u32);
 
 u64  gm107_devinit_disable(struct nvkm_devinit *);
index 3e3290c203c625d781f7dfacc13977c50c54d34b..b435c859dcbc3a76d7590f0cd1a6a785230037cf 100644 (file)
@@ -421,19 +421,21 @@ bool radeon_dp_getdpcd(struct radeon_connector *radeon_connector)
 {
        struct radeon_connector_atom_dig *dig_connector = radeon_connector->con_priv;
        u8 msg[DP_DPCD_SIZE];
-       int ret;
+       int ret, i;
 
-       ret = drm_dp_dpcd_read(&radeon_connector->ddc_bus->aux, DP_DPCD_REV, msg,
-                              DP_DPCD_SIZE);
-       if (ret > 0) {
-               memcpy(dig_connector->dpcd, msg, DP_DPCD_SIZE);
+       for (i = 0; i < 7; i++) {
+               ret = drm_dp_dpcd_read(&radeon_connector->ddc_bus->aux, DP_DPCD_REV, msg,
+                                      DP_DPCD_SIZE);
+               if (ret == DP_DPCD_SIZE) {
+                       memcpy(dig_connector->dpcd, msg, DP_DPCD_SIZE);
 
-               DRM_DEBUG_KMS("DPCD: %*ph\n", (int)sizeof(dig_connector->dpcd),
-                             dig_connector->dpcd);
+                       DRM_DEBUG_KMS("DPCD: %*ph\n", (int)sizeof(dig_connector->dpcd),
+                                     dig_connector->dpcd);
 
-               radeon_dp_probe_oui(radeon_connector);
+                       radeon_dp_probe_oui(radeon_connector);
 
-               return true;
+                       return true;
+               }
        }
        dig_connector->dpcd[0] = 0;
        return false;
index f57c1ab617bc877b4576e828ee203381626b177c..dd39f434b4a7eccf1446ff5cd1857a2cf5de972d 100644 (file)
@@ -1761,17 +1761,15 @@ radeon_atom_encoder_dpms(struct drm_encoder *encoder, int mode)
        struct drm_device *dev = encoder->dev;
        struct radeon_device *rdev = dev->dev_private;
        struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
-       struct drm_connector *connector = radeon_get_connector_for_encoder(encoder);
        int encoder_mode = atombios_get_encoder_mode(encoder);
 
        DRM_DEBUG_KMS("encoder dpms %d to mode %d, devices %08x, active_devices %08x\n",
                  radeon_encoder->encoder_id, mode, radeon_encoder->devices,
                  radeon_encoder->active_device);
 
-       if (connector && (radeon_audio != 0) &&
+       if ((radeon_audio != 0) &&
            ((encoder_mode == ATOM_ENCODER_MODE_HDMI) ||
-            (ENCODER_MODE_IS_DP(encoder_mode) &&
-             drm_detect_monitor_audio(radeon_connector_edid(connector)))))
+            ENCODER_MODE_IS_DP(encoder_mode)))
                radeon_audio_dpms(encoder, mode);
 
        switch (radeon_encoder->encoder_id) {
index 28faea9996f9e111d6b35e547587025aa93c3089..ba50f3c1c2e0332024959c46ebb99a877e7893b1 100644 (file)
@@ -5837,7 +5837,7 @@ static int cik_pcie_gart_enable(struct radeon_device *rdev)
        /* restore context1-15 */
        /* set vm size, must be a multiple of 4 */
        WREG32(VM_CONTEXT1_PAGE_TABLE_START_ADDR, 0);
-       WREG32(VM_CONTEXT1_PAGE_TABLE_END_ADDR, rdev->vm_manager.max_pfn);
+       WREG32(VM_CONTEXT1_PAGE_TABLE_END_ADDR, rdev->vm_manager.max_pfn - 1);
        for (i = 1; i < 16; i++) {
                if (i < 8)
                        WREG32(VM_CONTEXT0_PAGE_TABLE_BASE_ADDR + (i << 2),
index f04205170b8a5942d73437ada72437bc18d028a8..cfa3a84a2af03c100741cb7e5b352781adf60b00 100644 (file)
@@ -173,7 +173,7 @@ void dce3_2_hdmi_update_acr(struct drm_encoder *encoder, long offset,
        struct drm_device *dev = encoder->dev;
        struct radeon_device *rdev = dev->dev_private;
 
-       WREG32(HDMI0_ACR_PACKET_CONTROL + offset,
+       WREG32(DCE3_HDMI0_ACR_PACKET_CONTROL + offset,
                HDMI0_ACR_SOURCE |              /* select SW CTS value */
                HDMI0_ACR_AUTO_SEND);   /* allow hw to sent ACR packets when required */
 
index 3adc2afe32aa6be372abcdd925001bbc79176745..68fd9fc677e35f1ca161295694301ec21c089e4d 100644 (file)
@@ -295,28 +295,3 @@ void dce6_dp_audio_set_dto(struct radeon_device *rdev,
                WREG32(DCCG_AUDIO_DTO1_MODULE, clock);
        }
 }
-
-void dce6_dp_enable(struct drm_encoder *encoder, bool enable)
-{
-       struct drm_device *dev = encoder->dev;
-       struct radeon_device *rdev = dev->dev_private;
-       struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
-       struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv;
-
-       if (!dig || !dig->afmt)
-               return;
-
-       if (enable) {
-               WREG32(EVERGREEN_DP_SEC_TIMESTAMP + dig->afmt->offset,
-                      EVERGREEN_DP_SEC_TIMESTAMP_MODE(1));
-               WREG32(EVERGREEN_DP_SEC_CNTL + dig->afmt->offset,
-                      EVERGREEN_DP_SEC_ASP_ENABLE |            /* Audio packet transmission */
-                      EVERGREEN_DP_SEC_ATP_ENABLE |            /* Audio timestamp packet transmission */
-                      EVERGREEN_DP_SEC_AIP_ENABLE |            /* Audio infoframe packet transmission */
-                      EVERGREEN_DP_SEC_STREAM_ENABLE); /* Master enable for secondary stream engine */
-       } else {
-               WREG32(EVERGREEN_DP_SEC_CNTL + dig->afmt->offset, 0);
-       }
-
-       dig->afmt->enabled = enable;
-}
index c18d4ecbd95d02baa907d4d15b6da43f282f4e67..9953356fe2637cfacdc2ba41e8ecd082d65213ff 100644 (file)
@@ -219,13 +219,9 @@ void evergreen_set_avi_packet(struct radeon_device *rdev, u32 offset,
        WREG32(AFMT_AVI_INFO3 + offset,
                frame[0xC] | (frame[0xD] << 8) | (buffer[1] << 24));
 
-       WREG32_OR(HDMI_INFOFRAME_CONTROL0 + offset,
-               HDMI_AVI_INFO_SEND |    /* enable AVI info frames */
-               HDMI_AVI_INFO_CONT);    /* required for audio info values to be updated */
-
        WREG32_P(HDMI_INFOFRAME_CONTROL1 + offset,
-               HDMI_AVI_INFO_LINE(2),  /* anything other than 0 */
-               ~HDMI_AVI_INFO_LINE_MASK);
+                HDMI_AVI_INFO_LINE(2), /* anything other than 0 */
+                ~HDMI_AVI_INFO_LINE_MASK);
 }
 
 void dce4_hdmi_audio_set_dto(struct radeon_device *rdev,
@@ -370,9 +366,13 @@ void dce4_set_audio_packet(struct drm_encoder *encoder, u32 offset)
        WREG32(AFMT_AUDIO_PACKET_CONTROL2 + offset,
                AFMT_AUDIO_CHANNEL_ENABLE(0xff));
 
+       WREG32(HDMI_AUDIO_PACKET_CONTROL + offset,
+              HDMI_AUDIO_DELAY_EN(1) | /* set the default audio delay */
+              HDMI_AUDIO_PACKETS_PER_LINE(3)); /* should be suffient for all audio modes and small enough for all hblanks */
+
        /* allow 60958 channel status and send audio packets fields to be updated */
-       WREG32(AFMT_AUDIO_PACKET_CONTROL + offset,
-               AFMT_AUDIO_SAMPLE_SEND | AFMT_RESET_FIFO_WHEN_AUDIO_DIS | AFMT_60958_CS_UPDATE);
+       WREG32_OR(AFMT_AUDIO_PACKET_CONTROL + offset,
+                 AFMT_RESET_FIFO_WHEN_AUDIO_DIS | AFMT_60958_CS_UPDATE);
 }
 
 
@@ -398,17 +398,26 @@ void evergreen_hdmi_enable(struct drm_encoder *encoder, bool enable)
                return;
 
        if (enable) {
-               WREG32(HDMI_INFOFRAME_CONTROL1 + dig->afmt->offset,
-                      HDMI_AUDIO_INFO_LINE(2)); /* anything other than 0 */
-
-               WREG32(HDMI_AUDIO_PACKET_CONTROL + dig->afmt->offset,
-                      HDMI_AUDIO_DELAY_EN(1) | /* set the default audio delay */
-                      HDMI_AUDIO_PACKETS_PER_LINE(3)); /* should be suffient for all audio modes and small enough for all hblanks */
+               struct drm_connector *connector = radeon_get_connector_for_encoder(encoder);
 
-               WREG32(HDMI_INFOFRAME_CONTROL0 + dig->afmt->offset,
-                      HDMI_AUDIO_INFO_SEND | /* enable audio info frames (frames won't be set until audio is enabled) */
-                      HDMI_AUDIO_INFO_CONT); /* required for audio info values to be updated */
+               if (connector && drm_detect_monitor_audio(radeon_connector_edid(connector))) {
+                       WREG32(HDMI_INFOFRAME_CONTROL0 + dig->afmt->offset,
+                              HDMI_AVI_INFO_SEND | /* enable AVI info frames */
+                              HDMI_AVI_INFO_CONT | /* required for audio info values to be updated */
+                              HDMI_AUDIO_INFO_SEND | /* enable audio info frames (frames won't be set until audio is enabled) */
+                              HDMI_AUDIO_INFO_CONT); /* required for audio info values to be updated */
+                       WREG32_OR(AFMT_AUDIO_PACKET_CONTROL + dig->afmt->offset,
+                                 AFMT_AUDIO_SAMPLE_SEND);
+               } else {
+                       WREG32(HDMI_INFOFRAME_CONTROL0 + dig->afmt->offset,
+                              HDMI_AVI_INFO_SEND | /* enable AVI info frames */
+                              HDMI_AVI_INFO_CONT); /* required for audio info values to be updated */
+                       WREG32_AND(AFMT_AUDIO_PACKET_CONTROL + dig->afmt->offset,
+                                  ~AFMT_AUDIO_SAMPLE_SEND);
+               }
        } else {
+               WREG32_AND(AFMT_AUDIO_PACKET_CONTROL + dig->afmt->offset,
+                          ~AFMT_AUDIO_SAMPLE_SEND);
                WREG32(HDMI_INFOFRAME_CONTROL0 + dig->afmt->offset, 0);
        }
 
@@ -424,20 +433,25 @@ void evergreen_dp_enable(struct drm_encoder *encoder, bool enable)
        struct radeon_device *rdev = dev->dev_private;
        struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
        struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv;
+       struct drm_connector *connector = radeon_get_connector_for_encoder(encoder);
 
        if (!dig || !dig->afmt)
                return;
 
-       if (enable) {
+       if (enable && connector &&
+           drm_detect_monitor_audio(radeon_connector_edid(connector))) {
                struct drm_connector *connector = radeon_get_connector_for_encoder(encoder);
                struct radeon_connector *radeon_connector = to_radeon_connector(connector);
                struct radeon_connector_atom_dig *dig_connector;
                uint32_t val;
 
+               WREG32_OR(AFMT_AUDIO_PACKET_CONTROL + dig->afmt->offset,
+                         AFMT_AUDIO_SAMPLE_SEND);
+
                WREG32(EVERGREEN_DP_SEC_TIMESTAMP + dig->afmt->offset,
                       EVERGREEN_DP_SEC_TIMESTAMP_MODE(1));
 
-               if (radeon_connector->con_priv) {
+               if (!ASIC_IS_DCE6(rdev) && radeon_connector->con_priv) {
                        dig_connector = radeon_connector->con_priv;
                        val = RREG32(EVERGREEN_DP_SEC_AUD_N + dig->afmt->offset);
                        val &= ~EVERGREEN_DP_SEC_N_BASE_MULTIPLE(0xf);
@@ -457,6 +471,8 @@ void evergreen_dp_enable(struct drm_encoder *encoder, bool enable)
                        EVERGREEN_DP_SEC_STREAM_ENABLE);        /* Master enable for secondary stream engine */
        } else {
                WREG32(EVERGREEN_DP_SEC_CNTL + dig->afmt->offset, 0);
+               WREG32_AND(AFMT_AUDIO_PACKET_CONTROL + dig->afmt->offset,
+                          ~AFMT_AUDIO_SAMPLE_SEND);
        }
 
        dig->afmt->enabled = enable;
index e8a496ff007ee680d30a2bd688f30d094b58461c..64d3a771920db8a57a04cd343ba210d8ee2fefc7 100644 (file)
@@ -1301,7 +1301,8 @@ static int cayman_pcie_gart_enable(struct radeon_device *rdev)
         */
        for (i = 1; i < 8; i++) {
                WREG32(VM_CONTEXT0_PAGE_TABLE_START_ADDR + (i << 2), 0);
-               WREG32(VM_CONTEXT0_PAGE_TABLE_END_ADDR + (i << 2), rdev->vm_manager.max_pfn);
+               WREG32(VM_CONTEXT0_PAGE_TABLE_END_ADDR + (i << 2),
+                       rdev->vm_manager.max_pfn - 1);
                WREG32(VM_CONTEXT0_PAGE_TABLE_BASE_ADDR + (i << 2),
                       rdev->vm_manager.saved_table_addr[i]);
        }
index dd6606b8e23ca9a3bfd3f7be414b17d01af2aacb..e85894ade95c44ab61d73f58f6452efb01bee0da 100644 (file)
@@ -228,12 +228,13 @@ void r600_set_avi_packet(struct radeon_device *rdev, u32 offset,
        WREG32(HDMI0_AVI_INFO3 + offset,
                frame[0xC] | (frame[0xD] << 8) | (buffer[1] << 24));
 
+       WREG32_OR(HDMI0_INFOFRAME_CONTROL1 + offset,
+                 HDMI0_AVI_INFO_LINE(2));      /* anything other than 0 */
+
        WREG32_OR(HDMI0_INFOFRAME_CONTROL0 + offset,
-               HDMI0_AVI_INFO_SEND |   /* enable AVI info frames */
-               HDMI0_AVI_INFO_CONT);   /* send AVI info frames every frame/field */
+                 HDMI0_AVI_INFO_SEND | /* enable AVI info frames */
+                 HDMI0_AVI_INFO_CONT); /* send AVI info frames every frame/field */
 
-       WREG32_OR(HDMI0_INFOFRAME_CONTROL1 + offset,
-               HDMI0_AVI_INFO_LINE(2));        /* anything other than 0 */
 }
 
 /*
index d2abe481954fc14a8146c0f9db0f0a6e73816900..46eb0fa75a614307286446a99d7c1c2037973ab4 100644 (file)
@@ -1673,7 +1673,6 @@ struct radeon_uvd {
        struct radeon_bo        *vcpu_bo;
        void                    *cpu_addr;
        uint64_t                gpu_addr;
-       void                    *saved_bo;
        atomic_t                handles[RADEON_MAX_UVD_HANDLES];
        struct drm_file         *filp[RADEON_MAX_UVD_HANDLES];
        unsigned                img_size[RADEON_MAX_UVD_HANDLES];
index fafd8ce4d58fc6a844b9615aa3b013cf793123c6..8dbf5083c4ff795498e619d798890bcaa4dca1e1 100644 (file)
@@ -1202,7 +1202,7 @@ static struct radeon_asic rs780_asic = {
 static struct radeon_asic_ring rv770_uvd_ring = {
        .ib_execute = &uvd_v1_0_ib_execute,
        .emit_fence = &uvd_v2_2_fence_emit,
-       .emit_semaphore = &uvd_v1_0_semaphore_emit,
+       .emit_semaphore = &uvd_v2_2_semaphore_emit,
        .cs_parse = &radeon_uvd_cs_parse,
        .ring_test = &uvd_v1_0_ring_test,
        .ib_test = &uvd_v1_0_ib_test,
index cf0a90bb61cab3a7bce074a931440a3d12cfa115..a3ca8cd305c5c21541bae20820dbe3366f416706 100644 (file)
@@ -949,6 +949,10 @@ void uvd_v1_0_ib_execute(struct radeon_device *rdev, struct radeon_ib *ib);
 int uvd_v2_2_resume(struct radeon_device *rdev);
 void uvd_v2_2_fence_emit(struct radeon_device *rdev,
                         struct radeon_fence *fence);
+bool uvd_v2_2_semaphore_emit(struct radeon_device *rdev,
+                            struct radeon_ring *ring,
+                            struct radeon_semaphore *semaphore,
+                            bool emit_wait);
 
 /* uvd v3.1 */
 bool uvd_v3_1_semaphore_emit(struct radeon_device *rdev,
index 48d49e651a30cf94212fe2b4482178e7870ed029..25191f126f3bb63dffc5f812edf0b9fec335600b 100644 (file)
@@ -102,7 +102,6 @@ static void radeon_audio_dp_mode_set(struct drm_encoder *encoder,
 void r600_hdmi_enable(struct drm_encoder *encoder, bool enable);
 void evergreen_hdmi_enable(struct drm_encoder *encoder, bool enable);
 void evergreen_dp_enable(struct drm_encoder *encoder, bool enable);
-void dce6_dp_enable(struct drm_encoder *encoder, bool enable);
 
 static const u32 pin_offsets[7] =
 {
@@ -240,7 +239,7 @@ static struct radeon_audio_funcs dce6_dp_funcs = {
        .set_avi_packet = evergreen_set_avi_packet,
        .set_audio_packet = dce4_set_audio_packet,
        .mode_set = radeon_audio_dp_mode_set,
-       .dpms = dce6_dp_enable,
+       .dpms = evergreen_dp_enable,
 };
 
 static void radeon_audio_interface_init(struct radeon_device *rdev)
@@ -462,6 +461,10 @@ void radeon_audio_detect(struct drm_connector *connector,
                return;
 
        rdev = connector->encoder->dev->dev_private;
+
+       if (!radeon_audio_chipset_supported(rdev))
+               return;
+
        radeon_encoder = to_radeon_encoder(connector->encoder);
        dig = radeon_encoder->enc_priv;
 
index 4d0f96cc3da4488b0a324058533d26500011293f..ab39b85e0f76d4cd2f926594dd1e4bc1d83a56dd 100644 (file)
@@ -88,7 +88,7 @@ static int radeon_cs_parser_relocs(struct radeon_cs_parser *p)
        p->dma_reloc_idx = 0;
        /* FIXME: we assume that each relocs use 4 dwords */
        p->nrelocs = chunk->length_dw / 4;
-       p->relocs = kcalloc(p->nrelocs, sizeof(struct radeon_bo_list), GFP_KERNEL);
+       p->relocs = drm_calloc_large(p->nrelocs, sizeof(struct radeon_bo_list));
        if (p->relocs == NULL) {
                return -ENOMEM;
        }
@@ -428,7 +428,7 @@ static void radeon_cs_parser_fini(struct radeon_cs_parser *parser, int error, bo
                }
        }
        kfree(parser->track);
-       kfree(parser->relocs);
+       drm_free_large(parser->relocs);
        drm_free_large(parser->vm_bos);
        for (i = 0; i < parser->nchunks; i++)
                drm_free_large(parser->chunks[i].kdata);
index b7ca4c51462120fab3ab146dd74f653e8bcb91cb..a7fdfa4f0857b3a416e67d79007a1da731455b80 100644 (file)
@@ -1463,6 +1463,21 @@ int radeon_device_init(struct radeon_device *rdev,
        if (r)
                DRM_ERROR("ib ring test failed (%d).\n", r);
 
+       /*
+        * Turks/Thames GPU will freeze whole laptop if DPM is not restarted
+        * after the CP ring have chew one packet at least. Hence here we stop
+        * and restart DPM after the radeon_ib_ring_tests().
+        */
+       if (rdev->pm.dpm_enabled &&
+           (rdev->pm.pm_method == PM_METHOD_DPM) &&
+           (rdev->family == CHIP_TURKS) &&
+           (rdev->flags & RADEON_IS_MOBILITY)) {
+               mutex_lock(&rdev->pm.mutex);
+               radeon_dpm_disable(rdev);
+               radeon_dpm_enable(rdev);
+               mutex_unlock(&rdev->pm.mutex);
+       }
+
        if ((radeon_testing & 1)) {
                if (rdev->accel_working)
                        radeon_test_moves(rdev);
index bf1fecc6cceb2cba743bce902f26598f7156d03a..fcbd60bb03495740d435b7a33521ff698b171c40 100644 (file)
@@ -30,8 +30,6 @@
                            AUX_SW_RX_HPD_DISCON |           \
                            AUX_SW_RX_PARTIAL_BYTE |         \
                            AUX_SW_NON_AUX_MODE |            \
-                           AUX_SW_RX_MIN_COUNT_VIOL |       \
-                           AUX_SW_RX_INVALID_STOP |         \
                            AUX_SW_RX_SYNC_INVALID_L |       \
                            AUX_SW_RX_SYNC_INVALID_H |       \
                            AUX_SW_RX_INVALID_START |        \
index 1017338a49d9f49aaad6dc594d6ec1bef8a5f111..2b98ed3e684d706a07e3c43b6da9f2232143e580 100644 (file)
@@ -666,6 +666,9 @@ radeon_dp_mst_probe(struct radeon_connector *radeon_connector)
        int ret;
        u8 msg[1];
 
+       if (!radeon_mst)
+               return 0;
+
        if (dig_connector->dpcd[DP_DPCD_REV] < 0x12)
                return 0;
 
index 01701376b23987c624a8d48a899e065d10d4bb8b..eef006c4858499dd207c6eb70ad5fcbc05c53941 100644 (file)
@@ -135,28 +135,31 @@ static void radeon_mn_invalidate_range_start(struct mmu_notifier *mn,
        while (it) {
                struct radeon_mn_node *node;
                struct radeon_bo *bo;
-               int r;
+               long r;
 
                node = container_of(it, struct radeon_mn_node, it);
                it = interval_tree_iter_next(it, start, end);
 
                list_for_each_entry(bo, &node->bos, mn_list) {
 
+                       if (!bo->tbo.ttm || bo->tbo.ttm->state != tt_bound)
+                               continue;
+
                        r = radeon_bo_reserve(bo, true);
                        if (r) {
-                               DRM_ERROR("(%d) failed to reserve user bo\n", r);
+                               DRM_ERROR("(%ld) failed to reserve user bo\n", r);
                                continue;
                        }
 
                        r = reservation_object_wait_timeout_rcu(bo->tbo.resv,
                                true, false, MAX_SCHEDULE_TIMEOUT);
-                       if (r)
-                               DRM_ERROR("(%d) failed to wait for user bo\n", r);
+                       if (r <= 0)
+                               DRM_ERROR("(%ld) failed to wait for user bo\n", r);
 
                        radeon_ttm_placement_from_domain(bo, RADEON_GEM_DOMAIN_CPU);
                        r = ttm_bo_validate(&bo->tbo, &bo->placement, false, false);
                        if (r)
-                               DRM_ERROR("(%d) failed to validate user bo\n", r);
+                               DRM_ERROR("(%ld) failed to validate user bo\n", r);
 
                        radeon_bo_unreserve(bo);
                }
index b292aca0f342d53856ec3eaf982b71fd8b0a7fa8..edafd3c2b17028a73ff5128568c73adfaff0f85b 100644 (file)
@@ -591,8 +591,7 @@ static void radeon_ttm_tt_unpin_userptr(struct ttm_tt *ttm)
 {
        struct radeon_device *rdev = radeon_get_rdev(ttm->bdev);
        struct radeon_ttm_tt *gtt = (void *)ttm;
-       struct scatterlist *sg;
-       int i;
+       struct sg_page_iter sg_iter;
 
        int write = !(gtt->userflags & RADEON_GEM_USERPTR_READONLY);
        enum dma_data_direction direction = write ?
@@ -605,9 +604,8 @@ static void radeon_ttm_tt_unpin_userptr(struct ttm_tt *ttm)
        /* free the sg table and pages again */
        dma_unmap_sg(rdev->dev, ttm->sg->sgl, ttm->sg->nents, direction);
 
-       for_each_sg(ttm->sg->sgl, sg, ttm->sg->nents, i) {
-               struct page *page = sg_page(sg);
-
+       for_each_sg_page(ttm->sg->sgl, &sg_iter, ttm->sg->nents, 0) {
+               struct page *page = sg_page_iter_page(&sg_iter);
                if (!(gtt->userflags & RADEON_GEM_USERPTR_READONLY))
                        set_page_dirty(page);
 
index c10b2aec6450fa8ceb366a691ea0898aff14dcbc..6edcb54850922a87535a3440a24d0e316977cf05 100644 (file)
@@ -204,28 +204,32 @@ void radeon_uvd_fini(struct radeon_device *rdev)
 
 int radeon_uvd_suspend(struct radeon_device *rdev)
 {
-       unsigned size;
-       void *ptr;
-       int i;
+       int i, r;
 
        if (rdev->uvd.vcpu_bo == NULL)
                return 0;
 
-       for (i = 0; i < RADEON_MAX_UVD_HANDLES; ++i)
-               if (atomic_read(&rdev->uvd.handles[i]))
-                       break;
+       for (i = 0; i < RADEON_MAX_UVD_HANDLES; ++i) {
+               uint32_t handle = atomic_read(&rdev->uvd.handles[i]);
+               if (handle != 0) {
+                       struct radeon_fence *fence;
 
-       if (i == RADEON_MAX_UVD_HANDLES)
-               return 0;
+                       radeon_uvd_note_usage(rdev);
 
-       size = radeon_bo_size(rdev->uvd.vcpu_bo);
-       size -= rdev->uvd_fw->size;
+                       r = radeon_uvd_get_destroy_msg(rdev,
+                               R600_RING_TYPE_UVD_INDEX, handle, &fence);
+                       if (r) {
+                               DRM_ERROR("Error destroying UVD (%d)!\n", r);
+                               continue;
+                       }
 
-       ptr = rdev->uvd.cpu_addr;
-       ptr += rdev->uvd_fw->size;
+                       radeon_fence_wait(fence, false);
+                       radeon_fence_unref(&fence);
 
-       rdev->uvd.saved_bo = kmalloc(size, GFP_KERNEL);
-       memcpy(rdev->uvd.saved_bo, ptr, size);
+                       rdev->uvd.filp[i] = NULL;
+                       atomic_set(&rdev->uvd.handles[i], 0);
+               }
+       }
 
        return 0;
 }
@@ -246,12 +250,7 @@ int radeon_uvd_resume(struct radeon_device *rdev)
        ptr = rdev->uvd.cpu_addr;
        ptr += rdev->uvd_fw->size;
 
-       if (rdev->uvd.saved_bo != NULL) {
-               memcpy(ptr, rdev->uvd.saved_bo, size);
-               kfree(rdev->uvd.saved_bo);
-               rdev->uvd.saved_bo = NULL;
-       } else
-               memset(ptr, 0, size);
+       memset(ptr, 0, size);
 
        return 0;
 }
@@ -396,6 +395,29 @@ static int radeon_uvd_cs_msg_decode(uint32_t *msg, unsigned buf_sizes[])
        return 0;
 }
 
+static int radeon_uvd_validate_codec(struct radeon_cs_parser *p,
+                                    unsigned stream_type)
+{
+       switch (stream_type) {
+       case 0: /* H264 */
+       case 1: /* VC1 */
+               /* always supported */
+               return 0;
+
+       case 3: /* MPEG2 */
+       case 4: /* MPEG4 */
+               /* only since UVD 3 */
+               if (p->rdev->family >= CHIP_PALM)
+                       return 0;
+
+               /* fall through */
+       default:
+               DRM_ERROR("UVD codec not supported by hardware %d!\n",
+                         stream_type);
+               return -EINVAL;
+       }
+}
+
 static int radeon_uvd_cs_msg(struct radeon_cs_parser *p, struct radeon_bo *bo,
                             unsigned offset, unsigned buf_sizes[])
 {
@@ -436,50 +458,70 @@ static int radeon_uvd_cs_msg(struct radeon_cs_parser *p, struct radeon_bo *bo,
                return -EINVAL;
        }
 
-       if (msg_type == 1) {
-               /* it's a decode msg, calc buffer sizes */
-               r = radeon_uvd_cs_msg_decode(msg, buf_sizes);
-               /* calc image size (width * height) */
-               img_size = msg[6] * msg[7];
+       switch (msg_type) {
+       case 0:
+               /* it's a create msg, calc image size (width * height) */
+               img_size = msg[7] * msg[8];
+
+               r = radeon_uvd_validate_codec(p, msg[4]);
                radeon_bo_kunmap(bo);
                if (r)
                        return r;
 
-       } else if (msg_type == 2) {
+               /* try to alloc a new handle */
+               for (i = 0; i < RADEON_MAX_UVD_HANDLES; ++i) {
+                       if (atomic_read(&p->rdev->uvd.handles[i]) == handle) {
+                               DRM_ERROR("Handle 0x%x already in use!\n", handle);
+                               return -EINVAL;
+                       }
+
+                       if (!atomic_cmpxchg(&p->rdev->uvd.handles[i], 0, handle)) {
+                               p->rdev->uvd.filp[i] = p->filp;
+                               p->rdev->uvd.img_size[i] = img_size;
+                               return 0;
+                       }
+               }
+
+               DRM_ERROR("No more free UVD handles!\n");
+               return -EINVAL;
+
+       case 1:
+               /* it's a decode msg, validate codec and calc buffer sizes */
+               r = radeon_uvd_validate_codec(p, msg[4]);
+               if (!r)
+                       r = radeon_uvd_cs_msg_decode(msg, buf_sizes);
+               radeon_bo_kunmap(bo);
+               if (r)
+                       return r;
+
+               /* validate the handle */
+               for (i = 0; i < RADEON_MAX_UVD_HANDLES; ++i) {
+                       if (atomic_read(&p->rdev->uvd.handles[i]) == handle) {
+                               if (p->rdev->uvd.filp[i] != p->filp) {
+                                       DRM_ERROR("UVD handle collision detected!\n");
+                                       return -EINVAL;
+                               }
+                               return 0;
+                       }
+               }
+
+               DRM_ERROR("Invalid UVD handle 0x%x!\n", handle);
+               return -ENOENT;
+
+       case 2:
                /* it's a destroy msg, free the handle */
                for (i = 0; i < RADEON_MAX_UVD_HANDLES; ++i)
                        atomic_cmpxchg(&p->rdev->uvd.handles[i], handle, 0);
                radeon_bo_kunmap(bo);
                return 0;
-       } else {
-               /* it's a create msg, calc image size (width * height) */
-               img_size = msg[7] * msg[8];
-               radeon_bo_kunmap(bo);
 
-               if (msg_type != 0) {
-                       DRM_ERROR("Illegal UVD message type (%d)!\n", msg_type);
-                       return -EINVAL;
-               }
-
-               /* it's a create msg, no special handling needed */
-       }
-
-       /* create or decode, validate the handle */
-       for (i = 0; i < RADEON_MAX_UVD_HANDLES; ++i) {
-               if (atomic_read(&p->rdev->uvd.handles[i]) == handle)
-                       return 0;
-       }
+       default:
 
-       /* handle not found try to alloc a new one */
-       for (i = 0; i < RADEON_MAX_UVD_HANDLES; ++i) {
-               if (!atomic_cmpxchg(&p->rdev->uvd.handles[i], 0, handle)) {
-                       p->rdev->uvd.filp[i] = p->filp;
-                       p->rdev->uvd.img_size[i] = img_size;
-                       return 0;
-               }
+               DRM_ERROR("Illegal UVD message type (%d)!\n", msg_type);
+               return -EINVAL;
        }
 
-       DRM_ERROR("No more free UVD handles!\n");
+       BUG();
        return -EINVAL;
 }
 
index 24f849f888bbdf93c6518a271105f8bb0d302368..0de5711ac508842b2a1d70550c755f0f85cd6d71 100644 (file)
@@ -493,18 +493,27 @@ int radeon_vce_cs_reloc(struct radeon_cs_parser *p, int lo, int hi,
  *
  * @p: parser context
  * @handle: handle to validate
+ * @allocated: allocated a new handle?
  *
  * Validates the handle and return the found session index or -EINVAL
  * we we don't have another free session index.
  */
-int radeon_vce_validate_handle(struct radeon_cs_parser *p, uint32_t handle)
+static int radeon_vce_validate_handle(struct radeon_cs_parser *p,
+                                     uint32_t handle, bool *allocated)
 {
        unsigned i;
 
+       *allocated = false;
+
        /* validate the handle */
        for (i = 0; i < RADEON_MAX_VCE_HANDLES; ++i) {
-               if (atomic_read(&p->rdev->vce.handles[i]) == handle)
+               if (atomic_read(&p->rdev->vce.handles[i]) == handle) {
+                       if (p->rdev->vce.filp[i] != p->filp) {
+                               DRM_ERROR("VCE handle collision detected!\n");
+                               return -EINVAL;
+                       }
                        return i;
+               }
        }
 
        /* handle not found try to alloc a new one */
@@ -512,6 +521,7 @@ int radeon_vce_validate_handle(struct radeon_cs_parser *p, uint32_t handle)
                if (!atomic_cmpxchg(&p->rdev->vce.handles[i], 0, handle)) {
                        p->rdev->vce.filp[i] = p->filp;
                        p->rdev->vce.img_size[i] = 0;
+                       *allocated = true;
                        return i;
                }
        }
@@ -529,10 +539,10 @@ int radeon_vce_validate_handle(struct radeon_cs_parser *p, uint32_t handle)
 int radeon_vce_cs_parse(struct radeon_cs_parser *p)
 {
        int session_idx = -1;
-       bool destroyed = false;
+       bool destroyed = false, created = false, allocated = false;
        uint32_t tmp, handle = 0;
        uint32_t *size = &tmp;
-       int i, r;
+       int i, r = 0;
 
        while (p->idx < p->chunk_ib->length_dw) {
                uint32_t len = radeon_get_ib_value(p, p->idx);
@@ -540,18 +550,21 @@ int radeon_vce_cs_parse(struct radeon_cs_parser *p)
 
                if ((len < 8) || (len & 3)) {
                        DRM_ERROR("invalid VCE command length (%d)!\n", len);
-                       return -EINVAL;
+                       r = -EINVAL;
+                       goto out;
                }
 
                if (destroyed) {
                        DRM_ERROR("No other command allowed after destroy!\n");
-                       return -EINVAL;
+                       r = -EINVAL;
+                       goto out;
                }
 
                switch (cmd) {
                case 0x00000001: // session
                        handle = radeon_get_ib_value(p, p->idx + 2);
-                       session_idx = radeon_vce_validate_handle(p, handle);
+                       session_idx = radeon_vce_validate_handle(p, handle,
+                                                                &allocated);
                        if (session_idx < 0)
                                return session_idx;
                        size = &p->rdev->vce.img_size[session_idx];
@@ -561,6 +574,13 @@ int radeon_vce_cs_parse(struct radeon_cs_parser *p)
                        break;
 
                case 0x01000001: // create
+                       created = true;
+                       if (!allocated) {
+                               DRM_ERROR("Handle already in use!\n");
+                               r = -EINVAL;
+                               goto out;
+                       }
+
                        *size = radeon_get_ib_value(p, p->idx + 8) *
                                radeon_get_ib_value(p, p->idx + 10) *
                                8 * 3 / 2;
@@ -578,12 +598,12 @@ int radeon_vce_cs_parse(struct radeon_cs_parser *p)
                        r = radeon_vce_cs_reloc(p, p->idx + 10, p->idx + 9,
                                                *size);
                        if (r)
-                               return r;
+                               goto out;
 
                        r = radeon_vce_cs_reloc(p, p->idx + 12, p->idx + 11,
                                                *size / 3);
                        if (r)
-                               return r;
+                               goto out;
                        break;
 
                case 0x02000001: // destroy
@@ -594,7 +614,7 @@ int radeon_vce_cs_parse(struct radeon_cs_parser *p)
                        r = radeon_vce_cs_reloc(p, p->idx + 3, p->idx + 2,
                                                *size * 2);
                        if (r)
-                               return r;
+                               goto out;
                        break;
 
                case 0x05000004: // video bitstream buffer
@@ -602,36 +622,47 @@ int radeon_vce_cs_parse(struct radeon_cs_parser *p)
                        r = radeon_vce_cs_reloc(p, p->idx + 3, p->idx + 2,
                                                tmp);
                        if (r)
-                               return r;
+                               goto out;
                        break;
 
                case 0x05000005: // feedback buffer
                        r = radeon_vce_cs_reloc(p, p->idx + 3, p->idx + 2,
                                                4096);
                        if (r)
-                               return r;
+                               goto out;
                        break;
 
                default:
                        DRM_ERROR("invalid VCE command (0x%x)!\n", cmd);
-                       return -EINVAL;
+                       r = -EINVAL;
+                       goto out;
                }
 
                if (session_idx == -1) {
                        DRM_ERROR("no session command at start of IB\n");
-                       return -EINVAL;
+                       r = -EINVAL;
+                       goto out;
                }
 
                p->idx += len / 4;
        }
 
-       if (destroyed) {
-               /* IB contains a destroy msg, free the handle */
+       if (allocated && !created) {
+               DRM_ERROR("New session without create command!\n");
+               r = -ENOENT;
+       }
+
+out:
+       if ((!r && destroyed) || (r && allocated)) {
+               /*
+                * IB contains a destroy msg or we have allocated an
+                * handle and got an error, anyway free the handle
+                */
                for (i = 0; i < RADEON_MAX_VCE_HANDLES; ++i)
                        atomic_cmpxchg(&p->rdev->vce.handles[i], handle, 0);
        }
 
-       return 0;
+       return r;
 }
 
 /**
index 2a5a4a9e772d6668ee844b94c61219a0c3100340..9c3377ca17b75ecd2092e4fd78a2238c126d88f1 100644 (file)
@@ -458,14 +458,16 @@ int radeon_vm_bo_set_addr(struct radeon_device *rdev,
                /* make sure object fit at this offset */
                eoffset = soffset + size;
                if (soffset >= eoffset) {
-                       return -EINVAL;
+                       r = -EINVAL;
+                       goto error_unreserve;
                }
 
                last_pfn = eoffset / RADEON_GPU_PAGE_SIZE;
                if (last_pfn > rdev->vm_manager.max_pfn) {
                        dev_err(rdev->dev, "va above limit (0x%08X > 0x%08X)\n",
                                last_pfn, rdev->vm_manager.max_pfn);
-                       return -EINVAL;
+                       r = -EINVAL;
+                       goto error_unreserve;
                }
 
        } else {
@@ -473,6 +475,24 @@ int radeon_vm_bo_set_addr(struct radeon_device *rdev,
        }
 
        mutex_lock(&vm->mutex);
+       soffset /= RADEON_GPU_PAGE_SIZE;
+       eoffset /= RADEON_GPU_PAGE_SIZE;
+       if (soffset || eoffset) {
+               struct interval_tree_node *it;
+               it = interval_tree_iter_first(&vm->va, soffset, eoffset - 1);
+               if (it && it != &bo_va->it) {
+                       struct radeon_bo_va *tmp;
+                       tmp = container_of(it, struct radeon_bo_va, it);
+                       /* bo and tmp overlap, invalid offset */
+                       dev_err(rdev->dev, "bo %p va 0x%010Lx conflict with "
+                               "(bo %p 0x%010lx 0x%010lx)\n", bo_va->bo,
+                               soffset, tmp->bo, tmp->it.start, tmp->it.last);
+                       mutex_unlock(&vm->mutex);
+                       r = -EINVAL;
+                       goto error_unreserve;
+               }
+       }
+
        if (bo_va->it.start || bo_va->it.last) {
                if (bo_va->addr) {
                        /* add a clone of the bo_va to clear the old address */
@@ -480,7 +500,8 @@ int radeon_vm_bo_set_addr(struct radeon_device *rdev,
                        tmp = kzalloc(sizeof(struct radeon_bo_va), GFP_KERNEL);
                        if (!tmp) {
                                mutex_unlock(&vm->mutex);
-                               return -ENOMEM;
+                               r = -ENOMEM;
+                               goto error_unreserve;
                        }
                        tmp->it.start = bo_va->it.start;
                        tmp->it.last = bo_va->it.last;
@@ -490,6 +511,8 @@ int radeon_vm_bo_set_addr(struct radeon_device *rdev,
                        spin_lock(&vm->status_lock);
                        list_add(&tmp->vm_status, &vm->freed);
                        spin_unlock(&vm->status_lock);
+
+                       bo_va->addr = 0;
                }
 
                interval_tree_remove(&bo_va->it, &vm->va);
@@ -497,21 +520,7 @@ int radeon_vm_bo_set_addr(struct radeon_device *rdev,
                bo_va->it.last = 0;
        }
 
-       soffset /= RADEON_GPU_PAGE_SIZE;
-       eoffset /= RADEON_GPU_PAGE_SIZE;
        if (soffset || eoffset) {
-               struct interval_tree_node *it;
-               it = interval_tree_iter_first(&vm->va, soffset, eoffset - 1);
-               if (it) {
-                       struct radeon_bo_va *tmp;
-                       tmp = container_of(it, struct radeon_bo_va, it);
-                       /* bo and tmp overlap, invalid offset */
-                       dev_err(rdev->dev, "bo %p va 0x%010Lx conflict with "
-                               "(bo %p 0x%010lx 0x%010lx)\n", bo_va->bo,
-                               soffset, tmp->bo, tmp->it.start, tmp->it.last);
-                       mutex_unlock(&vm->mutex);
-                       return -EINVAL;
-               }
                bo_va->it.start = soffset;
                bo_va->it.last = eoffset - 1;
                interval_tree_insert(&bo_va->it, &vm->va);
@@ -550,7 +559,6 @@ int radeon_vm_bo_set_addr(struct radeon_device *rdev,
                r = radeon_vm_clear_bo(rdev, pt);
                if (r) {
                        radeon_bo_unref(&pt);
-                       radeon_bo_reserve(bo_va->bo, false);
                        return r;
                }
 
@@ -570,6 +578,10 @@ int radeon_vm_bo_set_addr(struct radeon_device *rdev,
 
        mutex_unlock(&vm->mutex);
        return 0;
+
+error_unreserve:
+       radeon_bo_unreserve(bo_va->bo);
+       return r;
 }
 
 /**
@@ -1107,7 +1119,8 @@ void radeon_vm_bo_rmv(struct radeon_device *rdev,
        list_del(&bo_va->bo_list);
 
        mutex_lock(&vm->mutex);
-       interval_tree_remove(&bo_va->it, &vm->va);
+       if (bo_va->it.start || bo_va->it.last)
+               interval_tree_remove(&bo_va->it, &vm->va);
        spin_lock(&vm->status_lock);
        list_del(&bo_va->vm_status);
 
index 3cf1e2921545f9a980569925088d720e347505d1..9ef2064b1c9cdfc0392c6154258366387a1bf95a 100644 (file)
                         ((n) & 0x3FFF) << 16)
 
 /* UVD */
+#define UVD_SEMA_ADDR_LOW                              0xef00
+#define UVD_SEMA_ADDR_HIGH                             0xef04
+#define UVD_SEMA_CMD                                   0xef08
 #define UVD_GPCOM_VCPU_CMD                             0xef0c
 #define UVD_GPCOM_VCPU_DATA0                           0xef10
 #define UVD_GPCOM_VCPU_DATA1                           0xef14
index b1d74bc375d82f665dbb4455db5aa84db0c8d8dc..4c679b802bc851db50450ee759c3d3f314d0bfdf 100644 (file)
@@ -4318,7 +4318,7 @@ static int si_pcie_gart_enable(struct radeon_device *rdev)
        /* empty context1-15 */
        /* set vm size, must be a multiple of 4 */
        WREG32(VM_CONTEXT1_PAGE_TABLE_START_ADDR, 0);
-       WREG32(VM_CONTEXT1_PAGE_TABLE_END_ADDR, rdev->vm_manager.max_pfn);
+       WREG32(VM_CONTEXT1_PAGE_TABLE_END_ADDR, rdev->vm_manager.max_pfn - 1);
        /* Assign the pt base to something valid for now; the pts used for
         * the VMs are determined by the application and setup and assigned
         * on the fly in the vm part of radeon_gart.c
index b35bccfeef79c402c33b6406e0e70755fd4098ad..ff8b83f5e929a851943e61e76fc3d45b2967a2a3 100644 (file)
@@ -2924,6 +2924,7 @@ struct si_dpm_quirk {
 static struct si_dpm_quirk si_dpm_quirk_list[] = {
        /* PITCAIRN - https://bugs.freedesktop.org/show_bug.cgi?id=76490 */
        { PCI_VENDOR_ID_ATI, 0x6810, 0x1462, 0x3036, 0, 120000 },
+       { PCI_VENDOR_ID_ATI, 0x6811, 0x174b, 0xe271, 0, 120000 },
        { 0, 0, 0, 0 },
 };
 
index e72b3cb593589876cc8999e8ab913cbf886b64f3..c6b1cbca47fc8e2b423a52fd4affe6d9532678af 100644 (file)
@@ -466,18 +466,8 @@ bool uvd_v1_0_semaphore_emit(struct radeon_device *rdev,
                             struct radeon_semaphore *semaphore,
                             bool emit_wait)
 {
-       uint64_t addr = semaphore->gpu_addr;
-
-       radeon_ring_write(ring, PACKET0(UVD_SEMA_ADDR_LOW, 0));
-       radeon_ring_write(ring, (addr >> 3) & 0x000FFFFF);
-
-       radeon_ring_write(ring, PACKET0(UVD_SEMA_ADDR_HIGH, 0));
-       radeon_ring_write(ring, (addr >> 23) & 0x000FFFFF);
-
-       radeon_ring_write(ring, PACKET0(UVD_SEMA_CMD, 0));
-       radeon_ring_write(ring, emit_wait ? 1 : 0);
-
-       return true;
+       /* disable semaphores for UVD V1 hardware */
+       return false;
 }
 
 /**
index 89193519f8a1faf32fd7fe9013ddd8107cafd977..7ed778cec7c6400206674f9c8e2264734dba4b0a 100644 (file)
@@ -59,6 +59,35 @@ void uvd_v2_2_fence_emit(struct radeon_device *rdev,
        radeon_ring_write(ring, 2);
 }
 
+/**
+ * uvd_v2_2_semaphore_emit - emit semaphore command
+ *
+ * @rdev: radeon_device pointer
+ * @ring: radeon_ring pointer
+ * @semaphore: semaphore to emit commands for
+ * @emit_wait: true if we should emit a wait command
+ *
+ * Emit a semaphore command (either wait or signal) to the UVD ring.
+ */
+bool uvd_v2_2_semaphore_emit(struct radeon_device *rdev,
+                            struct radeon_ring *ring,
+                            struct radeon_semaphore *semaphore,
+                            bool emit_wait)
+{
+       uint64_t addr = semaphore->gpu_addr;
+
+       radeon_ring_write(ring, PACKET0(UVD_SEMA_ADDR_LOW, 0));
+       radeon_ring_write(ring, (addr >> 3) & 0x000FFFFF);
+
+       radeon_ring_write(ring, PACKET0(UVD_SEMA_ADDR_HIGH, 0));
+       radeon_ring_write(ring, (addr >> 23) & 0x000FFFFF);
+
+       radeon_ring_write(ring, PACKET0(UVD_SEMA_CMD, 0));
+       radeon_ring_write(ring, emit_wait ? 1 : 0);
+
+       return true;
+}
+
 /**
  * uvd_v2_2_resume - memory controller programming
  *
index ccb0ce073ef2af6f2233fbc88428ea176dbea855..4557f335a8a56f243ad4aa326a1826572116d3a5 100644 (file)
@@ -1409,7 +1409,7 @@ static int vop_bind(struct device *dev, struct device *master, void *data)
        struct vop *vop;
        struct resource *res;
        size_t alloc_size;
-       int ret;
+       int ret, irq;
 
        of_id = of_match_device(vop_driver_dt_match, dev);
        vop_data = of_id->data;
@@ -1445,11 +1445,12 @@ static int vop_bind(struct device *dev, struct device *master, void *data)
                return ret;
        }
 
-       vop->irq = platform_get_irq(pdev, 0);
-       if (vop->irq < 0) {
+       irq = platform_get_irq(pdev, 0);
+       if (irq < 0) {
                dev_err(dev, "cannot find irq for vop\n");
-               return vop->irq;
+               return irq;
        }
+       vop->irq = (unsigned int)irq;
 
        spin_lock_init(&vop->reg_lock);
        spin_lock_init(&vop->irq_lock);
index 1833abd7d3aafa38c796cc5acb7d3bb9a8356c86..bfad15a913a023b0f0f3272118fe822fc9097d0c 100644 (file)
@@ -173,7 +173,6 @@ static int tegra_drm_load(struct drm_device *drm, unsigned long flags)
        drm->irq_enabled = true;
 
        /* syncpoints are used for full 32-bit hardware VBLANK counters */
-       drm->vblank_disable_immediate = true;
        drm->max_vblank_count = 0xffffffff;
 
        err = drm_vblank_init(drm, drm->mode_config.num_crtc);
index 1055cb79096c6b508d568fd3c07255b05bf8b56c..3f4c7b8420287188288641e66b9f82addd5b21f3 100644 (file)
@@ -1,4 +1,4 @@
 ccflags-y := -Iinclude/drm
-vgem-y := vgem_drv.o vgem_dma_buf.o
+vgem-y := vgem_drv.o
 
 obj-$(CONFIG_DRM_VGEM) += vgem.o
diff --git a/drivers/gpu/drm/vgem/vgem_dma_buf.c b/drivers/gpu/drm/vgem/vgem_dma_buf.c
deleted file mode 100644 (file)
index 0254438..0000000
+++ /dev/null
@@ -1,94 +0,0 @@
-/*
- * Copyright Â© 2012 Intel Corporation
- * Copyright Â© 2014 The Chromium OS Authors
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice (including the next
- * paragraph) shall be included in all copies or substantial portions of the
- * Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
- * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
- * IN THE SOFTWARE.
- *
- * Authors:
- *    Ben Widawsky <ben@bwidawsk.net>
- *
- */
-
-#include <linux/dma-buf.h>
-#include "vgem_drv.h"
-
-struct sg_table *vgem_gem_prime_get_sg_table(struct drm_gem_object *gobj)
-{
-       struct drm_vgem_gem_object *obj = to_vgem_bo(gobj);
-       BUG_ON(obj->pages == NULL);
-
-       return drm_prime_pages_to_sg(obj->pages, obj->base.size / PAGE_SIZE);
-}
-
-int vgem_gem_prime_pin(struct drm_gem_object *gobj)
-{
-       struct drm_vgem_gem_object *obj = to_vgem_bo(gobj);
-       return vgem_gem_get_pages(obj);
-}
-
-void vgem_gem_prime_unpin(struct drm_gem_object *gobj)
-{
-       struct drm_vgem_gem_object *obj = to_vgem_bo(gobj);
-       vgem_gem_put_pages(obj);
-}
-
-void *vgem_gem_prime_vmap(struct drm_gem_object *gobj)
-{
-       struct drm_vgem_gem_object *obj = to_vgem_bo(gobj);
-       BUG_ON(obj->pages == NULL);
-
-       return vmap(obj->pages, obj->base.size / PAGE_SIZE, 0, PAGE_KERNEL);
-}
-
-void vgem_gem_prime_vunmap(struct drm_gem_object *obj, void *vaddr)
-{
-       vunmap(vaddr);
-}
-
-struct drm_gem_object *vgem_gem_prime_import(struct drm_device *dev,
-                                            struct dma_buf *dma_buf)
-{
-       struct drm_vgem_gem_object *obj = NULL;
-       int ret;
-
-       obj = kzalloc(sizeof(*obj), GFP_KERNEL);
-       if (obj == NULL) {
-               ret = -ENOMEM;
-               goto fail;
-       }
-
-       ret = drm_gem_object_init(dev, &obj->base, dma_buf->size);
-       if (ret) {
-               ret = -ENOMEM;
-               goto fail_free;
-       }
-
-       get_dma_buf(dma_buf);
-
-       obj->base.dma_buf = dma_buf;
-       obj->use_dma_buf = true;
-
-       return &obj->base;
-
-fail_free:
-       kfree(obj);
-fail:
-       return ERR_PTR(ret);
-}
index cb3b43525b2de3e512c2000dec12b1e92c923e2c..7a207ca547be24011fc0b89284ed7e728ded26f8 100644 (file)
@@ -302,22 +302,13 @@ static const struct file_operations vgem_driver_fops = {
 };
 
 static struct drm_driver vgem_driver = {
-       .driver_features                = DRIVER_GEM | DRIVER_PRIME,
+       .driver_features                = DRIVER_GEM,
        .gem_free_object                = vgem_gem_free_object,
        .gem_vm_ops                     = &vgem_gem_vm_ops,
        .ioctls                         = vgem_ioctls,
        .fops                           = &vgem_driver_fops,
        .dumb_create                    = vgem_gem_dumb_create,
        .dumb_map_offset                = vgem_gem_dumb_map,
-       .prime_handle_to_fd             = drm_gem_prime_handle_to_fd,
-       .prime_fd_to_handle             = drm_gem_prime_fd_to_handle,
-       .gem_prime_export               = drm_gem_prime_export,
-       .gem_prime_import               = vgem_gem_prime_import,
-       .gem_prime_pin                  = vgem_gem_prime_pin,
-       .gem_prime_unpin                = vgem_gem_prime_unpin,
-       .gem_prime_get_sg_table         = vgem_gem_prime_get_sg_table,
-       .gem_prime_vmap                 = vgem_gem_prime_vmap,
-       .gem_prime_vunmap               = vgem_gem_prime_vunmap,
        .name   = DRIVER_NAME,
        .desc   = DRIVER_DESC,
        .date   = DRIVER_DATE,
index 57ab4d8f41f92b083299d786d62f0ebca00577a1..e9f92f7ee275cf791b8f81d8a53c1a8f3c45ba8e 100644 (file)
@@ -43,15 +43,4 @@ struct drm_vgem_gem_object {
 extern void vgem_gem_put_pages(struct drm_vgem_gem_object *obj);
 extern int vgem_gem_get_pages(struct drm_vgem_gem_object *obj);
 
-/* vgem_dma_buf.c */
-extern struct sg_table *vgem_gem_prime_get_sg_table(
-                       struct drm_gem_object *gobj);
-extern int vgem_gem_prime_pin(struct drm_gem_object *gobj);
-extern void vgem_gem_prime_unpin(struct drm_gem_object *gobj);
-extern void *vgem_gem_prime_vmap(struct drm_gem_object *gobj);
-extern void vgem_gem_prime_vunmap(struct drm_gem_object *obj, void *vaddr);
-extern struct drm_gem_object *vgem_gem_prime_import(struct drm_device *dev,
-                                                   struct dma_buf *dma_buf);
-
-
 #endif
index 41f167e4d75fdeec20d795b566fdeba1c642497f..7ce93d927f62d8d029c3f32cefd3dc3f3b2f36dd 100644 (file)
 #define USB_DEVICE_ID_ATEN_2PORTKVM    0x2204
 #define USB_DEVICE_ID_ATEN_4PORTKVM    0x2205
 #define USB_DEVICE_ID_ATEN_4PORTKVMC   0x2208
+#define USB_DEVICE_ID_ATEN_CS682       0x2213
 
 #define USB_VENDOR_ID_ATMEL            0x03eb
 #define USB_DEVICE_ID_ATMEL_MULTITOUCH 0x211c
index b3cf6fd4be96473ba62ebbbf92d1522c024a509e..5fd530acf747c50fcd5bfbd51d19d3271e5d716b 100644 (file)
@@ -44,7 +44,6 @@ MODULE_PARM_DESC(disable_raw_mode,
 /* bits 1..20 are reserved for classes */
 #define HIDPP_QUIRK_DELAYED_INIT               BIT(21)
 #define HIDPP_QUIRK_WTP_PHYSICAL_BUTTONS       BIT(22)
-#define HIDPP_QUIRK_MULTI_INPUT                        BIT(23)
 
 /*
  * There are two hidpp protocols in use, the first version hidpp10 is known
@@ -706,12 +705,6 @@ static int wtp_input_mapping(struct hid_device *hdev, struct hid_input *hi,
                struct hid_field *field, struct hid_usage *usage,
                unsigned long **bit, int *max)
 {
-       struct hidpp_device *hidpp = hid_get_drvdata(hdev);
-
-       if ((hidpp->quirks & HIDPP_QUIRK_MULTI_INPUT) &&
-           (field->application == HID_GD_KEYBOARD))
-               return 0;
-
        return -1;
 }
 
@@ -720,10 +713,6 @@ static void wtp_populate_input(struct hidpp_device *hidpp,
 {
        struct wtp_data *wd = hidpp->private_data;
 
-       if ((hidpp->quirks & HIDPP_QUIRK_MULTI_INPUT) && origin_is_hid_core)
-               /* this is the generic hid-input call */
-               return;
-
        __set_bit(EV_ABS, input_dev->evbit);
        __set_bit(EV_KEY, input_dev->evbit);
        __clear_bit(EV_REL, input_dev->evbit);
@@ -1245,10 +1234,6 @@ static int hidpp_probe(struct hid_device *hdev, const struct hid_device_id *id)
        if (hidpp->quirks & HIDPP_QUIRK_DELAYED_INIT)
                connect_mask &= ~HID_CONNECT_HIDINPUT;
 
-       /* Re-enable hidinput for multi-input devices */
-       if (hidpp->quirks & HIDPP_QUIRK_MULTI_INPUT)
-               connect_mask |= HID_CONNECT_HIDINPUT;
-
        ret = hid_hw_start(hdev, connect_mask);
        if (ret) {
                hid_err(hdev, "%s:hid_hw_start returned error\n", __func__);
@@ -1296,11 +1281,6 @@ static const struct hid_device_id hidpp_devices[] = {
          HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_LOGITECH,
                USB_DEVICE_ID_LOGITECH_T651),
          .driver_data = HIDPP_QUIRK_CLASS_WTP },
-       { /* Keyboard TK820 */
-         HID_DEVICE(BUS_USB, HID_GROUP_LOGITECH_DJ_DEVICE,
-               USB_VENDOR_ID_LOGITECH, 0x4102),
-         .driver_data = HIDPP_QUIRK_DELAYED_INIT | HIDPP_QUIRK_MULTI_INPUT |
-                        HIDPP_QUIRK_CLASS_WTP },
 
        { HID_DEVICE(BUS_USB, HID_GROUP_LOGITECH_DJ_DEVICE,
                USB_VENDOR_ID_LOGITECH, HID_ANY_ID)},
index c3f6f1e311ea0d98da6981669e292e085552a927..090a1ba0abb6fb1f6c937a7190980bbd8f318a0c 100644 (file)
@@ -294,7 +294,7 @@ int sensor_hub_input_attr_get_raw_value(struct hid_sensor_hub_device *hsdev,
        if (!report)
                return -EINVAL;
 
-       mutex_lock(&hsdev->mutex);
+       mutex_lock(hsdev->mutex_ptr);
        if (flag == SENSOR_HUB_SYNC) {
                memset(&hsdev->pending, 0, sizeof(hsdev->pending));
                init_completion(&hsdev->pending.ready);
@@ -328,7 +328,7 @@ int sensor_hub_input_attr_get_raw_value(struct hid_sensor_hub_device *hsdev,
                kfree(hsdev->pending.raw_data);
                hsdev->pending.status = false;
        }
-       mutex_unlock(&hsdev->mutex);
+       mutex_unlock(hsdev->mutex_ptr);
 
        return ret_val;
 }
@@ -667,7 +667,14 @@ static int sensor_hub_probe(struct hid_device *hdev,
                        hsdev->vendor_id = hdev->vendor;
                        hsdev->product_id = hdev->product;
                        hsdev->usage = collection->usage;
-                       mutex_init(&hsdev->mutex);
+                       hsdev->mutex_ptr = devm_kzalloc(&hdev->dev,
+                                                       sizeof(struct mutex),
+                                                       GFP_KERNEL);
+                       if (!hsdev->mutex_ptr) {
+                               ret = -ENOMEM;
+                               goto err_stop_hw;
+                       }
+                       mutex_init(hsdev->mutex_ptr);
                        hsdev->start_collection_index = i;
                        if (last_hsdev)
                                last_hsdev->end_collection_index = i;
index ab4dd952b6ba654d91d75523951f4f02cbfa1138..92d6cdf024607d848249e011d14f19e88d7c4a39 100644 (file)
@@ -862,6 +862,7 @@ static int i2c_hid_acpi_pdata(struct i2c_client *client,
        union acpi_object *obj;
        struct acpi_device *adev;
        acpi_handle handle;
+       int ret;
 
        handle = ACPI_HANDLE(&client->dev);
        if (!handle || acpi_bus_get_device(handle, &adev))
@@ -877,7 +878,9 @@ static int i2c_hid_acpi_pdata(struct i2c_client *client,
        pdata->hid_descriptor_address = obj->integer.value;
        ACPI_FREE(obj);
 
-       return acpi_dev_add_driver_gpios(adev, i2c_hid_acpi_gpios);
+       /* GPIOs are optional */
+       ret = acpi_dev_add_driver_gpios(adev, i2c_hid_acpi_gpios);
+       return ret < 0 && ret != -ENXIO ? ret : 0;
 }
 
 static const struct acpi_device_id i2c_hid_acpi_match[] = {
index a775143e6265e337597e2dd15e6c9d682c04354f..4696895eb708316944dac63092e959e4b1bb1765 100644 (file)
@@ -61,6 +61,7 @@ static const struct hid_blacklist {
        { USB_VENDOR_ID_ATEN, USB_DEVICE_ID_ATEN_2PORTKVM, HID_QUIRK_NOGET },
        { USB_VENDOR_ID_ATEN, USB_DEVICE_ID_ATEN_4PORTKVM, HID_QUIRK_NOGET },
        { USB_VENDOR_ID_ATEN, USB_DEVICE_ID_ATEN_4PORTKVMC, HID_QUIRK_NOGET },
+       { USB_VENDOR_ID_ATEN, USB_DEVICE_ID_ATEN_CS682, HID_QUIRK_NOGET },
        { USB_VENDOR_ID_CH, USB_DEVICE_ID_CH_FIGHTERSTICK, HID_QUIRK_NOGET },
        { USB_VENDOR_ID_CH, USB_DEVICE_ID_CH_COMBATSTICK, HID_QUIRK_NOGET },
        { USB_VENDOR_ID_CH, USB_DEVICE_ID_CH_FLIGHT_SIM_ECLIPSE_YOKE, HID_QUIRK_NOGET },
index fa54d329065945bade5b9048df9cb5a98c0bf7f2..adf959dcfa5df9da7bca7414e2d4ac74a35e1457 100644 (file)
@@ -1072,6 +1072,9 @@ static int wacom_wac_finger_count_touches(struct wacom_wac *wacom)
        int count = 0;
        int i;
 
+       if (!touch_max)
+               return 0;
+
        /* non-HID_GENERIC single touch input doesn't call this routine */
        if ((touch_max == 1) && (wacom->features.type == HID_GENERIC))
                return wacom->hid_data.tipswitch &&
index f3830db02d4637675cebbe7b6b5e185492571a1e..37f01702d08195b1a9bab1f82fe88434302556b9 100644 (file)
@@ -439,6 +439,7 @@ nct6683_create_attr_group(struct device *dev, struct sensor_template_group *tg,
                                 (*t)->dev_attr.attr.name, tg->base + i);
                        if ((*t)->s2) {
                                a2 = &su->u.a2;
+                               sysfs_attr_init(&a2->dev_attr.attr);
                                a2->dev_attr.attr.name = su->name;
                                a2->nr = (*t)->u.s.nr + i;
                                a2->index = (*t)->u.s.index;
@@ -449,6 +450,7 @@ nct6683_create_attr_group(struct device *dev, struct sensor_template_group *tg,
                                *attrs = &a2->dev_attr.attr;
                        } else {
                                a = &su->u.a1;
+                               sysfs_attr_init(&a->dev_attr.attr);
                                a->dev_attr.attr.name = su->name;
                                a->index = (*t)->u.index + i;
                                a->dev_attr.attr.mode =
index 4fcb481032992f475e8d196dc3a9dbcfa2407b30..bd1c99deac71b73dadf15615c1e8442027bccee9 100644 (file)
@@ -995,6 +995,7 @@ nct6775_create_attr_group(struct device *dev, struct sensor_template_group *tg,
                                 (*t)->dev_attr.attr.name, tg->base + i);
                        if ((*t)->s2) {
                                a2 = &su->u.a2;
+                               sysfs_attr_init(&a2->dev_attr.attr);
                                a2->dev_attr.attr.name = su->name;
                                a2->nr = (*t)->u.s.nr + i;
                                a2->index = (*t)->u.s.index;
@@ -1005,6 +1006,7 @@ nct6775_create_attr_group(struct device *dev, struct sensor_template_group *tg,
                                *attrs = &a2->dev_attr.attr;
                        } else {
                                a = &su->u.a1;
+                               sysfs_attr_init(&a->dev_attr.attr);
                                a->dev_attr.attr.name = su->name;
                                a->index = (*t)->u.index + i;
                                a->dev_attr.attr.mode =
index 112e4d45e4a0c31ff8234a36f008b629c71230a5..68800115876bf65867c187498902d0de6dcae687 100644 (file)
@@ -239,8 +239,10 @@ static struct ntc_thermistor_platform_data *
 ntc_thermistor_parse_dt(struct platform_device *pdev)
 {
        struct iio_channel *chan;
+       enum iio_chan_type type;
        struct device_node *np = pdev->dev.of_node;
        struct ntc_thermistor_platform_data *pdata;
+       int ret;
 
        if (!np)
                return NULL;
@@ -253,6 +255,13 @@ ntc_thermistor_parse_dt(struct platform_device *pdev)
        if (IS_ERR(chan))
                return ERR_CAST(chan);
 
+       ret = iio_get_channel_type(chan, &type);
+       if (ret < 0)
+               return ERR_PTR(ret);
+
+       if (type != IIO_VOLTAGE)
+               return ERR_PTR(-EINVAL);
+
        if (of_property_read_u32(np, "pullup-uv", &pdata->pullup_uv))
                return ERR_PTR(-ENODEV);
        if (of_property_read_u32(np, "pullup-ohm", &pdata->pullup_ohm))
index 99664ebc738d8003139135a89f07f97e3c6305e2..ccf4cffe0ee1dfac282b9afc6e28da5340aa51f3 100644 (file)
@@ -44,7 +44,7 @@
 #include <linux/sysfs.h>
 
 /* Addresses to scan */
-static const unsigned short normal_i2c[] = { 0x37, 0x48, 0x49, 0x4a, 0x4c, 0x4d,
+static const unsigned short normal_i2c[] = { 0x48, 0x49, 0x4a, 0x4c, 0x4d,
        0x4e, 0x4f, I2C_CLIENT_END };
 
 enum chips { tmp401, tmp411, tmp431, tmp432, tmp435 };
index 8fe78d08e01cf1551ea0eaf53f50d2185dfff809..7c6966434ee7b9a2707da849e56128af41c0baf5 100644 (file)
@@ -554,4 +554,4 @@ module_platform_driver(hix5hd2_i2c_driver);
 MODULE_DESCRIPTION("Hix5hd2 I2C Bus driver");
 MODULE_AUTHOR("Wei Yan <sledge.yanwei@huawei.com>");
 MODULE_LICENSE("GPL");
-MODULE_ALIAS("platform:i2c-hix5hd2");
+MODULE_ALIAS("platform:hix5hd2-i2c");
index 958c8db4ec30740e2d9aae00a7835256700d3424..297e9c9ac9432f5e645e06cf932710cd93c7f924 100644 (file)
@@ -1143,6 +1143,7 @@ static int s3c24xx_i2c_probe(struct platform_device *pdev)
                return -ENOMEM;
 
        i2c->quirks = s3c24xx_get_device_quirks(pdev);
+       i2c->sysreg = ERR_PTR(-ENOENT);
        if (pdata)
                memcpy(i2c->pdata, pdata, sizeof(*pdata));
        else
index a04c49f2a0118a887e22c16b9716656af6e87723..39ea67f9b066989ff901674cea38d2b1bb0ff2b3 100644 (file)
@@ -643,15 +643,6 @@ config BLK_DEV_TC86C001
        help
        This driver adds support for Toshiba TC86C001 GOKU-S chip.
 
-config BLK_DEV_CELLEB
-       tristate "Toshiba's Cell Reference Set IDE support"
-       depends on PPC_CELLEB
-       select BLK_DEV_IDEDMA_PCI
-       help
-         This driver provides support for the on-board IDE controller on
-         Toshiba Cell Reference Board.
-         If unsure, say Y.
-
 endif
 
 # TODO: BLK_DEV_IDEDMA_PCI -> BLK_DEV_IDEDMA_SFF
index a04ee82f1c8f5bf5bd712f90dd73744a37762e2a..2a8c417d4081087daa50d154844bcb65f6cb55c0 100644 (file)
@@ -38,7 +38,6 @@ obj-$(CONFIG_BLK_DEV_AEC62XX)         += aec62xx.o
 obj-$(CONFIG_BLK_DEV_ALI15X3)          += alim15x3.o
 obj-$(CONFIG_BLK_DEV_AMD74XX)          += amd74xx.o
 obj-$(CONFIG_BLK_DEV_ATIIXP)           += atiixp.o
-obj-$(CONFIG_BLK_DEV_CELLEB)           += scc_pata.o
 obj-$(CONFIG_BLK_DEV_CMD64X)           += cmd64x.o
 obj-$(CONFIG_BLK_DEV_CS5520)           += cs5520.o
 obj-$(CONFIG_BLK_DEV_CS5530)           += cs5530.o
diff --git a/drivers/ide/scc_pata.c b/drivers/ide/scc_pata.c
deleted file mode 100644 (file)
index 2a2d188..0000000
+++ /dev/null
@@ -1,887 +0,0 @@
-/*
- * Support for IDE interfaces on Celleb platform
- *
- * (C) Copyright 2006 TOSHIBA CORPORATION
- *
- * This code is based on drivers/ide/pci/siimage.c:
- * Copyright (C) 2001-2002     Andre Hedrick <andre@linux-ide.org>
- * Copyright (C) 2003          Red Hat
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- */
-
-#include <linux/types.h>
-#include <linux/module.h>
-#include <linux/pci.h>
-#include <linux/delay.h>
-#include <linux/ide.h>
-#include <linux/init.h>
-
-#define PCI_DEVICE_ID_TOSHIBA_SCC_ATA            0x01b4
-
-#define SCC_PATA_NAME           "scc IDE"
-
-#define TDVHSEL_MASTER          0x00000001
-#define TDVHSEL_SLAVE           0x00000004
-
-#define MODE_JCUSFEN            0x00000080
-
-#define CCKCTRL_ATARESET        0x00040000
-#define CCKCTRL_BUFCNT          0x00020000
-#define CCKCTRL_CRST            0x00010000
-#define CCKCTRL_OCLKEN          0x00000100
-#define CCKCTRL_ATACLKOEN       0x00000002
-#define CCKCTRL_LCLKEN          0x00000001
-
-#define QCHCD_IOS_SS           0x00000001
-
-#define QCHSD_STPDIAG          0x00020000
-
-#define INTMASK_MSK             0xD1000012
-#define INTSTS_SERROR          0x80000000
-#define INTSTS_PRERR           0x40000000
-#define INTSTS_RERR            0x10000000
-#define INTSTS_ICERR           0x01000000
-#define INTSTS_BMSINT          0x00000010
-#define INTSTS_BMHE            0x00000008
-#define INTSTS_IOIRQS           0x00000004
-#define INTSTS_INTRQ            0x00000002
-#define INTSTS_ACTEINT          0x00000001
-
-#define ECMODE_VALUE 0x01
-
-static struct scc_ports {
-       unsigned long ctl, dma;
-       struct ide_host *host;  /* for removing port from system */
-} scc_ports[MAX_HWIFS];
-
-/* PIO transfer mode  table */
-/* JCHST */
-static unsigned long JCHSTtbl[2][7] = {
-       {0x0E, 0x05, 0x02, 0x03, 0x02, 0x00, 0x00},   /* 100MHz */
-       {0x13, 0x07, 0x04, 0x04, 0x03, 0x00, 0x00}    /* 133MHz */
-};
-
-/* JCHHT */
-static unsigned long JCHHTtbl[2][7] = {
-       {0x0E, 0x02, 0x02, 0x02, 0x02, 0x00, 0x00},   /* 100MHz */
-       {0x13, 0x03, 0x03, 0x03, 0x03, 0x00, 0x00}    /* 133MHz */
-};
-
-/* JCHCT */
-static unsigned long JCHCTtbl[2][7] = {
-       {0x1D, 0x1D, 0x1C, 0x0B, 0x06, 0x00, 0x00},   /* 100MHz */
-       {0x27, 0x26, 0x26, 0x0E, 0x09, 0x00, 0x00}    /* 133MHz */
-};
-
-
-/* DMA transfer mode  table */
-/* JCHDCTM/JCHDCTS */
-static unsigned long JCHDCTxtbl[2][7] = {
-       {0x0A, 0x06, 0x04, 0x03, 0x01, 0x00, 0x00},   /* 100MHz */
-       {0x0E, 0x09, 0x06, 0x04, 0x02, 0x01, 0x00}    /* 133MHz */
-};
-
-/* JCSTWTM/JCSTWTS  */
-static unsigned long JCSTWTxtbl[2][7] = {
-       {0x06, 0x04, 0x03, 0x02, 0x02, 0x02, 0x00},   /* 100MHz */
-       {0x09, 0x06, 0x04, 0x02, 0x02, 0x02, 0x02}    /* 133MHz */
-};
-
-/* JCTSS */
-static unsigned long JCTSStbl[2][7] = {
-       {0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x00},   /* 100MHz */
-       {0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05}    /* 133MHz */
-};
-
-/* JCENVT */
-static unsigned long JCENVTtbl[2][7] = {
-       {0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00},   /* 100MHz */
-       {0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02}    /* 133MHz */
-};
-
-/* JCACTSELS/JCACTSELM */
-static unsigned long JCACTSELtbl[2][7] = {
-       {0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00},   /* 100MHz */
-       {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01}    /* 133MHz */
-};
-
-
-static u8 scc_ide_inb(unsigned long port)
-{
-       u32 data = in_be32((void*)port);
-       return (u8)data;
-}
-
-static void scc_exec_command(ide_hwif_t *hwif, u8 cmd)
-{
-       out_be32((void *)hwif->io_ports.command_addr, cmd);
-       eieio();
-       in_be32((void *)(hwif->dma_base + 0x01c));
-       eieio();
-}
-
-static u8 scc_read_status(ide_hwif_t *hwif)
-{
-       return (u8)in_be32((void *)hwif->io_ports.status_addr);
-}
-
-static u8 scc_read_altstatus(ide_hwif_t *hwif)
-{
-       return (u8)in_be32((void *)hwif->io_ports.ctl_addr);
-}
-
-static u8 scc_dma_sff_read_status(ide_hwif_t *hwif)
-{
-       return (u8)in_be32((void *)(hwif->dma_base + 4));
-}
-
-static void scc_write_devctl(ide_hwif_t *hwif, u8 ctl)
-{
-       out_be32((void *)hwif->io_ports.ctl_addr, ctl);
-       eieio();
-       in_be32((void *)(hwif->dma_base + 0x01c));
-       eieio();
-}
-
-static void scc_ide_insw(unsigned long port, void *addr, u32 count)
-{
-       u16 *ptr = (u16 *)addr;
-       while (count--) {
-               *ptr++ = le16_to_cpu(in_be32((void*)port));
-       }
-}
-
-static void scc_ide_insl(unsigned long port, void *addr, u32 count)
-{
-       u16 *ptr = (u16 *)addr;
-       while (count--) {
-               *ptr++ = le16_to_cpu(in_be32((void*)port));
-               *ptr++ = le16_to_cpu(in_be32((void*)port));
-       }
-}
-
-static void scc_ide_outb(u8 addr, unsigned long port)
-{
-       out_be32((void*)port, addr);
-}
-
-static void
-scc_ide_outsw(unsigned long port, void *addr, u32 count)
-{
-       u16 *ptr = (u16 *)addr;
-       while (count--) {
-               out_be32((void*)port, cpu_to_le16(*ptr++));
-       }
-}
-
-static void
-scc_ide_outsl(unsigned long port, void *addr, u32 count)
-{
-       u16 *ptr = (u16 *)addr;
-       while (count--) {
-               out_be32((void*)port, cpu_to_le16(*ptr++));
-               out_be32((void*)port, cpu_to_le16(*ptr++));
-       }
-}
-
-/**
- *     scc_set_pio_mode        -       set host controller for PIO mode
- *     @hwif: port
- *     @drive: drive
- *
- *     Load the timing settings for this device mode into the
- *     controller.
- */
-
-static void scc_set_pio_mode(ide_hwif_t *hwif, ide_drive_t *drive)
-{
-       struct scc_ports *ports = ide_get_hwifdata(hwif);
-       unsigned long ctl_base = ports->ctl;
-       unsigned long cckctrl_port = ctl_base + 0xff0;
-       unsigned long piosht_port = ctl_base + 0x000;
-       unsigned long pioct_port = ctl_base + 0x004;
-       unsigned long reg;
-       int offset;
-       const u8 pio = drive->pio_mode - XFER_PIO_0;
-
-       reg = in_be32((void __iomem *)cckctrl_port);
-       if (reg & CCKCTRL_ATACLKOEN) {
-               offset = 1; /* 133MHz */
-       } else {
-               offset = 0; /* 100MHz */
-       }
-       reg = JCHSTtbl[offset][pio] << 16 | JCHHTtbl[offset][pio];
-       out_be32((void __iomem *)piosht_port, reg);
-       reg = JCHCTtbl[offset][pio];
-       out_be32((void __iomem *)pioct_port, reg);
-}
-
-/**
- *     scc_set_dma_mode        -       set host controller for DMA mode
- *     @hwif: port
- *     @drive: drive
- *
- *     Load the timing settings for this device mode into the
- *     controller.
- */
-
-static void scc_set_dma_mode(ide_hwif_t *hwif, ide_drive_t *drive)
-{
-       struct scc_ports *ports = ide_get_hwifdata(hwif);
-       unsigned long ctl_base = ports->ctl;
-       unsigned long cckctrl_port = ctl_base + 0xff0;
-       unsigned long mdmact_port = ctl_base + 0x008;
-       unsigned long mcrcst_port = ctl_base + 0x00c;
-       unsigned long sdmact_port = ctl_base + 0x010;
-       unsigned long scrcst_port = ctl_base + 0x014;
-       unsigned long udenvt_port = ctl_base + 0x018;
-       unsigned long tdvhsel_port   = ctl_base + 0x020;
-       int is_slave = drive->dn & 1;
-       int offset, idx;
-       unsigned long reg;
-       unsigned long jcactsel;
-       const u8 speed = drive->dma_mode;
-
-       reg = in_be32((void __iomem *)cckctrl_port);
-       if (reg & CCKCTRL_ATACLKOEN) {
-               offset = 1; /* 133MHz */
-       } else {
-               offset = 0; /* 100MHz */
-       }
-
-       idx = speed - XFER_UDMA_0;
-
-       jcactsel = JCACTSELtbl[offset][idx];
-       if (is_slave) {
-               out_be32((void __iomem *)sdmact_port, JCHDCTxtbl[offset][idx]);
-               out_be32((void __iomem *)scrcst_port, JCSTWTxtbl[offset][idx]);
-               jcactsel = jcactsel << 2;
-               out_be32((void __iomem *)tdvhsel_port, (in_be32((void __iomem *)tdvhsel_port) & ~TDVHSEL_SLAVE) | jcactsel);
-       } else {
-               out_be32((void __iomem *)mdmact_port, JCHDCTxtbl[offset][idx]);
-               out_be32((void __iomem *)mcrcst_port, JCSTWTxtbl[offset][idx]);
-               out_be32((void __iomem *)tdvhsel_port, (in_be32((void __iomem *)tdvhsel_port) & ~TDVHSEL_MASTER) | jcactsel);
-       }
-       reg = JCTSStbl[offset][idx] << 16 | JCENVTtbl[offset][idx];
-       out_be32((void __iomem *)udenvt_port, reg);
-}
-
-static void scc_dma_host_set(ide_drive_t *drive, int on)
-{
-       ide_hwif_t *hwif = drive->hwif;
-       u8 unit = drive->dn & 1;
-       u8 dma_stat = scc_dma_sff_read_status(hwif);
-
-       if (on)
-               dma_stat |= (1 << (5 + unit));
-       else
-               dma_stat &= ~(1 << (5 + unit));
-
-       scc_ide_outb(dma_stat, hwif->dma_base + 4);
-}
-
-/**
- *     scc_dma_setup   -       begin a DMA phase
- *     @drive: target device
- *     @cmd: command
- *
- *     Build an IDE DMA PRD (IDE speak for scatter gather table)
- *     and then set up the DMA transfer registers.
- *
- *     Returns 0 on success. If a PIO fallback is required then 1
- *     is returned.
- */
-
-static int scc_dma_setup(ide_drive_t *drive, struct ide_cmd *cmd)
-{
-       ide_hwif_t *hwif = drive->hwif;
-       u32 rw = (cmd->tf_flags & IDE_TFLAG_WRITE) ? 0 : ATA_DMA_WR;
-       u8 dma_stat;
-
-       /* fall back to pio! */
-       if (ide_build_dmatable(drive, cmd) == 0)
-               return 1;
-
-       /* PRD table */
-       out_be32((void __iomem *)(hwif->dma_base + 8), hwif->dmatable_dma);
-
-       /* specify r/w */
-       out_be32((void __iomem *)hwif->dma_base, rw);
-
-       /* read DMA status for INTR & ERROR flags */
-       dma_stat = scc_dma_sff_read_status(hwif);
-
-       /* clear INTR & ERROR flags */
-       out_be32((void __iomem *)(hwif->dma_base + 4), dma_stat | 6);
-
-       return 0;
-}
-
-static void scc_dma_start(ide_drive_t *drive)
-{
-       ide_hwif_t *hwif = drive->hwif;
-       u8 dma_cmd = scc_ide_inb(hwif->dma_base);
-
-       /* start DMA */
-       scc_ide_outb(dma_cmd | 1, hwif->dma_base);
-}
-
-static int __scc_dma_end(ide_drive_t *drive)
-{
-       ide_hwif_t *hwif = drive->hwif;
-       u8 dma_stat, dma_cmd;
-
-       /* get DMA command mode */
-       dma_cmd = scc_ide_inb(hwif->dma_base);
-       /* stop DMA */
-       scc_ide_outb(dma_cmd & ~1, hwif->dma_base);
-       /* get DMA status */
-       dma_stat = scc_dma_sff_read_status(hwif);
-       /* clear the INTR & ERROR bits */
-       scc_ide_outb(dma_stat | 6, hwif->dma_base + 4);
-       /* verify good DMA status */
-       return (dma_stat & 7) != 4 ? (0x10 | dma_stat) : 0;
-}
-
-/**
- *     scc_dma_end     -       Stop DMA
- *     @drive: IDE drive
- *
- *     Check and clear INT Status register.
- *     Then call __scc_dma_end().
- */
-
-static int scc_dma_end(ide_drive_t *drive)
-{
-       ide_hwif_t *hwif = drive->hwif;
-       void __iomem *dma_base = (void __iomem *)hwif->dma_base;
-       unsigned long intsts_port = hwif->dma_base + 0x014;
-       u32 reg;
-       int dma_stat, data_loss = 0;
-       static int retry = 0;
-
-       /* errata A308 workaround: Step5 (check data loss) */
-       /* We don't check non ide_disk because it is limited to UDMA4 */
-       if (!(in_be32((void __iomem *)hwif->io_ports.ctl_addr)
-             & ATA_ERR) &&
-           drive->media == ide_disk && drive->current_speed > XFER_UDMA_4) {
-               reg = in_be32((void __iomem *)intsts_port);
-               if (!(reg & INTSTS_ACTEINT)) {
-                       printk(KERN_WARNING "%s: operation failed (transfer data loss)\n",
-                              drive->name);
-                       data_loss = 1;
-                       if (retry++) {
-                               struct request *rq = hwif->rq;
-                               ide_drive_t *drive;
-                               int i;
-
-                               /* ERROR_RESET and drive->crc_count are needed
-                                * to reduce DMA transfer mode in retry process.
-                                */
-                               if (rq)
-                                       rq->errors |= ERROR_RESET;
-
-                               ide_port_for_each_dev(i, drive, hwif)
-                                       drive->crc_count++;
-                       }
-               }
-       }
-
-       while (1) {
-               reg = in_be32((void __iomem *)intsts_port);
-
-               if (reg & INTSTS_SERROR) {
-                       printk(KERN_WARNING "%s: SERROR\n", SCC_PATA_NAME);
-                       out_be32((void __iomem *)intsts_port, INTSTS_SERROR|INTSTS_BMSINT);
-
-                       out_be32(dma_base, in_be32(dma_base) & ~QCHCD_IOS_SS);
-                       continue;
-               }
-
-               if (reg & INTSTS_PRERR) {
-                       u32 maea0, maec0;
-                       unsigned long ctl_base = hwif->config_data;
-
-                       maea0 = in_be32((void __iomem *)(ctl_base + 0xF50));
-                       maec0 = in_be32((void __iomem *)(ctl_base + 0xF54));
-
-                       printk(KERN_WARNING "%s: PRERR [addr:%x cmd:%x]\n", SCC_PATA_NAME, maea0, maec0);
-
-                       out_be32((void __iomem *)intsts_port, INTSTS_PRERR|INTSTS_BMSINT);
-
-                       out_be32(dma_base, in_be32(dma_base) & ~QCHCD_IOS_SS);
-                       continue;
-               }
-
-               if (reg & INTSTS_RERR) {
-                       printk(KERN_WARNING "%s: Response Error\n", SCC_PATA_NAME);
-                       out_be32((void __iomem *)intsts_port, INTSTS_RERR|INTSTS_BMSINT);
-
-                       out_be32(dma_base, in_be32(dma_base) & ~QCHCD_IOS_SS);
-                       continue;
-               }
-
-               if (reg & INTSTS_ICERR) {
-                       out_be32(dma_base, in_be32(dma_base) & ~QCHCD_IOS_SS);
-
-                       printk(KERN_WARNING "%s: Illegal Configuration\n", SCC_PATA_NAME);
-                       out_be32((void __iomem *)intsts_port, INTSTS_ICERR|INTSTS_BMSINT);
-                       continue;
-               }
-
-               if (reg & INTSTS_BMSINT) {
-                       printk(KERN_WARNING "%s: Internal Bus Error\n", SCC_PATA_NAME);
-                       out_be32((void __iomem *)intsts_port, INTSTS_BMSINT);
-
-                       ide_do_reset(drive);
-                       continue;
-               }
-
-               if (reg & INTSTS_BMHE) {
-                       out_be32((void __iomem *)intsts_port, INTSTS_BMHE);
-                       continue;
-               }
-
-               if (reg & INTSTS_ACTEINT) {
-                       out_be32((void __iomem *)intsts_port, INTSTS_ACTEINT);
-                       continue;
-               }
-
-               if (reg & INTSTS_IOIRQS) {
-                       out_be32((void __iomem *)intsts_port, INTSTS_IOIRQS);
-                       continue;
-               }
-               break;
-       }
-
-       dma_stat = __scc_dma_end(drive);
-       if (data_loss)
-               dma_stat |= 2; /* emulate DMA error (to retry command) */
-       return dma_stat;
-}
-
-/* returns 1 if dma irq issued, 0 otherwise */
-static int scc_dma_test_irq(ide_drive_t *drive)
-{
-       ide_hwif_t *hwif = drive->hwif;
-       u32 int_stat = in_be32((void __iomem *)hwif->dma_base + 0x014);
-
-       /* SCC errata A252,A308 workaround: Step4 */
-       if ((in_be32((void __iomem *)hwif->io_ports.ctl_addr)
-            & ATA_ERR) &&
-           (int_stat & INTSTS_INTRQ))
-               return 1;
-
-       /* SCC errata A308 workaround: Step5 (polling IOIRQS) */
-       if (int_stat & INTSTS_IOIRQS)
-               return 1;
-
-       return 0;
-}
-
-static u8 scc_udma_filter(ide_drive_t *drive)
-{
-       ide_hwif_t *hwif = drive->hwif;
-       u8 mask = hwif->ultra_mask;
-
-       /* errata A308 workaround: limit non ide_disk drive to UDMA4 */
-       if ((drive->media != ide_disk) && (mask & 0xE0)) {
-               printk(KERN_INFO "%s: limit %s to UDMA4\n",
-                      SCC_PATA_NAME, drive->name);
-               mask = ATA_UDMA4;
-       }
-
-       return mask;
-}
-
-/**
- *     setup_mmio_scc  -       map CTRL/BMID region
- *     @dev: PCI device we are configuring
- *     @name: device name
- *
- */
-
-static int setup_mmio_scc (struct pci_dev *dev, const char *name)
-{
-       void __iomem *ctl_addr;
-       void __iomem *dma_addr;
-       int i, ret;
-
-       for (i = 0; i < MAX_HWIFS; i++) {
-               if (scc_ports[i].ctl == 0)
-                       break;
-       }
-       if (i >= MAX_HWIFS)
-               return -ENOMEM;
-
-       ret = pci_request_selected_regions(dev, (1 << 2) - 1, name);
-       if (ret < 0) {
-               printk(KERN_ERR "%s: can't reserve resources\n", name);
-               return ret;
-       }
-
-       ctl_addr = pci_ioremap_bar(dev, 0);
-       if (!ctl_addr)
-               goto fail_0;
-
-       dma_addr = pci_ioremap_bar(dev, 1);
-       if (!dma_addr)
-               goto fail_1;
-
-       pci_set_master(dev);
-       scc_ports[i].ctl = (unsigned long)ctl_addr;
-       scc_ports[i].dma = (unsigned long)dma_addr;
-       pci_set_drvdata(dev, (void *) &scc_ports[i]);
-
-       return 1;
-
- fail_1:
-       iounmap(ctl_addr);
- fail_0:
-       return -ENOMEM;
-}
-
-static int scc_ide_setup_pci_device(struct pci_dev *dev,
-                                   const struct ide_port_info *d)
-{
-       struct scc_ports *ports = pci_get_drvdata(dev);
-       struct ide_host *host;
-       struct ide_hw hw, *hws[] = { &hw };
-       int i, rc;
-
-       memset(&hw, 0, sizeof(hw));
-       for (i = 0; i <= 8; i++)
-               hw.io_ports_array[i] = ports->dma + 0x20 + i * 4;
-       hw.irq = dev->irq;
-       hw.dev = &dev->dev;
-
-       rc = ide_host_add(d, hws, 1, &host);
-       if (rc)
-               return rc;
-
-       ports->host = host;
-
-       return 0;
-}
-
-/**
- *     init_setup_scc  -       set up an SCC PATA Controller
- *     @dev: PCI device
- *     @d: IDE port info
- *
- *     Perform the initial set up for this device.
- */
-
-static int init_setup_scc(struct pci_dev *dev, const struct ide_port_info *d)
-{
-       unsigned long ctl_base;
-       unsigned long dma_base;
-       unsigned long cckctrl_port;
-       unsigned long intmask_port;
-       unsigned long mode_port;
-       unsigned long ecmode_port;
-       u32 reg = 0;
-       struct scc_ports *ports;
-       int rc;
-
-       rc = pci_enable_device(dev);
-       if (rc)
-               goto end;
-
-       rc = setup_mmio_scc(dev, d->name);
-       if (rc < 0)
-               goto end;
-
-       ports = pci_get_drvdata(dev);
-       ctl_base = ports->ctl;
-       dma_base = ports->dma;
-       cckctrl_port = ctl_base + 0xff0;
-       intmask_port = dma_base + 0x010;
-       mode_port = ctl_base + 0x024;
-       ecmode_port = ctl_base + 0xf00;
-
-       /* controller initialization */
-       reg = 0;
-       out_be32((void*)cckctrl_port, reg);
-       reg |= CCKCTRL_ATACLKOEN;
-       out_be32((void*)cckctrl_port, reg);
-       reg |= CCKCTRL_LCLKEN | CCKCTRL_OCLKEN;
-       out_be32((void*)cckctrl_port, reg);
-       reg |= CCKCTRL_CRST;
-       out_be32((void*)cckctrl_port, reg);
-
-       for (;;) {
-               reg = in_be32((void*)cckctrl_port);
-               if (reg & CCKCTRL_CRST)
-                       break;
-               udelay(5000);
-       }
-
-       reg |= CCKCTRL_ATARESET;
-       out_be32((void*)cckctrl_port, reg);
-
-       out_be32((void*)ecmode_port, ECMODE_VALUE);
-       out_be32((void*)mode_port, MODE_JCUSFEN);
-       out_be32((void*)intmask_port, INTMASK_MSK);
-
-       rc = scc_ide_setup_pci_device(dev, d);
-
- end:
-       return rc;
-}
-
-static void scc_tf_load(ide_drive_t *drive, struct ide_taskfile *tf, u8 valid)
-{
-       struct ide_io_ports *io_ports = &drive->hwif->io_ports;
-
-       if (valid & IDE_VALID_FEATURE)
-               scc_ide_outb(tf->feature, io_ports->feature_addr);
-       if (valid & IDE_VALID_NSECT)
-               scc_ide_outb(tf->nsect, io_ports->nsect_addr);
-       if (valid & IDE_VALID_LBAL)
-               scc_ide_outb(tf->lbal, io_ports->lbal_addr);
-       if (valid & IDE_VALID_LBAM)
-               scc_ide_outb(tf->lbam, io_ports->lbam_addr);
-       if (valid & IDE_VALID_LBAH)
-               scc_ide_outb(tf->lbah, io_ports->lbah_addr);
-       if (valid & IDE_VALID_DEVICE)
-               scc_ide_outb(tf->device, io_ports->device_addr);
-}
-
-static void scc_tf_read(ide_drive_t *drive, struct ide_taskfile *tf, u8 valid)
-{
-       struct ide_io_ports *io_ports = &drive->hwif->io_ports;
-
-       if (valid & IDE_VALID_ERROR)
-               tf->error  = scc_ide_inb(io_ports->feature_addr);
-       if (valid & IDE_VALID_NSECT)
-               tf->nsect  = scc_ide_inb(io_ports->nsect_addr);
-       if (valid & IDE_VALID_LBAL)
-               tf->lbal   = scc_ide_inb(io_ports->lbal_addr);
-       if (valid & IDE_VALID_LBAM)
-               tf->lbam   = scc_ide_inb(io_ports->lbam_addr);
-       if (valid & IDE_VALID_LBAH)
-               tf->lbah   = scc_ide_inb(io_ports->lbah_addr);
-       if (valid & IDE_VALID_DEVICE)
-               tf->device = scc_ide_inb(io_ports->device_addr);
-}
-
-static void scc_input_data(ide_drive_t *drive, struct ide_cmd *cmd,
-                          void *buf, unsigned int len)
-{
-       unsigned long data_addr = drive->hwif->io_ports.data_addr;
-
-       len++;
-
-       if (drive->io_32bit) {
-               scc_ide_insl(data_addr, buf, len / 4);
-
-               if ((len & 3) >= 2)
-                       scc_ide_insw(data_addr, (u8 *)buf + (len & ~3), 1);
-       } else
-               scc_ide_insw(data_addr, buf, len / 2);
-}
-
-static void scc_output_data(ide_drive_t *drive,  struct ide_cmd *cmd,
-                           void *buf, unsigned int len)
-{
-       unsigned long data_addr = drive->hwif->io_ports.data_addr;
-
-       len++;
-
-       if (drive->io_32bit) {
-               scc_ide_outsl(data_addr, buf, len / 4);
-
-               if ((len & 3) >= 2)
-                       scc_ide_outsw(data_addr, (u8 *)buf + (len & ~3), 1);
-       } else
-               scc_ide_outsw(data_addr, buf, len / 2);
-}
-
-/**
- *     init_mmio_iops_scc      -       set up the iops for MMIO
- *     @hwif: interface to set up
- *
- */
-
-static void init_mmio_iops_scc(ide_hwif_t *hwif)
-{
-       struct pci_dev *dev = to_pci_dev(hwif->dev);
-       struct scc_ports *ports = pci_get_drvdata(dev);
-       unsigned long dma_base = ports->dma;
-
-       ide_set_hwifdata(hwif, ports);
-
-       hwif->dma_base = dma_base;
-       hwif->config_data = ports->ctl;
-}
-
-/**
- *     init_iops_scc   -       set up iops
- *     @hwif: interface to set up
- *
- *     Do the basic setup for the SCC hardware interface
- *     and then do the MMIO setup.
- */
-
-static void init_iops_scc(ide_hwif_t *hwif)
-{
-       struct pci_dev *dev = to_pci_dev(hwif->dev);
-
-       hwif->hwif_data = NULL;
-       if (pci_get_drvdata(dev) == NULL)
-               return;
-       init_mmio_iops_scc(hwif);
-}
-
-static int scc_init_dma(ide_hwif_t *hwif, const struct ide_port_info *d)
-{
-       return ide_allocate_dma_engine(hwif);
-}
-
-static u8 scc_cable_detect(ide_hwif_t *hwif)
-{
-       return ATA_CBL_PATA80;
-}
-
-/**
- *     init_hwif_scc   -       set up hwif
- *     @hwif: interface to set up
- *
- *     We do the basic set up of the interface structure. The SCC
- *     requires several custom handlers so we override the default
- *     ide DMA handlers appropriately.
- */
-
-static void init_hwif_scc(ide_hwif_t *hwif)
-{
-       /* PTERADD */
-       out_be32((void __iomem *)(hwif->dma_base + 0x018), hwif->dmatable_dma);
-
-       if (in_be32((void __iomem *)(hwif->config_data + 0xff0)) & CCKCTRL_ATACLKOEN)
-               hwif->ultra_mask = ATA_UDMA6; /* 133MHz */
-       else
-               hwif->ultra_mask = ATA_UDMA5; /* 100MHz */
-}
-
-static const struct ide_tp_ops scc_tp_ops = {
-       .exec_command           = scc_exec_command,
-       .read_status            = scc_read_status,
-       .read_altstatus         = scc_read_altstatus,
-       .write_devctl           = scc_write_devctl,
-
-       .dev_select             = ide_dev_select,
-       .tf_load                = scc_tf_load,
-       .tf_read                = scc_tf_read,
-
-       .input_data             = scc_input_data,
-       .output_data            = scc_output_data,
-};
-
-static const struct ide_port_ops scc_port_ops = {
-       .set_pio_mode           = scc_set_pio_mode,
-       .set_dma_mode           = scc_set_dma_mode,
-       .udma_filter            = scc_udma_filter,
-       .cable_detect           = scc_cable_detect,
-};
-
-static const struct ide_dma_ops scc_dma_ops = {
-       .dma_host_set           = scc_dma_host_set,
-       .dma_setup              = scc_dma_setup,
-       .dma_start              = scc_dma_start,
-       .dma_end                = scc_dma_end,
-       .dma_test_irq           = scc_dma_test_irq,
-       .dma_lost_irq           = ide_dma_lost_irq,
-       .dma_timer_expiry       = ide_dma_sff_timer_expiry,
-       .dma_sff_read_status    = scc_dma_sff_read_status,
-};
-
-static const struct ide_port_info scc_chipset = {
-       .name           = "sccIDE",
-       .init_iops      = init_iops_scc,
-       .init_dma       = scc_init_dma,
-       .init_hwif      = init_hwif_scc,
-       .tp_ops         = &scc_tp_ops,
-       .port_ops       = &scc_port_ops,
-       .dma_ops        = &scc_dma_ops,
-       .host_flags     = IDE_HFLAG_SINGLE,
-       .irq_flags      = IRQF_SHARED,
-       .pio_mask       = ATA_PIO4,
-       .chipset        = ide_pci,
-};
-
-/**
- *     scc_init_one    -       pci layer discovery entry
- *     @dev: PCI device
- *     @id: ident table entry
- *
- *     Called by the PCI code when it finds an SCC PATA controller.
- *     We then use the IDE PCI generic helper to do most of the work.
- */
-
-static int scc_init_one(struct pci_dev *dev, const struct pci_device_id *id)
-{
-       return init_setup_scc(dev, &scc_chipset);
-}
-
-/**
- *     scc_remove      -       pci layer remove entry
- *     @dev: PCI device
- *
- *     Called by the PCI code when it removes an SCC PATA controller.
- */
-
-static void scc_remove(struct pci_dev *dev)
-{
-       struct scc_ports *ports = pci_get_drvdata(dev);
-       struct ide_host *host = ports->host;
-
-       ide_host_remove(host);
-
-       iounmap((void*)ports->dma);
-       iounmap((void*)ports->ctl);
-       pci_release_selected_regions(dev, (1 << 2) - 1);
-       memset(ports, 0, sizeof(*ports));
-}
-
-static const struct pci_device_id scc_pci_tbl[] = {
-       { PCI_VDEVICE(TOSHIBA_2, PCI_DEVICE_ID_TOSHIBA_SCC_ATA), 0 },
-       { 0, },
-};
-MODULE_DEVICE_TABLE(pci, scc_pci_tbl);
-
-static struct pci_driver scc_pci_driver = {
-       .name = "SCC IDE",
-       .id_table = scc_pci_tbl,
-       .probe = scc_init_one,
-       .remove = scc_remove,
-};
-
-static int __init scc_ide_init(void)
-{
-       return ide_pci_register_driver(&scc_pci_driver);
-}
-
-static void __exit scc_ide_exit(void)
-{
-       pci_unregister_driver(&scc_pci_driver);
-}
-
-module_init(scc_ide_init);
-module_exit(scc_ide_exit);
-
-MODULE_DESCRIPTION("PCI driver module for Toshiba SCC IDE");
-MODULE_LICENSE("GPL");
index 7f55a6d7cd035d5e7d2fbad512ce60f3465508e2..c6d5a3a40b609c9044fb57846fca951eabfe199b 100644 (file)
@@ -389,7 +389,12 @@ int mma9551_read_config_words(struct i2c_client *client, u8 app_id,
 {
        int ret, i;
        int len_words = len / sizeof(u16);
-       __be16 be_buf[MMA9551_MAX_MAILBOX_DATA_REGS];
+       __be16 be_buf[MMA9551_MAX_MAILBOX_DATA_REGS / 2];
+
+       if (len_words > ARRAY_SIZE(be_buf)) {
+               dev_err(&client->dev, "Invalid buffer size %d\n", len);
+               return -EINVAL;
+       }
 
        ret = mma9551_transfer(client, app_id, MMA9551_CMD_READ_CONFIG,
                               reg, NULL, 0, (u8 *) be_buf, len);
@@ -424,7 +429,12 @@ int mma9551_read_status_words(struct i2c_client *client, u8 app_id,
 {
        int ret, i;
        int len_words = len / sizeof(u16);
-       __be16 be_buf[MMA9551_MAX_MAILBOX_DATA_REGS];
+       __be16 be_buf[MMA9551_MAX_MAILBOX_DATA_REGS / 2];
+
+       if (len_words > ARRAY_SIZE(be_buf)) {
+               dev_err(&client->dev, "Invalid buffer size %d\n", len);
+               return -EINVAL;
+       }
 
        ret = mma9551_transfer(client, app_id, MMA9551_CMD_READ_STATUS,
                               reg, NULL, 0, (u8 *) be_buf, len);
@@ -459,7 +469,12 @@ int mma9551_write_config_words(struct i2c_client *client, u8 app_id,
 {
        int i;
        int len_words = len / sizeof(u16);
-       __be16 be_buf[MMA9551_MAX_MAILBOX_DATA_REGS];
+       __be16 be_buf[(MMA9551_MAX_MAILBOX_DATA_REGS - 1) / 2];
+
+       if (len_words > ARRAY_SIZE(be_buf)) {
+               dev_err(&client->dev, "Invalid buffer size %d\n", len);
+               return -EINVAL;
+       }
 
        for (i = 0; i < len_words; i++)
                be_buf[i] = cpu_to_be16(buf[i]);
index 2df1af7d43fc6df34b87f80373e413152e33a739..365a109aaaefe8f5367c8de6a1f0e2ccfc9bf463 100644 (file)
@@ -54,6 +54,7 @@
 #define MMA9553_MASK_CONF_STEPCOALESCE         GENMASK(7, 0)
 
 #define MMA9553_REG_CONF_ACTTHD                        0x0E
+#define MMA9553_MAX_ACTTHD                     GENMASK(15, 0)
 
 /* Pedometer status registers (R-only) */
 #define MMA9553_REG_STATUS                     0x00
@@ -316,22 +317,19 @@ static int mma9553_set_config(struct mma9553_data *data, u16 reg,
 static int mma9553_read_activity_stepcnt(struct mma9553_data *data,
                                         u8 *activity, u16 *stepcnt)
 {
-       u32 status_stepcnt;
-       u16 status;
+       u16 buf[2];
        int ret;
 
        ret = mma9551_read_status_words(data->client, MMA9551_APPID_PEDOMETER,
-                                       MMA9553_REG_STATUS, sizeof(u32),
-                                       (u16 *) &status_stepcnt);
+                                       MMA9553_REG_STATUS, sizeof(u32), buf);
        if (ret < 0) {
                dev_err(&data->client->dev,
                        "error reading status and stepcnt\n");
                return ret;
        }
 
-       status = status_stepcnt & MMA9553_MASK_CONF_WORD;
-       *activity = mma9553_get_bits(status, MMA9553_MASK_STATUS_ACTIVITY);
-       *stepcnt = status_stepcnt >> 16;
+       *activity = mma9553_get_bits(buf[0], MMA9553_MASK_STATUS_ACTIVITY);
+       *stepcnt = buf[1];
 
        return 0;
 }
@@ -872,6 +870,9 @@ static int mma9553_write_event_value(struct iio_dev *indio_dev,
        case IIO_EV_INFO_PERIOD:
                switch (chan->type) {
                case IIO_ACTIVITY:
+                       if (val < 0 || val > MMA9553_ACTIVITY_THD_TO_SEC(
+                           MMA9553_MAX_ACTTHD))
+                               return -EINVAL;
                        mutex_lock(&data->mutex);
                        ret = mma9553_set_config(data, MMA9553_REG_CONF_ACTTHD,
                                                 &data->conf.actthd,
@@ -971,7 +972,8 @@ static const struct iio_chan_spec_ext_info mma9553_ext_info[] = {
        .modified = 1,                                                  \
        .channel2 = _chan2,                                             \
        .info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED),             \
-       .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_CALIBHEIGHT),     \
+       .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_CALIBHEIGHT) |    \
+                                   BIT(IIO_CHAN_INFO_ENABLE),          \
        .event_spec = mma9553_activity_events,                          \
        .num_event_specs = ARRAY_SIZE(mma9553_activity_events),         \
        .ext_info = mma9553_ext_info,                                   \
index 58d1d13d552ae8cf336061f93603e4dd07b222ac..211b13271c61566c5d3f3d4e9990bcd3c7470823 100644 (file)
@@ -546,6 +546,7 @@ int st_accel_common_probe(struct iio_dev *indio_dev)
 
        indio_dev->modes = INDIO_DIRECT_MODE;
        indio_dev->info = &accel_info;
+       mutex_init(&adata->tb.buf_lock);
 
        st_sensors_power_enable(indio_dev);
 
index 08bcfb061ca5617505a47d9fa96b5f762b867f63..56008a86b78f854229943769307ce2fd2c328201 100644 (file)
@@ -53,39 +53,42 @@ static const struct iio_chan_spec const axp288_adc_channels[] = {
                .channel = 0,
                .address = AXP288_TS_ADC_H,
                .datasheet_name = "TS_PIN",
+               .info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
        }, {
                .indexed = 1,
                .type = IIO_TEMP,
                .channel = 1,
                .address = AXP288_PMIC_ADC_H,
                .datasheet_name = "PMIC_TEMP",
+               .info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
        }, {
                .indexed = 1,
                .type = IIO_TEMP,
                .channel = 2,
                .address = AXP288_GP_ADC_H,
                .datasheet_name = "GPADC",
+               .info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
        }, {
                .indexed = 1,
                .type = IIO_CURRENT,
                .channel = 3,
                .address = AXP20X_BATT_CHRG_I_H,
                .datasheet_name = "BATT_CHG_I",
-               .info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED),
+               .info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
        }, {
                .indexed = 1,
                .type = IIO_CURRENT,
                .channel = 4,
                .address = AXP20X_BATT_DISCHRG_I_H,
                .datasheet_name = "BATT_DISCHRG_I",
-               .info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED),
+               .info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
        }, {
                .indexed = 1,
                .type = IIO_VOLTAGE,
                .channel = 5,
                .address = AXP20X_BATT_V_H,
                .datasheet_name = "BATT_V",
-               .info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED),
+               .info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
        },
 };
 
@@ -151,9 +154,6 @@ static int axp288_adc_read_raw(struct iio_dev *indio_dev,
                                                chan->address))
                        dev_err(&indio_dev->dev, "TS pin restore\n");
                break;
-       case IIO_CHAN_INFO_PROCESSED:
-               ret = axp288_adc_read_channel(val, chan->address, info->regmap);
-               break;
        default:
                ret = -EINVAL;
        }
index 51e2a83c9404ca3ddc0a24d64ffa47f6090500ba..115f6e99a7fa7c603ca9655d04759545c48e5932 100644 (file)
@@ -35,8 +35,9 @@
 #define CC10001_ADC_EOC_SET            BIT(0)
 
 #define CC10001_ADC_CHSEL_SAMPLED      0x0c
-#define CC10001_ADC_POWER_UP           0x10
-#define CC10001_ADC_POWER_UP_SET       BIT(0)
+#define CC10001_ADC_POWER_DOWN         0x10
+#define CC10001_ADC_POWER_DOWN_SET     BIT(0)
+
 #define CC10001_ADC_DEBUG              0x14
 #define CC10001_ADC_DATA_COUNT         0x20
 
@@ -62,7 +63,6 @@ struct cc10001_adc_device {
        u16 *buf;
 
        struct mutex lock;
-       unsigned long channel_map;
        unsigned int start_delay_ns;
        unsigned int eoc_delay_ns;
 };
@@ -79,6 +79,18 @@ static inline u32 cc10001_adc_read_reg(struct cc10001_adc_device *adc_dev,
        return readl(adc_dev->reg_base + reg);
 }
 
+static void cc10001_adc_power_up(struct cc10001_adc_device *adc_dev)
+{
+       cc10001_adc_write_reg(adc_dev, CC10001_ADC_POWER_DOWN, 0);
+       ndelay(adc_dev->start_delay_ns);
+}
+
+static void cc10001_adc_power_down(struct cc10001_adc_device *adc_dev)
+{
+       cc10001_adc_write_reg(adc_dev, CC10001_ADC_POWER_DOWN,
+                             CC10001_ADC_POWER_DOWN_SET);
+}
+
 static void cc10001_adc_start(struct cc10001_adc_device *adc_dev,
                              unsigned int channel)
 {
@@ -88,6 +100,7 @@ static void cc10001_adc_start(struct cc10001_adc_device *adc_dev,
        val = (channel & CC10001_ADC_CH_MASK) | CC10001_ADC_MODE_SINGLE_CONV;
        cc10001_adc_write_reg(adc_dev, CC10001_ADC_CONFIG, val);
 
+       udelay(1);
        val = cc10001_adc_read_reg(adc_dev, CC10001_ADC_CONFIG);
        val = val | CC10001_ADC_START_CONV;
        cc10001_adc_write_reg(adc_dev, CC10001_ADC_CONFIG, val);
@@ -129,6 +142,7 @@ static irqreturn_t cc10001_adc_trigger_h(int irq, void *p)
        struct iio_dev *indio_dev;
        unsigned int delay_ns;
        unsigned int channel;
+       unsigned int scan_idx;
        bool sample_invalid;
        u16 *data;
        int i;
@@ -139,20 +153,17 @@ static irqreturn_t cc10001_adc_trigger_h(int irq, void *p)
 
        mutex_lock(&adc_dev->lock);
 
-       cc10001_adc_write_reg(adc_dev, CC10001_ADC_POWER_UP,
-                             CC10001_ADC_POWER_UP_SET);
-
-       /* Wait for 8 (6+2) clock cycles before activating START */
-       ndelay(adc_dev->start_delay_ns);
+       cc10001_adc_power_up(adc_dev);
 
        /* Calculate delay step for eoc and sampled data */
        delay_ns = adc_dev->eoc_delay_ns / CC10001_MAX_POLL_COUNT;
 
        i = 0;
        sample_invalid = false;
-       for_each_set_bit(channel, indio_dev->active_scan_mask,
+       for_each_set_bit(scan_idx, indio_dev->active_scan_mask,
                                  indio_dev->masklength) {
 
+               channel = indio_dev->channels[scan_idx].channel;
                cc10001_adc_start(adc_dev, channel);
 
                data[i] = cc10001_adc_poll_done(indio_dev, channel, delay_ns);
@@ -166,7 +177,7 @@ static irqreturn_t cc10001_adc_trigger_h(int irq, void *p)
        }
 
 done:
-       cc10001_adc_write_reg(adc_dev, CC10001_ADC_POWER_UP, 0);
+       cc10001_adc_power_down(adc_dev);
 
        mutex_unlock(&adc_dev->lock);
 
@@ -185,11 +196,7 @@ static u16 cc10001_adc_read_raw_voltage(struct iio_dev *indio_dev,
        unsigned int delay_ns;
        u16 val;
 
-       cc10001_adc_write_reg(adc_dev, CC10001_ADC_POWER_UP,
-                             CC10001_ADC_POWER_UP_SET);
-
-       /* Wait for 8 (6+2) clock cycles before activating START */
-       ndelay(adc_dev->start_delay_ns);
+       cc10001_adc_power_up(adc_dev);
 
        /* Calculate delay step for eoc and sampled data */
        delay_ns = adc_dev->eoc_delay_ns / CC10001_MAX_POLL_COUNT;
@@ -198,7 +205,7 @@ static u16 cc10001_adc_read_raw_voltage(struct iio_dev *indio_dev,
 
        val = cc10001_adc_poll_done(indio_dev, chan->channel, delay_ns);
 
-       cc10001_adc_write_reg(adc_dev, CC10001_ADC_POWER_UP, 0);
+       cc10001_adc_power_down(adc_dev);
 
        return val;
 }
@@ -224,7 +231,7 @@ static int cc10001_adc_read_raw(struct iio_dev *indio_dev,
 
        case IIO_CHAN_INFO_SCALE:
                ret = regulator_get_voltage(adc_dev->reg);
-               if (ret)
+               if (ret < 0)
                        return ret;
 
                *val = ret / 1000;
@@ -255,22 +262,22 @@ static const struct iio_info cc10001_adc_info = {
        .update_scan_mode = &cc10001_update_scan_mode,
 };
 
-static int cc10001_adc_channel_init(struct iio_dev *indio_dev)
+static int cc10001_adc_channel_init(struct iio_dev *indio_dev,
+                                   unsigned long channel_map)
 {
-       struct cc10001_adc_device *adc_dev = iio_priv(indio_dev);
        struct iio_chan_spec *chan_array, *timestamp;
        unsigned int bit, idx = 0;
 
-       indio_dev->num_channels = bitmap_weight(&adc_dev->channel_map,
-                                               CC10001_ADC_NUM_CHANNELS);
+       indio_dev->num_channels = bitmap_weight(&channel_map,
+                                               CC10001_ADC_NUM_CHANNELS) + 1;
 
-       chan_array = devm_kcalloc(&indio_dev->dev, indio_dev->num_channels + 1,
+       chan_array = devm_kcalloc(&indio_dev->dev, indio_dev->num_channels,
                                  sizeof(struct iio_chan_spec),
                                  GFP_KERNEL);
        if (!chan_array)
                return -ENOMEM;
 
-       for_each_set_bit(bit, &adc_dev->channel_map, CC10001_ADC_NUM_CHANNELS) {
+       for_each_set_bit(bit, &channel_map, CC10001_ADC_NUM_CHANNELS) {
                struct iio_chan_spec *chan = &chan_array[idx];
 
                chan->type = IIO_VOLTAGE;
@@ -305,6 +312,7 @@ static int cc10001_adc_probe(struct platform_device *pdev)
        unsigned long adc_clk_rate;
        struct resource *res;
        struct iio_dev *indio_dev;
+       unsigned long channel_map;
        int ret;
 
        indio_dev = devm_iio_device_alloc(&pdev->dev, sizeof(*adc_dev));
@@ -313,9 +321,9 @@ static int cc10001_adc_probe(struct platform_device *pdev)
 
        adc_dev = iio_priv(indio_dev);
 
-       adc_dev->channel_map = GENMASK(CC10001_ADC_NUM_CHANNELS - 1, 0);
+       channel_map = GENMASK(CC10001_ADC_NUM_CHANNELS - 1, 0);
        if (!of_property_read_u32(node, "adc-reserved-channels", &ret))
-               adc_dev->channel_map &= ~ret;
+               channel_map &= ~ret;
 
        adc_dev->reg = devm_regulator_get(&pdev->dev, "vref");
        if (IS_ERR(adc_dev->reg))
@@ -361,7 +369,7 @@ static int cc10001_adc_probe(struct platform_device *pdev)
        adc_dev->start_delay_ns = adc_dev->eoc_delay_ns * CC10001_WAIT_CYCLES;
 
        /* Setup the ADC channels available on the device */
-       ret = cc10001_adc_channel_init(indio_dev);
+       ret = cc10001_adc_channel_init(indio_dev, channel_map);
        if (ret < 0)
                goto err_disable_clk;
 
index efbfd12a4bfdd9f764732d976a2650719408552c..8d9c9b9215ddc1ef5530df512d475a618cb71d8f 100644 (file)
@@ -60,12 +60,12 @@ struct mcp320x {
        struct spi_message msg;
        struct spi_transfer transfer[2];
 
-       u8 tx_buf;
-       u8 rx_buf[2];
-
        struct regulator *reg;
        struct mutex lock;
        const struct mcp320x_chip_info *chip_info;
+
+       u8 tx_buf ____cacheline_aligned;
+       u8 rx_buf[2];
 };
 
 static int mcp320x_channel_to_tx_data(int device_index,
index 3211729bcb0bd2fa3a53629c4e78c2c9c37579a2..0c4618b4d51549cb7bfe8fead1e3ce61c1882366 100644 (file)
@@ -18,6 +18,7 @@
 #include <linux/iio/iio.h>
 #include <linux/interrupt.h>
 #include <linux/kernel.h>
+#include <linux/math64.h>
 #include <linux/module.h>
 #include <linux/of.h>
 #include <linux/platform_device.h>
@@ -471,11 +472,11 @@ static s32 vadc_calibrate(struct vadc_priv *vadc,
                          const struct vadc_channel_prop *prop, u16 adc_code)
 {
        const struct vadc_prescale_ratio *prescale;
-       s32 voltage;
+       s64 voltage;
 
        voltage = adc_code - vadc->graph[prop->calibration].gnd;
        voltage *= vadc->graph[prop->calibration].dx;
-       voltage = voltage / vadc->graph[prop->calibration].dy;
+       voltage = div64_s64(voltage, vadc->graph[prop->calibration].dy);
 
        if (prop->calibration == VADC_CALIB_ABSOLUTE)
                voltage += vadc->graph[prop->calibration].dx;
@@ -487,7 +488,7 @@ static s32 vadc_calibrate(struct vadc_priv *vadc,
 
        voltage = voltage * prescale->den;
 
-       return voltage / prescale->num;
+       return div64_s64(voltage, prescale->num);
 }
 
 static int vadc_decimation_from_dt(u32 value)
index 89d8aa1d2818502f974c92f7925ea4440df3d97d..df12c57e6ce07a700d211b81c9b5d3c9c15ff2d3 100644 (file)
@@ -1001,7 +1001,7 @@ static struct platform_driver twl6030_gpadc_driver = {
 
 module_platform_driver(twl6030_gpadc_driver);
 
-MODULE_ALIAS("platform: " DRIVER_NAME);
+MODULE_ALIAS("platform:" DRIVER_NAME);
 MODULE_AUTHOR("Balaji T K <balajitk@ti.com>");
 MODULE_AUTHOR("Graeme Gregory <gg@slimlogic.co.uk>");
 MODULE_AUTHOR("Oleksandr Kozaruk <oleksandr.kozaruk@ti.com");
index a221f7329b7914449492f7a287f6524d4770a4c3..ce93bd8e3f68b82fec81b31f8f1885b908ef0b45 100644 (file)
@@ -856,6 +856,7 @@ static int xadc_read_raw(struct iio_dev *indio_dev,
                        switch (chan->address) {
                        case XADC_REG_VCCINT:
                        case XADC_REG_VCCAUX:
+                       case XADC_REG_VREFP:
                        case XADC_REG_VCCBRAM:
                        case XADC_REG_VCCPINT:
                        case XADC_REG_VCCPAUX:
@@ -996,7 +997,7 @@ static const struct iio_event_spec xadc_voltage_events[] = {
        .num_event_specs = (_alarm) ? ARRAY_SIZE(xadc_voltage_events) : 0, \
        .scan_index = (_scan_index), \
        .scan_type = { \
-               .sign = 'u', \
+               .sign = ((_addr) == XADC_REG_VREFN) ? 's' : 'u', \
                .realbits = 12, \
                .storagebits = 16, \
                .shift = 4, \
@@ -1008,7 +1009,7 @@ static const struct iio_event_spec xadc_voltage_events[] = {
 static const struct iio_chan_spec xadc_channels[] = {
        XADC_CHAN_TEMP(0, 8, XADC_REG_TEMP),
        XADC_CHAN_VOLTAGE(0, 9, XADC_REG_VCCINT, "vccint", true),
-       XADC_CHAN_VOLTAGE(1, 10, XADC_REG_VCCINT, "vccaux", true),
+       XADC_CHAN_VOLTAGE(1, 10, XADC_REG_VCCAUX, "vccaux", true),
        XADC_CHAN_VOLTAGE(2, 14, XADC_REG_VCCBRAM, "vccbram", true),
        XADC_CHAN_VOLTAGE(3, 5, XADC_REG_VCCPINT, "vccpint", true),
        XADC_CHAN_VOLTAGE(4, 6, XADC_REG_VCCPAUX, "vccpaux", true),
index c7487e8d7f809f24b5616365408c5301fea196ad..54adc5087210bb173afd62bfa36712e4a014eafb 100644 (file)
@@ -145,9 +145,9 @@ static inline int xadc_write_adc_reg(struct xadc *xadc, unsigned int reg,
 #define XADC_REG_MAX_VCCPINT   0x28
 #define XADC_REG_MAX_VCCPAUX   0x29
 #define XADC_REG_MAX_VCCO_DDR  0x2a
-#define XADC_REG_MIN_VCCPINT   0x2b
-#define XADC_REG_MIN_VCCPAUX   0x2c
-#define XADC_REG_MIN_VCCO_DDR  0x2d
+#define XADC_REG_MIN_VCCPINT   0x2c
+#define XADC_REG_MIN_VCCPAUX   0x2d
+#define XADC_REG_MIN_VCCO_DDR  0x2e
 
 #define XADC_REG_CONF0         0x40
 #define XADC_REG_CONF1         0x41
index edd13d2b4121f7834c2e90eaca02e7a4f70c51b7..8dd0477e201c192bed10a8c5384f012bfe083ff8 100644 (file)
@@ -304,8 +304,6 @@ int st_sensors_init_sensor(struct iio_dev *indio_dev,
        struct st_sensors_platform_data *of_pdata;
        int err = 0;
 
-       mutex_init(&sdata->tb.buf_lock);
-
        /* If OF/DT pdata exists, it will take precedence of anything else */
        of_pdata = st_sensors_of_probe(indio_dev->dev.parent, pdata);
        if (of_pdata)
index 21395f26d2276548567dfd118f37c22087a0d1ce..ffe96642b6d049569d73356a1df541782657a912 100644 (file)
@@ -400,6 +400,7 @@ int st_gyro_common_probe(struct iio_dev *indio_dev)
 
        indio_dev->modes = INDIO_DIRECT_MODE;
        indio_dev->info = &gyro_info;
+       mutex_init(&gdata->tb.buf_lock);
 
        st_sensors_power_enable(indio_dev);
 
index 0916bf6b6c311c503931f26387712c6677b17645..73b189c1c0fb0fdcc73d64b7118ab4f79a12d41b 100644 (file)
 #define ADIS16400_NO_BURST             BIT(1)
 #define ADIS16400_HAS_SLOW_MODE                BIT(2)
 #define ADIS16400_HAS_SERIAL_NUMBER    BIT(3)
+#define ADIS16400_BURST_DIAG_STAT      BIT(4)
 
 struct adis16400_state;
 
@@ -165,6 +166,7 @@ struct adis16400_state {
        int                             filt_int;
 
        struct adis adis;
+       unsigned long avail_scan_mask[2];
 };
 
 /* At the moment triggers are only used for ring buffer
index 6e727ffe52621f43bb40f31466730705477961ef..90c24a23c679b8001e31cdff48b098cacb872682 100644 (file)
@@ -18,7 +18,8 @@ int adis16400_update_scan_mode(struct iio_dev *indio_dev,
 {
        struct adis16400_state *st = iio_priv(indio_dev);
        struct adis *adis = &st->adis;
-       uint16_t *tx;
+       unsigned int burst_length;
+       u8 *tx;
 
        if (st->variant->flags & ADIS16400_NO_BURST)
                return adis_update_scan_mode(indio_dev, scan_mask);
@@ -26,26 +27,29 @@ int adis16400_update_scan_mode(struct iio_dev *indio_dev,
        kfree(adis->xfer);
        kfree(adis->buffer);
 
+       /* All but the timestamp channel */
+       burst_length = (indio_dev->num_channels - 1) * sizeof(u16);
+       if (st->variant->flags & ADIS16400_BURST_DIAG_STAT)
+               burst_length += sizeof(u16);
+
        adis->xfer = kcalloc(2, sizeof(*adis->xfer), GFP_KERNEL);
        if (!adis->xfer)
                return -ENOMEM;
 
-       adis->buffer = kzalloc(indio_dev->scan_bytes + sizeof(u16),
-               GFP_KERNEL);
+       adis->buffer = kzalloc(burst_length + sizeof(u16), GFP_KERNEL);
        if (!adis->buffer)
                return -ENOMEM;
 
-       tx = adis->buffer + indio_dev->scan_bytes;
-
+       tx = adis->buffer + burst_length;
        tx[0] = ADIS_READ_REG(ADIS16400_GLOB_CMD);
        tx[1] = 0;
 
        adis->xfer[0].tx_buf = tx;
        adis->xfer[0].bits_per_word = 8;
        adis->xfer[0].len = 2;
-       adis->xfer[1].tx_buf = tx;
+       adis->xfer[1].rx_buf = adis->buffer;
        adis->xfer[1].bits_per_word = 8;
-       adis->xfer[1].len = indio_dev->scan_bytes;
+       adis->xfer[1].len = burst_length;
 
        spi_message_init(&adis->msg);
        spi_message_add_tail(&adis->xfer[0], &adis->msg);
@@ -61,6 +65,7 @@ irqreturn_t adis16400_trigger_handler(int irq, void *p)
        struct adis16400_state *st = iio_priv(indio_dev);
        struct adis *adis = &st->adis;
        u32 old_speed_hz = st->adis.spi->max_speed_hz;
+       void *buffer;
        int ret;
 
        if (!adis->buffer)
@@ -81,7 +86,12 @@ irqreturn_t adis16400_trigger_handler(int irq, void *p)
                spi_setup(st->adis.spi);
        }
 
-       iio_push_to_buffers_with_timestamp(indio_dev, adis->buffer,
+       if (st->variant->flags & ADIS16400_BURST_DIAG_STAT)
+               buffer = adis->buffer + sizeof(u16);
+       else
+               buffer = adis->buffer;
+
+       iio_push_to_buffers_with_timestamp(indio_dev, buffer,
                pf->timestamp);
 
        iio_trigger_notify_done(indio_dev->trig);
index fa795dcd5f75ec0a1e8de143bc0122ef36bf9409..2fd68f2219a7d422a604b91ce90138f1050528cd 100644 (file)
@@ -405,6 +405,11 @@ static int adis16400_read_raw(struct iio_dev *indio_dev,
                        *val = st->variant->temp_scale_nano / 1000000;
                        *val2 = (st->variant->temp_scale_nano % 1000000);
                        return IIO_VAL_INT_PLUS_MICRO;
+               case IIO_PRESSURE:
+                       /* 20 uBar = 0.002kPascal */
+                       *val = 0;
+                       *val2 = 2000;
+                       return IIO_VAL_INT_PLUS_MICRO;
                default:
                        return -EINVAL;
                }
@@ -454,10 +459,10 @@ static int adis16400_read_raw(struct iio_dev *indio_dev,
        }
 }
 
-#define ADIS16400_VOLTAGE_CHAN(addr, bits, name, si) { \
+#define ADIS16400_VOLTAGE_CHAN(addr, bits, name, si, chn) { \
        .type = IIO_VOLTAGE, \
        .indexed = 1, \
-       .channel = 0, \
+       .channel = chn, \
        .extend_name = name, \
        .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \
                BIT(IIO_CHAN_INFO_SCALE), \
@@ -474,10 +479,10 @@ static int adis16400_read_raw(struct iio_dev *indio_dev,
 }
 
 #define ADIS16400_SUPPLY_CHAN(addr, bits) \
-       ADIS16400_VOLTAGE_CHAN(addr, bits, "supply", ADIS16400_SCAN_SUPPLY)
+       ADIS16400_VOLTAGE_CHAN(addr, bits, "supply", ADIS16400_SCAN_SUPPLY, 0)
 
 #define ADIS16400_AUX_ADC_CHAN(addr, bits) \
-       ADIS16400_VOLTAGE_CHAN(addr, bits, NULL, ADIS16400_SCAN_ADC)
+       ADIS16400_VOLTAGE_CHAN(addr, bits, NULL, ADIS16400_SCAN_ADC, 1)
 
 #define ADIS16400_GYRO_CHAN(mod, addr, bits) { \
        .type = IIO_ANGL_VEL, \
@@ -773,7 +778,8 @@ static struct adis16400_chip_info adis16400_chips[] = {
                .channels = adis16448_channels,
                .num_channels = ARRAY_SIZE(adis16448_channels),
                .flags = ADIS16400_HAS_PROD_ID |
-                               ADIS16400_HAS_SERIAL_NUMBER,
+                               ADIS16400_HAS_SERIAL_NUMBER |
+                               ADIS16400_BURST_DIAG_STAT,
                .gyro_scale_micro = IIO_DEGREE_TO_RAD(10000), /* 0.01 deg/s */
                .accel_scale_micro = IIO_G_TO_M_S_2(833), /* 1/1200 g */
                .temp_scale_nano = 73860000, /* 0.07386 C */
@@ -791,11 +797,6 @@ static const struct iio_info adis16400_info = {
        .debugfs_reg_access = adis_debugfs_reg_access,
 };
 
-static const unsigned long adis16400_burst_scan_mask[] = {
-       ~0UL,
-       0,
-};
-
 static const char * const adis16400_status_error_msgs[] = {
        [ADIS16400_DIAG_STAT_ZACCL_FAIL] = "Z-axis accelerometer self-test failure",
        [ADIS16400_DIAG_STAT_YACCL_FAIL] = "Y-axis accelerometer self-test failure",
@@ -843,6 +844,20 @@ static const struct adis_data adis16400_data = {
                BIT(ADIS16400_DIAG_STAT_POWER_LOW),
 };
 
+static void adis16400_setup_chan_mask(struct adis16400_state *st)
+{
+       const struct adis16400_chip_info *chip_info = st->variant;
+       unsigned i;
+
+       for (i = 0; i < chip_info->num_channels; i++) {
+               const struct iio_chan_spec *ch = &chip_info->channels[i];
+
+               if (ch->scan_index >= 0 &&
+                   ch->scan_index != ADIS16400_SCAN_TIMESTAMP)
+                       st->avail_scan_mask[0] |= BIT(ch->scan_index);
+       }
+}
+
 static int adis16400_probe(struct spi_device *spi)
 {
        struct adis16400_state *st;
@@ -866,8 +881,10 @@ static int adis16400_probe(struct spi_device *spi)
        indio_dev->info = &adis16400_info;
        indio_dev->modes = INDIO_DIRECT_MODE;
 
-       if (!(st->variant->flags & ADIS16400_NO_BURST))
-               indio_dev->available_scan_masks = adis16400_burst_scan_mask;
+       if (!(st->variant->flags & ADIS16400_NO_BURST)) {
+               adis16400_setup_chan_mask(st);
+               indio_dev->available_scan_masks = st->avail_scan_mask;
+       }
 
        ret = adis_init(&st->adis, indio_dev, spi, &adis16400_data);
        if (ret)
index 847ca561afe014e83707d04eaef02054f9b2bbfa..55c267bbfd2f9293340fa2851bcf5cb245b22cc9 100644 (file)
@@ -38,7 +38,8 @@ static int iio_request_update_kfifo(struct iio_buffer *r)
                kfifo_free(&buf->kf);
                ret = __iio_allocate_kfifo(buf, buf->buffer.bytes_per_datum,
                                   buf->buffer.length);
-               buf->update_needed = false;
+               if (ret >= 0)
+                       buf->update_needed = false;
        } else {
                kfifo_reset_out(&buf->kf);
        }
index 91ecc46ffeaa0b9e5ecf25d3575d8ab364e4abe8..ef60bae738e344c510d529578051f7767eba7916 100644 (file)
@@ -43,8 +43,6 @@ struct prox_state {
 static const struct iio_chan_spec prox_channels[] = {
        {
                .type = IIO_PROXIMITY,
-               .modified = 1,
-               .channel2 = IIO_NO_MOD,
                .info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
                .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_OFFSET) |
                BIT(IIO_CHAN_INFO_SCALE) |
@@ -253,7 +251,6 @@ static int hid_prox_probe(struct platform_device *pdev)
        struct iio_dev *indio_dev;
        struct prox_state *prox_state;
        struct hid_sensor_hub_device *hsdev = pdev->dev.platform_data;
-       struct iio_chan_spec *channels;
 
        indio_dev = devm_iio_device_alloc(&pdev->dev,
                                sizeof(struct prox_state));
@@ -272,20 +269,21 @@ static int hid_prox_probe(struct platform_device *pdev)
                return ret;
        }
 
-       channels = kmemdup(prox_channels, sizeof(prox_channels), GFP_KERNEL);
-       if (!channels) {
+       indio_dev->channels = kmemdup(prox_channels, sizeof(prox_channels),
+                                     GFP_KERNEL);
+       if (!indio_dev->channels) {
                dev_err(&pdev->dev, "failed to duplicate channels\n");
                return -ENOMEM;
        }
 
-       ret = prox_parse_report(pdev, hsdev, channels,
+       ret = prox_parse_report(pdev, hsdev,
+                               (struct iio_chan_spec *)indio_dev->channels,
                                HID_USAGE_SENSOR_PROX, prox_state);
        if (ret) {
                dev_err(&pdev->dev, "failed to setup attributes\n");
                goto error_free_dev_mem;
        }
 
-       indio_dev->channels = channels;
        indio_dev->num_channels =
                                ARRAY_SIZE(prox_channels);
        indio_dev->dev.parent = &pdev->dev;
index 8ade473f99fee3ab35cb224eab0f69afebe2bf70..2e56f812a644d67a73f0e9bdccd0992c39777a25 100644 (file)
@@ -369,6 +369,7 @@ int st_magn_common_probe(struct iio_dev *indio_dev)
 
        indio_dev->modes = INDIO_DIRECT_MODE;
        indio_dev->info = &magn_info;
+       mutex_init(&mdata->tb.buf_lock);
 
        st_sensors_power_enable(indio_dev);
 
index 7c623e2bd6336c0968254e73547de8945efe4a42..a2602d8dd6d5ceea974cb1fdada67ddde7a2f129 100644 (file)
@@ -172,6 +172,7 @@ static s32 bmp280_compensate_temp(struct bmp280_data *data,
        var2 = (((((adc_temp >> 4) - ((s32)le16_to_cpu(buf[T1]))) *
                  ((adc_temp >> 4) - ((s32)le16_to_cpu(buf[T1])))) >> 12) *
                ((s32)(s16)le16_to_cpu(buf[T3]))) >> 14;
+       data->t_fine = var1 + var2;
 
        return (data->t_fine * 5 + 128) >> 8;
 }
index 7bb8d4c1f7df4922279dd328ddfc83fba1b113c4..3cf0bd67d24ca8001224f960513bbd93b45be1e5 100644 (file)
@@ -47,8 +47,6 @@ struct press_state {
 static const struct iio_chan_spec press_channels[] = {
        {
                .type = IIO_PRESSURE,
-               .modified = 1,
-               .channel2 = IIO_NO_MOD,
                .info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
                .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_OFFSET) |
                BIT(IIO_CHAN_INFO_SCALE) |
index 97baf40d424bd599687b124062081364f94b487e..e881fa6291e9228a56cc0a7f3d6cf3ee51621855 100644 (file)
@@ -417,6 +417,7 @@ int st_press_common_probe(struct iio_dev *indio_dev)
 
        indio_dev->modes = INDIO_DIRECT_MODE;
        indio_dev->info = &press_info;
+       mutex_init(&press_data->tb.buf_lock);
 
        st_sensors_power_enable(indio_dev);
 
index f80da50d84a5b6585a10656b369bcc33aedd0507..38339d220d7f52c402c08f581f20cf4ad8acea49 100644 (file)
@@ -472,13 +472,8 @@ int rdma_addr_find_dmac_by_grh(union ib_gid *sgid, union ib_gid *dgid, u8 *dmac,
        } sgid_addr, dgid_addr;
 
 
-       ret = rdma_gid2ip(&sgid_addr._sockaddr, sgid);
-       if (ret)
-               return ret;
-
-       ret = rdma_gid2ip(&dgid_addr._sockaddr, dgid);
-       if (ret)
-               return ret;
+       rdma_gid2ip(&sgid_addr._sockaddr, sgid);
+       rdma_gid2ip(&dgid_addr._sockaddr, dgid);
 
        memset(&dev_addr, 0, sizeof(dev_addr));
 
@@ -512,10 +507,8 @@ int rdma_addr_find_smac_by_sgid(union ib_gid *sgid, u8 *smac, u16 *vlan_id)
                struct sockaddr_in6 _sockaddr_in6;
        } gid_addr;
 
-       ret = rdma_gid2ip(&gid_addr._sockaddr, sgid);
+       rdma_gid2ip(&gid_addr._sockaddr, sgid);
 
-       if (ret)
-               return ret;
        memset(&dev_addr, 0, sizeof(dev_addr));
        ret = rdma_translate_ip(&gid_addr._sockaddr, &dev_addr, vlan_id);
        if (ret)
index e28a494e2a3a0f72b41af479b269262c6472cb77..0271608a51c40ff2ade721f94b710997ffbe5c2d 100644 (file)
@@ -437,39 +437,38 @@ static struct cm_id_private * cm_acquire_id(__be32 local_id, __be32 remote_id)
        return cm_id_priv;
 }
 
-static void cm_mask_copy(u8 *dst, u8 *src, u8 *mask)
+static void cm_mask_copy(u32 *dst, const u32 *src, const u32 *mask)
 {
        int i;
 
-       for (i = 0; i < IB_CM_COMPARE_SIZE / sizeof(unsigned long); i++)
-               ((unsigned long *) dst)[i] = ((unsigned long *) src)[i] &
-                                            ((unsigned long *) mask)[i];
+       for (i = 0; i < IB_CM_COMPARE_SIZE; i++)
+               dst[i] = src[i] & mask[i];
 }
 
 static int cm_compare_data(struct ib_cm_compare_data *src_data,
                           struct ib_cm_compare_data *dst_data)
 {
-       u8 src[IB_CM_COMPARE_SIZE];
-       u8 dst[IB_CM_COMPARE_SIZE];
+       u32 src[IB_CM_COMPARE_SIZE];
+       u32 dst[IB_CM_COMPARE_SIZE];
 
        if (!src_data || !dst_data)
                return 0;
 
        cm_mask_copy(src, src_data->data, dst_data->mask);
        cm_mask_copy(dst, dst_data->data, src_data->mask);
-       return memcmp(src, dst, IB_CM_COMPARE_SIZE);
+       return memcmp(src, dst, sizeof(src));
 }
 
-static int cm_compare_private_data(u8 *private_data,
+static int cm_compare_private_data(u32 *private_data,
                                   struct ib_cm_compare_data *dst_data)
 {
-       u8 src[IB_CM_COMPARE_SIZE];
+       u32 src[IB_CM_COMPARE_SIZE];
 
        if (!dst_data)
                return 0;
 
        cm_mask_copy(src, private_data, dst_data->mask);
-       return memcmp(src, dst_data->data, IB_CM_COMPARE_SIZE);
+       return memcmp(src, dst_data->data, sizeof(src));
 }
 
 /*
@@ -538,7 +537,7 @@ static struct cm_id_private * cm_insert_listen(struct cm_id_private *cm_id_priv)
 
 static struct cm_id_private * cm_find_listen(struct ib_device *device,
                                             __be64 service_id,
-                                            u8 *private_data)
+                                            u32 *private_data)
 {
        struct rb_node *node = cm.listen_service_table.rb_node;
        struct cm_id_private *cm_id_priv;
@@ -862,6 +861,7 @@ retest:
                cm_reject_sidr_req(cm_id_priv, IB_SIDR_REJECT);
                break;
        case IB_CM_REQ_SENT:
+       case IB_CM_MRA_REQ_RCVD:
                ib_cancel_mad(cm_id_priv->av.port->mad_agent, cm_id_priv->msg);
                spin_unlock_irq(&cm_id_priv->lock);
                ib_send_cm_rej(cm_id, IB_CM_REJ_TIMEOUT,
@@ -880,7 +880,6 @@ retest:
                                       NULL, 0, NULL, 0);
                }
                break;
-       case IB_CM_MRA_REQ_RCVD:
        case IB_CM_REP_SENT:
        case IB_CM_MRA_REP_RCVD:
                ib_cancel_mad(cm_id_priv->av.port->mad_agent, cm_id_priv->msg);
@@ -953,7 +952,7 @@ int ib_cm_listen(struct ib_cm_id *cm_id, __be64 service_id, __be64 service_mask,
                cm_mask_copy(cm_id_priv->compare_data->data,
                             compare_data->data, compare_data->mask);
                memcpy(cm_id_priv->compare_data->mask, compare_data->mask,
-                      IB_CM_COMPARE_SIZE);
+                      sizeof(compare_data->mask));
        }
 
        cm_id->state = IB_CM_LISTEN;
index be068f47e47e86b79065356e62bf1d193c1da36f..8b76f0ef965e88d7171e8cebcbaf2a0c9a29f962 100644 (file)
@@ -103,7 +103,7 @@ struct cm_req_msg {
        /* local ACK timeout:5, rsvd:3 */
        u8 alt_offset139;
 
-       u8 private_data[IB_CM_REQ_PRIVATE_DATA_SIZE];
+       u32 private_data[IB_CM_REQ_PRIVATE_DATA_SIZE / sizeof(u32)];
 
 } __attribute__ ((packed));
 
@@ -801,7 +801,7 @@ struct cm_sidr_req_msg {
        __be16 rsvd;
        __be64 service_id;
 
-       u8 private_data[IB_CM_SIDR_REQ_PRIVATE_DATA_SIZE];
+       u32 private_data[IB_CM_SIDR_REQ_PRIVATE_DATA_SIZE / sizeof(u32)];
 } __attribute__ ((packed));
 
 struct cm_sidr_rep_msg {
index d570030d899c0c662d2b208ce30dd2cd20bc3f78..38ffe098150351aef9ff2ac650726ae7926f6856 100644 (file)
@@ -845,33 +845,49 @@ static void cma_save_ib_info(struct rdma_cm_id *id, struct rdma_cm_id *listen_id
        listen_ib = (struct sockaddr_ib *) &listen_id->route.addr.src_addr;
        ib = (struct sockaddr_ib *) &id->route.addr.src_addr;
        ib->sib_family = listen_ib->sib_family;
-       ib->sib_pkey = path->pkey;
-       ib->sib_flowinfo = path->flow_label;
-       memcpy(&ib->sib_addr, &path->sgid, 16);
+       if (path) {
+               ib->sib_pkey = path->pkey;
+               ib->sib_flowinfo = path->flow_label;
+               memcpy(&ib->sib_addr, &path->sgid, 16);
+       } else {
+               ib->sib_pkey = listen_ib->sib_pkey;
+               ib->sib_flowinfo = listen_ib->sib_flowinfo;
+               ib->sib_addr = listen_ib->sib_addr;
+       }
        ib->sib_sid = listen_ib->sib_sid;
        ib->sib_sid_mask = cpu_to_be64(0xffffffffffffffffULL);
        ib->sib_scope_id = listen_ib->sib_scope_id;
 
-       ib = (struct sockaddr_ib *) &id->route.addr.dst_addr;
-       ib->sib_family = listen_ib->sib_family;
-       ib->sib_pkey = path->pkey;
-       ib->sib_flowinfo = path->flow_label;
-       memcpy(&ib->sib_addr, &path->dgid, 16);
+       if (path) {
+               ib = (struct sockaddr_ib *) &id->route.addr.dst_addr;
+               ib->sib_family = listen_ib->sib_family;
+               ib->sib_pkey = path->pkey;
+               ib->sib_flowinfo = path->flow_label;
+               memcpy(&ib->sib_addr, &path->dgid, 16);
+       }
+}
+
+static __be16 ss_get_port(const struct sockaddr_storage *ss)
+{
+       if (ss->ss_family == AF_INET)
+               return ((struct sockaddr_in *)ss)->sin_port;
+       else if (ss->ss_family == AF_INET6)
+               return ((struct sockaddr_in6 *)ss)->sin6_port;
+       BUG();
 }
 
 static void cma_save_ip4_info(struct rdma_cm_id *id, struct rdma_cm_id *listen_id,
                              struct cma_hdr *hdr)
 {
-       struct sockaddr_in *listen4, *ip4;
+       struct sockaddr_in *ip4;
 
-       listen4 = (struct sockaddr_in *) &listen_id->route.addr.src_addr;
        ip4 = (struct sockaddr_in *) &id->route.addr.src_addr;
-       ip4->sin_family = listen4->sin_family;
+       ip4->sin_family = AF_INET;
        ip4->sin_addr.s_addr = hdr->dst_addr.ip4.addr;
-       ip4->sin_port = listen4->sin_port;
+       ip4->sin_port = ss_get_port(&listen_id->route.addr.src_addr);
 
        ip4 = (struct sockaddr_in *) &id->route.addr.dst_addr;
-       ip4->sin_family = listen4->sin_family;
+       ip4->sin_family = AF_INET;
        ip4->sin_addr.s_addr = hdr->src_addr.ip4.addr;
        ip4->sin_port = hdr->port;
 }
@@ -879,16 +895,15 @@ static void cma_save_ip4_info(struct rdma_cm_id *id, struct rdma_cm_id *listen_i
 static void cma_save_ip6_info(struct rdma_cm_id *id, struct rdma_cm_id *listen_id,
                              struct cma_hdr *hdr)
 {
-       struct sockaddr_in6 *listen6, *ip6;
+       struct sockaddr_in6 *ip6;
 
-       listen6 = (struct sockaddr_in6 *) &listen_id->route.addr.src_addr;
        ip6 = (struct sockaddr_in6 *) &id->route.addr.src_addr;
-       ip6->sin6_family = listen6->sin6_family;
+       ip6->sin6_family = AF_INET6;
        ip6->sin6_addr = hdr->dst_addr.ip6;
-       ip6->sin6_port = listen6->sin6_port;
+       ip6->sin6_port = ss_get_port(&listen_id->route.addr.src_addr);
 
        ip6 = (struct sockaddr_in6 *) &id->route.addr.dst_addr;
-       ip6->sin6_family = listen6->sin6_family;
+       ip6->sin6_family = AF_INET6;
        ip6->sin6_addr = hdr->src_addr.ip6;
        ip6->sin6_port = hdr->port;
 }
@@ -898,9 +913,11 @@ static int cma_save_net_info(struct rdma_cm_id *id, struct rdma_cm_id *listen_id
 {
        struct cma_hdr *hdr;
 
-       if ((listen_id->route.addr.src_addr.ss_family == AF_IB) &&
-           (ib_event->event == IB_CM_REQ_RECEIVED)) {
-               cma_save_ib_info(id, listen_id, ib_event->param.req_rcvd.primary_path);
+       if (listen_id->route.addr.src_addr.ss_family == AF_IB) {
+               if (ib_event->event == IB_CM_REQ_RECEIVED)
+                       cma_save_ib_info(id, listen_id, ib_event->param.req_rcvd.primary_path);
+               else if (ib_event->event == IB_CM_SIDR_REQ_RECEIVED)
+                       cma_save_ib_info(id, listen_id, NULL);
                return 0;
        }
 
index b85ddbc979e069e909cee12ac37cd31be244652d..e6ffa2e66c1ac54b7a2645f59bbb28c00bc91cc3 100644 (file)
@@ -33,7 +33,7 @@
 
 #include "iwpm_util.h"
 
-static const char iwpm_ulib_name[] = "iWarpPortMapperUser";
+static const char iwpm_ulib_name[IWPM_ULIBNAME_SIZE] = "iWarpPortMapperUser";
 static int iwpm_ulib_version = 3;
 static int iwpm_user_pid = IWPM_PID_UNDEFINED;
 static atomic_t echo_nlmsg_seq;
@@ -468,7 +468,8 @@ add_mapping_response_exit:
 }
 EXPORT_SYMBOL(iwpm_add_mapping_cb);
 
-/* netlink attribute policy for the response to add and query mapping request */
+/* netlink attribute policy for the response to add and query mapping request
+ * and response with remote address info */
 static const struct nla_policy resp_query_policy[IWPM_NLA_RQUERY_MAPPING_MAX] = {
        [IWPM_NLA_QUERY_MAPPING_SEQ]      = { .type = NLA_U32 },
        [IWPM_NLA_QUERY_LOCAL_ADDR]       = { .len = sizeof(struct sockaddr_storage) },
@@ -559,6 +560,76 @@ query_mapping_response_exit:
 }
 EXPORT_SYMBOL(iwpm_add_and_query_mapping_cb);
 
+/*
+ * iwpm_remote_info_cb - Process a port mapper message, containing
+ *                       the remote connecting peer address info
+ */
+int iwpm_remote_info_cb(struct sk_buff *skb, struct netlink_callback *cb)
+{
+       struct nlattr *nltb[IWPM_NLA_RQUERY_MAPPING_MAX];
+       struct sockaddr_storage *local_sockaddr, *remote_sockaddr;
+       struct sockaddr_storage *mapped_loc_sockaddr, *mapped_rem_sockaddr;
+       struct iwpm_remote_info *rem_info;
+       const char *msg_type;
+       u8 nl_client;
+       int ret = -EINVAL;
+
+       msg_type = "Remote Mapping info";
+       if (iwpm_parse_nlmsg(cb, IWPM_NLA_RQUERY_MAPPING_MAX,
+                               resp_query_policy, nltb, msg_type))
+               return ret;
+
+       nl_client = RDMA_NL_GET_CLIENT(cb->nlh->nlmsg_type);
+       if (!iwpm_valid_client(nl_client)) {
+               pr_info("%s: Invalid port mapper client = %d\n",
+                               __func__, nl_client);
+               return ret;
+       }
+       atomic_set(&echo_nlmsg_seq, cb->nlh->nlmsg_seq);
+
+       local_sockaddr = (struct sockaddr_storage *)
+                       nla_data(nltb[IWPM_NLA_QUERY_LOCAL_ADDR]);
+       remote_sockaddr = (struct sockaddr_storage *)
+                       nla_data(nltb[IWPM_NLA_QUERY_REMOTE_ADDR]);
+       mapped_loc_sockaddr = (struct sockaddr_storage *)
+                       nla_data(nltb[IWPM_NLA_RQUERY_MAPPED_LOC_ADDR]);
+       mapped_rem_sockaddr = (struct sockaddr_storage *)
+                       nla_data(nltb[IWPM_NLA_RQUERY_MAPPED_REM_ADDR]);
+
+       if (mapped_loc_sockaddr->ss_family != local_sockaddr->ss_family ||
+               mapped_rem_sockaddr->ss_family != remote_sockaddr->ss_family) {
+               pr_info("%s: Sockaddr family doesn't match the requested one\n",
+                               __func__);
+               return ret;
+       }
+       rem_info = kzalloc(sizeof(struct iwpm_remote_info), GFP_ATOMIC);
+       if (!rem_info) {
+               pr_err("%s: Unable to allocate a remote info\n", __func__);
+               ret = -ENOMEM;
+               return ret;
+       }
+       memcpy(&rem_info->mapped_loc_sockaddr, mapped_loc_sockaddr,
+              sizeof(struct sockaddr_storage));
+       memcpy(&rem_info->remote_sockaddr, remote_sockaddr,
+              sizeof(struct sockaddr_storage));
+       memcpy(&rem_info->mapped_rem_sockaddr, mapped_rem_sockaddr,
+              sizeof(struct sockaddr_storage));
+       rem_info->nl_client = nl_client;
+
+       iwpm_add_remote_info(rem_info);
+
+       iwpm_print_sockaddr(local_sockaddr,
+                       "remote_info: Local sockaddr:");
+       iwpm_print_sockaddr(mapped_loc_sockaddr,
+                       "remote_info: Mapped local sockaddr:");
+       iwpm_print_sockaddr(remote_sockaddr,
+                       "remote_info: Remote sockaddr:");
+       iwpm_print_sockaddr(mapped_rem_sockaddr,
+                       "remote_info: Mapped remote sockaddr:");
+       return ret;
+}
+EXPORT_SYMBOL(iwpm_remote_info_cb);
+
 /* netlink attribute policy for the received request for mapping info */
 static const struct nla_policy resp_mapinfo_policy[IWPM_NLA_MAPINFO_REQ_MAX] = {
        [IWPM_NLA_MAPINFO_ULIB_NAME] = { .type = NLA_STRING,
index 69e9f84c16056246bd5d45ca08293ce5b272ec84..a626795bf9c71f43f7d526d07ae3a490399fdb79 100644 (file)
 
 #include "iwpm_util.h"
 
-#define IWPM_HASH_BUCKET_SIZE  512
-#define IWPM_HASH_BUCKET_MASK  (IWPM_HASH_BUCKET_SIZE - 1)
+#define IWPM_MAPINFO_HASH_SIZE 512
+#define IWPM_MAPINFO_HASH_MASK (IWPM_MAPINFO_HASH_SIZE - 1)
+#define IWPM_REMINFO_HASH_SIZE 64
+#define IWPM_REMINFO_HASH_MASK (IWPM_REMINFO_HASH_SIZE - 1)
 
 static LIST_HEAD(iwpm_nlmsg_req_list);
 static DEFINE_SPINLOCK(iwpm_nlmsg_req_lock);
@@ -42,31 +44,49 @@ static DEFINE_SPINLOCK(iwpm_nlmsg_req_lock);
 static struct hlist_head *iwpm_hash_bucket;
 static DEFINE_SPINLOCK(iwpm_mapinfo_lock);
 
+static struct hlist_head *iwpm_reminfo_bucket;
+static DEFINE_SPINLOCK(iwpm_reminfo_lock);
+
 static DEFINE_MUTEX(iwpm_admin_lock);
 static struct iwpm_admin_data iwpm_admin;
 
 int iwpm_init(u8 nl_client)
 {
+       int ret = 0;
        if (iwpm_valid_client(nl_client))
                return -EINVAL;
        mutex_lock(&iwpm_admin_lock);
        if (atomic_read(&iwpm_admin.refcount) == 0) {
-               iwpm_hash_bucket = kzalloc(IWPM_HASH_BUCKET_SIZE *
+               iwpm_hash_bucket = kzalloc(IWPM_MAPINFO_HASH_SIZE *
                                        sizeof(struct hlist_head), GFP_KERNEL);
                if (!iwpm_hash_bucket) {
-                       mutex_unlock(&iwpm_admin_lock);
+                       ret = -ENOMEM;
                        pr_err("%s Unable to create mapinfo hash table\n", __func__);
-                       return -ENOMEM;
+                       goto init_exit;
+               }
+               iwpm_reminfo_bucket = kzalloc(IWPM_REMINFO_HASH_SIZE *
+                                       sizeof(struct hlist_head), GFP_KERNEL);
+               if (!iwpm_reminfo_bucket) {
+                       kfree(iwpm_hash_bucket);
+                       ret = -ENOMEM;
+                       pr_err("%s Unable to create reminfo hash table\n", __func__);
+                       goto init_exit;
                }
        }
        atomic_inc(&iwpm_admin.refcount);
+init_exit:
        mutex_unlock(&iwpm_admin_lock);
-       iwpm_set_valid(nl_client, 1);
-       return 0;
+       if (!ret) {
+               iwpm_set_valid(nl_client, 1);
+               pr_debug("%s: Mapinfo and reminfo tables are created\n",
+                               __func__);
+       }
+       return ret;
 }
 EXPORT_SYMBOL(iwpm_init);
 
 static void free_hash_bucket(void);
+static void free_reminfo_bucket(void);
 
 int iwpm_exit(u8 nl_client)
 {
@@ -81,7 +101,8 @@ int iwpm_exit(u8 nl_client)
        }
        if (atomic_dec_and_test(&iwpm_admin.refcount)) {
                free_hash_bucket();
-               pr_debug("%s: Mapinfo hash table is destroyed\n", __func__);
+               free_reminfo_bucket();
+               pr_debug("%s: Resources are destroyed\n", __func__);
        }
        mutex_unlock(&iwpm_admin_lock);
        iwpm_set_valid(nl_client, 0);
@@ -89,7 +110,7 @@ int iwpm_exit(u8 nl_client)
 }
 EXPORT_SYMBOL(iwpm_exit);
 
-static struct hlist_head *get_hash_bucket_head(struct sockaddr_storage *,
+static struct hlist_head *get_mapinfo_hash_bucket(struct sockaddr_storage *,
                                               struct sockaddr_storage *);
 
 int iwpm_create_mapinfo(struct sockaddr_storage *local_sockaddr,
@@ -99,9 +120,10 @@ int iwpm_create_mapinfo(struct sockaddr_storage *local_sockaddr,
        struct hlist_head *hash_bucket_head;
        struct iwpm_mapping_info *map_info;
        unsigned long flags;
+       int ret = -EINVAL;
 
        if (!iwpm_valid_client(nl_client))
-               return -EINVAL;
+               return ret;
        map_info = kzalloc(sizeof(struct iwpm_mapping_info), GFP_KERNEL);
        if (!map_info) {
                pr_err("%s: Unable to allocate a mapping info\n", __func__);
@@ -115,13 +137,16 @@ int iwpm_create_mapinfo(struct sockaddr_storage *local_sockaddr,
 
        spin_lock_irqsave(&iwpm_mapinfo_lock, flags);
        if (iwpm_hash_bucket) {
-               hash_bucket_head = get_hash_bucket_head(
+               hash_bucket_head = get_mapinfo_hash_bucket(
                                        &map_info->local_sockaddr,
                                        &map_info->mapped_sockaddr);
-               hlist_add_head(&map_info->hlist_node, hash_bucket_head);
+               if (hash_bucket_head) {
+                       hlist_add_head(&map_info->hlist_node, hash_bucket_head);
+                       ret = 0;
+               }
        }
        spin_unlock_irqrestore(&iwpm_mapinfo_lock, flags);
-       return 0;
+       return ret;
 }
 EXPORT_SYMBOL(iwpm_create_mapinfo);
 
@@ -136,9 +161,12 @@ int iwpm_remove_mapinfo(struct sockaddr_storage *local_sockaddr,
 
        spin_lock_irqsave(&iwpm_mapinfo_lock, flags);
        if (iwpm_hash_bucket) {
-               hash_bucket_head = get_hash_bucket_head(
+               hash_bucket_head = get_mapinfo_hash_bucket(
                                        local_sockaddr,
                                        mapped_local_addr);
+               if (!hash_bucket_head)
+                       goto remove_mapinfo_exit;
+
                hlist_for_each_entry_safe(map_info, tmp_hlist_node,
                                        hash_bucket_head, hlist_node) {
 
@@ -152,6 +180,7 @@ int iwpm_remove_mapinfo(struct sockaddr_storage *local_sockaddr,
                        }
                }
        }
+remove_mapinfo_exit:
        spin_unlock_irqrestore(&iwpm_mapinfo_lock, flags);
        return ret;
 }
@@ -166,7 +195,7 @@ static void free_hash_bucket(void)
 
        /* remove all the mapinfo data from the list */
        spin_lock_irqsave(&iwpm_mapinfo_lock, flags);
-       for (i = 0; i < IWPM_HASH_BUCKET_SIZE; i++) {
+       for (i = 0; i < IWPM_MAPINFO_HASH_SIZE; i++) {
                hlist_for_each_entry_safe(map_info, tmp_hlist_node,
                        &iwpm_hash_bucket[i], hlist_node) {
 
@@ -180,6 +209,96 @@ static void free_hash_bucket(void)
        spin_unlock_irqrestore(&iwpm_mapinfo_lock, flags);
 }
 
+static void free_reminfo_bucket(void)
+{
+       struct hlist_node *tmp_hlist_node;
+       struct iwpm_remote_info *rem_info;
+       unsigned long flags;
+       int i;
+
+       /* remove all the remote info from the list */
+       spin_lock_irqsave(&iwpm_reminfo_lock, flags);
+       for (i = 0; i < IWPM_REMINFO_HASH_SIZE; i++) {
+               hlist_for_each_entry_safe(rem_info, tmp_hlist_node,
+                       &iwpm_reminfo_bucket[i], hlist_node) {
+
+                               hlist_del_init(&rem_info->hlist_node);
+                               kfree(rem_info);
+                       }
+       }
+       /* free the hash list */
+       kfree(iwpm_reminfo_bucket);
+       iwpm_reminfo_bucket = NULL;
+       spin_unlock_irqrestore(&iwpm_reminfo_lock, flags);
+}
+
+static struct hlist_head *get_reminfo_hash_bucket(struct sockaddr_storage *,
+                                               struct sockaddr_storage *);
+
+void iwpm_add_remote_info(struct iwpm_remote_info *rem_info)
+{
+       struct hlist_head *hash_bucket_head;
+       unsigned long flags;
+
+       spin_lock_irqsave(&iwpm_reminfo_lock, flags);
+       if (iwpm_reminfo_bucket) {
+               hash_bucket_head = get_reminfo_hash_bucket(
+                                       &rem_info->mapped_loc_sockaddr,
+                                       &rem_info->mapped_rem_sockaddr);
+               if (hash_bucket_head)
+                       hlist_add_head(&rem_info->hlist_node, hash_bucket_head);
+       }
+       spin_unlock_irqrestore(&iwpm_reminfo_lock, flags);
+}
+
+int iwpm_get_remote_info(struct sockaddr_storage *mapped_loc_addr,
+                               struct sockaddr_storage *mapped_rem_addr,
+                               struct sockaddr_storage *remote_addr,
+                               u8 nl_client)
+{
+       struct hlist_node *tmp_hlist_node;
+       struct hlist_head *hash_bucket_head;
+       struct iwpm_remote_info *rem_info = NULL;
+       unsigned long flags;
+       int ret = -EINVAL;
+
+       if (!iwpm_valid_client(nl_client)) {
+               pr_info("%s: Invalid client = %d\n", __func__, nl_client);
+               return ret;
+       }
+       spin_lock_irqsave(&iwpm_reminfo_lock, flags);
+       if (iwpm_reminfo_bucket) {
+               hash_bucket_head = get_reminfo_hash_bucket(
+                                       mapped_loc_addr,
+                                       mapped_rem_addr);
+               if (!hash_bucket_head)
+                       goto get_remote_info_exit;
+               hlist_for_each_entry_safe(rem_info, tmp_hlist_node,
+                                       hash_bucket_head, hlist_node) {
+
+                       if (!iwpm_compare_sockaddr(&rem_info->mapped_loc_sockaddr,
+                               mapped_loc_addr) &&
+                               !iwpm_compare_sockaddr(&rem_info->mapped_rem_sockaddr,
+                               mapped_rem_addr)) {
+
+                               memcpy(remote_addr, &rem_info->remote_sockaddr,
+                                       sizeof(struct sockaddr_storage));
+                               iwpm_print_sockaddr(remote_addr,
+                                               "get_remote_info: Remote sockaddr:");
+
+                               hlist_del_init(&rem_info->hlist_node);
+                               kfree(rem_info);
+                               ret = 0;
+                               break;
+                       }
+               }
+       }
+get_remote_info_exit:
+       spin_unlock_irqrestore(&iwpm_reminfo_lock, flags);
+       return ret;
+}
+EXPORT_SYMBOL(iwpm_get_remote_info);
+
 struct iwpm_nlmsg_request *iwpm_get_nlmsg_request(__u32 nlmsg_seq,
                                        u8 nl_client, gfp_t gfp)
 {
@@ -409,31 +528,54 @@ static u32 iwpm_ipv4_jhash(struct sockaddr_in *ipv4_sockaddr)
        return hash;
 }
 
-static struct hlist_head *get_hash_bucket_head(struct sockaddr_storage
-                                              *local_sockaddr,
-                                              struct sockaddr_storage
-                                              *mapped_sockaddr)
+static int get_hash_bucket(struct sockaddr_storage *a_sockaddr,
+                               struct sockaddr_storage *b_sockaddr, u32 *hash)
 {
-       u32 local_hash, mapped_hash, hash;
+       u32 a_hash, b_hash;
 
-       if (local_sockaddr->ss_family == AF_INET) {
-               local_hash = iwpm_ipv4_jhash((struct sockaddr_in *) local_sockaddr);
-               mapped_hash = iwpm_ipv4_jhash((struct sockaddr_in *) mapped_sockaddr);
+       if (a_sockaddr->ss_family == AF_INET) {
+               a_hash = iwpm_ipv4_jhash((struct sockaddr_in *) a_sockaddr);
+               b_hash = iwpm_ipv4_jhash((struct sockaddr_in *) b_sockaddr);
 
-       } else if (local_sockaddr->ss_family == AF_INET6) {
-               local_hash = iwpm_ipv6_jhash((struct sockaddr_in6 *) local_sockaddr);
-               mapped_hash = iwpm_ipv6_jhash((struct sockaddr_in6 *) mapped_sockaddr);
+       } else if (a_sockaddr->ss_family == AF_INET6) {
+               a_hash = iwpm_ipv6_jhash((struct sockaddr_in6 *) a_sockaddr);
+               b_hash = iwpm_ipv6_jhash((struct sockaddr_in6 *) b_sockaddr);
        } else {
                pr_err("%s: Invalid sockaddr family\n", __func__);
-               return NULL;
+               return -EINVAL;
        }
 
-       if (local_hash == mapped_hash) /* if port mapper isn't available */
-               hash = local_hash;
+       if (a_hash == b_hash) /* if port mapper isn't available */
+               *hash = a_hash;
        else
-               hash = jhash_2words(local_hash, mapped_hash, 0);
+               *hash = jhash_2words(a_hash, b_hash, 0);
+       return 0;
+}
+
+static struct hlist_head *get_mapinfo_hash_bucket(struct sockaddr_storage
+                               *local_sockaddr, struct sockaddr_storage
+                               *mapped_sockaddr)
+{
+       u32 hash;
+       int ret;
 
-       return &iwpm_hash_bucket[hash & IWPM_HASH_BUCKET_MASK];
+       ret = get_hash_bucket(local_sockaddr, mapped_sockaddr, &hash);
+       if (ret)
+               return NULL;
+       return &iwpm_hash_bucket[hash & IWPM_MAPINFO_HASH_MASK];
+}
+
+static struct hlist_head *get_reminfo_hash_bucket(struct sockaddr_storage
+                               *mapped_loc_sockaddr, struct sockaddr_storage
+                               *mapped_rem_sockaddr)
+{
+       u32 hash;
+       int ret;
+
+       ret = get_hash_bucket(mapped_loc_sockaddr, mapped_rem_sockaddr, &hash);
+       if (ret)
+               return NULL;
+       return &iwpm_reminfo_bucket[hash & IWPM_REMINFO_HASH_MASK];
 }
 
 static int send_mapinfo_num(u32 mapping_num, u8 nl_client, int iwpm_pid)
@@ -512,7 +654,7 @@ int iwpm_send_mapinfo(u8 nl_client, int iwpm_pid)
        }
        skb_num++;
        spin_lock_irqsave(&iwpm_mapinfo_lock, flags);
-       for (i = 0; i < IWPM_HASH_BUCKET_SIZE; i++) {
+       for (i = 0; i < IWPM_MAPINFO_HASH_SIZE; i++) {
                hlist_for_each_entry(map_info, &iwpm_hash_bucket[i],
                                     hlist_node) {
                        if (map_info->nl_client != nl_client)
@@ -595,7 +737,7 @@ int iwpm_mapinfo_available(void)
 
        spin_lock_irqsave(&iwpm_mapinfo_lock, flags);
        if (iwpm_hash_bucket) {
-               for (i = 0; i < IWPM_HASH_BUCKET_SIZE; i++) {
+               for (i = 0; i < IWPM_MAPINFO_HASH_SIZE; i++) {
                        if (!hlist_empty(&iwpm_hash_bucket[i])) {
                                full_bucket = 1;
                                break;
index 9777c869a1405d54ab47f5132595bd3868953383..ee2d9ff095be2d68d14c9c48eb551f9647ca562f 100644 (file)
@@ -76,6 +76,14 @@ struct iwpm_mapping_info {
        u8     nl_client;
 };
 
+struct iwpm_remote_info {
+       struct hlist_node hlist_node;
+       struct sockaddr_storage remote_sockaddr;
+       struct sockaddr_storage mapped_loc_sockaddr;
+       struct sockaddr_storage mapped_rem_sockaddr;
+       u8     nl_client;
+};
+
 struct iwpm_admin_data {
        atomic_t refcount;
        atomic_t nlmsg_seq;
@@ -127,6 +135,13 @@ int iwpm_wait_complete_req(struct iwpm_nlmsg_request *nlmsg_request);
  */
 int iwpm_get_nlmsg_seq(void);
 
+/**
+ * iwpm_add_reminfo - Add remote address info of the connecting peer
+ *                    to the remote info hash table
+ * @reminfo: The remote info to be added
+ */
+void iwpm_add_remote_info(struct iwpm_remote_info *reminfo);
+
 /**
  * iwpm_valid_client - Check if the port mapper client is valid
  * @nl_client: The index of the netlink client
index 8b8cc6fa0ab0c1ebf966b2ace4932807d9181bf1..40becdb3196e07b97c94ade818af5755bfaae4db 100644 (file)
@@ -446,7 +446,6 @@ static int ib_umem_odp_map_dma_single_page(
        int remove_existing_mapping = 0;
        int ret = 0;
 
-       mutex_lock(&umem->odp_data->umem_mutex);
        /*
         * Note: we avoid writing if seq is different from the initial seq, to
         * handle case of a racing notifier. This check also allows us to bail
@@ -479,8 +478,6 @@ static int ib_umem_odp_map_dma_single_page(
        }
 
 out:
-       mutex_unlock(&umem->odp_data->umem_mutex);
-
        /* On Demand Paging - avoid pinning the page */
        if (umem->context->invalidate_range || !stored_page)
                put_page(page);
@@ -586,6 +583,7 @@ int ib_umem_odp_map_dma_pages(struct ib_umem *umem, u64 user_virt, u64 bcnt,
 
                bcnt -= min_t(size_t, npages << PAGE_SHIFT, bcnt);
                user_virt += npages << PAGE_SHIFT;
+               mutex_lock(&umem->odp_data->umem_mutex);
                for (j = 0; j < npages; ++j) {
                        ret = ib_umem_odp_map_dma_single_page(
                                umem, k, base_virt_addr, local_page_list[j],
@@ -594,6 +592,7 @@ int ib_umem_odp_map_dma_pages(struct ib_umem *umem, u64 user_virt, u64 bcnt,
                                break;
                        k++;
                }
+               mutex_unlock(&umem->odp_data->umem_mutex);
 
                if (ret < 0) {
                        /* Release left over pages when handling errors. */
@@ -633,12 +632,11 @@ void ib_umem_odp_unmap_dma_pages(struct ib_umem *umem, u64 virt,
         * faults from completion. We might be racing with other
         * invalidations, so we must make sure we free each page only
         * once. */
+       mutex_lock(&umem->odp_data->umem_mutex);
        for (addr = virt; addr < bound; addr += (u64)umem->page_size) {
                idx = (addr - ib_umem_start(umem)) / PAGE_SIZE;
-               mutex_lock(&umem->odp_data->umem_mutex);
                if (umem->odp_data->page_list[idx]) {
                        struct page *page = umem->odp_data->page_list[idx];
-                       struct page *head_page = compound_head(page);
                        dma_addr_t dma = umem->odp_data->dma_list[idx];
                        dma_addr_t dma_addr = dma & ODP_DMA_ADDR_MASK;
 
@@ -646,7 +644,8 @@ void ib_umem_odp_unmap_dma_pages(struct ib_umem *umem, u64 virt,
 
                        ib_dma_unmap_page(dev, dma_addr, PAGE_SIZE,
                                          DMA_BIDIRECTIONAL);
-                       if (dma & ODP_WRITE_ALLOWED_BIT)
+                       if (dma & ODP_WRITE_ALLOWED_BIT) {
+                               struct page *head_page = compound_head(page);
                                /*
                                 * set_page_dirty prefers being called with
                                 * the page lock. However, MMU notifiers are
@@ -657,13 +656,14 @@ void ib_umem_odp_unmap_dma_pages(struct ib_umem *umem, u64 virt,
                                 * be removed.
                                 */
                                set_page_dirty(head_page);
+                       }
                        /* on demand pinning support */
                        if (!umem->context->invalidate_range)
                                put_page(page);
                        umem->odp_data->page_list[idx] = NULL;
                        umem->odp_data->dma_list[idx] = 0;
                }
-               mutex_unlock(&umem->odp_data->umem_mutex);
        }
+       mutex_unlock(&umem->odp_data->umem_mutex);
 }
 EXPORT_SYMBOL(ib_umem_odp_unmap_dma_pages);
index 57176ddd4c50ff677da5c711b8b7d14e9a020d0d..3ad8dc798f52c9101261882ac19138efb3905b94 100644 (file)
@@ -583,6 +583,22 @@ static void c4iw_record_pm_msg(struct c4iw_ep *ep,
                sizeof(ep->com.mapped_remote_addr));
 }
 
+static int get_remote_addr(struct c4iw_ep *parent_ep, struct c4iw_ep *child_ep)
+{
+       int ret;
+
+       print_addr(&parent_ep->com, __func__, "get_remote_addr parent_ep ");
+       print_addr(&child_ep->com, __func__, "get_remote_addr child_ep ");
+
+       ret = iwpm_get_remote_info(&parent_ep->com.mapped_local_addr,
+                                  &child_ep->com.mapped_remote_addr,
+                                  &child_ep->com.remote_addr, RDMA_NL_C4IW);
+       if (ret)
+               PDBG("Unable to find remote peer addr info - err %d\n", ret);
+
+       return ret;
+}
+
 static void best_mtu(const unsigned short *mtus, unsigned short mtu,
                     unsigned int *idx, int use_ts, int ipv6)
 {
@@ -675,7 +691,7 @@ static int send_connect(struct c4iw_ep *ep)
        if (is_t5(ep->com.dev->rdev.lldi.adapter_type)) {
                opt2 |= T5_OPT_2_VALID_F;
                opt2 |= CONG_CNTRL_V(CONG_ALG_TAHOE);
-               opt2 |= CONG_CNTRL_VALID; /* OPT_2_ISS for T5 */
+               opt2 |= T5_ISS_F;
        }
        t4_set_arp_err_handler(skb, ep, act_open_req_arp_failure);
 
@@ -2042,9 +2058,12 @@ static int act_open_rpl(struct c4iw_dev *dev, struct sk_buff *skb)
             status, status2errno(status));
 
        if (is_neg_adv(status)) {
-               dev_warn(&dev->rdev.lldi.pdev->dev,
-                        "Connection problems for atid %u status %u (%s)\n",
-                        atid, status, neg_adv_str(status));
+               PDBG("%s Connection problems for atid %u status %u (%s)\n",
+                    __func__, atid, status, neg_adv_str(status));
+               ep->stats.connect_neg_adv++;
+               mutex_lock(&dev->rdev.stats.lock);
+               dev->rdev.stats.neg_adv++;
+               mutex_unlock(&dev->rdev.stats.lock);
                return 0;
        }
 
@@ -2214,7 +2233,7 @@ static void accept_cr(struct c4iw_ep *ep, struct sk_buff *skb,
                u32 isn = (prandom_u32() & ~7UL) - 1;
                opt2 |= T5_OPT_2_VALID_F;
                opt2 |= CONG_CNTRL_V(CONG_ALG_TAHOE);
-               opt2 |= CONG_CNTRL_VALID; /* OPT_2_ISS for T5 */
+               opt2 |= T5_ISS_F;
                rpl5 = (void *)rpl;
                memset(&rpl5->iss, 0, roundup(sizeof(*rpl5)-sizeof(*rpl), 16));
                if (peer2peer)
@@ -2352,27 +2371,57 @@ static int pass_accept_req(struct c4iw_dev *dev, struct sk_buff *skb)
        state_set(&child_ep->com, CONNECTING);
        child_ep->com.dev = dev;
        child_ep->com.cm_id = NULL;
+
+       /*
+        * The mapped_local and mapped_remote addresses get setup with
+        * the actual 4-tuple.  The local address will be based on the
+        * actual local address of the connection, but on the port number
+        * of the parent listening endpoint.  The remote address is
+        * setup based on a query to the IWPM since we don't know what it
+        * originally was before mapping.  If no mapping was done, then
+        * mapped_remote == remote, and mapped_local == local.
+        */
        if (iptype == 4) {
                struct sockaddr_in *sin = (struct sockaddr_in *)
-                       &child_ep->com.local_addr;
+                       &child_ep->com.mapped_local_addr;
+
                sin->sin_family = PF_INET;
                sin->sin_port = local_port;
                sin->sin_addr.s_addr = *(__be32 *)local_ip;
-               sin = (struct sockaddr_in *)&child_ep->com.remote_addr;
+
+               sin = (struct sockaddr_in *)&child_ep->com.local_addr;
+               sin->sin_family = PF_INET;
+               sin->sin_port = ((struct sockaddr_in *)
+                                &parent_ep->com.local_addr)->sin_port;
+               sin->sin_addr.s_addr = *(__be32 *)local_ip;
+
+               sin = (struct sockaddr_in *)&child_ep->com.mapped_remote_addr;
                sin->sin_family = PF_INET;
                sin->sin_port = peer_port;
                sin->sin_addr.s_addr = *(__be32 *)peer_ip;
        } else {
                struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)
-                       &child_ep->com.local_addr;
+                       &child_ep->com.mapped_local_addr;
+
                sin6->sin6_family = PF_INET6;
                sin6->sin6_port = local_port;
                memcpy(sin6->sin6_addr.s6_addr, local_ip, 16);
-               sin6 = (struct sockaddr_in6 *)&child_ep->com.remote_addr;
+
+               sin6 = (struct sockaddr_in6 *)&child_ep->com.local_addr;
+               sin6->sin6_family = PF_INET6;
+               sin6->sin6_port = ((struct sockaddr_in6 *)
+                                  &parent_ep->com.local_addr)->sin6_port;
+               memcpy(sin6->sin6_addr.s6_addr, local_ip, 16);
+
+               sin6 = (struct sockaddr_in6 *)&child_ep->com.mapped_remote_addr;
                sin6->sin6_family = PF_INET6;
                sin6->sin6_port = peer_port;
                memcpy(sin6->sin6_addr.s6_addr, peer_ip, 16);
        }
+       memcpy(&child_ep->com.remote_addr, &child_ep->com.mapped_remote_addr,
+              sizeof(child_ep->com.remote_addr));
+       get_remote_addr(parent_ep, child_ep);
+
        c4iw_get_ep(&parent_ep->com);
        child_ep->parent_ep = parent_ep;
        child_ep->tos = PASS_OPEN_TOS_G(ntohl(req->tos_stid));
@@ -2520,9 +2569,13 @@ static int peer_abort(struct c4iw_dev *dev, struct sk_buff *skb)
 
        ep = lookup_tid(t, tid);
        if (is_neg_adv(req->status)) {
-               dev_warn(&dev->rdev.lldi.pdev->dev,
-                        "Negative advice on abort - tid %u status %d (%s)\n",
-                        ep->hwtid, req->status, neg_adv_str(req->status));
+               PDBG("%s Negative advice on abort- tid %u status %d (%s)\n",
+                    __func__, ep->hwtid, req->status,
+                    neg_adv_str(req->status));
+               ep->stats.abort_neg_adv++;
+               mutex_lock(&dev->rdev.stats.lock);
+               dev->rdev.stats.neg_adv++;
+               mutex_unlock(&dev->rdev.stats.lock);
                return 0;
        }
        PDBG("%s ep %p tid %u state %u\n", __func__, ep, ep->hwtid,
@@ -3571,7 +3624,7 @@ static void send_fw_pass_open_req(struct c4iw_dev *dev, struct sk_buff *skb,
         * TP will ignore any value > 0 for MSS index.
         */
        req->tcb.opt0 = cpu_to_be64(MSS_IDX_V(0xF));
-       req->cookie = (unsigned long)skb;
+       req->cookie = (uintptr_t)skb;
 
        set_wr_txq(req_skb, CPL_PRIORITY_CONTROL, port_id);
        ret = cxgb4_ofld_send(dev->rdev.lldi.ports[0], req_skb);
@@ -3931,9 +3984,11 @@ static int peer_abort_intr(struct c4iw_dev *dev, struct sk_buff *skb)
                return 0;
        }
        if (is_neg_adv(req->status)) {
-               dev_warn(&dev->rdev.lldi.pdev->dev,
-                        "Negative advice on abort - tid %u status %d (%s)\n",
-                        ep->hwtid, req->status, neg_adv_str(req->status));
+               PDBG("%s Negative advice on abort- tid %u status %d (%s)\n",
+                    __func__, ep->hwtid, req->status,
+                    neg_adv_str(req->status));
+               ep->stats.abort_neg_adv++;
+               dev->rdev.stats.neg_adv++;
                kfree_skb(skb);
                return 0;
        }
index ab7692ac2044b0a351c10681f08f63759f1934e8..68ddb37102152ec5382a7bbee7e9bab89e681b94 100644 (file)
@@ -55,7 +55,7 @@ static int destroy_cq(struct c4iw_rdev *rdev, struct t4_cq *cq,
                        FW_RI_RES_WR_NRES_V(1) |
                        FW_WR_COMPL_F);
        res_wr->len16_pkd = cpu_to_be32(DIV_ROUND_UP(wr_len, 16));
-       res_wr->cookie = (unsigned long) &wr_wait;
+       res_wr->cookie = (uintptr_t)&wr_wait;
        res = res_wr->res;
        res->u.cq.restype = FW_RI_RES_TYPE_CQ;
        res->u.cq.op = FW_RI_RES_OP_RESET;
@@ -125,7 +125,7 @@ static int create_cq(struct c4iw_rdev *rdev, struct t4_cq *cq,
                        FW_RI_RES_WR_NRES_V(1) |
                        FW_WR_COMPL_F);
        res_wr->len16_pkd = cpu_to_be32(DIV_ROUND_UP(wr_len, 16));
-       res_wr->cookie = (unsigned long) &wr_wait;
+       res_wr->cookie = (uintptr_t)&wr_wait;
        res = res_wr->res;
        res->u.cq.restype = FW_RI_RES_TYPE_CQ;
        res->u.cq.op = FW_RI_RES_OP_WRITE;
@@ -156,12 +156,19 @@ static int create_cq(struct c4iw_rdev *rdev, struct t4_cq *cq,
                goto err4;
 
        cq->gen = 1;
-       cq->gts = rdev->lldi.gts_reg;
        cq->rdev = rdev;
        if (user) {
-               cq->ugts = (u64)pci_resource_start(rdev->lldi.pdev, 2) +
-                                       (cq->cqid << rdev->cqshift);
-               cq->ugts &= PAGE_MASK;
+               u32 off = (cq->cqid << rdev->cqshift) & PAGE_MASK;
+
+               cq->ugts = (u64)rdev->bar2_pa + off;
+       } else if (is_t4(rdev->lldi.adapter_type)) {
+               cq->gts = rdev->lldi.gts_reg;
+               cq->qid_mask = -1U;
+       } else {
+               u32 off = ((cq->cqid << rdev->cqshift) & PAGE_MASK) + 12;
+
+               cq->gts = rdev->bar2_kva + off;
+               cq->qid_mask = rdev->qpmask;
        }
        return 0;
 err4:
@@ -970,8 +977,7 @@ struct ib_cq *c4iw_create_cq(struct ib_device *ibdev, int entries,
        }
        PDBG("%s cqid 0x%0x chp %p size %u memsize %zu, dma_addr 0x%0llx\n",
             __func__, chp->cq.cqid, chp, chp->cq.size,
-            chp->cq.memsize,
-            (unsigned long long) chp->cq.dma_addr);
+            chp->cq.memsize, (unsigned long long) chp->cq.dma_addr);
        return &chp->ibcq;
 err5:
        kfree(mm2);
index 8fb295e4a9ab7199a385dc7778ee6ae1e409a5c1..7e895d714b19e35a49ddd69f5a3432af5bcf1f71 100644 (file)
@@ -93,6 +93,7 @@ static struct ibnl_client_cbs c4iw_nl_cb_table[] = {
        [RDMA_NL_IWPM_ADD_MAPPING] = {.dump = iwpm_add_mapping_cb},
        [RDMA_NL_IWPM_QUERY_MAPPING] = {.dump = iwpm_add_and_query_mapping_cb},
        [RDMA_NL_IWPM_HANDLE_ERR] = {.dump = iwpm_mapping_error_cb},
+       [RDMA_NL_IWPM_REMOTE_INFO] = {.dump = iwpm_remote_info_cb},
        [RDMA_NL_IWPM_MAPINFO] = {.dump = iwpm_mapping_info_cb},
        [RDMA_NL_IWPM_MAPINFO_NUM] = {.dump = iwpm_ack_mapping_info_cb}
 };
@@ -151,7 +152,7 @@ static int wr_log_show(struct seq_file *seq, void *v)
        int prev_ts_set = 0;
        int idx, end;
 
-#define ts2ns(ts) div64_ul((ts) * dev->rdev.lldi.cclk_ps, 1000)
+#define ts2ns(ts) div64_u64((ts) * dev->rdev.lldi.cclk_ps, 1000)
 
        idx = atomic_read(&dev->rdev.wr_log_idx) &
                (dev->rdev.wr_log_size - 1);
@@ -489,6 +490,7 @@ static int stats_show(struct seq_file *seq, void *v)
                   dev->rdev.stats.act_ofld_conn_fails);
        seq_printf(seq, "PAS_OFLD_CONN_FAILS: %10llu\n",
                   dev->rdev.stats.pas_ofld_conn_fails);
+       seq_printf(seq, "NEG_ADV_RCVD: %10llu\n", dev->rdev.stats.neg_adv);
        seq_printf(seq, "AVAILABLE IRD: %10u\n", dev->avail_ird);
        return 0;
 }
@@ -560,10 +562,13 @@ static int dump_ep(int id, void *p, void *data)
                cc = snprintf(epd->buf + epd->pos, space,
                              "ep %p cm_id %p qp %p state %d flags 0x%lx "
                              "history 0x%lx hwtid %d atid %d "
+                             "conn_na %u abort_na %u "
                              "%pI4:%d/%d <-> %pI4:%d/%d\n",
                              ep, ep->com.cm_id, ep->com.qp,
                              (int)ep->com.state, ep->com.flags,
                              ep->com.history, ep->hwtid, ep->atid,
+                             ep->stats.connect_neg_adv,
+                             ep->stats.abort_neg_adv,
                              &lsin->sin_addr, ntohs(lsin->sin_port),
                              ntohs(mapped_lsin->sin_port),
                              &rsin->sin_addr, ntohs(rsin->sin_port),
@@ -581,10 +586,13 @@ static int dump_ep(int id, void *p, void *data)
                cc = snprintf(epd->buf + epd->pos, space,
                              "ep %p cm_id %p qp %p state %d flags 0x%lx "
                              "history 0x%lx hwtid %d atid %d "
+                             "conn_na %u abort_na %u "
                              "%pI6:%d/%d <-> %pI6:%d/%d\n",
                              ep, ep->com.cm_id, ep->com.qp,
                              (int)ep->com.state, ep->com.flags,
                              ep->com.history, ep->hwtid, ep->atid,
+                             ep->stats.connect_neg_adv,
+                             ep->stats.abort_neg_adv,
                              &lsin6->sin6_addr, ntohs(lsin6->sin6_port),
                              ntohs(mapped_lsin6->sin6_port),
                              &rsin6->sin6_addr, ntohs(rsin6->sin6_port),
@@ -764,6 +772,29 @@ static int c4iw_rdev_open(struct c4iw_rdev *rdev)
 
        c4iw_init_dev_ucontext(rdev, &rdev->uctx);
 
+       /*
+        * This implementation assumes udb_density == ucq_density!  Eventually
+        * we might need to support this but for now fail the open. Also the
+        * cqid and qpid range must match for now.
+        */
+       if (rdev->lldi.udb_density != rdev->lldi.ucq_density) {
+               pr_err(MOD "%s: unsupported udb/ucq densities %u/%u\n",
+                      pci_name(rdev->lldi.pdev), rdev->lldi.udb_density,
+                      rdev->lldi.ucq_density);
+               err = -EINVAL;
+               goto err1;
+       }
+       if (rdev->lldi.vr->qp.start != rdev->lldi.vr->cq.start ||
+           rdev->lldi.vr->qp.size != rdev->lldi.vr->cq.size) {
+               pr_err(MOD "%s: unsupported qp and cq id ranges "
+                      "qp start %u size %u cq start %u size %u\n",
+                      pci_name(rdev->lldi.pdev), rdev->lldi.vr->qp.start,
+                      rdev->lldi.vr->qp.size, rdev->lldi.vr->cq.size,
+                      rdev->lldi.vr->cq.size);
+               err = -EINVAL;
+               goto err1;
+       }
+
        /*
         * qpshift is the number of bits to shift the qpid left in order
         * to get the correct address of the doorbell for that qp.
@@ -784,10 +815,10 @@ static int c4iw_rdev_open(struct c4iw_rdev *rdev)
             rdev->lldi.vr->qp.size,
             rdev->lldi.vr->cq.start,
             rdev->lldi.vr->cq.size);
-       PDBG("udb len 0x%x udb base %llx db_reg %p gts_reg %p qpshift %lu "
+       PDBG("udb len 0x%x udb base %p db_reg %p gts_reg %p qpshift %lu "
             "qpmask 0x%x cqshift %lu cqmask 0x%x\n",
             (unsigned)pci_resource_len(rdev->lldi.pdev, 2),
-            (u64)pci_resource_start(rdev->lldi.pdev, 2),
+            (void *)pci_resource_start(rdev->lldi.pdev, 2),
             rdev->lldi.db_reg,
             rdev->lldi.gts_reg,
             rdev->qpshift, rdev->qpmask,
@@ -1355,7 +1386,7 @@ static void recover_lost_dbs(struct uld_ctx *ctx, struct qp_list *qp_list)
                                          t4_sq_host_wq_pidx(&qp->wq),
                                          t4_sq_wq_size(&qp->wq));
                if (ret) {
-                       pr_err(KERN_ERR MOD "%s: Fatal error - "
+                       pr_err(MOD "%s: Fatal error - "
                               "DB overflow recovery failed - "
                               "error syncing SQ qid %u\n",
                               pci_name(ctx->lldi.pdev), qp->wq.sq.qid);
@@ -1371,7 +1402,7 @@ static void recover_lost_dbs(struct uld_ctx *ctx, struct qp_list *qp_list)
                                          t4_rq_wq_size(&qp->wq));
 
                if (ret) {
-                       pr_err(KERN_ERR MOD "%s: Fatal error - "
+                       pr_err(MOD "%s: Fatal error - "
                               "DB overflow recovery failed - "
                               "error syncing RQ qid %u\n",
                               pci_name(ctx->lldi.pdev), qp->wq.rq.qid);
index d87e1650f6437835f3660c21d3a59ec920fa8f7c..97bb5550a6cf64bd77eb3d429b43b6c9d3e10b7e 100644 (file)
@@ -137,6 +137,7 @@ struct c4iw_stats {
        u64  tcam_full;
        u64  act_ofld_conn_fails;
        u64  pas_ofld_conn_fails;
+       u64  neg_adv;
 };
 
 struct c4iw_hw_queue {
@@ -814,6 +815,11 @@ struct c4iw_listen_ep {
        int backlog;
 };
 
+struct c4iw_ep_stats {
+       unsigned connect_neg_adv;
+       unsigned abort_neg_adv;
+};
+
 struct c4iw_ep {
        struct c4iw_ep_common com;
        struct c4iw_ep *parent_ep;
@@ -846,6 +852,7 @@ struct c4iw_ep {
        unsigned int retry_count;
        int snd_win;
        int rcv_win;
+       struct c4iw_ep_stats stats;
 };
 
 static inline void print_addr(struct c4iw_ep_common *epc, const char *func,
index 3ef0cf9f5c4403863310ffc5a7d92cd6bfc970d9..cff815b9170716a01bca790c586b7a9b14c586e7 100644 (file)
@@ -144,7 +144,7 @@ static int _c4iw_write_mem_inline(struct c4iw_rdev *rdev, u32 addr, u32 len,
                if (i == (num_wqe-1)) {
                        req->wr.wr_hi = cpu_to_be32(FW_WR_OP_V(FW_ULPTX_WR) |
                                                    FW_WR_COMPL_F);
-                       req->wr.wr_lo = (__force __be64)(unsigned long) &wr_wait;
+                       req->wr.wr_lo = (__force __be64)&wr_wait;
                } else
                        req->wr.wr_hi = cpu_to_be32(FW_WR_OP_V(FW_ULPTX_WR));
                req->wr.wr_mid = cpu_to_be32(
@@ -676,12 +676,12 @@ struct ib_mr *c4iw_get_dma_mr(struct ib_pd *pd, int acc)
        mhp->attr.zbva = 0;
        mhp->attr.va_fbo = 0;
        mhp->attr.page_size = 0;
-       mhp->attr.len = ~0UL;
+       mhp->attr.len = ~0ULL;
        mhp->attr.pbl_size = 0;
 
        ret = write_tpt_entry(&rhp->rdev, 0, &stag, 1, php->pdid,
                              FW_RI_STAG_NSMR, mhp->attr.perms,
-                             mhp->attr.mw_bind_enable, 0, 0, ~0UL, 0, 0, 0);
+                             mhp->attr.mw_bind_enable, 0, 0, ~0ULL, 0, 0, 0);
        if (ret)
                goto err1;
 
index 15cae5a3101851ed1a0cb049ff43987651a8955c..389ced335bc5cc528f7ef4ba1e4121c5ec79295c 100644 (file)
@@ -275,7 +275,7 @@ static int create_qp(struct c4iw_rdev *rdev, struct t4_wq *wq,
                        FW_RI_RES_WR_NRES_V(2) |
                        FW_WR_COMPL_F);
        res_wr->len16_pkd = cpu_to_be32(DIV_ROUND_UP(wr_len, 16));
-       res_wr->cookie = (unsigned long) &wr_wait;
+       res_wr->cookie = (uintptr_t)&wr_wait;
        res = res_wr->res;
        res->u.sqrq.restype = FW_RI_RES_TYPE_SQ;
        res->u.sqrq.op = FW_RI_RES_OP_WRITE;
@@ -1209,7 +1209,7 @@ static int rdma_fini(struct c4iw_dev *rhp, struct c4iw_qp *qhp,
        wqe->flowid_len16 = cpu_to_be32(
                FW_WR_FLOWID_V(ep->hwtid) |
                FW_WR_LEN16_V(DIV_ROUND_UP(sizeof(*wqe), 16)));
-       wqe->cookie = (unsigned long) &ep->com.wr_wait;
+       wqe->cookie = (uintptr_t)&ep->com.wr_wait;
 
        wqe->u.fini.type = FW_RI_TYPE_FINI;
        ret = c4iw_ofld_send(&rhp->rdev, skb);
@@ -1279,7 +1279,7 @@ static int rdma_init(struct c4iw_dev *rhp, struct c4iw_qp *qhp)
                FW_WR_FLOWID_V(qhp->ep->hwtid) |
                FW_WR_LEN16_V(DIV_ROUND_UP(sizeof(*wqe), 16)));
 
-       wqe->cookie = (unsigned long) &qhp->ep->com.wr_wait;
+       wqe->cookie = (uintptr_t)&qhp->ep->com.wr_wait;
 
        wqe->u.init.type = FW_RI_TYPE_INIT;
        wqe->u.init.mpareqbit_p2ptype =
@@ -1766,11 +1766,11 @@ struct ib_qp *c4iw_create_qp(struct ib_pd *pd, struct ib_qp_init_attr *attrs,
                mm2->len = PAGE_ALIGN(qhp->wq.rq.memsize);
                insert_mmap(ucontext, mm2);
                mm3->key = uresp.sq_db_gts_key;
-               mm3->addr = (__force unsigned long) qhp->wq.sq.udb;
+               mm3->addr = (__force unsigned long)qhp->wq.sq.udb;
                mm3->len = PAGE_SIZE;
                insert_mmap(ucontext, mm3);
                mm4->key = uresp.rq_db_gts_key;
-               mm4->addr = (__force unsigned long) qhp->wq.rq.udb;
+               mm4->addr = (__force unsigned long)qhp->wq.rq.udb;
                mm4->len = PAGE_SIZE;
                insert_mmap(ucontext, mm4);
                if (mm5) {
index 871cdcac7be26a3479f78eb34c3f799f5a8b840f..7f2a6c244d25d67ea922ab35ba568e8b73196ffe 100644 (file)
@@ -539,6 +539,7 @@ struct t4_cq {
        size_t memsize;
        __be64 bits_type_ts;
        u32 cqid;
+       u32 qid_mask;
        int vector;
        u16 size; /* including status page */
        u16 cidx;
@@ -563,12 +564,12 @@ static inline int t4_arm_cq(struct t4_cq *cq, int se)
        set_bit(CQ_ARMED, &cq->flags);
        while (cq->cidx_inc > CIDXINC_M) {
                val = SEINTARM_V(0) | CIDXINC_V(CIDXINC_M) | TIMERREG_V(7) |
-                     INGRESSQID_V(cq->cqid);
+                     INGRESSQID_V(cq->cqid & cq->qid_mask);
                writel(val, cq->gts);
                cq->cidx_inc -= CIDXINC_M;
        }
        val = SEINTARM_V(se) | CIDXINC_V(cq->cidx_inc) | TIMERREG_V(6) |
-             INGRESSQID_V(cq->cqid);
+             INGRESSQID_V(cq->cqid & cq->qid_mask);
        writel(val, cq->gts);
        cq->cidx_inc = 0;
        return 0;
@@ -601,7 +602,7 @@ static inline void t4_hwcq_consume(struct t4_cq *cq)
                u32 val;
 
                val = SEINTARM_V(0) | CIDXINC_V(cq->cidx_inc) | TIMERREG_V(7) |
-                     INGRESSQID_V(cq->cqid);
+                     INGRESSQID_V(cq->cqid & cq->qid_mask);
                writel(val, cq->gts);
                cq->cidx_inc = 0;
        }
index 5e53327fc6476b678227609bee4aee90bbb0c7c0..343e8daf2270dbc07680d2ef2e2b2027181f292c 100644 (file)
@@ -848,6 +848,8 @@ enum {                     /* TCP congestion control algorithms */
 #define CONG_CNTRL_V(x) ((x) << CONG_CNTRL_S)
 #define CONG_CNTRL_G(x) (((x) >> CONG_CNTRL_S) & CONG_CNTRL_M)
 
-#define CONG_CNTRL_VALID   (1 << 18)
+#define T5_ISS_S    18
+#define T5_ISS_V(x) ((x) << T5_ISS_S)
+#define T5_ISS_F    T5_ISS_V(1U)
 
 #endif /* _T4FW_RI_API_H_ */
index 120aedf9f989a7a34839046a360dd9ad53816d64..cec1815329245cfa6573f39ce3f44f628175fea7 100644 (file)
@@ -77,7 +77,7 @@ int ehca_attach_mcast(struct ib_qp *ibqp, union ib_gid *gid, u16 lid)
                return -EINVAL;
        }
 
-       memcpy(&my_gid.raw, gid->raw, sizeof(union ib_gid));
+       memcpy(&my_gid, gid->raw, sizeof(union ib_gid));
 
        subnet_prefix = be64_to_cpu(my_gid.global.subnet_prefix);
        interface_id = be64_to_cpu(my_gid.global.interface_id);
@@ -114,7 +114,7 @@ int ehca_detach_mcast(struct ib_qp *ibqp, union ib_gid *gid, u16 lid)
                return -EINVAL;
        }
 
-       memcpy(&my_gid.raw, gid->raw, sizeof(union ib_gid));
+       memcpy(&my_gid, gid->raw, sizeof(union ib_gid));
 
        subnet_prefix = be64_to_cpu(my_gid.global.subnet_prefix);
        interface_id = be64_to_cpu(my_gid.global.interface_id);
index 57070c529dfb5ca038e2118212684dc54bb3d21b..cc64400d41ace3005c8a878b4c6811b0506726f9 100644 (file)
@@ -1569,8 +1569,7 @@ static void reset_gids_task(struct work_struct *work)
                               MLX4_CMD_TIME_CLASS_B,
                               MLX4_CMD_WRAPPED);
                if (err)
-                       pr_warn(KERN_WARNING
-                               "set port %d command failed\n", gw->port);
+                       pr_warn("set port %d command failed\n", gw->port);
        }
 
        mlx4_free_cmd_mailbox(dev, mailbox);
index 4d7024b899cb091a12aacfa9450af1e7750d4f45..d35f62d4f4c58ecce848cfb2d0544500c62dbfd3 100644 (file)
@@ -1392,7 +1392,7 @@ static int mlx5_set_path(struct mlx5_ib_dev *dev, const struct ib_ah_attr *ah,
 
        if (ah->ah_flags & IB_AH_GRH) {
                if (ah->grh.sgid_index >= gen->port[port - 1].gid_table_len) {
-                       pr_err(KERN_ERR "sgid_index (%u) too large. max is %d\n",
+                       pr_err("sgid_index (%u) too large. max is %d\n",
                               ah->grh.sgid_index, gen->port[port - 1].gid_table_len);
                        return -EINVAL;
                }
index 3b2a6dc8ea99d734645a24cef66a78867f66a2cd..9f9d5c563a614c0c273368966d380c82d9b2a1a4 100644 (file)
@@ -116,6 +116,7 @@ static struct ibnl_client_cbs nes_nl_cb_table[] = {
        [RDMA_NL_IWPM_REG_PID] = {.dump = iwpm_register_pid_cb},
        [RDMA_NL_IWPM_ADD_MAPPING] = {.dump = iwpm_add_mapping_cb},
        [RDMA_NL_IWPM_QUERY_MAPPING] = {.dump = iwpm_add_and_query_mapping_cb},
+       [RDMA_NL_IWPM_REMOTE_INFO] = {.dump = iwpm_remote_info_cb},
        [RDMA_NL_IWPM_HANDLE_ERR] = {.dump = iwpm_mapping_error_cb},
        [RDMA_NL_IWPM_MAPINFO] = {.dump = iwpm_mapping_info_cb},
        [RDMA_NL_IWPM_MAPINFO_NUM] = {.dump = iwpm_ack_mapping_info_cb}
index 6f09a72e78d7d8ec9690413924e079af764aeaf3..72b43417cbe382aed9164b5554e80b449270c3ad 100644 (file)
@@ -596,27 +596,52 @@ static void nes_form_reg_msg(struct nes_vnic *nesvnic,
        memcpy(pm_msg->if_name, nesvnic->netdev->name, IWPM_IFNAME_SIZE);
 }
 
+static void record_sockaddr_info(struct sockaddr_storage *addr_info,
+                                       nes_addr_t *ip_addr, u16 *port_num)
+{
+       struct sockaddr_in *in_addr = (struct sockaddr_in *)addr_info;
+
+       if (in_addr->sin_family == AF_INET) {
+               *ip_addr = ntohl(in_addr->sin_addr.s_addr);
+               *port_num = ntohs(in_addr->sin_port);
+       }
+}
+
 /*
  * nes_record_pm_msg - Save the received mapping info
  */
 static void nes_record_pm_msg(struct nes_cm_info *cm_info,
                        struct iwpm_sa_data *pm_msg)
 {
-       struct sockaddr_in *mapped_loc_addr =
-                       (struct sockaddr_in *)&pm_msg->mapped_loc_addr;
-       struct sockaddr_in *mapped_rem_addr =
-                       (struct sockaddr_in *)&pm_msg->mapped_rem_addr;
-
-       if (mapped_loc_addr->sin_family == AF_INET) {
-               cm_info->mapped_loc_addr =
-                       ntohl(mapped_loc_addr->sin_addr.s_addr);
-               cm_info->mapped_loc_port = ntohs(mapped_loc_addr->sin_port);
-       }
-       if (mapped_rem_addr->sin_family == AF_INET) {
-               cm_info->mapped_rem_addr =
-                       ntohl(mapped_rem_addr->sin_addr.s_addr);
-               cm_info->mapped_rem_port = ntohs(mapped_rem_addr->sin_port);
-       }
+       record_sockaddr_info(&pm_msg->mapped_loc_addr,
+               &cm_info->mapped_loc_addr, &cm_info->mapped_loc_port);
+
+       record_sockaddr_info(&pm_msg->mapped_rem_addr,
+               &cm_info->mapped_rem_addr, &cm_info->mapped_rem_port);
+}
+
+/*
+ * nes_get_reminfo - Get the address info of the remote connecting peer
+ */
+static int nes_get_remote_addr(struct nes_cm_node *cm_node)
+{
+       struct sockaddr_storage mapped_loc_addr, mapped_rem_addr;
+       struct sockaddr_storage remote_addr;
+       int ret;
+
+       nes_create_sockaddr(htonl(cm_node->mapped_loc_addr),
+                       htons(cm_node->mapped_loc_port), &mapped_loc_addr);
+       nes_create_sockaddr(htonl(cm_node->mapped_rem_addr),
+                       htons(cm_node->mapped_rem_port), &mapped_rem_addr);
+
+       ret = iwpm_get_remote_info(&mapped_loc_addr, &mapped_rem_addr,
+                               &remote_addr, RDMA_NL_NES);
+       if (ret)
+               nes_debug(NES_DBG_CM, "Unable to find remote peer address info\n");
+       else
+               record_sockaddr_info(&remote_addr, &cm_node->rem_addr,
+                               &cm_node->rem_port);
+       return ret;
 }
 
 /**
@@ -1566,9 +1591,14 @@ static struct nes_cm_node *make_cm_node(struct nes_cm_core *cm_core,
                return NULL;
 
        /* set our node specific transport info */
-       cm_node->loc_addr = cm_info->loc_addr;
+       if (listener) {
+               cm_node->loc_addr = listener->loc_addr;
+               cm_node->loc_port = listener->loc_port;
+       } else {
+               cm_node->loc_addr = cm_info->loc_addr;
+               cm_node->loc_port = cm_info->loc_port;
+       }
        cm_node->rem_addr = cm_info->rem_addr;
-       cm_node->loc_port = cm_info->loc_port;
        cm_node->rem_port = cm_info->rem_port;
 
        cm_node->mapped_loc_addr = cm_info->mapped_loc_addr;
@@ -2151,6 +2181,7 @@ static int handle_ack_pkt(struct nes_cm_node *cm_node, struct sk_buff *skb,
                cm_node->state = NES_CM_STATE_ESTABLISHED;
                if (datasize) {
                        cm_node->tcp_cntxt.rcv_nxt = inc_sequence + datasize;
+                       nes_get_remote_addr(cm_node);
                        handle_rcv_mpa(cm_node, skb);
                } else { /* rcvd ACK only */
                        dev_kfree_skb_any(skb);
index c9780d919769a6ef9a0020b7e710afa7e7ce2497..b396344fae16af33153f0625104d95c17f488a8d 100644 (file)
@@ -40,7 +40,7 @@
 #include <be_roce.h>
 #include "ocrdma_sli.h"
 
-#define OCRDMA_ROCE_DRV_VERSION "10.4.205.0u"
+#define OCRDMA_ROCE_DRV_VERSION "10.6.0.0"
 
 #define OCRDMA_ROCE_DRV_DESC "Emulex OneConnect RoCE Driver"
 #define OCRDMA_NODE_DESC "Emulex OneConnect RoCE HCA"
@@ -515,6 +515,8 @@ static inline int ocrdma_resolve_dmac(struct ocrdma_dev *dev,
        memcpy(&in6, ah_attr->grh.dgid.raw, sizeof(in6));
        if (rdma_is_multicast_addr(&in6))
                rdma_get_mcast_mac(&in6, mac_addr);
+       else if (rdma_link_local_addr(&in6))
+               rdma_get_ll_mac(&in6, mac_addr);
        else
                memcpy(mac_addr, ah_attr->dmac, ETH_ALEN);
        return 0;
index d812904f398473d1502bb979d6d822c04b55f2b8..f5a5ea836dbdc9fe4f12e6f26e1acca5dac3c6d1 100644 (file)
@@ -56,7 +56,13 @@ static inline int set_av_attr(struct ocrdma_dev *dev, struct ocrdma_ah *ah,
        vlan_tag = attr->vlan_id;
        if (!vlan_tag || (vlan_tag > 0xFFF))
                vlan_tag = dev->pvid;
-       if (vlan_tag && (vlan_tag < 0x1000)) {
+       if (vlan_tag || dev->pfc_state) {
+               if (!vlan_tag) {
+                       pr_err("ocrdma%d:Using VLAN with PFC is recommended\n",
+                               dev->id);
+                       pr_err("ocrdma%d:Using VLAN 0 for this connection\n",
+                               dev->id);
+               }
                eth.eth_type = cpu_to_be16(0x8100);
                eth.roce_eth_type = cpu_to_be16(OCRDMA_ROCE_ETH_TYPE);
                vlan_tag |= (dev->sl & 0x07) << OCRDMA_VID_PCP_SHIFT;
@@ -121,7 +127,9 @@ struct ib_ah *ocrdma_create_ah(struct ib_pd *ibpd, struct ib_ah_attr *attr)
                goto av_conf_err;
        }
 
-       if (pd->uctx) {
+       if ((pd->uctx) &&
+           (!rdma_is_multicast_addr((struct in6_addr *)attr->grh.dgid.raw)) &&
+           (!rdma_link_local_addr((struct in6_addr *)attr->grh.dgid.raw))) {
                status = rdma_addr_find_dmac_by_grh(&sgid, &attr->grh.dgid,
                                         attr->dmac, &attr->vlan_id);
                if (status) {
index 0c9e95909a64651e931f4768e88f97e266c8379e..47615ff33bc6a1fb8c0c703b9f975acc6afe79c2 100644 (file)
@@ -933,12 +933,18 @@ static irqreturn_t ocrdma_irq_handler(int irq, void *handle)
        struct ocrdma_eqe eqe;
        struct ocrdma_eqe *ptr;
        u16 cq_id;
+       u8 mcode;
        int budget = eq->cq_cnt;
 
        do {
                ptr = ocrdma_get_eqe(eq);
                eqe = *ptr;
                ocrdma_le32_to_cpu(&eqe, sizeof(eqe));
+               mcode = (eqe.id_valid & OCRDMA_EQE_MAJOR_CODE_MASK)
+                               >> OCRDMA_EQE_MAJOR_CODE_SHIFT;
+               if (mcode == OCRDMA_MAJOR_CODE_SENTINAL)
+                       pr_err("EQ full on eqid = 0x%x, eqe = 0x%x\n",
+                              eq->q.id, eqe.id_valid);
                if ((eqe.id_valid & OCRDMA_EQE_VALID_MASK) == 0)
                        break;
 
@@ -1434,27 +1440,30 @@ static int ocrdma_mbx_alloc_pd_range(struct ocrdma_dev *dev)
        struct ocrdma_alloc_pd_range_rsp *rsp;
 
        /* Pre allocate the DPP PDs */
-       cmd = ocrdma_init_emb_mqe(OCRDMA_CMD_ALLOC_PD_RANGE, sizeof(*cmd));
-       if (!cmd)
-               return -ENOMEM;
-       cmd->pd_count = dev->attr.max_dpp_pds;
-       cmd->enable_dpp_rsvd |= OCRDMA_ALLOC_PD_ENABLE_DPP;
-       status = ocrdma_mbx_cmd(dev, (struct ocrdma_mqe *)cmd);
-       if (status)
-               goto mbx_err;
-       rsp = (struct ocrdma_alloc_pd_range_rsp *)cmd;
-
-       if ((rsp->dpp_page_pdid & OCRDMA_ALLOC_PD_RSP_DPP) && rsp->pd_count) {
-               dev->pd_mgr->dpp_page_index = rsp->dpp_page_pdid >>
-                               OCRDMA_ALLOC_PD_RSP_DPP_PAGE_SHIFT;
-               dev->pd_mgr->pd_dpp_start = rsp->dpp_page_pdid &
-                               OCRDMA_ALLOC_PD_RNG_RSP_START_PDID_MASK;
-               dev->pd_mgr->max_dpp_pd = rsp->pd_count;
-               pd_bitmap_size = BITS_TO_LONGS(rsp->pd_count) * sizeof(long);
-               dev->pd_mgr->pd_dpp_bitmap = kzalloc(pd_bitmap_size,
-                                                    GFP_KERNEL);
+       if (dev->attr.max_dpp_pds) {
+               cmd = ocrdma_init_emb_mqe(OCRDMA_CMD_ALLOC_PD_RANGE,
+                                         sizeof(*cmd));
+               if (!cmd)
+                       return -ENOMEM;
+               cmd->pd_count = dev->attr.max_dpp_pds;
+               cmd->enable_dpp_rsvd |= OCRDMA_ALLOC_PD_ENABLE_DPP;
+               status = ocrdma_mbx_cmd(dev, (struct ocrdma_mqe *)cmd);
+               rsp = (struct ocrdma_alloc_pd_range_rsp *)cmd;
+
+               if (!status && (rsp->dpp_page_pdid & OCRDMA_ALLOC_PD_RSP_DPP) &&
+                   rsp->pd_count) {
+                       dev->pd_mgr->dpp_page_index = rsp->dpp_page_pdid >>
+                                       OCRDMA_ALLOC_PD_RSP_DPP_PAGE_SHIFT;
+                       dev->pd_mgr->pd_dpp_start = rsp->dpp_page_pdid &
+                                       OCRDMA_ALLOC_PD_RNG_RSP_START_PDID_MASK;
+                       dev->pd_mgr->max_dpp_pd = rsp->pd_count;
+                       pd_bitmap_size =
+                               BITS_TO_LONGS(rsp->pd_count) * sizeof(long);
+                       dev->pd_mgr->pd_dpp_bitmap = kzalloc(pd_bitmap_size,
+                                                            GFP_KERNEL);
+               }
+               kfree(cmd);
        }
-       kfree(cmd);
 
        cmd = ocrdma_init_emb_mqe(OCRDMA_CMD_ALLOC_PD_RANGE, sizeof(*cmd));
        if (!cmd)
@@ -1462,10 +1471,8 @@ static int ocrdma_mbx_alloc_pd_range(struct ocrdma_dev *dev)
 
        cmd->pd_count = dev->attr.max_pd - dev->attr.max_dpp_pds;
        status = ocrdma_mbx_cmd(dev, (struct ocrdma_mqe *)cmd);
-       if (status)
-               goto mbx_err;
        rsp = (struct ocrdma_alloc_pd_range_rsp *)cmd;
-       if (rsp->pd_count) {
+       if (!status && rsp->pd_count) {
                dev->pd_mgr->pd_norm_start = rsp->dpp_page_pdid &
                                        OCRDMA_ALLOC_PD_RNG_RSP_START_PDID_MASK;
                dev->pd_mgr->max_normal_pd = rsp->pd_count;
@@ -1473,15 +1480,13 @@ static int ocrdma_mbx_alloc_pd_range(struct ocrdma_dev *dev)
                dev->pd_mgr->pd_norm_bitmap = kzalloc(pd_bitmap_size,
                                                      GFP_KERNEL);
        }
+       kfree(cmd);
 
        if (dev->pd_mgr->pd_norm_bitmap || dev->pd_mgr->pd_dpp_bitmap) {
                /* Enable PD resource manager */
                dev->pd_mgr->pd_prealloc_valid = true;
-       } else {
-               return -ENOMEM;
+               return 0;
        }
-mbx_err:
-       kfree(cmd);
        return status;
 }
 
@@ -2406,7 +2411,7 @@ int ocrdma_mbx_query_qp(struct ocrdma_dev *dev, struct ocrdma_qp *qp,
        struct ocrdma_query_qp *cmd;
        struct ocrdma_query_qp_rsp *rsp;
 
-       cmd = ocrdma_init_emb_mqe(OCRDMA_CMD_QUERY_QP, sizeof(*cmd));
+       cmd = ocrdma_init_emb_mqe(OCRDMA_CMD_QUERY_QP, sizeof(*rsp));
        if (!cmd)
                return status;
        cmd->qp_id = qp->id;
@@ -2428,7 +2433,7 @@ static int ocrdma_set_av_params(struct ocrdma_qp *qp,
        int status;
        struct ib_ah_attr *ah_attr = &attrs->ah_attr;
        union ib_gid sgid, zgid;
-       u32 vlan_id;
+       u32 vlan_id = 0xFFFF;
        u8 mac_addr[6];
        struct ocrdma_dev *dev = get_ocrdma_dev(qp->ibqp.device);
 
@@ -2468,12 +2473,22 @@ static int ocrdma_set_av_params(struct ocrdma_qp *qp,
        cmd->params.vlan_dmac_b4_to_b5 = mac_addr[4] | (mac_addr[5] << 8);
        if (attr_mask & IB_QP_VID) {
                vlan_id = attrs->vlan_id;
+       } else if (dev->pfc_state) {
+               vlan_id = 0;
+               pr_err("ocrdma%d:Using VLAN with PFC is recommended\n",
+                       dev->id);
+               pr_err("ocrdma%d:Using VLAN 0 for this connection\n",
+                       dev->id);
+       }
+
+       if (vlan_id < 0x1000) {
                cmd->params.vlan_dmac_b4_to_b5 |=
                    vlan_id << OCRDMA_QP_PARAMS_VLAN_SHIFT;
                cmd->flags |= OCRDMA_QP_PARA_VLAN_EN_VALID;
                cmd->params.rnt_rc_sl_fl |=
                        (dev->sl & 0x07) << OCRDMA_QP_PARAMS_SL_SHIFT;
        }
+
        return 0;
 }
 
@@ -2519,8 +2534,10 @@ static int ocrdma_set_qp_params(struct ocrdma_qp *qp,
                cmd->flags |= OCRDMA_QP_PARA_DST_QPN_VALID;
        }
        if (attr_mask & IB_QP_PATH_MTU) {
-               if (attrs->path_mtu < IB_MTU_256 ||
+               if (attrs->path_mtu < IB_MTU_512 ||
                    attrs->path_mtu > IB_MTU_4096) {
+                       pr_err("ocrdma%d: IB MTU %d is not supported\n",
+                              dev->id, ib_mtu_enum_to_int(attrs->path_mtu));
                        status = -EINVAL;
                        goto pmtu_err;
                }
@@ -3147,9 +3164,9 @@ void ocrdma_cleanup_hw(struct ocrdma_dev *dev)
        ocrdma_free_pd_pool(dev);
        ocrdma_mbx_delete_ah_tbl(dev);
 
-       /* cleanup the eqs */
-       ocrdma_destroy_eqs(dev);
-
        /* cleanup the control path */
        ocrdma_destroy_mq(dev);
+
+       /* cleanup the eqs */
+       ocrdma_destroy_eqs(dev);
 }
index 243c87c8bd65d09026f46ee12e3ee3b9109ce155..02ad0aee99afc0c5e9449c4f58353e57d38903f1 100644 (file)
@@ -1176,6 +1176,8 @@ struct ocrdma_query_qp_rsp {
        struct ocrdma_mqe_hdr hdr;
        struct ocrdma_mbx_rsp rsp;
        struct ocrdma_qp_params params;
+       u32 dpp_credits_cqid;
+       u32 rbq_id;
 };
 
 enum {
@@ -1624,12 +1626,19 @@ struct ocrdma_delete_ah_tbl_rsp {
 enum {
        OCRDMA_EQE_VALID_SHIFT          = 0,
        OCRDMA_EQE_VALID_MASK           = BIT(0),
+       OCRDMA_EQE_MAJOR_CODE_MASK      = 0x0E,
+       OCRDMA_EQE_MAJOR_CODE_SHIFT     = 0x01,
        OCRDMA_EQE_FOR_CQE_MASK         = 0xFFFE,
        OCRDMA_EQE_RESOURCE_ID_SHIFT    = 16,
        OCRDMA_EQE_RESOURCE_ID_MASK     = 0xFFFF <<
                                OCRDMA_EQE_RESOURCE_ID_SHIFT,
 };
 
+enum major_code {
+       OCRDMA_MAJOR_CODE_COMPLETION    = 0x00,
+       OCRDMA_MAJOR_CODE_SENTINAL      = 0x01
+};
+
 struct ocrdma_eqe {
        u32 id_valid;
 };
index 877175563634df79a889ed8a428405258b9df1e4..9dcb66077d6cbf9cd37bdaaa594414aadee4c96f 100644 (file)
@@ -365,7 +365,7 @@ static struct ocrdma_pd *_ocrdma_alloc_pd(struct ocrdma_dev *dev,
        if (!pd)
                return ERR_PTR(-ENOMEM);
 
-       if (udata && uctx) {
+       if (udata && uctx && dev->attr.max_dpp_pds) {
                pd->dpp_enabled =
                        ocrdma_get_asic_type(dev) == OCRDMA_ASIC_GEN_SKH_R;
                pd->num_dpp_qp =
@@ -1721,18 +1721,20 @@ int ocrdma_destroy_qp(struct ib_qp *ibqp)
        struct ocrdma_qp *qp;
        struct ocrdma_dev *dev;
        struct ib_qp_attr attrs;
-       int attr_mask = IB_QP_STATE;
+       int attr_mask;
        unsigned long flags;
 
        qp = get_ocrdma_qp(ibqp);
        dev = get_ocrdma_dev(ibqp->device);
 
-       attrs.qp_state = IB_QPS_ERR;
        pd = qp->pd;
 
        /* change the QP state to ERROR */
-       _ocrdma_modify_qp(ibqp, &attrs, attr_mask);
-
+       if (qp->state != OCRDMA_QPS_RST) {
+               attrs.qp_state = IB_QPS_ERR;
+               attr_mask = IB_QP_STATE;
+               _ocrdma_modify_qp(ibqp, &attrs, attr_mask);
+       }
        /* ensure that CQEs for newly created QP (whose id may be same with
         * one which just getting destroyed are same), dont get
         * discarded until the old CQEs are discarded.
index ffd48bfc4923457e5383345acfa3620fa5f6a52f..7df16f74bb4585e971e1208dd348911d142f78fb 100644 (file)
@@ -903,7 +903,7 @@ struct qib_devdata {
        /* PCI Device ID (here for NodeInfo) */
        u16 deviceid;
        /* for write combining settings */
-       unsigned long wc_cookie;
+       int wc_cookie;
        unsigned long wc_base;
        unsigned long wc_len;
 
@@ -1136,7 +1136,6 @@ extern struct qib_devdata *qib_lookup(int unit);
 extern u32 qib_cpulist_count;
 extern unsigned long *qib_cpulist;
 
-extern unsigned qib_wc_pat;
 extern unsigned qib_cc_table_size;
 int qib_init(struct qib_devdata *, int);
 int init_chip_wc_pat(struct qib_devdata *dd, u32);
index 9ea6c440a00ca7012f6422f1ffd7f525b8d80548..725881890c4a217247993f9fbb933ff11bb27e27 100644 (file)
@@ -835,7 +835,8 @@ static int mmap_piobufs(struct vm_area_struct *vma,
        vma->vm_flags &= ~VM_MAYREAD;
        vma->vm_flags |= VM_DONTCOPY | VM_DONTEXPAND;
 
-       if (qib_wc_pat)
+       /* We used PAT if wc_cookie == 0 */
+       if (!dd->wc_cookie)
                vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot);
 
        ret = io_remap_pfn_range(vma, vma->vm_start, phys >> PAGE_SHIFT,
index 0d2ba59af30af66bce01ef8132c8182cc6e44a33..4b927809d1a1191004799435c7aa9163d8d6f086 100644 (file)
@@ -3315,11 +3315,9 @@ static int init_6120_variables(struct qib_devdata *dd)
        qib_6120_config_ctxts(dd);
        qib_set_ctxtcnt(dd);
 
-       if (qib_wc_pat) {
-               ret = init_chip_wc_pat(dd, 0);
-               if (ret)
-                       goto bail;
-       }
+       ret = init_chip_wc_pat(dd, 0);
+       if (ret)
+               goto bail;
        set_6120_baseaddrs(dd); /* set chip access pointers now */
 
        ret = 0;
index 22affda8af88eacbd11f21abab55ba299dfb0e0b..00b2af211157b5513092e495d62a0a014a1e1c2f 100644 (file)
@@ -4126,11 +4126,9 @@ static int qib_init_7220_variables(struct qib_devdata *dd)
        qib_7220_config_ctxts(dd);
        qib_set_ctxtcnt(dd);  /* needed for PAT setup */
 
-       if (qib_wc_pat) {
-               ret = init_chip_wc_pat(dd, 0);
-               if (ret)
-                       goto bail;
-       }
+       ret = init_chip_wc_pat(dd, 0);
+       if (ret)
+               goto bail;
        set_7220_baseaddrs(dd); /* set chip access pointers now */
 
        ret = 0;
index ef97b71c8f7dd713a77401f593c6a10320a046e6..f32b4628e9913e17dfd0606e1713945ff65930f2 100644 (file)
@@ -6429,6 +6429,7 @@ static int qib_init_7322_variables(struct qib_devdata *dd)
        unsigned features, pidx, sbufcnt;
        int ret, mtu;
        u32 sbufs, updthresh;
+       resource_size_t vl15off;
 
        /* pport structs are contiguous, allocated after devdata */
        ppd = (struct qib_pportdata *)(dd + 1);
@@ -6677,29 +6678,27 @@ static int qib_init_7322_variables(struct qib_devdata *dd)
        qib_7322_config_ctxts(dd);
        qib_set_ctxtcnt(dd);
 
-       if (qib_wc_pat) {
-               resource_size_t vl15off;
-               /*
-                * We do not set WC on the VL15 buffers to avoid
-                * a rare problem with unaligned writes from
-                * interrupt-flushed store buffers, so we need
-                * to map those separately here.  We can't solve
-                * this for the rarely used mtrr case.
-                */
-               ret = init_chip_wc_pat(dd, 0);
-               if (ret)
-                       goto bail;
+       /*
+        * We do not set WC on the VL15 buffers to avoid
+        * a rare problem with unaligned writes from
+        * interrupt-flushed store buffers, so we need
+        * to map those separately here.  We can't solve
+        * this for the rarely used mtrr case.
+        */
+       ret = init_chip_wc_pat(dd, 0);
+       if (ret)
+               goto bail;
 
-               /* vl15 buffers start just after the 4k buffers */
-               vl15off = dd->physaddr + (dd->piobufbase >> 32) +
-                       dd->piobcnt4k * dd->align4k;
-               dd->piovl15base = ioremap_nocache(vl15off,
-                                                 NUM_VL15_BUFS * dd->align4k);
-               if (!dd->piovl15base) {
-                       ret = -ENOMEM;
-                       goto bail;
-               }
+       /* vl15 buffers start just after the 4k buffers */
+       vl15off = dd->physaddr + (dd->piobufbase >> 32) +
+                 dd->piobcnt4k * dd->align4k;
+       dd->piovl15base = ioremap_nocache(vl15off,
+                                         NUM_VL15_BUFS * dd->align4k);
+       if (!dd->piovl15base) {
+               ret = -ENOMEM;
+               goto bail;
        }
+
        qib_7322_set_baseaddrs(dd); /* set chip access pointers now */
 
        ret = 0;
index 2ee36953e234c46ff704bc6e5dfbed8339c09974..7e00470adc30223c183f0e287f7a7d0d9beff944 100644 (file)
@@ -91,15 +91,6 @@ MODULE_PARM_DESC(krcvqs, "number of kernel receive queues per IB port");
 unsigned qib_cc_table_size;
 module_param_named(cc_table_size, qib_cc_table_size, uint, S_IRUGO);
 MODULE_PARM_DESC(cc_table_size, "Congestion control table entries 0 (CCA disabled - default), min = 128, max = 1984");
-/*
- * qib_wc_pat parameter:
- *      0 is WC via MTRR
- *      1 is WC via PAT
- *      If PAT initialization fails, code reverts back to MTRR
- */
-unsigned qib_wc_pat = 1; /* default (1) is to use PAT, not MTRR */
-module_param_named(wc_pat, qib_wc_pat, uint, S_IRUGO);
-MODULE_PARM_DESC(wc_pat, "enable write-combining via PAT mechanism");
 
 static void verify_interrupt(unsigned long);
 
@@ -1377,8 +1368,7 @@ static void cleanup_device_data(struct qib_devdata *dd)
                spin_unlock(&dd->pport[pidx].cc_shadow_lock);
        }
 
-       if (!qib_wc_pat)
-               qib_disable_wc(dd);
+       qib_disable_wc(dd);
 
        if (dd->pioavailregs_dma) {
                dma_free_coherent(&dd->pcidev->dev, PAGE_SIZE,
@@ -1547,14 +1537,12 @@ static int qib_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
                goto bail;
        }
 
-       if (!qib_wc_pat) {
-               ret = qib_enable_wc(dd);
-               if (ret) {
-                       qib_dev_err(dd,
-                               "Write combining not enabled (err %d): performance may be poor\n",
-                               -ret);
-                       ret = 0;
-               }
+       ret = qib_enable_wc(dd);
+       if (ret) {
+               qib_dev_err(dd,
+                       "Write combining not enabled (err %d): performance may be poor\n",
+                       -ret);
+               ret = 0;
        }
 
        qib_verify_pioperf(dd);
index 81b225f2300aed34eab9b88077bd4c4097dceae2..edd0ddbd44815d8e48ed49d3dec46e37545aa031 100644 (file)
@@ -116,21 +116,10 @@ int qib_enable_wc(struct qib_devdata *dd)
        }
 
        if (!ret) {
-               int cookie;
-
-               cookie = mtrr_add(pioaddr, piolen, MTRR_TYPE_WRCOMB, 0);
-               if (cookie < 0) {
-                       {
-                               qib_devinfo(dd->pcidev,
-                                        "mtrr_add()  WC for PIO bufs failed (%d)\n",
-                                        cookie);
-                               ret = -EINVAL;
-                       }
-               } else {
-                       dd->wc_cookie = cookie;
-                       dd->wc_base = (unsigned long) pioaddr;
-                       dd->wc_len = (unsigned long) piolen;
-               }
+               dd->wc_cookie = arch_phys_wc_add(pioaddr, piolen);
+               if (dd->wc_cookie < 0)
+                       /* use error from routine */
+                       ret = dd->wc_cookie;
        }
 
        return ret;
@@ -142,18 +131,7 @@ int qib_enable_wc(struct qib_devdata *dd)
  */
 void qib_disable_wc(struct qib_devdata *dd)
 {
-       if (dd->wc_cookie) {
-               int r;
-
-               r = mtrr_del(dd->wc_cookie, dd->wc_base,
-                            dd->wc_len);
-               if (r < 0)
-                       qib_devinfo(dd->pcidev,
-                                "mtrr_del(%lx, %lx, %lx) failed: %d\n",
-                                dd->wc_cookie, dd->wc_base,
-                                dd->wc_len, r);
-               dd->wc_cookie = 0; /* even on failure */
-       }
+       arch_phys_wc_del(dd->wc_cookie);
 }
 
 /**
index 56959adb6c7da51ccbb6d20307247b7cb69ad55a..cf32a778e7d0ccc0b6225d9c01442f5d2ec4cdb1 100644 (file)
@@ -386,8 +386,8 @@ static int ipoib_cm_nonsrq_init_rx(struct net_device *dev, struct ib_cm_id *cm_i
                                           rx->rx_ring[i].mapping,
                                           GFP_KERNEL)) {
                        ipoib_warn(priv, "failed to allocate receive buffer %d\n", i);
-                               ret = -ENOMEM;
-                               goto err_count;
+                       ret = -ENOMEM;
+                       goto err_count;
                }
                ret = ipoib_cm_post_receive_nonsrq(dev, rx, &t->wr, t->sge, i);
                if (ret) {
index 327529ee85eb1ed20bb8b7afad8022df94118108..3f40319a55da364f2e757acb7bc0e83d86c78c38 100644 (file)
@@ -547,11 +547,11 @@ isert_create_pi_ctx(struct fast_reg_descriptor *desc,
        return 0;
 
 err_prot_mr:
-       ib_dereg_mr(desc->pi_ctx->prot_mr);
+       ib_dereg_mr(pi_ctx->prot_mr);
 err_prot_frpl:
-       ib_free_fast_reg_page_list(desc->pi_ctx->prot_frpl);
+       ib_free_fast_reg_page_list(pi_ctx->prot_frpl);
 err_pi_ctx:
-       kfree(desc->pi_ctx);
+       kfree(pi_ctx);
 
        return ret;
 }
index f362883c94e37ce828d18938b7d25790135cf2d1..1d247bcf2ae25b20508f734d72b4904f704987d8 100644 (file)
@@ -747,6 +747,63 @@ static void joydev_cleanup(struct joydev *joydev)
                input_close_device(handle);
 }
 
+static bool joydev_dev_is_absolute_mouse(struct input_dev *dev)
+{
+       DECLARE_BITMAP(jd_scratch, KEY_CNT);
+
+       BUILD_BUG_ON(ABS_CNT > KEY_CNT || EV_CNT > KEY_CNT);
+
+       /*
+        * Virtualization (VMware, etc) and remote management (HP
+        * ILO2) solutions use absolute coordinates for their virtual
+        * pointing devices so that there is one-to-one relationship
+        * between pointer position on the host screen and virtual
+        * guest screen, and so their mice use ABS_X, ABS_Y and 3
+        * primary button events. This clashes with what joydev
+        * considers to be joysticks (a device with at minimum ABS_X
+        * axis).
+        *
+        * Here we are trying to separate absolute mice from
+        * joysticks. A device is, for joystick detection purposes,
+        * considered to be an absolute mouse if the following is
+        * true:
+        *
+        * 1) Event types are exactly EV_ABS, EV_KEY and EV_SYN.
+        * 2) Absolute events are exactly ABS_X and ABS_Y.
+        * 3) Keys are exactly BTN_LEFT, BTN_RIGHT and BTN_MIDDLE.
+        * 4) Device is not on "Amiga" bus.
+        */
+
+       bitmap_zero(jd_scratch, EV_CNT);
+       __set_bit(EV_ABS, jd_scratch);
+       __set_bit(EV_KEY, jd_scratch);
+       __set_bit(EV_SYN, jd_scratch);
+       if (!bitmap_equal(jd_scratch, dev->evbit, EV_CNT))
+               return false;
+
+       bitmap_zero(jd_scratch, ABS_CNT);
+       __set_bit(ABS_X, jd_scratch);
+       __set_bit(ABS_Y, jd_scratch);
+       if (!bitmap_equal(dev->absbit, jd_scratch, ABS_CNT))
+               return false;
+
+       bitmap_zero(jd_scratch, KEY_CNT);
+       __set_bit(BTN_LEFT, jd_scratch);
+       __set_bit(BTN_RIGHT, jd_scratch);
+       __set_bit(BTN_MIDDLE, jd_scratch);
+
+       if (!bitmap_equal(dev->keybit, jd_scratch, KEY_CNT))
+               return false;
+
+       /*
+        * Amiga joystick (amijoy) historically uses left/middle/right
+        * button events.
+        */
+       if (dev->id.bustype == BUS_AMIGA)
+               return false;
+
+       return true;
+}
 
 static bool joydev_match(struct input_handler *handler, struct input_dev *dev)
 {
@@ -758,6 +815,10 @@ static bool joydev_match(struct input_handler *handler, struct input_dev *dev)
        if (test_bit(EV_KEY, dev->evbit) && test_bit(BTN_DIGI, dev->keybit))
                return false;
 
+       /* Avoid absolute mice */
+       if (joydev_dev_is_absolute_mouse(dev))
+               return false;
+
        return true;
 }
 
index 7462d2fc8cfed8d4bf11d77fb2bb5e853d9f00eb..d7820d1152d2ef2d78f39c16281a9c316906e7ae 100644 (file)
@@ -156,7 +156,7 @@ config MOUSE_PS2_VMMOUSE
          Say Y here if you are running under control of VMware hypervisor
          (ESXi, Workstation or Fusion). Also make sure that when you enable
          this option, you remove the xf86-input-vmmouse user-space driver
-         or upgrade it to at least xf86-input-vmmouse 13.0.1, which doesn't
+         or upgrade it to at least xf86-input-vmmouse 13.1.0, which doesn't
          load in the presence of an in-kernel vmmouse driver.
 
          If unsure, say N.
index e6708f6efb4db7189dccdc1ed1fc0b3ca117a6ef..a353b7de6d22e91a52378cd4c106b17cafc26a07 100644 (file)
@@ -941,6 +941,11 @@ static void alps_get_finger_coordinate_v7(struct input_mt_pos *mt,
        case V7_PACKET_ID_TWO:
                mt[1].x &= ~0x000F;
                mt[1].y |= 0x000F;
+               /* Detect false-postive touches where x & y report max value */
+               if (mt[1].y == 0x7ff && mt[1].x == 0xff0) {
+                       mt[1].x = 0;
+                       /* y gets set to 0 at the end of this function */
+               }
                break;
 
        case V7_PACKET_ID_MULTI:
@@ -1058,9 +1063,8 @@ static void alps_process_trackstick_packet_v7(struct psmouse *psmouse)
        right = (packet[1] & 0x02) >> 1;
        middle = (packet[1] & 0x04) >> 2;
 
-       /* Divide 2 since trackpoint's speed is too fast */
-       input_report_rel(dev2, REL_X, (char)x / 2);
-       input_report_rel(dev2, REL_Y, -((char)y / 2));
+       input_report_rel(dev2, REL_X, (char)x);
+       input_report_rel(dev2, REL_Y, -((char)y));
 
        input_report_key(dev2, BTN_LEFT, left);
        input_report_key(dev2, BTN_RIGHT, right);
index 991dc6b20a58594cbc28ee1dfc8f45d677497fe5..ce3d40004458c87392339472f654462fae7cf0bc 100644 (file)
@@ -315,7 +315,7 @@ static void elantech_report_semi_mt_data(struct input_dev *dev,
                                         unsigned int x2, unsigned int y2)
 {
        elantech_set_slot(dev, 0, num_fingers != 0, x1, y1);
-       elantech_set_slot(dev, 1, num_fingers == 2, x2, y2);
+       elantech_set_slot(dev, 1, num_fingers >= 2, x2, y2);
 }
 
 /*
@@ -1376,10 +1376,11 @@ static bool elantech_is_signature_valid(const unsigned char *param)
                return true;
 
        /*
-        * Some models have a revision higher then 20. Meaning param[2] may
-        * be 10 or 20, skip the rates check for these.
+        * Some hw_version >= 4 models have a revision higher then 20. Meaning
+        * that param[2] may be 10 or 20, skip the rates check for these.
         */
-       if (param[0] == 0x46 && (param[1] & 0xef) == 0x0f && param[2] < 40)
+       if ((param[0] & 0x0f) >= 0x06 && (param[1] & 0xaf) == 0x0f &&
+           param[2] < 40)
                return true;
 
        for (i = 0; i < ARRAY_SIZE(rates); i++)
@@ -1555,6 +1556,7 @@ static int elantech_set_properties(struct elantech_data *etd)
                case 9:
                case 10:
                case 13:
+               case 14:
                        etd->hw_version = 4;
                        break;
                default:
index 630af73e98c488a5e266e4ccb6eed5dba622f3d3..35c8d0ceabeebf989b8eeff5cd54ee8f3ac2e247 100644 (file)
@@ -150,6 +150,11 @@ static const struct min_max_quirk min_max_pnpid_table[] = {
                {ANY_BOARD_ID, 2961},
                1024, 5112, 2024, 4832
        },
+       {
+               (const char * const []){"LEN2000", NULL},
+               {ANY_BOARD_ID, ANY_BOARD_ID},
+               1024, 5113, 2021, 4832
+       },
        {
                (const char * const []){"LEN2001", NULL},
                {ANY_BOARD_ID, ANY_BOARD_ID},
@@ -191,7 +196,7 @@ static const char * const topbuttonpad_pnp_ids[] = {
        "LEN0045",
        "LEN0047",
        "LEN0049",
-       "LEN2000",
+       "LEN2000", /* S540 */
        "LEN2001", /* Edge E431 */
        "LEN2002", /* Edge E531 */
        "LEN2003",
index 2d5ff86b343fbc30f1abf9e363333164311bfec6..e4c31256a74dbeddb70c74ec628ed856065cdff4 100644 (file)
@@ -164,7 +164,7 @@ static irqreturn_t stmpe_ts_handler(int irq, void *data)
                        STMPE_TSC_CTRL_TSC_EN, STMPE_TSC_CTRL_TSC_EN);
 
        /* start polling for touch_det to detect release */
-       schedule_delayed_work(&ts->work, HZ / 50);
+       schedule_delayed_work(&ts->work, msecs_to_jiffies(50));
 
        return IRQ_HANDLED;
 }
index aecb9ad2e7016885cda6ee2a7c08af1e461c9980..642f4a53de509f2f240f4cd5279ce2749d235455 100644 (file)
@@ -187,7 +187,7 @@ static int sx8654_probe(struct i2c_client *client,
                return -ENOMEM;
 
        input = devm_input_allocate_device(&client->dev);
-       if (!sx8654)
+       if (!input)
                return -ENOMEM;
 
        input->name = "SX8654 I2C Touchscreen";
index e43d48956dea239fe6816bdb23f0174754c623ee..e1c7e9e51045165db5312f540dfc8875e7b1f0b6 100644 (file)
@@ -2930,6 +2930,7 @@ static void *alloc_coherent(struct device *dev, size_t size,
        size      = PAGE_ALIGN(size);
        dma_mask  = dev->coherent_dma_mask;
        flag     &= ~(__GFP_DMA | __GFP_HIGHMEM | __GFP_DMA32);
+       flag     |= __GFP_ZERO;
 
        page = alloc_pages(flag | __GFP_NOWARN,  get_order(size));
        if (!page) {
index a1cbba9056fdba15b1334bd923714c65957fc20c..3465faf1809e4cb1d6630e5cdc8f87cd4e405bd2 100644 (file)
@@ -266,6 +266,7 @@ static void put_pasid_state(struct pasid_state *pasid_state)
 
 static void put_pasid_state_wait(struct pasid_state *pasid_state)
 {
+       atomic_dec(&pasid_state->count);
        wait_event(pasid_state->wq, !atomic_read(&pasid_state->count));
        free_pasid_state(pasid_state);
 }
index 9f7e1d34a32bc8ec75c6470260c66f839419f502..66a803b9dd3af928024d853995ed31383e0a8dd2 100644 (file)
 #define RESUME_TERMINATE               (1 << 0)
 
 #define TTBCR2_SEP_SHIFT               15
-#define TTBCR2_SEP_MASK                        0x7
-
-#define TTBCR2_ADDR_32                 0
-#define TTBCR2_ADDR_36                 1
-#define TTBCR2_ADDR_40                 2
-#define TTBCR2_ADDR_42                 3
-#define TTBCR2_ADDR_44                 4
-#define TTBCR2_ADDR_48                 5
+#define TTBCR2_SEP_UPSTREAM            (0x7 << TTBCR2_SEP_SHIFT)
 
 #define TTBRn_HI_ASID_SHIFT            16
 
@@ -793,26 +786,7 @@ static void arm_smmu_init_context_bank(struct arm_smmu_domain *smmu_domain,
                writel_relaxed(reg, cb_base + ARM_SMMU_CB_TTBCR);
                if (smmu->version > ARM_SMMU_V1) {
                        reg = pgtbl_cfg->arm_lpae_s1_cfg.tcr >> 32;
-                       switch (smmu->va_size) {
-                       case 32:
-                               reg |= (TTBCR2_ADDR_32 << TTBCR2_SEP_SHIFT);
-                               break;
-                       case 36:
-                               reg |= (TTBCR2_ADDR_36 << TTBCR2_SEP_SHIFT);
-                               break;
-                       case 40:
-                               reg |= (TTBCR2_ADDR_40 << TTBCR2_SEP_SHIFT);
-                               break;
-                       case 42:
-                               reg |= (TTBCR2_ADDR_42 << TTBCR2_SEP_SHIFT);
-                               break;
-                       case 44:
-                               reg |= (TTBCR2_ADDR_44 << TTBCR2_SEP_SHIFT);
-                               break;
-                       case 48:
-                               reg |= (TTBCR2_ADDR_48 << TTBCR2_SEP_SHIFT);
-                               break;
-                       }
+                       reg |= TTBCR2_SEP_UPSTREAM;
                        writel_relaxed(reg, cb_base + ARM_SMMU_CB_TTBCR2);
                }
        } else {
index 68d43beccb7e560f845ad49b8ae7d9e38872fcf7..5ecfaf29933ad4634e2124544e3c800b9b309d44 100644 (file)
@@ -422,6 +422,14 @@ static int dmar_map_gfx = 1;
 static int dmar_forcedac;
 static int intel_iommu_strict;
 static int intel_iommu_superpage = 1;
+static int intel_iommu_ecs = 1;
+
+/* We only actually use ECS when PASID support (on the new bit 40)
+ * is also advertised. Some early implementations â€” the ones with
+ * PASID support on bit 28 â€” have issues even when we *only* use
+ * extended root/context tables. */
+#define ecs_enabled(iommu) (intel_iommu_ecs && ecap_ecs(iommu->ecap) && \
+                           ecap_pasid(iommu->ecap))
 
 int intel_iommu_gfx_mapped;
 EXPORT_SYMBOL_GPL(intel_iommu_gfx_mapped);
@@ -465,6 +473,10 @@ static int __init intel_iommu_setup(char *str)
                        printk(KERN_INFO
                                "Intel-IOMMU: disable supported super page\n");
                        intel_iommu_superpage = 0;
+               } else if (!strncmp(str, "ecs_off", 7)) {
+                       printk(KERN_INFO
+                               "Intel-IOMMU: disable extended context table support\n");
+                       intel_iommu_ecs = 0;
                }
 
                str += strcspn(str, ",");
@@ -669,7 +681,7 @@ static inline struct context_entry *iommu_context_addr(struct intel_iommu *iommu
        struct context_entry *context;
        u64 *entry;
 
-       if (ecap_ecs(iommu->ecap)) {
+       if (ecs_enabled(iommu)) {
                if (devfn >= 0x80) {
                        devfn -= 0x80;
                        entry = &root->hi;
@@ -696,6 +708,11 @@ static inline struct context_entry *iommu_context_addr(struct intel_iommu *iommu
        return &context[devfn];
 }
 
+static int iommu_dummy(struct device *dev)
+{
+       return dev->archdata.iommu == DUMMY_DEVICE_DOMAIN_INFO;
+}
+
 static struct intel_iommu *device_to_iommu(struct device *dev, u8 *bus, u8 *devfn)
 {
        struct dmar_drhd_unit *drhd = NULL;
@@ -705,6 +722,9 @@ static struct intel_iommu *device_to_iommu(struct device *dev, u8 *bus, u8 *devf
        u16 segment = 0;
        int i;
 
+       if (iommu_dummy(dev))
+               return NULL;
+
        if (dev_is_pci(dev)) {
                pdev = to_pci_dev(dev);
                segment = pci_domain_nr(pdev->bus);
@@ -798,7 +818,7 @@ static void free_context_table(struct intel_iommu *iommu)
                if (context)
                        free_pgtable_page(context);
 
-               if (!ecap_ecs(iommu->ecap))
+               if (!ecs_enabled(iommu))
                        continue;
 
                context = iommu_context_addr(iommu, i, 0x80, 0);
@@ -1133,7 +1153,7 @@ static void iommu_set_root_entry(struct intel_iommu *iommu)
        unsigned long flag;
 
        addr = virt_to_phys(iommu->root_entry);
-       if (ecap_ecs(iommu->ecap))
+       if (ecs_enabled(iommu))
                addr |= DMA_RTADDR_RTT;
 
        raw_spin_lock_irqsave(&iommu->register_lock, flag);
@@ -2969,11 +2989,6 @@ static inline struct dmar_domain *get_valid_domain_for_dev(struct device *dev)
        return __get_valid_domain_for_dev(dev);
 }
 
-static int iommu_dummy(struct device *dev)
-{
-       return dev->archdata.iommu == DUMMY_DEVICE_DOMAIN_INFO;
-}
-
 /* Check if the dev needs to go through non-identity map and unmap process.*/
 static int iommu_no_mapping(struct device *dev)
 {
index 4015560bf486db22e82f1652799731b90277b864..cab214544237cf6f89754c3878f0e57f66ba360d 100644 (file)
@@ -1004,20 +1004,18 @@ static int rk_iommu_remove(struct platform_device *pdev)
        return 0;
 }
 
-#ifdef CONFIG_OF
 static const struct of_device_id rk_iommu_dt_ids[] = {
        { .compatible = "rockchip,iommu" },
        { /* sentinel */ }
 };
 MODULE_DEVICE_TABLE(of, rk_iommu_dt_ids);
-#endif
 
 static struct platform_driver rk_iommu_driver = {
        .probe = rk_iommu_probe,
        .remove = rk_iommu_remove,
        .driver = {
                   .name = "rk_iommu",
-                  .of_match_table = of_match_ptr(rk_iommu_dt_ids),
+                  .of_match_table = rk_iommu_dt_ids,
        },
 };
 
index 9687f8afebffbb865256ba6677663e6c76702aa1..1b7e155869f6c1a5f9ff361f246b6fd71539dadc 100644 (file)
@@ -828,7 +828,14 @@ static int its_alloc_tables(struct its_node *its)
                        u64 typer = readq_relaxed(its->base + GITS_TYPER);
                        u32 ids = GITS_TYPER_DEVBITS(typer);
 
-                       order = get_order((1UL << ids) * entry_size);
+                       /*
+                        * 'order' was initialized earlier to the default page
+                        * granule of the the ITS.  We can't have an allocation
+                        * smaller than that.  If the requested allocation
+                        * is smaller, round up to the default page granule.
+                        */
+                       order = max(get_order((1UL << ids) * entry_size),
+                                   order);
                        if (order >= MAX_ORDER) {
                                order = MAX_ORDER - 1;
                                pr_warn("%s: Device Table too large, reduce its page order to %u\n",
index 7b315e385ba3a0bba8de91fa851ab03c3ef653e8..01999d74bd3af32c5d05b8f14c97c07637d4571e 100644 (file)
@@ -82,19 +82,6 @@ static DEFINE_RAW_SPINLOCK(irq_controller_lock);
 #define NR_GIC_CPU_IF 8
 static u8 gic_cpu_map[NR_GIC_CPU_IF] __read_mostly;
 
-/*
- * Supported arch specific GIC irq extension.
- * Default make them NULL.
- */
-struct irq_chip gic_arch_extn = {
-       .irq_eoi        = NULL,
-       .irq_mask       = NULL,
-       .irq_unmask     = NULL,
-       .irq_retrigger  = NULL,
-       .irq_set_type   = NULL,
-       .irq_set_wake   = NULL,
-};
-
 #ifndef MAX_GIC_NR
 #define MAX_GIC_NR     1
 #endif
@@ -167,34 +154,16 @@ static int gic_peek_irq(struct irq_data *d, u32 offset)
 
 static void gic_mask_irq(struct irq_data *d)
 {
-       unsigned long flags;
-
-       raw_spin_lock_irqsave(&irq_controller_lock, flags);
        gic_poke_irq(d, GIC_DIST_ENABLE_CLEAR);
-       if (gic_arch_extn.irq_mask)
-               gic_arch_extn.irq_mask(d);
-       raw_spin_unlock_irqrestore(&irq_controller_lock, flags);
 }
 
 static void gic_unmask_irq(struct irq_data *d)
 {
-       unsigned long flags;
-
-       raw_spin_lock_irqsave(&irq_controller_lock, flags);
-       if (gic_arch_extn.irq_unmask)
-               gic_arch_extn.irq_unmask(d);
        gic_poke_irq(d, GIC_DIST_ENABLE_SET);
-       raw_spin_unlock_irqrestore(&irq_controller_lock, flags);
 }
 
 static void gic_eoi_irq(struct irq_data *d)
 {
-       if (gic_arch_extn.irq_eoi) {
-               raw_spin_lock(&irq_controller_lock);
-               gic_arch_extn.irq_eoi(d);
-               raw_spin_unlock(&irq_controller_lock);
-       }
-
        writel_relaxed(gic_irq(d), gic_cpu_base(d) + GIC_CPU_EOI);
 }
 
@@ -251,8 +220,6 @@ static int gic_set_type(struct irq_data *d, unsigned int type)
 {
        void __iomem *base = gic_dist_base(d);
        unsigned int gicirq = gic_irq(d);
-       unsigned long flags;
-       int ret;
 
        /* Interrupt configuration for SGIs can't be changed */
        if (gicirq < 16)
@@ -263,25 +230,7 @@ static int gic_set_type(struct irq_data *d, unsigned int type)
                            type != IRQ_TYPE_EDGE_RISING)
                return -EINVAL;
 
-       raw_spin_lock_irqsave(&irq_controller_lock, flags);
-
-       if (gic_arch_extn.irq_set_type)
-               gic_arch_extn.irq_set_type(d, type);
-
-       ret = gic_configure_irq(gicirq, type, base, NULL);
-
-       raw_spin_unlock_irqrestore(&irq_controller_lock, flags);
-
-       return ret;
-}
-
-static int gic_retrigger(struct irq_data *d)
-{
-       if (gic_arch_extn.irq_retrigger)
-               return gic_arch_extn.irq_retrigger(d);
-
-       /* the genirq layer expects 0 if we can't retrigger in hardware */
-       return 0;
+       return gic_configure_irq(gicirq, type, base, NULL);
 }
 
 #ifdef CONFIG_SMP
@@ -312,21 +261,6 @@ static int gic_set_affinity(struct irq_data *d, const struct cpumask *mask_val,
 }
 #endif
 
-#ifdef CONFIG_PM
-static int gic_set_wake(struct irq_data *d, unsigned int on)
-{
-       int ret = -ENXIO;
-
-       if (gic_arch_extn.irq_set_wake)
-               ret = gic_arch_extn.irq_set_wake(d, on);
-
-       return ret;
-}
-
-#else
-#define gic_set_wake   NULL
-#endif
-
 static void __exception_irq_entry gic_handle_irq(struct pt_regs *regs)
 {
        u32 irqstat, irqnr;
@@ -385,11 +319,9 @@ static struct irq_chip gic_chip = {
        .irq_unmask             = gic_unmask_irq,
        .irq_eoi                = gic_eoi_irq,
        .irq_set_type           = gic_set_type,
-       .irq_retrigger          = gic_retrigger,
 #ifdef CONFIG_SMP
        .irq_set_affinity       = gic_set_affinity,
 #endif
-       .irq_set_wake           = gic_set_wake,
        .irq_get_irqchip_state  = gic_irq_get_irqchip_state,
        .irq_set_irqchip_state  = gic_irq_set_irqchip_state,
 };
@@ -1055,7 +987,6 @@ void __init gic_init_bases(unsigned int gic_nr, int irq_start,
                set_handle_irq(gic_handle_irq);
        }
 
-       gic_chip.flags |= gic_arch_extn.flags;
        gic_dist_init(gic);
        gic_cpu_init(gic);
        gic_pm_init(gic);
index 57f09cb544644bcd97aa81bfc044c2686b350bbb..269c2354c43169307aa02438dbf38aa4b54f0dad 100644 (file)
@@ -271,7 +271,7 @@ int gic_get_c0_fdc_int(void)
                                  GIC_LOCAL_TO_HWIRQ(GIC_LOCAL_INT_FDC));
 }
 
-static void gic_handle_shared_int(void)
+static void gic_handle_shared_int(bool chained)
 {
        unsigned int i, intr, virq;
        unsigned long *pcpu_mask;
@@ -299,7 +299,10 @@ static void gic_handle_shared_int(void)
        while (intr != gic_shared_intrs) {
                virq = irq_linear_revmap(gic_irq_domain,
                                         GIC_SHARED_TO_HWIRQ(intr));
-               do_IRQ(virq);
+               if (chained)
+                       generic_handle_irq(virq);
+               else
+                       do_IRQ(virq);
 
                /* go to next pending bit */
                bitmap_clear(pending, intr, 1);
@@ -431,7 +434,7 @@ static struct irq_chip gic_edge_irq_controller = {
 #endif
 };
 
-static void gic_handle_local_int(void)
+static void gic_handle_local_int(bool chained)
 {
        unsigned long pending, masked;
        unsigned int intr, virq;
@@ -445,7 +448,10 @@ static void gic_handle_local_int(void)
        while (intr != GIC_NUM_LOCAL_INTRS) {
                virq = irq_linear_revmap(gic_irq_domain,
                                         GIC_LOCAL_TO_HWIRQ(intr));
-               do_IRQ(virq);
+               if (chained)
+                       generic_handle_irq(virq);
+               else
+                       do_IRQ(virq);
 
                /* go to next pending bit */
                bitmap_clear(&pending, intr, 1);
@@ -509,13 +515,14 @@ static struct irq_chip gic_all_vpes_local_irq_controller = {
 
 static void __gic_irq_dispatch(void)
 {
-       gic_handle_local_int();
-       gic_handle_shared_int();
+       gic_handle_local_int(false);
+       gic_handle_shared_int(false);
 }
 
 static void gic_irq_dispatch(unsigned int irq, struct irq_desc *desc)
 {
-       __gic_irq_dispatch();
+       gic_handle_local_int(true);
+       gic_handle_shared_int(true);
 }
 
 #ifdef CONFIG_MIPS_GIC_IPI
index 4a9ce5b50c5bba33b7428a0b67b88d26e31c4067..6b2b582433bde95062e85d17403e4a505c5a4ef9 100644 (file)
@@ -104,7 +104,7 @@ static int sunxi_sc_nmi_set_type(struct irq_data *data, unsigned int flow_type)
        irqd_set_trigger_type(data, flow_type);
        irq_setup_alt_chip(data, flow_type);
 
-       for (i = 0; i <= gc->num_ct; i++, ct++)
+       for (i = 0; i < gc->num_ct; i++, ct++)
                if (ct->type & flow_type)
                        ctrl_off = ct->regs.type;
 
index 51c485d9a87736bcf06cfdf67c089f81288bc8d8..f67bbd80433e8c90527a9b911a2656987b800b96 100644 (file)
@@ -264,7 +264,7 @@ static int tegra_ictlr_domain_alloc(struct irq_domain *domain,
 
                irq_domain_set_hwirq_and_chip(domain, virq + i, hwirq + i,
                                              &tegra_ictlr_chip,
-                                             &info->base[ictlr]);
+                                             info->base[ictlr]);
        }
 
        parent_args = *args;
index 7dc93aa004c86cfa988993d53164ea1d665aff97..312ffd3d00177ca5a5e21393377c760e9bdec91e 100644 (file)
@@ -173,7 +173,7 @@ static void unmap_switcher(void)
 bool lguest_address_ok(const struct lguest *lg,
                       unsigned long addr, unsigned long len)
 {
-       return (addr+len) / PAGE_SIZE < lg->pfn_limit && (addr+len >= addr);
+       return addr+len <= lg->pfn_limit * PAGE_SIZE && (addr+len >= addr);
 }
 
 /*
index 2bc56e2a35262141859f8da21d09a54dec852e52..135a0907e9de413d140e9fb9b793a91b638a1606 100644 (file)
@@ -177,11 +177,16 @@ static struct md_rdev *next_active_rdev(struct md_rdev *rdev, struct mddev *mdde
         * nr_pending is 0 and In_sync is clear, the entries we return will
         * still be in the same position on the list when we re-enter
         * list_for_each_entry_continue_rcu.
+        *
+        * Note that if entered with 'rdev == NULL' to start at the
+        * beginning, we temporarily assign 'rdev' to an address which
+        * isn't really an rdev, but which can be used by
+        * list_for_each_entry_continue_rcu() to find the first entry.
         */
        rcu_read_lock();
        if (rdev == NULL)
                /* start at the beginning */
-               rdev = list_entry_rcu(&mddev->disks, struct md_rdev, same_set);
+               rdev = list_entry(&mddev->disks, struct md_rdev, same_set);
        else {
                /* release the previous rdev and start from there. */
                rdev_dec_pending(rdev, mddev);
index 9eeea196328acc63c3220c309399abf014dfbb4b..5503e43e5f28257a0df0be1620d21fadaefc6476 100644 (file)
@@ -925,10 +925,11 @@ static int crypt_convert(struct crypt_config *cc,
 
                switch (r) {
                /* async */
-               case -EINPROGRESS:
                case -EBUSY:
                        wait_for_completion(&ctx->restart);
                        reinit_completion(&ctx->restart);
+                       /* fall through*/
+               case -EINPROGRESS:
                        ctx->req = NULL;
                        ctx->cc_sector++;
                        continue;
@@ -1345,8 +1346,10 @@ static void kcryptd_async_done(struct crypto_async_request *async_req,
        struct dm_crypt_io *io = container_of(ctx, struct dm_crypt_io, ctx);
        struct crypt_config *cc = io->cc;
 
-       if (error == -EINPROGRESS)
+       if (error == -EINPROGRESS) {
+               complete(&ctx->restart);
                return;
+       }
 
        if (!error && cc->iv_gen_ops && cc->iv_gen_ops->post)
                error = cc->iv_gen_ops->post(cc, iv_of_dmreq(cc, dmreq), dmreq);
@@ -1357,15 +1360,12 @@ static void kcryptd_async_done(struct crypto_async_request *async_req,
        crypt_free_req(cc, req_of_dmreq(cc, dmreq), io->base_bio);
 
        if (!atomic_dec_and_test(&ctx->cc_pending))
-               goto done;
+               return;
 
        if (bio_data_dir(io->base_bio) == READ)
                kcryptd_crypt_read_done(io);
        else
                kcryptd_crypt_write_io_submit(io, 1);
-done:
-       if (!completion_done(&ctx->restart))
-               complete(&ctx->restart);
 }
 
 static void kcryptd_crypt(struct work_struct *work)
index c8a18e4ee9dce262bb2c5bb87392018176b6ccfc..720ceeb7fa9b29118bea02dcb59e82a9f2638ee6 100644 (file)
@@ -1298,21 +1298,22 @@ static int table_load(struct dm_ioctl *param, size_t param_size)
                goto err_unlock_md_type;
        }
 
-       if (dm_get_md_type(md) == DM_TYPE_NONE)
+       if (dm_get_md_type(md) == DM_TYPE_NONE) {
                /* Initial table load: acquire type of table. */
                dm_set_md_type(md, dm_table_get_type(t));
-       else if (dm_get_md_type(md) != dm_table_get_type(t)) {
+
+               /* setup md->queue to reflect md's type (may block) */
+               r = dm_setup_md_queue(md);
+               if (r) {
+                       DMWARN("unable to set up device queue for new table.");
+                       goto err_unlock_md_type;
+               }
+       } else if (dm_get_md_type(md) != dm_table_get_type(t)) {
                DMWARN("can't change device type after initial table load.");
                r = -EINVAL;
                goto err_unlock_md_type;
        }
 
-       /* setup md->queue to reflect md's type (may block) */
-       r = dm_setup_md_queue(md);
-       if (r) {
-               DMWARN("unable to set up device queue for new table.");
-               goto err_unlock_md_type;
-       }
        dm_unlock_md_type(md);
 
        /* stage inactive table */
index 63953477a07c36e771a32d5bde686bd0f05890f1..eff7bdd7731d5e437d3b83ca4803ac8c03bac6b6 100644 (file)
@@ -429,9 +429,11 @@ static int __multipath_map(struct dm_target *ti, struct request *clone,
                /* blk-mq request-based interface */
                *__clone = blk_get_request(bdev_get_queue(bdev),
                                           rq_data_dir(rq), GFP_ATOMIC);
-               if (IS_ERR(*__clone))
+               if (IS_ERR(*__clone)) {
                        /* ENOMEM, requeue */
+                       clear_mapinfo(m, map_context);
                        return r;
+               }
                (*__clone)->bio = (*__clone)->biotail = NULL;
                (*__clone)->rq_disk = bdev->bd_disk;
                (*__clone)->cmd_flags |= REQ_FAILFAST_TRANSPORT;
index d9b00b8565c6dc1a36f5a3d863baa370126da593..16ba55ad708992f7e942b2f6ce2048d12be5c1b6 100644 (file)
@@ -820,6 +820,12 @@ void dm_consume_args(struct dm_arg_set *as, unsigned num_args)
 }
 EXPORT_SYMBOL(dm_consume_args);
 
+static bool __table_type_request_based(unsigned table_type)
+{
+       return (table_type == DM_TYPE_REQUEST_BASED ||
+               table_type == DM_TYPE_MQ_REQUEST_BASED);
+}
+
 static int dm_table_set_type(struct dm_table *t)
 {
        unsigned i;
@@ -852,8 +858,7 @@ static int dm_table_set_type(struct dm_table *t)
                 * Determine the type from the live device.
                 * Default to bio-based if device is new.
                 */
-               if (live_md_type == DM_TYPE_REQUEST_BASED ||
-                   live_md_type == DM_TYPE_MQ_REQUEST_BASED)
+               if (__table_type_request_based(live_md_type))
                        request_based = 1;
                else
                        bio_based = 1;
@@ -903,7 +908,7 @@ static int dm_table_set_type(struct dm_table *t)
                        }
                t->type = DM_TYPE_MQ_REQUEST_BASED;
 
-       } else if (hybrid && list_empty(devices) && live_md_type != DM_TYPE_NONE) {
+       } else if (list_empty(devices) && __table_type_request_based(live_md_type)) {
                /* inherit live MD type */
                t->type = live_md_type;
 
@@ -925,10 +930,7 @@ struct target_type *dm_table_get_immutable_target_type(struct dm_table *t)
 
 bool dm_table_request_based(struct dm_table *t)
 {
-       unsigned table_type = dm_table_get_type(t);
-
-       return (table_type == DM_TYPE_REQUEST_BASED ||
-               table_type == DM_TYPE_MQ_REQUEST_BASED);
+       return __table_type_request_based(dm_table_get_type(t));
 }
 
 bool dm_table_mq_request_based(struct dm_table *t)
index f8c7ca3e8947378484a6d3f9745c363c78ab2879..2caf492890d64b27a0a88f24f4f04d1778448d9a 100644 (file)
@@ -1089,11 +1089,17 @@ static void free_rq_clone(struct request *clone)
 
        blk_rq_unprep_clone(clone);
 
-       if (clone->q->mq_ops)
+       if (md->type == DM_TYPE_MQ_REQUEST_BASED)
+               /* stacked on blk-mq queue(s) */
                tio->ti->type->release_clone_rq(clone);
        else if (!md->queue->mq_ops)
                /* request_fn queue stacked on request_fn queue(s) */
                free_clone_request(md, clone);
+       /*
+        * NOTE: for the blk-mq queue stacked on request_fn queue(s) case:
+        * no need to call free_clone_request() because we leverage blk-mq by
+        * allocating the clone at the end of the blk-mq pdu (see: clone_rq)
+        */
 
        if (!md->queue->mq_ops)
                free_rq_tio(tio);
@@ -1156,6 +1162,7 @@ static void old_requeue_request(struct request *rq)
 
        spin_lock_irqsave(q->queue_lock, flags);
        blk_requeue_request(q, rq);
+       blk_run_queue_async(q);
        spin_unlock_irqrestore(q->queue_lock, flags);
 }
 
@@ -1716,8 +1723,7 @@ static int dm_merge_bvec(struct request_queue *q,
        struct mapped_device *md = q->queuedata;
        struct dm_table *map = dm_get_live_table_fast(md);
        struct dm_target *ti;
-       sector_t max_sectors;
-       int max_size = 0;
+       sector_t max_sectors, max_size = 0;
 
        if (unlikely(!map))
                goto out;
@@ -1732,8 +1738,16 @@ static int dm_merge_bvec(struct request_queue *q,
        max_sectors = min(max_io_len(bvm->bi_sector, ti),
                          (sector_t) queue_max_sectors(q));
        max_size = (max_sectors << SECTOR_SHIFT) - bvm->bi_size;
-       if (unlikely(max_size < 0)) /* this shouldn't _ever_ happen */
-               max_size = 0;
+
+       /*
+        * FIXME: this stop-gap fix _must_ be cleaned up (by passing a sector_t
+        * to the targets' merge function since it holds sectors not bytes).
+        * Just doing this as an interim fix for stable@ because the more
+        * comprehensive cleanup of switching to sector_t will impact every
+        * DM target that implements a ->merge hook.
+        */
+       if (max_size > INT_MAX)
+               max_size = INT_MAX;
 
        /*
         * merge_bvec_fn() returns number of bytes
@@ -1741,7 +1755,7 @@ static int dm_merge_bvec(struct request_queue *q,
         * max is precomputed maximal io size
         */
        if (max_size && ti->type->merge)
-               max_size = ti->type->merge(ti, bvm, biovec, max_size);
+               max_size = ti->type->merge(ti, bvm, biovec, (int) max_size);
        /*
         * If the target doesn't support merge method and some of the devices
         * provided their merge_bvec method (we know this by looking for the
@@ -1963,8 +1977,8 @@ static int map_request(struct dm_rq_target_io *tio, struct request *rq,
                        dm_kill_unmapped_request(rq, r);
                        return r;
                }
-               if (IS_ERR(clone))
-                       return DM_MAPIO_REQUEUE;
+               if (r != DM_MAPIO_REMAPPED)
+                       return r;
                if (setup_clone(clone, rq, tio, GFP_ATOMIC)) {
                        /* -ENOMEM */
                        ti->type->release_clone_rq(clone);
@@ -2662,9 +2676,6 @@ static int dm_init_request_based_queue(struct mapped_device *md)
 {
        struct request_queue *q = NULL;
 
-       if (md->queue->elevator)
-               return 0;
-
        /* Fully initialize the queue */
        q = blk_init_allocated_queue(md->queue, dm_request_fn, NULL);
        if (!q)
@@ -2748,13 +2759,15 @@ static int dm_mq_queue_rq(struct blk_mq_hw_ctx *hctx,
        if (dm_table_get_type(map) == DM_TYPE_REQUEST_BASED) {
                /* clone request is allocated at the end of the pdu */
                tio->clone = (void *)blk_mq_rq_to_pdu(rq) + sizeof(struct dm_rq_target_io);
-               if (!clone_rq(rq, md, tio, GFP_ATOMIC))
-                       return BLK_MQ_RQ_QUEUE_BUSY;
+               (void) clone_rq(rq, md, tio, GFP_ATOMIC);
                queue_kthread_work(&md->kworker, &tio->work);
        } else {
                /* Direct call is fine since .queue_rq allows allocations */
-               if (map_request(tio, rq, md) == DM_MAPIO_REQUEUE)
-                       dm_requeue_unmapped_original_request(md, rq);
+               if (map_request(tio, rq, md) == DM_MAPIO_REQUEUE) {
+                       /* Undo dm_start_request() before requeuing */
+                       rq_completed(md, rq_data_dir(rq), false);
+                       return BLK_MQ_RQ_QUEUE_BUSY;
+               }
        }
 
        return BLK_MQ_RQ_QUEUE_OK;
index d4f31e195e26ebcc4233c9b333624d8b73191826..4dbed4a67aaf40e3c04bde925870c24d13cd1b4e 100644 (file)
@@ -3834,7 +3834,7 @@ array_state_store(struct mddev *mddev, const char *buf, size_t len)
                                err = -EBUSY;
                }
                spin_unlock(&mddev->lock);
-               return err;
+               return err ?: len;
        }
        err = mddev_lock(mddev);
        if (err)
@@ -4211,34 +4211,36 @@ action_store(struct mddev *mddev, const char *page, size_t len)
        if (!mddev->pers || !mddev->pers->sync_request)
                return -EINVAL;
 
-       if (cmd_match(page, "frozen"))
-               set_bit(MD_RECOVERY_FROZEN, &mddev->recovery);
-       else
-               clear_bit(MD_RECOVERY_FROZEN, &mddev->recovery);
 
        if (cmd_match(page, "idle") || cmd_match(page, "frozen")) {
-               flush_workqueue(md_misc_wq);
-               if (mddev->sync_thread) {
-                       set_bit(MD_RECOVERY_INTR, &mddev->recovery);
-                       if (mddev_lock(mddev) == 0) {
+               if (cmd_match(page, "frozen"))
+                       set_bit(MD_RECOVERY_FROZEN, &mddev->recovery);
+               else
+                       clear_bit(MD_RECOVERY_FROZEN, &mddev->recovery);
+               if (test_bit(MD_RECOVERY_RUNNING, &mddev->recovery) &&
+                   mddev_lock(mddev) == 0) {
+                       flush_workqueue(md_misc_wq);
+                       if (mddev->sync_thread) {
+                               set_bit(MD_RECOVERY_INTR, &mddev->recovery);
                                md_reap_sync_thread(mddev);
-                               mddev_unlock(mddev);
                        }
+                       mddev_unlock(mddev);
                }
        } else if (test_bit(MD_RECOVERY_RUNNING, &mddev->recovery) ||
                   test_bit(MD_RECOVERY_NEEDED, &mddev->recovery))
                return -EBUSY;
        else if (cmd_match(page, "resync"))
-               set_bit(MD_RECOVERY_NEEDED, &mddev->recovery);
+               clear_bit(MD_RECOVERY_FROZEN, &mddev->recovery);
        else if (cmd_match(page, "recover")) {
+               clear_bit(MD_RECOVERY_FROZEN, &mddev->recovery);
                set_bit(MD_RECOVERY_RECOVER, &mddev->recovery);
-               set_bit(MD_RECOVERY_NEEDED, &mddev->recovery);
        } else if (cmd_match(page, "reshape")) {
                int err;
                if (mddev->pers->start_reshape == NULL)
                        return -EINVAL;
                err = mddev_lock(mddev);
                if (!err) {
+                       clear_bit(MD_RECOVERY_FROZEN, &mddev->recovery);
                        err = mddev->pers->start_reshape(mddev);
                        mddev_unlock(mddev);
                }
@@ -4250,6 +4252,7 @@ action_store(struct mddev *mddev, const char *page, size_t len)
                        set_bit(MD_RECOVERY_CHECK, &mddev->recovery);
                else if (!cmd_match(page, "repair"))
                        return -EINVAL;
+               clear_bit(MD_RECOVERY_FROZEN, &mddev->recovery);
                set_bit(MD_RECOVERY_REQUESTED, &mddev->recovery);
                set_bit(MD_RECOVERY_SYNC, &mddev->recovery);
        }
@@ -4818,12 +4821,12 @@ static void md_free(struct kobject *ko)
        if (mddev->sysfs_state)
                sysfs_put(mddev->sysfs_state);
 
+       if (mddev->queue)
+               blk_cleanup_queue(mddev->queue);
        if (mddev->gendisk) {
                del_gendisk(mddev->gendisk);
                put_disk(mddev->gendisk);
        }
-       if (mddev->queue)
-               blk_cleanup_queue(mddev->queue);
 
        kfree(mddev);
 }
@@ -8259,6 +8262,7 @@ void md_reap_sync_thread(struct mddev *mddev)
        if (mddev_is_clustered(mddev))
                md_cluster_ops->metadata_update_finish(mddev);
        clear_bit(MD_RECOVERY_RUNNING, &mddev->recovery);
+       clear_bit(MD_RECOVERY_DONE, &mddev->recovery);
        clear_bit(MD_RECOVERY_SYNC, &mddev->recovery);
        clear_bit(MD_RECOVERY_RESHAPE, &mddev->recovery);
        clear_bit(MD_RECOVERY_REQUESTED, &mddev->recovery);
index 2cb59a641cd24417d996df89c2e2c81cc9eb087b..efb654eb53992fc45da9a6e08572779496083c3f 100644 (file)
@@ -188,8 +188,9 @@ static int create_strip_zones(struct mddev *mddev, struct r0conf **private_conf)
                }
                dev[j] = rdev1;
 
-               disk_stack_limits(mddev->gendisk, rdev1->bdev,
-                                 rdev1->data_offset << 9);
+               if (mddev->queue)
+                       disk_stack_limits(mddev->gendisk, rdev1->bdev,
+                                         rdev1->data_offset << 9);
 
                if (rdev1->bdev->bd_disk->queue->merge_bvec_fn)
                        conf->has_merge_bvec = 1;
@@ -523,6 +524,9 @@ static void raid0_make_request(struct mddev *mddev, struct bio *bio)
                         ? (sector & (chunk_sects-1))
                         : sector_div(sector, chunk_sects));
 
+               /* Restore due to sector_div */
+               sector = bio->bi_iter.bi_sector;
+
                if (sectors < bio_sectors(bio)) {
                        split = bio_split(bio, sectors, GFP_NOIO, fs_bio_set);
                        bio_chain(split, bio);
@@ -530,7 +534,6 @@ static void raid0_make_request(struct mddev *mddev, struct bio *bio)
                        split = bio;
                }
 
-               sector = bio->bi_iter.bi_sector;
                zone = find_zone(mddev->private, &sector);
                tmp_dev = map_sector(mddev, zone, sector, &sector);
                split->bi_bdev = tmp_dev->bdev;
index e793ab6b35705e0ed1ad6904ebe9353b6dbf6fd6..f55c3f35b7463141086afb727785c775c5185d76 100644 (file)
@@ -4156,6 +4156,7 @@ static int raid10_start_reshape(struct mddev *mddev)
 
        clear_bit(MD_RECOVERY_SYNC, &mddev->recovery);
        clear_bit(MD_RECOVERY_CHECK, &mddev->recovery);
+       clear_bit(MD_RECOVERY_DONE, &mddev->recovery);
        set_bit(MD_RECOVERY_RESHAPE, &mddev->recovery);
        set_bit(MD_RECOVERY_RUNNING, &mddev->recovery);
 
index 77dfd720aaa00ebc55d14234cd40b6e9b65bae5f..b6793d2e051f3b278405f236e6623980bcdf1d04 100644 (file)
@@ -749,6 +749,7 @@ static void unlock_two_stripes(struct stripe_head *sh1, struct stripe_head *sh2)
 static bool stripe_can_batch(struct stripe_head *sh)
 {
        return test_bit(STRIPE_BATCH_READY, &sh->state) &&
+               !test_bit(STRIPE_BITMAP_PENDING, &sh->state) &&
                is_full_stripe_write(sh);
 }
 
@@ -837,6 +838,15 @@ static void stripe_add_to_batch_list(struct r5conf *conf, struct stripe_head *sh
                    < IO_THRESHOLD)
                        md_wakeup_thread(conf->mddev->thread);
 
+       if (test_and_clear_bit(STRIPE_BIT_DELAY, &sh->state)) {
+               int seq = sh->bm_seq;
+               if (test_bit(STRIPE_BIT_DELAY, &sh->batch_head->state) &&
+                   sh->batch_head->bm_seq > seq)
+                       seq = sh->batch_head->bm_seq;
+               set_bit(STRIPE_BIT_DELAY, &sh->batch_head->state);
+               sh->batch_head->bm_seq = seq;
+       }
+
        atomic_inc(&sh->count);
 unlock_out:
        unlock_two_stripes(head, sh);
@@ -1078,9 +1088,6 @@ again:
                        pr_debug("skip op %ld on disc %d for sector %llu\n",
                                bi->bi_rw, i, (unsigned long long)sh->sector);
                        clear_bit(R5_LOCKED, &sh->dev[i].flags);
-                       if (sh->batch_head)
-                               set_bit(STRIPE_BATCH_ERR,
-                                       &sh->batch_head->state);
                        set_bit(STRIPE_HANDLE, &sh->state);
                }
 
@@ -1825,7 +1832,7 @@ again:
        } else
                init_async_submit(&submit, 0, tx, NULL, NULL,
                                  to_addr_conv(sh, percpu, j));
-       async_gen_syndrome(blocks, 0, count+2, STRIPE_SIZE,  &submit);
+       tx = async_gen_syndrome(blocks, 0, count+2, STRIPE_SIZE,  &submit);
        if (!last_stripe) {
                j++;
                sh = list_first_entry(&sh->batch_list, struct stripe_head,
@@ -1971,17 +1978,30 @@ static void raid_run_ops(struct stripe_head *sh, unsigned long ops_request)
        put_cpu();
 }
 
+static struct stripe_head *alloc_stripe(struct kmem_cache *sc, gfp_t gfp)
+{
+       struct stripe_head *sh;
+
+       sh = kmem_cache_zalloc(sc, gfp);
+       if (sh) {
+               spin_lock_init(&sh->stripe_lock);
+               spin_lock_init(&sh->batch_lock);
+               INIT_LIST_HEAD(&sh->batch_list);
+               INIT_LIST_HEAD(&sh->lru);
+               atomic_set(&sh->count, 1);
+       }
+       return sh;
+}
 static int grow_one_stripe(struct r5conf *conf, gfp_t gfp)
 {
        struct stripe_head *sh;
-       sh = kmem_cache_zalloc(conf->slab_cache, gfp);
+
+       sh = alloc_stripe(conf->slab_cache, gfp);
        if (!sh)
                return 0;
 
        sh->raid_conf = conf;
 
-       spin_lock_init(&sh->stripe_lock);
-
        if (grow_buffers(sh, gfp)) {
                shrink_buffers(sh);
                kmem_cache_free(conf->slab_cache, sh);
@@ -1990,13 +2010,8 @@ static int grow_one_stripe(struct r5conf *conf, gfp_t gfp)
        sh->hash_lock_index =
                conf->max_nr_stripes % NR_STRIPE_HASH_LOCKS;
        /* we just created an active stripe so... */
-       atomic_set(&sh->count, 1);
        atomic_inc(&conf->active_stripes);
-       INIT_LIST_HEAD(&sh->lru);
 
-       spin_lock_init(&sh->batch_lock);
-       INIT_LIST_HEAD(&sh->batch_list);
-       sh->batch_head = NULL;
        release_stripe(sh);
        conf->max_nr_stripes++;
        return 1;
@@ -2060,6 +2075,35 @@ static struct flex_array *scribble_alloc(int num, int cnt, gfp_t flags)
        return ret;
 }
 
+static int resize_chunks(struct r5conf *conf, int new_disks, int new_sectors)
+{
+       unsigned long cpu;
+       int err = 0;
+
+       mddev_suspend(conf->mddev);
+       get_online_cpus();
+       for_each_present_cpu(cpu) {
+               struct raid5_percpu *percpu;
+               struct flex_array *scribble;
+
+               percpu = per_cpu_ptr(conf->percpu, cpu);
+               scribble = scribble_alloc(new_disks,
+                                         new_sectors / STRIPE_SECTORS,
+                                         GFP_NOIO);
+
+               if (scribble) {
+                       flex_array_free(percpu->scribble);
+                       percpu->scribble = scribble;
+               } else {
+                       err = -ENOMEM;
+                       break;
+               }
+       }
+       put_online_cpus();
+       mddev_resume(conf->mddev);
+       return err;
+}
+
 static int resize_stripes(struct r5conf *conf, int newsize)
 {
        /* Make all the stripes able to hold 'newsize' devices.
@@ -2088,7 +2132,6 @@ static int resize_stripes(struct r5conf *conf, int newsize)
        struct stripe_head *osh, *nsh;
        LIST_HEAD(newstripes);
        struct disk_info *ndisks;
-       unsigned long cpu;
        int err;
        struct kmem_cache *sc;
        int i;
@@ -2109,13 +2152,11 @@ static int resize_stripes(struct r5conf *conf, int newsize)
                return -ENOMEM;
 
        for (i = conf->max_nr_stripes; i; i--) {
-               nsh = kmem_cache_zalloc(sc, GFP_KERNEL);
+               nsh = alloc_stripe(sc, GFP_KERNEL);
                if (!nsh)
                        break;
 
                nsh->raid_conf = conf;
-               spin_lock_init(&nsh->stripe_lock);
-
                list_add(&nsh->lru, &newstripes);
        }
        if (i) {
@@ -2142,13 +2183,11 @@ static int resize_stripes(struct r5conf *conf, int newsize)
                                    lock_device_hash_lock(conf, hash));
                osh = get_free_stripe(conf, hash);
                unlock_device_hash_lock(conf, hash);
-               atomic_set(&nsh->count, 1);
+
                for(i=0; i<conf->pool_size; i++) {
                        nsh->dev[i].page = osh->dev[i].page;
                        nsh->dev[i].orig_page = osh->dev[i].page;
                }
-               for( ; i<newsize; i++)
-                       nsh->dev[i].page = NULL;
                nsh->hash_lock_index = hash;
                kmem_cache_free(conf->slab_cache, osh);
                cnt++;
@@ -2174,25 +2213,6 @@ static int resize_stripes(struct r5conf *conf, int newsize)
        } else
                err = -ENOMEM;
 
-       get_online_cpus();
-       for_each_present_cpu(cpu) {
-               struct raid5_percpu *percpu;
-               struct flex_array *scribble;
-
-               percpu = per_cpu_ptr(conf->percpu, cpu);
-               scribble = scribble_alloc(newsize, conf->chunk_sectors /
-                       STRIPE_SECTORS, GFP_NOIO);
-
-               if (scribble) {
-                       flex_array_free(percpu->scribble);
-                       percpu->scribble = scribble;
-               } else {
-                       err = -ENOMEM;
-                       break;
-               }
-       }
-       put_online_cpus();
-
        /* Step 4, return new stripes to service */
        while(!list_empty(&newstripes)) {
                nsh = list_entry(newstripes.next, struct stripe_head, lru);
@@ -2212,7 +2232,8 @@ static int resize_stripes(struct r5conf *conf, int newsize)
 
        conf->slab_cache = sc;
        conf->active_name = 1-conf->active_name;
-       conf->pool_size = newsize;
+       if (!err)
+               conf->pool_size = newsize;
        return err;
 }
 
@@ -2434,7 +2455,7 @@ static void raid5_end_write_request(struct bio *bi, int error)
        }
        rdev_dec_pending(rdev, conf->mddev);
 
-       if (sh->batch_head && !uptodate)
+       if (sh->batch_head && !uptodate && !replacement)
                set_bit(STRIPE_BATCH_ERR, &sh->batch_head->state);
 
        if (!test_and_clear_bit(R5_DOUBLE_LOCKED, &sh->dev[i].flags))
@@ -2976,14 +2997,32 @@ static int add_stripe_bio(struct stripe_head *sh, struct bio *bi, int dd_idx,
        pr_debug("added bi b#%llu to stripe s#%llu, disk %d.\n",
                (unsigned long long)(*bip)->bi_iter.bi_sector,
                (unsigned long long)sh->sector, dd_idx);
-       spin_unlock_irq(&sh->stripe_lock);
 
        if (conf->mddev->bitmap && firstwrite) {
+               /* Cannot hold spinlock over bitmap_startwrite,
+                * but must ensure this isn't added to a batch until
+                * we have added to the bitmap and set bm_seq.
+                * So set STRIPE_BITMAP_PENDING to prevent
+                * batching.
+                * If multiple add_stripe_bio() calls race here they
+                * much all set STRIPE_BITMAP_PENDING.  So only the first one
+                * to complete "bitmap_startwrite" gets to set
+                * STRIPE_BIT_DELAY.  This is important as once a stripe
+                * is added to a batch, STRIPE_BIT_DELAY cannot be changed
+                * any more.
+                */
+               set_bit(STRIPE_BITMAP_PENDING, &sh->state);
+               spin_unlock_irq(&sh->stripe_lock);
                bitmap_startwrite(conf->mddev->bitmap, sh->sector,
                                  STRIPE_SECTORS, 0);
-               sh->bm_seq = conf->seq_flush+1;
-               set_bit(STRIPE_BIT_DELAY, &sh->state);
+               spin_lock_irq(&sh->stripe_lock);
+               clear_bit(STRIPE_BITMAP_PENDING, &sh->state);
+               if (!sh->batch_head) {
+                       sh->bm_seq = conf->seq_flush+1;
+                       set_bit(STRIPE_BIT_DELAY, &sh->state);
+               }
        }
+       spin_unlock_irq(&sh->stripe_lock);
 
        if (stripe_can_batch(sh))
                stripe_add_to_batch_list(conf, sh);
@@ -3278,7 +3317,9 @@ static int need_this_block(struct stripe_head *sh, struct stripe_head_state *s,
                /* reconstruct-write isn't being forced */
                return 0;
        for (i = 0; i < s->failed; i++) {
-               if (!test_bit(R5_UPTODATE, &fdev[i]->flags) &&
+               if (s->failed_num[i] != sh->pd_idx &&
+                   s->failed_num[i] != sh->qd_idx &&
+                   !test_bit(R5_UPTODATE, &fdev[i]->flags) &&
                    !test_bit(R5_OVERWRITE, &fdev[i]->flags))
                        return 1;
        }
@@ -3298,6 +3339,7 @@ static int fetch_block(struct stripe_head *sh, struct stripe_head_state *s,
                 */
                BUG_ON(test_bit(R5_Wantcompute, &dev->flags));
                BUG_ON(test_bit(R5_Wantread, &dev->flags));
+               BUG_ON(sh->batch_head);
                if ((s->uptodate == disks - 1) &&
                    (s->failed && (disk_idx == s->failed_num[0] ||
                                   disk_idx == s->failed_num[1]))) {
@@ -3366,7 +3408,6 @@ static void handle_stripe_fill(struct stripe_head *sh,
 {
        int i;
 
-       BUG_ON(sh->batch_head);
        /* look for blocks to read/compute, skip this if a compute
         * is already in flight, or if the stripe contents are in the
         * midst of changing due to a write
@@ -3379,6 +3420,8 @@ static void handle_stripe_fill(struct stripe_head *sh,
        set_bit(STRIPE_HANDLE, &sh->state);
 }
 
+static void break_stripe_batch_list(struct stripe_head *head_sh,
+                                   unsigned long handle_flags);
 /* handle_stripe_clean_event
  * any written block on an uptodate or failed drive can be returned.
  * Note that if we 'wrote' to a failed drive, it will be UPTODATE, but
@@ -3392,7 +3435,6 @@ static void handle_stripe_clean_event(struct r5conf *conf,
        int discard_pending = 0;
        struct stripe_head *head_sh = sh;
        bool do_endio = false;
-       int wakeup_nr = 0;
 
        for (i = disks; i--; )
                if (sh->dev[i].written) {
@@ -3481,44 +3523,8 @@ unhash:
                if (atomic_dec_and_test(&conf->pending_full_writes))
                        md_wakeup_thread(conf->mddev->thread);
 
-       if (!head_sh->batch_head || !do_endio)
-               return;
-       for (i = 0; i < head_sh->disks; i++) {
-               if (test_and_clear_bit(R5_Overlap, &head_sh->dev[i].flags))
-                       wakeup_nr++;
-       }
-       while (!list_empty(&head_sh->batch_list)) {
-               int i;
-               sh = list_first_entry(&head_sh->batch_list,
-                                     struct stripe_head, batch_list);
-               list_del_init(&sh->batch_list);
-
-               set_mask_bits(&sh->state, ~STRIPE_EXPAND_SYNC_FLAG,
-                             head_sh->state & ~((1 << STRIPE_ACTIVE) |
-                                                (1 << STRIPE_PREREAD_ACTIVE) |
-                                                STRIPE_EXPAND_SYNC_FLAG));
-               sh->check_state = head_sh->check_state;
-               sh->reconstruct_state = head_sh->reconstruct_state;
-               for (i = 0; i < sh->disks; i++) {
-                       if (test_and_clear_bit(R5_Overlap, &sh->dev[i].flags))
-                               wakeup_nr++;
-                       sh->dev[i].flags = head_sh->dev[i].flags;
-               }
-
-               spin_lock_irq(&sh->stripe_lock);
-               sh->batch_head = NULL;
-               spin_unlock_irq(&sh->stripe_lock);
-               if (sh->state & STRIPE_EXPAND_SYNC_FLAG)
-                       set_bit(STRIPE_HANDLE, &sh->state);
-               release_stripe(sh);
-       }
-
-       spin_lock_irq(&head_sh->stripe_lock);
-       head_sh->batch_head = NULL;
-       spin_unlock_irq(&head_sh->stripe_lock);
-       wake_up_nr(&conf->wait_for_overlap, wakeup_nr);
-       if (head_sh->state & STRIPE_EXPAND_SYNC_FLAG)
-               set_bit(STRIPE_HANDLE, &head_sh->state);
+       if (head_sh->batch_head && do_endio)
+               break_stripe_batch_list(head_sh, STRIPE_EXPAND_SYNC_FLAGS);
 }
 
 static void handle_stripe_dirtying(struct r5conf *conf,
@@ -4159,9 +4165,13 @@ static void analyse_stripe(struct stripe_head *sh, struct stripe_head_state *s)
 
 static int clear_batch_ready(struct stripe_head *sh)
 {
+       /* Return '1' if this is a member of batch, or
+        * '0' if it is a lone stripe or a head which can now be
+        * handled.
+        */
        struct stripe_head *tmp;
        if (!test_and_clear_bit(STRIPE_BATCH_READY, &sh->state))
-               return 0;
+               return (sh->batch_head && sh->batch_head != sh);
        spin_lock(&sh->stripe_lock);
        if (!sh->batch_head) {
                spin_unlock(&sh->stripe_lock);
@@ -4189,46 +4199,65 @@ static int clear_batch_ready(struct stripe_head *sh)
        return 0;
 }
 
-static void check_break_stripe_batch_list(struct stripe_head *sh)
+static void break_stripe_batch_list(struct stripe_head *head_sh,
+                                   unsigned long handle_flags)
 {
-       struct stripe_head *head_sh, *next;
+       struct stripe_head *sh, *next;
        int i;
+       int do_wakeup = 0;
 
-       if (!test_and_clear_bit(STRIPE_BATCH_ERR, &sh->state))
-               return;
+       list_for_each_entry_safe(sh, next, &head_sh->batch_list, batch_list) {
 
-       head_sh = sh;
-       do {
-               sh = list_first_entry(&sh->batch_list,
-                                     struct stripe_head, batch_list);
-               BUG_ON(sh == head_sh);
-       } while (!test_bit(STRIPE_DEGRADED, &sh->state));
-
-       while (sh != head_sh) {
-               next = list_first_entry(&sh->batch_list,
-                                       struct stripe_head, batch_list);
                list_del_init(&sh->batch_list);
 
-               set_mask_bits(&sh->state, ~STRIPE_EXPAND_SYNC_FLAG,
-                             head_sh->state & ~((1 << STRIPE_ACTIVE) |
-                                                (1 << STRIPE_PREREAD_ACTIVE) |
-                                                (1 << STRIPE_DEGRADED) |
-                                                STRIPE_EXPAND_SYNC_FLAG));
+               WARN_ON_ONCE(sh->state & ((1 << STRIPE_ACTIVE) |
+                                         (1 << STRIPE_SYNCING) |
+                                         (1 << STRIPE_REPLACED) |
+                                         (1 << STRIPE_PREREAD_ACTIVE) |
+                                         (1 << STRIPE_DELAYED) |
+                                         (1 << STRIPE_BIT_DELAY) |
+                                         (1 << STRIPE_FULL_WRITE) |
+                                         (1 << STRIPE_BIOFILL_RUN) |
+                                         (1 << STRIPE_COMPUTE_RUN)  |
+                                         (1 << STRIPE_OPS_REQ_PENDING) |
+                                         (1 << STRIPE_DISCARD) |
+                                         (1 << STRIPE_BATCH_READY) |
+                                         (1 << STRIPE_BATCH_ERR) |
+                                         (1 << STRIPE_BITMAP_PENDING)));
+               WARN_ON_ONCE(head_sh->state & ((1 << STRIPE_DISCARD) |
+                                             (1 << STRIPE_REPLACED)));
+
+               set_mask_bits(&sh->state, ~(STRIPE_EXPAND_SYNC_FLAGS |
+                                           (1 << STRIPE_DEGRADED)),
+                             head_sh->state & (1 << STRIPE_INSYNC));
+
                sh->check_state = head_sh->check_state;
                sh->reconstruct_state = head_sh->reconstruct_state;
-               for (i = 0; i < sh->disks; i++)
+               for (i = 0; i < sh->disks; i++) {
+                       if (test_and_clear_bit(R5_Overlap, &sh->dev[i].flags))
+                               do_wakeup = 1;
                        sh->dev[i].flags = head_sh->dev[i].flags &
                                (~((1 << R5_WriteError) | (1 << R5_Overlap)));
-
+               }
                spin_lock_irq(&sh->stripe_lock);
                sh->batch_head = NULL;
                spin_unlock_irq(&sh->stripe_lock);
-
-               set_bit(STRIPE_HANDLE, &sh->state);
+               if (handle_flags == 0 ||
+                   sh->state & handle_flags)
+                       set_bit(STRIPE_HANDLE, &sh->state);
                release_stripe(sh);
-
-               sh = next;
        }
+       spin_lock_irq(&head_sh->stripe_lock);
+       head_sh->batch_head = NULL;
+       spin_unlock_irq(&head_sh->stripe_lock);
+       for (i = 0; i < head_sh->disks; i++)
+               if (test_and_clear_bit(R5_Overlap, &head_sh->dev[i].flags))
+                       do_wakeup = 1;
+       if (head_sh->state & handle_flags)
+               set_bit(STRIPE_HANDLE, &head_sh->state);
+
+       if (do_wakeup)
+               wake_up(&head_sh->raid_conf->wait_for_overlap);
 }
 
 static void handle_stripe(struct stripe_head *sh)
@@ -4253,7 +4282,8 @@ static void handle_stripe(struct stripe_head *sh)
                return;
        }
 
-       check_break_stripe_batch_list(sh);
+       if (test_and_clear_bit(STRIPE_BATCH_ERR, &sh->state))
+               break_stripe_batch_list(sh, 0);
 
        if (test_bit(STRIPE_SYNC_REQUESTED, &sh->state) && !sh->batch_head) {
                spin_lock(&sh->stripe_lock);
@@ -4307,6 +4337,7 @@ static void handle_stripe(struct stripe_head *sh)
        if (s.failed > conf->max_degraded) {
                sh->check_state = 0;
                sh->reconstruct_state = 0;
+               break_stripe_batch_list(sh, 0);
                if (s.to_read+s.to_write+s.written)
                        handle_failed_stripe(conf, sh, &s, disks, &s.return_bi);
                if (s.syncing + s.replacing)
@@ -6221,8 +6252,11 @@ static int alloc_scratch_buffer(struct r5conf *conf, struct raid5_percpu *percpu
                percpu->spare_page = alloc_page(GFP_KERNEL);
        if (!percpu->scribble)
                percpu->scribble = scribble_alloc(max(conf->raid_disks,
-                       conf->previous_raid_disks), conf->chunk_sectors /
-                       STRIPE_SECTORS, GFP_KERNEL);
+                                                     conf->previous_raid_disks),
+                                                 max(conf->chunk_sectors,
+                                                     conf->prev_chunk_sectors)
+                                                  / STRIPE_SECTORS,
+                                                 GFP_KERNEL);
 
        if (!percpu->scribble || (conf->level == 6 && !percpu->spare_page)) {
                free_scratch_buffer(conf, percpu);
@@ -7198,6 +7232,15 @@ static int check_reshape(struct mddev *mddev)
        if (!check_stripe_cache(mddev))
                return -ENOSPC;
 
+       if (mddev->new_chunk_sectors > mddev->chunk_sectors ||
+           mddev->delta_disks > 0)
+               if (resize_chunks(conf,
+                                 conf->previous_raid_disks
+                                 + max(0, mddev->delta_disks),
+                                 max(mddev->new_chunk_sectors,
+                                     mddev->chunk_sectors)
+                           ) < 0)
+                       return -ENOMEM;
        return resize_stripes(conf, (conf->previous_raid_disks
                                     + mddev->delta_disks));
 }
@@ -7311,6 +7354,7 @@ static int raid5_start_reshape(struct mddev *mddev)
 
        clear_bit(MD_RECOVERY_SYNC, &mddev->recovery);
        clear_bit(MD_RECOVERY_CHECK, &mddev->recovery);
+       clear_bit(MD_RECOVERY_DONE, &mddev->recovery);
        set_bit(MD_RECOVERY_RESHAPE, &mddev->recovery);
        set_bit(MD_RECOVERY_RUNNING, &mddev->recovery);
        mddev->sync_thread = md_register_thread(md_do_sync, mddev,
index 7dc0dd86074b1702276ccb51ba166a38d5d0f7e3..896d603ad0da964d2c45f22039d8b733f0bef26e 100644 (file)
@@ -337,9 +337,12 @@ enum {
        STRIPE_ON_RELEASE_LIST,
        STRIPE_BATCH_READY,
        STRIPE_BATCH_ERR,
+       STRIPE_BITMAP_PENDING,  /* Being added to bitmap, don't add
+                                * to batch yet.
+                                */
 };
 
-#define STRIPE_EXPAND_SYNC_FLAG \
+#define STRIPE_EXPAND_SYNC_FLAGS \
        ((1 << STRIPE_EXPAND_SOURCE) |\
        (1 << STRIPE_EXPAND_READY) |\
        (1 << STRIPE_EXPANDING) |\
index 9c64b5d01c6ad7b85e8020f87046ddf51af83fe5..110fd70c73269dbbf5cdbdfb6461fe26eb511b1e 100644 (file)
@@ -116,8 +116,8 @@ static struct mcam_format_struct {
                .planar         = false,
        },
        {
-               .desc           = "UYVY 4:2:2",
-               .pixelformat    = V4L2_PIX_FMT_UYVY,
+               .desc           = "YVYU 4:2:2",
+               .pixelformat    = V4L2_PIX_FMT_YVYU,
                .mbus_code      = MEDIA_BUS_FMT_YUYV8_2X8,
                .bpp            = 2,
                .planar         = false,
@@ -748,7 +748,7 @@ static void mcam_ctlr_image(struct mcam_camera *cam)
 
        switch (fmt->pixelformat) {
        case V4L2_PIX_FMT_YUYV:
-       case V4L2_PIX_FMT_UYVY:
+       case V4L2_PIX_FMT_YVYU:
                widthy = fmt->width * 2;
                widthuv = 0;
                break;
@@ -784,15 +784,15 @@ static void mcam_ctlr_image(struct mcam_camera *cam)
        case V4L2_PIX_FMT_YUV420:
        case V4L2_PIX_FMT_YVU420:
                mcam_reg_write_mask(cam, REG_CTRL0,
-                       C0_DF_YUV | C0_YUV_420PL | C0_YUVE_YVYU, C0_DF_MASK);
+                       C0_DF_YUV | C0_YUV_420PL | C0_YUVE_VYUY, C0_DF_MASK);
                break;
        case V4L2_PIX_FMT_YUYV:
                mcam_reg_write_mask(cam, REG_CTRL0,
-                       C0_DF_YUV | C0_YUV_PACKED | C0_YUVE_UYVY, C0_DF_MASK);
+                       C0_DF_YUV | C0_YUV_PACKED | C0_YUVE_NOSWAP, C0_DF_MASK);
                break;
-       case V4L2_PIX_FMT_UYVY:
+       case V4L2_PIX_FMT_YVYU:
                mcam_reg_write_mask(cam, REG_CTRL0,
-                       C0_DF_YUV | C0_YUV_PACKED | C0_YUVE_YUYV, C0_DF_MASK);
+                       C0_DF_YUV | C0_YUV_PACKED | C0_YUVE_SWAP24, C0_DF_MASK);
                break;
        case V4L2_PIX_FMT_JPEG:
                mcam_reg_write_mask(cam, REG_CTRL0,
index aa0c6eac254a4cd5813dd660d279334202e9e747..7ffdf4dbaf8cc2de76dee0bdd6044d53bcecc11b 100644 (file)
@@ -330,10 +330,10 @@ int mccic_resume(struct mcam_camera *cam);
 #define          C0_YUVE_YVYU    0x00010000    /* Y1CrY0Cb             */
 #define          C0_YUVE_VYUY    0x00020000    /* CrY1CbY0             */
 #define          C0_YUVE_UYVY    0x00030000    /* CbY1CrY0             */
-#define          C0_YUVE_XYUV    0x00000000    /* 420: .YUV            */
-#define          C0_YUVE_XYVU    0x00010000    /* 420: .YVU            */
-#define          C0_YUVE_XUVY    0x00020000    /* 420: .UVY            */
-#define          C0_YUVE_XVUY    0x00030000    /* 420: .VUY            */
+#define          C0_YUVE_NOSWAP  0x00000000    /* no bytes swapping    */
+#define          C0_YUVE_SWAP13  0x00010000    /* swap byte 1 and 3    */
+#define          C0_YUVE_SWAP24  0x00020000    /* swap byte 2 and 4    */
+#define          C0_YUVE_SWAP1324 0x00030000   /* swap bytes 1&3 and 2&4 */
 /* Bayer bits 18,19 if needed */
 #define          C0_EOF_VSYNC    0x00400000    /* Generate EOF by VSYNC */
 #define          C0_VEDGE_CTRL   0x00800000    /* Detect falling edge of VSYNC */
index 9351f64dee7b4fcfb3e03368022eade6dea8f73e..6460f8e1b07fc6e41e4e31b90338fb7fa73ab48f 100644 (file)
 #define VIN_MAX_WIDTH          2048
 #define VIN_MAX_HEIGHT         2048
 
+#define TIMEOUT_MS             100
+
 enum chip_id {
        RCAR_GEN2,
        RCAR_H1,
@@ -820,7 +822,10 @@ static void rcar_vin_wait_stop_streaming(struct rcar_vin_priv *priv)
                if (priv->state == STOPPING) {
                        priv->request_to_stop = true;
                        spin_unlock_irq(&priv->lock);
-                       wait_for_completion(&priv->capture_stop);
+                       if (!wait_for_completion_timeout(
+                                       &priv->capture_stop,
+                                       msecs_to_jiffies(TIMEOUT_MS)))
+                               priv->state = STOPPED;
                        spin_lock_irq(&priv->lock);
                }
        }
index ae498b53ee4042ef3e39e6f77a7272cffe4abe74..46e3840c7a37392402deb53a7a9eb2cb7b8b27b6 100644 (file)
@@ -431,6 +431,10 @@ int da9052_adc_read_temp(struct da9052 *da9052)
 EXPORT_SYMBOL_GPL(da9052_adc_read_temp);
 
 static const struct mfd_cell da9052_subdev_info[] = {
+       {
+               .name = "da9052-regulator",
+               .id = 0,
+       },
        {
                .name = "da9052-regulator",
                .id = 1,
@@ -483,10 +487,6 @@ static const struct mfd_cell da9052_subdev_info[] = {
                .name = "da9052-regulator",
                .id = 13,
        },
-       {
-               .name = "da9052-regulator",
-               .id = 14,
-       },
        {
                .name = "da9052-onkey",
        },
index 2c25271f8c417e21982e43b2d163e65556e6aca1..60f7141a6b02e66c23b59404ea59ba7d716c057f 100644 (file)
@@ -1029,6 +1029,18 @@ static inline void mmc_blk_reset_success(struct mmc_blk_data *md, int type)
        md->reset_done &= ~type;
 }
 
+int mmc_access_rpmb(struct mmc_queue *mq)
+{
+       struct mmc_blk_data *md = mq->data;
+       /*
+        * If this is a RPMB partition access, return ture
+        */
+       if (md && md->part_type == EXT_CSD_PART_CONFIG_ACC_RPMB)
+               return true;
+
+       return false;
+}
+
 static int mmc_blk_issue_discard_rq(struct mmc_queue *mq, struct request *req)
 {
        struct mmc_blk_data *md = mq->data;
index 236d194c28835e87adb9bc108c55f5e122353c68..8efa3684aef849174ccef4053e049e3c95d8646f 100644 (file)
@@ -38,7 +38,7 @@ static int mmc_prep_request(struct request_queue *q, struct request *req)
                return BLKPREP_KILL;
        }
 
-       if (mq && mmc_card_removed(mq->card))
+       if (mq && (mmc_card_removed(mq->card) || mmc_access_rpmb(mq)))
                return BLKPREP_KILL;
 
        req->cmd_flags |= REQ_DONTPREP;
index 5752d50049a34c2a9ee8f6585105990f1e018d05..99e6521e61696202c036dfb00fe6bdcd96c0f613 100644 (file)
@@ -73,4 +73,6 @@ extern void mmc_queue_bounce_post(struct mmc_queue_req *);
 extern int mmc_packed_init(struct mmc_queue *, struct mmc_card *);
 extern void mmc_packed_clean(struct mmc_queue *);
 
+extern int mmc_access_rpmb(struct mmc_queue *);
+
 #endif
index c296bc098fe23684f4be66195b2342d7cd0159ef..92e7671426ebc214ce2d1ff2c35df50e68f02ee0 100644 (file)
@@ -2651,6 +2651,7 @@ int mmc_pm_notify(struct notifier_block *notify_block,
        switch (mode) {
        case PM_HIBERNATION_PREPARE:
        case PM_SUSPEND_PREPARE:
+       case PM_RESTORE_PREPARE:
                spin_lock_irqsave(&host->lock, flags);
                host->rescan_disable = 1;
                spin_unlock_irqrestore(&host->lock, flags);
index 03d7c7521d9712e051cd83579ef26d1938368469..9a39e0b7e583625e7fa8a3f24dab0179e3da880a 100644 (file)
@@ -1304,7 +1304,7 @@ static void atmci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
 
        if (ios->clock) {
                unsigned int clock_min = ~0U;
-               u32 clkdiv;
+               int clkdiv;
 
                spin_lock_bh(&host->lock);
                if (!host->mode_reg) {
@@ -1328,7 +1328,12 @@ static void atmci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
                /* Calculate clock divider */
                if (host->caps.has_odd_clk_div) {
                        clkdiv = DIV_ROUND_UP(host->bus_hz, clock_min) - 2;
-                       if (clkdiv > 511) {
+                       if (clkdiv < 0) {
+                               dev_warn(&mmc->class_dev,
+                                        "clock %u too fast; using %lu\n",
+                                        clock_min, host->bus_hz / 2);
+                               clkdiv = 0;
+                       } else if (clkdiv > 511) {
                                dev_warn(&mmc->class_dev,
                                         "clock %u too slow; using %lu\n",
                                         clock_min, host->bus_hz / (511 + 2));
index 38b29265cc7c7625484db40b4d38f2148a2c1aa6..5f5adafb253afec16429c3bb357e15be8d07bbb7 100644 (file)
@@ -589,9 +589,11 @@ static int dw_mci_idmac_init(struct dw_mci *host)
                host->ring_size = PAGE_SIZE / sizeof(struct idmac_desc);
 
                /* Forward link the descriptor list */
-               for (i = 0, p = host->sg_cpu; i < host->ring_size - 1; i++, p++)
+               for (i = 0, p = host->sg_cpu; i < host->ring_size - 1; i++, p++) {
                        p->des3 = cpu_to_le32(host->sg_dma +
                                        (sizeof(struct idmac_desc) * (i + 1)));
+                       p->des1 = 0;
+               }
 
                /* Set the last descriptor as the end-of-ring descriptor */
                p->des3 = cpu_to_le32(host->sg_dma);
@@ -1300,7 +1302,8 @@ static int dw_mci_get_cd(struct mmc_host *mmc)
        int gpio_cd = mmc_gpio_get_cd(mmc);
 
        /* Use platform get_cd function, else try onboard card detect */
-       if (brd->quirks & DW_MCI_QUIRK_BROKEN_CARD_DETECTION)
+       if ((brd->quirks & DW_MCI_QUIRK_BROKEN_CARD_DETECTION) ||
+           (mmc->caps & MMC_CAP_NONREMOVABLE))
                present = 1;
        else if (!IS_ERR_VALUE(gpio_cd))
                present = gpio_cd;
index 2b6ef6bd5d5fee1c3277c4970549da294b4706da..7eff087cf515edfd1e4d51a68989197d82749744 100644 (file)
@@ -1408,7 +1408,7 @@ static int sh_mmcif_probe(struct platform_device *pdev)
        host            = mmc_priv(mmc);
        host->mmc       = mmc;
        host->addr      = reg;
-       host->timeout   = msecs_to_jiffies(1000);
+       host->timeout   = msecs_to_jiffies(10000);
        host->ccs_enable = !pd || !pd->ccs_unsupported;
        host->clk_ctrl2_enable = pd && pd->clk_ctrl2_present;
 
index 7c8b1694a134da91cbeb5b4764922c8e7d8d06c2..3af137f49ac9aa49c0c58ad59977b53b9d81f358 100644 (file)
@@ -223,7 +223,7 @@ static int m25p_probe(struct spi_device *spi)
         */
        if (data && data->type)
                flash_name = data->type;
-       else if (!strcmp(spi->modalias, "nor-jedec"))
+       else if (!strcmp(spi->modalias, "spi-nor"))
                flash_name = NULL; /* auto-detect */
        else
                flash_name = spi->modalias;
@@ -255,7 +255,7 @@ static int m25p_remove(struct spi_device *spi)
  * since most of these flash are compatible to some extent, and their
  * differences can often be differentiated by the JEDEC read-ID command, we
  * encourage new users to add support to the spi-nor library, and simply bind
- * against a generic string here (e.g., "nor-jedec").
+ * against a generic string here (e.g., "jedec,spi-nor").
  *
  * Many flash names are kept here in this list (as well as in spi-nor.c) to
  * keep them available as module aliases for existing platforms.
@@ -305,7 +305,7 @@ static const struct spi_device_id m25p_ids[] = {
         * Generic support for SPI NOR that can be identified by the JEDEC READ
         * ID opcode (0x9F). Use this, if possible.
         */
-       {"nor-jedec"},
+       {"spi-nor"},
        { },
 };
 MODULE_DEVICE_TABLE(spi, m25p_ids);
index a3196b750a220663b22f866fbf8173ca6fe81d4a..58df07acdbdb5f4c397511834265c233c3a7f62d 100644 (file)
@@ -191,9 +191,11 @@ static int __init mtd_readtest_init(void)
                                err = ret;
                }
 
-               err = mtdtest_relax();
-               if (err)
+               ret = mtdtest_relax();
+               if (ret) {
+                       err = ret;
                        goto out;
+               }
        }
 
        if (err)
index db2c05b6fe7facc9f07a565d40ad6ee507e3da6e..c9eb78f10a0db829ca396539ccf49331c9f06a1e 100644 (file)
@@ -310,6 +310,8 @@ static void ubiblock_do_work(struct work_struct *work)
        blk_rq_map_sg(req->q, req, pdu->usgl.sg);
 
        ret = ubiblock_read(pdu);
+       rq_flush_dcache_pages(req);
+
        blk_mq_end_request(req, ret);
 }
 
index 78dde56ae6e6fa9dd7d04e64ae1969023d285238..d5fe5d5f490f3efa70e022fdac9b64bd89311e22 100644 (file)
@@ -82,6 +82,8 @@
 #include <net/bond_3ad.h>
 #include <net/bond_alb.h>
 
+#include "bonding_priv.h"
+
 /*---------------------------- Module parameters ----------------------------*/
 
 /* monitor all links that often (in milliseconds). <=0 disables monitoring */
@@ -4542,6 +4544,8 @@ unsigned int bond_get_num_tx_queues(void)
 int bond_create(struct net *net, const char *name)
 {
        struct net_device *bond_dev;
+       struct bonding *bond;
+       struct alb_bond_info *bond_info;
        int res;
 
        rtnl_lock();
@@ -4555,6 +4559,14 @@ int bond_create(struct net *net, const char *name)
                return -ENOMEM;
        }
 
+       /*
+        * Initialize rx_hashtbl_used_head to RLB_NULL_INDEX.
+        * It is set to 0 by default which is wrong.
+        */
+       bond = netdev_priv(bond_dev);
+       bond_info = &(BOND_ALB_INFO(bond));
+       bond_info->rx_hashtbl_used_head = RLB_NULL_INDEX;
+
        dev_net_set(bond_dev, net);
        bond_dev->rtnl_link_ops = &bond_link_ops;
 
index 4df28943d2229035166d2bb4a72ec11c8f9671c5..e8d3c1d35453d1e182cd4b82388978f580abe946 100644 (file)
@@ -624,7 +624,7 @@ int __bond_opt_set(struct bonding *bond,
 out:
        if (ret)
                bond_opt_error_interpret(bond, opt, ret, val);
-       else
+       else if (bond->dev->reg_state == NETREG_REGISTERED)
                call_netdevice_notifiers(NETDEV_CHANGEINFODATA, bond->dev);
 
        return ret;
index 62694cfc05b6548aff5c4f7186021f8c2a4ee570..b20b35acb47d3465063cdde30a1018321b344b56 100644 (file)
@@ -4,6 +4,7 @@
 #include <net/netns/generic.h>
 #include <net/bonding.h>
 
+#include "bonding_priv.h"
 
 static void *bond_info_seq_start(struct seq_file *seq, loff_t *pos)
        __acquires(RCU)
diff --git a/drivers/net/bonding/bonding_priv.h b/drivers/net/bonding/bonding_priv.h
new file mode 100644 (file)
index 0000000..5a4d81a
--- /dev/null
@@ -0,0 +1,25 @@
+/*
+ * Bond several ethernet interfaces into a Cisco, running 'Etherchannel'.
+ *
+ * Portions are (c) Copyright 1995 Simon "Guru Aleph-Null" Janes
+ * NCM: Network and Communications Management, Inc.
+ *
+ * BUT, I'm the one who modified it for ethernet, so:
+ * (c) Copyright 1999, Thomas Davis, tadavis@lbl.gov
+ *
+ *     This software may be used and distributed according to the terms
+ *     of the GNU Public License, incorporated herein by reference.
+ *
+ */
+
+#ifndef _BONDING_PRIV_H
+#define _BONDING_PRIV_H
+
+#define DRV_VERSION    "3.7.1"
+#define DRV_RELDATE    "April 27, 2011"
+#define DRV_NAME       "bonding"
+#define DRV_DESCRIPTION        "Ethernet Channel Bonding Driver"
+
+#define bond_version DRV_DESCRIPTION ": v" DRV_VERSION " (" DRV_RELDATE ")\n"
+
+#endif
index 58808f6514520c869631b356d6476f8cbc060a14..e8c96b8e86f48e66e68b2cd5285c0766865f067e 100644 (file)
@@ -112,7 +112,7 @@ config PCH_CAN
 
 config CAN_GRCAN
        tristate "Aeroflex Gaisler GRCAN and GRHCAN CAN devices"
-       depends on OF
+       depends on OF && HAS_DMA
        ---help---
          Say Y here if you want to use Aeroflex Gaisler GRCAN or GRHCAN.
          Note that the driver supports little endian, even though little
index 4643914859b2c7894f7556cfe023e1903eeb9cc6..8b17a9065b0b193a0c5e5a93048c637f0f7fbad3 100644 (file)
@@ -1102,7 +1102,7 @@ static void kvaser_usb_rx_can_err(const struct kvaser_usb_net_priv *priv,
 
        if (msg->u.rx_can_header.flag & (MSG_FLAG_ERROR_FRAME |
                                         MSG_FLAG_NERR)) {
-               netdev_err(priv->netdev, "Unknow error (flags: 0x%02x)\n",
+               netdev_err(priv->netdev, "Unknown error (flags: 0x%02x)\n",
                           msg->u.rx_can_header.flag);
 
                stats->rx_errors++;
index 6bddfe062b516467b6cc2be75a53c17c2040b2d7..fc55e8e0351dfe5f3ca436d8aed64bf6d660db84 100644 (file)
@@ -509,10 +509,11 @@ static int xcan_rx(struct net_device *ndev)
                        cf->can_id |= CAN_RTR_FLAG;
        }
 
-       if (!(id_xcan & XCAN_IDR_SRR_MASK)) {
-               data[0] = priv->read_reg(priv, XCAN_RXFIFO_DW1_OFFSET);
-               data[1] = priv->read_reg(priv, XCAN_RXFIFO_DW2_OFFSET);
+       /* DW1/DW2 must always be read to remove message from RXFIFO */
+       data[0] = priv->read_reg(priv, XCAN_RXFIFO_DW1_OFFSET);
+       data[1] = priv->read_reg(priv, XCAN_RXFIFO_DW2_OFFSET);
 
+       if (!(cf->can_id & CAN_RTR_FLAG)) {
                /* Change Xilinx CAN data format to socketCAN data format */
                if (cf->can_dlc > 0)
                        *(__be32 *)(cf->data) = cpu_to_be32(data[0]);
index af639ab4c55b64fd886df0413d090afd2fe618ba..cf309aa92802623ec0532b56b1dd10a88a234af1 100644 (file)
@@ -1469,6 +1469,9 @@ static void __exit mv88e6xxx_cleanup(void)
 #if IS_ENABLED(CONFIG_NET_DSA_MV88E6171)
        unregister_switch_driver(&mv88e6171_switch_driver);
 #endif
+#if IS_ENABLED(CONFIG_NET_DSA_MV88E6352)
+       unregister_switch_driver(&mv88e6352_switch_driver);
+#endif
 #if IS_ENABLED(CONFIG_NET_DSA_MV88E6123_61_65)
        unregister_switch_driver(&mv88e6123_61_65_switch_driver);
 #endif
index b36ee9e0d220c0f03e0b62e5fc3a6d9014411fab..d686b9cac29f0b4ac2805455b6ba8f1f99017a74 100644 (file)
@@ -523,7 +523,7 @@ static int etherh_addr(char *addr, struct expansion_card *ec)
        char *s;
        
        if (!ecard_readchunk(&cd, ec, 0xf5, 0)) {
-               printk(KERN_ERR "%s: unable to read podule description string\n",
+               printk(KERN_ERR "%s: unable to read module description string\n",
                       dev_name(&ec->dev));
                goto no_addr;
        }
index eba070f1678265d413b94737db86ae89e57e8e54..89cd11d866420475ae9fd9bc2fa295afa08d4a36 100644 (file)
@@ -58,15 +58,12 @@ struct msgdma_extended_desc {
 /* Tx buffer control flags
  */
 #define MSGDMA_DESC_CTL_TX_FIRST       (MSGDMA_DESC_CTL_GEN_SOP |      \
-                                        MSGDMA_DESC_CTL_TR_ERR_IRQ |   \
                                         MSGDMA_DESC_CTL_GO)
 
-#define MSGDMA_DESC_CTL_TX_MIDDLE      (MSGDMA_DESC_CTL_TR_ERR_IRQ |   \
-                                        MSGDMA_DESC_CTL_GO)
+#define MSGDMA_DESC_CTL_TX_MIDDLE      (MSGDMA_DESC_CTL_GO)
 
 #define MSGDMA_DESC_CTL_TX_LAST                (MSGDMA_DESC_CTL_GEN_EOP |      \
                                         MSGDMA_DESC_CTL_TR_COMP_IRQ |  \
-                                        MSGDMA_DESC_CTL_TR_ERR_IRQ |   \
                                         MSGDMA_DESC_CTL_GO)
 
 #define MSGDMA_DESC_CTL_TX_SINGLE      (MSGDMA_DESC_CTL_GEN_SOP |      \
index 90a76306ad0fafd441376fb524f1e00e1d202163..da48e66377b5ff42dc497a5ac4685ca1e16a1eb9 100644 (file)
@@ -391,6 +391,12 @@ static int tse_rx(struct altera_tse_private *priv, int limit)
                                   "RCV pktstatus %08X pktlength %08X\n",
                                   pktstatus, pktlength);
 
+               /* DMA trasfer from TSE starts with 2 aditional bytes for
+                * IP payload alignment. Status returned by get_rx_status()
+                * contains DMA transfer length. Packet is 2 bytes shorter.
+                */
+               pktlength -= 2;
+
                count++;
                next_entry = (++priv->rx_cons) % priv->rx_ring_size;
 
@@ -777,6 +783,8 @@ static int init_phy(struct net_device *dev)
        struct altera_tse_private *priv = netdev_priv(dev);
        struct phy_device *phydev;
        struct device_node *phynode;
+       bool fixed_link = false;
+       int rc = 0;
 
        /* Avoid init phy in case of no phy present */
        if (!priv->phy_iface)
@@ -789,13 +797,32 @@ static int init_phy(struct net_device *dev)
        phynode = of_parse_phandle(priv->device->of_node, "phy-handle", 0);
 
        if (!phynode) {
-               netdev_dbg(dev, "no phy-handle found\n");
-               if (!priv->mdio) {
-                       netdev_err(dev,
-                                  "No phy-handle nor local mdio specified\n");
-                       return -ENODEV;
+               /* check if a fixed-link is defined in device-tree */
+               if (of_phy_is_fixed_link(priv->device->of_node)) {
+                       rc = of_phy_register_fixed_link(priv->device->of_node);
+                       if (rc < 0) {
+                               netdev_err(dev, "cannot register fixed PHY\n");
+                               return rc;
+                       }
+
+                       /* In the case of a fixed PHY, the DT node associated
+                        * to the PHY is the Ethernet MAC DT node.
+                        */
+                       phynode = of_node_get(priv->device->of_node);
+                       fixed_link = true;
+
+                       netdev_dbg(dev, "fixed-link detected\n");
+                       phydev = of_phy_connect(dev, phynode,
+                                               &altera_tse_adjust_link,
+                                               0, priv->phy_iface);
+               } else {
+                       netdev_dbg(dev, "no phy-handle found\n");
+                       if (!priv->mdio) {
+                               netdev_err(dev, "No phy-handle nor local mdio specified\n");
+                               return -ENODEV;
+                       }
+                       phydev = connect_local_phy(dev);
                }
-               phydev = connect_local_phy(dev);
        } else {
                netdev_dbg(dev, "phy-handle found\n");
                phydev = of_phy_connect(dev, phynode,
@@ -819,10 +846,10 @@ static int init_phy(struct net_device *dev)
        /* Broken HW is sometimes missing the pull-up resistor on the
         * MDIO line, which results in reads to non-existent devices returning
         * 0 rather than 0xffff. Catch this here and treat 0 as a non-existent
-        * device as well.
+        * device as well. If a fixed-link is used the phy_id is always 0.
         * Note: phydev->phy_id is the result of reading the UID PHY registers.
         */
-       if (phydev->phy_id == 0) {
+       if ((phydev->phy_id == 0) && !fixed_link) {
                netdev_err(dev, "Bad PHY UID 0x%08x\n", phydev->phy_id);
                phy_disconnect(phydev);
                return -ENODEV;
index c638c85f3954bc685db3ccd9ac338d1375b8de02..426916036151649ca3a2cef4e69eb00735826c05 100644 (file)
@@ -179,7 +179,8 @@ config SUNLANCE
 
 config AMD_XGBE
        tristate "AMD 10GbE Ethernet driver"
-       depends on (OF_NET || ACPI) && HAS_IOMEM
+       depends on (OF_NET || ACPI) && HAS_IOMEM && HAS_DMA
+       depends on ARM64 || COMPILE_TEST
        select PHYLIB
        select AMD_XGBE_PHY
        select BITREVERSE
index db84ddcfec8464191a3edcccfd87c869ac1c5a7c..9fd6c69a8bac3c77d1c0c6e99eb4f3644561f78a 100644 (file)
@@ -423,7 +423,7 @@ static void xgbe_tx_timer(unsigned long data)
        if (napi_schedule_prep(napi)) {
                /* Disable Tx and Rx interrupts */
                if (pdata->per_channel_irq)
-                       disable_irq(channel->dma_irq);
+                       disable_irq_nosync(channel->dma_irq);
                else
                        xgbe_disable_rx_tx_ints(pdata);
 
index f4054d242f3c7ac6e52437c5cb795cac8e3da2dd..19e38afbc5ee3f5a015fd55ecba813c26a9bca1a 100644 (file)
@@ -1,6 +1,7 @@
 config NET_XGENE
        tristate "APM X-Gene SoC Ethernet Driver"
        depends on HAS_DMA
+       depends on ARCH_XGENE || COMPILE_TEST
        select PHYLIB
        help
          This is the Ethernet driver for the on-chip ethernet interface on the
index 8e262e2b39b63fc5b1e26cca09c66c08b76169c9..dea29ee24da4a28ce1effc2a9c72a77b516021cc 100644 (file)
@@ -25,8 +25,7 @@ config ARC_EMAC_CORE
 config ARC_EMAC
        tristate "ARC EMAC support"
        select ARC_EMAC_CORE
-       depends on OF_IRQ
-       depends on OF_NET
+       depends on OF_IRQ && OF_NET && HAS_DMA
        ---help---
          On some legacy ARC (Synopsys) FPGA boards such as ARCAngel4/ML50x
          non-standard on-chip ethernet device ARC EMAC 10/100 is used.
@@ -35,7 +34,7 @@ config ARC_EMAC
 config EMAC_ROCKCHIP
        tristate "Rockchip EMAC support"
        select ARC_EMAC_CORE
-       depends on OF_IRQ && OF_NET && REGULATOR
+       depends on OF_IRQ && OF_NET && REGULATOR && HAS_DMA
        ---help---
          Support for Rockchip RK3066/RK3188 EMAC ethernet controllers.
          This selects Rockchip SoC glue layer support for the
index 74df16aef7933871fb87c29a511ddc5b19182a01..88a6271de5bc96fde0993f6d9096a7904aa78c7b 100644 (file)
@@ -129,7 +129,7 @@ s32 atl1e_restart_autoneg(struct atl1e_hw *hw);
 #define     TWSI_CTRL_LD_SLV_ADDR_SHIFT     8
 #define     TWSI_CTRL_SW_LDSTART            0x800
 #define     TWSI_CTRL_HW_LDSTART            0x1000
-#define     TWSI_CTRL_SMB_SLV_ADDR_MASK     0x0x7F
+#define     TWSI_CTRL_SMB_SLV_ADDR_MASK     0x7F
 #define     TWSI_CTRL_SMB_SLV_ADDR_SHIFT    15
 #define     TWSI_CTRL_LD_EXIST              0x400000
 #define     TWSI_CTRL_READ_FREQ_SEL_MASK    0x3
index 77363d6805321534a582e579552f46e254737e25..a3b1c07ae0af0935f3026ba8a56e21512e238e36 100644 (file)
@@ -2464,6 +2464,7 @@ err_out_powerdown:
        ssb_bus_may_powerdown(sdev->bus);
 
 err_out_free_dev:
+       netif_napi_del(&bp->napi);
        free_netdev(dev);
 
 out:
@@ -2480,6 +2481,7 @@ static void b44_remove_one(struct ssb_device *sdev)
                b44_unregister_phy_one(bp);
        ssb_device_disable(sdev, 0);
        ssb_bus_may_powerdown(sdev->bus);
+       netif_napi_del(&bp->napi);
        free_netdev(dev);
        ssb_pcihost_set_power_state(sdev, PCI_D3hot);
        ssb_set_drvdata(sdev, NULL);
index 7e3d87a88c76a81e2c36b65559d8b2b0bcf34217..e2c043eabbf39d165644312aba5bbecb4f07fcf8 100644 (file)
@@ -543,7 +543,7 @@ struct bcm_sysport_tx_counters {
        u32     jbr;            /* RO # of xmited jabber count*/
        u32     bytes;          /* RO # of xmited byte count */
        u32     pok;            /* RO # of xmited good pkt */
-       u32     uc;             /* RO (0x0x4f0)# of xmited unitcast pkt */
+       u32     uc;             /* RO (0x4f0) # of xmited unicast pkt */
 };
 
 struct bcm_sysport_mib {
index de77d3a74abc82f0c8b77dff3200799e70634674..21e3c38c7c752dd75674a62aeb8211bc78477808 100644 (file)
@@ -1260,7 +1260,7 @@ static int bgmac_poll(struct napi_struct *napi, int weight)
 
        /* Poll again if more events arrived in the meantime */
        if (bgmac_read(bgmac, BGMAC_INT_STATUS) & (BGMAC_IS_TX0 | BGMAC_IS_RX))
-               return handled;
+               return weight;
 
        if (handled < weight) {
                napi_complete(napi);
index 355d5fea5be9c3847597371fe86092956929bf02..1f82a04ce01a8468e7d8dde208babdea4220ab88 100644 (file)
@@ -521,6 +521,7 @@ struct bnx2x_fp_txdata {
 };
 
 enum bnx2x_tpa_mode_t {
+       TPA_MODE_DISABLED,
        TPA_MODE_LRO,
        TPA_MODE_GRO
 };
@@ -589,7 +590,6 @@ struct bnx2x_fastpath {
 
        /* TPA related */
        struct bnx2x_agg_info   *tpa_info;
-       u8                      disable_tpa;
 #ifdef BNX2X_STOP_ON_ERROR
        u64                     tpa_queue_used;
 #endif
@@ -1545,9 +1545,7 @@ struct bnx2x {
 #define USING_MSIX_FLAG                        (1 << 5)
 #define USING_MSI_FLAG                 (1 << 6)
 #define DISABLE_MSI_FLAG               (1 << 7)
-#define TPA_ENABLE_FLAG                        (1 << 8)
 #define NO_MCP_FLAG                    (1 << 9)
-#define GRO_ENABLE_FLAG                        (1 << 10)
 #define MF_FUNC_DIS                    (1 << 11)
 #define OWN_CNIC_IRQ                   (1 << 12)
 #define NO_ISCSI_OOO_FLAG              (1 << 13)
@@ -1776,7 +1774,7 @@ struct bnx2x {
        int                     stats_state;
 
        /* used for synchronization of concurrent threads statistics handling */
-       struct mutex            stats_lock;
+       struct semaphore        stats_lock;
 
        /* used by dmae command loader */
        struct dmae_command     stats_dmae;
index 2f63467bce465ff9e8a5f50bf04be86b5150d77d..ec56a9b65dc3a313e1b0571e8a58047c161f6507 100644 (file)
@@ -947,10 +947,10 @@ static int bnx2x_rx_int(struct bnx2x_fastpath *fp, int budget)
                        u16 frag_size, pages;
 #ifdef BNX2X_STOP_ON_ERROR
                        /* sanity check */
-                       if (fp->disable_tpa &&
+                       if (fp->mode == TPA_MODE_DISABLED &&
                            (CQE_TYPE_START(cqe_fp_type) ||
                             CQE_TYPE_STOP(cqe_fp_type)))
-                               BNX2X_ERR("START/STOP packet while disable_tpa type %x\n",
+                               BNX2X_ERR("START/STOP packet while TPA disabled, type %x\n",
                                          CQE_TYPE(cqe_fp_type));
 #endif
 
@@ -1396,7 +1396,7 @@ void bnx2x_init_rx_rings(struct bnx2x *bp)
                DP(NETIF_MSG_IFUP,
                   "mtu %d  rx_buf_size %d\n", bp->dev->mtu, fp->rx_buf_size);
 
-               if (!fp->disable_tpa) {
+               if (fp->mode != TPA_MODE_DISABLED) {
                        /* Fill the per-aggregation pool */
                        for (i = 0; i < MAX_AGG_QS(bp); i++) {
                                struct bnx2x_agg_info *tpa_info =
@@ -1410,7 +1410,7 @@ void bnx2x_init_rx_rings(struct bnx2x *bp)
                                        BNX2X_ERR("Failed to allocate TPA skb pool for queue[%d] - disabling TPA on this queue!\n",
                                                  j);
                                        bnx2x_free_tpa_pool(bp, fp, i);
-                                       fp->disable_tpa = 1;
+                                       fp->mode = TPA_MODE_DISABLED;
                                        break;
                                }
                                dma_unmap_addr_set(first_buf, mapping, 0);
@@ -1438,7 +1438,7 @@ void bnx2x_init_rx_rings(struct bnx2x *bp)
                                                                ring_prod);
                                        bnx2x_free_tpa_pool(bp, fp,
                                                            MAX_AGG_QS(bp));
-                                       fp->disable_tpa = 1;
+                                       fp->mode = TPA_MODE_DISABLED;
                                        ring_prod = 0;
                                        break;
                                }
@@ -1560,7 +1560,7 @@ static void bnx2x_free_rx_skbs(struct bnx2x *bp)
 
                bnx2x_free_rx_bds(fp);
 
-               if (!fp->disable_tpa)
+               if (fp->mode != TPA_MODE_DISABLED)
                        bnx2x_free_tpa_pool(bp, fp, MAX_AGG_QS(bp));
        }
 }
@@ -2477,17 +2477,19 @@ static void bnx2x_bz_fp(struct bnx2x *bp, int index)
        /* set the tpa flag for each queue. The tpa flag determines the queue
         * minimal size so it must be set prior to queue memory allocation
         */
-       fp->disable_tpa = !(bp->flags & TPA_ENABLE_FLAG ||
-                                 (bp->flags & GRO_ENABLE_FLAG &&
-                                  bnx2x_mtu_allows_gro(bp->dev->mtu)));
-       if (bp->flags & TPA_ENABLE_FLAG)
+       if (bp->dev->features & NETIF_F_LRO)
                fp->mode = TPA_MODE_LRO;
-       else if (bp->flags & GRO_ENABLE_FLAG)
+       else if (bp->dev->features & NETIF_F_GRO &&
+                bnx2x_mtu_allows_gro(bp->dev->mtu))
                fp->mode = TPA_MODE_GRO;
+       else
+               fp->mode = TPA_MODE_DISABLED;
 
-       /* We don't want TPA on an FCoE L2 ring */
-       if (IS_FCOE_FP(fp))
-               fp->disable_tpa = 1;
+       /* We don't want TPA if it's disabled in bp
+        * or if this is an FCoE L2 ring.
+        */
+       if (bp->disable_tpa || IS_FCOE_FP(fp))
+               fp->mode = TPA_MODE_DISABLED;
 }
 
 int bnx2x_load_cnic(struct bnx2x *bp)
@@ -2608,7 +2610,7 @@ int bnx2x_nic_load(struct bnx2x *bp, int load_mode)
        /*
         * Zero fastpath structures preserving invariants like napi, which are
         * allocated only once, fp index, max_cos, bp pointer.
-        * Also set fp->disable_tpa and txdata_ptr.
+        * Also set fp->mode and txdata_ptr.
         */
        DP(NETIF_MSG_IFUP, "num queues: %d", bp->num_queues);
        for_each_queue(bp, i)
@@ -3247,7 +3249,7 @@ int bnx2x_low_latency_recv(struct napi_struct *napi)
 
        if ((bp->state == BNX2X_STATE_CLOSED) ||
            (bp->state == BNX2X_STATE_ERROR) ||
-           (bp->flags & (TPA_ENABLE_FLAG | GRO_ENABLE_FLAG)))
+           (bp->dev->features & (NETIF_F_LRO | NETIF_F_GRO)))
                return LL_FLUSH_FAILED;
 
        if (!bnx2x_fp_lock_poll(fp))
@@ -4543,7 +4545,7 @@ alloc_mem_err:
         * In these cases we disable the queue
         * Min size is different for OOO, TPA and non-TPA queues
         */
-       if (ring_size < (fp->disable_tpa ?
+       if (ring_size < (fp->mode == TPA_MODE_DISABLED ?
                                MIN_RX_SIZE_NONTPA : MIN_RX_SIZE_TPA)) {
                        /* release memory allocated for this queue */
                        bnx2x_free_fp_mem_at(bp, index);
@@ -4784,6 +4786,11 @@ int bnx2x_change_mtu(struct net_device *dev, int new_mtu)
 {
        struct bnx2x *bp = netdev_priv(dev);
 
+       if (pci_num_vf(bp->pdev)) {
+               DP(BNX2X_MSG_IOV, "VFs are enabled, can not change MTU\n");
+               return -EPERM;
+       }
+
        if (bp->recovery_state != BNX2X_RECOVERY_DONE) {
                BNX2X_ERR("Can't perform change MTU during parity recovery\n");
                return -EAGAIN;
@@ -4809,66 +4816,71 @@ netdev_features_t bnx2x_fix_features(struct net_device *dev,
 {
        struct bnx2x *bp = netdev_priv(dev);
 
+       if (pci_num_vf(bp->pdev)) {
+               netdev_features_t changed = dev->features ^ features;
+
+               /* Revert the requested changes in features if they
+                * would require internal reload of PF in bnx2x_set_features().
+                */
+               if (!(features & NETIF_F_RXCSUM) && !bp->disable_tpa) {
+                       features &= ~NETIF_F_RXCSUM;
+                       features |= dev->features & NETIF_F_RXCSUM;
+               }
+
+               if (changed & NETIF_F_LOOPBACK) {
+                       features &= ~NETIF_F_LOOPBACK;
+                       features |= dev->features & NETIF_F_LOOPBACK;
+               }
+       }
+
        /* TPA requires Rx CSUM offloading */
        if (!(features & NETIF_F_RXCSUM)) {
                features &= ~NETIF_F_LRO;
                features &= ~NETIF_F_GRO;
        }
 
-       /* Note: do not disable SW GRO in kernel when HW GRO is off */
-       if (bp->disable_tpa)
-               features &= ~NETIF_F_LRO;
-
        return features;
 }
 
 int bnx2x_set_features(struct net_device *dev, netdev_features_t features)
 {
        struct bnx2x *bp = netdev_priv(dev);
-       u32 flags = bp->flags;
-       u32 changes;
+       netdev_features_t changes = features ^ dev->features;
        bool bnx2x_reload = false;
+       int rc;
 
-       if (features & NETIF_F_LRO)
-               flags |= TPA_ENABLE_FLAG;
-       else
-               flags &= ~TPA_ENABLE_FLAG;
-
-       if (features & NETIF_F_GRO)
-               flags |= GRO_ENABLE_FLAG;
-       else
-               flags &= ~GRO_ENABLE_FLAG;
-
-       if (features & NETIF_F_LOOPBACK) {
-               if (bp->link_params.loopback_mode != LOOPBACK_BMAC) {
-                       bp->link_params.loopback_mode = LOOPBACK_BMAC;
-                       bnx2x_reload = true;
-               }
-       } else {
-               if (bp->link_params.loopback_mode != LOOPBACK_NONE) {
-                       bp->link_params.loopback_mode = LOOPBACK_NONE;
-                       bnx2x_reload = true;
+       /* VFs or non SRIOV PFs should be able to change loopback feature */
+       if (!pci_num_vf(bp->pdev)) {
+               if (features & NETIF_F_LOOPBACK) {
+                       if (bp->link_params.loopback_mode != LOOPBACK_BMAC) {
+                               bp->link_params.loopback_mode = LOOPBACK_BMAC;
+                               bnx2x_reload = true;
+                       }
+               } else {
+                       if (bp->link_params.loopback_mode != LOOPBACK_NONE) {
+                               bp->link_params.loopback_mode = LOOPBACK_NONE;
+                               bnx2x_reload = true;
+                       }
                }
        }
 
-       changes = flags ^ bp->flags;
-
        /* if GRO is changed while LRO is enabled, don't force a reload */
-       if ((changes & GRO_ENABLE_FLAG) && (flags & TPA_ENABLE_FLAG))
-               changes &= ~GRO_ENABLE_FLAG;
+       if ((changes & NETIF_F_GRO) && (features & NETIF_F_LRO))
+               changes &= ~NETIF_F_GRO;
 
        /* if GRO is changed while HW TPA is off, don't force a reload */
-       if ((changes & GRO_ENABLE_FLAG) && bp->disable_tpa)
-               changes &= ~GRO_ENABLE_FLAG;
+       if ((changes & NETIF_F_GRO) && bp->disable_tpa)
+               changes &= ~NETIF_F_GRO;
 
        if (changes)
                bnx2x_reload = true;
 
-       bp->flags = flags;
-
        if (bnx2x_reload) {
-               if (bp->recovery_state == BNX2X_RECOVERY_DONE)
-                       return bnx2x_reload_if_running(dev);
+               if (bp->recovery_state == BNX2X_RECOVERY_DONE) {
+                       dev->features = features;
+                       rc = bnx2x_reload_if_running(dev);
+                       return rc ? rc : 1;
+               }
                /* else: bnx2x_nic_load() will be called at end of recovery */
        }
 
index adcacda7af7b10e70b053821acc1e2dfe722732a..d7a71758e87615de36fe06664a914291bdb3cfa3 100644 (file)
@@ -969,7 +969,7 @@ static inline void bnx2x_free_rx_sge_range(struct bnx2x *bp,
 {
        int i;
 
-       if (fp->disable_tpa)
+       if (fp->mode == TPA_MODE_DISABLED)
                return;
 
        for (i = 0; i < last; i++)
index e3d853cab7c9644c241cd42ba1a2844b82e55176..48ed005ba73fd3a9d9aa550871b647fdd0b59350 100644 (file)
@@ -1843,6 +1843,12 @@ static int bnx2x_set_ringparam(struct net_device *dev,
           "set ring params command parameters: rx_pending = %d, tx_pending = %d\n",
           ering->rx_pending, ering->tx_pending);
 
+       if (pci_num_vf(bp->pdev)) {
+               DP(BNX2X_MSG_IOV,
+                  "VFs are enabled, can not change ring parameters\n");
+               return -EPERM;
+       }
+
        if (bp->recovery_state != BNX2X_RECOVERY_DONE) {
                DP(BNX2X_MSG_ETHTOOL,
                   "Handling parity error recovery. Try again later\n");
@@ -2899,6 +2905,12 @@ static void bnx2x_self_test(struct net_device *dev,
        u8 is_serdes, link_up;
        int rc, cnt = 0;
 
+       if (pci_num_vf(bp->pdev)) {
+               DP(BNX2X_MSG_IOV,
+                  "VFs are enabled, can not perform self test\n");
+               return;
+       }
+
        if (bp->recovery_state != BNX2X_RECOVERY_DONE) {
                netdev_err(bp->dev,
                           "Handling parity error recovery. Try again later\n");
@@ -3468,6 +3480,11 @@ static int bnx2x_set_channels(struct net_device *dev,
           channels->rx_count, channels->tx_count, channels->other_count,
           channels->combined_count);
 
+       if (pci_num_vf(bp->pdev)) {
+               DP(BNX2X_MSG_IOV, "VFs are enabled, can not set channels\n");
+               return -EPERM;
+       }
+
        /* We don't support separate rx / tx channels.
         * We don't allow setting 'other' channels.
         */
index b9f85fccb419be528ae328efc3af4303f0498103..33501bcddc48eb1f6157a08e3e3d1e08dc087c25 100644 (file)
@@ -3128,7 +3128,7 @@ static unsigned long bnx2x_get_q_flags(struct bnx2x *bp,
                __set_bit(BNX2X_Q_FLG_FORCE_DEFAULT_PRI, &flags);
        }
 
-       if (!fp->disable_tpa) {
+       if (fp->mode != TPA_MODE_DISABLED) {
                __set_bit(BNX2X_Q_FLG_TPA, &flags);
                __set_bit(BNX2X_Q_FLG_TPA_IPV6, &flags);
                if (fp->mode == TPA_MODE_GRO)
@@ -3176,7 +3176,7 @@ static void bnx2x_pf_rx_q_prep(struct bnx2x *bp,
        u16 sge_sz = 0;
        u16 tpa_agg_size = 0;
 
-       if (!fp->disable_tpa) {
+       if (fp->mode != TPA_MODE_DISABLED) {
                pause->sge_th_lo = SGE_TH_LO(bp);
                pause->sge_th_hi = SGE_TH_HI(bp);
 
@@ -3304,7 +3304,7 @@ static void bnx2x_pf_init(struct bnx2x *bp)
        /* This flag is relevant for E1x only.
         * E2 doesn't have a TPA configuration in a function level.
         */
-       flags |= (bp->flags & TPA_ENABLE_FLAG) ? FUNC_FLG_TPA : 0;
+       flags |= (bp->dev->features & NETIF_F_LRO) ? FUNC_FLG_TPA : 0;
 
        func_init.func_flgs = flags;
        func_init.pf_id = BP_FUNC(bp);
@@ -12054,7 +12054,7 @@ static int bnx2x_init_bp(struct bnx2x *bp)
        mutex_init(&bp->port.phy_mutex);
        mutex_init(&bp->fw_mb_mutex);
        mutex_init(&bp->drv_info_mutex);
-       mutex_init(&bp->stats_lock);
+       sema_init(&bp->stats_lock, 1);
        bp->drv_info_mng_owner = false;
 
        INIT_DELAYED_WORK(&bp->sp_task, bnx2x_sp_task);
@@ -12107,11 +12107,8 @@ static int bnx2x_init_bp(struct bnx2x *bp)
 
        /* Set TPA flags */
        if (bp->disable_tpa) {
-               bp->flags &= ~(TPA_ENABLE_FLAG | GRO_ENABLE_FLAG);
+               bp->dev->hw_features &= ~NETIF_F_LRO;
                bp->dev->features &= ~NETIF_F_LRO;
-       } else {
-               bp->flags |= (TPA_ENABLE_FLAG | GRO_ENABLE_FLAG);
-               bp->dev->features |= NETIF_F_LRO;
        }
 
        if (CHIP_IS_E1(bp))
@@ -13371,6 +13368,17 @@ static int bnx2x_init_one(struct pci_dev *pdev,
        bool is_vf;
        int cnic_cnt;
 
+       /* Management FW 'remembers' living interfaces. Allow it some time
+        * to forget previously living interfaces, allowing a proper re-load.
+        */
+       if (is_kdump_kernel()) {
+               ktime_t now = ktime_get_boottime();
+               ktime_t fw_ready_time = ktime_set(5, 0);
+
+               if (ktime_before(now, fw_ready_time))
+                       msleep(ktime_ms_delta(fw_ready_time, now));
+       }
+
        /* An estimated maximum supported CoS number according to the chip
         * version.
         * We will try to roughly estimate the maximum number of CoSes this chip
@@ -13682,9 +13690,10 @@ static int bnx2x_eeh_nic_unload(struct bnx2x *bp)
        cancel_delayed_work_sync(&bp->sp_task);
        cancel_delayed_work_sync(&bp->period_task);
 
-       mutex_lock(&bp->stats_lock);
-       bp->stats_state = STATS_STATE_DISABLED;
-       mutex_unlock(&bp->stats_lock);
+       if (!down_timeout(&bp->stats_lock, HZ / 10)) {
+               bp->stats_state = STATS_STATE_DISABLED;
+               up(&bp->stats_lock);
+       }
 
        bnx2x_save_statistics(bp);
 
index 266b055c2360af759c7f78395636d541210e5b9d..69d699f0730a3bd4d8980607e0a36cd8da461f1e 100644 (file)
@@ -1372,19 +1372,23 @@ void bnx2x_stats_handle(struct bnx2x *bp, enum bnx2x_stats_event event)
         * that context in case someone is in the middle of a transition.
         * For other events, wait a bit until lock is taken.
         */
-       if (!mutex_trylock(&bp->stats_lock)) {
+       if (down_trylock(&bp->stats_lock)) {
                if (event == STATS_EVENT_UPDATE)
                        return;
 
                DP(BNX2X_MSG_STATS,
                   "Unlikely stats' lock contention [event %d]\n", event);
-               mutex_lock(&bp->stats_lock);
+               if (unlikely(down_timeout(&bp->stats_lock, HZ / 10))) {
+                       BNX2X_ERR("Failed to take stats lock [event %d]\n",
+                                 event);
+                       return;
+               }
        }
 
        bnx2x_stats_stm[state][event].action(bp);
        bp->stats_state = bnx2x_stats_stm[state][event].next_state;
 
-       mutex_unlock(&bp->stats_lock);
+       up(&bp->stats_lock);
 
        if ((event != STATS_EVENT_UPDATE) || netif_msg_timer(bp))
                DP(BNX2X_MSG_STATS, "state %d -> event %d -> state %d\n",
@@ -1970,7 +1974,11 @@ int bnx2x_stats_safe_exec(struct bnx2x *bp,
        /* Wait for statistics to end [while blocking further requests],
         * then run supplied function 'safely'.
         */
-       mutex_lock(&bp->stats_lock);
+       rc = down_timeout(&bp->stats_lock, HZ / 10);
+       if (unlikely(rc)) {
+               BNX2X_ERR("Failed to take statistics lock for safe execution\n");
+               goto out_no_lock;
+       }
 
        bnx2x_stats_comp(bp);
        while (bp->stats_pending && cnt--)
@@ -1988,7 +1996,7 @@ out:
        /* No need to restart statistics - if they're enabled, the timer
         * will restart the statistics.
         */
-       mutex_unlock(&bp->stats_lock);
-
+       up(&bp->stats_lock);
+out_no_lock:
        return rc;
 }
index 15b2d164756058c6c5fb154bdc128f52aa3148c3..06b8c0d8fd3b12ab4e864c8c0971cc52380c007c 100644 (file)
@@ -594,7 +594,7 @@ int bnx2x_vfpf_setup_q(struct bnx2x *bp, struct bnx2x_fastpath *fp,
        bnx2x_vfpf_prep(bp, &req->first_tlv, CHANNEL_TLV_SETUP_Q, sizeof(*req));
 
        /* select tpa mode to request */
-       if (!fp->disable_tpa) {
+       if (fp->mode != TPA_MODE_DISABLED) {
                flags |= VFPF_QUEUE_FLG_TPA;
                flags |= VFPF_QUEUE_FLG_TPA_IPV6;
                if (fp->mode == TPA_MODE_GRO)
index e7651b3c6c5767f7609115ef0430c13aac8d17a9..420949cc55aab6349b75c33f0c4f061aa384d537 100644 (file)
@@ -299,9 +299,6 @@ int bcmgenet_mii_config(struct net_device *dev, bool init)
                        phy_name = "external RGMII (no delay)";
                else
                        phy_name = "external RGMII (TX delay)";
-               reg = bcmgenet_ext_readl(priv, EXT_RGMII_OOB_CTRL);
-               reg |= RGMII_MODE_EN | id_mode_dis;
-               bcmgenet_ext_writel(priv, reg, EXT_RGMII_OOB_CTRL);
                bcmgenet_sys_writel(priv,
                                    PORT_MODE_EXT_GPHY, SYS_PORT_CTRL);
                break;
@@ -310,6 +307,15 @@ int bcmgenet_mii_config(struct net_device *dev, bool init)
                return -EINVAL;
        }
 
+       /* This is an external PHY (xMII), so we need to enable the RGMII
+        * block for the interface to work
+        */
+       if (priv->ext_phy) {
+               reg = bcmgenet_ext_readl(priv, EXT_RGMII_OOB_CTRL);
+               reg |= RGMII_MODE_EN | id_mode_dis;
+               bcmgenet_ext_writel(priv, reg, EXT_RGMII_OOB_CTRL);
+       }
+
        if (init)
                dev_info(kdev, "configuring instance for %s\n", phy_name);
 
index 1270b189a9a2ffd7776985f8e0a96fada80f8de8..069952fa5d644b62b7d1a04fdb8b615a4ed3d69a 100644 (file)
@@ -18129,7 +18129,9 @@ static pci_ers_result_t tg3_io_error_detected(struct pci_dev *pdev,
 
        rtnl_lock();
 
-       tp->pcierr_recovery = true;
+       /* We needn't recover from permanent error */
+       if (state == pci_channel_io_frozen)
+               tp->pcierr_recovery = true;
 
        /* We probably don't have netdev yet */
        if (!netdev || !netif_running(netdev))
index 594a2ab36d3175de2633490eec1e0395dbb74e59..68f3c13c9ef6d992ac7eadde882c16b51375d6e8 100644 (file)
@@ -2414,7 +2414,7 @@ bfa_ioc_boot(struct bfa_ioc *ioc, enum bfi_fwboot_type boot_type,
        if (status == BFA_STATUS_OK)
                bfa_ioc_lpu_start(ioc);
        else
-               bfa_nw_iocpf_timeout(ioc);
+               bfa_fsm_send_event(&ioc->iocpf, IOCPF_E_TIMEOUT);
 
        return status;
 }
@@ -3029,7 +3029,7 @@ bfa_ioc_poll_fwinit(struct bfa_ioc *ioc)
        }
 
        if (ioc->iocpf.poll_time >= BFA_IOC_TOV) {
-               bfa_nw_iocpf_timeout(ioc);
+               bfa_fsm_send_event(&ioc->iocpf, IOCPF_E_TIMEOUT);
        } else {
                ioc->iocpf.poll_time += BFA_IOC_POLL_TOV;
                mod_timer(&ioc->iocpf_timer, jiffies +
index 37072a83f9d6d0afb29de683051e13af94a78fd8..caae6cb2bc1a4528f4d97bd8e1e11adf074bc81e 100644 (file)
@@ -3701,10 +3701,6 @@ bnad_pci_probe(struct pci_dev *pdev,
        setup_timer(&bnad->bna.ioceth.ioc.sem_timer, bnad_iocpf_sem_timeout,
                                ((unsigned long)bnad));
 
-       /* Now start the timer before calling IOC */
-       mod_timer(&bnad->bna.ioceth.ioc.iocpf_timer,
-                 jiffies + msecs_to_jiffies(BNA_IOC_TIMER_FREQ));
-
        /*
         * Start the chip
         * If the call back comes with error, we bail out.
index ebf462d8082f79373c1ea234e4f3034a16c53e73..badea368bdc89621927101dc0a79504765b87248 100644 (file)
@@ -30,6 +30,7 @@ cna_read_firmware(struct pci_dev *pdev, u32 **bfi_image,
                        u32 *bfi_image_size, char *fw_name)
 {
        const struct firmware *fw;
+       u32 n;
 
        if (request_firmware(&fw, fw_name, &pdev->dev)) {
                pr_alert("Can't locate firmware %s\n", fw_name);
@@ -40,6 +41,12 @@ cna_read_firmware(struct pci_dev *pdev, u32 **bfi_image,
        *bfi_image_size = fw->size/sizeof(u32);
        bfi_fw = fw;
 
+       /* Convert loaded firmware to host order as it is stored in file
+        * as sequence of LE32 integers.
+        */
+       for (n = 0; n < *bfi_image_size; n++)
+               le32_to_cpus(*bfi_image + n);
+
        return *bfi_image;
 error:
        return NULL;
index 9f5387249f242374437581e6c2df7c037917f83a..fc646a41d5481406400bb4013ced8f96cf236092 100644 (file)
@@ -350,6 +350,9 @@ static int macb_mii_probe(struct net_device *dev)
        else
                phydev->supported &= PHY_BASIC_FEATURES;
 
+       if (bp->caps & MACB_CAPS_NO_GIGABIT_HALF)
+               phydev->supported &= ~SUPPORTED_1000baseT_Half;
+
        phydev->advertising = phydev->supported;
 
        bp->link = 0;
@@ -707,6 +710,9 @@ static void gem_rx_refill(struct macb *bp)
 
                        /* properly align Ethernet header */
                        skb_reserve(skb, NET_IP_ALIGN);
+               } else {
+                       bp->rx_ring[entry].addr &= ~MACB_BIT(RX_USED);
+                       bp->rx_ring[entry].ctrl = 0;
                }
        }
 
@@ -978,7 +984,7 @@ static irqreturn_t macb_interrupt(int irq, void *dev_id)
        struct macb_queue *queue = dev_id;
        struct macb *bp = queue->bp;
        struct net_device *dev = bp->dev;
-       u32 status;
+       u32 status, ctrl;
 
        status = queue_readl(queue, ISR);
 
@@ -1034,6 +1040,21 @@ static irqreturn_t macb_interrupt(int irq, void *dev_id)
                 * add that if/when we get our hands on a full-blown MII PHY.
                 */
 
+               /* There is a hardware issue under heavy load where DMA can
+                * stop, this causes endless "used buffer descriptor read"
+                * interrupts but it can be cleared by re-enabling RX. See
+                * the at91 manual, section 41.3.1 or the Zynq manual
+                * section 16.7.4 for details.
+                */
+               if (status & MACB_BIT(RXUBR)) {
+                       ctrl = macb_readl(bp, NCR);
+                       macb_writel(bp, NCR, ctrl & ~MACB_BIT(RE));
+                       macb_writel(bp, NCR, ctrl | MACB_BIT(RE));
+
+                       if (bp->caps & MACB_CAPS_ISR_CLEAR_ON_WRITE)
+                               macb_writel(bp, ISR, MACB_BIT(RXUBR));
+               }
+
                if (status & MACB_BIT(ISR_ROVR)) {
                        /* We missed at least one packet */
                        if (macb_is_gem(bp))
@@ -1473,9 +1494,9 @@ static void macb_init_rings(struct macb *bp)
        for (i = 0; i < TX_RING_SIZE; i++) {
                bp->queues[0].tx_ring[i].addr = 0;
                bp->queues[0].tx_ring[i].ctrl = MACB_BIT(TX_USED);
-               bp->queues[0].tx_head = 0;
-               bp->queues[0].tx_tail = 0;
        }
+       bp->queues[0].tx_head = 0;
+       bp->queues[0].tx_tail = 0;
        bp->queues[0].tx_ring[TX_RING_SIZE - 1].ctrl |= MACB_BIT(TX_WRAP);
 
        bp->rx_tail = 0;
@@ -2681,6 +2702,14 @@ static const struct macb_config emac_config = {
        .init = at91ether_init,
 };
 
+static const struct macb_config zynq_config = {
+       .caps = MACB_CAPS_SG_DISABLED | MACB_CAPS_GIGABIT_MODE_AVAILABLE |
+               MACB_CAPS_NO_GIGABIT_HALF,
+       .dma_burst_length = 16,
+       .clk_init = macb_clk_init,
+       .init = macb_init,
+};
+
 static const struct of_device_id macb_dt_ids[] = {
        { .compatible = "cdns,at32ap7000-macb" },
        { .compatible = "cdns,at91sam9260-macb", .data = &at91sam9260_config },
@@ -2691,6 +2720,7 @@ static const struct of_device_id macb_dt_ids[] = {
        { .compatible = "atmel,sama5d4-gem", .data = &sama5d4_config },
        { .compatible = "cdns,at91rm9200-emac", .data = &emac_config },
        { .compatible = "cdns,emac", .data = &emac_config },
+       { .compatible = "cdns,zynq-gem", .data = &zynq_config },
        { /* sentinel */ }
 };
 MODULE_DEVICE_TABLE(of, macb_dt_ids);
index eb7d76f7bf6aaf983e97408ced9b359b54c8ddc3..24b1d9bcd8654d5aba2401b7b6a85b563f09d9cc 100644 (file)
 #define MACB_CAPS_ISR_CLEAR_ON_WRITE           0x00000001
 #define MACB_CAPS_USRIO_HAS_CLKEN              0x00000002
 #define MACB_CAPS_USRIO_DEFAULT_IS_MII         0x00000004
+#define MACB_CAPS_NO_GIGABIT_HALF              0x00000008
 #define MACB_CAPS_FIFO_MODE                    0x10000000
 #define MACB_CAPS_GIGABIT_MODE_AVAILABLE       0x20000000
 #define MACB_CAPS_SG_DISABLED                  0x40000000
index 5959e3ae72da213e11587e8cd27a2bc9759755d0..e8578a742f2a29b14a2eaec01216a8e47a68e12a 100644 (file)
@@ -492,7 +492,7 @@ int t4_memory_rw(struct adapter *adap, int win, int mtype, u32 addr,
                memoffset = (mtype * (edc_size * 1024 * 1024));
        else {
                mc_size = EXT_MEM0_SIZE_G(t4_read_reg(adap,
-                                                     MA_EXT_MEMORY1_BAR_A));
+                                                     MA_EXT_MEMORY0_BAR_A));
                memoffset = (MEM_MC0 * edc_size + mc_size) * 1024 * 1024;
        }
 
index 28d9ca675a274f9876473bcce7e6995a14e1289e..68d47b196daec3d3c5d0b8af19f8d167735e1e79 100644 (file)
@@ -131,8 +131,15 @@ static void enic_get_drvinfo(struct net_device *netdev,
 {
        struct enic *enic = netdev_priv(netdev);
        struct vnic_devcmd_fw_info *fw_info;
+       int err;
 
-       enic_dev_fw_info(enic, &fw_info);
+       err = enic_dev_fw_info(enic, &fw_info);
+       /* return only when pci_zalloc_consistent fails in vnic_dev_fw_info
+        * For other failures, like devcmd failure, we return previously
+        * recorded info.
+        */
+       if (err == -ENOMEM)
+               return;
 
        strlcpy(drvinfo->driver, DRV_NAME, sizeof(drvinfo->driver));
        strlcpy(drvinfo->version, DRV_VERSION, sizeof(drvinfo->version));
@@ -181,8 +188,15 @@ static void enic_get_ethtool_stats(struct net_device *netdev,
        struct enic *enic = netdev_priv(netdev);
        struct vnic_stats *vstats;
        unsigned int i;
-
-       enic_dev_stats_dump(enic, &vstats);
+       int err;
+
+       err = enic_dev_stats_dump(enic, &vstats);
+       /* return only when pci_zalloc_consistent fails in vnic_dev_stats_dump
+        * For other failures, like devcmd failure, we return previously
+        * recorded stats.
+        */
+       if (err == -ENOMEM)
+               return;
 
        for (i = 0; i < enic_n_tx_stats; i++)
                *(data++) = ((u64 *)&vstats->tx)[enic_tx_stats[i].index];
index 204bd182473bceaaabaa5b1eba5ed618de751808..eadae1b412c652974dde24a9a76c5d74a8c3fa29 100644 (file)
@@ -615,8 +615,15 @@ static struct rtnl_link_stats64 *enic_get_stats(struct net_device *netdev,
 {
        struct enic *enic = netdev_priv(netdev);
        struct vnic_stats *stats;
+       int err;
 
-       enic_dev_stats_dump(enic, &stats);
+       err = enic_dev_stats_dump(enic, &stats);
+       /* return only when pci_zalloc_consistent fails in vnic_dev_stats_dump
+        * For other failures, like devcmd failure, we return previously
+        * recorded stats.
+        */
+       if (err == -ENOMEM)
+               return net_stats;
 
        net_stats->tx_packets = stats->tx.tx_frames_ok;
        net_stats->tx_bytes = stats->tx.tx_bytes_ok;
@@ -1407,6 +1414,7 @@ static int enic_poll_msix_rq(struct napi_struct *napi, int budget)
                 */
                enic_calc_int_moderation(enic, &enic->rq[rq]);
 
+       enic_poll_unlock_napi(&enic->rq[rq]);
        if (work_done < work_to_do) {
 
                /* Some work done, but not enough to stay in polling,
@@ -1418,7 +1426,6 @@ static int enic_poll_msix_rq(struct napi_struct *napi, int budget)
                        enic_set_int_moderation(enic, &enic->rq[rq]);
                vnic_intr_unmask(&enic->intr[intr]);
        }
-       enic_poll_unlock_napi(&enic->rq[rq]);
 
        return work_done;
 }
index 36a2ed606c911f21355360fad81eb39b18162c59..c4b2183bf352fb2a1881001777df91857c2d1f79 100644 (file)
@@ -188,16 +188,15 @@ void vnic_rq_clean(struct vnic_rq *rq,
        struct vnic_rq_buf *buf;
        u32 fetch_index;
        unsigned int count = rq->ring.desc_count;
+       int i;
 
        buf = rq->to_clean;
 
-       while (vnic_rq_desc_used(rq) > 0) {
-
+       for (i = 0; i < rq->ring.desc_count; i++) {
                (*buf_clean)(rq, buf);
-
-               buf = rq->to_clean = buf->next;
-               rq->ring.desc_avail++;
+               buf = buf->next;
        }
+       rq->ring.desc_avail = rq->ring.desc_count - 1;
 
        /* Use current fetch_index as the ring starting point */
        fetch_index = ioread32(&rq->ctrl->fetch_index);
index fb140faeafb1cbda612cd11a9a1aac04e936c4a3..c5e1d0ac75f909f843dd0397ad41b85eeb26a164 100644 (file)
@@ -1720,9 +1720,9 @@ int be_cmd_get_regs(struct be_adapter *adapter, u32 buf_len, void *buf)
        total_size = buf_len;
 
        get_fat_cmd.size = sizeof(struct be_cmd_req_get_fat) + 60*1024;
-       get_fat_cmd.va = pci_alloc_consistent(adapter->pdev,
-                                             get_fat_cmd.size,
-                                             &get_fat_cmd.dma);
+       get_fat_cmd.va = dma_zalloc_coherent(&adapter->pdev->dev,
+                                            get_fat_cmd.size,
+                                            &get_fat_cmd.dma, GFP_ATOMIC);
        if (!get_fat_cmd.va) {
                dev_err(&adapter->pdev->dev,
                        "Memory allocation failure while reading FAT data\n");
@@ -1767,8 +1767,8 @@ int be_cmd_get_regs(struct be_adapter *adapter, u32 buf_len, void *buf)
                log_offset += buf_size;
        }
 err:
-       pci_free_consistent(adapter->pdev, get_fat_cmd.size,
-                           get_fat_cmd.va, get_fat_cmd.dma);
+       dma_free_coherent(&adapter->pdev->dev, get_fat_cmd.size,
+                         get_fat_cmd.va, get_fat_cmd.dma);
        spin_unlock_bh(&adapter->mcc_lock);
        return status;
 }
@@ -2215,12 +2215,12 @@ int be_cmd_read_port_transceiver_data(struct be_adapter *adapter,
                return -EINVAL;
 
        cmd.size = sizeof(struct be_cmd_resp_port_type);
-       cmd.va = pci_alloc_consistent(adapter->pdev, cmd.size, &cmd.dma);
+       cmd.va = dma_zalloc_coherent(&adapter->pdev->dev, cmd.size, &cmd.dma,
+                                    GFP_ATOMIC);
        if (!cmd.va) {
                dev_err(&adapter->pdev->dev, "Memory allocation failed\n");
                return -ENOMEM;
        }
-       memset(cmd.va, 0, cmd.size);
 
        spin_lock_bh(&adapter->mcc_lock);
 
@@ -2245,7 +2245,7 @@ int be_cmd_read_port_transceiver_data(struct be_adapter *adapter,
        }
 err:
        spin_unlock_bh(&adapter->mcc_lock);
-       pci_free_consistent(adapter->pdev, cmd.size, cmd.va, cmd.dma);
+       dma_free_coherent(&adapter->pdev->dev, cmd.size, cmd.va, cmd.dma);
        return status;
 }
 
@@ -2720,7 +2720,8 @@ int be_cmd_get_phy_info(struct be_adapter *adapter)
                goto err;
        }
        cmd.size = sizeof(struct be_cmd_req_get_phy_info);
-       cmd.va = pci_alloc_consistent(adapter->pdev, cmd.size, &cmd.dma);
+       cmd.va = dma_zalloc_coherent(&adapter->pdev->dev, cmd.size, &cmd.dma,
+                                    GFP_ATOMIC);
        if (!cmd.va) {
                dev_err(&adapter->pdev->dev, "Memory alloc failure\n");
                status = -ENOMEM;
@@ -2754,7 +2755,7 @@ int be_cmd_get_phy_info(struct be_adapter *adapter)
                                BE_SUPPORTED_SPEED_1GBPS;
                }
        }
-       pci_free_consistent(adapter->pdev, cmd.size, cmd.va, cmd.dma);
+       dma_free_coherent(&adapter->pdev->dev, cmd.size, cmd.va, cmd.dma);
 err:
        spin_unlock_bh(&adapter->mcc_lock);
        return status;
@@ -2805,8 +2806,9 @@ int be_cmd_get_cntl_attributes(struct be_adapter *adapter)
 
        memset(&attribs_cmd, 0, sizeof(struct be_dma_mem));
        attribs_cmd.size = sizeof(struct be_cmd_resp_cntl_attribs);
-       attribs_cmd.va = pci_alloc_consistent(adapter->pdev, attribs_cmd.size,
-                                             &attribs_cmd.dma);
+       attribs_cmd.va = dma_zalloc_coherent(&adapter->pdev->dev,
+                                            attribs_cmd.size,
+                                            &attribs_cmd.dma, GFP_ATOMIC);
        if (!attribs_cmd.va) {
                dev_err(&adapter->pdev->dev, "Memory allocation failure\n");
                status = -ENOMEM;
@@ -2833,8 +2835,8 @@ int be_cmd_get_cntl_attributes(struct be_adapter *adapter)
 err:
        mutex_unlock(&adapter->mbox_lock);
        if (attribs_cmd.va)
-               pci_free_consistent(adapter->pdev, attribs_cmd.size,
-                                   attribs_cmd.va, attribs_cmd.dma);
+               dma_free_coherent(&adapter->pdev->dev, attribs_cmd.size,
+                                 attribs_cmd.va, attribs_cmd.dma);
        return status;
 }
 
@@ -2972,9 +2974,10 @@ int be_cmd_get_mac_from_list(struct be_adapter *adapter, u8 *mac,
 
        memset(&get_mac_list_cmd, 0, sizeof(struct be_dma_mem));
        get_mac_list_cmd.size = sizeof(struct be_cmd_resp_get_mac_list);
-       get_mac_list_cmd.va = pci_alloc_consistent(adapter->pdev,
-                                                  get_mac_list_cmd.size,
-                                                  &get_mac_list_cmd.dma);
+       get_mac_list_cmd.va = dma_zalloc_coherent(&adapter->pdev->dev,
+                                                 get_mac_list_cmd.size,
+                                                 &get_mac_list_cmd.dma,
+                                                 GFP_ATOMIC);
 
        if (!get_mac_list_cmd.va) {
                dev_err(&adapter->pdev->dev,
@@ -3047,8 +3050,8 @@ int be_cmd_get_mac_from_list(struct be_adapter *adapter, u8 *mac,
 
 out:
        spin_unlock_bh(&adapter->mcc_lock);
-       pci_free_consistent(adapter->pdev, get_mac_list_cmd.size,
-                           get_mac_list_cmd.va, get_mac_list_cmd.dma);
+       dma_free_coherent(&adapter->pdev->dev, get_mac_list_cmd.size,
+                         get_mac_list_cmd.va, get_mac_list_cmd.dma);
        return status;
 }
 
@@ -3101,8 +3104,8 @@ int be_cmd_set_mac_list(struct be_adapter *adapter, u8 *mac_array,
 
        memset(&cmd, 0, sizeof(struct be_dma_mem));
        cmd.size = sizeof(struct be_cmd_req_set_mac_list);
-       cmd.va = dma_alloc_coherent(&adapter->pdev->dev, cmd.size,
-                                   &cmd.dma, GFP_KERNEL);
+       cmd.va = dma_zalloc_coherent(&adapter->pdev->dev, cmd.size, &cmd.dma,
+                                    GFP_KERNEL);
        if (!cmd.va)
                return -ENOMEM;
 
@@ -3291,7 +3294,8 @@ int be_cmd_get_acpi_wol_cap(struct be_adapter *adapter)
 
        memset(&cmd, 0, sizeof(struct be_dma_mem));
        cmd.size = sizeof(struct be_cmd_resp_acpi_wol_magic_config_v1);
-       cmd.va = pci_alloc_consistent(adapter->pdev, cmd.size, &cmd.dma);
+       cmd.va = dma_zalloc_coherent(&adapter->pdev->dev, cmd.size, &cmd.dma,
+                                    GFP_ATOMIC);
        if (!cmd.va) {
                dev_err(&adapter->pdev->dev, "Memory allocation failure\n");
                status = -ENOMEM;
@@ -3326,7 +3330,8 @@ int be_cmd_get_acpi_wol_cap(struct be_adapter *adapter)
 err:
        mutex_unlock(&adapter->mbox_lock);
        if (cmd.va)
-               pci_free_consistent(adapter->pdev, cmd.size, cmd.va, cmd.dma);
+               dma_free_coherent(&adapter->pdev->dev, cmd.size, cmd.va,
+                                 cmd.dma);
        return status;
 
 }
@@ -3340,8 +3345,9 @@ int be_cmd_set_fw_log_level(struct be_adapter *adapter, u32 level)
 
        memset(&extfat_cmd, 0, sizeof(struct be_dma_mem));
        extfat_cmd.size = sizeof(struct be_cmd_resp_get_ext_fat_caps);
-       extfat_cmd.va = pci_alloc_consistent(adapter->pdev, extfat_cmd.size,
-                                            &extfat_cmd.dma);
+       extfat_cmd.va = dma_zalloc_coherent(&adapter->pdev->dev,
+                                           extfat_cmd.size, &extfat_cmd.dma,
+                                           GFP_ATOMIC);
        if (!extfat_cmd.va)
                return -ENOMEM;
 
@@ -3363,8 +3369,8 @@ int be_cmd_set_fw_log_level(struct be_adapter *adapter, u32 level)
 
        status = be_cmd_set_ext_fat_capabilites(adapter, &extfat_cmd, cfgs);
 err:
-       pci_free_consistent(adapter->pdev, extfat_cmd.size, extfat_cmd.va,
-                           extfat_cmd.dma);
+       dma_free_coherent(&adapter->pdev->dev, extfat_cmd.size, extfat_cmd.va,
+                         extfat_cmd.dma);
        return status;
 }
 
@@ -3377,8 +3383,9 @@ int be_cmd_get_fw_log_level(struct be_adapter *adapter)
 
        memset(&extfat_cmd, 0, sizeof(struct be_dma_mem));
        extfat_cmd.size = sizeof(struct be_cmd_resp_get_ext_fat_caps);
-       extfat_cmd.va = pci_alloc_consistent(adapter->pdev, extfat_cmd.size,
-                                            &extfat_cmd.dma);
+       extfat_cmd.va = dma_zalloc_coherent(&adapter->pdev->dev,
+                                           extfat_cmd.size, &extfat_cmd.dma,
+                                           GFP_ATOMIC);
 
        if (!extfat_cmd.va) {
                dev_err(&adapter->pdev->dev, "%s: Memory allocation failure\n",
@@ -3396,8 +3403,8 @@ int be_cmd_get_fw_log_level(struct be_adapter *adapter)
                                level = cfgs->module[0].trace_lvl[j].dbg_lvl;
                }
        }
-       pci_free_consistent(adapter->pdev, extfat_cmd.size, extfat_cmd.va,
-                           extfat_cmd.dma);
+       dma_free_coherent(&adapter->pdev->dev, extfat_cmd.size, extfat_cmd.va,
+                         extfat_cmd.dma);
 err:
        return level;
 }
@@ -3595,7 +3602,8 @@ int be_cmd_get_func_config(struct be_adapter *adapter, struct be_resources *res)
 
        memset(&cmd, 0, sizeof(struct be_dma_mem));
        cmd.size = sizeof(struct be_cmd_resp_get_func_config);
-       cmd.va = pci_alloc_consistent(adapter->pdev, cmd.size, &cmd.dma);
+       cmd.va = dma_zalloc_coherent(&adapter->pdev->dev, cmd.size, &cmd.dma,
+                                    GFP_ATOMIC);
        if (!cmd.va) {
                dev_err(&adapter->pdev->dev, "Memory alloc failure\n");
                status = -ENOMEM;
@@ -3635,7 +3643,8 @@ int be_cmd_get_func_config(struct be_adapter *adapter, struct be_resources *res)
 err:
        mutex_unlock(&adapter->mbox_lock);
        if (cmd.va)
-               pci_free_consistent(adapter->pdev, cmd.size, cmd.va, cmd.dma);
+               dma_free_coherent(&adapter->pdev->dev, cmd.size, cmd.va,
+                                 cmd.dma);
        return status;
 }
 
@@ -3656,7 +3665,8 @@ int be_cmd_get_profile_config(struct be_adapter *adapter,
 
        memset(&cmd, 0, sizeof(struct be_dma_mem));
        cmd.size = sizeof(struct be_cmd_resp_get_profile_config);
-       cmd.va = pci_alloc_consistent(adapter->pdev, cmd.size, &cmd.dma);
+       cmd.va = dma_zalloc_coherent(&adapter->pdev->dev, cmd.size, &cmd.dma,
+                                    GFP_ATOMIC);
        if (!cmd.va)
                return -ENOMEM;
 
@@ -3702,7 +3712,8 @@ int be_cmd_get_profile_config(struct be_adapter *adapter,
                res->vf_if_cap_flags = vf_res->cap_flags;
 err:
        if (cmd.va)
-               pci_free_consistent(adapter->pdev, cmd.size, cmd.va, cmd.dma);
+               dma_free_coherent(&adapter->pdev->dev, cmd.size, cmd.va,
+                                 cmd.dma);
        return status;
 }
 
@@ -3717,7 +3728,8 @@ static int be_cmd_set_profile_config(struct be_adapter *adapter, void *desc,
 
        memset(&cmd, 0, sizeof(struct be_dma_mem));
        cmd.size = sizeof(struct be_cmd_req_set_profile_config);
-       cmd.va = pci_alloc_consistent(adapter->pdev, cmd.size, &cmd.dma);
+       cmd.va = dma_zalloc_coherent(&adapter->pdev->dev, cmd.size, &cmd.dma,
+                                    GFP_ATOMIC);
        if (!cmd.va)
                return -ENOMEM;
 
@@ -3733,7 +3745,8 @@ static int be_cmd_set_profile_config(struct be_adapter *adapter, void *desc,
        status = be_cmd_notify_wait(adapter, &wrb);
 
        if (cmd.va)
-               pci_free_consistent(adapter->pdev, cmd.size, cmd.va, cmd.dma);
+               dma_free_coherent(&adapter->pdev->dev, cmd.size, cmd.va,
+                                 cmd.dma);
        return status;
 }
 
index b765c24625bf523fd7932be17f6dfa22840a8e46..2835dee5dc3930cc5d1d09ec958bd2557228a2cd 100644 (file)
@@ -264,8 +264,8 @@ static int lancer_cmd_read_file(struct be_adapter *adapter, u8 *file_name,
        int status = 0;
 
        read_cmd.size = LANCER_READ_FILE_CHUNK;
-       read_cmd.va = pci_alloc_consistent(adapter->pdev, read_cmd.size,
-                                          &read_cmd.dma);
+       read_cmd.va = dma_zalloc_coherent(&adapter->pdev->dev, read_cmd.size,
+                                         &read_cmd.dma, GFP_ATOMIC);
 
        if (!read_cmd.va) {
                dev_err(&adapter->pdev->dev,
@@ -289,8 +289,8 @@ static int lancer_cmd_read_file(struct be_adapter *adapter, u8 *file_name,
                        break;
                }
        }
-       pci_free_consistent(adapter->pdev, read_cmd.size, read_cmd.va,
-                           read_cmd.dma);
+       dma_free_coherent(&adapter->pdev->dev, read_cmd.size, read_cmd.va,
+                         read_cmd.dma);
 
        return status;
 }
@@ -818,8 +818,9 @@ static int be_test_ddr_dma(struct be_adapter *adapter)
        };
 
        ddrdma_cmd.size = sizeof(struct be_cmd_req_ddrdma_test);
-       ddrdma_cmd.va = dma_alloc_coherent(&adapter->pdev->dev, ddrdma_cmd.size,
-                                          &ddrdma_cmd.dma, GFP_KERNEL);
+       ddrdma_cmd.va = dma_zalloc_coherent(&adapter->pdev->dev,
+                                           ddrdma_cmd.size, &ddrdma_cmd.dma,
+                                           GFP_KERNEL);
        if (!ddrdma_cmd.va)
                return -ENOMEM;
 
@@ -941,8 +942,9 @@ static int be_read_eeprom(struct net_device *netdev,
 
        memset(&eeprom_cmd, 0, sizeof(struct be_dma_mem));
        eeprom_cmd.size = sizeof(struct be_cmd_req_seeprom_read);
-       eeprom_cmd.va = dma_alloc_coherent(&adapter->pdev->dev, eeprom_cmd.size,
-                                          &eeprom_cmd.dma, GFP_KERNEL);
+       eeprom_cmd.va = dma_zalloc_coherent(&adapter->pdev->dev,
+                                           eeprom_cmd.size, &eeprom_cmd.dma,
+                                           GFP_KERNEL);
 
        if (!eeprom_cmd.va)
                return -ENOMEM;
index fb0bc3c3620e9cf87983b1c425e0f24d431bffc9..e43cc8a73ea7e85a927443c077c18ce6c673751a 100644 (file)
@@ -2358,11 +2358,11 @@ static int be_evt_queues_create(struct be_adapter *adapter)
                                    adapter->cfg_num_qs);
 
        for_all_evt_queues(adapter, eqo, i) {
+               int numa_node = dev_to_node(&adapter->pdev->dev);
                if (!zalloc_cpumask_var(&eqo->affinity_mask, GFP_KERNEL))
                        return -ENOMEM;
-               cpumask_set_cpu_local_first(i, dev_to_node(&adapter->pdev->dev),
-                                           eqo->affinity_mask);
-
+               cpumask_set_cpu(cpumask_local_spread(i, numa_node),
+                               eqo->affinity_mask);
                netif_napi_add(adapter->netdev, &eqo->napi, be_poll,
                               BE_NAPI_WEIGHT);
                napi_hash_add(&eqo->napi);
@@ -4605,8 +4605,8 @@ static int lancer_fw_download(struct be_adapter *adapter,
 
        flash_cmd.size = sizeof(struct lancer_cmd_req_write_object)
                                + LANCER_FW_DOWNLOAD_CHUNK;
-       flash_cmd.va = dma_alloc_coherent(dev, flash_cmd.size,
-                                         &flash_cmd.dma, GFP_KERNEL);
+       flash_cmd.va = dma_zalloc_coherent(dev, flash_cmd.size,
+                                          &flash_cmd.dma, GFP_KERNEL);
        if (!flash_cmd.va)
                return -ENOMEM;
 
@@ -4739,8 +4739,8 @@ static int be_fw_download(struct be_adapter *adapter, const struct firmware* fw)
        }
 
        flash_cmd.size = sizeof(struct be_cmd_write_flashrom);
-       flash_cmd.va = dma_alloc_coherent(dev, flash_cmd.size, &flash_cmd.dma,
-                                         GFP_KERNEL);
+       flash_cmd.va = dma_zalloc_coherent(dev, flash_cmd.size, &flash_cmd.dma,
+                                          GFP_KERNEL);
        if (!flash_cmd.va)
                return -ENOMEM;
 
@@ -4846,7 +4846,8 @@ err:
 }
 
 static int be_ndo_bridge_getlink(struct sk_buff *skb, u32 pid, u32 seq,
-                                struct net_device *dev, u32 filter_mask)
+                                struct net_device *dev, u32 filter_mask,
+                                int nlflags)
 {
        struct be_adapter *adapter = netdev_priv(dev);
        int status = 0;
@@ -4868,7 +4869,7 @@ static int be_ndo_bridge_getlink(struct sk_buff *skb, u32 pid, u32 seq,
        return ndo_dflt_bridge_getlink(skb, pid, seq, dev,
                                       hsw_mode == PORT_FWD_TYPE_VEPA ?
                                       BRIDGE_MODE_VEPA : BRIDGE_MODE_VEB,
-                                      0, 0);
+                                      0, 0, nlflags);
 }
 
 #ifdef CONFIG_BE2NET_VXLAN
@@ -5290,16 +5291,15 @@ static int be_drv_init(struct be_adapter *adapter)
        int status = 0;
 
        mbox_mem_alloc->size = sizeof(struct be_mcc_mailbox) + 16;
-       mbox_mem_alloc->va = dma_alloc_coherent(dev, mbox_mem_alloc->size,
-                                               &mbox_mem_alloc->dma,
-                                               GFP_KERNEL);
+       mbox_mem_alloc->va = dma_zalloc_coherent(dev, mbox_mem_alloc->size,
+                                                &mbox_mem_alloc->dma,
+                                                GFP_KERNEL);
        if (!mbox_mem_alloc->va)
                return -ENOMEM;
 
        mbox_mem_align->size = sizeof(struct be_mcc_mailbox);
        mbox_mem_align->va = PTR_ALIGN(mbox_mem_alloc->va, 16);
        mbox_mem_align->dma = PTR_ALIGN(mbox_mem_alloc->dma, 16);
-       memset(mbox_mem_align->va, 0, sizeof(struct be_mcc_mailbox));
 
        rx_filter->size = sizeof(struct be_cmd_req_rx_filter);
        rx_filter->va = dma_zalloc_coherent(dev, rx_filter->size,
index f6a3a7abd468e1f25fd4c33e874a38f0c85bc4dd..66d47e448e4d175aeefecddacc53f8f858f0085b 100644 (file)
@@ -988,7 +988,10 @@ fec_restart(struct net_device *ndev)
                rcntl |= 0x40000000 | 0x00000020;
 
                /* RGMII, RMII or MII */
-               if (fep->phy_interface == PHY_INTERFACE_MODE_RGMII)
+               if (fep->phy_interface == PHY_INTERFACE_MODE_RGMII ||
+                   fep->phy_interface == PHY_INTERFACE_MODE_RGMII_ID ||
+                   fep->phy_interface == PHY_INTERFACE_MODE_RGMII_RXID ||
+                   fep->phy_interface == PHY_INTERFACE_MODE_RGMII_TXID)
                        rcntl |= (1 << 6);
                else if (fep->phy_interface == PHY_INTERFACE_MODE_RMII)
                        rcntl |= (1 << 8);
index 291c87036e173c792a1b26234e2b99e8cd67bf65..2a0dc127df3f4e099e273a77715ad87358385aff 100644 (file)
@@ -3347,7 +3347,7 @@ static int ehea_register_memory_hooks(void)
 {
        int ret = 0;
 
-       if (atomic_inc_and_test(&ehea_memory_hooks_registered))
+       if (atomic_inc_return(&ehea_memory_hooks_registered) > 1)
                return 0;
 
        ret = ehea_create_busmap();
@@ -3381,12 +3381,14 @@ out3:
 out2:
        unregister_reboot_notifier(&ehea_reboot_nb);
 out:
+       atomic_dec(&ehea_memory_hooks_registered);
        return ret;
 }
 
 static void ehea_unregister_memory_hooks(void)
 {
-       if (atomic_read(&ehea_memory_hooks_registered))
+       /* Only remove the hooks if we've registered them */
+       if (atomic_read(&ehea_memory_hooks_registered) == 0)
                return;
 
        unregister_reboot_notifier(&ehea_reboot_nb);
index de79193221903edee02810fe657ac44815e877ca..b9df0cbd0a3833321d1f73bc74258b50b137f225 100644 (file)
@@ -2084,12 +2084,8 @@ static void emac_ethtool_get_pauseparam(struct net_device *ndev,
 
 static int emac_get_regs_len(struct emac_instance *dev)
 {
-       if (emac_has_feature(dev, EMAC_FTR_EMAC4))
-               return sizeof(struct emac_ethtool_regs_subhdr) +
-                       EMAC4_ETHTOOL_REGS_SIZE(dev);
-       else
                return sizeof(struct emac_ethtool_regs_subhdr) +
-                       EMAC_ETHTOOL_REGS_SIZE(dev);
+                       sizeof(struct emac_regs);
 }
 
 static int emac_ethtool_get_regs_len(struct net_device *ndev)
@@ -2114,15 +2110,15 @@ static void *emac_dump_regs(struct emac_instance *dev, void *buf)
        struct emac_ethtool_regs_subhdr *hdr = buf;
 
        hdr->index = dev->cell_index;
-       if (emac_has_feature(dev, EMAC_FTR_EMAC4)) {
+       if (emac_has_feature(dev, EMAC_FTR_EMAC4SYNC)) {
+               hdr->version = EMAC4SYNC_ETHTOOL_REGS_VER;
+       } else if (emac_has_feature(dev, EMAC_FTR_EMAC4)) {
                hdr->version = EMAC4_ETHTOOL_REGS_VER;
-               memcpy_fromio(hdr + 1, dev->emacp, EMAC4_ETHTOOL_REGS_SIZE(dev));
-               return (void *)(hdr + 1) + EMAC4_ETHTOOL_REGS_SIZE(dev);
        } else {
                hdr->version = EMAC_ETHTOOL_REGS_VER;
-               memcpy_fromio(hdr + 1, dev->emacp, EMAC_ETHTOOL_REGS_SIZE(dev));
-               return (void *)(hdr + 1) + EMAC_ETHTOOL_REGS_SIZE(dev);
        }
+       memcpy_fromio(hdr + 1, dev->emacp, sizeof(struct emac_regs));
+       return (void *)(hdr + 1) + sizeof(struct emac_regs);
 }
 
 static void emac_ethtool_get_regs(struct net_device *ndev,
index 67f342a9f65e46fe8dd015b921fd144e30db286b..28df37420da963d5d8f3b3234e4f584442537121 100644 (file)
@@ -461,10 +461,7 @@ struct emac_ethtool_regs_subhdr {
 };
 
 #define EMAC_ETHTOOL_REGS_VER          0
-#define EMAC_ETHTOOL_REGS_SIZE(dev)    ((dev)->rsrc_regs.end - \
-                                        (dev)->rsrc_regs.start + 1)
-#define EMAC4_ETHTOOL_REGS_VER         1
-#define EMAC4_ETHTOOL_REGS_SIZE(dev)   ((dev)->rsrc_regs.end - \
-                                        (dev)->rsrc_regs.start + 1)
+#define EMAC4_ETHTOOL_REGS_VER         1
+#define EMAC4SYNC_ETHTOOL_REGS_VER     2
 
 #endif /* __IBM_NEWEMAC_CORE_H */
index cd7675ac5bf9ed8b8658996d2d27190c6b20245f..18134766a11409c6c976f00ac0431de748c03073 100644 (file)
@@ -1238,7 +1238,7 @@ static int ibmveth_change_mtu(struct net_device *dev, int new_mtu)
                return -EINVAL;
 
        for (i = 0; i < IBMVETH_NUM_BUFF_POOLS; i++)
-               if (new_mtu_oh < adapter->rx_buff_pool[i].buff_size)
+               if (new_mtu_oh <= adapter->rx_buff_pool[i].buff_size)
                        break;
 
        if (i == IBMVETH_NUM_BUFF_POOLS)
@@ -1257,7 +1257,7 @@ static int ibmveth_change_mtu(struct net_device *dev, int new_mtu)
        for (i = 0; i < IBMVETH_NUM_BUFF_POOLS; i++) {
                adapter->rx_buff_pool[i].active = 1;
 
-               if (new_mtu_oh < adapter->rx_buff_pool[i].buff_size) {
+               if (new_mtu_oh <= adapter->rx_buff_pool[i].buff_size) {
                        dev->mtu = new_mtu;
                        vio_cmo_set_dev_desired(viodev,
                                                ibmveth_get_desired_dma
index 5d9ceb17b4cbad4f7e89cf0bb050e915f5b8d285..0abc942c966e4a377af222c1d876af6983edb91a 100644 (file)
@@ -40,6 +40,7 @@
 #include <linux/ptp_classify.h>
 #include <linux/mii.h>
 #include <linux/mdio.h>
+#include <linux/pm_qos.h>
 #include "hw.h"
 
 struct e1000_info;
index 1b0661e3573b78d73804ed59177420a4d6fde147..c754b2027281f8a2c0b18c079b31c2b7420eedbf 100644 (file)
@@ -610,7 +610,7 @@ static bool fm10k_clean_rx_irq(struct fm10k_q_vector *q_vector,
        unsigned int total_bytes = 0, total_packets = 0;
        u16 cleaned_count = fm10k_desc_unused(rx_ring);
 
-       do {
+       while (likely(total_packets < budget)) {
                union fm10k_rx_desc *rx_desc;
 
                /* return some buffers to hardware, one at a time is too slow */
@@ -659,7 +659,7 @@ static bool fm10k_clean_rx_irq(struct fm10k_q_vector *q_vector,
 
                /* update budget accounting */
                total_packets++;
-       } while (likely(total_packets < budget));
+       }
 
        /* place incomplete frames back on ring for completion */
        rx_ring->skb = skb;
index 33c35d3b7420fa9ae545aea4ebd5160036914718..5d47307121abbe413cd259ff74f9aa2ee68e6c45 100644 (file)
@@ -317,6 +317,7 @@ struct i40e_pf {
 #endif
 #define I40E_FLAG_PORT_ID_VALID                (u64)(1 << 28)
 #define I40E_FLAG_DCB_CAPABLE                  (u64)(1 << 29)
+#define I40E_FLAG_VEB_MODE_ENABLED             BIT_ULL(40)
 
        /* tracks features that get auto disabled by errors */
        u64 auto_disable_flags;
index 34170eabca7da939ba1c8b9b5fad14dc2f54370d..da0faf478af076199e4281b0f3da57ad92c5e62b 100644 (file)
@@ -1021,6 +1021,15 @@ static ssize_t i40e_dbg_command_write(struct file *filp,
                        goto command_write_done;
                }
 
+               /* By default we are in VEPA mode, if this is the first VF/VMDq
+                * VSI to be added switch to VEB mode.
+                */
+               if (!(pf->flags & I40E_FLAG_VEB_MODE_ENABLED)) {
+                       pf->flags |= I40E_FLAG_VEB_MODE_ENABLED;
+                       i40e_do_reset_safe(pf,
+                                          BIT_ULL(__I40E_PF_RESET_REQUESTED));
+               }
+
                vsi = i40e_vsi_setup(pf, I40E_VSI_VMDQ2, vsi_seid, 0);
                if (vsi)
                        dev_info(&pf->pdev->dev, "added VSI %d to relay %d\n",
index 24481cd7e59ac94e3e4ec14528938338aeaf4000..5b5bea159bd53c8684d0a69b310e492bc797c8b6 100644 (file)
@@ -6097,6 +6097,10 @@ static int i40e_reconstitute_veb(struct i40e_veb *veb)
        if (ret)
                goto end_reconstitute;
 
+       if (pf->flags & I40E_FLAG_VEB_MODE_ENABLED)
+               veb->bridge_mode = BRIDGE_MODE_VEB;
+       else
+               veb->bridge_mode = BRIDGE_MODE_VEPA;
        i40e_config_bridge_mode(veb);
 
        /* create the remaining VSIs attached to this VEB */
@@ -8031,7 +8035,12 @@ static int i40e_ndo_bridge_setlink(struct net_device *dev,
                } else if (mode != veb->bridge_mode) {
                        /* Existing HW bridge but different mode needs reset */
                        veb->bridge_mode = mode;
-                       i40e_do_reset(pf, (1 << __I40E_PF_RESET_REQUESTED));
+                       /* TODO: If no VFs or VMDq VSIs, disallow VEB mode */
+                       if (mode == BRIDGE_MODE_VEB)
+                               pf->flags |= I40E_FLAG_VEB_MODE_ENABLED;
+                       else
+                               pf->flags &= ~I40E_FLAG_VEB_MODE_ENABLED;
+                       i40e_do_reset(pf, BIT_ULL(__I40E_PF_RESET_REQUESTED));
                        break;
                }
        }
@@ -8053,10 +8062,10 @@ static int i40e_ndo_bridge_setlink(struct net_device *dev,
 #ifdef HAVE_BRIDGE_FILTER
 static int i40e_ndo_bridge_getlink(struct sk_buff *skb, u32 pid, u32 seq,
                                   struct net_device *dev,
-                                  u32 __always_unused filter_mask)
+                                  u32 __always_unused filter_mask, int nlflags)
 #else
 static int i40e_ndo_bridge_getlink(struct sk_buff *skb, u32 pid, u32 seq,
-                                  struct net_device *dev)
+                                  struct net_device *dev, int nlflags)
 #endif /* HAVE_BRIDGE_FILTER */
 {
        struct i40e_netdev_priv *np = netdev_priv(dev);
@@ -8078,7 +8087,8 @@ static int i40e_ndo_bridge_getlink(struct sk_buff *skb, u32 pid, u32 seq,
        if (!veb)
                return 0;
 
-       return ndo_dflt_bridge_getlink(skb, pid, seq, dev, veb->bridge_mode);
+       return ndo_dflt_bridge_getlink(skb, pid, seq, dev, veb->bridge_mode,
+                                      nlflags);
 }
 #endif /* HAVE_BRIDGE_ATTRIBS */
 
@@ -8342,11 +8352,12 @@ static int i40e_add_vsi(struct i40e_vsi *vsi)
                ctxt.uplink_seid = vsi->uplink_seid;
                ctxt.connection_type = I40E_AQ_VSI_CONN_TYPE_NORMAL;
                ctxt.flags = I40E_AQ_VSI_TYPE_PF;
-               if (i40e_is_vsi_uplink_mode_veb(vsi)) {
+               if ((pf->flags & I40E_FLAG_VEB_MODE_ENABLED) &&
+                   (i40e_is_vsi_uplink_mode_veb(vsi))) {
                        ctxt.info.valid_sections |=
-                               cpu_to_le16(I40E_AQ_VSI_PROP_SWITCH_VALID);
+                            cpu_to_le16(I40E_AQ_VSI_PROP_SWITCH_VALID);
                        ctxt.info.switch_id =
-                               cpu_to_le16(I40E_AQ_VSI_SW_ID_FLAG_ALLOW_LB);
+                          cpu_to_le16(I40E_AQ_VSI_SW_ID_FLAG_ALLOW_LB);
                }
                i40e_vsi_setup_queue_map(vsi, &ctxt, enabled_tc, true);
                break;
@@ -8745,6 +8756,14 @@ struct i40e_vsi *i40e_vsi_setup(struct i40e_pf *pf, u8 type,
                                         __func__);
                                return NULL;
                        }
+                       /* We come up by default in VEPA mode if SRIOV is not
+                        * already enabled, in which case we can't force VEPA
+                        * mode.
+                        */
+                       if (!(pf->flags & I40E_FLAG_VEB_MODE_ENABLED)) {
+                               veb->bridge_mode = BRIDGE_MODE_VEPA;
+                               pf->flags &= ~I40E_FLAG_VEB_MODE_ENABLED;
+                       }
                        i40e_config_bridge_mode(veb);
                }
                for (i = 0; i < I40E_MAX_VEB && !veb; i++) {
@@ -9855,6 +9874,15 @@ static int i40e_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
                goto err_switch_setup;
        }
 
+#ifdef CONFIG_PCI_IOV
+       /* prep for VF support */
+       if ((pf->flags & I40E_FLAG_SRIOV_ENABLED) &&
+           (pf->flags & I40E_FLAG_MSIX_ENABLED) &&
+           !test_bit(__I40E_BAD_EEPROM, &pf->state)) {
+               if (pci_num_vf(pdev))
+                       pf->flags |= I40E_FLAG_VEB_MODE_ENABLED;
+       }
+#endif
        err = i40e_setup_pf_switch(pf, false);
        if (err) {
                dev_info(&pdev->dev, "setup_pf_switch failed: %d\n", err);
index 4bd3a80aba82998bba343a1870b2d21f59bca4e0..9d95042d5a0f5805824d53ecc847ff76a9909444 100644 (file)
@@ -2410,14 +2410,12 @@ static int i40e_maybe_stop_tx(struct i40e_ring *tx_ring, int size)
  * i40e_chk_linearize - Check if there are more than 8 fragments per packet
  * @skb:      send buffer
  * @tx_flags: collected send information
- * @hdr_len:  size of the packet header
  *
  * Note: Our HW can't scatter-gather more than 8 fragments to build
  * a packet on the wire and so we need to figure out the cases where we
  * need to linearize the skb.
  **/
-static bool i40e_chk_linearize(struct sk_buff *skb, u32 tx_flags,
-                              const u8 hdr_len)
+static bool i40e_chk_linearize(struct sk_buff *skb, u32 tx_flags)
 {
        struct skb_frag_struct *frag;
        bool linearize = false;
@@ -2429,7 +2427,7 @@ static bool i40e_chk_linearize(struct sk_buff *skb, u32 tx_flags,
        gso_segs = skb_shinfo(skb)->gso_segs;
 
        if (tx_flags & (I40E_TX_FLAGS_TSO | I40E_TX_FLAGS_FSO)) {
-               u16 j = 1;
+               u16 j = 0;
 
                if (num_frags < (I40E_MAX_BUFFER_TXD))
                        goto linearize_chk_done;
@@ -2440,21 +2438,18 @@ static bool i40e_chk_linearize(struct sk_buff *skb, u32 tx_flags,
                        goto linearize_chk_done;
                }
                frag = &skb_shinfo(skb)->frags[0];
-               size = hdr_len;
                /* we might still have more fragments per segment */
                do {
                        size += skb_frag_size(frag);
                        frag++; j++;
+                       if ((size >= skb_shinfo(skb)->gso_size) &&
+                           (j < I40E_MAX_BUFFER_TXD)) {
+                               size = (size % skb_shinfo(skb)->gso_size);
+                               j = (size) ? 1 : 0;
+                       }
                        if (j == I40E_MAX_BUFFER_TXD) {
-                               if (size < skb_shinfo(skb)->gso_size) {
-                                       linearize = true;
-                                       break;
-                               }
-                               j = 1;
-                               size -= skb_shinfo(skb)->gso_size;
-                               if (size)
-                                       j++;
-                               size += hdr_len;
+                               linearize = true;
+                               break;
                        }
                        num_frags--;
                } while (num_frags);
@@ -2724,7 +2719,7 @@ static netdev_tx_t i40e_xmit_frame_ring(struct sk_buff *skb,
        if (tsyn)
                tx_flags |= I40E_TX_FLAGS_TSYN;
 
-       if (i40e_chk_linearize(skb, tx_flags, hdr_len))
+       if (i40e_chk_linearize(skb, tx_flags))
                if (skb_linearize(skb))
                        goto out_drop;
 
index 78d1c4ff565e8853473b70c3827e6a727ff3ce1c..4e9376da051829969de7750c2dc7a66acc5e5f40 100644 (file)
@@ -1018,11 +1018,19 @@ int i40e_pci_sriov_configure(struct pci_dev *pdev, int num_vfs)
 {
        struct i40e_pf *pf = pci_get_drvdata(pdev);
 
-       if (num_vfs)
+       if (num_vfs) {
+               if (!(pf->flags & I40E_FLAG_VEB_MODE_ENABLED)) {
+                       pf->flags |= I40E_FLAG_VEB_MODE_ENABLED;
+                       i40e_do_reset_safe(pf,
+                                          BIT_ULL(__I40E_PF_RESET_REQUESTED));
+               }
                return i40e_pci_sriov_enable(pdev, num_vfs);
+       }
 
        if (!pci_vfs_assigned(pf->pdev)) {
                i40e_free_vfs(pf);
+               pf->flags &= ~I40E_FLAG_VEB_MODE_ENABLED;
+               i40e_do_reset_safe(pf, BIT_ULL(__I40E_PF_RESET_REQUESTED));
        } else {
                dev_warn(&pdev->dev, "Unable to free VFs because some are assigned to VMs.\n");
                return -EINVAL;
index b077e02a0cc7ac8f67ad90560cf990f8f7a66277..458fbb421090772d0bbc1620277624339e0cd757 100644 (file)
@@ -1619,14 +1619,12 @@ static void i40e_create_tx_ctx(struct i40e_ring *tx_ring,
  * i40e_chk_linearize - Check if there are more than 8 fragments per packet
  * @skb:      send buffer
  * @tx_flags: collected send information
- * @hdr_len:  size of the packet header
  *
  * Note: Our HW can't scatter-gather more than 8 fragments to build
  * a packet on the wire and so we need to figure out the cases where we
  * need to linearize the skb.
  **/
-static bool i40e_chk_linearize(struct sk_buff *skb, u32 tx_flags,
-                              const u8 hdr_len)
+static bool i40e_chk_linearize(struct sk_buff *skb, u32 tx_flags)
 {
        struct skb_frag_struct *frag;
        bool linearize = false;
@@ -1638,7 +1636,7 @@ static bool i40e_chk_linearize(struct sk_buff *skb, u32 tx_flags,
        gso_segs = skb_shinfo(skb)->gso_segs;
 
        if (tx_flags & (I40E_TX_FLAGS_TSO | I40E_TX_FLAGS_FSO)) {
-               u16 j = 1;
+               u16 j = 0;
 
                if (num_frags < (I40E_MAX_BUFFER_TXD))
                        goto linearize_chk_done;
@@ -1649,21 +1647,18 @@ static bool i40e_chk_linearize(struct sk_buff *skb, u32 tx_flags,
                        goto linearize_chk_done;
                }
                frag = &skb_shinfo(skb)->frags[0];
-               size = hdr_len;
                /* we might still have more fragments per segment */
                do {
                        size += skb_frag_size(frag);
                        frag++; j++;
+                       if ((size >= skb_shinfo(skb)->gso_size) &&
+                           (j < I40E_MAX_BUFFER_TXD)) {
+                               size = (size % skb_shinfo(skb)->gso_size);
+                               j = (size) ? 1 : 0;
+                       }
                        if (j == I40E_MAX_BUFFER_TXD) {
-                               if (size < skb_shinfo(skb)->gso_size) {
-                                       linearize = true;
-                                       break;
-                               }
-                               j = 1;
-                               size -= skb_shinfo(skb)->gso_size;
-                               if (size)
-                                       j++;
-                               size += hdr_len;
+                               linearize = true;
+                               break;
                        }
                        num_frags--;
                } while (num_frags);
@@ -1950,7 +1945,7 @@ static netdev_tx_t i40e_xmit_frame_ring(struct sk_buff *skb,
        else if (tso)
                tx_flags |= I40E_TX_FLAGS_TSO;
 
-       if (i40e_chk_linearize(skb, tx_flags, hdr_len))
+       if (i40e_chk_linearize(skb, tx_flags))
                if (skb_linearize(skb))
                        goto out_drop;
 
index 8457d0306e3a76107c18ed524a3000d47b3ead6e..a0a9b1fcb5e8efcf4f7ebfe980459f64056e896f 100644 (file)
@@ -1036,7 +1036,7 @@ static void igb_reset_q_vector(struct igb_adapter *adapter, int v_idx)
                adapter->tx_ring[q_vector->tx.ring->queue_index] = NULL;
 
        if (q_vector->rx.ring)
-               adapter->tx_ring[q_vector->rx.ring->queue_index] = NULL;
+               adapter->rx_ring[q_vector->rx.ring->queue_index] = NULL;
 
        netif_napi_del(&q_vector->napi);
 
@@ -1207,6 +1207,8 @@ static int igb_alloc_q_vector(struct igb_adapter *adapter,
        q_vector = adapter->q_vector[v_idx];
        if (!q_vector)
                q_vector = kzalloc(size, GFP_KERNEL);
+       else
+               memset(q_vector, 0, size);
        if (!q_vector)
                return -ENOMEM;
 
index e3b9b63ad01083cb987429f57c9ebef84d86f4db..c3a9392cbc192229f4178c913fad8ab64d8c44c3 100644 (file)
@@ -538,8 +538,8 @@ static int igb_ptp_feature_enable_i210(struct ptp_clock_info *ptp,
                        igb->perout[i].start.tv_nsec = rq->perout.start.nsec;
                        igb->perout[i].period.tv_sec = ts.tv_sec;
                        igb->perout[i].period.tv_nsec = ts.tv_nsec;
-                       wr32(trgttiml, rq->perout.start.sec);
-                       wr32(trgttimh, rq->perout.start.nsec);
+                       wr32(trgttimh, rq->perout.start.sec);
+                       wr32(trgttiml, rq->perout.start.nsec);
                        tsauxc |= tsauxc_mask;
                        tsim |= tsim_mask;
                } else {
index d3f4b0ceb3f781216599408248b351cd4854bc92..5be12a00e1f447744f2497131cea1a70e313fd1f 100644 (file)
@@ -8044,7 +8044,7 @@ static int ixgbe_ndo_bridge_setlink(struct net_device *dev,
 
 static int ixgbe_ndo_bridge_getlink(struct sk_buff *skb, u32 pid, u32 seq,
                                    struct net_device *dev,
-                                   u32 filter_mask)
+                                   u32 filter_mask, int nlflags)
 {
        struct ixgbe_adapter *adapter = netdev_priv(dev);
 
@@ -8052,7 +8052,7 @@ static int ixgbe_ndo_bridge_getlink(struct sk_buff *skb, u32 pid, u32 seq,
                return 0;
 
        return ndo_dflt_bridge_getlink(skb, pid, seq, dev,
-                                      adapter->bridge_mode, 0, 0);
+                                      adapter->bridge_mode, 0, 0, nlflags);
 }
 
 static void *ixgbe_fwd_add(struct net_device *pdev, struct net_device *vdev)
index a16d267fbce4b0f6883c8cf5d43db1ad3bf7e458..e71cdde9cb017aecab834d2f2d9c5d4821c3d42e 100644 (file)
@@ -3612,7 +3612,7 @@ static int ixgbevf_xmit_frame(struct sk_buff *skb, struct net_device *netdev)
        u8 *dst_mac = skb_header_pointer(skb, 0, 0, NULL);
 
        if (!dst_mac || is_link_local_ether_addr(dst_mac)) {
-               dev_kfree_skb(skb);
+               dev_kfree_skb_any(skb);
                return NETDEV_TX_OK;
        }
 
index af829c57840039e54e853bd5c4230ab0c6f17699..7ace07dad6a31d4b18ab5aa1e5335c0727cff596 100644 (file)
@@ -1508,7 +1508,8 @@ static int pxa168_eth_probe(struct platform_device *pdev)
                np = of_parse_phandle(pdev->dev.of_node, "phy-handle", 0);
                if (!np) {
                        dev_err(&pdev->dev, "missing phy-handle\n");
-                       return -EINVAL;
+                       err = -EINVAL;
+                       goto err_netdev;
                }
                of_property_read_u32(np, "reg", &pep->phy_addr);
                pep->phy_intf = of_get_phy_mode(pdev->dev.of_node);
@@ -1526,7 +1527,7 @@ static int pxa168_eth_probe(struct platform_device *pdev)
        pep->smi_bus = mdiobus_alloc();
        if (pep->smi_bus == NULL) {
                err = -ENOMEM;
-               goto err_base;
+               goto err_netdev;
        }
        pep->smi_bus->priv = pep;
        pep->smi_bus->name = "pxa168_eth smi";
@@ -1551,13 +1552,10 @@ err_mdiobus:
        mdiobus_unregister(pep->smi_bus);
 err_free_mdio:
        mdiobus_free(pep->smi_bus);
-err_base:
-       iounmap(pep->base);
 err_netdev:
        free_netdev(dev);
 err_clk:
-       clk_disable(clk);
-       clk_put(clk);
+       clk_disable_unprepare(clk);
        return err;
 }
 
@@ -1574,13 +1572,9 @@ static int pxa168_eth_remove(struct platform_device *pdev)
        if (pep->phy)
                phy_disconnect(pep->phy);
        if (pep->clk) {
-               clk_disable(pep->clk);
-               clk_put(pep->clk);
-               pep->clk = NULL;
+               clk_disable_unprepare(pep->clk);
        }
 
-       iounmap(pep->base);
-       pep->base = NULL;
        mdiobus_unregister(pep->smi_bus);
        mdiobus_free(pep->smi_bus);
        unregister_netdev(dev);
index 4f7dc044601e2751ad625e4c011aa3a1c328e62f..529ef0594b902ebaf2838cf478ef914a0b69d5b7 100644 (file)
@@ -714,8 +714,13 @@ static int mlx4_cmd_wait(struct mlx4_dev *dev, u64 in_param, u64 *out_param,
                                         msecs_to_jiffies(timeout))) {
                mlx4_warn(dev, "command 0x%x timed out (go bit not cleared)\n",
                          op);
-               err = -EIO;
-               goto out_reset;
+               if (op == MLX4_CMD_NOP) {
+                       err = -EBUSY;
+                       goto out;
+               } else {
+                       err = -EIO;
+                       goto out_reset;
+               }
        }
 
        err = context->result;
index 3f44e2bbb9824caad9068e7ce6f03e1a2df382f2..a2ddf3d75ff8ff8956763b924bc2fda8b156c222 100644 (file)
@@ -1102,20 +1102,21 @@ static int mlx4_en_check_rxfh_func(struct net_device *dev, u8 hfunc)
        struct mlx4_en_priv *priv = netdev_priv(dev);
 
        /* check if requested function is supported by the device */
-       if ((hfunc == ETH_RSS_HASH_TOP &&
-            !(priv->mdev->dev->caps.flags2 & MLX4_DEV_CAP_FLAG2_RSS_TOP)) ||
-           (hfunc == ETH_RSS_HASH_XOR &&
-            !(priv->mdev->dev->caps.flags2 & MLX4_DEV_CAP_FLAG2_RSS_XOR)))
-               return -EINVAL;
+       if (hfunc == ETH_RSS_HASH_TOP) {
+               if (!(priv->mdev->dev->caps.flags2 & MLX4_DEV_CAP_FLAG2_RSS_TOP))
+                       return -EINVAL;
+               if (!(dev->features & NETIF_F_RXHASH))
+                       en_warn(priv, "Toeplitz hash function should be used in conjunction with RX hashing for optimal performance\n");
+               return 0;
+       } else if (hfunc == ETH_RSS_HASH_XOR) {
+               if (!(priv->mdev->dev->caps.flags2 & MLX4_DEV_CAP_FLAG2_RSS_XOR))
+                       return -EINVAL;
+               if (dev->features & NETIF_F_RXHASH)
+                       en_warn(priv, "Enabling both XOR Hash function and RX Hashing can limit RPS functionality\n");
+               return 0;
+       }
 
-       priv->rss_hash_fn = hfunc;
-       if (hfunc == ETH_RSS_HASH_TOP && !(dev->features & NETIF_F_RXHASH))
-               en_warn(priv,
-                       "Toeplitz hash function should be used in conjunction with RX hashing for optimal performance\n");
-       if (hfunc == ETH_RSS_HASH_XOR && (dev->features & NETIF_F_RXHASH))
-               en_warn(priv,
-                       "Enabling both XOR Hash function and RX Hashing can limit RPS functionality\n");
-       return 0;
+       return -EINVAL;
 }
 
 static int mlx4_en_get_rxfh(struct net_device *dev, u32 *ring_index, u8 *key,
@@ -1189,6 +1190,8 @@ static int mlx4_en_set_rxfh(struct net_device *dev, const u32 *ring_index,
                priv->prof->rss_rings = rss_rings;
        if (key)
                memcpy(priv->rss_key, key, MLX4_EN_RSS_KEY_SIZE);
+       if (hfunc !=  ETH_RSS_HASH_NO_CHANGE)
+               priv->rss_hash_fn = hfunc;
 
        if (port_up) {
                err = mlx4_en_start_port(dev);
index 0f1afc085d580b34e0eda1eaa4b1cdc1737c71be..cf467a9f6cc78c0c8a53b9120cec2795888f4904 100644 (file)
@@ -1467,6 +1467,7 @@ static void mlx4_en_service_task(struct work_struct *work)
                if (mdev->dev->caps.flags2 & MLX4_DEV_CAP_FLAG2_TS)
                        mlx4_en_ptp_overflow_check(mdev);
 
+               mlx4_en_recover_from_oom(priv);
                queue_delayed_work(mdev->workqueue, &priv->service_task,
                                   SERVICE_TASK_DELAY);
        }
@@ -1500,17 +1501,13 @@ static int mlx4_en_init_affinity_hint(struct mlx4_en_priv *priv, int ring_idx)
 {
        struct mlx4_en_rx_ring *ring = priv->rx_ring[ring_idx];
        int numa_node = priv->mdev->dev->numa_node;
-       int ret = 0;
 
        if (!zalloc_cpumask_var(&ring->affinity_mask, GFP_KERNEL))
                return -ENOMEM;
 
-       ret = cpumask_set_cpu_local_first(ring_idx, numa_node,
-                                         ring->affinity_mask);
-       if (ret)
-               free_cpumask_var(ring->affinity_mask);
-
-       return ret;
+       cpumask_set_cpu(cpumask_local_spread(ring_idx, numa_node),
+                       ring->affinity_mask);
+       return 0;
 }
 
 static void mlx4_en_free_affinity_hint(struct mlx4_en_priv *priv, int ring_idx)
@@ -1721,7 +1718,7 @@ mac_err:
 cq_err:
        while (rx_index--) {
                mlx4_en_deactivate_cq(priv, priv->rx_cq[rx_index]);
-               mlx4_en_free_affinity_hint(priv, i);
+               mlx4_en_free_affinity_hint(priv, rx_index);
        }
        for (i = 0; i < priv->rx_ring_num; i++)
                mlx4_en_deactivate_rx_ring(priv, priv->rx_ring[i]);
index 54f0e5ab2e55ca87dc66a2ef8b4e27062a634ce4..0a56f010c8468d0734c3afd791605843d373b91a 100644 (file)
@@ -139,7 +139,7 @@ static unsigned long en_stats_adder(__be64 *start, __be64 *next, int num)
        int i;
        int offset = next - start;
 
-       for (i = 0; i <= num; i++) {
+       for (i = 0; i < num; i++) {
                ret += be64_to_cpu(*curr);
                curr += offset;
        }
index 4fdd3c37e47bf7c7862b9edf569be6f7f38e8dae..2a77a6b191216b19059c89fa8ad386252684806c 100644 (file)
@@ -244,6 +244,12 @@ static int mlx4_en_prepare_rx_desc(struct mlx4_en_priv *priv,
        return mlx4_en_alloc_frags(priv, rx_desc, frags, ring->page_alloc, gfp);
 }
 
+static inline bool mlx4_en_is_ring_empty(struct mlx4_en_rx_ring *ring)
+{
+       BUG_ON((u32)(ring->prod - ring->cons) > ring->actual_size);
+       return ring->prod == ring->cons;
+}
+
 static inline void mlx4_en_update_rx_prod_db(struct mlx4_en_rx_ring *ring)
 {
        *ring->wqres.db.db = cpu_to_be32(ring->prod & 0xffff);
@@ -315,8 +321,7 @@ static void mlx4_en_free_rx_buf(struct mlx4_en_priv *priv,
               ring->cons, ring->prod);
 
        /* Unmap and free Rx buffers */
-       BUG_ON((u32) (ring->prod - ring->cons) > ring->actual_size);
-       while (ring->cons != ring->prod) {
+       while (!mlx4_en_is_ring_empty(ring)) {
                index = ring->cons & ring->size_mask;
                en_dbg(DRV, priv, "Processing descriptor:%d\n", index);
                mlx4_en_free_rx_desc(priv, ring, index);
@@ -491,6 +496,23 @@ err_allocator:
        return err;
 }
 
+/* We recover from out of memory by scheduling our napi poll
+ * function (mlx4_en_process_cq), which tries to allocate
+ * all missing RX buffers (call to mlx4_en_refill_rx_buffers).
+ */
+void mlx4_en_recover_from_oom(struct mlx4_en_priv *priv)
+{
+       int ring;
+
+       if (!priv->port_up)
+               return;
+
+       for (ring = 0; ring < priv->rx_ring_num; ring++) {
+               if (mlx4_en_is_ring_empty(priv->rx_ring[ring]))
+                       napi_reschedule(&priv->rx_cq[ring]->napi);
+       }
+}
+
 void mlx4_en_destroy_rx_ring(struct mlx4_en_priv *priv,
                             struct mlx4_en_rx_ring **pring,
                             u32 size, u16 stride)
index 1783705273d89773c0a462cb28684f2969e55ac4..7bed3a88579fa9db92d7e42ad7d43265bd8a3d41 100644 (file)
@@ -143,8 +143,10 @@ int mlx4_en_create_tx_ring(struct mlx4_en_priv *priv,
        ring->hwtstamp_tx_type = priv->hwtstamp_config.tx_type;
        ring->queue_index = queue_index;
 
-       if (queue_index < priv->num_tx_rings_p_up && cpu_online(queue_index))
-               cpumask_set_cpu(queue_index, &ring->affinity_mask);
+       if (queue_index < priv->num_tx_rings_p_up)
+               cpumask_set_cpu(cpumask_local_spread(queue_index,
+                                                    priv->mdev->dev->numa_node),
+                               &ring->affinity_mask);
 
        *pring = ring;
        return 0;
@@ -213,7 +215,7 @@ int mlx4_en_activate_tx_ring(struct mlx4_en_priv *priv,
 
        err = mlx4_qp_to_ready(mdev->dev, &ring->wqres.mtt, &ring->context,
                               &ring->qp, &ring->qp_state);
-       if (!user_prio && cpu_online(ring->queue_index))
+       if (!cpumask_empty(&ring->affinity_mask))
                netif_set_xps_queue(priv->dev, &ring->affinity_mask,
                                    ring->queue_index);
 
index a4079811b176f1afeba6c16e84bbcc29e8d3e463..e30bf57ad7a18ff559eb4bba122252eaf0308964 100644 (file)
@@ -56,11 +56,13 @@ MODULE_PARM_DESC(enable_qos, "Enable Enhanced QoS support (default: on)");
 #define MLX4_GET(dest, source, offset)                               \
        do {                                                          \
                void *__p = (char *) (source) + (offset);             \
+               u64 val;                                              \
                switch (sizeof (dest)) {                              \
                case 1: (dest) = *(u8 *) __p;       break;            \
                case 2: (dest) = be16_to_cpup(__p); break;            \
                case 4: (dest) = be32_to_cpup(__p); break;            \
-               case 8: (dest) = be64_to_cpup(__p); break;            \
+               case 8: val = get_unaligned((u64 *)__p);              \
+                       (dest) = be64_to_cpu(val);  break;            \
                default: __buggy_use_of_MLX4_GET();                   \
                }                                                     \
        } while (0)
@@ -1605,9 +1607,17 @@ static void get_board_id(void *vsd, char *board_id)
                 * swaps each 4-byte word before passing it back to
                 * us.  Therefore we need to swab it before printing.
                 */
-               for (i = 0; i < 4; ++i)
-                       ((u32 *) board_id)[i] =
-                               swab32(*(u32 *) (vsd + VSD_OFFSET_MLX_BOARD_ID + i * 4));
+               u32 *bid_u32 = (u32 *)board_id;
+
+               for (i = 0; i < 4; ++i) {
+                       u32 *addr;
+                       u32 val;
+
+                       addr = (u32 *) (vsd + VSD_OFFSET_MLX_BOARD_ID + i * 4);
+                       val = get_unaligned(addr);
+                       val = swab32(val);
+                       put_unaligned(val, &bid_u32[i]);
+               }
        }
 }
 
index 9de30216b146bb09188a6867307b5bbcf7aa9dd0..d021f079f181b06bb6ec73250ea8493ad87d1cee 100644 (file)
@@ -774,6 +774,7 @@ int mlx4_en_activate_tx_ring(struct mlx4_en_priv *priv,
 void mlx4_en_deactivate_tx_ring(struct mlx4_en_priv *priv,
                                struct mlx4_en_tx_ring *ring);
 void mlx4_en_set_num_rx_rings(struct mlx4_en_dev *mdev);
+void mlx4_en_recover_from_oom(struct mlx4_en_priv *priv);
 int mlx4_en_create_rx_ring(struct mlx4_en_priv *priv,
                           struct mlx4_en_rx_ring **pring,
                           u32 size, u16 stride, int node);
index c7f28bf4b8e21436cc927c8212c5cc6b57706e51..bafe2180cf0c413c4d971f8043e401a018dc8100 100644 (file)
@@ -2845,7 +2845,7 @@ int mlx4_SW2HW_EQ_wrapper(struct mlx4_dev *dev, int slave,
 {
        int err;
        int eqn = vhcr->in_modifier;
-       int res_id = (slave << 8) | eqn;
+       int res_id = (slave << 10) | eqn;
        struct mlx4_eq_context *eqc = inbox->buf;
        int mtt_base = eq_get_mtt_addr(eqc) / dev->caps.mtt_entry_sz;
        int mtt_size = eq_get_mtt_size(eqc);
@@ -3051,7 +3051,7 @@ int mlx4_HW2SW_EQ_wrapper(struct mlx4_dev *dev, int slave,
                          struct mlx4_cmd_info *cmd)
 {
        int eqn = vhcr->in_modifier;
-       int res_id = eqn | (slave << 8);
+       int res_id = eqn | (slave << 10);
        struct res_eq *eq;
        int err;
 
@@ -3108,7 +3108,7 @@ int mlx4_GEN_EQE(struct mlx4_dev *dev, int slave, struct mlx4_eqe *eqe)
                return 0;
 
        mutex_lock(&priv->mfunc.master.gen_eqe_mutex[slave]);
-       res_id = (slave << 8) | event_eq->eqn;
+       res_id = (slave << 10) | event_eq->eqn;
        err = get_res(dev, slave, res_id, RES_EQ, &req);
        if (err)
                goto unlock;
@@ -3131,7 +3131,7 @@ int mlx4_GEN_EQE(struct mlx4_dev *dev, int slave, struct mlx4_eqe *eqe)
 
        memcpy(mailbox->buf, (u8 *) eqe, 28);
 
-       in_modifier = (slave & 0xff) | ((event_eq->eqn & 0xff) << 16);
+       in_modifier = (slave & 0xff) | ((event_eq->eqn & 0x3ff) << 16);
 
        err = mlx4_cmd(dev, mailbox->dma, in_modifier, 0,
                       MLX4_CMD_GEN_EQE, MLX4_CMD_TIME_CLASS_B,
@@ -3157,7 +3157,7 @@ int mlx4_QUERY_EQ_wrapper(struct mlx4_dev *dev, int slave,
                          struct mlx4_cmd_info *cmd)
 {
        int eqn = vhcr->in_modifier;
-       int res_id = eqn | (slave << 8);
+       int res_id = eqn | (slave << 10);
        struct res_eq *eq;
        int err;
 
@@ -3187,7 +3187,7 @@ int mlx4_SW2HW_CQ_wrapper(struct mlx4_dev *dev, int slave,
        int cqn = vhcr->in_modifier;
        struct mlx4_cq_context *cqc = inbox->buf;
        int mtt_base = cq_get_mtt_addr(cqc) / dev->caps.mtt_entry_sz;
-       struct res_cq *cq;
+       struct res_cq *cq = NULL;
        struct res_mtt *mtt;
 
        err = cq_res_start_move_to(dev, slave, cqn, RES_CQ_HW, &cq);
@@ -3223,7 +3223,7 @@ int mlx4_HW2SW_CQ_wrapper(struct mlx4_dev *dev, int slave,
 {
        int err;
        int cqn = vhcr->in_modifier;
-       struct res_cq *cq;
+       struct res_cq *cq = NULL;
 
        err = cq_res_start_move_to(dev, slave, cqn, RES_CQ_ALLOCATED, &cq);
        if (err)
@@ -3362,7 +3362,7 @@ int mlx4_SW2HW_SRQ_wrapper(struct mlx4_dev *dev, int slave,
        int err;
        int srqn = vhcr->in_modifier;
        struct res_mtt *mtt;
-       struct res_srq *srq;
+       struct res_srq *srq = NULL;
        struct mlx4_srq_context *srqc = inbox->buf;
        int mtt_base = srq_get_mtt_addr(srqc) / dev->caps.mtt_entry_sz;
 
@@ -3406,7 +3406,7 @@ int mlx4_HW2SW_SRQ_wrapper(struct mlx4_dev *dev, int slave,
 {
        int err;
        int srqn = vhcr->in_modifier;
-       struct res_srq *srq;
+       struct res_srq *srq = NULL;
 
        err = srq_res_start_move_to(dev, slave, srqn, RES_SRQ_ALLOCATED, &srq);
        if (err)
@@ -4714,13 +4714,13 @@ static void rem_slave_eqs(struct mlx4_dev *dev, int slave)
                                        break;
 
                                case RES_EQ_HW:
-                                       err = mlx4_cmd(dev, slave, eqn & 0xff,
+                                       err = mlx4_cmd(dev, slave, eqn & 0x3ff,
                                                       1, MLX4_CMD_HW2SW_EQ,
                                                       MLX4_CMD_TIME_CLASS_A,
                                                       MLX4_CMD_NATIVE);
                                        if (err)
                                                mlx4_dbg(dev, "rem_slave_eqs: failed to move slave %d eqs %d to SW ownership\n",
-                                                        slave, eqn);
+                                                        slave, eqn & 0x3ff);
                                        atomic_dec(&eq->mtt->ref_count);
                                        state = RES_EQ_RESERVED;
                                        break;
index 1412f5af05ecf521e41ff109dc1a24e7621090ce..2bae50292dcd814a2b8cb338da1bb0a6beac82f0 100644 (file)
 #include <net/ip.h>
 #include <net/tcp.h>
 #include <asm/byteorder.h>
-#include <asm/io.h>
 #include <asm/processor.h>
-#ifdef CONFIG_MTRR
-#include <asm/mtrr.h>
-#endif
 #include <net/busy_poll.h>
 
 #include "myri10ge_mcp.h"
@@ -242,8 +238,7 @@ struct myri10ge_priv {
        unsigned int rdma_tags_available;
        int intr_coal_delay;
        __be32 __iomem *intr_coal_delay_ptr;
-       int mtrr;
-       int wc_enabled;
+       int wc_cookie;
        int down_cnt;
        wait_queue_head_t down_wq;
        struct work_struct watchdog_work;
@@ -1905,7 +1900,7 @@ static const char myri10ge_gstrings_main_stats[][ETH_GSTRING_LEN] = {
        "tx_aborted_errors", "tx_carrier_errors", "tx_fifo_errors",
        "tx_heartbeat_errors", "tx_window_errors",
        /* device-specific stats */
-       "tx_boundary", "WC", "irq", "MSI", "MSIX",
+       "tx_boundary", "irq", "MSI", "MSIX",
        "read_dma_bw_MBs", "write_dma_bw_MBs", "read_write_dma_bw_MBs",
        "serial_number", "watchdog_resets",
 #ifdef CONFIG_MYRI10GE_DCA
@@ -1984,7 +1979,6 @@ myri10ge_get_ethtool_stats(struct net_device *netdev,
                data[i] = ((u64 *)&link_stats)[i];
 
        data[i++] = (unsigned int)mgp->tx_boundary;
-       data[i++] = (unsigned int)mgp->wc_enabled;
        data[i++] = (unsigned int)mgp->pdev->irq;
        data[i++] = (unsigned int)mgp->msi_enabled;
        data[i++] = (unsigned int)mgp->msix_enabled;
@@ -4040,14 +4034,7 @@ static int myri10ge_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
 
        mgp->board_span = pci_resource_len(pdev, 0);
        mgp->iomem_base = pci_resource_start(pdev, 0);
-       mgp->mtrr = -1;
-       mgp->wc_enabled = 0;
-#ifdef CONFIG_MTRR
-       mgp->mtrr = mtrr_add(mgp->iomem_base, mgp->board_span,
-                            MTRR_TYPE_WRCOMB, 1);
-       if (mgp->mtrr >= 0)
-               mgp->wc_enabled = 1;
-#endif
+       mgp->wc_cookie = arch_phys_wc_add(mgp->iomem_base, mgp->board_span);
        mgp->sram = ioremap_wc(mgp->iomem_base, mgp->board_span);
        if (mgp->sram == NULL) {
                dev_err(&pdev->dev, "ioremap failed for %ld bytes at 0x%lx\n",
@@ -4146,14 +4133,14 @@ static int myri10ge_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
                goto abort_with_state;
        }
        if (mgp->msix_enabled)
-               dev_info(dev, "%d MSI-X IRQs, tx bndry %d, fw %s, WC %s\n",
+               dev_info(dev, "%d MSI-X IRQs, tx bndry %d, fw %s, MTRR %s, WC Enabled\n",
                         mgp->num_slices, mgp->tx_boundary, mgp->fw_name,
-                        (mgp->wc_enabled ? "Enabled" : "Disabled"));
+                        (mgp->wc_cookie > 0 ? "Enabled" : "Disabled"));
        else
-               dev_info(dev, "%s IRQ %d, tx bndry %d, fw %s, WC %s\n",
+               dev_info(dev, "%s IRQ %d, tx bndry %d, fw %s, MTRR %s, WC Enabled\n",
                         mgp->msi_enabled ? "MSI" : "xPIC",
                         pdev->irq, mgp->tx_boundary, mgp->fw_name,
-                        (mgp->wc_enabled ? "Enabled" : "Disabled"));
+                        (mgp->wc_cookie > 0 ? "Enabled" : "Disabled"));
 
        board_number++;
        return 0;
@@ -4175,10 +4162,7 @@ abort_with_ioremap:
        iounmap(mgp->sram);
 
 abort_with_mtrr:
-#ifdef CONFIG_MTRR
-       if (mgp->mtrr >= 0)
-               mtrr_del(mgp->mtrr, mgp->iomem_base, mgp->board_span);
-#endif
+       arch_phys_wc_del(mgp->wc_cookie);
        dma_free_coherent(&pdev->dev, sizeof(*mgp->cmd),
                          mgp->cmd, mgp->cmd_bus);
 
@@ -4220,11 +4204,7 @@ static void myri10ge_remove(struct pci_dev *pdev)
        pci_restore_state(pdev);
 
        iounmap(mgp->sram);
-
-#ifdef CONFIG_MTRR
-       if (mgp->mtrr >= 0)
-               mtrr_del(mgp->mtrr, mgp->iomem_base, mgp->board_span);
-#endif
+       arch_phys_wc_del(mgp->wc_cookie);
        myri10ge_free_slices(mgp);
        kfree(mgp->msix_vectors);
        dma_free_coherent(&pdev->dev, sizeof(*mgp->cmd),
index 5c4068353f664e8924f832c3d681ec41f53465c6..7b43a3b4abdcbc7bc1cdfd4d13c611563e2760a2 100644 (file)
@@ -135,7 +135,7 @@ void netxen_release_tx_buffers(struct netxen_adapter *adapter)
        int i, j;
        struct nx_host_tx_ring *tx_ring = adapter->tx_ring;
 
-       spin_lock(&adapter->tx_clean_lock);
+       spin_lock_bh(&adapter->tx_clean_lock);
        cmd_buf = tx_ring->cmd_buf_arr;
        for (i = 0; i < tx_ring->num_desc; i++) {
                buffrag = cmd_buf->frag_array;
@@ -159,7 +159,7 @@ void netxen_release_tx_buffers(struct netxen_adapter *adapter)
                }
                cmd_buf++;
        }
-       spin_unlock(&adapter->tx_clean_lock);
+       spin_unlock_bh(&adapter->tx_clean_lock);
 }
 
 void netxen_free_sw_resources(struct netxen_adapter *adapter)
@@ -1764,7 +1764,7 @@ int netxen_process_cmd_ring(struct netxen_adapter *adapter)
        int done = 0;
        struct nx_host_tx_ring *tx_ring = adapter->tx_ring;
 
-       if (!spin_trylock(&adapter->tx_clean_lock))
+       if (!spin_trylock_bh(&adapter->tx_clean_lock))
                return 1;
 
        sw_consumer = tx_ring->sw_consumer;
@@ -1819,7 +1819,7 @@ int netxen_process_cmd_ring(struct netxen_adapter *adapter)
         */
        hw_consumer = le32_to_cpu(*(tx_ring->hw_consumer));
        done = (sw_consumer == hw_consumer);
-       spin_unlock(&adapter->tx_clean_lock);
+       spin_unlock_bh(&adapter->tx_clean_lock);
 
        return done;
 }
index e0c31e3947d1091371bfa742fbea5cee9743002d..6409a06bbdf633b0ce440bf817aabfe69311dd1e 100644 (file)
@@ -3025,9 +3025,9 @@ netxen_sysfs_read_dimm(struct file *filp, struct kobject *kobj,
        u8 dw, rows, cols, banks, ranks;
        u32 val;
 
-       if (size != sizeof(struct netxen_dimm_cfg)) {
+       if (size < attr->size) {
                netdev_err(netdev, "Invalid size\n");
-               return -1;
+               return -EINVAL;
        }
 
        memset(&dimm, 0, sizeof(struct netxen_dimm_cfg));
@@ -3137,7 +3137,7 @@ out:
 
 static struct bin_attribute bin_attr_dimm = {
        .attr = { .name = "dimm", .mode = (S_IRUGO | S_IWUSR) },
-       .size = 0,
+       .size = sizeof(struct netxen_dimm_cfg),
        .read = netxen_sysfs_read_dimm,
 };
 
index f66641d961e3bc18ae15a301323497ff9fb265e8..6af028d5f9bcbdcc3aae303a114fd64d87986eed 100644 (file)
@@ -912,6 +912,8 @@ qca_spi_probe(struct spi_device *spi_device)
        qca->spi_dev = spi_device;
        qca->legacy_mode = legacy_mode;
 
+       spi_set_drvdata(spi_device, qcaspi_devs);
+
        mac = of_get_mac_address(spi_device->dev.of_node);
 
        if (mac)
@@ -944,8 +946,6 @@ qca_spi_probe(struct spi_device *spi_device)
                return -EFAULT;
        }
 
-       spi_set_drvdata(spi_device, qcaspi_devs);
-
        qcaspi_init_device_debugfs(qca);
 
        return 0;
index c70ab40d86989974d54c9161bf7acd8558d93c74..3df51faf18ae3ba8ce6bb7f49e6f51e4da1be738 100644 (file)
@@ -6884,7 +6884,7 @@ static void r8169_csum_workaround(struct rtl8169_private *tp,
                        rtl8169_start_xmit(nskb, tp->dev);
                } while (segs);
 
-               dev_kfree_skb(skb);
+               dev_consume_skb_any(skb);
        } else if (skb->ip_summed == CHECKSUM_PARTIAL) {
                if (skb_checksum_help(skb) < 0)
                        goto drop;
@@ -6896,7 +6896,7 @@ static void r8169_csum_workaround(struct rtl8169_private *tp,
 drop:
                stats = &tp->dev->stats;
                stats->tx_dropped++;
-               dev_kfree_skb(skb);
+               dev_kfree_skb_any(skb);
        }
 }
 
index a570a60533be5531c5881ace3683e69e9d80ece5..cf98cc9bbc8dc9d57545bbbe25592f6878fcf324 100644 (file)
@@ -2921,10 +2921,11 @@ static int rocker_port_ipv4_resolve(struct rocker_port *rocker_port,
        struct neighbour *n = __ipv4_neigh_lookup(dev, (__force u32)ip_addr);
        int err = 0;
 
-       if (!n)
+       if (!n) {
                n = neigh_create(&arp_tbl, &ip_addr, dev);
-       if (!n)
-               return -ENOMEM;
+               if (IS_ERR(n))
+                       return IS_ERR(n);
+       }
 
        /* If the neigh is already resolved, then go ahead and
         * install the entry, otherwise start the ARP process to
@@ -2936,6 +2937,7 @@ static int rocker_port_ipv4_resolve(struct rocker_port *rocker_port,
        else
                neigh_event_send(n, NULL);
 
+       neigh_release(n);
        return err;
 }
 
@@ -4176,14 +4178,15 @@ static int rocker_port_bridge_setlink(struct net_device *dev,
 
 static int rocker_port_bridge_getlink(struct sk_buff *skb, u32 pid, u32 seq,
                                      struct net_device *dev,
-                                     u32 filter_mask)
+                                     u32 filter_mask, int nlflags)
 {
        struct rocker_port *rocker_port = netdev_priv(dev);
        u16 mode = BRIDGE_MODE_UNDEF;
        u32 mask = BR_LEARNING | BR_LEARNING_SYNC;
 
        return ndo_dflt_bridge_getlink(skb, pid, seq, dev, mode,
-                                      rocker_port->brport_flags, mask);
+                                      rocker_port->brport_flags, mask,
+                                      nlflags);
 }
 
 static int rocker_port_get_phys_port_name(struct net_device *dev,
index c0ad95d2f63d9a12cd300aa0420ddda661ccaed1..809ea4610a77e774af0413d896e8ec802946d8fa 100644 (file)
@@ -224,12 +224,17 @@ static void efx_unmap_rx_buffer(struct efx_nic *efx,
        }
 }
 
-static void efx_free_rx_buffer(struct efx_rx_buffer *rx_buf)
+static void efx_free_rx_buffers(struct efx_rx_queue *rx_queue,
+                               struct efx_rx_buffer *rx_buf,
+                               unsigned int num_bufs)
 {
-       if (rx_buf->page) {
-               put_page(rx_buf->page);
-               rx_buf->page = NULL;
-       }
+       do {
+               if (rx_buf->page) {
+                       put_page(rx_buf->page);
+                       rx_buf->page = NULL;
+               }
+               rx_buf = efx_rx_buf_next(rx_queue, rx_buf);
+       } while (--num_bufs);
 }
 
 /* Attempt to recycle the page if there is an RX recycle ring; the page can
@@ -278,7 +283,7 @@ static void efx_fini_rx_buffer(struct efx_rx_queue *rx_queue,
        /* If this is the last buffer in a page, unmap and free it. */
        if (rx_buf->flags & EFX_RX_BUF_LAST_IN_PAGE) {
                efx_unmap_rx_buffer(rx_queue->efx, rx_buf);
-               efx_free_rx_buffer(rx_buf);
+               efx_free_rx_buffers(rx_queue, rx_buf, 1);
        }
        rx_buf->page = NULL;
 }
@@ -304,10 +309,7 @@ static void efx_discard_rx_packet(struct efx_channel *channel,
 
        efx_recycle_rx_pages(channel, rx_buf, n_frags);
 
-       do {
-               efx_free_rx_buffer(rx_buf);
-               rx_buf = efx_rx_buf_next(rx_queue, rx_buf);
-       } while (--n_frags);
+       efx_free_rx_buffers(rx_queue, rx_buf, n_frags);
 }
 
 /**
@@ -431,11 +433,10 @@ efx_rx_packet_gro(struct efx_channel *channel, struct efx_rx_buffer *rx_buf,
 
        skb = napi_get_frags(napi);
        if (unlikely(!skb)) {
-               while (n_frags--) {
-                       put_page(rx_buf->page);
-                       rx_buf->page = NULL;
-                       rx_buf = efx_rx_buf_next(&channel->rx_queue, rx_buf);
-               }
+               struct efx_rx_queue *rx_queue;
+
+               rx_queue = efx_channel_get_rx_queue(channel);
+               efx_free_rx_buffers(rx_queue, rx_buf, n_frags);
                return;
        }
 
@@ -622,7 +623,10 @@ static void efx_rx_deliver(struct efx_channel *channel, u8 *eh,
 
        skb = efx_rx_mk_skb(channel, rx_buf, n_frags, eh, hdr_len);
        if (unlikely(skb == NULL)) {
-               efx_free_rx_buffer(rx_buf);
+               struct efx_rx_queue *rx_queue;
+
+               rx_queue = efx_channel_get_rx_queue(channel);
+               efx_free_rx_buffers(rx_queue, rx_buf, n_frags);
                return;
        }
        skb_record_rx_queue(skb, channel->rx_queue.core_index);
@@ -661,8 +665,12 @@ void __efx_rx_packet(struct efx_channel *channel)
         * loopback layer, and free the rx_buf here
         */
        if (unlikely(efx->loopback_selftest)) {
+               struct efx_rx_queue *rx_queue;
+
                efx_loopback_rx_packet(efx, eh, rx_buf->len);
-               efx_free_rx_buffer(rx_buf);
+               rx_queue = efx_channel_get_rx_queue(channel);
+               efx_free_rx_buffers(rx_queue, rx_buf,
+                                   channel->rx_pkt_n_frags);
                goto out;
        }
 
index 14b363a25c023c70f13b73e9c485bf28e9d533e2..630f0b7800e47e085c5ffb2db6ac23efef9ad08c 100644 (file)
@@ -2238,9 +2238,10 @@ static int smc_drv_probe(struct platform_device *pdev)
        const struct of_device_id *match = NULL;
        struct smc_local *lp;
        struct net_device *ndev;
-       struct resource *res, *ires;
+       struct resource *res;
        unsigned int __iomem *addr;
        unsigned long irq_flags = SMC_IRQ_FLAGS;
+       unsigned long irq_resflags;
        int ret;
 
        ndev = alloc_etherdev(sizeof(struct smc_local));
@@ -2332,16 +2333,19 @@ static int smc_drv_probe(struct platform_device *pdev)
                goto out_free_netdev;
        }
 
-       ires = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
-       if (!ires) {
+       ndev->irq = platform_get_irq(pdev, 0);
+       if (ndev->irq <= 0) {
                ret = -ENODEV;
                goto out_release_io;
        }
-
-       ndev->irq = ires->start;
-
-       if (irq_flags == -1 || ires->flags & IRQF_TRIGGER_MASK)
-               irq_flags = ires->flags & IRQF_TRIGGER_MASK;
+       /*
+        * If this platform does not specify any special irqflags, or if
+        * the resource supplies a trigger, override the irqflags with
+        * the trigger flags from the resource.
+        */
+       irq_resflags = irqd_get_trigger_type(irq_get_irq_data(ndev->irq));
+       if (irq_flags == -1 || irq_resflags & IRQF_TRIGGER_MASK)
+               irq_flags = irq_resflags & IRQF_TRIGGER_MASK;
 
        ret = smc_request_attrib(pdev, ndev);
        if (ret)
index 41047c9143d0a66cde1441311fb5feb3ce0796d0..959aeeade0c97b8cbf5ee27024ecda185c6258b2 100644 (file)
@@ -2418,9 +2418,9 @@ static int smsc911x_drv_probe(struct platform_device *pdev)
        struct net_device *dev;
        struct smsc911x_data *pdata;
        struct smsc911x_platform_config *config = dev_get_platdata(&pdev->dev);
-       struct resource *res, *irq_res;
+       struct resource *res;
        unsigned int intcfg = 0;
-       int res_size, irq_flags;
+       int res_size, irq, irq_flags;
        int retval;
 
        res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
@@ -2434,8 +2434,8 @@ static int smsc911x_drv_probe(struct platform_device *pdev)
        }
        res_size = resource_size(res);
 
-       irq_res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
-       if (!irq_res) {
+       irq = platform_get_irq(pdev, 0);
+       if (irq <= 0) {
                pr_warn("Could not allocate irq resource\n");
                retval = -ENODEV;
                goto out_0;
@@ -2455,8 +2455,8 @@ static int smsc911x_drv_probe(struct platform_device *pdev)
        SET_NETDEV_DEV(dev, &pdev->dev);
 
        pdata = netdev_priv(dev);
-       dev->irq = irq_res->start;
-       irq_flags = irq_res->flags & IRQF_TRIGGER_MASK;
+       dev->irq = irq;
+       irq_flags = irq_get_trigger_type(irq);
        pdata->ioaddr = ioremap_nocache(res->start, res_size);
 
        pdata->dev = dev;
index 2ac9552d1fa385953e261ff3797c74b8d5ad4add..73bab983edd96a47169bf4b1957e5fd13c28a3a0 100644 (file)
@@ -117,6 +117,12 @@ struct stmmac_priv {
        int use_riwt;
        int irq_wake;
        spinlock_t ptp_lock;
+
+#ifdef CONFIG_DEBUG_FS
+       struct dentry *dbgfs_dir;
+       struct dentry *dbgfs_rings_status;
+       struct dentry *dbgfs_dma_cap;
+#endif
 };
 
 int stmmac_mdio_unregister(struct net_device *ndev);
index 05c146f718a36551c4fe4ada4871f2612f16571d..2c5ce2baca8712790d51096a53868b84466f7dde 100644 (file)
@@ -118,7 +118,7 @@ static irqreturn_t stmmac_interrupt(int irq, void *dev_id);
 
 #ifdef CONFIG_DEBUG_FS
 static int stmmac_init_fs(struct net_device *dev);
-static void stmmac_exit_fs(void);
+static void stmmac_exit_fs(struct net_device *dev);
 #endif
 
 #define STMMAC_COAL_TIMER(x) (jiffies + usecs_to_jiffies(x))
@@ -1916,7 +1916,7 @@ static int stmmac_release(struct net_device *dev)
        netif_carrier_off(dev);
 
 #ifdef CONFIG_DEBUG_FS
-       stmmac_exit_fs();
+       stmmac_exit_fs(dev);
 #endif
 
        stmmac_release_ptp(priv);
@@ -2508,8 +2508,6 @@ static int stmmac_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
 
 #ifdef CONFIG_DEBUG_FS
 static struct dentry *stmmac_fs_dir;
-static struct dentry *stmmac_rings_status;
-static struct dentry *stmmac_dma_cap;
 
 static void sysfs_display_ring(void *head, int size, int extend_desc,
                               struct seq_file *seq)
@@ -2648,36 +2646,39 @@ static const struct file_operations stmmac_dma_cap_fops = {
 
 static int stmmac_init_fs(struct net_device *dev)
 {
-       /* Create debugfs entries */
-       stmmac_fs_dir = debugfs_create_dir(STMMAC_RESOURCE_NAME, NULL);
+       struct stmmac_priv *priv = netdev_priv(dev);
+
+       /* Create per netdev entries */
+       priv->dbgfs_dir = debugfs_create_dir(dev->name, stmmac_fs_dir);
 
-       if (!stmmac_fs_dir || IS_ERR(stmmac_fs_dir)) {
-               pr_err("ERROR %s, debugfs create directory failed\n",
-                      STMMAC_RESOURCE_NAME);
+       if (!priv->dbgfs_dir || IS_ERR(priv->dbgfs_dir)) {
+               pr_err("ERROR %s/%s, debugfs create directory failed\n",
+                      STMMAC_RESOURCE_NAME, dev->name);
 
                return -ENOMEM;
        }
 
        /* Entry to report DMA RX/TX rings */
-       stmmac_rings_status = debugfs_create_file("descriptors_status",
-                                                 S_IRUGO, stmmac_fs_dir, dev,
-                                                 &stmmac_rings_status_fops);
+       priv->dbgfs_rings_status =
+               debugfs_create_file("descriptors_status", S_IRUGO,
+                                   priv->dbgfs_dir, dev,
+                                   &stmmac_rings_status_fops);
 
-       if (!stmmac_rings_status || IS_ERR(stmmac_rings_status)) {
+       if (!priv->dbgfs_rings_status || IS_ERR(priv->dbgfs_rings_status)) {
                pr_info("ERROR creating stmmac ring debugfs file\n");
-               debugfs_remove(stmmac_fs_dir);
+               debugfs_remove_recursive(priv->dbgfs_dir);
 
                return -ENOMEM;
        }
 
        /* Entry to report the DMA HW features */
-       stmmac_dma_cap = debugfs_create_file("dma_cap", S_IRUGO, stmmac_fs_dir,
-                                            dev, &stmmac_dma_cap_fops);
+       priv->dbgfs_dma_cap = debugfs_create_file("dma_cap", S_IRUGO,
+                                           priv->dbgfs_dir,
+                                           dev, &stmmac_dma_cap_fops);
 
-       if (!stmmac_dma_cap || IS_ERR(stmmac_dma_cap)) {
+       if (!priv->dbgfs_dma_cap || IS_ERR(priv->dbgfs_dma_cap)) {
                pr_info("ERROR creating stmmac MMC debugfs file\n");
-               debugfs_remove(stmmac_rings_status);
-               debugfs_remove(stmmac_fs_dir);
+               debugfs_remove_recursive(priv->dbgfs_dir);
 
                return -ENOMEM;
        }
@@ -2685,11 +2686,11 @@ static int stmmac_init_fs(struct net_device *dev)
        return 0;
 }
 
-static void stmmac_exit_fs(void)
+static void stmmac_exit_fs(struct net_device *dev)
 {
-       debugfs_remove(stmmac_rings_status);
-       debugfs_remove(stmmac_dma_cap);
-       debugfs_remove(stmmac_fs_dir);
+       struct stmmac_priv *priv = netdev_priv(dev);
+
+       debugfs_remove_recursive(priv->dbgfs_dir);
 }
 #endif /* CONFIG_DEBUG_FS */
 
@@ -3149,6 +3150,35 @@ err:
 __setup("stmmaceth=", stmmac_cmdline_opt);
 #endif /* MODULE */
 
+static int __init stmmac_init(void)
+{
+#ifdef CONFIG_DEBUG_FS
+       /* Create debugfs main directory if it doesn't exist yet */
+       if (!stmmac_fs_dir) {
+               stmmac_fs_dir = debugfs_create_dir(STMMAC_RESOURCE_NAME, NULL);
+
+               if (!stmmac_fs_dir || IS_ERR(stmmac_fs_dir)) {
+                       pr_err("ERROR %s, debugfs create directory failed\n",
+                              STMMAC_RESOURCE_NAME);
+
+                       return -ENOMEM;
+               }
+       }
+#endif
+
+       return 0;
+}
+
+static void __exit stmmac_exit(void)
+{
+#ifdef CONFIG_DEBUG_FS
+       debugfs_remove_recursive(stmmac_fs_dir);
+#endif
+}
+
+module_init(stmmac_init)
+module_exit(stmmac_exit)
+
 MODULE_DESCRIPTION("STMMAC 10/100/1000 Ethernet device driver");
 MODULE_AUTHOR("Giuseppe Cavallaro <peppe.cavallaro@st.com>");
 MODULE_LICENSE("GPL");
index 705bbdf9394058944927fd575d1dfc47cdb283d5..68aec5c460db46c1378cdf122c3ad8f4eba15e86 100644 (file)
@@ -23,6 +23,7 @@
 *******************************************************************************/
 
 #include <linux/platform_device.h>
+#include <linux/module.h>
 #include <linux/io.h>
 #include <linux/of.h>
 #include <linux/of_net.h>
index 2bef655279f32a4ffb6097b295362e2da22867c0..9b7e0a34c98b10aca5eed610c47f33b2eedbbd00 100644 (file)
@@ -1765,7 +1765,9 @@ static void netcp_ethss_link_state_action(struct gbe_priv *gbe_dev,
                                     ALE_PORT_STATE,
                                     ALE_PORT_STATE_FORWARD);
 
-               if (ndev && slave->open)
+               if (ndev && slave->open &&
+                   slave->link_interface != SGMII_LINK_MAC_PHY &&
+                   slave->link_interface != XGMII_LINK_MAC_PHY)
                        netif_carrier_on(ndev);
        } else {
                writel(mac_control, GBE_REG_ADDR(slave, emac_regs,
@@ -1773,7 +1775,9 @@ static void netcp_ethss_link_state_action(struct gbe_priv *gbe_dev,
                cpsw_ale_control_set(gbe_dev->ale, slave->port_num,
                                     ALE_PORT_STATE,
                                     ALE_PORT_STATE_DISABLE);
-               if (ndev)
+               if (ndev &&
+                   slave->link_interface != SGMII_LINK_MAC_PHY &&
+                   slave->link_interface != XGMII_LINK_MAC_PHY)
                        netif_carrier_off(ndev);
        }
 
index 690a4c36b3166c76b4d8ed63f9d21574ecac8bb3..af2694dc6f90146fc2afe9073a0dde7058731f59 100644 (file)
@@ -707,8 +707,8 @@ static int temac_start_xmit(struct sk_buff *skb, struct net_device *ndev)
 
        cur_p->app0 |= STS_CTRL_APP0_SOP;
        cur_p->len = skb_headlen(skb);
-       cur_p->phys = dma_map_single(ndev->dev.parent, skb->data, skb->len,
-                                    DMA_TO_DEVICE);
+       cur_p->phys = dma_map_single(ndev->dev.parent, skb->data,
+                                    skb_headlen(skb), DMA_TO_DEVICE);
        cur_p->app4 = (unsigned long)skb;
 
        for (ii = 0; ii < num_frag; ii++) {
index a10b31664709f51215435d94a9439c65d311221b..41071d32bc8e0e1259726aa647bc8a77324ffdd9 100644 (file)
@@ -128,7 +128,6 @@ struct ndis_tcp_ip_checksum_info;
 struct hv_netvsc_packet {
        /* Bookkeeping stuff */
        u32 status;
-       bool part_of_skb;
 
        bool is_data_pkt;
        bool xmit_more; /* from skb */
@@ -612,6 +611,15 @@ struct multi_send_data {
        u32 count; /* counter of batched packets */
 };
 
+/* The context of the netvsc device  */
+struct net_device_context {
+       /* point back to our device context */
+       struct hv_device *device_ctx;
+       struct delayed_work dwork;
+       struct work_struct work;
+       u32 msg_enable; /* debug level */
+};
+
 /* Per netvsc device */
 struct netvsc_device {
        struct hv_device *dev;
@@ -667,6 +675,9 @@ struct netvsc_device {
        struct multi_send_data msd[NR_CPUS];
        u32 max_pkt; /* max number of pkt in one send, e.g. 8 */
        u32 pkt_align; /* alignment bytes, e.g. 8 */
+
+       /* The net device context */
+       struct net_device_context *nd_ctx;
 };
 
 /* NdisInitialize message */
index 2e8ad0636b466668e8939e4eabe442160e6c2402..ea091bc5ff09dad379fde915fbb7ec073c613aa1 100644 (file)
@@ -826,7 +826,6 @@ int netvsc_send(struct hv_device *device,
        u16 q_idx = packet->q_idx;
        u32 pktlen = packet->total_data_buflen, msd_len = 0;
        unsigned int section_index = NETVSC_INVALID_INDEX;
-       struct sk_buff *skb = NULL;
        unsigned long flag;
        struct multi_send_data *msdp;
        struct hv_netvsc_packet *msd_send = NULL, *cur_send = NULL;
@@ -889,11 +888,6 @@ int netvsc_send(struct hv_device *device,
                } else {
                        packet->page_buf_cnt = 0;
                        packet->total_data_buflen += msd_len;
-                       if (!packet->part_of_skb) {
-                               skb = (struct sk_buff *)(unsigned long)packet->
-                                      send_completion_tid;
-                               packet->send_completion_tid = 0;
-                       }
                }
 
                if (msdp->pkt)
@@ -929,12 +923,8 @@ int netvsc_send(struct hv_device *device,
        if (cur_send)
                ret = netvsc_send_pkt(cur_send, net_device);
 
-       if (ret != 0) {
-               if (section_index != NETVSC_INVALID_INDEX)
-                       netvsc_free_send_slot(net_device, section_index);
-       } else if (skb) {
-               dev_kfree_skb_any(skb);
-       }
+       if (ret != 0 && section_index != NETVSC_INVALID_INDEX)
+               netvsc_free_send_slot(net_device, section_index);
 
        return ret;
 }
@@ -1197,6 +1187,9 @@ int netvsc_device_add(struct hv_device *device, void *additional_info)
         */
        ndev = net_device->ndev;
 
+       /* Add netvsc_device context to netvsc_device */
+       net_device->nd_ctx = netdev_priv(ndev);
+
        /* Initialize the NetVSC channel extension */
        init_completion(&net_device->channel_init_wait);
 
index a3a9d3898a6e8a80ddb21cb11864c09006e47554..5993c7e2d723a7e42d6022c90cb8e495420a49ad 100644 (file)
 
 #include "hyperv_net.h"
 
-struct net_device_context {
-       /* point back to our device context */
-       struct hv_device *device_ctx;
-       struct delayed_work dwork;
-       struct work_struct work;
-};
 
 #define RING_SIZE_MIN 64
 static int ring_size = 128;
 module_param(ring_size, int, S_IRUGO);
 MODULE_PARM_DESC(ring_size, "Ring buffer size (# of pages)");
 
+static const u32 default_msg = NETIF_MSG_DRV | NETIF_MSG_PROBE |
+                               NETIF_MSG_LINK | NETIF_MSG_IFUP |
+                               NETIF_MSG_IFDOWN | NETIF_MSG_RX_ERR |
+                               NETIF_MSG_TX_ERR;
+
+static int debug = -1;
+module_param(debug, int, S_IRUGO);
+MODULE_PARM_DESC(debug, "Debug level (0=none,...,16=all)");
+
 static void do_set_multicast(struct work_struct *w)
 {
        struct net_device_context *ndevctx =
@@ -235,9 +238,6 @@ void netvsc_xmit_completion(void *context)
        struct sk_buff *skb = (struct sk_buff *)
                (unsigned long)packet->send_completion_tid;
 
-       if (!packet->part_of_skb)
-               kfree(packet);
-
        if (skb)
                dev_kfree_skb_any(skb);
 }
@@ -389,7 +389,6 @@ static int netvsc_start_xmit(struct sk_buff *skb, struct net_device *net)
        u32 net_trans_info;
        u32 hash;
        u32 skb_length;
-       u32 head_room;
        u32 pkt_sz;
        struct hv_page_buffer page_buf[MAX_PAGE_BUFFER_COUNT];
 
@@ -402,7 +401,6 @@ static int netvsc_start_xmit(struct sk_buff *skb, struct net_device *net)
 
 check_size:
        skb_length = skb->len;
-       head_room = skb_headroom(skb);
        num_data_pgs = netvsc_get_slots(skb) + 2;
        if (num_data_pgs > MAX_PAGE_BUFFER_COUNT && linear) {
                net_alert_ratelimited("packet too big: %u pages (%u bytes)\n",
@@ -421,20 +419,14 @@ check_size:
 
        pkt_sz = sizeof(struct hv_netvsc_packet) + RNDIS_AND_PPI_SIZE;
 
-       if (head_room < pkt_sz) {
-               packet = kmalloc(pkt_sz, GFP_ATOMIC);
-               if (!packet) {
-                       /* out of memory, drop packet */
-                       netdev_err(net, "unable to alloc hv_netvsc_packet\n");
-                       ret = -ENOMEM;
-                       goto drop;
-               }
-               packet->part_of_skb = false;
-       } else {
-               /* Use the headroom for building up the packet */
-               packet = (struct hv_netvsc_packet *)skb->head;
-               packet->part_of_skb = true;
+       ret = skb_cow_head(skb, pkt_sz);
+       if (ret) {
+               netdev_err(net, "unable to alloc hv_netvsc_packet\n");
+               ret = -ENOMEM;
+               goto drop;
        }
+       /* Use the headroom for building up the packet */
+       packet = (struct hv_netvsc_packet *)skb->head;
 
        packet->status = 0;
        packet->xmit_more = skb->xmit_more;
@@ -591,8 +583,6 @@ drop:
                net->stats.tx_bytes += skb_length;
                net->stats.tx_packets++;
        } else {
-               if (packet && !packet->part_of_skb)
-                       kfree(packet);
                if (ret != -EAGAIN) {
                        dev_kfree_skb_any(skb);
                        net->stats.tx_dropped++;
@@ -888,6 +878,11 @@ static int netvsc_probe(struct hv_device *dev,
 
        net_device_ctx = netdev_priv(net);
        net_device_ctx->device_ctx = dev;
+       net_device_ctx->msg_enable = netif_msg_init(debug, default_msg);
+       if (netif_msg_probe(net_device_ctx))
+               netdev_dbg(net, "netvsc msg_enable: %d\n",
+                          net_device_ctx->msg_enable);
+
        hv_set_drvdata(dev, net);
        INIT_DELAYED_WORK(&net_device_ctx->dwork, netvsc_link_change);
        INIT_WORK(&net_device_ctx->work, do_set_multicast);
index 0d92efefd796c9b631beeca1b35ad9979cb36d2f..9118cea918821cb6bbe83a2f97a71134a58fd5dd 100644 (file)
@@ -429,7 +429,8 @@ int rndis_filter_receive(struct hv_device *dev,
 
        rndis_msg = pkt->data;
 
-       dump_rndis_message(dev, rndis_msg);
+       if (netif_msg_rx_err(net_dev->nd_ctx))
+               dump_rndis_message(dev, rndis_msg);
 
        switch (rndis_msg->ndis_msg_type) {
        case RNDIS_MSG_PACKET:
index 38026650c0387ecb101d085e24273bf24ded2783..67d00fbc2e0e29e7bd426ed8f7d21b22bf6772fc 100644 (file)
@@ -85,6 +85,7 @@ struct at86rf230_local {
        struct ieee802154_hw *hw;
        struct at86rf2xx_chip_data *data;
        struct regmap *regmap;
+       int slp_tr;
 
        struct completion state_complete;
        struct at86rf230_state_change state;
@@ -95,163 +96,164 @@ struct at86rf230_local {
        unsigned long cal_timeout;
        s8 max_frame_retries;
        bool is_tx;
+       bool is_tx_from_off;
        u8 tx_retry;
        struct sk_buff *tx_skb;
        struct at86rf230_state_change tx;
 };
 
-#define        RG_TRX_STATUS   (0x01)
-#define        SR_TRX_STATUS           0x01, 0x1f, 0
-#define        SR_RESERVED_01_3        0x01, 0x20, 5
-#define        SR_CCA_STATUS           0x01, 0x40, 6
-#define        SR_CCA_DONE             0x01, 0x80, 7
-#define        RG_TRX_STATE    (0x02)
-#define        SR_TRX_CMD              0x02, 0x1f, 0
-#define        SR_TRAC_STATUS          0x02, 0xe0, 5
-#define        RG_TRX_CTRL_0   (0x03)
-#define        SR_CLKM_CTRL            0x03, 0x07, 0
-#define        SR_CLKM_SHA_SEL         0x03, 0x08, 3
-#define        SR_PAD_IO_CLKM          0x03, 0x30, 4
-#define        SR_PAD_IO               0x03, 0xc0, 6
-#define        RG_TRX_CTRL_1   (0x04)
-#define        SR_IRQ_POLARITY         0x04, 0x01, 0
-#define        SR_IRQ_MASK_MODE        0x04, 0x02, 1
-#define        SR_SPI_CMD_MODE         0x04, 0x0c, 2
-#define        SR_RX_BL_CTRL           0x04, 0x10, 4
-#define        SR_TX_AUTO_CRC_ON       0x04, 0x20, 5
-#define        SR_IRQ_2_EXT_EN         0x04, 0x40, 6
-#define        SR_PA_EXT_EN            0x04, 0x80, 7
-#define        RG_PHY_TX_PWR   (0x05)
-#define        SR_TX_PWR               0x05, 0x0f, 0
-#define        SR_PA_LT                0x05, 0x30, 4
-#define        SR_PA_BUF_LT            0x05, 0xc0, 6
-#define        RG_PHY_RSSI     (0x06)
-#define        SR_RSSI                 0x06, 0x1f, 0
-#define        SR_RND_VALUE            0x06, 0x60, 5
-#define        SR_RX_CRC_VALID         0x06, 0x80, 7
-#define        RG_PHY_ED_LEVEL (0x07)
-#define        SR_ED_LEVEL             0x07, 0xff, 0
-#define        RG_PHY_CC_CCA   (0x08)
-#define        SR_CHANNEL              0x08, 0x1f, 0
-#define        SR_CCA_MODE             0x08, 0x60, 5
-#define        SR_CCA_REQUEST          0x08, 0x80, 7
-#define        RG_CCA_THRES    (0x09)
-#define        SR_CCA_ED_THRES         0x09, 0x0f, 0
-#define        SR_RESERVED_09_1        0x09, 0xf0, 4
-#define        RG_RX_CTRL      (0x0a)
-#define        SR_PDT_THRES            0x0a, 0x0f, 0
-#define        SR_RESERVED_0a_1        0x0a, 0xf0, 4
-#define        RG_SFD_VALUE    (0x0b)
-#define        SR_SFD_VALUE            0x0b, 0xff, 0
-#define        RG_TRX_CTRL_2   (0x0c)
-#define        SR_OQPSK_DATA_RATE      0x0c, 0x03, 0
-#define        SR_SUB_MODE             0x0c, 0x04, 2
-#define        SR_BPSK_QPSK            0x0c, 0x08, 3
-#define        SR_OQPSK_SUB1_RC_EN     0x0c, 0x10, 4
-#define        SR_RESERVED_0c_5        0x0c, 0x60, 5
-#define        SR_RX_SAFE_MODE         0x0c, 0x80, 7
-#define        RG_ANT_DIV      (0x0d)
-#define        SR_ANT_CTRL             0x0d, 0x03, 0
-#define        SR_ANT_EXT_SW_EN        0x0d, 0x04, 2
-#define        SR_ANT_DIV_EN           0x0d, 0x08, 3
-#define        SR_RESERVED_0d_2        0x0d, 0x70, 4
-#define        SR_ANT_SEL              0x0d, 0x80, 7
-#define        RG_IRQ_MASK     (0x0e)
-#define        SR_IRQ_MASK             0x0e, 0xff, 0
-#define        RG_IRQ_STATUS   (0x0f)
-#define        SR_IRQ_0_PLL_LOCK       0x0f, 0x01, 0
-#define        SR_IRQ_1_PLL_UNLOCK     0x0f, 0x02, 1
-#define        SR_IRQ_2_RX_START       0x0f, 0x04, 2
-#define        SR_IRQ_3_TRX_END        0x0f, 0x08, 3
-#define        SR_IRQ_4_CCA_ED_DONE    0x0f, 0x10, 4
-#define        SR_IRQ_5_AMI            0x0f, 0x20, 5
-#define        SR_IRQ_6_TRX_UR         0x0f, 0x40, 6
-#define        SR_IRQ_7_BAT_LOW        0x0f, 0x80, 7
-#define        RG_VREG_CTRL    (0x10)
-#define        SR_RESERVED_10_6        0x10, 0x03, 0
-#define        SR_DVDD_OK              0x10, 0x04, 2
-#define        SR_DVREG_EXT            0x10, 0x08, 3
-#define        SR_RESERVED_10_3        0x10, 0x30, 4
-#define        SR_AVDD_OK              0x10, 0x40, 6
-#define        SR_AVREG_EXT            0x10, 0x80, 7
-#define        RG_BATMON       (0x11)
-#define        SR_BATMON_VTH           0x11, 0x0f, 0
-#define        SR_BATMON_HR            0x11, 0x10, 4
-#define        SR_BATMON_OK            0x11, 0x20, 5
-#define        SR_RESERVED_11_1        0x11, 0xc0, 6
-#define        RG_XOSC_CTRL    (0x12)
-#define        SR_XTAL_TRIM            0x12, 0x0f, 0
-#define        SR_XTAL_MODE            0x12, 0xf0, 4
-#define        RG_RX_SYN       (0x15)
-#define        SR_RX_PDT_LEVEL         0x15, 0x0f, 0
-#define        SR_RESERVED_15_2        0x15, 0x70, 4
-#define        SR_RX_PDT_DIS           0x15, 0x80, 7
-#define        RG_XAH_CTRL_1   (0x17)
-#define        SR_RESERVED_17_8        0x17, 0x01, 0
-#define        SR_AACK_PROM_MODE       0x17, 0x02, 1
-#define        SR_AACK_ACK_TIME        0x17, 0x04, 2
-#define        SR_RESERVED_17_5        0x17, 0x08, 3
-#define        SR_AACK_UPLD_RES_FT     0x17, 0x10, 4
-#define        SR_AACK_FLTR_RES_FT     0x17, 0x20, 5
-#define        SR_CSMA_LBT_MODE        0x17, 0x40, 6
-#define        SR_RESERVED_17_1        0x17, 0x80, 7
-#define        RG_FTN_CTRL     (0x18)
-#define        SR_RESERVED_18_2        0x18, 0x7f, 0
-#define        SR_FTN_START            0x18, 0x80, 7
-#define        RG_PLL_CF       (0x1a)
-#define        SR_RESERVED_1a_2        0x1a, 0x7f, 0
-#define        SR_PLL_CF_START         0x1a, 0x80, 7
-#define        RG_PLL_DCU      (0x1b)
-#define        SR_RESERVED_1b_3        0x1b, 0x3f, 0
-#define        SR_RESERVED_1b_2        0x1b, 0x40, 6
-#define        SR_PLL_DCU_START        0x1b, 0x80, 7
-#define        RG_PART_NUM     (0x1c)
-#define        SR_PART_NUM             0x1c, 0xff, 0
-#define        RG_VERSION_NUM  (0x1d)
-#define        SR_VERSION_NUM          0x1d, 0xff, 0
-#define        RG_MAN_ID_0     (0x1e)
-#define        SR_MAN_ID_0             0x1e, 0xff, 0
-#define        RG_MAN_ID_1     (0x1f)
-#define        SR_MAN_ID_1             0x1f, 0xff, 0
-#define        RG_SHORT_ADDR_0 (0x20)
-#define        SR_SHORT_ADDR_0         0x20, 0xff, 0
-#define        RG_SHORT_ADDR_1 (0x21)
-#define        SR_SHORT_ADDR_1         0x21, 0xff, 0
-#define        RG_PAN_ID_0     (0x22)
-#define        SR_PAN_ID_0             0x22, 0xff, 0
-#define        RG_PAN_ID_1     (0x23)
-#define        SR_PAN_ID_1             0x23, 0xff, 0
-#define        RG_IEEE_ADDR_0  (0x24)
-#define        SR_IEEE_ADDR_0          0x24, 0xff, 0
-#define        RG_IEEE_ADDR_1  (0x25)
-#define        SR_IEEE_ADDR_1          0x25, 0xff, 0
-#define        RG_IEEE_ADDR_2  (0x26)
-#define        SR_IEEE_ADDR_2          0x26, 0xff, 0
-#define        RG_IEEE_ADDR_3  (0x27)
-#define        SR_IEEE_ADDR_3          0x27, 0xff, 0
-#define        RG_IEEE_ADDR_4  (0x28)
-#define        SR_IEEE_ADDR_4          0x28, 0xff, 0
-#define        RG_IEEE_ADDR_5  (0x29)
-#define        SR_IEEE_ADDR_5          0x29, 0xff, 0
-#define        RG_IEEE_ADDR_6  (0x2a)
-#define        SR_IEEE_ADDR_6          0x2a, 0xff, 0
-#define        RG_IEEE_ADDR_7  (0x2b)
-#define        SR_IEEE_ADDR_7          0x2b, 0xff, 0
-#define        RG_XAH_CTRL_0   (0x2c)
-#define        SR_SLOTTED_OPERATION    0x2c, 0x01, 0
-#define        SR_MAX_CSMA_RETRIES     0x2c, 0x0e, 1
-#define        SR_MAX_FRAME_RETRIES    0x2c, 0xf0, 4
-#define        RG_CSMA_SEED_0  (0x2d)
-#define        SR_CSMA_SEED_0          0x2d, 0xff, 0
-#define        RG_CSMA_SEED_1  (0x2e)
-#define        SR_CSMA_SEED_1          0x2e, 0x07, 0
-#define        SR_AACK_I_AM_COORD      0x2e, 0x08, 3
-#define        SR_AACK_DIS_ACK         0x2e, 0x10, 4
-#define        SR_AACK_SET_PD          0x2e, 0x20, 5
-#define        SR_AACK_FVN_MODE        0x2e, 0xc0, 6
-#define        RG_CSMA_BE      (0x2f)
-#define        SR_MIN_BE               0x2f, 0x0f, 0
-#define        SR_MAX_BE               0x2f, 0xf0, 4
+#define RG_TRX_STATUS  (0x01)
+#define SR_TRX_STATUS          0x01, 0x1f, 0
+#define SR_RESERVED_01_3       0x01, 0x20, 5
+#define SR_CCA_STATUS          0x01, 0x40, 6
+#define SR_CCA_DONE            0x01, 0x80, 7
+#define RG_TRX_STATE   (0x02)
+#define SR_TRX_CMD             0x02, 0x1f, 0
+#define SR_TRAC_STATUS         0x02, 0xe0, 5
+#define RG_TRX_CTRL_0  (0x03)
+#define SR_CLKM_CTRL           0x03, 0x07, 0
+#define SR_CLKM_SHA_SEL                0x03, 0x08, 3
+#define SR_PAD_IO_CLKM         0x03, 0x30, 4
+#define SR_PAD_IO              0x03, 0xc0, 6
+#define RG_TRX_CTRL_1  (0x04)
+#define SR_IRQ_POLARITY                0x04, 0x01, 0
+#define SR_IRQ_MASK_MODE       0x04, 0x02, 1
+#define SR_SPI_CMD_MODE                0x04, 0x0c, 2
+#define SR_RX_BL_CTRL          0x04, 0x10, 4
+#define SR_TX_AUTO_CRC_ON      0x04, 0x20, 5
+#define SR_IRQ_2_EXT_EN                0x04, 0x40, 6
+#define SR_PA_EXT_EN           0x04, 0x80, 7
+#define RG_PHY_TX_PWR  (0x05)
+#define SR_TX_PWR              0x05, 0x0f, 0
+#define SR_PA_LT               0x05, 0x30, 4
+#define SR_PA_BUF_LT           0x05, 0xc0, 6
+#define RG_PHY_RSSI    (0x06)
+#define SR_RSSI                        0x06, 0x1f, 0
+#define SR_RND_VALUE           0x06, 0x60, 5
+#define SR_RX_CRC_VALID                0x06, 0x80, 7
+#define RG_PHY_ED_LEVEL        (0x07)
+#define SR_ED_LEVEL            0x07, 0xff, 0
+#define RG_PHY_CC_CCA  (0x08)
+#define SR_CHANNEL             0x08, 0x1f, 0
+#define SR_CCA_MODE            0x08, 0x60, 5
+#define SR_CCA_REQUEST         0x08, 0x80, 7
+#define RG_CCA_THRES   (0x09)
+#define SR_CCA_ED_THRES                0x09, 0x0f, 0
+#define SR_RESERVED_09_1       0x09, 0xf0, 4
+#define RG_RX_CTRL     (0x0a)
+#define SR_PDT_THRES           0x0a, 0x0f, 0
+#define SR_RESERVED_0a_1       0x0a, 0xf0, 4
+#define RG_SFD_VALUE   (0x0b)
+#define SR_SFD_VALUE           0x0b, 0xff, 0
+#define RG_TRX_CTRL_2  (0x0c)
+#define SR_OQPSK_DATA_RATE     0x0c, 0x03, 0
+#define SR_SUB_MODE            0x0c, 0x04, 2
+#define SR_BPSK_QPSK           0x0c, 0x08, 3
+#define SR_OQPSK_SUB1_RC_EN    0x0c, 0x10, 4
+#define SR_RESERVED_0c_5       0x0c, 0x60, 5
+#define SR_RX_SAFE_MODE                0x0c, 0x80, 7
+#define RG_ANT_DIV     (0x0d)
+#define SR_ANT_CTRL            0x0d, 0x03, 0
+#define SR_ANT_EXT_SW_EN       0x0d, 0x04, 2
+#define SR_ANT_DIV_EN          0x0d, 0x08, 3
+#define SR_RESERVED_0d_2       0x0d, 0x70, 4
+#define SR_ANT_SEL             0x0d, 0x80, 7
+#define RG_IRQ_MASK    (0x0e)
+#define SR_IRQ_MASK            0x0e, 0xff, 0
+#define RG_IRQ_STATUS  (0x0f)
+#define SR_IRQ_0_PLL_LOCK      0x0f, 0x01, 0
+#define SR_IRQ_1_PLL_UNLOCK    0x0f, 0x02, 1
+#define SR_IRQ_2_RX_START      0x0f, 0x04, 2
+#define SR_IRQ_3_TRX_END       0x0f, 0x08, 3
+#define SR_IRQ_4_CCA_ED_DONE   0x0f, 0x10, 4
+#define SR_IRQ_5_AMI           0x0f, 0x20, 5
+#define SR_IRQ_6_TRX_UR                0x0f, 0x40, 6
+#define SR_IRQ_7_BAT_LOW       0x0f, 0x80, 7
+#define RG_VREG_CTRL   (0x10)
+#define SR_RESERVED_10_6       0x10, 0x03, 0
+#define SR_DVDD_OK             0x10, 0x04, 2
+#define SR_DVREG_EXT           0x10, 0x08, 3
+#define SR_RESERVED_10_3       0x10, 0x30, 4
+#define SR_AVDD_OK             0x10, 0x40, 6
+#define SR_AVREG_EXT           0x10, 0x80, 7
+#define RG_BATMON      (0x11)
+#define SR_BATMON_VTH          0x11, 0x0f, 0
+#define SR_BATMON_HR           0x11, 0x10, 4
+#define SR_BATMON_OK           0x11, 0x20, 5
+#define SR_RESERVED_11_1       0x11, 0xc0, 6
+#define RG_XOSC_CTRL   (0x12)
+#define SR_XTAL_TRIM           0x12, 0x0f, 0
+#define SR_XTAL_MODE           0x12, 0xf0, 4
+#define RG_RX_SYN      (0x15)
+#define SR_RX_PDT_LEVEL                0x15, 0x0f, 0
+#define SR_RESERVED_15_2       0x15, 0x70, 4
+#define SR_RX_PDT_DIS          0x15, 0x80, 7
+#define RG_XAH_CTRL_1  (0x17)
+#define SR_RESERVED_17_8       0x17, 0x01, 0
+#define SR_AACK_PROM_MODE      0x17, 0x02, 1
+#define SR_AACK_ACK_TIME       0x17, 0x04, 2
+#define SR_RESERVED_17_5       0x17, 0x08, 3
+#define SR_AACK_UPLD_RES_FT    0x17, 0x10, 4
+#define SR_AACK_FLTR_RES_FT    0x17, 0x20, 5
+#define SR_CSMA_LBT_MODE       0x17, 0x40, 6
+#define SR_RESERVED_17_1       0x17, 0x80, 7
+#define RG_FTN_CTRL    (0x18)
+#define SR_RESERVED_18_2       0x18, 0x7f, 0
+#define SR_FTN_START           0x18, 0x80, 7
+#define RG_PLL_CF      (0x1a)
+#define SR_RESERVED_1a_2       0x1a, 0x7f, 0
+#define SR_PLL_CF_START                0x1a, 0x80, 7
+#define RG_PLL_DCU     (0x1b)
+#define SR_RESERVED_1b_3       0x1b, 0x3f, 0
+#define SR_RESERVED_1b_2       0x1b, 0x40, 6
+#define SR_PLL_DCU_START       0x1b, 0x80, 7
+#define RG_PART_NUM    (0x1c)
+#define SR_PART_NUM            0x1c, 0xff, 0
+#define RG_VERSION_NUM (0x1d)
+#define SR_VERSION_NUM         0x1d, 0xff, 0
+#define RG_MAN_ID_0    (0x1e)
+#define SR_MAN_ID_0            0x1e, 0xff, 0
+#define RG_MAN_ID_1    (0x1f)
+#define SR_MAN_ID_1            0x1f, 0xff, 0
+#define RG_SHORT_ADDR_0        (0x20)
+#define SR_SHORT_ADDR_0                0x20, 0xff, 0
+#define RG_SHORT_ADDR_1        (0x21)
+#define SR_SHORT_ADDR_1                0x21, 0xff, 0
+#define RG_PAN_ID_0    (0x22)
+#define SR_PAN_ID_0            0x22, 0xff, 0
+#define RG_PAN_ID_1    (0x23)
+#define SR_PAN_ID_1            0x23, 0xff, 0
+#define RG_IEEE_ADDR_0 (0x24)
+#define SR_IEEE_ADDR_0         0x24, 0xff, 0
+#define RG_IEEE_ADDR_1 (0x25)
+#define SR_IEEE_ADDR_1         0x25, 0xff, 0
+#define RG_IEEE_ADDR_2 (0x26)
+#define SR_IEEE_ADDR_2         0x26, 0xff, 0
+#define RG_IEEE_ADDR_3 (0x27)
+#define SR_IEEE_ADDR_3         0x27, 0xff, 0
+#define RG_IEEE_ADDR_4 (0x28)
+#define SR_IEEE_ADDR_4         0x28, 0xff, 0
+#define RG_IEEE_ADDR_5 (0x29)
+#define SR_IEEE_ADDR_5         0x29, 0xff, 0
+#define RG_IEEE_ADDR_6 (0x2a)
+#define SR_IEEE_ADDR_6         0x2a, 0xff, 0
+#define RG_IEEE_ADDR_7 (0x2b)
+#define SR_IEEE_ADDR_7         0x2b, 0xff, 0
+#define RG_XAH_CTRL_0  (0x2c)
+#define SR_SLOTTED_OPERATION   0x2c, 0x01, 0
+#define SR_MAX_CSMA_RETRIES    0x2c, 0x0e, 1
+#define SR_MAX_FRAME_RETRIES   0x2c, 0xf0, 4
+#define RG_CSMA_SEED_0 (0x2d)
+#define SR_CSMA_SEED_0         0x2d, 0xff, 0
+#define RG_CSMA_SEED_1 (0x2e)
+#define SR_CSMA_SEED_1         0x2e, 0x07, 0
+#define SR_AACK_I_AM_COORD     0x2e, 0x08, 3
+#define SR_AACK_DIS_ACK                0x2e, 0x10, 4
+#define SR_AACK_SET_PD         0x2e, 0x20, 5
+#define SR_AACK_FVN_MODE       0x2e, 0xc0, 6
+#define RG_CSMA_BE     (0x2f)
+#define SR_MIN_BE              0x2f, 0x0f, 0
+#define SR_MAX_BE              0x2f, 0xf0, 4
 
 #define CMD_REG                0x80
 #define CMD_REG_MASK   0x3f
@@ -292,6 +294,8 @@ struct at86rf230_local {
 #define STATE_BUSY_RX_AACK_NOCLK 0x1E
 #define STATE_TRANSITION_IN_PROGRESS 0x1F
 
+#define TRX_STATE_MASK         (0x1F)
+
 #define AT86RF2XX_NUMREGS 0x3F
 
 static void
@@ -336,6 +340,14 @@ at86rf230_write_subreg(struct at86rf230_local *lp,
        return regmap_update_bits(lp->regmap, addr, mask, data << shift);
 }
 
+static inline void
+at86rf230_slp_tr_rising_edge(struct at86rf230_local *lp)
+{
+       gpio_set_value(lp->slp_tr, 1);
+       udelay(1);
+       gpio_set_value(lp->slp_tr, 0);
+}
+
 static bool
 at86rf230_reg_writeable(struct device *dev, unsigned int reg)
 {
@@ -509,7 +521,7 @@ at86rf230_async_state_assert(void *context)
        struct at86rf230_state_change *ctx = context;
        struct at86rf230_local *lp = ctx->lp;
        const u8 *buf = ctx->buf;
-       const u8 trx_state = buf[1] & 0x1f;
+       const u8 trx_state = buf[1] & TRX_STATE_MASK;
 
        /* Assert state change */
        if (trx_state != ctx->to_state) {
@@ -609,11 +621,17 @@ at86rf230_async_state_delay(void *context)
                switch (ctx->to_state) {
                case STATE_RX_AACK_ON:
                        tim = ktime_set(0, c->t_off_to_aack * NSEC_PER_USEC);
+                       /* state change from TRX_OFF to RX_AACK_ON to do a
+                        * calibration, we need to reset the timeout for the
+                        * next one.
+                        */
+                       lp->cal_timeout = jiffies + AT86RF2XX_CAL_LOOP_TIMEOUT;
                        goto change;
+               case STATE_TX_ARET_ON:
                case STATE_TX_ON:
                        tim = ktime_set(0, c->t_off_to_tx_on * NSEC_PER_USEC);
-                       /* state change from TRX_OFF to TX_ON to do a
-                        * calibration, we need to reset the timeout for the
+                       /* state change from TRX_OFF to TX_ON or ARET_ON to do
+                        * calibration, we need to reset the timeout for the
                         * next one.
                         */
                        lp->cal_timeout = jiffies + AT86RF2XX_CAL_LOOP_TIMEOUT;
@@ -667,7 +685,7 @@ at86rf230_async_state_change_start(void *context)
        struct at86rf230_state_change *ctx = context;
        struct at86rf230_local *lp = ctx->lp;
        u8 *buf = ctx->buf;
-       const u8 trx_state = buf[1] & 0x1f;
+       const u8 trx_state = buf[1] & TRX_STATE_MASK;
        int rc;
 
        /* Check for "possible" STATE_TRANSITION_IN_PROGRESS */
@@ -772,16 +790,6 @@ at86rf230_tx_on(void *context)
                                     at86rf230_tx_complete, true);
 }
 
-static void
-at86rf230_tx_trac_error(void *context)
-{
-       struct at86rf230_state_change *ctx = context;
-       struct at86rf230_local *lp = ctx->lp;
-
-       at86rf230_async_state_change(lp, ctx, STATE_TX_ON,
-                                    at86rf230_tx_on, true);
-}
-
 static void
 at86rf230_tx_trac_check(void *context)
 {
@@ -791,12 +799,12 @@ at86rf230_tx_trac_check(void *context)
        const u8 trac = (buf[1] & 0xe0) >> 5;
 
        /* If trac status is different than zero we need to do a state change
-        * to STATE_FORCE_TRX_OFF then STATE_TX_ON to recover the transceiver
-        * state to TX_ON.
+        * to STATE_FORCE_TRX_OFF then STATE_RX_AACK_ON to recover the
+        * transceiver.
         */
        if (trac)
                at86rf230_async_state_change(lp, ctx, STATE_FORCE_TRX_OFF,
-                                            at86rf230_tx_trac_error, true);
+                                            at86rf230_tx_on, true);
        else
                at86rf230_tx_on(context);
 }
@@ -941,13 +949,18 @@ at86rf230_write_frame_complete(void *context)
        u8 *buf = ctx->buf;
        int rc;
 
-       buf[0] = (RG_TRX_STATE & CMD_REG_MASK) | CMD_REG | CMD_WRITE;
-       buf[1] = STATE_BUSY_TX;
        ctx->trx.len = 2;
-       ctx->msg.complete = NULL;
-       rc = spi_async(lp->spi, &ctx->msg);
-       if (rc)
-               at86rf230_async_error(lp, ctx, rc);
+
+       if (gpio_is_valid(lp->slp_tr)) {
+               at86rf230_slp_tr_rising_edge(lp);
+       } else {
+               buf[0] = (RG_TRX_STATE & CMD_REG_MASK) | CMD_REG | CMD_WRITE;
+               buf[1] = STATE_BUSY_TX;
+               ctx->msg.complete = NULL;
+               rc = spi_async(lp->spi, &ctx->msg);
+               if (rc)
+                       at86rf230_async_error(lp, ctx, rc);
+       }
 }
 
 static void
@@ -993,12 +1006,21 @@ at86rf230_xmit_start(void *context)
         * are in STATE_TX_ON. The pfad differs here, so we change
         * the complete handler.
         */
-       if (lp->tx_aret)
-               at86rf230_async_state_change(lp, ctx, STATE_TX_ON,
-                                            at86rf230_xmit_tx_on, false);
-       else
+       if (lp->tx_aret) {
+               if (lp->is_tx_from_off) {
+                       lp->is_tx_from_off = false;
+                       at86rf230_async_state_change(lp, ctx, STATE_TX_ARET_ON,
+                                                    at86rf230_xmit_tx_on,
+                                                    false);
+               } else {
+                       at86rf230_async_state_change(lp, ctx, STATE_TX_ON,
+                                                    at86rf230_xmit_tx_on,
+                                                    false);
+               }
+       } else {
                at86rf230_async_state_change(lp, ctx, STATE_TX_ON,
                                             at86rf230_write_frame, false);
+       }
 }
 
 static int
@@ -1017,11 +1039,13 @@ at86rf230_xmit(struct ieee802154_hw *hw, struct sk_buff *skb)
         * to TX_ON, the lp->cal_timeout should be reinit by state_delay
         * function then to start in the next 5 minutes.
         */
-       if (time_is_before_jiffies(lp->cal_timeout))
+       if (time_is_before_jiffies(lp->cal_timeout)) {
+               lp->is_tx_from_off = true;
                at86rf230_async_state_change(lp, ctx, STATE_TRX_OFF,
                                             at86rf230_xmit_start, false);
-       else
+       } else {
                at86rf230_xmit_start(ctx);
+       }
 
        return 0;
 }
@@ -1037,9 +1061,6 @@ at86rf230_ed(struct ieee802154_hw *hw, u8 *level)
 static int
 at86rf230_start(struct ieee802154_hw *hw)
 {
-       struct at86rf230_local *lp = hw->priv;
-
-       lp->cal_timeout = jiffies + AT86RF2XX_CAL_LOOP_TIMEOUT;
        return at86rf230_sync_state_change(hw->priv, STATE_RX_AACK_ON);
 }
 
@@ -1673,6 +1694,7 @@ static int at86rf230_probe(struct spi_device *spi)
        lp = hw->priv;
        lp->hw = hw;
        lp->spi = spi;
+       lp->slp_tr = slp_tr;
        hw->parent = &spi->dev;
        hw->vif_data_size = sizeof(*lp);
        ieee802154_random_extended_addr(&hw->phy->perm_extended_addr);
index b227a13f6473404a5082a0a99d4e7067b3daeaf7..9f59f17dc317a254641bdc48973ce78e089761bc 100644 (file)
@@ -599,10 +599,18 @@ static int macvlan_open(struct net_device *dev)
                        goto del_unicast;
        }
 
+       if (dev->flags & IFF_PROMISC) {
+               err = dev_set_promiscuity(lowerdev, 1);
+               if (err < 0)
+                       goto clear_multi;
+       }
+
 hash_add:
        macvlan_hash_add(vlan);
        return 0;
 
+clear_multi:
+       dev_set_allmulti(lowerdev, -1);
 del_unicast:
        dev_uc_del(lowerdev, dev->dev_addr);
 out:
@@ -638,6 +646,9 @@ static int macvlan_stop(struct net_device *dev)
        if (dev->flags & IFF_ALLMULTI)
                dev_set_allmulti(lowerdev, -1);
 
+       if (dev->flags & IFF_PROMISC)
+               dev_set_promiscuity(lowerdev, -1);
+
        dev_uc_del(lowerdev, dev->dev_addr);
 
 hash_del:
@@ -696,6 +707,10 @@ static void macvlan_change_rx_flags(struct net_device *dev, int change)
        if (dev->flags & IFF_UP) {
                if (change & IFF_ALLMULTI)
                        dev_set_allmulti(lowerdev, dev->flags & IFF_ALLMULTI ? 1 : -1);
+               if (change & IFF_PROMISC)
+                       dev_set_promiscuity(lowerdev,
+                                           dev->flags & IFF_PROMISC ? 1 : -1);
+
        }
 }
 
index 8fadaa14b9f0fbd97b689d7bab562eccd30d17bf..70641d2c042957e7e154b4a1d265f39fe3ffa386 100644 (file)
@@ -27,6 +27,7 @@ config AMD_PHY
 config AMD_XGBE_PHY
        tristate "Driver for the AMD 10GbE (amd-xgbe) PHYs"
        depends on (OF || ACPI) && HAS_IOMEM
+       depends on ARM64 || COMPILE_TEST
        ---help---
          Currently supports the AMD 10GbE PHY
 
index fb276f64cd6400cc7617c2586582c378eb2e9c53..34a75cba3b739ce5b4f28e1549915e19502fb4cc 100644 (file)
@@ -755,6 +755,45 @@ static int amd_xgbe_phy_set_mode(struct phy_device *phydev,
        return ret;
 }
 
+static bool amd_xgbe_phy_use_xgmii_mode(struct phy_device *phydev)
+{
+       if (phydev->autoneg == AUTONEG_ENABLE) {
+               if (phydev->advertising & ADVERTISED_10000baseKR_Full)
+                       return true;
+       } else {
+               if (phydev->speed == SPEED_10000)
+                       return true;
+       }
+
+       return false;
+}
+
+static bool amd_xgbe_phy_use_gmii_2500_mode(struct phy_device *phydev)
+{
+       if (phydev->autoneg == AUTONEG_ENABLE) {
+               if (phydev->advertising & ADVERTISED_2500baseX_Full)
+                       return true;
+       } else {
+               if (phydev->speed == SPEED_2500)
+                       return true;
+       }
+
+       return false;
+}
+
+static bool amd_xgbe_phy_use_gmii_mode(struct phy_device *phydev)
+{
+       if (phydev->autoneg == AUTONEG_ENABLE) {
+               if (phydev->advertising & ADVERTISED_1000baseKX_Full)
+                       return true;
+       } else {
+               if (phydev->speed == SPEED_1000)
+                       return true;
+       }
+
+       return false;
+}
+
 static int amd_xgbe_phy_set_an(struct phy_device *phydev, bool enable,
                               bool restart)
 {
@@ -1235,11 +1274,11 @@ static int amd_xgbe_phy_config_init(struct phy_device *phydev)
        /* Set initial mode - call the mode setting routines
         * directly to insure we are properly configured
         */
-       if (phydev->advertising & SUPPORTED_10000baseKR_Full)
+       if (amd_xgbe_phy_use_xgmii_mode(phydev))
                ret = amd_xgbe_phy_xgmii_mode(phydev);
-       else if (phydev->advertising & SUPPORTED_1000baseKX_Full)
+       else if (amd_xgbe_phy_use_gmii_mode(phydev))
                ret = amd_xgbe_phy_gmii_mode(phydev);
-       else if (phydev->advertising & SUPPORTED_2500baseX_Full)
+       else if (amd_xgbe_phy_use_gmii_2500_mode(phydev))
                ret = amd_xgbe_phy_gmii_2500_mode(phydev);
        else
                ret = -EINVAL;
index 64c74c6a482806bfc5d2bb4f821b4b1ef085adfd..b5dc59de094eef06838d4601cacd9dbeaba04a6a 100644 (file)
@@ -404,7 +404,7 @@ static struct phy_driver bcm7xxx_driver[] = {
        .name           = "Broadcom BCM7425",
        .features       = PHY_GBIT_FEATURES |
                          SUPPORTED_Pause | SUPPORTED_Asym_Pause,
-       .flags          = 0,
+       .flags          = PHY_IS_INTERNAL,
        .config_init    = bcm7xxx_config_init,
        .config_aneg    = genphy_config_aneg,
        .read_status    = genphy_read_status,
index 496e02f961d37039ff56d5e45a8aa28aa0f44b91..00cb41e713123689803e5dddfa527c3ebaee26ae 100644 (file)
@@ -47,7 +47,7 @@
 #define PSF_TX         0x1000
 #define EXT_EVENT      1
 #define CAL_EVENT      7
-#define CAL_TRIGGER    7
+#define CAL_TRIGGER    1
 #define DP83640_N_PINS 12
 
 #define MII_DP83640_MICR 0x11
@@ -496,7 +496,9 @@ static int ptp_dp83640_enable(struct ptp_clock_info *ptp,
                        else
                                evnt |= EVNT_RISE;
                }
+               mutex_lock(&clock->extreg_lock);
                ext_write(0, phydev, PAGE5, PTP_EVNT, evnt);
+               mutex_unlock(&clock->extreg_lock);
                return 0;
 
        case PTP_CLK_REQ_PEROUT:
@@ -532,6 +534,8 @@ static u8 status_frame_src[6] = { 0x08, 0x00, 0x17, 0x0B, 0x6B, 0x0F };
 
 static void enable_status_frames(struct phy_device *phydev, bool on)
 {
+       struct dp83640_private *dp83640 = phydev->priv;
+       struct dp83640_clock *clock = dp83640->clock;
        u16 cfg0 = 0, ver;
 
        if (on)
@@ -539,9 +543,13 @@ static void enable_status_frames(struct phy_device *phydev, bool on)
 
        ver = (PSF_PTPVER & VERSIONPTP_MASK) << VERSIONPTP_SHIFT;
 
+       mutex_lock(&clock->extreg_lock);
+
        ext_write(0, phydev, PAGE5, PSF_CFG0, cfg0);
        ext_write(0, phydev, PAGE6, PSF_CFG1, ver);
 
+       mutex_unlock(&clock->extreg_lock);
+
        if (!phydev->attached_dev) {
                pr_warn("expected to find an attached netdevice\n");
                return;
@@ -838,7 +846,7 @@ static void decode_rxts(struct dp83640_private *dp83640,
        list_del_init(&rxts->list);
        phy2rxts(phy_rxts, rxts);
 
-       spin_lock_irqsave(&dp83640->rx_queue.lock, flags);
+       spin_lock(&dp83640->rx_queue.lock);
        skb_queue_walk(&dp83640->rx_queue, skb) {
                struct dp83640_skb_info *skb_info;
 
@@ -853,7 +861,7 @@ static void decode_rxts(struct dp83640_private *dp83640,
                        break;
                }
        }
-       spin_unlock_irqrestore(&dp83640->rx_queue.lock, flags);
+       spin_unlock(&dp83640->rx_queue.lock);
 
        if (!shhwtstamps)
                list_add_tail(&rxts->list, &dp83640->rxts);
@@ -1173,11 +1181,18 @@ static int dp83640_config_init(struct phy_device *phydev)
 
        if (clock->chosen && !list_empty(&clock->phylist))
                recalibrate(clock);
-       else
+       else {
+               mutex_lock(&clock->extreg_lock);
                enable_broadcast(phydev, clock->page, 1);
+               mutex_unlock(&clock->extreg_lock);
+       }
 
        enable_status_frames(phydev, true);
+
+       mutex_lock(&clock->extreg_lock);
        ext_write(0, phydev, PAGE4, PTP_CTL, PTP_ENABLE);
+       mutex_unlock(&clock->extreg_lock);
+
        return 0;
 }
 
index 49ce7ece5af30c04c3e632a1719ba45d9b47f3b5..53d18150f4e291bb4bb047a18a9877d3a82a08f4 100644 (file)
@@ -80,7 +80,8 @@ static void mdio_dir(struct mdiobb_ctrl *ctrl, int dir)
                 * assume the pin serves as pull-up. If direction is
                 * output, the default value is high.
                 */
-               gpio_set_value(bitbang->mdo, 1 ^ bitbang->mdo_active_low);
+               gpio_set_value_cansleep(bitbang->mdo,
+                                       1 ^ bitbang->mdo_active_low);
                return;
        }
 
@@ -96,7 +97,8 @@ static int mdio_get(struct mdiobb_ctrl *ctrl)
        struct mdio_gpio_info *bitbang =
                container_of(ctrl, struct mdio_gpio_info, ctrl);
 
-       return gpio_get_value(bitbang->mdio) ^ bitbang->mdio_active_low;
+       return gpio_get_value_cansleep(bitbang->mdio) ^
+               bitbang->mdio_active_low;
 }
 
 static void mdio_set(struct mdiobb_ctrl *ctrl, int what)
@@ -105,9 +107,11 @@ static void mdio_set(struct mdiobb_ctrl *ctrl, int what)
                container_of(ctrl, struct mdio_gpio_info, ctrl);
 
        if (bitbang->mdo)
-               gpio_set_value(bitbang->mdo, what ^ bitbang->mdo_active_low);
+               gpio_set_value_cansleep(bitbang->mdo,
+                                       what ^ bitbang->mdo_active_low);
        else
-               gpio_set_value(bitbang->mdio, what ^ bitbang->mdio_active_low);
+               gpio_set_value_cansleep(bitbang->mdio,
+                                       what ^ bitbang->mdio_active_low);
 }
 
 static void mdc_set(struct mdiobb_ctrl *ctrl, int what)
@@ -115,7 +119,7 @@ static void mdc_set(struct mdiobb_ctrl *ctrl, int what)
        struct mdio_gpio_info *bitbang =
                container_of(ctrl, struct mdio_gpio_info, ctrl);
 
-       gpio_set_value(bitbang->mdc, what ^ bitbang->mdc_active_low);
+       gpio_set_value_cansleep(bitbang->mdc, what ^ bitbang->mdc_active_low);
 }
 
 static struct mdiobb_ops mdio_gpio_ops = {
@@ -164,7 +168,10 @@ static struct mii_bus *mdio_gpio_bus_init(struct device *dev,
                if (!new_bus->irq[i])
                        new_bus->irq[i] = PHY_POLL;
 
-       snprintf(new_bus->id, MII_BUS_ID_SIZE, "gpio-%x", bus_id);
+       if (bus_id != -1)
+               snprintf(new_bus->id, MII_BUS_ID_SIZE, "gpio-%x", bus_id);
+       else
+               strncpy(new_bus->id, "gpio", MII_BUS_ID_SIZE);
 
        if (devm_gpio_request(dev, bitbang->mdc, "mdc"))
                goto out_free_bus;
index 1a87a585e74df9abac74d5a60c8715917b179ff9..66edd99bc302ddc5c5bdd0d0757acd7923adf8f4 100644 (file)
 #include <linux/module.h>
 #include <linux/phy.h>
 #include <linux/mdio-mux.h>
-#include <linux/of_gpio.h>
+#include <linux/gpio/consumer.h>
 
 #define DRV_VERSION "1.1"
 #define DRV_DESCRIPTION "GPIO controlled MDIO bus multiplexer driver"
 
-#define MDIO_MUX_GPIO_MAX_BITS 8
-
 struct mdio_mux_gpio_state {
-       struct gpio_desc *gpio[MDIO_MUX_GPIO_MAX_BITS];
-       unsigned int num_gpios;
+       struct gpio_descs *gpios;
        void *mux_handle;
 };
 
 static int mdio_mux_gpio_switch_fn(int current_child, int desired_child,
                                   void *data)
 {
-       int values[MDIO_MUX_GPIO_MAX_BITS];
-       unsigned int n;
        struct mdio_mux_gpio_state *s = data;
+       int values[s->gpios->ndescs];
+       unsigned int n;
 
        if (current_child == desired_child)
                return 0;
 
-       for (n = 0; n < s->num_gpios; n++) {
+       for (n = 0; n < s->gpios->ndescs; n++)
                values[n] = (desired_child >> n) & 1;
-       }
-       gpiod_set_array_cansleep(s->num_gpios, s->gpio, values);
+
+       gpiod_set_array_cansleep(s->gpios->ndescs, s->gpios->desc, values);
 
        return 0;
 }
@@ -46,56 +43,33 @@ static int mdio_mux_gpio_switch_fn(int current_child, int desired_child,
 static int mdio_mux_gpio_probe(struct platform_device *pdev)
 {
        struct mdio_mux_gpio_state *s;
-       int num_gpios;
-       unsigned int n;
        int r;
 
-       if (!pdev->dev.of_node)
-               return -ENODEV;
-
-       num_gpios = of_gpio_count(pdev->dev.of_node);
-       if (num_gpios <= 0 || num_gpios > MDIO_MUX_GPIO_MAX_BITS)
-               return -ENODEV;
-
        s = devm_kzalloc(&pdev->dev, sizeof(*s), GFP_KERNEL);
        if (!s)
                return -ENOMEM;
 
-       s->num_gpios = num_gpios;
-
-       for (n = 0; n < num_gpios; ) {
-               struct gpio_desc *gpio = gpiod_get_index(&pdev->dev, NULL, n,
-                                                        GPIOD_OUT_LOW);
-               if (IS_ERR(gpio)) {
-                       r = PTR_ERR(gpio);
-                       goto err;
-               }
-               s->gpio[n] = gpio;
-               n++;
-       }
+       s->gpios = gpiod_get_array(&pdev->dev, NULL, GPIOD_OUT_LOW);
+       if (IS_ERR(s->gpios))
+               return PTR_ERR(s->gpios);
 
        r = mdio_mux_init(&pdev->dev,
                          mdio_mux_gpio_switch_fn, &s->mux_handle, s);
 
-       if (r == 0) {
-               pdev->dev.platform_data = s;
-               return 0;
-       }
-err:
-       while (n) {
-               n--;
-               gpiod_put(s->gpio[n]);
+       if (r != 0) {
+               gpiod_put_array(s->gpios);
+               return r;
        }
-       return r;
+
+       pdev->dev.platform_data = s;
+       return 0;
 }
 
 static int mdio_mux_gpio_remove(struct platform_device *pdev)
 {
-       unsigned int n;
        struct mdio_mux_gpio_state *s = dev_get_platdata(&pdev->dev);
        mdio_mux_uninit(s->mux_handle);
-       for (n = 0; n < s->num_gpios; n++)
-               gpiod_put(s->gpio[n]);
+       gpiod_put_array(s->gpios);
        return 0;
 }
 
index 1190fd8f008862bc8f70f271575839d280a8f906..ebdc357c513167515baef710ba56d8b6b8e57cb9 100644 (file)
@@ -548,7 +548,8 @@ static int kszphy_probe(struct phy_device *phydev)
        }
 
        clk = devm_clk_get(&phydev->dev, "rmii-ref");
-       if (!IS_ERR(clk)) {
+       /* NOTE: clk may be NULL if building without CONFIG_HAVE_CLK */
+       if (!IS_ERR_OR_NULL(clk)) {
                unsigned long rate = clk_get_rate(clk);
                bool rmii_ref_clk_sel_25_mhz;
 
index 52cd8db2c57daad2767dec72149f4cdabbcf6917..47cd578052fc2328169fcc9df304be79e7af9ac5 100644 (file)
@@ -742,6 +742,9 @@ EXPORT_SYMBOL(phy_stop);
  */
 void phy_start(struct phy_device *phydev)
 {
+       bool do_resume = false;
+       int err = 0;
+
        mutex_lock(&phydev->lock);
 
        switch (phydev->state) {
@@ -752,11 +755,22 @@ void phy_start(struct phy_device *phydev)
                phydev->state = PHY_UP;
                break;
        case PHY_HALTED:
+               /* make sure interrupts are re-enabled for the PHY */
+               err = phy_enable_interrupts(phydev);
+               if (err < 0)
+                       break;
+
                phydev->state = PHY_RESUMING;
+               do_resume = true;
+               break;
        default:
                break;
        }
        mutex_unlock(&phydev->lock);
+
+       /* if phy was suspended, bring the physical link up again */
+       if (do_resume)
+               phy_resume(phydev);
 }
 EXPORT_SYMBOL(phy_start);
 
@@ -769,7 +783,7 @@ void phy_state_machine(struct work_struct *work)
        struct delayed_work *dwork = to_delayed_work(work);
        struct phy_device *phydev =
                        container_of(dwork, struct phy_device, state_queue);
-       bool needs_aneg = false, do_suspend = false, do_resume = false;
+       bool needs_aneg = false, do_suspend = false;
        int err = 0;
 
        mutex_lock(&phydev->lock);
@@ -888,14 +902,6 @@ void phy_state_machine(struct work_struct *work)
                }
                break;
        case PHY_RESUMING:
-               err = phy_clear_interrupt(phydev);
-               if (err)
-                       break;
-
-               err = phy_config_interrupt(phydev, PHY_INTERRUPT_ENABLED);
-               if (err)
-                       break;
-
                if (AUTONEG_ENABLE == phydev->autoneg) {
                        err = phy_aneg_done(phydev);
                        if (err < 0)
@@ -933,7 +939,6 @@ void phy_state_machine(struct work_struct *work)
                        }
                        phydev->adjust_link(phydev->attached_dev);
                }
-               do_resume = true;
                break;
        }
 
@@ -943,8 +948,6 @@ void phy_state_machine(struct work_struct *work)
                err = phy_start_aneg(phydev);
        else if (do_suspend)
                phy_suspend(phydev);
-       else if (do_resume)
-               phy_resume(phydev);
 
        if (err < 0)
                phy_error(phydev);
@@ -1053,13 +1056,14 @@ int phy_init_eee(struct phy_device *phydev, bool clk_stop_enable)
 {
        /* According to 802.3az,the EEE is supported only in full duplex-mode.
         * Also EEE feature is active when core is operating with MII, GMII
-        * or RGMII. Internal PHYs are also allowed to proceed and should
-        * return an error if they do not support EEE.
+        * or RGMII (all kinds). Internal PHYs are also allowed to proceed and
+        * should return an error if they do not support EEE.
         */
        if ((phydev->duplex == DUPLEX_FULL) &&
            ((phydev->interface == PHY_INTERFACE_MODE_MII) ||
            (phydev->interface == PHY_INTERFACE_MODE_GMII) ||
-           (phydev->interface == PHY_INTERFACE_MODE_RGMII) ||
+           (phydev->interface >= PHY_INTERFACE_MODE_RGMII &&
+            phydev->interface <= PHY_INTERFACE_MODE_RGMII_TXID) ||
             phy_is_internal(phydev))) {
                int eee_lp, eee_cap, eee_adv;
                u32 lp, cap, adv;
index 911b21602ff271885c2dbfb4c5c04f69fb028e7e..05005c660d4d954527d278130824f232383c2d49 100644 (file)
@@ -478,7 +478,6 @@ mppe_decompress(void *arg, unsigned char *ibuf, int isize, unsigned char *obuf,
        struct blkcipher_desc desc = { .tfm = state->arc4 };
        unsigned ccount;
        int flushed = MPPE_BITS(ibuf) & MPPE_BIT_FLUSHED;
-       int sanity = 0;
        struct scatterlist sg_in[1], sg_out[1];
 
        if (isize <= PPP_HDRLEN + MPPE_OVHD) {
@@ -514,31 +513,19 @@ mppe_decompress(void *arg, unsigned char *ibuf, int isize, unsigned char *obuf,
                       "mppe_decompress[%d]: ENCRYPTED bit not set!\n",
                       state->unit);
                state->sanity_errors += 100;
-               sanity = 1;
+               goto sanity_error;
        }
        if (!state->stateful && !flushed) {
                printk(KERN_DEBUG "mppe_decompress[%d]: FLUSHED bit not set in "
                       "stateless mode!\n", state->unit);
                state->sanity_errors += 100;
-               sanity = 1;
+               goto sanity_error;
        }
        if (state->stateful && ((ccount & 0xff) == 0xff) && !flushed) {
                printk(KERN_DEBUG "mppe_decompress[%d]: FLUSHED bit not set on "
                       "flag packet!\n", state->unit);
                state->sanity_errors += 100;
-               sanity = 1;
-       }
-
-       if (sanity) {
-               if (state->sanity_errors < SANITY_MAX)
-                       return DECOMP_ERROR;
-               else
-                       /*
-                        * Take LCP down if the peer is sending too many bogons.
-                        * We don't want to do this for a single or just a few
-                        * instances since it could just be due to packet corruption.
-                        */
-                       return DECOMP_FATALERROR;
+               goto sanity_error;
        }
 
        /*
@@ -546,6 +533,13 @@ mppe_decompress(void *arg, unsigned char *ibuf, int isize, unsigned char *obuf,
         */
 
        if (!state->stateful) {
+               /* Discard late packet */
+               if ((ccount - state->ccount) % MPPE_CCOUNT_SPACE
+                                               > MPPE_CCOUNT_SPACE / 2) {
+                       state->sanity_errors++;
+                       goto sanity_error;
+               }
+
                /* RFC 3078, sec 8.1.  Rekey for every packet. */
                while (state->ccount != ccount) {
                        mppe_rekey(state, 0);
@@ -649,6 +643,16 @@ mppe_decompress(void *arg, unsigned char *ibuf, int isize, unsigned char *obuf,
        state->sanity_errors >>= 1;
 
        return osize;
+
+sanity_error:
+       if (state->sanity_errors < SANITY_MAX)
+               return DECOMP_ERROR;
+       else
+               /* Take LCP down if the peer is sending too many bogons.
+                * We don't want to do this for a single or just a few
+                * instances since it could just be due to packet corruption.
+                */
+               return DECOMP_FATALERROR;
 }
 
 /*
index aa1dd926623ad622e3a15f905733e3d585aca871..b62a5e3a1c652d27e2bbb0d2a8a88990c3fef027 100644 (file)
@@ -465,6 +465,10 @@ static void pppoe_unbind_sock_work(struct work_struct *work)
        struct sock *sk = sk_pppox(po);
 
        lock_sock(sk);
+       if (po->pppoe_dev) {
+               dev_put(po->pppoe_dev);
+               po->pppoe_dev = NULL;
+       }
        pppox_unbind_sock(sk);
        release_sock(sk);
        sock_put(sk);
index c3e4da9e79ca071a06082e965a3aec5bb206a77e..8067b8fbb0eea42b106cc56ffe6bc216ae01f85a 100644 (file)
@@ -1182,7 +1182,7 @@ cdc_ncm_fill_tx_frame(struct usbnet *dev, struct sk_buff *skb, __le32 sign)
         * payload data instead.
         */
        usbnet_set_skb_tx_stats(skb_out, n,
-                               ctx->tx_curr_frame_payload - skb_out->len);
+                               (long)ctx->tx_curr_frame_payload - skb_out->len);
 
        return skb_out;
 
index ac4d03b328b130ab918175b1fa5c8fe55a0cbc7b..aafa1a1898e43de0d3d06e7d8367751473f25142 100644 (file)
@@ -4116,6 +4116,7 @@ static struct usb_device_id rtl8152_table[] = {
        {REALTEK_USB_DEVICE(VENDOR_ID_REALTEK, 0x8153)},
        {REALTEK_USB_DEVICE(VENDOR_ID_SAMSUNG, 0xa101)},
        {REALTEK_USB_DEVICE(VENDOR_ID_LENOVO,  0x7205)},
+       {REALTEK_USB_DEVICE(VENDOR_ID_LENOVO,  0x304f)},
        {}
 };
 
index 733f4feb2ef3c5f11bbf99af962ecbb77253314b..3c86b107275a899f3748e4cfee82ab2bb43aff6b 100644 (file)
@@ -1285,7 +1285,7 @@ netdev_tx_t usbnet_start_xmit (struct sk_buff *skb,
                                     struct net_device *net)
 {
        struct usbnet           *dev = netdev_priv(net);
-       int                     length;
+       unsigned int                    length;
        struct urb              *urb = NULL;
        struct skb_data         *entry;
        struct driver_info      *info = dev->driver_info;
@@ -1413,7 +1413,7 @@ not_drop:
                }
        } else
                netif_dbg(dev, tx_queued, dev->net,
-                         "> tx, len %d, type 0x%x\n", length, skb->protocol);
+                         "> tx, len %u, type 0x%x\n", length, skb->protocol);
 #ifdef CONFIG_PM
 deferred:
 #endif
index 154116aafd0d8c5cb6caab9056a2245cbc3c783b..21a0fbf1ed947a83506de920f7f61501457bfe68 100644 (file)
@@ -730,12 +730,8 @@ static int vxlan_fdb_create(struct vxlan_dev *vxlan,
                        /* Only change unicasts */
                        if (!(is_multicast_ether_addr(f->eth_addr) ||
                             is_zero_ether_addr(f->eth_addr))) {
-                               int rc = vxlan_fdb_replace(f, ip, port, vni,
+                               notify |= vxlan_fdb_replace(f, ip, port, vni,
                                                           ifindex);
-
-                               if (rc < 0)
-                                       return rc;
-                               notify |= rc;
                        } else
                                return -EOPNOTSUPP;
                }
@@ -2965,7 +2961,7 @@ static void __net_exit vxlan_exit_net(struct net *net)
                 * to the list by the previous loop.
                 */
                if (!net_eq(dev_net(vxlan->dev), net))
-                       unregister_netdevice_queue(dev, &list);
+                       unregister_netdevice_queue(vxlan->dev, &list);
        }
 
        unregister_netdevice_many(&list);
index 0acd079ba96bd3d2f60602ebf5f889f36da9f908..3ad79bb4f2c21c94b6c41c526a7e033e0937ed77 100644 (file)
@@ -1103,28 +1103,14 @@ static u8 ath_get_rate_txpower(struct ath_softc *sc, struct ath_buf *bf,
        struct sk_buff *skb;
        struct ath_frame_info *fi;
        struct ieee80211_tx_info *info;
-       struct ieee80211_vif *vif;
        struct ath_hw *ah = sc->sc_ah;
 
        if (sc->tx99_state || !ah->tpc_enabled)
                return MAX_RATE_POWER;
 
        skb = bf->bf_mpdu;
-       info = IEEE80211_SKB_CB(skb);
-       vif = info->control.vif;
-
-       if (!vif) {
-               max_power = sc->cur_chan->cur_txpower;
-               goto out;
-       }
-
-       if (vif->bss_conf.txpower_type != NL80211_TX_POWER_LIMITED) {
-               max_power = min_t(u8, sc->cur_chan->cur_txpower,
-                                 2 * vif->bss_conf.txpower);
-               goto out;
-       }
-
        fi = get_frame_info(skb);
+       info = IEEE80211_SKB_CB(skb);
 
        if (!AR_SREV_9300_20_OR_LATER(ah)) {
                int txpower = fi->tx_power;
@@ -1161,25 +1147,26 @@ static u8 ath_get_rate_txpower(struct ath_softc *sc, struct ath_buf *bf,
                        txpower -= 2;
 
                txpower = max(txpower, 0);
-               max_power = min_t(u8, ah->tx_power[rateidx],
-                                 2 * vif->bss_conf.txpower);
-               max_power = min_t(u8, max_power, txpower);
+               max_power = min_t(u8, ah->tx_power[rateidx], txpower);
+
+               /* XXX: clamp minimum TX power at 1 for AR9160 since if
+                * max_power is set to 0, frames are transmitted at max
+                * TX power
+                */
+               if (!max_power && !AR_SREV_9280_20_OR_LATER(ah))
+                       max_power = 1;
        } else if (!bf->bf_state.bfs_paprd) {
                if (rateidx < 8 && (info->flags & IEEE80211_TX_CTL_STBC))
                        max_power = min_t(u8, ah->tx_power_stbc[rateidx],
-                                         2 * vif->bss_conf.txpower);
+                                         fi->tx_power);
                else
                        max_power = min_t(u8, ah->tx_power[rateidx],
-                                         2 * vif->bss_conf.txpower);
-               max_power = min(max_power, fi->tx_power);
+                                         fi->tx_power);
        } else {
                max_power = ah->paprd_training_power;
        }
-out:
-       /* XXX: clamp minimum TX power at 1 for AR9160 since if max_power
-        * is set to 0, frames are transmitted at max TX power
-        */
-       return (!max_power && !AR_SREV_9280_20_OR_LATER(ah)) ? 1 : max_power;
+
+       return max_power;
 }
 
 static void ath_buf_set_rate(struct ath_softc *sc, struct ath_buf *bf,
@@ -2129,6 +2116,7 @@ static void setup_frame_info(struct ieee80211_hw *hw,
        struct ath_node *an = NULL;
        enum ath9k_key_type keytype;
        bool short_preamble = false;
+       u8 txpower;
 
        /*
         * We check if Short Preamble is needed for the CTS rate by
@@ -2145,6 +2133,16 @@ static void setup_frame_info(struct ieee80211_hw *hw,
        if (sta)
                an = (struct ath_node *) sta->drv_priv;
 
+       if (tx_info->control.vif) {
+               struct ieee80211_vif *vif = tx_info->control.vif;
+
+               txpower = 2 * vif->bss_conf.txpower;
+       } else {
+               struct ath_softc *sc = hw->priv;
+
+               txpower = sc->cur_chan->cur_txpower;
+       }
+
        memset(fi, 0, sizeof(*fi));
        fi->txq = -1;
        if (hw_key)
@@ -2155,7 +2153,7 @@ static void setup_frame_info(struct ieee80211_hw *hw,
                fi->keyix = ATH9K_TXKEYIX_INVALID;
        fi->keytype = keytype;
        fi->framelen = framelen;
-       fi->tx_power = MAX_RATE_POWER;
+       fi->tx_power = txpower;
 
        if (!rate)
                return;
index 4ec9811f49c87744458ed16cdcec32422432dc3f..65efb146898844510aa489502ee2c9db23906c92 100644 (file)
@@ -511,11 +511,9 @@ static int brcmf_msgbuf_query_dcmd(struct brcmf_pub *drvr, int ifidx,
                                     msgbuf->rx_pktids,
                                     msgbuf->ioctl_resp_pktid);
        if (msgbuf->ioctl_resp_ret_len != 0) {
-               if (!skb) {
-                       brcmf_err("Invalid packet id idx recv'd %d\n",
-                                 msgbuf->ioctl_resp_pktid);
+               if (!skb)
                        return -EBADF;
-               }
+
                memcpy(buf, skb->data, (len < msgbuf->ioctl_resp_ret_len) ?
                                       len : msgbuf->ioctl_resp_ret_len);
        }
@@ -874,10 +872,8 @@ brcmf_msgbuf_process_txstatus(struct brcmf_msgbuf *msgbuf, void *buf)
        flowid -= BRCMF_NROF_H2D_COMMON_MSGRINGS;
        skb = brcmf_msgbuf_get_pktid(msgbuf->drvr->bus_if->dev,
                                     msgbuf->tx_pktids, idx);
-       if (!skb) {
-               brcmf_err("Invalid packet id idx recv'd %d\n", idx);
+       if (!skb)
                return;
-       }
 
        set_bit(flowid, msgbuf->txstatus_done_map);
        commonring = msgbuf->flowrings[flowid];
@@ -1156,6 +1152,8 @@ brcmf_msgbuf_process_rx_complete(struct brcmf_msgbuf *msgbuf, void *buf)
 
        skb = brcmf_msgbuf_get_pktid(msgbuf->drvr->bus_if->dev,
                                     msgbuf->rx_pktids, idx);
+       if (!skb)
+               return;
 
        if (data_offset)
                skb_pull(skb, data_offset);
index ab019b45551b9ea9bef61a1861feba7601897a5f..f89f446e5c8ae32b5dccc42cae6234ad75283ff8 100644 (file)
@@ -21,6 +21,7 @@ config IWLWIFI
                Intel 7260 Wi-Fi Adapter
                Intel 3160 Wi-Fi Adapter
                Intel 7265 Wi-Fi Adapter
+               Intel 3165 Wi-Fi Adapter
 
 
          This driver uses the kernel's mac80211 subsystem.
index 36e786f0387bd42593fe3c8ec523831694483bea..74ad278116be3feb18b3a2a98e4034aa3145a6a1 100644 (file)
 
 /* Highest firmware API version supported */
 #define IWL7260_UCODE_API_MAX  13
-#define IWL3160_UCODE_API_MAX  13
 
 /* Oldest version we won't warn about */
 #define IWL7260_UCODE_API_OK   12
-#define IWL3160_UCODE_API_OK   12
+#define IWL3165_UCODE_API_OK   13
 
 /* Lowest firmware API version supported */
 #define IWL7260_UCODE_API_MIN  10
-#define IWL3160_UCODE_API_MIN  10
+#define IWL3165_UCODE_API_MIN  13
 
 /* NVM versions */
 #define IWL7260_NVM_VERSION            0x0a1d
 #define IWL3160_FW_PRE "iwlwifi-3160-"
 #define IWL3160_MODULE_FIRMWARE(api) IWL3160_FW_PRE __stringify(api) ".ucode"
 
-#define IWL3165_FW_PRE "iwlwifi-3165-"
-#define IWL3165_MODULE_FIRMWARE(api) IWL3165_FW_PRE __stringify(api) ".ucode"
-
 #define IWL7265_FW_PRE "iwlwifi-7265-"
 #define IWL7265_MODULE_FIRMWARE(api) IWL7265_FW_PRE __stringify(api) ".ucode"
 
@@ -248,8 +244,13 @@ static const struct iwl_ht_params iwl7265_ht_params = {
 
 const struct iwl_cfg iwl3165_2ac_cfg = {
        .name = "Intel(R) Dual Band Wireless AC 3165",
-       .fw_name_pre = IWL3165_FW_PRE,
+       .fw_name_pre = IWL7265D_FW_PRE,
        IWL_DEVICE_7000,
+       /* sparse doens't like the re-assignment but it is safe */
+#ifndef __CHECKER__
+       .ucode_api_ok = IWL3165_UCODE_API_OK,
+       .ucode_api_min = IWL3165_UCODE_API_MIN,
+#endif
        .ht_params = &iwl7000_ht_params,
        .nvm_ver = IWL3165_NVM_VERSION,
        .nvm_calib_ver = IWL3165_TX_POWER_VERSION,
@@ -325,6 +326,5 @@ const struct iwl_cfg iwl7265d_n_cfg = {
 
 MODULE_FIRMWARE(IWL7260_MODULE_FIRMWARE(IWL7260_UCODE_API_OK));
 MODULE_FIRMWARE(IWL3160_MODULE_FIRMWARE(IWL3160_UCODE_API_OK));
-MODULE_FIRMWARE(IWL3165_MODULE_FIRMWARE(IWL3160_UCODE_API_OK));
 MODULE_FIRMWARE(IWL7265_MODULE_FIRMWARE(IWL7260_UCODE_API_OK));
 MODULE_FIRMWARE(IWL7265D_MODULE_FIRMWARE(IWL7260_UCODE_API_OK));
index 41ff85de73343b0a5686bfd175164807e8dc4684..21302b6f2bfd79a8e8617a345e3771f6608c0145 100644 (file)
@@ -6,6 +6,7 @@
  * GPL LICENSE SUMMARY
  *
  * Copyright(c) 2008 - 2014 Intel Corporation. All rights reserved.
+ * Copyright(c) 2015 Intel Mobile Communications GmbH
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of version 2 of the GNU General Public License as
@@ -31,6 +32,7 @@
  * BSD LICENSE
  *
  * Copyright(c) 2005 - 2014 Intel Corporation. All rights reserved.
+ * Copyright(c) 2015 Intel Mobile Communications GmbH
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -748,6 +750,9 @@ void iwl_init_ht_hw_capab(const struct iwl_cfg *cfg,
                return;
        }
 
+       if (data->sku_cap_mimo_disabled)
+               rx_chains = 1;
+
        ht_info->ht_supported = true;
        ht_info->cap = IEEE80211_HT_CAP_DSSSCCK40;
 
index 5234a0bf11e4e3286b740c22518f4a039e224e94..750c8c9ee70d0352e5828049ff4b138e31a3ae6c 100644 (file)
@@ -6,6 +6,7 @@
  * GPL LICENSE SUMMARY
  *
  * Copyright(c) 2008 - 2014 Intel Corporation. All rights reserved.
+ * Copyright(c) 2015 Intel Mobile Communications GmbH
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of version 2 of the GNU General Public License as
@@ -31,6 +32,7 @@
  * BSD LICENSE
  *
  * Copyright(c) 2005 - 2014 Intel Corporation. All rights reserved.
+ * Copyright(c) 2015 Intel Mobile Communications GmbH
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -84,6 +86,7 @@ struct iwl_nvm_data {
        bool sku_cap_11ac_enable;
        bool sku_cap_amt_enable;
        bool sku_cap_ipan_enable;
+       bool sku_cap_mimo_disabled;
 
        u16 radio_cfg_type;
        u8 radio_cfg_step;
index bfdf3faa6c470dafbd9a66672b2f55e38b0872bc..62db2e5e45ebd51793c372e54832b21511057c58 100644 (file)
@@ -244,6 +244,7 @@ enum iwl_ucode_tlv_flag {
  *     longer than the passive one, which is essential for fragmented scan.
  * @IWL_UCODE_TLV_API_WIFI_MCC_UPDATE: ucode supports MCC updates with source.
  * IWL_UCODE_TLV_API_HDC_PHASE_0: ucode supports finer configuration of LTR
+ * @IWL_UCODE_TLV_API_TX_POWER_DEV: new API for tx power.
  * @IWL_UCODE_TLV_API_BASIC_DWELL: use only basic dwell time in scan command,
  *     regardless of the band or the number of the probes. FW will calculate
  *     the actual dwell time.
@@ -260,6 +261,7 @@ enum iwl_ucode_tlv_api {
        IWL_UCODE_TLV_API_FRAGMENTED_SCAN       = BIT(8),
        IWL_UCODE_TLV_API_WIFI_MCC_UPDATE       = BIT(9),
        IWL_UCODE_TLV_API_HDC_PHASE_0           = BIT(10),
+       IWL_UCODE_TLV_API_TX_POWER_DEV          = BIT(11),
        IWL_UCODE_TLV_API_BASIC_DWELL           = BIT(13),
        IWL_UCODE_TLV_API_SCD_CFG               = BIT(15),
        IWL_UCODE_TLV_API_SINGLE_SCAN_EBS       = BIT(16),
index 83903a5025c2e69779554e7bcf980aff48b3d080..8e604a3931ca6db6a1ab0eff59d2787d8562e494 100644 (file)
@@ -6,7 +6,7 @@
  * GPL LICENSE SUMMARY
  *
  * Copyright(c) 2008 - 2014 Intel Corporation. All rights reserved.
- * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH
+ * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of version 2 of the GNU General Public License as
@@ -32,7 +32,7 @@
  * BSD LICENSE
  *
  * Copyright(c) 2005 - 2014 Intel Corporation. All rights reserved.
- * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH
+ * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -116,10 +116,11 @@ enum family_8000_nvm_offsets {
 
 /* SKU Capabilities (actual values from NVM definition) */
 enum nvm_sku_bits {
-       NVM_SKU_CAP_BAND_24GHZ  = BIT(0),
-       NVM_SKU_CAP_BAND_52GHZ  = BIT(1),
-       NVM_SKU_CAP_11N_ENABLE  = BIT(2),
-       NVM_SKU_CAP_11AC_ENABLE = BIT(3),
+       NVM_SKU_CAP_BAND_24GHZ          = BIT(0),
+       NVM_SKU_CAP_BAND_52GHZ          = BIT(1),
+       NVM_SKU_CAP_11N_ENABLE          = BIT(2),
+       NVM_SKU_CAP_11AC_ENABLE         = BIT(3),
+       NVM_SKU_CAP_MIMO_DISABLE        = BIT(5),
 };
 
 /*
@@ -368,6 +369,11 @@ static void iwl_init_vht_hw_capab(const struct iwl_cfg *cfg,
        if (cfg->ht_params->ldpc)
                vht_cap->cap |= IEEE80211_VHT_CAP_RXLDPC;
 
+       if (data->sku_cap_mimo_disabled) {
+               num_rx_ants = 1;
+               num_tx_ants = 1;
+       }
+
        if (num_tx_ants > 1)
                vht_cap->cap |= IEEE80211_VHT_CAP_TXSTBC;
        else
@@ -465,7 +471,7 @@ static int iwl_get_radio_cfg(const struct iwl_cfg *cfg, const __le16 *nvm_sw,
        if (cfg->device_family != IWL_DEVICE_FAMILY_8000)
                return le16_to_cpup(nvm_sw + RADIO_CFG);
 
-       return le32_to_cpup((__le32 *)(nvm_sw + RADIO_CFG_FAMILY_8000));
+       return le32_to_cpup((__le32 *)(phy_sku + RADIO_CFG_FAMILY_8000));
 
 }
 
@@ -527,6 +533,10 @@ static void iwl_set_hw_address_family_8000(struct device *dev,
        const u8 *hw_addr;
 
        if (mac_override) {
+               static const u8 reserved_mac[] = {
+                       0x02, 0xcc, 0xaa, 0xff, 0xee, 0x00
+               };
+
                hw_addr = (const u8 *)(mac_override +
                                 MAC_ADDRESS_OVERRIDE_FAMILY_8000);
 
@@ -538,7 +548,12 @@ static void iwl_set_hw_address_family_8000(struct device *dev,
                data->hw_addr[4] = hw_addr[5];
                data->hw_addr[5] = hw_addr[4];
 
-               if (is_valid_ether_addr(data->hw_addr))
+               /*
+                * Force the use of the OTP MAC address in case of reserved MAC
+                * address in the NVM, or if address is given but invalid.
+                */
+               if (is_valid_ether_addr(data->hw_addr) &&
+                   memcmp(reserved_mac, hw_addr, ETH_ALEN) != 0)
                        return;
 
                IWL_ERR_DEV(dev,
@@ -610,6 +625,7 @@ iwl_parse_nvm_data(struct device *dev, const struct iwl_cfg *cfg,
                data->sku_cap_11n_enable = false;
        data->sku_cap_11ac_enable = data->sku_cap_11n_enable &&
                                    (sku & NVM_SKU_CAP_11AC_ENABLE);
+       data->sku_cap_mimo_disabled = sku & NVM_SKU_CAP_MIMO_DISABLE;
 
        data->n_hw_addrs = iwl_get_n_hw_addrs(cfg, nvm_sw);
 
index 6dfed1259260f06d23feb544d78ce6484c01fb36..56254a837214ffad421a7b7a14a9eaec3d7dc029 100644 (file)
@@ -6,7 +6,7 @@
  * GPL LICENSE SUMMARY
  *
  * Copyright(c) 2007 - 2014 Intel Corporation. All rights reserved.
- * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH
+ * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of version 2 of the GNU General Public License as
@@ -32,7 +32,7 @@
  * BSD LICENSE
  *
  * Copyright(c) 2005 - 2014 Intel Corporation. All rights reserved.
- * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH
+ * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -421,8 +421,9 @@ struct iwl_trans_txq_scd_cfg {
  *
  * All the handlers MUST be implemented
  *
- * @start_hw: starts the HW- from that point on, the HW can send interrupts
- *     May sleep
+ * @start_hw: starts the HW. If low_power is true, the NIC needs to be taken
+ *     out of a low power state. From that point on, the HW can send
+ *     interrupts. May sleep.
  * @op_mode_leave: Turn off the HW RF kill indication if on
  *     May sleep
  * @start_fw: allocates and inits all the resources for the transport
@@ -432,10 +433,11 @@ struct iwl_trans_txq_scd_cfg {
  *     the SCD base address in SRAM, then provide it here, or 0 otherwise.
  *     May sleep
  * @stop_device: stops the whole device (embedded CPU put to reset) and stops
- *     the HW. From that point on, the HW will be in low power but will still
- *     issue interrupt if the HW RF kill is triggered. This callback must do
- *     the right thing and not crash even if start_hw() was called but not
- *     start_fw(). May sleep
+ *     the HW. If low_power is true, the NIC will be put in low power state.
+ *     From that point on, the HW will be stopped but will still issue an
+ *     interrupt if the HW RF kill switch is triggered.
+ *     This callback must do the right thing and not crash even if %start_hw()
+ *     was called but not &start_fw(). May sleep.
  * @d3_suspend: put the device into the correct mode for WoWLAN during
  *     suspend. This is optional, if not implemented WoWLAN will not be
  *     supported. This callback may sleep.
@@ -491,14 +493,14 @@ struct iwl_trans_txq_scd_cfg {
  */
 struct iwl_trans_ops {
 
-       int (*start_hw)(struct iwl_trans *iwl_trans);
+       int (*start_hw)(struct iwl_trans *iwl_trans, bool low_power);
        void (*op_mode_leave)(struct iwl_trans *iwl_trans);
        int (*start_fw)(struct iwl_trans *trans, const struct fw_img *fw,
                        bool run_in_rfkill);
        int (*update_sf)(struct iwl_trans *trans,
                         struct iwl_sf_region *st_fwrd_space);
        void (*fw_alive)(struct iwl_trans *trans, u32 scd_addr);
-       void (*stop_device)(struct iwl_trans *trans);
+       void (*stop_device)(struct iwl_trans *trans, bool low_power);
 
        void (*d3_suspend)(struct iwl_trans *trans, bool test);
        int (*d3_resume)(struct iwl_trans *trans, enum iwl_d3_status *status,
@@ -652,11 +654,16 @@ static inline void iwl_trans_configure(struct iwl_trans *trans,
        trans->ops->configure(trans, trans_cfg);
 }
 
-static inline int iwl_trans_start_hw(struct iwl_trans *trans)
+static inline int _iwl_trans_start_hw(struct iwl_trans *trans, bool low_power)
 {
        might_sleep();
 
-       return trans->ops->start_hw(trans);
+       return trans->ops->start_hw(trans, low_power);
+}
+
+static inline int iwl_trans_start_hw(struct iwl_trans *trans)
+{
+       return trans->ops->start_hw(trans, true);
 }
 
 static inline void iwl_trans_op_mode_leave(struct iwl_trans *trans)
@@ -703,15 +710,21 @@ static inline int iwl_trans_update_sf(struct iwl_trans *trans,
        return 0;
 }
 
-static inline void iwl_trans_stop_device(struct iwl_trans *trans)
+static inline void _iwl_trans_stop_device(struct iwl_trans *trans,
+                                         bool low_power)
 {
        might_sleep();
 
-       trans->ops->stop_device(trans);
+       trans->ops->stop_device(trans, low_power);
 
        trans->state = IWL_TRANS_NO_FW;
 }
 
+static inline void iwl_trans_stop_device(struct iwl_trans *trans)
+{
+       _iwl_trans_stop_device(trans, true);
+}
+
 static inline void iwl_trans_d3_suspend(struct iwl_trans *trans, bool test)
 {
        might_sleep();
index d954591e0be58528d138f8738b2cb2325db1fed3..6ac6de2af9779982231d1efb4c6186fad4442f5d 100644 (file)
@@ -776,7 +776,7 @@ static int iwl_mvm_bt_coex_reduced_txp(struct iwl_mvm *mvm, u8 sta_id,
        struct iwl_host_cmd cmd = {
                .id = BT_CONFIG,
                .len = { sizeof(*bt_cmd), },
-               .dataflags = { IWL_HCMD_DFL_NOCOPY, },
+               .dataflags = { IWL_HCMD_DFL_DUP, },
                .flags = CMD_ASYNC,
        };
        struct iwl_mvm_sta *mvmsta;
index a6c48c7b1e1683fdbdcb99fd0e4f971cf6ad66d2..4310cf102d78ecd4f3e7baffa13570d878153cb4 100644 (file)
@@ -1726,7 +1726,7 @@ iwl_mvm_netdetect_query_results(struct iwl_mvm *mvm,
        results->matched_profiles = le32_to_cpu(query->matched_profiles);
        memcpy(results->matches, query->matches, sizeof(results->matches));
 
-#ifdef CPTCFG_IWLWIFI_DEBUGFS
+#ifdef CONFIG_IWLWIFI_DEBUGFS
        mvm->last_netdetect_scans = le32_to_cpu(query->n_scans_done);
 #endif
 
@@ -1750,8 +1750,10 @@ static void iwl_mvm_query_netdetect_reasons(struct iwl_mvm *mvm,
        int i, j, n_matches, ret;
 
        fw_status = iwl_mvm_get_wakeup_status(mvm, vif);
-       if (!IS_ERR_OR_NULL(fw_status))
+       if (!IS_ERR_OR_NULL(fw_status)) {
                reasons = le32_to_cpu(fw_status->wakeup_reasons);
+               kfree(fw_status);
+       }
 
        if (reasons & IWL_WOWLAN_WAKEUP_BY_RFKILL_DEASSERTED)
                wakeup.rfkill_release = true;
@@ -1868,15 +1870,15 @@ static int __iwl_mvm_resume(struct iwl_mvm *mvm, bool test)
        /* get the BSS vif pointer again */
        vif = iwl_mvm_get_bss_vif(mvm);
        if (IS_ERR_OR_NULL(vif))
-               goto out_unlock;
+               goto err;
 
        ret = iwl_trans_d3_resume(mvm->trans, &d3_status, test);
        if (ret)
-               goto out_unlock;
+               goto err;
 
        if (d3_status != IWL_D3_STATUS_ALIVE) {
                IWL_INFO(mvm, "Device was reset during suspend\n");
-               goto out_unlock;
+               goto err;
        }
 
        /* query SRAM first in case we want event logging */
@@ -1902,7 +1904,8 @@ static int __iwl_mvm_resume(struct iwl_mvm *mvm, bool test)
                goto out_iterate;
        }
 
- out_unlock:
+err:
+       iwl_mvm_free_nd(mvm);
        mutex_unlock(&mvm->mutex);
 
 out_iterate:
@@ -1915,6 +1918,14 @@ out:
        /* return 1 to reconfigure the device */
        set_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status);
        set_bit(IWL_MVM_STATUS_D3_RECONFIG, &mvm->status);
+
+       /* We always return 1, which causes mac80211 to do a reconfig
+        * with IEEE80211_RECONFIG_TYPE_RESTART.  This type of
+        * reconfig calls iwl_mvm_restart_complete(), where we unref
+        * the IWL_MVM_REF_UCODE_DOWN, so we need to take the
+        * reference here.
+        */
+       iwl_mvm_ref(mvm, IWL_MVM_REF_UCODE_DOWN);
        return 1;
 }
 
@@ -2021,7 +2032,6 @@ static int iwl_mvm_d3_test_release(struct inode *inode, struct file *file)
        __iwl_mvm_resume(mvm, true);
        rtnl_unlock();
        iwl_abort_notification_waits(&mvm->notif_wait);
-       iwl_mvm_ref(mvm, IWL_MVM_REF_UCODE_DOWN);
        ieee80211_restart_hw(mvm->hw);
 
        /* wait for restart and disconnect all interfaces */
index 4fc0938b3fb6d6c92464f63b3f206cbc798f92b7..b1baa33cc19b3228a8534af71ab69c7dede40520 100644 (file)
@@ -297,6 +297,40 @@ struct iwl_uapsd_misbehaving_ap_notif {
        u8 reserved[3];
 } __packed;
 
+/**
+ * struct iwl_reduce_tx_power_cmd - TX power reduction command
+ * REDUCE_TX_POWER_CMD = 0x9f
+ * @flags: (reserved for future implementation)
+ * @mac_context_id: id of the mac ctx for which we are reducing TX power.
+ * @pwr_restriction: TX power restriction in dBms.
+ */
+struct iwl_reduce_tx_power_cmd {
+       u8 flags;
+       u8 mac_context_id;
+       __le16 pwr_restriction;
+} __packed; /* TX_REDUCED_POWER_API_S_VER_1 */
+
+/**
+ * struct iwl_dev_tx_power_cmd - TX power reduction command
+ * REDUCE_TX_POWER_CMD = 0x9f
+ * @set_mode: 0 - MAC tx power, 1 - device tx power
+ * @mac_context_id: id of the mac ctx for which we are reducing TX power.
+ * @pwr_restriction: TX power restriction in 1/8 dBms.
+ * @dev_24: device TX power restriction in 1/8 dBms
+ * @dev_52_low: device TX power restriction upper band - low
+ * @dev_52_high: device TX power restriction upper band - high
+ */
+struct iwl_dev_tx_power_cmd {
+       __le32 set_mode;
+       __le32 mac_context_id;
+       __le16 pwr_restriction;
+       __le16 dev_24;
+       __le16 dev_52_low;
+       __le16 dev_52_high;
+} __packed; /* TX_REDUCED_POWER_API_S_VER_2 */
+
+#define IWL_DEV_MAX_TX_POWER 0x7FFF
+
 /**
  * struct iwl_beacon_filter_cmd
  * REPLY_BEACON_FILTERING_CMD = 0xd2 (command)
index 4f81dcf57a736e7409087f4b3193809c3570db6f..d6cced47d561b9601a59166296a229facfd9014e 100644 (file)
@@ -122,46 +122,6 @@ enum iwl_scan_complete_status {
        SCAN_COMP_STATUS_ERR_ALLOC_TE = 0x0C,
 };
 
-/**
- * struct iwl_scan_results_notif - scan results for one channel
- * ( SCAN_RESULTS_NOTIFICATION = 0x83 )
- * @channel: which channel the results are from
- * @band: 0 for 5.2 GHz, 1 for 2.4 GHz
- * @probe_status: SCAN_PROBE_STATUS_*, indicates success of probe request
- * @num_probe_not_sent: # of request that weren't sent due to not enough time
- * @duration: duration spent in channel, in usecs
- * @statistics: statistics gathered for this channel
- */
-struct iwl_scan_results_notif {
-       u8 channel;
-       u8 band;
-       u8 probe_status;
-       u8 num_probe_not_sent;
-       __le32 duration;
-       __le32 statistics[SCAN_RESULTS_STATISTICS];
-} __packed; /* SCAN_RESULT_NTF_API_S_VER_2 */
-
-/**
- * struct iwl_scan_complete_notif - notifies end of scanning (all channels)
- * ( SCAN_COMPLETE_NOTIFICATION = 0x84 )
- * @scanned_channels: number of channels scanned (and number of valid results)
- * @status: one of SCAN_COMP_STATUS_*
- * @bt_status: BT on/off status
- * @last_channel: last channel that was scanned
- * @tsf_low: TSF timer (lower half) in usecs
- * @tsf_high: TSF timer (higher half) in usecs
- * @results: array of scan results, only "scanned_channels" of them are valid
- */
-struct iwl_scan_complete_notif {
-       u8 scanned_channels;
-       u8 status;
-       u8 bt_status;
-       u8 last_channel;
-       __le32 tsf_low;
-       __le32 tsf_high;
-       struct iwl_scan_results_notif results[];
-} __packed; /* SCAN_COMPLETE_NTF_API_S_VER_2 */
-
 /* scan offload */
 #define IWL_SCAN_MAX_BLACKLIST_LEN     64
 #define IWL_SCAN_SHORT_BLACKLIST_LEN   16
@@ -554,7 +514,7 @@ struct iwl_scan_req_unified_lmac {
 } __packed;
 
 /**
- * struct iwl_lmac_scan_results_notif - scan results for one channel -
+ * struct iwl_scan_results_notif - scan results for one channel -
  *     SCAN_RESULT_NTF_API_S_VER_3
  * @channel: which channel the results are from
  * @band: 0 for 5.2 GHz, 1 for 2.4 GHz
@@ -562,7 +522,7 @@ struct iwl_scan_req_unified_lmac {
  * @num_probe_not_sent: # of request that weren't sent due to not enough time
  * @duration: duration spent in channel, in usecs
  */
-struct iwl_lmac_scan_results_notif {
+struct iwl_scan_results_notif {
        u8 channel;
        u8 band;
        u8 probe_status;
index aab68cbae754d547a9e1fe514c4c88de6877777f..01b1da6ad35977b349fc79336c15238706ca9078 100644 (file)
@@ -281,19 +281,6 @@ struct iwl_tx_ant_cfg_cmd {
        __le32 valid;
 } __packed;
 
-/**
- * struct iwl_reduce_tx_power_cmd - TX power reduction command
- * REDUCE_TX_POWER_CMD = 0x9f
- * @flags: (reserved for future implementation)
- * @mac_context_id: id of the mac ctx for which we are reducing TX power.
- * @pwr_restriction: TX power restriction in dBms.
- */
-struct iwl_reduce_tx_power_cmd {
-       u8 flags;
-       u8 mac_context_id;
-       __le16 pwr_restriction;
-} __packed; /* TX_REDUCED_POWER_API_S_VER_1 */
-
 /*
  * Calibration control struct.
  * Sent as part of the phy configuration command.
index bc5eac4960e18a79a211da2a2bf6492b1a39e570..df869633f4dd976c9404e036ecf8a49a855fd0b4 100644 (file)
@@ -6,7 +6,7 @@
  * GPL LICENSE SUMMARY
  *
  * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
- * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH
+ * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of version 2 of the GNU General Public License as
@@ -32,7 +32,7 @@
  * BSD LICENSE
  *
  * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
- * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH
+ * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -322,7 +322,7 @@ int iwl_run_init_mvm_ucode(struct iwl_mvm *mvm, bool read_nvm)
 
        lockdep_assert_held(&mvm->mutex);
 
-       if (WARN_ON_ONCE(mvm->init_ucode_complete || mvm->calibrating))
+       if (WARN_ON_ONCE(mvm->calibrating))
                return 0;
 
        iwl_init_notification_wait(&mvm->notif_wait,
@@ -396,8 +396,6 @@ int iwl_run_init_mvm_ucode(struct iwl_mvm *mvm, bool read_nvm)
         */
        ret = iwl_wait_notification(&mvm->notif_wait, &calib_wait,
                        MVM_UCODE_CALIB_TIMEOUT);
-       if (!ret)
-               mvm->init_ucode_complete = true;
 
        if (ret && iwl_mvm_is_radio_killed(mvm)) {
                IWL_DEBUG_RF_KILL(mvm, "RFKILL while calibrating.\n");
@@ -494,15 +492,6 @@ int iwl_mvm_fw_dbg_collect_desc(struct iwl_mvm *mvm,
 
        mvm->fw_dump_desc = desc;
 
-       /* stop recording */
-       if (mvm->cfg->device_family == IWL_DEVICE_FAMILY_7000) {
-               iwl_set_bits_prph(mvm->trans, MON_BUFF_SAMPLE_CTL, 0x100);
-       } else {
-               iwl_write_prph(mvm->trans, DBGC_IN_SAMPLE, 0);
-               /* wait before we collect the data till the DBGC stop */
-               udelay(100);
-       }
-
        queue_delayed_work(system_wq, &mvm->fw_dump_wk, delay);
 
        return 0;
@@ -658,25 +647,24 @@ int iwl_mvm_up(struct iwl_mvm *mvm)
         * module loading, load init ucode now
         * (for example, if we were in RFKILL)
         */
-       if (!mvm->init_ucode_complete) {
-               ret = iwl_run_init_mvm_ucode(mvm, false);
-               if (ret && !iwlmvm_mod_params.init_dbg) {
-                       IWL_ERR(mvm, "Failed to run INIT ucode: %d\n", ret);
-                       /* this can't happen */
-                       if (WARN_ON(ret > 0))
-                               ret = -ERFKILL;
-                       goto error;
-               }
-               if (!iwlmvm_mod_params.init_dbg) {
-                       /*
-                        * should stop and start HW since that INIT
-                        * image just loaded
-                        */
-                       iwl_trans_stop_device(mvm->trans);
-                       ret = iwl_trans_start_hw(mvm->trans);
-                       if (ret)
-                               return ret;
-               }
+       ret = iwl_run_init_mvm_ucode(mvm, false);
+       if (ret && !iwlmvm_mod_params.init_dbg) {
+               IWL_ERR(mvm, "Failed to run INIT ucode: %d\n", ret);
+               /* this can't happen */
+               if (WARN_ON(ret > 0))
+                       ret = -ERFKILL;
+               goto error;
+       }
+       if (!iwlmvm_mod_params.init_dbg) {
+               /*
+                * Stop and start the transport without entering low power
+                * mode. This will save the state of other components on the
+                * device that are triggered by the INIT firwmare (MFUART).
+                */
+               _iwl_trans_stop_device(mvm->trans, false);
+               _iwl_trans_start_hw(mvm->trans, false);
+               if (ret)
+                       return ret;
        }
 
        if (iwlmvm_mod_params.init_dbg)
index 84555170b6f751bb4f0925bf5c85319de76293b6..dda9f7b5f3423173e668f507719e47c3540b27d0 100644 (file)
@@ -1322,7 +1322,7 @@ static void iwl_mvm_restart_complete(struct iwl_mvm *mvm)
 
        clear_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status);
        iwl_mvm_d0i3_enable_tx(mvm, NULL);
-       ret = iwl_mvm_update_quotas(mvm, false, NULL);
+       ret = iwl_mvm_update_quotas(mvm, true, NULL);
        if (ret)
                IWL_ERR(mvm, "Failed to update quotas after restart (%d)\n",
                        ret);
@@ -1471,8 +1471,8 @@ static struct iwl_mvm_phy_ctxt *iwl_mvm_get_free_phy_ctxt(struct iwl_mvm *mvm)
        return NULL;
 }
 
-static int iwl_mvm_set_tx_power(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
-                               s8 tx_power)
+static int iwl_mvm_set_tx_power_old(struct iwl_mvm *mvm,
+                                   struct ieee80211_vif *vif, s8 tx_power)
 {
        /* FW is in charge of regulatory enforcement */
        struct iwl_reduce_tx_power_cmd reduce_txpwr_cmd = {
@@ -1485,6 +1485,26 @@ static int iwl_mvm_set_tx_power(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
                                    &reduce_txpwr_cmd);
 }
 
+static int iwl_mvm_set_tx_power(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
+                               s16 tx_power)
+{
+       struct iwl_dev_tx_power_cmd cmd = {
+               .set_mode = 0,
+               .mac_context_id =
+                       cpu_to_le32(iwl_mvm_vif_from_mac80211(vif)->id),
+               .pwr_restriction = cpu_to_le16(8 * tx_power),
+       };
+
+       if (!(mvm->fw->ucode_capa.api[0] & IWL_UCODE_TLV_API_TX_POWER_DEV))
+               return iwl_mvm_set_tx_power_old(mvm, vif, tx_power);
+
+       if (tx_power == IWL_DEFAULT_MAX_TX_POWER)
+               cmd.pwr_restriction = cpu_to_le16(IWL_DEV_MAX_TX_POWER);
+
+       return iwl_mvm_send_cmd_pdu(mvm, REDUCE_TX_POWER_CMD, 0,
+                                   sizeof(cmd), &cmd);
+}
+
 static int iwl_mvm_mac_add_interface(struct ieee80211_hw *hw,
                                     struct ieee80211_vif *vif)
 {
@@ -3975,9 +3995,6 @@ static void iwl_mvm_mac_event_callback(struct ieee80211_hw *hw,
        if (!iwl_fw_dbg_trigger_enabled(mvm->fw, FW_DBG_TRIGGER_MLME))
                return;
 
-       if (event->u.mlme.status == MLME_SUCCESS)
-               return;
-
        trig = iwl_fw_dbg_get_trigger(mvm->fw, FW_DBG_TRIGGER_MLME);
        trig_mlme = (void *)trig->data;
        if (!iwl_fw_dbg_trigger_check_stop(mvm, vif, trig))
index d5522a16124292cd6cab36159851a8446b5e2d95..cf70f681d1acb7e271717091684ca805749e13ab 100644 (file)
@@ -603,7 +603,6 @@ struct iwl_mvm {
 
        enum iwl_ucode_type cur_ucode;
        bool ucode_loaded;
-       bool init_ucode_complete;
        bool calibrating;
        u32 error_event_table;
        u32 log_event_table;
index a08b03d58d4bf0f3ebd4773a7fdb6e07cc8406b8..2ea01238754eb8d1c2470156f0293a2e15988fd6 100644 (file)
@@ -865,6 +865,16 @@ static void iwl_mvm_fw_error_dump_wk(struct work_struct *work)
                return;
 
        mutex_lock(&mvm->mutex);
+
+       /* stop recording */
+       if (mvm->cfg->device_family == IWL_DEVICE_FAMILY_7000) {
+               iwl_set_bits_prph(mvm->trans, MON_BUFF_SAMPLE_CTL, 0x100);
+       } else {
+               iwl_write_prph(mvm->trans, DBGC_IN_SAMPLE, 0);
+               /* wait before we collect the data till the DBGC stop */
+               udelay(100);
+       }
+
        iwl_mvm_fw_error_dump(mvm);
 
        /* start recording again if the firmware is not crashed */
@@ -1253,11 +1263,13 @@ static void iwl_mvm_d0i3_exit_work(struct work_struct *wk)
                ieee80211_iterate_active_interfaces(
                        mvm->hw, IEEE80211_IFACE_ITER_NORMAL,
                        iwl_mvm_d0i3_disconnect_iter, mvm);
-
-       iwl_free_resp(&get_status_cmd);
 out:
        iwl_mvm_d0i3_enable_tx(mvm, qos_seq);
 
+       /* qos_seq might point inside resp_pkt, so free it only now */
+       if (get_status_cmd.resp_pkt)
+               iwl_free_resp(&get_status_cmd);
+
        /* the FW might have updated the regdomain */
        iwl_mvm_update_changed_regdom(mvm);
 
index f9928f2c125f726bbf89474096bd47990bfb86eb..33cd68ae7bf9362539fa1a99e34686e0cca3de2b 100644 (file)
@@ -180,6 +180,9 @@ static bool rs_mimo_allow(struct iwl_mvm *mvm, struct ieee80211_sta *sta,
        if (iwl_mvm_vif_low_latency(mvmvif) && mvmsta->vif->p2p)
                return false;
 
+       if (mvm->nvm_data->sku_cap_mimo_disabled)
+               return false;
+
        return true;
 }
 
index 78ec7db64ba59e886e2a7b18a3df64f70a4ea29c..d6314ddf57b5d9638fcfd2fcf6ba917bb136779f 100644 (file)
@@ -478,6 +478,11 @@ static void iwl_mvm_stat_iterator(void *_data, u8 *mac,
        if (vif->type != NL80211_IFTYPE_STATION)
                return;
 
+       if (sig == 0) {
+               IWL_DEBUG_RX(mvm, "RSSI is 0 - skip signal based decision\n");
+               return;
+       }
+
        mvmvif->bf_data.ave_beacon_signal = sig;
 
        /* BT Coex */
index 74e1c86289dcbcedc1f5c7b963e468095de7cf25..1075a213bd6a87156e44ab410ac566cf18bdacc3 100644 (file)
@@ -319,7 +319,7 @@ int iwl_mvm_rx_scan_offload_iter_complete_notif(struct iwl_mvm *mvm,
                                                struct iwl_device_cmd *cmd)
 {
        struct iwl_rx_packet *pkt = rxb_addr(rxb);
-       struct iwl_scan_complete_notif *notif = (void *)pkt->data;
+       struct iwl_lmac_scan_complete_notif *notif = (void *)pkt->data;
 
        IWL_DEBUG_SCAN(mvm,
                       "Scan offload iteration complete: status=0x%x scanned channels=%d\n",
index 01996c9d98a79b1d62e3a665cd0c720df79ad04e..376b84e54ad7e8bbb48d039d354c03748665451c 100644 (file)
@@ -1,7 +1,7 @@
 /******************************************************************************
  *
- * Copyright(c) 2003 - 2014 Intel Corporation. All rights reserved.
- * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH
+ * Copyright(c) 2003 - 2015 Intel Corporation. All rights reserved.
+ * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH
  *
  * Portions of this file are derived from the ipw3945 project, as well
  * as portions of the ieee80211 subsystem header files.
@@ -320,7 +320,7 @@ struct iwl_trans_pcie {
 
        /*protect hw register */
        spinlock_t reg_lock;
-       bool cmd_in_flight;
+       bool cmd_hold_nic_awake;
        bool ref_cmd_in_flight;
 
        /* protect ref counter */
index 2de8fbfe4edf4d6c6997307fb91052177fd7e6e4..dc179094e6a0d440b2aa29909c05adbc07f3f6b5 100644 (file)
@@ -5,8 +5,8 @@
  *
  * GPL LICENSE SUMMARY
  *
- * Copyright(c) 2007 - 2014 Intel Corporation. All rights reserved.
- * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH
+ * Copyright(c) 2007 - 2015 Intel Corporation. All rights reserved.
+ * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of version 2 of the GNU General Public License as
@@ -31,8 +31,8 @@
  *
  * BSD LICENSE
  *
- * Copyright(c) 2005 - 2014 Intel Corporation. All rights reserved.
- * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH
+ * Copyright(c) 2005 - 2015 Intel Corporation. All rights reserved.
+ * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -104,7 +104,7 @@ static void iwl_pcie_free_fw_monitor(struct iwl_trans *trans)
 static void iwl_pcie_alloc_fw_monitor(struct iwl_trans *trans)
 {
        struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
-       struct page *page;
+       struct page *page = NULL;
        dma_addr_t phys;
        u32 size;
        u8 power;
@@ -131,6 +131,7 @@ static void iwl_pcie_alloc_fw_monitor(struct iwl_trans *trans)
                                    DMA_FROM_DEVICE);
                if (dma_mapping_error(trans->dev, phys)) {
                        __free_pages(page, order);
+                       page = NULL;
                        continue;
                }
                IWL_INFO(trans,
@@ -1020,7 +1021,7 @@ static void iwl_trans_pcie_fw_alive(struct iwl_trans *trans, u32 scd_addr)
        iwl_pcie_tx_start(trans, scd_addr);
 }
 
-static void iwl_trans_pcie_stop_device(struct iwl_trans *trans)
+static void iwl_trans_pcie_stop_device(struct iwl_trans *trans, bool low_power)
 {
        struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
        bool hw_rfkill, was_hw_rfkill;
@@ -1048,9 +1049,11 @@ static void iwl_trans_pcie_stop_device(struct iwl_trans *trans)
                iwl_pcie_rx_stop(trans);
 
                /* Power-down device's busmaster DMA clocks */
-               iwl_write_prph(trans, APMG_CLK_DIS_REG,
-                              APMG_CLK_VAL_DMA_CLK_RQT);
-               udelay(5);
+               if (trans->cfg->device_family != IWL_DEVICE_FAMILY_8000) {
+                       iwl_write_prph(trans, APMG_CLK_DIS_REG,
+                                      APMG_CLK_VAL_DMA_CLK_RQT);
+                       udelay(5);
+               }
        }
 
        /* Make sure (redundant) we've released our request to stay awake */
@@ -1115,7 +1118,7 @@ static void iwl_trans_pcie_stop_device(struct iwl_trans *trans)
 void iwl_trans_pcie_rf_kill(struct iwl_trans *trans, bool state)
 {
        if (iwl_op_mode_hw_rf_kill(trans->op_mode, state))
-               iwl_trans_pcie_stop_device(trans);
+               iwl_trans_pcie_stop_device(trans, true);
 }
 
 static void iwl_trans_pcie_d3_suspend(struct iwl_trans *trans, bool test)
@@ -1200,7 +1203,7 @@ static int iwl_trans_pcie_d3_resume(struct iwl_trans *trans,
        return 0;
 }
 
-static int iwl_trans_pcie_start_hw(struct iwl_trans *trans)
+static int iwl_trans_pcie_start_hw(struct iwl_trans *trans, bool low_power)
 {
        bool hw_rfkill;
        int err;
@@ -1369,7 +1372,7 @@ static bool iwl_trans_pcie_grab_nic_access(struct iwl_trans *trans, bool silent,
 
        spin_lock_irqsave(&trans_pcie->reg_lock, *flags);
 
-       if (trans_pcie->cmd_in_flight)
+       if (trans_pcie->cmd_hold_nic_awake)
                goto out;
 
        /* this bit wakes up the NIC */
@@ -1435,7 +1438,7 @@ static void iwl_trans_pcie_release_nic_access(struct iwl_trans *trans,
         */
        __acquire(&trans_pcie->reg_lock);
 
-       if (trans_pcie->cmd_in_flight)
+       if (trans_pcie->cmd_hold_nic_awake)
                goto out;
 
        __iwl_trans_pcie_clear_bit(trans, CSR_GP_CNTRL,
index 06952aadfd7b5d4dccfff9f9689cd804031ab0eb..5ef8044c2ea3ed7317870902168c71be936cd8df 100644 (file)
@@ -1039,18 +1039,14 @@ static int iwl_pcie_set_cmd_in_flight(struct iwl_trans *trans,
                iwl_trans_pcie_ref(trans);
        }
 
-       if (trans_pcie->cmd_in_flight)
-               return 0;
-
-       trans_pcie->cmd_in_flight = true;
-
        /*
         * wake up the NIC to make sure that the firmware will see the host
         * command - we will let the NIC sleep once all the host commands
         * returned. This needs to be done only on NICs that have
         * apmg_wake_up_wa set.
         */
-       if (trans->cfg->base_params->apmg_wake_up_wa) {
+       if (trans->cfg->base_params->apmg_wake_up_wa &&
+           !trans_pcie->cmd_hold_nic_awake) {
                __iwl_trans_pcie_set_bit(trans, CSR_GP_CNTRL,
                                         CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ);
                if (trans->cfg->device_family == IWL_DEVICE_FAMILY_8000)
@@ -1064,10 +1060,10 @@ static int iwl_pcie_set_cmd_in_flight(struct iwl_trans *trans,
                if (ret < 0) {
                        __iwl_trans_pcie_clear_bit(trans, CSR_GP_CNTRL,
                                        CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ);
-                       trans_pcie->cmd_in_flight = false;
                        IWL_ERR(trans, "Failed to wake NIC for hcmd\n");
                        return -EIO;
                }
+               trans_pcie->cmd_hold_nic_awake = true;
        }
 
        return 0;
@@ -1085,15 +1081,14 @@ static int iwl_pcie_clear_cmd_in_flight(struct iwl_trans *trans)
                iwl_trans_pcie_unref(trans);
        }
 
-       if (WARN_ON(!trans_pcie->cmd_in_flight))
-               return 0;
-
-       trans_pcie->cmd_in_flight = false;
+       if (trans->cfg->base_params->apmg_wake_up_wa) {
+               if (WARN_ON(!trans_pcie->cmd_hold_nic_awake))
+                       return 0;
 
-       if (trans->cfg->base_params->apmg_wake_up_wa)
+               trans_pcie->cmd_hold_nic_awake = false;
                __iwl_trans_pcie_clear_bit(trans, CSR_GP_CNTRL,
-                                       CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ);
-
+                                          CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ);
+       }
        return 0;
 }
 
index f0188c83c79f7d6027bdee6372768d3657347a2a..2721cf89fb160f0d3f4e6106474c5da101707a18 100644 (file)
@@ -126,7 +126,7 @@ static int _usbctrl_vendorreq_sync_read(struct usb_device *udev, u8 request,
 
        do {
                status = usb_control_msg(udev, pipe, request, reqtype, value,
-                                        index, pdata, len, 0); /*max. timeout*/
+                                        index, pdata, len, 1000);
                if (status < 0) {
                        /* firmware download is checksumed, don't retry */
                        if ((value >= FW_8192C_START_ADDRESS &&
index 4de46aa61d958fb9c5a1ae9d1ec3c0a0e48acdd4..0d2594395ffbc797671711603461148270f1a03f 100644 (file)
@@ -1250,7 +1250,7 @@ static void xenvif_tx_build_gops(struct xenvif_queue *queue,
                        netdev_err(queue->vif->dev,
                                   "txreq.offset: %x, size: %u, end: %lu\n",
                                   txreq.offset, txreq.size,
-                                  (txreq.offset&~PAGE_MASK) + txreq.size);
+                                  (unsigned long)(txreq.offset&~PAGE_MASK) + txreq.size);
                        xenvif_fatal_tx_err(queue->vif);
                        break;
                }
index 3d8dbf5f2d396aa8dde8745afe98d8b4f9febd67..968787abf78d454166561e0c79f9f7421dad931d 100644 (file)
@@ -34,6 +34,8 @@ struct backend_info {
        enum xenbus_state frontend_state;
        struct xenbus_watch hotplug_status_watch;
        u8 have_hotplug_status_watch:1;
+
+       const char *hotplug_script;
 };
 
 static int connect_rings(struct backend_info *be, struct xenvif_queue *queue);
@@ -238,6 +240,7 @@ static int netback_remove(struct xenbus_device *dev)
                xenvif_free(be->vif);
                be->vif = NULL;
        }
+       kfree(be->hotplug_script);
        kfree(be);
        dev_set_drvdata(&dev->dev, NULL);
        return 0;
@@ -255,6 +258,7 @@ static int netback_probe(struct xenbus_device *dev,
        struct xenbus_transaction xbt;
        int err;
        int sg;
+       const char *script;
        struct backend_info *be = kzalloc(sizeof(struct backend_info),
                                          GFP_KERNEL);
        if (!be) {
@@ -347,6 +351,15 @@ static int netback_probe(struct xenbus_device *dev,
        if (err)
                pr_debug("Error writing multi-queue-max-queues\n");
 
+       script = xenbus_read(XBT_NIL, dev->nodename, "script", NULL);
+       if (IS_ERR(script)) {
+               err = PTR_ERR(script);
+               xenbus_dev_fatal(dev, err, "reading script");
+               goto fail;
+       }
+
+       be->hotplug_script = script;
+
        err = xenbus_switch_state(dev, XenbusStateInitWait);
        if (err)
                goto fail;
@@ -379,22 +392,14 @@ static int netback_uevent(struct xenbus_device *xdev,
                          struct kobj_uevent_env *env)
 {
        struct backend_info *be = dev_get_drvdata(&xdev->dev);
-       char *val;
 
-       val = xenbus_read(XBT_NIL, xdev->nodename, "script", NULL);
-       if (IS_ERR(val)) {
-               int err = PTR_ERR(val);
-               xenbus_dev_fatal(xdev, err, "reading script");
-               return err;
-       } else {
-               if (add_uevent_var(env, "script=%s", val)) {
-                       kfree(val);
-                       return -ENOMEM;
-               }
-               kfree(val);
-       }
+       if (!be)
+               return 0;
 
-       if (!be || !be->vif)
+       if (add_uevent_var(env, "script=%s", be->hotplug_script))
+               return -ENOMEM;
+
+       if (!be->vif)
                return 0;
 
        return add_uevent_var(env, "vif=%s", be->vif->dev->name);
@@ -793,6 +798,7 @@ static void connect(struct backend_info *be)
                        goto err;
                }
 
+               queue->credit_bytes = credit_bytes;
                queue->remaining_credit = credit_bytes;
                queue->credit_usec = credit_usec;
 
index 3f45afd4382e164053dac1231978e91a5af6dbe0..e031c943286ef3f7765e42640397626d7555607c 100644 (file)
@@ -1698,6 +1698,7 @@ static void xennet_destroy_queues(struct netfront_info *info)
 
                if (netif_running(info->netdev))
                        napi_disable(&queue->napi);
+               del_timer_sync(&queue->rx_refill_timer);
                netif_napi_del(&queue->napi);
        }
 
@@ -2102,9 +2103,6 @@ static const struct attribute_group xennet_dev_group = {
 static int xennet_remove(struct xenbus_device *dev)
 {
        struct netfront_info *info = dev_get_drvdata(&dev->dev);
-       unsigned int num_queues = info->netdev->real_num_tx_queues;
-       struct netfront_queue *queue = NULL;
-       unsigned int i = 0;
 
        dev_dbg(&dev->dev, "%s\n", dev->nodename);
 
@@ -2112,16 +2110,7 @@ static int xennet_remove(struct xenbus_device *dev)
 
        unregister_netdev(info->netdev);
 
-       for (i = 0; i < num_queues; ++i) {
-               queue = &info->queues[i];
-               del_timer_sync(&queue->rx_refill_timer);
-       }
-
-       if (num_queues) {
-               kfree(info->queues);
-               info->queues = NULL;
-       }
-
+       xennet_destroy_queues(info);
        xennet_free_netdev(info->netdev);
 
        return 0;
index cd29b1038c5e3bf6f4a21659343c65584c44b969..15f9b7c9e4d38e93a52864a953e12d4172602797 100644 (file)
@@ -1660,6 +1660,7 @@ static int ntb_atom_detect(struct ntb_device *ndev)
        u32 ppd;
 
        ndev->hw_type = BWD_HW;
+       ndev->limits.max_mw = BWD_MAX_MW;
 
        rc = pci_read_config_dword(ndev->pdev, NTB_PPD_OFFSET, &ppd);
        if (rc)
@@ -1778,7 +1779,7 @@ static int ntb_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
                        dev_warn(&pdev->dev, "Cannot remap BAR %d\n",
                                 MW_TO_BAR(i));
                        rc = -EIO;
-                       goto err3;
+                       goto err4;
                }
        }
 
index 99764db0875aa0e1b34ca348ca1606c2a8990258..f0650265febf95cc6a37d03dd3d5b38b0d7370af 100644 (file)
@@ -189,7 +189,7 @@ int __of_attach_node_sysfs(struct device_node *np)
        return 0;
 }
 
-static int __init of_init(void)
+void __init of_core_init(void)
 {
        struct device_node *np;
 
@@ -198,7 +198,8 @@ static int __init of_init(void)
        of_kset = kset_create_and_add("devicetree", NULL, firmware_kobj);
        if (!of_kset) {
                mutex_unlock(&of_mutex);
-               return -ENOMEM;
+               pr_err("devicetree: failed to register existing nodes\n");
+               return;
        }
        for_each_of_allnodes(np)
                __of_attach_node_sysfs(np);
@@ -207,10 +208,7 @@ static int __init of_init(void)
        /* Symlink in /proc as required by userspace ABI */
        if (of_root)
                proc_symlink("device-tree", NULL, "/sys/firmware/devicetree/base");
-
-       return 0;
 }
-core_initcall(of_init);
 
 static struct property *__of_find_property(const struct device_node *np,
                                           const char *name, int *lenp)
index 3351ef408125d757f52ac772700687ef7f735c06..53826b84e0ec6d46d3699705f46216070a471867 100644 (file)
@@ -225,7 +225,7 @@ void __of_attach_node(struct device_node *np)
        phandle = __of_get_property(np, "phandle", &sz);
        if (!phandle)
                phandle = __of_get_property(np, "linux,phandle", &sz);
-       if (IS_ENABLED(PPC_PSERIES) && !phandle)
+       if (IS_ENABLED(CONFIG_PPC_PSERIES) && !phandle)
                phandle = __of_get_property(np, "ibm,phandle", &sz);
        np->phandle = (phandle && (sz >= 4)) ? be32_to_cpup(phandle) : 0;
 
index 8be2096c842390f5ecefc24186267e9ce4f61e2b..deeaed54422246dceb236f0a604696d5cddb2549 100644 (file)
@@ -348,7 +348,7 @@ int superio_fixup_irq(struct pci_dev *pcidev)
                BUG();
                return -1;
        }
-       printk("superio_fixup_irq(%s) ven 0x%x dev 0x%x from %pf\n",
+       printk(KERN_DEBUG "superio_fixup_irq(%s) ven 0x%x dev 0x%x from %ps\n",
                pci_name(pcidev),
                pcidev->vendor, pcidev->device,
                __builtin_return_address(0));
index 4fd0cacf7ca0ae0dfaebf5c612f457cdf6fa43f9..508cc56130e3f88d1b01716a7a00fead250fdf1c 100644 (file)
@@ -428,16 +428,19 @@ static void __assign_resources_sorted(struct list_head *head,
                 * consistent.
                 */
                if (add_align > dev_res->res->start) {
+                       resource_size_t r_size = resource_size(dev_res->res);
+
                        dev_res->res->start = add_align;
-                       dev_res->res->end = add_align +
-                                           resource_size(dev_res->res);
+                       dev_res->res->end = add_align + r_size - 1;
 
                        list_for_each_entry(dev_res2, head, list) {
                                align = pci_resource_alignment(dev_res2->dev,
                                                               dev_res2->res);
-                               if (add_align > align)
+                               if (add_align > align) {
                                        list_move_tail(&dev_res->list,
                                                       &dev_res2->list);
+                                       break;
+                               }
                        }
                }
 
index a53bd5b52df97ff48fa921a5009f2fa6937aa377..fc9b9f0ea91e8132b08c85478a592e3f820fc2cc 100644 (file)
@@ -38,7 +38,9 @@ config ARMADA375_USBCLUSTER_PHY
 config PHY_DM816X_USB
        tristate "TI dm816x USB PHY driver"
        depends on ARCH_OMAP2PLUS
+       depends on USB_SUPPORT
        select GENERIC_PHY
+       select USB_PHY
        help
          Enable this for dm816x USB to work.
 
@@ -97,8 +99,9 @@ config OMAP_CONTROL_PHY
 config OMAP_USB2
        tristate "OMAP USB2 PHY Driver"
        depends on ARCH_OMAP2PLUS
-       depends on USB_PHY
+       depends on USB_SUPPORT
        select GENERIC_PHY
+       select USB_PHY
        select OMAP_CONTROL_PHY
        depends on OMAP_OCP2SCP
        help
@@ -122,8 +125,9 @@ config TI_PIPE3
 config TWL4030_USB
        tristate "TWL4030 USB Transceiver Driver"
        depends on TWL4030_CORE && REGULATOR_TWL4030 && USB_MUSB_OMAP2PLUS
-       depends on USB_PHY
+       depends on USB_SUPPORT
        select GENERIC_PHY
+       select USB_PHY
        help
          Enable this to support the USB OTG transceiver on TWL4030
          family chips (including the TWL5030 and TPS659x0 devices).
@@ -304,7 +308,7 @@ config PHY_STIH41X_USB
 
 config PHY_QCOM_UFS
        tristate "Qualcomm UFS PHY driver"
-       depends on OF && ARCH_MSM
+       depends on OF && ARCH_QCOM
        select GENERIC_PHY
        help
          Support for UFS PHY on QCOM chipsets.
index 3791838f4bd4b14e145dd5718a3030c4b89d9f3b..63bc12d7a73e561a8e967ac4fb7f453c9a0d23ab 100644 (file)
@@ -530,7 +530,7 @@ struct phy *phy_optional_get(struct device *dev, const char *string)
 {
        struct phy *phy = phy_get(dev, string);
 
-       if (PTR_ERR(phy) == -ENODEV)
+       if (IS_ERR(phy) && (PTR_ERR(phy) == -ENODEV))
                phy = NULL;
 
        return phy;
@@ -584,7 +584,7 @@ struct phy *devm_phy_optional_get(struct device *dev, const char *string)
 {
        struct phy *phy = devm_phy_get(dev, string);
 
-       if (PTR_ERR(phy) == -ENODEV)
+       if (IS_ERR(phy) && (PTR_ERR(phy) == -ENODEV))
                phy = NULL;
 
        return phy;
index 183ef43681016ba0f238edfa98bbbef3684ab543..c1a468686bdc72433b7596512cb70852f3ef2420 100644 (file)
@@ -275,6 +275,7 @@ static int omap_usb2_probe(struct platform_device *pdev)
                phy->wkupclk = devm_clk_get(phy->dev, "usb_phy_cm_clk32k");
                if (IS_ERR(phy->wkupclk)) {
                        dev_err(&pdev->dev, "unable to get usb_phy_cm_clk32k\n");
+                       pm_runtime_disable(phy->dev);
                        return PTR_ERR(phy->wkupclk);
                } else {
                        dev_warn(&pdev->dev,
index 778276aba3aa0092d8e8e7bc2de15eae4f5a5a15..97d45f47d1ade847f9f0d7462d0ae91e91505974 100644 (file)
@@ -23,7 +23,7 @@
 #define USBHS_LPSTS                    0x02
 #define USBHS_UGCTRL                   0x80
 #define USBHS_UGCTRL2                  0x84
-#define USBHS_UGSTS                    0x88    /* The manuals have 0x90 */
+#define USBHS_UGSTS                    0x88    /* From technical update */
 
 /* Low Power Status register (LPSTS) */
 #define USBHS_LPSTS_SUSPM              0x4000
@@ -41,7 +41,7 @@
 #define USBHS_UGCTRL2_USB0SEL_HS_USB   0x00000030
 
 /* USB General status register (UGSTS) */
-#define USBHS_UGSTS_LOCK               0x00000300 /* The manuals have 0x3 */
+#define USBHS_UGSTS_LOCK               0x00000100 /* From technical update */
 
 #define PHYS_PER_CHANNEL       2
 
index 4ad5c1a996e3e906023bbe246c98a258ec3bba23..e406e3d8c1c71713e08ceb440e43900fbbb5b8be 100644 (file)
@@ -643,7 +643,9 @@ static const struct cygnus_gpio_pin_range cygnus_gpio_pintable[] = {
        CYGNUS_PINRANGE(87, 104, 12),
        CYGNUS_PINRANGE(99, 102, 2),
        CYGNUS_PINRANGE(101, 90, 4),
-       CYGNUS_PINRANGE(105, 116, 10),
+       CYGNUS_PINRANGE(105, 116, 6),
+       CYGNUS_PINRANGE(111, 100, 2),
+       CYGNUS_PINRANGE(113, 122, 4),
        CYGNUS_PINRANGE(123, 11, 1),
        CYGNUS_PINRANGE(124, 38, 4),
        CYGNUS_PINRANGE(128, 43, 1),
index 89dca77ca0382e93909188cad63ccd9ef6bff41b..18ee2089df4ae84e7edb6f665146be84ca43b83f 100644 (file)
@@ -1110,7 +1110,7 @@ void devm_pinctrl_put(struct pinctrl *p)
 EXPORT_SYMBOL_GPL(devm_pinctrl_put);
 
 int pinctrl_register_map(struct pinctrl_map const *maps, unsigned num_maps,
-                        bool dup, bool locked)
+                        bool dup)
 {
        int i, ret;
        struct pinctrl_maps *maps_node;
@@ -1178,11 +1178,9 @@ int pinctrl_register_map(struct pinctrl_map const *maps, unsigned num_maps,
                maps_node->maps = maps;
        }
 
-       if (!locked)
-               mutex_lock(&pinctrl_maps_mutex);
+       mutex_lock(&pinctrl_maps_mutex);
        list_add_tail(&maps_node->node, &pinctrl_maps);
-       if (!locked)
-               mutex_unlock(&pinctrl_maps_mutex);
+       mutex_unlock(&pinctrl_maps_mutex);
 
        return 0;
 }
@@ -1197,7 +1195,7 @@ int pinctrl_register_map(struct pinctrl_map const *maps, unsigned num_maps,
 int pinctrl_register_mappings(struct pinctrl_map const *maps,
                              unsigned num_maps)
 {
-       return pinctrl_register_map(maps, num_maps, true, false);
+       return pinctrl_register_map(maps, num_maps, true);
 }
 
 void pinctrl_unregister_map(struct pinctrl_map const *map)
index 75476b3d87dafe00c6273931a4e3a137f1509dfa..b24ea846c8677ebea49ffd435c04c3de40f226b9 100644 (file)
@@ -183,7 +183,7 @@ static inline struct pin_desc *pin_desc_get(struct pinctrl_dev *pctldev,
 }
 
 int pinctrl_register_map(struct pinctrl_map const *maps, unsigned num_maps,
-                        bool dup, bool locked);
+                        bool dup);
 void pinctrl_unregister_map(struct pinctrl_map const *map);
 
 extern int pinctrl_force_sleep(struct pinctrl_dev *pctldev);
index eda13de2e7c0d110f5e105a84b5b19da93cadc36..0bbf7d71b2811242a5a69db9fe97389c1acde5e8 100644 (file)
@@ -92,7 +92,7 @@ static int dt_remember_or_free_map(struct pinctrl *p, const char *statename,
        dt_map->num_maps = num_maps;
        list_add_tail(&dt_map->node, &p->dt_maps);
 
-       return pinctrl_register_map(map, num_maps, false, true);
+       return pinctrl_register_map(map, num_maps, false);
 }
 
 struct pinctrl_dev *of_pinctrl_get(struct device_node *np)
index 82f691eeeec4d82cd5e75b7a96be719befbcd57f..732ff757a95fe12fe7b5ddca1714a8e527017e90 100644 (file)
@@ -1292,6 +1292,49 @@ static void chv_gpio_irq_unmask(struct irq_data *d)
        chv_gpio_irq_mask_unmask(d, false);
 }
 
+static unsigned chv_gpio_irq_startup(struct irq_data *d)
+{
+       /*
+        * Check if the interrupt has been requested with 0 as triggering
+        * type. In that case it is assumed that the current values
+        * programmed to the hardware are used (e.g BIOS configured
+        * defaults).
+        *
+        * In that case ->irq_set_type() will never be called so we need to
+        * read back the values from hardware now, set correct flow handler
+        * and update mappings before the interrupt is being used.
+        */
+       if (irqd_get_trigger_type(d) == IRQ_TYPE_NONE) {
+               struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
+               struct chv_pinctrl *pctrl = gpiochip_to_pinctrl(gc);
+               unsigned offset = irqd_to_hwirq(d);
+               int pin = chv_gpio_offset_to_pin(pctrl, offset);
+               irq_flow_handler_t handler;
+               unsigned long flags;
+               u32 intsel, value;
+
+               intsel = readl(chv_padreg(pctrl, pin, CHV_PADCTRL0));
+               intsel &= CHV_PADCTRL0_INTSEL_MASK;
+               intsel >>= CHV_PADCTRL0_INTSEL_SHIFT;
+
+               value = readl(chv_padreg(pctrl, pin, CHV_PADCTRL1));
+               if (value & CHV_PADCTRL1_INTWAKECFG_LEVEL)
+                       handler = handle_level_irq;
+               else
+                       handler = handle_edge_irq;
+
+               spin_lock_irqsave(&pctrl->lock, flags);
+               if (!pctrl->intr_lines[intsel]) {
+                       __irq_set_handler_locked(d->irq, handler);
+                       pctrl->intr_lines[intsel] = offset;
+               }
+               spin_unlock_irqrestore(&pctrl->lock, flags);
+       }
+
+       chv_gpio_irq_unmask(d);
+       return 0;
+}
+
 static int chv_gpio_irq_type(struct irq_data *d, unsigned type)
 {
        struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
@@ -1357,6 +1400,7 @@ static int chv_gpio_irq_type(struct irq_data *d, unsigned type)
 
 static struct irq_chip chv_gpio_irqchip = {
        .name = "chv-gpio",
+       .irq_startup = chv_gpio_irq_startup,
        .irq_ack = chv_gpio_irq_ack,
        .irq_mask = chv_gpio_irq_mask,
        .irq_unmask = chv_gpio_irq_unmask,
index 493294c0ebe6faccf0dc8c0e5f15b98ddf9d76b0..474812e2b0cb97c806402fda486ab2e883398c06 100644 (file)
@@ -881,6 +881,8 @@ static int mtk_gpio_set_debounce(struct gpio_chip *chip, unsigned offset,
        if (!mtk_eint_get_mask(pctl, eint_num)) {
                mtk_eint_mask(d);
                unmask = 1;
+       } else {
+               unmask = 0;
        }
 
        clr_bit = 0xff << eint_offset;
index edcd140e089968e0f7b95fef4ffcd82f157f8294..a70a5fe79d44d343b0e1830ccd36fe7b6384d314 100644 (file)
@@ -569,7 +569,7 @@ static int meson_gpiolib_register(struct meson_pinctrl *pc)
                domain->chip.direction_output = meson_gpio_direction_output;
                domain->chip.get = meson_gpio_get;
                domain->chip.set = meson_gpio_set;
-               domain->chip.base = -1;
+               domain->chip.base = domain->data->pin_base;
                domain->chip.ngpio = domain->data->num_pins;
                domain->chip.can_sleep = false;
                domain->chip.of_node = domain->of_node;
index 2f7ea62298801c2a5b9b87605a3fe5fbb0ca00bd..9677807db364d70ee4512799e26449bccba56a08 100644 (file)
@@ -876,13 +876,13 @@ static struct meson_domain_data meson8b_domain_data[] = {
                .banks          = meson8b_banks,
                .num_banks      = ARRAY_SIZE(meson8b_banks),
                .pin_base       = 0,
-               .num_pins       = 83,
+               .num_pins       = 130,
        },
        {
                .name           = "ao-bank",
                .banks          = meson8b_ao_banks,
                .num_banks      = ARRAY_SIZE(meson8b_ao_banks),
-               .pin_base       = 83,
+               .pin_base       = 130,
                .num_pins       = 16,
        },
 };
index 42f930f70de31e9086d4d7f7fec78a47d83cbfcc..03aa58c4cb85bd04cb4b043f09a1e9aec5f19cc1 100644 (file)
@@ -364,7 +364,7 @@ static struct mvebu_mpp_mode mv88f6710_mpp_modes[] = {
           MPP_FUNCTION(0x5, "audio", "mclk"),
           MPP_FUNCTION(0x6, "uart0", "cts")),
        MPP_MODE(63,
-          MPP_FUNCTION(0x0, "gpo", NULL),
+          MPP_FUNCTION(0x0, "gpio", NULL),
           MPP_FUNCTION(0x1, "spi0", "sck"),
           MPP_FUNCTION(0x2, "tclk", NULL)),
        MPP_MODE(64,
index b2d22218a2582f94b2c5d0274843fa0c2d3d7162..ae4115e4b4efc676c69cb5f19c5a92956fed6507 100644 (file)
@@ -260,6 +260,7 @@ static int pmic_gpio_set_mux(struct pinctrl_dev *pctldev, unsigned function,
                        val = 1;
        }
 
+       val = val << PMIC_GPIO_REG_MODE_DIR_SHIFT;
        val |= pad->function << PMIC_GPIO_REG_MODE_FUNCTION_SHIFT;
        val |= pad->out_value & PMIC_GPIO_REG_MODE_VALUE_SHIFT;
 
@@ -417,7 +418,7 @@ static int pmic_gpio_config_set(struct pinctrl_dev *pctldev, unsigned int pin,
                return ret;
 
        val = pad->buffer_type << PMIC_GPIO_REG_OUT_TYPE_SHIFT;
-       val = pad->strength << PMIC_GPIO_REG_OUT_STRENGTH_SHIFT;
+       val |= pad->strength << PMIC_GPIO_REG_OUT_STRENGTH_SHIFT;
 
        ret = pmic_gpio_write(state, pad, PMIC_GPIO_REG_DIG_OUT_CTL, val);
        if (ret < 0)
@@ -466,12 +467,13 @@ static void pmic_gpio_config_dbg_show(struct pinctrl_dev *pctldev,
                seq_puts(s, " ---");
        } else {
 
-               if (!pad->input_enabled) {
+               if (pad->input_enabled) {
                        ret = pmic_gpio_read(state, pad, PMIC_MPP_REG_RT_STS);
-                       if (!ret) {
-                               ret &= PMIC_MPP_REG_RT_STS_VAL_MASK;
-                               pad->out_value = ret;
-                       }
+                       if (ret < 0)
+                               return;
+
+                       ret &= PMIC_MPP_REG_RT_STS_VAL_MASK;
+                       pad->out_value = ret;
                }
 
                seq_printf(s, " %-4s", pad->output_enabled ? "out" : "in");
index 8f36c5f9194903fd8433736499a03a61afbfb2ac..211b942ad6d544ade10ea2fa91c54e5210efa290 100644 (file)
@@ -370,6 +370,7 @@ static int pmic_mpp_set_mux(struct pinctrl_dev *pctldev, unsigned function,
                }
        }
 
+       val = val << PMIC_MPP_REG_MODE_DIR_SHIFT;
        val |= pad->function << PMIC_MPP_REG_MODE_FUNCTION_SHIFT;
        val |= pad->out_value & PMIC_MPP_REG_MODE_VALUE_MASK;
 
@@ -576,10 +577,11 @@ static void pmic_mpp_config_dbg_show(struct pinctrl_dev *pctldev,
 
                if (pad->input_enabled) {
                        ret = pmic_mpp_read(state, pad, PMIC_MPP_REG_RT_STS);
-                       if (!ret) {
-                               ret &= PMIC_MPP_REG_RT_STS_VAL_MASK;
-                               pad->out_value = ret;
-                       }
+                       if (ret < 0)
+                               return;
+
+                       ret &= PMIC_MPP_REG_RT_STS_VAL_MASK;
+                       pad->out_value = ret;
                }
 
                seq_printf(s, " %-4s", pad->output_enabled ? "out" : "in");
index b3d419a8472341dabee36c3cb40765157be443a9..b496db87bc0505368fe4501b6199f653f7a257e0 100644 (file)
@@ -829,6 +829,13 @@ static void ideapad_acpi_notify(acpi_handle handle, u32 event, void *data)
  * report all radios as hardware-blocked.
  */
 static const struct dmi_system_id no_hw_rfkill_list[] = {
+       {
+               .ident = "Lenovo G40-30",
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
+                       DMI_MATCH(DMI_PRODUCT_VERSION, "Lenovo G40-30"),
+               },
+       },
        {
                .ident = "Lenovo Yoga 2 11 / 13 / Pro",
                .matches = {
index 7769575345d89f6ed4b3efc8068258104291bdfb..28f328136f0df78fe3253d6996ae9108229f87e5 100644 (file)
@@ -2115,7 +2115,7 @@ static int hotkey_mask_get(void)
        return 0;
 }
 
-void static hotkey_mask_warn_incomplete_mask(void)
+static void hotkey_mask_warn_incomplete_mask(void)
 {
        /* log only what the user can fix... */
        const u32 wantedmask = hotkey_driver_mask &
@@ -2897,7 +2897,7 @@ static ssize_t hotkey_wakeup_reason_show(struct device *dev,
        return snprintf(buf, PAGE_SIZE, "%d\n", hotkey_wakeup_reason);
 }
 
-static DEVICE_ATTR_RO(hotkey_wakeup_reason);
+static DEVICE_ATTR(wakeup_reason, S_IRUGO, hotkey_wakeup_reason_show, NULL);
 
 static void hotkey_wakeup_reason_notify_change(void)
 {
@@ -2913,7 +2913,8 @@ static ssize_t hotkey_wakeup_hotunplug_complete_show(struct device *dev,
        return snprintf(buf, PAGE_SIZE, "%d\n", hotkey_autosleep_ack);
 }
 
-static DEVICE_ATTR_RO(hotkey_wakeup_hotunplug_complete);
+static DEVICE_ATTR(wakeup_hotunplug_complete, S_IRUGO,
+                  hotkey_wakeup_hotunplug_complete_show, NULL);
 
 static void hotkey_wakeup_hotunplug_complete_notify_change(void)
 {
@@ -2978,8 +2979,8 @@ static struct attribute *hotkey_attributes[] __initdata = {
        &dev_attr_hotkey_enable.attr,
        &dev_attr_hotkey_bios_enabled.attr,
        &dev_attr_hotkey_bios_mask.attr,
-       &dev_attr_hotkey_wakeup_reason.attr,
-       &dev_attr_hotkey_wakeup_hotunplug_complete.attr,
+       &dev_attr_wakeup_reason.attr,
+       &dev_attr_wakeup_hotunplug_complete.attr,
        &dev_attr_hotkey_mask.attr,
        &dev_attr_hotkey_all_mask.attr,
        &dev_attr_hotkey_recommended_mask.attr,
@@ -4393,12 +4394,13 @@ static ssize_t wan_enable_store(struct device *dev,
                        attr, buf, count);
 }
 
-static DEVICE_ATTR_RW(wan_enable);
+static DEVICE_ATTR(wwan_enable, S_IWUSR | S_IRUGO,
+                  wan_enable_show, wan_enable_store);
 
 /* --------------------------------------------------------------------- */
 
 static struct attribute *wan_attributes[] = {
-       &dev_attr_wan_enable.attr,
+       &dev_attr_wwan_enable.attr,
        NULL
 };
 
@@ -8138,7 +8140,8 @@ static ssize_t fan_pwm1_enable_store(struct device *dev,
        return count;
 }
 
-static DEVICE_ATTR_RW(fan_pwm1_enable);
+static DEVICE_ATTR(pwm1_enable, S_IWUSR | S_IRUGO,
+                  fan_pwm1_enable_show, fan_pwm1_enable_store);
 
 /* sysfs fan pwm1 ------------------------------------------------------ */
 static ssize_t fan_pwm1_show(struct device *dev,
@@ -8198,7 +8201,7 @@ static ssize_t fan_pwm1_store(struct device *dev,
        return (rc) ? rc : count;
 }
 
-static DEVICE_ATTR_RW(fan_pwm1);
+static DEVICE_ATTR(pwm1, S_IWUSR | S_IRUGO, fan_pwm1_show, fan_pwm1_store);
 
 /* sysfs fan fan1_input ------------------------------------------------ */
 static ssize_t fan_fan1_input_show(struct device *dev,
@@ -8215,7 +8218,7 @@ static ssize_t fan_fan1_input_show(struct device *dev,
        return snprintf(buf, PAGE_SIZE, "%u\n", speed);
 }
 
-static DEVICE_ATTR_RO(fan_fan1_input);
+static DEVICE_ATTR(fan1_input, S_IRUGO, fan_fan1_input_show, NULL);
 
 /* sysfs fan fan2_input ------------------------------------------------ */
 static ssize_t fan_fan2_input_show(struct device *dev,
@@ -8232,7 +8235,7 @@ static ssize_t fan_fan2_input_show(struct device *dev,
        return snprintf(buf, PAGE_SIZE, "%u\n", speed);
 }
 
-static DEVICE_ATTR_RO(fan_fan2_input);
+static DEVICE_ATTR(fan2_input, S_IRUGO, fan_fan2_input_show, NULL);
 
 /* sysfs fan fan_watchdog (hwmon driver) ------------------------------- */
 static ssize_t fan_fan_watchdog_show(struct device_driver *drv,
@@ -8265,8 +8268,8 @@ static DRIVER_ATTR(fan_watchdog, S_IWUSR | S_IRUGO,
 
 /* --------------------------------------------------------------------- */
 static struct attribute *fan_attributes[] = {
-       &dev_attr_fan_pwm1_enable.attr, &dev_attr_fan_pwm1.attr,
-       &dev_attr_fan_fan1_input.attr,
+       &dev_attr_pwm1_enable.attr, &dev_attr_pwm1.attr,
+       &dev_attr_fan1_input.attr,
        NULL, /* for fan2_input */
        NULL
 };
@@ -8400,7 +8403,7 @@ static int __init fan_init(struct ibm_init_struct *iibm)
                if (tp_features.second_fan) {
                        /* attach second fan tachometer */
                        fan_attributes[ARRAY_SIZE(fan_attributes)-2] =
-                                       &dev_attr_fan_fan2_input.attr;
+                                       &dev_attr_fan2_input.attr;
                }
                rc = sysfs_create_group(&tpacpi_sensors_pdev->dev.kobj,
                                         &fan_attr_group);
@@ -8848,7 +8851,7 @@ static ssize_t thinkpad_acpi_pdev_name_show(struct device *dev,
        return snprintf(buf, PAGE_SIZE, "%s\n", TPACPI_NAME);
 }
 
-static DEVICE_ATTR_RO(thinkpad_acpi_pdev_name);
+static DEVICE_ATTR(name, S_IRUGO, thinkpad_acpi_pdev_name_show, NULL);
 
 /* --------------------------------------------------------------------- */
 
@@ -9390,8 +9393,7 @@ static void thinkpad_acpi_module_exit(void)
                hwmon_device_unregister(tpacpi_hwmon);
 
        if (tp_features.sensors_pdev_attrs_registered)
-               device_remove_file(&tpacpi_sensors_pdev->dev,
-                                  &dev_attr_thinkpad_acpi_pdev_name);
+               device_remove_file(&tpacpi_sensors_pdev->dev, &dev_attr_name);
        if (tpacpi_sensors_pdev)
                platform_device_unregister(tpacpi_sensors_pdev);
        if (tpacpi_pdev)
@@ -9512,8 +9514,7 @@ static int __init thinkpad_acpi_module_init(void)
                thinkpad_acpi_module_exit();
                return ret;
        }
-       ret = device_create_file(&tpacpi_sensors_pdev->dev,
-                                &dev_attr_thinkpad_acpi_pdev_name);
+       ret = device_create_file(&tpacpi_sensors_pdev->dev, &dev_attr_name);
        if (ret) {
                pr_err("unable to create sysfs hwmon device attributes\n");
                thinkpad_acpi_module_exit();
index ca1cc5a47eb1e02b9acd38f1aeff2abf93bbf6ac..bd1dbfee2515dda65c54176d9b2e547cb4e3beca 100644 (file)
@@ -1149,6 +1149,7 @@ static struct platform_driver axp288_fuel_gauge_driver = {
 
 module_platform_driver(axp288_fuel_gauge_driver);
 
+MODULE_AUTHOR("Ramakrishna Pallala <ramakrishna.pallala@intel.com>");
 MODULE_AUTHOR("Todd Brandt <todd.e.brandt@linux.intel.com>");
 MODULE_DESCRIPTION("Xpower AXP288 Fuel Gauge Driver");
 MODULE_LICENSE("GPL");
index a57433de5c249fa33e6fb4f59e7c2dbf3190208b..b6b98378faa32b50c0e1900c76ca4e26da3bd6c1 100644 (file)
@@ -1109,6 +1109,14 @@ static void __exit bq27x00_battery_exit(void)
 }
 module_exit(bq27x00_battery_exit);
 
+#ifdef CONFIG_BATTERY_BQ27X00_PLATFORM
+MODULE_ALIAS("platform:bq27000-battery");
+#endif
+
+#ifdef CONFIG_BATTERY_BQ27X00_I2C
+MODULE_ALIAS("i2c:bq27000-battery");
+#endif
+
 MODULE_AUTHOR("Rodolfo Giometti <giometti@linux.it>");
 MODULE_DESCRIPTION("BQ27x00 battery monitor driver");
 MODULE_LICENSE("GPL");
index 2da9ed8ccbb5391f50c7137866b3fad5669dd2d7..8a971b3dbe583f0dc2640ddfa867f33c3e2c0ef4 100644 (file)
@@ -347,7 +347,7 @@ static int collie_bat_probe(struct ucb1x00_dev *dev)
                goto err_psy_reg_main;
        }
 
-       psy_main_cfg.drv_data = &collie_bat_bu;
+       psy_bu_cfg.drv_data = &collie_bat_bu;
        collie_bat_bu.psy = power_supply_register(&dev->ucb->dev,
                                                  &collie_bat_bu_desc,
                                                  &psy_bu_cfg);
index aad9c3318c02a271a864da8866b9b38c4623768c..17d93a73c5136e53ab2955d7aba02a7ef0c85d1f 100644 (file)
@@ -41,6 +41,7 @@ config POWER_RESET_AXXIA
 config POWER_RESET_BRCMSTB
        bool "Broadcom STB reset driver"
        depends on ARM || MIPS || COMPILE_TEST
+       depends on MFD_SYSCON
        default ARCH_BRCMSTB
        help
          This driver provides restart support for Broadcom STB boards.
index 01c7055c4200e3d9a7333ac7c0bcaccc3ac2d4a5..ca461ebc7ae8f73338059d6ce9547b850c269f1b 100644 (file)
@@ -212,9 +212,9 @@ static int at91_reset_platform_probe(struct platform_device *pdev)
                res = platform_get_resource(pdev, IORESOURCE_MEM, idx + 1 );
                at91_ramc_base[idx] = devm_ioremap(&pdev->dev, res->start,
                                                   resource_size(res));
-               if (IS_ERR(at91_ramc_base[idx])) {
+               if (!at91_ramc_base[idx]) {
                        dev_err(&pdev->dev, "Could not map ram controller address\n");
-                       return PTR_ERR(at91_ramc_base[idx]);
+                       return -ENOMEM;
                }
        }
 
index 7ef193b6f7fe81451c504797cec9bb4932879ee8..1e08195551fe7d505511a6dd92b07d1ab4300911 100644 (file)
@@ -120,18 +120,7 @@ static enum hrtimer_restart ltc2952_poweroff_timer_wde(struct hrtimer *timer)
 
 static void ltc2952_poweroff_start_wde(struct ltc2952_poweroff *data)
 {
-       if (hrtimer_start(&data->timer_wde, data->wde_interval,
-                         HRTIMER_MODE_REL)) {
-               /*
-                * The device will not toggle the watchdog reset,
-                * thus shut down is only safe if the PowerPath controller
-                * has a long enough time-off before triggering a hardware
-                * power-off.
-                *
-                * Only sending a warning as the system will power-off anyway
-                */
-               dev_err(data->dev, "unable to start the timer\n");
-       }
+       hrtimer_start(&data->timer_wde, data->wde_interval, HRTIMER_MODE_REL);
 }
 
 static enum hrtimer_restart
@@ -165,9 +154,8 @@ static irqreturn_t ltc2952_poweroff_handler(int irq, void *dev_id)
        }
 
        if (gpiod_get_value(data->gpio_trigger)) {
-               if (hrtimer_start(&data->timer_trigger, data->trigger_delay,
-                                 HRTIMER_MODE_REL))
-                       dev_err(data->dev, "unable to start the wait timer\n");
+               hrtimer_start(&data->timer_trigger, data->trigger_delay,
+                             HRTIMER_MODE_REL);
        } else {
                hrtimer_cancel(&data->timer_trigger);
                /* omitting return value check, timer should have been valid */
index 476171a768d61def6d1f1e476ebc6db78c60839b..8a029f9bc18cb0f0c2c95bc7ea4d9167164326be 100644 (file)
@@ -16,6 +16,7 @@
 #include <linux/mfd/syscon.h>
 #include <linux/module.h>
 #include <linux/of.h>
+#include <linux/of_device.h>
 #include <linux/platform_device.h>
 #include <linux/pwm.h>
 #include <linux/regmap.h>
 #define PERIP_PWM_PDM_CONTROL_CH_MASK          0x1
 #define PERIP_PWM_PDM_CONTROL_CH_SHIFT(ch)     ((ch) * 4)
 
-#define MAX_TMBASE_STEPS                       65536
+/*
+ * PWM period is specified with a timebase register,
+ * in number of step periods. The PWM duty cycle is also
+ * specified in step periods, in the [0, $timebase] range.
+ * In other words, the timebase imposes the duty cycle
+ * resolution. Therefore, let's constraint the timebase to
+ * a minimum value to allow a sane range of duty cycle values.
+ * Imposing a minimum timebase, will impose a maximum PWM frequency.
+ *
+ * The value chosen is completely arbitrary.
+ */
+#define MIN_TMBASE_STEPS                       16
+
+struct img_pwm_soc_data {
+       u32 max_timebase;
+};
 
 struct img_pwm_chip {
        struct device   *dev;
@@ -47,6 +63,9 @@ struct img_pwm_chip {
        struct clk      *sys_clk;
        void __iomem    *base;
        struct regmap   *periph_regs;
+       int             max_period_ns;
+       int             min_period_ns;
+       const struct img_pwm_soc_data   *data;
 };
 
 static inline struct img_pwm_chip *to_img_pwm_chip(struct pwm_chip *chip)
@@ -72,24 +91,31 @@ static int img_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
        u32 val, div, duty, timebase;
        unsigned long mul, output_clk_hz, input_clk_hz;
        struct img_pwm_chip *pwm_chip = to_img_pwm_chip(chip);
+       unsigned int max_timebase = pwm_chip->data->max_timebase;
+
+       if (period_ns < pwm_chip->min_period_ns ||
+           period_ns > pwm_chip->max_period_ns) {
+               dev_err(chip->dev, "configured period not in range\n");
+               return -ERANGE;
+       }
 
        input_clk_hz = clk_get_rate(pwm_chip->pwm_clk);
        output_clk_hz = DIV_ROUND_UP(NSEC_PER_SEC, period_ns);
 
        mul = DIV_ROUND_UP(input_clk_hz, output_clk_hz);
-       if (mul <= MAX_TMBASE_STEPS) {
+       if (mul <= max_timebase) {
                div = PWM_CTRL_CFG_NO_SUB_DIV;
                timebase = DIV_ROUND_UP(mul, 1);
-       } else if (mul <= MAX_TMBASE_STEPS * 8) {
+       } else if (mul <= max_timebase * 8) {
                div = PWM_CTRL_CFG_SUB_DIV0;
                timebase = DIV_ROUND_UP(mul, 8);
-       } else if (mul <= MAX_TMBASE_STEPS * 64) {
+       } else if (mul <= max_timebase * 64) {
                div = PWM_CTRL_CFG_SUB_DIV1;
                timebase = DIV_ROUND_UP(mul, 64);
-       } else if (mul <= MAX_TMBASE_STEPS * 512) {
+       } else if (mul <= max_timebase * 512) {
                div = PWM_CTRL_CFG_SUB_DIV0_DIV1;
                timebase = DIV_ROUND_UP(mul, 512);
-       } else if (mul > MAX_TMBASE_STEPS * 512) {
+       } else if (mul > max_timebase * 512) {
                dev_err(chip->dev,
                        "failed to configure timebase steps/divider value\n");
                return -EINVAL;
@@ -143,11 +169,27 @@ static const struct pwm_ops img_pwm_ops = {
        .owner = THIS_MODULE,
 };
 
+static const struct img_pwm_soc_data pistachio_pwm = {
+       .max_timebase = 255,
+};
+
+static const struct of_device_id img_pwm_of_match[] = {
+       {
+               .compatible = "img,pistachio-pwm",
+               .data = &pistachio_pwm,
+       },
+       { }
+};
+MODULE_DEVICE_TABLE(of, img_pwm_of_match);
+
 static int img_pwm_probe(struct platform_device *pdev)
 {
        int ret;
+       u64 val;
+       unsigned long clk_rate;
        struct resource *res;
        struct img_pwm_chip *pwm;
+       const struct of_device_id *of_dev_id;
 
        pwm = devm_kzalloc(&pdev->dev, sizeof(*pwm), GFP_KERNEL);
        if (!pwm)
@@ -160,6 +202,11 @@ static int img_pwm_probe(struct platform_device *pdev)
        if (IS_ERR(pwm->base))
                return PTR_ERR(pwm->base);
 
+       of_dev_id = of_match_device(img_pwm_of_match, &pdev->dev);
+       if (!of_dev_id)
+               return -ENODEV;
+       pwm->data = of_dev_id->data;
+
        pwm->periph_regs = syscon_regmap_lookup_by_phandle(pdev->dev.of_node,
                                                           "img,cr-periph");
        if (IS_ERR(pwm->periph_regs))
@@ -189,6 +236,17 @@ static int img_pwm_probe(struct platform_device *pdev)
                goto disable_sysclk;
        }
 
+       clk_rate = clk_get_rate(pwm->pwm_clk);
+
+       /* The maximum input clock divider is 512 */
+       val = (u64)NSEC_PER_SEC * 512 * pwm->data->max_timebase;
+       do_div(val, clk_rate);
+       pwm->max_period_ns = val;
+
+       val = (u64)NSEC_PER_SEC * MIN_TMBASE_STEPS;
+       do_div(val, clk_rate);
+       pwm->min_period_ns = val;
+
        pwm->chip.dev = &pdev->dev;
        pwm->chip.ops = &img_pwm_ops;
        pwm->chip.base = -1;
@@ -228,12 +286,6 @@ static int img_pwm_remove(struct platform_device *pdev)
        return pwmchip_remove(&pwm_chip->chip);
 }
 
-static const struct of_device_id img_pwm_of_match[] = {
-       { .compatible = "img,pistachio-pwm", },
-       { }
-};
-MODULE_DEVICE_TABLE(of, img_pwm_of_match);
-
 static struct platform_driver img_pwm_driver = {
        .driver = {
                .name = "img-pwm",
index a1d07d347c20e30af065d204d94a314d18c408e3..1e492feaa9c66014c26871353d0df601521c87e6 100644 (file)
@@ -78,11 +78,6 @@ static int arizona_ldo1_hc_set_voltage_sel(struct regulator_dev *rdev,
        if (ret != 0)
                return ret;
 
-       ret = regmap_update_bits(regmap, ARIZONA_DYNAMIC_FREQUENCY_SCALING_1,
-                                ARIZONA_SUBSYS_MAX_FREQ, val);
-       if (ret != 0)
-               return ret;
-
        if (val)
                return 0;
 
index 8a4df7a1f2eecc879a679711d13d64885397af39..e628d4c2f2ae43de1955aac857f745ec2d3d0357 100644 (file)
@@ -394,6 +394,7 @@ static inline struct da9052_regulator_info *find_regulator_info(u8 chip_id,
 
 static int da9052_regulator_probe(struct platform_device *pdev)
 {
+       const struct mfd_cell *cell = mfd_get_cell(pdev);
        struct regulator_config config = { };
        struct da9052_regulator *regulator;
        struct da9052 *da9052;
@@ -409,7 +410,7 @@ static int da9052_regulator_probe(struct platform_device *pdev)
        regulator->da9052 = da9052;
 
        regulator->info = find_regulator_info(regulator->da9052->chip_id,
-                                             pdev->id);
+                                             cell->id);
        if (regulator->info == NULL) {
                dev_err(&pdev->dev, "invalid regulator ID specified\n");
                return -EINVAL;
@@ -419,7 +420,7 @@ static int da9052_regulator_probe(struct platform_device *pdev)
        config.driver_data = regulator;
        config.regmap = da9052->regmap;
        if (pdata && pdata->regulators) {
-               config.init_data = pdata->regulators[pdev->id];
+               config.init_data = pdata->regulators[cell->id];
        } else {
 #ifdef CONFIG_OF
                struct device_node *nproot = da9052->dev->of_node;
index 6149ae01e11f9dfc2441efb49d1a04c2915cc3d4..0fe4ad8826b2cda45044d8699696486cbd4bd1eb 100644 (file)
@@ -164,6 +164,16 @@ config RTC_DRV_ABB5ZES3
          This driver can also be built as a module. If so, the module
          will be called rtc-ab-b5ze-s3.
 
+config RTC_DRV_ABX80X
+       tristate "Abracon ABx80x"
+       help
+         If you say yes here you get support for Abracon AB080X and AB180X
+         families of ultra-low-power  battery- and capacitor-backed real-time
+         clock chips.
+
+         This driver can also be built as a module. If so, the module
+         will be called rtc-abx80x.
+
 config RTC_DRV_AS3722
        tristate "ams AS3722 RTC driver"
        depends on MFD_AS3722
index c31731c297624096e5526be906dd3f8bea0a2f7a..2b82e2b0311bd9da719b037e5d217fdee9efc652 100644 (file)
@@ -25,6 +25,7 @@ obj-$(CONFIG_RTC_DRV_88PM80X) += rtc-88pm80x.o
 obj-$(CONFIG_RTC_DRV_AB3100)   += rtc-ab3100.o
 obj-$(CONFIG_RTC_DRV_AB8500)   += rtc-ab8500.o
 obj-$(CONFIG_RTC_DRV_ABB5ZES3) += rtc-ab-b5ze-s3.o
+obj-$(CONFIG_RTC_DRV_ABX80X)   += rtc-abx80x.o
 obj-$(CONFIG_RTC_DRV_ARMADA38X)        += rtc-armada38x.o
 obj-$(CONFIG_RTC_DRV_AS3722)   += rtc-as3722.o
 obj-$(CONFIG_RTC_DRV_AT32AP700X)+= rtc-at32ap700x.o
diff --git a/drivers/rtc/rtc-abx80x.c b/drivers/rtc/rtc-abx80x.c
new file mode 100644 (file)
index 0000000..4337c3b
--- /dev/null
@@ -0,0 +1,307 @@
+/*
+ * A driver for the I2C members of the Abracon AB x8xx RTC family,
+ * and compatible: AB 1805 and AB 0805
+ *
+ * Copyright 2014-2015 Macq S.A.
+ *
+ * Author: Philippe De Muyter <phdm@macqel.be>
+ * Author: Alexandre Belloni <alexandre.belloni@free-electrons.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ */
+
+#include <linux/bcd.h>
+#include <linux/i2c.h>
+#include <linux/module.h>
+#include <linux/rtc.h>
+
+#define ABX8XX_REG_HTH         0x00
+#define ABX8XX_REG_SC          0x01
+#define ABX8XX_REG_MN          0x02
+#define ABX8XX_REG_HR          0x03
+#define ABX8XX_REG_DA          0x04
+#define ABX8XX_REG_MO          0x05
+#define ABX8XX_REG_YR          0x06
+#define ABX8XX_REG_WD          0x07
+
+#define ABX8XX_REG_CTRL1       0x10
+#define ABX8XX_CTRL_WRITE      BIT(1)
+#define ABX8XX_CTRL_12_24      BIT(6)
+
+#define ABX8XX_REG_CFG_KEY     0x1f
+#define ABX8XX_CFG_KEY_MISC    0x9d
+
+#define ABX8XX_REG_ID0         0x28
+
+#define ABX8XX_REG_TRICKLE     0x20
+#define ABX8XX_TRICKLE_CHARGE_ENABLE   0xa0
+#define ABX8XX_TRICKLE_STANDARD_DIODE  0x8
+#define ABX8XX_TRICKLE_SCHOTTKY_DIODE  0x4
+
+static u8 trickle_resistors[] = {0, 3, 6, 11};
+
+enum abx80x_chip {AB0801, AB0803, AB0804, AB0805,
+       AB1801, AB1803, AB1804, AB1805, ABX80X};
+
+struct abx80x_cap {
+       u16 pn;
+       bool has_tc;
+};
+
+static struct abx80x_cap abx80x_caps[] = {
+       [AB0801] = {.pn = 0x0801},
+       [AB0803] = {.pn = 0x0803},
+       [AB0804] = {.pn = 0x0804, .has_tc = true},
+       [AB0805] = {.pn = 0x0805, .has_tc = true},
+       [AB1801] = {.pn = 0x1801},
+       [AB1803] = {.pn = 0x1803},
+       [AB1804] = {.pn = 0x1804, .has_tc = true},
+       [AB1805] = {.pn = 0x1805, .has_tc = true},
+       [ABX80X] = {.pn = 0}
+};
+
+static struct i2c_driver abx80x_driver;
+
+static int abx80x_enable_trickle_charger(struct i2c_client *client,
+                                        u8 trickle_cfg)
+{
+       int err;
+
+       /*
+        * Write the configuration key register to enable access to the Trickle
+        * register
+        */
+       err = i2c_smbus_write_byte_data(client, ABX8XX_REG_CFG_KEY,
+                                       ABX8XX_CFG_KEY_MISC);
+       if (err < 0) {
+               dev_err(&client->dev, "Unable to write configuration key\n");
+               return -EIO;
+       }
+
+       err = i2c_smbus_write_byte_data(client, ABX8XX_REG_TRICKLE,
+                                       ABX8XX_TRICKLE_CHARGE_ENABLE |
+                                       trickle_cfg);
+       if (err < 0) {
+               dev_err(&client->dev, "Unable to write trickle register\n");
+               return -EIO;
+       }
+
+       return 0;
+}
+
+static int abx80x_rtc_read_time(struct device *dev, struct rtc_time *tm)
+{
+       struct i2c_client *client = to_i2c_client(dev);
+       unsigned char buf[8];
+       int err;
+
+       err = i2c_smbus_read_i2c_block_data(client, ABX8XX_REG_HTH,
+                                           sizeof(buf), buf);
+       if (err < 0) {
+               dev_err(&client->dev, "Unable to read date\n");
+               return -EIO;
+       }
+
+       tm->tm_sec = bcd2bin(buf[ABX8XX_REG_SC] & 0x7F);
+       tm->tm_min = bcd2bin(buf[ABX8XX_REG_MN] & 0x7F);
+       tm->tm_hour = bcd2bin(buf[ABX8XX_REG_HR] & 0x3F);
+       tm->tm_wday = buf[ABX8XX_REG_WD] & 0x7;
+       tm->tm_mday = bcd2bin(buf[ABX8XX_REG_DA] & 0x3F);
+       tm->tm_mon = bcd2bin(buf[ABX8XX_REG_MO] & 0x1F) - 1;
+       tm->tm_year = bcd2bin(buf[ABX8XX_REG_YR]) + 100;
+
+       err = rtc_valid_tm(tm);
+       if (err < 0)
+               dev_err(&client->dev, "retrieved date/time is not valid.\n");
+
+       return err;
+}
+
+static int abx80x_rtc_set_time(struct device *dev, struct rtc_time *tm)
+{
+       struct i2c_client *client = to_i2c_client(dev);
+       unsigned char buf[8];
+       int err;
+
+       if (tm->tm_year < 100)
+               return -EINVAL;
+
+       buf[ABX8XX_REG_HTH] = 0;
+       buf[ABX8XX_REG_SC] = bin2bcd(tm->tm_sec);
+       buf[ABX8XX_REG_MN] = bin2bcd(tm->tm_min);
+       buf[ABX8XX_REG_HR] = bin2bcd(tm->tm_hour);
+       buf[ABX8XX_REG_DA] = bin2bcd(tm->tm_mday);
+       buf[ABX8XX_REG_MO] = bin2bcd(tm->tm_mon + 1);
+       buf[ABX8XX_REG_YR] = bin2bcd(tm->tm_year - 100);
+       buf[ABX8XX_REG_WD] = tm->tm_wday;
+
+       err = i2c_smbus_write_i2c_block_data(client, ABX8XX_REG_HTH,
+                                            sizeof(buf), buf);
+       if (err < 0) {
+               dev_err(&client->dev, "Unable to write to date registers\n");
+               return -EIO;
+       }
+
+       return 0;
+}
+
+static const struct rtc_class_ops abx80x_rtc_ops = {
+       .read_time      = abx80x_rtc_read_time,
+       .set_time       = abx80x_rtc_set_time,
+};
+
+static int abx80x_dt_trickle_cfg(struct device_node *np)
+{
+       const char *diode;
+       int trickle_cfg = 0;
+       int i, ret;
+       u32 tmp;
+
+       ret = of_property_read_string(np, "abracon,tc-diode", &diode);
+       if (ret)
+               return ret;
+
+       if (!strcmp(diode, "standard"))
+               trickle_cfg |= ABX8XX_TRICKLE_STANDARD_DIODE;
+       else if (!strcmp(diode, "schottky"))
+               trickle_cfg |= ABX8XX_TRICKLE_SCHOTTKY_DIODE;
+       else
+               return -EINVAL;
+
+       ret = of_property_read_u32(np, "abracon,tc-resistor", &tmp);
+       if (ret)
+               return ret;
+
+       for (i = 0; i < sizeof(trickle_resistors); i++)
+               if (trickle_resistors[i] == tmp)
+                       break;
+
+       if (i == sizeof(trickle_resistors))
+               return -EINVAL;
+
+       return (trickle_cfg | i);
+}
+
+static int abx80x_probe(struct i2c_client *client,
+                       const struct i2c_device_id *id)
+{
+       struct device_node *np = client->dev.of_node;
+       struct rtc_device *rtc;
+       int i, data, err, trickle_cfg = -EINVAL;
+       char buf[7];
+       unsigned int part = id->driver_data;
+       unsigned int partnumber;
+       unsigned int majrev, minrev;
+       unsigned int lot;
+       unsigned int wafer;
+       unsigned int uid;
+
+       if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C))
+               return -ENODEV;
+
+       err = i2c_smbus_read_i2c_block_data(client, ABX8XX_REG_ID0,
+                                           sizeof(buf), buf);
+       if (err < 0) {
+               dev_err(&client->dev, "Unable to read partnumber\n");
+               return -EIO;
+       }
+
+       partnumber = (buf[0] << 8) | buf[1];
+       majrev = buf[2] >> 3;
+       minrev = buf[2] & 0x7;
+       lot = ((buf[4] & 0x80) << 2) | ((buf[6] & 0x80) << 1) | buf[3];
+       uid = ((buf[4] & 0x7f) << 8) | buf[5];
+       wafer = (buf[6] & 0x7c) >> 2;
+       dev_info(&client->dev, "model %04x, revision %u.%u, lot %x, wafer %x, uid %x\n",
+                partnumber, majrev, minrev, lot, wafer, uid);
+
+       data = i2c_smbus_read_byte_data(client, ABX8XX_REG_CTRL1);
+       if (data < 0) {
+               dev_err(&client->dev, "Unable to read control register\n");
+               return -EIO;
+       }
+
+       err = i2c_smbus_write_byte_data(client, ABX8XX_REG_CTRL1,
+                                       ((data & ~ABX8XX_CTRL_12_24) |
+                                        ABX8XX_CTRL_WRITE));
+       if (err < 0) {
+               dev_err(&client->dev, "Unable to write control register\n");
+               return -EIO;
+       }
+
+       /* part autodetection */
+       if (part == ABX80X) {
+               for (i = 0; abx80x_caps[i].pn; i++)
+                       if (partnumber == abx80x_caps[i].pn)
+                               break;
+               if (abx80x_caps[i].pn == 0) {
+                       dev_err(&client->dev, "Unknown part: %04x\n",
+                               partnumber);
+                       return -EINVAL;
+               }
+               part = i;
+       }
+
+       if (partnumber != abx80x_caps[part].pn) {
+               dev_err(&client->dev, "partnumber mismatch %04x != %04x\n",
+                       partnumber, abx80x_caps[part].pn);
+               return -EINVAL;
+       }
+
+       if (np && abx80x_caps[part].has_tc)
+               trickle_cfg = abx80x_dt_trickle_cfg(np);
+
+       if (trickle_cfg > 0) {
+               dev_info(&client->dev, "Enabling trickle charger: %02x\n",
+                        trickle_cfg);
+               abx80x_enable_trickle_charger(client, trickle_cfg);
+       }
+
+       rtc = devm_rtc_device_register(&client->dev, abx80x_driver.driver.name,
+                                      &abx80x_rtc_ops, THIS_MODULE);
+
+       if (IS_ERR(rtc))
+               return PTR_ERR(rtc);
+
+       i2c_set_clientdata(client, rtc);
+
+       return 0;
+}
+
+static int abx80x_remove(struct i2c_client *client)
+{
+       return 0;
+}
+
+static const struct i2c_device_id abx80x_id[] = {
+       { "abx80x", ABX80X },
+       { "ab0801", AB0801 },
+       { "ab0803", AB0803 },
+       { "ab0804", AB0804 },
+       { "ab0805", AB0805 },
+       { "ab1801", AB1801 },
+       { "ab1803", AB1803 },
+       { "ab1804", AB1804 },
+       { "ab1805", AB1805 },
+       { }
+};
+MODULE_DEVICE_TABLE(i2c, abx80x_id);
+
+static struct i2c_driver abx80x_driver = {
+       .driver         = {
+               .name   = "rtc-abx80x",
+       },
+       .probe          = abx80x_probe,
+       .remove         = abx80x_remove,
+       .id_table       = abx80x_id,
+};
+
+module_i2c_driver(abx80x_driver);
+
+MODULE_AUTHOR("Philippe De Muyter <phdm@macqel.be>");
+MODULE_AUTHOR("Alexandre Belloni <alexandre.belloni@free-electrons.com>");
+MODULE_DESCRIPTION("Abracon ABX80X RTC driver");
+MODULE_LICENSE("GPL v2");
index 43e04af39e0964e3dccd24e251f484d04a680bc9..4b62d1a875e43eb09bf4631f7695f31dda9bfa6d 100644 (file)
@@ -40,6 +40,13 @@ struct armada38x_rtc {
        void __iomem        *regs;
        void __iomem        *regs_soc;
        spinlock_t          lock;
+       /*
+        * While setting the time, the RTC TIME register should not be
+        * accessed. Setting the RTC time involves sleeping during
+        * 100ms, so a mutex instead of a spinlock is used to protect
+        * it
+        */
+       struct mutex        mutex_time;
        int                 irq;
 };
 
@@ -57,10 +64,9 @@ static void rtc_delayed_write(u32 val, struct armada38x_rtc *rtc, int offset)
 static int armada38x_rtc_read_time(struct device *dev, struct rtc_time *tm)
 {
        struct armada38x_rtc *rtc = dev_get_drvdata(dev);
-       unsigned long time, time_check, flags;
-
-       spin_lock_irqsave(&rtc->lock, flags);
+       unsigned long time, time_check;
 
+       mutex_lock(&rtc->mutex_time);
        time = readl(rtc->regs + RTC_TIME);
        /*
         * WA for failing time set attempts. As stated in HW ERRATA if
@@ -71,7 +77,7 @@ static int armada38x_rtc_read_time(struct device *dev, struct rtc_time *tm)
        if ((time_check - time) > 1)
                time_check = readl(rtc->regs + RTC_TIME);
 
-       spin_unlock_irqrestore(&rtc->lock, flags);
+       mutex_unlock(&rtc->mutex_time);
 
        rtc_time_to_tm(time_check, tm);
 
@@ -94,19 +100,12 @@ static int armada38x_rtc_set_time(struct device *dev, struct rtc_time *tm)
         * then wait for 100ms before writing to the time register to be
         * sure that the data will be taken into account.
         */
-       spin_lock_irqsave(&rtc->lock, flags);
-
+       mutex_lock(&rtc->mutex_time);
        rtc_delayed_write(0, rtc, RTC_STATUS);
-
-       spin_unlock_irqrestore(&rtc->lock, flags);
-
        msleep(100);
-
-       spin_lock_irqsave(&rtc->lock, flags);
-
        rtc_delayed_write(time, rtc, RTC_TIME);
+       mutex_unlock(&rtc->mutex_time);
 
-       spin_unlock_irqrestore(&rtc->lock, flags);
 out:
        return ret;
 }
@@ -230,6 +229,7 @@ static __init int armada38x_rtc_probe(struct platform_device *pdev)
                return -ENOMEM;
 
        spin_lock_init(&rtc->lock);
+       mutex_init(&rtc->mutex_time);
 
        res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "rtc");
        rtc->regs = devm_ioremap_resource(&pdev->dev, res);
index c43aca69fb30dffed727c210b725b46a365440dd..0fc3fe5fd5b810c77fd24bc99e269414151e3405 100644 (file)
@@ -667,6 +667,8 @@ static struct raw3215_info *raw3215_alloc_info(void)
        info->buffer = kzalloc(RAW3215_BUFFER_SIZE, GFP_KERNEL | GFP_DMA);
        info->inbuf = kzalloc(RAW3215_INBUF_SIZE, GFP_KERNEL | GFP_DMA);
        if (!info->buffer || !info->inbuf) {
+               kfree(info->inbuf);
+               kfree(info->buffer);
                kfree(info);
                return NULL;
        }
index f0b9871a4bbd3ff209d77e56f28818fdbcce25e6..3ba61141975914aa25ef42658471686756fdefb5 100644 (file)
@@ -1158,11 +1158,12 @@ static ssize_t poll_timeout_store(struct bus_type *bus, const char *buf,
        poll_timeout = time;
        hr_time = ktime_set(0, poll_timeout);
 
-       if (!hrtimer_is_queued(&ap_poll_timer) ||
-           !hrtimer_forward(&ap_poll_timer, hrtimer_get_expires(&ap_poll_timer), hr_time)) {
-               hrtimer_set_expires(&ap_poll_timer, hr_time);
-               hrtimer_start_expires(&ap_poll_timer, HRTIMER_MODE_ABS);
-       }
+       spin_lock_bh(&ap_poll_timer_lock);
+       hrtimer_cancel(&ap_poll_timer);
+       hrtimer_set_expires(&ap_poll_timer, hr_time);
+       hrtimer_start_expires(&ap_poll_timer, HRTIMER_MODE_ABS);
+       spin_unlock_bh(&ap_poll_timer_lock);
+
        return count;
 }
 
@@ -1528,14 +1529,11 @@ static inline void __ap_schedule_poll_timer(void)
        ktime_t hr_time;
 
        spin_lock_bh(&ap_poll_timer_lock);
-       if (hrtimer_is_queued(&ap_poll_timer) || ap_suspend_flag)
-               goto out;
-       if (ktime_to_ns(hrtimer_expires_remaining(&ap_poll_timer)) <= 0) {
+       if (!hrtimer_is_queued(&ap_poll_timer) && !ap_suspend_flag) {
                hr_time = ktime_set(0, poll_timeout);
                hrtimer_forward_now(&ap_poll_timer, hr_time);
                hrtimer_restart(&ap_poll_timer);
        }
-out:
        spin_unlock_bh(&ap_poll_timer_lock);
 }
 
@@ -1952,7 +1950,7 @@ static void ap_reset_domain(void)
 {
        int i;
 
-       if (ap_domain_index != -1)
+       if ((ap_domain_index != -1) && (ap_test_config_domain(ap_domain_index)))
                for (i = 0; i < AP_DEVICES; i++)
                        ap_reset_queue(AP_MKQID(i, ap_domain_index));
 }
@@ -2097,7 +2095,6 @@ void ap_module_exit(void)
        hrtimer_cancel(&ap_poll_timer);
        destroy_workqueue(ap_work_queue);
        tasklet_kill(&ap_tasklet);
-       root_device_unregister(ap_root_device);
        while ((dev = bus_find_device(&ap_bus_type, NULL, NULL,
                    __ap_match_all)))
        {
@@ -2106,6 +2103,7 @@ void ap_module_exit(void)
        }
        for (i = 0; ap_bus_attrs[i]; i++)
                bus_remove_file(&ap_bus_type, ap_bus_attrs[i]);
+       root_device_unregister(ap_root_device);
        bus_unregister(&ap_bus_type);
        unregister_reset_call(&ap_reset_call);
        if (ap_using_interrupts())
index 7600639db4c46fb642e0b86a9e638ab94392538d..add419d6ff34996ed4aab8a145aee637ee987dbf 100644 (file)
@@ -149,7 +149,6 @@ static int twa_reset_sequence(TW_Device_Extension *tw_dev, int soft_reset);
 static int twa_scsiop_execute_scsi(TW_Device_Extension *tw_dev, int request_id, char *cdb, int use_sg, TW_SG_Entry *sglistarg);
 static void twa_scsiop_execute_scsi_complete(TW_Device_Extension *tw_dev, int request_id);
 static char *twa_string_lookup(twa_message_type *table, unsigned int aen_code);
-static void twa_unmap_scsi_data(TW_Device_Extension *tw_dev, int request_id);
 
 /* Functions */
 
@@ -1340,11 +1339,11 @@ static irqreturn_t twa_interrupt(int irq, void *dev_instance)
                                }
 
                                /* Now complete the io */
+                               scsi_dma_unmap(cmd);
+                               cmd->scsi_done(cmd);
                                tw_dev->state[request_id] = TW_S_COMPLETED;
                                twa_free_request_id(tw_dev, request_id);
                                tw_dev->posted_request_count--;
-                               tw_dev->srb[request_id]->scsi_done(tw_dev->srb[request_id]);
-                               twa_unmap_scsi_data(tw_dev, request_id);
                        }
 
                        /* Check for valid status after each drain */
@@ -1402,26 +1401,6 @@ static void twa_load_sgl(TW_Device_Extension *tw_dev, TW_Command_Full *full_comm
        }
 } /* End twa_load_sgl() */
 
-/* This function will perform a pci-dma mapping for a scatter gather list */
-static int twa_map_scsi_sg_data(TW_Device_Extension *tw_dev, int request_id)
-{
-       int use_sg;
-       struct scsi_cmnd *cmd = tw_dev->srb[request_id];
-
-       use_sg = scsi_dma_map(cmd);
-       if (!use_sg)
-               return 0;
-       else if (use_sg < 0) {
-               TW_PRINTK(tw_dev->host, TW_DRIVER, 0x1c, "Failed to map scatter gather list");
-               return 0;
-       }
-
-       cmd->SCp.phase = TW_PHASE_SGLIST;
-       cmd->SCp.have_data_in = use_sg;
-
-       return use_sg;
-} /* End twa_map_scsi_sg_data() */
-
 /* This function will poll for a response interrupt of a request */
 static int twa_poll_response(TW_Device_Extension *tw_dev, int request_id, int seconds)
 {
@@ -1600,9 +1579,11 @@ static int twa_reset_device_extension(TW_Device_Extension *tw_dev)
                    (tw_dev->state[i] != TW_S_INITIAL) &&
                    (tw_dev->state[i] != TW_S_COMPLETED)) {
                        if (tw_dev->srb[i]) {
-                               tw_dev->srb[i]->result = (DID_RESET << 16);
-                               tw_dev->srb[i]->scsi_done(tw_dev->srb[i]);
-                               twa_unmap_scsi_data(tw_dev, i);
+                               struct scsi_cmnd *cmd = tw_dev->srb[i];
+
+                               cmd->result = (DID_RESET << 16);
+                               scsi_dma_unmap(cmd);
+                               cmd->scsi_done(cmd);
                        }
                }
        }
@@ -1781,21 +1762,18 @@ static int twa_scsi_queue_lck(struct scsi_cmnd *SCpnt, void (*done)(struct scsi_
        /* Save the scsi command for use by the ISR */
        tw_dev->srb[request_id] = SCpnt;
 
-       /* Initialize phase to zero */
-       SCpnt->SCp.phase = TW_PHASE_INITIAL;
-
        retval = twa_scsiop_execute_scsi(tw_dev, request_id, NULL, 0, NULL);
        switch (retval) {
        case SCSI_MLQUEUE_HOST_BUSY:
+               scsi_dma_unmap(SCpnt);
                twa_free_request_id(tw_dev, request_id);
-               twa_unmap_scsi_data(tw_dev, request_id);
                break;
        case 1:
-               tw_dev->state[request_id] = TW_S_COMPLETED;
-               twa_free_request_id(tw_dev, request_id);
-               twa_unmap_scsi_data(tw_dev, request_id);
                SCpnt->result = (DID_ERROR << 16);
+               scsi_dma_unmap(SCpnt);
                done(SCpnt);
+               tw_dev->state[request_id] = TW_S_COMPLETED;
+               twa_free_request_id(tw_dev, request_id);
                retval = 0;
        }
 out:
@@ -1863,8 +1841,8 @@ static int twa_scsiop_execute_scsi(TW_Device_Extension *tw_dev, int request_id,
                                command_packet->sg_list[0].address = TW_CPU_TO_SGL(tw_dev->generic_buffer_phys[request_id]);
                                command_packet->sg_list[0].length = cpu_to_le32(TW_MIN_SGL_LENGTH);
                        } else {
-                               sg_count = twa_map_scsi_sg_data(tw_dev, request_id);
-                               if (sg_count == 0)
+                               sg_count = scsi_dma_map(srb);
+                               if (sg_count < 0)
                                        goto out;
 
                                scsi_for_each_sg(srb, sg, sg_count, i) {
@@ -1979,15 +1957,6 @@ static char *twa_string_lookup(twa_message_type *table, unsigned int code)
        return(table[index].text);
 } /* End twa_string_lookup() */
 
-/* This function will perform a pci-dma unmap */
-static void twa_unmap_scsi_data(TW_Device_Extension *tw_dev, int request_id)
-{
-       struct scsi_cmnd *cmd = tw_dev->srb[request_id];
-
-       if (cmd->SCp.phase == TW_PHASE_SGLIST)
-               scsi_dma_unmap(cmd);
-} /* End twa_unmap_scsi_data() */
-
 /* This function gets called when a disk is coming on-line */
 static int twa_slave_configure(struct scsi_device *sdev)
 {
index 040f7214e5b7a5c3782743a4a66a456aea79df81..0fdc83cfa0e1a28a42757ae52f434523238075b3 100644 (file)
@@ -324,11 +324,6 @@ static twa_message_type twa_error_table[] = {
 #define TW_CURRENT_DRIVER_BUILD 0
 #define TW_CURRENT_DRIVER_BRANCH 0
 
-/* Phase defines */
-#define TW_PHASE_INITIAL 0
-#define TW_PHASE_SINGLE  1
-#define TW_PHASE_SGLIST  2
-
 /* Misc defines */
 #define TW_9550SX_DRAIN_COMPLETED            0xFFFF
 #define TW_SECTOR_SIZE                        512
index 2361772d590966abf6f618d2e1228b0f3d424ebc..f8374850f714dd09c53aa1eb25a38bbcb7d0ee8d 100644 (file)
@@ -290,26 +290,6 @@ static int twl_post_command_packet(TW_Device_Extension *tw_dev, int request_id)
        return 0;
 } /* End twl_post_command_packet() */
 
-/* This function will perform a pci-dma mapping for a scatter gather list */
-static int twl_map_scsi_sg_data(TW_Device_Extension *tw_dev, int request_id)
-{
-       int use_sg;
-       struct scsi_cmnd *cmd = tw_dev->srb[request_id];
-
-       use_sg = scsi_dma_map(cmd);
-       if (!use_sg)
-               return 0;
-       else if (use_sg < 0) {
-               TW_PRINTK(tw_dev->host, TW_DRIVER, 0x1, "Failed to map scatter gather list");
-               return 0;
-       }
-
-       cmd->SCp.phase = TW_PHASE_SGLIST;
-       cmd->SCp.have_data_in = use_sg;
-
-       return use_sg;
-} /* End twl_map_scsi_sg_data() */
-
 /* This function hands scsi cdb's to the firmware */
 static int twl_scsiop_execute_scsi(TW_Device_Extension *tw_dev, int request_id, char *cdb, int use_sg, TW_SG_Entry_ISO *sglistarg)
 {
@@ -357,8 +337,8 @@ static int twl_scsiop_execute_scsi(TW_Device_Extension *tw_dev, int request_id,
        if (!sglistarg) {
                /* Map sglist from scsi layer to cmd packet */
                if (scsi_sg_count(srb)) {
-                       sg_count = twl_map_scsi_sg_data(tw_dev, request_id);
-                       if (sg_count == 0)
+                       sg_count = scsi_dma_map(srb);
+                       if (sg_count <= 0)
                                goto out;
 
                        scsi_for_each_sg(srb, sg, sg_count, i) {
@@ -1102,15 +1082,6 @@ out:
        return retval;
 } /* End twl_initialize_device_extension() */
 
-/* This function will perform a pci-dma unmap */
-static void twl_unmap_scsi_data(TW_Device_Extension *tw_dev, int request_id)
-{
-       struct scsi_cmnd *cmd = tw_dev->srb[request_id];
-
-       if (cmd->SCp.phase == TW_PHASE_SGLIST)
-               scsi_dma_unmap(cmd);
-} /* End twl_unmap_scsi_data() */
-
 /* This function will handle attention interrupts */
 static int twl_handle_attention_interrupt(TW_Device_Extension *tw_dev)
 {
@@ -1251,11 +1222,11 @@ static irqreturn_t twl_interrupt(int irq, void *dev_instance)
                        }
 
                        /* Now complete the io */
+                       scsi_dma_unmap(cmd);
+                       cmd->scsi_done(cmd);
                        tw_dev->state[request_id] = TW_S_COMPLETED;
                        twl_free_request_id(tw_dev, request_id);
                        tw_dev->posted_request_count--;
-                       tw_dev->srb[request_id]->scsi_done(tw_dev->srb[request_id]);
-                       twl_unmap_scsi_data(tw_dev, request_id);
                }
 
                /* Check for another response interrupt */
@@ -1400,10 +1371,12 @@ static int twl_reset_device_extension(TW_Device_Extension *tw_dev, int ioctl_res
                if ((tw_dev->state[i] != TW_S_FINISHED) &&
                    (tw_dev->state[i] != TW_S_INITIAL) &&
                    (tw_dev->state[i] != TW_S_COMPLETED)) {
-                       if (tw_dev->srb[i]) {
-                               tw_dev->srb[i]->result = (DID_RESET << 16);
-                               tw_dev->srb[i]->scsi_done(tw_dev->srb[i]);
-                               twl_unmap_scsi_data(tw_dev, i);
+                       struct scsi_cmnd *cmd = tw_dev->srb[i];
+
+                       if (cmd) {
+                               cmd->result = (DID_RESET << 16);
+                               scsi_dma_unmap(cmd);
+                               cmd->scsi_done(cmd);
                        }
                }
        }
@@ -1507,9 +1480,6 @@ static int twl_scsi_queue_lck(struct scsi_cmnd *SCpnt, void (*done)(struct scsi_
        /* Save the scsi command for use by the ISR */
        tw_dev->srb[request_id] = SCpnt;
 
-       /* Initialize phase to zero */
-       SCpnt->SCp.phase = TW_PHASE_INITIAL;
-
        retval = twl_scsiop_execute_scsi(tw_dev, request_id, NULL, 0, NULL);
        if (retval) {
                tw_dev->state[request_id] = TW_S_COMPLETED;
index d474892701d4540658a36b48edb7b903a8b9ba76..fec6449c7595132f706439277cd396b4dc66c0a8 100644 (file)
@@ -103,10 +103,6 @@ static char *twl_aen_severity_table[] =
 #define TW_CURRENT_DRIVER_BUILD 0
 #define TW_CURRENT_DRIVER_BRANCH 0
 
-/* Phase defines */
-#define TW_PHASE_INITIAL 0
-#define TW_PHASE_SGLIST  2
-
 /* Misc defines */
 #define TW_SECTOR_SIZE                        512
 #define TW_MAX_UNITS                         32
index c75f2048319f7ced2ba9f9956a2a56f41b181a24..2940bd769936cd7f75d2d20adc324914b0df4b84 100644 (file)
@@ -1271,32 +1271,6 @@ static int tw_initialize_device_extension(TW_Device_Extension *tw_dev)
        return 0;
 } /* End tw_initialize_device_extension() */
 
-static int tw_map_scsi_sg_data(struct pci_dev *pdev, struct scsi_cmnd *cmd)
-{
-       int use_sg;
-
-       dprintk(KERN_WARNING "3w-xxxx: tw_map_scsi_sg_data()\n");
-
-       use_sg = scsi_dma_map(cmd);
-       if (use_sg < 0) {
-               printk(KERN_WARNING "3w-xxxx: tw_map_scsi_sg_data(): pci_map_sg() failed.\n");
-               return 0;
-       }
-
-       cmd->SCp.phase = TW_PHASE_SGLIST;
-       cmd->SCp.have_data_in = use_sg;
-
-       return use_sg;
-} /* End tw_map_scsi_sg_data() */
-
-static void tw_unmap_scsi_data(struct pci_dev *pdev, struct scsi_cmnd *cmd)
-{
-       dprintk(KERN_WARNING "3w-xxxx: tw_unmap_scsi_data()\n");
-
-       if (cmd->SCp.phase == TW_PHASE_SGLIST)
-               scsi_dma_unmap(cmd);
-} /* End tw_unmap_scsi_data() */
-
 /* This function will reset a device extension */
 static int tw_reset_device_extension(TW_Device_Extension *tw_dev)
 {
@@ -1319,8 +1293,8 @@ static int tw_reset_device_extension(TW_Device_Extension *tw_dev)
                        srb = tw_dev->srb[i];
                        if (srb != NULL) {
                                srb->result = (DID_RESET << 16);
-                               tw_dev->srb[i]->scsi_done(tw_dev->srb[i]);
-                               tw_unmap_scsi_data(tw_dev->tw_pci_dev, tw_dev->srb[i]);
+                               scsi_dma_unmap(srb);
+                               srb->scsi_done(srb);
                        }
                }
        }
@@ -1767,8 +1741,8 @@ static int tw_scsiop_read_write(TW_Device_Extension *tw_dev, int request_id)
        command_packet->byte8.io.lba = lba;
        command_packet->byte6.block_count = num_sectors;
 
-       use_sg = tw_map_scsi_sg_data(tw_dev->tw_pci_dev, tw_dev->srb[request_id]);
-       if (!use_sg)
+       use_sg = scsi_dma_map(srb);
+       if (use_sg <= 0)
                return 1;
 
        scsi_for_each_sg(tw_dev->srb[request_id], sg, use_sg, i) {
@@ -1955,9 +1929,6 @@ static int tw_scsi_queue_lck(struct scsi_cmnd *SCpnt, void (*done)(struct scsi_c
        /* Save the scsi command for use by the ISR */
        tw_dev->srb[request_id] = SCpnt;
 
-       /* Initialize phase to zero */
-       SCpnt->SCp.phase = TW_PHASE_INITIAL;
-
        switch (*command) {
                case READ_10:
                case READ_6:
@@ -2185,12 +2156,11 @@ static irqreturn_t tw_interrupt(int irq, void *dev_instance)
 
                                /* Now complete the io */
                                if ((error != TW_ISR_DONT_COMPLETE)) {
+                                       scsi_dma_unmap(tw_dev->srb[request_id]);
+                                       tw_dev->srb[request_id]->scsi_done(tw_dev->srb[request_id]);
                                        tw_dev->state[request_id] = TW_S_COMPLETED;
                                        tw_state_request_finish(tw_dev, request_id);
                                        tw_dev->posted_request_count--;
-                                       tw_dev->srb[request_id]->scsi_done(tw_dev->srb[request_id]);
-                                       
-                                       tw_unmap_scsi_data(tw_dev->tw_pci_dev, tw_dev->srb[request_id]);
                                }
                        }
                                
index 29b0b84ed69e888b1939c57dde7e60589506e992..6f65e663d3932108edaed6b75eba328d469f4fce 100644 (file)
@@ -195,11 +195,6 @@ static unsigned char tw_sense_table[][4] =
 #define TW_AEN_SMART_FAIL        0x000F
 #define TW_AEN_SBUF_FAIL         0x0024
 
-/* Phase defines */
-#define TW_PHASE_INITIAL 0
-#define TW_PHASE_SINGLE 1
-#define TW_PHASE_SGLIST 2
-
 /* Misc defines */
 #define TW_ALIGNMENT_6000                    64 /* 64 bytes */
 #define TW_ALIGNMENT_7000                     4  /* 4 bytes */
index ec432763a29a3c3472a53952e017b1d831cd214e..b95d2779f4679cba20908b86a92502b32ec33a06 100644 (file)
@@ -375,9 +375,10 @@ static int aha1542_queuecommand(struct Scsi_Host *sh, struct scsi_cmnd *cmd)
        u8 lun = cmd->device->lun;
        unsigned long flags;
        int bufflen = scsi_bufflen(cmd);
-       int mbo;
+       int mbo, sg_count;
        struct mailbox *mb = aha1542->mb;
        struct ccb *ccb = aha1542->ccb;
+       struct chain *cptr;
 
        if (*cmd->cmnd == REQUEST_SENSE) {
                /* Don't do the command - we have the sense data already */
@@ -397,6 +398,13 @@ static int aha1542_queuecommand(struct Scsi_Host *sh, struct scsi_cmnd *cmd)
                print_hex_dump_bytes("command: ", DUMP_PREFIX_NONE, cmd->cmnd, cmd->cmd_len);
        }
 #endif
+       if (bufflen) {  /* allocate memory before taking host_lock */
+               sg_count = scsi_sg_count(cmd);
+               cptr = kmalloc(sizeof(*cptr) * sg_count, GFP_KERNEL | GFP_DMA);
+               if (!cptr)
+                       return SCSI_MLQUEUE_HOST_BUSY;
+       }
+
        /* Use the outgoing mailboxes in a round-robin fashion, because this
           is how the host adapter will scan for them */
 
@@ -441,19 +449,10 @@ static int aha1542_queuecommand(struct Scsi_Host *sh, struct scsi_cmnd *cmd)
 
        if (bufflen) {
                struct scatterlist *sg;
-               struct chain *cptr;
-               int i, sg_count = scsi_sg_count(cmd);
+               int i;
 
                ccb[mbo].op = 2;        /* SCSI Initiator Command  w/scatter-gather */
-               cmd->host_scribble = kmalloc(sizeof(*cptr)*sg_count,
-                                                        GFP_KERNEL | GFP_DMA);
-               cptr = (struct chain *) cmd->host_scribble;
-               if (cptr == NULL) {
-                       /* free the claimed mailbox slot */
-                       aha1542->int_cmds[mbo] = NULL;
-                       spin_unlock_irqrestore(sh->host_lock, flags);
-                       return SCSI_MLQUEUE_HOST_BUSY;
-               }
+               cmd->host_scribble = (void *)cptr;
                scsi_for_each_sg(cmd, sg, sg_count, i) {
                        any2scsi(cptr[i].dataptr, isa_page_to_bus(sg_page(sg))
                                                                + sg->offset);
index 81e83a65a1936cb897a2a0bbfc4bcfabb957b276..32070099c33356d6dca288330337df8eba5e5fa6 100644 (file)
@@ -1,5 +1,5 @@
 /**
- * Copyright (C) 2005 - 2014 Emulex
+ * Copyright (C) 2005 - 2015 Avago Technologies
  * All rights reserved.
  *
  * This program is free software; you can redistribute it and/or
@@ -8,9 +8,9 @@
  * Public License is included in this distribution in the file called COPYING.
  *
  * Contact Information:
- * linux-drivers@emulex.com
+ * linux-drivers@avagotech.com
  *
- * Emulex
+ * Avago Technologies
  * 3333 Susan Street
  * Costa Mesa, CA 92626
  */
index 1028760b8a22145e792de569862641d627d5b89f..447cf7ce606ec6e3cf8b0540ba4f455c41aec2d5 100644 (file)
@@ -1,5 +1,5 @@
 /**
- * Copyright (C) 2005 - 2014 Emulex
+ * Copyright (C) 2005 - 2015 Avago Technologies
  * All rights reserved.
  *
  * This program is free software; you can redistribute it and/or
@@ -8,9 +8,9 @@
  * Public License is included in this distribution in the file called COPYING.
  *
  * Contact Information:
- * linux-drivers@emulex.com
+ * linux-drivers@avagotech.com
  *
- * Emulex
+ * Avago Technologies
  * 3333 Susan Street
  * Costa Mesa, CA 92626
  */
index 98897434bcb4580c23e6939f35b6e8344002f7a3..f11d325fe6963f191424b52d6f0c16d69ddef671 100644 (file)
@@ -1,5 +1,5 @@
 /**
- * Copyright (C) 2005 - 2014 Emulex
+ * Copyright (C) 2005 - 2015 Avago Technologies
  * All rights reserved.
  *
  * This program is free software; you can redistribute it and/or
@@ -8,9 +8,9 @@
  * Public License is included in this distribution in the file called COPYING.
  *
  * Contact Information:
- * linux-drivers@emulex.com
+ * linux-drivers@avagotech.com
  *
- * Emulex
+ * Avago Technologies
  * 3333 Susan Street
  * Costa Mesa, CA 92626
  */
index b7391a3f9f0ba1d3e1f9ba96649d7ca8a9e2af16..2f0700796842004812a12c6307487747f2868e63 100644 (file)
@@ -1,5 +1,5 @@
 /**
- * Copyright (C) 2005 - 2014 Emulex
+ * Copyright (C) 2005 - 2015 Avago Technologies
  * All rights reserved.
  *
  * This program is free software; you can redistribute it and/or
@@ -7,12 +7,12 @@
  * as published by the Free Software Foundation.  The full GNU General
  * Public License is included in this distribution in the file called COPYING.
  *
- * Written by: Jayamohan Kallickal (jayamohan.kallickal@emulex.com)
+ * Written by: Jayamohan Kallickal (jayamohan.kallickal@avagotech.com)
  *
  * Contact Information:
- * linux-drivers@emulex.com
+ * linux-drivers@avagotech.com
  *
- * Emulex
+ * Avago Technologies
  * 3333 Susan Street
  * Costa Mesa, CA 92626
  */
index e0b3b2d1f27a64e9b5ee1eba4b558046847c0375..0c84e1c0763acc98e04003be5b966fd2f277f450 100644 (file)
@@ -1,5 +1,5 @@
 /**
- * Copyright (C) 2005 - 2014 Emulex
+ * Copyright (C) 2005 - 2015 Avago Technologies
  * All rights reserved.
  *
  * This program is free software; you can redistribute it and/or
@@ -7,12 +7,12 @@
  * as published by the Free Software Foundation.  The full GNU General
  * Public License is included in this distribution in the file called COPYING.
  *
- * Written by: Jayamohan Kallickal (jayamohan.kallickal@emulex.com)
+ * Written by: Jayamohan Kallickal (jayamohan.kallickal@avagotech.com)
  *
  * Contact Information:
- * linux-drivers@emulex.com
+ * linux-drivers@avagotech.com
  *
- * Emulex
+ * Avago Technologies
  * 3333 Susan Street
  * Costa Mesa, CA 92626
  */
index 923a2b5a24395547212207312588b125f19de3a2..1f74760ce86cb27db2308f4dbe1d9ba25f10bcaa 100644 (file)
@@ -1,5 +1,5 @@
 /**
- * Copyright (C) 2005 - 2014 Emulex
+ * Copyright (C) 2005 - 2015 Avago Technologies
  * All rights reserved.
  *
  * This program is free software; you can redistribute it and/or
@@ -7,12 +7,12 @@
  * as published by the Free Software Foundation.  The full GNU General
  * Public License is included in this distribution in the file called COPYING.
  *
- * Written by: Jayamohan Kallickal (jayamohan.kallickal@emulex.com)
+ * Written by: Jayamohan Kallickal (jayamohan.kallickal@avagotech.com)
  *
  * Contact Information:
- * linux-drivers@emulex.com
+ * linux-drivers@avagotech.com
  *
- * Emulex
+ * Avago Technologies
  * 3333 Susan Street
  * Costa Mesa, CA 92626
  */
@@ -50,7 +50,7 @@ static unsigned int enable_msix = 1;
 
 MODULE_DESCRIPTION(DRV_DESC " " BUILD_STR);
 MODULE_VERSION(BUILD_STR);
-MODULE_AUTHOR("Emulex Corporation");
+MODULE_AUTHOR("Avago Technologies");
 MODULE_LICENSE("GPL");
 module_param(be_iopoll_budget, int, 0);
 module_param(enable_msix, int, 0);
@@ -552,7 +552,7 @@ MODULE_DEVICE_TABLE(pci, beiscsi_pci_id_table);
 
 static struct scsi_host_template beiscsi_sht = {
        .module = THIS_MODULE,
-       .name = "Emulex 10Gbe open-iscsi Initiator Driver",
+       .name = "Avago Technologies 10Gbe open-iscsi Initiator Driver",
        .proc_name = DRV_NAME,
        .queuecommand = iscsi_queuecommand,
        .change_queue_depth = scsi_change_queue_depth,
index 7ee0ffc3851468ad19b5defe60b36b71266a6980..e70ea26bbc2b0fff8a82c540edd4aceab371da45 100644 (file)
@@ -1,5 +1,5 @@
 /**
- * Copyright (C) 2005 - 2014 Emulex
+ * Copyright (C) 2005 - 2015 Avago Technologies
  * All rights reserved.
  *
  * This program is free software; you can redistribute it and/or
@@ -7,12 +7,12 @@
  * as published by the Free Software Foundation.  The full GNU General
  * Public License is included in this distribution in the file called COPYING.
  *
- * Written by: Jayamohan Kallickal (jayamohan.kallickal@emulex.com)
+ * Written by: Jayamohan Kallickal (jayamohan.kallickal@avagotech.com)
  *
  * Contact Information:
- * linux-drivers@emulex.com
+ * linux-drivers@avagotech.com
  *
- * Emulex
+ * Avago Technologies
  * 3333 Susan Street
  * Costa Mesa, CA 92626
  */
@@ -37,7 +37,7 @@
 
 #define DRV_NAME               "be2iscsi"
 #define BUILD_STR              "10.4.114.0"
-#define BE_NAME                        "Emulex OneConnect" \
+#define BE_NAME                        "Avago Technologies OneConnect" \
                                "Open-iSCSI Driver version" BUILD_STR
 #define DRV_DESC               BE_NAME " " "Driver"
 
index 681d4e8f003ab6d6873cf9d4bc35c2c87d81aa35..c2c4d6975fb7b22b2a4db35adf6ca69d2ea06547 100644 (file)
@@ -1,5 +1,5 @@
 /**
- * Copyright (C) 2005 - 2014 Emulex
+ * Copyright (C) 2005 - 2015 Avago Technologies
  * All rights reserved.
  *
  * This program is free software; you can redistribute it and/or
@@ -7,12 +7,12 @@
  * as published by the Free Software Foundation.  The full GNU General
  * Public License is included in this distribution in the file called COPYING.
  *
- * Written by: Jayamohan Kallickal (jayamohan.kallickal@emulex.com)
+ * Written by: Jayamohan Kallickal (jayamohan.kallickal@avagotech.com)
  *
  * Contact Information:
- * linux-drivers@emulex.com
+ * linux-drivers@avagotech.com
  *
- * Emulex
+ * Avago Technologies
  * 3333 Susan Street
  * Costa Mesa, CA 92626
  */
index bd81446936fc34c5ecbc77cdd013416a0f1224f2..9356b9a86b66fcc7d640361aab6670d64315244f 100644 (file)
@@ -1,5 +1,5 @@
 /**
- * Copyright (C) 2005 - 2014 Emulex
+ * Copyright (C) 2005 - 2015 Avago Technologies
  * All rights reserved.
  *
  * This program is free software; you can redistribute it and/or
@@ -7,12 +7,12 @@
  * as published by the Free Software Foundation.  The full GNU General
  * Public License is included in this distribution in the file called COPYING.
  *
- * Written by: Jayamohan Kallickal (jayamohan.kallickal@emulex.com)
+ * Written by: Jayamohan Kallickal (jayamohan.kallickal@avagotech.com)
  *
  * Contact Information:
- * linux-drivers@emulex.com
+ * linux-drivers@avagotech.com
  *
- * Emulex
+ * Avago Technologies
  * 3333 Susan Street
  * Costa Mesa, CA 92626
  */
index cb73cf9e9ba5c9a7d16c2b069ef649663cf067f8..c140f99772caa5963b15a67456b32d9194373927 100644 (file)
@@ -1129,25 +1129,6 @@ lpfc_release_scsi_buf(struct lpfc_hba *phba, struct lpfc_scsi_buf *psb)
        phba->lpfc_release_scsi_buf(phba, psb);
 }
 
-/**
- * lpfc_fcpcmd_to_iocb - copy the fcp_cmd data into the IOCB
- * @data: A pointer to the immediate command data portion of the IOCB.
- * @fcp_cmnd: The FCP Command that is provided by the SCSI layer.
- *
- * The routine copies the entire FCP command from @fcp_cmnd to @data while
- * byte swapping the data to big endian format for transmission on the wire.
- **/
-static void
-lpfc_fcpcmd_to_iocb(uint8_t *data, struct fcp_cmnd *fcp_cmnd)
-{
-       int i, j;
-
-       for (i = 0, j = 0; i < sizeof(struct fcp_cmnd);
-            i += sizeof(uint32_t), j++) {
-               ((uint32_t *)data)[j] = cpu_to_be32(((uint32_t *)fcp_cmnd)[j]);
-       }
-}
-
 /**
  * lpfc_scsi_prep_dma_buf_s3 - DMA mapping for scsi buffer to SLI3 IF spec
  * @phba: The Hba for which this call is being executed.
@@ -1283,7 +1264,6 @@ lpfc_scsi_prep_dma_buf_s3(struct lpfc_hba *phba, struct lpfc_scsi_buf *lpfc_cmd)
         * we need to set word 4 of IOCB here
         */
        iocb_cmd->un.fcpi.fcpi_parm = scsi_bufflen(scsi_cmnd);
-       lpfc_fcpcmd_to_iocb(iocb_cmd->unsli3.fcp_ext.icd, fcp_cmnd);
        return 0;
 }
 
@@ -4146,6 +4126,24 @@ lpfc_scsi_cmd_iocb_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *pIocbIn,
        lpfc_release_scsi_buf(phba, lpfc_cmd);
 }
 
+/**
+ * lpfc_fcpcmd_to_iocb - copy the fcp_cmd data into the IOCB
+ * @data: A pointer to the immediate command data portion of the IOCB.
+ * @fcp_cmnd: The FCP Command that is provided by the SCSI layer.
+ *
+ * The routine copies the entire FCP command from @fcp_cmnd to @data while
+ * byte swapping the data to big endian format for transmission on the wire.
+ **/
+static void
+lpfc_fcpcmd_to_iocb(uint8_t *data, struct fcp_cmnd *fcp_cmnd)
+{
+       int i, j;
+       for (i = 0, j = 0; i < sizeof(struct fcp_cmnd);
+            i += sizeof(uint32_t), j++) {
+               ((uint32_t *)data)[j] = cpu_to_be32(((uint32_t *)fcp_cmnd)[j]);
+       }
+}
+
 /**
  * lpfc_scsi_prep_cmnd - Wrapper func for convert scsi cmnd to FCP info unit
  * @vport: The virtual port for which this call is being executed.
@@ -4225,6 +4223,9 @@ lpfc_scsi_prep_cmnd(struct lpfc_vport *vport, struct lpfc_scsi_buf *lpfc_cmd,
                fcp_cmnd->fcpCntl3 = 0;
                phba->fc4ControlRequests++;
        }
+       if (phba->sli_rev == 3 &&
+           !(phba->sli3_options & LPFC_SLI3_BG_ENABLED))
+               lpfc_fcpcmd_to_iocb(iocb_cmd->unsli3.fcp_ext.icd, fcp_cmnd);
        /*
         * Finish initializing those IOCB fields that are independent
         * of the scsi_cmnd request_buffer
index 68c2002e78bf80d3b383b92f76519901459059da..5c9e680aa375a57c07a8977790271615ffb1499d 100644 (file)
@@ -1020,8 +1020,7 @@ static void tcm_qla2xxx_depend_tpg(struct work_struct *work)
        struct se_portal_group *se_tpg = &base_tpg->se_tpg;
        struct scsi_qla_host *base_vha = base_tpg->lport->qla_vha;
 
-       if (!configfs_depend_item(se_tpg->se_tpg_tfo->tf_subsys,
-                                 &se_tpg->tpg_group.cg_item)) {
+       if (!target_depend_item(&se_tpg->tpg_group.cg_item)) {
                atomic_set(&base_tpg->lport_tpg_enabled, 1);
                qlt_enable_vha(base_vha);
        }
@@ -1037,8 +1036,7 @@ static void tcm_qla2xxx_undepend_tpg(struct work_struct *work)
 
        if (!qlt_stop_phase1(base_vha->vha_tgt.qla_tgt)) {
                atomic_set(&base_tpg->lport_tpg_enabled, 0);
-               configfs_undepend_item(se_tpg->se_tpg_tfo->tf_subsys,
-                                      &se_tpg->tpg_group.cg_item);
+               target_undepend_item(&se_tpg->tpg_group.cg_item);
        }
        complete(&base_tpg->tpg_base_comp);
 }
index 262ab837a7040d5586e4212b59e569aa55a2df0c..9f77d23239a264d85a2331ea50737cbfdc88ee36 100644 (file)
@@ -226,6 +226,7 @@ static struct {
        {"PIONEER", "CD-ROM DRM-624X", NULL, BLIST_FORCELUN | BLIST_SINGLELUN},
        {"Promise", "VTrak E610f", NULL, BLIST_SPARSELUN | BLIST_NO_RSOC},
        {"Promise", "", NULL, BLIST_SPARSELUN},
+       {"QNAP", "iSCSI Storage", NULL, BLIST_MAX_1024},
        {"QUANTUM", "XP34301", "1071", BLIST_NOTQ},
        {"REGAL", "CDC-4X", NULL, BLIST_MAX5LUN | BLIST_SINGLELUN},
        {"SanDisk", "ImageMate CF-SD1", NULL, BLIST_FORCELUN},
index 60aae01caa89d96cd8c78681a8f0a97b44cae8ec..6efab1c455e158a71a2792c07d9b6d3fadc7595c 100644 (file)
@@ -897,6 +897,12 @@ static int scsi_add_lun(struct scsi_device *sdev, unsigned char *inq_result,
         */
        if (*bflags & BLIST_MAX_512)
                blk_queue_max_hw_sectors(sdev->request_queue, 512);
+       /*
+        * Max 1024 sector transfer length for targets that report incorrect
+        * max/optimal lengths and relied on the old block layer safe default
+        */
+       else if (*bflags & BLIST_MAX_1024)
+               blk_queue_max_hw_sectors(sdev->request_queue, 1024);
 
        /*
         * Some devices may not want to have a start command automatically
index 79beebf53302e591bc0661372335561c65d3e006..7f9d65fe4fd9a441c1aa00f602f3dac14c866563 100644 (file)
@@ -1600,6 +1600,7 @@ static unsigned int sd_completed_bytes(struct scsi_cmnd *scmd)
 {
        u64 start_lba = blk_rq_pos(scmd->request);
        u64 end_lba = blk_rq_pos(scmd->request) + (scsi_bufflen(scmd) / 512);
+       u64 factor = scmd->device->sector_size / 512;
        u64 bad_lba;
        int info_valid;
        /*
@@ -1621,16 +1622,9 @@ static unsigned int sd_completed_bytes(struct scsi_cmnd *scmd)
        if (scsi_bufflen(scmd) <= scmd->device->sector_size)
                return 0;
 
-       if (scmd->device->sector_size < 512) {
-               /* only legitimate sector_size here is 256 */
-               start_lba <<= 1;
-               end_lba <<= 1;
-       } else {
-               /* be careful ... don't want any overflows */
-               unsigned int factor = scmd->device->sector_size / 512;
-               do_div(start_lba, factor);
-               do_div(end_lba, factor);
-       }
+       /* be careful ... don't want any overflows */
+       do_div(start_lba, factor);
+       do_div(end_lba, factor);
 
        /* The bad lba was reported incorrectly, we have no idea where
         * the error is.
@@ -2188,8 +2182,7 @@ got_data:
        if (sector_size != 512 &&
            sector_size != 1024 &&
            sector_size != 2048 &&
-           sector_size != 4096 &&
-           sector_size != 256) {
+           sector_size != 4096) {
                sd_printk(KERN_NOTICE, sdkp, "Unsupported sector size %d.\n",
                          sector_size);
                /*
@@ -2244,8 +2237,6 @@ got_data:
                sdkp->capacity <<= 2;
        else if (sector_size == 1024)
                sdkp->capacity <<= 1;
-       else if (sector_size == 256)
-               sdkp->capacity >>= 1;
 
        blk_queue_physical_block_size(sdp->request_queue,
                                      sdkp->physical_block_size);
index d9dad90344d545a18185ecf0736fa79a4b6a212b..3c6584ff65c1979b6119c4edce15e6d35eb3957f 100644 (file)
@@ -1600,8 +1600,7 @@ static int storvsc_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *scmnd)
                break;
        default:
                vm_srb->data_in = UNKNOWN_TYPE;
-               vm_srb->win8_extension.srb_flags |= (SRB_FLAGS_DATA_IN |
-                                                    SRB_FLAGS_DATA_OUT);
+               vm_srb->win8_extension.srb_flags |= SRB_FLAGS_NO_DATA_TRANSFER;
                break;
        }
 
index cd4c293f0dd0d375be6d6d815108aeb588304fec..fe8875f0d7be1155883655150ec57c3115356bbe 100644 (file)
@@ -80,9 +80,10 @@ static int __init sh_pm_runtime_init(void)
        if (IS_ENABLED(CONFIG_ARCH_SHMOBILE_MULTI)) {
                if (!of_machine_is_compatible("renesas,emev2") &&
                    !of_machine_is_compatible("renesas,r7s72100") &&
-                   !of_machine_is_compatible("renesas,r8a73a4") &&
 #ifndef CONFIG_PM_GENERIC_DOMAINS_OF
+                   !of_machine_is_compatible("renesas,r8a73a4") &&
                    !of_machine_is_compatible("renesas,r8a7740") &&
+                   !of_machine_is_compatible("renesas,sh73a0") &&
 #endif
                    !of_machine_is_compatible("renesas,r8a7778") &&
                    !of_machine_is_compatible("renesas,r8a7779") &&
@@ -90,9 +91,7 @@ static int __init sh_pm_runtime_init(void)
                    !of_machine_is_compatible("renesas,r8a7791") &&
                    !of_machine_is_compatible("renesas,r8a7792") &&
                    !of_machine_is_compatible("renesas,r8a7793") &&
-                   !of_machine_is_compatible("renesas,r8a7794") &&
-                   !of_machine_is_compatible("renesas,sh7372") &&
-                   !of_machine_is_compatible("renesas,sh73a0"))
+                   !of_machine_is_compatible("renesas,r8a7794"))
                        return 0;
        }
 
index bcdb22d5e215c9a393ccabe58f4f94ef132e3516..3c1850332a90212798ab5030554bc8fad39d9796 100644 (file)
@@ -4,6 +4,7 @@
 config MTK_PMIC_WRAP
        tristate "MediaTek PMIC Wrapper Support"
        depends on ARCH_MEDIATEK
+       depends on RESET_CONTROLLER
        select REGMAP
        help
          Say yes here to add support for MediaTek PMIC Wrapper found
index db5be1eec54c8db3977ea810e13c5470f416aaa7..f432291feee91e4b7c7b5ce3cc84f3b130933309 100644 (file)
@@ -443,11 +443,6 @@ static int pwrap_wait_for_state(struct pmic_wrapper *wrp,
 static int pwrap_write(struct pmic_wrapper *wrp, u32 adr, u32 wdata)
 {
        int ret;
-       u32 val;
-
-       val = pwrap_readl(wrp, PWRAP_WACS2_RDATA);
-       if (PWRAP_GET_WACS_FSM(val) == PWRAP_WACS_FSM_WFVLDCLR)
-               pwrap_writel(wrp, 1, PWRAP_WACS2_VLDCLR);
 
        ret = pwrap_wait_for_state(wrp, pwrap_is_fsm_idle);
        if (ret)
@@ -462,11 +457,6 @@ static int pwrap_write(struct pmic_wrapper *wrp, u32 adr, u32 wdata)
 static int pwrap_read(struct pmic_wrapper *wrp, u32 adr, u32 *rdata)
 {
        int ret;
-       u32 val;
-
-       val = pwrap_readl(wrp, PWRAP_WACS2_RDATA);
-       if (PWRAP_GET_WACS_FSM(val) == PWRAP_WACS_FSM_WFVLDCLR)
-               pwrap_writel(wrp, 1, PWRAP_WACS2_VLDCLR);
 
        ret = pwrap_wait_for_state(wrp, pwrap_is_fsm_idle);
        if (ret)
@@ -480,6 +470,8 @@ static int pwrap_read(struct pmic_wrapper *wrp, u32 adr, u32 *rdata)
 
        *rdata = PWRAP_GET_WACS_RDATA(pwrap_readl(wrp, PWRAP_WACS2_RDATA));
 
+       pwrap_writel(wrp, 1, PWRAP_WACS2_VLDCLR);
+
        return 0;
 }
 
@@ -563,45 +555,17 @@ static int pwrap_init_sidly(struct pmic_wrapper *wrp)
 
 static int pwrap_init_reg_clock(struct pmic_wrapper *wrp)
 {
-       unsigned long rate_spi;
-       int ck_mhz;
-
-       rate_spi = clk_get_rate(wrp->clk_spi);
-
-       if (rate_spi > 26000000)
-               ck_mhz = 26;
-       else if (rate_spi > 18000000)
-               ck_mhz = 18;
-       else
-               ck_mhz = 0;
-
-       switch (ck_mhz) {
-       case 18:
-               if (pwrap_is_mt8135(wrp))
-                       pwrap_writel(wrp, 0xc, PWRAP_CSHEXT);
-               pwrap_writel(wrp, 0x4, PWRAP_CSHEXT_WRITE);
-               pwrap_writel(wrp, 0xc, PWRAP_CSHEXT_READ);
-               pwrap_writel(wrp, 0x0, PWRAP_CSLEXT_START);
-               pwrap_writel(wrp, 0x0, PWRAP_CSLEXT_END);
-               break;
-       case 26:
-               if (pwrap_is_mt8135(wrp))
-                       pwrap_writel(wrp, 0x4, PWRAP_CSHEXT);
+       if (pwrap_is_mt8135(wrp)) {
+               pwrap_writel(wrp, 0x4, PWRAP_CSHEXT);
                pwrap_writel(wrp, 0x0, PWRAP_CSHEXT_WRITE);
                pwrap_writel(wrp, 0x4, PWRAP_CSHEXT_READ);
                pwrap_writel(wrp, 0x0, PWRAP_CSLEXT_START);
                pwrap_writel(wrp, 0x0, PWRAP_CSLEXT_END);
-               break;
-       case 0:
-               if (pwrap_is_mt8135(wrp))
-                       pwrap_writel(wrp, 0xf, PWRAP_CSHEXT);
-               pwrap_writel(wrp, 0xf, PWRAP_CSHEXT_WRITE);
-               pwrap_writel(wrp, 0xf, PWRAP_CSHEXT_READ);
-               pwrap_writel(wrp, 0xf, PWRAP_CSLEXT_START);
-               pwrap_writel(wrp, 0xf, PWRAP_CSLEXT_END);
-               break;
-       default:
-               return -EINVAL;
+       } else {
+               pwrap_writel(wrp, 0x0, PWRAP_CSHEXT_WRITE);
+               pwrap_writel(wrp, 0x4, PWRAP_CSHEXT_READ);
+               pwrap_writel(wrp, 0x2, PWRAP_CSLEXT_START);
+               pwrap_writel(wrp, 0x2, PWRAP_CSLEXT_END);
        }
 
        return 0;
index 198f96b7fb45dab78845ba1fcde123ea680e2082..72b059081559356100aa68dea2c021b056b492e5 100644 (file)
@@ -78,6 +78,7 @@ config SPI_ATMEL
 config SPI_BCM2835
        tristate "BCM2835 SPI controller"
        depends on ARCH_BCM2835 || COMPILE_TEST
+       depends on GPIOLIB
        help
          This selects a driver for the Broadcom BCM2835 SPI master.
 
@@ -302,7 +303,7 @@ config SPI_FSL_SPI
 config SPI_FSL_DSPI
        tristate "Freescale DSPI controller"
        select REGMAP_MMIO
-       depends on SOC_VF610 || COMPILE_TEST
+       depends on SOC_VF610 || SOC_LS1021A || COMPILE_TEST
        help
          This enables support for the Freescale DSPI controller in master
          mode. VF610 platform uses the controller.
index f63864a893c520c40d9c79f1c8ca838b15dedc8c..37875cf942f7b928c5d31f44345b5c060f182b36 100644 (file)
@@ -164,13 +164,12 @@ static int bcm2835_spi_transfer_one_poll(struct spi_master *master,
                                         unsigned long xfer_time_us)
 {
        struct bcm2835_spi *bs = spi_master_get_devdata(master);
-       unsigned long timeout = jiffies +
-               max(4 * xfer_time_us * HZ / 1000000, 2uL);
+       /* set timeout to 1 second of maximum polling */
+       unsigned long timeout = jiffies + HZ;
 
        /* enable HW block without interrupts */
        bcm2835_wr(bs, BCM2835_SPI_CS, cs | BCM2835_SPI_CS_TA);
 
-       /* set timeout to 4x the expected time, or 2 jiffies */
        /* loop until finished the transfer */
        while (bs->rx_len) {
                /* read from fifo as much as possible */
index 5ef6638d5e8a2698a6c8e85fad41c46d1f03fd06..840a4984d3650e27dcf98713235a67e040b8ca1a 100644 (file)
@@ -180,7 +180,6 @@ int spi_bitbang_setup(struct spi_device *spi)
 {
        struct spi_bitbang_cs   *cs = spi->controller_state;
        struct spi_bitbang      *bitbang;
-       int                     retval;
        unsigned long           flags;
 
        bitbang = spi_master_get_devdata(spi->master);
@@ -197,9 +196,11 @@ int spi_bitbang_setup(struct spi_device *spi)
        if (!cs->txrx_word)
                return -EINVAL;
 
-       retval = bitbang->setup_transfer(spi, NULL);
-       if (retval < 0)
-               return retval;
+       if (bitbang->setup_transfer) {
+               int retval = bitbang->setup_transfer(spi, NULL);
+               if (retval < 0)
+                       return retval;
+       }
 
        dev_dbg(&spi->dev, "%s, %u nsec/bit\n", __func__, 2 * cs->nsecs);
 
@@ -295,9 +296,11 @@ static int spi_bitbang_transfer_one(struct spi_master *master,
 
                /* init (-1) or override (1) transfer params */
                if (do_setup != 0) {
-                       status = bitbang->setup_transfer(spi, t);
-                       if (status < 0)
-                               break;
+                       if (bitbang->setup_transfer) {
+                               status = bitbang->setup_transfer(spi, t);
+                               if (status < 0)
+                                       break;
+                       }
                        if (do_setup == -1)
                                do_setup = 0;
                }
index 9c46a3058743b75228256f55e64b8419b49c1f3d..896add8cfd3b6c6bba311a335072e63a4060a3a4 100644 (file)
@@ -24,6 +24,7 @@
 #include <linux/of_address.h>
 #include <linux/spi/spi.h>
 #include <linux/types.h>
+#include <linux/platform_device.h>
 
 #include "spi-fsl-cpm.h"
 #include "spi-fsl-lib.h"
@@ -269,17 +270,6 @@ static unsigned long fsl_spi_cpm_get_pram(struct mpc8xxx_spi *mspi)
        if (mspi->flags & SPI_CPM2) {
                pram_ofs = cpm_muram_alloc(SPI_PRAM_SIZE, 64);
                out_be16(spi_base, pram_ofs);
-       } else {
-               struct spi_pram __iomem *pram = spi_base;
-               u16 rpbase = in_be16(&pram->rpbase);
-
-               /* Microcode relocation patch applied? */
-               if (rpbase) {
-                       pram_ofs = rpbase;
-               } else {
-                       pram_ofs = cpm_muram_alloc(SPI_PRAM_SIZE, 64);
-                       out_be16(spi_base, pram_ofs);
-               }
        }
 
        iounmap(spi_base);
@@ -292,7 +282,6 @@ int fsl_spi_cpm_init(struct mpc8xxx_spi *mspi)
        struct device_node *np = dev->of_node;
        const u32 *iprop;
        int size;
-       unsigned long pram_ofs;
        unsigned long bds_ofs;
 
        if (!(mspi->flags & SPI_CPM_MODE))
@@ -319,8 +308,26 @@ int fsl_spi_cpm_init(struct mpc8xxx_spi *mspi)
                }
        }
 
-       pram_ofs = fsl_spi_cpm_get_pram(mspi);
-       if (IS_ERR_VALUE(pram_ofs)) {
+       if (mspi->flags & SPI_CPM1) {
+               struct resource *res;
+               void *pram;
+
+               res = platform_get_resource(to_platform_device(dev),
+                                           IORESOURCE_MEM, 1);
+               pram = devm_ioremap_resource(dev, res);
+               if (IS_ERR(pram))
+                       mspi->pram = NULL;
+               else
+                       mspi->pram = pram;
+       } else {
+               unsigned long pram_ofs = fsl_spi_cpm_get_pram(mspi);
+
+               if (IS_ERR_VALUE(pram_ofs))
+                       mspi->pram = NULL;
+               else
+                       mspi->pram = cpm_muram_addr(pram_ofs);
+       }
+       if (mspi->pram == NULL) {
                dev_err(dev, "can't allocate spi parameter ram\n");
                goto err_pram;
        }
@@ -346,8 +353,6 @@ int fsl_spi_cpm_init(struct mpc8xxx_spi *mspi)
                goto err_dummy_rx;
        }
 
-       mspi->pram = cpm_muram_addr(pram_ofs);
-
        mspi->tx_bd = cpm_muram_addr(bds_ofs);
        mspi->rx_bd = cpm_muram_addr(bds_ofs + sizeof(*mspi->tx_bd));
 
@@ -375,7 +380,8 @@ err_dummy_rx:
 err_dummy_tx:
        cpm_muram_free(bds_ofs);
 err_bds:
-       cpm_muram_free(pram_ofs);
+       if (!(mspi->flags & SPI_CPM1))
+               cpm_muram_free(cpm_muram_offset(mspi->pram));
 err_pram:
        fsl_spi_free_dummy_rx();
        return -ENOMEM;
index d0a73a09a9bd3e02371a30bc4b5ceb34f6b52e4e..80d245ac846fa366abf8d2b7511a1fb4ac25c03e 100644 (file)
@@ -359,14 +359,16 @@ static void fsl_espi_rw_trans(struct spi_message *m,
                                struct fsl_espi_transfer *trans, u8 *rx_buff)
 {
        struct fsl_espi_transfer *espi_trans = trans;
-       unsigned int n_tx = espi_trans->n_tx;
-       unsigned int n_rx = espi_trans->n_rx;
+       unsigned int total_len = espi_trans->len;
        struct spi_transfer *t;
        u8 *local_buf;
        u8 *rx_buf = rx_buff;
        unsigned int trans_len;
        unsigned int addr;
-       int i, pos, loop;
+       unsigned int tx_only;
+       unsigned int rx_pos = 0;
+       unsigned int pos;
+       int i, loop;
 
        local_buf = kzalloc(SPCOM_TRANLEN_MAX, GFP_KERNEL);
        if (!local_buf) {
@@ -374,36 +376,48 @@ static void fsl_espi_rw_trans(struct spi_message *m,
                return;
        }
 
-       for (pos = 0, loop = 0; pos < n_rx; pos += trans_len, loop++) {
-               trans_len = n_rx - pos;
-               if (trans_len > SPCOM_TRANLEN_MAX - n_tx)
-                       trans_len = SPCOM_TRANLEN_MAX - n_tx;
+       for (pos = 0, loop = 0; pos < total_len; pos += trans_len, loop++) {
+               trans_len = total_len - pos;
 
                i = 0;
+               tx_only = 0;
                list_for_each_entry(t, &m->transfers, transfer_list) {
                        if (t->tx_buf) {
                                memcpy(local_buf + i, t->tx_buf, t->len);
                                i += t->len;
+                               if (!t->rx_buf)
+                                       tx_only += t->len;
                        }
                }
 
+               /* Add additional TX bytes to compensate SPCOM_TRANLEN_MAX */
+               if (loop > 0)
+                       trans_len += tx_only;
+
+               if (trans_len > SPCOM_TRANLEN_MAX)
+                       trans_len = SPCOM_TRANLEN_MAX;
+
+               /* Update device offset */
                if (pos > 0) {
                        addr = fsl_espi_cmd2addr(local_buf);
-                       addr += pos;
+                       addr += rx_pos;
                        fsl_espi_addr2cmd(addr, local_buf);
                }
 
-               espi_trans->n_tx = n_tx;
-               espi_trans->n_rx = trans_len;
-               espi_trans->len = trans_len + n_tx;
+               espi_trans->len = trans_len;
                espi_trans->tx_buf = local_buf;
                espi_trans->rx_buf = local_buf;
                fsl_espi_do_trans(m, espi_trans);
 
-               memcpy(rx_buf + pos, espi_trans->rx_buf + n_tx, trans_len);
+               /* If there is at least one RX byte then copy it to rx_buf */
+               if (tx_only < SPCOM_TRANLEN_MAX)
+                       memcpy(rx_buf + rx_pos, espi_trans->rx_buf + tx_only,
+                                       trans_len - tx_only);
+
+               rx_pos += trans_len - tx_only;
 
                if (loop > 0)
-                       espi_trans->actual_length += espi_trans->len - n_tx;
+                       espi_trans->actual_length += espi_trans->len - tx_only;
                else
                        espi_trans->actual_length += espi_trans->len;
        }
@@ -418,6 +432,7 @@ static int fsl_espi_do_one_msg(struct spi_master *master,
        u8 *rx_buf = NULL;
        unsigned int n_tx = 0;
        unsigned int n_rx = 0;
+       unsigned int xfer_len = 0;
        struct fsl_espi_transfer espi_trans;
 
        list_for_each_entry(t, &m->transfers, transfer_list) {
@@ -427,11 +442,13 @@ static int fsl_espi_do_one_msg(struct spi_master *master,
                        n_rx += t->len;
                        rx_buf = t->rx_buf;
                }
+               if ((t->tx_buf) || (t->rx_buf))
+                       xfer_len += t->len;
        }
 
        espi_trans.n_tx = n_tx;
        espi_trans.n_rx = n_rx;
-       espi_trans.len = n_tx + n_rx;
+       espi_trans.len = xfer_len;
        espi_trans.actual_length = 0;
        espi_trans.status = 0;
 
index 4df8942058deed3928e61a4b2bc4061c56eec7d7..d1a5b9fc3eba22edaafd6155a5292ee108d97ac7 100644 (file)
@@ -1210,6 +1210,7 @@ static int omap2_mcspi_transfer_one_message(struct spi_master *master,
        struct omap2_mcspi      *mcspi;
        struct omap2_mcspi_dma  *mcspi_dma;
        struct spi_transfer     *t;
+       int status;
 
        spi = m->spi;
        mcspi = spi_master_get_devdata(master);
@@ -1229,7 +1230,8 @@ static int omap2_mcspi_transfer_one_message(struct spi_master *master,
                                        tx_buf ? "tx" : "",
                                        rx_buf ? "rx" : "",
                                        t->bits_per_word);
-                       return -EINVAL;
+                       status = -EINVAL;
+                       goto out;
                }
 
                if (m->is_dma_mapped || len < DMA_MIN_BYTES)
@@ -1241,7 +1243,8 @@ static int omap2_mcspi_transfer_one_message(struct spi_master *master,
                        if (dma_mapping_error(mcspi->dev, t->tx_dma)) {
                                dev_dbg(mcspi->dev, "dma %cX %d bytes error\n",
                                                'T', len);
-                               return -EINVAL;
+                               status = -EINVAL;
+                               goto out;
                        }
                }
                if (mcspi_dma->dma_rx && rx_buf != NULL) {
@@ -1253,14 +1256,19 @@ static int omap2_mcspi_transfer_one_message(struct spi_master *master,
                                if (tx_buf != NULL)
                                        dma_unmap_single(mcspi->dev, t->tx_dma,
                                                        len, DMA_TO_DEVICE);
-                               return -EINVAL;
+                               status = -EINVAL;
+                               goto out;
                        }
                }
        }
 
        omap2_mcspi_work(mcspi, m);
+       /* spi_finalize_current_message() changes the status inside the
+        * spi_message, save the status here. */
+       status = m->status;
+out:
        spi_finalize_current_message(master);
-       return 0;
+       return status;
 }
 
 static int omap2_mcspi_master_setup(struct omap2_mcspi *mcspi)
index d5d7d2235163f9ef8c6430d99544ec7f2c791c6b..50910d85df5af28d6f281485cc79d4b3e15bc7e5 100644 (file)
@@ -583,6 +583,15 @@ static int spi_unmap_msg(struct spi_master *master, struct spi_message *msg)
        rx_dev = master->dma_rx->device->dev;
 
        list_for_each_entry(xfer, &msg->transfers, transfer_list) {
+               /*
+                * Restore the original value of tx_buf or rx_buf if they are
+                * NULL.
+                */
+               if (xfer->tx_buf == master->dummy_tx)
+                       xfer->tx_buf = NULL;
+               if (xfer->rx_buf == master->dummy_rx)
+                       xfer->rx_buf = NULL;
+
                if (!master->can_dma(master, msg->spi, xfer))
                        continue;
 
index 09428412139e399979537da2e6272eda827a8757..c5352ea4821ea0df593c7043ac911ee891f103b0 100644 (file)
@@ -621,8 +621,8 @@ static u32 ssb_pmu_get_alp_clock_clk0(struct ssb_chipcommon *cc)
        u32 crystalfreq;
        const struct pmu0_plltab_entry *e = NULL;
 
-       crystalfreq = chipco_read32(cc, SSB_CHIPCO_PMU_CTL) &
-                     SSB_CHIPCO_PMU_CTL_XTALFREQ >> SSB_CHIPCO_PMU_CTL_XTALFREQ_SHIFT;
+       crystalfreq = (chipco_read32(cc, SSB_CHIPCO_PMU_CTL) &
+                      SSB_CHIPCO_PMU_CTL_XTALFREQ)  >> SSB_CHIPCO_PMU_CTL_XTALFREQ_SHIFT;
        e = pmu0_plltab_find_entry(crystalfreq);
        BUG_ON(!e);
        return e->freq * 1000;
@@ -634,7 +634,7 @@ u32 ssb_pmu_get_alp_clock(struct ssb_chipcommon *cc)
 
        switch (bus->chip_id) {
        case 0x5354:
-               ssb_pmu_get_alp_clock_clk0(cc);
+               return ssb_pmu_get_alp_clock_clk0(cc);
        default:
                ssb_err("ERROR: PMU alp clock unknown for device %04X\n",
                        bus->chip_id);
index 15a7ee3859dd7dd74aee31593876b422093eff04..5fe1c22e289b881cacebbf081d7c245fad7d2098 100644 (file)
@@ -359,12 +359,13 @@ static void ssb_pcicore_init_hostmode(struct ssb_pcicore *pc)
 
        /*
         * Accessing PCI config without a proper delay after devices reset (not
-        * GPIO reset) was causing reboots on WRT300N v1.0.
+        * GPIO reset) was causing reboots on WRT300N v1.0 (BCM4704).
         * Tested delay 850 us lowered reboot chance to 50-80%, 1000 us fixed it
         * completely. Flushing all writes was also tested but with no luck.
+        * The same problem was reported for WRT350N v1 (BCM4705), so we just
+        * sleep here unconditionally.
         */
-       if (pc->dev->bus->chip_id == 0x4704)
-               usleep_range(1000, 2000);
+       usleep_range(1000, 2000);
 
        /* Enable PCI bridge BAR0 prefetch and burst */
        val = PCI_COMMAND_MASTER | PCI_COMMAND_MEMORY;
index 8199b0a697bb5f8b672aabad8f9685c8c51a8f5e..1cf24e4edf251ca1896a72073c5fdf6df0eac336 100644 (file)
@@ -158,7 +158,7 @@ static int up_to_host(struct mux_rx *r)
        unsigned int start_flag;
        unsigned int payload_size;
        unsigned short packet_type;
-       int dummy_cnt;
+       int total_len;
        u32 packet_size_sum = r->offset;
        int index;
        int ret = TO_HOST_INVALID_PACKET;
@@ -176,10 +176,10 @@ static int up_to_host(struct mux_rx *r)
                        break;
                }
 
-               dummy_cnt = ALIGN(MUX_HEADER_SIZE + payload_size, 4);
+               total_len = ALIGN(MUX_HEADER_SIZE + payload_size, 4);
 
                if (len - packet_size_sum <
-                       MUX_HEADER_SIZE + payload_size + dummy_cnt) {
+                       total_len) {
                        pr_err("invalid payload : %d %d %04x\n",
                               payload_size, len, packet_type);
                        break;
@@ -202,7 +202,7 @@ static int up_to_host(struct mux_rx *r)
                        break;
                }
 
-               packet_size_sum += MUX_HEADER_SIZE + payload_size + dummy_cnt;
+               packet_size_sum += total_len;
                if (len - packet_size_sum <= MUX_HEADER_SIZE + 2) {
                        ret = r->callback(NULL,
                                        0,
@@ -361,7 +361,6 @@ static int gdm_mux_send(void *priv_dev, void *data, int len, int tty_index,
        struct mux_pkt_header *mux_header;
        struct mux_tx *t = NULL;
        static u32 seq_num = 1;
-       int dummy_cnt;
        int total_len;
        int ret;
        unsigned long flags;
@@ -374,9 +373,7 @@ static int gdm_mux_send(void *priv_dev, void *data, int len, int tty_index,
 
        spin_lock_irqsave(&mux_dev->write_lock, flags);
 
-       dummy_cnt = ALIGN(MUX_HEADER_SIZE + len, 4);
-
-       total_len = len + MUX_HEADER_SIZE + dummy_cnt;
+       total_len = ALIGN(MUX_HEADER_SIZE + len, 4);
 
        t = alloc_mux_tx(total_len);
        if (!t) {
@@ -392,7 +389,8 @@ static int gdm_mux_send(void *priv_dev, void *data, int len, int tty_index,
        mux_header->packet_type = __cpu_to_le16(packet_type[tty_index]);
 
        memcpy(t->buf+MUX_HEADER_SIZE, data, len);
-       memset(t->buf+MUX_HEADER_SIZE+len, 0, dummy_cnt);
+       memset(t->buf+MUX_HEADER_SIZE+len, 0, total_len - MUX_HEADER_SIZE -
+              len);
 
        t->len = total_len;
        t->callback = cb;
index b78643f907e7a4e7cd4974a877c3ddd98a19a77e..072dac04a75007cd8dd5ad1f1769b791a14d216a 100644 (file)
@@ -2,6 +2,7 @@ config VIDEO_OMAP4
        bool "OMAP 4 Camera support"
        depends on VIDEO_V4L2=y && VIDEO_V4L2_SUBDEV_API && I2C=y && ARCH_OMAP4
        depends on HAS_DMA
+       select MFD_SYSCON
        select VIDEOBUF2_DMA_CONTIG
        ---help---
          Driver for an OMAP 4 ISS controller.
index e0ad5e520e2d26705f43d1862de128ea428f20a6..7ced940bd8073dd6b3e3f4299e656ff3cf48146b 100644 (file)
@@ -17,6 +17,7 @@
 #include <linux/dma-mapping.h>
 #include <linux/i2c.h>
 #include <linux/interrupt.h>
+#include <linux/mfd/syscon.h>
 #include <linux/module.h>
 #include <linux/platform_device.h>
 #include <linux/slab.h>
@@ -1386,6 +1387,16 @@ static int iss_probe(struct platform_device *pdev)
 
        platform_set_drvdata(pdev, iss);
 
+       /*
+        * TODO: When implementing DT support switch to syscon regmap lookup by
+        * phandle.
+        */
+       iss->syscon = syscon_regmap_lookup_by_compatible("syscon");
+       if (IS_ERR(iss->syscon)) {
+               ret = PTR_ERR(iss->syscon);
+               goto error;
+       }
+
        /* Clocks */
        ret = iss_map_mem_resource(pdev, iss, OMAP4_ISS_MEM_TOP);
        if (ret < 0)
index 734cfeeb03148abed151ff76c1009c9d3df8994a..35df8b4709e6089d44f15d81fa989e9a4a6840cc 100644 (file)
@@ -29,6 +29,8 @@
 #include "iss_ipipe.h"
 #include "iss_resizer.h"
 
+struct regmap;
+
 #define to_iss_device(ptr_module)                              \
        container_of(ptr_module, struct iss_device, ptr_module)
 #define to_device(ptr_module)                                          \
@@ -79,6 +81,7 @@ struct iss_reg {
 
 /*
  * struct iss_device - ISS device structure.
+ * @syscon: Regmap for the syscon register space
  * @crashed: Bitmask of crashed entities (indexed by entity ID)
  */
 struct iss_device {
@@ -93,6 +96,7 @@ struct iss_device {
 
        struct resource *res[OMAP4_ISS_MEM_LAST];
        void __iomem *regs[OMAP4_ISS_MEM_LAST];
+       struct regmap *syscon;
 
        u64 raw_dmamask;
 
index 7c3d55d811ef66d2597a5ef6fa4ceff087eab6b0..748607f8918f7021a2319ec21d05b6e18533f895 100644 (file)
@@ -13,6 +13,7 @@
 
 #include <linux/delay.h>
 #include <linux/device.h>
+#include <linux/regmap.h>
 
 #include "../../../../arch/arm/mach-omap2/control.h"
 
@@ -140,9 +141,11 @@ int omap4iss_csiphy_config(struct iss_device *iss,
         * - bit [18] : CSIPHY1 CTRLCLK enable
         * - bit [17:16] : CSIPHY1 config: 00 d-phy, 01/10 ccp2
         */
-       cam_rx_ctrl = omap4_ctrl_pad_readl(
-                       OMAP4_CTRL_MODULE_PAD_CORE_CONTROL_CAMERA_RX);
-
+       /*
+        * TODO: When implementing DT support specify the CONTROL_CAMERA_RX
+        * register offset in the syscon property instead of hardcoding it.
+        */
+       regmap_read(iss->syscon, 0x68, &cam_rx_ctrl);
 
        if (subdevs->interface == ISS_INTERFACE_CSI2A_PHY1) {
                cam_rx_ctrl &= ~(OMAP4_CAMERARX_CSI21_LANEENABLE_MASK |
@@ -166,8 +169,7 @@ int omap4iss_csiphy_config(struct iss_device *iss,
                cam_rx_ctrl |= OMAP4_CAMERARX_CSI22_CTRLCLKEN_MASK;
        }
 
-       omap4_ctrl_pad_writel(cam_rx_ctrl,
-                OMAP4_CTRL_MODULE_PAD_CORE_CONTROL_CAMERA_RX);
+       regmap_write(iss->syscon, 0x68, cam_rx_ctrl);
 
        /* Reset used lane count */
        csi2->phy->used_data_lanes = 0;
index 5ff4716b72c311485084005b9e09a36021157530..784b5ecfa8493ba07d8ba90cde1b11b2b6a4b6b7 100644 (file)
@@ -746,8 +746,8 @@ void oz_hcd_pd_reset(void *hpd, void *hport)
 /*
  * Context: softirq
  */
-void oz_hcd_get_desc_cnf(void *hport, u8 req_id, int status, const u8 *desc,
-                       int length, int offset, int total_size)
+void oz_hcd_get_desc_cnf(void *hport, u8 req_id, u8 status, const u8 *desc,
+                       u8 length, u16 offset, u16 total_size)
 {
        struct oz_port *port = hport;
        struct urb *urb;
@@ -759,8 +759,8 @@ void oz_hcd_get_desc_cnf(void *hport, u8 req_id, int status, const u8 *desc,
        if (!urb)
                return;
        if (status == 0) {
-               int copy_len;
-               int required_size = urb->transfer_buffer_length;
+               unsigned int copy_len;
+               unsigned int required_size = urb->transfer_buffer_length;
 
                if (required_size > total_size)
                        required_size = total_size;
index 4249fa37401289c4caf1f4cae4d46dba321f276b..d2a6085345bec8c2e927115389efc46bfbad3019 100644 (file)
@@ -29,8 +29,8 @@ void oz_usb_request_heartbeat(void *hpd);
 
 /* Confirmation functions.
  */
-void oz_hcd_get_desc_cnf(void *hport, u8 req_id, int status,
-       const u8 *desc, int length, int offset, int total_size);
+void oz_hcd_get_desc_cnf(void *hport, u8 req_id, u8 status,
+       const u8 *desc, u8 length, u16 offset, u16 total_size);
 void oz_hcd_control_cnf(void *hport, u8 req_id, u8 rcode,
        const u8 *data, int data_len);
 
index d434d8c6fff67c04b58d6cac5c76a6832bae5bc3..f660bb198c65534a6cbe8183d3f5d0a30a532eb1 100644 (file)
@@ -326,7 +326,11 @@ static void oz_usb_handle_ep_data(struct oz_usb_ctx *usb_ctx,
                        struct oz_multiple_fixed *body =
                                (struct oz_multiple_fixed *)data_hdr;
                        u8 *data = body->data;
-                       int n = (len - sizeof(struct oz_multiple_fixed)+1)
+                       unsigned int n;
+                       if (!body->unit_size ||
+                               len < sizeof(struct oz_multiple_fixed) - 1)
+                               break;
+                       n = (len - (sizeof(struct oz_multiple_fixed) - 1))
                                / body->unit_size;
                        while (n--) {
                                oz_hcd_data_ind(usb_ctx->hport, body->endpoint,
@@ -390,10 +394,15 @@ void oz_usb_rx(struct oz_pd *pd, struct oz_elt *elt)
        case OZ_GET_DESC_RSP: {
                        struct oz_get_desc_rsp *body =
                                (struct oz_get_desc_rsp *)usb_hdr;
-                       int data_len = elt->length -
-                                       sizeof(struct oz_get_desc_rsp) + 1;
-                       u16 offs = le16_to_cpu(get_unaligned(&body->offset));
-                       u16 total_size =
+                       u16 offs, total_size;
+                       u8 data_len;
+
+                       if (elt->length < sizeof(struct oz_get_desc_rsp) - 1)
+                               break;
+                       data_len = elt->length -
+                                       (sizeof(struct oz_get_desc_rsp) - 1);
+                       offs = le16_to_cpu(get_unaligned(&body->offset));
+                       total_size =
                                le16_to_cpu(get_unaligned(&body->total_size));
                        oz_dbg(ON, "USB_REQ_GET_DESCRIPTOR - cnf\n");
                        oz_hcd_get_desc_cnf(usb_ctx->hport, body->req_id,
index f1d47a0676c3e3ba29ea974754c77e8a32a3f950..ada8d5dafd492e97a1b4d9457d25e4a485e67556 100644 (file)
@@ -898,11 +898,11 @@ static void SwLedControlMode1(struct _adapter *padapter,
                          IS_LED_WPS_BLINKING(pLed))
                                return;
                        if (pLed->bLedLinkBlinkInProgress == true) {
-                               del_timer_sync(&pLed->BlinkTimer);
+                               del_timer(&pLed->BlinkTimer);
                                pLed->bLedLinkBlinkInProgress = false;
                        }
                        if (pLed->bLedBlinkInProgress == true) {
-                               del_timer_sync(&pLed->BlinkTimer);
+                               del_timer(&pLed->BlinkTimer);
                                pLed->bLedBlinkInProgress = false;
                        }
                        pLed->bLedNoLinkBlinkInProgress = true;
@@ -921,11 +921,11 @@ static void SwLedControlMode1(struct _adapter *padapter,
                            IS_LED_WPS_BLINKING(pLed))
                                return;
                        if (pLed->bLedNoLinkBlinkInProgress == true) {
-                               del_timer_sync(&pLed->BlinkTimer);
+                               del_timer(&pLed->BlinkTimer);
                                pLed->bLedNoLinkBlinkInProgress = false;
                        }
                        if (pLed->bLedBlinkInProgress == true) {
-                               del_timer_sync(&pLed->BlinkTimer);
+                               del_timer(&pLed->BlinkTimer);
                                pLed->bLedBlinkInProgress = false;
                        }
                        pLed->bLedLinkBlinkInProgress = true;
@@ -946,15 +946,15 @@ static void SwLedControlMode1(struct _adapter *padapter,
                        if (IS_LED_WPS_BLINKING(pLed))
                                return;
                        if (pLed->bLedNoLinkBlinkInProgress == true) {
-                               del_timer_sync(&pLed->BlinkTimer);
+                               del_timer(&pLed->BlinkTimer);
                                pLed->bLedNoLinkBlinkInProgress = false;
                        }
                        if (pLed->bLedLinkBlinkInProgress == true) {
-                               del_timer_sync(&pLed->BlinkTimer);
+                               del_timer(&pLed->BlinkTimer);
                                 pLed->bLedLinkBlinkInProgress = false;
                        }
                        if (pLed->bLedBlinkInProgress == true) {
-                               del_timer_sync(&pLed->BlinkTimer);
+                               del_timer(&pLed->BlinkTimer);
                                pLed->bLedBlinkInProgress = false;
                        }
                        pLed->bLedScanBlinkInProgress = true;
@@ -975,11 +975,11 @@ static void SwLedControlMode1(struct _adapter *padapter,
                            IS_LED_WPS_BLINKING(pLed))
                                return;
                        if (pLed->bLedNoLinkBlinkInProgress == true) {
-                               del_timer_sync(&pLed->BlinkTimer);
+                               del_timer(&pLed->BlinkTimer);
                                pLed->bLedNoLinkBlinkInProgress = false;
                        }
                        if (pLed->bLedLinkBlinkInProgress == true) {
-                               del_timer_sync(&pLed->BlinkTimer);
+                               del_timer(&pLed->BlinkTimer);
                                pLed->bLedLinkBlinkInProgress = false;
                        }
                        pLed->bLedBlinkInProgress = true;
@@ -998,19 +998,19 @@ static void SwLedControlMode1(struct _adapter *padapter,
        case LED_CTL_START_WPS_BOTTON:
                 if (pLed->bLedWPSBlinkInProgress == false) {
                        if (pLed->bLedNoLinkBlinkInProgress == true) {
-                               del_timer_sync(&pLed->BlinkTimer);
+                               del_timer(&pLed->BlinkTimer);
                                pLed->bLedNoLinkBlinkInProgress = false;
                        }
                        if (pLed->bLedLinkBlinkInProgress == true) {
-                               del_timer_sync(&pLed->BlinkTimer);
+                               del_timer(&pLed->BlinkTimer);
                                 pLed->bLedLinkBlinkInProgress = false;
                        }
                        if (pLed->bLedBlinkInProgress == true) {
-                               del_timer_sync(&pLed->BlinkTimer);
+                               del_timer(&pLed->BlinkTimer);
                                pLed->bLedBlinkInProgress = false;
                        }
                        if (pLed->bLedScanBlinkInProgress == true) {
-                               del_timer_sync(&pLed->BlinkTimer);
+                               del_timer(&pLed->BlinkTimer);
                                pLed->bLedScanBlinkInProgress = false;
                        }
                        pLed->bLedWPSBlinkInProgress = true;
@@ -1025,23 +1025,23 @@ static void SwLedControlMode1(struct _adapter *padapter,
                break;
        case LED_CTL_STOP_WPS:
                if (pLed->bLedNoLinkBlinkInProgress == true) {
-                       del_timer_sync(&pLed->BlinkTimer);
+                       del_timer(&pLed->BlinkTimer);
                        pLed->bLedNoLinkBlinkInProgress = false;
                }
                if (pLed->bLedLinkBlinkInProgress == true) {
-                       del_timer_sync(&pLed->BlinkTimer);
+                       del_timer(&pLed->BlinkTimer);
                         pLed->bLedLinkBlinkInProgress = false;
                }
                if (pLed->bLedBlinkInProgress == true) {
-                       del_timer_sync(&pLed->BlinkTimer);
+                       del_timer(&pLed->BlinkTimer);
                        pLed->bLedBlinkInProgress = false;
                }
                if (pLed->bLedScanBlinkInProgress == true) {
-                       del_timer_sync(&pLed->BlinkTimer);
+                       del_timer(&pLed->BlinkTimer);
                        pLed->bLedScanBlinkInProgress = false;
                }
                if (pLed->bLedWPSBlinkInProgress)
-                       del_timer_sync(&pLed->BlinkTimer);
+                       del_timer(&pLed->BlinkTimer);
                else
                        pLed->bLedWPSBlinkInProgress = true;
                pLed->CurrLedState = LED_BLINK_WPS_STOP;
@@ -1057,7 +1057,7 @@ static void SwLedControlMode1(struct _adapter *padapter,
                break;
        case LED_CTL_STOP_WPS_FAIL:
                if (pLed->bLedWPSBlinkInProgress) {
-                       del_timer_sync(&pLed->BlinkTimer);
+                       del_timer(&pLed->BlinkTimer);
                        pLed->bLedWPSBlinkInProgress = false;
                }
                pLed->bLedNoLinkBlinkInProgress = true;
@@ -1073,23 +1073,23 @@ static void SwLedControlMode1(struct _adapter *padapter,
                pLed->CurrLedState = LED_OFF;
                pLed->BlinkingLedState = LED_OFF;
                if (pLed->bLedNoLinkBlinkInProgress) {
-                       del_timer_sync(&pLed->BlinkTimer);
+                       del_timer(&pLed->BlinkTimer);
                        pLed->bLedNoLinkBlinkInProgress = false;
                }
                if (pLed->bLedLinkBlinkInProgress) {
-                       del_timer_sync(&pLed->BlinkTimer);
+                       del_timer(&pLed->BlinkTimer);
                        pLed->bLedLinkBlinkInProgress = false;
                }
                if (pLed->bLedBlinkInProgress) {
-                       del_timer_sync(&pLed->BlinkTimer);
+                       del_timer(&pLed->BlinkTimer);
                        pLed->bLedBlinkInProgress = false;
                }
                if (pLed->bLedWPSBlinkInProgress) {
-                       del_timer_sync(&pLed->BlinkTimer);
+                       del_timer(&pLed->BlinkTimer);
                        pLed->bLedWPSBlinkInProgress = false;
                }
                if (pLed->bLedScanBlinkInProgress) {
-                       del_timer_sync(&pLed->BlinkTimer);
+                       del_timer(&pLed->BlinkTimer);
                        pLed->bLedScanBlinkInProgress = false;
                }
                mod_timer(&pLed->BlinkTimer,
@@ -1116,7 +1116,7 @@ static void SwLedControlMode2(struct _adapter *padapter,
                                return;
 
                        if (pLed->bLedBlinkInProgress == true) {
-                               del_timer_sync(&pLed->BlinkTimer);
+                               del_timer(&pLed->BlinkTimer);
                                pLed->bLedBlinkInProgress = false;
                        }
                        pLed->bLedScanBlinkInProgress = true;
@@ -1154,11 +1154,11 @@ static void SwLedControlMode2(struct _adapter *padapter,
                pLed->CurrLedState = LED_ON;
                pLed->BlinkingLedState = LED_ON;
                if (pLed->bLedBlinkInProgress) {
-                       del_timer_sync(&pLed->BlinkTimer);
+                       del_timer(&pLed->BlinkTimer);
                        pLed->bLedBlinkInProgress = false;
                }
                if (pLed->bLedScanBlinkInProgress) {
-                       del_timer_sync(&pLed->BlinkTimer);
+                       del_timer(&pLed->BlinkTimer);
                        pLed->bLedScanBlinkInProgress = false;
                }
 
@@ -1170,11 +1170,11 @@ static void SwLedControlMode2(struct _adapter *padapter,
        case LED_CTL_START_WPS_BOTTON:
                if (pLed->bLedWPSBlinkInProgress == false) {
                        if (pLed->bLedBlinkInProgress == true) {
-                               del_timer_sync(&pLed->BlinkTimer);
+                               del_timer(&pLed->BlinkTimer);
                                pLed->bLedBlinkInProgress = false;
                        }
                        if (pLed->bLedScanBlinkInProgress == true) {
-                               del_timer_sync(&pLed->BlinkTimer);
+                               del_timer(&pLed->BlinkTimer);
                                pLed->bLedScanBlinkInProgress = false;
                        }
                        pLed->bLedWPSBlinkInProgress = true;
@@ -1214,15 +1214,15 @@ static void SwLedControlMode2(struct _adapter *padapter,
                pLed->CurrLedState = LED_OFF;
                pLed->BlinkingLedState = LED_OFF;
                if (pLed->bLedBlinkInProgress) {
-                       del_timer_sync(&pLed->BlinkTimer);
+                       del_timer(&pLed->BlinkTimer);
                        pLed->bLedBlinkInProgress = false;
                }
                if (pLed->bLedScanBlinkInProgress) {
-                       del_timer_sync(&pLed->BlinkTimer);
+                       del_timer(&pLed->BlinkTimer);
                        pLed->bLedScanBlinkInProgress = false;
                }
                if (pLed->bLedWPSBlinkInProgress) {
-                       del_timer_sync(&pLed->BlinkTimer);
+                       del_timer(&pLed->BlinkTimer);
                        pLed->bLedWPSBlinkInProgress = false;
                }
                mod_timer(&pLed->BlinkTimer,
@@ -1248,7 +1248,7 @@ static void SwLedControlMode3(struct _adapter *padapter,
                        if (IS_LED_WPS_BLINKING(pLed))
                                return;
                        if (pLed->bLedBlinkInProgress == true) {
-                               del_timer_sync(&pLed->BlinkTimer);
+                               del_timer(&pLed->BlinkTimer);
                                pLed->bLedBlinkInProgress = false;
                        }
                        pLed->bLedScanBlinkInProgress = true;
@@ -1286,11 +1286,11 @@ static void SwLedControlMode3(struct _adapter *padapter,
                pLed->CurrLedState = LED_ON;
                pLed->BlinkingLedState = LED_ON;
                if (pLed->bLedBlinkInProgress) {
-                       del_timer_sync(&pLed->BlinkTimer);
+                       del_timer(&pLed->BlinkTimer);
                        pLed->bLedBlinkInProgress = false;
                }
                if (pLed->bLedScanBlinkInProgress) {
-                       del_timer_sync(&pLed->BlinkTimer);
+                       del_timer(&pLed->BlinkTimer);
                        pLed->bLedScanBlinkInProgress = false;
                }
                mod_timer(&pLed->BlinkTimer,
@@ -1300,11 +1300,11 @@ static void SwLedControlMode3(struct _adapter *padapter,
        case LED_CTL_START_WPS_BOTTON:
                if (pLed->bLedWPSBlinkInProgress == false) {
                        if (pLed->bLedBlinkInProgress == true) {
-                               del_timer_sync(&pLed->BlinkTimer);
+                               del_timer(&pLed->BlinkTimer);
                                pLed->bLedBlinkInProgress = false;
                        }
                        if (pLed->bLedScanBlinkInProgress == true) {
-                               del_timer_sync(&pLed->BlinkTimer);
+                               del_timer(&pLed->BlinkTimer);
                                pLed->bLedScanBlinkInProgress = false;
                        }
                        pLed->bLedWPSBlinkInProgress = true;
@@ -1319,7 +1319,7 @@ static void SwLedControlMode3(struct _adapter *padapter,
                break;
        case LED_CTL_STOP_WPS:
                if (pLed->bLedWPSBlinkInProgress) {
-                       del_timer_sync(&(pLed->BlinkTimer));
+                       del_timer(&pLed->BlinkTimer);
                        pLed->bLedWPSBlinkInProgress = false;
                } else
                        pLed->bLedWPSBlinkInProgress = true;
@@ -1336,7 +1336,7 @@ static void SwLedControlMode3(struct _adapter *padapter,
                break;
        case LED_CTL_STOP_WPS_FAIL:
                if (pLed->bLedWPSBlinkInProgress) {
-                       del_timer_sync(&pLed->BlinkTimer);
+                       del_timer(&pLed->BlinkTimer);
                        pLed->bLedWPSBlinkInProgress = false;
                }
                pLed->CurrLedState = LED_OFF;
@@ -1357,15 +1357,15 @@ static void SwLedControlMode3(struct _adapter *padapter,
                pLed->CurrLedState = LED_OFF;
                pLed->BlinkingLedState = LED_OFF;
                if (pLed->bLedBlinkInProgress) {
-                       del_timer_sync(&pLed->BlinkTimer);
+                       del_timer(&pLed->BlinkTimer);
                        pLed->bLedBlinkInProgress = false;
                }
                if (pLed->bLedScanBlinkInProgress) {
-                       del_timer_sync(&pLed->BlinkTimer);
+                       del_timer(&pLed->BlinkTimer);
                        pLed->bLedScanBlinkInProgress = false;
                }
                if (pLed->bLedWPSBlinkInProgress) {
-                       del_timer_sync(&pLed->BlinkTimer);
+                       del_timer(&pLed->BlinkTimer);
                        pLed->bLedWPSBlinkInProgress = false;
                }
                mod_timer(&pLed->BlinkTimer,
@@ -1388,7 +1388,7 @@ static void SwLedControlMode4(struct _adapter *padapter,
        case LED_CTL_START_TO_LINK:
                if (pLed1->bLedWPSBlinkInProgress) {
                        pLed1->bLedWPSBlinkInProgress = false;
-                       del_timer_sync(&pLed1->BlinkTimer);
+                       del_timer(&pLed1->BlinkTimer);
                        pLed1->BlinkingLedState = LED_OFF;
                        pLed1->CurrLedState = LED_OFF;
                        if (pLed1->bLedOn)
@@ -1400,11 +1400,11 @@ static void SwLedControlMode4(struct _adapter *padapter,
                            IS_LED_WPS_BLINKING(pLed))
                                return;
                        if (pLed->bLedBlinkInProgress == true) {
-                               del_timer_sync(&pLed->BlinkTimer);
+                               del_timer(&pLed->BlinkTimer);
                                pLed->bLedBlinkInProgress = false;
                        }
                        if (pLed->bLedNoLinkBlinkInProgress == true) {
-                               del_timer_sync(&pLed->BlinkTimer);
+                               del_timer(&pLed->BlinkTimer);
                                pLed->bLedNoLinkBlinkInProgress = false;
                        }
                        pLed->bLedStartToLinkBlinkInProgress = true;
@@ -1426,7 +1426,7 @@ static void SwLedControlMode4(struct _adapter *padapter,
                if (LedAction == LED_CTL_LINK) {
                        if (pLed1->bLedWPSBlinkInProgress) {
                                pLed1->bLedWPSBlinkInProgress = false;
-                               del_timer_sync(&pLed1->BlinkTimer);
+                               del_timer(&pLed1->BlinkTimer);
                                pLed1->BlinkingLedState = LED_OFF;
                                pLed1->CurrLedState = LED_OFF;
                                if (pLed1->bLedOn)
@@ -1439,7 +1439,7 @@ static void SwLedControlMode4(struct _adapter *padapter,
                            IS_LED_WPS_BLINKING(pLed))
                                return;
                        if (pLed->bLedBlinkInProgress == true) {
-                               del_timer_sync(&pLed->BlinkTimer);
+                               del_timer(&pLed->BlinkTimer);
                                pLed->bLedBlinkInProgress = false;
                        }
                        pLed->bLedNoLinkBlinkInProgress = true;
@@ -1460,11 +1460,11 @@ static void SwLedControlMode4(struct _adapter *padapter,
                        if (IS_LED_WPS_BLINKING(pLed))
                                return;
                        if (pLed->bLedNoLinkBlinkInProgress == true) {
-                               del_timer_sync(&pLed->BlinkTimer);
+                               del_timer(&pLed->BlinkTimer);
                                pLed->bLedNoLinkBlinkInProgress = false;
                        }
                        if (pLed->bLedBlinkInProgress == true) {
-                               del_timer_sync(&pLed->BlinkTimer);
+                               del_timer(&pLed->BlinkTimer);
                                pLed->bLedBlinkInProgress = false;
                        }
                        pLed->bLedScanBlinkInProgress = true;
@@ -1485,7 +1485,7 @@ static void SwLedControlMode4(struct _adapter *padapter,
                            IS_LED_WPS_BLINKING(pLed))
                                return;
                        if (pLed->bLedNoLinkBlinkInProgress == true) {
-                               del_timer_sync(&pLed->BlinkTimer);
+                               del_timer(&pLed->BlinkTimer);
                                pLed->bLedNoLinkBlinkInProgress = false;
                        }
                        pLed->bLedBlinkInProgress = true;
@@ -1503,7 +1503,7 @@ static void SwLedControlMode4(struct _adapter *padapter,
        case LED_CTL_START_WPS_BOTTON:
                if (pLed1->bLedWPSBlinkInProgress) {
                        pLed1->bLedWPSBlinkInProgress = false;
-                       del_timer_sync(&(pLed1->BlinkTimer));
+                       del_timer(&pLed1->BlinkTimer);
                        pLed1->BlinkingLedState = LED_OFF;
                        pLed1->CurrLedState = LED_OFF;
                        if (pLed1->bLedOn)
@@ -1512,15 +1512,15 @@ static void SwLedControlMode4(struct _adapter *padapter,
                }
                if (pLed->bLedWPSBlinkInProgress == false) {
                        if (pLed->bLedNoLinkBlinkInProgress == true) {
-                               del_timer_sync(&pLed->BlinkTimer);
+                               del_timer(&pLed->BlinkTimer);
                                pLed->bLedNoLinkBlinkInProgress = false;
                        }
                        if (pLed->bLedBlinkInProgress == true) {
-                               del_timer_sync(&pLed->BlinkTimer);
+                               del_timer(&pLed->BlinkTimer);
                                pLed->bLedBlinkInProgress = false;
                        }
                        if (pLed->bLedScanBlinkInProgress == true) {
-                               del_timer_sync(&pLed->BlinkTimer);
+                               del_timer(&pLed->BlinkTimer);
                                pLed->bLedScanBlinkInProgress = false;
                        }
                        pLed->bLedWPSBlinkInProgress = true;
@@ -1538,7 +1538,7 @@ static void SwLedControlMode4(struct _adapter *padapter,
                break;
        case LED_CTL_STOP_WPS:  /*WPS connect success*/
                if (pLed->bLedWPSBlinkInProgress) {
-                       del_timer_sync(&pLed->BlinkTimer);
+                       del_timer(&pLed->BlinkTimer);
                        pLed->bLedWPSBlinkInProgress = false;
                }
                pLed->bLedNoLinkBlinkInProgress = true;
@@ -1552,7 +1552,7 @@ static void SwLedControlMode4(struct _adapter *padapter,
                break;
        case LED_CTL_STOP_WPS_FAIL:     /*WPS authentication fail*/
                if (pLed->bLedWPSBlinkInProgress) {
-                       del_timer_sync(&pLed->BlinkTimer);
+                       del_timer(&pLed->BlinkTimer);
                        pLed->bLedWPSBlinkInProgress = false;
                }
                pLed->bLedNoLinkBlinkInProgress = true;
@@ -1565,7 +1565,7 @@ static void SwLedControlMode4(struct _adapter *padapter,
                          msecs_to_jiffies(LED_BLINK_NO_LINK_INTERVAL_ALPHA));
                /*LED1 settings*/
                if (pLed1->bLedWPSBlinkInProgress)
-                       del_timer_sync(&pLed1->BlinkTimer);
+                       del_timer(&pLed1->BlinkTimer);
                else
                        pLed1->bLedWPSBlinkInProgress = true;
                pLed1->CurrLedState = LED_BLINK_WPS_STOP;
@@ -1578,7 +1578,7 @@ static void SwLedControlMode4(struct _adapter *padapter,
                break;
        case LED_CTL_STOP_WPS_FAIL_OVERLAP:     /*WPS session overlap*/
                if (pLed->bLedWPSBlinkInProgress) {
-                       del_timer_sync(&pLed->BlinkTimer);
+                       del_timer(&pLed->BlinkTimer);
                        pLed->bLedWPSBlinkInProgress = false;
                }
                pLed->bLedNoLinkBlinkInProgress = true;
@@ -1591,7 +1591,7 @@ static void SwLedControlMode4(struct _adapter *padapter,
                          msecs_to_jiffies(LED_BLINK_NO_LINK_INTERVAL_ALPHA));
                /*LED1 settings*/
                if (pLed1->bLedWPSBlinkInProgress)
-                       del_timer_sync(&pLed1->BlinkTimer);
+                       del_timer(&pLed1->BlinkTimer);
                else
                        pLed1->bLedWPSBlinkInProgress = true;
                pLed1->CurrLedState = LED_BLINK_WPS_STOP_OVERLAP;
@@ -1607,31 +1607,31 @@ static void SwLedControlMode4(struct _adapter *padapter,
                pLed->CurrLedState = LED_OFF;
                pLed->BlinkingLedState = LED_OFF;
                if (pLed->bLedNoLinkBlinkInProgress) {
-                       del_timer_sync(&pLed->BlinkTimer);
+                       del_timer(&pLed->BlinkTimer);
                        pLed->bLedNoLinkBlinkInProgress = false;
                }
                if (pLed->bLedLinkBlinkInProgress) {
-                       del_timer_sync(&pLed->BlinkTimer);
+                       del_timer(&pLed->BlinkTimer);
                        pLed->bLedLinkBlinkInProgress = false;
                }
                if (pLed->bLedBlinkInProgress) {
-                       del_timer_sync(&pLed->BlinkTimer);
+                       del_timer(&pLed->BlinkTimer);
                        pLed->bLedBlinkInProgress = false;
                }
                if (pLed->bLedWPSBlinkInProgress) {
-                       del_timer_sync(&pLed->BlinkTimer);
+                       del_timer(&pLed->BlinkTimer);
                        pLed->bLedWPSBlinkInProgress = false;
                }
                if (pLed->bLedScanBlinkInProgress) {
-                       del_timer_sync(&pLed->BlinkTimer);
+                       del_timer(&pLed->BlinkTimer);
                        pLed->bLedScanBlinkInProgress = false;
                }
                if (pLed->bLedStartToLinkBlinkInProgress) {
-                       del_timer_sync(&pLed->BlinkTimer);
+                       del_timer(&pLed->BlinkTimer);
                        pLed->bLedStartToLinkBlinkInProgress = false;
                }
                if (pLed1->bLedWPSBlinkInProgress) {
-                       del_timer_sync(&pLed1->BlinkTimer);
+                       del_timer(&pLed1->BlinkTimer);
                        pLed1->bLedWPSBlinkInProgress = false;
                }
                pLed1->BlinkingLedState = LED_UNKNOWN;
@@ -1671,7 +1671,7 @@ static void SwLedControlMode5(struct _adapter *padapter,
                        ; /* dummy branch */
                else if (pLed->bLedScanBlinkInProgress == false) {
                        if (pLed->bLedBlinkInProgress == true) {
-                               del_timer_sync(&pLed->BlinkTimer);
+                               del_timer(&pLed->BlinkTimer);
                                pLed->bLedBlinkInProgress = false;
                        }
                        pLed->bLedScanBlinkInProgress = true;
@@ -1705,7 +1705,7 @@ static void SwLedControlMode5(struct _adapter *padapter,
                pLed->CurrLedState = LED_OFF;
                pLed->BlinkingLedState = LED_OFF;
                if (pLed->bLedBlinkInProgress) {
-                       del_timer_sync(&pLed->BlinkTimer);
+                       del_timer(&pLed->BlinkTimer);
                        pLed->bLedBlinkInProgress = false;
                }
                SwLedOff(padapter, pLed);
@@ -1756,7 +1756,7 @@ static void SwLedControlMode6(struct _adapter *padapter,
        case LED_CTL_START_WPS_BOTTON:
                if (pLed->bLedWPSBlinkInProgress == false) {
                        if (pLed->bLedBlinkInProgress == true) {
-                               del_timer_sync(&pLed->BlinkTimer);
+                               del_timer(&pLed->BlinkTimer);
                                pLed->bLedBlinkInProgress = false;
                        }
                        pLed->bLedWPSBlinkInProgress = true;
@@ -1772,7 +1772,7 @@ static void SwLedControlMode6(struct _adapter *padapter,
        case LED_CTL_STOP_WPS_FAIL:
        case LED_CTL_STOP_WPS:
                if (pLed->bLedWPSBlinkInProgress) {
-                       del_timer_sync(&pLed->BlinkTimer);
+                       del_timer(&pLed->BlinkTimer);
                        pLed->bLedWPSBlinkInProgress = false;
                }
                pLed->CurrLedState = LED_ON;
@@ -1784,11 +1784,11 @@ static void SwLedControlMode6(struct _adapter *padapter,
                pLed->CurrLedState = LED_OFF;
                pLed->BlinkingLedState = LED_OFF;
                if (pLed->bLedBlinkInProgress) {
-                       del_timer_sync(&pLed->BlinkTimer);
+                       del_timer(&pLed->BlinkTimer);
                        pLed->bLedBlinkInProgress = false;
                }
                if (pLed->bLedWPSBlinkInProgress) {
-                       del_timer_sync(&pLed->BlinkTimer);
+                       del_timer(&pLed->BlinkTimer);
                        pLed->bLedWPSBlinkInProgress = false;
                }
                SwLedOff(padapter, pLed);
index 1a1c38f885d6b191d5a62b5fb1aae26713dd6cb3..e35854d28f90ed96aa3ff149f39175c9e46b1373 100644 (file)
@@ -910,7 +910,7 @@ void r8712_createbss_cmd_callback(struct _adapter *padapter,
        if (pcmd->res != H2C_SUCCESS)
                mod_timer(&pmlmepriv->assoc_timer,
                          jiffies + msecs_to_jiffies(1));
-       del_timer_sync(&pmlmepriv->assoc_timer);
+       del_timer(&pmlmepriv->assoc_timer);
 #ifdef __BIG_ENDIAN
        /* endian_convert */
        pnetwork->Length = le32_to_cpu(pnetwork->Length);
index 42fba3f5b593e08801a57269ede5e21da8c8841f..cb0b6387789f197dbe2d314b96728d05b6a361c9 100644 (file)
@@ -1900,23 +1900,20 @@ static int r871x_mp_ioctl_hdl(struct net_device *dev,
        struct mp_ioctl_handler *phandler;
        struct mp_ioctl_param *poidparam;
        unsigned long BytesRead, BytesWritten, BytesNeeded;
-       u8 *pparmbuf = NULL, bset;
+       u8 *pparmbuf, bset;
        u16 len;
        uint status;
        int ret = 0;
 
-       if ((!p->length) || (!p->pointer)) {
-               ret = -EINVAL;
-               goto _r871x_mp_ioctl_hdl_exit;
-       }
+       if ((!p->length) || (!p->pointer))
+               return -EINVAL;
+
        bset = (u8)(p->flags & 0xFFFF);
        len = p->length;
-       pparmbuf = NULL;
        pparmbuf = memdup_user(p->pointer, len);
-       if (IS_ERR(pparmbuf)) {
-               ret = PTR_ERR(pparmbuf);
-               goto _r871x_mp_ioctl_hdl_exit;
-       }
+       if (IS_ERR(pparmbuf))
+               return PTR_ERR(pparmbuf);
+
        poidparam = (struct mp_ioctl_param *)pparmbuf;
        if (poidparam->subcode >= MAX_MP_IOCTL_SUBCODE) {
                ret = -EINVAL;
index fb2b195b90af0d1690552dfccb6ec93b13960fdf..c044b0e55ba93d0c989031d52ce99f4008ae0630 100644 (file)
@@ -582,7 +582,7 @@ void r8712_surveydone_event_callback(struct _adapter *adapter, u8 *pbuf)
        spin_lock_irqsave(&pmlmepriv->lock, irqL);
 
        if (check_fwstate(pmlmepriv, _FW_UNDER_SURVEY) == true) {
-               del_timer_sync(&pmlmepriv->scan_to_timer);
+               del_timer(&pmlmepriv->scan_to_timer);
 
                _clr_fwstate_(pmlmepriv, _FW_UNDER_SURVEY);
        }
@@ -696,7 +696,7 @@ void r8712_ind_disconnect(struct _adapter *padapter)
        }
        if (padapter->pwrctrlpriv.pwr_mode !=
            padapter->registrypriv.power_mgnt) {
-               del_timer_sync(&pmlmepriv->dhcp_timer);
+               del_timer(&pmlmepriv->dhcp_timer);
                r8712_set_ps_mode(padapter, padapter->registrypriv.power_mgnt,
                                  padapter->registrypriv.smart_ps);
        }
@@ -910,7 +910,7 @@ void r8712_joinbss_event_callback(struct _adapter *adapter, u8 *pbuf)
                        if (check_fwstate(pmlmepriv, WIFI_STATION_STATE)
                                == true)
                                r8712_indicate_connect(adapter);
-                       del_timer_sync(&pmlmepriv->assoc_timer);
+                       del_timer(&pmlmepriv->assoc_timer);
                } else
                        goto ignore_joinbss_callback;
        } else {
index aaa584435c87d25d3efb3bbbe794da6cf2096c24..9bc04f474d18d7c79311c8bd6fc80b48015a6550 100644 (file)
@@ -103,7 +103,7 @@ void r8712_cpwm_int_hdl(struct _adapter *padapter,
 
        if (pwrpriv->cpwm_tog == ((preportpwrstate->state) & 0x80))
                return;
-       del_timer_sync(&padapter->pwrctrlpriv.rpwm_check_timer);
+       del_timer(&padapter->pwrctrlpriv.rpwm_check_timer);
        _enter_pwrlock(&pwrpriv->lock);
        pwrpriv->cpwm = (preportpwrstate->state) & 0xf;
        if (pwrpriv->cpwm >= PS_STATE_S2) {
index 7bb96c47f1883dad0c62e8618b2e98ac773fca27..a9b93d0f6f566b83bb00271de37f68dc1716586c 100644 (file)
@@ -198,7 +198,7 @@ void r8712_free_stainfo(struct _adapter *padapter, struct sta_info *psta)
         * cancel reordering_ctrl_timer */
        for (i = 0; i < 16; i++) {
                preorder_ctrl = &psta->recvreorder_ctrl[i];
-               del_timer_sync(&preorder_ctrl->reordering_ctrl_timer);
+               del_timer(&preorder_ctrl->reordering_ctrl_timer);
        }
        spin_lock(&(pfree_sta_queue->lock));
        /* insert into free_sta_queue; 20061114 */
index 3c7ea95dd9f93aa0f1619c246d3fea78d0eea155..dbbb2f879a29fb00a59e20733ee118920ff19c59 100644 (file)
@@ -1250,7 +1250,7 @@ err_enable:
        return -ENODEV;
 }
 
-static void __exit lynxfb_pci_remove(struct pci_dev *pdev)
+static void lynxfb_pci_remove(struct pci_dev *pdev)
 {
        struct fb_info *info;
        struct lynx_share *share;
index 1cdcf49b2445094ba5270011251dfe86684766e4..e00c0605d1541556492c8ab46d5d4db8156a30f6 100644 (file)
@@ -362,12 +362,16 @@ bool CARDbSetPhyParameter(struct vnt_private *pDevice, u8 bb_type)
  * Return Value: none
  */
 bool CARDbUpdateTSF(struct vnt_private *pDevice, unsigned char byRxRate,
-                   u64 qwBSSTimestamp, u64 qwLocalTSF)
+                   u64 qwBSSTimestamp)
 {
+       u64 local_tsf;
        u64 qwTSFOffset = 0;
 
-       if (qwBSSTimestamp != qwLocalTSF) {
-               qwTSFOffset = CARDqGetTSFOffset(byRxRate, qwBSSTimestamp, qwLocalTSF);
+       CARDbGetCurrentTSF(pDevice, &local_tsf);
+
+       if (qwBSSTimestamp != local_tsf) {
+               qwTSFOffset = CARDqGetTSFOffset(byRxRate, qwBSSTimestamp,
+                                               local_tsf);
                /* adjust TSF, HW's TSF add TSF Offset reg */
                VNSvOutPortD(pDevice->PortOffset + MAC_REG_TSFOFST, (u32)qwTSFOffset);
                VNSvOutPortD(pDevice->PortOffset + MAC_REG_TSFOFST + 4, (u32)(qwTSFOffset >> 32));
index 2dfc4195227188bf48f1473cc821051739f135da..16cca49e680a3fc74bde7795b7565cfbe61bd17a 100644 (file)
@@ -83,7 +83,7 @@ bool CARDbRadioPowerOff(struct vnt_private *);
 bool CARDbRadioPowerOn(struct vnt_private *);
 bool CARDbSetPhyParameter(struct vnt_private *, u8);
 bool CARDbUpdateTSF(struct vnt_private *, unsigned char byRxRate,
-                   u64 qwBSSTimestamp, u64 qwLocalTSF);
+                   u64 qwBSSTimestamp);
 bool CARDbSetBeaconPeriod(struct vnt_private *, unsigned short wBeaconInterval);
 
 #endif /* __CARD_H__ */
index 4bb4f8ee41321a23134bcaf750ff3d2896350e82..0343ae386f0351bdff320f2f956371540eb931f3 100644 (file)
@@ -912,7 +912,11 @@ static int vnt_int_report_rate(struct vnt_private *priv,
 
        if (!(tsr1 & TSR1_TERR)) {
                info->status.rates[0].idx = idx;
-               info->flags |= IEEE80211_TX_STAT_ACK;
+
+               if (info->flags & IEEE80211_TX_CTL_NO_ACK)
+                       info->flags |= IEEE80211_TX_STAT_NOACK_TRANSMITTED;
+               else
+                       info->flags |= IEEE80211_TX_STAT_ACK;
        }
 
        return 0;
@@ -937,9 +941,6 @@ static int device_tx_srv(struct vnt_private *pDevice, unsigned int uIdx)
                /* Only the status of first TD in the chain is correct */
                if (pTD->m_td1TD1.byTCR & TCR_STP) {
                        if ((pTD->pTDInfo->byFlags & TD_FLAGS_NETIF_SKB) != 0) {
-
-                               vnt_int_report_rate(pDevice, pTD->pTDInfo, byTsr0, byTsr1);
-
                                if (!(byTsr1 & TSR1_TERR)) {
                                        if (byTsr0 != 0) {
                                                pr_debug(" Tx[%d] OK but has error. tsr1[%02X] tsr0[%02X]\n",
@@ -958,6 +959,9 @@ static int device_tx_srv(struct vnt_private *pDevice, unsigned int uIdx)
                                                 (int)uIdx, byTsr1, byTsr0);
                                }
                        }
+
+                       vnt_int_report_rate(pDevice, pTD->pTDInfo, byTsr0, byTsr1);
+
                        device_free_tx_buf(pDevice, pTD);
                        pDevice->iTDUsed[uIdx]--;
                }
@@ -989,10 +993,8 @@ static void device_free_tx_buf(struct vnt_private *pDevice, PSTxDesc pDesc)
                                 skb->len, DMA_TO_DEVICE);
        }
 
-       if (pTDInfo->byFlags & TD_FLAGS_NETIF_SKB)
+       if (skb)
                ieee80211_tx_status_irqsafe(pDevice->hw, skb);
-       else
-               dev_kfree_skb_irq(skb);
 
        pTDInfo->skb_dma = 0;
        pTDInfo->skb = NULL;
@@ -1204,14 +1206,6 @@ static int vnt_tx_packet(struct vnt_private *priv, struct sk_buff *skb)
        if (dma_idx == TYPE_AC0DMA)
                head_td->pTDInfo->byFlags = TD_FLAGS_NETIF_SKB;
 
-       priv->iTDUsed[dma_idx]++;
-
-       /* Take ownership */
-       wmb();
-       head_td->m_td0TD0.f1Owner = OWNED_BY_NIC;
-
-       /* get Next */
-       wmb();
        priv->apCurrTD[dma_idx] = head_td->next;
 
        spin_unlock_irqrestore(&priv->lock, flags);
@@ -1232,11 +1226,18 @@ static int vnt_tx_packet(struct vnt_private *priv, struct sk_buff *skb)
 
        head_td->buff_addr = cpu_to_le32(head_td->pTDInfo->skb_dma);
 
+       /* Poll Transmit the adapter */
+       wmb();
+       head_td->m_td0TD0.f1Owner = OWNED_BY_NIC;
+       wmb(); /* second memory barrier */
+
        if (head_td->pTDInfo->byFlags & TD_FLAGS_NETIF_SKB)
                MACvTransmitAC0(priv->PortOffset);
        else
                MACvTransmit0(priv->PortOffset);
 
+       priv->iTDUsed[dma_idx]++;
+
        spin_unlock_irqrestore(&priv->lock, flags);
 
        return 0;
@@ -1416,9 +1417,16 @@ static void vnt_bss_info_changed(struct ieee80211_hw *hw,
 
        priv->current_aid = conf->aid;
 
-       if (changed & BSS_CHANGED_BSSID)
+       if (changed & BSS_CHANGED_BSSID) {
+               unsigned long flags;
+
+               spin_lock_irqsave(&priv->lock, flags);
+
                MACvWriteBSSIDAddress(priv->PortOffset, (u8 *)conf->bssid);
 
+               spin_unlock_irqrestore(&priv->lock, flags);
+       }
+
        if (changed & BSS_CHANGED_BASIC_RATES) {
                priv->basic_rates = conf->basic_rates;
 
@@ -1477,7 +1485,7 @@ static void vnt_bss_info_changed(struct ieee80211_hw *hw,
        if (changed & BSS_CHANGED_ASSOC && priv->op_mode != NL80211_IFTYPE_AP) {
                if (conf->assoc) {
                        CARDbUpdateTSF(priv, conf->beacon_rate->hw_value,
-                                      conf->sync_device_ts, conf->sync_tsf);
+                                      conf->sync_tsf);
 
                        CARDbSetBeaconPeriod(priv, conf->beacon_int);
 
index f6c2cf8590c4811471a88c9e82be1d4151a11618..5c589962a1e841ad66c41fe2057df51f18cdee31 100644 (file)
@@ -805,10 +805,18 @@ int vnt_tx_packet(struct vnt_private *priv, struct sk_buff *skb)
                vnt_schedule_command(priv, WLAN_CMD_SETPOWER);
        }
 
-       if (current_rate > RATE_11M)
-               pkt_type = priv->packet_type;
-       else
+       if (current_rate > RATE_11M) {
+               if (info->band == IEEE80211_BAND_5GHZ) {
+                       pkt_type = PK_TYPE_11A;
+               } else {
+                       if (tx_rate->flags & IEEE80211_TX_RC_USE_CTS_PROTECT)
+                               pkt_type = PK_TYPE_11GB;
+                       else
+                               pkt_type = PK_TYPE_11GA;
+               }
+       } else {
                pkt_type = PK_TYPE_11B;
+       }
 
        spin_lock_irqsave(&priv->lock, flags);
 
index 34871a628b11124e093231694b0b0fb14b62de80..74e6114ff18f9343e3012cf21c7faadbdf5c6f61 100644 (file)
@@ -230,7 +230,7 @@ int iscsit_access_np(struct iscsi_np *np, struct iscsi_portal_group *tpg)
         * Here we serialize access across the TIQN+TPG Tuple.
         */
        ret = down_interruptible(&tpg->np_login_sem);
-       if ((ret != 0) || signal_pending(current))
+       if (ret != 0)
                return -1;
 
        spin_lock_bh(&tpg->tpg_state_lock);
index 8ce94ff744e6ba1dfd131e5e59a3b18a75639bcb..70d799dfab03c2e3b616b06a635c2a63e8941fda 100644 (file)
@@ -346,6 +346,7 @@ static int iscsi_login_zero_tsih_s1(
        if (IS_ERR(sess->se_sess)) {
                iscsit_tx_login_rsp(conn, ISCSI_STATUS_CLS_TARGET_ERR,
                                ISCSI_LOGIN_STATUS_NO_RESOURCES);
+               kfree(sess->sess_ops);
                kfree(sess);
                return -ENOMEM;
        }
index e8a240818353bb54e2fdf9bb14cb194081c519c2..5e3295fe404d7cc93aae6354f2578bcbca55ee23 100644 (file)
@@ -161,10 +161,7 @@ struct iscsi_portal_group *iscsit_get_tpg_from_np(
 int iscsit_get_tpg(
        struct iscsi_portal_group *tpg)
 {
-       int ret;
-
-       ret = mutex_lock_interruptible(&tpg->tpg_access_lock);
-       return ((ret != 0) || signal_pending(current)) ? -1 : 0;
+       return mutex_lock_interruptible(&tpg->tpg_access_lock);
 }
 
 void iscsit_put_tpg(struct iscsi_portal_group *tpg)
index 75cbde1f7c5b6e34ea7060011c2aca817e4e55f2..4f8d4d459aa4f936a09438cc076fc998a75aa783 100644 (file)
@@ -704,7 +704,7 @@ target_alua_state_check(struct se_cmd *cmd)
 
        if (dev->se_hba->hba_flags & HBA_FLAGS_INTERNAL_USE)
                return 0;
-       if (dev->transport->transport_type == TRANSPORT_PLUGIN_PHBA_PDEV)
+       if (dev->transport->transport_flags & TRANSPORT_FLAG_PASSTHROUGH)
                return 0;
 
        if (!port)
@@ -2377,7 +2377,7 @@ ssize_t core_alua_store_secondary_write_metadata(
 
 int core_setup_alua(struct se_device *dev)
 {
-       if (dev->transport->transport_type != TRANSPORT_PLUGIN_PHBA_PDEV &&
+       if (!(dev->transport->transport_flags & TRANSPORT_FLAG_PASSTHROUGH) &&
            !(dev->se_hba->hba_flags & HBA_FLAGS_INTERNAL_USE)) {
                struct t10_alua_lu_gp_member *lu_gp_mem;
 
index ddaf76a4ac2aab3c00e70607a76c90a6cb308389..e7b0430a0575d0403dbb38b0fd4d41df1ccce79d 100644 (file)
@@ -212,10 +212,6 @@ static struct config_group *target_core_register_fabric(
 
        pr_debug("Target_Core_ConfigFS: REGISTER -> Allocated Fabric:"
                        " %s\n", tf->tf_group.cg_item.ci_name);
-       /*
-        * Setup tf_ops.tf_subsys pointer for usage with configfs_depend_item()
-        */
-       tf->tf_ops.tf_subsys = tf->tf_subsys;
        tf->tf_fabric = &tf->tf_group.cg_item;
        pr_debug("Target_Core_ConfigFS: REGISTER -> Set tf->tf_fabric"
                        " for %s\n", name);
@@ -291,10 +287,17 @@ static struct configfs_subsystem target_core_fabrics = {
        },
 };
 
-struct configfs_subsystem *target_core_subsystem[] = {
-       &target_core_fabrics,
-       NULL,
-};
+int target_depend_item(struct config_item *item)
+{
+       return configfs_depend_item(&target_core_fabrics, item);
+}
+EXPORT_SYMBOL(target_depend_item);
+
+void target_undepend_item(struct config_item *item)
+{
+       return configfs_undepend_item(&target_core_fabrics, item);
+}
+EXPORT_SYMBOL(target_undepend_item);
 
 /*##############################################################################
 // Start functions called by external Target Fabrics Modules
@@ -467,7 +470,6 @@ int target_register_template(const struct target_core_fabric_ops *fo)
         * struct target_fabric_configfs->tf_cit_tmpl
         */
        tf->tf_module = fo->module;
-       tf->tf_subsys = target_core_subsystem[0];
        snprintf(tf->tf_name, TARGET_FABRIC_NAME_SIZE, "%s", fo->name);
 
        tf->tf_ops = *fo;
@@ -809,7 +811,7 @@ static ssize_t target_core_dev_pr_show_attr_res_holder(struct se_device *dev,
 {
        int ret;
 
-       if (dev->transport->transport_type == TRANSPORT_PLUGIN_PHBA_PDEV)
+       if (dev->transport->transport_flags & TRANSPORT_FLAG_PASSTHROUGH)
                return sprintf(page, "Passthrough\n");
 
        spin_lock(&dev->dev_reservation_lock);
@@ -960,7 +962,7 @@ SE_DEV_PR_ATTR_RO(res_pr_type);
 static ssize_t target_core_dev_pr_show_attr_res_type(
                struct se_device *dev, char *page)
 {
-       if (dev->transport->transport_type == TRANSPORT_PLUGIN_PHBA_PDEV)
+       if (dev->transport->transport_flags & TRANSPORT_FLAG_PASSTHROUGH)
                return sprintf(page, "SPC_PASSTHROUGH\n");
        else if (dev->dev_reservation_flags & DRF_SPC2_RESERVATIONS)
                return sprintf(page, "SPC2_RESERVATIONS\n");
@@ -973,7 +975,7 @@ SE_DEV_PR_ATTR_RO(res_type);
 static ssize_t target_core_dev_pr_show_attr_res_aptpl_active(
                struct se_device *dev, char *page)
 {
-       if (dev->transport->transport_type == TRANSPORT_PLUGIN_PHBA_PDEV)
+       if (dev->transport->transport_flags & TRANSPORT_FLAG_PASSTHROUGH)
                return 0;
 
        return sprintf(page, "APTPL Bit Status: %s\n",
@@ -988,7 +990,7 @@ SE_DEV_PR_ATTR_RO(res_aptpl_active);
 static ssize_t target_core_dev_pr_show_attr_res_aptpl_metadata(
                struct se_device *dev, char *page)
 {
-       if (dev->transport->transport_type == TRANSPORT_PLUGIN_PHBA_PDEV)
+       if (dev->transport->transport_flags & TRANSPORT_FLAG_PASSTHROUGH)
                return 0;
 
        return sprintf(page, "Ready to process PR APTPL metadata..\n");
@@ -1035,7 +1037,7 @@ static ssize_t target_core_dev_pr_store_attr_res_aptpl_metadata(
        u16 port_rpti = 0, tpgt = 0;
        u8 type = 0, scope;
 
-       if (dev->transport->transport_type == TRANSPORT_PLUGIN_PHBA_PDEV)
+       if (dev->transport->transport_flags & TRANSPORT_FLAG_PASSTHROUGH)
                return 0;
        if (dev->dev_reservation_flags & DRF_SPC2_RESERVATIONS)
                return 0;
@@ -2870,7 +2872,7 @@ static int __init target_core_init_configfs(void)
 {
        struct config_group *target_cg, *hba_cg = NULL, *alua_cg = NULL;
        struct config_group *lu_gp_cg = NULL;
-       struct configfs_subsystem *subsys;
+       struct configfs_subsystem *subsys = &target_core_fabrics;
        struct t10_alua_lu_gp *lu_gp;
        int ret;
 
@@ -2878,7 +2880,6 @@ static int __init target_core_init_configfs(void)
                " Engine: %s on %s/%s on "UTS_RELEASE"\n",
                TARGET_CORE_VERSION, utsname()->sysname, utsname()->machine);
 
-       subsys = target_core_subsystem[0];
        config_group_init(&subsys->su_group);
        mutex_init(&subsys->su_mutex);
 
@@ -3008,13 +3009,10 @@ out_global:
 
 static void __exit target_core_exit_configfs(void)
 {
-       struct configfs_subsystem *subsys;
        struct config_group *hba_cg, *alua_cg, *lu_gp_cg;
        struct config_item *item;
        int i;
 
-       subsys = target_core_subsystem[0];
-
        lu_gp_cg = &alua_lu_gps_group;
        for (i = 0; lu_gp_cg->default_groups[i]; i++) {
                item = &lu_gp_cg->default_groups[i]->cg_item;
@@ -3045,8 +3043,8 @@ static void __exit target_core_exit_configfs(void)
         * We expect subsys->su_group.default_groups to be released
         * by configfs subsystem provider logic..
         */
-       configfs_unregister_subsystem(subsys);
-       kfree(subsys->su_group.default_groups);
+       configfs_unregister_subsystem(&target_core_fabrics);
+       kfree(target_core_fabrics.su_group.default_groups);
 
        core_alua_free_lu_gp(default_lu_gp);
        default_lu_gp = NULL;
index 7faa6aef9a4d5429cbf1d3810ebb181f7a911beb..ce5f768181ff6593a7afac365214c77b0f0aceab 100644 (file)
@@ -33,6 +33,7 @@
 #include <linux/kthread.h>
 #include <linux/in.h>
 #include <linux/export.h>
+#include <asm/unaligned.h>
 #include <net/sock.h>
 #include <net/tcp.h>
 #include <scsi/scsi.h>
@@ -527,7 +528,7 @@ static void core_export_port(
        list_add_tail(&port->sep_list, &dev->dev_sep_list);
        spin_unlock(&dev->se_port_lock);
 
-       if (dev->transport->transport_type != TRANSPORT_PLUGIN_PHBA_PDEV &&
+       if (!(dev->transport->transport_flags & TRANSPORT_FLAG_PASSTHROUGH) &&
            !(dev->se_hba->hba_flags & HBA_FLAGS_INTERNAL_USE)) {
                tg_pt_gp_mem = core_alua_allocate_tg_pt_gp_mem(port);
                if (IS_ERR(tg_pt_gp_mem) || !tg_pt_gp_mem) {
@@ -1603,7 +1604,7 @@ int target_configure_device(struct se_device *dev)
         * anything virtual (IBLOCK, FILEIO, RAMDISK), but not for TCM/pSCSI
         * passthrough because this is being provided by the backend LLD.
         */
-       if (dev->transport->transport_type != TRANSPORT_PLUGIN_PHBA_PDEV) {
+       if (!(dev->transport->transport_flags & TRANSPORT_FLAG_PASSTHROUGH)) {
                strncpy(&dev->t10_wwn.vendor[0], "LIO-ORG", 8);
                strncpy(&dev->t10_wwn.model[0],
                        dev->transport->inquiry_prod, 16);
@@ -1707,3 +1708,76 @@ void core_dev_release_virtual_lun0(void)
                target_free_device(g_lun0_dev);
        core_delete_hba(hba);
 }
+
+/*
+ * Common CDB parsing for kernel and user passthrough.
+ */
+sense_reason_t
+passthrough_parse_cdb(struct se_cmd *cmd,
+       sense_reason_t (*exec_cmd)(struct se_cmd *cmd))
+{
+       unsigned char *cdb = cmd->t_task_cdb;
+
+       /*
+        * Clear a lun set in the cdb if the initiator talking to use spoke
+        * and old standards version, as we can't assume the underlying device
+        * won't choke up on it.
+        */
+       switch (cdb[0]) {
+       case READ_10: /* SBC - RDProtect */
+       case READ_12: /* SBC - RDProtect */
+       case READ_16: /* SBC - RDProtect */
+       case SEND_DIAGNOSTIC: /* SPC - SELF-TEST Code */
+       case VERIFY: /* SBC - VRProtect */
+       case VERIFY_16: /* SBC - VRProtect */
+       case WRITE_VERIFY: /* SBC - VRProtect */
+       case WRITE_VERIFY_12: /* SBC - VRProtect */
+       case MAINTENANCE_IN: /* SPC - Parameter Data Format for SA RTPG */
+               break;
+       default:
+               cdb[1] &= 0x1f; /* clear logical unit number */
+               break;
+       }
+
+       /*
+        * For REPORT LUNS we always need to emulate the response, for everything
+        * else, pass it up.
+        */
+       if (cdb[0] == REPORT_LUNS) {
+               cmd->execute_cmd = spc_emulate_report_luns;
+               return TCM_NO_SENSE;
+       }
+
+       /* Set DATA_CDB flag for ops that should have it */
+       switch (cdb[0]) {
+       case READ_6:
+       case READ_10:
+       case READ_12:
+       case READ_16:
+       case WRITE_6:
+       case WRITE_10:
+       case WRITE_12:
+       case WRITE_16:
+       case WRITE_VERIFY:
+       case WRITE_VERIFY_12:
+       case 0x8e: /* WRITE_VERIFY_16 */
+       case COMPARE_AND_WRITE:
+       case XDWRITEREAD_10:
+               cmd->se_cmd_flags |= SCF_SCSI_DATA_CDB;
+               break;
+       case VARIABLE_LENGTH_CMD:
+               switch (get_unaligned_be16(&cdb[8])) {
+               case READ_32:
+               case WRITE_32:
+               case 0x0c: /* WRITE_VERIFY_32 */
+               case XDWRITEREAD_32:
+                       cmd->se_cmd_flags |= SCF_SCSI_DATA_CDB;
+                       break;
+               }
+       }
+
+       cmd->execute_cmd = exec_cmd;
+
+       return TCM_NO_SENSE;
+}
+EXPORT_SYMBOL(passthrough_parse_cdb);
index f7e6e51aed3614aa35e8a58c0bb1d2cfcc462141..3f27bfd816d87201c5f3cec3ad7857ead488191b 100644 (file)
@@ -958,7 +958,6 @@ static struct se_subsystem_api fileio_template = {
        .inquiry_prod           = "FILEIO",
        .inquiry_rev            = FD_VERSION,
        .owner                  = THIS_MODULE,
-       .transport_type         = TRANSPORT_PLUGIN_VHBA_PDEV,
        .attach_hba             = fd_attach_hba,
        .detach_hba             = fd_detach_hba,
        .alloc_device           = fd_alloc_device,
index 1b7947c2510fc8c65872127738c83ccbb34cf6a3..8c965683789f9e141233edac76593e156a58bd2f 100644 (file)
@@ -904,7 +904,6 @@ static struct se_subsystem_api iblock_template = {
        .inquiry_prod           = "IBLOCK",
        .inquiry_rev            = IBLOCK_VERSION,
        .owner                  = THIS_MODULE,
-       .transport_type         = TRANSPORT_PLUGIN_VHBA_PDEV,
        .attach_hba             = iblock_attach_hba,
        .detach_hba             = iblock_detach_hba,
        .alloc_device           = iblock_alloc_device,
index 874a9bc988d807a615a9ed7516041bfe54176c4b..68bd7f5d9f73cf6feacd2dfefb951db99dd21c4f 100644 (file)
@@ -4,9 +4,6 @@
 /* target_core_alua.c */
 extern struct t10_alua_lu_gp *default_lu_gp;
 
-/* target_core_configfs.c */
-extern struct configfs_subsystem *target_core_subsystem[];
-
 /* target_core_device.c */
 extern struct mutex g_device_mutex;
 extern struct list_head g_device_list;
index c1aa9655e96ec13881bdee2040254887fde0e903..a15411c79ae99649041c216439e938f52a7c071a 100644 (file)
@@ -1367,41 +1367,26 @@ void core_scsi3_free_all_registrations(
 
 static int core_scsi3_tpg_depend_item(struct se_portal_group *tpg)
 {
-       return configfs_depend_item(tpg->se_tpg_tfo->tf_subsys,
-                       &tpg->tpg_group.cg_item);
+       return target_depend_item(&tpg->tpg_group.cg_item);
 }
 
 static void core_scsi3_tpg_undepend_item(struct se_portal_group *tpg)
 {
-       configfs_undepend_item(tpg->se_tpg_tfo->tf_subsys,
-                       &tpg->tpg_group.cg_item);
-
+       target_undepend_item(&tpg->tpg_group.cg_item);
        atomic_dec_mb(&tpg->tpg_pr_ref_count);
 }
 
 static int core_scsi3_nodeacl_depend_item(struct se_node_acl *nacl)
 {
-       struct se_portal_group *tpg = nacl->se_tpg;
-
        if (nacl->dynamic_node_acl)
                return 0;
-
-       return configfs_depend_item(tpg->se_tpg_tfo->tf_subsys,
-                       &nacl->acl_group.cg_item);
+       return target_depend_item(&nacl->acl_group.cg_item);
 }
 
 static void core_scsi3_nodeacl_undepend_item(struct se_node_acl *nacl)
 {
-       struct se_portal_group *tpg = nacl->se_tpg;
-
-       if (nacl->dynamic_node_acl) {
-               atomic_dec_mb(&nacl->acl_pr_ref_count);
-               return;
-       }
-
-       configfs_undepend_item(tpg->se_tpg_tfo->tf_subsys,
-                       &nacl->acl_group.cg_item);
-
+       if (!nacl->dynamic_node_acl)
+               target_undepend_item(&nacl->acl_group.cg_item);
        atomic_dec_mb(&nacl->acl_pr_ref_count);
 }
 
@@ -1419,8 +1404,7 @@ static int core_scsi3_lunacl_depend_item(struct se_dev_entry *se_deve)
        nacl = lun_acl->se_lun_nacl;
        tpg = nacl->se_tpg;
 
-       return configfs_depend_item(tpg->se_tpg_tfo->tf_subsys,
-                       &lun_acl->se_lun_group.cg_item);
+       return target_depend_item(&lun_acl->se_lun_group.cg_item);
 }
 
 static void core_scsi3_lunacl_undepend_item(struct se_dev_entry *se_deve)
@@ -1438,9 +1422,7 @@ static void core_scsi3_lunacl_undepend_item(struct se_dev_entry *se_deve)
        nacl = lun_acl->se_lun_nacl;
        tpg = nacl->se_tpg;
 
-       configfs_undepend_item(tpg->se_tpg_tfo->tf_subsys,
-                       &lun_acl->se_lun_group.cg_item);
-
+       target_undepend_item(&lun_acl->se_lun_group.cg_item);
        atomic_dec_mb(&se_deve->pr_ref_count);
 }
 
@@ -4111,7 +4093,7 @@ target_check_reservation(struct se_cmd *cmd)
                return 0;
        if (dev->se_hba->hba_flags & HBA_FLAGS_INTERNAL_USE)
                return 0;
-       if (dev->transport->transport_type == TRANSPORT_PLUGIN_PHBA_PDEV)
+       if (dev->transport->transport_flags & TRANSPORT_FLAG_PASSTHROUGH)
                return 0;
 
        spin_lock(&dev->dev_reservation_lock);
index f6c954c4635f5dab27ac24ea117dd284561c836a..ecc5eaef13d6c38956a213a784ae66e1b4e0411b 100644 (file)
@@ -521,6 +521,7 @@ static int pscsi_configure_device(struct se_device *dev)
                                        " pdv_host_id: %d\n", pdv->pdv_host_id);
                                return -EINVAL;
                        }
+                       pdv->pdv_lld_host = sh;
                }
        } else {
                if (phv->phv_mode == PHV_VIRTUAL_HOST_ID) {
@@ -603,6 +604,8 @@ static void pscsi_free_device(struct se_device *dev)
                if ((phv->phv_mode == PHV_LLD_SCSI_HOST_NO) &&
                    (phv->phv_lld_host != NULL))
                        scsi_host_put(phv->phv_lld_host);
+               else if (pdv->pdv_lld_host)
+                       scsi_host_put(pdv->pdv_lld_host);
 
                if ((sd->type == TYPE_DISK) || (sd->type == TYPE_ROM))
                        scsi_device_put(sd);
@@ -970,64 +973,13 @@ fail:
        return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE;
 }
 
-/*
- * Clear a lun set in the cdb if the initiator talking to use spoke
- * and old standards version, as we can't assume the underlying device
- * won't choke up on it.
- */
-static inline void pscsi_clear_cdb_lun(unsigned char *cdb)
-{
-       switch (cdb[0]) {
-       case READ_10: /* SBC - RDProtect */
-       case READ_12: /* SBC - RDProtect */
-       case READ_16: /* SBC - RDProtect */
-       case SEND_DIAGNOSTIC: /* SPC - SELF-TEST Code */
-       case VERIFY: /* SBC - VRProtect */
-       case VERIFY_16: /* SBC - VRProtect */
-       case WRITE_VERIFY: /* SBC - VRProtect */
-       case WRITE_VERIFY_12: /* SBC - VRProtect */
-       case MAINTENANCE_IN: /* SPC - Parameter Data Format for SA RTPG */
-               break;
-       default:
-               cdb[1] &= 0x1f; /* clear logical unit number */
-               break;
-       }
-}
-
 static sense_reason_t
 pscsi_parse_cdb(struct se_cmd *cmd)
 {
-       unsigned char *cdb = cmd->t_task_cdb;
-
        if (cmd->se_cmd_flags & SCF_BIDI)
                return TCM_UNSUPPORTED_SCSI_OPCODE;
 
-       pscsi_clear_cdb_lun(cdb);
-
-       /*
-        * For REPORT LUNS we always need to emulate the response, for everything
-        * else the default for pSCSI is to pass the command to the underlying
-        * LLD / physical hardware.
-        */
-       switch (cdb[0]) {
-       case REPORT_LUNS:
-               cmd->execute_cmd = spc_emulate_report_luns;
-               return 0;
-       case READ_6:
-       case READ_10:
-       case READ_12:
-       case READ_16:
-       case WRITE_6:
-       case WRITE_10:
-       case WRITE_12:
-       case WRITE_16:
-       case WRITE_VERIFY:
-               cmd->se_cmd_flags |= SCF_SCSI_DATA_CDB;
-               /* FALLTHROUGH*/
-       default:
-               cmd->execute_cmd = pscsi_execute_cmd;
-               return 0;
-       }
+       return passthrough_parse_cdb(cmd, pscsi_execute_cmd);
 }
 
 static sense_reason_t
@@ -1189,7 +1141,7 @@ static struct configfs_attribute *pscsi_backend_dev_attrs[] = {
 static struct se_subsystem_api pscsi_template = {
        .name                   = "pscsi",
        .owner                  = THIS_MODULE,
-       .transport_type         = TRANSPORT_PLUGIN_PHBA_PDEV,
+       .transport_flags        = TRANSPORT_FLAG_PASSTHROUGH,
        .attach_hba             = pscsi_attach_hba,
        .detach_hba             = pscsi_detach_hba,
        .pmode_enable_hba       = pscsi_pmode_enable_hba,
index 1bd757dff8eee3806cae1d3da6ce33804e5deb17..820d3052b775caf438912d703402ebb4172d7f31 100644 (file)
@@ -45,6 +45,7 @@ struct pscsi_dev_virt {
        int     pdv_lun_id;
        struct block_device *pdv_bd;
        struct scsi_device *pdv_sd;
+       struct Scsi_Host *pdv_lld_host;
 } ____cacheline_aligned;
 
 typedef enum phv_modes {
index a263bf5fab8d4538384f557aef1a3df7df3d9792..d16489b6a1a4767ef4a8ba9445998a7bff2845d8 100644 (file)
@@ -733,7 +733,6 @@ static struct se_subsystem_api rd_mcp_template = {
        .name                   = "rd_mcp",
        .inquiry_prod           = "RAMDISK-MCP",
        .inquiry_rev            = RD_MCP_VERSION,
-       .transport_type         = TRANSPORT_PLUGIN_VHBA_VDEV,
        .attach_hba             = rd_attach_hba,
        .detach_hba             = rd_detach_hba,
        .alloc_device           = rd_alloc_device,
index 8855781ac653026aa0b513340b150e5f33f05f28..733824e3825f4845e9035b9f00a7d553b9d59d6e 100644 (file)
@@ -568,7 +568,7 @@ sbc_compare_and_write(struct se_cmd *cmd)
         * comparision using SGLs at cmd->t_bidi_data_sg..
         */
        rc = down_interruptible(&dev->caw_sem);
-       if ((rc != 0) || signal_pending(current)) {
+       if (rc != 0) {
                cmd->transport_complete_callback = NULL;
                return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE;
        }
index 3fe5cb240b6f6a5b4c8a3fb42396b77dd5701f74..675f2d9d1f14c69142d63179afa38e5b74255243 100644 (file)
@@ -1196,7 +1196,7 @@ transport_check_alloc_task_attr(struct se_cmd *cmd)
         * Check if SAM Task Attribute emulation is enabled for this
         * struct se_device storage object
         */
-       if (dev->transport->transport_type == TRANSPORT_PLUGIN_PHBA_PDEV)
+       if (dev->transport->transport_flags & TRANSPORT_FLAG_PASSTHROUGH)
                return 0;
 
        if (cmd->sam_task_attr == TCM_ACA_TAG) {
@@ -1770,7 +1770,7 @@ static int target_write_prot_action(struct se_cmd *cmd)
                                                   sectors, 0, NULL, 0);
                if (unlikely(cmd->pi_err)) {
                        spin_lock_irq(&cmd->t_state_lock);
-                       cmd->transport_state &= ~CMD_T_BUSY|CMD_T_SENT;
+                       cmd->transport_state &= ~(CMD_T_BUSY|CMD_T_SENT);
                        spin_unlock_irq(&cmd->t_state_lock);
                        transport_generic_request_failure(cmd, cmd->pi_err);
                        return -1;
@@ -1787,7 +1787,7 @@ static bool target_handle_task_attr(struct se_cmd *cmd)
 {
        struct se_device *dev = cmd->se_dev;
 
-       if (dev->transport->transport_type == TRANSPORT_PLUGIN_PHBA_PDEV)
+       if (dev->transport->transport_flags & TRANSPORT_FLAG_PASSTHROUGH)
                return false;
 
        /*
@@ -1868,7 +1868,7 @@ void target_execute_cmd(struct se_cmd *cmd)
 
        if (target_handle_task_attr(cmd)) {
                spin_lock_irq(&cmd->t_state_lock);
-               cmd->transport_state &= ~CMD_T_BUSY|CMD_T_SENT;
+               cmd->transport_state &= ~(CMD_T_BUSY | CMD_T_SENT);
                spin_unlock_irq(&cmd->t_state_lock);
                return;
        }
@@ -1912,7 +1912,7 @@ static void transport_complete_task_attr(struct se_cmd *cmd)
 {
        struct se_device *dev = cmd->se_dev;
 
-       if (dev->transport->transport_type == TRANSPORT_PLUGIN_PHBA_PDEV)
+       if (dev->transport->transport_flags & TRANSPORT_FLAG_PASSTHROUGH)
                return;
 
        if (cmd->sam_task_attr == TCM_SIMPLE_TAG) {
@@ -1957,8 +1957,7 @@ static void transport_complete_qf(struct se_cmd *cmd)
        case DMA_TO_DEVICE:
                if (cmd->se_cmd_flags & SCF_BIDI) {
                        ret = cmd->se_tfo->queue_data_in(cmd);
-                       if (ret < 0)
-                               break;
+                       break;
                }
                /* Fall through for DMA_TO_DEVICE */
        case DMA_NONE:
index dbc872a6c9816e95211f5b93bb9f623233d249ba..07d2996d8c1fe922334ee57dfe4d27fd9d7685f8 100644 (file)
@@ -71,13 +71,6 @@ struct tcmu_hba {
        u32 host_id;
 };
 
-/* User wants all cmds or just some */
-enum passthru_level {
-       TCMU_PASS_ALL = 0,
-       TCMU_PASS_IO,
-       TCMU_PASS_INVALID,
-};
-
 #define TCMU_CONFIG_LEN 256
 
 struct tcmu_dev {
@@ -89,7 +82,6 @@ struct tcmu_dev {
 #define TCMU_DEV_BIT_OPEN 0
 #define TCMU_DEV_BIT_BROKEN 1
        unsigned long flags;
-       enum passthru_level pass_level;
 
        struct uio_info uio_info;
 
@@ -683,8 +675,6 @@ static struct se_device *tcmu_alloc_device(struct se_hba *hba, const char *name)
        setup_timer(&udev->timeout, tcmu_device_timedout,
                (unsigned long)udev);
 
-       udev->pass_level = TCMU_PASS_ALL;
-
        return &udev->se_dev;
 }
 
@@ -948,13 +938,13 @@ static void tcmu_free_device(struct se_device *dev)
 }
 
 enum {
-       Opt_dev_config, Opt_dev_size, Opt_err, Opt_pass_level,
+       Opt_dev_config, Opt_dev_size, Opt_hw_block_size, Opt_err,
 };
 
 static match_table_t tokens = {
        {Opt_dev_config, "dev_config=%s"},
        {Opt_dev_size, "dev_size=%u"},
-       {Opt_pass_level, "pass_level=%u"},
+       {Opt_hw_block_size, "hw_block_size=%u"},
        {Opt_err, NULL}
 };
 
@@ -965,7 +955,7 @@ static ssize_t tcmu_set_configfs_dev_params(struct se_device *dev,
        char *orig, *ptr, *opts, *arg_p;
        substring_t args[MAX_OPT_ARGS];
        int ret = 0, token;
-       int arg;
+       unsigned long tmp_ul;
 
        opts = kstrdup(page, GFP_KERNEL);
        if (!opts)
@@ -998,15 +988,23 @@ static ssize_t tcmu_set_configfs_dev_params(struct se_device *dev,
                        if (ret < 0)
                                pr_err("kstrtoul() failed for dev_size=\n");
                        break;
-               case Opt_pass_level:
-                       match_int(args, &arg);
-                       if (arg >= TCMU_PASS_INVALID) {
-                               pr_warn("TCMU: Invalid pass_level: %d\n", arg);
+               case Opt_hw_block_size:
+                       arg_p = match_strdup(&args[0]);
+                       if (!arg_p) {
+                               ret = -ENOMEM;
                                break;
                        }
-
-                       pr_debug("TCMU: Setting pass_level to %d\n", arg);
-                       udev->pass_level = arg;
+                       ret = kstrtoul(arg_p, 0, &tmp_ul);
+                       kfree(arg_p);
+                       if (ret < 0) {
+                               pr_err("kstrtoul() failed for hw_block_size=\n");
+                               break;
+                       }
+                       if (!tmp_ul) {
+                               pr_err("hw_block_size must be nonzero\n");
+                               break;
+                       }
+                       dev->dev_attrib.hw_block_size = tmp_ul;
                        break;
                default:
                        break;
@@ -1024,8 +1022,7 @@ static ssize_t tcmu_show_configfs_dev_params(struct se_device *dev, char *b)
 
        bl = sprintf(b + bl, "Config: %s ",
                     udev->dev_config[0] ? udev->dev_config : "NULL");
-       bl += sprintf(b + bl, "Size: %zu PassLevel: %u\n",
-                     udev->dev_size, udev->pass_level);
+       bl += sprintf(b + bl, "Size: %zu\n", udev->dev_size);
 
        return bl;
 }
@@ -1038,20 +1035,6 @@ static sector_t tcmu_get_blocks(struct se_device *dev)
                       dev->dev_attrib.block_size);
 }
 
-static sense_reason_t
-tcmu_execute_rw(struct se_cmd *se_cmd, struct scatterlist *sgl, u32 sgl_nents,
-               enum dma_data_direction data_direction)
-{
-       int ret;
-
-       ret = tcmu_queue_cmd(se_cmd);
-
-       if (ret != 0)
-               return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE;
-       else
-               return TCM_NO_SENSE;
-}
-
 static sense_reason_t
 tcmu_pass_op(struct se_cmd *se_cmd)
 {
@@ -1063,91 +1046,29 @@ tcmu_pass_op(struct se_cmd *se_cmd)
                return TCM_NO_SENSE;
 }
 
-static struct sbc_ops tcmu_sbc_ops = {
-       .execute_rw = tcmu_execute_rw,
-       .execute_sync_cache     = tcmu_pass_op,
-       .execute_write_same     = tcmu_pass_op,
-       .execute_write_same_unmap = tcmu_pass_op,
-       .execute_unmap          = tcmu_pass_op,
-};
-
 static sense_reason_t
 tcmu_parse_cdb(struct se_cmd *cmd)
 {
-       unsigned char *cdb = cmd->t_task_cdb;
-       struct tcmu_dev *udev = TCMU_DEV(cmd->se_dev);
-       sense_reason_t ret;
-
-       switch (udev->pass_level) {
-       case TCMU_PASS_ALL:
-               /* We're just like pscsi, then */
-               /*
-                * For REPORT LUNS we always need to emulate the response, for everything
-                * else, pass it up.
-                */
-               switch (cdb[0]) {
-               case REPORT_LUNS:
-                       cmd->execute_cmd = spc_emulate_report_luns;
-                       break;
-               case READ_6:
-               case READ_10:
-               case READ_12:
-               case READ_16:
-               case WRITE_6:
-               case WRITE_10:
-               case WRITE_12:
-               case WRITE_16:
-               case WRITE_VERIFY:
-                       cmd->se_cmd_flags |= SCF_SCSI_DATA_CDB;
-                       /* FALLTHROUGH */
-               default:
-                       cmd->execute_cmd = tcmu_pass_op;
-               }
-               ret = TCM_NO_SENSE;
-               break;
-       case TCMU_PASS_IO:
-               ret = sbc_parse_cdb(cmd, &tcmu_sbc_ops);
-               break;
-       default:
-               pr_err("Unknown tcm-user pass level %d\n", udev->pass_level);
-               ret = TCM_CHECK_CONDITION_ABORT_CMD;
-       }
-
-       return ret;
+       return passthrough_parse_cdb(cmd, tcmu_pass_op);
 }
 
-DEF_TB_DEFAULT_ATTRIBS(tcmu);
+DEF_TB_DEV_ATTRIB_RO(tcmu, hw_pi_prot_type);
+TB_DEV_ATTR_RO(tcmu, hw_pi_prot_type);
+
+DEF_TB_DEV_ATTRIB_RO(tcmu, hw_block_size);
+TB_DEV_ATTR_RO(tcmu, hw_block_size);
+
+DEF_TB_DEV_ATTRIB_RO(tcmu, hw_max_sectors);
+TB_DEV_ATTR_RO(tcmu, hw_max_sectors);
+
+DEF_TB_DEV_ATTRIB_RO(tcmu, hw_queue_depth);
+TB_DEV_ATTR_RO(tcmu, hw_queue_depth);
 
 static struct configfs_attribute *tcmu_backend_dev_attrs[] = {
-       &tcmu_dev_attrib_emulate_model_alias.attr,
-       &tcmu_dev_attrib_emulate_dpo.attr,
-       &tcmu_dev_attrib_emulate_fua_write.attr,
-       &tcmu_dev_attrib_emulate_fua_read.attr,
-       &tcmu_dev_attrib_emulate_write_cache.attr,
-       &tcmu_dev_attrib_emulate_ua_intlck_ctrl.attr,
-       &tcmu_dev_attrib_emulate_tas.attr,
-       &tcmu_dev_attrib_emulate_tpu.attr,
-       &tcmu_dev_attrib_emulate_tpws.attr,
-       &tcmu_dev_attrib_emulate_caw.attr,
-       &tcmu_dev_attrib_emulate_3pc.attr,
-       &tcmu_dev_attrib_pi_prot_type.attr,
        &tcmu_dev_attrib_hw_pi_prot_type.attr,
-       &tcmu_dev_attrib_pi_prot_format.attr,
-       &tcmu_dev_attrib_enforce_pr_isids.attr,
-       &tcmu_dev_attrib_is_nonrot.attr,
-       &tcmu_dev_attrib_emulate_rest_reord.attr,
-       &tcmu_dev_attrib_force_pr_aptpl.attr,
        &tcmu_dev_attrib_hw_block_size.attr,
-       &tcmu_dev_attrib_block_size.attr,
        &tcmu_dev_attrib_hw_max_sectors.attr,
-       &tcmu_dev_attrib_optimal_sectors.attr,
        &tcmu_dev_attrib_hw_queue_depth.attr,
-       &tcmu_dev_attrib_queue_depth.attr,
-       &tcmu_dev_attrib_max_unmap_lba_count.attr,
-       &tcmu_dev_attrib_max_unmap_block_desc_count.attr,
-       &tcmu_dev_attrib_unmap_granularity.attr,
-       &tcmu_dev_attrib_unmap_granularity_alignment.attr,
-       &tcmu_dev_attrib_max_write_same_len.attr,
        NULL,
 };
 
@@ -1156,7 +1077,7 @@ static struct se_subsystem_api tcmu_template = {
        .inquiry_prod           = "USER",
        .inquiry_rev            = TCMU_VERSION,
        .owner                  = THIS_MODULE,
-       .transport_type         = TRANSPORT_PLUGIN_VHBA_PDEV,
+       .transport_flags        = TRANSPORT_FLAG_PASSTHROUGH,
        .attach_hba             = tcmu_attach_hba,
        .detach_hba             = tcmu_detach_hba,
        .alloc_device           = tcmu_alloc_device,
index a600ff15dcfd1674140170b0808d494db64333ea..8fd680ac941bde49cd7803134da5beb77c7092b0 100644 (file)
@@ -58,7 +58,6 @@ static int target_xcopy_locate_se_dev_e4(struct se_cmd *se_cmd, struct xcopy_op
                                        bool src)
 {
        struct se_device *se_dev;
-       struct configfs_subsystem *subsys = target_core_subsystem[0];
        unsigned char tmp_dev_wwn[XCOPY_NAA_IEEE_REGEX_LEN], *dev_wwn;
        int rc;
 
@@ -90,8 +89,7 @@ static int target_xcopy_locate_se_dev_e4(struct se_cmd *se_cmd, struct xcopy_op
                                " se_dev\n", xop->src_dev);
                }
 
-               rc = configfs_depend_item(subsys,
-                               &se_dev->dev_group.cg_item);
+               rc = target_depend_item(&se_dev->dev_group.cg_item);
                if (rc != 0) {
                        pr_err("configfs_depend_item attempt failed:"
                                " %d for se_dev: %p\n", rc, se_dev);
@@ -99,8 +97,8 @@ static int target_xcopy_locate_se_dev_e4(struct se_cmd *se_cmd, struct xcopy_op
                        return rc;
                }
 
-               pr_debug("Called configfs_depend_item for subsys: %p se_dev: %p"
-                       " se_dev->se_dev_group: %p\n", subsys, se_dev,
+               pr_debug("Called configfs_depend_item for se_dev: %p"
+                       " se_dev->se_dev_group: %p\n", se_dev,
                        &se_dev->dev_group);
 
                mutex_unlock(&g_device_mutex);
@@ -373,7 +371,6 @@ static int xcopy_pt_get_cmd_state(struct se_cmd *se_cmd)
 
 static void xcopy_pt_undepend_remotedev(struct xcopy_op *xop)
 {
-       struct configfs_subsystem *subsys = target_core_subsystem[0];
        struct se_device *remote_dev;
 
        if (xop->op_origin == XCOL_SOURCE_RECV_OP)
@@ -381,11 +378,11 @@ static void xcopy_pt_undepend_remotedev(struct xcopy_op *xop)
        else
                remote_dev = xop->src_dev;
 
-       pr_debug("Calling configfs_undepend_item for subsys: %p"
+       pr_debug("Calling configfs_undepend_item for"
                  " remote_dev: %p remote_dev->dev_group: %p\n",
-                 subsys, remote_dev, &remote_dev->dev_group.cg_item);
+                 remote_dev, &remote_dev->dev_group.cg_item);
 
-       configfs_undepend_item(subsys, &remote_dev->dev_group.cg_item);
+       target_undepend_item(&remote_dev->dev_group.cg_item);
 }
 
 static void xcopy_pt_release_cmd(struct se_cmd *se_cmd)
index c2556cf5186bc75b71870ed6a304fda430b8521b..01255fd65135949ce78b7f94fde7bccc196ac75c 100644 (file)
@@ -224,9 +224,9 @@ static const struct armada_thermal_data armada380_data = {
        .is_valid_shift = 10,
        .temp_shift = 0,
        .temp_mask = 0x3ff,
-       .coef_b = 1169498786UL,
-       .coef_m = 2000000UL,
-       .coef_div = 4289,
+       .coef_b = 2931108200UL,
+       .coef_m = 5000000UL,
+       .coef_div = 10502,
        .inverted = true,
 };
 
index 12623bc02f46679674d9bd1c3f1574fc21b57c37..725718e97a0bc86f8d69d3fc112fba7670543402 100644 (file)
@@ -206,51 +206,57 @@ static void find_target_mwait(void)
 
 }
 
+struct pkg_cstate_info {
+       bool skip;
+       int msr_index;
+       int cstate_id;
+};
+
+#define PKG_CSTATE_INIT(id) {                          \
+               .msr_index = MSR_PKG_C##id##_RESIDENCY, \
+               .cstate_id = id                         \
+                       }
+
+static struct pkg_cstate_info pkg_cstates[] = {
+       PKG_CSTATE_INIT(2),
+       PKG_CSTATE_INIT(3),
+       PKG_CSTATE_INIT(6),
+       PKG_CSTATE_INIT(7),
+       PKG_CSTATE_INIT(8),
+       PKG_CSTATE_INIT(9),
+       PKG_CSTATE_INIT(10),
+       {NULL},
+};
+
 static bool has_pkg_state_counter(void)
 {
-       u64 tmp;
-       return !rdmsrl_safe(MSR_PKG_C2_RESIDENCY, &tmp) ||
-              !rdmsrl_safe(MSR_PKG_C3_RESIDENCY, &tmp) ||
-              !rdmsrl_safe(MSR_PKG_C6_RESIDENCY, &tmp) ||
-              !rdmsrl_safe(MSR_PKG_C7_RESIDENCY, &tmp);
+       u64 val;
+       struct pkg_cstate_info *info = pkg_cstates;
+
+       /* check if any one of the counter msrs exists */
+       while (info->msr_index) {
+               if (!rdmsrl_safe(info->msr_index, &val))
+                       return true;
+               info++;
+       }
+
+       return false;
 }
 
 static u64 pkg_state_counter(void)
 {
        u64 val;
        u64 count = 0;
-
-       static bool skip_c2;
-       static bool skip_c3;
-       static bool skip_c6;
-       static bool skip_c7;
-
-       if (!skip_c2) {
-               if (!rdmsrl_safe(MSR_PKG_C2_RESIDENCY, &val))
-                       count += val;
-               else
-                       skip_c2 = true;
-       }
-
-       if (!skip_c3) {
-               if (!rdmsrl_safe(MSR_PKG_C3_RESIDENCY, &val))
-                       count += val;
-               else
-                       skip_c3 = true;
-       }
-
-       if (!skip_c6) {
-               if (!rdmsrl_safe(MSR_PKG_C6_RESIDENCY, &val))
-                       count += val;
-               else
-                       skip_c6 = true;
-       }
-
-       if (!skip_c7) {
-               if (!rdmsrl_safe(MSR_PKG_C7_RESIDENCY, &val))
-                       count += val;
-               else
-                       skip_c7 = true;
+       struct pkg_cstate_info *info = pkg_cstates;
+
+       while (info->msr_index) {
+               if (!info->skip) {
+                       if (!rdmsrl_safe(info->msr_index, &val))
+                               count += val;
+                       else
+                               info->skip = true;
+               }
+               info++;
        }
 
        return count;
@@ -667,7 +673,7 @@ static struct thermal_cooling_device_ops powerclamp_cooling_ops = {
 };
 
 /* runs on Nehalem and later */
-static const struct x86_cpu_id intel_powerclamp_ids[] = {
+static const struct x86_cpu_id intel_powerclamp_ids[] __initconst = {
        { X86_VENDOR_INTEL, 6, 0x1a},
        { X86_VENDOR_INTEL, 6, 0x1c},
        { X86_VENDOR_INTEL, 6, 0x1e},
@@ -689,12 +695,13 @@ static const struct x86_cpu_id intel_powerclamp_ids[] = {
        { X86_VENDOR_INTEL, 6, 0x46},
        { X86_VENDOR_INTEL, 6, 0x4c},
        { X86_VENDOR_INTEL, 6, 0x4d},
+       { X86_VENDOR_INTEL, 6, 0x4f},
        { X86_VENDOR_INTEL, 6, 0x56},
        {}
 };
 MODULE_DEVICE_TABLE(x86cpu, intel_powerclamp_ids);
 
-static int powerclamp_probe(void)
+static int __init powerclamp_probe(void)
 {
        if (!x86_match_cpu(intel_powerclamp_ids)) {
                pr_err("Intel powerclamp does not run on family %d model %d\n",
@@ -760,7 +767,7 @@ file_error:
        debugfs_remove_recursive(debug_dir);
 }
 
-static int powerclamp_init(void)
+static int __init powerclamp_init(void)
 {
        int retval;
        int bitmap_size;
@@ -809,7 +816,7 @@ exit_free:
 }
 module_init(powerclamp_init);
 
-static void powerclamp_exit(void)
+static void __exit powerclamp_exit(void)
 {
        unregister_hotcpu_notifier(&powerclamp_cpu_notifier);
        end_power_clamp();
index 3aa46ac7cdbc33765a90279da09fd84507a09d6c..cd8f5f93b42c45aa4cde0f8c4aa346836006f6da 100644 (file)
@@ -529,7 +529,7 @@ static int rockchip_thermal_probe(struct platform_device *pdev)
 
        thermal->pclk = devm_clk_get(&pdev->dev, "apb_pclk");
        if (IS_ERR(thermal->pclk)) {
-               error = PTR_ERR(thermal->clk);
+               error = PTR_ERR(thermal->pclk);
                dev_err(&pdev->dev, "failed to get apb_pclk clock: %d\n",
                        error);
                return error;
index 0531c752fbbb6680c40e939ad2a14fdc1830f357..8e391812e50377664f079cb83f61c380b16e6d93 100644 (file)
@@ -103,7 +103,7 @@ static inline int of_thermal_get_ntrips(struct thermal_zone_device *tz)
 static inline bool of_thermal_is_trip_valid(struct thermal_zone_device *tz,
                                            int trip)
 {
-       return 0;
+       return false;
 }
 static inline const struct thermal_trip *
 of_thermal_get_trip_points(struct thermal_zone_device *tz)
index a4929272074f3f8a161ff7978289af475560b9eb..58b5c6694cd4361472b34fa941890e5121d3dba9 100644 (file)
@@ -420,7 +420,8 @@ const struct ti_bandgap_data dra752_data = {
                        TI_BANDGAP_FEATURE_FREEZE_BIT |
                        TI_BANDGAP_FEATURE_TALERT |
                        TI_BANDGAP_FEATURE_COUNTER_DELAY |
-                       TI_BANDGAP_FEATURE_HISTORY_BUFFER,
+                       TI_BANDGAP_FEATURE_HISTORY_BUFFER |
+                       TI_BANDGAP_FEATURE_ERRATA_814,
        .fclock_name = "l3instr_ts_gclk_div",
        .div_ck_name = "l3instr_ts_gclk_div",
        .conv_table = dra752_adc_to_temp,
index eff0c80fd4af50110cde6b4dc5cba3500787e91e..79ff70c446ba195ef893125b377567ff4ac2e58b 100644 (file)
@@ -319,7 +319,8 @@ const struct ti_bandgap_data omap5430_data = {
                        TI_BANDGAP_FEATURE_FREEZE_BIT |
                        TI_BANDGAP_FEATURE_TALERT |
                        TI_BANDGAP_FEATURE_COUNTER_DELAY |
-                       TI_BANDGAP_FEATURE_HISTORY_BUFFER,
+                       TI_BANDGAP_FEATURE_HISTORY_BUFFER |
+                       TI_BANDGAP_FEATURE_ERRATA_813,
        .fclock_name = "l3instr_ts_gclk_div",
        .div_ck_name = "l3instr_ts_gclk_div",
        .conv_table = omap5430_adc_to_temp,
index 62a5d449c38805019db7d554e6c0f7f43d215341..bc14dc874594e4d9fd37a68874bb6adb6eb4b562 100644 (file)
@@ -118,6 +118,37 @@ exit:
        return ret;
 }
 
+/**
+ * ti_errata814_bandgap_read_temp() - helper function to read dra7 sensor temperature
+ * @bgp: pointer to ti_bandgap structure
+ * @reg: desired register (offset) to be read
+ *
+ * Function to read dra7 bandgap sensor temperature. This is done separately
+ * so as to workaround the errata "Bandgap Temperature read Dtemp can be
+ * corrupted" - Errata ID: i814".
+ * Read accesses to registers listed below can be corrupted due to incorrect
+ * resynchronization between clock domains.
+ * Read access to registers below can be corrupted :
+ * CTRL_CORE_DTEMP_MPU/GPU/CORE/DSPEVE/IVA_n (n = 0 to 4)
+ * CTRL_CORE_TEMP_SENSOR_MPU/GPU/CORE/DSPEVE/IVA_n
+ *
+ * Return: the register value.
+ */
+static u32 ti_errata814_bandgap_read_temp(struct ti_bandgap *bgp,  u32 reg)
+{
+       u32 val1, val2;
+
+       val1 = ti_bandgap_readl(bgp, reg);
+       val2 = ti_bandgap_readl(bgp, reg);
+
+       /* If both times we read the same value then that is right */
+       if (val1 == val2)
+               return val1;
+
+       /* if val1 and val2 are different read it third time */
+       return ti_bandgap_readl(bgp, reg);
+}
+
 /**
  * ti_bandgap_read_temp() - helper function to read sensor temperature
  * @bgp: pointer to ti_bandgap structure
@@ -148,7 +179,11 @@ static u32 ti_bandgap_read_temp(struct ti_bandgap *bgp, int id)
        }
 
        /* read temperature */
-       temp = ti_bandgap_readl(bgp, reg);
+       if (TI_BANDGAP_HAS(bgp, ERRATA_814))
+               temp = ti_errata814_bandgap_read_temp(bgp, reg);
+       else
+               temp = ti_bandgap_readl(bgp, reg);
+
        temp &= tsr->bgap_dtemp_mask;
 
        if (TI_BANDGAP_HAS(bgp, FREEZE_BIT))
@@ -410,7 +445,7 @@ static int ti_bandgap_update_alert_threshold(struct ti_bandgap *bgp, int id,
 {
        struct temp_sensor_data *ts_data = bgp->conf->sensors[id].ts_data;
        struct temp_sensor_registers *tsr;
-       u32 thresh_val, reg_val, t_hot, t_cold;
+       u32 thresh_val, reg_val, t_hot, t_cold, ctrl;
        int err = 0;
 
        tsr = bgp->conf->sensors[id].registers;
@@ -442,8 +477,47 @@ static int ti_bandgap_update_alert_threshold(struct ti_bandgap *bgp, int id,
                  ~(tsr->threshold_thot_mask | tsr->threshold_tcold_mask);
        reg_val |= (t_hot << __ffs(tsr->threshold_thot_mask)) |
                   (t_cold << __ffs(tsr->threshold_tcold_mask));
+
+       /**
+        * Errata i813:
+        * Spurious Thermal Alert: Talert can happen randomly while the device
+        * remains under the temperature limit defined for this event to trig.
+        * This spurious event is caused by a incorrect re-synchronization
+        * between clock domains. The comparison between configured threshold
+        * and current temperature value can happen while the value is
+        * transitioning (metastable), thus causing inappropriate event
+        * generation. No spurious event occurs as long as the threshold value
+        * stays unchanged. Spurious event can be generated while a thermal
+        * alert threshold is modified in
+        * CONTROL_BANDGAP_THRESHOLD_MPU/GPU/CORE/DSPEVE/IVA_n.
+        */
+
+       if (TI_BANDGAP_HAS(bgp, ERRATA_813)) {
+               /* Mask t_hot and t_cold events at the IP Level */
+               ctrl = ti_bandgap_readl(bgp, tsr->bgap_mask_ctrl);
+
+               if (hot)
+                       ctrl &= ~tsr->mask_hot_mask;
+               else
+                       ctrl &= ~tsr->mask_cold_mask;
+
+               ti_bandgap_writel(bgp, ctrl, tsr->bgap_mask_ctrl);
+       }
+
+       /* Write the threshold value */
        ti_bandgap_writel(bgp, reg_val, tsr->bgap_threshold);
 
+       if (TI_BANDGAP_HAS(bgp, ERRATA_813)) {
+               /* Unmask t_hot and t_cold events at the IP Level */
+               ctrl = ti_bandgap_readl(bgp, tsr->bgap_mask_ctrl);
+               if (hot)
+                       ctrl |= tsr->mask_hot_mask;
+               else
+                       ctrl |= tsr->mask_cold_mask;
+
+               ti_bandgap_writel(bgp, ctrl, tsr->bgap_mask_ctrl);
+       }
+
        if (err) {
                dev_err(bgp->dev, "failed to reprogram thot threshold\n");
                err = -EIO;
index b3adf72f252d310779e5014b9ee272bf2a499946..0c52f7afba00b5335adbeba60cd31f547d2256a3 100644 (file)
@@ -318,6 +318,10 @@ struct ti_temp_sensor {
  * TI_BANDGAP_FEATURE_HISTORY_BUFFER - used when the bandgap device features
  *     a history buffer of temperatures.
  *
+ * TI_BANDGAP_FEATURE_ERRATA_814 - used to workaorund when the bandgap device
+ *     has Errata 814
+ * TI_BANDGAP_FEATURE_ERRATA_813 - used to workaorund when the bandgap device
+ *     has Errata 813
  * TI_BANDGAP_HAS(b, f) - macro to check if a bandgap device is capable of a
  *      specific feature (above) or not. Return non-zero, if yes.
  */
@@ -331,6 +335,8 @@ struct ti_temp_sensor {
 #define TI_BANDGAP_FEATURE_FREEZE_BIT          BIT(7)
 #define TI_BANDGAP_FEATURE_COUNTER_DELAY       BIT(8)
 #define TI_BANDGAP_FEATURE_HISTORY_BUFFER      BIT(9)
+#define TI_BANDGAP_FEATURE_ERRATA_814          BIT(10)
+#define TI_BANDGAP_FEATURE_ERRATA_813          BIT(11)
 #define TI_BANDGAP_HAS(b, f)                   \
                        ((b)->conf->features & TI_BANDGAP_FEATURE_ ## f)
 
index f1e57425e39ff00b1a929500f4ea297aba5ae095..7a3d146a5f0efc0dbc3b94e854adb4d81c85da4d 100644 (file)
@@ -289,7 +289,7 @@ static int xen_initial_domain_console_init(void)
                        return -ENOMEM;
        }
 
-       info->irq = bind_virq_to_irq(VIRQ_CONSOLE, 0);
+       info->irq = bind_virq_to_irq(VIRQ_CONSOLE, 0, false);
        info->vtermno = HVC_COOKIE;
 
        spin_lock(&xencons_lock);
@@ -299,11 +299,27 @@ static int xen_initial_domain_console_init(void)
        return 0;
 }
 
+static void xen_console_update_evtchn(struct xencons_info *info)
+{
+       if (xen_hvm_domain()) {
+               uint64_t v;
+               int err;
+
+               err = hvm_get_parameter(HVM_PARAM_CONSOLE_EVTCHN, &v);
+               if (!err && v)
+                       info->evtchn = v;
+       } else
+               info->evtchn = xen_start_info->console.domU.evtchn;
+}
+
 void xen_console_resume(void)
 {
        struct xencons_info *info = vtermno_to_xencons(HVC_COOKIE);
-       if (info != NULL && info->irq)
+       if (info != NULL && info->irq) {
+               if (!xen_initial_domain())
+                       xen_console_update_evtchn(info);
                rebind_evtchn_irq(info->evtchn, info->irq);
+       }
 }
 
 static void xencons_disconnect_backend(struct xencons_info *info)
index 04d9e23d1ee16a508e0e0b1331407bcf6b20a94b..358323c83b4f340dec1a915ef923145fb972d933 100644 (file)
@@ -174,13 +174,13 @@ struct mips_ejtag_fdc_tty {
 static inline void mips_ejtag_fdc_write(struct mips_ejtag_fdc_tty *priv,
                                        unsigned int offs, unsigned int data)
 {
-       iowrite32(data, priv->reg + offs);
+       __raw_writel(data, priv->reg + offs);
 }
 
 static inline unsigned int mips_ejtag_fdc_read(struct mips_ejtag_fdc_tty *priv,
                                               unsigned int offs)
 {
-       return ioread32(priv->reg + offs);
+       return __raw_readl(priv->reg + offs);
 }
 
 /* Encoding of byte stream in FDC words */
@@ -347,9 +347,9 @@ static void mips_ejtag_fdc_console_write(struct console *c, const char *s,
                s += inc[word.bytes - 1];
 
                /* Busy wait until there's space in fifo */
-               while (ioread32(regs + REG_FDSTAT) & REG_FDSTAT_TXF)
+               while (__raw_readl(regs + REG_FDSTAT) & REG_FDSTAT_TXF)
                        ;
-               iowrite32(word.word, regs + REG_FDTX(c->index));
+               __raw_writel(word.word, regs + REG_FDTX(c->index));
        }
 out:
        local_irq_restore(flags);
@@ -1227,7 +1227,7 @@ static int kgdbfdc_read_char(void)
 
                /* Read next word from KGDB channel */
                do {
-                       stat = ioread32(regs + REG_FDSTAT);
+                       stat = __raw_readl(regs + REG_FDSTAT);
 
                        /* No data waiting? */
                        if (stat & REG_FDSTAT_RXE)
@@ -1236,7 +1236,7 @@ static int kgdbfdc_read_char(void)
                        /* Read next word */
                        channel = (stat & REG_FDSTAT_RXCHAN) >>
                                        REG_FDSTAT_RXCHAN_SHIFT;
-                       data = ioread32(regs + REG_FDRX);
+                       data = __raw_readl(regs + REG_FDRX);
                } while (channel != CONFIG_MIPS_EJTAG_FDC_KGDB_CHAN);
 
                /* Decode into rbuf */
@@ -1266,9 +1266,10 @@ static void kgdbfdc_push_one(void)
                return;
 
        /* Busy wait until there's space in fifo */
-       while (ioread32(regs + REG_FDSTAT) & REG_FDSTAT_TXF)
+       while (__raw_readl(regs + REG_FDSTAT) & REG_FDSTAT_TXF)
                ;
-       iowrite32(word.word, regs + REG_FDTX(CONFIG_MIPS_EJTAG_FDC_KGDB_CHAN));
+       __raw_writel(word.word,
+                    regs + REG_FDTX(CONFIG_MIPS_EJTAG_FDC_KGDB_CHAN));
 }
 
 /* flush the whole write buffer to the TX FIFO */
index 91abc00aa833b8493fe721e05024cd8368e23aa6..2c34c3249972de85f650d34fa0b25448efba3686 100644 (file)
@@ -3170,7 +3170,7 @@ static int gsmtty_break_ctl(struct tty_struct *tty, int state)
        return gsmtty_modem_update(dlci, encode);
 }
 
-static void gsmtty_remove(struct tty_driver *driver, struct tty_struct *tty)
+static void gsmtty_cleanup(struct tty_struct *tty)
 {
        struct gsm_dlci *dlci = tty->driver_data;
        struct gsm_mux *gsm = dlci->gsm;
@@ -3178,7 +3178,6 @@ static void gsmtty_remove(struct tty_driver *driver, struct tty_struct *tty)
        dlci_put(dlci);
        dlci_put(gsm->dlci[0]);
        mux_put(gsm);
-       driver->ttys[tty->index] = NULL;
 }
 
 /* Virtual ttys for the demux */
@@ -3199,7 +3198,7 @@ static const struct tty_operations gsmtty_ops = {
        .tiocmget               = gsmtty_tiocmget,
        .tiocmset               = gsmtty_tiocmset,
        .break_ctl              = gsmtty_break_ctl,
-       .remove                 = gsmtty_remove,
+       .cleanup                = gsmtty_cleanup,
 };
 
 
index 644ddb841d9f54085bb82a903034af5aaf42de45..bbc4ce66c2c18dd30fb10b80f955a4f4565225c5 100644 (file)
@@ -600,7 +600,7 @@ static ssize_t n_hdlc_tty_read(struct tty_struct *tty, struct file *file,
        add_wait_queue(&tty->read_wait, &wait);
 
        for (;;) {
-               if (test_bit(TTY_OTHER_CLOSED, &tty->flags)) {
+               if (test_bit(TTY_OTHER_DONE, &tty->flags)) {
                        ret = -EIO;
                        break;
                }
@@ -828,7 +828,7 @@ static unsigned int n_hdlc_tty_poll(struct tty_struct *tty, struct file *filp,
                /* set bits for operations that won't block */
                if (n_hdlc->rx_buf_list.head)
                        mask |= POLLIN | POLLRDNORM;    /* readable */
-               if (test_bit(TTY_OTHER_CLOSED, &tty->flags))
+               if (test_bit(TTY_OTHER_DONE, &tty->flags))
                        mask |= POLLHUP;
                if (tty_hung_up_p(filp))
                        mask |= POLLHUP;
index cf6e0f2e1331fd46310a6834d99896e2b943ea19..396344cb011fd1fafab05c3ddeeff1841e13e055 100644 (file)
@@ -162,6 +162,17 @@ static inline int tty_put_user(struct tty_struct *tty, unsigned char x,
        return put_user(x, ptr);
 }
 
+static inline int tty_copy_to_user(struct tty_struct *tty,
+                                       void __user *to,
+                                       const void *from,
+                                       unsigned long n)
+{
+       struct n_tty_data *ldata = tty->disc_data;
+
+       tty_audit_add_data(tty, to, n, ldata->icanon);
+       return copy_to_user(to, from, n);
+}
+
 /**
  *     n_tty_kick_worker - start input worker (if required)
  *     @tty: terminal
@@ -1949,6 +1960,18 @@ static inline int input_available_p(struct tty_struct *tty, int poll)
                return ldata->commit_head - ldata->read_tail >= amt;
 }
 
+static inline int check_other_done(struct tty_struct *tty)
+{
+       int done = test_bit(TTY_OTHER_DONE, &tty->flags);
+       if (done) {
+               /* paired with cmpxchg() in check_other_closed(); ensures
+                * read buffer head index is not stale
+                */
+               smp_mb__after_atomic();
+       }
+       return done;
+}
+
 /**
  *     copy_from_read_buf      -       copy read data directly
  *     @tty: terminal device
@@ -2058,8 +2081,8 @@ static int canon_copy_from_read_buf(struct tty_struct *tty,
 
        size = N_TTY_BUF_SIZE - tail;
        n = eol - tail;
-       if (n > 4096)
-               n += 4096;
+       if (n > N_TTY_BUF_SIZE)
+               n += N_TTY_BUF_SIZE;
        n += found;
        c = n;
 
@@ -2072,12 +2095,12 @@ static int canon_copy_from_read_buf(struct tty_struct *tty,
                    __func__, eol, found, n, c, size, more);
 
        if (n > size) {
-               ret = copy_to_user(*b, read_buf_addr(ldata, tail), size);
+               ret = tty_copy_to_user(tty, *b, read_buf_addr(ldata, tail), size);
                if (ret)
                        return -EFAULT;
-               ret = copy_to_user(*b + size, ldata->read_buf, n - size);
+               ret = tty_copy_to_user(tty, *b + size, ldata->read_buf, n - size);
        } else
-               ret = copy_to_user(*b, read_buf_addr(ldata, tail), n);
+               ret = tty_copy_to_user(tty, *b, read_buf_addr(ldata, tail), n);
 
        if (ret)
                return -EFAULT;
@@ -2167,7 +2190,7 @@ static ssize_t n_tty_read(struct tty_struct *tty, struct file *file,
        struct n_tty_data *ldata = tty->disc_data;
        unsigned char __user *b = buf;
        DEFINE_WAIT_FUNC(wait, woken_wake_function);
-       int c;
+       int c, done;
        int minimum, time;
        ssize_t retval = 0;
        long timeout;
@@ -2235,8 +2258,10 @@ static ssize_t n_tty_read(struct tty_struct *tty, struct file *file,
                    ((minimum - (b - buf)) >= 1))
                        ldata->minimum_to_wake = (minimum - (b - buf));
 
+               done = check_other_done(tty);
+
                if (!input_available_p(tty, 0)) {
-                       if (test_bit(TTY_OTHER_CLOSED, &tty->flags)) {
+                       if (done) {
                                retval = -EIO;
                                break;
                        }
@@ -2443,12 +2468,12 @@ static unsigned int n_tty_poll(struct tty_struct *tty, struct file *file,
 
        poll_wait(file, &tty->read_wait, wait);
        poll_wait(file, &tty->write_wait, wait);
+       if (check_other_done(tty))
+               mask |= POLLHUP;
        if (input_available_p(tty, 1))
                mask |= POLLIN | POLLRDNORM;
        if (tty->packet && tty->link->ctrl_status)
                mask |= POLLPRI | POLLIN | POLLRDNORM;
-       if (test_bit(TTY_OTHER_CLOSED, &tty->flags))
-               mask |= POLLHUP;
        if (tty_hung_up_p(file))
                mask |= POLLHUP;
        if (!(mask & (POLLHUP | POLLIN | POLLRDNORM))) {
index e72ee629cead1b0af93c54b96395cbfc98b69975..4d5e8409769c3cc412ba5d428e0f179b4b44fdad 100644 (file)
@@ -53,9 +53,8 @@ static void pty_close(struct tty_struct *tty, struct file *filp)
        /* Review - krefs on tty_link ?? */
        if (!tty->link)
                return;
-       tty_flush_to_ldisc(tty->link);
        set_bit(TTY_OTHER_CLOSED, &tty->link->flags);
-       wake_up_interruptible(&tty->link->read_wait);
+       tty_flip_buffer_push(tty->link->port);
        wake_up_interruptible(&tty->link->write_wait);
        if (tty->driver->subtype == PTY_TYPE_MASTER) {
                set_bit(TTY_OTHER_CLOSED, &tty->flags);
@@ -243,7 +242,9 @@ static int pty_open(struct tty_struct *tty, struct file *filp)
                goto out;
 
        clear_bit(TTY_IO_ERROR, &tty->flags);
+       /* TTY_OTHER_CLOSED must be cleared before TTY_OTHER_DONE */
        clear_bit(TTY_OTHER_CLOSED, &tty->link->flags);
+       clear_bit(TTY_OTHER_DONE, &tty->link->flags);
        set_bit(TTY_THROTTLED, &tty->flags);
        return 0;
 
index 9289999cb7c62bb05b2a4b758fa76d5ce9413316..dce1a23706e86531d3caa86ba4b03c36b03bf3cf 100644 (file)
@@ -562,12 +562,36 @@ static irqreturn_t omap_wake_irq(int irq, void *dev_id)
        return IRQ_NONE;
 }
 
+#ifdef CONFIG_SERIAL_8250_DMA
+static int omap_8250_dma_handle_irq(struct uart_port *port);
+#endif
+
+static irqreturn_t omap8250_irq(int irq, void *dev_id)
+{
+       struct uart_port *port = dev_id;
+       struct uart_8250_port *up = up_to_u8250p(port);
+       unsigned int iir;
+       int ret;
+
+#ifdef CONFIG_SERIAL_8250_DMA
+       if (up->dma) {
+               ret = omap_8250_dma_handle_irq(port);
+               return IRQ_RETVAL(ret);
+       }
+#endif
+
+       serial8250_rpm_get(up);
+       iir = serial_port_in(port, UART_IIR);
+       ret = serial8250_handle_irq(port, iir);
+       serial8250_rpm_put(up);
+
+       return IRQ_RETVAL(ret);
+}
+
 static int omap_8250_startup(struct uart_port *port)
 {
-       struct uart_8250_port *up =
-               container_of(port, struct uart_8250_port, port);
+       struct uart_8250_port *up = up_to_u8250p(port);
        struct omap8250_priv *priv = port->private_data;
-
        int ret;
 
        if (priv->wakeirq) {
@@ -580,10 +604,31 @@ static int omap_8250_startup(struct uart_port *port)
 
        pm_runtime_get_sync(port->dev);
 
-       ret = serial8250_do_startup(port);
-       if (ret)
+       up->mcr = 0;
+       serial_out(up, UART_FCR, UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT);
+
+       serial_out(up, UART_LCR, UART_LCR_WLEN8);
+
+       up->lsr_saved_flags = 0;
+       up->msr_saved_flags = 0;
+
+       if (up->dma) {
+               ret = serial8250_request_dma(up);
+               if (ret) {
+                       dev_warn_ratelimited(port->dev,
+                                            "failed to request DMA\n");
+                       up->dma = NULL;
+               }
+       }
+
+       ret = request_irq(port->irq, omap8250_irq, IRQF_SHARED,
+                         dev_name(port->dev), port);
+       if (ret < 0)
                goto err;
 
+       up->ier = UART_IER_RLSI | UART_IER_RDI;
+       serial_out(up, UART_IER, up->ier);
+
 #ifdef CONFIG_PM
        up->capabilities |= UART_CAP_RPM;
 #endif
@@ -610,8 +655,7 @@ err:
 
 static void omap_8250_shutdown(struct uart_port *port)
 {
-       struct uart_8250_port *up =
-               container_of(port, struct uart_8250_port, port);
+       struct uart_8250_port *up = up_to_u8250p(port);
        struct omap8250_priv *priv = port->private_data;
 
        flush_work(&priv->qos_work);
@@ -621,11 +665,24 @@ static void omap_8250_shutdown(struct uart_port *port)
        pm_runtime_get_sync(port->dev);
 
        serial_out(up, UART_OMAP_WER, 0);
-       serial8250_do_shutdown(port);
+
+       up->ier = 0;
+       serial_out(up, UART_IER, 0);
+
+       if (up->dma)
+               serial8250_release_dma(up);
+
+       /*
+        * Disable break condition and FIFOs
+        */
+       if (up->lcr & UART_LCR_SBC)
+               serial_out(up, UART_LCR, up->lcr & ~UART_LCR_SBC);
+       serial_out(up, UART_FCR, UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT);
 
        pm_runtime_mark_last_busy(port->dev);
        pm_runtime_put_autosuspend(port->dev);
 
+       free_irq(port->irq, port);
        if (priv->wakeirq)
                free_irq(priv->wakeirq, port);
 }
@@ -974,6 +1031,13 @@ static inline int omap_8250_rx_dma(struct uart_8250_port *p, unsigned int iir)
 }
 #endif
 
+static int omap8250_no_handle_irq(struct uart_port *port)
+{
+       /* IRQ has not been requested but handling irq? */
+       WARN_ONCE(1, "Unexpected irq handling before port startup\n");
+       return 0;
+}
+
 static int omap8250_probe(struct platform_device *pdev)
 {
        struct resource *regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
@@ -1075,6 +1139,7 @@ static int omap8250_probe(struct platform_device *pdev)
        pm_runtime_get_sync(&pdev->dev);
 
        omap_serial_fill_features_erratas(&up, priv);
+       up.port.handle_irq = omap8250_no_handle_irq;
 #ifdef CONFIG_SERIAL_8250_DMA
        if (pdev->dev.of_node) {
                /*
@@ -1088,7 +1153,6 @@ static int omap8250_probe(struct platform_device *pdev)
                ret = of_property_count_strings(pdev->dev.of_node, "dma-names");
                if (ret == 2) {
                        up.dma = &priv->omap8250_dma;
-                       up.port.handle_irq = omap_8250_dma_handle_irq;
                        priv->omap8250_dma.fn = the_no_dma_filter_fn;
                        priv->omap8250_dma.tx_dma = omap_8250_tx_dma;
                        priv->omap8250_dma.rx_dma = omap_8250_rx_dma;
index 08da4d3e21621ab03ed62a305562bf8f21a5f092..46bcebba54b2ff44fc32de373dfc8b09fc58687a 100644 (file)
@@ -1998,6 +1998,8 @@ pci_wch_ch38x_setup(struct serial_private *priv,
 #define PCIE_DEVICE_ID_WCH_CH382_2S1P  0x3250
 #define PCIE_DEVICE_ID_WCH_CH384_4S    0x3470
 
+#define PCI_DEVICE_ID_EXAR_XR17V8358   0x8358
+
 /* Unknown vendors/cards - this should not be in linux/pci_ids.h */
 #define PCI_SUBDEVICE_ID_UNKNOWN_0x1584        0x1584
 #define PCI_SUBDEVICE_ID_UNKNOWN_0x1588        0x1588
@@ -2520,6 +2522,13 @@ static struct pci_serial_quirk pci_serial_quirks[] __refdata = {
                .subdevice      = PCI_ANY_ID,
                .setup          = pci_xr17v35x_setup,
        },
+       {
+               .vendor = PCI_VENDOR_ID_EXAR,
+               .device = PCI_DEVICE_ID_EXAR_XR17V8358,
+               .subvendor      = PCI_ANY_ID,
+               .subdevice      = PCI_ANY_ID,
+               .setup          = pci_xr17v35x_setup,
+       },
        /*
         * Xircom cards
         */
@@ -2999,6 +3008,7 @@ enum pci_board_num_t {
        pbn_exar_XR17V352,
        pbn_exar_XR17V354,
        pbn_exar_XR17V358,
+       pbn_exar_XR17V8358,
        pbn_exar_ibm_saturn,
        pbn_pasemi_1682M,
        pbn_ni8430_2,
@@ -3685,6 +3695,14 @@ static struct pciserial_board pci_boards[] = {
                .reg_shift      = 0,
                .first_offset   = 0,
        },
+       [pbn_exar_XR17V8358] = {
+               .flags          = FL_BASE0,
+               .num_ports      = 16,
+               .base_baud      = 7812500,
+               .uart_offset    = 0x400,
+               .reg_shift      = 0,
+               .first_offset   = 0,
+       },
        [pbn_exar_ibm_saturn] = {
                .flags          = FL_BASE0,
                .num_ports      = 1,
@@ -5080,7 +5098,7 @@ static struct pci_device_id serial_pci_tbl[] = {
                0,
                0, pbn_exar_XR17C158 },
        /*
-        * Exar Corp. XR17V35[248] Dual/Quad/Octal PCIe UARTs
+        * Exar Corp. XR17V[48]35[248] Dual/Quad/Octal/Hexa PCIe UARTs
         */
        {       PCI_VENDOR_ID_EXAR, PCI_DEVICE_ID_EXAR_XR17V352,
                PCI_ANY_ID, PCI_ANY_ID,
@@ -5094,7 +5112,10 @@ static struct pci_device_id serial_pci_tbl[] = {
                PCI_ANY_ID, PCI_ANY_ID,
                0,
                0, pbn_exar_XR17V358 },
-
+       {       PCI_VENDOR_ID_EXAR, PCI_DEVICE_ID_EXAR_XR17V8358,
+               PCI_ANY_ID, PCI_ANY_ID,
+               0,
+               0, pbn_exar_XR17V8358 },
        /*
         * Topic TP560 Data/Fax/Voice 56k modem (reported by Evan Clarke)
         */
index 5a4e9d579585f9c5165839db0fec8e368dfb8133..763eb20fe3213b6cfda04dc2624bcd1b8638f324 100644 (file)
@@ -1249,20 +1249,19 @@ __acquires(&uap->port.lock)
 
 /*
  * Transmit a character
- * There must be at least one free entry in the TX FIFO to accept the char.
  *
- * Returns true if the FIFO might have space in it afterwards;
- * returns false if the FIFO definitely became full.
+ * Returns true if the character was successfully queued to the FIFO.
+ * Returns false otherwise.
  */
 static bool pl011_tx_char(struct uart_amba_port *uap, unsigned char c)
 {
+       if (readw(uap->port.membase + UART01x_FR) & UART01x_FR_TXFF)
+               return false; /* unable to transmit character */
+
        writew(c, uap->port.membase + UART01x_DR);
        uap->port.icount.tx++;
 
-       if (likely(uap->tx_irq_seen > 1))
-               return true;
-
-       return !(readw(uap->port.membase + UART01x_FR) & UART01x_FR_TXFF);
+       return true;
 }
 
 static bool pl011_tx_chars(struct uart_amba_port *uap)
@@ -1296,7 +1295,8 @@ static bool pl011_tx_chars(struct uart_amba_port *uap)
                return false;
 
        if (uap->port.x_char) {
-               pl011_tx_char(uap, uap->port.x_char);
+               if (!pl011_tx_char(uap, uap->port.x_char))
+                       goto done;
                uap->port.x_char = 0;
                --count;
        }
@@ -1639,6 +1639,9 @@ static int pl011_startup(struct uart_port *port)
 
        writew(uap->vendor->ifls, uap->port.membase + UART011_IFLS);
 
+       /* Assume that TX IRQ doesn't work until we see one: */
+       uap->tx_irq_seen = 0;
+
        spin_lock_irq(&uap->port.lock);
 
        /* restore RTS and DTR */
@@ -1702,7 +1705,7 @@ static void pl011_shutdown(struct uart_port *port)
        spin_lock_irq(&uap->port.lock);
        uap->im = 0;
        writew(uap->im, uap->port.membase + UART011_IMSC);
-       writew(0xffff & ~UART011_TXIS, uap->port.membase + UART011_ICR);
+       writew(0xffff, uap->port.membase + UART011_ICR);
        spin_unlock_irq(&uap->port.lock);
 
        pl011_dma_shutdown(uap);
index d58fe4763d9e1bdacf07577e3043414e22f8ecbc..27dade29646b7c8d962494cf37daee398c774514 100644 (file)
@@ -880,6 +880,7 @@ static int atmel_prepare_tx_dma(struct uart_port *port)
        config.direction = DMA_MEM_TO_DEV;
        config.dst_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE;
        config.dst_addr = port->mapbase + ATMEL_US_THR;
+       config.dst_maxburst = 1;
 
        ret = dmaengine_slave_config(atmel_port->chan_tx,
                                     &config);
@@ -1059,6 +1060,7 @@ static int atmel_prepare_rx_dma(struct uart_port *port)
        config.direction = DMA_DEV_TO_MEM;
        config.src_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE;
        config.src_addr = port->mapbase + ATMEL_US_RHR;
+       config.src_maxburst = 1;
 
        ret = dmaengine_slave_config(atmel_port->chan_rx,
                                     &config);
index 5fdc9f3ecd644d9b58a0f9a10f150296b68282d7..6dc471e30e793aaf99bfc1bac6d376387d9e21a5 100644 (file)
@@ -187,13 +187,8 @@ static int __init param_setup_earlycon(char *buf)
                return 0;
 
        err = setup_earlycon(buf);
-       if (err == -ENOENT) {
-               pr_warn("no match for %s\n", buf);
-               err = 0;
-       } else if (err == -EALREADY) {
-               pr_warn("already registered\n");
-               err = 0;
-       }
+       if (err == -ENOENT || err == -EALREADY)
+               return 0;
        return err;
 }
 early_param("earlycon", param_setup_earlycon);
index c8cfa06371280af6abfd63bd379ee5c121523ad7..88250395b0ce96486a2dac5e2e9162fb7f4eae43 100644 (file)
@@ -911,6 +911,14 @@ static void dma_rx_callback(void *data)
 
        status = dmaengine_tx_status(chan, (dma_cookie_t)0, &state);
        count = RX_BUF_SIZE - state.residue;
+
+       if (readl(sport->port.membase + USR2) & USR2_IDLE) {
+               /* In condition [3] the SDMA counted up too early */
+               count--;
+
+               writel(USR2_IDLE, sport->port.membase + USR2);
+       }
+
        dev_dbg(sport->port.dev, "We get %d bytes.\n", count);
 
        if (count) {
index 5b73afb9f9f34343371477be0c48d535f600dc86..137381e649e5bec1c2ac5bf616bc9da6e813772a 100644 (file)
@@ -346,7 +346,6 @@ static const struct of_device_id of_platform_serial_table[] = {
        { .compatible = "ibm,qpace-nwp-serial",
                .data = (void *)PORT_NWPSERIAL, },
 #endif
-       { .type = "serial",         .data = (void *)PORT_UNKNOWN, },
        { /* end of list */ },
 };
 
index 211479aa34bb20d5375078afb103829faa5bfd84..7f49172ccd8673b316b3b82ab21282885ef983eb 100644 (file)
@@ -1735,6 +1735,8 @@ static int serial_omap_probe(struct platform_device *pdev)
 err_add_port:
        pm_runtime_put(&pdev->dev);
        pm_runtime_disable(&pdev->dev);
+       pm_qos_remove_request(&up->pm_qos_request);
+       device_init_wakeup(up->dev, false);
 err_rs485:
 err_port_line:
        return ret;
index cf08876922f1446e55a2d8ca79bf87e0d4e24fed..a0ae942d9562d818c3e35a30c71d1bd1cb12e426 100644 (file)
@@ -1068,8 +1068,9 @@ static int s3c64xx_serial_startup(struct uart_port *port)
        spin_lock_irqsave(&port->lock, flags);
 
        ufcon = rd_regl(port, S3C2410_UFCON);
-       ufcon |= S3C2410_UFCON_RESETRX | S3C2410_UFCON_RESETTX |
-                       S5PV210_UFCON_RXTRIG8;
+       ufcon |= S3C2410_UFCON_RESETRX | S5PV210_UFCON_RXTRIG8;
+       if (!uart_console(port))
+               ufcon |= S3C2410_UFCON_RESETTX;
        wr_regl(port, S3C2410_UFCON, ufcon);
 
        enable_rx_pio(ourport);
index eb5b03be9dfdf5ff1dddbf5ce7bd271596975967..0b7bb12dfc68bc7edc45f7274a4e75acb9238a59 100644 (file)
@@ -1770,7 +1770,7 @@ static const struct file_operations uart_proc_fops = {
  *     @port: the port to write the message
  *     @s: array of characters
  *     @count: number of characters in string to write
- *     @write: function to write character to port
+ *     @putchar: function to write character to port
  */
 void uart_console_write(struct uart_port *port, const char *s,
                        unsigned int count,
index 708eead850b032bdc74c17031c66b0d58abb192a..b1c6bd3d483fa87a0372928ebd59cbdf9173d17d 100644 (file)
@@ -632,7 +632,8 @@ MODULE_DEVICE_TABLE(of, ulite_of_match);
 
 static int ulite_probe(struct platform_device *pdev)
 {
-       struct resource *res, *res2;
+       struct resource *res;
+       int irq;
        int id = pdev->id;
 #ifdef CONFIG_OF
        const __be32 *prop;
@@ -646,11 +647,11 @@ static int ulite_probe(struct platform_device *pdev)
        if (!res)
                return -ENODEV;
 
-       res2 = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
-       if (!res2)
-               return -ENODEV;
+       irq = platform_get_irq(pdev, 0);
+       if (irq <= 0)
+               return -ENXIO;
 
-       return ulite_assign(&pdev->dev, id, res->start, res2->start);
+       return ulite_assign(&pdev->dev, id, res->start, irq);
 }
 
 static int ulite_remove(struct platform_device *pdev)
index f218ec658f5d200e415d6bdf7503f7bc83f7a825..3ddbac767db3c43e3f5e3afd1e5dd482af86f88a 100644 (file)
@@ -1331,9 +1331,9 @@ static SIMPLE_DEV_PM_OPS(cdns_uart_dev_pm_ops, cdns_uart_suspend,
  */
 static int cdns_uart_probe(struct platform_device *pdev)
 {
-       int rc, id;
+       int rc, id, irq;
        struct uart_port *port;
-       struct resource *res, *res2;
+       struct resource *res;
        struct cdns_uart *cdns_uart_data;
 
        cdns_uart_data = devm_kzalloc(&pdev->dev, sizeof(*cdns_uart_data),
@@ -1380,9 +1380,9 @@ static int cdns_uart_probe(struct platform_device *pdev)
                goto err_out_clk_disable;
        }
 
-       res2 = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
-       if (!res2) {
-               rc = -ENODEV;
+       irq = platform_get_irq(pdev, 0);
+       if (irq <= 0) {
+               rc = -ENXIO;
                goto err_out_clk_disable;
        }
 
@@ -1411,7 +1411,7 @@ static int cdns_uart_probe(struct platform_device *pdev)
                 * and triggers invocation of the config_port() entry point.
                 */
                port->mapbase = res->start;
-               port->irq = res2->start;
+               port->irq = irq;
                port->dev = &pdev->dev;
                port->uartclk = clk_get_rate(cdns_uart_data->uartclk);
                port->private_data = cdns_uart_data;
index 75661641f5fe068237e7830acd9472383964da3a..2f78b77f0f8180fa07df27ab2ab931cf73f53587 100644 (file)
 
 #define TTY_BUFFER_PAGE        (((PAGE_SIZE - sizeof(struct tty_buffer)) / 2) & ~0xFF)
 
+/*
+ * If all tty flip buffers have been processed by flush_to_ldisc() or
+ * dropped by tty_buffer_flush(), check if the linked pty has been closed.
+ * If so, wake the reader/poll to process
+ */
+static inline void check_other_closed(struct tty_struct *tty)
+{
+       unsigned long flags, old;
+
+       /* transition from TTY_OTHER_CLOSED => TTY_OTHER_DONE must be atomic */
+       for (flags = ACCESS_ONCE(tty->flags);
+            test_bit(TTY_OTHER_CLOSED, &flags);
+            ) {
+               old = flags;
+               __set_bit(TTY_OTHER_DONE, &flags);
+               flags = cmpxchg(&tty->flags, old, flags);
+               if (old == flags) {
+                       wake_up_interruptible(&tty->read_wait);
+                       break;
+               }
+       }
+}
 
 /**
  *     tty_buffer_lock_exclusive       -       gain exclusive access to buffer
@@ -229,6 +251,8 @@ void tty_buffer_flush(struct tty_struct *tty, struct tty_ldisc *ld)
        if (ld && ld->ops->flush_buffer)
                ld->ops->flush_buffer(tty);
 
+       check_other_closed(tty);
+
        atomic_dec(&buf->priority);
        mutex_unlock(&buf->lock);
 }
@@ -471,8 +495,10 @@ static void flush_to_ldisc(struct work_struct *work)
                smp_rmb();
                count = head->commit - head->read;
                if (!count) {
-                       if (next == NULL)
+                       if (next == NULL) {
+                               check_other_closed(tty);
                                break;
+                       }
                        buf->head = next;
                        tty_buffer_free(port, head);
                        continue;
@@ -488,19 +514,6 @@ static void flush_to_ldisc(struct work_struct *work)
        tty_ldisc_deref(disc);
 }
 
-/**
- *     tty_flush_to_ldisc
- *     @tty: tty to push
- *
- *     Push the terminal flip buffers to the line discipline.
- *
- *     Must not be called from IRQ context.
- */
-void tty_flush_to_ldisc(struct tty_struct *tty)
-{
-       flush_work(&tty->port->buf.work);
-}
-
 /**
  *     tty_flip_buffer_push    -       terminal
  *     @port: tty port to push
index 632fc815206169281af9aa13f6ca345eb846eabe..8e53fe4696647e6bbfd8951e3a96a0d070ce28af 100644 (file)
@@ -536,7 +536,7 @@ EXPORT_SYMBOL(tty_termios_hw_change);
  *     Locking: termios_rwsem
  */
 
-static int tty_set_termios(struct tty_struct *tty, struct ktermios *new_termios)
+int tty_set_termios(struct tty_struct *tty, struct ktermios *new_termios)
 {
        struct ktermios old_termios;
        struct tty_ldisc *ld;
@@ -569,6 +569,7 @@ static int tty_set_termios(struct tty_struct *tty, struct ktermios *new_termios)
        up_write(&tty->termios_rwsem);
        return 0;
 }
+EXPORT_SYMBOL_GPL(tty_set_termios);
 
 /**
  *     set_termios             -       set termios values for a tty
index dfb05edcdb96dbbb3b794d6faf5c799b3c031f06..5b7061a331038d36ad20b7ec3c05b2ab1f8b3efc 100644 (file)
@@ -88,9 +88,13 @@ static ssize_t ci_port_test_write(struct file *file, const char __user *ubuf,
        char buf[32];
        int ret;
 
-       if (copy_from_user(buf, ubuf, min_t(size_t, sizeof(buf) - 1, count)))
+       count = min_t(size_t, sizeof(buf) - 1, count);
+       if (copy_from_user(buf, ubuf, count))
                return -EFAULT;
 
+       /* sscanf requires a zero terminated string */
+       buf[count] = '\0';
+
        if (sscanf(buf, "%u", &mode) != 1)
                return -EINVAL;
 
index 083acf45ad5aba6cc9e0fe6c9c7d94b3e0fcd85c..19d655a743b55eb8e17f4308bc722a40bfe4e505 100644 (file)
@@ -520,7 +520,6 @@ static int ci_otg_start_host(struct otg_fsm *fsm, int on)
 {
        struct ci_hdrc  *ci = container_of(fsm, struct ci_hdrc, fsm);
 
-       mutex_unlock(&fsm->lock);
        if (on) {
                ci_role_stop(ci);
                ci_role_start(ci, CI_ROLE_HOST);
@@ -529,7 +528,6 @@ static int ci_otg_start_host(struct otg_fsm *fsm, int on)
                hw_device_reset(ci);
                ci_role_start(ci, CI_ROLE_GADGET);
        }
-       mutex_lock(&fsm->lock);
        return 0;
 }
 
@@ -537,12 +535,10 @@ static int ci_otg_start_gadget(struct otg_fsm *fsm, int on)
 {
        struct ci_hdrc  *ci = container_of(fsm, struct ci_hdrc, fsm);
 
-       mutex_unlock(&fsm->lock);
        if (on)
                usb_gadget_vbus_connect(&ci->gadget);
        else
                usb_gadget_vbus_disconnect(&ci->gadget);
-       mutex_lock(&fsm->lock);
 
        return 0;
 }
index 3e15add665e236f2ef15bd1a9858dd9eabcb0c96..5c8f58114677daa1c65d5bd46255b71e8fd7fe72 100644 (file)
@@ -1142,11 +1142,16 @@ static int acm_probe(struct usb_interface *intf,
        }
 
        while (buflen > 0) {
+               elength = buffer[0];
+               if (!elength) {
+                       dev_err(&intf->dev, "skipping garbage byte\n");
+                       elength = 1;
+                       goto next_desc;
+               }
                if (buffer[1] != USB_DT_CS_INTERFACE) {
                        dev_err(&intf->dev, "skipping garbage\n");
                        goto next_desc;
                }
-               elength = buffer[0];
 
                switch (buffer[2]) {
                case USB_CDC_UNION_TYPE: /* we've found it */
index 41e510ae8c837ea337135c4ec8ddbe26fccac275..d85abfed84ccaa2327820f1b35cabac11422d647 100644 (file)
@@ -106,6 +106,9 @@ static const struct usb_device_id usb_quirk_list[] = {
        { USB_DEVICE(0x04f3, 0x010c), .driver_info =
                        USB_QUIRK_DEVICE_QUALIFIER },
 
+       { USB_DEVICE(0x04f3, 0x0125), .driver_info =
+                       USB_QUIRK_DEVICE_QUALIFIER },
+
        { USB_DEVICE(0x04f3, 0x016f), .driver_info =
                        USB_QUIRK_DEVICE_QUALIFIER },
 
index fdab715a063119d6e696a8f66ea26d4a1613e983..c0eafa6fd40314086474f5b7cab8f63361c73d64 100644 (file)
 #define DWC3_DGCMD_SET_ENDPOINT_NRDY   0x0c
 #define DWC3_DGCMD_RUN_SOC_BUS_LOOPBACK        0x10
 
-#define DWC3_DGCMD_STATUS(n)           (((n) >> 15) & 1)
+#define DWC3_DGCMD_STATUS(n)           (((n) >> 12) & 0x0F)
 #define DWC3_DGCMD_CMDACT              (1 << 10)
 #define DWC3_DGCMD_CMDIOC              (1 << 8)
 
 #define DWC3_DEPCMD_PARAM_SHIFT                16
 #define DWC3_DEPCMD_PARAM(x)           ((x) << DWC3_DEPCMD_PARAM_SHIFT)
 #define DWC3_DEPCMD_GET_RSC_IDX(x)     (((x) >> DWC3_DEPCMD_PARAM_SHIFT) & 0x7f)
-#define DWC3_DEPCMD_STATUS(x)          (((x) >> 15) & 1)
+#define DWC3_DEPCMD_STATUS(x)          (((x) >> 12) & 0x0F)
 #define DWC3_DEPCMD_HIPRI_FORCERM      (1 << 11)
 #define DWC3_DEPCMD_CMDACT             (1 << 10)
 #define DWC3_DEPCMD_CMDIOC             (1 << 8)
index edba5348be186bf33857bd7c1d47233df6d12422..6b486a36863c08dd908df48375d819602672762b 100644 (file)
@@ -65,8 +65,8 @@
 #define USBOTGSS_IRQENABLE_SET_MISC            0x003c
 #define USBOTGSS_IRQENABLE_CLR_MISC            0x0040
 #define USBOTGSS_IRQMISC_OFFSET                        0x03fc
-#define USBOTGSS_UTMI_OTG_CTRL                 0x0080
-#define USBOTGSS_UTMI_OTG_STATUS               0x0084
+#define USBOTGSS_UTMI_OTG_STATUS               0x0080
+#define USBOTGSS_UTMI_OTG_CTRL                 0x0084
 #define USBOTGSS_UTMI_OTG_OFFSET               0x0480
 #define USBOTGSS_TXFIFO_DEPTH                  0x0508
 #define USBOTGSS_RXFIFO_DEPTH                  0x050c
 #define USBOTGSS_IRQMISC_DISCHRGVBUS_FALL              (1 << 3)
 #define USBOTGSS_IRQMISC_IDPULLUP_FALL         (1 << 0)
 
-/* UTMI_OTG_CTRL REGISTER */
-#define USBOTGSS_UTMI_OTG_CTRL_DRVVBUS         (1 << 5)
-#define USBOTGSS_UTMI_OTG_CTRL_CHRGVBUS                (1 << 4)
-#define USBOTGSS_UTMI_OTG_CTRL_DISCHRGVBUS     (1 << 3)
-#define USBOTGSS_UTMI_OTG_CTRL_IDPULLUP                (1 << 0)
-
 /* UTMI_OTG_STATUS REGISTER */
-#define USBOTGSS_UTMI_OTG_STATUS_SW_MODE       (1 << 31)
-#define USBOTGSS_UTMI_OTG_STATUS_POWERPRESENT  (1 << 9)
-#define USBOTGSS_UTMI_OTG_STATUS_TXBITSTUFFENABLE (1 << 8)
-#define USBOTGSS_UTMI_OTG_STATUS_IDDIG         (1 << 4)
-#define USBOTGSS_UTMI_OTG_STATUS_SESSEND       (1 << 3)
-#define USBOTGSS_UTMI_OTG_STATUS_SESSVALID     (1 << 2)
-#define USBOTGSS_UTMI_OTG_STATUS_VBUSVALID     (1 << 1)
+#define USBOTGSS_UTMI_OTG_STATUS_DRVVBUS       (1 << 5)
+#define USBOTGSS_UTMI_OTG_STATUS_CHRGVBUS      (1 << 4)
+#define USBOTGSS_UTMI_OTG_STATUS_DISCHRGVBUS   (1 << 3)
+#define USBOTGSS_UTMI_OTG_STATUS_IDPULLUP      (1 << 0)
+
+/* UTMI_OTG_CTRL REGISTER */
+#define USBOTGSS_UTMI_OTG_CTRL_SW_MODE         (1 << 31)
+#define USBOTGSS_UTMI_OTG_CTRL_POWERPRESENT    (1 << 9)
+#define USBOTGSS_UTMI_OTG_CTRL_TXBITSTUFFENABLE (1 << 8)
+#define USBOTGSS_UTMI_OTG_CTRL_IDDIG           (1 << 4)
+#define USBOTGSS_UTMI_OTG_CTRL_SESSEND         (1 << 3)
+#define USBOTGSS_UTMI_OTG_CTRL_SESSVALID       (1 << 2)
+#define USBOTGSS_UTMI_OTG_CTRL_VBUSVALID       (1 << 1)
 
 struct dwc3_omap {
        struct device           *dev;
@@ -119,7 +119,7 @@ struct dwc3_omap {
        int                     irq;
        void __iomem            *base;
 
-       u32                     utmi_otg_status;
+       u32                     utmi_otg_ctrl;
        u32                     utmi_otg_offset;
        u32                     irqmisc_offset;
        u32                     irq_eoi_offset;
@@ -153,15 +153,15 @@ static inline void dwc3_omap_writel(void __iomem *base, u32 offset, u32 value)
        writel(value, base + offset);
 }
 
-static u32 dwc3_omap_read_utmi_status(struct dwc3_omap *omap)
+static u32 dwc3_omap_read_utmi_ctrl(struct dwc3_omap *omap)
 {
-       return dwc3_omap_readl(omap->base, USBOTGSS_UTMI_OTG_STATUS +
+       return dwc3_omap_readl(omap->base, USBOTGSS_UTMI_OTG_CTRL +
                                                        omap->utmi_otg_offset);
 }
 
-static void dwc3_omap_write_utmi_status(struct dwc3_omap *omap, u32 value)
+static void dwc3_omap_write_utmi_ctrl(struct dwc3_omap *omap, u32 value)
 {
-       dwc3_omap_writel(omap->base, USBOTGSS_UTMI_OTG_STATUS +
+       dwc3_omap_writel(omap->base, USBOTGSS_UTMI_OTG_CTRL +
                                        omap->utmi_otg_offset, value);
 
 }
@@ -235,25 +235,25 @@ static void dwc3_omap_set_mailbox(struct dwc3_omap *omap,
                        }
                }
 
-               val = dwc3_omap_read_utmi_status(omap);
-               val &= ~(USBOTGSS_UTMI_OTG_STATUS_IDDIG
-                               | USBOTGSS_UTMI_OTG_STATUS_VBUSVALID
-                               | USBOTGSS_UTMI_OTG_STATUS_SESSEND);
-               val |= USBOTGSS_UTMI_OTG_STATUS_SESSVALID
-                               | USBOTGSS_UTMI_OTG_STATUS_POWERPRESENT;
-               dwc3_omap_write_utmi_status(omap, val);
+               val = dwc3_omap_read_utmi_ctrl(omap);
+               val &= ~(USBOTGSS_UTMI_OTG_CTRL_IDDIG
+                               | USBOTGSS_UTMI_OTG_CTRL_VBUSVALID
+                               | USBOTGSS_UTMI_OTG_CTRL_SESSEND);
+               val |= USBOTGSS_UTMI_OTG_CTRL_SESSVALID
+                               | USBOTGSS_UTMI_OTG_CTRL_POWERPRESENT;
+               dwc3_omap_write_utmi_ctrl(omap, val);
                break;
 
        case OMAP_DWC3_VBUS_VALID:
                dev_dbg(omap->dev, "VBUS Connect\n");
 
-               val = dwc3_omap_read_utmi_status(omap);
-               val &= ~USBOTGSS_UTMI_OTG_STATUS_SESSEND;
-               val |= USBOTGSS_UTMI_OTG_STATUS_IDDIG
-                               | USBOTGSS_UTMI_OTG_STATUS_VBUSVALID
-                               | USBOTGSS_UTMI_OTG_STATUS_SESSVALID
-                               | USBOTGSS_UTMI_OTG_STATUS_POWERPRESENT;
-               dwc3_omap_write_utmi_status(omap, val);
+               val = dwc3_omap_read_utmi_ctrl(omap);
+               val &= ~USBOTGSS_UTMI_OTG_CTRL_SESSEND;
+               val |= USBOTGSS_UTMI_OTG_CTRL_IDDIG
+                               | USBOTGSS_UTMI_OTG_CTRL_VBUSVALID
+                               | USBOTGSS_UTMI_OTG_CTRL_SESSVALID
+                               | USBOTGSS_UTMI_OTG_CTRL_POWERPRESENT;
+               dwc3_omap_write_utmi_ctrl(omap, val);
                break;
 
        case OMAP_DWC3_ID_FLOAT:
@@ -263,13 +263,13 @@ static void dwc3_omap_set_mailbox(struct dwc3_omap *omap,
        case OMAP_DWC3_VBUS_OFF:
                dev_dbg(omap->dev, "VBUS Disconnect\n");
 
-               val = dwc3_omap_read_utmi_status(omap);
-               val &= ~(USBOTGSS_UTMI_OTG_STATUS_SESSVALID
-                               | USBOTGSS_UTMI_OTG_STATUS_VBUSVALID
-                               | USBOTGSS_UTMI_OTG_STATUS_POWERPRESENT);
-               val |= USBOTGSS_UTMI_OTG_STATUS_SESSEND
-                               | USBOTGSS_UTMI_OTG_STATUS_IDDIG;
-               dwc3_omap_write_utmi_status(omap, val);
+               val = dwc3_omap_read_utmi_ctrl(omap);
+               val &= ~(USBOTGSS_UTMI_OTG_CTRL_SESSVALID
+                               | USBOTGSS_UTMI_OTG_CTRL_VBUSVALID
+                               | USBOTGSS_UTMI_OTG_CTRL_POWERPRESENT);
+               val |= USBOTGSS_UTMI_OTG_CTRL_SESSEND
+                               | USBOTGSS_UTMI_OTG_CTRL_IDDIG;
+               dwc3_omap_write_utmi_ctrl(omap, val);
                break;
 
        default:
@@ -422,22 +422,22 @@ static void dwc3_omap_set_utmi_mode(struct dwc3_omap *omap)
        struct device_node      *node = omap->dev->of_node;
        int                     utmi_mode = 0;
 
-       reg = dwc3_omap_read_utmi_status(omap);
+       reg = dwc3_omap_read_utmi_ctrl(omap);
 
        of_property_read_u32(node, "utmi-mode", &utmi_mode);
 
        switch (utmi_mode) {
        case DWC3_OMAP_UTMI_MODE_SW:
-               reg |= USBOTGSS_UTMI_OTG_STATUS_SW_MODE;
+               reg |= USBOTGSS_UTMI_OTG_CTRL_SW_MODE;
                break;
        case DWC3_OMAP_UTMI_MODE_HW:
-               reg &= ~USBOTGSS_UTMI_OTG_STATUS_SW_MODE;
+               reg &= ~USBOTGSS_UTMI_OTG_CTRL_SW_MODE;
                break;
        default:
                dev_dbg(omap->dev, "UNKNOWN utmi mode %d\n", utmi_mode);
        }
 
-       dwc3_omap_write_utmi_status(omap, reg);
+       dwc3_omap_write_utmi_ctrl(omap, reg);
 }
 
 static int dwc3_omap_extcon_register(struct dwc3_omap *omap)
@@ -614,7 +614,7 @@ static int dwc3_omap_suspend(struct device *dev)
 {
        struct dwc3_omap        *omap = dev_get_drvdata(dev);
 
-       omap->utmi_otg_status = dwc3_omap_read_utmi_status(omap);
+       omap->utmi_otg_ctrl = dwc3_omap_read_utmi_ctrl(omap);
        dwc3_omap_disable_irqs(omap);
 
        return 0;
@@ -624,7 +624,7 @@ static int dwc3_omap_resume(struct device *dev)
 {
        struct dwc3_omap        *omap = dev_get_drvdata(dev);
 
-       dwc3_omap_write_utmi_status(omap, omap->utmi_otg_status);
+       dwc3_omap_write_utmi_ctrl(omap, omap->utmi_otg_ctrl);
        dwc3_omap_enable_irqs(omap);
 
        pm_runtime_disable(dev);
index c42765b3a060bc6b28b0f7a55f0231489afe651c..0495c94a23d7e96a9c3554b99893b6b0f63e7302 100644 (file)
@@ -1295,6 +1295,7 @@ static void purge_configs_funcs(struct gadget_info *gi)
                        }
                }
                c->next_interface_id = 0;
+               memset(c->interface, 0, sizeof(c->interface));
                c->superspeed = 0;
                c->highspeed = 0;
                c->fullspeed = 0;
index 6bdb5706904497ca9eccb7fd5d979c67824d8600..3507f880eb74294c76ddbc43c3aa153528478f53 100644 (file)
@@ -315,7 +315,6 @@ static ssize_t ffs_ep0_write(struct file *file, const char __user *buf,
                                return ret;
                        }
 
-                       set_bit(FFS_FL_CALL_CLOSED_CALLBACK, &ffs->flags);
                        return len;
                }
                break;
@@ -847,7 +846,7 @@ static ssize_t ffs_epfile_io(struct file *file, struct ffs_io_data *io_data)
                                ret = ep->status;
                                if (io_data->read && ret > 0) {
                                        ret = copy_to_iter(data, ret, &io_data->data);
-                                       if (unlikely(iov_iter_count(&io_data->data)))
+                                       if (!ret)
                                                ret = -EFAULT;
                                }
                        }
@@ -1463,8 +1462,7 @@ static void ffs_data_clear(struct ffs_data *ffs)
 {
        ENTER();
 
-       if (test_and_clear_bit(FFS_FL_CALL_CLOSED_CALLBACK, &ffs->flags))
-               ffs_closed(ffs);
+       ffs_closed(ffs);
 
        BUG_ON(ffs->gadget);
 
@@ -3422,9 +3420,13 @@ static int ffs_ready(struct ffs_data *ffs)
        ffs_obj->desc_ready = true;
        ffs_obj->ffs_data = ffs;
 
-       if (ffs_obj->ffs_ready_callback)
+       if (ffs_obj->ffs_ready_callback) {
                ret = ffs_obj->ffs_ready_callback(ffs);
+               if (ret)
+                       goto done;
+       }
 
+       set_bit(FFS_FL_CALL_CLOSED_CALLBACK, &ffs->flags);
 done:
        ffs_dev_unlock();
        return ret;
@@ -3443,7 +3445,8 @@ static void ffs_closed(struct ffs_data *ffs)
 
        ffs_obj->desc_ready = false;
 
-       if (ffs_obj->ffs_closed_callback)
+       if (test_and_clear_bit(FFS_FL_CALL_CLOSED_CALLBACK, &ffs->flags) &&
+           ffs_obj->ffs_closed_callback)
                ffs_obj->ffs_closed_callback(ffs);
 
        if (!ffs_obj->opts || ffs_obj->opts->no_configfs
index 13dfc9915b1dee679b89f83a19ab3ef56641ae34..f7f35a36c09a06eab17ef2e5af013ee3de2b5b8e 100644 (file)
@@ -437,12 +437,20 @@ static int hidg_setup(struct usb_function *f,
                  | USB_REQ_GET_DESCRIPTOR):
                switch (value >> 8) {
                case HID_DT_HID:
+               {
+                       struct hid_descriptor hidg_desc_copy = hidg_desc;
+
                        VDBG(cdev, "USB_REQ_GET_DESCRIPTOR: HID\n");
+                       hidg_desc_copy.desc[0].bDescriptorType = HID_DT_REPORT;
+                       hidg_desc_copy.desc[0].wDescriptorLength =
+                               cpu_to_le16(hidg->report_desc_length);
+
                        length = min_t(unsigned short, length,
-                                                  hidg_desc.bLength);
-                       memcpy(req->buf, &hidg_desc, length);
+                                                  hidg_desc_copy.bLength);
+                       memcpy(req->buf, &hidg_desc_copy, length);
                        goto respond;
                        break;
+               }
                case HID_DT_REPORT:
                        VDBG(cdev, "USB_REQ_GET_DESCRIPTOR: REPORT\n");
                        length = min_t(unsigned short, length,
@@ -632,6 +640,10 @@ static int hidg_bind(struct usb_configuration *c, struct usb_function *f)
        hidg_fs_in_ep_desc.wMaxPacketSize = cpu_to_le16(hidg->report_length);
        hidg_hs_out_ep_desc.wMaxPacketSize = cpu_to_le16(hidg->report_length);
        hidg_fs_out_ep_desc.wMaxPacketSize = cpu_to_le16(hidg->report_length);
+       /*
+        * We can use hidg_desc struct here but we should not relay
+        * that its content won't change after returning from this function.
+        */
        hidg_desc.desc[0].bDescriptorType = HID_DT_REPORT;
        hidg_desc.desc[0].wDescriptorLength =
                cpu_to_le16(hidg->report_desc_length);
index 259b656c0b3ec7bde9e119488f46ded351bb7300..6316aa5b1c4947a6df2e08b4c45856dc77b94374 100644 (file)
@@ -973,7 +973,13 @@ static ssize_t f_midi_opts_id_show(struct f_midi_opts *opts, char *page)
        int result;
 
        mutex_lock(&opts->lock);
-       result = strlcpy(page, opts->id, PAGE_SIZE);
+       if (opts->id) {
+               result = strlcpy(page, opts->id, PAGE_SIZE);
+       } else {
+               page[0] = 0;
+               result = 0;
+       }
+
        mutex_unlock(&opts->lock);
 
        return result;
index 9719abfb61455ca91ec5d1721e53622d4b76f1ef..7856b3394494b7d4250637277dd1f42f45d7a1ea 100644 (file)
@@ -588,7 +588,10 @@ static int f_audio_set_alt(struct usb_function *f, unsigned intf, unsigned alt)
 
        if (intf == 1) {
                if (alt == 1) {
-                       config_ep_by_speed(cdev->gadget, f, out_ep);
+                       err = config_ep_by_speed(cdev->gadget, f, out_ep);
+                       if (err)
+                               return err;
+
                        usb_ep_enable(out_ep);
                        out_ep->driver_data = audio;
                        audio->copy_buf = f_audio_buffer_alloc(audio_buf_size);
index 89179ab20c109277a3d49c48b7d91d85eb821f4c..7ee057930ae71793bcbd2777cb275572af21c295 100644 (file)
@@ -113,6 +113,7 @@ struct gs_port {
        int write_allocated;
        struct gs_buf           port_write_buf;
        wait_queue_head_t       drain_wait;     /* wait while writes drain */
+       bool                    write_busy;
 
        /* REVISIT this state ... */
        struct usb_cdc_line_coding port_line_coding;    /* 8-N-1 etc */
@@ -363,7 +364,7 @@ __acquires(&port->port_lock)
        int                     status = 0;
        bool                    do_tty_wake = false;
 
-       while (!list_empty(pool)) {
+       while (!port->write_busy && !list_empty(pool)) {
                struct usb_request      *req;
                int                     len;
 
@@ -393,9 +394,11 @@ __acquires(&port->port_lock)
                 * NOTE that we may keep sending data for a while after
                 * the TTY closed (dev->ioport->port_tty is NULL).
                 */
+               port->write_busy = true;
                spin_unlock(&port->port_lock);
                status = usb_ep_queue(in, req, GFP_ATOMIC);
                spin_lock(&port->port_lock);
+               port->write_busy = false;
 
                if (status) {
                        pr_debug("%s: %s %s err %d\n",
index c30b7b572465d290b8cc6097915d63fd596aa79d..1194b09ae7462638d689eb99af6a15bd209c9e9e 100644 (file)
@@ -121,7 +121,7 @@ static struct usb_function *f_msg;
 /*
  * We _always_ have both ACM and mass storage functions.
  */
-static int __init acm_ms_do_config(struct usb_configuration *c)
+static int acm_ms_do_config(struct usb_configuration *c)
 {
        struct fsg_opts *opts;
        int     status;
@@ -174,7 +174,7 @@ static struct usb_configuration acm_ms_config_driver = {
 
 /*-------------------------------------------------------------------------*/
 
-static int __init acm_ms_bind(struct usb_composite_dev *cdev)
+static int acm_ms_bind(struct usb_composite_dev *cdev)
 {
        struct usb_gadget       *gadget = cdev->gadget;
        struct fsg_opts         *opts;
@@ -249,7 +249,7 @@ fail_get_msg:
        return status;
 }
 
-static int __exit acm_ms_unbind(struct usb_composite_dev *cdev)
+static int acm_ms_unbind(struct usb_composite_dev *cdev)
 {
        usb_put_function(f_msg);
        usb_put_function_instance(fi_msg);
@@ -258,13 +258,13 @@ static int __exit acm_ms_unbind(struct usb_composite_dev *cdev)
        return 0;
 }
 
-static __refdata struct usb_composite_driver acm_ms_driver = {
+static struct usb_composite_driver acm_ms_driver = {
        .name           = "g_acm_ms",
        .dev            = &device_desc,
        .max_speed      = USB_SPEED_SUPER,
        .strings        = dev_strings,
        .bind           = acm_ms_bind,
-       .unbind         = __exit_p(acm_ms_unbind),
+       .unbind         = acm_ms_unbind,
 };
 
 module_usb_composite_driver(acm_ms_driver);
index f46a3956e43d1f334d9dafd2d3055aa99eee5b58..f289caf18a45341dc613a676345bfe8eeb51ee8e 100644 (file)
@@ -167,7 +167,7 @@ static const struct usb_descriptor_header *otg_desc[] = {
 
 /*-------------------------------------------------------------------------*/
 
-static int __init audio_do_config(struct usb_configuration *c)
+static int audio_do_config(struct usb_configuration *c)
 {
        int status;
 
@@ -216,7 +216,7 @@ static struct usb_configuration audio_config_driver = {
 
 /*-------------------------------------------------------------------------*/
 
-static int __init audio_bind(struct usb_composite_dev *cdev)
+static int audio_bind(struct usb_composite_dev *cdev)
 {
 #ifndef CONFIG_GADGET_UAC1
        struct f_uac2_opts      *uac2_opts;
@@ -276,7 +276,7 @@ fail:
        return status;
 }
 
-static int __exit audio_unbind(struct usb_composite_dev *cdev)
+static int audio_unbind(struct usb_composite_dev *cdev)
 {
 #ifdef CONFIG_GADGET_UAC1
        if (!IS_ERR_OR_NULL(f_uac1))
@@ -292,13 +292,13 @@ static int __exit audio_unbind(struct usb_composite_dev *cdev)
        return 0;
 }
 
-static __refdata struct usb_composite_driver audio_driver = {
+static struct usb_composite_driver audio_driver = {
        .name           = "g_audio",
        .dev            = &device_desc,
        .strings        = audio_strings,
        .max_speed      = USB_SPEED_HIGH,
        .bind           = audio_bind,
-       .unbind         = __exit_p(audio_unbind),
+       .unbind         = audio_unbind,
 };
 
 module_usb_composite_driver(audio_driver);
index 2e85d947347830b5b09ddf70b43631c85b2489d8..afd3e37921a7d9f1cc879cda5fe64ac5f940b6fa 100644 (file)
@@ -104,7 +104,7 @@ static struct usb_function_instance *fi_ecm;
 /*
  * We _always_ have both CDC ECM and CDC ACM functions.
  */
-static int __init cdc_do_config(struct usb_configuration *c)
+static int cdc_do_config(struct usb_configuration *c)
 {
        int     status;
 
@@ -153,7 +153,7 @@ static struct usb_configuration cdc_config_driver = {
 
 /*-------------------------------------------------------------------------*/
 
-static int __init cdc_bind(struct usb_composite_dev *cdev)
+static int cdc_bind(struct usb_composite_dev *cdev)
 {
        struct usb_gadget       *gadget = cdev->gadget;
        struct f_ecm_opts       *ecm_opts;
@@ -211,7 +211,7 @@ fail:
        return status;
 }
 
-static int __exit cdc_unbind(struct usb_composite_dev *cdev)
+static int cdc_unbind(struct usb_composite_dev *cdev)
 {
        usb_put_function(f_acm);
        usb_put_function_instance(fi_serial);
@@ -222,13 +222,13 @@ static int __exit cdc_unbind(struct usb_composite_dev *cdev)
        return 0;
 }
 
-static __refdata struct usb_composite_driver cdc_driver = {
+static struct usb_composite_driver cdc_driver = {
        .name           = "g_cdc",
        .dev            = &device_desc,
        .strings        = dev_strings,
        .max_speed      = USB_SPEED_HIGH,
        .bind           = cdc_bind,
-       .unbind         = __exit_p(cdc_unbind),
+       .unbind         = cdc_unbind,
 };
 
 module_usb_composite_driver(cdc_driver);
index 633683a72a1169d95ee9f553efde929e9bf48808..204b10b1a7e7dd08c36bc00d44205e0c6753b1c2 100644 (file)
@@ -284,7 +284,7 @@ fail_1:
        return -ENODEV;
 }
 
-static int __init dbgp_bind(struct usb_gadget *gadget,
+static int dbgp_bind(struct usb_gadget *gadget,
                struct usb_gadget_driver *driver)
 {
        int err, stp;
@@ -406,7 +406,7 @@ fail:
        return err;
 }
 
-static __refdata struct usb_gadget_driver dbgp_driver = {
+static struct usb_gadget_driver dbgp_driver = {
        .function = "dbgp",
        .max_speed = USB_SPEED_HIGH,
        .bind = dbgp_bind,
index c5fdc61cdc4a6bcf1684d005fddb7f34e2971bb6..a3323dca218f9514b4c2a5e4319d9866c950d8e5 100644 (file)
@@ -222,7 +222,7 @@ static struct usb_function *f_rndis;
  * the first one present.  That's to make Microsoft's drivers happy,
  * and to follow DOCSIS 1.0 (cable modem standard).
  */
-static int __init rndis_do_config(struct usb_configuration *c)
+static int rndis_do_config(struct usb_configuration *c)
 {
        int status;
 
@@ -264,7 +264,7 @@ MODULE_PARM_DESC(use_eem, "use CDC EEM mode");
 /*
  * We _always_ have an ECM, CDC Subset, or EEM configuration.
  */
-static int __init eth_do_config(struct usb_configuration *c)
+static int eth_do_config(struct usb_configuration *c)
 {
        int status = 0;
 
@@ -318,7 +318,7 @@ static struct usb_configuration eth_config_driver = {
 
 /*-------------------------------------------------------------------------*/
 
-static int __init eth_bind(struct usb_composite_dev *cdev)
+static int eth_bind(struct usb_composite_dev *cdev)
 {
        struct usb_gadget       *gadget = cdev->gadget;
        struct f_eem_opts       *eem_opts = NULL;
@@ -447,7 +447,7 @@ fail:
        return status;
 }
 
-static int __exit eth_unbind(struct usb_composite_dev *cdev)
+static int eth_unbind(struct usb_composite_dev *cdev)
 {
        if (has_rndis()) {
                usb_put_function(f_rndis);
@@ -466,13 +466,13 @@ static int __exit eth_unbind(struct usb_composite_dev *cdev)
        return 0;
 }
 
-static __refdata struct usb_composite_driver eth_driver = {
+static struct usb_composite_driver eth_driver = {
        .name           = "g_ether",
        .dev            = &device_desc,
        .strings        = dev_strings,
        .max_speed      = USB_SPEED_SUPER,
        .bind           = eth_bind,
-       .unbind         = __exit_p(eth_unbind),
+       .unbind         = eth_unbind,
 };
 
 module_usb_composite_driver(eth_driver);
index b01b88e1b716a5902d5276196ef459663545a216..e821931c965cd9203a8011358ffeb16844dc7eed 100644 (file)
@@ -163,7 +163,7 @@ static int gfs_unbind(struct usb_composite_dev *cdev);
 static int gfs_do_config(struct usb_configuration *c);
 
 
-static __refdata struct usb_composite_driver gfs_driver = {
+static struct usb_composite_driver gfs_driver = {
        .name           = DRIVER_NAME,
        .dev            = &gfs_dev_desc,
        .strings        = gfs_dev_strings,
@@ -304,8 +304,10 @@ static int functionfs_ready_callback(struct ffs_data *ffs)
        gfs_registered = true;
 
        ret = usb_composite_probe(&gfs_driver);
-       if (unlikely(ret < 0))
+       if (unlikely(ret < 0)) {
+               ++missing_funcs;
                gfs_registered = false;
+       }
        
        return ret;
 }
index e02a095294ac24fe0640555839d37e57833a13bd..da19c486b61e33a5b3214830f1c5db42ed979a75 100644 (file)
@@ -118,7 +118,7 @@ static struct usb_gadget_strings *dev_strings[] = {
 static struct usb_function_instance *fi_midi;
 static struct usb_function *f_midi;
 
-static int __exit midi_unbind(struct usb_composite_dev *dev)
+static int midi_unbind(struct usb_composite_dev *dev)
 {
        usb_put_function(f_midi);
        usb_put_function_instance(fi_midi);
@@ -133,7 +133,7 @@ static struct usb_configuration midi_config = {
        .MaxPower       = CONFIG_USB_GADGET_VBUS_DRAW,
 };
 
-static int __init midi_bind_config(struct usb_configuration *c)
+static int midi_bind_config(struct usb_configuration *c)
 {
        int status;
 
@@ -150,7 +150,7 @@ static int __init midi_bind_config(struct usb_configuration *c)
        return 0;
 }
 
-static int __init midi_bind(struct usb_composite_dev *cdev)
+static int midi_bind(struct usb_composite_dev *cdev)
 {
        struct f_midi_opts *midi_opts;
        int status;
@@ -185,13 +185,13 @@ put:
        return status;
 }
 
-static __refdata struct usb_composite_driver midi_driver = {
+static struct usb_composite_driver midi_driver = {
        .name           = (char *) longname,
        .dev            = &device_desc,
        .strings        = dev_strings,
        .max_speed      = USB_SPEED_HIGH,
        .bind           = midi_bind,
-       .unbind         = __exit_p(midi_unbind),
+       .unbind         = midi_unbind,
 };
 
 module_usb_composite_driver(midi_driver);
index 614b06d80b4122c0b469dc898b5a251551667e69..2baa572686c6acbd5e1350ab167b65a367482302 100644 (file)
@@ -106,7 +106,7 @@ static struct usb_gadget_strings *dev_strings[] = {
 
 /****************************** Configurations ******************************/
 
-static int __init do_config(struct usb_configuration *c)
+static int do_config(struct usb_configuration *c)
 {
        struct hidg_func_node *e, *n;
        int status = 0;
@@ -147,7 +147,7 @@ static struct usb_configuration config_driver = {
 
 /****************************** Gadget Bind ******************************/
 
-static int __init hid_bind(struct usb_composite_dev *cdev)
+static int hid_bind(struct usb_composite_dev *cdev)
 {
        struct usb_gadget *gadget = cdev->gadget;
        struct list_head *tmp;
@@ -205,7 +205,7 @@ put:
        return status;
 }
 
-static int __exit hid_unbind(struct usb_composite_dev *cdev)
+static int hid_unbind(struct usb_composite_dev *cdev)
 {
        struct hidg_func_node *n;
 
@@ -216,7 +216,7 @@ static int __exit hid_unbind(struct usb_composite_dev *cdev)
        return 0;
 }
 
-static int __init hidg_plat_driver_probe(struct platform_device *pdev)
+static int hidg_plat_driver_probe(struct platform_device *pdev)
 {
        struct hidg_func_descriptor *func = dev_get_platdata(&pdev->dev);
        struct hidg_func_node *entry;
@@ -252,13 +252,13 @@ static int hidg_plat_driver_remove(struct platform_device *pdev)
 /****************************** Some noise ******************************/
 
 
-static __refdata struct usb_composite_driver hidg_driver = {
+static struct usb_composite_driver hidg_driver = {
        .name           = "g_hid",
        .dev            = &device_desc,
        .strings        = dev_strings,
        .max_speed      = USB_SPEED_HIGH,
        .bind           = hid_bind,
-       .unbind         = __exit_p(hid_unbind),
+       .unbind         = hid_unbind,
 };
 
 static struct platform_driver hidg_plat_driver = {
index 8e27a8c9644470bfa8d5b44fc95a198aeda7214f..e7bfb081f111e4b60e55bce9ae5cd5f0743dad20 100644 (file)
@@ -130,7 +130,7 @@ static int msg_thread_exits(struct fsg_common *common)
        return 0;
 }
 
-static int __init msg_do_config(struct usb_configuration *c)
+static int msg_do_config(struct usb_configuration *c)
 {
        struct fsg_opts *opts;
        int ret;
@@ -170,7 +170,7 @@ static struct usb_configuration msg_config_driver = {
 
 /****************************** Gadget Bind ******************************/
 
-static int __init msg_bind(struct usb_composite_dev *cdev)
+static int msg_bind(struct usb_composite_dev *cdev)
 {
        static const struct fsg_operations ops = {
                .thread_exits = msg_thread_exits,
@@ -248,7 +248,7 @@ static int msg_unbind(struct usb_composite_dev *cdev)
 
 /****************************** Some noise ******************************/
 
-static __refdata struct usb_composite_driver msg_driver = {
+static struct usb_composite_driver msg_driver = {
        .name           = "g_mass_storage",
        .dev            = &msg_device_desc,
        .max_speed      = USB_SPEED_SUPER,
index 39d27bb343b410fc8eae1c6aefb59bc2bb1fe0d5..b21b51f0c9fadb27bbe319791ad970502eb88aa3 100644 (file)
@@ -149,7 +149,7 @@ static struct usb_function *f_acm_rndis;
 static struct usb_function *f_rndis;
 static struct usb_function *f_msg_rndis;
 
-static __init int rndis_do_config(struct usb_configuration *c)
+static int rndis_do_config(struct usb_configuration *c)
 {
        struct fsg_opts *fsg_opts;
        int ret;
@@ -237,7 +237,7 @@ static struct usb_function *f_acm_multi;
 static struct usb_function *f_ecm;
 static struct usb_function *f_msg_multi;
 
-static __init int cdc_do_config(struct usb_configuration *c)
+static int cdc_do_config(struct usb_configuration *c)
 {
        struct fsg_opts *fsg_opts;
        int ret;
@@ -466,7 +466,7 @@ fail:
        return status;
 }
 
-static int __exit multi_unbind(struct usb_composite_dev *cdev)
+static int multi_unbind(struct usb_composite_dev *cdev)
 {
 #ifdef CONFIG_USB_G_MULTI_CDC
        usb_put_function(f_msg_multi);
@@ -497,13 +497,13 @@ static int __exit multi_unbind(struct usb_composite_dev *cdev)
 /****************************** Some noise ******************************/
 
 
-static __refdata struct usb_composite_driver multi_driver = {
+static struct usb_composite_driver multi_driver = {
        .name           = "g_multi",
        .dev            = &device_desc,
        .strings        = dev_strings,
        .max_speed      = USB_SPEED_HIGH,
        .bind           = multi_bind,
-       .unbind         = __exit_p(multi_unbind),
+       .unbind         = multi_unbind,
        .needs_serial   = 1,
 };
 
index e90e23db2acba192330741b9219c5d28e6a94b38..6ce7421412e9c14d7766210ab3442d06ca8f49d6 100644 (file)
@@ -107,7 +107,7 @@ static struct usb_function *f_ncm;
 
 /*-------------------------------------------------------------------------*/
 
-static int __init ncm_do_config(struct usb_configuration *c)
+static int ncm_do_config(struct usb_configuration *c)
 {
        int status;
 
@@ -143,7 +143,7 @@ static struct usb_configuration ncm_config_driver = {
 
 /*-------------------------------------------------------------------------*/
 
-static int __init gncm_bind(struct usb_composite_dev *cdev)
+static int gncm_bind(struct usb_composite_dev *cdev)
 {
        struct usb_gadget       *gadget = cdev->gadget;
        struct f_ncm_opts       *ncm_opts;
@@ -186,7 +186,7 @@ fail:
        return status;
 }
 
-static int __exit gncm_unbind(struct usb_composite_dev *cdev)
+static int gncm_unbind(struct usb_composite_dev *cdev)
 {
        if (!IS_ERR_OR_NULL(f_ncm))
                usb_put_function(f_ncm);
@@ -195,13 +195,13 @@ static int __exit gncm_unbind(struct usb_composite_dev *cdev)
        return 0;
 }
 
-static __refdata struct usb_composite_driver ncm_driver = {
+static struct usb_composite_driver ncm_driver = {
        .name           = "g_ncm",
        .dev            = &device_desc,
        .strings        = dev_strings,
        .max_speed      = USB_SPEED_HIGH,
        .bind           = gncm_bind,
-       .unbind         = __exit_p(gncm_unbind),
+       .unbind         = gncm_unbind,
 };
 
 module_usb_composite_driver(ncm_driver);
index 9b8fd701648ced489d50ab562e8a8288afaf1125..4bb498a38a1c01eb17077844bc163028c3e22b93 100644 (file)
@@ -118,7 +118,7 @@ static struct usb_function_instance *fi_obex1;
 static struct usb_function_instance *fi_obex2;
 static struct usb_function_instance *fi_phonet;
 
-static int __init nokia_bind_config(struct usb_configuration *c)
+static int nokia_bind_config(struct usb_configuration *c)
 {
        struct usb_function *f_acm;
        struct usb_function *f_phonet = NULL;
@@ -224,7 +224,7 @@ err_get_acm:
        return status;
 }
 
-static int __init nokia_bind(struct usb_composite_dev *cdev)
+static int nokia_bind(struct usb_composite_dev *cdev)
 {
        struct usb_gadget       *gadget = cdev->gadget;
        int                     status;
@@ -307,7 +307,7 @@ err_usb:
        return status;
 }
 
-static int __exit nokia_unbind(struct usb_composite_dev *cdev)
+static int nokia_unbind(struct usb_composite_dev *cdev)
 {
        if (!IS_ERR_OR_NULL(f_obex1_cfg2))
                usb_put_function(f_obex1_cfg2);
@@ -338,13 +338,13 @@ static int __exit nokia_unbind(struct usb_composite_dev *cdev)
        return 0;
 }
 
-static __refdata struct usb_composite_driver nokia_driver = {
+static struct usb_composite_driver nokia_driver = {
        .name           = "g_nokia",
        .dev            = &device_desc,
        .strings        = dev_strings,
        .max_speed      = USB_SPEED_HIGH,
        .bind           = nokia_bind,
-       .unbind         = __exit_p(nokia_unbind),
+       .unbind         = nokia_unbind,
 };
 
 module_usb_composite_driver(nokia_driver);
index d5b6ee725a2ac04030ac52fc4b4e9c93477a90b6..1ce7df1060a5b237ae2532f514d95e3edd63cf34 100644 (file)
@@ -126,7 +126,7 @@ static struct usb_configuration printer_cfg_driver = {
        .bmAttributes           = USB_CONFIG_ATT_ONE | USB_CONFIG_ATT_SELFPOWER,
 };
 
-static int __init printer_do_config(struct usb_configuration *c)
+static int printer_do_config(struct usb_configuration *c)
 {
        struct usb_gadget       *gadget = c->cdev->gadget;
        int                     status = 0;
@@ -152,7 +152,7 @@ static int __init printer_do_config(struct usb_configuration *c)
        return status;
 }
 
-static int __init printer_bind(struct usb_composite_dev *cdev)
+static int printer_bind(struct usb_composite_dev *cdev)
 {
        struct f_printer_opts *opts;
        int ret, len;
@@ -191,7 +191,7 @@ static int __init printer_bind(struct usb_composite_dev *cdev)
        return ret;
 }
 
-static int __exit printer_unbind(struct usb_composite_dev *cdev)
+static int printer_unbind(struct usb_composite_dev *cdev)
 {
        usb_put_function(f_printer);
        usb_put_function_instance(fi_printer);
@@ -199,7 +199,7 @@ static int __exit printer_unbind(struct usb_composite_dev *cdev)
        return 0;
 }
 
-static __refdata struct usb_composite_driver printer_driver = {
+static struct usb_composite_driver printer_driver = {
        .name           = shortname,
        .dev            = &device_desc,
        .strings        = dev_strings,
index 1f5f978d35d5318be56d1e069750d42e18b6b3c5..8b7528f9b78eff02a7d20bca4122429d6294be6d 100644 (file)
@@ -174,7 +174,7 @@ out:
        return ret;
 }
 
-static int __init gs_bind(struct usb_composite_dev *cdev)
+static int gs_bind(struct usb_composite_dev *cdev)
 {
        int                     status;
 
@@ -230,7 +230,7 @@ static int gs_unbind(struct usb_composite_dev *cdev)
        return 0;
 }
 
-static __refdata struct usb_composite_driver gserial_driver = {
+static struct usb_composite_driver gserial_driver = {
        .name           = "g_serial",
        .dev            = &device_desc,
        .strings        = dev_strings,
index 8b80addc4ce6a5aaae4a330f4e27abd3ea67c5f8..f9b4882fce528f7cd6fa04ec66d90109a3a12047 100644 (file)
@@ -2397,7 +2397,7 @@ static int usb_target_bind(struct usb_composite_dev *cdev)
        return 0;
 }
 
-static __refdata struct usb_composite_driver usbg_driver = {
+static struct usb_composite_driver usbg_driver = {
        .name           = "g_target",
        .dev            = &usbg_device_desc,
        .strings        = usbg_strings,
index 04a3da20f74248442f6cabdbb4853db2b0f4f3b9..72c976bf3530f595115a9536267069c50e13aeba 100644 (file)
@@ -334,7 +334,7 @@ static const struct uvc_descriptor_header * const uvc_ss_streaming_cls[] = {
  * USB configuration
  */
 
-static int __init
+static int
 webcam_config_bind(struct usb_configuration *c)
 {
        int status = 0;
@@ -358,7 +358,7 @@ static struct usb_configuration webcam_config_driver = {
        .MaxPower               = CONFIG_USB_GADGET_VBUS_DRAW,
 };
 
-static int /* __init_or_exit */
+static int
 webcam_unbind(struct usb_composite_dev *cdev)
 {
        if (!IS_ERR_OR_NULL(f_uvc))
@@ -368,7 +368,7 @@ webcam_unbind(struct usb_composite_dev *cdev)
        return 0;
 }
 
-static int __init
+static int
 webcam_bind(struct usb_composite_dev *cdev)
 {
        struct f_uvc_opts *uvc_opts;
@@ -422,7 +422,7 @@ error:
  * Driver
  */
 
-static __refdata struct usb_composite_driver webcam_driver = {
+static struct usb_composite_driver webcam_driver = {
        .name           = "g_webcam",
        .dev            = &webcam_device_descriptor,
        .strings        = webcam_device_strings,
index 5ee95152493c2b6b0be74257cc437bdb560f250b..c986e8addb90ac809428f780e04cfb9242c22a90 100644 (file)
@@ -272,7 +272,7 @@ static struct usb_function_instance *func_inst_lb;
 module_param_named(qlen, gzero_options.qlen, uint, S_IRUGO|S_IWUSR);
 MODULE_PARM_DESC(qlen, "depth of loopback queue");
 
-static int __init zero_bind(struct usb_composite_dev *cdev)
+static int zero_bind(struct usb_composite_dev *cdev)
 {
        struct f_ss_opts        *ss_opts;
        struct f_lb_opts        *lb_opts;
@@ -400,7 +400,7 @@ static int zero_unbind(struct usb_composite_dev *cdev)
        return 0;
 }
 
-static __refdata struct usb_composite_driver zero_driver = {
+static struct usb_composite_driver zero_driver = {
        .name           = "zero",
        .dev            = &device_desc,
        .strings        = dev_strings,
index 2fbedca3c2b4eb80a19325c3bcc54913df6a7c27..fc4226462f8f5da2f71741a77093b7d69343afe3 100644 (file)
@@ -1942,7 +1942,7 @@ err_unprepare_fclk:
        return retval;
 }
 
-static int __exit at91udc_remove(struct platform_device *pdev)
+static int at91udc_remove(struct platform_device *pdev)
 {
        struct at91_udc *udc = platform_get_drvdata(pdev);
        unsigned long   flags;
@@ -2018,7 +2018,7 @@ static int at91udc_resume(struct platform_device *pdev)
 #endif
 
 static struct platform_driver at91_udc_driver = {
-       .remove         = __exit_p(at91udc_remove),
+       .remove         = at91udc_remove,
        .shutdown       = at91udc_shutdown,
        .suspend        = at91udc_suspend,
        .resume         = at91udc_resume,
index 4c01953a0869cf67693ec2842d48b508770927a2..351d48550c332af0768e43912f0d21069fbf8ea4 100644 (file)
@@ -2186,7 +2186,7 @@ static int usba_udc_probe(struct platform_device *pdev)
        return 0;
 }
 
-static int __exit usba_udc_remove(struct platform_device *pdev)
+static int usba_udc_remove(struct platform_device *pdev)
 {
        struct usba_udc *udc;
        int i;
@@ -2258,7 +2258,7 @@ static int usba_udc_resume(struct device *dev)
 static SIMPLE_DEV_PM_OPS(usba_udc_pm_ops, usba_udc_suspend, usba_udc_resume);
 
 static struct platform_driver udc_driver = {
-       .remove         = __exit_p(usba_udc_remove),
+       .remove         = usba_udc_remove,
        .driver         = {
                .name           = "atmel_usba_udc",
                .pm             = &usba_udc_pm_ops,
index 55fcb930f92e404252620e14cd3556314287714e..c60022b46a4835b4cc2b151b7a46193fe0f5554b 100644 (file)
@@ -2525,7 +2525,7 @@ err_kfree:
 /* Driver removal function
  * Free resources and finish pending transactions
  */
-static int __exit fsl_udc_remove(struct platform_device *pdev)
+static int fsl_udc_remove(struct platform_device *pdev)
 {
        struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
        struct fsl_usb2_platform_data *pdata = dev_get_platdata(&pdev->dev);
@@ -2663,7 +2663,7 @@ static const struct platform_device_id fsl_udc_devtype[] = {
 };
 MODULE_DEVICE_TABLE(platform, fsl_udc_devtype);
 static struct platform_driver udc_driver = {
-       .remove         = __exit_p(fsl_udc_remove),
+       .remove         = fsl_udc_remove,
        /* Just for FSL i.mx SoC currently */
        .id_table       = fsl_udc_devtype,
        /* these suspend and resume are not usb suspend and resume */
index fb4df159d32d59cb81c8cdbbfd9b33b3aa1d8d89..3970f453de4903fb55c21831e4cb511b2a2afc11 100644 (file)
@@ -1342,7 +1342,7 @@ static const struct usb_gadget_ops fusb300_gadget_ops = {
        .udc_stop       = fusb300_udc_stop,
 };
 
-static int __exit fusb300_remove(struct platform_device *pdev)
+static int fusb300_remove(struct platform_device *pdev)
 {
        struct fusb300 *fusb300 = platform_get_drvdata(pdev);
 
@@ -1492,7 +1492,7 @@ clean_up:
 }
 
 static struct platform_driver fusb300_driver = {
-       .remove =       __exit_p(fusb300_remove),
+       .remove =       fusb300_remove,
        .driver         = {
                .name = (char *) udc_name,
        },
index 8c7c83c937139b084b48dba9a548683c865481d2..309706fe4bf0ab0fd61d37a492a2bef0d73deb2a 100644 (file)
@@ -1528,7 +1528,7 @@ static const struct usb_gadget_ops m66592_gadget_ops = {
        .pullup                 = m66592_pullup,
 };
 
-static int __exit m66592_remove(struct platform_device *pdev)
+static int m66592_remove(struct platform_device *pdev)
 {
        struct m66592           *m66592 = platform_get_drvdata(pdev);
 
@@ -1695,7 +1695,7 @@ clean_up:
 
 /*-------------------------------------------------------------------------*/
 static struct platform_driver m66592_driver = {
-       .remove =       __exit_p(m66592_remove),
+       .remove =       m66592_remove,
        .driver         = {
                .name = (char *) udc_name,
        },
index 2495fe9c95c5855f0c18be45d6f58deb0cf21a45..0293f7169deeace9688bab19316b2bd04fa8641c 100644 (file)
@@ -1820,7 +1820,7 @@ static const struct usb_gadget_ops r8a66597_gadget_ops = {
        .set_selfpowered        = r8a66597_set_selfpowered,
 };
 
-static int __exit r8a66597_remove(struct platform_device *pdev)
+static int r8a66597_remove(struct platform_device *pdev)
 {
        struct r8a66597         *r8a66597 = platform_get_drvdata(pdev);
 
@@ -1974,7 +1974,7 @@ clean_up2:
 
 /*-------------------------------------------------------------------------*/
 static struct platform_driver r8a66597_driver = {
-       .remove =       __exit_p(r8a66597_remove),
+       .remove =       r8a66597_remove,
        .driver         = {
                .name = (char *) udc_name,
        },
index b808951491ccbfcdd949d8e78f7c1cc2b4c55f47..99fd9a5667dfd4997092d982c0beae28b578a17c 100644 (file)
@@ -1487,7 +1487,7 @@ static int s3c2410_udc_pullup(struct usb_gadget *gadget, int is_on)
 
        dprintk(DEBUG_NORMAL, "%s()\n", __func__);
 
-       s3c2410_udc_set_pullup(udc, is_on ? 0 : 1);
+       s3c2410_udc_set_pullup(udc, is_on);
        return 0;
 }
 
index dd3e9fd31b801fbc9b8e200930f2dfe814aed2d3..1f24274477ab9352ce582f96bfbfbdd61605d07e 100644 (file)
@@ -2071,8 +2071,8 @@ static int xudc_probe(struct platform_device *pdev)
        /* Map the registers */
        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
        udc->addr = devm_ioremap_resource(&pdev->dev, res);
-       if (!udc->addr)
-               return -ENOMEM;
+       if (IS_ERR(udc->addr))
+               return PTR_ERR(udc->addr);
 
        irq = platform_get_irq(pdev, 0);
        if (irq < 0) {
index 9db74ca7e5b98224dd9889a3a09e3a8e4941668c..275c92e53a5972615166310742b63af0a8d61cf5 100644 (file)
@@ -88,13 +88,20 @@ static int ehci_msm_probe(struct platform_device *pdev)
        }
 
        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       hcd->regs = devm_ioremap_resource(&pdev->dev, res);
-       if (IS_ERR(hcd->regs)) {
-               ret = PTR_ERR(hcd->regs);
+       if (!res) {
+               dev_err(&pdev->dev, "Unable to get memory resource\n");
+               ret = -ENODEV;
                goto put_hcd;
        }
+
        hcd->rsrc_start = res->start;
        hcd->rsrc_len = resource_size(res);
+       hcd->regs = devm_ioremap(&pdev->dev, hcd->rsrc_start, hcd->rsrc_len);
+       if (!hcd->regs) {
+               dev_err(&pdev->dev, "ioremap failed\n");
+               ret = -ENOMEM;
+               goto put_hcd;
+       }
 
        /*
         * OTG driver takes care of PHY initialization, clock management,
index f5397a517c54ce5a7df00b60e4b2482a2fd8b16c..7d34cbfaf373b54826cd0ffad697ef6f5d36c096 100644 (file)
@@ -2026,8 +2026,13 @@ static int process_isoc_td(struct xhci_hcd *xhci, struct xhci_td *td,
                break;
        case COMP_DEV_ERR:
        case COMP_STALL:
+               frame->status = -EPROTO;
+               skip_td = true;
+               break;
        case COMP_TX_ERR:
                frame->status = -EPROTO;
+               if (event_trb != td->last_trb)
+                       return 0;
                skip_td = true;
                break;
        case COMP_STOP:
@@ -2640,7 +2645,7 @@ irqreturn_t xhci_irq(struct usb_hcd *hcd)
                xhci_halt(xhci);
 hw_died:
                spin_unlock(&xhci->lock);
-               return -ESHUTDOWN;
+               return IRQ_HANDLED;
        }
 
        /*
index ec8ac16748547a2ac87bf9aa225ed0a36c0bf7df..36bf089b708fe5219258d46305719b7a999a23f6 100644 (file)
@@ -3682,18 +3682,21 @@ int xhci_alloc_dev(struct usb_hcd *hcd, struct usb_device *udev)
 {
        struct xhci_hcd *xhci = hcd_to_xhci(hcd);
        unsigned long flags;
-       int ret;
+       int ret, slot_id;
        struct xhci_command *command;
 
        command = xhci_alloc_command(xhci, false, false, GFP_KERNEL);
        if (!command)
                return 0;
 
+       /* xhci->slot_id and xhci->addr_dev are not thread-safe */
+       mutex_lock(&xhci->mutex);
        spin_lock_irqsave(&xhci->lock, flags);
        command->completion = &xhci->addr_dev;
        ret = xhci_queue_slot_control(xhci, command, TRB_ENABLE_SLOT, 0);
        if (ret) {
                spin_unlock_irqrestore(&xhci->lock, flags);
+               mutex_unlock(&xhci->mutex);
                xhci_dbg(xhci, "FIXME: allocate a command ring segment\n");
                kfree(command);
                return 0;
@@ -3702,8 +3705,10 @@ int xhci_alloc_dev(struct usb_hcd *hcd, struct usb_device *udev)
        spin_unlock_irqrestore(&xhci->lock, flags);
 
        wait_for_completion(command->completion);
+       slot_id = xhci->slot_id;
+       mutex_unlock(&xhci->mutex);
 
-       if (!xhci->slot_id || command->status != COMP_SUCCESS) {
+       if (!slot_id || command->status != COMP_SUCCESS) {
                xhci_err(xhci, "Error while assigning device slot ID\n");
                xhci_err(xhci, "Max number of devices this xHCI host supports is %u.\n",
                                HCS_MAX_SLOTS(
@@ -3728,11 +3733,11 @@ int xhci_alloc_dev(struct usb_hcd *hcd, struct usb_device *udev)
         * xhci_discover_or_reset_device(), which may be called as part of
         * mass storage driver error handling.
         */
-       if (!xhci_alloc_virt_device(xhci, xhci->slot_id, udev, GFP_NOIO)) {
+       if (!xhci_alloc_virt_device(xhci, slot_id, udev, GFP_NOIO)) {
                xhci_warn(xhci, "Could not allocate xHCI USB device data structures\n");
                goto disable_slot;
        }
-       udev->slot_id = xhci->slot_id;
+       udev->slot_id = slot_id;
 
 #ifndef CONFIG_USB_DEFAULT_PERSIST
        /*
@@ -3778,12 +3783,15 @@ static int xhci_setup_device(struct usb_hcd *hcd, struct usb_device *udev,
        struct xhci_slot_ctx *slot_ctx;
        struct xhci_input_control_ctx *ctrl_ctx;
        u64 temp_64;
-       struct xhci_command *command;
+       struct xhci_command *command = NULL;
+
+       mutex_lock(&xhci->mutex);
 
        if (!udev->slot_id) {
                xhci_dbg_trace(xhci, trace_xhci_dbg_address,
                                "Bad Slot ID %d", udev->slot_id);
-               return -EINVAL;
+               ret = -EINVAL;
+               goto out;
        }
 
        virt_dev = xhci->devs[udev->slot_id];
@@ -3796,7 +3804,8 @@ static int xhci_setup_device(struct usb_hcd *hcd, struct usb_device *udev,
                 */
                xhci_warn(xhci, "Virt dev invalid for slot_id 0x%x!\n",
                        udev->slot_id);
-               return -EINVAL;
+               ret = -EINVAL;
+               goto out;
        }
 
        if (setup == SETUP_CONTEXT_ONLY) {
@@ -3804,13 +3813,15 @@ static int xhci_setup_device(struct usb_hcd *hcd, struct usb_device *udev,
                if (GET_SLOT_STATE(le32_to_cpu(slot_ctx->dev_state)) ==
                    SLOT_STATE_DEFAULT) {
                        xhci_dbg(xhci, "Slot already in default state\n");
-                       return 0;
+                       goto out;
                }
        }
 
        command = xhci_alloc_command(xhci, false, false, GFP_KERNEL);
-       if (!command)
-               return -ENOMEM;
+       if (!command) {
+               ret = -ENOMEM;
+               goto out;
+       }
 
        command->in_ctx = virt_dev->in_ctx;
        command->completion = &xhci->addr_dev;
@@ -3820,8 +3831,8 @@ static int xhci_setup_device(struct usb_hcd *hcd, struct usb_device *udev,
        if (!ctrl_ctx) {
                xhci_warn(xhci, "%s: Could not get input context, bad type.\n",
                                __func__);
-               kfree(command);
-               return -EINVAL;
+               ret = -EINVAL;
+               goto out;
        }
        /*
         * If this is the first Set Address since device plug-in or
@@ -3848,8 +3859,7 @@ static int xhci_setup_device(struct usb_hcd *hcd, struct usb_device *udev,
                spin_unlock_irqrestore(&xhci->lock, flags);
                xhci_dbg_trace(xhci, trace_xhci_dbg_address,
                                "FIXME: allocate a command ring segment");
-               kfree(command);
-               return ret;
+               goto out;
        }
        xhci_ring_cmd_db(xhci);
        spin_unlock_irqrestore(&xhci->lock, flags);
@@ -3896,10 +3906,8 @@ static int xhci_setup_device(struct usb_hcd *hcd, struct usb_device *udev,
                ret = -EINVAL;
                break;
        }
-       if (ret) {
-               kfree(command);
-               return ret;
-       }
+       if (ret)
+               goto out;
        temp_64 = xhci_read_64(xhci, &xhci->op_regs->dcbaa_ptr);
        xhci_dbg_trace(xhci, trace_xhci_dbg_address,
                        "Op regs DCBAA ptr = %#016llx", temp_64);
@@ -3932,8 +3940,10 @@ static int xhci_setup_device(struct usb_hcd *hcd, struct usb_device *udev,
        xhci_dbg_trace(xhci, trace_xhci_dbg_address,
                       "Internal device address = %d",
                       le32_to_cpu(slot_ctx->dev_state) & DEV_ADDR_MASK);
+out:
+       mutex_unlock(&xhci->mutex);
        kfree(command);
-       return 0;
+       return ret;
 }
 
 int xhci_address_device(struct usb_hcd *hcd, struct usb_device *udev)
@@ -4855,6 +4865,7 @@ int xhci_gen_setup(struct usb_hcd *hcd, xhci_get_quirks_t get_quirks)
                return 0;
        }
 
+       mutex_init(&xhci->mutex);
        xhci->cap_regs = hcd->regs;
        xhci->op_regs = hcd->regs +
                HC_LENGTH(readl(&xhci->cap_regs->hc_capbase));
@@ -5011,4 +5022,12 @@ static int __init xhci_hcd_init(void)
        BUILD_BUG_ON(sizeof(struct xhci_run_regs) != (8+8*128)*32/8);
        return 0;
 }
+
+/*
+ * If an init function is provided, an exit function must also be provided
+ * to allow module unload.
+ */
+static void __exit xhci_hcd_fini(void) { }
+
 module_init(xhci_hcd_init);
+module_exit(xhci_hcd_fini);
index 8e421b89632ddaa4eaf30ee34ef60f89b7ac3e2d..6977f8491fa7ced6ea317bf75354a0eb7703670e 100644 (file)
@@ -1267,7 +1267,7 @@ union xhci_trb {
  * since the command ring is 64-byte aligned.
  * It must also be greater than 16.
  */
-#define TRBS_PER_SEGMENT       64
+#define TRBS_PER_SEGMENT       256
 /* Allow two commands + a link TRB, along with any reserved command TRBs */
 #define MAX_RSVD_CMD_TRBS      (TRBS_PER_SEGMENT - 3)
 #define TRB_SEGMENT_SIZE       (TRBS_PER_SEGMENT*16)
@@ -1497,6 +1497,8 @@ struct xhci_hcd {
        struct list_head        lpm_failed_devs;
 
        /* slot enabling and address device helpers */
+       /* these are not thread safe so use mutex */
+       struct mutex mutex;
        struct completion       addr_dev;
        int slot_id;
        /* For USB 3.0 LPM enable/disable. */
index 3789b08ef67b037781e278c41c0d4b2f2d33e5d9..6dca3d794ced6e1948dd5cbb180e708893f7ba83 100644 (file)
@@ -2021,13 +2021,7 @@ musb_init_controller(struct device *dev, int nIrq, void __iomem *ctrl)
        if (musb->ops->quirks)
                musb->io.quirks = musb->ops->quirks;
 
-       /* At least tusb6010 has it's own offsets.. */
-       if (musb->ops->ep_offset)
-               musb->io.ep_offset = musb->ops->ep_offset;
-       if (musb->ops->ep_select)
-               musb->io.ep_select = musb->ops->ep_select;
-
-       /* ..and some devices use indexed offset or flat offset */
+       /* Most devices use indexed offset or flat offset */
        if (musb->io.quirks & MUSB_INDEXED_EP) {
                musb->io.ep_offset = musb_indexed_ep_offset;
                musb->io.ep_select = musb_indexed_ep_select;
@@ -2036,6 +2030,12 @@ musb_init_controller(struct device *dev, int nIrq, void __iomem *ctrl)
                musb->io.ep_select = musb_flat_ep_select;
        }
 
+       /* At least tusb6010 has its own offsets */
+       if (musb->ops->ep_offset)
+               musb->io.ep_offset = musb->ops->ep_offset;
+       if (musb->ops->ep_select)
+               musb->io.ep_select = musb->ops->ep_select;
+
        if (musb->ops->fifo_mode)
                fifo_mode = musb->ops->fifo_mode;
        else
index 7225d526df0446ff26fd69ef65268265737d8c66..03ab0c699f74dd1768f2b769ca823eb7904132ab 100644 (file)
@@ -1179,7 +1179,7 @@ static int ab8500_usb_irq_setup(struct platform_device *pdev,
                }
                err = devm_request_threaded_irq(&pdev->dev, irq, NULL,
                                ab8500_usb_link_status_irq,
-                               IRQF_NO_SUSPEND | IRQF_SHARED,
+                               IRQF_NO_SUSPEND | IRQF_SHARED | IRQF_ONESHOT,
                                "usb-link-status", ab);
                if (err < 0) {
                        dev_err(ab->dev, "request_irq failed for link status irq\n");
@@ -1195,7 +1195,7 @@ static int ab8500_usb_irq_setup(struct platform_device *pdev,
                }
                err = devm_request_threaded_irq(&pdev->dev, irq, NULL,
                                ab8500_usb_disconnect_irq,
-                               IRQF_NO_SUSPEND | IRQF_SHARED,
+                               IRQF_NO_SUSPEND | IRQF_SHARED | IRQF_ONESHOT,
                                "usb-id-fall", ab);
                if (err < 0) {
                        dev_err(ab->dev, "request_irq failed for ID fall irq\n");
@@ -1211,7 +1211,7 @@ static int ab8500_usb_irq_setup(struct platform_device *pdev,
                }
                err = devm_request_threaded_irq(&pdev->dev, irq, NULL,
                                ab8500_usb_disconnect_irq,
-                               IRQF_NO_SUSPEND | IRQF_SHARED,
+                               IRQF_NO_SUSPEND | IRQF_SHARED | IRQF_ONESHOT,
                                "usb-vbus-fall", ab);
                if (err < 0) {
                        dev_err(ab->dev, "request_irq failed for Vbus fall irq\n");
index 1e0e10dd6ba51904b34bb32a9155cba7a5173f8f..3af263cc0caa3760a7a1704f329803e4951e62ae 100644 (file)
@@ -94,7 +94,7 @@ struct isp1301 {
 
 #if defined(CONFIG_MACH_OMAP_H2) || defined(CONFIG_MACH_OMAP_H3)
 
-#if    defined(CONFIG_TPS65010) || defined(CONFIG_TPS65010_MODULE)
+#if    defined(CONFIG_TPS65010) || (defined(CONFIG_TPS65010_MODULE) && defined(MODULE))
 
 #include <linux/i2c/tps65010.h>
 
index 845f658276b106342907c7606a078dbfa47d06d1..2b28443d07b92daed26660f1d80f0bd390937992 100644 (file)
@@ -401,7 +401,8 @@ static int tahvo_usb_probe(struct platform_device *pdev)
        dev_set_drvdata(&pdev->dev, tu);
 
        tu->irq = platform_get_irq(pdev, 0);
-       ret = request_threaded_irq(tu->irq, NULL, tahvo_usb_vbus_interrupt, 0,
+       ret = request_threaded_irq(tu->irq, NULL, tahvo_usb_vbus_interrupt,
+                                  IRQF_ONESHOT,
                                   "tahvo-vbus", tu);
        if (ret) {
                dev_err(&pdev->dev, "could not register tahvo-vbus irq: %d\n",
index 8597cf9cfceb7715883738ac8cf1c0380e9a00b1..c0f5c652d272c8959f5b3d59461e1af139d6f7fd 100644 (file)
@@ -611,6 +611,8 @@ struct usbhs_pkt_handle usbhs_fifo_pio_push_handler = {
 static int usbhsf_prepare_pop(struct usbhs_pkt *pkt, int *is_done)
 {
        struct usbhs_pipe *pipe = pkt->pipe;
+       struct usbhs_priv *priv = usbhs_pipe_to_priv(pipe);
+       struct usbhs_fifo *fifo = usbhsf_get_cfifo(priv);
 
        if (usbhs_pipe_is_busy(pipe))
                return 0;
@@ -624,6 +626,9 @@ static int usbhsf_prepare_pop(struct usbhs_pkt *pkt, int *is_done)
        usbhs_pipe_data_sequence(pipe, pkt->sequence);
        pkt->sequence = -1; /* -1 sequence will be ignored */
 
+       if (usbhs_pipe_is_dcp(pipe))
+               usbhsf_fifo_clear(pipe, fifo);
+
        usbhs_pipe_set_trans_count_if_bulk(pipe, pkt->length);
        usbhs_pipe_enable(pipe);
        usbhs_pipe_running(pipe, 1);
@@ -673,7 +678,14 @@ static int usbhsf_pio_try_pop(struct usbhs_pkt *pkt, int *is_done)
                *is_done = 1;
                usbhsf_rx_irq_ctrl(pipe, 0);
                usbhs_pipe_running(pipe, 0);
-               usbhs_pipe_disable(pipe);       /* disable pipe first */
+               /*
+                * If function mode, since this controller is possible to enter
+                * Control Write status stage at this timing, this driver
+                * should not disable the pipe. If such a case happens, this
+                * controller is not able to complete the status stage.
+                */
+               if (!usbhs_mod_is_host(priv) && !usbhs_pipe_is_dcp(pipe))
+                       usbhs_pipe_disable(pipe);       /* disable pipe first */
        }
 
        /*
@@ -1227,15 +1239,21 @@ static void usbhsf_dma_init_dt(struct device *dev, struct usbhs_fifo *fifo,
 {
        char name[16];
 
-       snprintf(name, sizeof(name), "tx%d", channel);
-       fifo->tx_chan = dma_request_slave_channel_reason(dev, name);
-       if (IS_ERR(fifo->tx_chan))
-               fifo->tx_chan = NULL;
-
-       snprintf(name, sizeof(name), "rx%d", channel);
-       fifo->rx_chan = dma_request_slave_channel_reason(dev, name);
-       if (IS_ERR(fifo->rx_chan))
-               fifo->rx_chan = NULL;
+       /*
+        * To avoid complex handing for DnFIFOs, the driver uses each
+        * DnFIFO as TX or RX direction (not bi-direction).
+        * So, the driver uses odd channels for TX, even channels for RX.
+        */
+       snprintf(name, sizeof(name), "ch%d", channel);
+       if (channel & 1) {
+               fifo->tx_chan = dma_request_slave_channel_reason(dev, name);
+               if (IS_ERR(fifo->tx_chan))
+                       fifo->tx_chan = NULL;
+       } else {
+               fifo->rx_chan = dma_request_slave_channel_reason(dev, name);
+               if (IS_ERR(fifo->rx_chan))
+                       fifo->rx_chan = NULL;
+       }
 }
 
 static void usbhsf_dma_init(struct usbhs_priv *priv, struct usbhs_fifo *fifo,
index 84ce2d74894c9c3b25c7bcf0185f23887492eb94..ffd739e31bfc193b058628560e86ea6f9b96f375 100644 (file)
@@ -127,6 +127,8 @@ static const struct usb_device_id id_table[] = {
        { USB_DEVICE(0x10C4, 0x88A5) }, /* Planet Innovation Ingeni ZigBee USB Device */
        { USB_DEVICE(0x10C4, 0x8946) }, /* Ketra N1 Wireless Interface */
        { USB_DEVICE(0x10C4, 0x8977) }, /* CEL MeshWorks DevKit Device */
+       { USB_DEVICE(0x10C4, 0x8998) }, /* KCF Technologies PRN */
+       { USB_DEVICE(0x10C4, 0x8A2A) }, /* HubZ dual ZigBee and Z-Wave dongle */
        { USB_DEVICE(0x10C4, 0xEA60) }, /* Silicon Labs factory default */
        { USB_DEVICE(0x10C4, 0xEA61) }, /* Silicon Labs factory default */
        { USB_DEVICE(0x10C4, 0xEA70) }, /* Silicon Labs factory default */
index 8eb68a31cab6c4021617ca555cd58b086872c112..4c8b3b82103d6318ea1d46250ad708bb3f722260 100644 (file)
@@ -699,6 +699,7 @@ static const struct usb_device_id id_table_combined[] = {
        { USB_DEVICE(XSENS_VID, XSENS_AWINDA_DONGLE_PID) },
        { USB_DEVICE(XSENS_VID, XSENS_AWINDA_STATION_PID) },
        { USB_DEVICE(XSENS_VID, XSENS_CONVERTER_PID) },
+       { USB_DEVICE(XSENS_VID, XSENS_MTDEVBOARD_PID) },
        { USB_DEVICE(XSENS_VID, XSENS_MTW_PID) },
        { USB_DEVICE(FTDI_VID, FTDI_OMNI1509) },
        { USB_DEVICE(MOBILITY_VID, MOBILITY_USB_SERIAL_PID) },
index 4e4f46f3c89c025670d42860756f39b2bb62ae24..792e054126de51402711814f5962945f7742e188 100644 (file)
 #define XSENS_AWINDA_STATION_PID 0x0101
 #define XSENS_AWINDA_DONGLE_PID 0x0102
 #define XSENS_MTW_PID          0x0200  /* Xsens MTw */
+#define XSENS_MTDEVBOARD_PID   0x0300  /* Motion Tracker Development Board */
 #define XSENS_CONVERTER_PID    0xD00D  /* Xsens USB-serial converter */
 
 /* Xsens devices using FTDI VID */
index 829604d11f3fa72a6b5bec5580f150c27c513cbf..f5257af33ecfbc30bb0989fe03fea09af215639e 100644 (file)
@@ -61,7 +61,6 @@ static const struct usb_device_id id_table[] = {
        { USB_DEVICE(DCU10_VENDOR_ID, DCU10_PRODUCT_ID) },
        { USB_DEVICE(SITECOM_VENDOR_ID, SITECOM_PRODUCT_ID) },
        { USB_DEVICE(ALCATEL_VENDOR_ID, ALCATEL_PRODUCT_ID) },
-       { USB_DEVICE(SAMSUNG_VENDOR_ID, SAMSUNG_PRODUCT_ID) },
        { USB_DEVICE(SIEMENS_VENDOR_ID, SIEMENS_PRODUCT_ID_SX1),
                .driver_info = PL2303_QUIRK_UART_STATE_IDX0 },
        { USB_DEVICE(SIEMENS_VENDOR_ID, SIEMENS_PRODUCT_ID_X65),
index 71fd9da1d6e7ac6e36ecdf38e8f8192c60fbbc39..e3b7af8adfb73ccefa92d4ba3c2c927a044dfa43 100644 (file)
 #define ALCATEL_VENDOR_ID      0x11f7
 #define ALCATEL_PRODUCT_ID     0x02df
 
-/* Samsung I330 phone cradle */
-#define SAMSUNG_VENDOR_ID      0x04e8
-#define SAMSUNG_PRODUCT_ID     0x8001
-
 #define SIEMENS_VENDOR_ID      0x11f5
 #define SIEMENS_PRODUCT_ID_SX1 0x0001
 #define SIEMENS_PRODUCT_ID_X65 0x0003
index bf2bd40e5f2ac7cdf1291caf1350f686925039bf..60afb39eb73c0b95d261ec367890a306621fd2de 100644 (file)
@@ -95,7 +95,7 @@ static const struct usb_device_id id_table[] = {
                .driver_info = (kernel_ulong_t)&palm_os_4_probe },
        { USB_DEVICE(ACER_VENDOR_ID, ACER_S10_ID),
                .driver_info = (kernel_ulong_t)&palm_os_4_probe },
-       { USB_DEVICE(SAMSUNG_VENDOR_ID, SAMSUNG_SCH_I330_ID),
+       { USB_DEVICE_INTERFACE_CLASS(SAMSUNG_VENDOR_ID, SAMSUNG_SCH_I330_ID, 0xff),
                .driver_info = (kernel_ulong_t)&palm_os_4_probe },
        { USB_DEVICE(SAMSUNG_VENDOR_ID, SAMSUNG_SPH_I500_ID),
                .driver_info = (kernel_ulong_t)&palm_os_4_probe },
index 9893d696fc973e9e4183b57b56b3ceb22570942f..f58caa9e6a27e6e1a7161a66e5e9a97698cc1e1a 100644 (file)
@@ -51,7 +51,8 @@ static int uas_find_endpoints(struct usb_host_interface *alt,
 }
 
 static int uas_use_uas_driver(struct usb_interface *intf,
-                             const struct usb_device_id *id)
+                             const struct usb_device_id *id,
+                             unsigned long *flags_ret)
 {
        struct usb_host_endpoint *eps[4] = { };
        struct usb_device *udev = interface_to_usbdev(intf);
@@ -73,7 +74,7 @@ static int uas_use_uas_driver(struct usb_interface *intf,
         * this writing the following versions exist:
         * ASM1051 - no uas support version
         * ASM1051 - with broken (*) uas support
-        * ASM1053 - with working uas support
+        * ASM1053 - with working uas support, but problems with large xfers
         * ASM1153 - with working uas support
         *
         * Devices with these chips re-use a number of device-ids over the
@@ -103,6 +104,9 @@ static int uas_use_uas_driver(struct usb_interface *intf,
                } else if (usb_ss_max_streams(&eps[1]->ss_ep_comp) == 32) {
                        /* Possibly an ASM1051, disable uas */
                        flags |= US_FL_IGNORE_UAS;
+               } else {
+                       /* ASM1053, these have issues with large transfers */
+                       flags |= US_FL_MAX_SECTORS_240;
                }
        }
 
@@ -132,5 +136,8 @@ static int uas_use_uas_driver(struct usb_interface *intf,
                return 0;
        }
 
+       if (flags_ret)
+               *flags_ret = flags;
+
        return 1;
 }
index 6cdabdc119a73bc172d5b2e52f024113bde09d3b..6d3122afeed33e9cfe1b571c3acaf19dac967da4 100644 (file)
@@ -759,7 +759,10 @@ static int uas_eh_bus_reset_handler(struct scsi_cmnd *cmnd)
 
 static int uas_slave_alloc(struct scsi_device *sdev)
 {
-       sdev->hostdata = (void *)sdev->host->hostdata;
+       struct uas_dev_info *devinfo =
+               (struct uas_dev_info *)sdev->host->hostdata;
+
+       sdev->hostdata = devinfo;
 
        /* USB has unusual DMA-alignment requirements: Although the
         * starting address of each scatter-gather element doesn't matter,
@@ -778,6 +781,11 @@ static int uas_slave_alloc(struct scsi_device *sdev)
         */
        blk_queue_update_dma_alignment(sdev->request_queue, (512 - 1));
 
+       if (devinfo->flags & US_FL_MAX_SECTORS_64)
+               blk_queue_max_hw_sectors(sdev->request_queue, 64);
+       else if (devinfo->flags & US_FL_MAX_SECTORS_240)
+               blk_queue_max_hw_sectors(sdev->request_queue, 240);
+
        return 0;
 }
 
@@ -887,8 +895,9 @@ static int uas_probe(struct usb_interface *intf, const struct usb_device_id *id)
        struct Scsi_Host *shost = NULL;
        struct uas_dev_info *devinfo;
        struct usb_device *udev = interface_to_usbdev(intf);
+       unsigned long dev_flags;
 
-       if (!uas_use_uas_driver(intf, id))
+       if (!uas_use_uas_driver(intf, id, &dev_flags))
                return -ENODEV;
 
        if (uas_switch_interface(udev, intf))
@@ -910,8 +919,7 @@ static int uas_probe(struct usb_interface *intf, const struct usb_device_id *id)
        devinfo->udev = udev;
        devinfo->resetting = 0;
        devinfo->shutdown = 0;
-       devinfo->flags = id->driver_info;
-       usb_stor_adjust_quirks(udev, &devinfo->flags);
+       devinfo->flags = dev_flags;
        init_usb_anchor(&devinfo->cmd_urbs);
        init_usb_anchor(&devinfo->sense_urbs);
        init_usb_anchor(&devinfo->data_urbs);
index d684b4b8108ff34a5c4023088d9e927dcb378f6b..caf188800c679e7f24fc329903848a8c1f64d41a 100644 (file)
@@ -766,6 +766,13 @@ UNUSUAL_DEV(  0x059f, 0x0643, 0x0000, 0x0000,
                USB_SC_DEVICE, USB_PR_DEVICE, NULL,
                US_FL_GO_SLOW ),
 
+/* Reported by Christian Schaller <cschalle@redhat.com> */
+UNUSUAL_DEV(  0x059f, 0x0651, 0x0000, 0x0000,
+               "LaCie",
+               "External HDD",
+               USB_SC_DEVICE, USB_PR_DEVICE, NULL,
+               US_FL_NO_WP_DETECT ),
+
 /* Submitted by Joel Bourquard <numlock@freesurf.ch>
  * Some versions of this device need the SubClass and Protocol overrides
  * while others don't.
index 5600c33fcadb219e52e8f985bf692c6ff3a1025e..6c10c888f35fb976b94b1ea3fddd61c4bcabe520 100644 (file)
@@ -479,7 +479,8 @@ void usb_stor_adjust_quirks(struct usb_device *udev, unsigned long *fflags)
                        US_FL_SINGLE_LUN | US_FL_NO_WP_DETECT |
                        US_FL_NO_READ_DISC_INFO | US_FL_NO_READ_CAPACITY_16 |
                        US_FL_INITIAL_READ10 | US_FL_WRITE_CACHE |
-                       US_FL_NO_ATA_1X | US_FL_NO_REPORT_OPCODES);
+                       US_FL_NO_ATA_1X | US_FL_NO_REPORT_OPCODES |
+                       US_FL_MAX_SECTORS_240);
 
        p = quirks;
        while (*p) {
@@ -520,6 +521,9 @@ void usb_stor_adjust_quirks(struct usb_device *udev, unsigned long *fflags)
                case 'f':
                        f |= US_FL_NO_REPORT_OPCODES;
                        break;
+               case 'g':
+                       f |= US_FL_MAX_SECTORS_240;
+                       break;
                case 'h':
                        f |= US_FL_CAPACITY_HEURISTICS;
                        break;
@@ -1080,7 +1084,7 @@ static int storage_probe(struct usb_interface *intf,
 
        /* If uas is enabled and this device can do uas then ignore it. */
 #if IS_ENABLED(CONFIG_USB_UAS)
-       if (uas_use_uas_driver(intf, id))
+       if (uas_use_uas_driver(intf, id, NULL))
                return -ENXIO;
 #endif
 
index 69fab0fd15aec4a5cb05c870984dc7e4bc9dcad4..e9851add6f4ef251defba65a3bab9af359b60b3a 100644 (file)
@@ -907,8 +907,14 @@ static void vfio_pci_request(void *device_data, unsigned int count)
        mutex_lock(&vdev->igate);
 
        if (vdev->req_trigger) {
-               dev_dbg(&vdev->pdev->dev, "Requesting device from user\n");
+               if (!(count % 10))
+                       dev_notice_ratelimited(&vdev->pdev->dev,
+                               "Relaying device request to user (#%u)\n",
+                               count);
                eventfd_signal(vdev->req_trigger, 1);
+       } else if (count == 0) {
+               dev_warn(&vdev->pdev->dev,
+                       "No device request channel registered, blocked until released by user\n");
        }
 
        mutex_unlock(&vdev->igate);
index 0d336625ac7113b0e0cc10d4a9d00283cc673766..e1278fe04b1e7ba16eddbece247c21620b6e8fb7 100644 (file)
@@ -710,6 +710,8 @@ void *vfio_del_group_dev(struct device *dev)
        void *device_data = device->device_data;
        struct vfio_unbound_dev *unbound;
        unsigned int i = 0;
+       long ret;
+       bool interrupted = false;
 
        /*
         * The group exists so long as we have a device reference.  Get
@@ -755,9 +757,22 @@ void *vfio_del_group_dev(struct device *dev)
 
                vfio_device_put(device);
 
-       } while (wait_event_interruptible_timeout(vfio.release_q,
-                                                 !vfio_dev_present(group, dev),
-                                                 HZ * 10) <= 0);
+               if (interrupted) {
+                       ret = wait_event_timeout(vfio.release_q,
+                                       !vfio_dev_present(group, dev), HZ * 10);
+               } else {
+                       ret = wait_event_interruptible_timeout(vfio.release_q,
+                                       !vfio_dev_present(group, dev), HZ * 10);
+                       if (ret == -ERESTARTSYS) {
+                               interrupted = true;
+                               dev_warn(dev,
+                                        "Device is currently in use, task"
+                                        " \"%s\" (%d) "
+                                        "blocked until device is released",
+                                        current->comm, task_pid_nr(current));
+                       }
+               }
+       } while (ret <= 0);
 
        vfio_group_put(group);
 
index 5e19bb53b3a99a4ccc93696bf9792a4f4f1ad7c4..ea32b386797f5d52b70ee6f4028f5e8df43f3a8f 100644 (file)
@@ -1409,8 +1409,7 @@ vhost_scsi_set_endpoint(struct vhost_scsi *vs,
                         * dependency now.
                         */
                        se_tpg = &tpg->se_tpg;
-                       ret = configfs_depend_item(se_tpg->se_tpg_tfo->tf_subsys,
-                                                  &se_tpg->tpg_group.cg_item);
+                       ret = target_depend_item(&se_tpg->tpg_group.cg_item);
                        if (ret) {
                                pr_warn("configfs_depend_item() failed: %d\n", ret);
                                kfree(vs_tpg);
@@ -1513,8 +1512,7 @@ vhost_scsi_clear_endpoint(struct vhost_scsi *vs,
                 * to allow vhost-scsi WWPN se_tpg->tpg_group shutdown to occur.
                 */
                se_tpg = &tpg->se_tpg;
-               configfs_undepend_item(se_tpg->se_tpg_tfo->tf_subsys,
-                                      &se_tpg->tpg_group.cg_item);
+               target_undepend_item(&se_tpg->tpg_group.cg_item);
        }
        if (match) {
                for (i = 0; i < VHOST_SCSI_MAX_VQ; i++) {
index 3a145a643e0d5185146001275b47d3d0cc745454..6897f1c1bc732efe36632895fcedc577b7292a33 100644 (file)
@@ -274,6 +274,10 @@ static int pwm_backlight_probe(struct platform_device *pdev)
 
        pb->pwm = devm_pwm_get(&pdev->dev, NULL);
        if (IS_ERR(pb->pwm)) {
+               ret = PTR_ERR(pb->pwm);
+               if (ret == -EPROBE_DEFER)
+                       goto err_alloc;
+
                dev_err(&pdev->dev, "unable to request PWM, trying legacy API\n");
                pb->legacy = true;
                pb->pwm = pwm_request(data->pwm_id, "pwm-backlight");
index e894eb278d8336d018d3e6e8c29556dc9b5f3cb5..eba1b7ac729454d30b1d611cd01d45b5ba23407e 100644 (file)
@@ -423,6 +423,7 @@ int vp_set_vq_affinity(struct virtqueue *vq, int cpu)
                if (cpu == -1)
                        irq_set_affinity_hint(irq, NULL);
                else {
+                       cpumask_clear(mask);
                        cpumask_set_cpu(cpu, mask);
                        irq_set_affinity_hint(irq, mask);
                }
index 5db43fc100a413bf0ee55676d2b359e4db94e7ec..7dd46312c18023c6e9ca6db16fba107c79a9bb84 100644 (file)
@@ -345,6 +345,15 @@ irqreturn_t xen_debug_interrupt(int irq, void *dev_id)
        return IRQ_HANDLED;
 }
 
+static void evtchn_2l_resume(void)
+{
+       int i;
+
+       for_each_online_cpu(i)
+               memset(per_cpu(cpu_evtchn_mask, i), 0, sizeof(xen_ulong_t) *
+                               EVTCHN_2L_NR_CHANNELS/BITS_PER_EVTCHN_WORD);
+}
+
 static const struct evtchn_ops evtchn_ops_2l = {
        .max_channels      = evtchn_2l_max_channels,
        .nr_channels       = evtchn_2l_max_channels,
@@ -356,6 +365,7 @@ static const struct evtchn_ops evtchn_ops_2l = {
        .mask              = evtchn_2l_mask,
        .unmask            = evtchn_2l_unmask,
        .handle_events     = evtchn_2l_handle_events,
+       .resume            = evtchn_2l_resume,
 };
 
 void __init xen_evtchn_2l_init(void)
index 70fba973a107165c2c29b2104d8f4d438faddc2b..38387950490eb8dbd07c85434ac59e5129af2c1f 100644 (file)
@@ -529,8 +529,8 @@ static unsigned int __startup_pirq(unsigned int irq)
        if (rc)
                goto err;
 
-       bind_evtchn_to_cpu(evtchn, 0);
        info->evtchn = evtchn;
+       bind_evtchn_to_cpu(evtchn, 0);
 
        rc = xen_evtchn_port_setup(info);
        if (rc)
@@ -957,7 +957,7 @@ unsigned xen_evtchn_nr_channels(void)
 }
 EXPORT_SYMBOL_GPL(xen_evtchn_nr_channels);
 
-int bind_virq_to_irq(unsigned int virq, unsigned int cpu)
+int bind_virq_to_irq(unsigned int virq, unsigned int cpu, bool percpu)
 {
        struct evtchn_bind_virq bind_virq;
        int evtchn, irq, ret;
@@ -971,8 +971,12 @@ int bind_virq_to_irq(unsigned int virq, unsigned int cpu)
                if (irq < 0)
                        goto out;
 
-               irq_set_chip_and_handler_name(irq, &xen_percpu_chip,
-                                             handle_percpu_irq, "virq");
+               if (percpu)
+                       irq_set_chip_and_handler_name(irq, &xen_percpu_chip,
+                                                     handle_percpu_irq, "virq");
+               else
+                       irq_set_chip_and_handler_name(irq, &xen_dynamic_chip,
+                                                     handle_edge_irq, "virq");
 
                bind_virq.virq = virq;
                bind_virq.vcpu = cpu;
@@ -1062,7 +1066,7 @@ int bind_virq_to_irqhandler(unsigned int virq, unsigned int cpu,
 {
        int irq, retval;
 
-       irq = bind_virq_to_irq(virq, cpu);
+       irq = bind_virq_to_irq(virq, cpu, irqflags & IRQF_PERCPU);
        if (irq < 0)
                return irq;
        retval = request_irq(irq, handler, irqflags, devname, dev_id);
@@ -1279,8 +1283,9 @@ void rebind_evtchn_irq(int evtchn, int irq)
 
        mutex_unlock(&irq_mapping_update_lock);
 
-       /* new event channels are always bound to cpu 0 */
-       irq_set_affinity(irq, cpumask_of(0));
+        bind_evtchn_to_cpu(evtchn, info->cpu);
+       /* This will be deferred until interrupt is processed */
+       irq_set_affinity(irq, cpumask_of(info->cpu));
 
        /* Unmask the event channel. */
        enable_irq(irq);
index d5bb1a33d0a3fc7337975734f4305038c1959723..89274850741b5e3ee457fa2bd19d6efaf16d1f5d 100644 (file)
@@ -327,30 +327,10 @@ static int map_grant_pages(struct grant_map *map)
        return err;
 }
 
-struct unmap_grant_pages_callback_data
-{
-       struct completion completion;
-       int result;
-};
-
-static void unmap_grant_callback(int result,
-                                struct gntab_unmap_queue_data *data)
-{
-       struct unmap_grant_pages_callback_data* d = data->data;
-
-       d->result = result;
-       complete(&d->completion);
-}
-
 static int __unmap_grant_pages(struct grant_map *map, int offset, int pages)
 {
        int i, err = 0;
        struct gntab_unmap_queue_data unmap_data;
-       struct unmap_grant_pages_callback_data data;
-
-       init_completion(&data.completion);
-       unmap_data.data = &data;
-       unmap_data.done= &unmap_grant_callback;
 
        if (map->notify.flags & UNMAP_NOTIFY_CLEAR_BYTE) {
                int pgno = (map->notify.addr >> PAGE_SHIFT);
@@ -367,11 +347,9 @@ static int __unmap_grant_pages(struct grant_map *map, int offset, int pages)
        unmap_data.pages = map->pages + offset;
        unmap_data.count = pages;
 
-       gnttab_unmap_refs_async(&unmap_data);
-
-       wait_for_completion(&data.completion);
-       if (data.result)
-               return data.result;
+       err = gnttab_unmap_refs_sync(&unmap_data);
+       if (err)
+               return err;
 
        for (i = 0; i < pages; i++) {
                if (map->unmap_ops[offset+i].status)
index 17972fbacddc41d34122c5af816461bd6b99effd..b1c7170e5c9e1edf85049c4d43fc4d1b9f2b18f8 100644 (file)
@@ -123,6 +123,11 @@ struct gnttab_ops {
        int (*query_foreign_access)(grant_ref_t ref);
 };
 
+struct unmap_refs_callback_data {
+       struct completion completion;
+       int result;
+};
+
 static struct gnttab_ops *gnttab_interface;
 
 static int grant_table_version;
@@ -863,6 +868,29 @@ void gnttab_unmap_refs_async(struct gntab_unmap_queue_data* item)
 }
 EXPORT_SYMBOL_GPL(gnttab_unmap_refs_async);
 
+static void unmap_refs_callback(int result,
+               struct gntab_unmap_queue_data *data)
+{
+       struct unmap_refs_callback_data *d = data->data;
+
+       d->result = result;
+       complete(&d->completion);
+}
+
+int gnttab_unmap_refs_sync(struct gntab_unmap_queue_data *item)
+{
+       struct unmap_refs_callback_data data;
+
+       init_completion(&data.completion);
+       item->data = &data;
+       item->done = &unmap_refs_callback;
+       gnttab_unmap_refs_async(item);
+       wait_for_completion(&data.completion);
+
+       return data.result;
+}
+EXPORT_SYMBOL_GPL(gnttab_unmap_refs_sync);
+
 static int gnttab_map_frames_v1(xen_pfn_t *frames, unsigned int nr_gframes)
 {
        int rc;
index bf1940706422fe1c2dd334cf28096294ab74e542..9e6a85104a20820ff16ef748804eb8c6a98b4201 100644 (file)
@@ -131,6 +131,8 @@ static void do_suspend(void)
                goto out_resume;
        }
 
+       xen_arch_suspend();
+
        si.cancelled = 1;
 
        err = stop_machine(xen_suspend, &si, cpumask_of(0));
@@ -148,11 +150,12 @@ static void do_suspend(void)
                si.cancelled = 1;
        }
 
+       xen_arch_resume();
+
 out_resume:
-       if (!si.cancelled) {
-               xen_arch_resume();
+       if (!si.cancelled)
                xs_resume();
-       else
+       else
                xs_suspend_cancel();
 
        dpm_resume_end(si.cancelled ? PMSG_THAW : PMSG_RESTORE);
index 810ad419e34ca76ef3f2d0444e789d579dea1b9e..4c549323c605d97591224050b00add55e3a833a0 100644 (file)
@@ -235,7 +235,7 @@ retry:
 #define SLABS_PER_PAGE (1 << (PAGE_SHIFT - IO_TLB_SHIFT))
 #define IO_TLB_MIN_SLABS ((1<<20) >> IO_TLB_SHIFT)
                while ((SLABS_PER_PAGE << order) > IO_TLB_MIN_SLABS) {
-                       xen_io_tlb_start = (void *)__get_free_pages(__GFP_NOWARN, order);
+                       xen_io_tlb_start = (void *)xen_get_swiotlb_free_pages(order);
                        if (xen_io_tlb_start)
                                break;
                        order--;
index 75fe3d466515a08cf8ec8da7eebafd8c5b903895..9c234209d8b52d44d6483397f33a190fa2899c90 100644 (file)
@@ -16,8 +16,8 @@
 #include "conf_space.h"
 #include "conf_space_quirks.h"
 
-bool permissive;
-module_param(permissive, bool, 0644);
+bool xen_pcibk_permissive;
+module_param_named(permissive, xen_pcibk_permissive, bool, 0644);
 
 /* This is where xen_pcibk_read_config_byte, xen_pcibk_read_config_word,
  * xen_pcibk_write_config_word, and xen_pcibk_write_config_byte are created. */
@@ -262,7 +262,7 @@ int xen_pcibk_config_write(struct pci_dev *dev, int offset, int size, u32 value)
                 * This means that some fields may still be read-only because
                 * they have entries in the config_field list that intercept
                 * the write and do nothing. */
-               if (dev_data->permissive || permissive) {
+               if (dev_data->permissive || xen_pcibk_permissive) {
                        switch (size) {
                        case 1:
                                err = pci_write_config_byte(dev, offset,
index 2e1d73d1d5d09393ebf7e2ab21a026b709e5bb5f..62461a8ba1d6bbfbf9e6de2e98a8230ebc67ff3e 100644 (file)
@@ -64,7 +64,7 @@ struct config_field_entry {
        void *data;
 };
 
-extern bool permissive;
+extern bool xen_pcibk_permissive;
 
 #define OFFSET(cfg_entry) ((cfg_entry)->base_offset+(cfg_entry)->field->offset)
 
index c2260a0456c94fa1f73b6ef96777b4565aaef61e..ad3d17d29c81171838d01a2f1a081c769407f02d 100644 (file)
@@ -118,7 +118,7 @@ static int command_write(struct pci_dev *dev, int offset, u16 value, void *data)
 
        cmd->val = value;
 
-       if (!permissive && (!dev_data || !dev_data->permissive))
+       if (!xen_pcibk_permissive && (!dev_data || !dev_data->permissive))
                return 0;
 
        /* Only allow the guest to control certain bits. */
index 564b31584860432634a898a8fce9c7dc155a6662..5390a674b5e3a8d8ea62112343be83a34be58547 100644 (file)
@@ -57,6 +57,7 @@
 #include <xen/xen.h>
 #include <xen/xenbus.h>
 #include <xen/events.h>
+#include <xen/xen-ops.h>
 #include <xen/page.h>
 
 #include <xen/hvm.h>
@@ -735,6 +736,30 @@ static int __init xenstored_local_init(void)
        return err;
 }
 
+static int xenbus_resume_cb(struct notifier_block *nb,
+                           unsigned long action, void *data)
+{
+       int err = 0;
+
+       if (xen_hvm_domain()) {
+               uint64_t v;
+
+               err = hvm_get_parameter(HVM_PARAM_STORE_EVTCHN, &v);
+               if (!err && v)
+                       xen_store_evtchn = v;
+               else
+                       pr_warn("Cannot update xenstore event channel: %d\n",
+                               err);
+       } else
+               xen_store_evtchn = xen_start_info->store_evtchn;
+
+       return err;
+}
+
+static struct notifier_block xenbus_resume_nb = {
+       .notifier_call = xenbus_resume_cb,
+};
+
 static int __init xenbus_init(void)
 {
        int err = 0;
@@ -793,6 +818,10 @@ static int __init xenbus_init(void)
                goto out_error;
        }
 
+       if ((xen_store_domain_type != XS_LOCAL) &&
+           (xen_store_domain_type != XS_UNKNOWN))
+               xen_resume_notifier_register(&xenbus_resume_nb);
+
 #ifdef CONFIG_XEN_COMPAT_XENFS
        /*
         * Create xenfs mountpoint in /proc for compatibility with
index 241ef68d28930a7faed26f18b67b296138e61d9e..cd46e415883090747d8238c2a2fbaa9b101dbc5e 100644 (file)
@@ -918,7 +918,7 @@ static int load_elf_binary(struct linux_binprm *bprm)
                        total_size = total_mapping_size(elf_phdata,
                                                        loc->elf_ex.e_phnum);
                        if (!total_size) {
-                               error = -EINVAL;
+                               retval = -EINVAL;
                                goto out_free_dentry;
                        }
                }
index 9de772ee0031707c59292ac7849520ef8d6e9e47..614aaa1969bdfded3485ae9a72146269dd9101eb 100644 (file)
@@ -880,6 +880,8 @@ static int __add_keyed_refs(struct btrfs_fs_info *fs_info,
  * indirect refs to their parent bytenr.
  * When roots are found, they're added to the roots list
  *
+ * NOTE: This can return values > 0
+ *
  * FIXME some caching might speed things up
  */
 static int find_parent_nodes(struct btrfs_trans_handle *trans,
@@ -1198,6 +1200,19 @@ int btrfs_find_all_roots(struct btrfs_trans_handle *trans,
        return ret;
 }
 
+/**
+ * btrfs_check_shared - tell us whether an extent is shared
+ *
+ * @trans: optional trans handle
+ *
+ * btrfs_check_shared uses the backref walking code but will short
+ * circuit as soon as it finds a root or inode that doesn't match the
+ * one passed in. This provides a significant performance benefit for
+ * callers (such as fiemap) which want to know whether the extent is
+ * shared but do not need a ref count.
+ *
+ * Return: 0 if extent is not shared, 1 if it is shared, < 0 on error.
+ */
 int btrfs_check_shared(struct btrfs_trans_handle *trans,
                       struct btrfs_fs_info *fs_info, u64 root_objectid,
                       u64 inum, u64 bytenr)
@@ -1226,11 +1241,13 @@ int btrfs_check_shared(struct btrfs_trans_handle *trans,
                ret = find_parent_nodes(trans, fs_info, bytenr, elem.seq, tmp,
                                        roots, NULL, root_objectid, inum);
                if (ret == BACKREF_FOUND_SHARED) {
+                       /* this is the only condition under which we return 1 */
                        ret = 1;
                        break;
                }
                if (ret < 0 && ret != -ENOENT)
                        break;
+               ret = 0;
                node = ulist_next(tmp, &uiter);
                if (!node)
                        break;
index cde698a07d210f446ba4562c7a09647515610176..a2ae42720a6afe92701de402b837d56dd66d03b4 100644 (file)
@@ -1802,6 +1802,8 @@ int btrfs_fill_inode(struct inode *inode, u32 *rdev)
        set_nlink(inode, btrfs_stack_inode_nlink(inode_item));
        inode_set_bytes(inode, btrfs_stack_inode_nbytes(inode_item));
        BTRFS_I(inode)->generation = btrfs_stack_inode_generation(inode_item);
+        BTRFS_I(inode)->last_trans = btrfs_stack_inode_transid(inode_item);
+
        inode->i_version = btrfs_stack_inode_sequence(inode_item);
        inode->i_rdev = 0;
        *rdev = btrfs_stack_inode_rdev(inode_item);
index 1eef4ee01d1a3c7fd78e4546dd1bd2570f9c7783..0ec3acd14cbf5e1273f331231f09165710d80d91 100644 (file)
@@ -3178,10 +3178,8 @@ static int write_one_cache_group(struct btrfs_trans_handle *trans,
        bi = btrfs_item_ptr_offset(leaf, path->slots[0]);
        write_extent_buffer(leaf, &cache->item, bi, sizeof(cache->item));
        btrfs_mark_buffer_dirty(leaf);
-       btrfs_release_path(path);
 fail:
-       if (ret)
-               btrfs_abort_transaction(trans, root, ret);
+       btrfs_release_path(path);
        return ret;
 
 }
@@ -3305,8 +3303,7 @@ again:
 
        spin_lock(&block_group->lock);
        if (block_group->cached != BTRFS_CACHE_FINISHED ||
-           !btrfs_test_opt(root, SPACE_CACHE) ||
-           block_group->delalloc_bytes) {
+           !btrfs_test_opt(root, SPACE_CACHE)) {
                /*
                 * don't bother trying to write stuff out _if_
                 * a) we're not cached,
@@ -3408,17 +3405,14 @@ int btrfs_start_dirty_block_groups(struct btrfs_trans_handle *trans,
        int loops = 0;
 
        spin_lock(&cur_trans->dirty_bgs_lock);
-       if (!list_empty(&cur_trans->dirty_bgs)) {
-               list_splice_init(&cur_trans->dirty_bgs, &dirty);
+       if (list_empty(&cur_trans->dirty_bgs)) {
+               spin_unlock(&cur_trans->dirty_bgs_lock);
+               return 0;
        }
+       list_splice_init(&cur_trans->dirty_bgs, &dirty);
        spin_unlock(&cur_trans->dirty_bgs_lock);
 
 again:
-       if (list_empty(&dirty)) {
-               btrfs_free_path(path);
-               return 0;
-       }
-
        /*
         * make sure all the block groups on our dirty list actually
         * exist
@@ -3431,18 +3425,16 @@ again:
                        return -ENOMEM;
        }
 
+       /*
+        * cache_write_mutex is here only to save us from balance or automatic
+        * removal of empty block groups deleting this block group while we are
+        * writing out the cache
+        */
+       mutex_lock(&trans->transaction->cache_write_mutex);
        while (!list_empty(&dirty)) {
                cache = list_first_entry(&dirty,
                                         struct btrfs_block_group_cache,
                                         dirty_list);
-
-               /*
-                * cache_write_mutex is here only to save us from balance
-                * deleting this block group while we are writing out the
-                * cache
-                */
-               mutex_lock(&trans->transaction->cache_write_mutex);
-
                /*
                 * this can happen if something re-dirties a block
                 * group that is already under IO.  Just wait for it to
@@ -3493,9 +3485,30 @@ again:
                                ret = 0;
                        }
                }
-               if (!ret)
+               if (!ret) {
                        ret = write_one_cache_group(trans, root, path, cache);
-               mutex_unlock(&trans->transaction->cache_write_mutex);
+                       /*
+                        * Our block group might still be attached to the list
+                        * of new block groups in the transaction handle of some
+                        * other task (struct btrfs_trans_handle->new_bgs). This
+                        * means its block group item isn't yet in the extent
+                        * tree. If this happens ignore the error, as we will
+                        * try again later in the critical section of the
+                        * transaction commit.
+                        */
+                       if (ret == -ENOENT) {
+                               ret = 0;
+                               spin_lock(&cur_trans->dirty_bgs_lock);
+                               if (list_empty(&cache->dirty_list)) {
+                                       list_add_tail(&cache->dirty_list,
+                                                     &cur_trans->dirty_bgs);
+                                       btrfs_get_block_group(cache);
+                               }
+                               spin_unlock(&cur_trans->dirty_bgs_lock);
+                       } else if (ret) {
+                               btrfs_abort_transaction(trans, root, ret);
+                       }
+               }
 
                /* if its not on the io list, we need to put the block group */
                if (should_put)
@@ -3503,7 +3516,16 @@ again:
 
                if (ret)
                        break;
+
+               /*
+                * Avoid blocking other tasks for too long. It might even save
+                * us from writing caches for block groups that are going to be
+                * removed.
+                */
+               mutex_unlock(&trans->transaction->cache_write_mutex);
+               mutex_lock(&trans->transaction->cache_write_mutex);
        }
+       mutex_unlock(&trans->transaction->cache_write_mutex);
 
        /*
         * go through delayed refs for all the stuff we've just kicked off
@@ -3514,8 +3536,15 @@ again:
                loops++;
                spin_lock(&cur_trans->dirty_bgs_lock);
                list_splice_init(&cur_trans->dirty_bgs, &dirty);
+               /*
+                * dirty_bgs_lock protects us from concurrent block group
+                * deletes too (not just cache_write_mutex).
+                */
+               if (!list_empty(&dirty)) {
+                       spin_unlock(&cur_trans->dirty_bgs_lock);
+                       goto again;
+               }
                spin_unlock(&cur_trans->dirty_bgs_lock);
-               goto again;
        }
 
        btrfs_free_path(path);
@@ -3588,8 +3617,11 @@ int btrfs_write_dirty_block_groups(struct btrfs_trans_handle *trans,
                                ret = 0;
                        }
                }
-               if (!ret)
+               if (!ret) {
                        ret = write_one_cache_group(trans, root, path, cache);
+                       if (ret)
+                               btrfs_abort_transaction(trans, root, ret);
+               }
 
                /* if its not on the io list, we need to put the block group */
                if (should_put)
@@ -7537,7 +7569,7 @@ static void unuse_block_rsv(struct btrfs_fs_info *fs_info,
  * returns the key for the extent through ins, and a tree buffer for
  * the first block of the extent through buf.
  *
- * returns the tree buffer or NULL.
+ * returns the tree buffer or an ERR_PTR on error.
  */
 struct extent_buffer *btrfs_alloc_tree_block(struct btrfs_trans_handle *trans,
                                        struct btrfs_root *root,
@@ -7548,6 +7580,7 @@ struct extent_buffer *btrfs_alloc_tree_block(struct btrfs_trans_handle *trans,
        struct btrfs_key ins;
        struct btrfs_block_rsv *block_rsv;
        struct extent_buffer *buf;
+       struct btrfs_delayed_extent_op *extent_op;
        u64 flags = 0;
        int ret;
        u32 blocksize = root->nodesize;
@@ -7568,13 +7601,14 @@ struct extent_buffer *btrfs_alloc_tree_block(struct btrfs_trans_handle *trans,
 
        ret = btrfs_reserve_extent(root, blocksize, blocksize,
                                   empty_size, hint, &ins, 0, 0);
-       if (ret) {
-               unuse_block_rsv(root->fs_info, block_rsv, blocksize);
-               return ERR_PTR(ret);
-       }
+       if (ret)
+               goto out_unuse;
 
        buf = btrfs_init_new_buffer(trans, root, ins.objectid, level);
-       BUG_ON(IS_ERR(buf)); /* -ENOMEM */
+       if (IS_ERR(buf)) {
+               ret = PTR_ERR(buf);
+               goto out_free_reserved;
+       }
 
        if (root_objectid == BTRFS_TREE_RELOC_OBJECTID) {
                if (parent == 0)
@@ -7584,9 +7618,11 @@ struct extent_buffer *btrfs_alloc_tree_block(struct btrfs_trans_handle *trans,
                BUG_ON(parent > 0);
 
        if (root_objectid != BTRFS_TREE_LOG_OBJECTID) {
-               struct btrfs_delayed_extent_op *extent_op;
                extent_op = btrfs_alloc_delayed_extent_op();
-               BUG_ON(!extent_op); /* -ENOMEM */
+               if (!extent_op) {
+                       ret = -ENOMEM;
+                       goto out_free_buf;
+               }
                if (key)
                        memcpy(&extent_op->key, key, sizeof(extent_op->key));
                else
@@ -7601,13 +7637,24 @@ struct extent_buffer *btrfs_alloc_tree_block(struct btrfs_trans_handle *trans,
                extent_op->level = level;
 
                ret = btrfs_add_delayed_tree_ref(root->fs_info, trans,
-                                       ins.objectid,
-                                       ins.offset, parent, root_objectid,
-                                       level, BTRFS_ADD_DELAYED_EXTENT,
-                                       extent_op, 0);
-               BUG_ON(ret); /* -ENOMEM */
+                                                ins.objectid, ins.offset,
+                                                parent, root_objectid, level,
+                                                BTRFS_ADD_DELAYED_EXTENT,
+                                                extent_op, 0);
+               if (ret)
+                       goto out_free_delayed;
        }
        return buf;
+
+out_free_delayed:
+       btrfs_free_delayed_extent_op(extent_op);
+out_free_buf:
+       free_extent_buffer(buf);
+out_free_reserved:
+       btrfs_free_reserved_extent(root, ins.objectid, ins.offset, 0);
+out_unuse:
+       unuse_block_rsv(root->fs_info, block_rsv, blocksize);
+       return ERR_PTR(ret);
 }
 
 struct walk_control {
@@ -8782,6 +8829,24 @@ again:
                goto again;
        }
 
+       /*
+        * if we are changing raid levels, try to allocate a corresponding
+        * block group with the new raid level.
+        */
+       alloc_flags = update_block_group_flags(root, cache->flags);
+       if (alloc_flags != cache->flags) {
+               ret = do_chunk_alloc(trans, root, alloc_flags,
+                                    CHUNK_ALLOC_FORCE);
+               /*
+                * ENOSPC is allowed here, we may have enough space
+                * already allocated at the new raid level to
+                * carry on
+                */
+               if (ret == -ENOSPC)
+                       ret = 0;
+               if (ret < 0)
+                       goto out;
+       }
 
        ret = set_block_group_ro(cache, 0);
        if (!ret)
@@ -8795,7 +8860,9 @@ again:
 out:
        if (cache->flags & BTRFS_BLOCK_GROUP_SYSTEM) {
                alloc_flags = update_block_group_flags(root, cache->flags);
+               lock_chunks(root->fs_info->chunk_root);
                check_system_chunk(trans, root, alloc_flags);
+               unlock_chunks(root->fs_info->chunk_root);
        }
        mutex_unlock(&root->fs_info->ro_block_group_mutex);
 
index 782f3bc4651d319529394b1ce29e20d58d01e62c..c32d226bfeccbb28f25f2f417fa9e57b14411136 100644 (file)
@@ -4560,36 +4560,37 @@ static void btrfs_release_extent_buffer_page(struct extent_buffer *eb)
        do {
                index--;
                page = eb->pages[index];
-               if (page && mapped) {
+               if (!page)
+                       continue;
+               if (mapped)
                        spin_lock(&page->mapping->private_lock);
+               /*
+                * We do this since we'll remove the pages after we've
+                * removed the eb from the radix tree, so we could race
+                * and have this page now attached to the new eb.  So
+                * only clear page_private if it's still connected to
+                * this eb.
+                */
+               if (PagePrivate(page) &&
+                   page->private == (unsigned long)eb) {
+                       BUG_ON(test_bit(EXTENT_BUFFER_DIRTY, &eb->bflags));
+                       BUG_ON(PageDirty(page));
+                       BUG_ON(PageWriteback(page));
                        /*
-                        * We do this since we'll remove the pages after we've
-                        * removed the eb from the radix tree, so we could race
-                        * and have this page now attached to the new eb.  So
-                        * only clear page_private if it's still connected to
-                        * this eb.
+                        * We need to make sure we haven't be attached
+                        * to a new eb.
                         */
-                       if (PagePrivate(page) &&
-                           page->private == (unsigned long)eb) {
-                               BUG_ON(test_bit(EXTENT_BUFFER_DIRTY, &eb->bflags));
-                               BUG_ON(PageDirty(page));
-                               BUG_ON(PageWriteback(page));
-                               /*
-                                * We need to make sure we haven't be attached
-                                * to a new eb.
-                                */
-                               ClearPagePrivate(page);
-                               set_page_private(page, 0);
-                               /* One for the page private */
-                               page_cache_release(page);
-                       }
-                       spin_unlock(&page->mapping->private_lock);
-
-               }
-               if (page) {
-                       /* One for when we alloced the page */
+                       ClearPagePrivate(page);
+                       set_page_private(page, 0);
+                       /* One for the page private */
                        page_cache_release(page);
                }
+
+               if (mapped)
+                       spin_unlock(&page->mapping->private_lock);
+
+               /* One for when we alloced the page */
+               page_cache_release(page);
        } while (index != 0);
 }
 
@@ -4771,6 +4772,25 @@ struct extent_buffer *find_extent_buffer(struct btrfs_fs_info *fs_info,
                               start >> PAGE_CACHE_SHIFT);
        if (eb && atomic_inc_not_zero(&eb->refs)) {
                rcu_read_unlock();
+               /*
+                * Lock our eb's refs_lock to avoid races with
+                * free_extent_buffer. When we get our eb it might be flagged
+                * with EXTENT_BUFFER_STALE and another task running
+                * free_extent_buffer might have seen that flag set,
+                * eb->refs == 2, that the buffer isn't under IO (dirty and
+                * writeback flags not set) and it's still in the tree (flag
+                * EXTENT_BUFFER_TREE_REF set), therefore being in the process
+                * of decrementing the extent buffer's reference count twice.
+                * So here we could race and increment the eb's reference count,
+                * clear its stale flag, mark it as dirty and drop our reference
+                * before the other task finishes executing free_extent_buffer,
+                * which would later result in an attempt to free an extent
+                * buffer that is dirty.
+                */
+               if (test_bit(EXTENT_BUFFER_STALE, &eb->bflags)) {
+                       spin_lock(&eb->refs_lock);
+                       spin_unlock(&eb->refs_lock);
+               }
                mark_extent_buffer_accessed(eb, NULL);
                return eb;
        }
@@ -4870,6 +4890,7 @@ struct extent_buffer *alloc_extent_buffer(struct btrfs_fs_info *fs_info,
                                mark_extent_buffer_accessed(exists, p);
                                goto free_eb;
                        }
+                       exists = NULL;
 
                        /*
                         * Do this so attach doesn't complain and we need to
@@ -4933,12 +4954,12 @@ again:
        return eb;
 
 free_eb:
+       WARN_ON(!atomic_dec_and_test(&eb->refs));
        for (i = 0; i < num_pages; i++) {
                if (eb->pages[i])
                        unlock_page(eb->pages[i]);
        }
 
-       WARN_ON(!atomic_dec_and_test(&eb->refs));
        btrfs_release_extent_buffer(eb);
        return exists;
 }
index 81fa75a8e1f38e644be2e8bc2e02a4d15f5707c5..9dbe5b548fa6a74029960de0ea1d8ebf63f835e8 100644 (file)
@@ -86,7 +86,7 @@ static struct inode *__lookup_free_space_inode(struct btrfs_root *root,
 
        mapping_set_gfp_mask(inode->i_mapping,
                        mapping_gfp_mask(inode->i_mapping) &
-                       ~(GFP_NOFS & ~__GFP_HIGHMEM));
+                       ~(__GFP_FS | __GFP_HIGHMEM));
 
        return inode;
 }
@@ -1218,7 +1218,7 @@ out:
  *
  * This function writes out a free space cache struct to disk for quick recovery
  * on mount.  This will return 0 if it was successfull in writing the cache out,
- * and -1 if it was not.
+ * or an errno if it was not.
  */
 static int __btrfs_write_out_cache(struct btrfs_root *root, struct inode *inode,
                                   struct btrfs_free_space_ctl *ctl,
@@ -1235,12 +1235,12 @@ static int __btrfs_write_out_cache(struct btrfs_root *root, struct inode *inode,
        int must_iput = 0;
 
        if (!i_size_read(inode))
-               return -1;
+               return -EIO;
 
        WARN_ON(io_ctl->pages);
        ret = io_ctl_init(io_ctl, inode, root, 1);
        if (ret)
-               return -1;
+               return ret;
 
        if (block_group && (block_group->flags & BTRFS_BLOCK_GROUP_DATA)) {
                down_write(&block_group->data_rwsem);
@@ -1258,7 +1258,9 @@ static int __btrfs_write_out_cache(struct btrfs_root *root, struct inode *inode,
        }
 
        /* Lock all pages first so we can lock the extent safely. */
-       io_ctl_prepare_pages(io_ctl, inode, 0);
+       ret = io_ctl_prepare_pages(io_ctl, inode, 0);
+       if (ret)
+               goto out;
 
        lock_extent_bits(&BTRFS_I(inode)->io_tree, 0, i_size_read(inode) - 1,
                         0, &cached_state);
@@ -3464,6 +3466,7 @@ int btrfs_write_out_ino_cache(struct btrfs_root *root,
        struct btrfs_free_space_ctl *ctl = root->free_ino_ctl;
        int ret;
        struct btrfs_io_ctl io_ctl;
+       bool release_metadata = true;
 
        if (!btrfs_test_opt(root, INODE_MAP_CACHE))
                return 0;
@@ -3471,11 +3474,20 @@ int btrfs_write_out_ino_cache(struct btrfs_root *root,
        memset(&io_ctl, 0, sizeof(io_ctl));
        ret = __btrfs_write_out_cache(root, inode, ctl, NULL, &io_ctl,
                                      trans, path, 0);
-       if (!ret)
+       if (!ret) {
+               /*
+                * At this point writepages() didn't error out, so our metadata
+                * reservation is released when the writeback finishes, at
+                * inode.c:btrfs_finish_ordered_io(), regardless of it finishing
+                * with or without an error.
+                */
+               release_metadata = false;
                ret = btrfs_wait_cache_io(root, trans, NULL, &io_ctl, path, 0);
+       }
 
        if (ret) {
-               btrfs_delalloc_release_metadata(inode, inode->i_size);
+               if (release_metadata)
+                       btrfs_delalloc_release_metadata(inode, inode->i_size);
 #ifdef DEBUG
                btrfs_err(root->fs_info,
                        "failed to write free ino cache for root %llu",
index ada4d24ed11b71c3f20a90b9a8524d4c69bf2d20..8bb013672aee061e81eb03fcba6d51db9cd169af 100644 (file)
@@ -3632,25 +3632,28 @@ static void btrfs_read_locked_inode(struct inode *inode)
        BTRFS_I(inode)->generation = btrfs_inode_generation(leaf, inode_item);
        BTRFS_I(inode)->last_trans = btrfs_inode_transid(leaf, inode_item);
 
+       inode->i_version = btrfs_inode_sequence(leaf, inode_item);
+       inode->i_generation = BTRFS_I(inode)->generation;
+       inode->i_rdev = 0;
+       rdev = btrfs_inode_rdev(leaf, inode_item);
+
+       BTRFS_I(inode)->index_cnt = (u64)-1;
+       BTRFS_I(inode)->flags = btrfs_inode_flags(leaf, inode_item);
+
+cache_index:
        /*
         * If we were modified in the current generation and evicted from memory
         * and then re-read we need to do a full sync since we don't have any
         * idea about which extents were modified before we were evicted from
         * cache.
+        *
+        * This is required for both inode re-read from disk and delayed inode
+        * in delayed_nodes_tree.
         */
        if (BTRFS_I(inode)->last_trans == root->fs_info->generation)
                set_bit(BTRFS_INODE_NEEDS_FULL_SYNC,
                        &BTRFS_I(inode)->runtime_flags);
 
-       inode->i_version = btrfs_inode_sequence(leaf, inode_item);
-       inode->i_generation = BTRFS_I(inode)->generation;
-       inode->i_rdev = 0;
-       rdev = btrfs_inode_rdev(leaf, inode_item);
-
-       BTRFS_I(inode)->index_cnt = (u64)-1;
-       BTRFS_I(inode)->flags = btrfs_inode_flags(leaf, inode_item);
-
-cache_index:
        path->slots[0]++;
        if (inode->i_nlink != 1 ||
            path->slots[0] >= btrfs_header_nritems(leaf))
index b05653f182c231639080abe76688a473f263284e..1c22c65185045c61b170db3f1db8f2c3627bbd84 100644 (file)
@@ -2410,7 +2410,7 @@ static noinline int btrfs_ioctl_snap_destroy(struct file *file,
                        "Attempt to delete subvolume %llu during send",
                        dest->root_key.objectid);
                err = -EPERM;
-               goto out_dput;
+               goto out_unlock_inode;
        }
 
        d_invalidate(dentry);
@@ -2505,6 +2505,7 @@ out_up_write:
                                root_flags & ~BTRFS_ROOT_SUBVOL_DEAD);
                spin_unlock(&dest->root_item_lock);
        }
+out_unlock_inode:
        mutex_unlock(&inode->i_mutex);
        if (!err) {
                shrink_dcache_sb(root->fs_info->sb);
index 157cc54fc63486e485a95bf6d8d6da692ef171ca..760c4a5e096b4d5a403f7923ad4b65537a085886 100644 (file)
@@ -722,6 +722,7 @@ void btrfs_start_ordered_extent(struct inode *inode,
 int btrfs_wait_ordered_range(struct inode *inode, u64 start, u64 len)
 {
        int ret = 0;
+       int ret_wb = 0;
        u64 end;
        u64 orig_end;
        struct btrfs_ordered_extent *ordered;
@@ -741,9 +742,14 @@ int btrfs_wait_ordered_range(struct inode *inode, u64 start, u64 len)
        if (ret)
                return ret;
 
-       ret = filemap_fdatawait_range(inode->i_mapping, start, orig_end);
-       if (ret)
-               return ret;
+       /*
+        * If we have a writeback error don't return immediately. Wait first
+        * for any ordered extents that haven't completed yet. This is to make
+        * sure no one can dirty the same page ranges and call writepages()
+        * before the ordered extents complete - to avoid failures (-EEXIST)
+        * when adding the new ordered extents to the ordered tree.
+        */
+       ret_wb = filemap_fdatawait_range(inode->i_mapping, start, orig_end);
 
        end = orig_end;
        while (1) {
@@ -767,7 +773,7 @@ int btrfs_wait_ordered_range(struct inode *inode, u64 start, u64 len)
                        break;
                end--;
        }
-       return ret;
+       return ret_wb ? ret_wb : ret;
 }
 
 /*
index 8bcd2a00751785e0a6d41df74a3475e1acd8c455..174f5e1e00abfa533b1cb7483e44aae0f550e63a 100644 (file)
@@ -1058,6 +1058,7 @@ static int contains_pending_extent(struct btrfs_trans_handle *trans,
        struct extent_map *em;
        struct list_head *search_list = &trans->transaction->pending_chunks;
        int ret = 0;
+       u64 physical_start = *start;
 
 again:
        list_for_each_entry(em, search_list, list) {
@@ -1068,9 +1069,9 @@ again:
                for (i = 0; i < map->num_stripes; i++) {
                        if (map->stripes[i].dev != device)
                                continue;
-                       if (map->stripes[i].physical >= *start + len ||
+                       if (map->stripes[i].physical >= physical_start + len ||
                            map->stripes[i].physical + em->orig_block_len <=
-                           *start)
+                           physical_start)
                                continue;
                        *start = map->stripes[i].physical +
                                em->orig_block_len;
@@ -1193,8 +1194,14 @@ again:
                         */
                        if (contains_pending_extent(trans, device,
                                                    &search_start,
-                                                   hole_size))
-                               hole_size = 0;
+                                                   hole_size)) {
+                               if (key.offset >= search_start) {
+                                       hole_size = key.offset - search_start;
+                               } else {
+                                       WARN_ON_ONCE(1);
+                                       hole_size = 0;
+                               }
+                       }
 
                        if (hole_size > max_hole_size) {
                                max_hole_start = search_start;
@@ -4618,6 +4625,7 @@ int btrfs_alloc_chunk(struct btrfs_trans_handle *trans,
 {
        u64 chunk_offset;
 
+       ASSERT(mutex_is_locked(&extent_root->fs_info->chunk_mutex));
        chunk_offset = find_next_chunk(extent_root->fs_info);
        return __btrfs_alloc_chunk(trans, extent_root, chunk_offset, type);
 }
index 430e0348c99ebb9b86c65ccd957a1b5e69ed6a2a..7dc886c9a78fc428b368a1c911b8c1ad745f48a5 100644 (file)
@@ -24,6 +24,7 @@
 #include "cifsfs.h"
 #include "dns_resolve.h"
 #include "cifs_debug.h"
+#include "cifs_unicode.h"
 
 static LIST_HEAD(cifs_dfs_automount_list);
 
@@ -312,7 +313,7 @@ static struct vfsmount *cifs_dfs_do_automount(struct dentry *mntpt)
        xid = get_xid();
        rc = get_dfs_path(xid, ses, full_path + 1, cifs_sb->local_nls,
                &num_referrals, &referrals,
-               cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
+               cifs_remap(cifs_sb));
        free_xid(xid);
 
        cifs_put_tlink(tlink);
index 0303c6793d903ab07cb7d1829bc372f0be3fc15f..5a53ac6b1e02515be90a4e446b103aa9f6f26874 100644 (file)
 #include "cifsglob.h"
 #include "cifs_debug.h"
 
-/*
- * cifs_utf16_bytes - how long will a string be after conversion?
- * @utf16 - pointer to input string
- * @maxbytes - don't go past this many bytes of input string
- * @codepage - destination codepage
- *
- * Walk a utf16le string and return the number of bytes that the string will
- * be after being converted to the given charset, not including any null
- * termination required. Don't walk past maxbytes in the source buffer.
- */
-int
-cifs_utf16_bytes(const __le16 *from, int maxbytes,
-               const struct nls_table *codepage)
-{
-       int i;
-       int charlen, outlen = 0;
-       int maxwords = maxbytes / 2;
-       char tmp[NLS_MAX_CHARSET_SIZE];
-       __u16 ftmp;
-
-       for (i = 0; i < maxwords; i++) {
-               ftmp = get_unaligned_le16(&from[i]);
-               if (ftmp == 0)
-                       break;
-
-               charlen = codepage->uni2char(ftmp, tmp, NLS_MAX_CHARSET_SIZE);
-               if (charlen > 0)
-                       outlen += charlen;
-               else
-                       outlen++;
-       }
-
-       return outlen;
-}
-
 int cifs_remap(struct cifs_sb_info *cifs_sb)
 {
        int map_type;
@@ -155,10 +120,13 @@ convert_sfm_char(const __u16 src_char, char *target)
  * enough to hold the result of the conversion (at least NLS_MAX_CHARSET_SIZE).
  */
 static int
-cifs_mapchar(char *target, const __u16 src_char, const struct nls_table *cp,
+cifs_mapchar(char *target, const __u16 *from, const struct nls_table *cp,
             int maptype)
 {
        int len = 1;
+       __u16 src_char;
+
+       src_char = *from;
 
        if ((maptype == SFM_MAP_UNI_RSVD) && convert_sfm_char(src_char, target))
                return len;
@@ -168,10 +136,23 @@ cifs_mapchar(char *target, const __u16 src_char, const struct nls_table *cp,
 
        /* if character not one of seven in special remap set */
        len = cp->uni2char(src_char, target, NLS_MAX_CHARSET_SIZE);
-       if (len <= 0) {
-               *target = '?';
-               len = 1;
-       }
+       if (len <= 0)
+               goto surrogate_pair;
+
+       return len;
+
+surrogate_pair:
+       /* convert SURROGATE_PAIR and IVS */
+       if (strcmp(cp->charset, "utf8"))
+               goto unknown;
+       len = utf16s_to_utf8s(from, 3, UTF16_LITTLE_ENDIAN, target, 6);
+       if (len <= 0)
+               goto unknown;
+       return len;
+
+unknown:
+       *target = '?';
+       len = 1;
        return len;
 }
 
@@ -206,7 +187,7 @@ cifs_from_utf16(char *to, const __le16 *from, int tolen, int fromlen,
        int nullsize = nls_nullsize(codepage);
        int fromwords = fromlen / 2;
        char tmp[NLS_MAX_CHARSET_SIZE];
-       __u16 ftmp;
+       __u16 ftmp[3];          /* ftmp[3] = 3array x 2bytes = 6bytes UTF-16 */
 
        /*
         * because the chars can be of varying widths, we need to take care
@@ -217,9 +198,17 @@ cifs_from_utf16(char *to, const __le16 *from, int tolen, int fromlen,
        safelen = tolen - (NLS_MAX_CHARSET_SIZE + nullsize);
 
        for (i = 0; i < fromwords; i++) {
-               ftmp = get_unaligned_le16(&from[i]);
-               if (ftmp == 0)
+               ftmp[0] = get_unaligned_le16(&from[i]);
+               if (ftmp[0] == 0)
                        break;
+               if (i + 1 < fromwords)
+                       ftmp[1] = get_unaligned_le16(&from[i + 1]);
+               else
+                       ftmp[1] = 0;
+               if (i + 2 < fromwords)
+                       ftmp[2] = get_unaligned_le16(&from[i + 2]);
+               else
+                       ftmp[2] = 0;
 
                /*
                 * check to see if converting this character might make the
@@ -234,6 +223,17 @@ cifs_from_utf16(char *to, const __le16 *from, int tolen, int fromlen,
                /* put converted char into 'to' buffer */
                charlen = cifs_mapchar(&to[outlen], ftmp, codepage, map_type);
                outlen += charlen;
+
+               /* charlen (=bytes of UTF-8 for 1 character)
+                * 4bytes UTF-8(surrogate pair) is charlen=4
+                *   (4bytes UTF-16 code)
+                * 7-8bytes UTF-8(IVS) is charlen=3+4 or 4+4
+                *   (2 UTF-8 pairs divided to 2 UTF-16 pairs) */
+               if (charlen == 4)
+                       i++;
+               else if (charlen >= 5)
+                       /* 5-6bytes UTF-8 */
+                       i += 2;
        }
 
        /* properly null-terminate string */
@@ -295,6 +295,46 @@ success:
        return i;
 }
 
+/*
+ * cifs_utf16_bytes - how long will a string be after conversion?
+ * @utf16 - pointer to input string
+ * @maxbytes - don't go past this many bytes of input string
+ * @codepage - destination codepage
+ *
+ * Walk a utf16le string and return the number of bytes that the string will
+ * be after being converted to the given charset, not including any null
+ * termination required. Don't walk past maxbytes in the source buffer.
+ */
+int
+cifs_utf16_bytes(const __le16 *from, int maxbytes,
+               const struct nls_table *codepage)
+{
+       int i;
+       int charlen, outlen = 0;
+       int maxwords = maxbytes / 2;
+       char tmp[NLS_MAX_CHARSET_SIZE];
+       __u16 ftmp[3];
+
+       for (i = 0; i < maxwords; i++) {
+               ftmp[0] = get_unaligned_le16(&from[i]);
+               if (ftmp[0] == 0)
+                       break;
+               if (i + 1 < maxwords)
+                       ftmp[1] = get_unaligned_le16(&from[i + 1]);
+               else
+                       ftmp[1] = 0;
+               if (i + 2 < maxwords)
+                       ftmp[2] = get_unaligned_le16(&from[i + 2]);
+               else
+                       ftmp[2] = 0;
+
+               charlen = cifs_mapchar(tmp, ftmp, codepage, NO_MAP_UNI_RSVD);
+               outlen += charlen;
+       }
+
+       return outlen;
+}
+
 /*
  * cifs_strndup_from_utf16 - copy a string from wire format to the local
  * codepage
@@ -409,10 +449,15 @@ cifsConvertToUTF16(__le16 *target, const char *source, int srclen,
        char src_char;
        __le16 dst_char;
        wchar_t tmp;
+       wchar_t *wchar_to;      /* UTF-16 */
+       int ret;
+       unicode_t u;
 
        if (map_chars == NO_MAP_UNI_RSVD)
                return cifs_strtoUTF16(target, source, PATH_MAX, cp);
 
+       wchar_to = kzalloc(6, GFP_KERNEL);
+
        for (i = 0; i < srclen; j++) {
                src_char = source[i];
                charlen = 1;
@@ -441,11 +486,55 @@ cifsConvertToUTF16(__le16 *target, const char *source, int srclen,
                         * if no match, use question mark, which at least in
                         * some cases serves as wild card
                         */
-                       if (charlen < 1) {
-                               dst_char = cpu_to_le16(0x003f);
-                               charlen = 1;
+                       if (charlen > 0)
+                               goto ctoUTF16;
+
+                       /* convert SURROGATE_PAIR */
+                       if (strcmp(cp->charset, "utf8") || !wchar_to)
+                               goto unknown;
+                       if (*(source + i) & 0x80) {
+                               charlen = utf8_to_utf32(source + i, 6, &u);
+                               if (charlen < 0)
+                                       goto unknown;
+                       } else
+                               goto unknown;
+                       ret  = utf8s_to_utf16s(source + i, charlen,
+                                              UTF16_LITTLE_ENDIAN,
+                                              wchar_to, 6);
+                       if (ret < 0)
+                               goto unknown;
+
+                       i += charlen;
+                       dst_char = cpu_to_le16(*wchar_to);
+                       if (charlen <= 3)
+                               /* 1-3bytes UTF-8 to 2bytes UTF-16 */
+                               put_unaligned(dst_char, &target[j]);
+                       else if (charlen == 4) {
+                               /* 4bytes UTF-8(surrogate pair) to 4bytes UTF-16
+                                * 7-8bytes UTF-8(IVS) divided to 2 UTF-16
+                                *   (charlen=3+4 or 4+4) */
+                               put_unaligned(dst_char, &target[j]);
+                               dst_char = cpu_to_le16(*(wchar_to + 1));
+                               j++;
+                               put_unaligned(dst_char, &target[j]);
+                       } else if (charlen >= 5) {
+                               /* 5-6bytes UTF-8 to 6bytes UTF-16 */
+                               put_unaligned(dst_char, &target[j]);
+                               dst_char = cpu_to_le16(*(wchar_to + 1));
+                               j++;
+                               put_unaligned(dst_char, &target[j]);
+                               dst_char = cpu_to_le16(*(wchar_to + 2));
+                               j++;
+                               put_unaligned(dst_char, &target[j]);
                        }
+                       continue;
+
+unknown:
+                       dst_char = cpu_to_le16(0x003f);
+                       charlen = 1;
                }
+
+ctoUTF16:
                /*
                 * character may take more than one byte in the source string,
                 * but will take exactly two bytes in the target string
@@ -456,6 +545,7 @@ cifsConvertToUTF16(__le16 *target, const char *source, int srclen,
 
 ctoUTF16_out:
        put_unaligned(0, &target[j]); /* Null terminate target unicode string */
+       kfree(wchar_to);
        return j;
 }
 
index f5089bde363576dcab6a35887f3c539a8a7e6247..0a9fb6b53126a7c95715a862bfb3b067f443fc1a 100644 (file)
@@ -469,6 +469,8 @@ cifs_show_options(struct seq_file *s, struct dentry *root)
                seq_puts(s, ",nouser_xattr");
        if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR)
                seq_puts(s, ",mapchars");
+       if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SFM_CHR)
+               seq_puts(s, ",mapposix");
        if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UNX_EMUL)
                seq_puts(s, ",sfu");
        if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_BRL)
index c31ce98c1704a32b998f993d9a26613dc1342e29..c63fd1dde25b861b011f604522572c5619f177f1 100644 (file)
@@ -361,11 +361,11 @@ extern int CIFSUnixCreateHardLink(const unsigned int xid,
 extern int CIFSUnixCreateSymLink(const unsigned int xid,
                        struct cifs_tcon *tcon,
                        const char *fromName, const char *toName,
-                       const struct nls_table *nls_codepage);
+                       const struct nls_table *nls_codepage, int remap);
 extern int CIFSSMBUnixQuerySymLink(const unsigned int xid,
                        struct cifs_tcon *tcon,
                        const unsigned char *searchName, char **syminfo,
-                       const struct nls_table *nls_codepage);
+                       const struct nls_table *nls_codepage, int remap);
 extern int CIFSSMBQuerySymLink(const unsigned int xid, struct cifs_tcon *tcon,
                               __u16 fid, char **symlinkinfo,
                               const struct nls_table *nls_codepage);
index 84650a51c7c4064357eab083868cc613a75f7f18..f26ffbfc64d8b4eca26b8e8101f705043fc7a4a0 100644 (file)
@@ -2784,7 +2784,7 @@ copyRetry:
 int
 CIFSUnixCreateSymLink(const unsigned int xid, struct cifs_tcon *tcon,
                      const char *fromName, const char *toName,
-                     const struct nls_table *nls_codepage)
+                     const struct nls_table *nls_codepage, int remap)
 {
        TRANSACTION2_SPI_REQ *pSMB = NULL;
        TRANSACTION2_SPI_RSP *pSMBr = NULL;
@@ -2804,9 +2804,9 @@ createSymLinkRetry:
 
        if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
                name_len =
-                   cifs_strtoUTF16((__le16 *) pSMB->FileName, fromName,
-                                   /* find define for this maxpathcomponent */
-                                   PATH_MAX, nls_codepage);
+                   cifsConvertToUTF16((__le16 *) pSMB->FileName, fromName,
+                               /* find define for this maxpathcomponent */
+                                       PATH_MAX, nls_codepage, remap);
                name_len++;     /* trailing null */
                name_len *= 2;
 
@@ -2828,9 +2828,9 @@ createSymLinkRetry:
        data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
        if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
                name_len_target =
-                   cifs_strtoUTF16((__le16 *) data_offset, toName, PATH_MAX
-                                   /* find define for this maxpathcomponent */
-                                   , nls_codepage);
+                   cifsConvertToUTF16((__le16 *) data_offset, toName,
+                               /* find define for this maxpathcomponent */
+                                       PATH_MAX, nls_codepage, remap);
                name_len_target++;      /* trailing null */
                name_len_target *= 2;
        } else {        /* BB improve the check for buffer overruns BB */
@@ -3034,7 +3034,7 @@ winCreateHardLinkRetry:
 int
 CIFSSMBUnixQuerySymLink(const unsigned int xid, struct cifs_tcon *tcon,
                        const unsigned char *searchName, char **symlinkinfo,
-                       const struct nls_table *nls_codepage)
+                       const struct nls_table *nls_codepage, int remap)
 {
 /* SMB_QUERY_FILE_UNIX_LINK */
        TRANSACTION2_QPI_REQ *pSMB = NULL;
@@ -3055,8 +3055,9 @@ querySymLinkRetry:
 
        if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
                name_len =
-                       cifs_strtoUTF16((__le16 *) pSMB->FileName, searchName,
-                                       PATH_MAX, nls_codepage);
+                       cifsConvertToUTF16((__le16 *) pSMB->FileName,
+                                          searchName, PATH_MAX, nls_codepage,
+                                          remap);
                name_len++;     /* trailing null */
                name_len *= 2;
        } else {        /* BB improve the check for buffer overruns BB */
@@ -4917,7 +4918,7 @@ getDFSRetry:
                strncpy(pSMB->RequestFileName, search_name, name_len);
        }
 
-       if (ses->server && ses->server->sign)
+       if (ses->server->sign)
                pSMB->hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
 
        pSMB->hdr.Uid = ses->Suid;
index f3bfe08e177b6c86a4f1a99a8905f1b417f82af5..8383d5ea42028dac6788e642b6c3ed0f61459d51 100644 (file)
@@ -386,6 +386,7 @@ cifs_reconnect(struct TCP_Server_Info *server)
                rc = generic_ip_connect(server);
                if (rc) {
                        cifs_dbg(FYI, "reconnect error %d\n", rc);
+                       mutex_unlock(&server->srv_mutex);
                        msleep(3000);
                } else {
                        atomic_inc(&tcpSesReconnectCount);
@@ -393,8 +394,8 @@ cifs_reconnect(struct TCP_Server_Info *server)
                        if (server->tcpStatus != CifsExiting)
                                server->tcpStatus = CifsNeedNegotiate;
                        spin_unlock(&GlobalMid_Lock);
+                       mutex_unlock(&server->srv_mutex);
                }
-               mutex_unlock(&server->srv_mutex);
        } while (server->tcpStatus == CifsNeedReconnect);
 
        return rc;
index 338d56936f6af694b7085284a38e7b751ba7eb66..c3eb998a99bd18a2ed9b7b843c99be15fedab9df 100644 (file)
@@ -620,8 +620,7 @@ int cifs_mknod(struct inode *inode, struct dentry *direntry, umode_t mode,
                }
                rc = CIFSSMBUnixSetPathInfo(xid, tcon, full_path, &args,
                                            cifs_sb->local_nls,
-                                           cifs_sb->mnt_cifs_flags &
-                                               CIFS_MOUNT_MAP_SPECIAL_CHR);
+                                           cifs_remap(cifs_sb));
                if (rc)
                        goto mknod_out;
 
index cafbf10521d5017074196e02ad37218939d0ab70..3f50cee79df9d3318209e19281acef536b34af37 100644 (file)
@@ -140,8 +140,7 @@ int cifs_posix_open(char *full_path, struct inode **pinode,
        posix_flags = cifs_posix_convert_flags(f_flags);
        rc = CIFSPOSIXCreate(xid, tcon, posix_flags, mode, pnetfid, presp_data,
                             poplock, full_path, cifs_sb->local_nls,
-                            cifs_sb->mnt_cifs_flags &
-                                       CIFS_MOUNT_MAP_SPECIAL_CHR);
+                            cifs_remap(cifs_sb));
        cifs_put_tlink(tlink);
 
        if (rc)
@@ -1553,8 +1552,8 @@ cifs_setlk(struct file *file, struct file_lock *flock, __u32 type,
                rc = server->ops->mand_unlock_range(cfile, flock, xid);
 
 out:
-       if (flock->fl_flags & FL_POSIX)
-               posix_lock_file_wait(file, flock);
+       if (flock->fl_flags & FL_POSIX && !rc)
+               rc = posix_lock_file_wait(file, flock);
        return rc;
 }
 
index 55b58112d122248b92305ea00eb66c6715a40b03..f621b44cb8009fe87bf631e0a96c941fe63d3408 100644 (file)
@@ -373,8 +373,7 @@ int cifs_get_inode_info_unix(struct inode **pinode,
 
        /* could have done a find first instead but this returns more info */
        rc = CIFSSMBUnixQPathInfo(xid, tcon, full_path, &find_data,
-                                 cifs_sb->local_nls, cifs_sb->mnt_cifs_flags &
-                                       CIFS_MOUNT_MAP_SPECIAL_CHR);
+                                 cifs_sb->local_nls, cifs_remap(cifs_sb));
        cifs_put_tlink(tlink);
 
        if (!rc) {
@@ -402,9 +401,25 @@ int cifs_get_inode_info_unix(struct inode **pinode,
                        rc = -ENOMEM;
        } else {
                /* we already have inode, update it */
+
+               /* if uniqueid is different, return error */
+               if (unlikely(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM &&
+                   CIFS_I(*pinode)->uniqueid != fattr.cf_uniqueid)) {
+                       rc = -ESTALE;
+                       goto cgiiu_exit;
+               }
+
+               /* if filetype is different, return error */
+               if (unlikely(((*pinode)->i_mode & S_IFMT) !=
+                   (fattr.cf_mode & S_IFMT))) {
+                       rc = -ESTALE;
+                       goto cgiiu_exit;
+               }
+
                cifs_fattr_to_inode(*pinode, &fattr);
        }
 
+cgiiu_exit:
        return rc;
 }
 
@@ -839,6 +854,15 @@ cifs_get_inode_info(struct inode **inode, const char *full_path,
                if (!*inode)
                        rc = -ENOMEM;
        } else {
+               /* we already have inode, update it */
+
+               /* if filetype is different, return error */
+               if (unlikely(((*inode)->i_mode & S_IFMT) !=
+                   (fattr.cf_mode & S_IFMT))) {
+                       rc = -ESTALE;
+                       goto cgii_exit;
+               }
+
                cifs_fattr_to_inode(*inode, &fattr);
        }
 
@@ -2215,8 +2239,7 @@ cifs_setattr_unix(struct dentry *direntry, struct iattr *attrs)
                pTcon = tlink_tcon(tlink);
                rc = CIFSSMBUnixSetPathInfo(xid, pTcon, full_path, args,
                                    cifs_sb->local_nls,
-                                   cifs_sb->mnt_cifs_flags &
-                                       CIFS_MOUNT_MAP_SPECIAL_CHR);
+                                   cifs_remap(cifs_sb));
                cifs_put_tlink(tlink);
        }
 
index 252e672d56043468fb8f906ce371acef27d74db0..e6c707cc62b39b445b4b374eeec51a5be4fe07f4 100644 (file)
@@ -717,7 +717,8 @@ cifs_symlink(struct inode *inode, struct dentry *direntry, const char *symname)
                rc = create_mf_symlink(xid, pTcon, cifs_sb, full_path, symname);
        else if (pTcon->unix_ext)
                rc = CIFSUnixCreateSymLink(xid, pTcon, full_path, symname,
-                                          cifs_sb->local_nls);
+                                          cifs_sb->local_nls,
+                                          cifs_remap(cifs_sb));
        /* else
           rc = CIFSCreateReparseSymLink(xid, pTcon, fromName, toName,
                                        cifs_sb_target->local_nls); */
index b4a47237486b883851e889e78505bd1179c7842d..b1eede3678a91d8d1ea3e350cb035cabf1da7ba7 100644 (file)
@@ -90,6 +90,8 @@ cifs_prime_dcache(struct dentry *parent, struct qstr *name,
        if (dentry) {
                inode = d_inode(dentry);
                if (inode) {
+                       if (d_mountpoint(dentry))
+                               goto out;
                        /*
                         * If we're generating inode numbers, then we don't
                         * want to clobber the existing one with the one that
index 7bfdd6066276256fc03855cd809f63c167d3991b..fc537c29044edd8a158bb130a65e371370826164 100644 (file)
@@ -960,7 +960,8 @@ cifs_query_symlink(const unsigned int xid, struct cifs_tcon *tcon,
        /* Check for unix extensions */
        if (cap_unix(tcon->ses)) {
                rc = CIFSSMBUnixQuerySymLink(xid, tcon, full_path, target_path,
-                                            cifs_sb->local_nls);
+                                            cifs_sb->local_nls,
+                                            cifs_remap(cifs_sb));
                if (rc == -EREMOTE)
                        rc = cifs_unix_dfs_readlink(xid, tcon, full_path,
                                                    target_path,
index 65cd7a84c8bc3206033a917fe9d98fc939cbe1af..54cbe19d9c0871a1bb47a17edfc1d414cb383b9f 100644 (file)
@@ -110,7 +110,7 @@ smb2_hdr_assemble(struct smb2_hdr *hdr, __le16 smb2_cmd /* command */ ,
 
        /* GLOBAL_CAP_LARGE_MTU will only be set if dialect > SMB2.02 */
        /* See sections 2.2.4 and 3.2.4.1.5 of MS-SMB2 */
-       if ((tcon->ses) &&
+       if ((tcon->ses) && (tcon->ses->server) &&
            (tcon->ses->server->capabilities & SMB2_GLOBAL_CAP_LARGE_MTU))
                hdr->CreditCharge = cpu_to_le16(1);
        /* else CreditCharge MBZ */
index da94e41bdbf685b02b567e95e3c0f37db33c2795..5373567420912c87b1d82f3c605e308bda94c68b 100644 (file)
@@ -173,5 +173,5 @@ MODULE_LICENSE("GPL");
 MODULE_VERSION("0.0.2");
 MODULE_DESCRIPTION("Simple RAM filesystem for user driven kernel subsystem configuration.");
 
-module_init(configfs_init);
+core_initcall(configfs_init);
 module_exit(configfs_exit);
index 656ce522a218f29850e2415b0a038c8208a5dd52..37b5afdaf6989e211151cc55a7fa656a6addd364 100644 (file)
@@ -1239,13 +1239,13 @@ ascend:
                /* might go back up the wrong parent if we have had a rename. */
                if (need_seqretry(&rename_lock, seq))
                        goto rename_retry;
-               next = child->d_child.next;
-               while (unlikely(child->d_flags & DCACHE_DENTRY_KILLED)) {
+               /* go into the first sibling still alive */
+               do {
+                       next = child->d_child.next;
                        if (next == &this_parent->d_subdirs)
                                goto ascend;
                        child = list_entry(next, struct dentry, d_child);
-                       next = next->next;
-               }
+               } while (unlikely(child->d_flags & DCACHE_DENTRY_KILLED));
                rcu_read_unlock();
                goto resume;
        }
index 59fedbcf87984e179569914e9094db57b431611e..86a2121828c312e53d64aedee9506319bbadf6c1 100644 (file)
@@ -121,7 +121,7 @@ static int efivarfs_callback(efi_char16_t *name16, efi_guid_t vendor,
        int len, i;
        int err = -ENOMEM;
 
-       entry = kmalloc(sizeof(*entry), GFP_KERNEL);
+       entry = kzalloc(sizeof(*entry), GFP_KERNEL);
        if (!entry)
                return err;
 
index 49a1c61433b73722683cad25eef1fb92045e265a..1977c2a553aca711ba145d1670ea9a84fd45ea84 100644 (file)
--- a/fs/exec.c
+++ b/fs/exec.c
@@ -659,6 +659,9 @@ int setup_arg_pages(struct linux_binprm *bprm,
        if (stack_base > STACK_SIZE_MAX)
                stack_base = STACK_SIZE_MAX;
 
+       /* Add space for stack randomization. */
+       stack_base += (STACK_RND_MASK << PAGE_SHIFT);
+
        /* Make sure we didn't let the argument array grow too large. */
        if (vma->vm_end - vma->vm_start > stack_base)
                return -ENOMEM;
index 18228c201f7f4c226f74c15d548ff35e63ff86c6..024f2284d3f6c03ec3a0b4697bc71cbe9d9b9e2e 100644 (file)
@@ -64,8 +64,8 @@ config EXT4_FS_SECURITY
          If you are not using a security module that requires using
          extended attributes for file security labels, say N.
 
-config EXT4_FS_ENCRYPTION
-       bool "Ext4 Encryption"
+config EXT4_ENCRYPTION
+       tristate "Ext4 Encryption"
        depends on EXT4_FS
        select CRYPTO_AES
        select CRYPTO_CBC
@@ -81,6 +81,11 @@ config EXT4_FS_ENCRYPTION
          efficient since it avoids caching the encrypted and
          decrypted pages in the page cache.
 
+config EXT4_FS_ENCRYPTION
+       bool
+       default y
+       depends on EXT4_ENCRYPTION
+
 config EXT4_DEBUG
        bool "EXT4 debugging support"
        depends on EXT4_FS
index ca2f5948c1ac52111259441ff0ee5e3405e0502a..fded02f7229921a8693909ade14c2e7b16095f5e 100644 (file)
@@ -66,6 +66,7 @@ static int ext4_fname_encrypt(struct ext4_fname_crypto_ctx *ctx,
        int res = 0;
        char iv[EXT4_CRYPTO_BLOCK_SIZE];
        struct scatterlist sg[1];
+       int padding = 4 << (ctx->flags & EXT4_POLICY_FLAGS_PAD_MASK);
        char *workbuf;
 
        if (iname->len <= 0 || iname->len > ctx->lim)
@@ -73,6 +74,7 @@ static int ext4_fname_encrypt(struct ext4_fname_crypto_ctx *ctx,
 
        ciphertext_len = (iname->len < EXT4_CRYPTO_BLOCK_SIZE) ?
                EXT4_CRYPTO_BLOCK_SIZE : iname->len;
+       ciphertext_len = ext4_fname_crypto_round_up(ciphertext_len, padding);
        ciphertext_len = (ciphertext_len > ctx->lim)
                        ? ctx->lim : ciphertext_len;
 
@@ -101,7 +103,7 @@ static int ext4_fname_encrypt(struct ext4_fname_crypto_ctx *ctx,
        /* Create encryption request */
        sg_init_table(sg, 1);
        sg_set_page(sg, ctx->workpage, PAGE_SIZE, 0);
-       ablkcipher_request_set_crypt(req, sg, sg, iname->len, iv);
+       ablkcipher_request_set_crypt(req, sg, sg, ciphertext_len, iv);
        res = crypto_ablkcipher_encrypt(req);
        if (res == -EINPROGRESS || res == -EBUSY) {
                BUG_ON(req->base.data != &ecr);
@@ -198,106 +200,57 @@ static int ext4_fname_decrypt(struct ext4_fname_crypto_ctx *ctx,
        return oname->len;
 }
 
+static const char *lookup_table =
+       "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+,";
+
 /**
  * ext4_fname_encode_digest() -
  *
  * Encodes the input digest using characters from the set [a-zA-Z0-9_+].
  * The encoded string is roughly 4/3 times the size of the input string.
  */
-int ext4_fname_encode_digest(char *dst, char *src, u32 len)
+static int digest_encode(const char *src, int len, char *dst)
 {
-       static const char *lookup_table =
-               "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_+";
-       u32 current_chunk, num_chunks, i;
-       char tmp_buf[3];
-       u32 c0, c1, c2, c3;
-
-       current_chunk = 0;
-       num_chunks = len/3;
-       for (i = 0; i < num_chunks; i++) {
-               c0 = src[3*i] & 0x3f;
-               c1 = (((src[3*i]>>6)&0x3) | ((src[3*i+1] & 0xf)<<2)) & 0x3f;
-               c2 = (((src[3*i+1]>>4)&0xf) | ((src[3*i+2] & 0x3)<<4)) & 0x3f;
-               c3 = (src[3*i+2]>>2) & 0x3f;
-               dst[4*i] = lookup_table[c0];
-               dst[4*i+1] = lookup_table[c1];
-               dst[4*i+2] = lookup_table[c2];
-               dst[4*i+3] = lookup_table[c3];
-       }
-       if (i*3 < len) {
-               memset(tmp_buf, 0, 3);
-               memcpy(tmp_buf, &src[3*i], len-3*i);
-               c0 = tmp_buf[0] & 0x3f;
-               c1 = (((tmp_buf[0]>>6)&0x3) | ((tmp_buf[1] & 0xf)<<2)) & 0x3f;
-               c2 = (((tmp_buf[1]>>4)&0xf) | ((tmp_buf[2] & 0x3)<<4)) & 0x3f;
-               c3 = (tmp_buf[2]>>2) & 0x3f;
-               dst[4*i] = lookup_table[c0];
-               dst[4*i+1] = lookup_table[c1];
-               dst[4*i+2] = lookup_table[c2];
-               dst[4*i+3] = lookup_table[c3];
+       int i = 0, bits = 0, ac = 0;
+       char *cp = dst;
+
+       while (i < len) {
+               ac += (((unsigned char) src[i]) << bits);
+               bits += 8;
+               do {
+                       *cp++ = lookup_table[ac & 0x3f];
+                       ac >>= 6;
+                       bits -= 6;
+               } while (bits >= 6);
                i++;
        }
-       return (i * 4);
+       if (bits)
+               *cp++ = lookup_table[ac & 0x3f];
+       return cp - dst;
 }
 
-/**
- * ext4_fname_hash() -
- *
- * This function computes the hash of the input filename, and sets the output
- * buffer to the *encoded* digest.  It returns the length of the digest as its
- * return value.  Errors are returned as negative numbers.  We trust the caller
- * to allocate sufficient memory to oname string.
- */
-static int ext4_fname_hash(struct ext4_fname_crypto_ctx *ctx,
-                          const struct ext4_str *iname,
-                          struct ext4_str *oname)
+static int digest_decode(const char *src, int len, char *dst)
 {
-       struct scatterlist sg;
-       struct hash_desc desc = {
-               .tfm = (struct crypto_hash *)ctx->htfm,
-               .flags = CRYPTO_TFM_REQ_MAY_SLEEP
-       };
-       int res = 0;
-
-       if (iname->len <= EXT4_FNAME_CRYPTO_DIGEST_SIZE) {
-               res = ext4_fname_encode_digest(oname->name, iname->name,
-                                              iname->len);
-               oname->len = res;
-               return res;
-       }
-
-       sg_init_one(&sg, iname->name, iname->len);
-       res = crypto_hash_init(&desc);
-       if (res) {
-               printk(KERN_ERR
-                      "%s: Error initializing crypto hash; res = [%d]\n",
-                      __func__, res);
-               goto out;
-       }
-       res = crypto_hash_update(&desc, &sg, iname->len);
-       if (res) {
-               printk(KERN_ERR
-                      "%s: Error updating crypto hash; res = [%d]\n",
-                      __func__, res);
-               goto out;
-       }
-       res = crypto_hash_final(&desc,
-               &oname->name[EXT4_FNAME_CRYPTO_DIGEST_SIZE]);
-       if (res) {
-               printk(KERN_ERR
-                      "%s: Error finalizing crypto hash; res = [%d]\n",
-                      __func__, res);
-               goto out;
+       int i = 0, bits = 0, ac = 0;
+       const char *p;
+       char *cp = dst;
+
+       while (i < len) {
+               p = strchr(lookup_table, src[i]);
+               if (p == NULL || src[i] == 0)
+                       return -2;
+               ac += (p - lookup_table) << bits;
+               bits += 6;
+               if (bits >= 8) {
+                       *cp++ = ac & 0xff;
+                       ac >>= 8;
+                       bits -= 8;
+               }
+               i++;
        }
-       /* Encode the digest as a printable string--this will increase the
-        * size of the digest */
-       oname->name[0] = 'I';
-       res = ext4_fname_encode_digest(oname->name+1,
-               &oname->name[EXT4_FNAME_CRYPTO_DIGEST_SIZE],
-               EXT4_FNAME_CRYPTO_DIGEST_SIZE) + 1;
-       oname->len = res;
-out:
-       return res;
+       if (ac)
+               return -1;
+       return cp - dst;
 }
 
 /**
@@ -405,6 +358,7 @@ struct ext4_fname_crypto_ctx *ext4_get_fname_crypto_ctx(
        if (IS_ERR(ctx))
                return ctx;
 
+       ctx->flags = ei->i_crypt_policy_flags;
        if (ctx->has_valid_key) {
                if (ctx->key.mode != EXT4_ENCRYPTION_MODE_AES_256_CTS) {
                        printk_once(KERN_WARNING
@@ -517,6 +471,7 @@ int ext4_fname_crypto_namelen_on_disk(struct ext4_fname_crypto_ctx *ctx,
                                      u32 namelen)
 {
        u32 ciphertext_len;
+       int padding = 4 << (ctx->flags & EXT4_POLICY_FLAGS_PAD_MASK);
 
        if (ctx == NULL)
                return -EIO;
@@ -524,6 +479,7 @@ int ext4_fname_crypto_namelen_on_disk(struct ext4_fname_crypto_ctx *ctx,
                return -EACCES;
        ciphertext_len = (namelen < EXT4_CRYPTO_BLOCK_SIZE) ?
                EXT4_CRYPTO_BLOCK_SIZE : namelen;
+       ciphertext_len = ext4_fname_crypto_round_up(ciphertext_len, padding);
        ciphertext_len = (ciphertext_len > ctx->lim)
                        ? ctx->lim : ciphertext_len;
        return (int) ciphertext_len;
@@ -539,10 +495,13 @@ int ext4_fname_crypto_alloc_buffer(struct ext4_fname_crypto_ctx *ctx,
                                   u32 ilen, struct ext4_str *crypto_str)
 {
        unsigned int olen;
+       int padding = 4 << (ctx->flags & EXT4_POLICY_FLAGS_PAD_MASK);
 
        if (!ctx)
                return -EIO;
-       olen = ext4_fname_crypto_round_up(ilen, EXT4_CRYPTO_BLOCK_SIZE);
+       if (padding < EXT4_CRYPTO_BLOCK_SIZE)
+               padding = EXT4_CRYPTO_BLOCK_SIZE;
+       olen = ext4_fname_crypto_round_up(ilen, padding);
        crypto_str->len = olen;
        if (olen < EXT4_FNAME_CRYPTO_DIGEST_SIZE*2)
                olen = EXT4_FNAME_CRYPTO_DIGEST_SIZE*2;
@@ -571,9 +530,13 @@ void ext4_fname_crypto_free_buffer(struct ext4_str *crypto_str)
  * ext4_fname_disk_to_usr() - converts a filename from disk space to user space
  */
 int _ext4_fname_disk_to_usr(struct ext4_fname_crypto_ctx *ctx,
-                          const struct ext4_str *iname,
-                          struct ext4_str *oname)
+                           struct dx_hash_info *hinfo,
+                           const struct ext4_str *iname,
+                           struct ext4_str *oname)
 {
+       char buf[24];
+       int ret;
+
        if (ctx == NULL)
                return -EIO;
        if (iname->len < 3) {
@@ -587,18 +550,33 @@ int _ext4_fname_disk_to_usr(struct ext4_fname_crypto_ctx *ctx,
        }
        if (ctx->has_valid_key)
                return ext4_fname_decrypt(ctx, iname, oname);
-       else
-               return ext4_fname_hash(ctx, iname, oname);
+
+       if (iname->len <= EXT4_FNAME_CRYPTO_DIGEST_SIZE) {
+               ret = digest_encode(iname->name, iname->len, oname->name);
+               oname->len = ret;
+               return ret;
+       }
+       if (hinfo) {
+               memcpy(buf, &hinfo->hash, 4);
+               memcpy(buf+4, &hinfo->minor_hash, 4);
+       } else
+               memset(buf, 0, 8);
+       memcpy(buf + 8, iname->name + iname->len - 16, 16);
+       oname->name[0] = '_';
+       ret = digest_encode(buf, 24, oname->name+1);
+       oname->len = ret + 1;
+       return ret + 1;
 }
 
 int ext4_fname_disk_to_usr(struct ext4_fname_crypto_ctx *ctx,
+                          struct dx_hash_info *hinfo,
                           const struct ext4_dir_entry_2 *de,
                           struct ext4_str *oname)
 {
        struct ext4_str iname = {.name = (unsigned char *) de->name,
                                 .len = de->name_len };
 
-       return _ext4_fname_disk_to_usr(ctx, &iname, oname);
+       return _ext4_fname_disk_to_usr(ctx, hinfo, &iname, oname);
 }
 
 
@@ -640,10 +618,11 @@ int ext4_fname_usr_to_hash(struct ext4_fname_crypto_ctx *ctx,
                            const struct qstr *iname,
                            struct dx_hash_info *hinfo)
 {
-       struct ext4_str tmp, tmp2;
+       struct ext4_str tmp;
        int ret = 0;
+       char buf[EXT4_FNAME_CRYPTO_DIGEST_SIZE+1];
 
-       if (!ctx || !ctx->has_valid_key ||
+       if (!ctx ||
            ((iname->name[0] == '.') &&
             ((iname->len == 1) ||
              ((iname->name[1] == '.') && (iname->len == 2))))) {
@@ -651,59 +630,90 @@ int ext4_fname_usr_to_hash(struct ext4_fname_crypto_ctx *ctx,
                return 0;
        }
 
+       if (!ctx->has_valid_key && iname->name[0] == '_') {
+               if (iname->len != 33)
+                       return -ENOENT;
+               ret = digest_decode(iname->name+1, iname->len, buf);
+               if (ret != 24)
+                       return -ENOENT;
+               memcpy(&hinfo->hash, buf, 4);
+               memcpy(&hinfo->minor_hash, buf + 4, 4);
+               return 0;
+       }
+
+       if (!ctx->has_valid_key && iname->name[0] != '_') {
+               if (iname->len > 43)
+                       return -ENOENT;
+               ret = digest_decode(iname->name, iname->len, buf);
+               ext4fs_dirhash(buf, ret, hinfo);
+               return 0;
+       }
+
        /* First encrypt the plaintext name */
        ret = ext4_fname_crypto_alloc_buffer(ctx, iname->len, &tmp);
        if (ret < 0)
                return ret;
 
        ret = ext4_fname_encrypt(ctx, iname, &tmp);
-       if (ret < 0)
-               goto out;
-
-       tmp2.len = (4 * ((EXT4_FNAME_CRYPTO_DIGEST_SIZE + 2) / 3)) + 1;
-       tmp2.name = kmalloc(tmp2.len + 1, GFP_KERNEL);
-       if (tmp2.name == NULL) {
-               ret = -ENOMEM;
-               goto out;
+       if (ret >= 0) {
+               ext4fs_dirhash(tmp.name, tmp.len, hinfo);
+               ret = 0;
        }
 
-       ret = ext4_fname_hash(ctx, &tmp, &tmp2);
-       if (ret > 0)
-               ext4fs_dirhash(tmp2.name, tmp2.len, hinfo);
-       ext4_fname_crypto_free_buffer(&tmp2);
-out:
        ext4_fname_crypto_free_buffer(&tmp);
        return ret;
 }
 
-/**
- * ext4_fname_disk_to_htree() - converts a filename from disk space to htree-access string
- */
-int ext4_fname_disk_to_hash(struct ext4_fname_crypto_ctx *ctx,
-                           const struct ext4_dir_entry_2 *de,
-                           struct dx_hash_info *hinfo)
+int ext4_fname_match(struct ext4_fname_crypto_ctx *ctx, struct ext4_str *cstr,
+                    int len, const char * const name,
+                    struct ext4_dir_entry_2 *de)
 {
-       struct ext4_str iname = {.name = (unsigned char *) de->name,
-                                .len = de->name_len};
-       struct ext4_str tmp;
-       int ret;
+       int ret = -ENOENT;
+       int bigname = (*name == '_');
 
-       if (!ctx ||
-           ((iname.name[0] == '.') &&
-            ((iname.len == 1) ||
-             ((iname.name[1] == '.') && (iname.len == 2))))) {
-               ext4fs_dirhash(iname.name, iname.len, hinfo);
-               return 0;
+       if (ctx->has_valid_key) {
+               if (cstr->name == NULL) {
+                       struct qstr istr;
+
+                       ret = ext4_fname_crypto_alloc_buffer(ctx, len, cstr);
+                       if (ret < 0)
+                               goto errout;
+                       istr.name = name;
+                       istr.len = len;
+                       ret = ext4_fname_encrypt(ctx, &istr, cstr);
+                       if (ret < 0)
+                               goto errout;
+               }
+       } else {
+               if (cstr->name == NULL) {
+                       cstr->name = kmalloc(32, GFP_KERNEL);
+                       if (cstr->name == NULL)
+                               return -ENOMEM;
+                       if ((bigname && (len != 33)) ||
+                           (!bigname && (len > 43)))
+                               goto errout;
+                       ret = digest_decode(name+bigname, len-bigname,
+                                           cstr->name);
+                       if (ret < 0) {
+                               ret = -ENOENT;
+                               goto errout;
+                       }
+                       cstr->len = ret;
+               }
+               if (bigname) {
+                       if (de->name_len < 16)
+                               return 0;
+                       ret = memcmp(de->name + de->name_len - 16,
+                                    cstr->name + 8, 16);
+                       return (ret == 0) ? 1 : 0;
+               }
        }
-
-       tmp.len = (4 * ((EXT4_FNAME_CRYPTO_DIGEST_SIZE + 2) / 3)) + 1;
-       tmp.name = kmalloc(tmp.len + 1, GFP_KERNEL);
-       if (tmp.name == NULL)
-               return -ENOMEM;
-
-       ret = ext4_fname_hash(ctx, &iname, &tmp);
-       if (ret > 0)
-               ext4fs_dirhash(tmp.name, tmp.len, hinfo);
-       ext4_fname_crypto_free_buffer(&tmp);
+       if (de->name_len != cstr->len)
+               return 0;
+       ret = memcmp(de->name, cstr->name, cstr->len);
+       return (ret == 0) ? 1 : 0;
+errout:
+       kfree(cstr->name);
+       cstr->name = NULL;
        return ret;
 }
index c8392af8abbbbd8fffb0a1027d5cf5c74dbb6b81..52170d0b7c4036d03bec92d8bd0ec95981105040 100644 (file)
@@ -110,6 +110,7 @@ int ext4_generate_encryption_key(struct inode *inode)
        }
        res = 0;
 
+       ei->i_crypt_policy_flags = ctx.flags;
        if (S_ISREG(inode->i_mode))
                crypt_key->mode = ctx.contents_encryption_mode;
        else if (S_ISDIR(inode->i_mode) || S_ISLNK(inode->i_mode))
index 30eaf9e9864a967db328bbebc18211ff4796961e..a6d6291aea163e74efad0760b7b21b308d2a49f4 100644 (file)
@@ -37,6 +37,8 @@ static int ext4_is_encryption_context_consistent_with_policy(
                return 0;
        return (memcmp(ctx.master_key_descriptor, policy->master_key_descriptor,
                        EXT4_KEY_DESCRIPTOR_SIZE) == 0 &&
+               (ctx.flags ==
+                policy->flags) &&
                (ctx.contents_encryption_mode ==
                 policy->contents_encryption_mode) &&
                (ctx.filenames_encryption_mode ==
@@ -56,25 +58,25 @@ static int ext4_create_encryption_context_from_policy(
                printk(KERN_WARNING
                       "%s: Invalid contents encryption mode %d\n", __func__,
                        policy->contents_encryption_mode);
-               res = -EINVAL;
-               goto out;
+               return -EINVAL;
        }
        if (!ext4_valid_filenames_enc_mode(policy->filenames_encryption_mode)) {
                printk(KERN_WARNING
                       "%s: Invalid filenames encryption mode %d\n", __func__,
                        policy->filenames_encryption_mode);
-               res = -EINVAL;
-               goto out;
+               return -EINVAL;
        }
+       if (policy->flags & ~EXT4_POLICY_FLAGS_VALID)
+               return -EINVAL;
        ctx.contents_encryption_mode = policy->contents_encryption_mode;
        ctx.filenames_encryption_mode = policy->filenames_encryption_mode;
+       ctx.flags = policy->flags;
        BUILD_BUG_ON(sizeof(ctx.nonce) != EXT4_KEY_DERIVATION_NONCE_SIZE);
        get_random_bytes(ctx.nonce, EXT4_KEY_DERIVATION_NONCE_SIZE);
 
        res = ext4_xattr_set(inode, EXT4_XATTR_INDEX_ENCRYPTION,
                             EXT4_XATTR_NAME_ENCRYPTION_CONTEXT, &ctx,
                             sizeof(ctx), 0);
-out:
        if (!res)
                ext4_set_inode_flag(inode, EXT4_INODE_ENCRYPT);
        return res;
@@ -115,6 +117,7 @@ int ext4_get_policy(struct inode *inode, struct ext4_encryption_policy *policy)
        policy->version = 0;
        policy->contents_encryption_mode = ctx.contents_encryption_mode;
        policy->filenames_encryption_mode = ctx.filenames_encryption_mode;
+       policy->flags = ctx.flags;
        memcpy(&policy->master_key_descriptor, ctx.master_key_descriptor,
               EXT4_KEY_DESCRIPTOR_SIZE);
        return 0;
@@ -176,6 +179,7 @@ int ext4_inherit_context(struct inode *parent, struct inode *child)
                                EXT4_ENCRYPTION_MODE_AES_256_XTS;
                        ctx.filenames_encryption_mode =
                                EXT4_ENCRYPTION_MODE_AES_256_CTS;
+                       ctx.flags = 0;
                        memset(ctx.master_key_descriptor, 0x42,
                               EXT4_KEY_DESCRIPTOR_SIZE);
                        res = 0;
index 61db51a5ce4c2feb3a3fb28a4c1a900ebf7ec958..5665d82d233216f48097de22359fd0188fc7d4bc 100644 (file)
@@ -249,7 +249,7 @@ static int ext4_readdir(struct file *file, struct dir_context *ctx)
                                } else {
                                        /* Directory is encrypted */
                                        err = ext4_fname_disk_to_usr(enc_ctx,
-                                                       de, &fname_crypto_str);
+                                               NULL, de, &fname_crypto_str);
                                        if (err < 0)
                                                goto errout;
                                        if (!dir_emit(ctx,
index ef267adce19a563d87f5708fa006db6dd3e6e393..9a83f149ac85525b821a4d24ba5387b93b3229d6 100644 (file)
@@ -911,6 +911,7 @@ struct ext4_inode_info {
 
        /* on-disk additional length */
        __u16 i_extra_isize;
+       char i_crypt_policy_flags;
 
        /* Indicate the inline data space. */
        u16 i_inline_off;
@@ -1066,12 +1067,6 @@ extern void ext4_set_bits(void *bm, int cur, int len);
 /* Metadata checksum algorithm codes */
 #define EXT4_CRC32C_CHKSUM             1
 
-/* Encryption algorithms */
-#define EXT4_ENCRYPTION_MODE_INVALID           0
-#define EXT4_ENCRYPTION_MODE_AES_256_XTS       1
-#define EXT4_ENCRYPTION_MODE_AES_256_GCM       2
-#define EXT4_ENCRYPTION_MODE_AES_256_CBC       3
-
 /*
  * Structure of the super block
  */
@@ -2093,9 +2088,11 @@ u32 ext4_fname_crypto_round_up(u32 size, u32 blksize);
 int ext4_fname_crypto_alloc_buffer(struct ext4_fname_crypto_ctx *ctx,
                                   u32 ilen, struct ext4_str *crypto_str);
 int _ext4_fname_disk_to_usr(struct ext4_fname_crypto_ctx *ctx,
+                           struct dx_hash_info *hinfo,
                            const struct ext4_str *iname,
                            struct ext4_str *oname);
 int ext4_fname_disk_to_usr(struct ext4_fname_crypto_ctx *ctx,
+                          struct dx_hash_info *hinfo,
                           const struct ext4_dir_entry_2 *de,
                           struct ext4_str *oname);
 int ext4_fname_usr_to_disk(struct ext4_fname_crypto_ctx *ctx,
@@ -2104,11 +2101,12 @@ int ext4_fname_usr_to_disk(struct ext4_fname_crypto_ctx *ctx,
 int ext4_fname_usr_to_hash(struct ext4_fname_crypto_ctx *ctx,
                           const struct qstr *iname,
                           struct dx_hash_info *hinfo);
-int ext4_fname_disk_to_hash(struct ext4_fname_crypto_ctx *ctx,
-                           const struct ext4_dir_entry_2 *de,
-                           struct dx_hash_info *hinfo);
 int ext4_fname_crypto_namelen_on_disk(struct ext4_fname_crypto_ctx *ctx,
                                      u32 namelen);
+int ext4_fname_match(struct ext4_fname_crypto_ctx *ctx, struct ext4_str *cstr,
+                    int len, const char * const name,
+                    struct ext4_dir_entry_2 *de);
+
 
 #ifdef CONFIG_EXT4_FS_ENCRYPTION
 void ext4_put_fname_crypto_ctx(struct ext4_fname_crypto_ctx **ctx);
@@ -2891,7 +2889,6 @@ extern int ext4_map_blocks(handle_t *handle, struct inode *inode,
                           struct ext4_map_blocks *map, int flags);
 extern int ext4_ext_calc_metadata_amount(struct inode *inode,
                                         ext4_lblk_t lblocks);
-extern int ext4_extent_tree_init(handle_t *, struct inode *);
 extern int ext4_ext_calc_credits_for_single_extent(struct inode *inode,
                                                   int num,
                                                   struct ext4_ext_path *path);
index c2ba35a914b65f5b6ec4497e05ef37bd10b1bea8..d75159c101ce333c2dcef8b3ff3e76f60ee0f259 100644 (file)
@@ -20,12 +20,20 @@ struct ext4_encryption_policy {
        char version;
        char contents_encryption_mode;
        char filenames_encryption_mode;
+       char flags;
        char master_key_descriptor[EXT4_KEY_DESCRIPTOR_SIZE];
 } __attribute__((__packed__));
 
 #define EXT4_ENCRYPTION_CONTEXT_FORMAT_V1 1
 #define EXT4_KEY_DERIVATION_NONCE_SIZE 16
 
+#define EXT4_POLICY_FLAGS_PAD_4                0x00
+#define EXT4_POLICY_FLAGS_PAD_8                0x01
+#define EXT4_POLICY_FLAGS_PAD_16       0x02
+#define EXT4_POLICY_FLAGS_PAD_32       0x03
+#define EXT4_POLICY_FLAGS_PAD_MASK     0x03
+#define EXT4_POLICY_FLAGS_VALID                0x03
+
 /**
  * Encryption context for inode
  *
@@ -41,7 +49,7 @@ struct ext4_encryption_context {
        char format;
        char contents_encryption_mode;
        char filenames_encryption_mode;
-       char reserved;
+       char flags;
        char master_key_descriptor[EXT4_KEY_DESCRIPTOR_SIZE];
        char nonce[EXT4_KEY_DERIVATION_NONCE_SIZE];
 } __attribute__((__packed__));
@@ -120,6 +128,7 @@ struct ext4_fname_crypto_ctx {
        struct crypto_hash *htfm;
        struct page *workpage;
        struct ext4_encryption_key key;
+       unsigned flags : 8;
        unsigned has_valid_key : 1;
        unsigned ctfm_key_is_ready : 1;
 };
index 3445035c7e015e9460f2cd3f74b698bf823cabb6..d4184318181878b023931078377ae17c9568a208 100644 (file)
@@ -87,6 +87,12 @@ int __ext4_journal_stop(const char *where, unsigned int line, handle_t *handle)
                ext4_put_nojournal(handle);
                return 0;
        }
+
+       if (!handle->h_transaction) {
+               err = jbd2_journal_stop(handle);
+               return handle->h_err ? handle->h_err : err;
+       }
+
        sb = handle->h_transaction->t_journal->j_private;
        err = handle->h_err;
        rc = jbd2_journal_stop(handle);
index 973816bfe4a9d115a11270a1689a1cecd6fd1dec..e003a1e81dc351c76465908bec21702ecc6d4b91 100644 (file)
@@ -377,7 +377,7 @@ static int ext4_valid_extent(struct inode *inode, struct ext4_extent *ext)
        ext4_lblk_t lblock = le32_to_cpu(ext->ee_block);
        ext4_lblk_t last = lblock + len - 1;
 
-       if (lblock > last)
+       if (len == 0 || lblock > last)
                return 0;
        return ext4_data_block_valid(EXT4_SB(inode->i_sb), block, len);
 }
@@ -4927,13 +4927,6 @@ long ext4_fallocate(struct file *file, int mode, loff_t offset, loff_t len)
        if (ret)
                return ret;
 
-       /*
-        * currently supporting (pre)allocate mode for extent-based
-        * files _only_
-        */
-       if (!(ext4_test_inode_flag(inode, EXT4_INODE_EXTENTS)))
-               return -EOPNOTSUPP;
-
        if (mode & FALLOC_FL_COLLAPSE_RANGE)
                return ext4_collapse_range(inode, offset, len);
 
@@ -4955,6 +4948,14 @@ long ext4_fallocate(struct file *file, int mode, loff_t offset, loff_t len)
 
        mutex_lock(&inode->i_mutex);
 
+       /*
+        * We only support preallocation for extent-based files only
+        */
+       if (!(ext4_test_inode_flag(inode, EXT4_INODE_EXTENTS))) {
+               ret = -EOPNOTSUPP;
+               goto out;
+       }
+
        if (!(mode & FALLOC_FL_KEEP_SIZE) &&
             offset + len > i_size_read(inode)) {
                new_size = offset + len;
@@ -5395,6 +5396,14 @@ int ext4_collapse_range(struct inode *inode, loff_t offset, loff_t len)
        loff_t new_size, ioffset;
        int ret;
 
+       /*
+        * We need to test this early because xfstests assumes that a
+        * collapse range of (0, 1) will return EOPNOTSUPP if the file
+        * system does not support collapse range.
+        */
+       if (!ext4_test_inode_flag(inode, EXT4_INODE_EXTENTS))
+               return -EOPNOTSUPP;
+
        /* Collapse range works only on fs block size aligned offsets. */
        if (offset & (EXT4_CLUSTER_SIZE(sb) - 1) ||
            len & (EXT4_CLUSTER_SIZE(sb) - 1))
index d33d5a6852b9b97610a0bd365f014bc0a8094876..26724aeece7396a7b55e20c22e586b1776a5b190 100644 (file)
@@ -703,6 +703,14 @@ int ext4_es_insert_extent(struct inode *inode, ext4_lblk_t lblk,
 
        BUG_ON(end < lblk);
 
+       if ((status & EXTENT_STATUS_DELAYED) &&
+           (status & EXTENT_STATUS_WRITTEN)) {
+               ext4_warning(inode->i_sb, "Inserting extent [%u/%u] as "
+                               " delayed and written which can potentially "
+                               " cause data loss.\n", lblk, len);
+               WARN_ON(1);
+       }
+
        newes.es_lblk = lblk;
        newes.es_len = len;
        ext4_es_store_pblock_status(&newes, pblk, status);
index cbd0654a26750e8827f1e40b5b1ae07192bd066b..0554b0b5957bb5db223534f2116d5eea18eae2d4 100644 (file)
@@ -531,6 +531,7 @@ int ext4_map_blocks(handle_t *handle, struct inode *inode,
                status = map->m_flags & EXT4_MAP_UNWRITTEN ?
                                EXTENT_STATUS_UNWRITTEN : EXTENT_STATUS_WRITTEN;
                if (!(flags & EXT4_GET_BLOCKS_DELALLOC_RESERVE) &&
+                   !(status & EXTENT_STATUS_WRITTEN) &&
                    ext4_find_delalloc_range(inode, map->m_lblk,
                                             map->m_lblk + map->m_len - 1))
                        status |= EXTENT_STATUS_DELAYED;
@@ -635,6 +636,7 @@ found:
                status = map->m_flags & EXT4_MAP_UNWRITTEN ?
                                EXTENT_STATUS_UNWRITTEN : EXTENT_STATUS_WRITTEN;
                if (!(flags & EXT4_GET_BLOCKS_DELALLOC_RESERVE) &&
+                   !(status & EXTENT_STATUS_WRITTEN) &&
                    ext4_find_delalloc_range(inode, map->m_lblk,
                                             map->m_lblk + map->m_len - 1))
                        status |= EXTENT_STATUS_DELAYED;
@@ -4343,7 +4345,7 @@ static void ext4_update_other_inodes_time(struct super_block *sb,
        int inode_size = EXT4_INODE_SIZE(sb);
 
        oi.orig_ino = orig_ino;
-       ino = orig_ino & ~(inodes_per_block - 1);
+       ino = (orig_ino & ~(inodes_per_block - 1)) + 1;
        for (i = 0; i < inodes_per_block; i++, ino++, buf += inode_size) {
                if (ino == orig_ino)
                        continue;
index 7223b0b4bc38cd0a67a8b53eadcd616396d5dce5..814f3beb436965f116b7555ee8cf9ac30c3f0165 100644 (file)
@@ -640,7 +640,7 @@ static struct stats dx_show_leaf(struct inode *dir,
                                                ext4_put_fname_crypto_ctx(&ctx);
                                                ctx = NULL;
                                        }
-                                       res = ext4_fname_disk_to_usr(ctx, de,
+                                       res = ext4_fname_disk_to_usr(ctx, NULL, de,
                                                        &fname_crypto_str);
                                        if (res < 0) {
                                                printk(KERN_WARNING "Error "
@@ -653,15 +653,8 @@ static struct stats dx_show_leaf(struct inode *dir,
                                                name = fname_crypto_str.name;
                                                len = fname_crypto_str.len;
                                        }
-                                       res = ext4_fname_disk_to_hash(ctx, de,
-                                                                     &h);
-                                       if (res < 0) {
-                                               printk(KERN_WARNING "Error "
-                                                       "converting filename "
-                                                       "from disk to htree"
-                                                       "\n");
-                                               h.hash = 0xDEADBEEF;
-                                       }
+                                       ext4fs_dirhash(de->name, de->name_len,
+                                                      &h);
                                        printk("%*.s:(E)%x.%u ", len, name,
                                               h.hash, (unsigned) ((char *) de
                                                                   - base));
@@ -1008,15 +1001,7 @@ static int htree_dirblock_to_tree(struct file *dir_file,
                        /* silently ignore the rest of the block */
                        break;
                }
-#ifdef CONFIG_EXT4_FS_ENCRYPTION
-               err = ext4_fname_disk_to_hash(ctx, de, hinfo);
-               if (err < 0) {
-                       count = err;
-                       goto errout;
-               }
-#else
                ext4fs_dirhash(de->name, de->name_len, hinfo);
-#endif
                if ((hinfo->hash < start_hash) ||
                    ((hinfo->hash == start_hash) &&
                     (hinfo->minor_hash < start_minor_hash)))
@@ -1032,7 +1017,7 @@ static int htree_dirblock_to_tree(struct file *dir_file,
                                   &tmp_str);
                } else {
                        /* Directory is encrypted */
-                       err = ext4_fname_disk_to_usr(ctx, de,
+                       err = ext4_fname_disk_to_usr(ctx, hinfo, de,
                                                     &fname_crypto_str);
                        if (err < 0) {
                                count = err;
@@ -1193,26 +1178,10 @@ static int dx_make_map(struct inode *dir, struct ext4_dir_entry_2 *de,
        int count = 0;
        char *base = (char *) de;
        struct dx_hash_info h = *hinfo;
-#ifdef CONFIG_EXT4_FS_ENCRYPTION
-       struct ext4_fname_crypto_ctx *ctx = NULL;
-       int err;
-
-       ctx = ext4_get_fname_crypto_ctx(dir, EXT4_NAME_LEN);
-       if (IS_ERR(ctx))
-               return PTR_ERR(ctx);
-#endif
 
        while ((char *) de < base + blocksize) {
                if (de->name_len && de->inode) {
-#ifdef CONFIG_EXT4_FS_ENCRYPTION
-                       err = ext4_fname_disk_to_hash(ctx, de, &h);
-                       if (err < 0) {
-                               ext4_put_fname_crypto_ctx(&ctx);
-                               return err;
-                       }
-#else
                        ext4fs_dirhash(de->name, de->name_len, &h);
-#endif
                        map_tail--;
                        map_tail->hash = h.hash;
                        map_tail->offs = ((char *) de - base)>>2;
@@ -1223,9 +1192,6 @@ static int dx_make_map(struct inode *dir, struct ext4_dir_entry_2 *de,
                /* XXX: do we need to check rec_len == 0 case? -Chris */
                de = ext4_next_entry(de, blocksize);
        }
-#ifdef CONFIG_EXT4_FS_ENCRYPTION
-       ext4_put_fname_crypto_ctx(&ctx);
-#endif
        return count;
 }
 
@@ -1287,16 +1253,8 @@ static inline int ext4_match(struct ext4_fname_crypto_ctx *ctx,
                return 0;
 
 #ifdef CONFIG_EXT4_FS_ENCRYPTION
-       if (ctx) {
-               /* Directory is encrypted */
-               res = ext4_fname_disk_to_usr(ctx, de, fname_crypto_str);
-               if (res < 0)
-                       return res;
-               if (len != res)
-                       return 0;
-               res = memcmp(name, fname_crypto_str->name, len);
-               return (res == 0) ? 1 : 0;
-       }
+       if (ctx)
+               return ext4_fname_match(ctx, fname_crypto_str, len, name, de);
 #endif
        if (len != de->name_len)
                return 0;
@@ -1324,16 +1282,6 @@ int search_dir(struct buffer_head *bh, char *search_buf, int buf_size,
        if (IS_ERR(ctx))
                return -1;
 
-       if (ctx != NULL) {
-               /* Allocate buffer to hold maximum name length */
-               res = ext4_fname_crypto_alloc_buffer(ctx, EXT4_NAME_LEN,
-                                                    &fname_crypto_str);
-               if (res < 0) {
-                       ext4_put_fname_crypto_ctx(&ctx);
-                       return -1;
-               }
-       }
-
        de = (struct ext4_dir_entry_2 *)search_buf;
        dlimit = search_buf + buf_size;
        while ((char *) de < dlimit) {
@@ -1872,14 +1820,6 @@ int ext4_find_dest_de(struct inode *dir, struct inode *inode,
                        return res;
                }
                reclen = EXT4_DIR_REC_LEN(res);
-
-               /* Allocate buffer to hold maximum name length */
-               res = ext4_fname_crypto_alloc_buffer(ctx, EXT4_NAME_LEN,
-                                                    &fname_crypto_str);
-               if (res < 0) {
-                       ext4_put_fname_crypto_ctx(&ctx);
-                       return -1;
-               }
        }
 
        de = (struct ext4_dir_entry_2 *)buf;
index 8a8ec6293b195f16623e716342463979427b3156..cf0c472047e3a89a84e262c7eeddd7ca72fd1b8c 100644 (file)
@@ -1432,12 +1432,15 @@ static int ext4_flex_group_add(struct super_block *sb,
                goto exit;
        /*
         * We will always be modifying at least the superblock and  GDT
-        * block.  If we are adding a group past the last current GDT block,
+        * blocks.  If we are adding a group past the last current GDT block,
         * we will also modify the inode and the dindirect block.  If we
         * are adding a group with superblock/GDT backups  we will also
         * modify each of the reserved GDT dindirect blocks.
         */
-       credit = flex_gd->count * 4 + reserved_gdb;
+       credit = 3;     /* sb, resize inode, resize inode dindirect */
+       /* GDT blocks */
+       credit += 1 + DIV_ROUND_UP(flex_gd->count, EXT4_DESC_PER_BLOCK(sb));
+       credit += reserved_gdb; /* Reserved GDT dindirect blocks */
        handle = ext4_journal_start_sb(sb, EXT4_HT_RESIZE, credit);
        if (IS_ERR(handle)) {
                err = PTR_ERR(handle);
index f06d0589ddba5db7226a38a6e0de3ef2cdee48d9..ca9d4a2fed415649cd9744fdac2a1e8bdfa1631a 100644 (file)
@@ -294,6 +294,8 @@ static void __save_error_info(struct super_block *sb, const char *func,
        struct ext4_super_block *es = EXT4_SB(sb)->s_es;
 
        EXT4_SB(sb)->s_mount_state |= EXT4_ERROR_FS;
+       if (bdev_read_only(sb->s_bdev))
+               return;
        es->s_state |= cpu_to_le16(EXT4_ERROR_FS);
        es->s_last_error_time = cpu_to_le32(get_seconds());
        strncpy(es->s_last_error_func, func, sizeof(es->s_last_error_func));
index 19f78f20975ea723f33e6488750f9645a7ea2d4a..187b789203142d6b444b264acd44798427626b41 100644 (file)
@@ -74,7 +74,7 @@ static void *ext4_follow_link(struct dentry *dentry, struct nameidata *nd)
                goto errout;
        }
        pstr.name = paddr;
-       res = _ext4_fname_disk_to_usr(ctx, &cstr, &pstr);
+       res = _ext4_fname_disk_to_usr(ctx, NULL, &cstr, &pstr);
        if (res < 0)
                goto errout;
        /* Null-terminate the name */
index b91b0e10678eb1adcb87e45628f7794caa0dcc9b..1e1aae669fa86275d7b6c932aeda89ded129ce17 100644 (file)
@@ -1513,6 +1513,7 @@ static int f2fs_write_data_pages(struct address_space *mapping,
 {
        struct inode *inode = mapping->host;
        struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
+       bool locked = false;
        int ret;
        long diff;
 
@@ -1533,7 +1534,13 @@ static int f2fs_write_data_pages(struct address_space *mapping,
 
        diff = nr_pages_to_write(sbi, DATA, wbc);
 
+       if (!S_ISDIR(inode->i_mode)) {
+               mutex_lock(&sbi->writepages);
+               locked = true;
+       }
        ret = write_cache_pages(mapping, wbc, __f2fs_writepage, mapping);
+       if (locked)
+               mutex_unlock(&sbi->writepages);
 
        f2fs_submit_merged_bio(sbi, DATA, WRITE);
 
index d8921cf2ba9a04454e553a75535dfa84d2b4da67..8de34ab6d5b1c5340276a5780bac1c133ac582fb 100644 (file)
@@ -625,6 +625,7 @@ struct f2fs_sb_info {
        struct mutex cp_mutex;                  /* checkpoint procedure lock */
        struct rw_semaphore cp_rwsem;           /* blocking FS operations */
        struct rw_semaphore node_write;         /* locking node writes */
+       struct mutex writepages;                /* mutex for writepages() */
        wait_queue_head_t cp_wait;
 
        struct inode_management im[MAX_INO_ENTRY];      /* manage inode cache */
index 7e3794edae42ab5c656f2ae9fec69e7431476b35..658e8079aaf9b9020068bd30aad723d168899309 100644 (file)
@@ -298,16 +298,14 @@ fail:
 
 static void *f2fs_follow_link(struct dentry *dentry, struct nameidata *nd)
 {
-       struct page *page;
+       struct page *page = page_follow_link_light(dentry, nd);
 
-       page = page_follow_link_light(dentry, nd);
-       if (IS_ERR(page))
+       if (IS_ERR_OR_NULL(page))
                return page;
 
        /* this is broken symlink case */
        if (*nd_get_link(nd) == 0) {
-               kunmap(page);
-               page_cache_release(page);
+               page_put_link(dentry, nd, page);
                return ERR_PTR(-ENOENT);
        }
        return page;
index 160b88346b2477466f3ed34d4d2dff2509742d7e..b2dd1b01f07634e27f42fc09e8fd627a70395e3e 100644 (file)
@@ -1035,6 +1035,7 @@ try_onemore:
        sbi->raw_super = raw_super;
        sbi->raw_super_buf = raw_super_buf;
        mutex_init(&sbi->gc_mutex);
+       mutex_init(&sbi->writepages);
        mutex_init(&sbi->cp_mutex);
        init_rwsem(&sbi->node_write);
        clear_sbi_flag(sbi, SBI_POR_DOING);
index 999ff5c3cab0edacd585447132180d5c35554e3c..d59712dfa3e701e86ff53609308e813cf8acf69e 100644 (file)
@@ -195,8 +195,9 @@ static int handle_to_path(int mountdirfd, struct file_handle __user *ufh,
                goto out_err;
        }
        /* copy the full handle */
-       if (copy_from_user(handle, ufh,
-                          sizeof(struct file_handle) +
+       *handle = f_handle;
+       if (copy_from_user(&handle->f_handle,
+                          &ufh->f_handle,
                           f_handle.handle_bytes)) {
                retval = -EFAULT;
                goto out_handle;
index ef263174acd23a88f2a110b80a67afc2fab2ddc0..07d8d8f52faf50d027f2f90a1699c7afa274aa34 100644 (file)
@@ -581,7 +581,7 @@ static int hostfs_create(struct inode *dir, struct dentry *dentry, umode_t mode,
        if (name == NULL)
                goto out_put;
 
-       fd = file_create(name, mode & S_IFMT);
+       fd = file_create(name, mode & 0777);
        if (fd < 0)
                error = fd;
        else
index b5128c6e63ad6644d19bf861a062d63f48265a4d..a9079d035ae59d9a6983bcaa79625ce5f0e5c343 100644 (file)
@@ -842,15 +842,23 @@ static int scan_revoke_records(journal_t *journal, struct buffer_head *bh,
 {
        jbd2_journal_revoke_header_t *header;
        int offset, max;
+       int csum_size = 0;
+       __u32 rcount;
        int record_len = 4;
 
        header = (jbd2_journal_revoke_header_t *) bh->b_data;
        offset = sizeof(jbd2_journal_revoke_header_t);
-       max = be32_to_cpu(header->r_count);
+       rcount = be32_to_cpu(header->r_count);
 
        if (!jbd2_revoke_block_csum_verify(journal, header))
                return -EINVAL;
 
+       if (jbd2_journal_has_csum_v2or3(journal))
+               csum_size = sizeof(struct jbd2_journal_revoke_tail);
+       if (rcount > journal->j_blocksize - csum_size)
+               return -EINVAL;
+       max = rcount;
+
        if (JBD2_HAS_INCOMPAT_FEATURE(journal, JBD2_FEATURE_INCOMPAT_64BIT))
                record_len = 8;
 
index c6cbaef2bda1498d8f2e00eeca30a40c8a462361..14214da80eb8ea5d781389ed5ff3b1e373f4e7b4 100644 (file)
@@ -577,7 +577,7 @@ static void write_one_revoke_record(journal_t *journal,
 {
        int csum_size = 0;
        struct buffer_head *descriptor;
-       int offset;
+       int sz, offset;
        journal_header_t *header;
 
        /* If we are already aborting, this all becomes a noop.  We
@@ -594,9 +594,14 @@ static void write_one_revoke_record(journal_t *journal,
        if (jbd2_journal_has_csum_v2or3(journal))
                csum_size = sizeof(struct jbd2_journal_revoke_tail);
 
+       if (JBD2_HAS_INCOMPAT_FEATURE(journal, JBD2_FEATURE_INCOMPAT_64BIT))
+               sz = 8;
+       else
+               sz = 4;
+
        /* Make sure we have a descriptor with space left for the record */
        if (descriptor) {
-               if (offset >= journal->j_blocksize - csum_size) {
+               if (offset + sz > journal->j_blocksize - csum_size) {
                        flush_descriptor(journal, descriptor, offset, write_op);
                        descriptor = NULL;
                }
@@ -619,16 +624,13 @@ static void write_one_revoke_record(journal_t *journal,
                *descriptorp = descriptor;
        }
 
-       if (JBD2_HAS_INCOMPAT_FEATURE(journal, JBD2_FEATURE_INCOMPAT_64BIT)) {
+       if (JBD2_HAS_INCOMPAT_FEATURE(journal, JBD2_FEATURE_INCOMPAT_64BIT))
                * ((__be64 *)(&descriptor->b_data[offset])) =
                        cpu_to_be64(record->blocknr);
-               offset += 8;
-
-       } else {
+       else
                * ((__be32 *)(&descriptor->b_data[offset])) =
                        cpu_to_be32(record->blocknr);
-               offset += 4;
-       }
+       offset += sz;
 
        *offsetp = offset;
 }
index 5f09370c90a8199647a87ef7cb6a5cfdba113d2b..ff2f2e6ad3114664cbcd80c3812b6b875f64807b 100644 (file)
@@ -551,7 +551,6 @@ int jbd2_journal_extend(handle_t *handle, int nblocks)
        int result;
        int wanted;
 
-       WARN_ON(!transaction);
        if (is_handle_aborted(handle))
                return -EROFS;
        journal = transaction->t_journal;
@@ -627,7 +626,6 @@ int jbd2__journal_restart(handle_t *handle, int nblocks, gfp_t gfp_mask)
        tid_t           tid;
        int             need_to_start, ret;
 
-       WARN_ON(!transaction);
        /* If we've had an abort of any type, don't even think about
         * actually doing the restart! */
        if (is_handle_aborted(handle))
@@ -785,7 +783,6 @@ do_get_write_access(handle_t *handle, struct journal_head *jh,
        int need_copy = 0;
        unsigned long start_lock, time_lock;
 
-       WARN_ON(!transaction);
        if (is_handle_aborted(handle))
                return -EROFS;
        journal = transaction->t_journal;
@@ -1051,7 +1048,6 @@ int jbd2_journal_get_create_access(handle_t *handle, struct buffer_head *bh)
        int err;
 
        jbd_debug(5, "journal_head %p\n", jh);
-       WARN_ON(!transaction);
        err = -EROFS;
        if (is_handle_aborted(handle))
                goto out;
@@ -1266,7 +1262,6 @@ int jbd2_journal_dirty_metadata(handle_t *handle, struct buffer_head *bh)
        struct journal_head *jh;
        int ret = 0;
 
-       WARN_ON(!transaction);
        if (is_handle_aborted(handle))
                return -EROFS;
        journal = transaction->t_journal;
@@ -1397,7 +1392,6 @@ int jbd2_journal_forget (handle_t *handle, struct buffer_head *bh)
        int err = 0;
        int was_modified = 0;
 
-       WARN_ON(!transaction);
        if (is_handle_aborted(handle))
                return -EROFS;
        journal = transaction->t_journal;
@@ -1530,8 +1524,22 @@ int jbd2_journal_stop(handle_t *handle)
        tid_t tid;
        pid_t pid;
 
-       if (!transaction)
-               goto free_and_exit;
+       if (!transaction) {
+               /*
+                * Handle is already detached from the transaction so
+                * there is nothing to do other than decrease a refcount,
+                * or free the handle if refcount drops to zero
+                */
+               if (--handle->h_ref > 0) {
+                       jbd_debug(4, "h_ref %d -> %d\n", handle->h_ref + 1,
+                                                        handle->h_ref);
+                       return err;
+               } else {
+                       if (handle->h_rsv_handle)
+                               jbd2_free_handle(handle->h_rsv_handle);
+                       goto free_and_exit;
+               }
+       }
        journal = transaction->t_journal;
 
        J_ASSERT(journal_current_handle() == handle);
@@ -2373,7 +2381,6 @@ int jbd2_journal_file_inode(handle_t *handle, struct jbd2_inode *jinode)
        transaction_t *transaction = handle->h_transaction;
        journal_t *journal;
 
-       WARN_ON(!transaction);
        if (is_handle_aborted(handle))
                return -EROFS;
        journal = transaction->t_journal;
index f131fc23ffc4c18f03a9764973fa998bf0e5f79e..fffca9517321c88ee1e0128b864b257c56e2350d 100644 (file)
@@ -518,7 +518,14 @@ static struct kernfs_node *__kernfs_new_node(struct kernfs_root *root,
        if (!kn)
                goto err_out1;
 
-       ret = ida_simple_get(&root->ino_ida, 1, 0, GFP_KERNEL);
+       /*
+        * If the ino of the sysfs entry created for a kmem cache gets
+        * allocated from an ida layer, which is accounted to the memcg that
+        * owns the cache, the memcg will get pinned forever. So do not account
+        * ino ida allocations.
+        */
+       ret = ida_simple_get(&root->ino_ida, 1, 0,
+                            GFP_KERNEL | __GFP_NOACCOUNT);
        if (ret < 0)
                goto err_out2;
        kn->ino = ret;
index 4a8d998b7274b3406532cc012d05ee18aa9b5bba..fe30d3be43a8b381d3b9ac3016b28531996f91b7 100644 (file)
@@ -1415,6 +1415,7 @@ static int lookup_fast(struct nameidata *nd,
         */
        if (nd->flags & LOOKUP_RCU) {
                unsigned seq;
+               bool negative;
                dentry = __d_lookup_rcu(parent, &nd->last, &seq);
                if (!dentry)
                        goto unlazy;
@@ -1424,8 +1425,11 @@ static int lookup_fast(struct nameidata *nd,
                 * the dentry name information from lookup.
                 */
                *inode = dentry->d_inode;
+               negative = d_is_negative(dentry);
                if (read_seqcount_retry(&dentry->d_seq, seq))
                        return -ECHILD;
+               if (negative)
+                       return -ENOENT;
 
                /*
                 * This sequence count validates that the parent had no
@@ -1472,6 +1476,10 @@ unlazy:
                goto need_lookup;
        }
 
+       if (unlikely(d_is_negative(dentry))) {
+               dput(dentry);
+               return -ENOENT;
+       }
        path->mnt = mnt;
        path->dentry = dentry;
        err = follow_managed(path, nd->flags);
@@ -1583,10 +1591,10 @@ static inline int walk_component(struct nameidata *nd, struct path *path,
                        goto out_err;
 
                inode = path->dentry->d_inode;
+               err = -ENOENT;
+               if (d_is_negative(path->dentry))
+                       goto out_path_put;
        }
-       err = -ENOENT;
-       if (d_is_negative(path->dentry))
-               goto out_path_put;
 
        if (should_follow_link(path->dentry, follow)) {
                if (nd->flags & LOOKUP_RCU) {
@@ -3036,14 +3044,13 @@ retry_lookup:
 
        BUG_ON(nd->flags & LOOKUP_RCU);
        inode = path->dentry->d_inode;
-finish_lookup:
-       /* we _can_ be in RCU mode here */
        error = -ENOENT;
        if (d_is_negative(path->dentry)) {
                path_to_nameidata(path, nd);
                goto out;
        }
-
+finish_lookup:
+       /* we _can_ be in RCU mode here */
        if (should_follow_link(path->dentry, !symlink_ok)) {
                if (nd->flags & LOOKUP_RCU) {
                        if (unlikely(nd->path.mnt != path->mnt ||
@@ -3226,7 +3233,7 @@ static struct file *path_openat(int dfd, struct filename *pathname,
 
        if (unlikely(file->f_flags & __O_TMPFILE)) {
                error = do_tmpfile(dfd, pathname, nd, flags, op, file, &opened);
-               goto out;
+               goto out2;
        }
 
        error = path_init(dfd, pathname, flags, nd);
@@ -3256,6 +3263,7 @@ static struct file *path_openat(int dfd, struct filename *pathname,
        }
 out:
        path_cleanup(nd);
+out2:
        if (!(opened & FILE_OPENED)) {
                BUG_ON(!error);
                put_filp(file);
index 1f4f9dac6e5af8017e41ab497b92e0515e5ed71c..1b9e11167baedc310b8f5b6585ac019abd78b915 100644 (file)
@@ -3179,6 +3179,12 @@ bool fs_fully_visible(struct file_system_type *type)
                if (mnt->mnt.mnt_sb->s_type != type)
                        continue;
 
+               /* This mount is not fully visible if it's root directory
+                * is not the root directory of the filesystem.
+                */
+               if (mnt->mnt.mnt_root != mnt->mnt.mnt_sb->s_root)
+                       continue;
+
                /* This mount is not fully visible if there are any child mounts
                 * that cover anything except for empty directories.
                 */
index 45b35b9b1e36a1213a2c2736e4ae551dcd0d8848..55e1e3af23a3d3f2313f977b185eb8c3f8ccbc6d 100644 (file)
@@ -38,6 +38,7 @@
 #include <linux/mm.h>
 #include <linux/delay.h>
 #include <linux/errno.h>
+#include <linux/file.h>
 #include <linux/string.h>
 #include <linux/ratelimit.h>
 #include <linux/printk.h>
@@ -5604,6 +5605,7 @@ static struct nfs4_lockdata *nfs4_alloc_lockdata(struct file_lock *fl,
        p->server = server;
        atomic_inc(&lsp->ls_count);
        p->ctx = get_nfs_open_context(ctx);
+       get_file(fl->fl_file);
        memcpy(&p->fl, fl, sizeof(p->fl));
        return p;
 out_free_seqid:
@@ -5716,6 +5718,7 @@ static void nfs4_lock_release(void *calldata)
                nfs_free_seqid(data->arg.lock_seqid);
        nfs4_put_lock_state(data->lsp);
        put_nfs_open_context(data->ctx);
+       fput(data->fl.fl_file);
        kfree(data);
        dprintk("%s: done!\n", __func__);
 }
index d12a4be613a5ced58599f8095822f4659b32f9a4..dfc19f1575a19d00bee1b0aeef6575e4416a9ef9 100644 (file)
@@ -1845,12 +1845,15 @@ int nfs_wb_all(struct inode *inode)
        trace_nfs_writeback_inode_enter(inode);
 
        ret = filemap_write_and_wait(inode->i_mapping);
-       if (!ret) {
-               ret = nfs_commit_inode(inode, FLUSH_SYNC);
-               if (!ret)
-                       pnfs_sync_inode(inode, true);
-       }
+       if (ret)
+               goto out;
+       ret = nfs_commit_inode(inode, FLUSH_SYNC);
+       if (ret < 0)
+               goto out;
+       pnfs_sync_inode(inode, true);
+       ret = 0;
 
+out:
        trace_nfs_writeback_inode_exit(inode, ret);
        return ret;
 }
index 03d647bf195d78bb3d6611553c9ad3e6fa4385a2..cdefaa331a0719e88df91ef7c04c32706ae199a1 100644 (file)
@@ -181,6 +181,17 @@ nfsd4_block_proc_layoutcommit(struct inode *inode,
 }
 
 const struct nfsd4_layout_ops bl_layout_ops = {
+       /*
+        * Pretend that we send notification to the client.  This is a blatant
+        * lie to force recent Linux clients to cache our device IDs.
+        * We rarely ever change the device ID, so the harm of leaking deviceids
+        * for a while isn't too bad.  Unfortunately RFC5661 is a complete mess
+        * in this regard, but I filed errata 4119 for this a while ago, and
+        * hopefully the Linux client will eventually start caching deviceids
+        * without this again.
+        */
+       .notify_types           =
+                       NOTIFY_DEVICEID4_DELETE | NOTIFY_DEVICEID4_CHANGE,
        .proc_getdeviceinfo     = nfsd4_block_proc_getdeviceinfo,
        .encode_getdeviceinfo   = nfsd4_block_encode_getdeviceinfo,
        .proc_layoutget         = nfsd4_block_proc_layoutget,
index 58277859a467d878cf5cd5d947d7361f8b3396cf..5694cfb7a47b73a0d7128ed987cf1aaba6ea8859 100644 (file)
@@ -224,7 +224,7 @@ static int nfs_cb_stat_to_errno(int status)
 }
 
 static int decode_cb_op_status(struct xdr_stream *xdr, enum nfs_opnum4 expected,
-                              enum nfsstat4 *status)
+                              int *status)
 {
        __be32 *p;
        u32 op;
@@ -235,7 +235,7 @@ static int decode_cb_op_status(struct xdr_stream *xdr, enum nfs_opnum4 expected,
        op = be32_to_cpup(p++);
        if (unlikely(op != expected))
                goto out_unexpected;
-       *status = be32_to_cpup(p);
+       *status = nfs_cb_stat_to_errno(be32_to_cpup(p));
        return 0;
 out_overflow:
        print_overflow_msg(__func__, xdr);
@@ -446,22 +446,16 @@ out_overflow:
 static int decode_cb_sequence4res(struct xdr_stream *xdr,
                                  struct nfsd4_callback *cb)
 {
-       enum nfsstat4 nfserr;
        int status;
 
        if (cb->cb_minorversion == 0)
                return 0;
 
-       status = decode_cb_op_status(xdr, OP_CB_SEQUENCE, &nfserr);
-       if (unlikely(status))
-               goto out;
-       if (unlikely(nfserr != NFS4_OK))
-               goto out_default;
-       status = decode_cb_sequence4resok(xdr, cb);
-out:
-       return status;
-out_default:
-       return nfs_cb_stat_to_errno(nfserr);
+       status = decode_cb_op_status(xdr, OP_CB_SEQUENCE, &cb->cb_status);
+       if (unlikely(status || cb->cb_status))
+               return status;
+
+       return decode_cb_sequence4resok(xdr, cb);
 }
 
 /*
@@ -524,26 +518,19 @@ static int nfs4_xdr_dec_cb_recall(struct rpc_rqst *rqstp,
                                  struct nfsd4_callback *cb)
 {
        struct nfs4_cb_compound_hdr hdr;
-       enum nfsstat4 nfserr;
        int status;
 
        status = decode_cb_compound4res(xdr, &hdr);
        if (unlikely(status))
-               goto out;
+               return status;
 
        if (cb != NULL) {
                status = decode_cb_sequence4res(xdr, cb);
-               if (unlikely(status))
-                       goto out;
+               if (unlikely(status || cb->cb_status))
+                       return status;
        }
 
-       status = decode_cb_op_status(xdr, OP_CB_RECALL, &nfserr);
-       if (unlikely(status))
-               goto out;
-       if (unlikely(nfserr != NFS4_OK))
-               status = nfs_cb_stat_to_errno(nfserr);
-out:
-       return status;
+       return decode_cb_op_status(xdr, OP_CB_RECALL, &cb->cb_status);
 }
 
 #ifdef CONFIG_NFSD_PNFS
@@ -621,24 +608,18 @@ static int nfs4_xdr_dec_cb_layout(struct rpc_rqst *rqstp,
                                  struct nfsd4_callback *cb)
 {
        struct nfs4_cb_compound_hdr hdr;
-       enum nfsstat4 nfserr;
        int status;
 
        status = decode_cb_compound4res(xdr, &hdr);
        if (unlikely(status))
-               goto out;
+               return status;
+
        if (cb) {
                status = decode_cb_sequence4res(xdr, cb);
-               if (unlikely(status))
-                       goto out;
+               if (unlikely(status || cb->cb_status))
+                       return status;
        }
-       status = decode_cb_op_status(xdr, OP_CB_LAYOUTRECALL, &nfserr);
-       if (unlikely(status))
-               goto out;
-       if (unlikely(nfserr != NFS4_OK))
-               status = nfs_cb_stat_to_errno(nfserr);
-out:
-       return status;
+       return decode_cb_op_status(xdr, OP_CB_LAYOUTRECALL, &cb->cb_status);
 }
 #endif /* CONFIG_NFSD_PNFS */
 
@@ -898,13 +879,6 @@ static void nfsd4_cb_prepare(struct rpc_task *task, void *calldata)
                if (!nfsd41_cb_get_slot(clp, task))
                        return;
        }
-       spin_lock(&clp->cl_lock);
-       if (list_empty(&cb->cb_per_client)) {
-               /* This is the first call, not a restart */
-               cb->cb_done = false;
-               list_add(&cb->cb_per_client, &clp->cl_callbacks);
-       }
-       spin_unlock(&clp->cl_lock);
        rpc_call_start(task);
 }
 
@@ -918,22 +892,33 @@ static void nfsd4_cb_done(struct rpc_task *task, void *calldata)
 
        if (clp->cl_minorversion) {
                /* No need for lock, access serialized in nfsd4_cb_prepare */
-               ++clp->cl_cb_session->se_cb_seq_nr;
+               if (!task->tk_status)
+                       ++clp->cl_cb_session->se_cb_seq_nr;
                clear_bit(0, &clp->cl_cb_slot_busy);
                rpc_wake_up_next(&clp->cl_cb_waitq);
                dprintk("%s: freed slot, new seqid=%d\n", __func__,
                        clp->cl_cb_session->se_cb_seq_nr);
        }
 
-       if (clp->cl_cb_client != task->tk_client) {
-               /* We're shutting down or changing cl_cb_client; leave
-                * it to nfsd4_process_cb_update to restart the call if
-                * necessary. */
+       /*
+        * If the backchannel connection was shut down while this
+        * task was queued, we need to resubmit it after setting up
+        * a new backchannel connection.
+        *
+        * Note that if we lost our callback connection permanently
+        * the submission code will error out, so we don't need to
+        * handle that case here.
+        */
+       if (task->tk_flags & RPC_TASK_KILLED) {
+               task->tk_status = 0;
+               cb->cb_need_restart = true;
                return;
        }
 
-       if (cb->cb_done)
-               return;
+       if (cb->cb_status) {
+               WARN_ON_ONCE(task->tk_status);
+               task->tk_status = cb->cb_status;
+       }
 
        switch (cb->cb_ops->done(cb, task)) {
        case 0:
@@ -949,21 +934,17 @@ static void nfsd4_cb_done(struct rpc_task *task, void *calldata)
        default:
                BUG();
        }
-       cb->cb_done = true;
 }
 
 static void nfsd4_cb_release(void *calldata)
 {
        struct nfsd4_callback *cb = calldata;
-       struct nfs4_client *clp = cb->cb_clp;
-
-       if (cb->cb_done) {
-               spin_lock(&clp->cl_lock);
-               list_del(&cb->cb_per_client);
-               spin_unlock(&clp->cl_lock);
 
+       if (cb->cb_need_restart)
+               nfsd4_run_cb(cb);
+       else
                cb->cb_ops->release(cb);
-       }
+
 }
 
 static const struct rpc_call_ops nfsd4_cb_ops = {
@@ -1058,9 +1039,6 @@ static void nfsd4_process_cb_update(struct nfsd4_callback *cb)
                nfsd4_mark_cb_down(clp, err);
                return;
        }
-       /* Yay, the callback channel's back! Restart any callbacks: */
-       list_for_each_entry(cb, &clp->cl_callbacks, cb_per_client)
-               queue_work(callback_wq, &cb->cb_work);
 }
 
 static void
@@ -1071,8 +1049,12 @@ nfsd4_run_cb_work(struct work_struct *work)
        struct nfs4_client *clp = cb->cb_clp;
        struct rpc_clnt *clnt;
 
-       if (cb->cb_ops && cb->cb_ops->prepare)
-               cb->cb_ops->prepare(cb);
+       if (cb->cb_need_restart) {
+               cb->cb_need_restart = false;
+       } else {
+               if (cb->cb_ops && cb->cb_ops->prepare)
+                       cb->cb_ops->prepare(cb);
+       }
 
        if (clp->cl_flags & NFSD4_CLIENT_CB_FLAG_MASK)
                nfsd4_process_cb_update(cb);
@@ -1084,6 +1066,15 @@ nfsd4_run_cb_work(struct work_struct *work)
                        cb->cb_ops->release(cb);
                return;
        }
+
+       /*
+        * Don't send probe messages for 4.1 or later.
+        */
+       if (!cb->cb_ops && clp->cl_minorversion) {
+               clp->cl_cb_state = NFSD4_CB_UP;
+               return;
+       }
+
        cb->cb_msg.rpc_cred = clp->cl_cb_cred;
        rpc_call_async(clnt, &cb->cb_msg, RPC_TASK_SOFT | RPC_TASK_SOFTCONN,
                        cb->cb_ops ? &nfsd4_cb_ops : &nfsd4_cb_probe_ops, cb);
@@ -1098,8 +1089,8 @@ void nfsd4_init_cb(struct nfsd4_callback *cb, struct nfs4_client *clp,
        cb->cb_msg.rpc_resp = cb;
        cb->cb_ops = ops;
        INIT_WORK(&cb->cb_work, nfsd4_run_cb_work);
-       INIT_LIST_HEAD(&cb->cb_per_client);
-       cb->cb_done = true;
+       cb->cb_status = 0;
+       cb->cb_need_restart = false;
 }
 
 void nfsd4_run_cb(struct nfsd4_callback *cb)
index 38f2d7abe3a707061c3f860ce8042649bf5109eb..039f9c8a95e84289c7296e9b78973efbea9d6e5a 100644 (file)
@@ -94,6 +94,7 @@ static struct kmem_cache *lockowner_slab;
 static struct kmem_cache *file_slab;
 static struct kmem_cache *stateid_slab;
 static struct kmem_cache *deleg_slab;
+static struct kmem_cache *odstate_slab;
 
 static void free_session(struct nfsd4_session *);
 
@@ -281,6 +282,7 @@ put_nfs4_file(struct nfs4_file *fi)
        if (atomic_dec_and_lock(&fi->fi_ref, &state_lock)) {
                hlist_del_rcu(&fi->fi_hash);
                spin_unlock(&state_lock);
+               WARN_ON_ONCE(!list_empty(&fi->fi_clnt_odstate));
                WARN_ON_ONCE(!list_empty(&fi->fi_delegations));
                call_rcu(&fi->fi_rcu, nfsd4_free_file_rcu);
        }
@@ -471,6 +473,86 @@ static void nfs4_file_put_access(struct nfs4_file *fp, u32 access)
                __nfs4_file_put_access(fp, O_RDONLY);
 }
 
+/*
+ * Allocate a new open/delegation state counter. This is needed for
+ * pNFS for proper return on close semantics.
+ *
+ * Note that we only allocate it for pNFS-enabled exports, otherwise
+ * all pointers to struct nfs4_clnt_odstate are always NULL.
+ */
+static struct nfs4_clnt_odstate *
+alloc_clnt_odstate(struct nfs4_client *clp)
+{
+       struct nfs4_clnt_odstate *co;
+
+       co = kmem_cache_zalloc(odstate_slab, GFP_KERNEL);
+       if (co) {
+               co->co_client = clp;
+               atomic_set(&co->co_odcount, 1);
+       }
+       return co;
+}
+
+static void
+hash_clnt_odstate_locked(struct nfs4_clnt_odstate *co)
+{
+       struct nfs4_file *fp = co->co_file;
+
+       lockdep_assert_held(&fp->fi_lock);
+       list_add(&co->co_perfile, &fp->fi_clnt_odstate);
+}
+
+static inline void
+get_clnt_odstate(struct nfs4_clnt_odstate *co)
+{
+       if (co)
+               atomic_inc(&co->co_odcount);
+}
+
+static void
+put_clnt_odstate(struct nfs4_clnt_odstate *co)
+{
+       struct nfs4_file *fp;
+
+       if (!co)
+               return;
+
+       fp = co->co_file;
+       if (atomic_dec_and_lock(&co->co_odcount, &fp->fi_lock)) {
+               list_del(&co->co_perfile);
+               spin_unlock(&fp->fi_lock);
+
+               nfsd4_return_all_file_layouts(co->co_client, fp);
+               kmem_cache_free(odstate_slab, co);
+       }
+}
+
+static struct nfs4_clnt_odstate *
+find_or_hash_clnt_odstate(struct nfs4_file *fp, struct nfs4_clnt_odstate *new)
+{
+       struct nfs4_clnt_odstate *co;
+       struct nfs4_client *cl;
+
+       if (!new)
+               return NULL;
+
+       cl = new->co_client;
+
+       spin_lock(&fp->fi_lock);
+       list_for_each_entry(co, &fp->fi_clnt_odstate, co_perfile) {
+               if (co->co_client == cl) {
+                       get_clnt_odstate(co);
+                       goto out;
+               }
+       }
+       co = new;
+       co->co_file = fp;
+       hash_clnt_odstate_locked(new);
+out:
+       spin_unlock(&fp->fi_lock);
+       return co;
+}
+
 struct nfs4_stid *nfs4_alloc_stid(struct nfs4_client *cl,
                                         struct kmem_cache *slab)
 {
@@ -606,7 +688,8 @@ static void block_delegations(struct knfsd_fh *fh)
 }
 
 static struct nfs4_delegation *
-alloc_init_deleg(struct nfs4_client *clp, struct svc_fh *current_fh)
+alloc_init_deleg(struct nfs4_client *clp, struct svc_fh *current_fh,
+                struct nfs4_clnt_odstate *odstate)
 {
        struct nfs4_delegation *dp;
        long n;
@@ -631,6 +714,8 @@ alloc_init_deleg(struct nfs4_client *clp, struct svc_fh *current_fh)
        INIT_LIST_HEAD(&dp->dl_perfile);
        INIT_LIST_HEAD(&dp->dl_perclnt);
        INIT_LIST_HEAD(&dp->dl_recall_lru);
+       dp->dl_clnt_odstate = odstate;
+       get_clnt_odstate(odstate);
        dp->dl_type = NFS4_OPEN_DELEGATE_READ;
        dp->dl_retries = 1;
        nfsd4_init_cb(&dp->dl_recall, dp->dl_stid.sc_client,
@@ -714,6 +799,7 @@ static void destroy_delegation(struct nfs4_delegation *dp)
        spin_lock(&state_lock);
        unhash_delegation_locked(dp);
        spin_unlock(&state_lock);
+       put_clnt_odstate(dp->dl_clnt_odstate);
        nfs4_put_deleg_lease(dp->dl_stid.sc_file);
        nfs4_put_stid(&dp->dl_stid);
 }
@@ -724,6 +810,7 @@ static void revoke_delegation(struct nfs4_delegation *dp)
 
        WARN_ON(!list_empty(&dp->dl_recall_lru));
 
+       put_clnt_odstate(dp->dl_clnt_odstate);
        nfs4_put_deleg_lease(dp->dl_stid.sc_file);
 
        if (clp->cl_minorversion == 0)
@@ -933,6 +1020,7 @@ static void nfs4_free_ol_stateid(struct nfs4_stid *stid)
 {
        struct nfs4_ol_stateid *stp = openlockstateid(stid);
 
+       put_clnt_odstate(stp->st_clnt_odstate);
        release_all_access(stp);
        if (stp->st_stateowner)
                nfs4_put_stateowner(stp->st_stateowner);
@@ -1538,7 +1626,6 @@ static struct nfs4_client *alloc_client(struct xdr_netobj name)
        INIT_LIST_HEAD(&clp->cl_openowners);
        INIT_LIST_HEAD(&clp->cl_delegations);
        INIT_LIST_HEAD(&clp->cl_lru);
-       INIT_LIST_HEAD(&clp->cl_callbacks);
        INIT_LIST_HEAD(&clp->cl_revoked);
 #ifdef CONFIG_NFSD_PNFS
        INIT_LIST_HEAD(&clp->cl_lo_states);
@@ -1634,6 +1721,7 @@ __destroy_client(struct nfs4_client *clp)
        while (!list_empty(&reaplist)) {
                dp = list_entry(reaplist.next, struct nfs4_delegation, dl_recall_lru);
                list_del_init(&dp->dl_recall_lru);
+               put_clnt_odstate(dp->dl_clnt_odstate);
                nfs4_put_deleg_lease(dp->dl_stid.sc_file);
                nfs4_put_stid(&dp->dl_stid);
        }
@@ -3057,6 +3145,7 @@ static void nfsd4_init_file(struct knfsd_fh *fh, unsigned int hashval,
        spin_lock_init(&fp->fi_lock);
        INIT_LIST_HEAD(&fp->fi_stateids);
        INIT_LIST_HEAD(&fp->fi_delegations);
+       INIT_LIST_HEAD(&fp->fi_clnt_odstate);
        fh_copy_shallow(&fp->fi_fhandle, fh);
        fp->fi_deleg_file = NULL;
        fp->fi_had_conflict = false;
@@ -3073,6 +3162,7 @@ static void nfsd4_init_file(struct knfsd_fh *fh, unsigned int hashval,
 void
 nfsd4_free_slabs(void)
 {
+       kmem_cache_destroy(odstate_slab);
        kmem_cache_destroy(openowner_slab);
        kmem_cache_destroy(lockowner_slab);
        kmem_cache_destroy(file_slab);
@@ -3103,8 +3193,14 @@ nfsd4_init_slabs(void)
                        sizeof(struct nfs4_delegation), 0, 0, NULL);
        if (deleg_slab == NULL)
                goto out_free_stateid_slab;
+       odstate_slab = kmem_cache_create("nfsd4_odstate",
+                       sizeof(struct nfs4_clnt_odstate), 0, 0, NULL);
+       if (odstate_slab == NULL)
+               goto out_free_deleg_slab;
        return 0;
 
+out_free_deleg_slab:
+       kmem_cache_destroy(deleg_slab);
 out_free_stateid_slab:
        kmem_cache_destroy(stateid_slab);
 out_free_file_slab:
@@ -3581,6 +3677,14 @@ alloc_stateid:
        open->op_stp = nfs4_alloc_open_stateid(clp);
        if (!open->op_stp)
                return nfserr_jukebox;
+
+       if (nfsd4_has_session(cstate) &&
+           (cstate->current_fh.fh_export->ex_flags & NFSEXP_PNFS)) {
+               open->op_odstate = alloc_clnt_odstate(clp);
+               if (!open->op_odstate)
+                       return nfserr_jukebox;
+       }
+
        return nfs_ok;
 }
 
@@ -3869,7 +3973,7 @@ out_fput:
 
 static struct nfs4_delegation *
 nfs4_set_delegation(struct nfs4_client *clp, struct svc_fh *fh,
-                   struct nfs4_file *fp)
+                   struct nfs4_file *fp, struct nfs4_clnt_odstate *odstate)
 {
        int status;
        struct nfs4_delegation *dp;
@@ -3877,7 +3981,7 @@ nfs4_set_delegation(struct nfs4_client *clp, struct svc_fh *fh,
        if (fp->fi_had_conflict)
                return ERR_PTR(-EAGAIN);
 
-       dp = alloc_init_deleg(clp, fh);
+       dp = alloc_init_deleg(clp, fh, odstate);
        if (!dp)
                return ERR_PTR(-ENOMEM);
 
@@ -3903,6 +4007,7 @@ out_unlock:
        spin_unlock(&state_lock);
 out:
        if (status) {
+               put_clnt_odstate(dp->dl_clnt_odstate);
                nfs4_put_stid(&dp->dl_stid);
                return ERR_PTR(status);
        }
@@ -3980,7 +4085,7 @@ nfs4_open_delegation(struct svc_fh *fh, struct nfsd4_open *open,
                default:
                        goto out_no_deleg;
        }
-       dp = nfs4_set_delegation(clp, fh, stp->st_stid.sc_file);
+       dp = nfs4_set_delegation(clp, fh, stp->st_stid.sc_file, stp->st_clnt_odstate);
        if (IS_ERR(dp))
                goto out_no_deleg;
 
@@ -4069,6 +4174,11 @@ nfsd4_process_open2(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nf
                        release_open_stateid(stp);
                        goto out;
                }
+
+               stp->st_clnt_odstate = find_or_hash_clnt_odstate(fp,
+                                                       open->op_odstate);
+               if (stp->st_clnt_odstate == open->op_odstate)
+                       open->op_odstate = NULL;
        }
        update_stateid(&stp->st_stid.sc_stateid);
        memcpy(&open->op_stateid, &stp->st_stid.sc_stateid, sizeof(stateid_t));
@@ -4129,6 +4239,8 @@ void nfsd4_cleanup_open_state(struct nfsd4_compound_state *cstate,
                kmem_cache_free(file_slab, open->op_file);
        if (open->op_stp)
                nfs4_put_stid(&open->op_stp->st_stid);
+       if (open->op_odstate)
+               kmem_cache_free(odstate_slab, open->op_odstate);
 }
 
 __be32
@@ -4385,10 +4497,17 @@ static __be32 check_stateid_generation(stateid_t *in, stateid_t *ref, bool has_s
        return nfserr_old_stateid;
 }
 
+static __be32 nfsd4_check_openowner_confirmed(struct nfs4_ol_stateid *ols)
+{
+       if (ols->st_stateowner->so_is_open_owner &&
+           !(openowner(ols->st_stateowner)->oo_flags & NFS4_OO_CONFIRMED))
+               return nfserr_bad_stateid;
+       return nfs_ok;
+}
+
 static __be32 nfsd4_validate_stateid(struct nfs4_client *cl, stateid_t *stateid)
 {
        struct nfs4_stid *s;
-       struct nfs4_ol_stateid *ols;
        __be32 status = nfserr_bad_stateid;
 
        if (ZERO_STATEID(stateid) || ONE_STATEID(stateid))
@@ -4418,13 +4537,7 @@ static __be32 nfsd4_validate_stateid(struct nfs4_client *cl, stateid_t *stateid)
                break;
        case NFS4_OPEN_STID:
        case NFS4_LOCK_STID:
-               ols = openlockstateid(s);
-               if (ols->st_stateowner->so_is_open_owner
-                               && !(openowner(ols->st_stateowner)->oo_flags
-                                               & NFS4_OO_CONFIRMED))
-                       status = nfserr_bad_stateid;
-               else
-                       status = nfs_ok;
+               status = nfsd4_check_openowner_confirmed(openlockstateid(s));
                break;
        default:
                printk("unknown stateid type %x\n", s->sc_type);
@@ -4516,8 +4629,8 @@ nfs4_preprocess_stateid_op(struct net *net, struct nfsd4_compound_state *cstate,
                status = nfs4_check_fh(current_fh, stp);
                if (status)
                        goto out;
-               if (stp->st_stateowner->so_is_open_owner
-                   && !(openowner(stp->st_stateowner)->oo_flags & NFS4_OO_CONFIRMED))
+               status = nfsd4_check_openowner_confirmed(stp);
+               if (status)
                        goto out;
                status = nfs4_check_openmode(stp, flags);
                if (status)
@@ -4852,9 +4965,6 @@ nfsd4_close(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
        update_stateid(&stp->st_stid.sc_stateid);
        memcpy(&close->cl_stateid, &stp->st_stid.sc_stateid, sizeof(stateid_t));
 
-       nfsd4_return_all_file_layouts(stp->st_stateowner->so_client,
-                                     stp->st_stid.sc_file);
-
        nfsd4_close_open_stateid(stp);
 
        /* put reference from nfs4_preprocess_seqid_op */
@@ -6488,6 +6598,7 @@ nfs4_state_shutdown_net(struct net *net)
        list_for_each_safe(pos, next, &reaplist) {
                dp = list_entry (pos, struct nfs4_delegation, dl_recall_lru);
                list_del_init(&dp->dl_recall_lru);
+               put_clnt_odstate(dp->dl_clnt_odstate);
                nfs4_put_deleg_lease(dp->dl_stid.sc_file);
                nfs4_put_stid(&dp->dl_stid);
        }
index 4f3bfeb1176662ce5c7eb6f59f9440c95c8cf68e..dbc4f85a500825a2c80b21a9a92b52ff1631b8fb 100644 (file)
@@ -63,12 +63,12 @@ typedef struct {
 
 struct nfsd4_callback {
        struct nfs4_client *cb_clp;
-       struct list_head cb_per_client;
        u32 cb_minorversion;
        struct rpc_message cb_msg;
        struct nfsd4_callback_ops *cb_ops;
        struct work_struct cb_work;
-       bool cb_done;
+       int cb_status;
+       bool cb_need_restart;
 };
 
 struct nfsd4_callback_ops {
@@ -126,6 +126,7 @@ struct nfs4_delegation {
        struct list_head        dl_perfile;
        struct list_head        dl_perclnt;
        struct list_head        dl_recall_lru;  /* delegation recalled */
+       struct nfs4_clnt_odstate *dl_clnt_odstate;
        u32                     dl_type;
        time_t                  dl_time;
 /* For recall: */
@@ -332,7 +333,6 @@ struct nfs4_client {
        int                     cl_cb_state;
        struct nfsd4_callback   cl_cb_null;
        struct nfsd4_session    *cl_cb_session;
-       struct list_head        cl_callbacks; /* list of in-progress callbacks */
 
        /* for all client information that callback code might need: */
        spinlock_t              cl_lock;
@@ -464,6 +464,17 @@ static inline struct nfs4_lockowner * lockowner(struct nfs4_stateowner *so)
        return container_of(so, struct nfs4_lockowner, lo_owner);
 }
 
+/*
+ * Per-client state indicating no. of opens and outstanding delegations
+ * on a file from a particular client.'od' stands for 'open & delegation'
+ */
+struct nfs4_clnt_odstate {
+       struct nfs4_client      *co_client;
+       struct nfs4_file        *co_file;
+       struct list_head        co_perfile;
+       atomic_t                co_odcount;
+};
+
 /*
  * nfs4_file: a file opened by some number of (open) nfs4_stateowners.
  *
@@ -485,6 +496,7 @@ struct nfs4_file {
                struct list_head        fi_delegations;
                struct rcu_head         fi_rcu;
        };
+       struct list_head        fi_clnt_odstate;
        /* One each for O_RDONLY, O_WRONLY, O_RDWR: */
        struct file *           fi_fds[3];
        /*
@@ -526,6 +538,7 @@ struct nfs4_ol_stateid {
        struct list_head              st_perstateowner;
        struct list_head              st_locks;
        struct nfs4_stateowner      * st_stateowner;
+       struct nfs4_clnt_odstate    * st_clnt_odstate;
        unsigned char                 st_access_bmap;
        unsigned char                 st_deny_bmap;
        struct nfs4_ol_stateid         * st_openstp;
index f982ae84f0cd2303df5275086a3a05ce519bbd86..2f8c092be2b3344901f07f2f16e0ee239034ccdf 100644 (file)
@@ -247,6 +247,7 @@ struct nfsd4_open {
        struct nfs4_openowner *op_openowner; /* used during processing */
        struct nfs4_file *op_file;          /* used during processing */
        struct nfs4_ol_stateid *op_stp;     /* used during processing */
+       struct nfs4_clnt_odstate *op_odstate; /* used during processing */
        struct nfs4_acl *op_acl;
        struct xdr_netobj op_label;
 };
index 059f37137f9ad7b55b6dc0c3f34fa6c0fea6160b..919fd5bb14a842e94b80ae8d839cac1918bb1cc2 100644 (file)
@@ -388,7 +388,7 @@ static int nilfs_btree_root_broken(const struct nilfs_btree_node *node,
        nchildren = nilfs_btree_node_get_nchildren(node);
 
        if (unlikely(level < NILFS_BTREE_LEVEL_NODE_MIN ||
-                    level > NILFS_BTREE_LEVEL_MAX ||
+                    level >= NILFS_BTREE_LEVEL_MAX ||
                     nchildren < 0 ||
                     nchildren > NILFS_BTREE_ROOT_NCHILDREN_MAX)) {
                pr_crit("NILFS: bad btree root (inode number=%lu): level = %d, flags = 0x%x, nchildren = %d\n",
index a6944b25fd5b5ddba427ac66c8f50fb582cf1451..fdf4b41d0609a00e591afeed69ea7cc2ab9d5254 100644 (file)
@@ -757,6 +757,19 @@ lookup:
        if (tmpres) {
                spin_unlock(&dlm->spinlock);
                spin_lock(&tmpres->spinlock);
+
+               /*
+                * Right after dlm spinlock was released, dlm_thread could have
+                * purged the lockres. Check if lockres got unhashed. If so
+                * start over.
+                */
+               if (hlist_unhashed(&tmpres->hash_node)) {
+                       spin_unlock(&tmpres->spinlock);
+                       dlm_lockres_put(tmpres);
+                       tmpres = NULL;
+                       goto lookup;
+               }
+
                /* Wait on the thread that is mastering the resource */
                if (tmpres->owner == DLM_LOCK_RES_OWNER_UNKNOWN) {
                        __dlm_wait_on_lockres(tmpres);
index 082234581d05b2b2190601f3b8a5f545f7380140..83f4e76511c2bf7804c922f268ba4319a5cfb799 100644 (file)
@@ -159,7 +159,7 @@ int omfs_allocate_range(struct super_block *sb,
        goto out;
 
 found:
-       *return_block = i * bits_per_entry + bit;
+       *return_block = (u64) i * bits_per_entry + bit;
        *return_size = run;
        ret = set_run(sb, i, bits_per_entry, bit, run, 1);
 
index 138321b0c6c2b95a8efcef1a5b3183f3126acbb9..3d935c81789aaab13e33e52fab88b408fbccd6f2 100644 (file)
@@ -306,7 +306,8 @@ static const struct super_operations omfs_sops = {
  */
 static int omfs_get_imap(struct super_block *sb)
 {
-       unsigned int bitmap_size, count, array_size;
+       unsigned int bitmap_size, array_size;
+       int count;
        struct omfs_sb_info *sbi = OMFS_SB(sb);
        struct buffer_head *bh;
        unsigned long **ptr;
@@ -359,7 +360,7 @@ nomem:
 }
 
 enum {
-       Opt_uid, Opt_gid, Opt_umask, Opt_dmask, Opt_fmask
+       Opt_uid, Opt_gid, Opt_umask, Opt_dmask, Opt_fmask, Opt_err
 };
 
 static const match_table_t tokens = {
@@ -368,6 +369,7 @@ static const match_table_t tokens = {
        {Opt_umask, "umask=%o"},
        {Opt_dmask, "dmask=%o"},
        {Opt_fmask, "fmask=%o"},
+       {Opt_err, NULL},
 };
 
 static int parse_options(char *options, struct omfs_sb_info *sbi)
@@ -548,8 +550,10 @@ static int omfs_fill_super(struct super_block *sb, void *data, int silent)
        }
 
        sb->s_root = d_make_root(root);
-       if (!sb->s_root)
+       if (!sb->s_root) {
+               ret = -ENOMEM;
                goto out_brelse_bh2;
+       }
        printk(KERN_DEBUG "omfs: Mounted volume %s\n", omfs_rb->r_name);
 
        ret = 0;
index 24f640441bd90977a079aac782768025c68f3712..84d693d374284b580208fec3b8eb3c57bdd4195c 100644 (file)
@@ -299,6 +299,9 @@ int ovl_copy_up_one(struct dentry *parent, struct dentry *dentry,
        struct cred *override_cred;
        char *link = NULL;
 
+       if (WARN_ON(!workdir))
+               return -EROFS;
+
        ovl_path_upper(parent, &parentpath);
        upperdir = parentpath.dentry;
 
index d139405d2bfad7cfd94c735913ecebf221def5b5..692ceda3bc21f6976b65f3e2d5aa4b7ef2e9c5e8 100644 (file)
@@ -222,6 +222,9 @@ static struct dentry *ovl_clear_empty(struct dentry *dentry,
        struct kstat stat;
        int err;
 
+       if (WARN_ON(!workdir))
+               return ERR_PTR(-EROFS);
+
        err = ovl_lock_rename_workdir(workdir, upperdir);
        if (err)
                goto out;
@@ -322,6 +325,9 @@ static int ovl_create_over_whiteout(struct dentry *dentry, struct inode *inode,
        struct dentry *newdentry;
        int err;
 
+       if (WARN_ON(!workdir))
+               return -EROFS;
+
        err = ovl_lock_rename_workdir(workdir, upperdir);
        if (err)
                goto out;
@@ -506,11 +512,28 @@ static int ovl_remove_and_whiteout(struct dentry *dentry, bool is_dir)
        struct dentry *opaquedir = NULL;
        int err;
 
-       if (is_dir && OVL_TYPE_MERGE_OR_LOWER(ovl_path_type(dentry))) {
-               opaquedir = ovl_check_empty_and_clear(dentry);
-               err = PTR_ERR(opaquedir);
-               if (IS_ERR(opaquedir))
-                       goto out;
+       if (WARN_ON(!workdir))
+               return -EROFS;
+
+       if (is_dir) {
+               if (OVL_TYPE_MERGE_OR_LOWER(ovl_path_type(dentry))) {
+                       opaquedir = ovl_check_empty_and_clear(dentry);
+                       err = PTR_ERR(opaquedir);
+                       if (IS_ERR(opaquedir))
+                               goto out;
+               } else {
+                       LIST_HEAD(list);
+
+                       /*
+                        * When removing an empty opaque directory, then it
+                        * makes no sense to replace it with an exact replica of
+                        * itself.  But emptiness still needs to be checked.
+                        */
+                       err = ovl_check_empty_dir(dentry, &list);
+                       ovl_cache_free(&list);
+                       if (err)
+                               goto out;
+               }
        }
 
        err = ovl_lock_rename_workdir(workdir, upperdir);
index 5f0d1993e6e3952bda9352d231e8fce7dee838e8..bf8537c7f455207830046a50d67d394f86d37f4a 100644 (file)
@@ -529,7 +529,7 @@ static int ovl_remount(struct super_block *sb, int *flags, char *data)
 {
        struct ovl_fs *ufs = sb->s_fs_info;
 
-       if (!(*flags & MS_RDONLY) && !ufs->upper_mnt)
+       if (!(*flags & MS_RDONLY) && (!ufs->upper_mnt || !ufs->workdir))
                return -EROFS;
 
        return 0;
@@ -925,9 +925,10 @@ static int ovl_fill_super(struct super_block *sb, void *data, int silent)
                ufs->workdir = ovl_workdir_create(ufs->upper_mnt, workpath.dentry);
                err = PTR_ERR(ufs->workdir);
                if (IS_ERR(ufs->workdir)) {
-                       pr_err("overlayfs: failed to create directory %s/%s\n",
-                              ufs->config.workdir, OVL_WORKDIR_NAME);
-                       goto out_put_upper_mnt;
+                       pr_warn("overlayfs: failed to create directory %s/%s (errno: %i); mounting read-only\n",
+                               ufs->config.workdir, OVL_WORKDIR_NAME, -err);
+                       sb->s_flags |= MS_RDONLY;
+                       ufs->workdir = NULL;
                }
        }
 
@@ -997,7 +998,6 @@ out_put_lower_mnt:
        kfree(ufs->lower_mnt);
 out_put_workdir:
        dput(ufs->workdir);
-out_put_upper_mnt:
        mntput(ufs->upper_mnt);
 out_put_lowerpath:
        for (i = 0; i < numlower; i++)
index 476024bb6546527887517868b122c9305dc32d07..bfe62ae40f40920e6b95fa8ce16cc3130b8b0972 100644 (file)
@@ -1161,7 +1161,7 @@ ssize_t splice_direct_to_actor(struct file *in, struct splice_desc *sd,
        long ret, bytes;
        umode_t i_mode;
        size_t len;
-       int i, flags;
+       int i, flags, more;
 
        /*
         * We require the input being a regular file, as we don't want to
@@ -1204,6 +1204,7 @@ ssize_t splice_direct_to_actor(struct file *in, struct splice_desc *sd,
         * Don't block on output, we have to drain the direct pipe.
         */
        sd->flags &= ~SPLICE_F_NONBLOCK;
+       more = sd->flags & SPLICE_F_MORE;
 
        while (len) {
                size_t read_len;
@@ -1216,6 +1217,15 @@ ssize_t splice_direct_to_actor(struct file *in, struct splice_desc *sd,
                read_len = ret;
                sd->total_len = read_len;
 
+               /*
+                * If more data is pending, set SPLICE_F_MORE
+                * If this is the last data and SPLICE_F_MORE was not set
+                * initially, clears it.
+                */
+               if (read_len < len)
+                       sd->flags |= SPLICE_F_MORE;
+               else if (!more)
+                       sd->flags &= ~SPLICE_F_MORE;
                /*
                 * NOTE: nonblocking mode only applies to the input. We
                 * must not do the output in nonblocking mode as then we
index 04e79d57bca600b4a21cd0a2a936639d9556e6c8..e9d401ce93bb19d822a2ec9b475dae7ad5d279c1 100644 (file)
@@ -574,8 +574,8 @@ xfs_attr_shortform_add(xfs_da_args_t *args, int forkoff)
  * After the last attribute is removed revert to original inode format,
  * making all literal area available to the data fork once more.
  */
-STATIC void
-xfs_attr_fork_reset(
+void
+xfs_attr_fork_remove(
        struct xfs_inode        *ip,
        struct xfs_trans        *tp)
 {
@@ -641,7 +641,7 @@ xfs_attr_shortform_remove(xfs_da_args_t *args)
            (mp->m_flags & XFS_MOUNT_ATTR2) &&
            (dp->i_d.di_format != XFS_DINODE_FMT_BTREE) &&
            !(args->op_flags & XFS_DA_OP_ADDNAME)) {
-               xfs_attr_fork_reset(dp, args->trans);
+               xfs_attr_fork_remove(dp, args->trans);
        } else {
                xfs_idata_realloc(dp, -size, XFS_ATTR_FORK);
                dp->i_d.di_forkoff = xfs_attr_shortform_bytesfit(dp, totsize);
@@ -905,7 +905,7 @@ xfs_attr3_leaf_to_shortform(
        if (forkoff == -1) {
                ASSERT(dp->i_mount->m_flags & XFS_MOUNT_ATTR2);
                ASSERT(dp->i_d.di_format != XFS_DINODE_FMT_BTREE);
-               xfs_attr_fork_reset(dp, args->trans);
+               xfs_attr_fork_remove(dp, args->trans);
                goto out;
        }
 
index 025c4b820c03a1c642c18d9c53d46e08a0ab2d94..882c8d3388913b3d44aa9105184920feb89709a6 100644 (file)
@@ -53,7 +53,7 @@ int   xfs_attr_shortform_remove(struct xfs_da_args *args);
 int    xfs_attr_shortform_list(struct xfs_attr_list_context *context);
 int    xfs_attr_shortform_allfit(struct xfs_buf *bp, struct xfs_inode *dp);
 int    xfs_attr_shortform_bytesfit(xfs_inode_t *dp, int bytes);
-
+void   xfs_attr_fork_remove(struct xfs_inode *ip, struct xfs_trans *tp);
 
 /*
  * Internal routines when attribute fork size == XFS_LBSIZE(mp).
index aeffeaaac0ec406e543730eb608de1eb3ebc40fb..f1026e86dabc9a00ead716785a3acb5c19ee8e10 100644 (file)
@@ -3224,12 +3224,24 @@ xfs_bmap_extsize_align(
                align_alen += temp;
                align_off -= temp;
        }
+
+       /* Same adjustment for the end of the requested area. */
+       temp = (align_alen % extsz);
+       if (temp)
+               align_alen += extsz - temp;
+
        /*
-        * Same adjustment for the end of the requested area.
+        * For large extent hint sizes, the aligned extent might be larger than
+        * MAXEXTLEN. In that case, reduce the size by an extsz so that it pulls
+        * the length back under MAXEXTLEN. The outer allocation loops handle
+        * short allocation just fine, so it is safe to do this. We only want to
+        * do it when we are forced to, though, because it means more allocation
+        * operations are required.
         */
-       if ((temp = (align_alen % extsz))) {
-               align_alen += extsz - temp;
-       }
+       while (align_alen > MAXEXTLEN)
+               align_alen -= extsz;
+       ASSERT(align_alen <= MAXEXTLEN);
+
        /*
         * If the previous block overlaps with this proposed allocation
         * then move the start forward without adjusting the length.
@@ -3318,7 +3330,9 @@ xfs_bmap_extsize_align(
                        return -EINVAL;
        } else {
                ASSERT(orig_off >= align_off);
-               ASSERT(orig_end <= align_off + align_alen);
+               /* see MAXEXTLEN handling above */
+               ASSERT(orig_end <= align_off + align_alen ||
+                      align_alen + extsz > MAXEXTLEN);
        }
 
 #ifdef DEBUG
@@ -4099,13 +4113,6 @@ xfs_bmapi_reserve_delalloc(
        /* Figure out the extent size, adjust alen */
        extsz = xfs_get_extsz_hint(ip);
        if (extsz) {
-               /*
-                * Make sure we don't exceed a single extent length when we
-                * align the extent by reducing length we are going to
-                * allocate by the maximum amount extent size aligment may
-                * require.
-                */
-               alen = XFS_FILBLKS_MIN(len, MAXEXTLEN - (2 * extsz - 1));
                error = xfs_bmap_extsize_align(mp, got, prev, extsz, rt, eof,
                                               1, 0, &aoff, &alen);
                ASSERT(!error);
index 07349a183a110fdf57bdf9a7f1d704452de5cdb7..1c9e75521250ecf606639578ce79696b6ff4a682 100644 (file)
@@ -376,7 +376,7 @@ xfs_ialloc_ag_alloc(
         */
        newlen = args.mp->m_ialloc_inos;
        if (args.mp->m_maxicount &&
-           percpu_counter_read(&args.mp->m_icount) + newlen >
+           percpu_counter_read_positive(&args.mp->m_icount) + newlen >
                                                        args.mp->m_maxicount)
                return -ENOSPC;
        args.minlen = args.maxlen = args.mp->m_ialloc_blks;
@@ -1339,10 +1339,13 @@ xfs_dialloc(
         * If we have already hit the ceiling of inode blocks then clear
         * okalloc so we scan all available agi structures for a free
         * inode.
+        *
+        * Read rough value of mp->m_icount by percpu_counter_read_positive,
+        * which will sacrifice the preciseness but improve the performance.
         */
        if (mp->m_maxicount &&
-           percpu_counter_read(&mp->m_icount) + mp->m_ialloc_inos >
-                                                       mp->m_maxicount) {
+           percpu_counter_read_positive(&mp->m_icount) + mp->m_ialloc_inos
+                                                       mp->m_maxicount) {
                noroom = 1;
                okalloc = 0;
        }
index f9c1c64782d39ec36fabf800653772f8c5b24280..3fbf167cfb4cddfcb42a57ca7d613096d5c97fe0 100644 (file)
@@ -380,23 +380,31 @@ xfs_attr3_root_inactive(
        return error;
 }
 
+/*
+ * xfs_attr_inactive kills all traces of an attribute fork on an inode. It
+ * removes both the on-disk and in-memory inode fork. Note that this also has to
+ * handle the condition of inodes without attributes but with an attribute fork
+ * configured, so we can't use xfs_inode_hasattr() here.
+ *
+ * The in-memory attribute fork is removed even on error.
+ */
 int
-xfs_attr_inactive(xfs_inode_t *dp)
+xfs_attr_inactive(
+       struct xfs_inode        *dp)
 {
-       xfs_trans_t *trans;
-       xfs_mount_t *mp;
-       int error;
+       struct xfs_trans        *trans;
+       struct xfs_mount        *mp;
+       int                     cancel_flags = 0;
+       int                     lock_mode = XFS_ILOCK_SHARED;
+       int                     error = 0;
 
        mp = dp->i_mount;
        ASSERT(! XFS_NOT_DQATTACHED(mp, dp));
 
-       xfs_ilock(dp, XFS_ILOCK_SHARED);
-       if (!xfs_inode_hasattr(dp) ||
-           dp->i_d.di_aformat == XFS_DINODE_FMT_LOCAL) {
-               xfs_iunlock(dp, XFS_ILOCK_SHARED);
-               return 0;
-       }
-       xfs_iunlock(dp, XFS_ILOCK_SHARED);
+       xfs_ilock(dp, lock_mode);
+       if (!XFS_IFORK_Q(dp))
+               goto out_destroy_fork;
+       xfs_iunlock(dp, lock_mode);
 
        /*
         * Start our first transaction of the day.
@@ -408,13 +416,18 @@ xfs_attr_inactive(xfs_inode_t *dp)
         * the inode in every transaction to let it float upward through
         * the log.
         */
+       lock_mode = 0;
        trans = xfs_trans_alloc(mp, XFS_TRANS_ATTRINVAL);
        error = xfs_trans_reserve(trans, &M_RES(mp)->tr_attrinval, 0, 0);
-       if (error) {
-               xfs_trans_cancel(trans, 0);
-               return error;
-       }
-       xfs_ilock(dp, XFS_ILOCK_EXCL);
+       if (error)
+               goto out_cancel;
+
+       lock_mode = XFS_ILOCK_EXCL;
+       cancel_flags = XFS_TRANS_RELEASE_LOG_RES | XFS_TRANS_ABORT;
+       xfs_ilock(dp, lock_mode);
+
+       if (!XFS_IFORK_Q(dp))
+               goto out_cancel;
 
        /*
         * No need to make quota reservations here. We expect to release some
@@ -422,29 +435,31 @@ xfs_attr_inactive(xfs_inode_t *dp)
         */
        xfs_trans_ijoin(trans, dp, 0);
 
-       /*
-        * Decide on what work routines to call based on the inode size.
-        */
-       if (!xfs_inode_hasattr(dp) ||
-           dp->i_d.di_aformat == XFS_DINODE_FMT_LOCAL) {
-               error = 0;
-               goto out;
+       /* invalidate and truncate the attribute fork extents */
+       if (dp->i_d.di_aformat != XFS_DINODE_FMT_LOCAL) {
+               error = xfs_attr3_root_inactive(&trans, dp);
+               if (error)
+                       goto out_cancel;
+
+               error = xfs_itruncate_extents(&trans, dp, XFS_ATTR_FORK, 0);
+               if (error)
+                       goto out_cancel;
        }
-       error = xfs_attr3_root_inactive(&trans, dp);
-       if (error)
-               goto out;
 
-       error = xfs_itruncate_extents(&trans, dp, XFS_ATTR_FORK, 0);
-       if (error)
-               goto out;
+       /* Reset the attribute fork - this also destroys the in-core fork */
+       xfs_attr_fork_remove(dp, trans);
 
        error = xfs_trans_commit(trans, XFS_TRANS_RELEASE_LOG_RES);
-       xfs_iunlock(dp, XFS_ILOCK_EXCL);
-
+       xfs_iunlock(dp, lock_mode);
        return error;
 
-out:
-       xfs_trans_cancel(trans, XFS_TRANS_RELEASE_LOG_RES|XFS_TRANS_ABORT);
-       xfs_iunlock(dp, XFS_ILOCK_EXCL);
+out_cancel:
+       xfs_trans_cancel(trans, cancel_flags);
+out_destroy_fork:
+       /* kill the in-core attr fork before we drop the inode lock */
+       if (dp->i_afp)
+               xfs_idestroy_fork(dp, XFS_ATTR_FORK);
+       if (lock_mode)
+               xfs_iunlock(dp, lock_mode);
        return error;
 }
index 8121e75352ee9bddd4726ca685d6d3e855256bdd..3b7591224f4a6698d32371a927e70cb2a391f4a9 100644 (file)
@@ -124,7 +124,7 @@ xfs_iozero(
                status = 0;
        } while (count);
 
-       return (-status);
+       return status;
 }
 
 int
index d6ebc85192b7b3f4fd21e3cbc25ccb5f54501319..539a85fddbc26864004e80f5fb229c6c2de565b8 100644 (file)
@@ -1946,21 +1946,17 @@ xfs_inactive(
        /*
         * If there are attributes associated with the file then blow them away
         * now.  The code calls a routine that recursively deconstructs the
-        * attribute fork.  We need to just commit the current transaction
-        * because we can't use it for xfs_attr_inactive().
+        * attribute fork. If also blows away the in-core attribute fork.
         */
-       if (ip->i_d.di_anextents > 0) {
-               ASSERT(ip->i_d.di_forkoff != 0);
-
+       if (XFS_IFORK_Q(ip)) {
                error = xfs_attr_inactive(ip);
                if (error)
                        return;
        }
 
-       if (ip->i_afp)
-               xfs_idestroy_fork(ip, XFS_ATTR_FORK);
-
+       ASSERT(!ip->i_afp);
        ASSERT(ip->i_d.di_anextents == 0);
+       ASSERT(ip->i_d.di_forkoff == 0);
 
        /*
         * Free the inode.
@@ -2883,7 +2879,13 @@ xfs_rename_alloc_whiteout(
        if (error)
                return error;
 
-       /* Satisfy xfs_bumplink that this is a real tmpfile */
+       /*
+        * Prepare the tmpfile inode as if it were created through the VFS.
+        * Otherwise, the link increment paths will complain about nlink 0->1.
+        * Drop the link count as done by d_tmpfile(), complete the inode setup
+        * and flag it as linkable.
+        */
+       drop_nlink(VFS_I(tmpfile));
        xfs_finish_inode_setup(tmpfile);
        VFS_I(tmpfile)->i_state |= I_LINKABLE;
 
@@ -3151,7 +3153,7 @@ xfs_rename(
         * intermediate state on disk.
         */
        if (wip) {
-               ASSERT(wip->i_d.di_nlink == 0);
+               ASSERT(VFS_I(wip)->i_nlink == 0 && wip->i_d.di_nlink == 0);
                error = xfs_bumplink(tp, wip);
                if (error)
                        goto out_trans_abort;
index 2ce7ee3b4ec1fdb9e9344a1ec7ea3a2df5a3b29c..6f23fbdfb365adca1571eadece38b77a619c50ad 100644 (file)
@@ -1084,14 +1084,18 @@ xfs_log_sbcount(xfs_mount_t *mp)
        return xfs_sync_sb(mp, true);
 }
 
+/*
+ * Deltas for the inode count are +/-64, hence we use a large batch size
+ * of 128 so we don't need to take the counter lock on every update.
+ */
+#define XFS_ICOUNT_BATCH       128
 int
 xfs_mod_icount(
        struct xfs_mount        *mp,
        int64_t                 delta)
 {
-       /* deltas are +/-64, hence the large batch size of 128. */
-       __percpu_counter_add(&mp->m_icount, delta, 128);
-       if (percpu_counter_compare(&mp->m_icount, 0) < 0) {
+       __percpu_counter_add(&mp->m_icount, delta, XFS_ICOUNT_BATCH);
+       if (__percpu_counter_compare(&mp->m_icount, 0, XFS_ICOUNT_BATCH) < 0) {
                ASSERT(0);
                percpu_counter_add(&mp->m_icount, -delta);
                return -EINVAL;
@@ -1113,6 +1117,14 @@ xfs_mod_ifree(
        return 0;
 }
 
+/*
+ * Deltas for the block count can vary from 1 to very large, but lock contention
+ * only occurs on frequent small block count updates such as in the delayed
+ * allocation path for buffered writes (page a time updates). Hence we set
+ * a large batch count (1024) to minimise global counter updates except when
+ * we get near to ENOSPC and we have to be very accurate with our updates.
+ */
+#define XFS_FDBLOCKS_BATCH     1024
 int
 xfs_mod_fdblocks(
        struct xfs_mount        *mp,
@@ -1151,25 +1163,19 @@ xfs_mod_fdblocks(
         * Taking blocks away, need to be more accurate the closer we
         * are to zero.
         *
-        * batch size is set to a maximum of 1024 blocks - if we are
-        * allocating of freeing extents larger than this then we aren't
-        * going to be hammering the counter lock so a lock per update
-        * is not a problem.
-        *
         * If the counter has a value of less than 2 * max batch size,
         * then make everything serialise as we are real close to
         * ENOSPC.
         */
-#define __BATCH        1024
-       if (percpu_counter_compare(&mp->m_fdblocks, 2 * __BATCH) < 0)
+       if (__percpu_counter_compare(&mp->m_fdblocks, 2 * XFS_FDBLOCKS_BATCH,
+                                    XFS_FDBLOCKS_BATCH) < 0)
                batch = 1;
        else
-               batch = __BATCH;
-#undef __BATCH
+               batch = XFS_FDBLOCKS_BATCH;
 
        __percpu_counter_add(&mp->m_fdblocks, delta, batch);
-       if (percpu_counter_compare(&mp->m_fdblocks,
-                                  XFS_ALLOC_SET_ASIDE(mp)) >= 0) {
+       if (__percpu_counter_compare(&mp->m_fdblocks, XFS_ALLOC_SET_ASIDE(mp),
+                                    XFS_FDBLOCKS_BATCH) >= 0) {
                /* we had space! */
                return 0;
        }
index f5ca0e989bba417b275c781a0de86b247c1d8619..1c3002e1db20c8f91a31f17e8d6d323ed76ea404 100644 (file)
 
 #ifndef ACPI_USE_SYSTEM_INTTYPES
 
-typedef unsigned char u8;
 typedef unsigned char u8;
 typedef unsigned short u16;
 typedef short s16;
index 2dd405c9be78d474fe4c1c11a70651b6741ab396..45c39a37f9249562761dc9615ffecf12ec194846 100644 (file)
        {0x1002, 0x6658, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_BONAIRE|RADEON_NEW_MEMMAP}, \
        {0x1002, 0x665c, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_BONAIRE|RADEON_NEW_MEMMAP}, \
        {0x1002, 0x665d, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_BONAIRE|RADEON_NEW_MEMMAP}, \
+       {0x1002, 0x665f, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_BONAIRE|RADEON_NEW_MEMMAP}, \
        {0x1002, 0x6660, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_HAINAN|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \
        {0x1002, 0x6663, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_HAINAN|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \
        {0x1002, 0x6664, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_HAINAN|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \
diff --git a/include/dt-bindings/sound/apq8016-lpass.h b/include/dt-bindings/sound/apq8016-lpass.h
new file mode 100644 (file)
index 0000000..499076e
--- /dev/null
@@ -0,0 +1,9 @@
+#ifndef __DT_APQ8016_LPASS_H
+#define __DT_APQ8016_LPASS_H
+
+#define MI2S_PRIMARY   0
+#define MI2S_SECONDARY 1
+#define MI2S_TERTIARY  2
+#define MI2S_QUATERNARY        3
+
+#endif /* __DT_APQ8016_LPASS_H */
diff --git a/include/dt-bindings/sound/audio-jack-events.h b/include/dt-bindings/sound/audio-jack-events.h
new file mode 100644 (file)
index 0000000..378349f
--- /dev/null
@@ -0,0 +1,9 @@
+#ifndef __AUDIO_JACK_EVENTS_H
+#define __AUDIO_JACK_EVENTS_H
+
+#define JACK_HEADPHONE         1
+#define JACK_MICROPHONE                2
+#define JACK_LINEOUT           3
+#define JACK_LINEIN            4
+
+#endif /* __AUDIO_JACK_EVENTS_H */
diff --git a/include/dt-bindings/sound/tas2552.h b/include/dt-bindings/sound/tas2552.h
new file mode 100644 (file)
index 0000000..a4e1a07
--- /dev/null
@@ -0,0 +1,18 @@
+#ifndef __DT_TAS2552_H
+#define __DT_TAS2552_H
+
+#define TAS2552_PLL_CLKIN              (0)
+#define TAS2552_PDM_CLK                        (1)
+#define TAS2552_CLK_TARGET_MASK                (1)
+
+#define TAS2552_PLL_CLKIN_MCLK         ((0 << 1) | TAS2552_PLL_CLKIN)
+#define TAS2552_PLL_CLKIN_BCLK         ((1 << 1) | TAS2552_PLL_CLKIN)
+#define TAS2552_PLL_CLKIN_IVCLKIN      ((2 << 1) | TAS2552_PLL_CLKIN)
+#define TAS2552_PLL_CLKIN_1_8_FIXED    ((3 << 1) | TAS2552_PLL_CLKIN)
+
+#define TAS2552_PDM_CLK_PLL            ((0 << 1) | TAS2552_PDM_CLK)
+#define TAS2552_PDM_CLK_IVCLKIN                ((1 << 1) | TAS2552_PDM_CLK)
+#define TAS2552_PDM_CLK_BCLK           ((2 << 1) | TAS2552_PDM_CLK)
+#define TAS2552_PDM_CLK_MCLK           ((3 << 1) | TAS2552_PDM_CLK)
+
+#endif /* __DT_TAS2552_H */
index aff923ae8c4b963272563759b9ac52ad55778bd0..d87d8eced06407c59c6d231f9e707bdcc398ce52 100644 (file)
@@ -116,7 +116,6 @@ __printf(3, 4)
 int bdi_register(struct backing_dev_info *bdi, struct device *parent,
                const char *fmt, ...);
 int bdi_register_dev(struct backing_dev_info *bdi, dev_t dev);
-void bdi_unregister(struct backing_dev_info *bdi);
 int __must_check bdi_setup_and_register(struct backing_dev_info *, char *);
 void bdi_start_writeback(struct backing_dev_info *bdi, long nr_pages,
                        enum wb_reason reason);
index a1b25e35ea5f9fc2978b7f62917c6b4e39c3dc75..b7299febc4b4adfee00cb8b05d6fbf6558f01547 100644 (file)
@@ -220,7 +220,7 @@ enum rq_flag_bits {
 
 /* This mask is used for both bio and request merge checking */
 #define REQ_NOMERGE_FLAGS \
-       (REQ_NOMERGE | REQ_STARTED | REQ_SOFTBARRIER | REQ_FLUSH | REQ_FUA)
+       (REQ_NOMERGE | REQ_STARTED | REQ_SOFTBARRIER | REQ_FLUSH | REQ_FUA | REQ_FLUSH_SEQ)
 
 #define REQ_RAHEAD             (1ULL << __REQ_RAHEAD)
 #define REQ_THROTTLED          (1ULL << __REQ_THROTTLED)
index 7f9a516f24dec57182f51cff3580db3904208a84..5d93a6645e88676a7d90a1ac55b5d5d6792da667 100644 (file)
@@ -821,8 +821,6 @@ extern int scsi_cmd_ioctl(struct request_queue *, struct gendisk *, fmode_t,
 extern int sg_scsi_ioctl(struct request_queue *, struct gendisk *, fmode_t,
                         struct scsi_ioctl_command __user *);
 
-extern void blk_queue_bio(struct request_queue *q, struct bio *bio);
-
 /*
  * A queue has just exitted congestion.  Note this in the global counter of
  * congested queues, and wake up anyone who was waiting for requests to be
index ae2982c0f7a60ed93339e767feaf1fc89aa02134..656da2a12ffee319f67cb744945f028599e0603c 100644 (file)
@@ -17,7 +17,7 @@
 #define PHY_ID_BCM7250                 0xae025280
 #define PHY_ID_BCM7364                 0xae025260
 #define PHY_ID_BCM7366                 0x600d8490
-#define PHY_ID_BCM7425                 0x03625e60
+#define PHY_ID_BCM7425                 0x600d86b0
 #define PHY_ID_BCM7429                 0x600d8730
 #define PHY_ID_BCM7439                 0x600d8480
 #define PHY_ID_BCM7439_2               0xae025080
index cdf13ca7cac32b61e07dcdbc9f9a79c68dd9ee3e..371e560d13cf1d19abe18e982f27d39d8ab6fc0a 100644 (file)
@@ -9,10 +9,24 @@
                   + __GNUC_MINOR__ * 100 \
                   + __GNUC_PATCHLEVEL__)
 
-
 /* Optimization barrier */
+
 /* The "volatile" is due to gcc bugs */
 #define barrier() __asm__ __volatile__("": : :"memory")
+/*
+ * This version is i.e. to prevent dead stores elimination on @ptr
+ * where gcc and llvm may behave differently when otherwise using
+ * normal barrier(): while gcc behavior gets along with a normal
+ * barrier(), llvm needs an explicit input variable to be assumed
+ * clobbered. The issue is as follows: while the inline asm might
+ * access any memory it wants, the compiler could have fit all of
+ * @ptr into memory registers instead, and since @ptr never escaped
+ * from that, it proofed that the inline asm wasn't touching any of
+ * it. This version works well with both compilers, i.e. we're telling
+ * the compiler that the inline asm absolutely may see the contents
+ * of @ptr. See also: https://llvm.org/bugs/show_bug.cgi?id=15495
+ */
+#define barrier_data(ptr) __asm__ __volatile__("": :"r"(ptr) :"memory")
 
 /*
  * This macro obfuscates arithmetic on a variable address so that gcc
index ba147a1727e6d2fc22c7899fcb5830803c629f41..0c9a2f2c2802fc381d025428543161d39aa148d4 100644 (file)
 /* Intel ECC compiler doesn't support gcc specific asm stmts.
  * It uses intrinsics to do the equivalent things.
  */
+#undef barrier_data
 #undef RELOC_HIDE
 #undef OPTIMIZER_HIDE_VAR
 
+#define barrier_data(ptr) barrier()
+
 #define RELOC_HIDE(ptr, off)                                   \
   ({ unsigned long __ptr;                                      \
      __ptr = (unsigned long) (ptr);                            \
index 0e41ca0e59275deb33b7c7220dffd1ff39cbb2f7..867722591be2c7e026e1b97c241e65e27e3b9d1b 100644 (file)
@@ -169,6 +169,10 @@ void ftrace_likely_update(struct ftrace_branch_data *f, int val, int expect);
 # define barrier() __memory_barrier()
 #endif
 
+#ifndef barrier_data
+# define barrier_data(ptr) barrier()
+#endif
+
 /* Unreachable code */
 #ifndef unreachable
 # define unreachable() do { } while (1)
index 27e285b92b5f748b8ffe9a8e599c8850f0346007..59915ea5373ca798dca185070e11af88cc7745d9 100644 (file)
@@ -151,10 +151,8 @@ static inline unsigned int cpumask_any_but(const struct cpumask *mask,
        return 1;
 }
 
-static inline int cpumask_set_cpu_local_first(int i, int numa_node, cpumask_t *dstp)
+static inline unsigned int cpumask_local_spread(unsigned int i, int node)
 {
-       set_bit(0, cpumask_bits(dstp));
-
        return 0;
 }
 
@@ -208,7 +206,7 @@ static inline unsigned int cpumask_next_zero(int n, const struct cpumask *srcp)
 
 int cpumask_next_and(int n, const struct cpumask *, const struct cpumask *);
 int cpumask_any_but(const struct cpumask *mask, unsigned int cpu);
-int cpumask_set_cpu_local_first(int i, int numa_node, cpumask_t *dstp);
+unsigned int cpumask_local_spread(unsigned int i, int node);
 
 /**
  * for_each_cpu - iterate over every cpu in a mask
index 46e83c2156c667c785fd869a8626e5df44f9c282..f9ecf63d47f1d27e116ff7a6e7959dce0a165837 100644 (file)
@@ -46,7 +46,7 @@ const char *ftrace_print_hex_seq(struct trace_seq *p,
                                 const unsigned char *buf, int len);
 
 const char *ftrace_print_array_seq(struct trace_seq *p,
-                                  const void *buf, int buf_len,
+                                  const void *buf, int count,
                                   size_t el_size);
 
 struct trace_iterator;
index 97a9373e61e80d048ee6259eb4962bd831cac822..15928f0647e44187eb00ae7e128f4047519b093b 100644 (file)
@@ -30,6 +30,7 @@ struct vm_area_struct;
 #define ___GFP_HARDWALL                0x20000u
 #define ___GFP_THISNODE                0x40000u
 #define ___GFP_RECLAIMABLE     0x80000u
+#define ___GFP_NOACCOUNT       0x100000u
 #define ___GFP_NOTRACK         0x200000u
 #define ___GFP_NO_KSWAPD       0x400000u
 #define ___GFP_OTHER_NODE      0x800000u
@@ -87,6 +88,7 @@ struct vm_area_struct;
 #define __GFP_HARDWALL   ((__force gfp_t)___GFP_HARDWALL) /* Enforce hardwall cpuset memory allocs */
 #define __GFP_THISNODE ((__force gfp_t)___GFP_THISNODE)/* No fallback, no policies */
 #define __GFP_RECLAIMABLE ((__force gfp_t)___GFP_RECLAIMABLE) /* Page is reclaimable */
+#define __GFP_NOACCOUNT        ((__force gfp_t)___GFP_NOACCOUNT) /* Don't account to kmemcg */
 #define __GFP_NOTRACK  ((__force gfp_t)___GFP_NOTRACK)  /* Don't track with kmemcheck */
 
 #define __GFP_NO_KSWAPD        ((__force gfp_t)___GFP_NO_KSWAPD)
index 0408421d885f9433c61149e2769bdd3c08192522..0042bf330b99ffa6edd77677529753bdd00b79d4 100644 (file)
@@ -74,7 +74,7 @@ struct sensor_hub_pending {
  * @usage:             Usage id for this hub device instance.
  * @start_collection_index: Starting index for a phy type collection
  * @end_collection_index: Last index for a phy type collection
- * @mutex:             synchronizing mutex.
+ * @mutex_ptr:         synchronizing mutex pointer.
  * @pending:           Holds information of pending sync read request.
  */
 struct hid_sensor_hub_device {
@@ -84,7 +84,7 @@ struct hid_sensor_hub_device {
        u32 usage;
        int start_collection_index;
        int end_collection_index;
-       struct mutex mutex;
+       struct mutex *mutex_ptr;
        struct sensor_hub_pending pending;
 };
 
index 796ef9645827f000cb76ce4cd8637dc6cfa4db7a..a240e61a7700da6ca9d0f751967829b9ba47676d 100644 (file)
@@ -115,13 +115,14 @@ static inline void dmar_writeq(void __iomem *addr, u64 val)
  * Extended Capability Register
  */
 
+#define ecap_pasid(e)          ((e >> 40) & 0x1)
 #define ecap_pss(e)            ((e >> 35) & 0x1f)
 #define ecap_eafs(e)           ((e >> 34) & 0x1)
 #define ecap_nwfs(e)           ((e >> 33) & 0x1)
 #define ecap_srs(e)            ((e >> 31) & 0x1)
 #define ecap_ers(e)            ((e >> 30) & 0x1)
 #define ecap_prs(e)            ((e >> 29) & 0x1)
-#define ecap_pasid(e)          ((e >> 28) & 0x1)
+/* PASID support used to be on bit 28 */
 #define ecap_dis(e)            ((e >> 27) & 0x1)
 #define ecap_nest(e)           ((e >> 26) & 0x1)
 #define ecap_mts(e)            ((e >> 25) & 0x1)
index 36ec4ae746345aaa9b79698546c3568976e0b2c3..9de976b4f9a79c8ef8bb43e7a150a2533e74f39a 100644 (file)
@@ -95,8 +95,6 @@
 
 struct device_node;
 
-extern struct irq_chip gic_arch_extn;
-
 void gic_set_irqchip_flags(unsigned long flags);
 void gic_init_bases(unsigned int, int, void __iomem *, void __iomem *,
                    u32 offset, struct device_node *);
index e60a745ac1982cd0ba11c29bad97d3175c681002..e804306ef5e88d7b02b8b7399b4d525c16b69cd3 100644 (file)
 #error KEXEC_CONTROL_MEMORY_LIMIT not defined
 #endif
 
+#ifndef KEXEC_CONTROL_MEMORY_GFP
+#define KEXEC_CONTROL_MEMORY_GFP GFP_KERNEL
+#endif
+
 #ifndef KEXEC_CONTROL_PAGE_SIZE
 #error KEXEC_CONTROL_PAGE_SIZE not defined
 #endif
index 5fc3d1083071ca24a96a6da038324fafae997667..2b6a204bd8d40cfb74db80e19bec216795366e33 100644 (file)
@@ -166,19 +166,34 @@ static inline bool ktime_before(const ktime_t cmp1, const ktime_t cmp2)
 }
 
 #if BITS_PER_LONG < 64
-extern u64 __ktime_divns(const ktime_t kt, s64 div);
-static inline u64 ktime_divns(const ktime_t kt, s64 div)
+extern s64 __ktime_divns(const ktime_t kt, s64 div);
+static inline s64 ktime_divns(const ktime_t kt, s64 div)
 {
+       /*
+        * Negative divisors could cause an inf loop,
+        * so bug out here.
+        */
+       BUG_ON(div < 0);
        if (__builtin_constant_p(div) && !(div >> 32)) {
-               u64 ns = kt.tv64;
-               do_div(ns, div);
-               return ns;
+               s64 ns = kt.tv64;
+               u64 tmp = ns < 0 ? -ns : ns;
+
+               do_div(tmp, div);
+               return ns < 0 ? -tmp : tmp;
        } else {
                return __ktime_divns(kt, div);
        }
 }
 #else /* BITS_PER_LONG < 64 */
-# define ktime_divns(kt, div)          (u64)((kt).tv64 / (div))
+static inline s64 ktime_divns(const ktime_t kt, s64 div)
+{
+       /*
+        * 32-bit implementation cannot handle negative divisors,
+        * so catch them on 64bit as well.
+        */
+       WARN_ON(div < 0);
+       return kt.tv64 / div;
+}
 #endif
 
 static inline s64 ktime_to_us(const ktime_t kt)
index 8dad4a307bb8c4b086e8f6f62211d91d8c05a53a..28aeae46f355fdfdc96f28dd5a091dacbc85e9b8 100644 (file)
@@ -205,6 +205,7 @@ enum {
        ATA_LFLAG_SW_ACTIVITY   = (1 << 7), /* keep activity stats */
        ATA_LFLAG_NO_LPM        = (1 << 8), /* disable LPM on this link */
        ATA_LFLAG_RST_ONCE      = (1 << 9), /* limit recovery to one reset */
+       ATA_LFLAG_CHANGED       = (1 << 10), /* LPM state changed on this link */
 
        /* struct ata_port flags */
        ATA_FLAG_SLAVE_POSS     = (1 << 0), /* host supports slave dev */
@@ -309,6 +310,12 @@ enum {
         */
        ATA_TMOUT_PMP_SRST_WAIT = 5000,
 
+       /* When the LPM policy is set to ATA_LPM_MAX_POWER, there might
+        * be a spurious PHY event, so ignore the first PHY event that
+        * occurs within 10s after the policy change.
+        */
+       ATA_TMOUT_SPURIOUS_PHY  = 10000,
+
        /* ATA bus states */
        BUS_UNKNOWN             = 0,
        BUS_DMA                 = 1,
@@ -788,6 +795,8 @@ struct ata_link {
        struct ata_eh_context   eh_context;
 
        struct ata_device       device[ATA_MAX_DEVICES];
+
+       unsigned long           last_lpm_change; /* when last LPM change happened */
 };
 #define ATA_LINK_CLEAR_BEGIN           offsetof(struct ata_link, active_tag)
 #define ATA_LINK_CLEAR_END             offsetof(struct ata_link, device[0])
@@ -1201,6 +1210,7 @@ extern struct ata_device *ata_dev_pair(struct ata_device *adev);
 extern int ata_do_set_mode(struct ata_link *link, struct ata_device **r_failed_dev);
 extern void ata_scsi_port_error_handler(struct Scsi_Host *host, struct ata_port *ap);
 extern void ata_scsi_cmd_error_handler(struct Scsi_Host *host, struct ata_port *ap, struct list_head *eh_q);
+extern bool sata_lpm_ignore_phy_events(struct ata_link *link);
 
 extern int ata_cable_40wire(struct ata_port *ap);
 extern int ata_cable_80wire(struct ata_port *ap);
index 72dff5fb0d0ceaf0386d80f1cba83c7bb2c7632f..6c8918114804fda89d00ed3e6b1482539f2dd4ee 100644 (file)
@@ -463,6 +463,8 @@ memcg_kmem_newpage_charge(gfp_t gfp, struct mem_cgroup **memcg, int order)
        if (!memcg_kmem_enabled())
                return true;
 
+       if (gfp & __GFP_NOACCOUNT)
+               return true;
        /*
         * __GFP_NOFAIL allocations will move on even if charging is not
         * possible. Therefore we don't even try, and have this allocation
@@ -522,6 +524,8 @@ memcg_kmem_get_cache(struct kmem_cache *cachep, gfp_t gfp)
 {
        if (!memcg_kmem_enabled())
                return cachep;
+       if (gfp & __GFP_NOACCOUNT)
+               return cachep;
        if (gfp & __GFP_NOFAIL)
                return cachep;
        if (in_interrupt() || (!current->mm) || (current->flags & PF_KTHREAD))
index bcbde799ec690157d47b64a3c7e0728865b54bfa..05b9a694e21312ad26beec7dfa0f32f719cc8c87 100644 (file)
@@ -25,7 +25,6 @@
 #ifndef _LINUX_NETDEVICE_H
 #define _LINUX_NETDEVICE_H
 
-#include <linux/pm_qos.h>
 #include <linux/timer.h>
 #include <linux/bug.h>
 #include <linux/delay.h>
@@ -60,6 +59,7 @@ struct phy_device;
 struct wireless_dev;
 /* 802.15.4 specific */
 struct wpan_dev;
+struct mpls_dev;
 
 void netdev_set_default_ethtool_ops(struct net_device *dev,
                                    const struct ethtool_ops *ops);
@@ -976,7 +976,8 @@ typedef u16 (*select_queue_fallback_t)(struct net_device *dev,
  * int (*ndo_bridge_setlink)(struct net_device *dev, struct nlmsghdr *nlh,
  *                          u16 flags)
  * int (*ndo_bridge_getlink)(struct sk_buff *skb, u32 pid, u32 seq,
- *                          struct net_device *dev, u32 filter_mask)
+ *                          struct net_device *dev, u32 filter_mask,
+ *                          int nlflags)
  * int (*ndo_bridge_dellink)(struct net_device *dev, struct nlmsghdr *nlh,
  *                          u16 flags);
  *
@@ -1172,7 +1173,8 @@ struct net_device_ops {
        int                     (*ndo_bridge_getlink)(struct sk_buff *skb,
                                                      u32 pid, u32 seq,
                                                      struct net_device *dev,
-                                                     u32 filter_mask);
+                                                     u32 filter_mask,
+                                                     int nlflags);
        int                     (*ndo_bridge_dellink)(struct net_device *dev,
                                                      struct nlmsghdr *nlh,
                                                      u16 flags);
@@ -1496,8 +1498,6 @@ enum netdev_priv_flags {
  *
  *     @qdisc_tx_busylock:     XXX: need comments on this one
  *
- *     @pm_qos_req:    Power Management QoS object
- *
  *     FIXME: cleanup struct net_device such that network protocol info
  *     moves out.
  */
@@ -1627,6 +1627,9 @@ struct net_device {
        void                    *ax25_ptr;
        struct wireless_dev     *ieee80211_ptr;
        struct wpan_dev         *ieee802154_ptr;
+#if IS_ENABLED(CONFIG_MPLS_ROUTING)
+       struct mpls_dev __rcu   *mpls_ptr;
+#endif
 
 /*
  * Cache lines mostly used on receive path (including eth_type_trans())
@@ -2021,10 +2024,10 @@ struct pcpu_sw_netstats {
 ({                                                             \
        typeof(type) __percpu *pcpu_stats = alloc_percpu(type); \
        if (pcpu_stats) {                                       \
-               int i;                                          \
-               for_each_possible_cpu(i) {                      \
+               int __cpu;                                      \
+               for_each_possible_cpu(__cpu) {                  \
                        typeof(type) *stat;                     \
-                       stat = per_cpu_ptr(pcpu_stats, i);      \
+                       stat = per_cpu_ptr(pcpu_stats, __cpu);  \
                        u64_stats_init(&stat->syncp);           \
                }                                               \
        }                                                       \
index ab8f76dba6680f485943545407daeb117620b489..f2fdb5a520709551462ca8b95cf9793b2f182af6 100644 (file)
@@ -39,12 +39,24 @@ static inline void br_drop_fake_rtable(struct sk_buff *skb)
 
 static inline int nf_bridge_get_physinif(const struct sk_buff *skb)
 {
-       return skb->nf_bridge ? skb->nf_bridge->physindev->ifindex : 0;
+       struct nf_bridge_info *nf_bridge;
+
+       if (skb->nf_bridge == NULL)
+               return 0;
+
+       nf_bridge = skb->nf_bridge;
+       return nf_bridge->physindev ? nf_bridge->physindev->ifindex : 0;
 }
 
 static inline int nf_bridge_get_physoutif(const struct sk_buff *skb)
 {
-       return skb->nf_bridge ? skb->nf_bridge->physoutdev->ifindex : 0;
+       struct nf_bridge_info *nf_bridge;
+
+       if (skb->nf_bridge == NULL)
+               return 0;
+
+       nf_bridge = skb->nf_bridge;
+       return nf_bridge->physoutdev ? nf_bridge->physoutdev->ifindex : 0;
 }
 
 static inline struct net_device *
index ff3fea3194c6a05e291de61df2cae02cec8d5348..9abb763e4b863e81aedcd34b868a597b3aaf3567 100644 (file)
@@ -460,7 +460,7 @@ struct nilfs_btree_node {
 /* level */
 #define NILFS_BTREE_LEVEL_DATA          0
 #define NILFS_BTREE_LEVEL_NODE_MIN      (NILFS_BTREE_LEVEL_DATA + 1)
-#define NILFS_BTREE_LEVEL_MAX           14
+#define NILFS_BTREE_LEVEL_MAX           14     /* Max level (exclusive) */
 
 /**
  * struct nilfs_palloc_group_desc - block group descriptor
index ddeaae6d2083b256b21b930f3eed8182510e26a8..b871ff9d81d7207333fa021e6a95cb6bdbcf34ac 100644 (file)
@@ -121,6 +121,8 @@ extern struct device_node *of_stdout;
 extern raw_spinlock_t devtree_lock;
 
 #ifdef CONFIG_OF
+void of_core_init(void);
+
 static inline bool is_of_node(struct fwnode_handle *fwnode)
 {
        return fwnode && fwnode->type == FWNODE_OF;
@@ -376,6 +378,10 @@ bool of_console_check(struct device_node *dn, char *name, int index);
 
 #else /* CONFIG_OF */
 
+static inline void of_core_init(void)
+{
+}
+
 static inline bool is_of_node(struct fwnode_handle *fwnode)
 {
        return false;
index 38cff8f6716dd7f6532a6ecb39b750844b346692..2f7b9a40f627ead2e04d4105ad1eaeab76fdf5bf 100644 (file)
 
 #define PCI_VENDOR_ID_INTEL            0x8086
 #define PCI_DEVICE_ID_INTEL_EESSC      0x0008
-#define PCI_DEVICE_ID_INTEL_SNB_IMC    0x0100
-#define PCI_DEVICE_ID_INTEL_IVB_IMC    0x0154
-#define PCI_DEVICE_ID_INTEL_IVB_E3_IMC 0x0150
-#define PCI_DEVICE_ID_INTEL_HSW_IMC    0x0c00
 #define PCI_DEVICE_ID_INTEL_PXHD_0     0x0320
 #define PCI_DEVICE_ID_INTEL_PXHD_1     0x0321
 #define PCI_DEVICE_ID_INTEL_PXH_0      0x0329
index 50e50095c8d172777c4ea2857435444385b81ece..84a1094496100906c1b89714f921451a00babb9f 100644 (file)
@@ -41,7 +41,12 @@ void percpu_counter_destroy(struct percpu_counter *fbc);
 void percpu_counter_set(struct percpu_counter *fbc, s64 amount);
 void __percpu_counter_add(struct percpu_counter *fbc, s64 amount, s32 batch);
 s64 __percpu_counter_sum(struct percpu_counter *fbc);
-int percpu_counter_compare(struct percpu_counter *fbc, s64 rhs);
+int __percpu_counter_compare(struct percpu_counter *fbc, s64 rhs, s32 batch);
+
+static inline int percpu_counter_compare(struct percpu_counter *fbc, s64 rhs)
+{
+       return __percpu_counter_compare(fbc, rhs, percpu_counter_batch);
+}
 
 static inline void percpu_counter_add(struct percpu_counter *fbc, s64 amount)
 {
@@ -116,6 +121,12 @@ static inline int percpu_counter_compare(struct percpu_counter *fbc, s64 rhs)
                return 0;
 }
 
+static inline int
+__percpu_counter_compare(struct percpu_counter *fbc, s64 rhs, s32 batch)
+{
+       return percpu_counter_compare(fbc, rhs);
+}
+
 static inline void
 percpu_counter_add(struct percpu_counter *fbc, s64 amount)
 {
index 61992cf2e9771699ee06595c8fbb1bd39633018a..d8a82a89f35abd762e697f6f1be719a32a868cec 100644 (file)
@@ -92,8 +92,6 @@ struct hw_perf_event_extra {
        int             idx;    /* index in shared_regs->regs[] */
 };
 
-struct event_constraint;
-
 /**
  * struct hw_perf_event - performance event hardware details:
  */
@@ -112,8 +110,6 @@ struct hw_perf_event {
 
                        struct hw_perf_event_extra extra_reg;
                        struct hw_perf_event_extra branch_reg;
-
-                       struct event_constraint *constraint;
                };
                struct { /* software */
                        struct hrtimer  hrtimer;
index a947ab8b441ad968f0953e6ce15d03270325e55b..533d9807e543701099cb77dbbb780513b7d48381 100644 (file)
@@ -5,8 +5,6 @@
 #ifndef __LINUX_PLATFORM_DATA_SI5351_H__
 #define __LINUX_PLATFORM_DATA_SI5351_H__
 
-struct clk;
-
 /**
  * enum si5351_pll_src - Si5351 pll clock source
  * @SI5351_PLL_SRC_DEFAULT: default, do not change eeprom config
@@ -107,8 +105,6 @@ struct si5351_clkout_config {
  * @clkout: array of clkout configuration
  */
 struct si5351_platform_data {
-       struct clk *clk_xtal;
-       struct clk *clk_clkin;
        enum si5351_pll_src pll_src[2];
        struct si5351_clkout_config clkout[8];
 };
index e23d242d1230ff899f37478bcb3a8b92769129d2..843ceca9a21e5f1327fa5c82fa5f3089c5ebab23 100644 (file)
@@ -17,6 +17,7 @@
 #ifndef _LINUX_RHASHTABLE_H
 #define _LINUX_RHASHTABLE_H
 
+#include <linux/atomic.h>
 #include <linux/compiler.h>
 #include <linux/errno.h>
 #include <linux/jhash.h>
@@ -100,6 +101,7 @@ struct rhashtable;
  * @key_len: Length of key
  * @key_offset: Offset of key in struct to be hashed
  * @head_offset: Offset of rhash_head in struct to be hashed
+ * @insecure_max_entries: Maximum number of entries (may be exceeded)
  * @max_size: Maximum size while expanding
  * @min_size: Minimum size while shrinking
  * @nulls_base: Base value to generate nulls marker
@@ -115,6 +117,7 @@ struct rhashtable_params {
        size_t                  key_len;
        size_t                  key_offset;
        size_t                  head_offset;
+       unsigned int            insecure_max_entries;
        unsigned int            max_size;
        unsigned int            min_size;
        u32                     nulls_base;
@@ -282,7 +285,20 @@ static inline bool rht_shrink_below_30(const struct rhashtable *ht,
 static inline bool rht_grow_above_100(const struct rhashtable *ht,
                                      const struct bucket_table *tbl)
 {
-       return atomic_read(&ht->nelems) > tbl->size;
+       return atomic_read(&ht->nelems) > tbl->size &&
+               (!ht->p.max_size || tbl->size < ht->p.max_size);
+}
+
+/**
+ * rht_grow_above_max - returns true if table is above maximum
+ * @ht:                hash table
+ * @tbl:       current table
+ */
+static inline bool rht_grow_above_max(const struct rhashtable *ht,
+                                     const struct bucket_table *tbl)
+{
+       return ht->p.insecure_max_entries &&
+              atomic_read(&ht->nelems) >= ht->p.insecure_max_entries;
 }
 
 /* The bucket lock is selected based on the hash and protects mutations
@@ -588,6 +604,10 @@ restart:
                goto out;
        }
 
+       err = -E2BIG;
+       if (unlikely(rht_grow_above_max(ht, tbl)))
+               goto out;
+
        if (unlikely(rht_grow_above_100(ht, tbl))) {
 slow_path:
                spin_unlock_bh(lock);
index 2da5d1081ad990b57a07715ea0751ae10a80ac54..7b8e260c4a27df00b8eca70d5cd4f52864ba6d87 100644 (file)
@@ -122,5 +122,5 @@ extern int ndo_dflt_fdb_del(struct ndmsg *ndm,
 
 extern int ndo_dflt_bridge_getlink(struct sk_buff *skb, u32 pid, u32 seq,
                                   struct net_device *dev, u16 mode,
-                                  u32 flags, u32 mask);
+                                  u32 flags, u32 mask, int nlflags);
 #endif /* __LINUX_RTNETLINK_H */
index 8222ae40ecb0167d55f3b59027277d2a9e98d80d..26a2e6122734f8237ac44d47fb6bf4e96cca124b 100644 (file)
@@ -175,14 +175,6 @@ extern void get_iowait_load(unsigned long *nr_waiters, unsigned long *load);
 extern void calc_global_load(unsigned long ticks);
 extern void update_cpu_load_nohz(void);
 
-/* Notifier for when a task gets migrated to a new CPU */
-struct task_migration_notifier {
-       struct task_struct *task;
-       int from_cpu;
-       int to_cpu;
-};
-extern void register_task_migration_notifier(struct notifier_block *n);
-
 extern unsigned long get_parent_ip(unsigned long addr);
 
 extern void dump_cpu_task(int cpu);
index 6341f5be6e2474c0a7e30fdd75e3eae5b4286bf3..a30b172df6e1a760905f83c2136ac35f4611320f 100644 (file)
@@ -18,7 +18,7 @@ static inline int rt_task(struct task_struct *p)
 #ifdef CONFIG_RT_MUTEXES
 extern int rt_mutex_getprio(struct task_struct *p);
 extern void rt_mutex_setprio(struct task_struct *p, int prio);
-extern int rt_mutex_check_prio(struct task_struct *task, int newprio);
+extern int rt_mutex_get_effective_prio(struct task_struct *task, int newprio);
 extern struct task_struct *rt_mutex_get_top_task(struct task_struct *task);
 extern void rt_mutex_adjust_pi(struct task_struct *p);
 static inline bool tsk_is_pi_blocked(struct task_struct *tsk)
@@ -31,9 +31,10 @@ static inline int rt_mutex_getprio(struct task_struct *p)
        return p->normal_prio;
 }
 
-static inline int rt_mutex_check_prio(struct task_struct *task, int newprio)
+static inline int rt_mutex_get_effective_prio(struct task_struct *task,
+                                             int newprio)
 {
-       return 0;
+       return newprio;
 }
 
 static inline struct task_struct *rt_mutex_get_top_task(struct task_struct *task)
index 06793b598f44828c5e36804c530aa5fd2400e8e2..f15154a879c711870ba649f867fc6eeb47212f14 100644 (file)
@@ -176,6 +176,7 @@ struct nf_bridge_info {
        struct net_device       *physindev;
        struct net_device       *physoutdev;
        char                    neigh_header[8];
+       __be32                  ipv4_daddr;
 };
 #endif
 
@@ -773,6 +774,7 @@ bool skb_try_coalesce(struct sk_buff *to, struct sk_buff *from,
 
 struct sk_buff *__alloc_skb(unsigned int size, gfp_t priority, int flags,
                            int node);
+struct sk_buff *__build_skb(void *data, unsigned int frag_size);
 struct sk_buff *build_skb(void *data, unsigned int frag_size);
 static inline struct sk_buff *alloc_skb(unsigned int size,
                                        gfp_t priority)
index 0caa3a2d4106eab0137d20ac75518af7964281ba..e8bbf403618f47931e1b32d4ade97b06465fc982 100644 (file)
@@ -145,11 +145,21 @@ struct tcp_sock {
  *     read the code and the spec side by side (and laugh ...)
  *     See RFC793 and RFC1122. The RFC writes these in capitals.
  */
+       u64     bytes_received; /* RFC4898 tcpEStatsAppHCThruOctetsReceived
+                                * sum(delta(rcv_nxt)), or how many bytes
+                                * were acked.
+                                */
        u32     rcv_nxt;        /* What we want to receive next         */
        u32     copied_seq;     /* Head of yet unread data              */
        u32     rcv_wup;        /* rcv_nxt on last window update sent   */
        u32     snd_nxt;        /* Next sequence we send                */
 
+       u64     bytes_acked;    /* RFC4898 tcpEStatsAppHCThruOctetsAcked
+                                * sum(delta(snd_una)), or how many bytes
+                                * were acked.
+                                */
+       struct u64_stats_sync syncp; /* protects 64bit vars (cf tcp_get_info()) */
+
        u32     snd_una;        /* First byte we want an ack for        */
        u32     snd_sml;        /* Last byte of the most recently transmitted small packet */
        u32     rcv_tstamp;     /* timestamp of last received ACK (for keepalives) */
index 358a337af598564f16b03bfa68a696ff85d4513b..d76631f615c224ac29e64198050279aa01e97880 100644 (file)
@@ -339,6 +339,7 @@ struct tty_file_private {
 #define TTY_EXCLUSIVE          3       /* Exclusive open mode */
 #define TTY_DEBUG              4       /* Debugging */
 #define TTY_DO_WRITE_WAKEUP    5       /* Call write_wakeup after queuing new */
+#define TTY_OTHER_DONE         6       /* Closed pty has completed input processing */
 #define TTY_LDISC_OPEN         11      /* Line discipline is open */
 #define TTY_PTY_LOCK           16      /* pty private */
 #define TTY_NO_WRITE_SPLIT     17      /* Preserve write boundaries to driver */
@@ -462,7 +463,6 @@ extern int tty_hung_up_p(struct file *filp);
 extern void do_SAK(struct tty_struct *tty);
 extern void __do_SAK(struct tty_struct *tty);
 extern void no_tty(void);
-extern void tty_flush_to_ldisc(struct tty_struct *tty);
 extern void tty_buffer_free_all(struct tty_port *port);
 extern void tty_buffer_flush(struct tty_struct *tty, struct tty_ldisc *ld);
 extern void tty_buffer_init(struct tty_port *port);
@@ -491,6 +491,7 @@ static inline speed_t tty_get_baud_rate(struct tty_struct *tty)
 
 extern void tty_termios_copy_hw(struct ktermios *new, struct ktermios *old);
 extern int tty_termios_hw_change(struct ktermios *a, struct ktermios *b);
+extern int tty_set_termios(struct tty_struct *tty, struct ktermios *kt);
 
 extern struct tty_ldisc *tty_ldisc_ref(struct tty_struct *);
 extern void tty_ldisc_deref(struct tty_ldisc *);
index 0ee05da3889946c10dd8fabaeb50e59cc20739c3..03835522dfcb68ab830a9d38768c374a99ec131d 100644 (file)
@@ -109,12 +109,12 @@ static inline bool gid_lte(kgid_t left, kgid_t right)
 
 static inline bool uid_valid(kuid_t uid)
 {
-       return !uid_eq(uid, INVALID_UID);
+       return __kuid_val(uid) != (uid_t) -1;
 }
 
 static inline bool gid_valid(kgid_t gid)
 {
-       return !gid_eq(gid, INVALID_GID);
+       return __kgid_val(gid) != (gid_t) -1;
 }
 
 #ifdef CONFIG_USER_NS
index a7f2604c5f25928938f2a55051f31f22ba469a49..7f5f78bd15ad448414fa8c06fb61fa25fb152b5f 100644 (file)
@@ -77,6 +77,8 @@
                /* Cannot handle ATA_12 or ATA_16 CDBs */       \
        US_FLAG(NO_REPORT_OPCODES,      0x04000000)             \
                /* Cannot handle MI_REPORT_SUPPORTED_OPERATION_CODES */ \
+       US_FLAG(MAX_SECTORS_240,        0x08000000)             \
+               /* Sets max_sectors to 240 */                   \
 
 #define US_FLAG(name, value)   US_FL_##name = value ,
 enum { US_DO_ALL_FLAGS };
index d5f4fb69dba3907db6719e5b260ae463065e7e5d..f9b2ce58039bd728f0d9274026e44e3ffdf1a076 100644 (file)
@@ -5,7 +5,7 @@
 ({                                                                     \
        typeof(as) __fc_i, __fc_as = (as) - 1;                          \
        typeof(x) __fc_x = (x);                                         \
-       typeof(*a) *__fc_a = (a);                                       \
+       typeof(*a) const *__fc_a = (a);                                 \
        for (__fc_i = 0; __fc_i < __fc_as; __fc_i++) {                  \
                if (__fc_x op DIV_ROUND_CLOSEST(__fc_a[__fc_i] +        \
                                                __fc_a[__fc_i + 1], 2)) \
index fda6feeb6c1f3fc3ae7c4929935901e31982166b..78ed135e9dea6a9971d15e3b786a64de170b310c 100644 (file)
 #include <net/bond_alb.h>
 #include <net/bond_options.h>
 
-#define DRV_VERSION    "3.7.1"
-#define DRV_RELDATE    "April 27, 2011"
-#define DRV_NAME       "bonding"
-#define DRV_DESCRIPTION        "Ethernet Channel Bonding Driver"
-
-#define bond_version DRV_DESCRIPTION ": v" DRV_VERSION " (" DRV_RELDATE ")\n"
-
 #define BOND_MAX_ARP_TARGETS   16
 
 #define BOND_DEFAULT_MIIMON    100
index eeda67652766a9979478de97105322b5ee6a7977..6ea16c84293b0cdcb981df77481a4fa5e509fdde 100644 (file)
@@ -30,11 +30,13 @@ struct wpan_phy_cca;
 struct cfg802154_ops {
        struct net_device * (*add_virtual_intf_deprecated)(struct wpan_phy *wpan_phy,
                                                           const char *name,
+                                                          unsigned char name_assign_type,
                                                           int type);
        void    (*del_virtual_intf_deprecated)(struct wpan_phy *wpan_phy,
                                               struct net_device *dev);
        int     (*add_virtual_intf)(struct wpan_phy *wpan_phy,
                                    const char *name,
+                                   unsigned char name_assign_type,
                                    enum nl802154_iftype type,
                                    __le64 extended_addr);
        int     (*del_virtual_intf)(struct wpan_phy *wpan_phy,
index aeee28081245c9215f10badd611f58ba0124fcd0..1e18005f7f65f061f6084ea1823a8d37368a57e4 100644 (file)
@@ -120,11 +120,13 @@ static inline u32 codel_time_to_us(codel_time_t val)
  * struct codel_params - contains codel parameters
  * @target:    target queue size (in time units)
  * @interval:  width of moving time window
+ * @mtu:       device mtu, or minimal queue backlog in bytes.
  * @ecn:       is Explicit Congestion Notification enabled
  */
 struct codel_params {
        codel_time_t    target;
        codel_time_t    interval;
+       u32             mtu;
        bool            ecn;
 };
 
@@ -166,10 +168,12 @@ struct codel_stats {
        u32             ecn_mark;
 };
 
-static void codel_params_init(struct codel_params *params)
+static void codel_params_init(struct codel_params *params,
+                             const struct Qdisc *sch)
 {
        params->interval = MS2TIME(100);
        params->target = MS2TIME(5);
+       params->mtu = psched_mtu(qdisc_dev(sch));
        params->ecn = false;
 }
 
@@ -180,7 +184,7 @@ static void codel_vars_init(struct codel_vars *vars)
 
 static void codel_stats_init(struct codel_stats *stats)
 {
-       stats->maxpacket = 256;
+       stats->maxpacket = 0;
 }
 
 /*
@@ -234,7 +238,7 @@ static bool codel_should_drop(const struct sk_buff *skb,
                stats->maxpacket = qdisc_pkt_len(skb);
 
        if (codel_time_before(vars->ldelay, params->target) ||
-           sch->qstats.backlog <= stats->maxpacket) {
+           sch->qstats.backlog <= params->mtu) {
                /* went below - stay below for at least interval */
                vars->first_above_time = 0;
                return false;
index 7b5887cd11723441418daa5ec306d8c8b4d7c1f1..0320bbb7d7b5a1987e7b85f6842cf9fa145d91c5 100644 (file)
@@ -98,7 +98,8 @@ struct inet_connection_sock {
        const struct tcp_congestion_ops *icsk_ca_ops;
        const struct inet_connection_sock_af_ops *icsk_af_ops;
        unsigned int              (*icsk_sync_mss)(struct sock *sk, u32 pmtu);
-       __u8                      icsk_ca_state:7,
+       __u8                      icsk_ca_state:6,
+                                 icsk_ca_setsockopt:1,
                                  icsk_ca_dst_locked:1;
        __u8                      icsk_retransmits;
        __u8                      icsk_pending;
@@ -129,9 +130,10 @@ struct inet_connection_sock {
 
                u32               probe_timestamp;
        } icsk_mtup;
-       u32                       icsk_ca_priv[16];
        u32                       icsk_user_timeout;
-#define ICSK_CA_PRIV_SIZE      (16 * sizeof(u32))
+
+       u64                       icsk_ca_priv[64 / sizeof(u64)];
+#define ICSK_CA_PRIV_SIZE      (8 * sizeof(u64))
 };
 
 #define ICSK_TIME_RETRANS      1       /* Retransmit timer */
@@ -279,12 +281,6 @@ static inline void inet_csk_reqsk_queue_add(struct sock *sk,
 void inet_csk_reqsk_queue_hash_add(struct sock *sk, struct request_sock *req,
                                   unsigned long timeout);
 
-static inline void inet_csk_reqsk_queue_removed(struct sock *sk,
-                                               struct request_sock *req)
-{
-       reqsk_queue_removed(&inet_csk(sk)->icsk_accept_queue, req);
-}
-
 static inline void inet_csk_reqsk_queue_added(struct sock *sk,
                                              const unsigned long timeout)
 {
@@ -306,19 +302,7 @@ static inline int inet_csk_reqsk_queue_is_full(const struct sock *sk)
        return reqsk_queue_is_full(&inet_csk(sk)->icsk_accept_queue);
 }
 
-static inline void inet_csk_reqsk_queue_unlink(struct sock *sk,
-                                              struct request_sock *req)
-{
-       reqsk_queue_unlink(&inet_csk(sk)->icsk_accept_queue, req);
-}
-
-static inline void inet_csk_reqsk_queue_drop(struct sock *sk,
-                                            struct request_sock *req)
-{
-       inet_csk_reqsk_queue_unlink(sk, req);
-       inet_csk_reqsk_queue_removed(sk, req);
-       reqsk_put(req);
-}
+void inet_csk_reqsk_queue_drop(struct sock *sk, struct request_sock *req);
 
 void inet_csk_destroy_sock(struct sock *sk);
 void inet_csk_prepare_forced_close(struct sock *sk);
index b4bef1152c05c52b87dc877e9d4e8b09050842f7..fc57f6b82fc59e4dc6ae72b802856ab80e0af6e9 100644 (file)
@@ -354,7 +354,7 @@ enum ieee80211_rssi_event_data {
 };
 
 /**
- * enum ieee80211_rssi_event - data attached to an %RSSI_EVENT
+ * struct ieee80211_rssi_event - data attached to an %RSSI_EVENT
  * @data: See &enum ieee80211_rssi_event_data
  */
 struct ieee80211_rssi_event {
@@ -388,7 +388,7 @@ enum ieee80211_mlme_event_status {
 };
 
 /**
- * enum ieee80211_mlme_event - data attached to an %MLME_EVENT
+ * struct ieee80211_mlme_event - data attached to an %MLME_EVENT
  * @data: See &enum ieee80211_mlme_event_data
  * @status: See &enum ieee80211_mlme_event_status
  * @reason: the reason code if applicable
@@ -401,9 +401,10 @@ struct ieee80211_mlme_event {
 
 /**
  * struct ieee80211_event - event to be sent to the driver
- * @type The event itself. See &enum ieee80211_event_type.
+ * @type: The event itself. See &enum ieee80211_event_type.
  * @rssi: relevant if &type is %RSSI_EVENT
  * @mlme: relevant if &type is %AUTH_EVENT
+ * @u:    union holding the above two fields
  */
 struct ieee80211_event {
        enum ieee80211_event_type type;
@@ -1666,6 +1667,8 @@ struct ieee80211_tx_control {
  * @sta: station table entry, %NULL for per-vif queue
  * @tid: the TID for this queue (unused for per-vif queue)
  * @ac: the AC for this queue
+ * @drv_priv: data area for driver use, will always be aligned to
+ *     sizeof(void *).
  *
  * The driver can obtain packets from this queue by calling
  * ieee80211_tx_dequeue().
index e18e7fd43f47d996613b0c1e7dfe6bc0e636c476..7df28a4c23f98793626371d1e2334ad91f7ebf87 100644 (file)
@@ -247,19 +247,109 @@ static inline void ieee802154_le64_to_be64(void *be64_dst, const void *le64_src)
        __put_unaligned_memmove64(swab64p(le64_src), be64_dst);
 }
 
-/* Basic interface to register ieee802154 device */
+/**
+ * ieee802154_alloc_hw - Allocate a new hardware device
+ *
+ * This must be called once for each hardware device. The returned pointer
+ * must be used to refer to this device when calling other functions.
+ * mac802154 allocates a private data area for the driver pointed to by
+ * @priv in &struct ieee802154_hw, the size of this area is given as
+ * @priv_data_len.
+ *
+ * @priv_data_len: length of private data
+ * @ops: callbacks for this device
+ *
+ * Return: A pointer to the new hardware device, or %NULL on error.
+ */
 struct ieee802154_hw *
 ieee802154_alloc_hw(size_t priv_data_len, const struct ieee802154_ops *ops);
+
+/**
+ * ieee802154_free_hw - free hardware descriptor
+ *
+ * This function frees everything that was allocated, including the
+ * private data for the driver. You must call ieee802154_unregister_hw()
+ * before calling this function.
+ *
+ * @hw: the hardware to free
+ */
 void ieee802154_free_hw(struct ieee802154_hw *hw);
+
+/**
+ * ieee802154_register_hw - Register hardware device
+ *
+ * You must call this function before any other functions in
+ * mac802154. Note that before a hardware can be registered, you
+ * need to fill the contained wpan_phy's information.
+ *
+ * @hw: the device to register as returned by ieee802154_alloc_hw()
+ *
+ * Return: 0 on success. An error code otherwise.
+ */
 int ieee802154_register_hw(struct ieee802154_hw *hw);
+
+/**
+ * ieee802154_unregister_hw - Unregister a hardware device
+ *
+ * This function instructs mac802154 to free allocated resources
+ * and unregister netdevices from the networking subsystem.
+ *
+ * @hw: the hardware to unregister
+ */
 void ieee802154_unregister_hw(struct ieee802154_hw *hw);
 
+/**
+ * ieee802154_rx - receive frame
+ *
+ * Use this function to hand received frames to mac802154. The receive
+ * buffer in @skb must start with an IEEE 802.15.4 header. In case of a
+ * paged @skb is used, the driver is recommended to put the ieee802154
+ * header of the frame on the linear part of the @skb to avoid memory
+ * allocation and/or memcpy by the stack.
+ *
+ * This function may not be called in IRQ context. Calls to this function
+ * for a single hardware must be synchronized against each other.
+ *
+ * @hw: the hardware this frame came in on
+ * @skb: the buffer to receive, owned by mac802154 after this call
+ */
 void ieee802154_rx(struct ieee802154_hw *hw, struct sk_buff *skb);
+
+/**
+ * ieee802154_rx_irqsafe - receive frame
+ *
+ * Like ieee802154_rx() but can be called in IRQ context
+ * (internally defers to a tasklet.)
+ *
+ * @hw: the hardware this frame came in on
+ * @skb: the buffer to receive, owned by mac802154 after this call
+ * @lqi: link quality indicator
+ */
 void ieee802154_rx_irqsafe(struct ieee802154_hw *hw, struct sk_buff *skb,
                           u8 lqi);
-
+/**
+ * ieee802154_wake_queue - wake ieee802154 queue
+ * @hw: pointer as obtained from ieee802154_alloc_hw().
+ *
+ * Drivers should use this function instead of netif_wake_queue.
+ */
 void ieee802154_wake_queue(struct ieee802154_hw *hw);
+
+/**
+ * ieee802154_stop_queue - stop ieee802154 queue
+ * @hw: pointer as obtained from ieee802154_alloc_hw().
+ *
+ * Drivers should use this function instead of netif_stop_queue.
+ */
 void ieee802154_stop_queue(struct ieee802154_hw *hw);
+
+/**
+ * ieee802154_xmit_complete - frame transmission complete
+ *
+ * @hw: pointer as obtained from ieee802154_alloc_hw().
+ * @skb: buffer for transmission
+ * @ifs_handling: indicate interframe space handling
+ */
 void ieee802154_xmit_complete(struct ieee802154_hw *hw, struct sk_buff *skb,
                              bool ifs_handling);
 
index fe41f3ceb008d767d594de6a042393ba463b509b..9f4265ce88927b0fe1d7418dbeff5f306855ae15 100644 (file)
@@ -212,24 +212,6 @@ static inline int reqsk_queue_empty(struct request_sock_queue *queue)
        return queue->rskq_accept_head == NULL;
 }
 
-static inline void reqsk_queue_unlink(struct request_sock_queue *queue,
-                                     struct request_sock *req)
-{
-       struct listen_sock *lopt = queue->listen_opt;
-       struct request_sock **prev;
-
-       spin_lock(&queue->syn_wait_lock);
-
-       prev = &lopt->syn_table[req->rsk_hash];
-       while (*prev != req)
-               prev = &(*prev)->dl_next;
-       *prev = req->dl_next;
-
-       spin_unlock(&queue->syn_wait_lock);
-       if (del_timer(&req->rsk_timer))
-               reqsk_put(req);
-}
-
 static inline void reqsk_queue_add(struct request_sock_queue *queue,
                                   struct request_sock *req,
                                   struct sock *parent,
index c56a438c3a1eaf89d630edb17dd20802f0e01590..ce13cf20f6253e866f52534b7e7dc10e5bac1a0e 100644 (file)
@@ -574,11 +574,14 @@ static inline void sctp_v6_map_v4(union sctp_addr *addr)
 /* Map v4 address to v4-mapped v6 address */
 static inline void sctp_v4_map_v6(union sctp_addr *addr)
 {
+       __be16 port;
+
+       port = addr->v4.sin_port;
+       addr->v6.sin6_addr.s6_addr32[3] = addr->v4.sin_addr.s_addr;
+       addr->v6.sin6_port = port;
        addr->v6.sin6_family = AF_INET6;
        addr->v6.sin6_flowinfo = 0;
        addr->v6.sin6_scope_id = 0;
-       addr->v6.sin6_port = addr->v4.sin_port;
-       addr->v6.sin6_addr.s6_addr32[3] = addr->v4.sin_addr.s_addr;
        addr->v6.sin6_addr.s6_addr32[0] = 0;
        addr->v6.sin6_addr.s6_addr32[1] = 0;
        addr->v6.sin6_addr.s6_addr32[2] = htonl(0x0000ffff);
index 051dc5c2802d3296f8b49d4b40911c0c22345262..6d204f3f9df8cafb82d856db08769a7d24dfd79e 100644 (file)
@@ -576,7 +576,7 @@ static inline int tcp_bound_to_half_wnd(struct tcp_sock *tp, int pktsize)
 }
 
 /* tcp.c */
-void tcp_get_info(const struct sock *, struct tcp_info *);
+void tcp_get_info(struct sock *, struct tcp_info *);
 
 /* Read 'sendfile()'-style from a TCP socket */
 typedef int (*sk_read_actor_t)(read_descriptor_t *, struct sk_buff *,
@@ -804,6 +804,8 @@ enum tcp_ca_ack_event_flags {
 /* Requires ECN/ECT set on all packets */
 #define TCP_CONG_NEEDS_ECN     0x2
 
+union tcp_cc_info;
+
 struct tcp_congestion_ops {
        struct list_head        list;
        u32 key;
@@ -829,7 +831,8 @@ struct tcp_congestion_ops {
        /* hook for packet ack accounting (optional) */
        void (*pkts_acked)(struct sock *sk, u32 num_acked, s32 rtt_us);
        /* get info for inet_diag (optional) */
-       int (*get_info)(struct sock *sk, u32 ext, struct sk_buff *skb);
+       size_t (*get_info)(struct sock *sk, u32 ext, int *attr,
+                          union tcp_cc_info *info);
 
        char            name[TCP_CA_NAME_MAX];
        struct module   *owner;
index ce55906b54a0eccc316216ce88f5b012a87c537e..ac54c27a2bfd39a2f5ec950afe57963c57b04a42 100644 (file)
@@ -160,7 +160,7 @@ static inline int rdma_ip2gid(struct sockaddr *addr, union ib_gid *gid)
 }
 
 /* Important - sockaddr should be a union of sockaddr_in and sockaddr_in6 */
-static inline int rdma_gid2ip(struct sockaddr *out, union ib_gid *gid)
+static inline void rdma_gid2ip(struct sockaddr *out, union ib_gid *gid)
 {
        if (ipv6_addr_v4mapped((struct in6_addr *)gid)) {
                struct sockaddr_in *out_in = (struct sockaddr_in *)out;
@@ -173,7 +173,6 @@ static inline int rdma_gid2ip(struct sockaddr *out, union ib_gid *gid)
                out_in->sin6_family = AF_INET6;
                memcpy(&out_in->sin6_addr.s6_addr, gid->raw, 16);
        }
-       return 0;
 }
 
 static inline void iboe_addr_get_sgid(struct rdma_dev_addr *dev_addr,
index 0e3ff30647d518483853cb9c52104991df966221..39ed2d2fbd51452216586b031a3e25d236099169 100644 (file)
@@ -105,7 +105,8 @@ enum ib_cm_data_size {
        IB_CM_SIDR_REQ_PRIVATE_DATA_SIZE = 216,
        IB_CM_SIDR_REP_PRIVATE_DATA_SIZE = 136,
        IB_CM_SIDR_REP_INFO_LENGTH       = 72,
-       IB_CM_COMPARE_SIZE               = 64
+       /* compare done u32 at a time */
+       IB_CM_COMPARE_SIZE               = (64 / sizeof(u32))
 };
 
 struct ib_cm_id;
@@ -337,8 +338,8 @@ void ib_destroy_cm_id(struct ib_cm_id *cm_id);
 #define IB_SDP_SERVICE_ID_MASK cpu_to_be64(0xFFFFFFFFFFFF0000ULL)
 
 struct ib_cm_compare_data {
-       u8  data[IB_CM_COMPARE_SIZE];
-       u8  mask[IB_CM_COMPARE_SIZE];
+       u32  data[IB_CM_COMPARE_SIZE];
+       u32  mask[IB_CM_COMPARE_SIZE];
 };
 
 /**
index 928b2775e99244e7df3dae25f218386b84d1ddf3..fda31673a5628831434991f0a087f8417a9589a2 100644 (file)
@@ -147,6 +147,16 @@ int iwpm_add_mapping_cb(struct sk_buff *, struct netlink_callback *);
  */
 int iwpm_add_and_query_mapping_cb(struct sk_buff *, struct netlink_callback *);
 
+/**
+ * iwpm_remote_info_cb - Process remote connecting peer address info, which
+ *                       the port mapper has received from the connecting peer
+ *
+ * @cb: Contains the received message (payload and netlink header)
+ *
+ * Stores the IPv4/IPv6 address info in a hash table
+ */
+int iwpm_remote_info_cb(struct sk_buff *, struct netlink_callback *);
+
 /**
  * iwpm_mapping_error_cb - Process port mapper notification for error
  *
@@ -174,6 +184,21 @@ int iwpm_mapping_info_cb(struct sk_buff *, struct netlink_callback *);
  */
 int iwpm_ack_mapping_info_cb(struct sk_buff *, struct netlink_callback *);
 
+/**
+ * iwpm_get_remote_info - Get the remote connecting peer address info
+ *
+ * @mapped_loc_addr: Mapped local address of the listening peer
+ * @mapped_rem_addr: Mapped remote address of the connecting peer
+ * @remote_addr: To store the remote address of the connecting peer
+ * @nl_client: The index of the netlink client
+ *
+ * The remote address info is retrieved and provided to the client in
+ * the remote_addr. After that it is removed from the hash table
+ */
+int iwpm_get_remote_info(struct sockaddr_storage *mapped_loc_addr,
+                       struct sockaddr_storage *mapped_rem_addr,
+                       struct sockaddr_storage *remote_addr, u8 nl_client);
+
 /**
  * iwpm_create_mapinfo - Store local and mapped IPv4/IPv6 address
  *                       info in a hash table
index 183eaab7c3803dcd081b5a9c30a3b9963767ffe5..96e3f56519e7d9831e4b4c4ce19f78afd436242f 100644 (file)
@@ -36,5 +36,6 @@
                                             for sequential scan */
 #define BLIST_TRY_VPD_PAGES    0x10000000 /* Attempt to read VPD pages */
 #define BLIST_NO_RSOC          0x20000000 /* don't try to issue RSOC */
+#define BLIST_MAX_1024         0x40000000 /* maximum 1024 sector cdb length */
 
 #endif
index 26f406e0f673437498406acbdf84841a87862763..3a8fca9409a7a0c1fad472155854b26f0a122487 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (ST) 2012 Rajeev Kumar (rajeev-dlh.kumar@st.com)
+ * Copyright (ST) 2012 Rajeev Kumar (rajeevkumar.linux@gmail.com)
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
index eb73a3a39ec2fbb9a3b4aef39ff65e21af9d51b4..f86ef5ea9b0147c4f51d6f885d5566ef4c6a023b 100644 (file)
@@ -90,11 +90,6 @@ void snd_dmaengine_pcm_set_config_from_dai_data(
  * makes sense if SND_DMAENGINE_PCM_FLAG_COMPAT is set as well.
  */
 #define SND_DMAENGINE_PCM_FLAG_NO_DT BIT(1)
-/*
- * The platforms dmaengine driver does not support reporting the amount of
- * bytes that are still left to transfer.
- */
-#define SND_DMAENGINE_PCM_FLAG_NO_RESIDUE BIT(2)
 /*
  * The PCM is half duplex and the DMA channel is shared between capture and
  * playback.
index 0de95ccb92cf58ed0536cca855d1255b0276b4fb..5bd134651f5eef50d7c0faee3c66457b66b1307f 100644 (file)
@@ -41,7 +41,8 @@
 
 #define EMUPAGESIZE     4096
 #define MAXREQVOICES    8
-#define MAXPAGES        8192
+#define MAXPAGES0       4096   /* 32 bit mode */
+#define MAXPAGES1       8192   /* 31 bit mode */
 #define RESERVED        0
 #define NUM_MIDI        16
 #define NUM_G           64              /* use all channels */
@@ -50,8 +51,7 @@
 
 /* FIXME? - according to the OSS driver the EMU10K1 needs a 29 bit DMA mask */
 #define EMU10K1_DMA_MASK       0x7fffffffUL    /* 31bit */
-#define AUDIGY_DMA_MASK                0x7fffffffUL    /* 31bit FIXME - 32 should work? */
-                                               /* See ALSA bug #1276 - rlrevell */
+#define AUDIGY_DMA_MASK                0xffffffffUL    /* 32bit mode */
 
 #define TMEMSIZE        256*1024
 #define TMEMSIZEREG     4
 
 #define MAPB                   0x0d            /* Cache map B                                          */
 
-#define MAP_PTE_MASK           0xffffe000      /* The 19 MSBs of the PTE indexed by the PTI            */
-#define MAP_PTI_MASK           0x00001fff      /* The 13 bit index to one of the 8192 PTE dwords       */
+#define MAP_PTE_MASK0          0xfffff000      /* The 20 MSBs of the PTE indexed by the PTI            */
+#define MAP_PTI_MASK0          0x00000fff      /* The 12 bit index to one of the 4096 PTE dwords       */
+
+#define MAP_PTE_MASK1          0xffffe000      /* The 19 MSBs of the PTE indexed by the PTI            */
+#define MAP_PTI_MASK1          0x00001fff      /* The 13 bit index to one of the 8192 PTE dwords       */
 
 /* 0x0e, 0x0f: Not used */
 
@@ -1704,6 +1707,7 @@ struct snd_emu10k1 {
        unsigned short model;                   /* subsystem id */
        unsigned int card_type;                 /* EMU10K1_CARD_* */
        unsigned int ecard_ctrl;                /* ecard control bits */
+       unsigned int address_mode;              /* address mode */
        unsigned long dma_mask;                 /* PCI DMA mask */
        unsigned int delay_pcm_irq;             /* in samples */
        int max_cache_pages;                    /* max memory size / PAGE_SIZE */
index 53a18b3635e24a458700a21566c56a10d0704c56..df705908480aebbf754900731834162fa8097f75 100644 (file)
@@ -9,6 +9,8 @@
 #include <sound/core.h>
 #include <sound/hdaudio.h>
 
+#define AC_AMP_FAKE_MUTE       0x10    /* fake mute bit set to amp verbs */
+
 int snd_hdac_regmap_init(struct hdac_device *codec);
 void snd_hdac_regmap_exit(struct hdac_device *codec);
 int snd_hdac_regmap_add_vendor_verb(struct hdac_device *codec,
index 120d9610054eae7ea880c50c3d259741c405dba0..22734bc3ffd4a2e72ec1a1979ec1adf7df8014c6 100644 (file)
@@ -15,17 +15,11 @@ struct rt5645_platform_data {
        /* IN2 can optionally be differential */
        bool in2_diff;
 
-       bool dmic_en;
        unsigned int dmic1_data_pin;
        /* 0 = IN2N; 1 = GPIO5; 2 = GPIO11 */
        unsigned int dmic2_data_pin;
        /* 0 = IN2P; 1 = GPIO6; 2 = GPIO10; 3 = GPIO12 */
 
-       unsigned int hp_det_gpio;
-       bool gpio_hp_det_active_high;
-
-       /* true if codec's jd function is used */
-       bool en_jd_func;
        unsigned int jd_mode;
 };
 
index 0bc83647d3fa39e05fcd153467eec20aa4c74556..37d95a89827595f8099bd72ebec02891c15bf6d1 100644 (file)
@@ -15,6 +15,8 @@
 
 #include <linux/types.h>
 #include <sound/control.h>
+#include <sound/soc-topology.h>
+#include <sound/asoc.h>
 
 struct device;
 
@@ -107,6 +109,10 @@ struct device;
 {      .id = snd_soc_dapm_mux, .name = wname, \
        SND_SOC_DAPM_INIT_REG_VAL(wreg, wshift, winvert), \
        .kcontrol_news = wcontrols, .num_kcontrols = 1}
+#define SND_SOC_DAPM_DEMUX(wname, wreg, wshift, winvert, wcontrols) \
+{      .id = snd_soc_dapm_demux, .name = wname, \
+       SND_SOC_DAPM_INIT_REG_VAL(wreg, wshift, winvert), \
+       .kcontrol_news = wcontrols, .num_kcontrols = 1}
 
 /* Simplified versions of above macros, assuming wncontrols = ARRAY_SIZE(wcontrols) */
 #define SOC_PGA_ARRAY(wname, wreg, wshift, winvert,\
@@ -287,7 +293,7 @@ struct device;
        .access = SNDRV_CTL_ELEM_ACCESS_TLV_READ | SNDRV_CTL_ELEM_ACCESS_READWRITE,\
        .tlv.p = (tlv_array), \
        .get = snd_soc_dapm_get_volsw, .put = snd_soc_dapm_put_volsw, \
-       .private_value = SOC_SINGLE_VALUE(reg, shift, max, invert, 0) }
+       .private_value = SOC_SINGLE_VALUE(reg, shift, max, invert, 1) }
 #define SOC_DAPM_SINGLE_TLV_VIRT(xname, max, tlv_array) \
        SOC_DAPM_SINGLE(xname, SND_SOC_NOPM, 0, max, 0, tlv_array)
 #define SOC_DAPM_ENUM(xname, xenum) \
@@ -444,11 +450,15 @@ int snd_soc_dapm_dai_get_connected_widgets(struct snd_soc_dai *dai, int stream,
 struct snd_soc_dapm_context *snd_soc_dapm_kcontrol_dapm(
        struct snd_kcontrol *kcontrol);
 
+int snd_soc_dapm_force_bias_level(struct snd_soc_dapm_context *dapm,
+       enum snd_soc_bias_level level);
+
 /* dapm widget types */
 enum snd_soc_dapm_type {
        snd_soc_dapm_input = 0,         /* input pin */
        snd_soc_dapm_output,            /* output pin */
        snd_soc_dapm_mux,                       /* selects 1 analog signal from many inputs */
+       snd_soc_dapm_demux,                     /* connects the input to one of multiple outputs */
        snd_soc_dapm_mixer,                     /* mixes several analog signals together */
        snd_soc_dapm_mixer_named_ctl,           /* mixer with named controls */
        snd_soc_dapm_pga,                       /* programmable gain/attenuation (volume) */
@@ -563,6 +573,7 @@ struct snd_soc_dapm_widget {
        int num_kcontrols;
        const struct snd_kcontrol_new *kcontrol_news;
        struct snd_kcontrol **kcontrols;
+       struct snd_soc_dobj dobj;
 
        /* widget input and outputs */
        struct list_head sources;
@@ -585,6 +596,10 @@ struct snd_soc_dapm_update {
        int val;
 };
 
+struct snd_soc_dapm_wcache {
+       struct snd_soc_dapm_widget *widget;
+};
+
 /* DAPM context */
 struct snd_soc_dapm_context {
        enum snd_soc_bias_level bias_level;
@@ -606,6 +621,9 @@ struct snd_soc_dapm_context {
        int (*set_bias_level)(struct snd_soc_dapm_context *dapm,
                              enum snd_soc_bias_level level);
 
+       struct snd_soc_dapm_wcache path_sink_cache;
+       struct snd_soc_dapm_wcache path_source_cache;
+
 #ifdef CONFIG_DEBUG_FS
        struct dentry *debugfs_dapm;
 #endif
@@ -623,4 +641,35 @@ struct snd_soc_dapm_stats {
        int neighbour_checks;
 };
 
+/**
+ * snd_soc_dapm_init_bias_level() - Initialize DAPM bias level
+ * @dapm: The DAPM context to initialize
+ * @level: The DAPM level to initialize to
+ *
+ * This function only sets the driver internal state of the DAPM level and will
+ * not modify the state of the device. Hence it should not be used during normal
+ * operation, but only to synchronize the internal state to the device state.
+ * E.g. during driver probe to set the DAPM level to the one corresponding with
+ * the power-on reset state of the device.
+ *
+ * To change the DAPM state of the device use snd_soc_dapm_set_bias_level().
+ */
+static inline void snd_soc_dapm_init_bias_level(
+       struct snd_soc_dapm_context *dapm, enum snd_soc_bias_level level)
+{
+       dapm->bias_level = level;
+}
+
+/**
+ * snd_soc_dapm_get_bias_level() - Get current DAPM bias level
+ * @dapm: The context for which to get the bias level
+ *
+ * Returns: The current bias level of the passed DAPM context.
+ */
+static inline enum snd_soc_bias_level snd_soc_dapm_get_bias_level(
+       struct snd_soc_dapm_context *dapm)
+{
+       return dapm->bias_level;
+}
+
 #endif
diff --git a/include/sound/soc-topology.h b/include/sound/soc-topology.h
new file mode 100644 (file)
index 0000000..865a141
--- /dev/null
@@ -0,0 +1,168 @@
+/*
+ * linux/sound/soc-topology.h -- ALSA SoC Firmware Controls and DAPM
+ *
+ * Copyright (C) 2012 Texas Instruments Inc.
+ * Copyright (C) 2015 Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Simple file API to load FW that includes mixers, coefficients, DAPM graphs,
+ * algorithms, equalisers, DAIs, widgets, FE caps, BE caps, codec link caps etc.
+ */
+
+#ifndef __LINUX_SND_SOC_TPLG_H
+#define __LINUX_SND_SOC_TPLG_H
+
+#include <sound/asoc.h>
+#include <linux/list.h>
+
+struct firmware;
+struct snd_kcontrol;
+struct snd_soc_tplg_pcm_be;
+struct snd_ctl_elem_value;
+struct snd_ctl_elem_info;
+struct snd_soc_dapm_widget;
+struct snd_soc_component;
+struct snd_soc_tplg_pcm_fe;
+struct snd_soc_dapm_context;
+struct snd_soc_card;
+
+/* object scan be loaded and unloaded in groups with identfying indexes */
+#define SND_SOC_TPLG_INDEX_ALL 0       /* ID that matches all FW objects */
+
+/* dynamic object type */
+enum snd_soc_dobj_type {
+       SND_SOC_DOBJ_NONE               = 0,    /* object is not dynamic */
+       SND_SOC_DOBJ_MIXER,
+       SND_SOC_DOBJ_ENUM,
+       SND_SOC_DOBJ_BYTES,
+       SND_SOC_DOBJ_PCM,
+       SND_SOC_DOBJ_DAI_LINK,
+       SND_SOC_DOBJ_CODEC_LINK,
+       SND_SOC_DOBJ_WIDGET,
+};
+
+/* dynamic control object */
+struct snd_soc_dobj_control {
+       struct snd_kcontrol *kcontrol;
+       char **dtexts;
+       unsigned long *dvalues;
+};
+
+/* dynamic widget object */
+struct snd_soc_dobj_widget {
+       unsigned int kcontrol_enum:1;   /* this widget is an enum kcontrol */
+};
+
+/* dynamic PCM DAI object */
+struct snd_soc_dobj_pcm_dai {
+       struct snd_soc_tplg_pcm_dai *pd;
+       unsigned int count;
+};
+
+/* generic dynamic object - all dynamic objects belong to this struct */
+struct snd_soc_dobj {
+       enum snd_soc_dobj_type type;
+       unsigned int index;     /* objects can belong in different groups */
+       struct list_head list;
+       struct snd_soc_tplg_ops *ops;
+       union {
+               struct snd_soc_dobj_control control;
+               struct snd_soc_dobj_widget widget;
+               struct snd_soc_dobj_pcm_dai pcm_dai;
+       };
+       void *private; /* core does not touch this */
+};
+
+/*
+ * Kcontrol operations - used to map handlers onto firmware based controls.
+ */
+struct snd_soc_tplg_kcontrol_ops {
+       u32 id;
+       int (*get)(struct snd_kcontrol *kcontrol,
+                       struct snd_ctl_elem_value *ucontrol);
+       int (*put)(struct snd_kcontrol *kcontrol,
+                       struct snd_ctl_elem_value *ucontrol);
+       int (*info)(struct snd_kcontrol *kcontrol,
+               struct snd_ctl_elem_info *uinfo);
+};
+
+/*
+ * DAPM widget event handlers - used to map handlers onto widgets.
+ */
+struct snd_soc_tplg_widget_events {
+       u16 type;
+       int (*event_handler)(struct snd_soc_dapm_widget *w,
+                       struct snd_kcontrol *k, int event);
+};
+
+/*
+ * Public API - Used by component drivers to load and unload dynamic objects
+ * and their resources.
+ */
+struct snd_soc_tplg_ops {
+
+       /* external kcontrol init - used for any driver specific init */
+       int (*control_load)(struct snd_soc_component *,
+               struct snd_kcontrol_new *, struct snd_soc_tplg_ctl_hdr *);
+       int (*control_unload)(struct snd_soc_component *,
+               struct snd_soc_dobj *);
+
+       /* external widget init - used for any driver specific init */
+       int (*widget_load)(struct snd_soc_component *,
+               struct snd_soc_dapm_widget *,
+               struct snd_soc_tplg_dapm_widget *);
+       int (*widget_unload)(struct snd_soc_component *,
+               struct snd_soc_dobj *);
+
+       /* FE - used for any driver specific init */
+       int (*pcm_dai_load)(struct snd_soc_component *,
+               struct snd_soc_tplg_pcm_dai *pcm_dai, int num_fe);
+       int (*pcm_dai_unload)(struct snd_soc_component *,
+               struct snd_soc_dobj *);
+
+       /* callback to handle vendor bespoke data */
+       int (*vendor_load)(struct snd_soc_component *,
+               struct snd_soc_tplg_hdr *);
+       int (*vendor_unload)(struct snd_soc_component *,
+               struct snd_soc_tplg_hdr *);
+
+       /* completion - called at completion of firmware loading */
+       void (*complete)(struct snd_soc_component *);
+
+       /* manifest - optional to inform component of manifest */
+       int (*manifest)(struct snd_soc_component *,
+               struct snd_soc_tplg_manifest *);
+
+       /* bespoke kcontrol handlers available for binding */
+       const struct snd_soc_tplg_kcontrol_ops *io_ops;
+       int io_ops_count;
+};
+
+/* gets a pointer to data from the firmware block header */
+static inline const void *snd_soc_tplg_get_data(struct snd_soc_tplg_hdr *hdr)
+{
+       const void *ptr = hdr;
+
+       return ptr + sizeof(*hdr);
+}
+
+/* Dynamic Object loading and removal for component drivers */
+int snd_soc_tplg_component_load(struct snd_soc_component *comp,
+       struct snd_soc_tplg_ops *ops, const struct firmware *fw,
+       u32 index);
+int snd_soc_tplg_component_remove(struct snd_soc_component *comp, u32 index);
+
+/* Widget removal - widgets also removed wth component API */
+void snd_soc_tplg_widget_remove(struct snd_soc_dapm_widget *w);
+void snd_soc_tplg_widget_remove_all(struct snd_soc_dapm_context *dapm,
+       u32 index);
+
+/* Binds event handlers to dynamic widgets */
+int snd_soc_tplg_widget_bind_event(struct snd_soc_dapm_widget *w,
+       const struct snd_soc_tplg_widget_events *events, int num_events,
+       u16 event_type);
+
+#endif
index fcb312b3f25809e781098e2bd2514ae89f59329f..93df8bf9d54a9e1b9502836faec752b4c6aa20b0 100644 (file)
@@ -27,6 +27,7 @@
 #include <sound/compress_driver.h>
 #include <sound/control.h>
 #include <sound/ac97_codec.h>
+#include <sound/soc-topology.h>
 
 /*
  * Convenience kcontrol builders
 #define SOC_VALUE_ENUM_DOUBLE(xreg, xshift_l, xshift_r, xmask, xitems, xtexts, xvalues) \
 {      .reg = xreg, .shift_l = xshift_l, .shift_r = xshift_r, \
        .mask = xmask, .items = xitems, .texts = xtexts, .values = xvalues}
-#define SOC_VALUE_ENUM_SINGLE(xreg, xshift, xmask, xnitmes, xtexts, xvalues) \
-       SOC_VALUE_ENUM_DOUBLE(xreg, xshift, xshift, xmask, xnitmes, xtexts, xvalues)
+#define SOC_VALUE_ENUM_SINGLE(xreg, xshift, xmask, xitems, xtexts, xvalues) \
+       SOC_VALUE_ENUM_DOUBLE(xreg, xshift, xshift, xmask, xitems, xtexts, xvalues)
+#define SOC_VALUE_ENUM_SINGLE_AUTODISABLE(xreg, xshift, xmask, xitems, xtexts, xvalues) \
+{      .reg = xreg, .shift_l = xshift, .shift_r = xshift, \
+       .mask = xmask, .items = xitems, .texts = xtexts, \
+       .values = xvalues, .autodisable = 1}
 #define SOC_ENUM_SINGLE_VIRT(xitems, xtexts) \
        SOC_ENUM_SINGLE(SND_SOC_NOPM, 0, xitems, xtexts)
 #define SOC_ENUM(xname, xenum) \
                                                        ARRAY_SIZE(xtexts), xtexts, xvalues)
 #define SOC_VALUE_ENUM_SINGLE_DECL(name, xreg, xshift, xmask, xtexts, xvalues) \
        SOC_VALUE_ENUM_DOUBLE_DECL(name, xreg, xshift, xshift, xmask, xtexts, xvalues)
+
+#define SOC_VALUE_ENUM_SINGLE_AUTODISABLE_DECL(name, xreg, xshift, xmask, xtexts, xvalues) \
+       const struct soc_enum name = SOC_VALUE_ENUM_SINGLE_AUTODISABLE(xreg, \
+               xshift, xmask, ARRAY_SIZE(xtexts), xtexts, xvalues)
+
 #define SOC_ENUM_SINGLE_VIRT_DECL(name, xtexts) \
        const struct soc_enum name = SOC_ENUM_SINGLE_VIRT(ARRAY_SIZE(xtexts), xtexts)
 
@@ -387,8 +397,20 @@ int snd_soc_codec_set_pll(struct snd_soc_codec *codec, int pll_id, int source,
 int snd_soc_register_card(struct snd_soc_card *card);
 int snd_soc_unregister_card(struct snd_soc_card *card);
 int devm_snd_soc_register_card(struct device *dev, struct snd_soc_card *card);
+#ifdef CONFIG_PM_SLEEP
 int snd_soc_suspend(struct device *dev);
 int snd_soc_resume(struct device *dev);
+#else
+static inline int snd_soc_suspend(struct device *dev)
+{
+       return 0;
+}
+
+static inline int snd_soc_resume(struct device *dev)
+{
+       return 0;
+}
+#endif
 int snd_soc_poweroff(struct device *dev);
 int snd_soc_register_platform(struct device *dev,
                const struct snd_soc_platform_driver *platform_drv);
@@ -755,6 +777,9 @@ struct snd_soc_component {
 
        struct mutex io_mutex;
 
+       /* attached dynamic objects */
+       struct list_head dobj_list;
+
 #ifdef CONFIG_DEBUG_FS
        struct dentry *debugfs_root;
 #endif
@@ -807,7 +832,7 @@ struct snd_soc_codec {
        /* component */
        struct snd_soc_component component;
 
-       /* dapm */
+       /* Don't access this directly, use snd_soc_codec_get_dapm() */
        struct snd_soc_dapm_context dapm;
 
 #ifdef CONFIG_DEBUG_FS
@@ -949,6 +974,24 @@ struct snd_soc_dai_link {
 
        enum snd_soc_dpcm_trigger trigger[2]; /* trigger type for DPCM */
 
+       /* codec/machine specific init - e.g. add machine controls */
+       int (*init)(struct snd_soc_pcm_runtime *rtd);
+
+       /* optional hw_params re-writing for BE and FE sync */
+       int (*be_hw_params_fixup)(struct snd_soc_pcm_runtime *rtd,
+                       struct snd_pcm_hw_params *params);
+
+       /* machine stream operations */
+       const struct snd_soc_ops *ops;
+       const struct snd_soc_compr_ops *compr_ops;
+
+       /* For unidirectional dai links */
+       bool playback_only;
+       bool capture_only;
+
+       /* Mark this pcm with non atomic ops */
+       bool nonatomic;
+
        /* Keep DAI active over suspend */
        unsigned int ignore_suspend:1;
 
@@ -957,9 +1000,6 @@ struct snd_soc_dai_link {
        unsigned int symmetric_channels:1;
        unsigned int symmetric_samplebits:1;
 
-       /* Mark this pcm with non atomic ops */
-       bool nonatomic;
-
        /* Do not create a PCM for this DAI link (Backend link) */
        unsigned int no_pcm:1;
 
@@ -970,23 +1010,11 @@ struct snd_soc_dai_link {
        unsigned int dpcm_capture:1;
        unsigned int dpcm_playback:1;
 
+       /* DPCM used FE & BE merged format */
+       unsigned int dpcm_merged_format:1;
+
        /* pmdown_time is ignored at stop */
        unsigned int ignore_pmdown_time:1;
-
-       /* codec/machine specific init - e.g. add machine controls */
-       int (*init)(struct snd_soc_pcm_runtime *rtd);
-
-       /* optional hw_params re-writing for BE and FE sync */
-       int (*be_hw_params_fixup)(struct snd_soc_pcm_runtime *rtd,
-                       struct snd_pcm_hw_params *params);
-
-       /* machine stream operations */
-       const struct snd_soc_ops *ops;
-       const struct snd_soc_compr_ops *compr_ops;
-
-       /* For unidirectional dai links */
-       bool playback_only;
-       bool capture_only;
 };
 
 struct snd_soc_codec_conf {
@@ -1099,6 +1127,9 @@ struct snd_soc_card {
        struct list_head dapm_list;
        struct list_head dapm_dirty;
 
+       /* attached dynamic objects */
+       struct list_head dobj_list;
+
        /* Generic DAPM context for the card */
        struct snd_soc_dapm_context dapm;
        struct snd_soc_dapm_stats dapm_stats;
@@ -1158,6 +1189,7 @@ struct soc_mixer_control {
        unsigned int sign_bit;
        unsigned int invert:1;
        unsigned int autodisable:1;
+       struct snd_soc_dobj dobj;
 };
 
 struct soc_bytes {
@@ -1168,6 +1200,8 @@ struct soc_bytes {
 
 struct soc_bytes_ext {
        int max;
+       struct snd_soc_dobj dobj;
+
        /* used for TLV byte control */
        int (*get)(unsigned int __user *bytes, unsigned int size);
        int (*put)(const unsigned int __user *bytes, unsigned int size);
@@ -1188,6 +1222,8 @@ struct soc_enum {
        unsigned int mask;
        const char * const *texts;
        const unsigned int *values;
+       unsigned int autodisable:1;
+       struct snd_soc_dobj dobj;
 };
 
 /**
@@ -1269,6 +1305,58 @@ static inline struct snd_soc_dapm_context *snd_soc_component_get_dapm(
        return component->dapm_ptr;
 }
 
+/**
+ * snd_soc_codec_get_dapm() - Returns the DAPM context for the CODEC
+ * @codec: The CODEC for which to get the DAPM context
+ *
+ * Note: Use this function instead of directly accessing the CODEC's dapm field
+ */
+static inline struct snd_soc_dapm_context *snd_soc_codec_get_dapm(
+       struct snd_soc_codec *codec)
+{
+       return &codec->dapm;
+}
+
+/**
+ * snd_soc_dapm_init_bias_level() - Initialize CODEC DAPM bias level
+ * @dapm: The CODEC for which to initialize the DAPM bias level
+ * @level: The DAPM level to initialize to
+ *
+ * Initializes the CODEC DAPM bias level. See snd_soc_dapm_init_bias_level().
+ */
+static inline void snd_soc_codec_init_bias_level(struct snd_soc_codec *codec,
+       enum snd_soc_bias_level level)
+{
+       snd_soc_dapm_init_bias_level(snd_soc_codec_get_dapm(codec), level);
+}
+
+/**
+ * snd_soc_dapm_get_bias_level() - Get current CODEC DAPM bias level
+ * @codec: The CODEC for which to get the DAPM bias level
+ *
+ * Returns: The current DAPM bias level of the CODEC.
+ */
+static inline enum snd_soc_bias_level snd_soc_codec_get_bias_level(
+       struct snd_soc_codec *codec)
+{
+       return snd_soc_dapm_get_bias_level(snd_soc_codec_get_dapm(codec));
+}
+
+/**
+ * snd_soc_codec_force_bias_level() - Set the CODEC DAPM bias level
+ * @codec: The CODEC for which to set the level
+ * @level: The level to set to
+ *
+ * Forces the CODEC bias level to a specific state. See
+ * snd_soc_dapm_force_bias_level().
+ */
+static inline int snd_soc_codec_force_bias_level(struct snd_soc_codec *codec,
+       enum snd_soc_bias_level level)
+{
+       return snd_soc_dapm_force_bias_level(snd_soc_codec_get_dapm(codec),
+               level);
+}
+
 /**
  * snd_soc_dapm_kcontrol_codec() - Returns the codec associated to a kcontrol
  * @kcontrol: The kcontrol
index 65aca51fe255e487f4a3b36e5708b5159b089c03..e290de4e7e82d3d8779be63e983ec234aef16bfe 100644 (file)
@@ -1,7 +1,7 @@
 /*
 * linux/spear_dma.h
 *
-* Copyright (ST) 2012 Rajeev Kumar (rajeev-dlh.kumar@st.com)
+* Copyright (ST) 2012 Rajeev Kumar (rajeevkumar.linux@gmail.com)
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
index e11e179420a11fb07bce24e48e960bfdba9671a4..df97d1966468f9967e152cf62206a767c7dc140e 100644 (file)
  *                       ~(sizeof(unsigned int) - 1)) ....
  */
 
-#define SNDRV_CTL_TLVT_CONTAINER 0     /* one level down - group of TLVs */
-#define SNDRV_CTL_TLVT_DB_SCALE        1       /* dB scale */
-#define SNDRV_CTL_TLVT_DB_LINEAR 2     /* linear volume */
-#define SNDRV_CTL_TLVT_DB_RANGE 3      /* dB range container */
-#define SNDRV_CTL_TLVT_DB_MINMAX 4     /* dB scale with min/max */
-#define SNDRV_CTL_TLVT_DB_MINMAX_MUTE 5        /* dB scale with min/max with mute */
+#include <uapi/sound/tlv.h>
 
 #define TLV_ITEM(type, ...) \
        (type), TLV_LENGTH(__VA_ARGS__), __VA_ARGS__
 
 #define TLV_DB_GAIN_MUTE       -9999999
 
-/*
- * channel-mapping TLV items
- *  TLV length must match with num_channels
- */
-#define SNDRV_CTL_TLVT_CHMAP_FIXED     0x101   /* fixed channel position */
-#define SNDRV_CTL_TLVT_CHMAP_VAR       0x102   /* channels freely swappable */
-#define SNDRV_CTL_TLVT_CHMAP_PAIRED    0x103   /* pair-wise swappable */
-
 #endif /* __SOUND_TLV_H */
index d61be7297b2c88c867acbacadcacfd65045e6c50..5f122570699339f5f5cf85fb14a90e2ad9fc51b7 100644 (file)
@@ -1,9 +1,7 @@
 #ifndef TARGET_CORE_BACKEND_H
 #define TARGET_CORE_BACKEND_H
 
-#define TRANSPORT_PLUGIN_PHBA_PDEV             1
-#define TRANSPORT_PLUGIN_VHBA_PDEV             2
-#define TRANSPORT_PLUGIN_VHBA_VDEV             3
+#define TRANSPORT_FLAG_PASSTHROUGH             1
 
 struct target_backend_cits {
        struct config_item_type tb_dev_cit;
@@ -22,7 +20,7 @@ struct se_subsystem_api {
        char inquiry_rev[4];
        struct module *owner;
 
-       u8 transport_type;
+       u8 transport_flags;
 
        int (*attach_hba)(struct se_hba *, u32);
        void (*detach_hba)(struct se_hba *);
@@ -138,5 +136,7 @@ int se_dev_set_queue_depth(struct se_device *, u32);
 int    se_dev_set_max_sectors(struct se_device *, u32);
 int    se_dev_set_optimal_sectors(struct se_device *, u32);
 int    se_dev_set_block_size(struct se_device *, u32);
+sense_reason_t passthrough_parse_cdb(struct se_cmd *cmd,
+       sense_reason_t (*exec_cmd)(struct se_cmd *cmd));
 
 #endif /* TARGET_CORE_BACKEND_H */
index 25bb04c4209ed5c42e82bc54d5ba3996194c4bb2..b99c01170392abff3978b6c96d7c1763f06bcc27 100644 (file)
@@ -40,8 +40,6 @@ struct target_fabric_configfs {
        struct config_item      *tf_fabric;
        /* Passed from fabric modules */
        struct config_item_type *tf_fabric_cit;
-       /* Pointer to target core subsystem */
-       struct configfs_subsystem *tf_subsys;
        /* Pointer to fabric's struct module */
        struct module *tf_module;
        struct target_core_fabric_ops tf_ops;
index 17c7f5ac7ea0f5066c6b7f2bae0d66b0021f6358..0f4dc3768587bc2d41370d015c69502757322324 100644 (file)
@@ -4,7 +4,6 @@
 struct target_core_fabric_ops {
        struct module *module;
        const char *name;
-       struct configfs_subsystem *tf_subsys;
        char *(*get_fabric_name)(void);
        u8 (*get_fabric_proto_ident)(struct se_portal_group *);
        char *(*tpg_get_wwn)(struct se_portal_group *);
@@ -109,6 +108,9 @@ struct target_core_fabric_ops {
 int target_register_template(const struct target_core_fabric_ops *fo);
 void target_unregister_template(const struct target_core_fabric_ops *fo);
 
+int target_depend_item(struct config_item *item);
+void target_undepend_item(struct config_item *item);
+
 struct se_session *transport_init_session(enum target_prot_op);
 int transport_alloc_session_tags(struct se_session *, unsigned int,
                unsigned int);
index 81ea598121173bf782c04f7c6bfae63b5207b75e..f7554fd7fc62b92d6b1d73d7db6030599b552014 100644 (file)
@@ -140,19 +140,42 @@ DEFINE_EVENT(kmem_free, kfree,
        TP_ARGS(call_site, ptr)
 );
 
-DEFINE_EVENT(kmem_free, kmem_cache_free,
+DEFINE_EVENT_CONDITION(kmem_free, kmem_cache_free,
 
        TP_PROTO(unsigned long call_site, const void *ptr),
 
-       TP_ARGS(call_site, ptr)
+       TP_ARGS(call_site, ptr),
+
+       /*
+        * This trace can be potentially called from an offlined cpu.
+        * Since trace points use RCU and RCU should not be used from
+        * offline cpus, filter such calls out.
+        * While this trace can be called from a preemptable section,
+        * it has no impact on the condition since tasks can migrate
+        * only from online cpus to other online cpus. Thus its safe
+        * to use raw_smp_processor_id.
+        */
+       TP_CONDITION(cpu_online(raw_smp_processor_id()))
 );
 
-TRACE_EVENT(mm_page_free,
+TRACE_EVENT_CONDITION(mm_page_free,
 
        TP_PROTO(struct page *page, unsigned int order),
 
        TP_ARGS(page, order),
 
+
+       /*
+        * This trace can be potentially called from an offlined cpu.
+        * Since trace points use RCU and RCU should not be used from
+        * offline cpus, filter such calls out.
+        * While this trace can be called from a preemptable section,
+        * it has no impact on the condition since tasks can migrate
+        * only from online cpus to other online cpus. Thus its safe
+        * to use raw_smp_processor_id.
+        */
+       TP_CONDITION(cpu_online(raw_smp_processor_id())),
+
        TP_STRUCT__entry(
                __field(        unsigned long,  pfn             )
                __field(        unsigned int,   order           )
@@ -253,12 +276,35 @@ DEFINE_EVENT(mm_page, mm_page_alloc_zone_locked,
        TP_ARGS(page, order, migratetype)
 );
 
-DEFINE_EVENT_PRINT(mm_page, mm_page_pcpu_drain,
+TRACE_EVENT_CONDITION(mm_page_pcpu_drain,
 
        TP_PROTO(struct page *page, unsigned int order, int migratetype),
 
        TP_ARGS(page, order, migratetype),
 
+       /*
+        * This trace can be potentially called from an offlined cpu.
+        * Since trace points use RCU and RCU should not be used from
+        * offline cpus, filter such calls out.
+        * While this trace can be called from a preemptable section,
+        * it has no impact on the condition since tasks can migrate
+        * only from online cpus to other online cpus. Thus its safe
+        * to use raw_smp_processor_id.
+        */
+       TP_CONDITION(cpu_online(raw_smp_processor_id())),
+
+       TP_STRUCT__entry(
+               __field(        unsigned long,  pfn             )
+               __field(        unsigned int,   order           )
+               __field(        int,            migratetype     )
+       ),
+
+       TP_fast_assign(
+               __entry->pfn            = page ? page_to_pfn(page) : -1UL;
+               __entry->order          = order;
+               __entry->migratetype    = migratetype;
+       ),
+
        TP_printk("page=%p pfn=%lu order=%d migratetype=%d",
                pfn_to_page(__entry->pfn), __entry->pfn,
                __entry->order, __entry->migratetype)
index 880dd74371729939a0179ef3dfd487e1fa017838..c178d13d6f4c0cb51d441c59e7b4975a1913ed3e 100644 (file)
@@ -250,7 +250,6 @@ DEFINE_EVENT(writeback_class, name, \
 DEFINE_WRITEBACK_EVENT(writeback_nowork);
 DEFINE_WRITEBACK_EVENT(writeback_wake_background);
 DEFINE_WRITEBACK_EVENT(writeback_bdi_register);
-DEFINE_WRITEBACK_EVENT(writeback_bdi_unregister);
 
 DECLARE_EVENT_CLASS(wbc_class,
        TP_PROTO(struct writeback_control *wbc, struct backing_dev_info *bdi),
index d65c0a09efd32041e3dd07ff80d0a421f0de6ae8..c7093c75bdd6b70a53c1c35a0950a92ad49722da 100644 (file)
@@ -143,4 +143,8 @@ struct tcp_dctcp_info {
        __u32   dctcp_ab_tot;
 };
 
+union tcp_cc_info {
+       struct tcpvegas_info    vegas;
+       struct tcp_dctcp_info   dctcp;
+};
 #endif /* _UAPI_INET_DIAG_H_ */
index bc9abfe88c9a0e1ba4a80f7f16af038c5cd1f2ac..139d4dd1cab83f1cee0399e9924138a24d350ba7 100644 (file)
@@ -31,4 +31,14 @@ struct mpls_label {
 #define MPLS_LS_TTL_MASK        0x000000FF
 #define MPLS_LS_TTL_SHIFT       0
 
+/* Reserved labels */
+#define MPLS_LABEL_IPV4NULL            0 /* RFC3032 */
+#define MPLS_LABEL_RTALERT             1 /* RFC3032 */
+#define MPLS_LABEL_IPV6NULL            2 /* RFC3032 */
+#define MPLS_LABEL_IMPLNULL            3 /* RFC3032 */
+#define MPLS_LABEL_ENTROPY             7 /* RFC6790 */
+#define MPLS_LABEL_GAL                 13 /* RFC5586 */
+#define MPLS_LABEL_OAMALERT            14 /* RFC3429 */
+#define MPLS_LABEL_EXTENSION           15 /* RFC7274 */
+
 #endif /* _UAPI_MPLS_H */
index 9993a421201c231af01d85ef7c1d355745526565..ef9f80f0f529d156a906b461cc7595c4c83358a6 100644 (file)
@@ -42,6 +42,9 @@ enum tcp_conntrack {
 /* The field td_maxack has been set */
 #define IP_CT_TCP_FLAG_MAXACK_SET              0x20
 
+/* Marks possibility for expected RFC5961 challenge ACK */
+#define IP_CT_EXP_CHALLENGE_ACK                0x40
+
 struct nf_ct_tcp_flags {
        __u8 flags;
        __u8 mask;
index 974db03f7b1a2d9ddf96d0b34a409f8356e94d1a..17fb02f488da88efdcd071258a487ab563251f37 100644 (file)
@@ -337,7 +337,7 @@ struct rtnexthop {
 #define RTNH_F_DEAD            1       /* Nexthop is dead (used by multipath)  */
 #define RTNH_F_PERVASIVE       2       /* Do recursive gateway lookup  */
 #define RTNH_F_ONLINK          4       /* Gateway is forced on link    */
-#define RTNH_F_EXTERNAL                8       /* Route installed externally   */
+#define RTNH_F_OFFLOAD         8       /* offloaded route */
 
 /* Macros to handle hexthops */
 
index 3b9718328d8bf7732a73a13a4811b98ff667f000..faa72f4fa547bcfe643b9cfd32b83b62caf6b973 100644 (file)
@@ -112,6 +112,7 @@ enum {
 #define TCP_FASTOPEN           23      /* Enable FastOpen on listeners */
 #define TCP_TIMESTAMP          24
 #define TCP_NOTSENT_LOWAT      25      /* limit number of unsent bytes in write queue */
+#define TCP_CC_INFO            26      /* Get Congestion Control (optional) info */
 
 struct tcp_repair_opt {
        __u32   opt_code;
@@ -189,6 +190,8 @@ struct tcp_info {
 
        __u64   tcpi_pacing_rate;
        __u64   tcpi_max_pacing_rate;
+       __u64   tcpi_bytes_acked; /* RFC4898 tcpEStatsAppHCThruOctetsAcked */
+       __u64   tcpi_bytes_received; /* RFC4898 tcpEStatsAppHCThruOctetsReceived */
 };
 
 /* for TCP_MD5SIG socket option */
index 984169a819ee4c8f2163c6a5c12d24fbf273caec..d7f1cbc3766c799ac514e4ab2710cb5cbb22a0c0 100644 (file)
@@ -26,6 +26,7 @@
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE. */
 #include <linux/types.h>
+#include <linux/virtio_types.h>
 #include <linux/virtio_ids.h>
 #include <linux/virtio_config.h>
 
index a3318f31e8e7fd05f317c595e8c4ce3bc3595fac..915980ac68dfa8cc1dc973b8a7e659fc56383c22 100644 (file)
@@ -155,7 +155,7 @@ static inline unsigned vring_size(unsigned int num, unsigned long align)
 }
 
 /* The following is used with USED_EVENT_IDX and AVAIL_EVENT_IDX */
-/* Assuming a given event_idx value from the other size, if
+/* Assuming a given event_idx value from the other side, if
  * we have just incremented index from old to new_idx,
  * should we trigger an event? */
 static inline int vring_need_event(__u16 event_idx, __u16 new_idx, __u16 old)
index de69170a30ce525378632523417c881985f6143a..6e4bb4270ca2ea1bb9eab5e49ae7049b6061e12b 100644 (file)
@@ -37,6 +37,7 @@ enum {
        RDMA_NL_IWPM_ADD_MAPPING,
        RDMA_NL_IWPM_QUERY_MAPPING,
        RDMA_NL_IWPM_REMOVE_MAPPING,
+       RDMA_NL_IWPM_REMOTE_INFO,
        RDMA_NL_IWPM_HANDLE_ERR,
        RDMA_NL_IWPM_MAPINFO,
        RDMA_NL_IWPM_MAPINFO_NUM,
diff --git a/include/uapi/sound/asoc.h b/include/uapi/sound/asoc.h
new file mode 100644 (file)
index 0000000..1221520
--- /dev/null
@@ -0,0 +1,388 @@
+/*
+ * uapi/sound/asoc.h -- ALSA SoC Firmware Controls and DAPM
+ *
+ * Copyright (C) 2012 Texas Instruments Inc.
+ * Copyright (C) 2015 Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Simple file API to load FW that includes mixers, coefficients, DAPM graphs,
+ * algorithms, equalisers, DAIs, widgets etc.
+*/
+
+#ifndef __LINUX_UAPI_SND_ASOC_H
+#define __LINUX_UAPI_SND_ASOC_H
+
+#include <linux/types.h>
+#include <sound/asound.h>
+
+/*
+ * Maximum number of channels topology kcontrol can represent.
+ */
+#define SND_SOC_TPLG_MAX_CHAN          8
+
+/*
+ * Maximum number of PCM formats capability
+ */
+#define SND_SOC_TPLG_MAX_FORMATS       16
+
+/*
+ * Maximum number of PCM stream configs
+ */
+#define SND_SOC_TPLG_STREAM_CONFIG_MAX  8
+
+/* individual kcontrol info types - can be mixed with other types */
+#define SND_SOC_TPLG_CTL_VOLSW         1
+#define SND_SOC_TPLG_CTL_VOLSW_SX      2
+#define SND_SOC_TPLG_CTL_VOLSW_XR_SX   3
+#define SND_SOC_TPLG_CTL_ENUM          4
+#define SND_SOC_TPLG_CTL_BYTES         5
+#define SND_SOC_TPLG_CTL_ENUM_VALUE    6
+#define SND_SOC_TPLG_CTL_RANGE         7
+#define SND_SOC_TPLG_CTL_STROBE                8
+
+
+/* individual widget kcontrol info types - can be mixed with other types */
+#define SND_SOC_TPLG_DAPM_CTL_VOLSW            64
+#define SND_SOC_TPLG_DAPM_CTL_ENUM_DOUBLE      65
+#define SND_SOC_TPLG_DAPM_CTL_ENUM_VIRT                66
+#define SND_SOC_TPLG_DAPM_CTL_ENUM_VALUE       67
+#define SND_SOC_TPLG_DAPM_CTL_PIN              68
+
+/* DAPM widget types - add new items to the end */
+#define SND_SOC_TPLG_DAPM_INPUT                0
+#define SND_SOC_TPLG_DAPM_OUTPUT       1
+#define SND_SOC_TPLG_DAPM_MUX          2
+#define SND_SOC_TPLG_DAPM_MIXER                3
+#define SND_SOC_TPLG_DAPM_PGA          4
+#define SND_SOC_TPLG_DAPM_OUT_DRV      5
+#define SND_SOC_TPLG_DAPM_ADC          6
+#define SND_SOC_TPLG_DAPM_DAC          7
+#define SND_SOC_TPLG_DAPM_SWITCH       8
+#define SND_SOC_TPLG_DAPM_PRE          9
+#define SND_SOC_TPLG_DAPM_POST         10
+#define SND_SOC_TPLG_DAPM_AIF_IN       11
+#define SND_SOC_TPLG_DAPM_AIF_OUT      12
+#define SND_SOC_TPLG_DAPM_DAI_IN       13
+#define SND_SOC_TPLG_DAPM_DAI_OUT      14
+#define SND_SOC_TPLG_DAPM_DAI_LINK     15
+#define SND_SOC_TPLG_DAPM_LAST         SND_SOC_TPLG_DAPM_DAI_LINK
+
+/* Header magic number and string sizes */
+#define SND_SOC_TPLG_MAGIC             0x41536F43 /* ASoC */
+
+/* string sizes */
+#define SND_SOC_TPLG_NUM_TEXTS         16
+
+/* ABI version */
+#define SND_SOC_TPLG_ABI_VERSION       0x2
+
+/* Max size of TLV data */
+#define SND_SOC_TPLG_TLV_SIZE          32
+
+/*
+ * File and Block header data types.
+ * Add new generic and vendor types to end of list.
+ * Generic types are handled by the core whilst vendors types are passed
+ * to the component drivers for handling.
+ */
+#define SND_SOC_TPLG_TYPE_MIXER                1
+#define SND_SOC_TPLG_TYPE_BYTES                2
+#define SND_SOC_TPLG_TYPE_ENUM         3
+#define SND_SOC_TPLG_TYPE_DAPM_GRAPH   4
+#define SND_SOC_TPLG_TYPE_DAPM_WIDGET  5
+#define SND_SOC_TPLG_TYPE_DAI_LINK     6
+#define SND_SOC_TPLG_TYPE_PCM          7
+#define SND_SOC_TPLG_TYPE_MANIFEST     8
+#define SND_SOC_TPLG_TYPE_CODEC_LINK   9
+#define SND_SOC_TPLG_TYPE_MAX  SND_SOC_TPLG_TYPE_CODEC_LINK
+
+/* vendor block IDs - please add new vendor types to end */
+#define SND_SOC_TPLG_TYPE_VENDOR_FW    1000
+#define SND_SOC_TPLG_TYPE_VENDOR_CONFIG        1001
+#define SND_SOC_TPLG_TYPE_VENDOR_COEFF 1002
+#define SND_SOC_TPLG_TYPEVENDOR_CODEC  1003
+
+#define SND_SOC_TPLG_STREAM_PLAYBACK   0
+#define SND_SOC_TPLG_STREAM_CAPTURE    1
+
+/*
+ * Block Header.
+ * This header preceeds all object and object arrays below.
+ */
+struct snd_soc_tplg_hdr {
+       __le32 magic;           /* magic number */
+       __le32 abi;             /* ABI version */
+       __le32 version;         /* optional vendor specific version details */
+       __le32 type;            /* SND_SOC_TPLG_TYPE_ */
+       __le32 size;            /* size of this structure */
+       __le32 vendor_type;     /* optional vendor specific type info */
+       __le32 payload_size;    /* data bytes, excluding this header */
+       __le32 index;           /* identifier for block */
+       __le32 count;           /* number of elements in block */
+} __attribute__((packed));
+
+/*
+ * Private data.
+ * All topology objects may have private data that can be used by the driver or
+ * firmware. Core will ignore this data.
+ */
+struct snd_soc_tplg_private {
+       __le32 size;    /* in bytes of private data */
+       char data[0];
+} __attribute__((packed));
+
+/*
+ * Kcontrol TLV data.
+ */
+struct snd_soc_tplg_ctl_tlv {
+       __le32 size;    /* in bytes aligned to 4 */
+       __le32 numid;   /* control element numeric identification */
+       __le32 count;   /* number of elem in data array */
+       __le32 data[SND_SOC_TPLG_TLV_SIZE];
+} __attribute__((packed));
+
+/*
+ * Kcontrol channel data
+ */
+struct snd_soc_tplg_channel {
+       __le32 size;    /* in bytes of this structure */
+       __le32 reg;
+       __le32 shift;
+       __le32 id;      /* ID maps to Left, Right, LFE etc */
+} __attribute__((packed));
+
+/*
+ * Kcontrol Operations IDs
+ */
+struct snd_soc_tplg_kcontrol_ops_id {
+       __le32 get;
+       __le32 put;
+       __le32 info;
+} __attribute__((packed));
+
+/*
+ * kcontrol header
+ */
+struct snd_soc_tplg_ctl_hdr {
+       __le32 size;    /* in bytes of this structure */
+       __le32 type;
+       char name[SNDRV_CTL_ELEM_ID_NAME_MAXLEN];
+       __le32 access;
+       struct snd_soc_tplg_kcontrol_ops_id ops;
+       __le32 tlv_size;        /* non zero means control has TLV data */
+} __attribute__((packed));
+
+/*
+ * Stream Capabilities
+ */
+struct snd_soc_tplg_stream_caps {
+       __le32 size;            /* in bytes of this structure */
+       char name[SNDRV_CTL_ELEM_ID_NAME_MAXLEN];
+       __le64 formats[SND_SOC_TPLG_MAX_FORMATS];       /* supported formats SNDRV_PCM_FMTBIT_* */
+       __le32 rates;           /* supported rates SNDRV_PCM_RATE_* */
+       __le32 rate_min;        /* min rate */
+       __le32 rate_max;        /* max rate */
+       __le32 channels_min;    /* min channels */
+       __le32 channels_max;    /* max channels */
+       __le32 periods_min;     /* min number of periods */
+       __le32 periods_max;     /* max number of periods */
+       __le32 period_size_min; /* min period size bytes */
+       __le32 period_size_max; /* max period size bytes */
+       __le32 buffer_size_min; /* min buffer size bytes */
+       __le32 buffer_size_max; /* max buffer size bytes */
+} __attribute__((packed));
+
+/*
+ * FE or BE Stream configuration supported by SW/FW
+ */
+struct snd_soc_tplg_stream {
+       __le32 size;            /* in bytes of this structure */
+       __le64 format;          /* SNDRV_PCM_FMTBIT_* */
+       __le32 rate;            /* SNDRV_PCM_RATE_* */
+       __le32 period_bytes;    /* size of period in bytes */
+       __le32 buffer_bytes;    /* size of buffer in bytes */
+       __le32 channels;        /* channels */
+       __le32 tdm_slot;        /* optional BE bitmask of supported TDM slots */
+       __le32 dai_fmt;         /* SND_SOC_DAIFMT_  */
+} __attribute__((packed));
+
+/*
+ * Duplex stream configuration supported by SW/FW.
+ */
+struct snd_soc_tplg_stream_config {
+       __le32 size;            /* in bytes of this structure */
+       char name[SNDRV_CTL_ELEM_ID_NAME_MAXLEN];
+       struct snd_soc_tplg_stream playback;
+       struct snd_soc_tplg_stream capture;
+} __attribute__((packed));
+
+/*
+ * Manifest. List totals for each payload type. Not used in parsing, but will
+ * be passed to the component driver before any other objects in order for any
+ * global componnent resource allocations.
+ *
+ * File block representation for manifest :-
+ * +-----------------------------------+----+
+ * | struct snd_soc_tplg_hdr           |  1 |
+ * +-----------------------------------+----+
+ * | struct snd_soc_tplg_manifest      |  1 |
+ * +-----------------------------------+----+
+ */
+struct snd_soc_tplg_manifest {
+       __le32 size;            /* in bytes of this structure */
+       __le32 control_elems;   /* number of control elements */
+       __le32 widget_elems;    /* number of widget elements */
+       __le32 graph_elems;     /* number of graph elements */
+       __le32 dai_elems;       /* number of DAI elements */
+       __le32 dai_link_elems;  /* number of DAI link elements */
+} __attribute__((packed));
+
+/*
+ * Mixer kcontrol.
+ *
+ * File block representation for mixer kcontrol :-
+ * +-----------------------------------+----+
+ * | struct snd_soc_tplg_hdr           |  1 |
+ * +-----------------------------------+----+
+ * | struct snd_soc_tplg_mixer_control |  N |
+ * +-----------------------------------+----+
+ */
+struct snd_soc_tplg_mixer_control {
+       struct snd_soc_tplg_ctl_hdr hdr;
+       __le32 size;    /* in bytes of this structure */
+       __le32 min;
+       __le32 max;
+       __le32 platform_max;
+       __le32 invert;
+       __le32 num_channels;
+       struct snd_soc_tplg_channel channel[SND_SOC_TPLG_MAX_CHAN];
+       struct snd_soc_tplg_ctl_tlv tlv;
+       struct snd_soc_tplg_private priv;
+} __attribute__((packed));
+
+/*
+ * Enumerated kcontrol
+ *
+ * File block representation for enum kcontrol :-
+ * +-----------------------------------+----+
+ * | struct snd_soc_tplg_hdr           |  1 |
+ * +-----------------------------------+----+
+ * | struct snd_soc_tplg_enum_control  |  N |
+ * +-----------------------------------+----+
+ */
+struct snd_soc_tplg_enum_control {
+       struct snd_soc_tplg_ctl_hdr hdr;
+       __le32 size;    /* in bytes of this structure */
+       __le32 num_channels;
+       struct snd_soc_tplg_channel channel[SND_SOC_TPLG_MAX_CHAN];
+       __le32 items;
+       __le32 mask;
+       __le32 count;
+       char texts[SND_SOC_TPLG_NUM_TEXTS][SNDRV_CTL_ELEM_ID_NAME_MAXLEN];
+       __le32 values[SND_SOC_TPLG_NUM_TEXTS * SNDRV_CTL_ELEM_ID_NAME_MAXLEN / 4];
+       struct snd_soc_tplg_private priv;
+} __attribute__((packed));
+
+/*
+ * Bytes kcontrol
+ *
+ * File block representation for bytes kcontrol :-
+ * +-----------------------------------+----+
+ * | struct snd_soc_tplg_hdr           |  1 |
+ * +-----------------------------------+----+
+ * | struct snd_soc_tplg_bytes_control |  N |
+ * +-----------------------------------+----+
+ */
+struct snd_soc_tplg_bytes_control {
+       struct snd_soc_tplg_ctl_hdr hdr;
+       __le32 size;    /* in bytes of this structure */
+       __le32 max;
+       __le32 mask;
+       __le32 base;
+       __le32 num_regs;
+       struct snd_soc_tplg_private priv;
+} __attribute__((packed));
+
+/*
+ * DAPM Graph Element
+ *
+ * File block representation for DAPM graph elements :-
+ * +-------------------------------------+----+
+ * | struct snd_soc_tplg_hdr             |  1 |
+ * +-------------------------------------+----+
+ * | struct snd_soc_tplg_dapm_graph_elem |  N |
+ * +-------------------------------------+----+
+ */
+struct snd_soc_tplg_dapm_graph_elem {
+       char sink[SNDRV_CTL_ELEM_ID_NAME_MAXLEN];
+       char control[SNDRV_CTL_ELEM_ID_NAME_MAXLEN];
+       char source[SNDRV_CTL_ELEM_ID_NAME_MAXLEN];
+} __attribute__((packed));
+
+/*
+ * DAPM Widget.
+ *
+ * File block representation for DAPM widget :-
+ * +-------------------------------------+-----+
+ * | struct snd_soc_tplg_hdr             |  1  |
+ * +-------------------------------------+-----+
+ * | struct snd_soc_tplg_dapm_widget     |  N  |
+ * +-------------------------------------+-----+
+ * |   struct snd_soc_tplg_enum_control  | 0|1 |
+ * |   struct snd_soc_tplg_mixer_control | 0|N |
+ * +-------------------------------------+-----+
+ *
+ * Optional enum or mixer control can be appended to the end of each widget
+ * in the block.
+ */
+struct snd_soc_tplg_dapm_widget {
+       __le32 size;            /* in bytes of this structure */
+       __le32 id;              /* SND_SOC_DAPM_CTL */
+       char name[SNDRV_CTL_ELEM_ID_NAME_MAXLEN];
+       char sname[SNDRV_CTL_ELEM_ID_NAME_MAXLEN];
+
+       __le32 reg;             /* negative reg = no direct dapm */
+       __le32 shift;           /* bits to shift */
+       __le32 mask;            /* non-shifted mask */
+       __u32 invert;           /* invert the power bit */
+       __u32 ignore_suspend;   /* kept enabled over suspend */
+       __u16 event_flags;
+       __u16 event_type;
+       __u16 num_kcontrols;
+       struct snd_soc_tplg_private priv;
+       /*
+        * kcontrols that relate to this widget
+        * follow here after widget private data
+        */
+} __attribute__((packed));
+
+struct snd_soc_tplg_pcm_cfg_caps {
+       struct snd_soc_tplg_stream_caps caps;
+       struct snd_soc_tplg_stream_config configs[SND_SOC_TPLG_STREAM_CONFIG_MAX];
+       __le32 num_configs;     /* number of configs */
+} __attribute__((packed));
+
+/*
+ * Describes SW/FW specific features of PCM or DAI link.
+ *
+ * File block representation for PCM/DAI-Link :-
+ * +-----------------------------------+-----+
+ * | struct snd_soc_tplg_hdr           |  1  |
+ * +-----------------------------------+-----+
+ * | struct snd_soc_tplg_dapm_pcm_dai  |  N  |
+ * +-----------------------------------+-----+
+ */
+struct snd_soc_tplg_pcm_dai {
+       __le32 size;            /* in bytes of this structure */
+       char name[SNDRV_CTL_ELEM_ID_NAME_MAXLEN];
+       __le32 id;                      /* unique ID - used to match */
+       __le32 playback;                /* supports playback mode */
+       __le32 capture;                 /* supports capture mode */
+       __le32 compress;                /* 1 = compressed; 0 = PCM */
+       struct snd_soc_tplg_pcm_cfg_caps capconf[2];    /* capabilities and configs */
+} __attribute__((packed));
+
+#endif
diff --git a/include/uapi/sound/tlv.h b/include/uapi/sound/tlv.h
new file mode 100644 (file)
index 0000000..ffc4f20
--- /dev/null
@@ -0,0 +1,31 @@
+/*
+ *   This program is free software; you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation; either version 2 of the License, or
+ *   (at your option) any later version.
+ *
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *   GNU General Public License for more details.
+ */
+
+#ifndef __UAPI_SOUND_TLV_H
+#define __UAPI_SOUND_TLV_H
+
+#define SNDRV_CTL_TLVT_CONTAINER 0     /* one level down - group of TLVs */
+#define SNDRV_CTL_TLVT_DB_SCALE        1       /* dB scale */
+#define SNDRV_CTL_TLVT_DB_LINEAR 2     /* linear volume */
+#define SNDRV_CTL_TLVT_DB_RANGE 3      /* dB range container */
+#define SNDRV_CTL_TLVT_DB_MINMAX 4     /* dB scale with min/max */
+#define SNDRV_CTL_TLVT_DB_MINMAX_MUTE 5        /* dB scale with min/max with mute */
+
+/*
+ * channel-mapping TLV items
+ *  TLV length must match with num_channels
+ */
+#define SNDRV_CTL_TLVT_CHMAP_FIXED     0x101   /* fixed channel position */
+#define SNDRV_CTL_TLVT_CHMAP_VAR       0x102   /* channels freely swappable */
+#define SNDRV_CTL_TLVT_CHMAP_PAIRED    0x103   /* pair-wise swappable */
+
+#endif
index 5321cd9636e6a48e0e4ad0e68fe159e2d015e7c8..7d95fdf9cf3e773f3d800194ca43a2f0a7acdd7a 100644 (file)
@@ -17,7 +17,7 @@ int bind_evtchn_to_irqhandler(unsigned int evtchn,
                              irq_handler_t handler,
                              unsigned long irqflags, const char *devname,
                              void *dev_id);
-int bind_virq_to_irq(unsigned int virq, unsigned int cpu);
+int bind_virq_to_irq(unsigned int virq, unsigned int cpu, bool percpu);
 int bind_virq_to_irqhandler(unsigned int virq, unsigned int cpu,
                            irq_handler_t handler,
                            unsigned long irqflags, const char *devname,
index 143ca5ffab7ac2c1e3ca5a653fef760f31879b47..4478f4b4aae2ff06473f2aff0e0100684f11c2bf 100644 (file)
@@ -191,6 +191,7 @@ int gnttab_unmap_refs(struct gnttab_unmap_grant_ref *unmap_ops,
                      struct gnttab_unmap_grant_ref *kunmap_ops,
                      struct page **pages, unsigned int count);
 void gnttab_unmap_refs_async(struct gntab_unmap_queue_data* item);
+int gnttab_unmap_refs_sync(struct gntab_unmap_queue_data *item);
 
 
 /* Perform a batch of grant map/copy operations. Retry every batch slot
index c643e6a94c9a31fd241902b924f00dcfb1e4fb34..0ce4f32017ea91e6af37bc860c5633f473da17b3 100644 (file)
@@ -13,6 +13,7 @@ void xen_arch_post_suspend(int suspend_cancelled);
 
 void xen_timer_resume(void);
 void xen_arch_resume(void);
+void xen_arch_suspend(void);
 
 void xen_resume_notifier_register(struct notifier_block *nb);
 void xen_resume_notifier_unregister(struct notifier_block *nb);
index 8369ffa5f33db24a12703ce74eb7ac437ada96f9..a95bbdb2a50232224eb64c5331123701ea7c2416 100644 (file)
@@ -225,10 +225,11 @@ dev_t name_to_dev_t(const char *name)
 #endif
 
        if (strncmp(name, "/dev/", 5) != 0) {
-               unsigned maj, min;
+               unsigned maj, min, offset;
                char dummy;
 
-               if (sscanf(name, "%u:%u%c", &maj, &min, &dummy) == 2) {
+               if ((sscanf(name, "%u:%u%c", &maj, &min, &dummy) == 2) ||
+                   (sscanf(name, "%u:%u:%u:%c", &maj, &min, &offset, &dummy) == 3)) {
                        res = MKDEV(maj, min);
                        if (maj != MAJOR(res) || min != MINOR(res))
                                goto fail;
index 0f8f8b0bc1bf660b9c8c4d7a51f2d698e1534a17..60c302cfb4d3cbb976f0b2d69f28a96899b1d4ce 100644 (file)
@@ -197,9 +197,9 @@ x509.genkey:
        @echo >>x509.genkey "x509_extensions = myexts"
        @echo >>x509.genkey
        @echo >>x509.genkey "[ req_distinguished_name ]"
-       @echo >>x509.genkey "O = Magrathea"
-       @echo >>x509.genkey "CN = Glacier signing key"
-       @echo >>x509.genkey "emailAddress = slartibartfast@magrathea.h2g2"
+       @echo >>x509.genkey "#O = Unspecified company"
+       @echo >>x509.genkey "CN = Build time autogenerated kernel key"
+       @echo >>x509.genkey "#emailAddress = unspecified.user@unspecified.company"
        @echo >>x509.genkey
        @echo >>x509.genkey "[ myexts ]"
        @echo >>x509.genkey "basicConstraints=critical,CA:FALSE"
index 4139a0f8b558e4e7db4f79adbd353c97c7fda553..54f0e7fcd0e288b4506fab80091dcc39069ae422 100644 (file)
@@ -357,8 +357,8 @@ select_insn:
        ALU64_MOD_X:
                if (unlikely(SRC == 0))
                        return 0;
-               tmp = DST;
-               DST = do_div(tmp, SRC);
+               div64_u64_rem(DST, SRC, &tmp);
+               DST = tmp;
                CONT;
        ALU_MOD_X:
                if (unlikely(SRC == 0))
@@ -367,8 +367,8 @@ select_insn:
                DST = do_div(tmp, (u32) SRC);
                CONT;
        ALU64_MOD_K:
-               tmp = DST;
-               DST = do_div(tmp, IMM);
+               div64_u64_rem(DST, IMM, &tmp);
+               DST = tmp;
                CONT;
        ALU_MOD_K:
                tmp = (u32) DST;
@@ -377,7 +377,7 @@ select_insn:
        ALU64_DIV_X:
                if (unlikely(SRC == 0))
                        return 0;
-               do_div(DST, SRC);
+               DST = div64_u64(DST, SRC);
                CONT;
        ALU_DIV_X:
                if (unlikely(SRC == 0))
@@ -387,7 +387,7 @@ select_insn:
                DST = (u32) tmp;
                CONT;
        ALU64_DIV_K:
-               do_div(DST, IMM);
+               DST = div64_u64(DST, IMM);
                CONT;
        ALU_DIV_K:
                tmp = (u32) DST;
index 24f00610c575fd5d34c40dcf9fad35b358596c22..333d364be29d9e6c8b209d9eaded9d28552a36d7 100644 (file)
@@ -912,7 +912,8 @@ long compat_get_bitmap(unsigned long *mask, const compat_ulong_t __user *umask,
                         * bitmap. We must however ensure the end of the
                         * kernel bitmap is zeroed.
                         */
-                       if (nr_compat_longs-- > 0) {
+                       if (nr_compat_longs) {
+                               nr_compat_longs--;
                                if (__get_user(um, umask))
                                        return -EFAULT;
                        } else {
@@ -954,7 +955,8 @@ long compat_put_bitmap(compat_ulong_t __user *umask, unsigned long *mask,
                         * We dont want to write past the end of the userspace
                         * bitmap.
                         */
-                       if (nr_compat_longs-- > 0) {
+                       if (nr_compat_longs) {
+                               nr_compat_longs--;
                                if (__put_user(um, umask))
                                        return -EFAULT;
                        }
index 81aa3a4ece9f787038027bb4e5a1e456312c1182..eddf1ed4155eaa5b4bc9c5321d99596a1c70d751 100644 (file)
@@ -913,10 +913,30 @@ static void put_ctx(struct perf_event_context *ctx)
  * Those places that change perf_event::ctx will hold both
  * perf_event_ctx::mutex of the 'old' and 'new' ctx value.
  *
- * Lock ordering is by mutex address. There is one other site where
- * perf_event_context::mutex nests and that is put_event(). But remember that
- * that is a parent<->child context relation, and migration does not affect
- * children, therefore these two orderings should not interact.
+ * Lock ordering is by mutex address. There are two other sites where
+ * perf_event_context::mutex nests and those are:
+ *
+ *  - perf_event_exit_task_context()   [ child , 0 ]
+ *      __perf_event_exit_task()
+ *        sync_child_event()
+ *          put_event()                        [ parent, 1 ]
+ *
+ *  - perf_event_init_context()                [ parent, 0 ]
+ *      inherit_task_group()
+ *        inherit_group()
+ *          inherit_event()
+ *            perf_event_alloc()
+ *              perf_init_event()
+ *                perf_try_init_event()        [ child , 1 ]
+ *
+ * While it appears there is an obvious deadlock here -- the parent and child
+ * nesting levels are inverted between the two. This is in fact safe because
+ * life-time rules separate them. That is an exiting task cannot fork, and a
+ * spawning task cannot (yet) exit.
+ *
+ * But remember that that these are parent<->child context relations, and
+ * migration does not affect children, therefore these two orderings should not
+ * interact.
  *
  * The change in perf_event::ctx does not affect children (as claimed above)
  * because the sys_perf_event_open() case will install a new event and break
@@ -3422,7 +3442,6 @@ static void free_event_rcu(struct rcu_head *head)
        if (event->ns)
                put_pid_ns(event->ns);
        perf_event_free_filter(event);
-       perf_event_free_bpf_prog(event);
        kfree(event);
 }
 
@@ -3553,6 +3572,8 @@ static void __free_event(struct perf_event *event)
                        put_callchain_buffers();
        }
 
+       perf_event_free_bpf_prog(event);
+
        if (event->destroy)
                event->destroy(event);
 
@@ -3657,9 +3678,6 @@ static void perf_remove_from_owner(struct perf_event *event)
        }
 }
 
-/*
- * Called when the last reference to the file is gone.
- */
 static void put_event(struct perf_event *event)
 {
        struct perf_event_context *ctx;
@@ -3697,6 +3715,9 @@ int perf_event_release_kernel(struct perf_event *event)
 }
 EXPORT_SYMBOL_GPL(perf_event_release_kernel);
 
+/*
+ * Called when the last reference to the file is gone.
+ */
 static int perf_release(struct inode *inode, struct file *file)
 {
        put_event(file->private_data);
@@ -7364,7 +7385,12 @@ static int perf_try_init_event(struct pmu *pmu, struct perf_event *event)
                return -ENODEV;
 
        if (event->group_leader != event) {
-               ctx = perf_event_ctx_lock(event->group_leader);
+               /*
+                * This ctx->mutex can nest when we're called through
+                * inheritance. See the perf_event_ctx_lock_nested() comment.
+                */
+               ctx = perf_event_ctx_lock_nested(event->group_leader,
+                                                SINGLE_DEPTH_NESTING);
                BUG_ON(!ctx);
        }
 
index 232f00f273cbe419d2738d5f83465dd96529ee17..725c416085e318aa6c21633dcd102cc4864940cf 100644 (file)
@@ -493,6 +493,20 @@ int rb_alloc_aux(struct ring_buffer *rb, struct perf_event *event,
                        rb->aux_pages[rb->aux_nr_pages] = page_address(page++);
        }
 
+       /*
+        * In overwrite mode, PMUs that don't support SG may not handle more
+        * than one contiguous allocation, since they rely on PMI to do double
+        * buffering. In this case, the entire buffer has to be one contiguous
+        * chunk.
+        */
+       if ((event->pmu->capabilities & PERF_PMU_CAP_AUX_NO_SG) &&
+           overwrite) {
+               struct page *page = virt_to_page(rb->aux_pages[0]);
+
+               if (page_private(page) != max_order)
+                       goto out;
+       }
+
        rb->aux_priv = event->pmu->setup_aux(event->cpu, rb->aux_pages, nr_pages,
                                             overwrite);
        if (!rb->aux_priv)
index 988dc58e8847f6ebdbcd78348d9f527a9e4f2dfe..2feb6feca0cc96dff8514c45750542386db5ec53 100644 (file)
@@ -57,5 +57,6 @@ struct irq_chip dummy_irq_chip = {
        .irq_ack        = noop,
        .irq_mask       = noop,
        .irq_unmask     = noop,
+       .flags          = IRQCHIP_SKIP_SET_WAKE,
 };
 EXPORT_SYMBOL_GPL(dummy_irq_chip);
index 38c25b1f2fd5c7e4922f36cf884519c1bd485a85..7a36fdcca5bfb064a6709021782c98bd2a6de179 100644 (file)
@@ -707,7 +707,7 @@ static struct page *kimage_alloc_normal_control_pages(struct kimage *image,
        do {
                unsigned long pfn, epfn, addr, eaddr;
 
-               pages = kimage_alloc_pages(GFP_KERNEL, order);
+               pages = kimage_alloc_pages(KEXEC_CONTROL_MEMORY_GFP, order);
                if (!pages)
                        break;
                pfn   = page_to_pfn(pages);
index a0831e1b99f4aabd6c80ea68cedb6350a7a9affc..aaeae885d9af7d1dc190c566d95e0d6bed845cfe 100644 (file)
@@ -3900,7 +3900,8 @@ static void zap_class(struct lock_class *class)
        list_del_rcu(&class->hash_entry);
        list_del_rcu(&class->lock_entry);
 
-       class->key = NULL;
+       RCU_INIT_POINTER(class->key, NULL);
+       RCU_INIT_POINTER(class->name, NULL);
 }
 
 static inline int within(const void *addr, void *start, unsigned long size)
index ef43ac4bafb59b83ab979a680d49d6077749f955..d83d798bef95a042e1060a35bf4b79e7c7a6c05c 100644 (file)
@@ -426,10 +426,12 @@ static void seq_lock_time(struct seq_file *m, struct lock_time *lt)
 
 static void seq_stats(struct seq_file *m, struct lock_stat_data *data)
 {
-       char name[39];
-       struct lock_class *class;
+       struct lockdep_subclass_key *ckey;
        struct lock_class_stats *stats;
+       struct lock_class *class;
+       const char *cname;
        int i, namelen;
+       char name[39];
 
        class = data->class;
        stats = &data->stats;
@@ -440,15 +442,25 @@ static void seq_stats(struct seq_file *m, struct lock_stat_data *data)
        if (class->subclass)
                namelen -= 2;
 
-       if (!class->name) {
+       rcu_read_lock_sched();
+       cname = rcu_dereference_sched(class->name);
+       ckey  = rcu_dereference_sched(class->key);
+
+       if (!cname && !ckey) {
+               rcu_read_unlock_sched();
+               return;
+
+       } else if (!cname) {
                char str[KSYM_NAME_LEN];
                const char *key_name;
 
-               key_name = __get_key_name(class->key, str);
+               key_name = __get_key_name(ckey, str);
                snprintf(name, namelen, "%s", key_name);
        } else {
-               snprintf(name, namelen, "%s", class->name);
+               snprintf(name, namelen, "%s", cname);
        }
+       rcu_read_unlock_sched();
+
        namelen = strlen(name);
        if (class->name_version > 1) {
                snprintf(name+namelen, 3, "#%d", class->name_version);
index b73279367087ca779072b79a784f69224929c149..b025295f49662469d1f3b4257f3835d2f40f01e1 100644 (file)
@@ -265,15 +265,17 @@ struct task_struct *rt_mutex_get_top_task(struct task_struct *task)
 }
 
 /*
- * Called by sched_setscheduler() to check whether the priority change
- * is overruled by a possible priority boosting.
+ * Called by sched_setscheduler() to get the priority which will be
+ * effective after the change.
  */
-int rt_mutex_check_prio(struct task_struct *task, int newprio)
+int rt_mutex_get_effective_prio(struct task_struct *task, int newprio)
 {
        if (!task_has_pi_waiters(task))
-               return 0;
+               return newprio;
 
-       return task_top_pi_waiter(task)->task->prio <= newprio;
+       if (task_top_pi_waiter(task)->task->prio <= newprio)
+               return task_top_pi_waiter(task)->task->prio;
+       return newprio;
 }
 
 /*
index 42a1d2afb2173cd3c7c740098dd72d7a52bdb3f8..cfc9e843a924091e2be3d2a2bcef72a038737f64 100644 (file)
@@ -3370,6 +3370,9 @@ static int load_module(struct load_info *info, const char __user *uargs,
        module_bug_cleanup(mod);
        mutex_unlock(&module_mutex);
 
+       blocking_notifier_call_chain(&module_notify_list,
+                                    MODULE_STATE_GOING, mod);
+
        /* we can't deallocate the module until we clear memory protection */
        unset_module_init_ro_nx(mod);
        unset_module_core_ro_nx(mod);
index 233165da782f51deb88c6373116d9d28a4fec38b..8cf7304b2867f5a113807afb0bd5dc0a3bd3cfc0 100644 (file)
@@ -162,11 +162,14 @@ static void invoke_rcu_callbacks(struct rcu_state *rsp, struct rcu_data *rdp);
 static int kthread_prio = CONFIG_RCU_KTHREAD_PRIO;
 module_param(kthread_prio, int, 0644);
 
-/* Delay in jiffies for grace-period initialization delays. */
-static int gp_init_delay = IS_ENABLED(CONFIG_RCU_TORTURE_TEST_SLOW_INIT)
-                               ? CONFIG_RCU_TORTURE_TEST_SLOW_INIT_DELAY
-                               : 0;
+/* Delay in jiffies for grace-period initialization delays, debug only. */
+#ifdef CONFIG_RCU_TORTURE_TEST_SLOW_INIT
+static int gp_init_delay = CONFIG_RCU_TORTURE_TEST_SLOW_INIT_DELAY;
 module_param(gp_init_delay, int, 0644);
+#else /* #ifdef CONFIG_RCU_TORTURE_TEST_SLOW_INIT */
+static const int gp_init_delay;
+#endif /* #else #ifdef CONFIG_RCU_TORTURE_TEST_SLOW_INIT */
+#define PER_RCU_NODE_PERIOD 10 /* Number of grace periods between delays. */
 
 /*
  * Track the rcutorture test sequence number and the update version
@@ -1843,9 +1846,8 @@ static int rcu_gp_init(struct rcu_state *rsp)
                raw_spin_unlock_irq(&rnp->lock);
                cond_resched_rcu_qs();
                ACCESS_ONCE(rsp->gp_activity) = jiffies;
-               if (IS_ENABLED(CONFIG_RCU_TORTURE_TEST_SLOW_INIT) &&
-                   gp_init_delay > 0 &&
-                   !(rsp->gpnum % (rcu_num_nodes * 10)))
+               if (gp_init_delay > 0 &&
+                   !(rsp->gpnum % (rcu_num_nodes * PER_RCU_NODE_PERIOD)))
                        schedule_timeout_uninterruptible(gp_init_delay);
        }
 
index f9123a82cbb614eb26cab55c0f58540a5a3eb24b..123673291ffbb160734ed889b934d557611a1cf1 100644 (file)
@@ -1016,13 +1016,6 @@ void check_preempt_curr(struct rq *rq, struct task_struct *p, int flags)
                rq_clock_skip_update(rq, true);
 }
 
-static ATOMIC_NOTIFIER_HEAD(task_migration_notifier);
-
-void register_task_migration_notifier(struct notifier_block *n)
-{
-       atomic_notifier_chain_register(&task_migration_notifier, n);
-}
-
 #ifdef CONFIG_SMP
 void set_task_cpu(struct task_struct *p, unsigned int new_cpu)
 {
@@ -1053,18 +1046,10 @@ void set_task_cpu(struct task_struct *p, unsigned int new_cpu)
        trace_sched_migrate_task(p, new_cpu);
 
        if (task_cpu(p) != new_cpu) {
-               struct task_migration_notifier tmn;
-
                if (p->sched_class->migrate_task_rq)
                        p->sched_class->migrate_task_rq(p, new_cpu);
                p->se.nr_migrations++;
                perf_sw_event_sched(PERF_COUNT_SW_CPU_MIGRATIONS, 1, 0);
-
-               tmn.task = p;
-               tmn.from_cpu = task_cpu(p);
-               tmn.to_cpu = new_cpu;
-
-               atomic_notifier_call_chain(&task_migration_notifier, 0, &tmn);
        }
 
        __set_task_cpu(p, new_cpu);
@@ -3315,15 +3300,18 @@ static void __setscheduler_params(struct task_struct *p,
 
 /* Actually do priority change: must hold pi & rq lock. */
 static void __setscheduler(struct rq *rq, struct task_struct *p,
-                          const struct sched_attr *attr)
+                          const struct sched_attr *attr, bool keep_boost)
 {
        __setscheduler_params(p, attr);
 
        /*
-        * If we get here, there was no pi waiters boosting the
-        * task. It is safe to use the normal prio.
+        * Keep a potential priority boosting if called from
+        * sched_setscheduler().
         */
-       p->prio = normal_prio(p);
+       if (keep_boost)
+               p->prio = rt_mutex_get_effective_prio(p, normal_prio(p));
+       else
+               p->prio = normal_prio(p);
 
        if (dl_prio(p->prio))
                p->sched_class = &dl_sched_class;
@@ -3423,7 +3411,7 @@ static int __sched_setscheduler(struct task_struct *p,
        int newprio = dl_policy(attr->sched_policy) ? MAX_DL_PRIO - 1 :
                      MAX_RT_PRIO - 1 - attr->sched_priority;
        int retval, oldprio, oldpolicy = -1, queued, running;
-       int policy = attr->sched_policy;
+       int new_effective_prio, policy = attr->sched_policy;
        unsigned long flags;
        const struct sched_class *prev_class;
        struct rq *rq;
@@ -3605,15 +3593,14 @@ change:
        oldprio = p->prio;
 
        /*
-        * Special case for priority boosted tasks.
-        *
-        * If the new priority is lower or equal (user space view)
-        * than the current (boosted) priority, we just store the new
+        * Take priority boosted tasks into account. If the new
+        * effective priority is unchanged, we just store the new
         * normal parameters and do not touch the scheduler class and
         * the runqueue. This will be done when the task deboost
         * itself.
         */
-       if (rt_mutex_check_prio(p, newprio)) {
+       new_effective_prio = rt_mutex_get_effective_prio(p, newprio);
+       if (new_effective_prio == oldprio) {
                __setscheduler_params(p, attr);
                task_rq_unlock(rq, p, &flags);
                return 0;
@@ -3627,7 +3614,7 @@ change:
                put_prev_task(rq, p);
 
        prev_class = p->sched_class;
-       __setscheduler(rq, p, attr);
+       __setscheduler(rq, p, attr, true);
 
        if (running)
                p->sched_class->set_curr_task(rq);
@@ -4402,10 +4389,7 @@ long __sched io_schedule_timeout(long timeout)
        long ret;
 
        current->in_iowait = 1;
-       if (old_iowait)
-               blk_schedule_flush_plug(current);
-       else
-               blk_flush_plug(current);
+       blk_schedule_flush_plug(current);
 
        delayacct_blkio_start();
        rq = raw_rq();
@@ -7012,27 +6996,23 @@ static int cpuset_cpu_inactive(struct notifier_block *nfb, unsigned long action,
        unsigned long flags;
        long cpu = (long)hcpu;
        struct dl_bw *dl_b;
+       bool overflow;
+       int cpus;
 
-       switch (action & ~CPU_TASKS_FROZEN) {
+       switch (action) {
        case CPU_DOWN_PREPARE:
-               /* explicitly allow suspend */
-               if (!(action & CPU_TASKS_FROZEN)) {
-                       bool overflow;
-                       int cpus;
-
-                       rcu_read_lock_sched();
-                       dl_b = dl_bw_of(cpu);
+               rcu_read_lock_sched();
+               dl_b = dl_bw_of(cpu);
 
-                       raw_spin_lock_irqsave(&dl_b->lock, flags);
-                       cpus = dl_bw_cpus(cpu);
-                       overflow = __dl_overflow(dl_b, cpus, 0, 0);
-                       raw_spin_unlock_irqrestore(&dl_b->lock, flags);
+               raw_spin_lock_irqsave(&dl_b->lock, flags);
+               cpus = dl_bw_cpus(cpu);
+               overflow = __dl_overflow(dl_b, cpus, 0, 0);
+               raw_spin_unlock_irqrestore(&dl_b->lock, flags);
 
-                       rcu_read_unlock_sched();
+               rcu_read_unlock_sched();
 
-                       if (overflow)
-                               return notifier_from_errno(-EBUSY);
-               }
+               if (overflow)
+                       return notifier_from_errno(-EBUSY);
                cpuset_update_active_cpus(false);
                break;
        case CPU_DOWN_PREPARE_FROZEN:
@@ -7361,7 +7341,7 @@ static void normalize_task(struct rq *rq, struct task_struct *p)
        queued = task_on_rq_queued(p);
        if (queued)
                dequeue_task(rq, p, 0);
-       __setscheduler(rq, p, &attr);
+       __setscheduler(rq, p, &attr, false);
        if (queued) {
                enqueue_task(rq, p, 0);
                resched_curr(rq);
index ffeaa4105e48a36105ecaea8967082e1e7a7af98..c2980e8733bcb9da333f5d06e85441a78f1097a8 100644 (file)
@@ -2181,7 +2181,7 @@ void task_numa_work(struct callback_head *work)
        }
        for (; vma; vma = vma->vm_next) {
                if (!vma_migratable(vma) || !vma_policy_mof(vma) ||
-                       is_vm_hugetlb_page(vma)) {
+                       is_vm_hugetlb_page(vma) || (vma->vm_flags & VM_MIXEDMAP)) {
                        continue;
                }
 
index deef1caa94c6779ea13e48690ffc2d9de2e7dddc..fefcb1fa5160139a41e9dd1fee74b20ef39105e0 100644 (file)
@@ -81,7 +81,6 @@ static void cpuidle_idle_call(void)
        struct cpuidle_device *dev = __this_cpu_read(cpuidle_devices);
        struct cpuidle_driver *drv = cpuidle_get_cpu_driver(dev);
        int next_state, entered_state;
-       unsigned int broadcast;
        bool reflect;
 
        /*
@@ -150,17 +149,6 @@ static void cpuidle_idle_call(void)
                goto exit_idle;
        }
 
-       broadcast = drv->states[next_state].flags & CPUIDLE_FLAG_TIMER_STOP;
-
-       /*
-        * Tell the time framework to switch to a broadcast timer
-        * because our local timer will be shutdown. If a local timer
-        * is used from another cpu as a broadcast timer, this call may
-        * fail if it is not available
-        */
-       if (broadcast && tick_broadcast_enter())
-               goto use_default;
-
        /* Take note of the planned idle state. */
        idle_set_state(this_rq(), &drv->states[next_state]);
 
@@ -174,8 +162,8 @@ static void cpuidle_idle_call(void)
        /* The cpu is no longer idle or about to enter idle. */
        idle_set_state(this_rq(), NULL);
 
-       if (broadcast)
-               tick_broadcast_exit();
+       if (entered_state == -EBUSY)
+               goto use_default;
 
        /*
         * Give the governor an opportunity to reflect on the outcome
index 11dc22a6983b55da3c2c356cb375fa27dbad0ed8..637a09461c1d9a3d30fc3d6a33cb85b76a990261 100644 (file)
@@ -117,11 +117,7 @@ static int __clockevents_set_state(struct clock_event_device *dev,
        /* Transition with new state-specific callbacks */
        switch (state) {
        case CLOCK_EVT_STATE_DETACHED:
-               /*
-                * This is an internal state, which is guaranteed to go from
-                * SHUTDOWN to DETACHED. No driver interaction required.
-                */
-               return 0;
+               /* The clockevent device is getting replaced. Shut it down. */
 
        case CLOCK_EVT_STATE_SHUTDOWN:
                return dev->set_state_shutdown(dev);
index 76d4bd962b19b3bab345460676954ef6f7c14568..93ef7190bdeaadbf99efe07954cca3bee6399d07 100644 (file)
@@ -266,21 +266,23 @@ lock_hrtimer_base(const struct hrtimer *timer, unsigned long *flags)
 /*
  * Divide a ktime value by a nanosecond value
  */
-u64 __ktime_divns(const ktime_t kt, s64 div)
+s64 __ktime_divns(const ktime_t kt, s64 div)
 {
-       u64 dclc;
        int sft = 0;
+       s64 dclc;
+       u64 tmp;
 
        dclc = ktime_to_ns(kt);
+       tmp = dclc < 0 ? -dclc : dclc;
+
        /* Make sure the divisor is less than 2^32: */
        while (div >> 32) {
                sft++;
                div >>= 1;
        }
-       dclc >>= sft;
-       do_div(dclc, (unsigned long) div);
-
-       return dclc;
+       tmp >>= sft;
+       do_div(tmp, (unsigned long) div);
+       return dclc < 0 ? -tmp : tmp;
 }
 EXPORT_SYMBOL_GPL(__ktime_divns);
 #endif /* BITS_PER_LONG >= 64 */
index 13d945c0d03f2bda5802971484b21bbe9f65301f..1b28df2d91042de97566454a80dcb36d24674a49 100644 (file)
@@ -450,7 +450,7 @@ static int __init ring_buffer_benchmark_init(void)
 
        if (producer_fifo >= 0) {
                struct sched_param param = {
-                       .sched_priority = consumer_fifo
+                       .sched_priority = producer_fifo
                };
                sched_setscheduler(producer, SCHED_FIFO, &param);
        } else
index 692bf7184c8c1322f54bc4fe529e4519ba22a35e..25a086bcb7004778057b1d9570dd02a275601d0a 100644 (file)
@@ -178,12 +178,13 @@ ftrace_print_hex_seq(struct trace_seq *p, const unsigned char *buf, int buf_len)
 EXPORT_SYMBOL(ftrace_print_hex_seq);
 
 const char *
-ftrace_print_array_seq(struct trace_seq *p, const void *buf, int buf_len,
+ftrace_print_array_seq(struct trace_seq *p, const void *buf, int count,
                       size_t el_size)
 {
        const char *ret = trace_seq_buffer_ptr(p);
        const char *prefix = "";
        void *ptr = (void *)buf;
+       size_t buf_len = count * el_size;
 
        trace_seq_putc(p, '{');
 
index 2316f50b07a456e979603fcee13a66fca03b1baa..581a68a04c64089b847d3b76d1abc138a83bb209 100644 (file)
@@ -41,6 +41,8 @@
 #define NMI_WATCHDOG_ENABLED      (1 << NMI_WATCHDOG_ENABLED_BIT)
 #define SOFT_WATCHDOG_ENABLED     (1 << SOFT_WATCHDOG_ENABLED_BIT)
 
+static DEFINE_MUTEX(watchdog_proc_mutex);
+
 #ifdef CONFIG_HARDLOCKUP_DETECTOR
 static unsigned long __read_mostly watchdog_enabled = SOFT_WATCHDOG_ENABLED|NMI_WATCHDOG_ENABLED;
 #else
@@ -608,26 +610,36 @@ void watchdog_nmi_enable_all(void)
 {
        int cpu;
 
-       if (!watchdog_user_enabled)
-               return;
+       mutex_lock(&watchdog_proc_mutex);
+
+       if (!(watchdog_enabled & NMI_WATCHDOG_ENABLED))
+               goto unlock;
 
        get_online_cpus();
        for_each_online_cpu(cpu)
                watchdog_nmi_enable(cpu);
        put_online_cpus();
+
+unlock:
+       mutex_unlock(&watchdog_proc_mutex);
 }
 
 void watchdog_nmi_disable_all(void)
 {
        int cpu;
 
+       mutex_lock(&watchdog_proc_mutex);
+
        if (!watchdog_running)
-               return;
+               goto unlock;
 
        get_online_cpus();
        for_each_online_cpu(cpu)
                watchdog_nmi_disable(cpu);
        put_online_cpus();
+
+unlock:
+       mutex_unlock(&watchdog_proc_mutex);
 }
 #else
 static int watchdog_nmi_enable(unsigned int cpu) { return 0; }
@@ -744,8 +756,6 @@ static int proc_watchdog_update(void)
 
 }
 
-static DEFINE_MUTEX(watchdog_proc_mutex);
-
 /*
  * common function for watchdog, nmi_watchdog and soft_watchdog parameter
  *
index 17670573dda82d92a515d4519211e8bbe65b5f63..ba2b0c87e65b196c7c1f016798e0b59ea8dba97c 100644 (file)
@@ -1281,6 +1281,7 @@ config RCU_TORTURE_TEST_SLOW_INIT_DELAY
        int "How much to slow down RCU grace-period initialization"
        range 0 5
        default 3
+       depends on RCU_TORTURE_TEST_SLOW_INIT
        help
          This option specifies the number of jiffies to wait between
          each rcu_node structure initialization.
index 4fecaedc80a27adadb25bfa2d4e4a13dc182ab72..777eda7d1ab4bff70b8aa465e336465239c9f1b9 100644 (file)
@@ -10,8 +10,11 @@ config KASAN
        help
          Enables kernel address sanitizer - runtime memory debugger,
          designed to find out-of-bounds accesses and use-after-free bugs.
-         This is strictly debugging feature. It consumes about 1/8
-         of available memory and brings about ~x3 performance slowdown.
+         This is strictly a debugging feature and it requires a gcc version
+         of 4.9.2 or later. Detection of out of bounds accesses to stack or
+         global variables requires gcc 5.0 or later.
+         This feature consumes about 1/8 of available memory and brings about
+         ~x3 performance slowdown.
          For better error detection enable CONFIG_STACKTRACE,
          and add slub_debug=U to boot cmdline.
 
@@ -40,6 +43,7 @@ config KASAN_INLINE
          memory accesses. This is faster than outline (in some workloads
          it gives about x2 boost over outline instrumentation), but
          make kernel's .text size much bigger.
+         This requires a gcc version of 5.0 or later.
 
 endchoice
 
index 830dd5dec40f1697b2bf2e40a294e05284ded89c..5f627084f2e998b2605016c311411d91f7016918 100644 (file)
@@ -139,64 +139,42 @@ void __init free_bootmem_cpumask_var(cpumask_var_t mask)
 #endif
 
 /**
- * cpumask_set_cpu_local_first - set i'th cpu with local numa cpu's first
- *
+ * cpumask_local_spread - select the i'th cpu with local numa cpu's first
  * @i: index number
- * @numa_node: local numa_node
- * @dstp: cpumask with the relevant cpu bit set according to the policy
+ * @node: local numa_node
  *
- * This function sets the cpumask according to a numa aware policy.
- * cpumask could be used as an affinity hint for the IRQ related to a
- * queue. When the policy is to spread queues across cores - local cores
- * first.
+ * This function selects an online CPU according to a numa aware policy;
+ * local cpus are returned first, followed by non-local ones, then it
+ * wraps around.
  *
- * Returns 0 on success, -ENOMEM for no memory, and -EAGAIN when failed to set
- * the cpu bit and need to re-call the function.
+ * It's not very efficient, but useful for setup.
  */
-int cpumask_set_cpu_local_first(int i, int numa_node, cpumask_t *dstp)
+unsigned int cpumask_local_spread(unsigned int i, int node)
 {
-       cpumask_var_t mask;
        int cpu;
-       int ret = 0;
-
-       if (!zalloc_cpumask_var(&mask, GFP_KERNEL))
-               return -ENOMEM;
 
+       /* Wrap: we always want a cpu. */
        i %= num_online_cpus();
 
-       if (numa_node == -1 || !cpumask_of_node(numa_node)) {
-               /* Use all online cpu's for non numa aware system */
-               cpumask_copy(mask, cpu_online_mask);
+       if (node == -1) {
+               for_each_cpu(cpu, cpu_online_mask)
+                       if (i-- == 0)
+                               return cpu;
        } else {
-               int n;
-
-               cpumask_and(mask,
-                           cpumask_of_node(numa_node), cpu_online_mask);
-
-               n = cpumask_weight(mask);
-               if (i >= n) {
-                       i -= n;
-
-                       /* If index > number of local cpu's, mask out local
-                        * cpu's
-                        */
-                       cpumask_andnot(mask, cpu_online_mask, mask);
+               /* NUMA first. */
+               for_each_cpu_and(cpu, cpumask_of_node(node), cpu_online_mask)
+                       if (i-- == 0)
+                               return cpu;
+
+               for_each_cpu(cpu, cpu_online_mask) {
+                       /* Skip NUMA nodes, done above. */
+                       if (cpumask_test_cpu(cpu, cpumask_of_node(node)))
+                               continue;
+
+                       if (i-- == 0)
+                               return cpu;
                }
        }
-
-       for_each_cpu(cpu, mask) {
-               if (--i < 0)
-                       goto out;
-       }
-
-       ret = -EAGAIN;
-
-out:
-       free_cpumask_var(mask);
-
-       if (!ret)
-               cpumask_set_cpu(cpu, dstp);
-
-       return ret;
+       BUG();
 }
-EXPORT_SYMBOL(cpumask_set_cpu_local_first);
+EXPORT_SYMBOL(cpumask_local_spread);
diff --git a/lib/find_last_bit.c b/lib/find_last_bit.c
deleted file mode 100644 (file)
index 3e3be40..0000000
+++ /dev/null
@@ -1,41 +0,0 @@
-/* find_last_bit.c: fallback find next bit implementation
- *
- * Copyright (C) 2008 IBM Corporation
- * Written by Rusty Russell <rusty@rustcorp.com.au>
- * (Inspired by David Howell's find_next_bit implementation)
- *
- * Rewritten by Yury Norov <yury.norov@gmail.com> to decrease
- * size and improve performance, 2015.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version
- * 2 of the License, or (at your option) any later version.
- */
-
-#include <linux/bitops.h>
-#include <linux/bitmap.h>
-#include <linux/export.h>
-#include <linux/kernel.h>
-
-#ifndef find_last_bit
-
-unsigned long find_last_bit(const unsigned long *addr, unsigned long size)
-{
-       if (size) {
-               unsigned long val = BITMAP_LAST_WORD_MASK(size);
-               unsigned long idx = (size-1) / BITS_PER_LONG;
-
-               do {
-                       val &= addr[idx];
-                       if (val)
-                               return idx * BITS_PER_LONG + __fls(val);
-
-                       val = ~0ul;
-               } while (idx--);
-       }
-       return size;
-}
-EXPORT_SYMBOL(find_last_bit);
-
-#endif
index aac511417ad19af5d9e3472747a983be5ed3ee4b..a89d041592c8bfa7b092c382962a4085560f5b1a 100644 (file)
@@ -639,7 +639,7 @@ do { \
        **************  MIPS  *****************
        ***************************************/
 #if defined(__mips__) && W_TYPE_SIZE == 32
-#if __GNUC__ >= 4 && __GNUC_MINOR__ >= 4
+#if (__GNUC__ >= 5) || (__GNUC__ >= 4 && __GNUC_MINOR__ >= 4)
 #define umul_ppmm(w1, w0, u, v)                        \
 do {                                           \
        UDItype __ll = (UDItype)(u) * (v);      \
@@ -671,7 +671,7 @@ do {                                                \
        **************  MIPS/64  **************
        ***************************************/
 #if (defined(__mips) && __mips >= 3) && W_TYPE_SIZE == 64
-#if __GNUC__ >= 4 && __GNUC_MINOR__ >= 4
+#if (__GNUC__ >= 5) || (__GNUC__ >= 4 && __GNUC_MINOR__ >= 4)
 #define umul_ppmm(w1, w0, u, v) \
 do {                                                                   \
        typedef unsigned int __ll_UTItype __attribute__((mode(TI)));    \
index 48144cdae819017e8a9c0a89aae976359d87121b..f051d69f0910a65be2dbce9799736e2ba4eee2c7 100644 (file)
@@ -197,13 +197,13 @@ static int percpu_counter_hotcpu_callback(struct notifier_block *nb,
  * Compare counter against given value.
  * Return 1 if greater, 0 if equal and -1 if less
  */
-int percpu_counter_compare(struct percpu_counter *fbc, s64 rhs)
+int __percpu_counter_compare(struct percpu_counter *fbc, s64 rhs, s32 batch)
 {
        s64     count;
 
        count = percpu_counter_read(fbc);
        /* Check to see if rough count will be sufficient for comparison */
-       if (abs(count - rhs) > (percpu_counter_batch*num_online_cpus())) {
+       if (abs(count - rhs) > (batch * num_online_cpus())) {
                if (count > rhs)
                        return 1;
                else
@@ -218,7 +218,7 @@ int percpu_counter_compare(struct percpu_counter *fbc, s64 rhs)
        else
                return 0;
 }
-EXPORT_SYMBOL(percpu_counter_compare);
+EXPORT_SYMBOL(__percpu_counter_compare);
 
 static int __init percpu_counter_startup(void)
 {
index 4898442b837fbd715f8d5079a1060e43c4b7a367..8609378e6505123a3688e0e95a18cdde013e278a 100644 (file)
@@ -14,6 +14,7 @@
  * published by the Free Software Foundation.
  */
 
+#include <linux/atomic.h>
 #include <linux/kernel.h>
 #include <linux/init.h>
 #include <linux/log2.h>
@@ -25,6 +26,7 @@
 #include <linux/random.h>
 #include <linux/rhashtable.h>
 #include <linux/err.h>
+#include <linux/export.h>
 
 #define HASH_DEFAULT_SIZE      64UL
 #define HASH_MIN_SIZE          4U
@@ -405,13 +407,18 @@ int rhashtable_insert_rehash(struct rhashtable *ht)
 
        if (rht_grow_above_75(ht, tbl))
                size *= 2;
-       /* More than two rehashes (not resizes) detected. */
-       else if (WARN_ON(old_tbl != tbl && old_tbl->size == size))
+       /* Do not schedule more than one rehash */
+       else if (old_tbl != tbl)
                return -EBUSY;
 
        new_tbl = bucket_table_alloc(ht, size, GFP_ATOMIC);
-       if (new_tbl == NULL)
+       if (new_tbl == NULL) {
+               /* Schedule async resize/rehash to try allocation
+                * non-atomic context.
+                */
+               schedule_work(&ht->run_work);
                return -ENOMEM;
+       }
 
        err = rhashtable_rehash_attach(ht, tbl, new_tbl);
        if (err) {
@@ -441,6 +448,10 @@ int rhashtable_insert_slow(struct rhashtable *ht, const void *key,
        if (key && rhashtable_lookup_fast(ht, key, ht->p))
                goto exit;
 
+       err = -E2BIG;
+       if (unlikely(rht_grow_above_max(ht, tbl)))
+               goto exit;
+
        err = -EAGAIN;
        if (rhashtable_check_elasticity(ht, tbl, hash) ||
            rht_grow_above_100(ht, tbl))
@@ -733,6 +744,12 @@ int rhashtable_init(struct rhashtable *ht,
        if (params->max_size)
                ht->p.max_size = rounddown_pow_of_two(params->max_size);
 
+       if (params->insecure_max_entries)
+               ht->p.insecure_max_entries =
+                       rounddown_pow_of_two(params->insecure_max_entries);
+       else
+               ht->p.insecure_max_entries = ht->p.max_size * 2;
+
        ht->p.min_size = max(ht->p.min_size, HASH_MIN_SIZE);
 
        /* The maximum (not average) chain length grows with the
index a5792019193cac08715b9f72304607f8746599de..bb3d4b6993c408321da2268b07b1eeefe57cd854 100644 (file)
@@ -607,7 +607,7 @@ EXPORT_SYMBOL(memset);
 void memzero_explicit(void *s, size_t count)
 {
        memset(s, 0, count);
-       barrier();
+       barrier_data(s);
 }
 EXPORT_SYMBOL(memzero_explicit);
 
index a28df5206d95c24d6f3b4116753747f1fb2a67e3..fe9a32591c2498b6266c2fc4753521fb469c876a 100644 (file)
@@ -57,7 +57,8 @@ static inline long do_strnlen_user(const char __user *src, unsigned long count,
                        return res + find_zero(data) + 1 - align;
                }
                res += sizeof(unsigned long);
-               if (unlikely(max < sizeof(unsigned long)))
+               /* We already handled 'unsigned long' bytes. Did we do it all ? */
+               if (unlikely(max <= sizeof(unsigned long)))
                        break;
                max -= sizeof(unsigned long);
                if (unlikely(__get_user(c,(unsigned long __user *)(src+res))))
@@ -89,8 +90,15 @@ static inline long do_strnlen_user(const char __user *src, unsigned long count,
  * Get the size of a NUL-terminated string in user space.
  *
  * Returns the size of the string INCLUDING the terminating NUL.
- * If the string is too long, returns 'count+1'.
+ * If the string is too long, returns a number larger than @count. User
+ * has to check the return value against "> count".
  * On exception (or invalid count), returns 0.
+ *
+ * NOTE! You should basically never use this function. There is
+ * almost never any valid case for using the length of a user space
+ * string, since the string can be changed at any time by other
+ * threads. Use "strncpy_from_user()" instead to get a stable copy
+ * of the string.
  */
 long strnlen_user(const char __user *str, long count)
 {
index 4abda074ea458947390b84c36f3eaad7095a2ceb..3c365ab6cf5f47711cf45ab65a593a6738713491 100644 (file)
@@ -537,8 +537,9 @@ EXPORT_SYMBOL_GPL(swiotlb_tbl_map_single);
  * Allocates bounce buffer and returns its kernel virtual address.
  */
 
-phys_addr_t map_single(struct device *hwdev, phys_addr_t phys, size_t size,
-                      enum dma_data_direction dir)
+static phys_addr_t
+map_single(struct device *hwdev, phys_addr_t phys, size_t size,
+          enum dma_data_direction dir)
 {
        dma_addr_t start_dma_addr = phys_to_dma(hwdev, io_tlb_start);
 
index 6dc4580df2af040b10bc10a5f9c423becc3ff47e..000e7b3b9896f2a9479687befd2442c43193614e 100644 (file)
@@ -359,23 +359,6 @@ static void bdi_wb_shutdown(struct backing_dev_info *bdi)
        flush_delayed_work(&bdi->wb.dwork);
 }
 
-/*
- * Called when the device behind @bdi has been removed or ejected.
- *
- * We can't really do much here except for reducing the dirty ratio at
- * the moment.  In the future we should be able to set a flag so that
- * the filesystem can handle errors at mark_inode_dirty time instead
- * of only at writeback time.
- */
-void bdi_unregister(struct backing_dev_info *bdi)
-{
-       if (WARN_ON_ONCE(!bdi->dev))
-               return;
-
-       bdi_set_min_ratio(bdi, 0);
-}
-EXPORT_SYMBOL(bdi_unregister);
-
 static void bdi_wb_init(struct bdi_writeback *wb, struct backing_dev_info *bdi)
 {
        memset(wb, 0, sizeof(*wb));
@@ -443,6 +426,7 @@ void bdi_destroy(struct backing_dev_info *bdi)
        int i;
 
        bdi_wb_shutdown(bdi);
+       bdi_set_min_ratio(bdi, 0);
 
        WARN_ON(!list_empty(&bdi->work_list));
        WARN_ON(delayed_work_pending(&bdi->wb.dwork));
index 329caf56df22d84d02495e35f051062b01bdeaba..4ca5fe0042e17c2eac0dd6d16f0065c41a5dfd4e 100644 (file)
@@ -34,13 +34,13 @@ static int hwpoison_inject(void *data, u64 val)
        if (!hwpoison_filter_enable)
                goto inject;
 
-       if (!PageLRU(p) && !PageHuge(p))
-               shake_page(p, 0);
+       if (!PageLRU(hpage) && !PageHuge(p))
+               shake_page(hpage, 0);
        /*
         * This implies unable to support non-LRU pages.
         */
-       if (!PageLRU(p) && !PageHuge(p))
-               return 0;
+       if (!PageLRU(hpage) && !PageHuge(p))
+               goto put_out;
 
        /*
         * do a racy check with elevated page count, to make sure PG_hwpoison
@@ -52,11 +52,14 @@ static int hwpoison_inject(void *data, u64 val)
        err = hwpoison_filter(hpage);
        unlock_page(hpage);
        if (err)
-               return 0;
+               goto put_out;
 
 inject:
        pr_info("Injecting memory failure at pfn %#lx\n", pfn);
        return memory_failure(pfn, 18, MF_COUNT_INCREASED);
+put_out:
+       put_page(hpage);
+       return 0;
 }
 
 static int hwpoison_unpoison(void *data, u64 val)
index 5405aff5a590c370d3c8ca37c0f9a0c19cb46775..f0fe4f2c1fa7aa865055731834cdd78e0684cca5 100644 (file)
 #define BYTES_PER_POINTER      sizeof(void *)
 
 /* GFP bitmask for kmemleak internal allocations */
-#define gfp_kmemleak_mask(gfp) (((gfp) & (GFP_KERNEL | GFP_ATOMIC)) | \
+#define gfp_kmemleak_mask(gfp) (((gfp) & (GFP_KERNEL | GFP_ATOMIC | \
+                                          __GFP_NOACCOUNT)) | \
                                 __GFP_NORETRY | __GFP_NOMEMALLOC | \
                                 __GFP_NOWARN)
 
index 14c2f2017e37cc405e52cb12bc30b128997f1f8e..a04225d372ba3ab77516b970c10135b19def3ac4 100644 (file)
@@ -2323,6 +2323,8 @@ done_restock:
        css_get_many(&memcg->css, batch);
        if (batch > nr_pages)
                refill_stock(memcg, batch - nr_pages);
+       if (!(gfp_mask & __GFP_WAIT))
+               goto done;
        /*
         * If the hierarchy is above the normal consumption range,
         * make the charging task trim their excess contribution.
@@ -5833,9 +5835,7 @@ void mem_cgroup_swapout(struct page *page, swp_entry_t entry)
        if (!mem_cgroup_is_root(memcg))
                page_counter_uncharge(&memcg->memory, 1);
 
-       /* XXX: caller holds IRQ-safe mapping->tree_lock */
-       VM_BUG_ON(!irqs_disabled());
-
+       /* Caller disabled preemption with mapping->tree_lock */
        mem_cgroup_charge_statistics(memcg, page, -1);
        memcg_check_events(memcg, page);
 }
index d9359b770cd96b37ee945553a4230edbfd720e46..501820c815b335b017ea87cf3dd3f1a0d034bd98 100644 (file)
@@ -1187,10 +1187,10 @@ int memory_failure(unsigned long pfn, int trapno, int flags)
         * The check (unnecessarily) ignores LRU pages being isolated and
         * walked by the page reclaim code, however that's not a big loss.
         */
-       if (!PageHuge(p) && !PageTransTail(p)) {
-               if (!PageLRU(p))
-                       shake_page(p, 0);
-               if (!PageLRU(p)) {
+       if (!PageHuge(p)) {
+               if (!PageLRU(hpage))
+                       shake_page(hpage, 0);
+               if (!PageLRU(hpage)) {
                        /*
                         * shake_page could have turned it free.
                         */
@@ -1777,12 +1777,12 @@ int soft_offline_page(struct page *page, int flags)
        } else if (ret == 0) { /* for free pages */
                if (PageHuge(page)) {
                        set_page_hwpoison_huge_page(hpage);
-                       dequeue_hwpoisoned_huge_page(hpage);
-                       atomic_long_add(1 << compound_order(hpage),
+                       if (!dequeue_hwpoisoned_huge_page(hpage))
+                               atomic_long_add(1 << compound_order(hpage),
                                        &num_poisoned_pages);
                } else {
-                       SetPageHWPoison(page);
-                       atomic_long_inc(&num_poisoned_pages);
+                       if (!TestSetPageHWPoison(page))
+                               atomic_long_inc(&num_poisoned_pages);
                }
        }
        unset_migratetype_isolate(page, MIGRATE_MOVABLE);
index 457bde530cbedcf0dea2f35e219466de0acf204d..9e88f749aa512395daea45f2727545fa0f281533 100644 (file)
@@ -1969,8 +1969,10 @@ void try_offline_node(int nid)
                 * wait_table may be allocated from boot memory,
                 * here only free if it's allocated by vmalloc.
                 */
-               if (is_vmalloc_addr(zone->wait_table))
+               if (is_vmalloc_addr(zone->wait_table)) {
                        vfree(zone->wait_table);
+                       zone->wait_table = NULL;
+               }
        }
 }
 EXPORT_SYMBOL(try_offline_node);
index ede26291d4aa92ad120bfd006786414fd6d45c56..747743237d9f4d3ead6117d4ee152c00659cd362 100644 (file)
@@ -2518,7 +2518,7 @@ static void __init check_numabalancing_enable(void)
        if (numabalancing_override)
                set_numabalancing_state(numabalancing_override == 1);
 
-       if (nr_node_ids > 1 && !numabalancing_override) {
+       if (num_online_nodes() > 1 && !numabalancing_override) {
                pr_info("%s automatic NUMA balancing. "
                        "Configure with numa_balancing= or the "
                        "kernel.numa_balancing sysctl",
index 5daf5568b9e149ea9dce0383b0452bd30ad67f84..eb59f7eea50827fc09e1c4f7a432b59ff2241d17 100644 (file)
@@ -580,7 +580,7 @@ static long long pos_ratio_polynom(unsigned long setpoint,
        long x;
 
        x = div64_s64(((s64)setpoint - (s64)dirty) << RATELIMIT_CALC_SHIFT,
-                   limit - setpoint + 1);
+                     (limit - setpoint) | 1);
        pos_ratio = x;
        pos_ratio = pos_ratio * x >> RATELIMIT_CALC_SHIFT;
        pos_ratio = pos_ratio * x >> RATELIMIT_CALC_SHIFT;
@@ -807,7 +807,7 @@ static unsigned long bdi_position_ratio(struct backing_dev_info *bdi,
         * scale global setpoint to bdi's:
         *      bdi_setpoint = setpoint * bdi_thresh / thresh
         */
-       x = div_u64((u64)bdi_thresh << 16, thresh + 1);
+       x = div_u64((u64)bdi_thresh << 16, thresh | 1);
        bdi_setpoint = setpoint * (u64)x >> 16;
        /*
         * Use span=(8*write_bw) in single bdi case as indicated by
@@ -822,7 +822,7 @@ static unsigned long bdi_position_ratio(struct backing_dev_info *bdi,
 
        if (bdi_dirty < x_intercept - span / 4) {
                pos_ratio = div64_u64(pos_ratio * (x_intercept - bdi_dirty),
-                                   x_intercept - bdi_setpoint + 1);
+                                     (x_intercept - bdi_setpoint) | 1);
        } else
                pos_ratio /= 4;
 
index 755a42c76eb4747623da51acdeb780b322b5ac06..303c908790efca6f7d0b30cc6d8a9db918085e10 100644 (file)
@@ -101,7 +101,8 @@ void unset_migratetype_isolate(struct page *page, unsigned migratetype)
                        buddy_idx = __find_buddy_index(page_idx, order);
                        buddy = page + (buddy_idx - page_idx);
 
-                       if (!is_migrate_isolate_page(buddy)) {
+                       if (pfn_valid_within(page_to_pfn(buddy)) &&
+                           !is_migrate_isolate_page(buddy)) {
                                __isolate_free_page(page, order);
                                kernel_map_pages(page, (1 << order), 1);
                                set_page_refcounted(page);
index 08bd7a3d464a9c6959a39e269d2284600e750a50..a8b5e749e84e7dbd50d325eecf84a47316145598 100644 (file)
@@ -289,7 +289,8 @@ static int create_handle_cache(struct zs_pool *pool)
 
 static void destroy_handle_cache(struct zs_pool *pool)
 {
-       kmem_cache_destroy(pool->handle_cachep);
+       if (pool->handle_cachep)
+               kmem_cache_destroy(pool->handle_cachep);
 }
 
 static unsigned long alloc_handle(struct zs_pool *pool)
index 98a30a5b866472b7421f5394636934bc23ec7f94..59555f0f8fc85b039cab18350906ae3c86a477af 100644 (file)
@@ -443,7 +443,7 @@ static int vlan_device_event(struct notifier_block *unused, unsigned long event,
        case NETDEV_UP:
                /* Put all VLANs for this dev in the up state too.  */
                vlan_group_for_each_dev(grp, i, vlandev) {
-                       flgs = vlandev->flags;
+                       flgs = dev_get_flags(vlandev);
                        if (flgs & IFF_UP)
                                continue;
 
index 476709bd068a474f7edcac83a4869849ccfb4b17..c4802f3bd4c51086de62c048858fb7f6057f3bbb 100644 (file)
@@ -1557,7 +1557,8 @@ static int hci_dev_do_close(struct hci_dev *hdev)
 {
        BT_DBG("%s %p", hdev->name, hdev);
 
-       if (!hci_dev_test_flag(hdev, HCI_UNREGISTER)) {
+       if (!hci_dev_test_flag(hdev, HCI_UNREGISTER) &&
+           test_bit(HCI_UP, &hdev->flags)) {
                /* Execute vendor specific shutdown routine */
                if (hdev->shutdown)
                        hdev->shutdown(hdev);
@@ -2853,9 +2854,11 @@ static void le_scan_disable_work_complete(struct hci_dev *hdev, u8 status,
                         * state. If we were running both LE and BR/EDR inquiry
                         * simultaneously, and BR/EDR inquiry is already
                         * finished, stop discovery, otherwise BR/EDR inquiry
-                        * will stop discovery when finished.
+                        * will stop discovery when finished. If we will resolve
+                        * remote device name, do not change discovery state.
                         */
-                       if (!test_bit(HCI_INQUIRY, &hdev->flags))
+                       if (!test_bit(HCI_INQUIRY, &hdev->flags) &&
+                           hdev->discovery.state != DISCOVERY_RESOLVING)
                                hci_discovery_set_state(hdev,
                                                        DISCOVERY_STOPPED);
                } else {
index e0670d7054f97c05d46b74952ee53d6fa6910776..659fb96672e41e2e6525323697ca23a41d271fbb 100644 (file)
@@ -796,9 +796,11 @@ static int __br_fdb_add(struct ndmsg *ndm, struct net_bridge_port *p,
        int err = 0;
 
        if (ndm->ndm_flags & NTF_USE) {
+               local_bh_disable();
                rcu_read_lock();
                br_fdb_update(p->br, p, addr, vid, true);
                rcu_read_unlock();
+               local_bh_enable();
        } else {
                spin_lock_bh(&p->br->hash_lock);
                err = fdb_add_entry(p, addr, ndm->ndm_state,
index 409608960899630b5349bbd310200a95dc2867a2..e29ad70b3000be4f0e7486b172746ea62b4f216f 100644 (file)
@@ -170,7 +170,7 @@ static int nlmsg_populate_mdb_fill(struct sk_buff *skb,
        struct br_port_msg *bpm;
        struct nlattr *nest, *nest2;
 
-       nlh = nlmsg_put(skb, pid, seq, type, sizeof(*bpm), NLM_F_MULTI);
+       nlh = nlmsg_put(skb, pid, seq, type, sizeof(*bpm), 0);
        if (!nlh)
                return -EMSGSIZE;
 
index 4b6722f8f1790811d2ef4b9b1ae8839628b745c8..ff667e18b2d6313f0a806752a4ef88435e939c4d 100644 (file)
@@ -1072,7 +1072,7 @@ static int br_ip6_multicast_mld2_report(struct net_bridge *br,
 
                err = br_ip6_multicast_add_group(br, port, &grec->grec_mca,
                                                 vid);
-               if (!err)
+               if (err)
                        break;
        }
 
@@ -1167,6 +1167,9 @@ static void br_multicast_add_router(struct net_bridge *br,
        struct net_bridge_port *p;
        struct hlist_node *slot = NULL;
 
+       if (!hlist_unhashed(&port->rlist))
+               return;
+
        hlist_for_each_entry(p, &br->router_list, rlist) {
                if ((unsigned long) port >= (unsigned long) p)
                        break;
@@ -1194,12 +1197,8 @@ static void br_multicast_mark_router(struct net_bridge *br,
        if (port->multicast_router != 1)
                return;
 
-       if (!hlist_unhashed(&port->rlist))
-               goto timer;
-
        br_multicast_add_router(br, port);
 
-timer:
        mod_timer(&port->multicast_router_timer,
                  now + br->multicast_querier_interval);
 }
@@ -1822,7 +1821,7 @@ static void br_multicast_query_expired(struct net_bridge *br,
        if (query->startup_sent < br->multicast_startup_query_count)
                query->startup_sent++;
 
-       RCU_INIT_POINTER(querier, NULL);
+       RCU_INIT_POINTER(querier->port, NULL);
        br_multicast_send_query(br, NULL, query);
        spin_unlock(&br->multicast_lock);
 }
index ab55e2472beb0e44dece07e327f2e0eb8d3f502c..60ddfbeb47f598fed5908dfc492abef48c0acd75 100644 (file)
 #include <net/route.h>
 #include <net/netfilter/br_netfilter.h>
 
-#if IS_ENABLED(CONFIG_NF_CONNTRACK)
-#include <net/netfilter/nf_conntrack.h>
-#endif
-
 #include <asm/uaccess.h>
 #include "br_private.h"
 #ifdef CONFIG_SYSCTL
@@ -350,24 +346,15 @@ free_skb:
        return 0;
 }
 
-static bool dnat_took_place(const struct sk_buff *skb)
+static bool daddr_was_changed(const struct sk_buff *skb,
+                             const struct nf_bridge_info *nf_bridge)
 {
-#if IS_ENABLED(CONFIG_NF_CONNTRACK)
-       enum ip_conntrack_info ctinfo;
-       struct nf_conn *ct;
-
-       ct = nf_ct_get(skb, &ctinfo);
-       if (!ct || nf_ct_is_untracked(ct))
-               return false;
-
-       return test_bit(IPS_DST_NAT_BIT, &ct->status);
-#else
-       return false;
-#endif
+       return ip_hdr(skb)->daddr != nf_bridge->ipv4_daddr;
 }
 
 /* This requires some explaining. If DNAT has taken place,
  * we will need to fix up the destination Ethernet address.
+ * This is also true when SNAT takes place (for the reply direction).
  *
  * There are two cases to consider:
  * 1. The packet was DNAT'ed to a device in the same bridge
@@ -421,7 +408,7 @@ static int br_nf_pre_routing_finish(struct sock *sk, struct sk_buff *skb)
                nf_bridge->pkt_otherhost = false;
        }
        nf_bridge->mask ^= BRNF_NF_BRIDGE_PREROUTING;
-       if (dnat_took_place(skb)) {
+       if (daddr_was_changed(skb, nf_bridge)) {
                if ((err = ip_route_input(skb, iph->daddr, iph->saddr, iph->tos, dev))) {
                        struct in_device *in_dev = __in_dev_get_rcu(dev);
 
@@ -632,6 +619,7 @@ static unsigned int br_nf_pre_routing(const struct nf_hook_ops *ops,
                                      struct sk_buff *skb,
                                      const struct nf_hook_state *state)
 {
+       struct nf_bridge_info *nf_bridge;
        struct net_bridge_port *p;
        struct net_bridge *br;
        __u32 len = nf_bridge_encap_header_len(skb);
@@ -669,6 +657,9 @@ static unsigned int br_nf_pre_routing(const struct nf_hook_ops *ops,
        if (!setup_pre_routing(skb))
                return NF_DROP;
 
+       nf_bridge = nf_bridge_info_get(skb);
+       nf_bridge->ipv4_daddr = ip_hdr(skb)->daddr;
+
        skb->protocol = htons(ETH_P_IP);
 
        NF_HOOK(NFPROTO_IPV4, NF_INET_PRE_ROUTING, state->sk, skb,
index 0e4ddb81610d90ff51a45835424cef547bba73bf..4b5c236998ff1010831711a17b773e16c7d8ba58 100644 (file)
@@ -394,7 +394,7 @@ errout:
  * Dump information about all ports, in response to GETLINK
  */
 int br_getlink(struct sk_buff *skb, u32 pid, u32 seq,
-              struct net_device *dev, u32 filter_mask)
+              struct net_device *dev, u32 filter_mask, int nlflags)
 {
        struct net_bridge_port *port = br_port_get_rtnl(dev);
 
@@ -402,7 +402,7 @@ int br_getlink(struct sk_buff *skb, u32 pid, u32 seq,
            !(filter_mask & RTEXT_FILTER_BRVLAN_COMPRESSED))
                return 0;
 
-       return br_fill_ifinfo(skb, port, pid, seq, RTM_NEWLINK, NLM_F_MULTI,
+       return br_fill_ifinfo(skb, port, pid, seq, RTM_NEWLINK, nlflags,
                              filter_mask, dev);
 }
 
index 6ca0251cb478bf3147501b325a381a4081dd5149..3362c29400f182c90db6e67a04fcc5018906fa41 100644 (file)
@@ -828,7 +828,7 @@ void br_ifinfo_notify(int event, struct net_bridge_port *port);
 int br_setlink(struct net_device *dev, struct nlmsghdr *nlmsg, u16 flags);
 int br_dellink(struct net_device *dev, struct nlmsghdr *nlmsg, u16 flags);
 int br_getlink(struct sk_buff *skb, u32 pid, u32 seq, struct net_device *dev,
-              u32 filter_mask);
+              u32 filter_mask, int nlflags);
 
 #ifdef CONFIG_SYSFS
 /* br_sysfs_if.c */
index 4fcaa67750fda845ad0a180332c4cd96a9524086..7caf7fae2d5b8aa369b924e1c87a47c343fb8954 100644 (file)
@@ -97,7 +97,9 @@ static void br_forward_delay_timer_expired(unsigned long arg)
                netif_carrier_on(br->dev);
        }
        br_log_state(p);
+       rcu_read_lock();
        br_ifinfo_notify(RTM_NEWLINK, p);
+       rcu_read_unlock();
        spin_unlock(&br->lock);
 }
 
index 4ec0c803aef112196657503cd615fe7a83e800bb..112ad784838a5bf6b46eed6c2b90f2d8b0e50d7a 100644 (file)
@@ -330,6 +330,10 @@ static long caif_stream_data_wait(struct sock *sk, long timeo)
                release_sock(sk);
                timeo = schedule_timeout(timeo);
                lock_sock(sk);
+
+               if (sock_flag(sk, SOCK_DEAD))
+                       break;
+
                clear_bit(SOCK_ASYNC_WAITDATA, &sk->sk_socket->flags);
        }
 
@@ -373,6 +377,10 @@ static int caif_stream_recvmsg(struct socket *sock, struct msghdr *msg,
                struct sk_buff *skb;
 
                lock_sock(sk);
+               if (sock_flag(sk, SOCK_DEAD)) {
+                       err = -ECONNRESET;
+                       goto unlock;
+               }
                skb = skb_dequeue(&sk->sk_receive_queue);
                caif_check_flow_release(sk);
 
index 41a4abc7e98eebfd36487d6d381f680732d4cd68..c4ec9239249ae6541a8ee378f95230a42c2f3a3d 100644 (file)
@@ -1306,8 +1306,6 @@ static void __unregister_linger_request(struct ceph_osd_client *osdc,
                if (list_empty(&req->r_osd_item))
                        req->r_osd = NULL;
        }
-
-       list_del_init(&req->r_req_lru_item); /* can be on notarget */
        ceph_osdc_put_request(req);
 }
 
@@ -2017,20 +2015,29 @@ static void kick_requests(struct ceph_osd_client *osdc, bool force_resend,
                err = __map_request(osdc, req,
                                    force_resend || force_resend_writes);
                dout("__map_request returned %d\n", err);
-               if (err == 0)
-                       continue;  /* no change and no osd was specified */
                if (err < 0)
                        continue;  /* hrm! */
-               if (req->r_osd == NULL) {
-                       dout("tid %llu maps to no valid osd\n", req->r_tid);
-                       needmap++;  /* request a newer map */
-                       continue;
-               }
+               if (req->r_osd == NULL || err > 0) {
+                       if (req->r_osd == NULL) {
+                               dout("lingering %p tid %llu maps to no osd\n",
+                                    req, req->r_tid);
+                               /*
+                                * A homeless lingering request makes
+                                * no sense, as it's job is to keep
+                                * a particular OSD connection open.
+                                * Request a newer map and kick the
+                                * request, knowing that it won't be
+                                * resent until we actually get a map
+                                * that can tell us where to send it.
+                                */
+                               needmap++;
+                       }
 
-               dout("kicking lingering %p tid %llu osd%d\n", req, req->r_tid,
-                    req->r_osd ? req->r_osd->o_osd : -1);
-               __register_request(osdc, req);
-               __unregister_linger_request(osdc, req);
+                       dout("kicking lingering %p tid %llu osd%d\n", req,
+                            req->r_tid, req->r_osd ? req->r_osd->o_osd : -1);
+                       __register_request(osdc, req);
+                       __unregister_linger_request(osdc, req);
+               }
        }
        reset_changed_osds(osdc);
        mutex_unlock(&osdc->request_mutex);
index 1796cef55ab5af93718047604c554475b4d3275b..aa82f9ab6a36d164769bf7c9633fcdfd5971466f 100644 (file)
@@ -1718,15 +1718,8 @@ EXPORT_SYMBOL_GPL(is_skb_forwardable);
 
 int __dev_forward_skb(struct net_device *dev, struct sk_buff *skb)
 {
-       if (skb_shinfo(skb)->tx_flags & SKBTX_DEV_ZEROCOPY) {
-               if (skb_copy_ubufs(skb, GFP_ATOMIC)) {
-                       atomic_long_inc(&dev->rx_dropped);
-                       kfree_skb(skb);
-                       return NET_RX_DROP;
-               }
-       }
-
-       if (unlikely(!is_skb_forwardable(dev, skb))) {
+       if (skb_orphan_frags(skb, GFP_ATOMIC) ||
+           unlikely(!is_skb_forwardable(dev, skb))) {
                atomic_long_inc(&dev->rx_dropped);
                kfree_skb(skb);
                return NET_RX_DROP;
@@ -3079,7 +3072,7 @@ static struct rps_dev_flow *
 set_rps_cpu(struct net_device *dev, struct sk_buff *skb,
            struct rps_dev_flow *rflow, u16 next_cpu)
 {
-       if (next_cpu != RPS_NO_CPU) {
+       if (next_cpu < nr_cpu_ids) {
 #ifdef CONFIG_RFS_ACCEL
                struct netdev_rx_queue *rxqueue;
                struct rps_dev_flow_table *flow_table;
@@ -3184,7 +3177,7 @@ static int get_rps_cpu(struct net_device *dev, struct sk_buff *skb,
                 * If the desired CPU (where last recvmsg was done) is
                 * different from current CPU (one in the rx-queue flow
                 * table entry), switch if one of the following holds:
-                *   - Current CPU is unset (equal to RPS_NO_CPU).
+                *   - Current CPU is unset (>= nr_cpu_ids).
                 *   - Current CPU is offline.
                 *   - The current CPU's queue tail has advanced beyond the
                 *     last packet that was enqueued using this table entry.
@@ -3192,14 +3185,14 @@ static int get_rps_cpu(struct net_device *dev, struct sk_buff *skb,
                 *     have been dequeued, thus preserving in order delivery.
                 */
                if (unlikely(tcpu != next_cpu) &&
-                   (tcpu == RPS_NO_CPU || !cpu_online(tcpu) ||
+                   (tcpu >= nr_cpu_ids || !cpu_online(tcpu) ||
                     ((int)(per_cpu(softnet_data, tcpu).input_queue_head -
                      rflow->last_qtail)) >= 0)) {
                        tcpu = next_cpu;
                        rflow = set_rps_cpu(dev, skb, rflow, next_cpu);
                }
 
-               if (tcpu != RPS_NO_CPU && cpu_online(tcpu)) {
+               if (tcpu < nr_cpu_ids && cpu_online(tcpu)) {
                        *rflowp = rflow;
                        cpu = tcpu;
                        goto done;
@@ -3240,14 +3233,14 @@ bool rps_may_expire_flow(struct net_device *dev, u16 rxq_index,
        struct rps_dev_flow_table *flow_table;
        struct rps_dev_flow *rflow;
        bool expire = true;
-       int cpu;
+       unsigned int cpu;
 
        rcu_read_lock();
        flow_table = rcu_dereference(rxqueue->rps_flow_table);
        if (flow_table && flow_id <= flow_table->mask) {
                rflow = &flow_table->flows[flow_id];
                cpu = ACCESS_ONCE(rflow->cpu);
-               if (rflow->filter == filter_id && cpu != RPS_NO_CPU &&
+               if (rflow->filter == filter_id && cpu < nr_cpu_ids &&
                    ((int)(per_cpu(softnet_data, cpu).input_queue_head -
                           rflow->last_qtail) <
                     (int)(10 * flow_table->mask)))
@@ -5209,7 +5202,7 @@ static int __netdev_upper_dev_link(struct net_device *dev,
        if (__netdev_find_adj(upper_dev, dev, &upper_dev->all_adj_list.upper))
                return -EBUSY;
 
-       if (__netdev_find_adj(dev, upper_dev, &dev->all_adj_list.upper))
+       if (__netdev_find_adj(dev, upper_dev, &dev->adj_list.upper))
                return -EEXIST;
 
        if (master && netdev_master_upper_dev_get(dev))
index 78fc04ad36fc03a0f1737ee484a08e1824b324dc..572af0011997a2057f30ba0b5022760e11493d98 100644 (file)
@@ -601,7 +601,7 @@ static int rtnl_net_getid(struct sk_buff *skb, struct nlmsghdr *nlh)
        }
 
        err = rtnl_net_fill(msg, NETLINK_CB(skb).portid, nlh->nlmsg_seq, 0,
-                           RTM_GETNSID, net, peer, -1);
+                           RTM_NEWNSID, net, peer, -1);
        if (err < 0)
                goto err_out;
 
index 358d52a38533b90d8df212de6636ca8e2525730b..8de36824018de4da2369fb02234692c4e0260b27 100644 (file)
@@ -2416,6 +2416,9 @@ void rtmsg_ifinfo(int type, struct net_device *dev, unsigned int change,
 {
        struct sk_buff *skb;
 
+       if (dev->reg_state != NETREG_REGISTERED)
+               return;
+
        skb = rtmsg_ifinfo_build_skb(type, dev, change, flags);
        if (skb)
                rtmsg_ifinfo_send(skb, dev, flags);
@@ -2854,7 +2857,7 @@ static int brport_nla_put_flag(struct sk_buff *skb, u32 flags, u32 mask,
 
 int ndo_dflt_bridge_getlink(struct sk_buff *skb, u32 pid, u32 seq,
                            struct net_device *dev, u16 mode,
-                           u32 flags, u32 mask)
+                           u32 flags, u32 mask, int nlflags)
 {
        struct nlmsghdr *nlh;
        struct ifinfomsg *ifm;
@@ -2863,7 +2866,7 @@ int ndo_dflt_bridge_getlink(struct sk_buff *skb, u32 pid, u32 seq,
        u8 operstate = netif_running(dev) ? dev->operstate : IF_OPER_DOWN;
        struct net_device *br_dev = netdev_master_upper_dev_get(dev);
 
-       nlh = nlmsg_put(skb, pid, seq, RTM_NEWLINK, sizeof(*ifm), NLM_F_MULTI);
+       nlh = nlmsg_put(skb, pid, seq, RTM_NEWLINK, sizeof(*ifm), nlflags);
        if (nlh == NULL)
                return -EMSGSIZE;
 
@@ -2969,7 +2972,8 @@ static int rtnl_bridge_getlink(struct sk_buff *skb, struct netlink_callback *cb)
                if (br_dev && br_dev->netdev_ops->ndo_bridge_getlink) {
                        if (idx >= cb->args[0] &&
                            br_dev->netdev_ops->ndo_bridge_getlink(
-                                   skb, portid, seq, dev, filter_mask) < 0)
+                                   skb, portid, seq, dev, filter_mask,
+                                   NLM_F_MULTI) < 0)
                                break;
                        idx++;
                }
@@ -2977,7 +2981,8 @@ static int rtnl_bridge_getlink(struct sk_buff *skb, struct netlink_callback *cb)
                if (ops->ndo_bridge_getlink) {
                        if (idx >= cb->args[0] &&
                            ops->ndo_bridge_getlink(skb, portid, seq, dev,
-                                                   filter_mask) < 0)
+                                                   filter_mask,
+                                                   NLM_F_MULTI) < 0)
                                break;
                        idx++;
                }
@@ -3018,7 +3023,7 @@ static int rtnl_bridge_notify(struct net_device *dev)
                goto errout;
        }
 
-       err = dev->netdev_ops->ndo_bridge_getlink(skb, 0, 0, dev, 0);
+       err = dev->netdev_ops->ndo_bridge_getlink(skb, 0, 0, dev, 0, 0);
        if (err < 0)
                goto errout;
 
index d1967dab9cc697a4dad45838e1a94c2b5f9cf147..41ec02242ea7c2ff57a6b506b685df22c62f3dcc 100644 (file)
@@ -280,13 +280,14 @@ nodata:
 EXPORT_SYMBOL(__alloc_skb);
 
 /**
- * build_skb - build a network buffer
+ * __build_skb - build a network buffer
  * @data: data buffer provided by caller
- * @frag_size: size of fragment, or 0 if head was kmalloced
+ * @frag_size: size of data, or 0 if head was kmalloced
  *
  * Allocate a new &sk_buff. Caller provides space holding head and
  * skb_shared_info. @data must have been allocated by kmalloc() only if
- * @frag_size is 0, otherwise data should come from the page allocator.
+ * @frag_size is 0, otherwise data should come from the page allocator
+ *  or vmalloc()
  * The return is the new skb buffer.
  * On a failure the return is %NULL, and @data is not freed.
  * Notes :
@@ -297,7 +298,7 @@ EXPORT_SYMBOL(__alloc_skb);
  *  before giving packet to stack.
  *  RX rings only contains data buffers, not full skbs.
  */
-struct sk_buff *build_skb(void *data, unsigned int frag_size)
+struct sk_buff *__build_skb(void *data, unsigned int frag_size)
 {
        struct skb_shared_info *shinfo;
        struct sk_buff *skb;
@@ -311,7 +312,6 @@ struct sk_buff *build_skb(void *data, unsigned int frag_size)
 
        memset(skb, 0, offsetof(struct sk_buff, tail));
        skb->truesize = SKB_TRUESIZE(size);
-       skb->head_frag = frag_size != 0;
        atomic_set(&skb->users, 1);
        skb->head = data;
        skb->data = data;
@@ -328,6 +328,23 @@ struct sk_buff *build_skb(void *data, unsigned int frag_size)
 
        return skb;
 }
+
+/* build_skb() is wrapper over __build_skb(), that specifically
+ * takes care of skb->head and skb->pfmemalloc
+ * This means that if @frag_size is not zero, then @data must be backed
+ * by a page fragment, not kmalloc() or vmalloc()
+ */
+struct sk_buff *build_skb(void *data, unsigned int frag_size)
+{
+       struct sk_buff *skb = __build_skb(data, frag_size);
+
+       if (skb && frag_size) {
+               skb->head_frag = 1;
+               if (virt_to_head_page(data)->pfmemalloc)
+                       skb->pfmemalloc = 1;
+       }
+       return skb;
+}
 EXPORT_SYMBOL(build_skb);
 
 struct netdev_alloc_cache {
@@ -348,7 +365,8 @@ static struct page *__page_frag_refill(struct netdev_alloc_cache *nc,
        gfp_t gfp = gfp_mask;
 
        if (order) {
-               gfp_mask |= __GFP_COMP | __GFP_NOWARN | __GFP_NORETRY;
+               gfp_mask |= __GFP_COMP | __GFP_NOWARN | __GFP_NORETRY |
+                           __GFP_NOMEMALLOC;
                page = alloc_pages_node(NUMA_NO_NODE, gfp_mask, order);
                nc->frag.size = PAGE_SIZE << (page ? order : 0);
        }
@@ -4380,7 +4398,7 @@ struct sk_buff *alloc_skb_with_frags(unsigned long header_len,
 
                while (order) {
                        if (npages >= 1 << order) {
-                               page = alloc_pages(gfp_mask |
+                               page = alloc_pages((gfp_mask & ~__GFP_WAIT) |
                                                   __GFP_COMP |
                                                   __GFP_NOWARN |
                                                   __GFP_NORETRY,
index e891bcf325ca759c9b7498f29ec76aa946198d5e..dc30dc5bb1b892923397fee073d42e9e5ef53a7e 100644 (file)
@@ -354,15 +354,12 @@ void sk_clear_memalloc(struct sock *sk)
 
        /*
         * SOCK_MEMALLOC is allowed to ignore rmem limits to ensure forward
-        * progress of swapping. However, if SOCK_MEMALLOC is cleared while
-        * it has rmem allocations there is a risk that the user of the
-        * socket cannot make forward progress due to exceeding the rmem
-        * limits. By rights, sk_clear_memalloc() should only be called
-        * on sockets being torn down but warn and reset the accounting if
-        * that assumption breaks.
+        * progress of swapping. SOCK_MEMALLOC may be cleared while
+        * it has rmem allocations due to the last swapfile being deactivated
+        * but there is a risk that the socket is unusable due to exceeding
+        * the rmem limits. Reclaim the reserves and obey rmem limits again.
         */
-       if (WARN_ON(sk->sk_forward_alloc))
-               sk_mem_reclaim(sk);
+       sk_mem_reclaim(sk);
 }
 EXPORT_SYMBOL_GPL(sk_clear_memalloc);
 
@@ -1474,8 +1471,8 @@ void sk_release_kernel(struct sock *sk)
                return;
 
        sock_hold(sk);
-       sock_net_set(sk, get_net(&init_net));
        sock_release(sk->sk_socket);
+       sock_net_set(sk, get_net(&init_net));
        sock_put(sk);
 }
 EXPORT_SYMBOL(sk_release_kernel);
@@ -1883,7 +1880,7 @@ bool skb_page_frag_refill(unsigned int sz, struct page_frag *pfrag, gfp_t gfp)
 
        pfrag->offset = 0;
        if (SKB_FRAG_PAGE_ORDER) {
-               pfrag->page = alloc_pages(gfp | __GFP_COMP |
+               pfrag->page = alloc_pages((gfp & ~__GFP_WAIT) | __GFP_COMP |
                                          __GFP_NOWARN | __GFP_NORETRY,
                                          SKB_FRAG_PAGE_ORDER);
                if (likely(pfrag->page)) {
index 2b4f21d34df6819c134b590d8ddeecffe668aaf6..ccf4c5629b3c8672f348a3ca29b0b6bd46cc23e8 100644 (file)
@@ -453,7 +453,8 @@ static struct sock *dccp_v4_hnd_req(struct sock *sk, struct sk_buff *skb)
                                                       iph->saddr, iph->daddr);
        if (req) {
                nsk = dccp_check_req(sk, skb, req);
-               reqsk_put(req);
+               if (!nsk)
+                       reqsk_put(req);
                return nsk;
        }
        nsk = inet_lookup_established(sock_net(sk), &dccp_hashinfo,
index 9d0551092c6cd73f3cfa30c89130bac69d693118..5165571f397aa6d40da19d36287ca8339852ab54 100644 (file)
@@ -301,7 +301,8 @@ static struct sock *dccp_v6_hnd_req(struct sock *sk,struct sk_buff *skb)
                                   &iph->daddr, inet6_iif(skb));
        if (req) {
                nsk = dccp_check_req(sk, skb, req);
-               reqsk_put(req);
+               if (!nsk)
+                       reqsk_put(req);
                return nsk;
        }
        nsk = __inet6_lookup_established(sock_net(sk), &dccp_hashinfo,
index 5f566663e47f3faa8025a998b2d8ae976db58860..30addee2dd037f9686c5585243e503632dcdd21a 100644 (file)
@@ -186,8 +186,7 @@ struct sock *dccp_check_req(struct sock *sk, struct sk_buff *skb,
        if (child == NULL)
                goto listen_overflow;
 
-       inet_csk_reqsk_queue_unlink(sk, req);
-       inet_csk_reqsk_queue_removed(sk, req);
+       inet_csk_reqsk_queue_drop(sk, req);
        inet_csk_reqsk_queue_add(sk, req, child);
 out:
        return child;
index 079a224471e7e20641079e9f54f82743c0172165..392e29a0227dbf4aa4870d73c5ef333db528b675 100644 (file)
@@ -359,7 +359,7 @@ dsa_switch_setup(struct dsa_switch_tree *dst, int index,
         */
        ds = kzalloc(sizeof(*ds) + drv->priv_size, GFP_KERNEL);
        if (ds == NULL)
-               return NULL;
+               return ERR_PTR(-ENOMEM);
 
        ds->dst = dst;
        ds->index = index;
@@ -370,7 +370,7 @@ dsa_switch_setup(struct dsa_switch_tree *dst, int index,
 
        ret = dsa_switch_setup_one(ds, parent);
        if (ret)
-               return NULL;
+               return ERR_PTR(ret);
 
        return ds;
 }
@@ -633,7 +633,7 @@ static int dsa_of_probe(struct device *dev)
                if (cd->sw_addr > PHY_MAX_ADDR)
                        continue;
 
-               if (!of_property_read_u32(np, "eeprom-length", &eeprom_len))
+               if (!of_property_read_u32(child, "eeprom-length", &eeprom_len))
                        cd->eeprom_len = eeprom_len;
 
                for_each_available_child_of_node(child, port) {
index 05dab2957cd49e9be95c6bbe1cef1eb9f35ab8a2..4adfd4d5471b83c254313a887687cb497ce7ad3a 100644 (file)
@@ -3,7 +3,9 @@ obj-$(CONFIG_IEEE802154_SOCKET) += ieee802154_socket.o
 obj-y += 6lowpan/
 
 ieee802154-y := netlink.o nl-mac.o nl-phy.o nl_policy.o core.o \
-                header_ops.o sysfs.o nl802154.o
+                header_ops.o sysfs.o nl802154.o trace.o
 ieee802154_socket-y := socket.o
 
+CFLAGS_trace.o := -I$(src)
+
 ccflags-y += -D__CHECK_ENDIAN__
index 1b9d25f6e898616d7972950692bcd1eab71ddb26..346c6665d25e59bf372bacedc5a2ae6df30d227c 100644 (file)
@@ -175,6 +175,7 @@ int ieee802154_add_iface(struct sk_buff *skb, struct genl_info *info)
        int rc = -ENOBUFS;
        struct net_device *dev;
        int type = __IEEE802154_DEV_INVALID;
+       unsigned char name_assign_type;
 
        pr_debug("%s\n", __func__);
 
@@ -190,8 +191,10 @@ int ieee802154_add_iface(struct sk_buff *skb, struct genl_info *info)
                if (devname[nla_len(info->attrs[IEEE802154_ATTR_DEV_NAME]) - 1]
                                != '\0')
                        return -EINVAL; /* phy name should be null-terminated */
+               name_assign_type = NET_NAME_USER;
        } else  {
                devname = "wpan%d";
+               name_assign_type = NET_NAME_ENUM;
        }
 
        if (strlen(devname) >= IFNAMSIZ)
@@ -221,7 +224,7 @@ int ieee802154_add_iface(struct sk_buff *skb, struct genl_info *info)
        }
 
        dev = rdev_add_virtual_intf_deprecated(wpan_phy_to_rdev(phy), devname,
-                                              type);
+                                              name_assign_type, type);
        if (IS_ERR(dev)) {
                rc = PTR_ERR(dev);
                goto nla_put_failure;
index a4daf91b8d0a395d6964dad93cf292e566dee22c..f3c12f6a4a392ad301e5a79fcabb2bb9f8521431 100644 (file)
@@ -589,7 +589,7 @@ static int nl802154_new_interface(struct sk_buff *skb, struct genl_info *info)
 
        return rdev_add_virtual_intf(rdev,
                                     nla_data(info->attrs[NL802154_ATTR_IFNAME]),
-                                    type, extended_addr);
+                                    NET_NAME_USER, type, extended_addr);
 }
 
 static int nl802154_del_interface(struct sk_buff *skb, struct genl_info *info)
index 7c46732fad2bdd3f6778fce066cb89330b5aeaa3..7b5a9dd94fe5a2b55d01103aa529261141ece521 100644 (file)
@@ -4,13 +4,16 @@
 #include <net/cfg802154.h>
 
 #include "core.h"
+#include "trace.h"
 
 static inline struct net_device *
 rdev_add_virtual_intf_deprecated(struct cfg802154_registered_device *rdev,
-                                const char *name, int type)
+                                const char *name,
+                                unsigned char name_assign_type,
+                                int type)
 {
        return rdev->ops->add_virtual_intf_deprecated(&rdev->wpan_phy, name,
-                                                     type);
+                                                     name_assign_type, type);
 }
 
 static inline void
@@ -22,75 +25,131 @@ rdev_del_virtual_intf_deprecated(struct cfg802154_registered_device *rdev,
 
 static inline int
 rdev_add_virtual_intf(struct cfg802154_registered_device *rdev, char *name,
+                     unsigned char name_assign_type,
                      enum nl802154_iftype type, __le64 extended_addr)
 {
-       return rdev->ops->add_virtual_intf(&rdev->wpan_phy, name, type,
+       int ret;
+
+       trace_802154_rdev_add_virtual_intf(&rdev->wpan_phy, name, type,
                                           extended_addr);
+       ret = rdev->ops->add_virtual_intf(&rdev->wpan_phy, name,
+                                         name_assign_type, type,
+                                         extended_addr);
+       trace_802154_rdev_return_int(&rdev->wpan_phy, ret);
+       return ret;
 }
 
 static inline int
 rdev_del_virtual_intf(struct cfg802154_registered_device *rdev,
                      struct wpan_dev *wpan_dev)
 {
-       return rdev->ops->del_virtual_intf(&rdev->wpan_phy, wpan_dev);
+       int ret;
+
+       trace_802154_rdev_del_virtual_intf(&rdev->wpan_phy, wpan_dev);
+       ret = rdev->ops->del_virtual_intf(&rdev->wpan_phy, wpan_dev);
+       trace_802154_rdev_return_int(&rdev->wpan_phy, ret);
+       return ret;
 }
 
 static inline int
 rdev_set_channel(struct cfg802154_registered_device *rdev, u8 page, u8 channel)
 {
-       return rdev->ops->set_channel(&rdev->wpan_phy, page, channel);
+       int ret;
+
+       trace_802154_rdev_set_channel(&rdev->wpan_phy, page, channel);
+       ret = rdev->ops->set_channel(&rdev->wpan_phy, page, channel);
+       trace_802154_rdev_return_int(&rdev->wpan_phy, ret);
+       return ret;
 }
 
 static inline int
 rdev_set_cca_mode(struct cfg802154_registered_device *rdev,
                  const struct wpan_phy_cca *cca)
 {
-       return rdev->ops->set_cca_mode(&rdev->wpan_phy, cca);
+       int ret;
+
+       trace_802154_rdev_set_cca_mode(&rdev->wpan_phy, cca);
+       ret = rdev->ops->set_cca_mode(&rdev->wpan_phy, cca);
+       trace_802154_rdev_return_int(&rdev->wpan_phy, ret);
+       return ret;
 }
 
 static inline int
 rdev_set_pan_id(struct cfg802154_registered_device *rdev,
                struct wpan_dev *wpan_dev, __le16 pan_id)
 {
-       return rdev->ops->set_pan_id(&rdev->wpan_phy, wpan_dev, pan_id);
+       int ret;
+
+       trace_802154_rdev_set_pan_id(&rdev->wpan_phy, wpan_dev, pan_id);
+       ret = rdev->ops->set_pan_id(&rdev->wpan_phy, wpan_dev, pan_id);
+       trace_802154_rdev_return_int(&rdev->wpan_phy, ret);
+       return ret;
 }
 
 static inline int
 rdev_set_short_addr(struct cfg802154_registered_device *rdev,
                    struct wpan_dev *wpan_dev, __le16 short_addr)
 {
-       return rdev->ops->set_short_addr(&rdev->wpan_phy, wpan_dev, short_addr);
+       int ret;
+
+       trace_802154_rdev_set_short_addr(&rdev->wpan_phy, wpan_dev, short_addr);
+       ret = rdev->ops->set_short_addr(&rdev->wpan_phy, wpan_dev, short_addr);
+       trace_802154_rdev_return_int(&rdev->wpan_phy, ret);
+       return ret;
 }
 
 static inline int
 rdev_set_backoff_exponent(struct cfg802154_registered_device *rdev,
                          struct wpan_dev *wpan_dev, u8 min_be, u8 max_be)
 {
-       return rdev->ops->set_backoff_exponent(&rdev->wpan_phy, wpan_dev,
+       int ret;
+
+       trace_802154_rdev_set_backoff_exponent(&rdev->wpan_phy, wpan_dev,
                                               min_be, max_be);
+       ret = rdev->ops->set_backoff_exponent(&rdev->wpan_phy, wpan_dev,
+                                             min_be, max_be);
+       trace_802154_rdev_return_int(&rdev->wpan_phy, ret);
+       return ret;
 }
 
 static inline int
 rdev_set_max_csma_backoffs(struct cfg802154_registered_device *rdev,
                           struct wpan_dev *wpan_dev, u8 max_csma_backoffs)
 {
-       return rdev->ops->set_max_csma_backoffs(&rdev->wpan_phy, wpan_dev,
-                                               max_csma_backoffs);
+       int ret;
+
+       trace_802154_rdev_set_csma_backoffs(&rdev->wpan_phy, wpan_dev,
+                                           max_csma_backoffs);
+       ret = rdev->ops->set_max_csma_backoffs(&rdev->wpan_phy, wpan_dev,
+                                              max_csma_backoffs);
+       trace_802154_rdev_return_int(&rdev->wpan_phy, ret);
+       return ret;
 }
 
 static inline int
 rdev_set_max_frame_retries(struct cfg802154_registered_device *rdev,
                           struct wpan_dev *wpan_dev, s8 max_frame_retries)
 {
-       return rdev->ops->set_max_frame_retries(&rdev->wpan_phy, wpan_dev,
+       int ret;
+
+       trace_802154_rdev_set_max_frame_retries(&rdev->wpan_phy, wpan_dev,
                                                max_frame_retries);
+       ret = rdev->ops->set_max_frame_retries(&rdev->wpan_phy, wpan_dev,
+                                              max_frame_retries);
+       trace_802154_rdev_return_int(&rdev->wpan_phy, ret);
+       return ret;
 }
 
 static inline int
 rdev_set_lbt_mode(struct cfg802154_registered_device *rdev,
                  struct wpan_dev *wpan_dev, bool mode)
 {
-       return rdev->ops->set_lbt_mode(&rdev->wpan_phy, wpan_dev, mode);
+       int ret;
+
+       trace_802154_rdev_set_lbt_mode(&rdev->wpan_phy, wpan_dev, mode);
+       ret = rdev->ops->set_lbt_mode(&rdev->wpan_phy, wpan_dev, mode);
+       trace_802154_rdev_return_int(&rdev->wpan_phy, ret);
+       return ret;
 }
 
 #endif /* __CFG802154_RDEV_OPS */
diff --git a/net/ieee802154/trace.c b/net/ieee802154/trace.c
new file mode 100644 (file)
index 0000000..95f997f
--- /dev/null
@@ -0,0 +1,7 @@
+#include <linux/module.h>
+
+#ifndef __CHECKER__
+#define CREATE_TRACE_POINTS
+#include "trace.h"
+
+#endif
diff --git a/net/ieee802154/trace.h b/net/ieee802154/trace.h
new file mode 100644 (file)
index 0000000..5ac25eb
--- /dev/null
@@ -0,0 +1,247 @@
+/* Based on net/wireless/tracing.h */
+
+#undef TRACE_SYSTEM
+#define TRACE_SYSTEM cfg802154
+
+#if !defined(__RDEV_CFG802154_OPS_TRACE) || defined(TRACE_HEADER_MULTI_READ)
+#define __RDEV_CFG802154_OPS_TRACE
+
+#include <linux/tracepoint.h>
+
+#include <net/cfg802154.h>
+
+#define MAXNAME                32
+#define WPAN_PHY_ENTRY __array(char, wpan_phy_name, MAXNAME)
+#define WPAN_PHY_ASSIGN        strlcpy(__entry->wpan_phy_name,  \
+                               wpan_phy_name(wpan_phy), \
+                               MAXNAME)
+#define WPAN_PHY_PR_FMT        "%s"
+#define WPAN_PHY_PR_ARG        __entry->wpan_phy_name
+
+#define WPAN_DEV_ENTRY __field(u32, identifier)
+#define WPAN_DEV_ASSIGN        (__entry->identifier) = (!IS_ERR_OR_NULL(wpan_dev) \
+                                        ? wpan_dev->identifier : 0)
+#define WPAN_DEV_PR_FMT        "wpan_dev(%u)"
+#define WPAN_DEV_PR_ARG        (__entry->identifier)
+
+#define WPAN_CCA_ENTRY __field(enum nl802154_cca_modes, cca_mode) \
+                       __field(enum nl802154_cca_opts, cca_opt)
+#define WPAN_CCA_ASSIGN \
+       do {                                     \
+               (__entry->cca_mode) = cca->mode; \
+               (__entry->cca_opt) = cca->opt;   \
+       } while (0)
+#define WPAN_CCA_PR_FMT        "cca_mode: %d, cca_opt: %d"
+#define WPAN_CCA_PR_ARG __entry->cca_mode, __entry->cca_opt
+
+#define BOOL_TO_STR(bo) (bo) ? "true" : "false"
+
+/*************************************************************
+ *                     rdev->ops traces                     *
+ *************************************************************/
+
+TRACE_EVENT(802154_rdev_add_virtual_intf,
+       TP_PROTO(struct wpan_phy *wpan_phy, char *name,
+                enum nl802154_iftype type, __le64 extended_addr),
+       TP_ARGS(wpan_phy, name, type, extended_addr),
+       TP_STRUCT__entry(
+               WPAN_PHY_ENTRY
+               __string(vir_intf_name, name ? name : "<noname>")
+               __field(enum nl802154_iftype, type)
+               __field(__le64, extended_addr)
+       ),
+       TP_fast_assign(
+               WPAN_PHY_ASSIGN;
+               __assign_str(vir_intf_name, name ? name : "<noname>");
+               __entry->type = type;
+               __entry->extended_addr = extended_addr;
+       ),
+       TP_printk(WPAN_PHY_PR_FMT ", virtual intf name: %s, type: %d, ea %llx",
+                 WPAN_PHY_PR_ARG, __get_str(vir_intf_name), __entry->type,
+                 __le64_to_cpu(__entry->extended_addr))
+);
+
+TRACE_EVENT(802154_rdev_del_virtual_intf,
+       TP_PROTO(struct wpan_phy *wpan_phy, struct wpan_dev *wpan_dev),
+       TP_ARGS(wpan_phy, wpan_dev),
+       TP_STRUCT__entry(
+               WPAN_PHY_ENTRY
+               WPAN_DEV_ENTRY
+       ),
+       TP_fast_assign(
+               WPAN_PHY_ASSIGN;
+               WPAN_DEV_ASSIGN;
+       ),
+       TP_printk(WPAN_PHY_PR_FMT ", " WPAN_DEV_PR_FMT, WPAN_PHY_PR_ARG,
+                 WPAN_DEV_PR_ARG)
+);
+
+TRACE_EVENT(802154_rdev_set_channel,
+       TP_PROTO(struct wpan_phy *wpan_phy, u8 page, u8 channel),
+       TP_ARGS(wpan_phy, page, channel),
+       TP_STRUCT__entry(
+               WPAN_PHY_ENTRY
+               __field(u8, page)
+               __field(u8, channel)
+       ),
+       TP_fast_assign(
+               WPAN_PHY_ASSIGN;
+               __entry->page = page;
+               __entry->channel = channel;
+       ),
+       TP_printk(WPAN_PHY_PR_FMT ", page: %d, channel: %d", WPAN_PHY_PR_ARG,
+                 __entry->page, __entry->channel)
+);
+
+TRACE_EVENT(802154_rdev_set_cca_mode,
+       TP_PROTO(struct wpan_phy *wpan_phy, const struct wpan_phy_cca *cca),
+       TP_ARGS(wpan_phy, cca),
+       TP_STRUCT__entry(
+               WPAN_PHY_ENTRY
+               WPAN_CCA_ENTRY
+       ),
+       TP_fast_assign(
+               WPAN_PHY_ASSIGN;
+               WPAN_CCA_ASSIGN;
+       ),
+       TP_printk(WPAN_PHY_PR_FMT ", " WPAN_CCA_PR_FMT, WPAN_PHY_PR_ARG,
+                 WPAN_CCA_PR_ARG)
+);
+
+DECLARE_EVENT_CLASS(802154_le16_template,
+       TP_PROTO(struct wpan_phy *wpan_phy, struct wpan_dev *wpan_dev,
+                __le16 le16arg),
+       TP_ARGS(wpan_phy, wpan_dev, le16arg),
+       TP_STRUCT__entry(
+               WPAN_PHY_ENTRY
+               WPAN_DEV_ENTRY
+               __field(__le16, le16arg)
+       ),
+       TP_fast_assign(
+               WPAN_PHY_ASSIGN;
+               WPAN_DEV_ASSIGN;
+               __entry->le16arg = le16arg;
+       ),
+       TP_printk(WPAN_PHY_PR_FMT ", " WPAN_DEV_PR_FMT ", pan id: 0x%04x",
+                 WPAN_PHY_PR_ARG, WPAN_DEV_PR_ARG,
+                 __le16_to_cpu(__entry->le16arg))
+);
+
+DEFINE_EVENT(802154_le16_template, 802154_rdev_set_pan_id,
+       TP_PROTO(struct wpan_phy *wpan_phy, struct wpan_dev *wpan_dev,
+                __le16 le16arg),
+       TP_ARGS(wpan_phy, wpan_dev, le16arg)
+);
+
+DEFINE_EVENT_PRINT(802154_le16_template, 802154_rdev_set_short_addr,
+       TP_PROTO(struct wpan_phy *wpan_phy, struct wpan_dev *wpan_dev,
+                __le16 le16arg),
+       TP_ARGS(wpan_phy, wpan_dev, le16arg),
+       TP_printk(WPAN_PHY_PR_FMT ", " WPAN_DEV_PR_FMT ", sa: 0x%04x",
+                 WPAN_PHY_PR_ARG, WPAN_DEV_PR_ARG,
+                 __le16_to_cpu(__entry->le16arg))
+);
+
+TRACE_EVENT(802154_rdev_set_backoff_exponent,
+       TP_PROTO(struct wpan_phy *wpan_phy, struct wpan_dev *wpan_dev,
+                u8 min_be, u8 max_be),
+       TP_ARGS(wpan_phy, wpan_dev, min_be, max_be),
+       TP_STRUCT__entry(
+               WPAN_PHY_ENTRY
+               WPAN_DEV_ENTRY
+               __field(u8, min_be)
+               __field(u8, max_be)
+       ),
+       TP_fast_assign(
+               WPAN_PHY_ASSIGN;
+               WPAN_DEV_ASSIGN;
+               __entry->min_be = min_be;
+               __entry->max_be = max_be;
+       ),
+
+       TP_printk(WPAN_PHY_PR_FMT ", " WPAN_DEV_PR_FMT
+                 ", min be: %d, max_be: %d", WPAN_PHY_PR_ARG,
+                 WPAN_DEV_PR_ARG, __entry->min_be, __entry->max_be)
+);
+
+TRACE_EVENT(802154_rdev_set_csma_backoffs,
+       TP_PROTO(struct wpan_phy *wpan_phy, struct wpan_dev *wpan_dev,
+                u8 max_csma_backoffs),
+       TP_ARGS(wpan_phy, wpan_dev, max_csma_backoffs),
+       TP_STRUCT__entry(
+               WPAN_PHY_ENTRY
+               WPAN_DEV_ENTRY
+               __field(u8, max_csma_backoffs)
+       ),
+       TP_fast_assign(
+               WPAN_PHY_ASSIGN;
+               WPAN_DEV_ASSIGN;
+               __entry->max_csma_backoffs = max_csma_backoffs;
+       ),
+
+       TP_printk(WPAN_PHY_PR_FMT ", " WPAN_DEV_PR_FMT
+                 ", max csma backoffs: %d", WPAN_PHY_PR_ARG,
+                 WPAN_DEV_PR_ARG, __entry->max_csma_backoffs)
+);
+
+TRACE_EVENT(802154_rdev_set_max_frame_retries,
+       TP_PROTO(struct wpan_phy *wpan_phy, struct wpan_dev *wpan_dev,
+                s8 max_frame_retries),
+       TP_ARGS(wpan_phy, wpan_dev, max_frame_retries),
+       TP_STRUCT__entry(
+               WPAN_PHY_ENTRY
+               WPAN_DEV_ENTRY
+               __field(s8, max_frame_retries)
+       ),
+       TP_fast_assign(
+               WPAN_PHY_ASSIGN;
+               WPAN_DEV_ASSIGN;
+               __entry->max_frame_retries = max_frame_retries;
+       ),
+
+       TP_printk(WPAN_PHY_PR_FMT ", " WPAN_DEV_PR_FMT
+                 ", max frame retries: %d", WPAN_PHY_PR_ARG,
+                 WPAN_DEV_PR_ARG, __entry->max_frame_retries)
+);
+
+TRACE_EVENT(802154_rdev_set_lbt_mode,
+       TP_PROTO(struct wpan_phy *wpan_phy, struct wpan_dev *wpan_dev,
+                bool mode),
+       TP_ARGS(wpan_phy, wpan_dev, mode),
+       TP_STRUCT__entry(
+               WPAN_PHY_ENTRY
+               WPAN_DEV_ENTRY
+               __field(bool, mode)
+       ),
+       TP_fast_assign(
+               WPAN_PHY_ASSIGN;
+               WPAN_DEV_ASSIGN;
+               __entry->mode = mode;
+       ),
+       TP_printk(WPAN_PHY_PR_FMT ", " WPAN_DEV_PR_FMT
+               ", lbt mode: %s", WPAN_PHY_PR_ARG,
+               WPAN_DEV_PR_ARG, BOOL_TO_STR(__entry->mode))
+);
+
+TRACE_EVENT(802154_rdev_return_int,
+       TP_PROTO(struct wpan_phy *wpan_phy, int ret),
+       TP_ARGS(wpan_phy, ret),
+       TP_STRUCT__entry(
+               WPAN_PHY_ENTRY
+               __field(int, ret)
+       ),
+       TP_fast_assign(
+               WPAN_PHY_ASSIGN;
+               __entry->ret = ret;
+       ),
+       TP_printk(WPAN_PHY_PR_FMT ", returned: %d", WPAN_PHY_PR_ARG,
+                 __entry->ret)
+);
+
+#endif /* !__RDEV_CFG802154_OPS_TRACE || TRACE_HEADER_MULTI_READ */
+
+#undef TRACE_INCLUDE_PATH
+#define TRACE_INCLUDE_PATH .
+#undef TRACE_INCLUDE_FILE
+#define TRACE_INCLUDE_FILE trace
+#include <trace/define_trace.h>
index 421a80b09b62358dad5a0fa35d99db73d28472a7..30b544f025acc09aaad99d9adc1e5dbc1227d307 100644 (file)
@@ -256,7 +256,8 @@ static int esp_output(struct xfrm_state *x, struct sk_buff *skb)
        aead_givcrypt_set_crypt(req, sg, sg, clen, iv);
        aead_givcrypt_set_assoc(req, asg, assoclen);
        aead_givcrypt_set_giv(req, esph->enc_data,
-                             XFRM_SKB_CB(skb)->seq.output.low);
+                             XFRM_SKB_CB(skb)->seq.output.low +
+                             ((u64)XFRM_SKB_CB(skb)->seq.output.hi << 32));
 
        ESP_SKB_CB(skb)->tmp = tmp;
        err = crypto_aead_givencrypt(req);
index e13fcc602da20ee44dfd505ab1115bbcc0e13375..09b62e17dd8cba4b1041de5f208180d278010604 100644 (file)
@@ -1164,6 +1164,7 @@ int fib_table_insert(struct fib_table *tb, struct fib_config *cfg)
                        state = fa->fa_state;
                        new_fa->fa_state = state & ~FA_S_ACCESSED;
                        new_fa->fa_slen = fa->fa_slen;
+                       new_fa->tb_id = tb->tb_id;
 
                        err = netdev_switch_fib_ipv4_add(key, plen, fi,
                                                         new_fa->fa_tos,
@@ -1764,7 +1765,7 @@ void fib_table_flush_external(struct fib_table *tb)
                        /* record local slen */
                        slen = fa->fa_slen;
 
-                       if (!fi || !(fi->fib_flags & RTNH_F_EXTERNAL))
+                       if (!fi || !(fi->fib_flags & RTNH_F_OFFLOAD))
                                continue;
 
                        netdev_switch_fib_ipv4_del(n->key,
index 5c3dd6267ed3557f2f139f83002fd7b1feaab237..8976ca423a074447f0d857973ab9ea3bc6bbca7c 100644 (file)
@@ -564,6 +564,40 @@ int inet_rtx_syn_ack(struct sock *parent, struct request_sock *req)
 }
 EXPORT_SYMBOL(inet_rtx_syn_ack);
 
+/* return true if req was found in the syn_table[] */
+static bool reqsk_queue_unlink(struct request_sock_queue *queue,
+                              struct request_sock *req)
+{
+       struct listen_sock *lopt = queue->listen_opt;
+       struct request_sock **prev;
+       bool found = false;
+
+       spin_lock(&queue->syn_wait_lock);
+
+       for (prev = &lopt->syn_table[req->rsk_hash]; *prev != NULL;
+            prev = &(*prev)->dl_next) {
+               if (*prev == req) {
+                       *prev = req->dl_next;
+                       found = true;
+                       break;
+               }
+       }
+
+       spin_unlock(&queue->syn_wait_lock);
+       if (del_timer(&req->rsk_timer))
+               reqsk_put(req);
+       return found;
+}
+
+void inet_csk_reqsk_queue_drop(struct sock *sk, struct request_sock *req)
+{
+       if (reqsk_queue_unlink(&inet_csk(sk)->icsk_accept_queue, req)) {
+               reqsk_queue_removed(&inet_csk(sk)->icsk_accept_queue, req);
+               reqsk_put(req);
+       }
+}
+EXPORT_SYMBOL(inet_csk_reqsk_queue_drop);
+
 static void reqsk_timer_handler(unsigned long data)
 {
        struct request_sock *req = (struct request_sock *)data;
index bb77ebdae3b31bcacbfc4fdb350d4282e400e2e8..4d32262c7502cc22d13a9f3bd47ca72e8ee355e8 100644 (file)
@@ -224,14 +224,16 @@ int inet_sk_diag_fill(struct sock *sk, struct inet_connection_sock *icsk,
        handler->idiag_get_info(sk, r, info);
 
        if (sk->sk_state < TCP_TIME_WAIT) {
-               int err = 0;
+               union tcp_cc_info info;
+               size_t sz = 0;
+               int attr;
 
                rcu_read_lock();
                ca_ops = READ_ONCE(icsk->icsk_ca_ops);
                if (ca_ops && ca_ops->get_info)
-                       err = ca_ops->get_info(sk, ext, skb);
+                       sz = ca_ops->get_info(sk, ext, &attr, &info);
                rcu_read_unlock();
-               if (err < 0)
+               if (sz && nla_put(skb, attr, sz, &info) < 0)
                        goto errout;
        }
 
index 9f7269f3c54af2ecbc74db4ec2c0f71d5184dc1c..0c152087ca15dd3f97548d3c7123d42bd6626f0e 100644 (file)
@@ -65,7 +65,6 @@ static int vti_input(struct sk_buff *skb, int nexthdr, __be32 spi,
                        goto drop;
 
                XFRM_TUNNEL_SKB_CB(skb)->tunnel.ip4 = tunnel;
-               skb->mark = be32_to_cpu(tunnel->parms.i_key);
 
                return xfrm_input(skb, nexthdr, spi, encap_type);
        }
@@ -91,6 +90,8 @@ static int vti_rcv_cb(struct sk_buff *skb, int err)
        struct pcpu_sw_netstats *tstats;
        struct xfrm_state *x;
        struct ip_tunnel *tunnel = XFRM_TUNNEL_SKB_CB(skb)->tunnel.ip4;
+       u32 orig_mark = skb->mark;
+       int ret;
 
        if (!tunnel)
                return 1;
@@ -107,7 +108,11 @@ static int vti_rcv_cb(struct sk_buff *skb, int err)
        x = xfrm_input_state(skb);
        family = x->inner_mode->afinfo->family;
 
-       if (!xfrm_policy_check(NULL, XFRM_POLICY_IN, skb, family))
+       skb->mark = be32_to_cpu(tunnel->parms.i_key);
+       ret = xfrm_policy_check(NULL, XFRM_POLICY_IN, skb, family);
+       skb->mark = orig_mark;
+
+       if (!ret)
                return -EPERM;
 
        skb_scrub_packet(skb, !net_eq(tunnel->net, dev_net(skb->dev)));
@@ -216,8 +221,6 @@ static netdev_tx_t vti_tunnel_xmit(struct sk_buff *skb, struct net_device *dev)
 
        memset(&fl, 0, sizeof(fl));
 
-       skb->mark = be32_to_cpu(tunnel->parms.o_key);
-
        switch (skb->protocol) {
        case htons(ETH_P_IP):
                xfrm_decode_session(skb, &fl, AF_INET);
@@ -233,6 +236,9 @@ static netdev_tx_t vti_tunnel_xmit(struct sk_buff *skb, struct net_device *dev)
                return NETDEV_TX_OK;
        }
 
+       /* override mark with tunnel output key */
+       fl.flowi_mark = be32_to_cpu(tunnel->parms.o_key);
+
        return vti_xmit(skb, dev, &fl);
 }
 
index 13bfe84bf3ca5a6aafe6982b8782958b0cce529f..a61200754f4ba29301855ae67055dd11d004780b 100644 (file)
@@ -1075,6 +1075,9 @@ static int do_replace(struct net *net, const void __user *user,
        /* overflow check */
        if (tmp.num_counters >= INT_MAX / sizeof(struct xt_counters))
                return -ENOMEM;
+       if (tmp.num_counters == 0)
+               return -EINVAL;
+
        tmp.name[sizeof(tmp.name)-1] = 0;
 
        newinfo = xt_alloc_table_info(tmp.size);
@@ -1499,6 +1502,9 @@ static int compat_do_replace(struct net *net, void __user *user,
                return -ENOMEM;
        if (tmp.num_counters >= INT_MAX / sizeof(struct xt_counters))
                return -ENOMEM;
+       if (tmp.num_counters == 0)
+               return -EINVAL;
+
        tmp.name[sizeof(tmp.name)-1] = 0;
 
        newinfo = xt_alloc_table_info(tmp.size);
index c69db7fa25ee6376ee3f2bee87d4ce7f09105fb3..2d0e265fef6e7f2c657c54d4db0fd10e010fa68b 100644 (file)
@@ -1262,6 +1262,9 @@ do_replace(struct net *net, const void __user *user, unsigned int len)
        /* overflow check */
        if (tmp.num_counters >= INT_MAX / sizeof(struct xt_counters))
                return -ENOMEM;
+       if (tmp.num_counters == 0)
+               return -EINVAL;
+
        tmp.name[sizeof(tmp.name)-1] = 0;
 
        newinfo = xt_alloc_table_info(tmp.size);
@@ -1809,6 +1812,9 @@ compat_do_replace(struct net *net, void __user *user, unsigned int len)
                return -ENOMEM;
        if (tmp.num_counters >= INT_MAX / sizeof(struct xt_counters))
                return -ENOMEM;
+       if (tmp.num_counters == 0)
+               return -EINVAL;
+
        tmp.name[sizeof(tmp.name)-1] = 0;
 
        newinfo = xt_alloc_table_info(tmp.size);
index a93f260cf24ca0a9d60346dc085eb51afdb43927..05ff44b758dfee1e02996a3726ac63854a96ad16 100644 (file)
@@ -158,6 +158,7 @@ void ping_unhash(struct sock *sk)
        if (sk_hashed(sk)) {
                write_lock_bh(&ping_table.lock);
                hlist_nulls_del(&sk->sk_nulls_node);
+               sk_nulls_node_init(&sk->sk_nulls_node);
                sock_put(sk);
                isk->inet_num = 0;
                isk->inet_sport = 0;
index a78540f28276771e4c8f35024d3ee133c31317ab..f45f2a12f37b25b7270560498423df9488405b1d 100644 (file)
@@ -902,6 +902,10 @@ static int ip_error(struct sk_buff *skb)
        bool send;
        int code;
 
+       /* IP on this device is disabled. */
+       if (!in_dev)
+               goto out;
+
        net = dev_net(rt->dst.dev);
        if (!IN_DEV_FORWARD(in_dev)) {
                switch (rt->dst.error) {
@@ -962,10 +966,7 @@ static void __ip_rt_update_pmtu(struct rtable *rt, struct flowi4 *fl4, u32 mtu)
        if (dst_metric_locked(dst, RTAX_MTU))
                return;
 
-       if (dst->dev->mtu < mtu)
-               return;
-
-       if (rt->rt_pmtu && rt->rt_pmtu < mtu)
+       if (ipv4_mtu(dst) < mtu)
                return;
 
        if (mtu < ip_rt_min_pmtu)
index 8c5cd9efebbcfa877fedb49dda67e3d098ccbbc1..f1377f2a0472ec26e88b92be2346cbc3c8a69b41 100644 (file)
 #include <linux/types.h>
 #include <linux/fcntl.h>
 #include <linux/poll.h>
+#include <linux/inet_diag.h>
 #include <linux/init.h>
 #include <linux/fs.h>
 #include <linux/skbuff.h>
@@ -401,6 +402,7 @@ void tcp_init_sock(struct sock *sk)
        tp->snd_ssthresh = TCP_INFINITE_SSTHRESH;
        tp->snd_cwnd_clamp = ~0;
        tp->mss_cache = TCP_MSS_DEFAULT;
+       u64_stats_init(&tp->syncp);
 
        tp->reordering = sysctl_tcp_reordering;
        tcp_enable_early_retrans(tp);
@@ -2592,11 +2594,12 @@ EXPORT_SYMBOL(compat_tcp_setsockopt);
 #endif
 
 /* Return information about state of tcp endpoint in API format. */
-void tcp_get_info(const struct sock *sk, struct tcp_info *info)
+void tcp_get_info(struct sock *sk, struct tcp_info *info)
 {
        const struct tcp_sock *tp = tcp_sk(sk);
        const struct inet_connection_sock *icsk = inet_csk(sk);
        u32 now = tcp_time_stamp;
+       unsigned int start;
        u32 rate;
 
        memset(info, 0, sizeof(*info));
@@ -2663,6 +2666,12 @@ void tcp_get_info(const struct sock *sk, struct tcp_info *info)
 
        rate = READ_ONCE(sk->sk_max_pacing_rate);
        info->tcpi_max_pacing_rate = rate != ~0U ? rate : ~0ULL;
+
+       do {
+               start = u64_stats_fetch_begin_irq(&tp->syncp);
+               info->tcpi_bytes_acked = tp->bytes_acked;
+               info->tcpi_bytes_received = tp->bytes_received;
+       } while (u64_stats_fetch_retry_irq(&tp->syncp, start));
 }
 EXPORT_SYMBOL_GPL(tcp_get_info);
 
@@ -2734,6 +2743,26 @@ static int do_tcp_getsockopt(struct sock *sk, int level,
                        return -EFAULT;
                return 0;
        }
+       case TCP_CC_INFO: {
+               const struct tcp_congestion_ops *ca_ops;
+               union tcp_cc_info info;
+               size_t sz = 0;
+               int attr;
+
+               if (get_user(len, optlen))
+                       return -EFAULT;
+
+               ca_ops = icsk->icsk_ca_ops;
+               if (ca_ops && ca_ops->get_info)
+                       sz = ca_ops->get_info(sk, ~0U, &attr, &info);
+
+               len = min_t(unsigned int, len, sz);
+               if (put_user(len, optlen))
+                       return -EFAULT;
+               if (copy_to_user(optval, &info, len))
+                       return -EFAULT;
+               return 0;
+       }
        case TCP_QUICKACK:
                val = !icsk->icsk_ack.pingpong;
                break;
index 7a5ae50c80c87add1e46e8255f0837796d2e4947..84be008c945c654b692211b943f83e909a622516 100644 (file)
@@ -187,6 +187,7 @@ static void tcp_reinit_congestion_control(struct sock *sk,
 
        tcp_cleanup_congestion_control(sk);
        icsk->icsk_ca_ops = ca;
+       icsk->icsk_ca_setsockopt = 1;
 
        if (sk->sk_state != TCP_CLOSE && icsk->icsk_ca_ops->init)
                icsk->icsk_ca_ops->init(sk);
@@ -335,8 +336,10 @@ int tcp_set_congestion_control(struct sock *sk, const char *name)
        rcu_read_lock();
        ca = __tcp_ca_find_autoload(name);
        /* No change asking for existing value */
-       if (ca == icsk->icsk_ca_ops)
+       if (ca == icsk->icsk_ca_ops) {
+               icsk->icsk_ca_setsockopt = 1;
                goto out;
+       }
        if (!ca)
                err = -ENOENT;
        else if (!((ca->flags & TCP_CONG_NON_RESTRICTED) ||
index 4376016f7fa5cf84a3114d1551da623442c9c713..4c41c1287197eb4748198ae9532d1f6233aa7f6a 100644 (file)
@@ -277,7 +277,8 @@ static void dctcp_cwnd_event(struct sock *sk, enum tcp_ca_event ev)
        }
 }
 
-static int dctcp_get_info(struct sock *sk, u32 ext, struct sk_buff *skb)
+static size_t dctcp_get_info(struct sock *sk, u32 ext, int *attr,
+                            union tcp_cc_info *info)
 {
        const struct dctcp *ca = inet_csk_ca(sk);
 
@@ -286,18 +287,17 @@ static int dctcp_get_info(struct sock *sk, u32 ext, struct sk_buff *skb)
         */
        if (ext & (1 << (INET_DIAG_DCTCPINFO - 1)) ||
            ext & (1 << (INET_DIAG_VEGASINFO - 1))) {
-               struct tcp_dctcp_info info;
-
-               memset(&info, 0, sizeof(info));
+               memset(info, 0, sizeof(struct tcp_dctcp_info));
                if (inet_csk(sk)->icsk_ca_ops != &dctcp_reno) {
-                       info.dctcp_enabled = 1;
-                       info.dctcp_ce_state = (u16) ca->ce_state;
-                       info.dctcp_alpha = ca->dctcp_alpha;
-                       info.dctcp_ab_ecn = ca->acked_bytes_ecn;
-                       info.dctcp_ab_tot = ca->acked_bytes_total;
+                       info->dctcp.dctcp_enabled = 1;
+                       info->dctcp.dctcp_ce_state = (u16) ca->ce_state;
+                       info->dctcp.dctcp_alpha = ca->dctcp_alpha;
+                       info->dctcp.dctcp_ab_ecn = ca->acked_bytes_ecn;
+                       info->dctcp.dctcp_ab_tot = ca->acked_bytes_total;
                }
 
-               return nla_put(skb, INET_DIAG_DCTCPINFO, sizeof(info), &info);
+               *attr = INET_DIAG_DCTCPINFO;
+               return sizeof(*info);
        }
        return 0;
 }
index e3d87aca6be8fafe02bec5a8f862a88a6fe79d50..46b087a27503acdf1ff55449c8e41269b1497e67 100644 (file)
@@ -206,6 +206,11 @@ static bool tcp_fastopen_create_child(struct sock *sk,
                        skb_set_owner_r(skb2, child);
                        __skb_queue_tail(&child->sk_receive_queue, skb2);
                        tp->syn_data_acked = 1;
+
+                       /* u64_stats_update_begin(&tp->syncp) not needed here,
+                        * as we certainly are not changing upper 32bit value (0)
+                        */
+                       tp->bytes_received = end_seq - TCP_SKB_CB(skb)->seq - 1;
                } else {
                        end_seq = TCP_SKB_CB(skb)->seq + 1;
                }
index 67476f085e4843dacaeb1b4d6b71ecc160c99b97..f71002e4db0ba7fe8dfe35bb2196bbaae751ed59 100644 (file)
@@ -300,24 +300,25 @@ static u32 tcp_illinois_ssthresh(struct sock *sk)
 }
 
 /* Extract info for Tcp socket info provided via netlink. */
-static int tcp_illinois_info(struct sock *sk, u32 ext, struct sk_buff *skb)
+static size_t tcp_illinois_info(struct sock *sk, u32 ext, int *attr,
+                               union tcp_cc_info *info)
 {
        const struct illinois *ca = inet_csk_ca(sk);
 
        if (ext & (1 << (INET_DIAG_VEGASINFO - 1))) {
-               struct tcpvegas_info info = {
-                       .tcpv_enabled = 1,
-                       .tcpv_rttcnt = ca->cnt_rtt,
-                       .tcpv_minrtt = ca->base_rtt,
-               };
+               info->vegas.tcpv_enabled = 1;
+               info->vegas.tcpv_rttcnt = ca->cnt_rtt;
+               info->vegas.tcpv_minrtt = ca->base_rtt;
+               info->vegas.tcpv_rtt = 0;
 
-               if (info.tcpv_rttcnt > 0) {
+               if (info->vegas.tcpv_rttcnt > 0) {
                        u64 t = ca->sum_rtt;
 
-                       do_div(t, info.tcpv_rttcnt);
-                       info.tcpv_rtt = t;
+                       do_div(t, info->vegas.tcpv_rttcnt);
+                       info->vegas.tcpv_rtt = t;
                }
-               return nla_put(skb, INET_DIAG_VEGASINFO, sizeof(info), &info);
+               *attr = INET_DIAG_VEGASINFO;
+               return sizeof(struct tcpvegas_info);
        }
        return 0;
 }
index 3a4d9b34bed44a2f6b77b2be0e753867bad32292..c9ab964189a0162c7de19d4319f6c3e56194117b 100644 (file)
@@ -1820,14 +1820,12 @@ advance_sp:
        for (j = 0; j < used_sacks; j++)
                tp->recv_sack_cache[i++] = sp[j];
 
-       tcp_mark_lost_retrans(sk);
-
-       tcp_verify_left_out(tp);
-
        if ((state.reord < tp->fackets_out) &&
            ((inet_csk(sk)->icsk_ca_state != TCP_CA_Loss) || tp->undo_marker))
                tcp_update_reordering(sk, tp->fackets_out - state.reord, 0);
 
+       tcp_mark_lost_retrans(sk);
+       tcp_verify_left_out(tp);
 out:
 
 #if FASTRETRANS_DEBUG > 0
@@ -2700,16 +2698,21 @@ static void tcp_process_loss(struct sock *sk, int flag, bool is_dupack)
        struct tcp_sock *tp = tcp_sk(sk);
        bool recovered = !before(tp->snd_una, tp->high_seq);
 
+       if ((flag & FLAG_SND_UNA_ADVANCED) &&
+           tcp_try_undo_loss(sk, false))
+               return;
+
        if (tp->frto) { /* F-RTO RFC5682 sec 3.1 (sack enhanced version). */
                /* Step 3.b. A timeout is spurious if not all data are
                 * lost, i.e., never-retransmitted data are (s)acked.
                 */
-               if (tcp_try_undo_loss(sk, flag & FLAG_ORIG_SACK_ACKED))
+               if ((flag & FLAG_ORIG_SACK_ACKED) &&
+                   tcp_try_undo_loss(sk, true))
                        return;
 
-               if (after(tp->snd_nxt, tp->high_seq) &&
-                   (flag & FLAG_DATA_SACKED || is_dupack)) {
-                       tp->frto = 0; /* Loss was real: 2nd part of step 3.a */
+               if (after(tp->snd_nxt, tp->high_seq)) {
+                       if (flag & FLAG_DATA_SACKED || is_dupack)
+                               tp->frto = 0; /* Step 3.a. loss was real */
                } else if (flag & FLAG_SND_UNA_ADVANCED && !recovered) {
                        tp->high_seq = tp->snd_nxt;
                        __tcp_push_pending_frames(sk, tcp_current_mss(sk),
@@ -2734,8 +2737,6 @@ static void tcp_process_loss(struct sock *sk, int flag, bool is_dupack)
                else if (flag & FLAG_SND_UNA_ADVANCED)
                        tcp_reset_reno_sack(tp);
        }
-       if (tcp_try_undo_loss(sk, false))
-               return;
        tcp_xmit_retransmit_queue(sk);
 }
 
@@ -3280,6 +3281,28 @@ static inline bool tcp_may_update_window(const struct tcp_sock *tp,
                (ack_seq == tp->snd_wl1 && nwin > tp->snd_wnd);
 }
 
+/* If we update tp->snd_una, also update tp->bytes_acked */
+static void tcp_snd_una_update(struct tcp_sock *tp, u32 ack)
+{
+       u32 delta = ack - tp->snd_una;
+
+       u64_stats_update_begin(&tp->syncp);
+       tp->bytes_acked += delta;
+       u64_stats_update_end(&tp->syncp);
+       tp->snd_una = ack;
+}
+
+/* If we update tp->rcv_nxt, also update tp->bytes_received */
+static void tcp_rcv_nxt_update(struct tcp_sock *tp, u32 seq)
+{
+       u32 delta = seq - tp->rcv_nxt;
+
+       u64_stats_update_begin(&tp->syncp);
+       tp->bytes_received += delta;
+       u64_stats_update_end(&tp->syncp);
+       tp->rcv_nxt = seq;
+}
+
 /* Update our send window.
  *
  * Window update algorithm, described in RFC793/RFC1122 (used in linux-2.2
@@ -3315,7 +3338,7 @@ static int tcp_ack_update_window(struct sock *sk, const struct sk_buff *skb, u32
                }
        }
 
-       tp->snd_una = ack;
+       tcp_snd_una_update(tp, ack);
 
        return flag;
 }
@@ -3497,7 +3520,7 @@ static int tcp_ack(struct sock *sk, const struct sk_buff *skb, int flag)
                 * Note, we use the fact that SND.UNA>=SND.WL2.
                 */
                tcp_update_wl(tp, ack_seq);
-               tp->snd_una = ack;
+               tcp_snd_una_update(tp, ack);
                flag |= FLAG_WIN_UPDATE;
 
                tcp_in_ack_event(sk, CA_ACK_WIN_UPDATE);
@@ -4236,7 +4259,7 @@ static void tcp_ofo_queue(struct sock *sk)
 
                tail = skb_peek_tail(&sk->sk_receive_queue);
                eaten = tail && tcp_try_coalesce(sk, tail, skb, &fragstolen);
-               tp->rcv_nxt = TCP_SKB_CB(skb)->end_seq;
+               tcp_rcv_nxt_update(tp, TCP_SKB_CB(skb)->end_seq);
                if (!eaten)
                        __skb_queue_tail(&sk->sk_receive_queue, skb);
                if (TCP_SKB_CB(skb)->tcp_flags & TCPHDR_FIN)
@@ -4404,7 +4427,7 @@ static int __must_check tcp_queue_rcv(struct sock *sk, struct sk_buff *skb, int
        __skb_pull(skb, hdrlen);
        eaten = (tail &&
                 tcp_try_coalesce(sk, tail, skb, fragstolen)) ? 1 : 0;
-       tcp_sk(sk)->rcv_nxt = TCP_SKB_CB(skb)->end_seq;
+       tcp_rcv_nxt_update(tcp_sk(sk), TCP_SKB_CB(skb)->end_seq);
        if (!eaten) {
                __skb_queue_tail(&sk->sk_receive_queue, skb);
                skb_set_owner_r(skb, sk);
@@ -4497,7 +4520,7 @@ queue_and_out:
 
                        eaten = tcp_queue_rcv(sk, skb, 0, &fragstolen);
                }
-               tp->rcv_nxt = TCP_SKB_CB(skb)->end_seq;
+               tcp_rcv_nxt_update(tp, TCP_SKB_CB(skb)->end_seq);
                if (skb->len)
                        tcp_event_data_recv(sk, skb);
                if (TCP_SKB_CB(skb)->tcp_flags & TCPHDR_FIN)
@@ -5245,7 +5268,7 @@ void tcp_rcv_established(struct sock *sk, struct sk_buff *skb,
                                        tcp_rcv_rtt_measure_ts(sk, skb);
 
                                        __skb_pull(skb, tcp_header_len);
-                                       tp->rcv_nxt = TCP_SKB_CB(skb)->end_seq;
+                                       tcp_rcv_nxt_update(tp, TCP_SKB_CB(skb)->end_seq);
                                        NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_TCPHPHITSTOUSER);
                                        eaten = 1;
                                }
index 3571f2be4470749b9a7c8178fa43a6bf2bac33d8..fc1c658ec6c18cb1daa1cc06039a9f19df67bb5e 100644 (file)
@@ -1348,7 +1348,8 @@ static struct sock *tcp_v4_hnd_req(struct sock *sk, struct sk_buff *skb)
        req = inet_csk_search_req(sk, th->source, iph->saddr, iph->daddr);
        if (req) {
                nsk = tcp_check_req(sk, skb, req, false);
-               reqsk_put(req);
+               if (!nsk)
+                       reqsk_put(req);
                return nsk;
        }
 
index 63d6311b5365944fae0bdaa0f7abfbc51f55a429..17e7339ee5cadd077769de396b7568a7ccb73e13 100644 (file)
@@ -300,7 +300,7 @@ void tcp_time_wait(struct sock *sk, int state, int timeo)
                        tw->tw_v6_daddr = sk->sk_v6_daddr;
                        tw->tw_v6_rcv_saddr = sk->sk_v6_rcv_saddr;
                        tw->tw_tclass = np->tclass;
-                       tw->tw_flowlabel = np->flow_label >> 12;
+                       tw->tw_flowlabel = be32_to_cpu(np->flow_label & IPV6_FLOWLABEL_MASK);
                        tw->tw_ipv6only = sk->sk_ipv6only;
                }
 #endif
@@ -420,7 +420,10 @@ void tcp_ca_openreq_child(struct sock *sk, const struct dst_entry *dst)
                rcu_read_unlock();
        }
 
-       if (!ca_got_dst && !try_module_get(icsk->icsk_ca_ops->owner))
+       /* If no valid choice made yet, assign current system default ca. */
+       if (!ca_got_dst &&
+           (!icsk->icsk_ca_setsockopt ||
+            !try_module_get(icsk->icsk_ca_ops->owner)))
                tcp_assign_congestion_control(sk);
 
        tcp_set_ca_state(sk, TCP_CA_Open);
@@ -755,10 +758,11 @@ struct sock *tcp_check_req(struct sock *sk, struct sk_buff *skb,
        if (!child)
                goto listen_overflow;
 
-       inet_csk_reqsk_queue_unlink(sk, req);
-       inet_csk_reqsk_queue_removed(sk, req);
-
+       inet_csk_reqsk_queue_drop(sk, req);
        inet_csk_reqsk_queue_add(sk, req, child);
+       /* Warning: caller must not call reqsk_put(req);
+        * child stole last reference on it.
+        */
        return child;
 
 listen_overflow:
index 8c8d7e06b72fc1e5c4a50ca55136757f0501f8c0..a369e8a70b2c775bfee94d7f329ee892c2cdc895 100644 (file)
@@ -2812,39 +2812,65 @@ begin_fwd:
        }
 }
 
-/* Send a fin.  The caller locks the socket for us.  This cannot be
- * allowed to fail queueing a FIN frame under any circumstances.
+/* We allow to exceed memory limits for FIN packets to expedite
+ * connection tear down and (memory) recovery.
+ * Otherwise tcp_send_fin() could be tempted to either delay FIN
+ * or even be forced to close flow without any FIN.
+ */
+static void sk_forced_wmem_schedule(struct sock *sk, int size)
+{
+       int amt, status;
+
+       if (size <= sk->sk_forward_alloc)
+               return;
+       amt = sk_mem_pages(size);
+       sk->sk_forward_alloc += amt * SK_MEM_QUANTUM;
+       sk_memory_allocated_add(sk, amt, &status);
+}
+
+/* Send a FIN. The caller locks the socket for us.
+ * We should try to send a FIN packet really hard, but eventually give up.
  */
 void tcp_send_fin(struct sock *sk)
 {
+       struct sk_buff *skb, *tskb = tcp_write_queue_tail(sk);
        struct tcp_sock *tp = tcp_sk(sk);
-       struct sk_buff *skb = tcp_write_queue_tail(sk);
-       int mss_now;
 
-       /* Optimization, tack on the FIN if we have a queue of
-        * unsent frames.  But be careful about outgoing SACKS
-        * and IP options.
+       /* Optimization, tack on the FIN if we have one skb in write queue and
+        * this skb was not yet sent, or we are under memory pressure.
+        * Note: in the latter case, FIN packet will be sent after a timeout,
+        * as TCP stack thinks it has already been transmitted.
         */
-       mss_now = tcp_current_mss(sk);
-
-       if (tcp_send_head(sk)) {
-               TCP_SKB_CB(skb)->tcp_flags |= TCPHDR_FIN;
-               TCP_SKB_CB(skb)->end_seq++;
+       if (tskb && (tcp_send_head(sk) || sk_under_memory_pressure(sk))) {
+coalesce:
+               TCP_SKB_CB(tskb)->tcp_flags |= TCPHDR_FIN;
+               TCP_SKB_CB(tskb)->end_seq++;
                tp->write_seq++;
+               if (!tcp_send_head(sk)) {
+                       /* This means tskb was already sent.
+                        * Pretend we included the FIN on previous transmit.
+                        * We need to set tp->snd_nxt to the value it would have
+                        * if FIN had been sent. This is because retransmit path
+                        * does not change tp->snd_nxt.
+                        */
+                       tp->snd_nxt++;
+                       return;
+               }
        } else {
-               /* Socket is locked, keep trying until memory is available. */
-               for (;;) {
-                       skb = sk_stream_alloc_skb(sk, 0, sk->sk_allocation);
-                       if (skb)
-                               break;
-                       yield();
+               skb = alloc_skb_fclone(MAX_TCP_HEADER, sk->sk_allocation);
+               if (unlikely(!skb)) {
+                       if (tskb)
+                               goto coalesce;
+                       return;
                }
+               skb_reserve(skb, MAX_TCP_HEADER);
+               sk_forced_wmem_schedule(sk, skb->truesize);
                /* FIN eats a sequence byte, write_seq advanced by tcp_queue_skb(). */
                tcp_init_nondata_skb(skb, tp->write_seq,
                                     TCPHDR_ACK | TCPHDR_FIN);
                tcp_queue_skb(sk, skb);
        }
-       __tcp_push_pending_frames(sk, mss_now, TCP_NAGLE_OFF);
+       __tcp_push_pending_frames(sk, tcp_current_mss(sk), TCP_NAGLE_OFF);
 }
 
 /* We get here when a process closes a file descriptor (either due to
index c71a1b8f7bde3082a6520128bb6f47d3081de8ac..a6cea1d5e20d47f06eab95f3344a3e3b7c44da89 100644 (file)
@@ -286,18 +286,19 @@ static void tcp_vegas_cong_avoid(struct sock *sk, u32 ack, u32 acked)
 }
 
 /* Extract info for Tcp socket info provided via netlink. */
-int tcp_vegas_get_info(struct sock *sk, u32 ext, struct sk_buff *skb)
+size_t tcp_vegas_get_info(struct sock *sk, u32 ext, int *attr,
+                         union tcp_cc_info *info)
 {
        const struct vegas *ca = inet_csk_ca(sk);
+
        if (ext & (1 << (INET_DIAG_VEGASINFO - 1))) {
-               struct tcpvegas_info info = {
-                       .tcpv_enabled = ca->doing_vegas_now,
-                       .tcpv_rttcnt = ca->cntRTT,
-                       .tcpv_rtt = ca->baseRTT,
-                       .tcpv_minrtt = ca->minRTT,
-               };
-
-               return nla_put(skb, INET_DIAG_VEGASINFO, sizeof(info), &info);
+               info->vegas.tcpv_enabled = ca->doing_vegas_now,
+               info->vegas.tcpv_rttcnt = ca->cntRTT,
+               info->vegas.tcpv_rtt = ca->baseRTT,
+               info->vegas.tcpv_minrtt = ca->minRTT,
+
+               *attr = INET_DIAG_VEGASINFO;
+               return sizeof(struct tcpvegas_info);
        }
        return 0;
 }
index e8a6b33cc61dd7c4d58ea7d3ebd1dd1f35041de9..ef9da5306c685b269cc1efe64ee40196faf11e66 100644 (file)
@@ -19,6 +19,7 @@ void tcp_vegas_init(struct sock *sk);
 void tcp_vegas_state(struct sock *sk, u8 ca_state);
 void tcp_vegas_pkts_acked(struct sock *sk, u32 cnt, s32 rtt_us);
 void tcp_vegas_cwnd_event(struct sock *sk, enum tcp_ca_event event);
-int tcp_vegas_get_info(struct sock *sk, u32 ext, struct sk_buff *skb);
+size_t tcp_vegas_get_info(struct sock *sk, u32 ext, int *attr,
+                         union tcp_cc_info *info);
 
 #endif /* __TCP_VEGAS_H */
index b3c57cceb9907fe9d79f33f33369a96b647b5f26..c10732e39837872c724b801700f627a7fb1c9390 100644 (file)
@@ -256,18 +256,19 @@ static void tcp_westwood_event(struct sock *sk, enum tcp_ca_event event)
 }
 
 /* Extract info for Tcp socket info provided via netlink. */
-static int tcp_westwood_info(struct sock *sk, u32 ext, struct sk_buff *skb)
+static size_t tcp_westwood_info(struct sock *sk, u32 ext, int *attr,
+                               union tcp_cc_info *info)
 {
        const struct westwood *ca = inet_csk_ca(sk);
 
        if (ext & (1 << (INET_DIAG_VEGASINFO - 1))) {
-               struct tcpvegas_info info = {
-                       .tcpv_enabled = 1,
-                       .tcpv_rtt = jiffies_to_usecs(ca->rtt),
-                       .tcpv_minrtt = jiffies_to_usecs(ca->rtt_min),
-               };
+               info->vegas.tcpv_enabled = 1;
+               info->vegas.tcpv_rttcnt = 0;
+               info->vegas.tcpv_rtt    = jiffies_to_usecs(ca->rtt),
+               info->vegas.tcpv_minrtt = jiffies_to_usecs(ca->rtt_min),
 
-               return nla_put(skb, INET_DIAG_VEGASINFO, sizeof(info), &info);
+               *attr = INET_DIAG_VEGASINFO;
+               return sizeof(struct tcpvegas_info);
        }
        return 0;
 }
index d10b7e0112ebdb8fa61c650725ae7fae68f7e669..83aa604f9273c332c5a0e5399253d961ef92eb9a 100644 (file)
@@ -90,6 +90,7 @@
 #include <linux/socket.h>
 #include <linux/sockios.h>
 #include <linux/igmp.h>
+#include <linux/inetdevice.h>
 #include <linux/in.h>
 #include <linux/errno.h>
 #include <linux/timer.h>
@@ -1345,10 +1346,8 @@ csum_copy_err:
        }
        unlock_sock_fast(sk, slow);
 
-       if (noblock)
-               return -EAGAIN;
-
-       /* starting over for a new packet */
+       /* starting over for a new packet, but check if we need to yield */
+       cond_resched();
        msg->msg_flags &= ~MSG_TRUNC;
        goto try_again;
 }
@@ -1962,6 +1961,7 @@ void udp_v4_early_demux(struct sk_buff *skb)
        struct sock *sk;
        struct dst_entry *dst;
        int dif = skb->dev->ifindex;
+       int ours;
 
        /* validate the packet */
        if (!pskb_may_pull(skb, skb_transport_offset(skb) + sizeof(struct udphdr)))
@@ -1971,14 +1971,24 @@ void udp_v4_early_demux(struct sk_buff *skb)
        uh = udp_hdr(skb);
 
        if (skb->pkt_type == PACKET_BROADCAST ||
-           skb->pkt_type == PACKET_MULTICAST)
+           skb->pkt_type == PACKET_MULTICAST) {
+               struct in_device *in_dev = __in_dev_get_rcu(skb->dev);
+
+               if (!in_dev)
+                       return;
+
+               ours = ip_check_mc_rcu(in_dev, iph->daddr, iph->saddr,
+                                      iph->protocol);
+               if (!ours)
+                       return;
                sk = __udp4_lib_mcast_demux_lookup(net, uh->dest, iph->daddr,
                                                   uh->source, iph->saddr, dif);
-       else if (skb->pkt_type == PACKET_HOST)
+       } else if (skb->pkt_type == PACKET_HOST) {
                sk = __udp4_lib_demux_lookup(net, uh->dest, iph->daddr,
                                             uh->source, iph->saddr, dif);
-       else
+       } else {
                return;
+       }
 
        if (!sk)
                return;
index d873ceea86e6c74c34e7fcd31bec41c78ce5720b..ca09bf49ac6806b399dba51399f84e47590cb9ed 100644 (file)
@@ -133,6 +133,14 @@ static void snmp6_free_dev(struct inet6_dev *idev)
        free_percpu(idev->stats.ipv6);
 }
 
+static void in6_dev_finish_destroy_rcu(struct rcu_head *head)
+{
+       struct inet6_dev *idev = container_of(head, struct inet6_dev, rcu);
+
+       snmp6_free_dev(idev);
+       kfree(idev);
+}
+
 /* Nobody refers to this device, we may destroy it. */
 
 void in6_dev_finish_destroy(struct inet6_dev *idev)
@@ -151,7 +159,6 @@ void in6_dev_finish_destroy(struct inet6_dev *idev)
                pr_warn("Freeing alive inet6 device %p\n", idev);
                return;
        }
-       snmp6_free_dev(idev);
-       kfree_rcu(idev, rcu);
+       call_rcu(&idev->rcu, in6_dev_finish_destroy_rcu);
 }
 EXPORT_SYMBOL(in6_dev_finish_destroy);
index 31f1b5d5e2ef8f7056eb8eddd513ba5b3343e2b1..7c07ce36aae2a5b9cc14cb5a883327b7230b38ee 100644 (file)
@@ -248,7 +248,8 @@ static int esp6_output(struct xfrm_state *x, struct sk_buff *skb)
        aead_givcrypt_set_crypt(req, sg, sg, clen, iv);
        aead_givcrypt_set_assoc(req, asg, assoclen);
        aead_givcrypt_set_giv(req, esph->enc_data,
-                             XFRM_SKB_CB(skb)->seq.output.low);
+                             XFRM_SKB_CB(skb)->seq.output.low +
+                             ((u64)XFRM_SKB_CB(skb)->seq.output.hi << 32));
 
        ESP_SKB_CB(skb)->tmp = tmp;
        err = crypto_aead_givencrypt(req);
index 96dbffff5a2400bfca0a7b0bee9072d76ec92e88..bde57b113009794637a07b405173bef1fd3c6fb3 100644 (file)
@@ -693,6 +693,7 @@ static int fib6_add_rt2node(struct fib6_node *fn, struct rt6_info *rt,
 {
        struct rt6_info *iter = NULL;
        struct rt6_info **ins;
+       struct rt6_info **fallback_ins = NULL;
        int replace = (info->nlh &&
                       (info->nlh->nlmsg_flags & NLM_F_REPLACE));
        int add = (!info->nlh ||
@@ -716,8 +717,13 @@ static int fib6_add_rt2node(struct fib6_node *fn, struct rt6_info *rt,
                            (info->nlh->nlmsg_flags & NLM_F_EXCL))
                                return -EEXIST;
                        if (replace) {
-                               found++;
-                               break;
+                               if (rt_can_ecmp == rt6_qualify_for_ecmp(iter)) {
+                                       found++;
+                                       break;
+                               }
+                               if (rt_can_ecmp)
+                                       fallback_ins = fallback_ins ?: ins;
+                               goto next_iter;
                        }
 
                        if (iter->dst.dev == rt->dst.dev &&
@@ -753,9 +759,17 @@ static int fib6_add_rt2node(struct fib6_node *fn, struct rt6_info *rt,
                if (iter->rt6i_metric > rt->rt6i_metric)
                        break;
 
+next_iter:
                ins = &iter->dst.rt6_next;
        }
 
+       if (fallback_ins && !found) {
+               /* No ECMP-able route found, replace first non-ECMP one */
+               ins = fallback_ins;
+               iter = *ins;
+               found++;
+       }
+
        /* Reset round-robin state, if necessary */
        if (ins == &fn->leaf)
                fn->rr_ptr = NULL;
@@ -815,6 +829,8 @@ add:
                }
 
        } else {
+               int nsiblings;
+
                if (!found) {
                        if (add)
                                goto add;
@@ -835,8 +851,27 @@ add:
                        info->nl_net->ipv6.rt6_stats->fib_route_nodes++;
                        fn->fn_flags |= RTN_RTINFO;
                }
+               nsiblings = iter->rt6i_nsiblings;
                fib6_purge_rt(iter, fn, info->nl_net);
                rt6_release(iter);
+
+               if (nsiblings) {
+                       /* Replacing an ECMP route, remove all siblings */
+                       ins = &rt->dst.rt6_next;
+                       iter = *ins;
+                       while (iter) {
+                               if (rt6_qualify_for_ecmp(iter)) {
+                                       *ins = iter->dst.rt6_next;
+                                       fib6_purge_rt(iter, fn, info->nl_net);
+                                       rt6_release(iter);
+                                       nsiblings--;
+                               } else {
+                                       ins = &iter->dst.rt6_next;
+                               }
+                               iter = *ins;
+                       }
+                       WARN_ON(nsiblings != 0);
+               }
        }
 
        return 0;
index b5e6cc1d4a7302f3288ba00ee9c75bb327410960..a38d3ac0f18f6e631e3a17904bf617f7a0dfe28a 100644 (file)
@@ -1246,7 +1246,6 @@ static void ip6gre_tunnel_setup(struct net_device *dev)
 static int ip6gre_tunnel_init(struct net_device *dev)
 {
        struct ip6_tnl *tunnel;
-       int i;
 
        tunnel = netdev_priv(dev);
 
@@ -1260,16 +1259,10 @@ static int ip6gre_tunnel_init(struct net_device *dev)
        if (ipv6_addr_any(&tunnel->parms.raddr))
                dev->header_ops = &ip6gre_header_ops;
 
-       dev->tstats = alloc_percpu(struct pcpu_sw_netstats);
+       dev->tstats = netdev_alloc_pcpu_stats(struct pcpu_sw_netstats);
        if (!dev->tstats)
                return -ENOMEM;
 
-       for_each_possible_cpu(i) {
-               struct pcpu_sw_netstats *ip6gre_tunnel_stats;
-               ip6gre_tunnel_stats = per_cpu_ptr(dev->tstats, i);
-               u64_stats_init(&ip6gre_tunnel_stats->syncp);
-       }
-
        return 0;
 }
 
index 7fde1f265c90e90f16291e6c861b6e242111c25b..bc09cb97b8401011c112afe469fd231382387622 100644 (file)
@@ -886,22 +886,45 @@ static int ip6_dst_lookup_tail(struct sock *sk,
 #endif
        int err;
 
-       if (!*dst)
-               *dst = ip6_route_output(net, sk, fl6);
-
-       err = (*dst)->error;
-       if (err)
-               goto out_err_release;
+       /* The correct way to handle this would be to do
+        * ip6_route_get_saddr, and then ip6_route_output; however,
+        * the route-specific preferred source forces the
+        * ip6_route_output call _before_ ip6_route_get_saddr.
+        *
+        * In source specific routing (no src=any default route),
+        * ip6_route_output will fail given src=any saddr, though, so
+        * that's why we try it again later.
+        */
+       if (ipv6_addr_any(&fl6->saddr) && (!*dst || !(*dst)->error)) {
+               struct rt6_info *rt;
+               bool had_dst = *dst != NULL;
 
-       if (ipv6_addr_any(&fl6->saddr)) {
-               struct rt6_info *rt = (struct rt6_info *) *dst;
+               if (!had_dst)
+                       *dst = ip6_route_output(net, sk, fl6);
+               rt = (*dst)->error ? NULL : (struct rt6_info *)*dst;
                err = ip6_route_get_saddr(net, rt, &fl6->daddr,
                                          sk ? inet6_sk(sk)->srcprefs : 0,
                                          &fl6->saddr);
                if (err)
                        goto out_err_release;
+
+               /* If we had an erroneous initial result, pretend it
+                * never existed and let the SA-enabled version take
+                * over.
+                */
+               if (!had_dst && (*dst)->error) {
+                       dst_release(*dst);
+                       *dst = NULL;
+               }
        }
 
+       if (!*dst)
+               *dst = ip6_route_output(net, sk, fl6);
+
+       err = (*dst)->error;
+       if (err)
+               goto out_err_release;
+
 #ifdef CONFIG_IPV6_OPTIMISTIC_DAD
        /*
         * Here if the dst entry we've looked up
@@ -1277,8 +1300,10 @@ emsgsize:
 
        /* If this is the first and only packet and device
         * supports checksum offloading, let's use it.
+        * Use transhdrlen, same as IPv4, because partial
+        * sums only work when transhdrlen is set.
         */
-       if (!skb && sk->sk_protocol == IPPROTO_UDP &&
+       if (transhdrlen && sk->sk_protocol == IPPROTO_UDP &&
            length + fragheaderlen < mtu &&
            rt->dst.dev->features & NETIF_F_V6_CSUM &&
            !exthdrlen)
index ed9d681207fa340881fd100db0ea1cb3eb9a2ffb..0224c032dca5dca98ea0146bcdf52c179fa23f6d 100644 (file)
@@ -322,7 +322,6 @@ static int vti6_rcv(struct sk_buff *skb)
                }
 
                XFRM_TUNNEL_SKB_CB(skb)->tunnel.ip6 = t;
-               skb->mark = be32_to_cpu(t->parms.i_key);
 
                rcu_read_unlock();
 
@@ -342,6 +341,8 @@ static int vti6_rcv_cb(struct sk_buff *skb, int err)
        struct pcpu_sw_netstats *tstats;
        struct xfrm_state *x;
        struct ip6_tnl *t = XFRM_TUNNEL_SKB_CB(skb)->tunnel.ip6;
+       u32 orig_mark = skb->mark;
+       int ret;
 
        if (!t)
                return 1;
@@ -358,7 +359,11 @@ static int vti6_rcv_cb(struct sk_buff *skb, int err)
        x = xfrm_input_state(skb);
        family = x->inner_mode->afinfo->family;
 
-       if (!xfrm_policy_check(NULL, XFRM_POLICY_IN, skb, family))
+       skb->mark = be32_to_cpu(t->parms.i_key);
+       ret = xfrm_policy_check(NULL, XFRM_POLICY_IN, skb, family);
+       skb->mark = orig_mark;
+
+       if (!ret)
                return -EPERM;
 
        skb_scrub_packet(skb, !net_eq(t->net, dev_net(skb->dev)));
@@ -430,6 +435,7 @@ vti6_xmit(struct sk_buff *skb, struct net_device *dev, struct flowi *fl)
        struct net_device *tdev;
        struct xfrm_state *x;
        int err = -1;
+       int mtu;
 
        if (!dst)
                goto tx_err_link_failure;
@@ -463,6 +469,19 @@ vti6_xmit(struct sk_buff *skb, struct net_device *dev, struct flowi *fl)
        skb_dst_set(skb, dst);
        skb->dev = skb_dst(skb)->dev;
 
+       mtu = dst_mtu(dst);
+       if (!skb->ignore_df && skb->len > mtu) {
+               skb_dst(skb)->ops->update_pmtu(dst, NULL, skb, mtu);
+
+               if (skb->protocol == htons(ETH_P_IPV6))
+                       icmpv6_send(skb, ICMPV6_PKT_TOOBIG, 0, mtu);
+               else
+                       icmp_send(skb, ICMP_DEST_UNREACH, ICMP_FRAG_NEEDED,
+                                 htonl(mtu));
+
+               return -EMSGSIZE;
+       }
+
        err = dst_output(skb);
        if (net_xmit_eval(err) == 0) {
                struct pcpu_sw_netstats *tstats = this_cpu_ptr(dev->tstats);
@@ -495,7 +514,6 @@ vti6_tnl_xmit(struct sk_buff *skb, struct net_device *dev)
        int ret;
 
        memset(&fl, 0, sizeof(fl));
-       skb->mark = be32_to_cpu(t->parms.o_key);
 
        switch (skb->protocol) {
        case htons(ETH_P_IPV6):
@@ -516,6 +534,9 @@ vti6_tnl_xmit(struct sk_buff *skb, struct net_device *dev)
                goto tx_err;
        }
 
+       /* override mark with tunnel output key */
+       fl.flowi_mark = be32_to_cpu(t->parms.o_key);
+
        ret = vti6_xmit(skb, dev, &fl);
        if (ret < 0)
                goto tx_err;
index 1a732a1d3c8e13c58508cef9381d2d32e5a34448..62f5b0d0bc9bfbf19940ba0c70ef9da464bf467f 100644 (file)
@@ -1275,6 +1275,9 @@ do_replace(struct net *net, const void __user *user, unsigned int len)
        /* overflow check */
        if (tmp.num_counters >= INT_MAX / sizeof(struct xt_counters))
                return -ENOMEM;
+       if (tmp.num_counters == 0)
+               return -EINVAL;
+
        tmp.name[sizeof(tmp.name)-1] = 0;
 
        newinfo = xt_alloc_table_info(tmp.size);
@@ -1822,6 +1825,9 @@ compat_do_replace(struct net *net, void __user *user, unsigned int len)
                return -ENOMEM;
        if (tmp.num_counters >= INT_MAX / sizeof(struct xt_counters))
                return -ENOMEM;
+       if (tmp.num_counters == 0)
+               return -EINVAL;
+
        tmp.name[sizeof(tmp.name)-1] = 0;
 
        newinfo = xt_alloc_table_info(tmp.size);
index 5c48293ff06235e72f586007ff1e7bb568733b92..c73ae5039e46d3811d60bf5df9e9482d966a4966 100644 (file)
@@ -2245,9 +2245,10 @@ int ip6_route_get_saddr(struct net *net,
                        unsigned int prefs,
                        struct in6_addr *saddr)
 {
-       struct inet6_dev *idev = ip6_dst_idev((struct dst_entry *)rt);
+       struct inet6_dev *idev =
+               rt ? ip6_dst_idev((struct dst_entry *)rt) : NULL;
        int err = 0;
-       if (rt->rt6i_prefsrc.plen)
+       if (rt && rt->rt6i_prefsrc.plen)
                *saddr = rt->rt6i_prefsrc.addr;
        else
                err = ipv6_dev_get_saddr(net, idev ? idev->dev : NULL,
@@ -2503,9 +2504,9 @@ static int ip6_route_multipath(struct fib6_config *cfg, int add)
        int attrlen;
        int err = 0, last_err = 0;
 
+       remaining = cfg->fc_mp_len;
 beginning:
        rtnh = (struct rtnexthop *)cfg->fc_mp;
-       remaining = cfg->fc_mp_len;
 
        /* Parse a Multipath Entry */
        while (rtnh_ok(rtnh, remaining)) {
@@ -2535,15 +2536,19 @@ beginning:
                                 * next hops that have been already added.
                                 */
                                add = 0;
+                               remaining = cfg->fc_mp_len - remaining;
                                goto beginning;
                        }
                }
                /* Because each route is added like a single route we remove
-                * this flag after the first nexthop (if there is a collision,
-                * we have already fail to add the first nexthop:
-                * fib6_add_rt2node() has reject it).
+                * these flags after the first nexthop: if there is a collision,
+                * we have already failed to add the first nexthop:
+                * fib6_add_rt2node() has rejected it; when replacing, old
+                * nexthops have been replaced by first new, the rest should
+                * be added to it.
                 */
-               cfg->fc_nlinfo.nlh->nlmsg_flags &= ~NLM_F_EXCL;
+               cfg->fc_nlinfo.nlh->nlmsg_flags &= ~(NLM_F_EXCL |
+                                                    NLM_F_REPLACE);
                rtnh = rtnh_next(rtnh, &remaining);
        }
 
index ad51df85aa00dda56b86dca24ed5fe9a3b5c791e..3adffb300238ebdaf729871bafbb348e82fbde56 100644 (file)
@@ -914,7 +914,7 @@ static void tcp_v6_timewait_ack(struct sock *sk, struct sk_buff *skb)
                        tcptw->tw_rcv_wnd >> tw->tw_rcv_wscale,
                        tcp_time_stamp + tcptw->tw_ts_offset,
                        tcptw->tw_ts_recent, tw->tw_bound_dev_if, tcp_twsk_md5_key(tcptw),
-                       tw->tw_tclass, (tw->tw_flowlabel << 12));
+                       tw->tw_tclass, cpu_to_be32(tw->tw_flowlabel));
 
        inet_twsk_put(tw);
 }
@@ -946,7 +946,8 @@ static struct sock *tcp_v6_hnd_req(struct sock *sk, struct sk_buff *skb)
                                   &ipv6_hdr(skb)->daddr, tcp_v6_iif(skb));
        if (req) {
                nsk = tcp_check_req(sk, skb, req, false);
-               reqsk_put(req);
+               if (!nsk)
+                       reqsk_put(req);
                return nsk;
        }
        nsk = __inet6_lookup_established(sock_net(sk), &tcp_hashinfo,
index 3477c919fcc8eb534c3a438ab6d607a6215897f8..e51fc3eee6dbd65506e8612fc5782b9482cf4708 100644 (file)
@@ -525,10 +525,8 @@ csum_copy_err:
        }
        unlock_sock_fast(sk, slow);
 
-       if (noblock)
-               return -EAGAIN;
-
-       /* starting over for a new packet */
+       /* starting over for a new packet, but check if we need to yield */
+       cond_resched();
        msg->msg_flags &= ~MSG_TRUNC;
        goto try_again;
 }
@@ -731,7 +729,9 @@ static bool __udp_v6_is_mcast_sock(struct net *net, struct sock *sk,
            (inet->inet_dport && inet->inet_dport != rmt_port) ||
            (!ipv6_addr_any(&sk->sk_v6_daddr) &&
                    !ipv6_addr_equal(&sk->sk_v6_daddr, rmt_addr)) ||
-           (sk->sk_bound_dev_if && sk->sk_bound_dev_if != dif))
+           (sk->sk_bound_dev_if && sk->sk_bound_dev_if != dif) ||
+           (!ipv6_addr_any(&sk->sk_v6_rcv_saddr) &&
+                   !ipv6_addr_equal(&sk->sk_v6_rcv_saddr, loc_addr)))
                return false;
        if (!inet6_mc_check(sk, loc_addr, rmt_addr))
                return false;
index 265e42721a661cf54a46246065168d6a17885147..ff347a0eebd4fdbcbd1580c8af0450c23f673f85 100644 (file)
@@ -2495,51 +2495,22 @@ static bool ieee80211_coalesce_started_roc(struct ieee80211_local *local,
                                           struct ieee80211_roc_work *new_roc,
                                           struct ieee80211_roc_work *cur_roc)
 {
-       unsigned long j = jiffies;
-       unsigned long cur_roc_end = cur_roc->hw_start_time +
-                                   msecs_to_jiffies(cur_roc->duration);
-       struct ieee80211_roc_work *next_roc;
-       int new_dur;
+       unsigned long now = jiffies;
+       unsigned long remaining = cur_roc->hw_start_time +
+                                 msecs_to_jiffies(cur_roc->duration) -
+                                 now;
 
        if (WARN_ON(!cur_roc->started || !cur_roc->hw_begun))
                return false;
 
-       if (time_after(j + IEEE80211_ROC_MIN_LEFT, cur_roc_end))
+       /* if it doesn't fit entirely, schedule a new one */
+       if (new_roc->duration > jiffies_to_msecs(remaining))
                return false;
 
        ieee80211_handle_roc_started(new_roc);
 
-       new_dur = new_roc->duration - jiffies_to_msecs(cur_roc_end - j);
-
-       /* cur_roc is long enough - add new_roc to the dependents list. */
-       if (new_dur <= 0) {
-               list_add_tail(&new_roc->list, &cur_roc->dependents);
-               return true;
-       }
-
-       new_roc->duration = new_dur;
-
-       /*
-        * if cur_roc was already coalesced before, we might
-        * want to extend the next roc instead of adding
-        * a new one.
-        */
-       next_roc = list_entry(cur_roc->list.next,
-                             struct ieee80211_roc_work, list);
-       if (&next_roc->list != &local->roc_list &&
-           next_roc->chan == new_roc->chan &&
-           next_roc->sdata == new_roc->sdata &&
-           !WARN_ON(next_roc->started)) {
-               list_add_tail(&new_roc->list, &next_roc->dependents);
-               next_roc->duration = max(next_roc->duration,
-                                        new_roc->duration);
-               next_roc->type = max(next_roc->type, new_roc->type);
-               return true;
-       }
-
-       /* add right after cur_roc */
-       list_add(&new_roc->list, &cur_roc->list);
-
+       /* add to dependents so we send the expired event properly */
+       list_add_tail(&new_roc->list, &cur_roc->dependents);
        return true;
 }
 
@@ -2652,17 +2623,9 @@ static int ieee80211_start_roc_work(struct ieee80211_local *local,
                         * In the offloaded ROC case, if it hasn't begun, add
                         * this new one to the dependent list to be handled
                         * when the master one begins. If it has begun,
-                        * check that there's still a minimum time left and
-                        * if so, start this one, transmitting the frame, but
-                        * add it to the list directly after this one with
-                        * a reduced time so we'll ask the driver to execute
-                        * it right after finishing the previous one, in the
-                        * hope that it'll also be executed right afterwards,
-                        * effectively extending the old one.
-                        * If there's no minimum time left, just add it to the
-                        * normal list.
-                        * TODO: the ROC type is ignored here, assuming that it
-                        * is better to immediately use the current ROC.
+                        * check if it fits entirely within the existing one,
+                        * in which case it will just be dependent as well.
+                        * Otherwise, schedule it by itself.
                         */
                        if (!tmp->hw_begun) {
                                list_add_tail(&roc->list, &tmp->dependents);
index ab46ab4a72498fd04f1c12ac6bb44f867d86869b..c0a9187bc3a9d579b36824fa64ecbbcbd6575110 100644 (file)
@@ -205,6 +205,8 @@ enum ieee80211_packet_rx_flags {
  * @IEEE80211_RX_CMNTR: received on cooked monitor already
  * @IEEE80211_RX_BEACON_REPORTED: This frame was already reported
  *     to cfg80211_report_obss_beacon().
+ * @IEEE80211_RX_REORDER_TIMER: this frame is released by the
+ *     reorder buffer timeout timer, not the normal RX path
  *
  * These flags are used across handling multiple interfaces
  * for a single frame.
@@ -212,6 +214,7 @@ enum ieee80211_packet_rx_flags {
 enum ieee80211_rx_flags {
        IEEE80211_RX_CMNTR              = BIT(0),
        IEEE80211_RX_BEACON_REPORTED    = BIT(1),
+       IEEE80211_RX_REORDER_TIMER      = BIT(2),
 };
 
 struct ieee80211_rx_data {
@@ -325,12 +328,6 @@ struct mesh_preq_queue {
        u8 flags;
 };
 
-#if HZ/100 == 0
-#define IEEE80211_ROC_MIN_LEFT 1
-#else
-#define IEEE80211_ROC_MIN_LEFT (HZ/100)
-#endif
-
 struct ieee80211_roc_work {
        struct list_head list;
        struct list_head dependents;
index b4ac596a7cb76205cf39d935708d3383490c2b73..84cef600c5730e74c6456e801ffa93ef55e4e47f 100644 (file)
@@ -522,6 +522,12 @@ int ieee80211_do_open(struct wireless_dev *wdev, bool coming_up)
                memcpy(sdata->vif.hw_queue, master->vif.hw_queue,
                       sizeof(sdata->vif.hw_queue));
                sdata->vif.bss_conf.chandef = master->vif.bss_conf.chandef;
+
+               mutex_lock(&local->key_mtx);
+               sdata->crypto_tx_tailroom_needed_cnt +=
+                       master->crypto_tx_tailroom_needed_cnt;
+               mutex_unlock(&local->key_mtx);
+
                break;
                }
        case NL80211_IFTYPE_AP:
@@ -819,13 +825,15 @@ static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata,
         * (because if we remove a STA after ops->remove_interface()
         * the driver will have removed the vif info already!)
         *
-        * This is relevant only in WDS mode, in all other modes we've
-        * already removed all stations when disconnecting or similar,
-        * so warn otherwise.
+        * In WDS mode a station must exist here and be flushed, for
+        * AP_VLANs stations may exist since there's nothing else that
+        * would have removed them, but in other modes there shouldn't
+        * be any stations.
         */
        flushed = sta_info_flush(sdata);
-       WARN_ON_ONCE((sdata->vif.type != NL80211_IFTYPE_WDS && flushed > 0) ||
-                    (sdata->vif.type == NL80211_IFTYPE_WDS && flushed != 1));
+       WARN_ON_ONCE(sdata->vif.type != NL80211_IFTYPE_AP_VLAN &&
+                    ((sdata->vif.type != NL80211_IFTYPE_WDS && flushed > 0) ||
+                     (sdata->vif.type == NL80211_IFTYPE_WDS && flushed != 1)));
 
        /* don't count this interface for promisc/allmulti while it is down */
        if (sdata->flags & IEEE80211_SDATA_ALLMULTI)
index 2291cd7300911514db84c0135369b807e93a9d06..a907f2d5c12d857bf1811af24e57f5af09eb8665 100644 (file)
@@ -58,6 +58,22 @@ static void assert_key_lock(struct ieee80211_local *local)
        lockdep_assert_held(&local->key_mtx);
 }
 
+static void
+update_vlan_tailroom_need_count(struct ieee80211_sub_if_data *sdata, int delta)
+{
+       struct ieee80211_sub_if_data *vlan;
+
+       if (sdata->vif.type != NL80211_IFTYPE_AP)
+               return;
+
+       mutex_lock(&sdata->local->mtx);
+
+       list_for_each_entry(vlan, &sdata->u.ap.vlans, u.vlan.list)
+               vlan->crypto_tx_tailroom_needed_cnt += delta;
+
+       mutex_unlock(&sdata->local->mtx);
+}
+
 static void increment_tailroom_need_count(struct ieee80211_sub_if_data *sdata)
 {
        /*
@@ -79,6 +95,8 @@ static void increment_tailroom_need_count(struct ieee80211_sub_if_data *sdata)
         * http://mid.gmane.org/1308590980.4322.19.camel@jlt3.sipsolutions.net
         */
 
+       update_vlan_tailroom_need_count(sdata, 1);
+
        if (!sdata->crypto_tx_tailroom_needed_cnt++) {
                /*
                 * Flush all XMIT packets currently using HW encryption or no
@@ -88,6 +106,15 @@ static void increment_tailroom_need_count(struct ieee80211_sub_if_data *sdata)
        }
 }
 
+static void decrease_tailroom_need_count(struct ieee80211_sub_if_data *sdata,
+                                        int delta)
+{
+       WARN_ON_ONCE(sdata->crypto_tx_tailroom_needed_cnt < delta);
+
+       update_vlan_tailroom_need_count(sdata, -delta);
+       sdata->crypto_tx_tailroom_needed_cnt -= delta;
+}
+
 static int ieee80211_key_enable_hw_accel(struct ieee80211_key *key)
 {
        struct ieee80211_sub_if_data *sdata;
@@ -144,7 +171,7 @@ static int ieee80211_key_enable_hw_accel(struct ieee80211_key *key)
 
                if (!((key->conf.flags & IEEE80211_KEY_FLAG_GENERATE_MMIC) ||
                      (key->conf.flags & IEEE80211_KEY_FLAG_RESERVE_TAILROOM)))
-                       sdata->crypto_tx_tailroom_needed_cnt--;
+                       decrease_tailroom_need_count(sdata, 1);
 
                WARN_ON((key->conf.flags & IEEE80211_KEY_FLAG_PUT_IV_SPACE) &&
                        (key->conf.flags & IEEE80211_KEY_FLAG_GENERATE_IV));
@@ -541,7 +568,7 @@ static void __ieee80211_key_destroy(struct ieee80211_key *key,
                        schedule_delayed_work(&sdata->dec_tailroom_needed_wk,
                                              HZ/2);
                } else {
-                       sdata->crypto_tx_tailroom_needed_cnt--;
+                       decrease_tailroom_need_count(sdata, 1);
                }
        }
 
@@ -631,6 +658,7 @@ void ieee80211_key_free(struct ieee80211_key *key, bool delay_tailroom)
 void ieee80211_enable_keys(struct ieee80211_sub_if_data *sdata)
 {
        struct ieee80211_key *key;
+       struct ieee80211_sub_if_data *vlan;
 
        ASSERT_RTNL();
 
@@ -639,7 +667,14 @@ void ieee80211_enable_keys(struct ieee80211_sub_if_data *sdata)
 
        mutex_lock(&sdata->local->key_mtx);
 
-       sdata->crypto_tx_tailroom_needed_cnt = 0;
+       WARN_ON_ONCE(sdata->crypto_tx_tailroom_needed_cnt ||
+                    sdata->crypto_tx_tailroom_pending_dec);
+
+       if (sdata->vif.type == NL80211_IFTYPE_AP) {
+               list_for_each_entry(vlan, &sdata->u.ap.vlans, u.vlan.list)
+                       WARN_ON_ONCE(vlan->crypto_tx_tailroom_needed_cnt ||
+                                    vlan->crypto_tx_tailroom_pending_dec);
+       }
 
        list_for_each_entry(key, &sdata->key_list, list) {
                increment_tailroom_need_count(sdata);
@@ -649,6 +684,22 @@ void ieee80211_enable_keys(struct ieee80211_sub_if_data *sdata)
        mutex_unlock(&sdata->local->key_mtx);
 }
 
+void ieee80211_reset_crypto_tx_tailroom(struct ieee80211_sub_if_data *sdata)
+{
+       struct ieee80211_sub_if_data *vlan;
+
+       mutex_lock(&sdata->local->key_mtx);
+
+       sdata->crypto_tx_tailroom_needed_cnt = 0;
+
+       if (sdata->vif.type == NL80211_IFTYPE_AP) {
+               list_for_each_entry(vlan, &sdata->u.ap.vlans, u.vlan.list)
+                       vlan->crypto_tx_tailroom_needed_cnt = 0;
+       }
+
+       mutex_unlock(&sdata->local->key_mtx);
+}
+
 void ieee80211_iter_keys(struct ieee80211_hw *hw,
                         struct ieee80211_vif *vif,
                         void (*iter)(struct ieee80211_hw *hw,
@@ -688,8 +739,8 @@ static void ieee80211_free_keys_iface(struct ieee80211_sub_if_data *sdata,
 {
        struct ieee80211_key *key, *tmp;
 
-       sdata->crypto_tx_tailroom_needed_cnt -=
-               sdata->crypto_tx_tailroom_pending_dec;
+       decrease_tailroom_need_count(sdata,
+                                    sdata->crypto_tx_tailroom_pending_dec);
        sdata->crypto_tx_tailroom_pending_dec = 0;
 
        ieee80211_debugfs_key_remove_mgmt_default(sdata);
@@ -709,6 +760,7 @@ void ieee80211_free_keys(struct ieee80211_sub_if_data *sdata,
 {
        struct ieee80211_local *local = sdata->local;
        struct ieee80211_sub_if_data *vlan;
+       struct ieee80211_sub_if_data *master;
        struct ieee80211_key *key, *tmp;
        LIST_HEAD(keys);
 
@@ -728,8 +780,20 @@ void ieee80211_free_keys(struct ieee80211_sub_if_data *sdata,
        list_for_each_entry_safe(key, tmp, &keys, list)
                __ieee80211_key_destroy(key, false);
 
-       WARN_ON_ONCE(sdata->crypto_tx_tailroom_needed_cnt ||
-                    sdata->crypto_tx_tailroom_pending_dec);
+       if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN) {
+               if (sdata->bss) {
+                       master = container_of(sdata->bss,
+                                             struct ieee80211_sub_if_data,
+                                             u.ap);
+
+                       WARN_ON_ONCE(sdata->crypto_tx_tailroom_needed_cnt !=
+                                    master->crypto_tx_tailroom_needed_cnt);
+               }
+       } else {
+               WARN_ON_ONCE(sdata->crypto_tx_tailroom_needed_cnt ||
+                            sdata->crypto_tx_tailroom_pending_dec);
+       }
+
        if (sdata->vif.type == NL80211_IFTYPE_AP) {
                list_for_each_entry(vlan, &sdata->u.ap.vlans, u.vlan.list)
                        WARN_ON_ONCE(vlan->crypto_tx_tailroom_needed_cnt ||
@@ -793,8 +857,8 @@ void ieee80211_delayed_tailroom_dec(struct work_struct *wk)
         */
 
        mutex_lock(&sdata->local->key_mtx);
-       sdata->crypto_tx_tailroom_needed_cnt -=
-               sdata->crypto_tx_tailroom_pending_dec;
+       decrease_tailroom_need_count(sdata,
+                                    sdata->crypto_tx_tailroom_pending_dec);
        sdata->crypto_tx_tailroom_pending_dec = 0;
        mutex_unlock(&sdata->local->key_mtx);
 }
index c5a31835be0e0ca22c154b1345d91be761308833..96557dd1e77dff325072cff12b7b671aad942015 100644 (file)
@@ -161,6 +161,7 @@ void ieee80211_free_keys(struct ieee80211_sub_if_data *sdata,
 void ieee80211_free_sta_keys(struct ieee80211_local *local,
                             struct sta_info *sta);
 void ieee80211_enable_keys(struct ieee80211_sub_if_data *sdata);
+void ieee80211_reset_crypto_tx_tailroom(struct ieee80211_sub_if_data *sdata);
 
 #define key_mtx_dereference(local, ref) \
        rcu_dereference_protected(ref, lockdep_is_held(&((local)->key_mtx)))
index 260eed45b6d2ff105052643169465c04d333c182..5793f75c5ffde91de02e9698bd27500ff4640826 100644 (file)
@@ -2121,7 +2121,8 @@ ieee80211_deliver_skb(struct ieee80211_rx_data *rx)
                /* deliver to local stack */
                skb->protocol = eth_type_trans(skb, dev);
                memset(skb->cb, 0, sizeof(skb->cb));
-               if (rx->local->napi)
+               if (!(rx->flags & IEEE80211_RX_REORDER_TIMER) &&
+                   rx->local->napi)
                        napi_gro_receive(rx->local->napi, skb);
                else
                        netif_receive_skb(skb);
@@ -3231,7 +3232,7 @@ void ieee80211_release_reorder_timeout(struct sta_info *sta, int tid)
                /* This is OK -- must be QoS data frame */
                .security_idx = tid,
                .seqno_idx = tid,
-               .flags = 0,
+               .flags = IEEE80211_RX_REORDER_TIMER,
        };
        struct tid_ampdu_rx *tid_agg_rx;
 
index 12971b71d0fa1ea8ce69dbdc09314c1c1641d7c8..2880f2ae99abe3a05b6421f53340a42e11a9ca30 100644 (file)
@@ -66,6 +66,7 @@
 
 static const struct rhashtable_params sta_rht_params = {
        .nelem_hint = 3, /* start small */
+       .automatic_shrinking = true,
        .head_offset = offsetof(struct sta_info, hash_node),
        .key_offset = offsetof(struct sta_info, sta.addr),
        .key_len = ETH_ALEN,
@@ -157,8 +158,24 @@ struct sta_info *sta_info_get(struct ieee80211_sub_if_data *sdata,
                              const u8 *addr)
 {
        struct ieee80211_local *local = sdata->local;
+       struct sta_info *sta;
+       struct rhash_head *tmp;
+       const struct bucket_table *tbl;
+
+       rcu_read_lock();
+       tbl = rht_dereference_rcu(local->sta_hash.tbl, &local->sta_hash);
 
-       return rhashtable_lookup_fast(&local->sta_hash, addr, sta_rht_params);
+       for_each_sta_info(local, tbl, addr, sta, tmp) {
+               if (sta->sdata == sdata) {
+                       rcu_read_unlock();
+                       /* this is safe as the caller must already hold
+                        * another rcu read section or the mutex
+                        */
+                       return sta;
+               }
+       }
+       rcu_read_unlock();
+       return NULL;
 }
 
 /*
index 79412f16b61db9953a4a537db3bd5693d7c61cdb..b864ebc6ab8fbf2a09baca02e650e7fe0314cc75 100644 (file)
@@ -2022,6 +2022,9 @@ int ieee80211_reconfig(struct ieee80211_local *local)
        mutex_unlock(&local->sta_mtx);
 
        /* add back keys */
+       list_for_each_entry(sdata, &local->interfaces, list)
+               ieee80211_reset_crypto_tx_tailroom(sdata);
+
        list_for_each_entry(sdata, &local->interfaces, list)
                if (ieee80211_sdata_running(sdata))
                        ieee80211_enable_keys(sdata);
index a4220e92f0cc20c0feb04c307f6ed72097f4fe3a..efa3f48f1ec5d51ea7191c8ae90dda77c0d330e1 100644 (file)
@@ -98,8 +98,7 @@ static u8 *ieee80211_wep_add_iv(struct ieee80211_local *local,
 
        hdr->frame_control |= cpu_to_le16(IEEE80211_FCTL_PROTECTED);
 
-       if (WARN_ON(skb_tailroom(skb) < IEEE80211_WEP_ICV_LEN ||
-                   skb_headroom(skb) < IEEE80211_WEP_IV_LEN))
+       if (WARN_ON(skb_headroom(skb) < IEEE80211_WEP_IV_LEN))
                return NULL;
 
        hdrlen = ieee80211_hdrlen(hdr->frame_control);
@@ -167,6 +166,9 @@ int ieee80211_wep_encrypt(struct ieee80211_local *local,
        size_t len;
        u8 rc4key[3 + WLAN_KEY_LEN_WEP104];
 
+       if (WARN_ON(skb_tailroom(skb) < IEEE80211_WEP_ICV_LEN))
+               return -1;
+
        iv = ieee80211_wep_add_iv(local, skb, keylen, keyidx);
        if (!iv)
                return -1;
index 5d9f68c75e5f8f68c5884d467e5a9d16db0edaac..70be9c799f8a81596a4e753b239849549d792dd0 100644 (file)
 
 static struct net_device *
 ieee802154_add_iface_deprecated(struct wpan_phy *wpan_phy,
-                               const char *name, int type)
+                               const char *name,
+                               unsigned char name_assign_type, int type)
 {
        struct ieee802154_local *local = wpan_phy_priv(wpan_phy);
        struct net_device *dev;
 
        rtnl_lock();
-       dev = ieee802154_if_add(local, name, type,
+       dev = ieee802154_if_add(local, name, name_assign_type, type,
                                cpu_to_le64(0x0000000000000000ULL));
        rtnl_unlock();
 
@@ -45,12 +46,14 @@ static void ieee802154_del_iface_deprecated(struct wpan_phy *wpan_phy,
 
 static int
 ieee802154_add_iface(struct wpan_phy *phy, const char *name,
+                    unsigned char name_assign_type,
                     enum nl802154_iftype type, __le64 extended_addr)
 {
        struct ieee802154_local *local = wpan_phy_priv(phy);
        struct net_device *err;
 
-       err = ieee802154_if_add(local, name, type, extended_addr);
+       err = ieee802154_if_add(local, name, name_assign_type, type,
+                               extended_addr);
        return PTR_ERR_OR_ZERO(err);
 }
 
index bebd70ffc7a3d101551f023e515db24033883f0b..127ba18386fc639aac4ccda482ebe4be11b8e6ee 100644 (file)
@@ -182,7 +182,8 @@ void ieee802154_iface_exit(void);
 void ieee802154_if_remove(struct ieee802154_sub_if_data *sdata);
 struct net_device *
 ieee802154_if_add(struct ieee802154_local *local, const char *name,
-                 enum nl802154_iftype type, __le64 extended_addr);
+                 unsigned char name_assign_type, enum nl802154_iftype type,
+                 __le64 extended_addr);
 void ieee802154_remove_interfaces(struct ieee802154_local *local);
 
 #endif /* __IEEE802154_I_H */
index 38b56f9d9386a4821e50cfdd6059fa115c5e4358..91b75abbd1a1d05b3219b9089232d9f67eb73ccd 100644 (file)
@@ -522,7 +522,8 @@ ieee802154_setup_sdata(struct ieee802154_sub_if_data *sdata,
 
 struct net_device *
 ieee802154_if_add(struct ieee802154_local *local, const char *name,
-                 enum nl802154_iftype type, __le64 extended_addr)
+                 unsigned char name_assign_type, enum nl802154_iftype type,
+                 __le64 extended_addr)
 {
        struct net_device *ndev = NULL;
        struct ieee802154_sub_if_data *sdata = NULL;
@@ -531,7 +532,7 @@ ieee802154_if_add(struct ieee802154_local *local, const char *name,
        ASSERT_RTNL();
 
        ndev = alloc_netdev(sizeof(*sdata) + local->hw.vif_data_size, name,
-                           NET_NAME_UNKNOWN, ieee802154_if_setup);
+                           name_assign_type, ieee802154_if_setup);
        if (!ndev)
                return ERR_PTR(-ENOMEM);
 
index dcf73958133a0d6d0c28f825f648b13cc9ef478b..5b2be12832e65fca351dec5a61619c1042de9004 100644 (file)
@@ -134,7 +134,7 @@ llsec_key_alloc(const struct ieee802154_llsec_key *template)
        for (i = 0; i < ARRAY_SIZE(key->tfm); i++) {
                key->tfm[i] = crypto_alloc_aead("ccm(aes)", 0,
                                                CRYPTO_ALG_ASYNC);
-               if (!key->tfm[i])
+               if (IS_ERR(key->tfm[i]))
                        goto err_tfm;
                if (crypto_aead_setkey(key->tfm[i], template->key,
                                       IEEE802154_LLSEC_KEY_SIZE))
@@ -144,7 +144,7 @@ llsec_key_alloc(const struct ieee802154_llsec_key *template)
        }
 
        key->tfm0 = crypto_alloc_blkcipher("ctr(aes)", 0, CRYPTO_ALG_ASYNC);
-       if (!key->tfm0)
+       if (IS_ERR(key->tfm0))
                goto err_tfm;
 
        if (crypto_blkcipher_setkey(key->tfm0, template->key,
index 8500378c8318cd3b5b7e3a368f44080b40c5900f..08cb32dc8fd33e892e53f7f87f601b10ede8c38d 100644 (file)
@@ -161,18 +161,21 @@ int ieee802154_register_hw(struct ieee802154_hw *hw)
 
        rtnl_lock();
 
-       dev = ieee802154_if_add(local, "wpan%d", NL802154_IFTYPE_NODE,
+       dev = ieee802154_if_add(local, "wpan%d", NET_NAME_ENUM,
+                               NL802154_IFTYPE_NODE,
                                cpu_to_le64(0x0000000000000000ULL));
        if (IS_ERR(dev)) {
                rtnl_unlock();
                rc = PTR_ERR(dev);
-               goto out_wq;
+               goto out_phy;
        }
 
        rtnl_unlock();
 
        return 0;
 
+out_phy:
+       wpan_phy_unregister(local->phy);
 out_wq:
        destroy_workqueue(local->workqueue);
 out:
index db8a2ea6d4de5bb2b4b92785d2e6a05a7613b0f3..1f93a5978f2ad43fc81a16427e34d07ca2c0f34e 100644 (file)
@@ -53,6 +53,11 @@ static struct mpls_route *mpls_route_input_rcu(struct net *net, unsigned index)
        return rt;
 }
 
+static inline struct mpls_dev *mpls_dev_get(const struct net_device *dev)
+{
+       return rcu_dereference_rtnl(dev->mpls_ptr);
+}
+
 static bool mpls_output_possible(const struct net_device *dev)
 {
        return dev && (dev->flags & IFF_UP) && netif_carrier_ok(dev);
@@ -136,6 +141,7 @@ static int mpls_forward(struct sk_buff *skb, struct net_device *dev,
        struct mpls_route *rt;
        struct mpls_entry_decoded dec;
        struct net_device *out_dev;
+       struct mpls_dev *mdev;
        unsigned int hh_len;
        unsigned int new_header_size;
        unsigned int mtu;
@@ -143,6 +149,10 @@ static int mpls_forward(struct sk_buff *skb, struct net_device *dev,
 
        /* Careful this entire function runs inside of an rcu critical section */
 
+       mdev = mpls_dev_get(dev);
+       if (!mdev || !mdev->input_enabled)
+               goto drop;
+
        if (skb->pkt_type != PACKET_HOST)
                goto drop;
 
@@ -352,9 +362,9 @@ static int mpls_route_add(struct mpls_route_config *cfg)
        if (!dev)
                goto errout;
 
-       /* For now just support ethernet devices */
+       /* Ensure this is a supported device */
        err = -EINVAL;
-       if ((dev->type != ARPHRD_ETHER) && (dev->type != ARPHRD_LOOPBACK))
+       if (!mpls_dev_get(dev))
                goto errout;
 
        err = -EINVAL;
@@ -428,10 +438,89 @@ errout:
        return err;
 }
 
+#define MPLS_PERDEV_SYSCTL_OFFSET(field)       \
+       (&((struct mpls_dev *)0)->field)
+
+static const struct ctl_table mpls_dev_table[] = {
+       {
+               .procname       = "input",
+               .maxlen         = sizeof(int),
+               .mode           = 0644,
+               .proc_handler   = proc_dointvec,
+               .data           = MPLS_PERDEV_SYSCTL_OFFSET(input_enabled),
+       },
+       { }
+};
+
+static int mpls_dev_sysctl_register(struct net_device *dev,
+                                   struct mpls_dev *mdev)
+{
+       char path[sizeof("net/mpls/conf/") + IFNAMSIZ];
+       struct ctl_table *table;
+       int i;
+
+       table = kmemdup(&mpls_dev_table, sizeof(mpls_dev_table), GFP_KERNEL);
+       if (!table)
+               goto out;
+
+       /* Table data contains only offsets relative to the base of
+        * the mdev at this point, so make them absolute.
+        */
+       for (i = 0; i < ARRAY_SIZE(mpls_dev_table); i++)
+               table[i].data = (char *)mdev + (uintptr_t)table[i].data;
+
+       snprintf(path, sizeof(path), "net/mpls/conf/%s", dev->name);
+
+       mdev->sysctl = register_net_sysctl(dev_net(dev), path, table);
+       if (!mdev->sysctl)
+               goto free;
+
+       return 0;
+
+free:
+       kfree(table);
+out:
+       return -ENOBUFS;
+}
+
+static void mpls_dev_sysctl_unregister(struct mpls_dev *mdev)
+{
+       struct ctl_table *table;
+
+       table = mdev->sysctl->ctl_table_arg;
+       unregister_net_sysctl_table(mdev->sysctl);
+       kfree(table);
+}
+
+static struct mpls_dev *mpls_add_dev(struct net_device *dev)
+{
+       struct mpls_dev *mdev;
+       int err = -ENOMEM;
+
+       ASSERT_RTNL();
+
+       mdev = kzalloc(sizeof(*mdev), GFP_KERNEL);
+       if (!mdev)
+               return ERR_PTR(err);
+
+       err = mpls_dev_sysctl_register(dev, mdev);
+       if (err)
+               goto free;
+
+       rcu_assign_pointer(dev->mpls_ptr, mdev);
+
+       return mdev;
+
+free:
+       kfree(mdev);
+       return ERR_PTR(err);
+}
+
 static void mpls_ifdown(struct net_device *dev)
 {
        struct mpls_route __rcu **platform_label;
        struct net *net = dev_net(dev);
+       struct mpls_dev *mdev;
        unsigned index;
 
        platform_label = rtnl_dereference(net->mpls.platform_label);
@@ -443,17 +532,49 @@ static void mpls_ifdown(struct net_device *dev)
                        continue;
                rt->rt_dev = NULL;
        }
+
+       mdev = mpls_dev_get(dev);
+       if (!mdev)
+               return;
+
+       mpls_dev_sysctl_unregister(mdev);
+
+       RCU_INIT_POINTER(dev->mpls_ptr, NULL);
+
+       kfree_rcu(mdev, rcu);
 }
 
 static int mpls_dev_notify(struct notifier_block *this, unsigned long event,
                           void *ptr)
 {
        struct net_device *dev = netdev_notifier_info_to_dev(ptr);
+       struct mpls_dev *mdev;
 
        switch(event) {
+       case NETDEV_REGISTER:
+               /* For now just support ethernet devices */
+               if ((dev->type == ARPHRD_ETHER) ||
+                   (dev->type == ARPHRD_LOOPBACK)) {
+                       mdev = mpls_add_dev(dev);
+                       if (IS_ERR(mdev))
+                               return notifier_from_errno(PTR_ERR(mdev));
+               }
+               break;
+
        case NETDEV_UNREGISTER:
                mpls_ifdown(dev);
                break;
+       case NETDEV_CHANGENAME:
+               mdev = mpls_dev_get(dev);
+               if (mdev) {
+                       int err;
+
+                       mpls_dev_sysctl_unregister(mdev);
+                       err = mpls_dev_sysctl_register(dev, mdev);
+                       if (err)
+                               return notifier_from_errno(err);
+               }
+               break;
        }
        return NOTIFY_OK;
 }
@@ -536,6 +657,15 @@ int nla_get_labels(const struct nlattr *nla,
                if ((dec.bos != bos) || dec.ttl || dec.tc)
                        return -EINVAL;
 
+               switch (dec.label) {
+               case MPLS_LABEL_IMPLNULL:
+                       /* RFC3032: This is a label that an LSR may
+                        * assign and distribute, but which never
+                        * actually appears in the encapsulation.
+                        */
+                       return -EINVAL;
+               }
+
                label[i] = dec.label;
        }
        *labels = nla_labels;
@@ -816,7 +946,7 @@ static int resize_platform_label_table(struct net *net, size_t limit)
        }
 
        /* In case the predefined labels need to be populated */
-       if (limit > LABEL_IPV4_EXPLICIT_NULL) {
+       if (limit > MPLS_LABEL_IPV4NULL) {
                struct net_device *lo = net->loopback_dev;
                rt0 = mpls_rt_alloc(lo->addr_len);
                if (!rt0)
@@ -826,7 +956,7 @@ static int resize_platform_label_table(struct net *net, size_t limit)
                rt0->rt_via_table = NEIGH_LINK_TABLE;
                memcpy(rt0->rt_via, lo->dev_addr, lo->addr_len);
        }
-       if (limit > LABEL_IPV6_EXPLICIT_NULL) {
+       if (limit > MPLS_LABEL_IPV6NULL) {
                struct net_device *lo = net->loopback_dev;
                rt2 = mpls_rt_alloc(lo->addr_len);
                if (!rt2)
@@ -854,15 +984,15 @@ static int resize_platform_label_table(struct net *net, size_t limit)
        memcpy(labels, old, cp_size);
 
        /* If needed set the predefined labels */
-       if ((old_limit <= LABEL_IPV6_EXPLICIT_NULL) &&
-           (limit > LABEL_IPV6_EXPLICIT_NULL)) {
-               RCU_INIT_POINTER(labels[LABEL_IPV6_EXPLICIT_NULL], rt2);
+       if ((old_limit <= MPLS_LABEL_IPV6NULL) &&
+           (limit > MPLS_LABEL_IPV6NULL)) {
+               RCU_INIT_POINTER(labels[MPLS_LABEL_IPV6NULL], rt2);
                rt2 = NULL;
        }
 
-       if ((old_limit <= LABEL_IPV4_EXPLICIT_NULL) &&
-           (limit > LABEL_IPV4_EXPLICIT_NULL)) {
-               RCU_INIT_POINTER(labels[LABEL_IPV4_EXPLICIT_NULL], rt0);
+       if ((old_limit <= MPLS_LABEL_IPV4NULL) &&
+           (limit > MPLS_LABEL_IPV4NULL)) {
+               RCU_INIT_POINTER(labels[MPLS_LABEL_IPV4NULL], rt0);
                rt0 = NULL;
        }
 
@@ -912,7 +1042,7 @@ static int mpls_platform_labels(struct ctl_table *table, int write,
        return ret;
 }
 
-static struct ctl_table mpls_table[] = {
+static const struct ctl_table mpls_table[] = {
        {
                .procname       = "platform_labels",
                .data           = NULL,
index fb6de92052c4bc87db6c83ba5288f2f921e13c62..8cabeb5a1cb928c856c037c5994116df8547fb71 100644 (file)
@@ -1,16 +1,6 @@
 #ifndef MPLS_INTERNAL_H
 #define MPLS_INTERNAL_H
 
-#define LABEL_IPV4_EXPLICIT_NULL       0 /* RFC3032 */
-#define LABEL_ROUTER_ALERT_LABEL       1 /* RFC3032 */
-#define LABEL_IPV6_EXPLICIT_NULL       2 /* RFC3032 */
-#define LABEL_IMPLICIT_NULL            3 /* RFC3032 */
-#define LABEL_ENTROPY_INDICATOR                7 /* RFC6790 */
-#define LABEL_GAL                      13 /* RFC5586 */
-#define LABEL_OAM_ALERT                        14 /* RFC3429 */
-#define LABEL_EXTENSION                        15 /* RFC7274 */
-
-
 struct mpls_shim_hdr {
        __be32 label_stack_entry;
 };
@@ -22,6 +12,13 @@ struct mpls_entry_decoded {
        u8 bos;
 };
 
+struct mpls_dev {
+       int                     input_enabled;
+
+       struct ctl_table_header *sysctl;
+       struct rcu_head         rcu;
+};
+
 struct sk_buff;
 
 static inline struct mpls_shim_hdr *mpls_hdr(const struct sk_buff *skb)
index f70e34a68f702ab39c43e27d4b8e8127b49525f6..a0f3e6a3c7d18f344d3321a83b5c11d1988d5d3d 100644 (file)
@@ -863,6 +863,7 @@ config NETFILTER_XT_TARGET_TPROXY
        depends on NETFILTER_XTABLES
        depends on NETFILTER_ADVANCED
        depends on (IPV6 || IPV6=n)
+       depends on (IP6_NF_IPTABLES || IP6_NF_IPTABLES=n)
        depends on IP_NF_MANGLE
        select NF_DEFRAG_IPV4
        select NF_DEFRAG_IPV6 if IP6_NF_IPTABLES
@@ -1356,6 +1357,7 @@ config NETFILTER_XT_MATCH_SOCKET
        depends on NETFILTER_ADVANCED
        depends on !NF_CONNTRACK || NF_CONNTRACK
        depends on (IPV6 || IPV6=n)
+       depends on (IP6_NF_IPTABLES || IP6_NF_IPTABLES=n)
        select NF_DEFRAG_IPV4
        select NF_DEFRAG_IPV6 if IP6_NF_IPTABLES
        help
index 49532672f66dad0c3bae1b923993b0d1f518b25b..285eae3a145483c48c00493651a46a5d81656845 100644 (file)
@@ -3823,6 +3823,9 @@ static void __net_exit ip_vs_control_net_cleanup_sysctl(struct net *net)
        cancel_work_sync(&ipvs->defense_work.work);
        unregister_net_sysctl_table(ipvs->sysctl_hdr);
        ip_vs_stop_estimator(net, &ipvs->tot_stats);
+
+       if (!net_eq(net, &init_net))
+               kfree(ipvs->sysctl_tbl);
 }
 
 #else
index 5caa0c41bf26c3e6a2542f0dd50ac6f029ed8a84..70383de7205460a8ebdadd7fd1ba615fc7681296 100644 (file)
@@ -202,7 +202,7 @@ static const u8 tcp_conntracks[2][6][TCP_CONNTRACK_MAX] = {
  *     sES -> sES      :-)
  *     sFW -> sCW      Normal close request answered by ACK.
  *     sCW -> sCW
- *     sLA -> sTW      Last ACK detected.
+ *     sLA -> sTW      Last ACK detected (RFC5961 challenged)
  *     sTW -> sTW      Retransmitted last ACK. Remain in the same state.
  *     sCL -> sCL
  */
@@ -261,7 +261,7 @@ static const u8 tcp_conntracks[2][6][TCP_CONNTRACK_MAX] = {
  *     sES -> sES      :-)
  *     sFW -> sCW      Normal close request answered by ACK.
  *     sCW -> sCW
- *     sLA -> sTW      Last ACK detected.
+ *     sLA -> sTW      Last ACK detected (RFC5961 challenged)
  *     sTW -> sTW      Retransmitted last ACK.
  *     sCL -> sCL
  */
@@ -906,6 +906,7 @@ static int tcp_packet(struct nf_conn *ct,
                                        1 : ct->proto.tcp.last_win;
                        ct->proto.tcp.seen[ct->proto.tcp.last_dir].td_scale =
                                ct->proto.tcp.last_wscale;
+                       ct->proto.tcp.last_flags &= ~IP_CT_EXP_CHALLENGE_ACK;
                        ct->proto.tcp.seen[ct->proto.tcp.last_dir].flags =
                                ct->proto.tcp.last_flags;
                        memset(&ct->proto.tcp.seen[dir], 0,
@@ -923,7 +924,9 @@ static int tcp_packet(struct nf_conn *ct,
                 * may be in sync but we are not. In that case, we annotate
                 * the TCP options and let the packet go through. If it is a
                 * valid SYN packet, the server will reply with a SYN/ACK, and
-                * then we'll get in sync. Otherwise, the server ignores it. */
+                * then we'll get in sync. Otherwise, the server potentially
+                * responds with a challenge ACK if implementing RFC5961.
+                */
                if (index == TCP_SYN_SET && dir == IP_CT_DIR_ORIGINAL) {
                        struct ip_ct_tcp_state seen = {};
 
@@ -939,6 +942,13 @@ static int tcp_packet(struct nf_conn *ct,
                                ct->proto.tcp.last_flags |=
                                        IP_CT_TCP_FLAG_SACK_PERM;
                        }
+                       /* Mark the potential for RFC5961 challenge ACK,
+                        * this pose a special problem for LAST_ACK state
+                        * as ACK is intrepretated as ACKing last FIN.
+                        */
+                       if (old_state == TCP_CONNTRACK_LAST_ACK)
+                               ct->proto.tcp.last_flags |=
+                                       IP_CT_EXP_CHALLENGE_ACK;
                }
                spin_unlock_bh(&ct->lock);
                if (LOG_INVALID(net, IPPROTO_TCP))
@@ -970,6 +980,25 @@ static int tcp_packet(struct nf_conn *ct,
                        nf_log_packet(net, pf, 0, skb, NULL, NULL, NULL,
                                  "nf_ct_tcp: invalid state ");
                return -NF_ACCEPT;
+       case TCP_CONNTRACK_TIME_WAIT:
+               /* RFC5961 compliance cause stack to send "challenge-ACK"
+                * e.g. in response to spurious SYNs.  Conntrack MUST
+                * not believe this ACK is acking last FIN.
+                */
+               if (old_state == TCP_CONNTRACK_LAST_ACK &&
+                   index == TCP_ACK_SET &&
+                   ct->proto.tcp.last_dir != dir &&
+                   ct->proto.tcp.last_index == TCP_SYN_SET &&
+                   (ct->proto.tcp.last_flags & IP_CT_EXP_CHALLENGE_ACK)) {
+                       /* Detected RFC5961 challenge ACK */
+                       ct->proto.tcp.last_flags &= ~IP_CT_EXP_CHALLENGE_ACK;
+                       spin_unlock_bh(&ct->lock);
+                       if (LOG_INVALID(net, IPPROTO_TCP))
+                               nf_log_packet(net, pf, 0, skb, NULL, NULL, NULL,
+                                     "nf_ct_tcp: challenge-ACK ignored ");
+                       return NF_ACCEPT; /* Don't change state */
+               }
+               break;
        case TCP_CONNTRACK_CLOSE:
                if (index == TCP_RST_SET
                    && (ct->proto.tcp.seen[!dir].flags & IP_CT_TCP_FLAG_MAXACK_SET)
index 78af83bc9c8e8dbfcead6e151247a127602ac107..34ded09317e715cc94b80ce8d918006bbe1f714b 100644 (file)
@@ -4340,7 +4340,6 @@ static int nft_verdict_init(const struct nft_ctx *ctx, struct nft_data *data,
        case NFT_CONTINUE:
        case NFT_BREAK:
        case NFT_RETURN:
-               desc->len = sizeof(data->verdict);
                break;
        case NFT_JUMP:
        case NFT_GOTO:
@@ -4355,10 +4354,10 @@ static int nft_verdict_init(const struct nft_ctx *ctx, struct nft_data *data,
 
                chain->use++;
                data->verdict.chain = chain;
-               desc->len = sizeof(data);
                break;
        }
 
+       desc->len = sizeof(data->verdict);
        desc->type = NFT_DATA_VERDICT;
        return 0;
 }
@@ -4473,9 +4472,9 @@ EXPORT_SYMBOL_GPL(nft_data_init);
  */
 void nft_data_uninit(const struct nft_data *data, enum nft_data_types type)
 {
-       switch (type) {
-       case NFT_DATA_VALUE:
+       if (type < NFT_DATA_VERDICT)
                return;
+       switch (type) {
        case NFT_DATA_VERDICT:
                return nft_verdict_uninit(data);
        default:
index 3ad91266c821489500fbc8cbbcfc7bfd774b6f48..4ef1fae8445ed5d00183e3b15c7ca18133957983 100644 (file)
@@ -1073,7 +1073,13 @@ static struct pernet_operations nfnl_log_net_ops = {
 
 static int __init nfnetlink_log_init(void)
 {
-       int status = -ENOMEM;
+       int status;
+
+       status = register_pernet_subsys(&nfnl_log_net_ops);
+       if (status < 0) {
+               pr_err("failed to register pernet ops\n");
+               goto out;
+       }
 
        netlink_register_notifier(&nfulnl_rtnl_notifier);
        status = nfnetlink_subsys_register(&nfulnl_subsys);
@@ -1088,28 +1094,23 @@ static int __init nfnetlink_log_init(void)
                goto cleanup_subsys;
        }
 
-       status = register_pernet_subsys(&nfnl_log_net_ops);
-       if (status < 0) {
-               pr_err("failed to register pernet ops\n");
-               goto cleanup_logger;
-       }
        return status;
 
-cleanup_logger:
-       nf_log_unregister(&nfulnl_logger);
 cleanup_subsys:
        nfnetlink_subsys_unregister(&nfulnl_subsys);
 cleanup_netlink_notifier:
        netlink_unregister_notifier(&nfulnl_rtnl_notifier);
+       unregister_pernet_subsys(&nfnl_log_net_ops);
+out:
        return status;
 }
 
 static void __exit nfnetlink_log_fini(void)
 {
-       unregister_pernet_subsys(&nfnl_log_net_ops);
        nf_log_unregister(&nfulnl_logger);
        nfnetlink_subsys_unregister(&nfulnl_subsys);
        netlink_unregister_notifier(&nfulnl_rtnl_notifier);
+       unregister_pernet_subsys(&nfnl_log_net_ops);
 }
 
 MODULE_DESCRIPTION("netfilter userspace logging");
index 0b98c74202390ae79598ceb955360f937bb9556d..11c7682fa0ea1fbd13c90a38126f6a77efcac537 100644 (file)
@@ -1317,7 +1317,13 @@ static struct pernet_operations nfnl_queue_net_ops = {
 
 static int __init nfnetlink_queue_init(void)
 {
-       int status = -ENOMEM;
+       int status;
+
+       status = register_pernet_subsys(&nfnl_queue_net_ops);
+       if (status < 0) {
+               pr_err("nf_queue: failed to register pernet ops\n");
+               goto out;
+       }
 
        netlink_register_notifier(&nfqnl_rtnl_notifier);
        status = nfnetlink_subsys_register(&nfqnl_subsys);
@@ -1326,19 +1332,13 @@ static int __init nfnetlink_queue_init(void)
                goto cleanup_netlink_notifier;
        }
 
-       status = register_pernet_subsys(&nfnl_queue_net_ops);
-       if (status < 0) {
-               pr_err("nf_queue: failed to register pernet ops\n");
-               goto cleanup_subsys;
-       }
        register_netdevice_notifier(&nfqnl_dev_notifier);
        nf_register_queue_handler(&nfqh);
        return status;
 
-cleanup_subsys:
-       nfnetlink_subsys_unregister(&nfqnl_subsys);
 cleanup_netlink_notifier:
        netlink_unregister_notifier(&nfqnl_rtnl_notifier);
+out:
        return status;
 }
 
@@ -1346,9 +1346,9 @@ static void __exit nfnetlink_queue_fini(void)
 {
        nf_unregister_queue_handler();
        unregister_netdevice_notifier(&nfqnl_dev_notifier);
-       unregister_pernet_subsys(&nfnl_queue_net_ops);
        nfnetlink_subsys_unregister(&nfqnl_subsys);
        netlink_unregister_notifier(&nfqnl_rtnl_notifier);
+       unregister_pernet_subsys(&nfnl_queue_net_ops);
 
        rcu_barrier(); /* Wait for completion of call_rcu()'s */
 }
index 57d3e1af56305e90eade03e1fca1b38524091be6..0522fc9bfb0a88db513c480f45dff35a6f233000 100644 (file)
@@ -63,6 +63,8 @@ int nft_reject_dump(struct sk_buff *skb, const struct nft_expr *expr)
                if (nla_put_u8(skb, NFTA_REJECT_ICMP_CODE, priv->icmp_code))
                        goto nla_put_failure;
                break;
+       default:
+               break;
        }
 
        return 0;
index 62cabee42fbecc93587a0b008b19913a5a8470f9..635dbba93d013244038cbdbb48bbe9549f622304 100644 (file)
@@ -108,6 +108,8 @@ static int nft_reject_inet_dump(struct sk_buff *skb,
                if (nla_put_u8(skb, NFTA_REJECT_ICMP_CODE, priv->icmp_code))
                        goto nla_put_failure;
                break;
+       default:
+               break;
        }
 
        return 0;
index 19909d0786a2e60574ba623d343193ca212ed2be..bf6e76643f7876d8dee4df261baf077aad837be3 100644 (file)
@@ -89,7 +89,7 @@ static inline int netlink_is_kernel(struct sock *sk)
        return nlk_sk(sk)->flags & NETLINK_KERNEL_SOCKET;
 }
 
-struct netlink_table *nl_table;
+struct netlink_table *nl_table __read_mostly;
 EXPORT_SYMBOL_GPL(nl_table);
 
 static DECLARE_WAIT_QUEUE_HEAD(nl_table_wait);
@@ -1081,6 +1081,7 @@ static int netlink_insert(struct sock *sk, u32 portid)
        if (err) {
                if (err == -EEXIST)
                        err = -EADDRINUSE;
+               nlk_sk(sk)->portid = 0;
                sock_put(sk);
        }
 
@@ -1629,13 +1630,11 @@ static struct sk_buff *netlink_alloc_large_skb(unsigned int size,
        if (data == NULL)
                return NULL;
 
-       skb = build_skb(data, size);
+       skb = __build_skb(data, size);
        if (skb == NULL)
                vfree(data);
-       else {
-               skb->head_frag = 0;
+       else
                skb->destructor = netlink_skb_destructor;
-       }
 
        return skb;
 }
@@ -3141,7 +3140,6 @@ static const struct rhashtable_params netlink_rhashtable_params = {
        .key_len = netlink_compare_arg_len,
        .obj_hashfn = netlink_hash,
        .obj_cmpfn = netlink_compare,
-       .max_size = 65536,
        .automatic_shrinking = true,
 };
 
index 4776282c64175209924740fbd87a56de8e05b609..33e6d6e2908f553516c5ca97c4b93abee7b7057b 100644 (file)
@@ -125,6 +125,7 @@ static struct vport *netdev_create(const struct vport_parms *parms)
        if (err)
                goto error_master_upper_dev_unlink;
 
+       dev_disable_lro(netdev_vport->dev);
        dev_set_promiscuity(netdev_vport->dev, 1);
        netdev_vport->dev->priv_flags |= IFF_OVS_DATAPATH;
        rtnl_unlock();
index 5102c3cc4eec4ecec6698859935d7769d37a174c..b5989c6ee5513904127a8ffec31d09589094c8f6 100644 (file)
@@ -2311,11 +2311,14 @@ static int tpacket_snd(struct packet_sock *po, struct msghdr *msg)
                tlen = dev->needed_tailroom;
                skb = sock_alloc_send_skb(&po->sk,
                                hlen + tlen + sizeof(struct sockaddr_ll),
-                               0, &err);
+                               !need_wait, &err);
 
-               if (unlikely(skb == NULL))
+               if (unlikely(skb == NULL)) {
+                       /* we assume the socket was initially writeable ... */
+                       if (likely(len_sum > 0))
+                               err = len_sum;
                        goto out_status;
-
+               }
                tp_len = tpacket_fill_skb(po, skb, ph, dev, size_max, proto,
                                          addr, hlen);
                if (tp_len > dev->mtu + dev->hard_header_len) {
index 14f041398ca1744ea7596decaad7145184c7df0c..da6da57e5f36b5cc13a5bc92abfedb6a5ccea45d 100644 (file)
@@ -126,7 +126,10 @@ static struct rds_connection *__rds_conn_create(__be32 laddr, __be32 faddr,
        struct rds_transport *loop_trans;
        unsigned long flags;
        int ret;
+       struct rds_transport *otrans = trans;
 
+       if (!is_outgoing && otrans->t_type == RDS_TRANS_TCP)
+               goto new_conn;
        rcu_read_lock();
        conn = rds_conn_lookup(head, laddr, faddr, trans);
        if (conn && conn->c_loopback && conn->c_trans != &rds_loop_transport &&
@@ -142,6 +145,7 @@ static struct rds_connection *__rds_conn_create(__be32 laddr, __be32 faddr,
        if (conn)
                goto out;
 
+new_conn:
        conn = kmem_cache_zalloc(rds_conn_slab, gfp);
        if (!conn) {
                conn = ERR_PTR(-ENOMEM);
@@ -230,13 +234,22 @@ static struct rds_connection *__rds_conn_create(__be32 laddr, __be32 faddr,
                /* Creating normal conn */
                struct rds_connection *found;
 
-               found = rds_conn_lookup(head, laddr, faddr, trans);
+               if (!is_outgoing && otrans->t_type == RDS_TRANS_TCP)
+                       found = NULL;
+               else
+                       found = rds_conn_lookup(head, laddr, faddr, trans);
                if (found) {
                        trans->conn_free(conn->c_transport_data);
                        kmem_cache_free(rds_conn_slab, conn);
                        conn = found;
                } else {
-                       hlist_add_head_rcu(&conn->c_hash_node, head);
+                       if ((is_outgoing && otrans->t_type == RDS_TRANS_TCP) ||
+                           (otrans->t_type != RDS_TRANS_TCP)) {
+                               /* Only the active side should be added to
+                                * reconnect list for TCP.
+                                */
+                               hlist_add_head_rcu(&conn->c_hash_node, head);
+                       }
                        rds_cong_add_conn(conn);
                        rds_conn_count++;
                }
index 31b74f5e61adbd37535b636b1499c384bdd992f5..8a09ee7db3c13bdd833784c4ee311e048a7c2789 100644 (file)
@@ -183,8 +183,17 @@ void rds_ib_cm_connect_complete(struct rds_connection *conn, struct rdma_cm_even
 
        /* If the peer gave us the last packet it saw, process this as if
         * we had received a regular ACK. */
-       if (dp && dp->dp_ack_seq)
-               rds_send_drop_acked(conn, be64_to_cpu(dp->dp_ack_seq), NULL);
+       if (dp) {
+               /* dp structure start is not guaranteed to be 8 bytes aligned.
+                * Since dp_ack_seq is 64-bit extended load operations can be
+                * used so go through get_unaligned to avoid unaligned errors.
+                */
+               __be64 dp_ack_seq = get_unaligned(&dp->dp_ack_seq);
+
+               if (dp_ack_seq)
+                       rds_send_drop_acked(conn, be64_to_cpu(dp_ack_seq),
+                                           NULL);
+       }
 
        rds_connect_complete(conn);
 }
index f9f564a6c960e47b3c243d11a3e11317c5a56353..973109c7b8e86f21bec783eb9e4e118e6e8ebb8b 100644 (file)
@@ -62,6 +62,7 @@ void rds_tcp_state_change(struct sock *sk)
                case TCP_ESTABLISHED:
                        rds_connect_complete(conn);
                        break;
+               case TCP_CLOSE_WAIT:
                case TCP_CLOSE:
                        rds_conn_drop(conn);
                default:
index 23ab4dcd1d9f03942aa4d70bc7f6d9aa401f7707..0da49e34495f1e974bf466b83ba1144ec8965f61 100644 (file)
@@ -45,12 +45,45 @@ static void rds_tcp_accept_worker(struct work_struct *work);
 static DECLARE_WORK(rds_tcp_listen_work, rds_tcp_accept_worker);
 static struct socket *rds_tcp_listen_sock;
 
+static int rds_tcp_keepalive(struct socket *sock)
+{
+       /* values below based on xs_udp_default_timeout */
+       int keepidle = 5; /* send a probe 'keepidle' secs after last data */
+       int keepcnt = 5; /* number of unack'ed probes before declaring dead */
+       int keepalive = 1;
+       int ret = 0;
+
+       ret = kernel_setsockopt(sock, SOL_SOCKET, SO_KEEPALIVE,
+                               (char *)&keepalive, sizeof(keepalive));
+       if (ret < 0)
+               goto bail;
+
+       ret = kernel_setsockopt(sock, IPPROTO_TCP, TCP_KEEPCNT,
+                               (char *)&keepcnt, sizeof(keepcnt));
+       if (ret < 0)
+               goto bail;
+
+       ret = kernel_setsockopt(sock, IPPROTO_TCP, TCP_KEEPIDLE,
+                               (char *)&keepidle, sizeof(keepidle));
+       if (ret < 0)
+               goto bail;
+
+       /* KEEPINTVL is the interval between successive probes. We follow
+        * the model in xs_tcp_finish_connecting() and re-use keepidle.
+        */
+       ret = kernel_setsockopt(sock, IPPROTO_TCP, TCP_KEEPINTVL,
+                               (char *)&keepidle, sizeof(keepidle));
+bail:
+       return ret;
+}
+
 static int rds_tcp_accept_one(struct socket *sock)
 {
        struct socket *new_sock = NULL;
        struct rds_connection *conn;
        int ret;
        struct inet_sock *inet;
+       struct rds_tcp_connection *rs_tcp;
 
        ret = sock_create_lite(sock->sk->sk_family, sock->sk->sk_type,
                               sock->sk->sk_protocol, &new_sock);
@@ -63,6 +96,10 @@ static int rds_tcp_accept_one(struct socket *sock)
        if (ret < 0)
                goto out;
 
+       ret = rds_tcp_keepalive(new_sock);
+       if (ret < 0)
+               goto out;
+
        rds_tcp_tune(new_sock);
 
        inet = inet_sk(new_sock->sk);
@@ -77,6 +114,15 @@ static int rds_tcp_accept_one(struct socket *sock)
                ret = PTR_ERR(conn);
                goto out;
        }
+       /* An incoming SYN request came in, and TCP just accepted it.
+        * We always create a new conn for listen side of TCP, and do not
+        * add it to the c_hash_list.
+        *
+        * If the client reboots, this conn will need to be cleaned up.
+        * rds_tcp_state_change() will do that cleanup
+        */
+       rs_tcp = (struct rds_tcp_connection *)conn->c_transport_data;
+       WARN_ON(!rs_tcp || rs_tcp->t_sock);
 
        /*
         * see the comment above rds_queue_delayed_reconnect()
index 8e472518f9f6856dcd5802c16373b6579f7284eb..295d14bd6c678c31b56219371df83d4ebe3b0a2c 100644 (file)
@@ -63,7 +63,6 @@ static int tcf_connmark(struct sk_buff *skb, const struct tc_action *a,
                skb->mark = c->mark;
                /* using overlimits stats to count how many packets marked */
                ca->tcf_qstats.overlimits++;
-               nf_ct_put(c);
                goto out;
        }
 
@@ -82,7 +81,6 @@ static int tcf_connmark(struct sk_buff *skb, const struct tc_action *a,
        nf_ct_put(c);
 
 out:
-       skb->nfct = NULL;
        spin_unlock(&ca->tcf_lock);
        return ca->tcf_action;
 }
index 8b0470e418dc6e9475464768d629969087e66b37..a75864d93142153bfff4ab765620e10bcfab3e96 100644 (file)
@@ -81,6 +81,11 @@ int unregister_tcf_proto_ops(struct tcf_proto_ops *ops)
        struct tcf_proto_ops *t;
        int rc = -ENOENT;
 
+       /* Wait for outstanding call_rcu()s, if any, from a
+        * tcf_proto_ops's destroy() handler.
+        */
+       rcu_barrier();
+
        write_lock(&cls_mod_lock);
        list_for_each_entry(t, &tcf_proto_base, head) {
                if (t == ops) {
@@ -308,12 +313,11 @@ replay:
                case RTM_DELTFILTER:
                        err = tp->ops->delete(tp, fh);
                        if (err == 0) {
-                               tfilter_notify(net, skb, n, tp, fh, RTM_DELTFILTER);
-                               if (tcf_destroy(tp, false)) {
-                                       struct tcf_proto *next = rtnl_dereference(tp->next);
+                               struct tcf_proto *next = rtnl_dereference(tp->next);
 
+                               tfilter_notify(net, skb, n, tp, fh, RTM_DELTFILTER);
+                               if (tcf_destroy(tp, false))
                                        RCU_INIT_POINTER(*back, next);
-                               }
                        }
                        goto errout;
                case RTM_GETTFILTER:
index ad9eed70bc8f8e16c3118c6527374a952823e2c0..1e1c89e51a118e79610c49412e335191fc3ba834 100644 (file)
@@ -815,10 +815,8 @@ static int qdisc_graft(struct net_device *dev, struct Qdisc *parent,
                if (dev->flags & IFF_UP)
                        dev_deactivate(dev);
 
-               if (new && new->ops->attach) {
-                       new->ops->attach(new);
-                       num_q = 0;
-               }
+               if (new && new->ops->attach)
+                       goto skip;
 
                for (i = 0; i < num_q; i++) {
                        struct netdev_queue *dev_queue = dev_ingress_queue(dev);
@@ -834,12 +832,16 @@ static int qdisc_graft(struct net_device *dev, struct Qdisc *parent,
                                qdisc_destroy(old);
                }
 
+skip:
                if (!ingress) {
                        notify_and_destroy(net, skb, n, classid,
                                           dev->qdisc, new);
                        if (new && !new->ops->attach)
                                atomic_inc(&new->refcnt);
                        dev->qdisc = new ? : &noop_qdisc;
+
+                       if (new && new->ops->attach)
+                               new->ops->attach(new);
                } else {
                        notify_and_destroy(net, skb, n, classid, old, new);
                }
index de28f8e968e8176ac7630a1e6fcccb45ad295f5d..7a0bdb16ac92fd0a20f565295392bed8674c8d90 100644 (file)
@@ -164,7 +164,7 @@ static int codel_init(struct Qdisc *sch, struct nlattr *opt)
 
        sch->limit = DEFAULT_CODEL_LIMIT;
 
-       codel_params_init(&q->params);
+       codel_params_init(&q->params, sch);
        codel_vars_init(&q->vars);
        codel_stats_init(&q->stats);
 
index 1e52decb7b59cf0b4173d0f17efdab8fefee5f26..c244c45b78d7feca32fda3b925f7605aebf0a5b6 100644 (file)
@@ -391,7 +391,7 @@ static int fq_codel_init(struct Qdisc *sch, struct nlattr *opt)
        q->perturbation = prandom_u32();
        INIT_LIST_HEAD(&q->new_flows);
        INIT_LIST_HEAD(&q->old_flows);
-       codel_params_init(&q->cparams);
+       codel_params_init(&q->cparams, sch);
        codel_stats_init(&q->cstats);
        q->cparams.ecn = true;
 
index a4ca4517cdc82843e21e5245989a59e89aa53702..634529e0ce6bddc44b48161b6f76bd79af0a2a8e 100644 (file)
@@ -229,7 +229,7 @@ static int gred_enqueue(struct sk_buff *skb, struct Qdisc *sch)
                break;
        }
 
-       if (q->backlog + qdisc_pkt_len(skb) <= q->limit) {
+       if (gred_backlog(t, q, sch) + qdisc_pkt_len(skb) <= q->limit) {
                q->backlog += qdisc_pkt_len(skb);
                return qdisc_enqueue_tail(skb, sch);
        }
@@ -553,7 +553,7 @@ static int gred_dump(struct Qdisc *sch, struct sk_buff *skb)
 
                opt.limit       = q->limit;
                opt.DP          = q->DP;
-               opt.backlog     = q->backlog;
+               opt.backlog     = gred_backlog(table, q, sch);
                opt.prio        = q->prio;
                opt.qth_min     = q->parms.qth_min >> q->parms.Wlog;
                opt.qth_max     = q->parms.qth_max >> q->parms.Wlog;
index fb7976aee61c84f38aecdc5c5f0d8be20e577fa9..4f15b7d730e13d6aaa58ba7a28262c9831afea95 100644 (file)
@@ -381,13 +381,14 @@ nomem:
 }
 
 
-/* Public interface to creat the association shared key.
+/* Public interface to create the association shared key.
  * See code above for the algorithm.
  */
 int sctp_auth_asoc_init_active_key(struct sctp_association *asoc, gfp_t gfp)
 {
        struct sctp_auth_bytes  *secret;
        struct sctp_shared_key *ep_key;
+       struct sctp_chunk *chunk;
 
        /* If we don't support AUTH, or peer is not capable
         * we don't need to do anything.
@@ -410,6 +411,14 @@ int sctp_auth_asoc_init_active_key(struct sctp_association *asoc, gfp_t gfp)
        sctp_auth_key_put(asoc->asoc_shared_key);
        asoc->asoc_shared_key = secret;
 
+       /* Update send queue in case any chunk already in there now
+        * needs authenticating
+        */
+       list_for_each_entry(chunk, &asoc->outqueue.out_chunk_list, list) {
+               if (sctp_auth_send_cid(chunk->chunk_hdr->type, asoc))
+                       chunk->auth = 1;
+       }
+
        return 0;
 }
 
index 1ec19f6f0c2b9fe71ee9a7110873873274b9ab62..eeeba5adee6d939ab3429100d231a46e82b1ff94 100644 (file)
@@ -793,20 +793,26 @@ int gssx_dec_accept_sec_context(struct rpc_rqst *rqstp,
 {
        u32 value_follows;
        int err;
+       struct page *scratch;
+
+       scratch = alloc_page(GFP_KERNEL);
+       if (!scratch)
+               return -ENOMEM;
+       xdr_set_scratch_buffer(xdr, page_address(scratch), PAGE_SIZE);
 
        /* res->status */
        err = gssx_dec_status(xdr, &res->status);
        if (err)
-               return err;
+               goto out_free;
 
        /* res->context_handle */
        err = gssx_dec_bool(xdr, &value_follows);
        if (err)
-               return err;
+               goto out_free;
        if (value_follows) {
                err = gssx_dec_ctx(xdr, res->context_handle);
                if (err)
-                       return err;
+                       goto out_free;
        } else {
                res->context_handle = NULL;
        }
@@ -814,11 +820,11 @@ int gssx_dec_accept_sec_context(struct rpc_rqst *rqstp,
        /* res->output_token */
        err = gssx_dec_bool(xdr, &value_follows);
        if (err)
-               return err;
+               goto out_free;
        if (value_follows) {
                err = gssx_dec_buffer(xdr, res->output_token);
                if (err)
-                       return err;
+                       goto out_free;
        } else {
                res->output_token = NULL;
        }
@@ -826,14 +832,17 @@ int gssx_dec_accept_sec_context(struct rpc_rqst *rqstp,
        /* res->delegated_cred_handle */
        err = gssx_dec_bool(xdr, &value_follows);
        if (err)
-               return err;
+               goto out_free;
        if (value_follows) {
                /* we do not support upcall servers sending this data. */
-               return -EINVAL;
+               err = -EINVAL;
+               goto out_free;
        }
 
        /* res->options */
        err = gssx_dec_option_array(xdr, &res->options);
 
+out_free:
+       __free_page(scratch);
        return err;
 }
index 46568b85c3339f57a0d6835e82eff4b67c3ba326..055453d486683ec19433961db220292e4f60571d 100644 (file)
@@ -338,7 +338,7 @@ int netdev_switch_fib_ipv4_add(u32 dst, int dst_len, struct fib_info *fi,
                                              fi, tos, type, nlflags,
                                              tb_id);
                if (!err)
-                       fi->fib_flags |= RTNH_F_EXTERNAL;
+                       fi->fib_flags |= RTNH_F_OFFLOAD;
        }
 
        return err;
@@ -364,7 +364,7 @@ int netdev_switch_fib_ipv4_del(u32 dst, int dst_len, struct fib_info *fi,
        const struct swdev_ops *ops;
        int err = 0;
 
-       if (!(fi->fib_flags & RTNH_F_EXTERNAL))
+       if (!(fi->fib_flags & RTNH_F_OFFLOAD))
                return 0;
 
        dev = netdev_switch_get_dev_by_nhs(fi);
@@ -376,7 +376,7 @@ int netdev_switch_fib_ipv4_del(u32 dst, int dst_len, struct fib_info *fi,
                err = ops->swdev_fib_ipv4_del(dev, htonl(dst), dst_len,
                                              fi, tos, type, tb_id);
                if (!err)
-                       fi->fib_flags &= ~RTNH_F_EXTERNAL;
+                       fi->fib_flags &= ~RTNH_F_OFFLOAD;
        }
 
        return err;
index 3613e72e858e2e259bd91455127e4ec0af5c903b..70e3dacbf84ab7a899298fca1fdcb2e77fd0c2d5 100644 (file)
@@ -591,14 +591,14 @@ void tipc_bearer_stop(struct net *net)
 
 /* Caller should hold rtnl_lock to protect the bearer */
 static int __tipc_nl_add_bearer(struct tipc_nl_msg *msg,
-                               struct tipc_bearer *bearer)
+                               struct tipc_bearer *bearer, int nlflags)
 {
        void *hdr;
        struct nlattr *attrs;
        struct nlattr *prop;
 
        hdr = genlmsg_put(msg->skb, msg->portid, msg->seq, &tipc_genl_family,
-                         NLM_F_MULTI, TIPC_NL_BEARER_GET);
+                         nlflags, TIPC_NL_BEARER_GET);
        if (!hdr)
                return -EMSGSIZE;
 
@@ -657,7 +657,7 @@ int tipc_nl_bearer_dump(struct sk_buff *skb, struct netlink_callback *cb)
                if (!bearer)
                        continue;
 
-               err = __tipc_nl_add_bearer(&msg, bearer);
+               err = __tipc_nl_add_bearer(&msg, bearer, NLM_F_MULTI);
                if (err)
                        break;
        }
@@ -705,7 +705,7 @@ int tipc_nl_bearer_get(struct sk_buff *skb, struct genl_info *info)
                goto err_out;
        }
 
-       err = __tipc_nl_add_bearer(&msg, bearer);
+       err = __tipc_nl_add_bearer(&msg, bearer, 0);
        if (err)
                goto err_out;
        rtnl_unlock();
@@ -857,14 +857,14 @@ int tipc_nl_bearer_set(struct sk_buff *skb, struct genl_info *info)
 }
 
 static int __tipc_nl_add_media(struct tipc_nl_msg *msg,
-                              struct tipc_media *media)
+                              struct tipc_media *media, int nlflags)
 {
        void *hdr;
        struct nlattr *attrs;
        struct nlattr *prop;
 
        hdr = genlmsg_put(msg->skb, msg->portid, msg->seq, &tipc_genl_family,
-                         NLM_F_MULTI, TIPC_NL_MEDIA_GET);
+                         nlflags, TIPC_NL_MEDIA_GET);
        if (!hdr)
                return -EMSGSIZE;
 
@@ -916,7 +916,8 @@ int tipc_nl_media_dump(struct sk_buff *skb, struct netlink_callback *cb)
 
        rtnl_lock();
        for (; media_info_array[i] != NULL; i++) {
-               err = __tipc_nl_add_media(&msg, media_info_array[i]);
+               err = __tipc_nl_add_media(&msg, media_info_array[i],
+                                         NLM_F_MULTI);
                if (err)
                        break;
        }
@@ -963,7 +964,7 @@ int tipc_nl_media_get(struct sk_buff *skb, struct genl_info *info)
                goto err_out;
        }
 
-       err = __tipc_nl_add_media(&msg, media);
+       err = __tipc_nl_add_media(&msg, media, 0);
        if (err)
                goto err_out;
        rtnl_unlock();
index a6b30df6ec02ec22f1b4b44930bd1ceb168258f3..43a515dc97b0d4a2c7fca5bc9dc2951175201fff 100644 (file)
@@ -1145,11 +1145,8 @@ void tipc_rcv(struct net *net, struct sk_buff *skb, struct tipc_bearer *b_ptr)
                }
                /* Synchronize with parallel link if applicable */
                if (unlikely((l_ptr->flags & LINK_SYNCHING) && !msg_dup(msg))) {
-                       link_handle_out_of_seq_msg(l_ptr, skb);
-                       if (link_synch(l_ptr))
-                               link_retrieve_defq(l_ptr, &head);
-                       skb = NULL;
-                       goto unlock;
+                       if (!link_synch(l_ptr))
+                               goto unlock;
                }
                l_ptr->next_in_no++;
                if (unlikely(!skb_queue_empty(&l_ptr->deferdq)))
@@ -2013,7 +2010,7 @@ msg_full:
 
 /* Caller should hold appropriate locks to protect the link */
 static int __tipc_nl_add_link(struct net *net, struct tipc_nl_msg *msg,
-                             struct tipc_link *link)
+                             struct tipc_link *link, int nlflags)
 {
        int err;
        void *hdr;
@@ -2022,7 +2019,7 @@ static int __tipc_nl_add_link(struct net *net, struct tipc_nl_msg *msg,
        struct tipc_net *tn = net_generic(net, tipc_net_id);
 
        hdr = genlmsg_put(msg->skb, msg->portid, msg->seq, &tipc_genl_family,
-                         NLM_F_MULTI, TIPC_NL_LINK_GET);
+                         nlflags, TIPC_NL_LINK_GET);
        if (!hdr)
                return -EMSGSIZE;
 
@@ -2095,7 +2092,7 @@ static int __tipc_nl_add_node_links(struct net *net, struct tipc_nl_msg *msg,
                if (!node->links[i])
                        continue;
 
-               err = __tipc_nl_add_link(net, msg, node->links[i]);
+               err = __tipc_nl_add_link(net, msg, node->links[i], NLM_F_MULTI);
                if (err)
                        return err;
        }
@@ -2143,7 +2140,6 @@ int tipc_nl_link_dump(struct sk_buff *skb, struct netlink_callback *cb)
                        err = __tipc_nl_add_node_links(net, &msg, node,
                                                       &prev_link);
                        tipc_node_unlock(node);
-                       tipc_node_put(node);
                        if (err)
                                goto out;
 
@@ -2210,7 +2206,7 @@ int tipc_nl_link_get(struct sk_buff *skb, struct genl_info *info)
                goto err_out;
        }
 
-       err = __tipc_nl_add_link(net, &msg, link);
+       err = __tipc_nl_add_link(net, &msg, link, 0);
        if (err)
                goto err_out;
 
index ab6183cdb12113565e3575e746470d5564f2ce22..77ff03ed1e18d13224f086c2315d7123cc931123 100644 (file)
@@ -102,7 +102,7 @@ static void tipc_conn_kref_release(struct kref *kref)
                }
                saddr->scope = -TIPC_NODE_SCOPE;
                kernel_bind(sock, (struct sockaddr *)saddr, sizeof(*saddr));
-               sk_release_kernel(sk);
+               sock_release(sock);
                con->sock = NULL;
        }
 
@@ -321,12 +321,9 @@ static struct socket *tipc_create_listen_sock(struct tipc_conn *con)
        struct socket *sock = NULL;
        int ret;
 
-       ret = sock_create_kern(AF_TIPC, SOCK_SEQPACKET, 0, &sock);
+       ret = __sock_create(s->net, AF_TIPC, SOCK_SEQPACKET, 0, &sock, 1);
        if (ret < 0)
                return NULL;
-
-       sk_change_net(sock->sk, s->net);
-
        ret = kernel_setsockopt(sock, SOL_TIPC, TIPC_IMPORTANCE,
                                (char *)&s->imp, sizeof(s->imp));
        if (ret < 0)
@@ -376,7 +373,7 @@ static struct socket *tipc_create_listen_sock(struct tipc_conn *con)
 
 create_err:
        kernel_sock_shutdown(sock, SHUT_RDWR);
-       sk_release_kernel(sock->sk);
+       sock_release(sock);
        return NULL;
 }
 
index ee90d74d7516e93af0587f5898d81e41f870e267..f485600c4507bc152cef654ae5667a03a52d990c 100644 (file)
@@ -1764,13 +1764,14 @@ static int tipc_sk_enqueue(struct sk_buff_head *inputq, struct sock *sk,
 int tipc_sk_rcv(struct net *net, struct sk_buff_head *inputq)
 {
        u32 dnode, dport = 0;
-       int err = -TIPC_ERR_NO_PORT;
+       int err;
        struct sk_buff *skb;
        struct tipc_sock *tsk;
        struct tipc_net *tn;
        struct sock *sk;
 
        while (skb_queue_len(inputq)) {
+               err = -TIPC_ERR_NO_PORT;
                skb = NULL;
                dport = tipc_skb_peek_port(inputq, dport);
                tsk = tipc_sk_lookup(net, dport);
@@ -2141,11 +2142,17 @@ static void tipc_sk_timeout(unsigned long data)
        peer_node = tsk_peer_node(tsk);
 
        if (tsk->probing_state == TIPC_CONN_PROBING) {
-               /* Previous probe not answered -> self abort */
-               skb = tipc_msg_create(TIPC_CRITICAL_IMPORTANCE,
-                                     TIPC_CONN_MSG, SHORT_H_SIZE, 0,
-                                     own_node, peer_node, tsk->portid,
-                                     peer_port, TIPC_ERR_NO_PORT);
+               if (!sock_owned_by_user(sk)) {
+                       sk->sk_socket->state = SS_DISCONNECTING;
+                       tsk->connected = 0;
+                       tipc_node_remove_conn(sock_net(sk), tsk_peer_node(tsk),
+                                             tsk_peer_port(tsk));
+                       sk->sk_state_change(sk);
+               } else {
+                       /* Try again later */
+                       sk_reset_timer(sk, &sk->sk_timer, (HZ / 20));
+               }
+
        } else {
                skb = tipc_msg_create(CONN_MANAGER, CONN_PROBE,
                                      INT_H_SIZE, 0, peer_node, own_node,
index 5266ea7b922b76d1977dea57cc7c227594c49285..06430598cf512fdaff480671620e8fa69c259bb5 100644 (file)
@@ -1880,6 +1880,10 @@ static long unix_stream_data_wait(struct sock *sk, long timeo,
                unix_state_unlock(sk);
                timeo = freezable_schedule_timeout(timeo);
                unix_state_lock(sk);
+
+               if (sock_flag(sk, SOCK_DEAD))
+                       break;
+
                clear_bit(SOCK_ASYNC_WAITDATA, &sk->sk_socket->flags);
        }
 
@@ -1939,6 +1943,10 @@ static int unix_stream_recvmsg(struct socket *sock, struct msghdr *msg,
                struct sk_buff *skb, *last;
 
                unix_state_lock(sk);
+               if (sock_flag(sk, SOCK_DEAD)) {
+                       err = -ECONNRESET;
+                       goto unlock;
+               }
                last = skb = skb_peek(&sk->sk_receive_queue);
 again:
                if (skb == NULL) {
index 99f7012b23b9f2101bc8b3a35ed27871a7835b1d..a73a226f2d33f07261f606fa84ef4db8b91ed6fc 100644 (file)
@@ -95,39 +95,36 @@ static DECLARE_WAIT_QUEUE_HEAD(unix_gc_wait);
 
 unsigned int unix_tot_inflight;
 
-
 struct sock *unix_get_socket(struct file *filp)
 {
        struct sock *u_sock = NULL;
        struct inode *inode = file_inode(filp);
 
-       /*
-        *      Socket ?
-        */
+       /* Socket ? */
        if (S_ISSOCK(inode->i_mode) && !(filp->f_mode & FMODE_PATH)) {
                struct socket *sock = SOCKET_I(inode);
                struct sock *s = sock->sk;
 
-               /*
-                *      PF_UNIX ?
-                */
+               /* PF_UNIX ? */
                if (s && sock->ops && sock->ops->family == PF_UNIX)
                        u_sock = s;
        }
        return u_sock;
 }
 
-/*
- *     Keep the number of times in flight count for the file
- *     descriptor if it is for an AF_UNIX socket.
+/* Keep the number of times in flight count for the file
+ * descriptor if it is for an AF_UNIX socket.
  */
 
 void unix_inflight(struct file *fp)
 {
        struct sock *s = unix_get_socket(fp);
+
        if (s) {
                struct unix_sock *u = unix_sk(s);
+
                spin_lock(&unix_gc_lock);
+
                if (atomic_long_inc_return(&u->inflight) == 1) {
                        BUG_ON(!list_empty(&u->link));
                        list_add_tail(&u->link, &gc_inflight_list);
@@ -142,10 +139,13 @@ void unix_inflight(struct file *fp)
 void unix_notinflight(struct file *fp)
 {
        struct sock *s = unix_get_socket(fp);
+
        if (s) {
                struct unix_sock *u = unix_sk(s);
+
                spin_lock(&unix_gc_lock);
                BUG_ON(list_empty(&u->link));
+
                if (atomic_long_dec_and_test(&u->inflight))
                        list_del_init(&u->link);
                unix_tot_inflight--;
@@ -161,32 +161,27 @@ static void scan_inflight(struct sock *x, void (*func)(struct unix_sock *),
 
        spin_lock(&x->sk_receive_queue.lock);
        skb_queue_walk_safe(&x->sk_receive_queue, skb, next) {
-               /*
-                *      Do we have file descriptors ?
-                */
+               /* Do we have file descriptors ? */
                if (UNIXCB(skb).fp) {
                        bool hit = false;
-                       /*
-                        *      Process the descriptors of this socket
-                        */
+                       /* Process the descriptors of this socket */
                        int nfd = UNIXCB(skb).fp->count;
                        struct file **fp = UNIXCB(skb).fp->fp;
+
                        while (nfd--) {
-                               /*
-                                *      Get the socket the fd matches
-                                *      if it indeed does so
-                                */
+                               /* Get the socket the fd matches if it indeed does so */
                                struct sock *sk = unix_get_socket(*fp++);
+
                                if (sk) {
                                        struct unix_sock *u = unix_sk(sk);
 
-                                       /*
-                                        * Ignore non-candidates, they could
+                                       /* Ignore non-candidates, they could
                                         * have been added to the queues after
                                         * starting the garbage collection
                                         */
                                        if (test_bit(UNIX_GC_CANDIDATE, &u->gc_flags)) {
                                                hit = true;
+
                                                func(u);
                                        }
                                }
@@ -203,24 +198,22 @@ static void scan_inflight(struct sock *x, void (*func)(struct unix_sock *),
 static void scan_children(struct sock *x, void (*func)(struct unix_sock *),
                          struct sk_buff_head *hitlist)
 {
-       if (x->sk_state != TCP_LISTEN)
+       if (x->sk_state != TCP_LISTEN) {
                scan_inflight(x, func, hitlist);
-       else {
+       else {
                struct sk_buff *skb;
                struct sk_buff *next;
                struct unix_sock *u;
                LIST_HEAD(embryos);
 
-               /*
-                * For a listening socket collect the queued embryos
+               /* For a listening socket collect the queued embryos
                 * and perform a scan on them as well.
                 */
                spin_lock(&x->sk_receive_queue.lock);
                skb_queue_walk_safe(&x->sk_receive_queue, skb, next) {
                        u = unix_sk(skb->sk);
 
-                       /*
-                        * An embryo cannot be in-flight, so it's safe
+                       /* An embryo cannot be in-flight, so it's safe
                         * to use the list link.
                         */
                        BUG_ON(!list_empty(&u->link));
@@ -249,8 +242,7 @@ static void inc_inflight(struct unix_sock *usk)
 static void inc_inflight_move_tail(struct unix_sock *u)
 {
        atomic_long_inc(&u->inflight);
-       /*
-        * If this still might be part of a cycle, move it to the end
+       /* If this still might be part of a cycle, move it to the end
         * of the list, so that it's checked even if it was already
         * passed over
         */
@@ -263,8 +255,7 @@ static bool gc_in_progress;
 
 void wait_for_unix_gc(void)
 {
-       /*
-        * If number of inflight sockets is insane,
+       /* If number of inflight sockets is insane,
         * force a garbage collect right now.
         */
        if (unix_tot_inflight > UNIX_INFLIGHT_TRIGGER_GC && !gc_in_progress)
@@ -288,8 +279,7 @@ void unix_gc(void)
                goto out;
 
        gc_in_progress = true;
-       /*
-        * First, select candidates for garbage collection.  Only
+       /* First, select candidates for garbage collection.  Only
         * in-flight sockets are considered, and from those only ones
         * which don't have any external reference.
         *
@@ -320,15 +310,13 @@ void unix_gc(void)
                }
        }
 
-       /*
-        * Now remove all internal in-flight reference to children of
+       /* Now remove all internal in-flight reference to children of
         * the candidates.
         */
        list_for_each_entry(u, &gc_candidates, link)
                scan_children(&u->sk, dec_inflight, NULL);
 
-       /*
-        * Restore the references for children of all candidates,
+       /* Restore the references for children of all candidates,
         * which have remaining references.  Do this recursively, so
         * only those remain, which form cyclic references.
         *
@@ -350,8 +338,7 @@ void unix_gc(void)
        }
        list_del(&cursor);
 
-       /*
-        * not_cycle_list contains those sockets which do not make up a
+       /* not_cycle_list contains those sockets which do not make up a
         * cycle.  Restore these to the inflight list.
         */
        while (!list_empty(&not_cycle_list)) {
@@ -360,8 +347,7 @@ void unix_gc(void)
                list_move_tail(&u->link, &gc_inflight_list);
        }
 
-       /*
-        * Now gc_candidates contains only garbage.  Restore original
+       /* Now gc_candidates contains only garbage.  Restore original
         * inflight counters for these as well, and remove the skbuffs
         * which are creating the cycle(s).
         */
index fff1bef6ed6d916f9019a63d708652f4ab07cddf..fd682832a0e3635d52c734871d5402d270336dc3 100644 (file)
@@ -1333,6 +1333,8 @@ static struct iw_statistics *cfg80211_wireless_stats(struct net_device *dev)
        memcpy(bssid, wdev->current_bss->pub.bssid, ETH_ALEN);
        wdev_unlock(wdev);
 
+       memset(&sinfo, 0, sizeof(sinfo));
+
        if (rdev_get_station(rdev, dev, bssid, &sinfo))
                return NULL;
 
index 526c4feb3b50d723d24b8c55288c8c941257da52..b58286ecd156fdb9de2a33ca0ede0fe3194bf289 100644 (file)
@@ -13,6 +13,8 @@
 #include <net/dst.h>
 #include <net/ip.h>
 #include <net/xfrm.h>
+#include <net/ip_tunnels.h>
+#include <net/ip6_tunnel.h>
 
 static struct kmem_cache *secpath_cachep __read_mostly;
 
@@ -186,6 +188,7 @@ int xfrm_input(struct sk_buff *skb, int nexthdr, __be32 spi, int encap_type)
        struct xfrm_state *x = NULL;
        xfrm_address_t *daddr;
        struct xfrm_mode *inner_mode;
+       u32 mark = skb->mark;
        unsigned int family;
        int decaps = 0;
        int async = 0;
@@ -203,6 +206,18 @@ int xfrm_input(struct sk_buff *skb, int nexthdr, __be32 spi, int encap_type)
                                   XFRM_SPI_SKB_CB(skb)->daddroff);
        family = XFRM_SPI_SKB_CB(skb)->family;
 
+       /* if tunnel is present override skb->mark value with tunnel i_key */
+       if (XFRM_TUNNEL_SKB_CB(skb)->tunnel.ip4) {
+               switch (family) {
+               case AF_INET:
+                       mark = be32_to_cpu(XFRM_TUNNEL_SKB_CB(skb)->tunnel.ip4->parms.i_key);
+                       break;
+               case AF_INET6:
+                       mark = be32_to_cpu(XFRM_TUNNEL_SKB_CB(skb)->tunnel.ip6->parms.i_key);
+                       break;
+               }
+       }
+
        /* Allocate new secpath or COW existing one. */
        if (!skb->sp || atomic_read(&skb->sp->refcnt) != 1) {
                struct sec_path *sp;
@@ -229,7 +244,7 @@ int xfrm_input(struct sk_buff *skb, int nexthdr, __be32 spi, int encap_type)
                        goto drop;
                }
 
-               x = xfrm_state_lookup(net, skb->mark, daddr, spi, nexthdr, family);
+               x = xfrm_state_lookup(net, mark, daddr, spi, nexthdr, family);
                if (x == NULL) {
                        XFRM_INC_STATS(net, LINUX_MIB_XFRMINNOSTATES);
                        xfrm_audit_state_notfound(skb, family, spi, seq);
index dab57daae40856030790fa8070068a59d82220af..4fd725a0c500ebf69a02e06fcf37ae3035ae0d98 100644 (file)
@@ -99,6 +99,7 @@ static int xfrm_replay_overflow(struct xfrm_state *x, struct sk_buff *skb)
 
        if (x->type->flags & XFRM_TYPE_REPLAY_PROT) {
                XFRM_SKB_CB(skb)->seq.output.low = ++x->replay.oseq;
+               XFRM_SKB_CB(skb)->seq.output.hi = 0;
                if (unlikely(x->replay.oseq == 0)) {
                        x->replay.oseq--;
                        xfrm_audit_state_replay_overflow(x, skb);
@@ -177,6 +178,7 @@ static int xfrm_replay_overflow_bmp(struct xfrm_state *x, struct sk_buff *skb)
 
        if (x->type->flags & XFRM_TYPE_REPLAY_PROT) {
                XFRM_SKB_CB(skb)->seq.output.low = ++replay_esn->oseq;
+               XFRM_SKB_CB(skb)->seq.output.hi = 0;
                if (unlikely(replay_esn->oseq == 0)) {
                        replay_esn->oseq--;
                        xfrm_audit_state_replay_overflow(x, skb);
index f5e39e35d73aa96c3551b0e46f9b26ab291d23aa..96688cd0f6f11bddee4451de1d09a9a8e5f212dd 100644 (file)
@@ -927,8 +927,8 @@ struct xfrm_state *xfrm_state_lookup_byspi(struct net *net, __be32 spi,
                        x->id.spi != spi)
                        continue;
 
-               spin_unlock_bh(&net->xfrm.xfrm_state_lock);
                xfrm_state_hold(x);
+               spin_unlock_bh(&net->xfrm.xfrm_state_lock);
                return x;
        }
        spin_unlock_bh(&net->xfrm.xfrm_state_lock);
index 89b1df4e72ab3423bce45011fb03f86c193f5ad4..c5ec977b9c3786097b214e1c835efd8fa337c173 100755 (executable)
@@ -3169,12 +3169,12 @@ sub process {
                }
 
 # check for global initialisers.
-               if ($line =~ /^\+(\s*$Type\s*$Ident\s*(?:\s+$Modifier))*\s*=\s*(0|NULL|false)\s*;/) {
+               if ($line =~ /^\+$Type\s*$Ident(?:\s+$Modifier)*\s*=\s*(?:0|NULL|false)\s*;/) {
                        if (ERROR("GLOBAL_INITIALISERS",
                                  "do not initialise globals to 0 or NULL\n" .
                                      $herecurr) &&
                            $fix) {
-                               $fixed[$fixlinenr] =~ s/($Type\s*$Ident\s*(?:\s+$Modifier))*\s*=\s*(0|NULL|false)\s*;/$1;/;
+                               $fixed[$fixlinenr] =~ s/(^.$Type\s*$Ident(?:\s+$Modifier)*)\s*=\s*(0|NULL|false)\s*;/$1;/;
                        }
                }
 # check for static initialisers.
index a1504c4f19003d6d4a57971471b2d873f4e2bb09..25db8cff44a2036c0ecf1da69c3da5c0d567b782 100644 (file)
@@ -73,18 +73,11 @@ class LxLsmod(gdb.Command):
                 "        " if utils.get_long_type().sizeof == 8 else ""))
 
         for module in module_list():
-            ref = 0
-            module_refptr = module['refptr']
-            for cpu in cpus.cpu_list("cpu_possible_mask"):
-                refptr = cpus.per_cpu(module_refptr, cpu)
-                ref += refptr['incs']
-                ref -= refptr['decs']
-
             gdb.write("{address} {name:<19} {size:>8}  {ref}".format(
                 address=str(module['module_core']).split()[0],
                 name=module['name'].string(),
                 size=str(module['core_size']),
-                ref=str(ref)))
+                ref=str(module['refcnt']['counter'])))
 
             source_list = module['source_list']
             t = self._module_use_type.get_type().pointer()
index cf4cedf2b420f12de4d46cf702fabeab2c136b02..6dad042630d8c4ab22f2e9c2f4a98823d1c5092f 100644 (file)
@@ -916,7 +916,6 @@ static struct ac97c_platform_data *atmel_ac97c_probe_dt(struct device *dev)
 {
        struct ac97c_platform_data *pdata;
        struct device_node *node = dev->of_node;
-       const struct of_device_id *match;
 
        if (!node) {
                dev_err(dev, "Device does not have associated DT data\n");
index ac6b33f3779c2ee8a08fe80aa64172d3858d452b..7d45645f10ba99e33b54b3218559778db3aca36a 100644 (file)
@@ -339,7 +339,7 @@ static int snd_pcm_update_hw_ptr0(struct snd_pcm_substream *substream,
                if (delta > new_hw_ptr) {
                        /* check for double acknowledged interrupts */
                        hdelta = curr_jiffies - runtime->hw_ptr_jiffies;
-                       if (hdelta > runtime->hw_ptr_buffer_jiffies/2) {
+                       if (hdelta > runtime->hw_ptr_buffer_jiffies/2 + 1) {
                                hw_base += runtime->buffer_size;
                                if (hw_base >= runtime->boundary) {
                                        hw_base = 0;
index 7371e0c3926f32a9104b521d0bf70f1c35f0740f..1eabcdf69457311129b766ec237d37e402f640bc 100644 (file)
@@ -246,6 +246,9 @@ static int hda_reg_read(void *context, unsigned int reg, unsigned int *val)
                return hda_reg_read_stereo_amp(codec, reg, val);
        if (verb == AC_VERB_GET_PROC_COEF)
                return hda_reg_read_coef(codec, reg, val);
+       if ((verb & 0x700) == AC_VERB_SET_AMP_GAIN_MUTE)
+               reg &= ~AC_AMP_FAKE_MUTE;
+
        err = snd_hdac_exec_verb(codec, reg, 0, val);
        if (err < 0)
                return err;
@@ -265,6 +268,9 @@ static int hda_reg_write(void *context, unsigned int reg, unsigned int val)
        unsigned int verb;
        int i, bytes, err;
 
+       if (codec->caps_overwriting)
+               return 0;
+
        reg &= ~0x00080000U; /* drop GET bit */
        reg |= (codec->addr << 28);
        verb = get_verb(reg);
@@ -280,6 +286,8 @@ static int hda_reg_write(void *context, unsigned int reg, unsigned int val)
 
        switch (verb & 0xf00) {
        case AC_VERB_SET_AMP_GAIN_MUTE:
+               if ((reg & AC_AMP_FAKE_MUTE) && (val & AC_AMP_MUTE))
+                       val = 0;
                verb = AC_VERB_SET_AMP_GAIN_MUTE;
                if (reg & AC_AMP_GET_LEFT)
                        verb |= AC_AMP_SET_LEFT >> 8;
index 37d0220a094cb55451cff620c5e455f83d8a894d..db7a2e5e4a14ee6d7d110206aa94d7d71002066a 100644 (file)
@@ -183,8 +183,10 @@ static int snd_card_emu10k1_probe(struct pci_dev *pci,
        }
 #endif
  
-       strcpy(card->driver, emu->card_capabilities->driver);
-       strcpy(card->shortname, emu->card_capabilities->name);
+       strlcpy(card->driver, emu->card_capabilities->driver,
+               sizeof(card->driver));
+       strlcpy(card->shortname, emu->card_capabilities->name,
+               sizeof(card->shortname));
        snprintf(card->longname, sizeof(card->longname),
                 "%s (rev.%d, serial:0x%x) at 0x%lx, irq %i",
                 card->shortname, emu->revision, emu->serial, emu->port, emu->irq);
index 874cd76c7b7fb09b5c6c3cc722173914280b45ce..d2c7ea3a7610861a15730bb3a8b0c8764205fd5a 100644 (file)
@@ -415,7 +415,7 @@ start_voice(struct snd_emux_voice *vp)
        snd_emu10k1_ptr_write(hw, Z2, ch, 0);
 
        /* invalidate maps */
-       temp = (hw->silent_page.addr << 1) | MAP_PTI_MASK;
+       temp = (hw->silent_page.addr << hw->address_mode) | (hw->address_mode ? MAP_PTI_MASK1 : MAP_PTI_MASK0);
        snd_emu10k1_ptr_write(hw, MAPA, ch, temp);
        snd_emu10k1_ptr_write(hw, MAPB, ch, temp);
 #if 0
@@ -436,7 +436,7 @@ start_voice(struct snd_emux_voice *vp)
                snd_emu10k1_ptr_write(hw, CDF, ch, sample);
 
                /* invalidate maps */
-               temp = ((unsigned int)hw->silent_page.addr << 1) | MAP_PTI_MASK;
+               temp = ((unsigned int)hw->silent_page.addr << hw_address_mode) | (hw->address_mode ? MAP_PTI_MASK1 : MAP_PTI_MASK0);
                snd_emu10k1_ptr_write(hw, MAPA, ch, temp);
                snd_emu10k1_ptr_write(hw, MAPB, ch, temp);
                
index 54079f5d5673951ad739c81e2e679d3864f0ea79..a4548147c6215e788bc6cd9ead8357cb72658f8a 100644 (file)
@@ -282,7 +282,7 @@ static int snd_emu10k1_init(struct snd_emu10k1 *emu, int enable_ir, int resume)
        snd_emu10k1_ptr_write(emu, TCB, 0, 0);  /* taken from original driver */
        snd_emu10k1_ptr_write(emu, TCBS, 0, 4); /* taken from original driver */
 
-       silent_page = (emu->silent_page.addr << 1) | MAP_PTI_MASK;
+       silent_page = (emu->silent_page.addr << emu->address_mode) | (emu->address_mode ? MAP_PTI_MASK1 : MAP_PTI_MASK0);
        for (ch = 0; ch < NUM_G; ch++) {
                snd_emu10k1_ptr_write(emu, MAPA, ch, silent_page);
                snd_emu10k1_ptr_write(emu, MAPB, ch, silent_page);
@@ -348,6 +348,11 @@ static int snd_emu10k1_init(struct snd_emu10k1 *emu, int enable_ir, int resume)
                outl(reg | A_IOCFG_GPOUT0, emu->port + A_IOCFG);
        }
 
+       if (emu->address_mode == 0) {
+               /* use 16M in 4G */
+               outl(inl(emu->port + HCFG) | HCFG_EXPANDED_MEM, emu->port + HCFG);
+       }
+
        return 0;
 }
 
@@ -1446,7 +1451,7 @@ static struct snd_emu_chip_details emu_chip_details[] = {
         *
         */
        {.vendor = 0x1102, .device = 0x0008, .subsystem = 0x20011102,
-        .driver = "Audigy2", .name = "SB Audigy 2 ZS Notebook [SB0530]",
+        .driver = "Audigy2", .name = "Audigy 2 ZS Notebook [SB0530]",
         .id = "Audigy2",
         .emu10k2_chip = 1,
         .ca0108_chip = 1,
@@ -1596,7 +1601,7 @@ static struct snd_emu_chip_details emu_chip_details[] = {
         .adc_1361t = 1,  /* 24 bit capture instead of 16bit */
         .ac97_chip = 1} ,
        {.vendor = 0x1102, .device = 0x0004, .subsystem = 0x10051102,
-        .driver = "Audigy2", .name = "SB Audigy 2 Platinum EX [SB0280]",
+        .driver = "Audigy2", .name = "Audigy 2 Platinum EX [SB0280]",
         .id = "Audigy2",
         .emu10k2_chip = 1,
         .ca0102_chip = 1,
@@ -1902,8 +1907,10 @@ int snd_emu10k1_create(struct snd_card *card,
 
        is_audigy = emu->audigy = c->emu10k2_chip;
 
+       /* set addressing mode */
+       emu->address_mode = is_audigy ? 0 : 1;
        /* set the DMA transfer mask */
-       emu->dma_mask = is_audigy ? AUDIGY_DMA_MASK : EMU10K1_DMA_MASK;
+       emu->dma_mask = emu->address_mode ? EMU10K1_DMA_MASK : AUDIGY_DMA_MASK;
        if (pci_set_dma_mask(pci, emu->dma_mask) < 0 ||
            pci_set_consistent_dma_mask(pci, emu->dma_mask) < 0) {
                dev_err(card->dev,
@@ -1928,7 +1935,7 @@ int snd_emu10k1_create(struct snd_card *card,
 
        emu->max_cache_pages = max_cache_bytes >> PAGE_SHIFT;
        if (snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(pci),
-                               32 * 1024, &emu->ptb_pages) < 0) {
+                               (emu->address_mode ? 32 : 16) * 1024, &emu->ptb_pages) < 0) {
                err = -ENOMEM;
                goto error;
        }
@@ -2027,8 +2034,8 @@ int snd_emu10k1_create(struct snd_card *card,
 
        /* Clear silent pages and set up pointers */
        memset(emu->silent_page.area, 0, PAGE_SIZE);
-       silent_page = emu->silent_page.addr << 1;
-       for (idx = 0; idx < MAXPAGES; idx++)
+       silent_page = emu->silent_page.addr << emu->address_mode;
+       for (idx = 0; idx < (emu->address_mode ? MAXPAGES1 : MAXPAGES0); idx++)
                ((u32 *)emu->ptb_pages.area)[idx] = cpu_to_le32(silent_page | idx);
 
        /* set up voice indices */
index 0dc07385af0ebaee5ea66126bf8d758e17f71054..14a305bd8a98577cf50ecad28090996714b2034b 100644 (file)
@@ -380,7 +380,7 @@ static void snd_emu10k1_pcm_init_voice(struct snd_emu10k1 *emu,
        snd_emu10k1_ptr_write(emu, Z1, voice, 0);
        snd_emu10k1_ptr_write(emu, Z2, voice, 0);
        /* invalidate maps */
-       silent_page = ((unsigned int)emu->silent_page.addr << 1) | MAP_PTI_MASK;
+       silent_page = ((unsigned int)emu->silent_page.addr << emu->address_mode) | (emu->address_mode ? MAP_PTI_MASK1 : MAP_PTI_MASK0);
        snd_emu10k1_ptr_write(emu, MAPA, voice, silent_page);
        snd_emu10k1_ptr_write(emu, MAPB, voice, silent_page);
        /* modulation envelope */
index c68e6dd2fa6772fc88cae359b1b7947f1c4e9796..4f1f69be18651b7c692f9feb812c239e8f911386 100644 (file)
  * aligned pages in others
  */
 #define __set_ptb_entry(emu,page,addr) \
-       (((u32 *)(emu)->ptb_pages.area)[page] = cpu_to_le32(((addr) << 1) | (page)))
+       (((u32 *)(emu)->ptb_pages.area)[page] = cpu_to_le32(((addr) << (emu->address_mode)) | (page)))
 
 #define UNIT_PAGES             (PAGE_SIZE / EMUPAGESIZE)
-#define MAX_ALIGN_PAGES                (MAXPAGES / UNIT_PAGES)
+#define MAX_ALIGN_PAGES0               (MAXPAGES0 / UNIT_PAGES)
+#define MAX_ALIGN_PAGES1               (MAXPAGES1 / UNIT_PAGES)
 /* get aligned page from offset address */
 #define get_aligned_page(offset)       ((offset) >> PAGE_SHIFT)
 /* get offset address from aligned page */
@@ -124,7 +125,7 @@ static int search_empty_map_area(struct snd_emu10k1 *emu, int npages, struct lis
                }
                page = blk->mapped_page + blk->pages;
        }
-       size = MAX_ALIGN_PAGES - page;
+       size = (emu->address_mode ? MAX_ALIGN_PAGES1 : MAX_ALIGN_PAGES0) - page;
        if (size >= max_size) {
                *nextp = pos;
                return page;
@@ -181,7 +182,7 @@ static int unmap_memblk(struct snd_emu10k1 *emu, struct snd_emu10k1_memblk *blk)
                q = get_emu10k1_memblk(p, mapped_link);
                end_page = q->mapped_page;
        } else
-               end_page = MAX_ALIGN_PAGES;
+               end_page = (emu->address_mode ? MAX_ALIGN_PAGES1 : MAX_ALIGN_PAGES0);
 
        /* remove links */
        list_del(&blk->mapped_link);
@@ -307,7 +308,7 @@ snd_emu10k1_alloc_pages(struct snd_emu10k1 *emu, struct snd_pcm_substream *subst
        if (snd_BUG_ON(!emu))
                return NULL;
        if (snd_BUG_ON(runtime->dma_bytes <= 0 ||
-                      runtime->dma_bytes >= MAXPAGES * EMUPAGESIZE))
+                      runtime->dma_bytes >= (emu->address_mode ? MAXPAGES1 : MAXPAGES0) * EMUPAGESIZE))
                return NULL;
        hdr = emu->memhdr;
        if (snd_BUG_ON(!hdr))
index 873ed1bce12b694b60be0c4737a16e0feee5abf0..5645481af3d9571b8340c963a27c34e377c405c5 100644 (file)
@@ -436,7 +436,7 @@ static unsigned int get_num_devices(struct hda_codec *codec, hda_nid_t nid)
            get_wcaps_type(wcaps) != AC_WID_PIN)
                return 0;
 
-       parm = snd_hda_param_read(codec, nid, AC_PAR_DEVLIST_LEN);
+       parm = snd_hdac_read_parm_uncached(&codec->core, nid, AC_PAR_DEVLIST_LEN);
        if (parm == -1 && codec->bus->rirb_error)
                parm = 0;
        return parm & AC_DEV_LIST_LEN_MASK;
@@ -873,14 +873,15 @@ struct hda_pcm *snd_hda_codec_pcm_new(struct hda_codec *codec,
        struct hda_pcm *pcm;
        va_list args;
 
-       va_start(args, fmt);
        pcm = kzalloc(sizeof(*pcm), GFP_KERNEL);
        if (!pcm)
                return NULL;
 
        pcm->codec = codec;
        kref_init(&pcm->kref);
+       va_start(args, fmt);
        pcm->name = kvasprintf(GFP_KERNEL, fmt, args);
+       va_end(args);
        if (!pcm->name) {
                kfree(pcm);
                return NULL;
@@ -1374,6 +1375,31 @@ int snd_hda_override_amp_caps(struct hda_codec *codec, hda_nid_t nid, int dir,
 }
 EXPORT_SYMBOL_GPL(snd_hda_override_amp_caps);
 
+/**
+ * snd_hda_codec_amp_update - update the AMP mono value
+ * @codec: HD-audio codec
+ * @nid: NID to read the AMP value
+ * @ch: channel to update (0 or 1)
+ * @dir: #HDA_INPUT or #HDA_OUTPUT
+ * @idx: the index value (only for input direction)
+ * @mask: bit mask to set
+ * @val: the bits value to set
+ *
+ * Update the AMP values for the given channel, direction and index.
+ */
+int snd_hda_codec_amp_update(struct hda_codec *codec, hda_nid_t nid,
+                            int ch, int dir, int idx, int mask, int val)
+{
+       unsigned int cmd = snd_hdac_regmap_encode_amp(nid, ch, dir, idx);
+
+       /* enable fake mute if no h/w mute but min=mute */
+       if ((query_amp_caps(codec, nid, dir) &
+            (AC_AMPCAP_MUTE | AC_AMPCAP_MIN_MUTE)) == AC_AMPCAP_MIN_MUTE)
+               cmd |= AC_AMP_FAKE_MUTE;
+       return snd_hdac_regmap_update_raw(&codec->core, cmd, mask, val);
+}
+EXPORT_SYMBOL_GPL(snd_hda_codec_amp_update);
+
 /**
  * snd_hda_codec_amp_stereo - update the AMP stereo values
  * @codec: HD-audio codec
@@ -2082,6 +2108,16 @@ static struct snd_kcontrol_new vmaster_mute_mode = {
        .put = vmaster_mute_mode_put,
 };
 
+/* meta hook to call each driver's vmaster hook */
+static void vmaster_hook(void *private_data, int enabled)
+{
+       struct hda_vmaster_mute_hook *hook = private_data;
+
+       if (hook->mute_mode != HDA_VMUTE_FOLLOW_MASTER)
+               enabled = hook->mute_mode;
+       hook->hook(hook->codec, enabled);
+}
+
 /**
  * snd_hda_add_vmaster_hook - Add a vmaster hook for mute-LED
  * @codec: the HDA codec
@@ -2100,9 +2136,9 @@ int snd_hda_add_vmaster_hook(struct hda_codec *codec,
 
        if (!hook->hook || !hook->sw_kctl)
                return 0;
-       snd_ctl_add_vmaster_hook(hook->sw_kctl, hook->hook, codec);
        hook->codec = codec;
        hook->mute_mode = HDA_VMUTE_FOLLOW_MASTER;
+       snd_ctl_add_vmaster_hook(hook->sw_kctl, vmaster_hook, hook);
        if (!expose_enum_ctl)
                return 0;
        kctl = snd_ctl_new1(&vmaster_mute_mode, hook);
@@ -2128,14 +2164,7 @@ void snd_hda_sync_vmaster_hook(struct hda_vmaster_mute_hook *hook)
         */
        if (hook->codec->bus->shutdown)
                return;
-       switch (hook->mute_mode) {
-       case HDA_VMUTE_FOLLOW_MASTER:
-               snd_ctl_sync_vmaster_hook(hook->sw_kctl);
-               break;
-       default:
-               hook->hook(hook->codec, hook->mute_mode);
-               break;
-       }
+       snd_ctl_sync_vmaster_hook(hook->sw_kctl);
 }
 EXPORT_SYMBOL_GPL(snd_hda_sync_vmaster_hook);
 
index 3d2597b7037bbc9c5a74faeeae035f5c5bd70f76..ac0db1679f098ee4ec08c6770fe1f1374c8bf431 100644 (file)
@@ -844,8 +844,16 @@ static hda_nid_t path_power_update(struct hda_codec *codec,
                        snd_hda_codec_write(codec, nid, 0,
                                            AC_VERB_SET_POWER_STATE, state);
                        changed = nid;
+                       /* all known codecs seem to be capable to handl
+                        * widgets state even in D3, so far.
+                        * if any new codecs need to restore the widget
+                        * states after D0 transition, call the function
+                        * below.
+                        */
+#if 0 /* disabled */
                        if (state == AC_PWRST_D0)
                                snd_hdac_regmap_sync_node(&codec->core, nid);
+#endif
                }
        }
        return changed;
@@ -3259,7 +3267,8 @@ static int create_input_ctls(struct hda_codec *codec)
                val = PIN_IN;
                if (cfg->inputs[i].type == AUTO_PIN_MIC)
                        val |= snd_hda_get_default_vref(codec, pin);
-               if (pin != spec->hp_mic_pin)
+               if (pin != spec->hp_mic_pin &&
+                   !snd_hda_codec_get_pin_target(codec, pin))
                        set_pin_target(codec, pin, val, false);
 
                if (mixer) {
@@ -4917,9 +4926,12 @@ int snd_hda_gen_parse_auto_config(struct hda_codec *codec,
  dig_only:
        parse_digital(codec);
 
-       if (spec->power_down_unused || codec->power_save_node)
+       if (spec->power_down_unused || codec->power_save_node) {
                if (!codec->power_filter)
                        codec->power_filter = snd_hda_gen_path_power_filter;
+               if (!codec->patch_ops.stream_pm)
+                       codec->patch_ops.stream_pm = snd_hda_gen_stream_pm;
+       }
 
        if (!spec->no_analog && spec->beep_nid) {
                err = snd_hda_attach_beep_device(codec, spec->beep_nid);
index 34040d26c94ff04c84e8ee1cb2115eb76b0e755d..a244ba706317379445f6b11a03ec118fc16eea05 100644 (file)
@@ -340,6 +340,11 @@ enum {
 #define use_vga_switcheroo(chip)       0
 #endif
 
+#define CONTROLLER_IN_GPU(pci) (((pci)->device == 0x0a0c) || \
+                                       ((pci)->device == 0x0c0c) || \
+                                       ((pci)->device == 0x0d0c) || \
+                                       ((pci)->device == 0x160c))
+
 static char *driver_short_names[] = {
        [AZX_DRIVER_ICH] = "HDA Intel",
        [AZX_DRIVER_PCH] = "HDA Intel PCH",
@@ -1854,8 +1859,17 @@ static int azx_probe_continue(struct azx *chip)
        if (chip->driver_caps & AZX_DCAPS_I915_POWERWELL) {
 #ifdef CONFIG_SND_HDA_I915
                err = hda_i915_init(hda);
-               if (err < 0)
-                       goto out_free;
+               if (err < 0) {
+                       /* if the controller is bound only with HDMI/DP
+                        * (for HSW and BDW), we need to abort the probe;
+                        * for other chips, still continue probing as other
+                        * codecs can be on the same link.
+                        */
+                       if (CONTROLLER_IN_GPU(pci))
+                               goto out_free;
+                       else
+                               goto skip_i915;
+               }
                err = hda_display_power(hda, true);
                if (err < 0) {
                        dev_err(chip->card->dev,
@@ -1865,6 +1879,7 @@ static int azx_probe_continue(struct azx *chip)
 #endif
        }
 
+ skip_i915:
        err = azx_first_init(chip);
        if (err < 0)
                goto out_free;
@@ -2089,6 +2104,8 @@ static const struct pci_device_id azx_ids[] = {
          .driver_data = AZX_DRIVER_ATIHDMI_NS | AZX_DCAPS_PRESET_ATI_HDMI_NS },
        { PCI_DEVICE(0x1002, 0xaab0),
          .driver_data = AZX_DRIVER_ATIHDMI_NS | AZX_DCAPS_PRESET_ATI_HDMI_NS },
+       { PCI_DEVICE(0x1002, 0xaac8),
+         .driver_data = AZX_DRIVER_ATIHDMI_NS | AZX_DCAPS_PRESET_ATI_HDMI_NS },
        /* VIA VT8251/VT8237A */
        { PCI_DEVICE(0x1106, 0x3288),
          .driver_data = AZX_DRIVER_VIA | AZX_DCAPS_POSFIX_VIA },
index 3b567f42296b9d6b2ca148c66c59c12b5628cb9e..bed66c3144318de3f82dcddeb2445a84ad9ce594 100644 (file)
@@ -129,8 +129,8 @@ int snd_hda_mixer_amp_switch_put_beep(struct snd_kcontrol *kcontrol,
 /* lowlevel accessor with caching; use carefully */
 #define snd_hda_codec_amp_read(codec, nid, ch, dir, idx) \
        snd_hdac_regmap_get_amp(&(codec)->core, nid, ch, dir, idx)
-#define snd_hda_codec_amp_update(codec, nid, ch, dir, idx, mask, val) \
-       snd_hdac_regmap_update_amp(&(codec)->core, nid, ch, dir, idx, mask, val)
+int snd_hda_codec_amp_update(struct hda_codec *codec, hda_nid_t nid,
+                            int ch, int dir, int idx, int mask, int val);
 int snd_hda_codec_amp_stereo(struct hda_codec *codec, hda_nid_t nid,
                             int dir, int idx, int mask, int val);
 int snd_hda_codec_amp_init(struct hda_codec *codec, hda_nid_t nid, int ch,
index f8f0dfbef1494538f2d2a370dc792cf860e68868..78b719b5b34dd4959b6c3e755f3625cef61b022d 100644 (file)
@@ -968,6 +968,14 @@ static const struct hda_codec_preset snd_hda_preset_conexant[] = {
          .patch = patch_conexant_auto },
        { .id = 0x14f150b9, .name = "CX20665",
          .patch = patch_conexant_auto },
+       { .id = 0x14f150f1, .name = "CX20721",
+         .patch = patch_conexant_auto },
+       { .id = 0x14f150f2, .name = "CX20722",
+         .patch = patch_conexant_auto },
+       { .id = 0x14f150f3, .name = "CX20723",
+         .patch = patch_conexant_auto },
+       { .id = 0x14f150f4, .name = "CX20724",
+         .patch = patch_conexant_auto },
        { .id = 0x14f1510f, .name = "CX20751/2",
          .patch = patch_conexant_auto },
        { .id = 0x14f15110, .name = "CX20751/2",
@@ -1002,6 +1010,10 @@ MODULE_ALIAS("snd-hda-codec-id:14f150ab");
 MODULE_ALIAS("snd-hda-codec-id:14f150ac");
 MODULE_ALIAS("snd-hda-codec-id:14f150b8");
 MODULE_ALIAS("snd-hda-codec-id:14f150b9");
+MODULE_ALIAS("snd-hda-codec-id:14f150f1");
+MODULE_ALIAS("snd-hda-codec-id:14f150f2");
+MODULE_ALIAS("snd-hda-codec-id:14f150f3");
+MODULE_ALIAS("snd-hda-codec-id:14f150f4");
 MODULE_ALIAS("snd-hda-codec-id:14f1510f");
 MODULE_ALIAS("snd-hda-codec-id:14f15110");
 MODULE_ALIAS("snd-hda-codec-id:14f15111");
index 06199e4e930f77111c701603ba98216c5572faec..0320cb523d9e68112d34f28b8f621c6c10cc6cc3 100644 (file)
@@ -883,6 +883,8 @@ static struct alc_codec_rename_pci_table rename_pci_tbl[] = {
        { 0x10ec0668, 0x1028, 0, "ALC3661" },
        { 0x10ec0275, 0x1028, 0, "ALC3260" },
        { 0x10ec0899, 0x1028, 0, "ALC3861" },
+       { 0x10ec0298, 0x1028, 0, "ALC3266" },
+       { 0x10ec0256, 0x1028, 0, "ALC3246" },
        { 0x10ec0670, 0x1025, 0, "ALC669X" },
        { 0x10ec0676, 0x1025, 0, "ALC679X" },
        { 0x10ec0282, 0x1043, 0, "ALC3229" },
@@ -2166,6 +2168,7 @@ static const struct hda_fixup alc882_fixups[] = {
 static const struct snd_pci_quirk alc882_fixup_tbl[] = {
        SND_PCI_QUIRK(0x1025, 0x006c, "Acer Aspire 9810", ALC883_FIXUP_ACER_EAPD),
        SND_PCI_QUIRK(0x1025, 0x0090, "Acer Aspire", ALC883_FIXUP_ACER_EAPD),
+       SND_PCI_QUIRK(0x1025, 0x0107, "Acer Aspire", ALC883_FIXUP_ACER_EAPD),
        SND_PCI_QUIRK(0x1025, 0x010a, "Acer Ferrari 5000", ALC883_FIXUP_ACER_EAPD),
        SND_PCI_QUIRK(0x1025, 0x0110, "Acer Aspire", ALC883_FIXUP_ACER_EAPD),
        SND_PCI_QUIRK(0x1025, 0x0112, "Acer Aspire 9303", ALC883_FIXUP_ACER_EAPD),
@@ -3673,6 +3676,10 @@ static void alc_headset_mode_mic_in(struct hda_codec *codec, hda_nid_t hp_pin,
                alc_process_coef_fw(codec, coef0293);
                snd_hda_set_pin_ctl_cache(codec, mic_pin, PIN_VREF50);
                break;
+       case 0x10ec0662:
+               snd_hda_set_pin_ctl_cache(codec, hp_pin, 0);
+               snd_hda_set_pin_ctl_cache(codec, mic_pin, PIN_VREF50);
+               break;
        case 0x10ec0668:
                alc_write_coef_idx(codec, 0x11, 0x0001);
                snd_hda_set_pin_ctl_cache(codec, hp_pin, 0);
@@ -3738,7 +3745,6 @@ static void alc_headset_mode_default(struct hda_codec *codec)
        case 0x10ec0288:
                alc_process_coef_fw(codec, coef0288);
                break;
-               break;
        case 0x10ec0292:
                alc_process_coef_fw(codec, coef0292);
                break;
@@ -4012,7 +4018,7 @@ static void alc_update_headset_mode(struct hda_codec *codec)
        if (new_headset_mode != ALC_HEADSET_MODE_MIC) {
                snd_hda_set_pin_ctl_cache(codec, hp_pin,
                                          AC_PINCTL_OUT_EN | AC_PINCTL_HP_EN);
-               if (spec->headphone_mic_pin)
+               if (spec->headphone_mic_pin && spec->headphone_mic_pin != hp_pin)
                        snd_hda_set_pin_ctl_cache(codec, spec->headphone_mic_pin,
                                                  PIN_VREFHIZ);
        }
@@ -4190,11 +4196,18 @@ static void alc_shutup_dell_xps13(struct hda_codec *codec)
 static void alc_fixup_dell_xps13(struct hda_codec *codec,
                                const struct hda_fixup *fix, int action)
 {
-       if (action == HDA_FIXUP_ACT_PROBE) {
-               struct alc_spec *spec = codec->spec;
-               struct hda_input_mux *imux = &spec->gen.input_mux;
-               int i;
+       struct alc_spec *spec = codec->spec;
+       struct hda_input_mux *imux = &spec->gen.input_mux;
+       int i;
 
+       switch (action) {
+       case HDA_FIXUP_ACT_PRE_PROBE:
+               /* mic pin 0x19 must be initialized with Vref Hi-Z, otherwise
+                * it causes a click noise at start up
+                */
+               snd_hda_codec_set_pin_target(codec, 0x19, PIN_VREFHIZ);
+               break;
+       case HDA_FIXUP_ACT_PROBE:
                spec->shutup = alc_shutup_dell_xps13;
 
                /* Make the internal mic the default input source. */
@@ -4204,9 +4217,27 @@ static void alc_fixup_dell_xps13(struct hda_codec *codec,
                                break;
                        }
                }
+               break;
        }
 }
 
+static void alc_fixup_headset_mode_alc662(struct hda_codec *codec,
+                               const struct hda_fixup *fix, int action)
+{
+       struct alc_spec *spec = codec->spec;
+
+       if (action == HDA_FIXUP_ACT_PRE_PROBE) {
+               spec->parse_flags |= HDA_PINCFG_HEADSET_MIC;
+               spec->gen.hp_mic = 1; /* Mic-in is same pin as headphone */
+
+               /* Disable boost for mic-in permanently. (This code is only called
+                  from quirks that guarantee that the headphone is at NID 0x1b.) */
+               snd_hda_codec_write(codec, 0x1b, 0, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000);
+               snd_hda_override_wcaps(codec, 0x1b, get_wcaps(codec, 0x1b) & ~AC_WCAP_IN_AMP);
+       } else
+               alc_fixup_headset_mode(codec, fix, action);
+}
+
 static void alc_fixup_headset_mode_alc668(struct hda_codec *codec,
                                const struct hda_fixup *fix, int action)
 {
@@ -5111,6 +5142,7 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = {
        SND_PCI_QUIRK(0x104d, 0x9099, "Sony VAIO S13", ALC275_FIXUP_SONY_DISABLE_AAMIX),
        SND_PCI_QUIRK(0x10cf, 0x1475, "Lifebook", ALC269_FIXUP_LIFEBOOK),
        SND_PCI_QUIRK(0x10cf, 0x15dc, "Lifebook T731", ALC269_FIXUP_LIFEBOOK_HP_PIN),
+       SND_PCI_QUIRK(0x10cf, 0x1757, "Lifebook E752", ALC269_FIXUP_LIFEBOOK_HP_PIN),
        SND_PCI_QUIRK(0x10cf, 0x1845, "Lifebook U904", ALC269_FIXUP_LIFEBOOK_EXTMIC),
        SND_PCI_QUIRK(0x144d, 0xc109, "Samsung Ativ book 9 (NP900X3G)", ALC269_FIXUP_INV_DMIC),
        SND_PCI_QUIRK(0x1458, 0xfa53, "Gigabyte BXBT-2807", ALC283_FIXUP_BXBT2807_MIC),
@@ -5140,6 +5172,7 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = {
        SND_PCI_QUIRK(0x17aa, 0x5026, "Thinkpad", ALC269_FIXUP_LIMIT_INT_MIC_BOOST),
        SND_PCI_QUIRK(0x17aa, 0x5034, "Thinkpad T450", ALC292_FIXUP_TPT440_DOCK),
        SND_PCI_QUIRK(0x17aa, 0x5036, "Thinkpad T450s", ALC292_FIXUP_TPT440_DOCK),
+       SND_PCI_QUIRK(0x17aa, 0x503c, "Thinkpad L450", ALC292_FIXUP_TPT440_DOCK),
        SND_PCI_QUIRK(0x17aa, 0x5109, "Thinkpad", ALC269_FIXUP_LIMIT_INT_MIC_BOOST),
        SND_PCI_QUIRK(0x17aa, 0x3bf8, "Quanta FL1", ALC269_FIXUP_PCM_44K),
        SND_PCI_QUIRK(0x17aa, 0x9e54, "LENOVO NB", ALC269_FIXUP_LENOVO_EAPD),
@@ -5337,6 +5370,20 @@ static const struct snd_hda_pin_quirk alc269_pin_fixup_tbl[] = {
                {0x17, 0x40000000},
                {0x1d, 0x40700001},
                {0x21, 0x02211050}),
+       SND_HDA_PIN_QUIRK(0x10ec0255, 0x1028, "Dell Inspiron 5548", ALC255_FIXUP_DELL1_MIC_NO_PRESENCE,
+               ALC255_STANDARD_PINS,
+               {0x12, 0x90a60180},
+               {0x14, 0x90170130},
+               {0x17, 0x40000000},
+               {0x1d, 0x40700001},
+               {0x21, 0x02211040}),
+       SND_HDA_PIN_QUIRK(0x10ec0256, 0x1028, "Dell", ALC255_FIXUP_DELL1_MIC_NO_PRESENCE,
+               ALC255_STANDARD_PINS,
+               {0x12, 0x90a60160},
+               {0x14, 0x90170120},
+               {0x17, 0x40000000},
+               {0x1d, 0x40700001},
+               {0x21, 0x02211030}),
        SND_HDA_PIN_QUIRK(0x10ec0256, 0x1028, "Dell", ALC255_FIXUP_DELL1_MIC_NO_PRESENCE,
                ALC256_STANDARD_PINS,
                {0x13, 0x40000000}),
@@ -5590,7 +5637,8 @@ static int patch_alc269(struct hda_codec *codec)
 
        spec = codec->spec;
        spec->gen.shared_mic_vref_pin = 0x18;
-       codec->power_save_node = 1;
+       if (codec->core.vendor_id != 0x10ec0292)
+               codec->power_save_node = 1;
 
        snd_hda_pick_fixup(codec, alc269_fixup_models,
                       alc269_fixup_tbl, alc269_fixups);
@@ -6071,7 +6119,9 @@ enum {
        ALC662_FIXUP_NO_JACK_DETECT,
        ALC662_FIXUP_ZOTAC_Z68,
        ALC662_FIXUP_INV_DMIC,
+       ALC662_FIXUP_DELL_MIC_NO_PRESENCE,
        ALC668_FIXUP_DELL_MIC_NO_PRESENCE,
+       ALC662_FIXUP_HEADSET_MODE,
        ALC668_FIXUP_HEADSET_MODE,
        ALC662_FIXUP_BASS_MODE4_CHMAP,
        ALC662_FIXUP_BASS_16,
@@ -6264,6 +6314,20 @@ static const struct hda_fixup alc662_fixups[] = {
                .chained = true,
                .chain_id = ALC668_FIXUP_DELL_MIC_NO_PRESENCE
        },
+       [ALC662_FIXUP_DELL_MIC_NO_PRESENCE] = {
+               .type = HDA_FIXUP_PINS,
+               .v.pins = (const struct hda_pintbl[]) {
+                       { 0x19, 0x03a1113c }, /* use as headset mic, without its own jack detect */
+                       /* headphone mic by setting pin control of 0x1b (headphone out) to in + vref_50 */
+                       { }
+               },
+               .chained = true,
+               .chain_id = ALC662_FIXUP_HEADSET_MODE
+       },
+       [ALC662_FIXUP_HEADSET_MODE] = {
+               .type = HDA_FIXUP_FUNC,
+               .v.func = alc_fixup_headset_mode_alc662,
+       },
        [ALC668_FIXUP_DELL_MIC_NO_PRESENCE] = {
                .type = HDA_FIXUP_PINS,
                .v.pins = (const struct hda_pintbl[]) {
@@ -6415,6 +6479,18 @@ static const struct hda_model_fixup alc662_fixup_models[] = {
 };
 
 static const struct snd_hda_pin_quirk alc662_pin_fixup_tbl[] = {
+       SND_HDA_PIN_QUIRK(0x10ec0662, 0x1028, "Dell", ALC662_FIXUP_DELL_MIC_NO_PRESENCE,
+               {0x12, 0x4004c000},
+               {0x14, 0x01014010},
+               {0x15, 0x411111f0},
+               {0x16, 0x411111f0},
+               {0x18, 0x01a19020},
+               {0x19, 0x411111f0},
+               {0x1a, 0x0181302f},
+               {0x1b, 0x0221401f},
+               {0x1c, 0x411111f0},
+               {0x1d, 0x4054c601},
+               {0x1e, 0x411111f0}),
        SND_HDA_PIN_QUIRK(0x10ec0668, 0x1028, "Dell", ALC668_FIXUP_AUTO_MUTE,
                {0x12, 0x99a30130},
                {0x14, 0x90170110},
index 43c99ce4a520c3fc24a720f6c76ba4222403ad3b..6833c74ed6ff47f60598d6d250b8709d914590a5 100644 (file)
@@ -4403,7 +4403,6 @@ static const struct hda_codec_ops stac_patch_ops = {
 #ifdef CONFIG_PM
        .suspend = stac_suspend,
 #endif
-       .stream_pm = snd_hda_gen_stream_pm,
        .reboot_notify = stac_shutup,
 };
 
@@ -4697,7 +4696,8 @@ static int patch_stac92hd71bxx(struct hda_codec *codec)
                return err;
 
        spec = codec->spec;
-       codec->power_save_node = 1;
+       /* disabled power_save_node since it causes noises on a Dell machine */
+       /* codec->power_save_node = 1; */
        spec->linear_tone_beep = 0;
        spec->gen.own_eapd_ctl = 1;
        spec->gen.power_down_unused = 1;
index 31a95cca015d4d1c34a1facff2e226b6821a5203..bab6c04932aa050ff63f054bf172acf288f5ee5e 100644 (file)
@@ -449,6 +449,15 @@ static int via_suspend(struct hda_codec *codec)
 
        return 0;
 }
+
+static int via_resume(struct hda_codec *codec)
+{
+       /* some delay here to make jack detection working (bko#98921) */
+       msleep(10);
+       codec->patch_ops.init(codec);
+       regcache_sync(codec->core.regmap);
+       return 0;
+}
 #endif
 
 #ifdef CONFIG_PM
@@ -475,6 +484,7 @@ static const struct hda_codec_ops via_patch_ops = {
        .stream_pm = snd_hda_gen_stream_pm,
 #ifdef CONFIG_PM
        .suspend = via_suspend,
+       .resume = via_resume,
        .check_power_status = via_check_power_status,
 #endif
 };
index 3ba52da18bc69a9bb41c84627cfc7d08f47e3bf0..2ae9619443d15dbeaf128cab385347db6bf26369 100644 (file)
@@ -45,6 +45,7 @@ source "sound/soc/nuc900/Kconfig"
 source "sound/soc/omap/Kconfig"
 source "sound/soc/kirkwood/Kconfig"
 source "sound/soc/intel/Kconfig"
+source "sound/soc/mediatek/Kconfig"
 source "sound/soc/mxs/Kconfig"
 source "sound/soc/pxa/Kconfig"
 source "sound/soc/qcom/Kconfig"
@@ -57,6 +58,7 @@ source "sound/soc/tegra/Kconfig"
 source "sound/soc/txx9/Kconfig"
 source "sound/soc/ux500/Kconfig"
 source "sound/soc/xtensa/Kconfig"
+source "sound/soc/zte/Kconfig"
 
 # Supported codecs
 source "sound/soc/codecs/Kconfig"
index 974ba708b4826a03077a58251434a311542d5e3c..e189903fabf42958eff143e487999f0f013b85d7 100644 (file)
@@ -1,5 +1,6 @@
 snd-soc-core-objs := soc-core.o soc-dapm.o soc-jack.o soc-cache.o soc-utils.o
 snd-soc-core-objs += soc-pcm.o soc-compress.o soc-io.o soc-devres.o soc-ops.o
+snd-soc-core-objs += soc-topology.o
 
 ifneq ($(CONFIG_SND_SOC_GENERIC_DMAENGINE_PCM),)
 snd-soc-core-objs += soc-generic-dmaengine-pcm.o
@@ -23,6 +24,7 @@ obj-$(CONFIG_SND_SOC) += dwc/
 obj-$(CONFIG_SND_SOC)  += fsl/
 obj-$(CONFIG_SND_SOC)  += jz4740/
 obj-$(CONFIG_SND_SOC)  += intel/
+obj-$(CONFIG_SND_SOC)  += mediatek/
 obj-$(CONFIG_SND_SOC)  += mxs/
 obj-$(CONFIG_SND_SOC)  += nuc900/
 obj-$(CONFIG_SND_SOC)  += omap/
@@ -38,3 +40,4 @@ obj-$(CONFIG_SND_SOC) += tegra/
 obj-$(CONFIG_SND_SOC)  += txx9/
 obj-$(CONFIG_SND_SOC)  += ux500/
 obj-$(CONFIG_SND_SOC)  += xtensa/
+obj-$(CONFIG_SND_SOC)  += zte/
index e7d08806f3e92d9c98a7c5bfc4fe84d5aead3f5f..1489cd461aeca365cf746a09bf506668c75c1ec5 100644 (file)
@@ -6,29 +6,35 @@ config SND_ATMEL_SOC
          the ATMEL SSC interface. You will also need
          to select the audio interfaces to support below.
 
+if SND_ATMEL_SOC
+
 config SND_ATMEL_SOC_PDC
        tristate
-       depends on SND_ATMEL_SOC
+       default m if SND_ATMEL_SOC_SSC_PDC=m && SND_ATMEL_SOC_SSC=m
+       default y if SND_ATMEL_SOC_SSC_PDC=y || (SND_ATMEL_SOC_SSC_PDC=m && SND_ATMEL_SOC_SSC=y)
+
+config SND_ATMEL_SOC_SSC_PDC
+       tristate
 
 config SND_ATMEL_SOC_DMA
        tristate
-       depends on SND_ATMEL_SOC
        select SND_SOC_GENERIC_DMAENGINE_PCM
+       default m if SND_ATMEL_SOC_SSC_DMA=m && SND_ATMEL_SOC_SSC=m
+       default y if SND_ATMEL_SOC_SSC_DMA=y || (SND_ATMEL_SOC_SSC_DMA=m && SND_ATMEL_SOC_SSC=y)
+
+config SND_ATMEL_SOC_SSC_DMA
+       tristate
 
 config SND_ATMEL_SOC_SSC
        tristate
-       depends on SND_ATMEL_SOC
-       help
-         Say Y or M if you want to add support for codecs the
-         ATMEL SSC interface. You will also needs to select the individual
-         machine drivers to support below.
+       default y if SND_ATMEL_SOC_SSC_DMA=y || SND_ATMEL_SOC_SSC_PDC=y
+       default m if SND_ATMEL_SOC_SSC_DMA=m || SND_ATMEL_SOC_SSC_PDC=m
 
 config SND_AT91_SOC_SAM9G20_WM8731
        tristate "SoC Audio support for WM8731-based At91sam9g20 evaluation board"
        depends on ARCH_AT91 || COMPILE_TEST
-       depends on ATMEL_SSC && SND_ATMEL_SOC && SND_SOC_I2C_AND_SPI
-       select SND_ATMEL_SOC_PDC
-       select SND_ATMEL_SOC_SSC
+       depends on ATMEL_SSC && SND_SOC_I2C_AND_SPI
+       select SND_ATMEL_SOC_SSC_PDC
        select SND_SOC_WM8731
        help
          Say Y if you want to add support for SoC audio on WM8731-based
@@ -37,9 +43,8 @@ config SND_AT91_SOC_SAM9G20_WM8731
 config SND_ATMEL_SOC_WM8904
        tristate "Atmel ASoC driver for boards using WM8904 codec"
        depends on ARCH_AT91 || COMPILE_TEST
-       depends on ATMEL_SSC && SND_ATMEL_SOC && I2C
-       select SND_ATMEL_SOC_SSC
-       select SND_ATMEL_SOC_DMA
+       depends on ATMEL_SSC && I2C
+       select SND_ATMEL_SOC_SSC_DMA
        select SND_SOC_WM8904
        help
          Say Y if you want to add support for Atmel ASoC driver for boards using
@@ -48,10 +53,10 @@ config SND_ATMEL_SOC_WM8904
 config SND_AT91_SOC_SAM9X5_WM8731
        tristate "SoC Audio support for WM8731-based at91sam9x5 board"
        depends on ARCH_AT91 || COMPILE_TEST
-       depends on ATMEL_SSC && SND_ATMEL_SOC && SND_SOC_I2C_AND_SPI
-       select SND_ATMEL_SOC_SSC
-       select SND_ATMEL_SOC_DMA
+       depends on ATMEL_SSC && SND_SOC_I2C_AND_SPI
+       select SND_ATMEL_SOC_SSC_DMA
        select SND_SOC_WM8731
        help
          Say Y if you want to add support for audio SoC on an
          at91sam9x5 based board that is using WM8731 codec.
+endif
index b6625c8c411b8a66a6d1cbaf807109f7ccc8ec71..dd57a9eac171dba4da718e9f09a4853c322c393f 100644 (file)
@@ -124,8 +124,7 @@ static const struct snd_dmaengine_pcm_config atmel_dmaengine_pcm_config = {
 
 int atmel_pcm_dma_platform_register(struct device *dev)
 {
-       return snd_dmaengine_pcm_register(dev, &atmel_dmaengine_pcm_config,
-                       SND_DMAENGINE_PCM_FLAG_NO_RESIDUE);
+       return snd_dmaengine_pcm_register(dev, &atmel_dmaengine_pcm_config, 0);
 }
 EXPORT_SYMBOL(atmel_pcm_dma_platform_register);
 
index 8de836165cf2ed1978c4846ac56e84bcbae4e6d1..d7469cdd90dc854a9f0db0dd5c666948ecf9bdf3 100644 (file)
@@ -95,8 +95,9 @@ static const struct snd_soc_dapm_widget at91sam9g20ek_dapm_widgets[] = {
 
 static const struct snd_soc_dapm_route intercon[] = {
 
-       /* speaker connected to LHPOUT */
+       /* speaker connected to LHPOUT/RHPOUT */
        {"Ext Spk", NULL, "LHPOUT"},
+       {"Ext Spk", NULL, "RHPOUT"},
 
        /* mic is connected to Mic Jack, with WM8731 Mic Bias */
        {"MICIN", NULL, "Mic Bias"},
@@ -108,9 +109,7 @@ static const struct snd_soc_dapm_route intercon[] = {
  */
 static int at91sam9g20ek_wm8731_init(struct snd_soc_pcm_runtime *rtd)
 {
-       struct snd_soc_codec *codec = rtd->codec;
        struct snd_soc_dai *codec_dai = rtd->codec_dai;
-       struct snd_soc_dapm_context *dapm = &codec->dapm;
        int ret;
 
        printk(KERN_DEBUG
@@ -124,10 +123,6 @@ static int at91sam9g20ek_wm8731_init(struct snd_soc_pcm_runtime *rtd)
                return ret;
        }
 
-       /* not connected */
-       snd_soc_dapm_nc_pin(dapm, "RLINEIN");
-       snd_soc_dapm_nc_pin(dapm, "LLINEIN");
-
 #ifndef ENABLE_MIC_INPUT
        snd_soc_dapm_nc_pin(&rtd->card->dapm, "Int Mic");
 #endif
@@ -158,6 +153,7 @@ static struct snd_soc_card snd_soc_at91sam9g20ek = {
        .num_dapm_widgets = ARRAY_SIZE(at91sam9g20ek_dapm_widgets),
        .dapm_routes = intercon,
        .num_dapm_routes = ARRAY_SIZE(intercon),
+       .fully_routed = true,
 };
 
 static int at91sam9g20ek_audio_probe(struct platform_device *pdev)
index c75995f2779cf57604de8d1ef37c4aa42c31d2a5..58c3164802b8ceda545e1469f557a814702694be 100644 (file)
@@ -21,7 +21,7 @@
 #include "../codecs/wm8731.h"
 #include "psc.h"
 
-static struct platform_device_id db1200_pids[] = {
+static const struct platform_device_id db1200_pids[] = {
        {
                .name           = "db1200-ac97",
                .driver_data    = 0,
index 5f664471d99ee480fd38bd723e65d8023462973c..67a73330db5e88e669c52f424dafa5045a0728d6 100644 (file)
@@ -60,7 +60,6 @@ int devm_ep93xx_pcm_platform_register(struct device *dev)
 {
        return devm_snd_dmaengine_pcm_register(dev,
                &ep93xx_dmaengine_pcm_config,
-               SND_DMAENGINE_PCM_FLAG_NO_RESIDUE |
                SND_DMAENGINE_PCM_FLAG_NO_DT |
                SND_DMAENGINE_PCM_FLAG_COMPAT);
 }
index a0f265327fdf8949e15b17187732d1da8702a7a9..38b3dad9d48ac42c58e2c9d7058c094392889c7a 100644 (file)
@@ -1140,7 +1140,7 @@ static int pm860x_set_bias_level(struct snd_soc_codec *codec,
                break;
 
        case SND_SOC_BIAS_STANDBY:
-               if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) {
+               if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_OFF) {
                        /* Enable Audio PLL & Audio section */
                        data = AUDIO_PLL | AUDIO_SECTION_ON;
                        pm860x_reg_write(pm860x->i2c, REG_MISC2, data);
@@ -1156,7 +1156,6 @@ static int pm860x_set_bias_level(struct snd_soc_codec *codec,
                pm860x_set_bits(pm860x->i2c, REG_MISC2, data, 0);
                break;
        }
-       codec->dapm.bias_level = level;
        return 0;
 }
 
@@ -1187,16 +1186,16 @@ static struct snd_soc_dai_driver pm860x_dai[] = {
                        .channels_min   = 2,
                        .channels_max   = 2,
                        .rates          = PM860X_RATES,
-                       .formats        = SNDRV_PCM_FORMAT_S16_LE | \
-                                         SNDRV_PCM_FORMAT_S18_3LE,
+                       .formats        = SNDRV_PCM_FMTBIT_S16_LE | \
+                                         SNDRV_PCM_FMTBIT_S18_3LE,
                },
                .capture = {
                        .stream_name    = "PCM Capture",
                        .channels_min   = 2,
                        .channels_max   = 2,
                        .rates          = PM860X_RATES,
-                       .formats        = SNDRV_PCM_FORMAT_S16_LE | \
-                                         SNDRV_PCM_FORMAT_S18_3LE,
+                       .formats        = SNDRV_PCM_FMTBIT_S16_LE | \
+                                         SNDRV_PCM_FMTBIT_S18_3LE,
                },
                .ops    = &pm860x_pcm_dai_ops,
        }, {
@@ -1208,16 +1207,16 @@ static struct snd_soc_dai_driver pm860x_dai[] = {
                        .channels_min   = 2,
                        .channels_max   = 2,
                        .rates          = SNDRV_PCM_RATE_8000_48000,
-                       .formats        = SNDRV_PCM_FORMAT_S16_LE | \
-                                         SNDRV_PCM_FORMAT_S18_3LE,
+                       .formats        = SNDRV_PCM_FMTBIT_S16_LE | \
+                                         SNDRV_PCM_FMTBIT_S18_3LE,
                },
                .capture = {
                        .stream_name    = "I2S Capture",
                        .channels_min   = 2,
                        .channels_max   = 2,
                        .rates          = SNDRV_PCM_RATE_8000_48000,
-                       .formats        = SNDRV_PCM_FORMAT_S16_LE | \
-                                         SNDRV_PCM_FORMAT_S18_3LE,
+                       .formats        = SNDRV_PCM_FMTBIT_S16_LE | \
+                                         SNDRV_PCM_FMTBIT_S18_3LE,
                },
                .ops    = &pm860x_i2s_dai_ops,
        },
index 061c46587628b5284a38b51d39a777f6341c2c1a..efaafce8ba387340e073796a9de2c7d9b00aac81 100644 (file)
@@ -16,7 +16,7 @@ config SND_SOC_ALL_CODECS
        select SND_SOC_88PM860X if MFD_88PM860X
        select SND_SOC_L3
        select SND_SOC_AB8500_CODEC if ABX500_CORE
-       select SND_SOC_AC97_CODEC if SND_SOC_AC97_BUS
+       select SND_SOC_AC97_CODEC
        select SND_SOC_AD1836 if SPI_MASTER
        select SND_SOC_AD193X_SPI if SPI_MASTER
        select SND_SOC_AD193X_I2C if I2C
@@ -54,7 +54,7 @@ config SND_SOC_ALL_CODECS
        select SND_SOC_CS4271_SPI if SPI_MASTER
        select SND_SOC_CS42XX8_I2C if I2C
        select SND_SOC_CX20442 if TTY
-       select SND_SOC_DA7210 if I2C
+       select SND_SOC_DA7210 if SND_SOC_I2C_AND_SPI
        select SND_SOC_DA7213 if I2C
        select SND_SOC_DA732X if I2C
        select SND_SOC_DA9055 if I2C
@@ -104,6 +104,7 @@ config SND_SOC_ALL_CODECS
        select SND_SOC_STAC9766 if SND_SOC_AC97_BUS
        select SND_SOC_TAS2552 if I2C
        select SND_SOC_TAS5086 if I2C
+       select SND_SOC_TAS571X if I2C
        select SND_SOC_TFA9879 if I2C
        select SND_SOC_TLV320AIC23_I2C if I2C
        select SND_SOC_TLV320AIC23_SPI if SPI_MASTER
@@ -211,8 +212,9 @@ config SND_SOC_AB8500_CODEC
        tristate
 
 config SND_SOC_AC97_CODEC
-       tristate
+       tristate "Build generic ASoC AC97 CODEC driver"
        select SND_AC97_CODEC
+       select SND_SOC_AC97_BUS
 
 config SND_SOC_AD1836
        tristate
@@ -507,6 +509,11 @@ config SND_SOC_RL6231
        default m if SND_SOC_RT5670=m
        default m if SND_SOC_RT5677=m
 
+config SND_SOC_RL6347A
+       tristate
+       default y if SND_SOC_RT286=y
+       default m if SND_SOC_RT286=m
+
 config SND_SOC_RT286
        tristate
        depends on I2C
@@ -611,6 +618,10 @@ config SND_SOC_TAS5086
        tristate "Texas Instruments TAS5086 speaker amplifier"
        depends on I2C
 
+config SND_SOC_TAS571X
+       tristate "Texas Instruments TAS5711/TAS5717/TAS5719 power amplifiers"
+       depends on I2C
+
 config SND_SOC_TFA9879
        tristate "NXP Semiconductors TFA9879 amplifier"
        depends on I2C
index abe2d7edf65c7af29dbad5de78b2c0fe2beeef16..cf160d972cb3640b0080634fb9d67f6800252e04 100644 (file)
@@ -77,6 +77,7 @@ snd-soc-pcm512x-objs := pcm512x.o
 snd-soc-pcm512x-i2c-objs := pcm512x-i2c.o
 snd-soc-pcm512x-spi-objs := pcm512x-spi.o
 snd-soc-rl6231-objs := rl6231.o
+snd-soc-rl6347a-objs := rl6347a.o
 snd-soc-rt286-objs := rt286.o
 snd-soc-rt5631-objs := rt5631.o
 snd-soc-rt5640-objs := rt5640.o
@@ -106,6 +107,7 @@ snd-soc-sta350-objs := sta350.o
 snd-soc-sta529-objs := sta529.o
 snd-soc-stac9766-objs := stac9766.o
 snd-soc-tas5086-objs := tas5086.o
+snd-soc-tas571x-objs := tas571x.o
 snd-soc-tfa9879-objs := tfa9879.o
 snd-soc-tlv320aic23-objs := tlv320aic23.o
 snd-soc-tlv320aic23-i2c-objs := tlv320aic23-i2c.o
@@ -262,6 +264,7 @@ obj-$(CONFIG_SND_SOC_PCM512x)       += snd-soc-pcm512x.o
 obj-$(CONFIG_SND_SOC_PCM512x_I2C)      += snd-soc-pcm512x-i2c.o
 obj-$(CONFIG_SND_SOC_PCM512x_SPI)      += snd-soc-pcm512x-spi.o
 obj-$(CONFIG_SND_SOC_RL6231)   += snd-soc-rl6231.o
+obj-$(CONFIG_SND_SOC_RL6347A)  += snd-soc-rl6347a.o
 obj-$(CONFIG_SND_SOC_RT286)    += snd-soc-rt286.o
 obj-$(CONFIG_SND_SOC_RT5631)   += snd-soc-rt5631.o
 obj-$(CONFIG_SND_SOC_RT5640)   += snd-soc-rt5640.o
@@ -288,6 +291,7 @@ obj-$(CONFIG_SND_SOC_STA529)   += snd-soc-sta529.o
 obj-$(CONFIG_SND_SOC_STAC9766) += snd-soc-stac9766.o
 obj-$(CONFIG_SND_SOC_TAS2552)  += snd-soc-tas2552.o
 obj-$(CONFIG_SND_SOC_TAS5086)  += snd-soc-tas5086.o
+obj-$(CONFIG_SND_SOC_TAS571X)  += snd-soc-tas571x.o
 obj-$(CONFIG_SND_SOC_TFA9879)  += snd-soc-tfa9879.o
 obj-$(CONFIG_SND_SOC_TLV320AIC23)      += snd-soc-tlv320aic23.o
 obj-$(CONFIG_SND_SOC_TLV320AIC23_I2C)  += snd-soc-tlv320aic23-i2c.o
index 88ca9cb0ce79374f9e9e02d0530ff689efdbbefe..c7d243db010ae593db892c028042a3e915bde309 100644 (file)
@@ -1209,6 +1209,7 @@ static int anc_status_control_put(struct snd_kcontrol *kcontrol,
                                struct snd_ctl_elem_value *ucontrol)
 {
        struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
+       struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
        struct ab8500_codec_drvdata *drvdata = dev_get_drvdata(codec->dev);
        struct device *dev = codec->dev;
        bool apply_fir, apply_iir;
@@ -1234,15 +1235,14 @@ static int anc_status_control_put(struct snd_kcontrol *kcontrol,
        apply_fir = req == ANC_APPLY_FIR || req == ANC_APPLY_FIR_IIR;
        apply_iir = req == ANC_APPLY_IIR || req == ANC_APPLY_FIR_IIR;
 
-       status = snd_soc_dapm_force_enable_pin(&codec->dapm,
-                                       "ANC Configure Input");
+       status = snd_soc_dapm_force_enable_pin(dapm, "ANC Configure Input");
        if (status < 0) {
                dev_err(dev,
                        "%s: ERROR: Failed to enable power (status = %d)!\n",
                        __func__, status);
                goto cleanup;
        }
-       snd_soc_dapm_sync(&codec->dapm);
+       snd_soc_dapm_sync(dapm);
 
        anc_configure(codec, apply_fir, apply_iir);
 
@@ -1259,8 +1259,8 @@ static int anc_status_control_put(struct snd_kcontrol *kcontrol,
                        drvdata->anc_status =  ANC_IIR_CONFIGURED;
        }
 
-       status = snd_soc_dapm_disable_pin(&codec->dapm, "ANC Configure Input");
-       snd_soc_dapm_sync(&codec->dapm);
+       status = snd_soc_dapm_disable_pin(dapm, "ANC Configure Input");
+       snd_soc_dapm_sync(dapm);
 
 cleanup:
        mutex_unlock(&drvdata->ctrl_lock);
@@ -1947,6 +1947,7 @@ static int ab8500_audio_init_audioblock(struct snd_soc_codec *codec)
 static int ab8500_audio_setup_mics(struct snd_soc_codec *codec,
                        struct amic_settings *amics)
 {
+       struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
        u8 value8;
        unsigned int value;
        int status;
@@ -1973,15 +1974,15 @@ static int ab8500_audio_setup_mics(struct snd_soc_codec *codec,
        dev_dbg(codec->dev, "%s: Mic 1a regulator: %s\n", __func__,
                amic_micbias_str(amics->mic1a_micbias));
        route = &ab8500_dapm_routes_mic1a_vamicx[amics->mic1a_micbias];
-       status = snd_soc_dapm_add_routes(&codec->dapm, route, 1);
+       status = snd_soc_dapm_add_routes(dapm, route, 1);
        dev_dbg(codec->dev, "%s: Mic 1b regulator: %s\n", __func__,
                amic_micbias_str(amics->mic1b_micbias));
        route = &ab8500_dapm_routes_mic1b_vamicx[amics->mic1b_micbias];
-       status |= snd_soc_dapm_add_routes(&codec->dapm, route, 1);
+       status |= snd_soc_dapm_add_routes(dapm, route, 1);
        dev_dbg(codec->dev, "%s: Mic 2 regulator: %s\n", __func__,
                amic_micbias_str(amics->mic2_micbias));
        route = &ab8500_dapm_routes_mic2_vamicx[amics->mic2_micbias];
-       status |= snd_soc_dapm_add_routes(&codec->dapm, route, 1);
+       status |= snd_soc_dapm_add_routes(dapm, route, 1);
        if (status < 0) {
                dev_err(codec->dev,
                        "%s: Failed to add AMic-regulator DAPM-routes (%d).\n",
@@ -2461,6 +2462,7 @@ static void ab8500_codec_of_probe(struct device *dev, struct device_node *np,
 
 static int ab8500_codec_probe(struct snd_soc_codec *codec)
 {
+       struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
        struct device *dev = codec->dev;
        struct device_node *np = dev->of_node;
        struct ab8500_codec_drvdata *drvdata = dev_get_drvdata(dev);
@@ -2541,7 +2543,7 @@ static int ab8500_codec_probe(struct snd_soc_codec *codec)
                &ab8500_filter_controls[AB8500_FILTER_SID_FIR].private_value;
        drvdata->sid_fir_values = (long *)fc->value;
 
-       (void)snd_soc_dapm_disable_pin(&codec->dapm, "ANC Configure Input");
+       snd_soc_dapm_disable_pin(dapm, "ANC Configure Input");
 
        mutex_init(&drvdata->ctrl_lock);
 
index d0ac723eee321a6f36c4f49fb398098a053fede1..5b3224c6394312cfebe9cf933f40451ee73fdb01 100644 (file)
@@ -44,10 +44,6 @@ static int ac97_prepare(struct snd_pcm_substream *substream,
        return snd_ac97_set_rate(ac97, reg, substream->runtime->rate);
 }
 
-#define STD_AC97_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 |\
-               SNDRV_PCM_RATE_22050 | SNDRV_PCM_RATE_44100 |\
-               SNDRV_PCM_RATE_48000)
-
 static const struct snd_soc_dai_ops ac97_dai_ops = {
        .prepare        = ac97_prepare,
 };
@@ -58,13 +54,13 @@ static struct snd_soc_dai_driver ac97_dai = {
                .stream_name = "AC97 Playback",
                .channels_min = 1,
                .channels_max = 2,
-               .rates = STD_AC97_RATES,
+               .rates = SNDRV_PCM_RATE_KNOT,
                .formats = SND_SOC_STD_AC97_FMTS,},
        .capture = {
                .stream_name = "AC97 Capture",
                .channels_min = 1,
                .channels_max = 2,
-               .rates = STD_AC97_RATES,
+               .rates = SNDRV_PCM_RATE_KNOT,
                .formats = SND_SOC_STD_AC97_FMTS,},
        .ops = &ac97_dai_ops,
 };
index 685998dd086e392d592fad5ac0ea9bf35e4ed612..95f0bec26a1bce16150f5465f3d86b373222b817 100644 (file)
@@ -251,7 +251,7 @@ static int ad1836_resume(struct snd_soc_codec *codec)
 static int ad1836_probe(struct snd_soc_codec *codec)
 {
        struct ad1836_priv *ad1836 = snd_soc_codec_get_drvdata(codec);
-       struct snd_soc_dapm_context *dapm = &codec->dapm;
+       struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
        int num_dacs, num_adcs;
        int ret = 0;
        int i;
index 783dcb57043a1a02c14e34ce1a94d754c8772440..a43160254929d5b31d7105cd75486263e14bf551 100644 (file)
@@ -1444,7 +1444,6 @@ static int adau1373_set_bias_level(struct snd_soc_codec *codec,
                        ADAU1373_PWDN_CTRL3_PWR_EN, 0);
                break;
        }
-       codec->dapm.bias_level = level;
        return 0;
 }
 
index d4e219b6b98f24636af3e4857bb297db005c10f8..ff7f846e3b765e1103c417f2590c73d65c78d7eb 100644 (file)
@@ -16,6 +16,7 @@
 #include <linux/of.h>
 #include <linux/of_gpio.h>
 #include <linux/of_device.h>
+#include <linux/regulator/consumer.h>
 #include <linux/regmap.h>
 #include <sound/core.h>
 #include <sound/pcm.h>
 
 #define ADAU1701_FIRMWARE "adau1701.bin"
 
+static const char * const supply_names[] = {
+       "dvdd", "avdd"
+};
+
 struct adau1701 {
        int gpio_nreset;
        int gpio_pll_mode[2];
@@ -112,6 +117,7 @@ struct adau1701 {
        u8 pin_config[12];
 
        struct sigmadsp *sigmadsp;
+       struct regulator_bulk_data supplies[ARRAY_SIZE(supply_names)];
 };
 
 static const struct snd_kcontrol_new adau1701_controls[] = {
@@ -565,7 +571,6 @@ static int adau1701_set_bias_level(struct snd_soc_codec *codec,
                break;
        }
 
-       codec->dapm.bias_level = level;
        return 0;
 }
 
@@ -669,6 +674,13 @@ static int adau1701_probe(struct snd_soc_codec *codec)
        if (ret)
                return ret;
 
+       ret = regulator_bulk_enable(ARRAY_SIZE(adau1701->supplies),
+                                   adau1701->supplies);
+       if (ret < 0) {
+               dev_err(codec->dev, "Failed to enable regulators: %d\n", ret);
+               return ret;
+       }
+
        /*
         * Let the pll_clkdiv variable default to something that won't happen
         * at runtime. That way, we can postpone the firmware download from
@@ -680,7 +692,7 @@ static int adau1701_probe(struct snd_soc_codec *codec)
        /* initalize with pre-configured pll mode settings */
        ret = adau1701_reset(codec, adau1701->pll_clkdiv, 0);
        if (ret < 0)
-               return ret;
+               goto exit_regulators_disable;
 
        /* set up pin config */
        val = 0;
@@ -696,10 +708,60 @@ static int adau1701_probe(struct snd_soc_codec *codec)
        regmap_write(adau1701->regmap, ADAU1701_PINCONF_1, val);
 
        return 0;
+
+exit_regulators_disable:
+
+       regulator_bulk_disable(ARRAY_SIZE(adau1701->supplies), adau1701->supplies);
+       return ret;
 }
 
+static int adau1701_remove(struct snd_soc_codec *codec)
+{
+       struct adau1701 *adau1701 = snd_soc_codec_get_drvdata(codec);
+
+       if (gpio_is_valid(adau1701->gpio_nreset))
+               gpio_set_value_cansleep(adau1701->gpio_nreset, 0);
+
+       regulator_bulk_disable(ARRAY_SIZE(adau1701->supplies), adau1701->supplies);
+
+       return 0;
+}
+
+#ifdef CONFIG_PM
+static int adau1701_suspend(struct snd_soc_codec *codec)
+{
+       struct adau1701 *adau1701 = snd_soc_codec_get_drvdata(codec);
+
+       regulator_bulk_disable(ARRAY_SIZE(adau1701->supplies),
+                              adau1701->supplies);
+
+       return 0;
+}
+
+static int adau1701_resume(struct snd_soc_codec *codec)
+{
+       struct adau1701 *adau1701 = snd_soc_codec_get_drvdata(codec);
+       int ret;
+
+        ret = regulator_bulk_enable(ARRAY_SIZE(adau1701->supplies),
+                                   adau1701->supplies);
+       if (ret < 0) {
+               dev_err(codec->dev, "Failed to enable regulators: %d\n", ret);
+               return ret;
+       }
+
+       return adau1701_reset(codec, adau1701->pll_clkdiv, 0);
+}
+#else
+#define adau1701_resume        NULL
+#define adau1701_suspend       NULL
+#endif /* CONFIG_PM */
+
 static struct snd_soc_codec_driver adau1701_codec_drv = {
        .probe                  = adau1701_probe,
+       .remove                 = adau1701_remove,
+       .resume                 = adau1701_resume,
+       .suspend                = adau1701_suspend,
        .set_bias_level         = adau1701_set_bias_level,
        .idle_bias_off          = true,
 
@@ -730,32 +792,58 @@ static int adau1701_i2c_probe(struct i2c_client *client,
        struct device *dev = &client->dev;
        int gpio_nreset = -EINVAL;
        int gpio_pll_mode[2] = { -EINVAL, -EINVAL };
-       int ret;
+       int ret, i;
 
        adau1701 = devm_kzalloc(dev, sizeof(*adau1701), GFP_KERNEL);
        if (!adau1701)
                return -ENOMEM;
 
+       for (i = 0; i < ARRAY_SIZE(supply_names); i++)
+               adau1701->supplies[i].supply = supply_names[i];
+
+       ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(adau1701->supplies),
+                       adau1701->supplies);
+       if (ret < 0) {
+               dev_err(dev, "Failed to get regulators: %d\n", ret);
+               return ret;
+       }
+
+       ret = regulator_bulk_enable(ARRAY_SIZE(adau1701->supplies),
+                       adau1701->supplies);
+       if (ret < 0) {
+               dev_err(dev, "Failed to enable regulators: %d\n", ret);
+               return ret;
+       }
+
        adau1701->client = client;
        adau1701->regmap = devm_regmap_init(dev, NULL, client,
                                            &adau1701_regmap);
-       if (IS_ERR(adau1701->regmap))
-               return PTR_ERR(adau1701->regmap);
+       if (IS_ERR(adau1701->regmap)) {
+               ret = PTR_ERR(adau1701->regmap);
+               goto exit_regulators_disable;
+       }
+
 
        if (dev->of_node) {
                gpio_nreset = of_get_named_gpio(dev->of_node, "reset-gpio", 0);
-               if (gpio_nreset < 0 && gpio_nreset != -ENOENT)
-                       return gpio_nreset;
+               if (gpio_nreset < 0 && gpio_nreset != -ENOENT) {
+                       ret = gpio_nreset;
+                       goto exit_regulators_disable;
+               }
 
                gpio_pll_mode[0] = of_get_named_gpio(dev->of_node,
                                                   "adi,pll-mode-gpios", 0);
-               if (gpio_pll_mode[0] < 0 && gpio_pll_mode[0] != -ENOENT)
-                       return gpio_pll_mode[0];
+               if (gpio_pll_mode[0] < 0 && gpio_pll_mode[0] != -ENOENT) {
+                       ret = gpio_pll_mode[0];
+                       goto exit_regulators_disable;
+               }
 
                gpio_pll_mode[1] = of_get_named_gpio(dev->of_node,
                                                   "adi,pll-mode-gpios", 1);
-               if (gpio_pll_mode[1] < 0 && gpio_pll_mode[1] != -ENOENT)
-                       return gpio_pll_mode[1];
+               if (gpio_pll_mode[1] < 0 && gpio_pll_mode[1] != -ENOENT) {
+                       ret = gpio_pll_mode[1];
+                       goto exit_regulators_disable;
+               }
 
                of_property_read_u32(dev->of_node, "adi,pll-clkdiv",
                                     &adau1701->pll_clkdiv);
@@ -769,7 +857,7 @@ static int adau1701_i2c_probe(struct i2c_client *client,
                ret = devm_gpio_request_one(dev, gpio_nreset, GPIOF_OUT_INIT_LOW,
                                            "ADAU1701 Reset");
                if (ret < 0)
-                       return ret;
+                       goto exit_regulators_disable;
        }
 
        if (gpio_is_valid(gpio_pll_mode[0]) &&
@@ -778,13 +866,13 @@ static int adau1701_i2c_probe(struct i2c_client *client,
                                            GPIOF_OUT_INIT_LOW,
                                            "ADAU1701 PLL mode 0");
                if (ret < 0)
-                       return ret;
+                       goto exit_regulators_disable;
 
                ret = devm_gpio_request_one(dev, gpio_pll_mode[1],
                                            GPIOF_OUT_INIT_LOW,
                                            "ADAU1701 PLL mode 1");
                if (ret < 0)
-                       return ret;
+                       goto exit_regulators_disable;
        }
 
        adau1701->gpio_nreset = gpio_nreset;
@@ -795,11 +883,17 @@ static int adau1701_i2c_probe(struct i2c_client *client,
 
        adau1701->sigmadsp = devm_sigmadsp_init_i2c(client,
                &adau1701_sigmadsp_ops, ADAU1701_FIRMWARE);
-       if (IS_ERR(adau1701->sigmadsp))
-               return PTR_ERR(adau1701->sigmadsp);
+       if (IS_ERR(adau1701->sigmadsp)) {
+               ret = PTR_ERR(adau1701->sigmadsp);
+               goto exit_regulators_disable;
+       }
 
        ret = snd_soc_register_codec(&client->dev, &adau1701_codec_drv,
                        &adau1701_dai, 1);
+
+exit_regulators_disable:
+
+       regulator_bulk_disable(ARRAY_SIZE(adau1701->supplies), adau1701->supplies);
        return ret;
 }
 
index a1baeee160f43b35780a7914c428e3b886e55c01..2f12477e539ebe36f90af0218ee83031b0ac178d 100644 (file)
@@ -466,7 +466,6 @@ static int adau1761_set_bias_level(struct snd_soc_codec *codec,
                break;
 
        }
-       codec->dapm.bias_level = level;
        return 0;
 }
 
@@ -483,6 +482,7 @@ static enum adau1761_output_mode adau1761_get_lineout_mode(
 
 static int adau1761_setup_digmic_jackdetect(struct snd_soc_codec *codec)
 {
+       struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
        struct adau1761_platform_data *pdata = codec->dev->platform_data;
        struct adau *adau = snd_soc_codec_get_drvdata(codec);
        enum adau1761_digmic_jackdet_pin_mode mode;
@@ -515,21 +515,18 @@ static int adau1761_setup_digmic_jackdetect(struct snd_soc_codec *codec)
                if (ret)
                        return ret;
        case ADAU1761_DIGMIC_JACKDET_PIN_MODE_NONE: /* fallthrough */
-               ret = snd_soc_dapm_add_routes(&codec->dapm,
-                       adau1761_no_dmic_routes,
+               ret = snd_soc_dapm_add_routes(dapm, adau1761_no_dmic_routes,
                        ARRAY_SIZE(adau1761_no_dmic_routes));
                if (ret)
                        return ret;
                break;
        case ADAU1761_DIGMIC_JACKDET_PIN_MODE_DIGMIC:
-               ret = snd_soc_dapm_new_controls(&codec->dapm,
-                       adau1761_dmic_widgets,
+               ret = snd_soc_dapm_new_controls(dapm, adau1761_dmic_widgets,
                        ARRAY_SIZE(adau1761_dmic_widgets));
                if (ret)
                        return ret;
 
-               ret = snd_soc_dapm_add_routes(&codec->dapm,
-                       adau1761_dmic_routes,
+               ret = snd_soc_dapm_add_routes(dapm, adau1761_dmic_routes,
                        ARRAY_SIZE(adau1761_dmic_routes));
                if (ret)
                        return ret;
@@ -547,6 +544,7 @@ static int adau1761_setup_digmic_jackdetect(struct snd_soc_codec *codec)
 
 static int adau1761_setup_headphone_mode(struct snd_soc_codec *codec)
 {
+       struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
        struct adau *adau = snd_soc_codec_get_drvdata(codec);
        struct adau1761_platform_data *pdata = codec->dev->platform_data;
        enum adau1761_output_mode mode;
@@ -577,12 +575,12 @@ static int adau1761_setup_headphone_mode(struct snd_soc_codec *codec)
        }
 
        if (mode == ADAU1761_OUTPUT_MODE_HEADPHONE_CAPLESS) {
-               ret = snd_soc_dapm_new_controls(&codec->dapm,
+               ret = snd_soc_dapm_new_controls(dapm,
                        adau1761_capless_dapm_widgets,
                        ARRAY_SIZE(adau1761_capless_dapm_widgets));
                if (ret)
                        return ret;
-               ret = snd_soc_dapm_add_routes(&codec->dapm,
+               ret = snd_soc_dapm_add_routes(dapm,
                        adau1761_capless_dapm_routes,
                        ARRAY_SIZE(adau1761_capless_dapm_routes));
        } else {
@@ -590,12 +588,12 @@ static int adau1761_setup_headphone_mode(struct snd_soc_codec *codec)
                        ARRAY_SIZE(adau1761_mono_controls));
                if (ret)
                        return ret;
-               ret = snd_soc_dapm_new_controls(&codec->dapm,
+               ret = snd_soc_dapm_new_controls(dapm,
                        adau1761_mono_dapm_widgets,
                        ARRAY_SIZE(adau1761_mono_dapm_widgets));
                if (ret)
                        return ret;
-               ret = snd_soc_dapm_add_routes(&codec->dapm,
+               ret = snd_soc_dapm_add_routes(dapm,
                        adau1761_mono_dapm_routes,
                        ARRAY_SIZE(adau1761_mono_dapm_routes));
        }
@@ -640,6 +638,7 @@ static bool adau1761_readable_register(struct device *dev, unsigned int reg)
 
 static int adau1761_codec_probe(struct snd_soc_codec *codec)
 {
+       struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
        struct adau1761_platform_data *pdata = codec->dev->platform_data;
        struct adau *adau = snd_soc_codec_get_drvdata(codec);
        int ret;
@@ -692,14 +691,12 @@ static int adau1761_codec_probe(struct snd_soc_codec *codec)
                return ret;
 
        if (adau->type == ADAU1761) {
-               ret = snd_soc_dapm_new_controls(&codec->dapm,
-                       adau1761_dapm_widgets,
+               ret = snd_soc_dapm_new_controls(dapm, adau1761_dapm_widgets,
                        ARRAY_SIZE(adau1761_dapm_widgets));
                if (ret)
                        return ret;
 
-               ret = snd_soc_dapm_add_routes(&codec->dapm,
-                       adau1761_dapm_routes,
+               ret = snd_soc_dapm_add_routes(dapm, adau1761_dapm_routes,
                        ARRAY_SIZE(adau1761_dapm_routes));
                if (ret)
                        return ret;
index 35581f43fa6d5e212d3d2c6735b70a8b3f0e2c3a..fde9068550a6801b6ffbb538fcec13ccacc24f5f 100644 (file)
@@ -339,7 +339,6 @@ static int adau1781_set_bias_level(struct snd_soc_codec *codec,
                break;
        }
 
-       codec->dapm.bias_level = level;
        return 0;
 }
 
@@ -383,6 +382,7 @@ static int adau1781_set_input_mode(struct adau *adau, unsigned int reg,
 
 static int adau1781_codec_probe(struct snd_soc_codec *codec)
 {
+       struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
        struct adau1781_platform_data *pdata = dev_get_platdata(codec->dev);
        struct adau *adau = snd_soc_codec_get_drvdata(codec);
        int ret;
@@ -403,19 +403,17 @@ static int adau1781_codec_probe(struct snd_soc_codec *codec)
        }
 
        if (pdata && pdata->use_dmic) {
-               ret = snd_soc_dapm_new_controls(&codec->dapm,
+               ret = snd_soc_dapm_new_controls(dapm,
                        adau1781_dmic_dapm_widgets,
                        ARRAY_SIZE(adau1781_dmic_dapm_widgets));
                if (ret)
                        return ret;
-               ret = snd_soc_dapm_add_routes(&codec->dapm,
-                       adau1781_dmic_dapm_routes,
+               ret = snd_soc_dapm_add_routes(dapm, adau1781_dmic_dapm_routes,
                        ARRAY_SIZE(adau1781_dmic_dapm_routes));
                if (ret)
                        return ret;
        } else {
-               ret = snd_soc_dapm_add_routes(&codec->dapm,
-                       adau1781_adc_dapm_routes,
+               ret = snd_soc_dapm_add_routes(dapm, adau1781_adc_dapm_routes,
                        ARRAY_SIZE(adau1781_adc_dapm_routes));
                if (ret)
                        return ret;
index fa2e690e51c8b5292ff690480b996c9cea14c610..fcf05b254ecd5c37a91dbff5a3ccc3de1069e2f0 100644 (file)
@@ -155,6 +155,7 @@ static int adau17x1_dsp_mux_enum_put(struct snd_kcontrol *kcontrol,
        struct snd_ctl_elem_value *ucontrol)
 {
        struct snd_soc_codec *codec = snd_soc_dapm_kcontrol_codec(kcontrol);
+       struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
        struct adau *adau = snd_soc_codec_get_drvdata(codec);
        struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
        struct snd_soc_dapm_update update;
@@ -188,7 +189,7 @@ static int adau17x1_dsp_mux_enum_put(struct snd_kcontrol *kcontrol,
                update.reg = reg;
                update.val = val;
 
-               snd_soc_dapm_mux_update_power(&codec->dapm, kcontrol,
+               snd_soc_dapm_mux_update_power(dapm, kcontrol,
                                ucontrol->value.enumerated.item[0], e, &update);
        }
 
@@ -444,8 +445,8 @@ static int adau17x1_set_dai_pll(struct snd_soc_dai *dai, int pll_id,
 static int adau17x1_set_dai_sysclk(struct snd_soc_dai *dai,
                int clk_id, unsigned int freq, int dir)
 {
+       struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(dai->codec);
        struct adau *adau = snd_soc_codec_get_drvdata(dai->codec);
-       struct snd_soc_dapm_context *dapm = &dai->codec->dapm;
 
        switch (clk_id) {
        case ADAU17X1_CLK_SRC_MCLK:
@@ -804,6 +805,7 @@ EXPORT_SYMBOL_GPL(adau17x1_setup_firmware);
 
 int adau17x1_add_widgets(struct snd_soc_codec *codec)
 {
+       struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
        struct adau *adau = snd_soc_codec_get_drvdata(codec);
        int ret;
 
@@ -811,14 +813,13 @@ int adau17x1_add_widgets(struct snd_soc_codec *codec)
                ARRAY_SIZE(adau17x1_controls));
        if (ret)
                return ret;
-       ret = snd_soc_dapm_new_controls(&codec->dapm, adau17x1_dapm_widgets,
+       ret = snd_soc_dapm_new_controls(dapm, adau17x1_dapm_widgets,
                ARRAY_SIZE(adau17x1_dapm_widgets));
        if (ret)
                return ret;
 
        if (adau17x1_has_dsp(adau)) {
-               ret = snd_soc_dapm_new_controls(&codec->dapm,
-                       adau17x1_dsp_dapm_widgets,
+               ret = snd_soc_dapm_new_controls(dapm, adau17x1_dsp_dapm_widgets,
                        ARRAY_SIZE(adau17x1_dsp_dapm_widgets));
                if (ret)
                        return ret;
@@ -840,21 +841,20 @@ EXPORT_SYMBOL_GPL(adau17x1_add_widgets);
 
 int adau17x1_add_routes(struct snd_soc_codec *codec)
 {
+       struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
        struct adau *adau = snd_soc_codec_get_drvdata(codec);
        int ret;
 
-       ret = snd_soc_dapm_add_routes(&codec->dapm, adau17x1_dapm_routes,
+       ret = snd_soc_dapm_add_routes(dapm, adau17x1_dapm_routes,
                ARRAY_SIZE(adau17x1_dapm_routes));
        if (ret)
                return ret;
 
        if (adau17x1_has_dsp(adau)) {
-               ret = snd_soc_dapm_add_routes(&codec->dapm,
-                       adau17x1_dsp_dapm_routes,
+               ret = snd_soc_dapm_add_routes(dapm, adau17x1_dsp_dapm_routes,
                        ARRAY_SIZE(adau17x1_dsp_dapm_routes));
        } else {
-               ret = snd_soc_dapm_add_routes(&codec->dapm,
-                       adau17x1_no_dsp_dapm_routes,
+               ret = snd_soc_dapm_add_routes(dapm, adau17x1_no_dsp_dapm_routes,
                        ARRAY_SIZE(adau17x1_no_dsp_dapm_routes));
        }
        return ret;
index 7ad8e156e2df9010a6d2fbe2d70bf45358da79af..9bdd15f408c164e9756f52e2ea041df9a0f65293 100644 (file)
@@ -202,7 +202,7 @@ static const struct snd_soc_dapm_route adau1977_dapm_routes[] = {
                ADAU1977_REG_DC_HPF_CAL, (x) - 1, 1, 0)
 
 #define ADAU1977_DC_SUB_SWITCH(x) \
-       SOC_SINGLE("ADC" #x " DC Substraction Capture Switch", \
+       SOC_SINGLE("ADC" #x " DC Subtraction Capture Switch", \
                ADAU1977_REG_DC_HPF_CAL, (x) + 3, 1, 0)
 
 static const struct snd_kcontrol_new adau1977_snd_controls[] = {
@@ -485,7 +485,7 @@ static int adau1977_set_bias_level(struct snd_soc_codec *codec,
        case SND_SOC_BIAS_PREPARE:
                break;
        case SND_SOC_BIAS_STANDBY:
-               if (codec->dapm.bias_level == SND_SOC_BIAS_OFF)
+               if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_OFF)
                        ret = adau1977_power_enable(adau1977);
                break;
        case SND_SOC_BIAS_OFF:
@@ -493,12 +493,7 @@ static int adau1977_set_bias_level(struct snd_soc_codec *codec,
                break;
        }
 
-       if (ret)
-               return ret;
-
-       codec->dapm.bias_level = level;
-
-       return 0;
+       return ret;
 }
 
 static int adau1977_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask,
@@ -853,12 +848,13 @@ static int adau1977_set_sysclk(struct snd_soc_codec *codec,
 
 static int adau1977_codec_probe(struct snd_soc_codec *codec)
 {
+       struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
        struct adau1977 *adau1977 = snd_soc_codec_get_drvdata(codec);
        int ret;
 
        switch (adau1977->type) {
        case ADAU1977:
-               ret = snd_soc_dapm_new_controls(&codec->dapm,
+               ret = snd_soc_dapm_new_controls(dapm,
                        adau1977_micbias_dapm_widgets,
                        ARRAY_SIZE(adau1977_micbias_dapm_widgets));
                if (ret < 0)
index 4373ada95648e6890f013582b97c355b45e76dd1..36d8425707459aec9f35bcdb9009b25fc546ad1b 100644 (file)
@@ -539,7 +539,7 @@ static int adav80x_set_sysclk(struct snd_soc_codec *codec,
                              unsigned int freq, int dir)
 {
        struct adav80x *adav80x = snd_soc_codec_get_drvdata(codec);
-       struct snd_soc_dapm_context *dapm = &codec->dapm;
+       struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
 
        if (dir == SND_SOC_CLOCK_IN) {
                switch (clk_id) {
@@ -622,6 +622,7 @@ static int adav80x_set_sysclk(struct snd_soc_codec *codec,
 static int adav80x_set_pll(struct snd_soc_codec *codec, int pll_id,
                int source, unsigned int freq_in, unsigned int freq_out)
 {
+       struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
        struct adav80x *adav80x = snd_soc_codec_get_drvdata(codec);
        unsigned int pll_ctrl1 = 0;
        unsigned int pll_ctrl2 = 0;
@@ -687,7 +688,7 @@ static int adav80x_set_pll(struct snd_soc_codec *codec, int pll_id,
 
                adav80x->pll_src = source;
 
-               snd_soc_dapm_sync(&codec->dapm);
+               snd_soc_dapm_sync(dapm);
        }
 
        return 0;
@@ -714,7 +715,6 @@ static int adav80x_set_bias_level(struct snd_soc_codec *codec,
                break;
        }
 
-       codec->dapm.bias_level = level;
        return 0;
 }
 
@@ -801,11 +801,12 @@ static struct snd_soc_dai_driver adav80x_dais[] = {
 
 static int adav80x_probe(struct snd_soc_codec *codec)
 {
+       struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
        struct adav80x *adav80x = snd_soc_codec_get_drvdata(codec);
 
        /* Force PLLs on for SYSCLK output */
-       snd_soc_dapm_force_enable_pin(&codec->dapm, "PLL1");
-       snd_soc_dapm_force_enable_pin(&codec->dapm, "PLL2");
+       snd_soc_dapm_force_enable_pin(dapm, "PLL1");
+       snd_soc_dapm_force_enable_pin(dapm, "PLL2");
 
        /* Power down S/PDIF receiver, since it is currently not supported */
        regmap_write(adav80x->regmap, ADAV80X_PLL_OUTE, 0x20);
index 9130d916f2f4d07badd45361de7b8e5415398986..8670861e5bec8d17130976487dffeab1069e4aff 100644 (file)
@@ -341,7 +341,6 @@ static int ak4535_set_bias_level(struct snd_soc_codec *codec,
                snd_soc_update_bits(codec, AK4535_PM1, 0x80, 0);
                break;
        }
-       codec->dapm.bias_level = level;
        return 0;
 }
 
index 81b54a270bd8f800637108d027f9edfffb464d04..2d0ff4595ea00f494b0846adb63e805ecef1e25c 100644 (file)
@@ -412,7 +412,7 @@ static int ak4641_set_bias_level(struct snd_soc_codec *codec,
                snd_soc_update_bits(codec, AK4641_DAC, 0x20, 0x20);
                break;
        case SND_SOC_BIAS_STANDBY:
-               if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) {
+               if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_OFF) {
                        if (pdata && gpio_is_valid(pdata->gpio_power))
                                gpio_set_value(pdata->gpio_power, 1);
                        mdelay(1);
@@ -439,7 +439,6 @@ static int ak4641_set_bias_level(struct snd_soc_codec *codec,
                regcache_mark_dirty(ak4641->regmap);
                break;
        }
-       codec->dapm.bias_level = level;
        return 0;
 }
 
index 13585e88f59704530e17ff36c0394b17d8c04571..7c0f6552c229b641ab8a81c83080411be9724ae9 100644 (file)
@@ -482,7 +482,6 @@ static int ak4642_set_bias_level(struct snd_soc_codec *codec,
                snd_soc_update_bits(codec, PW_MGMT1, PMVCM, PMVCM);
                break;
        }
-       codec->dapm.bias_level = level;
 
        return 0;
 }
index 2a58b1dccd2f18cb41221c45ac4d026e731240c9..0e59063aeb6f7916265a66636d8debb5d02e2853 100644 (file)
@@ -577,7 +577,6 @@ static int ak4671_set_bias_level(struct snd_soc_codec *codec,
                snd_soc_write(codec, AK4671_AD_DA_POWER_MANAGEMENT, 0x00);
                break;
        }
-       codec->dapm.bias_level = level;
        return 0;
 }
 
index 0e357996864bd141f4d57283c03fba3b0e11b8d7..0fc24e0d518c446053643a100abb3e0e2d659bb7 100644 (file)
@@ -826,7 +826,6 @@ static int alc5623_set_bias_level(struct snd_soc_codec *codec,
                snd_soc_write(codec, ALC5623_PWR_MANAG_ADD1, 0);
                break;
        }
-       codec->dapm.bias_level = level;
        return 0;
 }
 
@@ -894,7 +893,7 @@ static int alc5623_resume(struct snd_soc_codec *codec)
 static int alc5623_probe(struct snd_soc_codec *codec)
 {
        struct alc5623_priv *alc5623 = snd_soc_codec_get_drvdata(codec);
-       struct snd_soc_dapm_context *dapm = &codec->dapm;
+       struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
 
        alc5623_reset(codec);
 
index db3283abbe180788f10b3d7e5b70df996087867b..607a63b9705f939288c6a270e0fe46b06e6a21ab 100644 (file)
@@ -1000,7 +1000,6 @@ static int alc5632_set_bias_level(struct snd_soc_codec *codec,
                                ALC5632_PWR_MANAG_ADD1_MASK, 0);
                break;
        }
-       codec->dapm.bias_level = level;
        return 0;
 }
 
index eff4b4d512b7b8fbd8bfa31c3c0ee3a79474a478..88f6df21ad959e9d0bcf3feac761080114b140e5 100644 (file)
@@ -208,11 +208,12 @@ static const struct snd_soc_dapm_widget arizona_spkr =
 
 int arizona_init_spk(struct snd_soc_codec *codec)
 {
+       struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
        struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
        struct arizona *arizona = priv->arizona;
        int ret;
 
-       ret = snd_soc_dapm_new_controls(&codec->dapm, &arizona_spkl, 1);
+       ret = snd_soc_dapm_new_controls(dapm, &arizona_spkl, 1);
        if (ret != 0)
                return ret;
 
@@ -220,8 +221,7 @@ int arizona_init_spk(struct snd_soc_codec *codec)
        case WM8997:
                break;
        default:
-               ret = snd_soc_dapm_new_controls(&codec->dapm,
-                                               &arizona_spkr, 1);
+               ret = snd_soc_dapm_new_controls(dapm, &arizona_spkr, 1);
                if (ret != 0)
                        return ret;
                break;
@@ -258,13 +258,14 @@ static const struct snd_soc_dapm_route arizona_mono_routes[] = {
 
 int arizona_init_mono(struct snd_soc_codec *codec)
 {
+       struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
        struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
        struct arizona *arizona = priv->arizona;
        int i;
 
        for (i = 0; i < ARIZONA_MAX_OUTPUT; ++i) {
                if (arizona->pdata.out_mono[i])
-                       snd_soc_dapm_add_routes(&codec->dapm,
+                       snd_soc_dapm_add_routes(dapm,
                                                &arizona_mono_routes[i], 1);
        }
 
@@ -274,6 +275,7 @@ EXPORT_SYMBOL_GPL(arizona_init_mono);
 
 int arizona_init_gpio(struct snd_soc_codec *codec)
 {
+       struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
        struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
        struct arizona *arizona = priv->arizona;
        int i;
@@ -281,23 +283,21 @@ int arizona_init_gpio(struct snd_soc_codec *codec)
        switch (arizona->type) {
        case WM5110:
        case WM8280:
-               snd_soc_dapm_disable_pin(&codec->dapm, "DRC2 Signal Activity");
+               snd_soc_dapm_disable_pin(dapm, "DRC2 Signal Activity");
                break;
        default:
                break;
        }
 
-       snd_soc_dapm_disable_pin(&codec->dapm, "DRC1 Signal Activity");
+       snd_soc_dapm_disable_pin(dapm, "DRC1 Signal Activity");
 
        for (i = 0; i < ARRAY_SIZE(arizona->pdata.gpio_defaults); i++) {
                switch (arizona->pdata.gpio_defaults[i] & ARIZONA_GPN_FN_MASK) {
                case ARIZONA_GP_FN_DRC1_SIGNAL_DETECT:
-                       snd_soc_dapm_enable_pin(&codec->dapm,
-                                               "DRC1 Signal Activity");
+                       snd_soc_dapm_enable_pin(dapm, "DRC1 Signal Activity");
                        break;
                case ARIZONA_GP_FN_DRC2_SIGNAL_DETECT:
-                       snd_soc_dapm_enable_pin(&codec->dapm,
-                                               "DRC2 Signal Activity");
+                       snd_soc_dapm_enable_pin(dapm, "DRC2 Signal Activity");
                        break;
                default:
                        break;
@@ -851,6 +851,134 @@ int arizona_hp_ev(struct snd_soc_dapm_widget *w,
 }
 EXPORT_SYMBOL_GPL(arizona_hp_ev);
 
+static int arizona_dvfs_enable(struct snd_soc_codec *codec)
+{
+       const struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
+       struct arizona *arizona = priv->arizona;
+       int ret;
+
+       ret = regulator_set_voltage(arizona->dcvdd, 1800000, 1800000);
+       if (ret) {
+               dev_err(codec->dev, "Failed to boost DCVDD: %d\n", ret);
+               return ret;
+       }
+
+       ret = regmap_update_bits(arizona->regmap,
+                                ARIZONA_DYNAMIC_FREQUENCY_SCALING_1,
+                                ARIZONA_SUBSYS_MAX_FREQ,
+                                ARIZONA_SUBSYS_MAX_FREQ);
+       if (ret) {
+               dev_err(codec->dev, "Failed to enable subsys max: %d\n", ret);
+               regulator_set_voltage(arizona->dcvdd, 1200000, 1800000);
+               return ret;
+       }
+
+       return 0;
+}
+
+static int arizona_dvfs_disable(struct snd_soc_codec *codec)
+{
+       const struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
+       struct arizona *arizona = priv->arizona;
+       int ret;
+
+       ret = regmap_update_bits(arizona->regmap,
+                                ARIZONA_DYNAMIC_FREQUENCY_SCALING_1,
+                                ARIZONA_SUBSYS_MAX_FREQ, 0);
+       if (ret) {
+               dev_err(codec->dev, "Failed to disable subsys max: %d\n", ret);
+               return ret;
+       }
+
+       ret = regulator_set_voltage(arizona->dcvdd, 1200000, 1800000);
+       if (ret) {
+               dev_err(codec->dev, "Failed to unboost DCVDD: %d\n", ret);
+               return ret;
+       }
+
+       return 0;
+}
+
+int arizona_dvfs_up(struct snd_soc_codec *codec, unsigned int flags)
+{
+       struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
+       int ret = 0;
+
+       mutex_lock(&priv->dvfs_lock);
+
+       if (!priv->dvfs_cached && !priv->dvfs_reqs) {
+               ret = arizona_dvfs_enable(codec);
+               if (ret)
+                       goto err;
+       }
+
+       priv->dvfs_reqs |= flags;
+err:
+       mutex_unlock(&priv->dvfs_lock);
+       return ret;
+}
+EXPORT_SYMBOL_GPL(arizona_dvfs_up);
+
+int arizona_dvfs_down(struct snd_soc_codec *codec, unsigned int flags)
+{
+       struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
+       unsigned int old_reqs;
+       int ret = 0;
+
+       mutex_lock(&priv->dvfs_lock);
+
+       old_reqs = priv->dvfs_reqs;
+       priv->dvfs_reqs &= ~flags;
+
+       if (!priv->dvfs_cached && old_reqs && !priv->dvfs_reqs)
+               ret = arizona_dvfs_disable(codec);
+
+       mutex_unlock(&priv->dvfs_lock);
+       return ret;
+}
+EXPORT_SYMBOL_GPL(arizona_dvfs_down);
+
+int arizona_dvfs_sysclk_ev(struct snd_soc_dapm_widget *w,
+                          struct snd_kcontrol *kcontrol, int event)
+{
+       struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+       struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
+       int ret = 0;
+
+       mutex_lock(&priv->dvfs_lock);
+
+       switch (event) {
+       case SND_SOC_DAPM_POST_PMU:
+               if (priv->dvfs_reqs)
+                       ret = arizona_dvfs_enable(codec);
+
+               priv->dvfs_cached = false;
+               break;
+       case SND_SOC_DAPM_PRE_PMD:
+               /* We must ensure DVFS is disabled before the codec goes into
+                * suspend so that we are never in an illegal state of DVFS
+                * enabled without enough DCVDD
+                */
+               priv->dvfs_cached = true;
+
+               if (priv->dvfs_reqs)
+                       ret = arizona_dvfs_disable(codec);
+               break;
+       default:
+               break;
+       }
+
+       mutex_unlock(&priv->dvfs_lock);
+       return ret;
+}
+EXPORT_SYMBOL_GPL(arizona_dvfs_sysclk_ev);
+
+void arizona_init_dvfs(struct arizona_priv *priv)
+{
+       mutex_init(&priv->dvfs_lock);
+}
+EXPORT_SYMBOL_GPL(arizona_init_dvfs);
+
 static unsigned int arizona_sysclk_48k_rates[] = {
        6144000,
        12288000,
@@ -1266,7 +1394,7 @@ static int arizona_hw_params_rate(struct snd_pcm_substream *substream,
        struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
        struct arizona_dai_priv *dai_priv = &priv->dai[dai->id - 1];
        int base = dai->driver->base;
-       int i, sr_val;
+       int i, sr_val, ret;
 
        /*
         * We will need to be more flexible than this in future,
@@ -1282,6 +1410,23 @@ static int arizona_hw_params_rate(struct snd_pcm_substream *substream,
        }
        sr_val = i;
 
+       switch (priv->arizona->type) {
+       case WM5102:
+       case WM8997:
+               if (arizona_sr_vals[sr_val] >= 88200)
+                       ret = arizona_dvfs_up(codec, ARIZONA_DVFS_SR1_RQ);
+               else
+                       ret = arizona_dvfs_down(codec, ARIZONA_DVFS_SR1_RQ);
+
+               if (ret) {
+                       arizona_aif_err(dai, "Failed to change DVFS %d\n", ret);
+                       return ret;
+               }
+               break;
+       default:
+               break;
+       }
+
        switch (dai_priv->clk) {
        case ARIZONA_CLK_SYSCLK:
                switch (priv->arizona->type) {
@@ -1474,6 +1619,7 @@ static int arizona_dai_set_sysclk(struct snd_soc_dai *dai,
                                  int clk_id, unsigned int freq, int dir)
 {
        struct snd_soc_codec *codec = dai->codec;
+       struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
        struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
        struct arizona_dai_priv *dai_priv = &priv->dai[dai->id - 1];
        struct snd_soc_dapm_route routes[2];
@@ -1504,15 +1650,15 @@ static int arizona_dai_set_sysclk(struct snd_soc_dai *dai,
 
        routes[0].source = arizona_dai_clk_str(dai_priv->clk);
        routes[1].source = arizona_dai_clk_str(dai_priv->clk);
-       snd_soc_dapm_del_routes(&codec->dapm, routes, ARRAY_SIZE(routes));
+       snd_soc_dapm_del_routes(dapm, routes, ARRAY_SIZE(routes));
 
        routes[0].source = arizona_dai_clk_str(clk_id);
        routes[1].source = arizona_dai_clk_str(clk_id);
-       snd_soc_dapm_add_routes(&codec->dapm, routes, ARRAY_SIZE(routes));
+       snd_soc_dapm_add_routes(dapm, routes, ARRAY_SIZE(routes));
 
        dai_priv->clk = clk_id;
 
-       return snd_soc_dapm_sync(&codec->dapm);
+       return snd_soc_dapm_sync(dapm);
 }
 
 static int arizona_set_tristate(struct snd_soc_dai *dai, int tristate)
index 11ff899b02724fae943d2bc1ce98550b26a62985..84e119a5651533ff1c012c08617384078b254f68 100644 (file)
@@ -60,6 +60,9 @@
 #define ARIZONA_MAX_DAI  6
 #define ARIZONA_MAX_ADSP 4
 
+#define ARIZONA_DVFS_SR1_RQ    0x001
+#define ARIZONA_DVFS_ADSP1_RQ  0x100
+
 struct arizona;
 struct wm_adsp;
 
@@ -84,6 +87,10 @@ struct arizona_priv {
 
        unsigned int spk_ena:2;
        unsigned int spk_ena_pending:1;
+
+       unsigned int dvfs_reqs;
+       struct mutex dvfs_lock;
+       bool dvfs_cached;
 };
 
 #define ARIZONA_NUM_MIXER_INPUTS 103
@@ -107,8 +114,8 @@ extern int arizona_mixer_values[ARIZONA_NUM_MIXER_INPUTS];
                             arizona_mixer_tlv)
 
 #define ARIZONA_MUX_ENUM_DECL(name, reg) \
-       SOC_VALUE_ENUM_SINGLE_DECL(name, reg, 0, 0xff,                  \
-                                  arizona_mixer_texts, arizona_mixer_values)
+       SOC_VALUE_ENUM_SINGLE_AUTODISABLE_DECL( \
+               name, reg, 0, 0xff, arizona_mixer_texts, arizona_mixer_values)
 
 #define ARIZONA_MUX_CTL_DECL(name) \
        const struct snd_kcontrol_new name##_mux =      \
@@ -245,6 +252,12 @@ struct arizona_fll {
        char clock_ok_name[ARIZONA_FLL_NAME_LEN];
 };
 
+extern int arizona_dvfs_up(struct snd_soc_codec *codec, unsigned int flags);
+extern int arizona_dvfs_down(struct snd_soc_codec *codec, unsigned int flags);
+extern int arizona_dvfs_sysclk_ev(struct snd_soc_dapm_widget *w,
+                                 struct snd_kcontrol *kcontrol, int event);
+extern void arizona_init_dvfs(struct arizona_priv *priv);
+
 extern int arizona_init_fll(struct arizona *arizona, int id, int base,
                            int lock_irq, int ok_irq, struct arizona_fll *fll);
 extern int arizona_set_fll_refclk(struct arizona_fll *fll, int source,
index e7238b8904bceec6f0903bd2974d00b4c6c262aa..b084ad113e967824a6809dd3e3394f18990e3a72 100644 (file)
@@ -63,7 +63,7 @@ static int bt_sco_remove(struct platform_device *pdev)
        return 0;
 }
 
-static struct platform_device_id bt_sco_driver_ids[] = {
+static const struct platform_device_id bt_sco_driver_ids[] = {
        {
                .name           = "dfbmcs320",
        },
@@ -74,9 +74,18 @@ static struct platform_device_id bt_sco_driver_ids[] = {
 };
 MODULE_DEVICE_TABLE(platform, bt_sco_driver_ids);
 
+#if defined(CONFIG_OF)
+static const struct of_device_id bt_sco_codec_of_match[] = {
+       { .compatible = "delta,dfbmcs320", },
+       {},
+};
+MODULE_DEVICE_TABLE(of, bt_sco_codec_of_match);
+#endif
+
 static struct platform_driver bt_sco_driver = {
        .driver = {
                .name = "bt-sco",
+               .of_match_table = of_match_ptr(bt_sco_codec_of_match),
        },
        .probe = bt_sco_probe,
        .remove = bt_sco_remove,
index d6dedd4eab292613138428d2429e35d03da3bf7a..1c895a53001d9b313f0ef69cd0c9ab15ae54dfd8 100644 (file)
@@ -92,7 +92,6 @@ static int cq93vc_set_bias_level(struct snd_soc_codec *codec,
                             DAVINCI_VC_REG12_POWER_ALL_OFF);
                break;
        }
-       codec->dapm.bias_level = level;
 
        return 0;
 }
index 60598b23034111cb8646b7a8607bca95db79cf01..8f40025b7e7ca457f4f65eaca2f64a59e468a4a9 100644 (file)
@@ -13,7 +13,6 @@
 
 #include <linux/module.h>
 #include <linux/moduleparam.h>
-#include <linux/version.h>
 #include <linux/kernel.h>
 #include <linux/init.h>
 #include <linux/delay.h>
index cac48ddf3ba6bb71a20da39945fd6f819b24037a..d7ec4756e45bf9bab0c08059ee74c39b4ea3c812 100644 (file)
@@ -503,7 +503,6 @@ static int cs4265_set_bias_level(struct snd_soc_codec *codec,
                        CS4265_PWRCTL_PDN);
                break;
        }
-       codec->dapm.bias_level = level;
        return 0;
 }
 
index 1589e7a881d817ab403f7a7a149cecfda4797a92..4de52c9957ac5a53c321b6eef5b805ad199a60b4 100644 (file)
@@ -897,7 +897,7 @@ static int cs42l52_set_bias_level(struct snd_soc_codec *codec,
                                    CS42L52_PWRCTL1_PDN_CODEC, 0);
                break;
        case SND_SOC_BIAS_STANDBY:
-               if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) {
+               if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_OFF) {
                        regcache_cache_only(cs42l52->regmap, false);
                        regcache_sync(cs42l52->regmap);
                }
@@ -908,7 +908,6 @@ static int cs42l52_set_bias_level(struct snd_soc_codec *codec,
                regcache_cache_only(cs42l52->regmap, true);
                break;
        }
-       codec->dapm.bias_level = level;
 
        return 0;
 }
@@ -956,7 +955,7 @@ static void cs42l52_beep_work(struct work_struct *work)
        struct cs42l52_private *cs42l52 =
                container_of(work, struct cs42l52_private, beep_work);
        struct snd_soc_codec *codec = cs42l52->codec;
-       struct snd_soc_dapm_context *dapm = &codec->dapm;
+       struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
        int i;
        int val = 0;
        int best = 0;
index cbc654fe48c76d7fa1c231a874f0e60588ecfc2f..1e11ba45a79f01a0f2a45b538618c4a2d8e88002 100644 (file)
@@ -953,7 +953,7 @@ static int cs42l56_set_bias_level(struct snd_soc_codec *codec,
                                    CS42L56_PDN_ALL_MASK, 0);
                break;
        case SND_SOC_BIAS_STANDBY:
-               if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) {
+               if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_OFF) {
                        regcache_cache_only(cs42l56->regmap, false);
                        regcache_sync(cs42l56->regmap);
                        ret = regulator_bulk_enable(ARRAY_SIZE(cs42l56->supplies),
@@ -978,7 +978,6 @@ static int cs42l56_set_bias_level(struct snd_soc_codec *codec,
                                                    cs42l56->supplies);
                break;
        }
-       codec->dapm.bias_level = level;
 
        return 0;
 }
@@ -1026,7 +1025,7 @@ static void cs42l56_beep_work(struct work_struct *work)
        struct cs42l56_private *cs42l56 =
                container_of(work, struct cs42l56_private, beep_work);
        struct snd_soc_codec *codec = cs42l56->codec;
-       struct snd_soc_dapm_context *dapm = &codec->dapm;
+       struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
        int i;
        int val = 0;
        int best = 0;
index 8ecedba79606c561c0a385e04091513074662210..b7853b9d3a60bfe3c2273262a788b59473dfc9da 100644 (file)
@@ -1208,7 +1208,7 @@ static int cs42l73_set_bias_level(struct snd_soc_codec *codec,
                break;
 
        case SND_SOC_BIAS_STANDBY:
-               if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) {
+               if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_OFF) {
                        regcache_cache_only(cs42l73->regmap, false);
                        regcache_sync(cs42l73->regmap);
                }
@@ -1228,7 +1228,6 @@ static int cs42l73_set_bias_level(struct snd_soc_codec *codec,
                snd_soc_update_bits(codec, CS42L73_DMMCC, CS42L73_MCLKDIS, 1);
                break;
        }
-       codec->dapm.bias_level = level;
        return 0;
 }
 
index 670ebfe129030305369480a91ac3e21059f99933..e1d46862e81f15c34f284a19240e01ee1a841549 100644 (file)
@@ -380,7 +380,7 @@ EXPORT_SYMBOL_GPL(cs42xx8_regmap_config);
 static int cs42xx8_codec_probe(struct snd_soc_codec *codec)
 {
        struct cs42xx8_priv *cs42xx8 = snd_soc_codec_get_drvdata(codec);
-       struct snd_soc_dapm_context *dapm = &codec->dapm;
+       struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
 
        switch (cs42xx8->drvdata->num_adcs) {
        case 3:
index 0f334bc1b63c78893a452cd5d2cbda86b2f47a0f..d6f4abbbf8a7fd669237d667a03825c13c3603ed 100644 (file)
@@ -333,7 +333,7 @@ static int cx20442_set_bias_level(struct snd_soc_codec *codec,
 
        switch (level) {
        case SND_SOC_BIAS_PREPARE:
-               if (codec->dapm.bias_level != SND_SOC_BIAS_STANDBY)
+               if (snd_soc_codec_get_bias_level(codec) != SND_SOC_BIAS_STANDBY)
                        break;
                if (IS_ERR(cx20442->por))
                        err = PTR_ERR(cx20442->por);
@@ -341,7 +341,7 @@ static int cx20442_set_bias_level(struct snd_soc_codec *codec,
                        err = regulator_enable(cx20442->por);
                break;
        case SND_SOC_BIAS_STANDBY:
-               if (codec->dapm.bias_level != SND_SOC_BIAS_PREPARE)
+               if (snd_soc_codec_get_bias_level(codec) != SND_SOC_BIAS_PREPARE)
                        break;
                if (IS_ERR(cx20442->por))
                        err = PTR_ERR(cx20442->por);
@@ -351,8 +351,6 @@ static int cx20442_set_bias_level(struct snd_soc_codec *codec,
        default:
                break;
        }
-       if (!err)
-               codec->dapm.bias_level = level;
 
        return err;
 }
index 9ec577f0edb4c061197e75b932f671c43577b208..238e48a3a4fe7bbda84b0aa8b6b6639e2434bdd6 100644 (file)
@@ -1374,7 +1374,7 @@ static int da7213_set_bias_level(struct snd_soc_codec *codec,
        case SND_SOC_BIAS_PREPARE:
                break;
        case SND_SOC_BIAS_STANDBY:
-               if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) {
+               if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_OFF) {
                        /* Enable VMID reference & master bias */
                        snd_soc_update_bits(codec, DA7213_REFERENCES,
                                            DA7213_VMID_EN | DA7213_BIAS_EN,
@@ -1387,7 +1387,6 @@ static int da7213_set_bias_level(struct snd_soc_codec *codec,
                                    DA7213_VMID_EN | DA7213_BIAS_EN, 0);
                break;
        }
-       codec->dapm.bias_level = level;
        return 0;
 }
 
index 911c26c705fc8d226e819d469c669b72f989517a..207523686bd55993685693793510ead04460c364 100644 (file)
@@ -1432,7 +1432,7 @@ static int da732x_set_bias_level(struct snd_soc_codec *codec,
        case SND_SOC_BIAS_PREPARE:
                break;
        case SND_SOC_BIAS_STANDBY:
-               if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) {
+               if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_OFF) {
                        /* Init Codec */
                        snd_soc_write(codec, DA732X_REG_REF1,
                                      DA732X_VMID_FASTCHG);
@@ -1502,8 +1502,6 @@ static int da732x_set_bias_level(struct snd_soc_codec *codec,
                break;
        }
 
-       codec->dapm.bias_level = level;
-
        return 0;
 }
 
index ad19cc56702b46fda1d98045730ae27bd3a2b633..66bb446473b868532ef7bee0c117c9584f5e995f 100644 (file)
@@ -1364,7 +1364,7 @@ static int da9055_set_bias_level(struct snd_soc_codec *codec,
        case SND_SOC_BIAS_PREPARE:
                break;
        case SND_SOC_BIAS_STANDBY:
-               if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) {
+               if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_OFF) {
                        /* Enable VMID reference & master bias */
                        snd_soc_update_bits(codec, DA9055_REFERENCES,
                                            DA9055_VMID_EN | DA9055_BIAS_EN,
@@ -1377,7 +1377,6 @@ static int da9055_set_bias_level(struct snd_soc_codec *codec,
                                    DA9055_VMID_EN | DA9055_BIAS_EN, 0);
                break;
        }
-       codec->dapm.bias_level = level;
        return 0;
 }
 
index c5f35a07e8e48106335df49153acd81e104f7aa9..6a091016e0fc767c2465cfd5c8eaf822d09d2ea3 100644 (file)
@@ -536,7 +536,7 @@ static int es8328_set_bias_level(struct snd_soc_codec *codec,
                break;
 
        case SND_SOC_BIAS_STANDBY:
-               if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) {
+               if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_OFF) {
                        snd_soc_update_bits(codec, ES8328_CONTROL1,
                                        ES8328_CONTROL1_VMIDSEL_MASK |
                                        ES8328_CONTROL1_ENREF,
@@ -566,7 +566,6 @@ static int es8328_set_bias_level(struct snd_soc_codec *codec,
                                0);
                break;
        }
-       codec->dapm.bias_level = level;
        return 0;
 }
 
index 3a89ce66d51d7e1c56b7c655fc0ed984e520e75b..ebd90283c9604119f2bfe41ecba6d5051307cf09 100644 (file)
@@ -909,8 +909,6 @@ static int isabelle_set_bias_level(struct snd_soc_codec *codec,
                break;
        }
 
-       codec->dapm.bias_level = level;
-
        return 0;
 }
 
index 933f4476d76ccd0bd009d27c40d9a43fa4e7b352..9363fdbca9cdb1f776c035097ac8f16b5de642a4 100644 (file)
@@ -258,7 +258,7 @@ static int jz4740_codec_set_bias_level(struct snd_soc_codec *codec,
                break;
        case SND_SOC_BIAS_STANDBY:
                /* The only way to clear the suspend flag is to reset the codec */
-               if (codec->dapm.bias_level == SND_SOC_BIAS_OFF)
+               if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_OFF)
                        jz4740_codec_wakeup(regmap);
 
                mask = JZ4740_CODEC_1_VREF_DISABLE |
@@ -281,8 +281,6 @@ static int jz4740_codec_set_bias_level(struct snd_soc_codec *codec,
                break;
        }
 
-       codec->dapm.bias_level = level;
-
        return 0;
 }
 
index a924bb9d78860c11c84d7420f46c54929d3b7eb8..99ffc49aa7799b03095d5593e2592f682b49b256 100644 (file)
 #include <sound/soc.h>
 #include <sound/tlv.h>
 
-struct lm4857 {
-       struct regmap *regmap;
-       uint8_t mode;
-};
-
 static const struct reg_default lm4857_default_regs[] = {
        { 0x0, 0x00 },
        { 0x1, 0x00 },
@@ -46,66 +41,33 @@ static const struct reg_default lm4857_default_regs[] = {
 #define LM4857_WAKEUP 5
 #define LM4857_EPGAIN 4
 
-static int lm4857_get_mode(struct snd_kcontrol *kcontrol,
-       struct snd_ctl_elem_value *ucontrol)
-{
-       struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
-       struct lm4857 *lm4857 = snd_soc_codec_get_drvdata(codec);
-
-       ucontrol->value.integer.value[0] = lm4857->mode;
-
-       return 0;
-}
-
-static int lm4857_set_mode(struct snd_kcontrol *kcontrol,
-       struct snd_ctl_elem_value *ucontrol)
-{
-       struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
-       struct lm4857 *lm4857 = snd_soc_codec_get_drvdata(codec);
-       uint8_t value = ucontrol->value.integer.value[0];
-
-       lm4857->mode = value;
-
-       if (codec->dapm.bias_level == SND_SOC_BIAS_ON)
-               regmap_update_bits(lm4857->regmap, LM4857_CTRL, 0x0F, value + 6);
-
-       return 1;
-}
-
-static int lm4857_set_bias_level(struct snd_soc_codec *codec,
-                                enum snd_soc_bias_level level)
-{
-       struct lm4857 *lm4857 = snd_soc_codec_get_drvdata(codec);
-
-       switch (level) {
-       case SND_SOC_BIAS_ON:
-               regmap_update_bits(lm4857->regmap, LM4857_CTRL, 0x0F,
-                       lm4857->mode + 6);
-               break;
-       case SND_SOC_BIAS_STANDBY:
-               regmap_update_bits(lm4857->regmap, LM4857_CTRL, 0x0F, 0);
-               break;
-       default:
-               break;
-       }
-
-       codec->dapm.bias_level = level;
-
-       return 0;
-}
+static const unsigned int lm4857_mode_values[] = {
+       0,
+       6,
+       7,
+       8,
+       9,
+};
 
-static const char *lm4857_mode[] = {
+static const char * const lm4857_mode_texts[] = {
+       "Off",
        "Earpiece",
        "Loudspeaker",
        "Loudspeaker + Headphone",
        "Headphone",
 };
 
-static SOC_ENUM_SINGLE_EXT_DECL(lm4857_mode_enum, lm4857_mode);
+static SOC_VALUE_ENUM_SINGLE_AUTODISABLE_DECL(lm4857_mode_enum,
+       LM4857_CTRL, 0, 0xf, lm4857_mode_texts, lm4857_mode_values);
+
+static const struct snd_kcontrol_new lm4857_mode_ctrl =
+       SOC_DAPM_ENUM("Mode", lm4857_mode_enum);
 
 static const struct snd_soc_dapm_widget lm4857_dapm_widgets[] = {
        SND_SOC_DAPM_INPUT("IN"),
 
+       SND_SOC_DAPM_DEMUX("Mode", SND_SOC_NOPM, 0, 0, &lm4857_mode_ctrl),
+
        SND_SOC_DAPM_OUTPUT("LS"),
        SND_SOC_DAPM_OUTPUT("HP"),
        SND_SOC_DAPM_OUTPUT("EP"),
@@ -127,24 +89,18 @@ static const struct snd_kcontrol_new lm4857_controls[] = {
                LM4857_WAKEUP, 1, 0),
        SOC_SINGLE("Earpiece 6dB Playback Switch", LM4857_CTRL,
                LM4857_EPGAIN, 1, 0),
-
-       SOC_ENUM_EXT("Mode", lm4857_mode_enum,
-               lm4857_get_mode, lm4857_set_mode),
 };
 
-/* There is a demux between the input signal and the output signals.
- * Currently there is no easy way to model it in ASoC and since it does not make
- * much of a difference in practice simply connect the input direclty to the
- * outputs. */
 static const struct snd_soc_dapm_route lm4857_routes[] = {
-       {"LS", NULL, "IN"},
-       {"HP", NULL, "IN"},
-       {"EP", NULL, "IN"},
+       { "Mode", NULL, "IN" },
+       { "LS", "Loudspeaker", "Mode" },
+       { "LS", "Loudspeaker + Headphone", "Mode" },
+       { "HP", "Headphone", "Mode" },
+       { "HP", "Loudspeaker + Headphone", "Mode" },
+       { "EP", "Earpiece", "Mode" },
 };
 
-static struct snd_soc_codec_driver soc_codec_dev_lm4857 = {
-       .set_bias_level = lm4857_set_bias_level,
-
+static struct snd_soc_component_driver lm4857_component_driver = {
        .controls = lm4857_controls,
        .num_controls = ARRAY_SIZE(lm4857_controls),
        .dapm_widgets = lm4857_dapm_widgets,
@@ -167,25 +123,14 @@ static const struct regmap_config lm4857_regmap_config = {
 static int lm4857_i2c_probe(struct i2c_client *i2c,
                            const struct i2c_device_id *id)
 {
-       struct lm4857 *lm4857;
-
-       lm4857 = devm_kzalloc(&i2c->dev, sizeof(*lm4857), GFP_KERNEL);
-       if (!lm4857)
-               return -ENOMEM;
-
-       i2c_set_clientdata(i2c, lm4857);
-
-       lm4857->regmap = devm_regmap_init_i2c(i2c, &lm4857_regmap_config);
-       if (IS_ERR(lm4857->regmap))
-               return PTR_ERR(lm4857->regmap);
+       struct regmap *regmap;
 
-       return snd_soc_register_codec(&i2c->dev, &soc_codec_dev_lm4857, NULL, 0);
-}
+       regmap = devm_regmap_init_i2c(i2c, &lm4857_regmap_config);
+       if (IS_ERR(regmap))
+               return PTR_ERR(regmap);
 
-static int lm4857_i2c_remove(struct i2c_client *i2c)
-{
-       snd_soc_unregister_codec(&i2c->dev);
-       return 0;
+       return devm_snd_soc_register_component(&i2c->dev,
+               &lm4857_component_driver, NULL, 0);
 }
 
 static const struct i2c_device_id lm4857_i2c_id[] = {
@@ -200,7 +145,6 @@ static struct i2c_driver lm4857_i2c_driver = {
                .owner = THIS_MODULE,
        },
        .probe = lm4857_i2c_probe,
-       .remove = lm4857_i2c_remove,
        .id_table = lm4857_i2c_id,
 };
 
index c4dfde9bdf1c10b21dc443374d1e534f6046b016..6600aa0a33dc578afb0361bf9cd3acc6584c7edb 100644 (file)
@@ -1271,7 +1271,7 @@ static int lm49453_set_bias_level(struct snd_soc_codec *codec,
                break;
 
        case SND_SOC_BIAS_STANDBY:
-               if (codec->dapm.bias_level == SND_SOC_BIAS_OFF)
+               if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_OFF)
                        regcache_sync(lm49453->regmap);
 
                snd_soc_update_bits(codec, LM49453_P0_PMC_SETUP_REG,
@@ -1284,8 +1284,6 @@ static int lm49453_set_bias_level(struct snd_soc_codec *codec,
                break;
        }
 
-       codec->dapm.bias_level = level;
-
        return 0;
 }
 
index 805b3f8cd39df1d526543385dd273da18d40e35f..d0f45348bfbbccd35afb992f19b11255d201374c 100644 (file)
@@ -1571,7 +1571,7 @@ static int max98088_set_bias_level(struct snd_soc_codec *codec,
                break;
 
        case SND_SOC_BIAS_STANDBY:
-               if (codec->dapm.bias_level == SND_SOC_BIAS_OFF)
+               if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_OFF)
                        regcache_sync(max98088->regmap);
 
                snd_soc_update_bits(codec, M98088_REG_4C_PWR_EN_IN,
@@ -1584,7 +1584,6 @@ static int max98088_set_bias_level(struct snd_soc_codec *codec,
                regcache_mark_dirty(max98088->regmap);
                break;
        }
-       codec->dapm.bias_level = level;
        return 0;
 }
 
index 3e33ef2acf3c993b6ae1d87317452c9fb4e9021c..78268f0514e95073e8b2006d4e2822a482fb6d3b 100644 (file)
@@ -27,7 +27,7 @@
 #include "max98090.h"
 
 /* Allows for sparsely populated register maps */
-static struct reg_default max98090_reg[] = {
+static const struct reg_default max98090_reg[] = {
        { 0x00, 0x00 }, /* 00 Software Reset */
        { 0x03, 0x04 }, /* 03 Interrupt Masks */
        { 0x04, 0x00 }, /* 04 System Clock Quick */
@@ -1500,7 +1500,7 @@ static const struct snd_soc_dapm_route max98091_dapm_routes[] = {
 static int max98090_add_widgets(struct snd_soc_codec *codec)
 {
        struct max98090_priv *max98090 = snd_soc_codec_get_drvdata(codec);
-       struct snd_soc_dapm_context *dapm = &codec->dapm;
+       struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
 
        snd_soc_add_codec_controls(codec, max98090_snd_controls,
                ARRAY_SIZE(max98090_snd_controls));
@@ -1798,16 +1798,17 @@ static int max98090_set_bias_level(struct snd_soc_codec *codec,
                 * away from ON. Disable the clock in that case, otherwise
                 * enable it.
                 */
-               if (!IS_ERR(max98090->mclk)) {
-                       if (codec->dapm.bias_level == SND_SOC_BIAS_ON)
-                               clk_disable_unprepare(max98090->mclk);
-                       else
-                               clk_prepare_enable(max98090->mclk);
-               }
+               if (IS_ERR(max98090->mclk))
+                       break;
+
+               if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_ON)
+                       clk_disable_unprepare(max98090->mclk);
+               else
+                       clk_prepare_enable(max98090->mclk);
                break;
 
        case SND_SOC_BIAS_STANDBY:
-               if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) {
+               if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_OFF) {
                        ret = regcache_sync(max98090->regmap);
                        if (ret != 0) {
                                dev_err(codec->dev,
@@ -1824,7 +1825,6 @@ static int max98090_set_bias_level(struct snd_soc_codec *codec,
                regcache_mark_dirty(max98090->regmap);
                break;
        }
-       codec->dapm.bias_level = level;
        return 0;
 }
 
@@ -2187,7 +2187,6 @@ static void max98090_jack_work(struct work_struct *work)
                struct max98090_priv,
                jack_work.work);
        struct snd_soc_codec *codec = max98090->codec;
-       struct snd_soc_dapm_context *dapm = &codec->dapm;
        int status = 0;
        int reg;
 
@@ -2266,8 +2265,6 @@ static void max98090_jack_work(struct work_struct *work)
 
        snd_soc_jack_report(max98090->jack, status,
                            SND_JACK_HEADSET | SND_JACK_BTN_0);
-
-       snd_soc_dapm_sync(dapm);
 }
 
 static irqreturn_t max98090_interrupt(int irq, void *data)
@@ -2422,6 +2419,8 @@ static int max98090_probe(struct snd_soc_codec *codec)
        struct max98090_cdata *cdata;
        enum max98090_type devtype;
        int ret = 0;
+       int err;
+       unsigned int micbias;
 
        dev_dbg(codec->dev, "max98090_probe\n");
 
@@ -2506,8 +2505,17 @@ static int max98090_probe(struct snd_soc_codec *codec)
        snd_soc_write(codec, M98090_REG_BIAS_CONTROL,
                M98090_VCM_MODE_MASK);
 
+       err = device_property_read_u32(codec->dev, "maxim,micbias", &micbias);
+       if (err) {
+               micbias = M98090_MBVSEL_2V8;
+               dev_info(codec->dev, "use default 2.8v micbias\n");
+       } else if (micbias < M98090_MBVSEL_2V2 || micbias > M98090_MBVSEL_2V8) {
+               dev_err(codec->dev, "micbias out of range 0x%x\n", micbias);
+               micbias = M98090_MBVSEL_2V8;
+       }
+
        snd_soc_update_bits(codec, M98090_REG_MIC_BIAS_VOLTAGE,
-               M98090_MBVSEL_MASK, M98090_MBVSEL_2V8);
+               M98090_MBVSEL_MASK, micbias);
 
        max98090_add_widgets(codec);
 
@@ -2696,7 +2704,7 @@ static const struct of_device_id max98090_of_match[] = {
 MODULE_DEVICE_TABLE(of, max98090_of_match);
 
 #ifdef CONFIG_ACPI
-static struct acpi_device_id max98090_acpi_match[] = {
+static const struct acpi_device_id max98090_acpi_match[] = {
        { "193C9890", MAX98090 },
        { }
 };
index 8fba0c3db79827c97135928b4ed537bdec88bbaf..9a46d3dcf7035d781d132c453dcddafc92e15047 100644 (file)
@@ -1650,16 +1650,17 @@ static int max98095_set_bias_level(struct snd_soc_codec *codec,
                 * away from ON. Disable the clock in that case, otherwise
                 * enable it.
                 */
-               if (!IS_ERR(max98095->mclk)) {
-                       if (codec->dapm.bias_level == SND_SOC_BIAS_ON)
-                               clk_disable_unprepare(max98095->mclk);
-                       else
-                               clk_prepare_enable(max98095->mclk);
-               }
+               if (IS_ERR(max98095->mclk))
+                       break;
+
+               if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_ON)
+                       clk_disable_unprepare(max98095->mclk);
+               else
+                       clk_prepare_enable(max98095->mclk);
                break;
 
        case SND_SOC_BIAS_STANDBY:
-               if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) {
+               if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_OFF) {
                        ret = regcache_sync(max98095->regmap);
 
                        if (ret != 0) {
@@ -1678,7 +1679,6 @@ static int max98095_set_bias_level(struct snd_soc_codec *codec,
                regcache_mark_dirty(max98095->regmap);
                break;
        }
-       codec->dapm.bias_level = level;
        return 0;
 }
 
@@ -2198,7 +2198,7 @@ static int max98095_suspend(struct snd_soc_codec *codec)
        if (max98095->headphone_jack || max98095->mic_jack)
                max98095_jack_detect_disable(codec);
 
-       max98095_set_bias_level(codec, SND_SOC_BIAS_OFF);
+       snd_soc_codec_force_bias_level(codec, SND_SOC_BIAS_OFF);
 
        return 0;
 }
@@ -2208,7 +2208,7 @@ static int max98095_resume(struct snd_soc_codec *codec)
        struct max98095_priv *max98095 = snd_soc_codec_get_drvdata(codec);
        struct i2c_client *client = to_i2c_client(codec->dev);
 
-       max98095_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
+       snd_soc_codec_force_bias_level(codec, SND_SOC_BIAS_STANDBY);
 
        if (max98095->headphone_jack || max98095->mic_jack) {
                max98095_jack_detect_enable(codec);
@@ -2301,8 +2301,8 @@ static int max98095_probe(struct snd_soc_codec *codec)
                /* register an audio interrupt */
                ret = request_threaded_irq(client->irq, NULL,
                        max98095_report_jack,
-                       IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING,
-                       "max98095", codec);
+                       IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING |
+                       IRQF_ONESHOT, "max98095", codec);
                if (ret) {
                        dev_err(codec->dev, "Failed to request IRQ: %d\n", ret);
                        goto err_access;
index bf3e933ee895752352e90f610195f39fc6cc058f..3a2fda08a893c865023d61fec636e65e3c977577 100644 (file)
@@ -60,13 +60,12 @@ static int max98357a_codec_probe(struct snd_soc_codec *codec)
 {
        struct gpio_desc *sdmode;
 
-       sdmode = devm_gpiod_get(codec->dev, "sdmode");
+       sdmode = devm_gpiod_get(codec->dev, "sdmode", GPIOD_OUT_LOW);
        if (IS_ERR(sdmode)) {
                dev_err(codec->dev, "%s() unable to get sdmode GPIO: %ld\n",
                                __func__, PTR_ERR(sdmode));
                return PTR_ERR(sdmode);
        }
-       gpiod_direction_output(sdmode, 0);
        snd_soc_codec_set_drvdata(codec, sdmode);
 
        return 0;
index 10f8e47ce2c28604a1d8cfdbe87b871d1e029290..481d58f1cb3f6b543b5e0fa320dd39103c992bd8 100644 (file)
@@ -252,7 +252,7 @@ static int max9850_set_bias_level(struct snd_soc_codec *codec,
        case SND_SOC_BIAS_PREPARE:
                break;
        case SND_SOC_BIAS_STANDBY:
-               if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) {
+               if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_OFF) {
                        ret = regcache_sync(max9850->regmap);
                        if (ret) {
                                dev_err(codec->dev,
@@ -264,7 +264,6 @@ static int max9850_set_bias_level(struct snd_soc_codec *codec,
        case SND_SOC_BIAS_OFF:
                break;
        }
-       codec->dapm.bias_level = level;
        return 0;
 }
 
index 9b5a17de46909172057e4f6cc1d3d4afa579adbc..aad664225dc3a4d0142a89bf37a51f4743a0969e 100644 (file)
@@ -346,7 +346,7 @@ static int max98925_dai_set_fmt(struct snd_soc_dai *codec_dai,
        }
 
        regmap_update_bits(max98925->regmap, MAX98925_FORMAT,
-                       M98925_DAI_BCI_MASK, invert);
+                       M98925_DAI_BCI_MASK | M98925_DAI_WCI_MASK, invert);
        return 0;
 }
 
index 2ffb9a0570dc8db3625cc8224f034995ea88d7dd..3d44fc50e4d0c112d35627d01491e2f07674c459 100644 (file)
@@ -623,14 +623,14 @@ static int mc13783_probe(struct snd_soc_codec *codec)
                                AUDIO_SSI_SEL, 0);
        else
                mc13xxx_reg_rmw(priv->mc13xxx, MC13783_AUDIO_CODEC,
-                               0, AUDIO_SSI_SEL);
+                               AUDIO_SSI_SEL, AUDIO_SSI_SEL);
 
        if (priv->dac_ssi_port == MC13783_SSI1_PORT)
                mc13xxx_reg_rmw(priv->mc13xxx, MC13783_AUDIO_DAC,
                                AUDIO_SSI_SEL, 0);
        else
                mc13xxx_reg_rmw(priv->mc13xxx, MC13783_AUDIO_DAC,
-                               0, AUDIO_SSI_SEL);
+                               AUDIO_SSI_SEL, AUDIO_SSI_SEL);
 
        return 0;
 }
index 711f55039522f473a5070cb1454a03132423f5d6..b74118e019fbe142572644b79085a76496c685fb 100644 (file)
@@ -341,6 +341,7 @@ static int ml26124_hw_params(struct snd_pcm_substream *substream,
        struct snd_soc_codec *codec = dai->codec;
        struct ml26124_priv *priv = snd_soc_codec_get_drvdata(codec);
        int i = get_coeff(priv->mclk, params_rate(hw_params));
+       int srate;
 
        if (i < 0)
                return i;
@@ -370,53 +371,16 @@ static int ml26124_hw_params(struct snd_pcm_substream *substream,
                                    BIT(0) | BIT(1), 0);
        }
 
-       switch (params_rate(hw_params)) {
-       case 16000:
-               snd_soc_update_bits(codec, ML26124_SMPLING_RATE, 0xf,
-                                   get_srate(params_rate(hw_params)));
-               snd_soc_update_bits(codec, ML26124_PLLNL, 0xff,
-                                   coeff_div[i].pllnl);
-               snd_soc_update_bits(codec, ML26124_PLLNH, 0x1,
-                                   coeff_div[i].pllnh);
-               snd_soc_update_bits(codec, ML26124_PLLML, 0xff,
-                                   coeff_div[i].pllml);
-               snd_soc_update_bits(codec, ML26124_PLLMH, 0x3f,
-                                   coeff_div[i].pllmh);
-               snd_soc_update_bits(codec, ML26124_PLLDIV, 0x1f,
-                                   coeff_div[i].plldiv);
-               break;
-       case 32000:
-               snd_soc_update_bits(codec, ML26124_SMPLING_RATE, 0xf,
-                                   get_srate(params_rate(hw_params)));
-               snd_soc_update_bits(codec, ML26124_PLLNL, 0xff,
-                                   coeff_div[i].pllnl);
-               snd_soc_update_bits(codec, ML26124_PLLNH, 0x1,
-                                   coeff_div[i].pllnh);
-               snd_soc_update_bits(codec, ML26124_PLLML, 0xff,
-                                   coeff_div[i].pllml);
-               snd_soc_update_bits(codec, ML26124_PLLMH, 0x3f,
-                                   coeff_div[i].pllmh);
-               snd_soc_update_bits(codec, ML26124_PLLDIV, 0x1f,
-                                   coeff_div[i].plldiv);
-               break;
-       case 48000:
-               snd_soc_update_bits(codec, ML26124_SMPLING_RATE, 0xf,
-                                   get_srate(params_rate(hw_params)));
-               snd_soc_update_bits(codec, ML26124_PLLNL, 0xff,
-                                   coeff_div[i].pllnl);
-               snd_soc_update_bits(codec, ML26124_PLLNH, 0x1,
-                                   coeff_div[i].pllnh);
-               snd_soc_update_bits(codec, ML26124_PLLML, 0xff,
-                                   coeff_div[i].pllml);
-               snd_soc_update_bits(codec, ML26124_PLLMH, 0x3f,
-                                   coeff_div[i].pllmh);
-               snd_soc_update_bits(codec, ML26124_PLLDIV, 0x1f,
-                                   coeff_div[i].plldiv);
-               break;
-       default:
-               pr_err("%s:this rate is no support for ml26124\n", __func__);
-               return -EINVAL;
-       }
+       srate = get_srate(params_rate(hw_params));
+       if (srate < 0)
+               return srate;
+
+       snd_soc_update_bits(codec, ML26124_SMPLING_RATE, 0xf, srate);
+       snd_soc_update_bits(codec, ML26124_PLLNL, 0xff, coeff_div[i].pllnl);
+       snd_soc_update_bits(codec, ML26124_PLLNH, 0x1, coeff_div[i].pllnh);
+       snd_soc_update_bits(codec, ML26124_PLLML, 0xff, coeff_div[i].pllml);
+       snd_soc_update_bits(codec, ML26124_PLLMH, 0x3f, coeff_div[i].pllmh);
+       snd_soc_update_bits(codec, ML26124_PLLDIV, 0x1f, coeff_div[i].plldiv);
 
        return 0;
 }
@@ -523,7 +487,7 @@ static int ml26124_set_bias_level(struct snd_soc_codec *codec,
                break;
        case SND_SOC_BIAS_STANDBY:
                /* VMID ON */
-               if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) {
+               if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_OFF) {
                        snd_soc_update_bits(codec, ML26124_PW_REF_PW_MNG,
                                            ML26124_VMID, ML26124_VMID);
                        msleep(500);
@@ -536,7 +500,6 @@ static int ml26124_set_bias_level(struct snd_soc_codec *codec,
                                    ML26124_VMID, 0);
                break;
        }
-       codec->dapm.bias_level = level;
        return 0;
 }
 
index e12764d15431be69046bd4db72b5a822986255df..de16429f0a43114ef9c96cdf3932f3abd32c1d5f 100644 (file)
@@ -242,7 +242,7 @@ static int pcm512x_overclock_pll_put(struct snd_kcontrol *kcontrol,
        struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
        struct pcm512x_priv *pcm512x = snd_soc_codec_get_drvdata(codec);
 
-       switch (codec->dapm.bias_level) {
+       switch (snd_soc_codec_get_bias_level(codec)) {
        case SND_SOC_BIAS_OFF:
        case SND_SOC_BIAS_STANDBY:
                break;
@@ -270,7 +270,7 @@ static int pcm512x_overclock_dsp_put(struct snd_kcontrol *kcontrol,
        struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
        struct pcm512x_priv *pcm512x = snd_soc_codec_get_drvdata(codec);
 
-       switch (codec->dapm.bias_level) {
+       switch (snd_soc_codec_get_bias_level(codec)) {
        case SND_SOC_BIAS_OFF:
        case SND_SOC_BIAS_STANDBY:
                break;
@@ -298,7 +298,7 @@ static int pcm512x_overclock_dac_put(struct snd_kcontrol *kcontrol,
        struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
        struct pcm512x_priv *pcm512x = snd_soc_codec_get_drvdata(codec);
 
-       switch (codec->dapm.bias_level) {
+       switch (snd_soc_codec_get_bias_level(codec)) {
        case SND_SOC_BIAS_OFF:
        case SND_SOC_BIAS_STANDBY:
                break;
@@ -641,8 +641,6 @@ static int pcm512x_set_bias_level(struct snd_soc_codec *codec,
                break;
        }
 
-       codec->dapm.bias_level = level;
-
        return 0;
 }
 
diff --git a/sound/soc/codecs/rl6347a.c b/sound/soc/codecs/rl6347a.c
new file mode 100644 (file)
index 0000000..91d5166
--- /dev/null
@@ -0,0 +1,128 @@
+/*
+ * rl6347a.c - RL6347A class device shared support
+ *
+ * Copyright 2015 Realtek Semiconductor Corp.
+ *
+ * Author: Oder Chiou <oder_chiou@realtek.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/pm.h>
+#include <linux/i2c.h>
+#include <linux/platform_device.h>
+#include <linux/spi/spi.h>
+#include <linux/dmi.h>
+#include <linux/acpi.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include <sound/initval.h>
+#include <sound/tlv.h>
+#include <sound/jack.h>
+#include <linux/workqueue.h>
+#include <sound/hda_verbs.h>
+
+#include "rl6347a.h"
+
+int rl6347a_hw_write(void *context, unsigned int reg, unsigned int value)
+{
+       struct i2c_client *client = context;
+       struct rl6347a_priv *rl6347a = i2c_get_clientdata(client);
+       u8 data[4];
+       int ret, i;
+
+       /* handle index registers */
+       if (reg <= 0xff) {
+               rl6347a_hw_write(client, RL6347A_COEF_INDEX, reg);
+               for (i = 0; i < rl6347a->index_cache_size; i++) {
+                       if (reg == rl6347a->index_cache[i].reg) {
+                               rl6347a->index_cache[i].def = value;
+                               break;
+                       }
+
+               }
+               reg = RL6347A_PROC_COEF;
+       }
+
+       data[0] = (reg >> 24) & 0xff;
+       data[1] = (reg >> 16) & 0xff;
+       /*
+        * 4 bit VID: reg should be 0
+        * 12 bit VID: value should be 0
+        * So we use an OR operator to handle it rather than use if condition.
+        */
+       data[2] = ((reg >> 8) & 0xff) | ((value >> 8) & 0xff);
+       data[3] = value & 0xff;
+
+       ret = i2c_master_send(client, data, 4);
+
+       if (ret == 4)
+               return 0;
+       else
+               pr_err("ret=%d\n", ret);
+       if (ret < 0)
+               return ret;
+       else
+               return -EIO;
+}
+EXPORT_SYMBOL_GPL(rl6347a_hw_write);
+
+int rl6347a_hw_read(void *context, unsigned int reg, unsigned int *value)
+{
+       struct i2c_client *client = context;
+       struct i2c_msg xfer[2];
+       int ret;
+       __be32 be_reg;
+       unsigned int index, vid, buf = 0x0;
+
+       /* handle index registers */
+       if (reg <= 0xff) {
+               rl6347a_hw_write(client, RL6347A_COEF_INDEX, reg);
+               reg = RL6347A_PROC_COEF;
+       }
+
+       reg = reg | 0x80000;
+       vid = (reg >> 8) & 0xfff;
+
+       if (AC_VERB_GET_AMP_GAIN_MUTE == (vid & 0xf00)) {
+               index = (reg >> 8) & 0xf;
+               reg = (reg & ~0xf0f) | index;
+       }
+       be_reg = cpu_to_be32(reg);
+
+       /* Write register */
+       xfer[0].addr = client->addr;
+       xfer[0].flags = 0;
+       xfer[0].len = 4;
+       xfer[0].buf = (u8 *)&be_reg;
+
+       /* Read data */
+       xfer[1].addr = client->addr;
+       xfer[1].flags = I2C_M_RD;
+       xfer[1].len = 4;
+       xfer[1].buf = (u8 *)&buf;
+
+       ret = i2c_transfer(client->adapter, xfer, 2);
+       if (ret < 0)
+               return ret;
+       else if (ret != 2)
+               return -EIO;
+
+       *value = be32_to_cpu(buf);
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(rl6347a_hw_read);
+
+MODULE_DESCRIPTION("RL6347A class device shared support");
+MODULE_AUTHOR("Oder Chiou <oder_chiou@realtek.com>");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/codecs/rl6347a.h b/sound/soc/codecs/rl6347a.h
new file mode 100644 (file)
index 0000000..1cb56e5
--- /dev/null
@@ -0,0 +1,32 @@
+/*
+ * rl6347a.h - RL6347A class device shared support
+ *
+ * Copyright 2015 Realtek Semiconductor Corp.
+ *
+ * Author: Oder Chiou <oder_chiou@realtek.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+#ifndef __RL6347A_H__
+#define __RL6347A_H__
+
+#define VERB_CMD(V, N, D) ((N << 20) | (V << 8) | D)
+
+#define RL6347A_VENDOR_REGISTERS       0x20
+
+#define RL6347A_COEF_INDEX\
+       VERB_CMD(AC_VERB_SET_COEF_INDEX, RL6347A_VENDOR_REGISTERS, 0)
+#define RL6347A_PROC_COEF\
+       VERB_CMD(AC_VERB_SET_PROC_COEF, RL6347A_VENDOR_REGISTERS, 0)
+
+struct rl6347a_priv {
+       struct reg_default *index_cache;
+       int index_cache_size;
+};
+
+int rl6347a_hw_write(void *context, unsigned int reg, unsigned int value);
+int rl6347a_hw_read(void *context, unsigned int reg, unsigned int *value);
+
+#endif /* __RL6347A_H__ */
index 0fcda35a3a93694fa5352d06144e934ee99b7583..5c43e263b2c1f4a8f97bab4abe9fb64f0ee68070 100644 (file)
 #include <sound/rt286.h>
 #include <sound/hda_verbs.h>
 
+#include "rl6347a.h"
 #include "rt286.h"
 
 #define RT286_VENDOR_ID 0x10ec0286
 #define RT288_VENDOR_ID 0x10ec0288
 
 struct rt286_priv {
+       struct reg_default *index_cache;
+       int index_cache_size;
        struct regmap *regmap;
        struct snd_soc_codec *codec;
        struct rt286_platform_data pdata;
@@ -45,7 +48,6 @@ struct rt286_priv {
        struct delayed_work jack_detect_work;
        int sys_clk;
        int clk_id;
-       struct reg_default *index_cache;
 };
 
 static struct reg_default rt286_index_def[] = {
@@ -185,94 +187,6 @@ static bool rt286_readable_register(struct device *dev, unsigned int reg)
        }
 }
 
-static int rt286_hw_write(void *context, unsigned int reg, unsigned int value)
-{
-       struct i2c_client *client = context;
-       struct rt286_priv *rt286 = i2c_get_clientdata(client);
-       u8 data[4];
-       int ret, i;
-
-       /* handle index registers */
-       if (reg <= 0xff) {
-               rt286_hw_write(client, RT286_COEF_INDEX, reg);
-               for (i = 0; i < INDEX_CACHE_SIZE; i++) {
-                       if (reg == rt286->index_cache[i].reg) {
-                               rt286->index_cache[i].def = value;
-                               break;
-                       }
-
-               }
-               reg = RT286_PROC_COEF;
-       }
-
-       data[0] = (reg >> 24) & 0xff;
-       data[1] = (reg >> 16) & 0xff;
-       /*
-        * 4 bit VID: reg should be 0
-        * 12 bit VID: value should be 0
-        * So we use an OR operator to handle it rather than use if condition.
-        */
-       data[2] = ((reg >> 8) & 0xff) | ((value >> 8) & 0xff);
-       data[3] = value & 0xff;
-
-       ret = i2c_master_send(client, data, 4);
-
-       if (ret == 4)
-               return 0;
-       else
-               pr_err("ret=%d\n", ret);
-       if (ret < 0)
-               return ret;
-       else
-               return -EIO;
-}
-
-static int rt286_hw_read(void *context, unsigned int reg, unsigned int *value)
-{
-       struct i2c_client *client = context;
-       struct i2c_msg xfer[2];
-       int ret;
-       __be32 be_reg;
-       unsigned int index, vid, buf = 0x0;
-
-       /* handle index registers */
-       if (reg <= 0xff) {
-               rt286_hw_write(client, RT286_COEF_INDEX, reg);
-               reg = RT286_PROC_COEF;
-       }
-
-       reg = reg | 0x80000;
-       vid = (reg >> 8) & 0xfff;
-
-       if (AC_VERB_GET_AMP_GAIN_MUTE == (vid & 0xf00)) {
-               index = (reg >> 8) & 0xf;
-               reg = (reg & ~0xf0f) | index;
-       }
-       be_reg = cpu_to_be32(reg);
-
-       /* Write register */
-       xfer[0].addr = client->addr;
-       xfer[0].flags = 0;
-       xfer[0].len = 4;
-       xfer[0].buf = (u8 *)&be_reg;
-
-       /* Read data */
-       xfer[1].addr = client->addr;
-       xfer[1].flags = I2C_M_RD;
-       xfer[1].len = 4;
-       xfer[1].buf = (u8 *)&buf;
-
-       ret = i2c_transfer(client->adapter, xfer, 2);
-       if (ret < 0)
-               return ret;
-       else if (ret != 2)
-               return -EIO;
-
-       *value = be32_to_cpu(buf);
-
-       return 0;
-}
-
 #ifdef CONFIG_PM
 static void rt286_index_sync(struct snd_soc_codec *codec)
 {
@@ -301,6 +215,7 @@ static int rt286_support_power_controls[] = {
 
 static int rt286_jack_detect(struct rt286_priv *rt286, bool *hp, bool *mic)
 {
+       struct snd_soc_dapm_context *dapm;
        unsigned int val, buf;
 
        *hp = false;
@@ -308,6 +223,9 @@ static int rt286_jack_detect(struct rt286_priv *rt286, bool *hp, bool *mic)
 
        if (!rt286->codec)
                return -EINVAL;
+
+       dapm = snd_soc_codec_get_dapm(rt286->codec);
+
        if (rt286->pdata.cbj_en) {
                regmap_read(rt286->regmap, RT286_GET_HP_SENSE, &buf);
                *hp = buf & 0x80000000;
@@ -316,14 +234,11 @@ static int rt286_jack_detect(struct rt286_priv *rt286, bool *hp, bool *mic)
                        regmap_update_bits(rt286->regmap,
                                RT286_DC_GAIN, 0x200, 0x200);
 
-                       snd_soc_dapm_force_enable_pin(&rt286->codec->dapm,
-                                                       "HV");
-                       snd_soc_dapm_force_enable_pin(&rt286->codec->dapm,
-                                                       "VREF");
+                       snd_soc_dapm_force_enable_pin(dapm, "HV");
+                       snd_soc_dapm_force_enable_pin(dapm, "VREF");
                        /* power LDO1 */
-                       snd_soc_dapm_force_enable_pin(&rt286->codec->dapm,
-                                                       "LDO1");
-                       snd_soc_dapm_sync(&rt286->codec->dapm);
+                       snd_soc_dapm_force_enable_pin(dapm, "LDO1");
+                       snd_soc_dapm_sync(dapm);
 
                        regmap_write(rt286->regmap, RT286_SET_MIC1, 0x24);
                        msleep(50);
@@ -360,11 +275,11 @@ static int rt286_jack_detect(struct rt286_priv *rt286, bool *hp, bool *mic)
                *mic = buf & 0x80000000;
        }
 
-       snd_soc_dapm_disable_pin(&rt286->codec->dapm, "HV");
-       snd_soc_dapm_disable_pin(&rt286->codec->dapm, "VREF");
+       snd_soc_dapm_disable_pin(dapm, "HV");
+       snd_soc_dapm_disable_pin(dapm, "VREF");
        if (!*hp)
-               snd_soc_dapm_disable_pin(&rt286->codec->dapm, "LDO1");
-       snd_soc_dapm_sync(&rt286->codec->dapm);
+               snd_soc_dapm_disable_pin(dapm, "LDO1");
+       snd_soc_dapm_sync(dapm);
 
        return 0;
 }
@@ -391,6 +306,7 @@ static void rt286_jack_detect_work(struct work_struct *work)
 
 int rt286_mic_detect(struct snd_soc_codec *codec, struct snd_soc_jack *jack)
 {
+       struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
        struct rt286_priv *rt286 = snd_soc_codec_get_drvdata(codec);
 
        rt286->jack = jack;
@@ -398,7 +314,7 @@ int rt286_mic_detect(struct snd_soc_codec *codec, struct snd_soc_jack *jack)
        if (jack) {
                /* enable IRQ */
                if (rt286->jack->status & SND_JACK_HEADPHONE)
-                       snd_soc_dapm_force_enable_pin(&codec->dapm, "LDO1");
+                       snd_soc_dapm_force_enable_pin(dapm, "LDO1");
                regmap_update_bits(rt286->regmap, RT286_IRQ_CTRL, 0x2, 0x2);
                /* Send an initial empty report */
                snd_soc_jack_report(rt286->jack, rt286->jack->status,
@@ -406,9 +322,9 @@ int rt286_mic_detect(struct snd_soc_codec *codec, struct snd_soc_jack *jack)
        } else {
                /* disable IRQ */
                regmap_update_bits(rt286->regmap, RT286_IRQ_CTRL, 0x2, 0x0);
-               snd_soc_dapm_disable_pin(&codec->dapm, "LDO1");
+               snd_soc_dapm_disable_pin(dapm, "LDO1");
        }
-       snd_soc_dapm_sync(&codec->dapm);
+       snd_soc_dapm_sync(dapm);
 
        return 0;
 }
@@ -985,7 +901,7 @@ static int rt286_set_bias_level(struct snd_soc_codec *codec,
 {
        switch (level) {
        case SND_SOC_BIAS_PREPARE:
-               if (SND_SOC_BIAS_STANDBY == codec->dapm.bias_level) {
+               if (SND_SOC_BIAS_STANDBY == snd_soc_codec_get_bias_level(codec)) {
                        snd_soc_write(codec,
                                RT286_SET_AUDIO_POWER, AC_PWRST_D0);
                        snd_soc_update_bits(codec,
@@ -1012,7 +928,6 @@ static int rt286_set_bias_level(struct snd_soc_codec *codec,
        default:
                break;
        }
-       codec->dapm.bias_level = level;
 
        return 0;
 }
@@ -1173,8 +1088,8 @@ static const struct regmap_config rt286_regmap = {
        .max_register = 0x02370100,
        .volatile_reg = rt286_volatile_register,
        .readable_reg = rt286_readable_register,
-       .reg_write = rt286_hw_write,
-       .reg_read = rt286_hw_read,
+       .reg_write = rl6347a_hw_write,
+       .reg_read = rl6347a_hw_read,
        .cache_type = REGCACHE_RBTREE,
        .reg_defaults = rt286_reg,
        .num_reg_defaults = ARRAY_SIZE(rt286_reg),
@@ -1247,6 +1162,7 @@ static int rt286_i2c_probe(struct i2c_client *i2c,
        }
 
        rt286->index_cache = rt286_index_def;
+       rt286->index_cache_size = INDEX_CACHE_SIZE;
        rt286->i2c = i2c;
        i2c_set_clientdata(i2c, rt286);
 
index 2c10d77727af5d0c848a64fae5202a183dcd3f69..058167c80d714ba486e1dd330e472eb871785c43 100644 (file)
@@ -1546,7 +1546,7 @@ static int rt5631_set_bias_level(struct snd_soc_codec *codec,
                break;
 
        case SND_SOC_BIAS_STANDBY:
-               if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) {
+               if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_OFF) {
                        snd_soc_update_bits(codec, RT5631_PWR_MANAG_ADD3,
                                RT5631_PWR_VREF | RT5631_PWR_MAIN_BIAS,
                                RT5631_PWR_VREF | RT5631_PWR_MAIN_BIAS);
@@ -1569,7 +1569,6 @@ static int rt5631_set_bias_level(struct snd_soc_codec *codec,
        default:
                break;
        }
-       codec->dapm.bias_level = level;
 
        return 0;
 }
@@ -1615,7 +1614,7 @@ static int rt5631_probe(struct snd_soc_codec *codec)
                        RT5631_DMIC_R_CH_LATCH_RISING);
        }
 
-       codec->dapm.bias_level = SND_SOC_BIAS_STANDBY;
+       snd_soc_codec_init_bias_level(codec, SND_SOC_BIAS_STANDBY);
 
        return 0;
 }
index 178e55d4d48146b9bfee3a211bd297f67a822790..9bc78e57513d74e40c5a4f9bda59c34625b15715 100644 (file)
@@ -51,7 +51,7 @@ static const struct regmap_range_cfg rt5640_ranges[] = {
          .window_len = 0x1, },
 };
 
-static struct reg_default init_list[] = {
+static const struct reg_default init_list[] = {
        {RT5640_PR_BASE + 0x3d, 0x3600},
        {RT5640_PR_BASE + 0x12, 0x0aa8},
        {RT5640_PR_BASE + 0x14, 0x0aaa},
@@ -59,7 +59,6 @@ static struct reg_default init_list[] = {
        {RT5640_PR_BASE + 0x21, 0xe0e0},
        {RT5640_PR_BASE + 0x23, 0x1804},
 };
-#define RT5640_INIT_REG_LEN ARRAY_SIZE(init_list)
 
 static const struct reg_default rt5640_reg[] = {
        { 0x00, 0x000e },
@@ -1870,7 +1869,7 @@ static int rt5640_set_bias_level(struct snd_soc_codec *codec,
 {
        switch (level) {
        case SND_SOC_BIAS_STANDBY:
-               if (SND_SOC_BIAS_OFF == codec->dapm.bias_level) {
+               if (SND_SOC_BIAS_OFF == snd_soc_codec_get_bias_level(codec)) {
                        snd_soc_update_bits(codec, RT5640_PWR_ANLG1,
                                RT5640_PWR_VREF1 | RT5640_PWR_MB |
                                RT5640_PWR_BG | RT5640_PWR_VREF2,
@@ -1902,7 +1901,6 @@ static int rt5640_set_bias_level(struct snd_soc_codec *codec,
        default:
                break;
        }
-       codec->dapm.bias_level = level;
 
        return 0;
 }
@@ -1935,11 +1933,12 @@ EXPORT_SYMBOL_GPL(rt5640_dmic_enable);
 
 static int rt5640_probe(struct snd_soc_codec *codec)
 {
+       struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
        struct rt5640_priv *rt5640 = snd_soc_codec_get_drvdata(codec);
 
        rt5640->codec = codec;
 
-       rt5640_set_bias_level(codec, SND_SOC_BIAS_OFF);
+       snd_soc_codec_force_bias_level(codec, SND_SOC_BIAS_OFF);
 
        snd_soc_update_bits(codec, RT5640_DUMMY1, 0x0301, 0x0301);
        snd_soc_update_bits(codec, RT5640_MICBIAS, 0x0030, 0x0030);
@@ -1951,18 +1950,18 @@ static int rt5640_probe(struct snd_soc_codec *codec)
                snd_soc_add_codec_controls(codec,
                        rt5640_specific_snd_controls,
                        ARRAY_SIZE(rt5640_specific_snd_controls));
-               snd_soc_dapm_new_controls(&codec->dapm,
+               snd_soc_dapm_new_controls(dapm,
                        rt5640_specific_dapm_widgets,
                        ARRAY_SIZE(rt5640_specific_dapm_widgets));
-               snd_soc_dapm_add_routes(&codec->dapm,
+               snd_soc_dapm_add_routes(dapm,
                        rt5640_specific_dapm_routes,
                        ARRAY_SIZE(rt5640_specific_dapm_routes));
                break;
        case RT5640_ID_5639:
-               snd_soc_dapm_new_controls(&codec->dapm,
+               snd_soc_dapm_new_controls(dapm,
                        rt5639_specific_dapm_widgets,
                        ARRAY_SIZE(rt5639_specific_dapm_widgets));
-               snd_soc_dapm_add_routes(&codec->dapm,
+               snd_soc_dapm_add_routes(dapm,
                        rt5639_specific_dapm_routes,
                        ARRAY_SIZE(rt5639_specific_dapm_routes));
                break;
@@ -1991,7 +1990,7 @@ static int rt5640_suspend(struct snd_soc_codec *codec)
 {
        struct rt5640_priv *rt5640 = snd_soc_codec_get_drvdata(codec);
 
-       rt5640_set_bias_level(codec, SND_SOC_BIAS_OFF);
+       snd_soc_codec_force_bias_level(codec, SND_SOC_BIAS_OFF);
        rt5640_reset(codec);
        regcache_cache_only(rt5640->regmap, true);
        regcache_mark_dirty(rt5640->regmap);
@@ -2122,7 +2121,7 @@ MODULE_DEVICE_TABLE(of, rt5640_of_match);
 #endif
 
 #ifdef CONFIG_ACPI
-static struct acpi_device_id rt5640_acpi_match[] = {
+static const struct acpi_device_id rt5640_acpi_match[] = {
        { "INT33CA", 0 },
        { "10EC5640", 0 },
        { "10EC5642", 0 },
index 69528ae5410c991125c2e16f3810d51ae7026b88..9ce311e088fc514bf8cde70dd120a3074f78bfe5 100644 (file)
@@ -18,6 +18,9 @@
 #include <linux/platform_device.h>
 #include <linux/spi/spi.h>
 #include <linux/gpio.h>
+#include <linux/gpio/consumer.h>
+#include <linux/acpi.h>
+#include <linux/dmi.h>
 #include <sound/core.h>
 #include <sound/pcm.h>
 #include <sound/pcm_params.h>
@@ -346,6 +349,7 @@ static bool rt5645_readable_register(struct device *dev, unsigned int reg)
        case RT5645_TDM_CTRL_1:
        case RT5645_TDM_CTRL_2:
        case RT5645_TDM_CTRL_3:
+       case RT5650_TDM_CTRL_4:
        case RT5645_GLB_CLK:
        case RT5645_PLL_CTRL1:
        case RT5645_PLL_CTRL2:
@@ -414,9 +418,9 @@ static bool rt5645_readable_register(struct device *dev, unsigned int reg)
 }
 
 static const DECLARE_TLV_DB_SCALE(out_vol_tlv, -4650, 150, 0);
-static const DECLARE_TLV_DB_SCALE(dac_vol_tlv, -65625, 375, 0);
+static const DECLARE_TLV_DB_SCALE(dac_vol_tlv, -6525, 75, 0);
 static const DECLARE_TLV_DB_SCALE(in_vol_tlv, -3450, 150, 0);
-static const DECLARE_TLV_DB_SCALE(adc_vol_tlv, -17625, 375, 0);
+static const DECLARE_TLV_DB_SCALE(adc_vol_tlv, -1725, 75, 0);
 static const DECLARE_TLV_DB_SCALE(adc_bst_tlv, 0, 1200, 0);
 
 /* {0, +20, +24, +30, +35, +40, +44, +50, +52} dB */
@@ -431,30 +435,6 @@ static unsigned int bst_tlv[] = {
        8, 8, TLV_DB_SCALE_ITEM(5200, 0, 0),
 };
 
-static const char * const rt5645_tdm_data_swap_select[] = {
-       "L/R", "R/L", "L/L", "R/R"
-};
-
-static SOC_ENUM_SINGLE_DECL(rt5645_tdm_adc_slot0_1_enum,
-       RT5645_TDM_CTRL_1, 6, rt5645_tdm_data_swap_select);
-
-static SOC_ENUM_SINGLE_DECL(rt5645_tdm_adc_slot2_3_enum,
-       RT5645_TDM_CTRL_1, 4, rt5645_tdm_data_swap_select);
-
-static SOC_ENUM_SINGLE_DECL(rt5645_tdm_adc_slot4_5_enum,
-       RT5645_TDM_CTRL_1, 2, rt5645_tdm_data_swap_select);
-
-static SOC_ENUM_SINGLE_DECL(rt5645_tdm_adc_slot6_7_enum,
-       RT5645_TDM_CTRL_1, 0, rt5645_tdm_data_swap_select);
-
-static const char * const rt5645_tdm_adc_data_select[] = {
-       "1/2/R", "2/1/R", "R/1/2", "R/2/1"
-};
-
-static SOC_ENUM_SINGLE_DECL(rt5645_tdm_adc_sel_enum,
-                               RT5645_TDM_CTRL_1, 8,
-                               rt5645_tdm_adc_data_select);
-
 static const struct snd_kcontrol_new rt5645_snd_controls[] = {
        /* Speaker Output Volume */
        SOC_DOUBLE("Speaker Channel Switch", RT5645_SPK_VOL,
@@ -463,9 +443,9 @@ static const struct snd_kcontrol_new rt5645_snd_controls[] = {
                RT5645_L_VOL_SFT, RT5645_R_VOL_SFT, 39, 1, out_vol_tlv),
 
        /* Headphone Output Volume */
-       SOC_DOUBLE("HP Channel Switch", RT5645_HP_VOL,
+       SOC_DOUBLE("Headphone Channel Switch", RT5645_HP_VOL,
                RT5645_VOL_L_SFT, RT5645_VOL_R_SFT, 1, 1),
-       SOC_DOUBLE_TLV("HP Playback Volume", RT5645_HP_VOL,
+       SOC_DOUBLE_TLV("Headphone Playback Volume", RT5645_HP_VOL,
                RT5645_L_VOL_SFT, RT5645_R_VOL_SFT, 39, 1, out_vol_tlv),
 
        /* OUTPUT Control */
@@ -480,9 +460,9 @@ static const struct snd_kcontrol_new rt5645_snd_controls[] = {
        SOC_DOUBLE("DAC2 Playback Switch", RT5645_DAC_CTRL,
                RT5645_M_DAC_L2_VOL_SFT, RT5645_M_DAC_R2_VOL_SFT, 1, 1),
        SOC_DOUBLE_TLV("DAC1 Playback Volume", RT5645_DAC1_DIG_VOL,
-               RT5645_L_VOL_SFT, RT5645_R_VOL_SFT, 175, 0, dac_vol_tlv),
+               RT5645_L_VOL_SFT + 1, RT5645_R_VOL_SFT + 1, 87, 0, dac_vol_tlv),
        SOC_DOUBLE_TLV("Mono DAC Playback Volume", RT5645_DAC2_DIG_VOL,
-               RT5645_L_VOL_SFT, RT5645_R_VOL_SFT, 175, 0, dac_vol_tlv),
+               RT5645_L_VOL_SFT + 1, RT5645_R_VOL_SFT + 1, 87, 0, dac_vol_tlv),
 
        /* IN1/IN2 Control */
        SOC_SINGLE_TLV("IN1 Boost", RT5645_IN1_CTRL1,
@@ -498,11 +478,11 @@ static const struct snd_kcontrol_new rt5645_snd_controls[] = {
        SOC_DOUBLE("ADC Capture Switch", RT5645_STO1_ADC_DIG_VOL,
                RT5645_L_MUTE_SFT, RT5645_R_MUTE_SFT, 1, 1),
        SOC_DOUBLE_TLV("ADC Capture Volume", RT5645_STO1_ADC_DIG_VOL,
-               RT5645_L_VOL_SFT, RT5645_R_VOL_SFT, 127, 0, adc_vol_tlv),
+               RT5645_L_VOL_SFT + 1, RT5645_R_VOL_SFT + 1, 63, 0, adc_vol_tlv),
        SOC_DOUBLE("Mono ADC Capture Switch", RT5645_MONO_ADC_DIG_VOL,
                RT5645_L_MUTE_SFT, RT5645_R_MUTE_SFT, 1, 1),
        SOC_DOUBLE_TLV("Mono ADC Capture Volume", RT5645_MONO_ADC_DIG_VOL,
-               RT5645_L_VOL_SFT, RT5645_R_VOL_SFT, 127, 0, adc_vol_tlv),
+               RT5645_L_VOL_SFT + 1, RT5645_R_VOL_SFT + 1, 63, 0, adc_vol_tlv),
 
        /* ADC Boost Volume Control */
        SOC_DOUBLE_TLV("STO1 ADC Boost Gain", RT5645_ADC_BST_VOL1,
@@ -515,17 +495,6 @@ static const struct snd_kcontrol_new rt5645_snd_controls[] = {
        /* I2S2 function select */
        SOC_SINGLE("I2S2 Func Switch", RT5645_GPIO_CTRL1, RT5645_I2S2_SEL_SFT,
                1, 1),
-
-       /* TDM */
-       SOC_ENUM("TDM Adc Slot0 1 Data", rt5645_tdm_adc_slot0_1_enum),
-       SOC_ENUM("TDM Adc Slot2 3 Data", rt5645_tdm_adc_slot2_3_enum),
-       SOC_ENUM("TDM Adc Slot4 5 Data", rt5645_tdm_adc_slot4_5_enum),
-       SOC_ENUM("TDM Adc Slot6 7 Data", rt5645_tdm_adc_slot6_7_enum),
-       SOC_ENUM("TDM IF1 ADC DATA Sel", rt5645_tdm_adc_sel_enum),
-       SOC_SINGLE("TDM IF1_DAC1_L Sel", RT5645_TDM_CTRL_3, 12, 7, 0),
-       SOC_SINGLE("TDM IF1_DAC1_R Sel", RT5645_TDM_CTRL_3, 8, 7, 0),
-       SOC_SINGLE("TDM IF1_DAC2_L Sel", RT5645_TDM_CTRL_3, 4, 7, 0),
-       SOC_SINGLE("TDM IF1_DAC2_R Sel", RT5645_TDM_CTRL_3, 0, 7, 0),
 };
 
 /**
@@ -1092,7 +1061,8 @@ static const struct snd_kcontrol_new rt5645_mono_adc_r2_mux =
 
 /* MX-77 [9:8] */
 static const char * const rt5645_if1_adc_in_src[] = {
-       "IF_ADC1", "IF_ADC2", "VAD_ADC"
+       "IF_ADC1/IF_ADC2/VAD_ADC", "IF_ADC2/IF_ADC1/VAD_ADC",
+       "VAD_ADC/IF_ADC1/IF_ADC2", "VAD_ADC/IF_ADC2/IF_ADC1"
 };
 
 static SOC_ENUM_SINGLE_DECL(
@@ -1102,6 +1072,140 @@ static SOC_ENUM_SINGLE_DECL(
 static const struct snd_kcontrol_new rt5645_if1_adc_in_mux =
        SOC_DAPM_ENUM("IF1 ADC IN source", rt5645_if1_adc_in_enum);
 
+/* MX-78 [4:0] */
+static const char * const rt5650_if1_adc_in_src[] = {
+       "IF_ADC1/IF_ADC2/DAC_REF/Null",
+       "IF_ADC1/IF_ADC2/Null/DAC_REF",
+       "IF_ADC1/DAC_REF/IF_ADC2/Null",
+       "IF_ADC1/DAC_REF/Null/IF_ADC2",
+       "IF_ADC1/Null/DAC_REF/IF_ADC2",
+       "IF_ADC1/Null/IF_ADC2/DAC_REF",
+
+       "IF_ADC2/IF_ADC1/DAC_REF/Null",
+       "IF_ADC2/IF_ADC1/Null/DAC_REF",
+       "IF_ADC2/DAC_REF/IF_ADC1/Null",
+       "IF_ADC2/DAC_REF/Null/IF_ADC1",
+       "IF_ADC2/Null/DAC_REF/IF_ADC1",
+       "IF_ADC2/Null/IF_ADC1/DAC_REF",
+
+       "DAC_REF/IF_ADC1/IF_ADC2/Null",
+       "DAC_REF/IF_ADC1/Null/IF_ADC2",
+       "DAC_REF/IF_ADC2/IF_ADC1/Null",
+       "DAC_REF/IF_ADC2/Null/IF_ADC1",
+       "DAC_REF/Null/IF_ADC1/IF_ADC2",
+       "DAC_REF/Null/IF_ADC2/IF_ADC1",
+
+       "Null/IF_ADC1/IF_ADC2/DAC_REF",
+       "Null/IF_ADC1/DAC_REF/IF_ADC2",
+       "Null/IF_ADC2/IF_ADC1/DAC_REF",
+       "Null/IF_ADC2/DAC_REF/IF_ADC1",
+       "Null/DAC_REF/IF_ADC1/IF_ADC2",
+       "Null/DAC_REF/IF_ADC2/IF_ADC1",
+};
+
+static SOC_ENUM_SINGLE_DECL(
+       rt5650_if1_adc_in_enum, RT5645_TDM_CTRL_2,
+       0, rt5650_if1_adc_in_src);
+
+static const struct snd_kcontrol_new rt5650_if1_adc_in_mux =
+       SOC_DAPM_ENUM("IF1 ADC IN source", rt5650_if1_adc_in_enum);
+
+/* MX-78 [15:14][13:12][11:10] */
+static const char * const rt5645_tdm_adc_swap_select[] = {
+       "L/R", "R/L", "L/L", "R/R"
+};
+
+static SOC_ENUM_SINGLE_DECL(rt5650_tdm_adc_slot0_1_enum,
+       RT5645_TDM_CTRL_2, 14, rt5645_tdm_adc_swap_select);
+
+static const struct snd_kcontrol_new rt5650_if1_adc1_in_mux =
+       SOC_DAPM_ENUM("IF1 ADC1 IN source", rt5650_tdm_adc_slot0_1_enum);
+
+static SOC_ENUM_SINGLE_DECL(rt5650_tdm_adc_slot2_3_enum,
+       RT5645_TDM_CTRL_2, 12, rt5645_tdm_adc_swap_select);
+
+static const struct snd_kcontrol_new rt5650_if1_adc2_in_mux =
+       SOC_DAPM_ENUM("IF1 ADC2 IN source", rt5650_tdm_adc_slot2_3_enum);
+
+static SOC_ENUM_SINGLE_DECL(rt5650_tdm_adc_slot4_5_enum,
+       RT5645_TDM_CTRL_2, 10, rt5645_tdm_adc_swap_select);
+
+static const struct snd_kcontrol_new rt5650_if1_adc3_in_mux =
+       SOC_DAPM_ENUM("IF1 ADC3 IN source", rt5650_tdm_adc_slot4_5_enum);
+
+/* MX-77 [7:6][5:4][3:2] */
+static SOC_ENUM_SINGLE_DECL(rt5645_tdm_adc_slot0_1_enum,
+       RT5645_TDM_CTRL_1, 6, rt5645_tdm_adc_swap_select);
+
+static const struct snd_kcontrol_new rt5645_if1_adc1_in_mux =
+       SOC_DAPM_ENUM("IF1 ADC1 IN source", rt5645_tdm_adc_slot0_1_enum);
+
+static SOC_ENUM_SINGLE_DECL(rt5645_tdm_adc_slot2_3_enum,
+       RT5645_TDM_CTRL_1, 4, rt5645_tdm_adc_swap_select);
+
+static const struct snd_kcontrol_new rt5645_if1_adc2_in_mux =
+       SOC_DAPM_ENUM("IF1 ADC2 IN source", rt5645_tdm_adc_slot2_3_enum);
+
+static SOC_ENUM_SINGLE_DECL(rt5645_tdm_adc_slot4_5_enum,
+       RT5645_TDM_CTRL_1, 2, rt5645_tdm_adc_swap_select);
+
+static const struct snd_kcontrol_new rt5645_if1_adc3_in_mux =
+       SOC_DAPM_ENUM("IF1 ADC3 IN source", rt5645_tdm_adc_slot4_5_enum);
+
+/* MX-79 [14:12][10:8][6:4][2:0] */
+static const char * const rt5645_tdm_dac_swap_select[] = {
+       "Slot0", "Slot1", "Slot2", "Slot3"
+};
+
+static SOC_ENUM_SINGLE_DECL(rt5645_tdm_dac0_enum,
+       RT5645_TDM_CTRL_3, 12, rt5645_tdm_dac_swap_select);
+
+static const struct snd_kcontrol_new rt5645_if1_dac0_tdm_sel_mux =
+       SOC_DAPM_ENUM("IF1 DAC0 source", rt5645_tdm_dac0_enum);
+
+static SOC_ENUM_SINGLE_DECL(rt5645_tdm_dac1_enum,
+       RT5645_TDM_CTRL_3, 8, rt5645_tdm_dac_swap_select);
+
+static const struct snd_kcontrol_new rt5645_if1_dac1_tdm_sel_mux =
+       SOC_DAPM_ENUM("IF1 DAC1 source", rt5645_tdm_dac1_enum);
+
+static SOC_ENUM_SINGLE_DECL(rt5645_tdm_dac2_enum,
+       RT5645_TDM_CTRL_3, 4, rt5645_tdm_dac_swap_select);
+
+static const struct snd_kcontrol_new rt5645_if1_dac2_tdm_sel_mux =
+       SOC_DAPM_ENUM("IF1 DAC2 source", rt5645_tdm_dac2_enum);
+
+static SOC_ENUM_SINGLE_DECL(rt5645_tdm_dac3_enum,
+       RT5645_TDM_CTRL_3, 0, rt5645_tdm_dac_swap_select);
+
+static const struct snd_kcontrol_new rt5645_if1_dac3_tdm_sel_mux =
+       SOC_DAPM_ENUM("IF1 DAC3 source", rt5645_tdm_dac3_enum);
+
+/* MX-7a [14:12][10:8][6:4][2:0] */
+static SOC_ENUM_SINGLE_DECL(rt5650_tdm_dac0_enum,
+       RT5650_TDM_CTRL_4, 12, rt5645_tdm_dac_swap_select);
+
+static const struct snd_kcontrol_new rt5650_if1_dac0_tdm_sel_mux =
+       SOC_DAPM_ENUM("IF1 DAC0 source", rt5650_tdm_dac0_enum);
+
+static SOC_ENUM_SINGLE_DECL(rt5650_tdm_dac1_enum,
+       RT5650_TDM_CTRL_4, 8, rt5645_tdm_dac_swap_select);
+
+static const struct snd_kcontrol_new rt5650_if1_dac1_tdm_sel_mux =
+       SOC_DAPM_ENUM("IF1 DAC1 source", rt5650_tdm_dac1_enum);
+
+static SOC_ENUM_SINGLE_DECL(rt5650_tdm_dac2_enum,
+       RT5650_TDM_CTRL_4, 4, rt5645_tdm_dac_swap_select);
+
+static const struct snd_kcontrol_new rt5650_if1_dac2_tdm_sel_mux =
+       SOC_DAPM_ENUM("IF1 DAC2 source", rt5650_tdm_dac2_enum);
+
+static SOC_ENUM_SINGLE_DECL(rt5650_tdm_dac3_enum,
+       RT5650_TDM_CTRL_4, 0, rt5645_tdm_dac_swap_select);
+
+static const struct snd_kcontrol_new rt5650_if1_dac3_tdm_sel_mux =
+       SOC_DAPM_ENUM("IF1 DAC3 source", rt5650_tdm_dac3_enum);
+
 /* MX-2d [3] [2] */
 static const char * const rt5650_a_dac1_src[] = {
        "DAC1", "Stereo DAC Mixer"
@@ -1226,52 +1330,79 @@ static void hp_amp_power(struct snd_soc_codec *codec, int on)
 
        if (on) {
                if (hp_amp_power_count <= 0) {
-                       /* depop parameters */
-                       snd_soc_update_bits(codec, RT5645_DEPOP_M2,
-                               RT5645_DEPOP_MASK, RT5645_DEPOP_MAN);
-                       snd_soc_write(codec, RT5645_DEPOP_M1, 0x000d);
-                       regmap_write(rt5645->regmap, RT5645_PR_BASE +
-                               RT5645_HP_DCC_INT1, 0x9f01);
-                       mdelay(150);
-                       /* headphone amp power on */
-                       snd_soc_update_bits(codec, RT5645_PWR_ANLG1,
-                               RT5645_PWR_FV1 | RT5645_PWR_FV2 , 0);
-                       snd_soc_update_bits(codec, RT5645_PWR_VOL,
-                               RT5645_PWR_HV_L | RT5645_PWR_HV_R,
-                               RT5645_PWR_HV_L | RT5645_PWR_HV_R);
-                       snd_soc_update_bits(codec, RT5645_PWR_ANLG1,
-                               RT5645_PWR_HP_L | RT5645_PWR_HP_R |
-                               RT5645_PWR_HA,
-                               RT5645_PWR_HP_L | RT5645_PWR_HP_R |
-                               RT5645_PWR_HA);
-                       mdelay(5);
-                       snd_soc_update_bits(codec, RT5645_PWR_ANLG1,
-                               RT5645_PWR_FV1 | RT5645_PWR_FV2,
-                               RT5645_PWR_FV1 | RT5645_PWR_FV2);
-
-                       snd_soc_update_bits(codec, RT5645_DEPOP_M1,
-                               RT5645_HP_CO_MASK | RT5645_HP_SG_MASK,
-                               RT5645_HP_CO_EN | RT5645_HP_SG_EN);
-                       regmap_write(rt5645->regmap, RT5645_PR_BASE +
-                               0x14, 0x1aaa);
-                       regmap_write(rt5645->regmap, RT5645_PR_BASE +
-                               0x24, 0x0430);
+                       if (rt5645->codec_type == CODEC_TYPE_RT5650) {
+                               snd_soc_write(codec, RT5645_CHARGE_PUMP,
+                                       0x0e06);
+                               snd_soc_write(codec, RT5645_DEPOP_M1, 0x001d);
+                               regmap_write(rt5645->regmap, RT5645_PR_BASE +
+                                       0x3e, 0x7400);
+                               snd_soc_write(codec, RT5645_DEPOP_M3, 0x0737);
+                               regmap_write(rt5645->regmap, RT5645_PR_BASE +
+                                       RT5645_MAMP_INT_REG2, 0xfc00);
+                               snd_soc_write(codec, RT5645_DEPOP_M2, 0x1140);
+                       } else {
+                               /* depop parameters */
+                               snd_soc_update_bits(codec, RT5645_DEPOP_M2,
+                                       RT5645_DEPOP_MASK, RT5645_DEPOP_MAN);
+                               snd_soc_write(codec, RT5645_DEPOP_M1, 0x000d);
+                               regmap_write(rt5645->regmap, RT5645_PR_BASE +
+                                       RT5645_HP_DCC_INT1, 0x9f01);
+                               mdelay(150);
+                               /* headphone amp power on */
+                               snd_soc_update_bits(codec, RT5645_PWR_ANLG1,
+                                       RT5645_PWR_FV1 | RT5645_PWR_FV2, 0);
+                               snd_soc_update_bits(codec, RT5645_PWR_VOL,
+                                       RT5645_PWR_HV_L | RT5645_PWR_HV_R,
+                                       RT5645_PWR_HV_L | RT5645_PWR_HV_R);
+                               snd_soc_update_bits(codec, RT5645_PWR_ANLG1,
+                                       RT5645_PWR_HP_L | RT5645_PWR_HP_R |
+                                       RT5645_PWR_HA,
+                                       RT5645_PWR_HP_L | RT5645_PWR_HP_R |
+                                       RT5645_PWR_HA);
+                               mdelay(5);
+                               snd_soc_update_bits(codec, RT5645_PWR_ANLG1,
+                                       RT5645_PWR_FV1 | RT5645_PWR_FV2,
+                                       RT5645_PWR_FV1 | RT5645_PWR_FV2);
+
+                               snd_soc_update_bits(codec, RT5645_DEPOP_M1,
+                                       RT5645_HP_CO_MASK | RT5645_HP_SG_MASK,
+                                       RT5645_HP_CO_EN | RT5645_HP_SG_EN);
+                               regmap_write(rt5645->regmap, RT5645_PR_BASE +
+                                       0x14, 0x1aaa);
+                               regmap_write(rt5645->regmap, RT5645_PR_BASE +
+                                       0x24, 0x0430);
+                       }
                }
                hp_amp_power_count++;
        } else {
                hp_amp_power_count--;
                if (hp_amp_power_count <= 0) {
-                       snd_soc_update_bits(codec, RT5645_DEPOP_M1,
-                               RT5645_HP_SG_MASK | RT5645_HP_L_SMT_MASK |
-                               RT5645_HP_R_SMT_MASK, RT5645_HP_SG_DIS |
-                               RT5645_HP_L_SMT_DIS | RT5645_HP_R_SMT_DIS);
-                       /* headphone amp power down */
-                       snd_soc_write(codec, RT5645_DEPOP_M1, 0x0000);
-                       snd_soc_update_bits(codec, RT5645_PWR_ANLG1,
-                               RT5645_PWR_HP_L | RT5645_PWR_HP_R |
-                               RT5645_PWR_HA, 0);
-                       snd_soc_update_bits(codec, RT5645_DEPOP_M2,
-                               RT5645_DEPOP_MASK, 0);
+                       if (rt5645->codec_type == CODEC_TYPE_RT5650) {
+                               regmap_write(rt5645->regmap, RT5645_PR_BASE +
+                                       0x3e, 0x7400);
+                               snd_soc_write(codec, RT5645_DEPOP_M3, 0x0737);
+                               regmap_write(rt5645->regmap, RT5645_PR_BASE +
+                                       RT5645_MAMP_INT_REG2, 0xfc00);
+                               snd_soc_write(codec, RT5645_DEPOP_M2, 0x1140);
+                               msleep(100);
+                               snd_soc_write(codec, RT5645_DEPOP_M1, 0x0001);
+
+                       } else {
+                               snd_soc_update_bits(codec, RT5645_DEPOP_M1,
+                                       RT5645_HP_SG_MASK |
+                                       RT5645_HP_L_SMT_MASK |
+                                       RT5645_HP_R_SMT_MASK,
+                                       RT5645_HP_SG_DIS |
+                                       RT5645_HP_L_SMT_DIS |
+                                       RT5645_HP_R_SMT_DIS);
+                               /* headphone amp power down */
+                               snd_soc_write(codec, RT5645_DEPOP_M1, 0x0000);
+                               snd_soc_update_bits(codec, RT5645_PWR_ANLG1,
+                                       RT5645_PWR_HP_L | RT5645_PWR_HP_R |
+                                       RT5645_PWR_HA, 0);
+                               snd_soc_update_bits(codec, RT5645_DEPOP_M2,
+                                       RT5645_DEPOP_MASK, 0);
+                       }
                }
        }
 }
@@ -1286,56 +1417,52 @@ static int rt5645_hp_event(struct snd_soc_dapm_widget *w,
        case SND_SOC_DAPM_POST_PMU:
                hp_amp_power(codec, 1);
                /* headphone unmute sequence */
-               if (rt5645->codec_type == CODEC_TYPE_RT5650) {
-                       snd_soc_write(codec, RT5645_DEPOP_M3, 0x0737);
-               } else {
+               if (rt5645->codec_type == CODEC_TYPE_RT5645) {
                        snd_soc_update_bits(codec, RT5645_DEPOP_M3,
                                RT5645_CP_FQ1_MASK | RT5645_CP_FQ2_MASK |
                                RT5645_CP_FQ3_MASK,
                                (RT5645_CP_FQ_192_KHZ << RT5645_CP_FQ1_SFT) |
                                (RT5645_CP_FQ_12_KHZ << RT5645_CP_FQ2_SFT) |
                                (RT5645_CP_FQ_192_KHZ << RT5645_CP_FQ3_SFT));
+                       regmap_write(rt5645->regmap, RT5645_PR_BASE +
+                               RT5645_MAMP_INT_REG2, 0xfc00);
+                       snd_soc_update_bits(codec, RT5645_DEPOP_M1,
+                               RT5645_SMT_TRIG_MASK, RT5645_SMT_TRIG_EN);
+                       snd_soc_update_bits(codec, RT5645_DEPOP_M1,
+                               RT5645_RSTN_MASK, RT5645_RSTN_EN);
+                       snd_soc_update_bits(codec, RT5645_DEPOP_M1,
+                               RT5645_RSTN_MASK | RT5645_HP_L_SMT_MASK |
+                               RT5645_HP_R_SMT_MASK, RT5645_RSTN_DIS |
+                               RT5645_HP_L_SMT_EN | RT5645_HP_R_SMT_EN);
+                       msleep(40);
+                       snd_soc_update_bits(codec, RT5645_DEPOP_M1,
+                               RT5645_HP_SG_MASK | RT5645_HP_L_SMT_MASK |
+                               RT5645_HP_R_SMT_MASK, RT5645_HP_SG_DIS |
+                               RT5645_HP_L_SMT_DIS | RT5645_HP_R_SMT_DIS);
                }
-               regmap_write(rt5645->regmap,
-                       RT5645_PR_BASE + RT5645_MAMP_INT_REG2, 0xfc00);
-               snd_soc_update_bits(codec, RT5645_DEPOP_M1,
-                       RT5645_SMT_TRIG_MASK, RT5645_SMT_TRIG_EN);
-               snd_soc_update_bits(codec, RT5645_DEPOP_M1,
-                       RT5645_RSTN_MASK, RT5645_RSTN_EN);
-               snd_soc_update_bits(codec, RT5645_DEPOP_M1,
-                       RT5645_RSTN_MASK | RT5645_HP_L_SMT_MASK |
-                       RT5645_HP_R_SMT_MASK, RT5645_RSTN_DIS |
-                       RT5645_HP_L_SMT_EN | RT5645_HP_R_SMT_EN);
-               msleep(40);
-               snd_soc_update_bits(codec, RT5645_DEPOP_M1,
-                       RT5645_HP_SG_MASK | RT5645_HP_L_SMT_MASK |
-                       RT5645_HP_R_SMT_MASK, RT5645_HP_SG_DIS |
-                       RT5645_HP_L_SMT_DIS | RT5645_HP_R_SMT_DIS);
                break;
 
        case SND_SOC_DAPM_PRE_PMD:
                /* headphone mute sequence */
-               if (rt5645->codec_type == CODEC_TYPE_RT5650) {
-                       snd_soc_write(codec, RT5645_DEPOP_M3, 0x0737);
-               } else {
+               if (rt5645->codec_type == CODEC_TYPE_RT5645) {
                        snd_soc_update_bits(codec, RT5645_DEPOP_M3,
                                RT5645_CP_FQ1_MASK | RT5645_CP_FQ2_MASK |
                                RT5645_CP_FQ3_MASK,
                                (RT5645_CP_FQ_96_KHZ << RT5645_CP_FQ1_SFT) |
                                (RT5645_CP_FQ_12_KHZ << RT5645_CP_FQ2_SFT) |
                                (RT5645_CP_FQ_96_KHZ << RT5645_CP_FQ3_SFT));
+                       regmap_write(rt5645->regmap, RT5645_PR_BASE +
+                               RT5645_MAMP_INT_REG2, 0xfc00);
+                       snd_soc_update_bits(codec, RT5645_DEPOP_M1,
+                               RT5645_HP_SG_MASK, RT5645_HP_SG_EN);
+                       snd_soc_update_bits(codec, RT5645_DEPOP_M1,
+                               RT5645_RSTP_MASK, RT5645_RSTP_EN);
+                       snd_soc_update_bits(codec, RT5645_DEPOP_M1,
+                               RT5645_RSTP_MASK | RT5645_HP_L_SMT_MASK |
+                               RT5645_HP_R_SMT_MASK, RT5645_RSTP_DIS |
+                               RT5645_HP_L_SMT_EN | RT5645_HP_R_SMT_EN);
+                       msleep(30);
                }
-               regmap_write(rt5645->regmap,
-                       RT5645_PR_BASE + RT5645_MAMP_INT_REG2, 0xfc00);
-               snd_soc_update_bits(codec, RT5645_DEPOP_M1,
-                       RT5645_HP_SG_MASK, RT5645_HP_SG_EN);
-               snd_soc_update_bits(codec, RT5645_DEPOP_M1,
-                       RT5645_RSTP_MASK, RT5645_RSTP_EN);
-               snd_soc_update_bits(codec, RT5645_DEPOP_M1,
-                       RT5645_RSTP_MASK | RT5645_HP_L_SMT_MASK |
-                       RT5645_HP_R_SMT_MASK, RT5645_RSTP_DIS |
-                       RT5645_HP_L_SMT_EN | RT5645_HP_R_SMT_EN);
-               msleep(30);
                hp_amp_power(codec, 0);
                break;
 
@@ -1570,20 +1697,33 @@ static const struct snd_soc_dapm_widget rt5645_dapm_widgets[] = {
        SND_SOC_DAPM_PGA("IF1_ADC4", SND_SOC_NOPM, 0, 0, NULL, 0),
 
        /* IF1 2 Mux */
-       SND_SOC_DAPM_MUX("IF1 ADC Mux", SND_SOC_NOPM,
+       SND_SOC_DAPM_MUX("RT5645 IF1 ADC1 Swap Mux", SND_SOC_NOPM,
+               0, 0, &rt5645_if1_adc1_in_mux),
+       SND_SOC_DAPM_MUX("RT5645 IF1 ADC2 Swap Mux", SND_SOC_NOPM,
+               0, 0, &rt5645_if1_adc2_in_mux),
+       SND_SOC_DAPM_MUX("RT5645 IF1 ADC3 Swap Mux", SND_SOC_NOPM,
+               0, 0, &rt5645_if1_adc3_in_mux),
+       SND_SOC_DAPM_MUX("RT5645 IF1 ADC Mux", SND_SOC_NOPM,
                0, 0, &rt5645_if1_adc_in_mux),
+
        SND_SOC_DAPM_MUX("IF2 ADC Mux", SND_SOC_NOPM,
                0, 0, &rt5645_if2_adc_in_mux),
 
        /* Digital Interface */
        SND_SOC_DAPM_SUPPLY("I2S1", RT5645_PWR_DIG1,
                RT5645_PWR_I2S1_BIT, 0, NULL, 0),
+       SND_SOC_DAPM_PGA("IF1 DAC0", SND_SOC_NOPM, 0, 0, NULL, 0),
        SND_SOC_DAPM_PGA("IF1 DAC1", SND_SOC_NOPM, 0, 0, NULL, 0),
        SND_SOC_DAPM_PGA("IF1 DAC2", SND_SOC_NOPM, 0, 0, NULL, 0),
-       SND_SOC_DAPM_PGA("IF1 DAC1 L", SND_SOC_NOPM, 0, 0, NULL, 0),
-       SND_SOC_DAPM_PGA("IF1 DAC1 R", SND_SOC_NOPM, 0, 0, NULL, 0),
-       SND_SOC_DAPM_PGA("IF1 DAC2 L", SND_SOC_NOPM, 0, 0, NULL, 0),
-       SND_SOC_DAPM_PGA("IF1 DAC2 R", SND_SOC_NOPM, 0, 0, NULL, 0),
+       SND_SOC_DAPM_PGA("IF1 DAC3", SND_SOC_NOPM, 0, 0, NULL, 0),
+       SND_SOC_DAPM_MUX("RT5645 IF1 DAC1 L Mux", SND_SOC_NOPM, 0, 0,
+               &rt5645_if1_dac0_tdm_sel_mux),
+       SND_SOC_DAPM_MUX("RT5645 IF1 DAC1 R Mux", SND_SOC_NOPM, 0, 0,
+               &rt5645_if1_dac1_tdm_sel_mux),
+       SND_SOC_DAPM_MUX("RT5645 IF1 DAC2 L Mux", SND_SOC_NOPM, 0, 0,
+               &rt5645_if1_dac2_tdm_sel_mux),
+       SND_SOC_DAPM_MUX("RT5645 IF1 DAC2 R Mux", SND_SOC_NOPM, 0, 0,
+               &rt5645_if1_dac3_tdm_sel_mux),
        SND_SOC_DAPM_PGA("IF1 ADC", SND_SOC_NOPM, 0, 0, NULL, 0),
        SND_SOC_DAPM_PGA("IF1 ADC L", SND_SOC_NOPM, 0, 0, NULL, 0),
        SND_SOC_DAPM_PGA("IF1 ADC R", SND_SOC_NOPM, 0, 0, NULL, 0),
@@ -1725,6 +1865,24 @@ static const struct snd_soc_dapm_widget rt5650_specific_dapm_widgets[] = {
                0, 0, &rt5650_a_dac2_l_mux),
        SND_SOC_DAPM_MUX("A DAC2 R Mux", SND_SOC_NOPM,
                0, 0, &rt5650_a_dac2_r_mux),
+
+       SND_SOC_DAPM_MUX("RT5650 IF1 ADC1 Swap Mux", SND_SOC_NOPM,
+               0, 0, &rt5650_if1_adc1_in_mux),
+       SND_SOC_DAPM_MUX("RT5650 IF1 ADC2 Swap Mux", SND_SOC_NOPM,
+               0, 0, &rt5650_if1_adc2_in_mux),
+       SND_SOC_DAPM_MUX("RT5650 IF1 ADC3 Swap Mux", SND_SOC_NOPM,
+               0, 0, &rt5650_if1_adc3_in_mux),
+       SND_SOC_DAPM_MUX("RT5650 IF1 ADC Mux", SND_SOC_NOPM,
+               0, 0, &rt5650_if1_adc_in_mux),
+
+       SND_SOC_DAPM_MUX("RT5650 IF1 DAC1 L Mux", SND_SOC_NOPM, 0, 0,
+               &rt5650_if1_dac0_tdm_sel_mux),
+       SND_SOC_DAPM_MUX("RT5650 IF1 DAC1 R Mux", SND_SOC_NOPM, 0, 0,
+               &rt5650_if1_dac1_tdm_sel_mux),
+       SND_SOC_DAPM_MUX("RT5650 IF1 DAC2 L Mux", SND_SOC_NOPM, 0, 0,
+               &rt5650_if1_dac2_tdm_sel_mux),
+       SND_SOC_DAPM_MUX("RT5650 IF1 DAC2 R Mux", SND_SOC_NOPM, 0, 0,
+               &rt5650_if1_dac3_tdm_sel_mux),
 };
 
 static const struct snd_soc_dapm_route rt5645_dapm_routes[] = {
@@ -1847,42 +2005,32 @@ static const struct snd_soc_dapm_route rt5645_dapm_routes[] = {
        { "IF_ADC2", NULL, "Mono ADC MIXR" },
        { "VAD_ADC", NULL, "VAD ADC Mux" },
 
-       { "IF1 ADC Mux", "IF_ADC1", "IF_ADC1" },
-       { "IF1 ADC Mux", "IF_ADC2", "IF_ADC2" },
-       { "IF1 ADC Mux", "VAD_ADC", "VAD_ADC" },
-
        { "IF2 ADC Mux", "IF_ADC1", "IF_ADC1" },
        { "IF2 ADC Mux", "IF_ADC2", "IF_ADC2" },
        { "IF2 ADC Mux", "VAD_ADC", "VAD_ADC" },
 
        { "IF1 ADC", NULL, "I2S1" },
-       { "IF1 ADC", NULL, "IF1 ADC Mux" },
        { "IF2 ADC", NULL, "I2S2" },
        { "IF2 ADC", NULL, "IF2 ADC Mux" },
 
-       { "AIF1TX", NULL, "IF1 ADC" },
-       { "AIF1TX", NULL, "IF2 ADC" },
        { "AIF2TX", NULL, "IF2 ADC" },
 
+       { "IF1 DAC0", NULL, "AIF1RX" },
        { "IF1 DAC1", NULL, "AIF1RX" },
        { "IF1 DAC2", NULL, "AIF1RX" },
+       { "IF1 DAC3", NULL, "AIF1RX" },
        { "IF2 DAC", NULL, "AIF2RX" },
 
+       { "IF1 DAC0", NULL, "I2S1" },
        { "IF1 DAC1", NULL, "I2S1" },
        { "IF1 DAC2", NULL, "I2S1" },
+       { "IF1 DAC3", NULL, "I2S1" },
        { "IF2 DAC", NULL, "I2S2" },
 
-       { "IF1 DAC2 L", NULL, "IF1 DAC2" },
-       { "IF1 DAC2 R", NULL, "IF1 DAC2" },
-       { "IF1 DAC1 L", NULL, "IF1 DAC1" },
-       { "IF1 DAC1 R", NULL, "IF1 DAC1" },
        { "IF2 DAC L", NULL, "IF2 DAC" },
        { "IF2 DAC R", NULL, "IF2 DAC" },
 
-       { "DAC1 L Mux", "IF1 DAC", "IF1 DAC1 L" },
        { "DAC1 L Mux", "IF2 DAC", "IF2 DAC L" },
-
-       { "DAC1 R Mux", "IF1 DAC", "IF1 DAC1 R" },
        { "DAC1 R Mux", "IF2 DAC", "IF2 DAC R" },
 
        { "DAC1 MIXL", "Stereo ADC Switch", "Stereo1 ADC MIXL" },
@@ -1892,14 +2040,12 @@ static const struct snd_soc_dapm_route rt5645_dapm_routes[] = {
        { "DAC1 MIXR", "DAC1 Switch", "DAC1 R Mux" },
        { "DAC1 MIXR", NULL, "dac stereo1 filter" },
 
-       { "DAC L2 Mux", "IF1 DAC", "IF1 DAC2 L" },
        { "DAC L2 Mux", "IF2 DAC", "IF2 DAC L" },
        { "DAC L2 Mux", "Mono ADC", "Mono ADC MIXL" },
        { "DAC L2 Mux", "VAD_ADC", "VAD_ADC" },
        { "DAC L2 Volume", NULL, "DAC L2 Mux" },
        { "DAC L2 Volume", NULL, "dac mono left filter" },
 
-       { "DAC R2 Mux", "IF1 DAC", "IF1 DAC2 R" },
        { "DAC R2 Mux", "IF2 DAC", "IF2 DAC R" },
        { "DAC R2 Mux", "Mono ADC", "Mono ADC MIXR" },
        { "DAC R2 Mux", "Haptic", "Haptic Generator" },
@@ -2037,6 +2183,80 @@ static const struct snd_soc_dapm_route rt5650_specific_dapm_routes[] = {
        { "DAC R1", NULL, "A DAC1 R Mux" },
        { "DAC L2", NULL, "A DAC2 L Mux" },
        { "DAC R2", NULL, "A DAC2 R Mux" },
+
+       { "RT5650 IF1 ADC1 Swap Mux", "L/R", "IF_ADC1" },
+       { "RT5650 IF1 ADC1 Swap Mux", "R/L", "IF_ADC1" },
+       { "RT5650 IF1 ADC1 Swap Mux", "L/L", "IF_ADC1" },
+       { "RT5650 IF1 ADC1 Swap Mux", "R/R", "IF_ADC1" },
+
+       { "RT5650 IF1 ADC2 Swap Mux", "L/R", "IF_ADC2" },
+       { "RT5650 IF1 ADC2 Swap Mux", "R/L", "IF_ADC2" },
+       { "RT5650 IF1 ADC2 Swap Mux", "L/L", "IF_ADC2" },
+       { "RT5650 IF1 ADC2 Swap Mux", "R/R", "IF_ADC2" },
+
+       { "RT5650 IF1 ADC3 Swap Mux", "L/R", "VAD_ADC" },
+       { "RT5650 IF1 ADC3 Swap Mux", "R/L", "VAD_ADC" },
+       { "RT5650 IF1 ADC3 Swap Mux", "L/L", "VAD_ADC" },
+       { "RT5650 IF1 ADC3 Swap Mux", "R/R", "VAD_ADC" },
+
+       { "IF1 ADC", NULL, "RT5650 IF1 ADC1 Swap Mux" },
+       { "IF1 ADC", NULL, "RT5650 IF1 ADC2 Swap Mux" },
+       { "IF1 ADC", NULL, "RT5650 IF1 ADC3 Swap Mux" },
+
+       { "RT5650 IF1 ADC Mux", "IF_ADC1/IF_ADC2/DAC_REF/Null", "IF1 ADC" },
+       { "RT5650 IF1 ADC Mux", "IF_ADC1/IF_ADC2/Null/DAC_REF", "IF1 ADC" },
+       { "RT5650 IF1 ADC Mux", "IF_ADC1/DAC_REF/IF_ADC2/Null", "IF1 ADC" },
+       { "RT5650 IF1 ADC Mux", "IF_ADC1/DAC_REF/Null/IF_ADC2", "IF1 ADC" },
+       { "RT5650 IF1 ADC Mux", "IF_ADC1/Null/DAC_REF/IF_ADC2", "IF1 ADC" },
+       { "RT5650 IF1 ADC Mux", "IF_ADC1/Null/IF_ADC2/DAC_REF", "IF1 ADC" },
+
+       { "RT5650 IF1 ADC Mux", "IF_ADC2/IF_ADC1/DAC_REF/Null", "IF1 ADC" },
+       { "RT5650 IF1 ADC Mux", "IF_ADC2/IF_ADC1/Null/DAC_REF", "IF1 ADC" },
+       { "RT5650 IF1 ADC Mux", "IF_ADC2/DAC_REF/IF_ADC1/Null", "IF1 ADC" },
+       { "RT5650 IF1 ADC Mux", "IF_ADC2/DAC_REF/Null/IF_ADC1", "IF1 ADC" },
+       { "RT5650 IF1 ADC Mux", "IF_ADC2/Null/DAC_REF/IF_ADC1", "IF1 ADC" },
+       { "RT5650 IF1 ADC Mux", "IF_ADC2/Null/IF_ADC1/DAC_REF", "IF1 ADC" },
+
+       { "RT5650 IF1 ADC Mux", "DAC_REF/IF_ADC1/IF_ADC2/Null", "IF1 ADC" },
+       { "RT5650 IF1 ADC Mux", "DAC_REF/IF_ADC1/Null/IF_ADC2", "IF1 ADC" },
+       { "RT5650 IF1 ADC Mux", "DAC_REF/IF_ADC2/IF_ADC1/Null", "IF1 ADC" },
+       { "RT5650 IF1 ADC Mux", "DAC_REF/IF_ADC2/Null/IF_ADC1", "IF1 ADC" },
+       { "RT5650 IF1 ADC Mux", "DAC_REF/Null/IF_ADC1/IF_ADC2", "IF1 ADC" },
+       { "RT5650 IF1 ADC Mux", "DAC_REF/Null/IF_ADC2/IF_ADC1", "IF1 ADC" },
+
+       { "RT5650 IF1 ADC Mux", "Null/IF_ADC1/IF_ADC2/DAC_REF", "IF1 ADC" },
+       { "RT5650 IF1 ADC Mux", "Null/IF_ADC1/DAC_REF/IF_ADC2", "IF1 ADC" },
+       { "RT5650 IF1 ADC Mux", "Null/IF_ADC2/IF_ADC1/DAC_REF", "IF1 ADC" },
+       { "RT5650 IF1 ADC Mux", "Null/IF_ADC2/DAC_REF/IF_ADC1", "IF1 ADC" },
+       { "RT5650 IF1 ADC Mux", "Null/DAC_REF/IF_ADC1/IF_ADC2", "IF1 ADC" },
+       { "RT5650 IF1 ADC Mux", "Null/DAC_REF/IF_ADC2/IF_ADC1", "IF1 ADC" },
+       { "AIF1TX", NULL, "RT5650 IF1 ADC Mux" },
+
+       { "RT5650 IF1 DAC1 L Mux", "Slot0", "IF1 DAC0" },
+       { "RT5650 IF1 DAC1 L Mux", "Slot1", "IF1 DAC1" },
+       { "RT5650 IF1 DAC1 L Mux", "Slot2", "IF1 DAC2" },
+       { "RT5650 IF1 DAC1 L Mux", "Slot3", "IF1 DAC3" },
+
+       { "RT5650 IF1 DAC1 R Mux", "Slot0", "IF1 DAC0" },
+       { "RT5650 IF1 DAC1 R Mux", "Slot1", "IF1 DAC1" },
+       { "RT5650 IF1 DAC1 R Mux", "Slot2", "IF1 DAC2" },
+       { "RT5650 IF1 DAC1 R Mux", "Slot3", "IF1 DAC3" },
+
+       { "RT5650 IF1 DAC2 L Mux", "Slot0", "IF1 DAC0" },
+       { "RT5650 IF1 DAC2 L Mux", "Slot1", "IF1 DAC1" },
+       { "RT5650 IF1 DAC2 L Mux", "Slot2", "IF1 DAC2" },
+       { "RT5650 IF1 DAC2 L Mux", "Slot3", "IF1 DAC3" },
+
+       { "RT5650 IF1 DAC2 R Mux", "Slot0", "IF1 DAC0" },
+       { "RT5650 IF1 DAC2 R Mux", "Slot1", "IF1 DAC1" },
+       { "RT5650 IF1 DAC2 R Mux", "Slot2", "IF1 DAC2" },
+       { "RT5650 IF1 DAC2 R Mux", "Slot3", "IF1 DAC3" },
+
+       { "DAC1 L Mux", "IF1 DAC", "RT5650 IF1 DAC1 L Mux" },
+       { "DAC1 R Mux", "IF1 DAC", "RT5650 IF1 DAC1 R Mux" },
+
+       { "DAC L2 Mux", "IF1 DAC", "RT5650 IF1 DAC2 L Mux" },
+       { "DAC R2 Mux", "IF1 DAC", "RT5650 IF1 DAC2 R Mux" },
 };
 
 static const struct snd_soc_dapm_route rt5645_specific_dapm_routes[] = {
@@ -2044,6 +2264,57 @@ static const struct snd_soc_dapm_route rt5645_specific_dapm_routes[] = {
        { "DAC R1", NULL, "Stereo DAC MIXR" },
        { "DAC L2", NULL, "Mono DAC MIXL" },
        { "DAC R2", NULL, "Mono DAC MIXR" },
+
+       { "RT5645 IF1 ADC1 Swap Mux", "L/R", "IF_ADC1" },
+       { "RT5645 IF1 ADC1 Swap Mux", "R/L", "IF_ADC1" },
+       { "RT5645 IF1 ADC1 Swap Mux", "L/L", "IF_ADC1" },
+       { "RT5645 IF1 ADC1 Swap Mux", "R/R", "IF_ADC1" },
+
+       { "RT5645 IF1 ADC2 Swap Mux", "L/R", "IF_ADC2" },
+       { "RT5645 IF1 ADC2 Swap Mux", "R/L", "IF_ADC2" },
+       { "RT5645 IF1 ADC2 Swap Mux", "L/L", "IF_ADC2" },
+       { "RT5645 IF1 ADC2 Swap Mux", "R/R", "IF_ADC2" },
+
+       { "RT5645 IF1 ADC3 Swap Mux", "L/R", "VAD_ADC" },
+       { "RT5645 IF1 ADC3 Swap Mux", "R/L", "VAD_ADC" },
+       { "RT5645 IF1 ADC3 Swap Mux", "L/L", "VAD_ADC" },
+       { "RT5645 IF1 ADC3 Swap Mux", "R/R", "VAD_ADC" },
+
+       { "IF1 ADC", NULL, "RT5645 IF1 ADC1 Swap Mux" },
+       { "IF1 ADC", NULL, "RT5645 IF1 ADC2 Swap Mux" },
+       { "IF1 ADC", NULL, "RT5645 IF1 ADC3 Swap Mux" },
+
+       { "RT5645 IF1 ADC Mux", "IF_ADC1/IF_ADC2/VAD_ADC", "IF1 ADC" },
+       { "RT5645 IF1 ADC Mux", "IF_ADC2/IF_ADC1/VAD_ADC", "IF1 ADC" },
+       { "RT5645 IF1 ADC Mux", "VAD_ADC/IF_ADC1/IF_ADC2", "IF1 ADC" },
+       { "RT5645 IF1 ADC Mux", "VAD_ADC/IF_ADC2/IF_ADC1", "IF1 ADC" },
+       { "AIF1TX", NULL, "RT5645 IF1 ADC Mux" },
+
+       { "RT5645 IF1 DAC1 L Mux", "Slot0", "IF1 DAC0" },
+       { "RT5645 IF1 DAC1 L Mux", "Slot1", "IF1 DAC1" },
+       { "RT5645 IF1 DAC1 L Mux", "Slot2", "IF1 DAC2" },
+       { "RT5645 IF1 DAC1 L Mux", "Slot3", "IF1 DAC3" },
+
+       { "RT5645 IF1 DAC1 R Mux", "Slot0", "IF1 DAC0" },
+       { "RT5645 IF1 DAC1 R Mux", "Slot1", "IF1 DAC1" },
+       { "RT5645 IF1 DAC1 R Mux", "Slot2", "IF1 DAC2" },
+       { "RT5645 IF1 DAC1 R Mux", "Slot3", "IF1 DAC3" },
+
+       { "RT5645 IF1 DAC2 L Mux", "Slot0", "IF1 DAC0" },
+       { "RT5645 IF1 DAC2 L Mux", "Slot1", "IF1 DAC1" },
+       { "RT5645 IF1 DAC2 L Mux", "Slot2", "IF1 DAC2" },
+       { "RT5645 IF1 DAC2 L Mux", "Slot3", "IF1 DAC3" },
+
+       { "RT5645 IF1 DAC2 R Mux", "Slot0", "IF1 DAC0" },
+       { "RT5645 IF1 DAC2 R Mux", "Slot1", "IF1 DAC1" },
+       { "RT5645 IF1 DAC2 R Mux", "Slot2", "IF1 DAC2" },
+       { "RT5645 IF1 DAC2 R Mux", "Slot3", "IF1 DAC3" },
+
+       { "DAC1 L Mux", "IF1 DAC", "RT5645 IF1 DAC1 L Mux" },
+       { "DAC1 R Mux", "IF1 DAC", "RT5645 IF1 DAC1 R Mux" },
+
+       { "DAC L2 Mux", "IF1 DAC", "RT5645 IF1 DAC2 L Mux" },
+       { "DAC R2 Mux", "IF1 DAC", "RT5645 IF1 DAC2 R Mux" },
 };
 
 static int rt5645_hw_params(struct snd_pcm_substream *substream,
@@ -2101,9 +2372,8 @@ static int rt5645_hw_params(struct snd_pcm_substream *substream,
 
        switch (dai->id) {
        case RT5645_AIF1:
-               mask_clk = RT5645_I2S_BCLK_MS1_MASK | RT5645_I2S_PD1_MASK;
-               val_clk = bclk_ms << RT5645_I2S_BCLK_MS1_SFT |
-                       pre_div << RT5645_I2S_PD1_SFT;
+               mask_clk = RT5645_I2S_PD1_MASK;
+               val_clk = pre_div << RT5645_I2S_PD1_SFT;
                snd_soc_update_bits(codec, RT5645_I2S1_SDP,
                        (0x3 << dl_sft), (val_len << dl_sft));
                snd_soc_update_bits(codec, RT5645_ADDA_CLK1, mask_clk, val_clk);
@@ -2368,6 +2638,8 @@ static int rt5645_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask,
 static int rt5645_set_bias_level(struct snd_soc_codec *codec,
                        enum snd_soc_bias_level level)
 {
+       struct rt5645_priv *rt5645 = snd_soc_codec_get_drvdata(codec);
+
        switch (level) {
        case SND_SOC_BIAS_PREPARE:
                if (SND_SOC_BIAS_STANDBY == codec->dapm.bias_level) {
@@ -2398,8 +2670,9 @@ static int rt5645_set_bias_level(struct snd_soc_codec *codec,
 
        case SND_SOC_BIAS_OFF:
                snd_soc_write(codec, RT5645_DEPOP_M2, 0x1100);
-               snd_soc_update_bits(codec, RT5645_GEN_CTRL1,
-                               RT5645_DIG_GATE_CTRL, 0);
+               if (!rt5645->en_button_func)
+                       snd_soc_update_bits(codec, RT5645_GEN_CTRL1,
+                                       RT5645_DIG_GATE_CTRL, 0);
                snd_soc_update_bits(codec, RT5645_PWR_ANLG1,
                                RT5645_PWR_VREF1 | RT5645_PWR_MB |
                                RT5645_PWR_BG | RT5645_PWR_VREF2 |
@@ -2409,72 +2682,228 @@ static int rt5645_set_bias_level(struct snd_soc_codec *codec,
        default:
                break;
        }
-       codec->dapm.bias_level = level;
 
        return 0;
 }
 
-static int rt5645_jack_detect(struct snd_soc_codec *codec)
+static int rt5650_calibration(struct rt5645_priv *rt5645)
 {
-       struct rt5645_priv *rt5645 = snd_soc_codec_get_drvdata(codec);
-       int gpio_state, jack_type = 0;
-       unsigned int val;
+       int val, i;
+       int ret = -1;
 
-       if (!gpio_is_valid(rt5645->pdata.hp_det_gpio)) {
-               dev_err(codec->dev, "invalid gpio\n");
-               return -EINVAL;
+       regcache_cache_bypass(rt5645->regmap, true);
+       regmap_write(rt5645->regmap, RT5645_RESET, 0);
+       regmap_write(rt5645->regmap, RT5645_GEN_CTRL3, 0x0800);
+       regmap_write(rt5645->regmap, RT5645_PR_BASE + RT5645_CHOP_DAC_ADC,
+               0x3600);
+       regmap_write(rt5645->regmap, RT5645_PR_BASE + 0x25, 0x7000);
+       regmap_write(rt5645->regmap, RT5645_I2S1_SDP, 0x8008);
+       /* headset type */
+       regmap_write(rt5645->regmap, RT5645_GEN_CTRL1, 0x2061);
+       regmap_write(rt5645->regmap, RT5645_CHARGE_PUMP, 0x0006);
+       regmap_write(rt5645->regmap, RT5645_PWR_ANLG1, 0x2012);
+       regmap_write(rt5645->regmap, RT5645_PWR_MIXER, 0x0002);
+       regmap_write(rt5645->regmap, RT5645_PWR_VOL, 0x0020);
+       regmap_write(rt5645->regmap, RT5645_JD_CTRL3, 0x00f0);
+       regmap_write(rt5645->regmap, RT5645_IN1_CTRL1, 0x0006);
+       regmap_write(rt5645->regmap, RT5645_IN1_CTRL2, 0x1827);
+       regmap_write(rt5645->regmap, RT5645_IN1_CTRL2, 0x0827);
+       msleep(400);
+       /* Inline command */
+       regmap_write(rt5645->regmap, RT5645_DEPOP_M1, 0x0001);
+       regmap_write(rt5645->regmap, RT5650_4BTN_IL_CMD2, 0xc000);
+       regmap_write(rt5645->regmap, RT5650_4BTN_IL_CMD1, 0x0008);
+       /* Calbration */
+       regmap_write(rt5645->regmap, RT5645_GLB_CLK, 0x8000);
+       regmap_write(rt5645->regmap, RT5645_DEPOP_M1, 0x0000);
+       regmap_write(rt5645->regmap, RT5650_4BTN_IL_CMD2, 0xc000);
+       regmap_write(rt5645->regmap, RT5650_4BTN_IL_CMD1, 0x0008);
+       regmap_write(rt5645->regmap, RT5645_PWR_DIG2, 0x8800);
+       regmap_write(rt5645->regmap, RT5645_PWR_ANLG1, 0xe8fa);
+       regmap_write(rt5645->regmap, RT5645_PWR_ANLG2, 0x8c04);
+       regmap_write(rt5645->regmap, RT5645_DEPOP_M2, 0x3100);
+       regmap_write(rt5645->regmap, RT5645_CHARGE_PUMP, 0x0e06);
+       regmap_write(rt5645->regmap, RT5645_BASS_BACK, 0x8a13);
+       regmap_write(rt5645->regmap, RT5645_GEN_CTRL3, 0x0820);
+       regmap_write(rt5645->regmap, RT5645_DEPOP_M1, 0x000d);
+       /* Power on and Calbration */
+       regmap_write(rt5645->regmap, RT5645_PR_BASE + RT5645_HP_DCC_INT1,
+               0x9f01);
+       msleep(200);
+       for (i = 0; i < 5; i++) {
+               regmap_read(rt5645->regmap, RT5645_PR_BASE + 0x7a, &val);
+               if (val != 0 && val != 0x3f3f) {
+                       ret = 0;
+                       break;
+               }
+               msleep(50);
        }
-       gpio_state = gpio_get_value(rt5645->pdata.hp_det_gpio);
+       pr_debug("%s: PR-7A = 0x%x\n", __func__, val);
+
+       /* mute */
+       regmap_write(rt5645->regmap, RT5645_PR_BASE + 0x3e, 0x7400);
+       regmap_write(rt5645->regmap, RT5645_DEPOP_M3, 0x0737);
+       regmap_write(rt5645->regmap, RT5645_PR_BASE + RT5645_MAMP_INT_REG2,
+               0xfc00);
+       regmap_write(rt5645->regmap, RT5645_DEPOP_M2, 0x1140);
+       regmap_write(rt5645->regmap, RT5645_DEPOP_M1, 0x0000);
+       regmap_write(rt5645->regmap, RT5645_GEN_CTRL2, 0x4020);
+       regmap_write(rt5645->regmap, RT5645_PWR_ANLG2, 0x0006);
+       regmap_write(rt5645->regmap, RT5645_PWR_DIG2, 0x0000);
+       msleep(350);
+
+       regcache_cache_bypass(rt5645->regmap, false);
+
+       return ret;
+}
 
-       dev_dbg(codec->dev, "gpio = %d(%d)\n", rt5645->pdata.hp_det_gpio,
-               gpio_state);
+static void rt5645_enable_push_button_irq(struct snd_soc_codec *codec,
+       bool enable)
+{
+       struct rt5645_priv *rt5645 = snd_soc_codec_get_drvdata(codec);
 
-       if ((rt5645->pdata.gpio_hp_det_active_high && gpio_state) ||
-               (!rt5645->pdata.gpio_hp_det_active_high && !gpio_state)) {
-               snd_soc_dapm_force_enable_pin(&codec->dapm, "micbias1");
-               snd_soc_dapm_force_enable_pin(&codec->dapm, "micbias2");
-               snd_soc_dapm_force_enable_pin(&codec->dapm, "LDO2");
-               snd_soc_dapm_force_enable_pin(&codec->dapm, "Mic Det Power");
-               snd_soc_dapm_sync(&codec->dapm);
+       if (enable) {
+               snd_soc_dapm_mutex_lock(&codec->dapm);
+               snd_soc_dapm_force_enable_pin_unlocked(&codec->dapm,
+                                                       "ADC L power");
+               snd_soc_dapm_force_enable_pin_unlocked(&codec->dapm,
+                                                       "ADC R power");
+               snd_soc_dapm_force_enable_pin_unlocked(&codec->dapm,
+                                                       "LDO2");
+               snd_soc_dapm_force_enable_pin_unlocked(&codec->dapm,
+                                                       "Mic Det Power");
+               snd_soc_dapm_sync_unlocked(&codec->dapm);
+               snd_soc_dapm_mutex_unlock(&codec->dapm);
+
+               snd_soc_update_bits(codec,
+                                       RT5645_INT_IRQ_ST, 0x8, 0x8);
+               snd_soc_update_bits(codec,
+                                       RT5650_4BTN_IL_CMD2, 0x8000, 0x8000);
+               snd_soc_read(codec, RT5650_4BTN_IL_CMD1);
+               pr_debug("%s read %x = %x\n", __func__, RT5650_4BTN_IL_CMD1,
+                       snd_soc_read(codec, RT5650_4BTN_IL_CMD1));
+       } else {
+               snd_soc_update_bits(codec, RT5650_4BTN_IL_CMD2, 0x8000, 0x0);
+               snd_soc_update_bits(codec, RT5645_INT_IRQ_ST, 0x8, 0x0);
+
+               snd_soc_dapm_mutex_lock(&codec->dapm);
+               snd_soc_dapm_disable_pin_unlocked(&codec->dapm,
+                                                       "ADC L power");
+               snd_soc_dapm_disable_pin_unlocked(&codec->dapm,
+                                                       "ADC R power");
+               if (rt5645->pdata.jd_mode == 0)
+                       snd_soc_dapm_disable_pin_unlocked(&codec->dapm,
+                                                               "LDO2");
+               snd_soc_dapm_disable_pin_unlocked(&codec->dapm,
+                                                       "Mic Det Power");
+               snd_soc_dapm_sync_unlocked(&codec->dapm);
+               snd_soc_dapm_mutex_unlock(&codec->dapm);
+       }
+}
 
-               snd_soc_write(codec, RT5645_IN1_CTRL1, 0x0006);
-               snd_soc_write(codec, RT5645_JD_CTRL3, 0x00b0);
+static int rt5645_jack_detect(struct snd_soc_codec *codec, int jack_insert)
+{
+       struct rt5645_priv *rt5645 = snd_soc_codec_get_drvdata(codec);
+       unsigned int val;
 
-               snd_soc_update_bits(codec, RT5645_IN1_CTRL2,
-                       RT5645_CBJ_MN_JD, 0);
-               snd_soc_update_bits(codec, RT5645_IN1_CTRL2,
-                       RT5645_CBJ_MN_JD, RT5645_CBJ_MN_JD);
+       if (jack_insert) {
+               regmap_write(rt5645->regmap, RT5645_CHARGE_PUMP, 0x0006);
+
+               if (codec->component.card->instantiated) {
+                       /* for jack type detect */
+                       snd_soc_dapm_force_enable_pin(&codec->dapm, "LDO2");
+                       snd_soc_dapm_force_enable_pin(&codec->dapm,
+                               "Mic Det Power");
+                       snd_soc_dapm_sync(&codec->dapm);
+               } else {
+                       /* Power up necessary bits for JD if dapm is
+                          not ready yet */
+                       regmap_update_bits(rt5645->regmap, RT5645_PWR_ANLG1,
+                               RT5645_PWR_MB | RT5645_PWR_VREF2,
+                               RT5645_PWR_MB | RT5645_PWR_VREF2);
+                       regmap_update_bits(rt5645->regmap, RT5645_PWR_MIXER,
+                               RT5645_PWR_LDO2, RT5645_PWR_LDO2);
+                       regmap_update_bits(rt5645->regmap, RT5645_PWR_VOL,
+                               RT5645_PWR_MIC_DET, RT5645_PWR_MIC_DET);
+               }
 
-               msleep(400);
-               val = snd_soc_read(codec, RT5645_IN1_CTRL3) & 0x7;
+               regmap_write(rt5645->regmap, RT5645_JD_CTRL3, 0x00f0);
+               regmap_write(rt5645->regmap, RT5645_IN1_CTRL1, 0x0006);
+               regmap_update_bits(rt5645->regmap,
+                                  RT5645_IN1_CTRL2, 0x1000, 0x1000);
+               msleep(100);
+               regmap_update_bits(rt5645->regmap,
+                                  RT5645_IN1_CTRL2, 0x1000, 0x0000);
+
+               msleep(450);
+               regmap_read(rt5645->regmap, RT5645_IN1_CTRL3, &val);
+               val &= 0x7;
                dev_dbg(codec->dev, "val = %d\n", val);
 
-               if (val == 1 || val == 2)
-                       jack_type = SND_JACK_HEADSET;
-               else
-                       jack_type = SND_JACK_HEADPHONE;
+               if (val == 1 || val == 2) {
+                       rt5645->jack_type = SND_JACK_HEADSET;
+                       if (rt5645->en_button_func) {
+                               rt5645_enable_push_button_irq(codec, true);
+                       }
+               } else {
+                       if (codec->component.card->instantiated) {
+                               snd_soc_dapm_disable_pin(&codec->dapm,
+                                       "Mic Det Power");
+                               snd_soc_dapm_sync(&codec->dapm);
+                       } else
+                               regmap_update_bits(rt5645->regmap,
+                                       RT5645_PWR_VOL, RT5645_PWR_MIC_DET, 0);
+                       rt5645->jack_type = SND_JACK_HEADPHONE;
+               }
 
-               snd_soc_dapm_disable_pin(&codec->dapm, "micbias1");
-               snd_soc_dapm_disable_pin(&codec->dapm, "micbias2");
-               if (rt5645->pdata.jd_mode == 0)
-                       snd_soc_dapm_disable_pin(&codec->dapm, "LDO2");
-               snd_soc_dapm_disable_pin(&codec->dapm, "Mic Det Power");
-               snd_soc_dapm_sync(&codec->dapm);
+       } else { /* jack out */
+               rt5645->jack_type = 0;
+               if (rt5645->en_button_func)
+                       rt5645_enable_push_button_irq(codec, false);
+               else {
+                       if (codec->component.card->instantiated) {
+                               if (rt5645->pdata.jd_mode == 0)
+                                       snd_soc_dapm_disable_pin(&codec->dapm,
+                                               "LDO2");
+                               snd_soc_dapm_disable_pin(&codec->dapm,
+                                       "Mic Det Power");
+                               snd_soc_dapm_sync(&codec->dapm);
+                       } else {
+                               if (rt5645->pdata.jd_mode == 0)
+                                       regmap_update_bits(rt5645->regmap,
+                                               RT5645_PWR_MIXER,
+                                               RT5645_PWR_LDO2, 0);
+                               regmap_update_bits(rt5645->regmap,
+                                       RT5645_PWR_VOL, RT5645_PWR_MIC_DET, 0);
+                       }
+               }
        }
 
-       snd_soc_jack_report(rt5645->hp_jack, jack_type, SND_JACK_HEADPHONE);
-       snd_soc_jack_report(rt5645->mic_jack, jack_type, SND_JACK_MICROPHONE);
-       return 0;
+       return rt5645->jack_type;
 }
 
+static int rt5645_irq_detection(struct rt5645_priv *rt5645);
+static irqreturn_t rt5645_irq(int irq, void *data);
+
 int rt5645_set_jack_detect(struct snd_soc_codec *codec,
-       struct snd_soc_jack *hp_jack, struct snd_soc_jack *mic_jack)
+       struct snd_soc_jack *hp_jack, struct snd_soc_jack *mic_jack,
+       struct snd_soc_jack *btn_jack)
 {
        struct rt5645_priv *rt5645 = snd_soc_codec_get_drvdata(codec);
 
        rt5645->hp_jack = hp_jack;
        rt5645->mic_jack = mic_jack;
-       rt5645_jack_detect(codec);
+       rt5645->btn_jack = btn_jack;
+       if (rt5645->btn_jack && rt5645->codec_type == CODEC_TYPE_RT5650) {
+               rt5645->en_button_func = true;
+               regmap_update_bits(rt5645->regmap, RT5645_GPIO_CTRL1,
+                               RT5645_GP1_PIN_IRQ, RT5645_GP1_PIN_IRQ);
+               regmap_update_bits(rt5645->regmap, RT5645_DEPOP_M1,
+                               RT5645_HP_CB_MASK, RT5645_HP_CB_PU);
+               regmap_update_bits(rt5645->regmap, RT5645_GEN_CTRL1,
+                               RT5645_DIG_GATE_CTRL, RT5645_DIG_GATE_CTRL);
+       }
+       rt5645_irq(0, rt5645);
 
        return 0;
 }
@@ -2485,7 +2914,7 @@ static void rt5645_jack_detect_work(struct work_struct *work)
        struct rt5645_priv *rt5645 =
                container_of(work, struct rt5645_priv, jack_detect_work.work);
 
-       rt5645_jack_detect(rt5645->codec);
+       rt5645_irq_detection(rt5645);
 }
 
 static irqreturn_t rt5645_irq(int irq, void *data)
@@ -2498,6 +2927,120 @@ static irqreturn_t rt5645_irq(int irq, void *data)
        return IRQ_HANDLED;
 }
 
+static int rt5645_button_detect(struct snd_soc_codec *codec)
+{
+       int btn_type, val;
+
+       val = snd_soc_read(codec, RT5650_4BTN_IL_CMD1);
+       pr_debug("val=0x%x\n", val);
+       btn_type = val & 0xfff0;
+       snd_soc_write(codec, RT5650_4BTN_IL_CMD1, val);
+
+       return btn_type;
+}
+
+static int rt5645_irq_detection(struct rt5645_priv *rt5645)
+{
+       int val, btn_type, gpio_state = 0, report = 0;
+
+       switch (rt5645->pdata.jd_mode) {
+       case 0: /* Not using rt5645 JD */
+               if (rt5645->gpiod_hp_det) {
+                       gpio_state = gpiod_get_value(rt5645->gpiod_hp_det);
+                       dev_dbg(rt5645->codec->dev, "gpio_state = %d\n",
+                               gpio_state);
+                       report = rt5645_jack_detect(rt5645->codec, gpio_state);
+               }
+               snd_soc_jack_report(rt5645->hp_jack,
+                                   report, SND_JACK_HEADPHONE);
+               snd_soc_jack_report(rt5645->mic_jack,
+                                   report, SND_JACK_MICROPHONE);
+               return report;
+       case 1: /* 2 port */
+               val = snd_soc_read(rt5645->codec, RT5645_A_JD_CTRL1) & 0x0070;
+               break;
+       default: /* 1 port */
+               val = snd_soc_read(rt5645->codec, RT5645_A_JD_CTRL1) & 0x0020;
+               break;
+
+       }
+
+       switch (val) {
+       /* jack in */
+       case 0x30: /* 2 port */
+       case 0x0: /* 1 port or 2 port */
+               if (rt5645->jack_type == 0) {
+                       report = rt5645_jack_detect(rt5645->codec, 1);
+                       /* for push button and jack out */
+                       break;
+               }
+               btn_type = 0;
+               if (snd_soc_read(rt5645->codec, RT5645_INT_IRQ_ST) & 0x4) {
+                       /* button pressed */
+                       report = SND_JACK_HEADSET;
+                       btn_type = rt5645_button_detect(rt5645->codec);
+                       /* rt5650 can report three kinds of button behavior,
+                          one click, double click and hold. However,
+                          currently we will report button pressed/released
+                          event. So all the three button behaviors are
+                          treated as button pressed. */
+                       switch (btn_type) {
+                       case 0x8000:
+                       case 0x4000:
+                       case 0x2000:
+                               report |= SND_JACK_BTN_0;
+                               break;
+                       case 0x1000:
+                       case 0x0800:
+                       case 0x0400:
+                               report |= SND_JACK_BTN_1;
+                               break;
+                       case 0x0200:
+                       case 0x0100:
+                       case 0x0080:
+                               report |= SND_JACK_BTN_2;
+                               break;
+                       case 0x0040:
+                       case 0x0020:
+                       case 0x0010:
+                               report |= SND_JACK_BTN_3;
+                               break;
+                       case 0x0000: /* unpressed */
+                               break;
+                       default:
+                               dev_err(rt5645->codec->dev,
+                                       "Unexpected button code 0x%04x\n",
+                                       btn_type);
+                               break;
+                       }
+               }
+               if (btn_type == 0)/* button release */
+                       report =  rt5645->jack_type;
+
+               break;
+       /* jack out */
+       case 0x70: /* 2 port */
+       case 0x10: /* 2 port */
+       case 0x20: /* 1 port */
+               report = 0;
+               snd_soc_update_bits(rt5645->codec,
+                                   RT5645_INT_IRQ_ST, 0x1, 0x0);
+               rt5645_jack_detect(rt5645->codec, 0);
+               break;
+       default:
+               break;
+       }
+
+       snd_soc_jack_report(rt5645->hp_jack, report, SND_JACK_HEADPHONE);
+       snd_soc_jack_report(rt5645->mic_jack, report, SND_JACK_MICROPHONE);
+       if (rt5645->en_button_func)
+               snd_soc_jack_report(rt5645->btn_jack,
+                       report, SND_JACK_BTN_0 | SND_JACK_BTN_1 |
+                               SND_JACK_BTN_2 | SND_JACK_BTN_3);
+
+       return report;
+}
+
 static int rt5645_probe(struct snd_soc_codec *codec)
 {
        struct rt5645_priv *rt5645 = snd_soc_codec_get_drvdata(codec);
@@ -2520,12 +3063,10 @@ static int rt5645_probe(struct snd_soc_codec *codec)
                break;
        }
 
-       rt5645_set_bias_level(codec, SND_SOC_BIAS_OFF);
-
-       snd_soc_update_bits(codec, RT5645_CHARGE_PUMP, 0x0300, 0x0200);
+       snd_soc_codec_force_bias_level(codec, SND_SOC_BIAS_OFF);
 
        /* for JD function */
-       if (rt5645->pdata.en_jd_func) {
+       if (rt5645->pdata.jd_mode) {
                snd_soc_dapm_force_enable_pin(&codec->dapm, "JD Power");
                snd_soc_dapm_force_enable_pin(&codec->dapm, "LDO2");
                snd_soc_dapm_sync(&codec->dapm);
@@ -2656,6 +3197,55 @@ static const struct i2c_device_id rt5645_i2c_id[] = {
 };
 MODULE_DEVICE_TABLE(i2c, rt5645_i2c_id);
 
+#ifdef CONFIG_ACPI
+static struct acpi_device_id rt5645_acpi_match[] = {
+       { "10EC5645", 0 },
+       { "10EC5650", 0 },
+       {},
+};
+MODULE_DEVICE_TABLE(acpi, rt5645_acpi_match);
+#endif
+
+static struct rt5645_platform_data *rt5645_pdata;
+
+static struct rt5645_platform_data strago_platform_data = {
+       .dmic1_data_pin = RT5645_DMIC1_DISABLE,
+       .dmic2_data_pin = RT5645_DMIC_DATA_IN2P,
+       .jd_mode = 3,
+};
+
+static int strago_quirk_cb(const struct dmi_system_id *id)
+{
+       rt5645_pdata = &strago_platform_data;
+
+       return 1;
+}
+
+static struct dmi_system_id dmi_platform_intel_braswell[] = {
+       {
+               .ident = "Intel Strago",
+               .callback = strago_quirk_cb,
+               .matches = {
+                       DMI_MATCH(DMI_PRODUCT_NAME, "Strago"),
+               },
+       },
+       { }
+};
+
+static int rt5645_parse_dt(struct rt5645_priv *rt5645, struct device *dev)
+{
+       rt5645->pdata.in2_diff = device_property_read_bool(dev,
+               "realtek,in2-differential");
+       device_property_read_u32(dev,
+               "realtek,dmic1-data-pin", &rt5645->pdata.dmic1_data_pin);
+       device_property_read_u32(dev,
+               "realtek,dmic2-data-pin", &rt5645->pdata.dmic2_data_pin);
+       device_property_read_u32(dev,
+               "realtek,jd-mode", &rt5645->pdata.jd_mode);
+
+       return 0;
+}
+
 static int rt5645_i2c_probe(struct i2c_client *i2c,
                    const struct i2c_device_id *id)
 {
@@ -2674,6 +3264,18 @@ static int rt5645_i2c_probe(struct i2c_client *i2c,
 
        if (pdata)
                rt5645->pdata = *pdata;
+       else if (dmi_check_system(dmi_platform_intel_braswell))
+               rt5645->pdata = *rt5645_pdata;
+       else
+               rt5645_parse_dt(rt5645, &i2c->dev);
+
+       rt5645->gpiod_hp_det = devm_gpiod_get_optional(&i2c->dev, "hp-detect",
+                                                      GPIOD_IN);
+
+       if (IS_ERR(rt5645->gpiod_hp_det)) {
+               dev_err(&i2c->dev, "failed to initialize gpiod\n");
+               return PTR_ERR(rt5645->gpiod_hp_det);
+       }
 
        rt5645->regmap = devm_regmap_init_i2c(i2c, &rt5645_regmap);
        if (IS_ERR(rt5645->regmap)) {
@@ -2699,6 +3301,13 @@ static int rt5645_i2c_probe(struct i2c_client *i2c,
                return -ENODEV;
        }
 
+       if (rt5645->codec_type == CODEC_TYPE_RT5650) {
+               ret = rt5650_calibration(rt5645);
+
+               if (ret < 0)
+                       pr_err("calibration failed!\n");
+       }
+
        regmap_write(rt5645->regmap, RT5645_RESET, 0);
 
        ret = regmap_register_patch(rt5645->regmap, init_list,
@@ -2718,84 +3327,76 @@ static int rt5645_i2c_probe(struct i2c_client *i2c,
                regmap_update_bits(rt5645->regmap, RT5645_IN2_CTRL,
                                        RT5645_IN_DF2, RT5645_IN_DF2);
 
-       if (rt5645->pdata.dmic_en) {
+       if (rt5645->pdata.dmic1_data_pin || rt5645->pdata.dmic2_data_pin) {
                regmap_update_bits(rt5645->regmap, RT5645_GPIO_CTRL1,
                        RT5645_GP2_PIN_MASK, RT5645_GP2_PIN_DMIC1_SCL);
+       }
+       switch (rt5645->pdata.dmic1_data_pin) {
+       case RT5645_DMIC_DATA_IN2N:
+               regmap_update_bits(rt5645->regmap, RT5645_DMIC_CTRL1,
+                       RT5645_DMIC_1_DP_MASK, RT5645_DMIC_1_DP_IN2N);
+               break;
 
-               switch (rt5645->pdata.dmic1_data_pin) {
-               case RT5645_DMIC_DATA_IN2N:
-                       regmap_update_bits(rt5645->regmap, RT5645_DMIC_CTRL1,
-                               RT5645_DMIC_1_DP_MASK, RT5645_DMIC_1_DP_IN2N);
-                       break;
-
-               case RT5645_DMIC_DATA_GPIO5:
-                       regmap_update_bits(rt5645->regmap, RT5645_DMIC_CTRL1,
-                               RT5645_DMIC_1_DP_MASK, RT5645_DMIC_1_DP_GPIO5);
-                       regmap_update_bits(rt5645->regmap, RT5645_GPIO_CTRL1,
-                               RT5645_GP5_PIN_MASK, RT5645_GP5_PIN_DMIC1_SDA);
-                       break;
-
-               case RT5645_DMIC_DATA_GPIO11:
-                       regmap_update_bits(rt5645->regmap, RT5645_DMIC_CTRL1,
-                               RT5645_DMIC_1_DP_MASK, RT5645_DMIC_1_DP_GPIO11);
-                       regmap_update_bits(rt5645->regmap, RT5645_GPIO_CTRL1,
-                               RT5645_GP11_PIN_MASK,
-                               RT5645_GP11_PIN_DMIC1_SDA);
-                       break;
+       case RT5645_DMIC_DATA_GPIO5:
+               regmap_update_bits(rt5645->regmap, RT5645_DMIC_CTRL1,
+                       RT5645_DMIC_1_DP_MASK, RT5645_DMIC_1_DP_GPIO5);
+               regmap_update_bits(rt5645->regmap, RT5645_GPIO_CTRL1,
+                       RT5645_GP5_PIN_MASK, RT5645_GP5_PIN_DMIC1_SDA);
+               break;
 
-               default:
-                       break;
-               }
+       case RT5645_DMIC_DATA_GPIO11:
+               regmap_update_bits(rt5645->regmap, RT5645_DMIC_CTRL1,
+                       RT5645_DMIC_1_DP_MASK, RT5645_DMIC_1_DP_GPIO11);
+               regmap_update_bits(rt5645->regmap, RT5645_GPIO_CTRL1,
+                       RT5645_GP11_PIN_MASK,
+                       RT5645_GP11_PIN_DMIC1_SDA);
+               break;
 
-               switch (rt5645->pdata.dmic2_data_pin) {
-               case RT5645_DMIC_DATA_IN2P:
-                       regmap_update_bits(rt5645->regmap, RT5645_DMIC_CTRL1,
-                               RT5645_DMIC_2_DP_MASK, RT5645_DMIC_2_DP_IN2P);
-                       break;
+       default:
+               break;
+       }
 
-               case RT5645_DMIC_DATA_GPIO6:
-                       regmap_update_bits(rt5645->regmap, RT5645_DMIC_CTRL1,
-                               RT5645_DMIC_2_DP_MASK, RT5645_DMIC_2_DP_GPIO6);
-                       regmap_update_bits(rt5645->regmap, RT5645_GPIO_CTRL1,
-                               RT5645_GP6_PIN_MASK, RT5645_GP6_PIN_DMIC2_SDA);
-                       break;
+       switch (rt5645->pdata.dmic2_data_pin) {
+       case RT5645_DMIC_DATA_IN2P:
+               regmap_update_bits(rt5645->regmap, RT5645_DMIC_CTRL1,
+                       RT5645_DMIC_2_DP_MASK, RT5645_DMIC_2_DP_IN2P);
+               break;
 
-               case RT5645_DMIC_DATA_GPIO10:
-                       regmap_update_bits(rt5645->regmap, RT5645_DMIC_CTRL1,
-                               RT5645_DMIC_2_DP_MASK, RT5645_DMIC_2_DP_GPIO10);
-                       regmap_update_bits(rt5645->regmap, RT5645_GPIO_CTRL1,
-                               RT5645_GP10_PIN_MASK,
-                               RT5645_GP10_PIN_DMIC2_SDA);
-                       break;
+       case RT5645_DMIC_DATA_GPIO6:
+               regmap_update_bits(rt5645->regmap, RT5645_DMIC_CTRL1,
+                       RT5645_DMIC_2_DP_MASK, RT5645_DMIC_2_DP_GPIO6);
+               regmap_update_bits(rt5645->regmap, RT5645_GPIO_CTRL1,
+                       RT5645_GP6_PIN_MASK, RT5645_GP6_PIN_DMIC2_SDA);
+               break;
 
-               case RT5645_DMIC_DATA_GPIO12:
-                       regmap_update_bits(rt5645->regmap, RT5645_DMIC_CTRL1,
-                               RT5645_DMIC_1_DP_MASK, RT5645_DMIC_2_DP_GPIO12);
-                       regmap_update_bits(rt5645->regmap, RT5645_GPIO_CTRL1,
-                               RT5645_GP12_PIN_MASK,
-                               RT5645_GP12_PIN_DMIC2_SDA);
-                       break;
+       case RT5645_DMIC_DATA_GPIO10:
+               regmap_update_bits(rt5645->regmap, RT5645_DMIC_CTRL1,
+                       RT5645_DMIC_2_DP_MASK, RT5645_DMIC_2_DP_GPIO10);
+               regmap_update_bits(rt5645->regmap, RT5645_GPIO_CTRL1,
+                       RT5645_GP10_PIN_MASK,
+                       RT5645_GP10_PIN_DMIC2_SDA);
+               break;
 
-               default:
-                       break;
-               }
+       case RT5645_DMIC_DATA_GPIO12:
+               regmap_update_bits(rt5645->regmap, RT5645_DMIC_CTRL1,
+                       RT5645_DMIC_2_DP_MASK, RT5645_DMIC_2_DP_GPIO12);
+               regmap_update_bits(rt5645->regmap, RT5645_GPIO_CTRL1,
+                       RT5645_GP12_PIN_MASK,
+                       RT5645_GP12_PIN_DMIC2_SDA);
+               break;
 
+       default:
+               break;
        }
 
-       if (rt5645->pdata.en_jd_func) {
+       if (rt5645->pdata.jd_mode) {
                regmap_update_bits(rt5645->regmap, RT5645_GEN_CTRL3,
-                       RT5645_IRQ_CLK_GATE_CTRL | RT5645_MICINDET_MANU,
-                       RT5645_IRQ_CLK_GATE_CTRL | RT5645_MICINDET_MANU);
+                                  RT5645_IRQ_CLK_GATE_CTRL,
+                                  RT5645_IRQ_CLK_GATE_CTRL);
                regmap_update_bits(rt5645->regmap, RT5645_IN1_CTRL1,
-                       RT5645_CBJ_BST1_EN, RT5645_CBJ_BST1_EN);
-               regmap_update_bits(rt5645->regmap, RT5645_JD_CTRL3,
-                       RT5645_JD_CBJ_EN | RT5645_JD_CBJ_POL,
-                       RT5645_JD_CBJ_EN | RT5645_JD_CBJ_POL);
+                                  RT5645_CBJ_BST1_EN, RT5645_CBJ_BST1_EN);
                regmap_update_bits(rt5645->regmap, RT5645_MICBIAS,
-                       RT5645_IRQ_CLK_INT, RT5645_IRQ_CLK_INT);
-       }
-
-       if (rt5645->pdata.jd_mode) {
+                                  RT5645_IRQ_CLK_INT, RT5645_IRQ_CLK_INT);
                regmap_update_bits(rt5645->regmap, RT5645_IRQ_CTRL2,
                                   RT5645_IRQ_JD_1_1_EN, RT5645_IRQ_JD_1_1_EN);
                regmap_update_bits(rt5645->regmap, RT5645_GEN_CTRL3,
@@ -2827,6 +3428,8 @@ static int rt5645_i2c_probe(struct i2c_client *i2c,
                }
        }
 
+       INIT_DELAYED_WORK(&rt5645->jack_detect_work, rt5645_jack_detect_work);
+
        if (rt5645->i2c->irq) {
                ret = request_threaded_irq(rt5645->i2c->irq, NULL, rt5645_irq,
                        IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING
@@ -2835,18 +3438,6 @@ static int rt5645_i2c_probe(struct i2c_client *i2c,
                        dev_err(&i2c->dev, "Failed to reguest IRQ: %d\n", ret);
        }
 
-       if (gpio_is_valid(rt5645->pdata.hp_det_gpio)) {
-               ret = gpio_request(rt5645->pdata.hp_det_gpio, "rt5645");
-               if (ret)
-                       dev_err(&i2c->dev, "Fail gpio_request hp_det_gpio\n");
-
-               ret = gpio_direction_input(rt5645->pdata.hp_det_gpio);
-               if (ret)
-                       dev_err(&i2c->dev, "Fail gpio_direction hp_det_gpio\n");
-       }
-
-       INIT_DELAYED_WORK(&rt5645->jack_detect_work, rt5645_jack_detect_work);
-
        return snd_soc_register_codec(&i2c->dev, &soc_codec_dev_rt5645,
                                      rt5645_dai, ARRAY_SIZE(rt5645_dai));
 }
@@ -2860,9 +3451,6 @@ static int rt5645_i2c_remove(struct i2c_client *i2c)
 
        cancel_delayed_work_sync(&rt5645->jack_detect_work);
 
-       if (gpio_is_valid(rt5645->pdata.hp_det_gpio))
-               gpio_free(rt5645->pdata.hp_det_gpio);
-
        snd_soc_unregister_codec(&i2c->dev);
 
        return 0;
@@ -2872,6 +3460,7 @@ static struct i2c_driver rt5645_i2c_driver = {
        .driver = {
                .name = "rt5645",
                .owner = THIS_MODULE,
+               .acpi_match_table = ACPI_PTR(rt5645_acpi_match),
        },
        .probe = rt5645_i2c_probe,
        .remove   = rt5645_i2c_remove,
index db78e9462876978e7a3a3917c31c982a487f5fbd..0353a6a273ab4ca2bd5136c28aaedee14c6e54b2 100644 (file)
 #define RT5645_TDM_CTRL_1                      0x77
 #define RT5645_TDM_CTRL_2                      0x78
 #define RT5645_TDM_CTRL_3                      0x79
+#define RT5650_TDM_CTRL_4                      0x7a
 
 /* Function - Analog */
 #define RT5645_GLB_CLK                         0x80
 #define RT5645_I2S2_SDI_I2S2                   (0x1 << 6)
 
 /* ADC/DAC Clock Control 1 (0x73) */
-#define RT5645_I2S_BCLK_MS1_MASK               (0x1 << 15)
-#define RT5645_I2S_BCLK_MS1_SFT                        15
-#define RT5645_I2S_BCLK_MS1_32                 (0x0 << 15)
-#define RT5645_I2S_BCLK_MS1_64                 (0x1 << 15)
 #define RT5645_I2S_PD1_MASK                    (0x7 << 12)
 #define RT5645_I2S_PD1_SFT                     12
 #define RT5645_I2S_PD1_1                       (0x0 << 12)
 #define RT5645_SCLK_SRC_SFT                    14
 #define RT5645_SCLK_SRC_MCLK                   (0x0 << 14)
 #define RT5645_SCLK_SRC_PLL1                   (0x1 << 14)
-#define RT5645_SCLK_SRC_RCCLK                  (0x2 << 14) /* 15MHz */
-#define RT5645_PLL1_SRC_MASK                   (0x3 << 12)
-#define RT5645_PLL1_SRC_SFT                    12
-#define RT5645_PLL1_SRC_MCLK                   (0x0 << 12)
-#define RT5645_PLL1_SRC_BCLK1                  (0x1 << 12)
-#define RT5645_PLL1_SRC_BCLK2                  (0x2 << 12)
-#define RT5645_PLL1_SRC_BCLK3                  (0x3 << 12)
+#define RT5645_SCLK_SRC_RCCLK                  (0x2 << 14)
+#define RT5645_PLL1_SRC_MASK                   (0x7 << 11)
+#define RT5645_PLL1_SRC_SFT                    11
+#define RT5645_PLL1_SRC_MCLK                   (0x0 << 11)
+#define RT5645_PLL1_SRC_BCLK1                  (0x1 << 11)
+#define RT5645_PLL1_SRC_BCLK2                  (0x2 << 11)
+#define RT5645_PLL1_SRC_BCLK3                  (0x3 << 11)
+#define RT5645_PLL1_SRC_RCCLK                  (0x4 << 11)
 #define RT5645_PLL1_PD_MASK                    (0x1 << 3)
 #define RT5645_PLL1_PD_SFT                     3
 #define RT5645_PLL1_PD_1                       (0x0 << 3)
@@ -2147,6 +2145,7 @@ enum {
 };
 
 enum {
+       RT5645_DMIC1_DISABLE,
        RT5645_DMIC_DATA_IN2P,
        RT5645_DMIC_DATA_GPIO6,
        RT5645_DMIC_DATA_GPIO10,
@@ -2154,6 +2153,7 @@ enum {
 };
 
 enum {
+       RT5645_DMIC2_DISABLE,
        RT5645_DMIC_DATA_IN2N,
        RT5645_DMIC_DATA_GPIO5,
        RT5645_DMIC_DATA_GPIO11,
@@ -2182,8 +2182,10 @@ struct rt5645_priv {
        struct rt5645_platform_data pdata;
        struct regmap *regmap;
        struct i2c_client *i2c;
+       struct gpio_desc *gpiod_hp_det;
        struct snd_soc_jack *hp_jack;
        struct snd_soc_jack *mic_jack;
+       struct snd_soc_jack *btn_jack;
        struct delayed_work jack_detect_work;
 
        int codec_type;
@@ -2196,9 +2198,12 @@ struct rt5645_priv {
        int pll_src;
        int pll_in;
        int pll_out;
+
+       int jack_type;
+       bool en_button_func;
 };
 
 int rt5645_set_jack_detect(struct snd_soc_codec *codec,
-       struct snd_soc_jack *hp_jack, struct snd_soc_jack *mic_jack);
-
+       struct snd_soc_jack *hp_jack, struct snd_soc_jack *mic_jack,
+       struct snd_soc_jack *btn_jack);
 #endif /* __RT5645_H__ */
index 9f4c7be6d798691c70b953c65751904b68c66db1..a3506e193abcd26f90884bf592154a980b797f6a 100644 (file)
@@ -1571,7 +1571,7 @@ static int rt5651_set_bias_level(struct snd_soc_codec *codec,
 {
        switch (level) {
        case SND_SOC_BIAS_PREPARE:
-               if (SND_SOC_BIAS_STANDBY == codec->dapm.bias_level) {
+               if (SND_SOC_BIAS_STANDBY == snd_soc_codec_get_bias_level(codec)) {
                        snd_soc_update_bits(codec, RT5651_PWR_ANLG1,
                                RT5651_PWR_VREF1 | RT5651_PWR_MB |
                                RT5651_PWR_BG | RT5651_PWR_VREF2,
@@ -1604,7 +1604,6 @@ static int rt5651_set_bias_level(struct snd_soc_codec *codec,
        default:
                break;
        }
-       codec->dapm.bias_level = level;
 
        return 0;
 }
@@ -1625,7 +1624,7 @@ static int rt5651_probe(struct snd_soc_codec *codec)
                RT5651_PWR_FV1 | RT5651_PWR_FV2,
                RT5651_PWR_FV1 | RT5651_PWR_FV2);
 
-       rt5651_set_bias_level(codec, SND_SOC_BIAS_OFF);
+       snd_soc_codec_force_bias_level(codec, SND_SOC_BIAS_OFF);
 
        return 0;
 }
index cc7f84a150a7f03878795a7a96f991a6db5b1de5..a9123d41417875a0a5788a3106b6bcd03bb10c9b 100644 (file)
@@ -51,12 +51,11 @@ static const struct regmap_range_cfg rt5670_ranges[] = {
          .window_len = 0x1, },
 };
 
-static struct reg_default init_list[] = {
+static const struct reg_default init_list[] = {
        { RT5670_PR_BASE + 0x14, 0x9a8a },
        { RT5670_PR_BASE + 0x38, 0x3ba1 },
        { RT5670_PR_BASE + 0x3d, 0x3640 },
 };
-#define RT5670_INIT_REG_LEN ARRAY_SIZE(init_list)
 
 static const struct reg_default rt5670_reg[] = {
        { 0x00, 0x0000 },
@@ -416,12 +415,12 @@ static bool rt5670_readable_register(struct device *dev, unsigned int reg)
 static int rt5670_headset_detect(struct snd_soc_codec *codec, int jack_insert)
 {
        int val;
+       struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
        struct rt5670_priv *rt5670 = snd_soc_codec_get_drvdata(codec);
 
        if (jack_insert) {
-               snd_soc_dapm_force_enable_pin(&codec->dapm,
-                                                      "Mic Det Power");
-               snd_soc_dapm_sync(&codec->dapm);
+               snd_soc_dapm_force_enable_pin(dapm, "Mic Det Power");
+               snd_soc_dapm_sync(dapm);
                snd_soc_update_bits(codec, RT5670_GEN_CTRL3, 0x4, 0x0);
                snd_soc_update_bits(codec, RT5670_CJ_CTRL2,
                        RT5670_CBJ_DET_MODE | RT5670_CBJ_MN_JD,
@@ -447,15 +446,15 @@ static int rt5670_headset_detect(struct snd_soc_codec *codec, int jack_insert)
                } else {
                        snd_soc_update_bits(codec, RT5670_GEN_CTRL3, 0x4, 0x4);
                        rt5670->jack_type = SND_JACK_HEADPHONE;
-                       snd_soc_dapm_disable_pin(&codec->dapm, "Mic Det Power");
-                       snd_soc_dapm_sync(&codec->dapm);
+                       snd_soc_dapm_disable_pin(dapm, "Mic Det Power");
+                       snd_soc_dapm_sync(dapm);
                }
        } else {
                snd_soc_update_bits(codec, RT5670_INT_IRQ_ST, 0x8, 0x0);
                snd_soc_update_bits(codec, RT5670_GEN_CTRL3, 0x4, 0x4);
                rt5670->jack_type = 0;
-               snd_soc_dapm_disable_pin(&codec->dapm, "Mic Det Power");
-               snd_soc_dapm_sync(&codec->dapm);
+               snd_soc_dapm_disable_pin(dapm, "Mic Det Power");
+               snd_soc_dapm_sync(dapm);
        }
 
        return rt5670->jack_type;
@@ -2603,7 +2602,7 @@ static int rt5670_set_bias_level(struct snd_soc_codec *codec,
 
        switch (level) {
        case SND_SOC_BIAS_PREPARE:
-               if (SND_SOC_BIAS_STANDBY == codec->dapm.bias_level) {
+               if (SND_SOC_BIAS_STANDBY == snd_soc_codec_get_bias_level(codec)) {
                        snd_soc_update_bits(codec, RT5670_PWR_ANLG1,
                                RT5670_PWR_VREF1 | RT5670_PWR_MB |
                                RT5670_PWR_BG | RT5670_PWR_VREF2,
@@ -2647,30 +2646,30 @@ static int rt5670_set_bias_level(struct snd_soc_codec *codec,
        default:
                break;
        }
-       codec->dapm.bias_level = level;
 
        return 0;
 }
 
 static int rt5670_probe(struct snd_soc_codec *codec)
 {
+       struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
        struct rt5670_priv *rt5670 = snd_soc_codec_get_drvdata(codec);
 
        switch (snd_soc_read(codec, RT5670_RESET) & RT5670_ID_MASK) {
        case RT5670_ID_5670:
        case RT5670_ID_5671:
-               snd_soc_dapm_new_controls(&codec->dapm,
+               snd_soc_dapm_new_controls(dapm,
                        rt5670_specific_dapm_widgets,
                        ARRAY_SIZE(rt5670_specific_dapm_widgets));
-               snd_soc_dapm_add_routes(&codec->dapm,
+               snd_soc_dapm_add_routes(dapm,
                        rt5670_specific_dapm_routes,
                        ARRAY_SIZE(rt5670_specific_dapm_routes));
                break;
        case RT5670_ID_5672:
-               snd_soc_dapm_new_controls(&codec->dapm,
+               snd_soc_dapm_new_controls(dapm,
                        rt5672_specific_dapm_widgets,
                        ARRAY_SIZE(rt5672_specific_dapm_widgets));
-               snd_soc_dapm_add_routes(&codec->dapm,
+               snd_soc_dapm_add_routes(dapm,
                        rt5672_specific_dapm_routes,
                        ARRAY_SIZE(rt5672_specific_dapm_routes));
                break;
@@ -2809,7 +2808,7 @@ static const struct i2c_device_id rt5670_i2c_id[] = {
 MODULE_DEVICE_TABLE(i2c, rt5670_i2c_id);
 
 #ifdef CONFIG_ACPI
-static struct acpi_device_id rt5670_acpi_match[] = {
+static const struct acpi_device_id rt5670_acpi_match[] = {
        { "10EC5670", 0},
        { },
 };
index af182586712d42f9bbac6d5b03338e3e5219cf23..31d969ac11920ff419981caee098a234baf4d0f7 100644 (file)
@@ -62,6 +62,9 @@ static const struct reg_default init_list[] = {
        {RT5677_PR_BASE + 0x1e, 0x0000},
        {RT5677_PR_BASE + 0x12, 0x0eaa},
        {RT5677_PR_BASE + 0x14, 0x018a},
+       {RT5677_PR_BASE + 0x15, 0x0490},
+       {RT5677_PR_BASE + 0x38, 0x0f71},
+       {RT5677_PR_BASE + 0x39, 0x0f71},
 };
 #define RT5677_INIT_REG_LEN ARRAY_SIZE(init_list)
 
@@ -817,7 +820,7 @@ static int rt5677_dsp_vad_put(struct snd_kcontrol *kcontrol,
 
        rt5677->dsp_vad_en = !!ucontrol->value.integer.value[0];
 
-       if (codec->dapm.bias_level == SND_SOC_BIAS_OFF)
+       if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_OFF)
                rt5677_set_dsp_vad(codec, rt5677->dsp_vad_en);
 
        return 0;
@@ -914,7 +917,7 @@ static int set_dmic_clk(struct snd_soc_dapm_widget *w,
 {
        struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
        struct rt5677_priv *rt5677 = snd_soc_codec_get_drvdata(codec);
-       int idx = rl6231_calc_dmic_clk(rt5677->sysclk);
+       int idx = rl6231_calc_dmic_clk(rt5677->lrck[RT5677_AIF1] << 8);
 
        if (idx < 0)
                dev_err(codec->dev, "Failed to set DMIC clock\n");
@@ -1057,6 +1060,7 @@ int rt5677_sel_asrc_clk_src(struct snd_soc_codec *codec,
        unsigned int asrc5_mask = 0, asrc5_value = 0;
        unsigned int asrc6_mask = 0, asrc6_value = 0;
        unsigned int asrc7_mask = 0, asrc7_value = 0;
+       unsigned int asrc8_mask = 0, asrc8_value = 0;
 
        switch (clk_src) {
        case RT5677_CLK_SEL_SYS:
@@ -1193,10 +1197,108 @@ int rt5677_sel_asrc_clk_src(struct snd_soc_codec *codec,
                regmap_update_bits(rt5677->regmap, RT5677_ASRC_7, asrc7_mask,
                        asrc7_value);
 
+       /* ASRC 8 */
+       if (filter_mask & RT5677_I2S1_SOURCE) {
+               asrc8_mask |= RT5677_I2S1_CLK_SEL_MASK;
+               asrc8_value = (asrc8_value & ~RT5677_I2S1_CLK_SEL_MASK)
+                       | ((clk_src - 1) << RT5677_I2S1_CLK_SEL_SFT);
+       }
+
+       if (filter_mask & RT5677_I2S2_SOURCE) {
+               asrc8_mask |= RT5677_I2S2_CLK_SEL_MASK;
+               asrc8_value = (asrc8_value & ~RT5677_I2S2_CLK_SEL_MASK)
+                       | ((clk_src - 1) << RT5677_I2S2_CLK_SEL_SFT);
+       }
+
+       if (filter_mask & RT5677_I2S3_SOURCE) {
+               asrc8_mask |= RT5677_I2S3_CLK_SEL_MASK;
+               asrc8_value = (asrc8_value & ~RT5677_I2S3_CLK_SEL_MASK)
+                       | ((clk_src - 1) << RT5677_I2S3_CLK_SEL_SFT);
+       }
+
+       if (filter_mask & RT5677_I2S4_SOURCE) {
+               asrc8_mask |= RT5677_I2S4_CLK_SEL_MASK;
+               asrc8_value = (asrc8_value & ~RT5677_I2S4_CLK_SEL_MASK)
+                       | ((clk_src - 1) << RT5677_I2S4_CLK_SEL_SFT);
+       }
+
+       if (asrc8_mask)
+               regmap_update_bits(rt5677->regmap, RT5677_ASRC_8, asrc8_mask,
+                       asrc8_value);
+
        return 0;
 }
 EXPORT_SYMBOL_GPL(rt5677_sel_asrc_clk_src);
 
+static int rt5677_dmic_use_asrc(struct snd_soc_dapm_widget *source,
+                        struct snd_soc_dapm_widget *sink)
+{
+       struct snd_soc_codec *codec = snd_soc_dapm_to_codec(source->dapm);
+       struct rt5677_priv *rt5677 = snd_soc_codec_get_drvdata(codec);
+       unsigned int asrc_setting;
+
+       switch (source->shift) {
+       case 11:
+               regmap_read(rt5677->regmap, RT5677_ASRC_5, &asrc_setting);
+               asrc_setting = (asrc_setting & RT5677_AD_STO1_CLK_SEL_MASK) >>
+                               RT5677_AD_STO1_CLK_SEL_SFT;
+               if (asrc_setting >= RT5677_CLK_SEL_I2S1_ASRC &&
+                       asrc_setting <= RT5677_CLK_SEL_I2S6_ASRC)
+                       return 1;
+               break;
+
+       case 10:
+               regmap_read(rt5677->regmap, RT5677_ASRC_5, &asrc_setting);
+               asrc_setting = (asrc_setting & RT5677_AD_STO2_CLK_SEL_MASK) >>
+                               RT5677_AD_STO2_CLK_SEL_SFT;
+               if (asrc_setting >= RT5677_CLK_SEL_I2S1_ASRC &&
+                       asrc_setting <= RT5677_CLK_SEL_I2S6_ASRC)
+                       return 1;
+               break;
+
+       case 9:
+               regmap_read(rt5677->regmap, RT5677_ASRC_5, &asrc_setting);
+               asrc_setting = (asrc_setting & RT5677_AD_STO3_CLK_SEL_MASK) >>
+                               RT5677_AD_STO3_CLK_SEL_SFT;
+               if (asrc_setting >= RT5677_CLK_SEL_I2S1_ASRC &&
+                       asrc_setting <= RT5677_CLK_SEL_I2S6_ASRC)
+                       return 1;
+               break;
+
+       case 8:
+               regmap_read(rt5677->regmap, RT5677_ASRC_5, &asrc_setting);
+               asrc_setting = (asrc_setting & RT5677_AD_STO4_CLK_SEL_MASK) >>
+                       RT5677_AD_STO4_CLK_SEL_SFT;
+               if (asrc_setting >= RT5677_CLK_SEL_I2S1_ASRC &&
+                       asrc_setting <= RT5677_CLK_SEL_I2S6_ASRC)
+                       return 1;
+               break;
+
+       case 7:
+               regmap_read(rt5677->regmap, RT5677_ASRC_6, &asrc_setting);
+               asrc_setting = (asrc_setting & RT5677_AD_MONOL_CLK_SEL_MASK) >>
+                       RT5677_AD_MONOL_CLK_SEL_SFT;
+               if (asrc_setting >= RT5677_CLK_SEL_I2S1_ASRC &&
+                       asrc_setting <= RT5677_CLK_SEL_I2S6_ASRC)
+                       return 1;
+               break;
+
+       case 6:
+               regmap_read(rt5677->regmap, RT5677_ASRC_6, &asrc_setting);
+               asrc_setting = (asrc_setting & RT5677_AD_MONOR_CLK_SEL_MASK) >>
+                       RT5677_AD_MONOR_CLK_SEL_SFT;
+               if (asrc_setting >= RT5677_CLK_SEL_I2S1_ASRC &&
+                       asrc_setting <= RT5677_CLK_SEL_I2S6_ASRC)
+                       return 1;
+               break;
+
+       default:
+               break;
+       }
+
+       return 0;
+}
+
 /* Digital Mixer */
 static const struct snd_kcontrol_new rt5677_sto1_adc_l_mix[] = {
        SOC_DAPM_SINGLE("ADC1 Switch", RT5677_STO1_ADC_MIXER,
@@ -2476,7 +2578,7 @@ static int rt5677_vref_event(struct snd_soc_dapm_widget *w,
 
        switch (event) {
        case SND_SOC_DAPM_POST_PMU:
-               if (codec->dapm.bias_level != SND_SOC_BIAS_ON &&
+               if (snd_soc_codec_get_bias_level(codec) != SND_SOC_BIAS_ON &&
                        !rt5677->is_vref_slow) {
                        mdelay(20);
                        regmap_update_bits(rt5677->regmap, RT5677_PWR_ANLG1,
@@ -3054,12 +3156,12 @@ static const struct snd_soc_dapm_widget rt5677_dapm_widgets[] = {
 };
 
 static const struct snd_soc_dapm_route rt5677_dapm_routes[] = {
-       { "Stereo1 DMIC Mux", NULL, "DMIC STO1 ASRC", can_use_asrc },
-       { "Stereo2 DMIC Mux", NULL, "DMIC STO2 ASRC", can_use_asrc },
-       { "Stereo3 DMIC Mux", NULL, "DMIC STO3 ASRC", can_use_asrc },
-       { "Stereo4 DMIC Mux", NULL, "DMIC STO4 ASRC", can_use_asrc },
-       { "Mono DMIC L Mux", NULL, "DMIC MONO L ASRC", can_use_asrc },
-       { "Mono DMIC R Mux", NULL, "DMIC MONO R ASRC", can_use_asrc },
+       { "Stereo1 DMIC Mux", NULL, "DMIC STO1 ASRC", rt5677_dmic_use_asrc },
+       { "Stereo2 DMIC Mux", NULL, "DMIC STO2 ASRC", rt5677_dmic_use_asrc },
+       { "Stereo3 DMIC Mux", NULL, "DMIC STO3 ASRC", rt5677_dmic_use_asrc },
+       { "Stereo4 DMIC Mux", NULL, "DMIC STO4 ASRC", rt5677_dmic_use_asrc },
+       { "Mono DMIC L Mux", NULL, "DMIC MONO L ASRC", rt5677_dmic_use_asrc },
+       { "Mono DMIC R Mux", NULL, "DMIC MONO R ASRC", rt5677_dmic_use_asrc },
        { "I2S1", NULL, "I2S1 ASRC", can_use_asrc},
        { "I2S2", NULL, "I2S2 ASRC", can_use_asrc},
        { "I2S3", NULL, "I2S3 ASRC", can_use_asrc},
@@ -4350,7 +4452,7 @@ static int rt5677_set_bias_level(struct snd_soc_codec *codec,
                break;
 
        case SND_SOC_BIAS_PREPARE:
-               if (codec->dapm.bias_level == SND_SOC_BIAS_STANDBY) {
+               if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_STANDBY) {
                        rt5677_set_dsp_vad(codec, false);
 
                        regmap_update_bits(rt5677->regmap, RT5677_PWR_ANLG1,
@@ -4392,7 +4494,6 @@ static int rt5677_set_bias_level(struct snd_soc_codec *codec,
        default:
                break;
        }
-       codec->dapm.bias_level = level;
 
        return 0;
 }
@@ -4603,22 +4704,23 @@ static void rt5677_free_gpio(struct i2c_client *i2c)
 
 static int rt5677_probe(struct snd_soc_codec *codec)
 {
+       struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
        struct rt5677_priv *rt5677 = snd_soc_codec_get_drvdata(codec);
        int i;
 
        rt5677->codec = codec;
 
        if (rt5677->pdata.dmic2_clk_pin == RT5677_DMIC_CLK2) {
-               snd_soc_dapm_add_routes(&codec->dapm,
+               snd_soc_dapm_add_routes(dapm,
                        rt5677_dmic2_clk_2,
                        ARRAY_SIZE(rt5677_dmic2_clk_2));
        } else { /*use dmic1 clock by default*/
-               snd_soc_dapm_add_routes(&codec->dapm,
+               snd_soc_dapm_add_routes(dapm,
                        rt5677_dmic2_clk_1,
                        ARRAY_SIZE(rt5677_dmic2_clk_1));
        }
 
-       rt5677_set_bias_level(codec, SND_SOC_BIAS_OFF);
+       snd_soc_codec_force_bias_level(codec, SND_SOC_BIAS_OFF);
 
        regmap_write(rt5677->regmap, RT5677_DIG_MISC, 0x0020);
        regmap_write(rt5677->regmap, RT5677_PWR_DSP2, 0x0c00);
@@ -4664,6 +4766,8 @@ static int rt5677_remove(struct snd_soc_codec *codec)
        regmap_write(rt5677->regmap, RT5677_RESET, 0x10ec);
        if (gpio_is_valid(rt5677->pow_ldo2))
                gpio_set_value_cansleep(rt5677->pow_ldo2, 0);
+       if (gpio_is_valid(rt5677->reset_pin))
+               gpio_set_value_cansleep(rt5677->reset_pin, 0);
 
        return 0;
 }
@@ -4679,6 +4783,8 @@ static int rt5677_suspend(struct snd_soc_codec *codec)
 
                if (gpio_is_valid(rt5677->pow_ldo2))
                        gpio_set_value_cansleep(rt5677->pow_ldo2, 0);
+               if (gpio_is_valid(rt5677->reset_pin))
+                       gpio_set_value_cansleep(rt5677->reset_pin, 0);
        }
 
        return 0;
@@ -4689,10 +4795,13 @@ static int rt5677_resume(struct snd_soc_codec *codec)
        struct rt5677_priv *rt5677 = snd_soc_codec_get_drvdata(codec);
 
        if (!rt5677->dsp_vad_en) {
-               if (gpio_is_valid(rt5677->pow_ldo2)) {
+               if (gpio_is_valid(rt5677->pow_ldo2))
                        gpio_set_value_cansleep(rt5677->pow_ldo2, 1);
+               if (gpio_is_valid(rt5677->reset_pin))
+                       gpio_set_value_cansleep(rt5677->reset_pin, 1);
+               if (gpio_is_valid(rt5677->pow_ldo2) ||
+                   gpio_is_valid(rt5677->reset_pin))
                        msleep(10);
-               }
 
                regcache_cache_only(rt5677->regmap, false);
                regcache_sync(rt5677->regmap);
@@ -4930,6 +5039,8 @@ static int rt5677_parse_dt(struct rt5677_priv *rt5677, struct device_node *np)
 
        rt5677->pow_ldo2 = of_get_named_gpio(np,
                                        "realtek,pow-ldo2-gpio", 0);
+       rt5677->reset_pin = of_get_named_gpio(np,
+                                       "realtek,reset-gpio", 0);
 
        /*
         * POW_LDO2 is optional (it may be statically tied on the board).
@@ -4940,6 +5051,9 @@ static int rt5677_parse_dt(struct rt5677_priv *rt5677, struct device_node *np)
        if (!gpio_is_valid(rt5677->pow_ldo2) &&
                        (rt5677->pow_ldo2 != -ENOENT))
                return rt5677->pow_ldo2;
+       if (!gpio_is_valid(rt5677->reset_pin) &&
+                       (rt5677->reset_pin != -ENOENT))
+               return rt5677->reset_pin;
 
        of_property_read_u8_array(np, "realtek,gpio-config",
                rt5677->pdata.gpio_config, RT5677_GPIO_NUM);
@@ -5041,6 +5155,7 @@ static int rt5677_i2c_probe(struct i2c_client *i2c,
                }
        } else {
                rt5677->pow_ldo2 = -EINVAL;
+               rt5677->reset_pin = -EINVAL;
        }
 
        if (gpio_is_valid(rt5677->pow_ldo2)) {
@@ -5052,6 +5167,21 @@ static int rt5677_i2c_probe(struct i2c_client *i2c,
                                rt5677->pow_ldo2, ret);
                        return ret;
                }
+       }
+
+       if (gpio_is_valid(rt5677->reset_pin)) {
+               ret = devm_gpio_request_one(&i2c->dev, rt5677->reset_pin,
+                                           GPIOF_OUT_INIT_HIGH,
+                                           "RT5677 RESET");
+               if (ret < 0) {
+                       dev_err(&i2c->dev, "Failed to request RESET %d: %d\n",
+                               rt5677->reset_pin, ret);
+                       return ret;
+               }
+       }
+
+       if (gpio_is_valid(rt5677->pow_ldo2) ||
+           gpio_is_valid(rt5677->reset_pin)) {
                /* Wait a while until I2C bus becomes available. The datasheet
                 * does not specify the exact we should wait but startup
                 * sequence mentiones at least a few milliseconds.
index 9dceb41d18ea910db762dd69b7aa4506632ae1a5..7eca38a2325566469aa96f8d019dc4fefbc9328d 100644 (file)
 #define RT5677_DSP_OB_4_7_CLK_SEL_MASK         (0xf << 8)
 #define RT5677_DSP_OB_4_7_CLK_SEL_SFT          8
 
+/* ASRC Control 8 (0x8a) */
+#define RT5677_I2S1_CLK_SEL_MASK               (0xf << 12)
+#define RT5677_I2S1_CLK_SEL_SFT                        12
+#define RT5677_I2S2_CLK_SEL_MASK               (0xf << 8)
+#define RT5677_I2S2_CLK_SEL_SFT                        8
+#define RT5677_I2S3_CLK_SEL_MASK               (0xf << 4)
+#define RT5677_I2S3_CLK_SEL_SFT                        4
+#define RT5677_I2S4_CLK_SEL_MASK               (0xf)
+#define RT5677_I2S4_CLK_SEL_SFT                        0
+
 /* VAD Function Control 4 (0x9f) */
 #define RT5677_VAD_SRC_MASK                    (0x7 << 8)
 #define RT5677_VAD_SRC_SFT                     8
@@ -1744,6 +1754,10 @@ enum {
        RT5677_AD_MONO_R_FILTER = (0x1 << 12),
        RT5677_DSP_OB_0_3_FILTER = (0x1 << 13),
        RT5677_DSP_OB_4_7_FILTER = (0x1 << 14),
+       RT5677_I2S1_SOURCE = (0x1 << 15),
+       RT5677_I2S2_SOURCE = (0x1 << 16),
+       RT5677_I2S3_SOURCE = (0x1 << 17),
+       RT5677_I2S4_SOURCE = (0x1 << 18),
 };
 
 struct rt5677_priv {
@@ -1762,6 +1776,7 @@ struct rt5677_priv {
        int pll_in;
        int pll_out;
        int pow_ldo2; /* POW_LDO2 pin */
+       int reset_pin; /* RESET pin */
        enum rt5677_type type;
 #ifdef CONFIG_GPIOLIB
        struct gpio_chip gpio_chip;
index 3593a1496056d2aa7648142c67bd7952d5b589f6..e673f6ceb5213842dcc6bb98924979a3bb3454a9 100644 (file)
@@ -948,7 +948,7 @@ static int sgtl5000_set_bias_level(struct snd_soc_codec *codec,
        case SND_SOC_BIAS_PREPARE:
                break;
        case SND_SOC_BIAS_STANDBY:
-               if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) {
+               if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_OFF) {
                        ret = regulator_bulk_enable(
                                                ARRAY_SIZE(sgtl5000->supplies),
                                                sgtl5000->supplies);
@@ -979,7 +979,6 @@ static int sgtl5000_set_bias_level(struct snd_soc_codec *codec,
                break;
        }
 
-       codec->dapm.bias_level = level;
        return 0;
 }
 
@@ -1091,6 +1090,19 @@ static bool sgtl5000_readable(struct device *dev, unsigned int reg)
        }
 }
 
+/*
+ * This precalculated table contains all (vag_val * 100 / lo_calcntrl) results
+ * to select an appropriate lo_vol_* in SGTL5000_CHIP_LINE_OUT_VOL
+ * The calculatation was done for all possible register values which
+ * is the array index and the following formula: 10^((idx−15)/40) * 100
+ */
+static const u8 vol_quot_table[] = {
+       42, 45, 47, 50, 53, 56, 60, 63,
+       67, 71, 75, 79, 84, 89, 94, 100,
+       106, 112, 119, 126, 133, 141, 150, 158,
+       168, 178, 188, 200, 211, 224, 237, 251
+};
+
 /*
  * sgtl5000 has 3 internal power supplies:
  * 1. VAG, normally set to vdda/2
@@ -1111,6 +1123,10 @@ static int sgtl5000_set_power_regs(struct snd_soc_codec *codec)
        u16 ana_pwr;
        u16 lreg_ctrl;
        int vag;
+       int lo_vag;
+       int vol_quot;
+       int lo_vol;
+       size_t i;
        struct sgtl5000_priv *sgtl5000 = snd_soc_codec_get_drvdata(codec);
 
        vdda  = regulator_get_voltage(sgtl5000->supplies[VDDA].consumer);
@@ -1198,23 +1214,45 @@ static int sgtl5000_set_power_regs(struct snd_soc_codec *codec)
                        SGTL5000_ANA_GND_MASK, vag << SGTL5000_ANA_GND_SHIFT);
 
        /* set line out VAG to vddio / 2, in range (0.8v, 1.675v) */
-       vag = vddio / 2;
-       if (vag <= SGTL5000_LINE_OUT_GND_BASE)
-               vag = 0;
-       else if (vag >= SGTL5000_LINE_OUT_GND_BASE +
+       lo_vag = vddio / 2;
+       if (lo_vag <= SGTL5000_LINE_OUT_GND_BASE)
+               lo_vag = 0;
+       else if (lo_vag >= SGTL5000_LINE_OUT_GND_BASE +
                SGTL5000_LINE_OUT_GND_STP * SGTL5000_LINE_OUT_GND_MAX)
-               vag = SGTL5000_LINE_OUT_GND_MAX;
+               lo_vag = SGTL5000_LINE_OUT_GND_MAX;
        else
-               vag = (vag - SGTL5000_LINE_OUT_GND_BASE) /
+               lo_vag = (lo_vag - SGTL5000_LINE_OUT_GND_BASE) /
                    SGTL5000_LINE_OUT_GND_STP;
 
        snd_soc_update_bits(codec, SGTL5000_CHIP_LINE_OUT_CTRL,
                        SGTL5000_LINE_OUT_CURRENT_MASK |
                        SGTL5000_LINE_OUT_GND_MASK,
-                       vag << SGTL5000_LINE_OUT_GND_SHIFT |
+                       lo_vag << SGTL5000_LINE_OUT_GND_SHIFT |
                        SGTL5000_LINE_OUT_CURRENT_360u <<
                                SGTL5000_LINE_OUT_CURRENT_SHIFT);
 
+       /*
+        * Set lineout output level in range (0..31)
+        * the same value is used for right and left channel
+        *
+        * Searching for a suitable index solving this formula:
+        * idx = 40 * log10(vag_val / lo_cagcntrl) + 15
+        */
+       vol_quot = (vag * 100) / lo_vag;
+       lo_vol = 0;
+       for (i = 0; i < ARRAY_SIZE(vol_quot_table); i++) {
+               if (vol_quot >= vol_quot_table[i])
+                       lo_vol = i;
+               else
+                       break;
+       }
+
+       snd_soc_update_bits(codec, SGTL5000_CHIP_LINE_OUT_VOL,
+               SGTL5000_LINE_OUT_VOL_RIGHT_MASK |
+               SGTL5000_LINE_OUT_VOL_LEFT_MASK,
+               lo_vol << SGTL5000_LINE_OUT_VOL_RIGHT_SHIFT |
+               lo_vol << SGTL5000_LINE_OUT_VOL_LEFT_SHIFT);
+
        return 0;
 }
 
index 0a8e43c98a0706764664822f2c364de1ae34a6c4..29cb44256044c7557c6d202b503a925bc15e5d4a 100644 (file)
@@ -395,7 +395,7 @@ struct snd_soc_dai_driver sirf_audio_codec_dai = {
 
 static int sirf_audio_codec_probe(struct snd_soc_codec *codec)
 {
-       struct snd_soc_dapm_context *dapm = &codec->dapm;
+       struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
 
        pm_runtime_enable(codec->dev);
 
index 7947c0ebb1ed88a442ecd8e73338fe858c67819c..3a7de0159f2464f14f124de3cc09741e0f49e612 100644 (file)
@@ -194,7 +194,7 @@ static int sn95031_set_vaud_bias(struct snd_soc_codec *codec,
                break;
 
        case SND_SOC_BIAS_PREPARE:
-               if (codec->dapm.bias_level == SND_SOC_BIAS_STANDBY) {
+               if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_STANDBY) {
                        pr_debug("vaud_bias powering up pll\n");
                        /* power up the pll */
                        snd_soc_write(codec, SN95031_AUDPLLCTRL, BIT(5));
@@ -205,17 +205,22 @@ static int sn95031_set_vaud_bias(struct snd_soc_codec *codec,
                break;
 
        case SND_SOC_BIAS_STANDBY:
-               if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) {
+               switch (snd_soc_codec_get_bias_level(codec)) {
+               case SND_SOC_BIAS_OFF:
                        pr_debug("vaud_bias power up rail\n");
                        /* power up the rail */
                        snd_soc_write(codec, SN95031_VAUD,
                                        BIT(2)|BIT(1)|BIT(0));
                        msleep(1);
-               } else if (codec->dapm.bias_level == SND_SOC_BIAS_PREPARE) {
+                       break;
+               case SND_SOC_BIAS_PREPARE:
                        /* turn off pcm */
                        pr_debug("vaud_bias power dn pcm\n");
                        snd_soc_update_bits(codec, SN95031_PCM2C2, BIT(0), 0);
                        snd_soc_write(codec, SN95031_AUDPLLCTRL, 0);
+                       break;
+               default:
+                       break;
                }
                break;
 
@@ -226,7 +231,6 @@ static int sn95031_set_vaud_bias(struct snd_soc_codec *codec,
                break;
        }
 
-       codec->dapm.bias_level = level;
        return 0;
 }
 
index 67ea55adb307d373dd4f3d91291b930b35d68a7a..f30de7639bb9c8d60b9d477d475b445e26ee594d 100644 (file)
@@ -510,7 +510,7 @@ static int ssm2518_set_bias_level(struct snd_soc_codec *codec,
        case SND_SOC_BIAS_PREPARE:
                break;
        case SND_SOC_BIAS_STANDBY:
-               if (codec->dapm.bias_level == SND_SOC_BIAS_OFF)
+               if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_OFF)
                        ret = ssm2518_set_power(ssm2518, true);
                break;
        case SND_SOC_BIAS_OFF:
@@ -518,12 +518,7 @@ static int ssm2518_set_bias_level(struct snd_soc_codec *codec,
                break;
        }
 
-       if (ret)
-               return ret;
-
-       codec->dapm.bias_level = level;
-
-       return 0;
+       return ret;
 }
 
 static int ssm2518_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask,
index 314eaece1b7d6ac50bfb2d8af18ef1247bd3194c..69a773aeb13dbbb05906e54498b4b2300f7cba77 100644 (file)
@@ -473,7 +473,6 @@ static int ssm2602_set_bias_level(struct snd_soc_codec *codec,
                break;
 
        }
-       codec->dapm.bias_level = level;
        return 0;
 }
 
@@ -524,8 +523,8 @@ static int ssm2602_resume(struct snd_soc_codec *codec)
 
 static int ssm2602_codec_probe(struct snd_soc_codec *codec)
 {
+       struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
        struct ssm2602_priv *ssm2602 = snd_soc_codec_get_drvdata(codec);
-       struct snd_soc_dapm_context *dapm = &codec->dapm;
        int ret;
 
        regmap_update_bits(ssm2602->regmap, SSM2602_LOUT1V,
@@ -549,7 +548,7 @@ static int ssm2602_codec_probe(struct snd_soc_codec *codec)
 
 static int ssm2604_codec_probe(struct snd_soc_codec *codec)
 {
-       struct snd_soc_dapm_context *dapm = &codec->dapm;
+       struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
        int ret;
 
        ret = snd_soc_dapm_new_controls(dapm, ssm2604_dapm_widgets,
index a984485108cd10a028b45f1a7974c294c43ba3ed..938d2cb6d78bee03e809f02462b17f951f0c953a 100644 (file)
@@ -353,7 +353,7 @@ static int ssm4567_set_bias_level(struct snd_soc_codec *codec,
        case SND_SOC_BIAS_PREPARE:
                break;
        case SND_SOC_BIAS_STANDBY:
-               if (codec->dapm.bias_level == SND_SOC_BIAS_OFF)
+               if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_OFF)
                        ret = ssm4567_set_power(ssm4567, true);
                break;
        case SND_SOC_BIAS_OFF:
@@ -361,12 +361,7 @@ static int ssm4567_set_bias_level(struct snd_soc_codec *codec,
                break;
        }
 
-       if (ret)
-               return ret;
-
-       codec->dapm.bias_level = level;
-
-       return 0;
+       return ret;
 }
 
 static const struct snd_soc_dai_ops ssm4567_dai_ops = {
index 007a0e3bc2735c0c6f9d8325f15445657fcfd374..60eff36260cbdac1f2b2f406cd79a55811b290dd 100644 (file)
@@ -819,7 +819,7 @@ static int sta32x_set_bias_level(struct snd_soc_codec *codec,
                break;
 
        case SND_SOC_BIAS_STANDBY:
-               if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) {
+               if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_OFF) {
                        ret = regulator_bulk_enable(ARRAY_SIZE(sta32x->supplies),
                                                    sta32x->supplies);
                        if (ret != 0) {
@@ -854,7 +854,6 @@ static int sta32x_set_bias_level(struct snd_soc_codec *codec,
                                       sta32x->supplies);
                break;
        }
-       codec->dapm.bias_level = level;
        return 0;
 }
 
@@ -970,7 +969,7 @@ static int sta32x_probe(struct snd_soc_codec *codec)
        if (sta32x->pdata->needs_esd_watchdog)
                INIT_DELAYED_WORK(&sta32x->watchdog_work, sta32x_watchdog);
 
-       sta32x_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
+       snd_soc_codec_force_bias_level(codec, SND_SOC_BIAS_STANDBY);
        /* Bias level configuration will have done an extra enable */
        regulator_bulk_disable(ARRAY_SIZE(sta32x->supplies), sta32x->supplies);
 
@@ -1096,16 +1095,10 @@ static int sta32x_i2c_probe(struct i2c_client *i2c,
 #endif
 
        /* GPIOs */
-       sta32x->gpiod_nreset = devm_gpiod_get(dev, "reset");
-       if (IS_ERR(sta32x->gpiod_nreset)) {
-               ret = PTR_ERR(sta32x->gpiod_nreset);
-               if (ret != -ENOENT && ret != -ENOSYS)
-                       return ret;
-
-               sta32x->gpiod_nreset = NULL;
-       } else {
-               gpiod_direction_output(sta32x->gpiod_nreset, 0);
-       }
+       sta32x->gpiod_nreset = devm_gpiod_get_optional(dev, "reset",
+                                                      GPIOD_OUT_LOW);
+       if (IS_ERR(sta32x->gpiod_nreset))
+               return PTR_ERR(sta32x->gpiod_nreset);
 
        /* regulators */
        for (i = 0; i < ARRAY_SIZE(sta32x->supplies); i++)
index 669e3228241e39d14a2cb009a508cbdb1f6b9fcb..bd819a3f205aeba88930d0f3e597f31d2197cc5f 100644 (file)
@@ -853,7 +853,7 @@ static int sta350_set_bias_level(struct snd_soc_codec *codec,
                break;
 
        case SND_SOC_BIAS_STANDBY:
-               if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) {
+               if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_OFF) {
                        ret = regulator_bulk_enable(
                                ARRAY_SIZE(sta350->supplies),
                                sta350->supplies);
@@ -890,7 +890,6 @@ static int sta350_set_bias_level(struct snd_soc_codec *codec,
                                       sta350->supplies);
                break;
        }
-       codec->dapm.bias_level = level;
        return 0;
 }
 
@@ -1037,7 +1036,7 @@ static int sta350_probe(struct snd_soc_codec *codec)
        sta350->coef_shadow[60] = 0x400000;
        sta350->coef_shadow[61] = 0x400000;
 
-       sta350_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
+       snd_soc_codec_force_bias_level(codec, SND_SOC_BIAS_STANDBY);
        /* Bias level configuration will have done an extra enable */
        regulator_bulk_disable(ARRAY_SIZE(sta350->supplies), sta350->supplies);
 
@@ -1218,8 +1217,8 @@ static int sta350_i2c_probe(struct i2c_client *i2c,
        if (IS_ERR(sta350->gpiod_nreset))
                return PTR_ERR(sta350->gpiod_nreset);
 
-       sta350->gpiod_power_down = devm_gpiod_get(dev, "power-down",
-                                                 GPIOD_OUT_LOW);
+       sta350->gpiod_power_down = devm_gpiod_get_optional(dev, "power-down",
+                                                          GPIOD_OUT_LOW);
        if (IS_ERR(sta350->gpiod_power_down))
                return PTR_ERR(sta350->gpiod_power_down);
 
index b0f436d101253419dccdbd15d6abe694d383c2a7..4f70378b2cfb4095321f6793dd7d0277851c2ef0 100644 (file)
@@ -165,7 +165,7 @@ static int sta529_set_bias_level(struct snd_soc_codec *codec, enum
                                FFX_CLK_ENB);
                break;
        case SND_SOC_BIAS_STANDBY:
-               if (codec->dapm.bias_level == SND_SOC_BIAS_OFF)
+               if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_OFF)
                        regcache_sync(sta529->regmap);
                snd_soc_update_bits(codec, STA529_FFXCFG0,
                                        POWER_CNTLMSAK, POWER_STDBY);
@@ -179,12 +179,6 @@ static int sta529_set_bias_level(struct snd_soc_codec *codec, enum
                break;
        }
 
-       /*
-        * store the label for powers down audio subsystem for suspend.This is
-        * used by soc core layer
-        */
-       codec->dapm.bias_level = level;
-
        return 0;
 
 }
index 6464caf72b21d6bda252c5a91f5669574e852a98..ed4cca7f6779937a4e92717cc29209356f9a9e5e 100644 (file)
@@ -236,7 +236,6 @@ static int stac9766_set_bias_level(struct snd_soc_codec *codec,
                stac9766_ac97_write(codec, AC97_POWERDOWN, 0xffff);
                break;
        }
-       codec->dapm.bias_level = level;
        return 0;
 }
 
@@ -321,7 +320,7 @@ static struct snd_soc_dai_driver stac9766_dai[] = {
                .channels_max = 2,
                .rates = SNDRV_PCM_RATE_32000 | \
                        SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000,
-               .formats = SNDRV_PCM_FORMAT_IEC958_SUBFRAME_BE,
+               .formats = SNDRV_PCM_FMTBIT_IEC958_SUBFRAME_BE,
        },
        /* alsa ops */
        .ops = &stac9766_dai_ops_digital,
index dfb4ff5cc9ea1a697e050cc2d9343dfc9ff58618..891e2c529df3ae70a79a4f12b2731e9d88f6a30a 100644 (file)
@@ -34,6 +34,7 @@
 #include <sound/soc-dapm.h>
 #include <sound/tlv.h>
 #include <sound/tas2552-plat.h>
+#include <dt-bindings/sound/tas2552.h>
 
 #include "tas2552.h"
 
@@ -45,7 +46,7 @@ static struct reg_default tas2552_reg_defs[] = {
        {TAS2552_PDM_CFG, 0x01},
        {TAS2552_PGA_GAIN, 0x00},
        {TAS2552_BOOST_PT_CTRL, 0x0f},
-       {TAS2552_RESERVED_0D, 0x00},
+       {TAS2552_RESERVED_0D, 0xbe},
        {TAS2552_LIMIT_RATE_HYS, 0x08},
        {TAS2552_CFG_2, 0xef},
        {TAS2552_SER_CTRL_1, 0x00},
@@ -75,20 +76,45 @@ struct tas2552_data {
        struct regulator_bulk_data supplies[TAS2552_NUM_SUPPLIES];
        struct gpio_desc *enable_gpio;
        unsigned char regs[TAS2552_VBAT_DATA];
-       unsigned int mclk;
-};
+       unsigned int pll_clkin;
+       unsigned int pdm_clk;
 
-/* Input mux controls */
-static const char *tas2552_input_texts[] = {
-       "Digital", "Analog"
+       unsigned int dai_fmt;
+       unsigned int tdm_delay;
 };
 
+static int tas2552_post_event(struct snd_soc_dapm_widget *w,
+                             struct snd_kcontrol *kcontrol, int event)
+{
+       struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+
+       switch (event) {
+       case SND_SOC_DAPM_POST_PMU:
+               snd_soc_write(codec, TAS2552_RESERVED_0D, 0xc0);
+               snd_soc_update_bits(codec, TAS2552_LIMIT_RATE_HYS, (1 << 5),
+                                   (1 << 5));
+               snd_soc_update_bits(codec, TAS2552_CFG_2, 1, 0);
+               snd_soc_update_bits(codec, TAS2552_CFG_1, TAS2552_SWS, 0);
+               break;
+       case SND_SOC_DAPM_POST_PMD:
+               snd_soc_update_bits(codec, TAS2552_CFG_1, TAS2552_SWS,
+                                   TAS2552_SWS);
+               snd_soc_update_bits(codec, TAS2552_CFG_2, 1, 1);
+               snd_soc_update_bits(codec, TAS2552_LIMIT_RATE_HYS, (1 << 5), 0);
+               snd_soc_write(codec, TAS2552_RESERVED_0D, 0xbe);
+               break;
+       }
+       return 0;
+}
+
+/* Input mux controls */
+static const char * const tas2552_input_texts[] = {
+       "Digital", "Analog" };
 static SOC_ENUM_SINGLE_DECL(tas2552_input_mux_enum, TAS2552_CFG_3, 7,
                            tas2552_input_texts);
 
-static const struct snd_kcontrol_new tas2552_input_mux_control[] = {
-       SOC_DAPM_ENUM("Input selection", tas2552_input_mux_enum)
-};
+static const struct snd_kcontrol_new tas2552_input_mux_control =
+       SOC_DAPM_ENUM("Route", tas2552_input_mux_enum);
 
 static const struct snd_soc_dapm_widget tas2552_dapm_widgets[] =
 {
@@ -96,12 +122,13 @@ static const struct snd_soc_dapm_widget tas2552_dapm_widgets[] =
 
        /* MUX Controls */
        SND_SOC_DAPM_MUX("Input selection", SND_SOC_NOPM, 0, 0,
-                               tas2552_input_mux_control),
+                        &tas2552_input_mux_control),
 
        SND_SOC_DAPM_AIF_IN("DAC IN", "DAC Playback", 0, SND_SOC_NOPM, 0, 0),
        SND_SOC_DAPM_DAC("DAC", NULL, SND_SOC_NOPM, 0, 0),
        SND_SOC_DAPM_OUT_DRV("ClassD", TAS2552_CFG_2, 7, 0, NULL, 0),
        SND_SOC_DAPM_SUPPLY("PLL", TAS2552_CFG_2, 3, 0, NULL, 0),
+       SND_SOC_DAPM_POST("Post Event", tas2552_post_event),
 
        SND_SOC_DAPM_OUTPUT("OUT")
 };
@@ -118,15 +145,16 @@ static const struct snd_soc_dapm_route tas2552_audio_map[] = {
 #ifdef CONFIG_PM
 static void tas2552_sw_shutdown(struct tas2552_data *tas_data, int sw_shutdown)
 {
-       u8 cfg1_reg;
+       u8 cfg1_reg = 0;
+
+       if (!tas_data->codec)
+               return;
 
        if (sw_shutdown)
-               cfg1_reg = 0;
-       else
-               cfg1_reg = TAS2552_SWS_MASK;
+               cfg1_reg = TAS2552_SWS;
 
-       snd_soc_update_bits(tas_data->codec, TAS2552_CFG_1,
-                                                TAS2552_SWS_MASK, cfg1_reg);
+       snd_soc_update_bits(tas_data->codec, TAS2552_CFG_1, TAS2552_SWS,
+                           cfg1_reg);
 }
 #endif
 
@@ -138,15 +166,92 @@ static int tas2552_hw_params(struct snd_pcm_substream *substream,
        struct tas2552_data *tas2552 = dev_get_drvdata(codec->dev);
        int sample_rate, pll_clk;
        int d;
+       int cpf;
        u8 p, j;
+       u8 ser_ctrl1_reg, wclk_rate;
 
-       if (!tas2552->mclk)
+       switch (params_width(params)) {
+       case 16:
+               ser_ctrl1_reg = TAS2552_WORDLENGTH_16BIT;
+               cpf = 32 + tas2552->tdm_delay;
+               break;
+       case 20:
+               ser_ctrl1_reg = TAS2552_WORDLENGTH_20BIT;
+               cpf = 64 + tas2552->tdm_delay;
+               break;
+       case 24:
+               ser_ctrl1_reg = TAS2552_WORDLENGTH_24BIT;
+               cpf = 64 + tas2552->tdm_delay;
+               break;
+       case 32:
+               ser_ctrl1_reg = TAS2552_WORDLENGTH_32BIT;
+               cpf = 64 + tas2552->tdm_delay;
+               break;
+       default:
+               dev_err(codec->dev, "Not supported sample size: %d\n",
+                       params_width(params));
+               return -EINVAL;
+       }
+
+       if (cpf <= 32)
+               ser_ctrl1_reg |= TAS2552_CLKSPERFRAME_32;
+       else if (cpf <= 64)
+               ser_ctrl1_reg |= TAS2552_CLKSPERFRAME_64;
+       else if (cpf <= 128)
+               ser_ctrl1_reg |= TAS2552_CLKSPERFRAME_128;
+       else
+               ser_ctrl1_reg |= TAS2552_CLKSPERFRAME_256;
+
+       snd_soc_update_bits(codec, TAS2552_SER_CTRL_1,
+                           TAS2552_WORDLENGTH_MASK | TAS2552_CLKSPERFRAME_MASK,
+                           ser_ctrl1_reg);
+
+       switch (params_rate(params)) {
+       case 8000:
+               wclk_rate = TAS2552_WCLK_FREQ_8KHZ;
+               break;
+       case 11025:
+       case 12000:
+               wclk_rate = TAS2552_WCLK_FREQ_11_12KHZ;
+               break;
+       case 16000:
+               wclk_rate = TAS2552_WCLK_FREQ_16KHZ;
+               break;
+       case 22050:
+       case 24000:
+               wclk_rate = TAS2552_WCLK_FREQ_22_24KHZ;
+               break;
+       case 32000:
+               wclk_rate = TAS2552_WCLK_FREQ_32KHZ;
+               break;
+       case 44100:
+       case 48000:
+               wclk_rate = TAS2552_WCLK_FREQ_44_48KHZ;
+               break;
+       case 88200:
+       case 96000:
+               wclk_rate = TAS2552_WCLK_FREQ_88_96KHZ;
+               break;
+       case 176400:
+       case 192000:
+               wclk_rate = TAS2552_WCLK_FREQ_176_192KHZ;
+               break;
+       default:
+               dev_err(codec->dev, "Not supported sample rate: %d\n",
+                       params_rate(params));
+               return -EINVAL;
+       }
+
+       snd_soc_update_bits(codec, TAS2552_CFG_3, TAS2552_WCLK_FREQ_MASK,
+                           wclk_rate);
+
+       if (!tas2552->pll_clkin)
                return -EINVAL;
 
        snd_soc_update_bits(codec, TAS2552_CFG_2, TAS2552_PLL_ENABLE, 0);
 
-       if (tas2552->mclk == TAS2552_245MHZ_CLK ||
-               tas2552->mclk == TAS2552_225MHZ_CLK) {
+       if (tas2552->pll_clkin == TAS2552_245MHZ_CLK ||
+           tas2552->pll_clkin == TAS2552_225MHZ_CLK) {
                /* By pass the PLL configuration */
                snd_soc_update_bits(codec, TAS2552_PLL_CTRL_2,
                                    TAS2552_PLL_BYPASS_MASK,
@@ -170,8 +275,8 @@ static int tas2552_hw_params(struct snd_pcm_substream *substream,
                        return -EINVAL;
                }
 
-               j = (pll_clk * 2 * (1 << p)) / tas2552->mclk;
-               d = (pll_clk * 2 * (1 << p)) % tas2552->mclk;
+               j = (pll_clk * 2 * (1 << p)) / tas2552->pll_clkin;
+               d = (pll_clk * 2 * (1 << p)) % tas2552->pll_clkin;
 
                snd_soc_update_bits(codec, TAS2552_PLL_CTRL_1,
                                TAS2552_PLL_J_MASK, j);
@@ -185,56 +290,74 @@ static int tas2552_hw_params(struct snd_pcm_substream *substream,
        return 0;
 }
 
+#define TAS2552_DAI_FMT_MASK   (TAS2552_BCLKDIR | \
+                                TAS2552_WCLKDIR | \
+                                TAS2552_DATAFORMAT_MASK)
+static int tas2552_prepare(struct snd_pcm_substream *substream,
+                          struct snd_soc_dai *dai)
+{
+       struct snd_soc_codec *codec = dai->codec;
+       struct tas2552_data *tas2552 = snd_soc_codec_get_drvdata(codec);
+       int delay = 0;
+
+       /* TDM slot selection only valid in DSP_A/_B mode */
+       if (tas2552->dai_fmt == SND_SOC_DAIFMT_DSP_A)
+               delay += (tas2552->tdm_delay + 1);
+       else if (tas2552->dai_fmt == SND_SOC_DAIFMT_DSP_B)
+               delay += tas2552->tdm_delay;
+
+       /* Configure data delay */
+       snd_soc_write(codec, TAS2552_SER_CTRL_2, delay);
+
+       return 0;
+}
+
 static int tas2552_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)
 {
        struct snd_soc_codec *codec = dai->codec;
+       struct tas2552_data *tas2552 = dev_get_drvdata(codec->dev);
        u8 serial_format;
-       u8 serial_control_mask;
 
        switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
        case SND_SOC_DAIFMT_CBS_CFS:
                serial_format = 0x00;
                break;
        case SND_SOC_DAIFMT_CBS_CFM:
-               serial_format = TAS2552_WORD_CLK_MASK;
+               serial_format = TAS2552_WCLKDIR;
                break;
        case SND_SOC_DAIFMT_CBM_CFS:
-               serial_format = TAS2552_BIT_CLK_MASK;
+               serial_format = TAS2552_BCLKDIR;
                break;
        case SND_SOC_DAIFMT_CBM_CFM:
-               serial_format = (TAS2552_BIT_CLK_MASK | TAS2552_WORD_CLK_MASK);
+               serial_format = (TAS2552_BCLKDIR | TAS2552_WCLKDIR);
                break;
        default:
                dev_vdbg(codec->dev, "DAI Format master is not found\n");
                return -EINVAL;
        }
 
-       serial_control_mask = TAS2552_BIT_CLK_MASK | TAS2552_WORD_CLK_MASK;
-
-       switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
-       case SND_SOC_DAIFMT_I2S:
-               serial_format &= TAS2552_DAIFMT_I2S_MASK;
+       switch (fmt & (SND_SOC_DAIFMT_FORMAT_MASK |
+                      SND_SOC_DAIFMT_INV_MASK)) {
+       case (SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF):
                break;
-       case SND_SOC_DAIFMT_DSP_A:
-               serial_format |= TAS2552_DAIFMT_DSP;
+       case (SND_SOC_DAIFMT_DSP_A | SND_SOC_DAIFMT_IB_NF):
+       case (SND_SOC_DAIFMT_DSP_B | SND_SOC_DAIFMT_IB_NF):
+               serial_format |= TAS2552_DATAFORMAT_DSP;
                break;
-       case SND_SOC_DAIFMT_RIGHT_J:
-               serial_format |= TAS2552_DAIFMT_RIGHT_J;
+       case (SND_SOC_DAIFMT_RIGHT_J | SND_SOC_DAIFMT_NB_NF):
+               serial_format |= TAS2552_DATAFORMAT_RIGHT_J;
                break;
-       case SND_SOC_DAIFMT_LEFT_J:
-               serial_format |= TAS2552_DAIFMT_LEFT_J;
+       case (SND_SOC_DAIFMT_LEFT_J | SND_SOC_DAIFMT_NB_NF):
+               serial_format |= TAS2552_DATAFORMAT_LEFT_J;
                break;
        default:
                dev_vdbg(codec->dev, "DAI Format is not found\n");
                return -EINVAL;
        }
+       tas2552->dai_fmt = fmt & SND_SOC_DAIFMT_FORMAT_MASK;
 
-       if (fmt & SND_SOC_DAIFMT_FORMAT_MASK)
-               serial_control_mask |= TAS2552_DATA_FORMAT_MASK;
-
-       snd_soc_update_bits(codec, TAS2552_SER_CTRL_1, serial_control_mask,
-                                               serial_format);
-
+       snd_soc_update_bits(codec, TAS2552_SER_CTRL_1, TAS2552_DAI_FMT_MASK,
+                           serial_format);
        return 0;
 }
 
@@ -243,23 +366,75 @@ static int tas2552_set_dai_sysclk(struct snd_soc_dai *dai, int clk_id,
 {
        struct snd_soc_codec *codec = dai->codec;
        struct tas2552_data *tas2552 = dev_get_drvdata(codec->dev);
+       u8 reg, mask, val;
+
+       switch (clk_id) {
+       case TAS2552_PLL_CLKIN_MCLK:
+       case TAS2552_PLL_CLKIN_BCLK:
+       case TAS2552_PLL_CLKIN_IVCLKIN:
+       case TAS2552_PLL_CLKIN_1_8_FIXED:
+               mask = TAS2552_PLL_SRC_MASK;
+               val = (clk_id << 3) & mask; /* bit 4:5 in the register */
+               reg = TAS2552_CFG_1;
+               tas2552->pll_clkin = freq;
+               break;
+       case TAS2552_PDM_CLK_PLL:
+       case TAS2552_PDM_CLK_IVCLKIN:
+       case TAS2552_PDM_CLK_BCLK:
+       case TAS2552_PDM_CLK_MCLK:
+               mask = TAS2552_PDM_CLK_SEL_MASK;
+               val = (clk_id >> 1) & mask; /* bit 0:1 in the register */
+               reg = TAS2552_PDM_CFG;
+               tas2552->pdm_clk = freq;
+               break;
+       default:
+               dev_err(codec->dev, "Invalid clk id: %d\n", clk_id);
+               return -EINVAL;
+       }
+
+       snd_soc_update_bits(codec, reg, mask, val);
+
+       return 0;
+}
+
+static int tas2552_set_dai_tdm_slot(struct snd_soc_dai *dai,
+                                   unsigned int tx_mask, unsigned int rx_mask,
+                                   int slots, int slot_width)
+{
+       struct snd_soc_codec *codec = dai->codec;
+       struct tas2552_data *tas2552 = snd_soc_codec_get_drvdata(codec);
+       unsigned int lsb;
+
+       if (unlikely(!tx_mask)) {
+               dev_err(codec->dev, "tx masks need to be non 0\n");
+               return -EINVAL;
+       }
+
+       /* TDM based on DSP mode requires slots to be adjacent */
+       lsb = __ffs(tx_mask);
+       if ((lsb + 1) != __fls(tx_mask)) {
+               dev_err(codec->dev, "Invalid mask, slots must be adjacent\n");
+               return -EINVAL;
+       }
+
+       tas2552->tdm_delay = lsb * slot_width;
 
-       tas2552->mclk = freq;
+       /* DOUT in high-impedance on inactive bit clocks */
+       snd_soc_update_bits(codec, TAS2552_DOUT,
+                           TAS2552_SDOUT_TRISTATE, TAS2552_SDOUT_TRISTATE);
 
        return 0;
 }
 
 static int tas2552_mute(struct snd_soc_dai *dai, int mute)
 {
-       u8 cfg1_reg;
+       u8 cfg1_reg = 0;
        struct snd_soc_codec *codec = dai->codec;
 
        if (mute)
-               cfg1_reg = TAS2552_MUTE_MASK;
-       else
-               cfg1_reg = ~TAS2552_MUTE_MASK;
+               cfg1_reg |= TAS2552_MUTE;
 
-       snd_soc_update_bits(codec, TAS2552_CFG_1, TAS2552_MUTE_MASK, cfg1_reg);
+       snd_soc_update_bits(codec, TAS2552_CFG_1, TAS2552_MUTE, cfg1_reg);
 
        return 0;
 }
@@ -269,7 +444,7 @@ static int tas2552_runtime_suspend(struct device *dev)
 {
        struct tas2552_data *tas2552 = dev_get_drvdata(dev);
 
-       tas2552_sw_shutdown(tas2552, 0);
+       tas2552_sw_shutdown(tas2552, 1);
 
        regcache_cache_only(tas2552->regmap, true);
        regcache_mark_dirty(tas2552->regmap);
@@ -287,7 +462,7 @@ static int tas2552_runtime_resume(struct device *dev)
        if (tas2552->enable_gpio)
                gpiod_set_value(tas2552->enable_gpio, 1);
 
-       tas2552_sw_shutdown(tas2552, 1);
+       tas2552_sw_shutdown(tas2552, 0);
 
        regcache_cache_only(tas2552->regmap, false);
        regcache_sync(tas2552->regmap);
@@ -303,8 +478,10 @@ static const struct dev_pm_ops tas2552_pm = {
 
 static struct snd_soc_dai_ops tas2552_speaker_dai_ops = {
        .hw_params      = tas2552_hw_params,
+       .prepare        = tas2552_prepare,
        .set_sysclk     = tas2552_set_dai_sysclk,
        .set_fmt        = tas2552_set_dai_fmt,
+       .set_tdm_slot   = tas2552_set_dai_tdm_slot,
        .digital_mute = tas2552_mute,
 };
 
@@ -330,16 +507,11 @@ static struct snd_soc_dai_driver tas2552_dai[] = {
 /*
  * DAC digital volumes. From -7 to 24 dB in 1 dB steps
  */
-static DECLARE_TLV_DB_SCALE(dac_tlv, -7, 100, 24);
+static DECLARE_TLV_DB_SCALE(dac_tlv, -7, 100, 0);
 
 static const struct snd_kcontrol_new tas2552_snd_controls[] = {
        SOC_SINGLE_TLV("Speaker Driver Playback Volume",
-                        TAS2552_PGA_GAIN, 0, 0x1f, 1, dac_tlv),
-       SOC_DAPM_SINGLE("Playback AMP", SND_SOC_NOPM, 0, 1, 0),
-};
-
-static const struct reg_default tas2552_init_regs[] = {
-       { TAS2552_RESERVED_0D, 0xc0 },
+                        TAS2552_PGA_GAIN, 0, 0x1f, 0, dac_tlv),
 };
 
 static int tas2552_codec_probe(struct snd_soc_codec *codec)
@@ -368,31 +540,19 @@ static int tas2552_codec_probe(struct snd_soc_codec *codec)
                goto probe_fail;
        }
 
-       snd_soc_write(codec, TAS2552_CFG_1, TAS2552_MUTE_MASK |
-                               TAS2552_PLL_SRC_BCLK);
+       snd_soc_update_bits(codec, TAS2552_CFG_1, TAS2552_MUTE, TAS2552_MUTE);
        snd_soc_write(codec, TAS2552_CFG_3, TAS2552_I2S_OUT_SEL |
-                               TAS2552_DIN_SRC_SEL_AVG_L_R | TAS2552_88_96KHZ);
+                                           TAS2552_DIN_SRC_SEL_AVG_L_R);
        snd_soc_write(codec, TAS2552_DOUT, TAS2552_PDM_DATA_I);
        snd_soc_write(codec, TAS2552_OUTPUT_DATA, TAS2552_PDM_DATA_V_I | 0x8);
-       snd_soc_write(codec, TAS2552_PDM_CFG, TAS2552_PDM_BCLK_SEL);
        snd_soc_write(codec, TAS2552_BOOST_PT_CTRL, TAS2552_APT_DELAY_200 |
                                TAS2552_APT_THRESH_2_1_7);
 
-       ret = regmap_register_patch(tas2552->regmap, tas2552_init_regs,
-                                           ARRAY_SIZE(tas2552_init_regs));
-       if (ret != 0) {
-               dev_err(codec->dev, "Failed to write init registers: %d\n",
-                       ret);
-               goto patch_fail;
-       }
-
        snd_soc_write(codec, TAS2552_CFG_2, TAS2552_BOOST_EN |
                                  TAS2552_APT_EN | TAS2552_LIM_EN);
 
        return 0;
 
-patch_fail:
-       pm_runtime_put(codec->dev);
 probe_fail:
        if (tas2552->enable_gpio)
                gpiod_set_value(tas2552->enable_gpio, 0);
@@ -454,6 +614,8 @@ static struct snd_soc_codec_driver soc_codec_dev_tas2552 = {
        .remove = tas2552_codec_remove,
        .suspend =      tas2552_suspend,
        .resume = tas2552_resume,
+       .ignore_pmdown_time = true,
+
        .controls = tas2552_snd_controls,
        .num_controls = ARRAY_SIZE(tas2552_snd_controls),
        .dapm_widgets = tas2552_dapm_widgets,
@@ -486,8 +648,12 @@ static int tas2552_probe(struct i2c_client *client,
                return -ENOMEM;
 
        data->enable_gpio = devm_gpiod_get(dev, "enable", GPIOD_OUT_LOW);
-       if (IS_ERR(data->enable_gpio))
-               return PTR_ERR(data->enable_gpio);
+       if (IS_ERR(data->enable_gpio)) {
+               if (PTR_ERR(data->enable_gpio) == -EPROBE_DEFER)
+                       return -EPROBE_DEFER;
+
+               data->enable_gpio = NULL;;
+       }
 
        data->tas2552_client = client;
        data->regmap = devm_regmap_init_i2c(client, &tas2552_regmap_config);
index 6cea8f31bf8862a3672f8886332ba840b7490eea..bbb820495516a4d57a01f240e8ffb63ab50e5338 100644 (file)
 #define TAS2552_MAX_REG                        0x20
 
 /* CFG1 Register Masks */
-#define TAS2552_MUTE_MASK              (1 << 2)
-#define TAS2552_SWS_MASK               (1 << 1)
-#define TAS2552_WCLK_MASK              0x07
-#define TAS2552_CLASSD_EN_MASK (1 << 7)
+#define TAS2552_DEV_RESET              (1 << 0)
+#define TAS2552_SWS                    (1 << 1)
+#define TAS2552_MUTE                   (1 << 2)
+#define TAS2552_PLL_SRC_MCLK           (0x0 << 4)
+#define TAS2552_PLL_SRC_BCLK           (0x1 << 4)
+#define TAS2552_PLL_SRC_IVCLKIN                (0x2 << 4)
+#define TAS2552_PLL_SRC_1_8_FIXED      (0x3 << 4)
+#define TAS2552_PLL_SRC_MASK           TAS2552_PLL_SRC_1_8_FIXED
 
 /* CFG2 Register Masks */
 #define TAS2552_CLASSD_EN              (1 << 7)
 #define TAS2552_IVSENSE_EN             (1 << 1)
 
 /* CFG3 Register Masks */
-#define TAS2552_WORD_CLK_MASK          (1 << 7)
-#define TAS2552_BIT_CLK_MASK           (1 << 6)
-#define TAS2552_DATA_FORMAT_MASK       (0x11 << 2)
-
-#define TAS2552_DAIFMT_I2S_MASK                0xf3
-#define TAS2552_DAIFMT_DSP                     (1 << 3)
-#define TAS2552_DAIFMT_RIGHT_J         (1 << 4)
-#define TAS2552_DAIFMT_LEFT_J          (0x11 << 3)
-
-#define TAS2552_PLL_SRC_MCLK   0x00
-#define TAS2552_PLL_SRC_BCLK   (1 << 3)
-#define TAS2552_PLL_SRC_IVCLKIN        (1 << 4)
-#define TAS2552_PLL_SRC_1_8_FIXED (0x11 << 3)
-
-#define TAS2552_DIN_SRC_SEL_MUTED      0x00
-#define TAS2552_DIN_SRC_SEL_LEFT       (1 << 4)
-#define TAS2552_DIN_SRC_SEL_RIGHT      (1 << 5)
-#define TAS2552_DIN_SRC_SEL_AVG_L_R    (0x11 << 4)
-
+#define TAS2552_WCLK_FREQ_8KHZ         (0x0 << 0)
+#define TAS2552_WCLK_FREQ_11_12KHZ     (0x1 << 0)
+#define TAS2552_WCLK_FREQ_16KHZ                (0x2 << 0)
+#define TAS2552_WCLK_FREQ_22_24KHZ     (0x3 << 0)
+#define TAS2552_WCLK_FREQ_32KHZ                (0x4 << 0)
+#define TAS2552_WCLK_FREQ_44_48KHZ     (0x5 << 0)
+#define TAS2552_WCLK_FREQ_88_96KHZ     (0x6 << 0)
+#define TAS2552_WCLK_FREQ_176_192KHZ   (0x7 << 0)
+#define TAS2552_WCLK_FREQ_MASK         TAS2552_WCLK_FREQ_176_192KHZ
+#define TAS2552_DIN_SRC_SEL_MUTED      (0x0 << 3)
+#define TAS2552_DIN_SRC_SEL_LEFT       (0x1 << 3)
+#define TAS2552_DIN_SRC_SEL_RIGHT      (0x2 << 3)
+#define TAS2552_DIN_SRC_SEL_AVG_L_R    (0x3 << 3)
 #define TAS2552_PDM_IN_SEL             (1 << 5)
 #define TAS2552_I2S_OUT_SEL            (1 << 6)
-#define TAS2552_ANALOG_IN_SEL  (1 << 7)
-
-/* CFG3 WCLK Dividers */
-#define TAS2552_8KHZ           0x00
-#define TAS2552_11_12KHZ       (1 << 1)
-#define TAS2552_16KHZ          (1 << 2)
-#define TAS2552_22_24KHZ       (1 << 3)
-#define TAS2552_32KHZ          (1 << 4)
-#define TAS2552_44_48KHZ       (1 << 5)
-#define TAS2552_88_96KHZ       (1 << 6)
-#define TAS2552_176_192KHZ     (1 << 7)
+#define TAS2552_ANALOG_IN_SEL          (1 << 7)
+
+/* DOUT Register Masks */
+#define TAS2552_SDOUT_TRISTATE         (1 << 2)
+
+/* Serial Interface Control Register Masks */
+#define TAS2552_WORDLENGTH_16BIT       (0x0 << 0)
+#define TAS2552_WORDLENGTH_20BIT       (0x1 << 0)
+#define TAS2552_WORDLENGTH_24BIT       (0x2 << 0)
+#define TAS2552_WORDLENGTH_32BIT       (0x3 << 0)
+#define TAS2552_WORDLENGTH_MASK                TAS2552_WORDLENGTH_32BIT
+#define TAS2552_DATAFORMAT_I2S         (0x0 << 2)
+#define TAS2552_DATAFORMAT_DSP         (0x1 << 2)
+#define TAS2552_DATAFORMAT_RIGHT_J     (0x2 << 2)
+#define TAS2552_DATAFORMAT_LEFT_J      (0x3 << 2)
+#define TAS2552_DATAFORMAT_MASK                TAS2552_DATAFORMAT_LEFT_J
+#define TAS2552_CLKSPERFRAME_32                (0x0 << 4)
+#define TAS2552_CLKSPERFRAME_64                (0x1 << 4)
+#define TAS2552_CLKSPERFRAME_128       (0x2 << 4)
+#define TAS2552_CLKSPERFRAME_256       (0x3 << 4)
+#define TAS2552_CLKSPERFRAME_MASK      TAS2552_CLKSPERFRAME_256
+#define TAS2552_BCLKDIR                        (1 << 6)
+#define TAS2552_WCLKDIR                        (1 << 7)
 
 /* OUTPUT_DATA register */
 #define TAS2552_PDM_DATA_I             0x00
 #define TAS2552_PDM_DATA_V_I   (0x11 << 6)
 
 /* PDM CFG Register */
-#define TAS2552_PDM_DATA_ES_RISE 0x4
-
-#define TAS2552_PDM_PLL_CLK_SEL 0x00
-#define TAS2552_PDM_IV_CLK_SEL (1 << 1)
-#define TAS2552_PDM_BCLK_SEL   (1 << 2)
-#define TAS2552_PDM_MCLK_SEL   (1 << 3)
+#define TAS2552_PDM_CLK_SEL_PLL                (0x0 << 0)
+#define TAS2552_PDM_CLK_SEL_IVCLKIN    (0x1 << 0)
+#define TAS2552_PDM_CLK_SEL_BCLK       (0x2 << 0)
+#define TAS2552_PDM_CLK_SEL_MCLK       (0x3 << 0)
+#define TAS2552_PDM_CLK_SEL_MASK       TAS2552_PDM_CLK_SEL_MCLK
+#define TAS2552_PDM_DATA_ES            (1 << 2)
 
 /* Boost pass-through register */
 #define TAS2552_APT_DELAY_50   0x00
diff --git a/sound/soc/codecs/tas571x.c b/sound/soc/codecs/tas571x.c
new file mode 100644 (file)
index 0000000..85bcc37
--- /dev/null
@@ -0,0 +1,514 @@
+/*
+ * TAS571x amplifier audio driver
+ *
+ * Copyright (C) 2015 Google, Inc.
+ * Copyright (c) 2013 Daniel Mack <zonque@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/gpio/consumer.h>
+#include <linux/i2c.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/of_device.h>
+#include <linux/regmap.h>
+#include <linux/regulator/consumer.h>
+#include <linux/stddef.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/tlv.h>
+
+#include "tas571x.h"
+
+#define TAS571X_MAX_SUPPLIES           6
+
+struct tas571x_chip {
+       const char                      *const *supply_names;
+       int                             num_supply_names;
+       const struct snd_kcontrol_new   *controls;
+       int                             num_controls;
+       const struct regmap_config      *regmap_config;
+       int                             vol_reg_size;
+};
+
+struct tas571x_private {
+       const struct tas571x_chip       *chip;
+       struct regmap                   *regmap;
+       struct regulator_bulk_data      supplies[TAS571X_MAX_SUPPLIES];
+       struct clk                      *mclk;
+       unsigned int                    format;
+       struct gpio_desc                *reset_gpio;
+       struct gpio_desc                *pdn_gpio;
+       struct snd_soc_codec_driver     codec_driver;
+};
+
+static int tas571x_register_size(struct tas571x_private *priv, unsigned int reg)
+{
+       switch (reg) {
+       case TAS571X_MVOL_REG:
+       case TAS571X_CH1_VOL_REG:
+       case TAS571X_CH2_VOL_REG:
+               return priv->chip->vol_reg_size;
+       default:
+               return 1;
+       }
+}
+
+static int tas571x_reg_write(void *context, unsigned int reg,
+                            unsigned int value)
+{
+       struct i2c_client *client = context;
+       struct tas571x_private *priv = i2c_get_clientdata(client);
+       unsigned int i, size;
+       uint8_t buf[5];
+       int ret;
+
+       size = tas571x_register_size(priv, reg);
+       buf[0] = reg;
+
+       for (i = size; i >= 1; --i) {
+               buf[i] = value;
+               value >>= 8;
+       }
+
+       ret = i2c_master_send(client, buf, size + 1);
+       if (ret == size + 1)
+               return 0;
+       else if (ret < 0)
+               return ret;
+       else
+               return -EIO;
+}
+
+static int tas571x_reg_read(void *context, unsigned int reg,
+                           unsigned int *value)
+{
+       struct i2c_client *client = context;
+       struct tas571x_private *priv = i2c_get_clientdata(client);
+       uint8_t send_buf, recv_buf[4];
+       struct i2c_msg msgs[2];
+       unsigned int size;
+       unsigned int i;
+       int ret;
+
+       size = tas571x_register_size(priv, reg);
+       send_buf = reg;
+
+       msgs[0].addr = client->addr;
+       msgs[0].len = sizeof(send_buf);
+       msgs[0].buf = &send_buf;
+       msgs[0].flags = 0;
+
+       msgs[1].addr = client->addr;
+       msgs[1].len = size;
+       msgs[1].buf = recv_buf;
+       msgs[1].flags = I2C_M_RD;
+
+       ret = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs));
+       if (ret < 0)
+               return ret;
+       else if (ret != ARRAY_SIZE(msgs))
+               return -EIO;
+
+       *value = 0;
+
+       for (i = 0; i < size; i++) {
+               *value <<= 8;
+               *value |= recv_buf[i];
+       }
+
+       return 0;
+}
+
+static int tas571x_set_dai_fmt(struct snd_soc_dai *dai, unsigned int format)
+{
+       struct tas571x_private *priv = snd_soc_codec_get_drvdata(dai->codec);
+
+       priv->format = format;
+
+       return 0;
+}
+
+static int tas571x_hw_params(struct snd_pcm_substream *substream,
+                            struct snd_pcm_hw_params *params,
+                            struct snd_soc_dai *dai)
+{
+       struct tas571x_private *priv = snd_soc_codec_get_drvdata(dai->codec);
+       u32 val;
+
+       switch (priv->format & SND_SOC_DAIFMT_FORMAT_MASK) {
+       case SND_SOC_DAIFMT_RIGHT_J:
+               val = 0x00;
+               break;
+       case SND_SOC_DAIFMT_I2S:
+               val = 0x03;
+               break;
+       case SND_SOC_DAIFMT_LEFT_J:
+               val = 0x06;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       if (params_width(params) >= 24)
+               val += 2;
+       else if (params_width(params) >= 20)
+               val += 1;
+
+       return regmap_update_bits(priv->regmap, TAS571X_SDI_REG,
+                                 TAS571X_SDI_FMT_MASK, val);
+}
+
+static int tas571x_set_bias_level(struct snd_soc_codec *codec,
+                                 enum snd_soc_bias_level level)
+{
+       struct tas571x_private *priv = snd_soc_codec_get_drvdata(codec);
+       int ret;
+
+       switch (level) {
+       case SND_SOC_BIAS_ON:
+               break;
+       case SND_SOC_BIAS_PREPARE:
+               break;
+       case SND_SOC_BIAS_STANDBY:
+               if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) {
+                       if (!IS_ERR(priv->mclk)) {
+                               ret = clk_prepare_enable(priv->mclk);
+                               if (ret) {
+                                       dev_err(codec->dev,
+                                               "Failed to enable master clock: %d\n",
+                                               ret);
+                                       return ret;
+                               }
+                       }
+
+                       gpiod_set_value(priv->pdn_gpio, 0);
+                       usleep_range(5000, 6000);
+
+                       regcache_cache_only(priv->regmap, false);
+                       ret = regcache_sync(priv->regmap);
+                       if (ret)
+                               return ret;
+               }
+               break;
+       case SND_SOC_BIAS_OFF:
+               regcache_cache_only(priv->regmap, true);
+               gpiod_set_value(priv->pdn_gpio, 1);
+
+               if (!IS_ERR(priv->mclk))
+                       clk_disable_unprepare(priv->mclk);
+               break;
+       }
+
+       return 0;
+}
+
+static const struct snd_soc_dai_ops tas571x_dai_ops = {
+       .set_fmt        = tas571x_set_dai_fmt,
+       .hw_params      = tas571x_hw_params,
+};
+
+static const char *const tas5711_supply_names[] = {
+       "AVDD",
+       "DVDD",
+       "PVDD_A",
+       "PVDD_B",
+       "PVDD_C",
+       "PVDD_D",
+};
+
+static const DECLARE_TLV_DB_SCALE(tas5711_volume_tlv, -10350, 50, 1);
+
+static const struct snd_kcontrol_new tas5711_controls[] = {
+       SOC_SINGLE_TLV("Master Volume",
+                      TAS571X_MVOL_REG,
+                      0, 0xff, 1, tas5711_volume_tlv),
+       SOC_DOUBLE_R_TLV("Speaker Volume",
+                        TAS571X_CH1_VOL_REG,
+                        TAS571X_CH2_VOL_REG,
+                        0, 0xff, 1, tas5711_volume_tlv),
+       SOC_DOUBLE("Speaker Switch",
+                  TAS571X_SOFT_MUTE_REG,
+                  TAS571X_SOFT_MUTE_CH1_SHIFT, TAS571X_SOFT_MUTE_CH2_SHIFT,
+                  1, 1),
+};
+
+static const struct reg_default tas5711_reg_defaults[] = {
+       { 0x04, 0x05 },
+       { 0x05, 0x40 },
+       { 0x06, 0x00 },
+       { 0x07, 0xff },
+       { 0x08, 0x30 },
+       { 0x09, 0x30 },
+       { 0x1b, 0x82 },
+};
+
+static const struct regmap_config tas5711_regmap_config = {
+       .reg_bits                       = 8,
+       .val_bits                       = 32,
+       .max_register                   = 0xff,
+       .reg_read                       = tas571x_reg_read,
+       .reg_write                      = tas571x_reg_write,
+       .reg_defaults                   = tas5711_reg_defaults,
+       .num_reg_defaults               = ARRAY_SIZE(tas5711_reg_defaults),
+       .cache_type                     = REGCACHE_RBTREE,
+};
+
+static const struct tas571x_chip tas5711_chip = {
+       .supply_names                   = tas5711_supply_names,
+       .num_supply_names               = ARRAY_SIZE(tas5711_supply_names),
+       .controls                       = tas5711_controls,
+       .num_controls                   = ARRAY_SIZE(tas5711_controls),
+       .regmap_config                  = &tas5711_regmap_config,
+       .vol_reg_size                   = 1,
+};
+
+static const char *const tas5717_supply_names[] = {
+       "AVDD",
+       "DVDD",
+       "HPVDD",
+       "PVDD_AB",
+       "PVDD_CD",
+};
+
+static const DECLARE_TLV_DB_SCALE(tas5717_volume_tlv, -10375, 25, 0);
+
+static const struct snd_kcontrol_new tas5717_controls[] = {
+       /* MVOL LSB is ignored - see comments in tas571x_i2c_probe() */
+       SOC_SINGLE_TLV("Master Volume",
+                      TAS571X_MVOL_REG, 1, 0x1ff, 1,
+                      tas5717_volume_tlv),
+       SOC_DOUBLE_R_TLV("Speaker Volume",
+                        TAS571X_CH1_VOL_REG, TAS571X_CH2_VOL_REG,
+                        1, 0x1ff, 1, tas5717_volume_tlv),
+       SOC_DOUBLE("Speaker Switch",
+                  TAS571X_SOFT_MUTE_REG,
+                  TAS571X_SOFT_MUTE_CH1_SHIFT, TAS571X_SOFT_MUTE_CH2_SHIFT,
+                  1, 1),
+};
+
+static const struct reg_default tas5717_reg_defaults[] = {
+       { 0x04, 0x05 },
+       { 0x05, 0x40 },
+       { 0x06, 0x00 },
+       { 0x07, 0x03ff },
+       { 0x08, 0x00c0 },
+       { 0x09, 0x00c0 },
+       { 0x1b, 0x82 },
+};
+
+static const struct regmap_config tas5717_regmap_config = {
+       .reg_bits                       = 8,
+       .val_bits                       = 32,
+       .max_register                   = 0xff,
+       .reg_read                       = tas571x_reg_read,
+       .reg_write                      = tas571x_reg_write,
+       .reg_defaults                   = tas5717_reg_defaults,
+       .num_reg_defaults               = ARRAY_SIZE(tas5717_reg_defaults),
+       .cache_type                     = REGCACHE_RBTREE,
+};
+
+/* This entry is reused for tas5719 as the software interface is identical. */
+static const struct tas571x_chip tas5717_chip = {
+       .supply_names                   = tas5717_supply_names,
+       .num_supply_names               = ARRAY_SIZE(tas5717_supply_names),
+       .controls                       = tas5717_controls,
+       .num_controls                   = ARRAY_SIZE(tas5717_controls),
+       .regmap_config                  = &tas5717_regmap_config,
+       .vol_reg_size                   = 2,
+};
+
+static const struct snd_soc_dapm_widget tas571x_dapm_widgets[] = {
+       SND_SOC_DAPM_DAC("DACL", NULL, SND_SOC_NOPM, 0, 0),
+       SND_SOC_DAPM_DAC("DACR", NULL, SND_SOC_NOPM, 0, 0),
+
+       SND_SOC_DAPM_OUTPUT("OUT_A"),
+       SND_SOC_DAPM_OUTPUT("OUT_B"),
+       SND_SOC_DAPM_OUTPUT("OUT_C"),
+       SND_SOC_DAPM_OUTPUT("OUT_D"),
+};
+
+static const struct snd_soc_dapm_route tas571x_dapm_routes[] = {
+       { "DACL",  NULL, "Playback" },
+       { "DACR",  NULL, "Playback" },
+
+       { "OUT_A", NULL, "DACL" },
+       { "OUT_B", NULL, "DACL" },
+       { "OUT_C", NULL, "DACR" },
+       { "OUT_D", NULL, "DACR" },
+};
+
+static const struct snd_soc_codec_driver tas571x_codec = {
+       .set_bias_level = tas571x_set_bias_level,
+       .idle_bias_off = true,
+
+       .dapm_widgets = tas571x_dapm_widgets,
+       .num_dapm_widgets = ARRAY_SIZE(tas571x_dapm_widgets),
+       .dapm_routes = tas571x_dapm_routes,
+       .num_dapm_routes = ARRAY_SIZE(tas571x_dapm_routes),
+};
+
+static struct snd_soc_dai_driver tas571x_dai = {
+       .name = "tas571x-hifi",
+       .playback = {
+               .stream_name = "Playback",
+               .channels_min = 2,
+               .channels_max = 2,
+               .rates = SNDRV_PCM_RATE_8000_48000,
+               .formats = SNDRV_PCM_FMTBIT_S32_LE |
+                          SNDRV_PCM_FMTBIT_S24_LE |
+                          SNDRV_PCM_FMTBIT_S16_LE,
+       },
+       .ops = &tas571x_dai_ops,
+};
+
+static const struct of_device_id tas571x_of_match[];
+
+static int tas571x_i2c_probe(struct i2c_client *client,
+                            const struct i2c_device_id *id)
+{
+       struct tas571x_private *priv;
+       struct device *dev = &client->dev;
+       const struct of_device_id *of_id;
+       int i, ret;
+
+       priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
+       if (!priv)
+               return -ENOMEM;
+       i2c_set_clientdata(client, priv);
+
+       of_id = of_match_device(tas571x_of_match, dev);
+       if (!of_id) {
+               dev_err(dev, "Unknown device type\n");
+               return -EINVAL;
+       }
+       priv->chip = of_id->data;
+
+       priv->mclk = devm_clk_get(dev, "mclk");
+       if (IS_ERR(priv->mclk) && PTR_ERR(priv->mclk) != -ENOENT) {
+               dev_err(dev, "Failed to request mclk: %ld\n",
+                       PTR_ERR(priv->mclk));
+               return PTR_ERR(priv->mclk);
+       }
+
+       BUG_ON(priv->chip->num_supply_names > TAS571X_MAX_SUPPLIES);
+       for (i = 0; i < priv->chip->num_supply_names; i++)
+               priv->supplies[i].supply = priv->chip->supply_names[i];
+
+       ret = devm_regulator_bulk_get(dev, priv->chip->num_supply_names,
+                                     priv->supplies);
+       if (ret) {
+               dev_err(dev, "Failed to get supplies: %d\n", ret);
+               return ret;
+       }
+       ret = regulator_bulk_enable(priv->chip->num_supply_names,
+                                   priv->supplies);
+       if (ret) {
+               dev_err(dev, "Failed to enable supplies: %d\n", ret);
+               return ret;
+       }
+
+       priv->regmap = devm_regmap_init(dev, NULL, client,
+                                       priv->chip->regmap_config);
+       if (IS_ERR(priv->regmap))
+               return PTR_ERR(priv->regmap);
+
+       priv->pdn_gpio = devm_gpiod_get_optional(dev, "pdn", GPIOD_OUT_LOW);
+       if (IS_ERR(priv->pdn_gpio)) {
+               dev_err(dev, "error requesting pdn_gpio: %ld\n",
+                       PTR_ERR(priv->pdn_gpio));
+               return PTR_ERR(priv->pdn_gpio);
+       }
+
+       priv->reset_gpio = devm_gpiod_get_optional(dev, "reset",
+                                                  GPIOD_OUT_HIGH);
+       if (IS_ERR(priv->reset_gpio)) {
+               dev_err(dev, "error requesting reset_gpio: %ld\n",
+                       PTR_ERR(priv->reset_gpio));
+               return PTR_ERR(priv->reset_gpio);
+       } else if (priv->reset_gpio) {
+               /* pulse the active low reset line for ~100us */
+               usleep_range(100, 200);
+               gpiod_set_value(priv->reset_gpio, 0);
+               usleep_range(12000, 20000);
+       }
+
+       ret = regmap_write(priv->regmap, TAS571X_OSC_TRIM_REG, 0);
+       if (ret)
+               return ret;
+
+       ret = regmap_update_bits(priv->regmap, TAS571X_SYS_CTRL_2_REG,
+                                TAS571X_SYS_CTRL_2_SDN_MASK, 0);
+       if (ret)
+               return ret;
+
+       memcpy(&priv->codec_driver, &tas571x_codec, sizeof(priv->codec_driver));
+       priv->codec_driver.controls = priv->chip->controls;
+       priv->codec_driver.num_controls = priv->chip->num_controls;
+
+       if (priv->chip->vol_reg_size == 2) {
+               /*
+                * The master volume defaults to 0x3ff (mute), but we ignore
+                * (zero) the LSB because the hardware step size is 0.125 dB
+                * and TLV_DB_SCALE_ITEM has a resolution of 0.01 dB.
+                */
+               ret = regmap_update_bits(priv->regmap, TAS571X_MVOL_REG, 1, 0);
+               if (ret)
+                       return ret;
+       }
+
+       regcache_cache_only(priv->regmap, true);
+       gpiod_set_value(priv->pdn_gpio, 1);
+
+       return snd_soc_register_codec(&client->dev, &priv->codec_driver,
+                                     &tas571x_dai, 1);
+}
+
+static int tas571x_i2c_remove(struct i2c_client *client)
+{
+       struct tas571x_private *priv = i2c_get_clientdata(client);
+
+       snd_soc_unregister_codec(&client->dev);
+       regulator_bulk_disable(priv->chip->num_supply_names, priv->supplies);
+
+       return 0;
+}
+
+static const struct of_device_id tas571x_of_match[] = {
+       { .compatible = "ti,tas5711", .data = &tas5711_chip, },
+       { .compatible = "ti,tas5717", .data = &tas5717_chip, },
+       { .compatible = "ti,tas5719", .data = &tas5717_chip, },
+       { }
+};
+MODULE_DEVICE_TABLE(of, tas571x_of_match);
+
+static const struct i2c_device_id tas571x_i2c_id[] = {
+       { "tas5711", 0 },
+       { "tas5717", 0 },
+       { "tas5719", 0 },
+       { }
+};
+MODULE_DEVICE_TABLE(i2c, tas571x_i2c_id);
+
+static struct i2c_driver tas571x_i2c_driver = {
+       .driver = {
+               .name = "tas571x",
+               .of_match_table = of_match_ptr(tas571x_of_match),
+       },
+       .probe = tas571x_i2c_probe,
+       .remove = tas571x_i2c_remove,
+       .id_table = tas571x_i2c_id,
+};
+module_i2c_driver(tas571x_i2c_driver);
+
+MODULE_DESCRIPTION("ASoC TAS571x driver");
+MODULE_AUTHOR("Kevin Cernekee <cernekee@chromium.org>");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/tas571x.h b/sound/soc/codecs/tas571x.h
new file mode 100644 (file)
index 0000000..0aee471
--- /dev/null
@@ -0,0 +1,33 @@
+/*
+ * TAS571x amplifier audio driver
+ *
+ * Copyright (C) 2015 Google, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#ifndef _TAS571X_H
+#define _TAS571X_H
+
+/* device registers */
+#define TAS571X_SDI_REG                        0x04
+#define TAS571X_SDI_FMT_MASK           0x0f
+
+#define TAS571X_SYS_CTRL_2_REG         0x05
+#define TAS571X_SYS_CTRL_2_SDN_MASK    0x40
+
+#define TAS571X_SOFT_MUTE_REG          0x06
+#define TAS571X_SOFT_MUTE_CH1_SHIFT    0
+#define TAS571X_SOFT_MUTE_CH2_SHIFT    1
+#define TAS571X_SOFT_MUTE_CH3_SHIFT    2
+
+#define TAS571X_MVOL_REG               0x07
+#define TAS571X_CH1_VOL_REG            0x08
+#define TAS571X_CH2_VOL_REG            0x09
+
+#define TAS571X_OSC_TRIM_REG           0x1b
+
+#endif /* _TAS571X_H */
index 16f1b71edb554aac82cb74093cbf6a80b84f5d0b..aab0af681e8cb3cd1b2c0ea0b5a22e32c1f08c2b 100644 (file)
@@ -280,8 +280,8 @@ static int tfa9879_i2c_probe(struct i2c_client *i2c,
        int i;
 
        tfa9879 = devm_kzalloc(&i2c->dev, sizeof(*tfa9879), GFP_KERNEL);
-       if (IS_ERR(tfa9879))
-               return PTR_ERR(tfa9879);
+       if (!tfa9879)
+               return -ENOMEM;
 
        i2c_set_clientdata(i2c, tfa9879);
 
index cc17e7e5126e0750d46c933a8e96bc52c42a07df..cd8c02b6e4de471ceb7b3d33b8687fb98310b8ea 100644 (file)
@@ -506,7 +506,6 @@ static int tlv320aic23_set_bias_level(struct snd_soc_codec *codec,
                snd_soc_write(codec, TLV320AIC23_PWR, 0x1ff);
                break;
        }
-       codec->dapm.bias_level = level;
        return 0;
 }
 
index c86dd9aae1576670925b0ae1ce4b7959e5f199e4..c4c960f592a1fb092d43d1610d52316bb0422c97 100644 (file)
@@ -646,7 +646,7 @@ static int aic31xx_add_controls(struct snd_soc_codec *codec)
 
 static int aic31xx_add_widgets(struct snd_soc_codec *codec)
 {
-       struct snd_soc_dapm_context *dapm = &codec->dapm;
+       struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
        struct aic31xx_priv *aic31xx = snd_soc_codec_get_drvdata(codec);
        int ret = 0;
 
@@ -1027,17 +1027,17 @@ static int aic31xx_set_bias_level(struct snd_soc_codec *codec,
                                  enum snd_soc_bias_level level)
 {
        dev_dbg(codec->dev, "## %s: %d -> %d\n", __func__,
-               codec->dapm.bias_level, level);
+               snd_soc_codec_get_bias_level(codec), level);
 
        switch (level) {
        case SND_SOC_BIAS_ON:
                break;
        case SND_SOC_BIAS_PREPARE:
-               if (codec->dapm.bias_level == SND_SOC_BIAS_STANDBY)
+               if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_STANDBY)
                        aic31xx_clk_on(codec);
                break;
        case SND_SOC_BIAS_STANDBY:
-               switch (codec->dapm.bias_level) {
+               switch (snd_soc_codec_get_bias_level(codec)) {
                case SND_SOC_BIAS_OFF:
                        aic31xx_power_on(codec);
                        break;
@@ -1049,11 +1049,10 @@ static int aic31xx_set_bias_level(struct snd_soc_codec *codec,
                }
                break;
        case SND_SOC_BIAS_OFF:
-               if (codec->dapm.bias_level == SND_SOC_BIAS_STANDBY)
+               if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_STANDBY)
                        aic31xx_power_off(codec);
                break;
        }
-       codec->dapm.bias_level = level;
 
        return 0;
 }
index 015467ed606bc895ef9ce074f437453e498bfaef..ad6cb90e5f9b3fcc6edef66bfe295f9d8631a82e 100644 (file)
@@ -564,7 +564,6 @@ static int aic32x4_set_bias_level(struct snd_soc_codec *codec,
        case SND_SOC_BIAS_OFF:
                break;
        }
-       codec->dapm.bias_level = level;
        return 0;
 }
 
index 51c4713ac6e39059efbb6d296be7ee3527435649..a7cf19b53fb2d44d3cdefc6ef15f058b3da44bf5 100644 (file)
@@ -147,6 +147,7 @@ static int snd_soc_dapm_put_volsw_aic3x(struct snd_kcontrol *kcontrol,
                                        struct snd_ctl_elem_value *ucontrol)
 {
        struct snd_soc_codec *codec = snd_soc_dapm_kcontrol_codec(kcontrol);
+       struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
        struct soc_mixer_control *mc =
                (struct soc_mixer_control *)kcontrol->private_value;
        unsigned int reg = mc->reg;
@@ -179,7 +180,7 @@ static int snd_soc_dapm_put_volsw_aic3x(struct snd_kcontrol *kcontrol,
                update.mask = mask;
                update.val = val;
 
-               snd_soc_dapm_mixer_update_power(&codec->dapm, kcontrol, connect,
+               snd_soc_dapm_mixer_update_power(dapm, kcontrol, connect,
                        &update);
        }
 
@@ -979,7 +980,7 @@ static const struct snd_soc_dapm_route intercon_3007[] = {
 static int aic3x_add_widgets(struct snd_soc_codec *codec)
 {
        struct aic3x_priv *aic3x = snd_soc_codec_get_drvdata(codec);
-       struct snd_soc_dapm_context *dapm = &codec->dapm;
+       struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
 
        switch (aic3x->model) {
        case AIC3X_MODEL_3X:
@@ -1384,7 +1385,7 @@ static int aic3x_set_bias_level(struct snd_soc_codec *codec,
        case SND_SOC_BIAS_ON:
                break;
        case SND_SOC_BIAS_PREPARE:
-               if (codec->dapm.bias_level == SND_SOC_BIAS_STANDBY &&
+               if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_STANDBY &&
                    aic3x->master) {
                        /* enable pll */
                        snd_soc_update_bits(codec, AIC3X_PLL_PROGA_REG,
@@ -1394,7 +1395,7 @@ static int aic3x_set_bias_level(struct snd_soc_codec *codec,
        case SND_SOC_BIAS_STANDBY:
                if (!aic3x->power)
                        aic3x_set_power(codec, 1);
-               if (codec->dapm.bias_level == SND_SOC_BIAS_PREPARE &&
+               if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_PREPARE &&
                    aic3x->master) {
                        /* disable pll */
                        snd_soc_update_bits(codec, AIC3X_PLL_PROGA_REG,
@@ -1406,7 +1407,6 @@ static int aic3x_set_bias_level(struct snd_soc_codec *codec,
                        aic3x_set_power(codec, 0);
                break;
        }
-       codec->dapm.bias_level = level;
 
        return 0;
 }
index 4e3e607dec13085df4cbc4a3d198ae5cacf78c32..d67a311f0e75017ea27189f362e3dd00e63fa235 100644 (file)
@@ -633,7 +633,7 @@ static int dac33_set_bias_level(struct snd_soc_codec *codec,
        case SND_SOC_BIAS_PREPARE:
                break;
        case SND_SOC_BIAS_STANDBY:
-               if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) {
+               if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_OFF) {
                        /* Coming from OFF, switch on the codec */
                        ret = dac33_hard_power(codec, 1);
                        if (ret != 0)
@@ -644,14 +644,13 @@ static int dac33_set_bias_level(struct snd_soc_codec *codec,
                break;
        case SND_SOC_BIAS_OFF:
                /* Do not power off, when the codec is already off */
-               if (codec->dapm.bias_level == SND_SOC_BIAS_OFF)
+               if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_OFF)
                        return 0;
                ret = dac33_hard_power(codec, 0);
                if (ret != 0)
                        return ret;
                break;
        }
-       codec->dapm.bias_level = level;
 
        return 0;
 }
index 9fd80ac1897f5b369bc14a0420c0b834da748343..12232d7db4c527703646c9713a0471629aac3971 100644 (file)
@@ -254,12 +254,13 @@ static const struct regmap_config ts3a227e_regmap_config = {
        .num_reg_defaults = ARRAY_SIZE(ts3a227e_reg_defaults),
 };
 
-static int ts3a227e_parse_dt(struct ts3a227e *ts3a227e, struct device_node *np)
+static int ts3a227e_parse_device_property(struct ts3a227e *ts3a227e,
+                               struct device *dev)
 {
        u32 micbias;
        int err;
 
-       err = of_property_read_u32(np, "ti,micbias", &micbias);
+       err = device_property_read_u32(dev, "ti,micbias", &micbias);
        if (!err) {
                regmap_update_bits(ts3a227e->regmap, TS3A227E_REG_SETTING_3,
                        MICBIAS_SETTING_MASK,
@@ -287,12 +288,10 @@ static int ts3a227e_i2c_probe(struct i2c_client *i2c,
        if (IS_ERR(ts3a227e->regmap))
                return PTR_ERR(ts3a227e->regmap);
 
-       if (dev->of_node) {
-               ret = ts3a227e_parse_dt(ts3a227e, dev->of_node);
-               if (ret) {
-                       dev_err(dev, "Failed to parse device tree: %d\n", ret);
-                       return ret;
-               }
+       ret = ts3a227e_parse_device_property(ts3a227e, dev);
+       if (ret) {
+               dev_err(dev, "Failed to parse device property: %d\n", ret);
+               return ret;
        }
 
        ret = devm_request_threaded_irq(dev, i2c->irq, NULL, ts3a227e_interrupt,
index d04693e9cf9f8c9b362b212b04058e7fe6ee2278..90f5f04eca2d89903e16b5bdb9ff949c929f9ad2 100644 (file)
@@ -1588,14 +1588,13 @@ static int twl4030_set_bias_level(struct snd_soc_codec *codec,
        case SND_SOC_BIAS_PREPARE:
                break;
        case SND_SOC_BIAS_STANDBY:
-               if (codec->dapm.bias_level == SND_SOC_BIAS_OFF)
+               if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_OFF)
                        twl4030_codec_enable(codec, 1);
                break;
        case SND_SOC_BIAS_OFF:
                twl4030_codec_enable(codec, 0);
                break;
        }
-       codec->dapm.bias_level = level;
 
        return 0;
 }
index aeec27b6f1af76aca729aacd35e872b01eb05362..4cad8929d26221f952863ed52772abebcc03fca3 100644 (file)
@@ -533,7 +533,7 @@ static int twl6040_pll_put_enum(struct snd_kcontrol *kcontrol,
 
 int twl6040_get_dl1_gain(struct snd_soc_codec *codec)
 {
-       struct snd_soc_dapm_context *dapm = &codec->dapm;
+       struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
 
        if (snd_soc_dapm_get_pin_status(dapm, "EP"))
                return -1; /* -1dB */
@@ -853,8 +853,6 @@ static int twl6040_set_bias_level(struct snd_soc_codec *codec,
                break;
        }
 
-       codec->dapm.bias_level = level;
-
        return 0;
 }
 
@@ -1123,14 +1121,15 @@ static int twl6040_probe(struct snd_soc_codec *codec)
        mutex_init(&priv->mutex);
 
        ret = request_threaded_irq(priv->plug_irq, NULL,
-                                       twl6040_audio_handler, IRQF_NO_SUSPEND,
+                                       twl6040_audio_handler,
+                                       IRQF_NO_SUSPEND | IRQF_ONESHOT,
                                        "twl6040_irq_plug", codec);
        if (ret) {
                dev_err(codec->dev, "PLUG IRQ request failed: %d\n", ret);
                return ret;
        }
 
-       twl6040_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
+       snd_soc_codec_force_bias_level(codec, SND_SOC_BIAS_STANDBY);
        twl6040_init_chip(codec);
 
        return 0;
index f883308c00de20738235c536111202d08241f7f5..913edf2832399cb5d5cb36b3bb26bf9d8364e638 100644 (file)
@@ -350,7 +350,6 @@ static int uda134x_set_bias_level(struct snd_soc_codec *codec,
                        pd->power(0);
                break;
        }
-       codec->dapm.bias_level = level;
        return 0;
 }
 
@@ -478,6 +477,7 @@ static struct snd_soc_dai_driver uda134x_dai = {
 
 static int uda134x_soc_probe(struct snd_soc_codec *codec)
 {
+       struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
        struct uda134x_priv *uda134x;
        struct uda134x_platform_data *pd = codec->component.card->dev->platform_data;
        const struct snd_soc_dapm_widget *widgets;
@@ -526,7 +526,7 @@ static int uda134x_soc_probe(struct snd_soc_codec *codec)
                num_widgets = ARRAY_SIZE(uda1340_dapm_widgets);
        }
 
-       ret = snd_soc_dapm_new_controls(&codec->dapm, widgets, num_widgets);
+       ret = snd_soc_dapm_new_controls(dapm, widgets, num_widgets);
        if (ret) {
                printk(KERN_ERR "%s failed to register dapm controls: %d",
                        __func__, ret);
index dc7778b6dd7f6fa40b76b598e3441aa5c2c5d571..6e159f59d219beaba3ff75a0b4f7c7b5405d2b9b 100644 (file)
@@ -437,7 +437,7 @@ static int uda1380_set_dai_fmt_both(struct snd_soc_dai *codec_dai,
        if ((fmt & SND_SOC_DAIFMT_MASTER_MASK) != SND_SOC_DAIFMT_CBS_CFS)
                return -EINVAL;
 
-       uda1380_write(codec, UDA1380_IFACE, iface);
+       uda1380_write_reg_cache(codec, UDA1380_IFACE, iface);
 
        return 0;
 }
@@ -590,9 +590,6 @@ static int uda1380_set_bias_level(struct snd_soc_codec *codec,
        int reg;
        struct uda1380_platform_data *pdata = codec->dev->platform_data;
 
-       if (codec->dapm.bias_level == level)
-               return 0;
-
        switch (level) {
        case SND_SOC_BIAS_ON:
        case SND_SOC_BIAS_PREPARE:
@@ -600,7 +597,7 @@ static int uda1380_set_bias_level(struct snd_soc_codec *codec,
                uda1380_write(codec, UDA1380_PM, R02_PON_BIAS | pm);
                break;
        case SND_SOC_BIAS_STANDBY:
-               if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) {
+               if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_OFF) {
                        if (gpio_is_valid(pdata->gpio_power)) {
                                gpio_set_value(pdata->gpio_power, 1);
                                mdelay(1);
@@ -623,7 +620,6 @@ static int uda1380_set_bias_level(struct snd_soc_codec *codec,
                for (reg = UDA1380_MVOL; reg < UDA1380_CACHEREGNUM; reg++)
                        set_bit(reg - 0x10, &uda1380_cache_dirty);
        }
-       codec->dapm.bias_level = level;
        return 0;
 }
 
index f37989ec7cbaff9509c50f4b5a66b1c4e1fe1e85..6560a66b3f3539ea79cfd8d9ef20f3825d2e03df 100644 (file)
@@ -751,13 +751,13 @@ static int wm0010_set_bias_level(struct snd_soc_codec *codec,
 
        switch (level) {
        case SND_SOC_BIAS_ON:
-               if (codec->dapm.bias_level == SND_SOC_BIAS_PREPARE)
+               if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_PREPARE)
                        wm0010_boot(codec);
                break;
        case SND_SOC_BIAS_PREPARE:
                break;
        case SND_SOC_BIAS_STANDBY:
-               if (codec->dapm.bias_level == SND_SOC_BIAS_PREPARE) {
+               if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_PREPARE) {
                        mutex_lock(&wm0010->lock);
                        wm0010_halt(codec);
                        mutex_unlock(&wm0010->lock);
@@ -767,8 +767,6 @@ static int wm0010_set_bias_level(struct snd_soc_codec *codec,
                break;
        }
 
-       codec->dapm.bias_level = level;
-
        return 0;
 }
 
index 8011f75fb6cbd45b5328c9f238a61da1325b080b..048f00568260a82b82b544b09c4b24625aeb2f62 100644 (file)
@@ -61,8 +61,6 @@ static int wm1250_ev1_set_bias_level(struct snd_soc_codec *codec,
                break;
        }
 
-       codec->dapm.bias_level = level;
-
        return 0;
 }
 
index 96740379b711bf2d5816666772fabf92e85124d9..4c10cd88c1af66a1a54b168c34844c190e077b9d 100644 (file)
@@ -2101,7 +2101,7 @@ static void wm5100_micd_irq(struct wm5100_priv *wm5100)
 int wm5100_detect(struct snd_soc_codec *codec, struct snd_soc_jack *jack)
 {
        struct wm5100_priv *wm5100 = snd_soc_codec_get_drvdata(codec);
-       struct snd_soc_dapm_context *dapm = &codec->dapm;
+       struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
 
        if (jack) {
                wm5100->jack = jack;
@@ -2336,6 +2336,7 @@ static void wm5100_free_gpio(struct i2c_client *i2c)
 
 static int wm5100_probe(struct snd_soc_codec *codec)
 {
+       struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
        struct i2c_client *i2c = to_i2c_client(codec->dev);
        struct wm5100_priv *wm5100 = snd_soc_codec_get_drvdata(codec);
        int ret, i;
@@ -2353,8 +2354,7 @@ static int wm5100_probe(struct snd_soc_codec *codec)
        /* TODO: check if we're symmetric */
 
        if (i2c->irq)
-               snd_soc_dapm_new_controls(&codec->dapm,
-                                         wm5100_dapm_widgets_noirq,
+               snd_soc_dapm_new_controls(dapm, wm5100_dapm_widgets_noirq,
                                          ARRAY_SIZE(wm5100_dapm_widgets_noirq));
 
        if (wm5100->pdata.hp_pol) {
@@ -2570,11 +2570,13 @@ static int wm5100_i2c_probe(struct i2c_client *i2c,
 
                if (irq_flags & (IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING))
                        ret = request_threaded_irq(i2c->irq, NULL,
-                                                  wm5100_edge_irq, irq_flags,
+                                                  wm5100_edge_irq,
+                                                  irq_flags | IRQF_ONESHOT,
                                                   "wm5100", wm5100);
                else
                        ret = request_threaded_irq(i2c->irq, NULL, wm5100_irq,
-                                                  irq_flags, "wm5100",
+                                                  irq_flags | IRQF_ONESHOT,
+                                                  "wm5100",
                                                   wm5100);
 
                if (ret != 0) {
index 0c6d1bc0526eff324d180f0c3a7041ff3aa5fe00..c5ec519d34bef7c63c37374871207e2e350f17fb 100644 (file)
@@ -42,7 +42,7 @@ struct wm5102_priv {
 static DECLARE_TLV_DB_SCALE(ana_tlv, 0, 100, 0);
 static DECLARE_TLV_DB_SCALE(eq_tlv, -1200, 100, 0);
 static DECLARE_TLV_DB_SCALE(digital_tlv, -6400, 50, 0);
-static DECLARE_TLV_DB_SCALE(noise_tlv, 0, 600, 0);
+static DECLARE_TLV_DB_SCALE(noise_tlv, -13200, 600, 0);
 static DECLARE_TLV_DB_SCALE(ng_tlv, -10200, 600, 0);
 
 static const struct wm_adsp_region wm5102_dsp1_regions[] = {
@@ -605,12 +605,56 @@ static int wm5102_sysclk_ev(struct snd_soc_dapm_widget *w,
                                regmap_write_async(regmap, patch[i].reg,
                                                   patch[i].def);
                break;
+       case SND_SOC_DAPM_PRE_PMD:
+               break;
+       default:
+               return 0;
+       }
+
+       return arizona_dvfs_sysclk_ev(w, kcontrol, event);
+}
+
+static int wm5102_adsp_power_ev(struct snd_soc_dapm_widget *w,
+                  struct snd_kcontrol *kcontrol, int event)
+{
+       struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+       struct arizona *arizona = dev_get_drvdata(codec->dev->parent);
+       unsigned int v;
+       int ret;
+
+       switch (event) {
+       case SND_SOC_DAPM_PRE_PMU:
+               ret = regmap_read(arizona->regmap, ARIZONA_SYSTEM_CLOCK_1, &v);
+               if (ret != 0) {
+                       dev_err(codec->dev,
+                               "Failed to read SYSCLK state: %d\n", ret);
+                       return -EIO;
+               }
+
+               v = (v & ARIZONA_SYSCLK_FREQ_MASK) >> ARIZONA_SYSCLK_FREQ_SHIFT;
+
+               if (v >= 3) {
+                       ret = arizona_dvfs_up(codec, ARIZONA_DVFS_ADSP1_RQ);
+                       if (ret) {
+                               dev_err(codec->dev,
+                                       "Failed to raise DVFS: %d\n", ret);
+                               return ret;
+                       }
+               }
+               break;
+
+       case SND_SOC_DAPM_POST_PMD:
+               ret = arizona_dvfs_down(codec, ARIZONA_DVFS_ADSP1_RQ);
+               if (ret)
+                       dev_warn(codec->dev,
+                                "Failed to lower DVFS: %d\n", ret);
+               break;
 
        default:
                break;
        }
 
-       return 0;
+       return wm_adsp2_early_event(w, kcontrol, event);
 }
 
 static int wm5102_out_comp_coeff_get(struct snd_kcontrol *kcontrol,
@@ -1036,7 +1080,8 @@ static const struct snd_kcontrol_new wm5102_aec_loopback_mux =
 
 static const struct snd_soc_dapm_widget wm5102_dapm_widgets[] = {
 SND_SOC_DAPM_SUPPLY("SYSCLK", ARIZONA_SYSTEM_CLOCK_1, ARIZONA_SYSCLK_ENA_SHIFT,
-                   0, wm5102_sysclk_ev, SND_SOC_DAPM_POST_PMU),
+                   0, wm5102_sysclk_ev,
+                   SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
 SND_SOC_DAPM_SUPPLY("ASYNCCLK", ARIZONA_ASYNC_CLOCK_1,
                    ARIZONA_ASYNC_CLK_ENA_SHIFT, 0, NULL, 0),
 SND_SOC_DAPM_SUPPLY("OPCLK", ARIZONA_OUTPUT_SYSTEM_CLOCK,
@@ -1367,7 +1412,7 @@ ARIZONA_MUX_WIDGETS(ISRC2DEC2, "ISRC2DEC2"),
 ARIZONA_MUX_WIDGETS(ISRC2INT1, "ISRC2INT1"),
 ARIZONA_MUX_WIDGETS(ISRC2INT2, "ISRC2INT2"),
 
-WM_ADSP2("DSP1", 0),
+WM_ADSP2_E("DSP1", 0, wm5102_adsp_power_ev),
 
 SND_SOC_DAPM_OUTPUT("HPOUT1L"),
 SND_SOC_DAPM_OUTPUT("HPOUT1R"),
@@ -1827,19 +1872,20 @@ static struct snd_soc_dai_driver wm5102_dai[] = {
 
 static int wm5102_codec_probe(struct snd_soc_codec *codec)
 {
+       struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
        struct wm5102_priv *priv = snd_soc_codec_get_drvdata(codec);
        int ret;
 
-       ret = snd_soc_add_codec_controls(codec, wm_adsp2_fw_controls, 2);
-       if (ret != 0)
+       ret = wm_adsp2_codec_probe(&priv->core.adsp[0], codec);
+       if (ret)
                return ret;
 
        arizona_init_spk(codec);
        arizona_init_gpio(codec);
 
-       snd_soc_dapm_disable_pin(&codec->dapm, "HAPTICS");
+       snd_soc_dapm_disable_pin(dapm, "HAPTICS");
 
-       priv->core.arizona->dapm = &codec->dapm;
+       priv->core.arizona->dapm = dapm;
 
        return 0;
 }
@@ -1848,6 +1894,8 @@ static int wm5102_codec_remove(struct snd_soc_codec *codec)
 {
        struct wm5102_priv *priv = snd_soc_codec_get_drvdata(codec);
 
+       wm_adsp2_codec_remove(&priv->core.adsp[0], codec);
+
        priv->core.arizona->dapm = NULL;
 
        return 0;
@@ -1909,6 +1957,8 @@ static int wm5102_probe(struct platform_device *pdev)
        wm5102->core.arizona = arizona;
        wm5102->core.num_inputs = 6;
 
+       arizona_init_dvfs(&wm5102->core);
+
        wm5102->core.adsp[0].part = "wm5102";
        wm5102->core.adsp[0].num = 1;
        wm5102->core.adsp[0].type = WMFW_ADSP2;
@@ -1918,7 +1968,7 @@ static int wm5102_probe(struct platform_device *pdev)
        wm5102->core.adsp[0].mem = wm5102_dsp1_regions;
        wm5102->core.adsp[0].num_mems = ARRAY_SIZE(wm5102_dsp1_regions);
 
-       ret = wm_adsp2_init(&wm5102->core.adsp[0], true);
+       ret = wm_adsp2_init(&wm5102->core.adsp[0]);
        if (ret != 0)
                return ret;
 
index fbaeddb3e9033a3044b4995265dce2849b348160..5f032a37b61f38e08dbd311da7f2e8e481f558b0 100644 (file)
@@ -167,7 +167,7 @@ static int wm5110_sysclk_ev(struct snd_soc_dapm_widget *w,
 static DECLARE_TLV_DB_SCALE(ana_tlv, 0, 100, 0);
 static DECLARE_TLV_DB_SCALE(eq_tlv, -1200, 100, 0);
 static DECLARE_TLV_DB_SCALE(digital_tlv, -6400, 50, 0);
-static DECLARE_TLV_DB_SCALE(noise_tlv, 0, 600, 0);
+static DECLARE_TLV_DB_SCALE(noise_tlv, -13200, 600, 0);
 static DECLARE_TLV_DB_SCALE(ng_tlv, -10200, 600, 0);
 
 #define WM5110_NG_SRC(name, base) \
@@ -1598,22 +1598,23 @@ static struct snd_soc_dai_driver wm5110_dai[] = {
 
 static int wm5110_codec_probe(struct snd_soc_codec *codec)
 {
+       struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
        struct wm5110_priv *priv = snd_soc_codec_get_drvdata(codec);
-       int ret;
+       int i, ret;
 
-       priv->core.arizona->dapm = &codec->dapm;
+       priv->core.arizona->dapm = dapm;
 
        arizona_init_spk(codec);
        arizona_init_gpio(codec);
        arizona_init_mono(codec);
 
-       ret = snd_soc_add_codec_controls(codec, wm_adsp2_fw_controls, 8);
-       if (ret != 0)
-               return ret;
-
-       snd_soc_dapm_disable_pin(&codec->dapm, "HAPTICS");
+       for (i = 0; i < WM5110_NUM_ADSP; ++i) {
+               ret = wm_adsp2_codec_probe(&priv->core.adsp[i], codec);
+               if (ret)
+                       return ret;
+       }
 
-       priv->core.arizona->dapm = &codec->dapm;
+       snd_soc_dapm_disable_pin(dapm, "HAPTICS");
 
        return 0;
 }
@@ -1621,6 +1622,10 @@ static int wm5110_codec_probe(struct snd_soc_codec *codec)
 static int wm5110_codec_remove(struct snd_soc_codec *codec)
 {
        struct wm5110_priv *priv = snd_soc_codec_get_drvdata(codec);
+       int i;
+
+       for (i = 0; i < WM5110_NUM_ADSP; ++i)
+               wm_adsp2_codec_remove(&priv->core.adsp[i], codec);
 
        priv->core.arizona->dapm = NULL;
 
@@ -1697,7 +1702,7 @@ static int wm5110_probe(struct platform_device *pdev)
                wm5110->core.adsp[i].num_mems
                        = ARRAY_SIZE(wm5110_dsp1_regions);
 
-               ret = wm_adsp2_init(&wm5110->core.adsp[i], false);
+               ret = wm_adsp2_init(&wm5110->core.adsp[i]);
                if (ret != 0)
                        return ret;
        }
index c65e5a75fc1afd4e992cca9bda59db14ddba24f1..41c62c1e62db5dc5754512532e7a758025cce311 100644 (file)
@@ -1102,7 +1102,7 @@ static int wm8350_set_bias_level(struct snd_soc_codec *codec,
                break;
 
        case SND_SOC_BIAS_STANDBY:
-               if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) {
+               if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_OFF) {
                        ret = regulator_bulk_enable(ARRAY_SIZE(priv->supplies),
                                                    priv->supplies);
                        if (ret != 0)
@@ -1235,7 +1235,6 @@ static int wm8350_set_bias_level(struct snd_soc_codec *codec,
                                       priv->supplies);
                break;
        }
-       codec->dapm.bias_level = level;
        return 0;
 }
 
index b0d84e552fca758786100c5eca18b746013a1d61..d7555085e7f473bc568569de6a9c20e7061edf6d 100644 (file)
@@ -1145,7 +1145,7 @@ static int wm8400_set_bias_level(struct snd_soc_codec *codec,
                break;
 
        case SND_SOC_BIAS_STANDBY:
-               if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) {
+               if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_OFF) {
                        ret = regulator_bulk_enable(ARRAY_SIZE(power),
                                                    &power[0]);
                        if (ret != 0) {
@@ -1232,7 +1232,6 @@ static int wm8400_set_bias_level(struct snd_soc_codec *codec,
                break;
        }
 
-       codec->dapm.bias_level = level;
        return 0;
 }
 
index 8736ad094b248926051b3bf2590356c8db7ce3da..dac5beb4d02356f7e8eef2fbf8e464ab77aa4f6b 100644 (file)
@@ -519,7 +519,7 @@ static int wm8510_set_bias_level(struct snd_soc_codec *codec,
        case SND_SOC_BIAS_STANDBY:
                power1 |= WM8510_POWER1_BIASEN | WM8510_POWER1_BUFIOEN;
 
-               if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) {
+               if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_OFF) {
                        regcache_sync(wm8510->regmap);
 
                        /* Initial cap charge at VMID 5k */
@@ -538,7 +538,6 @@ static int wm8510_set_bias_level(struct snd_soc_codec *codec,
                break;
        }
 
-       codec->dapm.bias_level = level;
        return 0;
 }
 
index b1cc94f5fc4b253282a71d167cbb1815861d99d1..8c5b9df3e54204f5f6ee1c6159d1897999fd96c9 100644 (file)
@@ -308,7 +308,7 @@ static int wm8523_set_bias_level(struct snd_soc_codec *codec,
                break;
 
        case SND_SOC_BIAS_STANDBY:
-               if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) {
+               if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_OFF) {
                        ret = regulator_bulk_enable(ARRAY_SIZE(wm8523->supplies),
                                                    wm8523->supplies);
                        if (ret != 0) {
@@ -344,7 +344,6 @@ static int wm8523_set_bias_level(struct snd_soc_codec *codec,
                                       wm8523->supplies);
                break;
        }
-       codec->dapm.bias_level = level;
        return 0;
 }
 
index 0a887c5ec83a4c69edd6a0079cb17b676c46c774..759a7928ac3ee48a43ecf7f626683042d5126534 100644 (file)
@@ -795,7 +795,7 @@ static int wm8580_set_bias_level(struct snd_soc_codec *codec,
                break;
 
        case SND_SOC_BIAS_STANDBY:
-               if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) {
+               if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_OFF) {
                        /* Power up and get individual control of the DACs */
                        snd_soc_update_bits(codec, WM8580_PWRDN1,
                                            WM8580_PWRDN1_PWDN |
@@ -812,7 +812,6 @@ static int wm8580_set_bias_level(struct snd_soc_codec *codec,
                                    WM8580_PWRDN1_PWDN, WM8580_PWRDN1_PWDN);
                break;
        }
-       codec->dapm.bias_level = level;
        return 0;
 }
 
index 121e46d53779f33cf7f9c0eb49b8531c61323774..cc8251f09f8ab8240140030302cbbe11c095ef79 100644 (file)
@@ -310,7 +310,7 @@ static int wm8711_set_bias_level(struct snd_soc_codec *codec,
        case SND_SOC_BIAS_PREPARE:
                break;
        case SND_SOC_BIAS_STANDBY:
-               if (codec->dapm.bias_level == SND_SOC_BIAS_OFF)
+               if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_OFF)
                        regcache_sync(wm8711->regmap);
 
                snd_soc_write(codec, WM8711_PWR, reg | 0x0040);
@@ -320,7 +320,6 @@ static int wm8711_set_bias_level(struct snd_soc_codec *codec,
                snd_soc_write(codec, WM8711_PWR, 0xffff);
                break;
        }
-       codec->dapm.bias_level = level;
        return 0;
 }
 
index 55c7fb4fc78667c49d799faef3e1e89a7af2bd1c..f1a173e6ec33bd29db81abfeded8b3842ca08032 100644 (file)
@@ -170,7 +170,7 @@ static int wm8728_set_bias_level(struct snd_soc_codec *codec,
        case SND_SOC_BIAS_ON:
        case SND_SOC_BIAS_PREPARE:
        case SND_SOC_BIAS_STANDBY:
-               if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) {
+               if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_OFF) {
                        /* Power everything up... */
                        reg = snd_soc_read(codec, WM8728_DACCTL);
                        snd_soc_write(codec, WM8728_DACCTL, reg & ~0x4);
@@ -185,7 +185,6 @@ static int wm8728_set_bias_level(struct snd_soc_codec *codec,
                snd_soc_write(codec, WM8728_DACCTL, reg | 0x4);
                break;
        }
-       codec->dapm.bias_level = level;
        return 0;
 }
 
index 2245b6a32f3dc52da5b5f8ddf9393cf400172a7b..915ea11ad4b6337f73bf85e9536a27c7d7fa45f1 100644 (file)
@@ -387,6 +387,7 @@ static int wm8731_set_dai_sysclk(struct snd_soc_dai *codec_dai,
                int clk_id, unsigned int freq, int dir)
 {
        struct snd_soc_codec *codec = codec_dai->codec;
+       struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
        struct wm8731_priv *wm8731 = snd_soc_codec_get_drvdata(codec);
 
        switch (clk_id) {
@@ -421,7 +422,7 @@ static int wm8731_set_dai_sysclk(struct snd_soc_dai *codec_dai,
 
        wm8731->sysclk = freq;
 
-       snd_soc_dapm_sync(&codec->dapm);
+       snd_soc_dapm_sync(dapm);
 
        return 0;
 }
@@ -501,7 +502,7 @@ static int wm8731_set_bias_level(struct snd_soc_codec *codec,
        case SND_SOC_BIAS_PREPARE:
                break;
        case SND_SOC_BIAS_STANDBY:
-               if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) {
+               if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_OFF) {
                        ret = regulator_bulk_enable(ARRAY_SIZE(wm8731->supplies),
                                                    wm8731->supplies);
                        if (ret != 0)
@@ -523,7 +524,6 @@ static int wm8731_set_bias_level(struct snd_soc_codec *codec,
                regcache_mark_dirty(wm8731->regmap);
                break;
        }
-       codec->dapm.bias_level = level;
        return 0;
 }
 
@@ -599,7 +599,7 @@ static int wm8731_probe(struct snd_soc_codec *codec)
                goto err_regulator_enable;
        }
 
-       wm8731_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
+       snd_soc_codec_force_bias_level(codec, SND_SOC_BIAS_STANDBY);
 
        /* Latch the update bits */
        snd_soc_update_bits(codec, WM8731_LOUT1V, 0x100, 0);
index ada9ac1ba2c647ce6a8d4bb75d504002935a6f85..6ad606fd8b6908c2382d501da96036a942998b9f 100644 (file)
@@ -469,7 +469,7 @@ static int wm8737_set_bias_level(struct snd_soc_codec *codec,
                break;
 
        case SND_SOC_BIAS_STANDBY:
-               if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) {
+               if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_OFF) {
                        ret = regulator_bulk_enable(ARRAY_SIZE(wm8737->supplies),
                                                    wm8737->supplies);
                        if (ret != 0) {
@@ -483,7 +483,8 @@ static int wm8737_set_bias_level(struct snd_soc_codec *codec,
 
                        /* Fast VMID ramp at 2*2.5k */
                        snd_soc_update_bits(codec, WM8737_MISC_BIAS_CONTROL,
-                                           WM8737_VMIDSEL_MASK, 0x4);
+                                           WM8737_VMIDSEL_MASK,
+                                           2 << WM8737_VMIDSEL_SHIFT);
 
                        /* Bring VMID up */
                        snd_soc_update_bits(codec, WM8737_POWER_MANAGEMENT,
@@ -497,7 +498,8 @@ static int wm8737_set_bias_level(struct snd_soc_codec *codec,
 
                /* VMID at 2*300k */
                snd_soc_update_bits(codec, WM8737_MISC_BIAS_CONTROL,
-                                   WM8737_VMIDSEL_MASK, 2);
+                                   WM8737_VMIDSEL_MASK,
+                                   1 << WM8737_VMIDSEL_SHIFT);
 
                break;
 
@@ -510,7 +512,6 @@ static int wm8737_set_bias_level(struct snd_soc_codec *codec,
                break;
        }
 
-       codec->dapm.bias_level = level;
        return 0;
 }
 
@@ -560,7 +561,7 @@ static int wm8737_probe(struct snd_soc_codec *codec)
        snd_soc_update_bits(codec, WM8737_RIGHT_PGA_VOLUME, WM8737_RVU,
                            WM8737_RVU);
 
-       wm8737_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
+       snd_soc_codec_force_bias_level(codec, SND_SOC_BIAS_STANDBY);
 
        /* Bias level configuration will have done an extra enable */
        regulator_bulk_disable(ARRAY_SIZE(wm8737->supplies), wm8737->supplies);
index 9e71c768966f050e0a8279b54ec4e9eeb7f8e6d9..09ff01f2fc1e859d65eef02131aa371d4cf93111 100644 (file)
@@ -41,6 +41,7 @@ static const char *wm8741_supply_names[WM8741_NUM_SUPPLIES] = {
 
 /* codec private data */
 struct wm8741_priv {
+       struct wm8741_platform_data pdata;
        struct regmap *regmap;
        struct regulator_bulk_data supplies[WM8741_NUM_SUPPLIES];
        unsigned int sysclk;
@@ -87,13 +88,27 @@ static int wm8741_reset(struct snd_soc_codec *codec)
 static const DECLARE_TLV_DB_SCALE(dac_tlv_fine, -12700, 13, 0);
 static const DECLARE_TLV_DB_SCALE(dac_tlv, -12700, 400, 0);
 
-static const struct snd_kcontrol_new wm8741_snd_controls[] = {
+static const struct snd_kcontrol_new wm8741_snd_controls_stereo[] = {
 SOC_DOUBLE_R_TLV("Fine Playback Volume", WM8741_DACLLSB_ATTENUATION,
                 WM8741_DACRLSB_ATTENUATION, 1, 255, 1, dac_tlv_fine),
 SOC_DOUBLE_R_TLV("Playback Volume", WM8741_DACLMSB_ATTENUATION,
                 WM8741_DACRMSB_ATTENUATION, 0, 511, 1, dac_tlv),
 };
 
+static const struct snd_kcontrol_new wm8741_snd_controls_mono_left[] = {
+SOC_SINGLE_TLV("Fine Playback Volume", WM8741_DACLLSB_ATTENUATION,
+                1, 255, 1, dac_tlv_fine),
+SOC_SINGLE_TLV("Playback Volume", WM8741_DACLMSB_ATTENUATION,
+                0, 511, 1, dac_tlv),
+};
+
+static const struct snd_kcontrol_new wm8741_snd_controls_mono_right[] = {
+SOC_SINGLE_TLV("Fine Playback Volume", WM8741_DACRLSB_ATTENUATION,
+               1, 255, 1, dac_tlv_fine),
+SOC_SINGLE_TLV("Playback Volume", WM8741_DACRMSB_ATTENUATION,
+               0, 511, 1, dac_tlv),
+};
+
 static const struct snd_soc_dapm_widget wm8741_dapm_widgets[] = {
 SND_SOC_DAPM_DAC("DACL", "Playback", SND_SOC_NOPM, 0, 0),
 SND_SOC_DAPM_DAC("DACR", "Playback", SND_SOC_NOPM, 0, 0),
@@ -398,7 +413,7 @@ static struct snd_soc_dai_driver wm8741_dai = {
        .name = "wm8741",
        .playback = {
                .stream_name = "Playback",
-               .channels_min = 2,  /* Mono modes not yet supported */
+               .channels_min = 2,
                .channels_max = 2,
                .rates = WM8741_RATES,
                .formats = WM8741_FORMATS,
@@ -416,6 +431,65 @@ static int wm8741_resume(struct snd_soc_codec *codec)
 #define wm8741_resume NULL
 #endif
 
+static int wm8741_configure(struct snd_soc_codec *codec)
+{
+       struct wm8741_priv *wm8741 = snd_soc_codec_get_drvdata(codec);
+
+       /* Configure differential mode */
+       switch (wm8741->pdata.diff_mode) {
+       case WM8741_DIFF_MODE_STEREO:
+       case WM8741_DIFF_MODE_STEREO_REVERSED:
+       case WM8741_DIFF_MODE_MONO_LEFT:
+       case WM8741_DIFF_MODE_MONO_RIGHT:
+               snd_soc_update_bits(codec, WM8741_MODE_CONTROL_2,
+                               WM8741_DIFF_MASK,
+                               wm8741->pdata.diff_mode << WM8741_DIFF_SHIFT);
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       /* Change some default settings - latch VU */
+       snd_soc_update_bits(codec, WM8741_DACLLSB_ATTENUATION,
+                       WM8741_UPDATELL, WM8741_UPDATELL);
+       snd_soc_update_bits(codec, WM8741_DACLMSB_ATTENUATION,
+                       WM8741_UPDATELM, WM8741_UPDATELM);
+       snd_soc_update_bits(codec, WM8741_DACRLSB_ATTENUATION,
+                       WM8741_UPDATERL, WM8741_UPDATERL);
+       snd_soc_update_bits(codec, WM8741_DACRMSB_ATTENUATION,
+                       WM8741_UPDATERM, WM8741_UPDATERM);
+
+       return 0;
+}
+
+static int wm8741_add_controls(struct snd_soc_codec *codec)
+{
+       struct wm8741_priv *wm8741 = snd_soc_codec_get_drvdata(codec);
+
+       switch (wm8741->pdata.diff_mode) {
+       case WM8741_DIFF_MODE_STEREO:
+       case WM8741_DIFF_MODE_STEREO_REVERSED:
+               snd_soc_add_codec_controls(codec,
+                               wm8741_snd_controls_stereo,
+                               ARRAY_SIZE(wm8741_snd_controls_stereo));
+               break;
+       case WM8741_DIFF_MODE_MONO_LEFT:
+               snd_soc_add_codec_controls(codec,
+                               wm8741_snd_controls_mono_left,
+                               ARRAY_SIZE(wm8741_snd_controls_mono_left));
+               break;
+       case WM8741_DIFF_MODE_MONO_RIGHT:
+               snd_soc_add_codec_controls(codec,
+                               wm8741_snd_controls_mono_right,
+                               ARRAY_SIZE(wm8741_snd_controls_mono_right));
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
 static int wm8741_probe(struct snd_soc_codec *codec)
 {
        struct wm8741_priv *wm8741 = snd_soc_codec_get_drvdata(codec);
@@ -434,15 +508,17 @@ static int wm8741_probe(struct snd_soc_codec *codec)
                goto err_enable;
        }
 
-       /* Change some default settings - latch VU */
-       snd_soc_update_bits(codec, WM8741_DACLLSB_ATTENUATION,
-                           WM8741_UPDATELL, WM8741_UPDATELL);
-       snd_soc_update_bits(codec, WM8741_DACLMSB_ATTENUATION,
-                           WM8741_UPDATELM, WM8741_UPDATELM);
-       snd_soc_update_bits(codec, WM8741_DACRLSB_ATTENUATION,
-                           WM8741_UPDATERL, WM8741_UPDATERL);
-       snd_soc_update_bits(codec, WM8741_DACRMSB_ATTENUATION,
-                           WM8741_UPDATERM, WM8741_UPDATERM);
+       ret = wm8741_configure(codec);
+       if (ret < 0) {
+               dev_err(codec->dev, "Failed to change default settings\n");
+               goto err_enable;
+       }
+
+       ret = wm8741_add_controls(codec);
+       if (ret < 0) {
+               dev_err(codec->dev, "Failed to add controls\n");
+               goto err_enable;
+       }
 
        dev_dbg(codec->dev, "Successful registration\n");
        return ret;
@@ -467,8 +543,6 @@ static struct snd_soc_codec_driver soc_codec_dev_wm8741 = {
        .remove =       wm8741_remove,
        .resume =       wm8741_resume,
 
-       .controls = wm8741_snd_controls,
-       .num_controls = ARRAY_SIZE(wm8741_snd_controls),
        .dapm_widgets = wm8741_dapm_widgets,
        .num_dapm_widgets = ARRAY_SIZE(wm8741_dapm_widgets),
        .dapm_routes = wm8741_dapm_routes,
@@ -493,6 +567,23 @@ static const struct regmap_config wm8741_regmap = {
        .readable_reg = wm8741_readable,
 };
 
+static int wm8741_set_pdata(struct device *dev, struct wm8741_priv *wm8741)
+{
+       const struct wm8741_platform_data *pdata = dev_get_platdata(dev);
+       u32 diff_mode;
+
+       if (dev->of_node) {
+               if (of_property_read_u32(dev->of_node, "diff-mode", &diff_mode)
+                               >= 0)
+                       wm8741->pdata.diff_mode = diff_mode;
+       } else {
+               if (pdata != NULL)
+                       memcpy(&wm8741->pdata, pdata, sizeof(wm8741->pdata));
+       }
+
+       return 0;
+}
+
 #if IS_ENABLED(CONFIG_I2C)
 static int wm8741_i2c_probe(struct i2c_client *i2c,
                            const struct i2c_device_id *id)
@@ -522,6 +613,12 @@ static int wm8741_i2c_probe(struct i2c_client *i2c,
                return ret;
        }
 
+       ret = wm8741_set_pdata(&i2c->dev, wm8741);
+       if (ret != 0) {
+               dev_err(&i2c->dev, "Failed to set pdata: %d\n", ret);
+               return ret;
+       }
+
        i2c_set_clientdata(i2c, wm8741);
 
        ret = snd_soc_register_codec(&i2c->dev,
@@ -582,6 +679,12 @@ static int wm8741_spi_probe(struct spi_device *spi)
                return ret;
        }
 
+       ret = wm8741_set_pdata(&spi->dev, wm8741);
+       if (ret != 0) {
+               dev_err(&spi->dev, "Failed to set pdata: %d\n", ret);
+               return ret;
+       }
+
        spi_set_drvdata(spi, wm8741);
 
        ret = snd_soc_register_codec(&spi->dev,
index 56c1b1d4a68100f52fcf6ec61363a9140e88e63a..c8835f65f3425c3a58b68f83de63282b89cea297 100644 (file)
 #define WM8741_DITHER_SHIFT                          0  /* DITHER - [1:0] */
 #define WM8741_DITHER_WIDTH                          2  /* DITHER - [1:0] */
 
+/* DIFF field values */
+#define WM8741_DIFF_MODE_STEREO                      0  /* stereo normal */
+#define WM8741_DIFF_MODE_STEREO_REVERSED             2  /* stereo reversed */
+#define WM8741_DIFF_MODE_MONO_LEFT                   1  /* mono left */
+#define WM8741_DIFF_MODE_MONO_RIGHT                  3  /* mono right */
+
 /*
  * R32 (0x20) - ADDITONAL_CONTROL_1
  */
 
 #define  WM8741_SYSCLK 0
 
+struct wm8741_platform_data {
+       u32 diff_mode;   /* Differential Output Mode */
+};
+
 #endif
index eb0a1644ba1142d05cc8ac561945a507f776e066..56d89b0865fa6878fd6f760ec74b247455fa8fe4 100644 (file)
@@ -634,7 +634,7 @@ static int wm8750_set_bias_level(struct snd_soc_codec *codec,
        case SND_SOC_BIAS_PREPARE:
                break;
        case SND_SOC_BIAS_STANDBY:
-               if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) {
+               if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_OFF) {
                        snd_soc_cache_sync(codec);
 
                        /* Set VMID to 5k */
@@ -651,7 +651,6 @@ static int wm8750_set_bias_level(struct snd_soc_codec *codec,
                snd_soc_write(codec, WM8750_PWR1, 0x0001);
                break;
        }
-       codec->dapm.bias_level = level;
        return 0;
 }
 
index c50a5959345fcf346f55e32056c2b1d4ae5ebd11..feb2997a377aa0a0fe12df1c6b44384c4ff3f3fb 100644 (file)
@@ -1352,7 +1352,7 @@ static int wm8753_set_bias_level(struct snd_soc_codec *codec,
                flush_delayed_work(&wm8753->charge_work);
                break;
        case SND_SOC_BIAS_STANDBY:
-               if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) {
+               if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_OFF) {
                        /* set vmid to 5k for quick power up */
                        snd_soc_write(codec, WM8753_PWR1, pwr_reg | 0x01c1);
                        schedule_delayed_work(&wm8753->charge_work,
@@ -1367,7 +1367,6 @@ static int wm8753_set_bias_level(struct snd_soc_codec *codec,
                snd_soc_write(codec, WM8753_PWR1, 0x0001);
                break;
        }
-       codec->dapm.bias_level = level;
        return 0;
 }
 
index 53e977da2f86d325c0366efae3e3ba121e49fedd..66c1f151071de81f0e275a13ec8bbd9b2127e6e1 100644 (file)
@@ -510,7 +510,7 @@ static int wm8770_set_bias_level(struct snd_soc_codec *codec,
        case SND_SOC_BIAS_PREPARE:
                break;
        case SND_SOC_BIAS_STANDBY:
-               if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) {
+               if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_OFF) {
                        ret = regulator_bulk_enable(ARRAY_SIZE(wm8770->supplies),
                                                    wm8770->supplies);
                        if (ret) {
@@ -534,7 +534,6 @@ static int wm8770_set_bias_level(struct snd_soc_codec *codec,
                break;
        }
 
-       codec->dapm.bias_level = level;
        return 0;
 }
 
index c13050b7793190b029668effdb5c177e4cdd3389..ece9b44567676612564058557d496649be5a2265 100644 (file)
@@ -344,7 +344,7 @@ static int wm8776_set_bias_level(struct snd_soc_codec *codec,
        case SND_SOC_BIAS_PREPARE:
                break;
        case SND_SOC_BIAS_STANDBY:
-               if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) {
+               if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_OFF) {
                        regcache_sync(wm8776->regmap);
 
                        /* Disable the global powerdown; DAPM does the rest */
@@ -357,7 +357,6 @@ static int wm8776_set_bias_level(struct snd_soc_codec *codec,
                break;
        }
 
-       codec->dapm.bias_level = level;
        return 0;
 }
 
index 1e403f67cf161cfbcf24cd3d934df30765522f16..c195c2e8af074e5fa1b6985b2cf6e85a3df4fd16 100644 (file)
@@ -162,7 +162,7 @@ static int txsrc_put(struct snd_kcontrol *kcontrol,
                     struct snd_ctl_elem_value *ucontrol)
 {
        struct snd_soc_codec *codec = snd_soc_dapm_kcontrol_codec(kcontrol);
-       struct snd_soc_dapm_context *dapm = &codec->dapm;
+       struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
        struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
        unsigned int val = ucontrol->value.enumerated.item[0] << e->shift_l;
        unsigned int mask = 1 << e->shift_l;
index 2eb986c19b886a48e9d367623adf353a94796689..f3759ec5a8638647cd54088f560a239e58776428 100644 (file)
@@ -998,8 +998,8 @@ static int wm8900_digital_mute(struct snd_soc_dai *codec_dai, int mute)
                      SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000)
 
 #define WM8900_PCM_FORMATS \
-       (SNDRV_PCM_FORMAT_S16_LE | SNDRV_PCM_FORMAT_S20_3LE | \
-        SNDRV_PCM_FORMAT_S24_LE)
+       (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE | \
+        SNDRV_PCM_FMTBIT_S24_LE)
 
 static const struct snd_soc_dai_ops wm8900_dai_ops = {
        .hw_params      = wm8900_hw_params,
@@ -1049,7 +1049,7 @@ static int wm8900_set_bias_level(struct snd_soc_codec *codec,
 
        case SND_SOC_BIAS_STANDBY:
                /* Charge capacitors if initial power up */
-               if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) {
+               if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_OFF) {
                        /* STARTUP_BIAS_ENA on */
                        snd_soc_write(codec, WM8900_REG_POWER1,
                                     WM8900_REG_POWER1_STARTUP_BIAS_ENA);
@@ -1117,7 +1117,6 @@ static int wm8900_set_bias_level(struct snd_soc_codec *codec,
                             WM8900_REG_POWER2_SYSCLK_ENA);
                break;
        }
-       codec->dapm.bias_level = level;
        return 0;
 }
 
@@ -1138,7 +1137,7 @@ static int wm8900_suspend(struct snd_soc_codec *codec)
        wm8900->fll_out = fll_out;
        wm8900->fll_in = fll_in;
 
-       wm8900_set_bias_level(codec, SND_SOC_BIAS_OFF);
+       snd_soc_codec_force_bias_level(codec, SND_SOC_BIAS_OFF);
 
        return 0;
 }
@@ -1156,7 +1155,7 @@ static int wm8900_resume(struct snd_soc_codec *codec)
                return ret;
        }
 
-       wm8900_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
+       snd_soc_codec_force_bias_level(codec, SND_SOC_BIAS_STANDBY);
 
        /* Restart the FLL? */
        if (wm8900->fll_out) {
@@ -1189,7 +1188,7 @@ static int wm8900_probe(struct snd_soc_codec *codec)
        wm8900_reset(codec);
 
        /* Turn the chip on */
-       wm8900_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
+       snd_soc_codec_force_bias_level(codec, SND_SOC_BIAS_STANDBY);
 
        /* Latch the volume update bits */
        snd_soc_update_bits(codec, WM8900_REG_LINVOL, 0x100, 0x100);
index 04b04f8e147c6bdeada6decdca981a026ce57afa..b5322c1544fba51e2d609b186d6fdd2ebb7b57d7 100644 (file)
@@ -1105,7 +1105,7 @@ static int wm8903_set_bias_level(struct snd_soc_codec *codec,
                break;
 
        case SND_SOC_BIAS_STANDBY:
-               if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) {
+               if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_OFF) {
                        snd_soc_update_bits(codec, WM8903_BIAS_CONTROL_0,
                                            WM8903_POBCTRL | WM8903_ISEL_MASK |
                                            WM8903_STARTUP_BIAS_ENA |
@@ -1200,8 +1200,6 @@ static int wm8903_set_bias_level(struct snd_soc_codec *codec,
                break;
        }
 
-       codec->dapm.bias_level = level;
-
        return 0;
 }
 
index db949311c0f206c401f70839a4f318f3fc8557e4..0bb4a647755d84c88a2edddd29da26dae6aa95ac 100644 (file)
@@ -172,7 +172,7 @@ extern int wm8903_mic_detect(struct snd_soc_codec *codec,
 #define WM8903_VMID_BUF_ENA_WIDTH                    1  /* VMID_BUF_ENA */
 
 #define WM8903_VMID_RES_50K                          2
-#define WM8903_VMID_RES_250K                         3
+#define WM8903_VMID_RES_250K                         4
 #define WM8903_VMID_RES_5K                           6
 
 /*
index 215e93c1ddf0358f42dc5581fd01b1d9a3d7e1e0..265a4a58a2d1bf7c4e80e1b48c981af4ef878ae5 100644 (file)
@@ -1168,7 +1168,7 @@ static const struct snd_soc_dapm_route wm8912_intercon[] = {
 static int wm8904_add_widgets(struct snd_soc_codec *codec)
 {
        struct wm8904_priv *wm8904 = snd_soc_codec_get_drvdata(codec);
-       struct snd_soc_dapm_context *dapm = &codec->dapm;
+       struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
 
        snd_soc_dapm_new_controls(dapm, wm8904_core_dapm_widgets,
                                  ARRAY_SIZE(wm8904_core_dapm_widgets));
@@ -1852,7 +1852,7 @@ static int wm8904_set_bias_level(struct snd_soc_codec *codec,
                break;
 
        case SND_SOC_BIAS_STANDBY:
-               if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) {
+               if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_OFF) {
                        ret = regulator_bulk_enable(ARRAY_SIZE(wm8904->supplies),
                                                    wm8904->supplies);
                        if (ret != 0) {
@@ -1907,7 +1907,6 @@ static int wm8904_set_bias_level(struct snd_soc_codec *codec,
                clk_disable_unprepare(wm8904->mclk);
                break;
        }
-       codec->dapm.bias_level = level;
        return 0;
 }
 
index e4142b4309eb577c5efb866a8a75994f7ed93dea..98ef0ba5c2a45844282e6c14a6a382d01455dfdc 100644 (file)
@@ -492,7 +492,7 @@ static int wm8940_set_bias_level(struct snd_soc_codec *codec,
                ret = snd_soc_write(codec, WM8940_POWER1, pwr_reg | 0x1);
                break;
        case SND_SOC_BIAS_STANDBY:
-               if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) {
+               if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_OFF) {
                        ret = regcache_sync(wm8940->regmap);
                        if (ret < 0) {
                                dev_err(codec->dev, "Failed to sync cache: %d\n", ret);
@@ -510,8 +510,6 @@ static int wm8940_set_bias_level(struct snd_soc_codec *codec,
                break;
        }
 
-       codec->dapm.bias_level = level;
-
        return ret;
 }
 
@@ -707,7 +705,7 @@ static int wm8940_probe(struct snd_soc_codec *codec)
                return ret;
        }
 
-       wm8940_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
+       snd_soc_codec_force_bias_level(codec, SND_SOC_BIAS_STANDBY);
 
        ret = snd_soc_write(codec, WM8940_POWER1, 0x180);
        if (ret < 0)
index 00bec915d6522152a5d40dcc3d2df52ef16424eb..2d591c24704be487830ab956e9f4b2ef1be02075 100644 (file)
@@ -298,7 +298,7 @@ static int wm8955_configure_clocking(struct snd_soc_codec *codec)
                snd_soc_update_bits(codec, WM8955_PLL_CONTROL_2,
                                    WM8955_K_17_9_MASK,
                                    (pll.k >> 9) & WM8955_K_17_9_MASK);
-               snd_soc_update_bits(codec, WM8955_PLL_CONTROL_2,
+               snd_soc_update_bits(codec, WM8955_PLL_CONTROL_3,
                                    WM8955_K_8_0_MASK,
                                    pll.k & WM8955_K_8_0_MASK);
                if (pll.k)
@@ -785,7 +785,7 @@ static int wm8955_set_bias_level(struct snd_soc_codec *codec,
                break;
 
        case SND_SOC_BIAS_STANDBY:
-               if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) {
+               if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_OFF) {
                        ret = regulator_bulk_enable(ARRAY_SIZE(wm8955->supplies),
                                                    wm8955->supplies);
                        if (ret != 0) {
@@ -838,7 +838,6 @@ static int wm8955_set_bias_level(struct snd_soc_codec *codec,
                                       wm8955->supplies);
                break;
        }
-       codec->dapm.bias_level = level;
        return 0;
 }
 
@@ -929,7 +928,7 @@ static int wm8955_probe(struct snd_soc_codec *codec)
                                            WM8955_DMEN, WM8955_DMEN);
        }
 
-       wm8955_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
+       snd_soc_codec_force_bias_level(codec, SND_SOC_BIAS_STANDBY);
 
        /* Bias level configuration will have done an extra enable */
        regulator_bulk_disable(ARRAY_SIZE(wm8955->supplies), wm8955->supplies);
index 3035d98564156746bc4e814f744e1ea0f236564a..94c5c4681ce5c0c83accd7ab8682de448c9e7b07 100644 (file)
@@ -127,6 +127,8 @@ struct wm8960_priv {
        struct snd_soc_dapm_widget *out3;
        bool deemph;
        int playback_fs;
+       int bclk;
+       int sysclk;
        struct wm8960_data pdata;
 };
 
@@ -245,7 +247,7 @@ SOC_SINGLE("PCM Playback -6dB Switch", WM8960_DACCTL1, 7, 1, 0),
 SOC_ENUM("ADC Polarity", wm8960_enum[0]),
 SOC_SINGLE("ADC High Pass Filter Switch", WM8960_DACCTL1, 0, 1, 0),
 
-SOC_ENUM("DAC Polarity", wm8960_enum[2]),
+SOC_ENUM("DAC Polarity", wm8960_enum[1]),
 SOC_SINGLE_BOOL_EXT("DAC Deemphasis Switch", 0,
                    wm8960_get_deemph, wm8960_put_deemph),
 
@@ -395,7 +397,7 @@ static const struct snd_soc_dapm_route audio_paths[] = {
        { "Right Input Mixer", "Boost Switch", "Right Boost Mixer", },
        { "Right Input Mixer", NULL, "RINPUT1", },  /* Really Boost Switch */
        { "Right Input Mixer", NULL, "RINPUT2" },
-       { "Right Input Mixer", NULL, "LINPUT3" },
+       { "Right Input Mixer", NULL, "RINPUT3" },
 
        { "Left ADC", NULL, "Left Input Mixer" },
        { "Right ADC", NULL, "Right Input Mixer" },
@@ -445,7 +447,7 @@ static int wm8960_add_widgets(struct snd_soc_codec *codec)
 {
        struct wm8960_priv *wm8960 = snd_soc_codec_get_drvdata(codec);
        struct wm8960_data *pdata = &wm8960->pdata;
-       struct snd_soc_dapm_context *dapm = &codec->dapm;
+       struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
        struct snd_soc_dapm_widget *w;
 
        snd_soc_dapm_new_controls(dapm, wm8960_dapm_widgets,
@@ -476,7 +478,7 @@ static int wm8960_add_widgets(struct snd_soc_codec *codec)
         * and save the result.
         */
        list_for_each_entry(w, &codec->component.card->widgets, list) {
-               if (w->dapm != &codec->dapm)
+               if (w->dapm != dapm)
                        continue;
                if (strcmp(w->name, "LOUT1 PGA") == 0)
                        wm8960->lout1 = w;
@@ -563,6 +565,72 @@ static struct {
        {  8000, 5 },
 };
 
+/* Multiply 256 for internal 256 div */
+static const int dac_divs[] = { 256, 384, 512, 768, 1024, 1408, 1536 };
+
+/* Multiply 10 to eliminate decimials */
+static const int bclk_divs[] = {
+       10, 15, 20, 30, 40, 55, 60, 80, 110,
+       120, 160, 220, 240, 320, 320, 320
+};
+
+static void wm8960_configure_clocking(struct snd_soc_codec *codec,
+               bool tx, int lrclk)
+{
+       struct wm8960_priv *wm8960 = snd_soc_codec_get_drvdata(codec);
+       u16 iface1 = snd_soc_read(codec, WM8960_IFACE1);
+       u16 iface2 = snd_soc_read(codec, WM8960_IFACE2);
+       u32 sysclk;
+       int i, j;
+
+       if (!(iface1 & (1<<6))) {
+               dev_dbg(codec->dev,
+                       "Codec is slave mode, no need to configure clock\n");
+               return;
+       }
+
+       if (!wm8960->sysclk) {
+               dev_dbg(codec->dev, "No SYSCLK configured\n");
+               return;
+       }
+
+       if (!wm8960->bclk || !lrclk) {
+               dev_dbg(codec->dev, "No audio clocks configured\n");
+               return;
+       }
+
+       for (i = 0; i < ARRAY_SIZE(dac_divs); ++i) {
+               if (wm8960->sysclk == lrclk * dac_divs[i]) {
+                       for (j = 0; j < ARRAY_SIZE(bclk_divs); ++j) {
+                               sysclk = wm8960->bclk * bclk_divs[j] / 10;
+                               if (wm8960->sysclk == sysclk)
+                                       break;
+                       }
+                       if(j != ARRAY_SIZE(bclk_divs))
+                               break;
+               }
+       }
+
+       if (i == ARRAY_SIZE(dac_divs)) {
+               dev_err(codec->dev, "Unsupported sysclk %d\n", wm8960->sysclk);
+               return;
+       }
+
+       /*
+        * configure frame clock. If ADCLRC configure as GPIO pin, DACLRC
+        * pin is used as a frame clock for ADCs and DACs.
+        */
+       if (iface2 & (1<<6))
+               snd_soc_update_bits(codec, WM8960_CLOCK1, 0x7 << 3, i << 3);
+       else if (tx)
+               snd_soc_update_bits(codec, WM8960_CLOCK1, 0x7 << 3, i << 3);
+       else if (!tx)
+               snd_soc_update_bits(codec, WM8960_CLOCK1, 0x7 << 6, i << 6);
+
+       /* configure bit clock */
+       snd_soc_update_bits(codec, WM8960_CLOCK2, 0xf, j);
+}
+
 static int wm8960_hw_params(struct snd_pcm_substream *substream,
                            struct snd_pcm_hw_params *params,
                            struct snd_soc_dai *dai)
@@ -570,8 +638,13 @@ static int wm8960_hw_params(struct snd_pcm_substream *substream,
        struct snd_soc_codec *codec = dai->codec;
        struct wm8960_priv *wm8960 = snd_soc_codec_get_drvdata(codec);
        u16 iface = snd_soc_read(codec, WM8960_IFACE1) & 0xfff3;
+       bool tx = substream->stream == SNDRV_PCM_STREAM_PLAYBACK;
        int i;
 
+       wm8960->bclk = snd_soc_params_to_bclk(params);
+       if (params_channels(params) == 1)
+               wm8960->bclk *= 2;
+
        /* bit size */
        switch (params_width(params)) {
        case 16:
@@ -582,6 +655,12 @@ static int wm8960_hw_params(struct snd_pcm_substream *substream,
        case 24:
                iface |= 0x0008;
                break;
+       case 32:
+               /* right justify mode does not support 32 word length */
+               if ((iface & 0x3) != 0) {
+                       iface |= 0x000c;
+                       break;
+               }
        default:
                dev_err(codec->dev, "unsupported width %d\n",
                        params_width(params));
@@ -602,6 +681,9 @@ static int wm8960_hw_params(struct snd_pcm_substream *substream,
 
        /* set iface */
        snd_soc_write(codec, WM8960_IFACE1, iface);
+
+       wm8960_configure_clocking(codec, tx, params_rate(params));
+
        return 0;
 }
 
@@ -627,7 +709,7 @@ static int wm8960_set_bias_level_out3(struct snd_soc_codec *codec,
                break;
 
        case SND_SOC_BIAS_PREPARE:
-               switch (codec->dapm.bias_level) {
+               switch (snd_soc_codec_get_bias_level(codec)) {
                case SND_SOC_BIAS_STANDBY:
                        if (!IS_ERR(wm8960->mclk)) {
                                ret = clk_prepare_enable(wm8960->mclk);
@@ -655,7 +737,7 @@ static int wm8960_set_bias_level_out3(struct snd_soc_codec *codec,
                break;
 
        case SND_SOC_BIAS_STANDBY:
-               if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) {
+               if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_OFF) {
                        regcache_sync(wm8960->regmap);
 
                        /* Enable anti-pop features */
@@ -691,8 +773,6 @@ static int wm8960_set_bias_level_out3(struct snd_soc_codec *codec,
                break;
        }
 
-       codec->dapm.bias_level = level;
-
        return 0;
 }
 
@@ -707,7 +787,7 @@ static int wm8960_set_bias_level_capless(struct snd_soc_codec *codec,
                break;
 
        case SND_SOC_BIAS_PREPARE:
-               switch (codec->dapm.bias_level) {
+               switch (snd_soc_codec_get_bias_level(codec)) {
                case SND_SOC_BIAS_STANDBY:
                        /* Enable anti pop mode */
                        snd_soc_update_bits(codec, WM8960_APOP1,
@@ -778,7 +858,7 @@ static int wm8960_set_bias_level_capless(struct snd_soc_codec *codec,
                break;
 
        case SND_SOC_BIAS_STANDBY:
-               switch (codec->dapm.bias_level) {
+               switch (snd_soc_codec_get_bias_level(codec)) {
                case SND_SOC_BIAS_PREPARE:
                        /* Disable HP discharge */
                        snd_soc_update_bits(codec, WM8960_APOP2,
@@ -802,8 +882,6 @@ static int wm8960_set_bias_level_capless(struct snd_soc_codec *codec,
                break;
        }
 
-       codec->dapm.bias_level = level;
-
        return 0;
 }
 
@@ -950,11 +1028,35 @@ static int wm8960_set_bias_level(struct snd_soc_codec *codec,
        return wm8960->set_bias_level(codec, level);
 }
 
+static int wm8960_set_dai_sysclk(struct snd_soc_dai *dai, int clk_id,
+                                       unsigned int freq, int dir)
+{
+       struct snd_soc_codec *codec = dai->codec;
+       struct wm8960_priv *wm8960 = snd_soc_codec_get_drvdata(codec);
+
+       switch (clk_id) {
+       case WM8960_SYSCLK_MCLK:
+               snd_soc_update_bits(codec, WM8960_CLOCK1,
+                                       0x1, WM8960_SYSCLK_MCLK);
+               break;
+       case WM8960_SYSCLK_PLL:
+               snd_soc_update_bits(codec, WM8960_CLOCK1,
+                                       0x1, WM8960_SYSCLK_PLL);
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       wm8960->sysclk = freq;
+
+       return 0;
+}
+
 #define WM8960_RATES SNDRV_PCM_RATE_8000_48000
 
 #define WM8960_FORMATS \
        (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE | \
-       SNDRV_PCM_FMTBIT_S24_LE)
+       SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE)
 
 static const struct snd_soc_dai_ops wm8960_dai_ops = {
        .hw_params = wm8960_hw_params,
@@ -962,6 +1064,7 @@ static const struct snd_soc_dai_ops wm8960_dai_ops = {
        .set_fmt = wm8960_set_dai_fmt,
        .set_clkdiv = wm8960_set_dai_clkdiv,
        .set_pll = wm8960_set_dai_pll,
+       .set_sysclk = wm8960_set_dai_sysclk,
 };
 
 static struct snd_soc_dai_driver wm8960_dai = {
index 95e2c1bfc809ff1a0d9c20b6f280c0afed491239..a057662632ffae459a318c5d9e88189b0e8391b5 100644 (file)
@@ -758,7 +758,7 @@ static int wm8961_set_bias_level(struct snd_soc_codec *codec,
                break;
 
        case SND_SOC_BIAS_PREPARE:
-               if (codec->dapm.bias_level == SND_SOC_BIAS_STANDBY) {
+               if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_STANDBY) {
                        /* Enable bias generation */
                        reg = snd_soc_read(codec, WM8961_ANTI_POP);
                        reg |= WM8961_BUFIOEN | WM8961_BUFDCOPEN;
@@ -773,7 +773,7 @@ static int wm8961_set_bias_level(struct snd_soc_codec *codec,
                break;
 
        case SND_SOC_BIAS_STANDBY:
-               if (codec->dapm.bias_level == SND_SOC_BIAS_PREPARE) {
+               if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_PREPARE) {
                        /* VREF off */
                        reg = snd_soc_read(codec, WM8961_PWR_MGMT_1);
                        reg &= ~WM8961_VREF;
@@ -795,8 +795,6 @@ static int wm8961_set_bias_level(struct snd_soc_codec *codec,
                break;
        }
 
-       codec->dapm.bias_level = level;
-
        return 0;
 }
 
index 118b0034ba235d238bfc5c137db7681126bba45b..c5748fd4f2962a816308faf605f7aee7116b970a 100644 (file)
@@ -2361,7 +2361,7 @@ static int wm8962_add_widgets(struct snd_soc_codec *codec)
 {
        struct wm8962_priv *wm8962 = snd_soc_codec_get_drvdata(codec);
        struct wm8962_pdata *pdata = &wm8962->pdata;
-       struct snd_soc_dapm_context *dapm = &codec->dapm;
+       struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
 
        snd_soc_add_codec_controls(codec, wm8962_snd_controls,
                             ARRAY_SIZE(wm8962_snd_controls));
@@ -2446,13 +2446,13 @@ static void wm8962_configure_bclk(struct snd_soc_codec *codec)
         * So we here provisionally enable it and then disable it afterward
         * if current bias_level hasn't reached SND_SOC_BIAS_ON.
         */
-       if (codec->dapm.bias_level != SND_SOC_BIAS_ON)
+       if (snd_soc_codec_get_bias_level(codec) != SND_SOC_BIAS_ON)
                snd_soc_update_bits(codec, WM8962_CLOCKING2,
                                WM8962_SYSCLK_ENA_MASK, WM8962_SYSCLK_ENA);
 
        dspclk = snd_soc_read(codec, WM8962_CLOCKING1);
 
-       if (codec->dapm.bias_level != SND_SOC_BIAS_ON)
+       if (snd_soc_codec_get_bias_level(codec) != SND_SOC_BIAS_ON)
                snd_soc_update_bits(codec, WM8962_CLOCKING2,
                                WM8962_SYSCLK_ENA_MASK, 0);
 
@@ -2510,9 +2510,6 @@ static void wm8962_configure_bclk(struct snd_soc_codec *codec)
 static int wm8962_set_bias_level(struct snd_soc_codec *codec,
                                 enum snd_soc_bias_level level)
 {
-       if (level == codec->dapm.bias_level)
-               return 0;
-
        switch (level) {
        case SND_SOC_BIAS_ON:
                break;
@@ -2530,7 +2527,7 @@ static int wm8962_set_bias_level(struct snd_soc_codec *codec,
                snd_soc_update_bits(codec, WM8962_PWR_MGMT_1,
                                    WM8962_VMID_SEL_MASK, 0x100);
 
-               if (codec->dapm.bias_level == SND_SOC_BIAS_OFF)
+               if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_OFF)
                        msleep(100);
                break;
 
@@ -2538,7 +2535,6 @@ static int wm8962_set_bias_level(struct snd_soc_codec *codec,
                break;
        }
 
-       codec->dapm.bias_level = level;
        return 0;
 }
 
@@ -2614,7 +2610,7 @@ static int wm8962_hw_params(struct snd_pcm_substream *substream,
        dev_dbg(codec->dev, "hw_params set BCLK %dHz LRCLK %dHz\n",
                wm8962->bclk, wm8962->lrclk);
 
-       if (codec->dapm.bias_level == SND_SOC_BIAS_ON)
+       if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_ON)
                wm8962_configure_bclk(codec);
 
        return 0;
@@ -3118,7 +3114,7 @@ static irqreturn_t wm8962_irq(int irq, void *data)
 int wm8962_mic_detect(struct snd_soc_codec *codec, struct snd_soc_jack *jack)
 {
        struct wm8962_priv *wm8962 = snd_soc_codec_get_drvdata(codec);
-       struct snd_soc_dapm_context *dapm = &codec->dapm;
+       struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
        int irq_mask, enable;
 
        wm8962->jack = jack;
@@ -3164,7 +3160,7 @@ static void wm8962_beep_work(struct work_struct *work)
        struct wm8962_priv *wm8962 =
                container_of(work, struct wm8962_priv, beep_work);
        struct snd_soc_codec *codec = wm8962->codec;
-       struct snd_soc_dapm_context *dapm = &codec->dapm;
+       struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
        int i;
        int reg = 0;
        int best = 0;
@@ -3415,6 +3411,7 @@ static void wm8962_free_gpio(struct snd_soc_codec *codec)
 
 static int wm8962_probe(struct snd_soc_codec *codec)
 {
+       struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
        int ret;
        struct wm8962_priv *wm8962 = snd_soc_codec_get_drvdata(codec);
        int i;
@@ -3462,7 +3459,7 @@ static int wm8962_probe(struct snd_soc_codec *codec)
        }
        if (!dmicclk || !dmicdat) {
                dev_dbg(codec->dev, "DMIC not in use, disabling\n");
-               snd_soc_dapm_nc_pin(&codec->dapm, "DMICDAT");
+               snd_soc_dapm_nc_pin(dapm, "DMICDAT");
        }
        if (dmicclk != dmicdat)
                dev_warn(codec->dev, "DMIC GPIOs partially configured\n");
index f9cbabdc623889e1adfa066674bed51a868bd49a..b51184c4e8163ed312d92b597d3b0f64d505dd2e 100644 (file)
@@ -577,7 +577,7 @@ static int wm8971_set_bias_level(struct snd_soc_codec *codec,
                flush_delayed_work(&wm8971->charge_work);
                break;
        case SND_SOC_BIAS_STANDBY:
-               if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) {
+               if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_OFF) {
                        snd_soc_cache_sync(codec);
                        /* charge output caps - set vmid to 5k for quick power up */
                        snd_soc_write(codec, WM8971_PWR1, pwr_reg | 0x01c0);
@@ -594,7 +594,6 @@ static int wm8971_set_bias_level(struct snd_soc_codec *codec,
                snd_soc_write(codec, WM8971_PWR1, 0x0001);
                break;
        }
-       codec->dapm.bias_level = level;
        return 0;
 }
 
index ff0e4646b934c6dc9427206ac71889ccd3f30f5a..33b16a7ba82ef4adec09423dd7ffcfbf1427411e 100644 (file)
@@ -514,7 +514,7 @@ static int wm8974_set_bias_level(struct snd_soc_codec *codec,
        case SND_SOC_BIAS_STANDBY:
                power1 |= WM8974_POWER1_BIASEN | WM8974_POWER1_BUFIOEN;
 
-               if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) {
+               if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_OFF) {
                        regcache_sync(dev_get_regmap(codec->dev, NULL));
 
                        /* Initial cap charge at VMID 5k */
@@ -533,7 +533,6 @@ static int wm8974_set_bias_level(struct snd_soc_codec *codec,
                break;
        }
 
-       codec->dapm.bias_level = level;
        return 0;
 }
 
index cf70329117211806ad7f43a38bd3725b6cc1b0e0..cfc8cdf499707ac6827e3da1da05ab356bcef3d4 100644 (file)
@@ -868,7 +868,7 @@ static int wm8978_set_bias_level(struct snd_soc_codec *codec,
                /* bit 3: enable bias, bit 2: enable I/O tie off buffer */
                power1 |= 0xc;
 
-               if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) {
+               if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_OFF) {
                        /* Initial cap charge at VMID 5k */
                        snd_soc_write(codec, WM8978_POWER_MANAGEMENT_1,
                                      power1 | 0x3);
@@ -888,7 +888,6 @@ static int wm8978_set_bias_level(struct snd_soc_codec *codec,
 
        dev_dbg(codec->dev, "%s: %d, %x\n", __func__, level, power1);
 
-       codec->dapm.bias_level = level;
        return 0;
 }
 
@@ -928,7 +927,7 @@ static int wm8978_suspend(struct snd_soc_codec *codec)
 {
        struct wm8978_priv *wm8978 = snd_soc_codec_get_drvdata(codec);
 
-       wm8978_set_bias_level(codec, SND_SOC_BIAS_OFF);
+       snd_soc_codec_force_bias_level(codec, SND_SOC_BIAS_OFF);
        /* Also switch PLL off */
        snd_soc_write(codec, WM8978_POWER_MANAGEMENT_1, 0);
 
@@ -944,7 +943,7 @@ static int wm8978_resume(struct snd_soc_codec *codec)
        /* Sync reg_cache with the hardware */
        regcache_sync(wm8978->regmap);
 
-       wm8978_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
+       snd_soc_codec_force_bias_level(codec, SND_SOC_BIAS_STANDBY);
 
        if (wm8978->f_pllout)
                /* Switch PLL on */
index 5d1cf08a72b872539fc8fce5a5c228ce69d1cfb5..2fdd2c6cc09d3b62d04f157042901bd33c991e18 100644 (file)
@@ -915,7 +915,7 @@ static int wm8983_set_bias_level(struct snd_soc_codec *codec,
                                    1 << WM8983_VMIDSEL_SHIFT);
                break;
        case SND_SOC_BIAS_STANDBY:
-               if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) {
+               if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_OFF) {
                        ret = regcache_sync(wm8983->regmap);
                        if (ret < 0) {
                                dev_err(codec->dev, "Failed to sync cache: %d\n", ret);
@@ -963,7 +963,6 @@ static int wm8983_set_bias_level(struct snd_soc_codec *codec,
                break;
        }
 
-       codec->dapm.bias_level = level;
        return 0;
 }
 
index 0b3b54c9971dc7300337f401c32b261b8db576d5..8a85f5004d41c095e3e346c046b8bf0c5e8b8217 100644 (file)
@@ -897,7 +897,7 @@ static int wm8985_set_bias_level(struct snd_soc_codec *codec,
                                    1 << WM8985_VMIDSEL_SHIFT);
                break;
        case SND_SOC_BIAS_STANDBY:
-               if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) {
+               if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_OFF) {
                        ret = regulator_bulk_enable(ARRAY_SIZE(wm8985->supplies),
                                                    wm8985->supplies);
                        if (ret) {
@@ -957,7 +957,6 @@ static int wm8985_set_bias_level(struct snd_soc_codec *codec,
                break;
        }
 
-       codec->dapm.bias_level = level;
        return 0;
 }
 
index 24968aa8618a52e705fdbfe3f04de156abb5a6da..f13a995af2773441af988585c11445fb13038367 100644 (file)
@@ -738,7 +738,7 @@ static int wm8988_set_bias_level(struct snd_soc_codec *codec,
                break;
 
        case SND_SOC_BIAS_STANDBY:
-               if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) {
+               if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_OFF) {
                        regcache_sync(wm8988->regmap);
 
                        /* VREF, VMID=2x5k */
@@ -756,7 +756,6 @@ static int wm8988_set_bias_level(struct snd_soc_codec *codec,
                snd_soc_write(codec, WM8988_PWR1, 0x0000);
                break;
        }
-       codec->dapm.bias_level = level;
        return 0;
 }
 
index c93bffcb3cfba2e3953b53b571e046a9553ff5a0..1993fd2a6f15b3b8217bd3fbf56e0145a99980b1 100644 (file)
@@ -1124,7 +1124,7 @@ static int wm8990_set_bias_level(struct snd_soc_codec *codec,
                break;
 
        case SND_SOC_BIAS_STANDBY:
-               if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) {
+               if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_OFF) {
                        ret = regcache_sync(wm8990->regmap);
                        if (ret < 0) {
                                dev_err(codec->dev, "Failed to sync cache: %d\n", ret);
@@ -1227,7 +1227,6 @@ static int wm8990_set_bias_level(struct snd_soc_codec *codec,
                break;
        }
 
-       codec->dapm.bias_level = level;
        return 0;
 }
 
@@ -1281,7 +1280,7 @@ static int wm8990_probe(struct snd_soc_codec *codec)
        wm8990_reset(codec);
 
        /* charge output caps */
-       wm8990_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
+       snd_soc_codec_force_bias_level(codec, SND_SOC_BIAS_STANDBY);
 
        snd_soc_update_bits(codec, WM8990_AUDIO_INTERFACE_4,
                            WM8990_ALRCGPIO1, WM8990_ALRCGPIO1);
index 49df0dc607e67f41252cd6c56eb38cc0abdf06dc..44a677720828e013b52ae71330d8f0c3359b3a1b 100644 (file)
@@ -1131,7 +1131,7 @@ static int wm8991_set_bias_level(struct snd_soc_codec *codec,
                break;
 
        case SND_SOC_BIAS_STANDBY:
-               if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) {
+               if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_OFF) {
                        regcache_sync(wm8991->regmap);
                        /* Enable all output discharge bits */
                        snd_soc_write(codec, WM8991_ANTIPOP1, WM8991_DIS_LLINE |
@@ -1224,7 +1224,6 @@ static int wm8991_set_bias_level(struct snd_soc_codec *codec,
                break;
        }
 
-       codec->dapm.bias_level = level;
        return 0;
 }
 
index 2e70a270eb2894f36ccb5cacd3fd618dee45256c..8a8db8605dc2e72acd5ab0e70149834d06ba7bf0 100644 (file)
@@ -992,7 +992,7 @@ static int wm8993_set_bias_level(struct snd_soc_codec *codec,
                break;
 
        case SND_SOC_BIAS_STANDBY:
-               if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) {
+               if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_OFF) {
                        ret = regulator_bulk_enable(ARRAY_SIZE(wm8993->supplies),
                                                    wm8993->supplies);
                        if (ret != 0)
@@ -1065,8 +1065,6 @@ static int wm8993_set_bias_level(struct snd_soc_codec *codec,
                break;
        }
 
-       codec->dapm.bias_level = level;
-
        return 0;
 }
 
@@ -1485,7 +1483,7 @@ static struct snd_soc_dai_driver wm8993_dai = {
 static int wm8993_probe(struct snd_soc_codec *codec)
 {
        struct wm8993_priv *wm8993 = snd_soc_codec_get_drvdata(codec);
-       struct snd_soc_dapm_context *dapm = &codec->dapm;
+       struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
 
        wm8993->hubs_data.hp_startup_mode = 1;
        wm8993->hubs_data.dcs_codes_l = -2;
@@ -1539,7 +1537,7 @@ static int wm8993_probe(struct snd_soc_codec *codec)
         * VMID as an output and can disable it.
         */
        if (wm8993->pdata.lineout1_diff && wm8993->pdata.lineout2_diff)
-               codec->dapm.idle_bias_off = 1;
+               dapm->idle_bias_off = 1;
 
        return 0;
 
@@ -1563,7 +1561,7 @@ static int wm8993_suspend(struct snd_soc_codec *codec)
        wm8993->fll_fout = fll_fout;
        wm8993->fll_fref = fll_fref;
 
-       wm8993_set_bias_level(codec, SND_SOC_BIAS_OFF);
+       snd_soc_codec_force_bias_level(codec, SND_SOC_BIAS_OFF);
 
        return 0;
 }
@@ -1573,7 +1571,7 @@ static int wm8993_resume(struct snd_soc_codec *codec)
        struct wm8993_priv *wm8993 = snd_soc_codec_get_drvdata(codec);
        int ret;
 
-       wm8993_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
+       snd_soc_codec_force_bias_level(codec, SND_SOC_BIAS_STANDBY);
 
        /* Restart the FLL? */
        if (wm8993->fll_fout) {
index 4fbc7689339a8903f724fa9aefcb6feb31dad54f..962e1d31a629bb8b6a18c47065c4fab4b6afe5cf 100644 (file)
@@ -212,6 +212,7 @@ static int configure_aif_clock(struct snd_soc_codec *codec, int aif)
 
 static int configure_clock(struct snd_soc_codec *codec)
 {
+       struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
        struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
        int change, new;
 
@@ -239,7 +240,7 @@ static int configure_clock(struct snd_soc_codec *codec)
        change = snd_soc_update_bits(codec, WM8994_CLOCKING_1,
                                     WM8994_SYSCLK_SRC, new);
        if (change)
-               snd_soc_dapm_sync(&codec->dapm);
+               snd_soc_dapm_sync(dapm);
 
        wm8958_micd_set_rate(codec);
 
@@ -2492,12 +2493,12 @@ static int wm8994_set_bias_level(struct snd_soc_codec *codec,
                        break;
                }
 
-               if (codec->dapm.bias_level == SND_SOC_BIAS_STANDBY)
+               if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_STANDBY)
                        active_reference(codec);
                break;
 
        case SND_SOC_BIAS_STANDBY:
-               if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) {
+               if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_OFF) {
                        switch (control->type) {
                        case WM8958:
                                if (control->revision == 0) {
@@ -2521,7 +2522,7 @@ static int wm8994_set_bias_level(struct snd_soc_codec *codec,
                                            WM8994_LINEOUT2_DISCH);
                }
 
-               if (codec->dapm.bias_level == SND_SOC_BIAS_PREPARE)
+               if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_PREPARE)
                        active_dereference(codec);
 
                /* MICBIAS into bypass mode on newer devices */
@@ -2541,20 +2542,18 @@ static int wm8994_set_bias_level(struct snd_soc_codec *codec,
                break;
 
        case SND_SOC_BIAS_OFF:
-               if (codec->dapm.bias_level == SND_SOC_BIAS_STANDBY)
+               if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_STANDBY)
                        wm8994->cur_fw = NULL;
                break;
        }
 
-       codec->dapm.bias_level = level;
-
        return 0;
 }
 
 int wm8994_vmid_mode(struct snd_soc_codec *codec, enum wm8994_vmid_mode mode)
 {
        struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
-       struct snd_soc_dapm_context *dapm = &codec->dapm;
+       struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
 
        switch (mode) {
        case WM8994_VMID_NORMAL:
@@ -2754,7 +2753,7 @@ static struct {
 };
 
 static int fs_ratios[] = {
-       64, 128, 192, 256, 348, 512, 768, 1024, 1408, 1536
+       64, 128, 192, 256, 384, 512, 768, 1024, 1408, 1536
 };
 
 static int bclk_divs[] = {
@@ -3163,7 +3162,7 @@ static int wm8994_codec_suspend(struct snd_soc_codec *codec)
                                 i + 1, ret);
        }
 
-       wm8994_set_bias_level(codec, SND_SOC_BIAS_OFF);
+       snd_soc_codec_force_bias_level(codec, SND_SOC_BIAS_OFF);
 
        return 0;
 }
@@ -3356,6 +3355,7 @@ static void wm8994_handle_pdata(struct wm8994_priv *wm8994)
 int wm8994_mic_detect(struct snd_soc_codec *codec, struct snd_soc_jack *jack,
                      int micbias)
 {
+       struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
        struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
        struct wm8994_micdet *micdet;
        struct wm8994 *control = wm8994->wm8994;
@@ -3370,20 +3370,16 @@ int wm8994_mic_detect(struct snd_soc_codec *codec, struct snd_soc_jack *jack,
        case 1:
                micdet = &wm8994->micdet[0];
                if (jack)
-                       ret = snd_soc_dapm_force_enable_pin(&codec->dapm,
-                                                           "MICBIAS1");
+                       ret = snd_soc_dapm_force_enable_pin(dapm, "MICBIAS1");
                else
-                       ret = snd_soc_dapm_disable_pin(&codec->dapm,
-                                                      "MICBIAS1");
+                       ret = snd_soc_dapm_disable_pin(dapm, "MICBIAS1");
                break;
        case 2:
                micdet = &wm8994->micdet[1];
                if (jack)
-                       ret = snd_soc_dapm_force_enable_pin(&codec->dapm,
-                                                           "MICBIAS1");
+                       ret = snd_soc_dapm_force_enable_pin(dapm, "MICBIAS1");
                else
-                       ret = snd_soc_dapm_disable_pin(&codec->dapm,
-                                                      "MICBIAS1");
+                       ret = snd_soc_dapm_disable_pin(dapm, "MICBIAS1");
                break;
        default:
                dev_warn(codec->dev, "Invalid MICBIAS %d\n", micbias);
@@ -3415,7 +3411,7 @@ int wm8994_mic_detect(struct snd_soc_codec *codec, struct snd_soc_jack *jack,
                            WM8994_MIC2_DET_DB_MASK | WM8994_MIC2_SHRT_DB_MASK,
                            WM8994_MIC1_DET_DB | WM8994_MIC1_SHRT_DB);
 
-       snd_soc_dapm_sync(&codec->dapm);
+       snd_soc_dapm_sync(dapm);
 
        return 0;
 }
@@ -3505,6 +3501,7 @@ static irqreturn_t wm8994_mic_irq(int irq, void *data)
 /* Should be called with accdet_lock held */
 static void wm1811_micd_stop(struct snd_soc_codec *codec)
 {
+       struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
        struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
 
        if (!wm8994->jackdet)
@@ -3515,8 +3512,7 @@ static void wm1811_micd_stop(struct snd_soc_codec *codec)
        wm1811_jackdet_set_mode(codec, WM1811_JACKDET_MODE_JACK);
 
        if (wm8994->wm8994->pdata.jd_ext_cap)
-               snd_soc_dapm_disable_pin(&codec->dapm,
-                                        "MICBIAS2");
+               snd_soc_dapm_disable_pin(dapm, "MICBIAS2");
 }
 
 static void wm8958_button_det(struct snd_soc_codec *codec, u16 status)
@@ -3625,14 +3621,14 @@ static void wm1811_mic_work(struct work_struct *work)
                                                  mic_work.work);
        struct wm8994 *control = wm8994->wm8994;
        struct snd_soc_codec *codec = wm8994->hubs.codec;
+       struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
 
        pm_runtime_get_sync(codec->dev);
 
        /* If required for an external cap force MICBIAS on */
        if (control->pdata.jd_ext_cap) {
-               snd_soc_dapm_force_enable_pin(&codec->dapm,
-                                             "MICBIAS2");
-               snd_soc_dapm_sync(&codec->dapm);
+               snd_soc_dapm_force_enable_pin(dapm, "MICBIAS2");
+               snd_soc_dapm_sync(dapm);
        }
 
        mutex_lock(&wm8994->accdet_lock);
@@ -3664,6 +3660,7 @@ static irqreturn_t wm1811_jackdet_irq(int irq, void *data)
        struct wm8994_priv *wm8994 = data;
        struct wm8994 *control = wm8994->wm8994;
        struct snd_soc_codec *codec = wm8994->hubs.codec;
+       struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
        int reg, delay;
        bool present;
 
@@ -3724,7 +3721,7 @@ static irqreturn_t wm1811_jackdet_irq(int irq, void *data)
 
        /* Turn off MICBIAS if it was on for an external cap */
        if (control->pdata.jd_ext_cap && !present)
-               snd_soc_dapm_disable_pin(&codec->dapm, "MICBIAS2");
+               snd_soc_dapm_disable_pin(dapm, "MICBIAS2");
 
        if (present)
                snd_soc_jack_report(wm8994->micdet[0].jack,
@@ -3770,6 +3767,7 @@ int wm8958_mic_detect(struct snd_soc_codec *codec, struct snd_soc_jack *jack,
                      wm1811_micdet_cb det_cb, void *det_cb_data,
                      wm1811_mic_id_cb id_cb, void *id_cb_data)
 {
+       struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
        struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
        struct wm8994 *control = wm8994->wm8994;
        u16 micd_lvl_sel;
@@ -3783,8 +3781,8 @@ int wm8958_mic_detect(struct snd_soc_codec *codec, struct snd_soc_jack *jack,
        }
 
        if (jack) {
-               snd_soc_dapm_force_enable_pin(&codec->dapm, "CLK_SYS");
-               snd_soc_dapm_sync(&codec->dapm);
+               snd_soc_dapm_force_enable_pin(dapm, "CLK_SYS");
+               snd_soc_dapm_sync(dapm);
 
                wm8994->micdet[0].jack = jack;
 
@@ -3819,7 +3817,7 @@ int wm8958_mic_detect(struct snd_soc_codec *codec, struct snd_soc_jack *jack,
                snd_soc_update_bits(codec, WM8958_MIC_DETECT_2,
                                    WM8958_MICD_LVL_SEL_MASK, micd_lvl_sel);
 
-               WARN_ON(codec->dapm.bias_level > SND_SOC_BIAS_STANDBY);
+               WARN_ON(snd_soc_codec_get_bias_level(codec) > SND_SOC_BIAS_STANDBY);
 
                /*
                 * If we can use jack detection start off with that,
@@ -3846,8 +3844,8 @@ int wm8958_mic_detect(struct snd_soc_codec *codec, struct snd_soc_jack *jack,
                snd_soc_update_bits(codec, WM8958_MIC_DETECT_1,
                                    WM8958_MICD_ENA, 0);
                wm1811_jackdet_set_mode(codec, WM1811_JACKDET_MODE_NONE);
-               snd_soc_dapm_disable_pin(&codec->dapm, "CLK_SYS");
-               snd_soc_dapm_sync(&codec->dapm);
+               snd_soc_dapm_disable_pin(dapm, "CLK_SYS");
+               snd_soc_dapm_sync(dapm);
        }
 
        return 0;
@@ -3985,9 +3983,9 @@ static irqreturn_t wm8994_temp_shut(int irq, void *data)
 
 static int wm8994_codec_probe(struct snd_soc_codec *codec)
 {
+       struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
        struct wm8994 *control = dev_get_drvdata(codec->dev->parent);
        struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
-       struct snd_soc_dapm_context *dapm = &codec->dapm;
        unsigned int reg;
        int ret, i;
 
@@ -4018,7 +4016,7 @@ static int wm8994_codec_probe(struct snd_soc_codec *codec)
        wm8994->micdet_irq = control->pdata.micdet_irq;
 
        /* By default use idle_bias_off, will override for WM8994 */
-       codec->dapm.idle_bias_off = 1;
+       dapm->idle_bias_off = 1;
 
        /* Set revision-specific configuration */
        switch (control->type) {
@@ -4026,7 +4024,7 @@ static int wm8994_codec_probe(struct snd_soc_codec *codec)
                /* Single ended line outputs should have VMID on. */
                if (!control->pdata.lineout1_diff ||
                    !control->pdata.lineout2_diff)
-                       codec->dapm.idle_bias_off = 0;
+                       dapm->idle_bias_off = 0;
 
                switch (control->revision) {
                case 2:
@@ -4086,7 +4084,8 @@ static int wm8994_codec_probe(struct snd_soc_codec *codec)
                if (wm8994->micdet_irq)
                        ret = request_threaded_irq(wm8994->micdet_irq, NULL,
                                                   wm8994_mic_irq,
-                                                  IRQF_TRIGGER_RISING,
+                                                  IRQF_TRIGGER_RISING |
+                                                  IRQF_ONESHOT,
                                                   "Mic1 detect",
                                                   wm8994);
                 else
@@ -4134,7 +4133,8 @@ static int wm8994_codec_probe(struct snd_soc_codec *codec)
                if (wm8994->micdet_irq) {
                        ret = request_threaded_irq(wm8994->micdet_irq, NULL,
                                                   wm8958_mic_irq,
-                                                  IRQF_TRIGGER_RISING,
+                                                  IRQF_TRIGGER_RISING |
+                                                  IRQF_ONESHOT,
                                                   "Mic detect",
                                                   wm8994);
                        if (ret != 0)
index 66103c2b012e522062a9d29d5f92a099223c6015..687c4dd7ec994a26c466bfaa77864417839739ec 100644 (file)
@@ -721,6 +721,7 @@ static int configure_aif_clock(struct snd_soc_codec *codec, int aif)
 
 static int configure_clock(struct snd_soc_codec *codec)
 {
+       struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
        struct wm8995_priv *wm8995;
        int change, new;
 
@@ -751,7 +752,7 @@ static int configure_clock(struct snd_soc_codec *codec)
        if (!change)
                return 0;
 
-       snd_soc_dapm_sync(&codec->dapm);
+       snd_soc_dapm_sync(dapm);
 
        return 0;
 }
@@ -1965,7 +1966,7 @@ static int wm8995_set_bias_level(struct snd_soc_codec *codec,
        case SND_SOC_BIAS_PREPARE:
                break;
        case SND_SOC_BIAS_STANDBY:
-               if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) {
+               if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_OFF) {
                        ret = regulator_bulk_enable(ARRAY_SIZE(wm8995->supplies),
                                                    wm8995->supplies);
                        if (ret)
@@ -1990,7 +1991,6 @@ static int wm8995_set_bias_level(struct snd_soc_codec *codec,
                break;
        }
 
-       codec->dapm.bias_level = level;
        return 0;
 }
 
index 308748a022c55214949b9003f81f67dccad2995e..3dd063f682b29f6fa4e1bb1dbdda1a3305c750bc 100644 (file)
@@ -1590,7 +1590,7 @@ static int wm8996_set_bias_level(struct snd_soc_codec *codec,
                break;
 
        case SND_SOC_BIAS_STANDBY:
-               if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) {
+               if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_OFF) {
                        ret = regulator_bulk_enable(ARRAY_SIZE(wm8996->supplies),
                                                    wm8996->supplies);
                        if (ret != 0) {
@@ -1628,8 +1628,6 @@ static int wm8996_set_bias_level(struct snd_soc_codec *codec,
                break;
        }
 
-       codec->dapm.bias_level = level;
-
        return 0;
 }
 
@@ -2247,7 +2245,7 @@ int wm8996_detect(struct snd_soc_codec *codec, struct snd_soc_jack *jack,
                  wm8996_polarity_fn polarity_cb)
 {
        struct wm8996_priv *wm8996 = snd_soc_codec_get_drvdata(codec);
-       struct snd_soc_dapm_context *dapm = &codec->dapm;
+       struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
 
        wm8996->jack = jack;
        wm8996->detecting = true;
@@ -2292,6 +2290,7 @@ EXPORT_SYMBOL_GPL(wm8996_detect);
 
 static void wm8996_hpdet_irq(struct snd_soc_codec *codec)
 {
+       struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
        struct wm8996_priv *wm8996 = snd_soc_codec_get_drvdata(codec);
        int val, reg, report;
 
@@ -2345,12 +2344,14 @@ out:
        snd_soc_update_bits(codec, WM8996_MIC_DETECT_1, WM8996_MICD_ENA,
                            WM8996_MICD_ENA);
 
-       snd_soc_dapm_disable_pin(&codec->dapm, "Bandgap");
-       snd_soc_dapm_sync(&codec->dapm);
+       snd_soc_dapm_disable_pin(dapm, "Bandgap");
+       snd_soc_dapm_sync(dapm);
 }
 
 static void wm8996_hpdet_start(struct snd_soc_codec *codec)
 {
+       struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
+
        /* Unclamp the output, we can't measure while we're shorting it */
        snd_soc_update_bits(codec, WM8996_ANALOGUE_HP_1,
                            WM8996_HPOUT1L_RMV_SHORT |
@@ -2359,8 +2360,8 @@ static void wm8996_hpdet_start(struct snd_soc_codec *codec)
                            WM8996_HPOUT1R_RMV_SHORT);
 
        /* We need bandgap for HPDET */
-       snd_soc_dapm_force_enable_pin(&codec->dapm, "Bandgap");
-       snd_soc_dapm_sync(&codec->dapm);
+       snd_soc_dapm_force_enable_pin(dapm, "Bandgap");
+       snd_soc_dapm_sync(dapm);
 
        /* Go into headphone detect left mode */
        snd_soc_update_bits(codec, WM8996_MIC_DETECT_1, WM8996_MICD_ENA, 0);
@@ -2646,10 +2647,12 @@ static int wm8996_probe(struct snd_soc_codec *codec)
                if (irq_flags & (IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING))
                        ret = request_threaded_irq(i2c->irq, NULL,
                                                   wm8996_edge_irq,
-                                                  irq_flags, "wm8996", codec);
+                                                  irq_flags | IRQF_ONESHOT,
+                                                  "wm8996", codec);
                else
                        ret = request_threaded_irq(i2c->irq, NULL, wm8996_irq,
-                                                  irq_flags, "wm8996", codec);
+                                                  irq_flags | IRQF_ONESHOT,
+                                                  "wm8996", codec);
 
                if (ret == 0) {
                        /* Unmask the interrupt */
index a4d11770630cdd9bd169836c5e14e0f8dfc5633b..4134dc7e12434cb1a1e43b723eb43a9e23bcee52 100644 (file)
@@ -40,7 +40,7 @@ struct wm8997_priv {
 static DECLARE_TLV_DB_SCALE(ana_tlv, 0, 100, 0);
 static DECLARE_TLV_DB_SCALE(eq_tlv, -1200, 100, 0);
 static DECLARE_TLV_DB_SCALE(digital_tlv, -6400, 50, 0);
-static DECLARE_TLV_DB_SCALE(noise_tlv, 0, 600, 0);
+static DECLARE_TLV_DB_SCALE(noise_tlv, -13200, 600, 0);
 static DECLARE_TLV_DB_SCALE(ng_tlv, -10200, 600, 0);
 
 static const struct reg_default wm8997_sysclk_reva_patch[] = {
@@ -106,11 +106,13 @@ static int wm8997_sysclk_ev(struct snd_soc_dapm_widget *w,
                                regmap_write_async(regmap, patch[i].reg,
                                                   patch[i].def);
                break;
-       default:
+       case SND_SOC_DAPM_PRE_PMD:
                break;
+       default:
+               return 0;
        }
 
-       return 0;
+       return arizona_dvfs_sysclk_ev(w, kcontrol, event);
 }
 
 static const char *wm8997_osr_text[] = {
@@ -409,7 +411,8 @@ static const struct snd_kcontrol_new wm8997_aec_loopback_mux =
 
 static const struct snd_soc_dapm_widget wm8997_dapm_widgets[] = {
 SND_SOC_DAPM_SUPPLY("SYSCLK", ARIZONA_SYSTEM_CLOCK_1, ARIZONA_SYSCLK_ENA_SHIFT,
-                   0, wm8997_sysclk_ev, SND_SOC_DAPM_POST_PMU),
+                   0, wm8997_sysclk_ev,
+                   SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
 SND_SOC_DAPM_SUPPLY("ASYNCCLK", ARIZONA_ASYNC_CLOCK_1,
                    ARIZONA_ASYNC_CLK_ENA_SHIFT, 0, NULL, 0),
 SND_SOC_DAPM_SUPPLY("OPCLK", ARIZONA_OUTPUT_SYSTEM_CLOCK,
@@ -1055,13 +1058,14 @@ static struct snd_soc_dai_driver wm8997_dai[] = {
 
 static int wm8997_codec_probe(struct snd_soc_codec *codec)
 {
+       struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
        struct wm8997_priv *priv = snd_soc_codec_get_drvdata(codec);
 
        arizona_init_spk(codec);
 
-       snd_soc_dapm_disable_pin(&codec->dapm, "HAPTICS");
+       snd_soc_dapm_disable_pin(dapm, "HAPTICS");
 
-       priv->core.arizona->dapm = &codec->dapm;
+       priv->core.arizona->dapm = dapm;
 
        return 0;
 }
@@ -1126,6 +1130,8 @@ static int wm8997_probe(struct platform_device *pdev)
        wm8997->core.arizona = arizona;
        wm8997->core.num_inputs = 4;
 
+       arizona_init_dvfs(&wm8997->core);
+
        for (i = 0; i < ARRAY_SIZE(wm8997->fll); i++)
                wm8997->fll[i].vco_mult = 1;
 
index 13a3f335ea5b6cb4bfeecd8ed0eb9ce13a1bb7ce..8a8b1c0f9142180f0bb84d86652b1e8d2f67fd6c 100644 (file)
@@ -838,7 +838,7 @@ static int wm9081_set_bias_level(struct snd_soc_codec *codec,
 
        case SND_SOC_BIAS_STANDBY:
                /* Initial cold start */
-               if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) {
+               if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_OFF) {
                        regcache_cache_only(wm9081->regmap, false);
                        regcache_sync(wm9081->regmap);
 
@@ -898,8 +898,6 @@ static int wm9081_set_bias_level(struct snd_soc_codec *codec,
                break;
        }
 
-       codec->dapm.bias_level = level;
-
        return 0;
 }
 
index 60d243c904f529597399c408c8426c2ca879ccd6..13d23fc797dbb10f1f05b0523e2467d074fdc7ec 100644 (file)
@@ -425,7 +425,7 @@ static const struct snd_soc_dapm_route audio_map_in2_diff[] = {
 static int wm9090_add_controls(struct snd_soc_codec *codec)
 {
        struct wm9090_priv *wm9090 = snd_soc_codec_get_drvdata(codec);
-       struct snd_soc_dapm_context *dapm = &codec->dapm;
+       struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
        int i;
 
        snd_soc_dapm_new_controls(dapm, wm9090_dapm_widgets,
@@ -496,7 +496,7 @@ static int wm9090_set_bias_level(struct snd_soc_codec *codec,
                break;
 
        case SND_SOC_BIAS_STANDBY:
-               if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) {
+               if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_OFF) {
                        /* Restore the register cache */
                        regcache_sync(wm9090->regmap);
                }
@@ -515,8 +515,6 @@ static int wm9090_set_bias_level(struct snd_soc_codec *codec,
                break;
        }
 
-       codec->dapm.bias_level = level;
-
        return 0;
 }
 
index 98c9525bd751fbacb0eec07f6465869cbc3e2aa5..1fda104dfc455cafcf83e13ed210302f8b825fbe 100644 (file)
@@ -610,7 +610,6 @@ static int wm9712_set_bias_level(struct snd_soc_codec *codec,
                ac97_write(codec, AC97_POWERDOWN, 0xffff);
                break;
        }
-       codec->dapm.bias_level = level;
        return 0;
 }
 
@@ -646,7 +645,7 @@ static int wm9712_soc_resume(struct snd_soc_codec *codec)
        if (ret < 0)
                return ret;
 
-       wm9712_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
+       snd_soc_codec_force_bias_level(codec, SND_SOC_BIAS_STANDBY);
 
        if (ret == 0) {
                /* Sync reg_cache with the hardware after cold reset */
index 79552953e1bdc607e4d25c95aa5ab473637be6cc..89cd2d6f57c01d46a8eaf8dd24b81f7cb2a054fb 100644 (file)
@@ -1054,8 +1054,8 @@ static int ac97_aux_prepare(struct snd_pcm_substream *substream,
                          SNDRV_PCM_RATE_48000)
 
 #define WM9713_PCM_FORMATS \
-       (SNDRV_PCM_FORMAT_S16_LE | SNDRV_PCM_FORMAT_S20_3LE | \
-        SNDRV_PCM_FORMAT_S24_LE)
+       (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE | \
+        SNDRV_PCM_FMTBIT_S24_LE)
 
 static const struct snd_soc_dai_ops wm9713_dai_ops_hifi = {
        .prepare        = ac97_hifi_prepare,
@@ -1171,7 +1171,6 @@ static int wm9713_set_bias_level(struct snd_soc_codec *codec,
                ac97_write(codec, AC97_POWERDOWN, 0xffff);
                break;
        }
-       codec->dapm.bias_level = level;
        return 0;
 }
 
@@ -1201,7 +1200,7 @@ static int wm9713_soc_resume(struct snd_soc_codec *codec)
        if (ret < 0)
                return ret;
 
-       wm9713_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
+       snd_soc_codec_force_bias_level(codec, SND_SOC_BIAS_STANDBY);
 
        /* do we need to re-start the PLL ? */
        if (wm9713->pll_in)
index d01c2095452f9a0aaa5a2f1e91d2753fd48b1500..f9f90b0f5db4ea06c47b1ed12a2dfc6c447e6fea 100644 (file)
@@ -23,6 +23,7 @@
 #include <linux/slab.h>
 #include <linux/vmalloc.h>
 #include <linux/workqueue.h>
+#include <linux/debugfs.h>
 #include <sound/core.h>
 #include <sound/pcm.h>
 #include <sound/pcm_params.h>
 #define ADSP2_WDMA_CONFIG_2 0x31
 #define ADSP2_RDMA_CONFIG_1 0x34
 
+#define ADSP2_SCRATCH0        0x40
+#define ADSP2_SCRATCH1        0x41
+#define ADSP2_SCRATCH2        0x42
+#define ADSP2_SCRATCH3        0x43
+
 /*
  * ADSP2 Control
  */
@@ -229,26 +235,197 @@ struct wm_coeff_ctl_ops {
 
 struct wm_coeff_ctl {
        const char *name;
-       struct wm_adsp_alg_region region;
+       const char *fw_name;
+       struct wm_adsp_alg_region alg_region;
        struct wm_coeff_ctl_ops ops;
-       struct wm_adsp *adsp;
-       void *private;
+       struct wm_adsp *dsp;
        unsigned int enabled:1;
        struct list_head list;
        void *cache;
+       unsigned int offset;
        size_t len;
        unsigned int set:1;
        struct snd_kcontrol *kcontrol;
+       unsigned int flags;
+};
+
+#ifdef CONFIG_DEBUG_FS
+static void wm_adsp_debugfs_save_wmfwname(struct wm_adsp *dsp, const char *s)
+{
+       char *tmp = kasprintf(GFP_KERNEL, "%s\n", s);
+
+       mutex_lock(&dsp->debugfs_lock);
+       kfree(dsp->wmfw_file_name);
+       dsp->wmfw_file_name = tmp;
+       mutex_unlock(&dsp->debugfs_lock);
+}
+
+static void wm_adsp_debugfs_save_binname(struct wm_adsp *dsp, const char *s)
+{
+       char *tmp = kasprintf(GFP_KERNEL, "%s\n", s);
+
+       mutex_lock(&dsp->debugfs_lock);
+       kfree(dsp->bin_file_name);
+       dsp->bin_file_name = tmp;
+       mutex_unlock(&dsp->debugfs_lock);
+}
+
+static void wm_adsp_debugfs_clear(struct wm_adsp *dsp)
+{
+       mutex_lock(&dsp->debugfs_lock);
+       kfree(dsp->wmfw_file_name);
+       kfree(dsp->bin_file_name);
+       dsp->wmfw_file_name = NULL;
+       dsp->bin_file_name = NULL;
+       mutex_unlock(&dsp->debugfs_lock);
+}
+
+static ssize_t wm_adsp_debugfs_wmfw_read(struct file *file,
+                                        char __user *user_buf,
+                                        size_t count, loff_t *ppos)
+{
+       struct wm_adsp *dsp = file->private_data;
+       ssize_t ret;
+
+       mutex_lock(&dsp->debugfs_lock);
+
+       if (!dsp->wmfw_file_name || !dsp->running)
+               ret = 0;
+       else
+               ret = simple_read_from_buffer(user_buf, count, ppos,
+                                             dsp->wmfw_file_name,
+                                             strlen(dsp->wmfw_file_name));
+
+       mutex_unlock(&dsp->debugfs_lock);
+       return ret;
+}
+
+static ssize_t wm_adsp_debugfs_bin_read(struct file *file,
+                                       char __user *user_buf,
+                                       size_t count, loff_t *ppos)
+{
+       struct wm_adsp *dsp = file->private_data;
+       ssize_t ret;
+
+       mutex_lock(&dsp->debugfs_lock);
+
+       if (!dsp->bin_file_name || !dsp->running)
+               ret = 0;
+       else
+               ret = simple_read_from_buffer(user_buf, count, ppos,
+                                             dsp->bin_file_name,
+                                             strlen(dsp->bin_file_name));
+
+       mutex_unlock(&dsp->debugfs_lock);
+       return ret;
+}
+
+static const struct {
+       const char *name;
+       const struct file_operations fops;
+} wm_adsp_debugfs_fops[] = {
+       {
+               .name = "wmfw_file_name",
+               .fops = {
+                       .open = simple_open,
+                       .read = wm_adsp_debugfs_wmfw_read,
+               },
+       },
+       {
+               .name = "bin_file_name",
+               .fops = {
+                       .open = simple_open,
+                       .read = wm_adsp_debugfs_bin_read,
+               },
+       },
 };
 
+static void wm_adsp2_init_debugfs(struct wm_adsp *dsp,
+                                 struct snd_soc_codec *codec)
+{
+       struct dentry *root = NULL;
+       char *root_name;
+       int i;
+
+       if (!codec->component.debugfs_root) {
+               adsp_err(dsp, "No codec debugfs root\n");
+               goto err;
+       }
+
+       root_name = kmalloc(PAGE_SIZE, GFP_KERNEL);
+       if (!root_name)
+               goto err;
+
+       snprintf(root_name, PAGE_SIZE, "dsp%d", dsp->num);
+       root = debugfs_create_dir(root_name, codec->component.debugfs_root);
+       kfree(root_name);
+
+       if (!root)
+               goto err;
+
+       if (!debugfs_create_bool("running", S_IRUGO, root, &dsp->running))
+               goto err;
+
+       if (!debugfs_create_x32("fw_id", S_IRUGO, root, &dsp->fw_id))
+               goto err;
+
+       if (!debugfs_create_x32("fw_version", S_IRUGO, root,
+                               &dsp->fw_id_version))
+               goto err;
+
+       for (i = 0; i < ARRAY_SIZE(wm_adsp_debugfs_fops); ++i) {
+               if (!debugfs_create_file(wm_adsp_debugfs_fops[i].name,
+                                        S_IRUGO, root, dsp,
+                                        &wm_adsp_debugfs_fops[i].fops))
+                       goto err;
+       }
+
+       dsp->debugfs_root = root;
+       return;
+
+err:
+       debugfs_remove_recursive(root);
+       adsp_err(dsp, "Failed to create debugfs\n");
+}
+
+static void wm_adsp2_cleanup_debugfs(struct wm_adsp *dsp)
+{
+       wm_adsp_debugfs_clear(dsp);
+       debugfs_remove_recursive(dsp->debugfs_root);
+}
+#else
+static inline void wm_adsp2_init_debugfs(struct wm_adsp *dsp,
+                                        struct snd_soc_codec *codec)
+{
+}
+
+static inline void wm_adsp2_cleanup_debugfs(struct wm_adsp *dsp)
+{
+}
+
+static inline void wm_adsp_debugfs_save_wmfwname(struct wm_adsp *dsp,
+                                                const char *s)
+{
+}
+
+static inline void wm_adsp_debugfs_save_binname(struct wm_adsp *dsp,
+                                               const char *s)
+{
+}
+
+static inline void wm_adsp_debugfs_clear(struct wm_adsp *dsp)
+{
+}
+#endif
+
 static int wm_adsp_fw_get(struct snd_kcontrol *kcontrol,
                          struct snd_ctl_elem_value *ucontrol)
 {
        struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
        struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
-       struct wm_adsp *adsp = snd_soc_codec_get_drvdata(codec);
+       struct wm_adsp *dsp = snd_soc_codec_get_drvdata(codec);
 
-       ucontrol->value.integer.value[0] = adsp[e->shift_l].fw;
+       ucontrol->value.integer.value[0] = dsp[e->shift_l].fw;
 
        return 0;
 }
@@ -258,18 +435,18 @@ static int wm_adsp_fw_put(struct snd_kcontrol *kcontrol,
 {
        struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
        struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
-       struct wm_adsp *adsp = snd_soc_codec_get_drvdata(codec);
+       struct wm_adsp *dsp = snd_soc_codec_get_drvdata(codec);
 
-       if (ucontrol->value.integer.value[0] == adsp[e->shift_l].fw)
+       if (ucontrol->value.integer.value[0] == dsp[e->shift_l].fw)
                return 0;
 
        if (ucontrol->value.integer.value[0] >= WM_ADSP_NUM_FW)
                return -EINVAL;
 
-       if (adsp[e->shift_l].running)
+       if (dsp[e->shift_l].running)
                return -EBUSY;
 
-       adsp[e->shift_l].fw = ucontrol->value.integer.value[0];
+       dsp[e->shift_l].fw = ucontrol->value.integer.value[0];
 
        return 0;
 }
@@ -291,7 +468,6 @@ const struct snd_kcontrol_new wm_adsp1_fw_controls[] = {
 };
 EXPORT_SYMBOL_GPL(wm_adsp1_fw_controls);
 
-#if IS_ENABLED(CONFIG_SND_SOC_ARIZONA)
 static const struct soc_enum wm_adsp2_rate_enum[] = {
        SOC_VALUE_ENUM_SINGLE(ARIZONA_DSP1_CONTROL_1,
                              ARIZONA_DSP1_RATE_SHIFT, 0xf,
@@ -311,22 +487,28 @@ static const struct soc_enum wm_adsp2_rate_enum[] = {
                              arizona_rate_text, arizona_rate_val),
 };
 
-const struct snd_kcontrol_new wm_adsp2_fw_controls[] = {
-       SOC_ENUM_EXT("DSP1 Firmware", wm_adsp_fw_enum[0],
-                    wm_adsp_fw_get, wm_adsp_fw_put),
-       SOC_ENUM("DSP1 Rate", wm_adsp2_rate_enum[0]),
-       SOC_ENUM_EXT("DSP2 Firmware", wm_adsp_fw_enum[1],
-                    wm_adsp_fw_get, wm_adsp_fw_put),
-       SOC_ENUM("DSP2 Rate", wm_adsp2_rate_enum[1]),
-       SOC_ENUM_EXT("DSP3 Firmware", wm_adsp_fw_enum[2],
-                    wm_adsp_fw_get, wm_adsp_fw_put),
-       SOC_ENUM("DSP3 Rate", wm_adsp2_rate_enum[2]),
-       SOC_ENUM_EXT("DSP4 Firmware", wm_adsp_fw_enum[3],
-                    wm_adsp_fw_get, wm_adsp_fw_put),
-       SOC_ENUM("DSP4 Rate", wm_adsp2_rate_enum[3]),
+static const struct snd_kcontrol_new wm_adsp2_fw_controls[4][2] = {
+       {
+               SOC_ENUM_EXT("DSP1 Firmware", wm_adsp_fw_enum[0],
+                            wm_adsp_fw_get, wm_adsp_fw_put),
+               SOC_ENUM("DSP1 Rate", wm_adsp2_rate_enum[0]),
+       },
+       {
+               SOC_ENUM_EXT("DSP2 Firmware", wm_adsp_fw_enum[1],
+                            wm_adsp_fw_get, wm_adsp_fw_put),
+               SOC_ENUM("DSP2 Rate", wm_adsp2_rate_enum[1]),
+       },
+       {
+               SOC_ENUM_EXT("DSP3 Firmware", wm_adsp_fw_enum[2],
+                            wm_adsp_fw_get, wm_adsp_fw_put),
+               SOC_ENUM("DSP3 Rate", wm_adsp2_rate_enum[2]),
+       },
+       {
+               SOC_ENUM_EXT("DSP4 Firmware", wm_adsp_fw_enum[3],
+                            wm_adsp_fw_get, wm_adsp_fw_put),
+               SOC_ENUM("DSP4 Rate", wm_adsp2_rate_enum[3]),
+       },
 };
-EXPORT_SYMBOL_GPL(wm_adsp2_fw_controls);
-#endif
 
 static struct wm_adsp_region const *wm_adsp_find_region(struct wm_adsp *dsp,
                                                        int type)
@@ -340,28 +522,47 @@ static struct wm_adsp_region const *wm_adsp_find_region(struct wm_adsp *dsp,
        return NULL;
 }
 
-static unsigned int wm_adsp_region_to_reg(struct wm_adsp_region const *region,
+static unsigned int wm_adsp_region_to_reg(struct wm_adsp_region const *mem,
                                          unsigned int offset)
 {
-       if (WARN_ON(!region))
+       if (WARN_ON(!mem))
                return offset;
-       switch (region->type) {
+       switch (mem->type) {
        case WMFW_ADSP1_PM:
-               return region->base + (offset * 3);
+               return mem->base + (offset * 3);
        case WMFW_ADSP1_DM:
-               return region->base + (offset * 2);
+               return mem->base + (offset * 2);
        case WMFW_ADSP2_XM:
-               return region->base + (offset * 2);
+               return mem->base + (offset * 2);
        case WMFW_ADSP2_YM:
-               return region->base + (offset * 2);
+               return mem->base + (offset * 2);
        case WMFW_ADSP1_ZM:
-               return region->base + (offset * 2);
+               return mem->base + (offset * 2);
        default:
                WARN(1, "Unknown memory region type");
                return offset;
        }
 }
 
+static void wm_adsp2_show_fw_status(struct wm_adsp *dsp)
+{
+       u16 scratch[4];
+       int ret;
+
+       ret = regmap_raw_read(dsp->regmap, dsp->base + ADSP2_SCRATCH0,
+                               scratch, sizeof(scratch));
+       if (ret) {
+               adsp_err(dsp, "Failed to read SCRATCH regs: %d\n", ret);
+               return;
+       }
+
+       adsp_dbg(dsp, "FW SCRATCH 0:0x%x 1:0x%x 2:0x%x 3:0x%x\n",
+                be16_to_cpu(scratch[0]),
+                be16_to_cpu(scratch[1]),
+                be16_to_cpu(scratch[2]),
+                be16_to_cpu(scratch[3]));
+}
+
 static int wm_coeff_info(struct snd_kcontrol *kcontrol,
                         struct snd_ctl_elem_info *uinfo)
 {
@@ -372,40 +573,39 @@ static int wm_coeff_info(struct snd_kcontrol *kcontrol,
        return 0;
 }
 
-static int wm_coeff_write_control(struct snd_kcontrol *kcontrol,
+static int wm_coeff_write_control(struct wm_coeff_ctl *ctl,
                                  const void *buf, size_t len)
 {
-       struct wm_coeff_ctl *ctl = (struct wm_coeff_ctl *)kcontrol->private_value;
-       struct wm_adsp_alg_region *region = &ctl->region;
+       struct wm_adsp_alg_region *alg_region = &ctl->alg_region;
        const struct wm_adsp_region *mem;
-       struct wm_adsp *adsp = ctl->adsp;
+       struct wm_adsp *dsp = ctl->dsp;
        void *scratch;
        int ret;
        unsigned int reg;
 
-       mem = wm_adsp_find_region(adsp, region->type);
+       mem = wm_adsp_find_region(dsp, alg_region->type);
        if (!mem) {
-               adsp_err(adsp, "No base for region %x\n",
-                        region->type);
+               adsp_err(dsp, "No base for region %x\n",
+                        alg_region->type);
                return -EINVAL;
        }
 
-       reg = ctl->region.base;
+       reg = ctl->alg_region.base + ctl->offset;
        reg = wm_adsp_region_to_reg(mem, reg);
 
        scratch = kmemdup(buf, ctl->len, GFP_KERNEL | GFP_DMA);
        if (!scratch)
                return -ENOMEM;
 
-       ret = regmap_raw_write(adsp->regmap, reg, scratch,
+       ret = regmap_raw_write(dsp->regmap, reg, scratch,
                               ctl->len);
        if (ret) {
-               adsp_err(adsp, "Failed to write %zu bytes to %x: %d\n",
+               adsp_err(dsp, "Failed to write %zu bytes to %x: %d\n",
                         ctl->len, reg, ret);
                kfree(scratch);
                return ret;
        }
-       adsp_dbg(adsp, "Wrote %zu bytes to %x\n", ctl->len, reg);
+       adsp_dbg(dsp, "Wrote %zu bytes to %x\n", ctl->len, reg);
 
        kfree(scratch);
 
@@ -424,42 +624,41 @@ static int wm_coeff_put(struct snd_kcontrol *kcontrol,
        if (!ctl->enabled)
                return 0;
 
-       return wm_coeff_write_control(kcontrol, p, ctl->len);
+       return wm_coeff_write_control(ctl, p, ctl->len);
 }
 
-static int wm_coeff_read_control(struct snd_kcontrol *kcontrol,
+static int wm_coeff_read_control(struct wm_coeff_ctl *ctl,
                                 void *buf, size_t len)
 {
-       struct wm_coeff_ctl *ctl = (struct wm_coeff_ctl *)kcontrol->private_value;
-       struct wm_adsp_alg_region *region = &ctl->region;
+       struct wm_adsp_alg_region *alg_region = &ctl->alg_region;
        const struct wm_adsp_region *mem;
-       struct wm_adsp *adsp = ctl->adsp;
+       struct wm_adsp *dsp = ctl->dsp;
        void *scratch;
        int ret;
        unsigned int reg;
 
-       mem = wm_adsp_find_region(adsp, region->type);
+       mem = wm_adsp_find_region(dsp, alg_region->type);
        if (!mem) {
-               adsp_err(adsp, "No base for region %x\n",
-                        region->type);
+               adsp_err(dsp, "No base for region %x\n",
+                        alg_region->type);
                return -EINVAL;
        }
 
-       reg = ctl->region.base;
+       reg = ctl->alg_region.base + ctl->offset;
        reg = wm_adsp_region_to_reg(mem, reg);
 
        scratch = kmalloc(ctl->len, GFP_KERNEL | GFP_DMA);
        if (!scratch)
                return -ENOMEM;
 
-       ret = regmap_raw_read(adsp->regmap, reg, scratch, ctl->len);
+       ret = regmap_raw_read(dsp->regmap, reg, scratch, ctl->len);
        if (ret) {
-               adsp_err(adsp, "Failed to read %zu bytes from %x: %d\n",
+               adsp_err(dsp, "Failed to read %zu bytes from %x: %d\n",
                         ctl->len, reg, ret);
                kfree(scratch);
                return ret;
        }
-       adsp_dbg(adsp, "Read %zu bytes from %x\n", ctl->len, reg);
+       adsp_dbg(dsp, "Read %zu bytes from %x\n", ctl->len, reg);
 
        memcpy(buf, scratch, ctl->len);
        kfree(scratch);
@@ -473,17 +672,25 @@ static int wm_coeff_get(struct snd_kcontrol *kcontrol,
        struct wm_coeff_ctl *ctl = (struct wm_coeff_ctl *)kcontrol->private_value;
        char *p = ucontrol->value.bytes.data;
 
+       if (ctl->flags & WMFW_CTL_FLAG_VOLATILE) {
+               if (ctl->enabled)
+                       return wm_coeff_read_control(ctl, p, ctl->len);
+               else
+                       return -EPERM;
+       }
+
        memcpy(p, ctl->cache, ctl->len);
+
        return 0;
 }
 
 struct wmfw_ctl_work {
-       struct wm_adsp *adsp;
+       struct wm_adsp *dsp;
        struct wm_coeff_ctl *ctl;
        struct work_struct work;
 };
 
-static int wmfw_add_ctl(struct wm_adsp *adsp, struct wm_coeff_ctl *ctl)
+static int wmfw_add_ctl(struct wm_adsp *dsp, struct wm_coeff_ctl *ctl)
 {
        struct snd_kcontrol_new *kcontrol;
        int ret;
@@ -502,17 +709,25 @@ static int wmfw_add_ctl(struct wm_adsp *adsp, struct wm_coeff_ctl *ctl)
        kcontrol->put = wm_coeff_put;
        kcontrol->private_value = (unsigned long)ctl;
 
-       ret = snd_soc_add_card_controls(adsp->card,
+       if (ctl->flags) {
+               if (ctl->flags & WMFW_CTL_FLAG_WRITEABLE)
+                       kcontrol->access |= SNDRV_CTL_ELEM_ACCESS_WRITE;
+               if (ctl->flags & WMFW_CTL_FLAG_READABLE)
+                       kcontrol->access |= SNDRV_CTL_ELEM_ACCESS_READ;
+               if (ctl->flags & WMFW_CTL_FLAG_VOLATILE)
+                       kcontrol->access |= SNDRV_CTL_ELEM_ACCESS_VOLATILE;
+       }
+
+       ret = snd_soc_add_card_controls(dsp->card,
                                        kcontrol, 1);
        if (ret < 0)
                goto err_kcontrol;
 
        kfree(kcontrol);
 
-       ctl->kcontrol = snd_soc_card_get_kcontrol(adsp->card,
+       ctl->kcontrol = snd_soc_card_get_kcontrol(dsp->card,
                                                  ctl->name);
 
-       list_add(&ctl->list, &adsp->ctl_list);
        return 0;
 
 err_kcontrol:
@@ -520,6 +735,358 @@ err_kcontrol:
        return ret;
 }
 
+static int wm_coeff_init_control_caches(struct wm_adsp *dsp)
+{
+       struct wm_coeff_ctl *ctl;
+       int ret;
+
+       list_for_each_entry(ctl, &dsp->ctl_list, list) {
+               if (!ctl->enabled || ctl->set)
+                       continue;
+               if (ctl->flags & WMFW_CTL_FLAG_VOLATILE)
+                       continue;
+
+               ret = wm_coeff_read_control(ctl,
+                                           ctl->cache,
+                                           ctl->len);
+               if (ret < 0)
+                       return ret;
+       }
+
+       return 0;
+}
+
+static int wm_coeff_sync_controls(struct wm_adsp *dsp)
+{
+       struct wm_coeff_ctl *ctl;
+       int ret;
+
+       list_for_each_entry(ctl, &dsp->ctl_list, list) {
+               if (!ctl->enabled)
+                       continue;
+               if (ctl->set && !(ctl->flags & WMFW_CTL_FLAG_VOLATILE)) {
+                       ret = wm_coeff_write_control(ctl,
+                                                    ctl->cache,
+                                                    ctl->len);
+                       if (ret < 0)
+                               return ret;
+               }
+       }
+
+       return 0;
+}
+
+static void wm_adsp_ctl_work(struct work_struct *work)
+{
+       struct wmfw_ctl_work *ctl_work = container_of(work,
+                                                     struct wmfw_ctl_work,
+                                                     work);
+
+       wmfw_add_ctl(ctl_work->dsp, ctl_work->ctl);
+       kfree(ctl_work);
+}
+
+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)
+{
+       struct wm_coeff_ctl *ctl;
+       struct wmfw_ctl_work *ctl_work;
+       char name[SNDRV_CTL_ELEM_ID_NAME_MAXLEN];
+       char *region_name;
+       int ret;
+
+       if (flags & WMFW_CTL_FLAG_SYS)
+               return 0;
+
+       switch (alg_region->type) {
+       case WMFW_ADSP1_PM:
+               region_name = "PM";
+               break;
+       case WMFW_ADSP1_DM:
+               region_name = "DM";
+               break;
+       case WMFW_ADSP2_XM:
+               region_name = "XM";
+               break;
+       case WMFW_ADSP2_YM:
+               region_name = "YM";
+               break;
+       case WMFW_ADSP1_ZM:
+               region_name = "ZM";
+               break;
+       default:
+               adsp_err(dsp, "Unknown region type: %d\n", alg_region->type);
+               return -EINVAL;
+       }
+
+       switch (dsp->fw_ver) {
+       case 0:
+       case 1:
+               snprintf(name, SNDRV_CTL_ELEM_ID_NAME_MAXLEN, "DSP%d %s %x",
+                        dsp->num, region_name, alg_region->alg);
+               break;
+       default:
+               ret = snprintf(name, SNDRV_CTL_ELEM_ID_NAME_MAXLEN,
+                               "DSP%d%c %.12s %x", dsp->num, *region_name,
+                               wm_adsp_fw_text[dsp->fw], alg_region->alg);
+
+               /* Truncate the subname from the start if it is too long */
+               if (subname) {
+                       int avail = SNDRV_CTL_ELEM_ID_NAME_MAXLEN - ret - 2;
+                       int skip = 0;
+
+                       if (subname_len > avail)
+                               skip = subname_len - avail;
+
+                       snprintf(name + ret,
+                                SNDRV_CTL_ELEM_ID_NAME_MAXLEN - ret, " %.*s",
+                                subname_len - skip, subname + skip);
+               }
+               break;
+       }
+
+       list_for_each_entry(ctl, &dsp->ctl_list,
+                           list) {
+               if (!strcmp(ctl->name, name)) {
+                       if (!ctl->enabled)
+                               ctl->enabled = 1;
+                       return 0;
+               }
+       }
+
+       ctl = kzalloc(sizeof(*ctl), GFP_KERNEL);
+       if (!ctl)
+               return -ENOMEM;
+       ctl->fw_name = wm_adsp_fw_text[dsp->fw];
+       ctl->alg_region = *alg_region;
+       ctl->name = kmemdup(name, strlen(name) + 1, GFP_KERNEL);
+       if (!ctl->name) {
+               ret = -ENOMEM;
+               goto err_ctl;
+       }
+       ctl->enabled = 1;
+       ctl->set = 0;
+       ctl->ops.xget = wm_coeff_get;
+       ctl->ops.xput = wm_coeff_put;
+       ctl->dsp = dsp;
+
+       ctl->flags = flags;
+       ctl->offset = offset;
+       if (len > 512) {
+               adsp_warn(dsp, "Truncating control %s from %d\n",
+                         ctl->name, len);
+               len = 512;
+       }
+       ctl->len = len;
+       ctl->cache = kzalloc(ctl->len, GFP_KERNEL);
+       if (!ctl->cache) {
+               ret = -ENOMEM;
+               goto err_ctl_name;
+       }
+
+       list_add(&ctl->list, &dsp->ctl_list);
+
+       ctl_work = kzalloc(sizeof(*ctl_work), GFP_KERNEL);
+       if (!ctl_work) {
+               ret = -ENOMEM;
+               goto err_ctl_cache;
+       }
+
+       ctl_work->dsp = dsp;
+       ctl_work->ctl = ctl;
+       INIT_WORK(&ctl_work->work, wm_adsp_ctl_work);
+       schedule_work(&ctl_work->work);
+
+       return 0;
+
+err_ctl_cache:
+       kfree(ctl->cache);
+err_ctl_name:
+       kfree(ctl->name);
+err_ctl:
+       kfree(ctl);
+
+       return ret;
+}
+
+struct wm_coeff_parsed_alg {
+       int id;
+       const u8 *name;
+       int name_len;
+       int ncoeff;
+};
+
+struct wm_coeff_parsed_coeff {
+       int offset;
+       int mem_type;
+       const u8 *name;
+       int name_len;
+       int ctl_type;
+       int flags;
+       int len;
+};
+
+static int wm_coeff_parse_string(int bytes, const u8 **pos, const u8 **str)
+{
+       int length;
+
+       switch (bytes) {
+       case 1:
+               length = **pos;
+               break;
+       case 2:
+               length = le16_to_cpu(*((__le16 *)*pos));
+               break;
+       default:
+               return 0;
+       }
+
+       if (str)
+               *str = *pos + bytes;
+
+       *pos += ((length + bytes) + 3) & ~0x03;
+
+       return length;
+}
+
+static int wm_coeff_parse_int(int bytes, const u8 **pos)
+{
+       int val = 0;
+
+       switch (bytes) {
+       case 2:
+               val = le16_to_cpu(*((__le16 *)*pos));
+               break;
+       case 4:
+               val = le32_to_cpu(*((__le32 *)*pos));
+               break;
+       default:
+               break;
+       }
+
+       *pos += bytes;
+
+       return val;
+}
+
+static inline void wm_coeff_parse_alg(struct wm_adsp *dsp, const u8 **data,
+                                     struct wm_coeff_parsed_alg *blk)
+{
+       const struct wmfw_adsp_alg_data *raw;
+
+       switch (dsp->fw_ver) {
+       case 0:
+       case 1:
+               raw = (const struct wmfw_adsp_alg_data *)*data;
+               *data = raw->data;
+
+               blk->id = le32_to_cpu(raw->id);
+               blk->name = raw->name;
+               blk->name_len = strlen(raw->name);
+               blk->ncoeff = le32_to_cpu(raw->ncoeff);
+               break;
+       default:
+               blk->id = wm_coeff_parse_int(sizeof(raw->id), data);
+               blk->name_len = wm_coeff_parse_string(sizeof(u8), data,
+                                                     &blk->name);
+               wm_coeff_parse_string(sizeof(u16), data, NULL);
+               blk->ncoeff = wm_coeff_parse_int(sizeof(raw->ncoeff), data);
+               break;
+       }
+
+       adsp_dbg(dsp, "Algorithm ID: %#x\n", blk->id);
+       adsp_dbg(dsp, "Algorithm name: %.*s\n", blk->name_len, blk->name);
+       adsp_dbg(dsp, "# of coefficient descriptors: %#x\n", blk->ncoeff);
+}
+
+static inline void wm_coeff_parse_coeff(struct wm_adsp *dsp, const u8 **data,
+                                       struct wm_coeff_parsed_coeff *blk)
+{
+       const struct wmfw_adsp_coeff_data *raw;
+       const u8 *tmp;
+       int length;
+
+       switch (dsp->fw_ver) {
+       case 0:
+       case 1:
+               raw = (const struct wmfw_adsp_coeff_data *)*data;
+               *data = *data + sizeof(raw->hdr) + le32_to_cpu(raw->hdr.size);
+
+               blk->offset = le16_to_cpu(raw->hdr.offset);
+               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->flags = le16_to_cpu(raw->flags);
+               blk->len = le32_to_cpu(raw->len);
+               break;
+       default:
+               tmp = *data;
+               blk->offset = wm_coeff_parse_int(sizeof(raw->hdr.offset), &tmp);
+               blk->mem_type = wm_coeff_parse_int(sizeof(raw->hdr.type), &tmp);
+               length = wm_coeff_parse_int(sizeof(raw->hdr.size), &tmp);
+               blk->name_len = wm_coeff_parse_string(sizeof(u8), &tmp,
+                                                     &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->flags = wm_coeff_parse_int(sizeof(raw->flags), &tmp);
+               blk->len = wm_coeff_parse_int(sizeof(raw->len), &tmp);
+
+               *data = *data + sizeof(raw->hdr) + length;
+               break;
+       }
+
+       adsp_dbg(dsp, "\tCoefficient type: %#x\n", blk->mem_type);
+       adsp_dbg(dsp, "\tCoefficient offset: %#x\n", blk->offset);
+       adsp_dbg(dsp, "\tCoefficient name: %.*s\n", blk->name_len, blk->name);
+       adsp_dbg(dsp, "\tCoefficient flags: %#x\n", blk->flags);
+       adsp_dbg(dsp, "\tALSA control type: %#x\n", blk->ctl_type);
+       adsp_dbg(dsp, "\tALSA control len: %#x\n", blk->len);
+}
+
+static int wm_adsp_parse_coeff(struct wm_adsp *dsp,
+                              const struct wmfw_region *region)
+{
+       struct wm_adsp_alg_region alg_region = {};
+       struct wm_coeff_parsed_alg alg_blk;
+       struct wm_coeff_parsed_coeff coeff_blk;
+       const u8 *data = region->data;
+       int i, ret;
+
+       wm_coeff_parse_alg(dsp, &data, &alg_blk);
+       for (i = 0; i < alg_blk.ncoeff; i++) {
+               wm_coeff_parse_coeff(dsp, &data, &coeff_blk);
+
+               switch (coeff_blk.ctl_type) {
+               case SNDRV_CTL_ELEM_TYPE_BYTES:
+                       break;
+               default:
+                       adsp_err(dsp, "Unknown control type: %d\n",
+                                coeff_blk.ctl_type);
+                       return -EINVAL;
+               }
+
+               alg_region.type = coeff_blk.mem_type;
+               alg_region.alg = alg_blk.id;
+
+               ret = wm_adsp_create_control(dsp, &alg_region,
+                                            coeff_blk.offset,
+                                            coeff_blk.len,
+                                            coeff_blk.name,
+                                            coeff_blk.name_len,
+                                            coeff_blk.flags);
+               if (ret < 0)
+                       adsp_err(dsp, "Failed to create control: %.*s, %d\n",
+                                coeff_blk.name_len, coeff_blk.name, ret);
+       }
+
+       return 0;
+}
+
 static int wm_adsp_load(struct wm_adsp *dsp)
 {
        LIST_HEAD(buf_list);
@@ -568,12 +1135,22 @@ static int wm_adsp_load(struct wm_adsp *dsp)
                goto out_fw;
        }
 
-       if (header->ver != 0) {
+       switch (header->ver) {
+       case 0:
+               adsp_warn(dsp, "%s: Depreciated file format %d\n",
+                         file, header->ver);
+               break;
+       case 1:
+       case 2:
+               break;
+       default:
                adsp_err(dsp, "%s: unknown file format %d\n",
                         file, header->ver);
                goto out_fw;
        }
+
        adsp_info(dsp, "Firmware version: %d\n", header->ver);
+       dsp->fw_ver = header->ver;
 
        if (header->core != dsp->type) {
                adsp_err(dsp, "%s: invalid core %d != %d\n",
@@ -638,6 +1215,12 @@ static int wm_adsp_load(struct wm_adsp *dsp)
                        text = kzalloc(le32_to_cpu(region->len) + 1,
                                       GFP_KERNEL);
                        break;
+               case WMFW_ALGORITHM_DATA:
+                       region_name = "Algorithm";
+                       ret = wm_adsp_parse_coeff(dsp, region);
+                       if (ret != 0)
+                               goto out_fw;
+                       break;
                case WMFW_INFO_TEXT:
                        region_name = "Information";
                        text = kzalloc(le32_to_cpu(region->len) + 1,
@@ -720,6 +1303,8 @@ static int wm_adsp_load(struct wm_adsp *dsp)
                adsp_warn(dsp, "%s.%d: %zu bytes at end of file\n",
                          file, regions, pos - firmware->size);
 
+       wm_adsp_debugfs_save_wmfwname(dsp, file);
+
 out_fw:
        regmap_async_complete(regmap);
        wm_adsp_buf_free(&buf_list);
@@ -730,444 +1315,317 @@ out:
        return ret;
 }
 
-static int wm_coeff_init_control_caches(struct wm_adsp *adsp)
+static void wm_adsp_ctl_fixup_base(struct wm_adsp *dsp,
+                                 const struct wm_adsp_alg_region *alg_region)
 {
        struct wm_coeff_ctl *ctl;
-       int ret;
 
-       list_for_each_entry(ctl, &adsp->ctl_list, list) {
-               if (!ctl->enabled || ctl->set)
-                       continue;
-               ret = wm_coeff_read_control(ctl->kcontrol,
-                                           ctl->cache,
-                                           ctl->len);
-               if (ret < 0)
-                       return ret;
+       list_for_each_entry(ctl, &dsp->ctl_list, list) {
+               if (ctl->fw_name == wm_adsp_fw_text[dsp->fw] &&
+                   alg_region->alg == ctl->alg_region.alg &&
+                   alg_region->type == ctl->alg_region.type) {
+                       ctl->alg_region.base = alg_region->base;
+               }
        }
-
-       return 0;
 }
 
-static int wm_coeff_sync_controls(struct wm_adsp *adsp)
+static void *wm_adsp_read_algs(struct wm_adsp *dsp, size_t n_algs,
+                              unsigned int pos, unsigned int len)
 {
-       struct wm_coeff_ctl *ctl;
+       void *alg;
        int ret;
+       __be32 val;
 
-       list_for_each_entry(ctl, &adsp->ctl_list, list) {
-               if (!ctl->enabled)
-                       continue;
-               if (ctl->set) {
-                       ret = wm_coeff_write_control(ctl->kcontrol,
-                                                    ctl->cache,
-                                                    ctl->len);
-                       if (ret < 0)
-                               return ret;
-               }
+       if (n_algs == 0) {
+               adsp_err(dsp, "No algorithms\n");
+               return ERR_PTR(-EINVAL);
        }
 
-       return 0;
-}
-
-static void wm_adsp_ctl_work(struct work_struct *work)
-{
-       struct wmfw_ctl_work *ctl_work = container_of(work,
-                                                     struct wmfw_ctl_work,
-                                                     work);
-
-       wmfw_add_ctl(ctl_work->adsp, ctl_work->ctl);
-       kfree(ctl_work);
-}
-
-static int wm_adsp_create_control(struct wm_adsp *dsp,
-                                 const struct wm_adsp_alg_region *region)
-
-{
-       struct wm_coeff_ctl *ctl;
-       struct wmfw_ctl_work *ctl_work;
-       char *name;
-       char *region_name;
-       int ret;
-
-       name = kmalloc(PAGE_SIZE, GFP_KERNEL);
-       if (!name)
-               return -ENOMEM;
+       if (n_algs > 1024) {
+               adsp_err(dsp, "Algorithm count %zx excessive\n", n_algs);
+               return ERR_PTR(-EINVAL);
+       }
 
-       switch (region->type) {
-       case WMFW_ADSP1_PM:
-               region_name = "PM";
-               break;
-       case WMFW_ADSP1_DM:
-               region_name = "DM";
-               break;
-       case WMFW_ADSP2_XM:
-               region_name = "XM";
-               break;
-       case WMFW_ADSP2_YM:
-               region_name = "YM";
-               break;
-       case WMFW_ADSP1_ZM:
-               region_name = "ZM";
-               break;
-       default:
-               ret = -EINVAL;
-               goto err_name;
+       /* Read the terminator first to validate the length */
+       ret = regmap_raw_read(dsp->regmap, pos + len, &val, sizeof(val));
+       if (ret != 0) {
+               adsp_err(dsp, "Failed to read algorithm list end: %d\n",
+                       ret);
+               return ERR_PTR(ret);
        }
 
-       snprintf(name, PAGE_SIZE, "DSP%d %s %x",
-                dsp->num, region_name, region->alg);
+       if (be32_to_cpu(val) != 0xbedead)
+               adsp_warn(dsp, "Algorithm list end %x 0x%x != 0xbeadead\n",
+                         pos + len, be32_to_cpu(val));
 
-       list_for_each_entry(ctl, &dsp->ctl_list,
-                           list) {
-               if (!strcmp(ctl->name, name)) {
-                       if (!ctl->enabled)
-                               ctl->enabled = 1;
-                       goto found;
-               }
-       }
+       alg = kzalloc(len * 2, GFP_KERNEL | GFP_DMA);
+       if (!alg)
+               return ERR_PTR(-ENOMEM);
 
-       ctl = kzalloc(sizeof(*ctl), GFP_KERNEL);
-       if (!ctl) {
-               ret = -ENOMEM;
-               goto err_name;
-       }
-       ctl->region = *region;
-       ctl->name = kmemdup(name, strlen(name) + 1, GFP_KERNEL);
-       if (!ctl->name) {
-               ret = -ENOMEM;
-               goto err_ctl;
+       ret = regmap_raw_read(dsp->regmap, pos, alg, len * 2);
+       if (ret != 0) {
+               adsp_err(dsp, "Failed to read algorithm list: %d\n",
+                       ret);
+               kfree(alg);
+               return ERR_PTR(ret);
        }
-       ctl->enabled = 1;
-       ctl->set = 0;
-       ctl->ops.xget = wm_coeff_get;
-       ctl->ops.xput = wm_coeff_put;
-       ctl->adsp = dsp;
 
-       ctl->len = region->len;
-       ctl->cache = kzalloc(ctl->len, GFP_KERNEL);
-       if (!ctl->cache) {
-               ret = -ENOMEM;
-               goto err_ctl_name;
-       }
+       return alg;
+}
 
-       ctl_work = kzalloc(sizeof(*ctl_work), GFP_KERNEL);
-       if (!ctl_work) {
-               ret = -ENOMEM;
-               goto err_ctl_cache;
-       }
+static struct wm_adsp_alg_region *wm_adsp_create_region(struct wm_adsp *dsp,
+                                                       int type, __be32 id,
+                                                       __be32 base)
+{
+       struct wm_adsp_alg_region *alg_region;
 
-       ctl_work->adsp = dsp;
-       ctl_work->ctl = ctl;
-       INIT_WORK(&ctl_work->work, wm_adsp_ctl_work);
-       schedule_work(&ctl_work->work);
+       alg_region = kzalloc(sizeof(*alg_region), GFP_KERNEL);
+       if (!alg_region)
+               return ERR_PTR(-ENOMEM);
 
-found:
-       kfree(name);
+       alg_region->type = type;
+       alg_region->alg = be32_to_cpu(id);
+       alg_region->base = be32_to_cpu(base);
 
-       return 0;
+       list_add_tail(&alg_region->list, &dsp->alg_regions);
 
-err_ctl_cache:
-       kfree(ctl->cache);
-err_ctl_name:
-       kfree(ctl->name);
-err_ctl:
-       kfree(ctl);
-err_name:
-       kfree(name);
-       return ret;
+       if (dsp->fw_ver > 0)
+               wm_adsp_ctl_fixup_base(dsp, alg_region);
+
+       return alg_region;
 }
 
-static int wm_adsp_setup_algs(struct wm_adsp *dsp)
+static int wm_adsp1_setup_algs(struct wm_adsp *dsp)
 {
-       struct regmap *regmap = dsp->regmap;
        struct wmfw_adsp1_id_hdr adsp1_id;
-       struct wmfw_adsp2_id_hdr adsp2_id;
        struct wmfw_adsp1_alg_hdr *adsp1_alg;
-       struct wmfw_adsp2_alg_hdr *adsp2_alg;
-       void *alg, *buf;
-       struct wm_adsp_alg_region *region;
+       struct wm_adsp_alg_region *alg_region;
        const struct wm_adsp_region *mem;
-       unsigned int pos, term;
-       size_t algs, buf_size;
-       __be32 val;
+       unsigned int pos, len;
+       size_t n_algs;
        int i, ret;
 
-       switch (dsp->type) {
-       case WMFW_ADSP1:
-               mem = wm_adsp_find_region(dsp, WMFW_ADSP1_DM);
-               break;
-       case WMFW_ADSP2:
-               mem = wm_adsp_find_region(dsp, WMFW_ADSP2_XM);
-               break;
-       default:
-               mem = NULL;
-               break;
-       }
-
+       mem = wm_adsp_find_region(dsp, WMFW_ADSP1_DM);
        if (WARN_ON(!mem))
                return -EINVAL;
 
-       switch (dsp->type) {
-       case WMFW_ADSP1:
-               ret = regmap_raw_read(regmap, mem->base, &adsp1_id,
-                                     sizeof(adsp1_id));
-               if (ret != 0) {
-                       adsp_err(dsp, "Failed to read algorithm info: %d\n",
-                                ret);
-                       return ret;
-               }
-
-               buf = &adsp1_id;
-               buf_size = sizeof(adsp1_id);
-
-               algs = be32_to_cpu(adsp1_id.algs);
-               dsp->fw_id = be32_to_cpu(adsp1_id.fw.id);
-               adsp_info(dsp, "Firmware: %x v%d.%d.%d, %zu algorithms\n",
-                         dsp->fw_id,
-                         (be32_to_cpu(adsp1_id.fw.ver) & 0xff0000) >> 16,
-                         (be32_to_cpu(adsp1_id.fw.ver) & 0xff00) >> 8,
-                         be32_to_cpu(adsp1_id.fw.ver) & 0xff,
-                         algs);
-
-               region = kzalloc(sizeof(*region), GFP_KERNEL);
-               if (!region)
-                       return -ENOMEM;
-               region->type = WMFW_ADSP1_ZM;
-               region->alg = be32_to_cpu(adsp1_id.fw.id);
-               region->base = be32_to_cpu(adsp1_id.zm);
-               list_add_tail(&region->list, &dsp->alg_regions);
-
-               region = kzalloc(sizeof(*region), GFP_KERNEL);
-               if (!region)
-                       return -ENOMEM;
-               region->type = WMFW_ADSP1_DM;
-               region->alg = be32_to_cpu(adsp1_id.fw.id);
-               region->base = be32_to_cpu(adsp1_id.dm);
-               list_add_tail(&region->list, &dsp->alg_regions);
-
-               pos = sizeof(adsp1_id) / 2;
-               term = pos + ((sizeof(*adsp1_alg) * algs) / 2);
-               break;
-
-       case WMFW_ADSP2:
-               ret = regmap_raw_read(regmap, mem->base, &adsp2_id,
-                                     sizeof(adsp2_id));
-               if (ret != 0) {
-                       adsp_err(dsp, "Failed to read algorithm info: %d\n",
-                                ret);
-                       return ret;
-               }
-
-               buf = &adsp2_id;
-               buf_size = sizeof(adsp2_id);
-
-               algs = be32_to_cpu(adsp2_id.algs);
-               dsp->fw_id = be32_to_cpu(adsp2_id.fw.id);
-               adsp_info(dsp, "Firmware: %x v%d.%d.%d, %zu algorithms\n",
-                         dsp->fw_id,
-                         (be32_to_cpu(adsp2_id.fw.ver) & 0xff0000) >> 16,
-                         (be32_to_cpu(adsp2_id.fw.ver) & 0xff00) >> 8,
-                         be32_to_cpu(adsp2_id.fw.ver) & 0xff,
-                         algs);
-
-               region = kzalloc(sizeof(*region), GFP_KERNEL);
-               if (!region)
-                       return -ENOMEM;
-               region->type = WMFW_ADSP2_XM;
-               region->alg = be32_to_cpu(adsp2_id.fw.id);
-               region->base = be32_to_cpu(adsp2_id.xm);
-               list_add_tail(&region->list, &dsp->alg_regions);
-
-               region = kzalloc(sizeof(*region), GFP_KERNEL);
-               if (!region)
-                       return -ENOMEM;
-               region->type = WMFW_ADSP2_YM;
-               region->alg = be32_to_cpu(adsp2_id.fw.id);
-               region->base = be32_to_cpu(adsp2_id.ym);
-               list_add_tail(&region->list, &dsp->alg_regions);
-
-               region = kzalloc(sizeof(*region), GFP_KERNEL);
-               if (!region)
-                       return -ENOMEM;
-               region->type = WMFW_ADSP2_ZM;
-               region->alg = be32_to_cpu(adsp2_id.fw.id);
-               region->base = be32_to_cpu(adsp2_id.zm);
-               list_add_tail(&region->list, &dsp->alg_regions);
-
-               pos = sizeof(adsp2_id) / 2;
-               term = pos + ((sizeof(*adsp2_alg) * algs) / 2);
-               break;
-
-       default:
-               WARN(1, "Unknown DSP type");
-               return -EINVAL;
-       }
-
-       if (algs == 0) {
-               adsp_err(dsp, "No algorithms\n");
-               return -EINVAL;
-       }
-
-       if (algs > 1024) {
-               adsp_err(dsp, "Algorithm count %zx excessive\n", algs);
-               print_hex_dump_bytes(dev_name(dsp->dev), DUMP_PREFIX_OFFSET,
-                                    buf, buf_size);
-               return -EINVAL;
-       }
-
-       /* Read the terminator first to validate the length */
-       ret = regmap_raw_read(regmap, mem->base + term, &val, sizeof(val));
+       ret = regmap_raw_read(dsp->regmap, mem->base, &adsp1_id,
+                             sizeof(adsp1_id));
        if (ret != 0) {
-               adsp_err(dsp, "Failed to read algorithm list end: %d\n",
-                       ret);
+               adsp_err(dsp, "Failed to read algorithm info: %d\n",
+                        ret);
                return ret;
        }
 
-       if (be32_to_cpu(val) != 0xbedead)
-               adsp_warn(dsp, "Algorithm list end %x 0x%x != 0xbeadead\n",
-                         term, be32_to_cpu(val));
-
-       alg = kzalloc((term - pos) * 2, GFP_KERNEL | GFP_DMA);
-       if (!alg)
-               return -ENOMEM;
-
-       ret = regmap_raw_read(regmap, mem->base + pos, alg, (term - pos) * 2);
-       if (ret != 0) {
-               adsp_err(dsp, "Failed to read algorithm list: %d\n",
-                       ret);
-               goto out;
-       }
-
-       adsp1_alg = alg;
-       adsp2_alg = alg;
-
-       for (i = 0; i < algs; i++) {
-               switch (dsp->type) {
-               case WMFW_ADSP1:
-                       adsp_info(dsp, "%d: ID %x v%d.%d.%d DM@%x ZM@%x\n",
-                                 i, be32_to_cpu(adsp1_alg[i].alg.id),
-                                 (be32_to_cpu(adsp1_alg[i].alg.ver) & 0xff0000) >> 16,
-                                 (be32_to_cpu(adsp1_alg[i].alg.ver) & 0xff00) >> 8,
-                                 be32_to_cpu(adsp1_alg[i].alg.ver) & 0xff,
-                                 be32_to_cpu(adsp1_alg[i].dm),
-                                 be32_to_cpu(adsp1_alg[i].zm));
-
-                       region = kzalloc(sizeof(*region), GFP_KERNEL);
-                       if (!region) {
-                               ret = -ENOMEM;
-                               goto out;
-                       }
-                       region->type = WMFW_ADSP1_DM;
-                       region->alg = be32_to_cpu(adsp1_alg[i].alg.id);
-                       region->base = be32_to_cpu(adsp1_alg[i].dm);
-                       region->len = 0;
-                       list_add_tail(&region->list, &dsp->alg_regions);
-                       if (i + 1 < algs) {
-                               region->len = be32_to_cpu(adsp1_alg[i + 1].dm);
-                               region->len -= be32_to_cpu(adsp1_alg[i].dm);
-                               region->len *= 4;
-                               wm_adsp_create_control(dsp, region);
+       n_algs = be32_to_cpu(adsp1_id.n_algs);
+       dsp->fw_id = be32_to_cpu(adsp1_id.fw.id);
+       adsp_info(dsp, "Firmware: %x v%d.%d.%d, %zu algorithms\n",
+                 dsp->fw_id,
+                 (be32_to_cpu(adsp1_id.fw.ver) & 0xff0000) >> 16,
+                 (be32_to_cpu(adsp1_id.fw.ver) & 0xff00) >> 8,
+                 be32_to_cpu(adsp1_id.fw.ver) & 0xff,
+                 n_algs);
+
+       alg_region = wm_adsp_create_region(dsp, WMFW_ADSP1_ZM,
+                                          adsp1_id.fw.id, adsp1_id.zm);
+       if (IS_ERR(alg_region))
+               return PTR_ERR(alg_region);
+
+       alg_region = wm_adsp_create_region(dsp, WMFW_ADSP1_DM,
+                                          adsp1_id.fw.id, adsp1_id.dm);
+       if (IS_ERR(alg_region))
+               return PTR_ERR(alg_region);
+
+       pos = sizeof(adsp1_id) / 2;
+       len = (sizeof(*adsp1_alg) * n_algs) / 2;
+
+       adsp1_alg = wm_adsp_read_algs(dsp, n_algs, mem->base + pos, len);
+       if (IS_ERR(adsp1_alg))
+               return PTR_ERR(adsp1_alg);
+
+       for (i = 0; i < n_algs; i++) {
+               adsp_info(dsp, "%d: ID %x v%d.%d.%d DM@%x ZM@%x\n",
+                         i, be32_to_cpu(adsp1_alg[i].alg.id),
+                         (be32_to_cpu(adsp1_alg[i].alg.ver) & 0xff0000) >> 16,
+                         (be32_to_cpu(adsp1_alg[i].alg.ver) & 0xff00) >> 8,
+                         be32_to_cpu(adsp1_alg[i].alg.ver) & 0xff,
+                         be32_to_cpu(adsp1_alg[i].dm),
+                         be32_to_cpu(adsp1_alg[i].zm));
+
+               alg_region = wm_adsp_create_region(dsp, WMFW_ADSP1_DM,
+                                                  adsp1_alg[i].alg.id,
+                                                  adsp1_alg[i].dm);
+               if (IS_ERR(alg_region)) {
+                       ret = PTR_ERR(alg_region);
+                       goto out;
+               }
+               if (dsp->fw_ver == 0) {
+                       if (i + 1 < n_algs) {
+                               len = be32_to_cpu(adsp1_alg[i + 1].dm);
+                               len -= be32_to_cpu(adsp1_alg[i].dm);
+                               len *= 4;
+                               wm_adsp_create_control(dsp, alg_region, 0,
+                                                      len, NULL, 0, 0);
                        } else {
                                adsp_warn(dsp, "Missing length info for region DM with ID %x\n",
                                          be32_to_cpu(adsp1_alg[i].alg.id));
                        }
+               }
 
-                       region = kzalloc(sizeof(*region), GFP_KERNEL);
-                       if (!region) {
-                               ret = -ENOMEM;
-                               goto out;
-                       }
-                       region->type = WMFW_ADSP1_ZM;
-                       region->alg = be32_to_cpu(adsp1_alg[i].alg.id);
-                       region->base = be32_to_cpu(adsp1_alg[i].zm);
-                       region->len = 0;
-                       list_add_tail(&region->list, &dsp->alg_regions);
-                       if (i + 1 < algs) {
-                               region->len = be32_to_cpu(adsp1_alg[i + 1].zm);
-                               region->len -= be32_to_cpu(adsp1_alg[i].zm);
-                               region->len *= 4;
-                               wm_adsp_create_control(dsp, region);
+               alg_region = wm_adsp_create_region(dsp, WMFW_ADSP1_ZM,
+                                                  adsp1_alg[i].alg.id,
+                                                  adsp1_alg[i].zm);
+               if (IS_ERR(alg_region)) {
+                       ret = PTR_ERR(alg_region);
+                       goto out;
+               }
+               if (dsp->fw_ver == 0) {
+                       if (i + 1 < n_algs) {
+                               len = be32_to_cpu(adsp1_alg[i + 1].zm);
+                               len -= be32_to_cpu(adsp1_alg[i].zm);
+                               len *= 4;
+                               wm_adsp_create_control(dsp, alg_region, 0,
+                                                      len, NULL, 0, 0);
                        } else {
                                adsp_warn(dsp, "Missing length info for region ZM with ID %x\n",
                                          be32_to_cpu(adsp1_alg[i].alg.id));
                        }
-                       break;
+               }
+       }
 
-               case WMFW_ADSP2:
-                       adsp_info(dsp,
-                                 "%d: ID %x v%d.%d.%d XM@%x YM@%x ZM@%x\n",
-                                 i, be32_to_cpu(adsp2_alg[i].alg.id),
-                                 (be32_to_cpu(adsp2_alg[i].alg.ver) & 0xff0000) >> 16,
-                                 (be32_to_cpu(adsp2_alg[i].alg.ver) & 0xff00) >> 8,
-                                 be32_to_cpu(adsp2_alg[i].alg.ver) & 0xff,
-                                 be32_to_cpu(adsp2_alg[i].xm),
-                                 be32_to_cpu(adsp2_alg[i].ym),
-                                 be32_to_cpu(adsp2_alg[i].zm));
-
-                       region = kzalloc(sizeof(*region), GFP_KERNEL);
-                       if (!region) {
-                               ret = -ENOMEM;
-                               goto out;
-                       }
-                       region->type = WMFW_ADSP2_XM;
-                       region->alg = be32_to_cpu(adsp2_alg[i].alg.id);
-                       region->base = be32_to_cpu(adsp2_alg[i].xm);
-                       region->len = 0;
-                       list_add_tail(&region->list, &dsp->alg_regions);
-                       if (i + 1 < algs) {
-                               region->len = be32_to_cpu(adsp2_alg[i + 1].xm);
-                               region->len -= be32_to_cpu(adsp2_alg[i].xm);
-                               region->len *= 4;
-                               wm_adsp_create_control(dsp, region);
+out:
+       kfree(adsp1_alg);
+       return ret;
+}
+
+static int wm_adsp2_setup_algs(struct wm_adsp *dsp)
+{
+       struct wmfw_adsp2_id_hdr adsp2_id;
+       struct wmfw_adsp2_alg_hdr *adsp2_alg;
+       struct wm_adsp_alg_region *alg_region;
+       const struct wm_adsp_region *mem;
+       unsigned int pos, len;
+       size_t n_algs;
+       int i, ret;
+
+       mem = wm_adsp_find_region(dsp, WMFW_ADSP2_XM);
+       if (WARN_ON(!mem))
+               return -EINVAL;
+
+       ret = regmap_raw_read(dsp->regmap, mem->base, &adsp2_id,
+                             sizeof(adsp2_id));
+       if (ret != 0) {
+               adsp_err(dsp, "Failed to read algorithm info: %d\n",
+                        ret);
+               return ret;
+       }
+
+       n_algs = be32_to_cpu(adsp2_id.n_algs);
+       dsp->fw_id = be32_to_cpu(adsp2_id.fw.id);
+       dsp->fw_id_version = be32_to_cpu(adsp2_id.fw.ver);
+       adsp_info(dsp, "Firmware: %x v%d.%d.%d, %zu algorithms\n",
+                 dsp->fw_id,
+                 (dsp->fw_id_version & 0xff0000) >> 16,
+                 (dsp->fw_id_version & 0xff00) >> 8,
+                 dsp->fw_id_version & 0xff,
+                 n_algs);
+
+       alg_region = wm_adsp_create_region(dsp, WMFW_ADSP2_XM,
+                                          adsp2_id.fw.id, adsp2_id.xm);
+       if (IS_ERR(alg_region))
+               return PTR_ERR(alg_region);
+
+       alg_region = wm_adsp_create_region(dsp, WMFW_ADSP2_YM,
+                                          adsp2_id.fw.id, adsp2_id.ym);
+       if (IS_ERR(alg_region))
+               return PTR_ERR(alg_region);
+
+       alg_region = wm_adsp_create_region(dsp, WMFW_ADSP2_ZM,
+                                          adsp2_id.fw.id, adsp2_id.zm);
+       if (IS_ERR(alg_region))
+               return PTR_ERR(alg_region);
+
+       pos = sizeof(adsp2_id) / 2;
+       len = (sizeof(*adsp2_alg) * n_algs) / 2;
+
+       adsp2_alg = wm_adsp_read_algs(dsp, n_algs, mem->base + pos, len);
+       if (IS_ERR(adsp2_alg))
+               return PTR_ERR(adsp2_alg);
+
+       for (i = 0; i < n_algs; i++) {
+               adsp_info(dsp,
+                         "%d: ID %x v%d.%d.%d XM@%x YM@%x ZM@%x\n",
+                         i, be32_to_cpu(adsp2_alg[i].alg.id),
+                         (be32_to_cpu(adsp2_alg[i].alg.ver) & 0xff0000) >> 16,
+                         (be32_to_cpu(adsp2_alg[i].alg.ver) & 0xff00) >> 8,
+                         be32_to_cpu(adsp2_alg[i].alg.ver) & 0xff,
+                         be32_to_cpu(adsp2_alg[i].xm),
+                         be32_to_cpu(adsp2_alg[i].ym),
+                         be32_to_cpu(adsp2_alg[i].zm));
+
+               alg_region = wm_adsp_create_region(dsp, WMFW_ADSP2_XM,
+                                                  adsp2_alg[i].alg.id,
+                                                  adsp2_alg[i].xm);
+               if (IS_ERR(alg_region)) {
+                       ret = PTR_ERR(alg_region);
+                       goto out;
+               }
+               if (dsp->fw_ver == 0) {
+                       if (i + 1 < n_algs) {
+                               len = be32_to_cpu(adsp2_alg[i + 1].xm);
+                               len -= be32_to_cpu(adsp2_alg[i].xm);
+                               len *= 4;
+                               wm_adsp_create_control(dsp, alg_region, 0,
+                                                      len, NULL, 0, 0);
                        } else {
                                adsp_warn(dsp, "Missing length info for region XM with ID %x\n",
                                          be32_to_cpu(adsp2_alg[i].alg.id));
                        }
+               }
 
-                       region = kzalloc(sizeof(*region), GFP_KERNEL);
-                       if (!region) {
-                               ret = -ENOMEM;
-                               goto out;
-                       }
-                       region->type = WMFW_ADSP2_YM;
-                       region->alg = be32_to_cpu(adsp2_alg[i].alg.id);
-                       region->base = be32_to_cpu(adsp2_alg[i].ym);
-                       region->len = 0;
-                       list_add_tail(&region->list, &dsp->alg_regions);
-                       if (i + 1 < algs) {
-                               region->len = be32_to_cpu(adsp2_alg[i + 1].ym);
-                               region->len -= be32_to_cpu(adsp2_alg[i].ym);
-                               region->len *= 4;
-                               wm_adsp_create_control(dsp, region);
+               alg_region = wm_adsp_create_region(dsp, WMFW_ADSP2_YM,
+                                                  adsp2_alg[i].alg.id,
+                                                  adsp2_alg[i].ym);
+               if (IS_ERR(alg_region)) {
+                       ret = PTR_ERR(alg_region);
+                       goto out;
+               }
+               if (dsp->fw_ver == 0) {
+                       if (i + 1 < n_algs) {
+                               len = be32_to_cpu(adsp2_alg[i + 1].ym);
+                               len -= be32_to_cpu(adsp2_alg[i].ym);
+                               len *= 4;
+                               wm_adsp_create_control(dsp, alg_region, 0,
+                                                      len, NULL, 0, 0);
                        } else {
                                adsp_warn(dsp, "Missing length info for region YM with ID %x\n",
                                          be32_to_cpu(adsp2_alg[i].alg.id));
                        }
+               }
 
-                       region = kzalloc(sizeof(*region), GFP_KERNEL);
-                       if (!region) {
-                               ret = -ENOMEM;
-                               goto out;
-                       }
-                       region->type = WMFW_ADSP2_ZM;
-                       region->alg = be32_to_cpu(adsp2_alg[i].alg.id);
-                       region->base = be32_to_cpu(adsp2_alg[i].zm);
-                       region->len = 0;
-                       list_add_tail(&region->list, &dsp->alg_regions);
-                       if (i + 1 < algs) {
-                               region->len = be32_to_cpu(adsp2_alg[i + 1].zm);
-                               region->len -= be32_to_cpu(adsp2_alg[i].zm);
-                               region->len *= 4;
-                               wm_adsp_create_control(dsp, region);
+               alg_region = wm_adsp_create_region(dsp, WMFW_ADSP2_ZM,
+                                                  adsp2_alg[i].alg.id,
+                                                  adsp2_alg[i].zm);
+               if (IS_ERR(alg_region)) {
+                       ret = PTR_ERR(alg_region);
+                       goto out;
+               }
+               if (dsp->fw_ver == 0) {
+                       if (i + 1 < n_algs) {
+                               len = be32_to_cpu(adsp2_alg[i + 1].zm);
+                               len -= be32_to_cpu(adsp2_alg[i].zm);
+                               len *= 4;
+                               wm_adsp_create_control(dsp, alg_region, 0,
+                                                      len, NULL, 0, 0);
                        } else {
                                adsp_warn(dsp, "Missing length info for region ZM with ID %x\n",
                                          be32_to_cpu(adsp2_alg[i].alg.id));
                        }
-                       break;
                }
        }
 
 out:
-       kfree(alg);
+       kfree(adsp2_alg);
        return ret;
 }
 
@@ -1345,6 +1803,8 @@ static int wm_adsp_load_coeff(struct wm_adsp *dsp)
                adsp_warn(dsp, "%s.%d: %zu bytes at end of file\n",
                          file, blocks, pos - firmware->size);
 
+       wm_adsp_debugfs_save_binname(dsp, file);
+
 out_fw:
        regmap_async_complete(regmap);
        release_firmware(firmware);
@@ -1354,10 +1814,13 @@ out:
        return ret;
 }
 
-int wm_adsp1_init(struct wm_adsp *adsp)
+int wm_adsp1_init(struct wm_adsp *dsp)
 {
-       INIT_LIST_HEAD(&adsp->alg_regions);
+       INIT_LIST_HEAD(&dsp->alg_regions);
 
+#ifdef CONFIG_DEBUG_FS
+       mutex_init(&dsp->debugfs_lock);
+#endif
        return 0;
 }
 EXPORT_SYMBOL_GPL(wm_adsp1_init);
@@ -1410,7 +1873,7 @@ int wm_adsp1_event(struct snd_soc_dapm_widget *w,
                if (ret != 0)
                        goto err;
 
-               ret = wm_adsp_setup_algs(dsp);
+               ret = wm_adsp1_setup_algs(dsp);
                if (ret != 0)
                        goto err;
 
@@ -1531,35 +1994,6 @@ static void wm_adsp2_boot_work(struct work_struct *work)
                return;
        }
 
-       if (dsp->dvfs) {
-               ret = regmap_read(dsp->regmap,
-                                 dsp->base + ADSP2_CLOCKING, &val);
-               if (ret != 0) {
-                       adsp_err(dsp, "Failed to read clocking: %d\n", ret);
-                       return;
-               }
-
-               if ((val & ADSP2_CLK_SEL_MASK) >= 3) {
-                       ret = regulator_enable(dsp->dvfs);
-                       if (ret != 0) {
-                               adsp_err(dsp,
-                                        "Failed to enable supply: %d\n",
-                                        ret);
-                               return;
-                       }
-
-                       ret = regulator_set_voltage(dsp->dvfs,
-                                                   1800000,
-                                                   1800000);
-                       if (ret != 0) {
-                               adsp_err(dsp,
-                                        "Failed to raise supply: %d\n",
-                                        ret);
-                               return;
-                       }
-               }
-       }
-
        ret = wm_adsp2_ena(dsp);
        if (ret != 0)
                return;
@@ -1568,7 +2002,7 @@ static void wm_adsp2_boot_work(struct work_struct *work)
        if (ret != 0)
                goto err;
 
-       ret = wm_adsp_setup_algs(dsp);
+       ret = wm_adsp2_setup_algs(dsp);
        if (ret != 0)
                goto err;
 
@@ -1642,6 +2076,13 @@ int wm_adsp2_event(struct snd_soc_dapm_widget *w,
                break;
 
        case SND_SOC_DAPM_PRE_PMD:
+               /* Log firmware state, it can be useful for analysis */
+               wm_adsp2_show_fw_status(dsp);
+
+               wm_adsp_debugfs_clear(dsp);
+
+               dsp->fw_id = 0;
+               dsp->fw_id_version = 0;
                dsp->running = false;
 
                regmap_update_bits(dsp->regmap, dsp->base + ADSP2_CONTROL,
@@ -1653,21 +2094,6 @@ int wm_adsp2_event(struct snd_soc_dapm_widget *w,
                regmap_write(dsp->regmap, dsp->base + ADSP2_WDMA_CONFIG_2, 0);
                regmap_write(dsp->regmap, dsp->base + ADSP2_RDMA_CONFIG_1, 0);
 
-               if (dsp->dvfs) {
-                       ret = regulator_set_voltage(dsp->dvfs, 1200000,
-                                                   1800000);
-                       if (ret != 0)
-                               adsp_warn(dsp,
-                                         "Failed to lower supply: %d\n",
-                                         ret);
-
-                       ret = regulator_disable(dsp->dvfs);
-                       if (ret != 0)
-                               adsp_err(dsp,
-                                        "Failed to enable supply: %d\n",
-                                        ret);
-               }
-
                list_for_each_entry(ctl, &dsp->ctl_list, list)
                        ctl->enabled = 0;
 
@@ -1694,7 +2120,25 @@ err:
 }
 EXPORT_SYMBOL_GPL(wm_adsp2_event);
 
-int wm_adsp2_init(struct wm_adsp *adsp, bool dvfs)
+int wm_adsp2_codec_probe(struct wm_adsp *dsp, struct snd_soc_codec *codec)
+{
+       wm_adsp2_init_debugfs(dsp, codec);
+
+       return snd_soc_add_codec_controls(codec,
+                                         wm_adsp2_fw_controls[dsp->num - 1],
+                                         ARRAY_SIZE(wm_adsp2_fw_controls[0]));
+}
+EXPORT_SYMBOL_GPL(wm_adsp2_codec_probe);
+
+int wm_adsp2_codec_remove(struct wm_adsp *dsp, struct snd_soc_codec *codec)
+{
+       wm_adsp2_cleanup_debugfs(dsp);
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(wm_adsp2_codec_remove);
+
+int wm_adsp2_init(struct wm_adsp *dsp)
 {
        int ret;
 
@@ -1702,44 +2146,20 @@ int wm_adsp2_init(struct wm_adsp *adsp, bool dvfs)
         * Disable the DSP memory by default when in reset for a small
         * power saving.
         */
-       ret = regmap_update_bits(adsp->regmap, adsp->base + ADSP2_CONTROL,
+       ret = regmap_update_bits(dsp->regmap, dsp->base + ADSP2_CONTROL,
                                 ADSP2_MEM_ENA, 0);
        if (ret != 0) {
-               adsp_err(adsp, "Failed to clear memory retention: %d\n", ret);
+               adsp_err(dsp, "Failed to clear memory retention: %d\n", ret);
                return ret;
        }
 
-       INIT_LIST_HEAD(&adsp->alg_regions);
-       INIT_LIST_HEAD(&adsp->ctl_list);
-       INIT_WORK(&adsp->boot_work, wm_adsp2_boot_work);
-
-       if (dvfs) {
-               adsp->dvfs = devm_regulator_get(adsp->dev, "DCVDD");
-               if (IS_ERR(adsp->dvfs)) {
-                       ret = PTR_ERR(adsp->dvfs);
-                       adsp_err(adsp, "Failed to get DCVDD: %d\n", ret);
-                       return ret;
-               }
-
-               ret = regulator_enable(adsp->dvfs);
-               if (ret != 0) {
-                       adsp_err(adsp, "Failed to enable DCVDD: %d\n", ret);
-                       return ret;
-               }
-
-               ret = regulator_set_voltage(adsp->dvfs, 1200000, 1800000);
-               if (ret != 0) {
-                       adsp_err(adsp, "Failed to initialise DVFS: %d\n", ret);
-                       return ret;
-               }
-
-               ret = regulator_disable(adsp->dvfs);
-               if (ret != 0) {
-                       adsp_err(adsp, "Failed to disable DCVDD: %d\n", ret);
-                       return ret;
-               }
-       }
+       INIT_LIST_HEAD(&dsp->alg_regions);
+       INIT_LIST_HEAD(&dsp->ctl_list);
+       INIT_WORK(&dsp->boot_work, wm_adsp2_boot_work);
 
+#ifdef CONFIG_DEBUG_FS
+       mutex_init(&dsp->debugfs_lock);
+#endif
        return 0;
 }
 EXPORT_SYMBOL_GPL(wm_adsp2_init);
index a4f6b64deb61bcec9729d5d8355b135b647774c8..5042cbd39e5479b05ca37219cadcce638353d868 100644 (file)
@@ -18,8 +18,6 @@
 
 #include "wmfw.h"
 
-struct regulator;
-
 struct wm_adsp_region {
        int type;
        unsigned int base;
@@ -30,7 +28,6 @@ struct wm_adsp_alg_region {
        unsigned int alg;
        int type;
        unsigned int base;
-       size_t len;
 };
 
 struct wm_adsp {
@@ -49,37 +46,49 @@ struct wm_adsp {
        struct list_head alg_regions;
 
        int fw_id;
+       int fw_id_version;
 
        const struct wm_adsp_region *mem;
        int num_mems;
 
        int fw;
-       bool running;
-
-       struct regulator *dvfs;
+       int fw_ver;
+       u32 running;
 
        struct list_head ctl_list;
 
        struct work_struct boot_work;
+
+#ifdef CONFIG_DEBUG_FS
+       struct dentry *debugfs_root;
+       struct mutex debugfs_lock;
+       char *wmfw_file_name;
+       char *bin_file_name;
+#endif
+
 };
 
 #define WM_ADSP1(wname, num) \
        SND_SOC_DAPM_PGA_E(wname, SND_SOC_NOPM, num, 0, NULL, 0, \
                wm_adsp1_event, SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD)
 
-#define WM_ADSP2(wname, num) \
+#define WM_ADSP2_E(wname, num, event_fn) \
 {      .id = snd_soc_dapm_dai_link, .name = wname " Preloader", \
-       .reg = SND_SOC_NOPM, .shift = num, .event = wm_adsp2_early_event, \
-       .event_flags = SND_SOC_DAPM_PRE_PMU }, \
+       .reg = SND_SOC_NOPM, .shift = num, .event = event_fn, \
+       .event_flags = SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD }, \
 {      .id = snd_soc_dapm_out_drv, .name = wname, \
        .reg = SND_SOC_NOPM, .shift = num, .event = wm_adsp2_event, \
        .event_flags = SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD }
 
+#define WM_ADSP2(wname, num) \
+       WM_ADSP2_E(wname, num, wm_adsp2_early_event)
+
 extern const struct snd_kcontrol_new wm_adsp1_fw_controls[];
-extern const struct snd_kcontrol_new wm_adsp2_fw_controls[];
 
-int wm_adsp1_init(struct wm_adsp *adsp);
-int wm_adsp2_init(struct wm_adsp *adsp, bool dvfs);
+int wm_adsp1_init(struct wm_adsp *dsp);
+int wm_adsp2_init(struct wm_adsp *dsp);
+int wm_adsp2_codec_probe(struct wm_adsp *dsp, struct snd_soc_codec *codec);
+int wm_adsp2_codec_remove(struct wm_adsp *dsp, struct snd_soc_codec *codec);
 int wm_adsp1_event(struct snd_soc_dapm_widget *w,
                   struct snd_kcontrol *kcontrol, int event);
 int wm_adsp2_early_event(struct snd_soc_dapm_widget *w,
index 8366e19657a73708fc4d65f5c3a13a449618ca92..fd86bd105460528ac3bfcf987a5e6b1db3e7d487 100644 (file)
@@ -1116,7 +1116,7 @@ static const struct snd_soc_dapm_route lineout2_se_routes[] = {
 
 int wm_hubs_add_analogue_controls(struct snd_soc_codec *codec)
 {
-       struct snd_soc_dapm_context *dapm = &codec->dapm;
+       struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
 
        /* Latch volume update bits & default ZC on */
        snd_soc_update_bits(codec, WM8993_LEFT_LINE_INPUT_1_2_VOLUME,
@@ -1160,7 +1160,7 @@ int wm_hubs_add_analogue_routes(struct snd_soc_codec *codec,
                                int lineout1_diff, int lineout2_diff)
 {
        struct wm_hubs_data *hubs = snd_soc_codec_get_drvdata(codec);
-       struct snd_soc_dapm_context *dapm = &codec->dapm;
+       struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
 
        hubs->codec = codec;
 
index ef163360a7459ebd7a8a70af00118cbcdb95717e..7613d60d62ea32d6d639a065b75eb2656c70dae7 100644 (file)
 
 #include <linux/types.h>
 
+#define WMFW_MAX_ALG_NAME         256
+#define WMFW_MAX_ALG_DESCR_NAME   256
+
+#define WMFW_MAX_COEFF_NAME       256
+#define WMFW_MAX_COEFF_DESCR_NAME 256
+
+#define WMFW_CTL_FLAG_SYS         0x8000
+#define WMFW_CTL_FLAG_VOLATILE    0x0004
+#define WMFW_CTL_FLAG_WRITEABLE   0x0002
+#define WMFW_CTL_FLAG_READABLE    0x0001
+
 struct wmfw_header {
        char magic[4];
        __le32 len;
@@ -61,7 +72,7 @@ struct wmfw_adsp1_id_hdr {
        struct wmfw_id_hdr fw;
        __be32 zm;
        __be32 dm;
-       __be32 algs;
+       __be32 n_algs;
 } __packed;
 
 struct wmfw_adsp2_id_hdr {
@@ -69,7 +80,7 @@ struct wmfw_adsp2_id_hdr {
        __be32 zm;
        __be32 xm;
        __be32 ym;
-       __be32 algs;
+       __be32 n_algs;
 } __packed;
 
 struct wmfw_alg_hdr {
@@ -90,6 +101,28 @@ struct wmfw_adsp2_alg_hdr {
        __be32 ym;
 } __packed;
 
+struct wmfw_adsp_alg_data {
+       __le32 id;
+       u8 name[WMFW_MAX_ALG_NAME];
+       u8 descr[WMFW_MAX_ALG_DESCR_NAME];
+       __le32 ncoeff;
+       u8 data[];
+} __packed;
+
+struct wmfw_adsp_coeff_data {
+       struct {
+               __le16 offset;
+               __le16 type;
+               __le32 size;
+       } hdr;
+       u8 name[WMFW_MAX_COEFF_NAME];
+       u8 descr[WMFW_MAX_COEFF_DESCR_NAME];
+       __le16 ctl_type;
+       __le16 flags;
+       __le32 len;
+       u8 data[];
+} __packed;
+
 struct wmfw_coeff_hdr {
        u8 magic[4];
        __le32 len;
@@ -117,9 +150,10 @@ struct wmfw_coeff_item {
 #define WMFW_ADSP1 1
 #define WMFW_ADSP2 2
 
-#define WMFW_ABSOLUTE  0xf0
-#define WMFW_NAME_TEXT 0xfe
-#define WMFW_INFO_TEXT 0xff
+#define WMFW_ABSOLUTE         0xf0
+#define WMFW_ALGORITHM_DATA   0xf2
+#define WMFW_NAME_TEXT        0xfe
+#define WMFW_INFO_TEXT        0xff
 
 #define WMFW_ADSP1_PM 2
 #define WMFW_ADSP1_DM 3
index bb4b78eada586df9b210ff03981f44149e85f25c..b960e626dad9093680e2d6efcd778fee0f1d380d 100644 (file)
@@ -107,6 +107,7 @@ struct davinci_mcasp {
 #endif
 
        struct davinci_mcasp_ruledata ruledata[2];
+       struct snd_pcm_hw_constraint_list chconstr[2];
 };
 
 static inline void mcasp_set_bits(struct davinci_mcasp *mcasp, u32 offset,
@@ -685,6 +686,8 @@ static int mcasp_common_hw_param(struct davinci_mcasp *mcasp, int stream,
                if (mcasp->serial_dir[i] == TX_MODE &&
                                        tx_ser < max_active_serializers) {
                        mcasp_set_bits(mcasp, DAVINCI_MCASP_PDIR_REG, AXR(i));
+                       mcasp_mod_bits(mcasp, DAVINCI_MCASP_XRSRCTL_REG(i),
+                                      DISMOD_LOW, DISMOD_MASK);
                        tx_ser++;
                } else if (mcasp->serial_dir[i] == RX_MODE &&
                                        rx_ser < max_active_serializers) {
@@ -915,15 +918,12 @@ static int davinci_mcasp_hw_params(struct snd_pcm_substream *substream,
         * the machine driver, we need to calculate the ratio.
         */
        if (mcasp->bclk_master && mcasp->bclk_div == 0 && mcasp->sysclk_freq) {
-               int channels = params_channels(params);
+               int slots = mcasp->tdm_slots;
                int rate = params_rate(params);
                int sbits = params_width(params);
                int ppm, div;
 
-               if (channels > mcasp->tdm_slots)
-                       channels = mcasp->tdm_slots;
-
-               div = davinci_mcasp_calc_clk_div(mcasp, rate*sbits*channels,
+               div = davinci_mcasp_calc_clk_div(mcasp, rate*sbits*slots,
                                                 &ppm);
                if (ppm)
                        dev_info(mcasp->dev, "Sample-rate is off by %d PPM\n",
@@ -1024,31 +1024,36 @@ static int davinci_mcasp_hw_rule_rate(struct snd_pcm_hw_params *params,
        struct snd_interval *ri =
                hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE);
        int sbits = params_width(params);
-       int channels = params_channels(params);
-       unsigned int list[ARRAY_SIZE(davinci_mcasp_dai_rates)];
-       int i, count = 0;
+       int slots = rd->mcasp->tdm_slots;
+       struct snd_interval range;
+       int i;
 
-       if (channels > rd->mcasp->tdm_slots)
-               channels = rd->mcasp->tdm_slots;
+       snd_interval_any(&range);
+       range.empty = 1;
 
        for (i = 0; i < ARRAY_SIZE(davinci_mcasp_dai_rates); i++) {
-               if (ri->min <= davinci_mcasp_dai_rates[i] &&
-                   ri->max >= davinci_mcasp_dai_rates[i]) {
-                       uint bclk_freq = sbits*channels*
+               if (snd_interval_test(ri, davinci_mcasp_dai_rates[i])) {
+                       uint bclk_freq = sbits*slots*
                                davinci_mcasp_dai_rates[i];
                        int ppm;
 
                        davinci_mcasp_calc_clk_div(rd->mcasp, bclk_freq, &ppm);
-                       if (abs(ppm) < DAVINCI_MAX_RATE_ERROR_PPM)
-                               list[count++] = davinci_mcasp_dai_rates[i];
+                       if (abs(ppm) < DAVINCI_MAX_RATE_ERROR_PPM) {
+                               if (range.empty) {
+                                       range.min = davinci_mcasp_dai_rates[i];
+                                       range.empty = 0;
+                               }
+                               range.max = davinci_mcasp_dai_rates[i];
+                       }
                }
        }
+
        dev_dbg(rd->mcasp->dev,
-               "%d frequencies (%d-%d) for %d sbits and %d channels\n",
-               count, ri->min, ri->max, sbits, channels);
+               "Frequencies %d-%d -> %d-%d for %d sbits and %d tdm slots\n",
+               ri->min, ri->max, range.min, range.max, sbits, slots);
 
-       return snd_interval_list(hw_param_interval(params, rule->var),
-                                count, list, 0);
+       return snd_interval_refine(hw_param_interval(params, rule->var),
+                                  &range);
 }
 
 static int davinci_mcasp_hw_rule_format(struct snd_pcm_hw_params *params,
@@ -1058,17 +1063,14 @@ static int davinci_mcasp_hw_rule_format(struct snd_pcm_hw_params *params,
        struct snd_mask *fmt = hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT);
        struct snd_mask nfmt;
        int rate = params_rate(params);
-       int channels = params_channels(params);
+       int slots = rd->mcasp->tdm_slots;
        int i, count = 0;
 
        snd_mask_none(&nfmt);
 
-       if (channels > rd->mcasp->tdm_slots)
-               channels = rd->mcasp->tdm_slots;
-
        for (i = 0; i < SNDRV_PCM_FORMAT_LAST; i++) {
                if (snd_mask_test(fmt, i)) {
-                       uint bclk_freq = snd_pcm_format_width(i)*channels*rate;
+                       uint bclk_freq = snd_pcm_format_width(i)*slots*rate;
                        int ppm;
 
                        davinci_mcasp_calc_clk_div(rd->mcasp, bclk_freq, &ppm);
@@ -1079,51 +1081,12 @@ static int davinci_mcasp_hw_rule_format(struct snd_pcm_hw_params *params,
                }
        }
        dev_dbg(rd->mcasp->dev,
-               "%d possible sample format for %d Hz and %d channels\n",
-               count, rate, channels);
+               "%d possible sample format for %d Hz and %d tdm slots\n",
+               count, rate, slots);
 
        return snd_mask_refine(fmt, &nfmt);
 }
 
-static int davinci_mcasp_hw_rule_channels(struct snd_pcm_hw_params *params,
-                                         struct snd_pcm_hw_rule *rule)
-{
-       struct davinci_mcasp_ruledata *rd = rule->private;
-       struct snd_interval *ci =
-               hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS);
-       int sbits = params_width(params);
-       int rate = params_rate(params);
-       int max_chan_per_wire = rd->mcasp->tdm_slots < ci->max ?
-               rd->mcasp->tdm_slots : ci->max;
-       unsigned int list[ci->max - ci->min + 1];
-       int c1, c, count = 0;
-
-       for (c1 = ci->min; c1 <= max_chan_per_wire; c1++) {
-               uint bclk_freq = c1*sbits*rate;
-               int ppm;
-
-               davinci_mcasp_calc_clk_div(rd->mcasp, bclk_freq, &ppm);
-               if (abs(ppm) < DAVINCI_MAX_RATE_ERROR_PPM) {
-                       /* If we can use all tdm_slots, we can put any
-                          amount of channels to remaining wires as
-                          long as they fit in. */
-                       if (c1 == rd->mcasp->tdm_slots) {
-                               for (c = c1; c <= rd->serializers*c1 &&
-                                            c <= ci->max; c++)
-                                       list[count++] = c;
-                       } else {
-                               list[count++] = c1;
-                       }
-               }
-       }
-       dev_dbg(rd->mcasp->dev,
-               "%d possible channel counts (%d-%d) for %d Hz and %d sbits\n",
-               count, ci->min, ci->max, rate, sbits);
-
-       return snd_interval_list(hw_param_interval(params, rule->var),
-                                count, list, 0);
-}
-
 static int davinci_mcasp_startup(struct snd_pcm_substream *substream,
                                 struct snd_soc_dai *cpu_dai)
 {
@@ -1167,6 +1130,11 @@ static int davinci_mcasp_startup(struct snd_pcm_substream *substream,
                                     SNDRV_PCM_HW_PARAM_CHANNELS,
                                     2, max_channels);
 
+       if (mcasp->chconstr[substream->stream].count)
+               snd_pcm_hw_constraint_list(substream->runtime,
+                                          0, SNDRV_PCM_HW_PARAM_CHANNELS,
+                                          &mcasp->chconstr[substream->stream]);
+
        /*
         * If we rely on implicit BCLK divider setting we should
         * set constraints based on what we can provide.
@@ -1180,24 +1148,14 @@ static int davinci_mcasp_startup(struct snd_pcm_substream *substream,
                                          SNDRV_PCM_HW_PARAM_RATE,
                                          davinci_mcasp_hw_rule_rate,
                                          ruledata,
-                                         SNDRV_PCM_HW_PARAM_FORMAT,
-                                         SNDRV_PCM_HW_PARAM_CHANNELS, -1);
+                                         SNDRV_PCM_HW_PARAM_FORMAT, -1);
                if (ret)
                        return ret;
                ret = snd_pcm_hw_rule_add(substream->runtime, 0,
                                          SNDRV_PCM_HW_PARAM_FORMAT,
                                          davinci_mcasp_hw_rule_format,
                                          ruledata,
-                                         SNDRV_PCM_HW_PARAM_RATE,
-                                         SNDRV_PCM_HW_PARAM_CHANNELS, -1);
-               if (ret)
-                       return ret;
-               ret = snd_pcm_hw_rule_add(substream->runtime, 0,
-                                         SNDRV_PCM_HW_PARAM_CHANNELS,
-                                         davinci_mcasp_hw_rule_channels,
-                                         ruledata,
-                                         SNDRV_PCM_HW_PARAM_RATE,
-                                         SNDRV_PCM_HW_PARAM_FORMAT, -1);
+                                         SNDRV_PCM_HW_PARAM_RATE, -1);
                if (ret)
                        return ret;
        }
@@ -1247,7 +1205,7 @@ static int davinci_mcasp_suspend(struct snd_soc_dai *dai)
        u32 reg;
        int i;
 
-       context->pm_state = pm_runtime_enabled(mcasp->dev);
+       context->pm_state = pm_runtime_active(mcasp->dev);
        if (!context->pm_state)
                pm_runtime_get_sync(mcasp->dev);
 
@@ -1556,6 +1514,102 @@ nodata:
        return  pdata;
 }
 
+/* All serializers must have equal number of channels */
+static int davinci_mcasp_ch_constraint(struct davinci_mcasp *mcasp,
+                                      struct snd_pcm_hw_constraint_list *cl,
+                                      int serializers)
+{
+       unsigned int *list;
+       int i, count = 0;
+
+       if (serializers <= 1)
+               return 0;
+
+       list = devm_kzalloc(mcasp->dev, sizeof(unsigned int) *
+                           (mcasp->tdm_slots + serializers - 2),
+                           GFP_KERNEL);
+       if (!list)
+               return -ENOMEM;
+
+       for (i = 2; i <= mcasp->tdm_slots; i++)
+               list[count++] = i;
+
+       for (i = 2; i <= serializers; i++)
+               list[count++] = i*mcasp->tdm_slots;
+
+       cl->count = count;
+       cl->list = list;
+
+       return 0;
+}
+
+
+static int davinci_mcasp_init_ch_constraints(struct davinci_mcasp *mcasp)
+{
+       int rx_serializers = 0, tx_serializers = 0, ret, i;
+
+       for (i = 0; i < mcasp->num_serializer; i++)
+               if (mcasp->serial_dir[i] == TX_MODE)
+                       tx_serializers++;
+               else if (mcasp->serial_dir[i] == RX_MODE)
+                       rx_serializers++;
+
+       ret = davinci_mcasp_ch_constraint(mcasp, &mcasp->chconstr[
+                                                 SNDRV_PCM_STREAM_PLAYBACK],
+                                         tx_serializers);
+       if (ret)
+               return ret;
+
+       ret = davinci_mcasp_ch_constraint(mcasp, &mcasp->chconstr[
+                                                 SNDRV_PCM_STREAM_CAPTURE],
+                                         rx_serializers);
+
+       return ret;
+}
+
+enum {
+       PCM_EDMA,
+       PCM_SDMA,
+};
+static const char *sdma_prefix = "ti,omap";
+
+static int davinci_mcasp_get_dma_type(struct davinci_mcasp *mcasp)
+{
+       struct dma_chan *chan;
+       const char *tmp;
+       int ret = PCM_EDMA;
+
+       if (!mcasp->dev->of_node)
+               return PCM_EDMA;
+
+       tmp = mcasp->dma_data[SNDRV_PCM_STREAM_PLAYBACK].filter_data;
+       chan = dma_request_slave_channel_reason(mcasp->dev, tmp);
+       if (IS_ERR(chan)) {
+               if (PTR_ERR(chan) != -EPROBE_DEFER)
+                       dev_err(mcasp->dev,
+                               "Can't verify DMA configuration (%ld)\n",
+                               PTR_ERR(chan));
+               return PTR_ERR(chan);
+       }
+       BUG_ON(!chan->device || !chan->device->dev);
+
+       if (chan->device->dev->of_node)
+               ret = of_property_read_string(chan->device->dev->of_node,
+                                             "compatible", &tmp);
+       else
+               dev_dbg(mcasp->dev, "DMA controller has no of-node\n");
+
+       dma_release_channel(chan);
+       if (ret)
+               return ret;
+
+       dev_dbg(mcasp->dev, "DMA controller compatible = \"%s\"\n", tmp);
+       if (!strncmp(tmp, sdma_prefix, strlen(sdma_prefix)))
+               return PCM_SDMA;
+
+       return PCM_EDMA;
+}
+
 static int davinci_mcasp_probe(struct platform_device *pdev)
 {
        struct snd_dmaengine_dai_dma_data *dma_data;
@@ -1739,6 +1793,10 @@ static int davinci_mcasp_probe(struct platform_device *pdev)
                mcasp->fifo_base = DAVINCI_MCASP_V3_AFIFO_BASE;
        }
 
+       ret = davinci_mcasp_init_ch_constraints(mcasp);
+       if (ret)
+               goto err;
+
        dev_set_drvdata(&pdev->dev, mcasp);
 
        mcasp_reparent_fck(pdev);
@@ -1750,27 +1808,34 @@ static int davinci_mcasp_probe(struct platform_device *pdev)
        if (ret != 0)
                goto err;
 
-       switch (mcasp->version) {
+       ret = davinci_mcasp_get_dma_type(mcasp);
+       switch (ret) {
+       case PCM_EDMA:
 #if IS_BUILTIN(CONFIG_SND_EDMA_SOC) || \
        (IS_MODULE(CONFIG_SND_DAVINCI_SOC_MCASP) && \
         IS_MODULE(CONFIG_SND_EDMA_SOC))
-       case MCASP_VERSION_1:
-       case MCASP_VERSION_2:
-       case MCASP_VERSION_3:
                ret = edma_pcm_platform_register(&pdev->dev);
-               break;
+#else
+               dev_err(&pdev->dev, "Missing SND_EDMA_SOC\n");
+               ret = -EINVAL;
+               goto err;
 #endif
+               break;
+       case PCM_SDMA:
 #if IS_BUILTIN(CONFIG_SND_OMAP_SOC) || \
        (IS_MODULE(CONFIG_SND_DAVINCI_SOC_MCASP) && \
         IS_MODULE(CONFIG_SND_OMAP_SOC))
-       case MCASP_VERSION_4:
                ret = omap_pcm_platform_register(&pdev->dev);
-               break;
+#else
+               dev_err(&pdev->dev, "Missing SND_SDMA_SOC\n");
+               ret = -EINVAL;
+               goto err;
 #endif
+               break;
        default:
-               dev_err(&pdev->dev, "Invalid McASP version: %d\n",
-                       mcasp->version);
-               ret = -EINVAL;
+               dev_err(&pdev->dev, "No DMA controller found (%d)\n", ret);
+       case -EPROBE_DEFER:
+               goto err;
                break;
        }
 
index 79dc511180bfdcb22649ce791beead7c2a1691d4..a3be108a8c1775eae827459fbb4133edeefebd8a 100644 (file)
  * DAVINCI_MCASP_XRSRCTL_BASE_REG -  Serializer Control Register Bits
  */
 #define MODE(val)      (val)
-#define DISMOD         (val)(val<<2)
+#define DISMOD_3STATE  (0x0)
+#define DISMOD_LOW     (0x2 << 2)
+#define DISMOD_HIGH    (0x3 << 2)
+#define DISMOD_MASK    DISMOD_HIGH
 #define TXSTATE                BIT(4)
 #define RXSTATE                BIT(5)
 #define SRMOD_MASK     3
index 93d7e56c60660845cc454bca70ed531bfaa9156d..ccadefceeff2c00e1e6e9ed2f74225d00a9a3cde 100644 (file)
@@ -445,7 +445,7 @@ static int fsl_dma_open(struct snd_pcm_substream *substream)
                return ret;
        }
 
-       dma->assigned = 1;
+       dma->assigned = true;
 
        snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer);
        snd_soc_set_runtime_hwparams(substream, &fsl_dma_hardware);
@@ -814,7 +814,7 @@ static int fsl_dma_close(struct snd_pcm_substream *substream)
                substream->runtime->private_data = NULL;
        }
 
-       dma->assigned = 0;
+       dma->assigned = false;
 
        return 0;
 }
index ec79c3d5e65e28acb24b6be4190a1fe091252e7a..5c73bea7b11ef89ae09bb3a472ff42d420e3c11e 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * Freescale ALSA SoC Digital Audio Interface (SAI) driver.
  *
- * Copyright 2012-2013 Freescale Semiconductor, Inc.
+ * Copyright 2012-2015 Freescale Semiconductor, Inc.
  *
  * This program is free software, you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by the
 #define FSL_SAI_FLAGS (FSL_SAI_CSR_SEIE |\
                       FSL_SAI_CSR_FEIE)
 
+static u32 fsl_sai_rates[] = {
+       8000, 11025, 12000, 16000, 22050,
+       24000, 32000, 44100, 48000, 64000,
+       88200, 96000, 176400, 192000
+};
+
+static struct snd_pcm_hw_constraint_list fsl_sai_rate_constraints = {
+       .count = ARRAY_SIZE(fsl_sai_rates),
+       .list = fsl_sai_rates,
+};
+
 static irqreturn_t fsl_sai_isr(int irq, void *devid)
 {
        struct fsl_sai *sai = (struct fsl_sai *)devid;
@@ -251,12 +262,14 @@ static int fsl_sai_set_dai_fmt_tr(struct snd_soc_dai *cpu_dai,
                val_cr4 |= FSL_SAI_CR4_FSD_MSTR;
                break;
        case SND_SOC_DAIFMT_CBM_CFM:
+               sai->is_slave_mode = true;
                break;
        case SND_SOC_DAIFMT_CBS_CFM:
                val_cr2 |= FSL_SAI_CR2_BCD_MSTR;
                break;
        case SND_SOC_DAIFMT_CBM_CFS:
                val_cr4 |= FSL_SAI_CR4_FSD_MSTR;
+               sai->is_slave_mode = true;
                break;
        default:
                return -EINVAL;
@@ -288,6 +301,79 @@ static int fsl_sai_set_dai_fmt(struct snd_soc_dai *cpu_dai, unsigned int fmt)
        return ret;
 }
 
+static int fsl_sai_set_bclk(struct snd_soc_dai *dai, bool tx, u32 freq)
+{
+       struct fsl_sai *sai = snd_soc_dai_get_drvdata(dai);
+       unsigned long clk_rate;
+       u32 savediv = 0, ratio, savesub = freq;
+       u32 id;
+       int ret = 0;
+
+       /* Don't apply to slave mode */
+       if (sai->is_slave_mode)
+               return 0;
+
+       for (id = 0; id < FSL_SAI_MCLK_MAX; id++) {
+               clk_rate = clk_get_rate(sai->mclk_clk[id]);
+               if (!clk_rate)
+                       continue;
+
+               ratio = clk_rate / freq;
+
+               ret = clk_rate - ratio * freq;
+
+               /*
+                * Drop the source that can not be
+                * divided into the required rate.
+                */
+               if (ret != 0 && clk_rate / ret < 1000)
+                       continue;
+
+               dev_dbg(dai->dev,
+                       "ratio %d for freq %dHz based on clock %ldHz\n",
+                       ratio, freq, clk_rate);
+
+               if (ratio % 2 == 0 && ratio >= 2 && ratio <= 512)
+                       ratio /= 2;
+               else
+                       continue;
+
+               if (ret < savesub) {
+                       savediv = ratio;
+                       sai->mclk_id[tx] = id;
+                       savesub = ret;
+               }
+
+               if (ret == 0)
+                       break;
+       }
+
+       if (savediv == 0) {
+               dev_err(dai->dev, "failed to derive required %cx rate: %d\n",
+                               tx ? 'T' : 'R', freq);
+               return -EINVAL;
+       }
+
+       if ((tx && sai->synchronous[TX]) || (!tx && !sai->synchronous[RX])) {
+               regmap_update_bits(sai->regmap, FSL_SAI_RCR2,
+                                  FSL_SAI_CR2_MSEL_MASK,
+                                  FSL_SAI_CR2_MSEL(sai->mclk_id[tx]));
+               regmap_update_bits(sai->regmap, FSL_SAI_RCR2,
+                                  FSL_SAI_CR2_DIV_MASK, savediv - 1);
+       } else {
+               regmap_update_bits(sai->regmap, FSL_SAI_TCR2,
+                                  FSL_SAI_CR2_MSEL_MASK,
+                                  FSL_SAI_CR2_MSEL(sai->mclk_id[tx]));
+               regmap_update_bits(sai->regmap, FSL_SAI_TCR2,
+                                  FSL_SAI_CR2_DIV_MASK, savediv - 1);
+       }
+
+       dev_dbg(dai->dev, "best fit: clock id=%d, div=%d, deviation =%d\n",
+                       sai->mclk_id[tx], savediv, savesub);
+
+       return 0;
+}
+
 static int fsl_sai_hw_params(struct snd_pcm_substream *substream,
                struct snd_pcm_hw_params *params,
                struct snd_soc_dai *cpu_dai)
@@ -297,6 +383,24 @@ static int fsl_sai_hw_params(struct snd_pcm_substream *substream,
        unsigned int channels = params_channels(params);
        u32 word_width = snd_pcm_format_width(params_format(params));
        u32 val_cr4 = 0, val_cr5 = 0;
+       int ret;
+
+       if (!sai->is_slave_mode) {
+               ret = fsl_sai_set_bclk(cpu_dai, tx,
+                       2 * word_width * params_rate(params));
+               if (ret)
+                       return ret;
+
+               /* Do not enable the clock if it is already enabled */
+               if (!(sai->mclk_streams & BIT(substream->stream))) {
+                       ret = clk_prepare_enable(sai->mclk_clk[sai->mclk_id[tx]]);
+                       if (ret)
+                               return ret;
+
+                       sai->mclk_streams |= BIT(substream->stream);
+               }
+
+       }
 
        if (!sai->is_dsp_mode)
                val_cr4 |= FSL_SAI_CR4_SYWD(word_width);
@@ -322,6 +426,22 @@ static int fsl_sai_hw_params(struct snd_pcm_substream *substream,
        return 0;
 }
 
+static int fsl_sai_hw_free(struct snd_pcm_substream *substream,
+               struct snd_soc_dai *cpu_dai)
+{
+       struct fsl_sai *sai = snd_soc_dai_get_drvdata(cpu_dai);
+       bool tx = substream->stream == SNDRV_PCM_STREAM_PLAYBACK;
+
+       if (!sai->is_slave_mode &&
+                       sai->mclk_streams & BIT(substream->stream)) {
+               clk_disable_unprepare(sai->mclk_clk[sai->mclk_id[tx]]);
+               sai->mclk_streams &= ~BIT(substream->stream);
+       }
+
+       return 0;
+}
+
+
 static int fsl_sai_trigger(struct snd_pcm_substream *substream, int cmd,
                struct snd_soc_dai *cpu_dai)
 {
@@ -410,7 +530,10 @@ static int fsl_sai_startup(struct snd_pcm_substream *substream,
        regmap_update_bits(sai->regmap, FSL_SAI_xCR3(tx), FSL_SAI_CR3_TRCE,
                           FSL_SAI_CR3_TRCE);
 
-       return 0;
+       ret = snd_pcm_hw_constraint_list(substream->runtime, 0,
+                       SNDRV_PCM_HW_PARAM_RATE, &fsl_sai_rate_constraints);
+
+       return ret;
 }
 
 static void fsl_sai_shutdown(struct snd_pcm_substream *substream,
@@ -428,6 +551,7 @@ static const struct snd_soc_dai_ops fsl_sai_pcm_dai_ops = {
        .set_sysclk     = fsl_sai_set_dai_sysclk,
        .set_fmt        = fsl_sai_set_dai_fmt,
        .hw_params      = fsl_sai_hw_params,
+       .hw_free        = fsl_sai_hw_free,
        .trigger        = fsl_sai_trigger,
        .startup        = fsl_sai_startup,
        .shutdown       = fsl_sai_shutdown,
@@ -463,14 +587,18 @@ static struct snd_soc_dai_driver fsl_sai_dai = {
                .stream_name = "CPU-Playback",
                .channels_min = 1,
                .channels_max = 2,
-               .rates = SNDRV_PCM_RATE_8000_96000,
+               .rate_min = 8000,
+               .rate_max = 192000,
+               .rates = SNDRV_PCM_RATE_KNOT,
                .formats = FSL_SAI_FORMATS,
        },
        .capture = {
                .stream_name = "CPU-Capture",
                .channels_min = 1,
                .channels_max = 2,
-               .rates = SNDRV_PCM_RATE_8000_96000,
+               .rate_min = 8000,
+               .rate_max = 192000,
+               .rates = SNDRV_PCM_RATE_KNOT,
                .formats = FSL_SAI_FORMATS,
        },
        .ops = &fsl_sai_pcm_dai_ops,
@@ -600,8 +728,9 @@ static int fsl_sai_probe(struct platform_device *pdev)
                sai->bus_clk = NULL;
        }
 
-       for (i = 0; i < FSL_SAI_MCLK_MAX; i++) {
-               sprintf(tmp, "mclk%d", i + 1);
+       sai->mclk_clk[0] = sai->bus_clk;
+       for (i = 1; i < FSL_SAI_MCLK_MAX; i++) {
+               sprintf(tmp, "mclk%d", i);
                sai->mclk_clk[i] = devm_clk_get(&pdev->dev, tmp);
                if (IS_ERR(sai->mclk_clk[i])) {
                        dev_err(&pdev->dev, "failed to get mclk%d clock: %ld\n",
@@ -664,8 +793,7 @@ static int fsl_sai_probe(struct platform_device *pdev)
        if (sai->sai_on_imx)
                return imx_pcm_dma_init(pdev);
        else
-               return devm_snd_dmaengine_pcm_register(&pdev->dev, NULL,
-                               SND_DMAENGINE_PCM_FLAG_NO_RESIDUE);
+               return devm_snd_dmaengine_pcm_register(&pdev->dev, NULL, 0);
 }
 
 static const struct of_device_id fsl_sai_ids[] = {
index 34667209b607d435d3abd9ac10bbfe6e8cf9a64c..066280953c8503bd03d2dc1a2469004978215e1a 100644 (file)
 
 /* SAI Transmit and Recieve Configuration 2 Register */
 #define FSL_SAI_CR2_SYNC       BIT(30)
-#define FSL_SAI_CR2_MSEL_MASK  (0xff << 26)
+#define FSL_SAI_CR2_MSEL_MASK  (0x3 << 26)
 #define FSL_SAI_CR2_MSEL_BUS   0
 #define FSL_SAI_CR2_MSEL_MCLK1 BIT(26)
 #define FSL_SAI_CR2_MSEL_MCLK2 BIT(27)
 #define FSL_SAI_CR2_MSEL_MCLK3 (BIT(26) | BIT(27))
+#define FSL_SAI_CR2_MSEL(ID)   ((ID) << 26)
 #define FSL_SAI_CR2_BCP                BIT(25)
 #define FSL_SAI_CR2_BCD_MSTR   BIT(24)
+#define FSL_SAI_CR2_DIV_MASK   0xff
 
 /* SAI Transmit and Recieve Configuration 3 Register */
 #define FSL_SAI_CR3_TRCE       BIT(16)
 #define FSL_SAI_CLK_MAST2      2
 #define FSL_SAI_CLK_MAST3      3
 
-#define FSL_SAI_MCLK_MAX       3
+#define FSL_SAI_MCLK_MAX       4
 
 /* SAI data transfer numbers per DMA request */
 #define FSL_SAI_MAXBURST_TX 6
@@ -132,11 +134,14 @@ struct fsl_sai {
        struct clk *bus_clk;
        struct clk *mclk_clk[FSL_SAI_MCLK_MAX];
 
+       bool is_slave_mode;
        bool is_lsb_first;
        bool is_dsp_mode;
        bool sai_on_imx;
        bool synchronous[2];
 
+       unsigned int mclk_id[2];
+       unsigned int mclk_streams;
        struct snd_dmaengine_dai_dma_data dma_params_rx;
        struct snd_dmaengine_dai_dma_data dma_params_tx;
 };
index 91eb3aef7f02f84d4dd2ec92cb46a9ce2ad67e55..8e932219cb3af924398f5296ea77758313d0ca7b 100644 (file)
@@ -417,11 +417,9 @@ static int spdif_set_sample_rate(struct snd_pcm_substream *substream,
        if (clk != STC_TXCLK_SPDIF_ROOT)
                goto clk_set_bypass;
 
-       /*
-        * The S/PDIF block needs a clock of 64 * fs * txclk_df.
-        * So request 64 * fs * (txclk_df + 1) to get rounded.
-        */
-       ret = clk_set_rate(spdif_priv->txclk[rate], 64 * sample_rate * (txclk_df + 1));
+       /* The S/PDIF block needs a clock of 64 * fs * txclk_df */
+       ret = clk_set_rate(spdif_priv->txclk[rate],
+                          64 * sample_rate * txclk_df);
        if (ret) {
                dev_err(&pdev->dev, "failed to set tx clock rate\n");
                return ret;
@@ -1060,7 +1058,7 @@ static u32 fsl_spdif_txclk_caldiv(struct fsl_spdif_priv *spdif_priv,
 
        for (sysclk_df = sysclk_dfmin; sysclk_df <= sysclk_dfmax; sysclk_df++) {
                for (txclk_df = 1; txclk_df <= 128; txclk_df++) {
-                       rate_ideal = rate[index] * (txclk_df + 1) * 64;
+                       rate_ideal = rate[index] * txclk_df * 64;
                        if (round)
                                rate_actual = clk_round_rate(clk, rate_ideal);
                        else
index e8bb8eef1d16bee3d9d8ca5e4b7e4d5a7a026267..c7647e066cfd76b07f6b1acd4d2a68ac04bae3bc 100644 (file)
@@ -1292,13 +1292,6 @@ static int fsl_ssi_probe(struct platform_device *pdev)
        void __iomem *iomem;
        char name[64];
 
-       /* SSIs that are not connected on the board should have a
-        *      status = "disabled"
-        * property in their device tree nodes.
-        */
-       if (!of_device_is_available(np))
-               return -ENODEV;
-
        of_id = of_match_device(fsl_ssi_ids, &pdev->dev);
        if (!of_id || !of_id->data)
                return -EINVAL;
@@ -1357,7 +1350,7 @@ static int fsl_ssi_probe(struct platform_device *pdev)
        }
 
        ssi_private->irq = platform_get_irq(pdev, 0);
-       if (!ssi_private->irq) {
+       if (ssi_private->irq < 0) {
                dev_err(&pdev->dev, "no irq for node %s\n", pdev->name);
                return ssi_private->irq;
        }
index d9050d946ae747894ee73c1184791d4ed1dc0b74..fc57da341d6106e029c6766370421b9cdc97e8f5 100644 (file)
@@ -184,7 +184,7 @@ static enum imx_audmux_type {
        IMX31_AUDMUX,
 } audmux_type;
 
-static struct platform_device_id imx_audmux_ids[] = {
+static const struct platform_device_id imx_audmux_ids[] = {
        {
                .name = "imx21-audmux",
                .driver_data = IMX21_AUDMUX,
index 9e6493d4e7ff92e6a328dfa2d062349a314d88a0..bb0459018b45faa695c557371887d57d3fce4005 100644 (file)
@@ -45,11 +45,7 @@ static int imx_mc13783_hifi_hw_params(struct snd_pcm_substream *substream,
        if (ret)
                return ret;
 
-       ret = snd_soc_dai_set_tdm_slot(cpu_dai, 0x3, 0x3, 2, 16);
-       if (ret)
-               return ret;
-
-       return 0;
+       return snd_soc_dai_set_tdm_slot(cpu_dai, 0x3, 0x3, 2, 16);
 }
 
 static struct snd_soc_ops imx_mc13783_hifi_ops = {
index cd146d4fa8054fb0980abdda8a9fc506c1c4ef98..b38b98cae855d0d5529f00e50d379493a6d6f753 100644 (file)
@@ -190,7 +190,7 @@ static int imx_wm8962_probe(struct platform_device *pdev)
                dev_err(&pdev->dev, "audmux internal port setup failed\n");
                return ret;
        }
-       imx_audmux_v2_configure_port(ext_port,
+       ret = imx_audmux_v2_configure_port(ext_port,
                        IMX_AUDMUX_V2_PTCR_SYN,
                        IMX_AUDMUX_V2_PDCR_RXDSEL(int_port));
        if (ret) {
index ee03dbdda235d7153507267226de62ccc2c4001a..f3060a4ca040b5b9339221f9c701b47ced365afc 100644 (file)
@@ -79,7 +79,6 @@ config SND_SOC_INTEL_BROADWELL_MACH
        depends on SND_SOC_INTEL_SST && X86_INTEL_LPSS && DW_DMAC && \
                   I2C_DESIGNWARE_PLATFORM
        select SND_SOC_INTEL_HASWELL
-       select SND_COMPRESS_OFFLOAD
        select SND_SOC_RT286
        help
          This adds support for the Wilcatpoint Audio DSP on Intel(R) Broadwell
@@ -112,12 +111,24 @@ config SND_SOC_INTEL_CHT_BSW_RT5672_MACH
           If unsure select "N".
 
 config SND_SOC_INTEL_CHT_BSW_RT5645_MACH
-       tristate "ASoC Audio driver for Intel Cherrytrail & Braswell with RT5645 codec"
-       depends on X86_INTEL_LPSS
+       tristate "ASoC Audio driver for Intel Cherrytrail & Braswell with RT5645/5650 codec"
+       depends on X86_INTEL_LPSS && I2C
        select SND_SOC_RT5645
        select SND_SST_MFLD_PLATFORM
        select SND_SST_IPC_ACPI
        help
          This adds support for ASoC machine driver for Intel(R) Cherrytrail & Braswell
-         platforms with RT5645 audio codec.
+         platforms with RT5645/5650 audio codec.
          If unsure select "N".
+
+config SND_SOC_INTEL_CHT_BSW_MAX98090_TI_MACH
+       tristate "ASoC Audio driver for Intel Cherrytrail & Braswell with MAX98090 & TI codec"
+       depends on X86_INTEL_LPSS && I2C
+       select SND_SOC_MAX98090
+       select SND_SOC_TS3A227E
+       select SND_SST_MFLD_PLATFORM
+       select SND_SST_IPC_ACPI
+       help
+      This adds support for ASoC machine driver for Intel(R) Cherrytrail & Braswell
+      platforms with MAX98090 audio codec it also can support TI jack chip as aux device.
+      If unsure select "N".
index cd9aee9871a36a4400646441f1105d949fe5a2af..3853ec2ddbc758d2c558dfcbe093d2cee59af8a1 100644 (file)
@@ -4,7 +4,7 @@ obj-$(CONFIG_SND_SOC_INTEL_SST) += common/
 # Platform Support
 obj-$(CONFIG_SND_SOC_INTEL_HASWELL) += haswell/
 obj-$(CONFIG_SND_SOC_INTEL_BAYTRAIL) += baytrail/
-obj-$(CONFIG_SND_SOC_INTEL_BAYTRAIL) += atom/
+obj-$(CONFIG_SND_SST_MFLD_PLATFORM) += atom/
 
 # Machine support
 obj-$(CONFIG_SND_SOC_INTEL_SST) += boards/
index 90aa5c0476f3ec2feb111ff1f6d2a8fa67533d41..31e9b9ecbb8a599100774ad6fdee346755d43b42 100644 (file)
@@ -774,8 +774,120 @@ int sst_handle_vb_timer(struct snd_soc_dai *dai, bool enable)
        return ret;
 }
 
+int sst_fill_ssp_slot(struct snd_soc_dai *dai, unsigned int tx_mask,
+               unsigned int rx_mask, int slots, int slot_width)
+{
+       struct sst_data *ctx = snd_soc_dai_get_drvdata(dai);
+
+       ctx->ssp_cmd.nb_slots = slots;
+       ctx->ssp_cmd.active_tx_slot_map = tx_mask;
+       ctx->ssp_cmd.active_rx_slot_map = rx_mask;
+       ctx->ssp_cmd.nb_bits_per_slots = slot_width;
+
+       return 0;
+}
+
+static int sst_get_frame_sync_polarity(struct snd_soc_dai *dai,
+               unsigned int fmt)
+{
+       int format;
+
+       format = fmt & SND_SOC_DAIFMT_INV_MASK;
+       dev_dbg(dai->dev, "Enter:%s, format=%x\n", __func__, format);
+
+       switch (format) {
+       case SND_SOC_DAIFMT_NB_NF:
+               return SSP_FS_ACTIVE_LOW;
+       case SND_SOC_DAIFMT_NB_IF:
+               return SSP_FS_ACTIVE_HIGH;
+       case SND_SOC_DAIFMT_IB_IF:
+               return SSP_FS_ACTIVE_LOW;
+       case SND_SOC_DAIFMT_IB_NF:
+               return SSP_FS_ACTIVE_HIGH;
+       default:
+               dev_err(dai->dev, "Invalid frame sync polarity %d\n", format);
+       }
+
+       return -EINVAL;
+}
+
+static int sst_get_ssp_mode(struct snd_soc_dai *dai, unsigned int fmt)
+{
+       int format;
+
+       format = (fmt & SND_SOC_DAIFMT_MASTER_MASK);
+       dev_dbg(dai->dev, "Enter:%s, format=%x\n", __func__, format);
+
+       switch (format) {
+       case SND_SOC_DAIFMT_CBS_CFS:
+               return SSP_MODE_MASTER;
+       case SND_SOC_DAIFMT_CBM_CFM:
+               return SSP_MODE_SLAVE;
+       default:
+               dev_err(dai->dev, "Invalid ssp protocol: %d\n", format);
+       }
+
+       return -EINVAL;
+}
+
+
+int sst_fill_ssp_config(struct snd_soc_dai *dai, unsigned int fmt)
+{
+       unsigned int mode;
+       int fs_polarity;
+       struct sst_data *ctx = snd_soc_dai_get_drvdata(dai);
+
+       mode = fmt & SND_SOC_DAIFMT_FORMAT_MASK;
+
+       switch (mode) {
+       case SND_SOC_DAIFMT_DSP_B:
+               ctx->ssp_cmd.ssp_protocol = SSP_MODE_PCM;
+               ctx->ssp_cmd.mode = sst_get_ssp_mode(dai, fmt) | (SSP_PCM_MODE_NETWORK << 1);
+               ctx->ssp_cmd.start_delay = 0;
+               ctx->ssp_cmd.data_polarity = 1;
+               ctx->ssp_cmd.frame_sync_width = 1;
+               break;
+
+       case SND_SOC_DAIFMT_DSP_A:
+               ctx->ssp_cmd.ssp_protocol = SSP_MODE_PCM;
+               ctx->ssp_cmd.mode = sst_get_ssp_mode(dai, fmt) | (SSP_PCM_MODE_NETWORK << 1);
+               ctx->ssp_cmd.start_delay = 1;
+               ctx->ssp_cmd.data_polarity = 1;
+               ctx->ssp_cmd.frame_sync_width = 1;
+               break;
+
+       case SND_SOC_DAIFMT_I2S:
+               ctx->ssp_cmd.ssp_protocol = SSP_MODE_I2S;
+               ctx->ssp_cmd.mode = sst_get_ssp_mode(dai, fmt) | (SSP_PCM_MODE_NORMAL << 1);
+               ctx->ssp_cmd.start_delay = 1;
+               ctx->ssp_cmd.data_polarity = 0;
+               ctx->ssp_cmd.frame_sync_width = ctx->ssp_cmd.nb_bits_per_slots;
+               break;
+
+       case SND_SOC_DAIFMT_LEFT_J:
+               ctx->ssp_cmd.ssp_protocol = SSP_MODE_I2S;
+               ctx->ssp_cmd.mode = sst_get_ssp_mode(dai, fmt) | (SSP_PCM_MODE_NORMAL << 1);
+               ctx->ssp_cmd.start_delay = 0;
+               ctx->ssp_cmd.data_polarity = 0;
+               ctx->ssp_cmd.frame_sync_width = ctx->ssp_cmd.nb_bits_per_slots;
+               break;
+
+       default:
+               dev_dbg(dai->dev, "using default ssp configs\n");
+       }
+
+       fs_polarity = sst_get_frame_sync_polarity(dai, fmt);
+       if (fs_polarity < 0)
+               return fs_polarity;
+
+       ctx->ssp_cmd.frame_sync_polarity = fs_polarity;
+
+       return 0;
+}
+
 /**
  * sst_ssp_config - contains SSP configuration for media UC
+ * this can be overwritten by set_dai_xxx APIs
  */
 static const struct sst_ssp_config sst_ssp_configs = {
        .ssp_id = SSP_CODEC,
@@ -789,47 +901,56 @@ static const struct sst_ssp_config sst_ssp_configs = {
        .fs_frequency = SSP_FS_48_KHZ,
        .active_slot_map = 0xF,
        .start_delay = 0,
+       .frame_sync_polarity = SSP_FS_ACTIVE_HIGH,
+       .data_polarity = 1,
 };
 
+void sst_fill_ssp_defaults(struct snd_soc_dai *dai)
+{
+       const struct sst_ssp_config *config;
+       struct sst_data *ctx = snd_soc_dai_get_drvdata(dai);
+
+       config = &sst_ssp_configs;
+
+       ctx->ssp_cmd.selection = config->ssp_id;
+       ctx->ssp_cmd.nb_bits_per_slots = config->bits_per_slot;
+       ctx->ssp_cmd.nb_slots = config->slots;
+       ctx->ssp_cmd.mode = config->ssp_mode | (config->pcm_mode << 1);
+       ctx->ssp_cmd.duplex = config->duplex;
+       ctx->ssp_cmd.active_tx_slot_map = config->active_slot_map;
+       ctx->ssp_cmd.active_rx_slot_map = config->active_slot_map;
+       ctx->ssp_cmd.frame_sync_frequency = config->fs_frequency;
+       ctx->ssp_cmd.frame_sync_polarity = config->frame_sync_polarity;
+       ctx->ssp_cmd.data_polarity = config->data_polarity;
+       ctx->ssp_cmd.frame_sync_width = config->fs_width;
+       ctx->ssp_cmd.ssp_protocol = config->ssp_protocol;
+       ctx->ssp_cmd.start_delay = config->start_delay;
+       ctx->ssp_cmd.reserved1 = ctx->ssp_cmd.reserved2 = 0xFF;
+}
+
 int send_ssp_cmd(struct snd_soc_dai *dai, const char *id, bool enable)
 {
-       struct sst_cmd_sba_hw_set_ssp cmd;
        struct sst_data *drv = snd_soc_dai_get_drvdata(dai);
        const struct sst_ssp_config *config;
 
        dev_info(dai->dev, "Enter: enable=%d port_name=%s\n", enable, id);
 
-       SST_FILL_DEFAULT_DESTINATION(cmd.header.dst);
-       cmd.header.command_id = SBA_HW_SET_SSP;
-       cmd.header.length = sizeof(struct sst_cmd_sba_hw_set_ssp)
+       SST_FILL_DEFAULT_DESTINATION(drv->ssp_cmd.header.dst);
+       drv->ssp_cmd.header.command_id = SBA_HW_SET_SSP;
+       drv->ssp_cmd.header.length = sizeof(struct sst_cmd_sba_hw_set_ssp)
                                - sizeof(struct sst_dsp_header);
 
        config = &sst_ssp_configs;
        dev_dbg(dai->dev, "ssp_id: %u\n", config->ssp_id);
 
        if (enable)
-               cmd.switch_state = SST_SWITCH_ON;
+               drv->ssp_cmd.switch_state = SST_SWITCH_ON;
        else
-               cmd.switch_state = SST_SWITCH_OFF;
-
-       cmd.selection = config->ssp_id;
-       cmd.nb_bits_per_slots = config->bits_per_slot;
-       cmd.nb_slots = config->slots;
-       cmd.mode = config->ssp_mode | (config->pcm_mode << 1);
-       cmd.duplex = config->duplex;
-       cmd.active_tx_slot_map = config->active_slot_map;
-       cmd.active_rx_slot_map = config->active_slot_map;
-       cmd.frame_sync_frequency = config->fs_frequency;
-       cmd.frame_sync_polarity = SSP_FS_ACTIVE_HIGH;
-       cmd.data_polarity = 1;
-       cmd.frame_sync_width = config->fs_width;
-       cmd.ssp_protocol = config->ssp_protocol;
-       cmd.start_delay = config->start_delay;
-       cmd.reserved1 = cmd.reserved2 = 0xFF;
+               drv->ssp_cmd.switch_state = SST_SWITCH_OFF;
 
        return sst_fill_and_send_cmd(drv, SST_IPC_IA_CMD, SST_FLAG_BLOCKED,
-                               SST_TASK_SBA, 0, &cmd,
-                               sizeof(cmd.header) + cmd.header.length);
+                               SST_TASK_SBA, 0, &drv->ssp_cmd,
+                               sizeof(drv->ssp_cmd.header) + drv->ssp_cmd.header.length);
 }
 
 static int sst_set_be_modules(struct snd_soc_dapm_widget *w,
@@ -1280,36 +1401,32 @@ static int sst_fill_widget_module_info(struct snd_soc_dapm_widget *w,
        down_read(&card->controls_rwsem);
 
        list_for_each_entry(kctl, &card->controls, list) {
-               idx = strstr(kctl->id.name, " ");
+               idx = strchr(kctl->id.name, ' ');
                if (idx == NULL)
                        continue;
-               index  = strlen(kctl->id.name) - strlen(idx);
+               index = idx - (char*)kctl->id.name;
+               if (strncmp(kctl->id.name, w->name, index))
+                       continue;
 
-               if (strstr(kctl->id.name, "Volume") &&
-                   !strncmp(kctl->id.name, w->name, index))
+               if (strstr(kctl->id.name, "Volume"))
                        ret = sst_fill_module_list(kctl, w, SST_MODULE_GAIN);
 
-               else if (strstr(kctl->id.name, "params") &&
-                        !strncmp(kctl->id.name, w->name, index))
+               else if (strstr(kctl->id.name, "params"))
                        ret = sst_fill_module_list(kctl, w, SST_MODULE_ALGO);
 
                else if (strstr(kctl->id.name, "Switch") &&
-                        !strncmp(kctl->id.name, w->name, index) &&
                         strstr(kctl->id.name, "Gain")) {
                        struct sst_gain_mixer_control *mc =
                                                (void *)kctl->private_value;
 
                        mc->w = w;
 
-               } else if (strstr(kctl->id.name, "interleaver") &&
-                        !strncmp(kctl->id.name, w->name, index)) {
+               } else if (strstr(kctl->id.name, "interleaver")) {
                        struct sst_enum *e = (void *)kctl->private_value;
 
                        e->w = w;
 
-               } else if (strstr(kctl->id.name, "deinterleaver") &&
-                        !strncmp(kctl->id.name, w->name, index)) {
-
+               } else if (strstr(kctl->id.name, "deinterleaver")) {
                        struct sst_enum *e = (void *)kctl->private_value;
 
                        e->w = w;
index daecc58f28afafb28c8172649355ff9b30749783..93de8045d4e1ad2062e0c57f487dc1e2e1456fbb 100644 (file)
@@ -562,6 +562,8 @@ struct sst_ssp_config {
        u8 active_slot_map;
        u8 start_delay;
        u16 fs_width;
+       u8 frame_sync_polarity;
+       u8 data_polarity;
 };
 
 struct sst_ssp_cfg {
@@ -695,7 +697,7 @@ struct sst_gain_mixer_control {
        u16 module_id;
        u16 pipe_id;
        u16 task_id;
-       char pname[44];
+       char pname[SNDRV_CTL_ELEM_ID_NAME_MAXLEN];
        struct snd_soc_dapm_widget *w;
 };
 
@@ -867,4 +869,9 @@ struct sst_enum {
        SOC_DAPM_ENUM(SST_MUX_CTL_NAME(xpname, xinstance), \
                          SST_SSP_MUX_ENUM(xreg, xshift, xtexts))
 
+int sst_fill_ssp_slot(struct snd_soc_dai *dai, unsigned int tx_mask,
+                               unsigned int rx_mask, int slots, int slot_width);
+int sst_fill_ssp_config(struct snd_soc_dai *dai, unsigned int fmt);
+void sst_fill_ssp_defaults(struct snd_soc_dai *dai);
+
 #endif
index 2fbaf2c75d1709e517a5fb1b1d8012f58865992c..641ebe61dc08ba507ffb99c81d7ec0aa2c6d7986 100644 (file)
@@ -434,13 +434,51 @@ static int sst_enable_ssp(struct snd_pcm_substream *substream,
 
        if (!dai->active) {
                ret = sst_handle_vb_timer(dai, true);
-               if (ret)
-                       return ret;
-               ret = send_ssp_cmd(dai, dai->name, 1);
+               sst_fill_ssp_defaults(dai);
        }
        return ret;
 }
 
+static int sst_be_hw_params(struct snd_pcm_substream *substream,
+                               struct snd_pcm_hw_params *params,
+                               struct snd_soc_dai *dai)
+{
+       int ret = 0;
+
+       if (dai->active == 1)
+               ret = send_ssp_cmd(dai, dai->name, 1);
+       return ret;
+}
+
+static int sst_set_format(struct snd_soc_dai *dai, unsigned int fmt)
+{
+       int ret = 0;
+
+       if (!dai->active)
+               return 0;
+
+       ret = sst_fill_ssp_config(dai, fmt);
+       if (ret < 0)
+               dev_err(dai->dev, "sst_set_format failed..\n");
+
+       return ret;
+}
+
+static int sst_platform_set_ssp_slot(struct snd_soc_dai *dai,
+                       unsigned int tx_mask, unsigned int rx_mask,
+                       int slots, int slot_width) {
+       int ret = 0;
+
+       if (!dai->active)
+               return ret;
+
+       ret = sst_fill_ssp_slot(dai, tx_mask, rx_mask, slots, slot_width);
+       if (ret < 0)
+               dev_err(dai->dev, "sst_fill_ssp_slot failed..%d\n", ret);
+
+       return ret;
+}
+
 static void sst_disable_ssp(struct snd_pcm_substream *substream,
                        struct snd_soc_dai *dai)
 {
@@ -465,6 +503,9 @@ static struct snd_soc_dai_ops sst_compr_dai_ops = {
 
 static struct snd_soc_dai_ops sst_be_dai_ops = {
        .startup = sst_enable_ssp,
+       .hw_params = sst_be_hw_params,
+       .set_fmt = sst_set_format,
+       .set_tdm_slot = sst_platform_set_ssp_slot,
        .shutdown = sst_disable_ssp,
 };
 
index 9094314be2b043e724bfcf3db3f0f54b10dd61d4..2409b23eeacf4d62b6ed377c13666b063c92b6ff 100644 (file)
@@ -22,6 +22,7 @@
 #define __SST_PLATFORMDRV_H__
 
 #include "sst-mfld-dsp.h"
+#include "sst-atom-controls.h"
 
 extern struct sst_device *sst;
 
@@ -175,6 +176,7 @@ struct sst_data {
        struct snd_sst_bytes_v2 *byte_stream;
        struct mutex lock;
        struct snd_soc_card *soc_card;
+       struct sst_cmd_sba_hw_set_ssp ssp_cmd;
 };
 int sst_register_dsp(struct sst_device *sst);
 int sst_unregister_dsp(struct sst_device *sst);
index 96c2e420cce61f57be72baa4031a29e3ee483c06..a4b458e770894f0ccb8935ba139aa8a0e5edb6a9 100644 (file)
@@ -368,8 +368,8 @@ static inline void sst_restore_shim64(struct intel_sst_drv *ctx,
         * initialize by FW or driver when firmware is loaded
         */
        spin_lock_irqsave(&ctx->ipc_spin_lock, irq_flags);
-       sst_shim_write64(shim, SST_IMRX, shim_regs->imrx),
-       sst_shim_write64(shim, SST_CSR, shim_regs->csr),
+       sst_shim_write64(shim, SST_IMRX, shim_regs->imrx);
+       sst_shim_write64(shim, SST_CSR, shim_regs->csr);
        spin_unlock_irqrestore(&ctx->ipc_spin_lock, irq_flags);
 }
 
index 05f69308391114c5d76333c8818c44b66b276f03..bb19b5801466b4ed04cbc681c11911353ccab2cb 100644 (file)
@@ -354,6 +354,10 @@ static struct sst_machines sst_acpi_chv[] = {
                                                &chv_platform_data },
        {"10EC5645", "cht-bsw", "cht-bsw-rt5645", NULL, "intel/fw_sst_22a8.bin",
                                                &chv_platform_data },
+       {"10EC5650", "cht-bsw", "cht-bsw-rt5645", NULL, "intel/fw_sst_22a8.bin",
+                                               &chv_platform_data },
+       {"193C9890", "cht-bsw", "cht-bsw-max98090", NULL,
+       "intel/fw_sst_22a8.bin", &chv_platform_data },
        {},
 };
 
index 7b50a9d17ec1bc0db11634e153c807fc7692984a..620da1d1b9e3ea4fbde293c3e98fae4c30708ac1 100644 (file)
@@ -533,7 +533,7 @@ static inline int sst_calc_tstamp(struct intel_sst_drv *ctx,
 
        info->buffer_ptr = pointer_samples / substream->runtime->channels;
 
-       info->pcm_delay = delay_frames / substream->runtime->channels;
+       info->pcm_delay = delay_frames;
        dev_dbg(ctx->dev, "buffer ptr %llu pcm_delay rep: %llu\n",
                        info->buffer_ptr, info->pcm_delay);
        return 0;
index 1efb33b36303ea8b5c3c725c4f35b65055744689..4c01bb43928d136c93963730f1149f9d9bf4a66b 100644 (file)
@@ -679,6 +679,14 @@ static u64 byt_reply_msg_match(u64 header, u64 *mask)
        return header;
 }
 
+static bool byt_is_dsp_busy(struct sst_dsp *dsp)
+{
+       u64 ipcx;
+
+       ipcx = sst_dsp_shim_read_unlocked(dsp, SST_IPCX);
+       return (ipcx & (SST_IPCX_BUSY | SST_IPCX_DONE));
+}
+
 int sst_byt_dsp_init(struct device *dev, struct sst_pdata *pdata)
 {
        struct sst_byt *byt;
@@ -699,6 +707,9 @@ int sst_byt_dsp_init(struct device *dev, struct sst_pdata *pdata)
        ipc->ops.shim_dbg = byt_shim_dbg;
        ipc->ops.tx_data_copy = byt_tx_data_copy;
        ipc->ops.reply_msg_match = byt_reply_msg_match;
+       ipc->ops.is_dsp_busy = byt_is_dsp_busy;
+       ipc->tx_data_max_size = IPC_MAX_MAILBOX_BYTES;
+       ipc->rx_data_max_size = IPC_MAX_MAILBOX_BYTES;
 
        err = sst_ipc_init(ipc);
        if (err != 0)
@@ -759,7 +770,6 @@ fw_err:
 dsp_new_err:
        sst_ipc_fini(ipc);
 ipc_init_err:
-       kfree(byt);
 
        return err;
 }
index f8237f0044eb0c87b3a281b741a6accc2b994a94..cb94895c9edb040e0e0bcdf33c9f80c1fb4215c9 100644 (file)
@@ -5,6 +5,7 @@ snd-soc-sst-broadwell-objs := broadwell.o
 snd-soc-sst-bytcr-rt5640-objs := bytcr_rt5640.o
 snd-soc-sst-cht-bsw-rt5672-objs := cht_bsw_rt5672.o
 snd-soc-sst-cht-bsw-rt5645-objs := cht_bsw_rt5645.o
+snd-soc-sst-cht-bsw-max98090_ti-objs := cht_bsw_max98090_ti.o
 
 obj-$(CONFIG_SND_SOC_INTEL_HASWELL_MACH) += snd-soc-sst-haswell.o
 obj-$(CONFIG_SND_SOC_INTEL_BYT_RT5640_MACH) += snd-soc-sst-byt-rt5640-mach.o
@@ -13,3 +14,4 @@ obj-$(CONFIG_SND_SOC_INTEL_BROADWELL_MACH) += snd-soc-sst-broadwell.o
 obj-$(CONFIG_SND_SOC_INTEL_BYTCR_RT5640_MACH) += snd-soc-sst-bytcr-rt5640.o
 obj-$(CONFIG_SND_SOC_INTEL_CHT_BSW_RT5672_MACH) += snd-soc-sst-cht-bsw-rt5672.o
 obj-$(CONFIG_SND_SOC_INTEL_CHT_BSW_RT5645_MACH) += snd-soc-sst-cht-bsw-rt5645.o
+obj-$(CONFIG_SND_SOC_INTEL_CHT_BSW_MAX98090_TI_MACH) += snd-soc-sst-cht-bsw-max98090_ti.o
diff --git a/sound/soc/intel/boards/cht_bsw_max98090_ti.c b/sound/soc/intel/boards/cht_bsw_max98090_ti.c
new file mode 100644 (file)
index 0000000..d604ee8
--- /dev/null
@@ -0,0 +1,348 @@
+/*
+ *  cht-bsw-max98090.c - ASoc Machine driver for Intel Cherryview-based
+ *  platforms Cherrytrail and Braswell, with max98090 & TI codec.
+ *
+ *  Copyright (C) 2015 Intel Corp
+ *  Author: Fang, Yang A <yang.a.fang@intel.com>
+ *  This file is modified from cht_bsw_rt5645.c
+ *  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; version 2 of the License.
+ *
+ *  This program is distributed in the hope that it will be useful, but
+ *  WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  General Public License for more details.
+ *
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ */
+
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/acpi.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/jack.h>
+#include "../../codecs/max98090.h"
+#include "../atom/sst-atom-controls.h"
+#include "../../codecs/ts3a227e.h"
+
+#define CHT_PLAT_CLK_3_HZ      19200000
+#define CHT_CODEC_DAI  "HiFi"
+
+struct cht_mc_private {
+       struct snd_soc_jack jack;
+       bool ts3a227e_present;
+};
+
+static inline struct snd_soc_dai *cht_get_codec_dai(struct snd_soc_card *card)
+{
+       int i;
+
+       for (i = 0; i < card->num_rtd; i++) {
+               struct snd_soc_pcm_runtime *rtd;
+
+               rtd = card->rtd + i;
+               if (!strncmp(rtd->codec_dai->name, CHT_CODEC_DAI,
+                            strlen(CHT_CODEC_DAI)))
+                       return rtd->codec_dai;
+       }
+       return NULL;
+}
+
+static const struct snd_soc_dapm_widget cht_dapm_widgets[] = {
+       SND_SOC_DAPM_HP("Headphone", NULL),
+       SND_SOC_DAPM_MIC("Headset Mic", NULL),
+       SND_SOC_DAPM_MIC("Int Mic", NULL),
+       SND_SOC_DAPM_SPK("Ext Spk", NULL),
+};
+
+static const struct snd_soc_dapm_route cht_audio_map[] = {
+       {"IN34", NULL, "Headset Mic"},
+       {"Headset Mic", NULL, "MICBIAS"},
+       {"DMICL", NULL, "Int Mic"},
+       {"Headphone", NULL, "HPL"},
+       {"Headphone", NULL, "HPR"},
+       {"Ext Spk", NULL, "SPKL"},
+       {"Ext Spk", NULL, "SPKR"},
+       {"AIF1 Playback", NULL, "ssp2 Tx"},
+       {"ssp2 Tx", NULL, "codec_out0"},
+       {"ssp2 Tx", NULL, "codec_out1"},
+       {"codec_in0", NULL, "ssp2 Rx" },
+       {"codec_in1", NULL, "ssp2 Rx" },
+       {"ssp2 Rx", NULL, "AIF1 Capture"},
+};
+
+static const struct snd_kcontrol_new cht_mc_controls[] = {
+       SOC_DAPM_PIN_SWITCH("Headphone"),
+       SOC_DAPM_PIN_SWITCH("Headset Mic"),
+       SOC_DAPM_PIN_SWITCH("Int Mic"),
+       SOC_DAPM_PIN_SWITCH("Ext Spk"),
+};
+
+static int cht_aif1_hw_params(struct snd_pcm_substream *substream,
+                            struct snd_pcm_hw_params *params)
+{
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+       struct snd_soc_dai *codec_dai = rtd->codec_dai;
+       int ret;
+
+       ret = snd_soc_dai_set_sysclk(codec_dai, M98090_REG_SYSTEM_CLOCK,
+                                    CHT_PLAT_CLK_3_HZ, SND_SOC_CLOCK_IN);
+       if (ret < 0) {
+               dev_err(rtd->dev, "can't set codec sysclk: %d\n", ret);
+               return ret;
+       }
+
+       return 0;
+}
+
+static int cht_ti_jack_event(struct notifier_block *nb,
+               unsigned long event, void *data)
+{
+
+       struct snd_soc_jack *jack = (struct snd_soc_jack *)data;
+       struct snd_soc_dai *codec_dai = jack->card->rtd->codec_dai;
+       struct snd_soc_codec *codec = codec_dai->codec;
+
+       if (event & SND_JACK_MICROPHONE) {
+
+               snd_soc_dapm_force_enable_pin(&codec->dapm, "SHDN");
+               snd_soc_dapm_force_enable_pin(&codec->dapm, "MICBIAS");
+               snd_soc_dapm_sync(&codec->dapm);
+       } else {
+
+               snd_soc_dapm_disable_pin(&codec->dapm, "MICBIAS");
+               snd_soc_dapm_disable_pin(&codec->dapm, "SHDN");
+               snd_soc_dapm_sync(&codec->dapm);
+       }
+
+       return 0;
+}
+
+static struct notifier_block cht_jack_nb = {
+       .notifier_call = cht_ti_jack_event,
+};
+
+static int cht_codec_init(struct snd_soc_pcm_runtime *runtime)
+{
+       int ret;
+       int jack_type;
+       struct cht_mc_private *ctx = snd_soc_card_get_drvdata(runtime->card);
+       struct snd_soc_jack *jack = &ctx->jack;
+
+       /**
+       * TI supports 4 butons headset detection
+       * KEY_MEDIA
+       * KEY_VOICECOMMAND
+       * KEY_VOLUMEUP
+       * KEY_VOLUMEDOWN
+       */
+       if (ctx->ts3a227e_present)
+               jack_type = SND_JACK_HEADPHONE | SND_JACK_MICROPHONE |
+                                       SND_JACK_BTN_0 | SND_JACK_BTN_1 |
+                                       SND_JACK_BTN_2 | SND_JACK_BTN_3;
+       else
+               jack_type = SND_JACK_HEADPHONE | SND_JACK_MICROPHONE;
+
+       ret = snd_soc_card_jack_new(runtime->card, "Headset Jack",
+                                       jack_type, jack, NULL, 0);
+
+       if (ret) {
+               dev_err(runtime->dev, "Headset Jack creation failed %d\n", ret);
+               return ret;
+       }
+
+       if (ctx->ts3a227e_present)
+               snd_soc_jack_notifier_register(jack, &cht_jack_nb);
+
+       return ret;
+}
+
+static int cht_codec_fixup(struct snd_soc_pcm_runtime *rtd,
+                           struct snd_pcm_hw_params *params)
+{
+       struct snd_interval *rate = hw_param_interval(params,
+                       SNDRV_PCM_HW_PARAM_RATE);
+       struct snd_interval *channels = hw_param_interval(params,
+                                               SNDRV_PCM_HW_PARAM_CHANNELS);
+       int ret = 0;
+       unsigned int fmt = 0;
+
+       ret = snd_soc_dai_set_tdm_slot(rtd->cpu_dai, 0x3, 0x3, 2, 16);
+       if (ret < 0) {
+               dev_err(rtd->dev, "can't set cpu_dai slot fmt: %d\n", ret);
+               return ret;
+       }
+
+       fmt = SND_SOC_DAIFMT_LEFT_J | SND_SOC_DAIFMT_NB_NF
+                               | SND_SOC_DAIFMT_CBS_CFS;
+
+       ret = snd_soc_dai_set_fmt(rtd->cpu_dai, fmt);
+       if (ret < 0) {
+               dev_err(rtd->dev, "can't set cpu_dai set fmt: %d\n", ret);
+               return ret;
+       }
+
+       /* The DSP will covert the FE rate to 48k, stereo, 24bits */
+       rate->min = rate->max = 48000;
+       channels->min = channels->max = 2;
+
+       /* set SSP2 to 24-bit */
+       params_set_format(params, SNDRV_PCM_FORMAT_S24_LE);
+       return 0;
+}
+
+static unsigned int rates_48000[] = {
+       48000,
+};
+
+static struct snd_pcm_hw_constraint_list constraints_48000 = {
+       .count = ARRAY_SIZE(rates_48000),
+       .list  = rates_48000,
+};
+
+static int cht_aif1_startup(struct snd_pcm_substream *substream)
+{
+       return snd_pcm_hw_constraint_list(substream->runtime, 0,
+                       SNDRV_PCM_HW_PARAM_RATE,
+                       &constraints_48000);
+}
+
+static int cht_max98090_headset_init(struct snd_soc_component *component)
+{
+       struct snd_soc_card *card = component->card;
+       struct cht_mc_private *ctx = snd_soc_card_get_drvdata(card);
+
+       return ts3a227e_enable_jack_detect(component, &ctx->jack);
+}
+
+static struct snd_soc_ops cht_aif1_ops = {
+       .startup = cht_aif1_startup,
+};
+
+static struct snd_soc_ops cht_be_ssp2_ops = {
+       .hw_params = cht_aif1_hw_params,
+};
+
+static struct snd_soc_aux_dev cht_max98090_headset_dev = {
+       .name = "Headset Chip",
+       .init = cht_max98090_headset_init,
+       .codec_name = "i2c-104C227E:00",
+};
+
+static struct snd_soc_dai_link cht_dailink[] = {
+       [MERR_DPCM_AUDIO] = {
+               .name = "Audio Port",
+               .stream_name = "Audio",
+               .cpu_dai_name = "media-cpu-dai",
+               .codec_dai_name = "snd-soc-dummy-dai",
+               .codec_name = "snd-soc-dummy",
+               .platform_name = "sst-mfld-platform",
+               .nonatomic = true,
+               .dynamic = 1,
+               .dpcm_playback = 1,
+               .dpcm_capture = 1,
+               .ops = &cht_aif1_ops,
+       },
+       [MERR_DPCM_COMPR] = {
+               .name = "Compressed Port",
+               .stream_name = "Compress",
+               .cpu_dai_name = "compress-cpu-dai",
+               .codec_dai_name = "snd-soc-dummy-dai",
+               .codec_name = "snd-soc-dummy",
+               .platform_name = "sst-mfld-platform",
+       },
+       /* back ends */
+       {
+               .name = "SSP2-Codec",
+               .be_id = 1,
+               .cpu_dai_name = "ssp2-port",
+               .platform_name = "sst-mfld-platform",
+               .no_pcm = 1,
+               .codec_dai_name = "HiFi",
+               .codec_name = "i2c-193C9890:00",
+               .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF
+                                       | SND_SOC_DAIFMT_CBS_CFS,
+               .init = cht_codec_init,
+               .be_hw_params_fixup = cht_codec_fixup,
+               .dpcm_playback = 1,
+               .dpcm_capture = 1,
+               .ops = &cht_be_ssp2_ops,
+       },
+};
+
+/* SoC card */
+static struct snd_soc_card snd_soc_card_cht = {
+       .name = "chtmax98090",
+       .dai_link = cht_dailink,
+       .num_links = ARRAY_SIZE(cht_dailink),
+       .aux_dev = &cht_max98090_headset_dev,
+       .num_aux_devs = 1,
+       .dapm_widgets = cht_dapm_widgets,
+       .num_dapm_widgets = ARRAY_SIZE(cht_dapm_widgets),
+       .dapm_routes = cht_audio_map,
+       .num_dapm_routes = ARRAY_SIZE(cht_audio_map),
+       .controls = cht_mc_controls,
+       .num_controls = ARRAY_SIZE(cht_mc_controls),
+};
+
+static acpi_status snd_acpi_codec_match(acpi_handle handle, u32 level,
+                                               void *context, void **ret)
+{
+       *(bool *)context = true;
+       return AE_OK;
+}
+
+static int snd_cht_mc_probe(struct platform_device *pdev)
+{
+       int ret_val = 0;
+       bool found = false;
+       struct cht_mc_private *drv;
+
+       drv = devm_kzalloc(&pdev->dev, sizeof(*drv), GFP_ATOMIC);
+       if (!drv)
+               return -ENOMEM;
+
+       if (ACPI_SUCCESS(acpi_get_devices(
+                                       "104C227E",
+                                       snd_acpi_codec_match,
+                                       &found, NULL)) && found) {
+               drv->ts3a227e_present = true;
+       } else {
+               /* no need probe TI jack detection chip */
+               snd_soc_card_cht.aux_dev = NULL;
+               snd_soc_card_cht.num_aux_devs = 0;
+               drv->ts3a227e_present = false;
+       }
+
+       /* register the soc card */
+       snd_soc_card_cht.dev = &pdev->dev;
+       snd_soc_card_set_drvdata(&snd_soc_card_cht, drv);
+       ret_val = devm_snd_soc_register_card(&pdev->dev, &snd_soc_card_cht);
+       if (ret_val) {
+               dev_err(&pdev->dev,
+                       "snd_soc_register_card failed %d\n", ret_val);
+               return ret_val;
+       }
+       platform_set_drvdata(pdev, &snd_soc_card_cht);
+       return ret_val;
+}
+
+static struct platform_driver snd_cht_mc_driver = {
+       .driver = {
+               .name = "cht-bsw-max98090",
+       },
+       .probe = snd_cht_mc_probe,
+};
+
+module_platform_driver(snd_cht_mc_driver)
+
+MODULE_DESCRIPTION("ASoC Intel(R) Braswell Machine driver");
+MODULE_AUTHOR("Fang, Yang A <yang.a.fang@intel.com>");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:cht-bsw-max98090");
index 20a28b22e30fea84853f798f960130cbdf99bf7f..bdcaf467842ab788219689ab854048feef029f6c 100644 (file)
@@ -21,6 +21,7 @@
  */
 
 #include <linux/module.h>
+#include <linux/acpi.h>
 #include <linux/platform_device.h>
 #include <linux/slab.h>
 #include <sound/pcm.h>
 #define CHT_PLAT_CLK_3_HZ      19200000
 #define CHT_CODEC_DAI  "rt5645-aif1"
 
+struct cht_acpi_card {
+       char *codec_id;
+       int codec_type;
+       struct snd_soc_card *soc_card;
+};
+
 struct cht_mc_private {
-       struct snd_soc_jack hp_jack;
-       struct snd_soc_jack mic_jack;
+       struct snd_soc_jack jack;
+       struct cht_acpi_card *acpi_card;
 };
 
 static inline struct snd_soc_dai *cht_get_codec_dai(struct snd_soc_card *card)
@@ -94,7 +101,7 @@ static const struct snd_soc_dapm_widget cht_dapm_widgets[] = {
                        platform_clock_control, SND_SOC_DAPM_POST_PMD),
 };
 
-static const struct snd_soc_dapm_route cht_audio_map[] = {
+static const struct snd_soc_dapm_route cht_rt5645_audio_map[] = {
        {"IN1P", NULL, "Headset Mic"},
        {"IN1N", NULL, "Headset Mic"},
        {"DMIC L1", NULL, "Int Mic"},
@@ -115,6 +122,27 @@ static const struct snd_soc_dapm_route cht_audio_map[] = {
        {"Ext Spk", NULL, "Platform Clock"},
 };
 
+static const struct snd_soc_dapm_route cht_rt5650_audio_map[] = {
+       {"IN1P", NULL, "Headset Mic"},
+       {"IN1N", NULL, "Headset Mic"},
+       {"DMIC L2", NULL, "Int Mic"},
+       {"DMIC R2", NULL, "Int Mic"},
+       {"Headphone", NULL, "HPOL"},
+       {"Headphone", NULL, "HPOR"},
+       {"Ext Spk", NULL, "SPOL"},
+       {"Ext Spk", NULL, "SPOR"},
+       {"AIF1 Playback", NULL, "ssp2 Tx"},
+       {"ssp2 Tx", NULL, "codec_out0"},
+       {"ssp2 Tx", NULL, "codec_out1"},
+       {"codec_in0", NULL, "ssp2 Rx" },
+       {"codec_in1", NULL, "ssp2 Rx" },
+       {"ssp2 Rx", NULL, "AIF1 Capture"},
+       {"Headphone", NULL, "Platform Clock"},
+       {"Headset Mic", NULL, "Platform Clock"},
+       {"Int Mic", NULL, "Platform Clock"},
+       {"Ext Spk", NULL, "Platform Clock"},
+};
+
 static const struct snd_kcontrol_new cht_mc_controls[] = {
        SOC_DAPM_PIN_SWITCH("Headphone"),
        SOC_DAPM_PIN_SWITCH("Headset Mic"),
@@ -150,6 +178,7 @@ static int cht_aif1_hw_params(struct snd_pcm_substream *substream,
 static int cht_codec_init(struct snd_soc_pcm_runtime *runtime)
 {
        int ret;
+       int jack_type;
        struct snd_soc_codec *codec = runtime->codec;
        struct snd_soc_dai *codec_dai = runtime->codec_dai;
        struct cht_mc_private *ctx = snd_soc_card_get_drvdata(runtime->card);
@@ -169,23 +198,22 @@ static int cht_codec_init(struct snd_soc_pcm_runtime *runtime)
                return ret;
        }
 
-       ret = snd_soc_card_jack_new(runtime->card, "Headphone Jack",
-                                   SND_JACK_HEADPHONE, &ctx->hp_jack,
-                                   NULL, 0);
-       if (ret) {
-               dev_err(runtime->dev, "HP jack creation failed %d\n", ret);
-               return ret;
-       }
+       if (ctx->acpi_card->codec_type == CODEC_TYPE_RT5650)
+               jack_type = SND_JACK_HEADPHONE | SND_JACK_MICROPHONE |
+                                       SND_JACK_BTN_0 | SND_JACK_BTN_1 |
+                                       SND_JACK_BTN_2 | SND_JACK_BTN_3;
+       else
+               jack_type = SND_JACK_HEADPHONE | SND_JACK_MICROPHONE;
 
-       ret = snd_soc_card_jack_new(runtime->card, "Mic Jack",
-                                   SND_JACK_MICROPHONE, &ctx->mic_jack,
+       ret = snd_soc_card_jack_new(runtime->card, "Headset Jack",
+                                   jack_type, &ctx->jack,
                                    NULL, 0);
        if (ret) {
-               dev_err(runtime->dev, "Mic jack creation failed %d\n", ret);
+               dev_err(runtime->dev, "Headset jack creation failed %d\n", ret);
                return ret;
        }
 
-       rt5645_set_jack_detect(codec, &ctx->hp_jack, &ctx->mic_jack);
+       rt5645_set_jack_detect(codec, &ctx->jack, &ctx->jack, &ctx->jack);
 
        return ret;
 }
@@ -239,7 +267,7 @@ static struct snd_soc_dai_link cht_dailink[] = {
                .codec_dai_name = "snd-soc-dummy-dai",
                .codec_name = "snd-soc-dummy",
                .platform_name = "sst-mfld-platform",
-               .ignore_suspend = 1,
+               .nonatomic = true,
                .dynamic = 1,
                .dpcm_playback = 1,
                .dpcm_capture = 1,
@@ -267,7 +295,7 @@ static struct snd_soc_dai_link cht_dailink[] = {
                                        | SND_SOC_DAIFMT_CBS_CFS,
                .init = cht_codec_init,
                .be_hw_params_fixup = cht_codec_fixup,
-               .ignore_suspend = 1,
+               .nonatomic = true,
                .dpcm_playback = 1,
                .dpcm_capture = 1,
                .ops = &cht_be_ssp2_ops,
@@ -275,43 +303,85 @@ static struct snd_soc_dai_link cht_dailink[] = {
 };
 
 /* SoC card */
-static struct snd_soc_card snd_soc_card_cht = {
+static struct snd_soc_card snd_soc_card_chtrt5645 = {
        .name = "chtrt5645",
        .dai_link = cht_dailink,
        .num_links = ARRAY_SIZE(cht_dailink),
        .dapm_widgets = cht_dapm_widgets,
        .num_dapm_widgets = ARRAY_SIZE(cht_dapm_widgets),
-       .dapm_routes = cht_audio_map,
-       .num_dapm_routes = ARRAY_SIZE(cht_audio_map),
+       .dapm_routes = cht_rt5645_audio_map,
+       .num_dapm_routes = ARRAY_SIZE(cht_rt5645_audio_map),
        .controls = cht_mc_controls,
        .num_controls = ARRAY_SIZE(cht_mc_controls),
 };
 
+static struct snd_soc_card snd_soc_card_chtrt5650 = {
+       .name = "chtrt5650",
+       .dai_link = cht_dailink,
+       .num_links = ARRAY_SIZE(cht_dailink),
+       .dapm_widgets = cht_dapm_widgets,
+       .num_dapm_widgets = ARRAY_SIZE(cht_dapm_widgets),
+       .dapm_routes = cht_rt5650_audio_map,
+       .num_dapm_routes = ARRAY_SIZE(cht_rt5650_audio_map),
+       .controls = cht_mc_controls,
+       .num_controls = ARRAY_SIZE(cht_mc_controls),
+};
+
+static struct cht_acpi_card snd_soc_cards[] = {
+       {"10EC5645", CODEC_TYPE_RT5645, &snd_soc_card_chtrt5645},
+       {"10EC5650", CODEC_TYPE_RT5650, &snd_soc_card_chtrt5650},
+};
+
+static acpi_status snd_acpi_codec_match(acpi_handle handle, u32 level,
+                                      void *context, void **ret)
+{
+       *(bool *)context = true;
+       return AE_OK;
+}
+
 static int snd_cht_mc_probe(struct platform_device *pdev)
 {
        int ret_val = 0;
+       int i;
        struct cht_mc_private *drv;
+       struct snd_soc_card *card = snd_soc_cards[0].soc_card;
+       bool found = false;
+       char codec_name[16];
 
        drv = devm_kzalloc(&pdev->dev, sizeof(*drv), GFP_ATOMIC);
        if (!drv)
                return -ENOMEM;
 
-       snd_soc_card_cht.dev = &pdev->dev;
-       snd_soc_card_set_drvdata(&snd_soc_card_cht, drv);
-       ret_val = devm_snd_soc_register_card(&pdev->dev, &snd_soc_card_cht);
+       for (i = 0; i < ARRAY_SIZE(snd_soc_cards); i++) {
+               if (ACPI_SUCCESS(acpi_get_devices(
+                                               snd_soc_cards[i].codec_id,
+                                               snd_acpi_codec_match,
+                                               &found, NULL)) && found) {
+                       dev_dbg(&pdev->dev,
+                               "found codec %s\n", snd_soc_cards[i].codec_id);
+                       card = snd_soc_cards[i].soc_card;
+                       drv->acpi_card = &snd_soc_cards[i];
+                       break;
+               }
+       }
+       card->dev = &pdev->dev;
+       sprintf(codec_name, "i2c-%s:00", drv->acpi_card->codec_id);
+       /* set correct codec name */
+       strcpy((char *)card->dai_link[2].codec_name, codec_name);
+       snd_soc_card_set_drvdata(card, drv);
+       ret_val = devm_snd_soc_register_card(&pdev->dev, card);
        if (ret_val) {
                dev_err(&pdev->dev,
                        "snd_soc_register_card failed %d\n", ret_val);
                return ret_val;
        }
-       platform_set_drvdata(pdev, &snd_soc_card_cht);
+       platform_set_drvdata(pdev, card);
        return ret_val;
 }
 
 static struct platform_driver snd_cht_mc_driver = {
        .driver = {
                .name = "cht-bsw-rt5645",
-               .pm = &snd_soc_pm_ops,
        },
        .probe = snd_cht_mc_probe,
 };
index 42f293f9c6e2dcfbdf5da2f451a6cf196fc296dc..67b6d3d52f57f69f4dd6fed65cc8546b694996ee 100644 (file)
@@ -263,7 +263,7 @@ static struct sst_acpi_desc sst_acpi_baytrail_desc = {
        .resindex_dma_base = -1,
 };
 
-static struct acpi_device_id sst_acpi_match[] = {
+static const struct acpi_device_id sst_acpi_match[] = {
        { "INT33C8", (unsigned long)&sst_acpi_haswell_desc },
        { "INT3438", (unsigned long)&sst_acpi_broadwell_desc },
        { "80860F28", (unsigned long)&sst_acpi_baytrail_desc },
index 4b62a553823ccdb91ded137c6a4e2bf113b7dff5..a12c7bb08d3b88b891e30cf2d920b39929028c45 100644 (file)
@@ -129,11 +129,31 @@ static int msg_empty_list_init(struct sst_generic_ipc *ipc)
                return -ENOMEM;
 
        for (i = 0; i < IPC_EMPTY_LIST_SIZE; i++) {
+               ipc->msg[i].tx_data = kzalloc(ipc->tx_data_max_size, GFP_KERNEL);
+               if (ipc->msg[i].tx_data == NULL)
+                       goto free_mem;
+
+               ipc->msg[i].rx_data = kzalloc(ipc->rx_data_max_size, GFP_KERNEL);
+               if (ipc->msg[i].rx_data == NULL) {
+                       kfree(ipc->msg[i].tx_data);
+                       goto free_mem;
+               }
+
                init_waitqueue_head(&ipc->msg[i].waitq);
                list_add(&ipc->msg[i].list, &ipc->empty_list);
        }
 
        return 0;
+
+free_mem:
+       while (i > 0) {
+               kfree(ipc->msg[i-1].tx_data);
+               kfree(ipc->msg[i-1].rx_data);
+               --i;
+       }
+       kfree(ipc->msg);
+
+       return -ENOMEM;
 }
 
 static void ipc_tx_msgs(struct kthread_work *work)
@@ -142,7 +162,6 @@ static void ipc_tx_msgs(struct kthread_work *work)
                container_of(work, struct sst_generic_ipc, kwork);
        struct ipc_message *msg;
        unsigned long flags;
-       u64 ipcx;
 
        spin_lock_irqsave(&ipc->dsp->spinlock, flags);
 
@@ -153,8 +172,8 @@ static void ipc_tx_msgs(struct kthread_work *work)
 
        /* if the DSP is busy, we will TX messages after IRQ.
         * also postpone if we are in the middle of procesing completion irq*/
-       ipcx = sst_dsp_shim_read_unlocked(ipc->dsp, SST_IPCX);
-       if (ipcx & (SST_IPCX_BUSY | SST_IPCX_DONE)) {
+       if (ipc->ops.is_dsp_busy && ipc->ops.is_dsp_busy(ipc->dsp)) {
+               dev_dbg(ipc->dev, "ipc_tx_msgs dsp busy\n");
                spin_unlock_irqrestore(&ipc->dsp->spinlock, flags);
                return;
        }
@@ -280,11 +299,18 @@ EXPORT_SYMBOL_GPL(sst_ipc_init);
 
 void sst_ipc_fini(struct sst_generic_ipc *ipc)
 {
+       int i;
+
        if (ipc->tx_thread)
                kthread_stop(ipc->tx_thread);
 
-       if (ipc->msg)
+       if (ipc->msg) {
+               for (i = 0; i < IPC_EMPTY_LIST_SIZE; i++) {
+                       kfree(ipc->msg[i].tx_data);
+                       kfree(ipc->msg[i].rx_data);
+               }
                kfree(ipc->msg);
+       }
 }
 EXPORT_SYMBOL_GPL(sst_ipc_fini);
 
index 125ea451a37369a939034646ed7bb37402d307c4..ceb7e468a3fa6db4e04c77ff3a9d7e1ffc83d840 100644 (file)
@@ -32,9 +32,9 @@ struct ipc_message {
        u64 header;
 
        /* direction wrt host CPU */
-       char tx_data[IPC_MAX_MAILBOX_BYTES];
+       char *tx_data;
        size_t tx_size;
-       char rx_data[IPC_MAX_MAILBOX_BYTES];
+       char *rx_data;
        size_t rx_size;
 
        wait_queue_head_t waitq;
@@ -51,6 +51,7 @@ struct sst_plat_ipc_ops {
        void (*shim_dbg)(struct sst_generic_ipc *, const char *);
        void (*tx_data_copy)(struct ipc_message *, char *, size_t);
        u64  (*reply_msg_match)(u64 header, u64 *mask);
+       bool (*is_dsp_busy)(struct sst_dsp *dsp);
 };
 
 /* SST generic IPC data */
@@ -68,6 +69,8 @@ struct sst_generic_ipc {
        struct kthread_work kwork;
        bool pending;
        struct ipc_message *msg;
+       int tx_data_max_size;
+       int rx_data_max_size;
 
        struct sst_plat_ipc_ops ops;
 };
index 344a1e9bbce5794311ec95a24143581ebf715907..f95f271aab0ce30412954428b426af2461438dea 100644 (file)
@@ -2098,6 +2098,14 @@ static u64 hsw_reply_msg_match(u64 header, u64 *mask)
        return header;
 }
 
+static bool hsw_is_dsp_busy(struct sst_dsp *dsp)
+{
+       u64 ipcx;
+
+       ipcx = sst_dsp_shim_read_unlocked(dsp, SST_IPCX);
+       return (ipcx & (SST_IPCX_BUSY | SST_IPCX_DONE));
+}
+
 int sst_hsw_dsp_init(struct device *dev, struct sst_pdata *pdata)
 {
        struct sst_hsw_ipc_fw_version version;
@@ -2117,6 +2125,10 @@ int sst_hsw_dsp_init(struct device *dev, struct sst_pdata *pdata)
        ipc->ops.shim_dbg = hsw_shim_dbg;
        ipc->ops.tx_data_copy = hsw_tx_data_copy;
        ipc->ops.reply_msg_match = hsw_reply_msg_match;
+       ipc->ops.is_dsp_busy = hsw_is_dsp_busy;
+
+       ipc->tx_data_max_size = IPC_MAX_MAILBOX_BYTES;
+       ipc->rx_data_max_size = IPC_MAX_MAILBOX_BYTES;
 
        ret = sst_ipc_init(ipc);
        if (ret != 0)
@@ -2201,7 +2213,6 @@ dma_err:
 dsp_new_err:
        sst_ipc_fini(ipc);
 ipc_init_err:
-       kfree(hsw);
        return ret;
 }
 EXPORT_SYMBOL_GPL(sst_hsw_dsp_init);
index 23ae0400d6db99668b3d2b48b47eb003d2fc2e46..e593e7a4b7a7c1f67a56bd57c06ab7dbb36f8ad6 100644 (file)
@@ -928,10 +928,15 @@ static void hsw_pcm_free_modules(struct hsw_priv_data *pdata)
 
        for (i = 0; i < ARRAY_SIZE(mod_map); i++) {
                pcm_data = &pdata->pcm[mod_map[i].dai_id][mod_map[i].stream];
-               sst_hsw_runtime_module_free(pcm_data->runtime);
+               if (pcm_data->runtime){
+                       sst_hsw_runtime_module_free(pcm_data->runtime);
+                       pcm_data->runtime = NULL;
+               }
        }
-       if (sst_hsw_is_module_loaded(hsw, SST_HSW_MODULE_WAVES)) {
+       if (sst_hsw_is_module_loaded(hsw, SST_HSW_MODULE_WAVES) &&
+                               pdata->runtime_waves) {
                sst_hsw_runtime_module_free(pdata->runtime_waves);
+               pdata->runtime_waves = NULL;
        }
 }
 
@@ -1204,6 +1209,20 @@ static int hsw_pcm_runtime_idle(struct device *dev)
        return 0;
 }
 
+static int hsw_pcm_suspend(struct device *dev)
+{
+       struct hsw_priv_data *pdata = dev_get_drvdata(dev);
+       struct sst_hsw *hsw = pdata->hsw;
+
+       /* enter D3 state and stall */
+       sst_hsw_dsp_runtime_suspend(hsw);
+       /* free all runtime modules */
+       hsw_pcm_free_modules(pdata);
+       /* put the DSP to sleep, fw unloaded after runtime modules freed */
+       sst_hsw_dsp_runtime_sleep(hsw);
+       return 0;
+}
+
 static int hsw_pcm_runtime_suspend(struct device *dev)
 {
        struct hsw_priv_data *pdata = dev_get_drvdata(dev);
@@ -1220,8 +1239,7 @@ static int hsw_pcm_runtime_suspend(struct device *dev)
                        return ret;
                sst_hsw_set_module_enabled_rtd3(hsw, SST_HSW_MODULE_WAVES);
        }
-       sst_hsw_dsp_runtime_suspend(hsw);
-       sst_hsw_dsp_runtime_sleep(hsw);
+       hsw_pcm_suspend(dev);
        pdata->pm_state = HSW_PM_STATE_RTD3;
 
        return 0;
@@ -1361,10 +1379,7 @@ static int hsw_pcm_prepare(struct device *dev)
                        if (err < 0)
                                dev_err(dev, "failed to save context for PCM %d\n", i);
                }
-               /* enter D3 state and stall */
-               sst_hsw_dsp_runtime_suspend(hsw);
-               /* put the DSP to sleep */
-               sst_hsw_dsp_runtime_sleep(hsw);
+               hsw_pcm_suspend(dev);
        }
 
        snd_soc_suspend(pdata->soc_card->dev);
diff --git a/sound/soc/mediatek/Kconfig b/sound/soc/mediatek/Kconfig
new file mode 100644 (file)
index 0000000..15c04e2
--- /dev/null
@@ -0,0 +1,30 @@
+config SND_SOC_MEDIATEK
+       tristate "ASoC support for Mediatek chip"
+       depends on ARCH_MEDIATEK
+       help
+         This adds ASoC platform driver support for Mediatek chip
+         that can be used with other codecs.
+         Select Y if you have such device.
+         Ex: MT8173
+
+config SND_SOC_MT8173_MAX98090
+       tristate "ASoC Audio driver for MT8173 with MAX98090 codec"
+       depends on SND_SOC_MEDIATEK
+       select SND_SOC_MAX98090
+       help
+         This adds ASoC driver for Mediatek MT8173 boards
+         with the MAX98090 audio codec.
+         Select Y if you have such device.
+         If unsure select "N".
+
+config SND_SOC_MT8173_RT5650_RT5676
+       tristate "ASoC Audio driver for MT8173 with RT5650 RT5676 codecs"
+       depends on SND_SOC_MEDIATEK
+       select SND_SOC_RT5645
+       select SND_SOC_RT5677
+       help
+         This adds ASoC driver for Mediatek MT8173 boards
+         with the RT5650 and RT5676 codecs.
+         Select Y if you have such device.
+         If unsure select "N".
+
diff --git a/sound/soc/mediatek/Makefile b/sound/soc/mediatek/Makefile
new file mode 100644 (file)
index 0000000..75effbe
--- /dev/null
@@ -0,0 +1,5 @@
+# MTK Platform Support
+obj-$(CONFIG_SND_SOC_MEDIATEK) += mtk-afe-pcm.o
+# Machine support
+obj-$(CONFIG_SND_SOC_MT8173_MAX98090) += mt8173-max98090.o
+obj-$(CONFIG_SND_SOC_MT8173_RT5650_RT5676) += mt8173-rt5650-rt5676.o
diff --git a/sound/soc/mediatek/mt8173-max98090.c b/sound/soc/mediatek/mt8173-max98090.c
new file mode 100644 (file)
index 0000000..4d44b58
--- /dev/null
@@ -0,0 +1,213 @@
+/*
+ * mt8173-max98090.c  --  MT8173 MAX98090 ALSA SoC machine driver
+ *
+ * Copyright (c) 2015 MediaTek Inc.
+ * Author: Koro Chen <koro.chen@mediatek.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/module.h>
+#include <sound/soc.h>
+#include <sound/jack.h>
+#include <linux/gpio.h>
+#include "../codecs/max98090.h"
+
+static struct snd_soc_jack mt8173_max98090_jack;
+
+static struct snd_soc_jack_pin mt8173_max98090_jack_pins[] = {
+       {
+               .pin    = "Headphone",
+               .mask   = SND_JACK_HEADPHONE,
+       },
+       {
+               .pin    = "Headset Mic",
+               .mask   = SND_JACK_MICROPHONE,
+       },
+};
+
+static const struct snd_soc_dapm_widget mt8173_max98090_widgets[] = {
+       SND_SOC_DAPM_SPK("Speaker", NULL),
+       SND_SOC_DAPM_MIC("Int Mic", NULL),
+       SND_SOC_DAPM_HP("Headphone", NULL),
+       SND_SOC_DAPM_MIC("Headset Mic", NULL),
+};
+
+static const struct snd_soc_dapm_route mt8173_max98090_routes[] = {
+       {"Speaker", NULL, "SPKL"},
+       {"Speaker", NULL, "SPKR"},
+       {"DMICL", NULL, "Int Mic"},
+       {"Headphone", NULL, "HPL"},
+       {"Headphone", NULL, "HPR"},
+       {"Headset Mic", NULL, "MICBIAS"},
+       {"IN34", NULL, "Headset Mic"},
+};
+
+static const struct snd_kcontrol_new mt8173_max98090_controls[] = {
+       SOC_DAPM_PIN_SWITCH("Speaker"),
+       SOC_DAPM_PIN_SWITCH("Int Mic"),
+       SOC_DAPM_PIN_SWITCH("Headphone"),
+       SOC_DAPM_PIN_SWITCH("Headset Mic"),
+};
+
+static int mt8173_max98090_hw_params(struct snd_pcm_substream *substream,
+                                    struct snd_pcm_hw_params *params)
+{
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+       struct snd_soc_dai *codec_dai = rtd->codec_dai;
+
+       return snd_soc_dai_set_sysclk(codec_dai, 0, params_rate(params) * 256,
+                                     SND_SOC_CLOCK_IN);
+}
+
+static struct snd_soc_ops mt8173_max98090_ops = {
+       .hw_params = mt8173_max98090_hw_params,
+};
+
+static int mt8173_max98090_init(struct snd_soc_pcm_runtime *runtime)
+{
+       int ret;
+       struct snd_soc_card *card = runtime->card;
+       struct snd_soc_codec *codec = runtime->codec;
+
+       /* enable jack detection */
+       ret = snd_soc_card_jack_new(card, "Headphone", SND_JACK_HEADPHONE,
+                                   &mt8173_max98090_jack, NULL, 0);
+       if (ret) {
+               dev_err(card->dev, "Can't snd_soc_jack_new %d\n", ret);
+               return ret;
+       }
+
+       ret = snd_soc_jack_add_pins(&mt8173_max98090_jack,
+                                   ARRAY_SIZE(mt8173_max98090_jack_pins),
+                                   mt8173_max98090_jack_pins);
+       if (ret) {
+               dev_err(card->dev, "Can't snd_soc_jack_add_pins %d\n", ret);
+               return ret;
+       }
+
+       return max98090_mic_detect(codec, &mt8173_max98090_jack);
+}
+
+/* Digital audio interface glue - connects codec <---> CPU */
+static struct snd_soc_dai_link mt8173_max98090_dais[] = {
+       /* Front End DAI links */
+       {
+               .name = "MAX98090 Playback",
+               .stream_name = "MAX98090 Playback",
+               .cpu_dai_name = "DL1",
+               .platform_name = "11220000.mt8173-afe-pcm",
+               .codec_name = "snd-soc-dummy",
+               .codec_dai_name = "snd-soc-dummy-dai",
+               .trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST},
+               .dynamic = 1,
+               .dpcm_playback = 1,
+       },
+       {
+               .name = "MAX98090 Capture",
+               .stream_name = "MAX98090 Capture",
+               .cpu_dai_name = "VUL",
+               .platform_name = "11220000.mt8173-afe-pcm",
+               .codec_name = "snd-soc-dummy",
+               .codec_dai_name = "snd-soc-dummy-dai",
+               .trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST},
+               .dynamic = 1,
+               .dpcm_capture = 1,
+       },
+       /* Back End DAI links */
+       {
+               .name = "Codec",
+               .cpu_dai_name = "I2S",
+               .platform_name = "11220000.mt8173-afe-pcm",
+               .no_pcm = 1,
+               .codec_dai_name = "HiFi",
+               .init = mt8173_max98090_init,
+               .ops = &mt8173_max98090_ops,
+               .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
+                          SND_SOC_DAIFMT_CBS_CFS,
+               .dpcm_playback = 1,
+               .dpcm_capture = 1,
+       },
+};
+
+static struct snd_soc_card mt8173_max98090_card = {
+       .name = "mt8173-max98090",
+       .dai_link = mt8173_max98090_dais,
+       .num_links = ARRAY_SIZE(mt8173_max98090_dais),
+       .controls = mt8173_max98090_controls,
+       .num_controls = ARRAY_SIZE(mt8173_max98090_controls),
+       .dapm_widgets = mt8173_max98090_widgets,
+       .num_dapm_widgets = ARRAY_SIZE(mt8173_max98090_widgets),
+       .dapm_routes = mt8173_max98090_routes,
+       .num_dapm_routes = ARRAY_SIZE(mt8173_max98090_routes),
+};
+
+static int mt8173_max98090_dev_probe(struct platform_device *pdev)
+{
+       struct snd_soc_card *card = &mt8173_max98090_card;
+       struct device_node *codec_node;
+       int ret, i;
+
+       codec_node = of_parse_phandle(pdev->dev.of_node,
+                                     "mediatek,audio-codec", 0);
+       if (!codec_node) {
+               dev_err(&pdev->dev,
+                       "Property 'audio-codec' missing or invalid\n");
+               return -EINVAL;
+       }
+       for (i = 0; i < card->num_links; i++) {
+               if (mt8173_max98090_dais[i].codec_name)
+                       continue;
+               mt8173_max98090_dais[i].codec_of_node = codec_node;
+       }
+       card->dev = &pdev->dev;
+
+       ret = snd_soc_register_card(card);
+       if (ret)
+               dev_err(&pdev->dev, "%s snd_soc_register_card fail %d\n",
+                       __func__, ret);
+       return ret;
+}
+
+static int mt8173_max98090_dev_remove(struct platform_device *pdev)
+{
+       struct snd_soc_card *card = platform_get_drvdata(pdev);
+
+       snd_soc_unregister_card(card);
+       return 0;
+}
+
+static const struct of_device_id mt8173_max98090_dt_match[] = {
+       { .compatible = "mediatek,mt8173-max98090", },
+       { }
+};
+MODULE_DEVICE_TABLE(of, mt8173_max98090_dt_match);
+
+static struct platform_driver mt8173_max98090_driver = {
+       .driver = {
+                  .name = "mt8173-max98090",
+                  .owner = THIS_MODULE,
+                  .of_match_table = mt8173_max98090_dt_match,
+#ifdef CONFIG_PM
+                  .pm = &snd_soc_pm_ops,
+#endif
+       },
+       .probe = mt8173_max98090_dev_probe,
+       .remove = mt8173_max98090_dev_remove,
+};
+
+module_platform_driver(mt8173_max98090_driver);
+
+/* Module information */
+MODULE_DESCRIPTION("MT8173 MAX98090 ALSA SoC machine driver");
+MODULE_AUTHOR("Koro Chen <koro.chen@mediatek.com>");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:mt8173-max98090");
+
diff --git a/sound/soc/mediatek/mt8173-rt5650-rt5676.c b/sound/soc/mediatek/mt8173-rt5650-rt5676.c
new file mode 100644 (file)
index 0000000..0940553
--- /dev/null
@@ -0,0 +1,278 @@
+/*
+ * mt8173-rt5650-rt5676.c  --  MT8173 machine driver with RT5650/5676 codecs
+ *
+ * Copyright (c) 2015 MediaTek Inc.
+ * Author: Koro Chen <koro.chen@mediatek.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/module.h>
+#include <linux/gpio.h>
+#include <linux/of_gpio.h>
+#include <sound/soc.h>
+#include <sound/jack.h>
+#include "../codecs/rt5645.h"
+#include "../codecs/rt5677.h"
+
+#define MCLK_FOR_CODECS                12288000
+
+static const struct snd_soc_dapm_widget mt8173_rt5650_rt5676_widgets[] = {
+       SND_SOC_DAPM_SPK("Speaker", NULL),
+       SND_SOC_DAPM_MIC("Int Mic", NULL),
+       SND_SOC_DAPM_HP("Headphone", NULL),
+       SND_SOC_DAPM_MIC("Headset Mic", NULL),
+};
+
+static const struct snd_soc_dapm_route mt8173_rt5650_rt5676_routes[] = {
+       {"Speaker", NULL, "SPOL"},
+       {"Speaker", NULL, "SPOR"},
+       {"Speaker", NULL, "Sub AIF2TX"}, /* IF2 ADC to 5650  */
+       {"Sub DMIC L1", NULL, "Int Mic"}, /* DMIC from 5676 */
+       {"Sub DMIC R1", NULL, "Int Mic"},
+       {"Headphone", NULL, "HPOL"},
+       {"Headphone", NULL, "HPOR"},
+       {"Headphone", NULL, "Sub AIF2TX"}, /* IF2 ADC to 5650  */
+       {"Headset Mic", NULL, "micbias1"},
+       {"Headset Mic", NULL, "micbias2"},
+       {"IN1P", NULL, "Headset Mic"},
+       {"IN1N", NULL, "Headset Mic"},
+       {"Sub AIF2RX", NULL, "Headset Mic"}, /* IF2 DAC from 5650  */
+};
+
+static const struct snd_kcontrol_new mt8173_rt5650_rt5676_controls[] = {
+       SOC_DAPM_PIN_SWITCH("Speaker"),
+       SOC_DAPM_PIN_SWITCH("Int Mic"),
+       SOC_DAPM_PIN_SWITCH("Headphone"),
+       SOC_DAPM_PIN_SWITCH("Headset Mic"),
+};
+
+static int mt8173_rt5650_rt5676_hw_params(struct snd_pcm_substream *substream,
+                                         struct snd_pcm_hw_params *params)
+{
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+       int i, ret;
+
+       for (i = 0; i < rtd->num_codecs; i++) {
+               struct snd_soc_dai *codec_dai = rtd->codec_dais[i];
+
+               /* pll from mclk 12.288M */
+               ret = snd_soc_dai_set_pll(codec_dai, 0, 0, MCLK_FOR_CODECS,
+                                         params_rate(params) * 512);
+               if (ret)
+                       return ret;
+
+               /* sysclk from pll */
+               ret = snd_soc_dai_set_sysclk(codec_dai, 1,
+                                            params_rate(params) * 512,
+                                            SND_SOC_CLOCK_IN);
+               if (ret)
+                       return ret;
+       }
+       return 0;
+}
+
+static struct snd_soc_ops mt8173_rt5650_rt5676_ops = {
+       .hw_params = mt8173_rt5650_rt5676_hw_params,
+};
+
+static struct snd_soc_jack mt8173_rt5650_rt5676_jack;
+
+static int mt8173_rt5650_rt5676_init(struct snd_soc_pcm_runtime *runtime)
+{
+       struct snd_soc_card *card = runtime->card;
+       struct snd_soc_codec *codec = runtime->codec_dais[0]->codec;
+       struct snd_soc_codec *codec_sub = runtime->codec_dais[1]->codec;
+       int ret;
+
+       rt5645_sel_asrc_clk_src(codec,
+                               RT5645_DA_STEREO_FILTER |
+                               RT5645_AD_STEREO_FILTER,
+                               RT5645_CLK_SEL_I2S1_ASRC);
+       rt5677_sel_asrc_clk_src(codec_sub,
+                               RT5677_DA_STEREO_FILTER |
+                               RT5677_AD_STEREO1_FILTER,
+                               RT5677_CLK_SEL_I2S1_ASRC);
+       rt5677_sel_asrc_clk_src(codec_sub,
+                               RT5677_AD_STEREO2_FILTER |
+                               RT5677_I2S2_SOURCE,
+                               RT5677_CLK_SEL_I2S2_ASRC);
+
+       /* enable jack detection */
+       ret = snd_soc_card_jack_new(card, "Headset Jack",
+                                   SND_JACK_HEADPHONE | SND_JACK_MICROPHONE |
+                                   SND_JACK_BTN_0 | SND_JACK_BTN_1 |
+                                   SND_JACK_BTN_2 | SND_JACK_BTN_3,
+                                   &mt8173_rt5650_rt5676_jack, NULL, 0);
+       if (ret) {
+               dev_err(card->dev, "Can't new Headset Jack %d\n", ret);
+               return ret;
+       }
+
+       return rt5645_set_jack_detect(codec,
+                                     &mt8173_rt5650_rt5676_jack,
+                                     &mt8173_rt5650_rt5676_jack,
+                                     &mt8173_rt5650_rt5676_jack);
+}
+
+static struct snd_soc_dai_link_component mt8173_rt5650_rt5676_codecs[] = {
+       {
+               .dai_name = "rt5645-aif1",
+       },
+       {
+               .dai_name = "rt5677-aif1",
+       },
+};
+
+/* Digital audio interface glue - connects codec <---> CPU */
+static struct snd_soc_dai_link mt8173_rt5650_rt5676_dais[] = {
+       /* Front End DAI links */
+       {
+               .name = "rt5650_rt5676 Playback",
+               .stream_name = "rt5650_rt5676 Playback",
+               .cpu_dai_name = "DL1",
+               .platform_name = "11220000.mt8173-afe-pcm",
+               .codec_name = "snd-soc-dummy",
+               .codec_dai_name = "snd-soc-dummy-dai",
+               .trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST},
+               .dynamic = 1,
+               .dpcm_playback = 1,
+       },
+       {
+               .name = "rt5650_rt5676 Capture",
+               .stream_name = "rt5650_rt5676 Capture",
+               .cpu_dai_name = "VUL",
+               .platform_name = "11220000.mt8173-afe-pcm",
+               .codec_name = "snd-soc-dummy",
+               .codec_dai_name = "snd-soc-dummy-dai",
+               .trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST},
+               .dynamic = 1,
+               .dpcm_capture = 1,
+       },
+
+       /* Back End DAI links */
+       {
+               .name = "Codec",
+               .cpu_dai_name = "I2S",
+               .platform_name = "11220000.mt8173-afe-pcm",
+               .no_pcm = 1,
+               .codecs = mt8173_rt5650_rt5676_codecs,
+               .num_codecs = 2,
+               .init = mt8173_rt5650_rt5676_init,
+               .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
+                          SND_SOC_DAIFMT_CBS_CFS,
+               .ops = &mt8173_rt5650_rt5676_ops,
+               .ignore_pmdown_time = 1,
+               .dpcm_playback = 1,
+               .dpcm_capture = 1,
+       },
+       { /* rt5676 <-> rt5650 intercodec link: Sets rt5676 I2S2 as master */
+               .name = "rt5650_rt5676 intercodec",
+               .stream_name = "rt5650_rt5676 intercodec",
+               .cpu_dai_name = "snd-soc-dummy-dai",
+               .platform_name = "snd-soc-dummy",
+               .no_pcm = 1,
+               .codec_dai_name = "rt5677-aif2",
+               .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
+                          SND_SOC_DAIFMT_CBM_CFM,
+       },
+
+};
+
+static struct snd_soc_codec_conf mt8173_rt5650_rt5676_codec_conf[] = {
+       {
+               .name_prefix = "Sub",
+       },
+};
+
+static struct snd_soc_card mt8173_rt5650_rt5676_card = {
+       .name = "mtk-rt5650-rt5676",
+       .dai_link = mt8173_rt5650_rt5676_dais,
+       .num_links = ARRAY_SIZE(mt8173_rt5650_rt5676_dais),
+       .codec_conf = mt8173_rt5650_rt5676_codec_conf,
+       .num_configs = ARRAY_SIZE(mt8173_rt5650_rt5676_codec_conf),
+       .controls = mt8173_rt5650_rt5676_controls,
+       .num_controls = ARRAY_SIZE(mt8173_rt5650_rt5676_controls),
+       .dapm_widgets = mt8173_rt5650_rt5676_widgets,
+       .num_dapm_widgets = ARRAY_SIZE(mt8173_rt5650_rt5676_widgets),
+       .dapm_routes = mt8173_rt5650_rt5676_routes,
+       .num_dapm_routes = ARRAY_SIZE(mt8173_rt5650_rt5676_routes),
+};
+
+static int mt8173_rt5650_rt5676_dev_probe(struct platform_device *pdev)
+{
+       struct snd_soc_card *card = &mt8173_rt5650_rt5676_card;
+       int ret;
+
+       mt8173_rt5650_rt5676_codecs[0].of_node =
+               of_parse_phandle(pdev->dev.of_node, "mediatek,audio-codec", 0);
+       if (!mt8173_rt5650_rt5676_codecs[0].of_node) {
+               dev_err(&pdev->dev,
+                       "Property 'audio-codec' missing or invalid\n");
+               return -EINVAL;
+       }
+       mt8173_rt5650_rt5676_codecs[1].of_node =
+               of_parse_phandle(pdev->dev.of_node, "mediatek,audio-codec", 1);
+       if (!mt8173_rt5650_rt5676_codecs[1].of_node) {
+               dev_err(&pdev->dev,
+                       "Property 'audio-codec' missing or invalid\n");
+               return -EINVAL;
+       }
+       mt8173_rt5650_rt5676_codec_conf[0].of_node =
+               mt8173_rt5650_rt5676_codecs[1].of_node;
+
+       mt8173_rt5650_rt5676_dais[3].codec_of_node =
+               mt8173_rt5650_rt5676_codecs[1].of_node;
+
+       card->dev = &pdev->dev;
+       platform_set_drvdata(pdev, card);
+
+       ret = snd_soc_register_card(card);
+       if (ret)
+               dev_err(&pdev->dev, "%s snd_soc_register_card fail %d\n",
+                       __func__, ret);
+       return ret;
+}
+
+static int mt8173_rt5650_rt5676_dev_remove(struct platform_device *pdev)
+{
+       struct snd_soc_card *card = platform_get_drvdata(pdev);
+
+       snd_soc_unregister_card(card);
+       return 0;
+}
+
+static const struct of_device_id mt8173_rt5650_rt5676_dt_match[] = {
+       { .compatible = "mediatek,mt8173-rt5650-rt5676", },
+       { }
+};
+MODULE_DEVICE_TABLE(of, mt8173_rt5650_rt5676_dt_match);
+
+static struct platform_driver mt8173_rt5650_rt5676_driver = {
+       .driver = {
+                  .name = "mtk-rt5650-rt5676",
+                  .owner = THIS_MODULE,
+                  .of_match_table = mt8173_rt5650_rt5676_dt_match,
+#ifdef CONFIG_PM
+                  .pm = &snd_soc_pm_ops,
+#endif
+       },
+       .probe = mt8173_rt5650_rt5676_dev_probe,
+       .remove = mt8173_rt5650_rt5676_dev_remove,
+};
+
+module_platform_driver(mt8173_rt5650_rt5676_driver);
+
+/* Module information */
+MODULE_DESCRIPTION("MT8173 RT5650 and RT5676 SoC machine driver");
+MODULE_AUTHOR("Koro Chen <koro.chen@mediatek.com>");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:mtk-rt5650-rt5676");
+
diff --git a/sound/soc/mediatek/mtk-afe-common.h b/sound/soc/mediatek/mtk-afe-common.h
new file mode 100644 (file)
index 0000000..a88b175
--- /dev/null
@@ -0,0 +1,109 @@
+/*
+ * mtk_afe_common.h  --  Mediatek audio driver common definitions
+ *
+ * Copyright (c) 2015 MediaTek Inc.
+ * Author: Koro Chen <koro.chen@mediatek.com>
+ *             Sascha Hauer <s.hauer@pengutronix.de>
+ *             Hidalgo Huang <hidalgo.huang@mediatek.com>
+ *             Ir Lian <ir.lian@mediatek.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef _MTK_AFE_COMMON_H_
+#define _MTK_AFE_COMMON_H_
+
+#include <linux/clk.h>
+#include <linux/regmap.h>
+
+enum {
+       MTK_AFE_MEMIF_DL1,
+       MTK_AFE_MEMIF_DL2,
+       MTK_AFE_MEMIF_VUL,
+       MTK_AFE_MEMIF_DAI,
+       MTK_AFE_MEMIF_AWB,
+       MTK_AFE_MEMIF_MOD_DAI,
+       MTK_AFE_MEMIF_HDMI,
+       MTK_AFE_MEMIF_NUM,
+       MTK_AFE_IO_MOD_PCM1 = MTK_AFE_MEMIF_NUM,
+       MTK_AFE_IO_MOD_PCM2,
+       MTK_AFE_IO_PMIC,
+       MTK_AFE_IO_I2S,
+       MTK_AFE_IO_2ND_I2S,
+       MTK_AFE_IO_HW_GAIN1,
+       MTK_AFE_IO_HW_GAIN2,
+       MTK_AFE_IO_MRG_O,
+       MTK_AFE_IO_MRG_I,
+       MTK_AFE_IO_DAIBT,
+       MTK_AFE_IO_HDMI,
+};
+
+enum {
+       MTK_AFE_IRQ_1,
+       MTK_AFE_IRQ_2,
+       MTK_AFE_IRQ_3,
+       MTK_AFE_IRQ_4,
+       MTK_AFE_IRQ_5,
+       MTK_AFE_IRQ_6,
+       MTK_AFE_IRQ_7,
+       MTK_AFE_IRQ_8,
+       MTK_AFE_IRQ_NUM,
+};
+
+enum {
+       MTK_CLK_INFRASYS_AUD,
+       MTK_CLK_TOP_PDN_AUD,
+       MTK_CLK_TOP_PDN_AUD_BUS,
+       MTK_CLK_I2S0_M,
+       MTK_CLK_I2S1_M,
+       MTK_CLK_I2S2_M,
+       MTK_CLK_I2S3_M,
+       MTK_CLK_I2S3_B,
+       MTK_CLK_BCK0,
+       MTK_CLK_BCK1,
+       MTK_CLK_NUM
+};
+
+struct mtk_afe;
+struct snd_pcm_substream;
+
+struct mtk_afe_memif_data {
+       int id;
+       const char *name;
+       int reg_ofs_base;
+       int reg_ofs_cur;
+       int fs_shift;
+       int mono_shift;
+       int enable_shift;
+       int irq_reg_cnt;
+       int irq_cnt_shift;
+       int irq_en_shift;
+       int irq_fs_shift;
+       int irq_clr_shift;
+};
+
+struct mtk_afe_memif {
+       unsigned int phys_buf_addr;
+       int buffer_size;
+       unsigned int hw_ptr;            /* Previous IRQ's HW ptr */
+       struct snd_pcm_substream *substream;
+       const struct mtk_afe_memif_data *data;
+       const struct mtk_afe_irq_data *irqdata;
+};
+
+struct mtk_afe {
+       /* address for ioremap audio hardware register */
+       void __iomem *base_addr;
+       struct device *dev;
+       struct regmap *regmap;
+       struct mtk_afe_memif memif[MTK_AFE_MEMIF_NUM];
+       struct clk *clocks[MTK_CLK_NUM];
+};
+#endif
diff --git a/sound/soc/mediatek/mtk-afe-pcm.c b/sound/soc/mediatek/mtk-afe-pcm.c
new file mode 100644 (file)
index 0000000..cc228db
--- /dev/null
@@ -0,0 +1,1233 @@
+/*
+ * Mediatek ALSA SoC AFE platform driver
+ *
+ * Copyright (c) 2015 MediaTek Inc.
+ * Author: Koro Chen <koro.chen@mediatek.com>
+ *             Sascha Hauer <s.hauer@pengutronix.de>
+ *             Hidalgo Huang <hidalgo.huang@mediatek.com>
+ *             Ir Lian <ir.lian@mediatek.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/delay.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/pm_runtime.h>
+#include <sound/soc.h>
+#include "mtk-afe-common.h"
+
+/*****************************************************************************
+ *                  R E G I S T E R       D E F I N I T I O N
+ *****************************************************************************/
+#define AUDIO_TOP_CON0         0x0000
+#define AUDIO_TOP_CON1         0x0004
+#define AFE_DAC_CON0           0x0010
+#define AFE_DAC_CON1           0x0014
+#define AFE_I2S_CON1           0x0034
+#define AFE_I2S_CON2           0x0038
+#define AFE_CONN_24BIT         0x006c
+
+#define AFE_CONN1              0x0024
+#define AFE_CONN2              0x0028
+#define AFE_CONN7              0x0460
+#define AFE_CONN8              0x0464
+#define AFE_HDMI_CONN0         0x0390
+
+/* Memory interface */
+#define AFE_DL1_BASE           0x0040
+#define AFE_DL1_CUR            0x0044
+#define AFE_DL2_BASE           0x0050
+#define AFE_DL2_CUR            0x0054
+#define AFE_AWB_BASE           0x0070
+#define AFE_AWB_CUR            0x007c
+#define AFE_VUL_BASE           0x0080
+#define AFE_VUL_CUR            0x008c
+#define AFE_DAI_BASE           0x0090
+#define AFE_DAI_CUR            0x009c
+#define AFE_MOD_PCM_BASE       0x0330
+#define AFE_MOD_PCM_CUR                0x033c
+#define AFE_HDMI_OUT_BASE      0x0374
+#define AFE_HDMI_OUT_CUR       0x0378
+
+#define AFE_ADDA2_TOP_CON0     0x0600
+
+#define AFE_HDMI_OUT_CON0      0x0370
+
+#define AFE_IRQ_MCU_CON                0x03a0
+#define AFE_IRQ_STATUS         0x03a4
+#define AFE_IRQ_CLR            0x03a8
+#define AFE_IRQ_CNT1           0x03ac
+#define AFE_IRQ_CNT2           0x03b0
+#define AFE_IRQ_MCU_EN         0x03b4
+#define AFE_IRQ_CNT5           0x03bc
+#define AFE_IRQ_CNT7           0x03dc
+
+#define AFE_TDM_CON1           0x0548
+#define AFE_TDM_CON2           0x054c
+
+#define AFE_BASE_END_OFFSET    8
+#define AFE_IRQ_STATUS_BITS    0xff
+
+/* AUDIO_TOP_CON0 (0x0000) */
+#define AUD_TCON0_PDN_SPDF             (0x1 << 21)
+#define AUD_TCON0_PDN_HDMI             (0x1 << 20)
+#define AUD_TCON0_PDN_24M              (0x1 << 9)
+#define AUD_TCON0_PDN_22M              (0x1 << 8)
+#define AUD_TCON0_PDN_AFE              (0x1 << 2)
+
+/* AFE_I2S_CON1 (0x0034) */
+#define AFE_I2S_CON1_LOW_JITTER_CLK    (0x1 << 12)
+#define AFE_I2S_CON1_RATE(x)           (((x) & 0xf) << 8)
+#define AFE_I2S_CON1_FORMAT_I2S                (0x1 << 3)
+#define AFE_I2S_CON1_EN                        (0x1 << 0)
+
+/* AFE_I2S_CON2 (0x0038) */
+#define AFE_I2S_CON2_LOW_JITTER_CLK    (0x1 << 12)
+#define AFE_I2S_CON2_RATE(x)           (((x) & 0xf) << 8)
+#define AFE_I2S_CON2_FORMAT_I2S                (0x1 << 3)
+#define AFE_I2S_CON2_EN                        (0x1 << 0)
+
+/* AFE_CONN_24BIT (0x006c) */
+#define AFE_CONN_24BIT_O04             (0x1 << 4)
+#define AFE_CONN_24BIT_O03             (0x1 << 3)
+
+/* AFE_HDMI_CONN0 (0x0390) */
+#define AFE_HDMI_CONN0_O37_I37         (0x7 << 21)
+#define AFE_HDMI_CONN0_O36_I36         (0x6 << 18)
+#define AFE_HDMI_CONN0_O35_I33         (0x3 << 15)
+#define AFE_HDMI_CONN0_O34_I32         (0x2 << 12)
+#define AFE_HDMI_CONN0_O33_I35         (0x5 << 9)
+#define AFE_HDMI_CONN0_O32_I34         (0x4 << 6)
+#define AFE_HDMI_CONN0_O31_I31         (0x1 << 3)
+#define AFE_HDMI_CONN0_O30_I30         (0x0 << 0)
+
+/* AFE_TDM_CON1 (0x0548) */
+#define AFE_TDM_CON1_LRCK_WIDTH(x)     (((x) - 1) << 24)
+#define AFE_TDM_CON1_32_BCK_CYCLES     (0x2 << 12)
+#define AFE_TDM_CON1_WLEN_32BIT                (0x2 << 8)
+#define AFE_TDM_CON1_MSB_ALIGNED       (0x1 << 4)
+#define AFE_TDM_CON1_1_BCK_DELAY       (0x1 << 3)
+#define AFE_TDM_CON1_BCK_INV           (0x1 << 1)
+#define AFE_TDM_CON1_EN                        (0x1 << 0)
+
+enum afe_tdm_ch_start {
+       AFE_TDM_CH_START_O30_O31 = 0,
+       AFE_TDM_CH_START_O32_O33,
+       AFE_TDM_CH_START_O34_O35,
+       AFE_TDM_CH_START_O36_O37,
+       AFE_TDM_CH_ZERO,
+};
+
+static const struct snd_pcm_hardware mtk_afe_hardware = {
+       .info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED |
+                SNDRV_PCM_INFO_MMAP_VALID),
+       .buffer_bytes_max = 256 * 1024,
+       .period_bytes_min = 512,
+       .period_bytes_max = 128 * 1024,
+       .periods_min = 2,
+       .periods_max = 256,
+       .fifo_size = 0,
+};
+
+static snd_pcm_uframes_t mtk_afe_pcm_pointer
+                        (struct snd_pcm_substream *substream)
+{
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+       struct mtk_afe *afe = snd_soc_platform_get_drvdata(rtd->platform);
+       struct mtk_afe_memif *memif = &afe->memif[rtd->cpu_dai->id];
+
+       return bytes_to_frames(substream->runtime, memif->hw_ptr);
+}
+
+static const struct snd_pcm_ops mtk_afe_pcm_ops = {
+       .ioctl = snd_pcm_lib_ioctl,
+       .pointer = mtk_afe_pcm_pointer,
+};
+
+static int mtk_afe_pcm_new(struct snd_soc_pcm_runtime *rtd)
+{
+       size_t size;
+       struct snd_card *card = rtd->card->snd_card;
+       struct snd_pcm *pcm = rtd->pcm;
+
+       size = mtk_afe_hardware.buffer_bytes_max;
+
+       return snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV,
+                                                    card->dev, size, size);
+}
+
+static void mtk_afe_pcm_free(struct snd_pcm *pcm)
+{
+       snd_pcm_lib_preallocate_free_for_all(pcm);
+}
+
+static const struct snd_soc_platform_driver mtk_afe_pcm_platform = {
+       .ops = &mtk_afe_pcm_ops,
+       .pcm_new = mtk_afe_pcm_new,
+       .pcm_free = mtk_afe_pcm_free,
+};
+
+struct mtk_afe_rate {
+       unsigned int rate;
+       unsigned int regvalue;
+};
+
+static const struct mtk_afe_rate mtk_afe_i2s_rates[] = {
+       { .rate = 8000, .regvalue = 0 },
+       { .rate = 11025, .regvalue = 1 },
+       { .rate = 12000, .regvalue = 2 },
+       { .rate = 16000, .regvalue = 4 },
+       { .rate = 22050, .regvalue = 5 },
+       { .rate = 24000, .regvalue = 6 },
+       { .rate = 32000, .regvalue = 8 },
+       { .rate = 44100, .regvalue = 9 },
+       { .rate = 48000, .regvalue = 10 },
+       { .rate = 88000, .regvalue = 11 },
+       { .rate = 96000, .regvalue = 12 },
+       { .rate = 174000, .regvalue = 13 },
+       { .rate = 192000, .regvalue = 14 },
+};
+
+static int mtk_afe_i2s_fs(unsigned int sample_rate)
+{
+       int i;
+
+       for (i = 0; i < ARRAY_SIZE(mtk_afe_i2s_rates); i++)
+               if (mtk_afe_i2s_rates[i].rate == sample_rate)
+                       return mtk_afe_i2s_rates[i].regvalue;
+
+       return -EINVAL;
+}
+
+static int mtk_afe_set_i2s(struct mtk_afe *afe, unsigned int rate)
+{
+       unsigned int val;
+       int fs = mtk_afe_i2s_fs(rate);
+
+       if (fs < 0)
+               return -EINVAL;
+
+       /* from external ADC */
+       regmap_update_bits(afe->regmap, AFE_ADDA2_TOP_CON0, 0x1, 0x1);
+
+       /* set input */
+       val = AFE_I2S_CON2_LOW_JITTER_CLK |
+             AFE_I2S_CON2_RATE(fs) |
+             AFE_I2S_CON2_FORMAT_I2S;
+
+       regmap_update_bits(afe->regmap, AFE_I2S_CON2, ~AFE_I2S_CON2_EN, val);
+
+       /* set output */
+       val = AFE_I2S_CON1_LOW_JITTER_CLK |
+             AFE_I2S_CON1_RATE(fs) |
+             AFE_I2S_CON1_FORMAT_I2S;
+
+       regmap_update_bits(afe->regmap, AFE_I2S_CON1, ~AFE_I2S_CON1_EN, val);
+       return 0;
+}
+
+static void mtk_afe_set_i2s_enable(struct mtk_afe *afe, bool enable)
+{
+       unsigned int val;
+
+       regmap_read(afe->regmap, AFE_I2S_CON2, &val);
+       if (!!(val & AFE_I2S_CON2_EN) == enable)
+               return; /* must skip soft reset */
+
+       /* I2S soft reset begin */
+       regmap_update_bits(afe->regmap, AUDIO_TOP_CON1, 0x4, 0x4);
+
+       /* input */
+       regmap_update_bits(afe->regmap, AFE_I2S_CON2, 0x1, enable);
+
+       /* output */
+       regmap_update_bits(afe->regmap, AFE_I2S_CON1, 0x1, enable);
+
+       /* I2S soft reset end */
+       udelay(1);
+       regmap_update_bits(afe->regmap, AUDIO_TOP_CON1, 0x4, 0);
+}
+
+static int mtk_afe_dais_enable_clks(struct mtk_afe *afe,
+                                   struct clk *m_ck, struct clk *b_ck)
+{
+       int ret;
+
+       if (m_ck) {
+               ret = clk_prepare_enable(m_ck);
+               if (ret) {
+                       dev_err(afe->dev, "Failed to enable m_ck\n");
+                       return ret;
+               }
+               regmap_update_bits(afe->regmap, AUDIO_TOP_CON0,
+                                  AUD_TCON0_PDN_22M | AUD_TCON0_PDN_24M, 0);
+       }
+
+       if (b_ck) {
+               ret = clk_prepare_enable(b_ck);
+               if (ret) {
+                       dev_err(afe->dev, "Failed to enable b_ck\n");
+                       return ret;
+               }
+       }
+       return 0;
+}
+
+static int mtk_afe_dais_set_clks(struct mtk_afe *afe,
+                                struct clk *m_ck, unsigned int mck_rate,
+                                struct clk *b_ck, unsigned int bck_rate)
+{
+       int ret;
+
+       if (m_ck) {
+               ret = clk_set_rate(m_ck, mck_rate);
+               if (ret) {
+                       dev_err(afe->dev, "Failed to set m_ck rate\n");
+                       return ret;
+               }
+       }
+
+       if (b_ck) {
+               ret = clk_set_rate(b_ck, bck_rate);
+               if (ret) {
+                       dev_err(afe->dev, "Failed to set b_ck rate\n");
+                       return ret;
+               }
+       }
+       return 0;
+}
+
+static void mtk_afe_dais_disable_clks(struct mtk_afe *afe,
+                                     struct clk *m_ck, struct clk *b_ck)
+{
+       if (m_ck) {
+               regmap_update_bits(afe->regmap, AUDIO_TOP_CON0,
+                                  AUD_TCON0_PDN_22M | AUD_TCON0_PDN_24M,
+                                  AUD_TCON0_PDN_22M | AUD_TCON0_PDN_24M);
+               clk_disable_unprepare(m_ck);
+       }
+       if (b_ck)
+               clk_disable_unprepare(b_ck);
+}
+
+static int mtk_afe_i2s_startup(struct snd_pcm_substream *substream,
+                              struct snd_soc_dai *dai)
+{
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+       struct mtk_afe *afe = snd_soc_platform_get_drvdata(rtd->platform);
+
+       if (dai->active)
+               return 0;
+
+       mtk_afe_dais_enable_clks(afe, afe->clocks[MTK_CLK_I2S1_M], NULL);
+       return 0;
+}
+
+static void mtk_afe_i2s_shutdown(struct snd_pcm_substream *substream,
+                                struct snd_soc_dai *dai)
+{
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+       struct mtk_afe *afe = snd_soc_platform_get_drvdata(rtd->platform);
+
+       if (dai->active)
+               return;
+
+       mtk_afe_set_i2s_enable(afe, false);
+       mtk_afe_dais_disable_clks(afe, afe->clocks[MTK_CLK_I2S1_M], NULL);
+
+       /* disable AFE */
+       regmap_update_bits(afe->regmap, AFE_DAC_CON0, 0x1, 0);
+}
+
+static int mtk_afe_i2s_prepare(struct snd_pcm_substream *substream,
+                              struct snd_soc_dai *dai)
+{
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+       struct snd_pcm_runtime * const runtime = substream->runtime;
+       struct mtk_afe *afe = snd_soc_platform_get_drvdata(rtd->platform);
+       int ret;
+
+       mtk_afe_dais_set_clks(afe,
+                             afe->clocks[MTK_CLK_I2S1_M], runtime->rate * 256,
+                             NULL, 0);
+       /* config I2S */
+       ret = mtk_afe_set_i2s(afe, substream->runtime->rate);
+       if (ret)
+               return ret;
+
+       mtk_afe_set_i2s_enable(afe, true);
+
+       return 0;
+}
+
+static int mtk_afe_hdmi_startup(struct snd_pcm_substream *substream,
+                               struct snd_soc_dai *dai)
+{
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+       struct mtk_afe *afe = snd_soc_platform_get_drvdata(rtd->platform);
+
+       if (dai->active)
+               return 0;
+
+       mtk_afe_dais_enable_clks(afe, afe->clocks[MTK_CLK_I2S3_M],
+                                afe->clocks[MTK_CLK_I2S3_B]);
+       return 0;
+}
+
+static void mtk_afe_hdmi_shutdown(struct snd_pcm_substream *substream,
+                                 struct snd_soc_dai *dai)
+{
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+       struct mtk_afe *afe = snd_soc_platform_get_drvdata(rtd->platform);
+
+       if (dai->active)
+               return;
+
+       mtk_afe_dais_disable_clks(afe, afe->clocks[MTK_CLK_I2S3_M],
+                                 afe->clocks[MTK_CLK_I2S3_B]);
+
+       /* disable AFE */
+       regmap_update_bits(afe->regmap, AFE_DAC_CON0, 0x1, 0);
+}
+
+static int mtk_afe_hdmi_prepare(struct snd_pcm_substream *substream,
+                               struct snd_soc_dai *dai)
+{
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+       struct snd_pcm_runtime * const runtime = substream->runtime;
+       struct mtk_afe *afe = snd_soc_platform_get_drvdata(rtd->platform);
+       unsigned int val;
+
+       mtk_afe_dais_set_clks(afe,
+                             afe->clocks[MTK_CLK_I2S3_M], runtime->rate * 128,
+                             afe->clocks[MTK_CLK_I2S3_B],
+                             runtime->rate * runtime->channels * 32);
+
+       val = AFE_TDM_CON1_BCK_INV |
+             AFE_TDM_CON1_1_BCK_DELAY |
+             AFE_TDM_CON1_MSB_ALIGNED | /* I2S mode */
+             AFE_TDM_CON1_WLEN_32BIT |
+             AFE_TDM_CON1_32_BCK_CYCLES |
+             AFE_TDM_CON1_LRCK_WIDTH(32);
+       regmap_update_bits(afe->regmap, AFE_TDM_CON1, ~AFE_TDM_CON1_EN, val);
+
+       /* set tdm2 config */
+       switch (runtime->channels) {
+       case 1:
+       case 2:
+               val = AFE_TDM_CH_START_O30_O31;
+               val |= (AFE_TDM_CH_ZERO << 4);
+               val |= (AFE_TDM_CH_ZERO << 8);
+               val |= (AFE_TDM_CH_ZERO << 12);
+               break;
+       case 3:
+       case 4:
+               val = AFE_TDM_CH_START_O30_O31;
+               val |= (AFE_TDM_CH_START_O32_O33 << 4);
+               val |= (AFE_TDM_CH_ZERO << 8);
+               val |= (AFE_TDM_CH_ZERO << 12);
+               break;
+       case 5:
+       case 6:
+               val = AFE_TDM_CH_START_O30_O31;
+               val |= (AFE_TDM_CH_START_O32_O33 << 4);
+               val |= (AFE_TDM_CH_START_O34_O35 << 8);
+               val |= (AFE_TDM_CH_ZERO << 12);
+               break;
+       case 7:
+       case 8:
+               val = AFE_TDM_CH_START_O30_O31;
+               val |= (AFE_TDM_CH_START_O32_O33 << 4);
+               val |= (AFE_TDM_CH_START_O34_O35 << 8);
+               val |= (AFE_TDM_CH_START_O36_O37 << 12);
+               break;
+       default:
+               val = 0;
+       }
+       regmap_update_bits(afe->regmap, AFE_TDM_CON2, 0x0000ffff, val);
+
+       regmap_update_bits(afe->regmap, AFE_HDMI_OUT_CON0,
+                          0x000000f0, runtime->channels << 4);
+       return 0;
+}
+
+static int mtk_afe_hdmi_trigger(struct snd_pcm_substream *substream, int cmd,
+                               struct snd_soc_dai *dai)
+{
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+       struct mtk_afe *afe = snd_soc_platform_get_drvdata(rtd->platform);
+
+       dev_info(afe->dev, "%s cmd=%d %s\n", __func__, cmd, dai->name);
+
+       switch (cmd) {
+       case SNDRV_PCM_TRIGGER_START:
+       case SNDRV_PCM_TRIGGER_RESUME:
+               regmap_update_bits(afe->regmap, AUDIO_TOP_CON0,
+                                  AUD_TCON0_PDN_HDMI | AUD_TCON0_PDN_SPDF, 0);
+
+               /* set connections:  O30~O37: L/R/LS/RS/C/LFE/CH7/CH8 */
+               regmap_write(afe->regmap, AFE_HDMI_CONN0,
+                            AFE_HDMI_CONN0_O30_I30 | AFE_HDMI_CONN0_O31_I31 |
+                            AFE_HDMI_CONN0_O32_I34 | AFE_HDMI_CONN0_O33_I35 |
+                            AFE_HDMI_CONN0_O34_I32 | AFE_HDMI_CONN0_O35_I33 |
+                            AFE_HDMI_CONN0_O36_I36 | AFE_HDMI_CONN0_O37_I37);
+
+               /* enable Out control */
+               regmap_update_bits(afe->regmap, AFE_HDMI_OUT_CON0, 0x1, 0x1);
+
+               /* enable tdm */
+               regmap_update_bits(afe->regmap, AFE_TDM_CON1, 0x1, 0x1);
+
+               return 0;
+       case SNDRV_PCM_TRIGGER_STOP:
+       case SNDRV_PCM_TRIGGER_SUSPEND:
+               /* disable tdm */
+               regmap_update_bits(afe->regmap, AFE_TDM_CON1, 0x1, 0);
+
+               /* disable Out control */
+               regmap_update_bits(afe->regmap, AFE_HDMI_OUT_CON0, 0x1, 0);
+
+               regmap_update_bits(afe->regmap, AUDIO_TOP_CON0,
+                                  AUD_TCON0_PDN_HDMI | AUD_TCON0_PDN_SPDF,
+                                  AUD_TCON0_PDN_HDMI | AUD_TCON0_PDN_SPDF);
+
+               return 0;
+       default:
+               return -EINVAL;
+       }
+}
+
+static int mtk_afe_dais_startup(struct snd_pcm_substream *substream,
+                               struct snd_soc_dai *dai)
+{
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+       struct mtk_afe *afe = snd_soc_platform_get_drvdata(rtd->platform);
+       struct snd_pcm_runtime *runtime = substream->runtime;
+       struct mtk_afe_memif *memif = &afe->memif[rtd->cpu_dai->id];
+       int ret;
+
+       memif->substream = substream;
+
+       snd_soc_set_runtime_hwparams(substream, &mtk_afe_hardware);
+       ret = snd_pcm_hw_constraint_integer(runtime,
+                                           SNDRV_PCM_HW_PARAM_PERIODS);
+       if (ret < 0)
+               dev_err(afe->dev, "snd_pcm_hw_constraint_integer failed\n");
+       return ret;
+}
+
+static void mtk_afe_dais_shutdown(struct snd_pcm_substream *substream,
+                                 struct snd_soc_dai *dai)
+{
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+       struct mtk_afe *afe = snd_soc_platform_get_drvdata(rtd->platform);
+       struct mtk_afe_memif *memif = &afe->memif[rtd->cpu_dai->id];
+
+       memif->substream = NULL;
+}
+
+static int mtk_afe_dais_hw_params(struct snd_pcm_substream *substream,
+                                 struct snd_pcm_hw_params *params,
+                                 struct snd_soc_dai *dai)
+{
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+       struct mtk_afe *afe = snd_soc_platform_get_drvdata(rtd->platform);
+       struct mtk_afe_memif *memif = &afe->memif[rtd->cpu_dai->id];
+       int ret;
+
+       dev_dbg(afe->dev,
+               "%s period = %u, rate= %u, channels=%u\n",
+               __func__, params_period_size(params), params_rate(params),
+               params_channels(params));
+
+       ret = snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(params));
+       if (ret < 0)
+               return ret;
+
+       memif->phys_buf_addr = substream->runtime->dma_addr;
+       memif->buffer_size = substream->runtime->dma_bytes;
+       memif->hw_ptr = 0;
+
+       /* start */
+       regmap_write(afe->regmap,
+                    memif->data->reg_ofs_base, memif->phys_buf_addr);
+       /* end */
+       regmap_write(afe->regmap,
+                    memif->data->reg_ofs_base + AFE_BASE_END_OFFSET,
+                    memif->phys_buf_addr + memif->buffer_size - 1);
+
+       /* set channel */
+       if (memif->data->mono_shift >= 0) {
+               unsigned int mono = (params_channels(params) == 1) ? 1 : 0;
+
+               regmap_update_bits(afe->regmap, AFE_DAC_CON1,
+                                  1 << memif->data->mono_shift,
+                                  mono << memif->data->mono_shift);
+       }
+
+       /* set rate */
+       if (memif->data->fs_shift < 0)
+               return 0;
+       if (memif->data->id == MTK_AFE_MEMIF_DAI ||
+           memif->data->id == MTK_AFE_MEMIF_MOD_DAI) {
+               unsigned int val;
+
+               switch (params_rate(params)) {
+               case 8000:
+                       val = 0;
+                       break;
+               case 16000:
+                       val = 1;
+                       break;
+               case 32000:
+                       val = 2;
+                       break;
+               default:
+                       return -EINVAL;
+               }
+
+               if (memif->data->id == MTK_AFE_MEMIF_DAI)
+                       regmap_update_bits(afe->regmap, AFE_DAC_CON0,
+                                          0x3 << memif->data->fs_shift,
+                                          val << memif->data->fs_shift);
+               else
+                       regmap_update_bits(afe->regmap, AFE_DAC_CON1,
+                                          0x3 << memif->data->fs_shift,
+                                          val << memif->data->fs_shift);
+
+       } else {
+               int fs = mtk_afe_i2s_fs(params_rate(params));
+
+               if (fs < 0)
+                       return -EINVAL;
+
+               regmap_update_bits(afe->regmap, AFE_DAC_CON1,
+                                  0xf << memif->data->fs_shift,
+                                  fs << memif->data->fs_shift);
+       }
+
+       return 0;
+}
+
+static int mtk_afe_dais_hw_free(struct snd_pcm_substream *substream,
+                               struct snd_soc_dai *dai)
+{
+       return snd_pcm_lib_free_pages(substream);
+}
+
+static int mtk_afe_dais_prepare(struct snd_pcm_substream *substream,
+                               struct snd_soc_dai *dai)
+{
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+       struct mtk_afe *afe = snd_soc_platform_get_drvdata(rtd->platform);
+
+       /* enable AFE */
+       regmap_update_bits(afe->regmap, AFE_DAC_CON0, 0x1, 0x1);
+       return 0;
+}
+
+static int mtk_afe_dais_trigger(struct snd_pcm_substream *substream, int cmd,
+                               struct snd_soc_dai *dai)
+{
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+       struct snd_pcm_runtime * const runtime = substream->runtime;
+       struct mtk_afe *afe = snd_soc_platform_get_drvdata(rtd->platform);
+       struct mtk_afe_memif *memif = &afe->memif[rtd->cpu_dai->id];
+       unsigned int counter = runtime->period_size;
+
+       dev_info(afe->dev, "%s %s cmd=%d\n", __func__, memif->data->name, cmd);
+
+       switch (cmd) {
+       case SNDRV_PCM_TRIGGER_START:
+       case SNDRV_PCM_TRIGGER_RESUME:
+               if (memif->data->enable_shift >= 0)
+                       regmap_update_bits(afe->regmap, AFE_DAC_CON0,
+                                          1 << memif->data->enable_shift,
+                                          1 << memif->data->enable_shift);
+
+               /* set irq counter */
+               regmap_update_bits(afe->regmap,
+                                  memif->data->irq_reg_cnt,
+                                  0x3ffff << memif->data->irq_cnt_shift,
+                                  counter << memif->data->irq_cnt_shift);
+
+               /* set irq fs */
+               if (memif->data->irq_fs_shift >= 0) {
+                       int fs = mtk_afe_i2s_fs(runtime->rate);
+
+                       if (fs < 0)
+                               return -EINVAL;
+
+                       regmap_update_bits(afe->regmap,
+                                          AFE_IRQ_MCU_CON,
+                                          0xf << memif->data->irq_fs_shift,
+                                          fs << memif->data->irq_fs_shift);
+               }
+               /* enable interrupt */
+               regmap_update_bits(afe->regmap, AFE_IRQ_MCU_CON,
+                                  1 << memif->data->irq_en_shift,
+                                  1 << memif->data->irq_en_shift);
+
+               return 0;
+       case SNDRV_PCM_TRIGGER_STOP:
+       case SNDRV_PCM_TRIGGER_SUSPEND:
+               if (memif->data->enable_shift >= 0)
+                       regmap_update_bits(afe->regmap, AFE_DAC_CON0,
+                                          1 << memif->data->enable_shift, 0);
+               /* disable interrupt */
+               regmap_update_bits(afe->regmap, AFE_IRQ_MCU_CON,
+                                  1 << memif->data->irq_en_shift,
+                                  0 << memif->data->irq_en_shift);
+               /* and clear pending IRQ */
+               regmap_write(afe->regmap, AFE_IRQ_CLR,
+                            1 << memif->data->irq_clr_shift);
+               memif->hw_ptr = 0;
+               return 0;
+       default:
+               return -EINVAL;
+       }
+}
+
+/* FE DAIs */
+static const struct snd_soc_dai_ops mtk_afe_dai_ops = {
+       .startup        = mtk_afe_dais_startup,
+       .shutdown       = mtk_afe_dais_shutdown,
+       .hw_params      = mtk_afe_dais_hw_params,
+       .hw_free        = mtk_afe_dais_hw_free,
+       .prepare        = mtk_afe_dais_prepare,
+       .trigger        = mtk_afe_dais_trigger,
+};
+
+/* BE DAIs */
+static const struct snd_soc_dai_ops mtk_afe_i2s_ops = {
+       .startup        = mtk_afe_i2s_startup,
+       .shutdown       = mtk_afe_i2s_shutdown,
+       .prepare        = mtk_afe_i2s_prepare,
+};
+
+static const struct snd_soc_dai_ops mtk_afe_hdmi_ops = {
+       .startup        = mtk_afe_hdmi_startup,
+       .shutdown       = mtk_afe_hdmi_shutdown,
+       .prepare        = mtk_afe_hdmi_prepare,
+       .trigger        = mtk_afe_hdmi_trigger,
+
+};
+
+static struct snd_soc_dai_driver mtk_afe_pcm_dais[] = {
+       /* FE DAIs: memory intefaces to CPU */
+       {
+               .name = "DL1", /* downlink 1 */
+               .id = MTK_AFE_MEMIF_DL1,
+               .playback = {
+                       .stream_name = "DL1",
+                       .channels_min = 1,
+                       .channels_max = 2,
+                       .rates = SNDRV_PCM_RATE_8000_48000,
+                       .formats = SNDRV_PCM_FMTBIT_S16_LE,
+               },
+               .ops = &mtk_afe_dai_ops,
+       }, {
+               .name = "VUL", /* voice uplink */
+               .id = MTK_AFE_MEMIF_VUL,
+               .capture = {
+                       .stream_name = "VUL",
+                       .channels_min = 1,
+                       .channels_max = 2,
+                       .rates = SNDRV_PCM_RATE_8000_48000,
+                       .formats = SNDRV_PCM_FMTBIT_S16_LE,
+               },
+               .ops = &mtk_afe_dai_ops,
+       }, {
+       /* BE DAIs */
+               .name = "I2S",
+               .id = MTK_AFE_IO_I2S,
+               .playback = {
+                       .stream_name = "I2S Playback",
+                       .channels_min = 1,
+                       .channels_max = 2,
+                       .rates = SNDRV_PCM_RATE_8000_48000,
+                       .formats = SNDRV_PCM_FMTBIT_S16_LE,
+               },
+               .capture = {
+                       .stream_name = "I2S Capture",
+                       .channels_min = 1,
+                       .channels_max = 2,
+                       .rates = SNDRV_PCM_RATE_8000_48000,
+                       .formats = SNDRV_PCM_FMTBIT_S16_LE,
+               },
+               .ops = &mtk_afe_i2s_ops,
+               .symmetric_rates = 1,
+       },
+};
+
+static struct snd_soc_dai_driver mtk_afe_hdmi_dais[] = {
+       /* FE DAIs */
+       {
+               .name = "HDMI",
+               .id = MTK_AFE_MEMIF_HDMI,
+               .playback = {
+                       .stream_name = "HDMI",
+                       .channels_min = 2,
+                       .channels_max = 8,
+                       .rates = SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 |
+                               SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_88200 |
+                               SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_176400 |
+                               SNDRV_PCM_RATE_192000,
+                       .formats = SNDRV_PCM_FMTBIT_S16_LE,
+               },
+               .ops = &mtk_afe_dai_ops,
+       }, {
+       /* BE DAIs */
+               .name = "HDMIO",
+               .id = MTK_AFE_IO_HDMI,
+               .playback = {
+                       .stream_name = "HDMIO Playback",
+                       .channels_min = 2,
+                       .channels_max = 8,
+                       .rates = SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 |
+                               SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_88200 |
+                               SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_176400 |
+                               SNDRV_PCM_RATE_192000,
+                       .formats = SNDRV_PCM_FMTBIT_S16_LE,
+               },
+               .ops = &mtk_afe_hdmi_ops,
+       },
+};
+
+static const struct snd_kcontrol_new mtk_afe_o03_mix[] = {
+       SOC_DAPM_SINGLE_AUTODISABLE("I05 Switch", AFE_CONN1, 21, 1, 0),
+};
+
+static const struct snd_kcontrol_new mtk_afe_o04_mix[] = {
+       SOC_DAPM_SINGLE_AUTODISABLE("I06 Switch", AFE_CONN2, 6, 1, 0),
+};
+
+static const struct snd_kcontrol_new mtk_afe_o09_mix[] = {
+       SOC_DAPM_SINGLE_AUTODISABLE("I17 Switch", AFE_CONN7, 30, 1, 0),
+};
+
+static const struct snd_kcontrol_new mtk_afe_o10_mix[] = {
+       SOC_DAPM_SINGLE_AUTODISABLE("I18 Switch", AFE_CONN8, 0, 1, 0),
+};
+
+static const struct snd_soc_dapm_widget mtk_afe_pcm_widgets[] = {
+       /* Backend DAIs  */
+       SND_SOC_DAPM_AIF_IN("I2S Capture", NULL, 0, SND_SOC_NOPM, 0, 0),
+       SND_SOC_DAPM_AIF_OUT("I2S Playback", NULL, 0, SND_SOC_NOPM, 0, 0),
+
+       /* inter-connections */
+       SND_SOC_DAPM_MIXER("I05", SND_SOC_NOPM, 0, 0, NULL, 0),
+       SND_SOC_DAPM_MIXER("I06", SND_SOC_NOPM, 0, 0, NULL, 0),
+       SND_SOC_DAPM_MIXER("I17", SND_SOC_NOPM, 0, 0, NULL, 0),
+       SND_SOC_DAPM_MIXER("I18", SND_SOC_NOPM, 0, 0, NULL, 0),
+
+       SND_SOC_DAPM_MIXER("O03", SND_SOC_NOPM, 0, 0,
+                          mtk_afe_o03_mix, ARRAY_SIZE(mtk_afe_o03_mix)),
+       SND_SOC_DAPM_MIXER("O04", SND_SOC_NOPM, 0, 0,
+                          mtk_afe_o04_mix, ARRAY_SIZE(mtk_afe_o04_mix)),
+       SND_SOC_DAPM_MIXER("O09", SND_SOC_NOPM, 0, 0,
+                          mtk_afe_o09_mix, ARRAY_SIZE(mtk_afe_o09_mix)),
+       SND_SOC_DAPM_MIXER("O10", SND_SOC_NOPM, 0, 0,
+                          mtk_afe_o10_mix, ARRAY_SIZE(mtk_afe_o10_mix)),
+};
+
+static const struct snd_soc_dapm_route mtk_afe_pcm_routes[] = {
+       {"I05", NULL, "DL1"},
+       {"I06", NULL, "DL1"},
+       {"I2S Playback", NULL, "O03"},
+       {"I2S Playback", NULL, "O04"},
+       {"VUL", NULL, "O09"},
+       {"VUL", NULL, "O10"},
+       {"I17", NULL, "I2S Capture"},
+       {"I18", NULL, "I2S Capture"},
+       { "O03", "I05 Switch", "I05" },
+       { "O04", "I06 Switch", "I06" },
+       { "O09", "I17 Switch", "I17" },
+       { "O10", "I18 Switch", "I18" },
+};
+
+static const struct snd_soc_dapm_widget mtk_afe_hdmi_widgets[] = {
+       /* Backend DAIs  */
+       SND_SOC_DAPM_AIF_OUT("HDMIO Playback", NULL, 0, SND_SOC_NOPM, 0, 0),
+};
+
+static const struct snd_soc_dapm_route mtk_afe_hdmi_routes[] = {
+       {"HDMIO Playback", NULL, "HDMI"},
+};
+
+static const struct snd_soc_component_driver mtk_afe_pcm_dai_component = {
+       .name = "mtk-afe-pcm-dai",
+       .dapm_widgets = mtk_afe_pcm_widgets,
+       .num_dapm_widgets = ARRAY_SIZE(mtk_afe_pcm_widgets),
+       .dapm_routes = mtk_afe_pcm_routes,
+       .num_dapm_routes = ARRAY_SIZE(mtk_afe_pcm_routes),
+};
+
+static const struct snd_soc_component_driver mtk_afe_hdmi_dai_component = {
+       .name = "mtk-afe-hdmi-dai",
+       .dapm_widgets = mtk_afe_hdmi_widgets,
+       .num_dapm_widgets = ARRAY_SIZE(mtk_afe_hdmi_widgets),
+       .dapm_routes = mtk_afe_hdmi_routes,
+       .num_dapm_routes = ARRAY_SIZE(mtk_afe_hdmi_routes),
+};
+
+static const char *aud_clks[MTK_CLK_NUM] = {
+       [MTK_CLK_INFRASYS_AUD] = "infra_sys_audio_clk",
+       [MTK_CLK_TOP_PDN_AUD] = "top_pdn_audio",
+       [MTK_CLK_TOP_PDN_AUD_BUS] = "top_pdn_aud_intbus",
+       [MTK_CLK_I2S0_M] =  "i2s0_m",
+       [MTK_CLK_I2S1_M] =  "i2s1_m",
+       [MTK_CLK_I2S2_M] =  "i2s2_m",
+       [MTK_CLK_I2S3_M] =  "i2s3_m",
+       [MTK_CLK_I2S3_B] =  "i2s3_b",
+       [MTK_CLK_BCK0] =  "bck0",
+       [MTK_CLK_BCK1] =  "bck1",
+};
+
+static const struct mtk_afe_memif_data memif_data[MTK_AFE_MEMIF_NUM] = {
+       {
+               .name = "DL1",
+               .id = MTK_AFE_MEMIF_DL1,
+               .reg_ofs_base = AFE_DL1_BASE,
+               .reg_ofs_cur = AFE_DL1_CUR,
+               .fs_shift = 0,
+               .mono_shift = 21,
+               .enable_shift = 1,
+               .irq_reg_cnt = AFE_IRQ_CNT1,
+               .irq_cnt_shift = 0,
+               .irq_en_shift = 0,
+               .irq_fs_shift = 4,
+               .irq_clr_shift = 0,
+       }, {
+               .name = "DL2",
+               .id = MTK_AFE_MEMIF_DL2,
+               .reg_ofs_base = AFE_DL2_BASE,
+               .reg_ofs_cur = AFE_DL2_CUR,
+               .fs_shift = 4,
+               .mono_shift = 22,
+               .enable_shift = 2,
+               .irq_reg_cnt = AFE_IRQ_CNT1,
+               .irq_cnt_shift = 20,
+               .irq_en_shift = 2,
+               .irq_fs_shift = 16,
+               .irq_clr_shift = 2,
+       }, {
+               .name = "VUL",
+               .id = MTK_AFE_MEMIF_VUL,
+               .reg_ofs_base = AFE_VUL_BASE,
+               .reg_ofs_cur = AFE_VUL_CUR,
+               .fs_shift = 16,
+               .mono_shift = 27,
+               .enable_shift = 3,
+               .irq_reg_cnt = AFE_IRQ_CNT2,
+               .irq_cnt_shift = 0,
+               .irq_en_shift = 1,
+               .irq_fs_shift = 8,
+               .irq_clr_shift = 1,
+       }, {
+               .name = "DAI",
+               .id = MTK_AFE_MEMIF_DAI,
+               .reg_ofs_base = AFE_DAI_BASE,
+               .reg_ofs_cur = AFE_DAI_CUR,
+               .fs_shift = 24,
+               .mono_shift = -1,
+               .enable_shift = 4,
+               .irq_reg_cnt = AFE_IRQ_CNT2,
+               .irq_cnt_shift = 20,
+               .irq_en_shift = 3,
+               .irq_fs_shift = 20,
+               .irq_clr_shift = 3,
+       }, {
+               .name = "AWB",
+               .id = MTK_AFE_MEMIF_AWB,
+               .reg_ofs_base = AFE_AWB_BASE,
+               .reg_ofs_cur = AFE_AWB_CUR,
+               .fs_shift = 12,
+               .mono_shift = 24,
+               .enable_shift = 6,
+               .irq_reg_cnt = AFE_IRQ_CNT7,
+               .irq_cnt_shift = 0,
+               .irq_en_shift = 14,
+               .irq_fs_shift = 24,
+               .irq_clr_shift = 6,
+       }, {
+               .name = "MOD_DAI",
+               .id = MTK_AFE_MEMIF_MOD_DAI,
+               .reg_ofs_base = AFE_MOD_PCM_BASE,
+               .reg_ofs_cur = AFE_MOD_PCM_CUR,
+               .fs_shift = 30,
+               .mono_shift = 30,
+               .enable_shift = 7,
+               .irq_reg_cnt = AFE_IRQ_CNT2,
+               .irq_cnt_shift = 20,
+               .irq_en_shift = 3,
+               .irq_fs_shift = 20,
+               .irq_clr_shift = 3,
+       }, {
+               .name = "HDMI",
+               .id = MTK_AFE_MEMIF_HDMI,
+               .reg_ofs_base = AFE_HDMI_OUT_BASE,
+               .reg_ofs_cur = AFE_HDMI_OUT_CUR,
+               .fs_shift = -1,
+               .mono_shift = -1,
+               .enable_shift = -1,
+               .irq_reg_cnt = AFE_IRQ_CNT5,
+               .irq_cnt_shift = 0,
+               .irq_en_shift = 12,
+               .irq_fs_shift = -1,
+               .irq_clr_shift = 4,
+       },
+};
+
+static const struct regmap_config mtk_afe_regmap_config = {
+       .reg_bits = 32,
+       .reg_stride = 4,
+       .val_bits = 32,
+       .max_register = AFE_ADDA2_TOP_CON0,
+       .cache_type = REGCACHE_NONE,
+};
+
+static irqreturn_t mtk_afe_irq_handler(int irq, void *dev_id)
+{
+       struct mtk_afe *afe = dev_id;
+       unsigned int reg_value, hw_ptr;
+       int i, ret;
+
+       ret = regmap_read(afe->regmap, AFE_IRQ_STATUS, &reg_value);
+       if (ret) {
+               dev_err(afe->dev, "%s irq status err\n", __func__);
+               reg_value = AFE_IRQ_STATUS_BITS;
+               goto err_irq;
+       }
+
+       for (i = 0; i < MTK_AFE_MEMIF_NUM; i++) {
+               struct mtk_afe_memif *memif = &afe->memif[i];
+
+               if (!(reg_value & (1 << memif->data->irq_clr_shift)))
+                       continue;
+
+               ret = regmap_read(afe->regmap, memif->data->reg_ofs_cur,
+                                 &hw_ptr);
+               if (ret || hw_ptr == 0) {
+                       dev_err(afe->dev, "%s hw_ptr err\n", __func__);
+                       hw_ptr = memif->phys_buf_addr;
+               }
+               memif->hw_ptr = hw_ptr - memif->phys_buf_addr;
+               snd_pcm_period_elapsed(memif->substream);
+       }
+
+err_irq:
+       /* clear irq */
+       regmap_write(afe->regmap, AFE_IRQ_CLR, reg_value & AFE_IRQ_STATUS_BITS);
+
+       return IRQ_HANDLED;
+}
+
+static int mtk_afe_runtime_suspend(struct device *dev)
+{
+       struct mtk_afe *afe = dev_get_drvdata(dev);
+
+       /* disable AFE clk */
+       regmap_update_bits(afe->regmap, AUDIO_TOP_CON0,
+                          AUD_TCON0_PDN_AFE, AUD_TCON0_PDN_AFE);
+
+       clk_disable_unprepare(afe->clocks[MTK_CLK_BCK0]);
+       clk_disable_unprepare(afe->clocks[MTK_CLK_BCK1]);
+       clk_disable_unprepare(afe->clocks[MTK_CLK_TOP_PDN_AUD]);
+       clk_disable_unprepare(afe->clocks[MTK_CLK_TOP_PDN_AUD_BUS]);
+       clk_disable_unprepare(afe->clocks[MTK_CLK_INFRASYS_AUD]);
+       return 0;
+}
+
+static int mtk_afe_runtime_resume(struct device *dev)
+{
+       struct mtk_afe *afe = dev_get_drvdata(dev);
+       int ret;
+
+       ret = clk_prepare_enable(afe->clocks[MTK_CLK_INFRASYS_AUD]);
+       if (ret)
+               return ret;
+
+       ret = clk_prepare_enable(afe->clocks[MTK_CLK_TOP_PDN_AUD_BUS]);
+       if (ret)
+               goto err_infra;
+
+       ret = clk_prepare_enable(afe->clocks[MTK_CLK_TOP_PDN_AUD]);
+       if (ret)
+               goto err_top_aud_bus;
+
+       ret = clk_prepare_enable(afe->clocks[MTK_CLK_BCK0]);
+       if (ret)
+               goto err_top_aud;
+
+       ret = clk_prepare_enable(afe->clocks[MTK_CLK_BCK1]);
+       if (ret)
+               goto err_bck0;
+
+       /* enable AFE clk */
+       regmap_update_bits(afe->regmap, AUDIO_TOP_CON0, AUD_TCON0_PDN_AFE, 0);
+
+       /* set O3/O4 16bits */
+       regmap_update_bits(afe->regmap, AFE_CONN_24BIT,
+                          AFE_CONN_24BIT_O03 | AFE_CONN_24BIT_O04, 0);
+
+       /* unmask all IRQs */
+       regmap_update_bits(afe->regmap, AFE_IRQ_MCU_EN, 0xff, 0xff);
+       return 0;
+
+err_bck0:
+       clk_disable_unprepare(afe->clocks[MTK_CLK_BCK0]);
+err_top_aud:
+       clk_disable_unprepare(afe->clocks[MTK_CLK_TOP_PDN_AUD]);
+err_top_aud_bus:
+       clk_disable_unprepare(afe->clocks[MTK_CLK_TOP_PDN_AUD_BUS]);
+err_infra:
+       clk_disable_unprepare(afe->clocks[MTK_CLK_INFRASYS_AUD]);
+       return ret;
+}
+
+static int mtk_afe_init_audio_clk(struct mtk_afe *afe)
+{
+       size_t i;
+
+       for (i = 0; i < ARRAY_SIZE(aud_clks); i++) {
+               afe->clocks[i] = devm_clk_get(afe->dev, aud_clks[i]);
+               if (IS_ERR(afe->clocks[i])) {
+                       dev_err(afe->dev, "%s devm_clk_get %s fail\n",
+                               __func__, aud_clks[i]);
+                       return PTR_ERR(afe->clocks[i]);
+               }
+       }
+       clk_set_rate(afe->clocks[MTK_CLK_BCK0], 22579200); /* 22M */
+       clk_set_rate(afe->clocks[MTK_CLK_BCK1], 24576000); /* 24M */
+       return 0;
+}
+
+static int mtk_afe_pcm_dev_probe(struct platform_device *pdev)
+{
+       int ret, i;
+       unsigned int irq_id;
+       struct mtk_afe *afe;
+       struct resource *res;
+
+       afe = devm_kzalloc(&pdev->dev, sizeof(*afe), GFP_KERNEL);
+       if (!afe)
+               return -ENOMEM;
+
+       afe->dev = &pdev->dev;
+
+       irq_id = platform_get_irq(pdev, 0);
+       if (!irq_id) {
+               dev_err(afe->dev, "np %s no irq\n", afe->dev->of_node->name);
+               return -ENXIO;
+       }
+       ret = devm_request_irq(afe->dev, irq_id, mtk_afe_irq_handler,
+                              0, "Afe_ISR_Handle", (void *)afe);
+       if (ret) {
+               dev_err(afe->dev, "could not request_irq\n");
+               return ret;
+       }
+
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       afe->base_addr = devm_ioremap_resource(&pdev->dev, res);
+       if (IS_ERR(afe->base_addr))
+               return PTR_ERR(afe->base_addr);
+
+       afe->regmap = devm_regmap_init_mmio(&pdev->dev, afe->base_addr,
+               &mtk_afe_regmap_config);
+       if (IS_ERR(afe->regmap))
+               return PTR_ERR(afe->regmap);
+
+       /* initial audio related clock */
+       ret = mtk_afe_init_audio_clk(afe);
+       if (ret) {
+               dev_err(afe->dev, "mtk_afe_init_audio_clk fail\n");
+               return ret;
+       }
+
+       for (i = 0; i < MTK_AFE_MEMIF_NUM; i++)
+               afe->memif[i].data = &memif_data[i];
+
+       platform_set_drvdata(pdev, afe);
+
+       pm_runtime_enable(&pdev->dev);
+       if (!pm_runtime_enabled(&pdev->dev)) {
+               ret = mtk_afe_runtime_resume(&pdev->dev);
+               if (ret)
+                       goto err_pm_disable;
+       }
+
+       ret = snd_soc_register_platform(&pdev->dev, &mtk_afe_pcm_platform);
+       if (ret)
+               goto err_pm_disable;
+
+       ret = snd_soc_register_component(&pdev->dev,
+                                        &mtk_afe_pcm_dai_component,
+                                        mtk_afe_pcm_dais,
+                                        ARRAY_SIZE(mtk_afe_pcm_dais));
+       if (ret)
+               goto err_platform;
+
+       ret = snd_soc_register_component(&pdev->dev,
+                                        &mtk_afe_hdmi_dai_component,
+                                        mtk_afe_hdmi_dais,
+                                        ARRAY_SIZE(mtk_afe_hdmi_dais));
+       if (ret)
+               goto err_comp;
+
+       dev_info(&pdev->dev, "MTK AFE driver initialized.\n");
+       return 0;
+
+err_comp:
+       snd_soc_unregister_component(&pdev->dev);
+err_platform:
+       snd_soc_unregister_platform(&pdev->dev);
+err_pm_disable:
+       pm_runtime_disable(&pdev->dev);
+       return ret;
+}
+
+static int mtk_afe_pcm_dev_remove(struct platform_device *pdev)
+{
+       pm_runtime_disable(&pdev->dev);
+       snd_soc_unregister_component(&pdev->dev);
+       snd_soc_unregister_platform(&pdev->dev);
+       return 0;
+}
+
+static const struct of_device_id mtk_afe_pcm_dt_match[] = {
+       { .compatible = "mediatek,mt8173-afe-pcm", },
+       { }
+};
+MODULE_DEVICE_TABLE(of, mtk_afe_pcm_dt_match);
+
+static const struct dev_pm_ops mtk_afe_pm_ops = {
+       SET_RUNTIME_PM_OPS(mtk_afe_runtime_suspend, mtk_afe_runtime_resume,
+                          NULL)
+};
+
+static struct platform_driver mtk_afe_pcm_driver = {
+       .driver = {
+                  .name = "mtk-afe-pcm",
+                  .owner = THIS_MODULE,
+                  .of_match_table = mtk_afe_pcm_dt_match,
+                  .pm = &mtk_afe_pm_ops,
+       },
+       .probe = mtk_afe_pcm_dev_probe,
+       .remove = mtk_afe_pcm_dev_remove,
+};
+
+module_platform_driver(mtk_afe_pcm_driver);
+
+MODULE_DESCRIPTION("Mediatek ALSA SoC AFE platform driver");
+MODULE_AUTHOR("Koro Chen <koro.chen@mediatek.com>");
+MODULE_LICENSE("GPL v2");
index 6768e4f7d7d0e264eb3ff37881155caf8c1d0229..30d0109703a935d638be338c762beb9fb56b70a7 100644 (file)
@@ -100,12 +100,13 @@ config SND_OMAP_SOC_OMAP_TWL4030
 
 config SND_OMAP_SOC_OMAP_ABE_TWL6040
        tristate "SoC Audio support for OMAP boards using ABE and twl6040 codec"
-       depends on TWL6040_CORE && SND_OMAP_SOC && (ARCH_OMAP4 || SOC_OMAP5 || COMPILE_TEST)
+       depends on TWL6040_CORE && SND_OMAP_SOC
+       depends on ARCH_OMAP4 || (SOC_OMAP5 && MFD_PALMAS) || COMPILE_TEST
        select SND_OMAP_SOC_DMIC
        select SND_OMAP_SOC_MCPDM
        select SND_SOC_TWL6040
        select SND_SOC_DMIC
-       select COMMON_CLK_PALMAS if MFD_PALMAS
+       select COMMON_CLK_PALMAS if (SOC_OMAP5 && MFD_PALMAS)
        help
          Say Y if you want to add support for SoC audio on OMAP boards using
          ABE and twl6040 codec. This driver currently supports:
index 3673ada43bfb244fd7a17f90e7bc420e7e020ed1..743131473056f5116e745db22ff17fe003c0d979 100644 (file)
@@ -159,9 +159,8 @@ static inline void twl4030_disconnect_pin(struct snd_soc_dapm_context *dapm,
 
 static int omap_twl4030_init(struct snd_soc_pcm_runtime *rtd)
 {
-       struct snd_soc_codec *codec = rtd->codec;
        struct snd_soc_card *card = rtd->card;
-       struct snd_soc_dapm_context *dapm = &codec->dapm;
+       struct snd_soc_dapm_context *dapm = &card->dapm;
        struct omap_tw4030_pdata *pdata = dev_get_platdata(card->dev);
        struct omap_twl4030 *priv = snd_soc_card_get_drvdata(card);
        int ret = 0;
index c2ddf0fbfa2895732a37d82d19b60c75408d67a7..3bebfb1d3a6f9b7ad9a8d20641018d16bf97f886 100644 (file)
@@ -245,6 +245,8 @@ static const struct snd_soc_dapm_widget aic34_dapm_widgets[] = {
 static const struct snd_soc_dapm_route audio_map[] = {
        {"Ext Spk", NULL, "HPLOUT"},
        {"Ext Spk", NULL, "HPROUT"},
+       {"Ext Spk", NULL, "HPLCOM"},
+       {"Ext Spk", NULL, "HPRCOM"},
        {"Headphone Jack", NULL, "LLOUT"},
        {"Headphone Jack", NULL, "RLOUT"},
        {"FM Transmitter", NULL, "LLOUT"},
@@ -288,15 +290,8 @@ static int rx51_aic34_init(struct snd_soc_pcm_runtime *rtd)
        struct snd_soc_codec *codec = rtd->codec;
        struct snd_soc_card *card = rtd->card;
        struct rx51_audio_pdata *pdata = snd_soc_card_get_drvdata(card);
-
-       struct snd_soc_dapm_context *dapm = &codec->dapm;
        int err;
 
-       /* Set up NC codec pins */
-       snd_soc_dapm_nc_pin(dapm, "MIC3L");
-       snd_soc_dapm_nc_pin(dapm, "MIC3R");
-       snd_soc_dapm_nc_pin(dapm, "LINE1R");
-
        err = tpa6130a2_add_controls(codec);
        if (err < 0) {
                dev_err(card->dev, "Failed to add TPA6130A2 controls\n");
@@ -383,6 +378,7 @@ static struct snd_soc_card rx51_sound_card = {
        .num_aux_devs = ARRAY_SIZE(rx51_aux_dev),
        .codec_conf = rx51_codec_conf,
        .num_configs = ARRAY_SIZE(rx51_codec_conf),
+       .fully_routed = true,
 
        .controls = aic34_rx51_controls,
        .num_controls = ARRAY_SIZE(aic34_rx51_controls),
@@ -455,50 +451,36 @@ static int rx51_soc_probe(struct platform_device *pdev)
        snd_soc_card_set_drvdata(card, pdata);
 
        pdata->tvout_selection_gpio = devm_gpiod_get(card->dev,
-                                                    "tvout-selection");
+                                                    "tvout-selection",
+                                                    GPIOD_OUT_LOW);
        if (IS_ERR(pdata->tvout_selection_gpio)) {
                dev_err(card->dev, "could not get tvout selection gpio\n");
                return PTR_ERR(pdata->tvout_selection_gpio);
        }
 
-       err = gpiod_direction_output(pdata->tvout_selection_gpio, 0);
-       if (err) {
-               dev_err(card->dev, "could not setup tvout selection gpio\n");
-               return err;
-       }
-
        pdata->jack_detection_gpio = devm_gpiod_get(card->dev,
-                                                   "jack-detection");
+                                                   "jack-detection",
+                                                   GPIOD_ASIS);
        if (IS_ERR(pdata->jack_detection_gpio)) {
                dev_err(card->dev, "could not get jack detection gpio\n");
                return PTR_ERR(pdata->jack_detection_gpio);
        }
 
-       pdata->eci_sw_gpio = devm_gpiod_get(card->dev, "eci-switch");
+       pdata->eci_sw_gpio = devm_gpiod_get(card->dev, "eci-switch",
+                                           GPIOD_OUT_HIGH);
        if (IS_ERR(pdata->eci_sw_gpio)) {
                dev_err(card->dev, "could not get eci switch gpio\n");
                return PTR_ERR(pdata->eci_sw_gpio);
        }
 
-       err = gpiod_direction_output(pdata->eci_sw_gpio, 1);
-       if (err) {
-               dev_err(card->dev, "could not setup eci switch gpio\n");
-               return err;
-       }
-
        pdata->speaker_amp_gpio = devm_gpiod_get(card->dev,
-                                                "speaker-amplifier");
+                                                "speaker-amplifier",
+                                                GPIOD_OUT_LOW);
        if (IS_ERR(pdata->speaker_amp_gpio)) {
                dev_err(card->dev, "could not get speaker enable gpio\n");
                return PTR_ERR(pdata->speaker_amp_gpio);
        }
 
-       err = gpiod_direction_output(pdata->speaker_amp_gpio, 0);
-       if (err) {
-               dev_err(card->dev, "could not setup speaker enable gpio\n");
-               return err;
-       }
-
        err = devm_snd_soc_register_card(card->dev, card);
        if (err) {
                dev_err(&pdev->dev, "snd_soc_register_card failed (%d)\n", err);
index 79936e3e80e70d18737189ae68328711c23dc84a..2b26318bc20097b0c5e369b50f151b7bde511e59 100644 (file)
@@ -45,29 +45,6 @@ static const struct snd_soc_dapm_route brownstone_audio_map[] = {
        {"MICBIAS1", NULL, "Main Mic"},
 };
 
-static int brownstone_wm8994_init(struct snd_soc_pcm_runtime *rtd)
-{
-       struct snd_soc_codec *codec = rtd->codec;
-       struct snd_soc_dapm_context *dapm = &codec->dapm;
-
-       /* set endpoints to not connected */
-       snd_soc_dapm_nc_pin(dapm, "HPOUT2P");
-       snd_soc_dapm_nc_pin(dapm, "HPOUT2N");
-       snd_soc_dapm_nc_pin(dapm, "LINEOUT1N");
-       snd_soc_dapm_nc_pin(dapm, "LINEOUT1P");
-       snd_soc_dapm_nc_pin(dapm, "LINEOUT2N");
-       snd_soc_dapm_nc_pin(dapm, "LINEOUT2P");
-       snd_soc_dapm_nc_pin(dapm, "IN1LN");
-       snd_soc_dapm_nc_pin(dapm, "IN1LP");
-       snd_soc_dapm_nc_pin(dapm, "IN1RP");
-       snd_soc_dapm_nc_pin(dapm, "IN2LP:VXRN");
-       snd_soc_dapm_nc_pin(dapm, "IN2RN");
-       snd_soc_dapm_nc_pin(dapm, "IN2RP:VXRP");
-       snd_soc_dapm_nc_pin(dapm, "IN2LN");
-
-       return 0;
-}
-
 static int brownstone_wm8994_hw_params(struct snd_pcm_substream *substream,
                                       struct snd_pcm_hw_params *params)
 {
@@ -115,7 +92,6 @@ static struct snd_soc_dai_link brownstone_wm8994_dai[] = {
        .dai_fmt        = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
                                SND_SOC_DAIFMT_CBS_CFS,
        .ops            = &brownstone_ops,
-       .init           = brownstone_wm8994_init,
 },
 };
 
@@ -132,6 +108,7 @@ static struct snd_soc_card brownstone = {
        .num_dapm_widgets = ARRAY_SIZE(brownstone_dapm_widgets),
        .dapm_routes = brownstone_audio_map,
        .num_dapm_routes = ARRAY_SIZE(brownstone_audio_map),
+       .fully_routed = true,
 };
 
 static int brownstone_probe(struct platform_device *pdev)
index 0fce8c420e969bf9f885729e6db2e5cb18a70507..80b457ac522acb2c9bdbf1318dfc59bbd36d3789 100644 (file)
@@ -192,6 +192,7 @@ static int poodle_amp_event(struct snd_soc_dapm_widget *w,
 static const struct snd_soc_dapm_widget wm8731_dapm_widgets[] = {
 SND_SOC_DAPM_HP("Headphone Jack", NULL),
 SND_SOC_DAPM_SPK("Ext Spk", poodle_amp_event),
+SND_SOC_DAPM_MIC("Microphone", NULL),
 };
 
 /* Corgi machine connections to the codec pins */
@@ -204,6 +205,8 @@ static const struct snd_soc_dapm_route poodle_audio_map[] = {
        /* speaker connected to LOUT, ROUT */
        {"Ext Spk", NULL, "ROUT"},
        {"Ext Spk", NULL, "LOUT"},
+
+       {"MICIN", NULL, "Microphone"},
 };
 
 static const char *jack_function[] = {"Off", "Headphone"};
@@ -220,20 +223,6 @@ static const struct snd_kcontrol_new wm8731_poodle_controls[] = {
                poodle_set_spk),
 };
 
-/*
- * Logic for a wm8731 as connected on a Sharp SL-C7x0 Device
- */
-static int poodle_wm8731_init(struct snd_soc_pcm_runtime *rtd)
-{
-       struct snd_soc_codec *codec = rtd->codec;
-       struct snd_soc_dapm_context *dapm = &codec->dapm;
-
-       snd_soc_dapm_nc_pin(dapm, "LLINEIN");
-       snd_soc_dapm_nc_pin(dapm, "RLINEIN");
-
-       return 0;
-}
-
 /* poodle digital audio interface glue - connects codec <--> CPU */
 static struct snd_soc_dai_link poodle_dai = {
        .name = "WM8731",
@@ -242,7 +231,6 @@ static struct snd_soc_dai_link poodle_dai = {
        .codec_dai_name = "wm8731-hifi",
        .platform_name = "pxa-pcm-audio",
        .codec_name = "wm8731.0-001b",
-       .init = poodle_wm8731_init,
        .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
                   SND_SOC_DAIFMT_CBS_CFS,
        .ops = &poodle_ops,
@@ -261,6 +249,7 @@ static struct snd_soc_card poodle = {
        .num_dapm_widgets = ARRAY_SIZE(wm8731_dapm_widgets),
        .dapm_routes = poodle_audio_map,
        .num_dapm_routes = ARRAY_SIZE(poodle_audio_map),
+       .fully_routed = true,
 };
 
 static int poodle_probe(struct platform_device *pdev)
index cb49284e853ad794154468258e926f62194073aa..f59f566551ef72ad4e0b5c4bb369d1c8b8de7ec0 100644 (file)
@@ -185,17 +185,6 @@ static const struct snd_kcontrol_new tosa_controls[] = {
                tosa_set_spk),
 };
 
-static int tosa_ac97_init(struct snd_soc_pcm_runtime *rtd)
-{
-       struct snd_soc_codec *codec = rtd->codec;
-       struct snd_soc_dapm_context *dapm = &codec->dapm;
-
-       snd_soc_dapm_nc_pin(dapm, "OUT3");
-       snd_soc_dapm_nc_pin(dapm, "MONOOUT");
-
-       return 0;
-}
-
 static struct snd_soc_dai_link tosa_dai[] = {
 {
        .name = "AC97",
@@ -204,7 +193,6 @@ static struct snd_soc_dai_link tosa_dai[] = {
        .codec_dai_name = "wm9712-hifi",
        .platform_name = "pxa-pcm-audio",
        .codec_name = "wm9712-codec",
-       .init = tosa_ac97_init,
        .ops = &tosa_ops,
 },
 {
@@ -230,6 +218,7 @@ static struct snd_soc_card tosa = {
        .num_dapm_widgets = ARRAY_SIZE(tosa_dapm_widgets),
        .dapm_routes = audio_map,
        .num_dapm_routes = ARRAY_SIZE(audio_map),
+       .fully_routed = true,
 };
 
 static int tosa_probe(struct platform_device *pdev)
index bcbfbe8303f7a03ac070c343e19e05d7847f8d8a..990b1aa6d7f67388e8fad6af6b6b4ec8c909b986 100644 (file)
@@ -132,16 +132,8 @@ static const struct snd_soc_dapm_route z2_audio_map[] = {
  */
 static int z2_wm8750_init(struct snd_soc_pcm_runtime *rtd)
 {
-       struct snd_soc_codec *codec = rtd->codec;
-       struct snd_soc_dapm_context *dapm = &codec->dapm;
        int ret;
 
-       /* NC codec pins */
-       snd_soc_dapm_disable_pin(dapm, "LINPUT3");
-       snd_soc_dapm_disable_pin(dapm, "RINPUT3");
-       snd_soc_dapm_disable_pin(dapm, "OUT3");
-       snd_soc_dapm_disable_pin(dapm, "MONO1");
-
        /* Jack detection API stuff */
        ret = snd_soc_card_jack_new(rtd->card, "Headset Jack", SND_JACK_HEADSET,
                                    &hs_jack, hs_jack_pins,
@@ -189,6 +181,7 @@ static struct snd_soc_card snd_soc_z2 = {
        .num_dapm_widgets = ARRAY_SIZE(wm8750_dapm_widgets),
        .dapm_routes = z2_audio_map,
        .num_dapm_routes = ARRAY_SIZE(z2_audio_map),
+       .fully_routed = true,
 };
 
 static struct platform_device *z2_snd_device;
index 5f58e4f1bca98b5c4c4c951dce24036aafa2d694..807fedfa1c76eb169b4abdf8652b8f448bb0a8e8 100644 (file)
@@ -6,20 +6,38 @@ config SND_SOC_QCOM
 
 config SND_SOC_LPASS_CPU
        tristate
-       depends on SND_SOC_QCOM
        select REGMAP_MMIO
 
 config SND_SOC_LPASS_PLATFORM
        tristate
-       depends on SND_SOC_QCOM
        select REGMAP_MMIO
 
-config SND_SOC_STORM
-       tristate "ASoC I2S support for Storm boards"
-       depends on (ARCH_QCOM && SND_SOC_QCOM) || COMPILE_TEST
+config SND_SOC_LPASS_IPQ806X
+       tristate
+       depends on SND_SOC_QCOM
+       select SND_SOC_LPASS_CPU
+       select SND_SOC_LPASS_PLATFORM
+
+config SND_SOC_LPASS_APQ8016
+       tristate
+       depends on SND_SOC_QCOM
        select SND_SOC_LPASS_CPU
        select SND_SOC_LPASS_PLATFORM
+
+config SND_SOC_STORM
+       tristate "ASoC I2S support for Storm boards"
+       depends on SND_SOC_QCOM && (ARCH_QCOM || COMPILE_TEST)
+       select SND_SOC_LPASS_IPQ806X
        select SND_SOC_MAX98357A
        help
           Say Y or M if you want add support for SoC audio on the
           Qualcomm Technologies IPQ806X-based Storm board.
+
+config SND_SOC_APQ8016_SBC
+       tristate "SoC Audio support for APQ8016 SBC platforms"
+       depends on SND_SOC_QCOM && (ARCH_QCOM || COMPILE_TEST)
+       select SND_SOC_LPASS_APQ8016
+       help
+          Support for Qualcomm Technologies LPASS audio block in
+          APQ8016 SOC-based systems.
+          Say Y if you want to use audio devices on MI2S.
index c5ce96c761c47b3a1b98e27d863fe0b5b9bc019e..79e5c50a8f71b85a1ae4d2e118fea62a6c5b7e82 100644 (file)
@@ -1,11 +1,17 @@
 # Platform
 snd-soc-lpass-cpu-objs := lpass-cpu.o
 snd-soc-lpass-platform-objs := lpass-platform.o
+snd-soc-lpass-ipq806x-objs := lpass-ipq806x.o
+snd-soc-lpass-apq8016-objs := lpass-apq8016.o
 
 obj-$(CONFIG_SND_SOC_LPASS_CPU) += snd-soc-lpass-cpu.o
 obj-$(CONFIG_SND_SOC_LPASS_PLATFORM) += snd-soc-lpass-platform.o
+obj-$(CONFIG_SND_SOC_LPASS_IPQ806X) += snd-soc-lpass-ipq806x.o
+obj-$(CONFIG_SND_SOC_LPASS_APQ8016) += snd-soc-lpass-apq8016.o
 
 # Machine
 snd-soc-storm-objs := storm.o
+snd-soc-apq8016-sbc-objs := apq8016_sbc.o
 
 obj-$(CONFIG_SND_SOC_STORM) += snd-soc-storm.o
+obj-$(CONFIG_SND_SOC_APQ8016_SBC) += snd-soc-apq8016-sbc.o
diff --git a/sound/soc/qcom/apq8016_sbc.c b/sound/soc/qcom/apq8016_sbc.c
new file mode 100644 (file)
index 0000000..1efdf00
--- /dev/null
@@ -0,0 +1,198 @@
+/*
+ * Copyright (c) 2015 The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <linux/device.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/io.h>
+#include <linux/of.h>
+#include <linux/clk.h>
+#include <linux/platform_device.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <dt-bindings/sound/apq8016-lpass.h>
+
+struct apq8016_sbc_data {
+       void __iomem *mic_iomux;
+       void __iomem *spkr_iomux;
+       struct snd_soc_dai_link dai_link[];     /* dynamically allocated */
+};
+
+#define MIC_CTRL_QUA_WS_SLAVE_SEL_10   BIT(17)
+#define MIC_CTRL_TLMM_SCLK_EN          BIT(1)
+#define        SPKR_CTL_PRI_WS_SLAVE_SEL_11    (BIT(17) | BIT(16))
+
+static int apq8016_sbc_dai_init(struct snd_soc_pcm_runtime *rtd)
+{
+       struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+       struct snd_soc_card *card = rtd->card;
+       struct apq8016_sbc_data *pdata = snd_soc_card_get_drvdata(card);
+       int rval = 0;
+
+       switch (cpu_dai->id) {
+       case MI2S_PRIMARY:
+               writel(readl(pdata->spkr_iomux) | SPKR_CTL_PRI_WS_SLAVE_SEL_11,
+                       pdata->spkr_iomux);
+               break;
+
+       case MI2S_QUATERNARY:
+               /* Configure the Quat MI2S to TLMM */
+               writel(readl(pdata->mic_iomux) | MIC_CTRL_QUA_WS_SLAVE_SEL_10 |
+                       MIC_CTRL_TLMM_SCLK_EN,
+                       pdata->mic_iomux);
+               break;
+
+       default:
+               dev_err(card->dev, "unsupported cpu dai configuration\n");
+               rval = -EINVAL;
+               break;
+
+       }
+
+       return rval;
+}
+
+static struct apq8016_sbc_data *apq8016_sbc_parse_of(struct snd_soc_card *card)
+{
+       struct device *dev = card->dev;
+       struct snd_soc_dai_link *link;
+       struct device_node *np, *codec, *cpu, *node  = dev->of_node;
+       struct apq8016_sbc_data *data;
+       int ret, num_links;
+
+       ret = snd_soc_of_parse_card_name(card, "qcom,model");
+       if (ret) {
+               dev_err(dev, "Error parsing card name: %d\n", ret);
+               return ERR_PTR(ret);
+       }
+
+       /* Populate links */
+       num_links = of_get_child_count(node);
+
+       /* Allocate the private data and the DAI link array */
+       data = devm_kzalloc(dev, sizeof(*data) + sizeof(*link) * num_links,
+                           GFP_KERNEL);
+       if (!data)
+               return ERR_PTR(-ENOMEM);
+
+       card->dai_link  = &data->dai_link[0];
+       card->num_links = num_links;
+
+       link = data->dai_link;
+
+       for_each_child_of_node(node, np) {
+               cpu = of_get_child_by_name(np, "cpu");
+               codec = of_get_child_by_name(np, "codec");
+
+               if (!cpu || !codec) {
+                       dev_err(dev, "Can't find cpu/codec DT node\n");
+                       return ERR_PTR(-EINVAL);
+               }
+
+               link->cpu_of_node = of_parse_phandle(cpu, "sound-dai", 0);
+               if (!link->cpu_of_node) {
+                       dev_err(card->dev, "error getting cpu phandle\n");
+                       return ERR_PTR(-EINVAL);
+               }
+
+               link->codec_of_node = of_parse_phandle(codec, "sound-dai", 0);
+               if (!link->codec_of_node) {
+                       dev_err(card->dev, "error getting codec phandle\n");
+                       return ERR_PTR(-EINVAL);
+               }
+
+               ret = snd_soc_of_get_dai_name(cpu, &link->cpu_dai_name);
+               if (ret) {
+                       dev_err(card->dev, "error getting cpu dai name\n");
+                       return ERR_PTR(ret);
+               }
+
+               ret = snd_soc_of_get_dai_name(codec, &link->codec_dai_name);
+               if (ret) {
+                       dev_err(card->dev, "error getting codec dai name\n");
+                       return ERR_PTR(ret);
+               }
+
+               link->platform_of_node = link->cpu_of_node;
+               /* For now we only support playback */
+               link->playback_only = true;
+
+               ret = of_property_read_string(np, "link-name", &link->name);
+               if (ret) {
+                       dev_err(card->dev, "error getting codec dai_link name\n");
+                       return ERR_PTR(ret);
+               }
+
+               link->stream_name = link->name;
+               link->init = apq8016_sbc_dai_init;
+               link++;
+       }
+
+       return data;
+}
+
+static int apq8016_sbc_platform_probe(struct platform_device *pdev)
+{
+       struct device *dev = &pdev->dev;
+       struct snd_soc_card *card;
+       struct apq8016_sbc_data *data;
+       struct resource *res;
+
+       card = devm_kzalloc(dev, sizeof(*card), GFP_KERNEL);
+       if (!card)
+               return -ENOMEM;
+
+       card->dev = dev;
+       data = apq8016_sbc_parse_of(card);
+       if (IS_ERR(data)) {
+               dev_err(&pdev->dev, "Error resolving dai links: %ld\n",
+                       PTR_ERR(data));
+               return PTR_ERR(data);
+       }
+
+       res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "mic-iomux");
+       data->mic_iomux = devm_ioremap_resource(dev, res);
+       if (IS_ERR(data->mic_iomux))
+               return PTR_ERR(data->mic_iomux);
+
+       res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "spkr-iomux");
+       data->spkr_iomux = devm_ioremap_resource(dev, res);
+       if (IS_ERR(data->spkr_iomux))
+               return PTR_ERR(data->spkr_iomux);
+
+       platform_set_drvdata(pdev, data);
+       snd_soc_card_set_drvdata(card, data);
+
+       return devm_snd_soc_register_card(&pdev->dev, card);
+}
+
+static const struct of_device_id apq8016_sbc_device_id[]  = {
+       { .compatible = "qcom,apq8016-sbc-sndcard" },
+       {},
+};
+MODULE_DEVICE_TABLE(of, apq8016_sbc_device_id);
+
+static struct platform_driver apq8016_sbc_platform_driver = {
+       .driver = {
+               .name = "qcom-apq8016-sbc",
+               .of_match_table = of_match_ptr(apq8016_sbc_device_id),
+       },
+       .probe = apq8016_sbc_platform_probe,
+};
+module_platform_driver(apq8016_sbc_platform_driver);
+
+MODULE_AUTHOR("Srinivas Kandagatla <srinivas.kandagatla@linaro.org");
+MODULE_DESCRIPTION("APQ8016 ASoC Machine Driver");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/qcom/lpass-apq8016.c b/sound/soc/qcom/lpass-apq8016.c
new file mode 100644 (file)
index 0000000..94efc01
--- /dev/null
@@ -0,0 +1,242 @@
+/*
+ * Copyright (c) 2010-2011,2013-2015 The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * lpass-apq8016.c -- ALSA SoC CPU DAI driver for APQ8016 LPASS
+ *
+ */
+
+
+#include <linux/clk.h>
+#include <linux/device.h>
+#include <linux/err.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/soc-dai.h>
+
+#include <dt-bindings/sound/apq8016-lpass.h>
+#include "lpass-lpaif-reg.h"
+#include "lpass.h"
+
+static struct snd_soc_dai_driver apq8016_lpass_cpu_dai_driver[] = {
+       [MI2S_PRIMARY] =  {
+               .id = MI2S_PRIMARY,
+               .name = "Primary MI2S",
+               .playback = {
+                       .stream_name    = "Primary Playback",
+                       .formats        = SNDRV_PCM_FMTBIT_S16 |
+                                               SNDRV_PCM_FMTBIT_S24 |
+                                               SNDRV_PCM_FMTBIT_S32,
+                       .rates          = SNDRV_PCM_RATE_8000 |
+                                               SNDRV_PCM_RATE_16000 |
+                                               SNDRV_PCM_RATE_32000 |
+                                               SNDRV_PCM_RATE_48000 |
+                                               SNDRV_PCM_RATE_96000,
+                       .rate_min       = 8000,
+                       .rate_max       = 96000,
+                       .channels_min   = 1,
+                       .channels_max   = 8,
+               },
+               .probe  = &asoc_qcom_lpass_cpu_dai_probe,
+               .ops    = &asoc_qcom_lpass_cpu_dai_ops,
+       },
+       [MI2S_SECONDARY] =  {
+               .id = MI2S_SECONDARY,
+               .name = "Secondary MI2S",
+               .playback = {
+                       .stream_name    = "Secondary Playback",
+                       .formats        = SNDRV_PCM_FMTBIT_S16 |
+                                               SNDRV_PCM_FMTBIT_S24 |
+                                               SNDRV_PCM_FMTBIT_S32,
+                       .rates          = SNDRV_PCM_RATE_8000 |
+                                               SNDRV_PCM_RATE_16000 |
+                                               SNDRV_PCM_RATE_32000 |
+                                               SNDRV_PCM_RATE_48000 |
+                                               SNDRV_PCM_RATE_96000,
+                       .rate_min       = 8000,
+                       .rate_max       = 96000,
+                       .channels_min   = 1,
+                       .channels_max   = 8,
+               },
+               .probe  = &asoc_qcom_lpass_cpu_dai_probe,
+               .ops    = &asoc_qcom_lpass_cpu_dai_ops,
+       },
+       [MI2S_TERTIARY] =  {
+               .id = MI2S_TERTIARY,
+               .name = "Tertiary MI2S",
+               .capture = {
+                       .stream_name    = "Tertiary Capture",
+                       .formats        = SNDRV_PCM_FMTBIT_S16 |
+                                               SNDRV_PCM_FMTBIT_S24 |
+                                               SNDRV_PCM_FMTBIT_S32,
+                       .rates          = SNDRV_PCM_RATE_8000 |
+                                               SNDRV_PCM_RATE_16000 |
+                                               SNDRV_PCM_RATE_32000 |
+                                               SNDRV_PCM_RATE_48000 |
+                                               SNDRV_PCM_RATE_96000,
+                       .rate_min       = 8000,
+                       .rate_max       = 96000,
+                       .channels_min   = 1,
+                       .channels_max   = 8,
+               },
+               .probe  = &asoc_qcom_lpass_cpu_dai_probe,
+               .ops    = &asoc_qcom_lpass_cpu_dai_ops,
+       },
+       [MI2S_QUATERNARY] =  {
+               .id = MI2S_QUATERNARY,
+               .name = "Quatenary MI2S",
+               .playback = {
+                       .stream_name    = "Quatenary Playback",
+                       .formats        = SNDRV_PCM_FMTBIT_S16 |
+                                               SNDRV_PCM_FMTBIT_S24 |
+                                               SNDRV_PCM_FMTBIT_S32,
+                       .rates          = SNDRV_PCM_RATE_8000 |
+                                               SNDRV_PCM_RATE_16000 |
+                                               SNDRV_PCM_RATE_32000 |
+                                               SNDRV_PCM_RATE_48000 |
+                                               SNDRV_PCM_RATE_96000,
+                       .rate_min       = 8000,
+                       .rate_max       = 96000,
+                       .channels_min   = 1,
+                       .channels_max   = 8,
+               },
+               .capture = {
+                       .stream_name    = "Quatenary Capture",
+                       .formats        = SNDRV_PCM_FMTBIT_S16 |
+                                               SNDRV_PCM_FMTBIT_S24 |
+                                               SNDRV_PCM_FMTBIT_S32,
+                       .rates          = SNDRV_PCM_RATE_8000 |
+                                               SNDRV_PCM_RATE_16000 |
+                                               SNDRV_PCM_RATE_32000 |
+                                               SNDRV_PCM_RATE_48000 |
+                                               SNDRV_PCM_RATE_96000,
+                       .rate_min       = 8000,
+                       .rate_max       = 96000,
+                       .channels_min   = 1,
+                       .channels_max   = 8,
+               },
+               .probe  = &asoc_qcom_lpass_cpu_dai_probe,
+               .ops    = &asoc_qcom_lpass_cpu_dai_ops,
+       },
+};
+
+static int apq8016_lpass_alloc_dma_channel(struct lpass_data *drvdata)
+{
+       struct lpass_variant *v = drvdata->variant;
+       int chan = find_first_zero_bit(&drvdata->rdma_ch_bit_map,
+                                       v->rdma_channels);
+
+       if (chan >= v->rdma_channels)
+               return -EBUSY;
+
+       set_bit(chan, &drvdata->rdma_ch_bit_map);
+
+       return chan;
+}
+
+static int apq8016_lpass_free_dma_channel(struct lpass_data *drvdata, int chan)
+{
+       clear_bit(chan, &drvdata->rdma_ch_bit_map);
+
+       return 0;
+}
+
+static int apq8016_lpass_init(struct platform_device *pdev)
+{
+       struct lpass_data *drvdata = platform_get_drvdata(pdev);
+       struct device *dev = &pdev->dev;
+       int ret;
+
+       drvdata->pcnoc_mport_clk = devm_clk_get(dev, "pcnoc-mport-clk");
+       if (IS_ERR(drvdata->pcnoc_mport_clk)) {
+               dev_err(&pdev->dev, "%s() error getting pcnoc-mport-clk: %ld\n",
+                               __func__, PTR_ERR(drvdata->pcnoc_mport_clk));
+               return PTR_ERR(drvdata->pcnoc_mport_clk);
+       }
+
+       ret = clk_prepare_enable(drvdata->pcnoc_mport_clk);
+       if (ret) {
+               dev_err(&pdev->dev, "%s() Error enabling pcnoc-mport-clk: %d\n",
+                               __func__, ret);
+               return ret;
+       }
+
+       drvdata->pcnoc_sway_clk = devm_clk_get(dev, "pcnoc-sway-clk");
+       if (IS_ERR(drvdata->pcnoc_sway_clk)) {
+               dev_err(&pdev->dev, "%s() error getting pcnoc-sway-clk: %ld\n",
+                               __func__, PTR_ERR(drvdata->pcnoc_sway_clk));
+               return PTR_ERR(drvdata->pcnoc_sway_clk);
+       }
+
+       ret = clk_prepare_enable(drvdata->pcnoc_sway_clk);
+       if (ret) {
+               dev_err(&pdev->dev, "%s() Error enabling pcnoc_sway_clk: %d\n",
+                               __func__, ret);
+               return ret;
+       }
+
+       return 0;
+}
+
+static int apq8016_lpass_exit(struct platform_device *pdev)
+{
+       struct lpass_data *drvdata = platform_get_drvdata(pdev);
+
+       clk_disable_unprepare(drvdata->pcnoc_mport_clk);
+       clk_disable_unprepare(drvdata->pcnoc_sway_clk);
+
+       return 0;
+}
+
+
+static struct lpass_variant apq8016_data = {
+       .i2sctrl_reg_base       = 0x1000,
+       .i2sctrl_reg_stride     = 0x1000,
+       .i2s_ports              = 4,
+       .irq_reg_base           = 0x6000,
+       .irq_reg_stride         = 0x1000,
+       .irq_ports              = 3,
+       .rdma_reg_base          = 0x8400,
+       .rdma_reg_stride        = 0x1000,
+       .rdma_channels          = 2,
+       .rdmactl_audif_start    = 1,
+       .dai_driver             = apq8016_lpass_cpu_dai_driver,
+       .num_dai                = ARRAY_SIZE(apq8016_lpass_cpu_dai_driver),
+       .init                   = apq8016_lpass_init,
+       .exit                   = apq8016_lpass_exit,
+       .alloc_dma_channel      = apq8016_lpass_alloc_dma_channel,
+       .free_dma_channel       = apq8016_lpass_free_dma_channel,
+};
+
+static const struct of_device_id apq8016_lpass_cpu_device_id[] = {
+       { .compatible = "qcom,lpass-cpu-apq8016", .data = &apq8016_data },
+       {}
+};
+MODULE_DEVICE_TABLE(of, apq8016_lpass_cpu_device_id);
+
+static struct platform_driver apq8016_lpass_cpu_platform_driver = {
+       .driver = {
+               .name           = "apq8016-lpass-cpu",
+               .of_match_table = of_match_ptr(apq8016_lpass_cpu_device_id),
+       },
+       .probe  = asoc_qcom_lpass_cpu_platform_probe,
+       .remove = asoc_qcom_lpass_cpu_platform_remove,
+};
+module_platform_driver(apq8016_lpass_cpu_platform_driver);
+
+MODULE_DESCRIPTION("APQ8016 LPASS CPU Driver");
+MODULE_LICENSE("GPL v2");
+
index 6698d058de29600a464be79490bec641736819c3..23f3d59e6d0957db55a6cd204107bf1b70400d37 100644 (file)
  */
 
 #include <linux/clk.h>
-#include <linux/compiler.h>
-#include <linux/device.h>
-#include <linux/err.h>
-#include <linux/ioport.h>
 #include <linux/kernel.h>
-#include <linux/mod_devicetable.h>
 #include <linux/module.h>
 #include <linux/of.h>
+#include <linux/of_device.h>
 #include <linux/platform_device.h>
 #include <sound/pcm.h>
 #include <sound/pcm_params.h>
 #include <linux/regmap.h>
 #include <sound/soc.h>
 #include <sound/soc-dai.h>
-#include "lpass-lpaif-ipq806x.h"
+#include "lpass-lpaif-reg.h"
 #include "lpass.h"
 
 static int lpass_cpu_daiops_set_sysclk(struct snd_soc_dai *dai, int clk_id,
@@ -37,7 +33,10 @@ static int lpass_cpu_daiops_set_sysclk(struct snd_soc_dai *dai, int clk_id,
        struct lpass_data *drvdata = snd_soc_dai_get_drvdata(dai);
        int ret;
 
-       ret = clk_set_rate(drvdata->mi2s_osr_clk, freq);
+       if (IS_ERR(drvdata->mi2s_osr_clk[dai->driver->id]))
+               return 0;
+
+       ret = clk_set_rate(drvdata->mi2s_osr_clk[dai->driver->id], freq);
        if (ret)
                dev_err(dai->dev, "%s() error setting mi2s osrclk to %u: %d\n",
                                __func__, freq, ret);
@@ -51,18 +50,23 @@ static int lpass_cpu_daiops_startup(struct snd_pcm_substream *substream,
        struct lpass_data *drvdata = snd_soc_dai_get_drvdata(dai);
        int ret;
 
-       ret = clk_prepare_enable(drvdata->mi2s_osr_clk);
-       if (ret) {
-               dev_err(dai->dev, "%s() error in enabling mi2s osr clk: %d\n",
-                               __func__, ret);
-               return ret;
+       if (!IS_ERR(drvdata->mi2s_osr_clk[dai->driver->id])) {
+               ret = clk_prepare_enable(
+                               drvdata->mi2s_osr_clk[dai->driver->id]);
+               if (ret) {
+                       dev_err(dai->dev, "%s() error in enabling mi2s osr clk: %d\n",
+                                       __func__, ret);
+                       return ret;
+               }
        }
 
-       ret = clk_prepare_enable(drvdata->mi2s_bit_clk);
+       ret = clk_prepare_enable(drvdata->mi2s_bit_clk[dai->driver->id]);
        if (ret) {
                dev_err(dai->dev, "%s() error in enabling mi2s bit clk: %d\n",
                                __func__, ret);
-               clk_disable_unprepare(drvdata->mi2s_osr_clk);
+               if (!IS_ERR(drvdata->mi2s_osr_clk[dai->driver->id]))
+                       clk_disable_unprepare(
+                               drvdata->mi2s_osr_clk[dai->driver->id]);
                return ret;
        }
 
@@ -74,8 +78,10 @@ static void lpass_cpu_daiops_shutdown(struct snd_pcm_substream *substream,
 {
        struct lpass_data *drvdata = snd_soc_dai_get_drvdata(dai);
 
-       clk_disable_unprepare(drvdata->mi2s_bit_clk);
-       clk_disable_unprepare(drvdata->mi2s_osr_clk);
+       clk_disable_unprepare(drvdata->mi2s_bit_clk[dai->driver->id]);
+
+       if (!IS_ERR(drvdata->mi2s_osr_clk[dai->driver->id]))
+               clk_disable_unprepare(drvdata->mi2s_osr_clk[dai->driver->id]);
 }
 
 static int lpass_cpu_daiops_hw_params(struct snd_pcm_substream *substream,
@@ -142,14 +148,16 @@ static int lpass_cpu_daiops_hw_params(struct snd_pcm_substream *substream,
        }
 
        ret = regmap_write(drvdata->lpaif_map,
-                       LPAIF_I2SCTL_REG(LPAIF_I2S_PORT_MI2S), regval);
+                          LPAIF_I2SCTL_REG(drvdata->variant, dai->driver->id),
+                          regval);
        if (ret) {
                dev_err(dai->dev, "%s() error writing to i2sctl reg: %d\n",
                                __func__, ret);
                return ret;
        }
 
-       ret = clk_set_rate(drvdata->mi2s_bit_clk, rate * bitwidth * 2);
+       ret = clk_set_rate(drvdata->mi2s_bit_clk[dai->driver->id],
+                          rate * bitwidth * 2);
        if (ret) {
                dev_err(dai->dev, "%s() error setting mi2s bitclk to %u: %d\n",
                                __func__, rate * bitwidth * 2, ret);
@@ -166,7 +174,8 @@ static int lpass_cpu_daiops_hw_free(struct snd_pcm_substream *substream,
        int ret;
 
        ret = regmap_write(drvdata->lpaif_map,
-                       LPAIF_I2SCTL_REG(LPAIF_I2S_PORT_MI2S), 0);
+                          LPAIF_I2SCTL_REG(drvdata->variant, dai->driver->id),
+                          0);
        if (ret)
                dev_err(dai->dev, "%s() error writing to i2sctl reg: %d\n",
                                __func__, ret);
@@ -181,7 +190,7 @@ static int lpass_cpu_daiops_prepare(struct snd_pcm_substream *substream,
        int ret;
 
        ret = regmap_update_bits(drvdata->lpaif_map,
-                       LPAIF_I2SCTL_REG(LPAIF_I2S_PORT_MI2S),
+                       LPAIF_I2SCTL_REG(drvdata->variant, dai->driver->id),
                        LPAIF_I2SCTL_SPKEN_MASK, LPAIF_I2SCTL_SPKEN_ENABLE);
        if (ret)
                dev_err(dai->dev, "%s() error writing to i2sctl reg: %d\n",
@@ -194,14 +203,15 @@ static int lpass_cpu_daiops_trigger(struct snd_pcm_substream *substream,
                int cmd, struct snd_soc_dai *dai)
 {
        struct lpass_data *drvdata = snd_soc_dai_get_drvdata(dai);
-       int ret;
+       int ret = -EINVAL;
 
        switch (cmd) {
        case SNDRV_PCM_TRIGGER_START:
        case SNDRV_PCM_TRIGGER_RESUME:
        case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
                ret = regmap_update_bits(drvdata->lpaif_map,
-                               LPAIF_I2SCTL_REG(LPAIF_I2S_PORT_MI2S),
+                               LPAIF_I2SCTL_REG(drvdata->variant,
+                                               dai->driver->id),
                                LPAIF_I2SCTL_SPKEN_MASK,
                                LPAIF_I2SCTL_SPKEN_ENABLE);
                if (ret)
@@ -212,7 +222,8 @@ static int lpass_cpu_daiops_trigger(struct snd_pcm_substream *substream,
        case SNDRV_PCM_TRIGGER_SUSPEND:
        case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
                ret = regmap_update_bits(drvdata->lpaif_map,
-                               LPAIF_I2SCTL_REG(LPAIF_I2S_PORT_MI2S),
+                               LPAIF_I2SCTL_REG(drvdata->variant,
+                                               dai->driver->id),
                                LPAIF_I2SCTL_SPKEN_MASK,
                                LPAIF_I2SCTL_SPKEN_DISABLE);
                if (ret)
@@ -224,7 +235,7 @@ static int lpass_cpu_daiops_trigger(struct snd_pcm_substream *substream,
        return ret;
 }
 
-static struct snd_soc_dai_ops lpass_cpu_dai_ops = {
+struct snd_soc_dai_ops asoc_qcom_lpass_cpu_dai_ops = {
        .set_sysclk     = lpass_cpu_daiops_set_sysclk,
        .startup        = lpass_cpu_daiops_startup,
        .shutdown       = lpass_cpu_daiops_shutdown,
@@ -233,41 +244,23 @@ static struct snd_soc_dai_ops lpass_cpu_dai_ops = {
        .prepare        = lpass_cpu_daiops_prepare,
        .trigger        = lpass_cpu_daiops_trigger,
 };
+EXPORT_SYMBOL_GPL(asoc_qcom_lpass_cpu_dai_ops);
 
-static int lpass_cpu_dai_probe(struct snd_soc_dai *dai)
+int asoc_qcom_lpass_cpu_dai_probe(struct snd_soc_dai *dai)
 {
        struct lpass_data *drvdata = snd_soc_dai_get_drvdata(dai);
        int ret;
 
        /* ensure audio hardware is disabled */
        ret = regmap_write(drvdata->lpaif_map,
-                       LPAIF_I2SCTL_REG(LPAIF_I2S_PORT_MI2S), 0);
+                       LPAIF_I2SCTL_REG(drvdata->variant, dai->driver->id), 0);
        if (ret)
                dev_err(dai->dev, "%s() error writing to i2sctl reg: %d\n",
                                __func__, ret);
 
        return ret;
 }
-
-static struct snd_soc_dai_driver lpass_cpu_dai_driver = {
-       .playback = {
-               .stream_name    = "lpass-cpu-playback",
-               .formats        = SNDRV_PCM_FMTBIT_S16 |
-                                       SNDRV_PCM_FMTBIT_S24 |
-                                       SNDRV_PCM_FMTBIT_S32,
-               .rates          = SNDRV_PCM_RATE_8000 |
-                                       SNDRV_PCM_RATE_16000 |
-                                       SNDRV_PCM_RATE_32000 |
-                                       SNDRV_PCM_RATE_48000 |
-                                       SNDRV_PCM_RATE_96000,
-               .rate_min       = 8000,
-               .rate_max       = 96000,
-               .channels_min   = 1,
-               .channels_max   = 8,
-       },
-       .probe  = &lpass_cpu_dai_probe,
-       .ops    = &lpass_cpu_dai_ops,
-};
+EXPORT_SYMBOL_GPL(asoc_qcom_lpass_cpu_dai_probe);
 
 static const struct snd_soc_component_driver lpass_cpu_comp_driver = {
        .name = "lpass-cpu",
@@ -275,27 +268,29 @@ static const struct snd_soc_component_driver lpass_cpu_comp_driver = {
 
 static bool lpass_cpu_regmap_writeable(struct device *dev, unsigned int reg)
 {
+       struct lpass_data *drvdata = dev_get_drvdata(dev);
+       struct lpass_variant *v = drvdata->variant;
        int i;
 
-       for (i = 0; i < LPAIF_I2S_PORT_NUM; ++i)
-               if (reg == LPAIF_I2SCTL_REG(i))
+       for (i = 0; i < v->i2s_ports; ++i)
+               if (reg == LPAIF_I2SCTL_REG(v, i))
                        return true;
 
-       for (i = 0; i < LPAIF_IRQ_PORT_NUM; ++i) {
-               if (reg == LPAIF_IRQEN_REG(i))
+       for (i = 0; i < v->irq_ports; ++i) {
+               if (reg == LPAIF_IRQEN_REG(v, i))
                        return true;
-               if (reg == LPAIF_IRQCLEAR_REG(i))
+               if (reg == LPAIF_IRQCLEAR_REG(v, i))
                        return true;
        }
 
-       for (i = 0; i < LPAIF_RDMA_CHAN_NUM; ++i) {
-               if (reg == LPAIF_RDMACTL_REG(i))
+       for (i = 0; i < v->rdma_channels; ++i) {
+               if (reg == LPAIF_RDMACTL_REG(v, i))
                        return true;
-               if (reg == LPAIF_RDMABASE_REG(i))
+               if (reg == LPAIF_RDMABASE_REG(v, i))
                        return true;
-               if (reg == LPAIF_RDMABUFF_REG(i))
+               if (reg == LPAIF_RDMABUFF_REG(v, i))
                        return true;
-               if (reg == LPAIF_RDMAPER_REG(i))
+               if (reg == LPAIF_RDMAPER_REG(v, i))
                        return true;
        }
 
@@ -304,29 +299,31 @@ static bool lpass_cpu_regmap_writeable(struct device *dev, unsigned int reg)
 
 static bool lpass_cpu_regmap_readable(struct device *dev, unsigned int reg)
 {
+       struct lpass_data *drvdata = dev_get_drvdata(dev);
+       struct lpass_variant *v = drvdata->variant;
        int i;
 
-       for (i = 0; i < LPAIF_I2S_PORT_NUM; ++i)
-               if (reg == LPAIF_I2SCTL_REG(i))
+       for (i = 0; i < v->i2s_ports; ++i)
+               if (reg == LPAIF_I2SCTL_REG(v, i))
                        return true;
 
-       for (i = 0; i < LPAIF_IRQ_PORT_NUM; ++i) {
-               if (reg == LPAIF_IRQEN_REG(i))
+       for (i = 0; i < v->irq_ports; ++i) {
+               if (reg == LPAIF_IRQEN_REG(v, i))
                        return true;
-               if (reg == LPAIF_IRQSTAT_REG(i))
+               if (reg == LPAIF_IRQSTAT_REG(v, i))
                        return true;
        }
 
-       for (i = 0; i < LPAIF_RDMA_CHAN_NUM; ++i) {
-               if (reg == LPAIF_RDMACTL_REG(i))
+       for (i = 0; i < v->rdma_channels; ++i) {
+               if (reg == LPAIF_RDMACTL_REG(v, i))
                        return true;
-               if (reg == LPAIF_RDMABASE_REG(i))
+               if (reg == LPAIF_RDMABASE_REG(v, i))
                        return true;
-               if (reg == LPAIF_RDMABUFF_REG(i))
+               if (reg == LPAIF_RDMABUFF_REG(v, i))
                        return true;
-               if (reg == LPAIF_RDMACURR_REG(i))
+               if (reg == LPAIF_RDMACURR_REG(v, i))
                        return true;
-               if (reg == LPAIF_RDMAPER_REG(i))
+               if (reg == LPAIF_RDMAPER_REG(v, i))
                        return true;
        }
 
@@ -335,36 +332,41 @@ static bool lpass_cpu_regmap_readable(struct device *dev, unsigned int reg)
 
 static bool lpass_cpu_regmap_volatile(struct device *dev, unsigned int reg)
 {
+       struct lpass_data *drvdata = dev_get_drvdata(dev);
+       struct lpass_variant *v = drvdata->variant;
        int i;
 
-       for (i = 0; i < LPAIF_IRQ_PORT_NUM; ++i)
-               if (reg == LPAIF_IRQSTAT_REG(i))
+       for (i = 0; i < v->irq_ports; ++i)
+               if (reg == LPAIF_IRQSTAT_REG(v, i))
                        return true;
 
-       for (i = 0; i < LPAIF_RDMA_CHAN_NUM; ++i)
-               if (reg == LPAIF_RDMACURR_REG(i))
+       for (i = 0; i < v->rdma_channels; ++i)
+               if (reg == LPAIF_RDMACURR_REG(v, i))
                        return true;
 
        return false;
 }
 
-static const struct regmap_config lpass_cpu_regmap_config = {
+static struct regmap_config lpass_cpu_regmap_config = {
        .reg_bits = 32,
        .reg_stride = 4,
        .val_bits = 32,
-       .max_register = LPAIF_RDMAPER_REG(LPAIF_RDMA_CHAN_MAX),
        .writeable_reg = lpass_cpu_regmap_writeable,
        .readable_reg = lpass_cpu_regmap_readable,
        .volatile_reg = lpass_cpu_regmap_volatile,
        .cache_type = REGCACHE_FLAT,
 };
 
-static int lpass_cpu_platform_probe(struct platform_device *pdev)
+int asoc_qcom_lpass_cpu_platform_probe(struct platform_device *pdev)
 {
        struct lpass_data *drvdata;
        struct device_node *dsp_of_node;
        struct resource *res;
-       int ret;
+       struct lpass_variant *variant;
+       struct device *dev = &pdev->dev;
+       const struct of_device_id *match;
+       char clk_name[16];
+       int ret, i, dai_id;
 
        dsp_of_node = of_parse_phandle(pdev->dev.of_node, "qcom,adsp", 0);
        if (dsp_of_node) {
@@ -379,11 +381,14 @@ static int lpass_cpu_platform_probe(struct platform_device *pdev)
                return -ENOMEM;
        platform_set_drvdata(pdev, drvdata);
 
+       match = of_match_device(dev->driver->of_match_table, dev);
+       if (!match || !match->data)
+               return -EINVAL;
+
+       drvdata->variant = (struct lpass_variant *)match->data;
+       variant = drvdata->variant;
+
        res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "lpass-lpaif");
-       if (!res) {
-               dev_err(&pdev->dev, "%s() error getting resource\n", __func__);
-               return -ENODEV;
-       }
 
        drvdata->lpaif = devm_ioremap_resource(&pdev->dev, res);
        if (IS_ERR((void const __force *)drvdata->lpaif)) {
@@ -393,6 +398,9 @@ static int lpass_cpu_platform_probe(struct platform_device *pdev)
                return PTR_ERR((void const __force *)drvdata->lpaif);
        }
 
+       lpass_cpu_regmap_config.max_register = LPAIF_RDMAPER_REG(variant,
+                                               variant->rdma_channels);
+
        drvdata->lpaif_map = devm_regmap_init_mmio(&pdev->dev, drvdata->lpaif,
                        &lpass_cpu_regmap_config);
        if (IS_ERR(drvdata->lpaif_map)) {
@@ -401,18 +409,38 @@ static int lpass_cpu_platform_probe(struct platform_device *pdev)
                return PTR_ERR(drvdata->lpaif_map);
        }
 
-       drvdata->mi2s_osr_clk = devm_clk_get(&pdev->dev, "mi2s-osr-clk");
-       if (IS_ERR(drvdata->mi2s_osr_clk)) {
-               dev_err(&pdev->dev, "%s() error getting mi2s-osr-clk: %ld\n",
-                               __func__, PTR_ERR(drvdata->mi2s_osr_clk));
-               return PTR_ERR(drvdata->mi2s_osr_clk);
-       }
-
-       drvdata->mi2s_bit_clk = devm_clk_get(&pdev->dev, "mi2s-bit-clk");
-       if (IS_ERR(drvdata->mi2s_bit_clk)) {
-               dev_err(&pdev->dev, "%s() error getting mi2s-bit-clk: %ld\n",
-                               __func__, PTR_ERR(drvdata->mi2s_bit_clk));
-               return PTR_ERR(drvdata->mi2s_bit_clk);
+       if (variant->init)
+               variant->init(pdev);
+
+       for (i = 0; i < variant->num_dai; i++) {
+               dai_id = variant->dai_driver[i].id;
+               if (variant->num_dai > 1)
+                       sprintf(clk_name, "mi2s-osr-clk%d", i);
+               else
+                       sprintf(clk_name, "mi2s-osr-clk");
+
+               drvdata->mi2s_osr_clk[dai_id] = devm_clk_get(&pdev->dev,
+                                                               clk_name);
+               if (IS_ERR(drvdata->mi2s_osr_clk[dai_id])) {
+                       dev_warn(&pdev->dev,
+                               "%s() error getting mi2s-osr-clk: %ld\n",
+                               __func__,
+                               PTR_ERR(drvdata->mi2s_osr_clk[dai_id]));
+               }
+
+               if (variant->num_dai > 1)
+                       sprintf(clk_name, "mi2s-bit-clk%d", i);
+               else
+                       sprintf(clk_name, "mi2s-bit-clk");
+
+               drvdata->mi2s_bit_clk[dai_id] = devm_clk_get(&pdev->dev,
+                                                           clk_name);
+               if (IS_ERR(drvdata->mi2s_bit_clk[dai_id])) {
+                       dev_err(&pdev->dev,
+                               "%s() error getting mi2s-bit-clk: %ld\n",
+                               __func__, PTR_ERR(drvdata->mi2s_bit_clk[i]));
+                       return PTR_ERR(drvdata->mi2s_bit_clk[dai_id]);
+               }
        }
 
        drvdata->ahbix_clk = devm_clk_get(&pdev->dev, "ahbix-clk");
@@ -439,7 +467,9 @@ static int lpass_cpu_platform_probe(struct platform_device *pdev)
        }
 
        ret = devm_snd_soc_register_component(&pdev->dev,
-                       &lpass_cpu_comp_driver, &lpass_cpu_dai_driver, 1);
+                                             &lpass_cpu_comp_driver,
+                                             variant->dai_driver,
+                                             variant->num_dai);
        if (ret) {
                dev_err(&pdev->dev, "%s() error registering cpu driver: %d\n",
                                __func__, ret);
@@ -459,33 +489,17 @@ err_clk:
        clk_disable_unprepare(drvdata->ahbix_clk);
        return ret;
 }
+EXPORT_SYMBOL_GPL(asoc_qcom_lpass_cpu_platform_probe);
 
-static int lpass_cpu_platform_remove(struct platform_device *pdev)
+int asoc_qcom_lpass_cpu_platform_remove(struct platform_device *pdev)
 {
        struct lpass_data *drvdata = platform_get_drvdata(pdev);
 
+       if (drvdata->variant->exit)
+               drvdata->variant->exit(pdev);
+
        clk_disable_unprepare(drvdata->ahbix_clk);
 
        return 0;
 }
-
-#ifdef CONFIG_OF
-static const struct of_device_id lpass_cpu_device_id[] = {
-       { .compatible = "qcom,lpass-cpu" },
-       {}
-};
-MODULE_DEVICE_TABLE(of, lpass_cpu_device_id);
-#endif
-
-static struct platform_driver lpass_cpu_platform_driver = {
-       .driver = {
-               .name           = "lpass-cpu",
-               .of_match_table = of_match_ptr(lpass_cpu_device_id),
-       },
-       .probe  = lpass_cpu_platform_probe,
-       .remove = lpass_cpu_platform_remove,
-};
-module_platform_driver(lpass_cpu_platform_driver);
-
-MODULE_DESCRIPTION("QTi LPASS CPU Driver");
-MODULE_LICENSE("GPL v2");
+EXPORT_SYMBOL_GPL(asoc_qcom_lpass_cpu_platform_remove);
diff --git a/sound/soc/qcom/lpass-ipq806x.c b/sound/soc/qcom/lpass-ipq806x.c
new file mode 100644 (file)
index 0000000..7356d3a
--- /dev/null
@@ -0,0 +1,109 @@
+/*
+ * Copyright (c) 2010-2011,2013-2015 The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * lpass-ipq806x.c -- ALSA SoC CPU DAI driver for QTi LPASS
+ * Splited out the IPQ8064 soc specific from lpass-cpu.c
+ */
+
+#include <linux/clk.h>
+#include <linux/device.h>
+#include <linux/err.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <sound/pcm.h>
+#include <sound/soc.h>
+#include <sound/soc-dai.h>
+
+#include "lpass-lpaif-reg.h"
+#include "lpass.h"
+
+enum lpaif_i2s_ports {
+       IPQ806X_LPAIF_I2S_PORT_CODEC_SPK,
+       IPQ806X_LPAIF_I2S_PORT_CODEC_MIC,
+       IPQ806X_LPAIF_I2S_PORT_SEC_SPK,
+       IPQ806X_LPAIF_I2S_PORT_SEC_MIC,
+       IPQ806X_LPAIF_I2S_PORT_MI2S,
+};
+
+enum lpaif_dma_channels {
+       IPQ806X_LPAIF_RDMA_CHAN_MI2S,
+       IPQ806X_LPAIF_RDMA_CHAN_PCM0,
+       IPQ806X_LPAIF_RDMA_CHAN_PCM1,
+};
+
+static struct snd_soc_dai_driver ipq806x_lpass_cpu_dai_driver = {
+       .id     = IPQ806X_LPAIF_I2S_PORT_MI2S,
+       .playback = {
+               .stream_name    = "lpass-cpu-playback",
+               .formats        = SNDRV_PCM_FMTBIT_S16 |
+                                       SNDRV_PCM_FMTBIT_S24 |
+                                       SNDRV_PCM_FMTBIT_S32,
+               .rates          = SNDRV_PCM_RATE_8000 |
+                                       SNDRV_PCM_RATE_16000 |
+                                       SNDRV_PCM_RATE_32000 |
+                                       SNDRV_PCM_RATE_48000 |
+                                       SNDRV_PCM_RATE_96000,
+               .rate_min       = 8000,
+               .rate_max       = 96000,
+               .channels_min   = 1,
+               .channels_max   = 8,
+       },
+       .probe  = &asoc_qcom_lpass_cpu_dai_probe,
+       .ops    = &asoc_qcom_lpass_cpu_dai_ops,
+};
+
+static int ipq806x_lpass_alloc_dma_channel(struct lpass_data *drvdata)
+{
+       return IPQ806X_LPAIF_RDMA_CHAN_MI2S;
+}
+
+static int ipq806x_lpass_free_dma_channel(struct lpass_data *drvdata, int chan)
+{
+       return 0;
+}
+
+struct lpass_variant ipq806x_data = {
+       .i2sctrl_reg_base       = 0x0010,
+       .i2sctrl_reg_stride     = 0x04,
+       .i2s_ports              = 5,
+       .irq_reg_base           = 0x3000,
+       .irq_reg_stride         = 0x1000,
+       .irq_ports              = 3,
+       .rdma_reg_base          = 0x6000,
+       .rdma_reg_stride        = 0x1000,
+       .rdma_channels          = 4,
+       .dai_driver             = &ipq806x_lpass_cpu_dai_driver,
+       .num_dai                = 1,
+       .alloc_dma_channel      = ipq806x_lpass_alloc_dma_channel,
+       .free_dma_channel       = ipq806x_lpass_free_dma_channel,
+};
+
+static const struct of_device_id ipq806x_lpass_cpu_device_id[] = {
+       { .compatible = "qcom,lpass-cpu", .data = &ipq806x_data },
+       {}
+};
+MODULE_DEVICE_TABLE(of, ipq806x_lpass_cpu_device_id);
+
+static struct platform_driver ipq806x_lpass_cpu_platform_driver = {
+       .driver = {
+               .name           = "lpass-cpu",
+               .of_match_table = of_match_ptr(ipq806x_lpass_cpu_device_id),
+       },
+       .probe  = asoc_qcom_lpass_cpu_platform_probe,
+       .remove = asoc_qcom_lpass_cpu_platform_remove,
+};
+module_platform_driver(ipq806x_lpass_cpu_platform_driver);
+
+MODULE_DESCRIPTION("QTi LPASS CPU Driver");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/qcom/lpass-lpaif-ipq806x.h b/sound/soc/qcom/lpass-lpaif-ipq806x.h
deleted file mode 100644 (file)
index dc423b8..0000000
+++ /dev/null
@@ -1,172 +0,0 @@
-/*
- * Copyright (c) 2010-2011,2013-2015 The Linux Foundation. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 and
- * only version 2 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * lpass-lpaif-ipq806x.h -- Definitions for the QTi LPAIF in the ipq806x LPASS
- */
-
-#ifndef __LPASS_LPAIF_H__
-#define __LPASS_LPAIF_H__
-
-#define LPAIF_BANK_OFFSET              0x1000
-
-/* LPAIF I2S */
-
-#define LPAIF_I2SCTL_REG_BASE          0x0010
-#define LPAIF_I2SCTL_REG_STRIDE                0x4
-#define LPAIF_I2SCTL_REG_ADDR(addr, port) \
-       (LPAIF_I2SCTL_REG_BASE + (addr) + (LPAIF_I2SCTL_REG_STRIDE * (port)))
-
-enum lpaif_i2s_ports {
-       LPAIF_I2S_PORT_MIN              = 0,
-
-       LPAIF_I2S_PORT_CODEC_SPK        = 0,
-       LPAIF_I2S_PORT_CODEC_MIC        = 1,
-       LPAIF_I2S_PORT_SEC_SPK          = 2,
-       LPAIF_I2S_PORT_SEC_MIC          = 3,
-       LPAIF_I2S_PORT_MI2S             = 4,
-
-       LPAIF_I2S_PORT_MAX              = 4,
-       LPAIF_I2S_PORT_NUM              = 5,
-};
-
-#define LPAIF_I2SCTL_REG(port)         LPAIF_I2SCTL_REG_ADDR(0x0, (port))
-
-#define LPAIF_I2SCTL_LOOPBACK_MASK     0x8000
-#define LPAIF_I2SCTL_LOOPBACK_SHIFT    15
-#define LPAIF_I2SCTL_LOOPBACK_DISABLE  (0 << LPAIF_I2SCTL_LOOPBACK_SHIFT)
-#define LPAIF_I2SCTL_LOOPBACK_ENABLE   (1 << LPAIF_I2SCTL_LOOPBACK_SHIFT)
-
-#define LPAIF_I2SCTL_SPKEN_MASK                0x4000
-#define LPAIF_I2SCTL_SPKEN_SHIFT       14
-#define LPAIF_I2SCTL_SPKEN_DISABLE     (0 << LPAIF_I2SCTL_SPKEN_SHIFT)
-#define LPAIF_I2SCTL_SPKEN_ENABLE      (1 << LPAIF_I2SCTL_SPKEN_SHIFT)
-
-#define LPAIF_I2SCTL_SPKMODE_MASK      0x3C00
-#define LPAIF_I2SCTL_SPKMODE_SHIFT     10
-#define LPAIF_I2SCTL_SPKMODE_NONE      (0 << LPAIF_I2SCTL_SPKMODE_SHIFT)
-#define LPAIF_I2SCTL_SPKMODE_SD0       (1 << LPAIF_I2SCTL_SPKMODE_SHIFT)
-#define LPAIF_I2SCTL_SPKMODE_SD1       (2 << LPAIF_I2SCTL_SPKMODE_SHIFT)
-#define LPAIF_I2SCTL_SPKMODE_SD2       (3 << LPAIF_I2SCTL_SPKMODE_SHIFT)
-#define LPAIF_I2SCTL_SPKMODE_SD3       (4 << LPAIF_I2SCTL_SPKMODE_SHIFT)
-#define LPAIF_I2SCTL_SPKMODE_QUAD01    (5 << LPAIF_I2SCTL_SPKMODE_SHIFT)
-#define LPAIF_I2SCTL_SPKMODE_QUAD23    (6 << LPAIF_I2SCTL_SPKMODE_SHIFT)
-#define LPAIF_I2SCTL_SPKMODE_6CH       (7 << LPAIF_I2SCTL_SPKMODE_SHIFT)
-#define LPAIF_I2SCTL_SPKMODE_8CH       (8 << LPAIF_I2SCTL_SPKMODE_SHIFT)
-
-#define LPAIF_I2SCTL_SPKMONO_MASK      0x0200
-#define LPAIF_I2SCTL_SPKMONO_SHIFT     9
-#define LPAIF_I2SCTL_SPKMONO_STEREO    (0 << LPAIF_I2SCTL_SPKMONO_SHIFT)
-#define LPAIF_I2SCTL_SPKMONO_MONO      (1 << LPAIF_I2SCTL_SPKMONO_SHIFT)
-
-#define LPAIF_I2SCTL_WSSRC_MASK                0x0004
-#define LPAIF_I2SCTL_WSSRC_SHIFT       2
-#define LPAIF_I2SCTL_WSSRC_INTERNAL    (0 << LPAIF_I2SCTL_WSSRC_SHIFT)
-#define LPAIF_I2SCTL_WSSRC_EXTERNAL    (1 << LPAIF_I2SCTL_WSSRC_SHIFT)
-
-#define LPAIF_I2SCTL_BITWIDTH_MASK     0x0003
-#define LPAIF_I2SCTL_BITWIDTH_SHIFT    0
-#define LPAIF_I2SCTL_BITWIDTH_16       (0 << LPAIF_I2SCTL_BITWIDTH_SHIFT)
-#define LPAIF_I2SCTL_BITWIDTH_24       (1 << LPAIF_I2SCTL_BITWIDTH_SHIFT)
-#define LPAIF_I2SCTL_BITWIDTH_32       (2 << LPAIF_I2SCTL_BITWIDTH_SHIFT)
-
-/* LPAIF IRQ */
-
-#define LPAIF_IRQ_REG_BASE             0x3000
-#define LPAIF_IRQ_REG_STRIDE           0x1000
-#define LPAIF_IRQ_REG_ADDR(addr, port) \
-       (LPAIF_IRQ_REG_BASE + (addr) + (LPAIF_IRQ_REG_STRIDE * (port)))
-
-enum lpaif_irq_ports {
-       LPAIF_IRQ_PORT_MIN              = 0,
-
-       LPAIF_IRQ_PORT_HOST             = 0,
-       LPAIF_IRQ_PORT_ADSP             = 1,
-
-       LPAIF_IRQ_PORT_MAX              = 2,
-       LPAIF_IRQ_PORT_NUM              = 3,
-};
-
-#define LPAIF_IRQEN_REG(port)          LPAIF_IRQ_REG_ADDR(0x0, (port))
-#define LPAIF_IRQSTAT_REG(port)                LPAIF_IRQ_REG_ADDR(0x4, (port))
-#define LPAIF_IRQCLEAR_REG(port)       LPAIF_IRQ_REG_ADDR(0xC, (port))
-
-#define LPAIF_IRQ_BITSTRIDE            3
-#define LPAIF_IRQ_PER(chan)            (1 << (LPAIF_IRQ_BITSTRIDE * (chan)))
-#define LPAIF_IRQ_XRUN(chan)           (2 << (LPAIF_IRQ_BITSTRIDE * (chan)))
-#define LPAIF_IRQ_ERR(chan)            (4 << (LPAIF_IRQ_BITSTRIDE * (chan)))
-#define LPAIF_IRQ_ALL(chan)            (7 << (LPAIF_IRQ_BITSTRIDE * (chan)))
-
-/* LPAIF DMA */
-
-#define LPAIF_RDMA_REG_BASE            0x6000
-#define LPAIF_RDMA_REG_STRIDE          0x1000
-#define LPAIF_RDMA_REG_ADDR(addr, chan) \
-       (LPAIF_RDMA_REG_BASE + (addr) + (LPAIF_RDMA_REG_STRIDE * (chan)))
-
-enum lpaif_dma_channels {
-       LPAIF_RDMA_CHAN_MIN             = 0,
-
-       LPAIF_RDMA_CHAN_MI2S            = 0,
-       LPAIF_RDMA_CHAN_PCM0            = 1,
-       LPAIF_RDMA_CHAN_PCM1            = 2,
-
-       LPAIF_RDMA_CHAN_MAX             = 4,
-       LPAIF_RDMA_CHAN_NUM             = 5,
-};
-
-#define LPAIF_RDMACTL_REG(chan)                LPAIF_RDMA_REG_ADDR(0x00, (chan))
-#define LPAIF_RDMABASE_REG(chan)       LPAIF_RDMA_REG_ADDR(0x04, (chan))
-#define        LPAIF_RDMABUFF_REG(chan)        LPAIF_RDMA_REG_ADDR(0x08, (chan))
-#define LPAIF_RDMACURR_REG(chan)       LPAIF_RDMA_REG_ADDR(0x0C, (chan))
-#define        LPAIF_RDMAPER_REG(chan)         LPAIF_RDMA_REG_ADDR(0x10, (chan))
-
-#define LPAIF_RDMACTL_BURSTEN_MASK     0x800
-#define LPAIF_RDMACTL_BURSTEN_SHIFT    11
-#define LPAIF_RDMACTL_BURSTEN_SINGLE   (0 << LPAIF_RDMACTL_BURSTEN_SHIFT)
-#define LPAIF_RDMACTL_BURSTEN_INCR4    (1 << LPAIF_RDMACTL_BURSTEN_SHIFT)
-
-#define LPAIF_RDMACTL_WPSCNT_MASK      0x700
-#define LPAIF_RDMACTL_WPSCNT_SHIFT     8
-#define LPAIF_RDMACTL_WPSCNT_ONE       (0 << LPAIF_RDMACTL_WPSCNT_SHIFT)
-#define LPAIF_RDMACTL_WPSCNT_TWO       (1 << LPAIF_RDMACTL_WPSCNT_SHIFT)
-#define LPAIF_RDMACTL_WPSCNT_THREE     (2 << LPAIF_RDMACTL_WPSCNT_SHIFT)
-#define LPAIF_RDMACTL_WPSCNT_FOUR      (3 << LPAIF_RDMACTL_WPSCNT_SHIFT)
-#define LPAIF_RDMACTL_WPSCNT_SIX       (5 << LPAIF_RDMACTL_WPSCNT_SHIFT)
-#define LPAIF_RDMACTL_WPSCNT_EIGHT     (7 << LPAIF_RDMACTL_WPSCNT_SHIFT)
-
-#define LPAIF_RDMACTL_AUDINTF_MASK     0x0F0
-#define LPAIF_RDMACTL_AUDINTF_SHIFT    4
-#define LPAIF_RDMACTL_AUDINTF_NONE     (0 << LPAIF_RDMACTL_AUDINTF_SHIFT)
-#define LPAIF_RDMACTL_AUDINTF_CODEC    (1 << LPAIF_RDMACTL_AUDINTF_SHIFT)
-#define LPAIF_RDMACTL_AUDINTF_PCM      (2 << LPAIF_RDMACTL_AUDINTF_SHIFT)
-#define LPAIF_RDMACTL_AUDINTF_SEC_I2S  (3 << LPAIF_RDMACTL_AUDINTF_SHIFT)
-#define LPAIF_RDMACTL_AUDINTF_MI2S     (4 << LPAIF_RDMACTL_AUDINTF_SHIFT)
-#define LPAIF_RDMACTL_AUDINTF_HDMI     (5 << LPAIF_RDMACTL_AUDINTF_SHIFT)
-#define LPAIF_RDMACTL_AUDINTF_SEC_PCM  (7 << LPAIF_RDMACTL_AUDINTF_SHIFT)
-
-#define LPAIF_RDMACTL_FIFOWM_MASK      0x00E
-#define LPAIF_RDMACTL_FIFOWM_SHIFT     1
-#define LPAIF_RDMACTL_FIFOWM_1         (0 << LPAIF_RDMACTL_FIFOWM_SHIFT)
-#define LPAIF_RDMACTL_FIFOWM_2         (1 << LPAIF_RDMACTL_FIFOWM_SHIFT)
-#define LPAIF_RDMACTL_FIFOWM_3         (2 << LPAIF_RDMACTL_FIFOWM_SHIFT)
-#define LPAIF_RDMACTL_FIFOWM_4         (3 << LPAIF_RDMACTL_FIFOWM_SHIFT)
-#define LPAIF_RDMACTL_FIFOWM_5         (4 << LPAIF_RDMACTL_FIFOWM_SHIFT)
-#define LPAIF_RDMACTL_FIFOWM_6         (5 << LPAIF_RDMACTL_FIFOWM_SHIFT)
-#define LPAIF_RDMACTL_FIFOWM_7         (6 << LPAIF_RDMACTL_FIFOWM_SHIFT)
-#define LPAIF_RDMACTL_FIFOWM_8         (7 << LPAIF_RDMACTL_FIFOWM_SHIFT)
-
-#define LPAIF_RDMACTL_ENABLE_MASK      0x1
-#define LPAIF_RDMACTL_ENABLE_SHIFT     0
-#define LPAIF_RDMACTL_ENABLE_OFF       (0 << LPAIF_RDMACTL_ENABLE_SHIFT)
-#define LPAIF_RDMACTL_ENABLE_ON                (1 << LPAIF_RDMACTL_ENABLE_SHIFT)
-
-#endif /* __LPASS_LPAIF_H__ */
diff --git a/sound/soc/qcom/lpass-lpaif-reg.h b/sound/soc/qcom/lpass-lpaif-reg.h
new file mode 100644 (file)
index 0000000..95e22f1
--- /dev/null
@@ -0,0 +1,126 @@
+/*
+ * Copyright (c) 2010-2011,2013-2015 The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef __LPASS_LPAIF_REG_H__
+#define __LPASS_LPAIF_REG_H__
+
+/* LPAIF I2S */
+
+#define LPAIF_I2SCTL_REG_ADDR(v, addr, port) \
+       (v->i2sctrl_reg_base + (addr) + v->i2sctrl_reg_stride * (port))
+
+#define LPAIF_I2SCTL_REG(v, port)      LPAIF_I2SCTL_REG_ADDR(v, 0x0, (port))
+#define LPAIF_I2SCTL_LOOPBACK_MASK     0x8000
+#define LPAIF_I2SCTL_LOOPBACK_SHIFT    15
+#define LPAIF_I2SCTL_LOOPBACK_DISABLE  (0 << LPAIF_I2SCTL_LOOPBACK_SHIFT)
+#define LPAIF_I2SCTL_LOOPBACK_ENABLE   (1 << LPAIF_I2SCTL_LOOPBACK_SHIFT)
+
+#define LPAIF_I2SCTL_SPKEN_MASK                0x4000
+#define LPAIF_I2SCTL_SPKEN_SHIFT       14
+#define LPAIF_I2SCTL_SPKEN_DISABLE     (0 << LPAIF_I2SCTL_SPKEN_SHIFT)
+#define LPAIF_I2SCTL_SPKEN_ENABLE      (1 << LPAIF_I2SCTL_SPKEN_SHIFT)
+
+#define LPAIF_I2SCTL_SPKMODE_MASK      0x3C00
+#define LPAIF_I2SCTL_SPKMODE_SHIFT     10
+#define LPAIF_I2SCTL_SPKMODE_NONE      (0 << LPAIF_I2SCTL_SPKMODE_SHIFT)
+#define LPAIF_I2SCTL_SPKMODE_SD0       (1 << LPAIF_I2SCTL_SPKMODE_SHIFT)
+#define LPAIF_I2SCTL_SPKMODE_SD1       (2 << LPAIF_I2SCTL_SPKMODE_SHIFT)
+#define LPAIF_I2SCTL_SPKMODE_SD2       (3 << LPAIF_I2SCTL_SPKMODE_SHIFT)
+#define LPAIF_I2SCTL_SPKMODE_SD3       (4 << LPAIF_I2SCTL_SPKMODE_SHIFT)
+#define LPAIF_I2SCTL_SPKMODE_QUAD01    (5 << LPAIF_I2SCTL_SPKMODE_SHIFT)
+#define LPAIF_I2SCTL_SPKMODE_QUAD23    (6 << LPAIF_I2SCTL_SPKMODE_SHIFT)
+#define LPAIF_I2SCTL_SPKMODE_6CH       (7 << LPAIF_I2SCTL_SPKMODE_SHIFT)
+#define LPAIF_I2SCTL_SPKMODE_8CH       (8 << LPAIF_I2SCTL_SPKMODE_SHIFT)
+
+#define LPAIF_I2SCTL_SPKMONO_MASK      0x0200
+#define LPAIF_I2SCTL_SPKMONO_SHIFT     9
+#define LPAIF_I2SCTL_SPKMONO_STEREO    (0 << LPAIF_I2SCTL_SPKMONO_SHIFT)
+#define LPAIF_I2SCTL_SPKMONO_MONO      (1 << LPAIF_I2SCTL_SPKMONO_SHIFT)
+
+#define LPAIF_I2SCTL_WSSRC_MASK                0x0004
+#define LPAIF_I2SCTL_WSSRC_SHIFT       2
+#define LPAIF_I2SCTL_WSSRC_INTERNAL    (0 << LPAIF_I2SCTL_WSSRC_SHIFT)
+#define LPAIF_I2SCTL_WSSRC_EXTERNAL    (1 << LPAIF_I2SCTL_WSSRC_SHIFT)
+
+#define LPAIF_I2SCTL_BITWIDTH_MASK     0x0003
+#define LPAIF_I2SCTL_BITWIDTH_SHIFT    0
+#define LPAIF_I2SCTL_BITWIDTH_16       (0 << LPAIF_I2SCTL_BITWIDTH_SHIFT)
+#define LPAIF_I2SCTL_BITWIDTH_24       (1 << LPAIF_I2SCTL_BITWIDTH_SHIFT)
+#define LPAIF_I2SCTL_BITWIDTH_32       (2 << LPAIF_I2SCTL_BITWIDTH_SHIFT)
+
+/* LPAIF IRQ */
+#define LPAIF_IRQ_REG_ADDR(v, addr, port) \
+       (v->irq_reg_base + (addr) + v->irq_reg_stride * (port))
+
+#define LPAIF_IRQ_PORT_HOST            0
+
+#define LPAIF_IRQEN_REG(v, port)       LPAIF_IRQ_REG_ADDR(v, 0x0, (port))
+#define LPAIF_IRQSTAT_REG(v, port)     LPAIF_IRQ_REG_ADDR(v, 0x4, (port))
+#define LPAIF_IRQCLEAR_REG(v, port)    LPAIF_IRQ_REG_ADDR(v, 0xC, (port))
+
+#define LPAIF_IRQ_BITSTRIDE            3
+
+#define LPAIF_IRQ_PER(chan)            (1 << (LPAIF_IRQ_BITSTRIDE * (chan)))
+#define LPAIF_IRQ_XRUN(chan)           (2 << (LPAIF_IRQ_BITSTRIDE * (chan)))
+#define LPAIF_IRQ_ERR(chan)            (4 << (LPAIF_IRQ_BITSTRIDE * (chan)))
+
+#define LPAIF_IRQ_ALL(chan)            (7 << (LPAIF_IRQ_BITSTRIDE * (chan)))
+
+/* LPAIF DMA */
+
+#define LPAIF_RDMA_REG_ADDR(v, addr, chan) \
+       (v->rdma_reg_base + (addr) + v->rdma_reg_stride * (chan))
+
+#define LPAIF_RDMACTL_AUDINTF(id)      (id << LPAIF_RDMACTL_AUDINTF_SHIFT)
+
+#define LPAIF_RDMACTL_REG(v, chan)     LPAIF_RDMA_REG_ADDR(v, 0x00, (chan))
+#define LPAIF_RDMABASE_REG(v, chan)    LPAIF_RDMA_REG_ADDR(v, 0x04, (chan))
+#define        LPAIF_RDMABUFF_REG(v, chan)     LPAIF_RDMA_REG_ADDR(v, 0x08, (chan))
+#define LPAIF_RDMACURR_REG(v, chan)    LPAIF_RDMA_REG_ADDR(v, 0x0C, (chan))
+#define        LPAIF_RDMAPER_REG(v, chan)      LPAIF_RDMA_REG_ADDR(v, 0x10, (chan))
+#define        LPAIF_RDMAPERCNT_REG(v, chan)   LPAIF_RDMA_REG_ADDR(v, 0x14, (chan))
+
+#define LPAIF_RDMACTL_BURSTEN_MASK     0x800
+#define LPAIF_RDMACTL_BURSTEN_SHIFT    11
+#define LPAIF_RDMACTL_BURSTEN_SINGLE   (0 << LPAIF_RDMACTL_BURSTEN_SHIFT)
+#define LPAIF_RDMACTL_BURSTEN_INCR4    (1 << LPAIF_RDMACTL_BURSTEN_SHIFT)
+
+#define LPAIF_RDMACTL_WPSCNT_MASK      0x700
+#define LPAIF_RDMACTL_WPSCNT_SHIFT     8
+#define LPAIF_RDMACTL_WPSCNT_ONE       (0 << LPAIF_RDMACTL_WPSCNT_SHIFT)
+#define LPAIF_RDMACTL_WPSCNT_TWO       (1 << LPAIF_RDMACTL_WPSCNT_SHIFT)
+#define LPAIF_RDMACTL_WPSCNT_THREE     (2 << LPAIF_RDMACTL_WPSCNT_SHIFT)
+#define LPAIF_RDMACTL_WPSCNT_FOUR      (3 << LPAIF_RDMACTL_WPSCNT_SHIFT)
+#define LPAIF_RDMACTL_WPSCNT_SIX       (5 << LPAIF_RDMACTL_WPSCNT_SHIFT)
+#define LPAIF_RDMACTL_WPSCNT_EIGHT     (7 << LPAIF_RDMACTL_WPSCNT_SHIFT)
+
+#define LPAIF_RDMACTL_AUDINTF_MASK     0x0F0
+#define LPAIF_RDMACTL_AUDINTF_SHIFT    4
+
+#define LPAIF_RDMACTL_FIFOWM_MASK      0x00E
+#define LPAIF_RDMACTL_FIFOWM_SHIFT     1
+#define LPAIF_RDMACTL_FIFOWM_1         (0 << LPAIF_RDMACTL_FIFOWM_SHIFT)
+#define LPAIF_RDMACTL_FIFOWM_2         (1 << LPAIF_RDMACTL_FIFOWM_SHIFT)
+#define LPAIF_RDMACTL_FIFOWM_3         (2 << LPAIF_RDMACTL_FIFOWM_SHIFT)
+#define LPAIF_RDMACTL_FIFOWM_4         (3 << LPAIF_RDMACTL_FIFOWM_SHIFT)
+#define LPAIF_RDMACTL_FIFOWM_5         (4 << LPAIF_RDMACTL_FIFOWM_SHIFT)
+#define LPAIF_RDMACTL_FIFOWM_6         (5 << LPAIF_RDMACTL_FIFOWM_SHIFT)
+#define LPAIF_RDMACTL_FIFOWM_7         (6 << LPAIF_RDMACTL_FIFOWM_SHIFT)
+#define LPAIF_RDMACTL_FIFOWM_8         (7 << LPAIF_RDMACTL_FIFOWM_SHIFT)
+
+#define LPAIF_RDMACTL_ENABLE_MASK      0x1
+#define LPAIF_RDMACTL_ENABLE_SHIFT     0
+#define LPAIF_RDMACTL_ENABLE_OFF       (0 << LPAIF_RDMACTL_ENABLE_SHIFT)
+#define LPAIF_RDMACTL_ENABLE_ON                (1 << LPAIF_RDMACTL_ENABLE_SHIFT)
+
+#endif /* __LPASS_LPAIF_REG_H__ */
index 2fa6280dfb234b213904ad73dfad91c7f575538c..79688aa1941a5c4168c2c52924c79722ce6172c7 100644 (file)
  * lpass-platform.c -- ALSA SoC platform driver for QTi LPASS
  */
 
-#include <linux/compiler.h>
-#include <linux/device.h>
 #include <linux/dma-mapping.h>
-#include <linux/err.h>
 #include <linux/export.h>
 #include <linux/kernel.h>
 #include <linux/module.h>
-#include <linux/io.h>
 #include <linux/platform_device.h>
-#include <sound/memalloc.h>
-#include <sound/pcm.h>
 #include <sound/pcm_params.h>
 #include <linux/regmap.h>
 #include <sound/soc.h>
-#include "lpass-lpaif-ipq806x.h"
+#include "lpass-lpaif-reg.h"
 #include "lpass.h"
 
+struct lpass_pcm_data {
+       int rdma_ch;
+       int i2s_port;
+};
+
 #define LPASS_PLATFORM_BUFFER_SIZE     (16 * 1024)
 #define LPASS_PLATFORM_PERIODS         2
 
@@ -84,13 +83,15 @@ static int lpass_platform_pcmops_hw_params(struct snd_pcm_substream *substream,
                struct snd_pcm_hw_params *params)
 {
        struct snd_soc_pcm_runtime *soc_runtime = substream->private_data;
+       struct lpass_pcm_data *pcm_data = snd_soc_pcm_get_drvdata(soc_runtime);
        struct lpass_data *drvdata =
                snd_soc_platform_get_drvdata(soc_runtime->platform);
+       struct lpass_variant *v = drvdata->variant;
        snd_pcm_format_t format = params_format(params);
        unsigned int channels = params_channels(params);
        unsigned int regval;
        int bitwidth;
-       int ret;
+       int ret, rdma_port = pcm_data->i2s_port + v->rdmactl_audif_start;
 
        bitwidth = snd_pcm_format_width(format);
        if (bitwidth < 0) {
@@ -100,7 +101,7 @@ static int lpass_platform_pcmops_hw_params(struct snd_pcm_substream *substream,
        }
 
        regval = LPAIF_RDMACTL_BURSTEN_INCR4 |
-                       LPAIF_RDMACTL_AUDINTF_MI2S |
+                       LPAIF_RDMACTL_AUDINTF(rdma_port) |
                        LPAIF_RDMACTL_FIFOWM_8;
 
        switch (bitwidth) {
@@ -156,7 +157,7 @@ static int lpass_platform_pcmops_hw_params(struct snd_pcm_substream *substream,
        }
 
        ret = regmap_write(drvdata->lpaif_map,
-                       LPAIF_RDMACTL_REG(LPAIF_RDMA_CHAN_MI2S), regval);
+                       LPAIF_RDMACTL_REG(v, pcm_data->rdma_ch), regval);
        if (ret) {
                dev_err(soc_runtime->dev, "%s() error writing to rdmactl reg: %d\n",
                                __func__, ret);
@@ -169,12 +170,14 @@ static int lpass_platform_pcmops_hw_params(struct snd_pcm_substream *substream,
 static int lpass_platform_pcmops_hw_free(struct snd_pcm_substream *substream)
 {
        struct snd_soc_pcm_runtime *soc_runtime = substream->private_data;
+       struct lpass_pcm_data *pcm_data = snd_soc_pcm_get_drvdata(soc_runtime);
        struct lpass_data *drvdata =
                snd_soc_platform_get_drvdata(soc_runtime->platform);
+       struct lpass_variant *v = drvdata->variant;
        int ret;
 
        ret = regmap_write(drvdata->lpaif_map,
-                       LPAIF_RDMACTL_REG(LPAIF_RDMA_CHAN_MI2S), 0);
+                       LPAIF_RDMACTL_REG(v, pcm_data->rdma_ch), 0);
        if (ret)
                dev_err(soc_runtime->dev, "%s() error writing to rdmactl reg: %d\n",
                                __func__, ret);
@@ -186,12 +189,14 @@ static int lpass_platform_pcmops_prepare(struct snd_pcm_substream *substream)
 {
        struct snd_pcm_runtime *runtime = substream->runtime;
        struct snd_soc_pcm_runtime *soc_runtime = substream->private_data;
+       struct lpass_pcm_data *pcm_data = snd_soc_pcm_get_drvdata(soc_runtime);
        struct lpass_data *drvdata =
                snd_soc_platform_get_drvdata(soc_runtime->platform);
-       int ret;
+       struct lpass_variant *v = drvdata->variant;
+       int ret, ch = pcm_data->rdma_ch;
 
        ret = regmap_write(drvdata->lpaif_map,
-                       LPAIF_RDMABASE_REG(LPAIF_RDMA_CHAN_MI2S),
+                       LPAIF_RDMABASE_REG(v, ch),
                        runtime->dma_addr);
        if (ret) {
                dev_err(soc_runtime->dev, "%s() error writing to rdmabase reg: %d\n",
@@ -200,7 +205,7 @@ static int lpass_platform_pcmops_prepare(struct snd_pcm_substream *substream)
        }
 
        ret = regmap_write(drvdata->lpaif_map,
-                       LPAIF_RDMABUFF_REG(LPAIF_RDMA_CHAN_MI2S),
+                       LPAIF_RDMABUFF_REG(v, ch),
                        (snd_pcm_lib_buffer_bytes(substream) >> 2) - 1);
        if (ret) {
                dev_err(soc_runtime->dev, "%s() error writing to rdmabuff reg: %d\n",
@@ -209,7 +214,7 @@ static int lpass_platform_pcmops_prepare(struct snd_pcm_substream *substream)
        }
 
        ret = regmap_write(drvdata->lpaif_map,
-                       LPAIF_RDMAPER_REG(LPAIF_RDMA_CHAN_MI2S),
+                       LPAIF_RDMAPER_REG(v, ch),
                        (snd_pcm_lib_period_bytes(substream) >> 2) - 1);
        if (ret) {
                dev_err(soc_runtime->dev, "%s() error writing to rdmaper reg: %d\n",
@@ -218,7 +223,7 @@ static int lpass_platform_pcmops_prepare(struct snd_pcm_substream *substream)
        }
 
        ret = regmap_update_bits(drvdata->lpaif_map,
-                       LPAIF_RDMACTL_REG(LPAIF_RDMA_CHAN_MI2S),
+                       LPAIF_RDMACTL_REG(v, ch),
                        LPAIF_RDMACTL_ENABLE_MASK, LPAIF_RDMACTL_ENABLE_ON);
        if (ret) {
                dev_err(soc_runtime->dev, "%s() error writing to rdmactl reg: %d\n",
@@ -233,9 +238,11 @@ static int lpass_platform_pcmops_trigger(struct snd_pcm_substream *substream,
                int cmd)
 {
        struct snd_soc_pcm_runtime *soc_runtime = substream->private_data;
+       struct lpass_pcm_data *pcm_data = snd_soc_pcm_get_drvdata(soc_runtime);
        struct lpass_data *drvdata =
                snd_soc_platform_get_drvdata(soc_runtime->platform);
-       int ret;
+       struct lpass_variant *v = drvdata->variant;
+       int ret, ch = pcm_data->rdma_ch;
 
        switch (cmd) {
        case SNDRV_PCM_TRIGGER_START:
@@ -243,8 +250,8 @@ static int lpass_platform_pcmops_trigger(struct snd_pcm_substream *substream,
        case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
                /* clear status before enabling interrupts */
                ret = regmap_write(drvdata->lpaif_map,
-                               LPAIF_IRQCLEAR_REG(LPAIF_IRQ_PORT_HOST),
-                               LPAIF_IRQ_ALL(LPAIF_RDMA_CHAN_MI2S));
+                               LPAIF_IRQCLEAR_REG(v, LPAIF_IRQ_PORT_HOST),
+                               LPAIF_IRQ_ALL(ch));
                if (ret) {
                        dev_err(soc_runtime->dev, "%s() error writing to irqclear reg: %d\n",
                                        __func__, ret);
@@ -252,9 +259,9 @@ static int lpass_platform_pcmops_trigger(struct snd_pcm_substream *substream,
                }
 
                ret = regmap_update_bits(drvdata->lpaif_map,
-                               LPAIF_IRQEN_REG(LPAIF_IRQ_PORT_HOST),
-                               LPAIF_IRQ_ALL(LPAIF_RDMA_CHAN_MI2S),
-                               LPAIF_IRQ_ALL(LPAIF_RDMA_CHAN_MI2S));
+                               LPAIF_IRQEN_REG(v, LPAIF_IRQ_PORT_HOST),
+                               LPAIF_IRQ_ALL(ch),
+                               LPAIF_IRQ_ALL(ch));
                if (ret) {
                        dev_err(soc_runtime->dev, "%s() error writing to irqen reg: %d\n",
                                        __func__, ret);
@@ -262,7 +269,7 @@ static int lpass_platform_pcmops_trigger(struct snd_pcm_substream *substream,
                }
 
                ret = regmap_update_bits(drvdata->lpaif_map,
-                               LPAIF_RDMACTL_REG(LPAIF_RDMA_CHAN_MI2S),
+                               LPAIF_RDMACTL_REG(v, ch),
                                LPAIF_RDMACTL_ENABLE_MASK,
                                LPAIF_RDMACTL_ENABLE_ON);
                if (ret) {
@@ -275,7 +282,7 @@ static int lpass_platform_pcmops_trigger(struct snd_pcm_substream *substream,
        case SNDRV_PCM_TRIGGER_SUSPEND:
        case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
                ret = regmap_update_bits(drvdata->lpaif_map,
-                               LPAIF_RDMACTL_REG(LPAIF_RDMA_CHAN_MI2S),
+                               LPAIF_RDMACTL_REG(v, ch),
                                LPAIF_RDMACTL_ENABLE_MASK,
                                LPAIF_RDMACTL_ENABLE_OFF);
                if (ret) {
@@ -285,8 +292,8 @@ static int lpass_platform_pcmops_trigger(struct snd_pcm_substream *substream,
                }
 
                ret = regmap_update_bits(drvdata->lpaif_map,
-                               LPAIF_IRQEN_REG(LPAIF_IRQ_PORT_HOST),
-                               LPAIF_IRQ_ALL(LPAIF_RDMA_CHAN_MI2S), 0);
+                               LPAIF_IRQEN_REG(v, LPAIF_IRQ_PORT_HOST),
+                               LPAIF_IRQ_ALL(ch), 0);
                if (ret) {
                        dev_err(soc_runtime->dev, "%s() error writing to irqen reg: %d\n",
                                        __func__, ret);
@@ -302,13 +309,15 @@ static snd_pcm_uframes_t lpass_platform_pcmops_pointer(
                struct snd_pcm_substream *substream)
 {
        struct snd_soc_pcm_runtime *soc_runtime = substream->private_data;
+       struct lpass_pcm_data *pcm_data = snd_soc_pcm_get_drvdata(soc_runtime);
        struct lpass_data *drvdata =
                        snd_soc_platform_get_drvdata(soc_runtime->platform);
+       struct lpass_variant *v = drvdata->variant;
        unsigned int base_addr, curr_addr;
-       int ret;
+       int ret, ch = pcm_data->rdma_ch;
 
        ret = regmap_read(drvdata->lpaif_map,
-                       LPAIF_RDMABASE_REG(LPAIF_RDMA_CHAN_MI2S), &base_addr);
+                       LPAIF_RDMABASE_REG(v, ch), &base_addr);
        if (ret) {
                dev_err(soc_runtime->dev, "%s() error reading from rdmabase reg: %d\n",
                                __func__, ret);
@@ -316,7 +325,7 @@ static snd_pcm_uframes_t lpass_platform_pcmops_pointer(
        }
 
        ret = regmap_read(drvdata->lpaif_map,
-                       LPAIF_RDMACURR_REG(LPAIF_RDMA_CHAN_MI2S), &curr_addr);
+                       LPAIF_RDMACURR_REG(v, ch), &curr_addr);
        if (ret) {
                dev_err(soc_runtime->dev, "%s() error reading from rdmacurr reg: %d\n",
                                __func__, ret);
@@ -347,29 +356,20 @@ static struct snd_pcm_ops lpass_platform_pcm_ops = {
        .mmap           = lpass_platform_pcmops_mmap,
 };
 
-static irqreturn_t lpass_platform_lpaif_irq(int irq, void *data)
+static irqreturn_t lpass_dma_interrupt_handler(
+                       struct snd_pcm_substream *substream,
+                       struct lpass_data *drvdata,
+                       int chan, u32 interrupts)
 {
-       struct snd_pcm_substream *substream = data;
        struct snd_soc_pcm_runtime *soc_runtime = substream->private_data;
-       struct lpass_data *drvdata =
-               snd_soc_platform_get_drvdata(soc_runtime->platform);
-       unsigned int interrupts;
+       struct lpass_variant *v = drvdata->variant;
        irqreturn_t ret = IRQ_NONE;
        int rv;
 
-       rv = regmap_read(drvdata->lpaif_map,
-                       LPAIF_IRQSTAT_REG(LPAIF_IRQ_PORT_HOST), &interrupts);
-       if (rv) {
-               dev_err(soc_runtime->dev, "%s() error reading from irqstat reg: %d\n",
-                               __func__, rv);
-               return IRQ_NONE;
-       }
-       interrupts &= LPAIF_IRQ_ALL(LPAIF_RDMA_CHAN_MI2S);
-
-       if (interrupts & LPAIF_IRQ_PER(LPAIF_RDMA_CHAN_MI2S)) {
+       if (interrupts & LPAIF_IRQ_PER(chan)) {
                rv = regmap_write(drvdata->lpaif_map,
-                               LPAIF_IRQCLEAR_REG(LPAIF_IRQ_PORT_HOST),
-                               LPAIF_IRQ_PER(LPAIF_RDMA_CHAN_MI2S));
+                               LPAIF_IRQCLEAR_REG(v, LPAIF_IRQ_PORT_HOST),
+                               LPAIF_IRQ_PER(chan));
                if (rv) {
                        dev_err(soc_runtime->dev, "%s() error writing to irqclear reg: %d\n",
                                        __func__, rv);
@@ -379,10 +379,10 @@ static irqreturn_t lpass_platform_lpaif_irq(int irq, void *data)
                ret = IRQ_HANDLED;
        }
 
-       if (interrupts & LPAIF_IRQ_XRUN(LPAIF_RDMA_CHAN_MI2S)) {
+       if (interrupts & LPAIF_IRQ_XRUN(chan)) {
                rv = regmap_write(drvdata->lpaif_map,
-                               LPAIF_IRQCLEAR_REG(LPAIF_IRQ_PORT_HOST),
-                               LPAIF_IRQ_XRUN(LPAIF_RDMA_CHAN_MI2S));
+                               LPAIF_IRQCLEAR_REG(v, LPAIF_IRQ_PORT_HOST),
+                               LPAIF_IRQ_XRUN(chan));
                if (rv) {
                        dev_err(soc_runtime->dev, "%s() error writing to irqclear reg: %d\n",
                                        __func__, rv);
@@ -393,10 +393,10 @@ static irqreturn_t lpass_platform_lpaif_irq(int irq, void *data)
                ret = IRQ_HANDLED;
        }
 
-       if (interrupts & LPAIF_IRQ_ERR(LPAIF_RDMA_CHAN_MI2S)) {
+       if (interrupts & LPAIF_IRQ_ERR(chan)) {
                rv = regmap_write(drvdata->lpaif_map,
-                               LPAIF_IRQCLEAR_REG(LPAIF_IRQ_PORT_HOST),
-                               LPAIF_IRQ_ERR(LPAIF_RDMA_CHAN_MI2S));
+                               LPAIF_IRQCLEAR_REG(v, LPAIF_IRQ_PORT_HOST),
+                               LPAIF_IRQ_ERR(chan));
                if (rv) {
                        dev_err(soc_runtime->dev, "%s() error writing to irqclear reg: %d\n",
                                        __func__, rv);
@@ -410,6 +410,35 @@ static irqreturn_t lpass_platform_lpaif_irq(int irq, void *data)
        return ret;
 }
 
+static irqreturn_t lpass_platform_lpaif_irq(int irq, void *data)
+{
+       struct lpass_data *drvdata = data;
+       struct lpass_variant *v = drvdata->variant;
+       unsigned int irqs;
+       int rv, chan;
+
+       rv = regmap_read(drvdata->lpaif_map,
+                       LPAIF_IRQSTAT_REG(v, LPAIF_IRQ_PORT_HOST), &irqs);
+       if (rv) {
+               pr_err("%s() error reading from irqstat reg: %d\n",
+                               __func__, rv);
+               return IRQ_NONE;
+       }
+
+       /* Handle per channel interrupts */
+       for (chan = 0; chan < LPASS_MAX_DMA_CHANNELS; chan++) {
+               if (irqs & LPAIF_IRQ_ALL(chan) && drvdata->substream[chan]) {
+                       rv = lpass_dma_interrupt_handler(
+                                               drvdata->substream[chan],
+                                               drvdata, chan, irqs);
+                       if (rv != IRQ_HANDLED)
+                               return rv;
+               }
+       }
+
+       return IRQ_HANDLED;
+}
+
 static int lpass_platform_alloc_buffer(struct snd_pcm_substream *substream,
                struct snd_soc_pcm_runtime *soc_runtime)
 {
@@ -448,9 +477,27 @@ static int lpass_platform_pcm_new(struct snd_soc_pcm_runtime *soc_runtime)
        struct snd_pcm *pcm = soc_runtime->pcm;
        struct snd_pcm_substream *substream =
                pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream;
+       struct snd_soc_dai *cpu_dai = soc_runtime->cpu_dai;
        struct lpass_data *drvdata =
                snd_soc_platform_get_drvdata(soc_runtime->platform);
+       struct lpass_variant *v = drvdata->variant;
        int ret;
+       struct lpass_pcm_data *data;
+
+       data = devm_kzalloc(soc_runtime->dev, sizeof(*data), GFP_KERNEL);
+       if (!data)
+               return -ENOMEM;
+
+       if (v->alloc_dma_channel)
+               data->rdma_ch = v->alloc_dma_channel(drvdata);
+
+       if (IS_ERR_VALUE(data->rdma_ch))
+               return data->rdma_ch;
+
+       drvdata->substream[data->rdma_ch] = substream;
+       data->i2s_port = cpu_dai->driver->id;
+
+       snd_soc_pcm_set_drvdata(soc_runtime, data);
 
        soc_runtime->dev->coherent_dma_mask = DMA_BIT_MASK(32);
        soc_runtime->dev->dma_mask = &soc_runtime->dev->coherent_dma_mask;
@@ -459,29 +506,12 @@ static int lpass_platform_pcm_new(struct snd_soc_pcm_runtime *soc_runtime)
        if (ret)
                return ret;
 
-       ret = devm_request_irq(soc_runtime->dev, drvdata->lpaif_irq,
-                       lpass_platform_lpaif_irq, IRQF_TRIGGER_RISING,
-                       "lpass-irq-lpaif", substream);
-       if (ret) {
-               dev_err(soc_runtime->dev, "%s() irq request failed: %d\n",
-                               __func__, ret);
-               goto err_buf;
-       }
-
-       /* ensure audio hardware is disabled */
        ret = regmap_write(drvdata->lpaif_map,
-                       LPAIF_IRQEN_REG(LPAIF_IRQ_PORT_HOST), 0);
-       if (ret) {
-               dev_err(soc_runtime->dev, "%s() error writing to irqen reg: %d\n",
-                               __func__, ret);
-               return ret;
-       }
-       ret = regmap_write(drvdata->lpaif_map,
-                       LPAIF_RDMACTL_REG(LPAIF_RDMA_CHAN_MI2S), 0);
+                       LPAIF_RDMACTL_REG(v, data->rdma_ch), 0);
        if (ret) {
                dev_err(soc_runtime->dev, "%s() error writing to rdmactl reg: %d\n",
                                __func__, ret);
-               return ret;
+               goto err_buf;
        }
 
        return 0;
@@ -496,6 +526,15 @@ static void lpass_platform_pcm_free(struct snd_pcm *pcm)
        struct snd_pcm_substream *substream =
                pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream;
        struct snd_soc_pcm_runtime *soc_runtime = substream->private_data;
+       struct lpass_data *drvdata =
+               snd_soc_platform_get_drvdata(soc_runtime->platform);
+       struct lpass_pcm_data *data = snd_soc_pcm_get_drvdata(soc_runtime);
+       struct lpass_variant *v = drvdata->variant;
+
+       drvdata->substream[data->rdma_ch] = NULL;
+
+       if (v->free_dma_channel)
+               v->free_dma_channel(drvdata, data->rdma_ch);
 
        lpass_platform_free_buffer(substream, soc_runtime);
 }
@@ -509,6 +548,8 @@ static struct snd_soc_platform_driver lpass_platform_driver = {
 int asoc_qcom_lpass_platform_register(struct platform_device *pdev)
 {
        struct lpass_data *drvdata = platform_get_drvdata(pdev);
+       struct lpass_variant *v = drvdata->variant;
+       int ret;
 
        drvdata->lpaif_irq = platform_get_irq_byname(pdev, "lpass-irq-lpaif");
        if (drvdata->lpaif_irq < 0) {
@@ -517,6 +558,25 @@ int asoc_qcom_lpass_platform_register(struct platform_device *pdev)
                return -ENODEV;
        }
 
+       /* ensure audio hardware is disabled */
+       ret = regmap_write(drvdata->lpaif_map,
+                       LPAIF_IRQEN_REG(v, LPAIF_IRQ_PORT_HOST), 0);
+       if (ret) {
+               dev_err(&pdev->dev, "%s() error writing to irqen reg: %d\n",
+                               __func__, ret);
+               return ret;
+       }
+
+       ret = devm_request_irq(&pdev->dev, drvdata->lpaif_irq,
+                       lpass_platform_lpaif_irq, IRQF_TRIGGER_RISING,
+                       "lpass-irq-lpaif", drvdata);
+       if (ret) {
+               dev_err(&pdev->dev, "%s() irq request failed: %d\n",
+                               __func__, ret);
+               return ret;
+       }
+
+
        return devm_snd_soc_register_platform(&pdev->dev,
                        &lpass_platform_driver);
 }
index 5c99b3dace86d3634b0dbc8c070ac7711d070890..d6e86c119e74909822c8e6cccd218b318f2858c2 100644 (file)
@@ -22,6 +22,8 @@
 #include <linux/regmap.h>
 
 #define LPASS_AHBIX_CLOCK_FREQUENCY            131072000
+#define LPASS_MAX_MI2S_PORTS                   (8)
+#define LPASS_MAX_DMA_CHANNELS                 (8)
 
 /* Both the CPU DAI and platform drivers will access this data */
 struct lpass_data {
@@ -30,10 +32,10 @@ struct lpass_data {
        struct clk *ahbix_clk;
 
        /* MI2S system clock */
-       struct clk *mi2s_osr_clk;
+       struct clk *mi2s_osr_clk[LPASS_MAX_MI2S_PORTS];
 
        /* MI2S bit clock (derived from system clock by a divider */
-       struct clk *mi2s_bit_clk;
+       struct clk *mi2s_bit_clk[LPASS_MAX_MI2S_PORTS];
 
        /* low-power audio interface (LPAIF) registers */
        void __iomem *lpaif;
@@ -43,9 +45,54 @@ struct lpass_data {
 
        /* interrupts from the low-power audio interface (LPAIF) */
        int lpaif_irq;
+
+       /* SOC specific variations in the LPASS IP integration */
+       struct lpass_variant *variant;
+
+       /* bit map to keep track of static channel allocations */
+       unsigned long rdma_ch_bit_map;
+
+       /* used it for handling interrupt per dma channel */
+       struct snd_pcm_substream *substream[LPASS_MAX_DMA_CHANNELS];
+
+       /* 8016 specific */
+       struct clk *pcnoc_mport_clk;
+       struct clk *pcnoc_sway_clk;
+};
+
+/* Vairant data per each SOC */
+struct lpass_variant {
+       u32     i2sctrl_reg_base;
+       u32     i2sctrl_reg_stride;
+       u32     i2s_ports;
+       u32     irq_reg_base;
+       u32     irq_reg_stride;
+       u32     irq_ports;
+       u32     rdma_reg_base;
+       u32     rdma_reg_stride;
+       u32     rdma_channels;
+
+       /**
+        * on SOCs like APQ8016 the channel control bits start
+        * at different offset to ipq806x
+        **/
+       u32     rdmactl_audif_start;
+       /* SOC specific intialization like clocks */
+       int (*init)(struct platform_device *pdev);
+       int (*exit)(struct platform_device *pdev);
+       int (*alloc_dma_channel)(struct lpass_data *data);
+       int (*free_dma_channel)(struct lpass_data *data, int ch);
+
+       /* SOC specific dais */
+       struct snd_soc_dai_driver *dai_driver;
+       int num_dai;
 };
 
 /* register the platform driver from the CPU DAI driver */
 int asoc_qcom_lpass_platform_register(struct platform_device *);
+int asoc_qcom_lpass_cpu_platform_remove(struct platform_device *pdev);
+int asoc_qcom_lpass_cpu_platform_probe(struct platform_device *pdev);
+int asoc_qcom_lpass_cpu_dai_probe(struct snd_soc_dai *dai);
+extern struct snd_soc_dai_ops asoc_qcom_lpass_cpu_dai_ops;
 
 #endif /* __LPASS_H__ */
index b8bd296190add83ba332d42256096c1376d2632d..2d833bffdba0340142f4fb3bc63da9851df90ff3 100644 (file)
@@ -69,11 +69,6 @@ static struct snd_soc_dai_link storm_dai_link = {
        .ops            = &storm_soc_ops,
 };
 
-static struct snd_soc_card storm_soc_card = {
-       .name   = "ipq806x-storm",
-       .dev    = NULL,
-};
-
 static int storm_parse_of(struct snd_soc_card *card)
 {
        struct snd_soc_dai_link *dai_link = card->dai_link;
@@ -99,14 +94,13 @@ static int storm_parse_of(struct snd_soc_card *card)
 
 static int storm_platform_probe(struct platform_device *pdev)
 {
-       struct snd_soc_card *card = &storm_soc_card;
+       struct snd_soc_card *card;
        int ret;
 
-       if (card->dev) {
-               dev_err(&pdev->dev, "%s() error, existing soundcard\n",
-                               __func__);
-               return -ENODEV;
-       }
+       card = devm_kzalloc(&pdev->dev, sizeof(*card), GFP_KERNEL);
+       if (!card)
+               return -ENOMEM;
+
        card->dev = &pdev->dev;
        platform_set_drvdata(pdev, card);
 
@@ -128,16 +122,12 @@ static int storm_platform_probe(struct platform_device *pdev)
        }
 
        ret = devm_snd_soc_register_card(&pdev->dev, card);
-       if (ret == -EPROBE_DEFER) {
-               card->dev = NULL;
-               return ret;
-       } else if (ret) {
+       if (ret)
                dev_err(&pdev->dev, "%s() error registering soundcard: %d\n",
                                __func__, ret);
-               return ret;
-       }
 
-       return 0;
+       return ret;
+
 }
 
 #ifdef CONFIG_OF
index 0632a36852c8476416f8fcb78d625abb98d658cf..3744c9ed537041f6c14c005bd71977d51d4cc375 100644 (file)
@@ -174,7 +174,8 @@ config SND_SOC_SMDK_WM8994_PCM
 
 config SND_SOC_SPEYSIDE
        tristate "Audio support for Wolfson Speyside"
-       depends on SND_SOC_SAMSUNG && MACH_WLF_CRAGG_6410 && I2C && SPI_MASTER
+       depends on SND_SOC_SAMSUNG && I2C && SPI_MASTER
+       depends on MACH_WLF_CRAGG_6410 || COMPILE_TEST
        select SND_SAMSUNG_I2S
        select SND_SOC_WM8996
        select SND_SOC_WM9081
@@ -183,13 +184,15 @@ config SND_SOC_SPEYSIDE
 
 config SND_SOC_TOBERMORY
        tristate "Audio support for Wolfson Tobermory"
-       depends on SND_SOC_SAMSUNG && MACH_WLF_CRAGG_6410 && INPUT && I2C
+       depends on SND_SOC_SAMSUNG && INPUT && I2C
+       depends on MACH_WLF_CRAGG_6410 || COMPILE_TEST
        select SND_SAMSUNG_I2S
        select SND_SOC_WM8962
 
 config SND_SOC_BELLS
        tristate "Audio support for Wolfson Bells"
-       depends on SND_SOC_SAMSUNG && MACH_WLF_CRAGG_6410 && MFD_ARIZONA && I2C && SPI_MASTER
+       depends on SND_SOC_SAMSUNG && MFD_ARIZONA && I2C && SPI_MASTER
+       depends on MACH_WLF_CRAGG_6410 || COMPILE_TEST
        select SND_SAMSUNG_I2S
        select SND_SOC_WM5102
        select SND_SOC_WM5110
@@ -199,14 +202,16 @@ config SND_SOC_BELLS
 
 config SND_SOC_LOWLAND
        tristate "Audio support for Wolfson Lowland"
-       depends on SND_SOC_SAMSUNG && MACH_WLF_CRAGG_6410 && I2C
+       depends on SND_SOC_SAMSUNG && I2C
+       depends on MACH_WLF_CRAGG_6410 || COMPILE_TEST
        select SND_SAMSUNG_I2S
        select SND_SOC_WM5100
        select SND_SOC_WM9081
 
 config SND_SOC_LITTLEMILL
        tristate "Audio support for Wolfson Littlemill"
-       depends on SND_SOC_SAMSUNG && MACH_WLF_CRAGG_6410 && I2C
+       depends on SND_SOC_SAMSUNG && I2C
+       depends on MACH_WLF_CRAGG_6410 || COMPILE_TEST
        select SND_SAMSUNG_I2S
        select MFD_WM8994
        select SND_SOC_WM8994
index b92ab40d2be6ebf46b67bc355c6d75da1a065692..ea4ab374a2231d8a79799e821a90b6a759c2291e 100644 (file)
@@ -1493,7 +1493,7 @@ static const struct samsung_i2s_dai_data samsung_dai_type_sec = {
        .dai_type = TYPE_SEC,
 };
 
-static struct platform_device_id samsung_i2s_driver_ids[] = {
+static const struct platform_device_id samsung_i2s_driver_ids[] = {
        {
                .name           = "samsung-i2s",
                .driver_data    = (kernel_ulong_t)&i2sv3_dai_type,
index 5f156093101e3ab2df8290841a656ab062ccd5af..0d0f58208b756f0e89c9f3cdcd6179760c244209 100644 (file)
@@ -72,7 +72,7 @@ static int lowland_wm9081_init(struct snd_soc_pcm_runtime *rtd)
 {
        struct snd_soc_codec *codec = rtd->codec;
 
-       snd_soc_dapm_nc_pin(&codec->dapm, "LINEOUT");
+       snd_soc_dapm_nc_pin(&rtd->card->dapm, "LINEOUT");
 
        /* At any time the WM9081 is active it will have this clock */
        return snd_soc_codec_set_sysclk(codec, WM9081_SYSCLK_MCLK, 0,
index 326d3c3804e34bccf1069e61df0bb12d5a8bf042..5bf723689692fc52ffc5edce20f82e8d5cb4fc21 100644 (file)
@@ -461,8 +461,8 @@ static int s3c24xx_iis_dev_probe(struct platform_device *pdev)
                return -ENOENT;
        }
        s3c24xx_i2s.regs = devm_ioremap_resource(&pdev->dev, res);
-       if (s3c24xx_i2s.regs == NULL)
-               return -ENXIO;
+       if (IS_ERR(s3c24xx_i2s.regs))
+               return PTR_ERR(s3c24xx_i2s.regs);
 
        s3c24xx_i2s_pcm_stereo_out.dma_addr = res->start + S3C2410_IISFIFO;
        s3c24xx_i2s_pcm_stereo_in.dma_addr = res->start + S3C2410_IISFIFO;
index dfbe2db1c4078da9de1d82d58d95573866cfe73e..a0fe37fbed9fb8485fd8ab8f103f9d230329950f 100644 (file)
@@ -137,8 +137,7 @@ static const struct snd_soc_dapm_route audio_map[] = {
 
 static int smartq_wm8987_init(struct snd_soc_pcm_runtime *rtd)
 {
-       struct snd_soc_codec *codec = rtd->codec;
-       struct snd_soc_dapm_context *dapm = &codec->dapm;
+       struct snd_soc_dapm_context *dapm = &rtd->card->dapm;
        int err = 0;
 
        /* set endpoints to not connected */
@@ -147,9 +146,6 @@ static int smartq_wm8987_init(struct snd_soc_pcm_runtime *rtd)
        snd_soc_dapm_nc_pin(dapm, "OUT3");
        snd_soc_dapm_nc_pin(dapm, "ROUT1");
 
-       /* set endpoints to default off mode */
-       snd_soc_dapm_disable_pin(dapm, "Headphone Jack");
-
        /* Headphone jack detection */
        err = snd_soc_card_jack_new(rtd->card, "Headphone Jack",
                                    SND_JACK_HEADPHONE, &smartq_jack,
index d38595fbdab7a4ecce2fbfbf1248b8e47a8c5d09..ff57b192d37d420fdc34b5d109579ab0672e27b3 100644 (file)
@@ -86,8 +86,7 @@ static struct snd_soc_ops smdk_ops = {
 
 static int smdk_wm8994_init_paiftx(struct snd_soc_pcm_runtime *rtd)
 {
-       struct snd_soc_codec *codec = rtd->codec;
-       struct snd_soc_dapm_context *dapm = &codec->dapm;
+       struct snd_soc_dapm_context *dapm = &rtd->card->dapm;
 
        /* Other pins NC */
        snd_soc_dapm_nc_pin(dapm, "HPOUT2P");
index 2dcb988bdff21272ffed15c7073e7f4643bee70f..d1ae21c5e25320e525a8431639e811e47c264a4e 100644 (file)
@@ -123,7 +123,7 @@ static void speyside_set_polarity(struct snd_soc_codec *codec,
        gpio_direction_output(WM8996_HPSEL_GPIO, speyside_jack_polarity);
 
        /* Re-run DAPM to make sure we're using the correct mic bias */
-       snd_soc_dapm_sync(&codec->dapm);
+       snd_soc_dapm_sync(snd_soc_codec_get_dapm(codec));
 }
 
 static int speyside_wm0010_init(struct snd_soc_pcm_runtime *rtd)
index 9f48d75fa992351adffef3d834620e7d2682354e..f1e5920654f6ff74803b770ef31d66579fd9b8df 100644 (file)
@@ -137,15 +137,17 @@ char *rsnd_mod_name(struct rsnd_mod *mod)
        return mod->ops->name;
 }
 
-struct dma_chan *rsnd_mod_dma_req(struct rsnd_mod *mod)
+struct dma_chan *rsnd_mod_dma_req(struct rsnd_dai_stream *io,
+                                 struct rsnd_mod *mod)
 {
        if (!mod || !mod->ops || !mod->ops->dma_req)
                return NULL;
 
-       return mod->ops->dma_req(mod);
+       return mod->ops->dma_req(io, mod);
 }
 
-int rsnd_mod_init(struct rsnd_mod *mod,
+int rsnd_mod_init(struct rsnd_priv *priv,
+                 struct rsnd_mod *mod,
                   struct rsnd_mod_ops *ops,
                   struct clk *clk,
                   enum rsnd_mod_type type,
@@ -160,6 +162,7 @@ int rsnd_mod_init(struct rsnd_mod *mod,
        mod->ops        = ops;
        mod->type       = type;
        mod->clk        = clk;
+       mod->priv       = priv;
 
        return ret;
 }
@@ -170,13 +173,41 @@ void rsnd_mod_quit(struct rsnd_mod *mod)
                clk_unprepare(mod->clk);
 }
 
+void rsnd_mod_interrupt(struct rsnd_mod *mod,
+                       void (*callback)(struct rsnd_mod *mod,
+                                        struct rsnd_dai_stream *io))
+{
+       struct rsnd_priv *priv = rsnd_mod_to_priv(mod);
+       struct rsnd_dai_stream *io;
+       struct rsnd_dai *rdai;
+       int i, j;
+
+       for_each_rsnd_dai(rdai, priv, j) {
+
+               for (i = 0; i < RSND_MOD_MAX; i++) {
+                       io = &rdai->playback;
+                       if (mod == io->mod[i])
+                               callback(mod, io);
+
+                       io = &rdai->capture;
+                       if (mod == io->mod[i])
+                               callback(mod, io);
+               }
+       }
+}
+
+int rsnd_io_is_working(struct rsnd_dai_stream *io)
+{
+       /* see rsnd_dai_stream_init/quit() */
+       return !!io->substream;
+}
+
 /*
  *     settting function
  */
-u32 rsnd_get_adinr(struct rsnd_mod *mod)
+u32 rsnd_get_adinr(struct rsnd_mod *mod, struct rsnd_dai_stream *io)
 {
        struct rsnd_priv *priv = rsnd_mod_to_priv(mod);
-       struct rsnd_dai_stream *io = rsnd_mod_to_io(mod);
        struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io);
        struct device *dev = rsnd_priv_to_dev(priv);
        u32 adinr = runtime->channels;
@@ -199,26 +230,31 @@ u32 rsnd_get_adinr(struct rsnd_mod *mod)
 /*
  *     rsnd_dai functions
  */
-#define __rsnd_mod_call(mod, func, param...)                   \
+#define __rsnd_mod_call(mod, io, func, param...)               \
 ({                                                             \
        struct rsnd_priv *priv = rsnd_mod_to_priv(mod);         \
        struct device *dev = rsnd_priv_to_dev(priv);            \
-       u32 mask = (1 << __rsnd_mod_shift_##func) & ~(1 << 31); \
-       u32 call = __rsnd_mod_call_##func << __rsnd_mod_shift_##func;   \
+       u32 mask = 0xF << __rsnd_mod_shift_##func;                      \
+       u8 val  = (mod->status >> __rsnd_mod_shift_##func) & 0xF;       \
+       u8 add  = ((val + __rsnd_mod_add_##func) & 0xF);                \
        int ret = 0;                                                    \
-       if ((mod->status & mask) == call) {                             \
-               dev_dbg(dev, "%s[%d] %s\n",                             \
-                       rsnd_mod_name(mod), rsnd_mod_id(mod), #func);   \
-               ret = (mod)->ops->func(mod, param);                     \
-               mod->status = (mod->status & ~mask) | (~call & mask);   \
+       int called = 0;                                                 \
+       if (val == __rsnd_mod_call_##func) {                            \
+               called = 1;                                             \
+               ret = (mod)->ops->func(mod, io, param);                 \
+               mod->status = (mod->status & ~mask) +                   \
+                       (add << __rsnd_mod_shift_##func);               \
        }                                                               \
+       dev_dbg(dev, "%s[%d] 0x%08x %s\n",                              \
+               rsnd_mod_name(mod), rsnd_mod_id(mod), mod->status,      \
+               called ? #func : "");                                   \
        ret;                                                            \
 })
 
-#define rsnd_mod_call(mod, func, param...)     \
+#define rsnd_mod_call(mod, io, func, param...) \
        (!(mod) ? -ENODEV :                     \
         !((mod)->ops->func) ? 0 :              \
-        __rsnd_mod_call(mod, func, param))
+        __rsnd_mod_call(mod, io, func, param))
 
 #define rsnd_dai_call(fn, io, param...)                                \
 ({                                                             \
@@ -228,7 +264,7 @@ u32 rsnd_get_adinr(struct rsnd_mod *mod)
                mod = (io)->mod[i];                             \
                if (!mod)                                       \
                        continue;                               \
-               ret = rsnd_mod_call(mod, fn, param);            \
+               ret = rsnd_mod_call(mod, io, fn, param);        \
                if (ret < 0)                                    \
                        break;                                  \
        }                                                       \
@@ -252,7 +288,6 @@ static int rsnd_dai_connect(struct rsnd_mod *mod,
        }
 
        io->mod[mod->type] = mod;
-       mod->io = io;
 
        return 0;
 }
@@ -260,7 +295,6 @@ static int rsnd_dai_connect(struct rsnd_mod *mod,
 static void rsnd_dai_disconnect(struct rsnd_mod *mod,
                                struct rsnd_dai_stream *io)
 {
-       mod->io = NULL;
        io->mod[mod->type] = NULL;
 }
 
@@ -272,9 +306,10 @@ struct rsnd_dai *rsnd_rdai_get(struct rsnd_priv *priv, int id)
        return priv->rdai + id;
 }
 
+#define rsnd_dai_to_priv(dai) snd_soc_dai_get_drvdata(dai)
 static struct rsnd_dai *rsnd_dai_to_rdai(struct snd_soc_dai *dai)
 {
-       struct rsnd_priv *priv = snd_soc_dai_get_drvdata(dai);
+       struct rsnd_priv *priv = rsnd_dai_to_priv(dai);
 
        return rsnd_rdai_get(priv, dai->id);
 }
@@ -293,7 +328,7 @@ int rsnd_dai_pointer_offset(struct rsnd_dai_stream *io, int additional)
        return pos;
 }
 
-void rsnd_dai_pointer_update(struct rsnd_dai_stream *io, int byte)
+bool rsnd_dai_pointer_update(struct rsnd_dai_stream *io, int byte)
 {
        io->byte_pos += byte;
 
@@ -310,11 +345,27 @@ void rsnd_dai_pointer_update(struct rsnd_dai_stream *io, int byte)
                        io->next_period_byte = io->byte_per_period;
                }
 
-               snd_pcm_period_elapsed(substream);
+               return true;
        }
+
+       return false;
 }
 
-static int rsnd_dai_stream_init(struct rsnd_dai_stream *io,
+void rsnd_dai_period_elapsed(struct rsnd_dai_stream *io)
+{
+       struct snd_pcm_substream *substream = io->substream;
+
+       /*
+        * this function should be called...
+        *
+        * - if rsnd_dai_pointer_update() returns true
+        * - without spin lock
+        */
+
+       snd_pcm_period_elapsed(substream);
+}
+
+static void rsnd_dai_stream_init(struct rsnd_dai_stream *io,
                                struct snd_pcm_substream *substream)
 {
        struct snd_pcm_runtime *runtime = substream->runtime;
@@ -326,8 +377,11 @@ static int rsnd_dai_stream_init(struct rsnd_dai_stream *io,
                                  runtime->channels *
                                  samples_to_bytes(runtime, 1);
        io->next_period_byte    = io->byte_per_period;
+}
 
-       return 0;
+static void rsnd_dai_stream_quit(struct rsnd_dai_stream *io)
+{
+       io->substream           = NULL;
 }
 
 static
@@ -351,20 +405,18 @@ struct rsnd_dai_stream *rsnd_rdai_to_io(struct rsnd_dai *rdai,
 static int rsnd_soc_dai_trigger(struct snd_pcm_substream *substream, int cmd,
                            struct snd_soc_dai *dai)
 {
-       struct rsnd_priv *priv = snd_soc_dai_get_drvdata(dai);
+       struct rsnd_priv *priv = rsnd_dai_to_priv(dai);
        struct rsnd_dai *rdai = rsnd_dai_to_rdai(dai);
        struct rsnd_dai_stream *io = rsnd_rdai_to_io(rdai, substream);
        int ssi_id = rsnd_mod_id(rsnd_io_to_mod_ssi(io));
        int ret;
        unsigned long flags;
 
-       rsnd_lock(priv, flags);
+       spin_lock_irqsave(&priv->lock, flags);
 
        switch (cmd) {
        case SNDRV_PCM_TRIGGER_START:
-               ret = rsnd_dai_stream_init(io, substream);
-               if (ret < 0)
-                       goto dai_trigger_end;
+               rsnd_dai_stream_init(io, substream);
 
                ret = rsnd_platform_call(priv, dai, start, ssi_id);
                if (ret < 0)
@@ -390,13 +442,15 @@ static int rsnd_soc_dai_trigger(struct snd_pcm_substream *substream, int cmd,
                ret = rsnd_platform_call(priv, dai, stop, ssi_id);
                if (ret < 0)
                        goto dai_trigger_end;
+
+               rsnd_dai_stream_quit(io);
                break;
        default:
                ret = -EINVAL;
        }
 
 dai_trigger_end:
-       rsnd_unlock(priv, flags);
+       spin_unlock_irqrestore(&priv->lock, flags);
 
        return ret;
 }
@@ -822,23 +876,27 @@ static int rsnd_kctrl_put(struct snd_kcontrol *kctrl,
        }
 
        if (change)
-               cfg->update(mod);
+               cfg->update(cfg->io, mod);
 
        return change;
 }
 
 static int __rsnd_kctrl_new(struct rsnd_mod *mod,
+                           struct rsnd_dai_stream *io,
                            struct snd_soc_pcm_runtime *rtd,
                            const unsigned char *name,
                            struct rsnd_kctrl_cfg *cfg,
-                           void (*update)(struct rsnd_mod *mod))
+                           void (*update)(struct rsnd_dai_stream *io,
+                                          struct rsnd_mod *mod))
 {
+       struct snd_soc_card *soc_card = rtd->card;
        struct snd_card *card = rtd->card->snd_card;
        struct snd_kcontrol *kctrl;
        struct snd_kcontrol_new knew = {
                .iface          = SNDRV_CTL_ELEM_IFACE_MIXER,
                .name           = name,
                .info           = rsnd_kctrl_info,
+               .index          = rtd - soc_card->rtd,
                .get            = rsnd_kctrl_get,
                .put            = rsnd_kctrl_put,
                .private_value  = (unsigned long)cfg,
@@ -858,6 +916,7 @@ static int __rsnd_kctrl_new(struct rsnd_mod *mod,
        cfg->update = update;
        cfg->card = card;
        cfg->kctrl = kctrl;
+       cfg->io = io;
 
        return 0;
 }
@@ -868,36 +927,42 @@ void _rsnd_kctrl_remove(struct rsnd_kctrl_cfg *cfg)
 }
 
 int rsnd_kctrl_new_m(struct rsnd_mod *mod,
+                    struct rsnd_dai_stream *io,
                     struct snd_soc_pcm_runtime *rtd,
                     const unsigned char *name,
-                    void (*update)(struct rsnd_mod *mod),
+                    void (*update)(struct rsnd_dai_stream *io,
+                                   struct rsnd_mod *mod),
                     struct rsnd_kctrl_cfg_m *_cfg,
                     u32 max)
 {
        _cfg->cfg.max   = max;
        _cfg->cfg.size  = RSND_DVC_CHANNELS;
        _cfg->cfg.val   = _cfg->val;
-       return __rsnd_kctrl_new(mod, rtd, name, &_cfg->cfg, update);
+       return __rsnd_kctrl_new(mod, io, rtd, name, &_cfg->cfg, update);
 }
 
 int rsnd_kctrl_new_s(struct rsnd_mod *mod,
+                    struct rsnd_dai_stream *io,
                     struct snd_soc_pcm_runtime *rtd,
                     const unsigned char *name,
-                    void (*update)(struct rsnd_mod *mod),
+                    void (*update)(struct rsnd_dai_stream *io,
+                                   struct rsnd_mod *mod),
                     struct rsnd_kctrl_cfg_s *_cfg,
                     u32 max)
 {
        _cfg->cfg.max   = max;
        _cfg->cfg.size  = 1;
        _cfg->cfg.val   = &_cfg->val;
-       return __rsnd_kctrl_new(mod, rtd, name, &_cfg->cfg, update);
+       return __rsnd_kctrl_new(mod, io, rtd, name, &_cfg->cfg, update);
 }
 
 int rsnd_kctrl_new_e(struct rsnd_mod *mod,
+                    struct rsnd_dai_stream *io,
                     struct snd_soc_pcm_runtime *rtd,
                     const unsigned char *name,
                     struct rsnd_kctrl_cfg_s *_cfg,
-                    void (*update)(struct rsnd_mod *mod),
+                    void (*update)(struct rsnd_dai_stream *io,
+                                   struct rsnd_mod *mod),
                     const char * const *texts,
                     u32 max)
 {
@@ -905,7 +970,7 @@ int rsnd_kctrl_new_e(struct rsnd_mod *mod,
        _cfg->cfg.size  = 1;
        _cfg->cfg.val   = &_cfg->val;
        _cfg->cfg.texts = texts;
-       return __rsnd_kctrl_new(mod, rtd, name, &_cfg->cfg, update);
+       return __rsnd_kctrl_new(mod, io, rtd, name, &_cfg->cfg, update);
 }
 
 /*
index ac3756f6af603e9a21fe79988b00d13477da6fab..d306e298c63dce269ec3b790a8ac225516181d1f 100644 (file)
@@ -32,11 +32,12 @@ struct rsnd_dma_ctrl {
 /*
  *             Audio DMAC
  */
-static void rsnd_dmaen_complete(void *data)
+static void __rsnd_dmaen_complete(struct rsnd_mod *mod,
+                                 struct rsnd_dai_stream *io)
 {
-       struct rsnd_dma *dma = (struct rsnd_dma *)data;
-       struct rsnd_mod *mod = rsnd_dma_to_mod(dma);
-       struct rsnd_dai_stream *io = rsnd_mod_to_io(mod);
+       struct rsnd_priv *priv = rsnd_mod_to_priv(mod);
+       bool elapsed = false;
+       unsigned long flags;
 
        /*
         * Renesas sound Gen1 needs 1 DMAC,
@@ -49,23 +50,36 @@ static void rsnd_dmaen_complete(void *data)
         * rsnd_dai_pointer_update() will be called twice,
         * ant it will breaks io->byte_pos
         */
+       spin_lock_irqsave(&priv->lock, flags);
+
+       if (rsnd_io_is_working(io))
+               elapsed = rsnd_dai_pointer_update(io, io->byte_per_period);
 
-       rsnd_dai_pointer_update(io, io->byte_per_period);
+       spin_unlock_irqrestore(&priv->lock, flags);
+
+       if (elapsed)
+               rsnd_dai_period_elapsed(io);
 }
 
-static void rsnd_dmaen_stop(struct rsnd_dma *dma)
+static void rsnd_dmaen_complete(void *data)
+{
+       struct rsnd_mod *mod = data;
+
+       rsnd_mod_interrupt(mod, __rsnd_dmaen_complete);
+}
+
+static void rsnd_dmaen_stop(struct rsnd_dai_stream *io, struct rsnd_dma *dma)
 {
        struct rsnd_dmaen *dmaen = rsnd_dma_to_dmaen(dma);
 
        dmaengine_terminate_all(dmaen->chan);
 }
 
-static void rsnd_dmaen_start(struct rsnd_dma *dma)
+static void rsnd_dmaen_start(struct rsnd_dai_stream *io, struct rsnd_dma *dma)
 {
        struct rsnd_dmaen *dmaen = rsnd_dma_to_dmaen(dma);
        struct rsnd_mod *mod = rsnd_dma_to_mod(dma);
        struct rsnd_priv *priv = rsnd_mod_to_priv(mod);
-       struct rsnd_dai_stream *io = rsnd_mod_to_io(mod);
        struct snd_pcm_substream *substream = io->substream;
        struct device *dev = rsnd_priv_to_dev(priv);
        struct dma_async_tx_descriptor *desc;
@@ -84,7 +98,7 @@ static void rsnd_dmaen_start(struct rsnd_dma *dma)
        }
 
        desc->callback          = rsnd_dmaen_complete;
-       desc->callback_param    = dma;
+       desc->callback_param    = mod;
 
        if (dmaengine_submit(desc) < 0) {
                dev_err(dev, "dmaengine_submit() fail\n");
@@ -115,7 +129,8 @@ struct dma_chan *rsnd_dma_request_channel(struct device_node *of_node,
        return chan;
 }
 
-static struct dma_chan *rsnd_dmaen_request_channel(struct rsnd_mod *mod_from,
+static struct dma_chan *rsnd_dmaen_request_channel(struct rsnd_dai_stream *io,
+                                                  struct rsnd_mod *mod_from,
                                                   struct rsnd_mod *mod_to)
 {
        if ((!mod_from && !mod_to) ||
@@ -123,19 +138,19 @@ static struct dma_chan *rsnd_dmaen_request_channel(struct rsnd_mod *mod_from,
                return NULL;
 
        if (mod_from)
-               return rsnd_mod_dma_req(mod_from);
+               return rsnd_mod_dma_req(io, mod_from);
        else
-               return rsnd_mod_dma_req(mod_to);
+               return rsnd_mod_dma_req(io, mod_to);
 }
 
-static int rsnd_dmaen_init(struct rsnd_priv *priv, struct rsnd_dma *dma, int id,
+static int rsnd_dmaen_init(struct rsnd_dai_stream *io,
+                          struct rsnd_dma *dma, int id,
                           struct rsnd_mod *mod_from, struct rsnd_mod *mod_to)
 {
        struct rsnd_dmaen *dmaen = rsnd_dma_to_dmaen(dma);
+       struct rsnd_priv *priv = rsnd_io_to_priv(io);
        struct device *dev = rsnd_priv_to_dev(priv);
        struct dma_slave_config cfg = {};
-       struct rsnd_mod *mod = rsnd_dma_to_mod(dma);
-       struct rsnd_dai_stream *io = rsnd_mod_to_io(mod);
        int is_play = rsnd_io_is_play(io);
        int ret;
 
@@ -145,7 +160,7 @@ static int rsnd_dmaen_init(struct rsnd_priv *priv, struct rsnd_dma *dma, int id,
        }
 
        if (dev->of_node) {
-               dmaen->chan = rsnd_dmaen_request_channel(mod_from, mod_to);
+               dmaen->chan = rsnd_dmaen_request_channel(io, mod_from, mod_to);
        } else {
                dma_cap_mask_t mask;
 
@@ -156,6 +171,7 @@ static int rsnd_dmaen_init(struct rsnd_priv *priv, struct rsnd_dma *dma, int id,
                                                  (void *)id);
        }
        if (IS_ERR_OR_NULL(dmaen->chan)) {
+               dmaen->chan = NULL;
                dev_err(dev, "can't get dma channel\n");
                goto rsnd_dma_channel_err;
        }
@@ -176,7 +192,7 @@ static int rsnd_dmaen_init(struct rsnd_priv *priv, struct rsnd_dma *dma, int id,
        return 0;
 
 rsnd_dma_init_err:
-       rsnd_dma_quit(dma);
+       rsnd_dma_quit(io, dma);
 rsnd_dma_channel_err:
 
        /*
@@ -188,7 +204,7 @@ rsnd_dma_channel_err:
        return -EAGAIN;
 }
 
-static void rsnd_dmaen_quit(struct rsnd_dma *dma)
+static void rsnd_dmaen_quit(struct rsnd_dai_stream *io, struct rsnd_dma *dma)
 {
        struct rsnd_dmaen *dmaen = rsnd_dma_to_dmaen(dma);
 
@@ -237,9 +253,9 @@ static const u8 gen2_id_table_cmd[] = {
        0x38, /* SCU_CMD1 */
 };
 
-static u32 rsnd_dmapp_get_id(struct rsnd_mod *mod)
+static u32 rsnd_dmapp_get_id(struct rsnd_dai_stream *io,
+                            struct rsnd_mod *mod)
 {
-       struct rsnd_dai_stream *io = rsnd_mod_to_io(mod);
        struct rsnd_mod *ssi = rsnd_io_to_mod_ssi(io);
        struct rsnd_mod *src = rsnd_io_to_mod_src(io);
        struct rsnd_mod *dvc = rsnd_io_to_mod_dvc(io);
@@ -267,11 +283,12 @@ static u32 rsnd_dmapp_get_id(struct rsnd_mod *mod)
        return entry[id];
 }
 
-static u32 rsnd_dmapp_get_chcr(struct rsnd_mod *mod_from,
+static u32 rsnd_dmapp_get_chcr(struct rsnd_dai_stream *io,
+                              struct rsnd_mod *mod_from,
                               struct rsnd_mod *mod_to)
 {
-       return  (rsnd_dmapp_get_id(mod_from) << 24) +
-               (rsnd_dmapp_get_id(mod_to) << 16);
+       return  (rsnd_dmapp_get_id(io, mod_from) << 24) +
+               (rsnd_dmapp_get_id(io, mod_to) << 16);
 }
 
 #define rsnd_dmapp_addr(dmac, dma, reg) \
@@ -298,7 +315,7 @@ static u32 rsnd_dmapp_read(struct rsnd_dma *dma, u32 reg)
        return ioread32(rsnd_dmapp_addr(dmac, dma, reg));
 }
 
-static void rsnd_dmapp_stop(struct rsnd_dma *dma)
+static void rsnd_dmapp_stop(struct rsnd_dai_stream *io, struct rsnd_dma *dma)
 {
        int i;
 
@@ -311,7 +328,7 @@ static void rsnd_dmapp_stop(struct rsnd_dma *dma)
        }
 }
 
-static void rsnd_dmapp_start(struct rsnd_dma *dma)
+static void rsnd_dmapp_start(struct rsnd_dai_stream *io, struct rsnd_dma *dma)
 {
        struct rsnd_dmapp *dmapp = rsnd_dma_to_dmapp(dma);
 
@@ -320,19 +337,21 @@ static void rsnd_dmapp_start(struct rsnd_dma *dma)
        rsnd_dmapp_write(dma, dmapp->chcr,      PDMACHCR);
 }
 
-static int rsnd_dmapp_init(struct rsnd_priv *priv, struct rsnd_dma *dma, int id,
+static int rsnd_dmapp_init(struct rsnd_dai_stream *io,
+                          struct rsnd_dma *dma, int id,
                           struct rsnd_mod *mod_from, struct rsnd_mod *mod_to)
 {
        struct rsnd_dmapp *dmapp = rsnd_dma_to_dmapp(dma);
+       struct rsnd_priv *priv = rsnd_io_to_priv(io);
        struct rsnd_dma_ctrl *dmac = rsnd_priv_to_dmac(priv);
        struct device *dev = rsnd_priv_to_dev(priv);
 
        dmapp->dmapp_id = dmac->dmapp_num;
-       dmapp->chcr = rsnd_dmapp_get_chcr(mod_from, mod_to) | PDMACHCR_DE;
+       dmapp->chcr = rsnd_dmapp_get_chcr(io, mod_from, mod_to) | PDMACHCR_DE;
 
        dmac->dmapp_num++;
 
-       rsnd_dmapp_stop(dma);
+       rsnd_dmapp_stop(io, dma);
 
        dev_dbg(dev, "id/src/dst/chcr = %d/%pad/%pad/%08x\n",
                dmapp->dmapp_id, &dma->src_addr, &dma->dst_addr, dmapp->chcr);
@@ -385,12 +404,12 @@ static struct rsnd_dma_ops rsnd_dmapp_ops = {
 #define RDMA_CMD_O_P(addr, i)  (addr ##_reg - 0x001f8000 + (0x400 * i))
 
 static dma_addr_t
-rsnd_gen2_dma_addr(struct rsnd_priv *priv,
+rsnd_gen2_dma_addr(struct rsnd_dai_stream *io,
                   struct rsnd_mod *mod,
                   int is_play, int is_from)
 {
+       struct rsnd_priv *priv = rsnd_io_to_priv(io);
        struct device *dev = rsnd_priv_to_dev(priv);
-       struct rsnd_dai_stream *io = rsnd_mod_to_io(mod);
        phys_addr_t ssi_reg = rsnd_gen_get_phy_addr(priv, RSND_GEN2_SSI);
        phys_addr_t src_reg = rsnd_gen_get_phy_addr(priv, RSND_GEN2_SCU);
        int is_ssi = !!(rsnd_io_to_mod_ssi(io) == mod);
@@ -437,7 +456,7 @@ rsnd_gen2_dma_addr(struct rsnd_priv *priv,
                dev_err(dev, "DVC is selected without SRC\n");
 
        /* use SSIU or SSI ? */
-       if (is_ssi && rsnd_ssi_use_busif(mod))
+       if (is_ssi && rsnd_ssi_use_busif(io, mod))
                is_ssi++;
 
        return (is_from) ?
@@ -445,10 +464,12 @@ rsnd_gen2_dma_addr(struct rsnd_priv *priv,
                dma_addrs[is_ssi][is_play][use_src + use_dvc].in_addr;
 }
 
-static dma_addr_t rsnd_dma_addr(struct rsnd_priv *priv,
+static dma_addr_t rsnd_dma_addr(struct rsnd_dai_stream *io,
                                struct rsnd_mod *mod,
                                int is_play, int is_from)
 {
+       struct rsnd_priv *priv = rsnd_io_to_priv(io);
+
        /*
         * gen1 uses default DMA addr
         */
@@ -458,17 +479,17 @@ static dma_addr_t rsnd_dma_addr(struct rsnd_priv *priv,
        if (!mod)
                return 0;
 
-       return rsnd_gen2_dma_addr(priv, mod, is_play, is_from);
+       return rsnd_gen2_dma_addr(io, mod, is_play, is_from);
 }
 
 #define MOD_MAX 4 /* MEM/SSI/SRC/DVC */
 static void rsnd_dma_of_path(struct rsnd_dma *dma,
+                            struct rsnd_dai_stream *io,
                             int is_play,
                             struct rsnd_mod **mod_from,
                             struct rsnd_mod **mod_to)
 {
        struct rsnd_mod *this = rsnd_dma_to_mod(dma);
-       struct rsnd_dai_stream *io = rsnd_mod_to_io(this);
        struct rsnd_mod *ssi = rsnd_io_to_mod_ssi(io);
        struct rsnd_mod *src = rsnd_io_to_mod_src(io);
        struct rsnd_mod *dvc = rsnd_io_to_mod_dvc(io);
@@ -523,17 +544,17 @@ static void rsnd_dma_of_path(struct rsnd_dma *dma,
        }
 }
 
-void rsnd_dma_stop(struct rsnd_dma *dma)
+void rsnd_dma_stop(struct rsnd_dai_stream *io, struct rsnd_dma *dma)
 {
-       dma->ops->stop(dma);
+       dma->ops->stop(io, dma);
 }
 
-void rsnd_dma_start(struct rsnd_dma *dma)
+void rsnd_dma_start(struct rsnd_dai_stream *io, struct rsnd_dma *dma)
 {
-       dma->ops->start(dma);
+       dma->ops->start(io, dma);
 }
 
-void rsnd_dma_quit(struct rsnd_dma *dma)
+void rsnd_dma_quit(struct rsnd_dai_stream *io, struct rsnd_dma *dma)
 {
        struct rsnd_mod *mod = rsnd_dma_to_mod(dma);
        struct rsnd_priv *priv = rsnd_mod_to_priv(mod);
@@ -542,15 +563,14 @@ void rsnd_dma_quit(struct rsnd_dma *dma)
        if (!dmac)
                return;
 
-       dma->ops->quit(dma);
+       dma->ops->quit(io, dma);
 }
 
-int rsnd_dma_init(struct rsnd_priv *priv, struct rsnd_dma *dma, int id)
+int rsnd_dma_init(struct rsnd_dai_stream *io, struct rsnd_dma *dma, int id)
 {
-       struct rsnd_mod *mod = rsnd_dma_to_mod(dma);
        struct rsnd_mod *mod_from;
        struct rsnd_mod *mod_to;
-       struct rsnd_dai_stream *io = rsnd_mod_to_io(mod);
+       struct rsnd_priv *priv = rsnd_io_to_priv(io);
        struct rsnd_dma_ctrl *dmac = rsnd_priv_to_dmac(priv);
        int is_play = rsnd_io_is_play(io);
 
@@ -563,10 +583,10 @@ int rsnd_dma_init(struct rsnd_priv *priv, struct rsnd_dma *dma, int id)
        if (!dmac)
                return -EAGAIN;
 
-       rsnd_dma_of_path(dma, is_play, &mod_from, &mod_to);
+       rsnd_dma_of_path(dma, io, is_play, &mod_from, &mod_to);
 
-       dma->src_addr = rsnd_dma_addr(priv, mod_from, is_play, 1);
-       dma->dst_addr = rsnd_dma_addr(priv, mod_to,   is_play, 0);
+       dma->src_addr = rsnd_dma_addr(io, mod_from, is_play, 1);
+       dma->dst_addr = rsnd_dma_addr(io, mod_to,   is_play, 0);
 
        /* for Gen2 */
        if (mod_from && mod_to)
@@ -578,7 +598,7 @@ int rsnd_dma_init(struct rsnd_priv *priv, struct rsnd_dma *dma, int id)
        if (rsnd_is_gen1(priv))
                dma->ops = &rsnd_dmaen_ops;
 
-       return dma->ops->init(priv, dma, id, mod_from, mod_to);
+       return dma->ops->init(io, dma, id, mod_from, mod_to);
 }
 
 int rsnd_dma_probe(struct platform_device *pdev,
index e5fcb062ad77239bad2ef195037f8c9969edf119..36fc020cbc1803cbec2a7e1a225ae8690ea84a98 100644 (file)
@@ -63,7 +63,8 @@ static const char * const dvc_ramp_rate[] = {
        "0.125 dB/8192 steps",   /* 10111 */
 };
 
-static void rsnd_dvc_volume_update(struct rsnd_mod *mod)
+static void rsnd_dvc_volume_update(struct rsnd_dai_stream *io,
+                                  struct rsnd_mod *mod)
 {
        struct rsnd_dvc *dvc = rsnd_mod_to_dvc(mod);
        u32 val[RSND_DVC_CHANNELS];
@@ -120,6 +121,7 @@ static void rsnd_dvc_volume_update(struct rsnd_mod *mod)
 }
 
 static int rsnd_dvc_remove_gen2(struct rsnd_mod *mod,
+                               struct rsnd_dai_stream *io,
                                struct rsnd_priv *priv)
 {
        struct rsnd_dvc *dvc = rsnd_mod_to_dvc(mod);
@@ -134,9 +136,9 @@ static int rsnd_dvc_remove_gen2(struct rsnd_mod *mod,
 }
 
 static int rsnd_dvc_init(struct rsnd_mod *dvc_mod,
+                        struct rsnd_dai_stream *io,
                         struct rsnd_priv *priv)
 {
-       struct rsnd_dai_stream *io = rsnd_mod_to_io(dvc_mod);
        struct rsnd_mod *src_mod = rsnd_io_to_mod_src(io);
        struct device *dev = rsnd_priv_to_dev(priv);
        int dvc_id = rsnd_mod_id(dvc_mod);
@@ -168,10 +170,10 @@ static int rsnd_dvc_init(struct rsnd_mod *dvc_mod,
 
        rsnd_mod_write(dvc_mod, DVC_DVUIR, 1);
 
-       rsnd_mod_write(dvc_mod, DVC_ADINR, rsnd_get_adinr(dvc_mod));
+       rsnd_mod_write(dvc_mod, DVC_ADINR, rsnd_get_adinr(dvc_mod, io));
 
        /* ch0/ch1 Volume */
-       rsnd_dvc_volume_update(dvc_mod);
+       rsnd_dvc_volume_update(io, dvc_mod);
 
        rsnd_mod_write(dvc_mod, DVC_DVUIR, 0);
 
@@ -181,6 +183,7 @@ static int rsnd_dvc_init(struct rsnd_mod *dvc_mod,
 }
 
 static int rsnd_dvc_quit(struct rsnd_mod *mod,
+                        struct rsnd_dai_stream *io,
                         struct rsnd_priv *priv)
 {
        rsnd_mod_hw_stop(mod);
@@ -189,6 +192,7 @@ static int rsnd_dvc_quit(struct rsnd_mod *mod,
 }
 
 static int rsnd_dvc_start(struct rsnd_mod *mod,
+                         struct rsnd_dai_stream *io,
                          struct rsnd_priv *priv)
 {
        rsnd_mod_write(mod, CMD_CTRL, 0x10);
@@ -197,6 +201,7 @@ static int rsnd_dvc_start(struct rsnd_mod *mod,
 }
 
 static int rsnd_dvc_stop(struct rsnd_mod *mod,
+                        struct rsnd_dai_stream *io,
                         struct rsnd_priv *priv)
 {
        rsnd_mod_write(mod, CMD_CTRL, 0);
@@ -205,15 +210,15 @@ static int rsnd_dvc_stop(struct rsnd_mod *mod,
 }
 
 static int rsnd_dvc_pcm_new(struct rsnd_mod *mod,
+                           struct rsnd_dai_stream *io,
                            struct snd_soc_pcm_runtime *rtd)
 {
-       struct rsnd_dai_stream *io = rsnd_mod_to_io(mod);
        struct rsnd_dvc *dvc = rsnd_mod_to_dvc(mod);
        int is_play = rsnd_io_is_play(io);
        int ret;
 
        /* Volume */
-       ret = rsnd_kctrl_new_m(mod, rtd,
+       ret = rsnd_kctrl_new_m(mod, io, rtd,
                        is_play ?
                        "DVC Out Playback Volume" : "DVC In Capture Volume",
                        rsnd_dvc_volume_update,
@@ -222,7 +227,7 @@ static int rsnd_dvc_pcm_new(struct rsnd_mod *mod,
                return ret;
 
        /* Mute */
-       ret = rsnd_kctrl_new_m(mod, rtd,
+       ret = rsnd_kctrl_new_m(mod, io, rtd,
                        is_play ?
                        "DVC Out Mute Switch" : "DVC In Mute Switch",
                        rsnd_dvc_volume_update,
@@ -231,7 +236,7 @@ static int rsnd_dvc_pcm_new(struct rsnd_mod *mod,
                return ret;
 
        /* Ramp */
-       ret = rsnd_kctrl_new_s(mod, rtd,
+       ret = rsnd_kctrl_new_s(mod, io, rtd,
                        is_play ?
                        "DVC Out Ramp Switch" : "DVC In Ramp Switch",
                        rsnd_dvc_volume_update,
@@ -239,7 +244,7 @@ static int rsnd_dvc_pcm_new(struct rsnd_mod *mod,
        if (ret < 0)
                return ret;
 
-       ret = rsnd_kctrl_new_e(mod, rtd,
+       ret = rsnd_kctrl_new_e(mod, io, rtd,
                        is_play ?
                        "DVC Out Ramp Up Rate" : "DVC In Ramp Up Rate",
                        &dvc->rup,
@@ -248,7 +253,7 @@ static int rsnd_dvc_pcm_new(struct rsnd_mod *mod,
        if (ret < 0)
                return ret;
 
-       ret = rsnd_kctrl_new_e(mod, rtd,
+       ret = rsnd_kctrl_new_e(mod, io, rtd,
                        is_play ?
                        "DVC Out Ramp Down Rate" : "DVC In Ramp Down Rate",
                        &dvc->rdown,
@@ -261,7 +266,8 @@ static int rsnd_dvc_pcm_new(struct rsnd_mod *mod,
        return 0;
 }
 
-static struct dma_chan *rsnd_dvc_dma_req(struct rsnd_mod *mod)
+static struct dma_chan *rsnd_dvc_dma_req(struct rsnd_dai_stream *io,
+                                        struct rsnd_mod *mod)
 {
        struct rsnd_priv *priv = rsnd_mod_to_priv(mod);
 
@@ -366,7 +372,7 @@ int rsnd_dvc_probe(struct platform_device *pdev,
 
                dvc->info = &info->dvc_info[i];
 
-               ret = rsnd_mod_init(&dvc->mod, &rsnd_dvc_ops,
+               ret = rsnd_mod_init(priv, &dvc->mod, &rsnd_dvc_ops,
                              clk, RSND_MOD_DVC, i);
                if (ret)
                        return ret;
index 4e6de6804cfb17a1d70d3d1c363ee0a0c14ed019..09fcc54a8ee067589c682df1b3b0390ea463b5ed 100644 (file)
@@ -165,18 +165,18 @@ void rsnd_write(struct rsnd_priv *priv, struct rsnd_mod *mod,
                enum rsnd_reg reg, u32 data);
 void rsnd_bset(struct rsnd_priv *priv, struct rsnd_mod *mod, enum rsnd_reg reg,
                    u32 mask, u32 data);
-u32 rsnd_get_adinr(struct rsnd_mod *mod);
+u32 rsnd_get_adinr(struct rsnd_mod *mod, struct rsnd_dai_stream *io);
 
 /*
  *     R-Car DMA
  */
 struct rsnd_dma;
 struct rsnd_dma_ops {
-       void (*start)(struct rsnd_dma *dma);
-       void (*stop)(struct rsnd_dma *dma);
-       int (*init)(struct rsnd_priv *priv, struct rsnd_dma *dma, int id,
+       void (*start)(struct rsnd_dai_stream *io, struct rsnd_dma *dma);
+       void (*stop)(struct rsnd_dai_stream *io, struct rsnd_dma *dma);
+       int (*init)(struct rsnd_dai_stream *io, struct rsnd_dma *dma, int id,
                    struct rsnd_mod *mod_from, struct rsnd_mod *mod_to);
-       void  (*quit)(struct rsnd_dma *dma);
+       void (*quit)(struct rsnd_dai_stream *io, struct rsnd_dma *dma);
 };
 
 struct rsnd_dmaen {
@@ -200,10 +200,10 @@ struct rsnd_dma {
 #define rsnd_dma_to_dmaen(dma) (&(dma)->dma.en)
 #define rsnd_dma_to_dmapp(dma) (&(dma)->dma.pp)
 
-void rsnd_dma_start(struct rsnd_dma *dma);
-void rsnd_dma_stop(struct rsnd_dma *dma);
-int rsnd_dma_init(struct rsnd_priv *priv, struct rsnd_dma *dma, int id);
-void  rsnd_dma_quit(struct rsnd_dma *dma);
+void rsnd_dma_start(struct rsnd_dai_stream *io, struct rsnd_dma *dma);
+void rsnd_dma_stop(struct rsnd_dai_stream *io, struct rsnd_dma *dma);
+int rsnd_dma_init(struct rsnd_dai_stream *io, struct rsnd_dma *dma, int id);
+void rsnd_dma_quit(struct rsnd_dai_stream *io, struct rsnd_dma *dma);
 int rsnd_dma_probe(struct platform_device *pdev,
                   const struct rsnd_of_data *of_data,
                   struct rsnd_priv *priv);
@@ -224,25 +224,35 @@ enum rsnd_mod_type {
 
 struct rsnd_mod_ops {
        char *name;
-       struct dma_chan* (*dma_req)(struct rsnd_mod *mod);
+       struct dma_chan* (*dma_req)(struct rsnd_dai_stream *io,
+                                   struct rsnd_mod *mod);
        int (*probe)(struct rsnd_mod *mod,
+                    struct rsnd_dai_stream *io,
                     struct rsnd_priv *priv);
        int (*remove)(struct rsnd_mod *mod,
+                     struct rsnd_dai_stream *io,
                      struct rsnd_priv *priv);
        int (*init)(struct rsnd_mod *mod,
+                   struct rsnd_dai_stream *io,
                    struct rsnd_priv *priv);
        int (*quit)(struct rsnd_mod *mod,
+                   struct rsnd_dai_stream *io,
                    struct rsnd_priv *priv);
        int (*start)(struct rsnd_mod *mod,
+                    struct rsnd_dai_stream *io,
                     struct rsnd_priv *priv);
        int (*stop)(struct rsnd_mod *mod,
+                   struct rsnd_dai_stream *io,
                    struct rsnd_priv *priv);
        int (*pcm_new)(struct rsnd_mod *mod,
+                      struct rsnd_dai_stream *io,
                       struct snd_soc_pcm_runtime *rtd);
        int (*hw_params)(struct rsnd_mod *mod,
+                        struct rsnd_dai_stream *io,
                         struct snd_pcm_substream *substream,
                         struct snd_pcm_hw_params *hw_params);
        int (*fallback)(struct rsnd_mod *mod,
+                       struct rsnd_dai_stream *io,
                        struct rsnd_priv *priv);
 };
 
@@ -252,32 +262,43 @@ struct rsnd_mod {
        enum rsnd_mod_type type;
        struct rsnd_mod_ops *ops;
        struct rsnd_dma dma;
-       struct rsnd_dai_stream *io;
+       struct rsnd_priv *priv;
        struct clk *clk;
        u32 status;
 };
 /*
  * status
  *
- * bit
- * 0   0: probe        1: remove
- * 1   0: init         1: quit
- * 2   0: start        1: stop
- * 3   0: pcm_new
- * 4   0: fallback
+ * 0xH0000CBA
+ *
+ * A   0: probe        1: remove
+ * B   0: init         1: quit
+ * C   0: start        1: stop
  *
- * 31 bit is always called (see __rsnd_mod_call)
- * 31  0: hw_params
+ * H is always called (see __rsnd_mod_call)
+ * H   0: pcm_new
+ * H   0: fallback
+ * H   0: hw_params
  */
 #define __rsnd_mod_shift_probe         0
 #define __rsnd_mod_shift_remove                0
-#define __rsnd_mod_shift_init          1
-#define __rsnd_mod_shift_quit          1
-#define __rsnd_mod_shift_start         2
-#define __rsnd_mod_shift_stop          2
-#define __rsnd_mod_shift_pcm_new       3
-#define __rsnd_mod_shift_fallback      4
-#define __rsnd_mod_shift_hw_params     31 /* always called */
+#define __rsnd_mod_shift_init          4
+#define __rsnd_mod_shift_quit          4
+#define __rsnd_mod_shift_start         8
+#define __rsnd_mod_shift_stop          8
+#define __rsnd_mod_shift_pcm_new       28 /* always called */
+#define __rsnd_mod_shift_fallback      28 /* always called */
+#define __rsnd_mod_shift_hw_params     28 /* always called */
+
+#define __rsnd_mod_add_probe            1
+#define __rsnd_mod_add_remove          -1
+#define __rsnd_mod_add_init             1
+#define __rsnd_mod_add_quit            -1
+#define __rsnd_mod_add_start            1
+#define __rsnd_mod_add_stop            -1
+#define __rsnd_mod_add_pcm_new         0
+#define __rsnd_mod_add_fallback                0
+#define __rsnd_mod_add_hw_params       0
 
 #define __rsnd_mod_call_probe          0
 #define __rsnd_mod_call_remove         1
@@ -289,21 +310,25 @@ struct rsnd_mod {
 #define __rsnd_mod_call_fallback       0
 #define __rsnd_mod_call_hw_params      0
 
-#define rsnd_mod_to_priv(mod) (rsnd_io_to_priv(rsnd_mod_to_io(mod)))
+#define rsnd_mod_to_priv(mod) ((mod)->priv)
 #define rsnd_mod_to_dma(mod) (&(mod)->dma)
-#define rsnd_mod_to_io(mod) ((mod)->io)
 #define rsnd_mod_id(mod) ((mod)->id)
 #define rsnd_mod_hw_start(mod) clk_enable((mod)->clk)
 #define rsnd_mod_hw_stop(mod)  clk_disable((mod)->clk)
 
-int rsnd_mod_init(struct rsnd_mod *mod,
+int rsnd_mod_init(struct rsnd_priv *priv,
+                 struct rsnd_mod *mod,
                   struct rsnd_mod_ops *ops,
                   struct clk *clk,
                   enum rsnd_mod_type type,
                   int id);
 void rsnd_mod_quit(struct rsnd_mod *mod);
 char *rsnd_mod_name(struct rsnd_mod *mod);
-struct dma_chan *rsnd_mod_dma_req(struct rsnd_mod *mod);
+struct dma_chan *rsnd_mod_dma_req(struct rsnd_dai_stream *io,
+                                 struct rsnd_mod *mod);
+void rsnd_mod_interrupt(struct rsnd_mod *mod,
+                       void (*callback)(struct rsnd_mod *mod,
+                                        struct rsnd_dai_stream *io));
 
 /*
  *     R-Car sound DAI
@@ -328,7 +353,7 @@ struct rsnd_dai_stream {
 #define rsnd_io_is_play(io)    (&rsnd_io_to_rdai(io)->playback == io)
 #define rsnd_io_to_runtime(io) ((io)->substream ? \
                                (io)->substream->runtime : NULL)
-
+int rsnd_io_is_working(struct rsnd_dai_stream *io);
 
 struct rsnd_dai {
        char name[RSND_DAI_NAME_SIZE];
@@ -354,7 +379,8 @@ struct rsnd_dai {
 
 struct rsnd_dai *rsnd_rdai_get(struct rsnd_priv *priv, int id);
 
-void rsnd_dai_pointer_update(struct rsnd_dai_stream *io, int cnt);
+bool rsnd_dai_pointer_update(struct rsnd_dai_stream *io, int cnt);
+void rsnd_dai_period_elapsed(struct rsnd_dai_stream *io);
 int rsnd_dai_pointer_offset(struct rsnd_dai_stream *io, int additional);
 
 /*
@@ -449,8 +475,6 @@ struct rsnd_priv {
 #define rsnd_priv_to_pdev(priv)        ((priv)->pdev)
 #define rsnd_priv_to_dev(priv) (&(rsnd_priv_to_pdev(priv)->dev))
 #define rsnd_priv_to_info(priv)        ((priv)->info)
-#define rsnd_lock(priv, flags) spin_lock_irqsave(&priv->lock, flags)
-#define rsnd_unlock(priv, flags) spin_unlock_irqrestore(&priv->lock, flags)
 
 /*
  *     rsnd_kctrl
@@ -460,7 +484,8 @@ struct rsnd_kctrl_cfg {
        unsigned int size;
        u32 *val;
        const char * const *texts;
-       void (*update)(struct rsnd_mod *mod);
+       void (*update)(struct rsnd_dai_stream *io, struct rsnd_mod *mod);
+       struct rsnd_dai_stream *io;
        struct snd_card *card;
        struct snd_kcontrol *kctrl;
 };
@@ -480,22 +505,28 @@ void _rsnd_kctrl_remove(struct rsnd_kctrl_cfg *cfg);
 #define rsnd_kctrl_remove(_cfg)        _rsnd_kctrl_remove(&((_cfg).cfg))
 
 int rsnd_kctrl_new_m(struct rsnd_mod *mod,
+                    struct rsnd_dai_stream *io,
                     struct snd_soc_pcm_runtime *rtd,
                     const unsigned char *name,
-                    void (*update)(struct rsnd_mod *mod),
+                    void (*update)(struct rsnd_dai_stream *io,
+                                   struct rsnd_mod *mod),
                     struct rsnd_kctrl_cfg_m *_cfg,
                     u32 max);
 int rsnd_kctrl_new_s(struct rsnd_mod *mod,
+                    struct rsnd_dai_stream *io,
                     struct snd_soc_pcm_runtime *rtd,
                     const unsigned char *name,
-                    void (*update)(struct rsnd_mod *mod),
+                    void (*update)(struct rsnd_dai_stream *io,
+                                   struct rsnd_mod *mod),
                     struct rsnd_kctrl_cfg_s *_cfg,
                     u32 max);
 int rsnd_kctrl_new_e(struct rsnd_mod *mod,
+                    struct rsnd_dai_stream *io,
                     struct snd_soc_pcm_runtime *rtd,
                     const unsigned char *name,
                     struct rsnd_kctrl_cfg_s *_cfg,
-                    void (*update)(struct rsnd_mod *mod),
+                    void (*update)(struct rsnd_dai_stream *io,
+                                   struct rsnd_mod *mod),
                     const char * const *texts,
                     u32 max);
 
@@ -512,8 +543,10 @@ unsigned int rsnd_src_get_ssi_rate(struct rsnd_priv *priv,
                                   struct rsnd_dai_stream *io,
                                   struct snd_pcm_runtime *runtime);
 int rsnd_src_ssiu_start(struct rsnd_mod *ssi_mod,
+                       struct rsnd_dai_stream *io,
                        int use_busif);
-int rsnd_src_ssiu_stop(struct rsnd_mod *ssi_mod);
+int rsnd_src_ssiu_stop(struct rsnd_mod *ssi_mod,
+                      struct rsnd_dai_stream *io);
 int rsnd_src_ssi_irq_enable(struct rsnd_mod *ssi_mod);
 int rsnd_src_ssi_irq_disable(struct rsnd_mod *ssi_mod);
 
@@ -530,7 +563,7 @@ void rsnd_ssi_remove(struct platform_device *pdev,
 struct rsnd_mod *rsnd_ssi_mod_get(struct rsnd_priv *priv, int id);
 int rsnd_ssi_is_pin_sharing(struct rsnd_mod *mod);
 int rsnd_ssi_is_dma_mode(struct rsnd_mod *mod);
-int rsnd_ssi_use_busif(struct rsnd_mod *mod);
+int rsnd_ssi_use_busif(struct rsnd_dai_stream *io, struct rsnd_mod *mod);
 
 /*
  *     R-Car DVC
index a68517afe61596ce674582ba5170caff9a7b8cd9..8caca2e180c39122d9fcb340d525c04cbfec1817 100644 (file)
@@ -45,61 +45,50 @@ static const struct of_device_id rsrc_card_of_match[] = {
 };
 MODULE_DEVICE_TABLE(of, rsrc_card_of_match);
 
+#define DAI_NAME_NUM   32
 struct rsrc_card_dai {
-       const char *name;
        unsigned int fmt;
        unsigned int sysclk;
        struct clk *clk;
+       char dai_name[DAI_NAME_NUM];
 };
 
-#define RSRC_FB_NUM    2 /* FE/BE */
 #define IDX_CPU                0
 #define IDX_CODEC      1
 struct rsrc_card_priv {
        struct snd_soc_card snd_card;
-       struct rsrc_card_dai_props {
-               struct rsrc_card_dai cpu_dai;
-               struct rsrc_card_dai codec_dai;
-       } dai_props[RSRC_FB_NUM];
        struct snd_soc_codec_conf codec_conf;
-       struct snd_soc_dai_link dai_link[RSRC_FB_NUM];
+       struct rsrc_card_dai *dai_props;
+       struct snd_soc_dai_link *dai_link;
+       int dai_num;
        u32 convert_rate;
 };
 
 #define rsrc_priv_to_dev(priv) ((priv)->snd_card.dev)
-#define rsrc_priv_to_link(priv, i) ((priv)->snd_card.dai_link + i)
-#define rsrc_priv_to_props(priv, i) ((priv)->dai_props + i)
+#define rsrc_priv_to_link(priv, i) ((priv)->snd_card.dai_link + (i))
+#define rsrc_priv_to_props(priv, i) ((priv)->dai_props + (i))
 #define rsrc_dev_to_of_data(dev) (of_match_device(rsrc_card_of_match, (dev))->data)
 
 static int rsrc_card_startup(struct snd_pcm_substream *substream)
 {
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
        struct rsrc_card_priv *priv =   snd_soc_card_get_drvdata(rtd->card);
-       struct rsrc_card_dai_props *dai_props =
-               &priv->dai_props[rtd - rtd->card->rtd];
+       struct rsrc_card_dai *dai_props =
+               rsrc_priv_to_props(priv, rtd - rtd->card->rtd);
        int ret;
 
-       ret = clk_prepare_enable(dai_props->cpu_dai.clk);
-       if (ret)
-               return ret;
-
-       ret = clk_prepare_enable(dai_props->codec_dai.clk);
-       if (ret)
-               clk_disable_unprepare(dai_props->cpu_dai.clk);
 
-       return ret;
+       return clk_prepare_enable(dai_props->clk);
 }
 
 static void rsrc_card_shutdown(struct snd_pcm_substream *substream)
 {
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
        struct rsrc_card_priv *priv =   snd_soc_card_get_drvdata(rtd->card);
-       struct rsrc_card_dai_props *dai_props =
-               &priv->dai_props[rtd - rtd->card->rtd];
-
-       clk_disable_unprepare(dai_props->cpu_dai.clk);
+       struct rsrc_card_dai *dai_props =
+               rsrc_priv_to_props(priv, rtd - rtd->card->rtd);
 
-       clk_disable_unprepare(dai_props->codec_dai.clk);
+       clk_disable_unprepare(dai_props->clk);
 }
 
 static struct snd_soc_ops rsrc_card_ops = {
@@ -107,21 +96,31 @@ static struct snd_soc_ops rsrc_card_ops = {
        .shutdown = rsrc_card_shutdown,
 };
 
-static int __rsrc_card_dai_init(struct snd_soc_dai *dai,
-                               struct rsrc_card_dai *set)
+static int rsrc_card_dai_init(struct snd_soc_pcm_runtime *rtd)
 {
+       struct rsrc_card_priv *priv = snd_soc_card_get_drvdata(rtd->card);
+       struct snd_soc_dai *dai;
+       struct snd_soc_dai_link *dai_link;
+       struct rsrc_card_dai *dai_props;
+       int num = rtd - rtd->card->rtd;
        int ret;
 
-       if (set->fmt) {
-               ret = snd_soc_dai_set_fmt(dai, set->fmt);
+       dai_link        = rsrc_priv_to_link(priv, num);
+       dai_props       = rsrc_priv_to_props(priv, num);
+       dai             = dai_link->dynamic ?
+                               rtd->cpu_dai :
+                               rtd->codec_dai;
+
+       if (dai_props->fmt) {
+               ret = snd_soc_dai_set_fmt(dai, dai_props->fmt);
                if (ret && ret != -ENOTSUPP) {
                        dev_err(dai->dev, "set_fmt error\n");
                        goto err;
                }
        }
 
-       if (set->sysclk) {
-               ret = snd_soc_dai_set_sysclk(dai, 0, set->sysclk, 0);
+       if (dai_props->sysclk) {
+               ret = snd_soc_dai_set_sysclk(dai, 0, dai_props->sysclk, 0);
                if (ret && ret != -ENOTSUPP) {
                        dev_err(dai->dev, "set_sysclk error\n");
                        goto err;
@@ -134,27 +133,6 @@ err:
        return ret;
 }
 
-static int rsrc_card_dai_init(struct snd_soc_pcm_runtime *rtd)
-{
-       struct rsrc_card_priv *priv =   snd_soc_card_get_drvdata(rtd->card);
-       struct snd_soc_dai *codec = rtd->codec_dai;
-       struct snd_soc_dai *cpu = rtd->cpu_dai;
-       struct rsrc_card_dai_props *dai_props;
-       int num, ret;
-
-       num = rtd - rtd->card->rtd;
-       dai_props = &priv->dai_props[num];
-       ret = __rsrc_card_dai_init(codec, &dai_props->codec_dai);
-       if (ret < 0)
-               return ret;
-
-       ret = __rsrc_card_dai_init(cpu, &dai_props->cpu_dai);
-       if (ret < 0)
-               return ret;
-
-       return 0;
-}
-
 static int rsrc_card_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
                                        struct snd_pcm_hw_params *params)
 {
@@ -170,40 +148,47 @@ static int rsrc_card_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
        return 0;
 }
 
-static int
-rsrc_card_sub_parse_of(struct rsrc_card_priv *priv,
-                      struct device_node *np,
-                      struct rsrc_card_dai *dai,
-                      struct snd_soc_dai_link *dai_link,
-                      int *args_count)
+static int rsrc_card_parse_daifmt(struct device_node *node,
+                                 struct device_node *np,
+                                 struct rsrc_card_priv *priv,
+                                 int idx, bool is_fe)
 {
-       struct device *dev = rsrc_priv_to_dev(priv);
-       const struct rsrc_card_of_data *of_data = rsrc_dev_to_of_data(dev);
-       struct of_phandle_args args;
-       struct device_node **p_node;
-       struct clk *clk;
-       const char **dai_name;
-       const char **name;
-       u32 val;
-       int ret;
+       struct rsrc_card_dai *dai_props = rsrc_priv_to_props(priv, idx);
+       struct device_node *bitclkmaster = NULL;
+       struct device_node *framemaster = NULL;
+       struct device_node *codec = is_fe ? NULL : np;
+       unsigned int daifmt;
 
-       if (args_count) {
-               p_node          = &dai_link->cpu_of_node;
-               dai_name        = &dai_link->cpu_dai_name;
-               name            = &dai_link->cpu_name;
-       } else {
-               p_node          = &dai_link->codec_of_node;
-               dai_name        = &dai_link->codec_dai_name;
-               name            = &dai_link->codec_name;
-       }
+       daifmt = snd_soc_of_parse_daifmt(node, NULL,
+                                        &bitclkmaster, &framemaster);
+       daifmt &= ~SND_SOC_DAIFMT_MASTER_MASK;
 
-       if (!np) {
-               /* use snd-soc-dummy */
-               *p_node         = NULL;
-               *dai_name       = "snd-soc-dummy-dai";
-               *name           = "snd-soc-dummy";
-               return 0;
-       }
+       if (!bitclkmaster && !framemaster)
+               return -EINVAL;
+
+       if (codec == bitclkmaster)
+               daifmt |= (codec == framemaster) ?
+                       SND_SOC_DAIFMT_CBM_CFM : SND_SOC_DAIFMT_CBM_CFS;
+       else
+               daifmt |= (codec == framemaster) ?
+                       SND_SOC_DAIFMT_CBS_CFM : SND_SOC_DAIFMT_CBS_CFS;
+
+       dai_props->fmt  = daifmt;
+
+       of_node_put(bitclkmaster);
+       of_node_put(framemaster);
+
+       return 0;
+}
+
+static int rsrc_card_parse_links(struct device_node *np,
+                                struct rsrc_card_priv *priv,
+                                int idx, bool is_fe)
+{
+       struct snd_soc_dai_link *dai_link = rsrc_priv_to_link(priv, idx);
+       struct rsrc_card_dai *dai_props = rsrc_priv_to_props(priv, idx);
+       struct of_phandle_args args;
+       int ret;
 
        /*
         * Get node via "sound-dai = <&phandle port>"
@@ -214,30 +199,82 @@ rsrc_card_sub_parse_of(struct rsrc_card_priv *priv,
        if (ret)
                return ret;
 
-       *p_node = args.np;
+       if (is_fe) {
+               /* BE is dummy */
+               dai_link->codec_of_node         = NULL;
+               dai_link->codec_dai_name        = "snd-soc-dummy-dai";
+               dai_link->codec_name            = "snd-soc-dummy";
+
+               /* FE settings */
+               dai_link->dynamic               = 1;
+               dai_link->dpcm_merged_format    = 1;
+               dai_link->cpu_of_node           = args.np;
+               snd_soc_of_get_dai_name(np, &dai_link->cpu_dai_name);
+
+               /* set dai_name */
+               snprintf(dai_props->dai_name, DAI_NAME_NUM, "fe.%s",
+                        dai_link->cpu_dai_name);
+
+               /*
+                * In soc_bind_dai_link() will check cpu name after
+                * of_node matching if dai_link has cpu_dai_name.
+                * but, it will never match if name was created by
+                * fmt_single_name() remove cpu_dai_name if cpu_args
+                * was 0. See:
+                *      fmt_single_name()
+                *      fmt_multiple_name()
+                */
+               if (!args.args_count)
+                       dai_link->cpu_dai_name = NULL;
+       } else {
+               struct device *dev = rsrc_priv_to_dev(priv);
+               const struct rsrc_card_of_data *of_data;
 
-       /* Get dai->name */
-       ret = snd_soc_of_get_dai_name(np, dai_name);
-       if (ret < 0)
-               return ret;
+               of_data = rsrc_dev_to_of_data(dev);
 
-       /*
-        * FIXME
-        *
-        * rsrc assumes DPCM playback/capture
-        */
-       dai_link->dpcm_playback = 1;
-       dai_link->dpcm_capture = 1;
+               /* FE is dummy */
+               dai_link->cpu_of_node           = NULL;
+               dai_link->cpu_dai_name          = "snd-soc-dummy-dai";
+               dai_link->cpu_name              = "snd-soc-dummy";
 
-       if (args_count) {
-               *args_count = args.args_count;
-               dai_link->dynamic = 1;
-       } else {
-               dai_link->no_pcm = 1;
-               priv->codec_conf.of_node = (*p_node);
-               priv->codec_conf.name_prefix = of_data->prefix;
+               /* BE settings */
+               dai_link->no_pcm                = 1;
+               dai_link->be_hw_params_fixup    = rsrc_card_be_hw_params_fixup;
+               dai_link->codec_of_node         = args.np;
+               snd_soc_of_get_dai_name(np, &dai_link->codec_dai_name);
+
+               /* additional name prefix */
+               priv->codec_conf.of_node        = dai_link->codec_of_node;
+               priv->codec_conf.name_prefix    = of_data->prefix;
+
+               /* set dai_name */
+               snprintf(dai_props->dai_name, DAI_NAME_NUM, "be.%s",
+                        dai_link->codec_dai_name);
        }
 
+       /* Simple Card assumes platform == cpu */
+       dai_link->platform_of_node      = dai_link->cpu_of_node;
+       dai_link->dpcm_playback         = 1;
+       dai_link->dpcm_capture          = 1;
+       dai_link->name                  = dai_props->dai_name;
+       dai_link->stream_name           = dai_props->dai_name;
+       dai_link->ops                   = &rsrc_card_ops;
+       dai_link->init                  = rsrc_card_dai_init;
+
+       return 0;
+}
+
+static int rsrc_card_parse_clk(struct device_node *np,
+                              struct rsrc_card_priv *priv,
+                              int idx, bool is_fe)
+{
+       struct snd_soc_dai_link *dai_link = rsrc_priv_to_link(priv, idx);
+       struct rsrc_card_dai *dai_props = rsrc_priv_to_props(priv, idx);
+       struct clk *clk;
+       struct device_node *of_np = is_fe ?     dai_link->cpu_of_node :
+                                               dai_link->codec_of_node;
+       u32 val;
+
        /*
         * Parse dai->sysclk come from "clocks = <&xxx>"
         * (if system has common clock)
@@ -246,173 +283,92 @@ rsrc_card_sub_parse_of(struct rsrc_card_priv *priv,
         */
        if (of_property_read_bool(np, "clocks")) {
                clk = of_clk_get(np, 0);
-               if (IS_ERR(clk)) {
-                       ret = PTR_ERR(clk);
-                       return ret;
-               }
+               if (IS_ERR(clk))
+                       return PTR_ERR(clk);
 
-               dai->sysclk = clk_get_rate(clk);
-               dai->clk = clk;
+               dai_props->sysclk = clk_get_rate(clk);
+               dai_props->clk = clk;
        } else if (!of_property_read_u32(np, "system-clock-frequency", &val)) {
-               dai->sysclk = val;
+               dai_props->sysclk = val;
        } else {
-               clk = of_clk_get(args.np, 0);
+               clk = of_clk_get(of_np, 0);
                if (!IS_ERR(clk))
-                       dai->sysclk = clk_get_rate(clk);
+                       dai_props->sysclk = clk_get_rate(clk);
        }
 
        return 0;
 }
 
-static int rsrc_card_parse_daifmt(struct device_node *node,
-                                 struct rsrc_card_priv *priv,
-                                 struct device_node *codec,
-                                 int idx)
-{
-       struct device_node *bitclkmaster = NULL;
-       struct device_node *framemaster = NULL;
-       struct rsrc_card_dai_props *dai_props = rsrc_priv_to_props(priv, idx);
-       struct rsrc_card_dai *cpu_dai = &dai_props->cpu_dai;
-       struct rsrc_card_dai *codec_dai = &dai_props->codec_dai;
-       unsigned int daifmt;
-
-       daifmt = snd_soc_of_parse_daifmt(node, NULL,
-                                        &bitclkmaster, &framemaster);
-       daifmt &= ~SND_SOC_DAIFMT_MASTER_MASK;
-
-       if (!bitclkmaster && !framemaster)
-               return -EINVAL;
-
-       if (codec == bitclkmaster)
-               daifmt |= (codec == framemaster) ?
-                       SND_SOC_DAIFMT_CBM_CFM : SND_SOC_DAIFMT_CBM_CFS;
-       else
-               daifmt |= (codec == framemaster) ?
-                       SND_SOC_DAIFMT_CBS_CFM : SND_SOC_DAIFMT_CBS_CFS;
-
-       cpu_dai->fmt    = daifmt;
-       codec_dai->fmt  = daifmt;
-
-       of_node_put(bitclkmaster);
-       of_node_put(framemaster);
-
-       return 0;
-}
-
 static int rsrc_card_dai_link_of(struct device_node *node,
+                                struct device_node *np,
                                 struct rsrc_card_priv *priv,
                                 int idx)
 {
        struct device *dev = rsrc_priv_to_dev(priv);
-       struct snd_soc_dai_link *dai_link = rsrc_priv_to_link(priv, idx);
-       struct rsrc_card_dai_props *dai_props = rsrc_priv_to_props(priv, idx);
-       struct device_node *cpu = NULL;
-       struct device_node *codec = NULL;
-       char *name;
-       char prop[128];
-       int ret, cpu_args;
-
-       cpu = of_get_child_by_name(node, "cpu");
-       codec = of_get_child_by_name(node, "codec");
-
-       if (!cpu || !codec) {
-               ret = -EINVAL;
-               dev_err(dev, "%s: Can't find %s DT node\n", __func__, prop);
-               goto dai_link_of_err;
-       }
+       struct rsrc_card_dai *dai_props = rsrc_priv_to_props(priv, idx);
+       bool is_fe = false;
+       int ret;
 
-       ret = rsrc_card_parse_daifmt(node, priv, codec, idx);
-       if (ret < 0)
-               goto dai_link_of_err;
+       if (0 == strcmp(np->name, "cpu"))
+               is_fe = true;
 
-       ret = rsrc_card_sub_parse_of(priv, (idx == IDX_CPU) ? cpu : NULL,
-                                    &dai_props->cpu_dai,
-                                    dai_link,
-                                    &cpu_args);
+       ret = rsrc_card_parse_daifmt(node, np, priv, idx, is_fe);
        if (ret < 0)
-               goto dai_link_of_err;
+               return ret;
 
-       ret = rsrc_card_sub_parse_of(priv, (idx == IDX_CODEC) ? codec : NULL,
-                                    &dai_props->codec_dai,
-                                    dai_link,
-                                    NULL);
+       ret = rsrc_card_parse_links(np, priv, idx, is_fe);
        if (ret < 0)
-               goto dai_link_of_err;
-
-       if (!dai_link->cpu_dai_name || !dai_link->codec_dai_name) {
-               ret = -EINVAL;
-               goto dai_link_of_err;
-       }
-
-       /* Simple Card assumes platform == cpu */
-       dai_link->platform_of_node = dai_link->cpu_of_node;
-
-       /* DAI link name is created from CPU/CODEC dai name */
-       name = devm_kzalloc(dev,
-                           strlen(dai_link->cpu_dai_name)   +
-                           strlen(dai_link->codec_dai_name) + 2,
-                           GFP_KERNEL);
-       if (!name) {
-               ret = -ENOMEM;
-               goto dai_link_of_err;
-       }
-
-       sprintf(name, "%s-%s", dai_link->cpu_dai_name,
-               dai_link->codec_dai_name);
-       dai_link->name = dai_link->stream_name = name;
-       dai_link->ops = &rsrc_card_ops;
-       dai_link->init = rsrc_card_dai_init;
-
-       if (idx == IDX_CODEC)
-               dai_link->be_hw_params_fixup = rsrc_card_be_hw_params_fixup;
-
-       dev_dbg(dev, "\tname : %s\n", dai_link->stream_name);
-       dev_dbg(dev, "\tcpu : %s / %04x / %d\n",
-               dai_link->cpu_dai_name,
-               dai_props->cpu_dai.fmt,
-               dai_props->cpu_dai.sysclk);
-       dev_dbg(dev, "\tcodec : %s / %04x / %d\n",
-               dai_link->codec_dai_name,
-               dai_props->codec_dai.fmt,
-               dai_props->codec_dai.sysclk);
+               return ret;
 
-       /*
-        * In soc_bind_dai_link() will check cpu name after
-        * of_node matching if dai_link has cpu_dai_name.
-        * but, it will never match if name was created by
-        * fmt_single_name() remove cpu_dai_name if cpu_args
-        * was 0. See:
-        *      fmt_single_name()
-        *      fmt_multiple_name()
-        */
-       if (!cpu_args)
-               dai_link->cpu_dai_name = NULL;
+       ret = rsrc_card_parse_clk(np, priv, idx, is_fe);
+       if (ret < 0)
+               return ret;
 
-dai_link_of_err:
-       of_node_put(cpu);
-       of_node_put(codec);
+       dev_dbg(dev, "\t%s / %04x / %d\n",
+               dai_props->dai_name,
+               dai_props->fmt,
+               dai_props->sysclk);
 
        return ret;
 }
 
 static int rsrc_card_parse_of(struct device_node *node,
-                             struct rsrc_card_priv *priv)
+                             struct rsrc_card_priv *priv,
+                             struct device *dev)
 {
-       struct device *dev = rsrc_priv_to_dev(priv);
        const struct rsrc_card_of_data *of_data = rsrc_dev_to_of_data(dev);
+       struct rsrc_card_dai *props;
+       struct snd_soc_dai_link *links;
+       struct device_node *np;
        int ret;
-       int i;
+       int i, num;
 
        if (!node)
                return -EINVAL;
 
-       /* Parse the card name from DT */
-       snd_soc_of_parse_card_name(&priv->snd_card, "card-name");
+       num = of_get_child_count(node);
+       props = devm_kzalloc(dev, sizeof(*props) * num, GFP_KERNEL);
+       links = devm_kzalloc(dev, sizeof(*links) * num, GFP_KERNEL);
+       if (!props || !links)
+               return -ENOMEM;
+
+       priv->dai_props = props;
+       priv->dai_link  = links;
+       priv->dai_num   = num;
 
-       /* DAPM routes */
+       /* Init snd_soc_card */
+       priv->snd_card.owner                    = THIS_MODULE;
+       priv->snd_card.dev                      = dev;
+       priv->snd_card.dai_link                 = priv->dai_link;
+       priv->snd_card.num_links                = num;
+       priv->snd_card.codec_conf               = &priv->codec_conf;
+       priv->snd_card.num_configs              = 1;
        priv->snd_card.of_dapm_routes           = of_data->routes;
        priv->snd_card.num_of_dapm_routes       = of_data->num_routes;
 
+       /* Parse the card name from DT */
+       snd_soc_of_parse_card_name(&priv->snd_card, "card-name");
+
        /* sampling rate convert */
        of_property_read_u32(node, "convert-rate", &priv->convert_rate);
 
@@ -420,11 +376,12 @@ static int rsrc_card_parse_of(struct device_node *node,
                priv->snd_card.name ? priv->snd_card.name : "",
                priv->convert_rate);
 
-       /* FE/BE */
-       for (i = 0; i < RSRC_FB_NUM; i++) {
-               ret = rsrc_card_dai_link_of(node, priv, i);
+       i = 0;
+       for_each_child_of_node(node, np) {
+               ret = rsrc_card_dai_link_of(node, np, priv, i);
                if (ret < 0)
                        return ret;
+               i++;
        }
 
        if (!priv->snd_card.name)
@@ -451,7 +408,6 @@ static int rsrc_card_unref(struct snd_soc_card *card)
 static int rsrc_card_probe(struct platform_device *pdev)
 {
        struct rsrc_card_priv *priv;
-       struct snd_soc_dai_link *dai_link;
        struct device_node *np = pdev->dev.of_node;
        struct device *dev = &pdev->dev;
        int ret;
@@ -461,16 +417,7 @@ static int rsrc_card_probe(struct platform_device *pdev)
        if (!priv)
                return -ENOMEM;
 
-       /* Init snd_soc_card */
-       priv->snd_card.owner = THIS_MODULE;
-       priv->snd_card.dev = dev;
-       dai_link = priv->dai_link;
-       priv->snd_card.dai_link = dai_link;
-       priv->snd_card.num_links = RSRC_FB_NUM;
-       priv->snd_card.codec_conf = &priv->codec_conf;
-       priv->snd_card.num_configs = 1;
-
-       ret = rsrc_card_parse_of(np, priv);
+       ret = rsrc_card_parse_of(np, priv, dev);
        if (ret < 0) {
                if (ret != -EPROBE_DEFER)
                        dev_err(dev, "parse error %d\n", ret);
index 3beb32eb412a103db4135a20e96948f4a1c88c80..c61c171801423fc03b98598a3fd1624c7eb4155c 100644 (file)
@@ -117,10 +117,10 @@ struct rsnd_src {
 /*
  *             Gen1/Gen2 common functions
  */
-static struct dma_chan *rsnd_src_dma_req(struct rsnd_mod *mod)
+static struct dma_chan *rsnd_src_dma_req(struct rsnd_dai_stream *io,
+                                        struct rsnd_mod *mod)
 {
        struct rsnd_priv *priv = rsnd_mod_to_priv(mod);
-       struct rsnd_dai_stream *io = rsnd_mod_to_io(mod);
        int is_play = rsnd_io_is_play(io);
 
        return rsnd_dma_request_channel(rsnd_src_of_node(priv),
@@ -129,9 +129,9 @@ static struct dma_chan *rsnd_src_dma_req(struct rsnd_mod *mod)
 }
 
 int rsnd_src_ssiu_start(struct rsnd_mod *ssi_mod,
+                       struct rsnd_dai_stream *io,
                        int use_busif)
 {
-       struct rsnd_dai_stream *io = rsnd_mod_to_io(ssi_mod);
        struct rsnd_dai *rdai = rsnd_io_to_rdai(io);
        struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io);
        int ssi_id = rsnd_mod_id(ssi_mod);
@@ -174,7 +174,7 @@ int rsnd_src_ssiu_start(struct rsnd_mod *ssi_mod,
                u32 mask = ~0;
 
                rsnd_mod_write(ssi_mod, SSI_BUSIF_ADINR,
-                              rsnd_get_adinr(ssi_mod));
+                              rsnd_get_adinr(ssi_mod, io));
                rsnd_mod_write(ssi_mod, SSI_BUSIF_MODE,  1);
                rsnd_mod_write(ssi_mod, SSI_CTRL, 0x1);
 
@@ -196,7 +196,8 @@ int rsnd_src_ssiu_start(struct rsnd_mod *ssi_mod,
        return 0;
 }
 
-int rsnd_src_ssiu_stop(struct rsnd_mod *ssi_mod)
+int rsnd_src_ssiu_stop(struct rsnd_mod *ssi_mod,
+                      struct rsnd_dai_stream *io)
 {
        /*
         * DMA settings for SSIU
@@ -235,10 +236,9 @@ int rsnd_src_ssi_irq_disable(struct rsnd_mod *ssi_mod)
        return 0;
 }
 
-static u32 rsnd_src_convert_rate(struct rsnd_src *src)
+static u32 rsnd_src_convert_rate(struct rsnd_dai_stream *io,
+                                struct rsnd_src *src)
 {
-       struct rsnd_mod *mod = &src->mod;
-       struct rsnd_dai_stream *io = rsnd_mod_to_io(mod);
        struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io);
        u32 convert_rate;
 
@@ -274,7 +274,7 @@ unsigned int rsnd_src_get_ssi_rate(struct rsnd_priv *priv,
                 * return convert rate if SRC is used,
                 * otherwise, return runtime->rate as usual
                 */
-               rate = rsnd_src_convert_rate(src);
+               rate = rsnd_src_convert_rate(io, src);
        }
 
        if (!rate)
@@ -283,12 +283,12 @@ unsigned int rsnd_src_get_ssi_rate(struct rsnd_priv *priv,
        return rate;
 }
 
-static int rsnd_src_set_convert_rate(struct rsnd_mod *mod)
+static int rsnd_src_set_convert_rate(struct rsnd_mod *mod,
+                                    struct rsnd_dai_stream *io)
 {
-       struct rsnd_dai_stream *io = rsnd_mod_to_io(mod);
        struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io);
        struct rsnd_src *src = rsnd_mod_to_src(mod);
-       u32 convert_rate = rsnd_src_convert_rate(src);
+       u32 convert_rate = rsnd_src_convert_rate(io, src);
        u32 fsrate = 0;
 
        if (convert_rate)
@@ -299,7 +299,7 @@ static int rsnd_src_set_convert_rate(struct rsnd_mod *mod)
        rsnd_mod_write(mod, SRC_SWRSR, 1);
 
        /* Set channel number and output bit length */
-       rsnd_mod_write(mod, SRC_ADINR, rsnd_get_adinr(mod));
+       rsnd_mod_write(mod, SRC_ADINR, rsnd_get_adinr(mod, io));
 
        /* Enable the initial value of IFS */
        if (fsrate) {
@@ -316,6 +316,7 @@ static int rsnd_src_set_convert_rate(struct rsnd_mod *mod)
 }
 
 static int rsnd_src_hw_params(struct rsnd_mod *mod,
+                             struct rsnd_dai_stream *io,
                              struct snd_pcm_substream *substream,
                              struct snd_pcm_hw_params *fe_params)
 {
@@ -372,6 +373,7 @@ static int rsnd_src_init(struct rsnd_mod *mod,
 }
 
 static int rsnd_src_quit(struct rsnd_mod *mod,
+                        struct rsnd_dai_stream *io,
                         struct rsnd_priv *priv)
 {
        struct rsnd_src *src = rsnd_mod_to_src(mod);
@@ -411,9 +413,9 @@ static int rsnd_src_stop(struct rsnd_mod *mod)
 /*
  *             Gen1 functions
  */
-static int rsnd_src_set_route_gen1(struct rsnd_mod *mod)
+static int rsnd_src_set_route_gen1(struct rsnd_dai_stream *io,
+                                  struct rsnd_mod *mod)
 {
-       struct rsnd_dai_stream *io = rsnd_mod_to_io(mod);
        struct src_route_config {
                u32 mask;
                int shift;
@@ -448,13 +450,13 @@ static int rsnd_src_set_route_gen1(struct rsnd_mod *mod)
        return 0;
 }
 
-static int rsnd_src_set_convert_timing_gen1(struct rsnd_mod *mod)
+static int rsnd_src_set_convert_timing_gen1(struct rsnd_dai_stream *io,
+                                           struct rsnd_mod *mod)
 {
-       struct rsnd_dai_stream *io = rsnd_mod_to_io(mod);
        struct rsnd_priv *priv = rsnd_mod_to_priv(mod);
        struct rsnd_src *src = rsnd_mod_to_src(mod);
        struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io);
-       u32 convert_rate = rsnd_src_convert_rate(src);
+       u32 convert_rate = rsnd_src_convert_rate(io, src);
        u32 mask;
        u32 val;
        int shift;
@@ -506,12 +508,13 @@ static int rsnd_src_set_convert_timing_gen1(struct rsnd_mod *mod)
        return 0;
 }
 
-static int rsnd_src_set_convert_rate_gen1(struct rsnd_mod *mod)
+static int rsnd_src_set_convert_rate_gen1(struct rsnd_mod *mod,
+                                         struct rsnd_dai_stream *io)
 {
        struct rsnd_src *src = rsnd_mod_to_src(mod);
        int ret;
 
-       ret = rsnd_src_set_convert_rate(mod);
+       ret = rsnd_src_set_convert_rate(mod, io);
        if (ret < 0)
                return ret;
 
@@ -523,7 +526,7 @@ static int rsnd_src_set_convert_rate_gen1(struct rsnd_mod *mod)
                       rsnd_mod_read(mod, SRC_IFSVR) / 100 * 98);
 
        /* Gen1/Gen2 are not compatible */
-       if (rsnd_src_convert_rate(src))
+       if (rsnd_src_convert_rate(io, src))
                rsnd_mod_write(mod, SRC_ROUTE_MODE0, 1);
 
        /* no SRC_BFSSR settings, since SRC_SRCCR::BUFMD is 0 */
@@ -532,6 +535,7 @@ static int rsnd_src_set_convert_rate_gen1(struct rsnd_mod *mod)
 }
 
 static int rsnd_src_init_gen1(struct rsnd_mod *mod,
+                             struct rsnd_dai_stream *io,
                              struct rsnd_priv *priv)
 {
        int ret;
@@ -540,15 +544,15 @@ static int rsnd_src_init_gen1(struct rsnd_mod *mod,
        if (ret < 0)
                return ret;
 
-       ret = rsnd_src_set_route_gen1(mod);
+       ret = rsnd_src_set_route_gen1(io, mod);
        if (ret < 0)
                return ret;
 
-       ret = rsnd_src_set_convert_rate_gen1(mod);
+       ret = rsnd_src_set_convert_rate_gen1(mod, io);
        if (ret < 0)
                return ret;
 
-       ret = rsnd_src_set_convert_timing_gen1(mod);
+       ret = rsnd_src_set_convert_timing_gen1(io, mod);
        if (ret < 0)
                return ret;
 
@@ -556,6 +560,7 @@ static int rsnd_src_init_gen1(struct rsnd_mod *mod,
 }
 
 static int rsnd_src_start_gen1(struct rsnd_mod *mod,
+                              struct rsnd_dai_stream *io,
                               struct rsnd_priv *priv)
 {
        int id = rsnd_mod_id(mod);
@@ -566,6 +571,7 @@ static int rsnd_src_start_gen1(struct rsnd_mod *mod,
 }
 
 static int rsnd_src_stop_gen1(struct rsnd_mod *mod,
+                             struct rsnd_dai_stream *io,
                              struct rsnd_priv *priv)
 {
        int id = rsnd_mod_id(mod);
@@ -643,9 +649,9 @@ static bool rsnd_src_error_record_gen2(struct rsnd_mod *mod)
        return ret;
 }
 
-static int _rsnd_src_start_gen2(struct rsnd_mod *mod)
+static int _rsnd_src_start_gen2(struct rsnd_mod *mod,
+                               struct rsnd_dai_stream *io)
 {
-       struct rsnd_dai_stream *io = rsnd_mod_to_io(mod);
        u32 val = rsnd_io_to_mod_dvc(io) ? 0x01 : 0x11;
 
        rsnd_mod_write(mod, SRC_CTRL, val);
@@ -670,13 +676,16 @@ static int _rsnd_src_stop_gen2(struct rsnd_mod *mod)
        return rsnd_src_stop(mod);
 }
 
-static irqreturn_t rsnd_src_interrupt_gen2(int irq, void *data)
+static void __rsnd_src_interrupt_gen2(struct rsnd_mod *mod,
+                                     struct rsnd_dai_stream *io)
 {
-       struct rsnd_mod *mod = data;
-       struct rsnd_dai_stream *io = rsnd_mod_to_io(mod);
+       struct rsnd_priv *priv = rsnd_mod_to_priv(mod);
 
-       if (!io)
-               return IRQ_NONE;
+       spin_lock(&priv->lock);
+
+       /* ignore all cases if not working */
+       if (!rsnd_io_is_working(io))
+               goto rsnd_src_interrupt_gen2_out;
 
        if (rsnd_src_error_record_gen2(mod)) {
                struct rsnd_priv *priv = rsnd_mod_to_priv(mod);
@@ -688,22 +697,32 @@ static irqreturn_t rsnd_src_interrupt_gen2(int irq, void *data)
 
                _rsnd_src_stop_gen2(mod);
                if (src->err < 1024)
-                       _rsnd_src_start_gen2(mod);
+                       _rsnd_src_start_gen2(mod, io);
                else
                        dev_warn(dev, "no more SRC restart\n");
        }
 
+rsnd_src_interrupt_gen2_out:
+       spin_unlock(&priv->lock);
+}
+
+static irqreturn_t rsnd_src_interrupt_gen2(int irq, void *data)
+{
+       struct rsnd_mod *mod = data;
+
+       rsnd_mod_interrupt(mod, __rsnd_src_interrupt_gen2);
+
        return IRQ_HANDLED;
 }
 
-static int rsnd_src_set_convert_rate_gen2(struct rsnd_mod *mod)
+static int rsnd_src_set_convert_rate_gen2(struct rsnd_mod *mod,
+                                         struct rsnd_dai_stream *io)
 {
        struct rsnd_priv *priv = rsnd_mod_to_priv(mod);
        struct device *dev = rsnd_priv_to_dev(priv);
-       struct rsnd_dai_stream *io = rsnd_mod_to_io(mod);
        struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io);
        struct rsnd_src *src = rsnd_mod_to_src(mod);
-       u32 convert_rate = rsnd_src_convert_rate(src);
+       u32 convert_rate = rsnd_src_convert_rate(io, src);
        u32 cr, route;
        uint ratio;
        int ret;
@@ -721,7 +740,7 @@ static int rsnd_src_set_convert_rate_gen2(struct rsnd_mod *mod)
                return -EINVAL;
        }
 
-       ret = rsnd_src_set_convert_rate(mod);
+       ret = rsnd_src_set_convert_rate(mod, io);
        if (ret < 0)
                return ret;
 
@@ -757,12 +776,12 @@ static int rsnd_src_set_convert_rate_gen2(struct rsnd_mod *mod)
        return 0;
 }
 
-static int rsnd_src_set_convert_timing_gen2(struct rsnd_mod *mod)
+static int rsnd_src_set_convert_timing_gen2(struct rsnd_dai_stream *io,
+                                           struct rsnd_mod *mod)
 {
-       struct rsnd_dai_stream *io = rsnd_mod_to_io(mod);
        struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io);
        struct rsnd_src *src = rsnd_mod_to_src(mod);
-       u32 convert_rate = rsnd_src_convert_rate(src);
+       u32 convert_rate = rsnd_src_convert_rate(io, src);
        int ret;
 
        if (convert_rate)
@@ -776,6 +795,7 @@ static int rsnd_src_set_convert_timing_gen2(struct rsnd_mod *mod)
 }
 
 static int rsnd_src_probe_gen2(struct rsnd_mod *mod,
+                              struct rsnd_dai_stream *io,
                               struct rsnd_priv *priv)
 {
        struct rsnd_src *src = rsnd_mod_to_src(mod);
@@ -797,7 +817,7 @@ static int rsnd_src_probe_gen2(struct rsnd_mod *mod,
                        return ret;
        }
 
-       ret = rsnd_dma_init(priv,
+       ret = rsnd_dma_init(io,
                            rsnd_mod_to_dma(mod),
                            src->info->dma_id);
 
@@ -805,14 +825,16 @@ static int rsnd_src_probe_gen2(struct rsnd_mod *mod,
 }
 
 static int rsnd_src_remove_gen2(struct rsnd_mod *mod,
+                               struct rsnd_dai_stream *io,
                                struct rsnd_priv *priv)
 {
-       rsnd_dma_quit(rsnd_mod_to_dma(mod));
+       rsnd_dma_quit(io, rsnd_mod_to_dma(mod));
 
        return 0;
 }
 
 static int rsnd_src_init_gen2(struct rsnd_mod *mod,
+                             struct rsnd_dai_stream *io,
                              struct rsnd_priv *priv)
 {
        int ret;
@@ -821,11 +843,11 @@ static int rsnd_src_init_gen2(struct rsnd_mod *mod,
        if (ret < 0)
                return ret;
 
-       ret = rsnd_src_set_convert_rate_gen2(mod);
+       ret = rsnd_src_set_convert_rate_gen2(mod, io);
        if (ret < 0)
                return ret;
 
-       ret = rsnd_src_set_convert_timing_gen2(mod);
+       ret = rsnd_src_set_convert_timing_gen2(io, mod);
        if (ret < 0)
                return ret;
 
@@ -833,31 +855,33 @@ static int rsnd_src_init_gen2(struct rsnd_mod *mod,
 }
 
 static int rsnd_src_start_gen2(struct rsnd_mod *mod,
+                              struct rsnd_dai_stream *io,
                               struct rsnd_priv *priv)
 {
-       rsnd_dma_start(rsnd_mod_to_dma(mod));
+       rsnd_dma_start(io, rsnd_mod_to_dma(mod));
 
-       return _rsnd_src_start_gen2(mod);
+       return _rsnd_src_start_gen2(mod, io);
 }
 
 static int rsnd_src_stop_gen2(struct rsnd_mod *mod,
+                             struct rsnd_dai_stream *io,
                              struct rsnd_priv *priv)
 {
        int ret;
 
        ret = _rsnd_src_stop_gen2(mod);
 
-       rsnd_dma_stop(rsnd_mod_to_dma(mod));
+       rsnd_dma_stop(io, rsnd_mod_to_dma(mod));
 
        return ret;
 }
 
-static void rsnd_src_reconvert_update(struct rsnd_mod *mod)
+static void rsnd_src_reconvert_update(struct rsnd_dai_stream *io,
+                                     struct rsnd_mod *mod)
 {
-       struct rsnd_dai_stream *io = rsnd_mod_to_io(mod);
        struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io);
        struct rsnd_src *src = rsnd_mod_to_src(mod);
-       u32 convert_rate = rsnd_src_convert_rate(src);
+       u32 convert_rate = rsnd_src_convert_rate(io, src);
        u32 fsrate;
 
        if (!runtime)
@@ -873,10 +897,10 @@ static void rsnd_src_reconvert_update(struct rsnd_mod *mod)
 }
 
 static int rsnd_src_pcm_new(struct rsnd_mod *mod,
+                           struct rsnd_dai_stream *io,
                            struct snd_soc_pcm_runtime *rtd)
 {
        struct rsnd_priv *priv = rsnd_mod_to_priv(mod);
-       struct rsnd_dai_stream *io = rsnd_mod_to_io(mod);
        struct rsnd_dai *rdai = rsnd_io_to_rdai(io);
        struct rsnd_src *src = rsnd_mod_to_src(mod);
        int ret;
@@ -907,7 +931,7 @@ static int rsnd_src_pcm_new(struct rsnd_mod *mod,
        /*
         * enable sync convert
         */
-       ret = rsnd_kctrl_new_s(mod, rtd,
+       ret = rsnd_kctrl_new_s(mod, io, rtd,
                               rsnd_io_is_play(io) ?
                               "SRC Out Rate Switch" :
                               "SRC In Rate Switch",
@@ -916,7 +940,7 @@ static int rsnd_src_pcm_new(struct rsnd_mod *mod,
        if (ret < 0)
                return ret;
 
-       ret = rsnd_kctrl_new_s(mod, rtd,
+       ret = rsnd_kctrl_new_s(mod, io, rtd,
                               rsnd_io_is_play(io) ?
                               "SRC Out Rate" :
                               "SRC In Rate",
@@ -1041,7 +1065,7 @@ int rsnd_src_probe(struct platform_device *pdev,
 
                src->info = &info->src_info[i];
 
-               ret = rsnd_mod_init(&src->mod, ops, clk, RSND_MOD_SRC, i);
+               ret = rsnd_mod_init(priv, &src->mod, ops, clk, RSND_MOD_SRC, i);
                if (ret)
                        return ret;
        }
index 7bb9c087f3dc458a0dbd4ef6fe01c7d8c44ac7f4..2fbe59f7f9b5a845f5b97376de05bad6ff9c162f 100644 (file)
@@ -66,6 +66,7 @@ struct rsnd_ssi {
 
        u32 cr_own;
        u32 cr_clk;
+       int chan;
        int err;
        unsigned int usrcnt;
 };
@@ -80,16 +81,15 @@ struct rsnd_ssi {
 #define rsnd_mod_to_ssi(_mod) container_of((_mod), struct rsnd_ssi, mod)
 #define rsnd_dma_to_ssi(dma)  rsnd_mod_to_ssi(rsnd_dma_to_mod(dma))
 #define rsnd_ssi_pio_available(ssi) ((ssi)->info->irq > 0)
-#define rsnd_ssi_clk_from_parent(ssi) ((ssi)->parent)
+#define rsnd_ssi_parent(ssi) ((ssi)->parent)
 #define rsnd_ssi_mode_flags(p) ((p)->info->flags)
 #define rsnd_ssi_dai_id(ssi) ((ssi)->info->dai_id)
 #define rsnd_ssi_of_node(priv) \
        of_get_child_by_name(rsnd_priv_to_dev(priv)->of_node, "rcar_sound,ssi")
 
-int rsnd_ssi_use_busif(struct rsnd_mod *mod)
+int rsnd_ssi_use_busif(struct rsnd_dai_stream *io, struct rsnd_mod *mod)
 {
        struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod);
-       struct rsnd_dai_stream *io = rsnd_mod_to_io(mod);
        int use_busif = 0;
 
        if (!rsnd_ssi_is_dma_mode(mod))
@@ -189,22 +189,26 @@ static void rsnd_ssi_hw_start(struct rsnd_ssi *ssi,
                rsnd_mod_hw_start(&ssi->mod);
 
                if (rsnd_rdai_is_clk_master(rdai)) {
-                       if (rsnd_ssi_clk_from_parent(ssi))
-                               rsnd_ssi_hw_start(ssi->parent, io);
+                       struct rsnd_ssi *ssi_parent = rsnd_ssi_parent(ssi);
+
+                       if (ssi_parent)
+                               rsnd_ssi_hw_start(ssi_parent, io);
                        else
                                rsnd_ssi_master_clk_start(ssi, io);
                }
        }
 
-       cr_mode = rsnd_ssi_is_dma_mode(&ssi->mod) ?
-               DMEN :  /* DMA : enable DMA */
-               DIEN;   /* PIO : enable Data interrupt */
-
+       if (rsnd_ssi_is_dma_mode(&ssi->mod)) {
+               cr_mode = UIEN | OIEN | /* over/under run */
+                         DMEN;         /* DMA : enable DMA */
+       } else {
+               cr_mode = DIEN;         /* PIO : enable Data interrupt */
+       }
 
        cr  =   ssi->cr_own     |
                ssi->cr_clk     |
                cr_mode         |
-               UIEN | OIEN | EN;
+               EN;
 
        rsnd_mod_write(&ssi->mod, SSICR, cr);
 
@@ -221,16 +225,17 @@ static void rsnd_ssi_hw_start(struct rsnd_ssi *ssi,
                rsnd_mod_name(&ssi->mod), rsnd_mod_id(&ssi->mod));
 }
 
-static void rsnd_ssi_hw_stop(struct rsnd_ssi *ssi)
+static void rsnd_ssi_hw_stop(struct rsnd_dai_stream *io, struct rsnd_ssi *ssi)
 {
        struct rsnd_priv *priv = rsnd_mod_to_priv(&ssi->mod);
-       struct rsnd_dai_stream *io = rsnd_mod_to_io(&ssi->mod);
        struct rsnd_dai *rdai = rsnd_io_to_rdai(io);
        struct device *dev = rsnd_priv_to_dev(priv);
        u32 cr;
 
-       if (0 == ssi->usrcnt) /* stop might be called without start */
+       if (0 == ssi->usrcnt) {
+               dev_err(dev, "%s called without starting\n", __func__);
                return;
+       }
 
        ssi->usrcnt--;
 
@@ -253,13 +258,17 @@ static void rsnd_ssi_hw_stop(struct rsnd_ssi *ssi)
                rsnd_ssi_status_check(&ssi->mod, IIRQ);
 
                if (rsnd_rdai_is_clk_master(rdai)) {
-                       if (rsnd_ssi_clk_from_parent(ssi))
-                               rsnd_ssi_hw_stop(ssi->parent);
+                       struct rsnd_ssi *ssi_parent = rsnd_ssi_parent(ssi);
+
+                       if (ssi_parent)
+                               rsnd_ssi_hw_stop(io, ssi_parent);
                        else
                                rsnd_ssi_master_clk_stop(ssi);
                }
 
                rsnd_mod_hw_stop(&ssi->mod);
+
+               ssi->chan = 0;
        }
 
        dev_dbg(dev, "%s[%d] hw stopped\n",
@@ -270,10 +279,10 @@ static void rsnd_ssi_hw_stop(struct rsnd_ssi *ssi)
  *     SSI mod common functions
  */
 static int rsnd_ssi_init(struct rsnd_mod *mod,
+                        struct rsnd_dai_stream *io,
                         struct rsnd_priv *priv)
 {
        struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod);
-       struct rsnd_dai_stream *io = rsnd_mod_to_io(mod);
        struct rsnd_dai *rdai = rsnd_io_to_rdai(io);
        struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io);
        u32 cr;
@@ -321,6 +330,7 @@ static int rsnd_ssi_init(struct rsnd_mod *mod,
 }
 
 static int rsnd_ssi_quit(struct rsnd_mod *mod,
+                        struct rsnd_dai_stream *io,
                         struct rsnd_priv *priv)
 {
        struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod);
@@ -336,6 +346,37 @@ static int rsnd_ssi_quit(struct rsnd_mod *mod,
        return 0;
 }
 
+static int rsnd_ssi_hw_params(struct rsnd_mod *mod,
+                             struct rsnd_dai_stream *io,
+                             struct snd_pcm_substream *substream,
+                             struct snd_pcm_hw_params *params)
+{
+       struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod);
+       struct rsnd_ssi *ssi_parent = rsnd_ssi_parent(ssi);
+       int chan = params_channels(params);
+
+       /*
+        * Already working.
+        * It will happen if SSI has parent/child connection.
+        */
+       if (ssi->usrcnt) {
+               /*
+                * it is error if child <-> parent SSI uses
+                * different channels.
+                */
+               if (ssi->chan != chan)
+                       return -EIO;
+       }
+
+       /* It will be removed on rsnd_ssi_hw_stop */
+       ssi->chan = chan;
+       if (ssi_parent)
+               return rsnd_ssi_hw_params(&ssi_parent->mod, io,
+                                         substream, params);
+
+       return 0;
+}
+
 static void rsnd_ssi_record_error(struct rsnd_ssi *ssi, u32 status)
 {
        /* under/over flow error */
@@ -348,12 +389,12 @@ static void rsnd_ssi_record_error(struct rsnd_ssi *ssi, u32 status)
 }
 
 static int rsnd_ssi_start(struct rsnd_mod *mod,
+                         struct rsnd_dai_stream *io,
                          struct rsnd_priv *priv)
 {
        struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod);
-       struct rsnd_dai_stream *io = rsnd_mod_to_io(mod);
 
-       rsnd_src_ssiu_start(mod, rsnd_ssi_use_busif(mod));
+       rsnd_src_ssiu_start(mod, io, rsnd_ssi_use_busif(io, mod));
 
        rsnd_ssi_hw_start(ssi, io);
 
@@ -363,6 +404,7 @@ static int rsnd_ssi_start(struct rsnd_mod *mod,
 }
 
 static int rsnd_ssi_stop(struct rsnd_mod *mod,
+                        struct rsnd_dai_stream *io,
                         struct rsnd_priv *priv)
 {
        struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod);
@@ -371,24 +413,29 @@ static int rsnd_ssi_stop(struct rsnd_mod *mod,
 
        rsnd_ssi_record_error(ssi, rsnd_mod_read(mod, SSISR));
 
-       rsnd_ssi_hw_stop(ssi);
+       rsnd_ssi_hw_stop(io, ssi);
 
-       rsnd_src_ssiu_stop(mod);
+       rsnd_src_ssiu_stop(mod, io);
 
        return 0;
 }
 
-static irqreturn_t rsnd_ssi_interrupt(int irq, void *data)
+static void __rsnd_ssi_interrupt(struct rsnd_mod *mod,
+                                struct rsnd_dai_stream *io)
 {
-       struct rsnd_ssi *ssi = data;
-       struct rsnd_mod *mod = &ssi->mod;
+       struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod);
        struct rsnd_priv *priv = rsnd_mod_to_priv(mod);
-       struct rsnd_dai_stream *io = rsnd_mod_to_io(mod);
        int is_dma = rsnd_ssi_is_dma_mode(mod);
-       u32 status = rsnd_mod_read(mod, SSISR);
+       u32 status;
+       bool elapsed = false;
+
+       spin_lock(&priv->lock);
+
+       /* ignore all cases if not working */
+       if (!rsnd_io_is_working(io))
+               goto rsnd_ssi_interrupt_out;
 
-       if (!io)
-               return IRQ_NONE;
+       status = rsnd_mod_read(mod, SSISR);
 
        /* PIO only */
        if (!is_dma && (status & DIRQ)) {
@@ -406,11 +453,11 @@ static irqreturn_t rsnd_ssi_interrupt(int irq, void *data)
                else
                        *buf = rsnd_mod_read(mod, SSIRDR);
 
-               rsnd_dai_pointer_update(io, sizeof(*buf));
+               elapsed = rsnd_dai_pointer_update(io, sizeof(*buf));
        }
 
-       /* PIO / DMA */
-       if (status & (UIRQ | OIRQ)) {
+       /* DMA only */
+       if (is_dma && (status & (UIRQ | OIRQ))) {
                struct device *dev = rsnd_priv_to_dev(priv);
 
                /*
@@ -419,15 +466,28 @@ static irqreturn_t rsnd_ssi_interrupt(int irq, void *data)
                dev_dbg(dev, "%s[%d] restart\n",
                        rsnd_mod_name(mod), rsnd_mod_id(mod));
 
-               rsnd_ssi_stop(mod, priv);
+               rsnd_ssi_stop(mod, io, priv);
                if (ssi->err < 1024)
-                       rsnd_ssi_start(mod, priv);
+                       rsnd_ssi_start(mod, io, priv);
                else
                        dev_warn(dev, "no more SSI restart\n");
        }
 
        rsnd_ssi_record_error(ssi, status);
 
+rsnd_ssi_interrupt_out:
+       spin_unlock(&priv->lock);
+
+       if (elapsed)
+               rsnd_dai_period_elapsed(io);
+}
+
+static irqreturn_t rsnd_ssi_interrupt(int irq, void *data)
+{
+       struct rsnd_mod *mod = data;
+
+       rsnd_mod_interrupt(mod, __rsnd_ssi_interrupt);
+
        return IRQ_HANDLED;
 }
 
@@ -435,6 +495,7 @@ static irqreturn_t rsnd_ssi_interrupt(int irq, void *data)
  *             SSI PIO
  */
 static int rsnd_ssi_pio_probe(struct rsnd_mod *mod,
+                             struct rsnd_dai_stream *io,
                              struct rsnd_priv *priv)
 {
        struct device *dev = rsnd_priv_to_dev(priv);
@@ -444,7 +505,7 @@ static int rsnd_ssi_pio_probe(struct rsnd_mod *mod,
        ret = devm_request_irq(dev, ssi->info->irq,
                               rsnd_ssi_interrupt,
                               IRQF_SHARED,
-                              dev_name(dev), ssi);
+                              dev_name(dev), mod);
 
        return ret;
 }
@@ -456,9 +517,11 @@ static struct rsnd_mod_ops rsnd_ssi_pio_ops = {
        .quit   = rsnd_ssi_quit,
        .start  = rsnd_ssi_start,
        .stop   = rsnd_ssi_stop,
+       .hw_params = rsnd_ssi_hw_params,
 };
 
 static int rsnd_ssi_dma_probe(struct rsnd_mod *mod,
+                             struct rsnd_dai_stream *io,
                              struct rsnd_priv *priv)
 {
        struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod);
@@ -469,25 +532,26 @@ static int rsnd_ssi_dma_probe(struct rsnd_mod *mod,
        ret = devm_request_irq(dev, ssi->info->irq,
                               rsnd_ssi_interrupt,
                               IRQF_SHARED,
-                              dev_name(dev), ssi);
+                              dev_name(dev), mod);
        if (ret)
                return ret;
 
        ret = rsnd_dma_init(
-               priv, rsnd_mod_to_dma(mod),
+               io, rsnd_mod_to_dma(mod),
                dma_id);
 
        return ret;
 }
 
 static int rsnd_ssi_dma_remove(struct rsnd_mod *mod,
+                              struct rsnd_dai_stream *io,
                               struct rsnd_priv *priv)
 {
        struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod);
        struct device *dev = rsnd_priv_to_dev(priv);
        int irq = ssi->info->irq;
 
-       rsnd_dma_quit(rsnd_mod_to_dma(mod));
+       rsnd_dma_quit(io, rsnd_mod_to_dma(mod));
 
        /* PIO will request IRQ again */
        devm_free_irq(dev, irq, ssi);
@@ -496,6 +560,7 @@ static int rsnd_ssi_dma_remove(struct rsnd_mod *mod,
 }
 
 static int rsnd_ssi_fallback(struct rsnd_mod *mod,
+                            struct rsnd_dai_stream *io,
                             struct rsnd_priv *priv)
 {
        struct device *dev = rsnd_priv_to_dev(priv);
@@ -516,37 +581,39 @@ static int rsnd_ssi_fallback(struct rsnd_mod *mod,
 }
 
 static int rsnd_ssi_dma_start(struct rsnd_mod *mod,
+                             struct rsnd_dai_stream *io,
                              struct rsnd_priv *priv)
 {
        struct rsnd_dma *dma = rsnd_mod_to_dma(mod);
 
-       rsnd_dma_start(dma);
+       rsnd_dma_start(io, dma);
 
-       rsnd_ssi_start(mod, priv);
+       rsnd_ssi_start(mod, io, priv);
 
        return 0;
 }
 
 static int rsnd_ssi_dma_stop(struct rsnd_mod *mod,
+                            struct rsnd_dai_stream *io,
                             struct rsnd_priv *priv)
 {
        struct rsnd_dma *dma = rsnd_mod_to_dma(mod);
 
-       rsnd_ssi_stop(mod, priv);
+       rsnd_ssi_stop(mod, io, priv);
 
-       rsnd_dma_stop(dma);
+       rsnd_dma_stop(io, dma);
 
        return 0;
 }
 
-static struct dma_chan *rsnd_ssi_dma_req(struct rsnd_mod *mod)
+static struct dma_chan *rsnd_ssi_dma_req(struct rsnd_dai_stream *io,
+                                        struct rsnd_mod *mod)
 {
        struct rsnd_priv *priv = rsnd_mod_to_priv(mod);
-       struct rsnd_dai_stream *io = rsnd_mod_to_io(mod);
        int is_play = rsnd_io_is_play(io);
        char *name;
 
-       if (rsnd_ssi_use_busif(mod))
+       if (rsnd_ssi_use_busif(io, mod))
                name = is_play ? "rxu" : "txu";
        else
                name = is_play ? "rx" : "tx";
@@ -565,6 +632,7 @@ static struct rsnd_mod_ops rsnd_ssi_dma_ops = {
        .start  = rsnd_ssi_dma_start,
        .stop   = rsnd_ssi_dma_stop,
        .fallback = rsnd_ssi_fallback,
+       .hw_params = rsnd_ssi_hw_params,
 };
 
 int rsnd_ssi_is_dma_mode(struct rsnd_mod *mod)
@@ -598,7 +666,7 @@ int rsnd_ssi_is_pin_sharing(struct rsnd_mod *mod)
        return !!(rsnd_ssi_mode_flags(ssi) & RSND_SSI_CLK_PIN_SHARE);
 }
 
-static void rsnd_ssi_parent_clk_setup(struct rsnd_priv *priv, struct rsnd_ssi *ssi)
+static void rsnd_ssi_parent_setup(struct rsnd_priv *priv, struct rsnd_ssi *ssi)
 {
        if (!rsnd_ssi_is_pin_sharing(&ssi->mod))
                return;
@@ -728,11 +796,11 @@ int rsnd_ssi_probe(struct platform_device *pdev,
                else if (rsnd_ssi_pio_available(ssi))
                        ops = &rsnd_ssi_pio_ops;
 
-               ret = rsnd_mod_init(&ssi->mod, ops, clk, RSND_MOD_SSI, i);
+               ret = rsnd_mod_init(priv, &ssi->mod, ops, clk, RSND_MOD_SSI, i);
                if (ret)
                        return ret;
 
-               rsnd_ssi_parent_clk_setup(priv, ssi);
+               rsnd_ssi_parent_setup(priv, ssi);
        }
 
        return 0;
index 23732523f87c72e24488e4655ff03cb5271b3f16..3a4a5c0e3f9737c795f74367b04c9825462651f8 100644 (file)
@@ -40,6 +40,7 @@
 #include <sound/pcm_params.h>
 #include <sound/soc.h>
 #include <sound/soc-dpcm.h>
+#include <sound/soc-topology.h>
 #include <sound/initval.h>
 
 #define CREATE_TRACE_POINTS
@@ -92,30 +93,21 @@ static int format_register_str(struct snd_soc_codec *codec,
        int wordsize = min_bytes_needed(codec->driver->reg_cache_size) * 2;
        int regsize = codec->driver->reg_word_size * 2;
        int ret;
-       char tmpbuf[len + 1];
-       char regbuf[regsize + 1];
-
-       /* since tmpbuf is allocated on the stack, warn the callers if they
-        * try to abuse this function */
-       WARN_ON(len > 63);
 
        /* +2 for ': ' and + 1 for '\n' */
        if (wordsize + regsize + 2 + 1 != len)
                return -EINVAL;
 
-       ret = snd_soc_read(codec, reg);
-       if (ret < 0) {
-               memset(regbuf, 'X', regsize);
-               regbuf[regsize] = '\0';
-       } else {
-               snprintf(regbuf, regsize + 1, "%.*x", regsize, ret);
-       }
-
-       /* prepare the buffer */
-       snprintf(tmpbuf, len + 1, "%.*x: %s\n", wordsize, reg, regbuf);
-       /* copy it back to the caller without the '\0' */
-       memcpy(buf, tmpbuf, len);
+       sprintf(buf, "%.*x: ", wordsize, reg);
+       buf += wordsize + 2;
 
+       ret = snd_soc_read(codec, reg);
+       if (ret < 0)
+               memset(buf, 'X', regsize);
+       else
+               sprintf(buf, "%.*x", regsize, ret);
+       buf[regsize] = '\n';
+       /* no NUL-termination needed */
        return 0;
 }
 
@@ -750,23 +742,10 @@ static void soc_resume_deferred(struct work_struct *work)
        }
 
        list_for_each_entry(codec, &card->codec_dev_list, card_list) {
-               /* If the CODEC was idle over suspend then it will have been
-                * left with bias OFF or STANDBY and suspended so we must now
-                * resume.  Otherwise the suspend was suppressed.
-                */
                if (codec->suspended) {
-                       switch (codec->dapm.bias_level) {
-                       case SND_SOC_BIAS_STANDBY:
-                       case SND_SOC_BIAS_OFF:
-                               if (codec->driver->resume)
-                                       codec->driver->resume(codec);
-                               codec->suspended = 0;
-                               break;
-                       default:
-                               dev_dbg(codec->dev,
-                                       "ASoC: CODEC was on over suspend\n");
-                               break;
-                       }
+                       if (codec->driver->resume)
+                               codec->driver->resume(codec);
+                       codec->suspended = 0;
                }
        }
 
@@ -904,12 +883,17 @@ static struct snd_soc_dai *snd_soc_find_dai(
 {
        struct snd_soc_component *component;
        struct snd_soc_dai *dai;
+       struct device_node *component_of_node;
 
        lockdep_assert_held(&client_mutex);
 
        /* Find CPU DAI from registered DAIs*/
        list_for_each_entry(component, &component_list, list) {
-               if (dlc->of_node && component->dev->of_node != dlc->of_node)
+               component_of_node = component->dev->of_node;
+               if (!component_of_node && component->dev->parent)
+                       component_of_node = component->dev->parent->of_node;
+
+               if (dlc->of_node && component_of_node != dlc->of_node)
                        continue;
                if (dlc->name && strcmp(component->name, dlc->name))
                        continue;
@@ -2435,6 +2419,7 @@ int snd_soc_register_card(struct snd_soc_card *card)
                card->rtd_aux[i].card = card;
 
        INIT_LIST_HEAD(&card->dapm_dirty);
+       INIT_LIST_HEAD(&card->dobj_list);
        card->instantiated = 0;
        mutex_init(&card->mutex);
        mutex_init(&card->dapm_mutex);
@@ -2599,7 +2584,8 @@ static int snd_soc_register_dais(struct snd_soc_component *component,
                 * the same naming style even though those DAIs are not
                 * component-less anymore.
                 */
-               if (count == 1 && legacy_dai_naming) {
+               if (count == 1 && legacy_dai_naming &&
+                       (dai_drv[i].id == 0 || dai_drv[i].name == NULL)) {
                        dai->name = fmt_single_name(dev, &dai->id);
                } else {
                        dai->name = fmt_multiple_name(dev, &dai_drv[i]);
@@ -2749,6 +2735,7 @@ static void snd_soc_component_add_unlocked(struct snd_soc_component *component)
        }
 
        list_add(&component->list, &component_list);
+       INIT_LIST_HEAD(&component->dobj_list);
 }
 
 static void snd_soc_component_add(struct snd_soc_component *component)
@@ -2825,6 +2812,7 @@ void snd_soc_unregister_component(struct device *dev)
        return;
 
 found:
+       snd_soc_tplg_component_remove(cmpnt, SND_SOC_TPLG_INDEX_ALL);
        snd_soc_component_del_unlocked(cmpnt);
        mutex_unlock(&client_mutex);
        snd_soc_component_cleanup(cmpnt);
@@ -3488,11 +3476,16 @@ static int snd_soc_get_dai_name(struct of_phandle_args *args,
                                const char **dai_name)
 {
        struct snd_soc_component *pos;
+       struct device_node *component_of_node;
        int ret = -EPROBE_DEFER;
 
        mutex_lock(&client_mutex);
        list_for_each_entry(pos, &component_list, list) {
-               if (pos->dev->of_node != args->np)
+               component_of_node = pos->dev->of_node;
+               if (!component_of_node && pos->dev->parent)
+                       component_of_node = pos->dev->parent->of_node;
+
+               if (component_of_node != args->np)
                        continue;
 
                if (pos->driver->of_xlate_dai_name) {
index defe0f0082b5e8877d6ae092d53395c6387fbaff..aa327c92480c56c2609699380594a75ad765fbda 100644 (file)
@@ -52,10 +52,15 @@ static int snd_soc_dapm_add_path(struct snd_soc_dapm_context *dapm,
        const char *control,
        int (*connected)(struct snd_soc_dapm_widget *source,
                         struct snd_soc_dapm_widget *sink));
-static struct snd_soc_dapm_widget *
+
+struct snd_soc_dapm_widget *
 snd_soc_dapm_new_control(struct snd_soc_dapm_context *dapm,
                         const struct snd_soc_dapm_widget *widget);
 
+struct snd_soc_dapm_widget *
+snd_soc_dapm_new_control_unlocked(struct snd_soc_dapm_context *dapm,
+                        const struct snd_soc_dapm_widget *widget);
+
 /* dapm power sequences - make this per codec in the future */
 static int dapm_up_seq[] = {
        [snd_soc_dapm_pre] = 0,
@@ -70,6 +75,7 @@ static int dapm_up_seq[] = {
        [snd_soc_dapm_aif_out] = 4,
        [snd_soc_dapm_mic] = 5,
        [snd_soc_dapm_mux] = 6,
+       [snd_soc_dapm_demux] = 6,
        [snd_soc_dapm_dac] = 7,
        [snd_soc_dapm_switch] = 8,
        [snd_soc_dapm_mixer] = 8,
@@ -100,6 +106,7 @@ static int dapm_down_seq[] = {
        [snd_soc_dapm_mic] = 7,
        [snd_soc_dapm_micbias] = 8,
        [snd_soc_dapm_mux] = 9,
+       [snd_soc_dapm_demux] = 9,
        [snd_soc_dapm_aif_in] = 10,
        [snd_soc_dapm_aif_out] = 10,
        [snd_soc_dapm_dai_in] = 10,
@@ -308,14 +315,13 @@ static int dapm_kcontrol_data_alloc(struct snd_soc_dapm_widget *widget,
 {
        struct dapm_kcontrol_data *data;
        struct soc_mixer_control *mc;
+       struct soc_enum *e;
+       const char *name;
+       int ret;
 
        data = kzalloc(sizeof(*data), GFP_KERNEL);
-       if (!data) {
-               dev_err(widget->dapm->dev,
-                               "ASoC: can't allocate kcontrol data for %s\n",
-                               widget->name);
+       if (!data)
                return -ENOMEM;
-       }
 
        INIT_LIST_HEAD(&data->paths);
 
@@ -328,6 +334,13 @@ static int dapm_kcontrol_data_alloc(struct snd_soc_dapm_widget *widget,
                if (mc->autodisable) {
                        struct snd_soc_dapm_widget template;
 
+                       name = kasprintf(GFP_KERNEL, "%s %s", kcontrol->id.name,
+                                        "Autodisable");
+                       if (!name) {
+                               ret = -ENOMEM;
+                               goto err_data;
+                       }
+
                        memset(&template, 0, sizeof(template));
                        template.reg = mc->reg;
                        template.mask = (1 << fls(mc->max)) - 1;
@@ -338,18 +351,55 @@ static int dapm_kcontrol_data_alloc(struct snd_soc_dapm_widget *widget,
                                template.off_val = 0;
                        template.on_val = template.off_val;
                        template.id = snd_soc_dapm_kcontrol;
-                       template.name = kcontrol->id.name;
+                       template.name = name;
 
                        data->value = template.on_val;
 
-                       data->widget = snd_soc_dapm_new_control(widget->dapm,
+                       data->widget =
+                               snd_soc_dapm_new_control_unlocked(widget->dapm,
                                &template);
                        if (!data->widget) {
-                               kfree(data);
-                               return -ENOMEM;
+                               ret = -ENOMEM;
+                               goto err_name;
                        }
                }
                break;
+       case snd_soc_dapm_demux:
+       case snd_soc_dapm_mux:
+               e = (struct soc_enum *)kcontrol->private_value;
+
+               if (e->autodisable) {
+                       struct snd_soc_dapm_widget template;
+
+                       name = kasprintf(GFP_KERNEL, "%s %s", kcontrol->id.name,
+                                        "Autodisable");
+                       if (!name) {
+                               ret = -ENOMEM;
+                               goto err_data;
+                       }
+
+                       memset(&template, 0, sizeof(template));
+                       template.reg = e->reg;
+                       template.mask = e->mask << e->shift_l;
+                       template.shift = e->shift_l;
+                       template.off_val = snd_soc_enum_item_to_val(e, 0);
+                       template.on_val = template.off_val;
+                       template.id = snd_soc_dapm_kcontrol;
+                       template.name = name;
+
+                       data->value = template.on_val;
+
+                       data->widget = snd_soc_dapm_new_control(widget->dapm,
+                                       &template);
+                       if (!data->widget) {
+                               ret = -ENOMEM;
+                               goto err_name;
+                       }
+
+                       snd_soc_dapm_add_path(widget->dapm, data->widget,
+                                             widget, NULL, NULL);
+               }
+               break;
        default:
                break;
        }
@@ -357,11 +407,19 @@ static int dapm_kcontrol_data_alloc(struct snd_soc_dapm_widget *widget,
        kcontrol->private_data = data;
 
        return 0;
+
+err_name:
+       kfree(name);
+err_data:
+       kfree(data);
+       return ret;
 }
 
 static void dapm_kcontrol_free(struct snd_kcontrol *kctl)
 {
        struct dapm_kcontrol_data *data = snd_kcontrol_chip(kctl);
+       if (data->widget)
+               kfree(data->widget->name);
        kfree(data->wlist);
        kfree(data);
 }
@@ -405,11 +463,6 @@ static void dapm_kcontrol_add_path(const struct snd_kcontrol *kcontrol,
        struct dapm_kcontrol_data *data = snd_kcontrol_chip(kcontrol);
 
        list_add_tail(&path->list_kcontrol, &data->paths);
-
-       if (data->widget) {
-               snd_soc_dapm_add_path(data->widget->dapm, data->widget,
-                   path->source, NULL, NULL);
-       }
 }
 
 static bool dapm_kcontrol_is_powered(const struct snd_kcontrol *kcontrol)
@@ -525,6 +578,67 @@ static void soc_dapm_async_complete(struct snd_soc_dapm_context *dapm)
                snd_soc_component_async_complete(dapm->component);
 }
 
+static struct snd_soc_dapm_widget *
+dapm_wcache_lookup(struct snd_soc_dapm_wcache *wcache, const char *name)
+{
+       struct snd_soc_dapm_widget *w = wcache->widget;
+       struct list_head *wlist;
+       const int depth = 2;
+       int i = 0;
+
+       if (w) {
+               wlist = &w->dapm->card->widgets;
+
+               list_for_each_entry_from(w, wlist, list) {
+                       if (!strcmp(name, w->name))
+                               return w;
+
+                       if (++i == depth)
+                               break;
+               }
+       }
+
+       return NULL;
+}
+
+static inline void dapm_wcache_update(struct snd_soc_dapm_wcache *wcache,
+                                     struct snd_soc_dapm_widget *w)
+{
+       wcache->widget = w;
+}
+
+/**
+ * snd_soc_dapm_force_bias_level() - Sets the DAPM bias level
+ * @dapm: The DAPM context for which to set the level
+ * @level: The level to set
+ *
+ * Forces the DAPM bias level to a specific state. It will call the bias level
+ * callback of DAPM context with the specified level. This will even happen if
+ * the context is already at the same level. Furthermore it will not go through
+ * the normal bias level sequencing, meaning any intermediate states between the
+ * current and the target state will not be entered.
+ *
+ * Note that the change in bias level is only temporary and the next time
+ * snd_soc_dapm_sync() is called the state will be set to the level as
+ * determined by the DAPM core. The function is mainly intended to be used to
+ * used during probe or resume from suspend to power up the device so
+ * initialization can be done, before the DAPM core takes over.
+ */
+int snd_soc_dapm_force_bias_level(struct snd_soc_dapm_context *dapm,
+       enum snd_soc_bias_level level)
+{
+       int ret = 0;
+
+       if (dapm->set_bias_level)
+               ret = dapm->set_bias_level(dapm, level);
+
+       if (ret == 0)
+               dapm->bias_level = level;
+
+       return ret;
+}
+EXPORT_SYMBOL_GPL(snd_soc_dapm_force_bias_level);
+
 /**
  * snd_soc_dapm_set_bias_level - set the bias level for the system
  * @dapm: DAPM context
@@ -547,10 +661,8 @@ static int snd_soc_dapm_set_bias_level(struct snd_soc_dapm_context *dapm,
        if (ret != 0)
                goto out;
 
-       if (dapm->set_bias_level)
-               ret = dapm->set_bias_level(dapm, level);
-       else if (!card || dapm != &card->dapm)
-               dapm->bias_level = level;
+       if (!card || dapm != &card->dapm)
+               ret = snd_soc_dapm_force_bias_level(dapm, level);
 
        if (ret != 0)
                goto out;
@@ -565,9 +677,10 @@ out:
 
 /* connect mux widget to its interconnecting audio paths */
 static int dapm_connect_mux(struct snd_soc_dapm_context *dapm,
-       struct snd_soc_dapm_path *path, const char *control_name)
+       struct snd_soc_dapm_path *path, const char *control_name,
+       struct snd_soc_dapm_widget *w)
 {
-       const struct snd_kcontrol_new *kcontrol = &path->sink->kcontrol_news[0];
+       const struct snd_kcontrol_new *kcontrol = &w->kcontrol_news[0];
        struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
        unsigned int val, item;
        int i;
@@ -707,6 +820,7 @@ static int dapm_create_or_share_mixmux_kcontrol(struct snd_soc_dapm_widget *w,
                                wname_in_long_name = false;
                                kcname_in_long_name = true;
                                break;
+                       case snd_soc_dapm_demux:
                        case snd_soc_dapm_mux:
                                wname_in_long_name = true;
                                kcname_in_long_name = false;
@@ -777,6 +891,7 @@ static int dapm_new_mixer(struct snd_soc_dapm_widget *w)
 {
        int i, ret;
        struct snd_soc_dapm_path *path;
+       struct dapm_kcontrol_data *data;
 
        /* add kcontrol */
        for (i = 0; i < w->num_kcontrols; i++) {
@@ -786,16 +901,20 @@ static int dapm_new_mixer(struct snd_soc_dapm_widget *w)
                        if (path->name != (char *)w->kcontrol_news[i].name)
                                continue;
 
-                       if (w->kcontrols[i]) {
-                               dapm_kcontrol_add_path(w->kcontrols[i], path);
-                               continue;
+                       if (!w->kcontrols[i]) {
+                               ret = dapm_create_or_share_mixmux_kcontrol(w, i);
+                               if (ret < 0)
+                                       return ret;
                        }
 
-                       ret = dapm_create_or_share_mixmux_kcontrol(w, i);
-                       if (ret < 0)
-                               return ret;
-
                        dapm_kcontrol_add_path(w->kcontrols[i], path);
+
+                       data = snd_kcontrol_chip(w->kcontrols[i]);
+                       if (data->widget)
+                               snd_soc_dapm_add_path(data->widget->dapm,
+                                                     data->widget,
+                                                     path->source,
+                                                     NULL, NULL);
                }
        }
 
@@ -807,17 +926,32 @@ static int dapm_new_mux(struct snd_soc_dapm_widget *w)
 {
        struct snd_soc_dapm_context *dapm = w->dapm;
        struct snd_soc_dapm_path *path;
+       struct list_head *paths;
+       const char *type;
        int ret;
 
+       switch (w->id) {
+       case snd_soc_dapm_mux:
+               paths = &w->sources;
+               type = "mux";
+               break;
+       case snd_soc_dapm_demux:
+               paths = &w->sinks;
+               type = "demux";
+               break;
+       default:
+               return -EINVAL;
+       }
+
        if (w->num_kcontrols != 1) {
                dev_err(dapm->dev,
-                       "ASoC: mux %s has incorrect number of controls\n",
+                       "ASoC: %s %s has incorrect number of controls\n", type,
                        w->name);
                return -EINVAL;
        }
 
-       if (list_empty(&w->sources)) {
-               dev_err(dapm->dev, "ASoC: mux %s has no paths\n", w->name);
+       if (list_empty(paths)) {
+               dev_err(dapm->dev, "ASoC: %s %s has no paths\n", type, w->name);
                return -EINVAL;
        }
 
@@ -825,9 +959,16 @@ static int dapm_new_mux(struct snd_soc_dapm_widget *w)
        if (ret < 0)
                return ret;
 
-       list_for_each_entry(path, &w->sources, list_sink) {
-               if (path->name)
-                       dapm_kcontrol_add_path(w->kcontrols[0], path);
+       if (w->id == snd_soc_dapm_mux) {
+               list_for_each_entry(path, &w->sources, list_sink) {
+                       if (path->name)
+                               dapm_kcontrol_add_path(w->kcontrols[0], path);
+               }
+       } else {
+               list_for_each_entry(path, &w->sinks, list_source) {
+                       if (path->name)
+                               dapm_kcontrol_add_path(w->kcontrols[0], path);
+               }
        }
 
        return 0;
@@ -2335,6 +2476,50 @@ static void dapm_update_widget_flags(struct snd_soc_dapm_widget *w)
        }
 }
 
+static int snd_soc_dapm_check_dynamic_path(struct snd_soc_dapm_context *dapm,
+       struct snd_soc_dapm_widget *source, struct snd_soc_dapm_widget *sink,
+       const char *control)
+{
+       bool dynamic_source = false;
+       bool dynamic_sink = false;
+
+       if (!control)
+               return 0;
+
+       switch (source->id) {
+       case snd_soc_dapm_demux:
+               dynamic_source = true;
+               break;
+       default:
+               break;
+       }
+
+       switch (sink->id) {
+       case snd_soc_dapm_mux:
+       case snd_soc_dapm_switch:
+       case snd_soc_dapm_mixer:
+       case snd_soc_dapm_mixer_named_ctl:
+               dynamic_sink = true;
+               break;
+       default:
+               break;
+       }
+
+       if (dynamic_source && dynamic_sink) {
+               dev_err(dapm->dev,
+                       "Direct connection between demux and mixer/mux not supported for path %s -> [%s] -> %s\n",
+                       source->name, control, sink->name);
+               return -EINVAL;
+       } else if (!dynamic_source && !dynamic_sink) {
+               dev_err(dapm->dev,
+                       "Control not supported for path %s -> [%s] -> %s\n",
+                       source->name, control, sink->name);
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
 static int snd_soc_dapm_add_path(struct snd_soc_dapm_context *dapm,
        struct snd_soc_dapm_widget *wsource, struct snd_soc_dapm_widget *wsink,
        const char *control,
@@ -2365,6 +2550,10 @@ static int snd_soc_dapm_add_path(struct snd_soc_dapm_context *dapm,
                return -EINVAL;
        }
 
+       ret = snd_soc_dapm_check_dynamic_path(dapm, wsource, wsink, control);
+       if (ret)
+               return ret;
+
        path = kzalloc(sizeof(struct snd_soc_dapm_path), GFP_KERNEL);
        if (!path)
                return -ENOMEM;
@@ -2384,10 +2573,19 @@ static int snd_soc_dapm_add_path(struct snd_soc_dapm_context *dapm,
        if (control == NULL) {
                path->connect = 1;
        } else {
-               /* connect dynamic paths */
+               switch (wsource->id) {
+               case snd_soc_dapm_demux:
+                       ret = dapm_connect_mux(dapm, path, control, wsource);
+                       if (ret)
+                               goto err;
+                       break;
+               default:
+                       break;
+               }
+
                switch (wsink->id) {
                case snd_soc_dapm_mux:
-                       ret = dapm_connect_mux(dapm, path, control);
+                       ret = dapm_connect_mux(dapm, path, control, wsink);
                        if (ret != 0)
                                goto err;
                        break;
@@ -2399,11 +2597,7 @@ static int snd_soc_dapm_add_path(struct snd_soc_dapm_context *dapm,
                                goto err;
                        break;
                default:
-                       dev_err(dapm->dev,
-                               "Control not supported for path %s -> [%s] -> %s\n",
-                               wsource->name, control, wsink->name);
-                       ret = -EINVAL;
-                       goto err;
+                       break;
                }
        }
 
@@ -2451,6 +2645,12 @@ static int snd_soc_dapm_add_route(struct snd_soc_dapm_context *dapm,
                source = route->source;
        }
 
+       wsource = dapm_wcache_lookup(&dapm->path_source_cache, source);
+       wsink = dapm_wcache_lookup(&dapm->path_sink_cache, sink);
+
+       if (wsink && wsource)
+               goto skip_search;
+
        /*
         * find src and dest widgets over all widgets but favor a widget from
         * current DAPM context
@@ -2458,14 +2658,20 @@ static int snd_soc_dapm_add_route(struct snd_soc_dapm_context *dapm,
        list_for_each_entry(w, &dapm->card->widgets, list) {
                if (!wsink && !(strcmp(w->name, sink))) {
                        wtsink = w;
-                       if (w->dapm == dapm)
+                       if (w->dapm == dapm) {
                                wsink = w;
+                               if (wsource)
+                                       break;
+                       }
                        continue;
                }
                if (!wsource && !(strcmp(w->name, source))) {
                        wtsource = w;
-                       if (w->dapm == dapm)
+                       if (w->dapm == dapm) {
                                wsource = w;
+                               if (wsink)
+                                       break;
+                       }
                }
        }
        /* use widget from another DAPM context if not found from this */
@@ -2485,6 +2691,10 @@ static int snd_soc_dapm_add_route(struct snd_soc_dapm_context *dapm,
                return -ENODEV;
        }
 
+skip_search:
+       dapm_wcache_update(&dapm->path_sink_cache, wsink);
+       dapm_wcache_update(&dapm->path_source_cache, wsource);
+
        ret = snd_soc_dapm_add_path(dapm, wsource, wsink, route->control,
                route->connected);
        if (ret)
@@ -2736,6 +2946,7 @@ int snd_soc_dapm_new_widgets(struct snd_soc_card *card)
                        dapm_new_mixer(w);
                        break;
                case snd_soc_dapm_mux:
+               case snd_soc_dapm_demux:
                        dapm_new_mux(w);
                        break;
                case snd_soc_dapm_pga:
@@ -2902,16 +3113,21 @@ int snd_soc_dapm_get_enum_double(struct snd_kcontrol *kcontrol,
        struct snd_ctl_elem_value *ucontrol)
 {
        struct snd_soc_dapm_context *dapm = snd_soc_dapm_kcontrol_dapm(kcontrol);
+       struct snd_soc_card *card = dapm->card;
        struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
        unsigned int reg_val, val;
 
-       if (e->reg != SND_SOC_NOPM) {
+       mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME);
+       if (e->reg != SND_SOC_NOPM && dapm_kcontrol_is_powered(kcontrol)) {
                int ret = soc_dapm_read(dapm, e->reg, &reg_val);
-               if (ret)
+               if (ret) {
+                       mutex_unlock(&card->dapm_mutex);
                        return ret;
+               }
        } else {
                reg_val = dapm_kcontrol_get_value(kcontrol);
        }
+       mutex_unlock(&card->dapm_mutex);
 
        val = (reg_val >> e->shift_l) & e->mask;
        ucontrol->value.enumerated.item[0] = snd_soc_enum_val_to_item(e, val);
@@ -2941,7 +3157,7 @@ int snd_soc_dapm_put_enum_double(struct snd_kcontrol *kcontrol,
        struct snd_soc_card *card = dapm->card;
        struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
        unsigned int *item = ucontrol->value.enumerated.item;
-       unsigned int val, change;
+       unsigned int val, change, reg_change = 0;
        unsigned int mask;
        struct snd_soc_dapm_update update;
        int ret = 0;
@@ -2960,19 +3176,20 @@ int snd_soc_dapm_put_enum_double(struct snd_kcontrol *kcontrol,
 
        mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME);
 
+       change = dapm_kcontrol_set_value(kcontrol, val);
+
        if (e->reg != SND_SOC_NOPM)
-               change = soc_dapm_test_bits(dapm, e->reg, mask, val);
-       else
-               change = dapm_kcontrol_set_value(kcontrol, val);
+               reg_change = soc_dapm_test_bits(dapm, e->reg, mask, val);
 
-       if (change) {
-               if (e->reg != SND_SOC_NOPM) {
+       if (change || reg_change) {
+               if (reg_change) {
                        update.kcontrol = kcontrol;
                        update.reg = e->reg;
                        update.mask = mask;
                        update.val = val;
                        card->update = &update;
                }
+               change |= reg_change;
 
                ret = soc_dapm_mux_update_power(card, kcontrol, item[0], e);
 
@@ -3053,8 +3270,25 @@ int snd_soc_dapm_put_pin_switch(struct snd_kcontrol *kcontrol,
 }
 EXPORT_SYMBOL_GPL(snd_soc_dapm_put_pin_switch);
 
-static struct snd_soc_dapm_widget *
+struct snd_soc_dapm_widget *
 snd_soc_dapm_new_control(struct snd_soc_dapm_context *dapm,
+       const struct snd_soc_dapm_widget *widget)
+{
+       struct snd_soc_dapm_widget *w;
+
+       mutex_lock_nested(&dapm->card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME);
+       w = snd_soc_dapm_new_control_unlocked(dapm, widget);
+       if (!w)
+               dev_err(dapm->dev,
+                       "ASoC: Failed to create DAPM control %s\n",
+                       widget->name);
+
+       mutex_unlock(&dapm->card->dapm_mutex);
+       return w;
+}
+
+struct snd_soc_dapm_widget *
+snd_soc_dapm_new_control_unlocked(struct snd_soc_dapm_context *dapm,
                         const struct snd_soc_dapm_widget *widget)
 {
        struct snd_soc_dapm_widget *w;
@@ -3100,11 +3334,16 @@ snd_soc_dapm_new_control(struct snd_soc_dapm_context *dapm,
        }
 
        prefix = soc_dapm_prefix(dapm);
-       if (prefix)
+       if (prefix) {
                w->name = kasprintf(GFP_KERNEL, "%s %s", prefix, widget->name);
-       else
+               if (widget->sname)
+                       w->sname = kasprintf(GFP_KERNEL, "%s %s", prefix,
+                                            widget->sname);
+       } else {
                w->name = kasprintf(GFP_KERNEL, "%s", widget->name);
-
+               if (widget->sname)
+                       w->sname = kasprintf(GFP_KERNEL, "%s", widget->sname);
+       }
        if (w->name == NULL) {
                kfree(w);
                return NULL;
@@ -3136,6 +3375,7 @@ snd_soc_dapm_new_control(struct snd_soc_dapm_context *dapm,
                w->power_check = dapm_always_on_check_power;
                break;
        case snd_soc_dapm_mux:
+       case snd_soc_dapm_demux:
        case snd_soc_dapm_switch:
        case snd_soc_dapm_mixer:
        case snd_soc_dapm_mixer_named_ctl:
@@ -3169,7 +3409,7 @@ snd_soc_dapm_new_control(struct snd_soc_dapm_context *dapm,
        INIT_LIST_HEAD(&w->sinks);
        INIT_LIST_HEAD(&w->list);
        INIT_LIST_HEAD(&w->dirty);
-       list_add(&w->list, &dapm->card->widgets);
+       list_add_tail(&w->list, &dapm->card->widgets);
 
        w->inputs = -1;
        w->outputs = -1;
@@ -3199,7 +3439,7 @@ int snd_soc_dapm_new_controls(struct snd_soc_dapm_context *dapm,
 
        mutex_lock_nested(&dapm->card->dapm_mutex, SND_SOC_DAPM_CLASS_INIT);
        for (i = 0; i < num; i++) {
-               w = snd_soc_dapm_new_control(dapm, widget);
+               w = snd_soc_dapm_new_control_unlocked(dapm, widget);
                if (!w) {
                        dev_err(dapm->dev,
                                "ASoC: Failed to create DAPM control %s\n",
@@ -3437,7 +3677,7 @@ int snd_soc_dapm_new_pcm(struct snd_soc_card *card,
 
        dev_dbg(card->dev, "ASoC: adding %s widget\n", link_name);
 
-       w = snd_soc_dapm_new_control(&card->dapm, &template);
+       w = snd_soc_dapm_new_control_unlocked(&card->dapm, &template);
        if (!w) {
                dev_err(card->dev, "ASoC: Failed to create %s widget\n",
                        link_name);
@@ -3488,7 +3728,7 @@ int snd_soc_dapm_new_dai_widgets(struct snd_soc_dapm_context *dapm,
                dev_dbg(dai->dev, "ASoC: adding %s widget\n",
                        template.name);
 
-               w = snd_soc_dapm_new_control(dapm, &template);
+               w = snd_soc_dapm_new_control_unlocked(dapm, &template);
                if (!w) {
                        dev_err(dapm->dev, "ASoC: Failed to create %s widget\n",
                                dai->driver->playback.stream_name);
@@ -3507,7 +3747,7 @@ int snd_soc_dapm_new_dai_widgets(struct snd_soc_dapm_context *dapm,
                dev_dbg(dai->dev, "ASoC: adding %s widget\n",
                        template.name);
 
-               w = snd_soc_dapm_new_control(dapm, &template);
+               w = snd_soc_dapm_new_control_unlocked(dapm, &template);
                if (!w) {
                        dev_err(dapm->dev, "ASoC: Failed to create %s widget\n",
                                dai->driver->capture.stream_name);
index c9917ca5de1a50285482da998fb03b305f81a5e0..6fd1906af3873aa90b351649c2d0b8afe7152e9d 100644 (file)
 
 #include <sound/dmaengine_pcm.h>
 
+/*
+ * The platforms dmaengine driver does not support reporting the amount of
+ * bytes that are still left to transfer.
+ */
+#define SND_DMAENGINE_PCM_FLAG_NO_RESIDUE BIT(31)
+
 struct dmaengine_pcm {
        struct dma_chan *chan[SNDRV_PCM_STREAM_LAST + 1];
        const struct snd_dmaengine_pcm_config *config;
@@ -222,14 +228,18 @@ static struct dma_chan *dmaengine_pcm_compat_request_channel(
        return snd_dmaengine_pcm_request_channel(fn, dma_data->filter_data);
 }
 
-static bool dmaengine_pcm_can_report_residue(struct dma_chan *chan)
+static bool dmaengine_pcm_can_report_residue(struct device *dev,
+       struct dma_chan *chan)
 {
        struct dma_slave_caps dma_caps;
        int ret;
 
        ret = dma_get_slave_caps(chan, &dma_caps);
-       if (ret != 0)
-               return true;
+       if (ret != 0) {
+               dev_warn(dev, "Failed to get DMA channel capabilities, falling back to period counting: %d\n",
+                        ret);
+               return false;
+       }
 
        if (dma_caps.residue_granularity == DMA_RESIDUE_GRANULARITY_DESCRIPTOR)
                return false;
@@ -289,14 +299,7 @@ static int dmaengine_pcm_new(struct snd_soc_pcm_runtime *rtd)
                if (ret)
                        return ret;
 
-               /*
-                * This will only return false if we know for sure that at least
-                * one channel does not support residue reporting. If the DMA
-                * driver does not implement the slave_caps API we rely having
-                * the NO_RESIDUE flag set manually in case residue reporting is
-                * not supported.
-                */
-               if (!dmaengine_pcm_can_report_residue(pcm->chan[i]))
+               if (!dmaengine_pcm_can_report_residue(dev, pcm->chan[i]))
                        pcm->flags |= SND_DMAENGINE_PCM_FLAG_NO_RESIDUE;
        }
 
index 9f60c25c4568e7e1280e1ca28058c48c0ca65efa..171c4291ea211fd2caaa83573bf150e3f6597a83 100644 (file)
@@ -315,8 +315,11 @@ int snd_soc_jack_add_gpios(struct snd_soc_jack *jack, int count,
                        goto undo;
                }
 
-               if (gpios[i].gpiod_dev) {
-                       /* GPIO descriptor */
+               if (gpios[i].desc) {
+                       /* Already have a GPIO descriptor. */
+                       goto got_gpio;
+               } else if (gpios[i].gpiod_dev) {
+                       /* Get a GPIO descriptor */
                        gpios[i].desc = gpiod_get_index(gpios[i].gpiod_dev,
                                                        gpios[i].name,
                                                        gpios[i].idx, GPIOD_IN);
@@ -344,7 +347,7 @@ int snd_soc_jack_add_gpios(struct snd_soc_jack *jack, int count,
 
                        gpios[i].desc = gpio_to_desc(gpios[i].gpio);
                }
-
+got_gpio:
                INIT_DELAYED_WORK(&gpios[i].work, gpio_work);
                gpios[i].jack = jack;
 
index 35fe58f4fa86240b176db74c1789065c62bd17a7..256b9c91aa94316979a270aa7459c83a0659b5da 100644 (file)
@@ -1485,30 +1485,67 @@ unwind:
 }
 
 static void dpcm_init_runtime_hw(struct snd_pcm_runtime *runtime,
-       struct snd_soc_pcm_stream *stream)
+                                struct snd_soc_pcm_stream *stream,
+                                u64 formats)
 {
        runtime->hw.rate_min = stream->rate_min;
        runtime->hw.rate_max = stream->rate_max;
        runtime->hw.channels_min = stream->channels_min;
        runtime->hw.channels_max = stream->channels_max;
        if (runtime->hw.formats)
-               runtime->hw.formats &= stream->formats;
+               runtime->hw.formats &= formats & stream->formats;
        else
-               runtime->hw.formats = stream->formats;
+               runtime->hw.formats = formats & stream->formats;
        runtime->hw.rates = stream->rates;
 }
 
+static u64 dpcm_runtime_base_format(struct snd_pcm_substream *substream)
+{
+       struct snd_soc_pcm_runtime *fe = substream->private_data;
+       struct snd_soc_dpcm *dpcm;
+       u64 formats = ULLONG_MAX;
+       int stream = substream->stream;
+
+       if (!fe->dai_link->dpcm_merged_format)
+               return formats;
+
+       /*
+        * It returns merged BE codec format
+        * if FE want to use it (= dpcm_merged_format)
+        */
+
+       list_for_each_entry(dpcm, &fe->dpcm[stream].be_clients, list_be) {
+               struct snd_soc_pcm_runtime *be = dpcm->be;
+               struct snd_soc_dai_driver *codec_dai_drv;
+               struct snd_soc_pcm_stream *codec_stream;
+               int i;
+
+               for (i = 0; i < be->num_codecs; i++) {
+                       codec_dai_drv = be->codec_dais[i]->driver;
+                       if (stream == SNDRV_PCM_STREAM_PLAYBACK)
+                               codec_stream = &codec_dai_drv->playback;
+                       else
+                               codec_stream = &codec_dai_drv->capture;
+
+                       formats &= codec_stream->formats;
+               }
+       }
+
+       return formats;
+}
+
 static void dpcm_set_fe_runtime(struct snd_pcm_substream *substream)
 {
        struct snd_pcm_runtime *runtime = substream->runtime;
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
        struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
        struct snd_soc_dai_driver *cpu_dai_drv = cpu_dai->driver;
+       u64 format = dpcm_runtime_base_format(substream);
 
        if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
-               dpcm_init_runtime_hw(runtime, &cpu_dai_drv->playback);
+               dpcm_init_runtime_hw(runtime, &cpu_dai_drv->playback, format);
        else
-               dpcm_init_runtime_hw(runtime, &cpu_dai_drv->capture);
+               dpcm_init_runtime_hw(runtime, &cpu_dai_drv->capture, format);
 }
 
 static int dpcm_fe_dai_do_trigger(struct snd_pcm_substream *substream, int cmd);
diff --git a/sound/soc/soc-topology.c b/sound/soc/soc-topology.c
new file mode 100644 (file)
index 0000000..d096068
--- /dev/null
@@ -0,0 +1,1826 @@
+/*
+ * soc-topology.c  --  ALSA SoC Topology
+ *
+ * Copyright (C) 2012 Texas Instruments Inc.
+ * Copyright (C) 2015 Intel Corporation.
+ *
+ * Authors: Liam Girdwood <liam.r.girdwood@linux.intel.com>
+ *             K, Mythri P <mythri.p.k@intel.com>
+ *             Prusty, Subhransu S <subhransu.s.prusty@intel.com>
+ *             B, Jayachandran <jayachandran.b@intel.com>
+ *             Abdullah, Omair M <omair.m.abdullah@intel.com>
+ *             Jin, Yao <yao.jin@intel.com>
+ *             Lin, Mengdong <mengdong.lin@intel.com>
+ *
+ *  This program is free software; you can redistribute  it and/or modify it
+ *  under  the terms of  the GNU General  Public License as published by the
+ *  Free Software Foundation;  either version 2 of the  License, or (at your
+ *  option) any later version.
+ *
+ *  Add support to read audio firmware topology alongside firmware text. The
+ *  topology data can contain kcontrols, DAPM graphs, widgets, DAIs, DAI links,
+ *  equalizers, firmware, coefficients etc.
+ *
+ *  This file only manages the core ALSA and ASoC components, all other bespoke
+ *  firmware topology data is passed to component drivers for bespoke handling.
+ */
+
+#include <linux/kernel.h>
+#include <linux/export.h>
+#include <linux/list.h>
+#include <linux/firmware.h>
+#include <linux/slab.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include <sound/soc-topology.h>
+
+/*
+ * We make several passes over the data (since it wont necessarily be ordered)
+ * and process objects in the following order. This guarantees the component
+ * drivers will be ready with any vendor data before the mixers and DAPM objects
+ * are loaded (that may make use of the vendor data).
+ */
+#define SOC_TPLG_PASS_MANIFEST         0
+#define SOC_TPLG_PASS_VENDOR           1
+#define SOC_TPLG_PASS_MIXER            2
+#define SOC_TPLG_PASS_WIDGET           3
+#define SOC_TPLG_PASS_GRAPH            4
+#define SOC_TPLG_PASS_PINS             5
+#define SOC_TPLG_PASS_PCM_DAI          6
+
+#define SOC_TPLG_PASS_START    SOC_TPLG_PASS_MANIFEST
+#define SOC_TPLG_PASS_END      SOC_TPLG_PASS_PCM_DAI
+
+struct soc_tplg {
+       const struct firmware *fw;
+
+       /* runtime FW parsing */
+       const u8 *pos;          /* read postion */
+       const u8 *hdr_pos;      /* header position */
+       unsigned int pass;      /* pass number */
+
+       /* component caller */
+       struct device *dev;
+       struct snd_soc_component *comp;
+       u32 index;      /* current block index */
+       u32 req_index;  /* required index, only loaded/free matching blocks */
+
+       /* kcontrol operations */
+       const struct snd_soc_tplg_kcontrol_ops *io_ops;
+       int io_ops_count;
+
+       /* optional fw loading callbacks to component drivers */
+       struct snd_soc_tplg_ops *ops;
+};
+
+static int soc_tplg_process_headers(struct soc_tplg *tplg);
+static void soc_tplg_complete(struct soc_tplg *tplg);
+struct snd_soc_dapm_widget *
+snd_soc_dapm_new_control_unlocked(struct snd_soc_dapm_context *dapm,
+                        const struct snd_soc_dapm_widget *widget);
+struct snd_soc_dapm_widget *
+snd_soc_dapm_new_control(struct snd_soc_dapm_context *dapm,
+                        const struct snd_soc_dapm_widget *widget);
+
+/* check we dont overflow the data for this control chunk */
+static int soc_tplg_check_elem_count(struct soc_tplg *tplg, size_t elem_size,
+       unsigned int count, size_t bytes, const char *elem_type)
+{
+       const u8 *end = tplg->pos + elem_size * count;
+
+       if (end > tplg->fw->data + tplg->fw->size) {
+               dev_err(tplg->dev, "ASoC: %s overflow end of data\n",
+                       elem_type);
+               return -EINVAL;
+       }
+
+       /* check there is enough room in chunk for control.
+          extra bytes at the end of control are for vendor data here  */
+       if (elem_size * count > bytes) {
+               dev_err(tplg->dev,
+                       "ASoC: %s count %d of size %zu is bigger than chunk %zu\n",
+                       elem_type, count, elem_size, bytes);
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static inline int soc_tplg_is_eof(struct soc_tplg *tplg)
+{
+       const u8 *end = tplg->hdr_pos;
+
+       if (end >= tplg->fw->data + tplg->fw->size)
+               return 1;
+       return 0;
+}
+
+static inline unsigned long soc_tplg_get_hdr_offset(struct soc_tplg *tplg)
+{
+       return (unsigned long)(tplg->hdr_pos - tplg->fw->data);
+}
+
+static inline unsigned long soc_tplg_get_offset(struct soc_tplg *tplg)
+{
+       return (unsigned long)(tplg->pos - tplg->fw->data);
+}
+
+/* mapping of Kcontrol types and associated operations. */
+static const struct snd_soc_tplg_kcontrol_ops io_ops[] = {
+       {SND_SOC_TPLG_CTL_VOLSW, snd_soc_get_volsw,
+               snd_soc_put_volsw, snd_soc_info_volsw},
+       {SND_SOC_TPLG_CTL_VOLSW_SX, snd_soc_get_volsw_sx,
+               snd_soc_put_volsw_sx, NULL},
+       {SND_SOC_TPLG_CTL_ENUM, snd_soc_get_enum_double,
+               snd_soc_put_enum_double, snd_soc_info_enum_double},
+       {SND_SOC_TPLG_CTL_ENUM_VALUE, snd_soc_get_enum_double,
+               snd_soc_put_enum_double, NULL},
+       {SND_SOC_TPLG_CTL_BYTES, snd_soc_bytes_get,
+               snd_soc_bytes_put, snd_soc_bytes_info},
+       {SND_SOC_TPLG_CTL_RANGE, snd_soc_get_volsw_range,
+               snd_soc_put_volsw_range, snd_soc_info_volsw_range},
+       {SND_SOC_TPLG_CTL_VOLSW_XR_SX, snd_soc_get_xr_sx,
+               snd_soc_put_xr_sx, snd_soc_info_xr_sx},
+       {SND_SOC_TPLG_CTL_STROBE, snd_soc_get_strobe,
+               snd_soc_put_strobe, NULL},
+       {SND_SOC_TPLG_DAPM_CTL_VOLSW, snd_soc_dapm_get_volsw,
+               snd_soc_dapm_put_volsw, NULL},
+       {SND_SOC_TPLG_DAPM_CTL_ENUM_DOUBLE, snd_soc_dapm_get_enum_double,
+               snd_soc_dapm_put_enum_double, snd_soc_info_enum_double},
+       {SND_SOC_TPLG_DAPM_CTL_ENUM_VIRT, snd_soc_dapm_get_enum_double,
+               snd_soc_dapm_put_enum_double, NULL},
+       {SND_SOC_TPLG_DAPM_CTL_ENUM_VALUE, snd_soc_dapm_get_enum_double,
+               snd_soc_dapm_put_enum_double, NULL},
+       {SND_SOC_TPLG_DAPM_CTL_PIN, snd_soc_dapm_get_pin_switch,
+               snd_soc_dapm_put_pin_switch, snd_soc_dapm_info_pin_switch},
+};
+
+struct soc_tplg_map {
+       int uid;
+       int kid;
+};
+
+/* mapping of widget types from UAPI IDs to kernel IDs */
+static const struct soc_tplg_map dapm_map[] = {
+       {SND_SOC_TPLG_DAPM_INPUT, snd_soc_dapm_input},
+       {SND_SOC_TPLG_DAPM_OUTPUT, snd_soc_dapm_output},
+       {SND_SOC_TPLG_DAPM_MUX, snd_soc_dapm_mux},
+       {SND_SOC_TPLG_DAPM_MIXER, snd_soc_dapm_mixer},
+       {SND_SOC_TPLG_DAPM_PGA, snd_soc_dapm_pga},
+       {SND_SOC_TPLG_DAPM_OUT_DRV, snd_soc_dapm_out_drv},
+       {SND_SOC_TPLG_DAPM_ADC, snd_soc_dapm_adc},
+       {SND_SOC_TPLG_DAPM_DAC, snd_soc_dapm_dac},
+       {SND_SOC_TPLG_DAPM_SWITCH, snd_soc_dapm_switch},
+       {SND_SOC_TPLG_DAPM_PRE, snd_soc_dapm_pre},
+       {SND_SOC_TPLG_DAPM_POST, snd_soc_dapm_post},
+       {SND_SOC_TPLG_DAPM_AIF_IN, snd_soc_dapm_aif_in},
+       {SND_SOC_TPLG_DAPM_AIF_OUT, snd_soc_dapm_aif_out},
+       {SND_SOC_TPLG_DAPM_DAI_IN, snd_soc_dapm_dai_in},
+       {SND_SOC_TPLG_DAPM_DAI_OUT, snd_soc_dapm_dai_out},
+       {SND_SOC_TPLG_DAPM_DAI_LINK, snd_soc_dapm_dai_link},
+};
+
+static int tplc_chan_get_reg(struct soc_tplg *tplg,
+       struct snd_soc_tplg_channel *chan, int map)
+{
+       int i;
+
+       for (i = 0; i < SND_SOC_TPLG_MAX_CHAN; i++) {
+               if (chan[i].id == map)
+                       return chan[i].reg;
+       }
+
+       return -EINVAL;
+}
+
+static int tplc_chan_get_shift(struct soc_tplg *tplg,
+       struct snd_soc_tplg_channel *chan, int map)
+{
+       int i;
+
+       for (i = 0; i < SND_SOC_TPLG_MAX_CHAN; i++) {
+               if (chan[i].id == map)
+                       return chan[i].shift;
+       }
+
+       return -EINVAL;
+}
+
+static int get_widget_id(int tplg_type)
+{
+       int i;
+
+       for (i = 0; i < ARRAY_SIZE(dapm_map); i++) {
+               if (tplg_type == dapm_map[i].uid)
+                       return dapm_map[i].kid;
+       }
+
+       return -EINVAL;
+}
+
+static enum snd_soc_dobj_type get_dobj_mixer_type(
+       struct snd_soc_tplg_ctl_hdr *control_hdr)
+{
+       if (control_hdr == NULL)
+               return SND_SOC_DOBJ_NONE;
+
+       switch (control_hdr->ops.info) {
+       case SND_SOC_TPLG_CTL_VOLSW:
+       case SND_SOC_TPLG_CTL_VOLSW_SX:
+       case SND_SOC_TPLG_CTL_VOLSW_XR_SX:
+       case SND_SOC_TPLG_CTL_RANGE:
+       case SND_SOC_TPLG_CTL_STROBE:
+               return SND_SOC_DOBJ_MIXER;
+       case SND_SOC_TPLG_CTL_ENUM:
+       case SND_SOC_TPLG_CTL_ENUM_VALUE:
+               return SND_SOC_DOBJ_ENUM;
+       case SND_SOC_TPLG_CTL_BYTES:
+               return SND_SOC_DOBJ_BYTES;
+       default:
+               return SND_SOC_DOBJ_NONE;
+       }
+}
+
+static enum snd_soc_dobj_type get_dobj_type(struct snd_soc_tplg_hdr *hdr,
+       struct snd_soc_tplg_ctl_hdr *control_hdr)
+{
+       switch (hdr->type) {
+       case SND_SOC_TPLG_TYPE_MIXER:
+               return get_dobj_mixer_type(control_hdr);
+       case SND_SOC_TPLG_TYPE_DAPM_GRAPH:
+       case SND_SOC_TPLG_TYPE_MANIFEST:
+               return SND_SOC_DOBJ_NONE;
+       case SND_SOC_TPLG_TYPE_DAPM_WIDGET:
+               return SND_SOC_DOBJ_WIDGET;
+       case SND_SOC_TPLG_TYPE_DAI_LINK:
+               return SND_SOC_DOBJ_DAI_LINK;
+       case SND_SOC_TPLG_TYPE_PCM:
+               return SND_SOC_DOBJ_PCM;
+       case SND_SOC_TPLG_TYPE_CODEC_LINK:
+               return SND_SOC_DOBJ_CODEC_LINK;
+       default:
+               return SND_SOC_DOBJ_NONE;
+       }
+}
+
+static inline void soc_bind_err(struct soc_tplg *tplg,
+       struct snd_soc_tplg_ctl_hdr *hdr, int index)
+{
+       dev_err(tplg->dev,
+               "ASoC: invalid control type (g,p,i) %d:%d:%d index %d at 0x%lx\n",
+               hdr->ops.get, hdr->ops.put, hdr->ops.info, index,
+               soc_tplg_get_offset(tplg));
+}
+
+static inline void soc_control_err(struct soc_tplg *tplg,
+       struct snd_soc_tplg_ctl_hdr *hdr, const char *name)
+{
+       dev_err(tplg->dev,
+               "ASoC: no complete mixer IO handler for %s type (g,p,i) %d:%d:%d at 0x%lx\n",
+               name, hdr->ops.get, hdr->ops.put, hdr->ops.info,
+               soc_tplg_get_offset(tplg));
+}
+
+/* pass vendor data to component driver for processing */
+static int soc_tplg_vendor_load_(struct soc_tplg *tplg,
+       struct snd_soc_tplg_hdr *hdr)
+{
+       int ret = 0;
+
+       if (tplg->comp && tplg->ops && tplg->ops->vendor_load)
+               ret = tplg->ops->vendor_load(tplg->comp, hdr);
+       else {
+               dev_err(tplg->dev, "ASoC: no vendor load callback for ID %d\n",
+                       hdr->vendor_type);
+               return -EINVAL;
+       }
+
+       if (ret < 0)
+               dev_err(tplg->dev,
+                       "ASoC: vendor load failed at hdr offset %ld/0x%lx for type %d:%d\n",
+                       soc_tplg_get_hdr_offset(tplg),
+                       soc_tplg_get_hdr_offset(tplg),
+                       hdr->type, hdr->vendor_type);
+       return ret;
+}
+
+/* pass vendor data to component driver for processing */
+static int soc_tplg_vendor_load(struct soc_tplg *tplg,
+       struct snd_soc_tplg_hdr *hdr)
+{
+       if (tplg->pass != SOC_TPLG_PASS_VENDOR)
+               return 0;
+
+       return soc_tplg_vendor_load_(tplg, hdr);
+}
+
+/* optionally pass new dynamic widget to component driver. This is mainly for
+ * external widgets where we can assign private data/ops */
+static int soc_tplg_widget_load(struct soc_tplg *tplg,
+       struct snd_soc_dapm_widget *w, struct snd_soc_tplg_dapm_widget *tplg_w)
+{
+       if (tplg->comp && tplg->ops && tplg->ops->widget_load)
+               return tplg->ops->widget_load(tplg->comp, w, tplg_w);
+
+       return 0;
+}
+
+/* pass dynamic FEs configurations to component driver */
+static int soc_tplg_pcm_dai_load(struct soc_tplg *tplg,
+       struct snd_soc_tplg_pcm_dai *pcm_dai, int num_pcm_dai)
+{
+       if (tplg->comp && tplg->ops && tplg->ops->pcm_dai_load)
+               return tplg->ops->pcm_dai_load(tplg->comp, pcm_dai, num_pcm_dai);
+
+       return 0;
+}
+
+/* tell the component driver that all firmware has been loaded in this request */
+static void soc_tplg_complete(struct soc_tplg *tplg)
+{
+       if (tplg->comp && tplg->ops && tplg->ops->complete)
+               tplg->ops->complete(tplg->comp);
+}
+
+/* add a dynamic kcontrol */
+static int soc_tplg_add_dcontrol(struct snd_card *card, struct device *dev,
+       const struct snd_kcontrol_new *control_new, const char *prefix,
+       void *data, struct snd_kcontrol **kcontrol)
+{
+       int err;
+
+       *kcontrol = snd_soc_cnew(control_new, data, control_new->name, prefix);
+       if (*kcontrol == NULL) {
+               dev_err(dev, "ASoC: Failed to create new kcontrol %s\n",
+               control_new->name);
+               return -ENOMEM;
+       }
+
+       err = snd_ctl_add(card, *kcontrol);
+       if (err < 0) {
+               dev_err(dev, "ASoC: Failed to add %s: %d\n",
+                       control_new->name, err);
+               return err;
+       }
+
+       return 0;
+}
+
+/* add a dynamic kcontrol for component driver */
+static int soc_tplg_add_kcontrol(struct soc_tplg *tplg,
+       struct snd_kcontrol_new *k, struct snd_kcontrol **kcontrol)
+{
+       struct snd_soc_component *comp = tplg->comp;
+
+       return soc_tplg_add_dcontrol(comp->card->snd_card,
+                               comp->dev, k, NULL, comp, kcontrol);
+}
+
+/* remove a mixer kcontrol */
+static void remove_mixer(struct snd_soc_component *comp,
+       struct snd_soc_dobj *dobj, int pass)
+{
+       struct snd_card *card = comp->card->snd_card;
+       struct soc_mixer_control *sm =
+               container_of(dobj, struct soc_mixer_control, dobj);
+       const unsigned int *p = NULL;
+
+       if (pass != SOC_TPLG_PASS_MIXER)
+               return;
+
+       if (dobj->ops && dobj->ops->control_unload)
+               dobj->ops->control_unload(comp, dobj);
+
+       if (sm->dobj.control.kcontrol->tlv.p)
+               p = sm->dobj.control.kcontrol->tlv.p;
+       snd_ctl_remove(card, sm->dobj.control.kcontrol);
+       list_del(&sm->dobj.list);
+       kfree(sm);
+       kfree(p);
+}
+
+/* remove an enum kcontrol */
+static void remove_enum(struct snd_soc_component *comp,
+       struct snd_soc_dobj *dobj, int pass)
+{
+       struct snd_card *card = comp->card->snd_card;
+       struct soc_enum *se = container_of(dobj, struct soc_enum, dobj);
+       int i;
+
+       if (pass != SOC_TPLG_PASS_MIXER)
+               return;
+
+       if (dobj->ops && dobj->ops->control_unload)
+               dobj->ops->control_unload(comp, dobj);
+
+       snd_ctl_remove(card, se->dobj.control.kcontrol);
+       list_del(&se->dobj.list);
+
+       kfree(se->dobj.control.dvalues);
+       for (i = 0; i < se->items; i++)
+               kfree(se->dobj.control.dtexts[i]);
+       kfree(se);
+}
+
+/* remove a byte kcontrol */
+static void remove_bytes(struct snd_soc_component *comp,
+       struct snd_soc_dobj *dobj, int pass)
+{
+       struct snd_card *card = comp->card->snd_card;
+       struct soc_bytes_ext *sb =
+               container_of(dobj, struct soc_bytes_ext, dobj);
+
+       if (pass != SOC_TPLG_PASS_MIXER)
+               return;
+
+       if (dobj->ops && dobj->ops->control_unload)
+               dobj->ops->control_unload(comp, dobj);
+
+       snd_ctl_remove(card, sb->dobj.control.kcontrol);
+       list_del(&sb->dobj.list);
+       kfree(sb);
+}
+
+/* remove a widget and it's kcontrols - routes must be removed first */
+static void remove_widget(struct snd_soc_component *comp,
+       struct snd_soc_dobj *dobj, int pass)
+{
+       struct snd_card *card = comp->card->snd_card;
+       struct snd_soc_dapm_widget *w =
+               container_of(dobj, struct snd_soc_dapm_widget, dobj);
+       int i;
+
+       if (pass != SOC_TPLG_PASS_WIDGET)
+               return;
+
+       if (dobj->ops && dobj->ops->widget_unload)
+               dobj->ops->widget_unload(comp, dobj);
+
+       /*
+        * Dynamic Widgets either have 1 enum kcontrol or 1..N mixers.
+        * The enum may either have an array of values or strings.
+        */
+       if (dobj->widget.kcontrol_enum) {
+               /* enumerated widget mixer */
+               struct soc_enum *se =
+                       (struct soc_enum *)w->kcontrols[0]->private_value;
+
+               snd_ctl_remove(card, w->kcontrols[0]);
+
+               kfree(se->dobj.control.dvalues);
+               for (i = 0; i < se->items; i++)
+                       kfree(se->dobj.control.dtexts[i]);
+
+               kfree(se);
+               kfree(w->kcontrol_news);
+       } else {
+               /* non enumerated widget mixer */
+               for (i = 0; i < w->num_kcontrols; i++) {
+                       struct snd_kcontrol *kcontrol = w->kcontrols[i];
+                       struct soc_mixer_control *sm =
+                       (struct soc_mixer_control *) kcontrol->private_value;
+
+                       kfree(w->kcontrols[i]->tlv.p);
+
+                       snd_ctl_remove(card, w->kcontrols[i]);
+                       kfree(sm);
+               }
+               kfree(w->kcontrol_news);
+       }
+       /* widget w is freed by soc-dapm.c */
+}
+
+/* remove PCM DAI configurations */
+static void remove_pcm_dai(struct snd_soc_component *comp,
+       struct snd_soc_dobj *dobj, int pass)
+{
+       if (pass != SOC_TPLG_PASS_PCM_DAI)
+               return;
+
+       if (dobj->ops && dobj->ops->pcm_dai_unload)
+               dobj->ops->pcm_dai_unload(comp, dobj);
+
+       list_del(&dobj->list);
+       kfree(dobj);
+}
+
+/* bind a kcontrol to it's IO handlers */
+static int soc_tplg_kcontrol_bind_io(struct snd_soc_tplg_ctl_hdr *hdr,
+       struct snd_kcontrol_new *k,
+       const struct snd_soc_tplg_kcontrol_ops *ops, int num_ops,
+       const struct snd_soc_tplg_kcontrol_ops *bops, int num_bops)
+{
+       int i;
+
+       /* try and map standard kcontrols handler first */
+       for (i = 0; i < num_ops; i++) {
+
+               if (ops[i].id == hdr->ops.put)
+                       k->put = ops[i].put;
+               if (ops[i].id == hdr->ops.get)
+                       k->get = ops[i].get;
+               if (ops[i].id == hdr->ops.info)
+                       k->info = ops[i].info;
+       }
+
+       /* standard handlers found ? */
+       if (k->put && k->get && k->info)
+               return 0;
+
+       /* none found so try bespoke handlers */
+       for (i = 0; i < num_bops; i++) {
+
+               if (k->put == NULL && bops[i].id == hdr->ops.put)
+                       k->put = bops[i].put;
+               if (k->get == NULL && bops[i].id == hdr->ops.get)
+                       k->get = bops[i].get;
+               if (k->info == NULL && ops[i].id == hdr->ops.info)
+                       k->info = bops[i].info;
+       }
+
+       /* bespoke handlers found ? */
+       if (k->put && k->get && k->info)
+               return 0;
+
+       /* nothing to bind */
+       return -EINVAL;
+}
+
+/* bind a widgets to it's evnt handlers */
+int snd_soc_tplg_widget_bind_event(struct snd_soc_dapm_widget *w,
+               const struct snd_soc_tplg_widget_events *events,
+               int num_events, u16 event_type)
+{
+       int i;
+
+       w->event = NULL;
+
+       for (i = 0; i < num_events; i++) {
+               if (event_type == events[i].type) {
+
+                       /* found - so assign event */
+                       w->event = events[i].event_handler;
+                       return 0;
+               }
+       }
+
+       /* not found */
+       return -EINVAL;
+}
+EXPORT_SYMBOL_GPL(snd_soc_tplg_widget_bind_event);
+
+/* optionally pass new dynamic kcontrol to component driver. */
+static int soc_tplg_init_kcontrol(struct soc_tplg *tplg,
+       struct snd_kcontrol_new *k, struct snd_soc_tplg_ctl_hdr *hdr)
+{
+       if (tplg->comp && tplg->ops && tplg->ops->control_load)
+               return tplg->ops->control_load(tplg->comp, k, hdr);
+
+       return 0;
+}
+
+static int soc_tplg_create_tlv(struct soc_tplg *tplg,
+       struct snd_kcontrol_new *kc, u32 tlv_size)
+{
+       struct snd_soc_tplg_ctl_tlv *tplg_tlv;
+       struct snd_ctl_tlv *tlv;
+
+       if (tlv_size == 0)
+               return 0;
+
+       tplg_tlv = (struct snd_soc_tplg_ctl_tlv *) tplg->pos;
+       tplg->pos += tlv_size;
+
+       tlv = kzalloc(sizeof(*tlv) + tlv_size, GFP_KERNEL);
+       if (tlv == NULL)
+               return -ENOMEM;
+
+       dev_dbg(tplg->dev, " created TLV type %d size %d bytes\n",
+               tplg_tlv->numid, tplg_tlv->size);
+
+       tlv->numid = tplg_tlv->numid;
+       tlv->length = tplg_tlv->size;
+       memcpy(tlv->tlv, tplg_tlv + 1, tplg_tlv->size);
+       kc->tlv.p = (void *)tlv;
+
+       return 0;
+}
+
+static inline void soc_tplg_free_tlv(struct soc_tplg *tplg,
+       struct snd_kcontrol_new *kc)
+{
+       kfree(kc->tlv.p);
+}
+
+static int soc_tplg_dbytes_create(struct soc_tplg *tplg, unsigned int count,
+       size_t size)
+{
+       struct snd_soc_tplg_bytes_control *be;
+       struct soc_bytes_ext *sbe;
+       struct snd_kcontrol_new kc;
+       int i, err;
+
+       if (soc_tplg_check_elem_count(tplg,
+               sizeof(struct snd_soc_tplg_bytes_control), count,
+                       size, "mixer bytes")) {
+               dev_err(tplg->dev, "ASoC: Invalid count %d for byte control\n",
+                       count);
+               return -EINVAL;
+       }
+
+       for (i = 0; i < count; i++) {
+               be = (struct snd_soc_tplg_bytes_control *)tplg->pos;
+
+               /* validate kcontrol */
+               if (strnlen(be->hdr.name, SNDRV_CTL_ELEM_ID_NAME_MAXLEN) ==
+                       SNDRV_CTL_ELEM_ID_NAME_MAXLEN)
+                       return -EINVAL;
+
+               sbe = kzalloc(sizeof(*sbe), GFP_KERNEL);
+               if (sbe == NULL)
+                       return -ENOMEM;
+
+               tplg->pos += (sizeof(struct snd_soc_tplg_bytes_control) +
+                       be->priv.size);
+
+               dev_dbg(tplg->dev,
+                       "ASoC: adding bytes kcontrol %s with access 0x%x\n",
+                       be->hdr.name, be->hdr.access);
+
+               memset(&kc, 0, sizeof(kc));
+               kc.name = be->hdr.name;
+               kc.private_value = (long)sbe;
+               kc.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
+               kc.access = be->hdr.access;
+
+               sbe->max = be->max;
+               sbe->dobj.type = SND_SOC_DOBJ_BYTES;
+               sbe->dobj.ops = tplg->ops;
+               INIT_LIST_HEAD(&sbe->dobj.list);
+
+               /* map io handlers */
+               err = soc_tplg_kcontrol_bind_io(&be->hdr, &kc, io_ops,
+                       ARRAY_SIZE(io_ops), tplg->io_ops, tplg->io_ops_count);
+               if (err) {
+                       soc_control_err(tplg, &be->hdr, be->hdr.name);
+                       kfree(sbe);
+                       continue;
+               }
+
+               /* pass control to driver for optional further init */
+               err = soc_tplg_init_kcontrol(tplg, &kc,
+                       (struct snd_soc_tplg_ctl_hdr *)be);
+               if (err < 0) {
+                       dev_err(tplg->dev, "ASoC: failed to init %s\n",
+                               be->hdr.name);
+                       kfree(sbe);
+                       continue;
+               }
+
+               /* register control here */
+               err = soc_tplg_add_kcontrol(tplg, &kc,
+                       &sbe->dobj.control.kcontrol);
+               if (err < 0) {
+                       dev_err(tplg->dev, "ASoC: failed to add %s\n",
+                               be->hdr.name);
+                       kfree(sbe);
+                       continue;
+               }
+
+               list_add(&sbe->dobj.list, &tplg->comp->dobj_list);
+       }
+       return 0;
+
+}
+
+static int soc_tplg_dmixer_create(struct soc_tplg *tplg, unsigned int count,
+       size_t size)
+{
+       struct snd_soc_tplg_mixer_control *mc;
+       struct soc_mixer_control *sm;
+       struct snd_kcontrol_new kc;
+       int i, err;
+
+       if (soc_tplg_check_elem_count(tplg,
+               sizeof(struct snd_soc_tplg_mixer_control),
+               count, size, "mixers")) {
+
+               dev_err(tplg->dev, "ASoC: invalid count %d for controls\n",
+                       count);
+               return -EINVAL;
+       }
+
+       for (i = 0; i < count; i++) {
+               mc = (struct snd_soc_tplg_mixer_control *)tplg->pos;
+
+               /* validate kcontrol */
+               if (strnlen(mc->hdr.name, SNDRV_CTL_ELEM_ID_NAME_MAXLEN) ==
+                       SNDRV_CTL_ELEM_ID_NAME_MAXLEN)
+                       return -EINVAL;
+
+               sm = kzalloc(sizeof(*sm), GFP_KERNEL);
+               if (sm == NULL)
+                       return -ENOMEM;
+               tplg->pos += (sizeof(struct snd_soc_tplg_mixer_control) +
+                       mc->priv.size);
+
+               dev_dbg(tplg->dev,
+                       "ASoC: adding mixer kcontrol %s with access 0x%x\n",
+                       mc->hdr.name, mc->hdr.access);
+
+               memset(&kc, 0, sizeof(kc));
+               kc.name = mc->hdr.name;
+               kc.private_value = (long)sm;
+               kc.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
+               kc.access = mc->hdr.access;
+
+               /* we only support FL/FR channel mapping atm */
+               sm->reg = tplc_chan_get_reg(tplg, mc->channel,
+                       SNDRV_CHMAP_FL);
+               sm->rreg = tplc_chan_get_reg(tplg, mc->channel,
+                       SNDRV_CHMAP_FR);
+               sm->shift = tplc_chan_get_shift(tplg, mc->channel,
+                       SNDRV_CHMAP_FL);
+               sm->rshift = tplc_chan_get_shift(tplg, mc->channel,
+                       SNDRV_CHMAP_FR);
+
+               sm->max = mc->max;
+               sm->min = mc->min;
+               sm->invert = mc->invert;
+               sm->platform_max = mc->platform_max;
+               sm->dobj.index = tplg->index;
+               sm->dobj.ops = tplg->ops;
+               sm->dobj.type = SND_SOC_DOBJ_MIXER;
+               INIT_LIST_HEAD(&sm->dobj.list);
+
+               /* map io handlers */
+               err = soc_tplg_kcontrol_bind_io(&mc->hdr, &kc, io_ops,
+                       ARRAY_SIZE(io_ops), tplg->io_ops, tplg->io_ops_count);
+               if (err) {
+                       soc_control_err(tplg, &mc->hdr, mc->hdr.name);
+                       kfree(sm);
+                       continue;
+               }
+
+               /* pass control to driver for optional further init */
+               err = soc_tplg_init_kcontrol(tplg, &kc,
+                       (struct snd_soc_tplg_ctl_hdr *) mc);
+               if (err < 0) {
+                       dev_err(tplg->dev, "ASoC: failed to init %s\n",
+                               mc->hdr.name);
+                       kfree(sm);
+                       continue;
+               }
+
+               /* create any TLV data */
+               soc_tplg_create_tlv(tplg, &kc, mc->hdr.tlv_size);
+
+               /* register control here */
+               err = soc_tplg_add_kcontrol(tplg, &kc,
+                       &sm->dobj.control.kcontrol);
+               if (err < 0) {
+                       dev_err(tplg->dev, "ASoC: failed to add %s\n",
+                               mc->hdr.name);
+                       soc_tplg_free_tlv(tplg, &kc);
+                       kfree(sm);
+                       continue;
+               }
+
+               list_add(&sm->dobj.list, &tplg->comp->dobj_list);
+       }
+
+       return 0;
+}
+
+static int soc_tplg_denum_create_texts(struct soc_enum *se,
+       struct snd_soc_tplg_enum_control *ec)
+{
+       int i, ret;
+
+       se->dobj.control.dtexts =
+               kzalloc(sizeof(char *) * ec->items, GFP_KERNEL);
+       if (se->dobj.control.dtexts == NULL)
+               return -ENOMEM;
+
+       for (i = 0; i < ec->items; i++) {
+
+               if (strnlen(ec->texts[i], SNDRV_CTL_ELEM_ID_NAME_MAXLEN) ==
+                       SNDRV_CTL_ELEM_ID_NAME_MAXLEN) {
+                       ret = -EINVAL;
+                       goto err;
+               }
+
+               se->dobj.control.dtexts[i] = kstrdup(ec->texts[i], GFP_KERNEL);
+               if (!se->dobj.control.dtexts[i]) {
+                       ret = -ENOMEM;
+                       goto err;
+               }
+       }
+
+       return 0;
+
+err:
+       for (--i; i >= 0; i--)
+               kfree(se->dobj.control.dtexts[i]);
+       kfree(se->dobj.control.dtexts);
+       return ret;
+}
+
+static int soc_tplg_denum_create_values(struct soc_enum *se,
+       struct snd_soc_tplg_enum_control *ec)
+{
+       if (ec->items > sizeof(*ec->values))
+               return -EINVAL;
+
+       se->dobj.control.dvalues =
+               kmalloc(ec->items * sizeof(u32), GFP_KERNEL);
+       if (!se->dobj.control.dvalues)
+               return -ENOMEM;
+
+       memcpy(se->dobj.control.dvalues, ec->values, ec->items * sizeof(u32));
+       return 0;
+}
+
+static int soc_tplg_denum_create(struct soc_tplg *tplg, unsigned int count,
+       size_t size)
+{
+       struct snd_soc_tplg_enum_control *ec;
+       struct soc_enum *se;
+       struct snd_kcontrol_new kc;
+       int i, ret, err;
+
+       if (soc_tplg_check_elem_count(tplg,
+               sizeof(struct snd_soc_tplg_enum_control),
+               count, size, "enums")) {
+
+               dev_err(tplg->dev, "ASoC: invalid count %d for enum controls\n",
+                       count);
+               return -EINVAL;
+       }
+
+       for (i = 0; i < count; i++) {
+               ec = (struct snd_soc_tplg_enum_control *)tplg->pos;
+               tplg->pos += (sizeof(struct snd_soc_tplg_enum_control) +
+                       ec->priv.size);
+
+               /* validate kcontrol */
+               if (strnlen(ec->hdr.name, SNDRV_CTL_ELEM_ID_NAME_MAXLEN) ==
+                       SNDRV_CTL_ELEM_ID_NAME_MAXLEN)
+                       return -EINVAL;
+
+               se = kzalloc((sizeof(*se)), GFP_KERNEL);
+               if (se == NULL)
+                       return -ENOMEM;
+
+               dev_dbg(tplg->dev, "ASoC: adding enum kcontrol %s size %d\n",
+                       ec->hdr.name, ec->items);
+
+               memset(&kc, 0, sizeof(kc));
+               kc.name = ec->hdr.name;
+               kc.private_value = (long)se;
+               kc.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
+               kc.access = ec->hdr.access;
+
+               se->reg = tplc_chan_get_reg(tplg, ec->channel, SNDRV_CHMAP_FL);
+               se->shift_l = tplc_chan_get_shift(tplg, ec->channel,
+                       SNDRV_CHMAP_FL);
+               se->shift_r = tplc_chan_get_shift(tplg, ec->channel,
+                       SNDRV_CHMAP_FL);
+
+               se->items = ec->items;
+               se->mask = ec->mask;
+               se->dobj.index = tplg->index;
+               se->dobj.type = SND_SOC_DOBJ_ENUM;
+               se->dobj.ops = tplg->ops;
+               INIT_LIST_HEAD(&se->dobj.list);
+
+               switch (ec->hdr.ops.info) {
+               case SND_SOC_TPLG_DAPM_CTL_ENUM_VALUE:
+               case SND_SOC_TPLG_CTL_ENUM_VALUE:
+                       err = soc_tplg_denum_create_values(se, ec);
+                       if (err < 0) {
+                               dev_err(tplg->dev,
+                                       "ASoC: could not create values for %s\n",
+                                       ec->hdr.name);
+                               kfree(se);
+                               continue;
+                       }
+                       /* fall through and create texts */
+               case SND_SOC_TPLG_CTL_ENUM:
+               case SND_SOC_TPLG_DAPM_CTL_ENUM_DOUBLE:
+               case SND_SOC_TPLG_DAPM_CTL_ENUM_VIRT:
+                       err = soc_tplg_denum_create_texts(se, ec);
+                       if (err < 0) {
+                               dev_err(tplg->dev,
+                                       "ASoC: could not create texts for %s\n",
+                                       ec->hdr.name);
+                               kfree(se);
+                               continue;
+                       }
+                       break;
+               default:
+                       dev_err(tplg->dev,
+                               "ASoC: invalid enum control type %d for %s\n",
+                               ec->hdr.ops.info, ec->hdr.name);
+                       kfree(se);
+                       continue;
+               }
+
+               /* map io handlers */
+               err = soc_tplg_kcontrol_bind_io(&ec->hdr, &kc, io_ops,
+                       ARRAY_SIZE(io_ops), tplg->io_ops, tplg->io_ops_count);
+               if (err) {
+                       soc_control_err(tplg, &ec->hdr, ec->hdr.name);
+                       kfree(se);
+                       continue;
+               }
+
+               /* pass control to driver for optional further init */
+               err = soc_tplg_init_kcontrol(tplg, &kc,
+                       (struct snd_soc_tplg_ctl_hdr *) ec);
+               if (err < 0) {
+                       dev_err(tplg->dev, "ASoC: failed to init %s\n",
+                               ec->hdr.name);
+                       kfree(se);
+                       continue;
+               }
+
+               /* register control here */
+               ret = soc_tplg_add_kcontrol(tplg,
+                       &kc, &se->dobj.control.kcontrol);
+               if (ret < 0) {
+                       dev_err(tplg->dev, "ASoC: could not add kcontrol %s\n",
+                               ec->hdr.name);
+                       kfree(se);
+                       continue;
+               }
+
+               list_add(&se->dobj.list, &tplg->comp->dobj_list);
+       }
+
+       return 0;
+}
+
+static int soc_tplg_kcontrol_elems_load(struct soc_tplg *tplg,
+       struct snd_soc_tplg_hdr *hdr)
+{
+       struct snd_soc_tplg_ctl_hdr *control_hdr;
+       int i;
+
+       if (tplg->pass != SOC_TPLG_PASS_MIXER) {
+               tplg->pos += hdr->size + hdr->payload_size;
+               return 0;
+       }
+
+       dev_dbg(tplg->dev, "ASoC: adding %d kcontrols at 0x%lx\n", hdr->count,
+               soc_tplg_get_offset(tplg));
+
+       for (i = 0; i < hdr->count; i++) {
+
+               control_hdr = (struct snd_soc_tplg_ctl_hdr *)tplg->pos;
+
+               switch (control_hdr->ops.info) {
+               case SND_SOC_TPLG_CTL_VOLSW:
+               case SND_SOC_TPLG_CTL_STROBE:
+               case SND_SOC_TPLG_CTL_VOLSW_SX:
+               case SND_SOC_TPLG_CTL_VOLSW_XR_SX:
+               case SND_SOC_TPLG_CTL_RANGE:
+               case SND_SOC_TPLG_DAPM_CTL_VOLSW:
+               case SND_SOC_TPLG_DAPM_CTL_PIN:
+                       soc_tplg_dmixer_create(tplg, 1, hdr->payload_size);
+                       break;
+               case SND_SOC_TPLG_CTL_ENUM:
+               case SND_SOC_TPLG_CTL_ENUM_VALUE:
+               case SND_SOC_TPLG_DAPM_CTL_ENUM_DOUBLE:
+               case SND_SOC_TPLG_DAPM_CTL_ENUM_VIRT:
+               case SND_SOC_TPLG_DAPM_CTL_ENUM_VALUE:
+                       soc_tplg_denum_create(tplg, 1, hdr->payload_size);
+                       break;
+               case SND_SOC_TPLG_CTL_BYTES:
+                       soc_tplg_dbytes_create(tplg, 1, hdr->payload_size);
+                       break;
+               default:
+                       soc_bind_err(tplg, control_hdr, i);
+                       return -EINVAL;
+               }
+       }
+
+       return 0;
+}
+
+static int soc_tplg_dapm_graph_elems_load(struct soc_tplg *tplg,
+       struct snd_soc_tplg_hdr *hdr)
+{
+       struct snd_soc_dapm_context *dapm = &tplg->comp->dapm;
+       struct snd_soc_dapm_route route;
+       struct snd_soc_tplg_dapm_graph_elem *elem;
+       int count = hdr->count, i;
+
+       if (tplg->pass != SOC_TPLG_PASS_GRAPH) {
+               tplg->pos += hdr->size + hdr->payload_size;
+               return 0;
+       }
+
+       if (soc_tplg_check_elem_count(tplg,
+               sizeof(struct snd_soc_tplg_dapm_graph_elem),
+               count, hdr->payload_size, "graph")) {
+
+               dev_err(tplg->dev, "ASoC: invalid count %d for DAPM routes\n",
+                       count);
+               return -EINVAL;
+       }
+
+       dev_dbg(tplg->dev, "ASoC: adding %d DAPM routes\n", count);
+
+       for (i = 0; i < count; i++) {
+               elem = (struct snd_soc_tplg_dapm_graph_elem *)tplg->pos;
+               tplg->pos += sizeof(struct snd_soc_tplg_dapm_graph_elem);
+
+               /* validate routes */
+               if (strnlen(elem->source, SNDRV_CTL_ELEM_ID_NAME_MAXLEN) ==
+                       SNDRV_CTL_ELEM_ID_NAME_MAXLEN)
+                       return -EINVAL;
+               if (strnlen(elem->sink, SNDRV_CTL_ELEM_ID_NAME_MAXLEN) ==
+                       SNDRV_CTL_ELEM_ID_NAME_MAXLEN)
+                       return -EINVAL;
+               if (strnlen(elem->control, SNDRV_CTL_ELEM_ID_NAME_MAXLEN) ==
+                       SNDRV_CTL_ELEM_ID_NAME_MAXLEN)
+                       return -EINVAL;
+
+               route.source = elem->source;
+               route.sink = elem->sink;
+               route.connected = NULL; /* set to NULL atm for tplg users */
+               if (strnlen(elem->control, SNDRV_CTL_ELEM_ID_NAME_MAXLEN) == 0)
+                       route.control = NULL;
+               else
+                       route.control = elem->control;
+
+               /* add route, but keep going if some fail */
+               snd_soc_dapm_add_routes(dapm, &route, 1);
+       }
+
+       return 0;
+}
+
+static struct snd_kcontrol_new *soc_tplg_dapm_widget_dmixer_create(
+       struct soc_tplg *tplg, int num_kcontrols)
+{
+       struct snd_kcontrol_new *kc;
+       struct soc_mixer_control *sm;
+       struct snd_soc_tplg_mixer_control *mc;
+       int i, err;
+
+       kc = kzalloc(sizeof(*kc) * num_kcontrols, GFP_KERNEL);
+       if (kc == NULL)
+               return NULL;
+
+       for (i = 0; i < num_kcontrols; i++) {
+               mc = (struct snd_soc_tplg_mixer_control *)tplg->pos;
+               sm = kzalloc(sizeof(*sm), GFP_KERNEL);
+               if (sm == NULL)
+                       goto err;
+
+               tplg->pos += (sizeof(struct snd_soc_tplg_mixer_control) +
+                       mc->priv.size);
+
+               /* validate kcontrol */
+               if (strnlen(mc->hdr.name, SNDRV_CTL_ELEM_ID_NAME_MAXLEN) ==
+                       SNDRV_CTL_ELEM_ID_NAME_MAXLEN)
+                       goto err_str;
+
+               dev_dbg(tplg->dev, " adding DAPM widget mixer control %s at %d\n",
+                       mc->hdr.name, i);
+
+               kc[i].name = mc->hdr.name;
+               kc[i].private_value = (long)sm;
+               kc[i].iface = SNDRV_CTL_ELEM_IFACE_MIXER;
+               kc[i].access = mc->hdr.access;
+
+               /* we only support FL/FR channel mapping atm */
+               sm->reg = tplc_chan_get_reg(tplg, mc->channel,
+                       SNDRV_CHMAP_FL);
+               sm->rreg = tplc_chan_get_reg(tplg, mc->channel,
+                       SNDRV_CHMAP_FR);
+               sm->shift = tplc_chan_get_shift(tplg, mc->channel,
+                       SNDRV_CHMAP_FL);
+               sm->rshift = tplc_chan_get_shift(tplg, mc->channel,
+                       SNDRV_CHMAP_FR);
+
+               sm->max = mc->max;
+               sm->min = mc->min;
+               sm->invert = mc->invert;
+               sm->platform_max = mc->platform_max;
+               sm->dobj.index = tplg->index;
+               INIT_LIST_HEAD(&sm->dobj.list);
+
+               /* map io handlers */
+               err = soc_tplg_kcontrol_bind_io(&mc->hdr, &kc[i], io_ops,
+                       ARRAY_SIZE(io_ops), tplg->io_ops, tplg->io_ops_count);
+               if (err) {
+                       soc_control_err(tplg, &mc->hdr, mc->hdr.name);
+                       kfree(sm);
+                       continue;
+               }
+
+               /* pass control to driver for optional further init */
+               err = soc_tplg_init_kcontrol(tplg, &kc[i],
+                       (struct snd_soc_tplg_ctl_hdr *)mc);
+               if (err < 0) {
+                       dev_err(tplg->dev, "ASoC: failed to init %s\n",
+                               mc->hdr.name);
+                       kfree(sm);
+                       continue;
+               }
+       }
+       return kc;
+
+err_str:
+       kfree(sm);
+err:
+       for (--i; i >= 0; i--)
+               kfree((void *)kc[i].private_value);
+       kfree(kc);
+       return NULL;
+}
+
+static struct snd_kcontrol_new *soc_tplg_dapm_widget_denum_create(
+       struct soc_tplg *tplg)
+{
+       struct snd_kcontrol_new *kc;
+       struct snd_soc_tplg_enum_control *ec;
+       struct soc_enum *se;
+       int i, err;
+
+       ec = (struct snd_soc_tplg_enum_control *)tplg->pos;
+       tplg->pos += (sizeof(struct snd_soc_tplg_enum_control) +
+               ec->priv.size);
+
+       /* validate kcontrol */
+       if (strnlen(ec->hdr.name, SNDRV_CTL_ELEM_ID_NAME_MAXLEN) ==
+               SNDRV_CTL_ELEM_ID_NAME_MAXLEN)
+               return NULL;
+
+       kc = kzalloc(sizeof(*kc), GFP_KERNEL);
+       if (kc == NULL)
+               return NULL;
+
+       se = kzalloc(sizeof(*se), GFP_KERNEL);
+       if (se == NULL)
+               goto err;
+
+       dev_dbg(tplg->dev, " adding DAPM widget enum control %s\n",
+               ec->hdr.name);
+
+       kc->name = ec->hdr.name;
+       kc->private_value = (long)se;
+       kc->iface = SNDRV_CTL_ELEM_IFACE_MIXER;
+       kc->access = ec->hdr.access;
+
+       /* we only support FL/FR channel mapping atm */
+       se->reg = tplc_chan_get_reg(tplg, ec->channel, SNDRV_CHMAP_FL);
+       se->shift_l = tplc_chan_get_shift(tplg, ec->channel, SNDRV_CHMAP_FL);
+       se->shift_r = tplc_chan_get_shift(tplg, ec->channel, SNDRV_CHMAP_FR);
+
+       se->items = ec->items;
+       se->mask = ec->mask;
+       se->dobj.index = tplg->index;
+
+       switch (ec->hdr.ops.info) {
+       case SND_SOC_TPLG_CTL_ENUM_VALUE:
+       case SND_SOC_TPLG_DAPM_CTL_ENUM_VALUE:
+               err = soc_tplg_denum_create_values(se, ec);
+               if (err < 0) {
+                       dev_err(tplg->dev, "ASoC: could not create values for %s\n",
+                               ec->hdr.name);
+                       goto err_se;
+               }
+               /* fall through to create texts */
+       case SND_SOC_TPLG_CTL_ENUM:
+       case SND_SOC_TPLG_DAPM_CTL_ENUM_DOUBLE:
+       case SND_SOC_TPLG_DAPM_CTL_ENUM_VIRT:
+               err = soc_tplg_denum_create_texts(se, ec);
+               if (err < 0) {
+                       dev_err(tplg->dev, "ASoC: could not create texts for %s\n",
+                               ec->hdr.name);
+                       goto err_se;
+               }
+               break;
+       default:
+               dev_err(tplg->dev, "ASoC: invalid enum control type %d for %s\n",
+                       ec->hdr.ops.info, ec->hdr.name);
+               goto err_se;
+       }
+
+       /* map io handlers */
+       err = soc_tplg_kcontrol_bind_io(&ec->hdr, kc, io_ops,
+               ARRAY_SIZE(io_ops), tplg->io_ops, tplg->io_ops_count);
+       if (err) {
+               soc_control_err(tplg, &ec->hdr, ec->hdr.name);
+               goto err_se;
+       }
+
+       /* pass control to driver for optional further init */
+       err = soc_tplg_init_kcontrol(tplg, kc,
+               (struct snd_soc_tplg_ctl_hdr *)ec);
+       if (err < 0) {
+               dev_err(tplg->dev, "ASoC: failed to init %s\n",
+                       ec->hdr.name);
+               goto err_se;
+       }
+
+       return kc;
+
+err_se:
+       /* free values and texts */
+       kfree(se->dobj.control.dvalues);
+       for (i = 0; i < ec->items; i++)
+               kfree(se->dobj.control.dtexts[i]);
+
+       kfree(se);
+err:
+       kfree(kc);
+
+       return NULL;
+}
+
+static struct snd_kcontrol_new *soc_tplg_dapm_widget_dbytes_create(
+       struct soc_tplg *tplg, int count)
+{
+       struct snd_soc_tplg_bytes_control *be;
+       struct soc_bytes_ext  *sbe;
+       struct snd_kcontrol_new *kc;
+       int i, err;
+
+       kc = kzalloc(sizeof(*kc) * count, GFP_KERNEL);
+       if (!kc)
+               return NULL;
+
+       for (i = 0; i < count; i++) {
+               be = (struct snd_soc_tplg_bytes_control *)tplg->pos;
+
+               /* validate kcontrol */
+               if (strnlen(be->hdr.name, SNDRV_CTL_ELEM_ID_NAME_MAXLEN) ==
+                       SNDRV_CTL_ELEM_ID_NAME_MAXLEN)
+                       goto err;
+
+               sbe = kzalloc(sizeof(*sbe), GFP_KERNEL);
+               if (sbe == NULL)
+                       goto err;
+
+               tplg->pos += (sizeof(struct snd_soc_tplg_bytes_control) +
+                       be->priv.size);
+
+               dev_dbg(tplg->dev,
+                       "ASoC: adding bytes kcontrol %s with access 0x%x\n",
+                       be->hdr.name, be->hdr.access);
+
+               memset(kc, 0, sizeof(*kc));
+               kc[i].name = be->hdr.name;
+               kc[i].private_value = (long)sbe;
+               kc[i].iface = SNDRV_CTL_ELEM_IFACE_MIXER;
+               kc[i].access = be->hdr.access;
+
+               sbe->max = be->max;
+               INIT_LIST_HEAD(&sbe->dobj.list);
+
+               /* map standard io handlers and check for external handlers */
+               err = soc_tplg_kcontrol_bind_io(&be->hdr, &kc[i], io_ops,
+                               ARRAY_SIZE(io_ops), tplg->io_ops,
+                               tplg->io_ops_count);
+               if (err) {
+                       soc_control_err(tplg, &be->hdr, be->hdr.name);
+                       kfree(sbe);
+                       continue;
+               }
+
+               /* pass control to driver for optional further init */
+               err = soc_tplg_init_kcontrol(tplg, &kc[i],
+                       (struct snd_soc_tplg_ctl_hdr *)be);
+               if (err < 0) {
+                       dev_err(tplg->dev, "ASoC: failed to init %s\n",
+                               be->hdr.name);
+                       kfree(sbe);
+                       continue;
+               }
+       }
+
+       return kc;
+
+err:
+       for (--i; i >= 0; i--)
+               kfree((void *)kc[i].private_value);
+
+       kfree(kc);
+       return NULL;
+}
+
+static int soc_tplg_dapm_widget_create(struct soc_tplg *tplg,
+       struct snd_soc_tplg_dapm_widget *w)
+{
+       struct snd_soc_dapm_context *dapm = &tplg->comp->dapm;
+       struct snd_soc_dapm_widget template, *widget;
+       struct snd_soc_tplg_ctl_hdr *control_hdr;
+       struct snd_soc_card *card = tplg->comp->card;
+       int ret = 0;
+
+       if (strnlen(w->name, SNDRV_CTL_ELEM_ID_NAME_MAXLEN) ==
+               SNDRV_CTL_ELEM_ID_NAME_MAXLEN)
+               return -EINVAL;
+       if (strnlen(w->sname, SNDRV_CTL_ELEM_ID_NAME_MAXLEN) ==
+               SNDRV_CTL_ELEM_ID_NAME_MAXLEN)
+               return -EINVAL;
+
+       dev_dbg(tplg->dev, "ASoC: creating DAPM widget %s id %d\n",
+               w->name, w->id);
+
+       memset(&template, 0, sizeof(template));
+
+       /* map user to kernel widget ID */
+       template.id = get_widget_id(w->id);
+       if (template.id < 0)
+               return template.id;
+
+       template.name = kstrdup(w->name, GFP_KERNEL);
+       if (!template.name)
+               return -ENOMEM;
+       template.sname = kstrdup(w->sname, GFP_KERNEL);
+       if (!template.sname) {
+               ret = -ENOMEM;
+               goto err;
+       }
+       template.reg = w->reg;
+       template.shift = w->shift;
+       template.mask = w->mask;
+       template.on_val = w->invert ? 0 : 1;
+       template.off_val = w->invert ? 1 : 0;
+       template.ignore_suspend = w->ignore_suspend;
+       template.event_flags = w->event_flags;
+       template.dobj.index = tplg->index;
+
+       tplg->pos +=
+               (sizeof(struct snd_soc_tplg_dapm_widget) + w->priv.size);
+       if (w->num_kcontrols == 0) {
+               template.num_kcontrols = 0;
+               goto widget;
+       }
+
+       control_hdr = (struct snd_soc_tplg_ctl_hdr *)tplg->pos;
+       dev_dbg(tplg->dev, "ASoC: template %s has %d controls of type %x\n",
+               w->name, w->num_kcontrols, control_hdr->type);
+
+       switch (control_hdr->ops.info) {
+       case SND_SOC_TPLG_CTL_VOLSW:
+       case SND_SOC_TPLG_CTL_STROBE:
+       case SND_SOC_TPLG_CTL_VOLSW_SX:
+       case SND_SOC_TPLG_CTL_VOLSW_XR_SX:
+       case SND_SOC_TPLG_CTL_RANGE:
+       case SND_SOC_TPLG_DAPM_CTL_VOLSW:
+               template.num_kcontrols = w->num_kcontrols;
+               template.kcontrol_news =
+                       soc_tplg_dapm_widget_dmixer_create(tplg,
+                       template.num_kcontrols);
+               if (!template.kcontrol_news) {
+                       ret = -ENOMEM;
+                       goto hdr_err;
+               }
+               break;
+       case SND_SOC_TPLG_CTL_ENUM:
+       case SND_SOC_TPLG_CTL_ENUM_VALUE:
+       case SND_SOC_TPLG_DAPM_CTL_ENUM_DOUBLE:
+       case SND_SOC_TPLG_DAPM_CTL_ENUM_VIRT:
+       case SND_SOC_TPLG_DAPM_CTL_ENUM_VALUE:
+               template.dobj.widget.kcontrol_enum = 1;
+               template.num_kcontrols = 1;
+               template.kcontrol_news =
+                       soc_tplg_dapm_widget_denum_create(tplg);
+               if (!template.kcontrol_news) {
+                       ret = -ENOMEM;
+                       goto hdr_err;
+               }
+               break;
+       case SND_SOC_TPLG_CTL_BYTES:
+               template.num_kcontrols = w->num_kcontrols;
+               template.kcontrol_news =
+                       soc_tplg_dapm_widget_dbytes_create(tplg,
+                               template.num_kcontrols);
+               if (!template.kcontrol_news) {
+                       ret = -ENOMEM;
+                       goto hdr_err;
+               }
+               break;
+       default:
+               dev_err(tplg->dev, "ASoC: invalid widget control type %d:%d:%d\n",
+                       control_hdr->ops.get, control_hdr->ops.put,
+                       control_hdr->ops.info);
+               ret = -EINVAL;
+               goto hdr_err;
+       }
+
+widget:
+       ret = soc_tplg_widget_load(tplg, &template, w);
+       if (ret < 0)
+               goto hdr_err;
+
+       /* card dapm mutex is held by the core if we are loading topology
+        * data during sound card init. */
+       if (card->instantiated)
+               widget = snd_soc_dapm_new_control(dapm, &template);
+       else
+               widget = snd_soc_dapm_new_control_unlocked(dapm, &template);
+       if (widget == NULL) {
+               dev_err(tplg->dev, "ASoC: failed to create widget %s controls\n",
+                       w->name);
+               goto hdr_err;
+       }
+
+       widget->dobj.type = SND_SOC_DOBJ_WIDGET;
+       widget->dobj.ops = tplg->ops;
+       widget->dobj.index = tplg->index;
+       list_add(&widget->dobj.list, &tplg->comp->dobj_list);
+       return 0;
+
+hdr_err:
+       kfree(template.sname);
+err:
+       kfree(template.name);
+       return ret;
+}
+
+static int soc_tplg_dapm_widget_elems_load(struct soc_tplg *tplg,
+       struct snd_soc_tplg_hdr *hdr)
+{
+       struct snd_soc_tplg_dapm_widget *widget;
+       int ret, count = hdr->count, i;
+
+       if (tplg->pass != SOC_TPLG_PASS_WIDGET)
+               return 0;
+
+       dev_dbg(tplg->dev, "ASoC: adding %d DAPM widgets\n", count);
+
+       for (i = 0; i < count; i++) {
+               widget = (struct snd_soc_tplg_dapm_widget *) tplg->pos;
+               ret = soc_tplg_dapm_widget_create(tplg, widget);
+               if (ret < 0)
+                       dev_err(tplg->dev, "ASoC: failed to load widget %s\n",
+                               widget->name);
+       }
+
+       return 0;
+}
+
+static int soc_tplg_dapm_complete(struct soc_tplg *tplg)
+{
+       struct snd_soc_card *card = tplg->comp->card;
+       int ret;
+
+       /* Card might not have been registered at this point.
+        * If so, just return success.
+       */
+       if (!card || !card->instantiated) {
+               dev_warn(tplg->dev, "ASoC: Parent card not yet available,"
+                               "Do not add new widgets now\n");
+               return 0;
+       }
+
+       ret = snd_soc_dapm_new_widgets(card);
+       if (ret < 0)
+               dev_err(tplg->dev, "ASoC: failed to create new widgets %d\n",
+                       ret);
+
+       return 0;
+}
+
+static int soc_tplg_pcm_dai_elems_load(struct soc_tplg *tplg,
+       struct snd_soc_tplg_hdr *hdr)
+{
+       struct snd_soc_tplg_pcm_dai *pcm_dai;
+       struct snd_soc_dobj *dobj;
+       int count = hdr->count;
+       int ret;
+
+       if (tplg->pass != SOC_TPLG_PASS_PCM_DAI)
+               return 0;
+
+       pcm_dai = (struct snd_soc_tplg_pcm_dai *)tplg->pos;
+
+       if (soc_tplg_check_elem_count(tplg,
+               sizeof(struct snd_soc_tplg_pcm_dai), count,
+               hdr->payload_size, "PCM DAI")) {
+               dev_err(tplg->dev, "ASoC: invalid count %d for PCM DAI elems\n",
+                       count);
+               return -EINVAL;
+       }
+
+       dev_dbg(tplg->dev, "ASoC: adding %d PCM DAIs\n", count);
+       tplg->pos += sizeof(struct snd_soc_tplg_pcm_dai) * count;
+
+       dobj = kzalloc(sizeof(struct snd_soc_dobj), GFP_KERNEL);
+       if (dobj == NULL)
+               return -ENOMEM;
+
+       /* Call the platform driver call back to register the dais */
+       ret = soc_tplg_pcm_dai_load(tplg, pcm_dai, count);
+       if (ret < 0) {
+               dev_err(tplg->comp->dev, "ASoC: PCM DAI loading failed\n");
+               goto err;
+       }
+
+       dobj->type = get_dobj_type(hdr, NULL);
+       dobj->pcm_dai.count = count;
+       dobj->pcm_dai.pd = pcm_dai;
+       dobj->ops = tplg->ops;
+       dobj->index = tplg->index;
+       list_add(&dobj->list, &tplg->comp->dobj_list);
+       return 0;
+
+err:
+       kfree(dobj);
+       return ret;
+}
+
+static int soc_tplg_manifest_load(struct soc_tplg *tplg,
+       struct snd_soc_tplg_hdr *hdr)
+{
+       struct snd_soc_tplg_manifest *manifest;
+
+       if (tplg->pass != SOC_TPLG_PASS_MANIFEST)
+               return 0;
+
+       manifest = (struct snd_soc_tplg_manifest *)tplg->pos;
+       tplg->pos += sizeof(struct snd_soc_tplg_manifest);
+
+       if (tplg->comp && tplg->ops && tplg->ops->manifest)
+               return tplg->ops->manifest(tplg->comp, manifest);
+
+       dev_err(tplg->dev, "ASoC: Firmware manifest not supported\n");
+       return 0;
+}
+
+/* validate header magic, size and type */
+static int soc_valid_header(struct soc_tplg *tplg,
+       struct snd_soc_tplg_hdr *hdr)
+{
+       if (soc_tplg_get_hdr_offset(tplg) >= tplg->fw->size)
+               return 0;
+
+       /* big endian firmware objects not supported atm */
+       if (hdr->magic == cpu_to_be32(SND_SOC_TPLG_MAGIC)) {
+               dev_err(tplg->dev,
+                       "ASoC: pass %d big endian not supported header got %x at offset 0x%lx size 0x%zx.\n",
+                       tplg->pass, hdr->magic,
+                       soc_tplg_get_hdr_offset(tplg), tplg->fw->size);
+               return -EINVAL;
+       }
+
+       if (hdr->magic != SND_SOC_TPLG_MAGIC) {
+               dev_err(tplg->dev,
+                       "ASoC: pass %d does not have a valid header got %x at offset 0x%lx size 0x%zx.\n",
+                       tplg->pass, hdr->magic,
+                       soc_tplg_get_hdr_offset(tplg), tplg->fw->size);
+               return -EINVAL;
+       }
+
+       if (hdr->abi != SND_SOC_TPLG_ABI_VERSION) {
+               dev_err(tplg->dev,
+                       "ASoC: pass %d invalid ABI version got 0x%x need 0x%x at offset 0x%lx size 0x%zx.\n",
+                       tplg->pass, hdr->abi,
+                       SND_SOC_TPLG_ABI_VERSION, soc_tplg_get_hdr_offset(tplg),
+                       tplg->fw->size);
+               return -EINVAL;
+       }
+
+       if (hdr->payload_size == 0) {
+               dev_err(tplg->dev, "ASoC: header has 0 size at offset 0x%lx.\n",
+                       soc_tplg_get_hdr_offset(tplg));
+               return -EINVAL;
+       }
+
+       if (tplg->pass == hdr->type)
+               dev_dbg(tplg->dev,
+                       "ASoC: Got 0x%x bytes of type %d version %d vendor %d at pass %d\n",
+                       hdr->payload_size, hdr->type, hdr->version,
+                       hdr->vendor_type, tplg->pass);
+
+       return 1;
+}
+
+/* check header type and call appropriate handler */
+static int soc_tplg_load_header(struct soc_tplg *tplg,
+       struct snd_soc_tplg_hdr *hdr)
+{
+       tplg->pos = tplg->hdr_pos + sizeof(struct snd_soc_tplg_hdr);
+
+       /* check for matching ID */
+       if (hdr->index != tplg->req_index &&
+               hdr->index != SND_SOC_TPLG_INDEX_ALL)
+               return 0;
+
+       tplg->index = hdr->index;
+
+       switch (hdr->type) {
+       case SND_SOC_TPLG_TYPE_MIXER:
+       case SND_SOC_TPLG_TYPE_ENUM:
+       case SND_SOC_TPLG_TYPE_BYTES:
+               return soc_tplg_kcontrol_elems_load(tplg, hdr);
+       case SND_SOC_TPLG_TYPE_DAPM_GRAPH:
+               return soc_tplg_dapm_graph_elems_load(tplg, hdr);
+       case SND_SOC_TPLG_TYPE_DAPM_WIDGET:
+               return soc_tplg_dapm_widget_elems_load(tplg, hdr);
+       case SND_SOC_TPLG_TYPE_PCM:
+       case SND_SOC_TPLG_TYPE_DAI_LINK:
+       case SND_SOC_TPLG_TYPE_CODEC_LINK:
+               return soc_tplg_pcm_dai_elems_load(tplg, hdr);
+       case SND_SOC_TPLG_TYPE_MANIFEST:
+               return soc_tplg_manifest_load(tplg, hdr);
+       default:
+               /* bespoke vendor data object */
+               return soc_tplg_vendor_load(tplg, hdr);
+       }
+
+       return 0;
+}
+
+/* process the topology file headers */
+static int soc_tplg_process_headers(struct soc_tplg *tplg)
+{
+       struct snd_soc_tplg_hdr *hdr;
+       int ret;
+
+       tplg->pass = SOC_TPLG_PASS_START;
+
+       /* process the header types from start to end */
+       while (tplg->pass <= SOC_TPLG_PASS_END) {
+
+               tplg->hdr_pos = tplg->fw->data;
+               hdr = (struct snd_soc_tplg_hdr *)tplg->hdr_pos;
+
+               while (!soc_tplg_is_eof(tplg)) {
+
+                       /* make sure header is valid before loading */
+                       ret = soc_valid_header(tplg, hdr);
+                       if (ret < 0)
+                               return ret;
+                       else if (ret == 0)
+                               break;
+
+                       /* load the header object */
+                       ret = soc_tplg_load_header(tplg, hdr);
+                       if (ret < 0)
+                               return ret;
+
+                       /* goto next header */
+                       tplg->hdr_pos += hdr->payload_size +
+                               sizeof(struct snd_soc_tplg_hdr);
+                       hdr = (struct snd_soc_tplg_hdr *)tplg->hdr_pos;
+               }
+
+               /* next data type pass */
+               tplg->pass++;
+       }
+
+       /* signal DAPM we are complete */
+       ret = soc_tplg_dapm_complete(tplg);
+       if (ret < 0)
+               dev_err(tplg->dev,
+                       "ASoC: failed to initialise DAPM from Firmware\n");
+
+       return ret;
+}
+
+static int soc_tplg_load(struct soc_tplg *tplg)
+{
+       int ret;
+
+       ret = soc_tplg_process_headers(tplg);
+       if (ret == 0)
+               soc_tplg_complete(tplg);
+
+       return ret;
+}
+
+/* load audio component topology from "firmware" file */
+int snd_soc_tplg_component_load(struct snd_soc_component *comp,
+       struct snd_soc_tplg_ops *ops, const struct firmware *fw, u32 id)
+{
+       struct soc_tplg tplg;
+
+       /* setup parsing context */
+       memset(&tplg, 0, sizeof(tplg));
+       tplg.fw = fw;
+       tplg.dev = comp->dev;
+       tplg.comp = comp;
+       tplg.ops = ops;
+       tplg.req_index = id;
+       tplg.io_ops = ops->io_ops;
+       tplg.io_ops_count = ops->io_ops_count;
+
+       return soc_tplg_load(&tplg);
+}
+EXPORT_SYMBOL_GPL(snd_soc_tplg_component_load);
+
+/* remove this dynamic widget */
+void snd_soc_tplg_widget_remove(struct snd_soc_dapm_widget *w)
+{
+       /* make sure we are a widget */
+       if (w->dobj.type != SND_SOC_DOBJ_WIDGET)
+               return;
+
+       remove_widget(w->dapm->component, &w->dobj, SOC_TPLG_PASS_WIDGET);
+}
+EXPORT_SYMBOL_GPL(snd_soc_tplg_widget_remove);
+
+/* remove all dynamic widgets from this DAPM context */
+void snd_soc_tplg_widget_remove_all(struct snd_soc_dapm_context *dapm,
+       u32 index)
+{
+       struct snd_soc_dapm_widget *w, *next_w;
+       struct snd_soc_dapm_path *p, *next_p;
+
+       list_for_each_entry_safe(w, next_w, &dapm->card->widgets, list) {
+
+               /* make sure we are a widget with correct context */
+               if (w->dobj.type != SND_SOC_DOBJ_WIDGET || w->dapm != dapm)
+                       continue;
+
+               /* match ID */
+               if (w->dobj.index != index &&
+                       w->dobj.index != SND_SOC_TPLG_INDEX_ALL)
+                       continue;
+
+               list_del(&w->list);
+
+               /*
+                * remove source and sink paths associated to this widget.
+                * While removing the path, remove reference to it from both
+                * source and sink widgets so that path is removed only once.
+                */
+               list_for_each_entry_safe(p, next_p, &w->sources, list_sink) {
+                       list_del(&p->list_sink);
+                       list_del(&p->list_source);
+                       list_del(&p->list);
+                       kfree(p);
+               }
+               list_for_each_entry_safe(p, next_p, &w->sinks, list_source) {
+                       list_del(&p->list_sink);
+                       list_del(&p->list_source);
+                       list_del(&p->list);
+                       kfree(p);
+               }
+               /* check and free and dynamic widget kcontrols */
+               snd_soc_tplg_widget_remove(w);
+               kfree(w->kcontrols);
+               kfree(w->name);
+               kfree(w);
+       }
+}
+EXPORT_SYMBOL_GPL(snd_soc_tplg_widget_remove_all);
+
+/* remove dynamic controls from the component driver */
+int snd_soc_tplg_component_remove(struct snd_soc_component *comp, u32 index)
+{
+       struct snd_soc_dobj *dobj, *next_dobj;
+       int pass = SOC_TPLG_PASS_END;
+
+       /* process the header types from end to start */
+       while (pass >= SOC_TPLG_PASS_START) {
+
+               /* remove mixer controls */
+               list_for_each_entry_safe(dobj, next_dobj, &comp->dobj_list,
+                       list) {
+
+                       /* match index */
+                       if (dobj->index != index &&
+                               dobj->index != SND_SOC_TPLG_INDEX_ALL)
+                               continue;
+
+                       switch (dobj->type) {
+                       case SND_SOC_DOBJ_MIXER:
+                               remove_mixer(comp, dobj, pass);
+                               break;
+                       case SND_SOC_DOBJ_ENUM:
+                               remove_enum(comp, dobj, pass);
+                               break;
+                       case SND_SOC_DOBJ_BYTES:
+                               remove_bytes(comp, dobj, pass);
+                               break;
+                       case SND_SOC_DOBJ_WIDGET:
+                               remove_widget(comp, dobj, pass);
+                               break;
+                       case SND_SOC_DOBJ_PCM:
+                       case SND_SOC_DOBJ_DAI_LINK:
+                       case SND_SOC_DOBJ_CODEC_LINK:
+                               remove_pcm_dai(comp, dobj, pass);
+                               break;
+                       default:
+                               dev_err(comp->dev, "ASoC: invalid component type %d for removal\n",
+                                       dobj->type);
+                               break;
+                       }
+               }
+               pass--;
+       }
+
+       /* let caller know if FW can be freed when no objects are left */
+       return !list_empty(&comp->dobj_list);
+}
+EXPORT_SYMBOL_GPL(snd_soc_tplg_component_remove);
index b81a7a4c938b80e7f1eb43c2e3cfc56b4aa4488a..85d810d7667c1992d53a032c203ecf4631ac88f7 100644 (file)
@@ -372,6 +372,10 @@ int mop500_ab8500_machine_init(struct snd_soc_pcm_runtime *rtd)
        /* Create driver private-data struct */
        drvdata = devm_kzalloc(dev, sizeof(struct mop500_ab8500_drvdata),
                        GFP_KERNEL);
+
+       if (!drvdata)
+               return -ENOMEM;
+
        snd_soc_card_set_drvdata(rtd->card, drvdata);
 
        /* Setup clocks */
index 51a66a87305ae0ad96b26206108f13bcec5a189f..f12c01dddc8dd5df6dd185a91016b4e38820856a 100644 (file)
@@ -147,7 +147,6 @@ int ux500_pcm_register_platform(struct platform_device *pdev)
                pcm_config = &ux500_dmaengine_pcm_config;
 
        ret = snd_dmaengine_pcm_register(&pdev->dev, pcm_config,
-                                        SND_DMAENGINE_PCM_FLAG_NO_RESIDUE |
                                         SND_DMAENGINE_PCM_FLAG_COMPAT);
        if (ret < 0) {
                dev_err(&pdev->dev,
diff --git a/sound/soc/zte/Kconfig b/sound/soc/zte/Kconfig
new file mode 100644 (file)
index 0000000..c47eb25
--- /dev/null
@@ -0,0 +1,17 @@
+config ZX296702_SPDIF
+       tristate "ZX296702 spdif"
+       depends on SOC_ZX296702 || 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
+         zx296702 spdif interface
+
+config ZX296702_I2S
+       tristate "ZX296702 i2s"
+       depends on SOC_ZX296702 || 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
+         zx296702 i2s interface
diff --git a/sound/soc/zte/Makefile b/sound/soc/zte/Makefile
new file mode 100644 (file)
index 0000000..254ed2c
--- /dev/null
@@ -0,0 +1,2 @@
+obj-$(CONFIG_ZX296702_SPDIF)   += zx296702-spdif.o
+obj-$(CONFIG_ZX296702_I2S)     += zx296702-i2s.o
diff --git a/sound/soc/zte/zx296702-i2s.c b/sound/soc/zte/zx296702-i2s.c
new file mode 100644 (file)
index 0000000..98d96e1
--- /dev/null
@@ -0,0 +1,436 @@
+/*
+ * Copyright (C) 2015 Linaro
+ *
+ * Author: Jun Nie <jun.nie@linaro.org>
+ *
+ * License terms: GNU General Public License (GPL) version 2
+ */
+
+#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>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.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_clk;
+       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 timeing\n");
+               return -EINVAL;
+       }
+
+       switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+       case SND_SOC_DAIFMT_CBM_CFM:
+               i2s->master = 1;
+               val |= ZX_I2S_TIMING_MAST;
+               break;
+       case SND_SOC_DAIFMT_CBS_CFS:
+               i2s->master = 0;
+               val |= ZX_I2S_TIMING_SLAVE;
+               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 long val, format;
+       unsigned long chn_cfg;
+
+       dma_data = snd_soc_dai_get_dma_data(socdai, substream);
+       dma_data->addr_width = params_width(params) >> 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:
+               format = 0;
+               len = 16;
+               break;
+       case SNDRV_PCM_FORMAT_S24_LE:
+               format = 1;
+               len = 24;
+               break;
+       case SNDRV_PCM_FORMAT_S32_LE:
+               format = 2;
+               len = 32;
+               break;
+       default:
+               dev_err(socdai->dev, "Unknown data format\n");
+               return -EINVAL;
+       }
+       val |= ZX_I2S_TIMING_TS_WIDTH(len) | 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_clk,
+                                  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);
+       /* fall thru */
+       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);
+       /* fall thru */
+       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);
+
+       return clk_prepare_enable(zx_i2s->dai_clk);
+}
+
+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_clk);
+}
+
+static 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 =  kzalloc(sizeof(*zx_i2s), GFP_KERNEL);
+       if (!zx_i2s)
+               return -ENOMEM;
+
+       zx_i2s->dai_clk = devm_clk_get(&pdev->dev, "tx");
+       if (IS_ERR(zx_i2s->dai_clk)) {
+               dev_err(&pdev->dev, "Fail to get clk\n");
+               return PTR_ERR(zx_i2s->dai_clk);
+       }
+
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       zx_i2s->mapbase = res->start;
+       zx_i2s->reg_base = devm_ioremap_resource(&pdev->dev, res);
+       if (!zx_i2s->reg_base) {
+               dev_err(&pdev->dev, "ioremap failed!\n");
+               return -EIO;
+       }
+
+       writel_relaxed(0, zx_i2s->reg_base + ZX_I2S_FIFO_CTRL);
+       platform_set_drvdata(pdev, zx_i2s);
+
+       ret = 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/zx296702-spdif.c b/sound/soc/zte/zx296702-spdif.c
new file mode 100644 (file)
index 0000000..11a0e46
--- /dev/null
@@ -0,0 +1,365 @@
+/*
+ * Copyright (C) 2015 Linaro
+ *
+ * Author: Jun Nie <jun.nie@linaro.org>
+ *
+ * License terms: GNU General Public License (GPL) version 2
+ */
+
+#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               (4 * 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 = &zx_spdif->dma_data;
+       u32 val, ch_num, rate;
+       int ret;
+
+       dma_data = snd_soc_dai_get_dma_data(socdai, substream);
+       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);
+       /* fall thru */
+       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 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 (!zx_spdif->reg_base) {
+               dev_err(&pdev->dev, "ioremap failed!\n");
+               return -EIO;
+       }
+
+       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");
index ab37add269aecd6ae00909776d954735e587f9a2..82e350e9501ccc0d5ebc82962f60c034466448eb 100644 (file)
@@ -118,12 +118,8 @@ snd_emux_open_seq_oss(struct snd_seq_oss_arg *arg, void *closure)
        if (snd_BUG_ON(!arg || !emu))
                return -ENXIO;
 
-       mutex_lock(&emu->register_mutex);
-
-       if (!snd_emux_inc_count(emu)) {
-               mutex_unlock(&emu->register_mutex);
+       if (!snd_emux_inc_count(emu))
                return -EFAULT;
-       }
 
        memset(&callback, 0, sizeof(callback));
        callback.owner = THIS_MODULE;
@@ -135,7 +131,6 @@ snd_emux_open_seq_oss(struct snd_seq_oss_arg *arg, void *closure)
        if (p == NULL) {
                snd_printk(KERN_ERR "can't create port\n");
                snd_emux_dec_count(emu);
-               mutex_unlock(&emu->register_mutex);
                return -ENOMEM;
        }
 
@@ -148,8 +143,6 @@ snd_emux_open_seq_oss(struct snd_seq_oss_arg *arg, void *closure)
        reset_port_mode(p, arg->seq_mode);
 
        snd_emux_reset_port(p);
-
-       mutex_unlock(&emu->register_mutex);
        return 0;
 }
 
@@ -195,13 +188,11 @@ snd_emux_close_seq_oss(struct snd_seq_oss_arg *arg)
        if (snd_BUG_ON(!emu))
                return -ENXIO;
 
-       mutex_lock(&emu->register_mutex);
        snd_emux_sounds_off_all(p);
        snd_soundfont_close_check(emu->sflist, SF_CLIENT_NO(p->chset.port));
        snd_seq_event_port_detach(p->chset.client, p->chset.port);
        snd_emux_dec_count(emu);
 
-       mutex_unlock(&emu->register_mutex);
        return 0;
 }
 
index 7778b8e19782e24a3ca56a5aa5dff9e00bf33e4d..a0209204ae4892a490877c30eaf056c45cd8043a 100644 (file)
@@ -124,12 +124,10 @@ snd_emux_detach_seq(struct snd_emux *emu)
        if (emu->voices)
                snd_emux_terminate_all(emu);
                
-       mutex_lock(&emu->register_mutex);
        if (emu->client >= 0) {
                snd_seq_delete_kernel_client(emu->client);
                emu->client = -1;
        }
-       mutex_unlock(&emu->register_mutex);
 }
 
 
@@ -269,8 +267,8 @@ snd_emux_event_input(struct snd_seq_event *ev, int direct, void *private_data,
 /*
  * increment usage count
  */
-int
-snd_emux_inc_count(struct snd_emux *emu)
+static int
+__snd_emux_inc_count(struct snd_emux *emu)
 {
        emu->used++;
        if (!try_module_get(emu->ops.owner))
@@ -284,12 +282,21 @@ snd_emux_inc_count(struct snd_emux *emu)
        return 1;
 }
 
+int snd_emux_inc_count(struct snd_emux *emu)
+{
+       int ret;
+
+       mutex_lock(&emu->register_mutex);
+       ret = __snd_emux_inc_count(emu);
+       mutex_unlock(&emu->register_mutex);
+       return ret;
+}
 
 /*
  * decrease usage count
  */
-void
-snd_emux_dec_count(struct snd_emux *emu)
+static void
+__snd_emux_dec_count(struct snd_emux *emu)
 {
        module_put(emu->card->module);
        emu->used--;
@@ -298,6 +305,12 @@ snd_emux_dec_count(struct snd_emux *emu)
        module_put(emu->ops.owner);
 }
 
+void snd_emux_dec_count(struct snd_emux *emu)
+{
+       mutex_lock(&emu->register_mutex);
+       __snd_emux_dec_count(emu);
+       mutex_unlock(&emu->register_mutex);
+}
 
 /*
  * Routine that is called upon a first use of a particular port
@@ -317,7 +330,7 @@ snd_emux_use(void *private_data, struct snd_seq_port_subscribe *info)
 
        mutex_lock(&emu->register_mutex);
        snd_emux_init_port(p);
-       snd_emux_inc_count(emu);
+       __snd_emux_inc_count(emu);
        mutex_unlock(&emu->register_mutex);
        return 0;
 }
@@ -340,7 +353,7 @@ snd_emux_unuse(void *private_data, struct snd_seq_port_subscribe *info)
 
        mutex_lock(&emu->register_mutex);
        snd_emux_sounds_off_all(p);
-       snd_emux_dec_count(emu);
+       __snd_emux_dec_count(emu);
        mutex_unlock(&emu->register_mutex);
        return 0;
 }
index 3e2ef61c627b831bfec65724cc7166db051f5099..8b7e391dd0b80193d49f8634bb69fa45814593f0 100644 (file)
@@ -918,6 +918,7 @@ static void volume_control_quirks(struct usb_mixer_elem_info *cval,
        case USB_ID(0x046d, 0x081d): /* HD Webcam c510 */
        case USB_ID(0x046d, 0x0825): /* HD Webcam c270 */
        case USB_ID(0x046d, 0x0826): /* HD Webcam c525 */
+       case USB_ID(0x046d, 0x08ca): /* Logitech Quickcam Fusion */
        case USB_ID(0x046d, 0x0991):
        /* Most audio usb devices lie about volume resolution.
         * Most Logitech webcams have res = 384.
@@ -1582,12 +1583,6 @@ static int parse_audio_mixer_unit(struct mixer_build *state, int unitid,
                              unitid);
                return -EINVAL;
        }
-       /* no bmControls field (e.g. Maya44) -> ignore */
-       if (desc->bLength <= 10 + input_pins) {
-               usb_audio_dbg(state->chip, "MU %d has no bmControls field\n",
-                             unitid);
-               return 0;
-       }
 
        num_ins = 0;
        ich = 0;
@@ -1595,6 +1590,9 @@ static int parse_audio_mixer_unit(struct mixer_build *state, int unitid,
                err = parse_audio_unit(state, desc->baSourceID[pin]);
                if (err < 0)
                        continue;
+               /* no bmControls field (e.g. Maya44) -> ignore */
+               if (desc->bLength <= 10 + input_pins)
+                       continue;
                err = check_input_term(state, desc->baSourceID[pin], &iterm);
                if (err < 0)
                        return err;
index b703cb3cda1993402d60efc03e9e7d840cb68f72..e5000da9e9d7093f6e287194665de2d63f046e93 100644 (file)
@@ -436,6 +436,11 @@ static struct usbmix_ctl_map usbmix_ctl_maps[] = {
                .id = USB_ID(0x200c, 0x1018),
                .map = ebox44_map,
        },
+       {
+               /* MAYA44 USB+ */
+               .id = USB_ID(0x2573, 0x0008),
+               .map = maya44_map,
+       },
        {
                /* KEF X300A */
                .id = USB_ID(0x27ac, 0x1000),
index 7c5a701392785daf7b112443986e5527e63a0324..754e689596a21b43f3b3a45b8f3062ec29b74099 100644 (file)
@@ -1117,7 +1117,10 @@ bool snd_usb_get_sample_rate_quirk(struct snd_usb_audio *chip)
        switch (chip->usb_id) {
        case USB_ID(0x045E, 0x075D): /* MS Lifecam Cinema  */
        case USB_ID(0x045E, 0x076D): /* MS Lifecam HD-5000 */
+       case USB_ID(0x045E, 0x0772): /* MS Lifecam Studio */
+       case USB_ID(0x045E, 0x0779): /* MS Lifecam HD-3000 */
        case USB_ID(0x04D8, 0xFEEA): /* Benchmark DAC1 Pre */
+       case USB_ID(0x074D, 0x3553): /* Outlaw RR2150 (Micronas UAC3553B) */
                return true;
        }
        return false;
@@ -1264,8 +1267,9 @@ u64 snd_usb_interface_dsd_format_quirks(struct snd_usb_audio *chip,
                if (fp->altsetting == 2)
                        return SNDRV_PCM_FMTBIT_DSD_U32_BE;
                break;
-       /* DIYINHK DSD DXD 384kHz USB to I2S/DSD */
-       case USB_ID(0x20b1, 0x2009):
+
+       case USB_ID(0x20b1, 0x2009): /* DIYINHK DSD DXD 384kHz USB to I2S/DSD */
+       case USB_ID(0x20b1, 0x2023): /* JLsounds I2SoverUSB */
                if (fp->altsetting == 3)
                        return SNDRV_PCM_FMTBIT_DSD_U32_BE;
                break;
index d8fe29fc19a41de308141fac73ce05dc80388f39..8bd9606584632582f7e893c0a3c01e8f0240678f 100644 (file)
@@ -16,7 +16,7 @@ MAKEFLAGS += --no-print-directory
 LIBFILE = $(OUTPUT)libapi.a
 
 CFLAGS := $(EXTRA_WARNINGS) $(EXTRA_CFLAGS)
-CFLAGS += -ggdb3 -Wall -Wextra -std=gnu99 -Werror -O6 -D_FORTIFY_SOURCE=2 -fPIC
+CFLAGS += -ggdb3 -Wall -Wextra -std=gnu99 -Werror -O6 -U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=2 -fPIC
 CFLAGS += -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64
 
 RM = rm -f
index 0c356fb650220c6cd5d452d68a22eeb286d40d13..18ffccf004264d202632990d40227c27c41d27ad 100644 (file)
@@ -14,9 +14,10 @@ define allow-override
     $(eval $(1) = $(2)))
 endef
 
-# Allow setting CC and AR, or setting CROSS_COMPILE as a prefix.
+# Allow setting CC and AR and LD, or setting CROSS_COMPILE as a prefix.
 $(call allow-override,CC,$(CROSS_COMPILE)gcc)
 $(call allow-override,AR,$(CROSS_COMPILE)ar)
+$(call allow-override,LD,$(CROSS_COMPILE)ld)
 
 INSTALL = install
 
index a11e3c357be7f8fb00720694324f26adae0402c5..cd2cc59a5da7900e53084fe19e650438e13af0a2 100644 (file)
@@ -28,6 +28,9 @@
 #define __init
 #define noinline
 #define list_add_tail_rcu list_add_tail
+#define list_for_each_entry_rcu list_for_each_entry
+#define barrier() 
+#define synchronize_sched()
 
 #ifndef CALLER_ADDR0
 #define CALLER_ADDR0 ((unsigned long)__builtin_return_address(0))
index e0917c0f5d9f3babf82fc84ece90472a8a321f4e..29f94f6f0d9e9e2510d38471724e686a9a21167c 100644 (file)
@@ -3865,7 +3865,7 @@ static void print_str_arg(struct trace_seq *s, void *data, int size,
                        } else if (el_size == 4) {
                                trace_seq_printf(s, "%u", *(uint32_t *)num);
                        } else if (el_size == 8) {
-                               trace_seq_printf(s, "%lu", *(uint64_t *)num);
+                               trace_seq_printf(s, "%"PRIu64, *(uint64_t *)num);
                        } else {
                                trace_seq_printf(s, "BAD SIZE:%d 0x%x",
                                                 el_size, *(uint8_t *)num);
index c5baf9c591b7bb5a2c280e173f4e0a2b561285fa..618c2bcd4eabc6143b0e7f0431f57b8620101fe5 100644 (file)
@@ -123,6 +123,8 @@ static int get_last_jit_image(char *haystack, size_t hlen,
        assert(ret == 0);
 
        ptr = haystack;
+       memset(pmatch, 0, sizeof(pmatch));
+
        while (1) {
                ret = regexec(&regex, ptr, 1, pmatch, 0);
                if (ret == 0) {
index c699dc35eef9cbd1bc96427f453acc23a2e9c103..d31a7bbd7cee8610db236c7842cfb5ec63dc56b0 100644 (file)
@@ -24,7 +24,7 @@ unexport MAKEFLAGS
 # (To override it, run 'make JOBS=1' and similar.)
 #
 ifeq ($(JOBS),)
-  JOBS := $(shell egrep -c '^processor|^CPU' /proc/cpuinfo 2>/dev/null)
+  JOBS := $(shell (getconf _NPROCESSORS_ONLN || egrep -c '^processor|^CPU[0-9]' /proc/cpuinfo) 2>/dev/null)
   ifeq ($(JOBS),0)
     JOBS := 1
   endif
index bedff6b5b3cf3a61b38b172a97504cafebfd519f..ad0d9b5342fb6ae4713178daf15fdcce6238a2d9 100644 (file)
@@ -132,6 +132,9 @@ int bench_futex_requeue(int argc, const char **argv,
        if (!fshared)
                futex_flag = FUTEX_PRIVATE_FLAG;
 
+       if (nrequeue > nthreads)
+               nrequeue = nthreads;
+
        printf("Run summary [PID %d]: Requeuing %d threads (from [%s] %p to %p), "
               "%d at a time.\n\n",  getpid(), nthreads,
               fshared ? "shared":"private", &futex1, &futex2, nrequeue);
@@ -161,20 +164,18 @@ int bench_futex_requeue(int argc, const char **argv,
 
                /* Ok, all threads are patiently blocked, start requeueing */
                gettimeofday(&start, NULL);
-               for (nrequeued = 0; nrequeued < nthreads; nrequeued += nrequeue) {
+               while (nrequeued < nthreads) {
                        /*
                         * Do not wakeup any tasks blocked on futex1, allowing
                         * us to really measure futex_wait functionality.
                         */
-                       futex_cmp_requeue(&futex1, 0, &futex2, 0,
-                                         nrequeue, futex_flag);
+                       nrequeued += futex_cmp_requeue(&futex1, 0, &futex2, 0,
+                                                      nrequeue, futex_flag);
                }
+
                gettimeofday(&end, NULL);
                timersub(&end, &start, &runtime);
 
-               if (nrequeued > nthreads)
-                       nrequeued = nthreads;
-
                update_stats(&requeued_stats, nrequeued);
                update_stats(&requeuetime_stats, runtime.tv_usec);
 
@@ -184,7 +185,7 @@ int bench_futex_requeue(int argc, const char **argv,
                }
 
                /* everybody should be blocked on futex2, wake'em up */
-               nrequeued = futex_wake(&futex2, nthreads, futex_flag);
+               nrequeued = futex_wake(&futex2, nrequeued, futex_flag);
                if (nthreads != nrequeued)
                        warnx("couldn't wakeup all tasks (%d/%d)", nrequeued, nthreads);
 
index ebfa163b80b568af4d2708b1ff3b1980ea16e2b6..ba5efa4710b558239ff79c08b025ddc2da06efc5 100644 (file)
@@ -180,7 +180,7 @@ static const struct option options[] = {
        OPT_INTEGER('H', "thp"          , &p0.thp,              "MADV_NOHUGEPAGE < 0 < MADV_HUGEPAGE"),
        OPT_BOOLEAN('c', "show_convergence", &p0.show_convergence, "show convergence details"),
        OPT_BOOLEAN('m', "measure_convergence", &p0.measure_convergence, "measure convergence latency"),
-       OPT_BOOLEAN('q', "quiet"        , &p0.show_quiet,       "bzero the initial allocations"),
+       OPT_BOOLEAN('q', "quiet"        , &p0.show_quiet,       "quiet mode"),
        OPT_BOOLEAN('S', "serialize-startup", &p0.serialize_startup,"serialize thread startup"),
 
        /* Special option string parsing callbacks: */
@@ -828,6 +828,9 @@ static int count_process_nodes(int process_nr)
                td = g->threads + task_nr;
 
                node = numa_node_of_cpu(td->curr_cpu);
+               if (node < 0) /* curr_cpu was likely still -1 */
+                       return 0;
+
                node_present[node] = 1;
        }
 
@@ -882,6 +885,11 @@ static void calc_convergence_compression(int *strong)
        for (p = 0; p < g->p.nr_proc; p++) {
                unsigned int nodes = count_process_nodes(p);
 
+               if (!nodes) {
+                       *strong = 0;
+                       return;
+               }
+
                nodes_min = min(nodes, nodes_min);
                nodes_max = max(nodes, nodes_max);
        }
@@ -1395,7 +1403,7 @@ static void print_res(const char *name, double val,
        if (!name)
                name = "main,";
 
-       if (g->p.show_quiet)
+       if (!g->p.show_quiet)
                printf(" %-30s %15.3f, %-15s %s\n", name, val, txt_unit, txt_short);
        else
                printf(" %14.3f %s\n", val, txt_long);
index 63ea01349b6e2b6c6bf4fb16ce3722c93d625695..1634186d537cdc2eb2ee38b174891361ef13db9f 100644 (file)
@@ -319,7 +319,7 @@ static int page_stat_cmp(struct page_stat *a, struct page_stat *b)
        return 0;
 }
 
-static struct page_stat *search_page_alloc_stat(struct page_stat *stat, bool create)
+static struct page_stat *search_page_alloc_stat(struct page_stat *pstat, bool create)
 {
        struct rb_node **node = &page_alloc_tree.rb_node;
        struct rb_node *parent = NULL;
@@ -331,7 +331,7 @@ static struct page_stat *search_page_alloc_stat(struct page_stat *stat, bool cre
                parent = *node;
                data = rb_entry(*node, struct page_stat, node);
 
-               cmp = page_stat_cmp(data, stat);
+               cmp = page_stat_cmp(data, pstat);
                if (cmp < 0)
                        node = &parent->rb_left;
                else if (cmp > 0)
@@ -345,10 +345,10 @@ static struct page_stat *search_page_alloc_stat(struct page_stat *stat, bool cre
 
        data = zalloc(sizeof(*data));
        if (data != NULL) {
-               data->page = stat->page;
-               data->order = stat->order;
-               data->gfp_flags = stat->gfp_flags;
-               data->migrate_type = stat->migrate_type;
+               data->page = pstat->page;
+               data->order = pstat->order;
+               data->gfp_flags = pstat->gfp_flags;
+               data->migrate_type = pstat->migrate_type;
 
                rb_link_node(&data->node, parent, node);
                rb_insert_color(&data->node, &page_alloc_tree);
@@ -375,7 +375,7 @@ static int perf_evsel__process_page_alloc_event(struct perf_evsel *evsel,
        unsigned int migrate_type = perf_evsel__intval(evsel, sample,
                                                       "migratetype");
        u64 bytes = kmem_page_size << order;
-       struct page_stat *stat;
+       struct page_stat *pstat;
        struct page_stat this = {
                .order = order,
                .gfp_flags = gfp_flags,
@@ -401,21 +401,21 @@ static int perf_evsel__process_page_alloc_event(struct perf_evsel *evsel,
         * This is to find the current page (with correct gfp flags and
         * migrate type) at free event.
         */
-       stat = search_page(page, true);
-       if (stat == NULL)
+       pstat = search_page(page, true);
+       if (pstat == NULL)
                return -ENOMEM;
 
-       stat->order = order;
-       stat->gfp_flags = gfp_flags;
-       stat->migrate_type = migrate_type;
+       pstat->order = order;
+       pstat->gfp_flags = gfp_flags;
+       pstat->migrate_type = migrate_type;
 
        this.page = page;
-       stat = search_page_alloc_stat(&this, true);
-       if (stat == NULL)
+       pstat = search_page_alloc_stat(&this, true);
+       if (pstat == NULL)
                return -ENOMEM;
 
-       stat->nr_alloc++;
-       stat->alloc_bytes += bytes;
+       pstat->nr_alloc++;
+       pstat->alloc_bytes += bytes;
 
        order_stats[order][migrate_type]++;
 
@@ -428,7 +428,7 @@ static int perf_evsel__process_page_free_event(struct perf_evsel *evsel,
        u64 page;
        unsigned int order = perf_evsel__intval(evsel, sample, "order");
        u64 bytes = kmem_page_size << order;
-       struct page_stat *stat;
+       struct page_stat *pstat;
        struct page_stat this = {
                .order = order,
        };
@@ -441,8 +441,8 @@ static int perf_evsel__process_page_free_event(struct perf_evsel *evsel,
        nr_page_frees++;
        total_page_free_bytes += bytes;
 
-       stat = search_page(page, false);
-       if (stat == NULL) {
+       pstat = search_page(page, false);
+       if (pstat == NULL) {
                pr_debug2("missing free at page %"PRIx64" (order: %d)\n",
                          page, order);
 
@@ -453,18 +453,18 @@ static int perf_evsel__process_page_free_event(struct perf_evsel *evsel,
        }
 
        this.page = page;
-       this.gfp_flags = stat->gfp_flags;
-       this.migrate_type = stat->migrate_type;
+       this.gfp_flags = pstat->gfp_flags;
+       this.migrate_type = pstat->migrate_type;
 
-       rb_erase(&stat->node, &page_tree);
-       free(stat);
+       rb_erase(&pstat->node, &page_tree);
+       free(pstat);
 
-       stat = search_page_alloc_stat(&this, false);
-       if (stat == NULL)
+       pstat = search_page_alloc_stat(&this, false);
+       if (pstat == NULL)
                return -ENOENT;
 
-       stat->nr_free++;
-       stat->free_bytes += bytes;
+       pstat->nr_free++;
+       pstat->free_bytes += bytes;
 
        return 0;
 }
@@ -640,9 +640,9 @@ static void print_page_summary(void)
               nr_page_frees, total_page_free_bytes / 1024);
        printf("\n");
 
-       printf("%-30s: %'16lu   [ %'16"PRIu64" KB ]\n", "Total alloc+freed requests",
+       printf("%-30s: %'16"PRIu64"   [ %'16"PRIu64" KB ]\n", "Total alloc+freed requests",
               nr_alloc_freed, (total_alloc_freed_bytes) / 1024);
-       printf("%-30s: %'16lu   [ %'16"PRIu64" KB ]\n", "Total alloc-only requests",
+       printf("%-30s: %'16"PRIu64"   [ %'16"PRIu64" KB ]\n", "Total alloc-only requests",
               nr_page_allocs - nr_alloc_freed,
               (total_page_alloc_bytes - total_alloc_freed_bytes) / 1024);
        printf("%-30s: %'16lu   [ %'16"PRIu64" KB ]\n", "Total free-only requests",
index 476cdf7afcca3fc7b1135d9973d15886cd7b8988..b63aeda719be0c7604da5229e1a3a0ec33253400 100644 (file)
@@ -329,7 +329,7 @@ static int perf_evlist__tty_browse_hists(struct perf_evlist *evlist,
                fprintf(stdout, "\n\n");
        }
 
-       if (sort_order == default_sort_order &&
+       if (sort_order == NULL &&
            parent_pattern == default_parent_pattern) {
                fprintf(stdout, "#\n# (%s)\n#\n", help);
 
index 1cb3436276d1599ea0f1ffc80d36e655aad690be..6a4d5d41c671d0ce176deb13d318de35acee0161 100644 (file)
@@ -733,7 +733,7 @@ static void perf_event__process_sample(struct perf_tool *tool,
 "Kernel address maps (/proc/{kallsyms,modules}) are restricted.\n\n"
 "Check /proc/sys/kernel/kptr_restrict.\n\n"
 "Kernel%s samples will not be resolved.\n",
-                         !RB_EMPTY_ROOT(&al.map->dso->symbols[MAP__FUNCTION]) ?
+                         al.map && !RB_EMPTY_ROOT(&al.map->dso->symbols[MAP__FUNCTION]) ?
                          " modules" : "");
                if (use_browser <= 0)
                        sleep(5);
index e124741be187ee729a77b088d30f843ee24eefa4..e122970361f21af6d07c321480aefa2cb90bf31d 100644 (file)
@@ -2241,10 +2241,11 @@ static int trace__run(struct trace *trace, int argc, const char **argv)
        if (err < 0)
                goto out_error_mmap;
 
+       if (!target__none(&trace->opts.target))
+               perf_evlist__enable(evlist);
+
        if (forks)
                perf_evlist__start_workload(evlist);
-       else
-               perf_evlist__enable(evlist);
 
        trace->multiple_threads = evlist->threads->map[0] == -1 ||
                                  evlist->threads->nr > 1 ||
@@ -2272,6 +2273,11 @@ next_event:
 
                        if (interrupted)
                                goto out_disable;
+
+                       if (done && !draining) {
+                               perf_evlist__disable(evlist);
+                               draining = true;
+                       }
                }
        }
 
index d8bb616ff57c29b38c05ac134d35e88f646f42cd..d05b77cf35f77051354b9d08acc035cf4575dd5b 100644 (file)
@@ -1084,6 +1084,8 @@ static int parse_perf_probe_point(char *arg, struct perf_probe_event *pev)
         *
         * TODO:Group name support
         */
+       if (!arg)
+               return -EINVAL;
 
        ptr = strpbrk(arg, ";=@+%");
        if (ptr && *ptr == '=') {       /* Event name */
index b5bf9d5efeaf2dc32317573de059c1d73367cc7c..2a76e14db73289d196a0171f4830693b46445e23 100644 (file)
@@ -578,10 +578,12 @@ static int find_variable(Dwarf_Die *sc_die, struct probe_finder *pf)
        /* Search child die for local variables and parameters. */
        if (!die_find_variable_at(sc_die, pf->pvar->var, pf->addr, &vr_die)) {
                /* Search again in global variables */
-               if (!die_find_variable_at(&pf->cu_die, pf->pvar->var, 0, &vr_die))
+               if (!die_find_variable_at(&pf->cu_die, pf->pvar->var,
+                                               0, &vr_die)) {
                        pr_warning("Failed to find '%s' in this function.\n",
                                   pf->pvar->var);
                        ret = -ENOENT;
+               }
        }
        if (ret >= 0)
                ret = convert_variable(&vr_die, pf);
index bac98ca3d4ca7e4cd8efb36e79d550a43bb4d1d4..323b65edfc970b5ba5783de3c16f8b684728e47b 100644 (file)
@@ -52,6 +52,7 @@ unsigned int skip_c0;
 unsigned int skip_c1;
 unsigned int do_nhm_cstates;
 unsigned int do_snb_cstates;
+unsigned int do_knl_cstates;
 unsigned int do_pc2;
 unsigned int do_pc3;
 unsigned int do_pc6;
@@ -91,6 +92,7 @@ unsigned int do_gfx_perf_limit_reasons;
 unsigned int do_ring_perf_limit_reasons;
 unsigned int crystal_hz;
 unsigned long long tsc_hz;
+int base_cpu;
 
 #define RAPL_PKG               (1 << 0)
                                        /* 0x610 MSR_PKG_POWER_LIMIT */
@@ -316,7 +318,7 @@ void print_header(void)
 
        if (do_nhm_cstates)
                outp += sprintf(outp, "  CPU%%c1");
-       if (do_nhm_cstates && !do_slm_cstates)
+       if (do_nhm_cstates && !do_slm_cstates && !do_knl_cstates)
                outp += sprintf(outp, "  CPU%%c3");
        if (do_nhm_cstates)
                outp += sprintf(outp, "  CPU%%c6");
@@ -546,7 +548,7 @@ int format_counters(struct thread_data *t, struct core_data *c,
        if (!(t->flags & CPU_IS_FIRST_THREAD_IN_CORE))
                goto done;
 
-       if (do_nhm_cstates && !do_slm_cstates)
+       if (do_nhm_cstates && !do_slm_cstates && !do_knl_cstates)
                outp += sprintf(outp, "%8.2f", 100.0 * c->c3/t->tsc);
        if (do_nhm_cstates)
                outp += sprintf(outp, "%8.2f", 100.0 * c->c6/t->tsc);
@@ -1018,14 +1020,17 @@ int get_counters(struct thread_data *t, struct core_data *c, struct pkg_data *p)
        if (!(t->flags & CPU_IS_FIRST_THREAD_IN_CORE))
                return 0;
 
-       if (do_nhm_cstates && !do_slm_cstates) {
+       if (do_nhm_cstates && !do_slm_cstates && !do_knl_cstates) {
                if (get_msr(cpu, MSR_CORE_C3_RESIDENCY, &c->c3))
                        return -6;
        }
 
-       if (do_nhm_cstates) {
+       if (do_nhm_cstates && !do_knl_cstates) {
                if (get_msr(cpu, MSR_CORE_C6_RESIDENCY, &c->c6))
                        return -7;
+       } else if (do_knl_cstates) {
+               if (get_msr(cpu, MSR_KNL_CORE_C6_RESIDENCY, &c->c6))
+                       return -7;
        }
 
        if (do_snb_cstates)
@@ -1150,7 +1155,7 @@ dump_nhm_platform_info(void)
        unsigned long long msr;
        unsigned int ratio;
 
-       get_msr(0, MSR_NHM_PLATFORM_INFO, &msr);
+       get_msr(base_cpu, MSR_NHM_PLATFORM_INFO, &msr);
 
        fprintf(stderr, "cpu0: MSR_NHM_PLATFORM_INFO: 0x%08llx\n", msr);
 
@@ -1162,7 +1167,7 @@ dump_nhm_platform_info(void)
        fprintf(stderr, "%d * %.0f = %.0f MHz base frequency\n",
                ratio, bclk, ratio * bclk);
 
-       get_msr(0, MSR_IA32_POWER_CTL, &msr);
+       get_msr(base_cpu, MSR_IA32_POWER_CTL, &msr);
        fprintf(stderr, "cpu0: MSR_IA32_POWER_CTL: 0x%08llx (C1E auto-promotion: %sabled)\n",
                msr, msr & 0x2 ? "EN" : "DIS");
 
@@ -1175,7 +1180,7 @@ dump_hsw_turbo_ratio_limits(void)
        unsigned long long msr;
        unsigned int ratio;
 
-       get_msr(0, MSR_TURBO_RATIO_LIMIT2, &msr);
+       get_msr(base_cpu, MSR_TURBO_RATIO_LIMIT2, &msr);
 
        fprintf(stderr, "cpu0: MSR_TURBO_RATIO_LIMIT2: 0x%08llx\n", msr);
 
@@ -1197,7 +1202,7 @@ dump_ivt_turbo_ratio_limits(void)
        unsigned long long msr;
        unsigned int ratio;
 
-       get_msr(0, MSR_TURBO_RATIO_LIMIT1, &msr);
+       get_msr(base_cpu, MSR_TURBO_RATIO_LIMIT1, &msr);
 
        fprintf(stderr, "cpu0: MSR_TURBO_RATIO_LIMIT1: 0x%08llx\n", msr);
 
@@ -1249,7 +1254,7 @@ dump_nhm_turbo_ratio_limits(void)
        unsigned long long msr;
        unsigned int ratio;
 
-       get_msr(0, MSR_TURBO_RATIO_LIMIT, &msr);
+       get_msr(base_cpu, MSR_TURBO_RATIO_LIMIT, &msr);
 
        fprintf(stderr, "cpu0: MSR_TURBO_RATIO_LIMIT: 0x%08llx\n", msr);
 
@@ -1295,12 +1300,73 @@ dump_nhm_turbo_ratio_limits(void)
        return;
 }
 
+static void
+dump_knl_turbo_ratio_limits(void)
+{
+       int cores;
+       unsigned int ratio;
+       unsigned long long msr;
+       int delta_cores;
+       int delta_ratio;
+       int i;
+
+       get_msr(base_cpu, MSR_NHM_TURBO_RATIO_LIMIT, &msr);
+
+       fprintf(stderr, "cpu0: MSR_NHM_TURBO_RATIO_LIMIT: 0x%08llx\n",
+       msr);
+
+       /**
+        * Turbo encoding in KNL is as follows:
+        * [7:0] -- Base value of number of active cores of bucket 1.
+        * [15:8] -- Base value of freq ratio of bucket 1.
+        * [20:16] -- +ve delta of number of active cores of bucket 2.
+        * i.e. active cores of bucket 2 =
+        * active cores of bucket 1 + delta
+        * [23:21] -- Negative delta of freq ratio of bucket 2.
+        * i.e. freq ratio of bucket 2 =
+        * freq ratio of bucket 1 - delta
+        * [28:24]-- +ve delta of number of active cores of bucket 3.
+        * [31:29]-- -ve delta of freq ratio of bucket 3.
+        * [36:32]-- +ve delta of number of active cores of bucket 4.
+        * [39:37]-- -ve delta of freq ratio of bucket 4.
+        * [44:40]-- +ve delta of number of active cores of bucket 5.
+        * [47:45]-- -ve delta of freq ratio of bucket 5.
+        * [52:48]-- +ve delta of number of active cores of bucket 6.
+        * [55:53]-- -ve delta of freq ratio of bucket 6.
+        * [60:56]-- +ve delta of number of active cores of bucket 7.
+        * [63:61]-- -ve delta of freq ratio of bucket 7.
+        */
+       cores = msr & 0xFF;
+       ratio = (msr >> 8) && 0xFF;
+       if (ratio > 0)
+               fprintf(stderr,
+                       "%d * %.0f = %.0f MHz max turbo %d active cores\n",
+                       ratio, bclk, ratio * bclk, cores);
+
+       for (i = 16; i < 64; i = i + 8) {
+               delta_cores = (msr >> i) & 0x1F;
+               delta_ratio = (msr >> (i + 5)) && 0x7;
+               if (!delta_cores || !delta_ratio)
+                       return;
+               cores = cores + delta_cores;
+               ratio = ratio - delta_ratio;
+
+               /** -ve ratios will make successive ratio calculations
+                * negative. Hence return instead of carrying on.
+                */
+               if (ratio > 0)
+                       fprintf(stderr,
+                               "%d * %.0f = %.0f MHz max turbo %d active cores\n",
+                               ratio, bclk, ratio * bclk, cores);
+       }
+}
+
 static void
 dump_nhm_cst_cfg(void)
 {
        unsigned long long msr;
 
-       get_msr(0, MSR_NHM_SNB_PKG_CST_CFG_CTL, &msr);
+       get_msr(base_cpu, MSR_NHM_SNB_PKG_CST_CFG_CTL, &msr);
 
 #define SNB_C1_AUTO_UNDEMOTE              (1UL << 27)
 #define SNB_C3_AUTO_UNDEMOTE              (1UL << 28)
@@ -1381,12 +1447,41 @@ int parse_int_file(const char *fmt, ...)
 }
 
 /*
- * cpu_is_first_sibling_in_core(cpu)
- * return 1 if given CPU is 1st HT sibling in the core
+ * get_cpu_position_in_core(cpu)
+ * return the position of the CPU among its HT siblings in the core
+ * return -1 if the sibling is not in list
  */
-int cpu_is_first_sibling_in_core(int cpu)
+int get_cpu_position_in_core(int cpu)
 {
-       return cpu == parse_int_file("/sys/devices/system/cpu/cpu%d/topology/thread_siblings_list", cpu);
+       char path[64];
+       FILE *filep;
+       int this_cpu;
+       char character;
+       int i;
+
+       sprintf(path,
+               "/sys/devices/system/cpu/cpu%d/topology/thread_siblings_list",
+               cpu);
+       filep = fopen(path, "r");
+       if (filep == NULL) {
+               perror(path);
+               exit(1);
+       }
+
+       for (i = 0; i < topo.num_threads_per_core; i++) {
+               fscanf(filep, "%d", &this_cpu);
+               if (this_cpu == cpu) {
+                       fclose(filep);
+                       return i;
+               }
+
+               /* Account for no separator after last thread*/
+               if (i != (topo.num_threads_per_core - 1))
+                       fscanf(filep, "%c", &character);
+       }
+
+       fclose(filep);
+       return -1;
 }
 
 /*
@@ -1412,25 +1507,31 @@ int get_num_ht_siblings(int cpu)
 {
        char path[80];
        FILE *filep;
-       int sib1, sib2;
-       int matches;
+       int sib1;
+       int matches = 0;
        char character;
+       char str[100];
+       char *ch;
 
        sprintf(path, "/sys/devices/system/cpu/cpu%d/topology/thread_siblings_list", cpu);
        filep = fopen_or_die(path, "r");
+
        /*
         * file format:
-        * if a pair of number with a character between: 2 siblings (eg. 1-2, or 1,4)
-        * otherwinse 1 sibling (self).
+        * A ',' separated or '-' separated set of numbers
+        * (eg 1-2 or 1,3,4,5)
         */
-       matches = fscanf(filep, "%d%c%d\n", &sib1, &character, &sib2);
+       fscanf(filep, "%d%c\n", &sib1, &character);
+       fseek(filep, 0, SEEK_SET);
+       fgets(str, 100, filep);
+       ch = strchr(str, character);
+       while (ch != NULL) {
+               matches++;
+               ch = strchr(ch+1, character);
+       }
 
        fclose(filep);
-
-       if (matches == 3)
-               return 2;
-       else
-               return 1;
+       return matches+1;
 }
 
 /*
@@ -1594,8 +1695,10 @@ restart:
 void check_dev_msr()
 {
        struct stat sb;
+       char pathname[32];
 
-       if (stat("/dev/cpu/0/msr", &sb))
+       sprintf(pathname, "/dev/cpu/%d/msr", base_cpu);
+       if (stat(pathname, &sb))
                if (system("/sbin/modprobe msr > /dev/null 2>&1"))
                        err(-5, "no /dev/cpu/0/msr, Try \"# modprobe msr\" ");
 }
@@ -1608,6 +1711,7 @@ void check_permissions()
        cap_user_data_t cap_data = &cap_data_data;
        extern int capget(cap_user_header_t hdrp, cap_user_data_t datap);
        int do_exit = 0;
+       char pathname[32];
 
        /* check for CAP_SYS_RAWIO */
        cap_header->pid = getpid();
@@ -1622,7 +1726,8 @@ void check_permissions()
        }
 
        /* test file permissions */
-       if (euidaccess("/dev/cpu/0/msr", R_OK)) {
+       sprintf(pathname, "/dev/cpu/%d/msr", base_cpu);
+       if (euidaccess(pathname, R_OK)) {
                do_exit++;
                warn("/dev/cpu/0/msr open failed, try chown or chmod +r /dev/cpu/*/msr");
        }
@@ -1704,7 +1809,7 @@ int probe_nhm_msrs(unsigned int family, unsigned int model)
        default:
                return 0;
        }
-       get_msr(0, MSR_NHM_SNB_PKG_CST_CFG_CTL, &msr);
+       get_msr(base_cpu, MSR_NHM_SNB_PKG_CST_CFG_CTL, &msr);
 
        pkg_cstate_limit = pkg_cstate_limits[msr & 0xF];
 
@@ -1753,6 +1858,21 @@ int has_hsw_turbo_ratio_limit(unsigned int family, unsigned int model)
        }
 }
 
+int has_knl_turbo_ratio_limit(unsigned int family, unsigned int model)
+{
+       if (!genuine_intel)
+               return 0;
+
+       if (family != 6)
+               return 0;
+
+       switch (model) {
+       case 0x57:      /* Knights Landing */
+               return 1;
+       default:
+               return 0;
+       }
+}
 static void
 dump_cstate_pstate_config_info(family, model)
 {
@@ -1770,6 +1890,9 @@ dump_cstate_pstate_config_info(family, model)
        if (has_nhm_turbo_ratio_limit(family, model))
                dump_nhm_turbo_ratio_limits();
 
+       if (has_knl_turbo_ratio_limit(family, model))
+               dump_knl_turbo_ratio_limits();
+
        dump_nhm_cst_cfg();
 }
 
@@ -1801,7 +1924,7 @@ int print_epb(struct thread_data *t, struct core_data *c, struct pkg_data *p)
        if (get_msr(cpu, MSR_IA32_ENERGY_PERF_BIAS, &msr))
                return 0;
 
-       switch (msr & 0x7) {
+       switch (msr & 0xF) {
        case ENERGY_PERF_BIAS_PERFORMANCE:
                epb_string = "performance";
                break;
@@ -1925,7 +2048,7 @@ double get_tdp(model)
        unsigned long long msr;
 
        if (do_rapl & RAPL_PKG_POWER_INFO)
-               if (!get_msr(0, MSR_PKG_POWER_INFO, &msr))
+               if (!get_msr(base_cpu, MSR_PKG_POWER_INFO, &msr))
                        return ((msr >> 0) & RAPL_POWER_GRANULARITY) * rapl_power_units;
 
        switch (model) {
@@ -1950,6 +2073,7 @@ rapl_dram_energy_units_probe(int  model, double rapl_energy_units)
        case 0x3F:      /* HSX */
        case 0x4F:      /* BDX */
        case 0x56:      /* BDX-DE */
+       case 0x57:      /* KNL */
                return (rapl_dram_energy_units = 15.3 / 1000000);
        default:
                return (rapl_energy_units);
@@ -1991,6 +2115,7 @@ void rapl_probe(unsigned int family, unsigned int model)
        case 0x3F:      /* HSX */
        case 0x4F:      /* BDX */
        case 0x56:      /* BDX-DE */
+       case 0x57:      /* KNL */
                do_rapl = RAPL_PKG | RAPL_DRAM | RAPL_DRAM_POWER_INFO | RAPL_DRAM_PERF_STATUS | RAPL_PKG_PERF_STATUS | RAPL_PKG_POWER_INFO;
                break;
        case 0x2D:
@@ -2006,7 +2131,7 @@ void rapl_probe(unsigned int family, unsigned int model)
        }
 
        /* units on package 0, verify later other packages match */
-       if (get_msr(0, MSR_RAPL_POWER_UNIT, &msr))
+       if (get_msr(base_cpu, MSR_RAPL_POWER_UNIT, &msr))
                return;
 
        rapl_power_units = 1.0 / (1 << (msr & 0xF));
@@ -2331,6 +2456,17 @@ int is_slm(unsigned int family, unsigned int model)
        return 0;
 }
 
+int is_knl(unsigned int family, unsigned int model)
+{
+       if (!genuine_intel)
+               return 0;
+       switch (model) {
+       case 0x57:      /* KNL */
+               return 1;
+       }
+       return 0;
+}
+
 #define SLM_BCLK_FREQS 5
 double slm_freq_table[SLM_BCLK_FREQS] = { 83.3, 100.0, 133.3, 116.7, 80.0};
 
@@ -2340,7 +2476,7 @@ double slm_bclk(void)
        unsigned int i;
        double freq;
 
-       if (get_msr(0, MSR_FSB_FREQ, &msr))
+       if (get_msr(base_cpu, MSR_FSB_FREQ, &msr))
                fprintf(stderr, "SLM BCLK: unknown\n");
 
        i = msr & 0xf;
@@ -2408,7 +2544,7 @@ int set_temperature_target(struct thread_data *t, struct core_data *c, struct pk
        if (!do_nhm_platform_info)
                goto guess;
 
-       if (get_msr(0, MSR_IA32_TEMPERATURE_TARGET, &msr))
+       if (get_msr(base_cpu, MSR_IA32_TEMPERATURE_TARGET, &msr))
                goto guess;
 
        target_c_local = (msr >> 16) & 0xFF;
@@ -2541,6 +2677,7 @@ void process_cpuid()
        do_c8_c9_c10 = has_hsw_msrs(family, model);
        do_skl_residency = has_skl_msrs(family, model);
        do_slm_cstates = is_slm(family, model);
+       do_knl_cstates  = is_knl(family, model);
        bclk = discover_bclk(family, model);
 
        rapl_probe(family, model);
@@ -2755,13 +2892,9 @@ int initialize_counters(int cpu_id)
 
        my_package_id = get_physical_package_id(cpu_id);
        my_core_id = get_core_id(cpu_id);
-
-       if (cpu_is_first_sibling_in_core(cpu_id)) {
-               my_thread_id = 0;
+       my_thread_id = get_cpu_position_in_core(cpu_id);
+       if (!my_thread_id)
                topo.num_cores++;
-       } else {
-               my_thread_id = 1;
-       }
 
        init_counter(EVEN_COUNTERS, my_thread_id, my_core_id, my_package_id, cpu_id);
        init_counter(ODD_COUNTERS, my_thread_id, my_core_id, my_package_id, cpu_id);
@@ -2785,13 +2918,24 @@ void setup_all_buffers(void)
        for_all_proc_cpus(initialize_counters);
 }
 
+void set_base_cpu(void)
+{
+       base_cpu = sched_getcpu();
+       if (base_cpu < 0)
+               err(-ENODEV, "No valid cpus found");
+
+       if (debug > 1)
+               fprintf(stderr, "base_cpu = %d\n", base_cpu);
+}
+
 void turbostat_init()
 {
+       setup_all_buffers();
+       set_base_cpu();
        check_dev_msr();
        check_permissions();
        process_cpuid();
 
-       setup_all_buffers();
 
        if (debug)
                for_all_cpus(print_epb, ODD_COUNTERS);
@@ -2870,7 +3014,7 @@ int get_and_dump_counters(void)
 }
 
 void print_version() {
-       fprintf(stderr, "turbostat version 4.5 2 Apr, 2015"
+       fprintf(stderr, "turbostat version 4.7 27-May, 2015"
                " - Len Brown <lenb@kernel.org>\n");
 }
 
index 5a161175bbd4197e907dbeb68f7c5f7003ecdf76..a9099d9f8f39ea8a38a6345b15e2d24ab2e00eb7 100644 (file)
@@ -26,7 +26,7 @@ override define EMIT_TESTS
        $(MAKE) -s -C ebb emit_tests
 endef
 
-DEFAULT_INSTALL := $(INSTALL_RULE)
+DEFAULT_INSTALL_RULE := $(INSTALL_RULE)
 override define INSTALL_RULE
        $(DEFAULT_INSTALL_RULE)
        $(MAKE) -C ebb install
index 1b616fa79e93947987fa0093e8f73d1428205fd2..6bff955e1d55ac6cccb526f5a00355ac4e904973 100644 (file)
@@ -1,4 +1,4 @@
-TEST_PROGS := tm-resched-dscr tm-syscall
+TEST_PROGS := tm-resched-dscr
 
 all: $(TEST_PROGS)
 
index ddf63569df5ae166e466901aa1a60e1b194fe508..9b0d8baf2934ed30acb88df525275aa2da64f275 100644 (file)
@@ -1,48 +1,59 @@
-.PHONY: all all_32 all_64 check_build32 clean run_tests
+all:
+
+include ../lib.mk
+
+.PHONY: all all_32 all_64 warn_32bit_failure clean
 
 TARGETS_C_BOTHBITS := sigreturn single_step_syscall
+TARGETS_C_32BIT_ONLY := entry_from_vm86
 
-BINARIES_32 := $(TARGETS_C_BOTHBITS:%=%_32)
+TARGETS_C_32BIT_ALL := $(TARGETS_C_BOTHBITS) $(TARGETS_C_32BIT_ONLY)
+BINARIES_32 := $(TARGETS_C_32BIT_ALL:%=%_32)
 BINARIES_64 := $(TARGETS_C_BOTHBITS:%=%_64)
 
 CFLAGS := -O2 -g -std=gnu99 -pthread -Wall
 
-UNAME_P := $(shell uname -p)
+UNAME_M := $(shell uname -m)
+CAN_BUILD_I386 := $(shell ./check_cc.sh $(CC) trivial_32bit_program.c -m32)
+CAN_BUILD_X86_64 := $(shell ./check_cc.sh $(CC) trivial_64bit_program.c)
 
-# Always build 32-bit tests
+ifeq ($(CAN_BUILD_I386),1)
 all: all_32
+TEST_PROGS += $(BINARIES_32)
+endif
 
-# If we're on a 64-bit host, build 64-bit tests as well
-ifeq ($(shell uname -p),x86_64)
+ifeq ($(CAN_BUILD_X86_64),1)
 all: all_64
+TEST_PROGS += $(BINARIES_64)
 endif
 
-all_32: check_build32 $(BINARIES_32)
+all_32: $(BINARIES_32)
 
 all_64: $(BINARIES_64)
 
 clean:
        $(RM) $(BINARIES_32) $(BINARIES_64)
 
-run_tests:
-       ./run_x86_tests.sh
-
-$(TARGETS_C_BOTHBITS:%=%_32): %_32: %.c
+$(TARGETS_C_32BIT_ALL:%=%_32): %_32: %.c
        $(CC) -m32 -o $@ $(CFLAGS) $(EXTRA_CFLAGS) $^ -lrt -ldl
 
 $(TARGETS_C_BOTHBITS:%=%_64): %_64: %.c
        $(CC) -m64 -o $@ $(CFLAGS) $(EXTRA_CFLAGS) $^ -lrt -ldl
 
-check_build32:
-       @if ! $(CC) -m32 -o /dev/null trivial_32bit_program.c; then     \
-         echo "Warning: you seem to have a broken 32-bit build" 2>&1;  \
-         echo "environment.  If you are using a Debian-like";          \
-         echo " distribution, try:";                                   \
-         echo "";                                                      \
-         echo "  apt-get install gcc-multilib libc6-i386 libc6-dev-i386"; \
-         echo "";                                                      \
-         echo "If you are using a Fedora-like distribution, try:";     \
-         echo "";                                                      \
-         echo "  yum install glibc-devel.*i686";                       \
-         exit 1;                                                       \
-       fi
+# x86_64 users should be encouraged to install 32-bit libraries
+ifeq ($(CAN_BUILD_I386)$(CAN_BUILD_X86_64),01)
+all: warn_32bit_failure
+
+warn_32bit_failure:
+       @echo "Warning: you seem to have a broken 32-bit build" 2>&1;   \
+       echo "environment.  This will reduce test coverage of 64-bit" 2>&1; \
+       echo "kernels.  If you are using a Debian-like distribution," 2>&1; \
+       echo "try:"; 2>&1; \
+       echo "";                                                        \
+       echo "  apt-get install gcc-multilib libc6-i386 libc6-dev-i386"; \
+       echo "";                                                        \
+       echo "If you are using a Fedora-like distribution, try:";       \
+       echo "";                                                        \
+       echo "  yum install glibc-devel.*i686";                         \
+       exit 0;
+endif
diff --git a/tools/testing/selftests/x86/check_cc.sh b/tools/testing/selftests/x86/check_cc.sh
new file mode 100755 (executable)
index 0000000..172d329
--- /dev/null
@@ -0,0 +1,16 @@
+#!/bin/sh
+# check_cc.sh - Helper to test userspace compilation support
+# Copyright (c) 2015 Andrew Lutomirski
+# GPL v2
+
+CC="$1"
+TESTPROG="$2"
+shift 2
+
+if "$CC" -o /dev/null "$TESTPROG" -O0 "$@" 2>/dev/null; then
+    echo 1
+else
+    echo 0
+fi
+
+exit 0
diff --git a/tools/testing/selftests/x86/entry_from_vm86.c b/tools/testing/selftests/x86/entry_from_vm86.c
new file mode 100644 (file)
index 0000000..5c38a18
--- /dev/null
@@ -0,0 +1,114 @@
+/*
+ * entry_from_vm86.c - tests kernel entries from vm86 mode
+ * Copyright (c) 2014-2015 Andrew Lutomirski
+ *
+ * This exercises a few paths that need to special-case vm86 mode.
+ *
+ * GPL v2.
+ */
+
+#define _GNU_SOURCE
+
+#include <assert.h>
+#include <stdlib.h>
+#include <sys/syscall.h>
+#include <sys/signal.h>
+#include <sys/ucontext.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <string.h>
+#include <inttypes.h>
+#include <sys/mman.h>
+#include <err.h>
+#include <stddef.h>
+#include <stdbool.h>
+#include <errno.h>
+#include <sys/vm86.h>
+
+static unsigned long load_addr = 0x10000;
+static int nerrs = 0;
+
+asm (
+       ".pushsection .rodata\n\t"
+       ".type vmcode_bound, @object\n\t"
+       "vmcode:\n\t"
+       "vmcode_bound:\n\t"
+       ".code16\n\t"
+       "bound %ax, (2048)\n\t"
+       "int3\n\t"
+       "vmcode_sysenter:\n\t"
+       "sysenter\n\t"
+       ".size vmcode, . - vmcode\n\t"
+       "end_vmcode:\n\t"
+       ".code32\n\t"
+       ".popsection"
+       );
+
+extern unsigned char vmcode[], end_vmcode[];
+extern unsigned char vmcode_bound[], vmcode_sysenter[];
+
+static void do_test(struct vm86plus_struct *v86, unsigned long eip,
+                   const char *text)
+{
+       long ret;
+
+       printf("[RUN]\t%s from vm86 mode\n", text);
+       v86->regs.eip = eip;
+       ret = vm86(VM86_ENTER, v86);
+
+       if (ret == -1 && errno == ENOSYS) {
+               printf("[SKIP]\tvm86 not supported\n");
+               return;
+       }
+
+       if (VM86_TYPE(ret) == VM86_INTx) {
+               char trapname[32];
+               int trapno = VM86_ARG(ret);
+               if (trapno == 13)
+                       strcpy(trapname, "GP");
+               else if (trapno == 5)
+                       strcpy(trapname, "BR");
+               else if (trapno == 14)
+                       strcpy(trapname, "PF");
+               else
+                       sprintf(trapname, "%d", trapno);
+
+               printf("[OK]\tExited vm86 mode due to #%s\n", trapname);
+       } else if (VM86_TYPE(ret) == VM86_UNKNOWN) {
+               printf("[OK]\tExited vm86 mode due to unhandled GP fault\n");
+       } else {
+               printf("[OK]\tExited vm86 mode due to type %ld, arg %ld\n",
+                      VM86_TYPE(ret), VM86_ARG(ret));
+       }
+}
+
+int main(void)
+{
+       struct vm86plus_struct v86;
+       unsigned char *addr = mmap((void *)load_addr, 4096,
+                                  PROT_READ | PROT_WRITE | PROT_EXEC,
+                                  MAP_ANONYMOUS | MAP_PRIVATE, -1,0);
+       if (addr != (unsigned char *)load_addr)
+               err(1, "mmap");
+
+       memcpy(addr, vmcode, end_vmcode - vmcode);
+       addr[2048] = 2;
+       addr[2050] = 3;
+
+       memset(&v86, 0, sizeof(v86));
+
+       v86.regs.cs = load_addr / 16;
+       v86.regs.ss = load_addr / 16;
+       v86.regs.ds = load_addr / 16;
+       v86.regs.es = load_addr / 16;
+
+       assert((v86.regs.cs & 3) == 0); /* Looks like RPL = 0 */
+
+       /* #BR -- should deliver SIG??? */
+       do_test(&v86, vmcode_bound - vmcode, "#BR");
+
+       /* SYSENTER -- should cause #GP or #UD depending on CPU */
+       do_test(&v86, vmcode_sysenter - vmcode, "SYSENTER");
+
+       return (nerrs == 0 ? 0 : 1);
+}
diff --git a/tools/testing/selftests/x86/run_x86_tests.sh b/tools/testing/selftests/x86/run_x86_tests.sh
deleted file mode 100644 (file)
index 3fc19b3..0000000
+++ /dev/null
@@ -1,13 +0,0 @@
-#!/bin/bash
-
-# This is deliberately minimal.  IMO kselftests should provide a standard
-# script here.
-./sigreturn_32 || exit 1
-./single_step_syscall_32 || exit 1
-
-if [[ "$uname -p" -eq "x86_64" ]]; then
-    ./sigreturn_64 || exit 1
-    ./single_step_syscall_64 || exit 1
-fi
-
-exit 0
index 2e231beb0a39e7c4b1571dc6ee746941ff069705..fabdf0f51621e30a850c510ffcce8841115c10f2 100644 (file)
@@ -4,6 +4,10 @@
  * GPL v2
  */
 
+#ifndef __i386__
+# error wrong architecture
+#endif
+
 #include <stdio.h>
 
 int main()
diff --git a/tools/testing/selftests/x86/trivial_64bit_program.c b/tools/testing/selftests/x86/trivial_64bit_program.c
new file mode 100644 (file)
index 0000000..b994946
--- /dev/null
@@ -0,0 +1,18 @@
+/*
+ * Trivial program to check that we have a valid 32-bit build environment.
+ * Copyright (c) 2015 Andy Lutomirski
+ * GPL v2
+ */
+
+#ifndef __x86_64__
+# error wrong architecture
+#endif
+
+#include <stdio.h>
+
+int main()
+{
+       printf("\n");
+
+       return 0;
+}
index 0788621c8d760f01f714d377a18c6a390a990fde..2e83dd3655a28ae606a0a2c8c4b80a58331ef24e 100644 (file)
@@ -12,10 +12,6 @@ TARGET=tmon
 INSTALL_PROGRAM=install -m 755 -p
 DEL_FILE=rm -f
 
-INSTALL_CONFIGFILE=install -m 644 -p
-CONFIG_FILE=
-CONFIG_PATH=
-
 # Static builds might require -ltinfo, for instance
 ifneq ($(findstring -static, $(LDFLAGS)),)
 STATIC := --static
@@ -38,13 +34,9 @@ valgrind: tmon
 install:
        - mkdir -p $(INSTALL_ROOT)/$(BINDIR)
        - $(INSTALL_PROGRAM) "$(TARGET)" "$(INSTALL_ROOT)/$(BINDIR)/$(TARGET)"
-       - mkdir -p $(INSTALL_ROOT)/$(CONFIG_PATH)
-       - $(INSTALL_CONFIGFILE) "$(CONFIG_FILE)" "$(INSTALL_ROOT)/$(CONFIG_PATH)"
 
 uninstall:
        $(DEL_FILE) "$(INSTALL_ROOT)/$(BINDIR)/$(TARGET)"
-       $(CONFIG_FILE) "$(CONFIG_PATH)"
-
 
 clean:
        find . -name "*.o" | xargs $(DEL_FILE)
index ac884b65a0725fc9b4e2ed46a490996524fd96a3..93aadaf7ff63d66afab325a67bd09fba982de947 100644 (file)
@@ -3,7 +3,7 @@
 TARGETS=page-types slabinfo page_owner_sort
 
 LIB_DIR = ../lib/api
-LIBS = $(LIB_DIR)/libapikfs.a
+LIBS = $(LIB_DIR)/libapi.a
 
 CC = $(CROSS_COMPILE)gcc
 CFLAGS = -Wall -Wextra -I../lib/